[Add meta-filogic bsp for rdkb development]

[Description]
Add meta-filogic bsp for rdkb development
1. rdkb base on dunfell rdkb-next (> 2022q1)
2. arm64/arm 32bit bsp both can run on rdkb

[Release-log]
N/A

diff --git a/recipes-kernel/linux/linux-mediatek-5.4/001-rdkb-eth-mtk-change-ifname-for.patch b/recipes-kernel/linux/linux-mediatek-5.4/001-rdkb-eth-mtk-change-ifname-for.patch
new file mode 100644
index 0000000..50eea64
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/001-rdkb-eth-mtk-change-ifname-for.patch
@@ -0,0 +1,12 @@
+diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+index 1bf43b3..3001525 100755
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -3395,6 +3395,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
+ 
+ 	eth->netdev[id]->irq = eth->irq[0];
+ 	eth->netdev[id]->dev.of_node = np;
++	sprintf (eth->netdev[id]->name, "eth%d",id+1);
+ 
+ 	return 0;
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/002-rdkb-mtd-ubi-relayout.patch b/recipes-kernel/linux/linux-mediatek-5.4/002-rdkb-mtd-ubi-relayout.patch
new file mode 100644
index 0000000..1174889
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/002-rdkb-mtd-ubi-relayout.patch
@@ -0,0 +1,50 @@
+diff --git a/arch/arm64/boot/dts/mediatek/mt7986-spim-nand-partition.dtsi b/arch/arm64/boot/dts/mediatek/mt7986-spim-nand-partition.dtsi
+index 4cc7961..924f8cc 100644
+--- a/arch/arm64/boot/dts/mediatek/mt7986-spim-nand-partition.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986-spim-nand-partition.dtsi
+@@ -34,10 +34,16 @@
+ 				reg = <0x380000 0x0200000>;
+ 			};
+ 
+-			partition@580000 {
+-				label = "ubi";
+-				reg = <0x580000 0x4000000>;
+-			};
++                        partition@580000 {
++                                label = "Kernel";
++                                reg = <0x580000 0x800000>;
++                        };
++
++                        partition@D80000 {
++                                label = "ubi";
++                                reg = <0xD80000 0xF280000>;
++                        };
++
+ 		};
+ 	};
+ };
+diff --git a/arch/arm/boot/dts/mt7986-spim-nand-partition.dtsi b/arch/arm/boot/dts/mt7986-spim-nand-partition.dtsi
+index 4cc7961..924f8cc 100644
+--- a/arch/arm/boot/dts/mt7986-spim-nand-partition.dtsi
++++ b/arch/arm/boot/dts/mt7986-spim-nand-partition.dtsi
+@@ -34,10 +34,16 @@
+ 				reg = <0x380000 0x0200000>;
+ 			};
+ 
+-			partition@580000 {
+-				label = "ubi";
+-				reg = <0x580000 0x4000000>;
+-			};
++                        partition@580000 {
++                                label = "Kernel";
++                                reg = <0x580000 0x800000>;
++                        };
++
++                        partition@D80000 {
++                                label = "ubi";
++                                reg = <0xD80000 0xF280000>;
++                        };
++
+ 		};
+ 	};
+ };
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/010-Kbuild-don-t-hardcode-path-to-awk-in-scripts-ld-vers.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/010-Kbuild-don-t-hardcode-path-to-awk-in-scripts-ld-vers.patch
new file mode 100644
index 0000000..7ac4f9d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/010-Kbuild-don-t-hardcode-path-to-awk-in-scripts-ld-vers.patch
@@ -0,0 +1,30 @@
+From 13b1ecc3401653a355798eb1dee10cc1608202f4 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Mon, 18 Jan 2016 12:27:49 +0100
+Subject: [PATCH 33/34] Kbuild: don't hardcode path to awk in
+ scripts/ld-version.sh
+
+On some systems /usr/bin/awk does not exist, or is broken. Find it via
+$PATH instead.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ scripts/ld-version.sh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/scripts/ld-version.sh
++++ b/scripts/ld-version.sh
+@@ -1,6 +1,7 @@
+-#!/usr/bin/awk -f
++#!/bin/sh
+ # SPDX-License-Identifier: GPL-2.0
+ # extract linker version number from stdin and turn into single number
++exec awk '
+ 	{
+ 	gsub(".*\\)", "");
+ 	gsub(".*version ", "");
+@@ -9,3 +10,4 @@
+ 	print a[1]*100000000 + a[2]*1000000 + a[3]*10000;
+ 	exit
+ 	}
++'
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/011-kbuild-export-SUBARCH.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/011-kbuild-export-SUBARCH.patch
new file mode 100644
index 0000000..60defa3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/011-kbuild-export-SUBARCH.patch
@@ -0,0 +1,21 @@
+From 173019b66dcc9d68ad9333aa744dad1e369b5aa8 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 9 Jul 2017 00:26:53 +0200
+Subject: [PATCH 34/34] kernel: add compile fix for linux 4.9 on x86
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ Makefile | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/Makefile
++++ b/Makefile
+@@ -493,7 +493,7 @@ KBUILD_LDFLAGS :=
+ GCC_PLUGINS_CFLAGS :=
+ CLANG_FLAGS :=
+ 
+-export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC
++export ARCH SRCARCH SUBARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC
+ export CPP AR NM STRIP OBJCOPY OBJDUMP OBJSIZE READELF PAHOLE LEX YACC AWK INSTALLKERNEL
+ export PERL PYTHON PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX
+ export KGZIP KBZIP2 KLZOP LZMA LZ4 XZ
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/030-modpost-add-a-helper-to-get-data-pointed-by-a-symbol.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/030-modpost-add-a-helper-to-get-data-pointed-by-a-symbol.patch
new file mode 100644
index 0000000..cf88c0c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/030-modpost-add-a-helper-to-get-data-pointed-by-a-symbol.patch
@@ -0,0 +1,53 @@
+From afa0459daa7b08c7b2c879705b69d39b734a11d0 Mon Sep 17 00:00:00 2001
+From: Masahiro Yamada <yamada.masahiro@socionext.com>
+Date: Fri, 15 Nov 2019 02:42:21 +0900
+Subject: [PATCH] modpost: add a helper to get data pointed by a symbol
+
+When CONFIG_MODULE_REL_CRCS is enabled, the value of __crc_* is not
+an absolute value, but the address to the CRC data embedded in the
+.rodata section.
+
+Getting the data pointed by the symbol value is somewhat complex.
+Split it out into a new helper, sym_get_data().
+
+I will reuse it to refactor namespace_from_kstrtabns() in the next
+commit.
+
+Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
+---
+ scripts/mod/modpost.c | 17 +++++++++++++----
+ 1 file changed, 13 insertions(+), 4 deletions(-)
+
+--- a/scripts/mod/modpost.c
++++ b/scripts/mod/modpost.c
+@@ -312,6 +312,18 @@ static const char *sec_name(struct elf_i
+ 	return sech_name(elf, &elf->sechdrs[secindex]);
+ }
+ 
++static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)
++{
++	Elf_Shdr *sechdr = &info->sechdrs[sym->st_shndx];
++	unsigned long offset;
++
++	offset = sym->st_value;
++	if (info->hdr->e_type != ET_REL)
++		offset -= sechdr->sh_addr;
++
++	return (void *)info->hdr + sechdr->sh_offset + offset;
++}
++
+ #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
+ 
+ static enum export export_from_secname(struct elf_info *elf, unsigned int sec)
+@@ -701,10 +713,7 @@ static void handle_modversions(struct mo
+ 			unsigned int *crcp;
+ 
+ 			/* symbol points to the CRC in the ELF object */
+-			crcp = (void *)info->hdr + sym->st_value +
+-			       info->sechdrs[sym->st_shndx].sh_offset -
+-			       (info->hdr->e_type != ET_REL ?
+-				info->sechdrs[sym->st_shndx].sh_addr : 0);
++			crcp = sym_get_data(info, sym);
+ 			crc = TO_NATIVE(*crcp);
+ 		}
+ 		sym_update_crc(symname + strlen("__crc_"), mod, crc,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/031-modpost-refactor-namespace_from_kstrtabns-to-not-har.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/031-modpost-refactor-namespace_from_kstrtabns-to-not-har.patch
new file mode 100644
index 0000000..230dc6b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/031-modpost-refactor-namespace_from_kstrtabns-to-not-har.patch
@@ -0,0 +1,62 @@
+From e84f9fbbece1585f45a03ccc11eeabe121cadc1b Mon Sep 17 00:00:00 2001
+From: Masahiro Yamada <yamada.masahiro@socionext.com>
+Date: Fri, 15 Nov 2019 02:42:22 +0900
+Subject: [PATCH] modpost: refactor namespace_from_kstrtabns() to not hard-code
+ section name
+
+Currently, namespace_from_kstrtabns() relies on the fact that
+namespace strings are recorded in the __ksymtab_strings section.
+Actually, it is coded in include/linux/export.h, but modpost does
+not need to hard-code the section name.
+
+Elf_Sym::st_shndx holds the index of the relevant section. Using it is
+a more portable way to get the namespace string.
+
+Make namespace_from_kstrtabns() simply call sym_get_data(), and delete
+the info->ksymtab_strings .
+
+While I was here, I added more 'const' qualifiers to pointers.
+
+Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
+---
+ scripts/mod/modpost.c | 10 +++-------
+ scripts/mod/modpost.h |  1 -
+ 2 files changed, 3 insertions(+), 8 deletions(-)
+
+--- a/scripts/mod/modpost.c
++++ b/scripts/mod/modpost.c
+@@ -360,10 +360,10 @@ static enum export export_from_sec(struc
+ 		return export_unknown;
+ }
+ 
+-static const char *namespace_from_kstrtabns(struct elf_info *info,
+-					    Elf_Sym *kstrtabns)
++static const char *namespace_from_kstrtabns(const struct elf_info *info,
++					    const Elf_Sym *sym)
+ {
+-	char *value = info->ksymtab_strings + kstrtabns->st_value;
++	const char *value = sym_get_data(info, sym);
+ 	return value[0] ? value : NULL;
+ }
+ 
+@@ -605,10 +605,6 @@ static int parse_elf(struct elf_info *in
+ 			info->export_unused_gpl_sec = i;
+ 		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
+ 			info->export_gpl_future_sec = i;
+-		else if (strcmp(secname, "__ksymtab_strings") == 0)
+-			info->ksymtab_strings = (void *)hdr +
+-						sechdrs[i].sh_offset -
+-						sechdrs[i].sh_addr;
+ 
+ 		if (sechdrs[i].sh_type == SHT_SYMTAB) {
+ 			unsigned int sh_link_idx;
+--- a/scripts/mod/modpost.h
++++ b/scripts/mod/modpost.h
+@@ -143,7 +143,6 @@ struct elf_info {
+ 	Elf_Section  export_gpl_sec;
+ 	Elf_Section  export_unused_gpl_sec;
+ 	Elf_Section  export_gpl_future_sec;
+-	char	     *ksymtab_strings;
+ 	char         *strtab;
+ 	char	     *modinfo;
+ 	unsigned int modinfo_len;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/041-v5.5-arm64-Implement-optimised-checksum-routine.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/041-v5.5-arm64-Implement-optimised-checksum-routine.patch
new file mode 100644
index 0000000..00ec7d0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/041-v5.5-arm64-Implement-optimised-checksum-routine.patch
@@ -0,0 +1,176 @@
+From: Robin Murphy <robin.murphy@arm.com>
+Date: Wed, 15 Jan 2020 16:42:39 +0000
+Subject: [PATCH] arm64: Implement optimised checksum routine
+
+Apparently there exist certain workloads which rely heavily on software
+checksumming, for which the generic do_csum() implementation becomes a
+significant bottleneck. Therefore let's give arm64 its own optimised
+version - for ease of maintenance this foregoes assembly or intrisics,
+and is thus not actually arm64-specific, but does rely heavily on C
+idioms that translate well to the A64 ISA and the typical load/store
+capabilities of most ARMv8 CPU cores.
+
+The resulting increase in checksum throughput scales nicely with buffer
+size, tending towards 4x for a small in-order core (Cortex-A53), and up
+to 6x or more for an aggressive big core (Ampere eMAG).
+
+Reported-by: Lingyan Huang <huanglingyan2@huawei.com>
+Tested-by: Lingyan Huang <huanglingyan2@huawei.com>
+Signed-off-by: Robin Murphy <robin.murphy@arm.com>
+Signed-off-by: Will Deacon <will@kernel.org>
+---
+ create mode 100644 arch/arm64/lib/csum.c
+
+--- a/arch/arm64/include/asm/checksum.h
++++ b/arch/arm64/include/asm/checksum.h
+@@ -36,6 +36,9 @@ static inline __sum16 ip_fast_csum(const
+ }
+ #define ip_fast_csum ip_fast_csum
+ 
++extern unsigned int do_csum(const unsigned char *buff, int len);
++#define do_csum do_csum
++
+ #include <asm-generic/checksum.h>
+ 
+ #endif	/* __ASM_CHECKSUM_H */
+--- a/arch/arm64/lib/Makefile
++++ b/arch/arm64/lib/Makefile
+@@ -1,9 +1,9 @@
+ # SPDX-License-Identifier: GPL-2.0
+ lib-y		:= clear_user.o delay.o copy_from_user.o		\
+ 		   copy_to_user.o copy_in_user.o copy_page.o		\
+-		   clear_page.o memchr.o memcpy.o memmove.o memset.o	\
+-		   memcmp.o strcmp.o strncmp.o strlen.o strnlen.o	\
+-		   strchr.o strrchr.o tishift.o
++		   clear_page.o csum.o memchr.o memcpy.o memmove.o	\
++		   memset.o memcmp.o strcmp.o strncmp.o strlen.o	\
++		   strnlen.o strchr.o strrchr.o tishift.o
+ 
+ ifeq ($(CONFIG_KERNEL_MODE_NEON), y)
+ obj-$(CONFIG_XOR_BLOCKS)	+= xor-neon.o
+--- /dev/null
++++ b/arch/arm64/lib/csum.c
+@@ -0,0 +1,123 @@
++// SPDX-License-Identifier: GPL-2.0-only
++// Copyright (C) 2019-2020 Arm Ltd.
++
++#include <linux/compiler.h>
++#include <linux/kasan-checks.h>
++#include <linux/kernel.h>
++
++#include <net/checksum.h>
++
++/* Looks dumb, but generates nice-ish code */
++static u64 accumulate(u64 sum, u64 data)
++{
++	__uint128_t tmp = (__uint128_t)sum + data;
++	return tmp + (tmp >> 64);
++}
++
++unsigned int do_csum(const unsigned char *buff, int len)
++{
++	unsigned int offset, shift, sum;
++	const u64 *ptr;
++	u64 data, sum64 = 0;
++
++	offset = (unsigned long)buff & 7;
++	/*
++	 * This is to all intents and purposes safe, since rounding down cannot
++	 * result in a different page or cache line being accessed, and @buff
++	 * should absolutely not be pointing to anything read-sensitive. We do,
++	 * however, have to be careful not to piss off KASAN, which means using
++	 * unchecked reads to accommodate the head and tail, for which we'll
++	 * compensate with an explicit check up-front.
++	 */
++	kasan_check_read(buff, len);
++	ptr = (u64 *)(buff - offset);
++	len = len + offset - 8;
++
++	/*
++	 * Head: zero out any excess leading bytes. Shifting back by the same
++	 * amount should be at least as fast as any other way of handling the
++	 * odd/even alignment, and means we can ignore it until the very end.
++	 */
++	shift = offset * 8;
++	data = READ_ONCE_NOCHECK(*ptr++);
++#ifdef __LITTLE_ENDIAN
++	data = (data >> shift) << shift;
++#else
++	data = (data << shift) >> shift;
++#endif
++
++	/*
++	 * Body: straightforward aligned loads from here on (the paired loads
++	 * underlying the quadword type still only need dword alignment). The
++	 * main loop strictly excludes the tail, so the second loop will always
++	 * run at least once.
++	 */
++	while (unlikely(len > 64)) {
++		__uint128_t tmp1, tmp2, tmp3, tmp4;
++
++		tmp1 = READ_ONCE_NOCHECK(*(__uint128_t *)ptr);
++		tmp2 = READ_ONCE_NOCHECK(*(__uint128_t *)(ptr + 2));
++		tmp3 = READ_ONCE_NOCHECK(*(__uint128_t *)(ptr + 4));
++		tmp4 = READ_ONCE_NOCHECK(*(__uint128_t *)(ptr + 6));
++
++		len -= 64;
++		ptr += 8;
++
++		/* This is the "don't dump the carry flag into a GPR" idiom */
++		tmp1 += (tmp1 >> 64) | (tmp1 << 64);
++		tmp2 += (tmp2 >> 64) | (tmp2 << 64);
++		tmp3 += (tmp3 >> 64) | (tmp3 << 64);
++		tmp4 += (tmp4 >> 64) | (tmp4 << 64);
++		tmp1 = ((tmp1 >> 64) << 64) | (tmp2 >> 64);
++		tmp1 += (tmp1 >> 64) | (tmp1 << 64);
++		tmp3 = ((tmp3 >> 64) << 64) | (tmp4 >> 64);
++		tmp3 += (tmp3 >> 64) | (tmp3 << 64);
++		tmp1 = ((tmp1 >> 64) << 64) | (tmp3 >> 64);
++		tmp1 += (tmp1 >> 64) | (tmp1 << 64);
++		tmp1 = ((tmp1 >> 64) << 64) | sum64;
++		tmp1 += (tmp1 >> 64) | (tmp1 << 64);
++		sum64 = tmp1 >> 64;
++	}
++	while (len > 8) {
++		__uint128_t tmp;
++
++		sum64 = accumulate(sum64, data);
++		tmp = READ_ONCE_NOCHECK(*(__uint128_t *)ptr);
++
++		len -= 16;
++		ptr += 2;
++
++#ifdef __LITTLE_ENDIAN
++		data = tmp >> 64;
++		sum64 = accumulate(sum64, tmp);
++#else
++		data = tmp;
++		sum64 = accumulate(sum64, tmp >> 64);
++#endif
++	}
++	if (len > 0) {
++		sum64 = accumulate(sum64, data);
++		data = READ_ONCE_NOCHECK(*ptr);
++		len -= 8;
++	}
++	/*
++	 * Tail: zero any over-read bytes similarly to the head, again
++	 * preserving odd/even alignment.
++	 */
++	shift = len * -8;
++#ifdef __LITTLE_ENDIAN
++	data = (data << shift) >> shift;
++#else
++	data = (data >> shift) << shift;
++#endif
++	sum64 = accumulate(sum64, data);
++
++	/* Finally, folding */
++	sum64 += (sum64 >> 32) | (sum64 << 32);
++	sum = sum64 >> 32;
++	sum += (sum >> 16) | (sum << 16);
++	if (offset & 1)
++		return (u16)swab32(sum);
++
++	return sum >> 16;
++}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/042-v5.5-arm64-csum-Fix-pathological-zero-length-calls.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/042-v5.5-arm64-csum-Fix-pathological-zero-length-calls.patch
new file mode 100644
index 0000000..50b210e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/042-v5.5-arm64-csum-Fix-pathological-zero-length-calls.patch
@@ -0,0 +1,28 @@
+From: Robin Murphy <robin.murphy@arm.com>
+Date: Fri, 17 Jan 2020 15:48:39 +0000
+Subject: [PATCH] arm64: csum: Fix pathological zero-length calls
+
+In validating the checksumming results of the new routine, I sadly
+neglected to test its not-checksumming results. Thus it slipped through
+that the one case where @buff is already dword-aligned and @len = 0
+manages to defeat the tail-masking logic and behave as if @len = 8.
+For a zero length it doesn't make much sense to deference @buff anyway,
+so just add an early return (which has essentially zero impact on
+performance).
+
+Signed-off-by: Robin Murphy <robin.murphy@arm.com>
+Signed-off-by: Will Deacon <will@kernel.org>
+---
+
+--- a/arch/arm64/lib/csum.c
++++ b/arch/arm64/lib/csum.c
+@@ -20,6 +20,9 @@ unsigned int do_csum(const unsigned char
+ 	const u64 *ptr;
+ 	u64 data, sum64 = 0;
+ 
++	if (unlikely(len == 0))
++		return 0;
++
+ 	offset = (unsigned long)buff & 7;
+ 	/*
+ 	 * This is to all intents and purposes safe, since rounding down cannot
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0001-crypto-lib-tidy-up-lib-crypto-Kconfig-and-Makefile.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0001-crypto-lib-tidy-up-lib-crypto-Kconfig-and-Makefile.patch
new file mode 100644
index 0000000..e32e18a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0001-crypto-lib-tidy-up-lib-crypto-Kconfig-and-Makefile.patch
@@ -0,0 +1,112 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:07 +0100
+Subject: [PATCH] crypto: lib - tidy up lib/crypto Kconfig and Makefile
+
+commit 746b2e024c67aa605ac12d135cd7085a49cf9dc4 upstream.
+
+In preparation of introducing a set of crypto library interfaces, tidy
+up the Makefile and split off the Kconfig symbols into a separate file.
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ crypto/Kconfig      | 13 +------------
+ lib/crypto/Kconfig  | 15 +++++++++++++++
+ lib/crypto/Makefile | 16 ++++++++--------
+ 3 files changed, 24 insertions(+), 20 deletions(-)
+ create mode 100644 lib/crypto/Kconfig
+
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -878,9 +878,6 @@ config CRYPTO_SHA1_PPC_SPE
+ 	  SHA-1 secure hash standard (DFIPS 180-4) implemented
+ 	  using powerpc SPE SIMD instruction set.
+ 
+-config CRYPTO_LIB_SHA256
+-	tristate
+-
+ config CRYPTO_SHA256
+ 	tristate "SHA224 and SHA256 digest algorithm"
+ 	select CRYPTO_HASH
+@@ -1019,9 +1016,6 @@ config CRYPTO_GHASH_CLMUL_NI_INTEL
+ 
+ comment "Ciphers"
+ 
+-config CRYPTO_LIB_AES
+-	tristate
+-
+ config CRYPTO_AES
+ 	tristate "AES cipher algorithms"
+ 	select CRYPTO_ALGAPI
+@@ -1150,9 +1144,6 @@ config CRYPTO_ANUBIS
+ 	  <https://www.cosic.esat.kuleuven.be/nessie/reports/>
+ 	  <http://www.larc.usp.br/~pbarreto/AnubisPage.html>
+ 
+-config CRYPTO_LIB_ARC4
+-	tristate
+-
+ config CRYPTO_ARC4
+ 	tristate "ARC4 cipher algorithm"
+ 	select CRYPTO_BLKCIPHER
+@@ -1339,9 +1330,6 @@ config CRYPTO_CAST6_AVX_X86_64
+ 	  This module provides the Cast6 cipher algorithm that processes
+ 	  eight blocks parallel using the AVX instruction set.
+ 
+-config CRYPTO_LIB_DES
+-	tristate
+-
+ config CRYPTO_DES
+ 	tristate "DES and Triple DES EDE cipher algorithms"
+ 	select CRYPTO_ALGAPI
+@@ -1845,6 +1833,7 @@ config CRYPTO_STATS
+ config CRYPTO_HASH_INFO
+ 	bool
+ 
++source "lib/crypto/Kconfig"
+ source "drivers/crypto/Kconfig"
+ source "crypto/asymmetric_keys/Kconfig"
+ source "certs/Kconfig"
+--- /dev/null
++++ b/lib/crypto/Kconfig
+@@ -0,0 +1,15 @@
++# SPDX-License-Identifier: GPL-2.0
++
++comment "Crypto library routines"
++
++config CRYPTO_LIB_AES
++	tristate
++
++config CRYPTO_LIB_ARC4
++	tristate
++
++config CRYPTO_LIB_DES
++	tristate
++
++config CRYPTO_LIB_SHA256
++	tristate
+--- a/lib/crypto/Makefile
++++ b/lib/crypto/Makefile
+@@ -1,13 +1,13 @@
+ # SPDX-License-Identifier: GPL-2.0
+ 
+-obj-$(CONFIG_CRYPTO_LIB_AES) += libaes.o
+-libaes-y := aes.o
++obj-$(CONFIG_CRYPTO_LIB_AES)			+= libaes.o
++libaes-y					:= aes.o
+ 
+-obj-$(CONFIG_CRYPTO_LIB_ARC4) += libarc4.o
+-libarc4-y := arc4.o
++obj-$(CONFIG_CRYPTO_LIB_ARC4)			+= libarc4.o
++libarc4-y					:= arc4.o
+ 
+-obj-$(CONFIG_CRYPTO_LIB_DES) += libdes.o
+-libdes-y := des.o
++obj-$(CONFIG_CRYPTO_LIB_DES)			+= libdes.o
++libdes-y					:= des.o
+ 
+-obj-$(CONFIG_CRYPTO_LIB_SHA256) += libsha256.o
+-libsha256-y := sha256.o
++obj-$(CONFIG_CRYPTO_LIB_SHA256)			+= libsha256.o
++libsha256-y					:= sha256.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0002-crypto-chacha-move-existing-library-code-into-lib-cr.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0002-crypto-chacha-move-existing-library-code-into-lib-cr.patch
new file mode 100644
index 0000000..177b584
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0002-crypto-chacha-move-existing-library-code-into-lib-cr.patch
@@ -0,0 +1,668 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:08 +0100
+Subject: [PATCH] crypto: chacha - move existing library code into lib/crypto
+
+commit 5fb8ef25803ef33e2eb60b626435828b937bed75 upstream.
+
+Currently, our generic ChaCha implementation consists of a permute
+function in lib/chacha.c that operates on the 64-byte ChaCha state
+directly [and which is always included into the core kernel since it
+is used by the /dev/random driver], and the crypto API plumbing to
+expose it as a skcipher.
+
+In order to support in-kernel users that need the ChaCha streamcipher
+but have no need [or tolerance] for going through the abstractions of
+the crypto API, let's expose the streamcipher bits via a library API
+as well, in a way that permits the implementation to be superseded by
+an architecture specific one if provided.
+
+So move the streamcipher code into a separate module in lib/crypto,
+and expose the init() and crypt() routines to users of the library.
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm/crypto/chacha-neon-glue.c   |  2 +-
+ arch/arm64/crypto/chacha-neon-glue.c |  2 +-
+ arch/x86/crypto/chacha_glue.c        |  2 +-
+ crypto/Kconfig                       |  1 +
+ crypto/chacha_generic.c              | 60 ++--------------------
+ include/crypto/chacha.h              | 77 ++++++++++++++++++++++------
+ include/crypto/internal/chacha.h     | 53 +++++++++++++++++++
+ lib/Makefile                         |  3 +-
+ lib/crypto/Kconfig                   | 26 ++++++++++
+ lib/crypto/Makefile                  |  4 ++
+ lib/{ => crypto}/chacha.c            | 20 ++++----
+ lib/crypto/libchacha.c               | 35 +++++++++++++
+ 12 files changed, 199 insertions(+), 86 deletions(-)
+ create mode 100644 include/crypto/internal/chacha.h
+ rename lib/{ => crypto}/chacha.c (88%)
+ create mode 100644 lib/crypto/libchacha.c
+
+--- a/arch/arm/crypto/chacha-neon-glue.c
++++ b/arch/arm/crypto/chacha-neon-glue.c
+@@ -20,7 +20,7 @@
+  */
+ 
+ #include <crypto/algapi.h>
+-#include <crypto/chacha.h>
++#include <crypto/internal/chacha.h>
+ #include <crypto/internal/simd.h>
+ #include <crypto/internal/skcipher.h>
+ #include <linux/kernel.h>
+--- a/arch/arm64/crypto/chacha-neon-glue.c
++++ b/arch/arm64/crypto/chacha-neon-glue.c
+@@ -20,7 +20,7 @@
+  */
+ 
+ #include <crypto/algapi.h>
+-#include <crypto/chacha.h>
++#include <crypto/internal/chacha.h>
+ #include <crypto/internal/simd.h>
+ #include <crypto/internal/skcipher.h>
+ #include <linux/kernel.h>
+--- a/arch/x86/crypto/chacha_glue.c
++++ b/arch/x86/crypto/chacha_glue.c
+@@ -7,7 +7,7 @@
+  */
+ 
+ #include <crypto/algapi.h>
+-#include <crypto/chacha.h>
++#include <crypto/internal/chacha.h>
+ #include <crypto/internal/simd.h>
+ #include <crypto/internal/skcipher.h>
+ #include <linux/kernel.h>
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -1393,6 +1393,7 @@ config CRYPTO_SALSA20
+ 
+ config CRYPTO_CHACHA20
+ 	tristate "ChaCha stream cipher algorithms"
++	select CRYPTO_LIB_CHACHA_GENERIC
+ 	select CRYPTO_BLKCIPHER
+ 	help
+ 	  The ChaCha20, XChaCha20, and XChaCha12 stream cipher algorithms.
+--- a/crypto/chacha_generic.c
++++ b/crypto/chacha_generic.c
+@@ -8,29 +8,10 @@
+ 
+ #include <asm/unaligned.h>
+ #include <crypto/algapi.h>
+-#include <crypto/chacha.h>
++#include <crypto/internal/chacha.h>
+ #include <crypto/internal/skcipher.h>
+ #include <linux/module.h>
+ 
+-static void chacha_docrypt(u32 *state, u8 *dst, const u8 *src,
+-			   unsigned int bytes, int nrounds)
+-{
+-	/* aligned to potentially speed up crypto_xor() */
+-	u8 stream[CHACHA_BLOCK_SIZE] __aligned(sizeof(long));
+-
+-	while (bytes >= CHACHA_BLOCK_SIZE) {
+-		chacha_block(state, stream, nrounds);
+-		crypto_xor_cpy(dst, src, stream, CHACHA_BLOCK_SIZE);
+-		bytes -= CHACHA_BLOCK_SIZE;
+-		dst += CHACHA_BLOCK_SIZE;
+-		src += CHACHA_BLOCK_SIZE;
+-	}
+-	if (bytes) {
+-		chacha_block(state, stream, nrounds);
+-		crypto_xor_cpy(dst, src, stream, bytes);
+-	}
+-}
+-
+ static int chacha_stream_xor(struct skcipher_request *req,
+ 			     const struct chacha_ctx *ctx, const u8 *iv)
+ {
+@@ -48,8 +29,8 @@ static int chacha_stream_xor(struct skci
+ 		if (nbytes < walk.total)
+ 			nbytes = round_down(nbytes, CHACHA_BLOCK_SIZE);
+ 
+-		chacha_docrypt(state, walk.dst.virt.addr, walk.src.virt.addr,
+-			       nbytes, ctx->nrounds);
++		chacha_crypt_generic(state, walk.dst.virt.addr,
++				     walk.src.virt.addr, nbytes, ctx->nrounds);
+ 		err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
+ 	}
+ 
+@@ -58,41 +39,10 @@ static int chacha_stream_xor(struct skci
+ 
+ void crypto_chacha_init(u32 *state, const struct chacha_ctx *ctx, const u8 *iv)
+ {
+-	state[0]  = 0x61707865; /* "expa" */
+-	state[1]  = 0x3320646e; /* "nd 3" */
+-	state[2]  = 0x79622d32; /* "2-by" */
+-	state[3]  = 0x6b206574; /* "te k" */
+-	state[4]  = ctx->key[0];
+-	state[5]  = ctx->key[1];
+-	state[6]  = ctx->key[2];
+-	state[7]  = ctx->key[3];
+-	state[8]  = ctx->key[4];
+-	state[9]  = ctx->key[5];
+-	state[10] = ctx->key[6];
+-	state[11] = ctx->key[7];
+-	state[12] = get_unaligned_le32(iv +  0);
+-	state[13] = get_unaligned_le32(iv +  4);
+-	state[14] = get_unaligned_le32(iv +  8);
+-	state[15] = get_unaligned_le32(iv + 12);
++	chacha_init_generic(state, ctx->key, iv);
+ }
+ EXPORT_SYMBOL_GPL(crypto_chacha_init);
+ 
+-static int chacha_setkey(struct crypto_skcipher *tfm, const u8 *key,
+-			 unsigned int keysize, int nrounds)
+-{
+-	struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
+-	int i;
+-
+-	if (keysize != CHACHA_KEY_SIZE)
+-		return -EINVAL;
+-
+-	for (i = 0; i < ARRAY_SIZE(ctx->key); i++)
+-		ctx->key[i] = get_unaligned_le32(key + i * sizeof(u32));
+-
+-	ctx->nrounds = nrounds;
+-	return 0;
+-}
+-
+ int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ 			   unsigned int keysize)
+ {
+@@ -126,7 +76,7 @@ int crypto_xchacha_crypt(struct skcipher
+ 
+ 	/* Compute the subkey given the original key and first 128 nonce bits */
+ 	crypto_chacha_init(state, ctx, req->iv);
+-	hchacha_block(state, subctx.key, ctx->nrounds);
++	hchacha_block_generic(state, subctx.key, ctx->nrounds);
+ 	subctx.nrounds = ctx->nrounds;
+ 
+ 	/* Build the real IV */
+--- a/include/crypto/chacha.h
++++ b/include/crypto/chacha.h
+@@ -15,9 +15,8 @@
+ #ifndef _CRYPTO_CHACHA_H
+ #define _CRYPTO_CHACHA_H
+ 
+-#include <crypto/skcipher.h>
++#include <asm/unaligned.h>
+ #include <linux/types.h>
+-#include <linux/crypto.h>
+ 
+ /* 32-bit stream position, then 96-bit nonce (RFC7539 convention) */
+ #define CHACHA_IV_SIZE		16
+@@ -29,26 +28,70 @@
+ /* 192-bit nonce, then 64-bit stream position */
+ #define XCHACHA_IV_SIZE		32
+ 
+-struct chacha_ctx {
+-	u32 key[8];
+-	int nrounds;
+-};
+-
+-void chacha_block(u32 *state, u8 *stream, int nrounds);
++void chacha_block_generic(u32 *state, u8 *stream, int nrounds);
+ static inline void chacha20_block(u32 *state, u8 *stream)
+ {
+-	chacha_block(state, stream, 20);
++	chacha_block_generic(state, stream, 20);
+ }
+-void hchacha_block(const u32 *in, u32 *out, int nrounds);
+ 
+-void crypto_chacha_init(u32 *state, const struct chacha_ctx *ctx, const u8 *iv);
++void hchacha_block_arch(const u32 *state, u32 *out, int nrounds);
++void hchacha_block_generic(const u32 *state, u32 *out, int nrounds);
++
++static inline void hchacha_block(const u32 *state, u32 *out, int nrounds)
++{
++	if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CHACHA))
++		hchacha_block_arch(state, out, nrounds);
++	else
++		hchacha_block_generic(state, out, nrounds);
++}
+ 
+-int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key,
+-			   unsigned int keysize);
+-int crypto_chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key,
+-			   unsigned int keysize);
++void chacha_init_arch(u32 *state, const u32 *key, const u8 *iv);
++static inline void chacha_init_generic(u32 *state, const u32 *key, const u8 *iv)
++{
++	state[0]  = 0x61707865; /* "expa" */
++	state[1]  = 0x3320646e; /* "nd 3" */
++	state[2]  = 0x79622d32; /* "2-by" */
++	state[3]  = 0x6b206574; /* "te k" */
++	state[4]  = key[0];
++	state[5]  = key[1];
++	state[6]  = key[2];
++	state[7]  = key[3];
++	state[8]  = key[4];
++	state[9]  = key[5];
++	state[10] = key[6];
++	state[11] = key[7];
++	state[12] = get_unaligned_le32(iv +  0);
++	state[13] = get_unaligned_le32(iv +  4);
++	state[14] = get_unaligned_le32(iv +  8);
++	state[15] = get_unaligned_le32(iv + 12);
++}
+ 
+-int crypto_chacha_crypt(struct skcipher_request *req);
+-int crypto_xchacha_crypt(struct skcipher_request *req);
++static inline void chacha_init(u32 *state, const u32 *key, const u8 *iv)
++{
++	if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CHACHA))
++		chacha_init_arch(state, key, iv);
++	else
++		chacha_init_generic(state, key, iv);
++}
++
++void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src,
++		       unsigned int bytes, int nrounds);
++void chacha_crypt_generic(u32 *state, u8 *dst, const u8 *src,
++			  unsigned int bytes, int nrounds);
++
++static inline void chacha_crypt(u32 *state, u8 *dst, const u8 *src,
++				unsigned int bytes, int nrounds)
++{
++	if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CHACHA))
++		chacha_crypt_arch(state, dst, src, bytes, nrounds);
++	else
++		chacha_crypt_generic(state, dst, src, bytes, nrounds);
++}
++
++static inline void chacha20_crypt(u32 *state, u8 *dst, const u8 *src,
++				  unsigned int bytes)
++{
++	chacha_crypt(state, dst, src, bytes, 20);
++}
+ 
+ #endif /* _CRYPTO_CHACHA_H */
+--- /dev/null
++++ b/include/crypto/internal/chacha.h
+@@ -0,0 +1,53 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++
++#ifndef _CRYPTO_INTERNAL_CHACHA_H
++#define _CRYPTO_INTERNAL_CHACHA_H
++
++#include <crypto/chacha.h>
++#include <crypto/internal/skcipher.h>
++#include <linux/crypto.h>
++
++struct chacha_ctx {
++	u32 key[8];
++	int nrounds;
++};
++
++void crypto_chacha_init(u32 *state, const struct chacha_ctx *ctx, const u8 *iv);
++
++static inline int chacha_setkey(struct crypto_skcipher *tfm, const u8 *key,
++				unsigned int keysize, int nrounds)
++{
++	struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
++	int i;
++
++	if (keysize != CHACHA_KEY_SIZE)
++		return -EINVAL;
++
++	for (i = 0; i < ARRAY_SIZE(ctx->key); i++)
++		ctx->key[i] = get_unaligned_le32(key + i * sizeof(u32));
++
++	ctx->nrounds = nrounds;
++	return 0;
++}
++
++static inline int chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key,
++				  unsigned int keysize)
++{
++	return chacha_setkey(tfm, key, keysize, 20);
++}
++
++static int inline chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key,
++				  unsigned int keysize)
++{
++	return chacha_setkey(tfm, key, keysize, 12);
++}
++
++int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key,
++			   unsigned int keysize);
++int crypto_chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key,
++			   unsigned int keysize);
++
++int crypto_chacha_crypt(struct skcipher_request *req);
++int crypto_xchacha_crypt(struct skcipher_request *req);
++
++#endif /* _CRYPTO_CHACHA_H */
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -26,8 +26,7 @@ endif
+ 
+ lib-y := ctype.o string.o vsprintf.o cmdline.o \
+ 	 rbtree.o radix-tree.o timerqueue.o xarray.o \
+-	 idr.o extable.o \
+-	 sha1.o chacha.o irq_regs.o argv_split.o \
++	 idr.o extable.o sha1.o irq_regs.o argv_split.o \
+ 	 flex_proportions.o ratelimit.o show_mem.o \
+ 	 is_single_threaded.o plist.o decompress.o kobject_uevent.o \
+ 	 earlycpio.o seq_buf.o siphash.o dec_and_lock.o \
+--- a/lib/crypto/Kconfig
++++ b/lib/crypto/Kconfig
+@@ -8,6 +8,32 @@ config CRYPTO_LIB_AES
+ config CRYPTO_LIB_ARC4
+ 	tristate
+ 
++config CRYPTO_ARCH_HAVE_LIB_CHACHA
++	tristate
++	help
++	  Declares whether the architecture provides an arch-specific
++	  accelerated implementation of the ChaCha library interface,
++	  either builtin or as a module.
++
++config CRYPTO_LIB_CHACHA_GENERIC
++	tristate
++	select CRYPTO_ALGAPI
++	help
++	  This symbol can be depended upon by arch implementations of the
++	  ChaCha library interface that require the generic code as a
++	  fallback, e.g., for SIMD implementations. If no arch specific
++	  implementation is enabled, this implementation serves the users
++	  of CRYPTO_LIB_CHACHA.
++
++config CRYPTO_LIB_CHACHA
++	tristate "ChaCha library interface"
++	depends on CRYPTO_ARCH_HAVE_LIB_CHACHA || !CRYPTO_ARCH_HAVE_LIB_CHACHA
++	select CRYPTO_LIB_CHACHA_GENERIC if CRYPTO_ARCH_HAVE_LIB_CHACHA=n
++	help
++	  Enable the ChaCha library interface. This interface may be fulfilled
++	  by either the generic implementation or an arch-specific one, if one
++	  is available and enabled.
++
+ config CRYPTO_LIB_DES
+ 	tristate
+ 
+--- a/lib/crypto/Makefile
++++ b/lib/crypto/Makefile
+@@ -1,5 +1,9 @@
+ # SPDX-License-Identifier: GPL-2.0
+ 
++# chacha is used by the /dev/random driver which is always builtin
++obj-y						+= chacha.o
++obj-$(CONFIG_CRYPTO_LIB_CHACHA_GENERIC)		+= libchacha.o
++
+ obj-$(CONFIG_CRYPTO_LIB_AES)			+= libaes.o
+ libaes-y					:= aes.o
+ 
+--- a/lib/chacha.c
++++ /dev/null
+@@ -1,113 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * The "hash function" used as the core of the ChaCha stream cipher (RFC7539)
+- *
+- * Copyright (C) 2015 Martin Willi
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/export.h>
+-#include <linux/bitops.h>
+-#include <linux/cryptohash.h>
+-#include <asm/unaligned.h>
+-#include <crypto/chacha.h>
+-
+-static void chacha_permute(u32 *x, int nrounds)
+-{
+-	int i;
+-
+-	/* whitelist the allowed round counts */
+-	WARN_ON_ONCE(nrounds != 20 && nrounds != 12);
+-
+-	for (i = 0; i < nrounds; i += 2) {
+-		x[0]  += x[4];    x[12] = rol32(x[12] ^ x[0],  16);
+-		x[1]  += x[5];    x[13] = rol32(x[13] ^ x[1],  16);
+-		x[2]  += x[6];    x[14] = rol32(x[14] ^ x[2],  16);
+-		x[3]  += x[7];    x[15] = rol32(x[15] ^ x[3],  16);
+-
+-		x[8]  += x[12];   x[4]  = rol32(x[4]  ^ x[8],  12);
+-		x[9]  += x[13];   x[5]  = rol32(x[5]  ^ x[9],  12);
+-		x[10] += x[14];   x[6]  = rol32(x[6]  ^ x[10], 12);
+-		x[11] += x[15];   x[7]  = rol32(x[7]  ^ x[11], 12);
+-
+-		x[0]  += x[4];    x[12] = rol32(x[12] ^ x[0],   8);
+-		x[1]  += x[5];    x[13] = rol32(x[13] ^ x[1],   8);
+-		x[2]  += x[6];    x[14] = rol32(x[14] ^ x[2],   8);
+-		x[3]  += x[7];    x[15] = rol32(x[15] ^ x[3],   8);
+-
+-		x[8]  += x[12];   x[4]  = rol32(x[4]  ^ x[8],   7);
+-		x[9]  += x[13];   x[5]  = rol32(x[5]  ^ x[9],   7);
+-		x[10] += x[14];   x[6]  = rol32(x[6]  ^ x[10],  7);
+-		x[11] += x[15];   x[7]  = rol32(x[7]  ^ x[11],  7);
+-
+-		x[0]  += x[5];    x[15] = rol32(x[15] ^ x[0],  16);
+-		x[1]  += x[6];    x[12] = rol32(x[12] ^ x[1],  16);
+-		x[2]  += x[7];    x[13] = rol32(x[13] ^ x[2],  16);
+-		x[3]  += x[4];    x[14] = rol32(x[14] ^ x[3],  16);
+-
+-		x[10] += x[15];   x[5]  = rol32(x[5]  ^ x[10], 12);
+-		x[11] += x[12];   x[6]  = rol32(x[6]  ^ x[11], 12);
+-		x[8]  += x[13];   x[7]  = rol32(x[7]  ^ x[8],  12);
+-		x[9]  += x[14];   x[4]  = rol32(x[4]  ^ x[9],  12);
+-
+-		x[0]  += x[5];    x[15] = rol32(x[15] ^ x[0],   8);
+-		x[1]  += x[6];    x[12] = rol32(x[12] ^ x[1],   8);
+-		x[2]  += x[7];    x[13] = rol32(x[13] ^ x[2],   8);
+-		x[3]  += x[4];    x[14] = rol32(x[14] ^ x[3],   8);
+-
+-		x[10] += x[15];   x[5]  = rol32(x[5]  ^ x[10],  7);
+-		x[11] += x[12];   x[6]  = rol32(x[6]  ^ x[11],  7);
+-		x[8]  += x[13];   x[7]  = rol32(x[7]  ^ x[8],   7);
+-		x[9]  += x[14];   x[4]  = rol32(x[4]  ^ x[9],   7);
+-	}
+-}
+-
+-/**
+- * chacha_block - generate one keystream block and increment block counter
+- * @state: input state matrix (16 32-bit words)
+- * @stream: output keystream block (64 bytes)
+- * @nrounds: number of rounds (20 or 12; 20 is recommended)
+- *
+- * This is the ChaCha core, a function from 64-byte strings to 64-byte strings.
+- * The caller has already converted the endianness of the input.  This function
+- * also handles incrementing the block counter in the input matrix.
+- */
+-void chacha_block(u32 *state, u8 *stream, int nrounds)
+-{
+-	u32 x[16];
+-	int i;
+-
+-	memcpy(x, state, 64);
+-
+-	chacha_permute(x, nrounds);
+-
+-	for (i = 0; i < ARRAY_SIZE(x); i++)
+-		put_unaligned_le32(x[i] + state[i], &stream[i * sizeof(u32)]);
+-
+-	state[12]++;
+-}
+-EXPORT_SYMBOL(chacha_block);
+-
+-/**
+- * hchacha_block - abbreviated ChaCha core, for XChaCha
+- * @in: input state matrix (16 32-bit words)
+- * @out: output (8 32-bit words)
+- * @nrounds: number of rounds (20 or 12; 20 is recommended)
+- *
+- * HChaCha is the ChaCha equivalent of HSalsa and is an intermediate step
+- * towards XChaCha (see https://cr.yp.to/snuffle/xsalsa-20081128.pdf).  HChaCha
+- * skips the final addition of the initial state, and outputs only certain words
+- * of the state.  It should not be used for streaming directly.
+- */
+-void hchacha_block(const u32 *in, u32 *out, int nrounds)
+-{
+-	u32 x[16];
+-
+-	memcpy(x, in, 64);
+-
+-	chacha_permute(x, nrounds);
+-
+-	memcpy(&out[0], &x[0], 16);
+-	memcpy(&out[4], &x[12], 16);
+-}
+-EXPORT_SYMBOL(hchacha_block);
+--- /dev/null
++++ b/lib/crypto/chacha.c
+@@ -0,0 +1,115 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * The "hash function" used as the core of the ChaCha stream cipher (RFC7539)
++ *
++ * Copyright (C) 2015 Martin Willi
++ */
++
++#include <linux/bug.h>
++#include <linux/kernel.h>
++#include <linux/export.h>
++#include <linux/bitops.h>
++#include <linux/string.h>
++#include <linux/cryptohash.h>
++#include <asm/unaligned.h>
++#include <crypto/chacha.h>
++
++static void chacha_permute(u32 *x, int nrounds)
++{
++	int i;
++
++	/* whitelist the allowed round counts */
++	WARN_ON_ONCE(nrounds != 20 && nrounds != 12);
++
++	for (i = 0; i < nrounds; i += 2) {
++		x[0]  += x[4];    x[12] = rol32(x[12] ^ x[0],  16);
++		x[1]  += x[5];    x[13] = rol32(x[13] ^ x[1],  16);
++		x[2]  += x[6];    x[14] = rol32(x[14] ^ x[2],  16);
++		x[3]  += x[7];    x[15] = rol32(x[15] ^ x[3],  16);
++
++		x[8]  += x[12];   x[4]  = rol32(x[4]  ^ x[8],  12);
++		x[9]  += x[13];   x[5]  = rol32(x[5]  ^ x[9],  12);
++		x[10] += x[14];   x[6]  = rol32(x[6]  ^ x[10], 12);
++		x[11] += x[15];   x[7]  = rol32(x[7]  ^ x[11], 12);
++
++		x[0]  += x[4];    x[12] = rol32(x[12] ^ x[0],   8);
++		x[1]  += x[5];    x[13] = rol32(x[13] ^ x[1],   8);
++		x[2]  += x[6];    x[14] = rol32(x[14] ^ x[2],   8);
++		x[3]  += x[7];    x[15] = rol32(x[15] ^ x[3],   8);
++
++		x[8]  += x[12];   x[4]  = rol32(x[4]  ^ x[8],   7);
++		x[9]  += x[13];   x[5]  = rol32(x[5]  ^ x[9],   7);
++		x[10] += x[14];   x[6]  = rol32(x[6]  ^ x[10],  7);
++		x[11] += x[15];   x[7]  = rol32(x[7]  ^ x[11],  7);
++
++		x[0]  += x[5];    x[15] = rol32(x[15] ^ x[0],  16);
++		x[1]  += x[6];    x[12] = rol32(x[12] ^ x[1],  16);
++		x[2]  += x[7];    x[13] = rol32(x[13] ^ x[2],  16);
++		x[3]  += x[4];    x[14] = rol32(x[14] ^ x[3],  16);
++
++		x[10] += x[15];   x[5]  = rol32(x[5]  ^ x[10], 12);
++		x[11] += x[12];   x[6]  = rol32(x[6]  ^ x[11], 12);
++		x[8]  += x[13];   x[7]  = rol32(x[7]  ^ x[8],  12);
++		x[9]  += x[14];   x[4]  = rol32(x[4]  ^ x[9],  12);
++
++		x[0]  += x[5];    x[15] = rol32(x[15] ^ x[0],   8);
++		x[1]  += x[6];    x[12] = rol32(x[12] ^ x[1],   8);
++		x[2]  += x[7];    x[13] = rol32(x[13] ^ x[2],   8);
++		x[3]  += x[4];    x[14] = rol32(x[14] ^ x[3],   8);
++
++		x[10] += x[15];   x[5]  = rol32(x[5]  ^ x[10],  7);
++		x[11] += x[12];   x[6]  = rol32(x[6]  ^ x[11],  7);
++		x[8]  += x[13];   x[7]  = rol32(x[7]  ^ x[8],   7);
++		x[9]  += x[14];   x[4]  = rol32(x[4]  ^ x[9],   7);
++	}
++}
++
++/**
++ * chacha_block - generate one keystream block and increment block counter
++ * @state: input state matrix (16 32-bit words)
++ * @stream: output keystream block (64 bytes)
++ * @nrounds: number of rounds (20 or 12; 20 is recommended)
++ *
++ * This is the ChaCha core, a function from 64-byte strings to 64-byte strings.
++ * The caller has already converted the endianness of the input.  This function
++ * also handles incrementing the block counter in the input matrix.
++ */
++void chacha_block_generic(u32 *state, u8 *stream, int nrounds)
++{
++	u32 x[16];
++	int i;
++
++	memcpy(x, state, 64);
++
++	chacha_permute(x, nrounds);
++
++	for (i = 0; i < ARRAY_SIZE(x); i++)
++		put_unaligned_le32(x[i] + state[i], &stream[i * sizeof(u32)]);
++
++	state[12]++;
++}
++EXPORT_SYMBOL(chacha_block_generic);
++
++/**
++ * hchacha_block_generic - abbreviated ChaCha core, for XChaCha
++ * @state: input state matrix (16 32-bit words)
++ * @out: output (8 32-bit words)
++ * @nrounds: number of rounds (20 or 12; 20 is recommended)
++ *
++ * HChaCha is the ChaCha equivalent of HSalsa and is an intermediate step
++ * towards XChaCha (see https://cr.yp.to/snuffle/xsalsa-20081128.pdf).  HChaCha
++ * skips the final addition of the initial state, and outputs only certain words
++ * of the state.  It should not be used for streaming directly.
++ */
++void hchacha_block_generic(const u32 *state, u32 *stream, int nrounds)
++{
++	u32 x[16];
++
++	memcpy(x, state, 64);
++
++	chacha_permute(x, nrounds);
++
++	memcpy(&stream[0], &x[0], 16);
++	memcpy(&stream[4], &x[12], 16);
++}
++EXPORT_SYMBOL(hchacha_block_generic);
+--- /dev/null
++++ b/lib/crypto/libchacha.c
+@@ -0,0 +1,35 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * The ChaCha stream cipher (RFC7539)
++ *
++ * Copyright (C) 2015 Martin Willi
++ */
++
++#include <linux/kernel.h>
++#include <linux/export.h>
++#include <linux/module.h>
++
++#include <crypto/algapi.h> // for crypto_xor_cpy
++#include <crypto/chacha.h>
++
++void chacha_crypt_generic(u32 *state, u8 *dst, const u8 *src,
++			  unsigned int bytes, int nrounds)
++{
++	/* aligned to potentially speed up crypto_xor() */
++	u8 stream[CHACHA_BLOCK_SIZE] __aligned(sizeof(long));
++
++	while (bytes >= CHACHA_BLOCK_SIZE) {
++		chacha_block_generic(state, stream, nrounds);
++		crypto_xor_cpy(dst, src, stream, CHACHA_BLOCK_SIZE);
++		bytes -= CHACHA_BLOCK_SIZE;
++		dst += CHACHA_BLOCK_SIZE;
++		src += CHACHA_BLOCK_SIZE;
++	}
++	if (bytes) {
++		chacha_block_generic(state, stream, nrounds);
++		crypto_xor_cpy(dst, src, stream, bytes);
++	}
++}
++EXPORT_SYMBOL(chacha_crypt_generic);
++
++MODULE_LICENSE("GPL");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0003-crypto-x86-chacha-depend-on-generic-chacha-library-i.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0003-crypto-x86-chacha-depend-on-generic-chacha-library-i.patch
new file mode 100644
index 0000000..b1f59cc
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0003-crypto-x86-chacha-depend-on-generic-chacha-library-i.patch
@@ -0,0 +1,192 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:09 +0100
+Subject: [PATCH] crypto: x86/chacha - depend on generic chacha library instead
+ of crypto driver
+
+commit 28e8d89b1ce8d2e7badfb5f69971dd635acb8863 upstream.
+
+In preparation of extending the x86 ChaCha driver to also expose the ChaCha
+library interface, drop the dependency on the chacha_generic crypto driver
+as a non-SIMD fallback, and depend on the generic ChaCha library directly.
+This way, we only pull in the code we actually need, without registering
+a set of ChaCha skciphers that we will never use.
+
+Since turning the FPU on and off is cheap these days, simplify the SIMD
+routine by dropping the per-page yield, which makes for a cleaner switch
+to the library API as well. This also allows use to invoke the skcipher
+walk routines in non-atomic mode.
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/chacha_glue.c | 90 ++++++++++++++---------------------
+ crypto/Kconfig                |  2 +-
+ 2 files changed, 36 insertions(+), 56 deletions(-)
+
+--- a/arch/x86/crypto/chacha_glue.c
++++ b/arch/x86/crypto/chacha_glue.c
+@@ -123,37 +123,38 @@ static void chacha_dosimd(u32 *state, u8
+ 	}
+ }
+ 
+-static int chacha_simd_stream_xor(struct skcipher_walk *walk,
++static int chacha_simd_stream_xor(struct skcipher_request *req,
+ 				  const struct chacha_ctx *ctx, const u8 *iv)
+ {
+ 	u32 *state, state_buf[16 + 2] __aligned(8);
+-	int next_yield = 4096; /* bytes until next FPU yield */
+-	int err = 0;
++	struct skcipher_walk walk;
++	int err;
++
++	err = skcipher_walk_virt(&walk, req, false);
+ 
+ 	BUILD_BUG_ON(CHACHA_STATE_ALIGN != 16);
+ 	state = PTR_ALIGN(state_buf + 0, CHACHA_STATE_ALIGN);
+ 
+-	crypto_chacha_init(state, ctx, iv);
++	chacha_init_generic(state, ctx->key, iv);
+ 
+-	while (walk->nbytes > 0) {
+-		unsigned int nbytes = walk->nbytes;
++	while (walk.nbytes > 0) {
++		unsigned int nbytes = walk.nbytes;
+ 
+-		if (nbytes < walk->total) {
+-			nbytes = round_down(nbytes, walk->stride);
+-			next_yield -= nbytes;
+-		}
+-
+-		chacha_dosimd(state, walk->dst.virt.addr, walk->src.virt.addr,
+-			      nbytes, ctx->nrounds);
++		if (nbytes < walk.total)
++			nbytes = round_down(nbytes, walk.stride);
+ 
+-		if (next_yield <= 0) {
+-			/* temporarily allow preemption */
+-			kernel_fpu_end();
++		if (!crypto_simd_usable()) {
++			chacha_crypt_generic(state, walk.dst.virt.addr,
++					     walk.src.virt.addr, nbytes,
++					     ctx->nrounds);
++		} else {
+ 			kernel_fpu_begin();
+-			next_yield = 4096;
++			chacha_dosimd(state, walk.dst.virt.addr,
++				      walk.src.virt.addr, nbytes,
++				      ctx->nrounds);
++			kernel_fpu_end();
+ 		}
+-
+-		err = skcipher_walk_done(walk, walk->nbytes - nbytes);
++		err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
+ 	}
+ 
+ 	return err;
+@@ -163,55 +164,34 @@ static int chacha_simd(struct skcipher_r
+ {
+ 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ 	struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
+-	struct skcipher_walk walk;
+-	int err;
+-
+-	if (req->cryptlen <= CHACHA_BLOCK_SIZE || !crypto_simd_usable())
+-		return crypto_chacha_crypt(req);
+ 
+-	err = skcipher_walk_virt(&walk, req, true);
+-	if (err)
+-		return err;
+-
+-	kernel_fpu_begin();
+-	err = chacha_simd_stream_xor(&walk, ctx, req->iv);
+-	kernel_fpu_end();
+-	return err;
++	return chacha_simd_stream_xor(req, ctx, req->iv);
+ }
+ 
+ static int xchacha_simd(struct skcipher_request *req)
+ {
+ 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ 	struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
+-	struct skcipher_walk walk;
+-	struct chacha_ctx subctx;
+ 	u32 *state, state_buf[16 + 2] __aligned(8);
++	struct chacha_ctx subctx;
+ 	u8 real_iv[16];
+-	int err;
+-
+-	if (req->cryptlen <= CHACHA_BLOCK_SIZE || !crypto_simd_usable())
+-		return crypto_xchacha_crypt(req);
+-
+-	err = skcipher_walk_virt(&walk, req, true);
+-	if (err)
+-		return err;
+ 
+ 	BUILD_BUG_ON(CHACHA_STATE_ALIGN != 16);
+ 	state = PTR_ALIGN(state_buf + 0, CHACHA_STATE_ALIGN);
+-	crypto_chacha_init(state, ctx, req->iv);
++	chacha_init_generic(state, ctx->key, req->iv);
+ 
+-	kernel_fpu_begin();
+-
+-	hchacha_block_ssse3(state, subctx.key, ctx->nrounds);
++	if (req->cryptlen > CHACHA_BLOCK_SIZE && crypto_simd_usable()) {
++		kernel_fpu_begin();
++		hchacha_block_ssse3(state, subctx.key, ctx->nrounds);
++		kernel_fpu_end();
++	} else {
++		hchacha_block_generic(state, subctx.key, ctx->nrounds);
++	}
+ 	subctx.nrounds = ctx->nrounds;
+ 
+ 	memcpy(&real_iv[0], req->iv + 24, 8);
+ 	memcpy(&real_iv[8], req->iv + 16, 8);
+-	err = chacha_simd_stream_xor(&walk, &subctx, real_iv);
+-
+-	kernel_fpu_end();
+-
+-	return err;
++	return chacha_simd_stream_xor(req, &subctx, real_iv);
+ }
+ 
+ static struct skcipher_alg algs[] = {
+@@ -227,7 +207,7 @@ static struct skcipher_alg algs[] = {
+ 		.max_keysize		= CHACHA_KEY_SIZE,
+ 		.ivsize			= CHACHA_IV_SIZE,
+ 		.chunksize		= CHACHA_BLOCK_SIZE,
+-		.setkey			= crypto_chacha20_setkey,
++		.setkey			= chacha20_setkey,
+ 		.encrypt		= chacha_simd,
+ 		.decrypt		= chacha_simd,
+ 	}, {
+@@ -242,7 +222,7 @@ static struct skcipher_alg algs[] = {
+ 		.max_keysize		= CHACHA_KEY_SIZE,
+ 		.ivsize			= XCHACHA_IV_SIZE,
+ 		.chunksize		= CHACHA_BLOCK_SIZE,
+-		.setkey			= crypto_chacha20_setkey,
++		.setkey			= chacha20_setkey,
+ 		.encrypt		= xchacha_simd,
+ 		.decrypt		= xchacha_simd,
+ 	}, {
+@@ -257,7 +237,7 @@ static struct skcipher_alg algs[] = {
+ 		.max_keysize		= CHACHA_KEY_SIZE,
+ 		.ivsize			= XCHACHA_IV_SIZE,
+ 		.chunksize		= CHACHA_BLOCK_SIZE,
+-		.setkey			= crypto_chacha12_setkey,
++		.setkey			= chacha12_setkey,
+ 		.encrypt		= xchacha_simd,
+ 		.decrypt		= xchacha_simd,
+ 	},
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -1417,7 +1417,7 @@ config CRYPTO_CHACHA20_X86_64
+ 	tristate "ChaCha stream cipher algorithms (x86_64/SSSE3/AVX2/AVX-512VL)"
+ 	depends on X86 && 64BIT
+ 	select CRYPTO_BLKCIPHER
+-	select CRYPTO_CHACHA20
++	select CRYPTO_LIB_CHACHA_GENERIC
+ 	help
+ 	  SSSE3, AVX2, and AVX-512VL optimized implementations of the ChaCha20,
+ 	  XChaCha20, and XChaCha12 stream ciphers.
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0004-crypto-x86-chacha-expose-SIMD-ChaCha-routine-as-libr.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0004-crypto-x86-chacha-expose-SIMD-ChaCha-routine-as-libr.patch
new file mode 100644
index 0000000..0e54628
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0004-crypto-x86-chacha-expose-SIMD-ChaCha-routine-as-libr.patch
@@ -0,0 +1,205 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:10 +0100
+Subject: [PATCH] crypto: x86/chacha - expose SIMD ChaCha routine as library
+ function
+
+commit 84e03fa39fbe95a5567d43bff458c6d3b3a23ad1 upstream.
+
+Wire the existing x86 SIMD ChaCha code into the new ChaCha library
+interface, so that users of the library interface will get the
+accelerated version when available.
+
+Given that calls into the library API will always go through the
+routines in this module if it is enabled, switch to static keys
+to select the optimal implementation available (which may be none
+at all, in which case we defer to the generic implementation for
+all invocations).
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/chacha_glue.c | 91 +++++++++++++++++++++++++----------
+ crypto/Kconfig                |  1 +
+ include/crypto/chacha.h       |  6 +++
+ 3 files changed, 73 insertions(+), 25 deletions(-)
+
+--- a/arch/x86/crypto/chacha_glue.c
++++ b/arch/x86/crypto/chacha_glue.c
+@@ -21,24 +21,24 @@ asmlinkage void chacha_block_xor_ssse3(u
+ asmlinkage void chacha_4block_xor_ssse3(u32 *state, u8 *dst, const u8 *src,
+ 					unsigned int len, int nrounds);
+ asmlinkage void hchacha_block_ssse3(const u32 *state, u32 *out, int nrounds);
+-#ifdef CONFIG_AS_AVX2
++
+ asmlinkage void chacha_2block_xor_avx2(u32 *state, u8 *dst, const u8 *src,
+ 				       unsigned int len, int nrounds);
+ asmlinkage void chacha_4block_xor_avx2(u32 *state, u8 *dst, const u8 *src,
+ 				       unsigned int len, int nrounds);
+ asmlinkage void chacha_8block_xor_avx2(u32 *state, u8 *dst, const u8 *src,
+ 				       unsigned int len, int nrounds);
+-static bool chacha_use_avx2;
+-#ifdef CONFIG_AS_AVX512
++
+ asmlinkage void chacha_2block_xor_avx512vl(u32 *state, u8 *dst, const u8 *src,
+ 					   unsigned int len, int nrounds);
+ asmlinkage void chacha_4block_xor_avx512vl(u32 *state, u8 *dst, const u8 *src,
+ 					   unsigned int len, int nrounds);
+ asmlinkage void chacha_8block_xor_avx512vl(u32 *state, u8 *dst, const u8 *src,
+ 					   unsigned int len, int nrounds);
+-static bool chacha_use_avx512vl;
+-#endif
+-#endif
++
++static __ro_after_init DEFINE_STATIC_KEY_FALSE(chacha_use_simd);
++static __ro_after_init DEFINE_STATIC_KEY_FALSE(chacha_use_avx2);
++static __ro_after_init DEFINE_STATIC_KEY_FALSE(chacha_use_avx512vl);
+ 
+ static unsigned int chacha_advance(unsigned int len, unsigned int maxblocks)
+ {
+@@ -49,9 +49,8 @@ static unsigned int chacha_advance(unsig
+ static void chacha_dosimd(u32 *state, u8 *dst, const u8 *src,
+ 			  unsigned int bytes, int nrounds)
+ {
+-#ifdef CONFIG_AS_AVX2
+-#ifdef CONFIG_AS_AVX512
+-	if (chacha_use_avx512vl) {
++	if (IS_ENABLED(CONFIG_AS_AVX512) &&
++	    static_branch_likely(&chacha_use_avx512vl)) {
+ 		while (bytes >= CHACHA_BLOCK_SIZE * 8) {
+ 			chacha_8block_xor_avx512vl(state, dst, src, bytes,
+ 						   nrounds);
+@@ -79,8 +78,9 @@ static void chacha_dosimd(u32 *state, u8
+ 			return;
+ 		}
+ 	}
+-#endif
+-	if (chacha_use_avx2) {
++
++	if (IS_ENABLED(CONFIG_AS_AVX2) &&
++	    static_branch_likely(&chacha_use_avx2)) {
+ 		while (bytes >= CHACHA_BLOCK_SIZE * 8) {
+ 			chacha_8block_xor_avx2(state, dst, src, bytes, nrounds);
+ 			bytes -= CHACHA_BLOCK_SIZE * 8;
+@@ -104,7 +104,7 @@ static void chacha_dosimd(u32 *state, u8
+ 			return;
+ 		}
+ 	}
+-#endif
++
+ 	while (bytes >= CHACHA_BLOCK_SIZE * 4) {
+ 		chacha_4block_xor_ssse3(state, dst, src, bytes, nrounds);
+ 		bytes -= CHACHA_BLOCK_SIZE * 4;
+@@ -123,6 +123,43 @@ static void chacha_dosimd(u32 *state, u8
+ 	}
+ }
+ 
++void hchacha_block_arch(const u32 *state, u32 *stream, int nrounds)
++{
++	state = PTR_ALIGN(state, CHACHA_STATE_ALIGN);
++
++	if (!static_branch_likely(&chacha_use_simd) || !crypto_simd_usable()) {
++		hchacha_block_generic(state, stream, nrounds);
++	} else {
++		kernel_fpu_begin();
++		hchacha_block_ssse3(state, stream, nrounds);
++		kernel_fpu_end();
++	}
++}
++EXPORT_SYMBOL(hchacha_block_arch);
++
++void chacha_init_arch(u32 *state, const u32 *key, const u8 *iv)
++{
++	state = PTR_ALIGN(state, CHACHA_STATE_ALIGN);
++
++	chacha_init_generic(state, key, iv);
++}
++EXPORT_SYMBOL(chacha_init_arch);
++
++void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src, unsigned int bytes,
++		       int nrounds)
++{
++	state = PTR_ALIGN(state, CHACHA_STATE_ALIGN);
++
++	if (!static_branch_likely(&chacha_use_simd) || !crypto_simd_usable() ||
++	    bytes <= CHACHA_BLOCK_SIZE)
++		return chacha_crypt_generic(state, dst, src, bytes, nrounds);
++
++	kernel_fpu_begin();
++	chacha_dosimd(state, dst, src, bytes, nrounds);
++	kernel_fpu_end();
++}
++EXPORT_SYMBOL(chacha_crypt_arch);
++
+ static int chacha_simd_stream_xor(struct skcipher_request *req,
+ 				  const struct chacha_ctx *ctx, const u8 *iv)
+ {
+@@ -143,7 +180,8 @@ static int chacha_simd_stream_xor(struct
+ 		if (nbytes < walk.total)
+ 			nbytes = round_down(nbytes, walk.stride);
+ 
+-		if (!crypto_simd_usable()) {
++		if (!static_branch_likely(&chacha_use_simd) ||
++		    !crypto_simd_usable()) {
+ 			chacha_crypt_generic(state, walk.dst.virt.addr,
+ 					     walk.src.virt.addr, nbytes,
+ 					     ctx->nrounds);
+@@ -246,18 +284,21 @@ static struct skcipher_alg algs[] = {
+ static int __init chacha_simd_mod_init(void)
+ {
+ 	if (!boot_cpu_has(X86_FEATURE_SSSE3))
+-		return -ENODEV;
++		return 0;
+ 
+-#ifdef CONFIG_AS_AVX2
+-	chacha_use_avx2 = boot_cpu_has(X86_FEATURE_AVX) &&
+-			  boot_cpu_has(X86_FEATURE_AVX2) &&
+-			  cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL);
+-#ifdef CONFIG_AS_AVX512
+-	chacha_use_avx512vl = chacha_use_avx2 &&
+-			      boot_cpu_has(X86_FEATURE_AVX512VL) &&
+-			      boot_cpu_has(X86_FEATURE_AVX512BW); /* kmovq */
+-#endif
+-#endif
++	static_branch_enable(&chacha_use_simd);
++
++	if (IS_ENABLED(CONFIG_AS_AVX2) &&
++	    boot_cpu_has(X86_FEATURE_AVX) &&
++	    boot_cpu_has(X86_FEATURE_AVX2) &&
++	    cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL)) {
++		static_branch_enable(&chacha_use_avx2);
++
++		if (IS_ENABLED(CONFIG_AS_AVX512) &&
++		    boot_cpu_has(X86_FEATURE_AVX512VL) &&
++		    boot_cpu_has(X86_FEATURE_AVX512BW)) /* kmovq */
++			static_branch_enable(&chacha_use_avx512vl);
++	}
+ 	return crypto_register_skciphers(algs, ARRAY_SIZE(algs));
+ }
+ 
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -1418,6 +1418,7 @@ config CRYPTO_CHACHA20_X86_64
+ 	depends on X86 && 64BIT
+ 	select CRYPTO_BLKCIPHER
+ 	select CRYPTO_LIB_CHACHA_GENERIC
++	select CRYPTO_ARCH_HAVE_LIB_CHACHA
+ 	help
+ 	  SSSE3, AVX2, and AVX-512VL optimized implementations of the ChaCha20,
+ 	  XChaCha20, and XChaCha12 stream ciphers.
+--- a/include/crypto/chacha.h
++++ b/include/crypto/chacha.h
+@@ -25,6 +25,12 @@
+ #define CHACHA_BLOCK_SIZE	64
+ #define CHACHAPOLY_IV_SIZE	12
+ 
++#ifdef CONFIG_X86_64
++#define CHACHA_STATE_WORDS	((CHACHA_BLOCK_SIZE + 12) / sizeof(u32))
++#else
++#define CHACHA_STATE_WORDS	(CHACHA_BLOCK_SIZE / sizeof(u32))
++#endif
++
+ /* 192-bit nonce, then 64-bit stream position */
+ #define XCHACHA_IV_SIZE		32
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0005-crypto-arm64-chacha-depend-on-generic-chacha-library.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0005-crypto-arm64-chacha-depend-on-generic-chacha-library.patch
new file mode 100644
index 0000000..10e49c1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0005-crypto-arm64-chacha-depend-on-generic-chacha-library.patch
@@ -0,0 +1,129 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:11 +0100
+Subject: [PATCH] crypto: arm64/chacha - depend on generic chacha library
+ instead of crypto driver
+
+commit c77da4867cbb7841177275dbb250f5c09679fae4 upstream.
+
+Depend on the generic ChaCha library routines instead of pulling in the
+generic ChaCha skcipher driver, which is more than we need, and makes
+managing the dependencies between the generic library, generic driver,
+accelerated library and driver more complicated.
+
+While at it, drop the logic to prefer the scalar code on short inputs.
+Turning the NEON on and off is cheap these days, and one major use case
+for ChaCha20 is ChaCha20-Poly1305, which is guaranteed to hit the scalar
+path upon every invocation  (when doing the Poly1305 nonce generation)
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm64/crypto/Kconfig            |  2 +-
+ arch/arm64/crypto/chacha-neon-glue.c | 40 +++++++++++++++-------------
+ 2 files changed, 23 insertions(+), 19 deletions(-)
+
+--- a/arch/arm64/crypto/Kconfig
++++ b/arch/arm64/crypto/Kconfig
+@@ -103,7 +103,7 @@ config CRYPTO_CHACHA20_NEON
+ 	tristate "ChaCha20, XChaCha20, and XChaCha12 stream ciphers using NEON instructions"
+ 	depends on KERNEL_MODE_NEON
+ 	select CRYPTO_BLKCIPHER
+-	select CRYPTO_CHACHA20
++	select CRYPTO_LIB_CHACHA_GENERIC
+ 
+ config CRYPTO_NHPOLY1305_NEON
+ 	tristate "NHPoly1305 hash function using NEON instructions (for Adiantum)"
+--- a/arch/arm64/crypto/chacha-neon-glue.c
++++ b/arch/arm64/crypto/chacha-neon-glue.c
+@@ -68,7 +68,7 @@ static int chacha_neon_stream_xor(struct
+ 
+ 	err = skcipher_walk_virt(&walk, req, false);
+ 
+-	crypto_chacha_init(state, ctx, iv);
++	chacha_init_generic(state, ctx->key, iv);
+ 
+ 	while (walk.nbytes > 0) {
+ 		unsigned int nbytes = walk.nbytes;
+@@ -76,10 +76,16 @@ static int chacha_neon_stream_xor(struct
+ 		if (nbytes < walk.total)
+ 			nbytes = rounddown(nbytes, walk.stride);
+ 
+-		kernel_neon_begin();
+-		chacha_doneon(state, walk.dst.virt.addr, walk.src.virt.addr,
+-			      nbytes, ctx->nrounds);
+-		kernel_neon_end();
++		if (!crypto_simd_usable()) {
++			chacha_crypt_generic(state, walk.dst.virt.addr,
++					     walk.src.virt.addr, nbytes,
++					     ctx->nrounds);
++		} else {
++			kernel_neon_begin();
++			chacha_doneon(state, walk.dst.virt.addr,
++				      walk.src.virt.addr, nbytes, ctx->nrounds);
++			kernel_neon_end();
++		}
+ 		err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
+ 	}
+ 
+@@ -91,9 +97,6 @@ static int chacha_neon(struct skcipher_r
+ 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ 	struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
+ 
+-	if (req->cryptlen <= CHACHA_BLOCK_SIZE || !crypto_simd_usable())
+-		return crypto_chacha_crypt(req);
+-
+ 	return chacha_neon_stream_xor(req, ctx, req->iv);
+ }
+ 
+@@ -105,14 +108,15 @@ static int xchacha_neon(struct skcipher_
+ 	u32 state[16];
+ 	u8 real_iv[16];
+ 
+-	if (req->cryptlen <= CHACHA_BLOCK_SIZE || !crypto_simd_usable())
+-		return crypto_xchacha_crypt(req);
+-
+-	crypto_chacha_init(state, ctx, req->iv);
++	chacha_init_generic(state, ctx->key, req->iv);
+ 
+-	kernel_neon_begin();
+-	hchacha_block_neon(state, subctx.key, ctx->nrounds);
+-	kernel_neon_end();
++	if (crypto_simd_usable()) {
++		kernel_neon_begin();
++		hchacha_block_neon(state, subctx.key, ctx->nrounds);
++		kernel_neon_end();
++	} else {
++		hchacha_block_generic(state, subctx.key, ctx->nrounds);
++	}
+ 	subctx.nrounds = ctx->nrounds;
+ 
+ 	memcpy(&real_iv[0], req->iv + 24, 8);
+@@ -134,7 +138,7 @@ static struct skcipher_alg algs[] = {
+ 		.ivsize			= CHACHA_IV_SIZE,
+ 		.chunksize		= CHACHA_BLOCK_SIZE,
+ 		.walksize		= 5 * CHACHA_BLOCK_SIZE,
+-		.setkey			= crypto_chacha20_setkey,
++		.setkey			= chacha20_setkey,
+ 		.encrypt		= chacha_neon,
+ 		.decrypt		= chacha_neon,
+ 	}, {
+@@ -150,7 +154,7 @@ static struct skcipher_alg algs[] = {
+ 		.ivsize			= XCHACHA_IV_SIZE,
+ 		.chunksize		= CHACHA_BLOCK_SIZE,
+ 		.walksize		= 5 * CHACHA_BLOCK_SIZE,
+-		.setkey			= crypto_chacha20_setkey,
++		.setkey			= chacha20_setkey,
+ 		.encrypt		= xchacha_neon,
+ 		.decrypt		= xchacha_neon,
+ 	}, {
+@@ -166,7 +170,7 @@ static struct skcipher_alg algs[] = {
+ 		.ivsize			= XCHACHA_IV_SIZE,
+ 		.chunksize		= CHACHA_BLOCK_SIZE,
+ 		.walksize		= 5 * CHACHA_BLOCK_SIZE,
+-		.setkey			= crypto_chacha12_setkey,
++		.setkey			= chacha12_setkey,
+ 		.encrypt		= xchacha_neon,
+ 		.decrypt		= xchacha_neon,
+ 	}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0006-crypto-arm64-chacha-expose-arm64-ChaCha-routine-as-l.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0006-crypto-arm64-chacha-expose-arm64-ChaCha-routine-as-l.patch
new file mode 100644
index 0000000..71665e8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0006-crypto-arm64-chacha-expose-arm64-ChaCha-routine-as-l.patch
@@ -0,0 +1,138 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:12 +0100
+Subject: [PATCH] crypto: arm64/chacha - expose arm64 ChaCha routine as library
+ function
+
+commit b3aad5bad26a01a4bd8c49a5c5f52aec665f3b7c upstream.
+
+Expose the accelerated NEON ChaCha routine directly as a symbol
+export so that users of the ChaCha library API can use it directly.
+
+Given that calls into the library API will always go through the
+routines in this module if it is enabled, switch to static keys
+to select the optimal implementation available (which may be none
+at all, in which case we defer to the generic implementation for
+all invocations).
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm64/crypto/Kconfig            |  1 +
+ arch/arm64/crypto/chacha-neon-glue.c | 53 ++++++++++++++++++++++------
+ 2 files changed, 43 insertions(+), 11 deletions(-)
+
+--- a/arch/arm64/crypto/Kconfig
++++ b/arch/arm64/crypto/Kconfig
+@@ -104,6 +104,7 @@ config CRYPTO_CHACHA20_NEON
+ 	depends on KERNEL_MODE_NEON
+ 	select CRYPTO_BLKCIPHER
+ 	select CRYPTO_LIB_CHACHA_GENERIC
++	select CRYPTO_ARCH_HAVE_LIB_CHACHA
+ 
+ config CRYPTO_NHPOLY1305_NEON
+ 	tristate "NHPoly1305 hash function using NEON instructions (for Adiantum)"
+--- a/arch/arm64/crypto/chacha-neon-glue.c
++++ b/arch/arm64/crypto/chacha-neon-glue.c
+@@ -23,6 +23,7 @@
+ #include <crypto/internal/chacha.h>
+ #include <crypto/internal/simd.h>
+ #include <crypto/internal/skcipher.h>
++#include <linux/jump_label.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ 
+@@ -36,6 +37,8 @@ asmlinkage void chacha_4block_xor_neon(u
+ 				       int nrounds, int bytes);
+ asmlinkage void hchacha_block_neon(const u32 *state, u32 *out, int nrounds);
+ 
++static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon);
++
+ static void chacha_doneon(u32 *state, u8 *dst, const u8 *src,
+ 			  int bytes, int nrounds)
+ {
+@@ -59,6 +62,37 @@ static void chacha_doneon(u32 *state, u8
+ 	}
+ }
+ 
++void hchacha_block_arch(const u32 *state, u32 *stream, int nrounds)
++{
++	if (!static_branch_likely(&have_neon) || !crypto_simd_usable()) {
++		hchacha_block_generic(state, stream, nrounds);
++	} else {
++		kernel_neon_begin();
++		hchacha_block_neon(state, stream, nrounds);
++		kernel_neon_end();
++	}
++}
++EXPORT_SYMBOL(hchacha_block_arch);
++
++void chacha_init_arch(u32 *state, const u32 *key, const u8 *iv)
++{
++	chacha_init_generic(state, key, iv);
++}
++EXPORT_SYMBOL(chacha_init_arch);
++
++void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src, unsigned int bytes,
++		       int nrounds)
++{
++	if (!static_branch_likely(&have_neon) || bytes <= CHACHA_BLOCK_SIZE ||
++	    !crypto_simd_usable())
++		return chacha_crypt_generic(state, dst, src, bytes, nrounds);
++
++	kernel_neon_begin();
++	chacha_doneon(state, dst, src, bytes, nrounds);
++	kernel_neon_end();
++}
++EXPORT_SYMBOL(chacha_crypt_arch);
++
+ static int chacha_neon_stream_xor(struct skcipher_request *req,
+ 				  const struct chacha_ctx *ctx, const u8 *iv)
+ {
+@@ -76,7 +110,8 @@ static int chacha_neon_stream_xor(struct
+ 		if (nbytes < walk.total)
+ 			nbytes = rounddown(nbytes, walk.stride);
+ 
+-		if (!crypto_simd_usable()) {
++		if (!static_branch_likely(&have_neon) ||
++		    !crypto_simd_usable()) {
+ 			chacha_crypt_generic(state, walk.dst.virt.addr,
+ 					     walk.src.virt.addr, nbytes,
+ 					     ctx->nrounds);
+@@ -109,14 +144,7 @@ static int xchacha_neon(struct skcipher_
+ 	u8 real_iv[16];
+ 
+ 	chacha_init_generic(state, ctx->key, req->iv);
+-
+-	if (crypto_simd_usable()) {
+-		kernel_neon_begin();
+-		hchacha_block_neon(state, subctx.key, ctx->nrounds);
+-		kernel_neon_end();
+-	} else {
+-		hchacha_block_generic(state, subctx.key, ctx->nrounds);
+-	}
++	hchacha_block_arch(state, subctx.key, ctx->nrounds);
+ 	subctx.nrounds = ctx->nrounds;
+ 
+ 	memcpy(&real_iv[0], req->iv + 24, 8);
+@@ -179,14 +207,17 @@ static struct skcipher_alg algs[] = {
+ static int __init chacha_simd_mod_init(void)
+ {
+ 	if (!cpu_have_named_feature(ASIMD))
+-		return -ENODEV;
++		return 0;
++
++	static_branch_enable(&have_neon);
+ 
+ 	return crypto_register_skciphers(algs, ARRAY_SIZE(algs));
+ }
+ 
+ static void __exit chacha_simd_mod_fini(void)
+ {
+-	crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
++	if (cpu_have_named_feature(ASIMD))
++		crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
+ }
+ 
+ module_init(chacha_simd_mod_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0007-crypto-arm-chacha-import-Eric-Biggers-s-scalar-accel.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0007-crypto-arm-chacha-import-Eric-Biggers-s-scalar-accel.patch
new file mode 100644
index 0000000..978f2f5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0007-crypto-arm-chacha-import-Eric-Biggers-s-scalar-accel.patch
@@ -0,0 +1,480 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:13 +0100
+Subject: [PATCH] crypto: arm/chacha - import Eric Biggers's scalar accelerated
+ ChaCha code
+
+commit 29621d099f9c642b22a69dc8e7e20c108473a392 upstream.
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm/crypto/chacha-scalar-core.S | 461 +++++++++++++++++++++++++++
+ 1 file changed, 461 insertions(+)
+ create mode 100644 arch/arm/crypto/chacha-scalar-core.S
+
+--- /dev/null
++++ b/arch/arm/crypto/chacha-scalar-core.S
+@@ -0,0 +1,461 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2018 Google, Inc.
++ */
++
++#include <linux/linkage.h>
++#include <asm/assembler.h>
++
++/*
++ * Design notes:
++ *
++ * 16 registers would be needed to hold the state matrix, but only 14 are
++ * available because 'sp' and 'pc' cannot be used.  So we spill the elements
++ * (x8, x9) to the stack and swap them out with (x10, x11).  This adds one
++ * 'ldrd' and one 'strd' instruction per round.
++ *
++ * All rotates are performed using the implicit rotate operand accepted by the
++ * 'add' and 'eor' instructions.  This is faster than using explicit rotate
++ * instructions.  To make this work, we allow the values in the second and last
++ * rows of the ChaCha state matrix (rows 'b' and 'd') to temporarily have the
++ * wrong rotation amount.  The rotation amount is then fixed up just in time
++ * when the values are used.  'brot' is the number of bits the values in row 'b'
++ * need to be rotated right to arrive at the correct values, and 'drot'
++ * similarly for row 'd'.  (brot, drot) start out as (0, 0) but we make it such
++ * that they end up as (25, 24) after every round.
++ */
++
++	// ChaCha state registers
++	X0	.req	r0
++	X1	.req	r1
++	X2	.req	r2
++	X3	.req	r3
++	X4	.req	r4
++	X5	.req	r5
++	X6	.req	r6
++	X7	.req	r7
++	X8_X10	.req	r8	// shared by x8 and x10
++	X9_X11	.req	r9	// shared by x9 and x11
++	X12	.req	r10
++	X13	.req	r11
++	X14	.req	r12
++	X15	.req	r14
++
++.Lexpand_32byte_k:
++	// "expand 32-byte k"
++	.word	0x61707865, 0x3320646e, 0x79622d32, 0x6b206574
++
++#ifdef __thumb2__
++#  define adrl adr
++#endif
++
++.macro __rev		out, in,  t0, t1, t2
++.if __LINUX_ARM_ARCH__ >= 6
++	rev		\out, \in
++.else
++	lsl		\t0, \in, #24
++	and		\t1, \in, #0xff00
++	and		\t2, \in, #0xff0000
++	orr		\out, \t0, \in, lsr #24
++	orr		\out, \out, \t1, lsl #8
++	orr		\out, \out, \t2, lsr #8
++.endif
++.endm
++
++.macro _le32_bswap	x,  t0, t1, t2
++#ifdef __ARMEB__
++	__rev		\x, \x,  \t0, \t1, \t2
++#endif
++.endm
++
++.macro _le32_bswap_4x	a, b, c, d,  t0, t1, t2
++	_le32_bswap	\a,  \t0, \t1, \t2
++	_le32_bswap	\b,  \t0, \t1, \t2
++	_le32_bswap	\c,  \t0, \t1, \t2
++	_le32_bswap	\d,  \t0, \t1, \t2
++.endm
++
++.macro __ldrd		a, b, src, offset
++#if __LINUX_ARM_ARCH__ >= 6
++	ldrd		\a, \b, [\src, #\offset]
++#else
++	ldr		\a, [\src, #\offset]
++	ldr		\b, [\src, #\offset + 4]
++#endif
++.endm
++
++.macro __strd		a, b, dst, offset
++#if __LINUX_ARM_ARCH__ >= 6
++	strd		\a, \b, [\dst, #\offset]
++#else
++	str		\a, [\dst, #\offset]
++	str		\b, [\dst, #\offset + 4]
++#endif
++.endm
++
++.macro _halfround	a1, b1, c1, d1,  a2, b2, c2, d2
++
++	// a += b; d ^= a; d = rol(d, 16);
++	add		\a1, \a1, \b1, ror #brot
++	add		\a2, \a2, \b2, ror #brot
++	eor		\d1, \a1, \d1, ror #drot
++	eor		\d2, \a2, \d2, ror #drot
++	// drot == 32 - 16 == 16
++
++	// c += d; b ^= c; b = rol(b, 12);
++	add		\c1, \c1, \d1, ror #16
++	add		\c2, \c2, \d2, ror #16
++	eor		\b1, \c1, \b1, ror #brot
++	eor		\b2, \c2, \b2, ror #brot
++	// brot == 32 - 12 == 20
++
++	// a += b; d ^= a; d = rol(d, 8);
++	add		\a1, \a1, \b1, ror #20
++	add		\a2, \a2, \b2, ror #20
++	eor		\d1, \a1, \d1, ror #16
++	eor		\d2, \a2, \d2, ror #16
++	// drot == 32 - 8 == 24
++
++	// c += d; b ^= c; b = rol(b, 7);
++	add		\c1, \c1, \d1, ror #24
++	add		\c2, \c2, \d2, ror #24
++	eor		\b1, \c1, \b1, ror #20
++	eor		\b2, \c2, \b2, ror #20
++	// brot == 32 - 7 == 25
++.endm
++
++.macro _doubleround
++
++	// column round
++
++	// quarterrounds: (x0, x4, x8, x12) and (x1, x5, x9, x13)
++	_halfround	X0, X4, X8_X10, X12,  X1, X5, X9_X11, X13
++
++	// save (x8, x9); restore (x10, x11)
++	__strd		X8_X10, X9_X11, sp, 0
++	__ldrd		X8_X10, X9_X11, sp, 8
++
++	// quarterrounds: (x2, x6, x10, x14) and (x3, x7, x11, x15)
++	_halfround	X2, X6, X8_X10, X14,  X3, X7, X9_X11, X15
++
++	.set brot, 25
++	.set drot, 24
++
++	// diagonal round
++
++	// quarterrounds: (x0, x5, x10, x15) and (x1, x6, x11, x12)
++	_halfround	X0, X5, X8_X10, X15,  X1, X6, X9_X11, X12
++
++	// save (x10, x11); restore (x8, x9)
++	__strd		X8_X10, X9_X11, sp, 8
++	__ldrd		X8_X10, X9_X11, sp, 0
++
++	// quarterrounds: (x2, x7, x8, x13) and (x3, x4, x9, x14)
++	_halfround	X2, X7, X8_X10, X13,  X3, X4, X9_X11, X14
++.endm
++
++.macro _chacha_permute	nrounds
++	.set brot, 0
++	.set drot, 0
++	.rept \nrounds / 2
++	 _doubleround
++	.endr
++.endm
++
++.macro _chacha		nrounds
++
++.Lnext_block\@:
++	// Stack: unused0-unused1 x10-x11 x0-x15 OUT IN LEN
++	// Registers contain x0-x9,x12-x15.
++
++	// Do the core ChaCha permutation to update x0-x15.
++	_chacha_permute	\nrounds
++
++	add		sp, #8
++	// Stack: x10-x11 orig_x0-orig_x15 OUT IN LEN
++	// Registers contain x0-x9,x12-x15.
++	// x4-x7 are rotated by 'brot'; x12-x15 are rotated by 'drot'.
++
++	// Free up some registers (r8-r12,r14) by pushing (x8-x9,x12-x15).
++	push		{X8_X10, X9_X11, X12, X13, X14, X15}
++
++	// Load (OUT, IN, LEN).
++	ldr		r14, [sp, #96]
++	ldr		r12, [sp, #100]
++	ldr		r11, [sp, #104]
++
++	orr		r10, r14, r12
++
++	// Use slow path if fewer than 64 bytes remain.
++	cmp		r11, #64
++	blt		.Lxor_slowpath\@
++
++	// Use slow path if IN and/or OUT isn't 4-byte aligned.  Needed even on
++	// ARMv6+, since ldmia and stmia (used below) still require alignment.
++	tst		r10, #3
++	bne		.Lxor_slowpath\@
++
++	// Fast path: XOR 64 bytes of aligned data.
++
++	// Stack: x8-x9 x12-x15 x10-x11 orig_x0-orig_x15 OUT IN LEN
++	// Registers: r0-r7 are x0-x7; r8-r11 are free; r12 is IN; r14 is OUT.
++	// x4-x7 are rotated by 'brot'; x12-x15 are rotated by 'drot'.
++
++	// x0-x3
++	__ldrd		r8, r9, sp, 32
++	__ldrd		r10, r11, sp, 40
++	add		X0, X0, r8
++	add		X1, X1, r9
++	add		X2, X2, r10
++	add		X3, X3, r11
++	_le32_bswap_4x	X0, X1, X2, X3,  r8, r9, r10
++	ldmia		r12!, {r8-r11}
++	eor		X0, X0, r8
++	eor		X1, X1, r9
++	eor		X2, X2, r10
++	eor		X3, X3, r11
++	stmia		r14!, {X0-X3}
++
++	// x4-x7
++	__ldrd		r8, r9, sp, 48
++	__ldrd		r10, r11, sp, 56
++	add		X4, r8, X4, ror #brot
++	add		X5, r9, X5, ror #brot
++	ldmia		r12!, {X0-X3}
++	add		X6, r10, X6, ror #brot
++	add		X7, r11, X7, ror #brot
++	_le32_bswap_4x	X4, X5, X6, X7,  r8, r9, r10
++	eor		X4, X4, X0
++	eor		X5, X5, X1
++	eor		X6, X6, X2
++	eor		X7, X7, X3
++	stmia		r14!, {X4-X7}
++
++	// x8-x15
++	pop		{r0-r7}			// (x8-x9,x12-x15,x10-x11)
++	__ldrd		r8, r9, sp, 32
++	__ldrd		r10, r11, sp, 40
++	add		r0, r0, r8		// x8
++	add		r1, r1, r9		// x9
++	add		r6, r6, r10		// x10
++	add		r7, r7, r11		// x11
++	_le32_bswap_4x	r0, r1, r6, r7,  r8, r9, r10
++	ldmia		r12!, {r8-r11}
++	eor		r0, r0, r8		// x8
++	eor		r1, r1, r9		// x9
++	eor		r6, r6, r10		// x10
++	eor		r7, r7, r11		// x11
++	stmia		r14!, {r0,r1,r6,r7}
++	ldmia		r12!, {r0,r1,r6,r7}
++	__ldrd		r8, r9, sp, 48
++	__ldrd		r10, r11, sp, 56
++	add		r2, r8, r2, ror #drot	// x12
++	add		r3, r9, r3, ror #drot	// x13
++	add		r4, r10, r4, ror #drot	// x14
++	add		r5, r11, r5, ror #drot	// x15
++	_le32_bswap_4x	r2, r3, r4, r5,  r9, r10, r11
++	  ldr		r9, [sp, #72]		// load LEN
++	eor		r2, r2, r0		// x12
++	eor		r3, r3, r1		// x13
++	eor		r4, r4, r6		// x14
++	eor		r5, r5, r7		// x15
++	  subs		r9, #64			// decrement and check LEN
++	stmia		r14!, {r2-r5}
++
++	beq		.Ldone\@
++
++.Lprepare_for_next_block\@:
++
++	// Stack: x0-x15 OUT IN LEN
++
++	// Increment block counter (x12)
++	add		r8, #1
++
++	// Store updated (OUT, IN, LEN)
++	str		r14, [sp, #64]
++	str		r12, [sp, #68]
++	str		r9, [sp, #72]
++
++	  mov		r14, sp
++
++	// Store updated block counter (x12)
++	str		r8, [sp, #48]
++
++	  sub		sp, #16
++
++	// Reload state and do next block
++	ldmia		r14!, {r0-r11}		// load x0-x11
++	__strd		r10, r11, sp, 8		// store x10-x11 before state
++	ldmia		r14, {r10-r12,r14}	// load x12-x15
++	b		.Lnext_block\@
++
++.Lxor_slowpath\@:
++	// Slow path: < 64 bytes remaining, or unaligned input or output buffer.
++	// We handle it by storing the 64 bytes of keystream to the stack, then
++	// XOR-ing the needed portion with the data.
++
++	// Allocate keystream buffer
++	sub		sp, #64
++	mov		r14, sp
++
++	// Stack: ks0-ks15 x8-x9 x12-x15 x10-x11 orig_x0-orig_x15 OUT IN LEN
++	// Registers: r0-r7 are x0-x7; r8-r11 are free; r12 is IN; r14 is &ks0.
++	// x4-x7 are rotated by 'brot'; x12-x15 are rotated by 'drot'.
++
++	// Save keystream for x0-x3
++	__ldrd		r8, r9, sp, 96
++	__ldrd		r10, r11, sp, 104
++	add		X0, X0, r8
++	add		X1, X1, r9
++	add		X2, X2, r10
++	add		X3, X3, r11
++	_le32_bswap_4x	X0, X1, X2, X3,  r8, r9, r10
++	stmia		r14!, {X0-X3}
++
++	// Save keystream for x4-x7
++	__ldrd		r8, r9, sp, 112
++	__ldrd		r10, r11, sp, 120
++	add		X4, r8, X4, ror #brot
++	add		X5, r9, X5, ror #brot
++	add		X6, r10, X6, ror #brot
++	add		X7, r11, X7, ror #brot
++	_le32_bswap_4x	X4, X5, X6, X7,  r8, r9, r10
++	  add		r8, sp, #64
++	stmia		r14!, {X4-X7}
++
++	// Save keystream for x8-x15
++	ldm		r8, {r0-r7}		// (x8-x9,x12-x15,x10-x11)
++	__ldrd		r8, r9, sp, 128
++	__ldrd		r10, r11, sp, 136
++	add		r0, r0, r8		// x8
++	add		r1, r1, r9		// x9
++	add		r6, r6, r10		// x10
++	add		r7, r7, r11		// x11
++	_le32_bswap_4x	r0, r1, r6, r7,  r8, r9, r10
++	stmia		r14!, {r0,r1,r6,r7}
++	__ldrd		r8, r9, sp, 144
++	__ldrd		r10, r11, sp, 152
++	add		r2, r8, r2, ror #drot	// x12
++	add		r3, r9, r3, ror #drot	// x13
++	add		r4, r10, r4, ror #drot	// x14
++	add		r5, r11, r5, ror #drot	// x15
++	_le32_bswap_4x	r2, r3, r4, r5,  r9, r10, r11
++	stmia		r14, {r2-r5}
++
++	// Stack: ks0-ks15 unused0-unused7 x0-x15 OUT IN LEN
++	// Registers: r8 is block counter, r12 is IN.
++
++	ldr		r9, [sp, #168]		// LEN
++	ldr		r14, [sp, #160]		// OUT
++	cmp		r9, #64
++	  mov		r0, sp
++	movle		r1, r9
++	movgt		r1, #64
++	// r1 is number of bytes to XOR, in range [1, 64]
++
++.if __LINUX_ARM_ARCH__ < 6
++	orr		r2, r12, r14
++	tst		r2, #3			// IN or OUT misaligned?
++	bne		.Lxor_next_byte\@
++.endif
++
++	// XOR a word at a time
++.rept 16
++	subs		r1, #4
++	blt		.Lxor_words_done\@
++	ldr		r2, [r12], #4
++	ldr		r3, [r0], #4
++	eor		r2, r2, r3
++	str		r2, [r14], #4
++.endr
++	b		.Lxor_slowpath_done\@
++.Lxor_words_done\@:
++	ands		r1, r1, #3
++	beq		.Lxor_slowpath_done\@
++
++	// XOR a byte at a time
++.Lxor_next_byte\@:
++	ldrb		r2, [r12], #1
++	ldrb		r3, [r0], #1
++	eor		r2, r2, r3
++	strb		r2, [r14], #1
++	subs		r1, #1
++	bne		.Lxor_next_byte\@
++
++.Lxor_slowpath_done\@:
++	subs		r9, #64
++	add		sp, #96
++	bgt		.Lprepare_for_next_block\@
++
++.Ldone\@:
++.endm	// _chacha
++
++/*
++ * void chacha20_arm(u8 *out, const u8 *in, size_t len, const u32 key[8],
++ *		     const u32 iv[4]);
++ */
++ENTRY(chacha20_arm)
++	cmp		r2, #0			// len == 0?
++	reteq		lr
++
++	push		{r0-r2,r4-r11,lr}
++
++	// Push state x0-x15 onto stack.
++	// Also store an extra copy of x10-x11 just before the state.
++
++	ldr		r4, [sp, #48]		// iv
++	mov		r0, sp
++	sub		sp, #80
++
++	// iv: x12-x15
++	ldm		r4, {X12,X13,X14,X15}
++	stmdb		r0!, {X12,X13,X14,X15}
++
++	// key: x4-x11
++	__ldrd		X8_X10, X9_X11, r3, 24
++	__strd		X8_X10, X9_X11, sp, 8
++	stmdb		r0!, {X8_X10, X9_X11}
++	ldm		r3, {X4-X9_X11}
++	stmdb		r0!, {X4-X9_X11}
++
++	// constants: x0-x3
++	adrl		X3, .Lexpand_32byte_k
++	ldm		X3, {X0-X3}
++	__strd		X0, X1, sp, 16
++	__strd		X2, X3, sp, 24
++
++	_chacha		20
++
++	add		sp, #76
++	pop		{r4-r11, pc}
++ENDPROC(chacha20_arm)
++
++/*
++ * void hchacha20_arm(const u32 state[16], u32 out[8]);
++ */
++ENTRY(hchacha20_arm)
++	push		{r1,r4-r11,lr}
++
++	mov		r14, r0
++	ldmia		r14!, {r0-r11}		// load x0-x11
++	push		{r10-r11}		// store x10-x11 to stack
++	ldm		r14, {r10-r12,r14}	// load x12-x15
++	sub		sp, #8
++
++	_chacha_permute	20
++
++	// Skip over (unused0-unused1, x10-x11)
++	add		sp, #16
++
++	// Fix up rotations of x12-x15
++	ror		X12, X12, #drot
++	ror		X13, X13, #drot
++	  pop		{r4}			// load 'out'
++	ror		X14, X14, #drot
++	ror		X15, X15, #drot
++
++	// Store (x0-x3,x12-x15) to 'out'
++	stm		r4, {X0,X1,X2,X3,X12,X13,X14,X15}
++
++	pop		{r4-r11,pc}
++ENDPROC(hchacha20_arm)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0008-crypto-arm-chacha-remove-dependency-on-generic-ChaCh.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0008-crypto-arm-chacha-remove-dependency-on-generic-ChaCh.patch
new file mode 100644
index 0000000..88c9738
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0008-crypto-arm-chacha-remove-dependency-on-generic-ChaCh.patch
@@ -0,0 +1,691 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:14 +0100
+Subject: [PATCH] crypto: arm/chacha - remove dependency on generic ChaCha
+ driver
+
+commit b36d8c09e710c71f6a9690b6586fea2d1c9e1e27 upstream.
+
+Instead of falling back to the generic ChaCha skcipher driver for
+non-SIMD cases, use a fast scalar implementation for ARM authored
+by Eric Biggers. This removes the module dependency on chacha-generic
+altogether, which also simplifies things when we expose the ChaCha
+library interface from this module.
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm/crypto/Kconfig              |   4 +-
+ arch/arm/crypto/Makefile             |   3 +-
+ arch/arm/crypto/chacha-glue.c        | 304 +++++++++++++++++++++++++++
+ arch/arm/crypto/chacha-neon-glue.c   | 202 ------------------
+ arch/arm/crypto/chacha-scalar-core.S |  65 +++---
+ arch/arm64/crypto/chacha-neon-glue.c |   2 +-
+ 6 files changed, 340 insertions(+), 240 deletions(-)
+ create mode 100644 arch/arm/crypto/chacha-glue.c
+ delete mode 100644 arch/arm/crypto/chacha-neon-glue.c
+
+--- a/arch/arm/crypto/Kconfig
++++ b/arch/arm/crypto/Kconfig
+@@ -127,10 +127,8 @@ config CRYPTO_CRC32_ARM_CE
+ 	select CRYPTO_HASH
+ 
+ config CRYPTO_CHACHA20_NEON
+-	tristate "NEON accelerated ChaCha stream cipher algorithms"
+-	depends on KERNEL_MODE_NEON
++	tristate "NEON and scalar accelerated ChaCha stream cipher algorithms"
+ 	select CRYPTO_BLKCIPHER
+-	select CRYPTO_CHACHA20
+ 
+ config CRYPTO_NHPOLY1305_NEON
+ 	tristate "NEON accelerated NHPoly1305 hash function (for Adiantum)"
+--- a/arch/arm/crypto/Makefile
++++ b/arch/arm/crypto/Makefile
+@@ -53,7 +53,8 @@ aes-arm-ce-y	:= aes-ce-core.o aes-ce-glu
+ ghash-arm-ce-y	:= ghash-ce-core.o ghash-ce-glue.o
+ crct10dif-arm-ce-y	:= crct10dif-ce-core.o crct10dif-ce-glue.o
+ crc32-arm-ce-y:= crc32-ce-core.o crc32-ce-glue.o
+-chacha-neon-y := chacha-neon-core.o chacha-neon-glue.o
++chacha-neon-y := chacha-scalar-core.o chacha-glue.o
++chacha-neon-$(CONFIG_KERNEL_MODE_NEON) += chacha-neon-core.o
+ nhpoly1305-neon-y := nh-neon-core.o nhpoly1305-neon-glue.o
+ 
+ ifdef REGENERATE_ARM_CRYPTO
+--- /dev/null
++++ b/arch/arm/crypto/chacha-glue.c
+@@ -0,0 +1,304 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * ARM NEON accelerated ChaCha and XChaCha stream ciphers,
++ * including ChaCha20 (RFC7539)
++ *
++ * Copyright (C) 2016-2019 Linaro, Ltd. <ard.biesheuvel@linaro.org>
++ * Copyright (C) 2015 Martin Willi
++ */
++
++#include <crypto/algapi.h>
++#include <crypto/internal/chacha.h>
++#include <crypto/internal/simd.h>
++#include <crypto/internal/skcipher.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++
++#include <asm/cputype.h>
++#include <asm/hwcap.h>
++#include <asm/neon.h>
++#include <asm/simd.h>
++
++asmlinkage void chacha_block_xor_neon(const u32 *state, u8 *dst, const u8 *src,
++				      int nrounds);
++asmlinkage void chacha_4block_xor_neon(const u32 *state, u8 *dst, const u8 *src,
++				       int nrounds);
++asmlinkage void hchacha_block_arm(const u32 *state, u32 *out, int nrounds);
++asmlinkage void hchacha_block_neon(const u32 *state, u32 *out, int nrounds);
++
++asmlinkage void chacha_doarm(u8 *dst, const u8 *src, unsigned int bytes,
++			     const u32 *state, int nrounds);
++
++static inline bool neon_usable(void)
++{
++	return crypto_simd_usable();
++}
++
++static void chacha_doneon(u32 *state, u8 *dst, const u8 *src,
++			  unsigned int bytes, int nrounds)
++{
++	u8 buf[CHACHA_BLOCK_SIZE];
++
++	while (bytes >= CHACHA_BLOCK_SIZE * 4) {
++		chacha_4block_xor_neon(state, dst, src, nrounds);
++		bytes -= CHACHA_BLOCK_SIZE * 4;
++		src += CHACHA_BLOCK_SIZE * 4;
++		dst += CHACHA_BLOCK_SIZE * 4;
++		state[12] += 4;
++	}
++	while (bytes >= CHACHA_BLOCK_SIZE) {
++		chacha_block_xor_neon(state, dst, src, nrounds);
++		bytes -= CHACHA_BLOCK_SIZE;
++		src += CHACHA_BLOCK_SIZE;
++		dst += CHACHA_BLOCK_SIZE;
++		state[12]++;
++	}
++	if (bytes) {
++		memcpy(buf, src, bytes);
++		chacha_block_xor_neon(state, buf, buf, nrounds);
++		memcpy(dst, buf, bytes);
++	}
++}
++
++static int chacha_stream_xor(struct skcipher_request *req,
++			     const struct chacha_ctx *ctx, const u8 *iv,
++			     bool neon)
++{
++	struct skcipher_walk walk;
++	u32 state[16];
++	int err;
++
++	err = skcipher_walk_virt(&walk, req, false);
++
++	chacha_init_generic(state, ctx->key, iv);
++
++	while (walk.nbytes > 0) {
++		unsigned int nbytes = walk.nbytes;
++
++		if (nbytes < walk.total)
++			nbytes = round_down(nbytes, walk.stride);
++
++		if (!neon) {
++			chacha_doarm(walk.dst.virt.addr, walk.src.virt.addr,
++				     nbytes, state, ctx->nrounds);
++			state[12] += DIV_ROUND_UP(nbytes, CHACHA_BLOCK_SIZE);
++		} else {
++			kernel_neon_begin();
++			chacha_doneon(state, walk.dst.virt.addr,
++				      walk.src.virt.addr, nbytes, ctx->nrounds);
++			kernel_neon_end();
++		}
++		err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
++	}
++
++	return err;
++}
++
++static int do_chacha(struct skcipher_request *req, bool neon)
++{
++	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
++	struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
++
++	return chacha_stream_xor(req, ctx, req->iv, neon);
++}
++
++static int chacha_arm(struct skcipher_request *req)
++{
++	return do_chacha(req, false);
++}
++
++static int chacha_neon(struct skcipher_request *req)
++{
++	return do_chacha(req, neon_usable());
++}
++
++static int do_xchacha(struct skcipher_request *req, bool neon)
++{
++	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
++	struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
++	struct chacha_ctx subctx;
++	u32 state[16];
++	u8 real_iv[16];
++
++	chacha_init_generic(state, ctx->key, req->iv);
++
++	if (!neon) {
++		hchacha_block_arm(state, subctx.key, ctx->nrounds);
++	} else {
++		kernel_neon_begin();
++		hchacha_block_neon(state, subctx.key, ctx->nrounds);
++		kernel_neon_end();
++	}
++	subctx.nrounds = ctx->nrounds;
++
++	memcpy(&real_iv[0], req->iv + 24, 8);
++	memcpy(&real_iv[8], req->iv + 16, 8);
++	return chacha_stream_xor(req, &subctx, real_iv, neon);
++}
++
++static int xchacha_arm(struct skcipher_request *req)
++{
++	return do_xchacha(req, false);
++}
++
++static int xchacha_neon(struct skcipher_request *req)
++{
++	return do_xchacha(req, neon_usable());
++}
++
++static struct skcipher_alg arm_algs[] = {
++	{
++		.base.cra_name		= "chacha20",
++		.base.cra_driver_name	= "chacha20-arm",
++		.base.cra_priority	= 200,
++		.base.cra_blocksize	= 1,
++		.base.cra_ctxsize	= sizeof(struct chacha_ctx),
++		.base.cra_module	= THIS_MODULE,
++
++		.min_keysize		= CHACHA_KEY_SIZE,
++		.max_keysize		= CHACHA_KEY_SIZE,
++		.ivsize			= CHACHA_IV_SIZE,
++		.chunksize		= CHACHA_BLOCK_SIZE,
++		.setkey			= chacha20_setkey,
++		.encrypt		= chacha_arm,
++		.decrypt		= chacha_arm,
++	}, {
++		.base.cra_name		= "xchacha20",
++		.base.cra_driver_name	= "xchacha20-arm",
++		.base.cra_priority	= 200,
++		.base.cra_blocksize	= 1,
++		.base.cra_ctxsize	= sizeof(struct chacha_ctx),
++		.base.cra_module	= THIS_MODULE,
++
++		.min_keysize		= CHACHA_KEY_SIZE,
++		.max_keysize		= CHACHA_KEY_SIZE,
++		.ivsize			= XCHACHA_IV_SIZE,
++		.chunksize		= CHACHA_BLOCK_SIZE,
++		.setkey			= chacha20_setkey,
++		.encrypt		= xchacha_arm,
++		.decrypt		= xchacha_arm,
++	}, {
++		.base.cra_name		= "xchacha12",
++		.base.cra_driver_name	= "xchacha12-arm",
++		.base.cra_priority	= 200,
++		.base.cra_blocksize	= 1,
++		.base.cra_ctxsize	= sizeof(struct chacha_ctx),
++		.base.cra_module	= THIS_MODULE,
++
++		.min_keysize		= CHACHA_KEY_SIZE,
++		.max_keysize		= CHACHA_KEY_SIZE,
++		.ivsize			= XCHACHA_IV_SIZE,
++		.chunksize		= CHACHA_BLOCK_SIZE,
++		.setkey			= chacha12_setkey,
++		.encrypt		= xchacha_arm,
++		.decrypt		= xchacha_arm,
++	},
++};
++
++static struct skcipher_alg neon_algs[] = {
++	{
++		.base.cra_name		= "chacha20",
++		.base.cra_driver_name	= "chacha20-neon",
++		.base.cra_priority	= 300,
++		.base.cra_blocksize	= 1,
++		.base.cra_ctxsize	= sizeof(struct chacha_ctx),
++		.base.cra_module	= THIS_MODULE,
++
++		.min_keysize		= CHACHA_KEY_SIZE,
++		.max_keysize		= CHACHA_KEY_SIZE,
++		.ivsize			= CHACHA_IV_SIZE,
++		.chunksize		= CHACHA_BLOCK_SIZE,
++		.walksize		= 4 * CHACHA_BLOCK_SIZE,
++		.setkey			= chacha20_setkey,
++		.encrypt		= chacha_neon,
++		.decrypt		= chacha_neon,
++	}, {
++		.base.cra_name		= "xchacha20",
++		.base.cra_driver_name	= "xchacha20-neon",
++		.base.cra_priority	= 300,
++		.base.cra_blocksize	= 1,
++		.base.cra_ctxsize	= sizeof(struct chacha_ctx),
++		.base.cra_module	= THIS_MODULE,
++
++		.min_keysize		= CHACHA_KEY_SIZE,
++		.max_keysize		= CHACHA_KEY_SIZE,
++		.ivsize			= XCHACHA_IV_SIZE,
++		.chunksize		= CHACHA_BLOCK_SIZE,
++		.walksize		= 4 * CHACHA_BLOCK_SIZE,
++		.setkey			= chacha20_setkey,
++		.encrypt		= xchacha_neon,
++		.decrypt		= xchacha_neon,
++	}, {
++		.base.cra_name		= "xchacha12",
++		.base.cra_driver_name	= "xchacha12-neon",
++		.base.cra_priority	= 300,
++		.base.cra_blocksize	= 1,
++		.base.cra_ctxsize	= sizeof(struct chacha_ctx),
++		.base.cra_module	= THIS_MODULE,
++
++		.min_keysize		= CHACHA_KEY_SIZE,
++		.max_keysize		= CHACHA_KEY_SIZE,
++		.ivsize			= XCHACHA_IV_SIZE,
++		.chunksize		= CHACHA_BLOCK_SIZE,
++		.walksize		= 4 * CHACHA_BLOCK_SIZE,
++		.setkey			= chacha12_setkey,
++		.encrypt		= xchacha_neon,
++		.decrypt		= xchacha_neon,
++	}
++};
++
++static int __init chacha_simd_mod_init(void)
++{
++	int err;
++
++	err = crypto_register_skciphers(arm_algs, ARRAY_SIZE(arm_algs));
++	if (err)
++		return err;
++
++	if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && (elf_hwcap & HWCAP_NEON)) {
++		int i;
++
++		switch (read_cpuid_part()) {
++		case ARM_CPU_PART_CORTEX_A7:
++		case ARM_CPU_PART_CORTEX_A5:
++			/*
++			 * The Cortex-A7 and Cortex-A5 do not perform well with
++			 * the NEON implementation but do incredibly with the
++			 * scalar one and use less power.
++			 */
++			for (i = 0; i < ARRAY_SIZE(neon_algs); i++)
++				neon_algs[i].base.cra_priority = 0;
++			break;
++		}
++
++		err = crypto_register_skciphers(neon_algs, ARRAY_SIZE(neon_algs));
++		if (err)
++			crypto_unregister_skciphers(arm_algs, ARRAY_SIZE(arm_algs));
++	}
++	return err;
++}
++
++static void __exit chacha_simd_mod_fini(void)
++{
++	crypto_unregister_skciphers(arm_algs, ARRAY_SIZE(arm_algs));
++	if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && (elf_hwcap & HWCAP_NEON))
++		crypto_unregister_skciphers(neon_algs, ARRAY_SIZE(neon_algs));
++}
++
++module_init(chacha_simd_mod_init);
++module_exit(chacha_simd_mod_fini);
++
++MODULE_DESCRIPTION("ChaCha and XChaCha stream ciphers (scalar and NEON accelerated)");
++MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS_CRYPTO("chacha20");
++MODULE_ALIAS_CRYPTO("chacha20-arm");
++MODULE_ALIAS_CRYPTO("xchacha20");
++MODULE_ALIAS_CRYPTO("xchacha20-arm");
++MODULE_ALIAS_CRYPTO("xchacha12");
++MODULE_ALIAS_CRYPTO("xchacha12-arm");
++#ifdef CONFIG_KERNEL_MODE_NEON
++MODULE_ALIAS_CRYPTO("chacha20-neon");
++MODULE_ALIAS_CRYPTO("xchacha20-neon");
++MODULE_ALIAS_CRYPTO("xchacha12-neon");
++#endif
+--- a/arch/arm/crypto/chacha-neon-glue.c
++++ /dev/null
+@@ -1,202 +0,0 @@
+-/*
+- * ARM NEON accelerated ChaCha and XChaCha stream ciphers,
+- * including ChaCha20 (RFC7539)
+- *
+- * Copyright (C) 2016 Linaro, Ltd. <ard.biesheuvel@linaro.org>
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License version 2 as
+- * published by the Free Software Foundation.
+- *
+- * Based on:
+- * ChaCha20 256-bit cipher algorithm, RFC7539, SIMD glue code
+- *
+- * Copyright (C) 2015 Martin Willi
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- */
+-
+-#include <crypto/algapi.h>
+-#include <crypto/internal/chacha.h>
+-#include <crypto/internal/simd.h>
+-#include <crypto/internal/skcipher.h>
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-
+-#include <asm/hwcap.h>
+-#include <asm/neon.h>
+-#include <asm/simd.h>
+-
+-asmlinkage void chacha_block_xor_neon(const u32 *state, u8 *dst, const u8 *src,
+-				      int nrounds);
+-asmlinkage void chacha_4block_xor_neon(const u32 *state, u8 *dst, const u8 *src,
+-				       int nrounds);
+-asmlinkage void hchacha_block_neon(const u32 *state, u32 *out, int nrounds);
+-
+-static void chacha_doneon(u32 *state, u8 *dst, const u8 *src,
+-			  unsigned int bytes, int nrounds)
+-{
+-	u8 buf[CHACHA_BLOCK_SIZE];
+-
+-	while (bytes >= CHACHA_BLOCK_SIZE * 4) {
+-		chacha_4block_xor_neon(state, dst, src, nrounds);
+-		bytes -= CHACHA_BLOCK_SIZE * 4;
+-		src += CHACHA_BLOCK_SIZE * 4;
+-		dst += CHACHA_BLOCK_SIZE * 4;
+-		state[12] += 4;
+-	}
+-	while (bytes >= CHACHA_BLOCK_SIZE) {
+-		chacha_block_xor_neon(state, dst, src, nrounds);
+-		bytes -= CHACHA_BLOCK_SIZE;
+-		src += CHACHA_BLOCK_SIZE;
+-		dst += CHACHA_BLOCK_SIZE;
+-		state[12]++;
+-	}
+-	if (bytes) {
+-		memcpy(buf, src, bytes);
+-		chacha_block_xor_neon(state, buf, buf, nrounds);
+-		memcpy(dst, buf, bytes);
+-	}
+-}
+-
+-static int chacha_neon_stream_xor(struct skcipher_request *req,
+-				  const struct chacha_ctx *ctx, const u8 *iv)
+-{
+-	struct skcipher_walk walk;
+-	u32 state[16];
+-	int err;
+-
+-	err = skcipher_walk_virt(&walk, req, false);
+-
+-	crypto_chacha_init(state, ctx, iv);
+-
+-	while (walk.nbytes > 0) {
+-		unsigned int nbytes = walk.nbytes;
+-
+-		if (nbytes < walk.total)
+-			nbytes = round_down(nbytes, walk.stride);
+-
+-		kernel_neon_begin();
+-		chacha_doneon(state, walk.dst.virt.addr, walk.src.virt.addr,
+-			      nbytes, ctx->nrounds);
+-		kernel_neon_end();
+-		err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
+-	}
+-
+-	return err;
+-}
+-
+-static int chacha_neon(struct skcipher_request *req)
+-{
+-	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+-	struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
+-
+-	if (req->cryptlen <= CHACHA_BLOCK_SIZE || !crypto_simd_usable())
+-		return crypto_chacha_crypt(req);
+-
+-	return chacha_neon_stream_xor(req, ctx, req->iv);
+-}
+-
+-static int xchacha_neon(struct skcipher_request *req)
+-{
+-	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+-	struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
+-	struct chacha_ctx subctx;
+-	u32 state[16];
+-	u8 real_iv[16];
+-
+-	if (req->cryptlen <= CHACHA_BLOCK_SIZE || !crypto_simd_usable())
+-		return crypto_xchacha_crypt(req);
+-
+-	crypto_chacha_init(state, ctx, req->iv);
+-
+-	kernel_neon_begin();
+-	hchacha_block_neon(state, subctx.key, ctx->nrounds);
+-	kernel_neon_end();
+-	subctx.nrounds = ctx->nrounds;
+-
+-	memcpy(&real_iv[0], req->iv + 24, 8);
+-	memcpy(&real_iv[8], req->iv + 16, 8);
+-	return chacha_neon_stream_xor(req, &subctx, real_iv);
+-}
+-
+-static struct skcipher_alg algs[] = {
+-	{
+-		.base.cra_name		= "chacha20",
+-		.base.cra_driver_name	= "chacha20-neon",
+-		.base.cra_priority	= 300,
+-		.base.cra_blocksize	= 1,
+-		.base.cra_ctxsize	= sizeof(struct chacha_ctx),
+-		.base.cra_module	= THIS_MODULE,
+-
+-		.min_keysize		= CHACHA_KEY_SIZE,
+-		.max_keysize		= CHACHA_KEY_SIZE,
+-		.ivsize			= CHACHA_IV_SIZE,
+-		.chunksize		= CHACHA_BLOCK_SIZE,
+-		.walksize		= 4 * CHACHA_BLOCK_SIZE,
+-		.setkey			= crypto_chacha20_setkey,
+-		.encrypt		= chacha_neon,
+-		.decrypt		= chacha_neon,
+-	}, {
+-		.base.cra_name		= "xchacha20",
+-		.base.cra_driver_name	= "xchacha20-neon",
+-		.base.cra_priority	= 300,
+-		.base.cra_blocksize	= 1,
+-		.base.cra_ctxsize	= sizeof(struct chacha_ctx),
+-		.base.cra_module	= THIS_MODULE,
+-
+-		.min_keysize		= CHACHA_KEY_SIZE,
+-		.max_keysize		= CHACHA_KEY_SIZE,
+-		.ivsize			= XCHACHA_IV_SIZE,
+-		.chunksize		= CHACHA_BLOCK_SIZE,
+-		.walksize		= 4 * CHACHA_BLOCK_SIZE,
+-		.setkey			= crypto_chacha20_setkey,
+-		.encrypt		= xchacha_neon,
+-		.decrypt		= xchacha_neon,
+-	}, {
+-		.base.cra_name		= "xchacha12",
+-		.base.cra_driver_name	= "xchacha12-neon",
+-		.base.cra_priority	= 300,
+-		.base.cra_blocksize	= 1,
+-		.base.cra_ctxsize	= sizeof(struct chacha_ctx),
+-		.base.cra_module	= THIS_MODULE,
+-
+-		.min_keysize		= CHACHA_KEY_SIZE,
+-		.max_keysize		= CHACHA_KEY_SIZE,
+-		.ivsize			= XCHACHA_IV_SIZE,
+-		.chunksize		= CHACHA_BLOCK_SIZE,
+-		.walksize		= 4 * CHACHA_BLOCK_SIZE,
+-		.setkey			= crypto_chacha12_setkey,
+-		.encrypt		= xchacha_neon,
+-		.decrypt		= xchacha_neon,
+-	}
+-};
+-
+-static int __init chacha_simd_mod_init(void)
+-{
+-	if (!(elf_hwcap & HWCAP_NEON))
+-		return -ENODEV;
+-
+-	return crypto_register_skciphers(algs, ARRAY_SIZE(algs));
+-}
+-
+-static void __exit chacha_simd_mod_fini(void)
+-{
+-	crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
+-}
+-
+-module_init(chacha_simd_mod_init);
+-module_exit(chacha_simd_mod_fini);
+-
+-MODULE_DESCRIPTION("ChaCha and XChaCha stream ciphers (NEON accelerated)");
+-MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
+-MODULE_LICENSE("GPL v2");
+-MODULE_ALIAS_CRYPTO("chacha20");
+-MODULE_ALIAS_CRYPTO("chacha20-neon");
+-MODULE_ALIAS_CRYPTO("xchacha20");
+-MODULE_ALIAS_CRYPTO("xchacha20-neon");
+-MODULE_ALIAS_CRYPTO("xchacha12");
+-MODULE_ALIAS_CRYPTO("xchacha12-neon");
+--- a/arch/arm/crypto/chacha-scalar-core.S
++++ b/arch/arm/crypto/chacha-scalar-core.S
+@@ -41,14 +41,6 @@
+ 	X14	.req	r12
+ 	X15	.req	r14
+ 
+-.Lexpand_32byte_k:
+-	// "expand 32-byte k"
+-	.word	0x61707865, 0x3320646e, 0x79622d32, 0x6b206574
+-
+-#ifdef __thumb2__
+-#  define adrl adr
+-#endif
+-
+ .macro __rev		out, in,  t0, t1, t2
+ .if __LINUX_ARM_ARCH__ >= 6
+ 	rev		\out, \in
+@@ -391,61 +383,65 @@
+ .endm	// _chacha
+ 
+ /*
+- * void chacha20_arm(u8 *out, const u8 *in, size_t len, const u32 key[8],
+- *		     const u32 iv[4]);
++ * void chacha_doarm(u8 *dst, const u8 *src, unsigned int bytes,
++ *		     const u32 *state, int nrounds);
+  */
+-ENTRY(chacha20_arm)
++ENTRY(chacha_doarm)
+ 	cmp		r2, #0			// len == 0?
+ 	reteq		lr
+ 
++	ldr		ip, [sp]
++	cmp		ip, #12
++
+ 	push		{r0-r2,r4-r11,lr}
+ 
+ 	// Push state x0-x15 onto stack.
+ 	// Also store an extra copy of x10-x11 just before the state.
+ 
+-	ldr		r4, [sp, #48]		// iv
+-	mov		r0, sp
+-	sub		sp, #80
+-
+-	// iv: x12-x15
+-	ldm		r4, {X12,X13,X14,X15}
+-	stmdb		r0!, {X12,X13,X14,X15}
++	add		X12, r3, #48
++	ldm		X12, {X12,X13,X14,X15}
++	push		{X12,X13,X14,X15}
++	sub		sp, sp, #64
+ 
+-	// key: x4-x11
+-	__ldrd		X8_X10, X9_X11, r3, 24
++	__ldrd		X8_X10, X9_X11, r3, 40
+ 	__strd		X8_X10, X9_X11, sp, 8
+-	stmdb		r0!, {X8_X10, X9_X11}
+-	ldm		r3, {X4-X9_X11}
+-	stmdb		r0!, {X4-X9_X11}
+-
+-	// constants: x0-x3
+-	adrl		X3, .Lexpand_32byte_k
+-	ldm		X3, {X0-X3}
++	__strd		X8_X10, X9_X11, sp, 56
++	ldm		r3, {X0-X9_X11}
+ 	__strd		X0, X1, sp, 16
+ 	__strd		X2, X3, sp, 24
++	__strd		X4, X5, sp, 32
++	__strd		X6, X7, sp, 40
++	__strd		X8_X10, X9_X11, sp, 48
+ 
++	beq		1f
+ 	_chacha		20
+ 
+-	add		sp, #76
++0:	add		sp, #76
+ 	pop		{r4-r11, pc}
+-ENDPROC(chacha20_arm)
++
++1:	_chacha		12
++	b		0b
++ENDPROC(chacha_doarm)
+ 
+ /*
+- * void hchacha20_arm(const u32 state[16], u32 out[8]);
++ * void hchacha_block_arm(const u32 state[16], u32 out[8], int nrounds);
+  */
+-ENTRY(hchacha20_arm)
++ENTRY(hchacha_block_arm)
+ 	push		{r1,r4-r11,lr}
+ 
++	cmp		r2, #12			// ChaCha12 ?
++
+ 	mov		r14, r0
+ 	ldmia		r14!, {r0-r11}		// load x0-x11
+ 	push		{r10-r11}		// store x10-x11 to stack
+ 	ldm		r14, {r10-r12,r14}	// load x12-x15
+ 	sub		sp, #8
+ 
++	beq		1f
+ 	_chacha_permute	20
+ 
+ 	// Skip over (unused0-unused1, x10-x11)
+-	add		sp, #16
++0:	add		sp, #16
+ 
+ 	// Fix up rotations of x12-x15
+ 	ror		X12, X12, #drot
+@@ -458,4 +454,7 @@ ENTRY(hchacha20_arm)
+ 	stm		r4, {X0,X1,X2,X3,X12,X13,X14,X15}
+ 
+ 	pop		{r4-r11,pc}
+-ENDPROC(hchacha20_arm)
++
++1:	_chacha_permute	12
++	b		0b
++ENDPROC(hchacha_block_arm)
+--- a/arch/arm64/crypto/chacha-neon-glue.c
++++ b/arch/arm64/crypto/chacha-neon-glue.c
+@@ -1,5 +1,5 @@
+ /*
+- * ARM NEON accelerated ChaCha and XChaCha stream ciphers,
++ * ARM NEON and scalar accelerated ChaCha and XChaCha stream ciphers,
+  * including ChaCha20 (RFC7539)
+  *
+  * Copyright (C) 2016 - 2017 Linaro, Ltd. <ard.biesheuvel@linaro.org>
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0009-crypto-arm-chacha-expose-ARM-ChaCha-routine-as-libra.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0009-crypto-arm-chacha-expose-ARM-ChaCha-routine-as-libra.patch
new file mode 100644
index 0000000..4006dc6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0009-crypto-arm-chacha-expose-ARM-ChaCha-routine-as-libra.patch
@@ -0,0 +1,108 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:15 +0100
+Subject: [PATCH] crypto: arm/chacha - expose ARM ChaCha routine as library
+ function
+
+commit a44a3430d71bad4ee56788a59fff099b291ea54c upstream.
+
+Expose the accelerated NEON ChaCha routine directly as a symbol
+export so that users of the ChaCha library API can use it directly.
+
+Given that calls into the library API will always go through the
+routines in this module if it is enabled, switch to static keys
+to select the optimal implementation available (which may be none
+at all, in which case we defer to the generic implementation for
+all invocations).
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm/crypto/Kconfig       |  1 +
+ arch/arm/crypto/chacha-glue.c | 41 ++++++++++++++++++++++++++++++++++-
+ 2 files changed, 41 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/crypto/Kconfig
++++ b/arch/arm/crypto/Kconfig
+@@ -129,6 +129,7 @@ config CRYPTO_CRC32_ARM_CE
+ config CRYPTO_CHACHA20_NEON
+ 	tristate "NEON and scalar accelerated ChaCha stream cipher algorithms"
+ 	select CRYPTO_BLKCIPHER
++	select CRYPTO_ARCH_HAVE_LIB_CHACHA
+ 
+ config CRYPTO_NHPOLY1305_NEON
+ 	tristate "NEON accelerated NHPoly1305 hash function (for Adiantum)"
+--- a/arch/arm/crypto/chacha-glue.c
++++ b/arch/arm/crypto/chacha-glue.c
+@@ -11,6 +11,7 @@
+ #include <crypto/internal/chacha.h>
+ #include <crypto/internal/simd.h>
+ #include <crypto/internal/skcipher.h>
++#include <linux/jump_label.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ 
+@@ -29,9 +30,11 @@ asmlinkage void hchacha_block_neon(const
+ asmlinkage void chacha_doarm(u8 *dst, const u8 *src, unsigned int bytes,
+ 			     const u32 *state, int nrounds);
+ 
++static __ro_after_init DEFINE_STATIC_KEY_FALSE(use_neon);
++
+ static inline bool neon_usable(void)
+ {
+-	return crypto_simd_usable();
++	return static_branch_likely(&use_neon) && crypto_simd_usable();
+ }
+ 
+ static void chacha_doneon(u32 *state, u8 *dst, const u8 *src,
+@@ -60,6 +63,40 @@ static void chacha_doneon(u32 *state, u8
+ 	}
+ }
+ 
++void hchacha_block_arch(const u32 *state, u32 *stream, int nrounds)
++{
++	if (!IS_ENABLED(CONFIG_KERNEL_MODE_NEON) || !neon_usable()) {
++		hchacha_block_arm(state, stream, nrounds);
++	} else {
++		kernel_neon_begin();
++		hchacha_block_neon(state, stream, nrounds);
++		kernel_neon_end();
++	}
++}
++EXPORT_SYMBOL(hchacha_block_arch);
++
++void chacha_init_arch(u32 *state, const u32 *key, const u8 *iv)
++{
++	chacha_init_generic(state, key, iv);
++}
++EXPORT_SYMBOL(chacha_init_arch);
++
++void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src, unsigned int bytes,
++		       int nrounds)
++{
++	if (!IS_ENABLED(CONFIG_KERNEL_MODE_NEON) || !neon_usable() ||
++	    bytes <= CHACHA_BLOCK_SIZE) {
++		chacha_doarm(dst, src, bytes, state, nrounds);
++		state[12] += DIV_ROUND_UP(bytes, CHACHA_BLOCK_SIZE);
++		return;
++	}
++
++	kernel_neon_begin();
++	chacha_doneon(state, dst, src, bytes, nrounds);
++	kernel_neon_end();
++}
++EXPORT_SYMBOL(chacha_crypt_arch);
++
+ static int chacha_stream_xor(struct skcipher_request *req,
+ 			     const struct chacha_ctx *ctx, const u8 *iv,
+ 			     bool neon)
+@@ -269,6 +306,8 @@ static int __init chacha_simd_mod_init(v
+ 			for (i = 0; i < ARRAY_SIZE(neon_algs); i++)
+ 				neon_algs[i].base.cra_priority = 0;
+ 			break;
++		default:
++			static_branch_enable(&use_neon);
+ 		}
+ 
+ 		err = crypto_register_skciphers(neon_algs, ARRAY_SIZE(neon_algs));
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0010-crypto-mips-chacha-import-32r2-ChaCha-code-from-Zinc.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0010-crypto-mips-chacha-import-32r2-ChaCha-code-from-Zinc.patch
new file mode 100644
index 0000000..0a2b4c4
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0010-crypto-mips-chacha-import-32r2-ChaCha-code-from-Zinc.patch
@@ -0,0 +1,451 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 8 Nov 2019 13:22:16 +0100
+Subject: [PATCH] crypto: mips/chacha - import 32r2 ChaCha code from Zinc
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit 49aa7c00eddf8d8f462b0256bd82e81762d7b0c6 upstream.
+
+This imports the accelerated MIPS 32r2 ChaCha20 implementation from the
+Zinc patch set.
+
+Co-developed-by: René van Dorst <opensource@vdorst.com>
+Signed-off-by: René van Dorst <opensource@vdorst.com>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/mips/crypto/chacha-core.S | 424 +++++++++++++++++++++++++++++++++
+ 1 file changed, 424 insertions(+)
+ create mode 100644 arch/mips/crypto/chacha-core.S
+
+--- /dev/null
++++ b/arch/mips/crypto/chacha-core.S
+@@ -0,0 +1,424 @@
++/* SPDX-License-Identifier: GPL-2.0 OR MIT */
++/*
++ * Copyright (C) 2016-2018 René van Dorst <opensource@vdorst.com>. All Rights Reserved.
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#define MASK_U32		0x3c
++#define CHACHA20_BLOCK_SIZE	64
++#define STACK_SIZE		32
++
++#define X0	$t0
++#define X1	$t1
++#define X2	$t2
++#define X3	$t3
++#define X4	$t4
++#define X5	$t5
++#define X6	$t6
++#define X7	$t7
++#define X8	$t8
++#define X9	$t9
++#define X10	$v1
++#define X11	$s6
++#define X12	$s5
++#define X13	$s4
++#define X14	$s3
++#define X15	$s2
++/* Use regs which are overwritten on exit for Tx so we don't leak clear data. */
++#define T0	$s1
++#define T1	$s0
++#define T(n)	T ## n
++#define X(n)	X ## n
++
++/* Input arguments */
++#define STATE		$a0
++#define OUT		$a1
++#define IN		$a2
++#define BYTES		$a3
++
++/* Output argument */
++/* NONCE[0] is kept in a register and not in memory.
++ * We don't want to touch original value in memory.
++ * Must be incremented every loop iteration.
++ */
++#define NONCE_0		$v0
++
++/* SAVED_X and SAVED_CA are set in the jump table.
++ * Use regs which are overwritten on exit else we don't leak clear data.
++ * They are used to handling the last bytes which are not multiple of 4.
++ */
++#define SAVED_X		X15
++#define SAVED_CA	$s7
++
++#define IS_UNALIGNED	$s7
++
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++#define MSB 0
++#define LSB 3
++#define ROTx rotl
++#define ROTR(n) rotr n, 24
++#define	CPU_TO_LE32(n) \
++	wsbh	n; \
++	rotr	n, 16;
++#else
++#define MSB 3
++#define LSB 0
++#define ROTx rotr
++#define CPU_TO_LE32(n)
++#define ROTR(n)
++#endif
++
++#define FOR_EACH_WORD(x) \
++	x( 0); \
++	x( 1); \
++	x( 2); \
++	x( 3); \
++	x( 4); \
++	x( 5); \
++	x( 6); \
++	x( 7); \
++	x( 8); \
++	x( 9); \
++	x(10); \
++	x(11); \
++	x(12); \
++	x(13); \
++	x(14); \
++	x(15);
++
++#define FOR_EACH_WORD_REV(x) \
++	x(15); \
++	x(14); \
++	x(13); \
++	x(12); \
++	x(11); \
++	x(10); \
++	x( 9); \
++	x( 8); \
++	x( 7); \
++	x( 6); \
++	x( 5); \
++	x( 4); \
++	x( 3); \
++	x( 2); \
++	x( 1); \
++	x( 0);
++
++#define PLUS_ONE_0	 1
++#define PLUS_ONE_1	 2
++#define PLUS_ONE_2	 3
++#define PLUS_ONE_3	 4
++#define PLUS_ONE_4	 5
++#define PLUS_ONE_5	 6
++#define PLUS_ONE_6	 7
++#define PLUS_ONE_7	 8
++#define PLUS_ONE_8	 9
++#define PLUS_ONE_9	10
++#define PLUS_ONE_10	11
++#define PLUS_ONE_11	12
++#define PLUS_ONE_12	13
++#define PLUS_ONE_13	14
++#define PLUS_ONE_14	15
++#define PLUS_ONE_15	16
++#define PLUS_ONE(x)	PLUS_ONE_ ## x
++#define _CONCAT3(a,b,c)	a ## b ## c
++#define CONCAT3(a,b,c)	_CONCAT3(a,b,c)
++
++#define STORE_UNALIGNED(x) \
++CONCAT3(.Lchacha20_mips_xor_unaligned_, PLUS_ONE(x), _b: ;) \
++	.if (x != 12); \
++		lw	T0, (x*4)(STATE); \
++	.endif; \
++	lwl	T1, (x*4)+MSB ## (IN); \
++	lwr	T1, (x*4)+LSB ## (IN); \
++	.if (x == 12); \
++		addu	X ## x, NONCE_0; \
++	.else; \
++		addu	X ## x, T0; \
++	.endif; \
++	CPU_TO_LE32(X ## x); \
++	xor	X ## x, T1; \
++	swl	X ## x, (x*4)+MSB ## (OUT); \
++	swr	X ## x, (x*4)+LSB ## (OUT);
++
++#define STORE_ALIGNED(x) \
++CONCAT3(.Lchacha20_mips_xor_aligned_, PLUS_ONE(x), _b: ;) \
++	.if (x != 12); \
++		lw	T0, (x*4)(STATE); \
++	.endif; \
++	lw	T1, (x*4) ## (IN); \
++	.if (x == 12); \
++		addu	X ## x, NONCE_0; \
++	.else; \
++		addu	X ## x, T0; \
++	.endif; \
++	CPU_TO_LE32(X ## x); \
++	xor	X ## x, T1; \
++	sw	X ## x, (x*4) ## (OUT);
++
++/* Jump table macro.
++ * Used for setup and handling the last bytes, which are not multiple of 4.
++ * X15 is free to store Xn
++ * Every jumptable entry must be equal in size.
++ */
++#define JMPTBL_ALIGNED(x) \
++.Lchacha20_mips_jmptbl_aligned_ ## x: ; \
++	.set	noreorder; \
++	b	.Lchacha20_mips_xor_aligned_ ## x ## _b; \
++	.if (x == 12); \
++		addu	SAVED_X, X ## x, NONCE_0; \
++	.else; \
++		addu	SAVED_X, X ## x, SAVED_CA; \
++	.endif; \
++	.set	reorder
++
++#define JMPTBL_UNALIGNED(x) \
++.Lchacha20_mips_jmptbl_unaligned_ ## x: ; \
++	.set	noreorder; \
++	b	.Lchacha20_mips_xor_unaligned_ ## x ## _b; \
++	.if (x == 12); \
++		addu	SAVED_X, X ## x, NONCE_0; \
++	.else; \
++		addu	SAVED_X, X ## x, SAVED_CA; \
++	.endif; \
++	.set	reorder
++
++#define AXR(A, B, C, D,  K, L, M, N,  V, W, Y, Z,  S) \
++	addu	X(A), X(K); \
++	addu	X(B), X(L); \
++	addu	X(C), X(M); \
++	addu	X(D), X(N); \
++	xor	X(V), X(A); \
++	xor	X(W), X(B); \
++	xor	X(Y), X(C); \
++	xor	X(Z), X(D); \
++	rotl	X(V), S;    \
++	rotl	X(W), S;    \
++	rotl	X(Y), S;    \
++	rotl	X(Z), S;
++
++.text
++.set	reorder
++.set	noat
++.globl	chacha20_mips
++.ent	chacha20_mips
++chacha20_mips:
++	.frame	$sp, STACK_SIZE, $ra
++
++	addiu	$sp, -STACK_SIZE
++
++	/* Return bytes = 0. */
++	beqz	BYTES, .Lchacha20_mips_end
++
++	lw	NONCE_0, 48(STATE)
++
++	/* Save s0-s7 */
++	sw	$s0,  0($sp)
++	sw	$s1,  4($sp)
++	sw	$s2,  8($sp)
++	sw	$s3, 12($sp)
++	sw	$s4, 16($sp)
++	sw	$s5, 20($sp)
++	sw	$s6, 24($sp)
++	sw	$s7, 28($sp)
++
++	/* Test IN or OUT is unaligned.
++	 * IS_UNALIGNED = ( IN | OUT ) & 0x00000003
++	 */
++	or	IS_UNALIGNED, IN, OUT
++	andi	IS_UNALIGNED, 0x3
++
++	/* Set number of rounds */
++	li	$at, 20
++
++	b	.Lchacha20_rounds_start
++
++.align 4
++.Loop_chacha20_rounds:
++	addiu	IN,  CHACHA20_BLOCK_SIZE
++	addiu	OUT, CHACHA20_BLOCK_SIZE
++	addiu	NONCE_0, 1
++
++.Lchacha20_rounds_start:
++	lw	X0,  0(STATE)
++	lw	X1,  4(STATE)
++	lw	X2,  8(STATE)
++	lw	X3,  12(STATE)
++
++	lw	X4,  16(STATE)
++	lw	X5,  20(STATE)
++	lw	X6,  24(STATE)
++	lw	X7,  28(STATE)
++	lw	X8,  32(STATE)
++	lw	X9,  36(STATE)
++	lw	X10, 40(STATE)
++	lw	X11, 44(STATE)
++
++	move	X12, NONCE_0
++	lw	X13, 52(STATE)
++	lw	X14, 56(STATE)
++	lw	X15, 60(STATE)
++
++.Loop_chacha20_xor_rounds:
++	addiu	$at, -2
++	AXR( 0, 1, 2, 3,  4, 5, 6, 7, 12,13,14,15, 16);
++	AXR( 8, 9,10,11, 12,13,14,15,  4, 5, 6, 7, 12);
++	AXR( 0, 1, 2, 3,  4, 5, 6, 7, 12,13,14,15,  8);
++	AXR( 8, 9,10,11, 12,13,14,15,  4, 5, 6, 7,  7);
++	AXR( 0, 1, 2, 3,  5, 6, 7, 4, 15,12,13,14, 16);
++	AXR(10,11, 8, 9, 15,12,13,14,  5, 6, 7, 4, 12);
++	AXR( 0, 1, 2, 3,  5, 6, 7, 4, 15,12,13,14,  8);
++	AXR(10,11, 8, 9, 15,12,13,14,  5, 6, 7, 4,  7);
++	bnez	$at, .Loop_chacha20_xor_rounds
++
++	addiu	BYTES, -(CHACHA20_BLOCK_SIZE)
++
++	/* Is data src/dst unaligned? Jump */
++	bnez	IS_UNALIGNED, .Loop_chacha20_unaligned
++
++	/* Set number rounds here to fill delayslot. */
++	li	$at, 20
++
++	/* BYTES < 0, it has no full block. */
++	bltz	BYTES, .Lchacha20_mips_no_full_block_aligned
++
++	FOR_EACH_WORD_REV(STORE_ALIGNED)
++
++	/* BYTES > 0? Loop again. */
++	bgtz	BYTES, .Loop_chacha20_rounds
++
++	/* Place this here to fill delay slot */
++	addiu	NONCE_0, 1
++
++	/* BYTES < 0? Handle last bytes */
++	bltz	BYTES, .Lchacha20_mips_xor_bytes
++
++.Lchacha20_mips_xor_done:
++	/* Restore used registers */
++	lw	$s0,  0($sp)
++	lw	$s1,  4($sp)
++	lw	$s2,  8($sp)
++	lw	$s3, 12($sp)
++	lw	$s4, 16($sp)
++	lw	$s5, 20($sp)
++	lw	$s6, 24($sp)
++	lw	$s7, 28($sp)
++
++	/* Write NONCE_0 back to right location in state */
++	sw	NONCE_0, 48(STATE)
++
++.Lchacha20_mips_end:
++	addiu	$sp, STACK_SIZE
++	jr	$ra
++
++.Lchacha20_mips_no_full_block_aligned:
++	/* Restore the offset on BYTES */
++	addiu	BYTES, CHACHA20_BLOCK_SIZE
++
++	/* Get number of full WORDS */
++	andi	$at, BYTES, MASK_U32
++
++	/* Load upper half of jump table addr */
++	lui	T0, %hi(.Lchacha20_mips_jmptbl_aligned_0)
++
++	/* Calculate lower half jump table offset */
++	ins	T0, $at, 1, 6
++
++	/* Add offset to STATE */
++	addu	T1, STATE, $at
++
++	/* Add lower half jump table addr */
++	addiu	T0, %lo(.Lchacha20_mips_jmptbl_aligned_0)
++
++	/* Read value from STATE */
++	lw	SAVED_CA, 0(T1)
++
++	/* Store remaining bytecounter as negative value */
++	subu	BYTES, $at, BYTES
++
++	jr	T0
++
++	/* Jump table */
++	FOR_EACH_WORD(JMPTBL_ALIGNED)
++
++
++.Loop_chacha20_unaligned:
++	/* Set number rounds here to fill delayslot. */
++	li	$at, 20
++
++	/* BYTES > 0, it has no full block. */
++	bltz	BYTES, .Lchacha20_mips_no_full_block_unaligned
++
++	FOR_EACH_WORD_REV(STORE_UNALIGNED)
++
++	/* BYTES > 0? Loop again. */
++	bgtz	BYTES, .Loop_chacha20_rounds
++
++	/* Write NONCE_0 back to right location in state */
++	sw	NONCE_0, 48(STATE)
++
++	.set noreorder
++	/* Fall through to byte handling */
++	bgez	BYTES, .Lchacha20_mips_xor_done
++.Lchacha20_mips_xor_unaligned_0_b:
++.Lchacha20_mips_xor_aligned_0_b:
++	/* Place this here to fill delay slot */
++	addiu	NONCE_0, 1
++	.set reorder
++
++.Lchacha20_mips_xor_bytes:
++	addu	IN, $at
++	addu	OUT, $at
++	/* First byte */
++	lbu	T1, 0(IN)
++	addiu	$at, BYTES, 1
++	CPU_TO_LE32(SAVED_X)
++	ROTR(SAVED_X)
++	xor	T1, SAVED_X
++	sb	T1, 0(OUT)
++	beqz	$at, .Lchacha20_mips_xor_done
++	/* Second byte */
++	lbu	T1, 1(IN)
++	addiu	$at, BYTES, 2
++	ROTx	SAVED_X, 8
++	xor	T1, SAVED_X
++	sb	T1, 1(OUT)
++	beqz	$at, .Lchacha20_mips_xor_done
++	/* Third byte */
++	lbu	T1, 2(IN)
++	ROTx	SAVED_X, 8
++	xor	T1, SAVED_X
++	sb	T1, 2(OUT)
++	b	.Lchacha20_mips_xor_done
++
++.Lchacha20_mips_no_full_block_unaligned:
++	/* Restore the offset on BYTES */
++	addiu	BYTES, CHACHA20_BLOCK_SIZE
++
++	/* Get number of full WORDS */
++	andi	$at, BYTES, MASK_U32
++
++	/* Load upper half of jump table addr */
++	lui	T0, %hi(.Lchacha20_mips_jmptbl_unaligned_0)
++
++	/* Calculate lower half jump table offset */
++	ins	T0, $at, 1, 6
++
++	/* Add offset to STATE */
++	addu	T1, STATE, $at
++
++	/* Add lower half jump table addr */
++	addiu	T0, %lo(.Lchacha20_mips_jmptbl_unaligned_0)
++
++	/* Read value from STATE */
++	lw	SAVED_CA, 0(T1)
++
++	/* Store remaining bytecounter as negative value */
++	subu	BYTES, $at, BYTES
++
++	jr	T0
++
++	/* Jump table */
++	FOR_EACH_WORD(JMPTBL_UNALIGNED)
++.end chacha20_mips
++.set at
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0011-crypto-mips-chacha-wire-up-accelerated-32r2-code-fro.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0011-crypto-mips-chacha-wire-up-accelerated-32r2-code-fro.patch
new file mode 100644
index 0000000..0d24ce2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0011-crypto-mips-chacha-wire-up-accelerated-32r2-code-fro.patch
@@ -0,0 +1,559 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:17 +0100
+Subject: [PATCH] crypto: mips/chacha - wire up accelerated 32r2 code from Zinc
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit 3a2f58f3ba4f6f44e33d1a48240d5eadb882cb59 upstream.
+
+This integrates the accelerated MIPS 32r2 implementation of ChaCha
+into both the API and library interfaces of the kernel crypto stack.
+
+The significance of this is that, in addition to becoming available
+as an accelerated library implementation, it can also be used by
+existing crypto API code such as Adiantum (for block encryption on
+ultra low performance cores) or IPsec using chacha20poly1305. These
+are use cases that have already opted into using the abstract crypto
+API. In order to support Adiantum, the core assembler routine has
+been adapted to take the round count as a function argument rather
+than hardcoding it to 20.
+
+Co-developed-by: René van Dorst <opensource@vdorst.com>
+Signed-off-by: René van Dorst <opensource@vdorst.com>
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/mips/Makefile             |   2 +-
+ arch/mips/crypto/Makefile      |   4 +
+ arch/mips/crypto/chacha-core.S | 159 ++++++++++++++++++++++++---------
+ arch/mips/crypto/chacha-glue.c | 150 +++++++++++++++++++++++++++++++
+ crypto/Kconfig                 |   6 ++
+ 5 files changed, 277 insertions(+), 44 deletions(-)
+ create mode 100644 arch/mips/crypto/chacha-glue.c
+
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -334,7 +334,7 @@ libs-$(CONFIG_MIPS_FP_SUPPORT) += arch/m
+ # See arch/mips/Kbuild for content of core part of the kernel
+ core-y += arch/mips/
+ 
+-drivers-$(CONFIG_MIPS_CRC_SUPPORT) += arch/mips/crypto/
++drivers-y			+= arch/mips/crypto/
+ drivers-$(CONFIG_OPROFILE)	+= arch/mips/oprofile/
+ 
+ # suspend and hibernation support
+--- a/arch/mips/crypto/Makefile
++++ b/arch/mips/crypto/Makefile
+@@ -4,3 +4,7 @@
+ #
+ 
+ obj-$(CONFIG_CRYPTO_CRC32_MIPS) += crc32-mips.o
++
++obj-$(CONFIG_CRYPTO_CHACHA_MIPS) += chacha-mips.o
++chacha-mips-y := chacha-core.o chacha-glue.o
++AFLAGS_chacha-core.o += -O2 # needed to fill branch delay slots
+--- a/arch/mips/crypto/chacha-core.S
++++ b/arch/mips/crypto/chacha-core.S
+@@ -125,7 +125,7 @@
+ #define CONCAT3(a,b,c)	_CONCAT3(a,b,c)
+ 
+ #define STORE_UNALIGNED(x) \
+-CONCAT3(.Lchacha20_mips_xor_unaligned_, PLUS_ONE(x), _b: ;) \
++CONCAT3(.Lchacha_mips_xor_unaligned_, PLUS_ONE(x), _b: ;) \
+ 	.if (x != 12); \
+ 		lw	T0, (x*4)(STATE); \
+ 	.endif; \
+@@ -142,7 +142,7 @@ CONCAT3(.Lchacha20_mips_xor_unaligned_,
+ 	swr	X ## x, (x*4)+LSB ## (OUT);
+ 
+ #define STORE_ALIGNED(x) \
+-CONCAT3(.Lchacha20_mips_xor_aligned_, PLUS_ONE(x), _b: ;) \
++CONCAT3(.Lchacha_mips_xor_aligned_, PLUS_ONE(x), _b: ;) \
+ 	.if (x != 12); \
+ 		lw	T0, (x*4)(STATE); \
+ 	.endif; \
+@@ -162,9 +162,9 @@ CONCAT3(.Lchacha20_mips_xor_aligned_, PL
+  * Every jumptable entry must be equal in size.
+  */
+ #define JMPTBL_ALIGNED(x) \
+-.Lchacha20_mips_jmptbl_aligned_ ## x: ; \
++.Lchacha_mips_jmptbl_aligned_ ## x: ; \
+ 	.set	noreorder; \
+-	b	.Lchacha20_mips_xor_aligned_ ## x ## _b; \
++	b	.Lchacha_mips_xor_aligned_ ## x ## _b; \
+ 	.if (x == 12); \
+ 		addu	SAVED_X, X ## x, NONCE_0; \
+ 	.else; \
+@@ -173,9 +173,9 @@ CONCAT3(.Lchacha20_mips_xor_aligned_, PL
+ 	.set	reorder
+ 
+ #define JMPTBL_UNALIGNED(x) \
+-.Lchacha20_mips_jmptbl_unaligned_ ## x: ; \
++.Lchacha_mips_jmptbl_unaligned_ ## x: ; \
+ 	.set	noreorder; \
+-	b	.Lchacha20_mips_xor_unaligned_ ## x ## _b; \
++	b	.Lchacha_mips_xor_unaligned_ ## x ## _b; \
+ 	.if (x == 12); \
+ 		addu	SAVED_X, X ## x, NONCE_0; \
+ 	.else; \
+@@ -200,15 +200,18 @@ CONCAT3(.Lchacha20_mips_xor_aligned_, PL
+ .text
+ .set	reorder
+ .set	noat
+-.globl	chacha20_mips
+-.ent	chacha20_mips
+-chacha20_mips:
++.globl	chacha_crypt_arch
++.ent	chacha_crypt_arch
++chacha_crypt_arch:
+ 	.frame	$sp, STACK_SIZE, $ra
+ 
++	/* Load number of rounds */
++	lw	$at, 16($sp)
++
+ 	addiu	$sp, -STACK_SIZE
+ 
+ 	/* Return bytes = 0. */
+-	beqz	BYTES, .Lchacha20_mips_end
++	beqz	BYTES, .Lchacha_mips_end
+ 
+ 	lw	NONCE_0, 48(STATE)
+ 
+@@ -228,18 +231,15 @@ chacha20_mips:
+ 	or	IS_UNALIGNED, IN, OUT
+ 	andi	IS_UNALIGNED, 0x3
+ 
+-	/* Set number of rounds */
+-	li	$at, 20
+-
+-	b	.Lchacha20_rounds_start
++	b	.Lchacha_rounds_start
+ 
+ .align 4
+-.Loop_chacha20_rounds:
++.Loop_chacha_rounds:
+ 	addiu	IN,  CHACHA20_BLOCK_SIZE
+ 	addiu	OUT, CHACHA20_BLOCK_SIZE
+ 	addiu	NONCE_0, 1
+ 
+-.Lchacha20_rounds_start:
++.Lchacha_rounds_start:
+ 	lw	X0,  0(STATE)
+ 	lw	X1,  4(STATE)
+ 	lw	X2,  8(STATE)
+@@ -259,7 +259,7 @@ chacha20_mips:
+ 	lw	X14, 56(STATE)
+ 	lw	X15, 60(STATE)
+ 
+-.Loop_chacha20_xor_rounds:
++.Loop_chacha_xor_rounds:
+ 	addiu	$at, -2
+ 	AXR( 0, 1, 2, 3,  4, 5, 6, 7, 12,13,14,15, 16);
+ 	AXR( 8, 9,10,11, 12,13,14,15,  4, 5, 6, 7, 12);
+@@ -269,31 +269,31 @@ chacha20_mips:
+ 	AXR(10,11, 8, 9, 15,12,13,14,  5, 6, 7, 4, 12);
+ 	AXR( 0, 1, 2, 3,  5, 6, 7, 4, 15,12,13,14,  8);
+ 	AXR(10,11, 8, 9, 15,12,13,14,  5, 6, 7, 4,  7);
+-	bnez	$at, .Loop_chacha20_xor_rounds
++	bnez	$at, .Loop_chacha_xor_rounds
+ 
+ 	addiu	BYTES, -(CHACHA20_BLOCK_SIZE)
+ 
+ 	/* Is data src/dst unaligned? Jump */
+-	bnez	IS_UNALIGNED, .Loop_chacha20_unaligned
++	bnez	IS_UNALIGNED, .Loop_chacha_unaligned
+ 
+ 	/* Set number rounds here to fill delayslot. */
+-	li	$at, 20
++	lw	$at, (STACK_SIZE+16)($sp)
+ 
+ 	/* BYTES < 0, it has no full block. */
+-	bltz	BYTES, .Lchacha20_mips_no_full_block_aligned
++	bltz	BYTES, .Lchacha_mips_no_full_block_aligned
+ 
+ 	FOR_EACH_WORD_REV(STORE_ALIGNED)
+ 
+ 	/* BYTES > 0? Loop again. */
+-	bgtz	BYTES, .Loop_chacha20_rounds
++	bgtz	BYTES, .Loop_chacha_rounds
+ 
+ 	/* Place this here to fill delay slot */
+ 	addiu	NONCE_0, 1
+ 
+ 	/* BYTES < 0? Handle last bytes */
+-	bltz	BYTES, .Lchacha20_mips_xor_bytes
++	bltz	BYTES, .Lchacha_mips_xor_bytes
+ 
+-.Lchacha20_mips_xor_done:
++.Lchacha_mips_xor_done:
+ 	/* Restore used registers */
+ 	lw	$s0,  0($sp)
+ 	lw	$s1,  4($sp)
+@@ -307,11 +307,11 @@ chacha20_mips:
+ 	/* Write NONCE_0 back to right location in state */
+ 	sw	NONCE_0, 48(STATE)
+ 
+-.Lchacha20_mips_end:
++.Lchacha_mips_end:
+ 	addiu	$sp, STACK_SIZE
+ 	jr	$ra
+ 
+-.Lchacha20_mips_no_full_block_aligned:
++.Lchacha_mips_no_full_block_aligned:
+ 	/* Restore the offset on BYTES */
+ 	addiu	BYTES, CHACHA20_BLOCK_SIZE
+ 
+@@ -319,7 +319,7 @@ chacha20_mips:
+ 	andi	$at, BYTES, MASK_U32
+ 
+ 	/* Load upper half of jump table addr */
+-	lui	T0, %hi(.Lchacha20_mips_jmptbl_aligned_0)
++	lui	T0, %hi(.Lchacha_mips_jmptbl_aligned_0)
+ 
+ 	/* Calculate lower half jump table offset */
+ 	ins	T0, $at, 1, 6
+@@ -328,7 +328,7 @@ chacha20_mips:
+ 	addu	T1, STATE, $at
+ 
+ 	/* Add lower half jump table addr */
+-	addiu	T0, %lo(.Lchacha20_mips_jmptbl_aligned_0)
++	addiu	T0, %lo(.Lchacha_mips_jmptbl_aligned_0)
+ 
+ 	/* Read value from STATE */
+ 	lw	SAVED_CA, 0(T1)
+@@ -342,31 +342,31 @@ chacha20_mips:
+ 	FOR_EACH_WORD(JMPTBL_ALIGNED)
+ 
+ 
+-.Loop_chacha20_unaligned:
++.Loop_chacha_unaligned:
+ 	/* Set number rounds here to fill delayslot. */
+-	li	$at, 20
++	lw	$at, (STACK_SIZE+16)($sp)
+ 
+ 	/* BYTES > 0, it has no full block. */
+-	bltz	BYTES, .Lchacha20_mips_no_full_block_unaligned
++	bltz	BYTES, .Lchacha_mips_no_full_block_unaligned
+ 
+ 	FOR_EACH_WORD_REV(STORE_UNALIGNED)
+ 
+ 	/* BYTES > 0? Loop again. */
+-	bgtz	BYTES, .Loop_chacha20_rounds
++	bgtz	BYTES, .Loop_chacha_rounds
+ 
+ 	/* Write NONCE_0 back to right location in state */
+ 	sw	NONCE_0, 48(STATE)
+ 
+ 	.set noreorder
+ 	/* Fall through to byte handling */
+-	bgez	BYTES, .Lchacha20_mips_xor_done
+-.Lchacha20_mips_xor_unaligned_0_b:
+-.Lchacha20_mips_xor_aligned_0_b:
++	bgez	BYTES, .Lchacha_mips_xor_done
++.Lchacha_mips_xor_unaligned_0_b:
++.Lchacha_mips_xor_aligned_0_b:
+ 	/* Place this here to fill delay slot */
+ 	addiu	NONCE_0, 1
+ 	.set reorder
+ 
+-.Lchacha20_mips_xor_bytes:
++.Lchacha_mips_xor_bytes:
+ 	addu	IN, $at
+ 	addu	OUT, $at
+ 	/* First byte */
+@@ -376,22 +376,22 @@ chacha20_mips:
+ 	ROTR(SAVED_X)
+ 	xor	T1, SAVED_X
+ 	sb	T1, 0(OUT)
+-	beqz	$at, .Lchacha20_mips_xor_done
++	beqz	$at, .Lchacha_mips_xor_done
+ 	/* Second byte */
+ 	lbu	T1, 1(IN)
+ 	addiu	$at, BYTES, 2
+ 	ROTx	SAVED_X, 8
+ 	xor	T1, SAVED_X
+ 	sb	T1, 1(OUT)
+-	beqz	$at, .Lchacha20_mips_xor_done
++	beqz	$at, .Lchacha_mips_xor_done
+ 	/* Third byte */
+ 	lbu	T1, 2(IN)
+ 	ROTx	SAVED_X, 8
+ 	xor	T1, SAVED_X
+ 	sb	T1, 2(OUT)
+-	b	.Lchacha20_mips_xor_done
++	b	.Lchacha_mips_xor_done
+ 
+-.Lchacha20_mips_no_full_block_unaligned:
++.Lchacha_mips_no_full_block_unaligned:
+ 	/* Restore the offset on BYTES */
+ 	addiu	BYTES, CHACHA20_BLOCK_SIZE
+ 
+@@ -399,7 +399,7 @@ chacha20_mips:
+ 	andi	$at, BYTES, MASK_U32
+ 
+ 	/* Load upper half of jump table addr */
+-	lui	T0, %hi(.Lchacha20_mips_jmptbl_unaligned_0)
++	lui	T0, %hi(.Lchacha_mips_jmptbl_unaligned_0)
+ 
+ 	/* Calculate lower half jump table offset */
+ 	ins	T0, $at, 1, 6
+@@ -408,7 +408,7 @@ chacha20_mips:
+ 	addu	T1, STATE, $at
+ 
+ 	/* Add lower half jump table addr */
+-	addiu	T0, %lo(.Lchacha20_mips_jmptbl_unaligned_0)
++	addiu	T0, %lo(.Lchacha_mips_jmptbl_unaligned_0)
+ 
+ 	/* Read value from STATE */
+ 	lw	SAVED_CA, 0(T1)
+@@ -420,5 +420,78 @@ chacha20_mips:
+ 
+ 	/* Jump table */
+ 	FOR_EACH_WORD(JMPTBL_UNALIGNED)
+-.end chacha20_mips
++.end chacha_crypt_arch
++.set at
++
++/* Input arguments
++ * STATE	$a0
++ * OUT		$a1
++ * NROUND	$a2
++ */
++
++#undef X12
++#undef X13
++#undef X14
++#undef X15
++
++#define X12	$a3
++#define X13	$at
++#define X14	$v0
++#define X15	STATE
++
++.set noat
++.globl	hchacha_block_arch
++.ent	hchacha_block_arch
++hchacha_block_arch:
++	.frame	$sp, STACK_SIZE, $ra
++
++	addiu	$sp, -STACK_SIZE
++
++	/* Save X11(s6) */
++	sw	X11, 0($sp)
++
++	lw	X0,  0(STATE)
++	lw	X1,  4(STATE)
++	lw	X2,  8(STATE)
++	lw	X3,  12(STATE)
++	lw	X4,  16(STATE)
++	lw	X5,  20(STATE)
++	lw	X6,  24(STATE)
++	lw	X7,  28(STATE)
++	lw	X8,  32(STATE)
++	lw	X9,  36(STATE)
++	lw	X10, 40(STATE)
++	lw	X11, 44(STATE)
++	lw	X12, 48(STATE)
++	lw	X13, 52(STATE)
++	lw	X14, 56(STATE)
++	lw	X15, 60(STATE)
++
++.Loop_hchacha_xor_rounds:
++	addiu	$a2, -2
++	AXR( 0, 1, 2, 3,  4, 5, 6, 7, 12,13,14,15, 16);
++	AXR( 8, 9,10,11, 12,13,14,15,  4, 5, 6, 7, 12);
++	AXR( 0, 1, 2, 3,  4, 5, 6, 7, 12,13,14,15,  8);
++	AXR( 8, 9,10,11, 12,13,14,15,  4, 5, 6, 7,  7);
++	AXR( 0, 1, 2, 3,  5, 6, 7, 4, 15,12,13,14, 16);
++	AXR(10,11, 8, 9, 15,12,13,14,  5, 6, 7, 4, 12);
++	AXR( 0, 1, 2, 3,  5, 6, 7, 4, 15,12,13,14,  8);
++	AXR(10,11, 8, 9, 15,12,13,14,  5, 6, 7, 4,  7);
++	bnez	$a2, .Loop_hchacha_xor_rounds
++
++	/* Restore used register */
++	lw	X11, 0($sp)
++
++	sw	X0,  0(OUT)
++	sw	X1,  4(OUT)
++	sw	X2,  8(OUT)
++	sw	X3,  12(OUT)
++	sw	X12, 16(OUT)
++	sw	X13, 20(OUT)
++	sw	X14, 24(OUT)
++	sw	X15, 28(OUT)
++
++	addiu	$sp, STACK_SIZE
++	jr	$ra
++.end hchacha_block_arch
+ .set at
+--- /dev/null
++++ b/arch/mips/crypto/chacha-glue.c
+@@ -0,0 +1,150 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * MIPS accelerated ChaCha and XChaCha stream ciphers,
++ * including ChaCha20 (RFC7539)
++ *
++ * Copyright (C) 2019 Linaro, Ltd. <ard.biesheuvel@linaro.org>
++ */
++
++#include <asm/byteorder.h>
++#include <crypto/algapi.h>
++#include <crypto/internal/chacha.h>
++#include <crypto/internal/skcipher.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++
++asmlinkage void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src,
++				  unsigned int bytes, int nrounds);
++EXPORT_SYMBOL(chacha_crypt_arch);
++
++asmlinkage void hchacha_block_arch(const u32 *state, u32 *stream, int nrounds);
++EXPORT_SYMBOL(hchacha_block_arch);
++
++void chacha_init_arch(u32 *state, const u32 *key, const u8 *iv)
++{
++	chacha_init_generic(state, key, iv);
++}
++EXPORT_SYMBOL(chacha_init_arch);
++
++static int chacha_mips_stream_xor(struct skcipher_request *req,
++				  const struct chacha_ctx *ctx, const u8 *iv)
++{
++	struct skcipher_walk walk;
++	u32 state[16];
++	int err;
++
++	err = skcipher_walk_virt(&walk, req, false);
++
++	chacha_init_generic(state, ctx->key, iv);
++
++	while (walk.nbytes > 0) {
++		unsigned int nbytes = walk.nbytes;
++
++		if (nbytes < walk.total)
++			nbytes = round_down(nbytes, walk.stride);
++
++		chacha_crypt(state, walk.dst.virt.addr, walk.src.virt.addr,
++			     nbytes, ctx->nrounds);
++		err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
++	}
++
++	return err;
++}
++
++static int chacha_mips(struct skcipher_request *req)
++{
++	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
++	struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
++
++	return chacha_mips_stream_xor(req, ctx, req->iv);
++}
++
++static int xchacha_mips(struct skcipher_request *req)
++{
++	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
++	struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
++	struct chacha_ctx subctx;
++	u32 state[16];
++	u8 real_iv[16];
++
++	chacha_init_generic(state, ctx->key, req->iv);
++
++	hchacha_block(state, subctx.key, ctx->nrounds);
++	subctx.nrounds = ctx->nrounds;
++
++	memcpy(&real_iv[0], req->iv + 24, 8);
++	memcpy(&real_iv[8], req->iv + 16, 8);
++	return chacha_mips_stream_xor(req, &subctx, real_iv);
++}
++
++static struct skcipher_alg algs[] = {
++	{
++		.base.cra_name		= "chacha20",
++		.base.cra_driver_name	= "chacha20-mips",
++		.base.cra_priority	= 200,
++		.base.cra_blocksize	= 1,
++		.base.cra_ctxsize	= sizeof(struct chacha_ctx),
++		.base.cra_module	= THIS_MODULE,
++
++		.min_keysize		= CHACHA_KEY_SIZE,
++		.max_keysize		= CHACHA_KEY_SIZE,
++		.ivsize			= CHACHA_IV_SIZE,
++		.chunksize		= CHACHA_BLOCK_SIZE,
++		.setkey			= chacha20_setkey,
++		.encrypt		= chacha_mips,
++		.decrypt		= chacha_mips,
++	}, {
++		.base.cra_name		= "xchacha20",
++		.base.cra_driver_name	= "xchacha20-mips",
++		.base.cra_priority	= 200,
++		.base.cra_blocksize	= 1,
++		.base.cra_ctxsize	= sizeof(struct chacha_ctx),
++		.base.cra_module	= THIS_MODULE,
++
++		.min_keysize		= CHACHA_KEY_SIZE,
++		.max_keysize		= CHACHA_KEY_SIZE,
++		.ivsize			= XCHACHA_IV_SIZE,
++		.chunksize		= CHACHA_BLOCK_SIZE,
++		.setkey			= chacha20_setkey,
++		.encrypt		= xchacha_mips,
++		.decrypt		= xchacha_mips,
++	}, {
++		.base.cra_name		= "xchacha12",
++		.base.cra_driver_name	= "xchacha12-mips",
++		.base.cra_priority	= 200,
++		.base.cra_blocksize	= 1,
++		.base.cra_ctxsize	= sizeof(struct chacha_ctx),
++		.base.cra_module	= THIS_MODULE,
++
++		.min_keysize		= CHACHA_KEY_SIZE,
++		.max_keysize		= CHACHA_KEY_SIZE,
++		.ivsize			= XCHACHA_IV_SIZE,
++		.chunksize		= CHACHA_BLOCK_SIZE,
++		.setkey			= chacha12_setkey,
++		.encrypt		= xchacha_mips,
++		.decrypt		= xchacha_mips,
++	}
++};
++
++static int __init chacha_simd_mod_init(void)
++{
++	return crypto_register_skciphers(algs, ARRAY_SIZE(algs));
++}
++
++static void __exit chacha_simd_mod_fini(void)
++{
++	crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
++}
++
++module_init(chacha_simd_mod_init);
++module_exit(chacha_simd_mod_fini);
++
++MODULE_DESCRIPTION("ChaCha and XChaCha stream ciphers (MIPS accelerated)");
++MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS_CRYPTO("chacha20");
++MODULE_ALIAS_CRYPTO("chacha20-mips");
++MODULE_ALIAS_CRYPTO("xchacha20");
++MODULE_ALIAS_CRYPTO("xchacha20-mips");
++MODULE_ALIAS_CRYPTO("xchacha12");
++MODULE_ALIAS_CRYPTO("xchacha12-mips");
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -1423,6 +1423,12 @@ config CRYPTO_CHACHA20_X86_64
+ 	  SSSE3, AVX2, and AVX-512VL optimized implementations of the ChaCha20,
+ 	  XChaCha20, and XChaCha12 stream ciphers.
+ 
++config CRYPTO_CHACHA_MIPS
++	tristate "ChaCha stream cipher algorithms (MIPS 32r2 optimized)"
++	depends on CPU_MIPS32_R2
++	select CRYPTO_BLKCIPHER
++	select CRYPTO_ARCH_HAVE_LIB_CHACHA
++
+ config CRYPTO_SEED
+ 	tristate "SEED cipher algorithm"
+ 	select CRYPTO_ALGAPI
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0012-crypto-chacha-unexport-chacha_generic-routines.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0012-crypto-chacha-unexport-chacha_generic-routines.patch
new file mode 100644
index 0000000..d06f47a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0012-crypto-chacha-unexport-chacha_generic-routines.patch
@@ -0,0 +1,115 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:18 +0100
+Subject: [PATCH] crypto: chacha - unexport chacha_generic routines
+
+commit 22cf705360707ced15f9fe5423938f313c7df536 upstream.
+
+Now that all users of generic ChaCha code have moved to the core library,
+there is no longer a need for the generic ChaCha skcpiher driver to
+export parts of it implementation for reuse by other drivers. So drop
+the exports, and make the symbols static.
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ crypto/chacha_generic.c          | 26 ++++++++------------------
+ include/crypto/internal/chacha.h | 10 ----------
+ 2 files changed, 8 insertions(+), 28 deletions(-)
+
+--- a/crypto/chacha_generic.c
++++ b/crypto/chacha_generic.c
+@@ -21,7 +21,7 @@ static int chacha_stream_xor(struct skci
+ 
+ 	err = skcipher_walk_virt(&walk, req, false);
+ 
+-	crypto_chacha_init(state, ctx, iv);
++	chacha_init_generic(state, ctx->key, iv);
+ 
+ 	while (walk.nbytes > 0) {
+ 		unsigned int nbytes = walk.nbytes;
+@@ -37,36 +37,27 @@ static int chacha_stream_xor(struct skci
+ 	return err;
+ }
+ 
+-void crypto_chacha_init(u32 *state, const struct chacha_ctx *ctx, const u8 *iv)
+-{
+-	chacha_init_generic(state, ctx->key, iv);
+-}
+-EXPORT_SYMBOL_GPL(crypto_chacha_init);
+-
+-int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key,
+-			   unsigned int keysize)
++static int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key,
++				  unsigned int keysize)
+ {
+ 	return chacha_setkey(tfm, key, keysize, 20);
+ }
+-EXPORT_SYMBOL_GPL(crypto_chacha20_setkey);
+ 
+-int crypto_chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key,
+-			   unsigned int keysize)
++static int crypto_chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key,
++				 unsigned int keysize)
+ {
+ 	return chacha_setkey(tfm, key, keysize, 12);
+ }
+-EXPORT_SYMBOL_GPL(crypto_chacha12_setkey);
+ 
+-int crypto_chacha_crypt(struct skcipher_request *req)
++static int crypto_chacha_crypt(struct skcipher_request *req)
+ {
+ 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ 	struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
+ 
+ 	return chacha_stream_xor(req, ctx, req->iv);
+ }
+-EXPORT_SYMBOL_GPL(crypto_chacha_crypt);
+ 
+-int crypto_xchacha_crypt(struct skcipher_request *req)
++static int crypto_xchacha_crypt(struct skcipher_request *req)
+ {
+ 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ 	struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
+@@ -75,7 +66,7 @@ int crypto_xchacha_crypt(struct skcipher
+ 	u8 real_iv[16];
+ 
+ 	/* Compute the subkey given the original key and first 128 nonce bits */
+-	crypto_chacha_init(state, ctx, req->iv);
++	chacha_init_generic(state, ctx->key, req->iv);
+ 	hchacha_block_generic(state, subctx.key, ctx->nrounds);
+ 	subctx.nrounds = ctx->nrounds;
+ 
+@@ -86,7 +77,6 @@ int crypto_xchacha_crypt(struct skcipher
+ 	/* Generate the stream and XOR it with the data */
+ 	return chacha_stream_xor(req, &subctx, real_iv);
+ }
+-EXPORT_SYMBOL_GPL(crypto_xchacha_crypt);
+ 
+ static struct skcipher_alg algs[] = {
+ 	{
+--- a/include/crypto/internal/chacha.h
++++ b/include/crypto/internal/chacha.h
+@@ -12,8 +12,6 @@ struct chacha_ctx {
+ 	int nrounds;
+ };
+ 
+-void crypto_chacha_init(u32 *state, const struct chacha_ctx *ctx, const u8 *iv);
+-
+ static inline int chacha_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ 				unsigned int keysize, int nrounds)
+ {
+@@ -42,12 +40,4 @@ static int inline chacha12_setkey(struct
+ 	return chacha_setkey(tfm, key, keysize, 12);
+ }
+ 
+-int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key,
+-			   unsigned int keysize);
+-int crypto_chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key,
+-			   unsigned int keysize);
+-
+-int crypto_chacha_crypt(struct skcipher_request *req);
+-int crypto_xchacha_crypt(struct skcipher_request *req);
+-
+ #endif /* _CRYPTO_CHACHA_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0013-crypto-poly1305-move-core-routines-into-a-separate-l.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0013-crypto-poly1305-move-core-routines-into-a-separate-l.patch
new file mode 100644
index 0000000..960300d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0013-crypto-poly1305-move-core-routines-into-a-separate-l.patch
@@ -0,0 +1,649 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:19 +0100
+Subject: [PATCH] crypto: poly1305 - move core routines into a separate library
+
+commit 48ea8c6ebc96bc0990e12ee1c43d0832c23576bb upstream.
+
+Move the core Poly1305 routines shared between the generic Poly1305
+shash driver and the Adiantum and NHPoly1305 drivers into a separate
+library so that using just this pieces does not pull in the crypto
+API pieces of the generic Poly1305 routine.
+
+In a subsequent patch, we will augment this generic library with
+init/update/final routines so that Poyl1305 algorithm can be used
+directly without the need for using the crypto API's shash abstraction.
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/poly1305_glue.c    |   2 +-
+ crypto/Kconfig                     |   5 +-
+ crypto/adiantum.c                  |   5 +-
+ crypto/nhpoly1305.c                |   3 +-
+ crypto/poly1305_generic.c          | 195 ++---------------------------
+ include/crypto/internal/poly1305.h |  67 ++++++++++
+ include/crypto/poly1305.h          |  23 ----
+ lib/crypto/Kconfig                 |   3 +
+ lib/crypto/Makefile                |   3 +
+ lib/crypto/poly1305.c              | 158 +++++++++++++++++++++++
+ 10 files changed, 248 insertions(+), 216 deletions(-)
+ create mode 100644 include/crypto/internal/poly1305.h
+ create mode 100644 lib/crypto/poly1305.c
+
+--- a/arch/x86/crypto/poly1305_glue.c
++++ b/arch/x86/crypto/poly1305_glue.c
+@@ -7,8 +7,8 @@
+ 
+ #include <crypto/algapi.h>
+ #include <crypto/internal/hash.h>
++#include <crypto/internal/poly1305.h>
+ #include <crypto/internal/simd.h>
+-#include <crypto/poly1305.h>
+ #include <linux/crypto.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -446,7 +446,7 @@ config CRYPTO_KEYWRAP
+ config CRYPTO_NHPOLY1305
+ 	tristate
+ 	select CRYPTO_HASH
+-	select CRYPTO_POLY1305
++	select CRYPTO_LIB_POLY1305_GENERIC
+ 
+ config CRYPTO_NHPOLY1305_SSE2
+ 	tristate "NHPoly1305 hash function (x86_64 SSE2 implementation)"
+@@ -467,7 +467,7 @@ config CRYPTO_NHPOLY1305_AVX2
+ config CRYPTO_ADIANTUM
+ 	tristate "Adiantum support"
+ 	select CRYPTO_CHACHA20
+-	select CRYPTO_POLY1305
++	select CRYPTO_LIB_POLY1305_GENERIC
+ 	select CRYPTO_NHPOLY1305
+ 	select CRYPTO_MANAGER
+ 	help
+@@ -686,6 +686,7 @@ config CRYPTO_GHASH
+ config CRYPTO_POLY1305
+ 	tristate "Poly1305 authenticator algorithm"
+ 	select CRYPTO_HASH
++	select CRYPTO_LIB_POLY1305_GENERIC
+ 	help
+ 	  Poly1305 authenticator algorithm, RFC7539.
+ 
+--- a/crypto/adiantum.c
++++ b/crypto/adiantum.c
+@@ -33,6 +33,7 @@
+ #include <crypto/b128ops.h>
+ #include <crypto/chacha.h>
+ #include <crypto/internal/hash.h>
++#include <crypto/internal/poly1305.h>
+ #include <crypto/internal/skcipher.h>
+ #include <crypto/nhpoly1305.h>
+ #include <crypto/scatterwalk.h>
+@@ -242,11 +243,11 @@ static void adiantum_hash_header(struct
+ 
+ 	BUILD_BUG_ON(sizeof(header) % POLY1305_BLOCK_SIZE != 0);
+ 	poly1305_core_blocks(&state, &tctx->header_hash_key,
+-			     &header, sizeof(header) / POLY1305_BLOCK_SIZE);
++			     &header, sizeof(header) / POLY1305_BLOCK_SIZE, 1);
+ 
+ 	BUILD_BUG_ON(TWEAK_SIZE % POLY1305_BLOCK_SIZE != 0);
+ 	poly1305_core_blocks(&state, &tctx->header_hash_key, req->iv,
+-			     TWEAK_SIZE / POLY1305_BLOCK_SIZE);
++			     TWEAK_SIZE / POLY1305_BLOCK_SIZE, 1);
+ 
+ 	poly1305_core_emit(&state, &rctx->header_hash);
+ }
+--- a/crypto/nhpoly1305.c
++++ b/crypto/nhpoly1305.c
+@@ -33,6 +33,7 @@
+ #include <asm/unaligned.h>
+ #include <crypto/algapi.h>
+ #include <crypto/internal/hash.h>
++#include <crypto/internal/poly1305.h>
+ #include <crypto/nhpoly1305.h>
+ #include <linux/crypto.h>
+ #include <linux/kernel.h>
+@@ -78,7 +79,7 @@ static void process_nh_hash_value(struct
+ 	BUILD_BUG_ON(NH_HASH_BYTES % POLY1305_BLOCK_SIZE != 0);
+ 
+ 	poly1305_core_blocks(&state->poly_state, &key->poly_key, state->nh_hash,
+-			     NH_HASH_BYTES / POLY1305_BLOCK_SIZE);
++			     NH_HASH_BYTES / POLY1305_BLOCK_SIZE, 1);
+ }
+ 
+ /*
+--- a/crypto/poly1305_generic.c
++++ b/crypto/poly1305_generic.c
+@@ -13,27 +13,12 @@
+ 
+ #include <crypto/algapi.h>
+ #include <crypto/internal/hash.h>
+-#include <crypto/poly1305.h>
++#include <crypto/internal/poly1305.h>
+ #include <linux/crypto.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <asm/unaligned.h>
+ 
+-static inline u64 mlt(u64 a, u64 b)
+-{
+-	return a * b;
+-}
+-
+-static inline u32 sr(u64 v, u_char n)
+-{
+-	return v >> n;
+-}
+-
+-static inline u32 and(u32 v, u32 mask)
+-{
+-	return v & mask;
+-}
+-
+ int crypto_poly1305_init(struct shash_desc *desc)
+ {
+ 	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
+@@ -47,124 +32,8 @@ int crypto_poly1305_init(struct shash_de
+ }
+ EXPORT_SYMBOL_GPL(crypto_poly1305_init);
+ 
+-void poly1305_core_setkey(struct poly1305_key *key, const u8 *raw_key)
+-{
+-	/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
+-	key->r[0] = (get_unaligned_le32(raw_key +  0) >> 0) & 0x3ffffff;
+-	key->r[1] = (get_unaligned_le32(raw_key +  3) >> 2) & 0x3ffff03;
+-	key->r[2] = (get_unaligned_le32(raw_key +  6) >> 4) & 0x3ffc0ff;
+-	key->r[3] = (get_unaligned_le32(raw_key +  9) >> 6) & 0x3f03fff;
+-	key->r[4] = (get_unaligned_le32(raw_key + 12) >> 8) & 0x00fffff;
+-}
+-EXPORT_SYMBOL_GPL(poly1305_core_setkey);
+-
+-/*
+- * Poly1305 requires a unique key for each tag, which implies that we can't set
+- * it on the tfm that gets accessed by multiple users simultaneously. Instead we
+- * expect the key as the first 32 bytes in the update() call.
+- */
+-unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
+-					const u8 *src, unsigned int srclen)
+-{
+-	if (!dctx->sset) {
+-		if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) {
+-			poly1305_core_setkey(&dctx->r, src);
+-			src += POLY1305_BLOCK_SIZE;
+-			srclen -= POLY1305_BLOCK_SIZE;
+-			dctx->rset = true;
+-		}
+-		if (srclen >= POLY1305_BLOCK_SIZE) {
+-			dctx->s[0] = get_unaligned_le32(src +  0);
+-			dctx->s[1] = get_unaligned_le32(src +  4);
+-			dctx->s[2] = get_unaligned_le32(src +  8);
+-			dctx->s[3] = get_unaligned_le32(src + 12);
+-			src += POLY1305_BLOCK_SIZE;
+-			srclen -= POLY1305_BLOCK_SIZE;
+-			dctx->sset = true;
+-		}
+-	}
+-	return srclen;
+-}
+-EXPORT_SYMBOL_GPL(crypto_poly1305_setdesckey);
+-
+-static void poly1305_blocks_internal(struct poly1305_state *state,
+-				     const struct poly1305_key *key,
+-				     const void *src, unsigned int nblocks,
+-				     u32 hibit)
+-{
+-	u32 r0, r1, r2, r3, r4;
+-	u32 s1, s2, s3, s4;
+-	u32 h0, h1, h2, h3, h4;
+-	u64 d0, d1, d2, d3, d4;
+-
+-	if (!nblocks)
+-		return;
+-
+-	r0 = key->r[0];
+-	r1 = key->r[1];
+-	r2 = key->r[2];
+-	r3 = key->r[3];
+-	r4 = key->r[4];
+-
+-	s1 = r1 * 5;
+-	s2 = r2 * 5;
+-	s3 = r3 * 5;
+-	s4 = r4 * 5;
+-
+-	h0 = state->h[0];
+-	h1 = state->h[1];
+-	h2 = state->h[2];
+-	h3 = state->h[3];
+-	h4 = state->h[4];
+-
+-	do {
+-		/* h += m[i] */
+-		h0 += (get_unaligned_le32(src +  0) >> 0) & 0x3ffffff;
+-		h1 += (get_unaligned_le32(src +  3) >> 2) & 0x3ffffff;
+-		h2 += (get_unaligned_le32(src +  6) >> 4) & 0x3ffffff;
+-		h3 += (get_unaligned_le32(src +  9) >> 6) & 0x3ffffff;
+-		h4 += (get_unaligned_le32(src + 12) >> 8) | hibit;
+-
+-		/* h *= r */
+-		d0 = mlt(h0, r0) + mlt(h1, s4) + mlt(h2, s3) +
+-		     mlt(h3, s2) + mlt(h4, s1);
+-		d1 = mlt(h0, r1) + mlt(h1, r0) + mlt(h2, s4) +
+-		     mlt(h3, s3) + mlt(h4, s2);
+-		d2 = mlt(h0, r2) + mlt(h1, r1) + mlt(h2, r0) +
+-		     mlt(h3, s4) + mlt(h4, s3);
+-		d3 = mlt(h0, r3) + mlt(h1, r2) + mlt(h2, r1) +
+-		     mlt(h3, r0) + mlt(h4, s4);
+-		d4 = mlt(h0, r4) + mlt(h1, r3) + mlt(h2, r2) +
+-		     mlt(h3, r1) + mlt(h4, r0);
+-
+-		/* (partial) h %= p */
+-		d1 += sr(d0, 26);     h0 = and(d0, 0x3ffffff);
+-		d2 += sr(d1, 26);     h1 = and(d1, 0x3ffffff);
+-		d3 += sr(d2, 26);     h2 = and(d2, 0x3ffffff);
+-		d4 += sr(d3, 26);     h3 = and(d3, 0x3ffffff);
+-		h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff);
+-		h1 += h0 >> 26;       h0 = h0 & 0x3ffffff;
+-
+-		src += POLY1305_BLOCK_SIZE;
+-	} while (--nblocks);
+-
+-	state->h[0] = h0;
+-	state->h[1] = h1;
+-	state->h[2] = h2;
+-	state->h[3] = h3;
+-	state->h[4] = h4;
+-}
+-
+-void poly1305_core_blocks(struct poly1305_state *state,
+-			  const struct poly1305_key *key,
+-			  const void *src, unsigned int nblocks)
+-{
+-	poly1305_blocks_internal(state, key, src, nblocks, 1 << 24);
+-}
+-EXPORT_SYMBOL_GPL(poly1305_core_blocks);
+-
+-static void poly1305_blocks(struct poly1305_desc_ctx *dctx,
+-			    const u8 *src, unsigned int srclen, u32 hibit)
++static void poly1305_blocks(struct poly1305_desc_ctx *dctx, const u8 *src,
++			    unsigned int srclen)
+ {
+ 	unsigned int datalen;
+ 
+@@ -174,8 +43,8 @@ static void poly1305_blocks(struct poly1
+ 		srclen = datalen;
+ 	}
+ 
+-	poly1305_blocks_internal(&dctx->h, &dctx->r,
+-				 src, srclen / POLY1305_BLOCK_SIZE, hibit);
++	poly1305_core_blocks(&dctx->h, &dctx->r, src,
++			     srclen / POLY1305_BLOCK_SIZE, 1);
+ }
+ 
+ int crypto_poly1305_update(struct shash_desc *desc,
+@@ -193,13 +62,13 @@ int crypto_poly1305_update(struct shash_
+ 
+ 		if (dctx->buflen == POLY1305_BLOCK_SIZE) {
+ 			poly1305_blocks(dctx, dctx->buf,
+-					POLY1305_BLOCK_SIZE, 1 << 24);
++					POLY1305_BLOCK_SIZE);
+ 			dctx->buflen = 0;
+ 		}
+ 	}
+ 
+ 	if (likely(srclen >= POLY1305_BLOCK_SIZE)) {
+-		poly1305_blocks(dctx, src, srclen, 1 << 24);
++		poly1305_blocks(dctx, src, srclen);
+ 		src += srclen - (srclen % POLY1305_BLOCK_SIZE);
+ 		srclen %= POLY1305_BLOCK_SIZE;
+ 	}
+@@ -213,54 +82,6 @@ int crypto_poly1305_update(struct shash_
+ }
+ EXPORT_SYMBOL_GPL(crypto_poly1305_update);
+ 
+-void poly1305_core_emit(const struct poly1305_state *state, void *dst)
+-{
+-	u32 h0, h1, h2, h3, h4;
+-	u32 g0, g1, g2, g3, g4;
+-	u32 mask;
+-
+-	/* fully carry h */
+-	h0 = state->h[0];
+-	h1 = state->h[1];
+-	h2 = state->h[2];
+-	h3 = state->h[3];
+-	h4 = state->h[4];
+-
+-	h2 += (h1 >> 26);     h1 = h1 & 0x3ffffff;
+-	h3 += (h2 >> 26);     h2 = h2 & 0x3ffffff;
+-	h4 += (h3 >> 26);     h3 = h3 & 0x3ffffff;
+-	h0 += (h4 >> 26) * 5; h4 = h4 & 0x3ffffff;
+-	h1 += (h0 >> 26);     h0 = h0 & 0x3ffffff;
+-
+-	/* compute h + -p */
+-	g0 = h0 + 5;
+-	g1 = h1 + (g0 >> 26);             g0 &= 0x3ffffff;
+-	g2 = h2 + (g1 >> 26);             g1 &= 0x3ffffff;
+-	g3 = h3 + (g2 >> 26);             g2 &= 0x3ffffff;
+-	g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x3ffffff;
+-
+-	/* select h if h < p, or h + -p if h >= p */
+-	mask = (g4 >> ((sizeof(u32) * 8) - 1)) - 1;
+-	g0 &= mask;
+-	g1 &= mask;
+-	g2 &= mask;
+-	g3 &= mask;
+-	g4 &= mask;
+-	mask = ~mask;
+-	h0 = (h0 & mask) | g0;
+-	h1 = (h1 & mask) | g1;
+-	h2 = (h2 & mask) | g2;
+-	h3 = (h3 & mask) | g3;
+-	h4 = (h4 & mask) | g4;
+-
+-	/* h = h % (2^128) */
+-	put_unaligned_le32((h0 >>  0) | (h1 << 26), dst +  0);
+-	put_unaligned_le32((h1 >>  6) | (h2 << 20), dst +  4);
+-	put_unaligned_le32((h2 >> 12) | (h3 << 14), dst +  8);
+-	put_unaligned_le32((h3 >> 18) | (h4 <<  8), dst + 12);
+-}
+-EXPORT_SYMBOL_GPL(poly1305_core_emit);
+-
+ int crypto_poly1305_final(struct shash_desc *desc, u8 *dst)
+ {
+ 	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
+@@ -274,7 +95,7 @@ int crypto_poly1305_final(struct shash_d
+ 		dctx->buf[dctx->buflen++] = 1;
+ 		memset(dctx->buf + dctx->buflen, 0,
+ 		       POLY1305_BLOCK_SIZE - dctx->buflen);
+-		poly1305_blocks(dctx, dctx->buf, POLY1305_BLOCK_SIZE, 0);
++		poly1305_core_blocks(&dctx->h, &dctx->r, dctx->buf, 1, 0);
+ 	}
+ 
+ 	poly1305_core_emit(&dctx->h, digest);
+--- /dev/null
++++ b/include/crypto/internal/poly1305.h
+@@ -0,0 +1,67 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Common values for the Poly1305 algorithm
++ */
++
++#ifndef _CRYPTO_INTERNAL_POLY1305_H
++#define _CRYPTO_INTERNAL_POLY1305_H
++
++#include <asm/unaligned.h>
++#include <linux/types.h>
++#include <crypto/poly1305.h>
++
++struct shash_desc;
++
++/*
++ * Poly1305 core functions.  These implement the ε-almost-∆-universal hash
++ * function underlying the Poly1305 MAC, i.e. they don't add an encrypted nonce
++ * ("s key") at the end.  They also only support block-aligned inputs.
++ */
++void poly1305_core_setkey(struct poly1305_key *key, const u8 *raw_key);
++static inline void poly1305_core_init(struct poly1305_state *state)
++{
++	*state = (struct poly1305_state){};
++}
++
++void poly1305_core_blocks(struct poly1305_state *state,
++			  const struct poly1305_key *key, const void *src,
++			  unsigned int nblocks, u32 hibit);
++void poly1305_core_emit(const struct poly1305_state *state, void *dst);
++
++/* Crypto API helper functions for the Poly1305 MAC */
++int crypto_poly1305_init(struct shash_desc *desc);
++
++int crypto_poly1305_update(struct shash_desc *desc,
++			   const u8 *src, unsigned int srclen);
++int crypto_poly1305_final(struct shash_desc *desc, u8 *dst);
++
++/*
++ * Poly1305 requires a unique key for each tag, which implies that we can't set
++ * it on the tfm that gets accessed by multiple users simultaneously. Instead we
++ * expect the key as the first 32 bytes in the update() call.
++ */
++static inline
++unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
++					const u8 *src, unsigned int srclen)
++{
++	if (!dctx->sset) {
++		if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) {
++			poly1305_core_setkey(&dctx->r, src);
++			src += POLY1305_BLOCK_SIZE;
++			srclen -= POLY1305_BLOCK_SIZE;
++			dctx->rset = true;
++		}
++		if (srclen >= POLY1305_BLOCK_SIZE) {
++			dctx->s[0] = get_unaligned_le32(src +  0);
++			dctx->s[1] = get_unaligned_le32(src +  4);
++			dctx->s[2] = get_unaligned_le32(src +  8);
++			dctx->s[3] = get_unaligned_le32(src + 12);
++			src += POLY1305_BLOCK_SIZE;
++			srclen -= POLY1305_BLOCK_SIZE;
++			dctx->sset = true;
++		}
++	}
++	return srclen;
++}
++
++#endif
+--- a/include/crypto/poly1305.h
++++ b/include/crypto/poly1305.h
+@@ -38,27 +38,4 @@ struct poly1305_desc_ctx {
+ 	bool sset;
+ };
+ 
+-/*
+- * Poly1305 core functions.  These implement the ε-almost-∆-universal hash
+- * function underlying the Poly1305 MAC, i.e. they don't add an encrypted nonce
+- * ("s key") at the end.  They also only support block-aligned inputs.
+- */
+-void poly1305_core_setkey(struct poly1305_key *key, const u8 *raw_key);
+-static inline void poly1305_core_init(struct poly1305_state *state)
+-{
+-	memset(state->h, 0, sizeof(state->h));
+-}
+-void poly1305_core_blocks(struct poly1305_state *state,
+-			  const struct poly1305_key *key,
+-			  const void *src, unsigned int nblocks);
+-void poly1305_core_emit(const struct poly1305_state *state, void *dst);
+-
+-/* Crypto API helper functions for the Poly1305 MAC */
+-int crypto_poly1305_init(struct shash_desc *desc);
+-unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
+-					const u8 *src, unsigned int srclen);
+-int crypto_poly1305_update(struct shash_desc *desc,
+-			   const u8 *src, unsigned int srclen);
+-int crypto_poly1305_final(struct shash_desc *desc, u8 *dst);
+-
+ #endif
+--- a/lib/crypto/Kconfig
++++ b/lib/crypto/Kconfig
+@@ -37,5 +37,8 @@ config CRYPTO_LIB_CHACHA
+ config CRYPTO_LIB_DES
+ 	tristate
+ 
++config CRYPTO_LIB_POLY1305_GENERIC
++	tristate
++
+ config CRYPTO_LIB_SHA256
+ 	tristate
+--- a/lib/crypto/Makefile
++++ b/lib/crypto/Makefile
+@@ -13,5 +13,8 @@ libarc4-y					:= arc4.o
+ obj-$(CONFIG_CRYPTO_LIB_DES)			+= libdes.o
+ libdes-y					:= des.o
+ 
++obj-$(CONFIG_CRYPTO_LIB_POLY1305_GENERIC)	+= libpoly1305.o
++libpoly1305-y					:= poly1305.o
++
+ obj-$(CONFIG_CRYPTO_LIB_SHA256)			+= libsha256.o
+ libsha256-y					:= sha256.o
+--- /dev/null
++++ b/lib/crypto/poly1305.c
+@@ -0,0 +1,158 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Poly1305 authenticator algorithm, RFC7539
++ *
++ * Copyright (C) 2015 Martin Willi
++ *
++ * Based on public domain code by Andrew Moon and Daniel J. Bernstein.
++ */
++
++#include <crypto/internal/poly1305.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <asm/unaligned.h>
++
++static inline u64 mlt(u64 a, u64 b)
++{
++	return a * b;
++}
++
++static inline u32 sr(u64 v, u_char n)
++{
++	return v >> n;
++}
++
++static inline u32 and(u32 v, u32 mask)
++{
++	return v & mask;
++}
++
++void poly1305_core_setkey(struct poly1305_key *key, const u8 *raw_key)
++{
++	/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
++	key->r[0] = (get_unaligned_le32(raw_key +  0) >> 0) & 0x3ffffff;
++	key->r[1] = (get_unaligned_le32(raw_key +  3) >> 2) & 0x3ffff03;
++	key->r[2] = (get_unaligned_le32(raw_key +  6) >> 4) & 0x3ffc0ff;
++	key->r[3] = (get_unaligned_le32(raw_key +  9) >> 6) & 0x3f03fff;
++	key->r[4] = (get_unaligned_le32(raw_key + 12) >> 8) & 0x00fffff;
++}
++EXPORT_SYMBOL_GPL(poly1305_core_setkey);
++
++void poly1305_core_blocks(struct poly1305_state *state,
++			  const struct poly1305_key *key, const void *src,
++			  unsigned int nblocks, u32 hibit)
++{
++	u32 r0, r1, r2, r3, r4;
++	u32 s1, s2, s3, s4;
++	u32 h0, h1, h2, h3, h4;
++	u64 d0, d1, d2, d3, d4;
++
++	if (!nblocks)
++		return;
++
++	r0 = key->r[0];
++	r1 = key->r[1];
++	r2 = key->r[2];
++	r3 = key->r[3];
++	r4 = key->r[4];
++
++	s1 = r1 * 5;
++	s2 = r2 * 5;
++	s3 = r3 * 5;
++	s4 = r4 * 5;
++
++	h0 = state->h[0];
++	h1 = state->h[1];
++	h2 = state->h[2];
++	h3 = state->h[3];
++	h4 = state->h[4];
++
++	do {
++		/* h += m[i] */
++		h0 += (get_unaligned_le32(src +  0) >> 0) & 0x3ffffff;
++		h1 += (get_unaligned_le32(src +  3) >> 2) & 0x3ffffff;
++		h2 += (get_unaligned_le32(src +  6) >> 4) & 0x3ffffff;
++		h3 += (get_unaligned_le32(src +  9) >> 6) & 0x3ffffff;
++		h4 += (get_unaligned_le32(src + 12) >> 8) | (hibit << 24);
++
++		/* h *= r */
++		d0 = mlt(h0, r0) + mlt(h1, s4) + mlt(h2, s3) +
++		     mlt(h3, s2) + mlt(h4, s1);
++		d1 = mlt(h0, r1) + mlt(h1, r0) + mlt(h2, s4) +
++		     mlt(h3, s3) + mlt(h4, s2);
++		d2 = mlt(h0, r2) + mlt(h1, r1) + mlt(h2, r0) +
++		     mlt(h3, s4) + mlt(h4, s3);
++		d3 = mlt(h0, r3) + mlt(h1, r2) + mlt(h2, r1) +
++		     mlt(h3, r0) + mlt(h4, s4);
++		d4 = mlt(h0, r4) + mlt(h1, r3) + mlt(h2, r2) +
++		     mlt(h3, r1) + mlt(h4, r0);
++
++		/* (partial) h %= p */
++		d1 += sr(d0, 26);     h0 = and(d0, 0x3ffffff);
++		d2 += sr(d1, 26);     h1 = and(d1, 0x3ffffff);
++		d3 += sr(d2, 26);     h2 = and(d2, 0x3ffffff);
++		d4 += sr(d3, 26);     h3 = and(d3, 0x3ffffff);
++		h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff);
++		h1 += h0 >> 26;       h0 = h0 & 0x3ffffff;
++
++		src += POLY1305_BLOCK_SIZE;
++	} while (--nblocks);
++
++	state->h[0] = h0;
++	state->h[1] = h1;
++	state->h[2] = h2;
++	state->h[3] = h3;
++	state->h[4] = h4;
++}
++EXPORT_SYMBOL_GPL(poly1305_core_blocks);
++
++void poly1305_core_emit(const struct poly1305_state *state, void *dst)
++{
++	u32 h0, h1, h2, h3, h4;
++	u32 g0, g1, g2, g3, g4;
++	u32 mask;
++
++	/* fully carry h */
++	h0 = state->h[0];
++	h1 = state->h[1];
++	h2 = state->h[2];
++	h3 = state->h[3];
++	h4 = state->h[4];
++
++	h2 += (h1 >> 26);     h1 = h1 & 0x3ffffff;
++	h3 += (h2 >> 26);     h2 = h2 & 0x3ffffff;
++	h4 += (h3 >> 26);     h3 = h3 & 0x3ffffff;
++	h0 += (h4 >> 26) * 5; h4 = h4 & 0x3ffffff;
++	h1 += (h0 >> 26);     h0 = h0 & 0x3ffffff;
++
++	/* compute h + -p */
++	g0 = h0 + 5;
++	g1 = h1 + (g0 >> 26);             g0 &= 0x3ffffff;
++	g2 = h2 + (g1 >> 26);             g1 &= 0x3ffffff;
++	g3 = h3 + (g2 >> 26);             g2 &= 0x3ffffff;
++	g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x3ffffff;
++
++	/* select h if h < p, or h + -p if h >= p */
++	mask = (g4 >> ((sizeof(u32) * 8) - 1)) - 1;
++	g0 &= mask;
++	g1 &= mask;
++	g2 &= mask;
++	g3 &= mask;
++	g4 &= mask;
++	mask = ~mask;
++	h0 = (h0 & mask) | g0;
++	h1 = (h1 & mask) | g1;
++	h2 = (h2 & mask) | g2;
++	h3 = (h3 & mask) | g3;
++	h4 = (h4 & mask) | g4;
++
++	/* h = h % (2^128) */
++	put_unaligned_le32((h0 >>  0) | (h1 << 26), dst +  0);
++	put_unaligned_le32((h1 >>  6) | (h2 << 20), dst +  4);
++	put_unaligned_le32((h2 >> 12) | (h3 << 14), dst +  8);
++	put_unaligned_le32((h3 >> 18) | (h4 <<  8), dst + 12);
++}
++EXPORT_SYMBOL_GPL(poly1305_core_emit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Martin Willi <martin@strongswan.org>");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0014-crypto-x86-poly1305-unify-Poly1305-state-struct-with.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0014-crypto-x86-poly1305-unify-Poly1305-state-struct-with.patch
new file mode 100644
index 0000000..7d23754
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0014-crypto-x86-poly1305-unify-Poly1305-state-struct-with.patch
@@ -0,0 +1,251 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:20 +0100
+Subject: [PATCH] crypto: x86/poly1305 - unify Poly1305 state struct with
+ generic code
+
+commit ad8f5b88383ea685f2b8df2a12ee3e08089a1287 upstream.
+
+In preparation of exposing a Poly1305 library interface directly from
+the accelerated x86 driver, align the state descriptor of the x86 code
+with the one used by the generic driver. This is needed to make the
+library interface unified between all implementations.
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/poly1305_glue.c    | 88 ++++++++++--------------------
+ crypto/poly1305_generic.c          |  6 +-
+ include/crypto/internal/poly1305.h |  4 +-
+ include/crypto/poly1305.h          | 18 +++---
+ 4 files changed, 43 insertions(+), 73 deletions(-)
+
+--- a/arch/x86/crypto/poly1305_glue.c
++++ b/arch/x86/crypto/poly1305_glue.c
+@@ -14,40 +14,14 @@
+ #include <linux/module.h>
+ #include <asm/simd.h>
+ 
+-struct poly1305_simd_desc_ctx {
+-	struct poly1305_desc_ctx base;
+-	/* derived key u set? */
+-	bool uset;
+-#ifdef CONFIG_AS_AVX2
+-	/* derived keys r^3, r^4 set? */
+-	bool wset;
+-#endif
+-	/* derived Poly1305 key r^2 */
+-	u32 u[5];
+-	/* ... silently appended r^3 and r^4 when using AVX2 */
+-};
+-
+ asmlinkage void poly1305_block_sse2(u32 *h, const u8 *src,
+ 				    const u32 *r, unsigned int blocks);
+ asmlinkage void poly1305_2block_sse2(u32 *h, const u8 *src, const u32 *r,
+ 				     unsigned int blocks, const u32 *u);
+-#ifdef CONFIG_AS_AVX2
+ asmlinkage void poly1305_4block_avx2(u32 *h, const u8 *src, const u32 *r,
+ 				     unsigned int blocks, const u32 *u);
+-static bool poly1305_use_avx2;
+-#endif
+ 
+-static int poly1305_simd_init(struct shash_desc *desc)
+-{
+-	struct poly1305_simd_desc_ctx *sctx = shash_desc_ctx(desc);
+-
+-	sctx->uset = false;
+-#ifdef CONFIG_AS_AVX2
+-	sctx->wset = false;
+-#endif
+-
+-	return crypto_poly1305_init(desc);
+-}
++static bool poly1305_use_avx2 __ro_after_init;
+ 
+ static void poly1305_simd_mult(u32 *a, const u32 *b)
+ {
+@@ -63,53 +37,49 @@ static void poly1305_simd_mult(u32 *a, c
+ static unsigned int poly1305_simd_blocks(struct poly1305_desc_ctx *dctx,
+ 					 const u8 *src, unsigned int srclen)
+ {
+-	struct poly1305_simd_desc_ctx *sctx;
+ 	unsigned int blocks, datalen;
+ 
+-	BUILD_BUG_ON(offsetof(struct poly1305_simd_desc_ctx, base));
+-	sctx = container_of(dctx, struct poly1305_simd_desc_ctx, base);
+-
+ 	if (unlikely(!dctx->sset)) {
+ 		datalen = crypto_poly1305_setdesckey(dctx, src, srclen);
+ 		src += srclen - datalen;
+ 		srclen = datalen;
+ 	}
+ 
+-#ifdef CONFIG_AS_AVX2
+-	if (poly1305_use_avx2 && srclen >= POLY1305_BLOCK_SIZE * 4) {
+-		if (unlikely(!sctx->wset)) {
+-			if (!sctx->uset) {
+-				memcpy(sctx->u, dctx->r.r, sizeof(sctx->u));
+-				poly1305_simd_mult(sctx->u, dctx->r.r);
+-				sctx->uset = true;
++	if (IS_ENABLED(CONFIG_AS_AVX2) &&
++	    poly1305_use_avx2 &&
++	    srclen >= POLY1305_BLOCK_SIZE * 4) {
++		if (unlikely(dctx->rset < 4)) {
++			if (dctx->rset < 2) {
++				dctx->r[1] = dctx->r[0];
++				poly1305_simd_mult(dctx->r[1].r, dctx->r[0].r);
+ 			}
+-			memcpy(sctx->u + 5, sctx->u, sizeof(sctx->u));
+-			poly1305_simd_mult(sctx->u + 5, dctx->r.r);
+-			memcpy(sctx->u + 10, sctx->u + 5, sizeof(sctx->u));
+-			poly1305_simd_mult(sctx->u + 10, dctx->r.r);
+-			sctx->wset = true;
++			dctx->r[2] = dctx->r[1];
++			poly1305_simd_mult(dctx->r[2].r, dctx->r[0].r);
++			dctx->r[3] = dctx->r[2];
++			poly1305_simd_mult(dctx->r[3].r, dctx->r[0].r);
++			dctx->rset = 4;
+ 		}
+ 		blocks = srclen / (POLY1305_BLOCK_SIZE * 4);
+-		poly1305_4block_avx2(dctx->h.h, src, dctx->r.r, blocks,
+-				     sctx->u);
++		poly1305_4block_avx2(dctx->h.h, src, dctx->r[0].r, blocks,
++				     dctx->r[1].r);
+ 		src += POLY1305_BLOCK_SIZE * 4 * blocks;
+ 		srclen -= POLY1305_BLOCK_SIZE * 4 * blocks;
+ 	}
+-#endif
++
+ 	if (likely(srclen >= POLY1305_BLOCK_SIZE * 2)) {
+-		if (unlikely(!sctx->uset)) {
+-			memcpy(sctx->u, dctx->r.r, sizeof(sctx->u));
+-			poly1305_simd_mult(sctx->u, dctx->r.r);
+-			sctx->uset = true;
++		if (unlikely(dctx->rset < 2)) {
++			dctx->r[1] = dctx->r[0];
++			poly1305_simd_mult(dctx->r[1].r, dctx->r[0].r);
++			dctx->rset = 2;
+ 		}
+ 		blocks = srclen / (POLY1305_BLOCK_SIZE * 2);
+-		poly1305_2block_sse2(dctx->h.h, src, dctx->r.r, blocks,
+-				     sctx->u);
++		poly1305_2block_sse2(dctx->h.h, src, dctx->r[0].r,
++				     blocks, dctx->r[1].r);
+ 		src += POLY1305_BLOCK_SIZE * 2 * blocks;
+ 		srclen -= POLY1305_BLOCK_SIZE * 2 * blocks;
+ 	}
+ 	if (srclen >= POLY1305_BLOCK_SIZE) {
+-		poly1305_block_sse2(dctx->h.h, src, dctx->r.r, 1);
++		poly1305_block_sse2(dctx->h.h, src, dctx->r[0].r, 1);
+ 		srclen -= POLY1305_BLOCK_SIZE;
+ 	}
+ 	return srclen;
+@@ -159,10 +129,10 @@ static int poly1305_simd_update(struct s
+ 
+ static struct shash_alg alg = {
+ 	.digestsize	= POLY1305_DIGEST_SIZE,
+-	.init		= poly1305_simd_init,
++	.init		= crypto_poly1305_init,
+ 	.update		= poly1305_simd_update,
+ 	.final		= crypto_poly1305_final,
+-	.descsize	= sizeof(struct poly1305_simd_desc_ctx),
++	.descsize	= sizeof(struct poly1305_desc_ctx),
+ 	.base		= {
+ 		.cra_name		= "poly1305",
+ 		.cra_driver_name	= "poly1305-simd",
+@@ -177,14 +147,14 @@ static int __init poly1305_simd_mod_init
+ 	if (!boot_cpu_has(X86_FEATURE_XMM2))
+ 		return -ENODEV;
+ 
+-#ifdef CONFIG_AS_AVX2
+-	poly1305_use_avx2 = boot_cpu_has(X86_FEATURE_AVX) &&
++	poly1305_use_avx2 = IS_ENABLED(CONFIG_AS_AVX2) &&
++			    boot_cpu_has(X86_FEATURE_AVX) &&
+ 			    boot_cpu_has(X86_FEATURE_AVX2) &&
+ 			    cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL);
+-	alg.descsize = sizeof(struct poly1305_simd_desc_ctx);
++	alg.descsize = sizeof(struct poly1305_desc_ctx) + 5 * sizeof(u32);
+ 	if (poly1305_use_avx2)
+ 		alg.descsize += 10 * sizeof(u32);
+-#endif
++
+ 	return crypto_register_shash(&alg);
+ }
+ 
+--- a/crypto/poly1305_generic.c
++++ b/crypto/poly1305_generic.c
+@@ -25,7 +25,7 @@ int crypto_poly1305_init(struct shash_de
+ 
+ 	poly1305_core_init(&dctx->h);
+ 	dctx->buflen = 0;
+-	dctx->rset = false;
++	dctx->rset = 0;
+ 	dctx->sset = false;
+ 
+ 	return 0;
+@@ -43,7 +43,7 @@ static void poly1305_blocks(struct poly1
+ 		srclen = datalen;
+ 	}
+ 
+-	poly1305_core_blocks(&dctx->h, &dctx->r, src,
++	poly1305_core_blocks(&dctx->h, dctx->r, src,
+ 			     srclen / POLY1305_BLOCK_SIZE, 1);
+ }
+ 
+@@ -95,7 +95,7 @@ int crypto_poly1305_final(struct shash_d
+ 		dctx->buf[dctx->buflen++] = 1;
+ 		memset(dctx->buf + dctx->buflen, 0,
+ 		       POLY1305_BLOCK_SIZE - dctx->buflen);
+-		poly1305_core_blocks(&dctx->h, &dctx->r, dctx->buf, 1, 0);
++		poly1305_core_blocks(&dctx->h, dctx->r, dctx->buf, 1, 0);
+ 	}
+ 
+ 	poly1305_core_emit(&dctx->h, digest);
+--- a/include/crypto/internal/poly1305.h
++++ b/include/crypto/internal/poly1305.h
+@@ -46,10 +46,10 @@ unsigned int crypto_poly1305_setdesckey(
+ {
+ 	if (!dctx->sset) {
+ 		if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) {
+-			poly1305_core_setkey(&dctx->r, src);
++			poly1305_core_setkey(dctx->r, src);
+ 			src += POLY1305_BLOCK_SIZE;
+ 			srclen -= POLY1305_BLOCK_SIZE;
+-			dctx->rset = true;
++			dctx->rset = 1;
+ 		}
+ 		if (srclen >= POLY1305_BLOCK_SIZE) {
+ 			dctx->s[0] = get_unaligned_le32(src +  0);
+--- a/include/crypto/poly1305.h
++++ b/include/crypto/poly1305.h
+@@ -22,20 +22,20 @@ struct poly1305_state {
+ };
+ 
+ struct poly1305_desc_ctx {
+-	/* key */
+-	struct poly1305_key r;
+-	/* finalize key */
+-	u32 s[4];
+-	/* accumulator */
+-	struct poly1305_state h;
+ 	/* partial buffer */
+ 	u8 buf[POLY1305_BLOCK_SIZE];
+ 	/* bytes used in partial buffer */
+ 	unsigned int buflen;
+-	/* r key has been set */
+-	bool rset;
+-	/* s key has been set */
++	/* how many keys have been set in r[] */
++	unsigned short rset;
++	/* whether s[] has been set */
+ 	bool sset;
++	/* finalize key */
++	u32 s[4];
++	/* accumulator */
++	struct poly1305_state h;
++	/* key */
++	struct poly1305_key r[1];
+ };
+ 
+ #endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0015-crypto-poly1305-expose-init-update-final-library-int.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0015-crypto-poly1305-expose-init-update-final-library-int.patch
new file mode 100644
index 0000000..bf8e90b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0015-crypto-poly1305-expose-init-update-final-library-int.patch
@@ -0,0 +1,224 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:21 +0100
+Subject: [PATCH] crypto: poly1305 - expose init/update/final library interface
+
+commit a1d93064094cc5e24d64e35cf093e7191d0c9344 upstream.
+
+Expose the existing generic Poly1305 code via a init/update/final
+library interface so that callers are not required to go through
+the crypto API's shash abstraction to access it. At the same time,
+make some preparations so that the library implementation can be
+superseded by an accelerated arch-specific version in the future.
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ crypto/poly1305_generic.c | 22 +-----------
+ include/crypto/poly1305.h | 38 +++++++++++++++++++-
+ lib/crypto/Kconfig        | 26 ++++++++++++++
+ lib/crypto/poly1305.c     | 74 +++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 138 insertions(+), 22 deletions(-)
+
+--- a/crypto/poly1305_generic.c
++++ b/crypto/poly1305_generic.c
+@@ -85,31 +85,11 @@ EXPORT_SYMBOL_GPL(crypto_poly1305_update
+ int crypto_poly1305_final(struct shash_desc *desc, u8 *dst)
+ {
+ 	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
+-	__le32 digest[4];
+-	u64 f = 0;
+ 
+ 	if (unlikely(!dctx->sset))
+ 		return -ENOKEY;
+ 
+-	if (unlikely(dctx->buflen)) {
+-		dctx->buf[dctx->buflen++] = 1;
+-		memset(dctx->buf + dctx->buflen, 0,
+-		       POLY1305_BLOCK_SIZE - dctx->buflen);
+-		poly1305_core_blocks(&dctx->h, dctx->r, dctx->buf, 1, 0);
+-	}
+-
+-	poly1305_core_emit(&dctx->h, digest);
+-
+-	/* mac = (h + s) % (2^128) */
+-	f = (f >> 32) + le32_to_cpu(digest[0]) + dctx->s[0];
+-	put_unaligned_le32(f, dst + 0);
+-	f = (f >> 32) + le32_to_cpu(digest[1]) + dctx->s[1];
+-	put_unaligned_le32(f, dst + 4);
+-	f = (f >> 32) + le32_to_cpu(digest[2]) + dctx->s[2];
+-	put_unaligned_le32(f, dst + 8);
+-	f = (f >> 32) + le32_to_cpu(digest[3]) + dctx->s[3];
+-	put_unaligned_le32(f, dst + 12);
+-
++	poly1305_final_generic(dctx, dst);
+ 	return 0;
+ }
+ EXPORT_SYMBOL_GPL(crypto_poly1305_final);
+--- a/include/crypto/poly1305.h
++++ b/include/crypto/poly1305.h
+@@ -35,7 +35,43 @@ struct poly1305_desc_ctx {
+ 	/* accumulator */
+ 	struct poly1305_state h;
+ 	/* key */
+-	struct poly1305_key r[1];
++	struct poly1305_key r[CONFIG_CRYPTO_LIB_POLY1305_RSIZE];
+ };
+ 
++void poly1305_init_arch(struct poly1305_desc_ctx *desc, const u8 *key);
++void poly1305_init_generic(struct poly1305_desc_ctx *desc, const u8 *key);
++
++static inline void poly1305_init(struct poly1305_desc_ctx *desc, const u8 *key)
++{
++	if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_POLY1305))
++		poly1305_init_arch(desc, key);
++	else
++		poly1305_init_generic(desc, key);
++}
++
++void poly1305_update_arch(struct poly1305_desc_ctx *desc, const u8 *src,
++			  unsigned int nbytes);
++void poly1305_update_generic(struct poly1305_desc_ctx *desc, const u8 *src,
++			     unsigned int nbytes);
++
++static inline void poly1305_update(struct poly1305_desc_ctx *desc,
++				   const u8 *src, unsigned int nbytes)
++{
++	if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_POLY1305))
++		poly1305_update_arch(desc, src, nbytes);
++	else
++		poly1305_update_generic(desc, src, nbytes);
++}
++
++void poly1305_final_arch(struct poly1305_desc_ctx *desc, u8 *digest);
++void poly1305_final_generic(struct poly1305_desc_ctx *desc, u8 *digest);
++
++static inline void poly1305_final(struct poly1305_desc_ctx *desc, u8 *digest)
++{
++	if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_POLY1305))
++		poly1305_final_arch(desc, digest);
++	else
++		poly1305_final_generic(desc, digest);
++}
++
+ #endif
+--- a/lib/crypto/Kconfig
++++ b/lib/crypto/Kconfig
+@@ -37,8 +37,34 @@ config CRYPTO_LIB_CHACHA
+ config CRYPTO_LIB_DES
+ 	tristate
+ 
++config CRYPTO_LIB_POLY1305_RSIZE
++	int
++	default 1
++
++config CRYPTO_ARCH_HAVE_LIB_POLY1305
++	tristate
++	help
++	  Declares whether the architecture provides an arch-specific
++	  accelerated implementation of the Poly1305 library interface,
++	  either builtin or as a module.
++
+ config CRYPTO_LIB_POLY1305_GENERIC
+ 	tristate
++	help
++	  This symbol can be depended upon by arch implementations of the
++	  Poly1305 library interface that require the generic code as a
++	  fallback, e.g., for SIMD implementations. If no arch specific
++	  implementation is enabled, this implementation serves the users
++	  of CRYPTO_LIB_POLY1305.
++
++config CRYPTO_LIB_POLY1305
++	tristate "Poly1305 library interface"
++	depends on CRYPTO_ARCH_HAVE_LIB_POLY1305 || !CRYPTO_ARCH_HAVE_LIB_POLY1305
++	select CRYPTO_LIB_POLY1305_GENERIC if CRYPTO_ARCH_HAVE_LIB_POLY1305=n
++	help
++	  Enable the Poly1305 library interface. This interface may be fulfilled
++	  by either the generic implementation or an arch-specific one, if one
++	  is available and enabled.
+ 
+ config CRYPTO_LIB_SHA256
+ 	tristate
+--- a/lib/crypto/poly1305.c
++++ b/lib/crypto/poly1305.c
+@@ -154,5 +154,79 @@ void poly1305_core_emit(const struct pol
+ }
+ EXPORT_SYMBOL_GPL(poly1305_core_emit);
+ 
++void poly1305_init_generic(struct poly1305_desc_ctx *desc, const u8 *key)
++{
++	poly1305_core_setkey(desc->r, key);
++	desc->s[0] = get_unaligned_le32(key + 16);
++	desc->s[1] = get_unaligned_le32(key + 20);
++	desc->s[2] = get_unaligned_le32(key + 24);
++	desc->s[3] = get_unaligned_le32(key + 28);
++	poly1305_core_init(&desc->h);
++	desc->buflen = 0;
++	desc->sset = true;
++	desc->rset = 1;
++}
++EXPORT_SYMBOL_GPL(poly1305_init_generic);
++
++void poly1305_update_generic(struct poly1305_desc_ctx *desc, const u8 *src,
++			     unsigned int nbytes)
++{
++	unsigned int bytes;
++
++	if (unlikely(desc->buflen)) {
++		bytes = min(nbytes, POLY1305_BLOCK_SIZE - desc->buflen);
++		memcpy(desc->buf + desc->buflen, src, bytes);
++		src += bytes;
++		nbytes -= bytes;
++		desc->buflen += bytes;
++
++		if (desc->buflen == POLY1305_BLOCK_SIZE) {
++			poly1305_core_blocks(&desc->h, desc->r, desc->buf, 1, 1);
++			desc->buflen = 0;
++		}
++	}
++
++	if (likely(nbytes >= POLY1305_BLOCK_SIZE)) {
++		poly1305_core_blocks(&desc->h, desc->r, src,
++				     nbytes / POLY1305_BLOCK_SIZE, 1);
++		src += nbytes - (nbytes % POLY1305_BLOCK_SIZE);
++		nbytes %= POLY1305_BLOCK_SIZE;
++	}
++
++	if (unlikely(nbytes)) {
++		desc->buflen = nbytes;
++		memcpy(desc->buf, src, nbytes);
++	}
++}
++EXPORT_SYMBOL_GPL(poly1305_update_generic);
++
++void poly1305_final_generic(struct poly1305_desc_ctx *desc, u8 *dst)
++{
++	__le32 digest[4];
++	u64 f = 0;
++
++	if (unlikely(desc->buflen)) {
++		desc->buf[desc->buflen++] = 1;
++		memset(desc->buf + desc->buflen, 0,
++		       POLY1305_BLOCK_SIZE - desc->buflen);
++		poly1305_core_blocks(&desc->h, desc->r, desc->buf, 1, 0);
++	}
++
++	poly1305_core_emit(&desc->h, digest);
++
++	/* mac = (h + s) % (2^128) */
++	f = (f >> 32) + le32_to_cpu(digest[0]) + desc->s[0];
++	put_unaligned_le32(f, dst + 0);
++	f = (f >> 32) + le32_to_cpu(digest[1]) + desc->s[1];
++	put_unaligned_le32(f, dst + 4);
++	f = (f >> 32) + le32_to_cpu(digest[2]) + desc->s[2];
++	put_unaligned_le32(f, dst + 8);
++	f = (f >> 32) + le32_to_cpu(digest[3]) + desc->s[3];
++	put_unaligned_le32(f, dst + 12);
++
++	*desc = (struct poly1305_desc_ctx){};
++}
++EXPORT_SYMBOL_GPL(poly1305_final_generic);
++
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Martin Willi <martin@strongswan.org>");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0016-crypto-x86-poly1305-depend-on-generic-library-not-ge.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0016-crypto-x86-poly1305-depend-on-generic-library-not-ge.patch
new file mode 100644
index 0000000..8ea63f3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0016-crypto-x86-poly1305-depend-on-generic-library-not-ge.patch
@@ -0,0 +1,217 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:22 +0100
+Subject: [PATCH] crypto: x86/poly1305 - depend on generic library not generic
+ shash
+
+commit 1b2c6a5120489d41c8ea3b8dacd0b4586289b158 upstream.
+
+Remove the dependency on the generic Poly1305 driver. Instead, depend
+on the generic library so that we only reuse code without pulling in
+the generic skcipher implementation as well.
+
+While at it, remove the logic that prefers the non-SIMD path for short
+inputs - this is no longer necessary after recent FPU handling changes
+on x86.
+
+Since this removes the last remaining user of the routines exported
+by the generic shash driver, unexport them and make them static.
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/poly1305_glue.c    | 66 +++++++++++++++++++++++++-----
+ crypto/Kconfig                     |  2 +-
+ crypto/poly1305_generic.c          | 11 ++---
+ include/crypto/internal/poly1305.h |  9 ----
+ 4 files changed, 60 insertions(+), 28 deletions(-)
+
+--- a/arch/x86/crypto/poly1305_glue.c
++++ b/arch/x86/crypto/poly1305_glue.c
+@@ -34,6 +34,24 @@ static void poly1305_simd_mult(u32 *a, c
+ 	poly1305_block_sse2(a, m, b, 1);
+ }
+ 
++static unsigned int poly1305_scalar_blocks(struct poly1305_desc_ctx *dctx,
++					   const u8 *src, unsigned int srclen)
++{
++	unsigned int datalen;
++
++	if (unlikely(!dctx->sset)) {
++		datalen = crypto_poly1305_setdesckey(dctx, src, srclen);
++		src += srclen - datalen;
++		srclen = datalen;
++	}
++	if (srclen >= POLY1305_BLOCK_SIZE) {
++		poly1305_core_blocks(&dctx->h, dctx->r, src,
++				     srclen / POLY1305_BLOCK_SIZE, 1);
++		srclen %= POLY1305_BLOCK_SIZE;
++	}
++	return srclen;
++}
++
+ static unsigned int poly1305_simd_blocks(struct poly1305_desc_ctx *dctx,
+ 					 const u8 *src, unsigned int srclen)
+ {
+@@ -91,12 +109,6 @@ static int poly1305_simd_update(struct s
+ 	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
+ 	unsigned int bytes;
+ 
+-	/* kernel_fpu_begin/end is costly, use fallback for small updates */
+-	if (srclen <= 288 || !crypto_simd_usable())
+-		return crypto_poly1305_update(desc, src, srclen);
+-
+-	kernel_fpu_begin();
+-
+ 	if (unlikely(dctx->buflen)) {
+ 		bytes = min(srclen, POLY1305_BLOCK_SIZE - dctx->buflen);
+ 		memcpy(dctx->buf + dctx->buflen, src, bytes);
+@@ -105,25 +117,57 @@ static int poly1305_simd_update(struct s
+ 		dctx->buflen += bytes;
+ 
+ 		if (dctx->buflen == POLY1305_BLOCK_SIZE) {
+-			poly1305_simd_blocks(dctx, dctx->buf,
+-					     POLY1305_BLOCK_SIZE);
++			if (likely(crypto_simd_usable())) {
++				kernel_fpu_begin();
++				poly1305_simd_blocks(dctx, dctx->buf,
++						     POLY1305_BLOCK_SIZE);
++				kernel_fpu_end();
++			} else {
++				poly1305_scalar_blocks(dctx, dctx->buf,
++						       POLY1305_BLOCK_SIZE);
++			}
+ 			dctx->buflen = 0;
+ 		}
+ 	}
+ 
+ 	if (likely(srclen >= POLY1305_BLOCK_SIZE)) {
+-		bytes = poly1305_simd_blocks(dctx, src, srclen);
++		if (likely(crypto_simd_usable())) {
++			kernel_fpu_begin();
++			bytes = poly1305_simd_blocks(dctx, src, srclen);
++			kernel_fpu_end();
++		} else {
++			bytes = poly1305_scalar_blocks(dctx, src, srclen);
++		}
+ 		src += srclen - bytes;
+ 		srclen = bytes;
+ 	}
+ 
+-	kernel_fpu_end();
+-
+ 	if (unlikely(srclen)) {
+ 		dctx->buflen = srclen;
+ 		memcpy(dctx->buf, src, srclen);
+ 	}
++}
++
++static int crypto_poly1305_init(struct shash_desc *desc)
++{
++	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
++
++	poly1305_core_init(&dctx->h);
++	dctx->buflen = 0;
++	dctx->rset = 0;
++	dctx->sset = false;
++
++	return 0;
++}
++
++static int crypto_poly1305_final(struct shash_desc *desc, u8 *dst)
++{
++	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
++
++	if (unlikely(!dctx->sset))
++		return -ENOKEY;
+ 
++	poly1305_final_generic(dctx, dst);
+ 	return 0;
+ }
+ 
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -697,7 +697,7 @@ config CRYPTO_POLY1305
+ config CRYPTO_POLY1305_X86_64
+ 	tristate "Poly1305 authenticator algorithm (x86_64/SSE2/AVX2)"
+ 	depends on X86 && 64BIT
+-	select CRYPTO_POLY1305
++	select CRYPTO_LIB_POLY1305_GENERIC
+ 	help
+ 	  Poly1305 authenticator algorithm, RFC7539.
+ 
+--- a/crypto/poly1305_generic.c
++++ b/crypto/poly1305_generic.c
+@@ -19,7 +19,7 @@
+ #include <linux/module.h>
+ #include <asm/unaligned.h>
+ 
+-int crypto_poly1305_init(struct shash_desc *desc)
++static int crypto_poly1305_init(struct shash_desc *desc)
+ {
+ 	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
+ 
+@@ -30,7 +30,6 @@ int crypto_poly1305_init(struct shash_de
+ 
+ 	return 0;
+ }
+-EXPORT_SYMBOL_GPL(crypto_poly1305_init);
+ 
+ static void poly1305_blocks(struct poly1305_desc_ctx *dctx, const u8 *src,
+ 			    unsigned int srclen)
+@@ -47,8 +46,8 @@ static void poly1305_blocks(struct poly1
+ 			     srclen / POLY1305_BLOCK_SIZE, 1);
+ }
+ 
+-int crypto_poly1305_update(struct shash_desc *desc,
+-			   const u8 *src, unsigned int srclen)
++static int crypto_poly1305_update(struct shash_desc *desc,
++				  const u8 *src, unsigned int srclen)
+ {
+ 	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
+ 	unsigned int bytes;
+@@ -80,9 +79,8 @@ int crypto_poly1305_update(struct shash_
+ 
+ 	return 0;
+ }
+-EXPORT_SYMBOL_GPL(crypto_poly1305_update);
+ 
+-int crypto_poly1305_final(struct shash_desc *desc, u8 *dst)
++static int crypto_poly1305_final(struct shash_desc *desc, u8 *dst)
+ {
+ 	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
+ 
+@@ -92,7 +90,6 @@ int crypto_poly1305_final(struct shash_d
+ 	poly1305_final_generic(dctx, dst);
+ 	return 0;
+ }
+-EXPORT_SYMBOL_GPL(crypto_poly1305_final);
+ 
+ static struct shash_alg poly1305_alg = {
+ 	.digestsize	= POLY1305_DIGEST_SIZE,
+--- a/include/crypto/internal/poly1305.h
++++ b/include/crypto/internal/poly1305.h
+@@ -10,8 +10,6 @@
+ #include <linux/types.h>
+ #include <crypto/poly1305.h>
+ 
+-struct shash_desc;
+-
+ /*
+  * Poly1305 core functions.  These implement the ε-almost-∆-universal hash
+  * function underlying the Poly1305 MAC, i.e. they don't add an encrypted nonce
+@@ -28,13 +26,6 @@ void poly1305_core_blocks(struct poly130
+ 			  unsigned int nblocks, u32 hibit);
+ void poly1305_core_emit(const struct poly1305_state *state, void *dst);
+ 
+-/* Crypto API helper functions for the Poly1305 MAC */
+-int crypto_poly1305_init(struct shash_desc *desc);
+-
+-int crypto_poly1305_update(struct shash_desc *desc,
+-			   const u8 *src, unsigned int srclen);
+-int crypto_poly1305_final(struct shash_desc *desc, u8 *dst);
+-
+ /*
+  * Poly1305 requires a unique key for each tag, which implies that we can't set
+  * it on the tfm that gets accessed by multiple users simultaneously. Instead we
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0017-crypto-x86-poly1305-expose-existing-driver-as-poly13.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0017-crypto-x86-poly1305-expose-existing-driver-as-poly13.patch
new file mode 100644
index 0000000..6514987
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0017-crypto-x86-poly1305-expose-existing-driver-as-poly13.patch
@@ -0,0 +1,163 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:23 +0100
+Subject: [PATCH] crypto: x86/poly1305 - expose existing driver as poly1305
+ library
+
+commit f0e89bcfbb894e5844cd1bbf6b3cf7c63cb0f5ac upstream.
+
+Implement the arch init/update/final Poly1305 library routines in the
+accelerated SIMD driver for x86 so they are accessible to users of
+the Poly1305 library interface as well.
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/poly1305_glue.c | 57 ++++++++++++++++++++++++---------
+ crypto/Kconfig                  |  1 +
+ lib/crypto/Kconfig              |  1 +
+ 3 files changed, 43 insertions(+), 16 deletions(-)
+
+--- a/arch/x86/crypto/poly1305_glue.c
++++ b/arch/x86/crypto/poly1305_glue.c
+@@ -10,6 +10,7 @@
+ #include <crypto/internal/poly1305.h>
+ #include <crypto/internal/simd.h>
+ #include <linux/crypto.h>
++#include <linux/jump_label.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <asm/simd.h>
+@@ -21,7 +22,8 @@ asmlinkage void poly1305_2block_sse2(u32
+ asmlinkage void poly1305_4block_avx2(u32 *h, const u8 *src, const u32 *r,
+ 				     unsigned int blocks, const u32 *u);
+ 
+-static bool poly1305_use_avx2 __ro_after_init;
++static __ro_after_init DEFINE_STATIC_KEY_FALSE(poly1305_use_simd);
++static __ro_after_init DEFINE_STATIC_KEY_FALSE(poly1305_use_avx2);
+ 
+ static void poly1305_simd_mult(u32 *a, const u32 *b)
+ {
+@@ -64,7 +66,7 @@ static unsigned int poly1305_simd_blocks
+ 	}
+ 
+ 	if (IS_ENABLED(CONFIG_AS_AVX2) &&
+-	    poly1305_use_avx2 &&
++	    static_branch_likely(&poly1305_use_avx2) &&
+ 	    srclen >= POLY1305_BLOCK_SIZE * 4) {
+ 		if (unlikely(dctx->rset < 4)) {
+ 			if (dctx->rset < 2) {
+@@ -103,10 +105,15 @@ static unsigned int poly1305_simd_blocks
+ 	return srclen;
+ }
+ 
+-static int poly1305_simd_update(struct shash_desc *desc,
+-				const u8 *src, unsigned int srclen)
++void poly1305_init_arch(struct poly1305_desc_ctx *desc, const u8 *key)
++{
++	poly1305_init_generic(desc, key);
++}
++EXPORT_SYMBOL(poly1305_init_arch);
++
++void poly1305_update_arch(struct poly1305_desc_ctx *dctx, const u8 *src,
++			  unsigned int srclen)
+ {
+-	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
+ 	unsigned int bytes;
+ 
+ 	if (unlikely(dctx->buflen)) {
+@@ -117,7 +124,8 @@ static int poly1305_simd_update(struct s
+ 		dctx->buflen += bytes;
+ 
+ 		if (dctx->buflen == POLY1305_BLOCK_SIZE) {
+-			if (likely(crypto_simd_usable())) {
++			if (static_branch_likely(&poly1305_use_simd) &&
++			    likely(crypto_simd_usable())) {
+ 				kernel_fpu_begin();
+ 				poly1305_simd_blocks(dctx, dctx->buf,
+ 						     POLY1305_BLOCK_SIZE);
+@@ -131,7 +139,8 @@ static int poly1305_simd_update(struct s
+ 	}
+ 
+ 	if (likely(srclen >= POLY1305_BLOCK_SIZE)) {
+-		if (likely(crypto_simd_usable())) {
++		if (static_branch_likely(&poly1305_use_simd) &&
++		    likely(crypto_simd_usable())) {
+ 			kernel_fpu_begin();
+ 			bytes = poly1305_simd_blocks(dctx, src, srclen);
+ 			kernel_fpu_end();
+@@ -147,6 +156,13 @@ static int poly1305_simd_update(struct s
+ 		memcpy(dctx->buf, src, srclen);
+ 	}
+ }
++EXPORT_SYMBOL(poly1305_update_arch);
++
++void poly1305_final_arch(struct poly1305_desc_ctx *desc, u8 *digest)
++{
++	poly1305_final_generic(desc, digest);
++}
++EXPORT_SYMBOL(poly1305_final_arch);
+ 
+ static int crypto_poly1305_init(struct shash_desc *desc)
+ {
+@@ -171,6 +187,15 @@ static int crypto_poly1305_final(struct
+ 	return 0;
+ }
+ 
++static int poly1305_simd_update(struct shash_desc *desc,
++				const u8 *src, unsigned int srclen)
++{
++	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
++
++	poly1305_update_arch(dctx, src, srclen);
++	return 0;
++}
++
+ static struct shash_alg alg = {
+ 	.digestsize	= POLY1305_DIGEST_SIZE,
+ 	.init		= crypto_poly1305_init,
+@@ -189,15 +214,15 @@ static struct shash_alg alg = {
+ static int __init poly1305_simd_mod_init(void)
+ {
+ 	if (!boot_cpu_has(X86_FEATURE_XMM2))
+-		return -ENODEV;
++		return 0;
+ 
+-	poly1305_use_avx2 = IS_ENABLED(CONFIG_AS_AVX2) &&
+-			    boot_cpu_has(X86_FEATURE_AVX) &&
+-			    boot_cpu_has(X86_FEATURE_AVX2) &&
+-			    cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL);
+-	alg.descsize = sizeof(struct poly1305_desc_ctx) + 5 * sizeof(u32);
+-	if (poly1305_use_avx2)
+-		alg.descsize += 10 * sizeof(u32);
++	static_branch_enable(&poly1305_use_simd);
++
++	if (IS_ENABLED(CONFIG_AS_AVX2) &&
++	    boot_cpu_has(X86_FEATURE_AVX) &&
++	    boot_cpu_has(X86_FEATURE_AVX2) &&
++	    cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL))
++		static_branch_enable(&poly1305_use_avx2);
+ 
+ 	return crypto_register_shash(&alg);
+ }
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -698,6 +698,7 @@ config CRYPTO_POLY1305_X86_64
+ 	tristate "Poly1305 authenticator algorithm (x86_64/SSE2/AVX2)"
+ 	depends on X86 && 64BIT
+ 	select CRYPTO_LIB_POLY1305_GENERIC
++	select CRYPTO_ARCH_HAVE_LIB_POLY1305
+ 	help
+ 	  Poly1305 authenticator algorithm, RFC7539.
+ 
+--- a/lib/crypto/Kconfig
++++ b/lib/crypto/Kconfig
+@@ -39,6 +39,7 @@ config CRYPTO_LIB_DES
+ 
+ config CRYPTO_LIB_POLY1305_RSIZE
+ 	int
++	default 4 if X86_64
+ 	default 1
+ 
+ config CRYPTO_ARCH_HAVE_LIB_POLY1305
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0018-crypto-arm64-poly1305-incorporate-OpenSSL-CRYPTOGAMS.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0018-crypto-arm64-poly1305-incorporate-OpenSSL-CRYPTOGAMS.patch
new file mode 100644
index 0000000..464c656
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0018-crypto-arm64-poly1305-incorporate-OpenSSL-CRYPTOGAMS.patch
@@ -0,0 +1,2083 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:24 +0100
+Subject: [PATCH] crypto: arm64/poly1305 - incorporate OpenSSL/CRYPTOGAMS NEON
+ implementation
+
+commit f569ca16475155013525686d0f73bc379c67e635 upstream.
+
+This is a straight import of the OpenSSL/CRYPTOGAMS Poly1305 implementation
+for NEON authored by Andy Polyakov, and contributed by him to the OpenSSL
+project. The file 'poly1305-armv8.pl' is taken straight from this upstream
+GitHub repository [0] at commit ec55a08dc0244ce570c4fc7cade330c60798952f,
+and already contains all the changes required to build it as part of a
+Linux kernel module.
+
+[0] https://github.com/dot-asm/cryptogams
+
+Co-developed-by: Andy Polyakov <appro@cryptogams.org>
+Signed-off-by: Andy Polyakov <appro@cryptogams.org>
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm64/crypto/Kconfig                 |   6 +
+ arch/arm64/crypto/Makefile                |  10 +-
+ arch/arm64/crypto/poly1305-armv8.pl       | 913 ++++++++++++++++++++++
+ arch/arm64/crypto/poly1305-core.S_shipped | 835 ++++++++++++++++++++
+ arch/arm64/crypto/poly1305-glue.c         | 237 ++++++
+ lib/crypto/Kconfig                        |   1 +
+ 6 files changed, 2001 insertions(+), 1 deletion(-)
+ create mode 100644 arch/arm64/crypto/poly1305-armv8.pl
+ create mode 100644 arch/arm64/crypto/poly1305-core.S_shipped
+ create mode 100644 arch/arm64/crypto/poly1305-glue.c
+
+--- a/arch/arm64/crypto/Kconfig
++++ b/arch/arm64/crypto/Kconfig
+@@ -106,6 +106,12 @@ config CRYPTO_CHACHA20_NEON
+ 	select CRYPTO_LIB_CHACHA_GENERIC
+ 	select CRYPTO_ARCH_HAVE_LIB_CHACHA
+ 
++config CRYPTO_POLY1305_NEON
++	tristate "Poly1305 hash function using scalar or NEON instructions"
++	depends on KERNEL_MODE_NEON
++	select CRYPTO_HASH
++	select CRYPTO_ARCH_HAVE_LIB_POLY1305
++
+ config CRYPTO_NHPOLY1305_NEON
+ 	tristate "NHPoly1305 hash function using NEON instructions (for Adiantum)"
+ 	depends on KERNEL_MODE_NEON
+--- a/arch/arm64/crypto/Makefile
++++ b/arch/arm64/crypto/Makefile
+@@ -50,6 +50,10 @@ sha512-arm64-y := sha512-glue.o sha512-c
+ obj-$(CONFIG_CRYPTO_CHACHA20_NEON) += chacha-neon.o
+ chacha-neon-y := chacha-neon-core.o chacha-neon-glue.o
+ 
++obj-$(CONFIG_CRYPTO_POLY1305_NEON) += poly1305-neon.o
++poly1305-neon-y := poly1305-core.o poly1305-glue.o
++AFLAGS_poly1305-core.o += -Dpoly1305_init=poly1305_init_arm64
++
+ obj-$(CONFIG_CRYPTO_NHPOLY1305_NEON) += nhpoly1305-neon.o
+ nhpoly1305-neon-y := nh-neon-core.o nhpoly1305-neon-glue.o
+ 
+@@ -68,11 +72,15 @@ ifdef REGENERATE_ARM64_CRYPTO
+ quiet_cmd_perlasm = PERLASM $@
+       cmd_perlasm = $(PERL) $(<) void $(@)
+ 
++$(src)/poly1305-core.S_shipped: $(src)/poly1305-armv8.pl
++	$(call cmd,perlasm)
++
+ $(src)/sha256-core.S_shipped: $(src)/sha512-armv8.pl
+ 	$(call cmd,perlasm)
+ 
+ $(src)/sha512-core.S_shipped: $(src)/sha512-armv8.pl
+ 	$(call cmd,perlasm)
++
+ endif
+ 
+-clean-files += sha256-core.S sha512-core.S
++clean-files += poly1305-core.S sha256-core.S sha512-core.S
+--- /dev/null
++++ b/arch/arm64/crypto/poly1305-armv8.pl
+@@ -0,0 +1,913 @@
++#!/usr/bin/env perl
++# SPDX-License-Identifier: GPL-1.0+ OR BSD-3-Clause
++#
++# ====================================================================
++# Written by Andy Polyakov, @dot-asm, initially for the OpenSSL
++# project.
++# ====================================================================
++#
++# This module implements Poly1305 hash for ARMv8.
++#
++# June 2015
++#
++# Numbers are cycles per processed byte with poly1305_blocks alone.
++#
++#		IALU/gcc-4.9	NEON
++#
++# Apple A7	1.86/+5%	0.72
++# Cortex-A53	2.69/+58%	1.47
++# Cortex-A57	2.70/+7%	1.14
++# Denver	1.64/+50%	1.18(*)
++# X-Gene	2.13/+68%	2.27
++# Mongoose	1.77/+75%	1.12
++# Kryo		2.70/+55%	1.13
++# ThunderX2	1.17/+95%	1.36
++#
++# (*)	estimate based on resources availability is less than 1.0,
++#	i.e. measured result is worse than expected, presumably binary
++#	translator is not almighty;
++
++$flavour=shift;
++$output=shift;
++
++if ($flavour && $flavour ne "void") {
++    $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++    ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++    ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++    die "can't locate arm-xlate.pl";
++
++    open STDOUT,"| \"$^X\" $xlate $flavour $output";
++} else {
++    open STDOUT,">$output";
++}
++
++my ($ctx,$inp,$len,$padbit) = map("x$_",(0..3));
++my ($mac,$nonce)=($inp,$len);
++
++my ($h0,$h1,$h2,$r0,$r1,$s1,$t0,$t1,$d0,$d1,$d2) = map("x$_",(4..14));
++
++$code.=<<___;
++#ifndef __KERNEL__
++# include "arm_arch.h"
++.extern	OPENSSL_armcap_P
++#endif
++
++.text
++
++// forward "declarations" are required for Apple
++.globl	poly1305_blocks
++.globl	poly1305_emit
++
++.globl	poly1305_init
++.type	poly1305_init,%function
++.align	5
++poly1305_init:
++	cmp	$inp,xzr
++	stp	xzr,xzr,[$ctx]		// zero hash value
++	stp	xzr,xzr,[$ctx,#16]	// [along with is_base2_26]
++
++	csel	x0,xzr,x0,eq
++	b.eq	.Lno_key
++
++#ifndef	__KERNEL__
++	adrp	x17,OPENSSL_armcap_P
++	ldr	w17,[x17,#:lo12:OPENSSL_armcap_P]
++#endif
++
++	ldp	$r0,$r1,[$inp]		// load key
++	mov	$s1,#0xfffffffc0fffffff
++	movk	$s1,#0x0fff,lsl#48
++#ifdef	__AARCH64EB__
++	rev	$r0,$r0			// flip bytes
++	rev	$r1,$r1
++#endif
++	and	$r0,$r0,$s1		// &=0ffffffc0fffffff
++	and	$s1,$s1,#-4
++	and	$r1,$r1,$s1		// &=0ffffffc0ffffffc
++	mov	w#$s1,#-1
++	stp	$r0,$r1,[$ctx,#32]	// save key value
++	str	w#$s1,[$ctx,#48]	// impossible key power value
++
++#ifndef	__KERNEL__
++	tst	w17,#ARMV7_NEON
++
++	adr	$d0,.Lpoly1305_blocks
++	adr	$r0,.Lpoly1305_blocks_neon
++	adr	$d1,.Lpoly1305_emit
++
++	csel	$d0,$d0,$r0,eq
++
++# ifdef	__ILP32__
++	stp	w#$d0,w#$d1,[$len]
++# else
++	stp	$d0,$d1,[$len]
++# endif
++#endif
++	mov	x0,#1
++.Lno_key:
++	ret
++.size	poly1305_init,.-poly1305_init
++
++.type	poly1305_blocks,%function
++.align	5
++poly1305_blocks:
++.Lpoly1305_blocks:
++	ands	$len,$len,#-16
++	b.eq	.Lno_data
++
++	ldp	$h0,$h1,[$ctx]		// load hash value
++	ldp	$h2,x17,[$ctx,#16]	// [along with is_base2_26]
++	ldp	$r0,$r1,[$ctx,#32]	// load key value
++
++#ifdef	__AARCH64EB__
++	lsr	$d0,$h0,#32
++	mov	w#$d1,w#$h0
++	lsr	$d2,$h1,#32
++	mov	w15,w#$h1
++	lsr	x16,$h2,#32
++#else
++	mov	w#$d0,w#$h0
++	lsr	$d1,$h0,#32
++	mov	w#$d2,w#$h1
++	lsr	x15,$h1,#32
++	mov	w16,w#$h2
++#endif
++
++	add	$d0,$d0,$d1,lsl#26	// base 2^26 -> base 2^64
++	lsr	$d1,$d2,#12
++	adds	$d0,$d0,$d2,lsl#52
++	add	$d1,$d1,x15,lsl#14
++	adc	$d1,$d1,xzr
++	lsr	$d2,x16,#24
++	adds	$d1,$d1,x16,lsl#40
++	adc	$d2,$d2,xzr
++
++	cmp	x17,#0			// is_base2_26?
++	add	$s1,$r1,$r1,lsr#2	// s1 = r1 + (r1 >> 2)
++	csel	$h0,$h0,$d0,eq		// choose between radixes
++	csel	$h1,$h1,$d1,eq
++	csel	$h2,$h2,$d2,eq
++
++.Loop:
++	ldp	$t0,$t1,[$inp],#16	// load input
++	sub	$len,$len,#16
++#ifdef	__AARCH64EB__
++	rev	$t0,$t0
++	rev	$t1,$t1
++#endif
++	adds	$h0,$h0,$t0		// accumulate input
++	adcs	$h1,$h1,$t1
++
++	mul	$d0,$h0,$r0		// h0*r0
++	adc	$h2,$h2,$padbit
++	umulh	$d1,$h0,$r0
++
++	mul	$t0,$h1,$s1		// h1*5*r1
++	umulh	$t1,$h1,$s1
++
++	adds	$d0,$d0,$t0
++	mul	$t0,$h0,$r1		// h0*r1
++	adc	$d1,$d1,$t1
++	umulh	$d2,$h0,$r1
++
++	adds	$d1,$d1,$t0
++	mul	$t0,$h1,$r0		// h1*r0
++	adc	$d2,$d2,xzr
++	umulh	$t1,$h1,$r0
++
++	adds	$d1,$d1,$t0
++	mul	$t0,$h2,$s1		// h2*5*r1
++	adc	$d2,$d2,$t1
++	mul	$t1,$h2,$r0		// h2*r0
++
++	adds	$d1,$d1,$t0
++	adc	$d2,$d2,$t1
++
++	and	$t0,$d2,#-4		// final reduction
++	and	$h2,$d2,#3
++	add	$t0,$t0,$d2,lsr#2
++	adds	$h0,$d0,$t0
++	adcs	$h1,$d1,xzr
++	adc	$h2,$h2,xzr
++
++	cbnz	$len,.Loop
++
++	stp	$h0,$h1,[$ctx]		// store hash value
++	stp	$h2,xzr,[$ctx,#16]	// [and clear is_base2_26]
++
++.Lno_data:
++	ret
++.size	poly1305_blocks,.-poly1305_blocks
++
++.type	poly1305_emit,%function
++.align	5
++poly1305_emit:
++.Lpoly1305_emit:
++	ldp	$h0,$h1,[$ctx]		// load hash base 2^64
++	ldp	$h2,$r0,[$ctx,#16]	// [along with is_base2_26]
++	ldp	$t0,$t1,[$nonce]	// load nonce
++
++#ifdef	__AARCH64EB__
++	lsr	$d0,$h0,#32
++	mov	w#$d1,w#$h0
++	lsr	$d2,$h1,#32
++	mov	w15,w#$h1
++	lsr	x16,$h2,#32
++#else
++	mov	w#$d0,w#$h0
++	lsr	$d1,$h0,#32
++	mov	w#$d2,w#$h1
++	lsr	x15,$h1,#32
++	mov	w16,w#$h2
++#endif
++
++	add	$d0,$d0,$d1,lsl#26	// base 2^26 -> base 2^64
++	lsr	$d1,$d2,#12
++	adds	$d0,$d0,$d2,lsl#52
++	add	$d1,$d1,x15,lsl#14
++	adc	$d1,$d1,xzr
++	lsr	$d2,x16,#24
++	adds	$d1,$d1,x16,lsl#40
++	adc	$d2,$d2,xzr
++
++	cmp	$r0,#0			// is_base2_26?
++	csel	$h0,$h0,$d0,eq		// choose between radixes
++	csel	$h1,$h1,$d1,eq
++	csel	$h2,$h2,$d2,eq
++
++	adds	$d0,$h0,#5		// compare to modulus
++	adcs	$d1,$h1,xzr
++	adc	$d2,$h2,xzr
++
++	tst	$d2,#-4			// see if it's carried/borrowed
++
++	csel	$h0,$h0,$d0,eq
++	csel	$h1,$h1,$d1,eq
++
++#ifdef	__AARCH64EB__
++	ror	$t0,$t0,#32		// flip nonce words
++	ror	$t1,$t1,#32
++#endif
++	adds	$h0,$h0,$t0		// accumulate nonce
++	adc	$h1,$h1,$t1
++#ifdef	__AARCH64EB__
++	rev	$h0,$h0			// flip output bytes
++	rev	$h1,$h1
++#endif
++	stp	$h0,$h1,[$mac]		// write result
++
++	ret
++.size	poly1305_emit,.-poly1305_emit
++___
++my ($R0,$R1,$S1,$R2,$S2,$R3,$S3,$R4,$S4) = map("v$_.4s",(0..8));
++my ($IN01_0,$IN01_1,$IN01_2,$IN01_3,$IN01_4) = map("v$_.2s",(9..13));
++my ($IN23_0,$IN23_1,$IN23_2,$IN23_3,$IN23_4) = map("v$_.2s",(14..18));
++my ($ACC0,$ACC1,$ACC2,$ACC3,$ACC4) = map("v$_.2d",(19..23));
++my ($H0,$H1,$H2,$H3,$H4) = map("v$_.2s",(24..28));
++my ($T0,$T1,$MASK) = map("v$_",(29..31));
++
++my ($in2,$zeros)=("x16","x17");
++my $is_base2_26 = $zeros;		# borrow
++
++$code.=<<___;
++.type	poly1305_mult,%function
++.align	5
++poly1305_mult:
++	mul	$d0,$h0,$r0		// h0*r0
++	umulh	$d1,$h0,$r0
++
++	mul	$t0,$h1,$s1		// h1*5*r1
++	umulh	$t1,$h1,$s1
++
++	adds	$d0,$d0,$t0
++	mul	$t0,$h0,$r1		// h0*r1
++	adc	$d1,$d1,$t1
++	umulh	$d2,$h0,$r1
++
++	adds	$d1,$d1,$t0
++	mul	$t0,$h1,$r0		// h1*r0
++	adc	$d2,$d2,xzr
++	umulh	$t1,$h1,$r0
++
++	adds	$d1,$d1,$t0
++	mul	$t0,$h2,$s1		// h2*5*r1
++	adc	$d2,$d2,$t1
++	mul	$t1,$h2,$r0		// h2*r0
++
++	adds	$d1,$d1,$t0
++	adc	$d2,$d2,$t1
++
++	and	$t0,$d2,#-4		// final reduction
++	and	$h2,$d2,#3
++	add	$t0,$t0,$d2,lsr#2
++	adds	$h0,$d0,$t0
++	adcs	$h1,$d1,xzr
++	adc	$h2,$h2,xzr
++
++	ret
++.size	poly1305_mult,.-poly1305_mult
++
++.type	poly1305_splat,%function
++.align	4
++poly1305_splat:
++	and	x12,$h0,#0x03ffffff	// base 2^64 -> base 2^26
++	ubfx	x13,$h0,#26,#26
++	extr	x14,$h1,$h0,#52
++	and	x14,x14,#0x03ffffff
++	ubfx	x15,$h1,#14,#26
++	extr	x16,$h2,$h1,#40
++
++	str	w12,[$ctx,#16*0]	// r0
++	add	w12,w13,w13,lsl#2	// r1*5
++	str	w13,[$ctx,#16*1]	// r1
++	add	w13,w14,w14,lsl#2	// r2*5
++	str	w12,[$ctx,#16*2]	// s1
++	str	w14,[$ctx,#16*3]	// r2
++	add	w14,w15,w15,lsl#2	// r3*5
++	str	w13,[$ctx,#16*4]	// s2
++	str	w15,[$ctx,#16*5]	// r3
++	add	w15,w16,w16,lsl#2	// r4*5
++	str	w14,[$ctx,#16*6]	// s3
++	str	w16,[$ctx,#16*7]	// r4
++	str	w15,[$ctx,#16*8]	// s4
++
++	ret
++.size	poly1305_splat,.-poly1305_splat
++
++#ifdef	__KERNEL__
++.globl	poly1305_blocks_neon
++#endif
++.type	poly1305_blocks_neon,%function
++.align	5
++poly1305_blocks_neon:
++.Lpoly1305_blocks_neon:
++	ldr	$is_base2_26,[$ctx,#24]
++	cmp	$len,#128
++	b.lo	.Lpoly1305_blocks
++
++	.inst	0xd503233f		// paciasp
++	stp	x29,x30,[sp,#-80]!
++	add	x29,sp,#0
++
++	stp	d8,d9,[sp,#16]		// meet ABI requirements
++	stp	d10,d11,[sp,#32]
++	stp	d12,d13,[sp,#48]
++	stp	d14,d15,[sp,#64]
++
++	cbz	$is_base2_26,.Lbase2_64_neon
++
++	ldp	w10,w11,[$ctx]		// load hash value base 2^26
++	ldp	w12,w13,[$ctx,#8]
++	ldr	w14,[$ctx,#16]
++
++	tst	$len,#31
++	b.eq	.Leven_neon
++
++	ldp	$r0,$r1,[$ctx,#32]	// load key value
++
++	add	$h0,x10,x11,lsl#26	// base 2^26 -> base 2^64
++	lsr	$h1,x12,#12
++	adds	$h0,$h0,x12,lsl#52
++	add	$h1,$h1,x13,lsl#14
++	adc	$h1,$h1,xzr
++	lsr	$h2,x14,#24
++	adds	$h1,$h1,x14,lsl#40
++	adc	$d2,$h2,xzr		// can be partially reduced...
++
++	ldp	$d0,$d1,[$inp],#16	// load input
++	sub	$len,$len,#16
++	add	$s1,$r1,$r1,lsr#2	// s1 = r1 + (r1 >> 2)
++
++#ifdef	__AARCH64EB__
++	rev	$d0,$d0
++	rev	$d1,$d1
++#endif
++	adds	$h0,$h0,$d0		// accumulate input
++	adcs	$h1,$h1,$d1
++	adc	$h2,$h2,$padbit
++
++	bl	poly1305_mult
++
++	and	x10,$h0,#0x03ffffff	// base 2^64 -> base 2^26
++	ubfx	x11,$h0,#26,#26
++	extr	x12,$h1,$h0,#52
++	and	x12,x12,#0x03ffffff
++	ubfx	x13,$h1,#14,#26
++	extr	x14,$h2,$h1,#40
++
++	b	.Leven_neon
++
++.align	4
++.Lbase2_64_neon:
++	ldp	$r0,$r1,[$ctx,#32]	// load key value
++
++	ldp	$h0,$h1,[$ctx]		// load hash value base 2^64
++	ldr	$h2,[$ctx,#16]
++
++	tst	$len,#31
++	b.eq	.Linit_neon
++
++	ldp	$d0,$d1,[$inp],#16	// load input
++	sub	$len,$len,#16
++	add	$s1,$r1,$r1,lsr#2	// s1 = r1 + (r1 >> 2)
++#ifdef	__AARCH64EB__
++	rev	$d0,$d0
++	rev	$d1,$d1
++#endif
++	adds	$h0,$h0,$d0		// accumulate input
++	adcs	$h1,$h1,$d1
++	adc	$h2,$h2,$padbit
++
++	bl	poly1305_mult
++
++.Linit_neon:
++	ldr	w17,[$ctx,#48]		// first table element
++	and	x10,$h0,#0x03ffffff	// base 2^64 -> base 2^26
++	ubfx	x11,$h0,#26,#26
++	extr	x12,$h1,$h0,#52
++	and	x12,x12,#0x03ffffff
++	ubfx	x13,$h1,#14,#26
++	extr	x14,$h2,$h1,#40
++
++	cmp	w17,#-1			// is value impossible?
++	b.ne	.Leven_neon
++
++	fmov	${H0},x10
++	fmov	${H1},x11
++	fmov	${H2},x12
++	fmov	${H3},x13
++	fmov	${H4},x14
++
++	////////////////////////////////// initialize r^n table
++	mov	$h0,$r0			// r^1
++	add	$s1,$r1,$r1,lsr#2	// s1 = r1 + (r1 >> 2)
++	mov	$h1,$r1
++	mov	$h2,xzr
++	add	$ctx,$ctx,#48+12
++	bl	poly1305_splat
++
++	bl	poly1305_mult		// r^2
++	sub	$ctx,$ctx,#4
++	bl	poly1305_splat
++
++	bl	poly1305_mult		// r^3
++	sub	$ctx,$ctx,#4
++	bl	poly1305_splat
++
++	bl	poly1305_mult		// r^4
++	sub	$ctx,$ctx,#4
++	bl	poly1305_splat
++	sub	$ctx,$ctx,#48		// restore original $ctx
++	b	.Ldo_neon
++
++.align	4
++.Leven_neon:
++	fmov	${H0},x10
++	fmov	${H1},x11
++	fmov	${H2},x12
++	fmov	${H3},x13
++	fmov	${H4},x14
++
++.Ldo_neon:
++	ldp	x8,x12,[$inp,#32]	// inp[2:3]
++	subs	$len,$len,#64
++	ldp	x9,x13,[$inp,#48]
++	add	$in2,$inp,#96
++	adr	$zeros,.Lzeros
++
++	lsl	$padbit,$padbit,#24
++	add	x15,$ctx,#48
++
++#ifdef	__AARCH64EB__
++	rev	x8,x8
++	rev	x12,x12
++	rev	x9,x9
++	rev	x13,x13
++#endif
++	and	x4,x8,#0x03ffffff	// base 2^64 -> base 2^26
++	and	x5,x9,#0x03ffffff
++	ubfx	x6,x8,#26,#26
++	ubfx	x7,x9,#26,#26
++	add	x4,x4,x5,lsl#32		// bfi	x4,x5,#32,#32
++	extr	x8,x12,x8,#52
++	extr	x9,x13,x9,#52
++	add	x6,x6,x7,lsl#32		// bfi	x6,x7,#32,#32
++	fmov	$IN23_0,x4
++	and	x8,x8,#0x03ffffff
++	and	x9,x9,#0x03ffffff
++	ubfx	x10,x12,#14,#26
++	ubfx	x11,x13,#14,#26
++	add	x12,$padbit,x12,lsr#40
++	add	x13,$padbit,x13,lsr#40
++	add	x8,x8,x9,lsl#32		// bfi	x8,x9,#32,#32
++	fmov	$IN23_1,x6
++	add	x10,x10,x11,lsl#32	// bfi	x10,x11,#32,#32
++	add	x12,x12,x13,lsl#32	// bfi	x12,x13,#32,#32
++	fmov	$IN23_2,x8
++	fmov	$IN23_3,x10
++	fmov	$IN23_4,x12
++
++	ldp	x8,x12,[$inp],#16	// inp[0:1]
++	ldp	x9,x13,[$inp],#48
++
++	ld1	{$R0,$R1,$S1,$R2},[x15],#64
++	ld1	{$S2,$R3,$S3,$R4},[x15],#64
++	ld1	{$S4},[x15]
++
++#ifdef	__AARCH64EB__
++	rev	x8,x8
++	rev	x12,x12
++	rev	x9,x9
++	rev	x13,x13
++#endif
++	and	x4,x8,#0x03ffffff	// base 2^64 -> base 2^26
++	and	x5,x9,#0x03ffffff
++	ubfx	x6,x8,#26,#26
++	ubfx	x7,x9,#26,#26
++	add	x4,x4,x5,lsl#32		// bfi	x4,x5,#32,#32
++	extr	x8,x12,x8,#52
++	extr	x9,x13,x9,#52
++	add	x6,x6,x7,lsl#32		// bfi	x6,x7,#32,#32
++	fmov	$IN01_0,x4
++	and	x8,x8,#0x03ffffff
++	and	x9,x9,#0x03ffffff
++	ubfx	x10,x12,#14,#26
++	ubfx	x11,x13,#14,#26
++	add	x12,$padbit,x12,lsr#40
++	add	x13,$padbit,x13,lsr#40
++	add	x8,x8,x9,lsl#32		// bfi	x8,x9,#32,#32
++	fmov	$IN01_1,x6
++	add	x10,x10,x11,lsl#32	// bfi	x10,x11,#32,#32
++	add	x12,x12,x13,lsl#32	// bfi	x12,x13,#32,#32
++	movi	$MASK.2d,#-1
++	fmov	$IN01_2,x8
++	fmov	$IN01_3,x10
++	fmov	$IN01_4,x12
++	ushr	$MASK.2d,$MASK.2d,#38
++
++	b.ls	.Lskip_loop
++
++.align	4
++.Loop_neon:
++	////////////////////////////////////////////////////////////////
++	// ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2
++	// ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r
++	//   \___________________/
++	// ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2
++	// ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r
++	//   \___________________/ \____________________/
++	//
++	// Note that we start with inp[2:3]*r^2. This is because it
++	// doesn't depend on reduction in previous iteration.
++	////////////////////////////////////////////////////////////////
++	// d4 = h0*r4 + h1*r3   + h2*r2   + h3*r1   + h4*r0
++	// d3 = h0*r3 + h1*r2   + h2*r1   + h3*r0   + h4*5*r4
++	// d2 = h0*r2 + h1*r1   + h2*r0   + h3*5*r4 + h4*5*r3
++	// d1 = h0*r1 + h1*r0   + h2*5*r4 + h3*5*r3 + h4*5*r2
++	// d0 = h0*r0 + h1*5*r4 + h2*5*r3 + h3*5*r2 + h4*5*r1
++
++	subs	$len,$len,#64
++	umull	$ACC4,$IN23_0,${R4}[2]
++	csel	$in2,$zeros,$in2,lo
++	umull	$ACC3,$IN23_0,${R3}[2]
++	umull	$ACC2,$IN23_0,${R2}[2]
++	 ldp	x8,x12,[$in2],#16	// inp[2:3] (or zero)
++	umull	$ACC1,$IN23_0,${R1}[2]
++	 ldp	x9,x13,[$in2],#48
++	umull	$ACC0,$IN23_0,${R0}[2]
++#ifdef	__AARCH64EB__
++	 rev	x8,x8
++	 rev	x12,x12
++	 rev	x9,x9
++	 rev	x13,x13
++#endif
++
++	umlal	$ACC4,$IN23_1,${R3}[2]
++	 and	x4,x8,#0x03ffffff	// base 2^64 -> base 2^26
++	umlal	$ACC3,$IN23_1,${R2}[2]
++	 and	x5,x9,#0x03ffffff
++	umlal	$ACC2,$IN23_1,${R1}[2]
++	 ubfx	x6,x8,#26,#26
++	umlal	$ACC1,$IN23_1,${R0}[2]
++	 ubfx	x7,x9,#26,#26
++	umlal	$ACC0,$IN23_1,${S4}[2]
++	 add	x4,x4,x5,lsl#32		// bfi	x4,x5,#32,#32
++
++	umlal	$ACC4,$IN23_2,${R2}[2]
++	 extr	x8,x12,x8,#52
++	umlal	$ACC3,$IN23_2,${R1}[2]
++	 extr	x9,x13,x9,#52
++	umlal	$ACC2,$IN23_2,${R0}[2]
++	 add	x6,x6,x7,lsl#32		// bfi	x6,x7,#32,#32
++	umlal	$ACC1,$IN23_2,${S4}[2]
++	 fmov	$IN23_0,x4
++	umlal	$ACC0,$IN23_2,${S3}[2]
++	 and	x8,x8,#0x03ffffff
++
++	umlal	$ACC4,$IN23_3,${R1}[2]
++	 and	x9,x9,#0x03ffffff
++	umlal	$ACC3,$IN23_3,${R0}[2]
++	 ubfx	x10,x12,#14,#26
++	umlal	$ACC2,$IN23_3,${S4}[2]
++	 ubfx	x11,x13,#14,#26
++	umlal	$ACC1,$IN23_3,${S3}[2]
++	 add	x8,x8,x9,lsl#32		// bfi	x8,x9,#32,#32
++	umlal	$ACC0,$IN23_3,${S2}[2]
++	 fmov	$IN23_1,x6
++
++	add	$IN01_2,$IN01_2,$H2
++	 add	x12,$padbit,x12,lsr#40
++	umlal	$ACC4,$IN23_4,${R0}[2]
++	 add	x13,$padbit,x13,lsr#40
++	umlal	$ACC3,$IN23_4,${S4}[2]
++	 add	x10,x10,x11,lsl#32	// bfi	x10,x11,#32,#32
++	umlal	$ACC2,$IN23_4,${S3}[2]
++	 add	x12,x12,x13,lsl#32	// bfi	x12,x13,#32,#32
++	umlal	$ACC1,$IN23_4,${S2}[2]
++	 fmov	$IN23_2,x8
++	umlal	$ACC0,$IN23_4,${S1}[2]
++	 fmov	$IN23_3,x10
++
++	////////////////////////////////////////////////////////////////
++	// (hash+inp[0:1])*r^4 and accumulate
++
++	add	$IN01_0,$IN01_0,$H0
++	 fmov	$IN23_4,x12
++	umlal	$ACC3,$IN01_2,${R1}[0]
++	 ldp	x8,x12,[$inp],#16	// inp[0:1]
++	umlal	$ACC0,$IN01_2,${S3}[0]
++	 ldp	x9,x13,[$inp],#48
++	umlal	$ACC4,$IN01_2,${R2}[0]
++	umlal	$ACC1,$IN01_2,${S4}[0]
++	umlal	$ACC2,$IN01_2,${R0}[0]
++#ifdef	__AARCH64EB__
++	 rev	x8,x8
++	 rev	x12,x12
++	 rev	x9,x9
++	 rev	x13,x13
++#endif
++
++	add	$IN01_1,$IN01_1,$H1
++	umlal	$ACC3,$IN01_0,${R3}[0]
++	umlal	$ACC4,$IN01_0,${R4}[0]
++	 and	x4,x8,#0x03ffffff	// base 2^64 -> base 2^26
++	umlal	$ACC2,$IN01_0,${R2}[0]
++	 and	x5,x9,#0x03ffffff
++	umlal	$ACC0,$IN01_0,${R0}[0]
++	 ubfx	x6,x8,#26,#26
++	umlal	$ACC1,$IN01_0,${R1}[0]
++	 ubfx	x7,x9,#26,#26
++
++	add	$IN01_3,$IN01_3,$H3
++	 add	x4,x4,x5,lsl#32		// bfi	x4,x5,#32,#32
++	umlal	$ACC3,$IN01_1,${R2}[0]
++	 extr	x8,x12,x8,#52
++	umlal	$ACC4,$IN01_1,${R3}[0]
++	 extr	x9,x13,x9,#52
++	umlal	$ACC0,$IN01_1,${S4}[0]
++	 add	x6,x6,x7,lsl#32		// bfi	x6,x7,#32,#32
++	umlal	$ACC2,$IN01_1,${R1}[0]
++	 fmov	$IN01_0,x4
++	umlal	$ACC1,$IN01_1,${R0}[0]
++	 and	x8,x8,#0x03ffffff
++
++	add	$IN01_4,$IN01_4,$H4
++	 and	x9,x9,#0x03ffffff
++	umlal	$ACC3,$IN01_3,${R0}[0]
++	 ubfx	x10,x12,#14,#26
++	umlal	$ACC0,$IN01_3,${S2}[0]
++	 ubfx	x11,x13,#14,#26
++	umlal	$ACC4,$IN01_3,${R1}[0]
++	 add	x8,x8,x9,lsl#32		// bfi	x8,x9,#32,#32
++	umlal	$ACC1,$IN01_3,${S3}[0]
++	 fmov	$IN01_1,x6
++	umlal	$ACC2,$IN01_3,${S4}[0]
++	 add	x12,$padbit,x12,lsr#40
++
++	umlal	$ACC3,$IN01_4,${S4}[0]
++	 add	x13,$padbit,x13,lsr#40
++	umlal	$ACC0,$IN01_4,${S1}[0]
++	 add	x10,x10,x11,lsl#32	// bfi	x10,x11,#32,#32
++	umlal	$ACC4,$IN01_4,${R0}[0]
++	 add	x12,x12,x13,lsl#32	// bfi	x12,x13,#32,#32
++	umlal	$ACC1,$IN01_4,${S2}[0]
++	 fmov	$IN01_2,x8
++	umlal	$ACC2,$IN01_4,${S3}[0]
++	 fmov	$IN01_3,x10
++	 fmov	$IN01_4,x12
++
++	/////////////////////////////////////////////////////////////////
++	// lazy reduction as discussed in "NEON crypto" by D.J. Bernstein
++	// and P. Schwabe
++	//
++	// [see discussion in poly1305-armv4 module]
++
++	ushr	$T0.2d,$ACC3,#26
++	xtn	$H3,$ACC3
++	 ushr	$T1.2d,$ACC0,#26
++	 and	$ACC0,$ACC0,$MASK.2d
++	add	$ACC4,$ACC4,$T0.2d	// h3 -> h4
++	bic	$H3,#0xfc,lsl#24	// &=0x03ffffff
++	 add	$ACC1,$ACC1,$T1.2d	// h0 -> h1
++
++	ushr	$T0.2d,$ACC4,#26
++	xtn	$H4,$ACC4
++	 ushr	$T1.2d,$ACC1,#26
++	 xtn	$H1,$ACC1
++	bic	$H4,#0xfc,lsl#24
++	 add	$ACC2,$ACC2,$T1.2d	// h1 -> h2
++
++	add	$ACC0,$ACC0,$T0.2d
++	shl	$T0.2d,$T0.2d,#2
++	 shrn	$T1.2s,$ACC2,#26
++	 xtn	$H2,$ACC2
++	add	$ACC0,$ACC0,$T0.2d	// h4 -> h0
++	 bic	$H1,#0xfc,lsl#24
++	 add	$H3,$H3,$T1.2s		// h2 -> h3
++	 bic	$H2,#0xfc,lsl#24
++
++	shrn	$T0.2s,$ACC0,#26
++	xtn	$H0,$ACC0
++	 ushr	$T1.2s,$H3,#26
++	 bic	$H3,#0xfc,lsl#24
++	 bic	$H0,#0xfc,lsl#24
++	add	$H1,$H1,$T0.2s		// h0 -> h1
++	 add	$H4,$H4,$T1.2s		// h3 -> h4
++
++	b.hi	.Loop_neon
++
++.Lskip_loop:
++	dup	$IN23_2,${IN23_2}[0]
++	add	$IN01_2,$IN01_2,$H2
++
++	////////////////////////////////////////////////////////////////
++	// multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1
++
++	adds	$len,$len,#32
++	b.ne	.Long_tail
++
++	dup	$IN23_2,${IN01_2}[0]
++	add	$IN23_0,$IN01_0,$H0
++	add	$IN23_3,$IN01_3,$H3
++	add	$IN23_1,$IN01_1,$H1
++	add	$IN23_4,$IN01_4,$H4
++
++.Long_tail:
++	dup	$IN23_0,${IN23_0}[0]
++	umull2	$ACC0,$IN23_2,${S3}
++	umull2	$ACC3,$IN23_2,${R1}
++	umull2	$ACC4,$IN23_2,${R2}
++	umull2	$ACC2,$IN23_2,${R0}
++	umull2	$ACC1,$IN23_2,${S4}
++
++	dup	$IN23_1,${IN23_1}[0]
++	umlal2	$ACC0,$IN23_0,${R0}
++	umlal2	$ACC2,$IN23_0,${R2}
++	umlal2	$ACC3,$IN23_0,${R3}
++	umlal2	$ACC4,$IN23_0,${R4}
++	umlal2	$ACC1,$IN23_0,${R1}
++
++	dup	$IN23_3,${IN23_3}[0]
++	umlal2	$ACC0,$IN23_1,${S4}
++	umlal2	$ACC3,$IN23_1,${R2}
++	umlal2	$ACC2,$IN23_1,${R1}
++	umlal2	$ACC4,$IN23_1,${R3}
++	umlal2	$ACC1,$IN23_1,${R0}
++
++	dup	$IN23_4,${IN23_4}[0]
++	umlal2	$ACC3,$IN23_3,${R0}
++	umlal2	$ACC4,$IN23_3,${R1}
++	umlal2	$ACC0,$IN23_3,${S2}
++	umlal2	$ACC1,$IN23_3,${S3}
++	umlal2	$ACC2,$IN23_3,${S4}
++
++	umlal2	$ACC3,$IN23_4,${S4}
++	umlal2	$ACC0,$IN23_4,${S1}
++	umlal2	$ACC4,$IN23_4,${R0}
++	umlal2	$ACC1,$IN23_4,${S2}
++	umlal2	$ACC2,$IN23_4,${S3}
++
++	b.eq	.Lshort_tail
++
++	////////////////////////////////////////////////////////////////
++	// (hash+inp[0:1])*r^4:r^3 and accumulate
++
++	add	$IN01_0,$IN01_0,$H0
++	umlal	$ACC3,$IN01_2,${R1}
++	umlal	$ACC0,$IN01_2,${S3}
++	umlal	$ACC4,$IN01_2,${R2}
++	umlal	$ACC1,$IN01_2,${S4}
++	umlal	$ACC2,$IN01_2,${R0}
++
++	add	$IN01_1,$IN01_1,$H1
++	umlal	$ACC3,$IN01_0,${R3}
++	umlal	$ACC0,$IN01_0,${R0}
++	umlal	$ACC4,$IN01_0,${R4}
++	umlal	$ACC1,$IN01_0,${R1}
++	umlal	$ACC2,$IN01_0,${R2}
++
++	add	$IN01_3,$IN01_3,$H3
++	umlal	$ACC3,$IN01_1,${R2}
++	umlal	$ACC0,$IN01_1,${S4}
++	umlal	$ACC4,$IN01_1,${R3}
++	umlal	$ACC1,$IN01_1,${R0}
++	umlal	$ACC2,$IN01_1,${R1}
++
++	add	$IN01_4,$IN01_4,$H4
++	umlal	$ACC3,$IN01_3,${R0}
++	umlal	$ACC0,$IN01_3,${S2}
++	umlal	$ACC4,$IN01_3,${R1}
++	umlal	$ACC1,$IN01_3,${S3}
++	umlal	$ACC2,$IN01_3,${S4}
++
++	umlal	$ACC3,$IN01_4,${S4}
++	umlal	$ACC0,$IN01_4,${S1}
++	umlal	$ACC4,$IN01_4,${R0}
++	umlal	$ACC1,$IN01_4,${S2}
++	umlal	$ACC2,$IN01_4,${S3}
++
++.Lshort_tail:
++	////////////////////////////////////////////////////////////////
++	// horizontal add
++
++	addp	$ACC3,$ACC3,$ACC3
++	 ldp	d8,d9,[sp,#16]		// meet ABI requirements
++	addp	$ACC0,$ACC0,$ACC0
++	 ldp	d10,d11,[sp,#32]
++	addp	$ACC4,$ACC4,$ACC4
++	 ldp	d12,d13,[sp,#48]
++	addp	$ACC1,$ACC1,$ACC1
++	 ldp	d14,d15,[sp,#64]
++	addp	$ACC2,$ACC2,$ACC2
++	 ldr	x30,[sp,#8]
++	 .inst	0xd50323bf		// autiasp
++
++	////////////////////////////////////////////////////////////////
++	// lazy reduction, but without narrowing
++
++	ushr	$T0.2d,$ACC3,#26
++	and	$ACC3,$ACC3,$MASK.2d
++	 ushr	$T1.2d,$ACC0,#26
++	 and	$ACC0,$ACC0,$MASK.2d
++
++	add	$ACC4,$ACC4,$T0.2d	// h3 -> h4
++	 add	$ACC1,$ACC1,$T1.2d	// h0 -> h1
++
++	ushr	$T0.2d,$ACC4,#26
++	and	$ACC4,$ACC4,$MASK.2d
++	 ushr	$T1.2d,$ACC1,#26
++	 and	$ACC1,$ACC1,$MASK.2d
++	 add	$ACC2,$ACC2,$T1.2d	// h1 -> h2
++
++	add	$ACC0,$ACC0,$T0.2d
++	shl	$T0.2d,$T0.2d,#2
++	 ushr	$T1.2d,$ACC2,#26
++	 and	$ACC2,$ACC2,$MASK.2d
++	add	$ACC0,$ACC0,$T0.2d	// h4 -> h0
++	 add	$ACC3,$ACC3,$T1.2d	// h2 -> h3
++
++	ushr	$T0.2d,$ACC0,#26
++	and	$ACC0,$ACC0,$MASK.2d
++	 ushr	$T1.2d,$ACC3,#26
++	 and	$ACC3,$ACC3,$MASK.2d
++	add	$ACC1,$ACC1,$T0.2d	// h0 -> h1
++	 add	$ACC4,$ACC4,$T1.2d	// h3 -> h4
++
++	////////////////////////////////////////////////////////////////
++	// write the result, can be partially reduced
++
++	st4	{$ACC0,$ACC1,$ACC2,$ACC3}[0],[$ctx],#16
++	mov	x4,#1
++	st1	{$ACC4}[0],[$ctx]
++	str	x4,[$ctx,#8]		// set is_base2_26
++
++	ldr	x29,[sp],#80
++	ret
++.size	poly1305_blocks_neon,.-poly1305_blocks_neon
++
++.align	5
++.Lzeros:
++.long	0,0,0,0,0,0,0,0
++.asciz	"Poly1305 for ARMv8, CRYPTOGAMS by \@dot-asm"
++.align	2
++#if !defined(__KERNEL__) && !defined(_WIN64)
++.comm	OPENSSL_armcap_P,4,4
++.hidden	OPENSSL_armcap_P
++#endif
++___
++
++foreach (split("\n",$code)) {
++	s/\b(shrn\s+v[0-9]+)\.[24]d/$1.2s/			or
++	s/\b(fmov\s+)v([0-9]+)[^,]*,\s*x([0-9]+)/$1d$2,x$3/	or
++	(m/\bdup\b/ and (s/\.[24]s/.2d/g or 1))			or
++	(m/\b(eor|and)/ and (s/\.[248][sdh]/.16b/g or 1))	or
++	(m/\bum(ul|la)l\b/ and (s/\.4s/.2s/g or 1))		or
++	(m/\bum(ul|la)l2\b/ and (s/\.2s/.4s/g or 1))		or
++	(m/\bst[1-4]\s+{[^}]+}\[/ and (s/\.[24]d/.s/g or 1));
++
++	s/\.[124]([sd])\[/.$1\[/;
++	s/w#x([0-9]+)/w$1/g;
++
++	print $_,"\n";
++}
++close STDOUT;
+--- /dev/null
++++ b/arch/arm64/crypto/poly1305-core.S_shipped
+@@ -0,0 +1,835 @@
++#ifndef __KERNEL__
++# include "arm_arch.h"
++.extern	OPENSSL_armcap_P
++#endif
++
++.text
++
++// forward "declarations" are required for Apple
++.globl	poly1305_blocks
++.globl	poly1305_emit
++
++.globl	poly1305_init
++.type	poly1305_init,%function
++.align	5
++poly1305_init:
++	cmp	x1,xzr
++	stp	xzr,xzr,[x0]		// zero hash value
++	stp	xzr,xzr,[x0,#16]	// [along with is_base2_26]
++
++	csel	x0,xzr,x0,eq
++	b.eq	.Lno_key
++
++#ifndef	__KERNEL__
++	adrp	x17,OPENSSL_armcap_P
++	ldr	w17,[x17,#:lo12:OPENSSL_armcap_P]
++#endif
++
++	ldp	x7,x8,[x1]		// load key
++	mov	x9,#0xfffffffc0fffffff
++	movk	x9,#0x0fff,lsl#48
++#ifdef	__AARCH64EB__
++	rev	x7,x7			// flip bytes
++	rev	x8,x8
++#endif
++	and	x7,x7,x9		// &=0ffffffc0fffffff
++	and	x9,x9,#-4
++	and	x8,x8,x9		// &=0ffffffc0ffffffc
++	mov	w9,#-1
++	stp	x7,x8,[x0,#32]	// save key value
++	str	w9,[x0,#48]	// impossible key power value
++
++#ifndef	__KERNEL__
++	tst	w17,#ARMV7_NEON
++
++	adr	x12,.Lpoly1305_blocks
++	adr	x7,.Lpoly1305_blocks_neon
++	adr	x13,.Lpoly1305_emit
++
++	csel	x12,x12,x7,eq
++
++# ifdef	__ILP32__
++	stp	w12,w13,[x2]
++# else
++	stp	x12,x13,[x2]
++# endif
++#endif
++	mov	x0,#1
++.Lno_key:
++	ret
++.size	poly1305_init,.-poly1305_init
++
++.type	poly1305_blocks,%function
++.align	5
++poly1305_blocks:
++.Lpoly1305_blocks:
++	ands	x2,x2,#-16
++	b.eq	.Lno_data
++
++	ldp	x4,x5,[x0]		// load hash value
++	ldp	x6,x17,[x0,#16]	// [along with is_base2_26]
++	ldp	x7,x8,[x0,#32]	// load key value
++
++#ifdef	__AARCH64EB__
++	lsr	x12,x4,#32
++	mov	w13,w4
++	lsr	x14,x5,#32
++	mov	w15,w5
++	lsr	x16,x6,#32
++#else
++	mov	w12,w4
++	lsr	x13,x4,#32
++	mov	w14,w5
++	lsr	x15,x5,#32
++	mov	w16,w6
++#endif
++
++	add	x12,x12,x13,lsl#26	// base 2^26 -> base 2^64
++	lsr	x13,x14,#12
++	adds	x12,x12,x14,lsl#52
++	add	x13,x13,x15,lsl#14
++	adc	x13,x13,xzr
++	lsr	x14,x16,#24
++	adds	x13,x13,x16,lsl#40
++	adc	x14,x14,xzr
++
++	cmp	x17,#0			// is_base2_26?
++	add	x9,x8,x8,lsr#2	// s1 = r1 + (r1 >> 2)
++	csel	x4,x4,x12,eq		// choose between radixes
++	csel	x5,x5,x13,eq
++	csel	x6,x6,x14,eq
++
++.Loop:
++	ldp	x10,x11,[x1],#16	// load input
++	sub	x2,x2,#16
++#ifdef	__AARCH64EB__
++	rev	x10,x10
++	rev	x11,x11
++#endif
++	adds	x4,x4,x10		// accumulate input
++	adcs	x5,x5,x11
++
++	mul	x12,x4,x7		// h0*r0
++	adc	x6,x6,x3
++	umulh	x13,x4,x7
++
++	mul	x10,x5,x9		// h1*5*r1
++	umulh	x11,x5,x9
++
++	adds	x12,x12,x10
++	mul	x10,x4,x8		// h0*r1
++	adc	x13,x13,x11
++	umulh	x14,x4,x8
++
++	adds	x13,x13,x10
++	mul	x10,x5,x7		// h1*r0
++	adc	x14,x14,xzr
++	umulh	x11,x5,x7
++
++	adds	x13,x13,x10
++	mul	x10,x6,x9		// h2*5*r1
++	adc	x14,x14,x11
++	mul	x11,x6,x7		// h2*r0
++
++	adds	x13,x13,x10
++	adc	x14,x14,x11
++
++	and	x10,x14,#-4		// final reduction
++	and	x6,x14,#3
++	add	x10,x10,x14,lsr#2
++	adds	x4,x12,x10
++	adcs	x5,x13,xzr
++	adc	x6,x6,xzr
++
++	cbnz	x2,.Loop
++
++	stp	x4,x5,[x0]		// store hash value
++	stp	x6,xzr,[x0,#16]	// [and clear is_base2_26]
++
++.Lno_data:
++	ret
++.size	poly1305_blocks,.-poly1305_blocks
++
++.type	poly1305_emit,%function
++.align	5
++poly1305_emit:
++.Lpoly1305_emit:
++	ldp	x4,x5,[x0]		// load hash base 2^64
++	ldp	x6,x7,[x0,#16]	// [along with is_base2_26]
++	ldp	x10,x11,[x2]	// load nonce
++
++#ifdef	__AARCH64EB__
++	lsr	x12,x4,#32
++	mov	w13,w4
++	lsr	x14,x5,#32
++	mov	w15,w5
++	lsr	x16,x6,#32
++#else
++	mov	w12,w4
++	lsr	x13,x4,#32
++	mov	w14,w5
++	lsr	x15,x5,#32
++	mov	w16,w6
++#endif
++
++	add	x12,x12,x13,lsl#26	// base 2^26 -> base 2^64
++	lsr	x13,x14,#12
++	adds	x12,x12,x14,lsl#52
++	add	x13,x13,x15,lsl#14
++	adc	x13,x13,xzr
++	lsr	x14,x16,#24
++	adds	x13,x13,x16,lsl#40
++	adc	x14,x14,xzr
++
++	cmp	x7,#0			// is_base2_26?
++	csel	x4,x4,x12,eq		// choose between radixes
++	csel	x5,x5,x13,eq
++	csel	x6,x6,x14,eq
++
++	adds	x12,x4,#5		// compare to modulus
++	adcs	x13,x5,xzr
++	adc	x14,x6,xzr
++
++	tst	x14,#-4			// see if it's carried/borrowed
++
++	csel	x4,x4,x12,eq
++	csel	x5,x5,x13,eq
++
++#ifdef	__AARCH64EB__
++	ror	x10,x10,#32		// flip nonce words
++	ror	x11,x11,#32
++#endif
++	adds	x4,x4,x10		// accumulate nonce
++	adc	x5,x5,x11
++#ifdef	__AARCH64EB__
++	rev	x4,x4			// flip output bytes
++	rev	x5,x5
++#endif
++	stp	x4,x5,[x1]		// write result
++
++	ret
++.size	poly1305_emit,.-poly1305_emit
++.type	poly1305_mult,%function
++.align	5
++poly1305_mult:
++	mul	x12,x4,x7		// h0*r0
++	umulh	x13,x4,x7
++
++	mul	x10,x5,x9		// h1*5*r1
++	umulh	x11,x5,x9
++
++	adds	x12,x12,x10
++	mul	x10,x4,x8		// h0*r1
++	adc	x13,x13,x11
++	umulh	x14,x4,x8
++
++	adds	x13,x13,x10
++	mul	x10,x5,x7		// h1*r0
++	adc	x14,x14,xzr
++	umulh	x11,x5,x7
++
++	adds	x13,x13,x10
++	mul	x10,x6,x9		// h2*5*r1
++	adc	x14,x14,x11
++	mul	x11,x6,x7		// h2*r0
++
++	adds	x13,x13,x10
++	adc	x14,x14,x11
++
++	and	x10,x14,#-4		// final reduction
++	and	x6,x14,#3
++	add	x10,x10,x14,lsr#2
++	adds	x4,x12,x10
++	adcs	x5,x13,xzr
++	adc	x6,x6,xzr
++
++	ret
++.size	poly1305_mult,.-poly1305_mult
++
++.type	poly1305_splat,%function
++.align	4
++poly1305_splat:
++	and	x12,x4,#0x03ffffff	// base 2^64 -> base 2^26
++	ubfx	x13,x4,#26,#26
++	extr	x14,x5,x4,#52
++	and	x14,x14,#0x03ffffff
++	ubfx	x15,x5,#14,#26
++	extr	x16,x6,x5,#40
++
++	str	w12,[x0,#16*0]	// r0
++	add	w12,w13,w13,lsl#2	// r1*5
++	str	w13,[x0,#16*1]	// r1
++	add	w13,w14,w14,lsl#2	// r2*5
++	str	w12,[x0,#16*2]	// s1
++	str	w14,[x0,#16*3]	// r2
++	add	w14,w15,w15,lsl#2	// r3*5
++	str	w13,[x0,#16*4]	// s2
++	str	w15,[x0,#16*5]	// r3
++	add	w15,w16,w16,lsl#2	// r4*5
++	str	w14,[x0,#16*6]	// s3
++	str	w16,[x0,#16*7]	// r4
++	str	w15,[x0,#16*8]	// s4
++
++	ret
++.size	poly1305_splat,.-poly1305_splat
++
++#ifdef	__KERNEL__
++.globl	poly1305_blocks_neon
++#endif
++.type	poly1305_blocks_neon,%function
++.align	5
++poly1305_blocks_neon:
++.Lpoly1305_blocks_neon:
++	ldr	x17,[x0,#24]
++	cmp	x2,#128
++	b.lo	.Lpoly1305_blocks
++
++	.inst	0xd503233f		// paciasp
++	stp	x29,x30,[sp,#-80]!
++	add	x29,sp,#0
++
++	stp	d8,d9,[sp,#16]		// meet ABI requirements
++	stp	d10,d11,[sp,#32]
++	stp	d12,d13,[sp,#48]
++	stp	d14,d15,[sp,#64]
++
++	cbz	x17,.Lbase2_64_neon
++
++	ldp	w10,w11,[x0]		// load hash value base 2^26
++	ldp	w12,w13,[x0,#8]
++	ldr	w14,[x0,#16]
++
++	tst	x2,#31
++	b.eq	.Leven_neon
++
++	ldp	x7,x8,[x0,#32]	// load key value
++
++	add	x4,x10,x11,lsl#26	// base 2^26 -> base 2^64
++	lsr	x5,x12,#12
++	adds	x4,x4,x12,lsl#52
++	add	x5,x5,x13,lsl#14
++	adc	x5,x5,xzr
++	lsr	x6,x14,#24
++	adds	x5,x5,x14,lsl#40
++	adc	x14,x6,xzr		// can be partially reduced...
++
++	ldp	x12,x13,[x1],#16	// load input
++	sub	x2,x2,#16
++	add	x9,x8,x8,lsr#2	// s1 = r1 + (r1 >> 2)
++
++#ifdef	__AARCH64EB__
++	rev	x12,x12
++	rev	x13,x13
++#endif
++	adds	x4,x4,x12		// accumulate input
++	adcs	x5,x5,x13
++	adc	x6,x6,x3
++
++	bl	poly1305_mult
++
++	and	x10,x4,#0x03ffffff	// base 2^64 -> base 2^26
++	ubfx	x11,x4,#26,#26
++	extr	x12,x5,x4,#52
++	and	x12,x12,#0x03ffffff
++	ubfx	x13,x5,#14,#26
++	extr	x14,x6,x5,#40
++
++	b	.Leven_neon
++
++.align	4
++.Lbase2_64_neon:
++	ldp	x7,x8,[x0,#32]	// load key value
++
++	ldp	x4,x5,[x0]		// load hash value base 2^64
++	ldr	x6,[x0,#16]
++
++	tst	x2,#31
++	b.eq	.Linit_neon
++
++	ldp	x12,x13,[x1],#16	// load input
++	sub	x2,x2,#16
++	add	x9,x8,x8,lsr#2	// s1 = r1 + (r1 >> 2)
++#ifdef	__AARCH64EB__
++	rev	x12,x12
++	rev	x13,x13
++#endif
++	adds	x4,x4,x12		// accumulate input
++	adcs	x5,x5,x13
++	adc	x6,x6,x3
++
++	bl	poly1305_mult
++
++.Linit_neon:
++	ldr	w17,[x0,#48]		// first table element
++	and	x10,x4,#0x03ffffff	// base 2^64 -> base 2^26
++	ubfx	x11,x4,#26,#26
++	extr	x12,x5,x4,#52
++	and	x12,x12,#0x03ffffff
++	ubfx	x13,x5,#14,#26
++	extr	x14,x6,x5,#40
++
++	cmp	w17,#-1			// is value impossible?
++	b.ne	.Leven_neon
++
++	fmov	d24,x10
++	fmov	d25,x11
++	fmov	d26,x12
++	fmov	d27,x13
++	fmov	d28,x14
++
++	////////////////////////////////// initialize r^n table
++	mov	x4,x7			// r^1
++	add	x9,x8,x8,lsr#2	// s1 = r1 + (r1 >> 2)
++	mov	x5,x8
++	mov	x6,xzr
++	add	x0,x0,#48+12
++	bl	poly1305_splat
++
++	bl	poly1305_mult		// r^2
++	sub	x0,x0,#4
++	bl	poly1305_splat
++
++	bl	poly1305_mult		// r^3
++	sub	x0,x0,#4
++	bl	poly1305_splat
++
++	bl	poly1305_mult		// r^4
++	sub	x0,x0,#4
++	bl	poly1305_splat
++	sub	x0,x0,#48		// restore original x0
++	b	.Ldo_neon
++
++.align	4
++.Leven_neon:
++	fmov	d24,x10
++	fmov	d25,x11
++	fmov	d26,x12
++	fmov	d27,x13
++	fmov	d28,x14
++
++.Ldo_neon:
++	ldp	x8,x12,[x1,#32]	// inp[2:3]
++	subs	x2,x2,#64
++	ldp	x9,x13,[x1,#48]
++	add	x16,x1,#96
++	adr	x17,.Lzeros
++
++	lsl	x3,x3,#24
++	add	x15,x0,#48
++
++#ifdef	__AARCH64EB__
++	rev	x8,x8
++	rev	x12,x12
++	rev	x9,x9
++	rev	x13,x13
++#endif
++	and	x4,x8,#0x03ffffff	// base 2^64 -> base 2^26
++	and	x5,x9,#0x03ffffff
++	ubfx	x6,x8,#26,#26
++	ubfx	x7,x9,#26,#26
++	add	x4,x4,x5,lsl#32		// bfi	x4,x5,#32,#32
++	extr	x8,x12,x8,#52
++	extr	x9,x13,x9,#52
++	add	x6,x6,x7,lsl#32		// bfi	x6,x7,#32,#32
++	fmov	d14,x4
++	and	x8,x8,#0x03ffffff
++	and	x9,x9,#0x03ffffff
++	ubfx	x10,x12,#14,#26
++	ubfx	x11,x13,#14,#26
++	add	x12,x3,x12,lsr#40
++	add	x13,x3,x13,lsr#40
++	add	x8,x8,x9,lsl#32		// bfi	x8,x9,#32,#32
++	fmov	d15,x6
++	add	x10,x10,x11,lsl#32	// bfi	x10,x11,#32,#32
++	add	x12,x12,x13,lsl#32	// bfi	x12,x13,#32,#32
++	fmov	d16,x8
++	fmov	d17,x10
++	fmov	d18,x12
++
++	ldp	x8,x12,[x1],#16	// inp[0:1]
++	ldp	x9,x13,[x1],#48
++
++	ld1	{v0.4s,v1.4s,v2.4s,v3.4s},[x15],#64
++	ld1	{v4.4s,v5.4s,v6.4s,v7.4s},[x15],#64
++	ld1	{v8.4s},[x15]
++
++#ifdef	__AARCH64EB__
++	rev	x8,x8
++	rev	x12,x12
++	rev	x9,x9
++	rev	x13,x13
++#endif
++	and	x4,x8,#0x03ffffff	// base 2^64 -> base 2^26
++	and	x5,x9,#0x03ffffff
++	ubfx	x6,x8,#26,#26
++	ubfx	x7,x9,#26,#26
++	add	x4,x4,x5,lsl#32		// bfi	x4,x5,#32,#32
++	extr	x8,x12,x8,#52
++	extr	x9,x13,x9,#52
++	add	x6,x6,x7,lsl#32		// bfi	x6,x7,#32,#32
++	fmov	d9,x4
++	and	x8,x8,#0x03ffffff
++	and	x9,x9,#0x03ffffff
++	ubfx	x10,x12,#14,#26
++	ubfx	x11,x13,#14,#26
++	add	x12,x3,x12,lsr#40
++	add	x13,x3,x13,lsr#40
++	add	x8,x8,x9,lsl#32		// bfi	x8,x9,#32,#32
++	fmov	d10,x6
++	add	x10,x10,x11,lsl#32	// bfi	x10,x11,#32,#32
++	add	x12,x12,x13,lsl#32	// bfi	x12,x13,#32,#32
++	movi	v31.2d,#-1
++	fmov	d11,x8
++	fmov	d12,x10
++	fmov	d13,x12
++	ushr	v31.2d,v31.2d,#38
++
++	b.ls	.Lskip_loop
++
++.align	4
++.Loop_neon:
++	////////////////////////////////////////////////////////////////
++	// ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2
++	// ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r
++	//   ___________________/
++	// ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2
++	// ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r
++	//   ___________________/ ____________________/
++	//
++	// Note that we start with inp[2:3]*r^2. This is because it
++	// doesn't depend on reduction in previous iteration.
++	////////////////////////////////////////////////////////////////
++	// d4 = h0*r4 + h1*r3   + h2*r2   + h3*r1   + h4*r0
++	// d3 = h0*r3 + h1*r2   + h2*r1   + h3*r0   + h4*5*r4
++	// d2 = h0*r2 + h1*r1   + h2*r0   + h3*5*r4 + h4*5*r3
++	// d1 = h0*r1 + h1*r0   + h2*5*r4 + h3*5*r3 + h4*5*r2
++	// d0 = h0*r0 + h1*5*r4 + h2*5*r3 + h3*5*r2 + h4*5*r1
++
++	subs	x2,x2,#64
++	umull	v23.2d,v14.2s,v7.s[2]
++	csel	x16,x17,x16,lo
++	umull	v22.2d,v14.2s,v5.s[2]
++	umull	v21.2d,v14.2s,v3.s[2]
++	 ldp	x8,x12,[x16],#16	// inp[2:3] (or zero)
++	umull	v20.2d,v14.2s,v1.s[2]
++	 ldp	x9,x13,[x16],#48
++	umull	v19.2d,v14.2s,v0.s[2]
++#ifdef	__AARCH64EB__
++	 rev	x8,x8
++	 rev	x12,x12
++	 rev	x9,x9
++	 rev	x13,x13
++#endif
++
++	umlal	v23.2d,v15.2s,v5.s[2]
++	 and	x4,x8,#0x03ffffff	// base 2^64 -> base 2^26
++	umlal	v22.2d,v15.2s,v3.s[2]
++	 and	x5,x9,#0x03ffffff
++	umlal	v21.2d,v15.2s,v1.s[2]
++	 ubfx	x6,x8,#26,#26
++	umlal	v20.2d,v15.2s,v0.s[2]
++	 ubfx	x7,x9,#26,#26
++	umlal	v19.2d,v15.2s,v8.s[2]
++	 add	x4,x4,x5,lsl#32		// bfi	x4,x5,#32,#32
++
++	umlal	v23.2d,v16.2s,v3.s[2]
++	 extr	x8,x12,x8,#52
++	umlal	v22.2d,v16.2s,v1.s[2]
++	 extr	x9,x13,x9,#52
++	umlal	v21.2d,v16.2s,v0.s[2]
++	 add	x6,x6,x7,lsl#32		// bfi	x6,x7,#32,#32
++	umlal	v20.2d,v16.2s,v8.s[2]
++	 fmov	d14,x4
++	umlal	v19.2d,v16.2s,v6.s[2]
++	 and	x8,x8,#0x03ffffff
++
++	umlal	v23.2d,v17.2s,v1.s[2]
++	 and	x9,x9,#0x03ffffff
++	umlal	v22.2d,v17.2s,v0.s[2]
++	 ubfx	x10,x12,#14,#26
++	umlal	v21.2d,v17.2s,v8.s[2]
++	 ubfx	x11,x13,#14,#26
++	umlal	v20.2d,v17.2s,v6.s[2]
++	 add	x8,x8,x9,lsl#32		// bfi	x8,x9,#32,#32
++	umlal	v19.2d,v17.2s,v4.s[2]
++	 fmov	d15,x6
++
++	add	v11.2s,v11.2s,v26.2s
++	 add	x12,x3,x12,lsr#40
++	umlal	v23.2d,v18.2s,v0.s[2]
++	 add	x13,x3,x13,lsr#40
++	umlal	v22.2d,v18.2s,v8.s[2]
++	 add	x10,x10,x11,lsl#32	// bfi	x10,x11,#32,#32
++	umlal	v21.2d,v18.2s,v6.s[2]
++	 add	x12,x12,x13,lsl#32	// bfi	x12,x13,#32,#32
++	umlal	v20.2d,v18.2s,v4.s[2]
++	 fmov	d16,x8
++	umlal	v19.2d,v18.2s,v2.s[2]
++	 fmov	d17,x10
++
++	////////////////////////////////////////////////////////////////
++	// (hash+inp[0:1])*r^4 and accumulate
++
++	add	v9.2s,v9.2s,v24.2s
++	 fmov	d18,x12
++	umlal	v22.2d,v11.2s,v1.s[0]
++	 ldp	x8,x12,[x1],#16	// inp[0:1]
++	umlal	v19.2d,v11.2s,v6.s[0]
++	 ldp	x9,x13,[x1],#48
++	umlal	v23.2d,v11.2s,v3.s[0]
++	umlal	v20.2d,v11.2s,v8.s[0]
++	umlal	v21.2d,v11.2s,v0.s[0]
++#ifdef	__AARCH64EB__
++	 rev	x8,x8
++	 rev	x12,x12
++	 rev	x9,x9
++	 rev	x13,x13
++#endif
++
++	add	v10.2s,v10.2s,v25.2s
++	umlal	v22.2d,v9.2s,v5.s[0]
++	umlal	v23.2d,v9.2s,v7.s[0]
++	 and	x4,x8,#0x03ffffff	// base 2^64 -> base 2^26
++	umlal	v21.2d,v9.2s,v3.s[0]
++	 and	x5,x9,#0x03ffffff
++	umlal	v19.2d,v9.2s,v0.s[0]
++	 ubfx	x6,x8,#26,#26
++	umlal	v20.2d,v9.2s,v1.s[0]
++	 ubfx	x7,x9,#26,#26
++
++	add	v12.2s,v12.2s,v27.2s
++	 add	x4,x4,x5,lsl#32		// bfi	x4,x5,#32,#32
++	umlal	v22.2d,v10.2s,v3.s[0]
++	 extr	x8,x12,x8,#52
++	umlal	v23.2d,v10.2s,v5.s[0]
++	 extr	x9,x13,x9,#52
++	umlal	v19.2d,v10.2s,v8.s[0]
++	 add	x6,x6,x7,lsl#32		// bfi	x6,x7,#32,#32
++	umlal	v21.2d,v10.2s,v1.s[0]
++	 fmov	d9,x4
++	umlal	v20.2d,v10.2s,v0.s[0]
++	 and	x8,x8,#0x03ffffff
++
++	add	v13.2s,v13.2s,v28.2s
++	 and	x9,x9,#0x03ffffff
++	umlal	v22.2d,v12.2s,v0.s[0]
++	 ubfx	x10,x12,#14,#26
++	umlal	v19.2d,v12.2s,v4.s[0]
++	 ubfx	x11,x13,#14,#26
++	umlal	v23.2d,v12.2s,v1.s[0]
++	 add	x8,x8,x9,lsl#32		// bfi	x8,x9,#32,#32
++	umlal	v20.2d,v12.2s,v6.s[0]
++	 fmov	d10,x6
++	umlal	v21.2d,v12.2s,v8.s[0]
++	 add	x12,x3,x12,lsr#40
++
++	umlal	v22.2d,v13.2s,v8.s[0]
++	 add	x13,x3,x13,lsr#40
++	umlal	v19.2d,v13.2s,v2.s[0]
++	 add	x10,x10,x11,lsl#32	// bfi	x10,x11,#32,#32
++	umlal	v23.2d,v13.2s,v0.s[0]
++	 add	x12,x12,x13,lsl#32	// bfi	x12,x13,#32,#32
++	umlal	v20.2d,v13.2s,v4.s[0]
++	 fmov	d11,x8
++	umlal	v21.2d,v13.2s,v6.s[0]
++	 fmov	d12,x10
++	 fmov	d13,x12
++
++	/////////////////////////////////////////////////////////////////
++	// lazy reduction as discussed in "NEON crypto" by D.J. Bernstein
++	// and P. Schwabe
++	//
++	// [see discussion in poly1305-armv4 module]
++
++	ushr	v29.2d,v22.2d,#26
++	xtn	v27.2s,v22.2d
++	 ushr	v30.2d,v19.2d,#26
++	 and	v19.16b,v19.16b,v31.16b
++	add	v23.2d,v23.2d,v29.2d	// h3 -> h4
++	bic	v27.2s,#0xfc,lsl#24	// &=0x03ffffff
++	 add	v20.2d,v20.2d,v30.2d	// h0 -> h1
++
++	ushr	v29.2d,v23.2d,#26
++	xtn	v28.2s,v23.2d
++	 ushr	v30.2d,v20.2d,#26
++	 xtn	v25.2s,v20.2d
++	bic	v28.2s,#0xfc,lsl#24
++	 add	v21.2d,v21.2d,v30.2d	// h1 -> h2
++
++	add	v19.2d,v19.2d,v29.2d
++	shl	v29.2d,v29.2d,#2
++	 shrn	v30.2s,v21.2d,#26
++	 xtn	v26.2s,v21.2d
++	add	v19.2d,v19.2d,v29.2d	// h4 -> h0
++	 bic	v25.2s,#0xfc,lsl#24
++	 add	v27.2s,v27.2s,v30.2s		// h2 -> h3
++	 bic	v26.2s,#0xfc,lsl#24
++
++	shrn	v29.2s,v19.2d,#26
++	xtn	v24.2s,v19.2d
++	 ushr	v30.2s,v27.2s,#26
++	 bic	v27.2s,#0xfc,lsl#24
++	 bic	v24.2s,#0xfc,lsl#24
++	add	v25.2s,v25.2s,v29.2s		// h0 -> h1
++	 add	v28.2s,v28.2s,v30.2s		// h3 -> h4
++
++	b.hi	.Loop_neon
++
++.Lskip_loop:
++	dup	v16.2d,v16.d[0]
++	add	v11.2s,v11.2s,v26.2s
++
++	////////////////////////////////////////////////////////////////
++	// multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1
++
++	adds	x2,x2,#32
++	b.ne	.Long_tail
++
++	dup	v16.2d,v11.d[0]
++	add	v14.2s,v9.2s,v24.2s
++	add	v17.2s,v12.2s,v27.2s
++	add	v15.2s,v10.2s,v25.2s
++	add	v18.2s,v13.2s,v28.2s
++
++.Long_tail:
++	dup	v14.2d,v14.d[0]
++	umull2	v19.2d,v16.4s,v6.4s
++	umull2	v22.2d,v16.4s,v1.4s
++	umull2	v23.2d,v16.4s,v3.4s
++	umull2	v21.2d,v16.4s,v0.4s
++	umull2	v20.2d,v16.4s,v8.4s
++
++	dup	v15.2d,v15.d[0]
++	umlal2	v19.2d,v14.4s,v0.4s
++	umlal2	v21.2d,v14.4s,v3.4s
++	umlal2	v22.2d,v14.4s,v5.4s
++	umlal2	v23.2d,v14.4s,v7.4s
++	umlal2	v20.2d,v14.4s,v1.4s
++
++	dup	v17.2d,v17.d[0]
++	umlal2	v19.2d,v15.4s,v8.4s
++	umlal2	v22.2d,v15.4s,v3.4s
++	umlal2	v21.2d,v15.4s,v1.4s
++	umlal2	v23.2d,v15.4s,v5.4s
++	umlal2	v20.2d,v15.4s,v0.4s
++
++	dup	v18.2d,v18.d[0]
++	umlal2	v22.2d,v17.4s,v0.4s
++	umlal2	v23.2d,v17.4s,v1.4s
++	umlal2	v19.2d,v17.4s,v4.4s
++	umlal2	v20.2d,v17.4s,v6.4s
++	umlal2	v21.2d,v17.4s,v8.4s
++
++	umlal2	v22.2d,v18.4s,v8.4s
++	umlal2	v19.2d,v18.4s,v2.4s
++	umlal2	v23.2d,v18.4s,v0.4s
++	umlal2	v20.2d,v18.4s,v4.4s
++	umlal2	v21.2d,v18.4s,v6.4s
++
++	b.eq	.Lshort_tail
++
++	////////////////////////////////////////////////////////////////
++	// (hash+inp[0:1])*r^4:r^3 and accumulate
++
++	add	v9.2s,v9.2s,v24.2s
++	umlal	v22.2d,v11.2s,v1.2s
++	umlal	v19.2d,v11.2s,v6.2s
++	umlal	v23.2d,v11.2s,v3.2s
++	umlal	v20.2d,v11.2s,v8.2s
++	umlal	v21.2d,v11.2s,v0.2s
++
++	add	v10.2s,v10.2s,v25.2s
++	umlal	v22.2d,v9.2s,v5.2s
++	umlal	v19.2d,v9.2s,v0.2s
++	umlal	v23.2d,v9.2s,v7.2s
++	umlal	v20.2d,v9.2s,v1.2s
++	umlal	v21.2d,v9.2s,v3.2s
++
++	add	v12.2s,v12.2s,v27.2s
++	umlal	v22.2d,v10.2s,v3.2s
++	umlal	v19.2d,v10.2s,v8.2s
++	umlal	v23.2d,v10.2s,v5.2s
++	umlal	v20.2d,v10.2s,v0.2s
++	umlal	v21.2d,v10.2s,v1.2s
++
++	add	v13.2s,v13.2s,v28.2s
++	umlal	v22.2d,v12.2s,v0.2s
++	umlal	v19.2d,v12.2s,v4.2s
++	umlal	v23.2d,v12.2s,v1.2s
++	umlal	v20.2d,v12.2s,v6.2s
++	umlal	v21.2d,v12.2s,v8.2s
++
++	umlal	v22.2d,v13.2s,v8.2s
++	umlal	v19.2d,v13.2s,v2.2s
++	umlal	v23.2d,v13.2s,v0.2s
++	umlal	v20.2d,v13.2s,v4.2s
++	umlal	v21.2d,v13.2s,v6.2s
++
++.Lshort_tail:
++	////////////////////////////////////////////////////////////////
++	// horizontal add
++
++	addp	v22.2d,v22.2d,v22.2d
++	 ldp	d8,d9,[sp,#16]		// meet ABI requirements
++	addp	v19.2d,v19.2d,v19.2d
++	 ldp	d10,d11,[sp,#32]
++	addp	v23.2d,v23.2d,v23.2d
++	 ldp	d12,d13,[sp,#48]
++	addp	v20.2d,v20.2d,v20.2d
++	 ldp	d14,d15,[sp,#64]
++	addp	v21.2d,v21.2d,v21.2d
++	 ldr	x30,[sp,#8]
++	 .inst	0xd50323bf		// autiasp
++
++	////////////////////////////////////////////////////////////////
++	// lazy reduction, but without narrowing
++
++	ushr	v29.2d,v22.2d,#26
++	and	v22.16b,v22.16b,v31.16b
++	 ushr	v30.2d,v19.2d,#26
++	 and	v19.16b,v19.16b,v31.16b
++
++	add	v23.2d,v23.2d,v29.2d	// h3 -> h4
++	 add	v20.2d,v20.2d,v30.2d	// h0 -> h1
++
++	ushr	v29.2d,v23.2d,#26
++	and	v23.16b,v23.16b,v31.16b
++	 ushr	v30.2d,v20.2d,#26
++	 and	v20.16b,v20.16b,v31.16b
++	 add	v21.2d,v21.2d,v30.2d	// h1 -> h2
++
++	add	v19.2d,v19.2d,v29.2d
++	shl	v29.2d,v29.2d,#2
++	 ushr	v30.2d,v21.2d,#26
++	 and	v21.16b,v21.16b,v31.16b
++	add	v19.2d,v19.2d,v29.2d	// h4 -> h0
++	 add	v22.2d,v22.2d,v30.2d	// h2 -> h3
++
++	ushr	v29.2d,v19.2d,#26
++	and	v19.16b,v19.16b,v31.16b
++	 ushr	v30.2d,v22.2d,#26
++	 and	v22.16b,v22.16b,v31.16b
++	add	v20.2d,v20.2d,v29.2d	// h0 -> h1
++	 add	v23.2d,v23.2d,v30.2d	// h3 -> h4
++
++	////////////////////////////////////////////////////////////////
++	// write the result, can be partially reduced
++
++	st4	{v19.s,v20.s,v21.s,v22.s}[0],[x0],#16
++	mov	x4,#1
++	st1	{v23.s}[0],[x0]
++	str	x4,[x0,#8]		// set is_base2_26
++
++	ldr	x29,[sp],#80
++	ret
++.size	poly1305_blocks_neon,.-poly1305_blocks_neon
++
++.align	5
++.Lzeros:
++.long	0,0,0,0,0,0,0,0
++.asciz	"Poly1305 for ARMv8, CRYPTOGAMS by @dot-asm"
++.align	2
++#if !defined(__KERNEL__) && !defined(_WIN64)
++.comm	OPENSSL_armcap_P,4,4
++.hidden	OPENSSL_armcap_P
++#endif
+--- /dev/null
++++ b/arch/arm64/crypto/poly1305-glue.c
+@@ -0,0 +1,237 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * OpenSSL/Cryptogams accelerated Poly1305 transform for arm64
++ *
++ * Copyright (C) 2019 Linaro Ltd. <ard.biesheuvel@linaro.org>
++ */
++
++#include <asm/hwcap.h>
++#include <asm/neon.h>
++#include <asm/simd.h>
++#include <asm/unaligned.h>
++#include <crypto/algapi.h>
++#include <crypto/internal/hash.h>
++#include <crypto/internal/poly1305.h>
++#include <crypto/internal/simd.h>
++#include <linux/cpufeature.h>
++#include <linux/crypto.h>
++#include <linux/jump_label.h>
++#include <linux/module.h>
++
++asmlinkage void poly1305_init_arm64(void *state, const u8 *key);
++asmlinkage void poly1305_blocks(void *state, const u8 *src, u32 len, u32 hibit);
++asmlinkage void poly1305_blocks_neon(void *state, const u8 *src, u32 len, u32 hibit);
++asmlinkage void poly1305_emit(void *state, __le32 *digest, const u32 *nonce);
++
++static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon);
++
++void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key)
++{
++	poly1305_init_arm64(&dctx->h, key);
++	dctx->s[0] = get_unaligned_le32(key + 16);
++	dctx->s[1] = get_unaligned_le32(key + 20);
++	dctx->s[2] = get_unaligned_le32(key + 24);
++	dctx->s[3] = get_unaligned_le32(key + 28);
++	dctx->buflen = 0;
++}
++EXPORT_SYMBOL(poly1305_init_arch);
++
++static int neon_poly1305_init(struct shash_desc *desc)
++{
++	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
++
++	dctx->buflen = 0;
++	dctx->rset = 0;
++	dctx->sset = false;
++
++	return 0;
++}
++
++static void neon_poly1305_blocks(struct poly1305_desc_ctx *dctx, const u8 *src,
++				 u32 len, u32 hibit, bool do_neon)
++{
++	if (unlikely(!dctx->sset)) {
++		if (!dctx->rset) {
++			poly1305_init_arch(dctx, src);
++			src += POLY1305_BLOCK_SIZE;
++			len -= POLY1305_BLOCK_SIZE;
++			dctx->rset = 1;
++		}
++		if (len >= POLY1305_BLOCK_SIZE) {
++			dctx->s[0] = get_unaligned_le32(src +  0);
++			dctx->s[1] = get_unaligned_le32(src +  4);
++			dctx->s[2] = get_unaligned_le32(src +  8);
++			dctx->s[3] = get_unaligned_le32(src + 12);
++			src += POLY1305_BLOCK_SIZE;
++			len -= POLY1305_BLOCK_SIZE;
++			dctx->sset = true;
++		}
++		if (len < POLY1305_BLOCK_SIZE)
++			return;
++	}
++
++	len &= ~(POLY1305_BLOCK_SIZE - 1);
++
++	if (static_branch_likely(&have_neon) && likely(do_neon))
++		poly1305_blocks_neon(&dctx->h, src, len, hibit);
++	else
++		poly1305_blocks(&dctx->h, src, len, hibit);
++}
++
++static void neon_poly1305_do_update(struct poly1305_desc_ctx *dctx,
++				    const u8 *src, u32 len, bool do_neon)
++{
++	if (unlikely(dctx->buflen)) {
++		u32 bytes = min(len, POLY1305_BLOCK_SIZE - dctx->buflen);
++
++		memcpy(dctx->buf + dctx->buflen, src, bytes);
++		src += bytes;
++		len -= bytes;
++		dctx->buflen += bytes;
++
++		if (dctx->buflen == POLY1305_BLOCK_SIZE) {
++			neon_poly1305_blocks(dctx, dctx->buf,
++					     POLY1305_BLOCK_SIZE, 1, false);
++			dctx->buflen = 0;
++		}
++	}
++
++	if (likely(len >= POLY1305_BLOCK_SIZE)) {
++		neon_poly1305_blocks(dctx, src, len, 1, do_neon);
++		src += round_down(len, POLY1305_BLOCK_SIZE);
++		len %= POLY1305_BLOCK_SIZE;
++	}
++
++	if (unlikely(len)) {
++		dctx->buflen = len;
++		memcpy(dctx->buf, src, len);
++	}
++}
++
++static int neon_poly1305_update(struct shash_desc *desc,
++				const u8 *src, unsigned int srclen)
++{
++	bool do_neon = crypto_simd_usable() && srclen > 128;
++	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
++
++	if (static_branch_likely(&have_neon) && do_neon)
++		kernel_neon_begin();
++	neon_poly1305_do_update(dctx, src, srclen, do_neon);
++	if (static_branch_likely(&have_neon) && do_neon)
++		kernel_neon_end();
++	return 0;
++}
++
++void poly1305_update_arch(struct poly1305_desc_ctx *dctx, const u8 *src,
++			  unsigned int nbytes)
++{
++	if (unlikely(dctx->buflen)) {
++		u32 bytes = min(nbytes, POLY1305_BLOCK_SIZE - dctx->buflen);
++
++		memcpy(dctx->buf + dctx->buflen, src, bytes);
++		src += bytes;
++		nbytes -= bytes;
++		dctx->buflen += bytes;
++
++		if (dctx->buflen == POLY1305_BLOCK_SIZE) {
++			poly1305_blocks(&dctx->h, dctx->buf, POLY1305_BLOCK_SIZE, 1);
++			dctx->buflen = 0;
++		}
++	}
++
++	if (likely(nbytes >= POLY1305_BLOCK_SIZE)) {
++		unsigned int len = round_down(nbytes, POLY1305_BLOCK_SIZE);
++
++		if (static_branch_likely(&have_neon) && crypto_simd_usable()) {
++			kernel_neon_begin();
++			poly1305_blocks_neon(&dctx->h, src, len, 1);
++			kernel_neon_end();
++		} else {
++			poly1305_blocks(&dctx->h, src, len, 1);
++		}
++		src += len;
++		nbytes %= POLY1305_BLOCK_SIZE;
++	}
++
++	if (unlikely(nbytes)) {
++		dctx->buflen = nbytes;
++		memcpy(dctx->buf, src, nbytes);
++	}
++}
++EXPORT_SYMBOL(poly1305_update_arch);
++
++void poly1305_final_arch(struct poly1305_desc_ctx *dctx, u8 *dst)
++{
++	__le32 digest[4];
++	u64 f = 0;
++
++	if (unlikely(dctx->buflen)) {
++		dctx->buf[dctx->buflen++] = 1;
++		memset(dctx->buf + dctx->buflen, 0,
++		       POLY1305_BLOCK_SIZE - dctx->buflen);
++		poly1305_blocks(&dctx->h, dctx->buf, POLY1305_BLOCK_SIZE, 0);
++	}
++
++	poly1305_emit(&dctx->h, digest, dctx->s);
++
++	/* mac = (h + s) % (2^128) */
++	f = (f >> 32) + le32_to_cpu(digest[0]);
++	put_unaligned_le32(f, dst);
++	f = (f >> 32) + le32_to_cpu(digest[1]);
++	put_unaligned_le32(f, dst + 4);
++	f = (f >> 32) + le32_to_cpu(digest[2]);
++	put_unaligned_le32(f, dst + 8);
++	f = (f >> 32) + le32_to_cpu(digest[3]);
++	put_unaligned_le32(f, dst + 12);
++
++	*dctx = (struct poly1305_desc_ctx){};
++}
++EXPORT_SYMBOL(poly1305_final_arch);
++
++static int neon_poly1305_final(struct shash_desc *desc, u8 *dst)
++{
++	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
++
++	if (unlikely(!dctx->sset))
++		return -ENOKEY;
++
++	poly1305_final_arch(dctx, dst);
++	return 0;
++}
++
++static struct shash_alg neon_poly1305_alg = {
++	.init			= neon_poly1305_init,
++	.update			= neon_poly1305_update,
++	.final			= neon_poly1305_final,
++	.digestsize		= POLY1305_DIGEST_SIZE,
++	.descsize		= sizeof(struct poly1305_desc_ctx),
++
++	.base.cra_name		= "poly1305",
++	.base.cra_driver_name	= "poly1305-neon",
++	.base.cra_priority	= 200,
++	.base.cra_blocksize	= POLY1305_BLOCK_SIZE,
++	.base.cra_module	= THIS_MODULE,
++};
++
++static int __init neon_poly1305_mod_init(void)
++{
++	if (!cpu_have_named_feature(ASIMD))
++		return 0;
++
++	static_branch_enable(&have_neon);
++
++	return crypto_register_shash(&neon_poly1305_alg);
++}
++
++static void __exit neon_poly1305_mod_exit(void)
++{
++	if (cpu_have_named_feature(ASIMD))
++		crypto_unregister_shash(&neon_poly1305_alg);
++}
++
++module_init(neon_poly1305_mod_init);
++module_exit(neon_poly1305_mod_exit);
++
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS_CRYPTO("poly1305");
++MODULE_ALIAS_CRYPTO("poly1305-neon");
+--- a/lib/crypto/Kconfig
++++ b/lib/crypto/Kconfig
+@@ -40,6 +40,7 @@ config CRYPTO_LIB_DES
+ config CRYPTO_LIB_POLY1305_RSIZE
+ 	int
+ 	default 4 if X86_64
++	default 9 if ARM64
+ 	default 1
+ 
+ config CRYPTO_ARCH_HAVE_LIB_POLY1305
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0019-crypto-arm-poly1305-incorporate-OpenSSL-CRYPTOGAMS-N.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0019-crypto-arm-poly1305-incorporate-OpenSSL-CRYPTOGAMS-N.patch
new file mode 100644
index 0000000..367b20f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0019-crypto-arm-poly1305-incorporate-OpenSSL-CRYPTOGAMS-N.patch
@@ -0,0 +1,2776 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:25 +0100
+Subject: [PATCH] crypto: arm/poly1305 - incorporate OpenSSL/CRYPTOGAMS NEON
+ implementation
+
+commit a6b803b3ddc793d6db0c16f12fc12d30d20fa9cc upstream.
+
+This is a straight import of the OpenSSL/CRYPTOGAMS Poly1305 implementation
+for NEON authored by Andy Polyakov, and contributed by him to the OpenSSL
+project. The file 'poly1305-armv4.pl' is taken straight from this upstream
+GitHub repository [0] at commit ec55a08dc0244ce570c4fc7cade330c60798952f,
+and already contains all the changes required to build it as part of a
+Linux kernel module.
+
+[0] https://github.com/dot-asm/cryptogams
+
+Co-developed-by: Andy Polyakov <appro@cryptogams.org>
+Signed-off-by: Andy Polyakov <appro@cryptogams.org>
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm/crypto/Kconfig                 |    5 +
+ arch/arm/crypto/Makefile                |   12 +-
+ arch/arm/crypto/poly1305-armv4.pl       | 1236 +++++++++++++++++++++++
+ arch/arm/crypto/poly1305-core.S_shipped | 1158 +++++++++++++++++++++
+ arch/arm/crypto/poly1305-glue.c         |  276 +++++
+ lib/crypto/Kconfig                      |    2 +-
+ 6 files changed, 2687 insertions(+), 2 deletions(-)
+ create mode 100644 arch/arm/crypto/poly1305-armv4.pl
+ create mode 100644 arch/arm/crypto/poly1305-core.S_shipped
+ create mode 100644 arch/arm/crypto/poly1305-glue.c
+
+--- a/arch/arm/crypto/Kconfig
++++ b/arch/arm/crypto/Kconfig
+@@ -131,6 +131,11 @@ config CRYPTO_CHACHA20_NEON
+ 	select CRYPTO_BLKCIPHER
+ 	select CRYPTO_ARCH_HAVE_LIB_CHACHA
+ 
++config CRYPTO_POLY1305_ARM
++	tristate "Accelerated scalar and SIMD Poly1305 hash implementations"
++	select CRYPTO_HASH
++	select CRYPTO_ARCH_HAVE_LIB_POLY1305
++
+ config CRYPTO_NHPOLY1305_NEON
+ 	tristate "NEON accelerated NHPoly1305 hash function (for Adiantum)"
+ 	depends on KERNEL_MODE_NEON
+--- a/arch/arm/crypto/Makefile
++++ b/arch/arm/crypto/Makefile
+@@ -10,6 +10,7 @@ obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sh
+ obj-$(CONFIG_CRYPTO_SHA256_ARM) += sha256-arm.o
+ obj-$(CONFIG_CRYPTO_SHA512_ARM) += sha512-arm.o
+ obj-$(CONFIG_CRYPTO_CHACHA20_NEON) += chacha-neon.o
++obj-$(CONFIG_CRYPTO_POLY1305_ARM) += poly1305-arm.o
+ obj-$(CONFIG_CRYPTO_NHPOLY1305_NEON) += nhpoly1305-neon.o
+ 
+ ce-obj-$(CONFIG_CRYPTO_AES_ARM_CE) += aes-arm-ce.o
+@@ -55,12 +56,16 @@ crct10dif-arm-ce-y	:= crct10dif-ce-core.
+ crc32-arm-ce-y:= crc32-ce-core.o crc32-ce-glue.o
+ chacha-neon-y := chacha-scalar-core.o chacha-glue.o
+ chacha-neon-$(CONFIG_KERNEL_MODE_NEON) += chacha-neon-core.o
++poly1305-arm-y := poly1305-core.o poly1305-glue.o
+ nhpoly1305-neon-y := nh-neon-core.o nhpoly1305-neon-glue.o
+ 
+ ifdef REGENERATE_ARM_CRYPTO
+ quiet_cmd_perl = PERL    $@
+       cmd_perl = $(PERL) $(<) > $(@)
+ 
++$(src)/poly1305-core.S_shipped: $(src)/poly1305-armv4.pl
++	$(call cmd,perl)
++
+ $(src)/sha256-core.S_shipped: $(src)/sha256-armv4.pl
+ 	$(call cmd,perl)
+ 
+@@ -68,4 +73,9 @@ $(src)/sha512-core.S_shipped: $(src)/sha
+ 	$(call cmd,perl)
+ endif
+ 
+-clean-files += sha256-core.S sha512-core.S
++clean-files += poly1305-core.S sha256-core.S sha512-core.S
++
++# massage the perlasm code a bit so we only get the NEON routine if we need it
++poly1305-aflags-$(CONFIG_CPU_V7) := -U__LINUX_ARM_ARCH__ -D__LINUX_ARM_ARCH__=5
++poly1305-aflags-$(CONFIG_KERNEL_MODE_NEON) := -U__LINUX_ARM_ARCH__ -D__LINUX_ARM_ARCH__=7
++AFLAGS_poly1305-core.o += $(poly1305-aflags-y)
+--- /dev/null
++++ b/arch/arm/crypto/poly1305-armv4.pl
+@@ -0,0 +1,1236 @@
++#!/usr/bin/env perl
++# SPDX-License-Identifier: GPL-1.0+ OR BSD-3-Clause
++#
++# ====================================================================
++# Written by Andy Polyakov, @dot-asm, initially for the OpenSSL
++# project.
++# ====================================================================
++#
++#			IALU(*)/gcc-4.4		NEON
++#
++# ARM11xx(ARMv6)	7.78/+100%		-
++# Cortex-A5		6.35/+130%		3.00
++# Cortex-A8		6.25/+115%		2.36
++# Cortex-A9		5.10/+95%		2.55
++# Cortex-A15		3.85/+85%		1.25(**)
++# Snapdragon S4		5.70/+100%		1.48(**)
++#
++# (*)	this is for -march=armv6, i.e. with bunch of ldrb loading data;
++# (**)	these are trade-off results, they can be improved by ~8% but at
++#	the cost of 15/12% regression on Cortex-A5/A7, it's even possible
++#	to improve Cortex-A9 result, but then A5/A7 loose more than 20%;
++
++$flavour = shift;
++if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
++else { while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {} }
++
++if ($flavour && $flavour ne "void") {
++    $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++    ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
++    ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
++    die "can't locate arm-xlate.pl";
++
++    open STDOUT,"| \"$^X\" $xlate $flavour $output";
++} else {
++    open STDOUT,">$output";
++}
++
++($ctx,$inp,$len,$padbit)=map("r$_",(0..3));
++
++$code.=<<___;
++#ifndef	__KERNEL__
++# include "arm_arch.h"
++#else
++# define __ARM_ARCH__ __LINUX_ARM_ARCH__
++# define __ARM_MAX_ARCH__ __LINUX_ARM_ARCH__
++# define poly1305_init   poly1305_init_arm
++# define poly1305_blocks poly1305_blocks_arm
++# define poly1305_emit   poly1305_emit_arm
++.globl	poly1305_blocks_neon
++#endif
++
++#if defined(__thumb2__)
++.syntax	unified
++.thumb
++#else
++.code	32
++#endif
++
++.text
++
++.globl	poly1305_emit
++.globl	poly1305_blocks
++.globl	poly1305_init
++.type	poly1305_init,%function
++.align	5
++poly1305_init:
++.Lpoly1305_init:
++	stmdb	sp!,{r4-r11}
++
++	eor	r3,r3,r3
++	cmp	$inp,#0
++	str	r3,[$ctx,#0]		@ zero hash value
++	str	r3,[$ctx,#4]
++	str	r3,[$ctx,#8]
++	str	r3,[$ctx,#12]
++	str	r3,[$ctx,#16]
++	str	r3,[$ctx,#36]		@ clear is_base2_26
++	add	$ctx,$ctx,#20
++
++#ifdef	__thumb2__
++	it	eq
++#endif
++	moveq	r0,#0
++	beq	.Lno_key
++
++#if	__ARM_MAX_ARCH__>=7
++	mov	r3,#-1
++	str	r3,[$ctx,#28]		@ impossible key power value
++# ifndef __KERNEL__
++	adr	r11,.Lpoly1305_init
++	ldr	r12,.LOPENSSL_armcap
++# endif
++#endif
++	ldrb	r4,[$inp,#0]
++	mov	r10,#0x0fffffff
++	ldrb	r5,[$inp,#1]
++	and	r3,r10,#-4		@ 0x0ffffffc
++	ldrb	r6,[$inp,#2]
++	ldrb	r7,[$inp,#3]
++	orr	r4,r4,r5,lsl#8
++	ldrb	r5,[$inp,#4]
++	orr	r4,r4,r6,lsl#16
++	ldrb	r6,[$inp,#5]
++	orr	r4,r4,r7,lsl#24
++	ldrb	r7,[$inp,#6]
++	and	r4,r4,r10
++
++#if	__ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
++# if !defined(_WIN32)
++	ldr	r12,[r11,r12]		@ OPENSSL_armcap_P
++# endif
++# if defined(__APPLE__) || defined(_WIN32)
++	ldr	r12,[r12]
++# endif
++#endif
++	ldrb	r8,[$inp,#7]
++	orr	r5,r5,r6,lsl#8
++	ldrb	r6,[$inp,#8]
++	orr	r5,r5,r7,lsl#16
++	ldrb	r7,[$inp,#9]
++	orr	r5,r5,r8,lsl#24
++	ldrb	r8,[$inp,#10]
++	and	r5,r5,r3
++
++#if	__ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
++	tst	r12,#ARMV7_NEON		@ check for NEON
++# ifdef	__thumb2__
++	adr	r9,.Lpoly1305_blocks_neon
++	adr	r11,.Lpoly1305_blocks
++	it	ne
++	movne	r11,r9
++	adr	r12,.Lpoly1305_emit
++	orr	r11,r11,#1		@ thumb-ify addresses
++	orr	r12,r12,#1
++# else
++	add	r12,r11,#(.Lpoly1305_emit-.Lpoly1305_init)
++	ite	eq
++	addeq	r11,r11,#(.Lpoly1305_blocks-.Lpoly1305_init)
++	addne	r11,r11,#(.Lpoly1305_blocks_neon-.Lpoly1305_init)
++# endif
++#endif
++	ldrb	r9,[$inp,#11]
++	orr	r6,r6,r7,lsl#8
++	ldrb	r7,[$inp,#12]
++	orr	r6,r6,r8,lsl#16
++	ldrb	r8,[$inp,#13]
++	orr	r6,r6,r9,lsl#24
++	ldrb	r9,[$inp,#14]
++	and	r6,r6,r3
++
++	ldrb	r10,[$inp,#15]
++	orr	r7,r7,r8,lsl#8
++	str	r4,[$ctx,#0]
++	orr	r7,r7,r9,lsl#16
++	str	r5,[$ctx,#4]
++	orr	r7,r7,r10,lsl#24
++	str	r6,[$ctx,#8]
++	and	r7,r7,r3
++	str	r7,[$ctx,#12]
++#if	__ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
++	stmia	r2,{r11,r12}		@ fill functions table
++	mov	r0,#1
++#else
++	mov	r0,#0
++#endif
++.Lno_key:
++	ldmia	sp!,{r4-r11}
++#if	__ARM_ARCH__>=5
++	ret				@ bx	lr
++#else
++	tst	lr,#1
++	moveq	pc,lr			@ be binary compatible with V4, yet
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	poly1305_init,.-poly1305_init
++___
++{
++my ($h0,$h1,$h2,$h3,$h4,$r0,$r1,$r2,$r3)=map("r$_",(4..12));
++my ($s1,$s2,$s3)=($r1,$r2,$r3);
++
++$code.=<<___;
++.type	poly1305_blocks,%function
++.align	5
++poly1305_blocks:
++.Lpoly1305_blocks:
++	stmdb	sp!,{r3-r11,lr}
++
++	ands	$len,$len,#-16
++	beq	.Lno_data
++
++	add	$len,$len,$inp		@ end pointer
++	sub	sp,sp,#32
++
++#if __ARM_ARCH__<7
++	ldmia	$ctx,{$h0-$r3}		@ load context
++	add	$ctx,$ctx,#20
++	str	$len,[sp,#16]		@ offload stuff
++	str	$ctx,[sp,#12]
++#else
++	ldr	lr,[$ctx,#36]		@ is_base2_26
++	ldmia	$ctx!,{$h0-$h4}		@ load hash value
++	str	$len,[sp,#16]		@ offload stuff
++	str	$ctx,[sp,#12]
++
++	adds	$r0,$h0,$h1,lsl#26	@ base 2^26 -> base 2^32
++	mov	$r1,$h1,lsr#6
++	adcs	$r1,$r1,$h2,lsl#20
++	mov	$r2,$h2,lsr#12
++	adcs	$r2,$r2,$h3,lsl#14
++	mov	$r3,$h3,lsr#18
++	adcs	$r3,$r3,$h4,lsl#8
++	mov	$len,#0
++	teq	lr,#0
++	str	$len,[$ctx,#16]		@ clear is_base2_26
++	adc	$len,$len,$h4,lsr#24
++
++	itttt	ne
++	movne	$h0,$r0			@ choose between radixes
++	movne	$h1,$r1
++	movne	$h2,$r2
++	movne	$h3,$r3
++	ldmia	$ctx,{$r0-$r3}		@ load key
++	it	ne
++	movne	$h4,$len
++#endif
++
++	mov	lr,$inp
++	cmp	$padbit,#0
++	str	$r1,[sp,#20]
++	str	$r2,[sp,#24]
++	str	$r3,[sp,#28]
++	b	.Loop
++
++.align	4
++.Loop:
++#if __ARM_ARCH__<7
++	ldrb	r0,[lr],#16		@ load input
++# ifdef	__thumb2__
++	it	hi
++# endif
++	addhi	$h4,$h4,#1		@ 1<<128
++	ldrb	r1,[lr,#-15]
++	ldrb	r2,[lr,#-14]
++	ldrb	r3,[lr,#-13]
++	orr	r1,r0,r1,lsl#8
++	ldrb	r0,[lr,#-12]
++	orr	r2,r1,r2,lsl#16
++	ldrb	r1,[lr,#-11]
++	orr	r3,r2,r3,lsl#24
++	ldrb	r2,[lr,#-10]
++	adds	$h0,$h0,r3		@ accumulate input
++
++	ldrb	r3,[lr,#-9]
++	orr	r1,r0,r1,lsl#8
++	ldrb	r0,[lr,#-8]
++	orr	r2,r1,r2,lsl#16
++	ldrb	r1,[lr,#-7]
++	orr	r3,r2,r3,lsl#24
++	ldrb	r2,[lr,#-6]
++	adcs	$h1,$h1,r3
++
++	ldrb	r3,[lr,#-5]
++	orr	r1,r0,r1,lsl#8
++	ldrb	r0,[lr,#-4]
++	orr	r2,r1,r2,lsl#16
++	ldrb	r1,[lr,#-3]
++	orr	r3,r2,r3,lsl#24
++	ldrb	r2,[lr,#-2]
++	adcs	$h2,$h2,r3
++
++	ldrb	r3,[lr,#-1]
++	orr	r1,r0,r1,lsl#8
++	str	lr,[sp,#8]		@ offload input pointer
++	orr	r2,r1,r2,lsl#16
++	add	$s1,$r1,$r1,lsr#2
++	orr	r3,r2,r3,lsl#24
++#else
++	ldr	r0,[lr],#16		@ load input
++	it	hi
++	addhi	$h4,$h4,#1		@ padbit
++	ldr	r1,[lr,#-12]
++	ldr	r2,[lr,#-8]
++	ldr	r3,[lr,#-4]
++# ifdef	__ARMEB__
++	rev	r0,r0
++	rev	r1,r1
++	rev	r2,r2
++	rev	r3,r3
++# endif
++	adds	$h0,$h0,r0		@ accumulate input
++	str	lr,[sp,#8]		@ offload input pointer
++	adcs	$h1,$h1,r1
++	add	$s1,$r1,$r1,lsr#2
++	adcs	$h2,$h2,r2
++#endif
++	add	$s2,$r2,$r2,lsr#2
++	adcs	$h3,$h3,r3
++	add	$s3,$r3,$r3,lsr#2
++
++	umull	r2,r3,$h1,$r0
++	 adc	$h4,$h4,#0
++	umull	r0,r1,$h0,$r0
++	umlal	r2,r3,$h4,$s1
++	umlal	r0,r1,$h3,$s1
++	ldr	$r1,[sp,#20]		@ reload $r1
++	umlal	r2,r3,$h2,$s3
++	umlal	r0,r1,$h1,$s3
++	umlal	r2,r3,$h3,$s2
++	umlal	r0,r1,$h2,$s2
++	umlal	r2,r3,$h0,$r1
++	str	r0,[sp,#0]		@ future $h0
++	 mul	r0,$s2,$h4
++	ldr	$r2,[sp,#24]		@ reload $r2
++	adds	r2,r2,r1		@ d1+=d0>>32
++	 eor	r1,r1,r1
++	adc	lr,r3,#0		@ future $h2
++	str	r2,[sp,#4]		@ future $h1
++
++	mul	r2,$s3,$h4
++	eor	r3,r3,r3
++	umlal	r0,r1,$h3,$s3
++	ldr	$r3,[sp,#28]		@ reload $r3
++	umlal	r2,r3,$h3,$r0
++	umlal	r0,r1,$h2,$r0
++	umlal	r2,r3,$h2,$r1
++	umlal	r0,r1,$h1,$r1
++	umlal	r2,r3,$h1,$r2
++	umlal	r0,r1,$h0,$r2
++	umlal	r2,r3,$h0,$r3
++	ldr	$h0,[sp,#0]
++	mul	$h4,$r0,$h4
++	ldr	$h1,[sp,#4]
++
++	adds	$h2,lr,r0		@ d2+=d1>>32
++	ldr	lr,[sp,#8]		@ reload input pointer
++	adc	r1,r1,#0
++	adds	$h3,r2,r1		@ d3+=d2>>32
++	ldr	r0,[sp,#16]		@ reload end pointer
++	adc	r3,r3,#0
++	add	$h4,$h4,r3		@ h4+=d3>>32
++
++	and	r1,$h4,#-4
++	and	$h4,$h4,#3
++	add	r1,r1,r1,lsr#2		@ *=5
++	adds	$h0,$h0,r1
++	adcs	$h1,$h1,#0
++	adcs	$h2,$h2,#0
++	adcs	$h3,$h3,#0
++	adc	$h4,$h4,#0
++
++	cmp	r0,lr			@ done yet?
++	bhi	.Loop
++
++	ldr	$ctx,[sp,#12]
++	add	sp,sp,#32
++	stmdb	$ctx,{$h0-$h4}		@ store the result
++
++.Lno_data:
++#if	__ARM_ARCH__>=5
++	ldmia	sp!,{r3-r11,pc}
++#else
++	ldmia	sp!,{r3-r11,lr}
++	tst	lr,#1
++	moveq	pc,lr			@ be binary compatible with V4, yet
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	poly1305_blocks,.-poly1305_blocks
++___
++}
++{
++my ($ctx,$mac,$nonce)=map("r$_",(0..2));
++my ($h0,$h1,$h2,$h3,$h4,$g0,$g1,$g2,$g3)=map("r$_",(3..11));
++my $g4=$ctx;
++
++$code.=<<___;
++.type	poly1305_emit,%function
++.align	5
++poly1305_emit:
++.Lpoly1305_emit:
++	stmdb	sp!,{r4-r11}
++
++	ldmia	$ctx,{$h0-$h4}
++
++#if __ARM_ARCH__>=7
++	ldr	ip,[$ctx,#36]		@ is_base2_26
++
++	adds	$g0,$h0,$h1,lsl#26	@ base 2^26 -> base 2^32
++	mov	$g1,$h1,lsr#6
++	adcs	$g1,$g1,$h2,lsl#20
++	mov	$g2,$h2,lsr#12
++	adcs	$g2,$g2,$h3,lsl#14
++	mov	$g3,$h3,lsr#18
++	adcs	$g3,$g3,$h4,lsl#8
++	mov	$g4,#0
++	adc	$g4,$g4,$h4,lsr#24
++
++	tst	ip,ip
++	itttt	ne
++	movne	$h0,$g0
++	movne	$h1,$g1
++	movne	$h2,$g2
++	movne	$h3,$g3
++	it	ne
++	movne	$h4,$g4
++#endif
++
++	adds	$g0,$h0,#5		@ compare to modulus
++	adcs	$g1,$h1,#0
++	adcs	$g2,$h2,#0
++	adcs	$g3,$h3,#0
++	adc	$g4,$h4,#0
++	tst	$g4,#4			@ did it carry/borrow?
++
++#ifdef	__thumb2__
++	it	ne
++#endif
++	movne	$h0,$g0
++	ldr	$g0,[$nonce,#0]
++#ifdef	__thumb2__
++	it	ne
++#endif
++	movne	$h1,$g1
++	ldr	$g1,[$nonce,#4]
++#ifdef	__thumb2__
++	it	ne
++#endif
++	movne	$h2,$g2
++	ldr	$g2,[$nonce,#8]
++#ifdef	__thumb2__
++	it	ne
++#endif
++	movne	$h3,$g3
++	ldr	$g3,[$nonce,#12]
++
++	adds	$h0,$h0,$g0
++	adcs	$h1,$h1,$g1
++	adcs	$h2,$h2,$g2
++	adc	$h3,$h3,$g3
++
++#if __ARM_ARCH__>=7
++# ifdef __ARMEB__
++	rev	$h0,$h0
++	rev	$h1,$h1
++	rev	$h2,$h2
++	rev	$h3,$h3
++# endif
++	str	$h0,[$mac,#0]
++	str	$h1,[$mac,#4]
++	str	$h2,[$mac,#8]
++	str	$h3,[$mac,#12]
++#else
++	strb	$h0,[$mac,#0]
++	mov	$h0,$h0,lsr#8
++	strb	$h1,[$mac,#4]
++	mov	$h1,$h1,lsr#8
++	strb	$h2,[$mac,#8]
++	mov	$h2,$h2,lsr#8
++	strb	$h3,[$mac,#12]
++	mov	$h3,$h3,lsr#8
++
++	strb	$h0,[$mac,#1]
++	mov	$h0,$h0,lsr#8
++	strb	$h1,[$mac,#5]
++	mov	$h1,$h1,lsr#8
++	strb	$h2,[$mac,#9]
++	mov	$h2,$h2,lsr#8
++	strb	$h3,[$mac,#13]
++	mov	$h3,$h3,lsr#8
++
++	strb	$h0,[$mac,#2]
++	mov	$h0,$h0,lsr#8
++	strb	$h1,[$mac,#6]
++	mov	$h1,$h1,lsr#8
++	strb	$h2,[$mac,#10]
++	mov	$h2,$h2,lsr#8
++	strb	$h3,[$mac,#14]
++	mov	$h3,$h3,lsr#8
++
++	strb	$h0,[$mac,#3]
++	strb	$h1,[$mac,#7]
++	strb	$h2,[$mac,#11]
++	strb	$h3,[$mac,#15]
++#endif
++	ldmia	sp!,{r4-r11}
++#if	__ARM_ARCH__>=5
++	ret				@ bx	lr
++#else
++	tst	lr,#1
++	moveq	pc,lr			@ be binary compatible with V4, yet
++	bx	lr			@ interoperable with Thumb ISA:-)
++#endif
++.size	poly1305_emit,.-poly1305_emit
++___
++{
++my ($R0,$R1,$S1,$R2,$S2,$R3,$S3,$R4,$S4) = map("d$_",(0..9));
++my ($D0,$D1,$D2,$D3,$D4, $H0,$H1,$H2,$H3,$H4) = map("q$_",(5..14));
++my ($T0,$T1,$MASK) = map("q$_",(15,4,0));
++
++my ($in2,$zeros,$tbl0,$tbl1) = map("r$_",(4..7));
++
++$code.=<<___;
++#if	__ARM_MAX_ARCH__>=7
++.fpu	neon
++
++.type	poly1305_init_neon,%function
++.align	5
++poly1305_init_neon:
++.Lpoly1305_init_neon:
++	ldr	r3,[$ctx,#48]		@ first table element
++	cmp	r3,#-1			@ is value impossible?
++	bne	.Lno_init_neon
++
++	ldr	r4,[$ctx,#20]		@ load key base 2^32
++	ldr	r5,[$ctx,#24]
++	ldr	r6,[$ctx,#28]
++	ldr	r7,[$ctx,#32]
++
++	and	r2,r4,#0x03ffffff	@ base 2^32 -> base 2^26
++	mov	r3,r4,lsr#26
++	mov	r4,r5,lsr#20
++	orr	r3,r3,r5,lsl#6
++	mov	r5,r6,lsr#14
++	orr	r4,r4,r6,lsl#12
++	mov	r6,r7,lsr#8
++	orr	r5,r5,r7,lsl#18
++	and	r3,r3,#0x03ffffff
++	and	r4,r4,#0x03ffffff
++	and	r5,r5,#0x03ffffff
++
++	vdup.32	$R0,r2			@ r^1 in both lanes
++	add	r2,r3,r3,lsl#2		@ *5
++	vdup.32	$R1,r3
++	add	r3,r4,r4,lsl#2
++	vdup.32	$S1,r2
++	vdup.32	$R2,r4
++	add	r4,r5,r5,lsl#2
++	vdup.32	$S2,r3
++	vdup.32	$R3,r5
++	add	r5,r6,r6,lsl#2
++	vdup.32	$S3,r4
++	vdup.32	$R4,r6
++	vdup.32	$S4,r5
++
++	mov	$zeros,#2		@ counter
++
++.Lsquare_neon:
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
++	@ d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
++	@ d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
++	@ d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
++	@ d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
++
++	vmull.u32	$D0,$R0,${R0}[1]
++	vmull.u32	$D1,$R1,${R0}[1]
++	vmull.u32	$D2,$R2,${R0}[1]
++	vmull.u32	$D3,$R3,${R0}[1]
++	vmull.u32	$D4,$R4,${R0}[1]
++
++	vmlal.u32	$D0,$R4,${S1}[1]
++	vmlal.u32	$D1,$R0,${R1}[1]
++	vmlal.u32	$D2,$R1,${R1}[1]
++	vmlal.u32	$D3,$R2,${R1}[1]
++	vmlal.u32	$D4,$R3,${R1}[1]
++
++	vmlal.u32	$D0,$R3,${S2}[1]
++	vmlal.u32	$D1,$R4,${S2}[1]
++	vmlal.u32	$D3,$R1,${R2}[1]
++	vmlal.u32	$D2,$R0,${R2}[1]
++	vmlal.u32	$D4,$R2,${R2}[1]
++
++	vmlal.u32	$D0,$R2,${S3}[1]
++	vmlal.u32	$D3,$R0,${R3}[1]
++	vmlal.u32	$D1,$R3,${S3}[1]
++	vmlal.u32	$D2,$R4,${S3}[1]
++	vmlal.u32	$D4,$R1,${R3}[1]
++
++	vmlal.u32	$D3,$R4,${S4}[1]
++	vmlal.u32	$D0,$R1,${S4}[1]
++	vmlal.u32	$D1,$R2,${S4}[1]
++	vmlal.u32	$D2,$R3,${S4}[1]
++	vmlal.u32	$D4,$R0,${R4}[1]
++
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ lazy reduction as discussed in "NEON crypto" by D.J. Bernstein
++	@ and P. Schwabe
++	@
++	@ H0>>+H1>>+H2>>+H3>>+H4
++	@ H3>>+H4>>*5+H0>>+H1
++	@
++	@ Trivia.
++	@
++	@ Result of multiplication of n-bit number by m-bit number is
++	@ n+m bits wide. However! Even though 2^n is a n+1-bit number,
++	@ m-bit number multiplied by 2^n is still n+m bits wide.
++	@
++	@ Sum of two n-bit numbers is n+1 bits wide, sum of three - n+2,
++	@ and so is sum of four. Sum of 2^m n-m-bit numbers and n-bit
++	@ one is n+1 bits wide.
++	@
++	@ >>+ denotes Hnext += Hn>>26, Hn &= 0x3ffffff. This means that
++	@ H0, H2, H3 are guaranteed to be 26 bits wide, while H1 and H4
++	@ can be 27. However! In cases when their width exceeds 26 bits
++	@ they are limited by 2^26+2^6. This in turn means that *sum*
++	@ of the products with these values can still be viewed as sum
++	@ of 52-bit numbers as long as the amount of addends is not a
++	@ power of 2. For example,
++	@
++	@ H4 = H4*R0 + H3*R1 + H2*R2 + H1*R3 + H0 * R4,
++	@
++	@ which can't be larger than 5 * (2^26 + 2^6) * (2^26 + 2^6), or
++	@ 5 * (2^52 + 2*2^32 + 2^12), which in turn is smaller than
++	@ 8 * (2^52) or 2^55. However, the value is then multiplied by
++	@ by 5, so we should be looking at 5 * 5 * (2^52 + 2^33 + 2^12),
++	@ which is less than 32 * (2^52) or 2^57. And when processing
++	@ data we are looking at triple as many addends...
++	@
++	@ In key setup procedure pre-reduced H0 is limited by 5*4+1 and
++	@ 5*H4 - by 5*5 52-bit addends, or 57 bits. But when hashing the
++	@ input H0 is limited by (5*4+1)*3 addends, or 58 bits, while
++	@ 5*H4 by 5*5*3, or 59[!] bits. How is this relevant? vmlal.u32
++	@ instruction accepts 2x32-bit input and writes 2x64-bit result.
++	@ This means that result of reduction have to be compressed upon
++	@ loop wrap-around. This can be done in the process of reduction
++	@ to minimize amount of instructions [as well as amount of
++	@ 128-bit instructions, which benefits low-end processors], but
++	@ one has to watch for H2 (which is narrower than H0) and 5*H4
++	@ not being wider than 58 bits, so that result of right shift
++	@ by 26 bits fits in 32 bits. This is also useful on x86,
++	@ because it allows to use paddd in place for paddq, which
++	@ benefits Atom, where paddq is ridiculously slow.
++
++	vshr.u64	$T0,$D3,#26
++	vmovn.i64	$D3#lo,$D3
++	 vshr.u64	$T1,$D0,#26
++	 vmovn.i64	$D0#lo,$D0
++	vadd.i64	$D4,$D4,$T0		@ h3 -> h4
++	vbic.i32	$D3#lo,#0xfc000000	@ &=0x03ffffff
++	 vadd.i64	$D1,$D1,$T1		@ h0 -> h1
++	 vbic.i32	$D0#lo,#0xfc000000
++
++	vshrn.u64	$T0#lo,$D4,#26
++	vmovn.i64	$D4#lo,$D4
++	 vshr.u64	$T1,$D1,#26
++	 vmovn.i64	$D1#lo,$D1
++	 vadd.i64	$D2,$D2,$T1		@ h1 -> h2
++	vbic.i32	$D4#lo,#0xfc000000
++	 vbic.i32	$D1#lo,#0xfc000000
++
++	vadd.i32	$D0#lo,$D0#lo,$T0#lo
++	vshl.u32	$T0#lo,$T0#lo,#2
++	 vshrn.u64	$T1#lo,$D2,#26
++	 vmovn.i64	$D2#lo,$D2
++	vadd.i32	$D0#lo,$D0#lo,$T0#lo	@ h4 -> h0
++	 vadd.i32	$D3#lo,$D3#lo,$T1#lo	@ h2 -> h3
++	 vbic.i32	$D2#lo,#0xfc000000
++
++	vshr.u32	$T0#lo,$D0#lo,#26
++	vbic.i32	$D0#lo,#0xfc000000
++	 vshr.u32	$T1#lo,$D3#lo,#26
++	 vbic.i32	$D3#lo,#0xfc000000
++	vadd.i32	$D1#lo,$D1#lo,$T0#lo	@ h0 -> h1
++	 vadd.i32	$D4#lo,$D4#lo,$T1#lo	@ h3 -> h4
++
++	subs		$zeros,$zeros,#1
++	beq		.Lsquare_break_neon
++
++	add		$tbl0,$ctx,#(48+0*9*4)
++	add		$tbl1,$ctx,#(48+1*9*4)
++
++	vtrn.32		$R0,$D0#lo		@ r^2:r^1
++	vtrn.32		$R2,$D2#lo
++	vtrn.32		$R3,$D3#lo
++	vtrn.32		$R1,$D1#lo
++	vtrn.32		$R4,$D4#lo
++
++	vshl.u32	$S2,$R2,#2		@ *5
++	vshl.u32	$S3,$R3,#2
++	vshl.u32	$S1,$R1,#2
++	vshl.u32	$S4,$R4,#2
++	vadd.i32	$S2,$S2,$R2
++	vadd.i32	$S1,$S1,$R1
++	vadd.i32	$S3,$S3,$R3
++	vadd.i32	$S4,$S4,$R4
++
++	vst4.32		{${R0}[0],${R1}[0],${S1}[0],${R2}[0]},[$tbl0]!
++	vst4.32		{${R0}[1],${R1}[1],${S1}[1],${R2}[1]},[$tbl1]!
++	vst4.32		{${S2}[0],${R3}[0],${S3}[0],${R4}[0]},[$tbl0]!
++	vst4.32		{${S2}[1],${R3}[1],${S3}[1],${R4}[1]},[$tbl1]!
++	vst1.32		{${S4}[0]},[$tbl0,:32]
++	vst1.32		{${S4}[1]},[$tbl1,:32]
++
++	b		.Lsquare_neon
++
++.align	4
++.Lsquare_break_neon:
++	add		$tbl0,$ctx,#(48+2*4*9)
++	add		$tbl1,$ctx,#(48+3*4*9)
++
++	vmov		$R0,$D0#lo		@ r^4:r^3
++	vshl.u32	$S1,$D1#lo,#2		@ *5
++	vmov		$R1,$D1#lo
++	vshl.u32	$S2,$D2#lo,#2
++	vmov		$R2,$D2#lo
++	vshl.u32	$S3,$D3#lo,#2
++	vmov		$R3,$D3#lo
++	vshl.u32	$S4,$D4#lo,#2
++	vmov		$R4,$D4#lo
++	vadd.i32	$S1,$S1,$D1#lo
++	vadd.i32	$S2,$S2,$D2#lo
++	vadd.i32	$S3,$S3,$D3#lo
++	vadd.i32	$S4,$S4,$D4#lo
++
++	vst4.32		{${R0}[0],${R1}[0],${S1}[0],${R2}[0]},[$tbl0]!
++	vst4.32		{${R0}[1],${R1}[1],${S1}[1],${R2}[1]},[$tbl1]!
++	vst4.32		{${S2}[0],${R3}[0],${S3}[0],${R4}[0]},[$tbl0]!
++	vst4.32		{${S2}[1],${R3}[1],${S3}[1],${R4}[1]},[$tbl1]!
++	vst1.32		{${S4}[0]},[$tbl0]
++	vst1.32		{${S4}[1]},[$tbl1]
++
++.Lno_init_neon:
++	ret				@ bx	lr
++.size	poly1305_init_neon,.-poly1305_init_neon
++
++.type	poly1305_blocks_neon,%function
++.align	5
++poly1305_blocks_neon:
++.Lpoly1305_blocks_neon:
++	ldr	ip,[$ctx,#36]		@ is_base2_26
++
++	cmp	$len,#64
++	blo	.Lpoly1305_blocks
++
++	stmdb	sp!,{r4-r7}
++	vstmdb	sp!,{d8-d15}		@ ABI specification says so
++
++	tst	ip,ip			@ is_base2_26?
++	bne	.Lbase2_26_neon
++
++	stmdb	sp!,{r1-r3,lr}
++	bl	.Lpoly1305_init_neon
++
++	ldr	r4,[$ctx,#0]		@ load hash value base 2^32
++	ldr	r5,[$ctx,#4]
++	ldr	r6,[$ctx,#8]
++	ldr	r7,[$ctx,#12]
++	ldr	ip,[$ctx,#16]
++
++	and	r2,r4,#0x03ffffff	@ base 2^32 -> base 2^26
++	mov	r3,r4,lsr#26
++	 veor	$D0#lo,$D0#lo,$D0#lo
++	mov	r4,r5,lsr#20
++	orr	r3,r3,r5,lsl#6
++	 veor	$D1#lo,$D1#lo,$D1#lo
++	mov	r5,r6,lsr#14
++	orr	r4,r4,r6,lsl#12
++	 veor	$D2#lo,$D2#lo,$D2#lo
++	mov	r6,r7,lsr#8
++	orr	r5,r5,r7,lsl#18
++	 veor	$D3#lo,$D3#lo,$D3#lo
++	and	r3,r3,#0x03ffffff
++	orr	r6,r6,ip,lsl#24
++	 veor	$D4#lo,$D4#lo,$D4#lo
++	and	r4,r4,#0x03ffffff
++	mov	r1,#1
++	and	r5,r5,#0x03ffffff
++	str	r1,[$ctx,#36]		@ set is_base2_26
++
++	vmov.32	$D0#lo[0],r2
++	vmov.32	$D1#lo[0],r3
++	vmov.32	$D2#lo[0],r4
++	vmov.32	$D3#lo[0],r5
++	vmov.32	$D4#lo[0],r6
++	adr	$zeros,.Lzeros
++
++	ldmia	sp!,{r1-r3,lr}
++	b	.Lhash_loaded
++
++.align	4
++.Lbase2_26_neon:
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ load hash value
++
++	veor		$D0#lo,$D0#lo,$D0#lo
++	veor		$D1#lo,$D1#lo,$D1#lo
++	veor		$D2#lo,$D2#lo,$D2#lo
++	veor		$D3#lo,$D3#lo,$D3#lo
++	veor		$D4#lo,$D4#lo,$D4#lo
++	vld4.32		{$D0#lo[0],$D1#lo[0],$D2#lo[0],$D3#lo[0]},[$ctx]!
++	adr		$zeros,.Lzeros
++	vld1.32		{$D4#lo[0]},[$ctx]
++	sub		$ctx,$ctx,#16		@ rewind
++
++.Lhash_loaded:
++	add		$in2,$inp,#32
++	mov		$padbit,$padbit,lsl#24
++	tst		$len,#31
++	beq		.Leven
++
++	vld4.32		{$H0#lo[0],$H1#lo[0],$H2#lo[0],$H3#lo[0]},[$inp]!
++	vmov.32		$H4#lo[0],$padbit
++	sub		$len,$len,#16
++	add		$in2,$inp,#32
++
++# ifdef	__ARMEB__
++	vrev32.8	$H0,$H0
++	vrev32.8	$H3,$H3
++	vrev32.8	$H1,$H1
++	vrev32.8	$H2,$H2
++# endif
++	vsri.u32	$H4#lo,$H3#lo,#8	@ base 2^32 -> base 2^26
++	vshl.u32	$H3#lo,$H3#lo,#18
++
++	vsri.u32	$H3#lo,$H2#lo,#14
++	vshl.u32	$H2#lo,$H2#lo,#12
++	vadd.i32	$H4#hi,$H4#lo,$D4#lo	@ add hash value and move to #hi
++
++	vbic.i32	$H3#lo,#0xfc000000
++	vsri.u32	$H2#lo,$H1#lo,#20
++	vshl.u32	$H1#lo,$H1#lo,#6
++
++	vbic.i32	$H2#lo,#0xfc000000
++	vsri.u32	$H1#lo,$H0#lo,#26
++	vadd.i32	$H3#hi,$H3#lo,$D3#lo
++
++	vbic.i32	$H0#lo,#0xfc000000
++	vbic.i32	$H1#lo,#0xfc000000
++	vadd.i32	$H2#hi,$H2#lo,$D2#lo
++
++	vadd.i32	$H0#hi,$H0#lo,$D0#lo
++	vadd.i32	$H1#hi,$H1#lo,$D1#lo
++
++	mov		$tbl1,$zeros
++	add		$tbl0,$ctx,#48
++
++	cmp		$len,$len
++	b		.Long_tail
++
++.align	4
++.Leven:
++	subs		$len,$len,#64
++	it		lo
++	movlo		$in2,$zeros
++
++	vmov.i32	$H4,#1<<24		@ padbit, yes, always
++	vld4.32		{$H0#lo,$H1#lo,$H2#lo,$H3#lo},[$inp]	@ inp[0:1]
++	add		$inp,$inp,#64
++	vld4.32		{$H0#hi,$H1#hi,$H2#hi,$H3#hi},[$in2]	@ inp[2:3] (or 0)
++	add		$in2,$in2,#64
++	itt		hi
++	addhi		$tbl1,$ctx,#(48+1*9*4)
++	addhi		$tbl0,$ctx,#(48+3*9*4)
++
++# ifdef	__ARMEB__
++	vrev32.8	$H0,$H0
++	vrev32.8	$H3,$H3
++	vrev32.8	$H1,$H1
++	vrev32.8	$H2,$H2
++# endif
++	vsri.u32	$H4,$H3,#8		@ base 2^32 -> base 2^26
++	vshl.u32	$H3,$H3,#18
++
++	vsri.u32	$H3,$H2,#14
++	vshl.u32	$H2,$H2,#12
++
++	vbic.i32	$H3,#0xfc000000
++	vsri.u32	$H2,$H1,#20
++	vshl.u32	$H1,$H1,#6
++
++	vbic.i32	$H2,#0xfc000000
++	vsri.u32	$H1,$H0,#26
++
++	vbic.i32	$H0,#0xfc000000
++	vbic.i32	$H1,#0xfc000000
++
++	bls		.Lskip_loop
++
++	vld4.32		{${R0}[1],${R1}[1],${S1}[1],${R2}[1]},[$tbl1]!	@ load r^2
++	vld4.32		{${R0}[0],${R1}[0],${S1}[0],${R2}[0]},[$tbl0]!	@ load r^4
++	vld4.32		{${S2}[1],${R3}[1],${S3}[1],${R4}[1]},[$tbl1]!
++	vld4.32		{${S2}[0],${R3}[0],${S3}[0],${R4}[0]},[$tbl0]!
++	b		.Loop_neon
++
++.align	5
++.Loop_neon:
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2
++	@ ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r
++	@   \___________________/
++	@ ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2
++	@ ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r
++	@   \___________________/ \____________________/
++	@
++	@ Note that we start with inp[2:3]*r^2. This is because it
++	@ doesn't depend on reduction in previous iteration.
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
++	@ d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
++	@ d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
++	@ d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
++	@ d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
++
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ inp[2:3]*r^2
++
++	vadd.i32	$H2#lo,$H2#lo,$D2#lo	@ accumulate inp[0:1]
++	vmull.u32	$D2,$H2#hi,${R0}[1]
++	vadd.i32	$H0#lo,$H0#lo,$D0#lo
++	vmull.u32	$D0,$H0#hi,${R0}[1]
++	vadd.i32	$H3#lo,$H3#lo,$D3#lo
++	vmull.u32	$D3,$H3#hi,${R0}[1]
++	vmlal.u32	$D2,$H1#hi,${R1}[1]
++	vadd.i32	$H1#lo,$H1#lo,$D1#lo
++	vmull.u32	$D1,$H1#hi,${R0}[1]
++
++	vadd.i32	$H4#lo,$H4#lo,$D4#lo
++	vmull.u32	$D4,$H4#hi,${R0}[1]
++	subs		$len,$len,#64
++	vmlal.u32	$D0,$H4#hi,${S1}[1]
++	it		lo
++	movlo		$in2,$zeros
++	vmlal.u32	$D3,$H2#hi,${R1}[1]
++	vld1.32		${S4}[1],[$tbl1,:32]
++	vmlal.u32	$D1,$H0#hi,${R1}[1]
++	vmlal.u32	$D4,$H3#hi,${R1}[1]
++
++	vmlal.u32	$D0,$H3#hi,${S2}[1]
++	vmlal.u32	$D3,$H1#hi,${R2}[1]
++	vmlal.u32	$D4,$H2#hi,${R2}[1]
++	vmlal.u32	$D1,$H4#hi,${S2}[1]
++	vmlal.u32	$D2,$H0#hi,${R2}[1]
++
++	vmlal.u32	$D3,$H0#hi,${R3}[1]
++	vmlal.u32	$D0,$H2#hi,${S3}[1]
++	vmlal.u32	$D4,$H1#hi,${R3}[1]
++	vmlal.u32	$D1,$H3#hi,${S3}[1]
++	vmlal.u32	$D2,$H4#hi,${S3}[1]
++
++	vmlal.u32	$D3,$H4#hi,${S4}[1]
++	vmlal.u32	$D0,$H1#hi,${S4}[1]
++	vmlal.u32	$D4,$H0#hi,${R4}[1]
++	vmlal.u32	$D1,$H2#hi,${S4}[1]
++	vmlal.u32	$D2,$H3#hi,${S4}[1]
++
++	vld4.32		{$H0#hi,$H1#hi,$H2#hi,$H3#hi},[$in2]	@ inp[2:3] (or 0)
++	add		$in2,$in2,#64
++
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ (hash+inp[0:1])*r^4 and accumulate
++
++	vmlal.u32	$D3,$H3#lo,${R0}[0]
++	vmlal.u32	$D0,$H0#lo,${R0}[0]
++	vmlal.u32	$D4,$H4#lo,${R0}[0]
++	vmlal.u32	$D1,$H1#lo,${R0}[0]
++	vmlal.u32	$D2,$H2#lo,${R0}[0]
++	vld1.32		${S4}[0],[$tbl0,:32]
++
++	vmlal.u32	$D3,$H2#lo,${R1}[0]
++	vmlal.u32	$D0,$H4#lo,${S1}[0]
++	vmlal.u32	$D4,$H3#lo,${R1}[0]
++	vmlal.u32	$D1,$H0#lo,${R1}[0]
++	vmlal.u32	$D2,$H1#lo,${R1}[0]
++
++	vmlal.u32	$D3,$H1#lo,${R2}[0]
++	vmlal.u32	$D0,$H3#lo,${S2}[0]
++	vmlal.u32	$D4,$H2#lo,${R2}[0]
++	vmlal.u32	$D1,$H4#lo,${S2}[0]
++	vmlal.u32	$D2,$H0#lo,${R2}[0]
++
++	vmlal.u32	$D3,$H0#lo,${R3}[0]
++	vmlal.u32	$D0,$H2#lo,${S3}[0]
++	vmlal.u32	$D4,$H1#lo,${R3}[0]
++	vmlal.u32	$D1,$H3#lo,${S3}[0]
++	vmlal.u32	$D3,$H4#lo,${S4}[0]
++
++	vmlal.u32	$D2,$H4#lo,${S3}[0]
++	vmlal.u32	$D0,$H1#lo,${S4}[0]
++	vmlal.u32	$D4,$H0#lo,${R4}[0]
++	vmov.i32	$H4,#1<<24		@ padbit, yes, always
++	vmlal.u32	$D1,$H2#lo,${S4}[0]
++	vmlal.u32	$D2,$H3#lo,${S4}[0]
++
++	vld4.32		{$H0#lo,$H1#lo,$H2#lo,$H3#lo},[$inp]	@ inp[0:1]
++	add		$inp,$inp,#64
++# ifdef	__ARMEB__
++	vrev32.8	$H0,$H0
++	vrev32.8	$H1,$H1
++	vrev32.8	$H2,$H2
++	vrev32.8	$H3,$H3
++# endif
++
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ lazy reduction interleaved with base 2^32 -> base 2^26 of
++	@ inp[0:3] previously loaded to $H0-$H3 and smashed to $H0-$H4.
++
++	vshr.u64	$T0,$D3,#26
++	vmovn.i64	$D3#lo,$D3
++	 vshr.u64	$T1,$D0,#26
++	 vmovn.i64	$D0#lo,$D0
++	vadd.i64	$D4,$D4,$T0		@ h3 -> h4
++	vbic.i32	$D3#lo,#0xfc000000
++	  vsri.u32	$H4,$H3,#8		@ base 2^32 -> base 2^26
++	 vadd.i64	$D1,$D1,$T1		@ h0 -> h1
++	  vshl.u32	$H3,$H3,#18
++	 vbic.i32	$D0#lo,#0xfc000000
++
++	vshrn.u64	$T0#lo,$D4,#26
++	vmovn.i64	$D4#lo,$D4
++	 vshr.u64	$T1,$D1,#26
++	 vmovn.i64	$D1#lo,$D1
++	 vadd.i64	$D2,$D2,$T1		@ h1 -> h2
++	  vsri.u32	$H3,$H2,#14
++	vbic.i32	$D4#lo,#0xfc000000
++	  vshl.u32	$H2,$H2,#12
++	 vbic.i32	$D1#lo,#0xfc000000
++
++	vadd.i32	$D0#lo,$D0#lo,$T0#lo
++	vshl.u32	$T0#lo,$T0#lo,#2
++	  vbic.i32	$H3,#0xfc000000
++	 vshrn.u64	$T1#lo,$D2,#26
++	 vmovn.i64	$D2#lo,$D2
++	vaddl.u32	$D0,$D0#lo,$T0#lo	@ h4 -> h0 [widen for a sec]
++	  vsri.u32	$H2,$H1,#20
++	 vadd.i32	$D3#lo,$D3#lo,$T1#lo	@ h2 -> h3
++	  vshl.u32	$H1,$H1,#6
++	 vbic.i32	$D2#lo,#0xfc000000
++	  vbic.i32	$H2,#0xfc000000
++
++	vshrn.u64	$T0#lo,$D0,#26		@ re-narrow
++	vmovn.i64	$D0#lo,$D0
++	  vsri.u32	$H1,$H0,#26
++	  vbic.i32	$H0,#0xfc000000
++	 vshr.u32	$T1#lo,$D3#lo,#26
++	 vbic.i32	$D3#lo,#0xfc000000
++	vbic.i32	$D0#lo,#0xfc000000
++	vadd.i32	$D1#lo,$D1#lo,$T0#lo	@ h0 -> h1
++	 vadd.i32	$D4#lo,$D4#lo,$T1#lo	@ h3 -> h4
++	  vbic.i32	$H1,#0xfc000000
++
++	bhi		.Loop_neon
++
++.Lskip_loop:
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1
++
++	add		$tbl1,$ctx,#(48+0*9*4)
++	add		$tbl0,$ctx,#(48+1*9*4)
++	adds		$len,$len,#32
++	it		ne
++	movne		$len,#0
++	bne		.Long_tail
++
++	vadd.i32	$H2#hi,$H2#lo,$D2#lo	@ add hash value and move to #hi
++	vadd.i32	$H0#hi,$H0#lo,$D0#lo
++	vadd.i32	$H3#hi,$H3#lo,$D3#lo
++	vadd.i32	$H1#hi,$H1#lo,$D1#lo
++	vadd.i32	$H4#hi,$H4#lo,$D4#lo
++
++.Long_tail:
++	vld4.32		{${R0}[1],${R1}[1],${S1}[1],${R2}[1]},[$tbl1]!	@ load r^1
++	vld4.32		{${R0}[0],${R1}[0],${S1}[0],${R2}[0]},[$tbl0]!	@ load r^2
++
++	vadd.i32	$H2#lo,$H2#lo,$D2#lo	@ can be redundant
++	vmull.u32	$D2,$H2#hi,$R0
++	vadd.i32	$H0#lo,$H0#lo,$D0#lo
++	vmull.u32	$D0,$H0#hi,$R0
++	vadd.i32	$H3#lo,$H3#lo,$D3#lo
++	vmull.u32	$D3,$H3#hi,$R0
++	vadd.i32	$H1#lo,$H1#lo,$D1#lo
++	vmull.u32	$D1,$H1#hi,$R0
++	vadd.i32	$H4#lo,$H4#lo,$D4#lo
++	vmull.u32	$D4,$H4#hi,$R0
++
++	vmlal.u32	$D0,$H4#hi,$S1
++	vld4.32		{${S2}[1],${R3}[1],${S3}[1],${R4}[1]},[$tbl1]!
++	vmlal.u32	$D3,$H2#hi,$R1
++	vld4.32		{${S2}[0],${R3}[0],${S3}[0],${R4}[0]},[$tbl0]!
++	vmlal.u32	$D1,$H0#hi,$R1
++	vmlal.u32	$D4,$H3#hi,$R1
++	vmlal.u32	$D2,$H1#hi,$R1
++
++	vmlal.u32	$D3,$H1#hi,$R2
++	vld1.32		${S4}[1],[$tbl1,:32]
++	vmlal.u32	$D0,$H3#hi,$S2
++	vld1.32		${S4}[0],[$tbl0,:32]
++	vmlal.u32	$D4,$H2#hi,$R2
++	vmlal.u32	$D1,$H4#hi,$S2
++	vmlal.u32	$D2,$H0#hi,$R2
++
++	vmlal.u32	$D3,$H0#hi,$R3
++	 it		ne
++	 addne		$tbl1,$ctx,#(48+2*9*4)
++	vmlal.u32	$D0,$H2#hi,$S3
++	 it		ne
++	 addne		$tbl0,$ctx,#(48+3*9*4)
++	vmlal.u32	$D4,$H1#hi,$R3
++	vmlal.u32	$D1,$H3#hi,$S3
++	vmlal.u32	$D2,$H4#hi,$S3
++
++	vmlal.u32	$D3,$H4#hi,$S4
++	 vorn		$MASK,$MASK,$MASK	@ all-ones, can be redundant
++	vmlal.u32	$D0,$H1#hi,$S4
++	 vshr.u64	$MASK,$MASK,#38
++	vmlal.u32	$D4,$H0#hi,$R4
++	vmlal.u32	$D1,$H2#hi,$S4
++	vmlal.u32	$D2,$H3#hi,$S4
++
++	beq		.Lshort_tail
++
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ (hash+inp[0:1])*r^4:r^3 and accumulate
++
++	vld4.32		{${R0}[1],${R1}[1],${S1}[1],${R2}[1]},[$tbl1]!	@ load r^3
++	vld4.32		{${R0}[0],${R1}[0],${S1}[0],${R2}[0]},[$tbl0]!	@ load r^4
++
++	vmlal.u32	$D2,$H2#lo,$R0
++	vmlal.u32	$D0,$H0#lo,$R0
++	vmlal.u32	$D3,$H3#lo,$R0
++	vmlal.u32	$D1,$H1#lo,$R0
++	vmlal.u32	$D4,$H4#lo,$R0
++
++	vmlal.u32	$D0,$H4#lo,$S1
++	vld4.32		{${S2}[1],${R3}[1],${S3}[1],${R4}[1]},[$tbl1]!
++	vmlal.u32	$D3,$H2#lo,$R1
++	vld4.32		{${S2}[0],${R3}[0],${S3}[0],${R4}[0]},[$tbl0]!
++	vmlal.u32	$D1,$H0#lo,$R1
++	vmlal.u32	$D4,$H3#lo,$R1
++	vmlal.u32	$D2,$H1#lo,$R1
++
++	vmlal.u32	$D3,$H1#lo,$R2
++	vld1.32		${S4}[1],[$tbl1,:32]
++	vmlal.u32	$D0,$H3#lo,$S2
++	vld1.32		${S4}[0],[$tbl0,:32]
++	vmlal.u32	$D4,$H2#lo,$R2
++	vmlal.u32	$D1,$H4#lo,$S2
++	vmlal.u32	$D2,$H0#lo,$R2
++
++	vmlal.u32	$D3,$H0#lo,$R3
++	vmlal.u32	$D0,$H2#lo,$S3
++	vmlal.u32	$D4,$H1#lo,$R3
++	vmlal.u32	$D1,$H3#lo,$S3
++	vmlal.u32	$D2,$H4#lo,$S3
++
++	vmlal.u32	$D3,$H4#lo,$S4
++	 vorn		$MASK,$MASK,$MASK	@ all-ones
++	vmlal.u32	$D0,$H1#lo,$S4
++	 vshr.u64	$MASK,$MASK,#38
++	vmlal.u32	$D4,$H0#lo,$R4
++	vmlal.u32	$D1,$H2#lo,$S4
++	vmlal.u32	$D2,$H3#lo,$S4
++
++.Lshort_tail:
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ horizontal addition
++
++	vadd.i64	$D3#lo,$D3#lo,$D3#hi
++	vadd.i64	$D0#lo,$D0#lo,$D0#hi
++	vadd.i64	$D4#lo,$D4#lo,$D4#hi
++	vadd.i64	$D1#lo,$D1#lo,$D1#hi
++	vadd.i64	$D2#lo,$D2#lo,$D2#hi
++
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ lazy reduction, but without narrowing
++
++	vshr.u64	$T0,$D3,#26
++	vand.i64	$D3,$D3,$MASK
++	 vshr.u64	$T1,$D0,#26
++	 vand.i64	$D0,$D0,$MASK
++	vadd.i64	$D4,$D4,$T0		@ h3 -> h4
++	 vadd.i64	$D1,$D1,$T1		@ h0 -> h1
++
++	vshr.u64	$T0,$D4,#26
++	vand.i64	$D4,$D4,$MASK
++	 vshr.u64	$T1,$D1,#26
++	 vand.i64	$D1,$D1,$MASK
++	 vadd.i64	$D2,$D2,$T1		@ h1 -> h2
++
++	vadd.i64	$D0,$D0,$T0
++	vshl.u64	$T0,$T0,#2
++	 vshr.u64	$T1,$D2,#26
++	 vand.i64	$D2,$D2,$MASK
++	vadd.i64	$D0,$D0,$T0		@ h4 -> h0
++	 vadd.i64	$D3,$D3,$T1		@ h2 -> h3
++
++	vshr.u64	$T0,$D0,#26
++	vand.i64	$D0,$D0,$MASK
++	 vshr.u64	$T1,$D3,#26
++	 vand.i64	$D3,$D3,$MASK
++	vadd.i64	$D1,$D1,$T0		@ h0 -> h1
++	 vadd.i64	$D4,$D4,$T1		@ h3 -> h4
++
++	cmp		$len,#0
++	bne		.Leven
++
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ store hash value
++
++	vst4.32		{$D0#lo[0],$D1#lo[0],$D2#lo[0],$D3#lo[0]},[$ctx]!
++	vst1.32		{$D4#lo[0]},[$ctx]
++
++	vldmia	sp!,{d8-d15}			@ epilogue
++	ldmia	sp!,{r4-r7}
++	ret					@ bx	lr
++.size	poly1305_blocks_neon,.-poly1305_blocks_neon
++
++.align	5
++.Lzeros:
++.long	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
++#ifndef	__KERNEL__
++.LOPENSSL_armcap:
++# ifdef	_WIN32
++.word	OPENSSL_armcap_P
++# else
++.word	OPENSSL_armcap_P-.Lpoly1305_init
++# endif
++.comm	OPENSSL_armcap_P,4,4
++.hidden	OPENSSL_armcap_P
++#endif
++#endif
++___
++}	}
++$code.=<<___;
++.asciz	"Poly1305 for ARMv4/NEON, CRYPTOGAMS by \@dot-asm"
++.align	2
++___
++
++foreach (split("\n",$code)) {
++	s/\`([^\`]*)\`/eval $1/geo;
++
++	s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo	or
++	s/\bret\b/bx	lr/go						or
++	s/\bbx\s+lr\b/.word\t0xe12fff1e/go;	# make it possible to compile with -march=armv4
++
++	print $_,"\n";
++}
++close STDOUT; # enforce flush
+--- /dev/null
++++ b/arch/arm/crypto/poly1305-core.S_shipped
+@@ -0,0 +1,1158 @@
++#ifndef	__KERNEL__
++# include "arm_arch.h"
++#else
++# define __ARM_ARCH__ __LINUX_ARM_ARCH__
++# define __ARM_MAX_ARCH__ __LINUX_ARM_ARCH__
++# define poly1305_init   poly1305_init_arm
++# define poly1305_blocks poly1305_blocks_arm
++# define poly1305_emit   poly1305_emit_arm
++.globl	poly1305_blocks_neon
++#endif
++
++#if defined(__thumb2__)
++.syntax	unified
++.thumb
++#else
++.code	32
++#endif
++
++.text
++
++.globl	poly1305_emit
++.globl	poly1305_blocks
++.globl	poly1305_init
++.type	poly1305_init,%function
++.align	5
++poly1305_init:
++.Lpoly1305_init:
++	stmdb	sp!,{r4-r11}
++
++	eor	r3,r3,r3
++	cmp	r1,#0
++	str	r3,[r0,#0]		@ zero hash value
++	str	r3,[r0,#4]
++	str	r3,[r0,#8]
++	str	r3,[r0,#12]
++	str	r3,[r0,#16]
++	str	r3,[r0,#36]		@ clear is_base2_26
++	add	r0,r0,#20
++
++#ifdef	__thumb2__
++	it	eq
++#endif
++	moveq	r0,#0
++	beq	.Lno_key
++
++#if	__ARM_MAX_ARCH__>=7
++	mov	r3,#-1
++	str	r3,[r0,#28]		@ impossible key power value
++# ifndef __KERNEL__
++	adr	r11,.Lpoly1305_init
++	ldr	r12,.LOPENSSL_armcap
++# endif
++#endif
++	ldrb	r4,[r1,#0]
++	mov	r10,#0x0fffffff
++	ldrb	r5,[r1,#1]
++	and	r3,r10,#-4		@ 0x0ffffffc
++	ldrb	r6,[r1,#2]
++	ldrb	r7,[r1,#3]
++	orr	r4,r4,r5,lsl#8
++	ldrb	r5,[r1,#4]
++	orr	r4,r4,r6,lsl#16
++	ldrb	r6,[r1,#5]
++	orr	r4,r4,r7,lsl#24
++	ldrb	r7,[r1,#6]
++	and	r4,r4,r10
++
++#if	__ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
++# if !defined(_WIN32)
++	ldr	r12,[r11,r12]		@ OPENSSL_armcap_P
++# endif
++# if defined(__APPLE__) || defined(_WIN32)
++	ldr	r12,[r12]
++# endif
++#endif
++	ldrb	r8,[r1,#7]
++	orr	r5,r5,r6,lsl#8
++	ldrb	r6,[r1,#8]
++	orr	r5,r5,r7,lsl#16
++	ldrb	r7,[r1,#9]
++	orr	r5,r5,r8,lsl#24
++	ldrb	r8,[r1,#10]
++	and	r5,r5,r3
++
++#if	__ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
++	tst	r12,#ARMV7_NEON		@ check for NEON
++# ifdef	__thumb2__
++	adr	r9,.Lpoly1305_blocks_neon
++	adr	r11,.Lpoly1305_blocks
++	it	ne
++	movne	r11,r9
++	adr	r12,.Lpoly1305_emit
++	orr	r11,r11,#1		@ thumb-ify addresses
++	orr	r12,r12,#1
++# else
++	add	r12,r11,#(.Lpoly1305_emit-.Lpoly1305_init)
++	ite	eq
++	addeq	r11,r11,#(.Lpoly1305_blocks-.Lpoly1305_init)
++	addne	r11,r11,#(.Lpoly1305_blocks_neon-.Lpoly1305_init)
++# endif
++#endif
++	ldrb	r9,[r1,#11]
++	orr	r6,r6,r7,lsl#8
++	ldrb	r7,[r1,#12]
++	orr	r6,r6,r8,lsl#16
++	ldrb	r8,[r1,#13]
++	orr	r6,r6,r9,lsl#24
++	ldrb	r9,[r1,#14]
++	and	r6,r6,r3
++
++	ldrb	r10,[r1,#15]
++	orr	r7,r7,r8,lsl#8
++	str	r4,[r0,#0]
++	orr	r7,r7,r9,lsl#16
++	str	r5,[r0,#4]
++	orr	r7,r7,r10,lsl#24
++	str	r6,[r0,#8]
++	and	r7,r7,r3
++	str	r7,[r0,#12]
++#if	__ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
++	stmia	r2,{r11,r12}		@ fill functions table
++	mov	r0,#1
++#else
++	mov	r0,#0
++#endif
++.Lno_key:
++	ldmia	sp!,{r4-r11}
++#if	__ARM_ARCH__>=5
++	bx	lr				@ bx	lr
++#else
++	tst	lr,#1
++	moveq	pc,lr			@ be binary compatible with V4, yet
++	.word	0xe12fff1e			@ interoperable with Thumb ISA:-)
++#endif
++.size	poly1305_init,.-poly1305_init
++.type	poly1305_blocks,%function
++.align	5
++poly1305_blocks:
++.Lpoly1305_blocks:
++	stmdb	sp!,{r3-r11,lr}
++
++	ands	r2,r2,#-16
++	beq	.Lno_data
++
++	add	r2,r2,r1		@ end pointer
++	sub	sp,sp,#32
++
++#if __ARM_ARCH__<7
++	ldmia	r0,{r4-r12}		@ load context
++	add	r0,r0,#20
++	str	r2,[sp,#16]		@ offload stuff
++	str	r0,[sp,#12]
++#else
++	ldr	lr,[r0,#36]		@ is_base2_26
++	ldmia	r0!,{r4-r8}		@ load hash value
++	str	r2,[sp,#16]		@ offload stuff
++	str	r0,[sp,#12]
++
++	adds	r9,r4,r5,lsl#26	@ base 2^26 -> base 2^32
++	mov	r10,r5,lsr#6
++	adcs	r10,r10,r6,lsl#20
++	mov	r11,r6,lsr#12
++	adcs	r11,r11,r7,lsl#14
++	mov	r12,r7,lsr#18
++	adcs	r12,r12,r8,lsl#8
++	mov	r2,#0
++	teq	lr,#0
++	str	r2,[r0,#16]		@ clear is_base2_26
++	adc	r2,r2,r8,lsr#24
++
++	itttt	ne
++	movne	r4,r9			@ choose between radixes
++	movne	r5,r10
++	movne	r6,r11
++	movne	r7,r12
++	ldmia	r0,{r9-r12}		@ load key
++	it	ne
++	movne	r8,r2
++#endif
++
++	mov	lr,r1
++	cmp	r3,#0
++	str	r10,[sp,#20]
++	str	r11,[sp,#24]
++	str	r12,[sp,#28]
++	b	.Loop
++
++.align	4
++.Loop:
++#if __ARM_ARCH__<7
++	ldrb	r0,[lr],#16		@ load input
++# ifdef	__thumb2__
++	it	hi
++# endif
++	addhi	r8,r8,#1		@ 1<<128
++	ldrb	r1,[lr,#-15]
++	ldrb	r2,[lr,#-14]
++	ldrb	r3,[lr,#-13]
++	orr	r1,r0,r1,lsl#8
++	ldrb	r0,[lr,#-12]
++	orr	r2,r1,r2,lsl#16
++	ldrb	r1,[lr,#-11]
++	orr	r3,r2,r3,lsl#24
++	ldrb	r2,[lr,#-10]
++	adds	r4,r4,r3		@ accumulate input
++
++	ldrb	r3,[lr,#-9]
++	orr	r1,r0,r1,lsl#8
++	ldrb	r0,[lr,#-8]
++	orr	r2,r1,r2,lsl#16
++	ldrb	r1,[lr,#-7]
++	orr	r3,r2,r3,lsl#24
++	ldrb	r2,[lr,#-6]
++	adcs	r5,r5,r3
++
++	ldrb	r3,[lr,#-5]
++	orr	r1,r0,r1,lsl#8
++	ldrb	r0,[lr,#-4]
++	orr	r2,r1,r2,lsl#16
++	ldrb	r1,[lr,#-3]
++	orr	r3,r2,r3,lsl#24
++	ldrb	r2,[lr,#-2]
++	adcs	r6,r6,r3
++
++	ldrb	r3,[lr,#-1]
++	orr	r1,r0,r1,lsl#8
++	str	lr,[sp,#8]		@ offload input pointer
++	orr	r2,r1,r2,lsl#16
++	add	r10,r10,r10,lsr#2
++	orr	r3,r2,r3,lsl#24
++#else
++	ldr	r0,[lr],#16		@ load input
++	it	hi
++	addhi	r8,r8,#1		@ padbit
++	ldr	r1,[lr,#-12]
++	ldr	r2,[lr,#-8]
++	ldr	r3,[lr,#-4]
++# ifdef	__ARMEB__
++	rev	r0,r0
++	rev	r1,r1
++	rev	r2,r2
++	rev	r3,r3
++# endif
++	adds	r4,r4,r0		@ accumulate input
++	str	lr,[sp,#8]		@ offload input pointer
++	adcs	r5,r5,r1
++	add	r10,r10,r10,lsr#2
++	adcs	r6,r6,r2
++#endif
++	add	r11,r11,r11,lsr#2
++	adcs	r7,r7,r3
++	add	r12,r12,r12,lsr#2
++
++	umull	r2,r3,r5,r9
++	 adc	r8,r8,#0
++	umull	r0,r1,r4,r9
++	umlal	r2,r3,r8,r10
++	umlal	r0,r1,r7,r10
++	ldr	r10,[sp,#20]		@ reload r10
++	umlal	r2,r3,r6,r12
++	umlal	r0,r1,r5,r12
++	umlal	r2,r3,r7,r11
++	umlal	r0,r1,r6,r11
++	umlal	r2,r3,r4,r10
++	str	r0,[sp,#0]		@ future r4
++	 mul	r0,r11,r8
++	ldr	r11,[sp,#24]		@ reload r11
++	adds	r2,r2,r1		@ d1+=d0>>32
++	 eor	r1,r1,r1
++	adc	lr,r3,#0		@ future r6
++	str	r2,[sp,#4]		@ future r5
++
++	mul	r2,r12,r8
++	eor	r3,r3,r3
++	umlal	r0,r1,r7,r12
++	ldr	r12,[sp,#28]		@ reload r12
++	umlal	r2,r3,r7,r9
++	umlal	r0,r1,r6,r9
++	umlal	r2,r3,r6,r10
++	umlal	r0,r1,r5,r10
++	umlal	r2,r3,r5,r11
++	umlal	r0,r1,r4,r11
++	umlal	r2,r3,r4,r12
++	ldr	r4,[sp,#0]
++	mul	r8,r9,r8
++	ldr	r5,[sp,#4]
++
++	adds	r6,lr,r0		@ d2+=d1>>32
++	ldr	lr,[sp,#8]		@ reload input pointer
++	adc	r1,r1,#0
++	adds	r7,r2,r1		@ d3+=d2>>32
++	ldr	r0,[sp,#16]		@ reload end pointer
++	adc	r3,r3,#0
++	add	r8,r8,r3		@ h4+=d3>>32
++
++	and	r1,r8,#-4
++	and	r8,r8,#3
++	add	r1,r1,r1,lsr#2		@ *=5
++	adds	r4,r4,r1
++	adcs	r5,r5,#0
++	adcs	r6,r6,#0
++	adcs	r7,r7,#0
++	adc	r8,r8,#0
++
++	cmp	r0,lr			@ done yet?
++	bhi	.Loop
++
++	ldr	r0,[sp,#12]
++	add	sp,sp,#32
++	stmdb	r0,{r4-r8}		@ store the result
++
++.Lno_data:
++#if	__ARM_ARCH__>=5
++	ldmia	sp!,{r3-r11,pc}
++#else
++	ldmia	sp!,{r3-r11,lr}
++	tst	lr,#1
++	moveq	pc,lr			@ be binary compatible with V4, yet
++	.word	0xe12fff1e			@ interoperable with Thumb ISA:-)
++#endif
++.size	poly1305_blocks,.-poly1305_blocks
++.type	poly1305_emit,%function
++.align	5
++poly1305_emit:
++.Lpoly1305_emit:
++	stmdb	sp!,{r4-r11}
++
++	ldmia	r0,{r3-r7}
++
++#if __ARM_ARCH__>=7
++	ldr	ip,[r0,#36]		@ is_base2_26
++
++	adds	r8,r3,r4,lsl#26	@ base 2^26 -> base 2^32
++	mov	r9,r4,lsr#6
++	adcs	r9,r9,r5,lsl#20
++	mov	r10,r5,lsr#12
++	adcs	r10,r10,r6,lsl#14
++	mov	r11,r6,lsr#18
++	adcs	r11,r11,r7,lsl#8
++	mov	r0,#0
++	adc	r0,r0,r7,lsr#24
++
++	tst	ip,ip
++	itttt	ne
++	movne	r3,r8
++	movne	r4,r9
++	movne	r5,r10
++	movne	r6,r11
++	it	ne
++	movne	r7,r0
++#endif
++
++	adds	r8,r3,#5		@ compare to modulus
++	adcs	r9,r4,#0
++	adcs	r10,r5,#0
++	adcs	r11,r6,#0
++	adc	r0,r7,#0
++	tst	r0,#4			@ did it carry/borrow?
++
++#ifdef	__thumb2__
++	it	ne
++#endif
++	movne	r3,r8
++	ldr	r8,[r2,#0]
++#ifdef	__thumb2__
++	it	ne
++#endif
++	movne	r4,r9
++	ldr	r9,[r2,#4]
++#ifdef	__thumb2__
++	it	ne
++#endif
++	movne	r5,r10
++	ldr	r10,[r2,#8]
++#ifdef	__thumb2__
++	it	ne
++#endif
++	movne	r6,r11
++	ldr	r11,[r2,#12]
++
++	adds	r3,r3,r8
++	adcs	r4,r4,r9
++	adcs	r5,r5,r10
++	adc	r6,r6,r11
++
++#if __ARM_ARCH__>=7
++# ifdef __ARMEB__
++	rev	r3,r3
++	rev	r4,r4
++	rev	r5,r5
++	rev	r6,r6
++# endif
++	str	r3,[r1,#0]
++	str	r4,[r1,#4]
++	str	r5,[r1,#8]
++	str	r6,[r1,#12]
++#else
++	strb	r3,[r1,#0]
++	mov	r3,r3,lsr#8
++	strb	r4,[r1,#4]
++	mov	r4,r4,lsr#8
++	strb	r5,[r1,#8]
++	mov	r5,r5,lsr#8
++	strb	r6,[r1,#12]
++	mov	r6,r6,lsr#8
++
++	strb	r3,[r1,#1]
++	mov	r3,r3,lsr#8
++	strb	r4,[r1,#5]
++	mov	r4,r4,lsr#8
++	strb	r5,[r1,#9]
++	mov	r5,r5,lsr#8
++	strb	r6,[r1,#13]
++	mov	r6,r6,lsr#8
++
++	strb	r3,[r1,#2]
++	mov	r3,r3,lsr#8
++	strb	r4,[r1,#6]
++	mov	r4,r4,lsr#8
++	strb	r5,[r1,#10]
++	mov	r5,r5,lsr#8
++	strb	r6,[r1,#14]
++	mov	r6,r6,lsr#8
++
++	strb	r3,[r1,#3]
++	strb	r4,[r1,#7]
++	strb	r5,[r1,#11]
++	strb	r6,[r1,#15]
++#endif
++	ldmia	sp!,{r4-r11}
++#if	__ARM_ARCH__>=5
++	bx	lr				@ bx	lr
++#else
++	tst	lr,#1
++	moveq	pc,lr			@ be binary compatible with V4, yet
++	.word	0xe12fff1e			@ interoperable with Thumb ISA:-)
++#endif
++.size	poly1305_emit,.-poly1305_emit
++#if	__ARM_MAX_ARCH__>=7
++.fpu	neon
++
++.type	poly1305_init_neon,%function
++.align	5
++poly1305_init_neon:
++.Lpoly1305_init_neon:
++	ldr	r3,[r0,#48]		@ first table element
++	cmp	r3,#-1			@ is value impossible?
++	bne	.Lno_init_neon
++
++	ldr	r4,[r0,#20]		@ load key base 2^32
++	ldr	r5,[r0,#24]
++	ldr	r6,[r0,#28]
++	ldr	r7,[r0,#32]
++
++	and	r2,r4,#0x03ffffff	@ base 2^32 -> base 2^26
++	mov	r3,r4,lsr#26
++	mov	r4,r5,lsr#20
++	orr	r3,r3,r5,lsl#6
++	mov	r5,r6,lsr#14
++	orr	r4,r4,r6,lsl#12
++	mov	r6,r7,lsr#8
++	orr	r5,r5,r7,lsl#18
++	and	r3,r3,#0x03ffffff
++	and	r4,r4,#0x03ffffff
++	and	r5,r5,#0x03ffffff
++
++	vdup.32	d0,r2			@ r^1 in both lanes
++	add	r2,r3,r3,lsl#2		@ *5
++	vdup.32	d1,r3
++	add	r3,r4,r4,lsl#2
++	vdup.32	d2,r2
++	vdup.32	d3,r4
++	add	r4,r5,r5,lsl#2
++	vdup.32	d4,r3
++	vdup.32	d5,r5
++	add	r5,r6,r6,lsl#2
++	vdup.32	d6,r4
++	vdup.32	d7,r6
++	vdup.32	d8,r5
++
++	mov	r5,#2		@ counter
++
++.Lsquare_neon:
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
++	@ d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
++	@ d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
++	@ d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
++	@ d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
++
++	vmull.u32	q5,d0,d0[1]
++	vmull.u32	q6,d1,d0[1]
++	vmull.u32	q7,d3,d0[1]
++	vmull.u32	q8,d5,d0[1]
++	vmull.u32	q9,d7,d0[1]
++
++	vmlal.u32	q5,d7,d2[1]
++	vmlal.u32	q6,d0,d1[1]
++	vmlal.u32	q7,d1,d1[1]
++	vmlal.u32	q8,d3,d1[1]
++	vmlal.u32	q9,d5,d1[1]
++
++	vmlal.u32	q5,d5,d4[1]
++	vmlal.u32	q6,d7,d4[1]
++	vmlal.u32	q8,d1,d3[1]
++	vmlal.u32	q7,d0,d3[1]
++	vmlal.u32	q9,d3,d3[1]
++
++	vmlal.u32	q5,d3,d6[1]
++	vmlal.u32	q8,d0,d5[1]
++	vmlal.u32	q6,d5,d6[1]
++	vmlal.u32	q7,d7,d6[1]
++	vmlal.u32	q9,d1,d5[1]
++
++	vmlal.u32	q8,d7,d8[1]
++	vmlal.u32	q5,d1,d8[1]
++	vmlal.u32	q6,d3,d8[1]
++	vmlal.u32	q7,d5,d8[1]
++	vmlal.u32	q9,d0,d7[1]
++
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ lazy reduction as discussed in "NEON crypto" by D.J. Bernstein
++	@ and P. Schwabe
++	@
++	@ H0>>+H1>>+H2>>+H3>>+H4
++	@ H3>>+H4>>*5+H0>>+H1
++	@
++	@ Trivia.
++	@
++	@ Result of multiplication of n-bit number by m-bit number is
++	@ n+m bits wide. However! Even though 2^n is a n+1-bit number,
++	@ m-bit number multiplied by 2^n is still n+m bits wide.
++	@
++	@ Sum of two n-bit numbers is n+1 bits wide, sum of three - n+2,
++	@ and so is sum of four. Sum of 2^m n-m-bit numbers and n-bit
++	@ one is n+1 bits wide.
++	@
++	@ >>+ denotes Hnext += Hn>>26, Hn &= 0x3ffffff. This means that
++	@ H0, H2, H3 are guaranteed to be 26 bits wide, while H1 and H4
++	@ can be 27. However! In cases when their width exceeds 26 bits
++	@ they are limited by 2^26+2^6. This in turn means that *sum*
++	@ of the products with these values can still be viewed as sum
++	@ of 52-bit numbers as long as the amount of addends is not a
++	@ power of 2. For example,
++	@
++	@ H4 = H4*R0 + H3*R1 + H2*R2 + H1*R3 + H0 * R4,
++	@
++	@ which can't be larger than 5 * (2^26 + 2^6) * (2^26 + 2^6), or
++	@ 5 * (2^52 + 2*2^32 + 2^12), which in turn is smaller than
++	@ 8 * (2^52) or 2^55. However, the value is then multiplied by
++	@ by 5, so we should be looking at 5 * 5 * (2^52 + 2^33 + 2^12),
++	@ which is less than 32 * (2^52) or 2^57. And when processing
++	@ data we are looking at triple as many addends...
++	@
++	@ In key setup procedure pre-reduced H0 is limited by 5*4+1 and
++	@ 5*H4 - by 5*5 52-bit addends, or 57 bits. But when hashing the
++	@ input H0 is limited by (5*4+1)*3 addends, or 58 bits, while
++	@ 5*H4 by 5*5*3, or 59[!] bits. How is this relevant? vmlal.u32
++	@ instruction accepts 2x32-bit input and writes 2x64-bit result.
++	@ This means that result of reduction have to be compressed upon
++	@ loop wrap-around. This can be done in the process of reduction
++	@ to minimize amount of instructions [as well as amount of
++	@ 128-bit instructions, which benefits low-end processors], but
++	@ one has to watch for H2 (which is narrower than H0) and 5*H4
++	@ not being wider than 58 bits, so that result of right shift
++	@ by 26 bits fits in 32 bits. This is also useful on x86,
++	@ because it allows to use paddd in place for paddq, which
++	@ benefits Atom, where paddq is ridiculously slow.
++
++	vshr.u64	q15,q8,#26
++	vmovn.i64	d16,q8
++	 vshr.u64	q4,q5,#26
++	 vmovn.i64	d10,q5
++	vadd.i64	q9,q9,q15		@ h3 -> h4
++	vbic.i32	d16,#0xfc000000	@ &=0x03ffffff
++	 vadd.i64	q6,q6,q4		@ h0 -> h1
++	 vbic.i32	d10,#0xfc000000
++
++	vshrn.u64	d30,q9,#26
++	vmovn.i64	d18,q9
++	 vshr.u64	q4,q6,#26
++	 vmovn.i64	d12,q6
++	 vadd.i64	q7,q7,q4		@ h1 -> h2
++	vbic.i32	d18,#0xfc000000
++	 vbic.i32	d12,#0xfc000000
++
++	vadd.i32	d10,d10,d30
++	vshl.u32	d30,d30,#2
++	 vshrn.u64	d8,q7,#26
++	 vmovn.i64	d14,q7
++	vadd.i32	d10,d10,d30	@ h4 -> h0
++	 vadd.i32	d16,d16,d8	@ h2 -> h3
++	 vbic.i32	d14,#0xfc000000
++
++	vshr.u32	d30,d10,#26
++	vbic.i32	d10,#0xfc000000
++	 vshr.u32	d8,d16,#26
++	 vbic.i32	d16,#0xfc000000
++	vadd.i32	d12,d12,d30	@ h0 -> h1
++	 vadd.i32	d18,d18,d8	@ h3 -> h4
++
++	subs		r5,r5,#1
++	beq		.Lsquare_break_neon
++
++	add		r6,r0,#(48+0*9*4)
++	add		r7,r0,#(48+1*9*4)
++
++	vtrn.32		d0,d10		@ r^2:r^1
++	vtrn.32		d3,d14
++	vtrn.32		d5,d16
++	vtrn.32		d1,d12
++	vtrn.32		d7,d18
++
++	vshl.u32	d4,d3,#2		@ *5
++	vshl.u32	d6,d5,#2
++	vshl.u32	d2,d1,#2
++	vshl.u32	d8,d7,#2
++	vadd.i32	d4,d4,d3
++	vadd.i32	d2,d2,d1
++	vadd.i32	d6,d6,d5
++	vadd.i32	d8,d8,d7
++
++	vst4.32		{d0[0],d1[0],d2[0],d3[0]},[r6]!
++	vst4.32		{d0[1],d1[1],d2[1],d3[1]},[r7]!
++	vst4.32		{d4[0],d5[0],d6[0],d7[0]},[r6]!
++	vst4.32		{d4[1],d5[1],d6[1],d7[1]},[r7]!
++	vst1.32		{d8[0]},[r6,:32]
++	vst1.32		{d8[1]},[r7,:32]
++
++	b		.Lsquare_neon
++
++.align	4
++.Lsquare_break_neon:
++	add		r6,r0,#(48+2*4*9)
++	add		r7,r0,#(48+3*4*9)
++
++	vmov		d0,d10		@ r^4:r^3
++	vshl.u32	d2,d12,#2		@ *5
++	vmov		d1,d12
++	vshl.u32	d4,d14,#2
++	vmov		d3,d14
++	vshl.u32	d6,d16,#2
++	vmov		d5,d16
++	vshl.u32	d8,d18,#2
++	vmov		d7,d18
++	vadd.i32	d2,d2,d12
++	vadd.i32	d4,d4,d14
++	vadd.i32	d6,d6,d16
++	vadd.i32	d8,d8,d18
++
++	vst4.32		{d0[0],d1[0],d2[0],d3[0]},[r6]!
++	vst4.32		{d0[1],d1[1],d2[1],d3[1]},[r7]!
++	vst4.32		{d4[0],d5[0],d6[0],d7[0]},[r6]!
++	vst4.32		{d4[1],d5[1],d6[1],d7[1]},[r7]!
++	vst1.32		{d8[0]},[r6]
++	vst1.32		{d8[1]},[r7]
++
++.Lno_init_neon:
++	bx	lr				@ bx	lr
++.size	poly1305_init_neon,.-poly1305_init_neon
++
++.type	poly1305_blocks_neon,%function
++.align	5
++poly1305_blocks_neon:
++.Lpoly1305_blocks_neon:
++	ldr	ip,[r0,#36]		@ is_base2_26
++
++	cmp	r2,#64
++	blo	.Lpoly1305_blocks
++
++	stmdb	sp!,{r4-r7}
++	vstmdb	sp!,{d8-d15}		@ ABI specification says so
++
++	tst	ip,ip			@ is_base2_26?
++	bne	.Lbase2_26_neon
++
++	stmdb	sp!,{r1-r3,lr}
++	bl	.Lpoly1305_init_neon
++
++	ldr	r4,[r0,#0]		@ load hash value base 2^32
++	ldr	r5,[r0,#4]
++	ldr	r6,[r0,#8]
++	ldr	r7,[r0,#12]
++	ldr	ip,[r0,#16]
++
++	and	r2,r4,#0x03ffffff	@ base 2^32 -> base 2^26
++	mov	r3,r4,lsr#26
++	 veor	d10,d10,d10
++	mov	r4,r5,lsr#20
++	orr	r3,r3,r5,lsl#6
++	 veor	d12,d12,d12
++	mov	r5,r6,lsr#14
++	orr	r4,r4,r6,lsl#12
++	 veor	d14,d14,d14
++	mov	r6,r7,lsr#8
++	orr	r5,r5,r7,lsl#18
++	 veor	d16,d16,d16
++	and	r3,r3,#0x03ffffff
++	orr	r6,r6,ip,lsl#24
++	 veor	d18,d18,d18
++	and	r4,r4,#0x03ffffff
++	mov	r1,#1
++	and	r5,r5,#0x03ffffff
++	str	r1,[r0,#36]		@ set is_base2_26
++
++	vmov.32	d10[0],r2
++	vmov.32	d12[0],r3
++	vmov.32	d14[0],r4
++	vmov.32	d16[0],r5
++	vmov.32	d18[0],r6
++	adr	r5,.Lzeros
++
++	ldmia	sp!,{r1-r3,lr}
++	b	.Lhash_loaded
++
++.align	4
++.Lbase2_26_neon:
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ load hash value
++
++	veor		d10,d10,d10
++	veor		d12,d12,d12
++	veor		d14,d14,d14
++	veor		d16,d16,d16
++	veor		d18,d18,d18
++	vld4.32		{d10[0],d12[0],d14[0],d16[0]},[r0]!
++	adr		r5,.Lzeros
++	vld1.32		{d18[0]},[r0]
++	sub		r0,r0,#16		@ rewind
++
++.Lhash_loaded:
++	add		r4,r1,#32
++	mov		r3,r3,lsl#24
++	tst		r2,#31
++	beq		.Leven
++
++	vld4.32		{d20[0],d22[0],d24[0],d26[0]},[r1]!
++	vmov.32		d28[0],r3
++	sub		r2,r2,#16
++	add		r4,r1,#32
++
++# ifdef	__ARMEB__
++	vrev32.8	q10,q10
++	vrev32.8	q13,q13
++	vrev32.8	q11,q11
++	vrev32.8	q12,q12
++# endif
++	vsri.u32	d28,d26,#8	@ base 2^32 -> base 2^26
++	vshl.u32	d26,d26,#18
++
++	vsri.u32	d26,d24,#14
++	vshl.u32	d24,d24,#12
++	vadd.i32	d29,d28,d18	@ add hash value and move to #hi
++
++	vbic.i32	d26,#0xfc000000
++	vsri.u32	d24,d22,#20
++	vshl.u32	d22,d22,#6
++
++	vbic.i32	d24,#0xfc000000
++	vsri.u32	d22,d20,#26
++	vadd.i32	d27,d26,d16
++
++	vbic.i32	d20,#0xfc000000
++	vbic.i32	d22,#0xfc000000
++	vadd.i32	d25,d24,d14
++
++	vadd.i32	d21,d20,d10
++	vadd.i32	d23,d22,d12
++
++	mov		r7,r5
++	add		r6,r0,#48
++
++	cmp		r2,r2
++	b		.Long_tail
++
++.align	4
++.Leven:
++	subs		r2,r2,#64
++	it		lo
++	movlo		r4,r5
++
++	vmov.i32	q14,#1<<24		@ padbit, yes, always
++	vld4.32		{d20,d22,d24,d26},[r1]	@ inp[0:1]
++	add		r1,r1,#64
++	vld4.32		{d21,d23,d25,d27},[r4]	@ inp[2:3] (or 0)
++	add		r4,r4,#64
++	itt		hi
++	addhi		r7,r0,#(48+1*9*4)
++	addhi		r6,r0,#(48+3*9*4)
++
++# ifdef	__ARMEB__
++	vrev32.8	q10,q10
++	vrev32.8	q13,q13
++	vrev32.8	q11,q11
++	vrev32.8	q12,q12
++# endif
++	vsri.u32	q14,q13,#8		@ base 2^32 -> base 2^26
++	vshl.u32	q13,q13,#18
++
++	vsri.u32	q13,q12,#14
++	vshl.u32	q12,q12,#12
++
++	vbic.i32	q13,#0xfc000000
++	vsri.u32	q12,q11,#20
++	vshl.u32	q11,q11,#6
++
++	vbic.i32	q12,#0xfc000000
++	vsri.u32	q11,q10,#26
++
++	vbic.i32	q10,#0xfc000000
++	vbic.i32	q11,#0xfc000000
++
++	bls		.Lskip_loop
++
++	vld4.32		{d0[1],d1[1],d2[1],d3[1]},[r7]!	@ load r^2
++	vld4.32		{d0[0],d1[0],d2[0],d3[0]},[r6]!	@ load r^4
++	vld4.32		{d4[1],d5[1],d6[1],d7[1]},[r7]!
++	vld4.32		{d4[0],d5[0],d6[0],d7[0]},[r6]!
++	b		.Loop_neon
++
++.align	5
++.Loop_neon:
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2
++	@ ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r
++	@   ___________________/
++	@ ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2
++	@ ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r
++	@   ___________________/ ____________________/
++	@
++	@ Note that we start with inp[2:3]*r^2. This is because it
++	@ doesn't depend on reduction in previous iteration.
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
++	@ d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
++	@ d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
++	@ d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
++	@ d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
++
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ inp[2:3]*r^2
++
++	vadd.i32	d24,d24,d14	@ accumulate inp[0:1]
++	vmull.u32	q7,d25,d0[1]
++	vadd.i32	d20,d20,d10
++	vmull.u32	q5,d21,d0[1]
++	vadd.i32	d26,d26,d16
++	vmull.u32	q8,d27,d0[1]
++	vmlal.u32	q7,d23,d1[1]
++	vadd.i32	d22,d22,d12
++	vmull.u32	q6,d23,d0[1]
++
++	vadd.i32	d28,d28,d18
++	vmull.u32	q9,d29,d0[1]
++	subs		r2,r2,#64
++	vmlal.u32	q5,d29,d2[1]
++	it		lo
++	movlo		r4,r5
++	vmlal.u32	q8,d25,d1[1]
++	vld1.32		d8[1],[r7,:32]
++	vmlal.u32	q6,d21,d1[1]
++	vmlal.u32	q9,d27,d1[1]
++
++	vmlal.u32	q5,d27,d4[1]
++	vmlal.u32	q8,d23,d3[1]
++	vmlal.u32	q9,d25,d3[1]
++	vmlal.u32	q6,d29,d4[1]
++	vmlal.u32	q7,d21,d3[1]
++
++	vmlal.u32	q8,d21,d5[1]
++	vmlal.u32	q5,d25,d6[1]
++	vmlal.u32	q9,d23,d5[1]
++	vmlal.u32	q6,d27,d6[1]
++	vmlal.u32	q7,d29,d6[1]
++
++	vmlal.u32	q8,d29,d8[1]
++	vmlal.u32	q5,d23,d8[1]
++	vmlal.u32	q9,d21,d7[1]
++	vmlal.u32	q6,d25,d8[1]
++	vmlal.u32	q7,d27,d8[1]
++
++	vld4.32		{d21,d23,d25,d27},[r4]	@ inp[2:3] (or 0)
++	add		r4,r4,#64
++
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ (hash+inp[0:1])*r^4 and accumulate
++
++	vmlal.u32	q8,d26,d0[0]
++	vmlal.u32	q5,d20,d0[0]
++	vmlal.u32	q9,d28,d0[0]
++	vmlal.u32	q6,d22,d0[0]
++	vmlal.u32	q7,d24,d0[0]
++	vld1.32		d8[0],[r6,:32]
++
++	vmlal.u32	q8,d24,d1[0]
++	vmlal.u32	q5,d28,d2[0]
++	vmlal.u32	q9,d26,d1[0]
++	vmlal.u32	q6,d20,d1[0]
++	vmlal.u32	q7,d22,d1[0]
++
++	vmlal.u32	q8,d22,d3[0]
++	vmlal.u32	q5,d26,d4[0]
++	vmlal.u32	q9,d24,d3[0]
++	vmlal.u32	q6,d28,d4[0]
++	vmlal.u32	q7,d20,d3[0]
++
++	vmlal.u32	q8,d20,d5[0]
++	vmlal.u32	q5,d24,d6[0]
++	vmlal.u32	q9,d22,d5[0]
++	vmlal.u32	q6,d26,d6[0]
++	vmlal.u32	q8,d28,d8[0]
++
++	vmlal.u32	q7,d28,d6[0]
++	vmlal.u32	q5,d22,d8[0]
++	vmlal.u32	q9,d20,d7[0]
++	vmov.i32	q14,#1<<24		@ padbit, yes, always
++	vmlal.u32	q6,d24,d8[0]
++	vmlal.u32	q7,d26,d8[0]
++
++	vld4.32		{d20,d22,d24,d26},[r1]	@ inp[0:1]
++	add		r1,r1,#64
++# ifdef	__ARMEB__
++	vrev32.8	q10,q10
++	vrev32.8	q11,q11
++	vrev32.8	q12,q12
++	vrev32.8	q13,q13
++# endif
++
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ lazy reduction interleaved with base 2^32 -> base 2^26 of
++	@ inp[0:3] previously loaded to q10-q13 and smashed to q10-q14.
++
++	vshr.u64	q15,q8,#26
++	vmovn.i64	d16,q8
++	 vshr.u64	q4,q5,#26
++	 vmovn.i64	d10,q5
++	vadd.i64	q9,q9,q15		@ h3 -> h4
++	vbic.i32	d16,#0xfc000000
++	  vsri.u32	q14,q13,#8		@ base 2^32 -> base 2^26
++	 vadd.i64	q6,q6,q4		@ h0 -> h1
++	  vshl.u32	q13,q13,#18
++	 vbic.i32	d10,#0xfc000000
++
++	vshrn.u64	d30,q9,#26
++	vmovn.i64	d18,q9
++	 vshr.u64	q4,q6,#26
++	 vmovn.i64	d12,q6
++	 vadd.i64	q7,q7,q4		@ h1 -> h2
++	  vsri.u32	q13,q12,#14
++	vbic.i32	d18,#0xfc000000
++	  vshl.u32	q12,q12,#12
++	 vbic.i32	d12,#0xfc000000
++
++	vadd.i32	d10,d10,d30
++	vshl.u32	d30,d30,#2
++	  vbic.i32	q13,#0xfc000000
++	 vshrn.u64	d8,q7,#26
++	 vmovn.i64	d14,q7
++	vaddl.u32	q5,d10,d30	@ h4 -> h0 [widen for a sec]
++	  vsri.u32	q12,q11,#20
++	 vadd.i32	d16,d16,d8	@ h2 -> h3
++	  vshl.u32	q11,q11,#6
++	 vbic.i32	d14,#0xfc000000
++	  vbic.i32	q12,#0xfc000000
++
++	vshrn.u64	d30,q5,#26		@ re-narrow
++	vmovn.i64	d10,q5
++	  vsri.u32	q11,q10,#26
++	  vbic.i32	q10,#0xfc000000
++	 vshr.u32	d8,d16,#26
++	 vbic.i32	d16,#0xfc000000
++	vbic.i32	d10,#0xfc000000
++	vadd.i32	d12,d12,d30	@ h0 -> h1
++	 vadd.i32	d18,d18,d8	@ h3 -> h4
++	  vbic.i32	q11,#0xfc000000
++
++	bhi		.Loop_neon
++
++.Lskip_loop:
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1
++
++	add		r7,r0,#(48+0*9*4)
++	add		r6,r0,#(48+1*9*4)
++	adds		r2,r2,#32
++	it		ne
++	movne		r2,#0
++	bne		.Long_tail
++
++	vadd.i32	d25,d24,d14	@ add hash value and move to #hi
++	vadd.i32	d21,d20,d10
++	vadd.i32	d27,d26,d16
++	vadd.i32	d23,d22,d12
++	vadd.i32	d29,d28,d18
++
++.Long_tail:
++	vld4.32		{d0[1],d1[1],d2[1],d3[1]},[r7]!	@ load r^1
++	vld4.32		{d0[0],d1[0],d2[0],d3[0]},[r6]!	@ load r^2
++
++	vadd.i32	d24,d24,d14	@ can be redundant
++	vmull.u32	q7,d25,d0
++	vadd.i32	d20,d20,d10
++	vmull.u32	q5,d21,d0
++	vadd.i32	d26,d26,d16
++	vmull.u32	q8,d27,d0
++	vadd.i32	d22,d22,d12
++	vmull.u32	q6,d23,d0
++	vadd.i32	d28,d28,d18
++	vmull.u32	q9,d29,d0
++
++	vmlal.u32	q5,d29,d2
++	vld4.32		{d4[1],d5[1],d6[1],d7[1]},[r7]!
++	vmlal.u32	q8,d25,d1
++	vld4.32		{d4[0],d5[0],d6[0],d7[0]},[r6]!
++	vmlal.u32	q6,d21,d1
++	vmlal.u32	q9,d27,d1
++	vmlal.u32	q7,d23,d1
++
++	vmlal.u32	q8,d23,d3
++	vld1.32		d8[1],[r7,:32]
++	vmlal.u32	q5,d27,d4
++	vld1.32		d8[0],[r6,:32]
++	vmlal.u32	q9,d25,d3
++	vmlal.u32	q6,d29,d4
++	vmlal.u32	q7,d21,d3
++
++	vmlal.u32	q8,d21,d5
++	 it		ne
++	 addne		r7,r0,#(48+2*9*4)
++	vmlal.u32	q5,d25,d6
++	 it		ne
++	 addne		r6,r0,#(48+3*9*4)
++	vmlal.u32	q9,d23,d5
++	vmlal.u32	q6,d27,d6
++	vmlal.u32	q7,d29,d6
++
++	vmlal.u32	q8,d29,d8
++	 vorn		q0,q0,q0	@ all-ones, can be redundant
++	vmlal.u32	q5,d23,d8
++	 vshr.u64	q0,q0,#38
++	vmlal.u32	q9,d21,d7
++	vmlal.u32	q6,d25,d8
++	vmlal.u32	q7,d27,d8
++
++	beq		.Lshort_tail
++
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ (hash+inp[0:1])*r^4:r^3 and accumulate
++
++	vld4.32		{d0[1],d1[1],d2[1],d3[1]},[r7]!	@ load r^3
++	vld4.32		{d0[0],d1[0],d2[0],d3[0]},[r6]!	@ load r^4
++
++	vmlal.u32	q7,d24,d0
++	vmlal.u32	q5,d20,d0
++	vmlal.u32	q8,d26,d0
++	vmlal.u32	q6,d22,d0
++	vmlal.u32	q9,d28,d0
++
++	vmlal.u32	q5,d28,d2
++	vld4.32		{d4[1],d5[1],d6[1],d7[1]},[r7]!
++	vmlal.u32	q8,d24,d1
++	vld4.32		{d4[0],d5[0],d6[0],d7[0]},[r6]!
++	vmlal.u32	q6,d20,d1
++	vmlal.u32	q9,d26,d1
++	vmlal.u32	q7,d22,d1
++
++	vmlal.u32	q8,d22,d3
++	vld1.32		d8[1],[r7,:32]
++	vmlal.u32	q5,d26,d4
++	vld1.32		d8[0],[r6,:32]
++	vmlal.u32	q9,d24,d3
++	vmlal.u32	q6,d28,d4
++	vmlal.u32	q7,d20,d3
++
++	vmlal.u32	q8,d20,d5
++	vmlal.u32	q5,d24,d6
++	vmlal.u32	q9,d22,d5
++	vmlal.u32	q6,d26,d6
++	vmlal.u32	q7,d28,d6
++
++	vmlal.u32	q8,d28,d8
++	 vorn		q0,q0,q0	@ all-ones
++	vmlal.u32	q5,d22,d8
++	 vshr.u64	q0,q0,#38
++	vmlal.u32	q9,d20,d7
++	vmlal.u32	q6,d24,d8
++	vmlal.u32	q7,d26,d8
++
++.Lshort_tail:
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ horizontal addition
++
++	vadd.i64	d16,d16,d17
++	vadd.i64	d10,d10,d11
++	vadd.i64	d18,d18,d19
++	vadd.i64	d12,d12,d13
++	vadd.i64	d14,d14,d15
++
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ lazy reduction, but without narrowing
++
++	vshr.u64	q15,q8,#26
++	vand.i64	q8,q8,q0
++	 vshr.u64	q4,q5,#26
++	 vand.i64	q5,q5,q0
++	vadd.i64	q9,q9,q15		@ h3 -> h4
++	 vadd.i64	q6,q6,q4		@ h0 -> h1
++
++	vshr.u64	q15,q9,#26
++	vand.i64	q9,q9,q0
++	 vshr.u64	q4,q6,#26
++	 vand.i64	q6,q6,q0
++	 vadd.i64	q7,q7,q4		@ h1 -> h2
++
++	vadd.i64	q5,q5,q15
++	vshl.u64	q15,q15,#2
++	 vshr.u64	q4,q7,#26
++	 vand.i64	q7,q7,q0
++	vadd.i64	q5,q5,q15		@ h4 -> h0
++	 vadd.i64	q8,q8,q4		@ h2 -> h3
++
++	vshr.u64	q15,q5,#26
++	vand.i64	q5,q5,q0
++	 vshr.u64	q4,q8,#26
++	 vand.i64	q8,q8,q0
++	vadd.i64	q6,q6,q15		@ h0 -> h1
++	 vadd.i64	q9,q9,q4		@ h3 -> h4
++
++	cmp		r2,#0
++	bne		.Leven
++
++	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
++	@ store hash value
++
++	vst4.32		{d10[0],d12[0],d14[0],d16[0]},[r0]!
++	vst1.32		{d18[0]},[r0]
++
++	vldmia	sp!,{d8-d15}			@ epilogue
++	ldmia	sp!,{r4-r7}
++	bx	lr					@ bx	lr
++.size	poly1305_blocks_neon,.-poly1305_blocks_neon
++
++.align	5
++.Lzeros:
++.long	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
++#ifndef	__KERNEL__
++.LOPENSSL_armcap:
++# ifdef	_WIN32
++.word	OPENSSL_armcap_P
++# else
++.word	OPENSSL_armcap_P-.Lpoly1305_init
++# endif
++.comm	OPENSSL_armcap_P,4,4
++.hidden	OPENSSL_armcap_P
++#endif
++#endif
++.asciz	"Poly1305 for ARMv4/NEON, CRYPTOGAMS by @dot-asm"
++.align	2
+--- /dev/null
++++ b/arch/arm/crypto/poly1305-glue.c
+@@ -0,0 +1,276 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * OpenSSL/Cryptogams accelerated Poly1305 transform for ARM
++ *
++ * Copyright (C) 2019 Linaro Ltd. <ard.biesheuvel@linaro.org>
++ */
++
++#include <asm/hwcap.h>
++#include <asm/neon.h>
++#include <asm/simd.h>
++#include <asm/unaligned.h>
++#include <crypto/algapi.h>
++#include <crypto/internal/hash.h>
++#include <crypto/internal/poly1305.h>
++#include <crypto/internal/simd.h>
++#include <linux/cpufeature.h>
++#include <linux/crypto.h>
++#include <linux/jump_label.h>
++#include <linux/module.h>
++
++void poly1305_init_arm(void *state, const u8 *key);
++void poly1305_blocks_arm(void *state, const u8 *src, u32 len, u32 hibit);
++void poly1305_emit_arm(void *state, __le32 *digest, const u32 *nonce);
++
++void __weak poly1305_blocks_neon(void *state, const u8 *src, u32 len, u32 hibit)
++{
++}
++
++static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon);
++
++void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key)
++{
++	poly1305_init_arm(&dctx->h, key);
++	dctx->s[0] = get_unaligned_le32(key + 16);
++	dctx->s[1] = get_unaligned_le32(key + 20);
++	dctx->s[2] = get_unaligned_le32(key + 24);
++	dctx->s[3] = get_unaligned_le32(key + 28);
++	dctx->buflen = 0;
++}
++EXPORT_SYMBOL(poly1305_init_arch);
++
++static int arm_poly1305_init(struct shash_desc *desc)
++{
++	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
++
++	dctx->buflen = 0;
++	dctx->rset = 0;
++	dctx->sset = false;
++
++	return 0;
++}
++
++static void arm_poly1305_blocks(struct poly1305_desc_ctx *dctx, const u8 *src,
++				 u32 len, u32 hibit, bool do_neon)
++{
++	if (unlikely(!dctx->sset)) {
++		if (!dctx->rset) {
++			poly1305_init_arm(&dctx->h, src);
++			src += POLY1305_BLOCK_SIZE;
++			len -= POLY1305_BLOCK_SIZE;
++			dctx->rset = 1;
++		}
++		if (len >= POLY1305_BLOCK_SIZE) {
++			dctx->s[0] = get_unaligned_le32(src +  0);
++			dctx->s[1] = get_unaligned_le32(src +  4);
++			dctx->s[2] = get_unaligned_le32(src +  8);
++			dctx->s[3] = get_unaligned_le32(src + 12);
++			src += POLY1305_BLOCK_SIZE;
++			len -= POLY1305_BLOCK_SIZE;
++			dctx->sset = true;
++		}
++		if (len < POLY1305_BLOCK_SIZE)
++			return;
++	}
++
++	len &= ~(POLY1305_BLOCK_SIZE - 1);
++
++	if (static_branch_likely(&have_neon) && likely(do_neon))
++		poly1305_blocks_neon(&dctx->h, src, len, hibit);
++	else
++		poly1305_blocks_arm(&dctx->h, src, len, hibit);
++}
++
++static void arm_poly1305_do_update(struct poly1305_desc_ctx *dctx,
++				    const u8 *src, u32 len, bool do_neon)
++{
++	if (unlikely(dctx->buflen)) {
++		u32 bytes = min(len, POLY1305_BLOCK_SIZE - dctx->buflen);
++
++		memcpy(dctx->buf + dctx->buflen, src, bytes);
++		src += bytes;
++		len -= bytes;
++		dctx->buflen += bytes;
++
++		if (dctx->buflen == POLY1305_BLOCK_SIZE) {
++			arm_poly1305_blocks(dctx, dctx->buf,
++					    POLY1305_BLOCK_SIZE, 1, false);
++			dctx->buflen = 0;
++		}
++	}
++
++	if (likely(len >= POLY1305_BLOCK_SIZE)) {
++		arm_poly1305_blocks(dctx, src, len, 1, do_neon);
++		src += round_down(len, POLY1305_BLOCK_SIZE);
++		len %= POLY1305_BLOCK_SIZE;
++	}
++
++	if (unlikely(len)) {
++		dctx->buflen = len;
++		memcpy(dctx->buf, src, len);
++	}
++}
++
++static int arm_poly1305_update(struct shash_desc *desc,
++			       const u8 *src, unsigned int srclen)
++{
++	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
++
++	arm_poly1305_do_update(dctx, src, srclen, false);
++	return 0;
++}
++
++static int __maybe_unused arm_poly1305_update_neon(struct shash_desc *desc,
++						   const u8 *src,
++						   unsigned int srclen)
++{
++	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
++	bool do_neon = crypto_simd_usable() && srclen > 128;
++
++	if (static_branch_likely(&have_neon) && do_neon)
++		kernel_neon_begin();
++	arm_poly1305_do_update(dctx, src, srclen, do_neon);
++	if (static_branch_likely(&have_neon) && do_neon)
++		kernel_neon_end();
++	return 0;
++}
++
++void poly1305_update_arch(struct poly1305_desc_ctx *dctx, const u8 *src,
++			  unsigned int nbytes)
++{
++	bool do_neon = IS_ENABLED(CONFIG_KERNEL_MODE_NEON) &&
++		       crypto_simd_usable();
++
++	if (unlikely(dctx->buflen)) {
++		u32 bytes = min(nbytes, POLY1305_BLOCK_SIZE - dctx->buflen);
++
++		memcpy(dctx->buf + dctx->buflen, src, bytes);
++		src += bytes;
++		nbytes -= bytes;
++		dctx->buflen += bytes;
++
++		if (dctx->buflen == POLY1305_BLOCK_SIZE) {
++			poly1305_blocks_arm(&dctx->h, dctx->buf,
++					    POLY1305_BLOCK_SIZE, 1);
++			dctx->buflen = 0;
++		}
++	}
++
++	if (likely(nbytes >= POLY1305_BLOCK_SIZE)) {
++		unsigned int len = round_down(nbytes, POLY1305_BLOCK_SIZE);
++
++		if (static_branch_likely(&have_neon) && do_neon) {
++			kernel_neon_begin();
++			poly1305_blocks_neon(&dctx->h, src, len, 1);
++			kernel_neon_end();
++		} else {
++			poly1305_blocks_arm(&dctx->h, src, len, 1);
++		}
++		src += len;
++		nbytes %= POLY1305_BLOCK_SIZE;
++	}
++
++	if (unlikely(nbytes)) {
++		dctx->buflen = nbytes;
++		memcpy(dctx->buf, src, nbytes);
++	}
++}
++EXPORT_SYMBOL(poly1305_update_arch);
++
++void poly1305_final_arch(struct poly1305_desc_ctx *dctx, u8 *dst)
++{
++	__le32 digest[4];
++	u64 f = 0;
++
++	if (unlikely(dctx->buflen)) {
++		dctx->buf[dctx->buflen++] = 1;
++		memset(dctx->buf + dctx->buflen, 0,
++		       POLY1305_BLOCK_SIZE - dctx->buflen);
++		poly1305_blocks_arm(&dctx->h, dctx->buf, POLY1305_BLOCK_SIZE, 0);
++	}
++
++	poly1305_emit_arm(&dctx->h, digest, dctx->s);
++
++	/* mac = (h + s) % (2^128) */
++	f = (f >> 32) + le32_to_cpu(digest[0]);
++	put_unaligned_le32(f, dst);
++	f = (f >> 32) + le32_to_cpu(digest[1]);
++	put_unaligned_le32(f, dst + 4);
++	f = (f >> 32) + le32_to_cpu(digest[2]);
++	put_unaligned_le32(f, dst + 8);
++	f = (f >> 32) + le32_to_cpu(digest[3]);
++	put_unaligned_le32(f, dst + 12);
++
++	*dctx = (struct poly1305_desc_ctx){};
++}
++EXPORT_SYMBOL(poly1305_final_arch);
++
++static int arm_poly1305_final(struct shash_desc *desc, u8 *dst)
++{
++	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
++
++	if (unlikely(!dctx->sset))
++		return -ENOKEY;
++
++	poly1305_final_arch(dctx, dst);
++	return 0;
++}
++
++static struct shash_alg arm_poly1305_algs[] = {{
++	.init			= arm_poly1305_init,
++	.update			= arm_poly1305_update,
++	.final			= arm_poly1305_final,
++	.digestsize		= POLY1305_DIGEST_SIZE,
++	.descsize		= sizeof(struct poly1305_desc_ctx),
++
++	.base.cra_name		= "poly1305",
++	.base.cra_driver_name	= "poly1305-arm",
++	.base.cra_priority	= 150,
++	.base.cra_blocksize	= POLY1305_BLOCK_SIZE,
++	.base.cra_module	= THIS_MODULE,
++#ifdef CONFIG_KERNEL_MODE_NEON
++}, {
++	.init			= arm_poly1305_init,
++	.update			= arm_poly1305_update_neon,
++	.final			= arm_poly1305_final,
++	.digestsize		= POLY1305_DIGEST_SIZE,
++	.descsize		= sizeof(struct poly1305_desc_ctx),
++
++	.base.cra_name		= "poly1305",
++	.base.cra_driver_name	= "poly1305-neon",
++	.base.cra_priority	= 200,
++	.base.cra_blocksize	= POLY1305_BLOCK_SIZE,
++	.base.cra_module	= THIS_MODULE,
++#endif
++}};
++
++static int __init arm_poly1305_mod_init(void)
++{
++	if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) &&
++	    (elf_hwcap & HWCAP_NEON))
++		static_branch_enable(&have_neon);
++	else
++		/* register only the first entry */
++		return crypto_register_shash(&arm_poly1305_algs[0]);
++
++	return crypto_register_shashes(arm_poly1305_algs,
++				       ARRAY_SIZE(arm_poly1305_algs));
++}
++
++static void __exit arm_poly1305_mod_exit(void)
++{
++	if (!static_branch_likely(&have_neon)) {
++		crypto_unregister_shash(&arm_poly1305_algs[0]);
++		return;
++	}
++	crypto_unregister_shashes(arm_poly1305_algs,
++				  ARRAY_SIZE(arm_poly1305_algs));
++}
++
++module_init(arm_poly1305_mod_init);
++module_exit(arm_poly1305_mod_exit);
++
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS_CRYPTO("poly1305");
++MODULE_ALIAS_CRYPTO("poly1305-arm");
++MODULE_ALIAS_CRYPTO("poly1305-neon");
+--- a/lib/crypto/Kconfig
++++ b/lib/crypto/Kconfig
+@@ -40,7 +40,7 @@ config CRYPTO_LIB_DES
+ config CRYPTO_LIB_POLY1305_RSIZE
+ 	int
+ 	default 4 if X86_64
+-	default 9 if ARM64
++	default 9 if ARM || ARM64
+ 	default 1
+ 
+ config CRYPTO_ARCH_HAVE_LIB_POLY1305
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0020-crypto-mips-poly1305-incorporate-OpenSSL-CRYPTOGAMS-.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0020-crypto-mips-poly1305-incorporate-OpenSSL-CRYPTOGAMS-.patch
new file mode 100644
index 0000000..272e179
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0020-crypto-mips-poly1305-incorporate-OpenSSL-CRYPTOGAMS-.patch
@@ -0,0 +1,1563 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:26 +0100
+Subject: [PATCH] crypto: mips/poly1305 - incorporate OpenSSL/CRYPTOGAMS
+ optimized implementation
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit a11d055e7a64ac34a5e99b6fe731299449cbcd58 upstream.
+
+This is a straight import of the OpenSSL/CRYPTOGAMS Poly1305 implementation for
+MIPS authored by Andy Polyakov, a prior 64-bit only version of which has been
+contributed by him to the OpenSSL project. The file 'poly1305-mips.pl' is taken
+straight from this upstream GitHub repository [0] at commit
+d22ade312a7af958ec955620b0d241cf42c37feb, and already contains all the changes
+required to build it as part of a Linux kernel module.
+
+[0] https://github.com/dot-asm/cryptogams
+
+Co-developed-by: Andy Polyakov <appro@cryptogams.org>
+Signed-off-by: Andy Polyakov <appro@cryptogams.org>
+Co-developed-by: René van Dorst <opensource@vdorst.com>
+Signed-off-by: René van Dorst <opensource@vdorst.com>
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/mips/crypto/Makefile         |   14 +
+ arch/mips/crypto/poly1305-glue.c  |  203 +++++
+ arch/mips/crypto/poly1305-mips.pl | 1273 +++++++++++++++++++++++++++++
+ crypto/Kconfig                    |    5 +
+ lib/crypto/Kconfig                |    1 +
+ 5 files changed, 1496 insertions(+)
+ create mode 100644 arch/mips/crypto/poly1305-glue.c
+ create mode 100644 arch/mips/crypto/poly1305-mips.pl
+
+--- a/arch/mips/crypto/Makefile
++++ b/arch/mips/crypto/Makefile
+@@ -8,3 +8,17 @@ obj-$(CONFIG_CRYPTO_CRC32_MIPS) += crc32
+ obj-$(CONFIG_CRYPTO_CHACHA_MIPS) += chacha-mips.o
+ chacha-mips-y := chacha-core.o chacha-glue.o
+ AFLAGS_chacha-core.o += -O2 # needed to fill branch delay slots
++
++obj-$(CONFIG_CRYPTO_POLY1305_MIPS) += poly1305-mips.o
++poly1305-mips-y := poly1305-core.o poly1305-glue.o
++
++perlasm-flavour-$(CONFIG_CPU_MIPS32) := o32
++perlasm-flavour-$(CONFIG_CPU_MIPS64) := 64
++
++quiet_cmd_perlasm = PERLASM $@
++      cmd_perlasm = $(PERL) $(<) $(perlasm-flavour-y) $(@)
++
++$(obj)/poly1305-core.S: $(src)/poly1305-mips.pl FORCE
++	$(call if_changed,perlasm)
++
++targets += poly1305-core.S
+--- /dev/null
++++ b/arch/mips/crypto/poly1305-glue.c
+@@ -0,0 +1,203 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * OpenSSL/Cryptogams accelerated Poly1305 transform for MIPS
++ *
++ * Copyright (C) 2019 Linaro Ltd. <ard.biesheuvel@linaro.org>
++ */
++
++#include <asm/unaligned.h>
++#include <crypto/algapi.h>
++#include <crypto/internal/hash.h>
++#include <crypto/internal/poly1305.h>
++#include <linux/cpufeature.h>
++#include <linux/crypto.h>
++#include <linux/module.h>
++
++asmlinkage void poly1305_init_mips(void *state, const u8 *key);
++asmlinkage void poly1305_blocks_mips(void *state, const u8 *src, u32 len, u32 hibit);
++asmlinkage void poly1305_emit_mips(void *state, __le32 *digest, const u32 *nonce);
++
++void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key)
++{
++	poly1305_init_mips(&dctx->h, key);
++	dctx->s[0] = get_unaligned_le32(key + 16);
++	dctx->s[1] = get_unaligned_le32(key + 20);
++	dctx->s[2] = get_unaligned_le32(key + 24);
++	dctx->s[3] = get_unaligned_le32(key + 28);
++	dctx->buflen = 0;
++}
++EXPORT_SYMBOL(poly1305_init_arch);
++
++static int mips_poly1305_init(struct shash_desc *desc)
++{
++	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
++
++	dctx->buflen = 0;
++	dctx->rset = 0;
++	dctx->sset = false;
++
++	return 0;
++}
++
++static void mips_poly1305_blocks(struct poly1305_desc_ctx *dctx, const u8 *src,
++				 u32 len, u32 hibit)
++{
++	if (unlikely(!dctx->sset)) {
++		if (!dctx->rset) {
++			poly1305_init_mips(&dctx->h, src);
++			src += POLY1305_BLOCK_SIZE;
++			len -= POLY1305_BLOCK_SIZE;
++			dctx->rset = 1;
++		}
++		if (len >= POLY1305_BLOCK_SIZE) {
++			dctx->s[0] = get_unaligned_le32(src +  0);
++			dctx->s[1] = get_unaligned_le32(src +  4);
++			dctx->s[2] = get_unaligned_le32(src +  8);
++			dctx->s[3] = get_unaligned_le32(src + 12);
++			src += POLY1305_BLOCK_SIZE;
++			len -= POLY1305_BLOCK_SIZE;
++			dctx->sset = true;
++		}
++		if (len < POLY1305_BLOCK_SIZE)
++			return;
++	}
++
++	len &= ~(POLY1305_BLOCK_SIZE - 1);
++
++	poly1305_blocks_mips(&dctx->h, src, len, hibit);
++}
++
++static int mips_poly1305_update(struct shash_desc *desc, const u8 *src,
++				unsigned int len)
++{
++	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
++
++	if (unlikely(dctx->buflen)) {
++		u32 bytes = min(len, POLY1305_BLOCK_SIZE - dctx->buflen);
++
++		memcpy(dctx->buf + dctx->buflen, src, bytes);
++		src += bytes;
++		len -= bytes;
++		dctx->buflen += bytes;
++
++		if (dctx->buflen == POLY1305_BLOCK_SIZE) {
++			mips_poly1305_blocks(dctx, dctx->buf, POLY1305_BLOCK_SIZE, 1);
++			dctx->buflen = 0;
++		}
++	}
++
++	if (likely(len >= POLY1305_BLOCK_SIZE)) {
++		mips_poly1305_blocks(dctx, src, len, 1);
++		src += round_down(len, POLY1305_BLOCK_SIZE);
++		len %= POLY1305_BLOCK_SIZE;
++	}
++
++	if (unlikely(len)) {
++		dctx->buflen = len;
++		memcpy(dctx->buf, src, len);
++	}
++	return 0;
++}
++
++void poly1305_update_arch(struct poly1305_desc_ctx *dctx, const u8 *src,
++			  unsigned int nbytes)
++{
++	if (unlikely(dctx->buflen)) {
++		u32 bytes = min(nbytes, POLY1305_BLOCK_SIZE - dctx->buflen);
++
++		memcpy(dctx->buf + dctx->buflen, src, bytes);
++		src += bytes;
++		nbytes -= bytes;
++		dctx->buflen += bytes;
++
++		if (dctx->buflen == POLY1305_BLOCK_SIZE) {
++			poly1305_blocks_mips(&dctx->h, dctx->buf,
++					     POLY1305_BLOCK_SIZE, 1);
++			dctx->buflen = 0;
++		}
++	}
++
++	if (likely(nbytes >= POLY1305_BLOCK_SIZE)) {
++		unsigned int len = round_down(nbytes, POLY1305_BLOCK_SIZE);
++
++		poly1305_blocks_mips(&dctx->h, src, len, 1);
++		src += len;
++		nbytes %= POLY1305_BLOCK_SIZE;
++	}
++
++	if (unlikely(nbytes)) {
++		dctx->buflen = nbytes;
++		memcpy(dctx->buf, src, nbytes);
++	}
++}
++EXPORT_SYMBOL(poly1305_update_arch);
++
++void poly1305_final_arch(struct poly1305_desc_ctx *dctx, u8 *dst)
++{
++	__le32 digest[4];
++	u64 f = 0;
++
++	if (unlikely(dctx->buflen)) {
++		dctx->buf[dctx->buflen++] = 1;
++		memset(dctx->buf + dctx->buflen, 0,
++		       POLY1305_BLOCK_SIZE - dctx->buflen);
++		poly1305_blocks_mips(&dctx->h, dctx->buf, POLY1305_BLOCK_SIZE, 0);
++	}
++
++	poly1305_emit_mips(&dctx->h, digest, dctx->s);
++
++	/* mac = (h + s) % (2^128) */
++	f = (f >> 32) + le32_to_cpu(digest[0]);
++	put_unaligned_le32(f, dst);
++	f = (f >> 32) + le32_to_cpu(digest[1]);
++	put_unaligned_le32(f, dst + 4);
++	f = (f >> 32) + le32_to_cpu(digest[2]);
++	put_unaligned_le32(f, dst + 8);
++	f = (f >> 32) + le32_to_cpu(digest[3]);
++	put_unaligned_le32(f, dst + 12);
++
++	*dctx = (struct poly1305_desc_ctx){};
++}
++EXPORT_SYMBOL(poly1305_final_arch);
++
++static int mips_poly1305_final(struct shash_desc *desc, u8 *dst)
++{
++	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
++
++	if (unlikely(!dctx->sset))
++		return -ENOKEY;
++
++	poly1305_final_arch(dctx, dst);
++	return 0;
++}
++
++static struct shash_alg mips_poly1305_alg = {
++	.init			= mips_poly1305_init,
++	.update			= mips_poly1305_update,
++	.final			= mips_poly1305_final,
++	.digestsize		= POLY1305_DIGEST_SIZE,
++	.descsize		= sizeof(struct poly1305_desc_ctx),
++
++	.base.cra_name		= "poly1305",
++	.base.cra_driver_name	= "poly1305-mips",
++	.base.cra_priority	= 200,
++	.base.cra_blocksize	= POLY1305_BLOCK_SIZE,
++	.base.cra_module	= THIS_MODULE,
++};
++
++static int __init mips_poly1305_mod_init(void)
++{
++	return crypto_register_shash(&mips_poly1305_alg);
++}
++
++static void __exit mips_poly1305_mod_exit(void)
++{
++	crypto_unregister_shash(&mips_poly1305_alg);
++}
++
++module_init(mips_poly1305_mod_init);
++module_exit(mips_poly1305_mod_exit);
++
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS_CRYPTO("poly1305");
++MODULE_ALIAS_CRYPTO("poly1305-mips");
+--- /dev/null
++++ b/arch/mips/crypto/poly1305-mips.pl
+@@ -0,0 +1,1273 @@
++#!/usr/bin/env perl
++# SPDX-License-Identifier: GPL-1.0+ OR BSD-3-Clause
++#
++# ====================================================================
++# Written by Andy Polyakov, @dot-asm, originally for the OpenSSL
++# project.
++# ====================================================================
++
++# Poly1305 hash for MIPS.
++#
++# May 2016
++#
++# Numbers are cycles per processed byte with poly1305_blocks alone.
++#
++#		IALU/gcc
++# R1x000	~5.5/+130%	(big-endian)
++# Octeon II	2.50/+70%	(little-endian)
++#
++# March 2019
++#
++# Add 32-bit code path.
++#
++# October 2019
++#
++# Modulo-scheduling reduction allows to omit dependency chain at the
++# end of inner loop and improve performance. Also optimize MIPS32R2
++# code path for MIPS 1004K core. Per René von Dorst's suggestions.
++#
++#		IALU/gcc
++# R1x000	~9.8/?		(big-endian)
++# Octeon II	3.65/+140%	(little-endian)
++# MT7621/1004K	4.75/?		(little-endian)
++#
++######################################################################
++# There is a number of MIPS ABI in use, O32 and N32/64 are most
++# widely used. Then there is a new contender: NUBI. It appears that if
++# one picks the latter, it's possible to arrange code in ABI neutral
++# manner. Therefore let's stick to NUBI register layout:
++#
++($zero,$at,$t0,$t1,$t2)=map("\$$_",(0..2,24,25));
++($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("\$$_",(4..11));
++($s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7,$s8,$s9,$s10,$s11)=map("\$$_",(12..23));
++($gp,$tp,$sp,$fp,$ra)=map("\$$_",(3,28..31));
++#
++# The return value is placed in $a0. Following coding rules facilitate
++# interoperability:
++#
++# - never ever touch $tp, "thread pointer", former $gp [o32 can be
++#   excluded from the rule, because it's specified volatile];
++# - copy return value to $t0, former $v0 [or to $a0 if you're adapting
++#   old code];
++# - on O32 populate $a4-$a7 with 'lw $aN,4*N($sp)' if necessary;
++#
++# For reference here is register layout for N32/64 MIPS ABIs:
++#
++# ($zero,$at,$v0,$v1)=map("\$$_",(0..3));
++# ($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("\$$_",(4..11));
++# ($t0,$t1,$t2,$t3,$t8,$t9)=map("\$$_",(12..15,24,25));
++# ($s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7)=map("\$$_",(16..23));
++# ($gp,$sp,$fp,$ra)=map("\$$_",(28..31));
++#
++# <appro@openssl.org>
++#
++######################################################################
++
++$flavour = shift || "64"; # supported flavours are o32,n32,64,nubi32,nubi64
++
++$v0 = ($flavour =~ /nubi/i) ? $a0 : $t0;
++
++if ($flavour =~ /64|n32/i) {{{
++######################################################################
++# 64-bit code path
++#
++
++my ($ctx,$inp,$len,$padbit) = ($a0,$a1,$a2,$a3);
++my ($in0,$in1,$tmp0,$tmp1,$tmp2,$tmp3,$tmp4) = ($a4,$a5,$a6,$a7,$at,$t0,$t1);
++
++$code.=<<___;
++#if (defined(_MIPS_ARCH_MIPS64R3) || defined(_MIPS_ARCH_MIPS64R5) || \\
++     defined(_MIPS_ARCH_MIPS64R6)) \\
++     && !defined(_MIPS_ARCH_MIPS64R2)
++# define _MIPS_ARCH_MIPS64R2
++#endif
++
++#if defined(_MIPS_ARCH_MIPS64R6)
++# define dmultu(rs,rt)
++# define mflo(rd,rs,rt)	dmulu	rd,rs,rt
++# define mfhi(rd,rs,rt)	dmuhu	rd,rs,rt
++#else
++# define dmultu(rs,rt)		dmultu	rs,rt
++# define mflo(rd,rs,rt)	mflo	rd
++# define mfhi(rd,rs,rt)	mfhi	rd
++#endif
++
++#ifdef	__KERNEL__
++# define poly1305_init   poly1305_init_mips
++# define poly1305_blocks poly1305_blocks_mips
++# define poly1305_emit   poly1305_emit_mips
++#endif
++
++#if defined(__MIPSEB__) && !defined(MIPSEB)
++# define MIPSEB
++#endif
++
++#ifdef MIPSEB
++# define MSB 0
++# define LSB 7
++#else
++# define MSB 7
++# define LSB 0
++#endif
++
++.text
++.set	noat
++.set	noreorder
++
++.align	5
++.globl	poly1305_init
++.ent	poly1305_init
++poly1305_init:
++	.frame	$sp,0,$ra
++	.set	reorder
++
++	sd	$zero,0($ctx)
++	sd	$zero,8($ctx)
++	sd	$zero,16($ctx)
++
++	beqz	$inp,.Lno_key
++
++#if defined(_MIPS_ARCH_MIPS64R6)
++	andi	$tmp0,$inp,7		# $inp % 8
++	dsubu	$inp,$inp,$tmp0		# align $inp
++	sll	$tmp0,$tmp0,3		# byte to bit offset
++	ld	$in0,0($inp)
++	ld	$in1,8($inp)
++	beqz	$tmp0,.Laligned_key
++	ld	$tmp2,16($inp)
++
++	subu	$tmp1,$zero,$tmp0
++# ifdef	MIPSEB
++	dsllv	$in0,$in0,$tmp0
++	dsrlv	$tmp3,$in1,$tmp1
++	dsllv	$in1,$in1,$tmp0
++	dsrlv	$tmp2,$tmp2,$tmp1
++# else
++	dsrlv	$in0,$in0,$tmp0
++	dsllv	$tmp3,$in1,$tmp1
++	dsrlv	$in1,$in1,$tmp0
++	dsllv	$tmp2,$tmp2,$tmp1
++# endif
++	or	$in0,$in0,$tmp3
++	or	$in1,$in1,$tmp2
++.Laligned_key:
++#else
++	ldl	$in0,0+MSB($inp)
++	ldl	$in1,8+MSB($inp)
++	ldr	$in0,0+LSB($inp)
++	ldr	$in1,8+LSB($inp)
++#endif
++#ifdef	MIPSEB
++# if defined(_MIPS_ARCH_MIPS64R2)
++	dsbh	$in0,$in0		# byte swap
++	 dsbh	$in1,$in1
++	dshd	$in0,$in0
++	 dshd	$in1,$in1
++# else
++	ori	$tmp0,$zero,0xFF
++	dsll	$tmp2,$tmp0,32
++	or	$tmp0,$tmp2		# 0x000000FF000000FF
++
++	and	$tmp1,$in0,$tmp0	# byte swap
++	 and	$tmp3,$in1,$tmp0
++	dsrl	$tmp2,$in0,24
++	 dsrl	$tmp4,$in1,24
++	dsll	$tmp1,24
++	 dsll	$tmp3,24
++	and	$tmp2,$tmp0
++	 and	$tmp4,$tmp0
++	dsll	$tmp0,8			# 0x0000FF000000FF00
++	or	$tmp1,$tmp2
++	 or	$tmp3,$tmp4
++	and	$tmp2,$in0,$tmp0
++	 and	$tmp4,$in1,$tmp0
++	dsrl	$in0,8
++	 dsrl	$in1,8
++	dsll	$tmp2,8
++	 dsll	$tmp4,8
++	and	$in0,$tmp0
++	 and	$in1,$tmp0
++	or	$tmp1,$tmp2
++	 or	$tmp3,$tmp4
++	or	$in0,$tmp1
++	 or	$in1,$tmp3
++	dsrl	$tmp1,$in0,32
++	 dsrl	$tmp3,$in1,32
++	dsll	$in0,32
++	 dsll	$in1,32
++	or	$in0,$tmp1
++	 or	$in1,$tmp3
++# endif
++#endif
++	li	$tmp0,1
++	dsll	$tmp0,32		# 0x0000000100000000
++	daddiu	$tmp0,-63		# 0x00000000ffffffc1
++	dsll	$tmp0,28		# 0x0ffffffc10000000
++	daddiu	$tmp0,-1		# 0x0ffffffc0fffffff
++
++	and	$in0,$tmp0
++	daddiu	$tmp0,-3		# 0x0ffffffc0ffffffc
++	and	$in1,$tmp0
++
++	sd	$in0,24($ctx)
++	dsrl	$tmp0,$in1,2
++	sd	$in1,32($ctx)
++	daddu	$tmp0,$in1		# s1 = r1 + (r1 >> 2)
++	sd	$tmp0,40($ctx)
++
++.Lno_key:
++	li	$v0,0			# return 0
++	jr	$ra
++.end	poly1305_init
++___
++{
++my $SAVED_REGS_MASK = ($flavour =~ /nubi/i) ? "0x0003f000" : "0x00030000";
++
++my ($h0,$h1,$h2,$r0,$r1,$rs1,$d0,$d1,$d2) =
++   ($s0,$s1,$s2,$s3,$s4,$s5,$in0,$in1,$t2);
++my ($shr,$shl) = ($s6,$s7);		# used on R6
++
++$code.=<<___;
++.align	5
++.globl	poly1305_blocks
++.ent	poly1305_blocks
++poly1305_blocks:
++	.set	noreorder
++	dsrl	$len,4			# number of complete blocks
++	bnez	$len,poly1305_blocks_internal
++	nop
++	jr	$ra
++	nop
++.end	poly1305_blocks
++
++.align	5
++.ent	poly1305_blocks_internal
++poly1305_blocks_internal:
++	.set	noreorder
++#if defined(_MIPS_ARCH_MIPS64R6)
++	.frame	$sp,8*8,$ra
++	.mask	$SAVED_REGS_MASK|0x000c0000,-8
++	dsubu	$sp,8*8
++	sd	$s7,56($sp)
++	sd	$s6,48($sp)
++#else
++	.frame	$sp,6*8,$ra
++	.mask	$SAVED_REGS_MASK,-8
++	dsubu	$sp,6*8
++#endif
++	sd	$s5,40($sp)
++	sd	$s4,32($sp)
++___
++$code.=<<___ if ($flavour =~ /nubi/i);	# optimize non-nubi prologue
++	sd	$s3,24($sp)
++	sd	$s2,16($sp)
++	sd	$s1,8($sp)
++	sd	$s0,0($sp)
++___
++$code.=<<___;
++	.set	reorder
++
++#if defined(_MIPS_ARCH_MIPS64R6)
++	andi	$shr,$inp,7
++	dsubu	$inp,$inp,$shr		# align $inp
++	sll	$shr,$shr,3		# byte to bit offset
++	subu	$shl,$zero,$shr
++#endif
++
++	ld	$h0,0($ctx)		# load hash value
++	ld	$h1,8($ctx)
++	ld	$h2,16($ctx)
++
++	ld	$r0,24($ctx)		# load key
++	ld	$r1,32($ctx)
++	ld	$rs1,40($ctx)
++
++	dsll	$len,4
++	daddu	$len,$inp		# end of buffer
++	b	.Loop
++
++.align	4
++.Loop:
++#if defined(_MIPS_ARCH_MIPS64R6)
++	ld	$in0,0($inp)		# load input
++	ld	$in1,8($inp)
++	beqz	$shr,.Laligned_inp
++
++	ld	$tmp2,16($inp)
++# ifdef	MIPSEB
++	dsllv	$in0,$in0,$shr
++	dsrlv	$tmp3,$in1,$shl
++	dsllv	$in1,$in1,$shr
++	dsrlv	$tmp2,$tmp2,$shl
++# else
++	dsrlv	$in0,$in0,$shr
++	dsllv	$tmp3,$in1,$shl
++	dsrlv	$in1,$in1,$shr
++	dsllv	$tmp2,$tmp2,$shl
++# endif
++	or	$in0,$in0,$tmp3
++	or	$in1,$in1,$tmp2
++.Laligned_inp:
++#else
++	ldl	$in0,0+MSB($inp)	# load input
++	ldl	$in1,8+MSB($inp)
++	ldr	$in0,0+LSB($inp)
++	ldr	$in1,8+LSB($inp)
++#endif
++	daddiu	$inp,16
++#ifdef	MIPSEB
++# if defined(_MIPS_ARCH_MIPS64R2)
++	dsbh	$in0,$in0		# byte swap
++	 dsbh	$in1,$in1
++	dshd	$in0,$in0
++	 dshd	$in1,$in1
++# else
++	ori	$tmp0,$zero,0xFF
++	dsll	$tmp2,$tmp0,32
++	or	$tmp0,$tmp2		# 0x000000FF000000FF
++
++	and	$tmp1,$in0,$tmp0	# byte swap
++	 and	$tmp3,$in1,$tmp0
++	dsrl	$tmp2,$in0,24
++	 dsrl	$tmp4,$in1,24
++	dsll	$tmp1,24
++	 dsll	$tmp3,24
++	and	$tmp2,$tmp0
++	 and	$tmp4,$tmp0
++	dsll	$tmp0,8			# 0x0000FF000000FF00
++	or	$tmp1,$tmp2
++	 or	$tmp3,$tmp4
++	and	$tmp2,$in0,$tmp0
++	 and	$tmp4,$in1,$tmp0
++	dsrl	$in0,8
++	 dsrl	$in1,8
++	dsll	$tmp2,8
++	 dsll	$tmp4,8
++	and	$in0,$tmp0
++	 and	$in1,$tmp0
++	or	$tmp1,$tmp2
++	 or	$tmp3,$tmp4
++	or	$in0,$tmp1
++	 or	$in1,$tmp3
++	dsrl	$tmp1,$in0,32
++	 dsrl	$tmp3,$in1,32
++	dsll	$in0,32
++	 dsll	$in1,32
++	or	$in0,$tmp1
++	 or	$in1,$tmp3
++# endif
++#endif
++	dsrl	$tmp1,$h2,2		# modulo-scheduled reduction
++	andi	$h2,$h2,3
++	dsll	$tmp0,$tmp1,2
++
++	daddu	$d0,$h0,$in0		# accumulate input
++	 daddu	$tmp1,$tmp0
++	sltu	$tmp0,$d0,$h0
++	daddu	$d0,$d0,$tmp1		# ... and residue
++	sltu	$tmp1,$d0,$tmp1
++	daddu	$d1,$h1,$in1
++	daddu	$tmp0,$tmp1
++	sltu	$tmp1,$d1,$h1
++	daddu	$d1,$tmp0
++
++	dmultu	($r0,$d0)		# h0*r0
++	 daddu	$d2,$h2,$padbit
++	 sltu	$tmp0,$d1,$tmp0
++	mflo	($h0,$r0,$d0)
++	mfhi	($h1,$r0,$d0)
++
++	dmultu	($rs1,$d1)		# h1*5*r1
++	 daddu	$d2,$tmp1
++	 daddu	$d2,$tmp0
++	mflo	($tmp0,$rs1,$d1)
++	mfhi	($tmp1,$rs1,$d1)
++
++	dmultu	($r1,$d0)		# h0*r1
++	mflo	($tmp2,$r1,$d0)
++	mfhi	($h2,$r1,$d0)
++	 daddu	$h0,$tmp0
++	 daddu	$h1,$tmp1
++	 sltu	$tmp0,$h0,$tmp0
++
++	dmultu	($r0,$d1)		# h1*r0
++	 daddu	$h1,$tmp0
++	 daddu	$h1,$tmp2
++	mflo	($tmp0,$r0,$d1)
++	mfhi	($tmp1,$r0,$d1)
++
++	dmultu	($rs1,$d2)		# h2*5*r1
++	 sltu	$tmp2,$h1,$tmp2
++	 daddu	$h2,$tmp2
++	mflo	($tmp2,$rs1,$d2)
++
++	dmultu	($r0,$d2)		# h2*r0
++	 daddu	$h1,$tmp0
++	 daddu	$h2,$tmp1
++	mflo	($tmp3,$r0,$d2)
++	 sltu	$tmp0,$h1,$tmp0
++	 daddu	$h2,$tmp0
++
++	daddu	$h1,$tmp2
++	sltu	$tmp2,$h1,$tmp2
++	daddu	$h2,$tmp2
++	daddu	$h2,$tmp3
++
++	bne	$inp,$len,.Loop
++
++	sd	$h0,0($ctx)		# store hash value
++	sd	$h1,8($ctx)
++	sd	$h2,16($ctx)
++
++	.set	noreorder
++#if defined(_MIPS_ARCH_MIPS64R6)
++	ld	$s7,56($sp)
++	ld	$s6,48($sp)
++#endif
++	ld	$s5,40($sp)		# epilogue
++	ld	$s4,32($sp)
++___
++$code.=<<___ if ($flavour =~ /nubi/i);	# optimize non-nubi epilogue
++	ld	$s3,24($sp)
++	ld	$s2,16($sp)
++	ld	$s1,8($sp)
++	ld	$s0,0($sp)
++___
++$code.=<<___;
++	jr	$ra
++#if defined(_MIPS_ARCH_MIPS64R6)
++	daddu	$sp,8*8
++#else
++	daddu	$sp,6*8
++#endif
++.end	poly1305_blocks_internal
++___
++}
++{
++my ($ctx,$mac,$nonce) = ($a0,$a1,$a2);
++
++$code.=<<___;
++.align	5
++.globl	poly1305_emit
++.ent	poly1305_emit
++poly1305_emit:
++	.frame	$sp,0,$ra
++	.set	reorder
++
++	ld	$tmp2,16($ctx)
++	ld	$tmp0,0($ctx)
++	ld	$tmp1,8($ctx)
++
++	li	$in0,-4			# final reduction
++	dsrl	$in1,$tmp2,2
++	and	$in0,$tmp2
++	andi	$tmp2,$tmp2,3
++	daddu	$in0,$in1
++
++	daddu	$tmp0,$tmp0,$in0
++	sltu	$in1,$tmp0,$in0
++	 daddiu	$in0,$tmp0,5		# compare to modulus
++	daddu	$tmp1,$tmp1,$in1
++	 sltiu	$tmp3,$in0,5
++	sltu	$tmp4,$tmp1,$in1
++	 daddu	$in1,$tmp1,$tmp3
++	daddu	$tmp2,$tmp2,$tmp4
++	 sltu	$tmp3,$in1,$tmp3
++	 daddu	$tmp2,$tmp2,$tmp3
++
++	dsrl	$tmp2,2			# see if it carried/borrowed
++	dsubu	$tmp2,$zero,$tmp2
++
++	xor	$in0,$tmp0
++	xor	$in1,$tmp1
++	and	$in0,$tmp2
++	and	$in1,$tmp2
++	xor	$in0,$tmp0
++	xor	$in1,$tmp1
++
++	lwu	$tmp0,0($nonce)		# load nonce
++	lwu	$tmp1,4($nonce)
++	lwu	$tmp2,8($nonce)
++	lwu	$tmp3,12($nonce)
++	dsll	$tmp1,32
++	dsll	$tmp3,32
++	or	$tmp0,$tmp1
++	or	$tmp2,$tmp3
++
++	daddu	$in0,$tmp0		# accumulate nonce
++	daddu	$in1,$tmp2
++	sltu	$tmp0,$in0,$tmp0
++	daddu	$in1,$tmp0
++
++	dsrl	$tmp0,$in0,8		# write mac value
++	dsrl	$tmp1,$in0,16
++	dsrl	$tmp2,$in0,24
++	sb	$in0,0($mac)
++	dsrl	$tmp3,$in0,32
++	sb	$tmp0,1($mac)
++	dsrl	$tmp0,$in0,40
++	sb	$tmp1,2($mac)
++	dsrl	$tmp1,$in0,48
++	sb	$tmp2,3($mac)
++	dsrl	$tmp2,$in0,56
++	sb	$tmp3,4($mac)
++	dsrl	$tmp3,$in1,8
++	sb	$tmp0,5($mac)
++	dsrl	$tmp0,$in1,16
++	sb	$tmp1,6($mac)
++	dsrl	$tmp1,$in1,24
++	sb	$tmp2,7($mac)
++
++	sb	$in1,8($mac)
++	dsrl	$tmp2,$in1,32
++	sb	$tmp3,9($mac)
++	dsrl	$tmp3,$in1,40
++	sb	$tmp0,10($mac)
++	dsrl	$tmp0,$in1,48
++	sb	$tmp1,11($mac)
++	dsrl	$tmp1,$in1,56
++	sb	$tmp2,12($mac)
++	sb	$tmp3,13($mac)
++	sb	$tmp0,14($mac)
++	sb	$tmp1,15($mac)
++
++	jr	$ra
++.end	poly1305_emit
++.rdata
++.asciiz	"Poly1305 for MIPS64, CRYPTOGAMS by \@dot-asm"
++.align	2
++___
++}
++}}} else {{{
++######################################################################
++# 32-bit code path
++#
++
++my ($ctx,$inp,$len,$padbit) = ($a0,$a1,$a2,$a3);
++my ($in0,$in1,$in2,$in3,$tmp0,$tmp1,$tmp2,$tmp3) =
++   ($a4,$a5,$a6,$a7,$at,$t0,$t1,$t2);
++
++$code.=<<___;
++#if (defined(_MIPS_ARCH_MIPS32R3) || defined(_MIPS_ARCH_MIPS32R5) || \\
++     defined(_MIPS_ARCH_MIPS32R6)) \\
++     && !defined(_MIPS_ARCH_MIPS32R2)
++# define _MIPS_ARCH_MIPS32R2
++#endif
++
++#if defined(_MIPS_ARCH_MIPS32R6)
++# define multu(rs,rt)
++# define mflo(rd,rs,rt)	mulu	rd,rs,rt
++# define mfhi(rd,rs,rt)	muhu	rd,rs,rt
++#else
++# define multu(rs,rt)	multu	rs,rt
++# define mflo(rd,rs,rt)	mflo	rd
++# define mfhi(rd,rs,rt)	mfhi	rd
++#endif
++
++#ifdef	__KERNEL__
++# define poly1305_init   poly1305_init_mips
++# define poly1305_blocks poly1305_blocks_mips
++# define poly1305_emit   poly1305_emit_mips
++#endif
++
++#if defined(__MIPSEB__) && !defined(MIPSEB)
++# define MIPSEB
++#endif
++
++#ifdef MIPSEB
++# define MSB 0
++# define LSB 3
++#else
++# define MSB 3
++# define LSB 0
++#endif
++
++.text
++.set	noat
++.set	noreorder
++
++.align	5
++.globl	poly1305_init
++.ent	poly1305_init
++poly1305_init:
++	.frame	$sp,0,$ra
++	.set	reorder
++
++	sw	$zero,0($ctx)
++	sw	$zero,4($ctx)
++	sw	$zero,8($ctx)
++	sw	$zero,12($ctx)
++	sw	$zero,16($ctx)
++
++	beqz	$inp,.Lno_key
++
++#if defined(_MIPS_ARCH_MIPS32R6)
++	andi	$tmp0,$inp,3		# $inp % 4
++	subu	$inp,$inp,$tmp0		# align $inp
++	sll	$tmp0,$tmp0,3		# byte to bit offset
++	lw	$in0,0($inp)
++	lw	$in1,4($inp)
++	lw	$in2,8($inp)
++	lw	$in3,12($inp)
++	beqz	$tmp0,.Laligned_key
++
++	lw	$tmp2,16($inp)
++	subu	$tmp1,$zero,$tmp0
++# ifdef	MIPSEB
++	sllv	$in0,$in0,$tmp0
++	srlv	$tmp3,$in1,$tmp1
++	sllv	$in1,$in1,$tmp0
++	or	$in0,$in0,$tmp3
++	srlv	$tmp3,$in2,$tmp1
++	sllv	$in2,$in2,$tmp0
++	or	$in1,$in1,$tmp3
++	srlv	$tmp3,$in3,$tmp1
++	sllv	$in3,$in3,$tmp0
++	or	$in2,$in2,$tmp3
++	srlv	$tmp2,$tmp2,$tmp1
++	or	$in3,$in3,$tmp2
++# else
++	srlv	$in0,$in0,$tmp0
++	sllv	$tmp3,$in1,$tmp1
++	srlv	$in1,$in1,$tmp0
++	or	$in0,$in0,$tmp3
++	sllv	$tmp3,$in2,$tmp1
++	srlv	$in2,$in2,$tmp0
++	or	$in1,$in1,$tmp3
++	sllv	$tmp3,$in3,$tmp1
++	srlv	$in3,$in3,$tmp0
++	or	$in2,$in2,$tmp3
++	sllv	$tmp2,$tmp2,$tmp1
++	or	$in3,$in3,$tmp2
++# endif
++.Laligned_key:
++#else
++	lwl	$in0,0+MSB($inp)
++	lwl	$in1,4+MSB($inp)
++	lwl	$in2,8+MSB($inp)
++	lwl	$in3,12+MSB($inp)
++	lwr	$in0,0+LSB($inp)
++	lwr	$in1,4+LSB($inp)
++	lwr	$in2,8+LSB($inp)
++	lwr	$in3,12+LSB($inp)
++#endif
++#ifdef	MIPSEB
++# if defined(_MIPS_ARCH_MIPS32R2)
++	wsbh	$in0,$in0		# byte swap
++	wsbh	$in1,$in1
++	wsbh	$in2,$in2
++	wsbh	$in3,$in3
++	rotr	$in0,$in0,16
++	rotr	$in1,$in1,16
++	rotr	$in2,$in2,16
++	rotr	$in3,$in3,16
++# else
++	srl	$tmp0,$in0,24		# byte swap
++	srl	$tmp1,$in0,8
++	andi	$tmp2,$in0,0xFF00
++	sll	$in0,$in0,24
++	andi	$tmp1,0xFF00
++	sll	$tmp2,$tmp2,8
++	or	$in0,$tmp0
++	 srl	$tmp0,$in1,24
++	or	$tmp1,$tmp2
++	 srl	$tmp2,$in1,8
++	or	$in0,$tmp1
++	 andi	$tmp1,$in1,0xFF00
++	 sll	$in1,$in1,24
++	 andi	$tmp2,0xFF00
++	 sll	$tmp1,$tmp1,8
++	 or	$in1,$tmp0
++	srl	$tmp0,$in2,24
++	 or	$tmp2,$tmp1
++	srl	$tmp1,$in2,8
++	 or	$in1,$tmp2
++	andi	$tmp2,$in2,0xFF00
++	sll	$in2,$in2,24
++	andi	$tmp1,0xFF00
++	sll	$tmp2,$tmp2,8
++	or	$in2,$tmp0
++	 srl	$tmp0,$in3,24
++	or	$tmp1,$tmp2
++	 srl	$tmp2,$in3,8
++	or	$in2,$tmp1
++	 andi	$tmp1,$in3,0xFF00
++	 sll	$in3,$in3,24
++	 andi	$tmp2,0xFF00
++	 sll	$tmp1,$tmp1,8
++	 or	$in3,$tmp0
++	 or	$tmp2,$tmp1
++	 or	$in3,$tmp2
++# endif
++#endif
++	lui	$tmp0,0x0fff
++	ori	$tmp0,0xffff		# 0x0fffffff
++	and	$in0,$in0,$tmp0
++	subu	$tmp0,3			# 0x0ffffffc
++	and	$in1,$in1,$tmp0
++	and	$in2,$in2,$tmp0
++	and	$in3,$in3,$tmp0
++
++	sw	$in0,20($ctx)
++	sw	$in1,24($ctx)
++	sw	$in2,28($ctx)
++	sw	$in3,32($ctx)
++
++	srl	$tmp1,$in1,2
++	srl	$tmp2,$in2,2
++	srl	$tmp3,$in3,2
++	addu	$in1,$in1,$tmp1		# s1 = r1 + (r1 >> 2)
++	addu	$in2,$in2,$tmp2
++	addu	$in3,$in3,$tmp3
++	sw	$in1,36($ctx)
++	sw	$in2,40($ctx)
++	sw	$in3,44($ctx)
++.Lno_key:
++	li	$v0,0
++	jr	$ra
++.end	poly1305_init
++___
++{
++my $SAVED_REGS_MASK = ($flavour =~ /nubi/i) ? "0x00fff000" : "0x00ff0000";
++
++my ($h0,$h1,$h2,$h3,$h4, $r0,$r1,$r2,$r3, $rs1,$rs2,$rs3) =
++   ($s0,$s1,$s2,$s3,$s4, $s5,$s6,$s7,$s8, $s9,$s10,$s11);
++my ($d0,$d1,$d2,$d3) =
++   ($a4,$a5,$a6,$a7);
++my $shr = $t2;		# used on R6
++my $one = $t2;		# used on R2
++
++$code.=<<___;
++.globl	poly1305_blocks
++.align	5
++.ent	poly1305_blocks
++poly1305_blocks:
++	.frame	$sp,16*4,$ra
++	.mask	$SAVED_REGS_MASK,-4
++	.set	noreorder
++	subu	$sp, $sp,4*12
++	sw	$s11,4*11($sp)
++	sw	$s10,4*10($sp)
++	sw	$s9, 4*9($sp)
++	sw	$s8, 4*8($sp)
++	sw	$s7, 4*7($sp)
++	sw	$s6, 4*6($sp)
++	sw	$s5, 4*5($sp)
++	sw	$s4, 4*4($sp)
++___
++$code.=<<___ if ($flavour =~ /nubi/i);	# optimize non-nubi prologue
++	sw	$s3, 4*3($sp)
++	sw	$s2, 4*2($sp)
++	sw	$s1, 4*1($sp)
++	sw	$s0, 4*0($sp)
++___
++$code.=<<___;
++	.set	reorder
++
++	srl	$len,4			# number of complete blocks
++	li	$one,1
++	beqz	$len,.Labort
++
++#if defined(_MIPS_ARCH_MIPS32R6)
++	andi	$shr,$inp,3
++	subu	$inp,$inp,$shr		# align $inp
++	sll	$shr,$shr,3		# byte to bit offset
++#endif
++
++	lw	$h0,0($ctx)		# load hash value
++	lw	$h1,4($ctx)
++	lw	$h2,8($ctx)
++	lw	$h3,12($ctx)
++	lw	$h4,16($ctx)
++
++	lw	$r0,20($ctx)		# load key
++	lw	$r1,24($ctx)
++	lw	$r2,28($ctx)
++	lw	$r3,32($ctx)
++	lw	$rs1,36($ctx)
++	lw	$rs2,40($ctx)
++	lw	$rs3,44($ctx)
++
++	sll	$len,4
++	addu	$len,$len,$inp		# end of buffer
++	b	.Loop
++
++.align	4
++.Loop:
++#if defined(_MIPS_ARCH_MIPS32R6)
++	lw	$d0,0($inp)		# load input
++	lw	$d1,4($inp)
++	lw	$d2,8($inp)
++	lw	$d3,12($inp)
++	beqz	$shr,.Laligned_inp
++
++	lw	$t0,16($inp)
++	subu	$t1,$zero,$shr
++# ifdef	MIPSEB
++	sllv	$d0,$d0,$shr
++	srlv	$at,$d1,$t1
++	sllv	$d1,$d1,$shr
++	or	$d0,$d0,$at
++	srlv	$at,$d2,$t1
++	sllv	$d2,$d2,$shr
++	or	$d1,$d1,$at
++	srlv	$at,$d3,$t1
++	sllv	$d3,$d3,$shr
++	or	$d2,$d2,$at
++	srlv	$t0,$t0,$t1
++	or	$d3,$d3,$t0
++# else
++	srlv	$d0,$d0,$shr
++	sllv	$at,$d1,$t1
++	srlv	$d1,$d1,$shr
++	or	$d0,$d0,$at
++	sllv	$at,$d2,$t1
++	srlv	$d2,$d2,$shr
++	or	$d1,$d1,$at
++	sllv	$at,$d3,$t1
++	srlv	$d3,$d3,$shr
++	or	$d2,$d2,$at
++	sllv	$t0,$t0,$t1
++	or	$d3,$d3,$t0
++# endif
++.Laligned_inp:
++#else
++	lwl	$d0,0+MSB($inp)		# load input
++	lwl	$d1,4+MSB($inp)
++	lwl	$d2,8+MSB($inp)
++	lwl	$d3,12+MSB($inp)
++	lwr	$d0,0+LSB($inp)
++	lwr	$d1,4+LSB($inp)
++	lwr	$d2,8+LSB($inp)
++	lwr	$d3,12+LSB($inp)
++#endif
++#ifdef	MIPSEB
++# if defined(_MIPS_ARCH_MIPS32R2)
++	wsbh	$d0,$d0			# byte swap
++	wsbh	$d1,$d1
++	wsbh	$d2,$d2
++	wsbh	$d3,$d3
++	rotr	$d0,$d0,16
++	rotr	$d1,$d1,16
++	rotr	$d2,$d2,16
++	rotr	$d3,$d3,16
++# else
++	srl	$at,$d0,24		# byte swap
++	srl	$t0,$d0,8
++	andi	$t1,$d0,0xFF00
++	sll	$d0,$d0,24
++	andi	$t0,0xFF00
++	sll	$t1,$t1,8
++	or	$d0,$at
++	 srl	$at,$d1,24
++	or	$t0,$t1
++	 srl	$t1,$d1,8
++	or	$d0,$t0
++	 andi	$t0,$d1,0xFF00
++	 sll	$d1,$d1,24
++	 andi	$t1,0xFF00
++	 sll	$t0,$t0,8
++	 or	$d1,$at
++	srl	$at,$d2,24
++	 or	$t1,$t0
++	srl	$t0,$d2,8
++	 or	$d1,$t1
++	andi	$t1,$d2,0xFF00
++	sll	$d2,$d2,24
++	andi	$t0,0xFF00
++	sll	$t1,$t1,8
++	or	$d2,$at
++	 srl	$at,$d3,24
++	or	$t0,$t1
++	 srl	$t1,$d3,8
++	or	$d2,$t0
++	 andi	$t0,$d3,0xFF00
++	 sll	$d3,$d3,24
++	 andi	$t1,0xFF00
++	 sll	$t0,$t0,8
++	 or	$d3,$at
++	 or	$t1,$t0
++	 or	$d3,$t1
++# endif
++#endif
++	srl	$t0,$h4,2		# modulo-scheduled reduction
++	andi	$h4,$h4,3
++	sll	$at,$t0,2
++
++	addu	$d0,$d0,$h0		# accumulate input
++	 addu	$t0,$t0,$at
++	sltu	$h0,$d0,$h0
++	addu	$d0,$d0,$t0		# ... and residue
++	sltu	$at,$d0,$t0
++
++	addu	$d1,$d1,$h1
++	 addu	$h0,$h0,$at		# carry
++	sltu	$h1,$d1,$h1
++	addu	$d1,$d1,$h0
++	sltu	$h0,$d1,$h0
++
++	addu	$d2,$d2,$h2
++	 addu	$h1,$h1,$h0		# carry
++	sltu	$h2,$d2,$h2
++	addu	$d2,$d2,$h1
++	sltu	$h1,$d2,$h1
++
++	addu	$d3,$d3,$h3
++	 addu	$h2,$h2,$h1		# carry
++	sltu	$h3,$d3,$h3
++	addu	$d3,$d3,$h2
++
++#if defined(_MIPS_ARCH_MIPS32R2) && !defined(_MIPS_ARCH_MIPS32R6)
++	multu	$r0,$d0			# d0*r0
++	 sltu	$h2,$d3,$h2
++	maddu	$rs3,$d1		# d1*s3
++	 addu	$h3,$h3,$h2		# carry
++	maddu	$rs2,$d2		# d2*s2
++	 addu	$h4,$h4,$padbit
++	maddu	$rs1,$d3		# d3*s1
++	 addu	$h4,$h4,$h3
++	mfhi	$at
++	mflo	$h0
++
++	multu	$r1,$d0			# d0*r1
++	maddu	$r0,$d1			# d1*r0
++	maddu	$rs3,$d2		# d2*s3
++	maddu	$rs2,$d3		# d3*s2
++	maddu	$rs1,$h4		# h4*s1
++	maddu	$at,$one		# hi*1
++	mfhi	$at
++	mflo	$h1
++
++	multu	$r2,$d0			# d0*r2
++	maddu	$r1,$d1			# d1*r1
++	maddu	$r0,$d2			# d2*r0
++	maddu	$rs3,$d3		# d3*s3
++	maddu	$rs2,$h4		# h4*s2
++	maddu	$at,$one		# hi*1
++	mfhi	$at
++	mflo	$h2
++
++	mul	$t0,$r0,$h4		# h4*r0
++
++	multu	$r3,$d0			# d0*r3
++	maddu	$r2,$d1			# d1*r2
++	maddu	$r1,$d2			# d2*r1
++	maddu	$r0,$d3			# d3*r0
++	maddu	$rs3,$h4		# h4*s3
++	maddu	$at,$one		# hi*1
++	mfhi	$at
++	mflo	$h3
++
++	 addiu	$inp,$inp,16
++
++	addu	$h4,$t0,$at
++#else
++	multu	($r0,$d0)		# d0*r0
++	mflo	($h0,$r0,$d0)
++	mfhi	($h1,$r0,$d0)
++
++	 sltu	$h2,$d3,$h2
++	 addu	$h3,$h3,$h2		# carry
++
++	multu	($rs3,$d1)		# d1*s3
++	mflo	($at,$rs3,$d1)
++	mfhi	($t0,$rs3,$d1)
++
++	 addu	$h4,$h4,$padbit
++	 addiu	$inp,$inp,16
++	 addu	$h4,$h4,$h3
++
++	multu	($rs2,$d2)		# d2*s2
++	mflo	($a3,$rs2,$d2)
++	mfhi	($t1,$rs2,$d2)
++	 addu	$h0,$h0,$at
++	 addu	$h1,$h1,$t0
++	multu	($rs1,$d3)		# d3*s1
++	 sltu	$at,$h0,$at
++	 addu	$h1,$h1,$at
++
++	mflo	($at,$rs1,$d3)
++	mfhi	($t0,$rs1,$d3)
++	 addu	$h0,$h0,$a3
++	 addu	$h1,$h1,$t1
++	multu	($r1,$d0)		# d0*r1
++	 sltu	$a3,$h0,$a3
++	 addu	$h1,$h1,$a3
++
++
++	mflo	($a3,$r1,$d0)
++	mfhi	($h2,$r1,$d0)
++	 addu	$h0,$h0,$at
++	 addu	$h1,$h1,$t0
++	multu	($r0,$d1)		# d1*r0
++	 sltu	$at,$h0,$at
++	 addu	$h1,$h1,$at
++
++	mflo	($at,$r0,$d1)
++	mfhi	($t0,$r0,$d1)
++	 addu	$h1,$h1,$a3
++	 sltu	$a3,$h1,$a3
++	multu	($rs3,$d2)		# d2*s3
++	 addu	$h2,$h2,$a3
++
++	mflo	($a3,$rs3,$d2)
++	mfhi	($t1,$rs3,$d2)
++	 addu	$h1,$h1,$at
++	 addu	$h2,$h2,$t0
++	multu	($rs2,$d3)		# d3*s2
++	 sltu	$at,$h1,$at
++	 addu	$h2,$h2,$at
++
++	mflo	($at,$rs2,$d3)
++	mfhi	($t0,$rs2,$d3)
++	 addu	$h1,$h1,$a3
++	 addu	$h2,$h2,$t1
++	multu	($rs1,$h4)		# h4*s1
++	 sltu	$a3,$h1,$a3
++	 addu	$h2,$h2,$a3
++
++	mflo	($a3,$rs1,$h4)
++	 addu	$h1,$h1,$at
++	 addu	$h2,$h2,$t0
++	multu	($r2,$d0)		# d0*r2
++	 sltu	$at,$h1,$at
++	 addu	$h2,$h2,$at
++
++
++	mflo	($at,$r2,$d0)
++	mfhi	($h3,$r2,$d0)
++	 addu	$h1,$h1,$a3
++	 sltu	$a3,$h1,$a3
++	multu	($r1,$d1)		# d1*r1
++	 addu	$h2,$h2,$a3
++
++	mflo	($a3,$r1,$d1)
++	mfhi	($t1,$r1,$d1)
++	 addu	$h2,$h2,$at
++	 sltu	$at,$h2,$at
++	multu	($r0,$d2)		# d2*r0
++	 addu	$h3,$h3,$at
++
++	mflo	($at,$r0,$d2)
++	mfhi	($t0,$r0,$d2)
++	 addu	$h2,$h2,$a3
++	 addu	$h3,$h3,$t1
++	multu	($rs3,$d3)		# d3*s3
++	 sltu	$a3,$h2,$a3
++	 addu	$h3,$h3,$a3
++
++	mflo	($a3,$rs3,$d3)
++	mfhi	($t1,$rs3,$d3)
++	 addu	$h2,$h2,$at
++	 addu	$h3,$h3,$t0
++	multu	($rs2,$h4)		# h4*s2
++	 sltu	$at,$h2,$at
++	 addu	$h3,$h3,$at
++
++	mflo	($at,$rs2,$h4)
++	 addu	$h2,$h2,$a3
++	 addu	$h3,$h3,$t1
++	multu	($r3,$d0)		# d0*r3
++	 sltu	$a3,$h2,$a3
++	 addu	$h3,$h3,$a3
++
++
++	mflo	($a3,$r3,$d0)
++	mfhi	($t1,$r3,$d0)
++	 addu	$h2,$h2,$at
++	 sltu	$at,$h2,$at
++	multu	($r2,$d1)		# d1*r2
++	 addu	$h3,$h3,$at
++
++	mflo	($at,$r2,$d1)
++	mfhi	($t0,$r2,$d1)
++	 addu	$h3,$h3,$a3
++	 sltu	$a3,$h3,$a3
++	multu	($r0,$d3)		# d3*r0
++	 addu	$t1,$t1,$a3
++
++	mflo	($a3,$r0,$d3)
++	mfhi	($d3,$r0,$d3)
++	 addu	$h3,$h3,$at
++	 addu	$t1,$t1,$t0
++	multu	($r1,$d2)		# d2*r1
++	 sltu	$at,$h3,$at
++	 addu	$t1,$t1,$at
++
++	mflo	($at,$r1,$d2)
++	mfhi	($t0,$r1,$d2)
++	 addu	$h3,$h3,$a3
++	 addu	$t1,$t1,$d3
++	multu	($rs3,$h4)		# h4*s3
++	 sltu	$a3,$h3,$a3
++	 addu	$t1,$t1,$a3
++
++	mflo	($a3,$rs3,$h4)
++	 addu	$h3,$h3,$at
++	 addu	$t1,$t1,$t0
++	multu	($r0,$h4)		# h4*r0
++	 sltu	$at,$h3,$at
++	 addu	$t1,$t1,$at
++
++
++	mflo	($h4,$r0,$h4)
++	 addu	$h3,$h3,$a3
++	 sltu	$a3,$h3,$a3
++	 addu	$t1,$t1,$a3
++	addu	$h4,$h4,$t1
++
++	li	$padbit,1		# if we loop, padbit is 1
++#endif
++	bne	$inp,$len,.Loop
++
++	sw	$h0,0($ctx)		# store hash value
++	sw	$h1,4($ctx)
++	sw	$h2,8($ctx)
++	sw	$h3,12($ctx)
++	sw	$h4,16($ctx)
++
++	.set	noreorder
++.Labort:
++	lw	$s11,4*11($sp)
++	lw	$s10,4*10($sp)
++	lw	$s9, 4*9($sp)
++	lw	$s8, 4*8($sp)
++	lw	$s7, 4*7($sp)
++	lw	$s6, 4*6($sp)
++	lw	$s5, 4*5($sp)
++	lw	$s4, 4*4($sp)
++___
++$code.=<<___ if ($flavour =~ /nubi/i);	# optimize non-nubi prologue
++	lw	$s3, 4*3($sp)
++	lw	$s2, 4*2($sp)
++	lw	$s1, 4*1($sp)
++	lw	$s0, 4*0($sp)
++___
++$code.=<<___;
++	jr	$ra
++	addu	$sp,$sp,4*12
++.end	poly1305_blocks
++___
++}
++{
++my ($ctx,$mac,$nonce,$tmp4) = ($a0,$a1,$a2,$a3);
++
++$code.=<<___;
++.align	5
++.globl	poly1305_emit
++.ent	poly1305_emit
++poly1305_emit:
++	.frame	$sp,0,$ra
++	.set	reorder
++
++	lw	$tmp4,16($ctx)
++	lw	$tmp0,0($ctx)
++	lw	$tmp1,4($ctx)
++	lw	$tmp2,8($ctx)
++	lw	$tmp3,12($ctx)
++
++	li	$in0,-4			# final reduction
++	srl	$ctx,$tmp4,2
++	and	$in0,$in0,$tmp4
++	andi	$tmp4,$tmp4,3
++	addu	$ctx,$ctx,$in0
++
++	addu	$tmp0,$tmp0,$ctx
++	sltu	$ctx,$tmp0,$ctx
++	 addiu	$in0,$tmp0,5		# compare to modulus
++	addu	$tmp1,$tmp1,$ctx
++	 sltiu	$in1,$in0,5
++	sltu	$ctx,$tmp1,$ctx
++	 addu	$in1,$in1,$tmp1
++	addu	$tmp2,$tmp2,$ctx
++	 sltu	$in2,$in1,$tmp1
++	sltu	$ctx,$tmp2,$ctx
++	 addu	$in2,$in2,$tmp2
++	addu	$tmp3,$tmp3,$ctx
++	 sltu	$in3,$in2,$tmp2
++	sltu	$ctx,$tmp3,$ctx
++	 addu	$in3,$in3,$tmp3
++	addu	$tmp4,$tmp4,$ctx
++	 sltu	$ctx,$in3,$tmp3
++	 addu	$ctx,$tmp4
++
++	srl	$ctx,2			# see if it carried/borrowed
++	subu	$ctx,$zero,$ctx
++
++	xor	$in0,$tmp0
++	xor	$in1,$tmp1
++	xor	$in2,$tmp2
++	xor	$in3,$tmp3
++	and	$in0,$ctx
++	and	$in1,$ctx
++	and	$in2,$ctx
++	and	$in3,$ctx
++	xor	$in0,$tmp0
++	xor	$in1,$tmp1
++	xor	$in2,$tmp2
++	xor	$in3,$tmp3
++
++	lw	$tmp0,0($nonce)		# load nonce
++	lw	$tmp1,4($nonce)
++	lw	$tmp2,8($nonce)
++	lw	$tmp3,12($nonce)
++
++	addu	$in0,$tmp0		# accumulate nonce
++	sltu	$ctx,$in0,$tmp0
++
++	addu	$in1,$tmp1
++	sltu	$tmp1,$in1,$tmp1
++	addu	$in1,$ctx
++	sltu	$ctx,$in1,$ctx
++	addu	$ctx,$tmp1
++
++	addu	$in2,$tmp2
++	sltu	$tmp2,$in2,$tmp2
++	addu	$in2,$ctx
++	sltu	$ctx,$in2,$ctx
++	addu	$ctx,$tmp2
++
++	addu	$in3,$tmp3
++	addu	$in3,$ctx
++
++	srl	$tmp0,$in0,8		# write mac value
++	srl	$tmp1,$in0,16
++	srl	$tmp2,$in0,24
++	sb	$in0, 0($mac)
++	sb	$tmp0,1($mac)
++	srl	$tmp0,$in1,8
++	sb	$tmp1,2($mac)
++	srl	$tmp1,$in1,16
++	sb	$tmp2,3($mac)
++	srl	$tmp2,$in1,24
++	sb	$in1, 4($mac)
++	sb	$tmp0,5($mac)
++	srl	$tmp0,$in2,8
++	sb	$tmp1,6($mac)
++	srl	$tmp1,$in2,16
++	sb	$tmp2,7($mac)
++	srl	$tmp2,$in2,24
++	sb	$in2, 8($mac)
++	sb	$tmp0,9($mac)
++	srl	$tmp0,$in3,8
++	sb	$tmp1,10($mac)
++	srl	$tmp1,$in3,16
++	sb	$tmp2,11($mac)
++	srl	$tmp2,$in3,24
++	sb	$in3, 12($mac)
++	sb	$tmp0,13($mac)
++	sb	$tmp1,14($mac)
++	sb	$tmp2,15($mac)
++
++	jr	$ra
++.end	poly1305_emit
++.rdata
++.asciiz	"Poly1305 for MIPS32, CRYPTOGAMS by \@dot-asm"
++.align	2
++___
++}
++}}}
++
++$output=pop and open STDOUT,">$output";
++print $code;
++close STDOUT;
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -707,6 +707,11 @@ config CRYPTO_POLY1305_X86_64
+ 	  in IETF protocols. This is the x86_64 assembler implementation using SIMD
+ 	  instructions.
+ 
++config CRYPTO_POLY1305_MIPS
++	tristate "Poly1305 authenticator algorithm (MIPS optimized)"
++	depends on CPU_MIPS32 || (CPU_MIPS64 && 64BIT)
++	select CRYPTO_ARCH_HAVE_LIB_POLY1305
++
+ config CRYPTO_MD4
+ 	tristate "MD4 digest algorithm"
+ 	select CRYPTO_HASH
+--- a/lib/crypto/Kconfig
++++ b/lib/crypto/Kconfig
+@@ -39,6 +39,7 @@ config CRYPTO_LIB_DES
+ 
+ config CRYPTO_LIB_POLY1305_RSIZE
+ 	int
++	default 2 if MIPS
+ 	default 4 if X86_64
+ 	default 9 if ARM || ARM64
+ 	default 1
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0021-crypto-blake2s-generic-C-library-implementation-and-.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0021-crypto-blake2s-generic-C-library-implementation-and-.patch
new file mode 100644
index 0000000..97f73b9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0021-crypto-blake2s-generic-C-library-implementation-and-.patch
@@ -0,0 +1,1097 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 8 Nov 2019 13:22:28 +0100
+Subject: [PATCH] crypto: blake2s - generic C library implementation and
+ selftest
+
+commit 66d7fb94e4ffe5acc589e0b2b4710aecc1f07a28 upstream.
+
+The C implementation was originally based on Samuel Neves' public
+domain reference implementation but has since been heavily modified
+for the kernel. We're able to do compile-time optimizations by moving
+some scaffolding around the final function into the header file.
+
+Information: https://blake2.net/
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Samuel Neves <sneves@dei.uc.pt>
+Co-developed-by: Samuel Neves <sneves@dei.uc.pt>
+[ardb: - move from lib/zinc to lib/crypto
+       - remove simd handling
+       - rewrote selftest for better coverage
+       - use fixed digest length for blake2s_hmac() and rename to
+         blake2s256_hmac() ]
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ include/crypto/blake2s.h          | 106 +++++
+ include/crypto/internal/blake2s.h |  19 +
+ lib/crypto/Kconfig                |  25 ++
+ lib/crypto/Makefile               |  10 +
+ lib/crypto/blake2s-generic.c      | 111 ++++++
+ lib/crypto/blake2s-selftest.c     | 622 ++++++++++++++++++++++++++++++
+ lib/crypto/blake2s.c              | 126 ++++++
+ 7 files changed, 1019 insertions(+)
+ create mode 100644 include/crypto/blake2s.h
+ create mode 100644 include/crypto/internal/blake2s.h
+ create mode 100644 lib/crypto/blake2s-generic.c
+ create mode 100644 lib/crypto/blake2s-selftest.c
+ create mode 100644 lib/crypto/blake2s.c
+
+--- /dev/null
++++ b/include/crypto/blake2s.h
+@@ -0,0 +1,106 @@
++/* SPDX-License-Identifier: GPL-2.0 OR MIT */
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#ifndef BLAKE2S_H
++#define BLAKE2S_H
++
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++
++#include <asm/bug.h>
++
++enum blake2s_lengths {
++	BLAKE2S_BLOCK_SIZE = 64,
++	BLAKE2S_HASH_SIZE = 32,
++	BLAKE2S_KEY_SIZE = 32,
++
++	BLAKE2S_128_HASH_SIZE = 16,
++	BLAKE2S_160_HASH_SIZE = 20,
++	BLAKE2S_224_HASH_SIZE = 28,
++	BLAKE2S_256_HASH_SIZE = 32,
++};
++
++struct blake2s_state {
++	u32 h[8];
++	u32 t[2];
++	u32 f[2];
++	u8 buf[BLAKE2S_BLOCK_SIZE];
++	unsigned int buflen;
++	unsigned int outlen;
++};
++
++enum blake2s_iv {
++	BLAKE2S_IV0 = 0x6A09E667UL,
++	BLAKE2S_IV1 = 0xBB67AE85UL,
++	BLAKE2S_IV2 = 0x3C6EF372UL,
++	BLAKE2S_IV3 = 0xA54FF53AUL,
++	BLAKE2S_IV4 = 0x510E527FUL,
++	BLAKE2S_IV5 = 0x9B05688CUL,
++	BLAKE2S_IV6 = 0x1F83D9ABUL,
++	BLAKE2S_IV7 = 0x5BE0CD19UL,
++};
++
++void blake2s_update(struct blake2s_state *state, const u8 *in, size_t inlen);
++void blake2s_final(struct blake2s_state *state, u8 *out);
++
++static inline void blake2s_init_param(struct blake2s_state *state,
++				      const u32 param)
++{
++	*state = (struct blake2s_state){{
++		BLAKE2S_IV0 ^ param,
++		BLAKE2S_IV1,
++		BLAKE2S_IV2,
++		BLAKE2S_IV3,
++		BLAKE2S_IV4,
++		BLAKE2S_IV5,
++		BLAKE2S_IV6,
++		BLAKE2S_IV7,
++	}};
++}
++
++static inline void blake2s_init(struct blake2s_state *state,
++				const size_t outlen)
++{
++	blake2s_init_param(state, 0x01010000 | outlen);
++	state->outlen = outlen;
++}
++
++static inline void blake2s_init_key(struct blake2s_state *state,
++				    const size_t outlen, const void *key,
++				    const size_t keylen)
++{
++	WARN_ON(IS_ENABLED(DEBUG) && (!outlen || outlen > BLAKE2S_HASH_SIZE ||
++		!key || !keylen || keylen > BLAKE2S_KEY_SIZE));
++
++	blake2s_init_param(state, 0x01010000 | keylen << 8 | outlen);
++	memcpy(state->buf, key, keylen);
++	state->buflen = BLAKE2S_BLOCK_SIZE;
++	state->outlen = outlen;
++}
++
++static inline void blake2s(u8 *out, const u8 *in, const u8 *key,
++			   const size_t outlen, const size_t inlen,
++			   const size_t keylen)
++{
++	struct blake2s_state state;
++
++	WARN_ON(IS_ENABLED(DEBUG) && ((!in && inlen > 0) || !out || !outlen ||
++		outlen > BLAKE2S_HASH_SIZE || keylen > BLAKE2S_KEY_SIZE ||
++		(!key && keylen)));
++
++	if (keylen)
++		blake2s_init_key(&state, outlen, key, keylen);
++	else
++		blake2s_init(&state, outlen);
++
++	blake2s_update(&state, in, inlen);
++	blake2s_final(&state, out);
++}
++
++void blake2s256_hmac(u8 *out, const u8 *in, const u8 *key, const size_t inlen,
++		     const size_t keylen);
++
++#endif /* BLAKE2S_H */
+--- /dev/null
++++ b/include/crypto/internal/blake2s.h
+@@ -0,0 +1,19 @@
++/* SPDX-License-Identifier: GPL-2.0 OR MIT */
++
++#ifndef BLAKE2S_INTERNAL_H
++#define BLAKE2S_INTERNAL_H
++
++#include <crypto/blake2s.h>
++
++void blake2s_compress_generic(struct blake2s_state *state,const u8 *block,
++			      size_t nblocks, const u32 inc);
++
++void blake2s_compress_arch(struct blake2s_state *state,const u8 *block,
++			   size_t nblocks, const u32 inc);
++
++static inline void blake2s_set_lastblock(struct blake2s_state *state)
++{
++	state->f[0] = -1;
++}
++
++#endif /* BLAKE2S_INTERNAL_H */
+--- a/lib/crypto/Kconfig
++++ b/lib/crypto/Kconfig
+@@ -8,6 +8,31 @@ config CRYPTO_LIB_AES
+ config CRYPTO_LIB_ARC4
+ 	tristate
+ 
++config CRYPTO_ARCH_HAVE_LIB_BLAKE2S
++	tristate
++	help
++	  Declares whether the architecture provides an arch-specific
++	  accelerated implementation of the Blake2s library interface,
++	  either builtin or as a module.
++
++config CRYPTO_LIB_BLAKE2S_GENERIC
++	tristate
++	help
++	  This symbol can be depended upon by arch implementations of the
++	  Blake2s library interface that require the generic code as a
++	  fallback, e.g., for SIMD implementations. If no arch specific
++	  implementation is enabled, this implementation serves the users
++	  of CRYPTO_LIB_BLAKE2S.
++
++config CRYPTO_LIB_BLAKE2S
++	tristate "BLAKE2s hash function library"
++	depends on CRYPTO_ARCH_HAVE_LIB_BLAKE2S || !CRYPTO_ARCH_HAVE_LIB_BLAKE2S
++	select CRYPTO_LIB_BLAKE2S_GENERIC if CRYPTO_ARCH_HAVE_LIB_BLAKE2S=n
++	help
++	  Enable the Blake2s library interface. This interface may be fulfilled
++	  by either the generic implementation or an arch-specific one, if one
++	  is available and enabled.
++
+ config CRYPTO_ARCH_HAVE_LIB_CHACHA
+ 	tristate
+ 	help
+--- a/lib/crypto/Makefile
++++ b/lib/crypto/Makefile
+@@ -10,6 +10,12 @@ libaes-y					:= aes.o
+ obj-$(CONFIG_CRYPTO_LIB_ARC4)			+= libarc4.o
+ libarc4-y					:= arc4.o
+ 
++obj-$(CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC)	+= libblake2s-generic.o
++libblake2s-generic-y				+= blake2s-generic.o
++
++obj-$(CONFIG_CRYPTO_LIB_BLAKE2S)		+= libblake2s.o
++libblake2s-y					+= blake2s.o
++
+ obj-$(CONFIG_CRYPTO_LIB_DES)			+= libdes.o
+ libdes-y					:= des.o
+ 
+@@ -18,3 +24,7 @@ libpoly1305-y					:= poly1305.o
+ 
+ obj-$(CONFIG_CRYPTO_LIB_SHA256)			+= libsha256.o
+ libsha256-y					:= sha256.o
++
++ifneq ($(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS),y)
++libblake2s-y					+= blake2s-selftest.o
++endif
+--- /dev/null
++++ b/lib/crypto/blake2s-generic.c
+@@ -0,0 +1,111 @@
++// SPDX-License-Identifier: GPL-2.0 OR MIT
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ *
++ * This is an implementation of the BLAKE2s hash and PRF functions.
++ *
++ * Information: https://blake2.net/
++ *
++ */
++
++#include <crypto/internal/blake2s.h>
++#include <linux/types.h>
++#include <linux/string.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/bug.h>
++#include <asm/unaligned.h>
++
++static const u8 blake2s_sigma[10][16] = {
++	{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
++	{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
++	{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
++	{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
++	{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
++	{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
++	{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
++	{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
++	{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
++	{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
++};
++
++static inline void blake2s_increment_counter(struct blake2s_state *state,
++					     const u32 inc)
++{
++	state->t[0] += inc;
++	state->t[1] += (state->t[0] < inc);
++}
++
++void blake2s_compress_generic(struct blake2s_state *state,const u8 *block,
++			      size_t nblocks, const u32 inc)
++{
++	u32 m[16];
++	u32 v[16];
++	int i;
++
++	WARN_ON(IS_ENABLED(DEBUG) &&
++		(nblocks > 1 && inc != BLAKE2S_BLOCK_SIZE));
++
++	while (nblocks > 0) {
++		blake2s_increment_counter(state, inc);
++		memcpy(m, block, BLAKE2S_BLOCK_SIZE);
++		le32_to_cpu_array(m, ARRAY_SIZE(m));
++		memcpy(v, state->h, 32);
++		v[ 8] = BLAKE2S_IV0;
++		v[ 9] = BLAKE2S_IV1;
++		v[10] = BLAKE2S_IV2;
++		v[11] = BLAKE2S_IV3;
++		v[12] = BLAKE2S_IV4 ^ state->t[0];
++		v[13] = BLAKE2S_IV5 ^ state->t[1];
++		v[14] = BLAKE2S_IV6 ^ state->f[0];
++		v[15] = BLAKE2S_IV7 ^ state->f[1];
++
++#define G(r, i, a, b, c, d) do { \
++	a += b + m[blake2s_sigma[r][2 * i + 0]]; \
++	d = ror32(d ^ a, 16); \
++	c += d; \
++	b = ror32(b ^ c, 12); \
++	a += b + m[blake2s_sigma[r][2 * i + 1]]; \
++	d = ror32(d ^ a, 8); \
++	c += d; \
++	b = ror32(b ^ c, 7); \
++} while (0)
++
++#define ROUND(r) do { \
++	G(r, 0, v[0], v[ 4], v[ 8], v[12]); \
++	G(r, 1, v[1], v[ 5], v[ 9], v[13]); \
++	G(r, 2, v[2], v[ 6], v[10], v[14]); \
++	G(r, 3, v[3], v[ 7], v[11], v[15]); \
++	G(r, 4, v[0], v[ 5], v[10], v[15]); \
++	G(r, 5, v[1], v[ 6], v[11], v[12]); \
++	G(r, 6, v[2], v[ 7], v[ 8], v[13]); \
++	G(r, 7, v[3], v[ 4], v[ 9], v[14]); \
++} while (0)
++		ROUND(0);
++		ROUND(1);
++		ROUND(2);
++		ROUND(3);
++		ROUND(4);
++		ROUND(5);
++		ROUND(6);
++		ROUND(7);
++		ROUND(8);
++		ROUND(9);
++
++#undef G
++#undef ROUND
++
++		for (i = 0; i < 8; ++i)
++			state->h[i] ^= v[i] ^ v[i + 8];
++
++		block += BLAKE2S_BLOCK_SIZE;
++		--nblocks;
++	}
++}
++
++EXPORT_SYMBOL(blake2s_compress_generic);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("BLAKE2s hash function");
++MODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>");
+--- /dev/null
++++ b/lib/crypto/blake2s-selftest.c
+@@ -0,0 +1,622 @@
++// SPDX-License-Identifier: GPL-2.0 OR MIT
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#include <crypto/blake2s.h>
++#include <linux/string.h>
++
++/*
++ * blake2s_testvecs[] generated with the program below (using libb2-dev and
++ * libssl-dev [OpenSSL])
++ *
++ * #include <blake2.h>
++ * #include <stdint.h>
++ * #include <stdio.h>
++ *
++ * #include <openssl/evp.h>
++ * #include <openssl/hmac.h>
++ *
++ * #define BLAKE2S_TESTVEC_COUNT	256
++ *
++ * static void print_vec(const uint8_t vec[], int len)
++ * {
++ *	int i;
++ *
++ *	printf("  { ");
++ *	for (i = 0; i < len; i++) {
++ *		if (i && (i % 12) == 0)
++ *			printf("\n    ");
++ *		printf("0x%02x, ", vec[i]);
++ *	}
++ *	printf("},\n");
++ * }
++ *
++ * int main(void)
++ * {
++ *	uint8_t key[BLAKE2S_KEYBYTES];
++ *	uint8_t buf[BLAKE2S_TESTVEC_COUNT];
++ *	uint8_t hash[BLAKE2S_OUTBYTES];
++ *	int i, j;
++ *
++ *	key[0] = key[1] = 1;
++ *	for (i = 2; i < BLAKE2S_KEYBYTES; ++i)
++ *		key[i] = key[i - 2] + key[i - 1];
++ *
++ *	for (i = 0; i < BLAKE2S_TESTVEC_COUNT; ++i)
++ *		buf[i] = (uint8_t)i;
++ *
++ *	printf("static const u8 blake2s_testvecs[][BLAKE2S_HASH_SIZE] __initconst = {\n");
++ *
++ *	for (i = 0; i < BLAKE2S_TESTVEC_COUNT; ++i) {
++ *		int outlen = 1 + i % BLAKE2S_OUTBYTES;
++ *		int keylen = (13 * i) % (BLAKE2S_KEYBYTES + 1);
++ *
++ *		blake2s(hash, buf, key + BLAKE2S_KEYBYTES - keylen, outlen, i,
++ *			keylen);
++ *		print_vec(hash, outlen);
++ *	}
++ *	printf("};\n\n");
++ *
++ *	printf("static const u8 blake2s_hmac_testvecs[][BLAKE2S_HASH_SIZE] __initconst = {\n");
++ *
++ *	HMAC(EVP_blake2s256(), key, sizeof(key), buf, sizeof(buf), hash, NULL);
++ *	print_vec(hash, BLAKE2S_OUTBYTES);
++ *
++ *	HMAC(EVP_blake2s256(), buf, sizeof(buf), key, sizeof(key), hash, NULL);
++ *	print_vec(hash, BLAKE2S_OUTBYTES);
++ *
++ *	printf("};\n");
++ *
++ *	return 0;
++ *}
++ */
++static const u8 blake2s_testvecs[][BLAKE2S_HASH_SIZE] __initconst = {
++  { 0xa1, },
++  { 0x7c, 0x89, },
++  { 0x74, 0x0e, 0xd4, },
++  { 0x47, 0x0c, 0x21, 0x15, },
++  { 0x18, 0xd6, 0x9c, 0xa6, 0xc4, },
++  { 0x13, 0x5d, 0x16, 0x63, 0x2e, 0xf9, },
++  { 0x2c, 0xb5, 0x04, 0xb7, 0x99, 0xe2, 0x73, },
++  { 0x9a, 0x0f, 0xd2, 0x39, 0xd6, 0x68, 0x1b, 0x92, },
++  { 0xc8, 0xde, 0x7a, 0xea, 0x2f, 0xf4, 0xd2, 0xe3, 0x2b, },
++  { 0x5b, 0xf9, 0x43, 0x52, 0x0c, 0x12, 0xba, 0xb5, 0x93, 0x9f, },
++  { 0xc6, 0x2c, 0x4e, 0x80, 0xfc, 0x32, 0x5b, 0x33, 0xb8, 0xb8, 0x0a, },
++  { 0xa7, 0x5c, 0xfd, 0x3a, 0xcc, 0xbf, 0x90, 0xca, 0xb7, 0x97, 0xde, 0xd8, },
++  { 0x66, 0xca, 0x3c, 0xc4, 0x19, 0xef, 0x92, 0x66, 0x3f, 0x21, 0x8f, 0xda,
++    0xb7, },
++  { 0xba, 0xe5, 0xbb, 0x30, 0x25, 0x94, 0x6d, 0xc3, 0x89, 0x09, 0xc4, 0x25,
++    0x52, 0x3e, },
++  { 0xa2, 0xef, 0x0e, 0x52, 0x0b, 0x5f, 0xa2, 0x01, 0x6d, 0x0a, 0x25, 0xbc,
++    0x57, 0xe2, 0x27, },
++  { 0x4f, 0xe0, 0xf9, 0x52, 0x12, 0xda, 0x84, 0xb7, 0xab, 0xae, 0xb0, 0xa6,
++    0x47, 0x2a, 0xc7, 0xf5, },
++  { 0x56, 0xe7, 0xa8, 0x1c, 0x4c, 0xca, 0xed, 0x90, 0x31, 0xec, 0x87, 0x43,
++    0xe7, 0x72, 0x08, 0xec, 0xbe, },
++  { 0x7e, 0xdf, 0x80, 0x1c, 0x93, 0x33, 0xfd, 0x53, 0x44, 0xba, 0xfd, 0x96,
++    0xe1, 0xbb, 0xb5, 0x65, 0xa5, 0x00, },
++  { 0xec, 0x6b, 0xed, 0xf7, 0x7b, 0x62, 0x1d, 0x7d, 0xf4, 0x82, 0xf3, 0x1e,
++    0x18, 0xff, 0x2b, 0xc4, 0x06, 0x20, 0x2a, },
++  { 0x74, 0x98, 0xd7, 0x68, 0x63, 0xed, 0x87, 0xe4, 0x5d, 0x8d, 0x9e, 0x1d,
++    0xfd, 0x2a, 0xbb, 0x86, 0xac, 0xe9, 0x2a, 0x89, },
++  { 0x89, 0xc3, 0x88, 0xce, 0x2b, 0x33, 0x1e, 0x10, 0xd1, 0x37, 0x20, 0x86,
++    0x28, 0x43, 0x70, 0xd9, 0xfb, 0x96, 0xd9, 0xb5, 0xd3, },
++  { 0xcb, 0x56, 0x74, 0x41, 0x8d, 0x80, 0x01, 0x9a, 0x6b, 0x38, 0xe1, 0x41,
++    0xad, 0x9c, 0x62, 0x74, 0xce, 0x35, 0xd5, 0x6c, 0x89, 0x6e, },
++  { 0x79, 0xaf, 0x94, 0x59, 0x99, 0x26, 0xe1, 0xc9, 0x34, 0xfe, 0x7c, 0x22,
++    0xf7, 0x43, 0xd7, 0x65, 0xd4, 0x48, 0x18, 0xac, 0x3d, 0xfd, 0x93, },
++  { 0x85, 0x0d, 0xff, 0xb8, 0x3e, 0x87, 0x41, 0xb0, 0x95, 0xd3, 0x3d, 0x00,
++    0x47, 0x55, 0x9e, 0xd2, 0x69, 0xea, 0xbf, 0xe9, 0x7a, 0x2d, 0x61, 0x45, },
++  { 0x03, 0xe0, 0x85, 0xec, 0x54, 0xb5, 0x16, 0x53, 0xa8, 0xc4, 0x71, 0xe9,
++    0x6a, 0xe7, 0xcb, 0xc4, 0x15, 0x02, 0xfc, 0x34, 0xa4, 0xa4, 0x28, 0x13,
++    0xd1, },
++  { 0xe3, 0x34, 0x4b, 0xe1, 0xd0, 0x4b, 0x55, 0x61, 0x8f, 0xc0, 0x24, 0x05,
++    0xe6, 0xe0, 0x3d, 0x70, 0x24, 0x4d, 0xda, 0xb8, 0x91, 0x05, 0x29, 0x07,
++    0x01, 0x3e, },
++  { 0x61, 0xff, 0x01, 0x72, 0xb1, 0x4d, 0xf6, 0xfe, 0xd1, 0xd1, 0x08, 0x74,
++    0xe6, 0x91, 0x44, 0xeb, 0x61, 0xda, 0x40, 0xaf, 0xfc, 0x8c, 0x91, 0x6b,
++    0xec, 0x13, 0xed, },
++  { 0xd4, 0x40, 0xd2, 0xa0, 0x7f, 0xc1, 0x58, 0x0c, 0x85, 0xa0, 0x86, 0xc7,
++    0x86, 0xb9, 0x61, 0xc9, 0xea, 0x19, 0x86, 0x1f, 0xab, 0x07, 0xce, 0x37,
++    0x72, 0x67, 0x09, 0xfc, },
++  { 0x9e, 0xf8, 0x18, 0x67, 0x93, 0x10, 0x9b, 0x39, 0x75, 0xe8, 0x8b, 0x38,
++    0x82, 0x7d, 0xb8, 0xb7, 0xa5, 0xaf, 0xe6, 0x6a, 0x22, 0x5e, 0x1f, 0x9c,
++    0x95, 0x29, 0x19, 0xf2, 0x4b, },
++  { 0xc8, 0x62, 0x25, 0xf5, 0x98, 0xc9, 0xea, 0xe5, 0x29, 0x3a, 0xd3, 0x22,
++    0xeb, 0xeb, 0x07, 0x7c, 0x15, 0x07, 0xee, 0x15, 0x61, 0xbb, 0x05, 0x30,
++    0x99, 0x7f, 0x11, 0xf6, 0x0a, 0x1d, },
++  { 0x68, 0x70, 0xf7, 0x90, 0xa1, 0x8b, 0x1f, 0x0f, 0xbb, 0xce, 0xd2, 0x0e,
++    0x33, 0x1f, 0x7f, 0xa9, 0x78, 0xa8, 0xa6, 0x81, 0x66, 0xab, 0x8d, 0xcd,
++    0x58, 0x55, 0x3a, 0x0b, 0x7a, 0xdb, 0xb5, },
++  { 0xdd, 0x35, 0xd2, 0xb4, 0xf6, 0xc7, 0xea, 0xab, 0x64, 0x24, 0x4e, 0xfe,
++    0xe5, 0x3d, 0x4e, 0x95, 0x8b, 0x6d, 0x6c, 0xbc, 0xb0, 0xf8, 0x88, 0x61,
++    0x09, 0xb7, 0x78, 0xa3, 0x31, 0xfe, 0xd9, 0x2f, },
++  { 0x0a, },
++  { 0x6e, 0xd4, },
++  { 0x64, 0xe9, 0xd1, },
++  { 0x30, 0xdd, 0x71, 0xef, },
++  { 0x11, 0xb5, 0x0c, 0x87, 0xc9, },
++  { 0x06, 0x1c, 0x6d, 0x04, 0x82, 0xd0, },
++  { 0x5c, 0x42, 0x0b, 0xee, 0xc5, 0x9c, 0xb2, },
++  { 0xe8, 0x29, 0xd6, 0xb4, 0x5d, 0xf7, 0x2b, 0x93, },
++  { 0x18, 0xca, 0x27, 0x72, 0x43, 0x39, 0x16, 0xbc, 0x6a, },
++  { 0x39, 0x8f, 0xfd, 0x64, 0xf5, 0x57, 0x23, 0xb0, 0x45, 0xf8, },
++  { 0xbb, 0x3a, 0x78, 0x6b, 0x02, 0x1d, 0x0b, 0x16, 0xe3, 0xb2, 0x9a, },
++  { 0xb8, 0xb4, 0x0b, 0xe5, 0xd4, 0x1d, 0x0d, 0x85, 0x49, 0x91, 0x35, 0xfa, },
++  { 0x6d, 0x48, 0x2a, 0x0c, 0x42, 0x08, 0xbd, 0xa9, 0x78, 0x6f, 0x18, 0xaf,
++    0xe2, },
++  { 0x10, 0x45, 0xd4, 0x58, 0x88, 0xec, 0x4e, 0x1e, 0xf6, 0x14, 0x92, 0x64,
++    0x7e, 0xb0, },
++  { 0x8b, 0x0b, 0x95, 0xee, 0x92, 0xc6, 0x3b, 0x91, 0xf1, 0x1e, 0xeb, 0x51,
++    0x98, 0x0a, 0x8d, },
++  { 0xa3, 0x50, 0x4d, 0xa5, 0x1d, 0x03, 0x68, 0xe9, 0x57, 0x78, 0xd6, 0x04,
++    0xf1, 0xc3, 0x94, 0xd8, },
++  { 0xb8, 0x66, 0x6e, 0xdd, 0x46, 0x15, 0xae, 0x3d, 0x83, 0x7e, 0xcf, 0xe7,
++    0x2c, 0xe8, 0x8f, 0xc7, 0x34, },
++  { 0x2e, 0xc0, 0x1f, 0x29, 0xea, 0xf6, 0xb9, 0xe2, 0xc2, 0x93, 0xeb, 0x41,
++    0x0d, 0xf0, 0x0a, 0x13, 0x0e, 0xa2, },
++  { 0x71, 0xb8, 0x33, 0xa9, 0x1b, 0xac, 0xf1, 0xb5, 0x42, 0x8f, 0x5e, 0x81,
++    0x34, 0x43, 0xb7, 0xa4, 0x18, 0x5c, 0x47, },
++  { 0xda, 0x45, 0xb8, 0x2e, 0x82, 0x1e, 0xc0, 0x59, 0x77, 0x9d, 0xfa, 0xb4,
++    0x1c, 0x5e, 0xa0, 0x2b, 0x33, 0x96, 0x5a, 0x58, },
++  { 0xe3, 0x09, 0x05, 0xa9, 0xeb, 0x48, 0x13, 0xad, 0x71, 0x88, 0x81, 0x9a,
++    0x3e, 0x2c, 0xe1, 0x23, 0x99, 0x13, 0x35, 0x9f, 0xb5, },
++  { 0xb7, 0x86, 0x2d, 0x16, 0xe1, 0x04, 0x00, 0x47, 0x47, 0x61, 0x31, 0xfb,
++    0x14, 0xac, 0xd8, 0xe9, 0xe3, 0x49, 0xbd, 0xf7, 0x9c, 0x3f, },
++  { 0x7f, 0xd9, 0x95, 0xa8, 0xa7, 0xa0, 0xcc, 0xba, 0xef, 0xb1, 0x0a, 0xa9,
++    0x21, 0x62, 0x08, 0x0f, 0x1b, 0xff, 0x7b, 0x9d, 0xae, 0xb2, 0x95, },
++  { 0x85, 0x99, 0xea, 0x33, 0xe0, 0x56, 0xff, 0x13, 0xc6, 0x61, 0x8c, 0xf9,
++    0x57, 0x05, 0x03, 0x11, 0xf9, 0xfb, 0x3a, 0xf7, 0xce, 0xbb, 0x52, 0x30, },
++  { 0xb2, 0x72, 0x9c, 0xf8, 0x77, 0x4e, 0x8f, 0x6b, 0x01, 0x6c, 0xff, 0x4e,
++    0x4f, 0x02, 0xd2, 0xbc, 0xeb, 0x51, 0x28, 0x99, 0x50, 0xab, 0xc4, 0x42,
++    0xe3, },
++  { 0x8b, 0x0a, 0xb5, 0x90, 0x8f, 0xf5, 0x7b, 0xdd, 0xba, 0x47, 0x37, 0xc9,
++    0x2a, 0xd5, 0x4b, 0x25, 0x08, 0x8b, 0x02, 0x17, 0xa7, 0x9e, 0x6b, 0x6e,
++    0xe3, 0x90, },
++  { 0x90, 0xdd, 0xf7, 0x75, 0xa7, 0xa3, 0x99, 0x5e, 0x5b, 0x7d, 0x75, 0xc3,
++    0x39, 0x6b, 0xa0, 0xe2, 0x44, 0x53, 0xb1, 0x9e, 0xc8, 0xf1, 0x77, 0x10,
++    0x58, 0x06, 0x9a, },
++  { 0x99, 0x52, 0xf0, 0x49, 0xa8, 0x8c, 0xec, 0xa6, 0x97, 0x32, 0x13, 0xb5,
++    0xf7, 0xa3, 0x8e, 0xfb, 0x4b, 0x59, 0x31, 0x3d, 0x01, 0x59, 0x98, 0x5d,
++    0x53, 0x03, 0x1a, 0x39, },
++  { 0x9f, 0xe0, 0xc2, 0xe5, 0x5d, 0x93, 0xd6, 0x9b, 0x47, 0x8f, 0x9b, 0xe0,
++    0x26, 0x35, 0x84, 0x20, 0x1d, 0xc5, 0x53, 0x10, 0x0f, 0x22, 0xb9, 0xb5,
++    0xd4, 0x36, 0xb1, 0xac, 0x73, },
++  { 0x30, 0x32, 0x20, 0x3b, 0x10, 0x28, 0xec, 0x1f, 0x4f, 0x9b, 0x47, 0x59,
++    0xeb, 0x7b, 0xee, 0x45, 0xfb, 0x0c, 0x49, 0xd8, 0x3d, 0x69, 0xbd, 0x90,
++    0x2c, 0xf0, 0x9e, 0x8d, 0xbf, 0xd5, },
++  { 0x2a, 0x37, 0x73, 0x7f, 0xf9, 0x96, 0x19, 0xaa, 0x25, 0xd8, 0x13, 0x28,
++    0x01, 0x29, 0x89, 0xdf, 0x6e, 0x0c, 0x9b, 0x43, 0x44, 0x51, 0xe9, 0x75,
++    0x26, 0x0c, 0xb7, 0x87, 0x66, 0x0b, 0x5f, },
++  { 0x23, 0xdf, 0x96, 0x68, 0x91, 0x86, 0xd0, 0x93, 0x55, 0x33, 0x24, 0xf6,
++    0xba, 0x08, 0x75, 0x5b, 0x59, 0x11, 0x69, 0xb8, 0xb9, 0xe5, 0x2c, 0x77,
++    0x02, 0xf6, 0x47, 0xee, 0x81, 0xdd, 0xb9, 0x06, },
++  { 0x9d, },
++  { 0x9d, 0x7d, },
++  { 0xfd, 0xc3, 0xda, },
++  { 0xe8, 0x82, 0xcd, 0x21, },
++  { 0xc3, 0x1d, 0x42, 0x4c, 0x74, },
++  { 0xe9, 0xda, 0xf1, 0xa2, 0xe5, 0x7c, },
++  { 0x52, 0xb8, 0x6f, 0x81, 0x5c, 0x3a, 0x4c, },
++  { 0x5b, 0x39, 0x26, 0xfc, 0x92, 0x5e, 0xe0, 0x49, },
++  { 0x59, 0xe4, 0x7c, 0x93, 0x1c, 0xf9, 0x28, 0x93, 0xde, },
++  { 0xde, 0xdf, 0xb2, 0x43, 0x61, 0x0b, 0x86, 0x16, 0x4c, 0x2e, },
++  { 0x14, 0x8f, 0x75, 0x51, 0xaf, 0xb9, 0xee, 0x51, 0x5a, 0xae, 0x23, },
++  { 0x43, 0x5f, 0x50, 0xd5, 0x70, 0xb0, 0x5b, 0x87, 0xf5, 0xd9, 0xb3, 0x6d, },
++  { 0x66, 0x0a, 0x64, 0x93, 0x79, 0x71, 0x94, 0x40, 0xb7, 0x68, 0x2d, 0xd3,
++    0x63, },
++  { 0x15, 0x00, 0xc4, 0x0c, 0x7d, 0x1b, 0x10, 0xa9, 0x73, 0x1b, 0x90, 0x6f,
++    0xe6, 0xa9, },
++  { 0x34, 0x75, 0xf3, 0x86, 0x8f, 0x56, 0xcf, 0x2a, 0x0a, 0xf2, 0x62, 0x0a,
++    0xf6, 0x0e, 0x20, },
++  { 0xb1, 0xde, 0xc9, 0xf5, 0xdb, 0xf3, 0x2f, 0x4c, 0xd6, 0x41, 0x7d, 0x39,
++    0x18, 0x3e, 0xc7, 0xc3, },
++  { 0xc5, 0x89, 0xb2, 0xf8, 0xb8, 0xc0, 0xa3, 0xb9, 0x3b, 0x10, 0x6d, 0x7c,
++    0x92, 0xfc, 0x7f, 0x34, 0x41, },
++  { 0xc4, 0xd8, 0xef, 0xba, 0xef, 0xd2, 0xaa, 0xc5, 0x6c, 0x8e, 0x3e, 0xbb,
++    0x12, 0xfc, 0x0f, 0x72, 0xbf, 0x0f, },
++  { 0xdd, 0x91, 0xd1, 0x15, 0x9e, 0x7d, 0xf8, 0xc1, 0xb9, 0x14, 0x63, 0x96,
++    0xb5, 0xcb, 0x83, 0x1d, 0x35, 0x1c, 0xec, },
++  { 0xa9, 0xf8, 0x52, 0xc9, 0x67, 0x76, 0x2b, 0xad, 0xfb, 0xd8, 0x3a, 0xa6,
++    0x74, 0x02, 0xae, 0xb8, 0x25, 0x2c, 0x63, 0x49, },
++  { 0x77, 0x1f, 0x66, 0x70, 0xfd, 0x50, 0x29, 0xaa, 0xeb, 0xdc, 0xee, 0xba,
++    0x75, 0x98, 0xdc, 0x93, 0x12, 0x3f, 0xdc, 0x7c, 0x38, },
++  { 0xe2, 0xe1, 0x89, 0x5c, 0x37, 0x38, 0x6a, 0xa3, 0x40, 0xac, 0x3f, 0xb0,
++    0xca, 0xfc, 0xa7, 0xf3, 0xea, 0xf9, 0x0f, 0x5d, 0x8e, 0x39, },
++  { 0x0f, 0x67, 0xc8, 0x38, 0x01, 0xb1, 0xb7, 0xb8, 0xa2, 0xe7, 0x0a, 0x6d,
++    0xd2, 0x63, 0x69, 0x9e, 0xcc, 0xf0, 0xf2, 0xbe, 0x9b, 0x98, 0xdd, },
++  { 0x13, 0xe1, 0x36, 0x30, 0xfe, 0xc6, 0x01, 0x8a, 0xa1, 0x63, 0x96, 0x59,
++    0xc2, 0xa9, 0x68, 0x3f, 0x58, 0xd4, 0x19, 0x0c, 0x40, 0xf3, 0xde, 0x02, },
++  { 0xa3, 0x9e, 0xce, 0xda, 0x42, 0xee, 0x8c, 0x6c, 0x5a, 0x7d, 0xdc, 0x89,
++    0x02, 0x77, 0xdd, 0xe7, 0x95, 0xbb, 0xff, 0x0d, 0xa4, 0xb5, 0x38, 0x1e,
++    0xaf, },
++  { 0x9a, 0xf6, 0xb5, 0x9a, 0x4f, 0xa9, 0x4f, 0x2c, 0x35, 0x3c, 0x24, 0xdc,
++    0x97, 0x6f, 0xd9, 0xa1, 0x7d, 0x1a, 0x85, 0x0b, 0xf5, 0xda, 0x2e, 0xe7,
++    0xb1, 0x1d, },
++  { 0x84, 0x1e, 0x8e, 0x3d, 0x45, 0xa5, 0xf2, 0x27, 0xf3, 0x31, 0xfe, 0xb9,
++    0xfb, 0xc5, 0x45, 0x99, 0x99, 0xdd, 0x93, 0x43, 0x02, 0xee, 0x58, 0xaf,
++    0xee, 0x6a, 0xbe, },
++  { 0x07, 0x2f, 0xc0, 0xa2, 0x04, 0xc4, 0xab, 0x7c, 0x26, 0xbb, 0xa8, 0xd8,
++    0xe3, 0x1c, 0x75, 0x15, 0x64, 0x5d, 0x02, 0x6a, 0xf0, 0x86, 0xe9, 0xcd,
++    0x5c, 0xef, 0xa3, 0x25, },
++  { 0x2f, 0x3b, 0x1f, 0xb5, 0x91, 0x8f, 0x86, 0xe0, 0xdc, 0x31, 0x48, 0xb6,
++    0xa1, 0x8c, 0xfd, 0x75, 0xbb, 0x7d, 0x3d, 0xc1, 0xf0, 0x10, 0x9a, 0xd8,
++    0x4b, 0x0e, 0xe3, 0x94, 0x9f, },
++  { 0x29, 0xbb, 0x8f, 0x6c, 0xd1, 0xf2, 0xb6, 0xaf, 0xe5, 0xe3, 0x2d, 0xdc,
++    0x6f, 0xa4, 0x53, 0x88, 0xd8, 0xcf, 0x4d, 0x45, 0x42, 0x62, 0xdb, 0xdf,
++    0xf8, 0x45, 0xc2, 0x13, 0xec, 0x35, },
++  { 0x06, 0x3c, 0xe3, 0x2c, 0x15, 0xc6, 0x43, 0x03, 0x81, 0xfb, 0x08, 0x76,
++    0x33, 0xcb, 0x02, 0xc1, 0xba, 0x33, 0xe5, 0xe0, 0xd1, 0x92, 0xa8, 0x46,
++    0x28, 0x3f, 0x3e, 0x9d, 0x2c, 0x44, 0x54, },
++  { 0xea, 0xbb, 0x96, 0xf8, 0xd1, 0x8b, 0x04, 0x11, 0x40, 0x78, 0x42, 0x02,
++    0x19, 0xd1, 0xbc, 0x65, 0x92, 0xd3, 0xc3, 0xd6, 0xd9, 0x19, 0xe7, 0xc3,
++    0x40, 0x97, 0xbd, 0xd4, 0xed, 0xfa, 0x5e, 0x28, },
++  { 0x02, },
++  { 0x52, 0xa8, },
++  { 0x38, 0x25, 0x0d, },
++  { 0xe3, 0x04, 0xd4, 0x92, },
++  { 0x97, 0xdb, 0xf7, 0x81, 0xca, },
++  { 0x8a, 0x56, 0x9d, 0x62, 0x56, 0xcc, },
++  { 0xa1, 0x8e, 0x3c, 0x72, 0x8f, 0x63, 0x03, },
++  { 0xf7, 0xf3, 0x39, 0x09, 0x0a, 0xa1, 0xbb, 0x23, },
++  { 0x6b, 0x03, 0xc0, 0xe9, 0xd9, 0x83, 0x05, 0x22, 0x01, },
++  { 0x1b, 0x4b, 0xf5, 0xd6, 0x4f, 0x05, 0x75, 0x91, 0x4c, 0x7f, },
++  { 0x4c, 0x8c, 0x25, 0x20, 0x21, 0xcb, 0xc2, 0x4b, 0x3a, 0x5b, 0x8d, },
++  { 0x56, 0xe2, 0x77, 0xa0, 0xb6, 0x9f, 0x81, 0xec, 0x83, 0x75, 0xc4, 0xf9, },
++  { 0x71, 0x70, 0x0f, 0xad, 0x4d, 0x35, 0x81, 0x9d, 0x88, 0x69, 0xf9, 0xaa,
++    0xd3, },
++  { 0x50, 0x6e, 0x86, 0x6e, 0x43, 0xc0, 0xc2, 0x44, 0xc2, 0xe2, 0xa0, 0x1c,
++    0xb7, 0x9a, },
++  { 0xe4, 0x7e, 0x72, 0xc6, 0x12, 0x8e, 0x7c, 0xfc, 0xbd, 0xe2, 0x08, 0x31,
++    0x3d, 0x47, 0x3d, },
++  { 0x08, 0x97, 0x5b, 0x80, 0xae, 0xc4, 0x1d, 0x50, 0x77, 0xdf, 0x1f, 0xd0,
++    0x24, 0xf0, 0x17, 0xc0, },
++  { 0x01, 0xb6, 0x29, 0xf4, 0xaf, 0x78, 0x5f, 0xb6, 0x91, 0xdd, 0x76, 0x76,
++    0xd2, 0xfd, 0x0c, 0x47, 0x40, },
++  { 0xa1, 0xd8, 0x09, 0x97, 0x7a, 0xa6, 0xc8, 0x94, 0xf6, 0x91, 0x7b, 0xae,
++    0x2b, 0x9f, 0x0d, 0x83, 0x48, 0xf7, },
++  { 0x12, 0xd5, 0x53, 0x7d, 0x9a, 0xb0, 0xbe, 0xd9, 0xed, 0xe9, 0x9e, 0xee,
++    0x61, 0x5b, 0x42, 0xf2, 0xc0, 0x73, 0xc0, },
++  { 0xd5, 0x77, 0xd6, 0x5c, 0x6e, 0xa5, 0x69, 0x2b, 0x3b, 0x8c, 0xd6, 0x7d,
++    0x1d, 0xbe, 0x2c, 0xa1, 0x02, 0x21, 0xcd, 0x29, },
++  { 0xa4, 0x98, 0x80, 0xca, 0x22, 0xcf, 0x6a, 0xab, 0x5e, 0x40, 0x0d, 0x61,
++    0x08, 0x21, 0xef, 0xc0, 0x6c, 0x52, 0xb4, 0xb0, 0x53, },
++  { 0xbf, 0xaf, 0x8f, 0x3b, 0x7a, 0x97, 0x33, 0xe5, 0xca, 0x07, 0x37, 0xfd,
++    0x15, 0xdf, 0xce, 0x26, 0x2a, 0xb1, 0xa7, 0x0b, 0xb3, 0xac, },
++  { 0x16, 0x22, 0xe1, 0xbc, 0x99, 0x4e, 0x01, 0xf0, 0xfa, 0xff, 0x8f, 0xa5,
++    0x0c, 0x61, 0xb0, 0xad, 0xcc, 0xb1, 0xe1, 0x21, 0x46, 0xfa, 0x2e, },
++  { 0x11, 0x5b, 0x0b, 0x2b, 0xe6, 0x14, 0xc1, 0xd5, 0x4d, 0x71, 0x5e, 0x17,
++    0xea, 0x23, 0xdd, 0x6c, 0xbd, 0x1d, 0xbe, 0x12, 0x1b, 0xee, 0x4c, 0x1a, },
++  { 0x40, 0x88, 0x22, 0xf3, 0x20, 0x6c, 0xed, 0xe1, 0x36, 0x34, 0x62, 0x2c,
++    0x98, 0x83, 0x52, 0xe2, 0x25, 0xee, 0xe9, 0xf5, 0xe1, 0x17, 0xf0, 0x5c,
++    0xae, },
++  { 0xc3, 0x76, 0x37, 0xde, 0x95, 0x8c, 0xca, 0x2b, 0x0c, 0x23, 0xe7, 0xb5,
++    0x38, 0x70, 0x61, 0xcc, 0xff, 0xd3, 0x95, 0x7b, 0xf3, 0xff, 0x1f, 0x9d,
++    0x59, 0x00, },
++  { 0x0c, 0x19, 0x52, 0x05, 0x22, 0x53, 0xcb, 0x48, 0xd7, 0x10, 0x0e, 0x7e,
++    0x14, 0x69, 0xb5, 0xa2, 0x92, 0x43, 0xa3, 0x9e, 0x4b, 0x8f, 0x51, 0x2c,
++    0x5a, 0x2c, 0x3b, },
++  { 0xe1, 0x9d, 0x70, 0x70, 0x28, 0xec, 0x86, 0x40, 0x55, 0x33, 0x56, 0xda,
++    0x88, 0xca, 0xee, 0xc8, 0x6a, 0x20, 0xb1, 0xe5, 0x3d, 0x57, 0xf8, 0x3c,
++    0x10, 0x07, 0x2a, 0xc4, },
++  { 0x0b, 0xae, 0xf1, 0xc4, 0x79, 0xee, 0x1b, 0x3d, 0x27, 0x35, 0x8d, 0x14,
++    0xd6, 0xae, 0x4e, 0x3c, 0xe9, 0x53, 0x50, 0xb5, 0xcc, 0x0c, 0xf7, 0xdf,
++    0xee, 0xa1, 0x74, 0xd6, 0x71, },
++  { 0xe6, 0xa4, 0xf4, 0x99, 0x98, 0xb9, 0x80, 0xea, 0x96, 0x7f, 0x4f, 0x33,
++    0xcf, 0x74, 0x25, 0x6f, 0x17, 0x6c, 0xbf, 0xf5, 0x5c, 0x38, 0xd0, 0xff,
++    0x96, 0xcb, 0x13, 0xf9, 0xdf, 0xfd, },
++  { 0xbe, 0x92, 0xeb, 0xba, 0x44, 0x2c, 0x24, 0x74, 0xd4, 0x03, 0x27, 0x3c,
++    0x5d, 0x5b, 0x03, 0x30, 0x87, 0x63, 0x69, 0xe0, 0xb8, 0x94, 0xf4, 0x44,
++    0x7e, 0xad, 0xcd, 0x20, 0x12, 0x16, 0x79, },
++  { 0x30, 0xf1, 0xc4, 0x8e, 0x05, 0x90, 0x2a, 0x97, 0x63, 0x94, 0x46, 0xff,
++    0xce, 0xd8, 0x67, 0xa7, 0xac, 0x33, 0x8c, 0x95, 0xb7, 0xcd, 0xa3, 0x23,
++    0x98, 0x9d, 0x76, 0x6c, 0x9d, 0xa8, 0xd6, 0x8a, },
++  { 0xbe, },
++  { 0x17, 0x6c, },
++  { 0x1a, 0x42, 0x4f, },
++  { 0xba, 0xaf, 0xb7, 0x65, },
++  { 0xc2, 0x63, 0x43, 0x6a, 0xea, },
++  { 0xe4, 0x4d, 0xad, 0xf2, 0x0b, 0x02, },
++  { 0x04, 0xc7, 0xc4, 0x7f, 0xa9, 0x2b, 0xce, },
++  { 0x66, 0xf6, 0x67, 0xcb, 0x03, 0x53, 0xc8, 0xf1, },
++  { 0x56, 0xa3, 0x60, 0x78, 0xc9, 0x5f, 0x70, 0x1b, 0x5e, },
++  { 0x99, 0xff, 0x81, 0x7c, 0x13, 0x3c, 0x29, 0x79, 0x4b, 0x65, },
++  { 0x51, 0x10, 0x50, 0x93, 0x01, 0x93, 0xb7, 0x01, 0xc9, 0x18, 0xb7, },
++  { 0x8e, 0x3c, 0x42, 0x1e, 0x5e, 0x7d, 0xc1, 0x50, 0x70, 0x1f, 0x00, 0x98, },
++  { 0x5f, 0xd9, 0x9b, 0xc8, 0xd7, 0xb2, 0x72, 0x62, 0x1a, 0x1e, 0xba, 0x92,
++    0xe9, },
++  { 0x70, 0x2b, 0xba, 0xfe, 0xad, 0x5d, 0x96, 0x3f, 0x27, 0xc2, 0x41, 0x6d,
++    0xc4, 0xb3, },
++  { 0xae, 0xe0, 0xd5, 0xd4, 0xc7, 0xae, 0x15, 0x5e, 0xdc, 0xdd, 0x33, 0x60,
++    0xd7, 0xd3, 0x5e, },
++  { 0x79, 0x8e, 0xbc, 0x9e, 0x20, 0xb9, 0x19, 0x4b, 0x63, 0x80, 0xf3, 0x16,
++    0xaf, 0x39, 0xbd, 0x92, },
++  { 0xc2, 0x0e, 0x85, 0xa0, 0x0b, 0x9a, 0xb0, 0xec, 0xde, 0x38, 0xd3, 0x10,
++    0xd9, 0xa7, 0x66, 0x27, 0xcf, },
++  { 0x0e, 0x3b, 0x75, 0x80, 0x67, 0x14, 0x0c, 0x02, 0x90, 0xd6, 0xb3, 0x02,
++    0x81, 0xf6, 0xa6, 0x87, 0xce, 0x58, },
++  { 0x79, 0xb5, 0xe9, 0x5d, 0x52, 0x4d, 0xf7, 0x59, 0xf4, 0x2e, 0x27, 0xdd,
++    0xb3, 0xed, 0x57, 0x5b, 0x82, 0xea, 0x6f, },
++  { 0xa2, 0x97, 0xf5, 0x80, 0x02, 0x3d, 0xde, 0xa3, 0xf9, 0xf6, 0xab, 0xe3,
++    0x57, 0x63, 0x7b, 0x9b, 0x10, 0x42, 0x6f, 0xf2, },
++  { 0x12, 0x7a, 0xfc, 0xb7, 0x67, 0x06, 0x0c, 0x78, 0x1a, 0xfe, 0x88, 0x4f,
++    0xc6, 0xac, 0x52, 0x96, 0x64, 0x28, 0x97, 0x84, 0x06, },
++  { 0xc5, 0x04, 0x44, 0x6b, 0xb2, 0xa5, 0xa4, 0x66, 0xe1, 0x76, 0xa2, 0x51,
++    0xf9, 0x59, 0x69, 0x97, 0x56, 0x0b, 0xbf, 0x50, 0xb3, 0x34, },
++  { 0x21, 0x32, 0x6b, 0x42, 0xb5, 0xed, 0x71, 0x8d, 0xf7, 0x5a, 0x35, 0xe3,
++    0x90, 0xe2, 0xee, 0xaa, 0x89, 0xf6, 0xc9, 0x9c, 0x4d, 0x73, 0xf4, },
++  { 0x4c, 0xa6, 0x09, 0xf4, 0x48, 0xe7, 0x46, 0xbc, 0x49, 0xfc, 0xe5, 0xda,
++    0xd1, 0x87, 0x13, 0x17, 0x4c, 0x59, 0x71, 0x26, 0x5b, 0x2c, 0x42, 0xb7, },
++  { 0x13, 0x63, 0xf3, 0x40, 0x02, 0xe5, 0xa3, 0x3a, 0x5e, 0x8e, 0xf8, 0xb6,
++    0x8a, 0x49, 0x60, 0x76, 0x34, 0x72, 0x94, 0x73, 0xf6, 0xd9, 0x21, 0x6a,
++    0x26, },
++  { 0xdf, 0x75, 0x16, 0x10, 0x1b, 0x5e, 0x81, 0xc3, 0xc8, 0xde, 0x34, 0x24,
++    0xb0, 0x98, 0xeb, 0x1b, 0x8f, 0xa1, 0x9b, 0x05, 0xee, 0xa5, 0xe9, 0x35,
++    0xf4, 0x1d, },
++  { 0xcd, 0x21, 0x93, 0x6e, 0x5b, 0xa0, 0x26, 0x2b, 0x21, 0x0e, 0xa0, 0xb9,
++    0x1c, 0xb5, 0xbb, 0xb8, 0xf8, 0x1e, 0xff, 0x5c, 0xa8, 0xf9, 0x39, 0x46,
++    0x4e, 0x29, 0x26, },
++  { 0x73, 0x7f, 0x0e, 0x3b, 0x0b, 0x5c, 0xf9, 0x60, 0xaa, 0x88, 0xa1, 0x09,
++    0xb1, 0x5d, 0x38, 0x7b, 0x86, 0x8f, 0x13, 0x7a, 0x8d, 0x72, 0x7a, 0x98,
++    0x1a, 0x5b, 0xff, 0xc9, },
++  { 0xd3, 0x3c, 0x61, 0x71, 0x44, 0x7e, 0x31, 0x74, 0x98, 0x9d, 0x9a, 0xd2,
++    0x27, 0xf3, 0x46, 0x43, 0x42, 0x51, 0xd0, 0x5f, 0xe9, 0x1c, 0x5c, 0x69,
++    0xbf, 0xf6, 0xbe, 0x3c, 0x40, },
++  { 0x31, 0x99, 0x31, 0x9f, 0xaa, 0x43, 0x2e, 0x77, 0x3e, 0x74, 0x26, 0x31,
++    0x5e, 0x61, 0xf1, 0x87, 0xe2, 0xeb, 0x9b, 0xcd, 0xd0, 0x3a, 0xee, 0x20,
++    0x7e, 0x10, 0x0a, 0x0b, 0x7e, 0xfa, },
++  { 0xa4, 0x27, 0x80, 0x67, 0x81, 0x2a, 0xa7, 0x62, 0xf7, 0x6e, 0xda, 0xd4,
++    0x5c, 0x39, 0x74, 0xad, 0x7e, 0xbe, 0xad, 0xa5, 0x84, 0x7f, 0xa9, 0x30,
++    0x5d, 0xdb, 0xe2, 0x05, 0x43, 0xf7, 0x1b, },
++  { 0x0b, 0x37, 0xd8, 0x02, 0xe1, 0x83, 0xd6, 0x80, 0xf2, 0x35, 0xc2, 0xb0,
++    0x37, 0xef, 0xef, 0x5e, 0x43, 0x93, 0xf0, 0x49, 0x45, 0x0a, 0xef, 0xb5,
++    0x76, 0x70, 0x12, 0x44, 0xc4, 0xdb, 0xf5, 0x7a, },
++  { 0x1f, },
++  { 0x82, 0x60, },
++  { 0xcc, 0xe3, 0x08, },
++  { 0x56, 0x17, 0xe4, 0x59, },
++  { 0xe2, 0xd7, 0x9e, 0xc4, 0x4c, },
++  { 0xb2, 0xad, 0xd3, 0x78, 0x58, 0x5a, },
++  { 0xce, 0x43, 0xb4, 0x02, 0x96, 0xab, 0x3c, },
++  { 0xe6, 0x05, 0x1a, 0x73, 0x22, 0x32, 0xbb, 0x77, },
++  { 0x23, 0xe7, 0xda, 0xfe, 0x2c, 0xef, 0x8c, 0x22, 0xec, },
++  { 0xe9, 0x8e, 0x55, 0x38, 0xd1, 0xd7, 0x35, 0x23, 0x98, 0xc7, },
++  { 0xb5, 0x81, 0x1a, 0xe5, 0xb5, 0xa5, 0xd9, 0x4d, 0xca, 0x41, 0xe7, },
++  { 0x41, 0x16, 0x16, 0x95, 0x8d, 0x9e, 0x0c, 0xea, 0x8c, 0x71, 0x9a, 0xc1, },
++  { 0x7c, 0x33, 0xc0, 0xa4, 0x00, 0x62, 0xea, 0x60, 0x67, 0xe4, 0x20, 0xbc,
++    0x5b, },
++  { 0xdb, 0xb1, 0xdc, 0xfd, 0x08, 0xc0, 0xde, 0x82, 0xd1, 0xde, 0x38, 0xc0,
++    0x90, 0x48, },
++  { 0x37, 0x18, 0x2e, 0x0d, 0x61, 0xaa, 0x61, 0xd7, 0x86, 0x20, 0x16, 0x60,
++    0x04, 0xd9, 0xd5, },
++  { 0xb0, 0xcf, 0x2c, 0x4c, 0x5e, 0x5b, 0x4f, 0x2a, 0x23, 0x25, 0x58, 0x47,
++    0xe5, 0x31, 0x06, 0x70, },
++  { 0x91, 0xa0, 0xa3, 0x86, 0x4e, 0xe0, 0x72, 0x38, 0x06, 0x67, 0x59, 0x5c,
++    0x70, 0x25, 0xdb, 0x33, 0x27, },
++  { 0x44, 0x58, 0x66, 0xb8, 0x58, 0xc7, 0x13, 0xed, 0x4c, 0xc0, 0xf4, 0x9a,
++    0x1e, 0x67, 0x75, 0x33, 0xb6, 0xb8, },
++  { 0x7f, 0x98, 0x4a, 0x8e, 0x50, 0xa2, 0x5c, 0xcd, 0x59, 0xde, 0x72, 0xb3,
++    0x9d, 0xc3, 0x09, 0x8a, 0xab, 0x56, 0xf1, },
++  { 0x80, 0x96, 0x49, 0x1a, 0x59, 0xa2, 0xc5, 0xd5, 0xa7, 0x20, 0x8a, 0xb7,
++    0x27, 0x62, 0x84, 0x43, 0xc6, 0xe1, 0x1b, 0x5d, },
++  { 0x6b, 0xb7, 0x2b, 0x26, 0x62, 0x14, 0x70, 0x19, 0x3d, 0x4d, 0xac, 0xac,
++    0x63, 0x58, 0x5e, 0x94, 0xb5, 0xb7, 0xe8, 0xe8, 0xa2, },
++  { 0x20, 0xa8, 0xc0, 0xfd, 0x63, 0x3d, 0x6e, 0x98, 0xcf, 0x0c, 0x49, 0x98,
++    0xe4, 0x5a, 0xfe, 0x8c, 0xaa, 0x70, 0x82, 0x1c, 0x7b, 0x74, },
++  { 0xc8, 0xe8, 0xdd, 0xdf, 0x69, 0x30, 0x01, 0xc2, 0x0f, 0x7e, 0x2f, 0x11,
++    0xcc, 0x3e, 0x17, 0xa5, 0x69, 0x40, 0x3f, 0x0e, 0x79, 0x7f, 0xcf, },
++  { 0xdb, 0x61, 0xc0, 0xe2, 0x2e, 0x49, 0x07, 0x31, 0x1d, 0x91, 0x42, 0x8a,
++    0xfc, 0x5e, 0xd3, 0xf8, 0x56, 0x1f, 0x2b, 0x73, 0xfd, 0x9f, 0xb2, 0x8e, },
++  { 0x0c, 0x89, 0x55, 0x0c, 0x1f, 0x59, 0x2c, 0x9d, 0x1b, 0x29, 0x1d, 0x41,
++    0x1d, 0xe6, 0x47, 0x8f, 0x8c, 0x2b, 0xea, 0x8f, 0xf0, 0xff, 0x21, 0x70,
++    0x88, },
++  { 0x12, 0x18, 0x95, 0xa6, 0x59, 0xb1, 0x31, 0x24, 0x45, 0x67, 0x55, 0xa4,
++    0x1a, 0x2d, 0x48, 0x67, 0x1b, 0x43, 0x88, 0x2d, 0x8e, 0xa0, 0x70, 0xb3,
++    0xc6, 0xbb, },
++  { 0xe7, 0xb1, 0x1d, 0xb2, 0x76, 0x4d, 0x68, 0x68, 0x68, 0x23, 0x02, 0x55,
++    0x3a, 0xe2, 0xe5, 0xd5, 0x4b, 0x43, 0xf9, 0x34, 0x77, 0x5c, 0xa1, 0xf5,
++    0x55, 0xfd, 0x4f, },
++  { 0x8c, 0x87, 0x5a, 0x08, 0x3a, 0x73, 0xad, 0x61, 0xe1, 0xe7, 0x99, 0x7e,
++    0xf0, 0x5d, 0xe9, 0x5d, 0x16, 0x43, 0x80, 0x2f, 0xd0, 0x66, 0x34, 0xe2,
++    0x42, 0x64, 0x3b, 0x1a, },
++  { 0x39, 0xc1, 0x99, 0xcf, 0x22, 0xbf, 0x16, 0x8f, 0x9f, 0x80, 0x7f, 0x95,
++    0x0a, 0x05, 0x67, 0x27, 0xe7, 0x15, 0xdf, 0x9d, 0xb2, 0xfe, 0x1c, 0xb5,
++    0x1d, 0x60, 0x8f, 0x8a, 0x1d, },
++  { 0x9b, 0x6e, 0x08, 0x09, 0x06, 0x73, 0xab, 0x68, 0x02, 0x62, 0x1a, 0xe4,
++    0xd4, 0xdf, 0xc7, 0x02, 0x4c, 0x6a, 0x5f, 0xfd, 0x23, 0xac, 0xae, 0x6d,
++    0x43, 0xa4, 0x7a, 0x50, 0x60, 0x3c, },
++  { 0x1d, 0xb4, 0xc6, 0xe1, 0xb1, 0x4b, 0xe3, 0xf2, 0xe2, 0x1a, 0x73, 0x1b,
++    0xa0, 0x92, 0xa7, 0xf5, 0xff, 0x8f, 0x8b, 0x5d, 0xdf, 0xa8, 0x04, 0xb3,
++    0xb0, 0xf7, 0xcc, 0x12, 0xfa, 0x35, 0x46, },
++  { 0x49, 0x45, 0x97, 0x11, 0x0f, 0x1c, 0x60, 0x8e, 0xe8, 0x47, 0x30, 0xcf,
++    0x60, 0xa8, 0x71, 0xc5, 0x1b, 0xe9, 0x39, 0x4d, 0x49, 0xb6, 0x12, 0x1f,
++    0x24, 0xab, 0x37, 0xff, 0x83, 0xc2, 0xe1, 0x3a, },
++  { 0x60, },
++  { 0x24, 0x26, },
++  { 0x47, 0xeb, 0xc9, },
++  { 0x4a, 0xd0, 0xbc, 0xf0, },
++  { 0x8e, 0x2b, 0xc9, 0x85, 0x3c, },
++  { 0xa2, 0x07, 0x15, 0xb8, 0x12, 0x74, },
++  { 0x0f, 0xdb, 0x5b, 0x33, 0x69, 0xfe, 0x4b, },
++  { 0xa2, 0x86, 0x54, 0xf4, 0xfd, 0xb2, 0xd4, 0xe6, },
++  { 0xbb, 0x84, 0x78, 0x49, 0x27, 0x8e, 0x61, 0xda, 0x60, },
++  { 0x04, 0xc3, 0xcd, 0xaa, 0x8f, 0xa7, 0x03, 0xc9, 0xf9, 0xb6, },
++  { 0xf8, 0x27, 0x1d, 0x61, 0xdc, 0x21, 0x42, 0xdd, 0xad, 0x92, 0x40, },
++  { 0x12, 0x87, 0xdf, 0xc2, 0x41, 0x45, 0x5a, 0x36, 0x48, 0x5b, 0x51, 0x2b, },
++  { 0xbb, 0x37, 0x5d, 0x1f, 0xf1, 0x68, 0x7a, 0xc4, 0xa5, 0xd2, 0xa4, 0x91,
++    0x8d, },
++  { 0x5b, 0x27, 0xd1, 0x04, 0x54, 0x52, 0x9f, 0xa3, 0x47, 0x86, 0x33, 0x33,
++    0xbf, 0xa0, },
++  { 0xcf, 0x04, 0xea, 0xf8, 0x03, 0x2a, 0x43, 0xff, 0xa6, 0x68, 0x21, 0x4c,
++    0xd5, 0x4b, 0xed, },
++  { 0xaf, 0xb8, 0xbc, 0x63, 0x0f, 0x18, 0x4d, 0xe2, 0x7a, 0xdd, 0x46, 0x44,
++    0xc8, 0x24, 0x0a, 0xb7, },
++  { 0x3e, 0xdc, 0x36, 0xe4, 0x89, 0xb1, 0xfa, 0xc6, 0x40, 0x93, 0x2e, 0x75,
++    0xb2, 0x15, 0xd1, 0xb1, 0x10, },
++  { 0x6c, 0xd8, 0x20, 0x3b, 0x82, 0x79, 0xf9, 0xc8, 0xbc, 0x9d, 0xe0, 0x35,
++    0xbe, 0x1b, 0x49, 0x1a, 0xbc, 0x3a, },
++  { 0x78, 0x65, 0x2c, 0xbe, 0x35, 0x67, 0xdc, 0x78, 0xd4, 0x41, 0xf6, 0xc9,
++    0xde, 0xde, 0x1f, 0x18, 0x13, 0x31, 0x11, },
++  { 0x8a, 0x7f, 0xb1, 0x33, 0x8f, 0x0c, 0x3c, 0x0a, 0x06, 0x61, 0xf0, 0x47,
++    0x29, 0x1b, 0x29, 0xbc, 0x1c, 0x47, 0xef, 0x7a, },
++  { 0x65, 0x91, 0xf1, 0xe6, 0xb3, 0x96, 0xd3, 0x8c, 0xc2, 0x4a, 0x59, 0x35,
++    0x72, 0x8e, 0x0b, 0x9a, 0x87, 0xca, 0x34, 0x7b, 0x63, },
++  { 0x5f, 0x08, 0x87, 0x80, 0x56, 0x25, 0x89, 0x77, 0x61, 0x8c, 0x64, 0xa1,
++    0x59, 0x6d, 0x59, 0x62, 0xe8, 0x4a, 0xc8, 0x58, 0x99, 0xd1, },
++  { 0x23, 0x87, 0x1d, 0xed, 0x6f, 0xf2, 0x91, 0x90, 0xe2, 0xfe, 0x43, 0x21,
++    0xaf, 0x97, 0xc6, 0xbc, 0xd7, 0x15, 0xc7, 0x2d, 0x08, 0x77, 0x91, },
++  { 0x90, 0x47, 0x9a, 0x9e, 0x3a, 0xdf, 0xf3, 0xc9, 0x4c, 0x1e, 0xa7, 0xd4,
++    0x6a, 0x32, 0x90, 0xfe, 0xb7, 0xb6, 0x7b, 0xfa, 0x96, 0x61, 0xfb, 0xa4, },
++  { 0xb1, 0x67, 0x60, 0x45, 0xb0, 0x96, 0xc5, 0x15, 0x9f, 0x4d, 0x26, 0xd7,
++    0x9d, 0xf1, 0xf5, 0x6d, 0x21, 0x00, 0x94, 0x31, 0x64, 0x94, 0xd3, 0xa7,
++    0xd3, },
++  { 0x02, 0x3e, 0xaf, 0xf3, 0x79, 0x73, 0xa5, 0xf5, 0xcc, 0x7a, 0x7f, 0xfb,
++    0x79, 0x2b, 0x85, 0x8c, 0x88, 0x72, 0x06, 0xbe, 0xfe, 0xaf, 0xc1, 0x16,
++    0xa6, 0xd6, },
++  { 0x2a, 0xb0, 0x1a, 0xe5, 0xaa, 0x6e, 0xb3, 0xae, 0x53, 0x85, 0x33, 0x80,
++    0x75, 0xae, 0x30, 0xe6, 0xb8, 0x72, 0x42, 0xf6, 0x25, 0x4f, 0x38, 0x88,
++    0x55, 0xd1, 0xa9, },
++  { 0x90, 0xd8, 0x0c, 0xc0, 0x93, 0x4b, 0x4f, 0x9e, 0x65, 0x6c, 0xa1, 0x54,
++    0xa6, 0xf6, 0x6e, 0xca, 0xd2, 0xbb, 0x7e, 0x6a, 0x1c, 0xd3, 0xce, 0x46,
++    0xef, 0xb0, 0x00, 0x8d, },
++  { 0xed, 0x9c, 0x49, 0xcd, 0xc2, 0xde, 0x38, 0x0e, 0xe9, 0x98, 0x6c, 0xc8,
++    0x90, 0x9e, 0x3c, 0xd4, 0xd3, 0xeb, 0x88, 0x32, 0xc7, 0x28, 0xe3, 0x94,
++    0x1c, 0x9f, 0x8b, 0xf3, 0xcb, },
++  { 0xac, 0xe7, 0x92, 0x16, 0xb4, 0x14, 0xa0, 0xe4, 0x04, 0x79, 0xa2, 0xf4,
++    0x31, 0xe6, 0x0c, 0x26, 0xdc, 0xbf, 0x2f, 0x69, 0x1b, 0x55, 0x94, 0x67,
++    0xda, 0x0c, 0xd7, 0x32, 0x1f, 0xef, },
++  { 0x68, 0x63, 0x85, 0x57, 0x95, 0x9e, 0x42, 0x27, 0x41, 0x43, 0x42, 0x02,
++    0xa5, 0x78, 0xa7, 0xc6, 0x43, 0xc1, 0x6a, 0xba, 0x70, 0x80, 0xcd, 0x04,
++    0xb6, 0x78, 0x76, 0x29, 0xf3, 0xe8, 0xa0, },
++  { 0xe6, 0xac, 0x8d, 0x9d, 0xf0, 0xc0, 0xf7, 0xf7, 0xe3, 0x3e, 0x4e, 0x28,
++    0x0f, 0x59, 0xb2, 0x67, 0x9e, 0x84, 0x34, 0x42, 0x96, 0x30, 0x2b, 0xca,
++    0x49, 0xb6, 0xc5, 0x9a, 0x84, 0x59, 0xa7, 0x81, },
++  { 0x7e, },
++  { 0x1e, 0x21, },
++  { 0x26, 0xd3, 0xdd, },
++  { 0x2c, 0xd4, 0xb3, 0x3d, },
++  { 0x86, 0x7b, 0x76, 0x3c, 0xf0, },
++  { 0x12, 0xc3, 0x70, 0x1d, 0x55, 0x18, },
++  { 0x96, 0xc2, 0xbd, 0x61, 0x55, 0xf4, 0x24, },
++  { 0x20, 0x51, 0xf7, 0x86, 0x58, 0x8f, 0x07, 0x2a, },
++  { 0x93, 0x15, 0xa8, 0x1d, 0xda, 0x97, 0xee, 0x0e, 0x6c, },
++  { 0x39, 0x93, 0xdf, 0xd5, 0x0e, 0xca, 0xdc, 0x7a, 0x92, 0xce, },
++  { 0x60, 0xd5, 0xfd, 0xf5, 0x1b, 0x26, 0x82, 0x26, 0x73, 0x02, 0xbc, },
++  { 0x98, 0xf2, 0x34, 0xe1, 0xf5, 0xfb, 0x00, 0xac, 0x10, 0x4a, 0x38, 0x9f, },
++  { 0xda, 0x3a, 0x92, 0x8a, 0xd0, 0xcd, 0x12, 0xcd, 0x15, 0xbb, 0xab, 0x77,
++    0x66, },
++  { 0xa2, 0x92, 0x1a, 0xe5, 0xca, 0x0c, 0x30, 0x75, 0xeb, 0xaf, 0x00, 0x31,
++    0x55, 0x66, },
++  { 0x06, 0xea, 0xfd, 0x3e, 0x86, 0x38, 0x62, 0x4e, 0xa9, 0x12, 0xa4, 0x12,
++    0x43, 0xbf, 0xa1, },
++  { 0xe4, 0x71, 0x7b, 0x94, 0xdb, 0xa0, 0xd2, 0xff, 0x9b, 0xeb, 0xad, 0x8e,
++    0x95, 0x8a, 0xc5, 0xed, },
++  { 0x25, 0x5a, 0x77, 0x71, 0x41, 0x0e, 0x7a, 0xe9, 0xed, 0x0c, 0x10, 0xef,
++    0xf6, 0x2b, 0x3a, 0xba, 0x60, },
++  { 0xee, 0xe2, 0xa3, 0x67, 0x64, 0x1d, 0xc6, 0x04, 0xc4, 0xe1, 0x68, 0xd2,
++    0x6e, 0xd2, 0x91, 0x75, 0x53, 0x07, },
++  { 0xe0, 0xf6, 0x4d, 0x8f, 0x68, 0xfc, 0x06, 0x7e, 0x18, 0x79, 0x7f, 0x2b,
++    0x6d, 0xef, 0x46, 0x7f, 0xab, 0xb2, 0xad, },
++  { 0x3d, 0x35, 0x88, 0x9f, 0x2e, 0xcf, 0x96, 0x45, 0x07, 0x60, 0x71, 0x94,
++    0x00, 0x8d, 0xbf, 0xf4, 0xef, 0x46, 0x2e, 0x3c, },
++  { 0x43, 0xcf, 0x98, 0xf7, 0x2d, 0xf4, 0x17, 0xe7, 0x8c, 0x05, 0x2d, 0x9b,
++    0x24, 0xfb, 0x4d, 0xea, 0x4a, 0xec, 0x01, 0x25, 0x29, },
++  { 0x8e, 0x73, 0x9a, 0x78, 0x11, 0xfe, 0x48, 0xa0, 0x3b, 0x1a, 0x26, 0xdf,
++    0x25, 0xe9, 0x59, 0x1c, 0x70, 0x07, 0x9f, 0xdc, 0xa0, 0xa6, },
++  { 0xe8, 0x47, 0x71, 0xc7, 0x3e, 0xdf, 0xb5, 0x13, 0xb9, 0x85, 0x13, 0xa8,
++    0x54, 0x47, 0x6e, 0x59, 0x96, 0x09, 0x13, 0x5f, 0x82, 0x16, 0x0b, },
++  { 0xfb, 0xc0, 0x8c, 0x03, 0x21, 0xb3, 0xc4, 0xb5, 0x43, 0x32, 0x6c, 0xea,
++    0x7f, 0xa8, 0x43, 0x91, 0xe8, 0x4e, 0x3f, 0xbf, 0x45, 0x58, 0x6a, 0xa3, },
++  { 0x55, 0xf8, 0xf3, 0x00, 0x76, 0x09, 0xef, 0x69, 0x5d, 0xd2, 0x8a, 0xf2,
++    0x65, 0xc3, 0xcb, 0x9b, 0x43, 0xfd, 0xb1, 0x7e, 0x7f, 0xa1, 0x94, 0xb0,
++    0xd7, },
++  { 0xaa, 0x13, 0xc1, 0x51, 0x40, 0x6d, 0x8d, 0x4c, 0x0a, 0x95, 0x64, 0x7b,
++    0xd1, 0x96, 0xb6, 0x56, 0xb4, 0x5b, 0xcf, 0xd6, 0xd9, 0x15, 0x97, 0xdd,
++    0xb6, 0xef, },
++  { 0xaf, 0xb7, 0x36, 0xb0, 0x04, 0xdb, 0xd7, 0x9c, 0x9a, 0x44, 0xc4, 0xf6,
++    0x1f, 0x12, 0x21, 0x2d, 0x59, 0x30, 0x54, 0xab, 0x27, 0x61, 0xa3, 0x57,
++    0xef, 0xf8, 0x53, },
++  { 0x97, 0x34, 0x45, 0x3e, 0xce, 0x7c, 0x35, 0xa2, 0xda, 0x9f, 0x4b, 0x46,
++    0x6c, 0x11, 0x67, 0xff, 0x2f, 0x76, 0x58, 0x15, 0x71, 0xfa, 0x44, 0x89,
++    0x89, 0xfd, 0xf7, 0x99, },
++  { 0x1f, 0xb1, 0x62, 0xeb, 0x83, 0xc5, 0x9c, 0x89, 0xf9, 0x2c, 0xd2, 0x03,
++    0x61, 0xbc, 0xbb, 0xa5, 0x74, 0x0e, 0x9b, 0x7e, 0x82, 0x3e, 0x70, 0x0a,
++    0xa9, 0x8f, 0x2b, 0x59, 0xfb, },
++  { 0xf8, 0xca, 0x5e, 0x3a, 0x4f, 0x9e, 0x10, 0x69, 0x10, 0xd5, 0x4c, 0xeb,
++    0x1a, 0x0f, 0x3c, 0x6a, 0x98, 0xf5, 0xb0, 0x97, 0x5b, 0x37, 0x2f, 0x0d,
++    0xbd, 0x42, 0x4b, 0x69, 0xa1, 0x82, },
++  { 0x12, 0x8c, 0x6d, 0x52, 0x08, 0xef, 0x74, 0xb2, 0xe6, 0xaa, 0xd3, 0xb0,
++    0x26, 0xb0, 0xd9, 0x94, 0xb6, 0x11, 0x45, 0x0e, 0x36, 0x71, 0x14, 0x2d,
++    0x41, 0x8c, 0x21, 0x53, 0x31, 0xe9, 0x68, },
++  { 0xee, 0xea, 0x0d, 0x89, 0x47, 0x7e, 0x72, 0xd1, 0xd8, 0xce, 0x58, 0x4c,
++    0x94, 0x1f, 0x0d, 0x51, 0x08, 0xa3, 0xb6, 0x3d, 0xe7, 0x82, 0x46, 0x92,
++    0xd6, 0x98, 0x6b, 0x07, 0x10, 0x65, 0x52, 0x65, },
++};
++
++static const u8 blake2s_hmac_testvecs[][BLAKE2S_HASH_SIZE] __initconst = {
++  { 0xce, 0xe1, 0x57, 0x69, 0x82, 0xdc, 0xbf, 0x43, 0xad, 0x56, 0x4c, 0x70,
++    0xed, 0x68, 0x16, 0x96, 0xcf, 0xa4, 0x73, 0xe8, 0xe8, 0xfc, 0x32, 0x79,
++    0x08, 0x0a, 0x75, 0x82, 0xda, 0x3f, 0x05, 0x11, },
++  { 0x77, 0x2f, 0x0c, 0x71, 0x41, 0xf4, 0x4b, 0x2b, 0xb3, 0xc6, 0xb6, 0xf9,
++    0x60, 0xde, 0xe4, 0x52, 0x38, 0x66, 0xe8, 0xbf, 0x9b, 0x96, 0xc4, 0x9f,
++    0x60, 0xd9, 0x24, 0x37, 0x99, 0xd6, 0xec, 0x31, },
++};
++
++bool __init blake2s_selftest(void)
++{
++	u8 key[BLAKE2S_KEY_SIZE];
++	u8 buf[ARRAY_SIZE(blake2s_testvecs)];
++	u8 hash[BLAKE2S_HASH_SIZE];
++	struct blake2s_state state;
++	bool success = true;
++	int i, l;
++
++	key[0] = key[1] = 1;
++	for (i = 2; i < sizeof(key); ++i)
++		key[i] = key[i - 2] + key[i - 1];
++
++	for (i = 0; i < sizeof(buf); ++i)
++		buf[i] = (u8)i;
++
++	for (i = l = 0; i < ARRAY_SIZE(blake2s_testvecs); l = (l + 37) % ++i) {
++		int outlen = 1 + i % BLAKE2S_HASH_SIZE;
++		int keylen = (13 * i) % (BLAKE2S_KEY_SIZE + 1);
++
++		blake2s(hash, buf, key + BLAKE2S_KEY_SIZE - keylen, outlen, i,
++			keylen);
++		if (memcmp(hash, blake2s_testvecs[i], outlen)) {
++			pr_err("blake2s self-test %d: FAIL\n", i + 1);
++			success = false;
++		}
++
++		if (!keylen)
++			blake2s_init(&state, outlen);
++		else
++			blake2s_init_key(&state, outlen,
++					 key + BLAKE2S_KEY_SIZE - keylen,
++					 keylen);
++
++		blake2s_update(&state, buf, l);
++		blake2s_update(&state, buf + l, i - l);
++		blake2s_final(&state, hash);
++		if (memcmp(hash, blake2s_testvecs[i], outlen)) {
++			pr_err("blake2s init/update/final self-test %d: FAIL\n",
++			       i + 1);
++			success = false;
++		}
++	}
++
++	if (success) {
++		blake2s256_hmac(hash, buf, key, sizeof(buf), sizeof(key));
++		success &= !memcmp(hash, blake2s_hmac_testvecs[0], BLAKE2S_HASH_SIZE);
++
++		blake2s256_hmac(hash, key, buf, sizeof(key), sizeof(buf));
++		success &= !memcmp(hash, blake2s_hmac_testvecs[1], BLAKE2S_HASH_SIZE);
++
++		if (!success)
++			pr_err("blake2s256_hmac self-test: FAIL\n");
++	}
++
++	return success;
++}
+--- /dev/null
++++ b/lib/crypto/blake2s.c
+@@ -0,0 +1,126 @@
++// SPDX-License-Identifier: GPL-2.0 OR MIT
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ *
++ * This is an implementation of the BLAKE2s hash and PRF functions.
++ *
++ * Information: https://blake2.net/
++ *
++ */
++
++#include <crypto/internal/blake2s.h>
++#include <linux/types.h>
++#include <linux/string.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/bug.h>
++#include <asm/unaligned.h>
++
++bool blake2s_selftest(void);
++
++void blake2s_update(struct blake2s_state *state, const u8 *in, size_t inlen)
++{
++	const size_t fill = BLAKE2S_BLOCK_SIZE - state->buflen;
++
++	if (unlikely(!inlen))
++		return;
++	if (inlen > fill) {
++		memcpy(state->buf + state->buflen, in, fill);
++		if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_BLAKE2S))
++			blake2s_compress_arch(state, state->buf, 1,
++					      BLAKE2S_BLOCK_SIZE);
++		else
++			blake2s_compress_generic(state, state->buf, 1,
++						 BLAKE2S_BLOCK_SIZE);
++		state->buflen = 0;
++		in += fill;
++		inlen -= fill;
++	}
++	if (inlen > BLAKE2S_BLOCK_SIZE) {
++		const size_t nblocks = DIV_ROUND_UP(inlen, BLAKE2S_BLOCK_SIZE);
++		/* Hash one less (full) block than strictly possible */
++		if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_BLAKE2S))
++			blake2s_compress_arch(state, in, nblocks - 1,
++					      BLAKE2S_BLOCK_SIZE);
++		else
++			blake2s_compress_generic(state, in, nblocks - 1,
++						 BLAKE2S_BLOCK_SIZE);
++		in += BLAKE2S_BLOCK_SIZE * (nblocks - 1);
++		inlen -= BLAKE2S_BLOCK_SIZE * (nblocks - 1);
++	}
++	memcpy(state->buf + state->buflen, in, inlen);
++	state->buflen += inlen;
++}
++EXPORT_SYMBOL(blake2s_update);
++
++void blake2s_final(struct blake2s_state *state, u8 *out)
++{
++	WARN_ON(IS_ENABLED(DEBUG) && !out);
++	blake2s_set_lastblock(state);
++	memset(state->buf + state->buflen, 0,
++	       BLAKE2S_BLOCK_SIZE - state->buflen); /* Padding */
++	if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_BLAKE2S))
++		blake2s_compress_arch(state, state->buf, 1, state->buflen);
++	else
++		blake2s_compress_generic(state, state->buf, 1, state->buflen);
++	cpu_to_le32_array(state->h, ARRAY_SIZE(state->h));
++	memcpy(out, state->h, state->outlen);
++	memzero_explicit(state, sizeof(*state));
++}
++EXPORT_SYMBOL(blake2s_final);
++
++void blake2s256_hmac(u8 *out, const u8 *in, const u8 *key, const size_t inlen,
++		     const size_t keylen)
++{
++	struct blake2s_state state;
++	u8 x_key[BLAKE2S_BLOCK_SIZE] __aligned(__alignof__(u32)) = { 0 };
++	u8 i_hash[BLAKE2S_HASH_SIZE] __aligned(__alignof__(u32));
++	int i;
++
++	if (keylen > BLAKE2S_BLOCK_SIZE) {
++		blake2s_init(&state, BLAKE2S_HASH_SIZE);
++		blake2s_update(&state, key, keylen);
++		blake2s_final(&state, x_key);
++	} else
++		memcpy(x_key, key, keylen);
++
++	for (i = 0; i < BLAKE2S_BLOCK_SIZE; ++i)
++		x_key[i] ^= 0x36;
++
++	blake2s_init(&state, BLAKE2S_HASH_SIZE);
++	blake2s_update(&state, x_key, BLAKE2S_BLOCK_SIZE);
++	blake2s_update(&state, in, inlen);
++	blake2s_final(&state, i_hash);
++
++	for (i = 0; i < BLAKE2S_BLOCK_SIZE; ++i)
++		x_key[i] ^= 0x5c ^ 0x36;
++
++	blake2s_init(&state, BLAKE2S_HASH_SIZE);
++	blake2s_update(&state, x_key, BLAKE2S_BLOCK_SIZE);
++	blake2s_update(&state, i_hash, BLAKE2S_HASH_SIZE);
++	blake2s_final(&state, i_hash);
++
++	memcpy(out, i_hash, BLAKE2S_HASH_SIZE);
++	memzero_explicit(x_key, BLAKE2S_BLOCK_SIZE);
++	memzero_explicit(i_hash, BLAKE2S_HASH_SIZE);
++}
++EXPORT_SYMBOL(blake2s256_hmac);
++
++static int __init mod_init(void)
++{
++	if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) &&
++	    WARN_ON(!blake2s_selftest()))
++		return -ENODEV;
++	return 0;
++}
++
++static void __exit mod_exit(void)
++{
++}
++
++module_init(mod_init);
++module_exit(mod_exit);
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("BLAKE2s hash function");
++MODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0022-crypto-testmgr-add-test-cases-for-Blake2s.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0022-crypto-testmgr-add-test-cases-for-Blake2s.patch
new file mode 100644
index 0000000..9adc75e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0022-crypto-testmgr-add-test-cases-for-Blake2s.patch
@@ -0,0 +1,322 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:29 +0100
+Subject: [PATCH] crypto: testmgr - add test cases for Blake2s
+
+commit 17e1df67023a5c9ccaeb5de8bf5b88f63127ecf7 upstream.
+
+As suggested by Eric for the Blake2b implementation contributed by
+David, introduce a set of test vectors for Blake2s covering different
+digest and key sizes.
+
+          blake2s-128  blake2s-160  blake2s-224  blake2s-256
+         ---------------------------------------------------
+len=0   | klen=0       klen=1       klen=16      klen=32
+len=1   | klen=16      klen=32      klen=0       klen=1
+len=7   | klen=32      klen=0       klen=1       klen=16
+len=15  | klen=1       klen=16      klen=32      klen=0
+len=64  | klen=0       klen=1       klen=16      klen=32
+len=247 | klen=16      klen=32      klen=0       klen=1
+len=256 | klen=32      klen=0       klen=1       klen=16
+
+Cc: David Sterba <dsterba@suse.com>
+Cc: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ crypto/testmgr.c |  24 +++++
+ crypto/testmgr.h | 251 +++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 275 insertions(+)
+
+--- a/crypto/testmgr.c
++++ b/crypto/testmgr.c
+@@ -4035,6 +4035,30 @@ static const struct alg_test_desc alg_te
+ 		.test = alg_test_null,
+ 		.fips_allowed = 1,
+ 	}, {
++		.alg = "blake2s-128",
++		.test = alg_test_hash,
++		.suite = {
++			.hash = __VECS(blakes2s_128_tv_template)
++		}
++	}, {
++		.alg = "blake2s-160",
++		.test = alg_test_hash,
++		.suite = {
++			.hash = __VECS(blakes2s_160_tv_template)
++		}
++	}, {
++		.alg = "blake2s-224",
++		.test = alg_test_hash,
++		.suite = {
++			.hash = __VECS(blakes2s_224_tv_template)
++		}
++	}, {
++		.alg = "blake2s-256",
++		.test = alg_test_hash,
++		.suite = {
++			.hash = __VECS(blakes2s_256_tv_template)
++		}
++	}, {
+ 		.alg = "cbc(aes)",
+ 		.test = alg_test_skcipher,
+ 		.fips_allowed = 1,
+--- a/crypto/testmgr.h
++++ b/crypto/testmgr.h
+@@ -31567,4 +31567,255 @@ static const struct aead_testvec essiv_h
+ 	},
+ };
+ 
++static const char blake2_ordered_sequence[] =
++	"\x00\x01\x02\x03\x04\x05\x06\x07"
++	"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
++	"\x10\x11\x12\x13\x14\x15\x16\x17"
++	"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
++	"\x20\x21\x22\x23\x24\x25\x26\x27"
++	"\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
++	"\x30\x31\x32\x33\x34\x35\x36\x37"
++	"\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
++	"\x40\x41\x42\x43\x44\x45\x46\x47"
++	"\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
++	"\x50\x51\x52\x53\x54\x55\x56\x57"
++	"\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
++	"\x60\x61\x62\x63\x64\x65\x66\x67"
++	"\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
++	"\x70\x71\x72\x73\x74\x75\x76\x77"
++	"\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
++	"\x80\x81\x82\x83\x84\x85\x86\x87"
++	"\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
++	"\x90\x91\x92\x93\x94\x95\x96\x97"
++	"\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
++	"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
++	"\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
++	"\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
++	"\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
++	"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
++	"\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
++	"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
++	"\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
++	"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
++	"\xe8\xe9\xea\xeb\xec\xed\xee\xef"
++	"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
++	"\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff";
++
++static const struct hash_testvec blakes2s_128_tv_template[] = {{
++	.digest = (u8[]){ 0x64, 0x55, 0x0d, 0x6f, 0xfe, 0x2c, 0x0a, 0x01,
++			  0xa1, 0x4a, 0xba, 0x1e, 0xad, 0xe0, 0x20, 0x0c, },
++}, {
++	.plaintext = blake2_ordered_sequence,
++	.psize = 64,
++	.digest = (u8[]){ 0xdc, 0x66, 0xca, 0x8f, 0x03, 0x86, 0x58, 0x01,
++			  0xb0, 0xff, 0xe0, 0x6e, 0xd8, 0xa1, 0xa9, 0x0e, },
++}, {
++	.ksize = 16,
++	.key = blake2_ordered_sequence,
++	.plaintext = blake2_ordered_sequence,
++	.psize = 1,
++	.digest = (u8[]){ 0x88, 0x1e, 0x42, 0xe7, 0xbb, 0x35, 0x80, 0x82,
++			  0x63, 0x7c, 0x0a, 0x0f, 0xd7, 0xec, 0x6c, 0x2f, },
++}, {
++	.ksize = 32,
++	.key = blake2_ordered_sequence,
++	.plaintext = blake2_ordered_sequence,
++	.psize = 7,
++	.digest = (u8[]){ 0xcf, 0x9e, 0x07, 0x2a, 0xd5, 0x22, 0xf2, 0xcd,
++			  0xa2, 0xd8, 0x25, 0x21, 0x80, 0x86, 0x73, 0x1c, },
++}, {
++	.ksize = 1,
++	.key = "B",
++	.plaintext = blake2_ordered_sequence,
++	.psize = 15,
++	.digest = (u8[]){ 0xf6, 0x33, 0x5a, 0x2c, 0x22, 0xa0, 0x64, 0xb2,
++			  0xb6, 0x3f, 0xeb, 0xbc, 0xd1, 0xc3, 0xe5, 0xb2, },
++}, {
++	.ksize = 16,
++	.key = blake2_ordered_sequence,
++	.plaintext = blake2_ordered_sequence,
++	.psize = 247,
++	.digest = (u8[]){ 0x72, 0x66, 0x49, 0x60, 0xf9, 0x4a, 0xea, 0xbe,
++			  0x1f, 0xf4, 0x60, 0xce, 0xb7, 0x81, 0xcb, 0x09, },
++}, {
++	.ksize = 32,
++	.key = blake2_ordered_sequence,
++	.plaintext = blake2_ordered_sequence,
++	.psize = 256,
++	.digest = (u8[]){ 0xd5, 0xa4, 0x0e, 0xc3, 0x16, 0xc7, 0x51, 0xa6,
++			  0x3c, 0xd0, 0xd9, 0x11, 0x57, 0xfa, 0x1e, 0xbb, },
++}};
++
++static const struct hash_testvec blakes2s_160_tv_template[] = {{
++	.plaintext = blake2_ordered_sequence,
++	.psize = 7,
++	.digest = (u8[]){ 0xb4, 0xf2, 0x03, 0x49, 0x37, 0xed, 0xb1, 0x3e,
++			  0x5b, 0x2a, 0xca, 0x64, 0x82, 0x74, 0xf6, 0x62,
++			  0xe3, 0xf2, 0x84, 0xff, },
++}, {
++	.plaintext = blake2_ordered_sequence,
++	.psize = 256,
++	.digest = (u8[]){ 0xaa, 0x56, 0x9b, 0xdc, 0x98, 0x17, 0x75, 0xf2,
++			  0xb3, 0x68, 0x83, 0xb7, 0x9b, 0x8d, 0x48, 0xb1,
++			  0x9b, 0x2d, 0x35, 0x05, },
++}, {
++	.ksize = 1,
++	.key = "B",
++	.digest = (u8[]){ 0x50, 0x16, 0xe7, 0x0c, 0x01, 0xd0, 0xd3, 0xc3,
++			  0xf4, 0x3e, 0xb1, 0x6e, 0x97, 0xa9, 0x4e, 0xd1,
++			  0x79, 0x65, 0x32, 0x93, },
++}, {
++	.ksize = 32,
++	.key = blake2_ordered_sequence,
++	.plaintext = blake2_ordered_sequence,
++	.psize = 1,
++	.digest = (u8[]){ 0x1c, 0x2b, 0xcd, 0x9a, 0x68, 0xca, 0x8c, 0x71,
++			  0x90, 0x29, 0x6c, 0x54, 0xfa, 0x56, 0x4a, 0xef,
++			  0xa2, 0x3a, 0x56, 0x9c, },
++}, {
++	.ksize = 16,
++	.key = blake2_ordered_sequence,
++	.plaintext = blake2_ordered_sequence,
++	.psize = 15,
++	.digest = (u8[]){ 0x36, 0xc3, 0x5f, 0x9a, 0xdc, 0x7e, 0xbf, 0x19,
++			  0x68, 0xaa, 0xca, 0xd8, 0x81, 0xbf, 0x09, 0x34,
++			  0x83, 0x39, 0x0f, 0x30, },
++}, {
++	.ksize = 1,
++	.key = "B",
++	.plaintext = blake2_ordered_sequence,
++	.psize = 64,
++	.digest = (u8[]){ 0x86, 0x80, 0x78, 0xa4, 0x14, 0xec, 0x03, 0xe5,
++			  0xb6, 0x9a, 0x52, 0x0e, 0x42, 0xee, 0x39, 0x9d,
++			  0xac, 0xa6, 0x81, 0x63, },
++}, {
++	.ksize = 32,
++	.key = blake2_ordered_sequence,
++	.plaintext = blake2_ordered_sequence,
++	.psize = 247,
++	.digest = (u8[]){ 0x2d, 0xd8, 0xd2, 0x53, 0x66, 0xfa, 0xa9, 0x01,
++			  0x1c, 0x9c, 0xaf, 0xa3, 0xe2, 0x9d, 0x9b, 0x10,
++			  0x0a, 0xf6, 0x73, 0xe8, },
++}};
++
++static const struct hash_testvec blakes2s_224_tv_template[] = {{
++	.plaintext = blake2_ordered_sequence,
++	.psize = 1,
++	.digest = (u8[]){ 0x61, 0xb9, 0x4e, 0xc9, 0x46, 0x22, 0xa3, 0x91,
++			  0xd2, 0xae, 0x42, 0xe6, 0x45, 0x6c, 0x90, 0x12,
++			  0xd5, 0x80, 0x07, 0x97, 0xb8, 0x86, 0x5a, 0xfc,
++			  0x48, 0x21, 0x97, 0xbb, },
++}, {
++	.plaintext = blake2_ordered_sequence,
++	.psize = 247,
++	.digest = (u8[]){ 0x9e, 0xda, 0xc7, 0x20, 0x2c, 0xd8, 0x48, 0x2e,
++			  0x31, 0x94, 0xab, 0x46, 0x6d, 0x94, 0xd8, 0xb4,
++			  0x69, 0xcd, 0xae, 0x19, 0x6d, 0x9e, 0x41, 0xcc,
++			  0x2b, 0xa4, 0xd5, 0xf6, },
++}, {
++	.ksize = 16,
++	.key = blake2_ordered_sequence,
++	.digest = (u8[]){ 0x32, 0xc0, 0xac, 0xf4, 0x3b, 0xd3, 0x07, 0x9f,
++			  0xbe, 0xfb, 0xfa, 0x4d, 0x6b, 0x4e, 0x56, 0xb3,
++			  0xaa, 0xd3, 0x27, 0xf6, 0x14, 0xbf, 0xb9, 0x32,
++			  0xa7, 0x19, 0xfc, 0xb8, },
++}, {
++	.ksize = 1,
++	.key = "B",
++	.plaintext = blake2_ordered_sequence,
++	.psize = 7,
++	.digest = (u8[]){ 0x73, 0xad, 0x5e, 0x6d, 0xb9, 0x02, 0x8e, 0x76,
++			  0xf2, 0x66, 0x42, 0x4b, 0x4c, 0xfa, 0x1f, 0xe6,
++			  0x2e, 0x56, 0x40, 0xe5, 0xa2, 0xb0, 0x3c, 0xe8,
++			  0x7b, 0x45, 0xfe, 0x05, },
++}, {
++	.ksize = 32,
++	.key = blake2_ordered_sequence,
++	.plaintext = blake2_ordered_sequence,
++	.psize = 15,
++	.digest = (u8[]){ 0x16, 0x60, 0xfb, 0x92, 0x54, 0xb3, 0x6e, 0x36,
++			  0x81, 0xf4, 0x16, 0x41, 0xc3, 0x3d, 0xd3, 0x43,
++			  0x84, 0xed, 0x10, 0x6f, 0x65, 0x80, 0x7a, 0x3e,
++			  0x25, 0xab, 0xc5, 0x02, },
++}, {
++	.ksize = 16,
++	.key = blake2_ordered_sequence,
++	.plaintext = blake2_ordered_sequence,
++	.psize = 64,
++	.digest = (u8[]){ 0xca, 0xaa, 0x39, 0x67, 0x9c, 0xf7, 0x6b, 0xc7,
++			  0xb6, 0x82, 0xca, 0x0e, 0x65, 0x36, 0x5b, 0x7c,
++			  0x24, 0x00, 0xfa, 0x5f, 0xda, 0x06, 0x91, 0x93,
++			  0x6a, 0x31, 0x83, 0xb5, },
++}, {
++	.ksize = 1,
++	.key = "B",
++	.plaintext = blake2_ordered_sequence,
++	.psize = 256,
++	.digest = (u8[]){ 0x90, 0x02, 0x26, 0xb5, 0x06, 0x9c, 0x36, 0x86,
++			  0x94, 0x91, 0x90, 0x1e, 0x7d, 0x2a, 0x71, 0xb2,
++			  0x48, 0xb5, 0xe8, 0x16, 0xfd, 0x64, 0x33, 0x45,
++			  0xb3, 0xd7, 0xec, 0xcc, },
++}};
++
++static const struct hash_testvec blakes2s_256_tv_template[] = {{
++	.plaintext = blake2_ordered_sequence,
++	.psize = 15,
++	.digest = (u8[]){ 0xd9, 0x7c, 0x82, 0x8d, 0x81, 0x82, 0xa7, 0x21,
++			  0x80, 0xa0, 0x6a, 0x78, 0x26, 0x83, 0x30, 0x67,
++			  0x3f, 0x7c, 0x4e, 0x06, 0x35, 0x94, 0x7c, 0x04,
++			  0xc0, 0x23, 0x23, 0xfd, 0x45, 0xc0, 0xa5, 0x2d, },
++}, {
++	.ksize = 32,
++	.key = blake2_ordered_sequence,
++	.digest = (u8[]){ 0x48, 0xa8, 0x99, 0x7d, 0xa4, 0x07, 0x87, 0x6b,
++			  0x3d, 0x79, 0xc0, 0xd9, 0x23, 0x25, 0xad, 0x3b,
++			  0x89, 0xcb, 0xb7, 0x54, 0xd8, 0x6a, 0xb7, 0x1a,
++			  0xee, 0x04, 0x7a, 0xd3, 0x45, 0xfd, 0x2c, 0x49, },
++}, {
++	.ksize = 1,
++	.key = "B",
++	.plaintext = blake2_ordered_sequence,
++	.psize = 1,
++	.digest = (u8[]){ 0x22, 0x27, 0xae, 0xaa, 0x6e, 0x81, 0x56, 0x03,
++			  0xa7, 0xe3, 0xa1, 0x18, 0xa5, 0x9a, 0x2c, 0x18,
++			  0xf4, 0x63, 0xbc, 0x16, 0x70, 0xf1, 0xe7, 0x4b,
++			  0x00, 0x6d, 0x66, 0x16, 0xae, 0x9e, 0x74, 0x4e, },
++}, {
++	.ksize = 16,
++	.key = blake2_ordered_sequence,
++	.plaintext = blake2_ordered_sequence,
++	.psize = 7,
++	.digest = (u8[]){ 0x58, 0x5d, 0xa8, 0x60, 0x1c, 0xa4, 0xd8, 0x03,
++			  0x86, 0x86, 0x84, 0x64, 0xd7, 0xa0, 0x8e, 0x15,
++			  0x2f, 0x05, 0xa2, 0x1b, 0xbc, 0xef, 0x7a, 0x34,
++			  0xb3, 0xc5, 0xbc, 0x4b, 0xf0, 0x32, 0xeb, 0x12, },
++}, {
++	.ksize = 32,
++	.key = blake2_ordered_sequence,
++	.plaintext = blake2_ordered_sequence,
++	.psize = 64,
++	.digest = (u8[]){ 0x89, 0x75, 0xb0, 0x57, 0x7f, 0xd3, 0x55, 0x66,
++			  0xd7, 0x50, 0xb3, 0x62, 0xb0, 0x89, 0x7a, 0x26,
++			  0xc3, 0x99, 0x13, 0x6d, 0xf0, 0x7b, 0xab, 0xab,
++			  0xbd, 0xe6, 0x20, 0x3f, 0xf2, 0x95, 0x4e, 0xd4, },
++}, {
++	.ksize = 1,
++	.key = "B",
++	.plaintext = blake2_ordered_sequence,
++	.psize = 247,
++	.digest = (u8[]){ 0x2e, 0x74, 0x1c, 0x1d, 0x03, 0xf4, 0x9d, 0x84,
++			  0x6f, 0xfc, 0x86, 0x32, 0x92, 0x49, 0x7e, 0x66,
++			  0xd7, 0xc3, 0x10, 0x88, 0xfe, 0x28, 0xb3, 0xe0,
++			  0xbf, 0x50, 0x75, 0xad, 0x8e, 0xa4, 0xe6, 0xb2, },
++}, {
++	.ksize = 16,
++	.key = blake2_ordered_sequence,
++	.plaintext = blake2_ordered_sequence,
++	.psize = 256,
++	.digest = (u8[]){ 0xb9, 0xd2, 0x81, 0x0e, 0x3a, 0xb1, 0x62, 0x9b,
++			  0xad, 0x44, 0x05, 0xf4, 0x92, 0x2e, 0x99, 0xc1,
++			  0x4a, 0x47, 0xbb, 0x5b, 0x6f, 0xb2, 0x96, 0xed,
++			  0xd5, 0x06, 0xb5, 0x3a, 0x7c, 0x7a, 0x65, 0x1d, },
++}};
++
+ #endif	/* _CRYPTO_TESTMGR_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0023-crypto-blake2s-implement-generic-shash-driver.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0023-crypto-blake2s-implement-generic-shash-driver.patch
new file mode 100644
index 0000000..e25edf5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0023-crypto-blake2s-implement-generic-shash-driver.patch
@@ -0,0 +1,245 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:30 +0100
+Subject: [PATCH] crypto: blake2s - implement generic shash driver
+
+commit 7f9b0880925f1f9d7d59504ea0892d2ae9cfc233 upstream.
+
+Wire up our newly added Blake2s implementation via the shash API.
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ crypto/Kconfig                    |  18 ++++
+ crypto/Makefile                   |   1 +
+ crypto/blake2s_generic.c          | 171 ++++++++++++++++++++++++++++++
+ include/crypto/internal/blake2s.h |   5 +
+ 4 files changed, 195 insertions(+)
+ create mode 100644 crypto/blake2s_generic.c
+
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -639,6 +639,24 @@ config CRYPTO_XXHASH
+ 	  xxHash non-cryptographic hash algorithm. Extremely fast, working at
+ 	  speeds close to RAM limits.
+ 
++config CRYPTO_BLAKE2S
++	tristate "BLAKE2s digest algorithm"
++	select CRYPTO_LIB_BLAKE2S_GENERIC
++	select CRYPTO_HASH
++	help
++	  Implementation of cryptographic hash function BLAKE2s
++	  optimized for 8-32bit platforms and can produce digests of any size
++	  between 1 to 32.  The keyed hash is also implemented.
++
++	  This module provides the following algorithms:
++
++	  - blake2s-128
++	  - blake2s-160
++	  - blake2s-224
++	  - blake2s-256
++
++	  See https://blake2.net for further information.
++
+ config CRYPTO_CRCT10DIF
+ 	tristate "CRCT10DIF algorithm"
+ 	select CRYPTO_HASH
+--- a/crypto/Makefile
++++ b/crypto/Makefile
+@@ -74,6 +74,7 @@ obj-$(CONFIG_CRYPTO_STREEBOG) += streebo
+ obj-$(CONFIG_CRYPTO_WP512) += wp512.o
+ CFLAGS_wp512.o := $(call cc-option,-fno-schedule-insns)  # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79149
+ obj-$(CONFIG_CRYPTO_TGR192) += tgr192.o
++obj-$(CONFIG_CRYPTO_BLAKE2S) += blake2s_generic.o
+ obj-$(CONFIG_CRYPTO_GF128MUL) += gf128mul.o
+ obj-$(CONFIG_CRYPTO_ECB) += ecb.o
+ obj-$(CONFIG_CRYPTO_CBC) += cbc.o
+--- /dev/null
++++ b/crypto/blake2s_generic.c
+@@ -0,0 +1,171 @@
++// SPDX-License-Identifier: GPL-2.0 OR MIT
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#include <crypto/internal/blake2s.h>
++#include <crypto/internal/simd.h>
++#include <crypto/internal/hash.h>
++
++#include <linux/types.h>
++#include <linux/jump_label.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++
++static int crypto_blake2s_setkey(struct crypto_shash *tfm, const u8 *key,
++				 unsigned int keylen)
++{
++	struct blake2s_tfm_ctx *tctx = crypto_shash_ctx(tfm);
++
++	if (keylen == 0 || keylen > BLAKE2S_KEY_SIZE) {
++		crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
++		return -EINVAL;
++	}
++
++	memcpy(tctx->key, key, keylen);
++	tctx->keylen = keylen;
++
++	return 0;
++}
++
++static int crypto_blake2s_init(struct shash_desc *desc)
++{
++	struct blake2s_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm);
++	struct blake2s_state *state = shash_desc_ctx(desc);
++	const int outlen = crypto_shash_digestsize(desc->tfm);
++
++	if (tctx->keylen)
++		blake2s_init_key(state, outlen, tctx->key, tctx->keylen);
++	else
++		blake2s_init(state, outlen);
++
++	return 0;
++}
++
++static int crypto_blake2s_update(struct shash_desc *desc, const u8 *in,
++				 unsigned int inlen)
++{
++	struct blake2s_state *state = shash_desc_ctx(desc);
++	const size_t fill = BLAKE2S_BLOCK_SIZE - state->buflen;
++
++	if (unlikely(!inlen))
++		return 0;
++	if (inlen > fill) {
++		memcpy(state->buf + state->buflen, in, fill);
++		blake2s_compress_generic(state, state->buf, 1, BLAKE2S_BLOCK_SIZE);
++		state->buflen = 0;
++		in += fill;
++		inlen -= fill;
++	}
++	if (inlen > BLAKE2S_BLOCK_SIZE) {
++		const size_t nblocks = DIV_ROUND_UP(inlen, BLAKE2S_BLOCK_SIZE);
++		/* Hash one less (full) block than strictly possible */
++		blake2s_compress_generic(state, in, nblocks - 1, BLAKE2S_BLOCK_SIZE);
++		in += BLAKE2S_BLOCK_SIZE * (nblocks - 1);
++		inlen -= BLAKE2S_BLOCK_SIZE * (nblocks - 1);
++	}
++	memcpy(state->buf + state->buflen, in, inlen);
++	state->buflen += inlen;
++
++	return 0;
++}
++
++static int crypto_blake2s_final(struct shash_desc *desc, u8 *out)
++{
++	struct blake2s_state *state = shash_desc_ctx(desc);
++
++	blake2s_set_lastblock(state);
++	memset(state->buf + state->buflen, 0,
++	       BLAKE2S_BLOCK_SIZE - state->buflen); /* Padding */
++	blake2s_compress_generic(state, state->buf, 1, state->buflen);
++	cpu_to_le32_array(state->h, ARRAY_SIZE(state->h));
++	memcpy(out, state->h, state->outlen);
++	memzero_explicit(state, sizeof(*state));
++
++	return 0;
++}
++
++static struct shash_alg blake2s_algs[] = {{
++	.base.cra_name		= "blake2s-128",
++	.base.cra_driver_name	= "blake2s-128-generic",
++	.base.cra_flags		= CRYPTO_ALG_OPTIONAL_KEY,
++	.base.cra_ctxsize	= sizeof(struct blake2s_tfm_ctx),
++	.base.cra_priority	= 200,
++	.base.cra_blocksize     = BLAKE2S_BLOCK_SIZE,
++	.base.cra_module	= THIS_MODULE,
++
++	.digestsize		= BLAKE2S_128_HASH_SIZE,
++	.setkey			= crypto_blake2s_setkey,
++	.init			= crypto_blake2s_init,
++	.update			= crypto_blake2s_update,
++	.final			= crypto_blake2s_final,
++	.descsize		= sizeof(struct blake2s_state),
++}, {
++	.base.cra_name		= "blake2s-160",
++	.base.cra_driver_name	= "blake2s-160-generic",
++	.base.cra_flags		= CRYPTO_ALG_OPTIONAL_KEY,
++	.base.cra_ctxsize	= sizeof(struct blake2s_tfm_ctx),
++	.base.cra_priority	= 200,
++	.base.cra_blocksize     = BLAKE2S_BLOCK_SIZE,
++	.base.cra_module	= THIS_MODULE,
++
++	.digestsize		= BLAKE2S_160_HASH_SIZE,
++	.setkey			= crypto_blake2s_setkey,
++	.init			= crypto_blake2s_init,
++	.update			= crypto_blake2s_update,
++	.final			= crypto_blake2s_final,
++	.descsize		= sizeof(struct blake2s_state),
++}, {
++	.base.cra_name		= "blake2s-224",
++	.base.cra_driver_name	= "blake2s-224-generic",
++	.base.cra_flags		= CRYPTO_ALG_OPTIONAL_KEY,
++	.base.cra_ctxsize	= sizeof(struct blake2s_tfm_ctx),
++	.base.cra_priority	= 200,
++	.base.cra_blocksize     = BLAKE2S_BLOCK_SIZE,
++	.base.cra_module	= THIS_MODULE,
++
++	.digestsize		= BLAKE2S_224_HASH_SIZE,
++	.setkey			= crypto_blake2s_setkey,
++	.init			= crypto_blake2s_init,
++	.update			= crypto_blake2s_update,
++	.final			= crypto_blake2s_final,
++	.descsize		= sizeof(struct blake2s_state),
++}, {
++	.base.cra_name		= "blake2s-256",
++	.base.cra_driver_name	= "blake2s-256-generic",
++	.base.cra_flags		= CRYPTO_ALG_OPTIONAL_KEY,
++	.base.cra_ctxsize	= sizeof(struct blake2s_tfm_ctx),
++	.base.cra_priority	= 200,
++	.base.cra_blocksize     = BLAKE2S_BLOCK_SIZE,
++	.base.cra_module	= THIS_MODULE,
++
++	.digestsize		= BLAKE2S_256_HASH_SIZE,
++	.setkey			= crypto_blake2s_setkey,
++	.init			= crypto_blake2s_init,
++	.update			= crypto_blake2s_update,
++	.final			= crypto_blake2s_final,
++	.descsize		= sizeof(struct blake2s_state),
++}};
++
++static int __init blake2s_mod_init(void)
++{
++	return crypto_register_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs));
++}
++
++static void __exit blake2s_mod_exit(void)
++{
++	crypto_unregister_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs));
++}
++
++subsys_initcall(blake2s_mod_init);
++module_exit(blake2s_mod_exit);
++
++MODULE_ALIAS_CRYPTO("blake2s-128");
++MODULE_ALIAS_CRYPTO("blake2s-128-generic");
++MODULE_ALIAS_CRYPTO("blake2s-160");
++MODULE_ALIAS_CRYPTO("blake2s-160-generic");
++MODULE_ALIAS_CRYPTO("blake2s-224");
++MODULE_ALIAS_CRYPTO("blake2s-224-generic");
++MODULE_ALIAS_CRYPTO("blake2s-256");
++MODULE_ALIAS_CRYPTO("blake2s-256-generic");
++MODULE_LICENSE("GPL v2");
+--- a/include/crypto/internal/blake2s.h
++++ b/include/crypto/internal/blake2s.h
+@@ -5,6 +5,11 @@
+ 
+ #include <crypto/blake2s.h>
+ 
++struct blake2s_tfm_ctx {
++	u8 key[BLAKE2S_KEY_SIZE];
++	unsigned int keylen;
++};
++
+ void blake2s_compress_generic(struct blake2s_state *state,const u8 *block,
+ 			      size_t nblocks, const u32 inc);
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0024-crypto-blake2s-x86_64-SIMD-implementation.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0024-crypto-blake2s-x86_64-SIMD-implementation.patch
new file mode 100644
index 0000000..0440558
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0024-crypto-blake2s-x86_64-SIMD-implementation.patch
@@ -0,0 +1,557 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 8 Nov 2019 13:22:31 +0100
+Subject: [PATCH] crypto: blake2s - x86_64 SIMD implementation
+
+commit ed0356eda153f6a95649e11feb7b07083caf9e20 upstream.
+
+These implementations from Samuel Neves support AVX and AVX-512VL.
+Originally this used AVX-512F, but Skylake thermal throttling made
+AVX-512VL more attractive and possible to do with negligable difference.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Samuel Neves <sneves@dei.uc.pt>
+Co-developed-by: Samuel Neves <sneves@dei.uc.pt>
+[ardb: move to arch/x86/crypto, wire into lib/crypto framework]
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/Makefile       |   2 +
+ arch/x86/crypto/blake2s-core.S | 258 +++++++++++++++++++++++++++++++++
+ arch/x86/crypto/blake2s-glue.c | 233 +++++++++++++++++++++++++++++
+ crypto/Kconfig                 |   6 +
+ 4 files changed, 499 insertions(+)
+ create mode 100644 arch/x86/crypto/blake2s-core.S
+ create mode 100644 arch/x86/crypto/blake2s-glue.c
+
+--- a/arch/x86/crypto/Makefile
++++ b/arch/x86/crypto/Makefile
+@@ -48,6 +48,7 @@ ifeq ($(avx_supported),yes)
+ 	obj-$(CONFIG_CRYPTO_CAST6_AVX_X86_64) += cast6-avx-x86_64.o
+ 	obj-$(CONFIG_CRYPTO_TWOFISH_AVX_X86_64) += twofish-avx-x86_64.o
+ 	obj-$(CONFIG_CRYPTO_SERPENT_AVX_X86_64) += serpent-avx-x86_64.o
++	obj-$(CONFIG_CRYPTO_BLAKE2S_X86) += blake2s-x86_64.o
+ endif
+ 
+ # These modules require assembler to support AVX2.
+@@ -70,6 +71,7 @@ serpent-sse2-x86_64-y := serpent-sse2-x8
+ aegis128-aesni-y := aegis128-aesni-asm.o aegis128-aesni-glue.o
+ 
+ nhpoly1305-sse2-y := nh-sse2-x86_64.o nhpoly1305-sse2-glue.o
++blake2s-x86_64-y := blake2s-core.o blake2s-glue.o
+ 
+ ifeq ($(avx_supported),yes)
+ 	camellia-aesni-avx-x86_64-y := camellia-aesni-avx-asm_64.o \
+--- /dev/null
++++ b/arch/x86/crypto/blake2s-core.S
+@@ -0,0 +1,258 @@
++/* SPDX-License-Identifier: GPL-2.0 OR MIT */
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ * Copyright (C) 2017-2019 Samuel Neves <sneves@dei.uc.pt>. All Rights Reserved.
++ */
++
++#include <linux/linkage.h>
++
++.section .rodata.cst32.BLAKE2S_IV, "aM", @progbits, 32
++.align 32
++IV:	.octa 0xA54FF53A3C6EF372BB67AE856A09E667
++	.octa 0x5BE0CD191F83D9AB9B05688C510E527F
++.section .rodata.cst16.ROT16, "aM", @progbits, 16
++.align 16
++ROT16:	.octa 0x0D0C0F0E09080B0A0504070601000302
++.section .rodata.cst16.ROR328, "aM", @progbits, 16
++.align 16
++ROR328:	.octa 0x0C0F0E0D080B0A090407060500030201
++.section .rodata.cst64.BLAKE2S_SIGMA, "aM", @progbits, 160
++.align 64
++SIGMA:
++.byte  0,  2,  4,  6,  1,  3,  5,  7, 14,  8, 10, 12, 15,  9, 11, 13
++.byte 14,  4,  9, 13, 10,  8, 15,  6,  5,  1,  0, 11,  3, 12,  2,  7
++.byte 11, 12,  5, 15,  8,  0,  2, 13,  9, 10,  3,  7,  4, 14,  6,  1
++.byte  7,  3, 13, 11,  9,  1, 12, 14, 15,  2,  5,  4,  8,  6, 10,  0
++.byte  9,  5,  2, 10,  0,  7,  4, 15,  3, 14, 11,  6, 13,  1, 12,  8
++.byte  2,  6,  0,  8, 12, 10, 11,  3,  1,  4,  7, 15,  9, 13,  5, 14
++.byte 12,  1, 14,  4,  5, 15, 13, 10,  8,  0,  6,  9, 11,  7,  3,  2
++.byte 13,  7, 12,  3, 11, 14,  1,  9,  2,  5, 15,  8, 10,  0,  4,  6
++.byte  6, 14, 11,  0, 15,  9,  3,  8, 10, 12, 13,  1,  5,  2,  7,  4
++.byte 10,  8,  7,  1,  2,  4,  6,  5, 13, 15,  9,  3,  0, 11, 14, 12
++#ifdef CONFIG_AS_AVX512
++.section .rodata.cst64.BLAKE2S_SIGMA2, "aM", @progbits, 640
++.align 64
++SIGMA2:
++.long  0,  2,  4,  6,  1,  3,  5,  7, 14,  8, 10, 12, 15,  9, 11, 13
++.long  8,  2, 13, 15, 10,  9, 12,  3,  6,  4,  0, 14,  5, 11,  1,  7
++.long 11, 13,  8,  6,  5, 10, 14,  3,  2,  4, 12, 15,  1,  0,  7,  9
++.long 11, 10,  7,  0,  8, 15,  1, 13,  3,  6,  2, 12,  4, 14,  9,  5
++.long  4, 10,  9, 14, 15,  0, 11,  8,  1,  7,  3, 13,  2,  5,  6, 12
++.long  2, 11,  4, 15, 14,  3, 10,  8, 13,  6,  5,  7,  0, 12,  1,  9
++.long  4,  8, 15,  9, 14, 11, 13,  5,  3,  2,  1, 12,  6, 10,  7,  0
++.long  6, 13,  0, 14, 12,  2,  1, 11, 15,  4,  5,  8,  7,  9,  3, 10
++.long 15,  5,  4, 13, 10,  7,  3, 11, 12,  2,  0,  6,  9,  8,  1, 14
++.long  8,  7, 14, 11, 13, 15,  0, 12, 10,  4,  5,  6,  3,  2,  1,  9
++#endif /* CONFIG_AS_AVX512 */
++
++.text
++#ifdef CONFIG_AS_SSSE3
++ENTRY(blake2s_compress_ssse3)
++	testq		%rdx,%rdx
++	je		.Lendofloop
++	movdqu		(%rdi),%xmm0
++	movdqu		0x10(%rdi),%xmm1
++	movdqa		ROT16(%rip),%xmm12
++	movdqa		ROR328(%rip),%xmm13
++	movdqu		0x20(%rdi),%xmm14
++	movq		%rcx,%xmm15
++	leaq		SIGMA+0xa0(%rip),%r8
++	jmp		.Lbeginofloop
++	.align		32
++.Lbeginofloop:
++	movdqa		%xmm0,%xmm10
++	movdqa		%xmm1,%xmm11
++	paddq		%xmm15,%xmm14
++	movdqa		IV(%rip),%xmm2
++	movdqa		%xmm14,%xmm3
++	pxor		IV+0x10(%rip),%xmm3
++	leaq		SIGMA(%rip),%rcx
++.Lroundloop:
++	movzbl		(%rcx),%eax
++	movd		(%rsi,%rax,4),%xmm4
++	movzbl		0x1(%rcx),%eax
++	movd		(%rsi,%rax,4),%xmm5
++	movzbl		0x2(%rcx),%eax
++	movd		(%rsi,%rax,4),%xmm6
++	movzbl		0x3(%rcx),%eax
++	movd		(%rsi,%rax,4),%xmm7
++	punpckldq	%xmm5,%xmm4
++	punpckldq	%xmm7,%xmm6
++	punpcklqdq	%xmm6,%xmm4
++	paddd		%xmm4,%xmm0
++	paddd		%xmm1,%xmm0
++	pxor		%xmm0,%xmm3
++	pshufb		%xmm12,%xmm3
++	paddd		%xmm3,%xmm2
++	pxor		%xmm2,%xmm1
++	movdqa		%xmm1,%xmm8
++	psrld		$0xc,%xmm1
++	pslld		$0x14,%xmm8
++	por		%xmm8,%xmm1
++	movzbl		0x4(%rcx),%eax
++	movd		(%rsi,%rax,4),%xmm5
++	movzbl		0x5(%rcx),%eax
++	movd		(%rsi,%rax,4),%xmm6
++	movzbl		0x6(%rcx),%eax
++	movd		(%rsi,%rax,4),%xmm7
++	movzbl		0x7(%rcx),%eax
++	movd		(%rsi,%rax,4),%xmm4
++	punpckldq	%xmm6,%xmm5
++	punpckldq	%xmm4,%xmm7
++	punpcklqdq	%xmm7,%xmm5
++	paddd		%xmm5,%xmm0
++	paddd		%xmm1,%xmm0
++	pxor		%xmm0,%xmm3
++	pshufb		%xmm13,%xmm3
++	paddd		%xmm3,%xmm2
++	pxor		%xmm2,%xmm1
++	movdqa		%xmm1,%xmm8
++	psrld		$0x7,%xmm1
++	pslld		$0x19,%xmm8
++	por		%xmm8,%xmm1
++	pshufd		$0x93,%xmm0,%xmm0
++	pshufd		$0x4e,%xmm3,%xmm3
++	pshufd		$0x39,%xmm2,%xmm2
++	movzbl		0x8(%rcx),%eax
++	movd		(%rsi,%rax,4),%xmm6
++	movzbl		0x9(%rcx),%eax
++	movd		(%rsi,%rax,4),%xmm7
++	movzbl		0xa(%rcx),%eax
++	movd		(%rsi,%rax,4),%xmm4
++	movzbl		0xb(%rcx),%eax
++	movd		(%rsi,%rax,4),%xmm5
++	punpckldq	%xmm7,%xmm6
++	punpckldq	%xmm5,%xmm4
++	punpcklqdq	%xmm4,%xmm6
++	paddd		%xmm6,%xmm0
++	paddd		%xmm1,%xmm0
++	pxor		%xmm0,%xmm3
++	pshufb		%xmm12,%xmm3
++	paddd		%xmm3,%xmm2
++	pxor		%xmm2,%xmm1
++	movdqa		%xmm1,%xmm8
++	psrld		$0xc,%xmm1
++	pslld		$0x14,%xmm8
++	por		%xmm8,%xmm1
++	movzbl		0xc(%rcx),%eax
++	movd		(%rsi,%rax,4),%xmm7
++	movzbl		0xd(%rcx),%eax
++	movd		(%rsi,%rax,4),%xmm4
++	movzbl		0xe(%rcx),%eax
++	movd		(%rsi,%rax,4),%xmm5
++	movzbl		0xf(%rcx),%eax
++	movd		(%rsi,%rax,4),%xmm6
++	punpckldq	%xmm4,%xmm7
++	punpckldq	%xmm6,%xmm5
++	punpcklqdq	%xmm5,%xmm7
++	paddd		%xmm7,%xmm0
++	paddd		%xmm1,%xmm0
++	pxor		%xmm0,%xmm3
++	pshufb		%xmm13,%xmm3
++	paddd		%xmm3,%xmm2
++	pxor		%xmm2,%xmm1
++	movdqa		%xmm1,%xmm8
++	psrld		$0x7,%xmm1
++	pslld		$0x19,%xmm8
++	por		%xmm8,%xmm1
++	pshufd		$0x39,%xmm0,%xmm0
++	pshufd		$0x4e,%xmm3,%xmm3
++	pshufd		$0x93,%xmm2,%xmm2
++	addq		$0x10,%rcx
++	cmpq		%r8,%rcx
++	jnz		.Lroundloop
++	pxor		%xmm2,%xmm0
++	pxor		%xmm3,%xmm1
++	pxor		%xmm10,%xmm0
++	pxor		%xmm11,%xmm1
++	addq		$0x40,%rsi
++	decq		%rdx
++	jnz		.Lbeginofloop
++	movdqu		%xmm0,(%rdi)
++	movdqu		%xmm1,0x10(%rdi)
++	movdqu		%xmm14,0x20(%rdi)
++.Lendofloop:
++	ret
++ENDPROC(blake2s_compress_ssse3)
++#endif /* CONFIG_AS_SSSE3 */
++
++#ifdef CONFIG_AS_AVX512
++ENTRY(blake2s_compress_avx512)
++	vmovdqu		(%rdi),%xmm0
++	vmovdqu		0x10(%rdi),%xmm1
++	vmovdqu		0x20(%rdi),%xmm4
++	vmovq		%rcx,%xmm5
++	vmovdqa		IV(%rip),%xmm14
++	vmovdqa		IV+16(%rip),%xmm15
++	jmp		.Lblake2s_compress_avx512_mainloop
++.align 32
++.Lblake2s_compress_avx512_mainloop:
++	vmovdqa		%xmm0,%xmm10
++	vmovdqa		%xmm1,%xmm11
++	vpaddq		%xmm5,%xmm4,%xmm4
++	vmovdqa		%xmm14,%xmm2
++	vpxor		%xmm15,%xmm4,%xmm3
++	vmovdqu		(%rsi),%ymm6
++	vmovdqu		0x20(%rsi),%ymm7
++	addq		$0x40,%rsi
++	leaq		SIGMA2(%rip),%rax
++	movb		$0xa,%cl
++.Lblake2s_compress_avx512_roundloop:
++	addq		$0x40,%rax
++	vmovdqa		-0x40(%rax),%ymm8
++	vmovdqa		-0x20(%rax),%ymm9
++	vpermi2d	%ymm7,%ymm6,%ymm8
++	vpermi2d	%ymm7,%ymm6,%ymm9
++	vmovdqa		%ymm8,%ymm6
++	vmovdqa		%ymm9,%ymm7
++	vpaddd		%xmm8,%xmm0,%xmm0
++	vpaddd		%xmm1,%xmm0,%xmm0
++	vpxor		%xmm0,%xmm3,%xmm3
++	vprord		$0x10,%xmm3,%xmm3
++	vpaddd		%xmm3,%xmm2,%xmm2
++	vpxor		%xmm2,%xmm1,%xmm1
++	vprord		$0xc,%xmm1,%xmm1
++	vextracti128	$0x1,%ymm8,%xmm8
++	vpaddd		%xmm8,%xmm0,%xmm0
++	vpaddd		%xmm1,%xmm0,%xmm0
++	vpxor		%xmm0,%xmm3,%xmm3
++	vprord		$0x8,%xmm3,%xmm3
++	vpaddd		%xmm3,%xmm2,%xmm2
++	vpxor		%xmm2,%xmm1,%xmm1
++	vprord		$0x7,%xmm1,%xmm1
++	vpshufd		$0x93,%xmm0,%xmm0
++	vpshufd		$0x4e,%xmm3,%xmm3
++	vpshufd		$0x39,%xmm2,%xmm2
++	vpaddd		%xmm9,%xmm0,%xmm0
++	vpaddd		%xmm1,%xmm0,%xmm0
++	vpxor		%xmm0,%xmm3,%xmm3
++	vprord		$0x10,%xmm3,%xmm3
++	vpaddd		%xmm3,%xmm2,%xmm2
++	vpxor		%xmm2,%xmm1,%xmm1
++	vprord		$0xc,%xmm1,%xmm1
++	vextracti128	$0x1,%ymm9,%xmm9
++	vpaddd		%xmm9,%xmm0,%xmm0
++	vpaddd		%xmm1,%xmm0,%xmm0
++	vpxor		%xmm0,%xmm3,%xmm3
++	vprord		$0x8,%xmm3,%xmm3
++	vpaddd		%xmm3,%xmm2,%xmm2
++	vpxor		%xmm2,%xmm1,%xmm1
++	vprord		$0x7,%xmm1,%xmm1
++	vpshufd		$0x39,%xmm0,%xmm0
++	vpshufd		$0x4e,%xmm3,%xmm3
++	vpshufd		$0x93,%xmm2,%xmm2
++	decb		%cl
++	jne		.Lblake2s_compress_avx512_roundloop
++	vpxor		%xmm10,%xmm0,%xmm0
++	vpxor		%xmm11,%xmm1,%xmm1
++	vpxor		%xmm2,%xmm0,%xmm0
++	vpxor		%xmm3,%xmm1,%xmm1
++	decq		%rdx
++	jne		.Lblake2s_compress_avx512_mainloop
++	vmovdqu		%xmm0,(%rdi)
++	vmovdqu		%xmm1,0x10(%rdi)
++	vmovdqu		%xmm4,0x20(%rdi)
++	vzeroupper
++	retq
++ENDPROC(blake2s_compress_avx512)
++#endif /* CONFIG_AS_AVX512 */
+--- /dev/null
++++ b/arch/x86/crypto/blake2s-glue.c
+@@ -0,0 +1,233 @@
++// SPDX-License-Identifier: GPL-2.0 OR MIT
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#include <crypto/internal/blake2s.h>
++#include <crypto/internal/simd.h>
++#include <crypto/internal/hash.h>
++
++#include <linux/types.h>
++#include <linux/jump_label.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++
++#include <asm/cpufeature.h>
++#include <asm/fpu/api.h>
++#include <asm/processor.h>
++#include <asm/simd.h>
++
++asmlinkage void blake2s_compress_ssse3(struct blake2s_state *state,
++				       const u8 *block, const size_t nblocks,
++				       const u32 inc);
++asmlinkage void blake2s_compress_avx512(struct blake2s_state *state,
++					const u8 *block, const size_t nblocks,
++					const u32 inc);
++
++static __ro_after_init DEFINE_STATIC_KEY_FALSE(blake2s_use_ssse3);
++static __ro_after_init DEFINE_STATIC_KEY_FALSE(blake2s_use_avx512);
++
++void blake2s_compress_arch(struct blake2s_state *state,
++			   const u8 *block, size_t nblocks,
++			   const u32 inc)
++{
++	/* SIMD disables preemption, so relax after processing each page. */
++	BUILD_BUG_ON(PAGE_SIZE / BLAKE2S_BLOCK_SIZE < 8);
++
++	if (!static_branch_likely(&blake2s_use_ssse3) || !crypto_simd_usable()) {
++		blake2s_compress_generic(state, block, nblocks, inc);
++		return;
++	}
++
++	for (;;) {
++		const size_t blocks = min_t(size_t, nblocks,
++					    PAGE_SIZE / BLAKE2S_BLOCK_SIZE);
++
++		kernel_fpu_begin();
++		if (IS_ENABLED(CONFIG_AS_AVX512) &&
++		    static_branch_likely(&blake2s_use_avx512))
++			blake2s_compress_avx512(state, block, blocks, inc);
++		else
++			blake2s_compress_ssse3(state, block, blocks, inc);
++		kernel_fpu_end();
++
++		nblocks -= blocks;
++		if (!nblocks)
++			break;
++		block += blocks * BLAKE2S_BLOCK_SIZE;
++	}
++}
++EXPORT_SYMBOL(blake2s_compress_arch);
++
++static int crypto_blake2s_setkey(struct crypto_shash *tfm, const u8 *key,
++				 unsigned int keylen)
++{
++	struct blake2s_tfm_ctx *tctx = crypto_shash_ctx(tfm);
++
++	if (keylen == 0 || keylen > BLAKE2S_KEY_SIZE) {
++		crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
++		return -EINVAL;
++	}
++
++	memcpy(tctx->key, key, keylen);
++	tctx->keylen = keylen;
++
++	return 0;
++}
++
++static int crypto_blake2s_init(struct shash_desc *desc)
++{
++	struct blake2s_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm);
++	struct blake2s_state *state = shash_desc_ctx(desc);
++	const int outlen = crypto_shash_digestsize(desc->tfm);
++
++	if (tctx->keylen)
++		blake2s_init_key(state, outlen, tctx->key, tctx->keylen);
++	else
++		blake2s_init(state, outlen);
++
++	return 0;
++}
++
++static int crypto_blake2s_update(struct shash_desc *desc, const u8 *in,
++				 unsigned int inlen)
++{
++	struct blake2s_state *state = shash_desc_ctx(desc);
++	const size_t fill = BLAKE2S_BLOCK_SIZE - state->buflen;
++
++	if (unlikely(!inlen))
++		return 0;
++	if (inlen > fill) {
++		memcpy(state->buf + state->buflen, in, fill);
++		blake2s_compress_arch(state, state->buf, 1, BLAKE2S_BLOCK_SIZE);
++		state->buflen = 0;
++		in += fill;
++		inlen -= fill;
++	}
++	if (inlen > BLAKE2S_BLOCK_SIZE) {
++		const size_t nblocks = DIV_ROUND_UP(inlen, BLAKE2S_BLOCK_SIZE);
++		/* Hash one less (full) block than strictly possible */
++		blake2s_compress_arch(state, in, nblocks - 1, BLAKE2S_BLOCK_SIZE);
++		in += BLAKE2S_BLOCK_SIZE * (nblocks - 1);
++		inlen -= BLAKE2S_BLOCK_SIZE * (nblocks - 1);
++	}
++	memcpy(state->buf + state->buflen, in, inlen);
++	state->buflen += inlen;
++
++	return 0;
++}
++
++static int crypto_blake2s_final(struct shash_desc *desc, u8 *out)
++{
++	struct blake2s_state *state = shash_desc_ctx(desc);
++
++	blake2s_set_lastblock(state);
++	memset(state->buf + state->buflen, 0,
++	       BLAKE2S_BLOCK_SIZE - state->buflen); /* Padding */
++	blake2s_compress_arch(state, state->buf, 1, state->buflen);
++	cpu_to_le32_array(state->h, ARRAY_SIZE(state->h));
++	memcpy(out, state->h, state->outlen);
++	memzero_explicit(state, sizeof(*state));
++
++	return 0;
++}
++
++static struct shash_alg blake2s_algs[] = {{
++	.base.cra_name		= "blake2s-128",
++	.base.cra_driver_name	= "blake2s-128-x86",
++	.base.cra_flags		= CRYPTO_ALG_OPTIONAL_KEY,
++	.base.cra_ctxsize	= sizeof(struct blake2s_tfm_ctx),
++	.base.cra_priority	= 200,
++	.base.cra_blocksize     = BLAKE2S_BLOCK_SIZE,
++	.base.cra_module	= THIS_MODULE,
++
++	.digestsize		= BLAKE2S_128_HASH_SIZE,
++	.setkey			= crypto_blake2s_setkey,
++	.init			= crypto_blake2s_init,
++	.update			= crypto_blake2s_update,
++	.final			= crypto_blake2s_final,
++	.descsize		= sizeof(struct blake2s_state),
++}, {
++	.base.cra_name		= "blake2s-160",
++	.base.cra_driver_name	= "blake2s-160-x86",
++	.base.cra_flags		= CRYPTO_ALG_OPTIONAL_KEY,
++	.base.cra_ctxsize	= sizeof(struct blake2s_tfm_ctx),
++	.base.cra_priority	= 200,
++	.base.cra_blocksize     = BLAKE2S_BLOCK_SIZE,
++	.base.cra_module	= THIS_MODULE,
++
++	.digestsize		= BLAKE2S_160_HASH_SIZE,
++	.setkey			= crypto_blake2s_setkey,
++	.init			= crypto_blake2s_init,
++	.update			= crypto_blake2s_update,
++	.final			= crypto_blake2s_final,
++	.descsize		= sizeof(struct blake2s_state),
++}, {
++	.base.cra_name		= "blake2s-224",
++	.base.cra_driver_name	= "blake2s-224-x86",
++	.base.cra_flags		= CRYPTO_ALG_OPTIONAL_KEY,
++	.base.cra_ctxsize	= sizeof(struct blake2s_tfm_ctx),
++	.base.cra_priority	= 200,
++	.base.cra_blocksize     = BLAKE2S_BLOCK_SIZE,
++	.base.cra_module	= THIS_MODULE,
++
++	.digestsize		= BLAKE2S_224_HASH_SIZE,
++	.setkey			= crypto_blake2s_setkey,
++	.init			= crypto_blake2s_init,
++	.update			= crypto_blake2s_update,
++	.final			= crypto_blake2s_final,
++	.descsize		= sizeof(struct blake2s_state),
++}, {
++	.base.cra_name		= "blake2s-256",
++	.base.cra_driver_name	= "blake2s-256-x86",
++	.base.cra_flags		= CRYPTO_ALG_OPTIONAL_KEY,
++	.base.cra_ctxsize	= sizeof(struct blake2s_tfm_ctx),
++	.base.cra_priority	= 200,
++	.base.cra_blocksize     = BLAKE2S_BLOCK_SIZE,
++	.base.cra_module	= THIS_MODULE,
++
++	.digestsize		= BLAKE2S_256_HASH_SIZE,
++	.setkey			= crypto_blake2s_setkey,
++	.init			= crypto_blake2s_init,
++	.update			= crypto_blake2s_update,
++	.final			= crypto_blake2s_final,
++	.descsize		= sizeof(struct blake2s_state),
++}};
++
++static int __init blake2s_mod_init(void)
++{
++	if (!boot_cpu_has(X86_FEATURE_SSSE3))
++		return 0;
++
++	static_branch_enable(&blake2s_use_ssse3);
++
++	if (IS_ENABLED(CONFIG_AS_AVX512) &&
++	    boot_cpu_has(X86_FEATURE_AVX) &&
++	    boot_cpu_has(X86_FEATURE_AVX2) &&
++	    boot_cpu_has(X86_FEATURE_AVX512F) &&
++	    boot_cpu_has(X86_FEATURE_AVX512VL) &&
++	    cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM |
++			      XFEATURE_MASK_AVX512, NULL))
++		static_branch_enable(&blake2s_use_avx512);
++
++	return crypto_register_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs));
++}
++
++static void __exit blake2s_mod_exit(void)
++{
++	if (boot_cpu_has(X86_FEATURE_SSSE3))
++		crypto_unregister_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs));
++}
++
++module_init(blake2s_mod_init);
++module_exit(blake2s_mod_exit);
++
++MODULE_ALIAS_CRYPTO("blake2s-128");
++MODULE_ALIAS_CRYPTO("blake2s-128-x86");
++MODULE_ALIAS_CRYPTO("blake2s-160");
++MODULE_ALIAS_CRYPTO("blake2s-160-x86");
++MODULE_ALIAS_CRYPTO("blake2s-224");
++MODULE_ALIAS_CRYPTO("blake2s-224-x86");
++MODULE_ALIAS_CRYPTO("blake2s-256");
++MODULE_ALIAS_CRYPTO("blake2s-256-x86");
++MODULE_LICENSE("GPL v2");
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -657,6 +657,12 @@ config CRYPTO_BLAKE2S
+ 
+ 	  See https://blake2.net for further information.
+ 
++config CRYPTO_BLAKE2S_X86
++	tristate "BLAKE2s digest algorithm (x86 accelerated version)"
++	depends on X86 && 64BIT
++	select CRYPTO_LIB_BLAKE2S_GENERIC
++	select CRYPTO_ARCH_HAVE_LIB_BLAKE2S
++
+ config CRYPTO_CRCT10DIF
+ 	tristate "CRCT10DIF algorithm"
+ 	select CRYPTO_HASH
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0025-crypto-curve25519-generic-C-library-implementations.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0025-crypto-curve25519-generic-C-library-implementations.patch
new file mode 100644
index 0000000..e58dda9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0025-crypto-curve25519-generic-C-library-implementations.patch
@@ -0,0 +1,1849 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 8 Nov 2019 13:22:32 +0100
+Subject: [PATCH] crypto: curve25519 - generic C library implementations
+
+commit 0ed42a6f431e930b2e8fae21955406e09fe75d70 upstream.
+
+This contains two formally verified C implementations of the Curve25519
+scalar multiplication function, one for 32-bit systems, and one for
+64-bit systems whose compiler supports efficient 128-bit integer types.
+Not only are these implementations formally verified, but they are also
+the fastest available C implementations. They have been modified to be
+friendly to kernel space and to be generally less horrendous looking,
+but still an effort has been made to retain their formally verified
+characteristic, and so the C might look slightly unidiomatic.
+
+The 64-bit version comes from HACL*: https://github.com/project-everest/hacl-star
+The 32-bit version comes from Fiat: https://github.com/mit-plv/fiat-crypto
+
+Information: https://cr.yp.to/ecdh.html
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+[ardb: - move from lib/zinc to lib/crypto
+       - replace .c #includes with Kconfig based object selection
+       - drop simd handling and simplify support for per-arch versions ]
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ include/crypto/curve25519.h    |  71 +++
+ lib/crypto/Kconfig             |  25 +
+ lib/crypto/Makefile            |   5 +
+ lib/crypto/curve25519-fiat32.c | 864 +++++++++++++++++++++++++++++++++
+ lib/crypto/curve25519-hacl64.c | 788 ++++++++++++++++++++++++++++++
+ lib/crypto/curve25519.c        |  25 +
+ 6 files changed, 1778 insertions(+)
+ create mode 100644 include/crypto/curve25519.h
+ create mode 100644 lib/crypto/curve25519-fiat32.c
+ create mode 100644 lib/crypto/curve25519-hacl64.c
+ create mode 100644 lib/crypto/curve25519.c
+
+--- /dev/null
++++ b/include/crypto/curve25519.h
+@@ -0,0 +1,71 @@
++/* SPDX-License-Identifier: GPL-2.0 OR MIT */
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#ifndef CURVE25519_H
++#define CURVE25519_H
++
++#include <crypto/algapi.h> // For crypto_memneq.
++#include <linux/types.h>
++#include <linux/random.h>
++
++enum curve25519_lengths {
++	CURVE25519_KEY_SIZE = 32
++};
++
++extern const u8 curve25519_null_point[];
++extern const u8 curve25519_base_point[];
++
++void curve25519_generic(u8 out[CURVE25519_KEY_SIZE],
++			const u8 scalar[CURVE25519_KEY_SIZE],
++			const u8 point[CURVE25519_KEY_SIZE]);
++
++void curve25519_arch(u8 out[CURVE25519_KEY_SIZE],
++		     const u8 scalar[CURVE25519_KEY_SIZE],
++		     const u8 point[CURVE25519_KEY_SIZE]);
++
++void curve25519_base_arch(u8 pub[CURVE25519_KEY_SIZE],
++			  const u8 secret[CURVE25519_KEY_SIZE]);
++
++static inline
++bool __must_check curve25519(u8 mypublic[CURVE25519_KEY_SIZE],
++			     const u8 secret[CURVE25519_KEY_SIZE],
++			     const u8 basepoint[CURVE25519_KEY_SIZE])
++{
++	if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519))
++		curve25519_arch(mypublic, secret, basepoint);
++	else
++		curve25519_generic(mypublic, secret, basepoint);
++	return crypto_memneq(mypublic, curve25519_null_point,
++			     CURVE25519_KEY_SIZE);
++}
++
++static inline bool
++__must_check curve25519_generate_public(u8 pub[CURVE25519_KEY_SIZE],
++					const u8 secret[CURVE25519_KEY_SIZE])
++{
++	if (unlikely(!crypto_memneq(secret, curve25519_null_point,
++				    CURVE25519_KEY_SIZE)))
++		return false;
++
++	if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519))
++		curve25519_base_arch(pub, secret);
++	else
++		curve25519_generic(pub, secret, curve25519_base_point);
++	return crypto_memneq(pub, curve25519_null_point, CURVE25519_KEY_SIZE);
++}
++
++static inline void curve25519_clamp_secret(u8 secret[CURVE25519_KEY_SIZE])
++{
++	secret[0] &= 248;
++	secret[31] = (secret[31] & 127) | 64;
++}
++
++static inline void curve25519_generate_secret(u8 secret[CURVE25519_KEY_SIZE])
++{
++	get_random_bytes_wait(secret, CURVE25519_KEY_SIZE);
++	curve25519_clamp_secret(secret);
++}
++
++#endif /* CURVE25519_H */
+--- a/lib/crypto/Kconfig
++++ b/lib/crypto/Kconfig
+@@ -59,6 +59,31 @@ config CRYPTO_LIB_CHACHA
+ 	  by either the generic implementation or an arch-specific one, if one
+ 	  is available and enabled.
+ 
++config CRYPTO_ARCH_HAVE_LIB_CURVE25519
++	tristate
++	help
++	  Declares whether the architecture provides an arch-specific
++	  accelerated implementation of the Curve25519 library interface,
++	  either builtin or as a module.
++
++config CRYPTO_LIB_CURVE25519_GENERIC
++	tristate
++	help
++	  This symbol can be depended upon by arch implementations of the
++	  Curve25519 library interface that require the generic code as a
++	  fallback, e.g., for SIMD implementations. If no arch specific
++	  implementation is enabled, this implementation serves the users
++	  of CRYPTO_LIB_CURVE25519.
++
++config CRYPTO_LIB_CURVE25519
++	tristate "Curve25519 scalar multiplication library"
++	depends on CRYPTO_ARCH_HAVE_LIB_CURVE25519 || !CRYPTO_ARCH_HAVE_LIB_CURVE25519
++	select CRYPTO_LIB_CURVE25519_GENERIC if CRYPTO_ARCH_HAVE_LIB_CURVE25519=n
++	help
++	  Enable the Curve25519 library interface. This interface may be
++	  fulfilled by either the generic implementation or an arch-specific
++	  one, if one is available and enabled.
++
+ config CRYPTO_LIB_DES
+ 	tristate
+ 
+--- a/lib/crypto/Makefile
++++ b/lib/crypto/Makefile
+@@ -16,6 +16,11 @@ libblake2s-generic-y				+= blake2s-gener
+ obj-$(CONFIG_CRYPTO_LIB_BLAKE2S)		+= libblake2s.o
+ libblake2s-y					+= blake2s.o
+ 
++obj-$(CONFIG_CRYPTO_LIB_CURVE25519_GENERIC)	+= libcurve25519.o
++libcurve25519-y					:= curve25519-fiat32.o
++libcurve25519-$(CONFIG_ARCH_SUPPORTS_INT128)	:= curve25519-hacl64.o
++libcurve25519-y					+= curve25519.o
++
+ obj-$(CONFIG_CRYPTO_LIB_DES)			+= libdes.o
+ libdes-y					:= des.o
+ 
+--- /dev/null
++++ b/lib/crypto/curve25519-fiat32.c
+@@ -0,0 +1,864 @@
++// SPDX-License-Identifier: GPL-2.0 OR MIT
++/*
++ * Copyright (C) 2015-2016 The fiat-crypto Authors.
++ * Copyright (C) 2018-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ *
++ * This is a machine-generated formally verified implementation of Curve25519
++ * ECDH from: <https://github.com/mit-plv/fiat-crypto>. Though originally
++ * machine generated, it has been tweaked to be suitable for use in the kernel.
++ * It is optimized for 32-bit machines and machines that cannot work efficiently
++ * with 128-bit integer types.
++ */
++
++#include <asm/unaligned.h>
++#include <crypto/curve25519.h>
++#include <linux/string.h>
++
++/* fe means field element. Here the field is \Z/(2^255-19). An element t,
++ * entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
++ * t[3]+2^102 t[4]+...+2^230 t[9].
++ * fe limbs are bounded by 1.125*2^26,1.125*2^25,1.125*2^26,1.125*2^25,etc.
++ * Multiplication and carrying produce fe from fe_loose.
++ */
++typedef struct fe { u32 v[10]; } fe;
++
++/* fe_loose limbs are bounded by 3.375*2^26,3.375*2^25,3.375*2^26,3.375*2^25,etc
++ * Addition and subtraction produce fe_loose from (fe, fe).
++ */
++typedef struct fe_loose { u32 v[10]; } fe_loose;
++
++static __always_inline void fe_frombytes_impl(u32 h[10], const u8 *s)
++{
++	/* Ignores top bit of s. */
++	u32 a0 = get_unaligned_le32(s);
++	u32 a1 = get_unaligned_le32(s+4);
++	u32 a2 = get_unaligned_le32(s+8);
++	u32 a3 = get_unaligned_le32(s+12);
++	u32 a4 = get_unaligned_le32(s+16);
++	u32 a5 = get_unaligned_le32(s+20);
++	u32 a6 = get_unaligned_le32(s+24);
++	u32 a7 = get_unaligned_le32(s+28);
++	h[0] = a0&((1<<26)-1);                    /* 26 used, 32-26 left.   26 */
++	h[1] = (a0>>26) | ((a1&((1<<19)-1))<< 6); /* (32-26) + 19 =  6+19 = 25 */
++	h[2] = (a1>>19) | ((a2&((1<<13)-1))<<13); /* (32-19) + 13 = 13+13 = 26 */
++	h[3] = (a2>>13) | ((a3&((1<< 6)-1))<<19); /* (32-13) +  6 = 19+ 6 = 25 */
++	h[4] = (a3>> 6);                          /* (32- 6)              = 26 */
++	h[5] = a4&((1<<25)-1);                    /*                        25 */
++	h[6] = (a4>>25) | ((a5&((1<<19)-1))<< 7); /* (32-25) + 19 =  7+19 = 26 */
++	h[7] = (a5>>19) | ((a6&((1<<12)-1))<<13); /* (32-19) + 12 = 13+12 = 25 */
++	h[8] = (a6>>12) | ((a7&((1<< 6)-1))<<20); /* (32-12) +  6 = 20+ 6 = 26 */
++	h[9] = (a7>> 6)&((1<<25)-1); /*                                     25 */
++}
++
++static __always_inline void fe_frombytes(fe *h, const u8 *s)
++{
++	fe_frombytes_impl(h->v, s);
++}
++
++static __always_inline u8 /*bool*/
++addcarryx_u25(u8 /*bool*/ c, u32 a, u32 b, u32 *low)
++{
++	/* This function extracts 25 bits of result and 1 bit of carry
++	 * (26 total), so a 32-bit intermediate is sufficient.
++	 */
++	u32 x = a + b + c;
++	*low = x & ((1 << 25) - 1);
++	return (x >> 25) & 1;
++}
++
++static __always_inline u8 /*bool*/
++addcarryx_u26(u8 /*bool*/ c, u32 a, u32 b, u32 *low)
++{
++	/* This function extracts 26 bits of result and 1 bit of carry
++	 * (27 total), so a 32-bit intermediate is sufficient.
++	 */
++	u32 x = a + b + c;
++	*low = x & ((1 << 26) - 1);
++	return (x >> 26) & 1;
++}
++
++static __always_inline u8 /*bool*/
++subborrow_u25(u8 /*bool*/ c, u32 a, u32 b, u32 *low)
++{
++	/* This function extracts 25 bits of result and 1 bit of borrow
++	 * (26 total), so a 32-bit intermediate is sufficient.
++	 */
++	u32 x = a - b - c;
++	*low = x & ((1 << 25) - 1);
++	return x >> 31;
++}
++
++static __always_inline u8 /*bool*/
++subborrow_u26(u8 /*bool*/ c, u32 a, u32 b, u32 *low)
++{
++	/* This function extracts 26 bits of result and 1 bit of borrow
++	 *(27 total), so a 32-bit intermediate is sufficient.
++	 */
++	u32 x = a - b - c;
++	*low = x & ((1 << 26) - 1);
++	return x >> 31;
++}
++
++static __always_inline u32 cmovznz32(u32 t, u32 z, u32 nz)
++{
++	t = -!!t; /* all set if nonzero, 0 if 0 */
++	return (t&nz) | ((~t)&z);
++}
++
++static __always_inline void fe_freeze(u32 out[10], const u32 in1[10])
++{
++	{ const u32 x17 = in1[9];
++	{ const u32 x18 = in1[8];
++	{ const u32 x16 = in1[7];
++	{ const u32 x14 = in1[6];
++	{ const u32 x12 = in1[5];
++	{ const u32 x10 = in1[4];
++	{ const u32 x8 = in1[3];
++	{ const u32 x6 = in1[2];
++	{ const u32 x4 = in1[1];
++	{ const u32 x2 = in1[0];
++	{ u32 x20; u8/*bool*/ x21 = subborrow_u26(0x0, x2, 0x3ffffed, &x20);
++	{ u32 x23; u8/*bool*/ x24 = subborrow_u25(x21, x4, 0x1ffffff, &x23);
++	{ u32 x26; u8/*bool*/ x27 = subborrow_u26(x24, x6, 0x3ffffff, &x26);
++	{ u32 x29; u8/*bool*/ x30 = subborrow_u25(x27, x8, 0x1ffffff, &x29);
++	{ u32 x32; u8/*bool*/ x33 = subborrow_u26(x30, x10, 0x3ffffff, &x32);
++	{ u32 x35; u8/*bool*/ x36 = subborrow_u25(x33, x12, 0x1ffffff, &x35);
++	{ u32 x38; u8/*bool*/ x39 = subborrow_u26(x36, x14, 0x3ffffff, &x38);
++	{ u32 x41; u8/*bool*/ x42 = subborrow_u25(x39, x16, 0x1ffffff, &x41);
++	{ u32 x44; u8/*bool*/ x45 = subborrow_u26(x42, x18, 0x3ffffff, &x44);
++	{ u32 x47; u8/*bool*/ x48 = subborrow_u25(x45, x17, 0x1ffffff, &x47);
++	{ u32 x49 = cmovznz32(x48, 0x0, 0xffffffff);
++	{ u32 x50 = (x49 & 0x3ffffed);
++	{ u32 x52; u8/*bool*/ x53 = addcarryx_u26(0x0, x20, x50, &x52);
++	{ u32 x54 = (x49 & 0x1ffffff);
++	{ u32 x56; u8/*bool*/ x57 = addcarryx_u25(x53, x23, x54, &x56);
++	{ u32 x58 = (x49 & 0x3ffffff);
++	{ u32 x60; u8/*bool*/ x61 = addcarryx_u26(x57, x26, x58, &x60);
++	{ u32 x62 = (x49 & 0x1ffffff);
++	{ u32 x64; u8/*bool*/ x65 = addcarryx_u25(x61, x29, x62, &x64);
++	{ u32 x66 = (x49 & 0x3ffffff);
++	{ u32 x68; u8/*bool*/ x69 = addcarryx_u26(x65, x32, x66, &x68);
++	{ u32 x70 = (x49 & 0x1ffffff);
++	{ u32 x72; u8/*bool*/ x73 = addcarryx_u25(x69, x35, x70, &x72);
++	{ u32 x74 = (x49 & 0x3ffffff);
++	{ u32 x76; u8/*bool*/ x77 = addcarryx_u26(x73, x38, x74, &x76);
++	{ u32 x78 = (x49 & 0x1ffffff);
++	{ u32 x80; u8/*bool*/ x81 = addcarryx_u25(x77, x41, x78, &x80);
++	{ u32 x82 = (x49 & 0x3ffffff);
++	{ u32 x84; u8/*bool*/ x85 = addcarryx_u26(x81, x44, x82, &x84);
++	{ u32 x86 = (x49 & 0x1ffffff);
++	{ u32 x88; addcarryx_u25(x85, x47, x86, &x88);
++	out[0] = x52;
++	out[1] = x56;
++	out[2] = x60;
++	out[3] = x64;
++	out[4] = x68;
++	out[5] = x72;
++	out[6] = x76;
++	out[7] = x80;
++	out[8] = x84;
++	out[9] = x88;
++	}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
++}
++
++static __always_inline void fe_tobytes(u8 s[32], const fe *f)
++{
++	u32 h[10];
++	fe_freeze(h, f->v);
++	s[0] = h[0] >> 0;
++	s[1] = h[0] >> 8;
++	s[2] = h[0] >> 16;
++	s[3] = (h[0] >> 24) | (h[1] << 2);
++	s[4] = h[1] >> 6;
++	s[5] = h[1] >> 14;
++	s[6] = (h[1] >> 22) | (h[2] << 3);
++	s[7] = h[2] >> 5;
++	s[8] = h[2] >> 13;
++	s[9] = (h[2] >> 21) | (h[3] << 5);
++	s[10] = h[3] >> 3;
++	s[11] = h[3] >> 11;
++	s[12] = (h[3] >> 19) | (h[4] << 6);
++	s[13] = h[4] >> 2;
++	s[14] = h[4] >> 10;
++	s[15] = h[4] >> 18;
++	s[16] = h[5] >> 0;
++	s[17] = h[5] >> 8;
++	s[18] = h[5] >> 16;
++	s[19] = (h[5] >> 24) | (h[6] << 1);
++	s[20] = h[6] >> 7;
++	s[21] = h[6] >> 15;
++	s[22] = (h[6] >> 23) | (h[7] << 3);
++	s[23] = h[7] >> 5;
++	s[24] = h[7] >> 13;
++	s[25] = (h[7] >> 21) | (h[8] << 4);
++	s[26] = h[8] >> 4;
++	s[27] = h[8] >> 12;
++	s[28] = (h[8] >> 20) | (h[9] << 6);
++	s[29] = h[9] >> 2;
++	s[30] = h[9] >> 10;
++	s[31] = h[9] >> 18;
++}
++
++/* h = f */
++static __always_inline void fe_copy(fe *h, const fe *f)
++{
++	memmove(h, f, sizeof(u32) * 10);
++}
++
++static __always_inline void fe_copy_lt(fe_loose *h, const fe *f)
++{
++	memmove(h, f, sizeof(u32) * 10);
++}
++
++/* h = 0 */
++static __always_inline void fe_0(fe *h)
++{
++	memset(h, 0, sizeof(u32) * 10);
++}
++
++/* h = 1 */
++static __always_inline void fe_1(fe *h)
++{
++	memset(h, 0, sizeof(u32) * 10);
++	h->v[0] = 1;
++}
++
++static void fe_add_impl(u32 out[10], const u32 in1[10], const u32 in2[10])
++{
++	{ const u32 x20 = in1[9];
++	{ const u32 x21 = in1[8];
++	{ const u32 x19 = in1[7];
++	{ const u32 x17 = in1[6];
++	{ const u32 x15 = in1[5];
++	{ const u32 x13 = in1[4];
++	{ const u32 x11 = in1[3];
++	{ const u32 x9 = in1[2];
++	{ const u32 x7 = in1[1];
++	{ const u32 x5 = in1[0];
++	{ const u32 x38 = in2[9];
++	{ const u32 x39 = in2[8];
++	{ const u32 x37 = in2[7];
++	{ const u32 x35 = in2[6];
++	{ const u32 x33 = in2[5];
++	{ const u32 x31 = in2[4];
++	{ const u32 x29 = in2[3];
++	{ const u32 x27 = in2[2];
++	{ const u32 x25 = in2[1];
++	{ const u32 x23 = in2[0];
++	out[0] = (x5 + x23);
++	out[1] = (x7 + x25);
++	out[2] = (x9 + x27);
++	out[3] = (x11 + x29);
++	out[4] = (x13 + x31);
++	out[5] = (x15 + x33);
++	out[6] = (x17 + x35);
++	out[7] = (x19 + x37);
++	out[8] = (x21 + x39);
++	out[9] = (x20 + x38);
++	}}}}}}}}}}}}}}}}}}}}
++}
++
++/* h = f + g
++ * Can overlap h with f or g.
++ */
++static __always_inline void fe_add(fe_loose *h, const fe *f, const fe *g)
++{
++	fe_add_impl(h->v, f->v, g->v);
++}
++
++static void fe_sub_impl(u32 out[10], const u32 in1[10], const u32 in2[10])
++{
++	{ const u32 x20 = in1[9];
++	{ const u32 x21 = in1[8];
++	{ const u32 x19 = in1[7];
++	{ const u32 x17 = in1[6];
++	{ const u32 x15 = in1[5];
++	{ const u32 x13 = in1[4];
++	{ const u32 x11 = in1[3];
++	{ const u32 x9 = in1[2];
++	{ const u32 x7 = in1[1];
++	{ const u32 x5 = in1[0];
++	{ const u32 x38 = in2[9];
++	{ const u32 x39 = in2[8];
++	{ const u32 x37 = in2[7];
++	{ const u32 x35 = in2[6];
++	{ const u32 x33 = in2[5];
++	{ const u32 x31 = in2[4];
++	{ const u32 x29 = in2[3];
++	{ const u32 x27 = in2[2];
++	{ const u32 x25 = in2[1];
++	{ const u32 x23 = in2[0];
++	out[0] = ((0x7ffffda + x5) - x23);
++	out[1] = ((0x3fffffe + x7) - x25);
++	out[2] = ((0x7fffffe + x9) - x27);
++	out[3] = ((0x3fffffe + x11) - x29);
++	out[4] = ((0x7fffffe + x13) - x31);
++	out[5] = ((0x3fffffe + x15) - x33);
++	out[6] = ((0x7fffffe + x17) - x35);
++	out[7] = ((0x3fffffe + x19) - x37);
++	out[8] = ((0x7fffffe + x21) - x39);
++	out[9] = ((0x3fffffe + x20) - x38);
++	}}}}}}}}}}}}}}}}}}}}
++}
++
++/* h = f - g
++ * Can overlap h with f or g.
++ */
++static __always_inline void fe_sub(fe_loose *h, const fe *f, const fe *g)
++{
++	fe_sub_impl(h->v, f->v, g->v);
++}
++
++static void fe_mul_impl(u32 out[10], const u32 in1[10], const u32 in2[10])
++{
++	{ const u32 x20 = in1[9];
++	{ const u32 x21 = in1[8];
++	{ const u32 x19 = in1[7];
++	{ const u32 x17 = in1[6];
++	{ const u32 x15 = in1[5];
++	{ const u32 x13 = in1[4];
++	{ const u32 x11 = in1[3];
++	{ const u32 x9 = in1[2];
++	{ const u32 x7 = in1[1];
++	{ const u32 x5 = in1[0];
++	{ const u32 x38 = in2[9];
++	{ const u32 x39 = in2[8];
++	{ const u32 x37 = in2[7];
++	{ const u32 x35 = in2[6];
++	{ const u32 x33 = in2[5];
++	{ const u32 x31 = in2[4];
++	{ const u32 x29 = in2[3];
++	{ const u32 x27 = in2[2];
++	{ const u32 x25 = in2[1];
++	{ const u32 x23 = in2[0];
++	{ u64 x40 = ((u64)x23 * x5);
++	{ u64 x41 = (((u64)x23 * x7) + ((u64)x25 * x5));
++	{ u64 x42 = ((((u64)(0x2 * x25) * x7) + ((u64)x23 * x9)) + ((u64)x27 * x5));
++	{ u64 x43 = (((((u64)x25 * x9) + ((u64)x27 * x7)) + ((u64)x23 * x11)) + ((u64)x29 * x5));
++	{ u64 x44 = (((((u64)x27 * x9) + (0x2 * (((u64)x25 * x11) + ((u64)x29 * x7)))) + ((u64)x23 * x13)) + ((u64)x31 * x5));
++	{ u64 x45 = (((((((u64)x27 * x11) + ((u64)x29 * x9)) + ((u64)x25 * x13)) + ((u64)x31 * x7)) + ((u64)x23 * x15)) + ((u64)x33 * x5));
++	{ u64 x46 = (((((0x2 * ((((u64)x29 * x11) + ((u64)x25 * x15)) + ((u64)x33 * x7))) + ((u64)x27 * x13)) + ((u64)x31 * x9)) + ((u64)x23 * x17)) + ((u64)x35 * x5));
++	{ u64 x47 = (((((((((u64)x29 * x13) + ((u64)x31 * x11)) + ((u64)x27 * x15)) + ((u64)x33 * x9)) + ((u64)x25 * x17)) + ((u64)x35 * x7)) + ((u64)x23 * x19)) + ((u64)x37 * x5));
++	{ u64 x48 = (((((((u64)x31 * x13) + (0x2 * (((((u64)x29 * x15) + ((u64)x33 * x11)) + ((u64)x25 * x19)) + ((u64)x37 * x7)))) + ((u64)x27 * x17)) + ((u64)x35 * x9)) + ((u64)x23 * x21)) + ((u64)x39 * x5));
++	{ u64 x49 = (((((((((((u64)x31 * x15) + ((u64)x33 * x13)) + ((u64)x29 * x17)) + ((u64)x35 * x11)) + ((u64)x27 * x19)) + ((u64)x37 * x9)) + ((u64)x25 * x21)) + ((u64)x39 * x7)) + ((u64)x23 * x20)) + ((u64)x38 * x5));
++	{ u64 x50 = (((((0x2 * ((((((u64)x33 * x15) + ((u64)x29 * x19)) + ((u64)x37 * x11)) + ((u64)x25 * x20)) + ((u64)x38 * x7))) + ((u64)x31 * x17)) + ((u64)x35 * x13)) + ((u64)x27 * x21)) + ((u64)x39 * x9));
++	{ u64 x51 = (((((((((u64)x33 * x17) + ((u64)x35 * x15)) + ((u64)x31 * x19)) + ((u64)x37 * x13)) + ((u64)x29 * x21)) + ((u64)x39 * x11)) + ((u64)x27 * x20)) + ((u64)x38 * x9));
++	{ u64 x52 = (((((u64)x35 * x17) + (0x2 * (((((u64)x33 * x19) + ((u64)x37 * x15)) + ((u64)x29 * x20)) + ((u64)x38 * x11)))) + ((u64)x31 * x21)) + ((u64)x39 * x13));
++	{ u64 x53 = (((((((u64)x35 * x19) + ((u64)x37 * x17)) + ((u64)x33 * x21)) + ((u64)x39 * x15)) + ((u64)x31 * x20)) + ((u64)x38 * x13));
++	{ u64 x54 = (((0x2 * ((((u64)x37 * x19) + ((u64)x33 * x20)) + ((u64)x38 * x15))) + ((u64)x35 * x21)) + ((u64)x39 * x17));
++	{ u64 x55 = (((((u64)x37 * x21) + ((u64)x39 * x19)) + ((u64)x35 * x20)) + ((u64)x38 * x17));
++	{ u64 x56 = (((u64)x39 * x21) + (0x2 * (((u64)x37 * x20) + ((u64)x38 * x19))));
++	{ u64 x57 = (((u64)x39 * x20) + ((u64)x38 * x21));
++	{ u64 x58 = ((u64)(0x2 * x38) * x20);
++	{ u64 x59 = (x48 + (x58 << 0x4));
++	{ u64 x60 = (x59 + (x58 << 0x1));
++	{ u64 x61 = (x60 + x58);
++	{ u64 x62 = (x47 + (x57 << 0x4));
++	{ u64 x63 = (x62 + (x57 << 0x1));
++	{ u64 x64 = (x63 + x57);
++	{ u64 x65 = (x46 + (x56 << 0x4));
++	{ u64 x66 = (x65 + (x56 << 0x1));
++	{ u64 x67 = (x66 + x56);
++	{ u64 x68 = (x45 + (x55 << 0x4));
++	{ u64 x69 = (x68 + (x55 << 0x1));
++	{ u64 x70 = (x69 + x55);
++	{ u64 x71 = (x44 + (x54 << 0x4));
++	{ u64 x72 = (x71 + (x54 << 0x1));
++	{ u64 x73 = (x72 + x54);
++	{ u64 x74 = (x43 + (x53 << 0x4));
++	{ u64 x75 = (x74 + (x53 << 0x1));
++	{ u64 x76 = (x75 + x53);
++	{ u64 x77 = (x42 + (x52 << 0x4));
++	{ u64 x78 = (x77 + (x52 << 0x1));
++	{ u64 x79 = (x78 + x52);
++	{ u64 x80 = (x41 + (x51 << 0x4));
++	{ u64 x81 = (x80 + (x51 << 0x1));
++	{ u64 x82 = (x81 + x51);
++	{ u64 x83 = (x40 + (x50 << 0x4));
++	{ u64 x84 = (x83 + (x50 << 0x1));
++	{ u64 x85 = (x84 + x50);
++	{ u64 x86 = (x85 >> 0x1a);
++	{ u32 x87 = ((u32)x85 & 0x3ffffff);
++	{ u64 x88 = (x86 + x82);
++	{ u64 x89 = (x88 >> 0x19);
++	{ u32 x90 = ((u32)x88 & 0x1ffffff);
++	{ u64 x91 = (x89 + x79);
++	{ u64 x92 = (x91 >> 0x1a);
++	{ u32 x93 = ((u32)x91 & 0x3ffffff);
++	{ u64 x94 = (x92 + x76);
++	{ u64 x95 = (x94 >> 0x19);
++	{ u32 x96 = ((u32)x94 & 0x1ffffff);
++	{ u64 x97 = (x95 + x73);
++	{ u64 x98 = (x97 >> 0x1a);
++	{ u32 x99 = ((u32)x97 & 0x3ffffff);
++	{ u64 x100 = (x98 + x70);
++	{ u64 x101 = (x100 >> 0x19);
++	{ u32 x102 = ((u32)x100 & 0x1ffffff);
++	{ u64 x103 = (x101 + x67);
++	{ u64 x104 = (x103 >> 0x1a);
++	{ u32 x105 = ((u32)x103 & 0x3ffffff);
++	{ u64 x106 = (x104 + x64);
++	{ u64 x107 = (x106 >> 0x19);
++	{ u32 x108 = ((u32)x106 & 0x1ffffff);
++	{ u64 x109 = (x107 + x61);
++	{ u64 x110 = (x109 >> 0x1a);
++	{ u32 x111 = ((u32)x109 & 0x3ffffff);
++	{ u64 x112 = (x110 + x49);
++	{ u64 x113 = (x112 >> 0x19);
++	{ u32 x114 = ((u32)x112 & 0x1ffffff);
++	{ u64 x115 = (x87 + (0x13 * x113));
++	{ u32 x116 = (u32) (x115 >> 0x1a);
++	{ u32 x117 = ((u32)x115 & 0x3ffffff);
++	{ u32 x118 = (x116 + x90);
++	{ u32 x119 = (x118 >> 0x19);
++	{ u32 x120 = (x118 & 0x1ffffff);
++	out[0] = x117;
++	out[1] = x120;
++	out[2] = (x119 + x93);
++	out[3] = x96;
++	out[4] = x99;
++	out[5] = x102;
++	out[6] = x105;
++	out[7] = x108;
++	out[8] = x111;
++	out[9] = x114;
++	}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
++}
++
++static __always_inline void fe_mul_ttt(fe *h, const fe *f, const fe *g)
++{
++	fe_mul_impl(h->v, f->v, g->v);
++}
++
++static __always_inline void fe_mul_tlt(fe *h, const fe_loose *f, const fe *g)
++{
++	fe_mul_impl(h->v, f->v, g->v);
++}
++
++static __always_inline void
++fe_mul_tll(fe *h, const fe_loose *f, const fe_loose *g)
++{
++	fe_mul_impl(h->v, f->v, g->v);
++}
++
++static void fe_sqr_impl(u32 out[10], const u32 in1[10])
++{
++	{ const u32 x17 = in1[9];
++	{ const u32 x18 = in1[8];
++	{ const u32 x16 = in1[7];
++	{ const u32 x14 = in1[6];
++	{ const u32 x12 = in1[5];
++	{ const u32 x10 = in1[4];
++	{ const u32 x8 = in1[3];
++	{ const u32 x6 = in1[2];
++	{ const u32 x4 = in1[1];
++	{ const u32 x2 = in1[0];
++	{ u64 x19 = ((u64)x2 * x2);
++	{ u64 x20 = ((u64)(0x2 * x2) * x4);
++	{ u64 x21 = (0x2 * (((u64)x4 * x4) + ((u64)x2 * x6)));
++	{ u64 x22 = (0x2 * (((u64)x4 * x6) + ((u64)x2 * x8)));
++	{ u64 x23 = ((((u64)x6 * x6) + ((u64)(0x4 * x4) * x8)) + ((u64)(0x2 * x2) * x10));
++	{ u64 x24 = (0x2 * ((((u64)x6 * x8) + ((u64)x4 * x10)) + ((u64)x2 * x12)));
++	{ u64 x25 = (0x2 * (((((u64)x8 * x8) + ((u64)x6 * x10)) + ((u64)x2 * x14)) + ((u64)(0x2 * x4) * x12)));
++	{ u64 x26 = (0x2 * (((((u64)x8 * x10) + ((u64)x6 * x12)) + ((u64)x4 * x14)) + ((u64)x2 * x16)));
++	{ u64 x27 = (((u64)x10 * x10) + (0x2 * ((((u64)x6 * x14) + ((u64)x2 * x18)) + (0x2 * (((u64)x4 * x16) + ((u64)x8 * x12))))));
++	{ u64 x28 = (0x2 * ((((((u64)x10 * x12) + ((u64)x8 * x14)) + ((u64)x6 * x16)) + ((u64)x4 * x18)) + ((u64)x2 * x17)));
++	{ u64 x29 = (0x2 * (((((u64)x12 * x12) + ((u64)x10 * x14)) + ((u64)x6 * x18)) + (0x2 * (((u64)x8 * x16) + ((u64)x4 * x17)))));
++	{ u64 x30 = (0x2 * (((((u64)x12 * x14) + ((u64)x10 * x16)) + ((u64)x8 * x18)) + ((u64)x6 * x17)));
++	{ u64 x31 = (((u64)x14 * x14) + (0x2 * (((u64)x10 * x18) + (0x2 * (((u64)x12 * x16) + ((u64)x8 * x17))))));
++	{ u64 x32 = (0x2 * ((((u64)x14 * x16) + ((u64)x12 * x18)) + ((u64)x10 * x17)));
++	{ u64 x33 = (0x2 * ((((u64)x16 * x16) + ((u64)x14 * x18)) + ((u64)(0x2 * x12) * x17)));
++	{ u64 x34 = (0x2 * (((u64)x16 * x18) + ((u64)x14 * x17)));
++	{ u64 x35 = (((u64)x18 * x18) + ((u64)(0x4 * x16) * x17));
++	{ u64 x36 = ((u64)(0x2 * x18) * x17);
++	{ u64 x37 = ((u64)(0x2 * x17) * x17);
++	{ u64 x38 = (x27 + (x37 << 0x4));
++	{ u64 x39 = (x38 + (x37 << 0x1));
++	{ u64 x40 = (x39 + x37);
++	{ u64 x41 = (x26 + (x36 << 0x4));
++	{ u64 x42 = (x41 + (x36 << 0x1));
++	{ u64 x43 = (x42 + x36);
++	{ u64 x44 = (x25 + (x35 << 0x4));
++	{ u64 x45 = (x44 + (x35 << 0x1));
++	{ u64 x46 = (x45 + x35);
++	{ u64 x47 = (x24 + (x34 << 0x4));
++	{ u64 x48 = (x47 + (x34 << 0x1));
++	{ u64 x49 = (x48 + x34);
++	{ u64 x50 = (x23 + (x33 << 0x4));
++	{ u64 x51 = (x50 + (x33 << 0x1));
++	{ u64 x52 = (x51 + x33);
++	{ u64 x53 = (x22 + (x32 << 0x4));
++	{ u64 x54 = (x53 + (x32 << 0x1));
++	{ u64 x55 = (x54 + x32);
++	{ u64 x56 = (x21 + (x31 << 0x4));
++	{ u64 x57 = (x56 + (x31 << 0x1));
++	{ u64 x58 = (x57 + x31);
++	{ u64 x59 = (x20 + (x30 << 0x4));
++	{ u64 x60 = (x59 + (x30 << 0x1));
++	{ u64 x61 = (x60 + x30);
++	{ u64 x62 = (x19 + (x29 << 0x4));
++	{ u64 x63 = (x62 + (x29 << 0x1));
++	{ u64 x64 = (x63 + x29);
++	{ u64 x65 = (x64 >> 0x1a);
++	{ u32 x66 = ((u32)x64 & 0x3ffffff);
++	{ u64 x67 = (x65 + x61);
++	{ u64 x68 = (x67 >> 0x19);
++	{ u32 x69 = ((u32)x67 & 0x1ffffff);
++	{ u64 x70 = (x68 + x58);
++	{ u64 x71 = (x70 >> 0x1a);
++	{ u32 x72 = ((u32)x70 & 0x3ffffff);
++	{ u64 x73 = (x71 + x55);
++	{ u64 x74 = (x73 >> 0x19);
++	{ u32 x75 = ((u32)x73 & 0x1ffffff);
++	{ u64 x76 = (x74 + x52);
++	{ u64 x77 = (x76 >> 0x1a);
++	{ u32 x78 = ((u32)x76 & 0x3ffffff);
++	{ u64 x79 = (x77 + x49);
++	{ u64 x80 = (x79 >> 0x19);
++	{ u32 x81 = ((u32)x79 & 0x1ffffff);
++	{ u64 x82 = (x80 + x46);
++	{ u64 x83 = (x82 >> 0x1a);
++	{ u32 x84 = ((u32)x82 & 0x3ffffff);
++	{ u64 x85 = (x83 + x43);
++	{ u64 x86 = (x85 >> 0x19);
++	{ u32 x87 = ((u32)x85 & 0x1ffffff);
++	{ u64 x88 = (x86 + x40);
++	{ u64 x89 = (x88 >> 0x1a);
++	{ u32 x90 = ((u32)x88 & 0x3ffffff);
++	{ u64 x91 = (x89 + x28);
++	{ u64 x92 = (x91 >> 0x19);
++	{ u32 x93 = ((u32)x91 & 0x1ffffff);
++	{ u64 x94 = (x66 + (0x13 * x92));
++	{ u32 x95 = (u32) (x94 >> 0x1a);
++	{ u32 x96 = ((u32)x94 & 0x3ffffff);
++	{ u32 x97 = (x95 + x69);
++	{ u32 x98 = (x97 >> 0x19);
++	{ u32 x99 = (x97 & 0x1ffffff);
++	out[0] = x96;
++	out[1] = x99;
++	out[2] = (x98 + x72);
++	out[3] = x75;
++	out[4] = x78;
++	out[5] = x81;
++	out[6] = x84;
++	out[7] = x87;
++	out[8] = x90;
++	out[9] = x93;
++	}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
++}
++
++static __always_inline void fe_sq_tl(fe *h, const fe_loose *f)
++{
++	fe_sqr_impl(h->v, f->v);
++}
++
++static __always_inline void fe_sq_tt(fe *h, const fe *f)
++{
++	fe_sqr_impl(h->v, f->v);
++}
++
++static __always_inline void fe_loose_invert(fe *out, const fe_loose *z)
++{
++	fe t0;
++	fe t1;
++	fe t2;
++	fe t3;
++	int i;
++
++	fe_sq_tl(&t0, z);
++	fe_sq_tt(&t1, &t0);
++	for (i = 1; i < 2; ++i)
++		fe_sq_tt(&t1, &t1);
++	fe_mul_tlt(&t1, z, &t1);
++	fe_mul_ttt(&t0, &t0, &t1);
++	fe_sq_tt(&t2, &t0);
++	fe_mul_ttt(&t1, &t1, &t2);
++	fe_sq_tt(&t2, &t1);
++	for (i = 1; i < 5; ++i)
++		fe_sq_tt(&t2, &t2);
++	fe_mul_ttt(&t1, &t2, &t1);
++	fe_sq_tt(&t2, &t1);
++	for (i = 1; i < 10; ++i)
++		fe_sq_tt(&t2, &t2);
++	fe_mul_ttt(&t2, &t2, &t1);
++	fe_sq_tt(&t3, &t2);
++	for (i = 1; i < 20; ++i)
++		fe_sq_tt(&t3, &t3);
++	fe_mul_ttt(&t2, &t3, &t2);
++	fe_sq_tt(&t2, &t2);
++	for (i = 1; i < 10; ++i)
++		fe_sq_tt(&t2, &t2);
++	fe_mul_ttt(&t1, &t2, &t1);
++	fe_sq_tt(&t2, &t1);
++	for (i = 1; i < 50; ++i)
++		fe_sq_tt(&t2, &t2);
++	fe_mul_ttt(&t2, &t2, &t1);
++	fe_sq_tt(&t3, &t2);
++	for (i = 1; i < 100; ++i)
++		fe_sq_tt(&t3, &t3);
++	fe_mul_ttt(&t2, &t3, &t2);
++	fe_sq_tt(&t2, &t2);
++	for (i = 1; i < 50; ++i)
++		fe_sq_tt(&t2, &t2);
++	fe_mul_ttt(&t1, &t2, &t1);
++	fe_sq_tt(&t1, &t1);
++	for (i = 1; i < 5; ++i)
++		fe_sq_tt(&t1, &t1);
++	fe_mul_ttt(out, &t1, &t0);
++}
++
++static __always_inline void fe_invert(fe *out, const fe *z)
++{
++	fe_loose l;
++	fe_copy_lt(&l, z);
++	fe_loose_invert(out, &l);
++}
++
++/* Replace (f,g) with (g,f) if b == 1;
++ * replace (f,g) with (f,g) if b == 0.
++ *
++ * Preconditions: b in {0,1}
++ */
++static __always_inline void fe_cswap(fe *f, fe *g, unsigned int b)
++{
++	unsigned i;
++	b = 0 - b;
++	for (i = 0; i < 10; i++) {
++		u32 x = f->v[i] ^ g->v[i];
++		x &= b;
++		f->v[i] ^= x;
++		g->v[i] ^= x;
++	}
++}
++
++/* NOTE: based on fiat-crypto fe_mul, edited for in2=121666, 0, 0.*/
++static __always_inline void fe_mul_121666_impl(u32 out[10], const u32 in1[10])
++{
++	{ const u32 x20 = in1[9];
++	{ const u32 x21 = in1[8];
++	{ const u32 x19 = in1[7];
++	{ const u32 x17 = in1[6];
++	{ const u32 x15 = in1[5];
++	{ const u32 x13 = in1[4];
++	{ const u32 x11 = in1[3];
++	{ const u32 x9 = in1[2];
++	{ const u32 x7 = in1[1];
++	{ const u32 x5 = in1[0];
++	{ const u32 x38 = 0;
++	{ const u32 x39 = 0;
++	{ const u32 x37 = 0;
++	{ const u32 x35 = 0;
++	{ const u32 x33 = 0;
++	{ const u32 x31 = 0;
++	{ const u32 x29 = 0;
++	{ const u32 x27 = 0;
++	{ const u32 x25 = 0;
++	{ const u32 x23 = 121666;
++	{ u64 x40 = ((u64)x23 * x5);
++	{ u64 x41 = (((u64)x23 * x7) + ((u64)x25 * x5));
++	{ u64 x42 = ((((u64)(0x2 * x25) * x7) + ((u64)x23 * x9)) + ((u64)x27 * x5));
++	{ u64 x43 = (((((u64)x25 * x9) + ((u64)x27 * x7)) + ((u64)x23 * x11)) + ((u64)x29 * x5));
++	{ u64 x44 = (((((u64)x27 * x9) + (0x2 * (((u64)x25 * x11) + ((u64)x29 * x7)))) + ((u64)x23 * x13)) + ((u64)x31 * x5));
++	{ u64 x45 = (((((((u64)x27 * x11) + ((u64)x29 * x9)) + ((u64)x25 * x13)) + ((u64)x31 * x7)) + ((u64)x23 * x15)) + ((u64)x33 * x5));
++	{ u64 x46 = (((((0x2 * ((((u64)x29 * x11) + ((u64)x25 * x15)) + ((u64)x33 * x7))) + ((u64)x27 * x13)) + ((u64)x31 * x9)) + ((u64)x23 * x17)) + ((u64)x35 * x5));
++	{ u64 x47 = (((((((((u64)x29 * x13) + ((u64)x31 * x11)) + ((u64)x27 * x15)) + ((u64)x33 * x9)) + ((u64)x25 * x17)) + ((u64)x35 * x7)) + ((u64)x23 * x19)) + ((u64)x37 * x5));
++	{ u64 x48 = (((((((u64)x31 * x13) + (0x2 * (((((u64)x29 * x15) + ((u64)x33 * x11)) + ((u64)x25 * x19)) + ((u64)x37 * x7)))) + ((u64)x27 * x17)) + ((u64)x35 * x9)) + ((u64)x23 * x21)) + ((u64)x39 * x5));
++	{ u64 x49 = (((((((((((u64)x31 * x15) + ((u64)x33 * x13)) + ((u64)x29 * x17)) + ((u64)x35 * x11)) + ((u64)x27 * x19)) + ((u64)x37 * x9)) + ((u64)x25 * x21)) + ((u64)x39 * x7)) + ((u64)x23 * x20)) + ((u64)x38 * x5));
++	{ u64 x50 = (((((0x2 * ((((((u64)x33 * x15) + ((u64)x29 * x19)) + ((u64)x37 * x11)) + ((u64)x25 * x20)) + ((u64)x38 * x7))) + ((u64)x31 * x17)) + ((u64)x35 * x13)) + ((u64)x27 * x21)) + ((u64)x39 * x9));
++	{ u64 x51 = (((((((((u64)x33 * x17) + ((u64)x35 * x15)) + ((u64)x31 * x19)) + ((u64)x37 * x13)) + ((u64)x29 * x21)) + ((u64)x39 * x11)) + ((u64)x27 * x20)) + ((u64)x38 * x9));
++	{ u64 x52 = (((((u64)x35 * x17) + (0x2 * (((((u64)x33 * x19) + ((u64)x37 * x15)) + ((u64)x29 * x20)) + ((u64)x38 * x11)))) + ((u64)x31 * x21)) + ((u64)x39 * x13));
++	{ u64 x53 = (((((((u64)x35 * x19) + ((u64)x37 * x17)) + ((u64)x33 * x21)) + ((u64)x39 * x15)) + ((u64)x31 * x20)) + ((u64)x38 * x13));
++	{ u64 x54 = (((0x2 * ((((u64)x37 * x19) + ((u64)x33 * x20)) + ((u64)x38 * x15))) + ((u64)x35 * x21)) + ((u64)x39 * x17));
++	{ u64 x55 = (((((u64)x37 * x21) + ((u64)x39 * x19)) + ((u64)x35 * x20)) + ((u64)x38 * x17));
++	{ u64 x56 = (((u64)x39 * x21) + (0x2 * (((u64)x37 * x20) + ((u64)x38 * x19))));
++	{ u64 x57 = (((u64)x39 * x20) + ((u64)x38 * x21));
++	{ u64 x58 = ((u64)(0x2 * x38) * x20);
++	{ u64 x59 = (x48 + (x58 << 0x4));
++	{ u64 x60 = (x59 + (x58 << 0x1));
++	{ u64 x61 = (x60 + x58);
++	{ u64 x62 = (x47 + (x57 << 0x4));
++	{ u64 x63 = (x62 + (x57 << 0x1));
++	{ u64 x64 = (x63 + x57);
++	{ u64 x65 = (x46 + (x56 << 0x4));
++	{ u64 x66 = (x65 + (x56 << 0x1));
++	{ u64 x67 = (x66 + x56);
++	{ u64 x68 = (x45 + (x55 << 0x4));
++	{ u64 x69 = (x68 + (x55 << 0x1));
++	{ u64 x70 = (x69 + x55);
++	{ u64 x71 = (x44 + (x54 << 0x4));
++	{ u64 x72 = (x71 + (x54 << 0x1));
++	{ u64 x73 = (x72 + x54);
++	{ u64 x74 = (x43 + (x53 << 0x4));
++	{ u64 x75 = (x74 + (x53 << 0x1));
++	{ u64 x76 = (x75 + x53);
++	{ u64 x77 = (x42 + (x52 << 0x4));
++	{ u64 x78 = (x77 + (x52 << 0x1));
++	{ u64 x79 = (x78 + x52);
++	{ u64 x80 = (x41 + (x51 << 0x4));
++	{ u64 x81 = (x80 + (x51 << 0x1));
++	{ u64 x82 = (x81 + x51);
++	{ u64 x83 = (x40 + (x50 << 0x4));
++	{ u64 x84 = (x83 + (x50 << 0x1));
++	{ u64 x85 = (x84 + x50);
++	{ u64 x86 = (x85 >> 0x1a);
++	{ u32 x87 = ((u32)x85 & 0x3ffffff);
++	{ u64 x88 = (x86 + x82);
++	{ u64 x89 = (x88 >> 0x19);
++	{ u32 x90 = ((u32)x88 & 0x1ffffff);
++	{ u64 x91 = (x89 + x79);
++	{ u64 x92 = (x91 >> 0x1a);
++	{ u32 x93 = ((u32)x91 & 0x3ffffff);
++	{ u64 x94 = (x92 + x76);
++	{ u64 x95 = (x94 >> 0x19);
++	{ u32 x96 = ((u32)x94 & 0x1ffffff);
++	{ u64 x97 = (x95 + x73);
++	{ u64 x98 = (x97 >> 0x1a);
++	{ u32 x99 = ((u32)x97 & 0x3ffffff);
++	{ u64 x100 = (x98 + x70);
++	{ u64 x101 = (x100 >> 0x19);
++	{ u32 x102 = ((u32)x100 & 0x1ffffff);
++	{ u64 x103 = (x101 + x67);
++	{ u64 x104 = (x103 >> 0x1a);
++	{ u32 x105 = ((u32)x103 & 0x3ffffff);
++	{ u64 x106 = (x104 + x64);
++	{ u64 x107 = (x106 >> 0x19);
++	{ u32 x108 = ((u32)x106 & 0x1ffffff);
++	{ u64 x109 = (x107 + x61);
++	{ u64 x110 = (x109 >> 0x1a);
++	{ u32 x111 = ((u32)x109 & 0x3ffffff);
++	{ u64 x112 = (x110 + x49);
++	{ u64 x113 = (x112 >> 0x19);
++	{ u32 x114 = ((u32)x112 & 0x1ffffff);
++	{ u64 x115 = (x87 + (0x13 * x113));
++	{ u32 x116 = (u32) (x115 >> 0x1a);
++	{ u32 x117 = ((u32)x115 & 0x3ffffff);
++	{ u32 x118 = (x116 + x90);
++	{ u32 x119 = (x118 >> 0x19);
++	{ u32 x120 = (x118 & 0x1ffffff);
++	out[0] = x117;
++	out[1] = x120;
++	out[2] = (x119 + x93);
++	out[3] = x96;
++	out[4] = x99;
++	out[5] = x102;
++	out[6] = x105;
++	out[7] = x108;
++	out[8] = x111;
++	out[9] = x114;
++	}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
++}
++
++static __always_inline void fe_mul121666(fe *h, const fe_loose *f)
++{
++	fe_mul_121666_impl(h->v, f->v);
++}
++
++void curve25519_generic(u8 out[CURVE25519_KEY_SIZE],
++			const u8 scalar[CURVE25519_KEY_SIZE],
++			const u8 point[CURVE25519_KEY_SIZE])
++{
++	fe x1, x2, z2, x3, z3;
++	fe_loose x2l, z2l, x3l;
++	unsigned swap = 0;
++	int pos;
++	u8 e[32];
++
++	memcpy(e, scalar, 32);
++	curve25519_clamp_secret(e);
++
++	/* The following implementation was transcribed to Coq and proven to
++	 * correspond to unary scalar multiplication in affine coordinates given
++	 * that x1 != 0 is the x coordinate of some point on the curve. It was
++	 * also checked in Coq that doing a ladderstep with x1 = x3 = 0 gives
++	 * z2' = z3' = 0, and z2 = z3 = 0 gives z2' = z3' = 0. The statement was
++	 * quantified over the underlying field, so it applies to Curve25519
++	 * itself and the quadratic twist of Curve25519. It was not proven in
++	 * Coq that prime-field arithmetic correctly simulates extension-field
++	 * arithmetic on prime-field values. The decoding of the byte array
++	 * representation of e was not considered.
++	 *
++	 * Specification of Montgomery curves in affine coordinates:
++	 * <https://github.com/mit-plv/fiat-crypto/blob/2456d821825521f7e03e65882cc3521795b0320f/src/Spec/MontgomeryCurve.v#L27>
++	 *
++	 * Proof that these form a group that is isomorphic to a Weierstrass
++	 * curve:
++	 * <https://github.com/mit-plv/fiat-crypto/blob/2456d821825521f7e03e65882cc3521795b0320f/src/Curves/Montgomery/AffineProofs.v#L35>
++	 *
++	 * Coq transcription and correctness proof of the loop
++	 * (where scalarbits=255):
++	 * <https://github.com/mit-plv/fiat-crypto/blob/2456d821825521f7e03e65882cc3521795b0320f/src/Curves/Montgomery/XZ.v#L118>
++	 * <https://github.com/mit-plv/fiat-crypto/blob/2456d821825521f7e03e65882cc3521795b0320f/src/Curves/Montgomery/XZProofs.v#L278>
++	 * preconditions: 0 <= e < 2^255 (not necessarily e < order),
++	 * fe_invert(0) = 0
++	 */
++	fe_frombytes(&x1, point);
++	fe_1(&x2);
++	fe_0(&z2);
++	fe_copy(&x3, &x1);
++	fe_1(&z3);
++
++	for (pos = 254; pos >= 0; --pos) {
++		fe tmp0, tmp1;
++		fe_loose tmp0l, tmp1l;
++		/* loop invariant as of right before the test, for the case
++		 * where x1 != 0:
++		 *   pos >= -1; if z2 = 0 then x2 is nonzero; if z3 = 0 then x3
++		 *   is nonzero
++		 *   let r := e >> (pos+1) in the following equalities of
++		 *   projective points:
++		 *   to_xz (r*P)     === if swap then (x3, z3) else (x2, z2)
++		 *   to_xz ((r+1)*P) === if swap then (x2, z2) else (x3, z3)
++		 *   x1 is the nonzero x coordinate of the nonzero
++		 *   point (r*P-(r+1)*P)
++		 */
++		unsigned b = 1 & (e[pos / 8] >> (pos & 7));
++		swap ^= b;
++		fe_cswap(&x2, &x3, swap);
++		fe_cswap(&z2, &z3, swap);
++		swap = b;
++		/* Coq transcription of ladderstep formula (called from
++		 * transcribed loop):
++		 * <https://github.com/mit-plv/fiat-crypto/blob/2456d821825521f7e03e65882cc3521795b0320f/src/Curves/Montgomery/XZ.v#L89>
++		 * <https://github.com/mit-plv/fiat-crypto/blob/2456d821825521f7e03e65882cc3521795b0320f/src/Curves/Montgomery/XZProofs.v#L131>
++		 * x1 != 0 <https://github.com/mit-plv/fiat-crypto/blob/2456d821825521f7e03e65882cc3521795b0320f/src/Curves/Montgomery/XZProofs.v#L217>
++		 * x1  = 0 <https://github.com/mit-plv/fiat-crypto/blob/2456d821825521f7e03e65882cc3521795b0320f/src/Curves/Montgomery/XZProofs.v#L147>
++		 */
++		fe_sub(&tmp0l, &x3, &z3);
++		fe_sub(&tmp1l, &x2, &z2);
++		fe_add(&x2l, &x2, &z2);
++		fe_add(&z2l, &x3, &z3);
++		fe_mul_tll(&z3, &tmp0l, &x2l);
++		fe_mul_tll(&z2, &z2l, &tmp1l);
++		fe_sq_tl(&tmp0, &tmp1l);
++		fe_sq_tl(&tmp1, &x2l);
++		fe_add(&x3l, &z3, &z2);
++		fe_sub(&z2l, &z3, &z2);
++		fe_mul_ttt(&x2, &tmp1, &tmp0);
++		fe_sub(&tmp1l, &tmp1, &tmp0);
++		fe_sq_tl(&z2, &z2l);
++		fe_mul121666(&z3, &tmp1l);
++		fe_sq_tl(&x3, &x3l);
++		fe_add(&tmp0l, &tmp0, &z3);
++		fe_mul_ttt(&z3, &x1, &z2);
++		fe_mul_tll(&z2, &tmp1l, &tmp0l);
++	}
++	/* here pos=-1, so r=e, so to_xz (e*P) === if swap then (x3, z3)
++	 * else (x2, z2)
++	 */
++	fe_cswap(&x2, &x3, swap);
++	fe_cswap(&z2, &z3, swap);
++
++	fe_invert(&z2, &z2);
++	fe_mul_ttt(&x2, &x2, &z2);
++	fe_tobytes(out, &x2);
++
++	memzero_explicit(&x1, sizeof(x1));
++	memzero_explicit(&x2, sizeof(x2));
++	memzero_explicit(&z2, sizeof(z2));
++	memzero_explicit(&x3, sizeof(x3));
++	memzero_explicit(&z3, sizeof(z3));
++	memzero_explicit(&x2l, sizeof(x2l));
++	memzero_explicit(&z2l, sizeof(z2l));
++	memzero_explicit(&x3l, sizeof(x3l));
++	memzero_explicit(&e, sizeof(e));
++}
+--- /dev/null
++++ b/lib/crypto/curve25519-hacl64.c
+@@ -0,0 +1,788 @@
++// SPDX-License-Identifier: GPL-2.0 OR MIT
++/*
++ * Copyright (C) 2016-2017 INRIA and Microsoft Corporation.
++ * Copyright (C) 2018-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ *
++ * This is a machine-generated formally verified implementation of Curve25519
++ * ECDH from: <https://github.com/mitls/hacl-star>. Though originally machine
++ * generated, it has been tweaked to be suitable for use in the kernel. It is
++ * optimized for 64-bit machines that can efficiently work with 128-bit
++ * integer types.
++ */
++
++#include <asm/unaligned.h>
++#include <crypto/curve25519.h>
++#include <linux/string.h>
++
++typedef __uint128_t u128;
++
++static __always_inline u64 u64_eq_mask(u64 a, u64 b)
++{
++	u64 x = a ^ b;
++	u64 minus_x = ~x + (u64)1U;
++	u64 x_or_minus_x = x | minus_x;
++	u64 xnx = x_or_minus_x >> (u32)63U;
++	u64 c = xnx - (u64)1U;
++	return c;
++}
++
++static __always_inline u64 u64_gte_mask(u64 a, u64 b)
++{
++	u64 x = a;
++	u64 y = b;
++	u64 x_xor_y = x ^ y;
++	u64 x_sub_y = x - y;
++	u64 x_sub_y_xor_y = x_sub_y ^ y;
++	u64 q = x_xor_y | x_sub_y_xor_y;
++	u64 x_xor_q = x ^ q;
++	u64 x_xor_q_ = x_xor_q >> (u32)63U;
++	u64 c = x_xor_q_ - (u64)1U;
++	return c;
++}
++
++static __always_inline void modulo_carry_top(u64 *b)
++{
++	u64 b4 = b[4];
++	u64 b0 = b[0];
++	u64 b4_ = b4 & 0x7ffffffffffffLLU;
++	u64 b0_ = b0 + 19 * (b4 >> 51);
++	b[4] = b4_;
++	b[0] = b0_;
++}
++
++static __always_inline void fproduct_copy_from_wide_(u64 *output, u128 *input)
++{
++	{
++		u128 xi = input[0];
++		output[0] = ((u64)(xi));
++	}
++	{
++		u128 xi = input[1];
++		output[1] = ((u64)(xi));
++	}
++	{
++		u128 xi = input[2];
++		output[2] = ((u64)(xi));
++	}
++	{
++		u128 xi = input[3];
++		output[3] = ((u64)(xi));
++	}
++	{
++		u128 xi = input[4];
++		output[4] = ((u64)(xi));
++	}
++}
++
++static __always_inline void
++fproduct_sum_scalar_multiplication_(u128 *output, u64 *input, u64 s)
++{
++	output[0] += (u128)input[0] * s;
++	output[1] += (u128)input[1] * s;
++	output[2] += (u128)input[2] * s;
++	output[3] += (u128)input[3] * s;
++	output[4] += (u128)input[4] * s;
++}
++
++static __always_inline void fproduct_carry_wide_(u128 *tmp)
++{
++	{
++		u32 ctr = 0;
++		u128 tctr = tmp[ctr];
++		u128 tctrp1 = tmp[ctr + 1];
++		u64 r0 = ((u64)(tctr)) & 0x7ffffffffffffLLU;
++		u128 c = ((tctr) >> (51));
++		tmp[ctr] = ((u128)(r0));
++		tmp[ctr + 1] = ((tctrp1) + (c));
++	}
++	{
++		u32 ctr = 1;
++		u128 tctr = tmp[ctr];
++		u128 tctrp1 = tmp[ctr + 1];
++		u64 r0 = ((u64)(tctr)) & 0x7ffffffffffffLLU;
++		u128 c = ((tctr) >> (51));
++		tmp[ctr] = ((u128)(r0));
++		tmp[ctr + 1] = ((tctrp1) + (c));
++	}
++
++	{
++		u32 ctr = 2;
++		u128 tctr = tmp[ctr];
++		u128 tctrp1 = tmp[ctr + 1];
++		u64 r0 = ((u64)(tctr)) & 0x7ffffffffffffLLU;
++		u128 c = ((tctr) >> (51));
++		tmp[ctr] = ((u128)(r0));
++		tmp[ctr + 1] = ((tctrp1) + (c));
++	}
++	{
++		u32 ctr = 3;
++		u128 tctr = tmp[ctr];
++		u128 tctrp1 = tmp[ctr + 1];
++		u64 r0 = ((u64)(tctr)) & 0x7ffffffffffffLLU;
++		u128 c = ((tctr) >> (51));
++		tmp[ctr] = ((u128)(r0));
++		tmp[ctr + 1] = ((tctrp1) + (c));
++	}
++}
++
++static __always_inline void fmul_shift_reduce(u64 *output)
++{
++	u64 tmp = output[4];
++	u64 b0;
++	{
++		u32 ctr = 5 - 0 - 1;
++		u64 z = output[ctr - 1];
++		output[ctr] = z;
++	}
++	{
++		u32 ctr = 5 - 1 - 1;
++		u64 z = output[ctr - 1];
++		output[ctr] = z;
++	}
++	{
++		u32 ctr = 5 - 2 - 1;
++		u64 z = output[ctr - 1];
++		output[ctr] = z;
++	}
++	{
++		u32 ctr = 5 - 3 - 1;
++		u64 z = output[ctr - 1];
++		output[ctr] = z;
++	}
++	output[0] = tmp;
++	b0 = output[0];
++	output[0] = 19 * b0;
++}
++
++static __always_inline void fmul_mul_shift_reduce_(u128 *output, u64 *input,
++						   u64 *input21)
++{
++	u32 i;
++	u64 input2i;
++	{
++		u64 input2i = input21[0];
++		fproduct_sum_scalar_multiplication_(output, input, input2i);
++		fmul_shift_reduce(input);
++	}
++	{
++		u64 input2i = input21[1];
++		fproduct_sum_scalar_multiplication_(output, input, input2i);
++		fmul_shift_reduce(input);
++	}
++	{
++		u64 input2i = input21[2];
++		fproduct_sum_scalar_multiplication_(output, input, input2i);
++		fmul_shift_reduce(input);
++	}
++	{
++		u64 input2i = input21[3];
++		fproduct_sum_scalar_multiplication_(output, input, input2i);
++		fmul_shift_reduce(input);
++	}
++	i = 4;
++	input2i = input21[i];
++	fproduct_sum_scalar_multiplication_(output, input, input2i);
++}
++
++static __always_inline void fmul_fmul(u64 *output, u64 *input, u64 *input21)
++{
++	u64 tmp[5] = { input[0], input[1], input[2], input[3], input[4] };
++	{
++		u128 b4;
++		u128 b0;
++		u128 b4_;
++		u128 b0_;
++		u64 i0;
++		u64 i1;
++		u64 i0_;
++		u64 i1_;
++		u128 t[5] = { 0 };
++		fmul_mul_shift_reduce_(t, tmp, input21);
++		fproduct_carry_wide_(t);
++		b4 = t[4];
++		b0 = t[0];
++		b4_ = ((b4) & (((u128)(0x7ffffffffffffLLU))));
++		b0_ = ((b0) + (((u128)(19) * (((u64)(((b4) >> (51))))))));
++		t[4] = b4_;
++		t[0] = b0_;
++		fproduct_copy_from_wide_(output, t);
++		i0 = output[0];
++		i1 = output[1];
++		i0_ = i0 & 0x7ffffffffffffLLU;
++		i1_ = i1 + (i0 >> 51);
++		output[0] = i0_;
++		output[1] = i1_;
++	}
++}
++
++static __always_inline void fsquare_fsquare__(u128 *tmp, u64 *output)
++{
++	u64 r0 = output[0];
++	u64 r1 = output[1];
++	u64 r2 = output[2];
++	u64 r3 = output[3];
++	u64 r4 = output[4];
++	u64 d0 = r0 * 2;
++	u64 d1 = r1 * 2;
++	u64 d2 = r2 * 2 * 19;
++	u64 d419 = r4 * 19;
++	u64 d4 = d419 * 2;
++	u128 s0 = ((((((u128)(r0) * (r0))) + (((u128)(d4) * (r1))))) +
++		   (((u128)(d2) * (r3))));
++	u128 s1 = ((((((u128)(d0) * (r1))) + (((u128)(d4) * (r2))))) +
++		   (((u128)(r3 * 19) * (r3))));
++	u128 s2 = ((((((u128)(d0) * (r2))) + (((u128)(r1) * (r1))))) +
++		   (((u128)(d4) * (r3))));
++	u128 s3 = ((((((u128)(d0) * (r3))) + (((u128)(d1) * (r2))))) +
++		   (((u128)(r4) * (d419))));
++	u128 s4 = ((((((u128)(d0) * (r4))) + (((u128)(d1) * (r3))))) +
++		   (((u128)(r2) * (r2))));
++	tmp[0] = s0;
++	tmp[1] = s1;
++	tmp[2] = s2;
++	tmp[3] = s3;
++	tmp[4] = s4;
++}
++
++static __always_inline void fsquare_fsquare_(u128 *tmp, u64 *output)
++{
++	u128 b4;
++	u128 b0;
++	u128 b4_;
++	u128 b0_;
++	u64 i0;
++	u64 i1;
++	u64 i0_;
++	u64 i1_;
++	fsquare_fsquare__(tmp, output);
++	fproduct_carry_wide_(tmp);
++	b4 = tmp[4];
++	b0 = tmp[0];
++	b4_ = ((b4) & (((u128)(0x7ffffffffffffLLU))));
++	b0_ = ((b0) + (((u128)(19) * (((u64)(((b4) >> (51))))))));
++	tmp[4] = b4_;
++	tmp[0] = b0_;
++	fproduct_copy_from_wide_(output, tmp);
++	i0 = output[0];
++	i1 = output[1];
++	i0_ = i0 & 0x7ffffffffffffLLU;
++	i1_ = i1 + (i0 >> 51);
++	output[0] = i0_;
++	output[1] = i1_;
++}
++
++static __always_inline void fsquare_fsquare_times_(u64 *output, u128 *tmp,
++						   u32 count1)
++{
++	u32 i;
++	fsquare_fsquare_(tmp, output);
++	for (i = 1; i < count1; ++i)
++		fsquare_fsquare_(tmp, output);
++}
++
++static __always_inline void fsquare_fsquare_times(u64 *output, u64 *input,
++						  u32 count1)
++{
++	u128 t[5];
++	memcpy(output, input, 5 * sizeof(*input));
++	fsquare_fsquare_times_(output, t, count1);
++}
++
++static __always_inline void fsquare_fsquare_times_inplace(u64 *output,
++							  u32 count1)
++{
++	u128 t[5];
++	fsquare_fsquare_times_(output, t, count1);
++}
++
++static __always_inline void crecip_crecip(u64 *out, u64 *z)
++{
++	u64 buf[20] = { 0 };
++	u64 *a0 = buf;
++	u64 *t00 = buf + 5;
++	u64 *b0 = buf + 10;
++	u64 *t01;
++	u64 *b1;
++	u64 *c0;
++	u64 *a;
++	u64 *t0;
++	u64 *b;
++	u64 *c;
++	fsquare_fsquare_times(a0, z, 1);
++	fsquare_fsquare_times(t00, a0, 2);
++	fmul_fmul(b0, t00, z);
++	fmul_fmul(a0, b0, a0);
++	fsquare_fsquare_times(t00, a0, 1);
++	fmul_fmul(b0, t00, b0);
++	fsquare_fsquare_times(t00, b0, 5);
++	t01 = buf + 5;
++	b1 = buf + 10;
++	c0 = buf + 15;
++	fmul_fmul(b1, t01, b1);
++	fsquare_fsquare_times(t01, b1, 10);
++	fmul_fmul(c0, t01, b1);
++	fsquare_fsquare_times(t01, c0, 20);
++	fmul_fmul(t01, t01, c0);
++	fsquare_fsquare_times_inplace(t01, 10);
++	fmul_fmul(b1, t01, b1);
++	fsquare_fsquare_times(t01, b1, 50);
++	a = buf;
++	t0 = buf + 5;
++	b = buf + 10;
++	c = buf + 15;
++	fmul_fmul(c, t0, b);
++	fsquare_fsquare_times(t0, c, 100);
++	fmul_fmul(t0, t0, c);
++	fsquare_fsquare_times_inplace(t0, 50);
++	fmul_fmul(t0, t0, b);
++	fsquare_fsquare_times_inplace(t0, 5);
++	fmul_fmul(out, t0, a);
++}
++
++static __always_inline void fsum(u64 *a, u64 *b)
++{
++	a[0] += b[0];
++	a[1] += b[1];
++	a[2] += b[2];
++	a[3] += b[3];
++	a[4] += b[4];
++}
++
++static __always_inline void fdifference(u64 *a, u64 *b)
++{
++	u64 tmp[5] = { 0 };
++	u64 b0;
++	u64 b1;
++	u64 b2;
++	u64 b3;
++	u64 b4;
++	memcpy(tmp, b, 5 * sizeof(*b));
++	b0 = tmp[0];
++	b1 = tmp[1];
++	b2 = tmp[2];
++	b3 = tmp[3];
++	b4 = tmp[4];
++	tmp[0] = b0 + 0x3fffffffffff68LLU;
++	tmp[1] = b1 + 0x3ffffffffffff8LLU;
++	tmp[2] = b2 + 0x3ffffffffffff8LLU;
++	tmp[3] = b3 + 0x3ffffffffffff8LLU;
++	tmp[4] = b4 + 0x3ffffffffffff8LLU;
++	{
++		u64 xi = a[0];
++		u64 yi = tmp[0];
++		a[0] = yi - xi;
++	}
++	{
++		u64 xi = a[1];
++		u64 yi = tmp[1];
++		a[1] = yi - xi;
++	}
++	{
++		u64 xi = a[2];
++		u64 yi = tmp[2];
++		a[2] = yi - xi;
++	}
++	{
++		u64 xi = a[3];
++		u64 yi = tmp[3];
++		a[3] = yi - xi;
++	}
++	{
++		u64 xi = a[4];
++		u64 yi = tmp[4];
++		a[4] = yi - xi;
++	}
++}
++
++static __always_inline void fscalar(u64 *output, u64 *b, u64 s)
++{
++	u128 tmp[5];
++	u128 b4;
++	u128 b0;
++	u128 b4_;
++	u128 b0_;
++	{
++		u64 xi = b[0];
++		tmp[0] = ((u128)(xi) * (s));
++	}
++	{
++		u64 xi = b[1];
++		tmp[1] = ((u128)(xi) * (s));
++	}
++	{
++		u64 xi = b[2];
++		tmp[2] = ((u128)(xi) * (s));
++	}
++	{
++		u64 xi = b[3];
++		tmp[3] = ((u128)(xi) * (s));
++	}
++	{
++		u64 xi = b[4];
++		tmp[4] = ((u128)(xi) * (s));
++	}
++	fproduct_carry_wide_(tmp);
++	b4 = tmp[4];
++	b0 = tmp[0];
++	b4_ = ((b4) & (((u128)(0x7ffffffffffffLLU))));
++	b0_ = ((b0) + (((u128)(19) * (((u64)(((b4) >> (51))))))));
++	tmp[4] = b4_;
++	tmp[0] = b0_;
++	fproduct_copy_from_wide_(output, tmp);
++}
++
++static __always_inline void fmul(u64 *output, u64 *a, u64 *b)
++{
++	fmul_fmul(output, a, b);
++}
++
++static __always_inline void crecip(u64 *output, u64 *input)
++{
++	crecip_crecip(output, input);
++}
++
++static __always_inline void point_swap_conditional_step(u64 *a, u64 *b,
++							u64 swap1, u32 ctr)
++{
++	u32 i = ctr - 1;
++	u64 ai = a[i];
++	u64 bi = b[i];
++	u64 x = swap1 & (ai ^ bi);
++	u64 ai1 = ai ^ x;
++	u64 bi1 = bi ^ x;
++	a[i] = ai1;
++	b[i] = bi1;
++}
++
++static __always_inline void point_swap_conditional5(u64 *a, u64 *b, u64 swap1)
++{
++	point_swap_conditional_step(a, b, swap1, 5);
++	point_swap_conditional_step(a, b, swap1, 4);
++	point_swap_conditional_step(a, b, swap1, 3);
++	point_swap_conditional_step(a, b, swap1, 2);
++	point_swap_conditional_step(a, b, swap1, 1);
++}
++
++static __always_inline void point_swap_conditional(u64 *a, u64 *b, u64 iswap)
++{
++	u64 swap1 = 0 - iswap;
++	point_swap_conditional5(a, b, swap1);
++	point_swap_conditional5(a + 5, b + 5, swap1);
++}
++
++static __always_inline void point_copy(u64 *output, u64 *input)
++{
++	memcpy(output, input, 5 * sizeof(*input));
++	memcpy(output + 5, input + 5, 5 * sizeof(*input));
++}
++
++static __always_inline void addanddouble_fmonty(u64 *pp, u64 *ppq, u64 *p,
++						u64 *pq, u64 *qmqp)
++{
++	u64 *qx = qmqp;
++	u64 *x2 = pp;
++	u64 *z2 = pp + 5;
++	u64 *x3 = ppq;
++	u64 *z3 = ppq + 5;
++	u64 *x = p;
++	u64 *z = p + 5;
++	u64 *xprime = pq;
++	u64 *zprime = pq + 5;
++	u64 buf[40] = { 0 };
++	u64 *origx = buf;
++	u64 *origxprime0 = buf + 5;
++	u64 *xxprime0;
++	u64 *zzprime0;
++	u64 *origxprime;
++	xxprime0 = buf + 25;
++	zzprime0 = buf + 30;
++	memcpy(origx, x, 5 * sizeof(*x));
++	fsum(x, z);
++	fdifference(z, origx);
++	memcpy(origxprime0, xprime, 5 * sizeof(*xprime));
++	fsum(xprime, zprime);
++	fdifference(zprime, origxprime0);
++	fmul(xxprime0, xprime, z);
++	fmul(zzprime0, x, zprime);
++	origxprime = buf + 5;
++	{
++		u64 *xx0;
++		u64 *zz0;
++		u64 *xxprime;
++		u64 *zzprime;
++		u64 *zzzprime;
++		xx0 = buf + 15;
++		zz0 = buf + 20;
++		xxprime = buf + 25;
++		zzprime = buf + 30;
++		zzzprime = buf + 35;
++		memcpy(origxprime, xxprime, 5 * sizeof(*xxprime));
++		fsum(xxprime, zzprime);
++		fdifference(zzprime, origxprime);
++		fsquare_fsquare_times(x3, xxprime, 1);
++		fsquare_fsquare_times(zzzprime, zzprime, 1);
++		fmul(z3, zzzprime, qx);
++		fsquare_fsquare_times(xx0, x, 1);
++		fsquare_fsquare_times(zz0, z, 1);
++		{
++			u64 *zzz;
++			u64 *xx;
++			u64 *zz;
++			u64 scalar;
++			zzz = buf + 10;
++			xx = buf + 15;
++			zz = buf + 20;
++			fmul(x2, xx, zz);
++			fdifference(zz, xx);
++			scalar = 121665;
++			fscalar(zzz, zz, scalar);
++			fsum(zzz, xx);
++			fmul(z2, zzz, zz);
++		}
++	}
++}
++
++static __always_inline void
++ladder_smallloop_cmult_small_loop_step(u64 *nq, u64 *nqpq, u64 *nq2, u64 *nqpq2,
++				       u64 *q, u8 byt)
++{
++	u64 bit0 = (u64)(byt >> 7);
++	u64 bit;
++	point_swap_conditional(nq, nqpq, bit0);
++	addanddouble_fmonty(nq2, nqpq2, nq, nqpq, q);
++	bit = (u64)(byt >> 7);
++	point_swap_conditional(nq2, nqpq2, bit);
++}
++
++static __always_inline void
++ladder_smallloop_cmult_small_loop_double_step(u64 *nq, u64 *nqpq, u64 *nq2,
++					      u64 *nqpq2, u64 *q, u8 byt)
++{
++	u8 byt1;
++	ladder_smallloop_cmult_small_loop_step(nq, nqpq, nq2, nqpq2, q, byt);
++	byt1 = byt << 1;
++	ladder_smallloop_cmult_small_loop_step(nq2, nqpq2, nq, nqpq, q, byt1);
++}
++
++static __always_inline void
++ladder_smallloop_cmult_small_loop(u64 *nq, u64 *nqpq, u64 *nq2, u64 *nqpq2,
++				  u64 *q, u8 byt, u32 i)
++{
++	while (i--) {
++		ladder_smallloop_cmult_small_loop_double_step(nq, nqpq, nq2,
++							      nqpq2, q, byt);
++		byt <<= 2;
++	}
++}
++
++static __always_inline void ladder_bigloop_cmult_big_loop(u8 *n1, u64 *nq,
++							  u64 *nqpq, u64 *nq2,
++							  u64 *nqpq2, u64 *q,
++							  u32 i)
++{
++	while (i--) {
++		u8 byte = n1[i];
++		ladder_smallloop_cmult_small_loop(nq, nqpq, nq2, nqpq2, q,
++						  byte, 4);
++	}
++}
++
++static void ladder_cmult(u64 *result, u8 *n1, u64 *q)
++{
++	u64 point_buf[40] = { 0 };
++	u64 *nq = point_buf;
++	u64 *nqpq = point_buf + 10;
++	u64 *nq2 = point_buf + 20;
++	u64 *nqpq2 = point_buf + 30;
++	point_copy(nqpq, q);
++	nq[0] = 1;
++	ladder_bigloop_cmult_big_loop(n1, nq, nqpq, nq2, nqpq2, q, 32);
++	point_copy(result, nq);
++}
++
++static __always_inline void format_fexpand(u64 *output, const u8 *input)
++{
++	const u8 *x00 = input + 6;
++	const u8 *x01 = input + 12;
++	const u8 *x02 = input + 19;
++	const u8 *x0 = input + 24;
++	u64 i0, i1, i2, i3, i4, output0, output1, output2, output3, output4;
++	i0 = get_unaligned_le64(input);
++	i1 = get_unaligned_le64(x00);
++	i2 = get_unaligned_le64(x01);
++	i3 = get_unaligned_le64(x02);
++	i4 = get_unaligned_le64(x0);
++	output0 = i0 & 0x7ffffffffffffLLU;
++	output1 = i1 >> 3 & 0x7ffffffffffffLLU;
++	output2 = i2 >> 6 & 0x7ffffffffffffLLU;
++	output3 = i3 >> 1 & 0x7ffffffffffffLLU;
++	output4 = i4 >> 12 & 0x7ffffffffffffLLU;
++	output[0] = output0;
++	output[1] = output1;
++	output[2] = output2;
++	output[3] = output3;
++	output[4] = output4;
++}
++
++static __always_inline void format_fcontract_first_carry_pass(u64 *input)
++{
++	u64 t0 = input[0];
++	u64 t1 = input[1];
++	u64 t2 = input[2];
++	u64 t3 = input[3];
++	u64 t4 = input[4];
++	u64 t1_ = t1 + (t0 >> 51);
++	u64 t0_ = t0 & 0x7ffffffffffffLLU;
++	u64 t2_ = t2 + (t1_ >> 51);
++	u64 t1__ = t1_ & 0x7ffffffffffffLLU;
++	u64 t3_ = t3 + (t2_ >> 51);
++	u64 t2__ = t2_ & 0x7ffffffffffffLLU;
++	u64 t4_ = t4 + (t3_ >> 51);
++	u64 t3__ = t3_ & 0x7ffffffffffffLLU;
++	input[0] = t0_;
++	input[1] = t1__;
++	input[2] = t2__;
++	input[3] = t3__;
++	input[4] = t4_;
++}
++
++static __always_inline void format_fcontract_first_carry_full(u64 *input)
++{
++	format_fcontract_first_carry_pass(input);
++	modulo_carry_top(input);
++}
++
++static __always_inline void format_fcontract_second_carry_pass(u64 *input)
++{
++	u64 t0 = input[0];
++	u64 t1 = input[1];
++	u64 t2 = input[2];
++	u64 t3 = input[3];
++	u64 t4 = input[4];
++	u64 t1_ = t1 + (t0 >> 51);
++	u64 t0_ = t0 & 0x7ffffffffffffLLU;
++	u64 t2_ = t2 + (t1_ >> 51);
++	u64 t1__ = t1_ & 0x7ffffffffffffLLU;
++	u64 t3_ = t3 + (t2_ >> 51);
++	u64 t2__ = t2_ & 0x7ffffffffffffLLU;
++	u64 t4_ = t4 + (t3_ >> 51);
++	u64 t3__ = t3_ & 0x7ffffffffffffLLU;
++	input[0] = t0_;
++	input[1] = t1__;
++	input[2] = t2__;
++	input[3] = t3__;
++	input[4] = t4_;
++}
++
++static __always_inline void format_fcontract_second_carry_full(u64 *input)
++{
++	u64 i0;
++	u64 i1;
++	u64 i0_;
++	u64 i1_;
++	format_fcontract_second_carry_pass(input);
++	modulo_carry_top(input);
++	i0 = input[0];
++	i1 = input[1];
++	i0_ = i0 & 0x7ffffffffffffLLU;
++	i1_ = i1 + (i0 >> 51);
++	input[0] = i0_;
++	input[1] = i1_;
++}
++
++static __always_inline void format_fcontract_trim(u64 *input)
++{
++	u64 a0 = input[0];
++	u64 a1 = input[1];
++	u64 a2 = input[2];
++	u64 a3 = input[3];
++	u64 a4 = input[4];
++	u64 mask0 = u64_gte_mask(a0, 0x7ffffffffffedLLU);
++	u64 mask1 = u64_eq_mask(a1, 0x7ffffffffffffLLU);
++	u64 mask2 = u64_eq_mask(a2, 0x7ffffffffffffLLU);
++	u64 mask3 = u64_eq_mask(a3, 0x7ffffffffffffLLU);
++	u64 mask4 = u64_eq_mask(a4, 0x7ffffffffffffLLU);
++	u64 mask = (((mask0 & mask1) & mask2) & mask3) & mask4;
++	u64 a0_ = a0 - (0x7ffffffffffedLLU & mask);
++	u64 a1_ = a1 - (0x7ffffffffffffLLU & mask);
++	u64 a2_ = a2 - (0x7ffffffffffffLLU & mask);
++	u64 a3_ = a3 - (0x7ffffffffffffLLU & mask);
++	u64 a4_ = a4 - (0x7ffffffffffffLLU & mask);
++	input[0] = a0_;
++	input[1] = a1_;
++	input[2] = a2_;
++	input[3] = a3_;
++	input[4] = a4_;
++}
++
++static __always_inline void format_fcontract_store(u8 *output, u64 *input)
++{
++	u64 t0 = input[0];
++	u64 t1 = input[1];
++	u64 t2 = input[2];
++	u64 t3 = input[3];
++	u64 t4 = input[4];
++	u64 o0 = t1 << 51 | t0;
++	u64 o1 = t2 << 38 | t1 >> 13;
++	u64 o2 = t3 << 25 | t2 >> 26;
++	u64 o3 = t4 << 12 | t3 >> 39;
++	u8 *b0 = output;
++	u8 *b1 = output + 8;
++	u8 *b2 = output + 16;
++	u8 *b3 = output + 24;
++	put_unaligned_le64(o0, b0);
++	put_unaligned_le64(o1, b1);
++	put_unaligned_le64(o2, b2);
++	put_unaligned_le64(o3, b3);
++}
++
++static __always_inline void format_fcontract(u8 *output, u64 *input)
++{
++	format_fcontract_first_carry_full(input);
++	format_fcontract_second_carry_full(input);
++	format_fcontract_trim(input);
++	format_fcontract_store(output, input);
++}
++
++static __always_inline void format_scalar_of_point(u8 *scalar, u64 *point)
++{
++	u64 *x = point;
++	u64 *z = point + 5;
++	u64 buf[10] __aligned(32) = { 0 };
++	u64 *zmone = buf;
++	u64 *sc = buf + 5;
++	crecip(zmone, z);
++	fmul(sc, x, zmone);
++	format_fcontract(scalar, sc);
++}
++
++void curve25519_generic(u8 mypublic[CURVE25519_KEY_SIZE],
++			const u8 secret[CURVE25519_KEY_SIZE],
++			const u8 basepoint[CURVE25519_KEY_SIZE])
++{
++	u64 buf0[10] __aligned(32) = { 0 };
++	u64 *x0 = buf0;
++	u64 *z = buf0 + 5;
++	u64 *q;
++	format_fexpand(x0, basepoint);
++	z[0] = 1;
++	q = buf0;
++	{
++		u8 e[32] __aligned(32) = { 0 };
++		u8 *scalar;
++		memcpy(e, secret, 32);
++		curve25519_clamp_secret(e);
++		scalar = e;
++		{
++			u64 buf[15] = { 0 };
++			u64 *nq = buf;
++			u64 *x = nq;
++			x[0] = 1;
++			ladder_cmult(nq, scalar, q);
++			format_scalar_of_point(mypublic, nq);
++			memzero_explicit(buf, sizeof(buf));
++		}
++		memzero_explicit(e, sizeof(e));
++	}
++	memzero_explicit(buf0, sizeof(buf0));
++}
+--- /dev/null
++++ b/lib/crypto/curve25519.c
+@@ -0,0 +1,25 @@
++// SPDX-License-Identifier: GPL-2.0 OR MIT
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ *
++ * This is an implementation of the Curve25519 ECDH algorithm, using either
++ * a 32-bit implementation or a 64-bit implementation with 128-bit integers,
++ * depending on what is supported by the target compiler.
++ *
++ * Information: https://cr.yp.to/ecdh.html
++ */
++
++#include <crypto/curve25519.h>
++#include <linux/module.h>
++#include <linux/init.h>
++
++const u8 curve25519_null_point[CURVE25519_KEY_SIZE] __aligned(32) = { 0 };
++const u8 curve25519_base_point[CURVE25519_KEY_SIZE] __aligned(32) = { 9 };
++
++EXPORT_SYMBOL(curve25519_null_point);
++EXPORT_SYMBOL(curve25519_base_point);
++EXPORT_SYMBOL(curve25519_generic);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("Curve25519 scalar multiplication");
++MODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0026-crypto-curve25519-add-kpp-selftest.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0026-crypto-curve25519-add-kpp-selftest.patch
new file mode 100644
index 0000000..b2813ae
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0026-crypto-curve25519-add-kpp-selftest.patch
@@ -0,0 +1,1268 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:33 +0100
+Subject: [PATCH] crypto: curve25519 - add kpp selftest
+
+commit f613457a7af085728297bef71233c37faf3c01b1 upstream.
+
+In preparation of introducing KPP implementations of Curve25519, import
+the set of test cases proposed by the Zinc patch set, but converted to
+the KPP format.
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ crypto/testmgr.c |    6 +
+ crypto/testmgr.h | 1225 ++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 1231 insertions(+)
+
+--- a/crypto/testmgr.c
++++ b/crypto/testmgr.c
+@@ -4296,6 +4296,12 @@ static const struct alg_test_desc alg_te
+ 		.test = alg_test_null,
+ 		.fips_allowed = 1,
+ 	}, {
++		.alg = "curve25519",
++		.test = alg_test_kpp,
++		.suite = {
++			.kpp = __VECS(curve25519_tv_template)
++		}
++	}, {
+ 		.alg = "deflate",
+ 		.test = alg_test_comp,
+ 		.fips_allowed = 1,
+--- a/crypto/testmgr.h
++++ b/crypto/testmgr.h
+@@ -1030,6 +1030,1231 @@ static const struct kpp_testvec dh_tv_te
+ 	}
+ };
+ 
++static const struct kpp_testvec curve25519_tv_template[] = {
++{
++	.secret = (u8[32]){ 0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d,
++		     0x3c, 0x16, 0xc1, 0x72, 0x51, 0xb2, 0x66, 0x45,
++		     0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a,
++		     0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a },
++	.b_public = (u8[32]){ 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4,
++		    0xd3, 0x5b, 0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37,
++		    0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78, 0x67, 0x4d,
++		    0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f },
++	.expected_ss = (u8[32]){ 0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1,
++		    0x72, 0x8e, 0x3b, 0xf4, 0x80, 0x35, 0x0f, 0x25,
++		    0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1, 0x9e, 0x33,
++		    0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++{
++	.secret = (u8[32]){ 0x5d, 0xab, 0x08, 0x7e, 0x62, 0x4a, 0x8a, 0x4b,
++		     0x79, 0xe1, 0x7f, 0x8b, 0x83, 0x80, 0x0e, 0xe6,
++		     0x6f, 0x3b, 0xb1, 0x29, 0x26, 0x18, 0xb6, 0xfd,
++		     0x1c, 0x2f, 0x8b, 0x27, 0xff, 0x88, 0xe0, 0xeb },
++	.b_public = (u8[32]){ 0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54,
++		    0x74, 0x8b, 0x7d, 0xdc, 0xb4, 0x3e, 0xf7, 0x5a,
++		    0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38, 0x1a, 0xf4,
++		    0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a },
++	.expected_ss = (u8[32]){ 0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1,
++		    0x72, 0x8e, 0x3b, 0xf4, 0x80, 0x35, 0x0f, 0x25,
++		    0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1, 0x9e, 0x33,
++		    0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++{
++	.secret = (u8[32]){ 1 },
++	.b_public = (u8[32]){ 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++	.expected_ss = (u8[32]){ 0x3c, 0x77, 0x77, 0xca, 0xf9, 0x97, 0xb2, 0x64,
++		    0x41, 0x60, 0x77, 0x66, 0x5b, 0x4e, 0x22, 0x9d,
++		    0x0b, 0x95, 0x48, 0xdc, 0x0c, 0xd8, 0x19, 0x98,
++		    0xdd, 0xcd, 0xc5, 0xc8, 0x53, 0x3c, 0x79, 0x7f },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++{
++	.secret = (u8[32]){ 1 },
++	.b_public = (u8[32]){ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++	.expected_ss = (u8[32]){ 0xb3, 0x2d, 0x13, 0x62, 0xc2, 0x48, 0xd6, 0x2f,
++		    0xe6, 0x26, 0x19, 0xcf, 0xf0, 0x4d, 0xd4, 0x3d,
++		    0xb7, 0x3f, 0xfc, 0x1b, 0x63, 0x08, 0xed, 0xe3,
++		    0x0b, 0x78, 0xd8, 0x73, 0x80, 0xf1, 0xe8, 0x34 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++{
++	.secret = (u8[32]){ 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d,
++		     0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd,
++		     0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18,
++		     0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4 },
++	.b_public = (u8[32]){ 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb,
++		    0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, 0x5f, 0x7c,
++		    0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b,
++		    0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c },
++	.expected_ss = (u8[32]){ 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90,
++		    0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, 0x08, 0x4f,
++		    0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7,
++		    0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++{
++	.secret = (u8[32]){ 0xff, 0xff, 0xff, 0xff, 0x0a, 0xff, 0xff, 0xff,
++		     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++	.b_public = (u8[32]){ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0x0a, 0x00, 0xfb, 0x9f },
++	.expected_ss = (u8[32]){ 0x77, 0x52, 0xb6, 0x18, 0xc1, 0x2d, 0x48, 0xd2,
++		    0xc6, 0x93, 0x46, 0x83, 0x81, 0x7c, 0xc6, 0x57,
++		    0xf3, 0x31, 0x03, 0x19, 0x49, 0x48, 0x20, 0x05,
++		    0x42, 0x2b, 0x4e, 0xae, 0x8d, 0x1d, 0x43, 0x23 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++{
++	.secret = (u8[32]){ 0x8e, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++	.b_public = (u8[32]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x06 },
++	.expected_ss = (u8[32]){ 0x5a, 0xdf, 0xaa, 0x25, 0x86, 0x8e, 0x32, 0x3d,
++		    0xae, 0x49, 0x62, 0xc1, 0x01, 0x5c, 0xb3, 0x12,
++		    0xe1, 0xc5, 0xc7, 0x9e, 0x95, 0x3f, 0x03, 0x99,
++		    0xb0, 0xba, 0x16, 0x22, 0xf3, 0xb6, 0xf7, 0x0c },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - normal case */
++{
++	.secret = (u8[32]){ 0x48, 0x52, 0x83, 0x4d, 0x9d, 0x6b, 0x77, 0xda,
++		     0xde, 0xab, 0xaa, 0xf2, 0xe1, 0x1d, 0xca, 0x66,
++		     0xd1, 0x9f, 0xe7, 0x49, 0x93, 0xa7, 0xbe, 0xc3,
++		     0x6c, 0x6e, 0x16, 0xa0, 0x98, 0x3f, 0xea, 0xba },
++	.b_public = (u8[32]){ 0x9c, 0x64, 0x7d, 0x9a, 0xe5, 0x89, 0xb9, 0xf5,
++		    0x8f, 0xdc, 0x3c, 0xa4, 0x94, 0x7e, 0xfb, 0xc9,
++		    0x15, 0xc4, 0xb2, 0xe0, 0x8e, 0x74, 0x4a, 0x0e,
++		    0xdf, 0x46, 0x9d, 0xac, 0x59, 0xc8, 0xf8, 0x5a },
++	.expected_ss = (u8[32]){ 0x87, 0xb7, 0xf2, 0x12, 0xb6, 0x27, 0xf7, 0xa5,
++		    0x4c, 0xa5, 0xe0, 0xbc, 0xda, 0xdd, 0xd5, 0x38,
++		    0x9d, 0x9d, 0xe6, 0x15, 0x6c, 0xdb, 0xcf, 0x8e,
++		    0xbe, 0x14, 0xff, 0xbc, 0xfb, 0x43, 0x65, 0x51 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - public key on twist */
++{
++	.secret = (u8[32]){ 0x58, 0x8c, 0x06, 0x1a, 0x50, 0x80, 0x4a, 0xc4,
++		     0x88, 0xad, 0x77, 0x4a, 0xc7, 0x16, 0xc3, 0xf5,
++		     0xba, 0x71, 0x4b, 0x27, 0x12, 0xe0, 0x48, 0x49,
++		     0x13, 0x79, 0xa5, 0x00, 0x21, 0x19, 0x98, 0xa8 },
++	.b_public = (u8[32]){ 0x63, 0xaa, 0x40, 0xc6, 0xe3, 0x83, 0x46, 0xc5,
++		    0xca, 0xf2, 0x3a, 0x6d, 0xf0, 0xa5, 0xe6, 0xc8,
++		    0x08, 0x89, 0xa0, 0x86, 0x47, 0xe5, 0x51, 0xb3,
++		    0x56, 0x34, 0x49, 0xbe, 0xfc, 0xfc, 0x97, 0x33 },
++	.expected_ss = (u8[32]){ 0xb1, 0xa7, 0x07, 0x51, 0x94, 0x95, 0xff, 0xff,
++		    0xb2, 0x98, 0xff, 0x94, 0x17, 0x16, 0xb0, 0x6d,
++		    0xfa, 0xb8, 0x7c, 0xf8, 0xd9, 0x11, 0x23, 0xfe,
++		    0x2b, 0xe9, 0xa2, 0x33, 0xdd, 0xa2, 0x22, 0x12 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - public key on twist */
++{
++	.secret = (u8[32]){ 0xb0, 0x5b, 0xfd, 0x32, 0xe5, 0x53, 0x25, 0xd9,
++		     0xfd, 0x64, 0x8c, 0xb3, 0x02, 0x84, 0x80, 0x39,
++		     0x00, 0x0b, 0x39, 0x0e, 0x44, 0xd5, 0x21, 0xe5,
++		     0x8a, 0xab, 0x3b, 0x29, 0xa6, 0x96, 0x0b, 0xa8 },
++	.b_public = (u8[32]){ 0x0f, 0x83, 0xc3, 0x6f, 0xde, 0xd9, 0xd3, 0x2f,
++		    0xad, 0xf4, 0xef, 0xa3, 0xae, 0x93, 0xa9, 0x0b,
++		    0xb5, 0xcf, 0xa6, 0x68, 0x93, 0xbc, 0x41, 0x2c,
++		    0x43, 0xfa, 0x72, 0x87, 0xdb, 0xb9, 0x97, 0x79 },
++	.expected_ss = (u8[32]){ 0x67, 0xdd, 0x4a, 0x6e, 0x16, 0x55, 0x33, 0x53,
++		    0x4c, 0x0e, 0x3f, 0x17, 0x2e, 0x4a, 0xb8, 0x57,
++		    0x6b, 0xca, 0x92, 0x3a, 0x5f, 0x07, 0xb2, 0xc0,
++		    0x69, 0xb4, 0xc3, 0x10, 0xff, 0x2e, 0x93, 0x5b },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - public key on twist */
++{
++	.secret = (u8[32]){ 0x70, 0xe3, 0x4b, 0xcb, 0xe1, 0xf4, 0x7f, 0xbc,
++		     0x0f, 0xdd, 0xfd, 0x7c, 0x1e, 0x1a, 0xa5, 0x3d,
++		     0x57, 0xbf, 0xe0, 0xf6, 0x6d, 0x24, 0x30, 0x67,
++		     0xb4, 0x24, 0xbb, 0x62, 0x10, 0xbe, 0xd1, 0x9c },
++	.b_public = (u8[32]){ 0x0b, 0x82, 0x11, 0xa2, 0xb6, 0x04, 0x90, 0x97,
++		    0xf6, 0x87, 0x1c, 0x6c, 0x05, 0x2d, 0x3c, 0x5f,
++		    0xc1, 0xba, 0x17, 0xda, 0x9e, 0x32, 0xae, 0x45,
++		    0x84, 0x03, 0xb0, 0x5b, 0xb2, 0x83, 0x09, 0x2a },
++	.expected_ss = (u8[32]){ 0x4a, 0x06, 0x38, 0xcf, 0xaa, 0x9e, 0xf1, 0x93,
++		    0x3b, 0x47, 0xf8, 0x93, 0x92, 0x96, 0xa6, 0xb2,
++		    0x5b, 0xe5, 0x41, 0xef, 0x7f, 0x70, 0xe8, 0x44,
++		    0xc0, 0xbc, 0xc0, 0x0b, 0x13, 0x4d, 0xe6, 0x4a },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - public key on twist */
++{
++	.secret = (u8[32]){ 0x68, 0xc1, 0xf3, 0xa6, 0x53, 0xa4, 0xcd, 0xb1,
++		     0xd3, 0x7b, 0xba, 0x94, 0x73, 0x8f, 0x8b, 0x95,
++		     0x7a, 0x57, 0xbe, 0xb2, 0x4d, 0x64, 0x6e, 0x99,
++		     0x4d, 0xc2, 0x9a, 0x27, 0x6a, 0xad, 0x45, 0x8d },
++	.b_public = (u8[32]){ 0x34, 0x3a, 0xc2, 0x0a, 0x3b, 0x9c, 0x6a, 0x27,
++		    0xb1, 0x00, 0x81, 0x76, 0x50, 0x9a, 0xd3, 0x07,
++		    0x35, 0x85, 0x6e, 0xc1, 0xc8, 0xd8, 0xfc, 0xae,
++		    0x13, 0x91, 0x2d, 0x08, 0xd1, 0x52, 0xf4, 0x6c },
++	.expected_ss = (u8[32]){ 0x39, 0x94, 0x91, 0xfc, 0xe8, 0xdf, 0xab, 0x73,
++		    0xb4, 0xf9, 0xf6, 0x11, 0xde, 0x8e, 0xa0, 0xb2,
++		    0x7b, 0x28, 0xf8, 0x59, 0x94, 0x25, 0x0b, 0x0f,
++		    0x47, 0x5d, 0x58, 0x5d, 0x04, 0x2a, 0xc2, 0x07 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - public key on twist */
++{
++	.secret = (u8[32]){ 0xd8, 0x77, 0xb2, 0x6d, 0x06, 0xdf, 0xf9, 0xd9,
++		     0xf7, 0xfd, 0x4c, 0x5b, 0x37, 0x69, 0xf8, 0xcd,
++		     0xd5, 0xb3, 0x05, 0x16, 0xa5, 0xab, 0x80, 0x6b,
++		     0xe3, 0x24, 0xff, 0x3e, 0xb6, 0x9e, 0xa0, 0xb2 },
++	.b_public = (u8[32]){ 0xfa, 0x69, 0x5f, 0xc7, 0xbe, 0x8d, 0x1b, 0xe5,
++		    0xbf, 0x70, 0x48, 0x98, 0xf3, 0x88, 0xc4, 0x52,
++		    0xba, 0xfd, 0xd3, 0xb8, 0xea, 0xe8, 0x05, 0xf8,
++		    0x68, 0x1a, 0x8d, 0x15, 0xc2, 0xd4, 0xe1, 0x42 },
++	.expected_ss = (u8[32]){ 0x2c, 0x4f, 0xe1, 0x1d, 0x49, 0x0a, 0x53, 0x86,
++		    0x17, 0x76, 0xb1, 0x3b, 0x43, 0x54, 0xab, 0xd4,
++		    0xcf, 0x5a, 0x97, 0x69, 0x9d, 0xb6, 0xe6, 0xc6,
++		    0x8c, 0x16, 0x26, 0xd0, 0x76, 0x62, 0xf7, 0x58 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case on twist */
++{
++	.secret = (u8[32]){ 0x38, 0xdd, 0xe9, 0xf3, 0xe7, 0xb7, 0x99, 0x04,
++		     0x5f, 0x9a, 0xc3, 0x79, 0x3d, 0x4a, 0x92, 0x77,
++		     0xda, 0xde, 0xad, 0xc4, 0x1b, 0xec, 0x02, 0x90,
++		     0xf8, 0x1f, 0x74, 0x4f, 0x73, 0x77, 0x5f, 0x84 },
++	.b_public = (u8[32]){ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++	.expected_ss = (u8[32]){ 0x9a, 0x2c, 0xfe, 0x84, 0xff, 0x9c, 0x4a, 0x97,
++		    0x39, 0x62, 0x5c, 0xae, 0x4a, 0x3b, 0x82, 0xa9,
++		    0x06, 0x87, 0x7a, 0x44, 0x19, 0x46, 0xf8, 0xd7,
++		    0xb3, 0xd7, 0x95, 0xfe, 0x8f, 0x5d, 0x16, 0x39 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case on twist */
++{
++	.secret = (u8[32]){ 0x98, 0x57, 0xa9, 0x14, 0xe3, 0xc2, 0x90, 0x36,
++		     0xfd, 0x9a, 0x44, 0x2b, 0xa5, 0x26, 0xb5, 0xcd,
++		     0xcd, 0xf2, 0x82, 0x16, 0x15, 0x3e, 0x63, 0x6c,
++		     0x10, 0x67, 0x7a, 0xca, 0xb6, 0xbd, 0x6a, 0xa5 },
++	.b_public = (u8[32]){ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++	.expected_ss = (u8[32]){ 0x4d, 0xa4, 0xe0, 0xaa, 0x07, 0x2c, 0x23, 0x2e,
++		    0xe2, 0xf0, 0xfa, 0x4e, 0x51, 0x9a, 0xe5, 0x0b,
++		    0x52, 0xc1, 0xed, 0xd0, 0x8a, 0x53, 0x4d, 0x4e,
++		    0xf3, 0x46, 0xc2, 0xe1, 0x06, 0xd2, 0x1d, 0x60 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case on twist */
++{
++	.secret = (u8[32]){ 0x48, 0xe2, 0x13, 0x0d, 0x72, 0x33, 0x05, 0xed,
++		     0x05, 0xe6, 0xe5, 0x89, 0x4d, 0x39, 0x8a, 0x5e,
++		     0x33, 0x36, 0x7a, 0x8c, 0x6a, 0xac, 0x8f, 0xcd,
++		     0xf0, 0xa8, 0x8e, 0x4b, 0x42, 0x82, 0x0d, 0xb7 },
++	.b_public = (u8[32]){ 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0xf8, 0xff,
++		    0xff, 0x1f, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
++		    0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x07, 0x00,
++		    0x00, 0xf0, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00 },
++	.expected_ss = (u8[32]){ 0x9e, 0xd1, 0x0c, 0x53, 0x74, 0x7f, 0x64, 0x7f,
++		    0x82, 0xf4, 0x51, 0x25, 0xd3, 0xde, 0x15, 0xa1,
++		    0xe6, 0xb8, 0x24, 0x49, 0x6a, 0xb4, 0x04, 0x10,
++		    0xff, 0xcc, 0x3c, 0xfe, 0x95, 0x76, 0x0f, 0x3b },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case on twist */
++{
++	.secret = (u8[32]){ 0x28, 0xf4, 0x10, 0x11, 0x69, 0x18, 0x51, 0xb3,
++		     0xa6, 0x2b, 0x64, 0x15, 0x53, 0xb3, 0x0d, 0x0d,
++		     0xfd, 0xdc, 0xb8, 0xff, 0xfc, 0xf5, 0x37, 0x00,
++		     0xa7, 0xbe, 0x2f, 0x6a, 0x87, 0x2e, 0x9f, 0xb0 },
++	.b_public = (u8[32]){ 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x07, 0x00,
++		    0x00, 0xe0, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00,
++		    0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0xf8, 0xff,
++		    0xff, 0x0f, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x7f },
++	.expected_ss = (u8[32]){ 0xcf, 0x72, 0xb4, 0xaa, 0x6a, 0xa1, 0xc9, 0xf8,
++		    0x94, 0xf4, 0x16, 0x5b, 0x86, 0x10, 0x9a, 0xa4,
++		    0x68, 0x51, 0x76, 0x48, 0xe1, 0xf0, 0xcc, 0x70,
++		    0xe1, 0xab, 0x08, 0x46, 0x01, 0x76, 0x50, 0x6b },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case on twist */
++{
++	.secret = (u8[32]){ 0x18, 0xa9, 0x3b, 0x64, 0x99, 0xb9, 0xf6, 0xb3,
++		     0x22, 0x5c, 0xa0, 0x2f, 0xef, 0x41, 0x0e, 0x0a,
++		     0xde, 0xc2, 0x35, 0x32, 0x32, 0x1d, 0x2d, 0x8e,
++		     0xf1, 0xa6, 0xd6, 0x02, 0xa8, 0xc6, 0x5b, 0x83 },
++	.b_public = (u8[32]){ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++		    0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++		    0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++		    0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x7f },
++	.expected_ss = (u8[32]){ 0x5d, 0x50, 0xb6, 0x28, 0x36, 0xbb, 0x69, 0x57,
++		    0x94, 0x10, 0x38, 0x6c, 0xf7, 0xbb, 0x81, 0x1c,
++		    0x14, 0xbf, 0x85, 0xb1, 0xc7, 0xb1, 0x7e, 0x59,
++		    0x24, 0xc7, 0xff, 0xea, 0x91, 0xef, 0x9e, 0x12 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case on twist */
++{
++	.secret = (u8[32]){ 0xc0, 0x1d, 0x13, 0x05, 0xa1, 0x33, 0x8a, 0x1f,
++		     0xca, 0xc2, 0xba, 0x7e, 0x2e, 0x03, 0x2b, 0x42,
++		     0x7e, 0x0b, 0x04, 0x90, 0x31, 0x65, 0xac, 0xa9,
++		     0x57, 0xd8, 0xd0, 0x55, 0x3d, 0x87, 0x17, 0xb0 },
++	.b_public = (u8[32]){ 0xea, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++	.expected_ss = (u8[32]){ 0x19, 0x23, 0x0e, 0xb1, 0x48, 0xd5, 0xd6, 0x7c,
++		    0x3c, 0x22, 0xab, 0x1d, 0xae, 0xff, 0x80, 0xa5,
++		    0x7e, 0xae, 0x42, 0x65, 0xce, 0x28, 0x72, 0x65,
++		    0x7b, 0x2c, 0x80, 0x99, 0xfc, 0x69, 0x8e, 0x50 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case for public key */
++{
++	.secret = (u8[32]){ 0x38, 0x6f, 0x7f, 0x16, 0xc5, 0x07, 0x31, 0xd6,
++		     0x4f, 0x82, 0xe6, 0xa1, 0x70, 0xb1, 0x42, 0xa4,
++		     0xe3, 0x4f, 0x31, 0xfd, 0x77, 0x68, 0xfc, 0xb8,
++		     0x90, 0x29, 0x25, 0xe7, 0xd1, 0xe2, 0x1a, 0xbe },
++	.b_public = (u8[32]){ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++	.expected_ss = (u8[32]){ 0x0f, 0xca, 0xb5, 0xd8, 0x42, 0xa0, 0x78, 0xd7,
++		    0xa7, 0x1f, 0xc5, 0x9b, 0x57, 0xbf, 0xb4, 0xca,
++		    0x0b, 0xe6, 0x87, 0x3b, 0x49, 0xdc, 0xdb, 0x9f,
++		    0x44, 0xe1, 0x4a, 0xe8, 0xfb, 0xdf, 0xa5, 0x42 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case for public key */
++{
++	.secret = (u8[32]){ 0xe0, 0x23, 0xa2, 0x89, 0xbd, 0x5e, 0x90, 0xfa,
++		     0x28, 0x04, 0xdd, 0xc0, 0x19, 0xa0, 0x5e, 0xf3,
++		     0xe7, 0x9d, 0x43, 0x4b, 0xb6, 0xea, 0x2f, 0x52,
++		     0x2e, 0xcb, 0x64, 0x3a, 0x75, 0x29, 0x6e, 0x95 },
++	.b_public = (u8[32]){ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++		    0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++		    0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++		    0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 },
++	.expected_ss = (u8[32]){ 0x54, 0xce, 0x8f, 0x22, 0x75, 0xc0, 0x77, 0xe3,
++		    0xb1, 0x30, 0x6a, 0x39, 0x39, 0xc5, 0xe0, 0x3e,
++		    0xef, 0x6b, 0xbb, 0x88, 0x06, 0x05, 0x44, 0x75,
++		    0x8d, 0x9f, 0xef, 0x59, 0xb0, 0xbc, 0x3e, 0x4f },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case for public key */
++{
++	.secret = (u8[32]){ 0x68, 0xf0, 0x10, 0xd6, 0x2e, 0xe8, 0xd9, 0x26,
++		     0x05, 0x3a, 0x36, 0x1c, 0x3a, 0x75, 0xc6, 0xea,
++		     0x4e, 0xbd, 0xc8, 0x60, 0x6a, 0xb2, 0x85, 0x00,
++		     0x3a, 0x6f, 0x8f, 0x40, 0x76, 0xb0, 0x1e, 0x83 },
++	.b_public = (u8[32]){ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03 },
++	.expected_ss = (u8[32]){ 0xf1, 0x36, 0x77, 0x5c, 0x5b, 0xeb, 0x0a, 0xf8,
++		    0x11, 0x0a, 0xf1, 0x0b, 0x20, 0x37, 0x23, 0x32,
++		    0x04, 0x3c, 0xab, 0x75, 0x24, 0x19, 0x67, 0x87,
++		    0x75, 0xa2, 0x23, 0xdf, 0x57, 0xc9, 0xd3, 0x0d },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case for public key */
++{
++	.secret = (u8[32]){ 0x58, 0xeb, 0xcb, 0x35, 0xb0, 0xf8, 0x84, 0x5c,
++		     0xaf, 0x1e, 0xc6, 0x30, 0xf9, 0x65, 0x76, 0xb6,
++		     0x2c, 0x4b, 0x7b, 0x6c, 0x36, 0xb2, 0x9d, 0xeb,
++		     0x2c, 0xb0, 0x08, 0x46, 0x51, 0x75, 0x5c, 0x96 },
++	.b_public = (u8[32]){ 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xfb, 0xff,
++		    0xff, 0xdf, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff,
++		    0xfe, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xf7, 0xff,
++		    0xff, 0xf7, 0xff, 0xff, 0xbf, 0xff, 0xff, 0x3f },
++	.expected_ss = (u8[32]){ 0xbf, 0x9a, 0xff, 0xd0, 0x6b, 0x84, 0x40, 0x85,
++		    0x58, 0x64, 0x60, 0x96, 0x2e, 0xf2, 0x14, 0x6f,
++		    0xf3, 0xd4, 0x53, 0x3d, 0x94, 0x44, 0xaa, 0xb0,
++		    0x06, 0xeb, 0x88, 0xcc, 0x30, 0x54, 0x40, 0x7d },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case for public key */
++{
++	.secret = (u8[32]){ 0x18, 0x8c, 0x4b, 0xc5, 0xb9, 0xc4, 0x4b, 0x38,
++		     0xbb, 0x65, 0x8b, 0x9b, 0x2a, 0xe8, 0x2d, 0x5b,
++		     0x01, 0x01, 0x5e, 0x09, 0x31, 0x84, 0xb1, 0x7c,
++		     0xb7, 0x86, 0x35, 0x03, 0xa7, 0x83, 0xe1, 0xbb },
++	.b_public = (u8[32]){ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f },
++	.expected_ss = (u8[32]){ 0xd4, 0x80, 0xde, 0x04, 0xf6, 0x99, 0xcb, 0x3b,
++		    0xe0, 0x68, 0x4a, 0x9c, 0xc2, 0xe3, 0x12, 0x81,
++		    0xea, 0x0b, 0xc5, 0xa9, 0xdc, 0xc1, 0x57, 0xd3,
++		    0xd2, 0x01, 0x58, 0xd4, 0x6c, 0xa5, 0x24, 0x6d },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case for public key */
++{
++	.secret = (u8[32]){ 0xe0, 0x6c, 0x11, 0xbb, 0x2e, 0x13, 0xce, 0x3d,
++		     0xc7, 0x67, 0x3f, 0x67, 0xf5, 0x48, 0x22, 0x42,
++		     0x90, 0x94, 0x23, 0xa9, 0xae, 0x95, 0xee, 0x98,
++		     0x6a, 0x98, 0x8d, 0x98, 0xfa, 0xee, 0x23, 0xa2 },
++	.b_public = (u8[32]){ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f,
++		    0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f,
++		    0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f,
++		    0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f },
++	.expected_ss = (u8[32]){ 0x4c, 0x44, 0x01, 0xcc, 0xe6, 0xb5, 0x1e, 0x4c,
++		    0xb1, 0x8f, 0x27, 0x90, 0x24, 0x6c, 0x9b, 0xf9,
++		    0x14, 0xdb, 0x66, 0x77, 0x50, 0xa1, 0xcb, 0x89,
++		    0x06, 0x90, 0x92, 0xaf, 0x07, 0x29, 0x22, 0x76 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case for public key */
++{
++	.secret = (u8[32]){ 0xc0, 0x65, 0x8c, 0x46, 0xdd, 0xe1, 0x81, 0x29,
++		     0x29, 0x38, 0x77, 0x53, 0x5b, 0x11, 0x62, 0xb6,
++		     0xf9, 0xf5, 0x41, 0x4a, 0x23, 0xcf, 0x4d, 0x2c,
++		     0xbc, 0x14, 0x0a, 0x4d, 0x99, 0xda, 0x2b, 0x8f },
++	.b_public = (u8[32]){ 0xeb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++	.expected_ss = (u8[32]){ 0x57, 0x8b, 0xa8, 0xcc, 0x2d, 0xbd, 0xc5, 0x75,
++		    0xaf, 0xcf, 0x9d, 0xf2, 0xb3, 0xee, 0x61, 0x89,
++		    0xf5, 0x33, 0x7d, 0x68, 0x54, 0xc7, 0x9b, 0x4c,
++		    0xe1, 0x65, 0xea, 0x12, 0x29, 0x3b, 0x3a, 0x0f },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - public key >= p */
++{
++	.secret = (u8[32]){ 0xf0, 0x1e, 0x48, 0xda, 0xfa, 0xc9, 0xd7, 0xbc,
++		     0xf5, 0x89, 0xcb, 0xc3, 0x82, 0xc8, 0x78, 0xd1,
++		     0x8b, 0xda, 0x35, 0x50, 0x58, 0x9f, 0xfb, 0x5d,
++		     0x50, 0xb5, 0x23, 0xbe, 0xbe, 0x32, 0x9d, 0xae },
++	.b_public = (u8[32]){ 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++	.expected_ss = (u8[32]){ 0xbd, 0x36, 0xa0, 0x79, 0x0e, 0xb8, 0x83, 0x09,
++		    0x8c, 0x98, 0x8b, 0x21, 0x78, 0x67, 0x73, 0xde,
++		    0x0b, 0x3a, 0x4d, 0xf1, 0x62, 0x28, 0x2c, 0xf1,
++		    0x10, 0xde, 0x18, 0xdd, 0x48, 0x4c, 0xe7, 0x4b },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - public key >= p */
++{
++	.secret = (u8[32]){ 0x28, 0x87, 0x96, 0xbc, 0x5a, 0xff, 0x4b, 0x81,
++		     0xa3, 0x75, 0x01, 0x75, 0x7b, 0xc0, 0x75, 0x3a,
++		     0x3c, 0x21, 0x96, 0x47, 0x90, 0xd3, 0x86, 0x99,
++		     0x30, 0x8d, 0xeb, 0xc1, 0x7a, 0x6e, 0xaf, 0x8d },
++	.b_public = (u8[32]){ 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++	.expected_ss = (u8[32]){ 0xb4, 0xe0, 0xdd, 0x76, 0xda, 0x7b, 0x07, 0x17,
++		    0x28, 0xb6, 0x1f, 0x85, 0x67, 0x71, 0xaa, 0x35,
++		    0x6e, 0x57, 0xed, 0xa7, 0x8a, 0x5b, 0x16, 0x55,
++		    0xcc, 0x38, 0x20, 0xfb, 0x5f, 0x85, 0x4c, 0x5c },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - public key >= p */
++{
++	.secret = (u8[32]){ 0x98, 0xdf, 0x84, 0x5f, 0x66, 0x51, 0xbf, 0x11,
++		     0x38, 0x22, 0x1f, 0x11, 0x90, 0x41, 0xf7, 0x2b,
++		     0x6d, 0xbc, 0x3c, 0x4a, 0xce, 0x71, 0x43, 0xd9,
++		     0x9f, 0xd5, 0x5a, 0xd8, 0x67, 0x48, 0x0d, 0xa8 },
++	.b_public = (u8[32]){ 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++	.expected_ss = (u8[32]){ 0x6f, 0xdf, 0x6c, 0x37, 0x61, 0x1d, 0xbd, 0x53,
++		    0x04, 0xdc, 0x0f, 0x2e, 0xb7, 0xc9, 0x51, 0x7e,
++		    0xb3, 0xc5, 0x0e, 0x12, 0xfd, 0x05, 0x0a, 0xc6,
++		    0xde, 0xc2, 0x70, 0x71, 0xd4, 0xbf, 0xc0, 0x34 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - public key >= p */
++{
++	.secret = (u8[32]){ 0xf0, 0x94, 0x98, 0xe4, 0x6f, 0x02, 0xf8, 0x78,
++		     0x82, 0x9e, 0x78, 0xb8, 0x03, 0xd3, 0x16, 0xa2,
++		     0xed, 0x69, 0x5d, 0x04, 0x98, 0xa0, 0x8a, 0xbd,
++		     0xf8, 0x27, 0x69, 0x30, 0xe2, 0x4e, 0xdc, 0xb0 },
++	.b_public = (u8[32]){ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++	.expected_ss = (u8[32]){ 0x4c, 0x8f, 0xc4, 0xb1, 0xc6, 0xab, 0x88, 0xfb,
++		    0x21, 0xf1, 0x8f, 0x6d, 0x4c, 0x81, 0x02, 0x40,
++		    0xd4, 0xe9, 0x46, 0x51, 0xba, 0x44, 0xf7, 0xa2,
++		    0xc8, 0x63, 0xce, 0xc7, 0xdc, 0x56, 0x60, 0x2d },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - public key >= p */
++{
++	.secret = (u8[32]){ 0x18, 0x13, 0xc1, 0x0a, 0x5c, 0x7f, 0x21, 0xf9,
++		     0x6e, 0x17, 0xf2, 0x88, 0xc0, 0xcc, 0x37, 0x60,
++		     0x7c, 0x04, 0xc5, 0xf5, 0xae, 0xa2, 0xdb, 0x13,
++		     0x4f, 0x9e, 0x2f, 0xfc, 0x66, 0xbd, 0x9d, 0xb8 },
++	.b_public = (u8[32]){ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 },
++	.expected_ss = (u8[32]){ 0x1c, 0xd0, 0xb2, 0x82, 0x67, 0xdc, 0x54, 0x1c,
++		    0x64, 0x2d, 0x6d, 0x7d, 0xca, 0x44, 0xa8, 0xb3,
++		    0x8a, 0x63, 0x73, 0x6e, 0xef, 0x5c, 0x4e, 0x65,
++		    0x01, 0xff, 0xbb, 0xb1, 0x78, 0x0c, 0x03, 0x3c },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - public key >= p */
++{
++	.secret = (u8[32]){ 0x78, 0x57, 0xfb, 0x80, 0x86, 0x53, 0x64, 0x5a,
++		     0x0b, 0xeb, 0x13, 0x8a, 0x64, 0xf5, 0xf4, 0xd7,
++		     0x33, 0xa4, 0x5e, 0xa8, 0x4c, 0x3c, 0xda, 0x11,
++		     0xa9, 0xc0, 0x6f, 0x7e, 0x71, 0x39, 0x14, 0x9e },
++	.b_public = (u8[32]){ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 },
++	.expected_ss = (u8[32]){ 0x87, 0x55, 0xbe, 0x01, 0xc6, 0x0a, 0x7e, 0x82,
++		    0x5c, 0xff, 0x3e, 0x0e, 0x78, 0xcb, 0x3a, 0xa4,
++		    0x33, 0x38, 0x61, 0x51, 0x6a, 0xa5, 0x9b, 0x1c,
++		    0x51, 0xa8, 0xb2, 0xa5, 0x43, 0xdf, 0xa8, 0x22 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - public key >= p */
++{
++	.secret = (u8[32]){ 0xe0, 0x3a, 0xa8, 0x42, 0xe2, 0xab, 0xc5, 0x6e,
++		     0x81, 0xe8, 0x7b, 0x8b, 0x9f, 0x41, 0x7b, 0x2a,
++		     0x1e, 0x59, 0x13, 0xc7, 0x23, 0xee, 0xd2, 0x8d,
++		     0x75, 0x2f, 0x8d, 0x47, 0xa5, 0x9f, 0x49, 0x8f },
++	.b_public = (u8[32]){ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 },
++	.expected_ss = (u8[32]){ 0x54, 0xc9, 0xa1, 0xed, 0x95, 0xe5, 0x46, 0xd2,
++		    0x78, 0x22, 0xa3, 0x60, 0x93, 0x1d, 0xda, 0x60,
++		    0xa1, 0xdf, 0x04, 0x9d, 0xa6, 0xf9, 0x04, 0x25,
++		    0x3c, 0x06, 0x12, 0xbb, 0xdc, 0x08, 0x74, 0x76 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - public key >= p */
++{
++	.secret = (u8[32]){ 0xf8, 0xf7, 0x07, 0xb7, 0x99, 0x9b, 0x18, 0xcb,
++		     0x0d, 0x6b, 0x96, 0x12, 0x4f, 0x20, 0x45, 0x97,
++		     0x2c, 0xa2, 0x74, 0xbf, 0xc1, 0x54, 0xad, 0x0c,
++		     0x87, 0x03, 0x8c, 0x24, 0xc6, 0xd0, 0xd4, 0xb2 },
++	.b_public = (u8[32]){ 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++	.expected_ss = (u8[32]){ 0xcc, 0x1f, 0x40, 0xd7, 0x43, 0xcd, 0xc2, 0x23,
++		    0x0e, 0x10, 0x43, 0xda, 0xba, 0x8b, 0x75, 0xe8,
++		    0x10, 0xf1, 0xfb, 0xab, 0x7f, 0x25, 0x52, 0x69,
++		    0xbd, 0x9e, 0xbb, 0x29, 0xe6, 0xbf, 0x49, 0x4f },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - public key >= p */
++{
++	.secret = (u8[32]){ 0xa0, 0x34, 0xf6, 0x84, 0xfa, 0x63, 0x1e, 0x1a,
++		     0x34, 0x81, 0x18, 0xc1, 0xce, 0x4c, 0x98, 0x23,
++		     0x1f, 0x2d, 0x9e, 0xec, 0x9b, 0xa5, 0x36, 0x5b,
++		     0x4a, 0x05, 0xd6, 0x9a, 0x78, 0x5b, 0x07, 0x96 },
++	.b_public = (u8[32]){ 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++	.expected_ss = (u8[32]){ 0x54, 0x99, 0x8e, 0xe4, 0x3a, 0x5b, 0x00, 0x7b,
++		    0xf4, 0x99, 0xf0, 0x78, 0xe7, 0x36, 0x52, 0x44,
++		    0x00, 0xa8, 0xb5, 0xc7, 0xe9, 0xb9, 0xb4, 0x37,
++		    0x71, 0x74, 0x8c, 0x7c, 0xdf, 0x88, 0x04, 0x12 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - public key >= p */
++{
++	.secret = (u8[32]){ 0x30, 0xb6, 0xc6, 0xa0, 0xf2, 0xff, 0xa6, 0x80,
++		     0x76, 0x8f, 0x99, 0x2b, 0xa8, 0x9e, 0x15, 0x2d,
++		     0x5b, 0xc9, 0x89, 0x3d, 0x38, 0xc9, 0x11, 0x9b,
++		     0xe4, 0xf7, 0x67, 0xbf, 0xab, 0x6e, 0x0c, 0xa5 },
++	.b_public = (u8[32]){ 0xdc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++	.expected_ss = (u8[32]){ 0xea, 0xd9, 0xb3, 0x8e, 0xfd, 0xd7, 0x23, 0x63,
++		    0x79, 0x34, 0xe5, 0x5a, 0xb7, 0x17, 0xa7, 0xae,
++		    0x09, 0xeb, 0x86, 0xa2, 0x1d, 0xc3, 0x6a, 0x3f,
++		    0xee, 0xb8, 0x8b, 0x75, 0x9e, 0x39, 0x1e, 0x09 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - public key >= p */
++{
++	.secret = (u8[32]){ 0x90, 0x1b, 0x9d, 0xcf, 0x88, 0x1e, 0x01, 0xe0,
++		     0x27, 0x57, 0x50, 0x35, 0xd4, 0x0b, 0x43, 0xbd,
++		     0xc1, 0xc5, 0x24, 0x2e, 0x03, 0x08, 0x47, 0x49,
++		     0x5b, 0x0c, 0x72, 0x86, 0x46, 0x9b, 0x65, 0x91 },
++	.b_public = (u8[32]){ 0xea, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++	.expected_ss = (u8[32]){ 0x60, 0x2f, 0xf4, 0x07, 0x89, 0xb5, 0x4b, 0x41,
++		    0x80, 0x59, 0x15, 0xfe, 0x2a, 0x62, 0x21, 0xf0,
++		    0x7a, 0x50, 0xff, 0xc2, 0xc3, 0xfc, 0x94, 0xcf,
++		    0x61, 0xf1, 0x3d, 0x79, 0x04, 0xe8, 0x8e, 0x0e },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - public key >= p */
++{
++	.secret = (u8[32]){ 0x80, 0x46, 0x67, 0x7c, 0x28, 0xfd, 0x82, 0xc9,
++		     0xa1, 0xbd, 0xb7, 0x1a, 0x1a, 0x1a, 0x34, 0xfa,
++		     0xba, 0x12, 0x25, 0xe2, 0x50, 0x7f, 0xe3, 0xf5,
++		     0x4d, 0x10, 0xbd, 0x5b, 0x0d, 0x86, 0x5f, 0x8e },
++	.b_public = (u8[32]){ 0xeb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++	.expected_ss = (u8[32]){ 0xe0, 0x0a, 0xe8, 0xb1, 0x43, 0x47, 0x12, 0x47,
++		    0xba, 0x24, 0xf1, 0x2c, 0x88, 0x55, 0x36, 0xc3,
++		    0xcb, 0x98, 0x1b, 0x58, 0xe1, 0xe5, 0x6b, 0x2b,
++		    0xaf, 0x35, 0xc1, 0x2a, 0xe1, 0xf7, 0x9c, 0x26 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - public key >= p */
++{
++	.secret = (u8[32]){ 0x60, 0x2f, 0x7e, 0x2f, 0x68, 0xa8, 0x46, 0xb8,
++		     0x2c, 0xc2, 0x69, 0xb1, 0xd4, 0x8e, 0x93, 0x98,
++		     0x86, 0xae, 0x54, 0xfd, 0x63, 0x6c, 0x1f, 0xe0,
++		     0x74, 0xd7, 0x10, 0x12, 0x7d, 0x47, 0x24, 0x91 },
++	.b_public = (u8[32]){ 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++	.expected_ss = (u8[32]){ 0x98, 0xcb, 0x9b, 0x50, 0xdd, 0x3f, 0xc2, 0xb0,
++		    0xd4, 0xf2, 0xd2, 0xbf, 0x7c, 0x5c, 0xfd, 0xd1,
++		    0x0c, 0x8f, 0xcd, 0x31, 0xfc, 0x40, 0xaf, 0x1a,
++		    0xd4, 0x4f, 0x47, 0xc1, 0x31, 0x37, 0x63, 0x62 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - public key >= p */
++{
++	.secret = (u8[32]){ 0x60, 0x88, 0x7b, 0x3d, 0xc7, 0x24, 0x43, 0x02,
++		     0x6e, 0xbe, 0xdb, 0xbb, 0xb7, 0x06, 0x65, 0xf4,
++		     0x2b, 0x87, 0xad, 0xd1, 0x44, 0x0e, 0x77, 0x68,
++		     0xfb, 0xd7, 0xe8, 0xe2, 0xce, 0x5f, 0x63, 0x9d },
++	.b_public = (u8[32]){ 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++	.expected_ss = (u8[32]){ 0x38, 0xd6, 0x30, 0x4c, 0x4a, 0x7e, 0x6d, 0x9f,
++		    0x79, 0x59, 0x33, 0x4f, 0xb5, 0x24, 0x5b, 0xd2,
++		    0xc7, 0x54, 0x52, 0x5d, 0x4c, 0x91, 0xdb, 0x95,
++		    0x02, 0x06, 0x92, 0x62, 0x34, 0xc1, 0xf6, 0x33 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - public key >= p */
++{
++	.secret = (u8[32]){ 0x78, 0xd3, 0x1d, 0xfa, 0x85, 0x44, 0x97, 0xd7,
++		     0x2d, 0x8d, 0xef, 0x8a, 0x1b, 0x7f, 0xb0, 0x06,
++		     0xce, 0xc2, 0xd8, 0xc4, 0x92, 0x46, 0x47, 0xc9,
++		     0x38, 0x14, 0xae, 0x56, 0xfa, 0xed, 0xa4, 0x95 },
++	.b_public = (u8[32]){ 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++	.expected_ss = (u8[32]){ 0x78, 0x6c, 0xd5, 0x49, 0x96, 0xf0, 0x14, 0xa5,
++		    0xa0, 0x31, 0xec, 0x14, 0xdb, 0x81, 0x2e, 0xd0,
++		    0x83, 0x55, 0x06, 0x1f, 0xdb, 0x5d, 0xe6, 0x80,
++		    0xa8, 0x00, 0xac, 0x52, 0x1f, 0x31, 0x8e, 0x23 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - public key >= p */
++{
++	.secret = (u8[32]){ 0xc0, 0x4c, 0x5b, 0xae, 0xfa, 0x83, 0x02, 0xdd,
++		     0xde, 0xd6, 0xa4, 0xbb, 0x95, 0x77, 0x61, 0xb4,
++		     0xeb, 0x97, 0xae, 0xfa, 0x4f, 0xc3, 0xb8, 0x04,
++		     0x30, 0x85, 0xf9, 0x6a, 0x56, 0x59, 0xb3, 0xa5 },
++	.b_public = (u8[32]){ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++	.expected_ss = (u8[32]){ 0x29, 0xae, 0x8b, 0xc7, 0x3e, 0x9b, 0x10, 0xa0,
++		    0x8b, 0x4f, 0x68, 0x1c, 0x43, 0xc3, 0xe0, 0xac,
++		    0x1a, 0x17, 0x1d, 0x31, 0xb3, 0x8f, 0x1a, 0x48,
++		    0xef, 0xba, 0x29, 0xae, 0x63, 0x9e, 0xa1, 0x34 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - RFC 7748 */
++{
++	.secret = (u8[32]){ 0xa0, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d,
++		     0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd,
++		     0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18,
++		     0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0x44 },
++	.b_public = (u8[32]){ 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb,
++		    0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, 0x5f, 0x7c,
++		    0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b,
++		    0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c },
++	.expected_ss = (u8[32]){ 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90,
++		    0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, 0x08, 0x4f,
++		    0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7,
++		    0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - RFC 7748 */
++{
++	.secret = (u8[32]){ 0x48, 0x66, 0xe9, 0xd4, 0xd1, 0xb4, 0x67, 0x3c,
++		     0x5a, 0xd2, 0x26, 0x91, 0x95, 0x7d, 0x6a, 0xf5,
++		     0xc1, 0x1b, 0x64, 0x21, 0xe0, 0xea, 0x01, 0xd4,
++		     0x2c, 0xa4, 0x16, 0x9e, 0x79, 0x18, 0xba, 0x4d },
++	.b_public = (u8[32]){ 0xe5, 0x21, 0x0f, 0x12, 0x78, 0x68, 0x11, 0xd3,
++		    0xf4, 0xb7, 0x95, 0x9d, 0x05, 0x38, 0xae, 0x2c,
++		    0x31, 0xdb, 0xe7, 0x10, 0x6f, 0xc0, 0x3c, 0x3e,
++		    0xfc, 0x4c, 0xd5, 0x49, 0xc7, 0x15, 0xa4, 0x13 },
++	.expected_ss = (u8[32]){ 0x95, 0xcb, 0xde, 0x94, 0x76, 0xe8, 0x90, 0x7d,
++		    0x7a, 0xad, 0xe4, 0x5c, 0xb4, 0xb8, 0x73, 0xf8,
++		    0x8b, 0x59, 0x5a, 0x68, 0x79, 0x9f, 0xa1, 0x52,
++		    0xe6, 0xf8, 0xf7, 0x64, 0x7a, 0xac, 0x79, 0x57 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case for shared secret */
++{
++	.secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++		     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++		     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++		     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++	.b_public = (u8[32]){ 0x0a, 0xb4, 0xe7, 0x63, 0x80, 0xd8, 0x4d, 0xde,
++		    0x4f, 0x68, 0x33, 0xc5, 0x8f, 0x2a, 0x9f, 0xb8,
++		    0xf8, 0x3b, 0xb0, 0x16, 0x9b, 0x17, 0x2b, 0xe4,
++		    0xb6, 0xe0, 0x59, 0x28, 0x87, 0x74, 0x1a, 0x36 },
++	.expected_ss = (u8[32]){ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case for shared secret */
++{
++	.secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++		     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++		     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++		     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++	.b_public = (u8[32]){ 0x89, 0xe1, 0x0d, 0x57, 0x01, 0xb4, 0x33, 0x7d,
++		    0x2d, 0x03, 0x21, 0x81, 0x53, 0x8b, 0x10, 0x64,
++		    0xbd, 0x40, 0x84, 0x40, 0x1c, 0xec, 0xa1, 0xfd,
++		    0x12, 0x66, 0x3a, 0x19, 0x59, 0x38, 0x80, 0x00 },
++	.expected_ss = (u8[32]){ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case for shared secret */
++{
++	.secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++		     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++		     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++		     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++	.b_public = (u8[32]){ 0x2b, 0x55, 0xd3, 0xaa, 0x4a, 0x8f, 0x80, 0xc8,
++		    0xc0, 0xb2, 0xae, 0x5f, 0x93, 0x3e, 0x85, 0xaf,
++		    0x49, 0xbe, 0xac, 0x36, 0xc2, 0xfa, 0x73, 0x94,
++		    0xba, 0xb7, 0x6c, 0x89, 0x33, 0xf8, 0xf8, 0x1d },
++	.expected_ss = (u8[32]){ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case for shared secret */
++{
++	.secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++		     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++		     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++		     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++	.b_public = (u8[32]){ 0x63, 0xe5, 0xb1, 0xfe, 0x96, 0x01, 0xfe, 0x84,
++		    0x38, 0x5d, 0x88, 0x66, 0xb0, 0x42, 0x12, 0x62,
++		    0xf7, 0x8f, 0xbf, 0xa5, 0xaf, 0xf9, 0x58, 0x5e,
++		    0x62, 0x66, 0x79, 0xb1, 0x85, 0x47, 0xd9, 0x59 },
++	.expected_ss = (u8[32]){ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case for shared secret */
++{
++	.secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++		     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++		     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++		     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++	.b_public = (u8[32]){ 0xe4, 0x28, 0xf3, 0xda, 0xc1, 0x78, 0x09, 0xf8,
++		    0x27, 0xa5, 0x22, 0xce, 0x32, 0x35, 0x50, 0x58,
++		    0xd0, 0x73, 0x69, 0x36, 0x4a, 0xa7, 0x89, 0x02,
++		    0xee, 0x10, 0x13, 0x9b, 0x9f, 0x9d, 0xd6, 0x53 },
++	.expected_ss = (u8[32]){ 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case for shared secret */
++{
++	.secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++		     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++		     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++		     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++	.b_public = (u8[32]){ 0xb3, 0xb5, 0x0e, 0x3e, 0xd3, 0xa4, 0x07, 0xb9,
++		    0x5d, 0xe9, 0x42, 0xef, 0x74, 0x57, 0x5b, 0x5a,
++		    0xb8, 0xa1, 0x0c, 0x09, 0xee, 0x10, 0x35, 0x44,
++		    0xd6, 0x0b, 0xdf, 0xed, 0x81, 0x38, 0xab, 0x2b },
++	.expected_ss = (u8[32]){ 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case for shared secret */
++{
++	.secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++		     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++		     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++		     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++	.b_public = (u8[32]){ 0x21, 0x3f, 0xff, 0xe9, 0x3d, 0x5e, 0xa8, 0xcd,
++		    0x24, 0x2e, 0x46, 0x28, 0x44, 0x02, 0x99, 0x22,
++		    0xc4, 0x3c, 0x77, 0xc9, 0xe3, 0xe4, 0x2f, 0x56,
++		    0x2f, 0x48, 0x5d, 0x24, 0xc5, 0x01, 0xa2, 0x0b },
++	.expected_ss = (u8[32]){ 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case for shared secret */
++{
++	.secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++		     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++		     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++		     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++	.b_public = (u8[32]){ 0x91, 0xb2, 0x32, 0xa1, 0x78, 0xb3, 0xcd, 0x53,
++		    0x09, 0x32, 0x44, 0x1e, 0x61, 0x39, 0x41, 0x8f,
++		    0x72, 0x17, 0x22, 0x92, 0xf1, 0xda, 0x4c, 0x18,
++		    0x34, 0xfc, 0x5e, 0xbf, 0xef, 0xb5, 0x1e, 0x3f },
++	.expected_ss = (u8[32]){ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case for shared secret */
++{
++	.secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++		     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++		     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++		     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++	.b_public = (u8[32]){ 0x04, 0x5c, 0x6e, 0x11, 0xc5, 0xd3, 0x32, 0x55,
++		    0x6c, 0x78, 0x22, 0xfe, 0x94, 0xeb, 0xf8, 0x9b,
++		    0x56, 0xa3, 0x87, 0x8d, 0xc2, 0x7c, 0xa0, 0x79,
++		    0x10, 0x30, 0x58, 0x84, 0x9f, 0xab, 0xcb, 0x4f },
++	.expected_ss = (u8[32]){ 0xe5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case for shared secret */
++{
++	.secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++		     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++		     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++		     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++	.b_public = (u8[32]){ 0x1c, 0xa2, 0x19, 0x0b, 0x71, 0x16, 0x35, 0x39,
++		    0x06, 0x3c, 0x35, 0x77, 0x3b, 0xda, 0x0c, 0x9c,
++		    0x92, 0x8e, 0x91, 0x36, 0xf0, 0x62, 0x0a, 0xeb,
++		    0x09, 0x3f, 0x09, 0x91, 0x97, 0xb7, 0xf7, 0x4e },
++	.expected_ss = (u8[32]){ 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case for shared secret */
++{
++	.secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++		     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++		     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++		     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++	.b_public = (u8[32]){ 0xf7, 0x6e, 0x90, 0x10, 0xac, 0x33, 0xc5, 0x04,
++		    0x3b, 0x2d, 0x3b, 0x76, 0xa8, 0x42, 0x17, 0x10,
++		    0x00, 0xc4, 0x91, 0x62, 0x22, 0xe9, 0xe8, 0x58,
++		    0x97, 0xa0, 0xae, 0xc7, 0xf6, 0x35, 0x0b, 0x3c },
++	.expected_ss = (u8[32]){ 0xdd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case for shared secret */
++{
++	.secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++		     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++		     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++		     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++	.b_public = (u8[32]){ 0xbb, 0x72, 0x68, 0x8d, 0x8f, 0x8a, 0xa7, 0xa3,
++		    0x9c, 0xd6, 0x06, 0x0c, 0xd5, 0xc8, 0x09, 0x3c,
++		    0xde, 0xc6, 0xfe, 0x34, 0x19, 0x37, 0xc3, 0x88,
++		    0x6a, 0x99, 0x34, 0x6c, 0xd0, 0x7f, 0xaa, 0x55 },
++	.expected_ss = (u8[32]){ 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case for shared secret */
++{
++	.secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++		     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++		     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++		     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++	.b_public = (u8[32]){ 0x88, 0xfd, 0xde, 0xa1, 0x93, 0x39, 0x1c, 0x6a,
++		    0x59, 0x33, 0xef, 0x9b, 0x71, 0x90, 0x15, 0x49,
++		    0x44, 0x72, 0x05, 0xaa, 0xe9, 0xda, 0x92, 0x8a,
++		    0x6b, 0x91, 0xa3, 0x52, 0xba, 0x10, 0xf4, 0x1f },
++	.expected_ss = (u8[32]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - edge case for shared secret */
++{
++	.secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++		     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++		     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++		     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++	.b_public = (u8[32]){ 0x30, 0x3b, 0x39, 0x2f, 0x15, 0x31, 0x16, 0xca,
++		    0xd9, 0xcc, 0x68, 0x2a, 0x00, 0xcc, 0xc4, 0x4c,
++		    0x95, 0xff, 0x0d, 0x3b, 0xbe, 0x56, 0x8b, 0xeb,
++		    0x6c, 0x4e, 0x73, 0x9b, 0xaf, 0xdc, 0x2c, 0x68 },
++	.expected_ss = (u8[32]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - checking for overflow */
++{
++	.secret = (u8[32]){ 0xc8, 0x17, 0x24, 0x70, 0x40, 0x00, 0xb2, 0x6d,
++		     0x31, 0x70, 0x3c, 0xc9, 0x7e, 0x3a, 0x37, 0x8d,
++		     0x56, 0xfa, 0xd8, 0x21, 0x93, 0x61, 0xc8, 0x8c,
++		     0xca, 0x8b, 0xd7, 0xc5, 0x71, 0x9b, 0x12, 0xb2 },
++	.b_public = (u8[32]){ 0xfd, 0x30, 0x0a, 0xeb, 0x40, 0xe1, 0xfa, 0x58,
++		    0x25, 0x18, 0x41, 0x2b, 0x49, 0xb2, 0x08, 0xa7,
++		    0x84, 0x2b, 0x1e, 0x1f, 0x05, 0x6a, 0x04, 0x01,
++		    0x78, 0xea, 0x41, 0x41, 0x53, 0x4f, 0x65, 0x2d },
++	.expected_ss = (u8[32]){ 0xb7, 0x34, 0x10, 0x5d, 0xc2, 0x57, 0x58, 0x5d,
++		    0x73, 0xb5, 0x66, 0xcc, 0xb7, 0x6f, 0x06, 0x27,
++		    0x95, 0xcc, 0xbe, 0xc8, 0x91, 0x28, 0xe5, 0x2b,
++		    0x02, 0xf3, 0xe5, 0x96, 0x39, 0xf1, 0x3c, 0x46 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - checking for overflow */
++{
++	.secret = (u8[32]){ 0xc8, 0x17, 0x24, 0x70, 0x40, 0x00, 0xb2, 0x6d,
++		     0x31, 0x70, 0x3c, 0xc9, 0x7e, 0x3a, 0x37, 0x8d,
++		     0x56, 0xfa, 0xd8, 0x21, 0x93, 0x61, 0xc8, 0x8c,
++		     0xca, 0x8b, 0xd7, 0xc5, 0x71, 0x9b, 0x12, 0xb2 },
++	.b_public = (u8[32]){ 0xc8, 0xef, 0x79, 0xb5, 0x14, 0xd7, 0x68, 0x26,
++		    0x77, 0xbc, 0x79, 0x31, 0xe0, 0x6e, 0xe5, 0xc2,
++		    0x7c, 0x9b, 0x39, 0x2b, 0x4a, 0xe9, 0x48, 0x44,
++		    0x73, 0xf5, 0x54, 0xe6, 0x67, 0x8e, 0xcc, 0x2e },
++	.expected_ss = (u8[32]){ 0x64, 0x7a, 0x46, 0xb6, 0xfc, 0x3f, 0x40, 0xd6,
++		    0x21, 0x41, 0xee, 0x3c, 0xee, 0x70, 0x6b, 0x4d,
++		    0x7a, 0x92, 0x71, 0x59, 0x3a, 0x7b, 0x14, 0x3e,
++		    0x8e, 0x2e, 0x22, 0x79, 0x88, 0x3e, 0x45, 0x50 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - checking for overflow */
++{
++	.secret = (u8[32]){ 0xc8, 0x17, 0x24, 0x70, 0x40, 0x00, 0xb2, 0x6d,
++		     0x31, 0x70, 0x3c, 0xc9, 0x7e, 0x3a, 0x37, 0x8d,
++		     0x56, 0xfa, 0xd8, 0x21, 0x93, 0x61, 0xc8, 0x8c,
++		     0xca, 0x8b, 0xd7, 0xc5, 0x71, 0x9b, 0x12, 0xb2 },
++	.b_public = (u8[32]){ 0x64, 0xae, 0xac, 0x25, 0x04, 0x14, 0x48, 0x61,
++		    0x53, 0x2b, 0x7b, 0xbc, 0xb6, 0xc8, 0x7d, 0x67,
++		    0xdd, 0x4c, 0x1f, 0x07, 0xeb, 0xc2, 0xe0, 0x6e,
++		    0xff, 0xb9, 0x5a, 0xec, 0xc6, 0x17, 0x0b, 0x2c },
++	.expected_ss = (u8[32]){ 0x4f, 0xf0, 0x3d, 0x5f, 0xb4, 0x3c, 0xd8, 0x65,
++		    0x7a, 0x3c, 0xf3, 0x7c, 0x13, 0x8c, 0xad, 0xce,
++		    0xcc, 0xe5, 0x09, 0xe4, 0xeb, 0xa0, 0x89, 0xd0,
++		    0xef, 0x40, 0xb4, 0xe4, 0xfb, 0x94, 0x61, 0x55 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - checking for overflow */
++{
++	.secret = (u8[32]){ 0xc8, 0x17, 0x24, 0x70, 0x40, 0x00, 0xb2, 0x6d,
++		     0x31, 0x70, 0x3c, 0xc9, 0x7e, 0x3a, 0x37, 0x8d,
++		     0x56, 0xfa, 0xd8, 0x21, 0x93, 0x61, 0xc8, 0x8c,
++		     0xca, 0x8b, 0xd7, 0xc5, 0x71, 0x9b, 0x12, 0xb2 },
++	.b_public = (u8[32]){ 0xbf, 0x68, 0xe3, 0x5e, 0x9b, 0xdb, 0x7e, 0xee,
++		    0x1b, 0x50, 0x57, 0x02, 0x21, 0x86, 0x0f, 0x5d,
++		    0xcd, 0xad, 0x8a, 0xcb, 0xab, 0x03, 0x1b, 0x14,
++		    0x97, 0x4c, 0xc4, 0x90, 0x13, 0xc4, 0x98, 0x31 },
++	.expected_ss = (u8[32]){ 0x21, 0xce, 0xe5, 0x2e, 0xfd, 0xbc, 0x81, 0x2e,
++		    0x1d, 0x02, 0x1a, 0x4a, 0xf1, 0xe1, 0xd8, 0xbc,
++		    0x4d, 0xb3, 0xc4, 0x00, 0xe4, 0xd2, 0xa2, 0xc5,
++		    0x6a, 0x39, 0x26, 0xdb, 0x4d, 0x99, 0xc6, 0x5b },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - checking for overflow */
++{
++	.secret = (u8[32]){ 0xc8, 0x17, 0x24, 0x70, 0x40, 0x00, 0xb2, 0x6d,
++		     0x31, 0x70, 0x3c, 0xc9, 0x7e, 0x3a, 0x37, 0x8d,
++		     0x56, 0xfa, 0xd8, 0x21, 0x93, 0x61, 0xc8, 0x8c,
++		     0xca, 0x8b, 0xd7, 0xc5, 0x71, 0x9b, 0x12, 0xb2 },
++	.b_public = (u8[32]){ 0x53, 0x47, 0xc4, 0x91, 0x33, 0x1a, 0x64, 0xb4,
++		    0x3d, 0xdc, 0x68, 0x30, 0x34, 0xe6, 0x77, 0xf5,
++		    0x3d, 0xc3, 0x2b, 0x52, 0xa5, 0x2a, 0x57, 0x7c,
++		    0x15, 0xa8, 0x3b, 0xf2, 0x98, 0xe9, 0x9f, 0x19 },
++	.expected_ss = (u8[32]){ 0x18, 0xcb, 0x89, 0xe4, 0xe2, 0x0c, 0x0c, 0x2b,
++		    0xd3, 0x24, 0x30, 0x52, 0x45, 0x26, 0x6c, 0x93,
++		    0x27, 0x69, 0x0b, 0xbe, 0x79, 0xac, 0xb8, 0x8f,
++		    0x5b, 0x8f, 0xb3, 0xf7, 0x4e, 0xca, 0x3e, 0x52 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - private key == -1 (mod order) */
++{
++	.secret = (u8[32]){ 0xa0, 0x23, 0xcd, 0xd0, 0x83, 0xef, 0x5b, 0xb8,
++		     0x2f, 0x10, 0xd6, 0x2e, 0x59, 0xe1, 0x5a, 0x68,
++		     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++		     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50 },
++	.b_public = (u8[32]){ 0x25, 0x8e, 0x04, 0x52, 0x3b, 0x8d, 0x25, 0x3e,
++		    0xe6, 0x57, 0x19, 0xfc, 0x69, 0x06, 0xc6, 0x57,
++		    0x19, 0x2d, 0x80, 0x71, 0x7e, 0xdc, 0x82, 0x8f,
++		    0xa0, 0xaf, 0x21, 0x68, 0x6e, 0x2f, 0xaa, 0x75 },
++	.expected_ss = (u8[32]){ 0x25, 0x8e, 0x04, 0x52, 0x3b, 0x8d, 0x25, 0x3e,
++		    0xe6, 0x57, 0x19, 0xfc, 0x69, 0x06, 0xc6, 0x57,
++		    0x19, 0x2d, 0x80, 0x71, 0x7e, 0xdc, 0x82, 0x8f,
++		    0xa0, 0xaf, 0x21, 0x68, 0x6e, 0x2f, 0xaa, 0x75 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++},
++/* wycheproof - private key == 1 (mod order) on twist */
++{
++	.secret = (u8[32]){ 0x58, 0x08, 0x3d, 0xd2, 0x61, 0xad, 0x91, 0xef,
++		     0xf9, 0x52, 0x32, 0x2e, 0xc8, 0x24, 0xc6, 0x82,
++		     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++		     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5f },
++	.b_public = (u8[32]){ 0x2e, 0xae, 0x5e, 0xc3, 0xdd, 0x49, 0x4e, 0x9f,
++		    0x2d, 0x37, 0xd2, 0x58, 0xf8, 0x73, 0xa8, 0xe6,
++		    0xe9, 0xd0, 0xdb, 0xd1, 0xe3, 0x83, 0xef, 0x64,
++		    0xd9, 0x8b, 0xb9, 0x1b, 0x3e, 0x0b, 0xe0, 0x35 },
++	.expected_ss = (u8[32]){ 0x2e, 0xae, 0x5e, 0xc3, 0xdd, 0x49, 0x4e, 0x9f,
++		    0x2d, 0x37, 0xd2, 0x58, 0xf8, 0x73, 0xa8, 0xe6,
++		    0xe9, 0xd0, 0xdb, 0xd1, 0xe3, 0x83, 0xef, 0x64,
++		    0xd9, 0x8b, 0xb9, 0x1b, 0x3e, 0x0b, 0xe0, 0x35 },
++	.secret_size = 32,
++	.b_public_size = 32,
++	.expected_ss_size = 32,
++
++}
++};
++
+ static const struct kpp_testvec ecdh_tv_template[] = {
+ 	{
+ #ifndef CONFIG_CRYPTO_FIPS
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0027-crypto-curve25519-implement-generic-KPP-driver.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0027-crypto-curve25519-implement-generic-KPP-driver.patch
new file mode 100644
index 0000000..d909561
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0027-crypto-curve25519-implement-generic-KPP-driver.patch
@@ -0,0 +1,136 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:34 +0100
+Subject: [PATCH] crypto: curve25519 - implement generic KPP driver
+
+commit ee772cb641135739c1530647391d5a04c39db192 upstream.
+
+Expose the generic Curve25519 library via the crypto API KPP interface.
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ crypto/Kconfig              |  5 +++
+ crypto/Makefile             |  1 +
+ crypto/curve25519-generic.c | 90 +++++++++++++++++++++++++++++++++++++
+ 3 files changed, 96 insertions(+)
+ create mode 100644 crypto/curve25519-generic.c
+
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -264,6 +264,11 @@ config CRYPTO_ECRDSA
+ 	  standard algorithms (called GOST algorithms). Only signature verification
+ 	  is implemented.
+ 
++config CRYPTO_CURVE25519
++	tristate "Curve25519 algorithm"
++	select CRYPTO_KPP
++	select CRYPTO_LIB_CURVE25519_GENERIC
++
+ comment "Authenticated Encryption with Associated Data"
+ 
+ config CRYPTO_CCM
+--- a/crypto/Makefile
++++ b/crypto/Makefile
+@@ -167,6 +167,7 @@ obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o
+ obj-$(CONFIG_CRYPTO_OFB) += ofb.o
+ obj-$(CONFIG_CRYPTO_ECC) += ecc.o
+ obj-$(CONFIG_CRYPTO_ESSIV) += essiv.o
++obj-$(CONFIG_CRYPTO_CURVE25519) += curve25519-generic.o
+ 
+ ecdh_generic-y += ecdh.o
+ ecdh_generic-y += ecdh_helper.o
+--- /dev/null
++++ b/crypto/curve25519-generic.c
+@@ -0,0 +1,90 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++
++#include <crypto/curve25519.h>
++#include <crypto/internal/kpp.h>
++#include <crypto/kpp.h>
++#include <linux/module.h>
++#include <linux/scatterlist.h>
++
++static int curve25519_set_secret(struct crypto_kpp *tfm, const void *buf,
++				 unsigned int len)
++{
++	u8 *secret = kpp_tfm_ctx(tfm);
++
++	if (!len)
++		curve25519_generate_secret(secret);
++	else if (len == CURVE25519_KEY_SIZE &&
++		 crypto_memneq(buf, curve25519_null_point, CURVE25519_KEY_SIZE))
++		memcpy(secret, buf, CURVE25519_KEY_SIZE);
++	else
++		return -EINVAL;
++	return 0;
++}
++
++static int curve25519_compute_value(struct kpp_request *req)
++{
++	struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
++	const u8 *secret = kpp_tfm_ctx(tfm);
++	u8 public_key[CURVE25519_KEY_SIZE];
++	u8 buf[CURVE25519_KEY_SIZE];
++	int copied, nbytes;
++	u8 const *bp;
++
++	if (req->src) {
++		copied = sg_copy_to_buffer(req->src,
++					   sg_nents_for_len(req->src,
++							    CURVE25519_KEY_SIZE),
++					   public_key, CURVE25519_KEY_SIZE);
++		if (copied != CURVE25519_KEY_SIZE)
++			return -EINVAL;
++		bp = public_key;
++	} else {
++		bp = curve25519_base_point;
++	}
++
++	curve25519_generic(buf, secret, bp);
++
++	/* might want less than we've got */
++	nbytes = min_t(size_t, CURVE25519_KEY_SIZE, req->dst_len);
++	copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst,
++								nbytes),
++				     buf, nbytes);
++	if (copied != nbytes)
++		return -EINVAL;
++	return 0;
++}
++
++static unsigned int curve25519_max_size(struct crypto_kpp *tfm)
++{
++	return CURVE25519_KEY_SIZE;
++}
++
++static struct kpp_alg curve25519_alg = {
++	.base.cra_name		= "curve25519",
++	.base.cra_driver_name	= "curve25519-generic",
++	.base.cra_priority	= 100,
++	.base.cra_module	= THIS_MODULE,
++	.base.cra_ctxsize	= CURVE25519_KEY_SIZE,
++
++	.set_secret		= curve25519_set_secret,
++	.generate_public_key	= curve25519_compute_value,
++	.compute_shared_secret	= curve25519_compute_value,
++	.max_size		= curve25519_max_size,
++};
++
++static int curve25519_init(void)
++{
++	return crypto_register_kpp(&curve25519_alg);
++}
++
++static void curve25519_exit(void)
++{
++	crypto_unregister_kpp(&curve25519_alg);
++}
++
++subsys_initcall(curve25519_init);
++module_exit(curve25519_exit);
++
++MODULE_ALIAS_CRYPTO("curve25519");
++MODULE_ALIAS_CRYPTO("curve25519-generic");
++MODULE_LICENSE("GPL");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0028-crypto-lib-curve25519-work-around-Clang-stack-spilli.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0028-crypto-lib-curve25519-work-around-Clang-stack-spilli.patch
new file mode 100644
index 0000000..36b59c9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0028-crypto-lib-curve25519-work-around-Clang-stack-spilli.patch
@@ -0,0 +1,75 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:35 +0100
+Subject: [PATCH] crypto: lib/curve25519 - work around Clang stack spilling
+ issue
+
+commit 660bb8e1f833ea63185fe80fde847e3e42f18e3b upstream.
+
+Arnd reports that the 32-bit generic library code for Curve25119 ends
+up using an excessive amount of stack space when built with Clang:
+
+  lib/crypto/curve25519-fiat32.c:756:6: error: stack frame size
+      of 1384 bytes in function 'curve25519_generic'
+      [-Werror,-Wframe-larger-than=]
+
+Let's give some hints to the compiler regarding which routines should
+not be inlined, to prevent it from running out of registers and spilling
+to the stack. The resulting code performs identically under both GCC
+and Clang, and makes the warning go away.
+
+Suggested-by: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ lib/crypto/curve25519-fiat32.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/lib/crypto/curve25519-fiat32.c
++++ b/lib/crypto/curve25519-fiat32.c
+@@ -223,7 +223,7 @@ static __always_inline void fe_1(fe *h)
+ 	h->v[0] = 1;
+ }
+ 
+-static void fe_add_impl(u32 out[10], const u32 in1[10], const u32 in2[10])
++static noinline void fe_add_impl(u32 out[10], const u32 in1[10], const u32 in2[10])
+ {
+ 	{ const u32 x20 = in1[9];
+ 	{ const u32 x21 = in1[8];
+@@ -266,7 +266,7 @@ static __always_inline void fe_add(fe_lo
+ 	fe_add_impl(h->v, f->v, g->v);
+ }
+ 
+-static void fe_sub_impl(u32 out[10], const u32 in1[10], const u32 in2[10])
++static noinline void fe_sub_impl(u32 out[10], const u32 in1[10], const u32 in2[10])
+ {
+ 	{ const u32 x20 = in1[9];
+ 	{ const u32 x21 = in1[8];
+@@ -309,7 +309,7 @@ static __always_inline void fe_sub(fe_lo
+ 	fe_sub_impl(h->v, f->v, g->v);
+ }
+ 
+-static void fe_mul_impl(u32 out[10], const u32 in1[10], const u32 in2[10])
++static noinline void fe_mul_impl(u32 out[10], const u32 in1[10], const u32 in2[10])
+ {
+ 	{ const u32 x20 = in1[9];
+ 	{ const u32 x21 = in1[8];
+@@ -441,7 +441,7 @@ fe_mul_tll(fe *h, const fe_loose *f, con
+ 	fe_mul_impl(h->v, f->v, g->v);
+ }
+ 
+-static void fe_sqr_impl(u32 out[10], const u32 in1[10])
++static noinline void fe_sqr_impl(u32 out[10], const u32 in1[10])
+ {
+ 	{ const u32 x17 = in1[9];
+ 	{ const u32 x18 = in1[8];
+@@ -619,7 +619,7 @@ static __always_inline void fe_invert(fe
+  *
+  * Preconditions: b in {0,1}
+  */
+-static __always_inline void fe_cswap(fe *f, fe *g, unsigned int b)
++static noinline void fe_cswap(fe *f, fe *g, unsigned int b)
+ {
+ 	unsigned i;
+ 	b = 0 - b;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0029-crypto-curve25519-x86_64-library-and-KPP-implementat.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0029-crypto-curve25519-x86_64-library-and-KPP-implementat.patch
new file mode 100644
index 0000000..49fd970
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0029-crypto-curve25519-x86_64-library-and-KPP-implementat.patch
@@ -0,0 +1,2536 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 8 Nov 2019 13:22:36 +0100
+Subject: [PATCH] crypto: curve25519 - x86_64 library and KPP implementations
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit bb611bdfd6be34d9f822c73305fcc83720499d38 upstream.
+
+This implementation is the fastest available x86_64 implementation, and
+unlike Sandy2x, it doesn't requie use of the floating point registers at
+all. Instead it makes use of BMI2 and ADX, available on recent
+microarchitectures. The implementation was written by Armando
+Faz-Hernández with contributions (upstream) from Samuel Neves and me,
+in addition to further changes in the kernel implementation from us.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Samuel Neves <sneves@dei.uc.pt>
+Co-developed-by: Samuel Neves <sneves@dei.uc.pt>
+[ardb: - move to arch/x86/crypto
+       - wire into lib/crypto framework
+       - implement crypto API KPP hooks ]
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/Makefile            |    1 +
+ arch/x86/crypto/curve25519-x86_64.c | 2475 +++++++++++++++++++++++++++
+ crypto/Kconfig                      |    6 +
+ 3 files changed, 2482 insertions(+)
+ create mode 100644 arch/x86/crypto/curve25519-x86_64.c
+
+--- a/arch/x86/crypto/Makefile
++++ b/arch/x86/crypto/Makefile
+@@ -39,6 +39,7 @@ obj-$(CONFIG_CRYPTO_AEGIS128_AESNI_SSE2)
+ 
+ obj-$(CONFIG_CRYPTO_NHPOLY1305_SSE2) += nhpoly1305-sse2.o
+ obj-$(CONFIG_CRYPTO_NHPOLY1305_AVX2) += nhpoly1305-avx2.o
++obj-$(CONFIG_CRYPTO_CURVE25519_X86) += curve25519-x86_64.o
+ 
+ # These modules require assembler to support AVX.
+ ifeq ($(avx_supported),yes)
+--- /dev/null
++++ b/arch/x86/crypto/curve25519-x86_64.c
+@@ -0,0 +1,2475 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
++/*
++ * Copyright (c) 2017 Armando Faz <armfazh@ic.unicamp.br>. All Rights Reserved.
++ * Copyright (C) 2018-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ * Copyright (C) 2018 Samuel Neves <sneves@dei.uc.pt>. All Rights Reserved.
++ */
++
++#include <crypto/curve25519.h>
++#include <crypto/internal/kpp.h>
++
++#include <linux/types.h>
++#include <linux/jump_label.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++
++#include <asm/cpufeature.h>
++#include <asm/processor.h>
++
++static __ro_after_init DEFINE_STATIC_KEY_FALSE(curve25519_use_bmi2);
++static __ro_after_init DEFINE_STATIC_KEY_FALSE(curve25519_use_adx);
++
++enum { NUM_WORDS_ELTFP25519 = 4 };
++typedef __aligned(32) u64 eltfp25519_1w[NUM_WORDS_ELTFP25519];
++typedef __aligned(32) u64 eltfp25519_1w_buffer[2 * NUM_WORDS_ELTFP25519];
++
++#define mul_eltfp25519_1w_adx(c, a, b) do { \
++	mul_256x256_integer_adx(m.buffer, a, b); \
++	red_eltfp25519_1w_adx(c, m.buffer); \
++} while (0)
++
++#define mul_eltfp25519_1w_bmi2(c, a, b) do { \
++	mul_256x256_integer_bmi2(m.buffer, a, b); \
++	red_eltfp25519_1w_bmi2(c, m.buffer); \
++} while (0)
++
++#define sqr_eltfp25519_1w_adx(a) do { \
++	sqr_256x256_integer_adx(m.buffer, a); \
++	red_eltfp25519_1w_adx(a, m.buffer); \
++} while (0)
++
++#define sqr_eltfp25519_1w_bmi2(a) do { \
++	sqr_256x256_integer_bmi2(m.buffer, a); \
++	red_eltfp25519_1w_bmi2(a, m.buffer); \
++} while (0)
++
++#define mul_eltfp25519_2w_adx(c, a, b) do { \
++	mul2_256x256_integer_adx(m.buffer, a, b); \
++	red_eltfp25519_2w_adx(c, m.buffer); \
++} while (0)
++
++#define mul_eltfp25519_2w_bmi2(c, a, b) do { \
++	mul2_256x256_integer_bmi2(m.buffer, a, b); \
++	red_eltfp25519_2w_bmi2(c, m.buffer); \
++} while (0)
++
++#define sqr_eltfp25519_2w_adx(a) do { \
++	sqr2_256x256_integer_adx(m.buffer, a); \
++	red_eltfp25519_2w_adx(a, m.buffer); \
++} while (0)
++
++#define sqr_eltfp25519_2w_bmi2(a) do { \
++	sqr2_256x256_integer_bmi2(m.buffer, a); \
++	red_eltfp25519_2w_bmi2(a, m.buffer); \
++} while (0)
++
++#define sqrn_eltfp25519_1w_adx(a, times) do { \
++	int ____counter = (times); \
++	while (____counter-- > 0) \
++		sqr_eltfp25519_1w_adx(a); \
++} while (0)
++
++#define sqrn_eltfp25519_1w_bmi2(a, times) do { \
++	int ____counter = (times); \
++	while (____counter-- > 0) \
++		sqr_eltfp25519_1w_bmi2(a); \
++} while (0)
++
++#define copy_eltfp25519_1w(C, A) do { \
++	(C)[0] = (A)[0]; \
++	(C)[1] = (A)[1]; \
++	(C)[2] = (A)[2]; \
++	(C)[3] = (A)[3]; \
++} while (0)
++
++#define setzero_eltfp25519_1w(C) do { \
++	(C)[0] = 0; \
++	(C)[1] = 0; \
++	(C)[2] = 0; \
++	(C)[3] = 0; \
++} while (0)
++
++__aligned(32) static const u64 table_ladder_8k[252 * NUM_WORDS_ELTFP25519] = {
++	/*   1 */ 0xfffffffffffffff3UL, 0xffffffffffffffffUL,
++		  0xffffffffffffffffUL, 0x5fffffffffffffffUL,
++	/*   2 */ 0x6b8220f416aafe96UL, 0x82ebeb2b4f566a34UL,
++		  0xd5a9a5b075a5950fUL, 0x5142b2cf4b2488f4UL,
++	/*   3 */ 0x6aaebc750069680cUL, 0x89cf7820a0f99c41UL,
++		  0x2a58d9183b56d0f4UL, 0x4b5aca80e36011a4UL,
++	/*   4 */ 0x329132348c29745dUL, 0xf4a2e616e1642fd7UL,
++		  0x1e45bb03ff67bc34UL, 0x306912d0f42a9b4aUL,
++	/*   5 */ 0xff886507e6af7154UL, 0x04f50e13dfeec82fUL,
++		  0xaa512fe82abab5ceUL, 0x174e251a68d5f222UL,
++	/*   6 */ 0xcf96700d82028898UL, 0x1743e3370a2c02c5UL,
++		  0x379eec98b4e86eaaUL, 0x0c59888a51e0482eUL,
++	/*   7 */ 0xfbcbf1d699b5d189UL, 0xacaef0d58e9fdc84UL,
++		  0xc1c20d06231f7614UL, 0x2938218da274f972UL,
++	/*   8 */ 0xf6af49beff1d7f18UL, 0xcc541c22387ac9c2UL,
++		  0x96fcc9ef4015c56bUL, 0x69c1627c690913a9UL,
++	/*   9 */ 0x7a86fd2f4733db0eUL, 0xfdb8c4f29e087de9UL,
++		  0x095e4b1a8ea2a229UL, 0x1ad7a7c829b37a79UL,
++	/*  10 */ 0x342d89cad17ea0c0UL, 0x67bedda6cced2051UL,
++		  0x19ca31bf2bb42f74UL, 0x3df7b4c84980acbbUL,
++	/*  11 */ 0xa8c6444dc80ad883UL, 0xb91e440366e3ab85UL,
++		  0xc215cda00164f6d8UL, 0x3d867c6ef247e668UL,
++	/*  12 */ 0xc7dd582bcc3e658cUL, 0xfd2c4748ee0e5528UL,
++		  0xa0fd9b95cc9f4f71UL, 0x7529d871b0675ddfUL,
++	/*  13 */ 0xb8f568b42d3cbd78UL, 0x1233011b91f3da82UL,
++		  0x2dce6ccd4a7c3b62UL, 0x75e7fc8e9e498603UL,
++	/*  14 */ 0x2f4f13f1fcd0b6ecUL, 0xf1a8ca1f29ff7a45UL,
++		  0xc249c1a72981e29bUL, 0x6ebe0dbb8c83b56aUL,
++	/*  15 */ 0x7114fa8d170bb222UL, 0x65a2dcd5bf93935fUL,
++		  0xbdc41f68b59c979aUL, 0x2f0eef79a2ce9289UL,
++	/*  16 */ 0x42ecbf0c083c37ceUL, 0x2930bc09ec496322UL,
++		  0xf294b0c19cfeac0dUL, 0x3780aa4bedfabb80UL,
++	/*  17 */ 0x56c17d3e7cead929UL, 0xe7cb4beb2e5722c5UL,
++		  0x0ce931732dbfe15aUL, 0x41b883c7621052f8UL,
++	/*  18 */ 0xdbf75ca0c3d25350UL, 0x2936be086eb1e351UL,
++		  0xc936e03cb4a9b212UL, 0x1d45bf82322225aaUL,
++	/*  19 */ 0xe81ab1036a024cc5UL, 0xe212201c304c9a72UL,
++		  0xc5d73fba6832b1fcUL, 0x20ffdb5a4d839581UL,
++	/*  20 */ 0xa283d367be5d0fadUL, 0x6c2b25ca8b164475UL,
++		  0x9d4935467caaf22eUL, 0x5166408eee85ff49UL,
++	/*  21 */ 0x3c67baa2fab4e361UL, 0xb3e433c67ef35cefUL,
++		  0x5259729241159b1cUL, 0x6a621892d5b0ab33UL,
++	/*  22 */ 0x20b74a387555cdcbUL, 0x532aa10e1208923fUL,
++		  0xeaa17b7762281dd1UL, 0x61ab3443f05c44bfUL,
++	/*  23 */ 0x257a6c422324def8UL, 0x131c6c1017e3cf7fUL,
++		  0x23758739f630a257UL, 0x295a407a01a78580UL,
++	/*  24 */ 0xf8c443246d5da8d9UL, 0x19d775450c52fa5dUL,
++		  0x2afcfc92731bf83dUL, 0x7d10c8e81b2b4700UL,
++	/*  25 */ 0xc8e0271f70baa20bUL, 0x993748867ca63957UL,
++		  0x5412efb3cb7ed4bbUL, 0x3196d36173e62975UL,
++	/*  26 */ 0xde5bcad141c7dffcUL, 0x47cc8cd2b395c848UL,
++		  0xa34cd942e11af3cbUL, 0x0256dbf2d04ecec2UL,
++	/*  27 */ 0x875ab7e94b0e667fUL, 0xcad4dd83c0850d10UL,
++		  0x47f12e8f4e72c79fUL, 0x5f1a87bb8c85b19bUL,
++	/*  28 */ 0x7ae9d0b6437f51b8UL, 0x12c7ce5518879065UL,
++		  0x2ade09fe5cf77aeeUL, 0x23a05a2f7d2c5627UL,
++	/*  29 */ 0x5908e128f17c169aUL, 0xf77498dd8ad0852dUL,
++		  0x74b4c4ceab102f64UL, 0x183abadd10139845UL,
++	/*  30 */ 0xb165ba8daa92aaacUL, 0xd5c5ef9599386705UL,
++		  0xbe2f8f0cf8fc40d1UL, 0x2701e635ee204514UL,
++	/*  31 */ 0x629fa80020156514UL, 0xf223868764a8c1ceUL,
++		  0x5b894fff0b3f060eUL, 0x60d9944cf708a3faUL,
++	/*  32 */ 0xaeea001a1c7a201fUL, 0xebf16a633ee2ce63UL,
++		  0x6f7709594c7a07e1UL, 0x79b958150d0208cbUL,
++	/*  33 */ 0x24b55e5301d410e7UL, 0xe3a34edff3fdc84dUL,
++		  0xd88768e4904032d8UL, 0x131384427b3aaeecUL,
++	/*  34 */ 0x8405e51286234f14UL, 0x14dc4739adb4c529UL,
++		  0xb8a2b5b250634ffdUL, 0x2fe2a94ad8a7ff93UL,
++	/*  35 */ 0xec5c57efe843faddUL, 0x2843ce40f0bb9918UL,
++		  0xa4b561d6cf3d6305UL, 0x743629bde8fb777eUL,
++	/*  36 */ 0x343edd46bbaf738fUL, 0xed981828b101a651UL,
++		  0xa401760b882c797aUL, 0x1fc223e28dc88730UL,
++	/*  37 */ 0x48604e91fc0fba0eUL, 0xb637f78f052c6fa4UL,
++		  0x91ccac3d09e9239cUL, 0x23f7eed4437a687cUL,
++	/*  38 */ 0x5173b1118d9bd800UL, 0x29d641b63189d4a7UL,
++		  0xfdbf177988bbc586UL, 0x2959894fcad81df5UL,
++	/*  39 */ 0xaebc8ef3b4bbc899UL, 0x4148995ab26992b9UL,
++		  0x24e20b0134f92cfbUL, 0x40d158894a05dee8UL,
++	/*  40 */ 0x46b00b1185af76f6UL, 0x26bac77873187a79UL,
++		  0x3dc0bf95ab8fff5fUL, 0x2a608bd8945524d7UL,
++	/*  41 */ 0x26449588bd446302UL, 0x7c4bc21c0388439cUL,
++		  0x8e98a4f383bd11b2UL, 0x26218d7bc9d876b9UL,
++	/*  42 */ 0xe3081542997c178aUL, 0x3c2d29a86fb6606fUL,
++		  0x5c217736fa279374UL, 0x7dde05734afeb1faUL,
++	/*  43 */ 0x3bf10e3906d42babUL, 0xe4f7803e1980649cUL,
++		  0xe6053bf89595bf7aUL, 0x394faf38da245530UL,
++	/*  44 */ 0x7a8efb58896928f4UL, 0xfbc778e9cc6a113cUL,
++		  0x72670ce330af596fUL, 0x48f222a81d3d6cf7UL,
++	/*  45 */ 0xf01fce410d72caa7UL, 0x5a20ecc7213b5595UL,
++		  0x7bc21165c1fa1483UL, 0x07f89ae31da8a741UL,
++	/*  46 */ 0x05d2c2b4c6830ff9UL, 0xd43e330fc6316293UL,
++		  0xa5a5590a96d3a904UL, 0x705edb91a65333b6UL,
++	/*  47 */ 0x048ee15e0bb9a5f7UL, 0x3240cfca9e0aaf5dUL,
++		  0x8f4b71ceedc4a40bUL, 0x621c0da3de544a6dUL,
++	/*  48 */ 0x92872836a08c4091UL, 0xce8375b010c91445UL,
++		  0x8a72eb524f276394UL, 0x2667fcfa7ec83635UL,
++	/*  49 */ 0x7f4c173345e8752aUL, 0x061b47feee7079a5UL,
++		  0x25dd9afa9f86ff34UL, 0x3780cef5425dc89cUL,
++	/*  50 */ 0x1a46035a513bb4e9UL, 0x3e1ef379ac575adaUL,
++		  0xc78c5f1c5fa24b50UL, 0x321a967634fd9f22UL,
++	/*  51 */ 0x946707b8826e27faUL, 0x3dca84d64c506fd0UL,
++		  0xc189218075e91436UL, 0x6d9284169b3b8484UL,
++	/*  52 */ 0x3a67e840383f2ddfUL, 0x33eec9a30c4f9b75UL,
++		  0x3ec7c86fa783ef47UL, 0x26ec449fbac9fbc4UL,
++	/*  53 */ 0x5c0f38cba09b9e7dUL, 0x81168cc762a3478cUL,
++		  0x3e23b0d306fc121cUL, 0x5a238aa0a5efdcddUL,
++	/*  54 */ 0x1ba26121c4ea43ffUL, 0x36f8c77f7c8832b5UL,
++		  0x88fbea0b0adcf99aUL, 0x5ca9938ec25bebf9UL,
++	/*  55 */ 0xd5436a5e51fccda0UL, 0x1dbc4797c2cd893bUL,
++		  0x19346a65d3224a08UL, 0x0f5034e49b9af466UL,
++	/*  56 */ 0xf23c3967a1e0b96eUL, 0xe58b08fa867a4d88UL,
++		  0xfb2fabc6a7341679UL, 0x2a75381eb6026946UL,
++	/*  57 */ 0xc80a3be4c19420acUL, 0x66b1f6c681f2b6dcUL,
++		  0x7cf7036761e93388UL, 0x25abbbd8a660a4c4UL,
++	/*  58 */ 0x91ea12ba14fd5198UL, 0x684950fc4a3cffa9UL,
++		  0xf826842130f5ad28UL, 0x3ea988f75301a441UL,
++	/*  59 */ 0xc978109a695f8c6fUL, 0x1746eb4a0530c3f3UL,
++		  0x444d6d77b4459995UL, 0x75952b8c054e5cc7UL,
++	/*  60 */ 0xa3703f7915f4d6aaUL, 0x66c346202f2647d8UL,
++		  0xd01469df811d644bUL, 0x77fea47d81a5d71fUL,
++	/*  61 */ 0xc5e9529ef57ca381UL, 0x6eeeb4b9ce2f881aUL,
++		  0xb6e91a28e8009bd6UL, 0x4b80be3e9afc3fecUL,
++	/*  62 */ 0x7e3773c526aed2c5UL, 0x1b4afcb453c9a49dUL,
++		  0xa920bdd7baffb24dUL, 0x7c54699f122d400eUL,
++	/*  63 */ 0xef46c8e14fa94bc8UL, 0xe0b074ce2952ed5eUL,
++		  0xbea450e1dbd885d5UL, 0x61b68649320f712cUL,
++	/*  64 */ 0x8a485f7309ccbdd1UL, 0xbd06320d7d4d1a2dUL,
++		  0x25232973322dbef4UL, 0x445dc4758c17f770UL,
++	/*  65 */ 0xdb0434177cc8933cUL, 0xed6fe82175ea059fUL,
++		  0x1efebefdc053db34UL, 0x4adbe867c65daf99UL,
++	/*  66 */ 0x3acd71a2a90609dfUL, 0xe5e991856dd04050UL,
++		  0x1ec69b688157c23cUL, 0x697427f6885cfe4dUL,
++	/*  67 */ 0xd7be7b9b65e1a851UL, 0xa03d28d522c536ddUL,
++		  0x28399d658fd2b645UL, 0x49e5b7e17c2641e1UL,
++	/*  68 */ 0x6f8c3a98700457a4UL, 0x5078f0a25ebb6778UL,
++		  0xd13c3ccbc382960fUL, 0x2e003258a7df84b1UL,
++	/*  69 */ 0x8ad1f39be6296a1cUL, 0xc1eeaa652a5fbfb2UL,
++		  0x33ee0673fd26f3cbUL, 0x59256173a69d2cccUL,
++	/*  70 */ 0x41ea07aa4e18fc41UL, 0xd9fc19527c87a51eUL,
++		  0xbdaacb805831ca6fUL, 0x445b652dc916694fUL,
++	/*  71 */ 0xce92a3a7f2172315UL, 0x1edc282de11b9964UL,
++		  0xa1823aafe04c314aUL, 0x790a2d94437cf586UL,
++	/*  72 */ 0x71c447fb93f6e009UL, 0x8922a56722845276UL,
++		  0xbf70903b204f5169UL, 0x2f7a89891ba319feUL,
++	/*  73 */ 0x02a08eb577e2140cUL, 0xed9a4ed4427bdcf4UL,
++		  0x5253ec44e4323cd1UL, 0x3e88363c14e9355bUL,
++	/*  74 */ 0xaa66c14277110b8cUL, 0x1ae0391610a23390UL,
++		  0x2030bd12c93fc2a2UL, 0x3ee141579555c7abUL,
++	/*  75 */ 0x9214de3a6d6e7d41UL, 0x3ccdd88607f17efeUL,
++		  0x674f1288f8e11217UL, 0x5682250f329f93d0UL,
++	/*  76 */ 0x6cf00b136d2e396eUL, 0x6e4cf86f1014debfUL,
++		  0x5930b1b5bfcc4e83UL, 0x047069b48aba16b6UL,
++	/*  77 */ 0x0d4ce4ab69b20793UL, 0xb24db91a97d0fb9eUL,
++		  0xcdfa50f54e00d01dUL, 0x221b1085368bddb5UL,
++	/*  78 */ 0xe7e59468b1e3d8d2UL, 0x53c56563bd122f93UL,
++		  0xeee8a903e0663f09UL, 0x61efa662cbbe3d42UL,
++	/*  79 */ 0x2cf8ddddde6eab2aUL, 0x9bf80ad51435f231UL,
++		  0x5deadacec9f04973UL, 0x29275b5d41d29b27UL,
++	/*  80 */ 0xcfde0f0895ebf14fUL, 0xb9aab96b054905a7UL,
++		  0xcae80dd9a1c420fdUL, 0x0a63bf2f1673bbc7UL,
++	/*  81 */ 0x092f6e11958fbc8cUL, 0x672a81e804822fadUL,
++		  0xcac8351560d52517UL, 0x6f3f7722c8f192f8UL,
++	/*  82 */ 0xf8ba90ccc2e894b7UL, 0x2c7557a438ff9f0dUL,
++		  0x894d1d855ae52359UL, 0x68e122157b743d69UL,
++	/*  83 */ 0xd87e5570cfb919f3UL, 0x3f2cdecd95798db9UL,
++		  0x2121154710c0a2ceUL, 0x3c66a115246dc5b2UL,
++	/*  84 */ 0xcbedc562294ecb72UL, 0xba7143c36a280b16UL,
++		  0x9610c2efd4078b67UL, 0x6144735d946a4b1eUL,
++	/*  85 */ 0x536f111ed75b3350UL, 0x0211db8c2041d81bUL,
++		  0xf93cb1000e10413cUL, 0x149dfd3c039e8876UL,
++	/*  86 */ 0xd479dde46b63155bUL, 0xb66e15e93c837976UL,
++		  0xdafde43b1f13e038UL, 0x5fafda1a2e4b0b35UL,
++	/*  87 */ 0x3600bbdf17197581UL, 0x3972050bbe3cd2c2UL,
++		  0x5938906dbdd5be86UL, 0x34fce5e43f9b860fUL,
++	/*  88 */ 0x75a8a4cd42d14d02UL, 0x828dabc53441df65UL,
++		  0x33dcabedd2e131d3UL, 0x3ebad76fb814d25fUL,
++	/*  89 */ 0xd4906f566f70e10fUL, 0x5d12f7aa51690f5aUL,
++		  0x45adb16e76cefcf2UL, 0x01f768aead232999UL,
++	/*  90 */ 0x2b6cc77b6248febdUL, 0x3cd30628ec3aaffdUL,
++		  0xce1c0b80d4ef486aUL, 0x4c3bff2ea6f66c23UL,
++	/*  91 */ 0x3f2ec4094aeaeb5fUL, 0x61b19b286e372ca7UL,
++		  0x5eefa966de2a701dUL, 0x23b20565de55e3efUL,
++	/*  92 */ 0xe301ca5279d58557UL, 0x07b2d4ce27c2874fUL,
++		  0xa532cd8a9dcf1d67UL, 0x2a52fee23f2bff56UL,
++	/*  93 */ 0x8624efb37cd8663dUL, 0xbbc7ac20ffbd7594UL,
++		  0x57b85e9c82d37445UL, 0x7b3052cb86a6ec66UL,
++	/*  94 */ 0x3482f0ad2525e91eUL, 0x2cb68043d28edca0UL,
++		  0xaf4f6d052e1b003aUL, 0x185f8c2529781b0aUL,
++	/*  95 */ 0xaa41de5bd80ce0d6UL, 0x9407b2416853e9d6UL,
++		  0x563ec36e357f4c3aUL, 0x4cc4b8dd0e297bceUL,
++	/*  96 */ 0xa2fc1a52ffb8730eUL, 0x1811f16e67058e37UL,
++		  0x10f9a366cddf4ee1UL, 0x72f4a0c4a0b9f099UL,
++	/*  97 */ 0x8c16c06f663f4ea7UL, 0x693b3af74e970fbaUL,
++		  0x2102e7f1d69ec345UL, 0x0ba53cbc968a8089UL,
++	/*  98 */ 0xca3d9dc7fea15537UL, 0x4c6824bb51536493UL,
++		  0xb9886314844006b1UL, 0x40d2a72ab454cc60UL,
++	/*  99 */ 0x5936a1b712570975UL, 0x91b9d648debda657UL,
++		  0x3344094bb64330eaUL, 0x006ba10d12ee51d0UL,
++	/* 100 */ 0x19228468f5de5d58UL, 0x0eb12f4c38cc05b0UL,
++		  0xa1039f9dd5601990UL, 0x4502d4ce4fff0e0bUL,
++	/* 101 */ 0xeb2054106837c189UL, 0xd0f6544c6dd3b93cUL,
++		  0x40727064c416d74fUL, 0x6e15c6114b502ef0UL,
++	/* 102 */ 0x4df2a398cfb1a76bUL, 0x11256c7419f2f6b1UL,
++		  0x4a497962066e6043UL, 0x705b3aab41355b44UL,
++	/* 103 */ 0x365ef536d797b1d8UL, 0x00076bd622ddf0dbUL,
++		  0x3bbf33b0e0575a88UL, 0x3777aa05c8e4ca4dUL,
++	/* 104 */ 0x392745c85578db5fUL, 0x6fda4149dbae5ae2UL,
++		  0xb1f0b00b8adc9867UL, 0x09963437d36f1da3UL,
++	/* 105 */ 0x7e824e90a5dc3853UL, 0xccb5f6641f135cbdUL,
++		  0x6736d86c87ce8fccUL, 0x625f3ce26604249fUL,
++	/* 106 */ 0xaf8ac8059502f63fUL, 0x0c05e70a2e351469UL,
++		  0x35292e9c764b6305UL, 0x1a394360c7e23ac3UL,
++	/* 107 */ 0xd5c6d53251183264UL, 0x62065abd43c2b74fUL,
++		  0xb5fbf5d03b973f9bUL, 0x13a3da3661206e5eUL,
++	/* 108 */ 0xc6bd5837725d94e5UL, 0x18e30912205016c5UL,
++		  0x2088ce1570033c68UL, 0x7fba1f495c837987UL,
++	/* 109 */ 0x5a8c7423f2f9079dUL, 0x1735157b34023fc5UL,
++		  0xe4f9b49ad2fab351UL, 0x6691ff72c878e33cUL,
++	/* 110 */ 0x122c2adedc5eff3eUL, 0xf8dd4bf1d8956cf4UL,
++		  0xeb86205d9e9e5bdaUL, 0x049b92b9d975c743UL,
++	/* 111 */ 0xa5379730b0f6c05aUL, 0x72a0ffacc6f3a553UL,
++		  0xb0032c34b20dcd6dUL, 0x470e9dbc88d5164aUL,
++	/* 112 */ 0xb19cf10ca237c047UL, 0xb65466711f6c81a2UL,
++		  0xb3321bd16dd80b43UL, 0x48c14f600c5fbe8eUL,
++	/* 113 */ 0x66451c264aa6c803UL, 0xb66e3904a4fa7da6UL,
++		  0xd45f19b0b3128395UL, 0x31602627c3c9bc10UL,
++	/* 114 */ 0x3120dc4832e4e10dUL, 0xeb20c46756c717f7UL,
++		  0x00f52e3f67280294UL, 0x566d4fc14730c509UL,
++	/* 115 */ 0x7e3a5d40fd837206UL, 0xc1e926dc7159547aUL,
++		  0x216730fba68d6095UL, 0x22e8c3843f69cea7UL,
++	/* 116 */ 0x33d074e8930e4b2bUL, 0xb6e4350e84d15816UL,
++		  0x5534c26ad6ba2365UL, 0x7773c12f89f1f3f3UL,
++	/* 117 */ 0x8cba404da57962aaUL, 0x5b9897a81999ce56UL,
++		  0x508e862f121692fcUL, 0x3a81907fa093c291UL,
++	/* 118 */ 0x0dded0ff4725a510UL, 0x10d8cc10673fc503UL,
++		  0x5b9d151c9f1f4e89UL, 0x32a5c1d5cb09a44cUL,
++	/* 119 */ 0x1e0aa442b90541fbUL, 0x5f85eb7cc1b485dbUL,
++		  0xbee595ce8a9df2e5UL, 0x25e496c722422236UL,
++	/* 120 */ 0x5edf3c46cd0fe5b9UL, 0x34e75a7ed2a43388UL,
++		  0xe488de11d761e352UL, 0x0e878a01a085545cUL,
++	/* 121 */ 0xba493c77e021bb04UL, 0x2b4d1843c7df899aUL,
++		  0x9ea37a487ae80d67UL, 0x67a9958011e41794UL,
++	/* 122 */ 0x4b58051a6697b065UL, 0x47e33f7d8d6ba6d4UL,
++		  0xbb4da8d483ca46c1UL, 0x68becaa181c2db0dUL,
++	/* 123 */ 0x8d8980e90b989aa5UL, 0xf95eb14a2c93c99bUL,
++		  0x51c6c7c4796e73a2UL, 0x6e228363b5efb569UL,
++	/* 124 */ 0xc6bbc0b02dd624c8UL, 0x777eb47dec8170eeUL,
++		  0x3cde15a004cfafa9UL, 0x1dc6bc087160bf9bUL,
++	/* 125 */ 0x2e07e043eec34002UL, 0x18e9fc677a68dc7fUL,
++		  0xd8da03188bd15b9aUL, 0x48fbc3bb00568253UL,
++	/* 126 */ 0x57547d4cfb654ce1UL, 0xd3565b82a058e2adUL,
++		  0xf63eaf0bbf154478UL, 0x47531ef114dfbb18UL,
++	/* 127 */ 0xe1ec630a4278c587UL, 0x5507d546ca8e83f3UL,
++		  0x85e135c63adc0c2bUL, 0x0aa7efa85682844eUL,
++	/* 128 */ 0x72691ba8b3e1f615UL, 0x32b4e9701fbe3ffaUL,
++		  0x97b6d92e39bb7868UL, 0x2cfe53dea02e39e8UL,
++	/* 129 */ 0x687392cd85cd52b0UL, 0x27ff66c910e29831UL,
++		  0x97134556a9832d06UL, 0x269bb0360a84f8a0UL,
++	/* 130 */ 0x706e55457643f85cUL, 0x3734a48c9b597d1bUL,
++		  0x7aee91e8c6efa472UL, 0x5cd6abc198a9d9e0UL,
++	/* 131 */ 0x0e04de06cb3ce41aUL, 0xd8c6eb893402e138UL,
++		  0x904659bb686e3772UL, 0x7215c371746ba8c8UL,
++	/* 132 */ 0xfd12a97eeae4a2d9UL, 0x9514b7516394f2c5UL,
++		  0x266fd5809208f294UL, 0x5c847085619a26b9UL,
++	/* 133 */ 0x52985410fed694eaUL, 0x3c905b934a2ed254UL,
++		  0x10bb47692d3be467UL, 0x063b3d2d69e5e9e1UL,
++	/* 134 */ 0x472726eedda57debUL, 0xefb6c4ae10f41891UL,
++		  0x2b1641917b307614UL, 0x117c554fc4f45b7cUL,
++	/* 135 */ 0xc07cf3118f9d8812UL, 0x01dbd82050017939UL,
++		  0xd7e803f4171b2827UL, 0x1015e87487d225eaUL,
++	/* 136 */ 0xc58de3fed23acc4dUL, 0x50db91c294a7be2dUL,
++		  0x0b94d43d1c9cf457UL, 0x6b1640fa6e37524aUL,
++	/* 137 */ 0x692f346c5fda0d09UL, 0x200b1c59fa4d3151UL,
++		  0xb8c46f760777a296UL, 0x4b38395f3ffdfbcfUL,
++	/* 138 */ 0x18d25e00be54d671UL, 0x60d50582bec8aba6UL,
++		  0x87ad8f263b78b982UL, 0x50fdf64e9cda0432UL,
++	/* 139 */ 0x90f567aac578dcf0UL, 0xef1e9b0ef2a3133bUL,
++		  0x0eebba9242d9de71UL, 0x15473c9bf03101c7UL,
++	/* 140 */ 0x7c77e8ae56b78095UL, 0xb678e7666e6f078eUL,
++		  0x2da0b9615348ba1fUL, 0x7cf931c1ff733f0bUL,
++	/* 141 */ 0x26b357f50a0a366cUL, 0xe9708cf42b87d732UL,
++		  0xc13aeea5f91cb2c0UL, 0x35d90c991143bb4cUL,
++	/* 142 */ 0x47c1c404a9a0d9dcUL, 0x659e58451972d251UL,
++		  0x3875a8c473b38c31UL, 0x1fbd9ed379561f24UL,
++	/* 143 */ 0x11fabc6fd41ec28dUL, 0x7ef8dfe3cd2a2dcaUL,
++		  0x72e73b5d8c404595UL, 0x6135fa4954b72f27UL,
++	/* 144 */ 0xccfc32a2de24b69cUL, 0x3f55698c1f095d88UL,
++		  0xbe3350ed5ac3f929UL, 0x5e9bf806ca477eebUL,
++	/* 145 */ 0xe9ce8fb63c309f68UL, 0x5376f63565e1f9f4UL,
++		  0xd1afcfb35a6393f1UL, 0x6632a1ede5623506UL,
++	/* 146 */ 0x0b7d6c390c2ded4cUL, 0x56cb3281df04cb1fUL,
++		  0x66305a1249ecc3c7UL, 0x5d588b60a38ca72aUL,
++	/* 147 */ 0xa6ecbf78e8e5f42dUL, 0x86eeb44b3c8a3eecUL,
++		  0xec219c48fbd21604UL, 0x1aaf1af517c36731UL,
++	/* 148 */ 0xc306a2836769bde7UL, 0x208280622b1e2adbUL,
++		  0x8027f51ffbff94a6UL, 0x76cfa1ce1124f26bUL,
++	/* 149 */ 0x18eb00562422abb6UL, 0xf377c4d58f8c29c3UL,
++		  0x4dbbc207f531561aUL, 0x0253b7f082128a27UL,
++	/* 150 */ 0x3d1f091cb62c17e0UL, 0x4860e1abd64628a9UL,
++		  0x52d17436309d4253UL, 0x356f97e13efae576UL,
++	/* 151 */ 0xd351e11aa150535bUL, 0x3e6b45bb1dd878ccUL,
++		  0x0c776128bed92c98UL, 0x1d34ae93032885b8UL,
++	/* 152 */ 0x4ba0488ca85ba4c3UL, 0x985348c33c9ce6ceUL,
++		  0x66124c6f97bda770UL, 0x0f81a0290654124aUL,
++	/* 153 */ 0x9ed09ca6569b86fdUL, 0x811009fd18af9a2dUL,
++		  0xff08d03f93d8c20aUL, 0x52a148199faef26bUL,
++	/* 154 */ 0x3e03f9dc2d8d1b73UL, 0x4205801873961a70UL,
++		  0xc0d987f041a35970UL, 0x07aa1f15a1c0d549UL,
++	/* 155 */ 0xdfd46ce08cd27224UL, 0x6d0a024f934e4239UL,
++		  0x808a7a6399897b59UL, 0x0a4556e9e13d95a2UL,
++	/* 156 */ 0xd21a991fe9c13045UL, 0x9b0e8548fe7751b8UL,
++		  0x5da643cb4bf30035UL, 0x77db28d63940f721UL,
++	/* 157 */ 0xfc5eeb614adc9011UL, 0x5229419ae8c411ebUL,
++		  0x9ec3e7787d1dcf74UL, 0x340d053e216e4cb5UL,
++	/* 158 */ 0xcac7af39b48df2b4UL, 0xc0faec2871a10a94UL,
++		  0x140a69245ca575edUL, 0x0cf1c37134273a4cUL,
++	/* 159 */ 0xc8ee306ac224b8a5UL, 0x57eaee7ccb4930b0UL,
++		  0xa1e806bdaacbe74fUL, 0x7d9a62742eeb657dUL,
++	/* 160 */ 0x9eb6b6ef546c4830UL, 0x885cca1fddb36e2eUL,
++		  0xe6b9f383ef0d7105UL, 0x58654fef9d2e0412UL,
++	/* 161 */ 0xa905c4ffbe0e8e26UL, 0x942de5df9b31816eUL,
++		  0x497d723f802e88e1UL, 0x30684dea602f408dUL,
++	/* 162 */ 0x21e5a278a3e6cb34UL, 0xaefb6e6f5b151dc4UL,
++		  0xb30b8e049d77ca15UL, 0x28c3c9cf53b98981UL,
++	/* 163 */ 0x287fb721556cdd2aUL, 0x0d317ca897022274UL,
++		  0x7468c7423a543258UL, 0x4a7f11464eb5642fUL,
++	/* 164 */ 0xa237a4774d193aa6UL, 0xd865986ea92129a1UL,
++		  0x24c515ecf87c1a88UL, 0x604003575f39f5ebUL,
++	/* 165 */ 0x47b9f189570a9b27UL, 0x2b98cede465e4b78UL,
++		  0x026df551dbb85c20UL, 0x74fcd91047e21901UL,
++	/* 166 */ 0x13e2a90a23c1bfa3UL, 0x0cb0074e478519f6UL,
++		  0x5ff1cbbe3af6cf44UL, 0x67fe5438be812dbeUL,
++	/* 167 */ 0xd13cf64fa40f05b0UL, 0x054dfb2f32283787UL,
++		  0x4173915b7f0d2aeaUL, 0x482f144f1f610d4eUL,
++	/* 168 */ 0xf6210201b47f8234UL, 0x5d0ae1929e70b990UL,
++		  0xdcd7f455b049567cUL, 0x7e93d0f1f0916f01UL,
++	/* 169 */ 0xdd79cbf18a7db4faUL, 0xbe8391bf6f74c62fUL,
++		  0x027145d14b8291bdUL, 0x585a73ea2cbf1705UL,
++	/* 170 */ 0x485ca03e928a0db2UL, 0x10fc01a5742857e7UL,
++		  0x2f482edbd6d551a7UL, 0x0f0433b5048fdb8aUL,
++	/* 171 */ 0x60da2e8dd7dc6247UL, 0x88b4c9d38cd4819aUL,
++		  0x13033ac001f66697UL, 0x273b24fe3b367d75UL,
++	/* 172 */ 0xc6e8f66a31b3b9d4UL, 0x281514a494df49d5UL,
++		  0xd1726fdfc8b23da7UL, 0x4b3ae7d103dee548UL,
++	/* 173 */ 0xc6256e19ce4b9d7eUL, 0xff5c5cf186e3c61cUL,
++		  0xacc63ca34b8ec145UL, 0x74621888fee66574UL,
++	/* 174 */ 0x956f409645290a1eUL, 0xef0bf8e3263a962eUL,
++		  0xed6a50eb5ec2647bUL, 0x0694283a9dca7502UL,
++	/* 175 */ 0x769b963643a2dcd1UL, 0x42b7c8ea09fc5353UL,
++		  0x4f002aee13397eabUL, 0x63005e2c19b7d63aUL,
++	/* 176 */ 0xca6736da63023beaUL, 0x966c7f6db12a99b7UL,
++		  0xace09390c537c5e1UL, 0x0b696063a1aa89eeUL,
++	/* 177 */ 0xebb03e97288c56e5UL, 0x432a9f9f938c8be8UL,
++		  0xa6a5a93d5b717f71UL, 0x1a5fb4c3e18f9d97UL,
++	/* 178 */ 0x1c94e7ad1c60cdceUL, 0xee202a43fc02c4a0UL,
++		  0x8dafe4d867c46a20UL, 0x0a10263c8ac27b58UL,
++	/* 179 */ 0xd0dea9dfe4432a4aUL, 0x856af87bbe9277c5UL,
++		  0xce8472acc212c71aUL, 0x6f151b6d9bbb1e91UL,
++	/* 180 */ 0x26776c527ceed56aUL, 0x7d211cb7fbf8faecUL,
++		  0x37ae66a6fd4609ccUL, 0x1f81b702d2770c42UL,
++	/* 181 */ 0x2fb0b057eac58392UL, 0xe1dd89fe29744e9dUL,
++		  0xc964f8eb17beb4f8UL, 0x29571073c9a2d41eUL,
++	/* 182 */ 0xa948a18981c0e254UL, 0x2df6369b65b22830UL,
++		  0xa33eb2d75fcfd3c6UL, 0x078cd6ec4199a01fUL,
++	/* 183 */ 0x4a584a41ad900d2fUL, 0x32142b78e2c74c52UL,
++		  0x68c4e8338431c978UL, 0x7f69ea9008689fc2UL,
++	/* 184 */ 0x52f2c81e46a38265UL, 0xfd78072d04a832fdUL,
++		  0x8cd7d5fa25359e94UL, 0x4de71b7454cc29d2UL,
++	/* 185 */ 0x42eb60ad1eda6ac9UL, 0x0aad37dfdbc09c3aUL,
++		  0x81004b71e33cc191UL, 0x44e6be345122803cUL,
++	/* 186 */ 0x03fe8388ba1920dbUL, 0xf5d57c32150db008UL,
++		  0x49c8c4281af60c29UL, 0x21edb518de701aeeUL,
++	/* 187 */ 0x7fb63e418f06dc99UL, 0xa4460d99c166d7b8UL,
++		  0x24dd5248ce520a83UL, 0x5ec3ad712b928358UL,
++	/* 188 */ 0x15022a5fbd17930fUL, 0xa4f64a77d82570e3UL,
++		  0x12bc8d6915783712UL, 0x498194c0fc620abbUL,
++	/* 189 */ 0x38a2d9d255686c82UL, 0x785c6bd9193e21f0UL,
++		  0xe4d5c81ab24a5484UL, 0x56307860b2e20989UL,
++	/* 190 */ 0x429d55f78b4d74c4UL, 0x22f1834643350131UL,
++		  0x1e60c24598c71fffUL, 0x59f2f014979983efUL,
++	/* 191 */ 0x46a47d56eb494a44UL, 0x3e22a854d636a18eUL,
++		  0xb346e15274491c3bUL, 0x2ceafd4e5390cde7UL,
++	/* 192 */ 0xba8a8538be0d6675UL, 0x4b9074bb50818e23UL,
++		  0xcbdab89085d304c3UL, 0x61a24fe0e56192c4UL,
++	/* 193 */ 0xcb7615e6db525bcbUL, 0xdd7d8c35a567e4caUL,
++		  0xe6b4153acafcdd69UL, 0x2d668e097f3c9766UL,
++	/* 194 */ 0xa57e7e265ce55ef0UL, 0x5d9f4e527cd4b967UL,
++		  0xfbc83606492fd1e5UL, 0x090d52beb7c3f7aeUL,
++	/* 195 */ 0x09b9515a1e7b4d7cUL, 0x1f266a2599da44c0UL,
++		  0xa1c49548e2c55504UL, 0x7ef04287126f15ccUL,
++	/* 196 */ 0xfed1659dbd30ef15UL, 0x8b4ab9eec4e0277bUL,
++		  0x884d6236a5df3291UL, 0x1fd96ea6bf5cf788UL,
++	/* 197 */ 0x42a161981f190d9aUL, 0x61d849507e6052c1UL,
++		  0x9fe113bf285a2cd5UL, 0x7c22d676dbad85d8UL,
++	/* 198 */ 0x82e770ed2bfbd27dUL, 0x4c05b2ece996f5a5UL,
++		  0xcd40a9c2b0900150UL, 0x5895319213d9bf64UL,
++	/* 199 */ 0xe7cc5d703fea2e08UL, 0xb50c491258e2188cUL,
++		  0xcce30baa48205bf0UL, 0x537c659ccfa32d62UL,
++	/* 200 */ 0x37b6623a98cfc088UL, 0xfe9bed1fa4d6aca4UL,
++		  0x04d29b8e56a8d1b0UL, 0x725f71c40b519575UL,
++	/* 201 */ 0x28c7f89cd0339ce6UL, 0x8367b14469ddc18bUL,
++		  0x883ada83a6a1652cUL, 0x585f1974034d6c17UL,
++	/* 202 */ 0x89cfb266f1b19188UL, 0xe63b4863e7c35217UL,
++		  0xd88c9da6b4c0526aUL, 0x3e035c9df0954635UL,
++	/* 203 */ 0xdd9d5412fb45de9dUL, 0xdd684532e4cff40dUL,
++		  0x4b5c999b151d671cUL, 0x2d8c2cc811e7f690UL,
++	/* 204 */ 0x7f54be1d90055d40UL, 0xa464c5df464aaf40UL,
++		  0x33979624f0e917beUL, 0x2c018dc527356b30UL,
++	/* 205 */ 0xa5415024e330b3d4UL, 0x73ff3d96691652d3UL,
++		  0x94ec42c4ef9b59f1UL, 0x0747201618d08e5aUL,
++	/* 206 */ 0x4d6ca48aca411c53UL, 0x66415f2fcfa66119UL,
++		  0x9c4dd40051e227ffUL, 0x59810bc09a02f7ebUL,
++	/* 207 */ 0x2a7eb171b3dc101dUL, 0x441c5ab99ffef68eUL,
++		  0x32025c9b93b359eaUL, 0x5e8ce0a71e9d112fUL,
++	/* 208 */ 0xbfcccb92429503fdUL, 0xd271ba752f095d55UL,
++		  0x345ead5e972d091eUL, 0x18c8df11a83103baUL,
++	/* 209 */ 0x90cd949a9aed0f4cUL, 0xc5d1f4cb6660e37eUL,
++		  0xb8cac52d56c52e0bUL, 0x6e42e400c5808e0dUL,
++	/* 210 */ 0xa3b46966eeaefd23UL, 0x0c4f1f0be39ecdcaUL,
++		  0x189dc8c9d683a51dUL, 0x51f27f054c09351bUL,
++	/* 211 */ 0x4c487ccd2a320682UL, 0x587ea95bb3df1c96UL,
++		  0xc8ccf79e555cb8e8UL, 0x547dc829a206d73dUL,
++	/* 212 */ 0xb822a6cd80c39b06UL, 0xe96d54732000d4c6UL,
++		  0x28535b6f91463b4dUL, 0x228f4660e2486e1dUL,
++	/* 213 */ 0x98799538de8d3abfUL, 0x8cd8330045ebca6eUL,
++		  0x79952a008221e738UL, 0x4322e1a7535cd2bbUL,
++	/* 214 */ 0xb114c11819d1801cUL, 0x2016e4d84f3f5ec7UL,
++		  0xdd0e2df409260f4cUL, 0x5ec362c0ae5f7266UL,
++	/* 215 */ 0xc0462b18b8b2b4eeUL, 0x7cc8d950274d1afbUL,
++		  0xf25f7105436b02d2UL, 0x43bbf8dcbff9ccd3UL,
++	/* 216 */ 0xb6ad1767a039e9dfUL, 0xb0714da8f69d3583UL,
++		  0x5e55fa18b42931f5UL, 0x4ed5558f33c60961UL,
++	/* 217 */ 0x1fe37901c647a5ddUL, 0x593ddf1f8081d357UL,
++		  0x0249a4fd813fd7a6UL, 0x69acca274e9caf61UL,
++	/* 218 */ 0x047ba3ea330721c9UL, 0x83423fc20e7e1ea0UL,
++		  0x1df4c0af01314a60UL, 0x09a62dab89289527UL,
++	/* 219 */ 0xa5b325a49cc6cb00UL, 0xe94b5dc654b56cb6UL,
++		  0x3be28779adc994a0UL, 0x4296e8f8ba3a4aadUL,
++	/* 220 */ 0x328689761e451eabUL, 0x2e4d598bff59594aUL,
++		  0x49b96853d7a7084aUL, 0x4980a319601420a8UL,
++	/* 221 */ 0x9565b9e12f552c42UL, 0x8a5318db7100fe96UL,
++		  0x05c90b4d43add0d7UL, 0x538b4cd66a5d4edaUL,
++	/* 222 */ 0xf4e94fc3e89f039fUL, 0x592c9af26f618045UL,
++		  0x08a36eb5fd4b9550UL, 0x25fffaf6c2ed1419UL,
++	/* 223 */ 0x34434459cc79d354UL, 0xeeecbfb4b1d5476bUL,
++		  0xddeb34a061615d99UL, 0x5129cecceb64b773UL,
++	/* 224 */ 0xee43215894993520UL, 0x772f9c7cf14c0b3bUL,
++		  0xd2e2fce306bedad5UL, 0x715f42b546f06a97UL,
++	/* 225 */ 0x434ecdceda5b5f1aUL, 0x0da17115a49741a9UL,
++		  0x680bd77c73edad2eUL, 0x487c02354edd9041UL,
++	/* 226 */ 0xb8efeff3a70ed9c4UL, 0x56a32aa3e857e302UL,
++		  0xdf3a68bd48a2a5a0UL, 0x07f650b73176c444UL,
++	/* 227 */ 0xe38b9b1626e0ccb1UL, 0x79e053c18b09fb36UL,
++		  0x56d90319c9f94964UL, 0x1ca941e7ac9ff5c4UL,
++	/* 228 */ 0x49c4df29162fa0bbUL, 0x8488cf3282b33305UL,
++		  0x95dfda14cabb437dUL, 0x3391f78264d5ad86UL,
++	/* 229 */ 0x729ae06ae2b5095dUL, 0xd58a58d73259a946UL,
++		  0xe9834262d13921edUL, 0x27fedafaa54bb592UL,
++	/* 230 */ 0xa99dc5b829ad48bbUL, 0x5f025742499ee260UL,
++		  0x802c8ecd5d7513fdUL, 0x78ceb3ef3f6dd938UL,
++	/* 231 */ 0xc342f44f8a135d94UL, 0x7b9edb44828cdda3UL,
++		  0x9436d11a0537cfe7UL, 0x5064b164ec1ab4c8UL,
++	/* 232 */ 0x7020eccfd37eb2fcUL, 0x1f31ea3ed90d25fcUL,
++		  0x1b930d7bdfa1bb34UL, 0x5344467a48113044UL,
++	/* 233 */ 0x70073170f25e6dfbUL, 0xe385dc1a50114cc8UL,
++		  0x2348698ac8fc4f00UL, 0x2a77a55284dd40d8UL,
++	/* 234 */ 0xfe06afe0c98c6ce4UL, 0xc235df96dddfd6e4UL,
++		  0x1428d01e33bf1ed3UL, 0x785768ec9300bdafUL,
++	/* 235 */ 0x9702e57a91deb63bUL, 0x61bdb8bfe5ce8b80UL,
++		  0x645b426f3d1d58acUL, 0x4804a82227a557bcUL,
++	/* 236 */ 0x8e57048ab44d2601UL, 0x68d6501a4b3a6935UL,
++		  0xc39c9ec3f9e1c293UL, 0x4172f257d4de63e2UL,
++	/* 237 */ 0xd368b450330c6401UL, 0x040d3017418f2391UL,
++		  0x2c34bb6090b7d90dUL, 0x16f649228fdfd51fUL,
++	/* 238 */ 0xbea6818e2b928ef5UL, 0xe28ccf91cdc11e72UL,
++		  0x594aaa68e77a36cdUL, 0x313034806c7ffd0fUL,
++	/* 239 */ 0x8a9d27ac2249bd65UL, 0x19a3b464018e9512UL,
++		  0xc26ccff352b37ec7UL, 0x056f68341d797b21UL,
++	/* 240 */ 0x5e79d6757efd2327UL, 0xfabdbcb6553afe15UL,
++		  0xd3e7222c6eaf5a60UL, 0x7046c76d4dae743bUL,
++	/* 241 */ 0x660be872b18d4a55UL, 0x19992518574e1496UL,
++		  0xc103053a302bdcbbUL, 0x3ed8e9800b218e8eUL,
++	/* 242 */ 0x7b0b9239fa75e03eUL, 0xefe9fb684633c083UL,
++		  0x98a35fbe391a7793UL, 0x6065510fe2d0fe34UL,
++	/* 243 */ 0x55cb668548abad0cUL, 0xb4584548da87e527UL,
++		  0x2c43ecea0107c1ddUL, 0x526028809372de35UL,
++	/* 244 */ 0x3415c56af9213b1fUL, 0x5bee1a4d017e98dbUL,
++		  0x13f6b105b5cf709bUL, 0x5ff20e3482b29ab6UL,
++	/* 245 */ 0x0aa29c75cc2e6c90UL, 0xfc7d73ca3a70e206UL,
++		  0x899fc38fc4b5c515UL, 0x250386b124ffc207UL,
++	/* 246 */ 0x54ea28d5ae3d2b56UL, 0x9913149dd6de60ceUL,
++		  0x16694fc58f06d6c1UL, 0x46b23975eb018fc7UL,
++	/* 247 */ 0x470a6a0fb4b7b4e2UL, 0x5d92475a8f7253deUL,
++		  0xabeee5b52fbd3adbUL, 0x7fa20801a0806968UL,
++	/* 248 */ 0x76f3faf19f7714d2UL, 0xb3e840c12f4660c3UL,
++		  0x0fb4cd8df212744eUL, 0x4b065a251d3a2dd2UL,
++	/* 249 */ 0x5cebde383d77cd4aUL, 0x6adf39df882c9cb1UL,
++		  0xa2dd242eb09af759UL, 0x3147c0e50e5f6422UL,
++	/* 250 */ 0x164ca5101d1350dbUL, 0xf8d13479c33fc962UL,
++		  0xe640ce4d13e5da08UL, 0x4bdee0c45061f8baUL,
++	/* 251 */ 0xd7c46dc1a4edb1c9UL, 0x5514d7b6437fd98aUL,
++		  0x58942f6bb2a1c00bUL, 0x2dffb2ab1d70710eUL,
++	/* 252 */ 0xccdfcf2fc18b6d68UL, 0xa8ebcba8b7806167UL,
++		  0x980697f95e2937e3UL, 0x02fbba1cd0126e8cUL
++};
++
++/* c is two 512-bit products: c0[0:7]=a0[0:3]*b0[0:3] and c1[8:15]=a1[4:7]*b1[4:7]
++ * a is two 256-bit integers: a0[0:3] and a1[4:7]
++ * b is two 256-bit integers: b0[0:3] and b1[4:7]
++ */
++static void mul2_256x256_integer_adx(u64 *const c, const u64 *const a,
++				     const u64 *const b)
++{
++	asm volatile(
++		"xorl %%r14d, %%r14d ;"
++		"movq   (%1), %%rdx; "	/* A[0] */
++		"mulx   (%2),  %%r8, %%r15; " /* A[0]*B[0] */
++		"xorl %%r10d, %%r10d ;"
++		"movq %%r8, (%0) ;"
++		"mulx  8(%2), %%r10, %%rax; " /* A[0]*B[1] */
++		"adox %%r10, %%r15 ;"
++		"mulx 16(%2),  %%r8, %%rbx; " /* A[0]*B[2] */
++		"adox  %%r8, %%rax ;"
++		"mulx 24(%2), %%r10, %%rcx; " /* A[0]*B[3] */
++		"adox %%r10, %%rbx ;"
++		/******************************************/
++		"adox %%r14, %%rcx ;"
++
++		"movq  8(%1), %%rdx; "	/* A[1] */
++		"mulx   (%2),  %%r8,  %%r9; " /* A[1]*B[0] */
++		"adox %%r15,  %%r8 ;"
++		"movq  %%r8, 8(%0) ;"
++		"mulx  8(%2), %%r10, %%r11; " /* A[1]*B[1] */
++		"adox %%r10,  %%r9 ;"
++		"adcx  %%r9, %%rax ;"
++		"mulx 16(%2),  %%r8, %%r13; " /* A[1]*B[2] */
++		"adox  %%r8, %%r11 ;"
++		"adcx %%r11, %%rbx ;"
++		"mulx 24(%2), %%r10, %%r15; " /* A[1]*B[3] */
++		"adox %%r10, %%r13 ;"
++		"adcx %%r13, %%rcx ;"
++		/******************************************/
++		"adox %%r14, %%r15 ;"
++		"adcx %%r14, %%r15 ;"
++
++		"movq 16(%1), %%rdx; " /* A[2] */
++		"xorl %%r10d, %%r10d ;"
++		"mulx   (%2),  %%r8,  %%r9; " /* A[2]*B[0] */
++		"adox %%rax,  %%r8 ;"
++		"movq %%r8, 16(%0) ;"
++		"mulx  8(%2), %%r10, %%r11; " /* A[2]*B[1] */
++		"adox %%r10,  %%r9 ;"
++		"adcx  %%r9, %%rbx ;"
++		"mulx 16(%2),  %%r8, %%r13; " /* A[2]*B[2] */
++		"adox  %%r8, %%r11 ;"
++		"adcx %%r11, %%rcx ;"
++		"mulx 24(%2), %%r10, %%rax; " /* A[2]*B[3] */
++		"adox %%r10, %%r13 ;"
++		"adcx %%r13, %%r15 ;"
++		/******************************************/
++		"adox %%r14, %%rax ;"
++		"adcx %%r14, %%rax ;"
++
++		"movq 24(%1), %%rdx; " /* A[3] */
++		"xorl %%r10d, %%r10d ;"
++		"mulx   (%2),  %%r8,  %%r9; " /* A[3]*B[0] */
++		"adox %%rbx,  %%r8 ;"
++		"movq %%r8, 24(%0) ;"
++		"mulx  8(%2), %%r10, %%r11; " /* A[3]*B[1] */
++		"adox %%r10,  %%r9 ;"
++		"adcx  %%r9, %%rcx ;"
++		"movq %%rcx, 32(%0) ;"
++		"mulx 16(%2),  %%r8, %%r13; " /* A[3]*B[2] */
++		"adox  %%r8, %%r11 ;"
++		"adcx %%r11, %%r15 ;"
++		"movq %%r15, 40(%0) ;"
++		"mulx 24(%2), %%r10, %%rbx; " /* A[3]*B[3] */
++		"adox %%r10, %%r13 ;"
++		"adcx %%r13, %%rax ;"
++		"movq %%rax, 48(%0) ;"
++		/******************************************/
++		"adox %%r14, %%rbx ;"
++		"adcx %%r14, %%rbx ;"
++		"movq %%rbx, 56(%0) ;"
++
++		"movq 32(%1), %%rdx; "	/* C[0] */
++		"mulx 32(%2),  %%r8, %%r15; " /* C[0]*D[0] */
++		"xorl %%r10d, %%r10d ;"
++		"movq %%r8, 64(%0);"
++		"mulx 40(%2), %%r10, %%rax; " /* C[0]*D[1] */
++		"adox %%r10, %%r15 ;"
++		"mulx 48(%2),  %%r8, %%rbx; " /* C[0]*D[2] */
++		"adox  %%r8, %%rax ;"
++		"mulx 56(%2), %%r10, %%rcx; " /* C[0]*D[3] */
++		"adox %%r10, %%rbx ;"
++		/******************************************/
++		"adox %%r14, %%rcx ;"
++
++		"movq 40(%1), %%rdx; " /* C[1] */
++		"xorl %%r10d, %%r10d ;"
++		"mulx 32(%2),  %%r8,  %%r9; " /* C[1]*D[0] */
++		"adox %%r15,  %%r8 ;"
++		"movq  %%r8, 72(%0);"
++		"mulx 40(%2), %%r10, %%r11; " /* C[1]*D[1] */
++		"adox %%r10,  %%r9 ;"
++		"adcx  %%r9, %%rax ;"
++		"mulx 48(%2),  %%r8, %%r13; " /* C[1]*D[2] */
++		"adox  %%r8, %%r11 ;"
++		"adcx %%r11, %%rbx ;"
++		"mulx 56(%2), %%r10, %%r15; " /* C[1]*D[3] */
++		"adox %%r10, %%r13 ;"
++		"adcx %%r13, %%rcx ;"
++		/******************************************/
++		"adox %%r14, %%r15 ;"
++		"adcx %%r14, %%r15 ;"
++
++		"movq 48(%1), %%rdx; " /* C[2] */
++		"xorl %%r10d, %%r10d ;"
++		"mulx 32(%2),  %%r8,  %%r9; " /* C[2]*D[0] */
++		"adox %%rax,  %%r8 ;"
++		"movq  %%r8, 80(%0);"
++		"mulx 40(%2), %%r10, %%r11; " /* C[2]*D[1] */
++		"adox %%r10,  %%r9 ;"
++		"adcx  %%r9, %%rbx ;"
++		"mulx 48(%2),  %%r8, %%r13; " /* C[2]*D[2] */
++		"adox  %%r8, %%r11 ;"
++		"adcx %%r11, %%rcx ;"
++		"mulx 56(%2), %%r10, %%rax; " /* C[2]*D[3] */
++		"adox %%r10, %%r13 ;"
++		"adcx %%r13, %%r15 ;"
++		/******************************************/
++		"adox %%r14, %%rax ;"
++		"adcx %%r14, %%rax ;"
++
++		"movq 56(%1), %%rdx; " /* C[3] */
++		"xorl %%r10d, %%r10d ;"
++		"mulx 32(%2),  %%r8,  %%r9; " /* C[3]*D[0] */
++		"adox %%rbx,  %%r8 ;"
++		"movq  %%r8, 88(%0);"
++		"mulx 40(%2), %%r10, %%r11; " /* C[3]*D[1] */
++		"adox %%r10,  %%r9 ;"
++		"adcx  %%r9, %%rcx ;"
++		"movq %%rcx,  96(%0) ;"
++		"mulx 48(%2),  %%r8, %%r13; " /* C[3]*D[2] */
++		"adox  %%r8, %%r11 ;"
++		"adcx %%r11, %%r15 ;"
++		"movq %%r15, 104(%0) ;"
++		"mulx 56(%2), %%r10, %%rbx; " /* C[3]*D[3] */
++		"adox %%r10, %%r13 ;"
++		"adcx %%r13, %%rax ;"
++		"movq %%rax, 112(%0) ;"
++		/******************************************/
++		"adox %%r14, %%rbx ;"
++		"adcx %%r14, %%rbx ;"
++		"movq %%rbx, 120(%0) ;"
++		:
++		: "r"(c), "r"(a), "r"(b)
++		: "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9",
++		  "%r10", "%r11", "%r13", "%r14", "%r15");
++}
++
++static void mul2_256x256_integer_bmi2(u64 *const c, const u64 *const a,
++				      const u64 *const b)
++{
++	asm volatile(
++		"movq   (%1), %%rdx; "	/* A[0] */
++		"mulx   (%2),  %%r8, %%r15; " /* A[0]*B[0] */
++		"movq %%r8,  (%0) ;"
++		"mulx  8(%2), %%r10, %%rax; " /* A[0]*B[1] */
++		"addq %%r10, %%r15 ;"
++		"mulx 16(%2),  %%r8, %%rbx; " /* A[0]*B[2] */
++		"adcq  %%r8, %%rax ;"
++		"mulx 24(%2), %%r10, %%rcx; " /* A[0]*B[3] */
++		"adcq %%r10, %%rbx ;"
++		/******************************************/
++		"adcq    $0, %%rcx ;"
++
++		"movq  8(%1), %%rdx; "	/* A[1] */
++		"mulx   (%2),  %%r8,  %%r9; " /* A[1]*B[0] */
++		"addq %%r15,  %%r8 ;"
++		"movq %%r8, 8(%0) ;"
++		"mulx  8(%2), %%r10, %%r11; " /* A[1]*B[1] */
++		"adcq %%r10,  %%r9 ;"
++		"mulx 16(%2),  %%r8, %%r13; " /* A[1]*B[2] */
++		"adcq  %%r8, %%r11 ;"
++		"mulx 24(%2), %%r10, %%r15; " /* A[1]*B[3] */
++		"adcq %%r10, %%r13 ;"
++		/******************************************/
++		"adcq    $0, %%r15 ;"
++
++		"addq  %%r9, %%rax ;"
++		"adcq %%r11, %%rbx ;"
++		"adcq %%r13, %%rcx ;"
++		"adcq    $0, %%r15 ;"
++
++		"movq 16(%1), %%rdx; "	/* A[2] */
++		"mulx   (%2),  %%r8,  %%r9; " /* A[2]*B[0] */
++		"addq %%rax,  %%r8 ;"
++		"movq %%r8, 16(%0) ;"
++		"mulx  8(%2), %%r10, %%r11; " /* A[2]*B[1] */
++		"adcq %%r10,  %%r9 ;"
++		"mulx 16(%2),  %%r8, %%r13; " /* A[2]*B[2] */
++		"adcq  %%r8, %%r11 ;"
++		"mulx 24(%2), %%r10, %%rax; " /* A[2]*B[3] */
++		"adcq %%r10, %%r13 ;"
++		/******************************************/
++		"adcq    $0, %%rax ;"
++
++		"addq  %%r9, %%rbx ;"
++		"adcq %%r11, %%rcx ;"
++		"adcq %%r13, %%r15 ;"
++		"adcq    $0, %%rax ;"
++
++		"movq 24(%1), %%rdx; "	/* A[3] */
++		"mulx   (%2),  %%r8,  %%r9; " /* A[3]*B[0] */
++		"addq %%rbx,  %%r8 ;"
++		"movq %%r8, 24(%0) ;"
++		"mulx  8(%2), %%r10, %%r11; " /* A[3]*B[1] */
++		"adcq %%r10,  %%r9 ;"
++		"mulx 16(%2),  %%r8, %%r13; " /* A[3]*B[2] */
++		"adcq  %%r8, %%r11 ;"
++		"mulx 24(%2), %%r10, %%rbx; " /* A[3]*B[3] */
++		"adcq %%r10, %%r13 ;"
++		/******************************************/
++		"adcq    $0, %%rbx ;"
++
++		"addq  %%r9, %%rcx ;"
++		"movq %%rcx, 32(%0) ;"
++		"adcq %%r11, %%r15 ;"
++		"movq %%r15, 40(%0) ;"
++		"adcq %%r13, %%rax ;"
++		"movq %%rax, 48(%0) ;"
++		"adcq    $0, %%rbx ;"
++		"movq %%rbx, 56(%0) ;"
++
++		"movq 32(%1), %%rdx; "	/* C[0] */
++		"mulx 32(%2),  %%r8, %%r15; " /* C[0]*D[0] */
++		"movq %%r8, 64(%0) ;"
++		"mulx 40(%2), %%r10, %%rax; " /* C[0]*D[1] */
++		"addq %%r10, %%r15 ;"
++		"mulx 48(%2),  %%r8, %%rbx; " /* C[0]*D[2] */
++		"adcq  %%r8, %%rax ;"
++		"mulx 56(%2), %%r10, %%rcx; " /* C[0]*D[3] */
++		"adcq %%r10, %%rbx ;"
++		/******************************************/
++		"adcq    $0, %%rcx ;"
++
++		"movq 40(%1), %%rdx; "	/* C[1] */
++		"mulx 32(%2),  %%r8,  %%r9; " /* C[1]*D[0] */
++		"addq %%r15,  %%r8 ;"
++		"movq %%r8, 72(%0) ;"
++		"mulx 40(%2), %%r10, %%r11; " /* C[1]*D[1] */
++		"adcq %%r10,  %%r9 ;"
++		"mulx 48(%2),  %%r8, %%r13; " /* C[1]*D[2] */
++		"adcq  %%r8, %%r11 ;"
++		"mulx 56(%2), %%r10, %%r15; " /* C[1]*D[3] */
++		"adcq %%r10, %%r13 ;"
++		/******************************************/
++		"adcq    $0, %%r15 ;"
++
++		"addq  %%r9, %%rax ;"
++		"adcq %%r11, %%rbx ;"
++		"adcq %%r13, %%rcx ;"
++		"adcq    $0, %%r15 ;"
++
++		"movq 48(%1), %%rdx; "	/* C[2] */
++		"mulx 32(%2),  %%r8,  %%r9; " /* C[2]*D[0] */
++		"addq %%rax,  %%r8 ;"
++		"movq %%r8, 80(%0) ;"
++		"mulx 40(%2), %%r10, %%r11; " /* C[2]*D[1] */
++		"adcq %%r10,  %%r9 ;"
++		"mulx 48(%2),  %%r8, %%r13; " /* C[2]*D[2] */
++		"adcq  %%r8, %%r11 ;"
++		"mulx 56(%2), %%r10, %%rax; " /* C[2]*D[3] */
++		"adcq %%r10, %%r13 ;"
++		/******************************************/
++		"adcq    $0, %%rax ;"
++
++		"addq  %%r9, %%rbx ;"
++		"adcq %%r11, %%rcx ;"
++		"adcq %%r13, %%r15 ;"
++		"adcq    $0, %%rax ;"
++
++		"movq 56(%1), %%rdx; "	/* C[3] */
++		"mulx 32(%2),  %%r8,  %%r9; " /* C[3]*D[0] */
++		"addq %%rbx,  %%r8 ;"
++		"movq %%r8, 88(%0) ;"
++		"mulx 40(%2), %%r10, %%r11; " /* C[3]*D[1] */
++		"adcq %%r10,  %%r9 ;"
++		"mulx 48(%2),  %%r8, %%r13; " /* C[3]*D[2] */
++		"adcq  %%r8, %%r11 ;"
++		"mulx 56(%2), %%r10, %%rbx; " /* C[3]*D[3] */
++		"adcq %%r10, %%r13 ;"
++		/******************************************/
++		"adcq    $0, %%rbx ;"
++
++		"addq  %%r9, %%rcx ;"
++		"movq %%rcx,  96(%0) ;"
++		"adcq %%r11, %%r15 ;"
++		"movq %%r15, 104(%0) ;"
++		"adcq %%r13, %%rax ;"
++		"movq %%rax, 112(%0) ;"
++		"adcq    $0, %%rbx ;"
++		"movq %%rbx, 120(%0) ;"
++		:
++		: "r"(c), "r"(a), "r"(b)
++		: "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9",
++		  "%r10", "%r11", "%r13", "%r15");
++}
++
++static void sqr2_256x256_integer_adx(u64 *const c, const u64 *const a)
++{
++	asm volatile(
++		"movq   (%1), %%rdx        ;" /* A[0]      */
++		"mulx  8(%1),  %%r8, %%r14 ;" /* A[1]*A[0] */
++		"xorl %%r15d, %%r15d;"
++		"mulx 16(%1),  %%r9, %%r10 ;" /* A[2]*A[0] */
++		"adcx %%r14,  %%r9 ;"
++		"mulx 24(%1), %%rax, %%rcx ;" /* A[3]*A[0] */
++		"adcx %%rax, %%r10 ;"
++		"movq 24(%1), %%rdx        ;" /* A[3]      */
++		"mulx  8(%1), %%r11, %%rbx ;" /* A[1]*A[3] */
++		"adcx %%rcx, %%r11 ;"
++		"mulx 16(%1), %%rax, %%r13 ;" /* A[2]*A[3] */
++		"adcx %%rax, %%rbx ;"
++		"movq  8(%1), %%rdx        ;" /* A[1]      */
++		"adcx %%r15, %%r13 ;"
++		"mulx 16(%1), %%rax, %%rcx ;" /* A[2]*A[1] */
++		"movq    $0, %%r14 ;"
++		/******************************************/
++		"adcx %%r15, %%r14 ;"
++
++		"xorl %%r15d, %%r15d;"
++		"adox %%rax, %%r10 ;"
++		"adcx  %%r8,  %%r8 ;"
++		"adox %%rcx, %%r11 ;"
++		"adcx  %%r9,  %%r9 ;"
++		"adox %%r15, %%rbx ;"
++		"adcx %%r10, %%r10 ;"
++		"adox %%r15, %%r13 ;"
++		"adcx %%r11, %%r11 ;"
++		"adox %%r15, %%r14 ;"
++		"adcx %%rbx, %%rbx ;"
++		"adcx %%r13, %%r13 ;"
++		"adcx %%r14, %%r14 ;"
++
++		"movq   (%1), %%rdx ;"
++		"mulx %%rdx, %%rax, %%rcx ;" /* A[0]^2 */
++		/*******************/
++		"movq %%rax,  0(%0) ;"
++		"addq %%rcx,  %%r8 ;"
++		"movq  %%r8,  8(%0) ;"
++		"movq  8(%1), %%rdx ;"
++		"mulx %%rdx, %%rax, %%rcx ;" /* A[1]^2 */
++		"adcq %%rax,  %%r9 ;"
++		"movq  %%r9, 16(%0) ;"
++		"adcq %%rcx, %%r10 ;"
++		"movq %%r10, 24(%0) ;"
++		"movq 16(%1), %%rdx ;"
++		"mulx %%rdx, %%rax, %%rcx ;" /* A[2]^2 */
++		"adcq %%rax, %%r11 ;"
++		"movq %%r11, 32(%0) ;"
++		"adcq %%rcx, %%rbx ;"
++		"movq %%rbx, 40(%0) ;"
++		"movq 24(%1), %%rdx ;"
++		"mulx %%rdx, %%rax, %%rcx ;" /* A[3]^2 */
++		"adcq %%rax, %%r13 ;"
++		"movq %%r13, 48(%0) ;"
++		"adcq %%rcx, %%r14 ;"
++		"movq %%r14, 56(%0) ;"
++
++
++		"movq 32(%1), %%rdx        ;" /* B[0]      */
++		"mulx 40(%1),  %%r8, %%r14 ;" /* B[1]*B[0] */
++		"xorl %%r15d, %%r15d;"
++		"mulx 48(%1),  %%r9, %%r10 ;" /* B[2]*B[0] */
++		"adcx %%r14,  %%r9 ;"
++		"mulx 56(%1), %%rax, %%rcx ;" /* B[3]*B[0] */
++		"adcx %%rax, %%r10 ;"
++		"movq 56(%1), %%rdx        ;" /* B[3]      */
++		"mulx 40(%1), %%r11, %%rbx ;" /* B[1]*B[3] */
++		"adcx %%rcx, %%r11 ;"
++		"mulx 48(%1), %%rax, %%r13 ;" /* B[2]*B[3] */
++		"adcx %%rax, %%rbx ;"
++		"movq 40(%1), %%rdx        ;" /* B[1]      */
++		"adcx %%r15, %%r13 ;"
++		"mulx 48(%1), %%rax, %%rcx ;" /* B[2]*B[1] */
++		"movq    $0, %%r14 ;"
++		/******************************************/
++		"adcx %%r15, %%r14 ;"
++
++		"xorl %%r15d, %%r15d;"
++		"adox %%rax, %%r10 ;"
++		"adcx  %%r8,  %%r8 ;"
++		"adox %%rcx, %%r11 ;"
++		"adcx  %%r9,  %%r9 ;"
++		"adox %%r15, %%rbx ;"
++		"adcx %%r10, %%r10 ;"
++		"adox %%r15, %%r13 ;"
++		"adcx %%r11, %%r11 ;"
++		"adox %%r15, %%r14 ;"
++		"adcx %%rbx, %%rbx ;"
++		"adcx %%r13, %%r13 ;"
++		"adcx %%r14, %%r14 ;"
++
++		"movq 32(%1), %%rdx ;"
++		"mulx %%rdx, %%rax, %%rcx ;" /* B[0]^2 */
++		/*******************/
++		"movq %%rax,  64(%0) ;"
++		"addq %%rcx,  %%r8 ;"
++		"movq  %%r8,  72(%0) ;"
++		"movq 40(%1), %%rdx ;"
++		"mulx %%rdx, %%rax, %%rcx ;" /* B[1]^2 */
++		"adcq %%rax,  %%r9 ;"
++		"movq  %%r9,  80(%0) ;"
++		"adcq %%rcx, %%r10 ;"
++		"movq %%r10,  88(%0) ;"
++		"movq 48(%1), %%rdx ;"
++		"mulx %%rdx, %%rax, %%rcx ;" /* B[2]^2 */
++		"adcq %%rax, %%r11 ;"
++		"movq %%r11,  96(%0) ;"
++		"adcq %%rcx, %%rbx ;"
++		"movq %%rbx, 104(%0) ;"
++		"movq 56(%1), %%rdx ;"
++		"mulx %%rdx, %%rax, %%rcx ;" /* B[3]^2 */
++		"adcq %%rax, %%r13 ;"
++		"movq %%r13, 112(%0) ;"
++		"adcq %%rcx, %%r14 ;"
++		"movq %%r14, 120(%0) ;"
++		:
++		: "r"(c), "r"(a)
++		: "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9",
++		  "%r10", "%r11", "%r13", "%r14", "%r15");
++}
++
++static void sqr2_256x256_integer_bmi2(u64 *const c, const u64 *const a)
++{
++	asm volatile(
++		"movq  8(%1), %%rdx        ;" /* A[1]      */
++		"mulx   (%1),  %%r8,  %%r9 ;" /* A[0]*A[1] */
++		"mulx 16(%1), %%r10, %%r11 ;" /* A[2]*A[1] */
++		"mulx 24(%1), %%rcx, %%r14 ;" /* A[3]*A[1] */
++
++		"movq 16(%1), %%rdx        ;" /* A[2]      */
++		"mulx 24(%1), %%r15, %%r13 ;" /* A[3]*A[2] */
++		"mulx   (%1), %%rax, %%rdx ;" /* A[0]*A[2] */
++
++		"addq %%rax,  %%r9 ;"
++		"adcq %%rdx, %%r10 ;"
++		"adcq %%rcx, %%r11 ;"
++		"adcq %%r14, %%r15 ;"
++		"adcq    $0, %%r13 ;"
++		"movq    $0, %%r14 ;"
++		"adcq    $0, %%r14 ;"
++
++		"movq   (%1), %%rdx        ;" /* A[0]      */
++		"mulx 24(%1), %%rax, %%rcx ;" /* A[0]*A[3] */
++
++		"addq %%rax, %%r10 ;"
++		"adcq %%rcx, %%r11 ;"
++		"adcq    $0, %%r15 ;"
++		"adcq    $0, %%r13 ;"
++		"adcq    $0, %%r14 ;"
++
++		"shldq $1, %%r13, %%r14 ;"
++		"shldq $1, %%r15, %%r13 ;"
++		"shldq $1, %%r11, %%r15 ;"
++		"shldq $1, %%r10, %%r11 ;"
++		"shldq $1,  %%r9, %%r10 ;"
++		"shldq $1,  %%r8,  %%r9 ;"
++		"shlq  $1,  %%r8        ;"
++
++		/*******************/
++		"mulx %%rdx, %%rax, %%rcx ; " /* A[0]^2 */
++		/*******************/
++		"movq %%rax,  0(%0) ;"
++		"addq %%rcx,  %%r8 ;"
++		"movq  %%r8,  8(%0) ;"
++		"movq  8(%1), %%rdx ;"
++		"mulx %%rdx, %%rax, %%rcx ; " /* A[1]^2 */
++		"adcq %%rax,  %%r9 ;"
++		"movq  %%r9, 16(%0) ;"
++		"adcq %%rcx, %%r10 ;"
++		"movq %%r10, 24(%0) ;"
++		"movq 16(%1), %%rdx ;"
++		"mulx %%rdx, %%rax, %%rcx ; " /* A[2]^2 */
++		"adcq %%rax, %%r11 ;"
++		"movq %%r11, 32(%0) ;"
++		"adcq %%rcx, %%r15 ;"
++		"movq %%r15, 40(%0) ;"
++		"movq 24(%1), %%rdx ;"
++		"mulx %%rdx, %%rax, %%rcx ; " /* A[3]^2 */
++		"adcq %%rax, %%r13 ;"
++		"movq %%r13, 48(%0) ;"
++		"adcq %%rcx, %%r14 ;"
++		"movq %%r14, 56(%0) ;"
++
++		"movq 40(%1), %%rdx        ;" /* B[1]      */
++		"mulx 32(%1),  %%r8,  %%r9 ;" /* B[0]*B[1] */
++		"mulx 48(%1), %%r10, %%r11 ;" /* B[2]*B[1] */
++		"mulx 56(%1), %%rcx, %%r14 ;" /* B[3]*B[1] */
++
++		"movq 48(%1), %%rdx        ;" /* B[2]      */
++		"mulx 56(%1), %%r15, %%r13 ;" /* B[3]*B[2] */
++		"mulx 32(%1), %%rax, %%rdx ;" /* B[0]*B[2] */
++
++		"addq %%rax,  %%r9 ;"
++		"adcq %%rdx, %%r10 ;"
++		"adcq %%rcx, %%r11 ;"
++		"adcq %%r14, %%r15 ;"
++		"adcq    $0, %%r13 ;"
++		"movq    $0, %%r14 ;"
++		"adcq    $0, %%r14 ;"
++
++		"movq 32(%1), %%rdx        ;" /* B[0]      */
++		"mulx 56(%1), %%rax, %%rcx ;" /* B[0]*B[3] */
++
++		"addq %%rax, %%r10 ;"
++		"adcq %%rcx, %%r11 ;"
++		"adcq    $0, %%r15 ;"
++		"adcq    $0, %%r13 ;"
++		"adcq    $0, %%r14 ;"
++
++		"shldq $1, %%r13, %%r14 ;"
++		"shldq $1, %%r15, %%r13 ;"
++		"shldq $1, %%r11, %%r15 ;"
++		"shldq $1, %%r10, %%r11 ;"
++		"shldq $1,  %%r9, %%r10 ;"
++		"shldq $1,  %%r8,  %%r9 ;"
++		"shlq  $1,  %%r8        ;"
++
++		/*******************/
++		"mulx %%rdx, %%rax, %%rcx ; " /* B[0]^2 */
++		/*******************/
++		"movq %%rax,  64(%0) ;"
++		"addq %%rcx,  %%r8 ;"
++		"movq  %%r8,  72(%0) ;"
++		"movq 40(%1), %%rdx ;"
++		"mulx %%rdx, %%rax, %%rcx ; " /* B[1]^2 */
++		"adcq %%rax,  %%r9 ;"
++		"movq  %%r9,  80(%0) ;"
++		"adcq %%rcx, %%r10 ;"
++		"movq %%r10,  88(%0) ;"
++		"movq 48(%1), %%rdx ;"
++		"mulx %%rdx, %%rax, %%rcx ; " /* B[2]^2 */
++		"adcq %%rax, %%r11 ;"
++		"movq %%r11,  96(%0) ;"
++		"adcq %%rcx, %%r15 ;"
++		"movq %%r15, 104(%0) ;"
++		"movq 56(%1), %%rdx ;"
++		"mulx %%rdx, %%rax, %%rcx ; " /* B[3]^2 */
++		"adcq %%rax, %%r13 ;"
++		"movq %%r13, 112(%0) ;"
++		"adcq %%rcx, %%r14 ;"
++		"movq %%r14, 120(%0) ;"
++		:
++		: "r"(c), "r"(a)
++		: "memory", "cc", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10",
++		  "%r11", "%r13", "%r14", "%r15");
++}
++
++static void red_eltfp25519_2w_adx(u64 *const c, const u64 *const a)
++{
++	asm volatile(
++		"movl    $38, %%edx; "	/* 2*c = 38 = 2^256 */
++		"mulx 32(%1),  %%r8, %%r10; " /* c*C[4] */
++		"xorl %%ebx, %%ebx ;"
++		"adox   (%1),  %%r8 ;"
++		"mulx 40(%1),  %%r9, %%r11; " /* c*C[5] */
++		"adcx %%r10,  %%r9 ;"
++		"adox  8(%1),  %%r9 ;"
++		"mulx 48(%1), %%r10, %%rax; " /* c*C[6] */
++		"adcx %%r11, %%r10 ;"
++		"adox 16(%1), %%r10 ;"
++		"mulx 56(%1), %%r11, %%rcx; " /* c*C[7] */
++		"adcx %%rax, %%r11 ;"
++		"adox 24(%1), %%r11 ;"
++		/***************************************/
++		"adcx %%rbx, %%rcx ;"
++		"adox  %%rbx, %%rcx ;"
++		"imul %%rdx, %%rcx ;" /* c*C[4], cf=0, of=0 */
++		"adcx %%rcx,  %%r8 ;"
++		"adcx %%rbx,  %%r9 ;"
++		"movq  %%r9,  8(%0) ;"
++		"adcx %%rbx, %%r10 ;"
++		"movq %%r10, 16(%0) ;"
++		"adcx %%rbx, %%r11 ;"
++		"movq %%r11, 24(%0) ;"
++		"mov     $0, %%ecx ;"
++		"cmovc %%edx, %%ecx ;"
++		"addq %%rcx,  %%r8 ;"
++		"movq  %%r8,   (%0) ;"
++
++		"mulx  96(%1),  %%r8, %%r10; " /* c*C[4] */
++		"xorl %%ebx, %%ebx ;"
++		"adox 64(%1),  %%r8 ;"
++		"mulx 104(%1),  %%r9, %%r11; " /* c*C[5] */
++		"adcx %%r10,  %%r9 ;"
++		"adox 72(%1),  %%r9 ;"
++		"mulx 112(%1), %%r10, %%rax; " /* c*C[6] */
++		"adcx %%r11, %%r10 ;"
++		"adox 80(%1), %%r10 ;"
++		"mulx 120(%1), %%r11, %%rcx; " /* c*C[7] */
++		"adcx %%rax, %%r11 ;"
++		"adox 88(%1), %%r11 ;"
++		/****************************************/
++		"adcx %%rbx, %%rcx ;"
++		"adox  %%rbx, %%rcx ;"
++		"imul %%rdx, %%rcx ;" /* c*C[4], cf=0, of=0 */
++		"adcx %%rcx,  %%r8 ;"
++		"adcx %%rbx,  %%r9 ;"
++		"movq  %%r9, 40(%0) ;"
++		"adcx %%rbx, %%r10 ;"
++		"movq %%r10, 48(%0) ;"
++		"adcx %%rbx, %%r11 ;"
++		"movq %%r11, 56(%0) ;"
++		"mov     $0, %%ecx ;"
++		"cmovc %%edx, %%ecx ;"
++		"addq %%rcx,  %%r8 ;"
++		"movq  %%r8, 32(%0) ;"
++		:
++		: "r"(c), "r"(a)
++		: "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9",
++		  "%r10", "%r11");
++}
++
++static void red_eltfp25519_2w_bmi2(u64 *const c, const u64 *const a)
++{
++	asm volatile(
++		"movl    $38, %%edx ; "       /* 2*c = 38 = 2^256 */
++		"mulx 32(%1),  %%r8, %%r10 ;" /* c*C[4] */
++		"mulx 40(%1),  %%r9, %%r11 ;" /* c*C[5] */
++		"addq %%r10,  %%r9 ;"
++		"mulx 48(%1), %%r10, %%rax ;" /* c*C[6] */
++		"adcq %%r11, %%r10 ;"
++		"mulx 56(%1), %%r11, %%rcx ;" /* c*C[7] */
++		"adcq %%rax, %%r11 ;"
++		/***************************************/
++		"adcq    $0, %%rcx ;"
++		"addq   (%1),  %%r8 ;"
++		"adcq  8(%1),  %%r9 ;"
++		"adcq 16(%1), %%r10 ;"
++		"adcq 24(%1), %%r11 ;"
++		"adcq     $0, %%rcx ;"
++		"imul %%rdx, %%rcx ;" /* c*C[4], cf=0 */
++		"addq %%rcx,  %%r8 ;"
++		"adcq    $0,  %%r9 ;"
++		"movq  %%r9,  8(%0) ;"
++		"adcq    $0, %%r10 ;"
++		"movq %%r10, 16(%0) ;"
++		"adcq    $0, %%r11 ;"
++		"movq %%r11, 24(%0) ;"
++		"mov     $0, %%ecx ;"
++		"cmovc %%edx, %%ecx ;"
++		"addq %%rcx,  %%r8 ;"
++		"movq  %%r8,   (%0) ;"
++
++		"mulx  96(%1),  %%r8, %%r10 ;" /* c*C[4] */
++		"mulx 104(%1),  %%r9, %%r11 ;" /* c*C[5] */
++		"addq %%r10,  %%r9 ;"
++		"mulx 112(%1), %%r10, %%rax ;" /* c*C[6] */
++		"adcq %%r11, %%r10 ;"
++		"mulx 120(%1), %%r11, %%rcx ;" /* c*C[7] */
++		"adcq %%rax, %%r11 ;"
++		/****************************************/
++		"adcq    $0, %%rcx ;"
++		"addq 64(%1),  %%r8 ;"
++		"adcq 72(%1),  %%r9 ;"
++		"adcq 80(%1), %%r10 ;"
++		"adcq 88(%1), %%r11 ;"
++		"adcq     $0, %%rcx ;"
++		"imul %%rdx, %%rcx ;" /* c*C[4], cf=0 */
++		"addq %%rcx,  %%r8 ;"
++		"adcq    $0,  %%r9 ;"
++		"movq  %%r9, 40(%0) ;"
++		"adcq    $0, %%r10 ;"
++		"movq %%r10, 48(%0) ;"
++		"adcq    $0, %%r11 ;"
++		"movq %%r11, 56(%0) ;"
++		"mov     $0, %%ecx ;"
++		"cmovc %%edx, %%ecx ;"
++		"addq %%rcx,  %%r8 ;"
++		"movq  %%r8, 32(%0) ;"
++		:
++		: "r"(c), "r"(a)
++		: "memory", "cc", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10",
++		  "%r11");
++}
++
++static void mul_256x256_integer_adx(u64 *const c, const u64 *const a,
++				    const u64 *const b)
++{
++	asm volatile(
++		"movq   (%1), %%rdx; "	/* A[0] */
++		"mulx   (%2),  %%r8,  %%r9; " /* A[0]*B[0] */
++		"xorl %%r10d, %%r10d ;"
++		"movq  %%r8,  (%0) ;"
++		"mulx  8(%2), %%r10, %%r11; " /* A[0]*B[1] */
++		"adox  %%r9, %%r10 ;"
++		"movq %%r10, 8(%0) ;"
++		"mulx 16(%2), %%r15, %%r13; " /* A[0]*B[2] */
++		"adox %%r11, %%r15 ;"
++		"mulx 24(%2), %%r14, %%rdx; " /* A[0]*B[3] */
++		"adox %%r13, %%r14 ;"
++		"movq $0, %%rax ;"
++		/******************************************/
++		"adox %%rdx, %%rax ;"
++
++		"movq  8(%1), %%rdx; "	/* A[1] */
++		"mulx   (%2),  %%r8,  %%r9; " /* A[1]*B[0] */
++		"xorl %%r10d, %%r10d ;"
++		"adcx 8(%0),  %%r8 ;"
++		"movq  %%r8,  8(%0) ;"
++		"mulx  8(%2), %%r10, %%r11; " /* A[1]*B[1] */
++		"adox  %%r9, %%r10 ;"
++		"adcx %%r15, %%r10 ;"
++		"movq %%r10, 16(%0) ;"
++		"mulx 16(%2), %%r15, %%r13; " /* A[1]*B[2] */
++		"adox %%r11, %%r15 ;"
++		"adcx %%r14, %%r15 ;"
++		"movq $0, %%r8  ;"
++		"mulx 24(%2), %%r14, %%rdx; " /* A[1]*B[3] */
++		"adox %%r13, %%r14 ;"
++		"adcx %%rax, %%r14 ;"
++		"movq $0, %%rax ;"
++		/******************************************/
++		"adox %%rdx, %%rax ;"
++		"adcx  %%r8, %%rax ;"
++
++		"movq 16(%1), %%rdx; "	/* A[2] */
++		"mulx   (%2),  %%r8,  %%r9; " /* A[2]*B[0] */
++		"xorl %%r10d, %%r10d ;"
++		"adcx 16(%0), %%r8 ;"
++		"movq  %%r8, 16(%0) ;"
++		"mulx  8(%2), %%r10, %%r11; " /* A[2]*B[1] */
++		"adox  %%r9, %%r10 ;"
++		"adcx %%r15, %%r10 ;"
++		"movq %%r10, 24(%0) ;"
++		"mulx 16(%2), %%r15, %%r13; " /* A[2]*B[2] */
++		"adox %%r11, %%r15 ;"
++		"adcx %%r14, %%r15 ;"
++		"movq $0, %%r8  ;"
++		"mulx 24(%2), %%r14, %%rdx; " /* A[2]*B[3] */
++		"adox %%r13, %%r14 ;"
++		"adcx %%rax, %%r14 ;"
++		"movq $0, %%rax ;"
++		/******************************************/
++		"adox %%rdx, %%rax ;"
++		"adcx  %%r8, %%rax ;"
++
++		"movq 24(%1), %%rdx; "	/* A[3] */
++		"mulx   (%2),  %%r8,  %%r9; " /* A[3]*B[0] */
++		"xorl %%r10d, %%r10d ;"
++		"adcx 24(%0), %%r8 ;"
++		"movq  %%r8, 24(%0) ;"
++		"mulx  8(%2), %%r10, %%r11; " /* A[3]*B[1] */
++		"adox  %%r9, %%r10 ;"
++		"adcx %%r15, %%r10 ;"
++		"movq %%r10, 32(%0) ;"
++		"mulx 16(%2), %%r15, %%r13; " /* A[3]*B[2] */
++		"adox %%r11, %%r15 ;"
++		"adcx %%r14, %%r15 ;"
++		"movq %%r15, 40(%0) ;"
++		"movq $0, %%r8  ;"
++		"mulx 24(%2), %%r14, %%rdx; " /* A[3]*B[3] */
++		"adox %%r13, %%r14 ;"
++		"adcx %%rax, %%r14 ;"
++		"movq %%r14, 48(%0) ;"
++		"movq $0, %%rax ;"
++		/******************************************/
++		"adox %%rdx, %%rax ;"
++		"adcx  %%r8, %%rax ;"
++		"movq %%rax, 56(%0) ;"
++		:
++		: "r"(c), "r"(a), "r"(b)
++		: "memory", "cc", "%rax", "%rdx", "%r8", "%r9", "%r10", "%r11",
++		  "%r13", "%r14", "%r15");
++}
++
++static void mul_256x256_integer_bmi2(u64 *const c, const u64 *const a,
++				     const u64 *const b)
++{
++	asm volatile(
++		"movq   (%1), %%rdx; "	/* A[0] */
++		"mulx   (%2),  %%r8, %%r15; " /* A[0]*B[0] */
++		"movq %%r8,  (%0) ;"
++		"mulx  8(%2), %%r10, %%rax; " /* A[0]*B[1] */
++		"addq %%r10, %%r15 ;"
++		"mulx 16(%2),  %%r8, %%rbx; " /* A[0]*B[2] */
++		"adcq  %%r8, %%rax ;"
++		"mulx 24(%2), %%r10, %%rcx; " /* A[0]*B[3] */
++		"adcq %%r10, %%rbx ;"
++		/******************************************/
++		"adcq    $0, %%rcx ;"
++
++		"movq  8(%1), %%rdx; "	/* A[1] */
++		"mulx   (%2),  %%r8,  %%r9; " /* A[1]*B[0] */
++		"addq %%r15,  %%r8 ;"
++		"movq %%r8, 8(%0) ;"
++		"mulx  8(%2), %%r10, %%r11; " /* A[1]*B[1] */
++		"adcq %%r10,  %%r9 ;"
++		"mulx 16(%2),  %%r8, %%r13; " /* A[1]*B[2] */
++		"adcq  %%r8, %%r11 ;"
++		"mulx 24(%2), %%r10, %%r15; " /* A[1]*B[3] */
++		"adcq %%r10, %%r13 ;"
++		/******************************************/
++		"adcq    $0, %%r15 ;"
++
++		"addq  %%r9, %%rax ;"
++		"adcq %%r11, %%rbx ;"
++		"adcq %%r13, %%rcx ;"
++		"adcq    $0, %%r15 ;"
++
++		"movq 16(%1), %%rdx; "	/* A[2] */
++		"mulx   (%2),  %%r8,  %%r9; " /* A[2]*B[0] */
++		"addq %%rax,  %%r8 ;"
++		"movq %%r8, 16(%0) ;"
++		"mulx  8(%2), %%r10, %%r11; " /* A[2]*B[1] */
++		"adcq %%r10,  %%r9 ;"
++		"mulx 16(%2),  %%r8, %%r13; " /* A[2]*B[2] */
++		"adcq  %%r8, %%r11 ;"
++		"mulx 24(%2), %%r10, %%rax; " /* A[2]*B[3] */
++		"adcq %%r10, %%r13 ;"
++		/******************************************/
++		"adcq    $0, %%rax ;"
++
++		"addq  %%r9, %%rbx ;"
++		"adcq %%r11, %%rcx ;"
++		"adcq %%r13, %%r15 ;"
++		"adcq    $0, %%rax ;"
++
++		"movq 24(%1), %%rdx; "	/* A[3] */
++		"mulx   (%2),  %%r8,  %%r9; " /* A[3]*B[0] */
++		"addq %%rbx,  %%r8 ;"
++		"movq %%r8, 24(%0) ;"
++		"mulx  8(%2), %%r10, %%r11; " /* A[3]*B[1] */
++		"adcq %%r10,  %%r9 ;"
++		"mulx 16(%2),  %%r8, %%r13; " /* A[3]*B[2] */
++		"adcq  %%r8, %%r11 ;"
++		"mulx 24(%2), %%r10, %%rbx; " /* A[3]*B[3] */
++		"adcq %%r10, %%r13 ;"
++		/******************************************/
++		"adcq    $0, %%rbx ;"
++
++		"addq  %%r9, %%rcx ;"
++		"movq %%rcx, 32(%0) ;"
++		"adcq %%r11, %%r15 ;"
++		"movq %%r15, 40(%0) ;"
++		"adcq %%r13, %%rax ;"
++		"movq %%rax, 48(%0) ;"
++		"adcq    $0, %%rbx ;"
++		"movq %%rbx, 56(%0) ;"
++		:
++		: "r"(c), "r"(a), "r"(b)
++		: "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9",
++		  "%r10", "%r11", "%r13", "%r15");
++}
++
++static void sqr_256x256_integer_adx(u64 *const c, const u64 *const a)
++{
++	asm volatile(
++		"movq   (%1), %%rdx        ;" /* A[0]      */
++		"mulx  8(%1),  %%r8, %%r14 ;" /* A[1]*A[0] */
++		"xorl %%r15d, %%r15d;"
++		"mulx 16(%1),  %%r9, %%r10 ;" /* A[2]*A[0] */
++		"adcx %%r14,  %%r9 ;"
++		"mulx 24(%1), %%rax, %%rcx ;" /* A[3]*A[0] */
++		"adcx %%rax, %%r10 ;"
++		"movq 24(%1), %%rdx        ;" /* A[3]      */
++		"mulx  8(%1), %%r11, %%rbx ;" /* A[1]*A[3] */
++		"adcx %%rcx, %%r11 ;"
++		"mulx 16(%1), %%rax, %%r13 ;" /* A[2]*A[3] */
++		"adcx %%rax, %%rbx ;"
++		"movq  8(%1), %%rdx        ;" /* A[1]      */
++		"adcx %%r15, %%r13 ;"
++		"mulx 16(%1), %%rax, %%rcx ;" /* A[2]*A[1] */
++		"movq    $0, %%r14 ;"
++		/******************************************/
++		"adcx %%r15, %%r14 ;"
++
++		"xorl %%r15d, %%r15d;"
++		"adox %%rax, %%r10 ;"
++		"adcx  %%r8,  %%r8 ;"
++		"adox %%rcx, %%r11 ;"
++		"adcx  %%r9,  %%r9 ;"
++		"adox %%r15, %%rbx ;"
++		"adcx %%r10, %%r10 ;"
++		"adox %%r15, %%r13 ;"
++		"adcx %%r11, %%r11 ;"
++		"adox %%r15, %%r14 ;"
++		"adcx %%rbx, %%rbx ;"
++		"adcx %%r13, %%r13 ;"
++		"adcx %%r14, %%r14 ;"
++
++		"movq   (%1), %%rdx ;"
++		"mulx %%rdx, %%rax, %%rcx ;" /* A[0]^2 */
++		/*******************/
++		"movq %%rax,  0(%0) ;"
++		"addq %%rcx,  %%r8 ;"
++		"movq  %%r8,  8(%0) ;"
++		"movq  8(%1), %%rdx ;"
++		"mulx %%rdx, %%rax, %%rcx ;" /* A[1]^2 */
++		"adcq %%rax,  %%r9 ;"
++		"movq  %%r9, 16(%0) ;"
++		"adcq %%rcx, %%r10 ;"
++		"movq %%r10, 24(%0) ;"
++		"movq 16(%1), %%rdx ;"
++		"mulx %%rdx, %%rax, %%rcx ;" /* A[2]^2 */
++		"adcq %%rax, %%r11 ;"
++		"movq %%r11, 32(%0) ;"
++		"adcq %%rcx, %%rbx ;"
++		"movq %%rbx, 40(%0) ;"
++		"movq 24(%1), %%rdx ;"
++		"mulx %%rdx, %%rax, %%rcx ;" /* A[3]^2 */
++		"adcq %%rax, %%r13 ;"
++		"movq %%r13, 48(%0) ;"
++		"adcq %%rcx, %%r14 ;"
++		"movq %%r14, 56(%0) ;"
++		:
++		: "r"(c), "r"(a)
++		: "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9",
++		  "%r10", "%r11", "%r13", "%r14", "%r15");
++}
++
++static void sqr_256x256_integer_bmi2(u64 *const c, const u64 *const a)
++{
++	asm volatile(
++		"movq  8(%1), %%rdx        ;" /* A[1]      */
++		"mulx   (%1),  %%r8,  %%r9 ;" /* A[0]*A[1] */
++		"mulx 16(%1), %%r10, %%r11 ;" /* A[2]*A[1] */
++		"mulx 24(%1), %%rcx, %%r14 ;" /* A[3]*A[1] */
++
++		"movq 16(%1), %%rdx        ;" /* A[2]      */
++		"mulx 24(%1), %%r15, %%r13 ;" /* A[3]*A[2] */
++		"mulx   (%1), %%rax, %%rdx ;" /* A[0]*A[2] */
++
++		"addq %%rax,  %%r9 ;"
++		"adcq %%rdx, %%r10 ;"
++		"adcq %%rcx, %%r11 ;"
++		"adcq %%r14, %%r15 ;"
++		"adcq    $0, %%r13 ;"
++		"movq    $0, %%r14 ;"
++		"adcq    $0, %%r14 ;"
++
++		"movq   (%1), %%rdx        ;" /* A[0]      */
++		"mulx 24(%1), %%rax, %%rcx ;" /* A[0]*A[3] */
++
++		"addq %%rax, %%r10 ;"
++		"adcq %%rcx, %%r11 ;"
++		"adcq    $0, %%r15 ;"
++		"adcq    $0, %%r13 ;"
++		"adcq    $0, %%r14 ;"
++
++		"shldq $1, %%r13, %%r14 ;"
++		"shldq $1, %%r15, %%r13 ;"
++		"shldq $1, %%r11, %%r15 ;"
++		"shldq $1, %%r10, %%r11 ;"
++		"shldq $1,  %%r9, %%r10 ;"
++		"shldq $1,  %%r8,  %%r9 ;"
++		"shlq  $1,  %%r8        ;"
++
++		/*******************/
++		"mulx %%rdx, %%rax, %%rcx ;" /* A[0]^2 */
++		/*******************/
++		"movq %%rax,  0(%0) ;"
++		"addq %%rcx,  %%r8 ;"
++		"movq  %%r8,  8(%0) ;"
++		"movq  8(%1), %%rdx ;"
++		"mulx %%rdx, %%rax, %%rcx ;" /* A[1]^2 */
++		"adcq %%rax,  %%r9 ;"
++		"movq  %%r9, 16(%0) ;"
++		"adcq %%rcx, %%r10 ;"
++		"movq %%r10, 24(%0) ;"
++		"movq 16(%1), %%rdx ;"
++		"mulx %%rdx, %%rax, %%rcx ;" /* A[2]^2 */
++		"adcq %%rax, %%r11 ;"
++		"movq %%r11, 32(%0) ;"
++		"adcq %%rcx, %%r15 ;"
++		"movq %%r15, 40(%0) ;"
++		"movq 24(%1), %%rdx ;"
++		"mulx %%rdx, %%rax, %%rcx ;" /* A[3]^2 */
++		"adcq %%rax, %%r13 ;"
++		"movq %%r13, 48(%0) ;"
++		"adcq %%rcx, %%r14 ;"
++		"movq %%r14, 56(%0) ;"
++		:
++		: "r"(c), "r"(a)
++		: "memory", "cc", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10",
++		  "%r11", "%r13", "%r14", "%r15");
++}
++
++static void red_eltfp25519_1w_adx(u64 *const c, const u64 *const a)
++{
++	asm volatile(
++		"movl    $38, %%edx ;"	/* 2*c = 38 = 2^256 */
++		"mulx 32(%1),  %%r8, %%r10 ;" /* c*C[4] */
++		"xorl %%ebx, %%ebx ;"
++		"adox   (%1),  %%r8 ;"
++		"mulx 40(%1),  %%r9, %%r11 ;" /* c*C[5] */
++		"adcx %%r10,  %%r9 ;"
++		"adox  8(%1),  %%r9 ;"
++		"mulx 48(%1), %%r10, %%rax ;" /* c*C[6] */
++		"adcx %%r11, %%r10 ;"
++		"adox 16(%1), %%r10 ;"
++		"mulx 56(%1), %%r11, %%rcx ;" /* c*C[7] */
++		"adcx %%rax, %%r11 ;"
++		"adox 24(%1), %%r11 ;"
++		/***************************************/
++		"adcx %%rbx, %%rcx ;"
++		"adox  %%rbx, %%rcx ;"
++		"imul %%rdx, %%rcx ;" /* c*C[4], cf=0, of=0 */
++		"adcx %%rcx,  %%r8 ;"
++		"adcx %%rbx,  %%r9 ;"
++		"movq  %%r9,  8(%0) ;"
++		"adcx %%rbx, %%r10 ;"
++		"movq %%r10, 16(%0) ;"
++		"adcx %%rbx, %%r11 ;"
++		"movq %%r11, 24(%0) ;"
++		"mov     $0, %%ecx ;"
++		"cmovc %%edx, %%ecx ;"
++		"addq %%rcx,  %%r8 ;"
++		"movq  %%r8,   (%0) ;"
++		:
++		: "r"(c), "r"(a)
++		: "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9",
++		  "%r10", "%r11");
++}
++
++static void red_eltfp25519_1w_bmi2(u64 *const c, const u64 *const a)
++{
++	asm volatile(
++		"movl    $38, %%edx ;"	/* 2*c = 38 = 2^256 */
++		"mulx 32(%1),  %%r8, %%r10 ;" /* c*C[4] */
++		"mulx 40(%1),  %%r9, %%r11 ;" /* c*C[5] */
++		"addq %%r10,  %%r9 ;"
++		"mulx 48(%1), %%r10, %%rax ;" /* c*C[6] */
++		"adcq %%r11, %%r10 ;"
++		"mulx 56(%1), %%r11, %%rcx ;" /* c*C[7] */
++		"adcq %%rax, %%r11 ;"
++		/***************************************/
++		"adcq    $0, %%rcx ;"
++		"addq   (%1),  %%r8 ;"
++		"adcq  8(%1),  %%r9 ;"
++		"adcq 16(%1), %%r10 ;"
++		"adcq 24(%1), %%r11 ;"
++		"adcq     $0, %%rcx ;"
++		"imul %%rdx, %%rcx ;" /* c*C[4], cf=0 */
++		"addq %%rcx,  %%r8 ;"
++		"adcq    $0,  %%r9 ;"
++		"movq  %%r9,  8(%0) ;"
++		"adcq    $0, %%r10 ;"
++		"movq %%r10, 16(%0) ;"
++		"adcq    $0, %%r11 ;"
++		"movq %%r11, 24(%0) ;"
++		"mov     $0, %%ecx ;"
++		"cmovc %%edx, %%ecx ;"
++		"addq %%rcx,  %%r8 ;"
++		"movq  %%r8,   (%0) ;"
++		:
++		: "r"(c), "r"(a)
++		: "memory", "cc", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10",
++		  "%r11");
++}
++
++static __always_inline void
++add_eltfp25519_1w_adx(u64 *const c, const u64 *const a, const u64 *const b)
++{
++	asm volatile(
++		"mov     $38, %%eax ;"
++		"xorl  %%ecx, %%ecx ;"
++		"movq   (%2),  %%r8 ;"
++		"adcx   (%1),  %%r8 ;"
++		"movq  8(%2),  %%r9 ;"
++		"adcx  8(%1),  %%r9 ;"
++		"movq 16(%2), %%r10 ;"
++		"adcx 16(%1), %%r10 ;"
++		"movq 24(%2), %%r11 ;"
++		"adcx 24(%1), %%r11 ;"
++		"cmovc %%eax, %%ecx ;"
++		"xorl %%eax, %%eax  ;"
++		"adcx %%rcx,  %%r8  ;"
++		"adcx %%rax,  %%r9  ;"
++		"movq  %%r9,  8(%0) ;"
++		"adcx %%rax, %%r10  ;"
++		"movq %%r10, 16(%0) ;"
++		"adcx %%rax, %%r11  ;"
++		"movq %%r11, 24(%0) ;"
++		"mov     $38, %%ecx ;"
++		"cmovc %%ecx, %%eax ;"
++		"addq %%rax,  %%r8  ;"
++		"movq  %%r8,   (%0) ;"
++		:
++		: "r"(c), "r"(a), "r"(b)
++		: "memory", "cc", "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11");
++}
++
++static __always_inline void
++add_eltfp25519_1w_bmi2(u64 *const c, const u64 *const a, const u64 *const b)
++{
++	asm volatile(
++		"mov     $38, %%eax ;"
++		"movq   (%2),  %%r8 ;"
++		"addq   (%1),  %%r8 ;"
++		"movq  8(%2),  %%r9 ;"
++		"adcq  8(%1),  %%r9 ;"
++		"movq 16(%2), %%r10 ;"
++		"adcq 16(%1), %%r10 ;"
++		"movq 24(%2), %%r11 ;"
++		"adcq 24(%1), %%r11 ;"
++		"mov      $0, %%ecx ;"
++		"cmovc %%eax, %%ecx ;"
++		"addq %%rcx,  %%r8  ;"
++		"adcq    $0,  %%r9  ;"
++		"movq  %%r9,  8(%0) ;"
++		"adcq    $0, %%r10  ;"
++		"movq %%r10, 16(%0) ;"
++		"adcq    $0, %%r11  ;"
++		"movq %%r11, 24(%0) ;"
++		"mov     $0, %%ecx  ;"
++		"cmovc %%eax, %%ecx ;"
++		"addq %%rcx,  %%r8  ;"
++		"movq  %%r8,   (%0) ;"
++		:
++		: "r"(c), "r"(a), "r"(b)
++		: "memory", "cc", "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11");
++}
++
++static __always_inline void
++sub_eltfp25519_1w(u64 *const c, const u64 *const a, const u64 *const b)
++{
++	asm volatile(
++		"mov     $38, %%eax ;"
++		"movq   (%1),  %%r8 ;"
++		"subq   (%2),  %%r8 ;"
++		"movq  8(%1),  %%r9 ;"
++		"sbbq  8(%2),  %%r9 ;"
++		"movq 16(%1), %%r10 ;"
++		"sbbq 16(%2), %%r10 ;"
++		"movq 24(%1), %%r11 ;"
++		"sbbq 24(%2), %%r11 ;"
++		"mov      $0, %%ecx ;"
++		"cmovc %%eax, %%ecx ;"
++		"subq %%rcx,  %%r8  ;"
++		"sbbq    $0,  %%r9  ;"
++		"movq  %%r9,  8(%0) ;"
++		"sbbq    $0, %%r10  ;"
++		"movq %%r10, 16(%0) ;"
++		"sbbq    $0, %%r11  ;"
++		"movq %%r11, 24(%0) ;"
++		"mov     $0, %%ecx  ;"
++		"cmovc %%eax, %%ecx ;"
++		"subq %%rcx,  %%r8  ;"
++		"movq  %%r8,   (%0) ;"
++		:
++		: "r"(c), "r"(a), "r"(b)
++		: "memory", "cc", "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11");
++}
++
++/* Multiplication by a24 = (A+2)/4 = (486662+2)/4 = 121666 */
++static __always_inline void
++mul_a24_eltfp25519_1w(u64 *const c, const u64 *const a)
++{
++	const u64 a24 = 121666;
++	asm volatile(
++		"movq     %2, %%rdx ;"
++		"mulx   (%1),  %%r8, %%r10 ;"
++		"mulx  8(%1),  %%r9, %%r11 ;"
++		"addq %%r10,  %%r9 ;"
++		"mulx 16(%1), %%r10, %%rax ;"
++		"adcq %%r11, %%r10 ;"
++		"mulx 24(%1), %%r11, %%rcx ;"
++		"adcq %%rax, %%r11 ;"
++		/**************************/
++		"adcq    $0, %%rcx ;"
++		"movl   $38, %%edx ;" /* 2*c = 38 = 2^256 mod 2^255-19*/
++		"imul %%rdx, %%rcx ;"
++		"addq %%rcx,  %%r8 ;"
++		"adcq    $0,  %%r9 ;"
++		"movq  %%r9,  8(%0) ;"
++		"adcq    $0, %%r10 ;"
++		"movq %%r10, 16(%0) ;"
++		"adcq    $0, %%r11 ;"
++		"movq %%r11, 24(%0) ;"
++		"mov     $0, %%ecx ;"
++		"cmovc %%edx, %%ecx ;"
++		"addq %%rcx,  %%r8 ;"
++		"movq  %%r8,   (%0) ;"
++		:
++		: "r"(c), "r"(a), "r"(a24)
++		: "memory", "cc", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10",
++		  "%r11");
++}
++
++static void inv_eltfp25519_1w_adx(u64 *const c, const u64 *const a)
++{
++	struct {
++		eltfp25519_1w_buffer buffer;
++		eltfp25519_1w x0, x1, x2;
++	} __aligned(32) m;
++	u64 *T[4];
++
++	T[0] = m.x0;
++	T[1] = c; /* x^(-1) */
++	T[2] = m.x1;
++	T[3] = m.x2;
++
++	copy_eltfp25519_1w(T[1], a);
++	sqrn_eltfp25519_1w_adx(T[1], 1);
++	copy_eltfp25519_1w(T[2], T[1]);
++	sqrn_eltfp25519_1w_adx(T[2], 2);
++	mul_eltfp25519_1w_adx(T[0], a, T[2]);
++	mul_eltfp25519_1w_adx(T[1], T[1], T[0]);
++	copy_eltfp25519_1w(T[2], T[1]);
++	sqrn_eltfp25519_1w_adx(T[2], 1);
++	mul_eltfp25519_1w_adx(T[0], T[0], T[2]);
++	copy_eltfp25519_1w(T[2], T[0]);
++	sqrn_eltfp25519_1w_adx(T[2], 5);
++	mul_eltfp25519_1w_adx(T[0], T[0], T[2]);
++	copy_eltfp25519_1w(T[2], T[0]);
++	sqrn_eltfp25519_1w_adx(T[2], 10);
++	mul_eltfp25519_1w_adx(T[2], T[2], T[0]);
++	copy_eltfp25519_1w(T[3], T[2]);
++	sqrn_eltfp25519_1w_adx(T[3], 20);
++	mul_eltfp25519_1w_adx(T[3], T[3], T[2]);
++	sqrn_eltfp25519_1w_adx(T[3], 10);
++	mul_eltfp25519_1w_adx(T[3], T[3], T[0]);
++	copy_eltfp25519_1w(T[0], T[3]);
++	sqrn_eltfp25519_1w_adx(T[0], 50);
++	mul_eltfp25519_1w_adx(T[0], T[0], T[3]);
++	copy_eltfp25519_1w(T[2], T[0]);
++	sqrn_eltfp25519_1w_adx(T[2], 100);
++	mul_eltfp25519_1w_adx(T[2], T[2], T[0]);
++	sqrn_eltfp25519_1w_adx(T[2], 50);
++	mul_eltfp25519_1w_adx(T[2], T[2], T[3]);
++	sqrn_eltfp25519_1w_adx(T[2], 5);
++	mul_eltfp25519_1w_adx(T[1], T[1], T[2]);
++
++	memzero_explicit(&m, sizeof(m));
++}
++
++static void inv_eltfp25519_1w_bmi2(u64 *const c, const u64 *const a)
++{
++	struct {
++		eltfp25519_1w_buffer buffer;
++		eltfp25519_1w x0, x1, x2;
++	} __aligned(32) m;
++	u64 *T[5];
++
++	T[0] = m.x0;
++	T[1] = c; /* x^(-1) */
++	T[2] = m.x1;
++	T[3] = m.x2;
++
++	copy_eltfp25519_1w(T[1], a);
++	sqrn_eltfp25519_1w_bmi2(T[1], 1);
++	copy_eltfp25519_1w(T[2], T[1]);
++	sqrn_eltfp25519_1w_bmi2(T[2], 2);
++	mul_eltfp25519_1w_bmi2(T[0], a, T[2]);
++	mul_eltfp25519_1w_bmi2(T[1], T[1], T[0]);
++	copy_eltfp25519_1w(T[2], T[1]);
++	sqrn_eltfp25519_1w_bmi2(T[2], 1);
++	mul_eltfp25519_1w_bmi2(T[0], T[0], T[2]);
++	copy_eltfp25519_1w(T[2], T[0]);
++	sqrn_eltfp25519_1w_bmi2(T[2], 5);
++	mul_eltfp25519_1w_bmi2(T[0], T[0], T[2]);
++	copy_eltfp25519_1w(T[2], T[0]);
++	sqrn_eltfp25519_1w_bmi2(T[2], 10);
++	mul_eltfp25519_1w_bmi2(T[2], T[2], T[0]);
++	copy_eltfp25519_1w(T[3], T[2]);
++	sqrn_eltfp25519_1w_bmi2(T[3], 20);
++	mul_eltfp25519_1w_bmi2(T[3], T[3], T[2]);
++	sqrn_eltfp25519_1w_bmi2(T[3], 10);
++	mul_eltfp25519_1w_bmi2(T[3], T[3], T[0]);
++	copy_eltfp25519_1w(T[0], T[3]);
++	sqrn_eltfp25519_1w_bmi2(T[0], 50);
++	mul_eltfp25519_1w_bmi2(T[0], T[0], T[3]);
++	copy_eltfp25519_1w(T[2], T[0]);
++	sqrn_eltfp25519_1w_bmi2(T[2], 100);
++	mul_eltfp25519_1w_bmi2(T[2], T[2], T[0]);
++	sqrn_eltfp25519_1w_bmi2(T[2], 50);
++	mul_eltfp25519_1w_bmi2(T[2], T[2], T[3]);
++	sqrn_eltfp25519_1w_bmi2(T[2], 5);
++	mul_eltfp25519_1w_bmi2(T[1], T[1], T[2]);
++
++	memzero_explicit(&m, sizeof(m));
++}
++
++/* Given c, a 256-bit number, fred_eltfp25519_1w updates c
++ * with a number such that 0 <= C < 2**255-19.
++ */
++static __always_inline void fred_eltfp25519_1w(u64 *const c)
++{
++	u64 tmp0 = 38, tmp1 = 19;
++	asm volatile(
++		"btrq   $63,    %3 ;" /* Put bit 255 in carry flag and clear */
++		"cmovncl %k5,   %k4 ;" /* c[255] ? 38 : 19 */
++
++		/* Add either 19 or 38 to c */
++		"addq    %4,   %0 ;"
++		"adcq    $0,   %1 ;"
++		"adcq    $0,   %2 ;"
++		"adcq    $0,   %3 ;"
++
++		/* Test for bit 255 again; only triggered on overflow modulo 2^255-19 */
++		"movl    $0,  %k4 ;"
++		"cmovnsl %k5,  %k4 ;" /* c[255] ? 0 : 19 */
++		"btrq   $63,   %3 ;" /* Clear bit 255 */
++
++		/* Subtract 19 if necessary */
++		"subq    %4,   %0 ;"
++		"sbbq    $0,   %1 ;"
++		"sbbq    $0,   %2 ;"
++		"sbbq    $0,   %3 ;"
++
++		: "+r"(c[0]), "+r"(c[1]), "+r"(c[2]), "+r"(c[3]), "+r"(tmp0),
++		  "+r"(tmp1)
++		:
++		: "memory", "cc");
++}
++
++static __always_inline void cswap(u8 bit, u64 *const px, u64 *const py)
++{
++	u64 temp;
++	asm volatile(
++		"test %9, %9 ;"
++		"movq %0, %8 ;"
++		"cmovnzq %4, %0 ;"
++		"cmovnzq %8, %4 ;"
++		"movq %1, %8 ;"
++		"cmovnzq %5, %1 ;"
++		"cmovnzq %8, %5 ;"
++		"movq %2, %8 ;"
++		"cmovnzq %6, %2 ;"
++		"cmovnzq %8, %6 ;"
++		"movq %3, %8 ;"
++		"cmovnzq %7, %3 ;"
++		"cmovnzq %8, %7 ;"
++		: "+r"(px[0]), "+r"(px[1]), "+r"(px[2]), "+r"(px[3]),
++		  "+r"(py[0]), "+r"(py[1]), "+r"(py[2]), "+r"(py[3]),
++		  "=r"(temp)
++		: "r"(bit)
++		: "cc"
++	);
++}
++
++static __always_inline void cselect(u8 bit, u64 *const px, const u64 *const py)
++{
++	asm volatile(
++		"test %4, %4 ;"
++		"cmovnzq %5, %0 ;"
++		"cmovnzq %6, %1 ;"
++		"cmovnzq %7, %2 ;"
++		"cmovnzq %8, %3 ;"
++		: "+r"(px[0]), "+r"(px[1]), "+r"(px[2]), "+r"(px[3])
++		: "r"(bit), "rm"(py[0]), "rm"(py[1]), "rm"(py[2]), "rm"(py[3])
++		: "cc"
++	);
++}
++
++static void curve25519_adx(u8 shared[CURVE25519_KEY_SIZE],
++			   const u8 private_key[CURVE25519_KEY_SIZE],
++			   const u8 session_key[CURVE25519_KEY_SIZE])
++{
++	struct {
++		u64 buffer[4 * NUM_WORDS_ELTFP25519];
++		u64 coordinates[4 * NUM_WORDS_ELTFP25519];
++		u64 workspace[6 * NUM_WORDS_ELTFP25519];
++		u8 session[CURVE25519_KEY_SIZE];
++		u8 private[CURVE25519_KEY_SIZE];
++	} __aligned(32) m;
++
++	int i = 0, j = 0;
++	u64 prev = 0;
++	u64 *const X1 = (u64 *)m.session;
++	u64 *const key = (u64 *)m.private;
++	u64 *const Px = m.coordinates + 0;
++	u64 *const Pz = m.coordinates + 4;
++	u64 *const Qx = m.coordinates + 8;
++	u64 *const Qz = m.coordinates + 12;
++	u64 *const X2 = Qx;
++	u64 *const Z2 = Qz;
++	u64 *const X3 = Px;
++	u64 *const Z3 = Pz;
++	u64 *const X2Z2 = Qx;
++	u64 *const X3Z3 = Px;
++
++	u64 *const A = m.workspace + 0;
++	u64 *const B = m.workspace + 4;
++	u64 *const D = m.workspace + 8;
++	u64 *const C = m.workspace + 12;
++	u64 *const DA = m.workspace + 16;
++	u64 *const CB = m.workspace + 20;
++	u64 *const AB = A;
++	u64 *const DC = D;
++	u64 *const DACB = DA;
++
++	memcpy(m.private, private_key, sizeof(m.private));
++	memcpy(m.session, session_key, sizeof(m.session));
++
++	curve25519_clamp_secret(m.private);
++
++	/* As in the draft:
++	 * When receiving such an array, implementations of curve25519
++	 * MUST mask the most-significant bit in the final byte. This
++	 * is done to preserve compatibility with point formats which
++	 * reserve the sign bit for use in other protocols and to
++	 * increase resistance to implementation fingerprinting
++	 */
++	m.session[CURVE25519_KEY_SIZE - 1] &= (1 << (255 % 8)) - 1;
++
++	copy_eltfp25519_1w(Px, X1);
++	setzero_eltfp25519_1w(Pz);
++	setzero_eltfp25519_1w(Qx);
++	setzero_eltfp25519_1w(Qz);
++
++	Pz[0] = 1;
++	Qx[0] = 1;
++
++	/* main-loop */
++	prev = 0;
++	j = 62;
++	for (i = 3; i >= 0; --i) {
++		while (j >= 0) {
++			u64 bit = (key[i] >> j) & 0x1;
++			u64 swap = bit ^ prev;
++			prev = bit;
++
++			add_eltfp25519_1w_adx(A, X2, Z2);	/* A = (X2+Z2) */
++			sub_eltfp25519_1w(B, X2, Z2);		/* B = (X2-Z2) */
++			add_eltfp25519_1w_adx(C, X3, Z3);	/* C = (X3+Z3) */
++			sub_eltfp25519_1w(D, X3, Z3);		/* D = (X3-Z3) */
++			mul_eltfp25519_2w_adx(DACB, AB, DC);	/* [DA|CB] = [A|B]*[D|C] */
++
++			cselect(swap, A, C);
++			cselect(swap, B, D);
++
++			sqr_eltfp25519_2w_adx(AB);		/* [AA|BB] = [A^2|B^2] */
++			add_eltfp25519_1w_adx(X3, DA, CB);	/* X3 = (DA+CB) */
++			sub_eltfp25519_1w(Z3, DA, CB);		/* Z3 = (DA-CB) */
++			sqr_eltfp25519_2w_adx(X3Z3);		/* [X3|Z3] = [(DA+CB)|(DA+CB)]^2 */
++
++			copy_eltfp25519_1w(X2, B);		/* X2 = B^2 */
++			sub_eltfp25519_1w(Z2, A, B);		/* Z2 = E = AA-BB */
++
++			mul_a24_eltfp25519_1w(B, Z2);		/* B = a24*E */
++			add_eltfp25519_1w_adx(B, B, X2);	/* B = a24*E+B */
++			mul_eltfp25519_2w_adx(X2Z2, X2Z2, AB);	/* [X2|Z2] = [B|E]*[A|a24*E+B] */
++			mul_eltfp25519_1w_adx(Z3, Z3, X1);	/* Z3 = Z3*X1 */
++			--j;
++		}
++		j = 63;
++	}
++
++	inv_eltfp25519_1w_adx(A, Qz);
++	mul_eltfp25519_1w_adx((u64 *)shared, Qx, A);
++	fred_eltfp25519_1w((u64 *)shared);
++
++	memzero_explicit(&m, sizeof(m));
++}
++
++static void curve25519_adx_base(u8 session_key[CURVE25519_KEY_SIZE],
++				const u8 private_key[CURVE25519_KEY_SIZE])
++{
++	struct {
++		u64 buffer[4 * NUM_WORDS_ELTFP25519];
++		u64 coordinates[4 * NUM_WORDS_ELTFP25519];
++		u64 workspace[4 * NUM_WORDS_ELTFP25519];
++		u8 private[CURVE25519_KEY_SIZE];
++	} __aligned(32) m;
++
++	const int ite[4] = { 64, 64, 64, 63 };
++	const int q = 3;
++	u64 swap = 1;
++
++	int i = 0, j = 0, k = 0;
++	u64 *const key = (u64 *)m.private;
++	u64 *const Ur1 = m.coordinates + 0;
++	u64 *const Zr1 = m.coordinates + 4;
++	u64 *const Ur2 = m.coordinates + 8;
++	u64 *const Zr2 = m.coordinates + 12;
++
++	u64 *const UZr1 = m.coordinates + 0;
++	u64 *const ZUr2 = m.coordinates + 8;
++
++	u64 *const A = m.workspace + 0;
++	u64 *const B = m.workspace + 4;
++	u64 *const C = m.workspace + 8;
++	u64 *const D = m.workspace + 12;
++
++	u64 *const AB = m.workspace + 0;
++	u64 *const CD = m.workspace + 8;
++
++	const u64 *const P = table_ladder_8k;
++
++	memcpy(m.private, private_key, sizeof(m.private));
++
++	curve25519_clamp_secret(m.private);
++
++	setzero_eltfp25519_1w(Ur1);
++	setzero_eltfp25519_1w(Zr1);
++	setzero_eltfp25519_1w(Zr2);
++	Ur1[0] = 1;
++	Zr1[0] = 1;
++	Zr2[0] = 1;
++
++	/* G-S */
++	Ur2[3] = 0x1eaecdeee27cab34UL;
++	Ur2[2] = 0xadc7a0b9235d48e2UL;
++	Ur2[1] = 0xbbf095ae14b2edf8UL;
++	Ur2[0] = 0x7e94e1fec82faabdUL;
++
++	/* main-loop */
++	j = q;
++	for (i = 0; i < NUM_WORDS_ELTFP25519; ++i) {
++		while (j < ite[i]) {
++			u64 bit = (key[i] >> j) & 0x1;
++			k = (64 * i + j - q);
++			swap = swap ^ bit;
++			cswap(swap, Ur1, Ur2);
++			cswap(swap, Zr1, Zr2);
++			swap = bit;
++			/* Addition */
++			sub_eltfp25519_1w(B, Ur1, Zr1);		/* B = Ur1-Zr1 */
++			add_eltfp25519_1w_adx(A, Ur1, Zr1);	/* A = Ur1+Zr1 */
++			mul_eltfp25519_1w_adx(C, &P[4 * k], B);	/* C = M0-B */
++			sub_eltfp25519_1w(B, A, C);		/* B = (Ur1+Zr1) - M*(Ur1-Zr1) */
++			add_eltfp25519_1w_adx(A, A, C);		/* A = (Ur1+Zr1) + M*(Ur1-Zr1) */
++			sqr_eltfp25519_2w_adx(AB);		/* A = A^2      |  B = B^2 */
++			mul_eltfp25519_2w_adx(UZr1, ZUr2, AB);	/* Ur1 = Zr2*A  |  Zr1 = Ur2*B */
++			++j;
++		}
++		j = 0;
++	}
++
++	/* Doubling */
++	for (i = 0; i < q; ++i) {
++		add_eltfp25519_1w_adx(A, Ur1, Zr1);	/*  A = Ur1+Zr1 */
++		sub_eltfp25519_1w(B, Ur1, Zr1);		/*  B = Ur1-Zr1 */
++		sqr_eltfp25519_2w_adx(AB);		/*  A = A**2     B = B**2 */
++		copy_eltfp25519_1w(C, B);		/*  C = B */
++		sub_eltfp25519_1w(B, A, B);		/*  B = A-B */
++		mul_a24_eltfp25519_1w(D, B);		/*  D = my_a24*B */
++		add_eltfp25519_1w_adx(D, D, C);		/*  D = D+C */
++		mul_eltfp25519_2w_adx(UZr1, AB, CD);	/*  Ur1 = A*B   Zr1 = Zr1*A */
++	}
++
++	/* Convert to affine coordinates */
++	inv_eltfp25519_1w_adx(A, Zr1);
++	mul_eltfp25519_1w_adx((u64 *)session_key, Ur1, A);
++	fred_eltfp25519_1w((u64 *)session_key);
++
++	memzero_explicit(&m, sizeof(m));
++}
++
++static void curve25519_bmi2(u8 shared[CURVE25519_KEY_SIZE],
++			    const u8 private_key[CURVE25519_KEY_SIZE],
++			    const u8 session_key[CURVE25519_KEY_SIZE])
++{
++	struct {
++		u64 buffer[4 * NUM_WORDS_ELTFP25519];
++		u64 coordinates[4 * NUM_WORDS_ELTFP25519];
++		u64 workspace[6 * NUM_WORDS_ELTFP25519];
++		u8 session[CURVE25519_KEY_SIZE];
++		u8 private[CURVE25519_KEY_SIZE];
++	} __aligned(32) m;
++
++	int i = 0, j = 0;
++	u64 prev = 0;
++	u64 *const X1 = (u64 *)m.session;
++	u64 *const key = (u64 *)m.private;
++	u64 *const Px = m.coordinates + 0;
++	u64 *const Pz = m.coordinates + 4;
++	u64 *const Qx = m.coordinates + 8;
++	u64 *const Qz = m.coordinates + 12;
++	u64 *const X2 = Qx;
++	u64 *const Z2 = Qz;
++	u64 *const X3 = Px;
++	u64 *const Z3 = Pz;
++	u64 *const X2Z2 = Qx;
++	u64 *const X3Z3 = Px;
++
++	u64 *const A = m.workspace + 0;
++	u64 *const B = m.workspace + 4;
++	u64 *const D = m.workspace + 8;
++	u64 *const C = m.workspace + 12;
++	u64 *const DA = m.workspace + 16;
++	u64 *const CB = m.workspace + 20;
++	u64 *const AB = A;
++	u64 *const DC = D;
++	u64 *const DACB = DA;
++
++	memcpy(m.private, private_key, sizeof(m.private));
++	memcpy(m.session, session_key, sizeof(m.session));
++
++	curve25519_clamp_secret(m.private);
++
++	/* As in the draft:
++	 * When receiving such an array, implementations of curve25519
++	 * MUST mask the most-significant bit in the final byte. This
++	 * is done to preserve compatibility with point formats which
++	 * reserve the sign bit for use in other protocols and to
++	 * increase resistance to implementation fingerprinting
++	 */
++	m.session[CURVE25519_KEY_SIZE - 1] &= (1 << (255 % 8)) - 1;
++
++	copy_eltfp25519_1w(Px, X1);
++	setzero_eltfp25519_1w(Pz);
++	setzero_eltfp25519_1w(Qx);
++	setzero_eltfp25519_1w(Qz);
++
++	Pz[0] = 1;
++	Qx[0] = 1;
++
++	/* main-loop */
++	prev = 0;
++	j = 62;
++	for (i = 3; i >= 0; --i) {
++		while (j >= 0) {
++			u64 bit = (key[i] >> j) & 0x1;
++			u64 swap = bit ^ prev;
++			prev = bit;
++
++			add_eltfp25519_1w_bmi2(A, X2, Z2);	/* A = (X2+Z2) */
++			sub_eltfp25519_1w(B, X2, Z2);		/* B = (X2-Z2) */
++			add_eltfp25519_1w_bmi2(C, X3, Z3);	/* C = (X3+Z3) */
++			sub_eltfp25519_1w(D, X3, Z3);		/* D = (X3-Z3) */
++			mul_eltfp25519_2w_bmi2(DACB, AB, DC);	/* [DA|CB] = [A|B]*[D|C] */
++
++			cselect(swap, A, C);
++			cselect(swap, B, D);
++
++			sqr_eltfp25519_2w_bmi2(AB);		/* [AA|BB] = [A^2|B^2] */
++			add_eltfp25519_1w_bmi2(X3, DA, CB);	/* X3 = (DA+CB) */
++			sub_eltfp25519_1w(Z3, DA, CB);		/* Z3 = (DA-CB) */
++			sqr_eltfp25519_2w_bmi2(X3Z3);		/* [X3|Z3] = [(DA+CB)|(DA+CB)]^2 */
++
++			copy_eltfp25519_1w(X2, B);		/* X2 = B^2 */
++			sub_eltfp25519_1w(Z2, A, B);		/* Z2 = E = AA-BB */
++
++			mul_a24_eltfp25519_1w(B, Z2);		/* B = a24*E */
++			add_eltfp25519_1w_bmi2(B, B, X2);	/* B = a24*E+B */
++			mul_eltfp25519_2w_bmi2(X2Z2, X2Z2, AB);	/* [X2|Z2] = [B|E]*[A|a24*E+B] */
++			mul_eltfp25519_1w_bmi2(Z3, Z3, X1);	/* Z3 = Z3*X1 */
++			--j;
++		}
++		j = 63;
++	}
++
++	inv_eltfp25519_1w_bmi2(A, Qz);
++	mul_eltfp25519_1w_bmi2((u64 *)shared, Qx, A);
++	fred_eltfp25519_1w((u64 *)shared);
++
++	memzero_explicit(&m, sizeof(m));
++}
++
++static void curve25519_bmi2_base(u8 session_key[CURVE25519_KEY_SIZE],
++				 const u8 private_key[CURVE25519_KEY_SIZE])
++{
++	struct {
++		u64 buffer[4 * NUM_WORDS_ELTFP25519];
++		u64 coordinates[4 * NUM_WORDS_ELTFP25519];
++		u64 workspace[4 * NUM_WORDS_ELTFP25519];
++		u8 private[CURVE25519_KEY_SIZE];
++	} __aligned(32) m;
++
++	const int ite[4] = { 64, 64, 64, 63 };
++	const int q = 3;
++	u64 swap = 1;
++
++	int i = 0, j = 0, k = 0;
++	u64 *const key = (u64 *)m.private;
++	u64 *const Ur1 = m.coordinates + 0;
++	u64 *const Zr1 = m.coordinates + 4;
++	u64 *const Ur2 = m.coordinates + 8;
++	u64 *const Zr2 = m.coordinates + 12;
++
++	u64 *const UZr1 = m.coordinates + 0;
++	u64 *const ZUr2 = m.coordinates + 8;
++
++	u64 *const A = m.workspace + 0;
++	u64 *const B = m.workspace + 4;
++	u64 *const C = m.workspace + 8;
++	u64 *const D = m.workspace + 12;
++
++	u64 *const AB = m.workspace + 0;
++	u64 *const CD = m.workspace + 8;
++
++	const u64 *const P = table_ladder_8k;
++
++	memcpy(m.private, private_key, sizeof(m.private));
++
++	curve25519_clamp_secret(m.private);
++
++	setzero_eltfp25519_1w(Ur1);
++	setzero_eltfp25519_1w(Zr1);
++	setzero_eltfp25519_1w(Zr2);
++	Ur1[0] = 1;
++	Zr1[0] = 1;
++	Zr2[0] = 1;
++
++	/* G-S */
++	Ur2[3] = 0x1eaecdeee27cab34UL;
++	Ur2[2] = 0xadc7a0b9235d48e2UL;
++	Ur2[1] = 0xbbf095ae14b2edf8UL;
++	Ur2[0] = 0x7e94e1fec82faabdUL;
++
++	/* main-loop */
++	j = q;
++	for (i = 0; i < NUM_WORDS_ELTFP25519; ++i) {
++		while (j < ite[i]) {
++			u64 bit = (key[i] >> j) & 0x1;
++			k = (64 * i + j - q);
++			swap = swap ^ bit;
++			cswap(swap, Ur1, Ur2);
++			cswap(swap, Zr1, Zr2);
++			swap = bit;
++			/* Addition */
++			sub_eltfp25519_1w(B, Ur1, Zr1);		/* B = Ur1-Zr1 */
++			add_eltfp25519_1w_bmi2(A, Ur1, Zr1);	/* A = Ur1+Zr1 */
++			mul_eltfp25519_1w_bmi2(C, &P[4 * k], B);/* C = M0-B */
++			sub_eltfp25519_1w(B, A, C);		/* B = (Ur1+Zr1) - M*(Ur1-Zr1) */
++			add_eltfp25519_1w_bmi2(A, A, C);	/* A = (Ur1+Zr1) + M*(Ur1-Zr1) */
++			sqr_eltfp25519_2w_bmi2(AB);		/* A = A^2      |  B = B^2 */
++			mul_eltfp25519_2w_bmi2(UZr1, ZUr2, AB);	/* Ur1 = Zr2*A  |  Zr1 = Ur2*B */
++			++j;
++		}
++		j = 0;
++	}
++
++	/* Doubling */
++	for (i = 0; i < q; ++i) {
++		add_eltfp25519_1w_bmi2(A, Ur1, Zr1);	/*  A = Ur1+Zr1 */
++		sub_eltfp25519_1w(B, Ur1, Zr1);		/*  B = Ur1-Zr1 */
++		sqr_eltfp25519_2w_bmi2(AB);		/*  A = A**2     B = B**2 */
++		copy_eltfp25519_1w(C, B);		/*  C = B */
++		sub_eltfp25519_1w(B, A, B);		/*  B = A-B */
++		mul_a24_eltfp25519_1w(D, B);		/*  D = my_a24*B */
++		add_eltfp25519_1w_bmi2(D, D, C);	/*  D = D+C */
++		mul_eltfp25519_2w_bmi2(UZr1, AB, CD);	/*  Ur1 = A*B   Zr1 = Zr1*A */
++	}
++
++	/* Convert to affine coordinates */
++	inv_eltfp25519_1w_bmi2(A, Zr1);
++	mul_eltfp25519_1w_bmi2((u64 *)session_key, Ur1, A);
++	fred_eltfp25519_1w((u64 *)session_key);
++
++	memzero_explicit(&m, sizeof(m));
++}
++
++void curve25519_arch(u8 mypublic[CURVE25519_KEY_SIZE],
++		     const u8 secret[CURVE25519_KEY_SIZE],
++		     const u8 basepoint[CURVE25519_KEY_SIZE])
++{
++	if (static_branch_likely(&curve25519_use_adx))
++		curve25519_adx(mypublic, secret, basepoint);
++	else if (static_branch_likely(&curve25519_use_bmi2))
++		curve25519_bmi2(mypublic, secret, basepoint);
++	else
++		curve25519_generic(mypublic, secret, basepoint);
++}
++EXPORT_SYMBOL(curve25519_arch);
++
++void curve25519_base_arch(u8 pub[CURVE25519_KEY_SIZE],
++			  const u8 secret[CURVE25519_KEY_SIZE])
++{
++	if (static_branch_likely(&curve25519_use_adx))
++		curve25519_adx_base(pub, secret);
++	else if (static_branch_likely(&curve25519_use_bmi2))
++		curve25519_bmi2_base(pub, secret);
++	else
++		curve25519_generic(pub, secret, curve25519_base_point);
++}
++EXPORT_SYMBOL(curve25519_base_arch);
++
++static int curve25519_set_secret(struct crypto_kpp *tfm, const void *buf,
++				 unsigned int len)
++{
++	u8 *secret = kpp_tfm_ctx(tfm);
++
++	if (!len)
++		curve25519_generate_secret(secret);
++	else if (len == CURVE25519_KEY_SIZE &&
++		 crypto_memneq(buf, curve25519_null_point, CURVE25519_KEY_SIZE))
++		memcpy(secret, buf, CURVE25519_KEY_SIZE);
++	else
++		return -EINVAL;
++	return 0;
++}
++
++static int curve25519_generate_public_key(struct kpp_request *req)
++{
++	struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
++	const u8 *secret = kpp_tfm_ctx(tfm);
++	u8 buf[CURVE25519_KEY_SIZE];
++	int copied, nbytes;
++
++	if (req->src)
++		return -EINVAL;
++
++	curve25519_base_arch(buf, secret);
++
++	/* might want less than we've got */
++	nbytes = min_t(size_t, CURVE25519_KEY_SIZE, req->dst_len);
++	copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst,
++								nbytes),
++				     buf, nbytes);
++	if (copied != nbytes)
++		return -EINVAL;
++	return 0;
++}
++
++static int curve25519_compute_shared_secret(struct kpp_request *req)
++{
++	struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
++	const u8 *secret = kpp_tfm_ctx(tfm);
++	u8 public_key[CURVE25519_KEY_SIZE];
++	u8 buf[CURVE25519_KEY_SIZE];
++	int copied, nbytes;
++
++	if (!req->src)
++		return -EINVAL;
++
++	copied = sg_copy_to_buffer(req->src,
++				   sg_nents_for_len(req->src,
++						    CURVE25519_KEY_SIZE),
++				   public_key, CURVE25519_KEY_SIZE);
++	if (copied != CURVE25519_KEY_SIZE)
++		return -EINVAL;
++
++	curve25519_arch(buf, secret, public_key);
++
++	/* might want less than we've got */
++	nbytes = min_t(size_t, CURVE25519_KEY_SIZE, req->dst_len);
++	copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst,
++								nbytes),
++				     buf, nbytes);
++	if (copied != nbytes)
++		return -EINVAL;
++	return 0;
++}
++
++static unsigned int curve25519_max_size(struct crypto_kpp *tfm)
++{
++	return CURVE25519_KEY_SIZE;
++}
++
++static struct kpp_alg curve25519_alg = {
++	.base.cra_name		= "curve25519",
++	.base.cra_driver_name	= "curve25519-x86",
++	.base.cra_priority	= 200,
++	.base.cra_module	= THIS_MODULE,
++	.base.cra_ctxsize	= CURVE25519_KEY_SIZE,
++
++	.set_secret		= curve25519_set_secret,
++	.generate_public_key	= curve25519_generate_public_key,
++	.compute_shared_secret	= curve25519_compute_shared_secret,
++	.max_size		= curve25519_max_size,
++};
++
++static int __init curve25519_mod_init(void)
++{
++	if (boot_cpu_has(X86_FEATURE_BMI2))
++		static_branch_enable(&curve25519_use_bmi2);
++	else if (boot_cpu_has(X86_FEATURE_ADX))
++		static_branch_enable(&curve25519_use_adx);
++	else
++		return 0;
++	return crypto_register_kpp(&curve25519_alg);
++}
++
++static void __exit curve25519_mod_exit(void)
++{
++	if (boot_cpu_has(X86_FEATURE_BMI2) ||
++	    boot_cpu_has(X86_FEATURE_ADX))
++		crypto_unregister_kpp(&curve25519_alg);
++}
++
++module_init(curve25519_mod_init);
++module_exit(curve25519_mod_exit);
++
++MODULE_ALIAS_CRYPTO("curve25519");
++MODULE_ALIAS_CRYPTO("curve25519-x86");
++MODULE_LICENSE("GPL v2");
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -269,6 +269,12 @@ config CRYPTO_CURVE25519
+ 	select CRYPTO_KPP
+ 	select CRYPTO_LIB_CURVE25519_GENERIC
+ 
++config CRYPTO_CURVE25519_X86
++	tristate "x86_64 accelerated Curve25519 scalar multiplication library"
++	depends on X86 && 64BIT
++	select CRYPTO_LIB_CURVE25519_GENERIC
++	select CRYPTO_ARCH_HAVE_LIB_CURVE25519
++
+ comment "Authenticated Encryption with Associated Data"
+ 
+ config CRYPTO_CCM
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0030-crypto-arm-curve25519-import-Bernstein-and-Schwabe-s.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0030-crypto-arm-curve25519-import-Bernstein-and-Schwabe-s.patch
new file mode 100644
index 0000000..8fda25d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0030-crypto-arm-curve25519-import-Bernstein-and-Schwabe-s.patch
@@ -0,0 +1,2135 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 8 Nov 2019 13:22:37 +0100
+Subject: [PATCH] crypto: arm/curve25519 - import Bernstein and Schwabe's
+ Curve25519 ARM implementation
+
+commit f0fb006b604f98e2309a30f34ef455ac734f7c1c upstream.
+
+This comes from Dan Bernstein and Peter Schwabe's public domain NEON
+code, and is included here in raw form so that subsequent commits that
+fix these up for the kernel can see how it has changed. This code does
+have some entirely cosmetic formatting differences, adding indentation
+and so forth, so that when we actually port it for use in the kernel in
+the subsequent commit, it's obvious what's changed in the process.
+
+This code originates from SUPERCOP 20180818, available at
+<https://bench.cr.yp.to/supercop.html>.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm/crypto/curve25519-core.S | 2105 +++++++++++++++++++++++++++++
+ 1 file changed, 2105 insertions(+)
+ create mode 100644 arch/arm/crypto/curve25519-core.S
+
+--- /dev/null
++++ b/arch/arm/crypto/curve25519-core.S
+@@ -0,0 +1,2105 @@
++/*
++ * Public domain code from Daniel J. Bernstein and Peter Schwabe, from
++ * SUPERCOP's curve25519/neon2/scalarmult.s.
++ */
++
++.fpu neon
++.text
++.align 4
++.global _crypto_scalarmult_curve25519_neon2
++.global crypto_scalarmult_curve25519_neon2
++.type _crypto_scalarmult_curve25519_neon2 STT_FUNC
++.type crypto_scalarmult_curve25519_neon2 STT_FUNC
++	_crypto_scalarmult_curve25519_neon2:
++	crypto_scalarmult_curve25519_neon2:
++	vpush		{q4, q5, q6, q7}
++	mov		r12, sp
++	sub		sp, sp, #736
++	and		sp, sp, #0xffffffe0
++	strd		r4, [sp, #0]
++	strd		r6, [sp, #8]
++	strd		r8, [sp, #16]
++	strd		r10, [sp, #24]
++	str		r12, [sp, #480]
++	str		r14, [sp, #484]
++	mov		r0, r0
++	mov		r1, r1
++	mov		r2, r2
++	add		r3, sp, #32
++	ldr		r4, =0
++	ldr		r5, =254
++	vmov.i32	q0, #1
++	vshr.u64	q1, q0, #7
++	vshr.u64	q0, q0, #8
++	vmov.i32	d4, #19
++	vmov.i32	d5, #38
++	add		r6, sp, #512
++	vst1.8		{d2-d3}, [r6, : 128]
++	add		r6, sp, #528
++	vst1.8		{d0-d1}, [r6, : 128]
++	add		r6, sp, #544
++	vst1.8		{d4-d5}, [r6, : 128]
++	add		r6, r3, #0
++	vmov.i32	q2, #0
++	vst1.8		{d4-d5}, [r6, : 128]!
++	vst1.8		{d4-d5}, [r6, : 128]!
++	vst1.8		d4, [r6, : 64]
++	add		r6, r3, #0
++	ldr		r7, =960
++	sub		r7, r7, #2
++	neg		r7, r7
++	sub		r7, r7, r7, LSL #7
++	str		r7, [r6]
++	add		r6, sp, #704
++	vld1.8		{d4-d5}, [r1]!
++	vld1.8		{d6-d7}, [r1]
++	vst1.8		{d4-d5}, [r6, : 128]!
++	vst1.8		{d6-d7}, [r6, : 128]
++	sub		r1, r6, #16
++	ldrb		r6, [r1]
++	and		r6, r6, #248
++	strb		r6, [r1]
++	ldrb		r6, [r1, #31]
++	and		r6, r6, #127
++	orr		r6, r6, #64
++	strb		r6, [r1, #31]
++	vmov.i64	q2, #0xffffffff
++	vshr.u64	q3, q2, #7
++	vshr.u64	q2, q2, #6
++	vld1.8		{d8}, [r2]
++	vld1.8		{d10}, [r2]
++	add		r2, r2, #6
++	vld1.8		{d12}, [r2]
++	vld1.8		{d14}, [r2]
++	add		r2, r2, #6
++	vld1.8		{d16}, [r2]
++	add		r2, r2, #4
++	vld1.8		{d18}, [r2]
++	vld1.8		{d20}, [r2]
++	add		r2, r2, #6
++	vld1.8		{d22}, [r2]
++	add		r2, r2, #2
++	vld1.8		{d24}, [r2]
++	vld1.8		{d26}, [r2]
++	vshr.u64	q5, q5, #26
++	vshr.u64	q6, q6, #3
++	vshr.u64	q7, q7, #29
++	vshr.u64	q8, q8, #6
++	vshr.u64	q10, q10, #25
++	vshr.u64	q11, q11, #3
++	vshr.u64	q12, q12, #12
++	vshr.u64	q13, q13, #38
++	vand		q4, q4, q2
++	vand		q6, q6, q2
++	vand		q8, q8, q2
++	vand		q10, q10, q2
++	vand		q2, q12, q2
++	vand		q5, q5, q3
++	vand		q7, q7, q3
++	vand		q9, q9, q3
++	vand		q11, q11, q3
++	vand		q3, q13, q3
++	add		r2, r3, #48
++	vadd.i64	q12, q4, q1
++	vadd.i64	q13, q10, q1
++	vshr.s64	q12, q12, #26
++	vshr.s64	q13, q13, #26
++	vadd.i64	q5, q5, q12
++	vshl.i64	q12, q12, #26
++	vadd.i64	q14, q5, q0
++	vadd.i64	q11, q11, q13
++	vshl.i64	q13, q13, #26
++	vadd.i64	q15, q11, q0
++	vsub.i64	q4, q4, q12
++	vshr.s64	q12, q14, #25
++	vsub.i64	q10, q10, q13
++	vshr.s64	q13, q15, #25
++	vadd.i64	q6, q6, q12
++	vshl.i64	q12, q12, #25
++	vadd.i64	q14, q6, q1
++	vadd.i64	q2, q2, q13
++	vsub.i64	q5, q5, q12
++	vshr.s64	q12, q14, #26
++	vshl.i64	q13, q13, #25
++	vadd.i64	q14, q2, q1
++	vadd.i64	q7, q7, q12
++	vshl.i64	q12, q12, #26
++	vadd.i64	q15, q7, q0
++	vsub.i64	q11, q11, q13
++	vshr.s64	q13, q14, #26
++	vsub.i64	q6, q6, q12
++	vshr.s64	q12, q15, #25
++	vadd.i64	q3, q3, q13
++	vshl.i64	q13, q13, #26
++	vadd.i64	q14, q3, q0
++	vadd.i64	q8, q8, q12
++	vshl.i64	q12, q12, #25
++	vadd.i64	q15, q8, q1
++	add		r2, r2, #8
++	vsub.i64	q2, q2, q13
++	vshr.s64	q13, q14, #25
++	vsub.i64	q7, q7, q12
++	vshr.s64	q12, q15, #26
++	vadd.i64	q14, q13, q13
++	vadd.i64	q9, q9, q12
++	vtrn.32		d12, d14
++	vshl.i64	q12, q12, #26
++	vtrn.32		d13, d15
++	vadd.i64	q0, q9, q0
++	vadd.i64	q4, q4, q14
++	vst1.8		d12, [r2, : 64]!
++	vshl.i64	q6, q13, #4
++	vsub.i64	q7, q8, q12
++	vshr.s64	q0, q0, #25
++	vadd.i64	q4, q4, q6
++	vadd.i64	q6, q10, q0
++	vshl.i64	q0, q0, #25
++	vadd.i64	q8, q6, q1
++	vadd.i64	q4, q4, q13
++	vshl.i64	q10, q13, #25
++	vadd.i64	q1, q4, q1
++	vsub.i64	q0, q9, q0
++	vshr.s64	q8, q8, #26
++	vsub.i64	q3, q3, q10
++	vtrn.32		d14, d0
++	vshr.s64	q1, q1, #26
++	vtrn.32		d15, d1
++	vadd.i64	q0, q11, q8
++	vst1.8		d14, [r2, : 64]
++	vshl.i64	q7, q8, #26
++	vadd.i64	q5, q5, q1
++	vtrn.32		d4, d6
++	vshl.i64	q1, q1, #26
++	vtrn.32		d5, d7
++	vsub.i64	q3, q6, q7
++	add		r2, r2, #16
++	vsub.i64	q1, q4, q1
++	vst1.8		d4, [r2, : 64]
++	vtrn.32		d6, d0
++	vtrn.32		d7, d1
++	sub		r2, r2, #8
++	vtrn.32		d2, d10
++	vtrn.32		d3, d11
++	vst1.8		d6, [r2, : 64]
++	sub		r2, r2, #24
++	vst1.8		d2, [r2, : 64]
++	add		r2, r3, #96
++	vmov.i32	q0, #0
++	vmov.i64	d2, #0xff
++	vmov.i64	d3, #0
++	vshr.u32	q1, q1, #7
++	vst1.8		{d2-d3}, [r2, : 128]!
++	vst1.8		{d0-d1}, [r2, : 128]!
++	vst1.8		d0, [r2, : 64]
++	add		r2, r3, #144
++	vmov.i32	q0, #0
++	vst1.8		{d0-d1}, [r2, : 128]!
++	vst1.8		{d0-d1}, [r2, : 128]!
++	vst1.8		d0, [r2, : 64]
++	add		r2, r3, #240
++	vmov.i32	q0, #0
++	vmov.i64	d2, #0xff
++	vmov.i64	d3, #0
++	vshr.u32	q1, q1, #7
++	vst1.8		{d2-d3}, [r2, : 128]!
++	vst1.8		{d0-d1}, [r2, : 128]!
++	vst1.8		d0, [r2, : 64]
++	add		r2, r3, #48
++	add		r6, r3, #192
++	vld1.8		{d0-d1}, [r2, : 128]!
++	vld1.8		{d2-d3}, [r2, : 128]!
++	vld1.8		{d4}, [r2, : 64]
++	vst1.8		{d0-d1}, [r6, : 128]!
++	vst1.8		{d2-d3}, [r6, : 128]!
++	vst1.8		d4, [r6, : 64]
++._mainloop:
++	mov		r2, r5, LSR #3
++	and		r6, r5, #7
++	ldrb		r2, [r1, r2]
++	mov		r2, r2, LSR r6
++	and		r2, r2, #1
++	str		r5, [sp, #488]
++	eor		r4, r4, r2
++	str		r2, [sp, #492]
++	neg		r2, r4
++	add		r4, r3, #96
++	add		r5, r3, #192
++	add		r6, r3, #144
++	vld1.8		{d8-d9}, [r4, : 128]!
++	add		r7, r3, #240
++	vld1.8		{d10-d11}, [r5, : 128]!
++	veor		q6, q4, q5
++	vld1.8		{d14-d15}, [r6, : 128]!
++	vdup.i32	q8, r2
++	vld1.8		{d18-d19}, [r7, : 128]!
++	veor		q10, q7, q9
++	vld1.8		{d22-d23}, [r4, : 128]!
++	vand		q6, q6, q8
++	vld1.8		{d24-d25}, [r5, : 128]!
++	vand		q10, q10, q8
++	vld1.8		{d26-d27}, [r6, : 128]!
++	veor		q4, q4, q6
++	vld1.8		{d28-d29}, [r7, : 128]!
++	veor		q5, q5, q6
++	vld1.8		{d0}, [r4, : 64]
++	veor		q6, q7, q10
++	vld1.8		{d2}, [r5, : 64]
++	veor		q7, q9, q10
++	vld1.8		{d4}, [r6, : 64]
++	veor		q9, q11, q12
++	vld1.8		{d6}, [r7, : 64]
++	veor		q10, q0, q1
++	sub		r2, r4, #32
++	vand		q9, q9, q8
++	sub		r4, r5, #32
++	vand		q10, q10, q8
++	sub		r5, r6, #32
++	veor		q11, q11, q9
++	sub		r6, r7, #32
++	veor		q0, q0, q10
++	veor		q9, q12, q9
++	veor		q1, q1, q10
++	veor		q10, q13, q14
++	veor		q12, q2, q3
++	vand		q10, q10, q8
++	vand		q8, q12, q8
++	veor		q12, q13, q10
++	veor		q2, q2, q8
++	veor		q10, q14, q10
++	veor		q3, q3, q8
++	vadd.i32	q8, q4, q6
++	vsub.i32	q4, q4, q6
++	vst1.8		{d16-d17}, [r2, : 128]!
++	vadd.i32	q6, q11, q12
++	vst1.8		{d8-d9}, [r5, : 128]!
++	vsub.i32	q4, q11, q12
++	vst1.8		{d12-d13}, [r2, : 128]!
++	vadd.i32	q6, q0, q2
++	vst1.8		{d8-d9}, [r5, : 128]!
++	vsub.i32	q0, q0, q2
++	vst1.8		d12, [r2, : 64]
++	vadd.i32	q2, q5, q7
++	vst1.8		d0, [r5, : 64]
++	vsub.i32	q0, q5, q7
++	vst1.8		{d4-d5}, [r4, : 128]!
++	vadd.i32	q2, q9, q10
++	vst1.8		{d0-d1}, [r6, : 128]!
++	vsub.i32	q0, q9, q10
++	vst1.8		{d4-d5}, [r4, : 128]!
++	vadd.i32	q2, q1, q3
++	vst1.8		{d0-d1}, [r6, : 128]!
++	vsub.i32	q0, q1, q3
++	vst1.8		d4, [r4, : 64]
++	vst1.8		d0, [r6, : 64]
++	add		r2, sp, #544
++	add		r4, r3, #96
++	add		r5, r3, #144
++	vld1.8		{d0-d1}, [r2, : 128]
++	vld1.8		{d2-d3}, [r4, : 128]!
++	vld1.8		{d4-d5}, [r5, : 128]!
++	vzip.i32	q1, q2
++	vld1.8		{d6-d7}, [r4, : 128]!
++	vld1.8		{d8-d9}, [r5, : 128]!
++	vshl.i32	q5, q1, #1
++	vzip.i32	q3, q4
++	vshl.i32	q6, q2, #1
++	vld1.8		{d14}, [r4, : 64]
++	vshl.i32	q8, q3, #1
++	vld1.8		{d15}, [r5, : 64]
++	vshl.i32	q9, q4, #1
++	vmul.i32	d21, d7, d1
++	vtrn.32		d14, d15
++	vmul.i32	q11, q4, q0
++	vmul.i32	q0, q7, q0
++	vmull.s32	q12, d2, d2
++	vmlal.s32	q12, d11, d1
++	vmlal.s32	q12, d12, d0
++	vmlal.s32	q12, d13, d23
++	vmlal.s32	q12, d16, d22
++	vmlal.s32	q12, d7, d21
++	vmull.s32	q10, d2, d11
++	vmlal.s32	q10, d4, d1
++	vmlal.s32	q10, d13, d0
++	vmlal.s32	q10, d6, d23
++	vmlal.s32	q10, d17, d22
++	vmull.s32	q13, d10, d4
++	vmlal.s32	q13, d11, d3
++	vmlal.s32	q13, d13, d1
++	vmlal.s32	q13, d16, d0
++	vmlal.s32	q13, d17, d23
++	vmlal.s32	q13, d8, d22
++	vmull.s32	q1, d10, d5
++	vmlal.s32	q1, d11, d4
++	vmlal.s32	q1, d6, d1
++	vmlal.s32	q1, d17, d0
++	vmlal.s32	q1, d8, d23
++	vmull.s32	q14, d10, d6
++	vmlal.s32	q14, d11, d13
++	vmlal.s32	q14, d4, d4
++	vmlal.s32	q14, d17, d1
++	vmlal.s32	q14, d18, d0
++	vmlal.s32	q14, d9, d23
++	vmull.s32	q11, d10, d7
++	vmlal.s32	q11, d11, d6
++	vmlal.s32	q11, d12, d5
++	vmlal.s32	q11, d8, d1
++	vmlal.s32	q11, d19, d0
++	vmull.s32	q15, d10, d8
++	vmlal.s32	q15, d11, d17
++	vmlal.s32	q15, d12, d6
++	vmlal.s32	q15, d13, d5
++	vmlal.s32	q15, d19, d1
++	vmlal.s32	q15, d14, d0
++	vmull.s32	q2, d10, d9
++	vmlal.s32	q2, d11, d8
++	vmlal.s32	q2, d12, d7
++	vmlal.s32	q2, d13, d6
++	vmlal.s32	q2, d14, d1
++	vmull.s32	q0, d15, d1
++	vmlal.s32	q0, d10, d14
++	vmlal.s32	q0, d11, d19
++	vmlal.s32	q0, d12, d8
++	vmlal.s32	q0, d13, d17
++	vmlal.s32	q0, d6, d6
++	add		r2, sp, #512
++	vld1.8		{d18-d19}, [r2, : 128]
++	vmull.s32	q3, d16, d7
++	vmlal.s32	q3, d10, d15
++	vmlal.s32	q3, d11, d14
++	vmlal.s32	q3, d12, d9
++	vmlal.s32	q3, d13, d8
++	add		r2, sp, #528
++	vld1.8		{d8-d9}, [r2, : 128]
++	vadd.i64	q5, q12, q9
++	vadd.i64	q6, q15, q9
++	vshr.s64	q5, q5, #26
++	vshr.s64	q6, q6, #26
++	vadd.i64	q7, q10, q5
++	vshl.i64	q5, q5, #26
++	vadd.i64	q8, q7, q4
++	vadd.i64	q2, q2, q6
++	vshl.i64	q6, q6, #26
++	vadd.i64	q10, q2, q4
++	vsub.i64	q5, q12, q5
++	vshr.s64	q8, q8, #25
++	vsub.i64	q6, q15, q6
++	vshr.s64	q10, q10, #25
++	vadd.i64	q12, q13, q8
++	vshl.i64	q8, q8, #25
++	vadd.i64	q13, q12, q9
++	vadd.i64	q0, q0, q10
++	vsub.i64	q7, q7, q8
++	vshr.s64	q8, q13, #26
++	vshl.i64	q10, q10, #25
++	vadd.i64	q13, q0, q9
++	vadd.i64	q1, q1, q8
++	vshl.i64	q8, q8, #26
++	vadd.i64	q15, q1, q4
++	vsub.i64	q2, q2, q10
++	vshr.s64	q10, q13, #26
++	vsub.i64	q8, q12, q8
++	vshr.s64	q12, q15, #25
++	vadd.i64	q3, q3, q10
++	vshl.i64	q10, q10, #26
++	vadd.i64	q13, q3, q4
++	vadd.i64	q14, q14, q12
++	add		r2, r3, #288
++	vshl.i64	q12, q12, #25
++	add		r4, r3, #336
++	vadd.i64	q15, q14, q9
++	add		r2, r2, #8
++	vsub.i64	q0, q0, q10
++	add		r4, r4, #8
++	vshr.s64	q10, q13, #25
++	vsub.i64	q1, q1, q12
++	vshr.s64	q12, q15, #26
++	vadd.i64	q13, q10, q10
++	vadd.i64	q11, q11, q12
++	vtrn.32		d16, d2
++	vshl.i64	q12, q12, #26
++	vtrn.32		d17, d3
++	vadd.i64	q1, q11, q4
++	vadd.i64	q4, q5, q13
++	vst1.8		d16, [r2, : 64]!
++	vshl.i64	q5, q10, #4
++	vst1.8		d17, [r4, : 64]!
++	vsub.i64	q8, q14, q12
++	vshr.s64	q1, q1, #25
++	vadd.i64	q4, q4, q5
++	vadd.i64	q5, q6, q1
++	vshl.i64	q1, q1, #25
++	vadd.i64	q6, q5, q9
++	vadd.i64	q4, q4, q10
++	vshl.i64	q10, q10, #25
++	vadd.i64	q9, q4, q9
++	vsub.i64	q1, q11, q1
++	vshr.s64	q6, q6, #26
++	vsub.i64	q3, q3, q10
++	vtrn.32		d16, d2
++	vshr.s64	q9, q9, #26
++	vtrn.32		d17, d3
++	vadd.i64	q1, q2, q6
++	vst1.8		d16, [r2, : 64]
++	vshl.i64	q2, q6, #26
++	vst1.8		d17, [r4, : 64]
++	vadd.i64	q6, q7, q9
++	vtrn.32		d0, d6
++	vshl.i64	q7, q9, #26
++	vtrn.32		d1, d7
++	vsub.i64	q2, q5, q2
++	add		r2, r2, #16
++	vsub.i64	q3, q4, q7
++	vst1.8		d0, [r2, : 64]
++	add		r4, r4, #16
++	vst1.8		d1, [r4, : 64]
++	vtrn.32		d4, d2
++	vtrn.32		d5, d3
++	sub		r2, r2, #8
++	sub		r4, r4, #8
++	vtrn.32		d6, d12
++	vtrn.32		d7, d13
++	vst1.8		d4, [r2, : 64]
++	vst1.8		d5, [r4, : 64]
++	sub		r2, r2, #24
++	sub		r4, r4, #24
++	vst1.8		d6, [r2, : 64]
++	vst1.8		d7, [r4, : 64]
++	add		r2, r3, #240
++	add		r4, r3, #96
++	vld1.8		{d0-d1}, [r4, : 128]!
++	vld1.8		{d2-d3}, [r4, : 128]!
++	vld1.8		{d4}, [r4, : 64]
++	add		r4, r3, #144
++	vld1.8		{d6-d7}, [r4, : 128]!
++	vtrn.32		q0, q3
++	vld1.8		{d8-d9}, [r4, : 128]!
++	vshl.i32	q5, q0, #4
++	vtrn.32		q1, q4
++	vshl.i32	q6, q3, #4
++	vadd.i32	q5, q5, q0
++	vadd.i32	q6, q6, q3
++	vshl.i32	q7, q1, #4
++	vld1.8		{d5}, [r4, : 64]
++	vshl.i32	q8, q4, #4
++	vtrn.32		d4, d5
++	vadd.i32	q7, q7, q1
++	vadd.i32	q8, q8, q4
++	vld1.8		{d18-d19}, [r2, : 128]!
++	vshl.i32	q10, q2, #4
++	vld1.8		{d22-d23}, [r2, : 128]!
++	vadd.i32	q10, q10, q2
++	vld1.8		{d24}, [r2, : 64]
++	vadd.i32	q5, q5, q0
++	add		r2, r3, #192
++	vld1.8		{d26-d27}, [r2, : 128]!
++	vadd.i32	q6, q6, q3
++	vld1.8		{d28-d29}, [r2, : 128]!
++	vadd.i32	q8, q8, q4
++	vld1.8		{d25}, [r2, : 64]
++	vadd.i32	q10, q10, q2
++	vtrn.32		q9, q13
++	vadd.i32	q7, q7, q1
++	vadd.i32	q5, q5, q0
++	vtrn.32		q11, q14
++	vadd.i32	q6, q6, q3
++	add		r2, sp, #560
++	vadd.i32	q10, q10, q2
++	vtrn.32		d24, d25
++	vst1.8		{d12-d13}, [r2, : 128]
++	vshl.i32	q6, q13, #1
++	add		r2, sp, #576
++	vst1.8		{d20-d21}, [r2, : 128]
++	vshl.i32	q10, q14, #1
++	add		r2, sp, #592
++	vst1.8		{d12-d13}, [r2, : 128]
++	vshl.i32	q15, q12, #1
++	vadd.i32	q8, q8, q4
++	vext.32		d10, d31, d30, #0
++	vadd.i32	q7, q7, q1
++	add		r2, sp, #608
++	vst1.8		{d16-d17}, [r2, : 128]
++	vmull.s32	q8, d18, d5
++	vmlal.s32	q8, d26, d4
++	vmlal.s32	q8, d19, d9
++	vmlal.s32	q8, d27, d3
++	vmlal.s32	q8, d22, d8
++	vmlal.s32	q8, d28, d2
++	vmlal.s32	q8, d23, d7
++	vmlal.s32	q8, d29, d1
++	vmlal.s32	q8, d24, d6
++	vmlal.s32	q8, d25, d0
++	add		r2, sp, #624
++	vst1.8		{d14-d15}, [r2, : 128]
++	vmull.s32	q2, d18, d4
++	vmlal.s32	q2, d12, d9
++	vmlal.s32	q2, d13, d8
++	vmlal.s32	q2, d19, d3
++	vmlal.s32	q2, d22, d2
++	vmlal.s32	q2, d23, d1
++	vmlal.s32	q2, d24, d0
++	add		r2, sp, #640
++	vst1.8		{d20-d21}, [r2, : 128]
++	vmull.s32	q7, d18, d9
++	vmlal.s32	q7, d26, d3
++	vmlal.s32	q7, d19, d8
++	vmlal.s32	q7, d27, d2
++	vmlal.s32	q7, d22, d7
++	vmlal.s32	q7, d28, d1
++	vmlal.s32	q7, d23, d6
++	vmlal.s32	q7, d29, d0
++	add		r2, sp, #656
++	vst1.8		{d10-d11}, [r2, : 128]
++	vmull.s32	q5, d18, d3
++	vmlal.s32	q5, d19, d2
++	vmlal.s32	q5, d22, d1
++	vmlal.s32	q5, d23, d0
++	vmlal.s32	q5, d12, d8
++	add		r2, sp, #672
++	vst1.8		{d16-d17}, [r2, : 128]
++	vmull.s32	q4, d18, d8
++	vmlal.s32	q4, d26, d2
++	vmlal.s32	q4, d19, d7
++	vmlal.s32	q4, d27, d1
++	vmlal.s32	q4, d22, d6
++	vmlal.s32	q4, d28, d0
++	vmull.s32	q8, d18, d7
++	vmlal.s32	q8, d26, d1
++	vmlal.s32	q8, d19, d6
++	vmlal.s32	q8, d27, d0
++	add		r2, sp, #576
++	vld1.8		{d20-d21}, [r2, : 128]
++	vmlal.s32	q7, d24, d21
++	vmlal.s32	q7, d25, d20
++	vmlal.s32	q4, d23, d21
++	vmlal.s32	q4, d29, d20
++	vmlal.s32	q8, d22, d21
++	vmlal.s32	q8, d28, d20
++	vmlal.s32	q5, d24, d20
++	add		r2, sp, #576
++	vst1.8		{d14-d15}, [r2, : 128]
++	vmull.s32	q7, d18, d6
++	vmlal.s32	q7, d26, d0
++	add		r2, sp, #656
++	vld1.8		{d30-d31}, [r2, : 128]
++	vmlal.s32	q2, d30, d21
++	vmlal.s32	q7, d19, d21
++	vmlal.s32	q7, d27, d20
++	add		r2, sp, #624
++	vld1.8		{d26-d27}, [r2, : 128]
++	vmlal.s32	q4, d25, d27
++	vmlal.s32	q8, d29, d27
++	vmlal.s32	q8, d25, d26
++	vmlal.s32	q7, d28, d27
++	vmlal.s32	q7, d29, d26
++	add		r2, sp, #608
++	vld1.8		{d28-d29}, [r2, : 128]
++	vmlal.s32	q4, d24, d29
++	vmlal.s32	q8, d23, d29
++	vmlal.s32	q8, d24, d28
++	vmlal.s32	q7, d22, d29
++	vmlal.s32	q7, d23, d28
++	add		r2, sp, #608
++	vst1.8		{d8-d9}, [r2, : 128]
++	add		r2, sp, #560
++	vld1.8		{d8-d9}, [r2, : 128]
++	vmlal.s32	q7, d24, d9
++	vmlal.s32	q7, d25, d31
++	vmull.s32	q1, d18, d2
++	vmlal.s32	q1, d19, d1
++	vmlal.s32	q1, d22, d0
++	vmlal.s32	q1, d24, d27
++	vmlal.s32	q1, d23, d20
++	vmlal.s32	q1, d12, d7
++	vmlal.s32	q1, d13, d6
++	vmull.s32	q6, d18, d1
++	vmlal.s32	q6, d19, d0
++	vmlal.s32	q6, d23, d27
++	vmlal.s32	q6, d22, d20
++	vmlal.s32	q6, d24, d26
++	vmull.s32	q0, d18, d0
++	vmlal.s32	q0, d22, d27
++	vmlal.s32	q0, d23, d26
++	vmlal.s32	q0, d24, d31
++	vmlal.s32	q0, d19, d20
++	add		r2, sp, #640
++	vld1.8		{d18-d19}, [r2, : 128]
++	vmlal.s32	q2, d18, d7
++	vmlal.s32	q2, d19, d6
++	vmlal.s32	q5, d18, d6
++	vmlal.s32	q5, d19, d21
++	vmlal.s32	q1, d18, d21
++	vmlal.s32	q1, d19, d29
++	vmlal.s32	q0, d18, d28
++	vmlal.s32	q0, d19, d9
++	vmlal.s32	q6, d18, d29
++	vmlal.s32	q6, d19, d28
++	add		r2, sp, #592
++	vld1.8		{d18-d19}, [r2, : 128]
++	add		r2, sp, #512
++	vld1.8		{d22-d23}, [r2, : 128]
++	vmlal.s32	q5, d19, d7
++	vmlal.s32	q0, d18, d21
++	vmlal.s32	q0, d19, d29
++	vmlal.s32	q6, d18, d6
++	add		r2, sp, #528
++	vld1.8		{d6-d7}, [r2, : 128]
++	vmlal.s32	q6, d19, d21
++	add		r2, sp, #576
++	vld1.8		{d18-d19}, [r2, : 128]
++	vmlal.s32	q0, d30, d8
++	add		r2, sp, #672
++	vld1.8		{d20-d21}, [r2, : 128]
++	vmlal.s32	q5, d30, d29
++	add		r2, sp, #608
++	vld1.8		{d24-d25}, [r2, : 128]
++	vmlal.s32	q1, d30, d28
++	vadd.i64	q13, q0, q11
++	vadd.i64	q14, q5, q11
++	vmlal.s32	q6, d30, d9
++	vshr.s64	q4, q13, #26
++	vshr.s64	q13, q14, #26
++	vadd.i64	q7, q7, q4
++	vshl.i64	q4, q4, #26
++	vadd.i64	q14, q7, q3
++	vadd.i64	q9, q9, q13
++	vshl.i64	q13, q13, #26
++	vadd.i64	q15, q9, q3
++	vsub.i64	q0, q0, q4
++	vshr.s64	q4, q14, #25
++	vsub.i64	q5, q5, q13
++	vshr.s64	q13, q15, #25
++	vadd.i64	q6, q6, q4
++	vshl.i64	q4, q4, #25
++	vadd.i64	q14, q6, q11
++	vadd.i64	q2, q2, q13
++	vsub.i64	q4, q7, q4
++	vshr.s64	q7, q14, #26
++	vshl.i64	q13, q13, #25
++	vadd.i64	q14, q2, q11
++	vadd.i64	q8, q8, q7
++	vshl.i64	q7, q7, #26
++	vadd.i64	q15, q8, q3
++	vsub.i64	q9, q9, q13
++	vshr.s64	q13, q14, #26
++	vsub.i64	q6, q6, q7
++	vshr.s64	q7, q15, #25
++	vadd.i64	q10, q10, q13
++	vshl.i64	q13, q13, #26
++	vadd.i64	q14, q10, q3
++	vadd.i64	q1, q1, q7
++	add		r2, r3, #144
++	vshl.i64	q7, q7, #25
++	add		r4, r3, #96
++	vadd.i64	q15, q1, q11
++	add		r2, r2, #8
++	vsub.i64	q2, q2, q13
++	add		r4, r4, #8
++	vshr.s64	q13, q14, #25
++	vsub.i64	q7, q8, q7
++	vshr.s64	q8, q15, #26
++	vadd.i64	q14, q13, q13
++	vadd.i64	q12, q12, q8
++	vtrn.32		d12, d14
++	vshl.i64	q8, q8, #26
++	vtrn.32		d13, d15
++	vadd.i64	q3, q12, q3
++	vadd.i64	q0, q0, q14
++	vst1.8		d12, [r2, : 64]!
++	vshl.i64	q7, q13, #4
++	vst1.8		d13, [r4, : 64]!
++	vsub.i64	q1, q1, q8
++	vshr.s64	q3, q3, #25
++	vadd.i64	q0, q0, q7
++	vadd.i64	q5, q5, q3
++	vshl.i64	q3, q3, #25
++	vadd.i64	q6, q5, q11
++	vadd.i64	q0, q0, q13
++	vshl.i64	q7, q13, #25
++	vadd.i64	q8, q0, q11
++	vsub.i64	q3, q12, q3
++	vshr.s64	q6, q6, #26
++	vsub.i64	q7, q10, q7
++	vtrn.32		d2, d6
++	vshr.s64	q8, q8, #26
++	vtrn.32		d3, d7
++	vadd.i64	q3, q9, q6
++	vst1.8		d2, [r2, : 64]
++	vshl.i64	q6, q6, #26
++	vst1.8		d3, [r4, : 64]
++	vadd.i64	q1, q4, q8
++	vtrn.32		d4, d14
++	vshl.i64	q4, q8, #26
++	vtrn.32		d5, d15
++	vsub.i64	q5, q5, q6
++	add		r2, r2, #16
++	vsub.i64	q0, q0, q4
++	vst1.8		d4, [r2, : 64]
++	add		r4, r4, #16
++	vst1.8		d5, [r4, : 64]
++	vtrn.32		d10, d6
++	vtrn.32		d11, d7
++	sub		r2, r2, #8
++	sub		r4, r4, #8
++	vtrn.32		d0, d2
++	vtrn.32		d1, d3
++	vst1.8		d10, [r2, : 64]
++	vst1.8		d11, [r4, : 64]
++	sub		r2, r2, #24
++	sub		r4, r4, #24
++	vst1.8		d0, [r2, : 64]
++	vst1.8		d1, [r4, : 64]
++	add		r2, r3, #288
++	add		r4, r3, #336
++	vld1.8		{d0-d1}, [r2, : 128]!
++	vld1.8		{d2-d3}, [r4, : 128]!
++	vsub.i32	q0, q0, q1
++	vld1.8		{d2-d3}, [r2, : 128]!
++	vld1.8		{d4-d5}, [r4, : 128]!
++	vsub.i32	q1, q1, q2
++	add		r5, r3, #240
++	vld1.8		{d4}, [r2, : 64]
++	vld1.8		{d6}, [r4, : 64]
++	vsub.i32	q2, q2, q3
++	vst1.8		{d0-d1}, [r5, : 128]!
++	vst1.8		{d2-d3}, [r5, : 128]!
++	vst1.8		d4, [r5, : 64]
++	add		r2, r3, #144
++	add		r4, r3, #96
++	add		r5, r3, #144
++	add		r6, r3, #192
++	vld1.8		{d0-d1}, [r2, : 128]!
++	vld1.8		{d2-d3}, [r4, : 128]!
++	vsub.i32	q2, q0, q1
++	vadd.i32	q0, q0, q1
++	vld1.8		{d2-d3}, [r2, : 128]!
++	vld1.8		{d6-d7}, [r4, : 128]!
++	vsub.i32	q4, q1, q3
++	vadd.i32	q1, q1, q3
++	vld1.8		{d6}, [r2, : 64]
++	vld1.8		{d10}, [r4, : 64]
++	vsub.i32	q6, q3, q5
++	vadd.i32	q3, q3, q5
++	vst1.8		{d4-d5}, [r5, : 128]!
++	vst1.8		{d0-d1}, [r6, : 128]!
++	vst1.8		{d8-d9}, [r5, : 128]!
++	vst1.8		{d2-d3}, [r6, : 128]!
++	vst1.8		d12, [r5, : 64]
++	vst1.8		d6, [r6, : 64]
++	add		r2, r3, #0
++	add		r4, r3, #240
++	vld1.8		{d0-d1}, [r4, : 128]!
++	vld1.8		{d2-d3}, [r4, : 128]!
++	vld1.8		{d4}, [r4, : 64]
++	add		r4, r3, #336
++	vld1.8		{d6-d7}, [r4, : 128]!
++	vtrn.32		q0, q3
++	vld1.8		{d8-d9}, [r4, : 128]!
++	vshl.i32	q5, q0, #4
++	vtrn.32		q1, q4
++	vshl.i32	q6, q3, #4
++	vadd.i32	q5, q5, q0
++	vadd.i32	q6, q6, q3
++	vshl.i32	q7, q1, #4
++	vld1.8		{d5}, [r4, : 64]
++	vshl.i32	q8, q4, #4
++	vtrn.32		d4, d5
++	vadd.i32	q7, q7, q1
++	vadd.i32	q8, q8, q4
++	vld1.8		{d18-d19}, [r2, : 128]!
++	vshl.i32	q10, q2, #4
++	vld1.8		{d22-d23}, [r2, : 128]!
++	vadd.i32	q10, q10, q2
++	vld1.8		{d24}, [r2, : 64]
++	vadd.i32	q5, q5, q0
++	add		r2, r3, #288
++	vld1.8		{d26-d27}, [r2, : 128]!
++	vadd.i32	q6, q6, q3
++	vld1.8		{d28-d29}, [r2, : 128]!
++	vadd.i32	q8, q8, q4
++	vld1.8		{d25}, [r2, : 64]
++	vadd.i32	q10, q10, q2
++	vtrn.32		q9, q13
++	vadd.i32	q7, q7, q1
++	vadd.i32	q5, q5, q0
++	vtrn.32		q11, q14
++	vadd.i32	q6, q6, q3
++	add		r2, sp, #560
++	vadd.i32	q10, q10, q2
++	vtrn.32		d24, d25
++	vst1.8		{d12-d13}, [r2, : 128]
++	vshl.i32	q6, q13, #1
++	add		r2, sp, #576
++	vst1.8		{d20-d21}, [r2, : 128]
++	vshl.i32	q10, q14, #1
++	add		r2, sp, #592
++	vst1.8		{d12-d13}, [r2, : 128]
++	vshl.i32	q15, q12, #1
++	vadd.i32	q8, q8, q4
++	vext.32		d10, d31, d30, #0
++	vadd.i32	q7, q7, q1
++	add		r2, sp, #608
++	vst1.8		{d16-d17}, [r2, : 128]
++	vmull.s32	q8, d18, d5
++	vmlal.s32	q8, d26, d4
++	vmlal.s32	q8, d19, d9
++	vmlal.s32	q8, d27, d3
++	vmlal.s32	q8, d22, d8
++	vmlal.s32	q8, d28, d2
++	vmlal.s32	q8, d23, d7
++	vmlal.s32	q8, d29, d1
++	vmlal.s32	q8, d24, d6
++	vmlal.s32	q8, d25, d0
++	add		r2, sp, #624
++	vst1.8		{d14-d15}, [r2, : 128]
++	vmull.s32	q2, d18, d4
++	vmlal.s32	q2, d12, d9
++	vmlal.s32	q2, d13, d8
++	vmlal.s32	q2, d19, d3
++	vmlal.s32	q2, d22, d2
++	vmlal.s32	q2, d23, d1
++	vmlal.s32	q2, d24, d0
++	add		r2, sp, #640
++	vst1.8		{d20-d21}, [r2, : 128]
++	vmull.s32	q7, d18, d9
++	vmlal.s32	q7, d26, d3
++	vmlal.s32	q7, d19, d8
++	vmlal.s32	q7, d27, d2
++	vmlal.s32	q7, d22, d7
++	vmlal.s32	q7, d28, d1
++	vmlal.s32	q7, d23, d6
++	vmlal.s32	q7, d29, d0
++	add		r2, sp, #656
++	vst1.8		{d10-d11}, [r2, : 128]
++	vmull.s32	q5, d18, d3
++	vmlal.s32	q5, d19, d2
++	vmlal.s32	q5, d22, d1
++	vmlal.s32	q5, d23, d0
++	vmlal.s32	q5, d12, d8
++	add		r2, sp, #672
++	vst1.8		{d16-d17}, [r2, : 128]
++	vmull.s32	q4, d18, d8
++	vmlal.s32	q4, d26, d2
++	vmlal.s32	q4, d19, d7
++	vmlal.s32	q4, d27, d1
++	vmlal.s32	q4, d22, d6
++	vmlal.s32	q4, d28, d0
++	vmull.s32	q8, d18, d7
++	vmlal.s32	q8, d26, d1
++	vmlal.s32	q8, d19, d6
++	vmlal.s32	q8, d27, d0
++	add		r2, sp, #576
++	vld1.8		{d20-d21}, [r2, : 128]
++	vmlal.s32	q7, d24, d21
++	vmlal.s32	q7, d25, d20
++	vmlal.s32	q4, d23, d21
++	vmlal.s32	q4, d29, d20
++	vmlal.s32	q8, d22, d21
++	vmlal.s32	q8, d28, d20
++	vmlal.s32	q5, d24, d20
++	add		r2, sp, #576
++	vst1.8		{d14-d15}, [r2, : 128]
++	vmull.s32	q7, d18, d6
++	vmlal.s32	q7, d26, d0
++	add		r2, sp, #656
++	vld1.8		{d30-d31}, [r2, : 128]
++	vmlal.s32	q2, d30, d21
++	vmlal.s32	q7, d19, d21
++	vmlal.s32	q7, d27, d20
++	add		r2, sp, #624
++	vld1.8		{d26-d27}, [r2, : 128]
++	vmlal.s32	q4, d25, d27
++	vmlal.s32	q8, d29, d27
++	vmlal.s32	q8, d25, d26
++	vmlal.s32	q7, d28, d27
++	vmlal.s32	q7, d29, d26
++	add		r2, sp, #608
++	vld1.8		{d28-d29}, [r2, : 128]
++	vmlal.s32	q4, d24, d29
++	vmlal.s32	q8, d23, d29
++	vmlal.s32	q8, d24, d28
++	vmlal.s32	q7, d22, d29
++	vmlal.s32	q7, d23, d28
++	add		r2, sp, #608
++	vst1.8		{d8-d9}, [r2, : 128]
++	add		r2, sp, #560
++	vld1.8		{d8-d9}, [r2, : 128]
++	vmlal.s32	q7, d24, d9
++	vmlal.s32	q7, d25, d31
++	vmull.s32	q1, d18, d2
++	vmlal.s32	q1, d19, d1
++	vmlal.s32	q1, d22, d0
++	vmlal.s32	q1, d24, d27
++	vmlal.s32	q1, d23, d20
++	vmlal.s32	q1, d12, d7
++	vmlal.s32	q1, d13, d6
++	vmull.s32	q6, d18, d1
++	vmlal.s32	q6, d19, d0
++	vmlal.s32	q6, d23, d27
++	vmlal.s32	q6, d22, d20
++	vmlal.s32	q6, d24, d26
++	vmull.s32	q0, d18, d0
++	vmlal.s32	q0, d22, d27
++	vmlal.s32	q0, d23, d26
++	vmlal.s32	q0, d24, d31
++	vmlal.s32	q0, d19, d20
++	add		r2, sp, #640
++	vld1.8		{d18-d19}, [r2, : 128]
++	vmlal.s32	q2, d18, d7
++	vmlal.s32	q2, d19, d6
++	vmlal.s32	q5, d18, d6
++	vmlal.s32	q5, d19, d21
++	vmlal.s32	q1, d18, d21
++	vmlal.s32	q1, d19, d29
++	vmlal.s32	q0, d18, d28
++	vmlal.s32	q0, d19, d9
++	vmlal.s32	q6, d18, d29
++	vmlal.s32	q6, d19, d28
++	add		r2, sp, #592
++	vld1.8		{d18-d19}, [r2, : 128]
++	add		r2, sp, #512
++	vld1.8		{d22-d23}, [r2, : 128]
++	vmlal.s32	q5, d19, d7
++	vmlal.s32	q0, d18, d21
++	vmlal.s32	q0, d19, d29
++	vmlal.s32	q6, d18, d6
++	add		r2, sp, #528
++	vld1.8		{d6-d7}, [r2, : 128]
++	vmlal.s32	q6, d19, d21
++	add		r2, sp, #576
++	vld1.8		{d18-d19}, [r2, : 128]
++	vmlal.s32	q0, d30, d8
++	add		r2, sp, #672
++	vld1.8		{d20-d21}, [r2, : 128]
++	vmlal.s32	q5, d30, d29
++	add		r2, sp, #608
++	vld1.8		{d24-d25}, [r2, : 128]
++	vmlal.s32	q1, d30, d28
++	vadd.i64	q13, q0, q11
++	vadd.i64	q14, q5, q11
++	vmlal.s32	q6, d30, d9
++	vshr.s64	q4, q13, #26
++	vshr.s64	q13, q14, #26
++	vadd.i64	q7, q7, q4
++	vshl.i64	q4, q4, #26
++	vadd.i64	q14, q7, q3
++	vadd.i64	q9, q9, q13
++	vshl.i64	q13, q13, #26
++	vadd.i64	q15, q9, q3
++	vsub.i64	q0, q0, q4
++	vshr.s64	q4, q14, #25
++	vsub.i64	q5, q5, q13
++	vshr.s64	q13, q15, #25
++	vadd.i64	q6, q6, q4
++	vshl.i64	q4, q4, #25
++	vadd.i64	q14, q6, q11
++	vadd.i64	q2, q2, q13
++	vsub.i64	q4, q7, q4
++	vshr.s64	q7, q14, #26
++	vshl.i64	q13, q13, #25
++	vadd.i64	q14, q2, q11
++	vadd.i64	q8, q8, q7
++	vshl.i64	q7, q7, #26
++	vadd.i64	q15, q8, q3
++	vsub.i64	q9, q9, q13
++	vshr.s64	q13, q14, #26
++	vsub.i64	q6, q6, q7
++	vshr.s64	q7, q15, #25
++	vadd.i64	q10, q10, q13
++	vshl.i64	q13, q13, #26
++	vadd.i64	q14, q10, q3
++	vadd.i64	q1, q1, q7
++	add		r2, r3, #288
++	vshl.i64	q7, q7, #25
++	add		r4, r3, #96
++	vadd.i64	q15, q1, q11
++	add		r2, r2, #8
++	vsub.i64	q2, q2, q13
++	add		r4, r4, #8
++	vshr.s64	q13, q14, #25
++	vsub.i64	q7, q8, q7
++	vshr.s64	q8, q15, #26
++	vadd.i64	q14, q13, q13
++	vadd.i64	q12, q12, q8
++	vtrn.32		d12, d14
++	vshl.i64	q8, q8, #26
++	vtrn.32		d13, d15
++	vadd.i64	q3, q12, q3
++	vadd.i64	q0, q0, q14
++	vst1.8		d12, [r2, : 64]!
++	vshl.i64	q7, q13, #4
++	vst1.8		d13, [r4, : 64]!
++	vsub.i64	q1, q1, q8
++	vshr.s64	q3, q3, #25
++	vadd.i64	q0, q0, q7
++	vadd.i64	q5, q5, q3
++	vshl.i64	q3, q3, #25
++	vadd.i64	q6, q5, q11
++	vadd.i64	q0, q0, q13
++	vshl.i64	q7, q13, #25
++	vadd.i64	q8, q0, q11
++	vsub.i64	q3, q12, q3
++	vshr.s64	q6, q6, #26
++	vsub.i64	q7, q10, q7
++	vtrn.32		d2, d6
++	vshr.s64	q8, q8, #26
++	vtrn.32		d3, d7
++	vadd.i64	q3, q9, q6
++	vst1.8		d2, [r2, : 64]
++	vshl.i64	q6, q6, #26
++	vst1.8		d3, [r4, : 64]
++	vadd.i64	q1, q4, q8
++	vtrn.32		d4, d14
++	vshl.i64	q4, q8, #26
++	vtrn.32		d5, d15
++	vsub.i64	q5, q5, q6
++	add		r2, r2, #16
++	vsub.i64	q0, q0, q4
++	vst1.8		d4, [r2, : 64]
++	add		r4, r4, #16
++	vst1.8		d5, [r4, : 64]
++	vtrn.32		d10, d6
++	vtrn.32		d11, d7
++	sub		r2, r2, #8
++	sub		r4, r4, #8
++	vtrn.32		d0, d2
++	vtrn.32		d1, d3
++	vst1.8		d10, [r2, : 64]
++	vst1.8		d11, [r4, : 64]
++	sub		r2, r2, #24
++	sub		r4, r4, #24
++	vst1.8		d0, [r2, : 64]
++	vst1.8		d1, [r4, : 64]
++	add		r2, sp, #544
++	add		r4, r3, #144
++	add		r5, r3, #192
++	vld1.8		{d0-d1}, [r2, : 128]
++	vld1.8		{d2-d3}, [r4, : 128]!
++	vld1.8		{d4-d5}, [r5, : 128]!
++	vzip.i32	q1, q2
++	vld1.8		{d6-d7}, [r4, : 128]!
++	vld1.8		{d8-d9}, [r5, : 128]!
++	vshl.i32	q5, q1, #1
++	vzip.i32	q3, q4
++	vshl.i32	q6, q2, #1
++	vld1.8		{d14}, [r4, : 64]
++	vshl.i32	q8, q3, #1
++	vld1.8		{d15}, [r5, : 64]
++	vshl.i32	q9, q4, #1
++	vmul.i32	d21, d7, d1
++	vtrn.32		d14, d15
++	vmul.i32	q11, q4, q0
++	vmul.i32	q0, q7, q0
++	vmull.s32	q12, d2, d2
++	vmlal.s32	q12, d11, d1
++	vmlal.s32	q12, d12, d0
++	vmlal.s32	q12, d13, d23
++	vmlal.s32	q12, d16, d22
++	vmlal.s32	q12, d7, d21
++	vmull.s32	q10, d2, d11
++	vmlal.s32	q10, d4, d1
++	vmlal.s32	q10, d13, d0
++	vmlal.s32	q10, d6, d23
++	vmlal.s32	q10, d17, d22
++	vmull.s32	q13, d10, d4
++	vmlal.s32	q13, d11, d3
++	vmlal.s32	q13, d13, d1
++	vmlal.s32	q13, d16, d0
++	vmlal.s32	q13, d17, d23
++	vmlal.s32	q13, d8, d22
++	vmull.s32	q1, d10, d5
++	vmlal.s32	q1, d11, d4
++	vmlal.s32	q1, d6, d1
++	vmlal.s32	q1, d17, d0
++	vmlal.s32	q1, d8, d23
++	vmull.s32	q14, d10, d6
++	vmlal.s32	q14, d11, d13
++	vmlal.s32	q14, d4, d4
++	vmlal.s32	q14, d17, d1
++	vmlal.s32	q14, d18, d0
++	vmlal.s32	q14, d9, d23
++	vmull.s32	q11, d10, d7
++	vmlal.s32	q11, d11, d6
++	vmlal.s32	q11, d12, d5
++	vmlal.s32	q11, d8, d1
++	vmlal.s32	q11, d19, d0
++	vmull.s32	q15, d10, d8
++	vmlal.s32	q15, d11, d17
++	vmlal.s32	q15, d12, d6
++	vmlal.s32	q15, d13, d5
++	vmlal.s32	q15, d19, d1
++	vmlal.s32	q15, d14, d0
++	vmull.s32	q2, d10, d9
++	vmlal.s32	q2, d11, d8
++	vmlal.s32	q2, d12, d7
++	vmlal.s32	q2, d13, d6
++	vmlal.s32	q2, d14, d1
++	vmull.s32	q0, d15, d1
++	vmlal.s32	q0, d10, d14
++	vmlal.s32	q0, d11, d19
++	vmlal.s32	q0, d12, d8
++	vmlal.s32	q0, d13, d17
++	vmlal.s32	q0, d6, d6
++	add		r2, sp, #512
++	vld1.8		{d18-d19}, [r2, : 128]
++	vmull.s32	q3, d16, d7
++	vmlal.s32	q3, d10, d15
++	vmlal.s32	q3, d11, d14
++	vmlal.s32	q3, d12, d9
++	vmlal.s32	q3, d13, d8
++	add		r2, sp, #528
++	vld1.8		{d8-d9}, [r2, : 128]
++	vadd.i64	q5, q12, q9
++	vadd.i64	q6, q15, q9
++	vshr.s64	q5, q5, #26
++	vshr.s64	q6, q6, #26
++	vadd.i64	q7, q10, q5
++	vshl.i64	q5, q5, #26
++	vadd.i64	q8, q7, q4
++	vadd.i64	q2, q2, q6
++	vshl.i64	q6, q6, #26
++	vadd.i64	q10, q2, q4
++	vsub.i64	q5, q12, q5
++	vshr.s64	q8, q8, #25
++	vsub.i64	q6, q15, q6
++	vshr.s64	q10, q10, #25
++	vadd.i64	q12, q13, q8
++	vshl.i64	q8, q8, #25
++	vadd.i64	q13, q12, q9
++	vadd.i64	q0, q0, q10
++	vsub.i64	q7, q7, q8
++	vshr.s64	q8, q13, #26
++	vshl.i64	q10, q10, #25
++	vadd.i64	q13, q0, q9
++	vadd.i64	q1, q1, q8
++	vshl.i64	q8, q8, #26
++	vadd.i64	q15, q1, q4
++	vsub.i64	q2, q2, q10
++	vshr.s64	q10, q13, #26
++	vsub.i64	q8, q12, q8
++	vshr.s64	q12, q15, #25
++	vadd.i64	q3, q3, q10
++	vshl.i64	q10, q10, #26
++	vadd.i64	q13, q3, q4
++	vadd.i64	q14, q14, q12
++	add		r2, r3, #144
++	vshl.i64	q12, q12, #25
++	add		r4, r3, #192
++	vadd.i64	q15, q14, q9
++	add		r2, r2, #8
++	vsub.i64	q0, q0, q10
++	add		r4, r4, #8
++	vshr.s64	q10, q13, #25
++	vsub.i64	q1, q1, q12
++	vshr.s64	q12, q15, #26
++	vadd.i64	q13, q10, q10
++	vadd.i64	q11, q11, q12
++	vtrn.32		d16, d2
++	vshl.i64	q12, q12, #26
++	vtrn.32		d17, d3
++	vadd.i64	q1, q11, q4
++	vadd.i64	q4, q5, q13
++	vst1.8		d16, [r2, : 64]!
++	vshl.i64	q5, q10, #4
++	vst1.8		d17, [r4, : 64]!
++	vsub.i64	q8, q14, q12
++	vshr.s64	q1, q1, #25
++	vadd.i64	q4, q4, q5
++	vadd.i64	q5, q6, q1
++	vshl.i64	q1, q1, #25
++	vadd.i64	q6, q5, q9
++	vadd.i64	q4, q4, q10
++	vshl.i64	q10, q10, #25
++	vadd.i64	q9, q4, q9
++	vsub.i64	q1, q11, q1
++	vshr.s64	q6, q6, #26
++	vsub.i64	q3, q3, q10
++	vtrn.32		d16, d2
++	vshr.s64	q9, q9, #26
++	vtrn.32		d17, d3
++	vadd.i64	q1, q2, q6
++	vst1.8		d16, [r2, : 64]
++	vshl.i64	q2, q6, #26
++	vst1.8		d17, [r4, : 64]
++	vadd.i64	q6, q7, q9
++	vtrn.32		d0, d6
++	vshl.i64	q7, q9, #26
++	vtrn.32		d1, d7
++	vsub.i64	q2, q5, q2
++	add		r2, r2, #16
++	vsub.i64	q3, q4, q7
++	vst1.8		d0, [r2, : 64]
++	add		r4, r4, #16
++	vst1.8		d1, [r4, : 64]
++	vtrn.32		d4, d2
++	vtrn.32		d5, d3
++	sub		r2, r2, #8
++	sub		r4, r4, #8
++	vtrn.32		d6, d12
++	vtrn.32		d7, d13
++	vst1.8		d4, [r2, : 64]
++	vst1.8		d5, [r4, : 64]
++	sub		r2, r2, #24
++	sub		r4, r4, #24
++	vst1.8		d6, [r2, : 64]
++	vst1.8		d7, [r4, : 64]
++	add		r2, r3, #336
++	add		r4, r3, #288
++	vld1.8		{d0-d1}, [r2, : 128]!
++	vld1.8		{d2-d3}, [r4, : 128]!
++	vadd.i32	q0, q0, q1
++	vld1.8		{d2-d3}, [r2, : 128]!
++	vld1.8		{d4-d5}, [r4, : 128]!
++	vadd.i32	q1, q1, q2
++	add		r5, r3, #288
++	vld1.8		{d4}, [r2, : 64]
++	vld1.8		{d6}, [r4, : 64]
++	vadd.i32	q2, q2, q3
++	vst1.8		{d0-d1}, [r5, : 128]!
++	vst1.8		{d2-d3}, [r5, : 128]!
++	vst1.8		d4, [r5, : 64]
++	add		r2, r3, #48
++	add		r4, r3, #144
++	vld1.8		{d0-d1}, [r4, : 128]!
++	vld1.8		{d2-d3}, [r4, : 128]!
++	vld1.8		{d4}, [r4, : 64]
++	add		r4, r3, #288
++	vld1.8		{d6-d7}, [r4, : 128]!
++	vtrn.32		q0, q3
++	vld1.8		{d8-d9}, [r4, : 128]!
++	vshl.i32	q5, q0, #4
++	vtrn.32		q1, q4
++	vshl.i32	q6, q3, #4
++	vadd.i32	q5, q5, q0
++	vadd.i32	q6, q6, q3
++	vshl.i32	q7, q1, #4
++	vld1.8		{d5}, [r4, : 64]
++	vshl.i32	q8, q4, #4
++	vtrn.32		d4, d5
++	vadd.i32	q7, q7, q1
++	vadd.i32	q8, q8, q4
++	vld1.8		{d18-d19}, [r2, : 128]!
++	vshl.i32	q10, q2, #4
++	vld1.8		{d22-d23}, [r2, : 128]!
++	vadd.i32	q10, q10, q2
++	vld1.8		{d24}, [r2, : 64]
++	vadd.i32	q5, q5, q0
++	add		r2, r3, #240
++	vld1.8		{d26-d27}, [r2, : 128]!
++	vadd.i32	q6, q6, q3
++	vld1.8		{d28-d29}, [r2, : 128]!
++	vadd.i32	q8, q8, q4
++	vld1.8		{d25}, [r2, : 64]
++	vadd.i32	q10, q10, q2
++	vtrn.32		q9, q13
++	vadd.i32	q7, q7, q1
++	vadd.i32	q5, q5, q0
++	vtrn.32		q11, q14
++	vadd.i32	q6, q6, q3
++	add		r2, sp, #560
++	vadd.i32	q10, q10, q2
++	vtrn.32		d24, d25
++	vst1.8		{d12-d13}, [r2, : 128]
++	vshl.i32	q6, q13, #1
++	add		r2, sp, #576
++	vst1.8		{d20-d21}, [r2, : 128]
++	vshl.i32	q10, q14, #1
++	add		r2, sp, #592
++	vst1.8		{d12-d13}, [r2, : 128]
++	vshl.i32	q15, q12, #1
++	vadd.i32	q8, q8, q4
++	vext.32		d10, d31, d30, #0
++	vadd.i32	q7, q7, q1
++	add		r2, sp, #608
++	vst1.8		{d16-d17}, [r2, : 128]
++	vmull.s32	q8, d18, d5
++	vmlal.s32	q8, d26, d4
++	vmlal.s32	q8, d19, d9
++	vmlal.s32	q8, d27, d3
++	vmlal.s32	q8, d22, d8
++	vmlal.s32	q8, d28, d2
++	vmlal.s32	q8, d23, d7
++	vmlal.s32	q8, d29, d1
++	vmlal.s32	q8, d24, d6
++	vmlal.s32	q8, d25, d0
++	add		r2, sp, #624
++	vst1.8		{d14-d15}, [r2, : 128]
++	vmull.s32	q2, d18, d4
++	vmlal.s32	q2, d12, d9
++	vmlal.s32	q2, d13, d8
++	vmlal.s32	q2, d19, d3
++	vmlal.s32	q2, d22, d2
++	vmlal.s32	q2, d23, d1
++	vmlal.s32	q2, d24, d0
++	add		r2, sp, #640
++	vst1.8		{d20-d21}, [r2, : 128]
++	vmull.s32	q7, d18, d9
++	vmlal.s32	q7, d26, d3
++	vmlal.s32	q7, d19, d8
++	vmlal.s32	q7, d27, d2
++	vmlal.s32	q7, d22, d7
++	vmlal.s32	q7, d28, d1
++	vmlal.s32	q7, d23, d6
++	vmlal.s32	q7, d29, d0
++	add		r2, sp, #656
++	vst1.8		{d10-d11}, [r2, : 128]
++	vmull.s32	q5, d18, d3
++	vmlal.s32	q5, d19, d2
++	vmlal.s32	q5, d22, d1
++	vmlal.s32	q5, d23, d0
++	vmlal.s32	q5, d12, d8
++	add		r2, sp, #672
++	vst1.8		{d16-d17}, [r2, : 128]
++	vmull.s32	q4, d18, d8
++	vmlal.s32	q4, d26, d2
++	vmlal.s32	q4, d19, d7
++	vmlal.s32	q4, d27, d1
++	vmlal.s32	q4, d22, d6
++	vmlal.s32	q4, d28, d0
++	vmull.s32	q8, d18, d7
++	vmlal.s32	q8, d26, d1
++	vmlal.s32	q8, d19, d6
++	vmlal.s32	q8, d27, d0
++	add		r2, sp, #576
++	vld1.8		{d20-d21}, [r2, : 128]
++	vmlal.s32	q7, d24, d21
++	vmlal.s32	q7, d25, d20
++	vmlal.s32	q4, d23, d21
++	vmlal.s32	q4, d29, d20
++	vmlal.s32	q8, d22, d21
++	vmlal.s32	q8, d28, d20
++	vmlal.s32	q5, d24, d20
++	add		r2, sp, #576
++	vst1.8		{d14-d15}, [r2, : 128]
++	vmull.s32	q7, d18, d6
++	vmlal.s32	q7, d26, d0
++	add		r2, sp, #656
++	vld1.8		{d30-d31}, [r2, : 128]
++	vmlal.s32	q2, d30, d21
++	vmlal.s32	q7, d19, d21
++	vmlal.s32	q7, d27, d20
++	add		r2, sp, #624
++	vld1.8		{d26-d27}, [r2, : 128]
++	vmlal.s32	q4, d25, d27
++	vmlal.s32	q8, d29, d27
++	vmlal.s32	q8, d25, d26
++	vmlal.s32	q7, d28, d27
++	vmlal.s32	q7, d29, d26
++	add		r2, sp, #608
++	vld1.8		{d28-d29}, [r2, : 128]
++	vmlal.s32	q4, d24, d29
++	vmlal.s32	q8, d23, d29
++	vmlal.s32	q8, d24, d28
++	vmlal.s32	q7, d22, d29
++	vmlal.s32	q7, d23, d28
++	add		r2, sp, #608
++	vst1.8		{d8-d9}, [r2, : 128]
++	add		r2, sp, #560
++	vld1.8		{d8-d9}, [r2, : 128]
++	vmlal.s32	q7, d24, d9
++	vmlal.s32	q7, d25, d31
++	vmull.s32	q1, d18, d2
++	vmlal.s32	q1, d19, d1
++	vmlal.s32	q1, d22, d0
++	vmlal.s32	q1, d24, d27
++	vmlal.s32	q1, d23, d20
++	vmlal.s32	q1, d12, d7
++	vmlal.s32	q1, d13, d6
++	vmull.s32	q6, d18, d1
++	vmlal.s32	q6, d19, d0
++	vmlal.s32	q6, d23, d27
++	vmlal.s32	q6, d22, d20
++	vmlal.s32	q6, d24, d26
++	vmull.s32	q0, d18, d0
++	vmlal.s32	q0, d22, d27
++	vmlal.s32	q0, d23, d26
++	vmlal.s32	q0, d24, d31
++	vmlal.s32	q0, d19, d20
++	add		r2, sp, #640
++	vld1.8		{d18-d19}, [r2, : 128]
++	vmlal.s32	q2, d18, d7
++	vmlal.s32	q2, d19, d6
++	vmlal.s32	q5, d18, d6
++	vmlal.s32	q5, d19, d21
++	vmlal.s32	q1, d18, d21
++	vmlal.s32	q1, d19, d29
++	vmlal.s32	q0, d18, d28
++	vmlal.s32	q0, d19, d9
++	vmlal.s32	q6, d18, d29
++	vmlal.s32	q6, d19, d28
++	add		r2, sp, #592
++	vld1.8		{d18-d19}, [r2, : 128]
++	add		r2, sp, #512
++	vld1.8		{d22-d23}, [r2, : 128]
++	vmlal.s32	q5, d19, d7
++	vmlal.s32	q0, d18, d21
++	vmlal.s32	q0, d19, d29
++	vmlal.s32	q6, d18, d6
++	add		r2, sp, #528
++	vld1.8		{d6-d7}, [r2, : 128]
++	vmlal.s32	q6, d19, d21
++	add		r2, sp, #576
++	vld1.8		{d18-d19}, [r2, : 128]
++	vmlal.s32	q0, d30, d8
++	add		r2, sp, #672
++	vld1.8		{d20-d21}, [r2, : 128]
++	vmlal.s32	q5, d30, d29
++	add		r2, sp, #608
++	vld1.8		{d24-d25}, [r2, : 128]
++	vmlal.s32	q1, d30, d28
++	vadd.i64	q13, q0, q11
++	vadd.i64	q14, q5, q11
++	vmlal.s32	q6, d30, d9
++	vshr.s64	q4, q13, #26
++	vshr.s64	q13, q14, #26
++	vadd.i64	q7, q7, q4
++	vshl.i64	q4, q4, #26
++	vadd.i64	q14, q7, q3
++	vadd.i64	q9, q9, q13
++	vshl.i64	q13, q13, #26
++	vadd.i64	q15, q9, q3
++	vsub.i64	q0, q0, q4
++	vshr.s64	q4, q14, #25
++	vsub.i64	q5, q5, q13
++	vshr.s64	q13, q15, #25
++	vadd.i64	q6, q6, q4
++	vshl.i64	q4, q4, #25
++	vadd.i64	q14, q6, q11
++	vadd.i64	q2, q2, q13
++	vsub.i64	q4, q7, q4
++	vshr.s64	q7, q14, #26
++	vshl.i64	q13, q13, #25
++	vadd.i64	q14, q2, q11
++	vadd.i64	q8, q8, q7
++	vshl.i64	q7, q7, #26
++	vadd.i64	q15, q8, q3
++	vsub.i64	q9, q9, q13
++	vshr.s64	q13, q14, #26
++	vsub.i64	q6, q6, q7
++	vshr.s64	q7, q15, #25
++	vadd.i64	q10, q10, q13
++	vshl.i64	q13, q13, #26
++	vadd.i64	q14, q10, q3
++	vadd.i64	q1, q1, q7
++	add		r2, r3, #240
++	vshl.i64	q7, q7, #25
++	add		r4, r3, #144
++	vadd.i64	q15, q1, q11
++	add		r2, r2, #8
++	vsub.i64	q2, q2, q13
++	add		r4, r4, #8
++	vshr.s64	q13, q14, #25
++	vsub.i64	q7, q8, q7
++	vshr.s64	q8, q15, #26
++	vadd.i64	q14, q13, q13
++	vadd.i64	q12, q12, q8
++	vtrn.32		d12, d14
++	vshl.i64	q8, q8, #26
++	vtrn.32		d13, d15
++	vadd.i64	q3, q12, q3
++	vadd.i64	q0, q0, q14
++	vst1.8		d12, [r2, : 64]!
++	vshl.i64	q7, q13, #4
++	vst1.8		d13, [r4, : 64]!
++	vsub.i64	q1, q1, q8
++	vshr.s64	q3, q3, #25
++	vadd.i64	q0, q0, q7
++	vadd.i64	q5, q5, q3
++	vshl.i64	q3, q3, #25
++	vadd.i64	q6, q5, q11
++	vadd.i64	q0, q0, q13
++	vshl.i64	q7, q13, #25
++	vadd.i64	q8, q0, q11
++	vsub.i64	q3, q12, q3
++	vshr.s64	q6, q6, #26
++	vsub.i64	q7, q10, q7
++	vtrn.32		d2, d6
++	vshr.s64	q8, q8, #26
++	vtrn.32		d3, d7
++	vadd.i64	q3, q9, q6
++	vst1.8		d2, [r2, : 64]
++	vshl.i64	q6, q6, #26
++	vst1.8		d3, [r4, : 64]
++	vadd.i64	q1, q4, q8
++	vtrn.32		d4, d14
++	vshl.i64	q4, q8, #26
++	vtrn.32		d5, d15
++	vsub.i64	q5, q5, q6
++	add		r2, r2, #16
++	vsub.i64	q0, q0, q4
++	vst1.8		d4, [r2, : 64]
++	add		r4, r4, #16
++	vst1.8		d5, [r4, : 64]
++	vtrn.32		d10, d6
++	vtrn.32		d11, d7
++	sub		r2, r2, #8
++	sub		r4, r4, #8
++	vtrn.32		d0, d2
++	vtrn.32		d1, d3
++	vst1.8		d10, [r2, : 64]
++	vst1.8		d11, [r4, : 64]
++	sub		r2, r2, #24
++	sub		r4, r4, #24
++	vst1.8		d0, [r2, : 64]
++	vst1.8		d1, [r4, : 64]
++	ldr		r2, [sp, #488]
++	ldr		r4, [sp, #492]
++	subs		r5, r2, #1
++	bge		._mainloop
++	add		r1, r3, #144
++	add		r2, r3, #336
++	vld1.8		{d0-d1}, [r1, : 128]!
++	vld1.8		{d2-d3}, [r1, : 128]!
++	vld1.8		{d4}, [r1, : 64]
++	vst1.8		{d0-d1}, [r2, : 128]!
++	vst1.8		{d2-d3}, [r2, : 128]!
++	vst1.8		d4, [r2, : 64]
++	ldr		r1, =0
++._invertloop:
++	add		r2, r3, #144
++	ldr		r4, =0
++	ldr		r5, =2
++	cmp		r1, #1
++	ldreq		r5, =1
++	addeq		r2, r3, #336
++	addeq		r4, r3, #48
++	cmp		r1, #2
++	ldreq		r5, =1
++	addeq		r2, r3, #48
++	cmp		r1, #3
++	ldreq		r5, =5
++	addeq		r4, r3, #336
++	cmp		r1, #4
++	ldreq		r5, =10
++	cmp		r1, #5
++	ldreq		r5, =20
++	cmp		r1, #6
++	ldreq		r5, =10
++	addeq		r2, r3, #336
++	addeq		r4, r3, #336
++	cmp		r1, #7
++	ldreq		r5, =50
++	cmp		r1, #8
++	ldreq		r5, =100
++	cmp		r1, #9
++	ldreq		r5, =50
++	addeq		r2, r3, #336
++	cmp		r1, #10
++	ldreq		r5, =5
++	addeq		r2, r3, #48
++	cmp		r1, #11
++	ldreq		r5, =0
++	addeq		r2, r3, #96
++	add		r6, r3, #144
++	add		r7, r3, #288
++	vld1.8		{d0-d1}, [r6, : 128]!
++	vld1.8		{d2-d3}, [r6, : 128]!
++	vld1.8		{d4}, [r6, : 64]
++	vst1.8		{d0-d1}, [r7, : 128]!
++	vst1.8		{d2-d3}, [r7, : 128]!
++	vst1.8		d4, [r7, : 64]
++	cmp		r5, #0
++	beq		._skipsquaringloop
++._squaringloop:
++	add		r6, r3, #288
++	add		r7, r3, #288
++	add		r8, r3, #288
++	vmov.i32	q0, #19
++	vmov.i32	q1, #0
++	vmov.i32	q2, #1
++	vzip.i32	q1, q2
++	vld1.8		{d4-d5}, [r7, : 128]!
++	vld1.8		{d6-d7}, [r7, : 128]!
++	vld1.8		{d9}, [r7, : 64]
++	vld1.8		{d10-d11}, [r6, : 128]!
++	add		r7, sp, #416
++	vld1.8		{d12-d13}, [r6, : 128]!
++	vmul.i32	q7, q2, q0
++	vld1.8		{d8}, [r6, : 64]
++	vext.32		d17, d11, d10, #1
++	vmul.i32	q9, q3, q0
++	vext.32		d16, d10, d8, #1
++	vshl.u32	q10, q5, q1
++	vext.32		d22, d14, d4, #1
++	vext.32		d24, d18, d6, #1
++	vshl.u32	q13, q6, q1
++	vshl.u32	d28, d8, d2
++	vrev64.i32	d22, d22
++	vmul.i32	d1, d9, d1
++	vrev64.i32	d24, d24
++	vext.32		d29, d8, d13, #1
++	vext.32		d0, d1, d9, #1
++	vrev64.i32	d0, d0
++	vext.32		d2, d9, d1, #1
++	vext.32		d23, d15, d5, #1
++	vmull.s32	q4, d20, d4
++	vrev64.i32	d23, d23
++	vmlal.s32	q4, d21, d1
++	vrev64.i32	d2, d2
++	vmlal.s32	q4, d26, d19
++	vext.32		d3, d5, d15, #1
++	vmlal.s32	q4, d27, d18
++	vrev64.i32	d3, d3
++	vmlal.s32	q4, d28, d15
++	vext.32		d14, d12, d11, #1
++	vmull.s32	q5, d16, d23
++	vext.32		d15, d13, d12, #1
++	vmlal.s32	q5, d17, d4
++	vst1.8		d8, [r7, : 64]!
++	vmlal.s32	q5, d14, d1
++	vext.32		d12, d9, d8, #0
++	vmlal.s32	q5, d15, d19
++	vmov.i64	d13, #0
++	vmlal.s32	q5, d29, d18
++	vext.32		d25, d19, d7, #1
++	vmlal.s32	q6, d20, d5
++	vrev64.i32	d25, d25
++	vmlal.s32	q6, d21, d4
++	vst1.8		d11, [r7, : 64]!
++	vmlal.s32	q6, d26, d1
++	vext.32		d9, d10, d10, #0
++	vmlal.s32	q6, d27, d19
++	vmov.i64	d8, #0
++	vmlal.s32	q6, d28, d18
++	vmlal.s32	q4, d16, d24
++	vmlal.s32	q4, d17, d5
++	vmlal.s32	q4, d14, d4
++	vst1.8		d12, [r7, : 64]!
++	vmlal.s32	q4, d15, d1
++	vext.32		d10, d13, d12, #0
++	vmlal.s32	q4, d29, d19
++	vmov.i64	d11, #0
++	vmlal.s32	q5, d20, d6
++	vmlal.s32	q5, d21, d5
++	vmlal.s32	q5, d26, d4
++	vext.32		d13, d8, d8, #0
++	vmlal.s32	q5, d27, d1
++	vmov.i64	d12, #0
++	vmlal.s32	q5, d28, d19
++	vst1.8		d9, [r7, : 64]!
++	vmlal.s32	q6, d16, d25
++	vmlal.s32	q6, d17, d6
++	vst1.8		d10, [r7, : 64]
++	vmlal.s32	q6, d14, d5
++	vext.32		d8, d11, d10, #0
++	vmlal.s32	q6, d15, d4
++	vmov.i64	d9, #0
++	vmlal.s32	q6, d29, d1
++	vmlal.s32	q4, d20, d7
++	vmlal.s32	q4, d21, d6
++	vmlal.s32	q4, d26, d5
++	vext.32		d11, d12, d12, #0
++	vmlal.s32	q4, d27, d4
++	vmov.i64	d10, #0
++	vmlal.s32	q4, d28, d1
++	vmlal.s32	q5, d16, d0
++	sub		r6, r7, #32
++	vmlal.s32	q5, d17, d7
++	vmlal.s32	q5, d14, d6
++	vext.32		d30, d9, d8, #0
++	vmlal.s32	q5, d15, d5
++	vld1.8		{d31}, [r6, : 64]!
++	vmlal.s32	q5, d29, d4
++	vmlal.s32	q15, d20, d0
++	vext.32		d0, d6, d18, #1
++	vmlal.s32	q15, d21, d25
++	vrev64.i32	d0, d0
++	vmlal.s32	q15, d26, d24
++	vext.32		d1, d7, d19, #1
++	vext.32		d7, d10, d10, #0
++	vmlal.s32	q15, d27, d23
++	vrev64.i32	d1, d1
++	vld1.8		{d6}, [r6, : 64]
++	vmlal.s32	q15, d28, d22
++	vmlal.s32	q3, d16, d4
++	add		r6, r6, #24
++	vmlal.s32	q3, d17, d2
++	vext.32		d4, d31, d30, #0
++	vmov		d17, d11
++	vmlal.s32	q3, d14, d1
++	vext.32		d11, d13, d13, #0
++	vext.32		d13, d30, d30, #0
++	vmlal.s32	q3, d15, d0
++	vext.32		d1, d8, d8, #0
++	vmlal.s32	q3, d29, d3
++	vld1.8		{d5}, [r6, : 64]
++	sub		r6, r6, #16
++	vext.32		d10, d6, d6, #0
++	vmov.i32	q1, #0xffffffff
++	vshl.i64	q4, q1, #25
++	add		r7, sp, #512
++	vld1.8		{d14-d15}, [r7, : 128]
++	vadd.i64	q9, q2, q7
++	vshl.i64	q1, q1, #26
++	vshr.s64	q10, q9, #26
++	vld1.8		{d0}, [r6, : 64]!
++	vadd.i64	q5, q5, q10
++	vand		q9, q9, q1
++	vld1.8		{d16}, [r6, : 64]!
++	add		r6, sp, #528
++	vld1.8		{d20-d21}, [r6, : 128]
++	vadd.i64	q11, q5, q10
++	vsub.i64	q2, q2, q9
++	vshr.s64	q9, q11, #25
++	vext.32		d12, d5, d4, #0
++	vand		q11, q11, q4
++	vadd.i64	q0, q0, q9
++	vmov		d19, d7
++	vadd.i64	q3, q0, q7
++	vsub.i64	q5, q5, q11
++	vshr.s64	q11, q3, #26
++	vext.32		d18, d11, d10, #0
++	vand		q3, q3, q1
++	vadd.i64	q8, q8, q11
++	vadd.i64	q11, q8, q10
++	vsub.i64	q0, q0, q3
++	vshr.s64	q3, q11, #25
++	vand		q11, q11, q4
++	vadd.i64	q3, q6, q3
++	vadd.i64	q6, q3, q7
++	vsub.i64	q8, q8, q11
++	vshr.s64	q11, q6, #26
++	vand		q6, q6, q1
++	vadd.i64	q9, q9, q11
++	vadd.i64	d25, d19, d21
++	vsub.i64	q3, q3, q6
++	vshr.s64	d23, d25, #25
++	vand		q4, q12, q4
++	vadd.i64	d21, d23, d23
++	vshl.i64	d25, d23, #4
++	vadd.i64	d21, d21, d23
++	vadd.i64	d25, d25, d21
++	vadd.i64	d4, d4, d25
++	vzip.i32	q0, q8
++	vadd.i64	d12, d4, d14
++	add		r6, r8, #8
++	vst1.8		d0, [r6, : 64]
++	vsub.i64	d19, d19, d9
++	add		r6, r6, #16
++	vst1.8		d16, [r6, : 64]
++	vshr.s64	d22, d12, #26
++	vand		q0, q6, q1
++	vadd.i64	d10, d10, d22
++	vzip.i32	q3, q9
++	vsub.i64	d4, d4, d0
++	sub		r6, r6, #8
++	vst1.8		d6, [r6, : 64]
++	add		r6, r6, #16
++	vst1.8		d18, [r6, : 64]
++	vzip.i32	q2, q5
++	sub		r6, r6, #32
++	vst1.8		d4, [r6, : 64]
++	subs		r5, r5, #1
++	bhi		._squaringloop
++._skipsquaringloop:
++	mov		r2, r2
++	add		r5, r3, #288
++	add		r6, r3, #144
++	vmov.i32	q0, #19
++	vmov.i32	q1, #0
++	vmov.i32	q2, #1
++	vzip.i32	q1, q2
++	vld1.8		{d4-d5}, [r5, : 128]!
++	vld1.8		{d6-d7}, [r5, : 128]!
++	vld1.8		{d9}, [r5, : 64]
++	vld1.8		{d10-d11}, [r2, : 128]!
++	add		r5, sp, #416
++	vld1.8		{d12-d13}, [r2, : 128]!
++	vmul.i32	q7, q2, q0
++	vld1.8		{d8}, [r2, : 64]
++	vext.32		d17, d11, d10, #1
++	vmul.i32	q9, q3, q0
++	vext.32		d16, d10, d8, #1
++	vshl.u32	q10, q5, q1
++	vext.32		d22, d14, d4, #1
++	vext.32		d24, d18, d6, #1
++	vshl.u32	q13, q6, q1
++	vshl.u32	d28, d8, d2
++	vrev64.i32	d22, d22
++	vmul.i32	d1, d9, d1
++	vrev64.i32	d24, d24
++	vext.32		d29, d8, d13, #1
++	vext.32		d0, d1, d9, #1
++	vrev64.i32	d0, d0
++	vext.32		d2, d9, d1, #1
++	vext.32		d23, d15, d5, #1
++	vmull.s32	q4, d20, d4
++	vrev64.i32	d23, d23
++	vmlal.s32	q4, d21, d1
++	vrev64.i32	d2, d2
++	vmlal.s32	q4, d26, d19
++	vext.32		d3, d5, d15, #1
++	vmlal.s32	q4, d27, d18
++	vrev64.i32	d3, d3
++	vmlal.s32	q4, d28, d15
++	vext.32		d14, d12, d11, #1
++	vmull.s32	q5, d16, d23
++	vext.32		d15, d13, d12, #1
++	vmlal.s32	q5, d17, d4
++	vst1.8		d8, [r5, : 64]!
++	vmlal.s32	q5, d14, d1
++	vext.32		d12, d9, d8, #0
++	vmlal.s32	q5, d15, d19
++	vmov.i64	d13, #0
++	vmlal.s32	q5, d29, d18
++	vext.32		d25, d19, d7, #1
++	vmlal.s32	q6, d20, d5
++	vrev64.i32	d25, d25
++	vmlal.s32	q6, d21, d4
++	vst1.8		d11, [r5, : 64]!
++	vmlal.s32	q6, d26, d1
++	vext.32		d9, d10, d10, #0
++	vmlal.s32	q6, d27, d19
++	vmov.i64	d8, #0
++	vmlal.s32	q6, d28, d18
++	vmlal.s32	q4, d16, d24
++	vmlal.s32	q4, d17, d5
++	vmlal.s32	q4, d14, d4
++	vst1.8		d12, [r5, : 64]!
++	vmlal.s32	q4, d15, d1
++	vext.32		d10, d13, d12, #0
++	vmlal.s32	q4, d29, d19
++	vmov.i64	d11, #0
++	vmlal.s32	q5, d20, d6
++	vmlal.s32	q5, d21, d5
++	vmlal.s32	q5, d26, d4
++	vext.32		d13, d8, d8, #0
++	vmlal.s32	q5, d27, d1
++	vmov.i64	d12, #0
++	vmlal.s32	q5, d28, d19
++	vst1.8		d9, [r5, : 64]!
++	vmlal.s32	q6, d16, d25
++	vmlal.s32	q6, d17, d6
++	vst1.8		d10, [r5, : 64]
++	vmlal.s32	q6, d14, d5
++	vext.32		d8, d11, d10, #0
++	vmlal.s32	q6, d15, d4
++	vmov.i64	d9, #0
++	vmlal.s32	q6, d29, d1
++	vmlal.s32	q4, d20, d7
++	vmlal.s32	q4, d21, d6
++	vmlal.s32	q4, d26, d5
++	vext.32		d11, d12, d12, #0
++	vmlal.s32	q4, d27, d4
++	vmov.i64	d10, #0
++	vmlal.s32	q4, d28, d1
++	vmlal.s32	q5, d16, d0
++	sub		r2, r5, #32
++	vmlal.s32	q5, d17, d7
++	vmlal.s32	q5, d14, d6
++	vext.32		d30, d9, d8, #0
++	vmlal.s32	q5, d15, d5
++	vld1.8		{d31}, [r2, : 64]!
++	vmlal.s32	q5, d29, d4
++	vmlal.s32	q15, d20, d0
++	vext.32		d0, d6, d18, #1
++	vmlal.s32	q15, d21, d25
++	vrev64.i32	d0, d0
++	vmlal.s32	q15, d26, d24
++	vext.32		d1, d7, d19, #1
++	vext.32		d7, d10, d10, #0
++	vmlal.s32	q15, d27, d23
++	vrev64.i32	d1, d1
++	vld1.8		{d6}, [r2, : 64]
++	vmlal.s32	q15, d28, d22
++	vmlal.s32	q3, d16, d4
++	add		r2, r2, #24
++	vmlal.s32	q3, d17, d2
++	vext.32		d4, d31, d30, #0
++	vmov		d17, d11
++	vmlal.s32	q3, d14, d1
++	vext.32		d11, d13, d13, #0
++	vext.32		d13, d30, d30, #0
++	vmlal.s32	q3, d15, d0
++	vext.32		d1, d8, d8, #0
++	vmlal.s32	q3, d29, d3
++	vld1.8		{d5}, [r2, : 64]
++	sub		r2, r2, #16
++	vext.32		d10, d6, d6, #0
++	vmov.i32	q1, #0xffffffff
++	vshl.i64	q4, q1, #25
++	add		r5, sp, #512
++	vld1.8		{d14-d15}, [r5, : 128]
++	vadd.i64	q9, q2, q7
++	vshl.i64	q1, q1, #26
++	vshr.s64	q10, q9, #26
++	vld1.8		{d0}, [r2, : 64]!
++	vadd.i64	q5, q5, q10
++	vand		q9, q9, q1
++	vld1.8		{d16}, [r2, : 64]!
++	add		r2, sp, #528
++	vld1.8		{d20-d21}, [r2, : 128]
++	vadd.i64	q11, q5, q10
++	vsub.i64	q2, q2, q9
++	vshr.s64	q9, q11, #25
++	vext.32		d12, d5, d4, #0
++	vand		q11, q11, q4
++	vadd.i64	q0, q0, q9
++	vmov		d19, d7
++	vadd.i64	q3, q0, q7
++	vsub.i64	q5, q5, q11
++	vshr.s64	q11, q3, #26
++	vext.32		d18, d11, d10, #0
++	vand		q3, q3, q1
++	vadd.i64	q8, q8, q11
++	vadd.i64	q11, q8, q10
++	vsub.i64	q0, q0, q3
++	vshr.s64	q3, q11, #25
++	vand		q11, q11, q4
++	vadd.i64	q3, q6, q3
++	vadd.i64	q6, q3, q7
++	vsub.i64	q8, q8, q11
++	vshr.s64	q11, q6, #26
++	vand		q6, q6, q1
++	vadd.i64	q9, q9, q11
++	vadd.i64	d25, d19, d21
++	vsub.i64	q3, q3, q6
++	vshr.s64	d23, d25, #25
++	vand		q4, q12, q4
++	vadd.i64	d21, d23, d23
++	vshl.i64	d25, d23, #4
++	vadd.i64	d21, d21, d23
++	vadd.i64	d25, d25, d21
++	vadd.i64	d4, d4, d25
++	vzip.i32	q0, q8
++	vadd.i64	d12, d4, d14
++	add		r2, r6, #8
++	vst1.8		d0, [r2, : 64]
++	vsub.i64	d19, d19, d9
++	add		r2, r2, #16
++	vst1.8		d16, [r2, : 64]
++	vshr.s64	d22, d12, #26
++	vand		q0, q6, q1
++	vadd.i64	d10, d10, d22
++	vzip.i32	q3, q9
++	vsub.i64	d4, d4, d0
++	sub		r2, r2, #8
++	vst1.8		d6, [r2, : 64]
++	add		r2, r2, #16
++	vst1.8		d18, [r2, : 64]
++	vzip.i32	q2, q5
++	sub		r2, r2, #32
++	vst1.8		d4, [r2, : 64]
++	cmp		r4, #0
++	beq		._skippostcopy
++	add		r2, r3, #144
++	mov		r4, r4
++	vld1.8		{d0-d1}, [r2, : 128]!
++	vld1.8		{d2-d3}, [r2, : 128]!
++	vld1.8		{d4}, [r2, : 64]
++	vst1.8		{d0-d1}, [r4, : 128]!
++	vst1.8		{d2-d3}, [r4, : 128]!
++	vst1.8		d4, [r4, : 64]
++._skippostcopy:
++	cmp		r1, #1
++	bne		._skipfinalcopy
++	add		r2, r3, #288
++	add		r4, r3, #144
++	vld1.8		{d0-d1}, [r2, : 128]!
++	vld1.8		{d2-d3}, [r2, : 128]!
++	vld1.8		{d4}, [r2, : 64]
++	vst1.8		{d0-d1}, [r4, : 128]!
++	vst1.8		{d2-d3}, [r4, : 128]!
++	vst1.8		d4, [r4, : 64]
++._skipfinalcopy:
++	add		r1, r1, #1
++	cmp		r1, #12
++	blo		._invertloop
++	add		r1, r3, #144
++	ldr		r2, [r1], #4
++	ldr		r3, [r1], #4
++	ldr		r4, [r1], #4
++	ldr		r5, [r1], #4
++	ldr		r6, [r1], #4
++	ldr		r7, [r1], #4
++	ldr		r8, [r1], #4
++	ldr		r9, [r1], #4
++	ldr		r10, [r1], #4
++	ldr		r1, [r1]
++	add		r11, r1, r1, LSL #4
++	add		r11, r11, r1, LSL #1
++	add		r11, r11, #16777216
++	mov		r11, r11, ASR #25
++	add		r11, r11, r2
++	mov		r11, r11, ASR #26
++	add		r11, r11, r3
++	mov		r11, r11, ASR #25
++	add		r11, r11, r4
++	mov		r11, r11, ASR #26
++	add		r11, r11, r5
++	mov		r11, r11, ASR #25
++	add		r11, r11, r6
++	mov		r11, r11, ASR #26
++	add		r11, r11, r7
++	mov		r11, r11, ASR #25
++	add		r11, r11, r8
++	mov		r11, r11, ASR #26
++	add		r11, r11, r9
++	mov		r11, r11, ASR #25
++	add		r11, r11, r10
++	mov		r11, r11, ASR #26
++	add		r11, r11, r1
++	mov		r11, r11, ASR #25
++	add		r2, r2, r11
++	add		r2, r2, r11, LSL #1
++	add		r2, r2, r11, LSL #4
++	mov		r11, r2, ASR #26
++	add		r3, r3, r11
++	sub		r2, r2, r11, LSL #26
++	mov		r11, r3, ASR #25
++	add		r4, r4, r11
++	sub		r3, r3, r11, LSL #25
++	mov		r11, r4, ASR #26
++	add		r5, r5, r11
++	sub		r4, r4, r11, LSL #26
++	mov		r11, r5, ASR #25
++	add		r6, r6, r11
++	sub		r5, r5, r11, LSL #25
++	mov		r11, r6, ASR #26
++	add		r7, r7, r11
++	sub		r6, r6, r11, LSL #26
++	mov		r11, r7, ASR #25
++	add		r8, r8, r11
++	sub		r7, r7, r11, LSL #25
++	mov		r11, r8, ASR #26
++	add		r9, r9, r11
++	sub		r8, r8, r11, LSL #26
++	mov		r11, r9, ASR #25
++	add		r10, r10, r11
++	sub		r9, r9, r11, LSL #25
++	mov		r11, r10, ASR #26
++	add		r1, r1, r11
++	sub		r10, r10, r11, LSL #26
++	mov		r11, r1, ASR #25
++	sub		r1, r1, r11, LSL #25
++	add		r2, r2, r3, LSL #26
++	mov		r3, r3, LSR #6
++	add		r3, r3, r4, LSL #19
++	mov		r4, r4, LSR #13
++	add		r4, r4, r5, LSL #13
++	mov		r5, r5, LSR #19
++	add		r5, r5, r6, LSL #6
++	add		r6, r7, r8, LSL #25
++	mov		r7, r8, LSR #7
++	add		r7, r7, r9, LSL #19
++	mov		r8, r9, LSR #13
++	add		r8, r8, r10, LSL #12
++	mov		r9, r10, LSR #20
++	add		r1, r9, r1, LSL #6
++	str		r2, [r0], #4
++	str		r3, [r0], #4
++	str		r4, [r0], #4
++	str		r5, [r0], #4
++	str		r6, [r0], #4
++	str		r7, [r0], #4
++	str		r8, [r0], #4
++	str		r1, [r0]
++	ldrd		r4, [sp, #0]
++	ldrd		r6, [sp, #8]
++	ldrd		r8, [sp, #16]
++	ldrd		r10, [sp, #24]
++	ldr		r12, [sp, #480]
++	ldr		r14, [sp, #484]
++	ldr		r0, =0
++	mov		sp, r12
++	vpop		{q4, q5, q6, q7}
++	bx		lr
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0031-crypto-arm-curve25519-wire-up-NEON-implementation.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0031-crypto-arm-curve25519-wire-up-NEON-implementation.patch
new file mode 100644
index 0000000..d84726b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0031-crypto-arm-curve25519-wire-up-NEON-implementation.patch
@@ -0,0 +1,1058 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 8 Nov 2019 13:22:38 +0100
+Subject: [PATCH] crypto: arm/curve25519 - wire up NEON implementation
+
+commit d8f1308a025fc7e00414194ed742d5f05a21e13c upstream.
+
+This ports the SUPERCOP implementation for usage in kernel space. In
+addition to the usual header, macro, and style changes required for
+kernel space, it makes a few small changes to the code:
+
+  - The stack alignment is relaxed to 16 bytes.
+  - Superfluous mov statements have been removed.
+  - ldr for constants has been replaced with movw.
+  - ldreq has been replaced with moveq.
+  - The str epilogue has been made more idiomatic.
+  - SIMD registers are not pushed and popped at the beginning and end.
+  - The prologue and epilogue have been made idiomatic.
+  - A hole has been removed from the stack, saving 32 bytes.
+  - We write-back the base register whenever possible for vld1.8.
+  - Some multiplications have been reordered for better A7 performance.
+
+There are more opportunities for cleanup, since this code is from qhasm,
+which doesn't always do the most opportune thing. But even prior to
+extensive hand optimizations, this code delivers significant performance
+improvements (given in get_cycles() per call):
+
+		      ----------- -------------
+	             | generic C | this commit |
+	 ------------ ----------- -------------
+	| Cortex-A7  |     49136 |       22395 |
+	 ------------ ----------- -------------
+	| Cortex-A17 |     17326 |        4983 |
+	 ------------ ----------- -------------
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+[ardb: - move to arch/arm/crypto
+       - wire into lib/crypto framework
+       - implement crypto API KPP hooks ]
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm/crypto/Kconfig           |   6 +
+ arch/arm/crypto/Makefile          |   2 +
+ arch/arm/crypto/curve25519-core.S | 347 +++++++++++++-----------------
+ arch/arm/crypto/curve25519-glue.c | 127 +++++++++++
+ 4 files changed, 287 insertions(+), 195 deletions(-)
+ create mode 100644 arch/arm/crypto/curve25519-glue.c
+
+--- a/arch/arm/crypto/Kconfig
++++ b/arch/arm/crypto/Kconfig
+@@ -141,4 +141,10 @@ config CRYPTO_NHPOLY1305_NEON
+ 	depends on KERNEL_MODE_NEON
+ 	select CRYPTO_NHPOLY1305
+ 
++config CRYPTO_CURVE25519_NEON
++	tristate "NEON accelerated Curve25519 scalar multiplication library"
++	depends on KERNEL_MODE_NEON
++	select CRYPTO_LIB_CURVE25519_GENERIC
++	select CRYPTO_ARCH_HAVE_LIB_CURVE25519
++
+ endif
+--- a/arch/arm/crypto/Makefile
++++ b/arch/arm/crypto/Makefile
+@@ -12,6 +12,7 @@ obj-$(CONFIG_CRYPTO_SHA512_ARM) += sha51
+ obj-$(CONFIG_CRYPTO_CHACHA20_NEON) += chacha-neon.o
+ obj-$(CONFIG_CRYPTO_POLY1305_ARM) += poly1305-arm.o
+ obj-$(CONFIG_CRYPTO_NHPOLY1305_NEON) += nhpoly1305-neon.o
++obj-$(CONFIG_CRYPTO_CURVE25519_NEON) += curve25519-neon.o
+ 
+ ce-obj-$(CONFIG_CRYPTO_AES_ARM_CE) += aes-arm-ce.o
+ ce-obj-$(CONFIG_CRYPTO_SHA1_ARM_CE) += sha1-arm-ce.o
+@@ -58,6 +59,7 @@ chacha-neon-y := chacha-scalar-core.o ch
+ chacha-neon-$(CONFIG_KERNEL_MODE_NEON) += chacha-neon-core.o
+ poly1305-arm-y := poly1305-core.o poly1305-glue.o
+ nhpoly1305-neon-y := nh-neon-core.o nhpoly1305-neon-glue.o
++curve25519-neon-y := curve25519-core.o curve25519-glue.o
+ 
+ ifdef REGENERATE_ARM_CRYPTO
+ quiet_cmd_perl = PERL    $@
+--- a/arch/arm/crypto/curve25519-core.S
++++ b/arch/arm/crypto/curve25519-core.S
+@@ -1,43 +1,35 @@
++/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+ /*
+- * Public domain code from Daniel J. Bernstein and Peter Schwabe, from
+- * SUPERCOP's curve25519/neon2/scalarmult.s.
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ *
++ * Based on public domain code from Daniel J. Bernstein and Peter Schwabe. This
++ * began from SUPERCOP's curve25519/neon2/scalarmult.s, but has subsequently been
++ * manually reworked for use in kernel space.
+  */
+ 
+-.fpu neon
++#include <linux/linkage.h>
++
+ .text
++.fpu neon
++.arch armv7-a
+ .align 4
+-.global _crypto_scalarmult_curve25519_neon2
+-.global crypto_scalarmult_curve25519_neon2
+-.type _crypto_scalarmult_curve25519_neon2 STT_FUNC
+-.type crypto_scalarmult_curve25519_neon2 STT_FUNC
+-	_crypto_scalarmult_curve25519_neon2:
+-	crypto_scalarmult_curve25519_neon2:
+-	vpush		{q4, q5, q6, q7}
+-	mov		r12, sp
+-	sub		sp, sp, #736
+-	and		sp, sp, #0xffffffe0
+-	strd		r4, [sp, #0]
+-	strd		r6, [sp, #8]
+-	strd		r8, [sp, #16]
+-	strd		r10, [sp, #24]
+-	str		r12, [sp, #480]
+-	str		r14, [sp, #484]
+-	mov		r0, r0
+-	mov		r1, r1
+-	mov		r2, r2
+-	add		r3, sp, #32
+-	ldr		r4, =0
+-	ldr		r5, =254
++
++ENTRY(curve25519_neon)
++	push		{r4-r11, lr}
++	mov		ip, sp
++	sub		r3, sp, #704
++	and		r3, r3, #0xfffffff0
++	mov		sp, r3
++	movw		r4, #0
++	movw		r5, #254
+ 	vmov.i32	q0, #1
+ 	vshr.u64	q1, q0, #7
+ 	vshr.u64	q0, q0, #8
+ 	vmov.i32	d4, #19
+ 	vmov.i32	d5, #38
+-	add		r6, sp, #512
+-	vst1.8		{d2-d3}, [r6, : 128]
+-	add		r6, sp, #528
+-	vst1.8		{d0-d1}, [r6, : 128]
+-	add		r6, sp, #544
++	add		r6, sp, #480
++	vst1.8		{d2-d3}, [r6, : 128]!
++	vst1.8		{d0-d1}, [r6, : 128]!
+ 	vst1.8		{d4-d5}, [r6, : 128]
+ 	add		r6, r3, #0
+ 	vmov.i32	q2, #0
+@@ -45,12 +37,12 @@
+ 	vst1.8		{d4-d5}, [r6, : 128]!
+ 	vst1.8		d4, [r6, : 64]
+ 	add		r6, r3, #0
+-	ldr		r7, =960
++	movw		r7, #960
+ 	sub		r7, r7, #2
+ 	neg		r7, r7
+ 	sub		r7, r7, r7, LSL #7
+ 	str		r7, [r6]
+-	add		r6, sp, #704
++	add		r6, sp, #672
+ 	vld1.8		{d4-d5}, [r1]!
+ 	vld1.8		{d6-d7}, [r1]
+ 	vst1.8		{d4-d5}, [r6, : 128]!
+@@ -212,15 +204,15 @@
+ 	vst1.8		{d0-d1}, [r6, : 128]!
+ 	vst1.8		{d2-d3}, [r6, : 128]!
+ 	vst1.8		d4, [r6, : 64]
+-._mainloop:
++.Lmainloop:
+ 	mov		r2, r5, LSR #3
+ 	and		r6, r5, #7
+ 	ldrb		r2, [r1, r2]
+ 	mov		r2, r2, LSR r6
+ 	and		r2, r2, #1
+-	str		r5, [sp, #488]
++	str		r5, [sp, #456]
+ 	eor		r4, r4, r2
+-	str		r2, [sp, #492]
++	str		r2, [sp, #460]
+ 	neg		r2, r4
+ 	add		r4, r3, #96
+ 	add		r5, r3, #192
+@@ -291,7 +283,7 @@
+ 	vsub.i32	q0, q1, q3
+ 	vst1.8		d4, [r4, : 64]
+ 	vst1.8		d0, [r6, : 64]
+-	add		r2, sp, #544
++	add		r2, sp, #512
+ 	add		r4, r3, #96
+ 	add		r5, r3, #144
+ 	vld1.8		{d0-d1}, [r2, : 128]
+@@ -361,14 +353,13 @@
+ 	vmlal.s32	q0, d12, d8
+ 	vmlal.s32	q0, d13, d17
+ 	vmlal.s32	q0, d6, d6
+-	add		r2, sp, #512
+-	vld1.8		{d18-d19}, [r2, : 128]
++	add		r2, sp, #480
++	vld1.8		{d18-d19}, [r2, : 128]!
+ 	vmull.s32	q3, d16, d7
+ 	vmlal.s32	q3, d10, d15
+ 	vmlal.s32	q3, d11, d14
+ 	vmlal.s32	q3, d12, d9
+ 	vmlal.s32	q3, d13, d8
+-	add		r2, sp, #528
+ 	vld1.8		{d8-d9}, [r2, : 128]
+ 	vadd.i64	q5, q12, q9
+ 	vadd.i64	q6, q15, q9
+@@ -502,22 +493,19 @@
+ 	vadd.i32	q5, q5, q0
+ 	vtrn.32		q11, q14
+ 	vadd.i32	q6, q6, q3
+-	add		r2, sp, #560
++	add		r2, sp, #528
+ 	vadd.i32	q10, q10, q2
+ 	vtrn.32		d24, d25
+-	vst1.8		{d12-d13}, [r2, : 128]
++	vst1.8		{d12-d13}, [r2, : 128]!
+ 	vshl.i32	q6, q13, #1
+-	add		r2, sp, #576
+-	vst1.8		{d20-d21}, [r2, : 128]
++	vst1.8		{d20-d21}, [r2, : 128]!
+ 	vshl.i32	q10, q14, #1
+-	add		r2, sp, #592
+-	vst1.8		{d12-d13}, [r2, : 128]
++	vst1.8		{d12-d13}, [r2, : 128]!
+ 	vshl.i32	q15, q12, #1
+ 	vadd.i32	q8, q8, q4
+ 	vext.32		d10, d31, d30, #0
+ 	vadd.i32	q7, q7, q1
+-	add		r2, sp, #608
+-	vst1.8		{d16-d17}, [r2, : 128]
++	vst1.8		{d16-d17}, [r2, : 128]!
+ 	vmull.s32	q8, d18, d5
+ 	vmlal.s32	q8, d26, d4
+ 	vmlal.s32	q8, d19, d9
+@@ -528,8 +516,7 @@
+ 	vmlal.s32	q8, d29, d1
+ 	vmlal.s32	q8, d24, d6
+ 	vmlal.s32	q8, d25, d0
+-	add		r2, sp, #624
+-	vst1.8		{d14-d15}, [r2, : 128]
++	vst1.8		{d14-d15}, [r2, : 128]!
+ 	vmull.s32	q2, d18, d4
+ 	vmlal.s32	q2, d12, d9
+ 	vmlal.s32	q2, d13, d8
+@@ -537,8 +524,7 @@
+ 	vmlal.s32	q2, d22, d2
+ 	vmlal.s32	q2, d23, d1
+ 	vmlal.s32	q2, d24, d0
+-	add		r2, sp, #640
+-	vst1.8		{d20-d21}, [r2, : 128]
++	vst1.8		{d20-d21}, [r2, : 128]!
+ 	vmull.s32	q7, d18, d9
+ 	vmlal.s32	q7, d26, d3
+ 	vmlal.s32	q7, d19, d8
+@@ -547,14 +533,12 @@
+ 	vmlal.s32	q7, d28, d1
+ 	vmlal.s32	q7, d23, d6
+ 	vmlal.s32	q7, d29, d0
+-	add		r2, sp, #656
+-	vst1.8		{d10-d11}, [r2, : 128]
++	vst1.8		{d10-d11}, [r2, : 128]!
+ 	vmull.s32	q5, d18, d3
+ 	vmlal.s32	q5, d19, d2
+ 	vmlal.s32	q5, d22, d1
+ 	vmlal.s32	q5, d23, d0
+ 	vmlal.s32	q5, d12, d8
+-	add		r2, sp, #672
+ 	vst1.8		{d16-d17}, [r2, : 128]
+ 	vmull.s32	q4, d18, d8
+ 	vmlal.s32	q4, d26, d2
+@@ -566,7 +550,7 @@
+ 	vmlal.s32	q8, d26, d1
+ 	vmlal.s32	q8, d19, d6
+ 	vmlal.s32	q8, d27, d0
+-	add		r2, sp, #576
++	add		r2, sp, #544
+ 	vld1.8		{d20-d21}, [r2, : 128]
+ 	vmlal.s32	q7, d24, d21
+ 	vmlal.s32	q7, d25, d20
+@@ -575,32 +559,30 @@
+ 	vmlal.s32	q8, d22, d21
+ 	vmlal.s32	q8, d28, d20
+ 	vmlal.s32	q5, d24, d20
+-	add		r2, sp, #576
+ 	vst1.8		{d14-d15}, [r2, : 128]
+ 	vmull.s32	q7, d18, d6
+ 	vmlal.s32	q7, d26, d0
+-	add		r2, sp, #656
++	add		r2, sp, #624
+ 	vld1.8		{d30-d31}, [r2, : 128]
+ 	vmlal.s32	q2, d30, d21
+ 	vmlal.s32	q7, d19, d21
+ 	vmlal.s32	q7, d27, d20
+-	add		r2, sp, #624
++	add		r2, sp, #592
+ 	vld1.8		{d26-d27}, [r2, : 128]
+ 	vmlal.s32	q4, d25, d27
+ 	vmlal.s32	q8, d29, d27
+ 	vmlal.s32	q8, d25, d26
+ 	vmlal.s32	q7, d28, d27
+ 	vmlal.s32	q7, d29, d26
+-	add		r2, sp, #608
++	add		r2, sp, #576
+ 	vld1.8		{d28-d29}, [r2, : 128]
+ 	vmlal.s32	q4, d24, d29
+ 	vmlal.s32	q8, d23, d29
+ 	vmlal.s32	q8, d24, d28
+ 	vmlal.s32	q7, d22, d29
+ 	vmlal.s32	q7, d23, d28
+-	add		r2, sp, #608
+ 	vst1.8		{d8-d9}, [r2, : 128]
+-	add		r2, sp, #560
++	add		r2, sp, #528
+ 	vld1.8		{d8-d9}, [r2, : 128]
+ 	vmlal.s32	q7, d24, d9
+ 	vmlal.s32	q7, d25, d31
+@@ -621,36 +603,36 @@
+ 	vmlal.s32	q0, d23, d26
+ 	vmlal.s32	q0, d24, d31
+ 	vmlal.s32	q0, d19, d20
+-	add		r2, sp, #640
++	add		r2, sp, #608
+ 	vld1.8		{d18-d19}, [r2, : 128]
+ 	vmlal.s32	q2, d18, d7
+-	vmlal.s32	q2, d19, d6
+ 	vmlal.s32	q5, d18, d6
+-	vmlal.s32	q5, d19, d21
+ 	vmlal.s32	q1, d18, d21
+-	vmlal.s32	q1, d19, d29
+ 	vmlal.s32	q0, d18, d28
+-	vmlal.s32	q0, d19, d9
+ 	vmlal.s32	q6, d18, d29
++	vmlal.s32	q2, d19, d6
++	vmlal.s32	q5, d19, d21
++	vmlal.s32	q1, d19, d29
++	vmlal.s32	q0, d19, d9
+ 	vmlal.s32	q6, d19, d28
+-	add		r2, sp, #592
++	add		r2, sp, #560
+ 	vld1.8		{d18-d19}, [r2, : 128]
+-	add		r2, sp, #512
++	add		r2, sp, #480
+ 	vld1.8		{d22-d23}, [r2, : 128]
+ 	vmlal.s32	q5, d19, d7
+ 	vmlal.s32	q0, d18, d21
+ 	vmlal.s32	q0, d19, d29
+ 	vmlal.s32	q6, d18, d6
+-	add		r2, sp, #528
++	add		r2, sp, #496
+ 	vld1.8		{d6-d7}, [r2, : 128]
+ 	vmlal.s32	q6, d19, d21
+-	add		r2, sp, #576
++	add		r2, sp, #544
+ 	vld1.8		{d18-d19}, [r2, : 128]
+ 	vmlal.s32	q0, d30, d8
+-	add		r2, sp, #672
++	add		r2, sp, #640
+ 	vld1.8		{d20-d21}, [r2, : 128]
+ 	vmlal.s32	q5, d30, d29
+-	add		r2, sp, #608
++	add		r2, sp, #576
+ 	vld1.8		{d24-d25}, [r2, : 128]
+ 	vmlal.s32	q1, d30, d28
+ 	vadd.i64	q13, q0, q11
+@@ -823,22 +805,19 @@
+ 	vadd.i32	q5, q5, q0
+ 	vtrn.32		q11, q14
+ 	vadd.i32	q6, q6, q3
+-	add		r2, sp, #560
++	add		r2, sp, #528
+ 	vadd.i32	q10, q10, q2
+ 	vtrn.32		d24, d25
+-	vst1.8		{d12-d13}, [r2, : 128]
++	vst1.8		{d12-d13}, [r2, : 128]!
+ 	vshl.i32	q6, q13, #1
+-	add		r2, sp, #576
+-	vst1.8		{d20-d21}, [r2, : 128]
++	vst1.8		{d20-d21}, [r2, : 128]!
+ 	vshl.i32	q10, q14, #1
+-	add		r2, sp, #592
+-	vst1.8		{d12-d13}, [r2, : 128]
++	vst1.8		{d12-d13}, [r2, : 128]!
+ 	vshl.i32	q15, q12, #1
+ 	vadd.i32	q8, q8, q4
+ 	vext.32		d10, d31, d30, #0
+ 	vadd.i32	q7, q7, q1
+-	add		r2, sp, #608
+-	vst1.8		{d16-d17}, [r2, : 128]
++	vst1.8		{d16-d17}, [r2, : 128]!
+ 	vmull.s32	q8, d18, d5
+ 	vmlal.s32	q8, d26, d4
+ 	vmlal.s32	q8, d19, d9
+@@ -849,8 +828,7 @@
+ 	vmlal.s32	q8, d29, d1
+ 	vmlal.s32	q8, d24, d6
+ 	vmlal.s32	q8, d25, d0
+-	add		r2, sp, #624
+-	vst1.8		{d14-d15}, [r2, : 128]
++	vst1.8		{d14-d15}, [r2, : 128]!
+ 	vmull.s32	q2, d18, d4
+ 	vmlal.s32	q2, d12, d9
+ 	vmlal.s32	q2, d13, d8
+@@ -858,8 +836,7 @@
+ 	vmlal.s32	q2, d22, d2
+ 	vmlal.s32	q2, d23, d1
+ 	vmlal.s32	q2, d24, d0
+-	add		r2, sp, #640
+-	vst1.8		{d20-d21}, [r2, : 128]
++	vst1.8		{d20-d21}, [r2, : 128]!
+ 	vmull.s32	q7, d18, d9
+ 	vmlal.s32	q7, d26, d3
+ 	vmlal.s32	q7, d19, d8
+@@ -868,15 +845,13 @@
+ 	vmlal.s32	q7, d28, d1
+ 	vmlal.s32	q7, d23, d6
+ 	vmlal.s32	q7, d29, d0
+-	add		r2, sp, #656
+-	vst1.8		{d10-d11}, [r2, : 128]
++	vst1.8		{d10-d11}, [r2, : 128]!
+ 	vmull.s32	q5, d18, d3
+ 	vmlal.s32	q5, d19, d2
+ 	vmlal.s32	q5, d22, d1
+ 	vmlal.s32	q5, d23, d0
+ 	vmlal.s32	q5, d12, d8
+-	add		r2, sp, #672
+-	vst1.8		{d16-d17}, [r2, : 128]
++	vst1.8		{d16-d17}, [r2, : 128]!
+ 	vmull.s32	q4, d18, d8
+ 	vmlal.s32	q4, d26, d2
+ 	vmlal.s32	q4, d19, d7
+@@ -887,7 +862,7 @@
+ 	vmlal.s32	q8, d26, d1
+ 	vmlal.s32	q8, d19, d6
+ 	vmlal.s32	q8, d27, d0
+-	add		r2, sp, #576
++	add		r2, sp, #544
+ 	vld1.8		{d20-d21}, [r2, : 128]
+ 	vmlal.s32	q7, d24, d21
+ 	vmlal.s32	q7, d25, d20
+@@ -896,32 +871,30 @@
+ 	vmlal.s32	q8, d22, d21
+ 	vmlal.s32	q8, d28, d20
+ 	vmlal.s32	q5, d24, d20
+-	add		r2, sp, #576
+ 	vst1.8		{d14-d15}, [r2, : 128]
+ 	vmull.s32	q7, d18, d6
+ 	vmlal.s32	q7, d26, d0
+-	add		r2, sp, #656
++	add		r2, sp, #624
+ 	vld1.8		{d30-d31}, [r2, : 128]
+ 	vmlal.s32	q2, d30, d21
+ 	vmlal.s32	q7, d19, d21
+ 	vmlal.s32	q7, d27, d20
+-	add		r2, sp, #624
++	add		r2, sp, #592
+ 	vld1.8		{d26-d27}, [r2, : 128]
+ 	vmlal.s32	q4, d25, d27
+ 	vmlal.s32	q8, d29, d27
+ 	vmlal.s32	q8, d25, d26
+ 	vmlal.s32	q7, d28, d27
+ 	vmlal.s32	q7, d29, d26
+-	add		r2, sp, #608
++	add		r2, sp, #576
+ 	vld1.8		{d28-d29}, [r2, : 128]
+ 	vmlal.s32	q4, d24, d29
+ 	vmlal.s32	q8, d23, d29
+ 	vmlal.s32	q8, d24, d28
+ 	vmlal.s32	q7, d22, d29
+ 	vmlal.s32	q7, d23, d28
+-	add		r2, sp, #608
+ 	vst1.8		{d8-d9}, [r2, : 128]
+-	add		r2, sp, #560
++	add		r2, sp, #528
+ 	vld1.8		{d8-d9}, [r2, : 128]
+ 	vmlal.s32	q7, d24, d9
+ 	vmlal.s32	q7, d25, d31
+@@ -942,36 +915,36 @@
+ 	vmlal.s32	q0, d23, d26
+ 	vmlal.s32	q0, d24, d31
+ 	vmlal.s32	q0, d19, d20
+-	add		r2, sp, #640
++	add		r2, sp, #608
+ 	vld1.8		{d18-d19}, [r2, : 128]
+ 	vmlal.s32	q2, d18, d7
+-	vmlal.s32	q2, d19, d6
+ 	vmlal.s32	q5, d18, d6
+-	vmlal.s32	q5, d19, d21
+ 	vmlal.s32	q1, d18, d21
+-	vmlal.s32	q1, d19, d29
+ 	vmlal.s32	q0, d18, d28
+-	vmlal.s32	q0, d19, d9
+ 	vmlal.s32	q6, d18, d29
++	vmlal.s32	q2, d19, d6
++	vmlal.s32	q5, d19, d21
++	vmlal.s32	q1, d19, d29
++	vmlal.s32	q0, d19, d9
+ 	vmlal.s32	q6, d19, d28
+-	add		r2, sp, #592
++	add		r2, sp, #560
+ 	vld1.8		{d18-d19}, [r2, : 128]
+-	add		r2, sp, #512
++	add		r2, sp, #480
+ 	vld1.8		{d22-d23}, [r2, : 128]
+ 	vmlal.s32	q5, d19, d7
+ 	vmlal.s32	q0, d18, d21
+ 	vmlal.s32	q0, d19, d29
+ 	vmlal.s32	q6, d18, d6
+-	add		r2, sp, #528
++	add		r2, sp, #496
+ 	vld1.8		{d6-d7}, [r2, : 128]
+ 	vmlal.s32	q6, d19, d21
+-	add		r2, sp, #576
++	add		r2, sp, #544
+ 	vld1.8		{d18-d19}, [r2, : 128]
+ 	vmlal.s32	q0, d30, d8
+-	add		r2, sp, #672
++	add		r2, sp, #640
+ 	vld1.8		{d20-d21}, [r2, : 128]
+ 	vmlal.s32	q5, d30, d29
+-	add		r2, sp, #608
++	add		r2, sp, #576
+ 	vld1.8		{d24-d25}, [r2, : 128]
+ 	vmlal.s32	q1, d30, d28
+ 	vadd.i64	q13, q0, q11
+@@ -1069,7 +1042,7 @@
+ 	sub		r4, r4, #24
+ 	vst1.8		d0, [r2, : 64]
+ 	vst1.8		d1, [r4, : 64]
+-	add		r2, sp, #544
++	add		r2, sp, #512
+ 	add		r4, r3, #144
+ 	add		r5, r3, #192
+ 	vld1.8		{d0-d1}, [r2, : 128]
+@@ -1139,14 +1112,13 @@
+ 	vmlal.s32	q0, d12, d8
+ 	vmlal.s32	q0, d13, d17
+ 	vmlal.s32	q0, d6, d6
+-	add		r2, sp, #512
+-	vld1.8		{d18-d19}, [r2, : 128]
++	add		r2, sp, #480
++	vld1.8		{d18-d19}, [r2, : 128]!
+ 	vmull.s32	q3, d16, d7
+ 	vmlal.s32	q3, d10, d15
+ 	vmlal.s32	q3, d11, d14
+ 	vmlal.s32	q3, d12, d9
+ 	vmlal.s32	q3, d13, d8
+-	add		r2, sp, #528
+ 	vld1.8		{d8-d9}, [r2, : 128]
+ 	vadd.i64	q5, q12, q9
+ 	vadd.i64	q6, q15, q9
+@@ -1295,22 +1267,19 @@
+ 	vadd.i32	q5, q5, q0
+ 	vtrn.32		q11, q14
+ 	vadd.i32	q6, q6, q3
+-	add		r2, sp, #560
++	add		r2, sp, #528
+ 	vadd.i32	q10, q10, q2
+ 	vtrn.32		d24, d25
+-	vst1.8		{d12-d13}, [r2, : 128]
++	vst1.8		{d12-d13}, [r2, : 128]!
+ 	vshl.i32	q6, q13, #1
+-	add		r2, sp, #576
+-	vst1.8		{d20-d21}, [r2, : 128]
++	vst1.8		{d20-d21}, [r2, : 128]!
+ 	vshl.i32	q10, q14, #1
+-	add		r2, sp, #592
+-	vst1.8		{d12-d13}, [r2, : 128]
++	vst1.8		{d12-d13}, [r2, : 128]!
+ 	vshl.i32	q15, q12, #1
+ 	vadd.i32	q8, q8, q4
+ 	vext.32		d10, d31, d30, #0
+ 	vadd.i32	q7, q7, q1
+-	add		r2, sp, #608
+-	vst1.8		{d16-d17}, [r2, : 128]
++	vst1.8		{d16-d17}, [r2, : 128]!
+ 	vmull.s32	q8, d18, d5
+ 	vmlal.s32	q8, d26, d4
+ 	vmlal.s32	q8, d19, d9
+@@ -1321,8 +1290,7 @@
+ 	vmlal.s32	q8, d29, d1
+ 	vmlal.s32	q8, d24, d6
+ 	vmlal.s32	q8, d25, d0
+-	add		r2, sp, #624
+-	vst1.8		{d14-d15}, [r2, : 128]
++	vst1.8		{d14-d15}, [r2, : 128]!
+ 	vmull.s32	q2, d18, d4
+ 	vmlal.s32	q2, d12, d9
+ 	vmlal.s32	q2, d13, d8
+@@ -1330,8 +1298,7 @@
+ 	vmlal.s32	q2, d22, d2
+ 	vmlal.s32	q2, d23, d1
+ 	vmlal.s32	q2, d24, d0
+-	add		r2, sp, #640
+-	vst1.8		{d20-d21}, [r2, : 128]
++	vst1.8		{d20-d21}, [r2, : 128]!
+ 	vmull.s32	q7, d18, d9
+ 	vmlal.s32	q7, d26, d3
+ 	vmlal.s32	q7, d19, d8
+@@ -1340,15 +1307,13 @@
+ 	vmlal.s32	q7, d28, d1
+ 	vmlal.s32	q7, d23, d6
+ 	vmlal.s32	q7, d29, d0
+-	add		r2, sp, #656
+-	vst1.8		{d10-d11}, [r2, : 128]
++	vst1.8		{d10-d11}, [r2, : 128]!
+ 	vmull.s32	q5, d18, d3
+ 	vmlal.s32	q5, d19, d2
+ 	vmlal.s32	q5, d22, d1
+ 	vmlal.s32	q5, d23, d0
+ 	vmlal.s32	q5, d12, d8
+-	add		r2, sp, #672
+-	vst1.8		{d16-d17}, [r2, : 128]
++	vst1.8		{d16-d17}, [r2, : 128]!
+ 	vmull.s32	q4, d18, d8
+ 	vmlal.s32	q4, d26, d2
+ 	vmlal.s32	q4, d19, d7
+@@ -1359,7 +1324,7 @@
+ 	vmlal.s32	q8, d26, d1
+ 	vmlal.s32	q8, d19, d6
+ 	vmlal.s32	q8, d27, d0
+-	add		r2, sp, #576
++	add		r2, sp, #544
+ 	vld1.8		{d20-d21}, [r2, : 128]
+ 	vmlal.s32	q7, d24, d21
+ 	vmlal.s32	q7, d25, d20
+@@ -1368,32 +1333,30 @@
+ 	vmlal.s32	q8, d22, d21
+ 	vmlal.s32	q8, d28, d20
+ 	vmlal.s32	q5, d24, d20
+-	add		r2, sp, #576
+ 	vst1.8		{d14-d15}, [r2, : 128]
+ 	vmull.s32	q7, d18, d6
+ 	vmlal.s32	q7, d26, d0
+-	add		r2, sp, #656
++	add		r2, sp, #624
+ 	vld1.8		{d30-d31}, [r2, : 128]
+ 	vmlal.s32	q2, d30, d21
+ 	vmlal.s32	q7, d19, d21
+ 	vmlal.s32	q7, d27, d20
+-	add		r2, sp, #624
++	add		r2, sp, #592
+ 	vld1.8		{d26-d27}, [r2, : 128]
+ 	vmlal.s32	q4, d25, d27
+ 	vmlal.s32	q8, d29, d27
+ 	vmlal.s32	q8, d25, d26
+ 	vmlal.s32	q7, d28, d27
+ 	vmlal.s32	q7, d29, d26
+-	add		r2, sp, #608
++	add		r2, sp, #576
+ 	vld1.8		{d28-d29}, [r2, : 128]
+ 	vmlal.s32	q4, d24, d29
+ 	vmlal.s32	q8, d23, d29
+ 	vmlal.s32	q8, d24, d28
+ 	vmlal.s32	q7, d22, d29
+ 	vmlal.s32	q7, d23, d28
+-	add		r2, sp, #608
+ 	vst1.8		{d8-d9}, [r2, : 128]
+-	add		r2, sp, #560
++	add		r2, sp, #528
+ 	vld1.8		{d8-d9}, [r2, : 128]
+ 	vmlal.s32	q7, d24, d9
+ 	vmlal.s32	q7, d25, d31
+@@ -1414,36 +1377,36 @@
+ 	vmlal.s32	q0, d23, d26
+ 	vmlal.s32	q0, d24, d31
+ 	vmlal.s32	q0, d19, d20
+-	add		r2, sp, #640
++	add		r2, sp, #608
+ 	vld1.8		{d18-d19}, [r2, : 128]
+ 	vmlal.s32	q2, d18, d7
+-	vmlal.s32	q2, d19, d6
+ 	vmlal.s32	q5, d18, d6
+-	vmlal.s32	q5, d19, d21
+ 	vmlal.s32	q1, d18, d21
+-	vmlal.s32	q1, d19, d29
+ 	vmlal.s32	q0, d18, d28
+-	vmlal.s32	q0, d19, d9
+ 	vmlal.s32	q6, d18, d29
++	vmlal.s32	q2, d19, d6
++	vmlal.s32	q5, d19, d21
++	vmlal.s32	q1, d19, d29
++	vmlal.s32	q0, d19, d9
+ 	vmlal.s32	q6, d19, d28
+-	add		r2, sp, #592
++	add		r2, sp, #560
+ 	vld1.8		{d18-d19}, [r2, : 128]
+-	add		r2, sp, #512
++	add		r2, sp, #480
+ 	vld1.8		{d22-d23}, [r2, : 128]
+ 	vmlal.s32	q5, d19, d7
+ 	vmlal.s32	q0, d18, d21
+ 	vmlal.s32	q0, d19, d29
+ 	vmlal.s32	q6, d18, d6
+-	add		r2, sp, #528
++	add		r2, sp, #496
+ 	vld1.8		{d6-d7}, [r2, : 128]
+ 	vmlal.s32	q6, d19, d21
+-	add		r2, sp, #576
++	add		r2, sp, #544
+ 	vld1.8		{d18-d19}, [r2, : 128]
+ 	vmlal.s32	q0, d30, d8
+-	add		r2, sp, #672
++	add		r2, sp, #640
+ 	vld1.8		{d20-d21}, [r2, : 128]
+ 	vmlal.s32	q5, d30, d29
+-	add		r2, sp, #608
++	add		r2, sp, #576
+ 	vld1.8		{d24-d25}, [r2, : 128]
+ 	vmlal.s32	q1, d30, d28
+ 	vadd.i64	q13, q0, q11
+@@ -1541,10 +1504,10 @@
+ 	sub		r4, r4, #24
+ 	vst1.8		d0, [r2, : 64]
+ 	vst1.8		d1, [r4, : 64]
+-	ldr		r2, [sp, #488]
+-	ldr		r4, [sp, #492]
++	ldr		r2, [sp, #456]
++	ldr		r4, [sp, #460]
+ 	subs		r5, r2, #1
+-	bge		._mainloop
++	bge		.Lmainloop
+ 	add		r1, r3, #144
+ 	add		r2, r3, #336
+ 	vld1.8		{d0-d1}, [r1, : 128]!
+@@ -1553,41 +1516,41 @@
+ 	vst1.8		{d0-d1}, [r2, : 128]!
+ 	vst1.8		{d2-d3}, [r2, : 128]!
+ 	vst1.8		d4, [r2, : 64]
+-	ldr		r1, =0
+-._invertloop:
++	movw		r1, #0
++.Linvertloop:
+ 	add		r2, r3, #144
+-	ldr		r4, =0
+-	ldr		r5, =2
++	movw		r4, #0
++	movw		r5, #2
+ 	cmp		r1, #1
+-	ldreq		r5, =1
++	moveq		r5, #1
+ 	addeq		r2, r3, #336
+ 	addeq		r4, r3, #48
+ 	cmp		r1, #2
+-	ldreq		r5, =1
++	moveq		r5, #1
+ 	addeq		r2, r3, #48
+ 	cmp		r1, #3
+-	ldreq		r5, =5
++	moveq		r5, #5
+ 	addeq		r4, r3, #336
+ 	cmp		r1, #4
+-	ldreq		r5, =10
++	moveq		r5, #10
+ 	cmp		r1, #5
+-	ldreq		r5, =20
++	moveq		r5, #20
+ 	cmp		r1, #6
+-	ldreq		r5, =10
++	moveq		r5, #10
+ 	addeq		r2, r3, #336
+ 	addeq		r4, r3, #336
+ 	cmp		r1, #7
+-	ldreq		r5, =50
++	moveq		r5, #50
+ 	cmp		r1, #8
+-	ldreq		r5, =100
++	moveq		r5, #100
+ 	cmp		r1, #9
+-	ldreq		r5, =50
++	moveq		r5, #50
+ 	addeq		r2, r3, #336
+ 	cmp		r1, #10
+-	ldreq		r5, =5
++	moveq		r5, #5
+ 	addeq		r2, r3, #48
+ 	cmp		r1, #11
+-	ldreq		r5, =0
++	moveq		r5, #0
+ 	addeq		r2, r3, #96
+ 	add		r6, r3, #144
+ 	add		r7, r3, #288
+@@ -1598,8 +1561,8 @@
+ 	vst1.8		{d2-d3}, [r7, : 128]!
+ 	vst1.8		d4, [r7, : 64]
+ 	cmp		r5, #0
+-	beq		._skipsquaringloop
+-._squaringloop:
++	beq		.Lskipsquaringloop
++.Lsquaringloop:
+ 	add		r6, r3, #288
+ 	add		r7, r3, #288
+ 	add		r8, r3, #288
+@@ -1611,7 +1574,7 @@
+ 	vld1.8		{d6-d7}, [r7, : 128]!
+ 	vld1.8		{d9}, [r7, : 64]
+ 	vld1.8		{d10-d11}, [r6, : 128]!
+-	add		r7, sp, #416
++	add		r7, sp, #384
+ 	vld1.8		{d12-d13}, [r6, : 128]!
+ 	vmul.i32	q7, q2, q0
+ 	vld1.8		{d8}, [r6, : 64]
+@@ -1726,7 +1689,7 @@
+ 	vext.32		d10, d6, d6, #0
+ 	vmov.i32	q1, #0xffffffff
+ 	vshl.i64	q4, q1, #25
+-	add		r7, sp, #512
++	add		r7, sp, #480
+ 	vld1.8		{d14-d15}, [r7, : 128]
+ 	vadd.i64	q9, q2, q7
+ 	vshl.i64	q1, q1, #26
+@@ -1735,7 +1698,7 @@
+ 	vadd.i64	q5, q5, q10
+ 	vand		q9, q9, q1
+ 	vld1.8		{d16}, [r6, : 64]!
+-	add		r6, sp, #528
++	add		r6, sp, #496
+ 	vld1.8		{d20-d21}, [r6, : 128]
+ 	vadd.i64	q11, q5, q10
+ 	vsub.i64	q2, q2, q9
+@@ -1789,8 +1752,8 @@
+ 	sub		r6, r6, #32
+ 	vst1.8		d4, [r6, : 64]
+ 	subs		r5, r5, #1
+-	bhi		._squaringloop
+-._skipsquaringloop:
++	bhi		.Lsquaringloop
++.Lskipsquaringloop:
+ 	mov		r2, r2
+ 	add		r5, r3, #288
+ 	add		r6, r3, #144
+@@ -1802,7 +1765,7 @@
+ 	vld1.8		{d6-d7}, [r5, : 128]!
+ 	vld1.8		{d9}, [r5, : 64]
+ 	vld1.8		{d10-d11}, [r2, : 128]!
+-	add		r5, sp, #416
++	add		r5, sp, #384
+ 	vld1.8		{d12-d13}, [r2, : 128]!
+ 	vmul.i32	q7, q2, q0
+ 	vld1.8		{d8}, [r2, : 64]
+@@ -1917,7 +1880,7 @@
+ 	vext.32		d10, d6, d6, #0
+ 	vmov.i32	q1, #0xffffffff
+ 	vshl.i64	q4, q1, #25
+-	add		r5, sp, #512
++	add		r5, sp, #480
+ 	vld1.8		{d14-d15}, [r5, : 128]
+ 	vadd.i64	q9, q2, q7
+ 	vshl.i64	q1, q1, #26
+@@ -1926,7 +1889,7 @@
+ 	vadd.i64	q5, q5, q10
+ 	vand		q9, q9, q1
+ 	vld1.8		{d16}, [r2, : 64]!
+-	add		r2, sp, #528
++	add		r2, sp, #496
+ 	vld1.8		{d20-d21}, [r2, : 128]
+ 	vadd.i64	q11, q5, q10
+ 	vsub.i64	q2, q2, q9
+@@ -1980,7 +1943,7 @@
+ 	sub		r2, r2, #32
+ 	vst1.8		d4, [r2, : 64]
+ 	cmp		r4, #0
+-	beq		._skippostcopy
++	beq		.Lskippostcopy
+ 	add		r2, r3, #144
+ 	mov		r4, r4
+ 	vld1.8		{d0-d1}, [r2, : 128]!
+@@ -1989,9 +1952,9 @@
+ 	vst1.8		{d0-d1}, [r4, : 128]!
+ 	vst1.8		{d2-d3}, [r4, : 128]!
+ 	vst1.8		d4, [r4, : 64]
+-._skippostcopy:
++.Lskippostcopy:
+ 	cmp		r1, #1
+-	bne		._skipfinalcopy
++	bne		.Lskipfinalcopy
+ 	add		r2, r3, #288
+ 	add		r4, r3, #144
+ 	vld1.8		{d0-d1}, [r2, : 128]!
+@@ -2000,10 +1963,10 @@
+ 	vst1.8		{d0-d1}, [r4, : 128]!
+ 	vst1.8		{d2-d3}, [r4, : 128]!
+ 	vst1.8		d4, [r4, : 64]
+-._skipfinalcopy:
++.Lskipfinalcopy:
+ 	add		r1, r1, #1
+ 	cmp		r1, #12
+-	blo		._invertloop
++	blo		.Linvertloop
+ 	add		r1, r3, #144
+ 	ldr		r2, [r1], #4
+ 	ldr		r3, [r1], #4
+@@ -2085,21 +2048,15 @@
+ 	add		r8, r8, r10, LSL #12
+ 	mov		r9, r10, LSR #20
+ 	add		r1, r9, r1, LSL #6
+-	str		r2, [r0], #4
+-	str		r3, [r0], #4
+-	str		r4, [r0], #4
+-	str		r5, [r0], #4
+-	str		r6, [r0], #4
+-	str		r7, [r0], #4
+-	str		r8, [r0], #4
+-	str		r1, [r0]
+-	ldrd		r4, [sp, #0]
+-	ldrd		r6, [sp, #8]
+-	ldrd		r8, [sp, #16]
+-	ldrd		r10, [sp, #24]
+-	ldr		r12, [sp, #480]
+-	ldr		r14, [sp, #484]
+-	ldr		r0, =0
+-	mov		sp, r12
+-	vpop		{q4, q5, q6, q7}
+-	bx		lr
++	str		r2, [r0]
++	str		r3, [r0, #4]
++	str		r4, [r0, #8]
++	str		r5, [r0, #12]
++	str		r6, [r0, #16]
++	str		r7, [r0, #20]
++	str		r8, [r0, #24]
++	str		r1, [r0, #28]
++	movw		r0, #0
++	mov		sp, ip
++	pop		{r4-r11, pc}
++ENDPROC(curve25519_neon)
+--- /dev/null
++++ b/arch/arm/crypto/curve25519-glue.c
+@@ -0,0 +1,127 @@
++// SPDX-License-Identifier: GPL-2.0 OR MIT
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ *
++ * Based on public domain code from Daniel J. Bernstein and Peter Schwabe. This
++ * began from SUPERCOP's curve25519/neon2/scalarmult.s, but has subsequently been
++ * manually reworked for use in kernel space.
++ */
++
++#include <asm/hwcap.h>
++#include <asm/neon.h>
++#include <asm/simd.h>
++#include <crypto/internal/kpp.h>
++#include <crypto/internal/simd.h>
++#include <linux/types.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/jump_label.h>
++#include <crypto/curve25519.h>
++
++asmlinkage void curve25519_neon(u8 mypublic[CURVE25519_KEY_SIZE],
++				const u8 secret[CURVE25519_KEY_SIZE],
++				const u8 basepoint[CURVE25519_KEY_SIZE]);
++
++static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon);
++
++void curve25519_arch(u8 out[CURVE25519_KEY_SIZE],
++		     const u8 scalar[CURVE25519_KEY_SIZE],
++		     const u8 point[CURVE25519_KEY_SIZE])
++{
++	if (static_branch_likely(&have_neon) && crypto_simd_usable()) {
++		kernel_neon_begin();
++		curve25519_neon(out, scalar, point);
++		kernel_neon_end();
++	} else {
++		curve25519_generic(out, scalar, point);
++	}
++}
++EXPORT_SYMBOL(curve25519_arch);
++
++static int curve25519_set_secret(struct crypto_kpp *tfm, const void *buf,
++				 unsigned int len)
++{
++	u8 *secret = kpp_tfm_ctx(tfm);
++
++	if (!len)
++		curve25519_generate_secret(secret);
++	else if (len == CURVE25519_KEY_SIZE &&
++		 crypto_memneq(buf, curve25519_null_point, CURVE25519_KEY_SIZE))
++		memcpy(secret, buf, CURVE25519_KEY_SIZE);
++	else
++		return -EINVAL;
++	return 0;
++}
++
++static int curve25519_compute_value(struct kpp_request *req)
++{
++	struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
++	const u8 *secret = kpp_tfm_ctx(tfm);
++	u8 public_key[CURVE25519_KEY_SIZE];
++	u8 buf[CURVE25519_KEY_SIZE];
++	int copied, nbytes;
++	u8 const *bp;
++
++	if (req->src) {
++		copied = sg_copy_to_buffer(req->src,
++					   sg_nents_for_len(req->src,
++							    CURVE25519_KEY_SIZE),
++					   public_key, CURVE25519_KEY_SIZE);
++		if (copied != CURVE25519_KEY_SIZE)
++			return -EINVAL;
++		bp = public_key;
++	} else {
++		bp = curve25519_base_point;
++	}
++
++	curve25519_arch(buf, secret, bp);
++
++	/* might want less than we've got */
++	nbytes = min_t(size_t, CURVE25519_KEY_SIZE, req->dst_len);
++	copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst,
++								nbytes),
++				     buf, nbytes);
++	if (copied != nbytes)
++		return -EINVAL;
++	return 0;
++}
++
++static unsigned int curve25519_max_size(struct crypto_kpp *tfm)
++{
++	return CURVE25519_KEY_SIZE;
++}
++
++static struct kpp_alg curve25519_alg = {
++	.base.cra_name		= "curve25519",
++	.base.cra_driver_name	= "curve25519-neon",
++	.base.cra_priority	= 200,
++	.base.cra_module	= THIS_MODULE,
++	.base.cra_ctxsize	= CURVE25519_KEY_SIZE,
++
++	.set_secret		= curve25519_set_secret,
++	.generate_public_key	= curve25519_compute_value,
++	.compute_shared_secret	= curve25519_compute_value,
++	.max_size		= curve25519_max_size,
++};
++
++static int __init mod_init(void)
++{
++	if (elf_hwcap & HWCAP_NEON) {
++		static_branch_enable(&have_neon);
++		return crypto_register_kpp(&curve25519_alg);
++	}
++	return 0;
++}
++
++static void __exit mod_exit(void)
++{
++	if (elf_hwcap & HWCAP_NEON)
++		crypto_unregister_kpp(&curve25519_alg);
++}
++
++module_init(mod_init);
++module_exit(mod_exit);
++
++MODULE_ALIAS_CRYPTO("curve25519");
++MODULE_ALIAS_CRYPTO("curve25519-neon");
++MODULE_LICENSE("GPL v2");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0032-crypto-chacha20poly1305-import-construction-and-self.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0032-crypto-chacha20poly1305-import-construction-and-self.patch
new file mode 100644
index 0000000..2d5601d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0032-crypto-chacha20poly1305-import-construction-and-self.patch
@@ -0,0 +1,7677 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:39 +0100
+Subject: [PATCH] crypto: chacha20poly1305 - import construction and selftest
+ from Zinc
+
+commit ed20078b7e3331e82828be357147af6a3282e4ce upstream.
+
+This incorporates the chacha20poly1305 from the Zinc library, retaining
+the library interface, but replacing the implementation with calls into
+the code that already existed in the kernel's crypto API.
+
+Note that this library API does not implement RFC7539 fully, given that
+it is limited to 64-bit nonces. (The 96-bit nonce version that was part
+of the selftest only has been removed, along with the 96-bit nonce test
+vectors that only tested the selftest but not the actual library itself)
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ include/crypto/chacha20poly1305.h      |   37 +
+ lib/crypto/Kconfig                     |    7 +
+ lib/crypto/Makefile                    |    4 +
+ lib/crypto/chacha20poly1305-selftest.c | 7348 ++++++++++++++++++++++++
+ lib/crypto/chacha20poly1305.c          |  219 +
+ 5 files changed, 7615 insertions(+)
+ create mode 100644 include/crypto/chacha20poly1305.h
+ create mode 100644 lib/crypto/chacha20poly1305-selftest.c
+ create mode 100644 lib/crypto/chacha20poly1305.c
+
+--- /dev/null
++++ b/include/crypto/chacha20poly1305.h
+@@ -0,0 +1,37 @@
++/* SPDX-License-Identifier: GPL-2.0 OR MIT */
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#ifndef __CHACHA20POLY1305_H
++#define __CHACHA20POLY1305_H
++
++#include <linux/types.h>
++
++enum chacha20poly1305_lengths {
++	XCHACHA20POLY1305_NONCE_SIZE = 24,
++	CHACHA20POLY1305_KEY_SIZE = 32,
++	CHACHA20POLY1305_AUTHTAG_SIZE = 16
++};
++
++void chacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len,
++			      const u8 *ad, const size_t ad_len,
++			      const u64 nonce,
++			      const u8 key[CHACHA20POLY1305_KEY_SIZE]);
++
++bool __must_check
++chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len,
++			 const u8 *ad, const size_t ad_len, const u64 nonce,
++			 const u8 key[CHACHA20POLY1305_KEY_SIZE]);
++
++void xchacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len,
++			       const u8 *ad, const size_t ad_len,
++			       const u8 nonce[XCHACHA20POLY1305_NONCE_SIZE],
++			       const u8 key[CHACHA20POLY1305_KEY_SIZE]);
++
++bool __must_check xchacha20poly1305_decrypt(
++	u8 *dst, const u8 *src, const size_t src_len, const u8 *ad,
++	const size_t ad_len, const u8 nonce[XCHACHA20POLY1305_NONCE_SIZE],
++	const u8 key[CHACHA20POLY1305_KEY_SIZE]);
++
++#endif /* __CHACHA20POLY1305_H */
+--- a/lib/crypto/Kconfig
++++ b/lib/crypto/Kconfig
+@@ -119,5 +119,12 @@ config CRYPTO_LIB_POLY1305
+ 	  by either the generic implementation or an arch-specific one, if one
+ 	  is available and enabled.
+ 
++config CRYPTO_LIB_CHACHA20POLY1305
++	tristate "ChaCha20-Poly1305 AEAD support (8-byte nonce library version)"
++	depends on CRYPTO_ARCH_HAVE_LIB_CHACHA || !CRYPTO_ARCH_HAVE_LIB_CHACHA
++	depends on CRYPTO_ARCH_HAVE_LIB_POLY1305 || !CRYPTO_ARCH_HAVE_LIB_POLY1305
++	select CRYPTO_LIB_CHACHA
++	select CRYPTO_LIB_POLY1305
++
+ config CRYPTO_LIB_SHA256
+ 	tristate
+--- a/lib/crypto/Makefile
++++ b/lib/crypto/Makefile
+@@ -16,6 +16,9 @@ libblake2s-generic-y				+= blake2s-gener
+ obj-$(CONFIG_CRYPTO_LIB_BLAKE2S)		+= libblake2s.o
+ libblake2s-y					+= blake2s.o
+ 
++obj-$(CONFIG_CRYPTO_LIB_CHACHA20POLY1305)	+= libchacha20poly1305.o
++libchacha20poly1305-y				+= chacha20poly1305.o
++
+ obj-$(CONFIG_CRYPTO_LIB_CURVE25519_GENERIC)	+= libcurve25519.o
+ libcurve25519-y					:= curve25519-fiat32.o
+ libcurve25519-$(CONFIG_ARCH_SUPPORTS_INT128)	:= curve25519-hacl64.o
+@@ -32,4 +35,5 @@ libsha256-y					:= sha256.o
+ 
+ ifneq ($(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS),y)
+ libblake2s-y					+= blake2s-selftest.o
++libchacha20poly1305-y				+= chacha20poly1305-selftest.o
+ endif
+--- /dev/null
++++ b/lib/crypto/chacha20poly1305-selftest.c
+@@ -0,0 +1,7348 @@
++// SPDX-License-Identifier: GPL-2.0 OR MIT
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#include <crypto/chacha20poly1305.h>
++#include <crypto/poly1305.h>
++
++#include <asm/unaligned.h>
++#include <linux/bug.h>
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++
++struct chacha20poly1305_testvec {
++	const u8 *input, *output, *assoc, *nonce, *key;
++	size_t ilen, alen, nlen;
++	bool failure;
++};
++
++/* The first of these are the ChaCha20-Poly1305 AEAD test vectors from RFC7539
++ * 2.8.2. After they are generated by reference implementations. And the final
++ * marked ones are taken from wycheproof, but we only do these for the encrypt
++ * side, because mostly we're stressing the primitives rather than the actual
++ * chapoly construction.
++ */
++
++static const u8 enc_input001[] __initconst = {
++	0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
++	0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x73, 0x20,
++	0x61, 0x72, 0x65, 0x20, 0x64, 0x72, 0x61, 0x66,
++	0x74, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65,
++	0x6e, 0x74, 0x73, 0x20, 0x76, 0x61, 0x6c, 0x69,
++	0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20,
++	0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20,
++	0x6f, 0x66, 0x20, 0x73, 0x69, 0x78, 0x20, 0x6d,
++	0x6f, 0x6e, 0x74, 0x68, 0x73, 0x20, 0x61, 0x6e,
++	0x64, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65,
++	0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64,
++	0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63,
++	0x65, 0x64, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x6f,
++	0x62, 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x64,
++	0x20, 0x62, 0x79, 0x20, 0x6f, 0x74, 0x68, 0x65,
++	0x72, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65,
++	0x6e, 0x74, 0x73, 0x20, 0x61, 0x74, 0x20, 0x61,
++	0x6e, 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x2e,
++	0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x69,
++	0x6e, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x70, 0x72,
++	0x69, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20,
++	0x75, 0x73, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65,
++	0x72, 0x6e, 0x65, 0x74, 0x2d, 0x44, 0x72, 0x61,
++	0x66, 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x72,
++	0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65,
++	0x20, 0x6d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61,
++	0x6c, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20,
++	0x63, 0x69, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65,
++	0x6d, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20,
++	0x74, 0x68, 0x61, 0x6e, 0x20, 0x61, 0x73, 0x20,
++	0x2f, 0xe2, 0x80, 0x9c, 0x77, 0x6f, 0x72, 0x6b,
++	0x20, 0x69, 0x6e, 0x20, 0x70, 0x72, 0x6f, 0x67,
++	0x72, 0x65, 0x73, 0x73, 0x2e, 0x2f, 0xe2, 0x80,
++	0x9d
++};
++static const u8 enc_output001[] __initconst = {
++	0x64, 0xa0, 0x86, 0x15, 0x75, 0x86, 0x1a, 0xf4,
++	0x60, 0xf0, 0x62, 0xc7, 0x9b, 0xe6, 0x43, 0xbd,
++	0x5e, 0x80, 0x5c, 0xfd, 0x34, 0x5c, 0xf3, 0x89,
++	0xf1, 0x08, 0x67, 0x0a, 0xc7, 0x6c, 0x8c, 0xb2,
++	0x4c, 0x6c, 0xfc, 0x18, 0x75, 0x5d, 0x43, 0xee,
++	0xa0, 0x9e, 0xe9, 0x4e, 0x38, 0x2d, 0x26, 0xb0,
++	0xbd, 0xb7, 0xb7, 0x3c, 0x32, 0x1b, 0x01, 0x00,
++	0xd4, 0xf0, 0x3b, 0x7f, 0x35, 0x58, 0x94, 0xcf,
++	0x33, 0x2f, 0x83, 0x0e, 0x71, 0x0b, 0x97, 0xce,
++	0x98, 0xc8, 0xa8, 0x4a, 0xbd, 0x0b, 0x94, 0x81,
++	0x14, 0xad, 0x17, 0x6e, 0x00, 0x8d, 0x33, 0xbd,
++	0x60, 0xf9, 0x82, 0xb1, 0xff, 0x37, 0xc8, 0x55,
++	0x97, 0x97, 0xa0, 0x6e, 0xf4, 0xf0, 0xef, 0x61,
++	0xc1, 0x86, 0x32, 0x4e, 0x2b, 0x35, 0x06, 0x38,
++	0x36, 0x06, 0x90, 0x7b, 0x6a, 0x7c, 0x02, 0xb0,
++	0xf9, 0xf6, 0x15, 0x7b, 0x53, 0xc8, 0x67, 0xe4,
++	0xb9, 0x16, 0x6c, 0x76, 0x7b, 0x80, 0x4d, 0x46,
++	0xa5, 0x9b, 0x52, 0x16, 0xcd, 0xe7, 0xa4, 0xe9,
++	0x90, 0x40, 0xc5, 0xa4, 0x04, 0x33, 0x22, 0x5e,
++	0xe2, 0x82, 0xa1, 0xb0, 0xa0, 0x6c, 0x52, 0x3e,
++	0xaf, 0x45, 0x34, 0xd7, 0xf8, 0x3f, 0xa1, 0x15,
++	0x5b, 0x00, 0x47, 0x71, 0x8c, 0xbc, 0x54, 0x6a,
++	0x0d, 0x07, 0x2b, 0x04, 0xb3, 0x56, 0x4e, 0xea,
++	0x1b, 0x42, 0x22, 0x73, 0xf5, 0x48, 0x27, 0x1a,
++	0x0b, 0xb2, 0x31, 0x60, 0x53, 0xfa, 0x76, 0x99,
++	0x19, 0x55, 0xeb, 0xd6, 0x31, 0x59, 0x43, 0x4e,
++	0xce, 0xbb, 0x4e, 0x46, 0x6d, 0xae, 0x5a, 0x10,
++	0x73, 0xa6, 0x72, 0x76, 0x27, 0x09, 0x7a, 0x10,
++	0x49, 0xe6, 0x17, 0xd9, 0x1d, 0x36, 0x10, 0x94,
++	0xfa, 0x68, 0xf0, 0xff, 0x77, 0x98, 0x71, 0x30,
++	0x30, 0x5b, 0xea, 0xba, 0x2e, 0xda, 0x04, 0xdf,
++	0x99, 0x7b, 0x71, 0x4d, 0x6c, 0x6f, 0x2c, 0x29,
++	0xa6, 0xad, 0x5c, 0xb4, 0x02, 0x2b, 0x02, 0x70,
++	0x9b, 0xee, 0xad, 0x9d, 0x67, 0x89, 0x0c, 0xbb,
++	0x22, 0x39, 0x23, 0x36, 0xfe, 0xa1, 0x85, 0x1f,
++	0x38
++};
++static const u8 enc_assoc001[] __initconst = {
++	0xf3, 0x33, 0x88, 0x86, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x4e, 0x91
++};
++static const u8 enc_nonce001[] __initconst = {
++	0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
++};
++static const u8 enc_key001[] __initconst = {
++	0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a,
++	0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0,
++	0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09,
++	0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0
++};
++
++static const u8 enc_input002[] __initconst = { };
++static const u8 enc_output002[] __initconst = {
++	0xea, 0xe0, 0x1e, 0x9e, 0x2c, 0x91, 0xaa, 0xe1,
++	0xdb, 0x5d, 0x99, 0x3f, 0x8a, 0xf7, 0x69, 0x92
++};
++static const u8 enc_assoc002[] __initconst = { };
++static const u8 enc_nonce002[] __initconst = {
++	0xca, 0xbf, 0x33, 0x71, 0x32, 0x45, 0x77, 0x8e
++};
++static const u8 enc_key002[] __initconst = {
++	0x4c, 0xf5, 0x96, 0x83, 0x38, 0xe6, 0xae, 0x7f,
++	0x2d, 0x29, 0x25, 0x76, 0xd5, 0x75, 0x27, 0x86,
++	0x91, 0x9a, 0x27, 0x7a, 0xfb, 0x46, 0xc5, 0xef,
++	0x94, 0x81, 0x79, 0x57, 0x14, 0x59, 0x40, 0x68
++};
++
++static const u8 enc_input003[] __initconst = { };
++static const u8 enc_output003[] __initconst = {
++	0xdd, 0x6b, 0x3b, 0x82, 0xce, 0x5a, 0xbd, 0xd6,
++	0xa9, 0x35, 0x83, 0xd8, 0x8c, 0x3d, 0x85, 0x77
++};
++static const u8 enc_assoc003[] __initconst = {
++	0x33, 0x10, 0x41, 0x12, 0x1f, 0xf3, 0xd2, 0x6b
++};
++static const u8 enc_nonce003[] __initconst = {
++	0x3d, 0x86, 0xb5, 0x6b, 0xc8, 0xa3, 0x1f, 0x1d
++};
++static const u8 enc_key003[] __initconst = {
++	0x2d, 0xb0, 0x5d, 0x40, 0xc8, 0xed, 0x44, 0x88,
++	0x34, 0xd1, 0x13, 0xaf, 0x57, 0xa1, 0xeb, 0x3a,
++	0x2a, 0x80, 0x51, 0x36, 0xec, 0x5b, 0xbc, 0x08,
++	0x93, 0x84, 0x21, 0xb5, 0x13, 0x88, 0x3c, 0x0d
++};
++
++static const u8 enc_input004[] __initconst = {
++	0xa4
++};
++static const u8 enc_output004[] __initconst = {
++	0xb7, 0x1b, 0xb0, 0x73, 0x59, 0xb0, 0x84, 0xb2,
++	0x6d, 0x8e, 0xab, 0x94, 0x31, 0xa1, 0xae, 0xac,
++	0x89
++};
++static const u8 enc_assoc004[] __initconst = {
++	0x6a, 0xe2, 0xad, 0x3f, 0x88, 0x39, 0x5a, 0x40
++};
++static const u8 enc_nonce004[] __initconst = {
++	0xd2, 0x32, 0x1f, 0x29, 0x28, 0xc6, 0xc4, 0xc4
++};
++static const u8 enc_key004[] __initconst = {
++	0x4b, 0x28, 0x4b, 0xa3, 0x7b, 0xbe, 0xe9, 0xf8,
++	0x31, 0x80, 0x82, 0xd7, 0xd8, 0xe8, 0xb5, 0xa1,
++	0xe2, 0x18, 0x18, 0x8a, 0x9c, 0xfa, 0xa3, 0x3d,
++	0x25, 0x71, 0x3e, 0x40, 0xbc, 0x54, 0x7a, 0x3e
++};
++
++static const u8 enc_input005[] __initconst = {
++	0x2d
++};
++static const u8 enc_output005[] __initconst = {
++	0xbf, 0xe1, 0x5b, 0x0b, 0xdb, 0x6b, 0xf5, 0x5e,
++	0x6c, 0x5d, 0x84, 0x44, 0x39, 0x81, 0xc1, 0x9c,
++	0xac
++};
++static const u8 enc_assoc005[] __initconst = { };
++static const u8 enc_nonce005[] __initconst = {
++	0x20, 0x1c, 0xaa, 0x5f, 0x9c, 0xbf, 0x92, 0x30
++};
++static const u8 enc_key005[] __initconst = {
++	0x66, 0xca, 0x9c, 0x23, 0x2a, 0x4b, 0x4b, 0x31,
++	0x0e, 0x92, 0x89, 0x8b, 0xf4, 0x93, 0xc7, 0x87,
++	0x98, 0xa3, 0xd8, 0x39, 0xf8, 0xf4, 0xa7, 0x01,
++	0xc0, 0x2e, 0x0a, 0xa6, 0x7e, 0x5a, 0x78, 0x87
++};
++
++static const u8 enc_input006[] __initconst = {
++	0x33, 0x2f, 0x94, 0xc1, 0xa4, 0xef, 0xcc, 0x2a,
++	0x5b, 0xa6, 0xe5, 0x8f, 0x1d, 0x40, 0xf0, 0x92,
++	0x3c, 0xd9, 0x24, 0x11, 0xa9, 0x71, 0xf9, 0x37,
++	0x14, 0x99, 0xfa, 0xbe, 0xe6, 0x80, 0xde, 0x50,
++	0xc9, 0x96, 0xd4, 0xb0, 0xec, 0x9e, 0x17, 0xec,
++	0xd2, 0x5e, 0x72, 0x99, 0xfc, 0x0a, 0xe1, 0xcb,
++	0x48, 0xd2, 0x85, 0xdd, 0x2f, 0x90, 0xe0, 0x66,
++	0x3b, 0xe6, 0x20, 0x74, 0xbe, 0x23, 0x8f, 0xcb,
++	0xb4, 0xe4, 0xda, 0x48, 0x40, 0xa6, 0xd1, 0x1b,
++	0xc7, 0x42, 0xce, 0x2f, 0x0c, 0xa6, 0x85, 0x6e,
++	0x87, 0x37, 0x03, 0xb1, 0x7c, 0x25, 0x96, 0xa3,
++	0x05, 0xd8, 0xb0, 0xf4, 0xed, 0xea, 0xc2, 0xf0,
++	0x31, 0x98, 0x6c, 0xd1, 0x14, 0x25, 0xc0, 0xcb,
++	0x01, 0x74, 0xd0, 0x82, 0xf4, 0x36, 0xf5, 0x41,
++	0xd5, 0xdc, 0xca, 0xc5, 0xbb, 0x98, 0xfe, 0xfc,
++	0x69, 0x21, 0x70, 0xd8, 0xa4, 0x4b, 0xc8, 0xde,
++	0x8f
++};
++static const u8 enc_output006[] __initconst = {
++	0x8b, 0x06, 0xd3, 0x31, 0xb0, 0x93, 0x45, 0xb1,
++	0x75, 0x6e, 0x26, 0xf9, 0x67, 0xbc, 0x90, 0x15,
++	0x81, 0x2c, 0xb5, 0xf0, 0xc6, 0x2b, 0xc7, 0x8c,
++	0x56, 0xd1, 0xbf, 0x69, 0x6c, 0x07, 0xa0, 0xda,
++	0x65, 0x27, 0xc9, 0x90, 0x3d, 0xef, 0x4b, 0x11,
++	0x0f, 0x19, 0x07, 0xfd, 0x29, 0x92, 0xd9, 0xc8,
++	0xf7, 0x99, 0x2e, 0x4a, 0xd0, 0xb8, 0x2c, 0xdc,
++	0x93, 0xf5, 0x9e, 0x33, 0x78, 0xd1, 0x37, 0xc3,
++	0x66, 0xd7, 0x5e, 0xbc, 0x44, 0xbf, 0x53, 0xa5,
++	0xbc, 0xc4, 0xcb, 0x7b, 0x3a, 0x8e, 0x7f, 0x02,
++	0xbd, 0xbb, 0xe7, 0xca, 0xa6, 0x6c, 0x6b, 0x93,
++	0x21, 0x93, 0x10, 0x61, 0xe7, 0x69, 0xd0, 0x78,
++	0xf3, 0x07, 0x5a, 0x1a, 0x8f, 0x73, 0xaa, 0xb1,
++	0x4e, 0xd3, 0xda, 0x4f, 0xf3, 0x32, 0xe1, 0x66,
++	0x3e, 0x6c, 0xc6, 0x13, 0xba, 0x06, 0x5b, 0xfc,
++	0x6a, 0xe5, 0x6f, 0x60, 0xfb, 0x07, 0x40, 0xb0,
++	0x8c, 0x9d, 0x84, 0x43, 0x6b, 0xc1, 0xf7, 0x8d,
++	0x8d, 0x31, 0xf7, 0x7a, 0x39, 0x4d, 0x8f, 0x9a,
++	0xeb
++};
++static const u8 enc_assoc006[] __initconst = {
++	0x70, 0xd3, 0x33, 0xf3, 0x8b, 0x18, 0x0b
++};
++static const u8 enc_nonce006[] __initconst = {
++	0xdf, 0x51, 0x84, 0x82, 0x42, 0x0c, 0x75, 0x9c
++};
++static const u8 enc_key006[] __initconst = {
++	0x68, 0x7b, 0x8d, 0x8e, 0xe3, 0xc4, 0xdd, 0xae,
++	0xdf, 0x72, 0x7f, 0x53, 0x72, 0x25, 0x1e, 0x78,
++	0x91, 0xcb, 0x69, 0x76, 0x1f, 0x49, 0x93, 0xf9,
++	0x6f, 0x21, 0xcc, 0x39, 0x9c, 0xad, 0xb1, 0x01
++};
++
++static const u8 enc_input007[] __initconst = {
++	0x9b, 0x18, 0xdb, 0xdd, 0x9a, 0x0f, 0x3e, 0xa5,
++	0x15, 0x17, 0xde, 0xdf, 0x08, 0x9d, 0x65, 0x0a,
++	0x67, 0x30, 0x12, 0xe2, 0x34, 0x77, 0x4b, 0xc1,
++	0xd9, 0xc6, 0x1f, 0xab, 0xc6, 0x18, 0x50, 0x17,
++	0xa7, 0x9d, 0x3c, 0xa6, 0xc5, 0x35, 0x8c, 0x1c,
++	0xc0, 0xa1, 0x7c, 0x9f, 0x03, 0x89, 0xca, 0xe1,
++	0xe6, 0xe9, 0xd4, 0xd3, 0x88, 0xdb, 0xb4, 0x51,
++	0x9d, 0xec, 0xb4, 0xfc, 0x52, 0xee, 0x6d, 0xf1,
++	0x75, 0x42, 0xc6, 0xfd, 0xbd, 0x7a, 0x8e, 0x86,
++	0xfc, 0x44, 0xb3, 0x4f, 0xf3, 0xea, 0x67, 0x5a,
++	0x41, 0x13, 0xba, 0xb0, 0xdc, 0xe1, 0xd3, 0x2a,
++	0x7c, 0x22, 0xb3, 0xca, 0xac, 0x6a, 0x37, 0x98,
++	0x3e, 0x1d, 0x40, 0x97, 0xf7, 0x9b, 0x1d, 0x36,
++	0x6b, 0xb3, 0x28, 0xbd, 0x60, 0x82, 0x47, 0x34,
++	0xaa, 0x2f, 0x7d, 0xe9, 0xa8, 0x70, 0x81, 0x57,
++	0xd4, 0xb9, 0x77, 0x0a, 0x9d, 0x29, 0xa7, 0x84,
++	0x52, 0x4f, 0xc2, 0x4a, 0x40, 0x3b, 0x3c, 0xd4,
++	0xc9, 0x2a, 0xdb, 0x4a, 0x53, 0xc4, 0xbe, 0x80,
++	0xe9, 0x51, 0x7f, 0x8f, 0xc7, 0xa2, 0xce, 0x82,
++	0x5c, 0x91, 0x1e, 0x74, 0xd9, 0xd0, 0xbd, 0xd5,
++	0xf3, 0xfd, 0xda, 0x4d, 0x25, 0xb4, 0xbb, 0x2d,
++	0xac, 0x2f, 0x3d, 0x71, 0x85, 0x7b, 0xcf, 0x3c,
++	0x7b, 0x3e, 0x0e, 0x22, 0x78, 0x0c, 0x29, 0xbf,
++	0xe4, 0xf4, 0x57, 0xb3, 0xcb, 0x49, 0xa0, 0xfc,
++	0x1e, 0x05, 0x4e, 0x16, 0xbc, 0xd5, 0xa8, 0xa3,
++	0xee, 0x05, 0x35, 0xc6, 0x7c, 0xab, 0x60, 0x14,
++	0x55, 0x1a, 0x8e, 0xc5, 0x88, 0x5d, 0xd5, 0x81,
++	0xc2, 0x81, 0xa5, 0xc4, 0x60, 0xdb, 0xaf, 0x77,
++	0x91, 0xe1, 0xce, 0xa2, 0x7e, 0x7f, 0x42, 0xe3,
++	0xb0, 0x13, 0x1c, 0x1f, 0x25, 0x60, 0x21, 0xe2,
++	0x40, 0x5f, 0x99, 0xb7, 0x73, 0xec, 0x9b, 0x2b,
++	0xf0, 0x65, 0x11, 0xc8, 0xd0, 0x0a, 0x9f, 0xd3
++};
++static const u8 enc_output007[] __initconst = {
++	0x85, 0x04, 0xc2, 0xed, 0x8d, 0xfd, 0x97, 0x5c,
++	0xd2, 0xb7, 0xe2, 0xc1, 0x6b, 0xa3, 0xba, 0xf8,
++	0xc9, 0x50, 0xc3, 0xc6, 0xa5, 0xe3, 0xa4, 0x7c,
++	0xc3, 0x23, 0x49, 0x5e, 0xa9, 0xb9, 0x32, 0xeb,
++	0x8a, 0x7c, 0xca, 0xe5, 0xec, 0xfb, 0x7c, 0xc0,
++	0xcb, 0x7d, 0xdc, 0x2c, 0x9d, 0x92, 0x55, 0x21,
++	0x0a, 0xc8, 0x43, 0x63, 0x59, 0x0a, 0x31, 0x70,
++	0x82, 0x67, 0x41, 0x03, 0xf8, 0xdf, 0xf2, 0xac,
++	0xa7, 0x02, 0xd4, 0xd5, 0x8a, 0x2d, 0xc8, 0x99,
++	0x19, 0x66, 0xd0, 0xf6, 0x88, 0x2c, 0x77, 0xd9,
++	0xd4, 0x0d, 0x6c, 0xbd, 0x98, 0xde, 0xe7, 0x7f,
++	0xad, 0x7e, 0x8a, 0xfb, 0xe9, 0x4b, 0xe5, 0xf7,
++	0xe5, 0x50, 0xa0, 0x90, 0x3f, 0xd6, 0x22, 0x53,
++	0xe3, 0xfe, 0x1b, 0xcc, 0x79, 0x3b, 0xec, 0x12,
++	0x47, 0x52, 0xa7, 0xd6, 0x04, 0xe3, 0x52, 0xe6,
++	0x93, 0x90, 0x91, 0x32, 0x73, 0x79, 0xb8, 0xd0,
++	0x31, 0xde, 0x1f, 0x9f, 0x2f, 0x05, 0x38, 0x54,
++	0x2f, 0x35, 0x04, 0x39, 0xe0, 0xa7, 0xba, 0xc6,
++	0x52, 0xf6, 0x37, 0x65, 0x4c, 0x07, 0xa9, 0x7e,
++	0xb3, 0x21, 0x6f, 0x74, 0x8c, 0xc9, 0xde, 0xdb,
++	0x65, 0x1b, 0x9b, 0xaa, 0x60, 0xb1, 0x03, 0x30,
++	0x6b, 0xb2, 0x03, 0xc4, 0x1c, 0x04, 0xf8, 0x0f,
++	0x64, 0xaf, 0x46, 0xe4, 0x65, 0x99, 0x49, 0xe2,
++	0xea, 0xce, 0x78, 0x00, 0xd8, 0x8b, 0xd5, 0x2e,
++	0xcf, 0xfc, 0x40, 0x49, 0xe8, 0x58, 0xdc, 0x34,
++	0x9c, 0x8c, 0x61, 0xbf, 0x0a, 0x8e, 0xec, 0x39,
++	0xa9, 0x30, 0x05, 0x5a, 0xd2, 0x56, 0x01, 0xc7,
++	0xda, 0x8f, 0x4e, 0xbb, 0x43, 0xa3, 0x3a, 0xf9,
++	0x15, 0x2a, 0xd0, 0xa0, 0x7a, 0x87, 0x34, 0x82,
++	0xfe, 0x8a, 0xd1, 0x2d, 0x5e, 0xc7, 0xbf, 0x04,
++	0x53, 0x5f, 0x3b, 0x36, 0xd4, 0x25, 0x5c, 0x34,
++	0x7a, 0x8d, 0xd5, 0x05, 0xce, 0x72, 0xca, 0xef,
++	0x7a, 0x4b, 0xbc, 0xb0, 0x10, 0x5c, 0x96, 0x42,
++	0x3a, 0x00, 0x98, 0xcd, 0x15, 0xe8, 0xb7, 0x53
++};
++static const u8 enc_assoc007[] __initconst = { };
++static const u8 enc_nonce007[] __initconst = {
++	0xde, 0x7b, 0xef, 0xc3, 0x65, 0x1b, 0x68, 0xb0
++};
++static const u8 enc_key007[] __initconst = {
++	0x8d, 0xb8, 0x91, 0x48, 0xf0, 0xe7, 0x0a, 0xbd,
++	0xf9, 0x3f, 0xcd, 0xd9, 0xa0, 0x1e, 0x42, 0x4c,
++	0xe7, 0xde, 0x25, 0x3d, 0xa3, 0xd7, 0x05, 0x80,
++	0x8d, 0xf2, 0x82, 0xac, 0x44, 0x16, 0x51, 0x01
++};
++
++static const u8 enc_input008[] __initconst = {
++	0xc3, 0x09, 0x94, 0x62, 0xe6, 0x46, 0x2e, 0x10,
++	0xbe, 0x00, 0xe4, 0xfc, 0xf3, 0x40, 0xa3, 0xe2,
++	0x0f, 0xc2, 0x8b, 0x28, 0xdc, 0xba, 0xb4, 0x3c,
++	0xe4, 0x21, 0x58, 0x61, 0xcd, 0x8b, 0xcd, 0xfb,
++	0xac, 0x94, 0xa1, 0x45, 0xf5, 0x1c, 0xe1, 0x12,
++	0xe0, 0x3b, 0x67, 0x21, 0x54, 0x5e, 0x8c, 0xaa,
++	0xcf, 0xdb, 0xb4, 0x51, 0xd4, 0x13, 0xda, 0xe6,
++	0x83, 0x89, 0xb6, 0x92, 0xe9, 0x21, 0x76, 0xa4,
++	0x93, 0x7d, 0x0e, 0xfd, 0x96, 0x36, 0x03, 0x91,
++	0x43, 0x5c, 0x92, 0x49, 0x62, 0x61, 0x7b, 0xeb,
++	0x43, 0x89, 0xb8, 0x12, 0x20, 0x43, 0xd4, 0x47,
++	0x06, 0x84, 0xee, 0x47, 0xe9, 0x8a, 0x73, 0x15,
++	0x0f, 0x72, 0xcf, 0xed, 0xce, 0x96, 0xb2, 0x7f,
++	0x21, 0x45, 0x76, 0xeb, 0x26, 0x28, 0x83, 0x6a,
++	0xad, 0xaa, 0xa6, 0x81, 0xd8, 0x55, 0xb1, 0xa3,
++	0x85, 0xb3, 0x0c, 0xdf, 0xf1, 0x69, 0x2d, 0x97,
++	0x05, 0x2a, 0xbc, 0x7c, 0x7b, 0x25, 0xf8, 0x80,
++	0x9d, 0x39, 0x25, 0xf3, 0x62, 0xf0, 0x66, 0x5e,
++	0xf4, 0xa0, 0xcf, 0xd8, 0xfd, 0x4f, 0xb1, 0x1f,
++	0x60, 0x3a, 0x08, 0x47, 0xaf, 0xe1, 0xf6, 0x10,
++	0x77, 0x09, 0xa7, 0x27, 0x8f, 0x9a, 0x97, 0x5a,
++	0x26, 0xfa, 0xfe, 0x41, 0x32, 0x83, 0x10, 0xe0,
++	0x1d, 0xbf, 0x64, 0x0d, 0xf4, 0x1c, 0x32, 0x35,
++	0xe5, 0x1b, 0x36, 0xef, 0xd4, 0x4a, 0x93, 0x4d,
++	0x00, 0x7c, 0xec, 0x02, 0x07, 0x8b, 0x5d, 0x7d,
++	0x1b, 0x0e, 0xd1, 0xa6, 0xa5, 0x5d, 0x7d, 0x57,
++	0x88, 0xa8, 0xcc, 0x81, 0xb4, 0x86, 0x4e, 0xb4,
++	0x40, 0xe9, 0x1d, 0xc3, 0xb1, 0x24, 0x3e, 0x7f,
++	0xcc, 0x8a, 0x24, 0x9b, 0xdf, 0x6d, 0xf0, 0x39,
++	0x69, 0x3e, 0x4c, 0xc0, 0x96, 0xe4, 0x13, 0xda,
++	0x90, 0xda, 0xf4, 0x95, 0x66, 0x8b, 0x17, 0x17,
++	0xfe, 0x39, 0x43, 0x25, 0xaa, 0xda, 0xa0, 0x43,
++	0x3c, 0xb1, 0x41, 0x02, 0xa3, 0xf0, 0xa7, 0x19,
++	0x59, 0xbc, 0x1d, 0x7d, 0x6c, 0x6d, 0x91, 0x09,
++	0x5c, 0xb7, 0x5b, 0x01, 0xd1, 0x6f, 0x17, 0x21,
++	0x97, 0xbf, 0x89, 0x71, 0xa5, 0xb0, 0x6e, 0x07,
++	0x45, 0xfd, 0x9d, 0xea, 0x07, 0xf6, 0x7a, 0x9f,
++	0x10, 0x18, 0x22, 0x30, 0x73, 0xac, 0xd4, 0x6b,
++	0x72, 0x44, 0xed, 0xd9, 0x19, 0x9b, 0x2d, 0x4a,
++	0x41, 0xdd, 0xd1, 0x85, 0x5e, 0x37, 0x19, 0xed,
++	0xd2, 0x15, 0x8f, 0x5e, 0x91, 0xdb, 0x33, 0xf2,
++	0xe4, 0xdb, 0xff, 0x98, 0xfb, 0xa3, 0xb5, 0xca,
++	0x21, 0x69, 0x08, 0xe7, 0x8a, 0xdf, 0x90, 0xff,
++	0x3e, 0xe9, 0x20, 0x86, 0x3c, 0xe9, 0xfc, 0x0b,
++	0xfe, 0x5c, 0x61, 0xaa, 0x13, 0x92, 0x7f, 0x7b,
++	0xec, 0xe0, 0x6d, 0xa8, 0x23, 0x22, 0xf6, 0x6b,
++	0x77, 0xc4, 0xfe, 0x40, 0x07, 0x3b, 0xb6, 0xf6,
++	0x8e, 0x5f, 0xd4, 0xb9, 0xb7, 0x0f, 0x21, 0x04,
++	0xef, 0x83, 0x63, 0x91, 0x69, 0x40, 0xa3, 0x48,
++	0x5c, 0xd2, 0x60, 0xf9, 0x4f, 0x6c, 0x47, 0x8b,
++	0x3b, 0xb1, 0x9f, 0x8e, 0xee, 0x16, 0x8a, 0x13,
++	0xfc, 0x46, 0x17, 0xc3, 0xc3, 0x32, 0x56, 0xf8,
++	0x3c, 0x85, 0x3a, 0xb6, 0x3e, 0xaa, 0x89, 0x4f,
++	0xb3, 0xdf, 0x38, 0xfd, 0xf1, 0xe4, 0x3a, 0xc0,
++	0xe6, 0x58, 0xb5, 0x8f, 0xc5, 0x29, 0xa2, 0x92,
++	0x4a, 0xb6, 0xa0, 0x34, 0x7f, 0xab, 0xb5, 0x8a,
++	0x90, 0xa1, 0xdb, 0x4d, 0xca, 0xb6, 0x2c, 0x41,
++	0x3c, 0xf7, 0x2b, 0x21, 0xc3, 0xfd, 0xf4, 0x17,
++	0x5c, 0xb5, 0x33, 0x17, 0x68, 0x2b, 0x08, 0x30,
++	0xf3, 0xf7, 0x30, 0x3c, 0x96, 0xe6, 0x6a, 0x20,
++	0x97, 0xe7, 0x4d, 0x10, 0x5f, 0x47, 0x5f, 0x49,
++	0x96, 0x09, 0xf0, 0x27, 0x91, 0xc8, 0xf8, 0x5a,
++	0x2e, 0x79, 0xb5, 0xe2, 0xb8, 0xe8, 0xb9, 0x7b,
++	0xd5, 0x10, 0xcb, 0xff, 0x5d, 0x14, 0x73, 0xf3
++};
++static const u8 enc_output008[] __initconst = {
++	0x14, 0xf6, 0x41, 0x37, 0xa6, 0xd4, 0x27, 0xcd,
++	0xdb, 0x06, 0x3e, 0x9a, 0x4e, 0xab, 0xd5, 0xb1,
++	0x1e, 0x6b, 0xd2, 0xbc, 0x11, 0xf4, 0x28, 0x93,
++	0x63, 0x54, 0xef, 0xbb, 0x5e, 0x1d, 0x3a, 0x1d,
++	0x37, 0x3c, 0x0a, 0x6c, 0x1e, 0xc2, 0xd1, 0x2c,
++	0xb5, 0xa3, 0xb5, 0x7b, 0xb8, 0x8f, 0x25, 0xa6,
++	0x1b, 0x61, 0x1c, 0xec, 0x28, 0x58, 0x26, 0xa4,
++	0xa8, 0x33, 0x28, 0x25, 0x5c, 0x45, 0x05, 0xe5,
++	0x6c, 0x99, 0xe5, 0x45, 0xc4, 0xa2, 0x03, 0x84,
++	0x03, 0x73, 0x1e, 0x8c, 0x49, 0xac, 0x20, 0xdd,
++	0x8d, 0xb3, 0xc4, 0xf5, 0xe7, 0x4f, 0xf1, 0xed,
++	0xa1, 0x98, 0xde, 0xa4, 0x96, 0xdd, 0x2f, 0xab,
++	0xab, 0x97, 0xcf, 0x3e, 0xd2, 0x9e, 0xb8, 0x13,
++	0x07, 0x28, 0x29, 0x19, 0xaf, 0xfd, 0xf2, 0x49,
++	0x43, 0xea, 0x49, 0x26, 0x91, 0xc1, 0x07, 0xd6,
++	0xbb, 0x81, 0x75, 0x35, 0x0d, 0x24, 0x7f, 0xc8,
++	0xda, 0xd4, 0xb7, 0xeb, 0xe8, 0x5c, 0x09, 0xa2,
++	0x2f, 0xdc, 0x28, 0x7d, 0x3a, 0x03, 0xfa, 0x94,
++	0xb5, 0x1d, 0x17, 0x99, 0x36, 0xc3, 0x1c, 0x18,
++	0x34, 0xe3, 0x9f, 0xf5, 0x55, 0x7c, 0xb0, 0x60,
++	0x9d, 0xff, 0xac, 0xd4, 0x61, 0xf2, 0xad, 0xf8,
++	0xce, 0xc7, 0xbe, 0x5c, 0xd2, 0x95, 0xa8, 0x4b,
++	0x77, 0x13, 0x19, 0x59, 0x26, 0xc9, 0xb7, 0x8f,
++	0x6a, 0xcb, 0x2d, 0x37, 0x91, 0xea, 0x92, 0x9c,
++	0x94, 0x5b, 0xda, 0x0b, 0xce, 0xfe, 0x30, 0x20,
++	0xf8, 0x51, 0xad, 0xf2, 0xbe, 0xe7, 0xc7, 0xff,
++	0xb3, 0x33, 0x91, 0x6a, 0xc9, 0x1a, 0x41, 0xc9,
++	0x0f, 0xf3, 0x10, 0x0e, 0xfd, 0x53, 0xff, 0x6c,
++	0x16, 0x52, 0xd9, 0xf3, 0xf7, 0x98, 0x2e, 0xc9,
++	0x07, 0x31, 0x2c, 0x0c, 0x72, 0xd7, 0xc5, 0xc6,
++	0x08, 0x2a, 0x7b, 0xda, 0xbd, 0x7e, 0x02, 0xea,
++	0x1a, 0xbb, 0xf2, 0x04, 0x27, 0x61, 0x28, 0x8e,
++	0xf5, 0x04, 0x03, 0x1f, 0x4c, 0x07, 0x55, 0x82,
++	0xec, 0x1e, 0xd7, 0x8b, 0x2f, 0x65, 0x56, 0xd1,
++	0xd9, 0x1e, 0x3c, 0xe9, 0x1f, 0x5e, 0x98, 0x70,
++	0x38, 0x4a, 0x8c, 0x49, 0xc5, 0x43, 0xa0, 0xa1,
++	0x8b, 0x74, 0x9d, 0x4c, 0x62, 0x0d, 0x10, 0x0c,
++	0xf4, 0x6c, 0x8f, 0xe0, 0xaa, 0x9a, 0x8d, 0xb7,
++	0xe0, 0xbe, 0x4c, 0x87, 0xf1, 0x98, 0x2f, 0xcc,
++	0xed, 0xc0, 0x52, 0x29, 0xdc, 0x83, 0xf8, 0xfc,
++	0x2c, 0x0e, 0xa8, 0x51, 0x4d, 0x80, 0x0d, 0xa3,
++	0xfe, 0xd8, 0x37, 0xe7, 0x41, 0x24, 0xfc, 0xfb,
++	0x75, 0xe3, 0x71, 0x7b, 0x57, 0x45, 0xf5, 0x97,
++	0x73, 0x65, 0x63, 0x14, 0x74, 0xb8, 0x82, 0x9f,
++	0xf8, 0x60, 0x2f, 0x8a, 0xf2, 0x4e, 0xf1, 0x39,
++	0xda, 0x33, 0x91, 0xf8, 0x36, 0xe0, 0x8d, 0x3f,
++	0x1f, 0x3b, 0x56, 0xdc, 0xa0, 0x8f, 0x3c, 0x9d,
++	0x71, 0x52, 0xa7, 0xb8, 0xc0, 0xa5, 0xc6, 0xa2,
++	0x73, 0xda, 0xf4, 0x4b, 0x74, 0x5b, 0x00, 0x3d,
++	0x99, 0xd7, 0x96, 0xba, 0xe6, 0xe1, 0xa6, 0x96,
++	0x38, 0xad, 0xb3, 0xc0, 0xd2, 0xba, 0x91, 0x6b,
++	0xf9, 0x19, 0xdd, 0x3b, 0xbe, 0xbe, 0x9c, 0x20,
++	0x50, 0xba, 0xa1, 0xd0, 0xce, 0x11, 0xbd, 0x95,
++	0xd8, 0xd1, 0xdd, 0x33, 0x85, 0x74, 0xdc, 0xdb,
++	0x66, 0x76, 0x44, 0xdc, 0x03, 0x74, 0x48, 0x35,
++	0x98, 0xb1, 0x18, 0x47, 0x94, 0x7d, 0xff, 0x62,
++	0xe4, 0x58, 0x78, 0xab, 0xed, 0x95, 0x36, 0xd9,
++	0x84, 0x91, 0x82, 0x64, 0x41, 0xbb, 0x58, 0xe6,
++	0x1c, 0x20, 0x6d, 0x15, 0x6b, 0x13, 0x96, 0xe8,
++	0x35, 0x7f, 0xdc, 0x40, 0x2c, 0xe9, 0xbc, 0x8a,
++	0x4f, 0x92, 0xec, 0x06, 0x2d, 0x50, 0xdf, 0x93,
++	0x5d, 0x65, 0x5a, 0xa8, 0xfc, 0x20, 0x50, 0x14,
++	0xa9, 0x8a, 0x7e, 0x1d, 0x08, 0x1f, 0xe2, 0x99,
++	0xd0, 0xbe, 0xfb, 0x3a, 0x21, 0x9d, 0xad, 0x86,
++	0x54, 0xfd, 0x0d, 0x98, 0x1c, 0x5a, 0x6f, 0x1f,
++	0x9a, 0x40, 0xcd, 0xa2, 0xff, 0x6a, 0xf1, 0x54
++};
++static const u8 enc_assoc008[] __initconst = { };
++static const u8 enc_nonce008[] __initconst = {
++	0x0e, 0x0d, 0x57, 0xbb, 0x7b, 0x40, 0x54, 0x02
++};
++static const u8 enc_key008[] __initconst = {
++	0xf2, 0xaa, 0x4f, 0x99, 0xfd, 0x3e, 0xa8, 0x53,
++	0xc1, 0x44, 0xe9, 0x81, 0x18, 0xdc, 0xf5, 0xf0,
++	0x3e, 0x44, 0x15, 0x59, 0xe0, 0xc5, 0x44, 0x86,
++	0xc3, 0x91, 0xa8, 0x75, 0xc0, 0x12, 0x46, 0xba
++};
++
++static const u8 enc_input009[] __initconst = {
++	0xe6, 0xc3, 0xdb, 0x63, 0x55, 0x15, 0xe3, 0x5b,
++	0xb7, 0x4b, 0x27, 0x8b, 0x5a, 0xdd, 0xc2, 0xe8,
++	0x3a, 0x6b, 0xd7, 0x81, 0x96, 0x35, 0x97, 0xca,
++	0xd7, 0x68, 0xe8, 0xef, 0xce, 0xab, 0xda, 0x09,
++	0x6e, 0xd6, 0x8e, 0xcb, 0x55, 0xb5, 0xe1, 0xe5,
++	0x57, 0xfd, 0xc4, 0xe3, 0xe0, 0x18, 0x4f, 0x85,
++	0xf5, 0x3f, 0x7e, 0x4b, 0x88, 0xc9, 0x52, 0x44,
++	0x0f, 0xea, 0xaf, 0x1f, 0x71, 0x48, 0x9f, 0x97,
++	0x6d, 0xb9, 0x6f, 0x00, 0xa6, 0xde, 0x2b, 0x77,
++	0x8b, 0x15, 0xad, 0x10, 0xa0, 0x2b, 0x7b, 0x41,
++	0x90, 0x03, 0x2d, 0x69, 0xae, 0xcc, 0x77, 0x7c,
++	0xa5, 0x9d, 0x29, 0x22, 0xc2, 0xea, 0xb4, 0x00,
++	0x1a, 0xd2, 0x7a, 0x98, 0x8a, 0xf9, 0xf7, 0x82,
++	0xb0, 0xab, 0xd8, 0xa6, 0x94, 0x8d, 0x58, 0x2f,
++	0x01, 0x9e, 0x00, 0x20, 0xfc, 0x49, 0xdc, 0x0e,
++	0x03, 0xe8, 0x45, 0x10, 0xd6, 0xa8, 0xda, 0x55,
++	0x10, 0x9a, 0xdf, 0x67, 0x22, 0x8b, 0x43, 0xab,
++	0x00, 0xbb, 0x02, 0xc8, 0xdd, 0x7b, 0x97, 0x17,
++	0xd7, 0x1d, 0x9e, 0x02, 0x5e, 0x48, 0xde, 0x8e,
++	0xcf, 0x99, 0x07, 0x95, 0x92, 0x3c, 0x5f, 0x9f,
++	0xc5, 0x8a, 0xc0, 0x23, 0xaa, 0xd5, 0x8c, 0x82,
++	0x6e, 0x16, 0x92, 0xb1, 0x12, 0x17, 0x07, 0xc3,
++	0xfb, 0x36, 0xf5, 0x6c, 0x35, 0xd6, 0x06, 0x1f,
++	0x9f, 0xa7, 0x94, 0xa2, 0x38, 0x63, 0x9c, 0xb0,
++	0x71, 0xb3, 0xa5, 0xd2, 0xd8, 0xba, 0x9f, 0x08,
++	0x01, 0xb3, 0xff, 0x04, 0x97, 0x73, 0x45, 0x1b,
++	0xd5, 0xa9, 0x9c, 0x80, 0xaf, 0x04, 0x9a, 0x85,
++	0xdb, 0x32, 0x5b, 0x5d, 0x1a, 0xc1, 0x36, 0x28,
++	0x10, 0x79, 0xf1, 0x3c, 0xbf, 0x1a, 0x41, 0x5c,
++	0x4e, 0xdf, 0xb2, 0x7c, 0x79, 0x3b, 0x7a, 0x62,
++	0x3d, 0x4b, 0xc9, 0x9b, 0x2a, 0x2e, 0x7c, 0xa2,
++	0xb1, 0x11, 0x98, 0xa7, 0x34, 0x1a, 0x00, 0xf3,
++	0xd1, 0xbc, 0x18, 0x22, 0xba, 0x02, 0x56, 0x62,
++	0x31, 0x10, 0x11, 0x6d, 0xe0, 0x54, 0x9d, 0x40,
++	0x1f, 0x26, 0x80, 0x41, 0xca, 0x3f, 0x68, 0x0f,
++	0x32, 0x1d, 0x0a, 0x8e, 0x79, 0xd8, 0xa4, 0x1b,
++	0x29, 0x1c, 0x90, 0x8e, 0xc5, 0xe3, 0xb4, 0x91,
++	0x37, 0x9a, 0x97, 0x86, 0x99, 0xd5, 0x09, 0xc5,
++	0xbb, 0xa3, 0x3f, 0x21, 0x29, 0x82, 0x14, 0x5c,
++	0xab, 0x25, 0xfb, 0xf2, 0x4f, 0x58, 0x26, 0xd4,
++	0x83, 0xaa, 0x66, 0x89, 0x67, 0x7e, 0xc0, 0x49,
++	0xe1, 0x11, 0x10, 0x7f, 0x7a, 0xda, 0x29, 0x04,
++	0xff, 0xf0, 0xcb, 0x09, 0x7c, 0x9d, 0xfa, 0x03,
++	0x6f, 0x81, 0x09, 0x31, 0x60, 0xfb, 0x08, 0xfa,
++	0x74, 0xd3, 0x64, 0x44, 0x7c, 0x55, 0x85, 0xec,
++	0x9c, 0x6e, 0x25, 0xb7, 0x6c, 0xc5, 0x37, 0xb6,
++	0x83, 0x87, 0x72, 0x95, 0x8b, 0x9d, 0xe1, 0x69,
++	0x5c, 0x31, 0x95, 0x42, 0xa6, 0x2c, 0xd1, 0x36,
++	0x47, 0x1f, 0xec, 0x54, 0xab, 0xa2, 0x1c, 0xd8,
++	0x00, 0xcc, 0xbc, 0x0d, 0x65, 0xe2, 0x67, 0xbf,
++	0xbc, 0xea, 0xee, 0x9e, 0xe4, 0x36, 0x95, 0xbe,
++	0x73, 0xd9, 0xa6, 0xd9, 0x0f, 0xa0, 0xcc, 0x82,
++	0x76, 0x26, 0xad, 0x5b, 0x58, 0x6c, 0x4e, 0xab,
++	0x29, 0x64, 0xd3, 0xd9, 0xa9, 0x08, 0x8c, 0x1d,
++	0xa1, 0x4f, 0x80, 0xd8, 0x3f, 0x94, 0xfb, 0xd3,
++	0x7b, 0xfc, 0xd1, 0x2b, 0xc3, 0x21, 0xeb, 0xe5,
++	0x1c, 0x84, 0x23, 0x7f, 0x4b, 0xfa, 0xdb, 0x34,
++	0x18, 0xa2, 0xc2, 0xe5, 0x13, 0xfe, 0x6c, 0x49,
++	0x81, 0xd2, 0x73, 0xe7, 0xe2, 0xd7, 0xe4, 0x4f,
++	0x4b, 0x08, 0x6e, 0xb1, 0x12, 0x22, 0x10, 0x9d,
++	0xac, 0x51, 0x1e, 0x17, 0xd9, 0x8a, 0x0b, 0x42,
++	0x88, 0x16, 0x81, 0x37, 0x7c, 0x6a, 0xf7, 0xef,
++	0x2d, 0xe3, 0xd9, 0xf8, 0x5f, 0xe0, 0x53, 0x27,
++	0x74, 0xb9, 0xe2, 0xd6, 0x1c, 0x80, 0x2c, 0x52,
++	0x65
++};
++static const u8 enc_output009[] __initconst = {
++	0xfd, 0x81, 0x8d, 0xd0, 0x3d, 0xb4, 0xd5, 0xdf,
++	0xd3, 0x42, 0x47, 0x5a, 0x6d, 0x19, 0x27, 0x66,
++	0x4b, 0x2e, 0x0c, 0x27, 0x9c, 0x96, 0x4c, 0x72,
++	0x02, 0xa3, 0x65, 0xc3, 0xb3, 0x6f, 0x2e, 0xbd,
++	0x63, 0x8a, 0x4a, 0x5d, 0x29, 0xa2, 0xd0, 0x28,
++	0x48, 0xc5, 0x3d, 0x98, 0xa3, 0xbc, 0xe0, 0xbe,
++	0x3b, 0x3f, 0xe6, 0x8a, 0xa4, 0x7f, 0x53, 0x06,
++	0xfa, 0x7f, 0x27, 0x76, 0x72, 0x31, 0xa1, 0xf5,
++	0xd6, 0x0c, 0x52, 0x47, 0xba, 0xcd, 0x4f, 0xd7,
++	0xeb, 0x05, 0x48, 0x0d, 0x7c, 0x35, 0x4a, 0x09,
++	0xc9, 0x76, 0x71, 0x02, 0xa3, 0xfb, 0xb7, 0x1a,
++	0x65, 0xb7, 0xed, 0x98, 0xc6, 0x30, 0x8a, 0x00,
++	0xae, 0xa1, 0x31, 0xe5, 0xb5, 0x9e, 0x6d, 0x62,
++	0xda, 0xda, 0x07, 0x0f, 0x38, 0x38, 0xd3, 0xcb,
++	0xc1, 0xb0, 0xad, 0xec, 0x72, 0xec, 0xb1, 0xa2,
++	0x7b, 0x59, 0xf3, 0x3d, 0x2b, 0xef, 0xcd, 0x28,
++	0x5b, 0x83, 0xcc, 0x18, 0x91, 0x88, 0xb0, 0x2e,
++	0xf9, 0x29, 0x31, 0x18, 0xf9, 0x4e, 0xe9, 0x0a,
++	0x91, 0x92, 0x9f, 0xae, 0x2d, 0xad, 0xf4, 0xe6,
++	0x1a, 0xe2, 0xa4, 0xee, 0x47, 0x15, 0xbf, 0x83,
++	0x6e, 0xd7, 0x72, 0x12, 0x3b, 0x2d, 0x24, 0xe9,
++	0xb2, 0x55, 0xcb, 0x3c, 0x10, 0xf0, 0x24, 0x8a,
++	0x4a, 0x02, 0xea, 0x90, 0x25, 0xf0, 0xb4, 0x79,
++	0x3a, 0xef, 0x6e, 0xf5, 0x52, 0xdf, 0xb0, 0x0a,
++	0xcd, 0x24, 0x1c, 0xd3, 0x2e, 0x22, 0x74, 0xea,
++	0x21, 0x6f, 0xe9, 0xbd, 0xc8, 0x3e, 0x36, 0x5b,
++	0x19, 0xf1, 0xca, 0x99, 0x0a, 0xb4, 0xa7, 0x52,
++	0x1a, 0x4e, 0xf2, 0xad, 0x8d, 0x56, 0x85, 0xbb,
++	0x64, 0x89, 0xba, 0x26, 0xf9, 0xc7, 0xe1, 0x89,
++	0x19, 0x22, 0x77, 0xc3, 0xa8, 0xfc, 0xff, 0xad,
++	0xfe, 0xb9, 0x48, 0xae, 0x12, 0x30, 0x9f, 0x19,
++	0xfb, 0x1b, 0xef, 0x14, 0x87, 0x8a, 0x78, 0x71,
++	0xf3, 0xf4, 0xb7, 0x00, 0x9c, 0x1d, 0xb5, 0x3d,
++	0x49, 0x00, 0x0c, 0x06, 0xd4, 0x50, 0xf9, 0x54,
++	0x45, 0xb2, 0x5b, 0x43, 0xdb, 0x6d, 0xcf, 0x1a,
++	0xe9, 0x7a, 0x7a, 0xcf, 0xfc, 0x8a, 0x4e, 0x4d,
++	0x0b, 0x07, 0x63, 0x28, 0xd8, 0xe7, 0x08, 0x95,
++	0xdf, 0xa6, 0x72, 0x93, 0x2e, 0xbb, 0xa0, 0x42,
++	0x89, 0x16, 0xf1, 0xd9, 0x0c, 0xf9, 0xa1, 0x16,
++	0xfd, 0xd9, 0x03, 0xb4, 0x3b, 0x8a, 0xf5, 0xf6,
++	0xe7, 0x6b, 0x2e, 0x8e, 0x4c, 0x3d, 0xe2, 0xaf,
++	0x08, 0x45, 0x03, 0xff, 0x09, 0xb6, 0xeb, 0x2d,
++	0xc6, 0x1b, 0x88, 0x94, 0xac, 0x3e, 0xf1, 0x9f,
++	0x0e, 0x0e, 0x2b, 0xd5, 0x00, 0x4d, 0x3f, 0x3b,
++	0x53, 0xae, 0xaf, 0x1c, 0x33, 0x5f, 0x55, 0x6e,
++	0x8d, 0xaf, 0x05, 0x7a, 0x10, 0x34, 0xc9, 0xf4,
++	0x66, 0xcb, 0x62, 0x12, 0xa6, 0xee, 0xe8, 0x1c,
++	0x5d, 0x12, 0x86, 0xdb, 0x6f, 0x1c, 0x33, 0xc4,
++	0x1c, 0xda, 0x82, 0x2d, 0x3b, 0x59, 0xfe, 0xb1,
++	0xa4, 0x59, 0x41, 0x86, 0xd0, 0xef, 0xae, 0xfb,
++	0xda, 0x6d, 0x11, 0xb8, 0xca, 0xe9, 0x6e, 0xff,
++	0xf7, 0xa9, 0xd9, 0x70, 0x30, 0xfc, 0x53, 0xe2,
++	0xd7, 0xa2, 0x4e, 0xc7, 0x91, 0xd9, 0x07, 0x06,
++	0xaa, 0xdd, 0xb0, 0x59, 0x28, 0x1d, 0x00, 0x66,
++	0xc5, 0x54, 0xc2, 0xfc, 0x06, 0xda, 0x05, 0x90,
++	0x52, 0x1d, 0x37, 0x66, 0xee, 0xf0, 0xb2, 0x55,
++	0x8a, 0x5d, 0xd2, 0x38, 0x86, 0x94, 0x9b, 0xfc,
++	0x10, 0x4c, 0xa1, 0xb9, 0x64, 0x3e, 0x44, 0xb8,
++	0x5f, 0xb0, 0x0c, 0xec, 0xe0, 0xc9, 0xe5, 0x62,
++	0x75, 0x3f, 0x09, 0xd5, 0xf5, 0xd9, 0x26, 0xba,
++	0x9e, 0xd2, 0xf4, 0xb9, 0x48, 0x0a, 0xbc, 0xa2,
++	0xd6, 0x7c, 0x36, 0x11, 0x7d, 0x26, 0x81, 0x89,
++	0xcf, 0xa4, 0xad, 0x73, 0x0e, 0xee, 0xcc, 0x06,
++	0xa9, 0xdb, 0xb1, 0xfd, 0xfb, 0x09, 0x7f, 0x90,
++	0x42, 0x37, 0x2f, 0xe1, 0x9c, 0x0f, 0x6f, 0xcf,
++	0x43, 0xb5, 0xd9, 0x90, 0xe1, 0x85, 0xf5, 0xa8,
++	0xae
++};
++static const u8 enc_assoc009[] __initconst = {
++	0x5a, 0x27, 0xff, 0xeb, 0xdf, 0x84, 0xb2, 0x9e,
++	0xef
++};
++static const u8 enc_nonce009[] __initconst = {
++	0xef, 0x2d, 0x63, 0xee, 0x6b, 0x80, 0x8b, 0x78
++};
++static const u8 enc_key009[] __initconst = {
++	0xea, 0xbc, 0x56, 0x99, 0xe3, 0x50, 0xff, 0xc5,
++	0xcc, 0x1a, 0xd7, 0xc1, 0x57, 0x72, 0xea, 0x86,
++	0x5b, 0x89, 0x88, 0x61, 0x3d, 0x2f, 0x9b, 0xb2,
++	0xe7, 0x9c, 0xec, 0x74, 0x6e, 0x3e, 0xf4, 0x3b
++};
++
++static const u8 enc_input010[] __initconst = {
++	0x42, 0x93, 0xe4, 0xeb, 0x97, 0xb0, 0x57, 0xbf,
++	0x1a, 0x8b, 0x1f, 0xe4, 0x5f, 0x36, 0x20, 0x3c,
++	0xef, 0x0a, 0xa9, 0x48, 0x5f, 0x5f, 0x37, 0x22,
++	0x3a, 0xde, 0xe3, 0xae, 0xbe, 0xad, 0x07, 0xcc,
++	0xb1, 0xf6, 0xf5, 0xf9, 0x56, 0xdd, 0xe7, 0x16,
++	0x1e, 0x7f, 0xdf, 0x7a, 0x9e, 0x75, 0xb7, 0xc7,
++	0xbe, 0xbe, 0x8a, 0x36, 0x04, 0xc0, 0x10, 0xf4,
++	0x95, 0x20, 0x03, 0xec, 0xdc, 0x05, 0xa1, 0x7d,
++	0xc4, 0xa9, 0x2c, 0x82, 0xd0, 0xbc, 0x8b, 0xc5,
++	0xc7, 0x45, 0x50, 0xf6, 0xa2, 0x1a, 0xb5, 0x46,
++	0x3b, 0x73, 0x02, 0xa6, 0x83, 0x4b, 0x73, 0x82,
++	0x58, 0x5e, 0x3b, 0x65, 0x2f, 0x0e, 0xfd, 0x2b,
++	0x59, 0x16, 0xce, 0xa1, 0x60, 0x9c, 0xe8, 0x3a,
++	0x99, 0xed, 0x8d, 0x5a, 0xcf, 0xf6, 0x83, 0xaf,
++	0xba, 0xd7, 0x73, 0x73, 0x40, 0x97, 0x3d, 0xca,
++	0xef, 0x07, 0x57, 0xe6, 0xd9, 0x70, 0x0e, 0x95,
++	0xae, 0xa6, 0x8d, 0x04, 0xcc, 0xee, 0xf7, 0x09,
++	0x31, 0x77, 0x12, 0xa3, 0x23, 0x97, 0x62, 0xb3,
++	0x7b, 0x32, 0xfb, 0x80, 0x14, 0x48, 0x81, 0xc3,
++	0xe5, 0xea, 0x91, 0x39, 0x52, 0x81, 0xa2, 0x4f,
++	0xe4, 0xb3, 0x09, 0xff, 0xde, 0x5e, 0xe9, 0x58,
++	0x84, 0x6e, 0xf9, 0x3d, 0xdf, 0x25, 0xea, 0xad,
++	0xae, 0xe6, 0x9a, 0xd1, 0x89, 0x55, 0xd3, 0xde,
++	0x6c, 0x52, 0xdb, 0x70, 0xfe, 0x37, 0xce, 0x44,
++	0x0a, 0xa8, 0x25, 0x5f, 0x92, 0xc1, 0x33, 0x4a,
++	0x4f, 0x9b, 0x62, 0x35, 0xff, 0xce, 0xc0, 0xa9,
++	0x60, 0xce, 0x52, 0x00, 0x97, 0x51, 0x35, 0x26,
++	0x2e, 0xb9, 0x36, 0xa9, 0x87, 0x6e, 0x1e, 0xcc,
++	0x91, 0x78, 0x53, 0x98, 0x86, 0x5b, 0x9c, 0x74,
++	0x7d, 0x88, 0x33, 0xe1, 0xdf, 0x37, 0x69, 0x2b,
++	0xbb, 0xf1, 0x4d, 0xf4, 0xd1, 0xf1, 0x39, 0x93,
++	0x17, 0x51, 0x19, 0xe3, 0x19, 0x1e, 0x76, 0x37,
++	0x25, 0xfb, 0x09, 0x27, 0x6a, 0xab, 0x67, 0x6f,
++	0x14, 0x12, 0x64, 0xe7, 0xc4, 0x07, 0xdf, 0x4d,
++	0x17, 0xbb, 0x6d, 0xe0, 0xe9, 0xb9, 0xab, 0xca,
++	0x10, 0x68, 0xaf, 0x7e, 0xb7, 0x33, 0x54, 0x73,
++	0x07, 0x6e, 0xf7, 0x81, 0x97, 0x9c, 0x05, 0x6f,
++	0x84, 0x5f, 0xd2, 0x42, 0xfb, 0x38, 0xcf, 0xd1,
++	0x2f, 0x14, 0x30, 0x88, 0x98, 0x4d, 0x5a, 0xa9,
++	0x76, 0xd5, 0x4f, 0x3e, 0x70, 0x6c, 0x85, 0x76,
++	0xd7, 0x01, 0xa0, 0x1a, 0xc8, 0x4e, 0xaa, 0xac,
++	0x78, 0xfe, 0x46, 0xde, 0x6a, 0x05, 0x46, 0xa7,
++	0x43, 0x0c, 0xb9, 0xde, 0xb9, 0x68, 0xfb, 0xce,
++	0x42, 0x99, 0x07, 0x4d, 0x0b, 0x3b, 0x5a, 0x30,
++	0x35, 0xa8, 0xf9, 0x3a, 0x73, 0xef, 0x0f, 0xdb,
++	0x1e, 0x16, 0x42, 0xc4, 0xba, 0xae, 0x58, 0xaa,
++	0xf8, 0xe5, 0x75, 0x2f, 0x1b, 0x15, 0x5c, 0xfd,
++	0x0a, 0x97, 0xd0, 0xe4, 0x37, 0x83, 0x61, 0x5f,
++	0x43, 0xa6, 0xc7, 0x3f, 0x38, 0x59, 0xe6, 0xeb,
++	0xa3, 0x90, 0xc3, 0xaa, 0xaa, 0x5a, 0xd3, 0x34,
++	0xd4, 0x17, 0xc8, 0x65, 0x3e, 0x57, 0xbc, 0x5e,
++	0xdd, 0x9e, 0xb7, 0xf0, 0x2e, 0x5b, 0xb2, 0x1f,
++	0x8a, 0x08, 0x0d, 0x45, 0x91, 0x0b, 0x29, 0x53,
++	0x4f, 0x4c, 0x5a, 0x73, 0x56, 0xfe, 0xaf, 0x41,
++	0x01, 0x39, 0x0a, 0x24, 0x3c, 0x7e, 0xbe, 0x4e,
++	0x53, 0xf3, 0xeb, 0x06, 0x66, 0x51, 0x28, 0x1d,
++	0xbd, 0x41, 0x0a, 0x01, 0xab, 0x16, 0x47, 0x27,
++	0x47, 0x47, 0xf7, 0xcb, 0x46, 0x0a, 0x70, 0x9e,
++	0x01, 0x9c, 0x09, 0xe1, 0x2a, 0x00, 0x1a, 0xd8,
++	0xd4, 0x79, 0x9d, 0x80, 0x15, 0x8e, 0x53, 0x2a,
++	0x65, 0x83, 0x78, 0x3e, 0x03, 0x00, 0x07, 0x12,
++	0x1f, 0x33, 0x3e, 0x7b, 0x13, 0x37, 0xf1, 0xc3,
++	0xef, 0xb7, 0xc1, 0x20, 0x3c, 0x3e, 0x67, 0x66,
++	0x5d, 0x88, 0xa7, 0x7d, 0x33, 0x50, 0x77, 0xb0,
++	0x28, 0x8e, 0xe7, 0x2c, 0x2e, 0x7a, 0xf4, 0x3c,
++	0x8d, 0x74, 0x83, 0xaf, 0x8e, 0x87, 0x0f, 0xe4,
++	0x50, 0xff, 0x84, 0x5c, 0x47, 0x0c, 0x6a, 0x49,
++	0xbf, 0x42, 0x86, 0x77, 0x15, 0x48, 0xa5, 0x90,
++	0x5d, 0x93, 0xd6, 0x2a, 0x11, 0xd5, 0xd5, 0x11,
++	0xaa, 0xce, 0xe7, 0x6f, 0xa5, 0xb0, 0x09, 0x2c,
++	0x8d, 0xd3, 0x92, 0xf0, 0x5a, 0x2a, 0xda, 0x5b,
++	0x1e, 0xd5, 0x9a, 0xc4, 0xc4, 0xf3, 0x49, 0x74,
++	0x41, 0xca, 0xe8, 0xc1, 0xf8, 0x44, 0xd6, 0x3c,
++	0xae, 0x6c, 0x1d, 0x9a, 0x30, 0x04, 0x4d, 0x27,
++	0x0e, 0xb1, 0x5f, 0x59, 0xa2, 0x24, 0xe8, 0xe1,
++	0x98, 0xc5, 0x6a, 0x4c, 0xfe, 0x41, 0xd2, 0x27,
++	0x42, 0x52, 0xe1, 0xe9, 0x7d, 0x62, 0xe4, 0x88,
++	0x0f, 0xad, 0xb2, 0x70, 0xcb, 0x9d, 0x4c, 0x27,
++	0x2e, 0x76, 0x1e, 0x1a, 0x63, 0x65, 0xf5, 0x3b,
++	0xf8, 0x57, 0x69, 0xeb, 0x5b, 0x38, 0x26, 0x39,
++	0x33, 0x25, 0x45, 0x3e, 0x91, 0xb8, 0xd8, 0xc7,
++	0xd5, 0x42, 0xc0, 0x22, 0x31, 0x74, 0xf4, 0xbc,
++	0x0c, 0x23, 0xf1, 0xca, 0xc1, 0x8d, 0xd7, 0xbe,
++	0xc9, 0x62, 0xe4, 0x08, 0x1a, 0xcf, 0x36, 0xd5,
++	0xfe, 0x55, 0x21, 0x59, 0x91, 0x87, 0x87, 0xdf,
++	0x06, 0xdb, 0xdf, 0x96, 0x45, 0x58, 0xda, 0x05,
++	0xcd, 0x50, 0x4d, 0xd2, 0x7d, 0x05, 0x18, 0x73,
++	0x6a, 0x8d, 0x11, 0x85, 0xa6, 0x88, 0xe8, 0xda,
++	0xe6, 0x30, 0x33, 0xa4, 0x89, 0x31, 0x75, 0xbe,
++	0x69, 0x43, 0x84, 0x43, 0x50, 0x87, 0xdd, 0x71,
++	0x36, 0x83, 0xc3, 0x78, 0x74, 0x24, 0x0a, 0xed,
++	0x7b, 0xdb, 0xa4, 0x24, 0x0b, 0xb9, 0x7e, 0x5d,
++	0xff, 0xde, 0xb1, 0xef, 0x61, 0x5a, 0x45, 0x33,
++	0xf6, 0x17, 0x07, 0x08, 0x98, 0x83, 0x92, 0x0f,
++	0x23, 0x6d, 0xe6, 0xaa, 0x17, 0x54, 0xad, 0x6a,
++	0xc8, 0xdb, 0x26, 0xbe, 0xb8, 0xb6, 0x08, 0xfa,
++	0x68, 0xf1, 0xd7, 0x79, 0x6f, 0x18, 0xb4, 0x9e,
++	0x2d, 0x3f, 0x1b, 0x64, 0xaf, 0x8d, 0x06, 0x0e,
++	0x49, 0x28, 0xe0, 0x5d, 0x45, 0x68, 0x13, 0x87,
++	0xfa, 0xde, 0x40, 0x7b, 0xd2, 0xc3, 0x94, 0xd5,
++	0xe1, 0xd9, 0xc2, 0xaf, 0x55, 0x89, 0xeb, 0xb4,
++	0x12, 0x59, 0xa8, 0xd4, 0xc5, 0x29, 0x66, 0x38,
++	0xe6, 0xac, 0x22, 0x22, 0xd9, 0x64, 0x9b, 0x34,
++	0x0a, 0x32, 0x9f, 0xc2, 0xbf, 0x17, 0x6c, 0x3f,
++	0x71, 0x7a, 0x38, 0x6b, 0x98, 0xfb, 0x49, 0x36,
++	0x89, 0xc9, 0xe2, 0xd6, 0xc7, 0x5d, 0xd0, 0x69,
++	0x5f, 0x23, 0x35, 0xc9, 0x30, 0xe2, 0xfd, 0x44,
++	0x58, 0x39, 0xd7, 0x97, 0xfb, 0x5c, 0x00, 0xd5,
++	0x4f, 0x7a, 0x1a, 0x95, 0x8b, 0x62, 0x4b, 0xce,
++	0xe5, 0x91, 0x21, 0x7b, 0x30, 0x00, 0xd6, 0xdd,
++	0x6d, 0x02, 0x86, 0x49, 0x0f, 0x3c, 0x1a, 0x27,
++	0x3c, 0xd3, 0x0e, 0x71, 0xf2, 0xff, 0xf5, 0x2f,
++	0x87, 0xac, 0x67, 0x59, 0x81, 0xa3, 0xf7, 0xf8,
++	0xd6, 0x11, 0x0c, 0x84, 0xa9, 0x03, 0xee, 0x2a,
++	0xc4, 0xf3, 0x22, 0xab, 0x7c, 0xe2, 0x25, 0xf5,
++	0x67, 0xa3, 0xe4, 0x11, 0xe0, 0x59, 0xb3, 0xca,
++	0x87, 0xa0, 0xae, 0xc9, 0xa6, 0x62, 0x1b, 0x6e,
++	0x4d, 0x02, 0x6b, 0x07, 0x9d, 0xfd, 0xd0, 0x92,
++	0x06, 0xe1, 0xb2, 0x9a, 0x4a, 0x1f, 0x1f, 0x13,
++	0x49, 0x99, 0x97, 0x08, 0xde, 0x7f, 0x98, 0xaf,
++	0x51, 0x98, 0xee, 0x2c, 0xcb, 0xf0, 0x0b, 0xc6,
++	0xb6, 0xb7, 0x2d, 0x9a, 0xb1, 0xac, 0xa6, 0xe3,
++	0x15, 0x77, 0x9d, 0x6b, 0x1a, 0xe4, 0xfc, 0x8b,
++	0xf2, 0x17, 0x59, 0x08, 0x04, 0x58, 0x81, 0x9d,
++	0x1b, 0x1b, 0x69, 0x55, 0xc2, 0xb4, 0x3c, 0x1f,
++	0x50, 0xf1, 0x7f, 0x77, 0x90, 0x4c, 0x66, 0x40,
++	0x5a, 0xc0, 0x33, 0x1f, 0xcb, 0x05, 0x6d, 0x5c,
++	0x06, 0x87, 0x52, 0xa2, 0x8f, 0x26, 0xd5, 0x4f
++};
++static const u8 enc_output010[] __initconst = {
++	0xe5, 0x26, 0xa4, 0x3d, 0xbd, 0x33, 0xd0, 0x4b,
++	0x6f, 0x05, 0xa7, 0x6e, 0x12, 0x7a, 0xd2, 0x74,
++	0xa6, 0xdd, 0xbd, 0x95, 0xeb, 0xf9, 0xa4, 0xf1,
++	0x59, 0x93, 0x91, 0x70, 0xd9, 0xfe, 0x9a, 0xcd,
++	0x53, 0x1f, 0x3a, 0xab, 0xa6, 0x7c, 0x9f, 0xa6,
++	0x9e, 0xbd, 0x99, 0xd9, 0xb5, 0x97, 0x44, 0xd5,
++	0x14, 0x48, 0x4d, 0x9d, 0xc0, 0xd0, 0x05, 0x96,
++	0xeb, 0x4c, 0x78, 0x55, 0x09, 0x08, 0x01, 0x02,
++	0x30, 0x90, 0x7b, 0x96, 0x7a, 0x7b, 0x5f, 0x30,
++	0x41, 0x24, 0xce, 0x68, 0x61, 0x49, 0x86, 0x57,
++	0x82, 0xdd, 0x53, 0x1c, 0x51, 0x28, 0x2b, 0x53,
++	0x6e, 0x2d, 0xc2, 0x20, 0x4c, 0xdd, 0x8f, 0x65,
++	0x10, 0x20, 0x50, 0xdd, 0x9d, 0x50, 0xe5, 0x71,
++	0x40, 0x53, 0x69, 0xfc, 0x77, 0x48, 0x11, 0xb9,
++	0xde, 0xa4, 0x8d, 0x58, 0xe4, 0xa6, 0x1a, 0x18,
++	0x47, 0x81, 0x7e, 0xfc, 0xdd, 0xf6, 0xef, 0xce,
++	0x2f, 0x43, 0x68, 0xd6, 0x06, 0xe2, 0x74, 0x6a,
++	0xad, 0x90, 0xf5, 0x37, 0xf3, 0x3d, 0x82, 0x69,
++	0x40, 0xe9, 0x6b, 0xa7, 0x3d, 0xa8, 0x1e, 0xd2,
++	0x02, 0x7c, 0xb7, 0x9b, 0xe4, 0xda, 0x8f, 0x95,
++	0x06, 0xc5, 0xdf, 0x73, 0xa3, 0x20, 0x9a, 0x49,
++	0xde, 0x9c, 0xbc, 0xee, 0x14, 0x3f, 0x81, 0x5e,
++	0xf8, 0x3b, 0x59, 0x3c, 0xe1, 0x68, 0x12, 0x5a,
++	0x3a, 0x76, 0x3a, 0x3f, 0xf7, 0x87, 0x33, 0x0a,
++	0x01, 0xb8, 0xd4, 0xed, 0xb6, 0xbe, 0x94, 0x5e,
++	0x70, 0x40, 0x56, 0x67, 0x1f, 0x50, 0x44, 0x19,
++	0xce, 0x82, 0x70, 0x10, 0x87, 0x13, 0x20, 0x0b,
++	0x4c, 0x5a, 0xb6, 0xf6, 0xa7, 0xae, 0x81, 0x75,
++	0x01, 0x81, 0xe6, 0x4b, 0x57, 0x7c, 0xdd, 0x6d,
++	0xf8, 0x1c, 0x29, 0x32, 0xf7, 0xda, 0x3c, 0x2d,
++	0xf8, 0x9b, 0x25, 0x6e, 0x00, 0xb4, 0xf7, 0x2f,
++	0xf7, 0x04, 0xf7, 0xa1, 0x56, 0xac, 0x4f, 0x1a,
++	0x64, 0xb8, 0x47, 0x55, 0x18, 0x7b, 0x07, 0x4d,
++	0xbd, 0x47, 0x24, 0x80, 0x5d, 0xa2, 0x70, 0xc5,
++	0xdd, 0x8e, 0x82, 0xd4, 0xeb, 0xec, 0xb2, 0x0c,
++	0x39, 0xd2, 0x97, 0xc1, 0xcb, 0xeb, 0xf4, 0x77,
++	0x59, 0xb4, 0x87, 0xef, 0xcb, 0x43, 0x2d, 0x46,
++	0x54, 0xd1, 0xa7, 0xd7, 0x15, 0x99, 0x0a, 0x43,
++	0xa1, 0xe0, 0x99, 0x33, 0x71, 0xc1, 0xed, 0xfe,
++	0x72, 0x46, 0x33, 0x8e, 0x91, 0x08, 0x9f, 0xc8,
++	0x2e, 0xca, 0xfa, 0xdc, 0x59, 0xd5, 0xc3, 0x76,
++	0x84, 0x9f, 0xa3, 0x37, 0x68, 0xc3, 0xf0, 0x47,
++	0x2c, 0x68, 0xdb, 0x5e, 0xc3, 0x49, 0x4c, 0xe8,
++	0x92, 0x85, 0xe2, 0x23, 0xd3, 0x3f, 0xad, 0x32,
++	0xe5, 0x2b, 0x82, 0xd7, 0x8f, 0x99, 0x0a, 0x59,
++	0x5c, 0x45, 0xd9, 0xb4, 0x51, 0x52, 0xc2, 0xae,
++	0xbf, 0x80, 0xcf, 0xc9, 0xc9, 0x51, 0x24, 0x2a,
++	0x3b, 0x3a, 0x4d, 0xae, 0xeb, 0xbd, 0x22, 0xc3,
++	0x0e, 0x0f, 0x59, 0x25, 0x92, 0x17, 0xe9, 0x74,
++	0xc7, 0x8b, 0x70, 0x70, 0x36, 0x55, 0x95, 0x75,
++	0x4b, 0xad, 0x61, 0x2b, 0x09, 0xbc, 0x82, 0xf2,
++	0x6e, 0x94, 0x43, 0xae, 0xc3, 0xd5, 0xcd, 0x8e,
++	0xfe, 0x5b, 0x9a, 0x88, 0x43, 0x01, 0x75, 0xb2,
++	0x23, 0x09, 0xf7, 0x89, 0x83, 0xe7, 0xfa, 0xf9,
++	0xb4, 0x9b, 0xf8, 0xef, 0xbd, 0x1c, 0x92, 0xc1,
++	0xda, 0x7e, 0xfe, 0x05, 0xba, 0x5a, 0xcd, 0x07,
++	0x6a, 0x78, 0x9e, 0x5d, 0xfb, 0x11, 0x2f, 0x79,
++	0x38, 0xb6, 0xc2, 0x5b, 0x6b, 0x51, 0xb4, 0x71,
++	0xdd, 0xf7, 0x2a, 0xe4, 0xf4, 0x72, 0x76, 0xad,
++	0xc2, 0xdd, 0x64, 0x5d, 0x79, 0xb6, 0xf5, 0x7a,
++	0x77, 0x20, 0x05, 0x3d, 0x30, 0x06, 0xd4, 0x4c,
++	0x0a, 0x2c, 0x98, 0x5a, 0xb9, 0xd4, 0x98, 0xa9,
++	0x3f, 0xc6, 0x12, 0xea, 0x3b, 0x4b, 0xc5, 0x79,
++	0x64, 0x63, 0x6b, 0x09, 0x54, 0x3b, 0x14, 0x27,
++	0xba, 0x99, 0x80, 0xc8, 0x72, 0xa8, 0x12, 0x90,
++	0x29, 0xba, 0x40, 0x54, 0x97, 0x2b, 0x7b, 0xfe,
++	0xeb, 0xcd, 0x01, 0x05, 0x44, 0x72, 0xdb, 0x99,
++	0xe4, 0x61, 0xc9, 0x69, 0xd6, 0xb9, 0x28, 0xd1,
++	0x05, 0x3e, 0xf9, 0x0b, 0x49, 0x0a, 0x49, 0xe9,
++	0x8d, 0x0e, 0xa7, 0x4a, 0x0f, 0xaf, 0x32, 0xd0,
++	0xe0, 0xb2, 0x3a, 0x55, 0x58, 0xfe, 0x5c, 0x28,
++	0x70, 0x51, 0x23, 0xb0, 0x7b, 0x6a, 0x5f, 0x1e,
++	0xb8, 0x17, 0xd7, 0x94, 0x15, 0x8f, 0xee, 0x20,
++	0xc7, 0x42, 0x25, 0x3e, 0x9a, 0x14, 0xd7, 0x60,
++	0x72, 0x39, 0x47, 0x48, 0xa9, 0xfe, 0xdd, 0x47,
++	0x0a, 0xb1, 0xe6, 0x60, 0x28, 0x8c, 0x11, 0x68,
++	0xe1, 0xff, 0xd7, 0xce, 0xc8, 0xbe, 0xb3, 0xfe,
++	0x27, 0x30, 0x09, 0x70, 0xd7, 0xfa, 0x02, 0x33,
++	0x3a, 0x61, 0x2e, 0xc7, 0xff, 0xa4, 0x2a, 0xa8,
++	0x6e, 0xb4, 0x79, 0x35, 0x6d, 0x4c, 0x1e, 0x38,
++	0xf8, 0xee, 0xd4, 0x84, 0x4e, 0x6e, 0x28, 0xa7,
++	0xce, 0xc8, 0xc1, 0xcf, 0x80, 0x05, 0xf3, 0x04,
++	0xef, 0xc8, 0x18, 0x28, 0x2e, 0x8d, 0x5e, 0x0c,
++	0xdf, 0xb8, 0x5f, 0x96, 0xe8, 0xc6, 0x9c, 0x2f,
++	0xe5, 0xa6, 0x44, 0xd7, 0xe7, 0x99, 0x44, 0x0c,
++	0xec, 0xd7, 0x05, 0x60, 0x97, 0xbb, 0x74, 0x77,
++	0x58, 0xd5, 0xbb, 0x48, 0xde, 0x5a, 0xb2, 0x54,
++	0x7f, 0x0e, 0x46, 0x70, 0x6a, 0x6f, 0x78, 0xa5,
++	0x08, 0x89, 0x05, 0x4e, 0x7e, 0xa0, 0x69, 0xb4,
++	0x40, 0x60, 0x55, 0x77, 0x75, 0x9b, 0x19, 0xf2,
++	0xd5, 0x13, 0x80, 0x77, 0xf9, 0x4b, 0x3f, 0x1e,
++	0xee, 0xe6, 0x76, 0x84, 0x7b, 0x8c, 0xe5, 0x27,
++	0xa8, 0x0a, 0x91, 0x01, 0x68, 0x71, 0x8a, 0x3f,
++	0x06, 0xab, 0xf6, 0xa9, 0xa5, 0xe6, 0x72, 0x92,
++	0xe4, 0x67, 0xe2, 0xa2, 0x46, 0x35, 0x84, 0x55,
++	0x7d, 0xca, 0xa8, 0x85, 0xd0, 0xf1, 0x3f, 0xbe,
++	0xd7, 0x34, 0x64, 0xfc, 0xae, 0xe3, 0xe4, 0x04,
++	0x9f, 0x66, 0x02, 0xb9, 0x88, 0x10, 0xd9, 0xc4,
++	0x4c, 0x31, 0x43, 0x7a, 0x93, 0xe2, 0x9b, 0x56,
++	0x43, 0x84, 0xdc, 0xdc, 0xde, 0x1d, 0xa4, 0x02,
++	0x0e, 0xc2, 0xef, 0xc3, 0xf8, 0x78, 0xd1, 0xb2,
++	0x6b, 0x63, 0x18, 0xc9, 0xa9, 0xe5, 0x72, 0xd8,
++	0xf3, 0xb9, 0xd1, 0x8a, 0xc7, 0x1a, 0x02, 0x27,
++	0x20, 0x77, 0x10, 0xe5, 0xc8, 0xd4, 0x4a, 0x47,
++	0xe5, 0xdf, 0x5f, 0x01, 0xaa, 0xb0, 0xd4, 0x10,
++	0xbb, 0x69, 0xe3, 0x36, 0xc8, 0xe1, 0x3d, 0x43,
++	0xfb, 0x86, 0xcd, 0xcc, 0xbf, 0xf4, 0x88, 0xe0,
++	0x20, 0xca, 0xb7, 0x1b, 0xf1, 0x2f, 0x5c, 0xee,
++	0xd4, 0xd3, 0xa3, 0xcc, 0xa4, 0x1e, 0x1c, 0x47,
++	0xfb, 0xbf, 0xfc, 0xa2, 0x41, 0x55, 0x9d, 0xf6,
++	0x5a, 0x5e, 0x65, 0x32, 0x34, 0x7b, 0x52, 0x8d,
++	0xd5, 0xd0, 0x20, 0x60, 0x03, 0xab, 0x3f, 0x8c,
++	0xd4, 0x21, 0xea, 0x2a, 0xd9, 0xc4, 0xd0, 0xd3,
++	0x65, 0xd8, 0x7a, 0x13, 0x28, 0x62, 0x32, 0x4b,
++	0x2c, 0x87, 0x93, 0xa8, 0xb4, 0x52, 0x45, 0x09,
++	0x44, 0xec, 0xec, 0xc3, 0x17, 0xdb, 0x9a, 0x4d,
++	0x5c, 0xa9, 0x11, 0xd4, 0x7d, 0xaf, 0x9e, 0xf1,
++	0x2d, 0xb2, 0x66, 0xc5, 0x1d, 0xed, 0xb7, 0xcd,
++	0x0b, 0x25, 0x5e, 0x30, 0x47, 0x3f, 0x40, 0xf4,
++	0xa1, 0xa0, 0x00, 0x94, 0x10, 0xc5, 0x6a, 0x63,
++	0x1a, 0xd5, 0x88, 0x92, 0x8e, 0x82, 0x39, 0x87,
++	0x3c, 0x78, 0x65, 0x58, 0x42, 0x75, 0x5b, 0xdd,
++	0x77, 0x3e, 0x09, 0x4e, 0x76, 0x5b, 0xe6, 0x0e,
++	0x4d, 0x38, 0xb2, 0xc0, 0xb8, 0x95, 0x01, 0x7a,
++	0x10, 0xe0, 0xfb, 0x07, 0xf2, 0xab, 0x2d, 0x8c,
++	0x32, 0xed, 0x2b, 0xc0, 0x46, 0xc2, 0xf5, 0x38,
++	0x83, 0xf0, 0x17, 0xec, 0xc1, 0x20, 0x6a, 0x9a,
++	0x0b, 0x00, 0xa0, 0x98, 0x22, 0x50, 0x23, 0xd5,
++	0x80, 0x6b, 0xf6, 0x1f, 0xc3, 0xcc, 0x97, 0xc9,
++	0x24, 0x9f, 0xf3, 0xaf, 0x43, 0x14, 0xd5, 0xa0
++};
++static const u8 enc_assoc010[] __initconst = {
++	0xd2, 0xa1, 0x70, 0xdb, 0x7a, 0xf8, 0xfa, 0x27,
++	0xba, 0x73, 0x0f, 0xbf, 0x3d, 0x1e, 0x82, 0xb2
++};
++static const u8 enc_nonce010[] __initconst = {
++	0xdb, 0x92, 0x0f, 0x7f, 0x17, 0x54, 0x0c, 0x30
++};
++static const u8 enc_key010[] __initconst = {
++	0x47, 0x11, 0xeb, 0x86, 0x2b, 0x2c, 0xab, 0x44,
++	0x34, 0xda, 0x7f, 0x57, 0x03, 0x39, 0x0c, 0xaf,
++	0x2c, 0x14, 0xfd, 0x65, 0x23, 0xe9, 0x8e, 0x74,
++	0xd5, 0x08, 0x68, 0x08, 0xe7, 0xb4, 0x72, 0xd7
++};
++
++static const u8 enc_input011[] __initconst = {
++	0x7a, 0x57, 0xf2, 0xc7, 0x06, 0x3f, 0x50, 0x7b,
++	0x36, 0x1a, 0x66, 0x5c, 0xb9, 0x0e, 0x5e, 0x3b,
++	0x45, 0x60, 0xbe, 0x9a, 0x31, 0x9f, 0xff, 0x5d,
++	0x66, 0x34, 0xb4, 0xdc, 0xfb, 0x9d, 0x8e, 0xee,
++	0x6a, 0x33, 0xa4, 0x07, 0x3c, 0xf9, 0x4c, 0x30,
++	0xa1, 0x24, 0x52, 0xf9, 0x50, 0x46, 0x88, 0x20,
++	0x02, 0x32, 0x3a, 0x0e, 0x99, 0x63, 0xaf, 0x1f,
++	0x15, 0x28, 0x2a, 0x05, 0xff, 0x57, 0x59, 0x5e,
++	0x18, 0xa1, 0x1f, 0xd0, 0x92, 0x5c, 0x88, 0x66,
++	0x1b, 0x00, 0x64, 0xa5, 0x93, 0x8d, 0x06, 0x46,
++	0xb0, 0x64, 0x8b, 0x8b, 0xef, 0x99, 0x05, 0x35,
++	0x85, 0xb3, 0xf3, 0x33, 0xbb, 0xec, 0x66, 0xb6,
++	0x3d, 0x57, 0x42, 0xe3, 0xb4, 0xc6, 0xaa, 0xb0,
++	0x41, 0x2a, 0xb9, 0x59, 0xa9, 0xf6, 0x3e, 0x15,
++	0x26, 0x12, 0x03, 0x21, 0x4c, 0x74, 0x43, 0x13,
++	0x2a, 0x03, 0x27, 0x09, 0xb4, 0xfb, 0xe7, 0xb7,
++	0x40, 0xff, 0x5e, 0xce, 0x48, 0x9a, 0x60, 0xe3,
++	0x8b, 0x80, 0x8c, 0x38, 0x2d, 0xcb, 0x93, 0x37,
++	0x74, 0x05, 0x52, 0x6f, 0x73, 0x3e, 0xc3, 0xbc,
++	0xca, 0x72, 0x0a, 0xeb, 0xf1, 0x3b, 0xa0, 0x95,
++	0xdc, 0x8a, 0xc4, 0xa9, 0xdc, 0xca, 0x44, 0xd8,
++	0x08, 0x63, 0x6a, 0x36, 0xd3, 0x3c, 0xb8, 0xac,
++	0x46, 0x7d, 0xfd, 0xaa, 0xeb, 0x3e, 0x0f, 0x45,
++	0x8f, 0x49, 0xda, 0x2b, 0xf2, 0x12, 0xbd, 0xaf,
++	0x67, 0x8a, 0x63, 0x48, 0x4b, 0x55, 0x5f, 0x6d,
++	0x8c, 0xb9, 0x76, 0x34, 0x84, 0xae, 0xc2, 0xfc,
++	0x52, 0x64, 0x82, 0xf7, 0xb0, 0x06, 0xf0, 0x45,
++	0x73, 0x12, 0x50, 0x30, 0x72, 0xea, 0x78, 0x9a,
++	0xa8, 0xaf, 0xb5, 0xe3, 0xbb, 0x77, 0x52, 0xec,
++	0x59, 0x84, 0xbf, 0x6b, 0x8f, 0xce, 0x86, 0x5e,
++	0x1f, 0x23, 0xe9, 0xfb, 0x08, 0x86, 0xf7, 0x10,
++	0xb9, 0xf2, 0x44, 0x96, 0x44, 0x63, 0xa9, 0xa8,
++	0x78, 0x00, 0x23, 0xd6, 0xc7, 0xe7, 0x6e, 0x66,
++	0x4f, 0xcc, 0xee, 0x15, 0xb3, 0xbd, 0x1d, 0xa0,
++	0xe5, 0x9c, 0x1b, 0x24, 0x2c, 0x4d, 0x3c, 0x62,
++	0x35, 0x9c, 0x88, 0x59, 0x09, 0xdd, 0x82, 0x1b,
++	0xcf, 0x0a, 0x83, 0x6b, 0x3f, 0xae, 0x03, 0xc4,
++	0xb4, 0xdd, 0x7e, 0x5b, 0x28, 0x76, 0x25, 0x96,
++	0xd9, 0xc9, 0x9d, 0x5f, 0x86, 0xfa, 0xf6, 0xd7,
++	0xd2, 0xe6, 0x76, 0x1d, 0x0f, 0xa1, 0xdc, 0x74,
++	0x05, 0x1b, 0x1d, 0xe0, 0xcd, 0x16, 0xb0, 0xa8,
++	0x8a, 0x34, 0x7b, 0x15, 0x11, 0x77, 0xe5, 0x7b,
++	0x7e, 0x20, 0xf7, 0xda, 0x38, 0xda, 0xce, 0x70,
++	0xe9, 0xf5, 0x6c, 0xd9, 0xbe, 0x0c, 0x4c, 0x95,
++	0x4c, 0xc2, 0x9b, 0x34, 0x55, 0x55, 0xe1, 0xf3,
++	0x46, 0x8e, 0x48, 0x74, 0x14, 0x4f, 0x9d, 0xc9,
++	0xf5, 0xe8, 0x1a, 0xf0, 0x11, 0x4a, 0xc1, 0x8d,
++	0xe0, 0x93, 0xa0, 0xbe, 0x09, 0x1c, 0x2b, 0x4e,
++	0x0f, 0xb2, 0x87, 0x8b, 0x84, 0xfe, 0x92, 0x32,
++	0x14, 0xd7, 0x93, 0xdf, 0xe7, 0x44, 0xbc, 0xc5,
++	0xae, 0x53, 0x69, 0xd8, 0xb3, 0x79, 0x37, 0x80,
++	0xe3, 0x17, 0x5c, 0xec, 0x53, 0x00, 0x9a, 0xe3,
++	0x8e, 0xdc, 0x38, 0xb8, 0x66, 0xf0, 0xd3, 0xad,
++	0x1d, 0x02, 0x96, 0x86, 0x3e, 0x9d, 0x3b, 0x5d,
++	0xa5, 0x7f, 0x21, 0x10, 0xf1, 0x1f, 0x13, 0x20,
++	0xf9, 0x57, 0x87, 0x20, 0xf5, 0x5f, 0xf1, 0x17,
++	0x48, 0x0a, 0x51, 0x5a, 0xcd, 0x19, 0x03, 0xa6,
++	0x5a, 0xd1, 0x12, 0x97, 0xe9, 0x48, 0xe2, 0x1d,
++	0x83, 0x75, 0x50, 0xd9, 0x75, 0x7d, 0x6a, 0x82,
++	0xa1, 0xf9, 0x4e, 0x54, 0x87, 0x89, 0xc9, 0x0c,
++	0xb7, 0x5b, 0x6a, 0x91, 0xc1, 0x9c, 0xb2, 0xa9,
++	0xdc, 0x9a, 0xa4, 0x49, 0x0a, 0x6d, 0x0d, 0xbb,
++	0xde, 0x86, 0x44, 0xdd, 0x5d, 0x89, 0x2b, 0x96,
++	0x0f, 0x23, 0x95, 0xad, 0xcc, 0xa2, 0xb3, 0xb9,
++	0x7e, 0x74, 0x38, 0xba, 0x9f, 0x73, 0xae, 0x5f,
++	0xf8, 0x68, 0xa2, 0xe0, 0xa9, 0xce, 0xbd, 0x40,
++	0xd4, 0x4c, 0x6b, 0xd2, 0x56, 0x62, 0xb0, 0xcc,
++	0x63, 0x7e, 0x5b, 0xd3, 0xae, 0xd1, 0x75, 0xce,
++	0xbb, 0xb4, 0x5b, 0xa8, 0xf8, 0xb4, 0xac, 0x71,
++	0x75, 0xaa, 0xc9, 0x9f, 0xbb, 0x6c, 0xad, 0x0f,
++	0x55, 0x5d, 0xe8, 0x85, 0x7d, 0xf9, 0x21, 0x35,
++	0xea, 0x92, 0x85, 0x2b, 0x00, 0xec, 0x84, 0x90,
++	0x0a, 0x63, 0x96, 0xe4, 0x6b, 0xa9, 0x77, 0xb8,
++	0x91, 0xf8, 0x46, 0x15, 0x72, 0x63, 0x70, 0x01,
++	0x40, 0xa3, 0xa5, 0x76, 0x62, 0x2b, 0xbf, 0xf1,
++	0xe5, 0x8d, 0x9f, 0xa3, 0xfa, 0x9b, 0x03, 0xbe,
++	0xfe, 0x65, 0x6f, 0xa2, 0x29, 0x0d, 0x54, 0xb4,
++	0x71, 0xce, 0xa9, 0xd6, 0x3d, 0x88, 0xf9, 0xaf,
++	0x6b, 0xa8, 0x9e, 0xf4, 0x16, 0x96, 0x36, 0xb9,
++	0x00, 0xdc, 0x10, 0xab, 0xb5, 0x08, 0x31, 0x1f,
++	0x00, 0xb1, 0x3c, 0xd9, 0x38, 0x3e, 0xc6, 0x04,
++	0xa7, 0x4e, 0xe8, 0xae, 0xed, 0x98, 0xc2, 0xf7,
++	0xb9, 0x00, 0x5f, 0x8c, 0x60, 0xd1, 0xe5, 0x15,
++	0xf7, 0xae, 0x1e, 0x84, 0x88, 0xd1, 0xf6, 0xbc,
++	0x3a, 0x89, 0x35, 0x22, 0x83, 0x7c, 0xca, 0xf0,
++	0x33, 0x82, 0x4c, 0x79, 0x3c, 0xfd, 0xb1, 0xae,
++	0x52, 0x62, 0x55, 0xd2, 0x41, 0x60, 0xc6, 0xbb,
++	0xfa, 0x0e, 0x59, 0xd6, 0xa8, 0xfe, 0x5d, 0xed,
++	0x47, 0x3d, 0xe0, 0xea, 0x1f, 0x6e, 0x43, 0x51,
++	0xec, 0x10, 0x52, 0x56, 0x77, 0x42, 0x6b, 0x52,
++	0x87, 0xd8, 0xec, 0xe0, 0xaa, 0x76, 0xa5, 0x84,
++	0x2a, 0x22, 0x24, 0xfd, 0x92, 0x40, 0x88, 0xd5,
++	0x85, 0x1c, 0x1f, 0x6b, 0x47, 0xa0, 0xc4, 0xe4,
++	0xef, 0xf4, 0xea, 0xd7, 0x59, 0xac, 0x2a, 0x9e,
++	0x8c, 0xfa, 0x1f, 0x42, 0x08, 0xfe, 0x4f, 0x74,
++	0xa0, 0x26, 0xf5, 0xb3, 0x84, 0xf6, 0x58, 0x5f,
++	0x26, 0x66, 0x3e, 0xd7, 0xe4, 0x22, 0x91, 0x13,
++	0xc8, 0xac, 0x25, 0x96, 0x23, 0xd8, 0x09, 0xea,
++	0x45, 0x75, 0x23, 0xb8, 0x5f, 0xc2, 0x90, 0x8b,
++	0x09, 0xc4, 0xfc, 0x47, 0x6c, 0x6d, 0x0a, 0xef,
++	0x69, 0xa4, 0x38, 0x19, 0xcf, 0x7d, 0xf9, 0x09,
++	0x73, 0x9b, 0x60, 0x5a, 0xf7, 0x37, 0xb5, 0xfe,
++	0x9f, 0xe3, 0x2b, 0x4c, 0x0d, 0x6e, 0x19, 0xf1,
++	0xd6, 0xc0, 0x70, 0xf3, 0x9d, 0x22, 0x3c, 0xf9,
++	0x49, 0xce, 0x30, 0x8e, 0x44, 0xb5, 0x76, 0x15,
++	0x8f, 0x52, 0xfd, 0xa5, 0x04, 0xb8, 0x55, 0x6a,
++	0x36, 0x59, 0x7c, 0xc4, 0x48, 0xb8, 0xd7, 0xab,
++	0x05, 0x66, 0xe9, 0x5e, 0x21, 0x6f, 0x6b, 0x36,
++	0x29, 0xbb, 0xe9, 0xe3, 0xa2, 0x9a, 0xa8, 0xcd,
++	0x55, 0x25, 0x11, 0xba, 0x5a, 0x58, 0xa0, 0xde,
++	0xae, 0x19, 0x2a, 0x48, 0x5a, 0xff, 0x36, 0xcd,
++	0x6d, 0x16, 0x7a, 0x73, 0x38, 0x46, 0xe5, 0x47,
++	0x59, 0xc8, 0xa2, 0xf6, 0xe2, 0x6c, 0x83, 0xc5,
++	0x36, 0x2c, 0x83, 0x7d, 0xb4, 0x01, 0x05, 0x69,
++	0xe7, 0xaf, 0x5c, 0xc4, 0x64, 0x82, 0x12, 0x21,
++	0xef, 0xf7, 0xd1, 0x7d, 0xb8, 0x8d, 0x8c, 0x98,
++	0x7c, 0x5f, 0x7d, 0x92, 0x88, 0xb9, 0x94, 0x07,
++	0x9c, 0xd8, 0xe9, 0x9c, 0x17, 0x38, 0xe3, 0x57,
++	0x6c, 0xe0, 0xdc, 0xa5, 0x92, 0x42, 0xb3, 0xbd,
++	0x50, 0xa2, 0x7e, 0xb5, 0xb1, 0x52, 0x72, 0x03,
++	0x97, 0xd8, 0xaa, 0x9a, 0x1e, 0x75, 0x41, 0x11,
++	0xa3, 0x4f, 0xcc, 0xd4, 0xe3, 0x73, 0xad, 0x96,
++	0xdc, 0x47, 0x41, 0x9f, 0xb0, 0xbe, 0x79, 0x91,
++	0xf5, 0xb6, 0x18, 0xfe, 0xc2, 0x83, 0x18, 0x7d,
++	0x73, 0xd9, 0x4f, 0x83, 0x84, 0x03, 0xb3, 0xf0,
++	0x77, 0x66, 0x3d, 0x83, 0x63, 0x2e, 0x2c, 0xf9,
++	0xdd, 0xa6, 0x1f, 0x89, 0x82, 0xb8, 0x23, 0x42,
++	0xeb, 0xe2, 0xca, 0x70, 0x82, 0x61, 0x41, 0x0a,
++	0x6d, 0x5f, 0x75, 0xc5, 0xe2, 0xc4, 0x91, 0x18,
++	0x44, 0x22, 0xfa, 0x34, 0x10, 0xf5, 0x20, 0xdc,
++	0xb7, 0xdd, 0x2a, 0x20, 0x77, 0xf5, 0xf9, 0xce,
++	0xdb, 0xa0, 0x0a, 0x52, 0x2a, 0x4e, 0xdd, 0xcc,
++	0x97, 0xdf, 0x05, 0xe4, 0x5e, 0xb7, 0xaa, 0xf0,
++	0xe2, 0x80, 0xff, 0xba, 0x1a, 0x0f, 0xac, 0xdf,
++	0x02, 0x32, 0xe6, 0xf7, 0xc7, 0x17, 0x13, 0xb7,
++	0xfc, 0x98, 0x48, 0x8c, 0x0d, 0x82, 0xc9, 0x80,
++	0x7a, 0xe2, 0x0a, 0xc5, 0xb4, 0xde, 0x7c, 0x3c,
++	0x79, 0x81, 0x0e, 0x28, 0x65, 0x79, 0x67, 0x82,
++	0x69, 0x44, 0x66, 0x09, 0xf7, 0x16, 0x1a, 0xf9,
++	0x7d, 0x80, 0xa1, 0x79, 0x14, 0xa9, 0xc8, 0x20,
++	0xfb, 0xa2, 0x46, 0xbe, 0x08, 0x35, 0x17, 0x58,
++	0xc1, 0x1a, 0xda, 0x2a, 0x6b, 0x2e, 0x1e, 0xe6,
++	0x27, 0x55, 0x7b, 0x19, 0xe2, 0xfb, 0x64, 0xfc,
++	0x5e, 0x15, 0x54, 0x3c, 0xe7, 0xc2, 0x11, 0x50,
++	0x30, 0xb8, 0x72, 0x03, 0x0b, 0x1a, 0x9f, 0x86,
++	0x27, 0x11, 0x5c, 0x06, 0x2b, 0xbd, 0x75, 0x1a,
++	0x0a, 0xda, 0x01, 0xfa, 0x5c, 0x4a, 0xc1, 0x80,
++	0x3a, 0x6e, 0x30, 0xc8, 0x2c, 0xeb, 0x56, 0xec,
++	0x89, 0xfa, 0x35, 0x7b, 0xb2, 0xf0, 0x97, 0x08,
++	0x86, 0x53, 0xbe, 0xbd, 0x40, 0x41, 0x38, 0x1c,
++	0xb4, 0x8b, 0x79, 0x2e, 0x18, 0x96, 0x94, 0xde,
++	0xe8, 0xca, 0xe5, 0x9f, 0x92, 0x9f, 0x15, 0x5d,
++	0x56, 0x60, 0x5c, 0x09, 0xf9, 0x16, 0xf4, 0x17,
++	0x0f, 0xf6, 0x4c, 0xda, 0xe6, 0x67, 0x89, 0x9f,
++	0xca, 0x6c, 0xe7, 0x9b, 0x04, 0x62, 0x0e, 0x26,
++	0xa6, 0x52, 0xbd, 0x29, 0xff, 0xc7, 0xa4, 0x96,
++	0xe6, 0x6a, 0x02, 0xa5, 0x2e, 0x7b, 0xfe, 0x97,
++	0x68, 0x3e, 0x2e, 0x5f, 0x3b, 0x0f, 0x36, 0xd6,
++	0x98, 0x19, 0x59, 0x48, 0xd2, 0xc6, 0xe1, 0x55,
++	0x1a, 0x6e, 0xd6, 0xed, 0x2c, 0xba, 0xc3, 0x9e,
++	0x64, 0xc9, 0x95, 0x86, 0x35, 0x5e, 0x3e, 0x88,
++	0x69, 0x99, 0x4b, 0xee, 0xbe, 0x9a, 0x99, 0xb5,
++	0x6e, 0x58, 0xae, 0xdd, 0x22, 0xdb, 0xdd, 0x6b,
++	0xfc, 0xaf, 0x90, 0xa3, 0x3d, 0xa4, 0xc1, 0x15,
++	0x92, 0x18, 0x8d, 0xd2, 0x4b, 0x7b, 0x06, 0xd1,
++	0x37, 0xb5, 0xe2, 0x7c, 0x2c, 0xf0, 0x25, 0xe4,
++	0x94, 0x2a, 0xbd, 0xe3, 0x82, 0x70, 0x78, 0xa3,
++	0x82, 0x10, 0x5a, 0x90, 0xd7, 0xa4, 0xfa, 0xaf,
++	0x1a, 0x88, 0x59, 0xdc, 0x74, 0x12, 0xb4, 0x8e,
++	0xd7, 0x19, 0x46, 0xf4, 0x84, 0x69, 0x9f, 0xbb,
++	0x70, 0xa8, 0x4c, 0x52, 0x81, 0xa9, 0xff, 0x76,
++	0x1c, 0xae, 0xd8, 0x11, 0x3d, 0x7f, 0x7d, 0xc5,
++	0x12, 0x59, 0x28, 0x18, 0xc2, 0xa2, 0xb7, 0x1c,
++	0x88, 0xf8, 0xd6, 0x1b, 0xa6, 0x7d, 0x9e, 0xde,
++	0x29, 0xf8, 0xed, 0xff, 0xeb, 0x92, 0x24, 0x4f,
++	0x05, 0xaa, 0xd9, 0x49, 0xba, 0x87, 0x59, 0x51,
++	0xc9, 0x20, 0x5c, 0x9b, 0x74, 0xcf, 0x03, 0xd9,
++	0x2d, 0x34, 0xc7, 0x5b, 0xa5, 0x40, 0xb2, 0x99,
++	0xf5, 0xcb, 0xb4, 0xf6, 0xb7, 0x72, 0x4a, 0xd6,
++	0xbd, 0xb0, 0xf3, 0x93, 0xe0, 0x1b, 0xa8, 0x04,
++	0x1e, 0x35, 0xd4, 0x80, 0x20, 0xf4, 0x9c, 0x31,
++	0x6b, 0x45, 0xb9, 0x15, 0xb0, 0x5e, 0xdd, 0x0a,
++	0x33, 0x9c, 0x83, 0xcd, 0x58, 0x89, 0x50, 0x56,
++	0xbb, 0x81, 0x00, 0x91, 0x32, 0xf3, 0x1b, 0x3e,
++	0xcf, 0x45, 0xe1, 0xf9, 0xe1, 0x2c, 0x26, 0x78,
++	0x93, 0x9a, 0x60, 0x46, 0xc9, 0xb5, 0x5e, 0x6a,
++	0x28, 0x92, 0x87, 0x3f, 0x63, 0x7b, 0xdb, 0xf7,
++	0xd0, 0x13, 0x9d, 0x32, 0x40, 0x5e, 0xcf, 0xfb,
++	0x79, 0x68, 0x47, 0x4c, 0xfd, 0x01, 0x17, 0xe6,
++	0x97, 0x93, 0x78, 0xbb, 0xa6, 0x27, 0xa3, 0xe8,
++	0x1a, 0xe8, 0x94, 0x55, 0x7d, 0x08, 0xe5, 0xdc,
++	0x66, 0xa3, 0x69, 0xc8, 0xca, 0xc5, 0xa1, 0x84,
++	0x55, 0xde, 0x08, 0x91, 0x16, 0x3a, 0x0c, 0x86,
++	0xab, 0x27, 0x2b, 0x64, 0x34, 0x02, 0x6c, 0x76,
++	0x8b, 0xc6, 0xaf, 0xcc, 0xe1, 0xd6, 0x8c, 0x2a,
++	0x18, 0x3d, 0xa6, 0x1b, 0x37, 0x75, 0x45, 0x73,
++	0xc2, 0x75, 0xd7, 0x53, 0x78, 0x3a, 0xd6, 0xe8,
++	0x29, 0xd2, 0x4a, 0xa8, 0x1e, 0x82, 0xf6, 0xb6,
++	0x81, 0xde, 0x21, 0xed, 0x2b, 0x56, 0xbb, 0xf2,
++	0xd0, 0x57, 0xc1, 0x7c, 0xd2, 0x6a, 0xd2, 0x56,
++	0xf5, 0x13, 0x5f, 0x1c, 0x6a, 0x0b, 0x74, 0xfb,
++	0xe9, 0xfe, 0x9e, 0xea, 0x95, 0xb2, 0x46, 0xab,
++	0x0a, 0xfc, 0xfd, 0xf3, 0xbb, 0x04, 0x2b, 0x76,
++	0x1b, 0xa4, 0x74, 0xb0, 0xc1, 0x78, 0xc3, 0x69,
++	0xe2, 0xb0, 0x01, 0xe1, 0xde, 0x32, 0x4c, 0x8d,
++	0x1a, 0xb3, 0x38, 0x08, 0xd5, 0xfc, 0x1f, 0xdc,
++	0x0e, 0x2c, 0x9c, 0xb1, 0xa1, 0x63, 0x17, 0x22,
++	0xf5, 0x6c, 0x93, 0x70, 0x74, 0x00, 0xf8, 0x39,
++	0x01, 0x94, 0xd1, 0x32, 0x23, 0x56, 0x5d, 0xa6,
++	0x02, 0x76, 0x76, 0x93, 0xce, 0x2f, 0x19, 0xe9,
++	0x17, 0x52, 0xae, 0x6e, 0x2c, 0x6d, 0x61, 0x7f,
++	0x3b, 0xaa, 0xe0, 0x52, 0x85, 0xc5, 0x65, 0xc1,
++	0xbb, 0x8e, 0x5b, 0x21, 0xd5, 0xc9, 0x78, 0x83,
++	0x07, 0x97, 0x4c, 0x62, 0x61, 0x41, 0xd4, 0xfc,
++	0xc9, 0x39, 0xe3, 0x9b, 0xd0, 0xcc, 0x75, 0xc4,
++	0x97, 0xe6, 0xdd, 0x2a, 0x5f, 0xa6, 0xe8, 0x59,
++	0x6c, 0x98, 0xb9, 0x02, 0xe2, 0xa2, 0xd6, 0x68,
++	0xee, 0x3b, 0x1d, 0xe3, 0x4d, 0x5b, 0x30, 0xef,
++	0x03, 0xf2, 0xeb, 0x18, 0x57, 0x36, 0xe8, 0xa1,
++	0xf4, 0x47, 0xfb, 0xcb, 0x8f, 0xcb, 0xc8, 0xf3,
++	0x4f, 0x74, 0x9d, 0x9d, 0xb1, 0x8d, 0x14, 0x44,
++	0xd9, 0x19, 0xb4, 0x54, 0x4f, 0x75, 0x19, 0x09,
++	0xa0, 0x75, 0xbc, 0x3b, 0x82, 0xc6, 0x3f, 0xb8,
++	0x83, 0x19, 0x6e, 0xd6, 0x37, 0xfe, 0x6e, 0x8a,
++	0x4e, 0xe0, 0x4a, 0xab, 0x7b, 0xc8, 0xb4, 0x1d,
++	0xf4, 0xed, 0x27, 0x03, 0x65, 0xa2, 0xa1, 0xae,
++	0x11, 0xe7, 0x98, 0x78, 0x48, 0x91, 0xd2, 0xd2,
++	0xd4, 0x23, 0x78, 0x50, 0xb1, 0x5b, 0x85, 0x10,
++	0x8d, 0xca, 0x5f, 0x0f, 0x71, 0xae, 0x72, 0x9a,
++	0xf6, 0x25, 0x19, 0x60, 0x06, 0xf7, 0x10, 0x34,
++	0x18, 0x0d, 0xc9, 0x9f, 0x7b, 0x0c, 0x9b, 0x8f,
++	0x91, 0x1b, 0x9f, 0xcd, 0x10, 0xee, 0x75, 0xf9,
++	0x97, 0x66, 0xfc, 0x4d, 0x33, 0x6e, 0x28, 0x2b,
++	0x92, 0x85, 0x4f, 0xab, 0x43, 0x8d, 0x8f, 0x7d,
++	0x86, 0xa7, 0xc7, 0xd8, 0xd3, 0x0b, 0x8b, 0x57,
++	0xb6, 0x1d, 0x95, 0x0d, 0xe9, 0xbc, 0xd9, 0x03,
++	0xd9, 0x10, 0x19, 0xc3, 0x46, 0x63, 0x55, 0x87,
++	0x61, 0x79, 0x6c, 0x95, 0x0e, 0x9c, 0xdd, 0xca,
++	0xc3, 0xf3, 0x64, 0xf0, 0x7d, 0x76, 0xb7, 0x53,
++	0x67, 0x2b, 0x1e, 0x44, 0x56, 0x81, 0xea, 0x8f,
++	0x5c, 0x42, 0x16, 0xb8, 0x28, 0xeb, 0x1b, 0x61,
++	0x10, 0x1e, 0xbf, 0xec, 0xa8
++};
++static const u8 enc_output011[] __initconst = {
++	0x6a, 0xfc, 0x4b, 0x25, 0xdf, 0xc0, 0xe4, 0xe8,
++	0x17, 0x4d, 0x4c, 0xc9, 0x7e, 0xde, 0x3a, 0xcc,
++	0x3c, 0xba, 0x6a, 0x77, 0x47, 0xdb, 0xe3, 0x74,
++	0x7a, 0x4d, 0x5f, 0x8d, 0x37, 0x55, 0x80, 0x73,
++	0x90, 0x66, 0x5d, 0x3a, 0x7d, 0x5d, 0x86, 0x5e,
++	0x8d, 0xfd, 0x83, 0xff, 0x4e, 0x74, 0x6f, 0xf9,
++	0xe6, 0x70, 0x17, 0x70, 0x3e, 0x96, 0xa7, 0x7e,
++	0xcb, 0xab, 0x8f, 0x58, 0x24, 0x9b, 0x01, 0xfd,
++	0xcb, 0xe6, 0x4d, 0x9b, 0xf0, 0x88, 0x94, 0x57,
++	0x66, 0xef, 0x72, 0x4c, 0x42, 0x6e, 0x16, 0x19,
++	0x15, 0xea, 0x70, 0x5b, 0xac, 0x13, 0xdb, 0x9f,
++	0x18, 0xe2, 0x3c, 0x26, 0x97, 0xbc, 0xdc, 0x45,
++	0x8c, 0x6c, 0x24, 0x69, 0x9c, 0xf7, 0x65, 0x1e,
++	0x18, 0x59, 0x31, 0x7c, 0xe4, 0x73, 0xbc, 0x39,
++	0x62, 0xc6, 0x5c, 0x9f, 0xbf, 0xfa, 0x90, 0x03,
++	0xc9, 0x72, 0x26, 0xb6, 0x1b, 0xc2, 0xb7, 0x3f,
++	0xf2, 0x13, 0x77, 0xf2, 0x8d, 0xb9, 0x47, 0xd0,
++	0x53, 0xdd, 0xc8, 0x91, 0x83, 0x8b, 0xb1, 0xce,
++	0xa3, 0xfe, 0xcd, 0xd9, 0xdd, 0x92, 0x7b, 0xdb,
++	0xb8, 0xfb, 0xc9, 0x2d, 0x01, 0x59, 0x39, 0x52,
++	0xad, 0x1b, 0xec, 0xcf, 0xd7, 0x70, 0x13, 0x21,
++	0xf5, 0x47, 0xaa, 0x18, 0x21, 0x5c, 0xc9, 0x9a,
++	0xd2, 0x6b, 0x05, 0x9c, 0x01, 0xa1, 0xda, 0x35,
++	0x5d, 0xb3, 0x70, 0xe6, 0xa9, 0x80, 0x8b, 0x91,
++	0xb7, 0xb3, 0x5f, 0x24, 0x9a, 0xb7, 0xd1, 0x6b,
++	0xa1, 0x1c, 0x50, 0xba, 0x49, 0xe0, 0xee, 0x2e,
++	0x75, 0xac, 0x69, 0xc0, 0xeb, 0x03, 0xdd, 0x19,
++	0xe5, 0xf6, 0x06, 0xdd, 0xc3, 0xd7, 0x2b, 0x07,
++	0x07, 0x30, 0xa7, 0x19, 0x0c, 0xbf, 0xe6, 0x18,
++	0xcc, 0xb1, 0x01, 0x11, 0x85, 0x77, 0x1d, 0x96,
++	0xa7, 0xa3, 0x00, 0x84, 0x02, 0xa2, 0x83, 0x68,
++	0xda, 0x17, 0x27, 0xc8, 0x7f, 0x23, 0xb7, 0xf4,
++	0x13, 0x85, 0xcf, 0xdd, 0x7a, 0x7d, 0x24, 0x57,
++	0xfe, 0x05, 0x93, 0xf5, 0x74, 0xce, 0xed, 0x0c,
++	0x20, 0x98, 0x8d, 0x92, 0x30, 0xa1, 0x29, 0x23,
++	0x1a, 0xa0, 0x4f, 0x69, 0x56, 0x4c, 0xe1, 0xc8,
++	0xce, 0xf6, 0x9a, 0x0c, 0xa4, 0xfa, 0x04, 0xf6,
++	0x62, 0x95, 0xf2, 0xfa, 0xc7, 0x40, 0x68, 0x40,
++	0x8f, 0x41, 0xda, 0xb4, 0x26, 0x6f, 0x70, 0xab,
++	0x40, 0x61, 0xa4, 0x0e, 0x75, 0xfb, 0x86, 0xeb,
++	0x9d, 0x9a, 0x1f, 0xec, 0x76, 0x99, 0xe7, 0xea,
++	0xaa, 0x1e, 0x2d, 0xb5, 0xd4, 0xa6, 0x1a, 0xb8,
++	0x61, 0x0a, 0x1d, 0x16, 0x5b, 0x98, 0xc2, 0x31,
++	0x40, 0xe7, 0x23, 0x1d, 0x66, 0x99, 0xc8, 0xc0,
++	0xd7, 0xce, 0xf3, 0x57, 0x40, 0x04, 0x3f, 0xfc,
++	0xea, 0xb3, 0xfc, 0xd2, 0xd3, 0x99, 0xa4, 0x94,
++	0x69, 0xa0, 0xef, 0xd1, 0x85, 0xb3, 0xa6, 0xb1,
++	0x28, 0xbf, 0x94, 0x67, 0x22, 0xc3, 0x36, 0x46,
++	0xf8, 0xd2, 0x0f, 0x5f, 0xf4, 0x59, 0x80, 0xe6,
++	0x2d, 0x43, 0x08, 0x7d, 0x19, 0x09, 0x97, 0xa7,
++	0x4c, 0x3d, 0x8d, 0xba, 0x65, 0x62, 0xa3, 0x71,
++	0x33, 0x29, 0x62, 0xdb, 0xc1, 0x33, 0x34, 0x1a,
++	0x63, 0x33, 0x16, 0xb6, 0x64, 0x7e, 0xab, 0x33,
++	0xf0, 0xe6, 0x26, 0x68, 0xba, 0x1d, 0x2e, 0x38,
++	0x08, 0xe6, 0x02, 0xd3, 0x25, 0x2c, 0x47, 0x23,
++	0x58, 0x34, 0x0f, 0x9d, 0x63, 0x4f, 0x63, 0xbb,
++	0x7f, 0x3b, 0x34, 0x38, 0xa7, 0xb5, 0x8d, 0x65,
++	0xd9, 0x9f, 0x79, 0x55, 0x3e, 0x4d, 0xe7, 0x73,
++	0xd8, 0xf6, 0x98, 0x97, 0x84, 0x60, 0x9c, 0xc8,
++	0xa9, 0x3c, 0xf6, 0xdc, 0x12, 0x5c, 0xe1, 0xbb,
++	0x0b, 0x8b, 0x98, 0x9c, 0x9d, 0x26, 0x7c, 0x4a,
++	0xe6, 0x46, 0x36, 0x58, 0x21, 0x4a, 0xee, 0xca,
++	0xd7, 0x3b, 0xc2, 0x6c, 0x49, 0x2f, 0xe5, 0xd5,
++	0x03, 0x59, 0x84, 0x53, 0xcb, 0xfe, 0x92, 0x71,
++	0x2e, 0x7c, 0x21, 0xcc, 0x99, 0x85, 0x7f, 0xb8,
++	0x74, 0x90, 0x13, 0x42, 0x3f, 0xe0, 0x6b, 0x1d,
++	0xf2, 0x4d, 0x54, 0xd4, 0xfc, 0x3a, 0x05, 0xe6,
++	0x74, 0xaf, 0xa6, 0xa0, 0x2a, 0x20, 0x23, 0x5d,
++	0x34, 0x5c, 0xd9, 0x3e, 0x4e, 0xfa, 0x93, 0xe7,
++	0xaa, 0xe9, 0x6f, 0x08, 0x43, 0x67, 0x41, 0xc5,
++	0xad, 0xfb, 0x31, 0x95, 0x82, 0x73, 0x32, 0xd8,
++	0xa6, 0xa3, 0xed, 0x0e, 0x2d, 0xf6, 0x5f, 0xfd,
++	0x80, 0xa6, 0x7a, 0xe0, 0xdf, 0x78, 0x15, 0x29,
++	0x74, 0x33, 0xd0, 0x9e, 0x83, 0x86, 0x72, 0x22,
++	0x57, 0x29, 0xb9, 0x9e, 0x5d, 0xd3, 0x1a, 0xb5,
++	0x96, 0x72, 0x41, 0x3d, 0xf1, 0x64, 0x43, 0x67,
++	0xee, 0xaa, 0x5c, 0xd3, 0x9a, 0x96, 0x13, 0x11,
++	0x5d, 0xf3, 0x0c, 0x87, 0x82, 0x1e, 0x41, 0x9e,
++	0xd0, 0x27, 0xd7, 0x54, 0x3b, 0x67, 0x73, 0x09,
++	0x91, 0xe9, 0xd5, 0x36, 0xa7, 0xb5, 0x55, 0xe4,
++	0xf3, 0x21, 0x51, 0x49, 0x22, 0x07, 0x55, 0x4f,
++	0x44, 0x4b, 0xd2, 0x15, 0x93, 0x17, 0x2a, 0xfa,
++	0x4d, 0x4a, 0x57, 0xdb, 0x4c, 0xa6, 0xeb, 0xec,
++	0x53, 0x25, 0x6c, 0x21, 0xed, 0x00, 0x4c, 0x3b,
++	0xca, 0x14, 0x57, 0xa9, 0xd6, 0x6a, 0xcd, 0x8d,
++	0x5e, 0x74, 0xac, 0x72, 0xc1, 0x97, 0xe5, 0x1b,
++	0x45, 0x4e, 0xda, 0xfc, 0xcc, 0x40, 0xe8, 0x48,
++	0x88, 0x0b, 0xa3, 0xe3, 0x8d, 0x83, 0x42, 0xc3,
++	0x23, 0xfd, 0x68, 0xb5, 0x8e, 0xf1, 0x9d, 0x63,
++	0x77, 0xe9, 0xa3, 0x8e, 0x8c, 0x26, 0x6b, 0xbd,
++	0x72, 0x73, 0x35, 0x0c, 0x03, 0xf8, 0x43, 0x78,
++	0x52, 0x71, 0x15, 0x1f, 0x71, 0x5d, 0x6e, 0xed,
++	0xb9, 0xcc, 0x86, 0x30, 0xdb, 0x2b, 0xd3, 0x82,
++	0x88, 0x23, 0x71, 0x90, 0x53, 0x5c, 0xa9, 0x2f,
++	0x76, 0x01, 0xb7, 0x9a, 0xfe, 0x43, 0x55, 0xa3,
++	0x04, 0x9b, 0x0e, 0xe4, 0x59, 0xdf, 0xc9, 0xe9,
++	0xb1, 0xea, 0x29, 0x28, 0x3c, 0x5c, 0xae, 0x72,
++	0x84, 0xb6, 0xc6, 0xeb, 0x0c, 0x27, 0x07, 0x74,
++	0x90, 0x0d, 0x31, 0xb0, 0x00, 0x77, 0xe9, 0x40,
++	0x70, 0x6f, 0x68, 0xa7, 0xfd, 0x06, 0xec, 0x4b,
++	0xc0, 0xb7, 0xac, 0xbc, 0x33, 0xb7, 0x6d, 0x0a,
++	0xbd, 0x12, 0x1b, 0x59, 0xcb, 0xdd, 0x32, 0xf5,
++	0x1d, 0x94, 0x57, 0x76, 0x9e, 0x0c, 0x18, 0x98,
++	0x71, 0xd7, 0x2a, 0xdb, 0x0b, 0x7b, 0xa7, 0x71,
++	0xb7, 0x67, 0x81, 0x23, 0x96, 0xae, 0xb9, 0x7e,
++	0x32, 0x43, 0x92, 0x8a, 0x19, 0xa0, 0xc4, 0xd4,
++	0x3b, 0x57, 0xf9, 0x4a, 0x2c, 0xfb, 0x51, 0x46,
++	0xbb, 0xcb, 0x5d, 0xb3, 0xef, 0x13, 0x93, 0x6e,
++	0x68, 0x42, 0x54, 0x57, 0xd3, 0x6a, 0x3a, 0x8f,
++	0x9d, 0x66, 0xbf, 0xbd, 0x36, 0x23, 0xf5, 0x93,
++	0x83, 0x7b, 0x9c, 0xc0, 0xdd, 0xc5, 0x49, 0xc0,
++	0x64, 0xed, 0x07, 0x12, 0xb3, 0xe6, 0xe4, 0xe5,
++	0x38, 0x95, 0x23, 0xb1, 0xa0, 0x3b, 0x1a, 0x61,
++	0xda, 0x17, 0xac, 0xc3, 0x58, 0xdd, 0x74, 0x64,
++	0x22, 0x11, 0xe8, 0x32, 0x1d, 0x16, 0x93, 0x85,
++	0x99, 0xa5, 0x9c, 0x34, 0x55, 0xb1, 0xe9, 0x20,
++	0x72, 0xc9, 0x28, 0x7b, 0x79, 0x00, 0xa1, 0xa6,
++	0xa3, 0x27, 0x40, 0x18, 0x8a, 0x54, 0xe0, 0xcc,
++	0xe8, 0x4e, 0x8e, 0x43, 0x96, 0xe7, 0x3f, 0xc8,
++	0xe9, 0xb2, 0xf9, 0xc9, 0xda, 0x04, 0x71, 0x50,
++	0x47, 0xe4, 0xaa, 0xce, 0xa2, 0x30, 0xc8, 0xe4,
++	0xac, 0xc7, 0x0d, 0x06, 0x2e, 0xe6, 0xe8, 0x80,
++	0x36, 0x29, 0x9e, 0x01, 0xb8, 0xc3, 0xf0, 0xa0,
++	0x5d, 0x7a, 0xca, 0x4d, 0xa0, 0x57, 0xbd, 0x2a,
++	0x45, 0xa7, 0x7f, 0x9c, 0x93, 0x07, 0x8f, 0x35,
++	0x67, 0x92, 0xe3, 0xe9, 0x7f, 0xa8, 0x61, 0x43,
++	0x9e, 0x25, 0x4f, 0x33, 0x76, 0x13, 0x6e, 0x12,
++	0xb9, 0xdd, 0xa4, 0x7c, 0x08, 0x9f, 0x7c, 0xe7,
++	0x0a, 0x8d, 0x84, 0x06, 0xa4, 0x33, 0x17, 0x34,
++	0x5e, 0x10, 0x7c, 0xc0, 0xa8, 0x3d, 0x1f, 0x42,
++	0x20, 0x51, 0x65, 0x5d, 0x09, 0xc3, 0xaa, 0xc0,
++	0xc8, 0x0d, 0xf0, 0x79, 0xbc, 0x20, 0x1b, 0x95,
++	0xe7, 0x06, 0x7d, 0x47, 0x20, 0x03, 0x1a, 0x74,
++	0xdd, 0xe2, 0xd4, 0xae, 0x38, 0x71, 0x9b, 0xf5,
++	0x80, 0xec, 0x08, 0x4e, 0x56, 0xba, 0x76, 0x12,
++	0x1a, 0xdf, 0x48, 0xf3, 0xae, 0xb3, 0xe6, 0xe6,
++	0xbe, 0xc0, 0x91, 0x2e, 0x01, 0xb3, 0x01, 0x86,
++	0xa2, 0xb9, 0x52, 0xd1, 0x21, 0xae, 0xd4, 0x97,
++	0x1d, 0xef, 0x41, 0x12, 0x95, 0x3d, 0x48, 0x45,
++	0x1c, 0x56, 0x32, 0x8f, 0xb8, 0x43, 0xbb, 0x19,
++	0xf3, 0xca, 0xe9, 0xeb, 0x6d, 0x84, 0xbe, 0x86,
++	0x06, 0xe2, 0x36, 0xb2, 0x62, 0x9d, 0xd3, 0x4c,
++	0x48, 0x18, 0x54, 0x13, 0x4e, 0xcf, 0xfd, 0xba,
++	0x84, 0xb9, 0x30, 0x53, 0xcf, 0xfb, 0xb9, 0x29,
++	0x8f, 0xdc, 0x9f, 0xef, 0x60, 0x0b, 0x64, 0xf6,
++	0x8b, 0xee, 0xa6, 0x91, 0xc2, 0x41, 0x6c, 0xf6,
++	0xfa, 0x79, 0x67, 0x4b, 0xc1, 0x3f, 0xaf, 0x09,
++	0x81, 0xd4, 0x5d, 0xcb, 0x09, 0xdf, 0x36, 0x31,
++	0xc0, 0x14, 0x3c, 0x7c, 0x0e, 0x65, 0x95, 0x99,
++	0x6d, 0xa3, 0xf4, 0xd7, 0x38, 0xee, 0x1a, 0x2b,
++	0x37, 0xe2, 0xa4, 0x3b, 0x4b, 0xd0, 0x65, 0xca,
++	0xf8, 0xc3, 0xe8, 0x15, 0x20, 0xef, 0xf2, 0x00,
++	0xfd, 0x01, 0x09, 0xc5, 0xc8, 0x17, 0x04, 0x93,
++	0xd0, 0x93, 0x03, 0x55, 0xc5, 0xfe, 0x32, 0xa3,
++	0x3e, 0x28, 0x2d, 0x3b, 0x93, 0x8a, 0xcc, 0x07,
++	0x72, 0x80, 0x8b, 0x74, 0x16, 0x24, 0xbb, 0xda,
++	0x94, 0x39, 0x30, 0x8f, 0xb1, 0xcd, 0x4a, 0x90,
++	0x92, 0x7c, 0x14, 0x8f, 0x95, 0x4e, 0xac, 0x9b,
++	0xd8, 0x8f, 0x1a, 0x87, 0xa4, 0x32, 0x27, 0x8a,
++	0xba, 0xf7, 0x41, 0xcf, 0x84, 0x37, 0x19, 0xe6,
++	0x06, 0xf5, 0x0e, 0xcf, 0x36, 0xf5, 0x9e, 0x6c,
++	0xde, 0xbc, 0xff, 0x64, 0x7e, 0x4e, 0x59, 0x57,
++	0x48, 0xfe, 0x14, 0xf7, 0x9c, 0x93, 0x5d, 0x15,
++	0xad, 0xcc, 0x11, 0xb1, 0x17, 0x18, 0xb2, 0x7e,
++	0xcc, 0xab, 0xe9, 0xce, 0x7d, 0x77, 0x5b, 0x51,
++	0x1b, 0x1e, 0x20, 0xa8, 0x32, 0x06, 0x0e, 0x75,
++	0x93, 0xac, 0xdb, 0x35, 0x37, 0x1f, 0xe9, 0x19,
++	0x1d, 0xb4, 0x71, 0x97, 0xd6, 0x4e, 0x2c, 0x08,
++	0xa5, 0x13, 0xf9, 0x0e, 0x7e, 0x78, 0x6e, 0x14,
++	0xe0, 0xa9, 0xb9, 0x96, 0x4c, 0x80, 0x82, 0xba,
++	0x17, 0xb3, 0x9d, 0x69, 0xb0, 0x84, 0x46, 0xff,
++	0xf9, 0x52, 0x79, 0x94, 0x58, 0x3a, 0x62, 0x90,
++	0x15, 0x35, 0x71, 0x10, 0x37, 0xed, 0xa1, 0x8e,
++	0x53, 0x6e, 0xf4, 0x26, 0x57, 0x93, 0x15, 0x93,
++	0xf6, 0x81, 0x2c, 0x5a, 0x10, 0xda, 0x92, 0xad,
++	0x2f, 0xdb, 0x28, 0x31, 0x2d, 0x55, 0x04, 0xd2,
++	0x06, 0x28, 0x8c, 0x1e, 0xdc, 0xea, 0x54, 0xac,
++	0xff, 0xb7, 0x6c, 0x30, 0x15, 0xd4, 0xb4, 0x0d,
++	0x00, 0x93, 0x57, 0xdd, 0xd2, 0x07, 0x07, 0x06,
++	0xd9, 0x43, 0x9b, 0xcd, 0x3a, 0xf4, 0x7d, 0x4c,
++	0x36, 0x5d, 0x23, 0xa2, 0xcc, 0x57, 0x40, 0x91,
++	0xe9, 0x2c, 0x2f, 0x2c, 0xd5, 0x30, 0x9b, 0x17,
++	0xb0, 0xc9, 0xf7, 0xa7, 0x2f, 0xd1, 0x93, 0x20,
++	0x6b, 0xc6, 0xc1, 0xe4, 0x6f, 0xcb, 0xd1, 0xe7,
++	0x09, 0x0f, 0x9e, 0xdc, 0xaa, 0x9f, 0x2f, 0xdf,
++	0x56, 0x9f, 0xd4, 0x33, 0x04, 0xaf, 0xd3, 0x6c,
++	0x58, 0x61, 0xf0, 0x30, 0xec, 0xf2, 0x7f, 0xf2,
++	0x9c, 0xdf, 0x39, 0xbb, 0x6f, 0xa2, 0x8c, 0x7e,
++	0xc4, 0x22, 0x51, 0x71, 0xc0, 0x4d, 0x14, 0x1a,
++	0xc4, 0xcd, 0x04, 0xd9, 0x87, 0x08, 0x50, 0x05,
++	0xcc, 0xaf, 0xf6, 0xf0, 0x8f, 0x92, 0x54, 0x58,
++	0xc2, 0xc7, 0x09, 0x7a, 0x59, 0x02, 0x05, 0xe8,
++	0xb0, 0x86, 0xd9, 0xbf, 0x7b, 0x35, 0x51, 0x4d,
++	0xaf, 0x08, 0x97, 0x2c, 0x65, 0xda, 0x2a, 0x71,
++	0x3a, 0xa8, 0x51, 0xcc, 0xf2, 0x73, 0x27, 0xc3,
++	0xfd, 0x62, 0xcf, 0xe3, 0xb2, 0xca, 0xcb, 0xbe,
++	0x1a, 0x0a, 0xa1, 0x34, 0x7b, 0x77, 0xc4, 0x62,
++	0x68, 0x78, 0x5f, 0x94, 0x07, 0x04, 0x65, 0x16,
++	0x4b, 0x61, 0xcb, 0xff, 0x75, 0x26, 0x50, 0x66,
++	0x1f, 0x6e, 0x93, 0xf8, 0xc5, 0x51, 0xeb, 0xa4,
++	0x4a, 0x48, 0x68, 0x6b, 0xe2, 0x5e, 0x44, 0xb2,
++	0x50, 0x2c, 0x6c, 0xae, 0x79, 0x4e, 0x66, 0x35,
++	0x81, 0x50, 0xac, 0xbc, 0x3f, 0xb1, 0x0c, 0xf3,
++	0x05, 0x3c, 0x4a, 0xa3, 0x6c, 0x2a, 0x79, 0xb4,
++	0xb7, 0xab, 0xca, 0xc7, 0x9b, 0x8e, 0xcd, 0x5f,
++	0x11, 0x03, 0xcb, 0x30, 0xa3, 0xab, 0xda, 0xfe,
++	0x64, 0xb9, 0xbb, 0xd8, 0x5e, 0x3a, 0x1a, 0x56,
++	0xe5, 0x05, 0x48, 0x90, 0x1e, 0x61, 0x69, 0x1b,
++	0x22, 0xe6, 0x1a, 0x3c, 0x75, 0xad, 0x1f, 0x37,
++	0x28, 0xdc, 0xe4, 0x6d, 0xbd, 0x42, 0xdc, 0xd3,
++	0xc8, 0xb6, 0x1c, 0x48, 0xfe, 0x94, 0x77, 0x7f,
++	0xbd, 0x62, 0xac, 0xa3, 0x47, 0x27, 0xcf, 0x5f,
++	0xd9, 0xdb, 0xaf, 0xec, 0xf7, 0x5e, 0xc1, 0xb0,
++	0x9d, 0x01, 0x26, 0x99, 0x7e, 0x8f, 0x03, 0x70,
++	0xb5, 0x42, 0xbe, 0x67, 0x28, 0x1b, 0x7c, 0xbd,
++	0x61, 0x21, 0x97, 0xcc, 0x5c, 0xe1, 0x97, 0x8f,
++	0x8d, 0xde, 0x2b, 0xaa, 0xa7, 0x71, 0x1d, 0x1e,
++	0x02, 0x73, 0x70, 0x58, 0x32, 0x5b, 0x1d, 0x67,
++	0x3d, 0xe0, 0x74, 0x4f, 0x03, 0xf2, 0x70, 0x51,
++	0x79, 0xf1, 0x61, 0x70, 0x15, 0x74, 0x9d, 0x23,
++	0x89, 0xde, 0xac, 0xfd, 0xde, 0xd0, 0x1f, 0xc3,
++	0x87, 0x44, 0x35, 0x4b, 0xe5, 0xb0, 0x60, 0xc5,
++	0x22, 0xe4, 0x9e, 0xca, 0xeb, 0xd5, 0x3a, 0x09,
++	0x45, 0xa4, 0xdb, 0xfa, 0x3f, 0xeb, 0x1b, 0xc7,
++	0xc8, 0x14, 0x99, 0x51, 0x92, 0x10, 0xed, 0xed,
++	0x28, 0xe0, 0xa1, 0xf8, 0x26, 0xcf, 0xcd, 0xcb,
++	0x63, 0xa1, 0x3b, 0xe3, 0xdf, 0x7e, 0xfe, 0xa6,
++	0xf0, 0x81, 0x9a, 0xbf, 0x55, 0xde, 0x54, 0xd5,
++	0x56, 0x60, 0x98, 0x10, 0x68, 0xf4, 0x38, 0x96,
++	0x8e, 0x6f, 0x1d, 0x44, 0x7f, 0xd6, 0x2f, 0xfe,
++	0x55, 0xfb, 0x0c, 0x7e, 0x67, 0xe2, 0x61, 0x44,
++	0xed, 0xf2, 0x35, 0x30, 0x5d, 0xe9, 0xc7, 0xd6,
++	0x6d, 0xe0, 0xa0, 0xed, 0xf3, 0xfc, 0xd8, 0x3e,
++	0x0a, 0x7b, 0xcd, 0xaf, 0x65, 0x68, 0x18, 0xc0,
++	0xec, 0x04, 0x1c, 0x74, 0x6d, 0xe2, 0x6e, 0x79,
++	0xd4, 0x11, 0x2b, 0x62, 0xd5, 0x27, 0xad, 0x4f,
++	0x01, 0x59, 0x73, 0xcc, 0x6a, 0x53, 0xfb, 0x2d,
++	0xd5, 0x4e, 0x99, 0x21, 0x65, 0x4d, 0xf5, 0x82,
++	0xf7, 0xd8, 0x42, 0xce, 0x6f, 0x3d, 0x36, 0x47,
++	0xf1, 0x05, 0x16, 0xe8, 0x1b, 0x6a, 0x8f, 0x93,
++	0xf2, 0x8f, 0x37, 0x40, 0x12, 0x28, 0xa3, 0xe6,
++	0xb9, 0x17, 0x4a, 0x1f, 0xb1, 0xd1, 0x66, 0x69,
++	0x86, 0xc4, 0xfc, 0x97, 0xae, 0x3f, 0x8f, 0x1e,
++	0x2b, 0xdf, 0xcd, 0xf9, 0x3c
++};
++static const u8 enc_assoc011[] __initconst = {
++	0xd6, 0x31, 0xda, 0x5d, 0x42, 0x5e, 0xd7
++};
++static const u8 enc_nonce011[] __initconst = {
++	0xfd, 0x87, 0xd4, 0xd8, 0x62, 0xfd, 0xec, 0xaa
++};
++static const u8 enc_key011[] __initconst = {
++	0x35, 0x4e, 0xb5, 0x70, 0x50, 0x42, 0x8a, 0x85,
++	0xf2, 0xfb, 0xed, 0x7b, 0xd0, 0x9e, 0x97, 0xca,
++	0xfa, 0x98, 0x66, 0x63, 0xee, 0x37, 0xcc, 0x52,
++	0xfe, 0xd1, 0xdf, 0x95, 0x15, 0x34, 0x29, 0x38
++};
++
++static const u8 enc_input012[] __initconst = {
++	0x74, 0xa6, 0x3e, 0xe4, 0xb1, 0xcb, 0xaf, 0xb0,
++	0x40, 0xe5, 0x0f, 0x9e, 0xf1, 0xf2, 0x89, 0xb5,
++	0x42, 0x34, 0x8a, 0xa1, 0x03, 0xb7, 0xe9, 0x57,
++	0x46, 0xbe, 0x20, 0xe4, 0x6e, 0xb0, 0xeb, 0xff,
++	0xea, 0x07, 0x7e, 0xef, 0xe2, 0x55, 0x9f, 0xe5,
++	0x78, 0x3a, 0xb7, 0x83, 0xc2, 0x18, 0x40, 0x7b,
++	0xeb, 0xcd, 0x81, 0xfb, 0x90, 0x12, 0x9e, 0x46,
++	0xa9, 0xd6, 0x4a, 0xba, 0xb0, 0x62, 0xdb, 0x6b,
++	0x99, 0xc4, 0xdb, 0x54, 0x4b, 0xb8, 0xa5, 0x71,
++	0xcb, 0xcd, 0x63, 0x32, 0x55, 0xfb, 0x31, 0xf0,
++	0x38, 0xf5, 0xbe, 0x78, 0xe4, 0x45, 0xce, 0x1b,
++	0x6a, 0x5b, 0x0e, 0xf4, 0x16, 0xe4, 0xb1, 0x3d,
++	0xf6, 0x63, 0x7b, 0xa7, 0x0c, 0xde, 0x6f, 0x8f,
++	0x74, 0xdf, 0xe0, 0x1e, 0x9d, 0xce, 0x8f, 0x24,
++	0xef, 0x23, 0x35, 0x33, 0x7b, 0x83, 0x34, 0x23,
++	0x58, 0x74, 0x14, 0x77, 0x1f, 0xc2, 0x4f, 0x4e,
++	0xc6, 0x89, 0xf9, 0x52, 0x09, 0x37, 0x64, 0x14,
++	0xc4, 0x01, 0x6b, 0x9d, 0x77, 0xe8, 0x90, 0x5d,
++	0xa8, 0x4a, 0x2a, 0xef, 0x5c, 0x7f, 0xeb, 0xbb,
++	0xb2, 0xc6, 0x93, 0x99, 0x66, 0xdc, 0x7f, 0xd4,
++	0x9e, 0x2a, 0xca, 0x8d, 0xdb, 0xe7, 0x20, 0xcf,
++	0xe4, 0x73, 0xae, 0x49, 0x7d, 0x64, 0x0f, 0x0e,
++	0x28, 0x46, 0xa9, 0xa8, 0x32, 0xe4, 0x0e, 0xf6,
++	0x51, 0x53, 0xb8, 0x3c, 0xb1, 0xff, 0xa3, 0x33,
++	0x41, 0x75, 0xff, 0xf1, 0x6f, 0xf1, 0xfb, 0xbb,
++	0x83, 0x7f, 0x06, 0x9b, 0xe7, 0x1b, 0x0a, 0xe0,
++	0x5c, 0x33, 0x60, 0x5b, 0xdb, 0x5b, 0xed, 0xfe,
++	0xa5, 0x16, 0x19, 0x72, 0xa3, 0x64, 0x23, 0x00,
++	0x02, 0xc7, 0xf3, 0x6a, 0x81, 0x3e, 0x44, 0x1d,
++	0x79, 0x15, 0x5f, 0x9a, 0xde, 0xe2, 0xfd, 0x1b,
++	0x73, 0xc1, 0xbc, 0x23, 0xba, 0x31, 0xd2, 0x50,
++	0xd5, 0xad, 0x7f, 0x74, 0xa7, 0xc9, 0xf8, 0x3e,
++	0x2b, 0x26, 0x10, 0xf6, 0x03, 0x36, 0x74, 0xe4,
++	0x0e, 0x6a, 0x72, 0xb7, 0x73, 0x0a, 0x42, 0x28,
++	0xc2, 0xad, 0x5e, 0x03, 0xbe, 0xb8, 0x0b, 0xa8,
++	0x5b, 0xd4, 0xb8, 0xba, 0x52, 0x89, 0xb1, 0x9b,
++	0xc1, 0xc3, 0x65, 0x87, 0xed, 0xa5, 0xf4, 0x86,
++	0xfd, 0x41, 0x80, 0x91, 0x27, 0x59, 0x53, 0x67,
++	0x15, 0x78, 0x54, 0x8b, 0x2d, 0x3d, 0xc7, 0xff,
++	0x02, 0x92, 0x07, 0x5f, 0x7a, 0x4b, 0x60, 0x59,
++	0x3c, 0x6f, 0x5c, 0xd8, 0xec, 0x95, 0xd2, 0xfe,
++	0xa0, 0x3b, 0xd8, 0x3f, 0xd1, 0x69, 0xa6, 0xd6,
++	0x41, 0xb2, 0xf4, 0x4d, 0x12, 0xf4, 0x58, 0x3e,
++	0x66, 0x64, 0x80, 0x31, 0x9b, 0xa8, 0x4c, 0x8b,
++	0x07, 0xb2, 0xec, 0x66, 0x94, 0x66, 0x47, 0x50,
++	0x50, 0x5f, 0x18, 0x0b, 0x0e, 0xd6, 0xc0, 0x39,
++	0x21, 0x13, 0x9e, 0x33, 0xbc, 0x79, 0x36, 0x02,
++	0x96, 0x70, 0xf0, 0x48, 0x67, 0x2f, 0x26, 0xe9,
++	0x6d, 0x10, 0xbb, 0xd6, 0x3f, 0xd1, 0x64, 0x7a,
++	0x2e, 0xbe, 0x0c, 0x61, 0xf0, 0x75, 0x42, 0x38,
++	0x23, 0xb1, 0x9e, 0x9f, 0x7c, 0x67, 0x66, 0xd9,
++	0x58, 0x9a, 0xf1, 0xbb, 0x41, 0x2a, 0x8d, 0x65,
++	0x84, 0x94, 0xfc, 0xdc, 0x6a, 0x50, 0x64, 0xdb,
++	0x56, 0x33, 0x76, 0x00, 0x10, 0xed, 0xbe, 0xd2,
++	0x12, 0xf6, 0xf6, 0x1b, 0xa2, 0x16, 0xde, 0xae,
++	0x31, 0x95, 0xdd, 0xb1, 0x08, 0x7e, 0x4e, 0xee,
++	0xe7, 0xf9, 0xa5, 0xfb, 0x5b, 0x61, 0x43, 0x00,
++	0x40, 0xf6, 0x7e, 0x02, 0x04, 0x32, 0x4e, 0x0c,
++	0xe2, 0x66, 0x0d, 0xd7, 0x07, 0x98, 0x0e, 0xf8,
++	0x72, 0x34, 0x6d, 0x95, 0x86, 0xd7, 0xcb, 0x31,
++	0x54, 0x47, 0xd0, 0x38, 0x29, 0x9c, 0x5a, 0x68,
++	0xd4, 0x87, 0x76, 0xc9, 0xe7, 0x7e, 0xe3, 0xf4,
++	0x81, 0x6d, 0x18, 0xcb, 0xc9, 0x05, 0xaf, 0xa0,
++	0xfb, 0x66, 0xf7, 0xf1, 0x1c, 0xc6, 0x14, 0x11,
++	0x4f, 0x2b, 0x79, 0x42, 0x8b, 0xbc, 0xac, 0xe7,
++	0x6c, 0xfe, 0x0f, 0x58, 0xe7, 0x7c, 0x78, 0x39,
++	0x30, 0xb0, 0x66, 0x2c, 0x9b, 0x6d, 0x3a, 0xe1,
++	0xcf, 0xc9, 0xa4, 0x0e, 0x6d, 0x6d, 0x8a, 0xa1,
++	0x3a, 0xe7, 0x28, 0xd4, 0x78, 0x4c, 0xa6, 0xa2,
++	0x2a, 0xa6, 0x03, 0x30, 0xd7, 0xa8, 0x25, 0x66,
++	0x87, 0x2f, 0x69, 0x5c, 0x4e, 0xdd, 0xa5, 0x49,
++	0x5d, 0x37, 0x4a, 0x59, 0xc4, 0xaf, 0x1f, 0xa2,
++	0xe4, 0xf8, 0xa6, 0x12, 0x97, 0xd5, 0x79, 0xf5,
++	0xe2, 0x4a, 0x2b, 0x5f, 0x61, 0xe4, 0x9e, 0xe3,
++	0xee, 0xb8, 0xa7, 0x5b, 0x2f, 0xf4, 0x9e, 0x6c,
++	0xfb, 0xd1, 0xc6, 0x56, 0x77, 0xba, 0x75, 0xaa,
++	0x3d, 0x1a, 0xa8, 0x0b, 0xb3, 0x68, 0x24, 0x00,
++	0x10, 0x7f, 0xfd, 0xd7, 0xa1, 0x8d, 0x83, 0x54,
++	0x4f, 0x1f, 0xd8, 0x2a, 0xbe, 0x8a, 0x0c, 0x87,
++	0xab, 0xa2, 0xde, 0xc3, 0x39, 0xbf, 0x09, 0x03,
++	0xa5, 0xf3, 0x05, 0x28, 0xe1, 0xe1, 0xee, 0x39,
++	0x70, 0x9c, 0xd8, 0x81, 0x12, 0x1e, 0x02, 0x40,
++	0xd2, 0x6e, 0xf0, 0xeb, 0x1b, 0x3d, 0x22, 0xc6,
++	0xe5, 0xe3, 0xb4, 0x5a, 0x98, 0xbb, 0xf0, 0x22,
++	0x28, 0x8d, 0xe5, 0xd3, 0x16, 0x48, 0x24, 0xa5,
++	0xe6, 0x66, 0x0c, 0xf9, 0x08, 0xf9, 0x7e, 0x1e,
++	0xe1, 0x28, 0x26, 0x22, 0xc7, 0xc7, 0x0a, 0x32,
++	0x47, 0xfa, 0xa3, 0xbe, 0x3c, 0xc4, 0xc5, 0x53,
++	0x0a, 0xd5, 0x94, 0x4a, 0xd7, 0x93, 0xd8, 0x42,
++	0x99, 0xb9, 0x0a, 0xdb, 0x56, 0xf7, 0xb9, 0x1c,
++	0x53, 0x4f, 0xfa, 0xd3, 0x74, 0xad, 0xd9, 0x68,
++	0xf1, 0x1b, 0xdf, 0x61, 0xc6, 0x5e, 0xa8, 0x48,
++	0xfc, 0xd4, 0x4a, 0x4c, 0x3c, 0x32, 0xf7, 0x1c,
++	0x96, 0x21, 0x9b, 0xf9, 0xa3, 0xcc, 0x5a, 0xce,
++	0xd5, 0xd7, 0x08, 0x24, 0xf6, 0x1c, 0xfd, 0xdd,
++	0x38, 0xc2, 0x32, 0xe9, 0xb8, 0xe7, 0xb6, 0xfa,
++	0x9d, 0x45, 0x13, 0x2c, 0x83, 0xfd, 0x4a, 0x69,
++	0x82, 0xcd, 0xdc, 0xb3, 0x76, 0x0c, 0x9e, 0xd8,
++	0xf4, 0x1b, 0x45, 0x15, 0xb4, 0x97, 0xe7, 0x58,
++	0x34, 0xe2, 0x03, 0x29, 0x5a, 0xbf, 0xb6, 0xe0,
++	0x5d, 0x13, 0xd9, 0x2b, 0xb4, 0x80, 0xb2, 0x45,
++	0x81, 0x6a, 0x2e, 0x6c, 0x89, 0x7d, 0xee, 0xbb,
++	0x52, 0xdd, 0x1f, 0x18, 0xe7, 0x13, 0x6b, 0x33,
++	0x0e, 0xea, 0x36, 0x92, 0x77, 0x7b, 0x6d, 0x9c,
++	0x5a, 0x5f, 0x45, 0x7b, 0x7b, 0x35, 0x62, 0x23,
++	0xd1, 0xbf, 0x0f, 0xd0, 0x08, 0x1b, 0x2b, 0x80,
++	0x6b, 0x7e, 0xf1, 0x21, 0x47, 0xb0, 0x57, 0xd1,
++	0x98, 0x72, 0x90, 0x34, 0x1c, 0x20, 0x04, 0xff,
++	0x3d, 0x5c, 0xee, 0x0e, 0x57, 0x5f, 0x6f, 0x24,
++	0x4e, 0x3c, 0xea, 0xfc, 0xa5, 0xa9, 0x83, 0xc9,
++	0x61, 0xb4, 0x51, 0x24, 0xf8, 0x27, 0x5e, 0x46,
++	0x8c, 0xb1, 0x53, 0x02, 0x96, 0x35, 0xba, 0xb8,
++	0x4c, 0x71, 0xd3, 0x15, 0x59, 0x35, 0x22, 0x20,
++	0xad, 0x03, 0x9f, 0x66, 0x44, 0x3b, 0x9c, 0x35,
++	0x37, 0x1f, 0x9b, 0xbb, 0xf3, 0xdb, 0x35, 0x63,
++	0x30, 0x64, 0xaa, 0xa2, 0x06, 0xa8, 0x5d, 0xbb,
++	0xe1, 0x9f, 0x70, 0xec, 0x82, 0x11, 0x06, 0x36,
++	0xec, 0x8b, 0x69, 0x66, 0x24, 0x44, 0xc9, 0x4a,
++	0x57, 0xbb, 0x9b, 0x78, 0x13, 0xce, 0x9c, 0x0c,
++	0xba, 0x92, 0x93, 0x63, 0xb8, 0xe2, 0x95, 0x0f,
++	0x0f, 0x16, 0x39, 0x52, 0xfd, 0x3a, 0x6d, 0x02,
++	0x4b, 0xdf, 0x13, 0xd3, 0x2a, 0x22, 0xb4, 0x03,
++	0x7c, 0x54, 0x49, 0x96, 0x68, 0x54, 0x10, 0xfa,
++	0xef, 0xaa, 0x6c, 0xe8, 0x22, 0xdc, 0x71, 0x16,
++	0x13, 0x1a, 0xf6, 0x28, 0xe5, 0x6d, 0x77, 0x3d,
++	0xcd, 0x30, 0x63, 0xb1, 0x70, 0x52, 0xa1, 0xc5,
++	0x94, 0x5f, 0xcf, 0xe8, 0xb8, 0x26, 0x98, 0xf7,
++	0x06, 0xa0, 0x0a, 0x70, 0xfa, 0x03, 0x80, 0xac,
++	0xc1, 0xec, 0xd6, 0x4c, 0x54, 0xd7, 0xfe, 0x47,
++	0xb6, 0x88, 0x4a, 0xf7, 0x71, 0x24, 0xee, 0xf3,
++	0xd2, 0xc2, 0x4a, 0x7f, 0xfe, 0x61, 0xc7, 0x35,
++	0xc9, 0x37, 0x67, 0xcb, 0x24, 0x35, 0xda, 0x7e,
++	0xca, 0x5f, 0xf3, 0x8d, 0xd4, 0x13, 0x8e, 0xd6,
++	0xcb, 0x4d, 0x53, 0x8f, 0x53, 0x1f, 0xc0, 0x74,
++	0xf7, 0x53, 0xb9, 0x5e, 0x23, 0x37, 0xba, 0x6e,
++	0xe3, 0x9d, 0x07, 0x55, 0x25, 0x7b, 0xe6, 0x2a,
++	0x64, 0xd1, 0x32, 0xdd, 0x54, 0x1b, 0x4b, 0xc0,
++	0xe1, 0xd7, 0x69, 0x58, 0xf8, 0x93, 0x29, 0xc4,
++	0xdd, 0x23, 0x2f, 0xa5, 0xfc, 0x9d, 0x7e, 0xf8,
++	0xd4, 0x90, 0xcd, 0x82, 0x55, 0xdc, 0x16, 0x16,
++	0x9f, 0x07, 0x52, 0x9b, 0x9d, 0x25, 0xed, 0x32,
++	0xc5, 0x7b, 0xdf, 0xf6, 0x83, 0x46, 0x3d, 0x65,
++	0xb7, 0xef, 0x87, 0x7a, 0x12, 0x69, 0x8f, 0x06,
++	0x7c, 0x51, 0x15, 0x4a, 0x08, 0xe8, 0xac, 0x9a,
++	0x0c, 0x24, 0xa7, 0x27, 0xd8, 0x46, 0x2f, 0xe7,
++	0x01, 0x0e, 0x1c, 0xc6, 0x91, 0xb0, 0x6e, 0x85,
++	0x65, 0xf0, 0x29, 0x0d, 0x2e, 0x6b, 0x3b, 0xfb,
++	0x4b, 0xdf, 0xe4, 0x80, 0x93, 0x03, 0x66, 0x46,
++	0x3e, 0x8a, 0x6e, 0xf3, 0x5e, 0x4d, 0x62, 0x0e,
++	0x49, 0x05, 0xaf, 0xd4, 0xf8, 0x21, 0x20, 0x61,
++	0x1d, 0x39, 0x17, 0xf4, 0x61, 0x47, 0x95, 0xfb,
++	0x15, 0x2e, 0xb3, 0x4f, 0xd0, 0x5d, 0xf5, 0x7d,
++	0x40, 0xda, 0x90, 0x3c, 0x6b, 0xcb, 0x17, 0x00,
++	0x13, 0x3b, 0x64, 0x34, 0x1b, 0xf0, 0xf2, 0xe5,
++	0x3b, 0xb2, 0xc7, 0xd3, 0x5f, 0x3a, 0x44, 0xa6,
++	0x9b, 0xb7, 0x78, 0x0e, 0x42, 0x5d, 0x4c, 0xc1,
++	0xe9, 0xd2, 0xcb, 0xb7, 0x78, 0xd1, 0xfe, 0x9a,
++	0xb5, 0x07, 0xe9, 0xe0, 0xbe, 0xe2, 0x8a, 0xa7,
++	0x01, 0x83, 0x00, 0x8c, 0x5c, 0x08, 0xe6, 0x63,
++	0x12, 0x92, 0xb7, 0xb7, 0xa6, 0x19, 0x7d, 0x38,
++	0x13, 0x38, 0x92, 0x87, 0x24, 0xf9, 0x48, 0xb3,
++	0x5e, 0x87, 0x6a, 0x40, 0x39, 0x5c, 0x3f, 0xed,
++	0x8f, 0xee, 0xdb, 0x15, 0x82, 0x06, 0xda, 0x49,
++	0x21, 0x2b, 0xb5, 0xbf, 0x32, 0x7c, 0x9f, 0x42,
++	0x28, 0x63, 0xcf, 0xaf, 0x1e, 0xf8, 0xc6, 0xa0,
++	0xd1, 0x02, 0x43, 0x57, 0x62, 0xec, 0x9b, 0x0f,
++	0x01, 0x9e, 0x71, 0xd8, 0x87, 0x9d, 0x01, 0xc1,
++	0x58, 0x77, 0xd9, 0xaf, 0xb1, 0x10, 0x7e, 0xdd,
++	0xa6, 0x50, 0x96, 0xe5, 0xf0, 0x72, 0x00, 0x6d,
++	0x4b, 0xf8, 0x2a, 0x8f, 0x19, 0xf3, 0x22, 0x88,
++	0x11, 0x4a, 0x8b, 0x7c, 0xfd, 0xb7, 0xed, 0xe1,
++	0xf6, 0x40, 0x39, 0xe0, 0xe9, 0xf6, 0x3d, 0x25,
++	0xe6, 0x74, 0x3c, 0x58, 0x57, 0x7f, 0xe1, 0x22,
++	0x96, 0x47, 0x31, 0x91, 0xba, 0x70, 0x85, 0x28,
++	0x6b, 0x9f, 0x6e, 0x25, 0xac, 0x23, 0x66, 0x2f,
++	0x29, 0x88, 0x28, 0xce, 0x8c, 0x5c, 0x88, 0x53,
++	0xd1, 0x3b, 0xcc, 0x6a, 0x51, 0xb2, 0xe1, 0x28,
++	0x3f, 0x91, 0xb4, 0x0d, 0x00, 0x3a, 0xe3, 0xf8,
++	0xc3, 0x8f, 0xd7, 0x96, 0x62, 0x0e, 0x2e, 0xfc,
++	0xc8, 0x6c, 0x77, 0xa6, 0x1d, 0x22, 0xc1, 0xb8,
++	0xe6, 0x61, 0xd7, 0x67, 0x36, 0x13, 0x7b, 0xbb,
++	0x9b, 0x59, 0x09, 0xa6, 0xdf, 0xf7, 0x6b, 0xa3,
++	0x40, 0x1a, 0xf5, 0x4f, 0xb4, 0xda, 0xd3, 0xf3,
++	0x81, 0x93, 0xc6, 0x18, 0xd9, 0x26, 0xee, 0xac,
++	0xf0, 0xaa, 0xdf, 0xc5, 0x9c, 0xca, 0xc2, 0xa2,
++	0xcc, 0x7b, 0x5c, 0x24, 0xb0, 0xbc, 0xd0, 0x6a,
++	0x4d, 0x89, 0x09, 0xb8, 0x07, 0xfe, 0x87, 0xad,
++	0x0a, 0xea, 0xb8, 0x42, 0xf9, 0x5e, 0xb3, 0x3e,
++	0x36, 0x4c, 0xaf, 0x75, 0x9e, 0x1c, 0xeb, 0xbd,
++	0xbc, 0xbb, 0x80, 0x40, 0xa7, 0x3a, 0x30, 0xbf,
++	0xa8, 0x44, 0xf4, 0xeb, 0x38, 0xad, 0x29, 0xba,
++	0x23, 0xed, 0x41, 0x0c, 0xea, 0xd2, 0xbb, 0x41,
++	0x18, 0xd6, 0xb9, 0xba, 0x65, 0x2b, 0xa3, 0x91,
++	0x6d, 0x1f, 0xa9, 0xf4, 0xd1, 0x25, 0x8d, 0x4d,
++	0x38, 0xff, 0x64, 0xa0, 0xec, 0xde, 0xa6, 0xb6,
++	0x79, 0xab, 0x8e, 0x33, 0x6c, 0x47, 0xde, 0xaf,
++	0x94, 0xa4, 0xa5, 0x86, 0x77, 0x55, 0x09, 0x92,
++	0x81, 0x31, 0x76, 0xc7, 0x34, 0x22, 0x89, 0x8e,
++	0x3d, 0x26, 0x26, 0xd7, 0xfc, 0x1e, 0x16, 0x72,
++	0x13, 0x33, 0x63, 0xd5, 0x22, 0xbe, 0xb8, 0x04,
++	0x34, 0x84, 0x41, 0xbb, 0x80, 0xd0, 0x9f, 0x46,
++	0x48, 0x07, 0xa7, 0xfc, 0x2b, 0x3a, 0x75, 0x55,
++	0x8c, 0xc7, 0x6a, 0xbd, 0x7e, 0x46, 0x08, 0x84,
++	0x0f, 0xd5, 0x74, 0xc0, 0x82, 0x8e, 0xaa, 0x61,
++	0x05, 0x01, 0xb2, 0x47, 0x6e, 0x20, 0x6a, 0x2d,
++	0x58, 0x70, 0x48, 0x32, 0xa7, 0x37, 0xd2, 0xb8,
++	0x82, 0x1a, 0x51, 0xb9, 0x61, 0xdd, 0xfd, 0x9d,
++	0x6b, 0x0e, 0x18, 0x97, 0xf8, 0x45, 0x5f, 0x87,
++	0x10, 0xcf, 0x34, 0x72, 0x45, 0x26, 0x49, 0x70,
++	0xe7, 0xa3, 0x78, 0xe0, 0x52, 0x89, 0x84, 0x94,
++	0x83, 0x82, 0xc2, 0x69, 0x8f, 0xe3, 0xe1, 0x3f,
++	0x60, 0x74, 0x88, 0xc4, 0xf7, 0x75, 0x2c, 0xfb,
++	0xbd, 0xb6, 0xc4, 0x7e, 0x10, 0x0a, 0x6c, 0x90,
++	0x04, 0x9e, 0xc3, 0x3f, 0x59, 0x7c, 0xce, 0x31,
++	0x18, 0x60, 0x57, 0x73, 0x46, 0x94, 0x7d, 0x06,
++	0xa0, 0x6d, 0x44, 0xec, 0xa2, 0x0a, 0x9e, 0x05,
++	0x15, 0xef, 0xca, 0x5c, 0xbf, 0x00, 0xeb, 0xf7,
++	0x3d, 0x32, 0xd4, 0xa5, 0xef, 0x49, 0x89, 0x5e,
++	0x46, 0xb0, 0xa6, 0x63, 0x5b, 0x8a, 0x73, 0xae,
++	0x6f, 0xd5, 0x9d, 0xf8, 0x4f, 0x40, 0xb5, 0xb2,
++	0x6e, 0xd3, 0xb6, 0x01, 0xa9, 0x26, 0xa2, 0x21,
++	0xcf, 0x33, 0x7a, 0x3a, 0xa4, 0x23, 0x13, 0xb0,
++	0x69, 0x6a, 0xee, 0xce, 0xd8, 0x9d, 0x01, 0x1d,
++	0x50, 0xc1, 0x30, 0x6c, 0xb1, 0xcd, 0xa0, 0xf0,
++	0xf0, 0xa2, 0x64, 0x6f, 0xbb, 0xbf, 0x5e, 0xe6,
++	0xab, 0x87, 0xb4, 0x0f, 0x4f, 0x15, 0xaf, 0xb5,
++	0x25, 0xa1, 0xb2, 0xd0, 0x80, 0x2c, 0xfb, 0xf9,
++	0xfe, 0xd2, 0x33, 0xbb, 0x76, 0xfe, 0x7c, 0xa8,
++	0x66, 0xf7, 0xe7, 0x85, 0x9f, 0x1f, 0x85, 0x57,
++	0x88, 0xe1, 0xe9, 0x63, 0xe4, 0xd8, 0x1c, 0xa1,
++	0xfb, 0xda, 0x44, 0x05, 0x2e, 0x1d, 0x3a, 0x1c,
++	0xff, 0xc8, 0x3b, 0xc0, 0xfe, 0xda, 0x22, 0x0b,
++	0x43, 0xd6, 0x88, 0x39, 0x4c, 0x4a, 0xa6, 0x69,
++	0x18, 0x93, 0x42, 0x4e, 0xb5, 0xcc, 0x66, 0x0d,
++	0x09, 0xf8, 0x1e, 0x7c, 0xd3, 0x3c, 0x99, 0x0d,
++	0x50, 0x1d, 0x62, 0xe9, 0x57, 0x06, 0xbf, 0x19,
++	0x88, 0xdd, 0xad, 0x7b, 0x4f, 0xf9, 0xc7, 0x82,
++	0x6d, 0x8d, 0xc8, 0xc4, 0xc5, 0x78, 0x17, 0x20,
++	0x15, 0xc5, 0x52, 0x41, 0xcf, 0x5b, 0xd6, 0x7f,
++	0x94, 0x02, 0x41, 0xe0, 0x40, 0x22, 0x03, 0x5e,
++	0xd1, 0x53, 0xd4, 0x86, 0xd3, 0x2c, 0x9f, 0x0f,
++	0x96, 0xe3, 0x6b, 0x9a, 0x76, 0x32, 0x06, 0x47,
++	0x4b, 0x11, 0xb3, 0xdd, 0x03, 0x65, 0xbd, 0x9b,
++	0x01, 0xda, 0x9c, 0xb9, 0x7e, 0x3f, 0x6a, 0xc4,
++	0x7b, 0xea, 0xd4, 0x3c, 0xb9, 0xfb, 0x5c, 0x6b,
++	0x64, 0x33, 0x52, 0xba, 0x64, 0x78, 0x8f, 0xa4,
++	0xaf, 0x7a, 0x61, 0x8d, 0xbc, 0xc5, 0x73, 0xe9,
++	0x6b, 0x58, 0x97, 0x4b, 0xbf, 0x63, 0x22, 0xd3,
++	0x37, 0x02, 0x54, 0xc5, 0xb9, 0x16, 0x4a, 0xf0,
++	0x19, 0xd8, 0x94, 0x57, 0xb8, 0x8a, 0xb3, 0x16,
++	0x3b, 0xd0, 0x84, 0x8e, 0x67, 0xa6, 0xa3, 0x7d,
++	0x78, 0xec, 0x00
++};
++static const u8 enc_output012[] __initconst = {
++	0x52, 0x34, 0xb3, 0x65, 0x3b, 0xb7, 0xe5, 0xd3,
++	0xab, 0x49, 0x17, 0x60, 0xd2, 0x52, 0x56, 0xdf,
++	0xdf, 0x34, 0x56, 0x82, 0xe2, 0xbe, 0xe5, 0xe1,
++	0x28, 0xd1, 0x4e, 0x5f, 0x4f, 0x01, 0x7d, 0x3f,
++	0x99, 0x6b, 0x30, 0x6e, 0x1a, 0x7c, 0x4c, 0x8e,
++	0x62, 0x81, 0xae, 0x86, 0x3f, 0x6b, 0xd0, 0xb5,
++	0xa9, 0xcf, 0x50, 0xf1, 0x02, 0x12, 0xa0, 0x0b,
++	0x24, 0xe9, 0xe6, 0x72, 0x89, 0x2c, 0x52, 0x1b,
++	0x34, 0x38, 0xf8, 0x75, 0x5f, 0xa0, 0x74, 0xe2,
++	0x99, 0xdd, 0xa6, 0x4b, 0x14, 0x50, 0x4e, 0xf1,
++	0xbe, 0xd6, 0x9e, 0xdb, 0xb2, 0x24, 0x27, 0x74,
++	0x12, 0x4a, 0x78, 0x78, 0x17, 0xa5, 0x58, 0x8e,
++	0x2f, 0xf9, 0xf4, 0x8d, 0xee, 0x03, 0x88, 0xae,
++	0xb8, 0x29, 0xa1, 0x2f, 0x4b, 0xee, 0x92, 0xbd,
++	0x87, 0xb3, 0xce, 0x34, 0x21, 0x57, 0x46, 0x04,
++	0x49, 0x0c, 0x80, 0xf2, 0x01, 0x13, 0xa1, 0x55,
++	0xb3, 0xff, 0x44, 0x30, 0x3c, 0x1c, 0xd0, 0xef,
++	0xbc, 0x18, 0x74, 0x26, 0xad, 0x41, 0x5b, 0x5b,
++	0x3e, 0x9a, 0x7a, 0x46, 0x4f, 0x16, 0xd6, 0x74,
++	0x5a, 0xb7, 0x3a, 0x28, 0x31, 0xd8, 0xae, 0x26,
++	0xac, 0x50, 0x53, 0x86, 0xf2, 0x56, 0xd7, 0x3f,
++	0x29, 0xbc, 0x45, 0x68, 0x8e, 0xcb, 0x98, 0x64,
++	0xdd, 0xc9, 0xba, 0xb8, 0x4b, 0x7b, 0x82, 0xdd,
++	0x14, 0xa7, 0xcb, 0x71, 0x72, 0x00, 0x5c, 0xad,
++	0x7b, 0x6a, 0x89, 0xa4, 0x3d, 0xbf, 0xb5, 0x4b,
++	0x3e, 0x7c, 0x5a, 0xcf, 0xb8, 0xa1, 0xc5, 0x6e,
++	0xc8, 0xb6, 0x31, 0x57, 0x7b, 0xdf, 0xa5, 0x7e,
++	0xb1, 0xd6, 0x42, 0x2a, 0x31, 0x36, 0xd1, 0xd0,
++	0x3f, 0x7a, 0xe5, 0x94, 0xd6, 0x36, 0xa0, 0x6f,
++	0xb7, 0x40, 0x7d, 0x37, 0xc6, 0x55, 0x7c, 0x50,
++	0x40, 0x6d, 0x29, 0x89, 0xe3, 0x5a, 0xae, 0x97,
++	0xe7, 0x44, 0x49, 0x6e, 0xbd, 0x81, 0x3d, 0x03,
++	0x93, 0x06, 0x12, 0x06, 0xe2, 0x41, 0x12, 0x4a,
++	0xf1, 0x6a, 0xa4, 0x58, 0xa2, 0xfb, 0xd2, 0x15,
++	0xba, 0xc9, 0x79, 0xc9, 0xce, 0x5e, 0x13, 0xbb,
++	0xf1, 0x09, 0x04, 0xcc, 0xfd, 0xe8, 0x51, 0x34,
++	0x6a, 0xe8, 0x61, 0x88, 0xda, 0xed, 0x01, 0x47,
++	0x84, 0xf5, 0x73, 0x25, 0xf9, 0x1c, 0x42, 0x86,
++	0x07, 0xf3, 0x5b, 0x1a, 0x01, 0xb3, 0xeb, 0x24,
++	0x32, 0x8d, 0xf6, 0xed, 0x7c, 0x4b, 0xeb, 0x3c,
++	0x36, 0x42, 0x28, 0xdf, 0xdf, 0xb6, 0xbe, 0xd9,
++	0x8c, 0x52, 0xd3, 0x2b, 0x08, 0x90, 0x8c, 0xe7,
++	0x98, 0x31, 0xe2, 0x32, 0x8e, 0xfc, 0x11, 0x48,
++	0x00, 0xa8, 0x6a, 0x42, 0x4a, 0x02, 0xc6, 0x4b,
++	0x09, 0xf1, 0xe3, 0x49, 0xf3, 0x45, 0x1f, 0x0e,
++	0xbc, 0x56, 0xe2, 0xe4, 0xdf, 0xfb, 0xeb, 0x61,
++	0xfa, 0x24, 0xc1, 0x63, 0x75, 0xbb, 0x47, 0x75,
++	0xaf, 0xe1, 0x53, 0x16, 0x96, 0x21, 0x85, 0x26,
++	0x11, 0xb3, 0x76, 0xe3, 0x23, 0xa1, 0x6b, 0x74,
++	0x37, 0xd0, 0xde, 0x06, 0x90, 0x71, 0x5d, 0x43,
++	0x88, 0x9b, 0x00, 0x54, 0xa6, 0x75, 0x2f, 0xa1,
++	0xc2, 0x0b, 0x73, 0x20, 0x1d, 0xb6, 0x21, 0x79,
++	0x57, 0x3f, 0xfa, 0x09, 0xbe, 0x8a, 0x33, 0xc3,
++	0x52, 0xf0, 0x1d, 0x82, 0x31, 0xd1, 0x55, 0xb5,
++	0x6c, 0x99, 0x25, 0xcf, 0x5c, 0x32, 0xce, 0xe9,
++	0x0d, 0xfa, 0x69, 0x2c, 0xd5, 0x0d, 0xc5, 0x6d,
++	0x86, 0xd0, 0x0c, 0x3b, 0x06, 0x50, 0x79, 0xe8,
++	0xc3, 0xae, 0x04, 0xe6, 0xcd, 0x51, 0xe4, 0x26,
++	0x9b, 0x4f, 0x7e, 0xa6, 0x0f, 0xab, 0xd8, 0xe5,
++	0xde, 0xa9, 0x00, 0x95, 0xbe, 0xa3, 0x9d, 0x5d,
++	0xb2, 0x09, 0x70, 0x18, 0x1c, 0xf0, 0xac, 0x29,
++	0x23, 0x02, 0x29, 0x28, 0xd2, 0x74, 0x35, 0x57,
++	0x62, 0x0f, 0x24, 0xea, 0x5e, 0x33, 0xc2, 0x92,
++	0xf3, 0x78, 0x4d, 0x30, 0x1e, 0xa1, 0x99, 0xa9,
++	0x82, 0xb0, 0x42, 0x31, 0x8d, 0xad, 0x8a, 0xbc,
++	0xfc, 0xd4, 0x57, 0x47, 0x3e, 0xb4, 0x50, 0xdd,
++	0x6e, 0x2c, 0x80, 0x4d, 0x22, 0xf1, 0xfb, 0x57,
++	0xc4, 0xdd, 0x17, 0xe1, 0x8a, 0x36, 0x4a, 0xb3,
++	0x37, 0xca, 0xc9, 0x4e, 0xab, 0xd5, 0x69, 0xc4,
++	0xf4, 0xbc, 0x0b, 0x3b, 0x44, 0x4b, 0x29, 0x9c,
++	0xee, 0xd4, 0x35, 0x22, 0x21, 0xb0, 0x1f, 0x27,
++	0x64, 0xa8, 0x51, 0x1b, 0xf0, 0x9f, 0x19, 0x5c,
++	0xfb, 0x5a, 0x64, 0x74, 0x70, 0x45, 0x09, 0xf5,
++	0x64, 0xfe, 0x1a, 0x2d, 0xc9, 0x14, 0x04, 0x14,
++	0xcf, 0xd5, 0x7d, 0x60, 0xaf, 0x94, 0x39, 0x94,
++	0xe2, 0x7d, 0x79, 0x82, 0xd0, 0x65, 0x3b, 0x6b,
++	0x9c, 0x19, 0x84, 0xb4, 0x6d, 0xb3, 0x0c, 0x99,
++	0xc0, 0x56, 0xa8, 0xbd, 0x73, 0xce, 0x05, 0x84,
++	0x3e, 0x30, 0xaa, 0xc4, 0x9b, 0x1b, 0x04, 0x2a,
++	0x9f, 0xd7, 0x43, 0x2b, 0x23, 0xdf, 0xbf, 0xaa,
++	0xd5, 0xc2, 0x43, 0x2d, 0x70, 0xab, 0xdc, 0x75,
++	0xad, 0xac, 0xf7, 0xc0, 0xbe, 0x67, 0xb2, 0x74,
++	0xed, 0x67, 0x10, 0x4a, 0x92, 0x60, 0xc1, 0x40,
++	0x50, 0x19, 0x8a, 0x8a, 0x8c, 0x09, 0x0e, 0x72,
++	0xe1, 0x73, 0x5e, 0xe8, 0x41, 0x85, 0x63, 0x9f,
++	0x3f, 0xd7, 0x7d, 0xc4, 0xfb, 0x22, 0x5d, 0x92,
++	0x6c, 0xb3, 0x1e, 0xe2, 0x50, 0x2f, 0x82, 0xa8,
++	0x28, 0xc0, 0xb5, 0xd7, 0x5f, 0x68, 0x0d, 0x2c,
++	0x2d, 0xaf, 0x7e, 0xfa, 0x2e, 0x08, 0x0f, 0x1f,
++	0x70, 0x9f, 0xe9, 0x19, 0x72, 0x55, 0xf8, 0xfb,
++	0x51, 0xd2, 0x33, 0x5d, 0xa0, 0xd3, 0x2b, 0x0a,
++	0x6c, 0xbc, 0x4e, 0xcf, 0x36, 0x4d, 0xdc, 0x3b,
++	0xe9, 0x3e, 0x81, 0x7c, 0x61, 0xdb, 0x20, 0x2d,
++	0x3a, 0xc3, 0xb3, 0x0c, 0x1e, 0x00, 0xb9, 0x7c,
++	0xf5, 0xca, 0x10, 0x5f, 0x3a, 0x71, 0xb3, 0xe4,
++	0x20, 0xdb, 0x0c, 0x2a, 0x98, 0x63, 0x45, 0x00,
++	0x58, 0xf6, 0x68, 0xe4, 0x0b, 0xda, 0x13, 0x3b,
++	0x60, 0x5c, 0x76, 0xdb, 0xb9, 0x97, 0x71, 0xe4,
++	0xd9, 0xb7, 0xdb, 0xbd, 0x68, 0xc7, 0x84, 0x84,
++	0xaa, 0x7c, 0x68, 0x62, 0x5e, 0x16, 0xfc, 0xba,
++	0x72, 0xaa, 0x9a, 0xa9, 0xeb, 0x7c, 0x75, 0x47,
++	0x97, 0x7e, 0xad, 0xe2, 0xd9, 0x91, 0xe8, 0xe4,
++	0xa5, 0x31, 0xd7, 0x01, 0x8e, 0xa2, 0x11, 0x88,
++	0x95, 0xb9, 0xf2, 0x9b, 0xd3, 0x7f, 0x1b, 0x81,
++	0x22, 0xf7, 0x98, 0x60, 0x0a, 0x64, 0xa6, 0xc1,
++	0xf6, 0x49, 0xc7, 0xe3, 0x07, 0x4d, 0x94, 0x7a,
++	0xcf, 0x6e, 0x68, 0x0c, 0x1b, 0x3f, 0x6e, 0x2e,
++	0xee, 0x92, 0xfa, 0x52, 0xb3, 0x59, 0xf8, 0xf1,
++	0x8f, 0x6a, 0x66, 0xa3, 0x82, 0x76, 0x4a, 0x07,
++	0x1a, 0xc7, 0xdd, 0xf5, 0xda, 0x9c, 0x3c, 0x24,
++	0xbf, 0xfd, 0x42, 0xa1, 0x10, 0x64, 0x6a, 0x0f,
++	0x89, 0xee, 0x36, 0xa5, 0xce, 0x99, 0x48, 0x6a,
++	0xf0, 0x9f, 0x9e, 0x69, 0xa4, 0x40, 0x20, 0xe9,
++	0x16, 0x15, 0xf7, 0xdb, 0x75, 0x02, 0xcb, 0xe9,
++	0x73, 0x8b, 0x3b, 0x49, 0x2f, 0xf0, 0xaf, 0x51,
++	0x06, 0x5c, 0xdf, 0x27, 0x27, 0x49, 0x6a, 0xd1,
++	0xcc, 0xc7, 0xb5, 0x63, 0xb5, 0xfc, 0xb8, 0x5c,
++	0x87, 0x7f, 0x84, 0xb4, 0xcc, 0x14, 0xa9, 0x53,
++	0xda, 0xa4, 0x56, 0xf8, 0xb6, 0x1b, 0xcc, 0x40,
++	0x27, 0x52, 0x06, 0x5a, 0x13, 0x81, 0xd7, 0x3a,
++	0xd4, 0x3b, 0xfb, 0x49, 0x65, 0x31, 0x33, 0xb2,
++	0xfa, 0xcd, 0xad, 0x58, 0x4e, 0x2b, 0xae, 0xd2,
++	0x20, 0xfb, 0x1a, 0x48, 0xb4, 0x3f, 0x9a, 0xd8,
++	0x7a, 0x35, 0x4a, 0xc8, 0xee, 0x88, 0x5e, 0x07,
++	0x66, 0x54, 0xb9, 0xec, 0x9f, 0xa3, 0xe3, 0xb9,
++	0x37, 0xaa, 0x49, 0x76, 0x31, 0xda, 0x74, 0x2d,
++	0x3c, 0xa4, 0x65, 0x10, 0x32, 0x38, 0xf0, 0xde,
++	0xd3, 0x99, 0x17, 0xaa, 0x71, 0xaa, 0x8f, 0x0f,
++	0x8c, 0xaf, 0xa2, 0xf8, 0x5d, 0x64, 0xba, 0x1d,
++	0xa3, 0xef, 0x96, 0x73, 0xe8, 0xa1, 0x02, 0x8d,
++	0x0c, 0x6d, 0xb8, 0x06, 0x90, 0xb8, 0x08, 0x56,
++	0x2c, 0xa7, 0x06, 0xc9, 0xc2, 0x38, 0xdb, 0x7c,
++	0x63, 0xb1, 0x57, 0x8e, 0xea, 0x7c, 0x79, 0xf3,
++	0x49, 0x1d, 0xfe, 0x9f, 0xf3, 0x6e, 0xb1, 0x1d,
++	0xba, 0x19, 0x80, 0x1a, 0x0a, 0xd3, 0xb0, 0x26,
++	0x21, 0x40, 0xb1, 0x7c, 0xf9, 0x4d, 0x8d, 0x10,
++	0xc1, 0x7e, 0xf4, 0xf6, 0x3c, 0xa8, 0xfd, 0x7c,
++	0xa3, 0x92, 0xb2, 0x0f, 0xaa, 0xcc, 0xa6, 0x11,
++	0xfe, 0x04, 0xe3, 0xd1, 0x7a, 0x32, 0x89, 0xdf,
++	0x0d, 0xc4, 0x8f, 0x79, 0x6b, 0xca, 0x16, 0x7c,
++	0x6e, 0xf9, 0xad, 0x0f, 0xf6, 0xfe, 0x27, 0xdb,
++	0xc4, 0x13, 0x70, 0xf1, 0x62, 0x1a, 0x4f, 0x79,
++	0x40, 0xc9, 0x9b, 0x8b, 0x21, 0xea, 0x84, 0xfa,
++	0xf5, 0xf1, 0x89, 0xce, 0xb7, 0x55, 0x0a, 0x80,
++	0x39, 0x2f, 0x55, 0x36, 0x16, 0x9c, 0x7b, 0x08,
++	0xbd, 0x87, 0x0d, 0xa5, 0x32, 0xf1, 0x52, 0x7c,
++	0xe8, 0x55, 0x60, 0x5b, 0xd7, 0x69, 0xe4, 0xfc,
++	0xfa, 0x12, 0x85, 0x96, 0xea, 0x50, 0x28, 0xab,
++	0x8a, 0xf7, 0xbb, 0x0e, 0x53, 0x74, 0xca, 0xa6,
++	0x27, 0x09, 0xc2, 0xb5, 0xde, 0x18, 0x14, 0xd9,
++	0xea, 0xe5, 0x29, 0x1c, 0x40, 0x56, 0xcf, 0xd7,
++	0xae, 0x05, 0x3f, 0x65, 0xaf, 0x05, 0x73, 0xe2,
++	0x35, 0x96, 0x27, 0x07, 0x14, 0xc0, 0xad, 0x33,
++	0xf1, 0xdc, 0x44, 0x7a, 0x89, 0x17, 0x77, 0xd2,
++	0x9c, 0x58, 0x60, 0xf0, 0x3f, 0x7b, 0x2d, 0x2e,
++	0x57, 0x95, 0x54, 0x87, 0xed, 0xf2, 0xc7, 0x4c,
++	0xf0, 0xae, 0x56, 0x29, 0x19, 0x7d, 0x66, 0x4b,
++	0x9b, 0x83, 0x84, 0x42, 0x3b, 0x01, 0x25, 0x66,
++	0x8e, 0x02, 0xde, 0xb9, 0x83, 0x54, 0x19, 0xf6,
++	0x9f, 0x79, 0x0d, 0x67, 0xc5, 0x1d, 0x7a, 0x44,
++	0x02, 0x98, 0xa7, 0x16, 0x1c, 0x29, 0x0d, 0x74,
++	0xff, 0x85, 0x40, 0x06, 0xef, 0x2c, 0xa9, 0xc6,
++	0xf5, 0x53, 0x07, 0x06, 0xae, 0xe4, 0xfa, 0x5f,
++	0xd8, 0x39, 0x4d, 0xf1, 0x9b, 0x6b, 0xd9, 0x24,
++	0x84, 0xfe, 0x03, 0x4c, 0xb2, 0x3f, 0xdf, 0xa1,
++	0x05, 0x9e, 0x50, 0x14, 0x5a, 0xd9, 0x1a, 0xa2,
++	0xa7, 0xfa, 0xfa, 0x17, 0xf7, 0x78, 0xd6, 0xb5,
++	0x92, 0x61, 0x91, 0xac, 0x36, 0xfa, 0x56, 0x0d,
++	0x38, 0x32, 0x18, 0x85, 0x08, 0x58, 0x37, 0xf0,
++	0x4b, 0xdb, 0x59, 0xe7, 0xa4, 0x34, 0xc0, 0x1b,
++	0x01, 0xaf, 0x2d, 0xde, 0xa1, 0xaa, 0x5d, 0xd3,
++	0xec, 0xe1, 0xd4, 0xf7, 0xe6, 0x54, 0x68, 0xf0,
++	0x51, 0x97, 0xa7, 0x89, 0xea, 0x24, 0xad, 0xd3,
++	0x6e, 0x47, 0x93, 0x8b, 0x4b, 0xb4, 0xf7, 0x1c,
++	0x42, 0x06, 0x67, 0xe8, 0x99, 0xf6, 0xf5, 0x7b,
++	0x85, 0xb5, 0x65, 0xb5, 0xb5, 0xd2, 0x37, 0xf5,
++	0xf3, 0x02, 0xa6, 0x4d, 0x11, 0xa7, 0xdc, 0x51,
++	0x09, 0x7f, 0xa0, 0xd8, 0x88, 0x1c, 0x13, 0x71,
++	0xae, 0x9c, 0xb7, 0x7b, 0x34, 0xd6, 0x4e, 0x68,
++	0x26, 0x83, 0x51, 0xaf, 0x1d, 0xee, 0x8b, 0xbb,
++	0x69, 0x43, 0x2b, 0x9e, 0x8a, 0xbc, 0x02, 0x0e,
++	0xa0, 0x1b, 0xe0, 0xa8, 0x5f, 0x6f, 0xaf, 0x1b,
++	0x8f, 0xe7, 0x64, 0x71, 0x74, 0x11, 0x7e, 0xa8,
++	0xd8, 0xf9, 0x97, 0x06, 0xc3, 0xb6, 0xfb, 0xfb,
++	0xb7, 0x3d, 0x35, 0x9d, 0x3b, 0x52, 0xed, 0x54,
++	0xca, 0xf4, 0x81, 0x01, 0x2d, 0x1b, 0xc3, 0xa7,
++	0x00, 0x3d, 0x1a, 0x39, 0x54, 0xe1, 0xf6, 0xff,
++	0xed, 0x6f, 0x0b, 0x5a, 0x68, 0xda, 0x58, 0xdd,
++	0xa9, 0xcf, 0x5c, 0x4a, 0xe5, 0x09, 0x4e, 0xde,
++	0x9d, 0xbc, 0x3e, 0xee, 0x5a, 0x00, 0x3b, 0x2c,
++	0x87, 0x10, 0x65, 0x60, 0xdd, 0xd7, 0x56, 0xd1,
++	0x4c, 0x64, 0x45, 0xe4, 0x21, 0xec, 0x78, 0xf8,
++	0x25, 0x7a, 0x3e, 0x16, 0x5d, 0x09, 0x53, 0x14,
++	0xbe, 0x4f, 0xae, 0x87, 0xd8, 0xd1, 0xaa, 0x3c,
++	0xf6, 0x3e, 0xa4, 0x70, 0x8c, 0x5e, 0x70, 0xa4,
++	0xb3, 0x6b, 0x66, 0x73, 0xd3, 0xbf, 0x31, 0x06,
++	0x19, 0x62, 0x93, 0x15, 0xf2, 0x86, 0xe4, 0x52,
++	0x7e, 0x53, 0x4c, 0x12, 0x38, 0xcc, 0x34, 0x7d,
++	0x57, 0xf6, 0x42, 0x93, 0x8a, 0xc4, 0xee, 0x5c,
++	0x8a, 0xe1, 0x52, 0x8f, 0x56, 0x64, 0xf6, 0xa6,
++	0xd1, 0x91, 0x57, 0x70, 0xcd, 0x11, 0x76, 0xf5,
++	0x59, 0x60, 0x60, 0x3c, 0xc1, 0xc3, 0x0b, 0x7f,
++	0x58, 0x1a, 0x50, 0x91, 0xf1, 0x68, 0x8f, 0x6e,
++	0x74, 0x74, 0xa8, 0x51, 0x0b, 0xf7, 0x7a, 0x98,
++	0x37, 0xf2, 0x0a, 0x0e, 0xa4, 0x97, 0x04, 0xb8,
++	0x9b, 0xfd, 0xa0, 0xea, 0xf7, 0x0d, 0xe1, 0xdb,
++	0x03, 0xf0, 0x31, 0x29, 0xf8, 0xdd, 0x6b, 0x8b,
++	0x5d, 0xd8, 0x59, 0xa9, 0x29, 0xcf, 0x9a, 0x79,
++	0x89, 0x19, 0x63, 0x46, 0x09, 0x79, 0x6a, 0x11,
++	0xda, 0x63, 0x68, 0x48, 0x77, 0x23, 0xfb, 0x7d,
++	0x3a, 0x43, 0xcb, 0x02, 0x3b, 0x7a, 0x6d, 0x10,
++	0x2a, 0x9e, 0xac, 0xf1, 0xd4, 0x19, 0xf8, 0x23,
++	0x64, 0x1d, 0x2c, 0x5f, 0xf2, 0xb0, 0x5c, 0x23,
++	0x27, 0xf7, 0x27, 0x30, 0x16, 0x37, 0xb1, 0x90,
++	0xab, 0x38, 0xfb, 0x55, 0xcd, 0x78, 0x58, 0xd4,
++	0x7d, 0x43, 0xf6, 0x45, 0x5e, 0x55, 0x8d, 0xb1,
++	0x02, 0x65, 0x58, 0xb4, 0x13, 0x4b, 0x36, 0xf7,
++	0xcc, 0xfe, 0x3d, 0x0b, 0x82, 0xe2, 0x12, 0x11,
++	0xbb, 0xe6, 0xb8, 0x3a, 0x48, 0x71, 0xc7, 0x50,
++	0x06, 0x16, 0x3a, 0xe6, 0x7c, 0x05, 0xc7, 0xc8,
++	0x4d, 0x2f, 0x08, 0x6a, 0x17, 0x9a, 0x95, 0x97,
++	0x50, 0x68, 0xdc, 0x28, 0x18, 0xc4, 0x61, 0x38,
++	0xb9, 0xe0, 0x3e, 0x78, 0xdb, 0x29, 0xe0, 0x9f,
++	0x52, 0xdd, 0xf8, 0x4f, 0x91, 0xc1, 0xd0, 0x33,
++	0xa1, 0x7a, 0x8e, 0x30, 0x13, 0x82, 0x07, 0x9f,
++	0xd3, 0x31, 0x0f, 0x23, 0xbe, 0x32, 0x5a, 0x75,
++	0xcf, 0x96, 0xb2, 0xec, 0xb5, 0x32, 0xac, 0x21,
++	0xd1, 0x82, 0x33, 0xd3, 0x15, 0x74, 0xbd, 0x90,
++	0xf1, 0x2c, 0xe6, 0x5f, 0x8d, 0xe3, 0x02, 0xe8,
++	0xe9, 0xc4, 0xca, 0x96, 0xeb, 0x0e, 0xbc, 0x91,
++	0xf4, 0xb9, 0xea, 0xd9, 0x1b, 0x75, 0xbd, 0xe1,
++	0xac, 0x2a, 0x05, 0x37, 0x52, 0x9b, 0x1b, 0x3f,
++	0x5a, 0xdc, 0x21, 0xc3, 0x98, 0xbb, 0xaf, 0xa3,
++	0xf2, 0x00, 0xbf, 0x0d, 0x30, 0x89, 0x05, 0xcc,
++	0xa5, 0x76, 0xf5, 0x06, 0xf0, 0xc6, 0x54, 0x8a,
++	0x5d, 0xd4, 0x1e, 0xc1, 0xf2, 0xce, 0xb0, 0x62,
++	0xc8, 0xfc, 0x59, 0x42, 0x9a, 0x90, 0x60, 0x55,
++	0xfe, 0x88, 0xa5, 0x8b, 0xb8, 0x33, 0x0c, 0x23,
++	0x24, 0x0d, 0x15, 0x70, 0x37, 0x1e, 0x3d, 0xf6,
++	0xd2, 0xea, 0x92, 0x10, 0xb2, 0xc4, 0x51, 0xac,
++	0xf2, 0xac, 0xf3, 0x6b, 0x6c, 0xaa, 0xcf, 0x12,
++	0xc5, 0x6c, 0x90, 0x50, 0xb5, 0x0c, 0xfc, 0x1a,
++	0x15, 0x52, 0xe9, 0x26, 0xc6, 0x52, 0xa4, 0xe7,
++	0x81, 0x69, 0xe1, 0xe7, 0x9e, 0x30, 0x01, 0xec,
++	0x84, 0x89, 0xb2, 0x0d, 0x66, 0xdd, 0xce, 0x28,
++	0x5c, 0xec, 0x98, 0x46, 0x68, 0x21, 0x9f, 0x88,
++	0x3f, 0x1f, 0x42, 0x77, 0xce, 0xd0, 0x61, 0xd4,
++	0x20, 0xa7, 0xff, 0x53, 0xad, 0x37, 0xd0, 0x17,
++	0x35, 0xc9, 0xfc, 0xba, 0x0a, 0x78, 0x3f, 0xf2,
++	0xcc, 0x86, 0x89, 0xe8, 0x4b, 0x3c, 0x48, 0x33,
++	0x09, 0x7f, 0xc6, 0xc0, 0xdd, 0xb8, 0xfd, 0x7a,
++	0x66, 0x66, 0x65, 0xeb, 0x47, 0xa7, 0x04, 0x28,
++	0xa3, 0x19, 0x8e, 0xa9, 0xb1, 0x13, 0x67, 0x62,
++	0x70, 0xcf, 0xd6
++};
++static const u8 enc_assoc012[] __initconst = {
++	0xb1, 0x69, 0x83, 0x87, 0x30, 0xaa, 0x5d, 0xb8,
++	0x77, 0xe8, 0x21, 0xff, 0x06, 0x59, 0x35, 0xce,
++	0x75, 0xfe, 0x38, 0xef, 0xb8, 0x91, 0x43, 0x8c,
++	0xcf, 0x70, 0xdd, 0x0a, 0x68, 0xbf, 0xd4, 0xbc,
++	0x16, 0x76, 0x99, 0x36, 0x1e, 0x58, 0x79, 0x5e,
++	0xd4, 0x29, 0xf7, 0x33, 0x93, 0x48, 0xdb, 0x5f,
++	0x01, 0xae, 0x9c, 0xb6, 0xe4, 0x88, 0x6d, 0x2b,
++	0x76, 0x75, 0xe0, 0xf3, 0x74, 0xe2, 0xc9
++};
++static const u8 enc_nonce012[] __initconst = {
++	0x05, 0xa3, 0x93, 0xed, 0x30, 0xc5, 0xa2, 0x06
++};
++static const u8 enc_key012[] __initconst = {
++	0xb3, 0x35, 0x50, 0x03, 0x54, 0x2e, 0x40, 0x5e,
++	0x8f, 0x59, 0x8e, 0xc5, 0x90, 0xd5, 0x27, 0x2d,
++	0xba, 0x29, 0x2e, 0xcb, 0x1b, 0x70, 0x44, 0x1e,
++	0x65, 0x91, 0x6e, 0x2a, 0x79, 0x22, 0xda, 0x64
++};
++
++/* wycheproof - misc */
++static const u8 enc_input053[] __initconst = {
++	0x25, 0x6d, 0x40, 0x88, 0x80, 0x94, 0x17, 0x83,
++	0x55, 0xd3, 0x04, 0x84, 0x64, 0x43, 0xfe, 0xe8,
++	0xdf, 0x99, 0x47, 0x03, 0x03, 0xfb, 0x3b, 0x7b,
++	0x80, 0xe0, 0x30, 0xbe, 0xeb, 0xd3, 0x29, 0xbe
++};
++static const u8 enc_output053[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0xe6, 0xd3, 0xd7, 0x32, 0x4a, 0x1c, 0xbb, 0xa7,
++	0x77, 0xbb, 0xb0, 0xec, 0xdd, 0xa3, 0x78, 0x07
++};
++static const u8 enc_assoc053[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++};
++static const u8 enc_nonce053[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00
++};
++static const u8 enc_key053[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input054[] __initconst = {
++	0x25, 0x6d, 0x40, 0x88, 0x80, 0x94, 0x17, 0x83,
++	0x55, 0xd3, 0x04, 0x84, 0x64, 0x43, 0xfe, 0xe8,
++	0xdf, 0x99, 0x47, 0x03, 0x03, 0xfb, 0x3b, 0x7b,
++	0x80, 0xe0, 0x30, 0xbe, 0xeb, 0xd3, 0x29, 0xbe,
++	0xe3, 0xbc, 0xdb, 0x5b, 0x1e, 0xde, 0xfc, 0xfe,
++	0x8b, 0xcd, 0xa1, 0xb6, 0xa1, 0x5c, 0x8c, 0x2b,
++	0x08, 0x69, 0xff, 0xd2, 0xec, 0x5e, 0x26, 0xe5,
++	0x53, 0xb7, 0xb2, 0x27, 0xfe, 0x87, 0xfd, 0xbd
++};
++static const u8 enc_output054[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x06, 0x2d, 0xe6, 0x79, 0x5f, 0x27, 0x4f, 0xd2,
++	0xa3, 0x05, 0xd7, 0x69, 0x80, 0xbc, 0x9c, 0xce
++};
++static const u8 enc_assoc054[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++};
++static const u8 enc_nonce054[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00
++};
++static const u8 enc_key054[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input055[] __initconst = {
++	0x25, 0x6d, 0x40, 0x88, 0x80, 0x94, 0x17, 0x83,
++	0x55, 0xd3, 0x04, 0x84, 0x64, 0x43, 0xfe, 0xe8,
++	0xdf, 0x99, 0x47, 0x03, 0x03, 0xfb, 0x3b, 0x7b,
++	0x80, 0xe0, 0x30, 0xbe, 0xeb, 0xd3, 0x29, 0xbe,
++	0xe3, 0xbc, 0xdb, 0x5b, 0x1e, 0xde, 0xfc, 0xfe,
++	0x8b, 0xcd, 0xa1, 0xb6, 0xa1, 0x5c, 0x8c, 0x2b,
++	0x08, 0x69, 0xff, 0xd2, 0xec, 0x5e, 0x26, 0xe5,
++	0x53, 0xb7, 0xb2, 0x27, 0xfe, 0x87, 0xfd, 0xbd,
++	0x7a, 0xda, 0x44, 0x42, 0x42, 0x69, 0xbf, 0xfa,
++	0x55, 0x27, 0xf2, 0x70, 0xac, 0xf6, 0x85, 0x02,
++	0xb7, 0x4c, 0x5a, 0xe2, 0xe6, 0x0c, 0x05, 0x80,
++	0x98, 0x1a, 0x49, 0x38, 0x45, 0x93, 0x92, 0xc4,
++	0x9b, 0xb2, 0xf2, 0x84, 0xb6, 0x46, 0xef, 0xc7,
++	0xf3, 0xf0, 0xb1, 0x36, 0x1d, 0xc3, 0x48, 0xed,
++	0x77, 0xd3, 0x0b, 0xc5, 0x76, 0x92, 0xed, 0x38,
++	0xfb, 0xac, 0x01, 0x88, 0x38, 0x04, 0x88, 0xc7
++};
++static const u8 enc_output055[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0xd8, 0xb4, 0x79, 0x02, 0xba, 0xae, 0xaf, 0xb3,
++	0x42, 0x03, 0x05, 0x15, 0x29, 0xaf, 0x28, 0x2e
++};
++static const u8 enc_assoc055[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++};
++static const u8 enc_nonce055[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00
++};
++static const u8 enc_key055[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input056[] __initconst = {
++	0xda, 0x92, 0xbf, 0x77, 0x7f, 0x6b, 0xe8, 0x7c,
++	0xaa, 0x2c, 0xfb, 0x7b, 0x9b, 0xbc, 0x01, 0x17,
++	0x20, 0x66, 0xb8, 0xfc, 0xfc, 0x04, 0xc4, 0x84,
++	0x7f, 0x1f, 0xcf, 0x41, 0x14, 0x2c, 0xd6, 0x41
++};
++static const u8 enc_output056[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xb3, 0x89, 0x1c, 0x84, 0x9c, 0xb5, 0x2c, 0x27,
++	0x74, 0x7e, 0xdf, 0xcf, 0x31, 0x21, 0x3b, 0xb6
++};
++static const u8 enc_assoc056[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce056[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00
++};
++static const u8 enc_key056[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input057[] __initconst = {
++	0xda, 0x92, 0xbf, 0x77, 0x7f, 0x6b, 0xe8, 0x7c,
++	0xaa, 0x2c, 0xfb, 0x7b, 0x9b, 0xbc, 0x01, 0x17,
++	0x20, 0x66, 0xb8, 0xfc, 0xfc, 0x04, 0xc4, 0x84,
++	0x7f, 0x1f, 0xcf, 0x41, 0x14, 0x2c, 0xd6, 0x41,
++	0x1c, 0x43, 0x24, 0xa4, 0xe1, 0x21, 0x03, 0x01,
++	0x74, 0x32, 0x5e, 0x49, 0x5e, 0xa3, 0x73, 0xd4,
++	0xf7, 0x96, 0x00, 0x2d, 0x13, 0xa1, 0xd9, 0x1a,
++	0xac, 0x48, 0x4d, 0xd8, 0x01, 0x78, 0x02, 0x42
++};
++static const u8 enc_output057[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xf0, 0xc1, 0x2d, 0x26, 0xef, 0x03, 0x02, 0x9b,
++	0x62, 0xc0, 0x08, 0xda, 0x27, 0xc5, 0xdc, 0x68
++};
++static const u8 enc_assoc057[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce057[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00
++};
++static const u8 enc_key057[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input058[] __initconst = {
++	0xda, 0x92, 0xbf, 0x77, 0x7f, 0x6b, 0xe8, 0x7c,
++	0xaa, 0x2c, 0xfb, 0x7b, 0x9b, 0xbc, 0x01, 0x17,
++	0x20, 0x66, 0xb8, 0xfc, 0xfc, 0x04, 0xc4, 0x84,
++	0x7f, 0x1f, 0xcf, 0x41, 0x14, 0x2c, 0xd6, 0x41,
++	0x1c, 0x43, 0x24, 0xa4, 0xe1, 0x21, 0x03, 0x01,
++	0x74, 0x32, 0x5e, 0x49, 0x5e, 0xa3, 0x73, 0xd4,
++	0xf7, 0x96, 0x00, 0x2d, 0x13, 0xa1, 0xd9, 0x1a,
++	0xac, 0x48, 0x4d, 0xd8, 0x01, 0x78, 0x02, 0x42,
++	0x85, 0x25, 0xbb, 0xbd, 0xbd, 0x96, 0x40, 0x05,
++	0xaa, 0xd8, 0x0d, 0x8f, 0x53, 0x09, 0x7a, 0xfd,
++	0x48, 0xb3, 0xa5, 0x1d, 0x19, 0xf3, 0xfa, 0x7f,
++	0x67, 0xe5, 0xb6, 0xc7, 0xba, 0x6c, 0x6d, 0x3b,
++	0x64, 0x4d, 0x0d, 0x7b, 0x49, 0xb9, 0x10, 0x38,
++	0x0c, 0x0f, 0x4e, 0xc9, 0xe2, 0x3c, 0xb7, 0x12,
++	0x88, 0x2c, 0xf4, 0x3a, 0x89, 0x6d, 0x12, 0xc7,
++	0x04, 0x53, 0xfe, 0x77, 0xc7, 0xfb, 0x77, 0x38
++};
++static const u8 enc_output058[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xee, 0x65, 0x78, 0x30, 0x01, 0xc2, 0x56, 0x91,
++	0xfa, 0x28, 0xd0, 0xf5, 0xf1, 0xc1, 0xd7, 0x62
++};
++static const u8 enc_assoc058[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce058[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00
++};
++static const u8 enc_key058[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input059[] __initconst = {
++	0x25, 0x6d, 0x40, 0x08, 0x80, 0x94, 0x17, 0x03,
++	0x55, 0xd3, 0x04, 0x04, 0x64, 0x43, 0xfe, 0x68,
++	0xdf, 0x99, 0x47, 0x83, 0x03, 0xfb, 0x3b, 0xfb,
++	0x80, 0xe0, 0x30, 0x3e, 0xeb, 0xd3, 0x29, 0x3e
++};
++static const u8 enc_output059[] __initconst = {
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x79, 0xba, 0x7a, 0x29, 0xf5, 0xa7, 0xbb, 0x75,
++	0x79, 0x7a, 0xf8, 0x7a, 0x61, 0x01, 0x29, 0xa4
++};
++static const u8 enc_assoc059[] __initconst = {
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80
++};
++static const u8 enc_nonce059[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00
++};
++static const u8 enc_key059[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input060[] __initconst = {
++	0x25, 0x6d, 0x40, 0x08, 0x80, 0x94, 0x17, 0x03,
++	0x55, 0xd3, 0x04, 0x04, 0x64, 0x43, 0xfe, 0x68,
++	0xdf, 0x99, 0x47, 0x83, 0x03, 0xfb, 0x3b, 0xfb,
++	0x80, 0xe0, 0x30, 0x3e, 0xeb, 0xd3, 0x29, 0x3e,
++	0xe3, 0xbc, 0xdb, 0xdb, 0x1e, 0xde, 0xfc, 0x7e,
++	0x8b, 0xcd, 0xa1, 0x36, 0xa1, 0x5c, 0x8c, 0xab,
++	0x08, 0x69, 0xff, 0x52, 0xec, 0x5e, 0x26, 0x65,
++	0x53, 0xb7, 0xb2, 0xa7, 0xfe, 0x87, 0xfd, 0x3d
++};
++static const u8 enc_output060[] __initconst = {
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x36, 0xb1, 0x74, 0x38, 0x19, 0xe1, 0xb9, 0xba,
++	0x15, 0x51, 0xe8, 0xed, 0x92, 0x2a, 0x95, 0x9a
++};
++static const u8 enc_assoc060[] __initconst = {
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80
++};
++static const u8 enc_nonce060[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00
++};
++static const u8 enc_key060[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input061[] __initconst = {
++	0x25, 0x6d, 0x40, 0x08, 0x80, 0x94, 0x17, 0x03,
++	0x55, 0xd3, 0x04, 0x04, 0x64, 0x43, 0xfe, 0x68,
++	0xdf, 0x99, 0x47, 0x83, 0x03, 0xfb, 0x3b, 0xfb,
++	0x80, 0xe0, 0x30, 0x3e, 0xeb, 0xd3, 0x29, 0x3e,
++	0xe3, 0xbc, 0xdb, 0xdb, 0x1e, 0xde, 0xfc, 0x7e,
++	0x8b, 0xcd, 0xa1, 0x36, 0xa1, 0x5c, 0x8c, 0xab,
++	0x08, 0x69, 0xff, 0x52, 0xec, 0x5e, 0x26, 0x65,
++	0x53, 0xb7, 0xb2, 0xa7, 0xfe, 0x87, 0xfd, 0x3d,
++	0x7a, 0xda, 0x44, 0xc2, 0x42, 0x69, 0xbf, 0x7a,
++	0x55, 0x27, 0xf2, 0xf0, 0xac, 0xf6, 0x85, 0x82,
++	0xb7, 0x4c, 0x5a, 0x62, 0xe6, 0x0c, 0x05, 0x00,
++	0x98, 0x1a, 0x49, 0xb8, 0x45, 0x93, 0x92, 0x44,
++	0x9b, 0xb2, 0xf2, 0x04, 0xb6, 0x46, 0xef, 0x47,
++	0xf3, 0xf0, 0xb1, 0xb6, 0x1d, 0xc3, 0x48, 0x6d,
++	0x77, 0xd3, 0x0b, 0x45, 0x76, 0x92, 0xed, 0xb8,
++	0xfb, 0xac, 0x01, 0x08, 0x38, 0x04, 0x88, 0x47
++};
++static const u8 enc_output061[] __initconst = {
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0xfe, 0xac, 0x49, 0x55, 0x55, 0x4e, 0x80, 0x6f,
++	0x3a, 0x19, 0x02, 0xe2, 0x44, 0x32, 0xc0, 0x8a
++};
++static const u8 enc_assoc061[] __initconst = {
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80
++};
++static const u8 enc_nonce061[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00
++};
++static const u8 enc_key061[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input062[] __initconst = {
++	0xda, 0x92, 0xbf, 0xf7, 0x7f, 0x6b, 0xe8, 0xfc,
++	0xaa, 0x2c, 0xfb, 0xfb, 0x9b, 0xbc, 0x01, 0x97,
++	0x20, 0x66, 0xb8, 0x7c, 0xfc, 0x04, 0xc4, 0x04,
++	0x7f, 0x1f, 0xcf, 0xc1, 0x14, 0x2c, 0xd6, 0xc1
++};
++static const u8 enc_output062[] __initconst = {
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0x20, 0xa3, 0x79, 0x8d, 0xf1, 0x29, 0x2c, 0x59,
++	0x72, 0xbf, 0x97, 0x41, 0xae, 0xc3, 0x8a, 0x19
++};
++static const u8 enc_assoc062[] __initconst = {
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f
++};
++static const u8 enc_nonce062[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00
++};
++static const u8 enc_key062[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input063[] __initconst = {
++	0xda, 0x92, 0xbf, 0xf7, 0x7f, 0x6b, 0xe8, 0xfc,
++	0xaa, 0x2c, 0xfb, 0xfb, 0x9b, 0xbc, 0x01, 0x97,
++	0x20, 0x66, 0xb8, 0x7c, 0xfc, 0x04, 0xc4, 0x04,
++	0x7f, 0x1f, 0xcf, 0xc1, 0x14, 0x2c, 0xd6, 0xc1,
++	0x1c, 0x43, 0x24, 0x24, 0xe1, 0x21, 0x03, 0x81,
++	0x74, 0x32, 0x5e, 0xc9, 0x5e, 0xa3, 0x73, 0x54,
++	0xf7, 0x96, 0x00, 0xad, 0x13, 0xa1, 0xd9, 0x9a,
++	0xac, 0x48, 0x4d, 0x58, 0x01, 0x78, 0x02, 0xc2
++};
++static const u8 enc_output063[] __initconst = {
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xc0, 0x3d, 0x9f, 0x67, 0x35, 0x4a, 0x97, 0xb2,
++	0xf0, 0x74, 0xf7, 0x55, 0x15, 0x57, 0xe4, 0x9c
++};
++static const u8 enc_assoc063[] __initconst = {
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f
++};
++static const u8 enc_nonce063[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00
++};
++static const u8 enc_key063[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input064[] __initconst = {
++	0xda, 0x92, 0xbf, 0xf7, 0x7f, 0x6b, 0xe8, 0xfc,
++	0xaa, 0x2c, 0xfb, 0xfb, 0x9b, 0xbc, 0x01, 0x97,
++	0x20, 0x66, 0xb8, 0x7c, 0xfc, 0x04, 0xc4, 0x04,
++	0x7f, 0x1f, 0xcf, 0xc1, 0x14, 0x2c, 0xd6, 0xc1,
++	0x1c, 0x43, 0x24, 0x24, 0xe1, 0x21, 0x03, 0x81,
++	0x74, 0x32, 0x5e, 0xc9, 0x5e, 0xa3, 0x73, 0x54,
++	0xf7, 0x96, 0x00, 0xad, 0x13, 0xa1, 0xd9, 0x9a,
++	0xac, 0x48, 0x4d, 0x58, 0x01, 0x78, 0x02, 0xc2,
++	0x85, 0x25, 0xbb, 0x3d, 0xbd, 0x96, 0x40, 0x85,
++	0xaa, 0xd8, 0x0d, 0x0f, 0x53, 0x09, 0x7a, 0x7d,
++	0x48, 0xb3, 0xa5, 0x9d, 0x19, 0xf3, 0xfa, 0xff,
++	0x67, 0xe5, 0xb6, 0x47, 0xba, 0x6c, 0x6d, 0xbb,
++	0x64, 0x4d, 0x0d, 0xfb, 0x49, 0xb9, 0x10, 0xb8,
++	0x0c, 0x0f, 0x4e, 0x49, 0xe2, 0x3c, 0xb7, 0x92,
++	0x88, 0x2c, 0xf4, 0xba, 0x89, 0x6d, 0x12, 0x47,
++	0x04, 0x53, 0xfe, 0xf7, 0xc7, 0xfb, 0x77, 0xb8
++};
++static const u8 enc_output064[] __initconst = {
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xc8, 0x6d, 0xa8, 0xdd, 0x65, 0x22, 0x86, 0xd5,
++	0x02, 0x13, 0xd3, 0x28, 0xd6, 0x3e, 0x40, 0x06
++};
++static const u8 enc_assoc064[] __initconst = {
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f
++};
++static const u8 enc_nonce064[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00
++};
++static const u8 enc_key064[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input065[] __initconst = {
++	0x5a, 0x92, 0xbf, 0x77, 0xff, 0x6b, 0xe8, 0x7c,
++	0x2a, 0x2c, 0xfb, 0x7b, 0x1b, 0xbc, 0x01, 0x17,
++	0xa0, 0x66, 0xb8, 0xfc, 0x7c, 0x04, 0xc4, 0x84,
++	0xff, 0x1f, 0xcf, 0x41, 0x94, 0x2c, 0xd6, 0x41
++};
++static const u8 enc_output065[] __initconst = {
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0xbe, 0xde, 0x90, 0x83, 0xce, 0xb3, 0x6d, 0xdf,
++	0xe5, 0xfa, 0x81, 0x1f, 0x95, 0x47, 0x1c, 0x67
++};
++static const u8 enc_assoc065[] __initconst = {
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce065[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00
++};
++static const u8 enc_key065[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input066[] __initconst = {
++	0x5a, 0x92, 0xbf, 0x77, 0xff, 0x6b, 0xe8, 0x7c,
++	0x2a, 0x2c, 0xfb, 0x7b, 0x1b, 0xbc, 0x01, 0x17,
++	0xa0, 0x66, 0xb8, 0xfc, 0x7c, 0x04, 0xc4, 0x84,
++	0xff, 0x1f, 0xcf, 0x41, 0x94, 0x2c, 0xd6, 0x41,
++	0x9c, 0x43, 0x24, 0xa4, 0x61, 0x21, 0x03, 0x01,
++	0xf4, 0x32, 0x5e, 0x49, 0xde, 0xa3, 0x73, 0xd4,
++	0x77, 0x96, 0x00, 0x2d, 0x93, 0xa1, 0xd9, 0x1a,
++	0x2c, 0x48, 0x4d, 0xd8, 0x81, 0x78, 0x02, 0x42
++};
++static const u8 enc_output066[] __initconst = {
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x30, 0x08, 0x74, 0xbb, 0x06, 0x92, 0xb6, 0x89,
++	0xde, 0xad, 0x9a, 0xe1, 0x5b, 0x06, 0x73, 0x90
++};
++static const u8 enc_assoc066[] __initconst = {
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce066[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00
++};
++static const u8 enc_key066[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input067[] __initconst = {
++	0x5a, 0x92, 0xbf, 0x77, 0xff, 0x6b, 0xe8, 0x7c,
++	0x2a, 0x2c, 0xfb, 0x7b, 0x1b, 0xbc, 0x01, 0x17,
++	0xa0, 0x66, 0xb8, 0xfc, 0x7c, 0x04, 0xc4, 0x84,
++	0xff, 0x1f, 0xcf, 0x41, 0x94, 0x2c, 0xd6, 0x41,
++	0x9c, 0x43, 0x24, 0xa4, 0x61, 0x21, 0x03, 0x01,
++	0xf4, 0x32, 0x5e, 0x49, 0xde, 0xa3, 0x73, 0xd4,
++	0x77, 0x96, 0x00, 0x2d, 0x93, 0xa1, 0xd9, 0x1a,
++	0x2c, 0x48, 0x4d, 0xd8, 0x81, 0x78, 0x02, 0x42,
++	0x05, 0x25, 0xbb, 0xbd, 0x3d, 0x96, 0x40, 0x05,
++	0x2a, 0xd8, 0x0d, 0x8f, 0xd3, 0x09, 0x7a, 0xfd,
++	0xc8, 0xb3, 0xa5, 0x1d, 0x99, 0xf3, 0xfa, 0x7f,
++	0xe7, 0xe5, 0xb6, 0xc7, 0x3a, 0x6c, 0x6d, 0x3b,
++	0xe4, 0x4d, 0x0d, 0x7b, 0xc9, 0xb9, 0x10, 0x38,
++	0x8c, 0x0f, 0x4e, 0xc9, 0x62, 0x3c, 0xb7, 0x12,
++	0x08, 0x2c, 0xf4, 0x3a, 0x09, 0x6d, 0x12, 0xc7,
++	0x84, 0x53, 0xfe, 0x77, 0x47, 0xfb, 0x77, 0x38
++};
++static const u8 enc_output067[] __initconst = {
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x99, 0xca, 0xd8, 0x5f, 0x45, 0xca, 0x40, 0x94,
++	0x2d, 0x0d, 0x4d, 0x5e, 0x95, 0x0a, 0xde, 0x22
++};
++static const u8 enc_assoc067[] __initconst = {
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
++	0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce067[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00
++};
++static const u8 enc_key067[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input068[] __initconst = {
++	0x25, 0x6d, 0x40, 0x88, 0x7f, 0x6b, 0xe8, 0x7c,
++	0x55, 0xd3, 0x04, 0x84, 0x9b, 0xbc, 0x01, 0x17,
++	0xdf, 0x99, 0x47, 0x03, 0xfc, 0x04, 0xc4, 0x84,
++	0x80, 0xe0, 0x30, 0xbe, 0x14, 0x2c, 0xd6, 0x41
++};
++static const u8 enc_output068[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x8b, 0xbe, 0x14, 0x52, 0x72, 0xe7, 0xc2, 0xd9,
++	0xa1, 0x89, 0x1a, 0x3a, 0xb0, 0x98, 0x3d, 0x9d
++};
++static const u8 enc_assoc068[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce068[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00
++};
++static const u8 enc_key068[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input069[] __initconst = {
++	0x25, 0x6d, 0x40, 0x88, 0x7f, 0x6b, 0xe8, 0x7c,
++	0x55, 0xd3, 0x04, 0x84, 0x9b, 0xbc, 0x01, 0x17,
++	0xdf, 0x99, 0x47, 0x03, 0xfc, 0x04, 0xc4, 0x84,
++	0x80, 0xe0, 0x30, 0xbe, 0x14, 0x2c, 0xd6, 0x41,
++	0xe3, 0xbc, 0xdb, 0x5b, 0xe1, 0x21, 0x03, 0x01,
++	0x8b, 0xcd, 0xa1, 0xb6, 0x5e, 0xa3, 0x73, 0xd4,
++	0x08, 0x69, 0xff, 0xd2, 0x13, 0xa1, 0xd9, 0x1a,
++	0x53, 0xb7, 0xb2, 0x27, 0x01, 0x78, 0x02, 0x42
++};
++static const u8 enc_output069[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x3b, 0x41, 0x86, 0x19, 0x13, 0xa8, 0xf6, 0xde,
++	0x7f, 0x61, 0xe2, 0x25, 0x63, 0x1b, 0xc3, 0x82
++};
++static const u8 enc_assoc069[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce069[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00
++};
++static const u8 enc_key069[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input070[] __initconst = {
++	0x25, 0x6d, 0x40, 0x88, 0x7f, 0x6b, 0xe8, 0x7c,
++	0x55, 0xd3, 0x04, 0x84, 0x9b, 0xbc, 0x01, 0x17,
++	0xdf, 0x99, 0x47, 0x03, 0xfc, 0x04, 0xc4, 0x84,
++	0x80, 0xe0, 0x30, 0xbe, 0x14, 0x2c, 0xd6, 0x41,
++	0xe3, 0xbc, 0xdb, 0x5b, 0xe1, 0x21, 0x03, 0x01,
++	0x8b, 0xcd, 0xa1, 0xb6, 0x5e, 0xa3, 0x73, 0xd4,
++	0x08, 0x69, 0xff, 0xd2, 0x13, 0xa1, 0xd9, 0x1a,
++	0x53, 0xb7, 0xb2, 0x27, 0x01, 0x78, 0x02, 0x42,
++	0x7a, 0xda, 0x44, 0x42, 0xbd, 0x96, 0x40, 0x05,
++	0x55, 0x27, 0xf2, 0x70, 0x53, 0x09, 0x7a, 0xfd,
++	0xb7, 0x4c, 0x5a, 0xe2, 0x19, 0xf3, 0xfa, 0x7f,
++	0x98, 0x1a, 0x49, 0x38, 0xba, 0x6c, 0x6d, 0x3b,
++	0x9b, 0xb2, 0xf2, 0x84, 0x49, 0xb9, 0x10, 0x38,
++	0xf3, 0xf0, 0xb1, 0x36, 0xe2, 0x3c, 0xb7, 0x12,
++	0x77, 0xd3, 0x0b, 0xc5, 0x89, 0x6d, 0x12, 0xc7,
++	0xfb, 0xac, 0x01, 0x88, 0xc7, 0xfb, 0x77, 0x38
++};
++static const u8 enc_output070[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x84, 0x28, 0xbc, 0xf0, 0x23, 0xec, 0x6b, 0xf3,
++	0x1f, 0xd9, 0xef, 0xb2, 0x03, 0xff, 0x08, 0x71
++};
++static const u8 enc_assoc070[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce070[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00
++};
++static const u8 enc_key070[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input071[] __initconst = {
++	0xda, 0x92, 0xbf, 0x77, 0x80, 0x94, 0x17, 0x83,
++	0xaa, 0x2c, 0xfb, 0x7b, 0x64, 0x43, 0xfe, 0xe8,
++	0x20, 0x66, 0xb8, 0xfc, 0x03, 0xfb, 0x3b, 0x7b,
++	0x7f, 0x1f, 0xcf, 0x41, 0xeb, 0xd3, 0x29, 0xbe
++};
++static const u8 enc_output071[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0x13, 0x9f, 0xdf, 0x64, 0x74, 0xea, 0x24, 0xf5,
++	0x49, 0xb0, 0x75, 0x82, 0x5f, 0x2c, 0x76, 0x20
++};
++static const u8 enc_assoc071[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00
++};
++static const u8 enc_nonce071[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00
++};
++static const u8 enc_key071[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input072[] __initconst = {
++	0xda, 0x92, 0xbf, 0x77, 0x80, 0x94, 0x17, 0x83,
++	0xaa, 0x2c, 0xfb, 0x7b, 0x64, 0x43, 0xfe, 0xe8,
++	0x20, 0x66, 0xb8, 0xfc, 0x03, 0xfb, 0x3b, 0x7b,
++	0x7f, 0x1f, 0xcf, 0x41, 0xeb, 0xd3, 0x29, 0xbe,
++	0x1c, 0x43, 0x24, 0xa4, 0x1e, 0xde, 0xfc, 0xfe,
++	0x74, 0x32, 0x5e, 0x49, 0xa1, 0x5c, 0x8c, 0x2b,
++	0xf7, 0x96, 0x00, 0x2d, 0xec, 0x5e, 0x26, 0xe5,
++	0xac, 0x48, 0x4d, 0xd8, 0xfe, 0x87, 0xfd, 0xbd
++};
++static const u8 enc_output072[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xbb, 0xad, 0x8d, 0x86, 0x3b, 0x83, 0x5a, 0x8e,
++	0x86, 0x64, 0xfd, 0x1d, 0x45, 0x66, 0xb6, 0xb4
++};
++static const u8 enc_assoc072[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00
++};
++static const u8 enc_nonce072[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00
++};
++static const u8 enc_key072[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input073[] __initconst = {
++	0xda, 0x92, 0xbf, 0x77, 0x80, 0x94, 0x17, 0x83,
++	0xaa, 0x2c, 0xfb, 0x7b, 0x64, 0x43, 0xfe, 0xe8,
++	0x20, 0x66, 0xb8, 0xfc, 0x03, 0xfb, 0x3b, 0x7b,
++	0x7f, 0x1f, 0xcf, 0x41, 0xeb, 0xd3, 0x29, 0xbe,
++	0x1c, 0x43, 0x24, 0xa4, 0x1e, 0xde, 0xfc, 0xfe,
++	0x74, 0x32, 0x5e, 0x49, 0xa1, 0x5c, 0x8c, 0x2b,
++	0xf7, 0x96, 0x00, 0x2d, 0xec, 0x5e, 0x26, 0xe5,
++	0xac, 0x48, 0x4d, 0xd8, 0xfe, 0x87, 0xfd, 0xbd,
++	0x85, 0x25, 0xbb, 0xbd, 0x42, 0x69, 0xbf, 0xfa,
++	0xaa, 0xd8, 0x0d, 0x8f, 0xac, 0xf6, 0x85, 0x02,
++	0x48, 0xb3, 0xa5, 0x1d, 0xe6, 0x0c, 0x05, 0x80,
++	0x67, 0xe5, 0xb6, 0xc7, 0x45, 0x93, 0x92, 0xc4,
++	0x64, 0x4d, 0x0d, 0x7b, 0xb6, 0x46, 0xef, 0xc7,
++	0x0c, 0x0f, 0x4e, 0xc9, 0x1d, 0xc3, 0x48, 0xed,
++	0x88, 0x2c, 0xf4, 0x3a, 0x76, 0x92, 0xed, 0x38,
++	0x04, 0x53, 0xfe, 0x77, 0x38, 0x04, 0x88, 0xc7
++};
++static const u8 enc_output073[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0x42, 0xf2, 0x35, 0x42, 0x97, 0x84, 0x9a, 0x51,
++	0x1d, 0x53, 0xe5, 0x57, 0x17, 0x72, 0xf7, 0x1f
++};
++static const u8 enc_assoc073[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00
++};
++static const u8 enc_nonce073[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00
++};
++static const u8 enc_key073[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - checking for int overflows */
++static const u8 enc_input076[] __initconst = {
++	0x1b, 0x99, 0x6f, 0x9a, 0x3c, 0xcc, 0x67, 0x85,
++	0xde, 0x22, 0xff, 0x5b, 0x8a, 0xdd, 0x95, 0x02,
++	0xce, 0x03, 0xa0, 0xfa, 0xf5, 0x99, 0x2a, 0x09,
++	0x52, 0x2c, 0xdd, 0x12, 0x06, 0xd2, 0x20, 0xb8,
++	0xf8, 0xbd, 0x07, 0xd1, 0xf1, 0xf5, 0xa1, 0xbd,
++	0x9a, 0x71, 0xd1, 0x1c, 0x7f, 0x57, 0x9b, 0x85,
++	0x58, 0x18, 0xc0, 0x8d, 0x4d, 0xe0, 0x36, 0x39,
++	0x31, 0x83, 0xb7, 0xf5, 0x90, 0xb3, 0x35, 0xae,
++	0xd8, 0xde, 0x5b, 0x57, 0xb1, 0x3c, 0x5f, 0xed,
++	0xe2, 0x44, 0x1c, 0x3e, 0x18, 0x4a, 0xa9, 0xd4,
++	0x6e, 0x61, 0x59, 0x85, 0x06, 0xb3, 0xe1, 0x1c,
++	0x43, 0xc6, 0x2c, 0xbc, 0xac, 0xec, 0xed, 0x33,
++	0x19, 0x08, 0x75, 0xb0, 0x12, 0x21, 0x8b, 0x19,
++	0x30, 0xfb, 0x7c, 0x38, 0xec, 0x45, 0xac, 0x11,
++	0xc3, 0x53, 0xd0, 0xcf, 0x93, 0x8d, 0xcc, 0xb9,
++	0xef, 0xad, 0x8f, 0xed, 0xbe, 0x46, 0xda, 0xa5
++};
++static const u8 enc_output076[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x4b, 0x0b, 0xda, 0x8a, 0xd0, 0x43, 0x83, 0x0d,
++	0x83, 0x19, 0xab, 0x82, 0xc5, 0x0c, 0x76, 0x63
++};
++static const u8 enc_assoc076[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce076[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xb4, 0xf0
++};
++static const u8 enc_key076[] __initconst = {
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30
++};
++
++/* wycheproof - checking for int overflows */
++static const u8 enc_input077[] __initconst = {
++	0x86, 0xcb, 0xac, 0xae, 0x4d, 0x3f, 0x74, 0xae,
++	0x01, 0x21, 0x3e, 0x05, 0x51, 0xcc, 0x15, 0x16,
++	0x0e, 0xa1, 0xbe, 0x84, 0x08, 0xe3, 0xd5, 0xd7,
++	0x4f, 0x01, 0x46, 0x49, 0x95, 0xa6, 0x9e, 0x61,
++	0x76, 0xcb, 0x9e, 0x02, 0xb2, 0x24, 0x7e, 0xd2,
++	0x99, 0x89, 0x2f, 0x91, 0x82, 0xa4, 0x5c, 0xaf,
++	0x4c, 0x69, 0x40, 0x56, 0x11, 0x76, 0x6e, 0xdf,
++	0xaf, 0xdc, 0x28, 0x55, 0x19, 0xea, 0x30, 0x48,
++	0x0c, 0x44, 0xf0, 0x5e, 0x78, 0x1e, 0xac, 0xf8,
++	0xfc, 0xec, 0xc7, 0x09, 0x0a, 0xbb, 0x28, 0xfa,
++	0x5f, 0xd5, 0x85, 0xac, 0x8c, 0xda, 0x7e, 0x87,
++	0x72, 0xe5, 0x94, 0xe4, 0xce, 0x6c, 0x88, 0x32,
++	0x81, 0x93, 0x2e, 0x0f, 0x89, 0xf8, 0x77, 0xa1,
++	0xf0, 0x4d, 0x9c, 0x32, 0xb0, 0x6c, 0xf9, 0x0b,
++	0x0e, 0x76, 0x2b, 0x43, 0x0c, 0x4d, 0x51, 0x7c,
++	0x97, 0x10, 0x70, 0x68, 0xf4, 0x98, 0xef, 0x7f
++};
++static const u8 enc_output077[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x4b, 0xc9, 0x8f, 0x72, 0xc4, 0x94, 0xc2, 0xa4,
++	0x3c, 0x2b, 0x15, 0xa1, 0x04, 0x3f, 0x1c, 0xfa
++};
++static const u8 enc_assoc077[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce077[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xfb, 0x66
++};
++static const u8 enc_key077[] __initconst = {
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30
++};
++
++/* wycheproof - checking for int overflows */
++static const u8 enc_input078[] __initconst = {
++	0xfa, 0xb1, 0xcd, 0xdf, 0x4f, 0xe1, 0x98, 0xef,
++	0x63, 0xad, 0xd8, 0x81, 0xd6, 0xea, 0xd6, 0xc5,
++	0x76, 0x37, 0xbb, 0xe9, 0x20, 0x18, 0xca, 0x7c,
++	0x0b, 0x96, 0xfb, 0xa0, 0x87, 0x1e, 0x93, 0x2d,
++	0xb1, 0xfb, 0xf9, 0x07, 0x61, 0xbe, 0x25, 0xdf,
++	0x8d, 0xfa, 0xf9, 0x31, 0xce, 0x57, 0x57, 0xe6,
++	0x17, 0xb3, 0xd7, 0xa9, 0xf0, 0xbf, 0x0f, 0xfe,
++	0x5d, 0x59, 0x1a, 0x33, 0xc1, 0x43, 0xb8, 0xf5,
++	0x3f, 0xd0, 0xb5, 0xa1, 0x96, 0x09, 0xfd, 0x62,
++	0xe5, 0xc2, 0x51, 0xa4, 0x28, 0x1a, 0x20, 0x0c,
++	0xfd, 0xc3, 0x4f, 0x28, 0x17, 0x10, 0x40, 0x6f,
++	0x4e, 0x37, 0x62, 0x54, 0x46, 0xff, 0x6e, 0xf2,
++	0x24, 0x91, 0x3d, 0xeb, 0x0d, 0x89, 0xaf, 0x33,
++	0x71, 0x28, 0xe3, 0xd1, 0x55, 0xd1, 0x6d, 0x3e,
++	0xc3, 0x24, 0x60, 0x41, 0x43, 0x21, 0x43, 0xe9,
++	0xab, 0x3a, 0x6d, 0x2c, 0xcc, 0x2f, 0x4d, 0x62
++};
++static const u8 enc_output078[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xf7, 0xe9, 0xe1, 0x51, 0xb0, 0x25, 0x33, 0xc7,
++	0x46, 0x58, 0xbf, 0xc7, 0x73, 0x7c, 0x68, 0x0d
++};
++static const u8 enc_assoc078[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce078[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0xbb, 0x90
++};
++static const u8 enc_key078[] __initconst = {
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30
++};
++
++/* wycheproof - checking for int overflows */
++static const u8 enc_input079[] __initconst = {
++	0x22, 0x72, 0x02, 0xbe, 0x7f, 0x35, 0x15, 0xe9,
++	0xd1, 0xc0, 0x2e, 0xea, 0x2f, 0x19, 0x50, 0xb6,
++	0x48, 0x1b, 0x04, 0x8a, 0x4c, 0x91, 0x50, 0x6c,
++	0xb4, 0x0d, 0x50, 0x4e, 0x6c, 0x94, 0x9f, 0x82,
++	0xd1, 0x97, 0xc2, 0x5a, 0xd1, 0x7d, 0xc7, 0x21,
++	0x65, 0x11, 0x25, 0x78, 0x2a, 0xc7, 0xa7, 0x12,
++	0x47, 0xfe, 0xae, 0xf3, 0x2f, 0x1f, 0x25, 0x0c,
++	0xe4, 0xbb, 0x8f, 0x79, 0xac, 0xaa, 0x17, 0x9d,
++	0x45, 0xa7, 0xb0, 0x54, 0x5f, 0x09, 0x24, 0x32,
++	0x5e, 0xfa, 0x87, 0xd5, 0xe4, 0x41, 0xd2, 0x84,
++	0x78, 0xc6, 0x1f, 0x22, 0x23, 0xee, 0x67, 0xc3,
++	0xb4, 0x1f, 0x43, 0x94, 0x53, 0x5e, 0x2a, 0x24,
++	0x36, 0x9a, 0x2e, 0x16, 0x61, 0x3c, 0x45, 0x94,
++	0x90, 0xc1, 0x4f, 0xb1, 0xd7, 0x55, 0xfe, 0x53,
++	0xfb, 0xe1, 0xee, 0x45, 0xb1, 0xb2, 0x1f, 0x71,
++	0x62, 0xe2, 0xfc, 0xaa, 0x74, 0x2a, 0xbe, 0xfd
++};
++static const u8 enc_output079[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x79, 0x5b, 0xcf, 0xf6, 0x47, 0xc5, 0x53, 0xc2,
++	0xe4, 0xeb, 0x6e, 0x0e, 0xaf, 0xd9, 0xe0, 0x4e
++};
++static const u8 enc_assoc079[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce079[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x48, 0x4a
++};
++static const u8 enc_key079[] __initconst = {
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30
++};
++
++/* wycheproof - checking for int overflows */
++static const u8 enc_input080[] __initconst = {
++	0xfa, 0xe5, 0x83, 0x45, 0xc1, 0x6c, 0xb0, 0xf5,
++	0xcc, 0x53, 0x7f, 0x2b, 0x1b, 0x34, 0x69, 0xc9,
++	0x69, 0x46, 0x3b, 0x3e, 0xa7, 0x1b, 0xcf, 0x6b,
++	0x98, 0xd6, 0x69, 0xa8, 0xe6, 0x0e, 0x04, 0xfc,
++	0x08, 0xd5, 0xfd, 0x06, 0x9c, 0x36, 0x26, 0x38,
++	0xe3, 0x40, 0x0e, 0xf4, 0xcb, 0x24, 0x2e, 0x27,
++	0xe2, 0x24, 0x5e, 0x68, 0xcb, 0x9e, 0xc5, 0x83,
++	0xda, 0x53, 0x40, 0xb1, 0x2e, 0xdf, 0x42, 0x3b,
++	0x73, 0x26, 0xad, 0x20, 0xfe, 0xeb, 0x57, 0xda,
++	0xca, 0x2e, 0x04, 0x67, 0xa3, 0x28, 0x99, 0xb4,
++	0x2d, 0xf8, 0xe5, 0x6d, 0x84, 0xe0, 0x06, 0xbc,
++	0x8a, 0x7a, 0xcc, 0x73, 0x1e, 0x7c, 0x1f, 0x6b,
++	0xec, 0xb5, 0x71, 0x9f, 0x70, 0x77, 0xf0, 0xd4,
++	0xf4, 0xc6, 0x1a, 0xb1, 0x1e, 0xba, 0xc1, 0x00,
++	0x18, 0x01, 0xce, 0x33, 0xc4, 0xe4, 0xa7, 0x7d,
++	0x83, 0x1d, 0x3c, 0xe3, 0x4e, 0x84, 0x10, 0xe1
++};
++static const u8 enc_output080[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x19, 0x46, 0xd6, 0x53, 0x96, 0x0f, 0x94, 0x7a,
++	0x74, 0xd3, 0xe8, 0x09, 0x3c, 0xf4, 0x85, 0x02
++};
++static const u8 enc_assoc080[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce080[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x2f, 0x40
++};
++static const u8 enc_key080[] __initconst = {
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30
++};
++
++/* wycheproof - checking for int overflows */
++static const u8 enc_input081[] __initconst = {
++	0xeb, 0xb2, 0x16, 0xdd, 0xd7, 0xca, 0x70, 0x92,
++	0x15, 0xf5, 0x03, 0xdf, 0x9c, 0xe6, 0x3c, 0x5c,
++	0xd2, 0x19, 0x4e, 0x7d, 0x90, 0x99, 0xe8, 0xa9,
++	0x0b, 0x2a, 0xfa, 0xad, 0x5e, 0xba, 0x35, 0x06,
++	0x99, 0x25, 0xa6, 0x03, 0xfd, 0xbc, 0x34, 0x1a,
++	0xae, 0xd4, 0x15, 0x05, 0xb1, 0x09, 0x41, 0xfa,
++	0x38, 0x56, 0xa7, 0xe2, 0x47, 0xb1, 0x04, 0x07,
++	0x09, 0x74, 0x6c, 0xfc, 0x20, 0x96, 0xca, 0xa6,
++	0x31, 0xb2, 0xff, 0xf4, 0x1c, 0x25, 0x05, 0x06,
++	0xd8, 0x89, 0xc1, 0xc9, 0x06, 0x71, 0xad, 0xe8,
++	0x53, 0xee, 0x63, 0x94, 0xc1, 0x91, 0x92, 0xa5,
++	0xcf, 0x37, 0x10, 0xd1, 0x07, 0x30, 0x99, 0xe5,
++	0xbc, 0x94, 0x65, 0x82, 0xfc, 0x0f, 0xab, 0x9f,
++	0x54, 0x3c, 0x71, 0x6a, 0xe2, 0x48, 0x6a, 0x86,
++	0x83, 0xfd, 0xca, 0x39, 0xd2, 0xe1, 0x4f, 0x23,
++	0xd0, 0x0a, 0x58, 0x26, 0x64, 0xf4, 0xec, 0xb1
++};
++static const u8 enc_output081[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x36, 0xc3, 0x00, 0x29, 0x85, 0xdd, 0x21, 0xba,
++	0xf8, 0x95, 0xd6, 0x33, 0x57, 0x3f, 0x12, 0xc0
++};
++static const u8 enc_assoc081[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce081[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x93, 0x35
++};
++static const u8 enc_key081[] __initconst = {
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30
++};
++
++/* wycheproof - checking for int overflows */
++static const u8 enc_input082[] __initconst = {
++	0x40, 0x8a, 0xe6, 0xef, 0x1c, 0x7e, 0xf0, 0xfb,
++	0x2c, 0x2d, 0x61, 0x08, 0x16, 0xfc, 0x78, 0x49,
++	0xef, 0xa5, 0x8f, 0x78, 0x27, 0x3f, 0x5f, 0x16,
++	0x6e, 0xa6, 0x5f, 0x81, 0xb5, 0x75, 0x74, 0x7d,
++	0x03, 0x5b, 0x30, 0x40, 0xfe, 0xde, 0x1e, 0xb9,
++	0x45, 0x97, 0x88, 0x66, 0x97, 0x88, 0x40, 0x8e,
++	0x00, 0x41, 0x3b, 0x3e, 0x37, 0x6d, 0x15, 0x2d,
++	0x20, 0x4a, 0xa2, 0xb7, 0xa8, 0x35, 0x58, 0xfc,
++	0xd4, 0x8a, 0x0e, 0xf7, 0xa2, 0x6b, 0x1c, 0xd6,
++	0xd3, 0x5d, 0x23, 0xb3, 0xf5, 0xdf, 0xe0, 0xca,
++	0x77, 0xa4, 0xce, 0x32, 0xb9, 0x4a, 0xbf, 0x83,
++	0xda, 0x2a, 0xef, 0xca, 0xf0, 0x68, 0x38, 0x08,
++	0x79, 0xe8, 0x9f, 0xb0, 0xa3, 0x82, 0x95, 0x95,
++	0xcf, 0x44, 0xc3, 0x85, 0x2a, 0xe2, 0xcc, 0x66,
++	0x2b, 0x68, 0x9f, 0x93, 0x55, 0xd9, 0xc1, 0x83,
++	0x80, 0x1f, 0x6a, 0xcc, 0x31, 0x3f, 0x89, 0x07
++};
++static const u8 enc_output082[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x65, 0x14, 0x51, 0x8e, 0x0a, 0x26, 0x41, 0x42,
++	0xe0, 0xb7, 0x35, 0x1f, 0x96, 0x7f, 0xc2, 0xae
++};
++static const u8 enc_assoc082[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce082[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xf7, 0xd5
++};
++static const u8 enc_key082[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - checking for int overflows */
++static const u8 enc_input083[] __initconst = {
++	0x0a, 0x0a, 0x24, 0x49, 0x9b, 0xca, 0xde, 0x58,
++	0xcf, 0x15, 0x76, 0xc3, 0x12, 0xac, 0xa9, 0x84,
++	0x71, 0x8c, 0xb4, 0xcc, 0x7e, 0x01, 0x53, 0xf5,
++	0xa9, 0x01, 0x58, 0x10, 0x85, 0x96, 0x44, 0xdf,
++	0xc0, 0x21, 0x17, 0x4e, 0x0b, 0x06, 0x0a, 0x39,
++	0x74, 0x48, 0xde, 0x8b, 0x48, 0x4a, 0x86, 0x03,
++	0xbe, 0x68, 0x0a, 0x69, 0x34, 0xc0, 0x90, 0x6f,
++	0x30, 0xdd, 0x17, 0xea, 0xe2, 0xd4, 0xc5, 0xfa,
++	0xa7, 0x77, 0xf8, 0xca, 0x53, 0x37, 0x0e, 0x08,
++	0x33, 0x1b, 0x88, 0xc3, 0x42, 0xba, 0xc9, 0x59,
++	0x78, 0x7b, 0xbb, 0x33, 0x93, 0x0e, 0x3b, 0x56,
++	0xbe, 0x86, 0xda, 0x7f, 0x2a, 0x6e, 0xb1, 0xf9,
++	0x40, 0x89, 0xd1, 0xd1, 0x81, 0x07, 0x4d, 0x43,
++	0x02, 0xf8, 0xe0, 0x55, 0x2d, 0x0d, 0xe1, 0xfa,
++	0xb3, 0x06, 0xa2, 0x1b, 0x42, 0xd4, 0xc3, 0xba,
++	0x6e, 0x6f, 0x0c, 0xbc, 0xc8, 0x1e, 0x87, 0x7a
++};
++static const u8 enc_output083[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x4c, 0x19, 0x4d, 0xa6, 0xa9, 0x9f, 0xd6, 0x5b,
++	0x40, 0xe9, 0xca, 0xd7, 0x98, 0xf4, 0x4b, 0x19
++};
++static const u8 enc_assoc083[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce083[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0xfc, 0xe4
++};
++static const u8 enc_key083[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - checking for int overflows */
++static const u8 enc_input084[] __initconst = {
++	0x4a, 0x0a, 0xaf, 0xf8, 0x49, 0x47, 0x29, 0x18,
++	0x86, 0x91, 0x70, 0x13, 0x40, 0xf3, 0xce, 0x2b,
++	0x8a, 0x78, 0xee, 0xd3, 0xa0, 0xf0, 0x65, 0x99,
++	0x4b, 0x72, 0x48, 0x4e, 0x79, 0x91, 0xd2, 0x5c,
++	0x29, 0xaa, 0x07, 0x5e, 0xb1, 0xfc, 0x16, 0xde,
++	0x93, 0xfe, 0x06, 0x90, 0x58, 0x11, 0x2a, 0xb2,
++	0x84, 0xa3, 0xed, 0x18, 0x78, 0x03, 0x26, 0xd1,
++	0x25, 0x8a, 0x47, 0x22, 0x2f, 0xa6, 0x33, 0xd8,
++	0xb2, 0x9f, 0x3b, 0xd9, 0x15, 0x0b, 0x23, 0x9b,
++	0x15, 0x46, 0xc2, 0xbb, 0x9b, 0x9f, 0x41, 0x0f,
++	0xeb, 0xea, 0xd3, 0x96, 0x00, 0x0e, 0xe4, 0x77,
++	0x70, 0x15, 0x32, 0xc3, 0xd0, 0xf5, 0xfb, 0xf8,
++	0x95, 0xd2, 0x80, 0x19, 0x6d, 0x2f, 0x73, 0x7c,
++	0x5e, 0x9f, 0xec, 0x50, 0xd9, 0x2b, 0xb0, 0xdf,
++	0x5d, 0x7e, 0x51, 0x3b, 0xe5, 0xb8, 0xea, 0x97,
++	0x13, 0x10, 0xd5, 0xbf, 0x16, 0xba, 0x7a, 0xee
++};
++static const u8 enc_output084[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xc8, 0xae, 0x77, 0x88, 0xcd, 0x28, 0x74, 0xab,
++	0xc1, 0x38, 0x54, 0x1e, 0x11, 0xfd, 0x05, 0x87
++};
++static const u8 enc_assoc084[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce084[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x01, 0x84, 0x86, 0xa8
++};
++static const u8 enc_key084[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - checking for int overflows */
++static const u8 enc_input085[] __initconst = {
++	0xff, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66,
++	0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c,
++	0x78, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09,
++	0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8,
++	0x9f, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca,
++	0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64,
++	0x9c, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39,
++	0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4,
++	0x47, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2,
++	0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73,
++	0xd4, 0xd2, 0x06, 0x61, 0x6f, 0x92, 0x93, 0xf6,
++	0x5b, 0x45, 0xdb, 0xbc, 0x74, 0xe7, 0xc2, 0xed,
++	0xfb, 0xcb, 0xbf, 0x1c, 0xfb, 0x67, 0x9b, 0xb7,
++	0x39, 0xa5, 0x86, 0x2d, 0xe2, 0xbc, 0xb9, 0x37,
++	0xf7, 0x4d, 0x5b, 0xf8, 0x67, 0x1c, 0x5a, 0x8a,
++	0x50, 0x92, 0xf6, 0x1d, 0x54, 0xc9, 0xaa, 0x5b
++};
++static const u8 enc_output085[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x93, 0x3a, 0x51, 0x63, 0xc7, 0xf6, 0x23, 0x68,
++	0x32, 0x7b, 0x3f, 0xbc, 0x10, 0x36, 0xc9, 0x43
++};
++static const u8 enc_assoc085[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce085[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key085[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input093[] __initconst = {
++	0x00, 0x52, 0x35, 0xd2, 0xa9, 0x19, 0xf2, 0x8d,
++	0x3d, 0xb7, 0x66, 0x4a, 0x34, 0xae, 0x6b, 0x44,
++	0x4d, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09,
++	0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8,
++	0x5b, 0x8b, 0x94, 0x50, 0x9e, 0x2b, 0x74, 0xa3,
++	0x6d, 0x34, 0x6e, 0x33, 0xd5, 0x72, 0x65, 0x9b,
++	0xa9, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39,
++	0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4,
++	0x83, 0xdc, 0xe9, 0xf3, 0x07, 0x3e, 0xfa, 0xdb,
++	0x7d, 0x23, 0xb8, 0x7a, 0xce, 0x35, 0x16, 0x8c
++};
++static const u8 enc_output093[] __initconst = {
++	0x00, 0x39, 0xe2, 0xfd, 0x2f, 0xd3, 0x12, 0x14,
++	0x9e, 0x98, 0x98, 0x80, 0x88, 0x48, 0x13, 0xe7,
++	0xca, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x3b, 0x0e, 0x86, 0x9a, 0xaa, 0x8e, 0xa4, 0x96,
++	0x32, 0xff, 0xff, 0x37, 0xb9, 0xe8, 0xce, 0x00,
++	0xca, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x3b, 0x0e, 0x86, 0x9a, 0xaa, 0x8e, 0xa4, 0x96,
++	0x32, 0xff, 0xff, 0x37, 0xb9, 0xe8, 0xce, 0x00,
++	0xa5, 0x19, 0xac, 0x1a, 0x35, 0xb4, 0xa5, 0x77,
++	0x87, 0x51, 0x0a, 0xf7, 0x8d, 0x8d, 0x20, 0x0a
++};
++static const u8 enc_assoc093[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce093[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key093[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input094[] __initconst = {
++	0xd3, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66,
++	0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c,
++	0xe5, 0xda, 0x78, 0x76, 0x6f, 0xa1, 0x92, 0x90,
++	0xc0, 0x31, 0xf7, 0x52, 0x08, 0x50, 0x67, 0x45,
++	0xae, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca,
++	0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64,
++	0x49, 0x6d, 0xde, 0xb0, 0x55, 0x09, 0xc6, 0xef,
++	0xff, 0xab, 0x75, 0xeb, 0x2d, 0xf4, 0xab, 0x09,
++	0x76, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2,
++	0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73,
++	0x01, 0x49, 0xef, 0x50, 0x4b, 0x71, 0xb1, 0x20,
++	0xca, 0x4f, 0xf3, 0x95, 0x19, 0xc2, 0xc2, 0x10
++};
++static const u8 enc_output094[] __initconst = {
++	0xd3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x62, 0x18, 0xb2, 0x7f, 0x83, 0xb8, 0xb4, 0x66,
++	0x02, 0xf6, 0xe1, 0xd8, 0x34, 0x20, 0x7b, 0x02,
++	0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x2a, 0x64, 0x16, 0xce, 0xdb, 0x1c, 0xdd, 0x29,
++	0x6e, 0xf5, 0xd7, 0xd6, 0x92, 0xda, 0xff, 0x02,
++	0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x2a, 0x64, 0x16, 0xce, 0xdb, 0x1c, 0xdd, 0x29,
++	0x6e, 0xf5, 0xd7, 0xd6, 0x92, 0xda, 0xff, 0x02,
++	0x30, 0x2f, 0xe8, 0x2a, 0xb0, 0xa0, 0x9a, 0xf6,
++	0x44, 0x00, 0xd0, 0x15, 0xae, 0x83, 0xd9, 0xcc
++};
++static const u8 enc_assoc094[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce094[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key094[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input095[] __initconst = {
++	0xe9, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66,
++	0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c,
++	0x6d, 0xf1, 0x39, 0x4e, 0xdc, 0x53, 0x9b, 0x5b,
++	0x3a, 0x09, 0x57, 0xbe, 0x0f, 0xb8, 0x59, 0x46,
++	0x80, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca,
++	0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64,
++	0xd1, 0x76, 0x9f, 0xe8, 0x06, 0xbb, 0xfe, 0xb6,
++	0xf5, 0x90, 0x95, 0x0f, 0x2e, 0xac, 0x9e, 0x0a,
++	0x58, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2,
++	0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73,
++	0x99, 0x52, 0xae, 0x08, 0x18, 0xc3, 0x89, 0x79,
++	0xc0, 0x74, 0x13, 0x71, 0x1a, 0x9a, 0xf7, 0x13
++};
++static const u8 enc_output095[] __initconst = {
++	0xe9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xea, 0x33, 0xf3, 0x47, 0x30, 0x4a, 0xbd, 0xad,
++	0xf8, 0xce, 0x41, 0x34, 0x33, 0xc8, 0x45, 0x01,
++	0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xb2, 0x7f, 0x57, 0x96, 0x88, 0xae, 0xe5, 0x70,
++	0x64, 0xce, 0x37, 0x32, 0x91, 0x82, 0xca, 0x01,
++	0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xb2, 0x7f, 0x57, 0x96, 0x88, 0xae, 0xe5, 0x70,
++	0x64, 0xce, 0x37, 0x32, 0x91, 0x82, 0xca, 0x01,
++	0x98, 0xa7, 0xe8, 0x36, 0xe0, 0xee, 0x4d, 0x02,
++	0x35, 0x00, 0xd0, 0x55, 0x7e, 0xc2, 0xcb, 0xe0
++};
++static const u8 enc_assoc095[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce095[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key095[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input096[] __initconst = {
++	0xff, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66,
++	0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c,
++	0x64, 0xf9, 0x0f, 0x5b, 0x26, 0x92, 0xb8, 0x60,
++	0xd4, 0x59, 0x6f, 0xf4, 0xb3, 0x40, 0x2c, 0x5c,
++	0x00, 0xb9, 0xbb, 0x53, 0x70, 0x7a, 0xa6, 0x67,
++	0xd3, 0x56, 0xfe, 0x50, 0xc7, 0x19, 0x96, 0x94,
++	0x03, 0x35, 0x61, 0xe7, 0xca, 0xca, 0x6d, 0x94,
++	0x1d, 0xc3, 0xcd, 0x69, 0x14, 0xad, 0x69, 0x04
++};
++static const u8 enc_output096[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xe3, 0x3b, 0xc5, 0x52, 0xca, 0x8b, 0x9e, 0x96,
++	0x16, 0x9e, 0x79, 0x7e, 0x8f, 0x30, 0x30, 0x1b,
++	0x60, 0x3c, 0xa9, 0x99, 0x44, 0xdf, 0x76, 0x52,
++	0x8c, 0x9d, 0x6f, 0x54, 0xab, 0x83, 0x3d, 0x0f,
++	0x60, 0x3c, 0xa9, 0x99, 0x44, 0xdf, 0x76, 0x52,
++	0x8c, 0x9d, 0x6f, 0x54, 0xab, 0x83, 0x3d, 0x0f,
++	0x6a, 0xb8, 0xdc, 0xe2, 0xc5, 0x9d, 0xa4, 0x73,
++	0x71, 0x30, 0xb0, 0x25, 0x2f, 0x68, 0xa8, 0xd8
++};
++static const u8 enc_assoc096[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce096[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key096[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input097[] __initconst = {
++	0x68, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66,
++	0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c,
++	0xb0, 0x8f, 0x25, 0x67, 0x5b, 0x9b, 0xcb, 0xf6,
++	0xe3, 0x84, 0x07, 0xde, 0x2e, 0xc7, 0x5a, 0x47,
++	0x9f, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca,
++	0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64,
++	0x2d, 0x2a, 0xf7, 0xcd, 0x6b, 0x08, 0x05, 0x01,
++	0xd3, 0x1b, 0xa5, 0x4f, 0xb2, 0xeb, 0x75, 0x96,
++	0x47, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2,
++	0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73,
++	0x65, 0x0e, 0xc6, 0x2d, 0x75, 0x70, 0x72, 0xce,
++	0xe6, 0xff, 0x23, 0x31, 0x86, 0xdd, 0x1c, 0x8f
++};
++static const u8 enc_output097[] __initconst = {
++	0x68, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x37, 0x4d, 0xef, 0x6e, 0xb7, 0x82, 0xed, 0x00,
++	0x21, 0x43, 0x11, 0x54, 0x12, 0xb7, 0x46, 0x00,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x4e, 0x23, 0x3f, 0xb3, 0xe5, 0x1d, 0x1e, 0xc7,
++	0x42, 0x45, 0x07, 0x72, 0x0d, 0xc5, 0x21, 0x9d,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x4e, 0x23, 0x3f, 0xb3, 0xe5, 0x1d, 0x1e, 0xc7,
++	0x42, 0x45, 0x07, 0x72, 0x0d, 0xc5, 0x21, 0x9d,
++	0x04, 0x4d, 0xea, 0x60, 0x88, 0x80, 0x41, 0x2b,
++	0xfd, 0xff, 0xcf, 0x35, 0x57, 0x9e, 0x9b, 0x26
++};
++static const u8 enc_assoc097[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce097[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key097[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input098[] __initconst = {
++	0x6d, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66,
++	0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c,
++	0xa1, 0x61, 0xb5, 0xab, 0x04, 0x09, 0x00, 0x62,
++	0x9e, 0xfe, 0xff, 0x78, 0xd7, 0xd8, 0x6b, 0x45,
++	0x9f, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca,
++	0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64,
++	0xc6, 0xf8, 0x07, 0x8c, 0xc8, 0xef, 0x12, 0xa0,
++	0xff, 0x65, 0x7d, 0x6d, 0x08, 0xdb, 0x10, 0xb8,
++	0x47, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2,
++	0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73,
++	0x8e, 0xdc, 0x36, 0x6c, 0xd6, 0x97, 0x65, 0x6f,
++	0xca, 0x81, 0xfb, 0x13, 0x3c, 0xed, 0x79, 0xa1
++};
++static const u8 enc_output098[] __initconst = {
++	0x6d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x26, 0xa3, 0x7f, 0xa2, 0xe8, 0x10, 0x26, 0x94,
++	0x5c, 0x39, 0xe9, 0xf2, 0xeb, 0xa8, 0x77, 0x02,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xa5, 0xf1, 0xcf, 0xf2, 0x46, 0xfa, 0x09, 0x66,
++	0x6e, 0x3b, 0xdf, 0x50, 0xb7, 0xf5, 0x44, 0xb3,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xa5, 0xf1, 0xcf, 0xf2, 0x46, 0xfa, 0x09, 0x66,
++	0x6e, 0x3b, 0xdf, 0x50, 0xb7, 0xf5, 0x44, 0xb3,
++	0x1e, 0x6b, 0xea, 0x63, 0x14, 0x54, 0x2e, 0x2e,
++	0xf9, 0xff, 0xcf, 0x45, 0x0b, 0x2e, 0x98, 0x2b
++};
++static const u8 enc_assoc098[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce098[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key098[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input099[] __initconst = {
++	0xff, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66,
++	0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c,
++	0xfc, 0x01, 0xb8, 0x91, 0xe5, 0xf0, 0xf9, 0x12,
++	0x8d, 0x7d, 0x1c, 0x57, 0x91, 0x92, 0xb6, 0x98,
++	0x63, 0x41, 0x44, 0x15, 0xb6, 0x99, 0x68, 0x95,
++	0x9a, 0x72, 0x91, 0xb7, 0xa5, 0xaf, 0x13, 0x48,
++	0x60, 0xcd, 0x9e, 0xa1, 0x0c, 0x29, 0xa3, 0x66,
++	0x54, 0xe7, 0xa2, 0x8e, 0x76, 0x1b, 0xec, 0xd8
++};
++static const u8 enc_output099[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x7b, 0xc3, 0x72, 0x98, 0x09, 0xe9, 0xdf, 0xe4,
++	0x4f, 0xba, 0x0a, 0xdd, 0xad, 0xe2, 0xaa, 0xdf,
++	0x03, 0xc4, 0x56, 0xdf, 0x82, 0x3c, 0xb8, 0xa0,
++	0xc5, 0xb9, 0x00, 0xb3, 0xc9, 0x35, 0xb8, 0xd3,
++	0x03, 0xc4, 0x56, 0xdf, 0x82, 0x3c, 0xb8, 0xa0,
++	0xc5, 0xb9, 0x00, 0xb3, 0xc9, 0x35, 0xb8, 0xd3,
++	0xed, 0x20, 0x17, 0xc8, 0xdb, 0xa4, 0x77, 0x56,
++	0x29, 0x04, 0x9d, 0x78, 0x6e, 0x3b, 0xce, 0xb1
++};
++static const u8 enc_assoc099[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce099[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key099[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input100[] __initconst = {
++	0xff, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66,
++	0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c,
++	0x6b, 0x6d, 0xc9, 0xd2, 0x1a, 0x81, 0x9e, 0x70,
++	0xb5, 0x77, 0xf4, 0x41, 0x37, 0xd3, 0xd6, 0xbd,
++	0x13, 0x35, 0xf5, 0xeb, 0x44, 0x49, 0x40, 0x77,
++	0xb2, 0x64, 0x49, 0xa5, 0x4b, 0x6c, 0x7c, 0x75,
++	0x10, 0xb9, 0x2f, 0x5f, 0xfe, 0xf9, 0x8b, 0x84,
++	0x7c, 0xf1, 0x7a, 0x9c, 0x98, 0xd8, 0x83, 0xe5
++};
++static const u8 enc_output100[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xec, 0xaf, 0x03, 0xdb, 0xf6, 0x98, 0xb8, 0x86,
++	0x77, 0xb0, 0xe2, 0xcb, 0x0b, 0xa3, 0xca, 0xfa,
++	0x73, 0xb0, 0xe7, 0x21, 0x70, 0xec, 0x90, 0x42,
++	0xed, 0xaf, 0xd8, 0xa1, 0x27, 0xf6, 0xd7, 0xee,
++	0x73, 0xb0, 0xe7, 0x21, 0x70, 0xec, 0x90, 0x42,
++	0xed, 0xaf, 0xd8, 0xa1, 0x27, 0xf6, 0xd7, 0xee,
++	0x07, 0x3f, 0x17, 0xcb, 0x67, 0x78, 0x64, 0x59,
++	0x25, 0x04, 0x9d, 0x88, 0x22, 0xcb, 0xca, 0xb6
++};
++static const u8 enc_assoc100[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce100[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key100[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input101[] __initconst = {
++	0xff, 0xcb, 0x2b, 0x11, 0x06, 0xf8, 0x23, 0x4c,
++	0x5e, 0x99, 0xd4, 0xdb, 0x4c, 0x70, 0x48, 0xde,
++	0x32, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09,
++	0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8,
++	0x16, 0xe9, 0x88, 0x4a, 0x11, 0x4f, 0x0e, 0x92,
++	0x66, 0xce, 0xa3, 0x88, 0x5f, 0xe3, 0x6b, 0x9f,
++	0xd6, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39,
++	0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4,
++	0xce, 0xbe, 0xf5, 0xe9, 0x88, 0x5a, 0x80, 0xea,
++	0x76, 0xd9, 0x75, 0xc1, 0x44, 0xa4, 0x18, 0x88
++};
++static const u8 enc_output101[] __initconst = {
++	0xff, 0xa0, 0xfc, 0x3e, 0x80, 0x32, 0xc3, 0xd5,
++	0xfd, 0xb6, 0x2a, 0x11, 0xf0, 0x96, 0x30, 0x7d,
++	0xb5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x76, 0x6c, 0x9a, 0x80, 0x25, 0xea, 0xde, 0xa7,
++	0x39, 0x05, 0x32, 0x8c, 0x33, 0x79, 0xc0, 0x04,
++	0xb5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x76, 0x6c, 0x9a, 0x80, 0x25, 0xea, 0xde, 0xa7,
++	0x39, 0x05, 0x32, 0x8c, 0x33, 0x79, 0xc0, 0x04,
++	0x8b, 0x9b, 0xb4, 0xb4, 0x86, 0x12, 0x89, 0x65,
++	0x8c, 0x69, 0x6a, 0x83, 0x40, 0x15, 0x04, 0x05
++};
++static const u8 enc_assoc101[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce101[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key101[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input102[] __initconst = {
++	0x6f, 0x9e, 0x70, 0xed, 0x3b, 0x8b, 0xac, 0xa0,
++	0x26, 0xe4, 0x6a, 0x5a, 0x09, 0x43, 0x15, 0x8d,
++	0x21, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09,
++	0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8,
++	0x0c, 0x61, 0x2c, 0x5e, 0x8d, 0x89, 0xa8, 0x73,
++	0xdb, 0xca, 0xad, 0x5b, 0x73, 0x46, 0x42, 0x9b,
++	0xc5, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39,
++	0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4,
++	0xd4, 0x36, 0x51, 0xfd, 0x14, 0x9c, 0x26, 0x0b,
++	0xcb, 0xdd, 0x7b, 0x12, 0x68, 0x01, 0x31, 0x8c
++};
++static const u8 enc_output102[] __initconst = {
++	0x6f, 0xf5, 0xa7, 0xc2, 0xbd, 0x41, 0x4c, 0x39,
++	0x85, 0xcb, 0x94, 0x90, 0xb5, 0xa5, 0x6d, 0x2e,
++	0xa6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x6c, 0xe4, 0x3e, 0x94, 0xb9, 0x2c, 0x78, 0x46,
++	0x84, 0x01, 0x3c, 0x5f, 0x1f, 0xdc, 0xe9, 0x00,
++	0xa6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x6c, 0xe4, 0x3e, 0x94, 0xb9, 0x2c, 0x78, 0x46,
++	0x84, 0x01, 0x3c, 0x5f, 0x1f, 0xdc, 0xe9, 0x00,
++	0x8b, 0x3b, 0xbd, 0x51, 0x64, 0x44, 0x59, 0x56,
++	0x8d, 0x81, 0xca, 0x1f, 0xa7, 0x2c, 0xe4, 0x04
++};
++static const u8 enc_assoc102[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce102[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key102[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input103[] __initconst = {
++	0x41, 0x2b, 0x08, 0x0a, 0x3e, 0x19, 0xc1, 0x0d,
++	0x44, 0xa1, 0xaf, 0x1e, 0xab, 0xde, 0xb4, 0xce,
++	0x35, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09,
++	0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8,
++	0x6b, 0x83, 0x94, 0x33, 0x09, 0x21, 0x48, 0x6c,
++	0xa1, 0x1d, 0x29, 0x1c, 0x3e, 0x97, 0xee, 0x9a,
++	0xd1, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39,
++	0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4,
++	0xb3, 0xd4, 0xe9, 0x90, 0x90, 0x34, 0xc6, 0x14,
++	0xb1, 0x0a, 0xff, 0x55, 0x25, 0xd0, 0x9d, 0x8d
++};
++static const u8 enc_output103[] __initconst = {
++	0x41, 0x40, 0xdf, 0x25, 0xb8, 0xd3, 0x21, 0x94,
++	0xe7, 0x8e, 0x51, 0xd4, 0x17, 0x38, 0xcc, 0x6d,
++	0xb2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x0b, 0x06, 0x86, 0xf9, 0x3d, 0x84, 0x98, 0x59,
++	0xfe, 0xd6, 0xb8, 0x18, 0x52, 0x0d, 0x45, 0x01,
++	0xb2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x0b, 0x06, 0x86, 0xf9, 0x3d, 0x84, 0x98, 0x59,
++	0xfe, 0xd6, 0xb8, 0x18, 0x52, 0x0d, 0x45, 0x01,
++	0x86, 0xfb, 0xab, 0x2b, 0x4a, 0x94, 0xf4, 0x7a,
++	0xa5, 0x6f, 0x0a, 0xea, 0x65, 0xd1, 0x10, 0x08
++};
++static const u8 enc_assoc103[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce103[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key103[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input104[] __initconst = {
++	0xb2, 0x47, 0xa7, 0x47, 0x23, 0x49, 0x1a, 0xac,
++	0xac, 0xaa, 0xd7, 0x09, 0xc9, 0x1e, 0x93, 0x2b,
++	0x31, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09,
++	0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8,
++	0x9a, 0xde, 0x04, 0xe7, 0x5b, 0xb7, 0x01, 0xd9,
++	0x66, 0x06, 0x01, 0xb3, 0x47, 0x65, 0xde, 0x98,
++	0xd5, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39,
++	0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4,
++	0x42, 0x89, 0x79, 0x44, 0xc2, 0xa2, 0x8f, 0xa1,
++	0x76, 0x11, 0xd7, 0xfa, 0x5c, 0x22, 0xad, 0x8f
++};
++static const u8 enc_output104[] __initconst = {
++	0xb2, 0x2c, 0x70, 0x68, 0xa5, 0x83, 0xfa, 0x35,
++	0x0f, 0x85, 0x29, 0xc3, 0x75, 0xf8, 0xeb, 0x88,
++	0xb6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xfa, 0x5b, 0x16, 0x2d, 0x6f, 0x12, 0xd1, 0xec,
++	0x39, 0xcd, 0x90, 0xb7, 0x2b, 0xff, 0x75, 0x03,
++	0xb6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xfa, 0x5b, 0x16, 0x2d, 0x6f, 0x12, 0xd1, 0xec,
++	0x39, 0xcd, 0x90, 0xb7, 0x2b, 0xff, 0x75, 0x03,
++	0xa0, 0x19, 0xac, 0x2e, 0xd6, 0x67, 0xe1, 0x7d,
++	0xa1, 0x6f, 0x0a, 0xfa, 0x19, 0x61, 0x0d, 0x0d
++};
++static const u8 enc_assoc104[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce104[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key104[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input105[] __initconst = {
++	0x74, 0x0f, 0x9e, 0x49, 0xf6, 0x10, 0xef, 0xa5,
++	0x85, 0xb6, 0x59, 0xca, 0x6e, 0xd8, 0xb4, 0x99,
++	0x2d, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09,
++	0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8,
++	0x41, 0x2d, 0x96, 0xaf, 0xbe, 0x80, 0xec, 0x3e,
++	0x79, 0xd4, 0x51, 0xb0, 0x0a, 0x2d, 0xb2, 0x9a,
++	0xc9, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39,
++	0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4,
++	0x99, 0x7a, 0xeb, 0x0c, 0x27, 0x95, 0x62, 0x46,
++	0x69, 0xc3, 0x87, 0xf9, 0x11, 0x6a, 0xc1, 0x8d
++};
++static const u8 enc_output105[] __initconst = {
++	0x74, 0x64, 0x49, 0x66, 0x70, 0xda, 0x0f, 0x3c,
++	0x26, 0x99, 0xa7, 0x00, 0xd2, 0x3e, 0xcc, 0x3a,
++	0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x21, 0xa8, 0x84, 0x65, 0x8a, 0x25, 0x3c, 0x0b,
++	0x26, 0x1f, 0xc0, 0xb4, 0x66, 0xb7, 0x19, 0x01,
++	0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x21, 0xa8, 0x84, 0x65, 0x8a, 0x25, 0x3c, 0x0b,
++	0x26, 0x1f, 0xc0, 0xb4, 0x66, 0xb7, 0x19, 0x01,
++	0x73, 0x6e, 0x18, 0x18, 0x16, 0x96, 0xa5, 0x88,
++	0x9c, 0x31, 0x59, 0xfa, 0xab, 0xab, 0x20, 0xfd
++};
++static const u8 enc_assoc105[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce105[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key105[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input106[] __initconst = {
++	0xad, 0xba, 0x5d, 0x10, 0x5b, 0xc8, 0xaa, 0x06,
++	0x2c, 0x23, 0x36, 0xcb, 0x88, 0x9d, 0xdb, 0xd5,
++	0x37, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09,
++	0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8,
++	0x17, 0x7c, 0x5f, 0xfe, 0x28, 0x75, 0xf4, 0x68,
++	0xf6, 0xc2, 0x96, 0x57, 0x48, 0xf3, 0x59, 0x9a,
++	0xd3, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39,
++	0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4,
++	0xcf, 0x2b, 0x22, 0x5d, 0xb1, 0x60, 0x7a, 0x10,
++	0xe6, 0xd5, 0x40, 0x1e, 0x53, 0xb4, 0x2a, 0x8d
++};
++static const u8 enc_output106[] __initconst = {
++	0xad, 0xd1, 0x8a, 0x3f, 0xdd, 0x02, 0x4a, 0x9f,
++	0x8f, 0x0c, 0xc8, 0x01, 0x34, 0x7b, 0xa3, 0x76,
++	0xb0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x77, 0xf9, 0x4d, 0x34, 0x1c, 0xd0, 0x24, 0x5d,
++	0xa9, 0x09, 0x07, 0x53, 0x24, 0x69, 0xf2, 0x01,
++	0xb0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x77, 0xf9, 0x4d, 0x34, 0x1c, 0xd0, 0x24, 0x5d,
++	0xa9, 0x09, 0x07, 0x53, 0x24, 0x69, 0xf2, 0x01,
++	0xba, 0xd5, 0x8f, 0x10, 0xa9, 0x1e, 0x6a, 0x88,
++	0x9a, 0xba, 0x32, 0xfd, 0x17, 0xd8, 0x33, 0x1a
++};
++static const u8 enc_assoc106[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce106[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key106[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input107[] __initconst = {
++	0xfe, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66,
++	0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c,
++	0xc0, 0x01, 0xed, 0xc5, 0xda, 0x44, 0x2e, 0x71,
++	0x9b, 0xce, 0x9a, 0xbe, 0x27, 0x3a, 0xf1, 0x44,
++	0xb4, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca,
++	0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64,
++	0x48, 0x02, 0x5f, 0x41, 0xfa, 0x4e, 0x33, 0x6c,
++	0x78, 0x69, 0x57, 0xa2, 0xa7, 0xc4, 0x93, 0x0a,
++	0x6c, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2,
++	0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73,
++	0x00, 0x26, 0x6e, 0xa1, 0xe4, 0x36, 0x44, 0xa3,
++	0x4d, 0x8d, 0xd1, 0xdc, 0x93, 0xf2, 0xfa, 0x13
++};
++static const u8 enc_output107[] __initconst = {
++	0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x47, 0xc3, 0x27, 0xcc, 0x36, 0x5d, 0x08, 0x87,
++	0x59, 0x09, 0x8c, 0x34, 0x1b, 0x4a, 0xed, 0x03,
++	0xd4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x2b, 0x0b, 0x97, 0x3f, 0x74, 0x5b, 0x28, 0xaa,
++	0xe9, 0x37, 0xf5, 0x9f, 0x18, 0xea, 0xc7, 0x01,
++	0xd4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x2b, 0x0b, 0x97, 0x3f, 0x74, 0x5b, 0x28, 0xaa,
++	0xe9, 0x37, 0xf5, 0x9f, 0x18, 0xea, 0xc7, 0x01,
++	0xd6, 0x8c, 0xe1, 0x74, 0x07, 0x9a, 0xdd, 0x02,
++	0x8d, 0xd0, 0x5c, 0xf8, 0x14, 0x63, 0x04, 0x88
++};
++static const u8 enc_assoc107[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce107[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key107[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input108[] __initconst = {
++	0xb5, 0x13, 0xb0, 0x6a, 0xb9, 0xac, 0x14, 0x43,
++	0x5a, 0xcb, 0x8a, 0xa3, 0xa3, 0x7a, 0xfd, 0xb6,
++	0x54, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09,
++	0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8,
++	0x61, 0x95, 0x01, 0x93, 0xb1, 0xbf, 0x03, 0x11,
++	0xff, 0x11, 0x79, 0x89, 0xae, 0xd9, 0xa9, 0x99,
++	0xb0, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39,
++	0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4,
++	0xb9, 0xc2, 0x7c, 0x30, 0x28, 0xaa, 0x8d, 0x69,
++	0xef, 0x06, 0xaf, 0xc0, 0xb5, 0x9e, 0xda, 0x8e
++};
++static const u8 enc_output108[] __initconst = {
++	0xb5, 0x78, 0x67, 0x45, 0x3f, 0x66, 0xf4, 0xda,
++	0xf9, 0xe4, 0x74, 0x69, 0x1f, 0x9c, 0x85, 0x15,
++	0xd3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x01, 0x10, 0x13, 0x59, 0x85, 0x1a, 0xd3, 0x24,
++	0xa0, 0xda, 0xe8, 0x8d, 0xc2, 0x43, 0x02, 0x02,
++	0xd3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x01, 0x10, 0x13, 0x59, 0x85, 0x1a, 0xd3, 0x24,
++	0xa0, 0xda, 0xe8, 0x8d, 0xc2, 0x43, 0x02, 0x02,
++	0xaa, 0x48, 0xa3, 0x88, 0x7d, 0x4b, 0x05, 0x96,
++	0x99, 0xc2, 0xfd, 0xf9, 0xc6, 0x78, 0x7e, 0x0a
++};
++static const u8 enc_assoc108[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce108[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key108[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input109[] __initconst = {
++	0xff, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66,
++	0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c,
++	0xd4, 0xf1, 0x09, 0xe8, 0x14, 0xce, 0xa8, 0x5a,
++	0x08, 0xc0, 0x11, 0xd8, 0x50, 0xdd, 0x1d, 0xcb,
++	0xcf, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca,
++	0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64,
++	0x53, 0x40, 0xb8, 0x5a, 0x9a, 0xa0, 0x82, 0x96,
++	0xb7, 0x7a, 0x5f, 0xc3, 0x96, 0x1f, 0x66, 0x0f,
++	0x17, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2,
++	0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73,
++	0x1b, 0x64, 0x89, 0xba, 0x84, 0xd8, 0xf5, 0x59,
++	0x82, 0x9e, 0xd9, 0xbd, 0xa2, 0x29, 0x0f, 0x16
++};
++static const u8 enc_output109[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x53, 0x33, 0xc3, 0xe1, 0xf8, 0xd7, 0x8e, 0xac,
++	0xca, 0x07, 0x07, 0x52, 0x6c, 0xad, 0x01, 0x8c,
++	0xaf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x30, 0x49, 0x70, 0x24, 0x14, 0xb5, 0x99, 0x50,
++	0x26, 0x24, 0xfd, 0xfe, 0x29, 0x31, 0x32, 0x04,
++	0xaf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x30, 0x49, 0x70, 0x24, 0x14, 0xb5, 0x99, 0x50,
++	0x26, 0x24, 0xfd, 0xfe, 0x29, 0x31, 0x32, 0x04,
++	0xb9, 0x36, 0xa8, 0x17, 0xf2, 0x21, 0x1a, 0xf1,
++	0x29, 0xe2, 0xcf, 0x16, 0x0f, 0xd4, 0x2b, 0xcb
++};
++static const u8 enc_assoc109[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce109[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key109[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input110[] __initconst = {
++	0xff, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66,
++	0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c,
++	0xdf, 0x4c, 0x62, 0x03, 0x2d, 0x41, 0x19, 0xb5,
++	0x88, 0x47, 0x7e, 0x99, 0x92, 0x5a, 0x56, 0xd9,
++	0xd6, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca,
++	0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64,
++	0xfa, 0x84, 0xf0, 0x64, 0x55, 0x36, 0x42, 0x1b,
++	0x2b, 0xb9, 0x24, 0x6e, 0xc2, 0x19, 0xed, 0x0b,
++	0x0e, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2,
++	0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73,
++	0xb2, 0xa0, 0xc1, 0x84, 0x4b, 0x4e, 0x35, 0xd4,
++	0x1e, 0x5d, 0xa2, 0x10, 0xf6, 0x2f, 0x84, 0x12
++};
++static const u8 enc_output110[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x58, 0x8e, 0xa8, 0x0a, 0xc1, 0x58, 0x3f, 0x43,
++	0x4a, 0x80, 0x68, 0x13, 0xae, 0x2a, 0x4a, 0x9e,
++	0xb6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x99, 0x8d, 0x38, 0x1a, 0xdb, 0x23, 0x59, 0xdd,
++	0xba, 0xe7, 0x86, 0x53, 0x7d, 0x37, 0xb9, 0x00,
++	0xb6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x99, 0x8d, 0x38, 0x1a, 0xdb, 0x23, 0x59, 0xdd,
++	0xba, 0xe7, 0x86, 0x53, 0x7d, 0x37, 0xb9, 0x00,
++	0x9f, 0x7a, 0xc4, 0x35, 0x1f, 0x6b, 0x91, 0xe6,
++	0x30, 0x97, 0xa7, 0x13, 0x11, 0x5d, 0x05, 0xbe
++};
++static const u8 enc_assoc110[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce110[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key110[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input111[] __initconst = {
++	0xff, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66,
++	0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c,
++	0x13, 0xf8, 0x0a, 0x00, 0x6d, 0xc1, 0xbb, 0xda,
++	0xd6, 0x39, 0xa9, 0x2f, 0xc7, 0xec, 0xa6, 0x55,
++	0xf7, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca,
++	0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64,
++	0x63, 0x48, 0xb8, 0xfd, 0x29, 0xbf, 0x96, 0xd5,
++	0x63, 0xa5, 0x17, 0xe2, 0x7d, 0x7b, 0xfc, 0x0f,
++	0x2f, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2,
++	0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73,
++	0x2b, 0x6c, 0x89, 0x1d, 0x37, 0xc7, 0xe1, 0x1a,
++	0x56, 0x41, 0x91, 0x9c, 0x49, 0x4d, 0x95, 0x16
++};
++static const u8 enc_output111[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x94, 0x3a, 0xc0, 0x09, 0x81, 0xd8, 0x9d, 0x2c,
++	0x14, 0xfe, 0xbf, 0xa5, 0xfb, 0x9c, 0xba, 0x12,
++	0x97, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x41, 0x70, 0x83, 0xa7, 0xaa, 0x8d, 0x13,
++	0xf2, 0xfb, 0xb5, 0xdf, 0xc2, 0x55, 0xa8, 0x04,
++	0x97, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x41, 0x70, 0x83, 0xa7, 0xaa, 0x8d, 0x13,
++	0xf2, 0xfb, 0xb5, 0xdf, 0xc2, 0x55, 0xa8, 0x04,
++	0x9a, 0x18, 0xa8, 0x28, 0x07, 0x02, 0x69, 0xf4,
++	0x47, 0x00, 0xd0, 0x09, 0xe7, 0x17, 0x1c, 0xc9
++};
++static const u8 enc_assoc111[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce111[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key111[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input112[] __initconst = {
++	0xff, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66,
++	0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c,
++	0x82, 0xe5, 0x9b, 0x45, 0x82, 0x91, 0x50, 0x38,
++	0xf9, 0x33, 0x81, 0x1e, 0x65, 0x2d, 0xc6, 0x6a,
++	0xfc, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca,
++	0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64,
++	0xb6, 0x71, 0xc8, 0xca, 0xc2, 0x70, 0xc2, 0x65,
++	0xa0, 0xac, 0x2f, 0x53, 0x57, 0x99, 0x88, 0x0a,
++	0x24, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2,
++	0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73,
++	0xfe, 0x55, 0xf9, 0x2a, 0xdc, 0x08, 0xb5, 0xaa,
++	0x95, 0x48, 0xa9, 0x2d, 0x63, 0xaf, 0xe1, 0x13
++};
++static const u8 enc_output112[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x05, 0x27, 0x51, 0x4c, 0x6e, 0x88, 0x76, 0xce,
++	0x3b, 0xf4, 0x97, 0x94, 0x59, 0x5d, 0xda, 0x2d,
++	0x9c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xd5, 0x78, 0x00, 0xb4, 0x4c, 0x65, 0xd9, 0xa3,
++	0x31, 0xf2, 0x8d, 0x6e, 0xe8, 0xb7, 0xdc, 0x01,
++	0x9c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xd5, 0x78, 0x00, 0xb4, 0x4c, 0x65, 0xd9, 0xa3,
++	0x31, 0xf2, 0x8d, 0x6e, 0xe8, 0xb7, 0xdc, 0x01,
++	0xb4, 0x36, 0xa8, 0x2b, 0x93, 0xd5, 0x55, 0xf7,
++	0x43, 0x00, 0xd0, 0x19, 0x9b, 0xa7, 0x18, 0xce
++};
++static const u8 enc_assoc112[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce112[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key112[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input113[] __initconst = {
++	0xff, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66,
++	0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c,
++	0xf1, 0xd1, 0x28, 0x87, 0xb7, 0x21, 0x69, 0x86,
++	0xa1, 0x2d, 0x79, 0x09, 0x8b, 0x6d, 0xe6, 0x0f,
++	0xc0, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca,
++	0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64,
++	0xa7, 0xc7, 0x58, 0x99, 0xf3, 0xe6, 0x0a, 0xf1,
++	0xfc, 0xb6, 0xc7, 0x30, 0x7d, 0x87, 0x59, 0x0f,
++	0x18, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2,
++	0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73,
++	0xef, 0xe3, 0x69, 0x79, 0xed, 0x9e, 0x7d, 0x3e,
++	0xc9, 0x52, 0x41, 0x4e, 0x49, 0xb1, 0x30, 0x16
++};
++static const u8 enc_output113[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x76, 0x13, 0xe2, 0x8e, 0x5b, 0x38, 0x4f, 0x70,
++	0x63, 0xea, 0x6f, 0x83, 0xb7, 0x1d, 0xfa, 0x48,
++	0xa0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xc4, 0xce, 0x90, 0xe7, 0x7d, 0xf3, 0x11, 0x37,
++	0x6d, 0xe8, 0x65, 0x0d, 0xc2, 0xa9, 0x0d, 0x04,
++	0xa0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xc4, 0xce, 0x90, 0xe7, 0x7d, 0xf3, 0x11, 0x37,
++	0x6d, 0xe8, 0x65, 0x0d, 0xc2, 0xa9, 0x0d, 0x04,
++	0xce, 0x54, 0xa8, 0x2e, 0x1f, 0xa9, 0x42, 0xfa,
++	0x3f, 0x00, 0xd0, 0x29, 0x4f, 0x37, 0x15, 0xd3
++};
++static const u8 enc_assoc113[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce113[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key113[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input114[] __initconst = {
++	0xcb, 0xf1, 0xda, 0x9e, 0x0b, 0xa9, 0x37, 0x73,
++	0x74, 0xe6, 0x9e, 0x1c, 0x0e, 0x60, 0x0c, 0xfc,
++	0x34, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09,
++	0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8,
++	0xbe, 0x3f, 0xa6, 0x6b, 0x6c, 0xe7, 0x80, 0x8a,
++	0xa3, 0xe4, 0x59, 0x49, 0xf9, 0x44, 0x64, 0x9f,
++	0xd0, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39,
++	0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4,
++	0x66, 0x68, 0xdb, 0xc8, 0xf5, 0xf2, 0x0e, 0xf2,
++	0xb3, 0xf3, 0x8f, 0x00, 0xe2, 0x03, 0x17, 0x88
++};
++static const u8 enc_output114[] __initconst = {
++	0xcb, 0x9a, 0x0d, 0xb1, 0x8d, 0x63, 0xd7, 0xea,
++	0xd7, 0xc9, 0x60, 0xd6, 0xb2, 0x86, 0x74, 0x5f,
++	0xb3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xde, 0xba, 0xb4, 0xa1, 0x58, 0x42, 0x50, 0xbf,
++	0xfc, 0x2f, 0xc8, 0x4d, 0x95, 0xde, 0xcf, 0x04,
++	0xb3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xde, 0xba, 0xb4, 0xa1, 0x58, 0x42, 0x50, 0xbf,
++	0xfc, 0x2f, 0xc8, 0x4d, 0x95, 0xde, 0xcf, 0x04,
++	0x23, 0x83, 0xab, 0x0b, 0x79, 0x92, 0x05, 0x69,
++	0x9b, 0x51, 0x0a, 0xa7, 0x09, 0xbf, 0x31, 0xf1
++};
++static const u8 enc_assoc114[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce114[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key114[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input115[] __initconst = {
++	0x8f, 0x27, 0x86, 0x94, 0xc4, 0xe9, 0xda, 0xeb,
++	0xd5, 0x8d, 0x3e, 0x5b, 0x96, 0x6e, 0x8b, 0x68,
++	0x42, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09,
++	0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8,
++	0x06, 0x53, 0xe7, 0xa3, 0x31, 0x71, 0x88, 0x33,
++	0xac, 0xc3, 0xb9, 0xad, 0xff, 0x1c, 0x31, 0x98,
++	0xa6, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39,
++	0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4,
++	0xde, 0x04, 0x9a, 0x00, 0xa8, 0x64, 0x06, 0x4b,
++	0xbc, 0xd4, 0x6f, 0xe4, 0xe4, 0x5b, 0x42, 0x8f
++};
++static const u8 enc_output115[] __initconst = {
++	0x8f, 0x4c, 0x51, 0xbb, 0x42, 0x23, 0x3a, 0x72,
++	0x76, 0xa2, 0xc0, 0x91, 0x2a, 0x88, 0xf3, 0xcb,
++	0xc5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x66, 0xd6, 0xf5, 0x69, 0x05, 0xd4, 0x58, 0x06,
++	0xf3, 0x08, 0x28, 0xa9, 0x93, 0x86, 0x9a, 0x03,
++	0xc5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x66, 0xd6, 0xf5, 0x69, 0x05, 0xd4, 0x58, 0x06,
++	0xf3, 0x08, 0x28, 0xa9, 0x93, 0x86, 0x9a, 0x03,
++	0x8b, 0xfb, 0xab, 0x17, 0xa9, 0xe0, 0xb8, 0x74,
++	0x8b, 0x51, 0x0a, 0xe7, 0xd9, 0xfd, 0x23, 0x05
++};
++static const u8 enc_assoc115[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce115[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key115[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input116[] __initconst = {
++	0xd5, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66,
++	0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c,
++	0x9a, 0x22, 0xd7, 0x0a, 0x48, 0xe2, 0x4f, 0xdd,
++	0xcd, 0xd4, 0x41, 0x9d, 0xe6, 0x4c, 0x8f, 0x44,
++	0xfc, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca,
++	0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64,
++	0x77, 0xb5, 0xc9, 0x07, 0xd9, 0xc9, 0xe1, 0xea,
++	0x51, 0x85, 0x1a, 0x20, 0x4a, 0xad, 0x9f, 0x0a,
++	0x24, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2,
++	0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73,
++	0x3f, 0x91, 0xf8, 0xe7, 0xc7, 0xb1, 0x96, 0x25,
++	0x64, 0x61, 0x9c, 0x5e, 0x7e, 0x9b, 0xf6, 0x13
++};
++static const u8 enc_output116[] __initconst = {
++	0xd5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x1d, 0xe0, 0x1d, 0x03, 0xa4, 0xfb, 0x69, 0x2b,
++	0x0f, 0x13, 0x57, 0x17, 0xda, 0x3c, 0x93, 0x03,
++	0x9c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x14, 0xbc, 0x01, 0x79, 0x57, 0xdc, 0xfa, 0x2c,
++	0xc0, 0xdb, 0xb8, 0x1d, 0xf5, 0x83, 0xcb, 0x01,
++	0x9c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x14, 0xbc, 0x01, 0x79, 0x57, 0xdc, 0xfa, 0x2c,
++	0xc0, 0xdb, 0xb8, 0x1d, 0xf5, 0x83, 0xcb, 0x01,
++	0x49, 0xbc, 0x6e, 0x9f, 0xc5, 0x1c, 0x4d, 0x50,
++	0x30, 0x36, 0x64, 0x4d, 0x84, 0x27, 0x73, 0xd2
++};
++static const u8 enc_assoc116[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce116[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key116[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input117[] __initconst = {
++	0xdb, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66,
++	0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c,
++	0x75, 0xd5, 0x64, 0x3a, 0xa5, 0xaf, 0x93, 0x4d,
++	0x8c, 0xce, 0x39, 0x2c, 0xc3, 0xee, 0xdb, 0x47,
++	0xc0, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca,
++	0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64,
++	0x60, 0x1b, 0x5a, 0xd2, 0x06, 0x7f, 0x28, 0x06,
++	0x6a, 0x8f, 0x32, 0x81, 0x71, 0x5b, 0xa8, 0x08,
++	0x18, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2,
++	0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73,
++	0x28, 0x3f, 0x6b, 0x32, 0x18, 0x07, 0x5f, 0xc9,
++	0x5f, 0x6b, 0xb4, 0xff, 0x45, 0x6d, 0xc1, 0x11
++};
++static const u8 enc_output117[] __initconst = {
++	0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xf2, 0x17, 0xae, 0x33, 0x49, 0xb6, 0xb5, 0xbb,
++	0x4e, 0x09, 0x2f, 0xa6, 0xff, 0x9e, 0xc7, 0x00,
++	0xa0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x03, 0x12, 0x92, 0xac, 0x88, 0x6a, 0x33, 0xc0,
++	0xfb, 0xd1, 0x90, 0xbc, 0xce, 0x75, 0xfc, 0x03,
++	0xa0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x03, 0x12, 0x92, 0xac, 0x88, 0x6a, 0x33, 0xc0,
++	0xfb, 0xd1, 0x90, 0xbc, 0xce, 0x75, 0xfc, 0x03,
++	0x63, 0xda, 0x6e, 0xa2, 0x51, 0xf0, 0x39, 0x53,
++	0x2c, 0x36, 0x64, 0x5d, 0x38, 0xb7, 0x6f, 0xd7
++};
++static const u8 enc_assoc117[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce117[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key117[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - edge case intermediate sums in poly1305 */
++static const u8 enc_input118[] __initconst = {
++	0x93, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66,
++	0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c,
++	0x62, 0x48, 0x39, 0x60, 0x42, 0x16, 0xe4, 0x03,
++	0xeb, 0xcc, 0x6a, 0xf5, 0x59, 0xec, 0x8b, 0x43,
++	0x97, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca,
++	0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64,
++	0xd8, 0xc8, 0xc3, 0xfa, 0x1a, 0x9e, 0x47, 0x4a,
++	0xbe, 0x52, 0xd0, 0x2c, 0x81, 0x87, 0xe9, 0x0f,
++	0x4f, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2,
++	0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73,
++	0x90, 0xec, 0xf2, 0x1a, 0x04, 0xe6, 0x30, 0x85,
++	0x8b, 0xb6, 0x56, 0x52, 0xb5, 0xb1, 0x80, 0x16
++};
++static const u8 enc_output118[] __initconst = {
++	0x93, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xe5, 0x8a, 0xf3, 0x69, 0xae, 0x0f, 0xc2, 0xf5,
++	0x29, 0x0b, 0x7c, 0x7f, 0x65, 0x9c, 0x97, 0x04,
++	0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xbb, 0xc1, 0x0b, 0x84, 0x94, 0x8b, 0x5c, 0x8c,
++	0x2f, 0x0c, 0x72, 0x11, 0x3e, 0xa9, 0xbd, 0x04,
++	0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xbb, 0xc1, 0x0b, 0x84, 0x94, 0x8b, 0x5c, 0x8c,
++	0x2f, 0x0c, 0x72, 0x11, 0x3e, 0xa9, 0xbd, 0x04,
++	0x73, 0xeb, 0x27, 0x24, 0xb5, 0xc4, 0x05, 0xf0,
++	0x4d, 0x00, 0xd0, 0xf1, 0x58, 0x40, 0xa1, 0xc1
++};
++static const u8 enc_assoc118[] __initconst = {
++	0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce118[] __initconst = {
++	0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52
++};
++static const u8 enc_key118[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++static const struct chacha20poly1305_testvec
++chacha20poly1305_enc_vectors[] __initconst = {
++	{ enc_input001, enc_output001, enc_assoc001, enc_nonce001, enc_key001,
++	  sizeof(enc_input001), sizeof(enc_assoc001), sizeof(enc_nonce001) },
++	{ enc_input002, enc_output002, enc_assoc002, enc_nonce002, enc_key002,
++	  sizeof(enc_input002), sizeof(enc_assoc002), sizeof(enc_nonce002) },
++	{ enc_input003, enc_output003, enc_assoc003, enc_nonce003, enc_key003,
++	  sizeof(enc_input003), sizeof(enc_assoc003), sizeof(enc_nonce003) },
++	{ enc_input004, enc_output004, enc_assoc004, enc_nonce004, enc_key004,
++	  sizeof(enc_input004), sizeof(enc_assoc004), sizeof(enc_nonce004) },
++	{ enc_input005, enc_output005, enc_assoc005, enc_nonce005, enc_key005,
++	  sizeof(enc_input005), sizeof(enc_assoc005), sizeof(enc_nonce005) },
++	{ enc_input006, enc_output006, enc_assoc006, enc_nonce006, enc_key006,
++	  sizeof(enc_input006), sizeof(enc_assoc006), sizeof(enc_nonce006) },
++	{ enc_input007, enc_output007, enc_assoc007, enc_nonce007, enc_key007,
++	  sizeof(enc_input007), sizeof(enc_assoc007), sizeof(enc_nonce007) },
++	{ enc_input008, enc_output008, enc_assoc008, enc_nonce008, enc_key008,
++	  sizeof(enc_input008), sizeof(enc_assoc008), sizeof(enc_nonce008) },
++	{ enc_input009, enc_output009, enc_assoc009, enc_nonce009, enc_key009,
++	  sizeof(enc_input009), sizeof(enc_assoc009), sizeof(enc_nonce009) },
++	{ enc_input010, enc_output010, enc_assoc010, enc_nonce010, enc_key010,
++	  sizeof(enc_input010), sizeof(enc_assoc010), sizeof(enc_nonce010) },
++	{ enc_input011, enc_output011, enc_assoc011, enc_nonce011, enc_key011,
++	  sizeof(enc_input011), sizeof(enc_assoc011), sizeof(enc_nonce011) },
++	{ enc_input012, enc_output012, enc_assoc012, enc_nonce012, enc_key012,
++	  sizeof(enc_input012), sizeof(enc_assoc012), sizeof(enc_nonce012) },
++	{ enc_input053, enc_output053, enc_assoc053, enc_nonce053, enc_key053,
++	  sizeof(enc_input053), sizeof(enc_assoc053), sizeof(enc_nonce053) },
++	{ enc_input054, enc_output054, enc_assoc054, enc_nonce054, enc_key054,
++	  sizeof(enc_input054), sizeof(enc_assoc054), sizeof(enc_nonce054) },
++	{ enc_input055, enc_output055, enc_assoc055, enc_nonce055, enc_key055,
++	  sizeof(enc_input055), sizeof(enc_assoc055), sizeof(enc_nonce055) },
++	{ enc_input056, enc_output056, enc_assoc056, enc_nonce056, enc_key056,
++	  sizeof(enc_input056), sizeof(enc_assoc056), sizeof(enc_nonce056) },
++	{ enc_input057, enc_output057, enc_assoc057, enc_nonce057, enc_key057,
++	  sizeof(enc_input057), sizeof(enc_assoc057), sizeof(enc_nonce057) },
++	{ enc_input058, enc_output058, enc_assoc058, enc_nonce058, enc_key058,
++	  sizeof(enc_input058), sizeof(enc_assoc058), sizeof(enc_nonce058) },
++	{ enc_input059, enc_output059, enc_assoc059, enc_nonce059, enc_key059,
++	  sizeof(enc_input059), sizeof(enc_assoc059), sizeof(enc_nonce059) },
++	{ enc_input060, enc_output060, enc_assoc060, enc_nonce060, enc_key060,
++	  sizeof(enc_input060), sizeof(enc_assoc060), sizeof(enc_nonce060) },
++	{ enc_input061, enc_output061, enc_assoc061, enc_nonce061, enc_key061,
++	  sizeof(enc_input061), sizeof(enc_assoc061), sizeof(enc_nonce061) },
++	{ enc_input062, enc_output062, enc_assoc062, enc_nonce062, enc_key062,
++	  sizeof(enc_input062), sizeof(enc_assoc062), sizeof(enc_nonce062) },
++	{ enc_input063, enc_output063, enc_assoc063, enc_nonce063, enc_key063,
++	  sizeof(enc_input063), sizeof(enc_assoc063), sizeof(enc_nonce063) },
++	{ enc_input064, enc_output064, enc_assoc064, enc_nonce064, enc_key064,
++	  sizeof(enc_input064), sizeof(enc_assoc064), sizeof(enc_nonce064) },
++	{ enc_input065, enc_output065, enc_assoc065, enc_nonce065, enc_key065,
++	  sizeof(enc_input065), sizeof(enc_assoc065), sizeof(enc_nonce065) },
++	{ enc_input066, enc_output066, enc_assoc066, enc_nonce066, enc_key066,
++	  sizeof(enc_input066), sizeof(enc_assoc066), sizeof(enc_nonce066) },
++	{ enc_input067, enc_output067, enc_assoc067, enc_nonce067, enc_key067,
++	  sizeof(enc_input067), sizeof(enc_assoc067), sizeof(enc_nonce067) },
++	{ enc_input068, enc_output068, enc_assoc068, enc_nonce068, enc_key068,
++	  sizeof(enc_input068), sizeof(enc_assoc068), sizeof(enc_nonce068) },
++	{ enc_input069, enc_output069, enc_assoc069, enc_nonce069, enc_key069,
++	  sizeof(enc_input069), sizeof(enc_assoc069), sizeof(enc_nonce069) },
++	{ enc_input070, enc_output070, enc_assoc070, enc_nonce070, enc_key070,
++	  sizeof(enc_input070), sizeof(enc_assoc070), sizeof(enc_nonce070) },
++	{ enc_input071, enc_output071, enc_assoc071, enc_nonce071, enc_key071,
++	  sizeof(enc_input071), sizeof(enc_assoc071), sizeof(enc_nonce071) },
++	{ enc_input072, enc_output072, enc_assoc072, enc_nonce072, enc_key072,
++	  sizeof(enc_input072), sizeof(enc_assoc072), sizeof(enc_nonce072) },
++	{ enc_input073, enc_output073, enc_assoc073, enc_nonce073, enc_key073,
++	  sizeof(enc_input073), sizeof(enc_assoc073), sizeof(enc_nonce073) },
++	{ enc_input076, enc_output076, enc_assoc076, enc_nonce076, enc_key076,
++	  sizeof(enc_input076), sizeof(enc_assoc076), sizeof(enc_nonce076) },
++	{ enc_input077, enc_output077, enc_assoc077, enc_nonce077, enc_key077,
++	  sizeof(enc_input077), sizeof(enc_assoc077), sizeof(enc_nonce077) },
++	{ enc_input078, enc_output078, enc_assoc078, enc_nonce078, enc_key078,
++	  sizeof(enc_input078), sizeof(enc_assoc078), sizeof(enc_nonce078) },
++	{ enc_input079, enc_output079, enc_assoc079, enc_nonce079, enc_key079,
++	  sizeof(enc_input079), sizeof(enc_assoc079), sizeof(enc_nonce079) },
++	{ enc_input080, enc_output080, enc_assoc080, enc_nonce080, enc_key080,
++	  sizeof(enc_input080), sizeof(enc_assoc080), sizeof(enc_nonce080) },
++	{ enc_input081, enc_output081, enc_assoc081, enc_nonce081, enc_key081,
++	  sizeof(enc_input081), sizeof(enc_assoc081), sizeof(enc_nonce081) },
++	{ enc_input082, enc_output082, enc_assoc082, enc_nonce082, enc_key082,
++	  sizeof(enc_input082), sizeof(enc_assoc082), sizeof(enc_nonce082) },
++	{ enc_input083, enc_output083, enc_assoc083, enc_nonce083, enc_key083,
++	  sizeof(enc_input083), sizeof(enc_assoc083), sizeof(enc_nonce083) },
++	{ enc_input084, enc_output084, enc_assoc084, enc_nonce084, enc_key084,
++	  sizeof(enc_input084), sizeof(enc_assoc084), sizeof(enc_nonce084) },
++	{ enc_input085, enc_output085, enc_assoc085, enc_nonce085, enc_key085,
++	  sizeof(enc_input085), sizeof(enc_assoc085), sizeof(enc_nonce085) },
++	{ enc_input093, enc_output093, enc_assoc093, enc_nonce093, enc_key093,
++	  sizeof(enc_input093), sizeof(enc_assoc093), sizeof(enc_nonce093) },
++	{ enc_input094, enc_output094, enc_assoc094, enc_nonce094, enc_key094,
++	  sizeof(enc_input094), sizeof(enc_assoc094), sizeof(enc_nonce094) },
++	{ enc_input095, enc_output095, enc_assoc095, enc_nonce095, enc_key095,
++	  sizeof(enc_input095), sizeof(enc_assoc095), sizeof(enc_nonce095) },
++	{ enc_input096, enc_output096, enc_assoc096, enc_nonce096, enc_key096,
++	  sizeof(enc_input096), sizeof(enc_assoc096), sizeof(enc_nonce096) },
++	{ enc_input097, enc_output097, enc_assoc097, enc_nonce097, enc_key097,
++	  sizeof(enc_input097), sizeof(enc_assoc097), sizeof(enc_nonce097) },
++	{ enc_input098, enc_output098, enc_assoc098, enc_nonce098, enc_key098,
++	  sizeof(enc_input098), sizeof(enc_assoc098), sizeof(enc_nonce098) },
++	{ enc_input099, enc_output099, enc_assoc099, enc_nonce099, enc_key099,
++	  sizeof(enc_input099), sizeof(enc_assoc099), sizeof(enc_nonce099) },
++	{ enc_input100, enc_output100, enc_assoc100, enc_nonce100, enc_key100,
++	  sizeof(enc_input100), sizeof(enc_assoc100), sizeof(enc_nonce100) },
++	{ enc_input101, enc_output101, enc_assoc101, enc_nonce101, enc_key101,
++	  sizeof(enc_input101), sizeof(enc_assoc101), sizeof(enc_nonce101) },
++	{ enc_input102, enc_output102, enc_assoc102, enc_nonce102, enc_key102,
++	  sizeof(enc_input102), sizeof(enc_assoc102), sizeof(enc_nonce102) },
++	{ enc_input103, enc_output103, enc_assoc103, enc_nonce103, enc_key103,
++	  sizeof(enc_input103), sizeof(enc_assoc103), sizeof(enc_nonce103) },
++	{ enc_input104, enc_output104, enc_assoc104, enc_nonce104, enc_key104,
++	  sizeof(enc_input104), sizeof(enc_assoc104), sizeof(enc_nonce104) },
++	{ enc_input105, enc_output105, enc_assoc105, enc_nonce105, enc_key105,
++	  sizeof(enc_input105), sizeof(enc_assoc105), sizeof(enc_nonce105) },
++	{ enc_input106, enc_output106, enc_assoc106, enc_nonce106, enc_key106,
++	  sizeof(enc_input106), sizeof(enc_assoc106), sizeof(enc_nonce106) },
++	{ enc_input107, enc_output107, enc_assoc107, enc_nonce107, enc_key107,
++	  sizeof(enc_input107), sizeof(enc_assoc107), sizeof(enc_nonce107) },
++	{ enc_input108, enc_output108, enc_assoc108, enc_nonce108, enc_key108,
++	  sizeof(enc_input108), sizeof(enc_assoc108), sizeof(enc_nonce108) },
++	{ enc_input109, enc_output109, enc_assoc109, enc_nonce109, enc_key109,
++	  sizeof(enc_input109), sizeof(enc_assoc109), sizeof(enc_nonce109) },
++	{ enc_input110, enc_output110, enc_assoc110, enc_nonce110, enc_key110,
++	  sizeof(enc_input110), sizeof(enc_assoc110), sizeof(enc_nonce110) },
++	{ enc_input111, enc_output111, enc_assoc111, enc_nonce111, enc_key111,
++	  sizeof(enc_input111), sizeof(enc_assoc111), sizeof(enc_nonce111) },
++	{ enc_input112, enc_output112, enc_assoc112, enc_nonce112, enc_key112,
++	  sizeof(enc_input112), sizeof(enc_assoc112), sizeof(enc_nonce112) },
++	{ enc_input113, enc_output113, enc_assoc113, enc_nonce113, enc_key113,
++	  sizeof(enc_input113), sizeof(enc_assoc113), sizeof(enc_nonce113) },
++	{ enc_input114, enc_output114, enc_assoc114, enc_nonce114, enc_key114,
++	  sizeof(enc_input114), sizeof(enc_assoc114), sizeof(enc_nonce114) },
++	{ enc_input115, enc_output115, enc_assoc115, enc_nonce115, enc_key115,
++	  sizeof(enc_input115), sizeof(enc_assoc115), sizeof(enc_nonce115) },
++	{ enc_input116, enc_output116, enc_assoc116, enc_nonce116, enc_key116,
++	  sizeof(enc_input116), sizeof(enc_assoc116), sizeof(enc_nonce116) },
++	{ enc_input117, enc_output117, enc_assoc117, enc_nonce117, enc_key117,
++	  sizeof(enc_input117), sizeof(enc_assoc117), sizeof(enc_nonce117) },
++	{ enc_input118, enc_output118, enc_assoc118, enc_nonce118, enc_key118,
++	  sizeof(enc_input118), sizeof(enc_assoc118), sizeof(enc_nonce118) }
++};
++
++static const u8 dec_input001[] __initconst = {
++	0x64, 0xa0, 0x86, 0x15, 0x75, 0x86, 0x1a, 0xf4,
++	0x60, 0xf0, 0x62, 0xc7, 0x9b, 0xe6, 0x43, 0xbd,
++	0x5e, 0x80, 0x5c, 0xfd, 0x34, 0x5c, 0xf3, 0x89,
++	0xf1, 0x08, 0x67, 0x0a, 0xc7, 0x6c, 0x8c, 0xb2,
++	0x4c, 0x6c, 0xfc, 0x18, 0x75, 0x5d, 0x43, 0xee,
++	0xa0, 0x9e, 0xe9, 0x4e, 0x38, 0x2d, 0x26, 0xb0,
++	0xbd, 0xb7, 0xb7, 0x3c, 0x32, 0x1b, 0x01, 0x00,
++	0xd4, 0xf0, 0x3b, 0x7f, 0x35, 0x58, 0x94, 0xcf,
++	0x33, 0x2f, 0x83, 0x0e, 0x71, 0x0b, 0x97, 0xce,
++	0x98, 0xc8, 0xa8, 0x4a, 0xbd, 0x0b, 0x94, 0x81,
++	0x14, 0xad, 0x17, 0x6e, 0x00, 0x8d, 0x33, 0xbd,
++	0x60, 0xf9, 0x82, 0xb1, 0xff, 0x37, 0xc8, 0x55,
++	0x97, 0x97, 0xa0, 0x6e, 0xf4, 0xf0, 0xef, 0x61,
++	0xc1, 0x86, 0x32, 0x4e, 0x2b, 0x35, 0x06, 0x38,
++	0x36, 0x06, 0x90, 0x7b, 0x6a, 0x7c, 0x02, 0xb0,
++	0xf9, 0xf6, 0x15, 0x7b, 0x53, 0xc8, 0x67, 0xe4,
++	0xb9, 0x16, 0x6c, 0x76, 0x7b, 0x80, 0x4d, 0x46,
++	0xa5, 0x9b, 0x52, 0x16, 0xcd, 0xe7, 0xa4, 0xe9,
++	0x90, 0x40, 0xc5, 0xa4, 0x04, 0x33, 0x22, 0x5e,
++	0xe2, 0x82, 0xa1, 0xb0, 0xa0, 0x6c, 0x52, 0x3e,
++	0xaf, 0x45, 0x34, 0xd7, 0xf8, 0x3f, 0xa1, 0x15,
++	0x5b, 0x00, 0x47, 0x71, 0x8c, 0xbc, 0x54, 0x6a,
++	0x0d, 0x07, 0x2b, 0x04, 0xb3, 0x56, 0x4e, 0xea,
++	0x1b, 0x42, 0x22, 0x73, 0xf5, 0x48, 0x27, 0x1a,
++	0x0b, 0xb2, 0x31, 0x60, 0x53, 0xfa, 0x76, 0x99,
++	0x19, 0x55, 0xeb, 0xd6, 0x31, 0x59, 0x43, 0x4e,
++	0xce, 0xbb, 0x4e, 0x46, 0x6d, 0xae, 0x5a, 0x10,
++	0x73, 0xa6, 0x72, 0x76, 0x27, 0x09, 0x7a, 0x10,
++	0x49, 0xe6, 0x17, 0xd9, 0x1d, 0x36, 0x10, 0x94,
++	0xfa, 0x68, 0xf0, 0xff, 0x77, 0x98, 0x71, 0x30,
++	0x30, 0x5b, 0xea, 0xba, 0x2e, 0xda, 0x04, 0xdf,
++	0x99, 0x7b, 0x71, 0x4d, 0x6c, 0x6f, 0x2c, 0x29,
++	0xa6, 0xad, 0x5c, 0xb4, 0x02, 0x2b, 0x02, 0x70,
++	0x9b, 0xee, 0xad, 0x9d, 0x67, 0x89, 0x0c, 0xbb,
++	0x22, 0x39, 0x23, 0x36, 0xfe, 0xa1, 0x85, 0x1f,
++	0x38
++};
++static const u8 dec_output001[] __initconst = {
++	0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
++	0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x73, 0x20,
++	0x61, 0x72, 0x65, 0x20, 0x64, 0x72, 0x61, 0x66,
++	0x74, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65,
++	0x6e, 0x74, 0x73, 0x20, 0x76, 0x61, 0x6c, 0x69,
++	0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20,
++	0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20,
++	0x6f, 0x66, 0x20, 0x73, 0x69, 0x78, 0x20, 0x6d,
++	0x6f, 0x6e, 0x74, 0x68, 0x73, 0x20, 0x61, 0x6e,
++	0x64, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65,
++	0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64,
++	0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63,
++	0x65, 0x64, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x6f,
++	0x62, 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x64,
++	0x20, 0x62, 0x79, 0x20, 0x6f, 0x74, 0x68, 0x65,
++	0x72, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65,
++	0x6e, 0x74, 0x73, 0x20, 0x61, 0x74, 0x20, 0x61,
++	0x6e, 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x2e,
++	0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x69,
++	0x6e, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x70, 0x72,
++	0x69, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20,
++	0x75, 0x73, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65,
++	0x72, 0x6e, 0x65, 0x74, 0x2d, 0x44, 0x72, 0x61,
++	0x66, 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x72,
++	0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65,
++	0x20, 0x6d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61,
++	0x6c, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20,
++	0x63, 0x69, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65,
++	0x6d, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20,
++	0x74, 0x68, 0x61, 0x6e, 0x20, 0x61, 0x73, 0x20,
++	0x2f, 0xe2, 0x80, 0x9c, 0x77, 0x6f, 0x72, 0x6b,
++	0x20, 0x69, 0x6e, 0x20, 0x70, 0x72, 0x6f, 0x67,
++	0x72, 0x65, 0x73, 0x73, 0x2e, 0x2f, 0xe2, 0x80,
++	0x9d
++};
++static const u8 dec_assoc001[] __initconst = {
++	0xf3, 0x33, 0x88, 0x86, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x4e, 0x91
++};
++static const u8 dec_nonce001[] __initconst = {
++	0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
++};
++static const u8 dec_key001[] __initconst = {
++	0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a,
++	0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0,
++	0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09,
++	0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0
++};
++
++static const u8 dec_input002[] __initconst = {
++	0xea, 0xe0, 0x1e, 0x9e, 0x2c, 0x91, 0xaa, 0xe1,
++	0xdb, 0x5d, 0x99, 0x3f, 0x8a, 0xf7, 0x69, 0x92
++};
++static const u8 dec_output002[] __initconst = { };
++static const u8 dec_assoc002[] __initconst = { };
++static const u8 dec_nonce002[] __initconst = {
++	0xca, 0xbf, 0x33, 0x71, 0x32, 0x45, 0x77, 0x8e
++};
++static const u8 dec_key002[] __initconst = {
++	0x4c, 0xf5, 0x96, 0x83, 0x38, 0xe6, 0xae, 0x7f,
++	0x2d, 0x29, 0x25, 0x76, 0xd5, 0x75, 0x27, 0x86,
++	0x91, 0x9a, 0x27, 0x7a, 0xfb, 0x46, 0xc5, 0xef,
++	0x94, 0x81, 0x79, 0x57, 0x14, 0x59, 0x40, 0x68
++};
++
++static const u8 dec_input003[] __initconst = {
++	0xdd, 0x6b, 0x3b, 0x82, 0xce, 0x5a, 0xbd, 0xd6,
++	0xa9, 0x35, 0x83, 0xd8, 0x8c, 0x3d, 0x85, 0x77
++};
++static const u8 dec_output003[] __initconst = { };
++static const u8 dec_assoc003[] __initconst = {
++	0x33, 0x10, 0x41, 0x12, 0x1f, 0xf3, 0xd2, 0x6b
++};
++static const u8 dec_nonce003[] __initconst = {
++	0x3d, 0x86, 0xb5, 0x6b, 0xc8, 0xa3, 0x1f, 0x1d
++};
++static const u8 dec_key003[] __initconst = {
++	0x2d, 0xb0, 0x5d, 0x40, 0xc8, 0xed, 0x44, 0x88,
++	0x34, 0xd1, 0x13, 0xaf, 0x57, 0xa1, 0xeb, 0x3a,
++	0x2a, 0x80, 0x51, 0x36, 0xec, 0x5b, 0xbc, 0x08,
++	0x93, 0x84, 0x21, 0xb5, 0x13, 0x88, 0x3c, 0x0d
++};
++
++static const u8 dec_input004[] __initconst = {
++	0xb7, 0x1b, 0xb0, 0x73, 0x59, 0xb0, 0x84, 0xb2,
++	0x6d, 0x8e, 0xab, 0x94, 0x31, 0xa1, 0xae, 0xac,
++	0x89
++};
++static const u8 dec_output004[] __initconst = {
++	0xa4
++};
++static const u8 dec_assoc004[] __initconst = {
++	0x6a, 0xe2, 0xad, 0x3f, 0x88, 0x39, 0x5a, 0x40
++};
++static const u8 dec_nonce004[] __initconst = {
++	0xd2, 0x32, 0x1f, 0x29, 0x28, 0xc6, 0xc4, 0xc4
++};
++static const u8 dec_key004[] __initconst = {
++	0x4b, 0x28, 0x4b, 0xa3, 0x7b, 0xbe, 0xe9, 0xf8,
++	0x31, 0x80, 0x82, 0xd7, 0xd8, 0xe8, 0xb5, 0xa1,
++	0xe2, 0x18, 0x18, 0x8a, 0x9c, 0xfa, 0xa3, 0x3d,
++	0x25, 0x71, 0x3e, 0x40, 0xbc, 0x54, 0x7a, 0x3e
++};
++
++static const u8 dec_input005[] __initconst = {
++	0xbf, 0xe1, 0x5b, 0x0b, 0xdb, 0x6b, 0xf5, 0x5e,
++	0x6c, 0x5d, 0x84, 0x44, 0x39, 0x81, 0xc1, 0x9c,
++	0xac
++};
++static const u8 dec_output005[] __initconst = {
++	0x2d
++};
++static const u8 dec_assoc005[] __initconst = { };
++static const u8 dec_nonce005[] __initconst = {
++	0x20, 0x1c, 0xaa, 0x5f, 0x9c, 0xbf, 0x92, 0x30
++};
++static const u8 dec_key005[] __initconst = {
++	0x66, 0xca, 0x9c, 0x23, 0x2a, 0x4b, 0x4b, 0x31,
++	0x0e, 0x92, 0x89, 0x8b, 0xf4, 0x93, 0xc7, 0x87,
++	0x98, 0xa3, 0xd8, 0x39, 0xf8, 0xf4, 0xa7, 0x01,
++	0xc0, 0x2e, 0x0a, 0xa6, 0x7e, 0x5a, 0x78, 0x87
++};
++
++static const u8 dec_input006[] __initconst = {
++	0x8b, 0x06, 0xd3, 0x31, 0xb0, 0x93, 0x45, 0xb1,
++	0x75, 0x6e, 0x26, 0xf9, 0x67, 0xbc, 0x90, 0x15,
++	0x81, 0x2c, 0xb5, 0xf0, 0xc6, 0x2b, 0xc7, 0x8c,
++	0x56, 0xd1, 0xbf, 0x69, 0x6c, 0x07, 0xa0, 0xda,
++	0x65, 0x27, 0xc9, 0x90, 0x3d, 0xef, 0x4b, 0x11,
++	0x0f, 0x19, 0x07, 0xfd, 0x29, 0x92, 0xd9, 0xc8,
++	0xf7, 0x99, 0x2e, 0x4a, 0xd0, 0xb8, 0x2c, 0xdc,
++	0x93, 0xf5, 0x9e, 0x33, 0x78, 0xd1, 0x37, 0xc3,
++	0x66, 0xd7, 0x5e, 0xbc, 0x44, 0xbf, 0x53, 0xa5,
++	0xbc, 0xc4, 0xcb, 0x7b, 0x3a, 0x8e, 0x7f, 0x02,
++	0xbd, 0xbb, 0xe7, 0xca, 0xa6, 0x6c, 0x6b, 0x93,
++	0x21, 0x93, 0x10, 0x61, 0xe7, 0x69, 0xd0, 0x78,
++	0xf3, 0x07, 0x5a, 0x1a, 0x8f, 0x73, 0xaa, 0xb1,
++	0x4e, 0xd3, 0xda, 0x4f, 0xf3, 0x32, 0xe1, 0x66,
++	0x3e, 0x6c, 0xc6, 0x13, 0xba, 0x06, 0x5b, 0xfc,
++	0x6a, 0xe5, 0x6f, 0x60, 0xfb, 0x07, 0x40, 0xb0,
++	0x8c, 0x9d, 0x84, 0x43, 0x6b, 0xc1, 0xf7, 0x8d,
++	0x8d, 0x31, 0xf7, 0x7a, 0x39, 0x4d, 0x8f, 0x9a,
++	0xeb
++};
++static const u8 dec_output006[] __initconst = {
++	0x33, 0x2f, 0x94, 0xc1, 0xa4, 0xef, 0xcc, 0x2a,
++	0x5b, 0xa6, 0xe5, 0x8f, 0x1d, 0x40, 0xf0, 0x92,
++	0x3c, 0xd9, 0x24, 0x11, 0xa9, 0x71, 0xf9, 0x37,
++	0x14, 0x99, 0xfa, 0xbe, 0xe6, 0x80, 0xde, 0x50,
++	0xc9, 0x96, 0xd4, 0xb0, 0xec, 0x9e, 0x17, 0xec,
++	0xd2, 0x5e, 0x72, 0x99, 0xfc, 0x0a, 0xe1, 0xcb,
++	0x48, 0xd2, 0x85, 0xdd, 0x2f, 0x90, 0xe0, 0x66,
++	0x3b, 0xe6, 0x20, 0x74, 0xbe, 0x23, 0x8f, 0xcb,
++	0xb4, 0xe4, 0xda, 0x48, 0x40, 0xa6, 0xd1, 0x1b,
++	0xc7, 0x42, 0xce, 0x2f, 0x0c, 0xa6, 0x85, 0x6e,
++	0x87, 0x37, 0x03, 0xb1, 0x7c, 0x25, 0x96, 0xa3,
++	0x05, 0xd8, 0xb0, 0xf4, 0xed, 0xea, 0xc2, 0xf0,
++	0x31, 0x98, 0x6c, 0xd1, 0x14, 0x25, 0xc0, 0xcb,
++	0x01, 0x74, 0xd0, 0x82, 0xf4, 0x36, 0xf5, 0x41,
++	0xd5, 0xdc, 0xca, 0xc5, 0xbb, 0x98, 0xfe, 0xfc,
++	0x69, 0x21, 0x70, 0xd8, 0xa4, 0x4b, 0xc8, 0xde,
++	0x8f
++};
++static const u8 dec_assoc006[] __initconst = {
++	0x70, 0xd3, 0x33, 0xf3, 0x8b, 0x18, 0x0b
++};
++static const u8 dec_nonce006[] __initconst = {
++	0xdf, 0x51, 0x84, 0x82, 0x42, 0x0c, 0x75, 0x9c
++};
++static const u8 dec_key006[] __initconst = {
++	0x68, 0x7b, 0x8d, 0x8e, 0xe3, 0xc4, 0xdd, 0xae,
++	0xdf, 0x72, 0x7f, 0x53, 0x72, 0x25, 0x1e, 0x78,
++	0x91, 0xcb, 0x69, 0x76, 0x1f, 0x49, 0x93, 0xf9,
++	0x6f, 0x21, 0xcc, 0x39, 0x9c, 0xad, 0xb1, 0x01
++};
++
++static const u8 dec_input007[] __initconst = {
++	0x85, 0x04, 0xc2, 0xed, 0x8d, 0xfd, 0x97, 0x5c,
++	0xd2, 0xb7, 0xe2, 0xc1, 0x6b, 0xa3, 0xba, 0xf8,
++	0xc9, 0x50, 0xc3, 0xc6, 0xa5, 0xe3, 0xa4, 0x7c,
++	0xc3, 0x23, 0x49, 0x5e, 0xa9, 0xb9, 0x32, 0xeb,
++	0x8a, 0x7c, 0xca, 0xe5, 0xec, 0xfb, 0x7c, 0xc0,
++	0xcb, 0x7d, 0xdc, 0x2c, 0x9d, 0x92, 0x55, 0x21,
++	0x0a, 0xc8, 0x43, 0x63, 0x59, 0x0a, 0x31, 0x70,
++	0x82, 0x67, 0x41, 0x03, 0xf8, 0xdf, 0xf2, 0xac,
++	0xa7, 0x02, 0xd4, 0xd5, 0x8a, 0x2d, 0xc8, 0x99,
++	0x19, 0x66, 0xd0, 0xf6, 0x88, 0x2c, 0x77, 0xd9,
++	0xd4, 0x0d, 0x6c, 0xbd, 0x98, 0xde, 0xe7, 0x7f,
++	0xad, 0x7e, 0x8a, 0xfb, 0xe9, 0x4b, 0xe5, 0xf7,
++	0xe5, 0x50, 0xa0, 0x90, 0x3f, 0xd6, 0x22, 0x53,
++	0xe3, 0xfe, 0x1b, 0xcc, 0x79, 0x3b, 0xec, 0x12,
++	0x47, 0x52, 0xa7, 0xd6, 0x04, 0xe3, 0x52, 0xe6,
++	0x93, 0x90, 0x91, 0x32, 0x73, 0x79, 0xb8, 0xd0,
++	0x31, 0xde, 0x1f, 0x9f, 0x2f, 0x05, 0x38, 0x54,
++	0x2f, 0x35, 0x04, 0x39, 0xe0, 0xa7, 0xba, 0xc6,
++	0x52, 0xf6, 0x37, 0x65, 0x4c, 0x07, 0xa9, 0x7e,
++	0xb3, 0x21, 0x6f, 0x74, 0x8c, 0xc9, 0xde, 0xdb,
++	0x65, 0x1b, 0x9b, 0xaa, 0x60, 0xb1, 0x03, 0x30,
++	0x6b, 0xb2, 0x03, 0xc4, 0x1c, 0x04, 0xf8, 0x0f,
++	0x64, 0xaf, 0x46, 0xe4, 0x65, 0x99, 0x49, 0xe2,
++	0xea, 0xce, 0x78, 0x00, 0xd8, 0x8b, 0xd5, 0x2e,
++	0xcf, 0xfc, 0x40, 0x49, 0xe8, 0x58, 0xdc, 0x34,
++	0x9c, 0x8c, 0x61, 0xbf, 0x0a, 0x8e, 0xec, 0x39,
++	0xa9, 0x30, 0x05, 0x5a, 0xd2, 0x56, 0x01, 0xc7,
++	0xda, 0x8f, 0x4e, 0xbb, 0x43, 0xa3, 0x3a, 0xf9,
++	0x15, 0x2a, 0xd0, 0xa0, 0x7a, 0x87, 0x34, 0x82,
++	0xfe, 0x8a, 0xd1, 0x2d, 0x5e, 0xc7, 0xbf, 0x04,
++	0x53, 0x5f, 0x3b, 0x36, 0xd4, 0x25, 0x5c, 0x34,
++	0x7a, 0x8d, 0xd5, 0x05, 0xce, 0x72, 0xca, 0xef,
++	0x7a, 0x4b, 0xbc, 0xb0, 0x10, 0x5c, 0x96, 0x42,
++	0x3a, 0x00, 0x98, 0xcd, 0x15, 0xe8, 0xb7, 0x53
++};
++static const u8 dec_output007[] __initconst = {
++	0x9b, 0x18, 0xdb, 0xdd, 0x9a, 0x0f, 0x3e, 0xa5,
++	0x15, 0x17, 0xde, 0xdf, 0x08, 0x9d, 0x65, 0x0a,
++	0x67, 0x30, 0x12, 0xe2, 0x34, 0x77, 0x4b, 0xc1,
++	0xd9, 0xc6, 0x1f, 0xab, 0xc6, 0x18, 0x50, 0x17,
++	0xa7, 0x9d, 0x3c, 0xa6, 0xc5, 0x35, 0x8c, 0x1c,
++	0xc0, 0xa1, 0x7c, 0x9f, 0x03, 0x89, 0xca, 0xe1,
++	0xe6, 0xe9, 0xd4, 0xd3, 0x88, 0xdb, 0xb4, 0x51,
++	0x9d, 0xec, 0xb4, 0xfc, 0x52, 0xee, 0x6d, 0xf1,
++	0x75, 0x42, 0xc6, 0xfd, 0xbd, 0x7a, 0x8e, 0x86,
++	0xfc, 0x44, 0xb3, 0x4f, 0xf3, 0xea, 0x67, 0x5a,
++	0x41, 0x13, 0xba, 0xb0, 0xdc, 0xe1, 0xd3, 0x2a,
++	0x7c, 0x22, 0xb3, 0xca, 0xac, 0x6a, 0x37, 0x98,
++	0x3e, 0x1d, 0x40, 0x97, 0xf7, 0x9b, 0x1d, 0x36,
++	0x6b, 0xb3, 0x28, 0xbd, 0x60, 0x82, 0x47, 0x34,
++	0xaa, 0x2f, 0x7d, 0xe9, 0xa8, 0x70, 0x81, 0x57,
++	0xd4, 0xb9, 0x77, 0x0a, 0x9d, 0x29, 0xa7, 0x84,
++	0x52, 0x4f, 0xc2, 0x4a, 0x40, 0x3b, 0x3c, 0xd4,
++	0xc9, 0x2a, 0xdb, 0x4a, 0x53, 0xc4, 0xbe, 0x80,
++	0xe9, 0x51, 0x7f, 0x8f, 0xc7, 0xa2, 0xce, 0x82,
++	0x5c, 0x91, 0x1e, 0x74, 0xd9, 0xd0, 0xbd, 0xd5,
++	0xf3, 0xfd, 0xda, 0x4d, 0x25, 0xb4, 0xbb, 0x2d,
++	0xac, 0x2f, 0x3d, 0x71, 0x85, 0x7b, 0xcf, 0x3c,
++	0x7b, 0x3e, 0x0e, 0x22, 0x78, 0x0c, 0x29, 0xbf,
++	0xe4, 0xf4, 0x57, 0xb3, 0xcb, 0x49, 0xa0, 0xfc,
++	0x1e, 0x05, 0x4e, 0x16, 0xbc, 0xd5, 0xa8, 0xa3,
++	0xee, 0x05, 0x35, 0xc6, 0x7c, 0xab, 0x60, 0x14,
++	0x55, 0x1a, 0x8e, 0xc5, 0x88, 0x5d, 0xd5, 0x81,
++	0xc2, 0x81, 0xa5, 0xc4, 0x60, 0xdb, 0xaf, 0x77,
++	0x91, 0xe1, 0xce, 0xa2, 0x7e, 0x7f, 0x42, 0xe3,
++	0xb0, 0x13, 0x1c, 0x1f, 0x25, 0x60, 0x21, 0xe2,
++	0x40, 0x5f, 0x99, 0xb7, 0x73, 0xec, 0x9b, 0x2b,
++	0xf0, 0x65, 0x11, 0xc8, 0xd0, 0x0a, 0x9f, 0xd3
++};
++static const u8 dec_assoc007[] __initconst = { };
++static const u8 dec_nonce007[] __initconst = {
++	0xde, 0x7b, 0xef, 0xc3, 0x65, 0x1b, 0x68, 0xb0
++};
++static const u8 dec_key007[] __initconst = {
++	0x8d, 0xb8, 0x91, 0x48, 0xf0, 0xe7, 0x0a, 0xbd,
++	0xf9, 0x3f, 0xcd, 0xd9, 0xa0, 0x1e, 0x42, 0x4c,
++	0xe7, 0xde, 0x25, 0x3d, 0xa3, 0xd7, 0x05, 0x80,
++	0x8d, 0xf2, 0x82, 0xac, 0x44, 0x16, 0x51, 0x01
++};
++
++static const u8 dec_input008[] __initconst = {
++	0x14, 0xf6, 0x41, 0x37, 0xa6, 0xd4, 0x27, 0xcd,
++	0xdb, 0x06, 0x3e, 0x9a, 0x4e, 0xab, 0xd5, 0xb1,
++	0x1e, 0x6b, 0xd2, 0xbc, 0x11, 0xf4, 0x28, 0x93,
++	0x63, 0x54, 0xef, 0xbb, 0x5e, 0x1d, 0x3a, 0x1d,
++	0x37, 0x3c, 0x0a, 0x6c, 0x1e, 0xc2, 0xd1, 0x2c,
++	0xb5, 0xa3, 0xb5, 0x7b, 0xb8, 0x8f, 0x25, 0xa6,
++	0x1b, 0x61, 0x1c, 0xec, 0x28, 0x58, 0x26, 0xa4,
++	0xa8, 0x33, 0x28, 0x25, 0x5c, 0x45, 0x05, 0xe5,
++	0x6c, 0x99, 0xe5, 0x45, 0xc4, 0xa2, 0x03, 0x84,
++	0x03, 0x73, 0x1e, 0x8c, 0x49, 0xac, 0x20, 0xdd,
++	0x8d, 0xb3, 0xc4, 0xf5, 0xe7, 0x4f, 0xf1, 0xed,
++	0xa1, 0x98, 0xde, 0xa4, 0x96, 0xdd, 0x2f, 0xab,
++	0xab, 0x97, 0xcf, 0x3e, 0xd2, 0x9e, 0xb8, 0x13,
++	0x07, 0x28, 0x29, 0x19, 0xaf, 0xfd, 0xf2, 0x49,
++	0x43, 0xea, 0x49, 0x26, 0x91, 0xc1, 0x07, 0xd6,
++	0xbb, 0x81, 0x75, 0x35, 0x0d, 0x24, 0x7f, 0xc8,
++	0xda, 0xd4, 0xb7, 0xeb, 0xe8, 0x5c, 0x09, 0xa2,
++	0x2f, 0xdc, 0x28, 0x7d, 0x3a, 0x03, 0xfa, 0x94,
++	0xb5, 0x1d, 0x17, 0x99, 0x36, 0xc3, 0x1c, 0x18,
++	0x34, 0xe3, 0x9f, 0xf5, 0x55, 0x7c, 0xb0, 0x60,
++	0x9d, 0xff, 0xac, 0xd4, 0x61, 0xf2, 0xad, 0xf8,
++	0xce, 0xc7, 0xbe, 0x5c, 0xd2, 0x95, 0xa8, 0x4b,
++	0x77, 0x13, 0x19, 0x59, 0x26, 0xc9, 0xb7, 0x8f,
++	0x6a, 0xcb, 0x2d, 0x37, 0x91, 0xea, 0x92, 0x9c,
++	0x94, 0x5b, 0xda, 0x0b, 0xce, 0xfe, 0x30, 0x20,
++	0xf8, 0x51, 0xad, 0xf2, 0xbe, 0xe7, 0xc7, 0xff,
++	0xb3, 0x33, 0x91, 0x6a, 0xc9, 0x1a, 0x41, 0xc9,
++	0x0f, 0xf3, 0x10, 0x0e, 0xfd, 0x53, 0xff, 0x6c,
++	0x16, 0x52, 0xd9, 0xf3, 0xf7, 0x98, 0x2e, 0xc9,
++	0x07, 0x31, 0x2c, 0x0c, 0x72, 0xd7, 0xc5, 0xc6,
++	0x08, 0x2a, 0x7b, 0xda, 0xbd, 0x7e, 0x02, 0xea,
++	0x1a, 0xbb, 0xf2, 0x04, 0x27, 0x61, 0x28, 0x8e,
++	0xf5, 0x04, 0x03, 0x1f, 0x4c, 0x07, 0x55, 0x82,
++	0xec, 0x1e, 0xd7, 0x8b, 0x2f, 0x65, 0x56, 0xd1,
++	0xd9, 0x1e, 0x3c, 0xe9, 0x1f, 0x5e, 0x98, 0x70,
++	0x38, 0x4a, 0x8c, 0x49, 0xc5, 0x43, 0xa0, 0xa1,
++	0x8b, 0x74, 0x9d, 0x4c, 0x62, 0x0d, 0x10, 0x0c,
++	0xf4, 0x6c, 0x8f, 0xe0, 0xaa, 0x9a, 0x8d, 0xb7,
++	0xe0, 0xbe, 0x4c, 0x87, 0xf1, 0x98, 0x2f, 0xcc,
++	0xed, 0xc0, 0x52, 0x29, 0xdc, 0x83, 0xf8, 0xfc,
++	0x2c, 0x0e, 0xa8, 0x51, 0x4d, 0x80, 0x0d, 0xa3,
++	0xfe, 0xd8, 0x37, 0xe7, 0x41, 0x24, 0xfc, 0xfb,
++	0x75, 0xe3, 0x71, 0x7b, 0x57, 0x45, 0xf5, 0x97,
++	0x73, 0x65, 0x63, 0x14, 0x74, 0xb8, 0x82, 0x9f,
++	0xf8, 0x60, 0x2f, 0x8a, 0xf2, 0x4e, 0xf1, 0x39,
++	0xda, 0x33, 0x91, 0xf8, 0x36, 0xe0, 0x8d, 0x3f,
++	0x1f, 0x3b, 0x56, 0xdc, 0xa0, 0x8f, 0x3c, 0x9d,
++	0x71, 0x52, 0xa7, 0xb8, 0xc0, 0xa5, 0xc6, 0xa2,
++	0x73, 0xda, 0xf4, 0x4b, 0x74, 0x5b, 0x00, 0x3d,
++	0x99, 0xd7, 0x96, 0xba, 0xe6, 0xe1, 0xa6, 0x96,
++	0x38, 0xad, 0xb3, 0xc0, 0xd2, 0xba, 0x91, 0x6b,
++	0xf9, 0x19, 0xdd, 0x3b, 0xbe, 0xbe, 0x9c, 0x20,
++	0x50, 0xba, 0xa1, 0xd0, 0xce, 0x11, 0xbd, 0x95,
++	0xd8, 0xd1, 0xdd, 0x33, 0x85, 0x74, 0xdc, 0xdb,
++	0x66, 0x76, 0x44, 0xdc, 0x03, 0x74, 0x48, 0x35,
++	0x98, 0xb1, 0x18, 0x47, 0x94, 0x7d, 0xff, 0x62,
++	0xe4, 0x58, 0x78, 0xab, 0xed, 0x95, 0x36, 0xd9,
++	0x84, 0x91, 0x82, 0x64, 0x41, 0xbb, 0x58, 0xe6,
++	0x1c, 0x20, 0x6d, 0x15, 0x6b, 0x13, 0x96, 0xe8,
++	0x35, 0x7f, 0xdc, 0x40, 0x2c, 0xe9, 0xbc, 0x8a,
++	0x4f, 0x92, 0xec, 0x06, 0x2d, 0x50, 0xdf, 0x93,
++	0x5d, 0x65, 0x5a, 0xa8, 0xfc, 0x20, 0x50, 0x14,
++	0xa9, 0x8a, 0x7e, 0x1d, 0x08, 0x1f, 0xe2, 0x99,
++	0xd0, 0xbe, 0xfb, 0x3a, 0x21, 0x9d, 0xad, 0x86,
++	0x54, 0xfd, 0x0d, 0x98, 0x1c, 0x5a, 0x6f, 0x1f,
++	0x9a, 0x40, 0xcd, 0xa2, 0xff, 0x6a, 0xf1, 0x54
++};
++static const u8 dec_output008[] __initconst = {
++	0xc3, 0x09, 0x94, 0x62, 0xe6, 0x46, 0x2e, 0x10,
++	0xbe, 0x00, 0xe4, 0xfc, 0xf3, 0x40, 0xa3, 0xe2,
++	0x0f, 0xc2, 0x8b, 0x28, 0xdc, 0xba, 0xb4, 0x3c,
++	0xe4, 0x21, 0x58, 0x61, 0xcd, 0x8b, 0xcd, 0xfb,
++	0xac, 0x94, 0xa1, 0x45, 0xf5, 0x1c, 0xe1, 0x12,
++	0xe0, 0x3b, 0x67, 0x21, 0x54, 0x5e, 0x8c, 0xaa,
++	0xcf, 0xdb, 0xb4, 0x51, 0xd4, 0x13, 0xda, 0xe6,
++	0x83, 0x89, 0xb6, 0x92, 0xe9, 0x21, 0x76, 0xa4,
++	0x93, 0x7d, 0x0e, 0xfd, 0x96, 0x36, 0x03, 0x91,
++	0x43, 0x5c, 0x92, 0x49, 0x62, 0x61, 0x7b, 0xeb,
++	0x43, 0x89, 0xb8, 0x12, 0x20, 0x43, 0xd4, 0x47,
++	0x06, 0x84, 0xee, 0x47, 0xe9, 0x8a, 0x73, 0x15,
++	0x0f, 0x72, 0xcf, 0xed, 0xce, 0x96, 0xb2, 0x7f,
++	0x21, 0x45, 0x76, 0xeb, 0x26, 0x28, 0x83, 0x6a,
++	0xad, 0xaa, 0xa6, 0x81, 0xd8, 0x55, 0xb1, 0xa3,
++	0x85, 0xb3, 0x0c, 0xdf, 0xf1, 0x69, 0x2d, 0x97,
++	0x05, 0x2a, 0xbc, 0x7c, 0x7b, 0x25, 0xf8, 0x80,
++	0x9d, 0x39, 0x25, 0xf3, 0x62, 0xf0, 0x66, 0x5e,
++	0xf4, 0xa0, 0xcf, 0xd8, 0xfd, 0x4f, 0xb1, 0x1f,
++	0x60, 0x3a, 0x08, 0x47, 0xaf, 0xe1, 0xf6, 0x10,
++	0x77, 0x09, 0xa7, 0x27, 0x8f, 0x9a, 0x97, 0x5a,
++	0x26, 0xfa, 0xfe, 0x41, 0x32, 0x83, 0x10, 0xe0,
++	0x1d, 0xbf, 0x64, 0x0d, 0xf4, 0x1c, 0x32, 0x35,
++	0xe5, 0x1b, 0x36, 0xef, 0xd4, 0x4a, 0x93, 0x4d,
++	0x00, 0x7c, 0xec, 0x02, 0x07, 0x8b, 0x5d, 0x7d,
++	0x1b, 0x0e, 0xd1, 0xa6, 0xa5, 0x5d, 0x7d, 0x57,
++	0x88, 0xa8, 0xcc, 0x81, 0xb4, 0x86, 0x4e, 0xb4,
++	0x40, 0xe9, 0x1d, 0xc3, 0xb1, 0x24, 0x3e, 0x7f,
++	0xcc, 0x8a, 0x24, 0x9b, 0xdf, 0x6d, 0xf0, 0x39,
++	0x69, 0x3e, 0x4c, 0xc0, 0x96, 0xe4, 0x13, 0xda,
++	0x90, 0xda, 0xf4, 0x95, 0x66, 0x8b, 0x17, 0x17,
++	0xfe, 0x39, 0x43, 0x25, 0xaa, 0xda, 0xa0, 0x43,
++	0x3c, 0xb1, 0x41, 0x02, 0xa3, 0xf0, 0xa7, 0x19,
++	0x59, 0xbc, 0x1d, 0x7d, 0x6c, 0x6d, 0x91, 0x09,
++	0x5c, 0xb7, 0x5b, 0x01, 0xd1, 0x6f, 0x17, 0x21,
++	0x97, 0xbf, 0x89, 0x71, 0xa5, 0xb0, 0x6e, 0x07,
++	0x45, 0xfd, 0x9d, 0xea, 0x07, 0xf6, 0x7a, 0x9f,
++	0x10, 0x18, 0x22, 0x30, 0x73, 0xac, 0xd4, 0x6b,
++	0x72, 0x44, 0xed, 0xd9, 0x19, 0x9b, 0x2d, 0x4a,
++	0x41, 0xdd, 0xd1, 0x85, 0x5e, 0x37, 0x19, 0xed,
++	0xd2, 0x15, 0x8f, 0x5e, 0x91, 0xdb, 0x33, 0xf2,
++	0xe4, 0xdb, 0xff, 0x98, 0xfb, 0xa3, 0xb5, 0xca,
++	0x21, 0x69, 0x08, 0xe7, 0x8a, 0xdf, 0x90, 0xff,
++	0x3e, 0xe9, 0x20, 0x86, 0x3c, 0xe9, 0xfc, 0x0b,
++	0xfe, 0x5c, 0x61, 0xaa, 0x13, 0x92, 0x7f, 0x7b,
++	0xec, 0xe0, 0x6d, 0xa8, 0x23, 0x22, 0xf6, 0x6b,
++	0x77, 0xc4, 0xfe, 0x40, 0x07, 0x3b, 0xb6, 0xf6,
++	0x8e, 0x5f, 0xd4, 0xb9, 0xb7, 0x0f, 0x21, 0x04,
++	0xef, 0x83, 0x63, 0x91, 0x69, 0x40, 0xa3, 0x48,
++	0x5c, 0xd2, 0x60, 0xf9, 0x4f, 0x6c, 0x47, 0x8b,
++	0x3b, 0xb1, 0x9f, 0x8e, 0xee, 0x16, 0x8a, 0x13,
++	0xfc, 0x46, 0x17, 0xc3, 0xc3, 0x32, 0x56, 0xf8,
++	0x3c, 0x85, 0x3a, 0xb6, 0x3e, 0xaa, 0x89, 0x4f,
++	0xb3, 0xdf, 0x38, 0xfd, 0xf1, 0xe4, 0x3a, 0xc0,
++	0xe6, 0x58, 0xb5, 0x8f, 0xc5, 0x29, 0xa2, 0x92,
++	0x4a, 0xb6, 0xa0, 0x34, 0x7f, 0xab, 0xb5, 0x8a,
++	0x90, 0xa1, 0xdb, 0x4d, 0xca, 0xb6, 0x2c, 0x41,
++	0x3c, 0xf7, 0x2b, 0x21, 0xc3, 0xfd, 0xf4, 0x17,
++	0x5c, 0xb5, 0x33, 0x17, 0x68, 0x2b, 0x08, 0x30,
++	0xf3, 0xf7, 0x30, 0x3c, 0x96, 0xe6, 0x6a, 0x20,
++	0x97, 0xe7, 0x4d, 0x10, 0x5f, 0x47, 0x5f, 0x49,
++	0x96, 0x09, 0xf0, 0x27, 0x91, 0xc8, 0xf8, 0x5a,
++	0x2e, 0x79, 0xb5, 0xe2, 0xb8, 0xe8, 0xb9, 0x7b,
++	0xd5, 0x10, 0xcb, 0xff, 0x5d, 0x14, 0x73, 0xf3
++};
++static const u8 dec_assoc008[] __initconst = { };
++static const u8 dec_nonce008[] __initconst = {
++	0x0e, 0x0d, 0x57, 0xbb, 0x7b, 0x40, 0x54, 0x02
++};
++static const u8 dec_key008[] __initconst = {
++	0xf2, 0xaa, 0x4f, 0x99, 0xfd, 0x3e, 0xa8, 0x53,
++	0xc1, 0x44, 0xe9, 0x81, 0x18, 0xdc, 0xf5, 0xf0,
++	0x3e, 0x44, 0x15, 0x59, 0xe0, 0xc5, 0x44, 0x86,
++	0xc3, 0x91, 0xa8, 0x75, 0xc0, 0x12, 0x46, 0xba
++};
++
++static const u8 dec_input009[] __initconst = {
++	0xfd, 0x81, 0x8d, 0xd0, 0x3d, 0xb4, 0xd5, 0xdf,
++	0xd3, 0x42, 0x47, 0x5a, 0x6d, 0x19, 0x27, 0x66,
++	0x4b, 0x2e, 0x0c, 0x27, 0x9c, 0x96, 0x4c, 0x72,
++	0x02, 0xa3, 0x65, 0xc3, 0xb3, 0x6f, 0x2e, 0xbd,
++	0x63, 0x8a, 0x4a, 0x5d, 0x29, 0xa2, 0xd0, 0x28,
++	0x48, 0xc5, 0x3d, 0x98, 0xa3, 0xbc, 0xe0, 0xbe,
++	0x3b, 0x3f, 0xe6, 0x8a, 0xa4, 0x7f, 0x53, 0x06,
++	0xfa, 0x7f, 0x27, 0x76, 0x72, 0x31, 0xa1, 0xf5,
++	0xd6, 0x0c, 0x52, 0x47, 0xba, 0xcd, 0x4f, 0xd7,
++	0xeb, 0x05, 0x48, 0x0d, 0x7c, 0x35, 0x4a, 0x09,
++	0xc9, 0x76, 0x71, 0x02, 0xa3, 0xfb, 0xb7, 0x1a,
++	0x65, 0xb7, 0xed, 0x98, 0xc6, 0x30, 0x8a, 0x00,
++	0xae, 0xa1, 0x31, 0xe5, 0xb5, 0x9e, 0x6d, 0x62,
++	0xda, 0xda, 0x07, 0x0f, 0x38, 0x38, 0xd3, 0xcb,
++	0xc1, 0xb0, 0xad, 0xec, 0x72, 0xec, 0xb1, 0xa2,
++	0x7b, 0x59, 0xf3, 0x3d, 0x2b, 0xef, 0xcd, 0x28,
++	0x5b, 0x83, 0xcc, 0x18, 0x91, 0x88, 0xb0, 0x2e,
++	0xf9, 0x29, 0x31, 0x18, 0xf9, 0x4e, 0xe9, 0x0a,
++	0x91, 0x92, 0x9f, 0xae, 0x2d, 0xad, 0xf4, 0xe6,
++	0x1a, 0xe2, 0xa4, 0xee, 0x47, 0x15, 0xbf, 0x83,
++	0x6e, 0xd7, 0x72, 0x12, 0x3b, 0x2d, 0x24, 0xe9,
++	0xb2, 0x55, 0xcb, 0x3c, 0x10, 0xf0, 0x24, 0x8a,
++	0x4a, 0x02, 0xea, 0x90, 0x25, 0xf0, 0xb4, 0x79,
++	0x3a, 0xef, 0x6e, 0xf5, 0x52, 0xdf, 0xb0, 0x0a,
++	0xcd, 0x24, 0x1c, 0xd3, 0x2e, 0x22, 0x74, 0xea,
++	0x21, 0x6f, 0xe9, 0xbd, 0xc8, 0x3e, 0x36, 0x5b,
++	0x19, 0xf1, 0xca, 0x99, 0x0a, 0xb4, 0xa7, 0x52,
++	0x1a, 0x4e, 0xf2, 0xad, 0x8d, 0x56, 0x85, 0xbb,
++	0x64, 0x89, 0xba, 0x26, 0xf9, 0xc7, 0xe1, 0x89,
++	0x19, 0x22, 0x77, 0xc3, 0xa8, 0xfc, 0xff, 0xad,
++	0xfe, 0xb9, 0x48, 0xae, 0x12, 0x30, 0x9f, 0x19,
++	0xfb, 0x1b, 0xef, 0x14, 0x87, 0x8a, 0x78, 0x71,
++	0xf3, 0xf4, 0xb7, 0x00, 0x9c, 0x1d, 0xb5, 0x3d,
++	0x49, 0x00, 0x0c, 0x06, 0xd4, 0x50, 0xf9, 0x54,
++	0x45, 0xb2, 0x5b, 0x43, 0xdb, 0x6d, 0xcf, 0x1a,
++	0xe9, 0x7a, 0x7a, 0xcf, 0xfc, 0x8a, 0x4e, 0x4d,
++	0x0b, 0x07, 0x63, 0x28, 0xd8, 0xe7, 0x08, 0x95,
++	0xdf, 0xa6, 0x72, 0x93, 0x2e, 0xbb, 0xa0, 0x42,
++	0x89, 0x16, 0xf1, 0xd9, 0x0c, 0xf9, 0xa1, 0x16,
++	0xfd, 0xd9, 0x03, 0xb4, 0x3b, 0x8a, 0xf5, 0xf6,
++	0xe7, 0x6b, 0x2e, 0x8e, 0x4c, 0x3d, 0xe2, 0xaf,
++	0x08, 0x45, 0x03, 0xff, 0x09, 0xb6, 0xeb, 0x2d,
++	0xc6, 0x1b, 0x88, 0x94, 0xac, 0x3e, 0xf1, 0x9f,
++	0x0e, 0x0e, 0x2b, 0xd5, 0x00, 0x4d, 0x3f, 0x3b,
++	0x53, 0xae, 0xaf, 0x1c, 0x33, 0x5f, 0x55, 0x6e,
++	0x8d, 0xaf, 0x05, 0x7a, 0x10, 0x34, 0xc9, 0xf4,
++	0x66, 0xcb, 0x62, 0x12, 0xa6, 0xee, 0xe8, 0x1c,
++	0x5d, 0x12, 0x86, 0xdb, 0x6f, 0x1c, 0x33, 0xc4,
++	0x1c, 0xda, 0x82, 0x2d, 0x3b, 0x59, 0xfe, 0xb1,
++	0xa4, 0x59, 0x41, 0x86, 0xd0, 0xef, 0xae, 0xfb,
++	0xda, 0x6d, 0x11, 0xb8, 0xca, 0xe9, 0x6e, 0xff,
++	0xf7, 0xa9, 0xd9, 0x70, 0x30, 0xfc, 0x53, 0xe2,
++	0xd7, 0xa2, 0x4e, 0xc7, 0x91, 0xd9, 0x07, 0x06,
++	0xaa, 0xdd, 0xb0, 0x59, 0x28, 0x1d, 0x00, 0x66,
++	0xc5, 0x54, 0xc2, 0xfc, 0x06, 0xda, 0x05, 0x90,
++	0x52, 0x1d, 0x37, 0x66, 0xee, 0xf0, 0xb2, 0x55,
++	0x8a, 0x5d, 0xd2, 0x38, 0x86, 0x94, 0x9b, 0xfc,
++	0x10, 0x4c, 0xa1, 0xb9, 0x64, 0x3e, 0x44, 0xb8,
++	0x5f, 0xb0, 0x0c, 0xec, 0xe0, 0xc9, 0xe5, 0x62,
++	0x75, 0x3f, 0x09, 0xd5, 0xf5, 0xd9, 0x26, 0xba,
++	0x9e, 0xd2, 0xf4, 0xb9, 0x48, 0x0a, 0xbc, 0xa2,
++	0xd6, 0x7c, 0x36, 0x11, 0x7d, 0x26, 0x81, 0x89,
++	0xcf, 0xa4, 0xad, 0x73, 0x0e, 0xee, 0xcc, 0x06,
++	0xa9, 0xdb, 0xb1, 0xfd, 0xfb, 0x09, 0x7f, 0x90,
++	0x42, 0x37, 0x2f, 0xe1, 0x9c, 0x0f, 0x6f, 0xcf,
++	0x43, 0xb5, 0xd9, 0x90, 0xe1, 0x85, 0xf5, 0xa8,
++	0xae
++};
++static const u8 dec_output009[] __initconst = {
++	0xe6, 0xc3, 0xdb, 0x63, 0x55, 0x15, 0xe3, 0x5b,
++	0xb7, 0x4b, 0x27, 0x8b, 0x5a, 0xdd, 0xc2, 0xe8,
++	0x3a, 0x6b, 0xd7, 0x81, 0x96, 0x35, 0x97, 0xca,
++	0xd7, 0x68, 0xe8, 0xef, 0xce, 0xab, 0xda, 0x09,
++	0x6e, 0xd6, 0x8e, 0xcb, 0x55, 0xb5, 0xe1, 0xe5,
++	0x57, 0xfd, 0xc4, 0xe3, 0xe0, 0x18, 0x4f, 0x85,
++	0xf5, 0x3f, 0x7e, 0x4b, 0x88, 0xc9, 0x52, 0x44,
++	0x0f, 0xea, 0xaf, 0x1f, 0x71, 0x48, 0x9f, 0x97,
++	0x6d, 0xb9, 0x6f, 0x00, 0xa6, 0xde, 0x2b, 0x77,
++	0x8b, 0x15, 0xad, 0x10, 0xa0, 0x2b, 0x7b, 0x41,
++	0x90, 0x03, 0x2d, 0x69, 0xae, 0xcc, 0x77, 0x7c,
++	0xa5, 0x9d, 0x29, 0x22, 0xc2, 0xea, 0xb4, 0x00,
++	0x1a, 0xd2, 0x7a, 0x98, 0x8a, 0xf9, 0xf7, 0x82,
++	0xb0, 0xab, 0xd8, 0xa6, 0x94, 0x8d, 0x58, 0x2f,
++	0x01, 0x9e, 0x00, 0x20, 0xfc, 0x49, 0xdc, 0x0e,
++	0x03, 0xe8, 0x45, 0x10, 0xd6, 0xa8, 0xda, 0x55,
++	0x10, 0x9a, 0xdf, 0x67, 0x22, 0x8b, 0x43, 0xab,
++	0x00, 0xbb, 0x02, 0xc8, 0xdd, 0x7b, 0x97, 0x17,
++	0xd7, 0x1d, 0x9e, 0x02, 0x5e, 0x48, 0xde, 0x8e,
++	0xcf, 0x99, 0x07, 0x95, 0x92, 0x3c, 0x5f, 0x9f,
++	0xc5, 0x8a, 0xc0, 0x23, 0xaa, 0xd5, 0x8c, 0x82,
++	0x6e, 0x16, 0x92, 0xb1, 0x12, 0x17, 0x07, 0xc3,
++	0xfb, 0x36, 0xf5, 0x6c, 0x35, 0xd6, 0x06, 0x1f,
++	0x9f, 0xa7, 0x94, 0xa2, 0x38, 0x63, 0x9c, 0xb0,
++	0x71, 0xb3, 0xa5, 0xd2, 0xd8, 0xba, 0x9f, 0x08,
++	0x01, 0xb3, 0xff, 0x04, 0x97, 0x73, 0x45, 0x1b,
++	0xd5, 0xa9, 0x9c, 0x80, 0xaf, 0x04, 0x9a, 0x85,
++	0xdb, 0x32, 0x5b, 0x5d, 0x1a, 0xc1, 0x36, 0x28,
++	0x10, 0x79, 0xf1, 0x3c, 0xbf, 0x1a, 0x41, 0x5c,
++	0x4e, 0xdf, 0xb2, 0x7c, 0x79, 0x3b, 0x7a, 0x62,
++	0x3d, 0x4b, 0xc9, 0x9b, 0x2a, 0x2e, 0x7c, 0xa2,
++	0xb1, 0x11, 0x98, 0xa7, 0x34, 0x1a, 0x00, 0xf3,
++	0xd1, 0xbc, 0x18, 0x22, 0xba, 0x02, 0x56, 0x62,
++	0x31, 0x10, 0x11, 0x6d, 0xe0, 0x54, 0x9d, 0x40,
++	0x1f, 0x26, 0x80, 0x41, 0xca, 0x3f, 0x68, 0x0f,
++	0x32, 0x1d, 0x0a, 0x8e, 0x79, 0xd8, 0xa4, 0x1b,
++	0x29, 0x1c, 0x90, 0x8e, 0xc5, 0xe3, 0xb4, 0x91,
++	0x37, 0x9a, 0x97, 0x86, 0x99, 0xd5, 0x09, 0xc5,
++	0xbb, 0xa3, 0x3f, 0x21, 0x29, 0x82, 0x14, 0x5c,
++	0xab, 0x25, 0xfb, 0xf2, 0x4f, 0x58, 0x26, 0xd4,
++	0x83, 0xaa, 0x66, 0x89, 0x67, 0x7e, 0xc0, 0x49,
++	0xe1, 0x11, 0x10, 0x7f, 0x7a, 0xda, 0x29, 0x04,
++	0xff, 0xf0, 0xcb, 0x09, 0x7c, 0x9d, 0xfa, 0x03,
++	0x6f, 0x81, 0x09, 0x31, 0x60, 0xfb, 0x08, 0xfa,
++	0x74, 0xd3, 0x64, 0x44, 0x7c, 0x55, 0x85, 0xec,
++	0x9c, 0x6e, 0x25, 0xb7, 0x6c, 0xc5, 0x37, 0xb6,
++	0x83, 0x87, 0x72, 0x95, 0x8b, 0x9d, 0xe1, 0x69,
++	0x5c, 0x31, 0x95, 0x42, 0xa6, 0x2c, 0xd1, 0x36,
++	0x47, 0x1f, 0xec, 0x54, 0xab, 0xa2, 0x1c, 0xd8,
++	0x00, 0xcc, 0xbc, 0x0d, 0x65, 0xe2, 0x67, 0xbf,
++	0xbc, 0xea, 0xee, 0x9e, 0xe4, 0x36, 0x95, 0xbe,
++	0x73, 0xd9, 0xa6, 0xd9, 0x0f, 0xa0, 0xcc, 0x82,
++	0x76, 0x26, 0xad, 0x5b, 0x58, 0x6c, 0x4e, 0xab,
++	0x29, 0x64, 0xd3, 0xd9, 0xa9, 0x08, 0x8c, 0x1d,
++	0xa1, 0x4f, 0x80, 0xd8, 0x3f, 0x94, 0xfb, 0xd3,
++	0x7b, 0xfc, 0xd1, 0x2b, 0xc3, 0x21, 0xeb, 0xe5,
++	0x1c, 0x84, 0x23, 0x7f, 0x4b, 0xfa, 0xdb, 0x34,
++	0x18, 0xa2, 0xc2, 0xe5, 0x13, 0xfe, 0x6c, 0x49,
++	0x81, 0xd2, 0x73, 0xe7, 0xe2, 0xd7, 0xe4, 0x4f,
++	0x4b, 0x08, 0x6e, 0xb1, 0x12, 0x22, 0x10, 0x9d,
++	0xac, 0x51, 0x1e, 0x17, 0xd9, 0x8a, 0x0b, 0x42,
++	0x88, 0x16, 0x81, 0x37, 0x7c, 0x6a, 0xf7, 0xef,
++	0x2d, 0xe3, 0xd9, 0xf8, 0x5f, 0xe0, 0x53, 0x27,
++	0x74, 0xb9, 0xe2, 0xd6, 0x1c, 0x80, 0x2c, 0x52,
++	0x65
++};
++static const u8 dec_assoc009[] __initconst = {
++	0x5a, 0x27, 0xff, 0xeb, 0xdf, 0x84, 0xb2, 0x9e,
++	0xef
++};
++static const u8 dec_nonce009[] __initconst = {
++	0xef, 0x2d, 0x63, 0xee, 0x6b, 0x80, 0x8b, 0x78
++};
++static const u8 dec_key009[] __initconst = {
++	0xea, 0xbc, 0x56, 0x99, 0xe3, 0x50, 0xff, 0xc5,
++	0xcc, 0x1a, 0xd7, 0xc1, 0x57, 0x72, 0xea, 0x86,
++	0x5b, 0x89, 0x88, 0x61, 0x3d, 0x2f, 0x9b, 0xb2,
++	0xe7, 0x9c, 0xec, 0x74, 0x6e, 0x3e, 0xf4, 0x3b
++};
++
++static const u8 dec_input010[] __initconst = {
++	0xe5, 0x26, 0xa4, 0x3d, 0xbd, 0x33, 0xd0, 0x4b,
++	0x6f, 0x05, 0xa7, 0x6e, 0x12, 0x7a, 0xd2, 0x74,
++	0xa6, 0xdd, 0xbd, 0x95, 0xeb, 0xf9, 0xa4, 0xf1,
++	0x59, 0x93, 0x91, 0x70, 0xd9, 0xfe, 0x9a, 0xcd,
++	0x53, 0x1f, 0x3a, 0xab, 0xa6, 0x7c, 0x9f, 0xa6,
++	0x9e, 0xbd, 0x99, 0xd9, 0xb5, 0x97, 0x44, 0xd5,
++	0x14, 0x48, 0x4d, 0x9d, 0xc0, 0xd0, 0x05, 0x96,
++	0xeb, 0x4c, 0x78, 0x55, 0x09, 0x08, 0x01, 0x02,
++	0x30, 0x90, 0x7b, 0x96, 0x7a, 0x7b, 0x5f, 0x30,
++	0x41, 0x24, 0xce, 0x68, 0x61, 0x49, 0x86, 0x57,
++	0x82, 0xdd, 0x53, 0x1c, 0x51, 0x28, 0x2b, 0x53,
++	0x6e, 0x2d, 0xc2, 0x20, 0x4c, 0xdd, 0x8f, 0x65,
++	0x10, 0x20, 0x50, 0xdd, 0x9d, 0x50, 0xe5, 0x71,
++	0x40, 0x53, 0x69, 0xfc, 0x77, 0x48, 0x11, 0xb9,
++	0xde, 0xa4, 0x8d, 0x58, 0xe4, 0xa6, 0x1a, 0x18,
++	0x47, 0x81, 0x7e, 0xfc, 0xdd, 0xf6, 0xef, 0xce,
++	0x2f, 0x43, 0x68, 0xd6, 0x06, 0xe2, 0x74, 0x6a,
++	0xad, 0x90, 0xf5, 0x37, 0xf3, 0x3d, 0x82, 0x69,
++	0x40, 0xe9, 0x6b, 0xa7, 0x3d, 0xa8, 0x1e, 0xd2,
++	0x02, 0x7c, 0xb7, 0x9b, 0xe4, 0xda, 0x8f, 0x95,
++	0x06, 0xc5, 0xdf, 0x73, 0xa3, 0x20, 0x9a, 0x49,
++	0xde, 0x9c, 0xbc, 0xee, 0x14, 0x3f, 0x81, 0x5e,
++	0xf8, 0x3b, 0x59, 0x3c, 0xe1, 0x68, 0x12, 0x5a,
++	0x3a, 0x76, 0x3a, 0x3f, 0xf7, 0x87, 0x33, 0x0a,
++	0x01, 0xb8, 0xd4, 0xed, 0xb6, 0xbe, 0x94, 0x5e,
++	0x70, 0x40, 0x56, 0x67, 0x1f, 0x50, 0x44, 0x19,
++	0xce, 0x82, 0x70, 0x10, 0x87, 0x13, 0x20, 0x0b,
++	0x4c, 0x5a, 0xb6, 0xf6, 0xa7, 0xae, 0x81, 0x75,
++	0x01, 0x81, 0xe6, 0x4b, 0x57, 0x7c, 0xdd, 0x6d,
++	0xf8, 0x1c, 0x29, 0x32, 0xf7, 0xda, 0x3c, 0x2d,
++	0xf8, 0x9b, 0x25, 0x6e, 0x00, 0xb4, 0xf7, 0x2f,
++	0xf7, 0x04, 0xf7, 0xa1, 0x56, 0xac, 0x4f, 0x1a,
++	0x64, 0xb8, 0x47, 0x55, 0x18, 0x7b, 0x07, 0x4d,
++	0xbd, 0x47, 0x24, 0x80, 0x5d, 0xa2, 0x70, 0xc5,
++	0xdd, 0x8e, 0x82, 0xd4, 0xeb, 0xec, 0xb2, 0x0c,
++	0x39, 0xd2, 0x97, 0xc1, 0xcb, 0xeb, 0xf4, 0x77,
++	0x59, 0xb4, 0x87, 0xef, 0xcb, 0x43, 0x2d, 0x46,
++	0x54, 0xd1, 0xa7, 0xd7, 0x15, 0x99, 0x0a, 0x43,
++	0xa1, 0xe0, 0x99, 0x33, 0x71, 0xc1, 0xed, 0xfe,
++	0x72, 0x46, 0x33, 0x8e, 0x91, 0x08, 0x9f, 0xc8,
++	0x2e, 0xca, 0xfa, 0xdc, 0x59, 0xd5, 0xc3, 0x76,
++	0x84, 0x9f, 0xa3, 0x37, 0x68, 0xc3, 0xf0, 0x47,
++	0x2c, 0x68, 0xdb, 0x5e, 0xc3, 0x49, 0x4c, 0xe8,
++	0x92, 0x85, 0xe2, 0x23, 0xd3, 0x3f, 0xad, 0x32,
++	0xe5, 0x2b, 0x82, 0xd7, 0x8f, 0x99, 0x0a, 0x59,
++	0x5c, 0x45, 0xd9, 0xb4, 0x51, 0x52, 0xc2, 0xae,
++	0xbf, 0x80, 0xcf, 0xc9, 0xc9, 0x51, 0x24, 0x2a,
++	0x3b, 0x3a, 0x4d, 0xae, 0xeb, 0xbd, 0x22, 0xc3,
++	0x0e, 0x0f, 0x59, 0x25, 0x92, 0x17, 0xe9, 0x74,
++	0xc7, 0x8b, 0x70, 0x70, 0x36, 0x55, 0x95, 0x75,
++	0x4b, 0xad, 0x61, 0x2b, 0x09, 0xbc, 0x82, 0xf2,
++	0x6e, 0x94, 0x43, 0xae, 0xc3, 0xd5, 0xcd, 0x8e,
++	0xfe, 0x5b, 0x9a, 0x88, 0x43, 0x01, 0x75, 0xb2,
++	0x23, 0x09, 0xf7, 0x89, 0x83, 0xe7, 0xfa, 0xf9,
++	0xb4, 0x9b, 0xf8, 0xef, 0xbd, 0x1c, 0x92, 0xc1,
++	0xda, 0x7e, 0xfe, 0x05, 0xba, 0x5a, 0xcd, 0x07,
++	0x6a, 0x78, 0x9e, 0x5d, 0xfb, 0x11, 0x2f, 0x79,
++	0x38, 0xb6, 0xc2, 0x5b, 0x6b, 0x51, 0xb4, 0x71,
++	0xdd, 0xf7, 0x2a, 0xe4, 0xf4, 0x72, 0x76, 0xad,
++	0xc2, 0xdd, 0x64, 0x5d, 0x79, 0xb6, 0xf5, 0x7a,
++	0x77, 0x20, 0x05, 0x3d, 0x30, 0x06, 0xd4, 0x4c,
++	0x0a, 0x2c, 0x98, 0x5a, 0xb9, 0xd4, 0x98, 0xa9,
++	0x3f, 0xc6, 0x12, 0xea, 0x3b, 0x4b, 0xc5, 0x79,
++	0x64, 0x63, 0x6b, 0x09, 0x54, 0x3b, 0x14, 0x27,
++	0xba, 0x99, 0x80, 0xc8, 0x72, 0xa8, 0x12, 0x90,
++	0x29, 0xba, 0x40, 0x54, 0x97, 0x2b, 0x7b, 0xfe,
++	0xeb, 0xcd, 0x01, 0x05, 0x44, 0x72, 0xdb, 0x99,
++	0xe4, 0x61, 0xc9, 0x69, 0xd6, 0xb9, 0x28, 0xd1,
++	0x05, 0x3e, 0xf9, 0x0b, 0x49, 0x0a, 0x49, 0xe9,
++	0x8d, 0x0e, 0xa7, 0x4a, 0x0f, 0xaf, 0x32, 0xd0,
++	0xe0, 0xb2, 0x3a, 0x55, 0x58, 0xfe, 0x5c, 0x28,
++	0x70, 0x51, 0x23, 0xb0, 0x7b, 0x6a, 0x5f, 0x1e,
++	0xb8, 0x17, 0xd7, 0x94, 0x15, 0x8f, 0xee, 0x20,
++	0xc7, 0x42, 0x25, 0x3e, 0x9a, 0x14, 0xd7, 0x60,
++	0x72, 0x39, 0x47, 0x48, 0xa9, 0xfe, 0xdd, 0x47,
++	0x0a, 0xb1, 0xe6, 0x60, 0x28, 0x8c, 0x11, 0x68,
++	0xe1, 0xff, 0xd7, 0xce, 0xc8, 0xbe, 0xb3, 0xfe,
++	0x27, 0x30, 0x09, 0x70, 0xd7, 0xfa, 0x02, 0x33,
++	0x3a, 0x61, 0x2e, 0xc7, 0xff, 0xa4, 0x2a, 0xa8,
++	0x6e, 0xb4, 0x79, 0x35, 0x6d, 0x4c, 0x1e, 0x38,
++	0xf8, 0xee, 0xd4, 0x84, 0x4e, 0x6e, 0x28, 0xa7,
++	0xce, 0xc8, 0xc1, 0xcf, 0x80, 0x05, 0xf3, 0x04,
++	0xef, 0xc8, 0x18, 0x28, 0x2e, 0x8d, 0x5e, 0x0c,
++	0xdf, 0xb8, 0x5f, 0x96, 0xe8, 0xc6, 0x9c, 0x2f,
++	0xe5, 0xa6, 0x44, 0xd7, 0xe7, 0x99, 0x44, 0x0c,
++	0xec, 0xd7, 0x05, 0x60, 0x97, 0xbb, 0x74, 0x77,
++	0x58, 0xd5, 0xbb, 0x48, 0xde, 0x5a, 0xb2, 0x54,
++	0x7f, 0x0e, 0x46, 0x70, 0x6a, 0x6f, 0x78, 0xa5,
++	0x08, 0x89, 0x05, 0x4e, 0x7e, 0xa0, 0x69, 0xb4,
++	0x40, 0x60, 0x55, 0x77, 0x75, 0x9b, 0x19, 0xf2,
++	0xd5, 0x13, 0x80, 0x77, 0xf9, 0x4b, 0x3f, 0x1e,
++	0xee, 0xe6, 0x76, 0x84, 0x7b, 0x8c, 0xe5, 0x27,
++	0xa8, 0x0a, 0x91, 0x01, 0x68, 0x71, 0x8a, 0x3f,
++	0x06, 0xab, 0xf6, 0xa9, 0xa5, 0xe6, 0x72, 0x92,
++	0xe4, 0x67, 0xe2, 0xa2, 0x46, 0x35, 0x84, 0x55,
++	0x7d, 0xca, 0xa8, 0x85, 0xd0, 0xf1, 0x3f, 0xbe,
++	0xd7, 0x34, 0x64, 0xfc, 0xae, 0xe3, 0xe4, 0x04,
++	0x9f, 0x66, 0x02, 0xb9, 0x88, 0x10, 0xd9, 0xc4,
++	0x4c, 0x31, 0x43, 0x7a, 0x93, 0xe2, 0x9b, 0x56,
++	0x43, 0x84, 0xdc, 0xdc, 0xde, 0x1d, 0xa4, 0x02,
++	0x0e, 0xc2, 0xef, 0xc3, 0xf8, 0x78, 0xd1, 0xb2,
++	0x6b, 0x63, 0x18, 0xc9, 0xa9, 0xe5, 0x72, 0xd8,
++	0xf3, 0xb9, 0xd1, 0x8a, 0xc7, 0x1a, 0x02, 0x27,
++	0x20, 0x77, 0x10, 0xe5, 0xc8, 0xd4, 0x4a, 0x47,
++	0xe5, 0xdf, 0x5f, 0x01, 0xaa, 0xb0, 0xd4, 0x10,
++	0xbb, 0x69, 0xe3, 0x36, 0xc8, 0xe1, 0x3d, 0x43,
++	0xfb, 0x86, 0xcd, 0xcc, 0xbf, 0xf4, 0x88, 0xe0,
++	0x20, 0xca, 0xb7, 0x1b, 0xf1, 0x2f, 0x5c, 0xee,
++	0xd4, 0xd3, 0xa3, 0xcc, 0xa4, 0x1e, 0x1c, 0x47,
++	0xfb, 0xbf, 0xfc, 0xa2, 0x41, 0x55, 0x9d, 0xf6,
++	0x5a, 0x5e, 0x65, 0x32, 0x34, 0x7b, 0x52, 0x8d,
++	0xd5, 0xd0, 0x20, 0x60, 0x03, 0xab, 0x3f, 0x8c,
++	0xd4, 0x21, 0xea, 0x2a, 0xd9, 0xc4, 0xd0, 0xd3,
++	0x65, 0xd8, 0x7a, 0x13, 0x28, 0x62, 0x32, 0x4b,
++	0x2c, 0x87, 0x93, 0xa8, 0xb4, 0x52, 0x45, 0x09,
++	0x44, 0xec, 0xec, 0xc3, 0x17, 0xdb, 0x9a, 0x4d,
++	0x5c, 0xa9, 0x11, 0xd4, 0x7d, 0xaf, 0x9e, 0xf1,
++	0x2d, 0xb2, 0x66, 0xc5, 0x1d, 0xed, 0xb7, 0xcd,
++	0x0b, 0x25, 0x5e, 0x30, 0x47, 0x3f, 0x40, 0xf4,
++	0xa1, 0xa0, 0x00, 0x94, 0x10, 0xc5, 0x6a, 0x63,
++	0x1a, 0xd5, 0x88, 0x92, 0x8e, 0x82, 0x39, 0x87,
++	0x3c, 0x78, 0x65, 0x58, 0x42, 0x75, 0x5b, 0xdd,
++	0x77, 0x3e, 0x09, 0x4e, 0x76, 0x5b, 0xe6, 0x0e,
++	0x4d, 0x38, 0xb2, 0xc0, 0xb8, 0x95, 0x01, 0x7a,
++	0x10, 0xe0, 0xfb, 0x07, 0xf2, 0xab, 0x2d, 0x8c,
++	0x32, 0xed, 0x2b, 0xc0, 0x46, 0xc2, 0xf5, 0x38,
++	0x83, 0xf0, 0x17, 0xec, 0xc1, 0x20, 0x6a, 0x9a,
++	0x0b, 0x00, 0xa0, 0x98, 0x22, 0x50, 0x23, 0xd5,
++	0x80, 0x6b, 0xf6, 0x1f, 0xc3, 0xcc, 0x97, 0xc9,
++	0x24, 0x9f, 0xf3, 0xaf, 0x43, 0x14, 0xd5, 0xa0
++};
++static const u8 dec_output010[] __initconst = {
++	0x42, 0x93, 0xe4, 0xeb, 0x97, 0xb0, 0x57, 0xbf,
++	0x1a, 0x8b, 0x1f, 0xe4, 0x5f, 0x36, 0x20, 0x3c,
++	0xef, 0x0a, 0xa9, 0x48, 0x5f, 0x5f, 0x37, 0x22,
++	0x3a, 0xde, 0xe3, 0xae, 0xbe, 0xad, 0x07, 0xcc,
++	0xb1, 0xf6, 0xf5, 0xf9, 0x56, 0xdd, 0xe7, 0x16,
++	0x1e, 0x7f, 0xdf, 0x7a, 0x9e, 0x75, 0xb7, 0xc7,
++	0xbe, 0xbe, 0x8a, 0x36, 0x04, 0xc0, 0x10, 0xf4,
++	0x95, 0x20, 0x03, 0xec, 0xdc, 0x05, 0xa1, 0x7d,
++	0xc4, 0xa9, 0x2c, 0x82, 0xd0, 0xbc, 0x8b, 0xc5,
++	0xc7, 0x45, 0x50, 0xf6, 0xa2, 0x1a, 0xb5, 0x46,
++	0x3b, 0x73, 0x02, 0xa6, 0x83, 0x4b, 0x73, 0x82,
++	0x58, 0x5e, 0x3b, 0x65, 0x2f, 0x0e, 0xfd, 0x2b,
++	0x59, 0x16, 0xce, 0xa1, 0x60, 0x9c, 0xe8, 0x3a,
++	0x99, 0xed, 0x8d, 0x5a, 0xcf, 0xf6, 0x83, 0xaf,
++	0xba, 0xd7, 0x73, 0x73, 0x40, 0x97, 0x3d, 0xca,
++	0xef, 0x07, 0x57, 0xe6, 0xd9, 0x70, 0x0e, 0x95,
++	0xae, 0xa6, 0x8d, 0x04, 0xcc, 0xee, 0xf7, 0x09,
++	0x31, 0x77, 0x12, 0xa3, 0x23, 0x97, 0x62, 0xb3,
++	0x7b, 0x32, 0xfb, 0x80, 0x14, 0x48, 0x81, 0xc3,
++	0xe5, 0xea, 0x91, 0x39, 0x52, 0x81, 0xa2, 0x4f,
++	0xe4, 0xb3, 0x09, 0xff, 0xde, 0x5e, 0xe9, 0x58,
++	0x84, 0x6e, 0xf9, 0x3d, 0xdf, 0x25, 0xea, 0xad,
++	0xae, 0xe6, 0x9a, 0xd1, 0x89, 0x55, 0xd3, 0xde,
++	0x6c, 0x52, 0xdb, 0x70, 0xfe, 0x37, 0xce, 0x44,
++	0x0a, 0xa8, 0x25, 0x5f, 0x92, 0xc1, 0x33, 0x4a,
++	0x4f, 0x9b, 0x62, 0x35, 0xff, 0xce, 0xc0, 0xa9,
++	0x60, 0xce, 0x52, 0x00, 0x97, 0x51, 0x35, 0x26,
++	0x2e, 0xb9, 0x36, 0xa9, 0x87, 0x6e, 0x1e, 0xcc,
++	0x91, 0x78, 0x53, 0x98, 0x86, 0x5b, 0x9c, 0x74,
++	0x7d, 0x88, 0x33, 0xe1, 0xdf, 0x37, 0x69, 0x2b,
++	0xbb, 0xf1, 0x4d, 0xf4, 0xd1, 0xf1, 0x39, 0x93,
++	0x17, 0x51, 0x19, 0xe3, 0x19, 0x1e, 0x76, 0x37,
++	0x25, 0xfb, 0x09, 0x27, 0x6a, 0xab, 0x67, 0x6f,
++	0x14, 0x12, 0x64, 0xe7, 0xc4, 0x07, 0xdf, 0x4d,
++	0x17, 0xbb, 0x6d, 0xe0, 0xe9, 0xb9, 0xab, 0xca,
++	0x10, 0x68, 0xaf, 0x7e, 0xb7, 0x33, 0x54, 0x73,
++	0x07, 0x6e, 0xf7, 0x81, 0x97, 0x9c, 0x05, 0x6f,
++	0x84, 0x5f, 0xd2, 0x42, 0xfb, 0x38, 0xcf, 0xd1,
++	0x2f, 0x14, 0x30, 0x88, 0x98, 0x4d, 0x5a, 0xa9,
++	0x76, 0xd5, 0x4f, 0x3e, 0x70, 0x6c, 0x85, 0x76,
++	0xd7, 0x01, 0xa0, 0x1a, 0xc8, 0x4e, 0xaa, 0xac,
++	0x78, 0xfe, 0x46, 0xde, 0x6a, 0x05, 0x46, 0xa7,
++	0x43, 0x0c, 0xb9, 0xde, 0xb9, 0x68, 0xfb, 0xce,
++	0x42, 0x99, 0x07, 0x4d, 0x0b, 0x3b, 0x5a, 0x30,
++	0x35, 0xa8, 0xf9, 0x3a, 0x73, 0xef, 0x0f, 0xdb,
++	0x1e, 0x16, 0x42, 0xc4, 0xba, 0xae, 0x58, 0xaa,
++	0xf8, 0xe5, 0x75, 0x2f, 0x1b, 0x15, 0x5c, 0xfd,
++	0x0a, 0x97, 0xd0, 0xe4, 0x37, 0x83, 0x61, 0x5f,
++	0x43, 0xa6, 0xc7, 0x3f, 0x38, 0x59, 0xe6, 0xeb,
++	0xa3, 0x90, 0xc3, 0xaa, 0xaa, 0x5a, 0xd3, 0x34,
++	0xd4, 0x17, 0xc8, 0x65, 0x3e, 0x57, 0xbc, 0x5e,
++	0xdd, 0x9e, 0xb7, 0xf0, 0x2e, 0x5b, 0xb2, 0x1f,
++	0x8a, 0x08, 0x0d, 0x45, 0x91, 0x0b, 0x29, 0x53,
++	0x4f, 0x4c, 0x5a, 0x73, 0x56, 0xfe, 0xaf, 0x41,
++	0x01, 0x39, 0x0a, 0x24, 0x3c, 0x7e, 0xbe, 0x4e,
++	0x53, 0xf3, 0xeb, 0x06, 0x66, 0x51, 0x28, 0x1d,
++	0xbd, 0x41, 0x0a, 0x01, 0xab, 0x16, 0x47, 0x27,
++	0x47, 0x47, 0xf7, 0xcb, 0x46, 0x0a, 0x70, 0x9e,
++	0x01, 0x9c, 0x09, 0xe1, 0x2a, 0x00, 0x1a, 0xd8,
++	0xd4, 0x79, 0x9d, 0x80, 0x15, 0x8e, 0x53, 0x2a,
++	0x65, 0x83, 0x78, 0x3e, 0x03, 0x00, 0x07, 0x12,
++	0x1f, 0x33, 0x3e, 0x7b, 0x13, 0x37, 0xf1, 0xc3,
++	0xef, 0xb7, 0xc1, 0x20, 0x3c, 0x3e, 0x67, 0x66,
++	0x5d, 0x88, 0xa7, 0x7d, 0x33, 0x50, 0x77, 0xb0,
++	0x28, 0x8e, 0xe7, 0x2c, 0x2e, 0x7a, 0xf4, 0x3c,
++	0x8d, 0x74, 0x83, 0xaf, 0x8e, 0x87, 0x0f, 0xe4,
++	0x50, 0xff, 0x84, 0x5c, 0x47, 0x0c, 0x6a, 0x49,
++	0xbf, 0x42, 0x86, 0x77, 0x15, 0x48, 0xa5, 0x90,
++	0x5d, 0x93, 0xd6, 0x2a, 0x11, 0xd5, 0xd5, 0x11,
++	0xaa, 0xce, 0xe7, 0x6f, 0xa5, 0xb0, 0x09, 0x2c,
++	0x8d, 0xd3, 0x92, 0xf0, 0x5a, 0x2a, 0xda, 0x5b,
++	0x1e, 0xd5, 0x9a, 0xc4, 0xc4, 0xf3, 0x49, 0x74,
++	0x41, 0xca, 0xe8, 0xc1, 0xf8, 0x44, 0xd6, 0x3c,
++	0xae, 0x6c, 0x1d, 0x9a, 0x30, 0x04, 0x4d, 0x27,
++	0x0e, 0xb1, 0x5f, 0x59, 0xa2, 0x24, 0xe8, 0xe1,
++	0x98, 0xc5, 0x6a, 0x4c, 0xfe, 0x41, 0xd2, 0x27,
++	0x42, 0x52, 0xe1, 0xe9, 0x7d, 0x62, 0xe4, 0x88,
++	0x0f, 0xad, 0xb2, 0x70, 0xcb, 0x9d, 0x4c, 0x27,
++	0x2e, 0x76, 0x1e, 0x1a, 0x63, 0x65, 0xf5, 0x3b,
++	0xf8, 0x57, 0x69, 0xeb, 0x5b, 0x38, 0x26, 0x39,
++	0x33, 0x25, 0x45, 0x3e, 0x91, 0xb8, 0xd8, 0xc7,
++	0xd5, 0x42, 0xc0, 0x22, 0x31, 0x74, 0xf4, 0xbc,
++	0x0c, 0x23, 0xf1, 0xca, 0xc1, 0x8d, 0xd7, 0xbe,
++	0xc9, 0x62, 0xe4, 0x08, 0x1a, 0xcf, 0x36, 0xd5,
++	0xfe, 0x55, 0x21, 0x59, 0x91, 0x87, 0x87, 0xdf,
++	0x06, 0xdb, 0xdf, 0x96, 0x45, 0x58, 0xda, 0x05,
++	0xcd, 0x50, 0x4d, 0xd2, 0x7d, 0x05, 0x18, 0x73,
++	0x6a, 0x8d, 0x11, 0x85, 0xa6, 0x88, 0xe8, 0xda,
++	0xe6, 0x30, 0x33, 0xa4, 0x89, 0x31, 0x75, 0xbe,
++	0x69, 0x43, 0x84, 0x43, 0x50, 0x87, 0xdd, 0x71,
++	0x36, 0x83, 0xc3, 0x78, 0x74, 0x24, 0x0a, 0xed,
++	0x7b, 0xdb, 0xa4, 0x24, 0x0b, 0xb9, 0x7e, 0x5d,
++	0xff, 0xde, 0xb1, 0xef, 0x61, 0x5a, 0x45, 0x33,
++	0xf6, 0x17, 0x07, 0x08, 0x98, 0x83, 0x92, 0x0f,
++	0x23, 0x6d, 0xe6, 0xaa, 0x17, 0x54, 0xad, 0x6a,
++	0xc8, 0xdb, 0x26, 0xbe, 0xb8, 0xb6, 0x08, 0xfa,
++	0x68, 0xf1, 0xd7, 0x79, 0x6f, 0x18, 0xb4, 0x9e,
++	0x2d, 0x3f, 0x1b, 0x64, 0xaf, 0x8d, 0x06, 0x0e,
++	0x49, 0x28, 0xe0, 0x5d, 0x45, 0x68, 0x13, 0x87,
++	0xfa, 0xde, 0x40, 0x7b, 0xd2, 0xc3, 0x94, 0xd5,
++	0xe1, 0xd9, 0xc2, 0xaf, 0x55, 0x89, 0xeb, 0xb4,
++	0x12, 0x59, 0xa8, 0xd4, 0xc5, 0x29, 0x66, 0x38,
++	0xe6, 0xac, 0x22, 0x22, 0xd9, 0x64, 0x9b, 0x34,
++	0x0a, 0x32, 0x9f, 0xc2, 0xbf, 0x17, 0x6c, 0x3f,
++	0x71, 0x7a, 0x38, 0x6b, 0x98, 0xfb, 0x49, 0x36,
++	0x89, 0xc9, 0xe2, 0xd6, 0xc7, 0x5d, 0xd0, 0x69,
++	0x5f, 0x23, 0x35, 0xc9, 0x30, 0xe2, 0xfd, 0x44,
++	0x58, 0x39, 0xd7, 0x97, 0xfb, 0x5c, 0x00, 0xd5,
++	0x4f, 0x7a, 0x1a, 0x95, 0x8b, 0x62, 0x4b, 0xce,
++	0xe5, 0x91, 0x21, 0x7b, 0x30, 0x00, 0xd6, 0xdd,
++	0x6d, 0x02, 0x86, 0x49, 0x0f, 0x3c, 0x1a, 0x27,
++	0x3c, 0xd3, 0x0e, 0x71, 0xf2, 0xff, 0xf5, 0x2f,
++	0x87, 0xac, 0x67, 0x59, 0x81, 0xa3, 0xf7, 0xf8,
++	0xd6, 0x11, 0x0c, 0x84, 0xa9, 0x03, 0xee, 0x2a,
++	0xc4, 0xf3, 0x22, 0xab, 0x7c, 0xe2, 0x25, 0xf5,
++	0x67, 0xa3, 0xe4, 0x11, 0xe0, 0x59, 0xb3, 0xca,
++	0x87, 0xa0, 0xae, 0xc9, 0xa6, 0x62, 0x1b, 0x6e,
++	0x4d, 0x02, 0x6b, 0x07, 0x9d, 0xfd, 0xd0, 0x92,
++	0x06, 0xe1, 0xb2, 0x9a, 0x4a, 0x1f, 0x1f, 0x13,
++	0x49, 0x99, 0x97, 0x08, 0xde, 0x7f, 0x98, 0xaf,
++	0x51, 0x98, 0xee, 0x2c, 0xcb, 0xf0, 0x0b, 0xc6,
++	0xb6, 0xb7, 0x2d, 0x9a, 0xb1, 0xac, 0xa6, 0xe3,
++	0x15, 0x77, 0x9d, 0x6b, 0x1a, 0xe4, 0xfc, 0x8b,
++	0xf2, 0x17, 0x59, 0x08, 0x04, 0x58, 0x81, 0x9d,
++	0x1b, 0x1b, 0x69, 0x55, 0xc2, 0xb4, 0x3c, 0x1f,
++	0x50, 0xf1, 0x7f, 0x77, 0x90, 0x4c, 0x66, 0x40,
++	0x5a, 0xc0, 0x33, 0x1f, 0xcb, 0x05, 0x6d, 0x5c,
++	0x06, 0x87, 0x52, 0xa2, 0x8f, 0x26, 0xd5, 0x4f
++};
++static const u8 dec_assoc010[] __initconst = {
++	0xd2, 0xa1, 0x70, 0xdb, 0x7a, 0xf8, 0xfa, 0x27,
++	0xba, 0x73, 0x0f, 0xbf, 0x3d, 0x1e, 0x82, 0xb2
++};
++static const u8 dec_nonce010[] __initconst = {
++	0xdb, 0x92, 0x0f, 0x7f, 0x17, 0x54, 0x0c, 0x30
++};
++static const u8 dec_key010[] __initconst = {
++	0x47, 0x11, 0xeb, 0x86, 0x2b, 0x2c, 0xab, 0x44,
++	0x34, 0xda, 0x7f, 0x57, 0x03, 0x39, 0x0c, 0xaf,
++	0x2c, 0x14, 0xfd, 0x65, 0x23, 0xe9, 0x8e, 0x74,
++	0xd5, 0x08, 0x68, 0x08, 0xe7, 0xb4, 0x72, 0xd7
++};
++
++static const u8 dec_input011[] __initconst = {
++	0x6a, 0xfc, 0x4b, 0x25, 0xdf, 0xc0, 0xe4, 0xe8,
++	0x17, 0x4d, 0x4c, 0xc9, 0x7e, 0xde, 0x3a, 0xcc,
++	0x3c, 0xba, 0x6a, 0x77, 0x47, 0xdb, 0xe3, 0x74,
++	0x7a, 0x4d, 0x5f, 0x8d, 0x37, 0x55, 0x80, 0x73,
++	0x90, 0x66, 0x5d, 0x3a, 0x7d, 0x5d, 0x86, 0x5e,
++	0x8d, 0xfd, 0x83, 0xff, 0x4e, 0x74, 0x6f, 0xf9,
++	0xe6, 0x70, 0x17, 0x70, 0x3e, 0x96, 0xa7, 0x7e,
++	0xcb, 0xab, 0x8f, 0x58, 0x24, 0x9b, 0x01, 0xfd,
++	0xcb, 0xe6, 0x4d, 0x9b, 0xf0, 0x88, 0x94, 0x57,
++	0x66, 0xef, 0x72, 0x4c, 0x42, 0x6e, 0x16, 0x19,
++	0x15, 0xea, 0x70, 0x5b, 0xac, 0x13, 0xdb, 0x9f,
++	0x18, 0xe2, 0x3c, 0x26, 0x97, 0xbc, 0xdc, 0x45,
++	0x8c, 0x6c, 0x24, 0x69, 0x9c, 0xf7, 0x65, 0x1e,
++	0x18, 0x59, 0x31, 0x7c, 0xe4, 0x73, 0xbc, 0x39,
++	0x62, 0xc6, 0x5c, 0x9f, 0xbf, 0xfa, 0x90, 0x03,
++	0xc9, 0x72, 0x26, 0xb6, 0x1b, 0xc2, 0xb7, 0x3f,
++	0xf2, 0x13, 0x77, 0xf2, 0x8d, 0xb9, 0x47, 0xd0,
++	0x53, 0xdd, 0xc8, 0x91, 0x83, 0x8b, 0xb1, 0xce,
++	0xa3, 0xfe, 0xcd, 0xd9, 0xdd, 0x92, 0x7b, 0xdb,
++	0xb8, 0xfb, 0xc9, 0x2d, 0x01, 0x59, 0x39, 0x52,
++	0xad, 0x1b, 0xec, 0xcf, 0xd7, 0x70, 0x13, 0x21,
++	0xf5, 0x47, 0xaa, 0x18, 0x21, 0x5c, 0xc9, 0x9a,
++	0xd2, 0x6b, 0x05, 0x9c, 0x01, 0xa1, 0xda, 0x35,
++	0x5d, 0xb3, 0x70, 0xe6, 0xa9, 0x80, 0x8b, 0x91,
++	0xb7, 0xb3, 0x5f, 0x24, 0x9a, 0xb7, 0xd1, 0x6b,
++	0xa1, 0x1c, 0x50, 0xba, 0x49, 0xe0, 0xee, 0x2e,
++	0x75, 0xac, 0x69, 0xc0, 0xeb, 0x03, 0xdd, 0x19,
++	0xe5, 0xf6, 0x06, 0xdd, 0xc3, 0xd7, 0x2b, 0x07,
++	0x07, 0x30, 0xa7, 0x19, 0x0c, 0xbf, 0xe6, 0x18,
++	0xcc, 0xb1, 0x01, 0x11, 0x85, 0x77, 0x1d, 0x96,
++	0xa7, 0xa3, 0x00, 0x84, 0x02, 0xa2, 0x83, 0x68,
++	0xda, 0x17, 0x27, 0xc8, 0x7f, 0x23, 0xb7, 0xf4,
++	0x13, 0x85, 0xcf, 0xdd, 0x7a, 0x7d, 0x24, 0x57,
++	0xfe, 0x05, 0x93, 0xf5, 0x74, 0xce, 0xed, 0x0c,
++	0x20, 0x98, 0x8d, 0x92, 0x30, 0xa1, 0x29, 0x23,
++	0x1a, 0xa0, 0x4f, 0x69, 0x56, 0x4c, 0xe1, 0xc8,
++	0xce, 0xf6, 0x9a, 0x0c, 0xa4, 0xfa, 0x04, 0xf6,
++	0x62, 0x95, 0xf2, 0xfa, 0xc7, 0x40, 0x68, 0x40,
++	0x8f, 0x41, 0xda, 0xb4, 0x26, 0x6f, 0x70, 0xab,
++	0x40, 0x61, 0xa4, 0x0e, 0x75, 0xfb, 0x86, 0xeb,
++	0x9d, 0x9a, 0x1f, 0xec, 0x76, 0x99, 0xe7, 0xea,
++	0xaa, 0x1e, 0x2d, 0xb5, 0xd4, 0xa6, 0x1a, 0xb8,
++	0x61, 0x0a, 0x1d, 0x16, 0x5b, 0x98, 0xc2, 0x31,
++	0x40, 0xe7, 0x23, 0x1d, 0x66, 0x99, 0xc8, 0xc0,
++	0xd7, 0xce, 0xf3, 0x57, 0x40, 0x04, 0x3f, 0xfc,
++	0xea, 0xb3, 0xfc, 0xd2, 0xd3, 0x99, 0xa4, 0x94,
++	0x69, 0xa0, 0xef, 0xd1, 0x85, 0xb3, 0xa6, 0xb1,
++	0x28, 0xbf, 0x94, 0x67, 0x22, 0xc3, 0x36, 0x46,
++	0xf8, 0xd2, 0x0f, 0x5f, 0xf4, 0x59, 0x80, 0xe6,
++	0x2d, 0x43, 0x08, 0x7d, 0x19, 0x09, 0x97, 0xa7,
++	0x4c, 0x3d, 0x8d, 0xba, 0x65, 0x62, 0xa3, 0x71,
++	0x33, 0x29, 0x62, 0xdb, 0xc1, 0x33, 0x34, 0x1a,
++	0x63, 0x33, 0x16, 0xb6, 0x64, 0x7e, 0xab, 0x33,
++	0xf0, 0xe6, 0x26, 0x68, 0xba, 0x1d, 0x2e, 0x38,
++	0x08, 0xe6, 0x02, 0xd3, 0x25, 0x2c, 0x47, 0x23,
++	0x58, 0x34, 0x0f, 0x9d, 0x63, 0x4f, 0x63, 0xbb,
++	0x7f, 0x3b, 0x34, 0x38, 0xa7, 0xb5, 0x8d, 0x65,
++	0xd9, 0x9f, 0x79, 0x55, 0x3e, 0x4d, 0xe7, 0x73,
++	0xd8, 0xf6, 0x98, 0x97, 0x84, 0x60, 0x9c, 0xc8,
++	0xa9, 0x3c, 0xf6, 0xdc, 0x12, 0x5c, 0xe1, 0xbb,
++	0x0b, 0x8b, 0x98, 0x9c, 0x9d, 0x26, 0x7c, 0x4a,
++	0xe6, 0x46, 0x36, 0x58, 0x21, 0x4a, 0xee, 0xca,
++	0xd7, 0x3b, 0xc2, 0x6c, 0x49, 0x2f, 0xe5, 0xd5,
++	0x03, 0x59, 0x84, 0x53, 0xcb, 0xfe, 0x92, 0x71,
++	0x2e, 0x7c, 0x21, 0xcc, 0x99, 0x85, 0x7f, 0xb8,
++	0x74, 0x90, 0x13, 0x42, 0x3f, 0xe0, 0x6b, 0x1d,
++	0xf2, 0x4d, 0x54, 0xd4, 0xfc, 0x3a, 0x05, 0xe6,
++	0x74, 0xaf, 0xa6, 0xa0, 0x2a, 0x20, 0x23, 0x5d,
++	0x34, 0x5c, 0xd9, 0x3e, 0x4e, 0xfa, 0x93, 0xe7,
++	0xaa, 0xe9, 0x6f, 0x08, 0x43, 0x67, 0x41, 0xc5,
++	0xad, 0xfb, 0x31, 0x95, 0x82, 0x73, 0x32, 0xd8,
++	0xa6, 0xa3, 0xed, 0x0e, 0x2d, 0xf6, 0x5f, 0xfd,
++	0x80, 0xa6, 0x7a, 0xe0, 0xdf, 0x78, 0x15, 0x29,
++	0x74, 0x33, 0xd0, 0x9e, 0x83, 0x86, 0x72, 0x22,
++	0x57, 0x29, 0xb9, 0x9e, 0x5d, 0xd3, 0x1a, 0xb5,
++	0x96, 0x72, 0x41, 0x3d, 0xf1, 0x64, 0x43, 0x67,
++	0xee, 0xaa, 0x5c, 0xd3, 0x9a, 0x96, 0x13, 0x11,
++	0x5d, 0xf3, 0x0c, 0x87, 0x82, 0x1e, 0x41, 0x9e,
++	0xd0, 0x27, 0xd7, 0x54, 0x3b, 0x67, 0x73, 0x09,
++	0x91, 0xe9, 0xd5, 0x36, 0xa7, 0xb5, 0x55, 0xe4,
++	0xf3, 0x21, 0x51, 0x49, 0x22, 0x07, 0x55, 0x4f,
++	0x44, 0x4b, 0xd2, 0x15, 0x93, 0x17, 0x2a, 0xfa,
++	0x4d, 0x4a, 0x57, 0xdb, 0x4c, 0xa6, 0xeb, 0xec,
++	0x53, 0x25, 0x6c, 0x21, 0xed, 0x00, 0x4c, 0x3b,
++	0xca, 0x14, 0x57, 0xa9, 0xd6, 0x6a, 0xcd, 0x8d,
++	0x5e, 0x74, 0xac, 0x72, 0xc1, 0x97, 0xe5, 0x1b,
++	0x45, 0x4e, 0xda, 0xfc, 0xcc, 0x40, 0xe8, 0x48,
++	0x88, 0x0b, 0xa3, 0xe3, 0x8d, 0x83, 0x42, 0xc3,
++	0x23, 0xfd, 0x68, 0xb5, 0x8e, 0xf1, 0x9d, 0x63,
++	0x77, 0xe9, 0xa3, 0x8e, 0x8c, 0x26, 0x6b, 0xbd,
++	0x72, 0x73, 0x35, 0x0c, 0x03, 0xf8, 0x43, 0x78,
++	0x52, 0x71, 0x15, 0x1f, 0x71, 0x5d, 0x6e, 0xed,
++	0xb9, 0xcc, 0x86, 0x30, 0xdb, 0x2b, 0xd3, 0x82,
++	0x88, 0x23, 0x71, 0x90, 0x53, 0x5c, 0xa9, 0x2f,
++	0x76, 0x01, 0xb7, 0x9a, 0xfe, 0x43, 0x55, 0xa3,
++	0x04, 0x9b, 0x0e, 0xe4, 0x59, 0xdf, 0xc9, 0xe9,
++	0xb1, 0xea, 0x29, 0x28, 0x3c, 0x5c, 0xae, 0x72,
++	0x84, 0xb6, 0xc6, 0xeb, 0x0c, 0x27, 0x07, 0x74,
++	0x90, 0x0d, 0x31, 0xb0, 0x00, 0x77, 0xe9, 0x40,
++	0x70, 0x6f, 0x68, 0xa7, 0xfd, 0x06, 0xec, 0x4b,
++	0xc0, 0xb7, 0xac, 0xbc, 0x33, 0xb7, 0x6d, 0x0a,
++	0xbd, 0x12, 0x1b, 0x59, 0xcb, 0xdd, 0x32, 0xf5,
++	0x1d, 0x94, 0x57, 0x76, 0x9e, 0x0c, 0x18, 0x98,
++	0x71, 0xd7, 0x2a, 0xdb, 0x0b, 0x7b, 0xa7, 0x71,
++	0xb7, 0x67, 0x81, 0x23, 0x96, 0xae, 0xb9, 0x7e,
++	0x32, 0x43, 0x92, 0x8a, 0x19, 0xa0, 0xc4, 0xd4,
++	0x3b, 0x57, 0xf9, 0x4a, 0x2c, 0xfb, 0x51, 0x46,
++	0xbb, 0xcb, 0x5d, 0xb3, 0xef, 0x13, 0x93, 0x6e,
++	0x68, 0x42, 0x54, 0x57, 0xd3, 0x6a, 0x3a, 0x8f,
++	0x9d, 0x66, 0xbf, 0xbd, 0x36, 0x23, 0xf5, 0x93,
++	0x83, 0x7b, 0x9c, 0xc0, 0xdd, 0xc5, 0x49, 0xc0,
++	0x64, 0xed, 0x07, 0x12, 0xb3, 0xe6, 0xe4, 0xe5,
++	0x38, 0x95, 0x23, 0xb1, 0xa0, 0x3b, 0x1a, 0x61,
++	0xda, 0x17, 0xac, 0xc3, 0x58, 0xdd, 0x74, 0x64,
++	0x22, 0x11, 0xe8, 0x32, 0x1d, 0x16, 0x93, 0x85,
++	0x99, 0xa5, 0x9c, 0x34, 0x55, 0xb1, 0xe9, 0x20,
++	0x72, 0xc9, 0x28, 0x7b, 0x79, 0x00, 0xa1, 0xa6,
++	0xa3, 0x27, 0x40, 0x18, 0x8a, 0x54, 0xe0, 0xcc,
++	0xe8, 0x4e, 0x8e, 0x43, 0x96, 0xe7, 0x3f, 0xc8,
++	0xe9, 0xb2, 0xf9, 0xc9, 0xda, 0x04, 0x71, 0x50,
++	0x47, 0xe4, 0xaa, 0xce, 0xa2, 0x30, 0xc8, 0xe4,
++	0xac, 0xc7, 0x0d, 0x06, 0x2e, 0xe6, 0xe8, 0x80,
++	0x36, 0x29, 0x9e, 0x01, 0xb8, 0xc3, 0xf0, 0xa0,
++	0x5d, 0x7a, 0xca, 0x4d, 0xa0, 0x57, 0xbd, 0x2a,
++	0x45, 0xa7, 0x7f, 0x9c, 0x93, 0x07, 0x8f, 0x35,
++	0x67, 0x92, 0xe3, 0xe9, 0x7f, 0xa8, 0x61, 0x43,
++	0x9e, 0x25, 0x4f, 0x33, 0x76, 0x13, 0x6e, 0x12,
++	0xb9, 0xdd, 0xa4, 0x7c, 0x08, 0x9f, 0x7c, 0xe7,
++	0x0a, 0x8d, 0x84, 0x06, 0xa4, 0x33, 0x17, 0x34,
++	0x5e, 0x10, 0x7c, 0xc0, 0xa8, 0x3d, 0x1f, 0x42,
++	0x20, 0x51, 0x65, 0x5d, 0x09, 0xc3, 0xaa, 0xc0,
++	0xc8, 0x0d, 0xf0, 0x79, 0xbc, 0x20, 0x1b, 0x95,
++	0xe7, 0x06, 0x7d, 0x47, 0x20, 0x03, 0x1a, 0x74,
++	0xdd, 0xe2, 0xd4, 0xae, 0x38, 0x71, 0x9b, 0xf5,
++	0x80, 0xec, 0x08, 0x4e, 0x56, 0xba, 0x76, 0x12,
++	0x1a, 0xdf, 0x48, 0xf3, 0xae, 0xb3, 0xe6, 0xe6,
++	0xbe, 0xc0, 0x91, 0x2e, 0x01, 0xb3, 0x01, 0x86,
++	0xa2, 0xb9, 0x52, 0xd1, 0x21, 0xae, 0xd4, 0x97,
++	0x1d, 0xef, 0x41, 0x12, 0x95, 0x3d, 0x48, 0x45,
++	0x1c, 0x56, 0x32, 0x8f, 0xb8, 0x43, 0xbb, 0x19,
++	0xf3, 0xca, 0xe9, 0xeb, 0x6d, 0x84, 0xbe, 0x86,
++	0x06, 0xe2, 0x36, 0xb2, 0x62, 0x9d, 0xd3, 0x4c,
++	0x48, 0x18, 0x54, 0x13, 0x4e, 0xcf, 0xfd, 0xba,
++	0x84, 0xb9, 0x30, 0x53, 0xcf, 0xfb, 0xb9, 0x29,
++	0x8f, 0xdc, 0x9f, 0xef, 0x60, 0x0b, 0x64, 0xf6,
++	0x8b, 0xee, 0xa6, 0x91, 0xc2, 0x41, 0x6c, 0xf6,
++	0xfa, 0x79, 0x67, 0x4b, 0xc1, 0x3f, 0xaf, 0x09,
++	0x81, 0xd4, 0x5d, 0xcb, 0x09, 0xdf, 0x36, 0x31,
++	0xc0, 0x14, 0x3c, 0x7c, 0x0e, 0x65, 0x95, 0x99,
++	0x6d, 0xa3, 0xf4, 0xd7, 0x38, 0xee, 0x1a, 0x2b,
++	0x37, 0xe2, 0xa4, 0x3b, 0x4b, 0xd0, 0x65, 0xca,
++	0xf8, 0xc3, 0xe8, 0x15, 0x20, 0xef, 0xf2, 0x00,
++	0xfd, 0x01, 0x09, 0xc5, 0xc8, 0x17, 0x04, 0x93,
++	0xd0, 0x93, 0x03, 0x55, 0xc5, 0xfe, 0x32, 0xa3,
++	0x3e, 0x28, 0x2d, 0x3b, 0x93, 0x8a, 0xcc, 0x07,
++	0x72, 0x80, 0x8b, 0x74, 0x16, 0x24, 0xbb, 0xda,
++	0x94, 0x39, 0x30, 0x8f, 0xb1, 0xcd, 0x4a, 0x90,
++	0x92, 0x7c, 0x14, 0x8f, 0x95, 0x4e, 0xac, 0x9b,
++	0xd8, 0x8f, 0x1a, 0x87, 0xa4, 0x32, 0x27, 0x8a,
++	0xba, 0xf7, 0x41, 0xcf, 0x84, 0x37, 0x19, 0xe6,
++	0x06, 0xf5, 0x0e, 0xcf, 0x36, 0xf5, 0x9e, 0x6c,
++	0xde, 0xbc, 0xff, 0x64, 0x7e, 0x4e, 0x59, 0x57,
++	0x48, 0xfe, 0x14, 0xf7, 0x9c, 0x93, 0x5d, 0x15,
++	0xad, 0xcc, 0x11, 0xb1, 0x17, 0x18, 0xb2, 0x7e,
++	0xcc, 0xab, 0xe9, 0xce, 0x7d, 0x77, 0x5b, 0x51,
++	0x1b, 0x1e, 0x20, 0xa8, 0x32, 0x06, 0x0e, 0x75,
++	0x93, 0xac, 0xdb, 0x35, 0x37, 0x1f, 0xe9, 0x19,
++	0x1d, 0xb4, 0x71, 0x97, 0xd6, 0x4e, 0x2c, 0x08,
++	0xa5, 0x13, 0xf9, 0x0e, 0x7e, 0x78, 0x6e, 0x14,
++	0xe0, 0xa9, 0xb9, 0x96, 0x4c, 0x80, 0x82, 0xba,
++	0x17, 0xb3, 0x9d, 0x69, 0xb0, 0x84, 0x46, 0xff,
++	0xf9, 0x52, 0x79, 0x94, 0x58, 0x3a, 0x62, 0x90,
++	0x15, 0x35, 0x71, 0x10, 0x37, 0xed, 0xa1, 0x8e,
++	0x53, 0x6e, 0xf4, 0x26, 0x57, 0x93, 0x15, 0x93,
++	0xf6, 0x81, 0x2c, 0x5a, 0x10, 0xda, 0x92, 0xad,
++	0x2f, 0xdb, 0x28, 0x31, 0x2d, 0x55, 0x04, 0xd2,
++	0x06, 0x28, 0x8c, 0x1e, 0xdc, 0xea, 0x54, 0xac,
++	0xff, 0xb7, 0x6c, 0x30, 0x15, 0xd4, 0xb4, 0x0d,
++	0x00, 0x93, 0x57, 0xdd, 0xd2, 0x07, 0x07, 0x06,
++	0xd9, 0x43, 0x9b, 0xcd, 0x3a, 0xf4, 0x7d, 0x4c,
++	0x36, 0x5d, 0x23, 0xa2, 0xcc, 0x57, 0x40, 0x91,
++	0xe9, 0x2c, 0x2f, 0x2c, 0xd5, 0x30, 0x9b, 0x17,
++	0xb0, 0xc9, 0xf7, 0xa7, 0x2f, 0xd1, 0x93, 0x20,
++	0x6b, 0xc6, 0xc1, 0xe4, 0x6f, 0xcb, 0xd1, 0xe7,
++	0x09, 0x0f, 0x9e, 0xdc, 0xaa, 0x9f, 0x2f, 0xdf,
++	0x56, 0x9f, 0xd4, 0x33, 0x04, 0xaf, 0xd3, 0x6c,
++	0x58, 0x61, 0xf0, 0x30, 0xec, 0xf2, 0x7f, 0xf2,
++	0x9c, 0xdf, 0x39, 0xbb, 0x6f, 0xa2, 0x8c, 0x7e,
++	0xc4, 0x22, 0x51, 0x71, 0xc0, 0x4d, 0x14, 0x1a,
++	0xc4, 0xcd, 0x04, 0xd9, 0x87, 0x08, 0x50, 0x05,
++	0xcc, 0xaf, 0xf6, 0xf0, 0x8f, 0x92, 0x54, 0x58,
++	0xc2, 0xc7, 0x09, 0x7a, 0x59, 0x02, 0x05, 0xe8,
++	0xb0, 0x86, 0xd9, 0xbf, 0x7b, 0x35, 0x51, 0x4d,
++	0xaf, 0x08, 0x97, 0x2c, 0x65, 0xda, 0x2a, 0x71,
++	0x3a, 0xa8, 0x51, 0xcc, 0xf2, 0x73, 0x27, 0xc3,
++	0xfd, 0x62, 0xcf, 0xe3, 0xb2, 0xca, 0xcb, 0xbe,
++	0x1a, 0x0a, 0xa1, 0x34, 0x7b, 0x77, 0xc4, 0x62,
++	0x68, 0x78, 0x5f, 0x94, 0x07, 0x04, 0x65, 0x16,
++	0x4b, 0x61, 0xcb, 0xff, 0x75, 0x26, 0x50, 0x66,
++	0x1f, 0x6e, 0x93, 0xf8, 0xc5, 0x51, 0xeb, 0xa4,
++	0x4a, 0x48, 0x68, 0x6b, 0xe2, 0x5e, 0x44, 0xb2,
++	0x50, 0x2c, 0x6c, 0xae, 0x79, 0x4e, 0x66, 0x35,
++	0x81, 0x50, 0xac, 0xbc, 0x3f, 0xb1, 0x0c, 0xf3,
++	0x05, 0x3c, 0x4a, 0xa3, 0x6c, 0x2a, 0x79, 0xb4,
++	0xb7, 0xab, 0xca, 0xc7, 0x9b, 0x8e, 0xcd, 0x5f,
++	0x11, 0x03, 0xcb, 0x30, 0xa3, 0xab, 0xda, 0xfe,
++	0x64, 0xb9, 0xbb, 0xd8, 0x5e, 0x3a, 0x1a, 0x56,
++	0xe5, 0x05, 0x48, 0x90, 0x1e, 0x61, 0x69, 0x1b,
++	0x22, 0xe6, 0x1a, 0x3c, 0x75, 0xad, 0x1f, 0x37,
++	0x28, 0xdc, 0xe4, 0x6d, 0xbd, 0x42, 0xdc, 0xd3,
++	0xc8, 0xb6, 0x1c, 0x48, 0xfe, 0x94, 0x77, 0x7f,
++	0xbd, 0x62, 0xac, 0xa3, 0x47, 0x27, 0xcf, 0x5f,
++	0xd9, 0xdb, 0xaf, 0xec, 0xf7, 0x5e, 0xc1, 0xb0,
++	0x9d, 0x01, 0x26, 0x99, 0x7e, 0x8f, 0x03, 0x70,
++	0xb5, 0x42, 0xbe, 0x67, 0x28, 0x1b, 0x7c, 0xbd,
++	0x61, 0x21, 0x97, 0xcc, 0x5c, 0xe1, 0x97, 0x8f,
++	0x8d, 0xde, 0x2b, 0xaa, 0xa7, 0x71, 0x1d, 0x1e,
++	0x02, 0x73, 0x70, 0x58, 0x32, 0x5b, 0x1d, 0x67,
++	0x3d, 0xe0, 0x74, 0x4f, 0x03, 0xf2, 0x70, 0x51,
++	0x79, 0xf1, 0x61, 0x70, 0x15, 0x74, 0x9d, 0x23,
++	0x89, 0xde, 0xac, 0xfd, 0xde, 0xd0, 0x1f, 0xc3,
++	0x87, 0x44, 0x35, 0x4b, 0xe5, 0xb0, 0x60, 0xc5,
++	0x22, 0xe4, 0x9e, 0xca, 0xeb, 0xd5, 0x3a, 0x09,
++	0x45, 0xa4, 0xdb, 0xfa, 0x3f, 0xeb, 0x1b, 0xc7,
++	0xc8, 0x14, 0x99, 0x51, 0x92, 0x10, 0xed, 0xed,
++	0x28, 0xe0, 0xa1, 0xf8, 0x26, 0xcf, 0xcd, 0xcb,
++	0x63, 0xa1, 0x3b, 0xe3, 0xdf, 0x7e, 0xfe, 0xa6,
++	0xf0, 0x81, 0x9a, 0xbf, 0x55, 0xde, 0x54, 0xd5,
++	0x56, 0x60, 0x98, 0x10, 0x68, 0xf4, 0x38, 0x96,
++	0x8e, 0x6f, 0x1d, 0x44, 0x7f, 0xd6, 0x2f, 0xfe,
++	0x55, 0xfb, 0x0c, 0x7e, 0x67, 0xe2, 0x61, 0x44,
++	0xed, 0xf2, 0x35, 0x30, 0x5d, 0xe9, 0xc7, 0xd6,
++	0x6d, 0xe0, 0xa0, 0xed, 0xf3, 0xfc, 0xd8, 0x3e,
++	0x0a, 0x7b, 0xcd, 0xaf, 0x65, 0x68, 0x18, 0xc0,
++	0xec, 0x04, 0x1c, 0x74, 0x6d, 0xe2, 0x6e, 0x79,
++	0xd4, 0x11, 0x2b, 0x62, 0xd5, 0x27, 0xad, 0x4f,
++	0x01, 0x59, 0x73, 0xcc, 0x6a, 0x53, 0xfb, 0x2d,
++	0xd5, 0x4e, 0x99, 0x21, 0x65, 0x4d, 0xf5, 0x82,
++	0xf7, 0xd8, 0x42, 0xce, 0x6f, 0x3d, 0x36, 0x47,
++	0xf1, 0x05, 0x16, 0xe8, 0x1b, 0x6a, 0x8f, 0x93,
++	0xf2, 0x8f, 0x37, 0x40, 0x12, 0x28, 0xa3, 0xe6,
++	0xb9, 0x17, 0x4a, 0x1f, 0xb1, 0xd1, 0x66, 0x69,
++	0x86, 0xc4, 0xfc, 0x97, 0xae, 0x3f, 0x8f, 0x1e,
++	0x2b, 0xdf, 0xcd, 0xf9, 0x3c
++};
++static const u8 dec_output011[] __initconst = {
++	0x7a, 0x57, 0xf2, 0xc7, 0x06, 0x3f, 0x50, 0x7b,
++	0x36, 0x1a, 0x66, 0x5c, 0xb9, 0x0e, 0x5e, 0x3b,
++	0x45, 0x60, 0xbe, 0x9a, 0x31, 0x9f, 0xff, 0x5d,
++	0x66, 0x34, 0xb4, 0xdc, 0xfb, 0x9d, 0x8e, 0xee,
++	0x6a, 0x33, 0xa4, 0x07, 0x3c, 0xf9, 0x4c, 0x30,
++	0xa1, 0x24, 0x52, 0xf9, 0x50, 0x46, 0x88, 0x20,
++	0x02, 0x32, 0x3a, 0x0e, 0x99, 0x63, 0xaf, 0x1f,
++	0x15, 0x28, 0x2a, 0x05, 0xff, 0x57, 0x59, 0x5e,
++	0x18, 0xa1, 0x1f, 0xd0, 0x92, 0x5c, 0x88, 0x66,
++	0x1b, 0x00, 0x64, 0xa5, 0x93, 0x8d, 0x06, 0x46,
++	0xb0, 0x64, 0x8b, 0x8b, 0xef, 0x99, 0x05, 0x35,
++	0x85, 0xb3, 0xf3, 0x33, 0xbb, 0xec, 0x66, 0xb6,
++	0x3d, 0x57, 0x42, 0xe3, 0xb4, 0xc6, 0xaa, 0xb0,
++	0x41, 0x2a, 0xb9, 0x59, 0xa9, 0xf6, 0x3e, 0x15,
++	0x26, 0x12, 0x03, 0x21, 0x4c, 0x74, 0x43, 0x13,
++	0x2a, 0x03, 0x27, 0x09, 0xb4, 0xfb, 0xe7, 0xb7,
++	0x40, 0xff, 0x5e, 0xce, 0x48, 0x9a, 0x60, 0xe3,
++	0x8b, 0x80, 0x8c, 0x38, 0x2d, 0xcb, 0x93, 0x37,
++	0x74, 0x05, 0x52, 0x6f, 0x73, 0x3e, 0xc3, 0xbc,
++	0xca, 0x72, 0x0a, 0xeb, 0xf1, 0x3b, 0xa0, 0x95,
++	0xdc, 0x8a, 0xc4, 0xa9, 0xdc, 0xca, 0x44, 0xd8,
++	0x08, 0x63, 0x6a, 0x36, 0xd3, 0x3c, 0xb8, 0xac,
++	0x46, 0x7d, 0xfd, 0xaa, 0xeb, 0x3e, 0x0f, 0x45,
++	0x8f, 0x49, 0xda, 0x2b, 0xf2, 0x12, 0xbd, 0xaf,
++	0x67, 0x8a, 0x63, 0x48, 0x4b, 0x55, 0x5f, 0x6d,
++	0x8c, 0xb9, 0x76, 0x34, 0x84, 0xae, 0xc2, 0xfc,
++	0x52, 0x64, 0x82, 0xf7, 0xb0, 0x06, 0xf0, 0x45,
++	0x73, 0x12, 0x50, 0x30, 0x72, 0xea, 0x78, 0x9a,
++	0xa8, 0xaf, 0xb5, 0xe3, 0xbb, 0x77, 0x52, 0xec,
++	0x59, 0x84, 0xbf, 0x6b, 0x8f, 0xce, 0x86, 0x5e,
++	0x1f, 0x23, 0xe9, 0xfb, 0x08, 0x86, 0xf7, 0x10,
++	0xb9, 0xf2, 0x44, 0x96, 0x44, 0x63, 0xa9, 0xa8,
++	0x78, 0x00, 0x23, 0xd6, 0xc7, 0xe7, 0x6e, 0x66,
++	0x4f, 0xcc, 0xee, 0x15, 0xb3, 0xbd, 0x1d, 0xa0,
++	0xe5, 0x9c, 0x1b, 0x24, 0x2c, 0x4d, 0x3c, 0x62,
++	0x35, 0x9c, 0x88, 0x59, 0x09, 0xdd, 0x82, 0x1b,
++	0xcf, 0x0a, 0x83, 0x6b, 0x3f, 0xae, 0x03, 0xc4,
++	0xb4, 0xdd, 0x7e, 0x5b, 0x28, 0x76, 0x25, 0x96,
++	0xd9, 0xc9, 0x9d, 0x5f, 0x86, 0xfa, 0xf6, 0xd7,
++	0xd2, 0xe6, 0x76, 0x1d, 0x0f, 0xa1, 0xdc, 0x74,
++	0x05, 0x1b, 0x1d, 0xe0, 0xcd, 0x16, 0xb0, 0xa8,
++	0x8a, 0x34, 0x7b, 0x15, 0x11, 0x77, 0xe5, 0x7b,
++	0x7e, 0x20, 0xf7, 0xda, 0x38, 0xda, 0xce, 0x70,
++	0xe9, 0xf5, 0x6c, 0xd9, 0xbe, 0x0c, 0x4c, 0x95,
++	0x4c, 0xc2, 0x9b, 0x34, 0x55, 0x55, 0xe1, 0xf3,
++	0x46, 0x8e, 0x48, 0x74, 0x14, 0x4f, 0x9d, 0xc9,
++	0xf5, 0xe8, 0x1a, 0xf0, 0x11, 0x4a, 0xc1, 0x8d,
++	0xe0, 0x93, 0xa0, 0xbe, 0x09, 0x1c, 0x2b, 0x4e,
++	0x0f, 0xb2, 0x87, 0x8b, 0x84, 0xfe, 0x92, 0x32,
++	0x14, 0xd7, 0x93, 0xdf, 0xe7, 0x44, 0xbc, 0xc5,
++	0xae, 0x53, 0x69, 0xd8, 0xb3, 0x79, 0x37, 0x80,
++	0xe3, 0x17, 0x5c, 0xec, 0x53, 0x00, 0x9a, 0xe3,
++	0x8e, 0xdc, 0x38, 0xb8, 0x66, 0xf0, 0xd3, 0xad,
++	0x1d, 0x02, 0x96, 0x86, 0x3e, 0x9d, 0x3b, 0x5d,
++	0xa5, 0x7f, 0x21, 0x10, 0xf1, 0x1f, 0x13, 0x20,
++	0xf9, 0x57, 0x87, 0x20, 0xf5, 0x5f, 0xf1, 0x17,
++	0x48, 0x0a, 0x51, 0x5a, 0xcd, 0x19, 0x03, 0xa6,
++	0x5a, 0xd1, 0x12, 0x97, 0xe9, 0x48, 0xe2, 0x1d,
++	0x83, 0x75, 0x50, 0xd9, 0x75, 0x7d, 0x6a, 0x82,
++	0xa1, 0xf9, 0x4e, 0x54, 0x87, 0x89, 0xc9, 0x0c,
++	0xb7, 0x5b, 0x6a, 0x91, 0xc1, 0x9c, 0xb2, 0xa9,
++	0xdc, 0x9a, 0xa4, 0x49, 0x0a, 0x6d, 0x0d, 0xbb,
++	0xde, 0x86, 0x44, 0xdd, 0x5d, 0x89, 0x2b, 0x96,
++	0x0f, 0x23, 0x95, 0xad, 0xcc, 0xa2, 0xb3, 0xb9,
++	0x7e, 0x74, 0x38, 0xba, 0x9f, 0x73, 0xae, 0x5f,
++	0xf8, 0x68, 0xa2, 0xe0, 0xa9, 0xce, 0xbd, 0x40,
++	0xd4, 0x4c, 0x6b, 0xd2, 0x56, 0x62, 0xb0, 0xcc,
++	0x63, 0x7e, 0x5b, 0xd3, 0xae, 0xd1, 0x75, 0xce,
++	0xbb, 0xb4, 0x5b, 0xa8, 0xf8, 0xb4, 0xac, 0x71,
++	0x75, 0xaa, 0xc9, 0x9f, 0xbb, 0x6c, 0xad, 0x0f,
++	0x55, 0x5d, 0xe8, 0x85, 0x7d, 0xf9, 0x21, 0x35,
++	0xea, 0x92, 0x85, 0x2b, 0x00, 0xec, 0x84, 0x90,
++	0x0a, 0x63, 0x96, 0xe4, 0x6b, 0xa9, 0x77, 0xb8,
++	0x91, 0xf8, 0x46, 0x15, 0x72, 0x63, 0x70, 0x01,
++	0x40, 0xa3, 0xa5, 0x76, 0x62, 0x2b, 0xbf, 0xf1,
++	0xe5, 0x8d, 0x9f, 0xa3, 0xfa, 0x9b, 0x03, 0xbe,
++	0xfe, 0x65, 0x6f, 0xa2, 0x29, 0x0d, 0x54, 0xb4,
++	0x71, 0xce, 0xa9, 0xd6, 0x3d, 0x88, 0xf9, 0xaf,
++	0x6b, 0xa8, 0x9e, 0xf4, 0x16, 0x96, 0x36, 0xb9,
++	0x00, 0xdc, 0x10, 0xab, 0xb5, 0x08, 0x31, 0x1f,
++	0x00, 0xb1, 0x3c, 0xd9, 0x38, 0x3e, 0xc6, 0x04,
++	0xa7, 0x4e, 0xe8, 0xae, 0xed, 0x98, 0xc2, 0xf7,
++	0xb9, 0x00, 0x5f, 0x8c, 0x60, 0xd1, 0xe5, 0x15,
++	0xf7, 0xae, 0x1e, 0x84, 0x88, 0xd1, 0xf6, 0xbc,
++	0x3a, 0x89, 0x35, 0x22, 0x83, 0x7c, 0xca, 0xf0,
++	0x33, 0x82, 0x4c, 0x79, 0x3c, 0xfd, 0xb1, 0xae,
++	0x52, 0x62, 0x55, 0xd2, 0x41, 0x60, 0xc6, 0xbb,
++	0xfa, 0x0e, 0x59, 0xd6, 0xa8, 0xfe, 0x5d, 0xed,
++	0x47, 0x3d, 0xe0, 0xea, 0x1f, 0x6e, 0x43, 0x51,
++	0xec, 0x10, 0x52, 0x56, 0x77, 0x42, 0x6b, 0x52,
++	0x87, 0xd8, 0xec, 0xe0, 0xaa, 0x76, 0xa5, 0x84,
++	0x2a, 0x22, 0x24, 0xfd, 0x92, 0x40, 0x88, 0xd5,
++	0x85, 0x1c, 0x1f, 0x6b, 0x47, 0xa0, 0xc4, 0xe4,
++	0xef, 0xf4, 0xea, 0xd7, 0x59, 0xac, 0x2a, 0x9e,
++	0x8c, 0xfa, 0x1f, 0x42, 0x08, 0xfe, 0x4f, 0x74,
++	0xa0, 0x26, 0xf5, 0xb3, 0x84, 0xf6, 0x58, 0x5f,
++	0x26, 0x66, 0x3e, 0xd7, 0xe4, 0x22, 0x91, 0x13,
++	0xc8, 0xac, 0x25, 0x96, 0x23, 0xd8, 0x09, 0xea,
++	0x45, 0x75, 0x23, 0xb8, 0x5f, 0xc2, 0x90, 0x8b,
++	0x09, 0xc4, 0xfc, 0x47, 0x6c, 0x6d, 0x0a, 0xef,
++	0x69, 0xa4, 0x38, 0x19, 0xcf, 0x7d, 0xf9, 0x09,
++	0x73, 0x9b, 0x60, 0x5a, 0xf7, 0x37, 0xb5, 0xfe,
++	0x9f, 0xe3, 0x2b, 0x4c, 0x0d, 0x6e, 0x19, 0xf1,
++	0xd6, 0xc0, 0x70, 0xf3, 0x9d, 0x22, 0x3c, 0xf9,
++	0x49, 0xce, 0x30, 0x8e, 0x44, 0xb5, 0x76, 0x15,
++	0x8f, 0x52, 0xfd, 0xa5, 0x04, 0xb8, 0x55, 0x6a,
++	0x36, 0x59, 0x7c, 0xc4, 0x48, 0xb8, 0xd7, 0xab,
++	0x05, 0x66, 0xe9, 0x5e, 0x21, 0x6f, 0x6b, 0x36,
++	0x29, 0xbb, 0xe9, 0xe3, 0xa2, 0x9a, 0xa8, 0xcd,
++	0x55, 0x25, 0x11, 0xba, 0x5a, 0x58, 0xa0, 0xde,
++	0xae, 0x19, 0x2a, 0x48, 0x5a, 0xff, 0x36, 0xcd,
++	0x6d, 0x16, 0x7a, 0x73, 0x38, 0x46, 0xe5, 0x47,
++	0x59, 0xc8, 0xa2, 0xf6, 0xe2, 0x6c, 0x83, 0xc5,
++	0x36, 0x2c, 0x83, 0x7d, 0xb4, 0x01, 0x05, 0x69,
++	0xe7, 0xaf, 0x5c, 0xc4, 0x64, 0x82, 0x12, 0x21,
++	0xef, 0xf7, 0xd1, 0x7d, 0xb8, 0x8d, 0x8c, 0x98,
++	0x7c, 0x5f, 0x7d, 0x92, 0x88, 0xb9, 0x94, 0x07,
++	0x9c, 0xd8, 0xe9, 0x9c, 0x17, 0x38, 0xe3, 0x57,
++	0x6c, 0xe0, 0xdc, 0xa5, 0x92, 0x42, 0xb3, 0xbd,
++	0x50, 0xa2, 0x7e, 0xb5, 0xb1, 0x52, 0x72, 0x03,
++	0x97, 0xd8, 0xaa, 0x9a, 0x1e, 0x75, 0x41, 0x11,
++	0xa3, 0x4f, 0xcc, 0xd4, 0xe3, 0x73, 0xad, 0x96,
++	0xdc, 0x47, 0x41, 0x9f, 0xb0, 0xbe, 0x79, 0x91,
++	0xf5, 0xb6, 0x18, 0xfe, 0xc2, 0x83, 0x18, 0x7d,
++	0x73, 0xd9, 0x4f, 0x83, 0x84, 0x03, 0xb3, 0xf0,
++	0x77, 0x66, 0x3d, 0x83, 0x63, 0x2e, 0x2c, 0xf9,
++	0xdd, 0xa6, 0x1f, 0x89, 0x82, 0xb8, 0x23, 0x42,
++	0xeb, 0xe2, 0xca, 0x70, 0x82, 0x61, 0x41, 0x0a,
++	0x6d, 0x5f, 0x75, 0xc5, 0xe2, 0xc4, 0x91, 0x18,
++	0x44, 0x22, 0xfa, 0x34, 0x10, 0xf5, 0x20, 0xdc,
++	0xb7, 0xdd, 0x2a, 0x20, 0x77, 0xf5, 0xf9, 0xce,
++	0xdb, 0xa0, 0x0a, 0x52, 0x2a, 0x4e, 0xdd, 0xcc,
++	0x97, 0xdf, 0x05, 0xe4, 0x5e, 0xb7, 0xaa, 0xf0,
++	0xe2, 0x80, 0xff, 0xba, 0x1a, 0x0f, 0xac, 0xdf,
++	0x02, 0x32, 0xe6, 0xf7, 0xc7, 0x17, 0x13, 0xb7,
++	0xfc, 0x98, 0x48, 0x8c, 0x0d, 0x82, 0xc9, 0x80,
++	0x7a, 0xe2, 0x0a, 0xc5, 0xb4, 0xde, 0x7c, 0x3c,
++	0x79, 0x81, 0x0e, 0x28, 0x65, 0x79, 0x67, 0x82,
++	0x69, 0x44, 0x66, 0x09, 0xf7, 0x16, 0x1a, 0xf9,
++	0x7d, 0x80, 0xa1, 0x79, 0x14, 0xa9, 0xc8, 0x20,
++	0xfb, 0xa2, 0x46, 0xbe, 0x08, 0x35, 0x17, 0x58,
++	0xc1, 0x1a, 0xda, 0x2a, 0x6b, 0x2e, 0x1e, 0xe6,
++	0x27, 0x55, 0x7b, 0x19, 0xe2, 0xfb, 0x64, 0xfc,
++	0x5e, 0x15, 0x54, 0x3c, 0xe7, 0xc2, 0x11, 0x50,
++	0x30, 0xb8, 0x72, 0x03, 0x0b, 0x1a, 0x9f, 0x86,
++	0x27, 0x11, 0x5c, 0x06, 0x2b, 0xbd, 0x75, 0x1a,
++	0x0a, 0xda, 0x01, 0xfa, 0x5c, 0x4a, 0xc1, 0x80,
++	0x3a, 0x6e, 0x30, 0xc8, 0x2c, 0xeb, 0x56, 0xec,
++	0x89, 0xfa, 0x35, 0x7b, 0xb2, 0xf0, 0x97, 0x08,
++	0x86, 0x53, 0xbe, 0xbd, 0x40, 0x41, 0x38, 0x1c,
++	0xb4, 0x8b, 0x79, 0x2e, 0x18, 0x96, 0x94, 0xde,
++	0xe8, 0xca, 0xe5, 0x9f, 0x92, 0x9f, 0x15, 0x5d,
++	0x56, 0x60, 0x5c, 0x09, 0xf9, 0x16, 0xf4, 0x17,
++	0x0f, 0xf6, 0x4c, 0xda, 0xe6, 0x67, 0x89, 0x9f,
++	0xca, 0x6c, 0xe7, 0x9b, 0x04, 0x62, 0x0e, 0x26,
++	0xa6, 0x52, 0xbd, 0x29, 0xff, 0xc7, 0xa4, 0x96,
++	0xe6, 0x6a, 0x02, 0xa5, 0x2e, 0x7b, 0xfe, 0x97,
++	0x68, 0x3e, 0x2e, 0x5f, 0x3b, 0x0f, 0x36, 0xd6,
++	0x98, 0x19, 0x59, 0x48, 0xd2, 0xc6, 0xe1, 0x55,
++	0x1a, 0x6e, 0xd6, 0xed, 0x2c, 0xba, 0xc3, 0x9e,
++	0x64, 0xc9, 0x95, 0x86, 0x35, 0x5e, 0x3e, 0x88,
++	0x69, 0x99, 0x4b, 0xee, 0xbe, 0x9a, 0x99, 0xb5,
++	0x6e, 0x58, 0xae, 0xdd, 0x22, 0xdb, 0xdd, 0x6b,
++	0xfc, 0xaf, 0x90, 0xa3, 0x3d, 0xa4, 0xc1, 0x15,
++	0x92, 0x18, 0x8d, 0xd2, 0x4b, 0x7b, 0x06, 0xd1,
++	0x37, 0xb5, 0xe2, 0x7c, 0x2c, 0xf0, 0x25, 0xe4,
++	0x94, 0x2a, 0xbd, 0xe3, 0x82, 0x70, 0x78, 0xa3,
++	0x82, 0x10, 0x5a, 0x90, 0xd7, 0xa4, 0xfa, 0xaf,
++	0x1a, 0x88, 0x59, 0xdc, 0x74, 0x12, 0xb4, 0x8e,
++	0xd7, 0x19, 0x46, 0xf4, 0x84, 0x69, 0x9f, 0xbb,
++	0x70, 0xa8, 0x4c, 0x52, 0x81, 0xa9, 0xff, 0x76,
++	0x1c, 0xae, 0xd8, 0x11, 0x3d, 0x7f, 0x7d, 0xc5,
++	0x12, 0x59, 0x28, 0x18, 0xc2, 0xa2, 0xb7, 0x1c,
++	0x88, 0xf8, 0xd6, 0x1b, 0xa6, 0x7d, 0x9e, 0xde,
++	0x29, 0xf8, 0xed, 0xff, 0xeb, 0x92, 0x24, 0x4f,
++	0x05, 0xaa, 0xd9, 0x49, 0xba, 0x87, 0x59, 0x51,
++	0xc9, 0x20, 0x5c, 0x9b, 0x74, 0xcf, 0x03, 0xd9,
++	0x2d, 0x34, 0xc7, 0x5b, 0xa5, 0x40, 0xb2, 0x99,
++	0xf5, 0xcb, 0xb4, 0xf6, 0xb7, 0x72, 0x4a, 0xd6,
++	0xbd, 0xb0, 0xf3, 0x93, 0xe0, 0x1b, 0xa8, 0x04,
++	0x1e, 0x35, 0xd4, 0x80, 0x20, 0xf4, 0x9c, 0x31,
++	0x6b, 0x45, 0xb9, 0x15, 0xb0, 0x5e, 0xdd, 0x0a,
++	0x33, 0x9c, 0x83, 0xcd, 0x58, 0x89, 0x50, 0x56,
++	0xbb, 0x81, 0x00, 0x91, 0x32, 0xf3, 0x1b, 0x3e,
++	0xcf, 0x45, 0xe1, 0xf9, 0xe1, 0x2c, 0x26, 0x78,
++	0x93, 0x9a, 0x60, 0x46, 0xc9, 0xb5, 0x5e, 0x6a,
++	0x28, 0x92, 0x87, 0x3f, 0x63, 0x7b, 0xdb, 0xf7,
++	0xd0, 0x13, 0x9d, 0x32, 0x40, 0x5e, 0xcf, 0xfb,
++	0x79, 0x68, 0x47, 0x4c, 0xfd, 0x01, 0x17, 0xe6,
++	0x97, 0x93, 0x78, 0xbb, 0xa6, 0x27, 0xa3, 0xe8,
++	0x1a, 0xe8, 0x94, 0x55, 0x7d, 0x08, 0xe5, 0xdc,
++	0x66, 0xa3, 0x69, 0xc8, 0xca, 0xc5, 0xa1, 0x84,
++	0x55, 0xde, 0x08, 0x91, 0x16, 0x3a, 0x0c, 0x86,
++	0xab, 0x27, 0x2b, 0x64, 0x34, 0x02, 0x6c, 0x76,
++	0x8b, 0xc6, 0xaf, 0xcc, 0xe1, 0xd6, 0x8c, 0x2a,
++	0x18, 0x3d, 0xa6, 0x1b, 0x37, 0x75, 0x45, 0x73,
++	0xc2, 0x75, 0xd7, 0x53, 0x78, 0x3a, 0xd6, 0xe8,
++	0x29, 0xd2, 0x4a, 0xa8, 0x1e, 0x82, 0xf6, 0xb6,
++	0x81, 0xde, 0x21, 0xed, 0x2b, 0x56, 0xbb, 0xf2,
++	0xd0, 0x57, 0xc1, 0x7c, 0xd2, 0x6a, 0xd2, 0x56,
++	0xf5, 0x13, 0x5f, 0x1c, 0x6a, 0x0b, 0x74, 0xfb,
++	0xe9, 0xfe, 0x9e, 0xea, 0x95, 0xb2, 0x46, 0xab,
++	0x0a, 0xfc, 0xfd, 0xf3, 0xbb, 0x04, 0x2b, 0x76,
++	0x1b, 0xa4, 0x74, 0xb0, 0xc1, 0x78, 0xc3, 0x69,
++	0xe2, 0xb0, 0x01, 0xe1, 0xde, 0x32, 0x4c, 0x8d,
++	0x1a, 0xb3, 0x38, 0x08, 0xd5, 0xfc, 0x1f, 0xdc,
++	0x0e, 0x2c, 0x9c, 0xb1, 0xa1, 0x63, 0x17, 0x22,
++	0xf5, 0x6c, 0x93, 0x70, 0x74, 0x00, 0xf8, 0x39,
++	0x01, 0x94, 0xd1, 0x32, 0x23, 0x56, 0x5d, 0xa6,
++	0x02, 0x76, 0x76, 0x93, 0xce, 0x2f, 0x19, 0xe9,
++	0x17, 0x52, 0xae, 0x6e, 0x2c, 0x6d, 0x61, 0x7f,
++	0x3b, 0xaa, 0xe0, 0x52, 0x85, 0xc5, 0x65, 0xc1,
++	0xbb, 0x8e, 0x5b, 0x21, 0xd5, 0xc9, 0x78, 0x83,
++	0x07, 0x97, 0x4c, 0x62, 0x61, 0x41, 0xd4, 0xfc,
++	0xc9, 0x39, 0xe3, 0x9b, 0xd0, 0xcc, 0x75, 0xc4,
++	0x97, 0xe6, 0xdd, 0x2a, 0x5f, 0xa6, 0xe8, 0x59,
++	0x6c, 0x98, 0xb9, 0x02, 0xe2, 0xa2, 0xd6, 0x68,
++	0xee, 0x3b, 0x1d, 0xe3, 0x4d, 0x5b, 0x30, 0xef,
++	0x03, 0xf2, 0xeb, 0x18, 0x57, 0x36, 0xe8, 0xa1,
++	0xf4, 0x47, 0xfb, 0xcb, 0x8f, 0xcb, 0xc8, 0xf3,
++	0x4f, 0x74, 0x9d, 0x9d, 0xb1, 0x8d, 0x14, 0x44,
++	0xd9, 0x19, 0xb4, 0x54, 0x4f, 0x75, 0x19, 0x09,
++	0xa0, 0x75, 0xbc, 0x3b, 0x82, 0xc6, 0x3f, 0xb8,
++	0x83, 0x19, 0x6e, 0xd6, 0x37, 0xfe, 0x6e, 0x8a,
++	0x4e, 0xe0, 0x4a, 0xab, 0x7b, 0xc8, 0xb4, 0x1d,
++	0xf4, 0xed, 0x27, 0x03, 0x65, 0xa2, 0xa1, 0xae,
++	0x11, 0xe7, 0x98, 0x78, 0x48, 0x91, 0xd2, 0xd2,
++	0xd4, 0x23, 0x78, 0x50, 0xb1, 0x5b, 0x85, 0x10,
++	0x8d, 0xca, 0x5f, 0x0f, 0x71, 0xae, 0x72, 0x9a,
++	0xf6, 0x25, 0x19, 0x60, 0x06, 0xf7, 0x10, 0x34,
++	0x18, 0x0d, 0xc9, 0x9f, 0x7b, 0x0c, 0x9b, 0x8f,
++	0x91, 0x1b, 0x9f, 0xcd, 0x10, 0xee, 0x75, 0xf9,
++	0x97, 0x66, 0xfc, 0x4d, 0x33, 0x6e, 0x28, 0x2b,
++	0x92, 0x85, 0x4f, 0xab, 0x43, 0x8d, 0x8f, 0x7d,
++	0x86, 0xa7, 0xc7, 0xd8, 0xd3, 0x0b, 0x8b, 0x57,
++	0xb6, 0x1d, 0x95, 0x0d, 0xe9, 0xbc, 0xd9, 0x03,
++	0xd9, 0x10, 0x19, 0xc3, 0x46, 0x63, 0x55, 0x87,
++	0x61, 0x79, 0x6c, 0x95, 0x0e, 0x9c, 0xdd, 0xca,
++	0xc3, 0xf3, 0x64, 0xf0, 0x7d, 0x76, 0xb7, 0x53,
++	0x67, 0x2b, 0x1e, 0x44, 0x56, 0x81, 0xea, 0x8f,
++	0x5c, 0x42, 0x16, 0xb8, 0x28, 0xeb, 0x1b, 0x61,
++	0x10, 0x1e, 0xbf, 0xec, 0xa8
++};
++static const u8 dec_assoc011[] __initconst = {
++	0xd6, 0x31, 0xda, 0x5d, 0x42, 0x5e, 0xd7
++};
++static const u8 dec_nonce011[] __initconst = {
++	0xfd, 0x87, 0xd4, 0xd8, 0x62, 0xfd, 0xec, 0xaa
++};
++static const u8 dec_key011[] __initconst = {
++	0x35, 0x4e, 0xb5, 0x70, 0x50, 0x42, 0x8a, 0x85,
++	0xf2, 0xfb, 0xed, 0x7b, 0xd0, 0x9e, 0x97, 0xca,
++	0xfa, 0x98, 0x66, 0x63, 0xee, 0x37, 0xcc, 0x52,
++	0xfe, 0xd1, 0xdf, 0x95, 0x15, 0x34, 0x29, 0x38
++};
++
++static const u8 dec_input012[] __initconst = {
++	0x52, 0x34, 0xb3, 0x65, 0x3b, 0xb7, 0xe5, 0xd3,
++	0xab, 0x49, 0x17, 0x60, 0xd2, 0x52, 0x56, 0xdf,
++	0xdf, 0x34, 0x56, 0x82, 0xe2, 0xbe, 0xe5, 0xe1,
++	0x28, 0xd1, 0x4e, 0x5f, 0x4f, 0x01, 0x7d, 0x3f,
++	0x99, 0x6b, 0x30, 0x6e, 0x1a, 0x7c, 0x4c, 0x8e,
++	0x62, 0x81, 0xae, 0x86, 0x3f, 0x6b, 0xd0, 0xb5,
++	0xa9, 0xcf, 0x50, 0xf1, 0x02, 0x12, 0xa0, 0x0b,
++	0x24, 0xe9, 0xe6, 0x72, 0x89, 0x2c, 0x52, 0x1b,
++	0x34, 0x38, 0xf8, 0x75, 0x5f, 0xa0, 0x74, 0xe2,
++	0x99, 0xdd, 0xa6, 0x4b, 0x14, 0x50, 0x4e, 0xf1,
++	0xbe, 0xd6, 0x9e, 0xdb, 0xb2, 0x24, 0x27, 0x74,
++	0x12, 0x4a, 0x78, 0x78, 0x17, 0xa5, 0x58, 0x8e,
++	0x2f, 0xf9, 0xf4, 0x8d, 0xee, 0x03, 0x88, 0xae,
++	0xb8, 0x29, 0xa1, 0x2f, 0x4b, 0xee, 0x92, 0xbd,
++	0x87, 0xb3, 0xce, 0x34, 0x21, 0x57, 0x46, 0x04,
++	0x49, 0x0c, 0x80, 0xf2, 0x01, 0x13, 0xa1, 0x55,
++	0xb3, 0xff, 0x44, 0x30, 0x3c, 0x1c, 0xd0, 0xef,
++	0xbc, 0x18, 0x74, 0x26, 0xad, 0x41, 0x5b, 0x5b,
++	0x3e, 0x9a, 0x7a, 0x46, 0x4f, 0x16, 0xd6, 0x74,
++	0x5a, 0xb7, 0x3a, 0x28, 0x31, 0xd8, 0xae, 0x26,
++	0xac, 0x50, 0x53, 0x86, 0xf2, 0x56, 0xd7, 0x3f,
++	0x29, 0xbc, 0x45, 0x68, 0x8e, 0xcb, 0x98, 0x64,
++	0xdd, 0xc9, 0xba, 0xb8, 0x4b, 0x7b, 0x82, 0xdd,
++	0x14, 0xa7, 0xcb, 0x71, 0x72, 0x00, 0x5c, 0xad,
++	0x7b, 0x6a, 0x89, 0xa4, 0x3d, 0xbf, 0xb5, 0x4b,
++	0x3e, 0x7c, 0x5a, 0xcf, 0xb8, 0xa1, 0xc5, 0x6e,
++	0xc8, 0xb6, 0x31, 0x57, 0x7b, 0xdf, 0xa5, 0x7e,
++	0xb1, 0xd6, 0x42, 0x2a, 0x31, 0x36, 0xd1, 0xd0,
++	0x3f, 0x7a, 0xe5, 0x94, 0xd6, 0x36, 0xa0, 0x6f,
++	0xb7, 0x40, 0x7d, 0x37, 0xc6, 0x55, 0x7c, 0x50,
++	0x40, 0x6d, 0x29, 0x89, 0xe3, 0x5a, 0xae, 0x97,
++	0xe7, 0x44, 0x49, 0x6e, 0xbd, 0x81, 0x3d, 0x03,
++	0x93, 0x06, 0x12, 0x06, 0xe2, 0x41, 0x12, 0x4a,
++	0xf1, 0x6a, 0xa4, 0x58, 0xa2, 0xfb, 0xd2, 0x15,
++	0xba, 0xc9, 0x79, 0xc9, 0xce, 0x5e, 0x13, 0xbb,
++	0xf1, 0x09, 0x04, 0xcc, 0xfd, 0xe8, 0x51, 0x34,
++	0x6a, 0xe8, 0x61, 0x88, 0xda, 0xed, 0x01, 0x47,
++	0x84, 0xf5, 0x73, 0x25, 0xf9, 0x1c, 0x42, 0x86,
++	0x07, 0xf3, 0x5b, 0x1a, 0x01, 0xb3, 0xeb, 0x24,
++	0x32, 0x8d, 0xf6, 0xed, 0x7c, 0x4b, 0xeb, 0x3c,
++	0x36, 0x42, 0x28, 0xdf, 0xdf, 0xb6, 0xbe, 0xd9,
++	0x8c, 0x52, 0xd3, 0x2b, 0x08, 0x90, 0x8c, 0xe7,
++	0x98, 0x31, 0xe2, 0x32, 0x8e, 0xfc, 0x11, 0x48,
++	0x00, 0xa8, 0x6a, 0x42, 0x4a, 0x02, 0xc6, 0x4b,
++	0x09, 0xf1, 0xe3, 0x49, 0xf3, 0x45, 0x1f, 0x0e,
++	0xbc, 0x56, 0xe2, 0xe4, 0xdf, 0xfb, 0xeb, 0x61,
++	0xfa, 0x24, 0xc1, 0x63, 0x75, 0xbb, 0x47, 0x75,
++	0xaf, 0xe1, 0x53, 0x16, 0x96, 0x21, 0x85, 0x26,
++	0x11, 0xb3, 0x76, 0xe3, 0x23, 0xa1, 0x6b, 0x74,
++	0x37, 0xd0, 0xde, 0x06, 0x90, 0x71, 0x5d, 0x43,
++	0x88, 0x9b, 0x00, 0x54, 0xa6, 0x75, 0x2f, 0xa1,
++	0xc2, 0x0b, 0x73, 0x20, 0x1d, 0xb6, 0x21, 0x79,
++	0x57, 0x3f, 0xfa, 0x09, 0xbe, 0x8a, 0x33, 0xc3,
++	0x52, 0xf0, 0x1d, 0x82, 0x31, 0xd1, 0x55, 0xb5,
++	0x6c, 0x99, 0x25, 0xcf, 0x5c, 0x32, 0xce, 0xe9,
++	0x0d, 0xfa, 0x69, 0x2c, 0xd5, 0x0d, 0xc5, 0x6d,
++	0x86, 0xd0, 0x0c, 0x3b, 0x06, 0x50, 0x79, 0xe8,
++	0xc3, 0xae, 0x04, 0xe6, 0xcd, 0x51, 0xe4, 0x26,
++	0x9b, 0x4f, 0x7e, 0xa6, 0x0f, 0xab, 0xd8, 0xe5,
++	0xde, 0xa9, 0x00, 0x95, 0xbe, 0xa3, 0x9d, 0x5d,
++	0xb2, 0x09, 0x70, 0x18, 0x1c, 0xf0, 0xac, 0x29,
++	0x23, 0x02, 0x29, 0x28, 0xd2, 0x74, 0x35, 0x57,
++	0x62, 0x0f, 0x24, 0xea, 0x5e, 0x33, 0xc2, 0x92,
++	0xf3, 0x78, 0x4d, 0x30, 0x1e, 0xa1, 0x99, 0xa9,
++	0x82, 0xb0, 0x42, 0x31, 0x8d, 0xad, 0x8a, 0xbc,
++	0xfc, 0xd4, 0x57, 0x47, 0x3e, 0xb4, 0x50, 0xdd,
++	0x6e, 0x2c, 0x80, 0x4d, 0x22, 0xf1, 0xfb, 0x57,
++	0xc4, 0xdd, 0x17, 0xe1, 0x8a, 0x36, 0x4a, 0xb3,
++	0x37, 0xca, 0xc9, 0x4e, 0xab, 0xd5, 0x69, 0xc4,
++	0xf4, 0xbc, 0x0b, 0x3b, 0x44, 0x4b, 0x29, 0x9c,
++	0xee, 0xd4, 0x35, 0x22, 0x21, 0xb0, 0x1f, 0x27,
++	0x64, 0xa8, 0x51, 0x1b, 0xf0, 0x9f, 0x19, 0x5c,
++	0xfb, 0x5a, 0x64, 0x74, 0x70, 0x45, 0x09, 0xf5,
++	0x64, 0xfe, 0x1a, 0x2d, 0xc9, 0x14, 0x04, 0x14,
++	0xcf, 0xd5, 0x7d, 0x60, 0xaf, 0x94, 0x39, 0x94,
++	0xe2, 0x7d, 0x79, 0x82, 0xd0, 0x65, 0x3b, 0x6b,
++	0x9c, 0x19, 0x84, 0xb4, 0x6d, 0xb3, 0x0c, 0x99,
++	0xc0, 0x56, 0xa8, 0xbd, 0x73, 0xce, 0x05, 0x84,
++	0x3e, 0x30, 0xaa, 0xc4, 0x9b, 0x1b, 0x04, 0x2a,
++	0x9f, 0xd7, 0x43, 0x2b, 0x23, 0xdf, 0xbf, 0xaa,
++	0xd5, 0xc2, 0x43, 0x2d, 0x70, 0xab, 0xdc, 0x75,
++	0xad, 0xac, 0xf7, 0xc0, 0xbe, 0x67, 0xb2, 0x74,
++	0xed, 0x67, 0x10, 0x4a, 0x92, 0x60, 0xc1, 0x40,
++	0x50, 0x19, 0x8a, 0x8a, 0x8c, 0x09, 0x0e, 0x72,
++	0xe1, 0x73, 0x5e, 0xe8, 0x41, 0x85, 0x63, 0x9f,
++	0x3f, 0xd7, 0x7d, 0xc4, 0xfb, 0x22, 0x5d, 0x92,
++	0x6c, 0xb3, 0x1e, 0xe2, 0x50, 0x2f, 0x82, 0xa8,
++	0x28, 0xc0, 0xb5, 0xd7, 0x5f, 0x68, 0x0d, 0x2c,
++	0x2d, 0xaf, 0x7e, 0xfa, 0x2e, 0x08, 0x0f, 0x1f,
++	0x70, 0x9f, 0xe9, 0x19, 0x72, 0x55, 0xf8, 0xfb,
++	0x51, 0xd2, 0x33, 0x5d, 0xa0, 0xd3, 0x2b, 0x0a,
++	0x6c, 0xbc, 0x4e, 0xcf, 0x36, 0x4d, 0xdc, 0x3b,
++	0xe9, 0x3e, 0x81, 0x7c, 0x61, 0xdb, 0x20, 0x2d,
++	0x3a, 0xc3, 0xb3, 0x0c, 0x1e, 0x00, 0xb9, 0x7c,
++	0xf5, 0xca, 0x10, 0x5f, 0x3a, 0x71, 0xb3, 0xe4,
++	0x20, 0xdb, 0x0c, 0x2a, 0x98, 0x63, 0x45, 0x00,
++	0x58, 0xf6, 0x68, 0xe4, 0x0b, 0xda, 0x13, 0x3b,
++	0x60, 0x5c, 0x76, 0xdb, 0xb9, 0x97, 0x71, 0xe4,
++	0xd9, 0xb7, 0xdb, 0xbd, 0x68, 0xc7, 0x84, 0x84,
++	0xaa, 0x7c, 0x68, 0x62, 0x5e, 0x16, 0xfc, 0xba,
++	0x72, 0xaa, 0x9a, 0xa9, 0xeb, 0x7c, 0x75, 0x47,
++	0x97, 0x7e, 0xad, 0xe2, 0xd9, 0x91, 0xe8, 0xe4,
++	0xa5, 0x31, 0xd7, 0x01, 0x8e, 0xa2, 0x11, 0x88,
++	0x95, 0xb9, 0xf2, 0x9b, 0xd3, 0x7f, 0x1b, 0x81,
++	0x22, 0xf7, 0x98, 0x60, 0x0a, 0x64, 0xa6, 0xc1,
++	0xf6, 0x49, 0xc7, 0xe3, 0x07, 0x4d, 0x94, 0x7a,
++	0xcf, 0x6e, 0x68, 0x0c, 0x1b, 0x3f, 0x6e, 0x2e,
++	0xee, 0x92, 0xfa, 0x52, 0xb3, 0x59, 0xf8, 0xf1,
++	0x8f, 0x6a, 0x66, 0xa3, 0x82, 0x76, 0x4a, 0x07,
++	0x1a, 0xc7, 0xdd, 0xf5, 0xda, 0x9c, 0x3c, 0x24,
++	0xbf, 0xfd, 0x42, 0xa1, 0x10, 0x64, 0x6a, 0x0f,
++	0x89, 0xee, 0x36, 0xa5, 0xce, 0x99, 0x48, 0x6a,
++	0xf0, 0x9f, 0x9e, 0x69, 0xa4, 0x40, 0x20, 0xe9,
++	0x16, 0x15, 0xf7, 0xdb, 0x75, 0x02, 0xcb, 0xe9,
++	0x73, 0x8b, 0x3b, 0x49, 0x2f, 0xf0, 0xaf, 0x51,
++	0x06, 0x5c, 0xdf, 0x27, 0x27, 0x49, 0x6a, 0xd1,
++	0xcc, 0xc7, 0xb5, 0x63, 0xb5, 0xfc, 0xb8, 0x5c,
++	0x87, 0x7f, 0x84, 0xb4, 0xcc, 0x14, 0xa9, 0x53,
++	0xda, 0xa4, 0x56, 0xf8, 0xb6, 0x1b, 0xcc, 0x40,
++	0x27, 0x52, 0x06, 0x5a, 0x13, 0x81, 0xd7, 0x3a,
++	0xd4, 0x3b, 0xfb, 0x49, 0x65, 0x31, 0x33, 0xb2,
++	0xfa, 0xcd, 0xad, 0x58, 0x4e, 0x2b, 0xae, 0xd2,
++	0x20, 0xfb, 0x1a, 0x48, 0xb4, 0x3f, 0x9a, 0xd8,
++	0x7a, 0x35, 0x4a, 0xc8, 0xee, 0x88, 0x5e, 0x07,
++	0x66, 0x54, 0xb9, 0xec, 0x9f, 0xa3, 0xe3, 0xb9,
++	0x37, 0xaa, 0x49, 0x76, 0x31, 0xda, 0x74, 0x2d,
++	0x3c, 0xa4, 0x65, 0x10, 0x32, 0x38, 0xf0, 0xde,
++	0xd3, 0x99, 0x17, 0xaa, 0x71, 0xaa, 0x8f, 0x0f,
++	0x8c, 0xaf, 0xa2, 0xf8, 0x5d, 0x64, 0xba, 0x1d,
++	0xa3, 0xef, 0x96, 0x73, 0xe8, 0xa1, 0x02, 0x8d,
++	0x0c, 0x6d, 0xb8, 0x06, 0x90, 0xb8, 0x08, 0x56,
++	0x2c, 0xa7, 0x06, 0xc9, 0xc2, 0x38, 0xdb, 0x7c,
++	0x63, 0xb1, 0x57, 0x8e, 0xea, 0x7c, 0x79, 0xf3,
++	0x49, 0x1d, 0xfe, 0x9f, 0xf3, 0x6e, 0xb1, 0x1d,
++	0xba, 0x19, 0x80, 0x1a, 0x0a, 0xd3, 0xb0, 0x26,
++	0x21, 0x40, 0xb1, 0x7c, 0xf9, 0x4d, 0x8d, 0x10,
++	0xc1, 0x7e, 0xf4, 0xf6, 0x3c, 0xa8, 0xfd, 0x7c,
++	0xa3, 0x92, 0xb2, 0x0f, 0xaa, 0xcc, 0xa6, 0x11,
++	0xfe, 0x04, 0xe3, 0xd1, 0x7a, 0x32, 0x89, 0xdf,
++	0x0d, 0xc4, 0x8f, 0x79, 0x6b, 0xca, 0x16, 0x7c,
++	0x6e, 0xf9, 0xad, 0x0f, 0xf6, 0xfe, 0x27, 0xdb,
++	0xc4, 0x13, 0x70, 0xf1, 0x62, 0x1a, 0x4f, 0x79,
++	0x40, 0xc9, 0x9b, 0x8b, 0x21, 0xea, 0x84, 0xfa,
++	0xf5, 0xf1, 0x89, 0xce, 0xb7, 0x55, 0x0a, 0x80,
++	0x39, 0x2f, 0x55, 0x36, 0x16, 0x9c, 0x7b, 0x08,
++	0xbd, 0x87, 0x0d, 0xa5, 0x32, 0xf1, 0x52, 0x7c,
++	0xe8, 0x55, 0x60, 0x5b, 0xd7, 0x69, 0xe4, 0xfc,
++	0xfa, 0x12, 0x85, 0x96, 0xea, 0x50, 0x28, 0xab,
++	0x8a, 0xf7, 0xbb, 0x0e, 0x53, 0x74, 0xca, 0xa6,
++	0x27, 0x09, 0xc2, 0xb5, 0xde, 0x18, 0x14, 0xd9,
++	0xea, 0xe5, 0x29, 0x1c, 0x40, 0x56, 0xcf, 0xd7,
++	0xae, 0x05, 0x3f, 0x65, 0xaf, 0x05, 0x73, 0xe2,
++	0x35, 0x96, 0x27, 0x07, 0x14, 0xc0, 0xad, 0x33,
++	0xf1, 0xdc, 0x44, 0x7a, 0x89, 0x17, 0x77, 0xd2,
++	0x9c, 0x58, 0x60, 0xf0, 0x3f, 0x7b, 0x2d, 0x2e,
++	0x57, 0x95, 0x54, 0x87, 0xed, 0xf2, 0xc7, 0x4c,
++	0xf0, 0xae, 0x56, 0x29, 0x19, 0x7d, 0x66, 0x4b,
++	0x9b, 0x83, 0x84, 0x42, 0x3b, 0x01, 0x25, 0x66,
++	0x8e, 0x02, 0xde, 0xb9, 0x83, 0x54, 0x19, 0xf6,
++	0x9f, 0x79, 0x0d, 0x67, 0xc5, 0x1d, 0x7a, 0x44,
++	0x02, 0x98, 0xa7, 0x16, 0x1c, 0x29, 0x0d, 0x74,
++	0xff, 0x85, 0x40, 0x06, 0xef, 0x2c, 0xa9, 0xc6,
++	0xf5, 0x53, 0x07, 0x06, 0xae, 0xe4, 0xfa, 0x5f,
++	0xd8, 0x39, 0x4d, 0xf1, 0x9b, 0x6b, 0xd9, 0x24,
++	0x84, 0xfe, 0x03, 0x4c, 0xb2, 0x3f, 0xdf, 0xa1,
++	0x05, 0x9e, 0x50, 0x14, 0x5a, 0xd9, 0x1a, 0xa2,
++	0xa7, 0xfa, 0xfa, 0x17, 0xf7, 0x78, 0xd6, 0xb5,
++	0x92, 0x61, 0x91, 0xac, 0x36, 0xfa, 0x56, 0x0d,
++	0x38, 0x32, 0x18, 0x85, 0x08, 0x58, 0x37, 0xf0,
++	0x4b, 0xdb, 0x59, 0xe7, 0xa4, 0x34, 0xc0, 0x1b,
++	0x01, 0xaf, 0x2d, 0xde, 0xa1, 0xaa, 0x5d, 0xd3,
++	0xec, 0xe1, 0xd4, 0xf7, 0xe6, 0x54, 0x68, 0xf0,
++	0x51, 0x97, 0xa7, 0x89, 0xea, 0x24, 0xad, 0xd3,
++	0x6e, 0x47, 0x93, 0x8b, 0x4b, 0xb4, 0xf7, 0x1c,
++	0x42, 0x06, 0x67, 0xe8, 0x99, 0xf6, 0xf5, 0x7b,
++	0x85, 0xb5, 0x65, 0xb5, 0xb5, 0xd2, 0x37, 0xf5,
++	0xf3, 0x02, 0xa6, 0x4d, 0x11, 0xa7, 0xdc, 0x51,
++	0x09, 0x7f, 0xa0, 0xd8, 0x88, 0x1c, 0x13, 0x71,
++	0xae, 0x9c, 0xb7, 0x7b, 0x34, 0xd6, 0x4e, 0x68,
++	0x26, 0x83, 0x51, 0xaf, 0x1d, 0xee, 0x8b, 0xbb,
++	0x69, 0x43, 0x2b, 0x9e, 0x8a, 0xbc, 0x02, 0x0e,
++	0xa0, 0x1b, 0xe0, 0xa8, 0x5f, 0x6f, 0xaf, 0x1b,
++	0x8f, 0xe7, 0x64, 0x71, 0x74, 0x11, 0x7e, 0xa8,
++	0xd8, 0xf9, 0x97, 0x06, 0xc3, 0xb6, 0xfb, 0xfb,
++	0xb7, 0x3d, 0x35, 0x9d, 0x3b, 0x52, 0xed, 0x54,
++	0xca, 0xf4, 0x81, 0x01, 0x2d, 0x1b, 0xc3, 0xa7,
++	0x00, 0x3d, 0x1a, 0x39, 0x54, 0xe1, 0xf6, 0xff,
++	0xed, 0x6f, 0x0b, 0x5a, 0x68, 0xda, 0x58, 0xdd,
++	0xa9, 0xcf, 0x5c, 0x4a, 0xe5, 0x09, 0x4e, 0xde,
++	0x9d, 0xbc, 0x3e, 0xee, 0x5a, 0x00, 0x3b, 0x2c,
++	0x87, 0x10, 0x65, 0x60, 0xdd, 0xd7, 0x56, 0xd1,
++	0x4c, 0x64, 0x45, 0xe4, 0x21, 0xec, 0x78, 0xf8,
++	0x25, 0x7a, 0x3e, 0x16, 0x5d, 0x09, 0x53, 0x14,
++	0xbe, 0x4f, 0xae, 0x87, 0xd8, 0xd1, 0xaa, 0x3c,
++	0xf6, 0x3e, 0xa4, 0x70, 0x8c, 0x5e, 0x70, 0xa4,
++	0xb3, 0x6b, 0x66, 0x73, 0xd3, 0xbf, 0x31, 0x06,
++	0x19, 0x62, 0x93, 0x15, 0xf2, 0x86, 0xe4, 0x52,
++	0x7e, 0x53, 0x4c, 0x12, 0x38, 0xcc, 0x34, 0x7d,
++	0x57, 0xf6, 0x42, 0x93, 0x8a, 0xc4, 0xee, 0x5c,
++	0x8a, 0xe1, 0x52, 0x8f, 0x56, 0x64, 0xf6, 0xa6,
++	0xd1, 0x91, 0x57, 0x70, 0xcd, 0x11, 0x76, 0xf5,
++	0x59, 0x60, 0x60, 0x3c, 0xc1, 0xc3, 0x0b, 0x7f,
++	0x58, 0x1a, 0x50, 0x91, 0xf1, 0x68, 0x8f, 0x6e,
++	0x74, 0x74, 0xa8, 0x51, 0x0b, 0xf7, 0x7a, 0x98,
++	0x37, 0xf2, 0x0a, 0x0e, 0xa4, 0x97, 0x04, 0xb8,
++	0x9b, 0xfd, 0xa0, 0xea, 0xf7, 0x0d, 0xe1, 0xdb,
++	0x03, 0xf0, 0x31, 0x29, 0xf8, 0xdd, 0x6b, 0x8b,
++	0x5d, 0xd8, 0x59, 0xa9, 0x29, 0xcf, 0x9a, 0x79,
++	0x89, 0x19, 0x63, 0x46, 0x09, 0x79, 0x6a, 0x11,
++	0xda, 0x63, 0x68, 0x48, 0x77, 0x23, 0xfb, 0x7d,
++	0x3a, 0x43, 0xcb, 0x02, 0x3b, 0x7a, 0x6d, 0x10,
++	0x2a, 0x9e, 0xac, 0xf1, 0xd4, 0x19, 0xf8, 0x23,
++	0x64, 0x1d, 0x2c, 0x5f, 0xf2, 0xb0, 0x5c, 0x23,
++	0x27, 0xf7, 0x27, 0x30, 0x16, 0x37, 0xb1, 0x90,
++	0xab, 0x38, 0xfb, 0x55, 0xcd, 0x78, 0x58, 0xd4,
++	0x7d, 0x43, 0xf6, 0x45, 0x5e, 0x55, 0x8d, 0xb1,
++	0x02, 0x65, 0x58, 0xb4, 0x13, 0x4b, 0x36, 0xf7,
++	0xcc, 0xfe, 0x3d, 0x0b, 0x82, 0xe2, 0x12, 0x11,
++	0xbb, 0xe6, 0xb8, 0x3a, 0x48, 0x71, 0xc7, 0x50,
++	0x06, 0x16, 0x3a, 0xe6, 0x7c, 0x05, 0xc7, 0xc8,
++	0x4d, 0x2f, 0x08, 0x6a, 0x17, 0x9a, 0x95, 0x97,
++	0x50, 0x68, 0xdc, 0x28, 0x18, 0xc4, 0x61, 0x38,
++	0xb9, 0xe0, 0x3e, 0x78, 0xdb, 0x29, 0xe0, 0x9f,
++	0x52, 0xdd, 0xf8, 0x4f, 0x91, 0xc1, 0xd0, 0x33,
++	0xa1, 0x7a, 0x8e, 0x30, 0x13, 0x82, 0x07, 0x9f,
++	0xd3, 0x31, 0x0f, 0x23, 0xbe, 0x32, 0x5a, 0x75,
++	0xcf, 0x96, 0xb2, 0xec, 0xb5, 0x32, 0xac, 0x21,
++	0xd1, 0x82, 0x33, 0xd3, 0x15, 0x74, 0xbd, 0x90,
++	0xf1, 0x2c, 0xe6, 0x5f, 0x8d, 0xe3, 0x02, 0xe8,
++	0xe9, 0xc4, 0xca, 0x96, 0xeb, 0x0e, 0xbc, 0x91,
++	0xf4, 0xb9, 0xea, 0xd9, 0x1b, 0x75, 0xbd, 0xe1,
++	0xac, 0x2a, 0x05, 0x37, 0x52, 0x9b, 0x1b, 0x3f,
++	0x5a, 0xdc, 0x21, 0xc3, 0x98, 0xbb, 0xaf, 0xa3,
++	0xf2, 0x00, 0xbf, 0x0d, 0x30, 0x89, 0x05, 0xcc,
++	0xa5, 0x76, 0xf5, 0x06, 0xf0, 0xc6, 0x54, 0x8a,
++	0x5d, 0xd4, 0x1e, 0xc1, 0xf2, 0xce, 0xb0, 0x62,
++	0xc8, 0xfc, 0x59, 0x42, 0x9a, 0x90, 0x60, 0x55,
++	0xfe, 0x88, 0xa5, 0x8b, 0xb8, 0x33, 0x0c, 0x23,
++	0x24, 0x0d, 0x15, 0x70, 0x37, 0x1e, 0x3d, 0xf6,
++	0xd2, 0xea, 0x92, 0x10, 0xb2, 0xc4, 0x51, 0xac,
++	0xf2, 0xac, 0xf3, 0x6b, 0x6c, 0xaa, 0xcf, 0x12,
++	0xc5, 0x6c, 0x90, 0x50, 0xb5, 0x0c, 0xfc, 0x1a,
++	0x15, 0x52, 0xe9, 0x26, 0xc6, 0x52, 0xa4, 0xe7,
++	0x81, 0x69, 0xe1, 0xe7, 0x9e, 0x30, 0x01, 0xec,
++	0x84, 0x89, 0xb2, 0x0d, 0x66, 0xdd, 0xce, 0x28,
++	0x5c, 0xec, 0x98, 0x46, 0x68, 0x21, 0x9f, 0x88,
++	0x3f, 0x1f, 0x42, 0x77, 0xce, 0xd0, 0x61, 0xd4,
++	0x20, 0xa7, 0xff, 0x53, 0xad, 0x37, 0xd0, 0x17,
++	0x35, 0xc9, 0xfc, 0xba, 0x0a, 0x78, 0x3f, 0xf2,
++	0xcc, 0x86, 0x89, 0xe8, 0x4b, 0x3c, 0x48, 0x33,
++	0x09, 0x7f, 0xc6, 0xc0, 0xdd, 0xb8, 0xfd, 0x7a,
++	0x66, 0x66, 0x65, 0xeb, 0x47, 0xa7, 0x04, 0x28,
++	0xa3, 0x19, 0x8e, 0xa9, 0xb1, 0x13, 0x67, 0x62,
++	0x70, 0xcf, 0xd6
++};
++static const u8 dec_output012[] __initconst = {
++	0x74, 0xa6, 0x3e, 0xe4, 0xb1, 0xcb, 0xaf, 0xb0,
++	0x40, 0xe5, 0x0f, 0x9e, 0xf1, 0xf2, 0x89, 0xb5,
++	0x42, 0x34, 0x8a, 0xa1, 0x03, 0xb7, 0xe9, 0x57,
++	0x46, 0xbe, 0x20, 0xe4, 0x6e, 0xb0, 0xeb, 0xff,
++	0xea, 0x07, 0x7e, 0xef, 0xe2, 0x55, 0x9f, 0xe5,
++	0x78, 0x3a, 0xb7, 0x83, 0xc2, 0x18, 0x40, 0x7b,
++	0xeb, 0xcd, 0x81, 0xfb, 0x90, 0x12, 0x9e, 0x46,
++	0xa9, 0xd6, 0x4a, 0xba, 0xb0, 0x62, 0xdb, 0x6b,
++	0x99, 0xc4, 0xdb, 0x54, 0x4b, 0xb8, 0xa5, 0x71,
++	0xcb, 0xcd, 0x63, 0x32, 0x55, 0xfb, 0x31, 0xf0,
++	0x38, 0xf5, 0xbe, 0x78, 0xe4, 0x45, 0xce, 0x1b,
++	0x6a, 0x5b, 0x0e, 0xf4, 0x16, 0xe4, 0xb1, 0x3d,
++	0xf6, 0x63, 0x7b, 0xa7, 0x0c, 0xde, 0x6f, 0x8f,
++	0x74, 0xdf, 0xe0, 0x1e, 0x9d, 0xce, 0x8f, 0x24,
++	0xef, 0x23, 0x35, 0x33, 0x7b, 0x83, 0x34, 0x23,
++	0x58, 0x74, 0x14, 0x77, 0x1f, 0xc2, 0x4f, 0x4e,
++	0xc6, 0x89, 0xf9, 0x52, 0x09, 0x37, 0x64, 0x14,
++	0xc4, 0x01, 0x6b, 0x9d, 0x77, 0xe8, 0x90, 0x5d,
++	0xa8, 0x4a, 0x2a, 0xef, 0x5c, 0x7f, 0xeb, 0xbb,
++	0xb2, 0xc6, 0x93, 0x99, 0x66, 0xdc, 0x7f, 0xd4,
++	0x9e, 0x2a, 0xca, 0x8d, 0xdb, 0xe7, 0x20, 0xcf,
++	0xe4, 0x73, 0xae, 0x49, 0x7d, 0x64, 0x0f, 0x0e,
++	0x28, 0x46, 0xa9, 0xa8, 0x32, 0xe4, 0x0e, 0xf6,
++	0x51, 0x53, 0xb8, 0x3c, 0xb1, 0xff, 0xa3, 0x33,
++	0x41, 0x75, 0xff, 0xf1, 0x6f, 0xf1, 0xfb, 0xbb,
++	0x83, 0x7f, 0x06, 0x9b, 0xe7, 0x1b, 0x0a, 0xe0,
++	0x5c, 0x33, 0x60, 0x5b, 0xdb, 0x5b, 0xed, 0xfe,
++	0xa5, 0x16, 0x19, 0x72, 0xa3, 0x64, 0x23, 0x00,
++	0x02, 0xc7, 0xf3, 0x6a, 0x81, 0x3e, 0x44, 0x1d,
++	0x79, 0x15, 0x5f, 0x9a, 0xde, 0xe2, 0xfd, 0x1b,
++	0x73, 0xc1, 0xbc, 0x23, 0xba, 0x31, 0xd2, 0x50,
++	0xd5, 0xad, 0x7f, 0x74, 0xa7, 0xc9, 0xf8, 0x3e,
++	0x2b, 0x26, 0x10, 0xf6, 0x03, 0x36, 0x74, 0xe4,
++	0x0e, 0x6a, 0x72, 0xb7, 0x73, 0x0a, 0x42, 0x28,
++	0xc2, 0xad, 0x5e, 0x03, 0xbe, 0xb8, 0x0b, 0xa8,
++	0x5b, 0xd4, 0xb8, 0xba, 0x52, 0x89, 0xb1, 0x9b,
++	0xc1, 0xc3, 0x65, 0x87, 0xed, 0xa5, 0xf4, 0x86,
++	0xfd, 0x41, 0x80, 0x91, 0x27, 0x59, 0x53, 0x67,
++	0x15, 0x78, 0x54, 0x8b, 0x2d, 0x3d, 0xc7, 0xff,
++	0x02, 0x92, 0x07, 0x5f, 0x7a, 0x4b, 0x60, 0x59,
++	0x3c, 0x6f, 0x5c, 0xd8, 0xec, 0x95, 0xd2, 0xfe,
++	0xa0, 0x3b, 0xd8, 0x3f, 0xd1, 0x69, 0xa6, 0xd6,
++	0x41, 0xb2, 0xf4, 0x4d, 0x12, 0xf4, 0x58, 0x3e,
++	0x66, 0x64, 0x80, 0x31, 0x9b, 0xa8, 0x4c, 0x8b,
++	0x07, 0xb2, 0xec, 0x66, 0x94, 0x66, 0x47, 0x50,
++	0x50, 0x5f, 0x18, 0x0b, 0x0e, 0xd6, 0xc0, 0x39,
++	0x21, 0x13, 0x9e, 0x33, 0xbc, 0x79, 0x36, 0x02,
++	0x96, 0x70, 0xf0, 0x48, 0x67, 0x2f, 0x26, 0xe9,
++	0x6d, 0x10, 0xbb, 0xd6, 0x3f, 0xd1, 0x64, 0x7a,
++	0x2e, 0xbe, 0x0c, 0x61, 0xf0, 0x75, 0x42, 0x38,
++	0x23, 0xb1, 0x9e, 0x9f, 0x7c, 0x67, 0x66, 0xd9,
++	0x58, 0x9a, 0xf1, 0xbb, 0x41, 0x2a, 0x8d, 0x65,
++	0x84, 0x94, 0xfc, 0xdc, 0x6a, 0x50, 0x64, 0xdb,
++	0x56, 0x33, 0x76, 0x00, 0x10, 0xed, 0xbe, 0xd2,
++	0x12, 0xf6, 0xf6, 0x1b, 0xa2, 0x16, 0xde, 0xae,
++	0x31, 0x95, 0xdd, 0xb1, 0x08, 0x7e, 0x4e, 0xee,
++	0xe7, 0xf9, 0xa5, 0xfb, 0x5b, 0x61, 0x43, 0x00,
++	0x40, 0xf6, 0x7e, 0x02, 0x04, 0x32, 0x4e, 0x0c,
++	0xe2, 0x66, 0x0d, 0xd7, 0x07, 0x98, 0x0e, 0xf8,
++	0x72, 0x34, 0x6d, 0x95, 0x86, 0xd7, 0xcb, 0x31,
++	0x54, 0x47, 0xd0, 0x38, 0x29, 0x9c, 0x5a, 0x68,
++	0xd4, 0x87, 0x76, 0xc9, 0xe7, 0x7e, 0xe3, 0xf4,
++	0x81, 0x6d, 0x18, 0xcb, 0xc9, 0x05, 0xaf, 0xa0,
++	0xfb, 0x66, 0xf7, 0xf1, 0x1c, 0xc6, 0x14, 0x11,
++	0x4f, 0x2b, 0x79, 0x42, 0x8b, 0xbc, 0xac, 0xe7,
++	0x6c, 0xfe, 0x0f, 0x58, 0xe7, 0x7c, 0x78, 0x39,
++	0x30, 0xb0, 0x66, 0x2c, 0x9b, 0x6d, 0x3a, 0xe1,
++	0xcf, 0xc9, 0xa4, 0x0e, 0x6d, 0x6d, 0x8a, 0xa1,
++	0x3a, 0xe7, 0x28, 0xd4, 0x78, 0x4c, 0xa6, 0xa2,
++	0x2a, 0xa6, 0x03, 0x30, 0xd7, 0xa8, 0x25, 0x66,
++	0x87, 0x2f, 0x69, 0x5c, 0x4e, 0xdd, 0xa5, 0x49,
++	0x5d, 0x37, 0x4a, 0x59, 0xc4, 0xaf, 0x1f, 0xa2,
++	0xe4, 0xf8, 0xa6, 0x12, 0x97, 0xd5, 0x79, 0xf5,
++	0xe2, 0x4a, 0x2b, 0x5f, 0x61, 0xe4, 0x9e, 0xe3,
++	0xee, 0xb8, 0xa7, 0x5b, 0x2f, 0xf4, 0x9e, 0x6c,
++	0xfb, 0xd1, 0xc6, 0x56, 0x77, 0xba, 0x75, 0xaa,
++	0x3d, 0x1a, 0xa8, 0x0b, 0xb3, 0x68, 0x24, 0x00,
++	0x10, 0x7f, 0xfd, 0xd7, 0xa1, 0x8d, 0x83, 0x54,
++	0x4f, 0x1f, 0xd8, 0x2a, 0xbe, 0x8a, 0x0c, 0x87,
++	0xab, 0xa2, 0xde, 0xc3, 0x39, 0xbf, 0x09, 0x03,
++	0xa5, 0xf3, 0x05, 0x28, 0xe1, 0xe1, 0xee, 0x39,
++	0x70, 0x9c, 0xd8, 0x81, 0x12, 0x1e, 0x02, 0x40,
++	0xd2, 0x6e, 0xf0, 0xeb, 0x1b, 0x3d, 0x22, 0xc6,
++	0xe5, 0xe3, 0xb4, 0x5a, 0x98, 0xbb, 0xf0, 0x22,
++	0x28, 0x8d, 0xe5, 0xd3, 0x16, 0x48, 0x24, 0xa5,
++	0xe6, 0x66, 0x0c, 0xf9, 0x08, 0xf9, 0x7e, 0x1e,
++	0xe1, 0x28, 0x26, 0x22, 0xc7, 0xc7, 0x0a, 0x32,
++	0x47, 0xfa, 0xa3, 0xbe, 0x3c, 0xc4, 0xc5, 0x53,
++	0x0a, 0xd5, 0x94, 0x4a, 0xd7, 0x93, 0xd8, 0x42,
++	0x99, 0xb9, 0x0a, 0xdb, 0x56, 0xf7, 0xb9, 0x1c,
++	0x53, 0x4f, 0xfa, 0xd3, 0x74, 0xad, 0xd9, 0x68,
++	0xf1, 0x1b, 0xdf, 0x61, 0xc6, 0x5e, 0xa8, 0x48,
++	0xfc, 0xd4, 0x4a, 0x4c, 0x3c, 0x32, 0xf7, 0x1c,
++	0x96, 0x21, 0x9b, 0xf9, 0xa3, 0xcc, 0x5a, 0xce,
++	0xd5, 0xd7, 0x08, 0x24, 0xf6, 0x1c, 0xfd, 0xdd,
++	0x38, 0xc2, 0x32, 0xe9, 0xb8, 0xe7, 0xb6, 0xfa,
++	0x9d, 0x45, 0x13, 0x2c, 0x83, 0xfd, 0x4a, 0x69,
++	0x82, 0xcd, 0xdc, 0xb3, 0x76, 0x0c, 0x9e, 0xd8,
++	0xf4, 0x1b, 0x45, 0x15, 0xb4, 0x97, 0xe7, 0x58,
++	0x34, 0xe2, 0x03, 0x29, 0x5a, 0xbf, 0xb6, 0xe0,
++	0x5d, 0x13, 0xd9, 0x2b, 0xb4, 0x80, 0xb2, 0x45,
++	0x81, 0x6a, 0x2e, 0x6c, 0x89, 0x7d, 0xee, 0xbb,
++	0x52, 0xdd, 0x1f, 0x18, 0xe7, 0x13, 0x6b, 0x33,
++	0x0e, 0xea, 0x36, 0x92, 0x77, 0x7b, 0x6d, 0x9c,
++	0x5a, 0x5f, 0x45, 0x7b, 0x7b, 0x35, 0x62, 0x23,
++	0xd1, 0xbf, 0x0f, 0xd0, 0x08, 0x1b, 0x2b, 0x80,
++	0x6b, 0x7e, 0xf1, 0x21, 0x47, 0xb0, 0x57, 0xd1,
++	0x98, 0x72, 0x90, 0x34, 0x1c, 0x20, 0x04, 0xff,
++	0x3d, 0x5c, 0xee, 0x0e, 0x57, 0x5f, 0x6f, 0x24,
++	0x4e, 0x3c, 0xea, 0xfc, 0xa5, 0xa9, 0x83, 0xc9,
++	0x61, 0xb4, 0x51, 0x24, 0xf8, 0x27, 0x5e, 0x46,
++	0x8c, 0xb1, 0x53, 0x02, 0x96, 0x35, 0xba, 0xb8,
++	0x4c, 0x71, 0xd3, 0x15, 0x59, 0x35, 0x22, 0x20,
++	0xad, 0x03, 0x9f, 0x66, 0x44, 0x3b, 0x9c, 0x35,
++	0x37, 0x1f, 0x9b, 0xbb, 0xf3, 0xdb, 0x35, 0x63,
++	0x30, 0x64, 0xaa, 0xa2, 0x06, 0xa8, 0x5d, 0xbb,
++	0xe1, 0x9f, 0x70, 0xec, 0x82, 0x11, 0x06, 0x36,
++	0xec, 0x8b, 0x69, 0x66, 0x24, 0x44, 0xc9, 0x4a,
++	0x57, 0xbb, 0x9b, 0x78, 0x13, 0xce, 0x9c, 0x0c,
++	0xba, 0x92, 0x93, 0x63, 0xb8, 0xe2, 0x95, 0x0f,
++	0x0f, 0x16, 0x39, 0x52, 0xfd, 0x3a, 0x6d, 0x02,
++	0x4b, 0xdf, 0x13, 0xd3, 0x2a, 0x22, 0xb4, 0x03,
++	0x7c, 0x54, 0x49, 0x96, 0x68, 0x54, 0x10, 0xfa,
++	0xef, 0xaa, 0x6c, 0xe8, 0x22, 0xdc, 0x71, 0x16,
++	0x13, 0x1a, 0xf6, 0x28, 0xe5, 0x6d, 0x77, 0x3d,
++	0xcd, 0x30, 0x63, 0xb1, 0x70, 0x52, 0xa1, 0xc5,
++	0x94, 0x5f, 0xcf, 0xe8, 0xb8, 0x26, 0x98, 0xf7,
++	0x06, 0xa0, 0x0a, 0x70, 0xfa, 0x03, 0x80, 0xac,
++	0xc1, 0xec, 0xd6, 0x4c, 0x54, 0xd7, 0xfe, 0x47,
++	0xb6, 0x88, 0x4a, 0xf7, 0x71, 0x24, 0xee, 0xf3,
++	0xd2, 0xc2, 0x4a, 0x7f, 0xfe, 0x61, 0xc7, 0x35,
++	0xc9, 0x37, 0x67, 0xcb, 0x24, 0x35, 0xda, 0x7e,
++	0xca, 0x5f, 0xf3, 0x8d, 0xd4, 0x13, 0x8e, 0xd6,
++	0xcb, 0x4d, 0x53, 0x8f, 0x53, 0x1f, 0xc0, 0x74,
++	0xf7, 0x53, 0xb9, 0x5e, 0x23, 0x37, 0xba, 0x6e,
++	0xe3, 0x9d, 0x07, 0x55, 0x25, 0x7b, 0xe6, 0x2a,
++	0x64, 0xd1, 0x32, 0xdd, 0x54, 0x1b, 0x4b, 0xc0,
++	0xe1, 0xd7, 0x69, 0x58, 0xf8, 0x93, 0x29, 0xc4,
++	0xdd, 0x23, 0x2f, 0xa5, 0xfc, 0x9d, 0x7e, 0xf8,
++	0xd4, 0x90, 0xcd, 0x82, 0x55, 0xdc, 0x16, 0x16,
++	0x9f, 0x07, 0x52, 0x9b, 0x9d, 0x25, 0xed, 0x32,
++	0xc5, 0x7b, 0xdf, 0xf6, 0x83, 0x46, 0x3d, 0x65,
++	0xb7, 0xef, 0x87, 0x7a, 0x12, 0x69, 0x8f, 0x06,
++	0x7c, 0x51, 0x15, 0x4a, 0x08, 0xe8, 0xac, 0x9a,
++	0x0c, 0x24, 0xa7, 0x27, 0xd8, 0x46, 0x2f, 0xe7,
++	0x01, 0x0e, 0x1c, 0xc6, 0x91, 0xb0, 0x6e, 0x85,
++	0x65, 0xf0, 0x29, 0x0d, 0x2e, 0x6b, 0x3b, 0xfb,
++	0x4b, 0xdf, 0xe4, 0x80, 0x93, 0x03, 0x66, 0x46,
++	0x3e, 0x8a, 0x6e, 0xf3, 0x5e, 0x4d, 0x62, 0x0e,
++	0x49, 0x05, 0xaf, 0xd4, 0xf8, 0x21, 0x20, 0x61,
++	0x1d, 0x39, 0x17, 0xf4, 0x61, 0x47, 0x95, 0xfb,
++	0x15, 0x2e, 0xb3, 0x4f, 0xd0, 0x5d, 0xf5, 0x7d,
++	0x40, 0xda, 0x90, 0x3c, 0x6b, 0xcb, 0x17, 0x00,
++	0x13, 0x3b, 0x64, 0x34, 0x1b, 0xf0, 0xf2, 0xe5,
++	0x3b, 0xb2, 0xc7, 0xd3, 0x5f, 0x3a, 0x44, 0xa6,
++	0x9b, 0xb7, 0x78, 0x0e, 0x42, 0x5d, 0x4c, 0xc1,
++	0xe9, 0xd2, 0xcb, 0xb7, 0x78, 0xd1, 0xfe, 0x9a,
++	0xb5, 0x07, 0xe9, 0xe0, 0xbe, 0xe2, 0x8a, 0xa7,
++	0x01, 0x83, 0x00, 0x8c, 0x5c, 0x08, 0xe6, 0x63,
++	0x12, 0x92, 0xb7, 0xb7, 0xa6, 0x19, 0x7d, 0x38,
++	0x13, 0x38, 0x92, 0x87, 0x24, 0xf9, 0x48, 0xb3,
++	0x5e, 0x87, 0x6a, 0x40, 0x39, 0x5c, 0x3f, 0xed,
++	0x8f, 0xee, 0xdb, 0x15, 0x82, 0x06, 0xda, 0x49,
++	0x21, 0x2b, 0xb5, 0xbf, 0x32, 0x7c, 0x9f, 0x42,
++	0x28, 0x63, 0xcf, 0xaf, 0x1e, 0xf8, 0xc6, 0xa0,
++	0xd1, 0x02, 0x43, 0x57, 0x62, 0xec, 0x9b, 0x0f,
++	0x01, 0x9e, 0x71, 0xd8, 0x87, 0x9d, 0x01, 0xc1,
++	0x58, 0x77, 0xd9, 0xaf, 0xb1, 0x10, 0x7e, 0xdd,
++	0xa6, 0x50, 0x96, 0xe5, 0xf0, 0x72, 0x00, 0x6d,
++	0x4b, 0xf8, 0x2a, 0x8f, 0x19, 0xf3, 0x22, 0x88,
++	0x11, 0x4a, 0x8b, 0x7c, 0xfd, 0xb7, 0xed, 0xe1,
++	0xf6, 0x40, 0x39, 0xe0, 0xe9, 0xf6, 0x3d, 0x25,
++	0xe6, 0x74, 0x3c, 0x58, 0x57, 0x7f, 0xe1, 0x22,
++	0x96, 0x47, 0x31, 0x91, 0xba, 0x70, 0x85, 0x28,
++	0x6b, 0x9f, 0x6e, 0x25, 0xac, 0x23, 0x66, 0x2f,
++	0x29, 0x88, 0x28, 0xce, 0x8c, 0x5c, 0x88, 0x53,
++	0xd1, 0x3b, 0xcc, 0x6a, 0x51, 0xb2, 0xe1, 0x28,
++	0x3f, 0x91, 0xb4, 0x0d, 0x00, 0x3a, 0xe3, 0xf8,
++	0xc3, 0x8f, 0xd7, 0x96, 0x62, 0x0e, 0x2e, 0xfc,
++	0xc8, 0x6c, 0x77, 0xa6, 0x1d, 0x22, 0xc1, 0xb8,
++	0xe6, 0x61, 0xd7, 0x67, 0x36, 0x13, 0x7b, 0xbb,
++	0x9b, 0x59, 0x09, 0xa6, 0xdf, 0xf7, 0x6b, 0xa3,
++	0x40, 0x1a, 0xf5, 0x4f, 0xb4, 0xda, 0xd3, 0xf3,
++	0x81, 0x93, 0xc6, 0x18, 0xd9, 0x26, 0xee, 0xac,
++	0xf0, 0xaa, 0xdf, 0xc5, 0x9c, 0xca, 0xc2, 0xa2,
++	0xcc, 0x7b, 0x5c, 0x24, 0xb0, 0xbc, 0xd0, 0x6a,
++	0x4d, 0x89, 0x09, 0xb8, 0x07, 0xfe, 0x87, 0xad,
++	0x0a, 0xea, 0xb8, 0x42, 0xf9, 0x5e, 0xb3, 0x3e,
++	0x36, 0x4c, 0xaf, 0x75, 0x9e, 0x1c, 0xeb, 0xbd,
++	0xbc, 0xbb, 0x80, 0x40, 0xa7, 0x3a, 0x30, 0xbf,
++	0xa8, 0x44, 0xf4, 0xeb, 0x38, 0xad, 0x29, 0xba,
++	0x23, 0xed, 0x41, 0x0c, 0xea, 0xd2, 0xbb, 0x41,
++	0x18, 0xd6, 0xb9, 0xba, 0x65, 0x2b, 0xa3, 0x91,
++	0x6d, 0x1f, 0xa9, 0xf4, 0xd1, 0x25, 0x8d, 0x4d,
++	0x38, 0xff, 0x64, 0xa0, 0xec, 0xde, 0xa6, 0xb6,
++	0x79, 0xab, 0x8e, 0x33, 0x6c, 0x47, 0xde, 0xaf,
++	0x94, 0xa4, 0xa5, 0x86, 0x77, 0x55, 0x09, 0x92,
++	0x81, 0x31, 0x76, 0xc7, 0x34, 0x22, 0x89, 0x8e,
++	0x3d, 0x26, 0x26, 0xd7, 0xfc, 0x1e, 0x16, 0x72,
++	0x13, 0x33, 0x63, 0xd5, 0x22, 0xbe, 0xb8, 0x04,
++	0x34, 0x84, 0x41, 0xbb, 0x80, 0xd0, 0x9f, 0x46,
++	0x48, 0x07, 0xa7, 0xfc, 0x2b, 0x3a, 0x75, 0x55,
++	0x8c, 0xc7, 0x6a, 0xbd, 0x7e, 0x46, 0x08, 0x84,
++	0x0f, 0xd5, 0x74, 0xc0, 0x82, 0x8e, 0xaa, 0x61,
++	0x05, 0x01, 0xb2, 0x47, 0x6e, 0x20, 0x6a, 0x2d,
++	0x58, 0x70, 0x48, 0x32, 0xa7, 0x37, 0xd2, 0xb8,
++	0x82, 0x1a, 0x51, 0xb9, 0x61, 0xdd, 0xfd, 0x9d,
++	0x6b, 0x0e, 0x18, 0x97, 0xf8, 0x45, 0x5f, 0x87,
++	0x10, 0xcf, 0x34, 0x72, 0x45, 0x26, 0x49, 0x70,
++	0xe7, 0xa3, 0x78, 0xe0, 0x52, 0x89, 0x84, 0x94,
++	0x83, 0x82, 0xc2, 0x69, 0x8f, 0xe3, 0xe1, 0x3f,
++	0x60, 0x74, 0x88, 0xc4, 0xf7, 0x75, 0x2c, 0xfb,
++	0xbd, 0xb6, 0xc4, 0x7e, 0x10, 0x0a, 0x6c, 0x90,
++	0x04, 0x9e, 0xc3, 0x3f, 0x59, 0x7c, 0xce, 0x31,
++	0x18, 0x60, 0x57, 0x73, 0x46, 0x94, 0x7d, 0x06,
++	0xa0, 0x6d, 0x44, 0xec, 0xa2, 0x0a, 0x9e, 0x05,
++	0x15, 0xef, 0xca, 0x5c, 0xbf, 0x00, 0xeb, 0xf7,
++	0x3d, 0x32, 0xd4, 0xa5, 0xef, 0x49, 0x89, 0x5e,
++	0x46, 0xb0, 0xa6, 0x63, 0x5b, 0x8a, 0x73, 0xae,
++	0x6f, 0xd5, 0x9d, 0xf8, 0x4f, 0x40, 0xb5, 0xb2,
++	0x6e, 0xd3, 0xb6, 0x01, 0xa9, 0x26, 0xa2, 0x21,
++	0xcf, 0x33, 0x7a, 0x3a, 0xa4, 0x23, 0x13, 0xb0,
++	0x69, 0x6a, 0xee, 0xce, 0xd8, 0x9d, 0x01, 0x1d,
++	0x50, 0xc1, 0x30, 0x6c, 0xb1, 0xcd, 0xa0, 0xf0,
++	0xf0, 0xa2, 0x64, 0x6f, 0xbb, 0xbf, 0x5e, 0xe6,
++	0xab, 0x87, 0xb4, 0x0f, 0x4f, 0x15, 0xaf, 0xb5,
++	0x25, 0xa1, 0xb2, 0xd0, 0x80, 0x2c, 0xfb, 0xf9,
++	0xfe, 0xd2, 0x33, 0xbb, 0x76, 0xfe, 0x7c, 0xa8,
++	0x66, 0xf7, 0xe7, 0x85, 0x9f, 0x1f, 0x85, 0x57,
++	0x88, 0xe1, 0xe9, 0x63, 0xe4, 0xd8, 0x1c, 0xa1,
++	0xfb, 0xda, 0x44, 0x05, 0x2e, 0x1d, 0x3a, 0x1c,
++	0xff, 0xc8, 0x3b, 0xc0, 0xfe, 0xda, 0x22, 0x0b,
++	0x43, 0xd6, 0x88, 0x39, 0x4c, 0x4a, 0xa6, 0x69,
++	0x18, 0x93, 0x42, 0x4e, 0xb5, 0xcc, 0x66, 0x0d,
++	0x09, 0xf8, 0x1e, 0x7c, 0xd3, 0x3c, 0x99, 0x0d,
++	0x50, 0x1d, 0x62, 0xe9, 0x57, 0x06, 0xbf, 0x19,
++	0x88, 0xdd, 0xad, 0x7b, 0x4f, 0xf9, 0xc7, 0x82,
++	0x6d, 0x8d, 0xc8, 0xc4, 0xc5, 0x78, 0x17, 0x20,
++	0x15, 0xc5, 0x52, 0x41, 0xcf, 0x5b, 0xd6, 0x7f,
++	0x94, 0x02, 0x41, 0xe0, 0x40, 0x22, 0x03, 0x5e,
++	0xd1, 0x53, 0xd4, 0x86, 0xd3, 0x2c, 0x9f, 0x0f,
++	0x96, 0xe3, 0x6b, 0x9a, 0x76, 0x32, 0x06, 0x47,
++	0x4b, 0x11, 0xb3, 0xdd, 0x03, 0x65, 0xbd, 0x9b,
++	0x01, 0xda, 0x9c, 0xb9, 0x7e, 0x3f, 0x6a, 0xc4,
++	0x7b, 0xea, 0xd4, 0x3c, 0xb9, 0xfb, 0x5c, 0x6b,
++	0x64, 0x33, 0x52, 0xba, 0x64, 0x78, 0x8f, 0xa4,
++	0xaf, 0x7a, 0x61, 0x8d, 0xbc, 0xc5, 0x73, 0xe9,
++	0x6b, 0x58, 0x97, 0x4b, 0xbf, 0x63, 0x22, 0xd3,
++	0x37, 0x02, 0x54, 0xc5, 0xb9, 0x16, 0x4a, 0xf0,
++	0x19, 0xd8, 0x94, 0x57, 0xb8, 0x8a, 0xb3, 0x16,
++	0x3b, 0xd0, 0x84, 0x8e, 0x67, 0xa6, 0xa3, 0x7d,
++	0x78, 0xec, 0x00
++};
++static const u8 dec_assoc012[] __initconst = {
++	0xb1, 0x69, 0x83, 0x87, 0x30, 0xaa, 0x5d, 0xb8,
++	0x77, 0xe8, 0x21, 0xff, 0x06, 0x59, 0x35, 0xce,
++	0x75, 0xfe, 0x38, 0xef, 0xb8, 0x91, 0x43, 0x8c,
++	0xcf, 0x70, 0xdd, 0x0a, 0x68, 0xbf, 0xd4, 0xbc,
++	0x16, 0x76, 0x99, 0x36, 0x1e, 0x58, 0x79, 0x5e,
++	0xd4, 0x29, 0xf7, 0x33, 0x93, 0x48, 0xdb, 0x5f,
++	0x01, 0xae, 0x9c, 0xb6, 0xe4, 0x88, 0x6d, 0x2b,
++	0x76, 0x75, 0xe0, 0xf3, 0x74, 0xe2, 0xc9
++};
++static const u8 dec_nonce012[] __initconst = {
++	0x05, 0xa3, 0x93, 0xed, 0x30, 0xc5, 0xa2, 0x06
++};
++static const u8 dec_key012[] __initconst = {
++	0xb3, 0x35, 0x50, 0x03, 0x54, 0x2e, 0x40, 0x5e,
++	0x8f, 0x59, 0x8e, 0xc5, 0x90, 0xd5, 0x27, 0x2d,
++	0xba, 0x29, 0x2e, 0xcb, 0x1b, 0x70, 0x44, 0x1e,
++	0x65, 0x91, 0x6e, 0x2a, 0x79, 0x22, 0xda, 0x64
++};
++
++static const u8 dec_input013[] __initconst = {
++	0x52, 0x34, 0xb3, 0x65, 0x3b, 0xb7, 0xe5, 0xd3,
++	0xab, 0x49, 0x17, 0x60, 0xd2, 0x52, 0x56, 0xdf,
++	0xdf, 0x34, 0x56, 0x82, 0xe2, 0xbe, 0xe5, 0xe1,
++	0x28, 0xd1, 0x4e, 0x5f, 0x4f, 0x01, 0x7d, 0x3f,
++	0x99, 0x6b, 0x30, 0x6e, 0x1a, 0x7c, 0x4c, 0x8e,
++	0x62, 0x81, 0xae, 0x86, 0x3f, 0x6b, 0xd0, 0xb5,
++	0xa9, 0xcf, 0x50, 0xf1, 0x02, 0x12, 0xa0, 0x0b,
++	0x24, 0xe9, 0xe6, 0x72, 0x89, 0x2c, 0x52, 0x1b,
++	0x34, 0x38, 0xf8, 0x75, 0x5f, 0xa0, 0x74, 0xe2,
++	0x99, 0xdd, 0xa6, 0x4b, 0x14, 0x50, 0x4e, 0xf1,
++	0xbe, 0xd6, 0x9e, 0xdb, 0xb2, 0x24, 0x27, 0x74,
++	0x12, 0x4a, 0x78, 0x78, 0x17, 0xa5, 0x58, 0x8e,
++	0x2f, 0xf9, 0xf4, 0x8d, 0xee, 0x03, 0x88, 0xae,
++	0xb8, 0x29, 0xa1, 0x2f, 0x4b, 0xee, 0x92, 0xbd,
++	0x87, 0xb3, 0xce, 0x34, 0x21, 0x57, 0x46, 0x04,
++	0x49, 0x0c, 0x80, 0xf2, 0x01, 0x13, 0xa1, 0x55,
++	0xb3, 0xff, 0x44, 0x30, 0x3c, 0x1c, 0xd0, 0xef,
++	0xbc, 0x18, 0x74, 0x26, 0xad, 0x41, 0x5b, 0x5b,
++	0x3e, 0x9a, 0x7a, 0x46, 0x4f, 0x16, 0xd6, 0x74,
++	0x5a, 0xb7, 0x3a, 0x28, 0x31, 0xd8, 0xae, 0x26,
++	0xac, 0x50, 0x53, 0x86, 0xf2, 0x56, 0xd7, 0x3f,
++	0x29, 0xbc, 0x45, 0x68, 0x8e, 0xcb, 0x98, 0x64,
++	0xdd, 0xc9, 0xba, 0xb8, 0x4b, 0x7b, 0x82, 0xdd,
++	0x14, 0xa7, 0xcb, 0x71, 0x72, 0x00, 0x5c, 0xad,
++	0x7b, 0x6a, 0x89, 0xa4, 0x3d, 0xbf, 0xb5, 0x4b,
++	0x3e, 0x7c, 0x5a, 0xcf, 0xb8, 0xa1, 0xc5, 0x6e,
++	0xc8, 0xb6, 0x31, 0x57, 0x7b, 0xdf, 0xa5, 0x7e,
++	0xb1, 0xd6, 0x42, 0x2a, 0x31, 0x36, 0xd1, 0xd0,
++	0x3f, 0x7a, 0xe5, 0x94, 0xd6, 0x36, 0xa0, 0x6f,
++	0xb7, 0x40, 0x7d, 0x37, 0xc6, 0x55, 0x7c, 0x50,
++	0x40, 0x6d, 0x29, 0x89, 0xe3, 0x5a, 0xae, 0x97,
++	0xe7, 0x44, 0x49, 0x6e, 0xbd, 0x81, 0x3d, 0x03,
++	0x93, 0x06, 0x12, 0x06, 0xe2, 0x41, 0x12, 0x4a,
++	0xf1, 0x6a, 0xa4, 0x58, 0xa2, 0xfb, 0xd2, 0x15,
++	0xba, 0xc9, 0x79, 0xc9, 0xce, 0x5e, 0x13, 0xbb,
++	0xf1, 0x09, 0x04, 0xcc, 0xfd, 0xe8, 0x51, 0x34,
++	0x6a, 0xe8, 0x61, 0x88, 0xda, 0xed, 0x01, 0x47,
++	0x84, 0xf5, 0x73, 0x25, 0xf9, 0x1c, 0x42, 0x86,
++	0x07, 0xf3, 0x5b, 0x1a, 0x01, 0xb3, 0xeb, 0x24,
++	0x32, 0x8d, 0xf6, 0xed, 0x7c, 0x4b, 0xeb, 0x3c,
++	0x36, 0x42, 0x28, 0xdf, 0xdf, 0xb6, 0xbe, 0xd9,
++	0x8c, 0x52, 0xd3, 0x2b, 0x08, 0x90, 0x8c, 0xe7,
++	0x98, 0x31, 0xe2, 0x32, 0x8e, 0xfc, 0x11, 0x48,
++	0x00, 0xa8, 0x6a, 0x42, 0x4a, 0x02, 0xc6, 0x4b,
++	0x09, 0xf1, 0xe3, 0x49, 0xf3, 0x45, 0x1f, 0x0e,
++	0xbc, 0x56, 0xe2, 0xe4, 0xdf, 0xfb, 0xeb, 0x61,
++	0xfa, 0x24, 0xc1, 0x63, 0x75, 0xbb, 0x47, 0x75,
++	0xaf, 0xe1, 0x53, 0x16, 0x96, 0x21, 0x85, 0x26,
++	0x11, 0xb3, 0x76, 0xe3, 0x23, 0xa1, 0x6b, 0x74,
++	0x37, 0xd0, 0xde, 0x06, 0x90, 0x71, 0x5d, 0x43,
++	0x88, 0x9b, 0x00, 0x54, 0xa6, 0x75, 0x2f, 0xa1,
++	0xc2, 0x0b, 0x73, 0x20, 0x1d, 0xb6, 0x21, 0x79,
++	0x57, 0x3f, 0xfa, 0x09, 0xbe, 0x8a, 0x33, 0xc3,
++	0x52, 0xf0, 0x1d, 0x82, 0x31, 0xd1, 0x55, 0xb5,
++	0x6c, 0x99, 0x25, 0xcf, 0x5c, 0x32, 0xce, 0xe9,
++	0x0d, 0xfa, 0x69, 0x2c, 0xd5, 0x0d, 0xc5, 0x6d,
++	0x86, 0xd0, 0x0c, 0x3b, 0x06, 0x50, 0x79, 0xe8,
++	0xc3, 0xae, 0x04, 0xe6, 0xcd, 0x51, 0xe4, 0x26,
++	0x9b, 0x4f, 0x7e, 0xa6, 0x0f, 0xab, 0xd8, 0xe5,
++	0xde, 0xa9, 0x00, 0x95, 0xbe, 0xa3, 0x9d, 0x5d,
++	0xb2, 0x09, 0x70, 0x18, 0x1c, 0xf0, 0xac, 0x29,
++	0x23, 0x02, 0x29, 0x28, 0xd2, 0x74, 0x35, 0x57,
++	0x62, 0x0f, 0x24, 0xea, 0x5e, 0x33, 0xc2, 0x92,
++	0xf3, 0x78, 0x4d, 0x30, 0x1e, 0xa1, 0x99, 0xa9,
++	0x82, 0xb0, 0x42, 0x31, 0x8d, 0xad, 0x8a, 0xbc,
++	0xfc, 0xd4, 0x57, 0x47, 0x3e, 0xb4, 0x50, 0xdd,
++	0x6e, 0x2c, 0x80, 0x4d, 0x22, 0xf1, 0xfb, 0x57,
++	0xc4, 0xdd, 0x17, 0xe1, 0x8a, 0x36, 0x4a, 0xb3,
++	0x37, 0xca, 0xc9, 0x4e, 0xab, 0xd5, 0x69, 0xc4,
++	0xf4, 0xbc, 0x0b, 0x3b, 0x44, 0x4b, 0x29, 0x9c,
++	0xee, 0xd4, 0x35, 0x22, 0x21, 0xb0, 0x1f, 0x27,
++	0x64, 0xa8, 0x51, 0x1b, 0xf0, 0x9f, 0x19, 0x5c,
++	0xfb, 0x5a, 0x64, 0x74, 0x70, 0x45, 0x09, 0xf5,
++	0x64, 0xfe, 0x1a, 0x2d, 0xc9, 0x14, 0x04, 0x14,
++	0xcf, 0xd5, 0x7d, 0x60, 0xaf, 0x94, 0x39, 0x94,
++	0xe2, 0x7d, 0x79, 0x82, 0xd0, 0x65, 0x3b, 0x6b,
++	0x9c, 0x19, 0x84, 0xb4, 0x6d, 0xb3, 0x0c, 0x99,
++	0xc0, 0x56, 0xa8, 0xbd, 0x73, 0xce, 0x05, 0x84,
++	0x3e, 0x30, 0xaa, 0xc4, 0x9b, 0x1b, 0x04, 0x2a,
++	0x9f, 0xd7, 0x43, 0x2b, 0x23, 0xdf, 0xbf, 0xaa,
++	0xd5, 0xc2, 0x43, 0x2d, 0x70, 0xab, 0xdc, 0x75,
++	0xad, 0xac, 0xf7, 0xc0, 0xbe, 0x67, 0xb2, 0x74,
++	0xed, 0x67, 0x10, 0x4a, 0x92, 0x60, 0xc1, 0x40,
++	0x50, 0x19, 0x8a, 0x8a, 0x8c, 0x09, 0x0e, 0x72,
++	0xe1, 0x73, 0x5e, 0xe8, 0x41, 0x85, 0x63, 0x9f,
++	0x3f, 0xd7, 0x7d, 0xc4, 0xfb, 0x22, 0x5d, 0x92,
++	0x6c, 0xb3, 0x1e, 0xe2, 0x50, 0x2f, 0x82, 0xa8,
++	0x28, 0xc0, 0xb5, 0xd7, 0x5f, 0x68, 0x0d, 0x2c,
++	0x2d, 0xaf, 0x7e, 0xfa, 0x2e, 0x08, 0x0f, 0x1f,
++	0x70, 0x9f, 0xe9, 0x19, 0x72, 0x55, 0xf8, 0xfb,
++	0x51, 0xd2, 0x33, 0x5d, 0xa0, 0xd3, 0x2b, 0x0a,
++	0x6c, 0xbc, 0x4e, 0xcf, 0x36, 0x4d, 0xdc, 0x3b,
++	0xe9, 0x3e, 0x81, 0x7c, 0x61, 0xdb, 0x20, 0x2d,
++	0x3a, 0xc3, 0xb3, 0x0c, 0x1e, 0x00, 0xb9, 0x7c,
++	0xf5, 0xca, 0x10, 0x5f, 0x3a, 0x71, 0xb3, 0xe4,
++	0x20, 0xdb, 0x0c, 0x2a, 0x98, 0x63, 0x45, 0x00,
++	0x58, 0xf6, 0x68, 0xe4, 0x0b, 0xda, 0x13, 0x3b,
++	0x60, 0x5c, 0x76, 0xdb, 0xb9, 0x97, 0x71, 0xe4,
++	0xd9, 0xb7, 0xdb, 0xbd, 0x68, 0xc7, 0x84, 0x84,
++	0xaa, 0x7c, 0x68, 0x62, 0x5e, 0x16, 0xfc, 0xba,
++	0x72, 0xaa, 0x9a, 0xa9, 0xeb, 0x7c, 0x75, 0x47,
++	0x97, 0x7e, 0xad, 0xe2, 0xd9, 0x91, 0xe8, 0xe4,
++	0xa5, 0x31, 0xd7, 0x01, 0x8e, 0xa2, 0x11, 0x88,
++	0x95, 0xb9, 0xf2, 0x9b, 0xd3, 0x7f, 0x1b, 0x81,
++	0x22, 0xf7, 0x98, 0x60, 0x0a, 0x64, 0xa6, 0xc1,
++	0xf6, 0x49, 0xc7, 0xe3, 0x07, 0x4d, 0x94, 0x7a,
++	0xcf, 0x6e, 0x68, 0x0c, 0x1b, 0x3f, 0x6e, 0x2e,
++	0xee, 0x92, 0xfa, 0x52, 0xb3, 0x59, 0xf8, 0xf1,
++	0x8f, 0x6a, 0x66, 0xa3, 0x82, 0x76, 0x4a, 0x07,
++	0x1a, 0xc7, 0xdd, 0xf5, 0xda, 0x9c, 0x3c, 0x24,
++	0xbf, 0xfd, 0x42, 0xa1, 0x10, 0x64, 0x6a, 0x0f,
++	0x89, 0xee, 0x36, 0xa5, 0xce, 0x99, 0x48, 0x6a,
++	0xf0, 0x9f, 0x9e, 0x69, 0xa4, 0x40, 0x20, 0xe9,
++	0x16, 0x15, 0xf7, 0xdb, 0x75, 0x02, 0xcb, 0xe9,
++	0x73, 0x8b, 0x3b, 0x49, 0x2f, 0xf0, 0xaf, 0x51,
++	0x06, 0x5c, 0xdf, 0x27, 0x27, 0x49, 0x6a, 0xd1,
++	0xcc, 0xc7, 0xb5, 0x63, 0xb5, 0xfc, 0xb8, 0x5c,
++	0x87, 0x7f, 0x84, 0xb4, 0xcc, 0x14, 0xa9, 0x53,
++	0xda, 0xa4, 0x56, 0xf8, 0xb6, 0x1b, 0xcc, 0x40,
++	0x27, 0x52, 0x06, 0x5a, 0x13, 0x81, 0xd7, 0x3a,
++	0xd4, 0x3b, 0xfb, 0x49, 0x65, 0x31, 0x33, 0xb2,
++	0xfa, 0xcd, 0xad, 0x58, 0x4e, 0x2b, 0xae, 0xd2,
++	0x20, 0xfb, 0x1a, 0x48, 0xb4, 0x3f, 0x9a, 0xd8,
++	0x7a, 0x35, 0x4a, 0xc8, 0xee, 0x88, 0x5e, 0x07,
++	0x66, 0x54, 0xb9, 0xec, 0x9f, 0xa3, 0xe3, 0xb9,
++	0x37, 0xaa, 0x49, 0x76, 0x31, 0xda, 0x74, 0x2d,
++	0x3c, 0xa4, 0x65, 0x10, 0x32, 0x38, 0xf0, 0xde,
++	0xd3, 0x99, 0x17, 0xaa, 0x71, 0xaa, 0x8f, 0x0f,
++	0x8c, 0xaf, 0xa2, 0xf8, 0x5d, 0x64, 0xba, 0x1d,
++	0xa3, 0xef, 0x96, 0x73, 0xe8, 0xa1, 0x02, 0x8d,
++	0x0c, 0x6d, 0xb8, 0x06, 0x90, 0xb8, 0x08, 0x56,
++	0x2c, 0xa7, 0x06, 0xc9, 0xc2, 0x38, 0xdb, 0x7c,
++	0x63, 0xb1, 0x57, 0x8e, 0xea, 0x7c, 0x79, 0xf3,
++	0x49, 0x1d, 0xfe, 0x9f, 0xf3, 0x6e, 0xb1, 0x1d,
++	0xba, 0x19, 0x80, 0x1a, 0x0a, 0xd3, 0xb0, 0x26,
++	0x21, 0x40, 0xb1, 0x7c, 0xf9, 0x4d, 0x8d, 0x10,
++	0xc1, 0x7e, 0xf4, 0xf6, 0x3c, 0xa8, 0xfd, 0x7c,
++	0xa3, 0x92, 0xb2, 0x0f, 0xaa, 0xcc, 0xa6, 0x11,
++	0xfe, 0x04, 0xe3, 0xd1, 0x7a, 0x32, 0x89, 0xdf,
++	0x0d, 0xc4, 0x8f, 0x79, 0x6b, 0xca, 0x16, 0x7c,
++	0x6e, 0xf9, 0xad, 0x0f, 0xf6, 0xfe, 0x27, 0xdb,
++	0xc4, 0x13, 0x70, 0xf1, 0x62, 0x1a, 0x4f, 0x79,
++	0x40, 0xc9, 0x9b, 0x8b, 0x21, 0xea, 0x84, 0xfa,
++	0xf5, 0xf1, 0x89, 0xce, 0xb7, 0x55, 0x0a, 0x80,
++	0x39, 0x2f, 0x55, 0x36, 0x16, 0x9c, 0x7b, 0x08,
++	0xbd, 0x87, 0x0d, 0xa5, 0x32, 0xf1, 0x52, 0x7c,
++	0xe8, 0x55, 0x60, 0x5b, 0xd7, 0x69, 0xe4, 0xfc,
++	0xfa, 0x12, 0x85, 0x96, 0xea, 0x50, 0x28, 0xab,
++	0x8a, 0xf7, 0xbb, 0x0e, 0x53, 0x74, 0xca, 0xa6,
++	0x27, 0x09, 0xc2, 0xb5, 0xde, 0x18, 0x14, 0xd9,
++	0xea, 0xe5, 0x29, 0x1c, 0x40, 0x56, 0xcf, 0xd7,
++	0xae, 0x05, 0x3f, 0x65, 0xaf, 0x05, 0x73, 0xe2,
++	0x35, 0x96, 0x27, 0x07, 0x14, 0xc0, 0xad, 0x33,
++	0xf1, 0xdc, 0x44, 0x7a, 0x89, 0x17, 0x77, 0xd2,
++	0x9c, 0x58, 0x60, 0xf0, 0x3f, 0x7b, 0x2d, 0x2e,
++	0x57, 0x95, 0x54, 0x87, 0xed, 0xf2, 0xc7, 0x4c,
++	0xf0, 0xae, 0x56, 0x29, 0x19, 0x7d, 0x66, 0x4b,
++	0x9b, 0x83, 0x84, 0x42, 0x3b, 0x01, 0x25, 0x66,
++	0x8e, 0x02, 0xde, 0xb9, 0x83, 0x54, 0x19, 0xf6,
++	0x9f, 0x79, 0x0d, 0x67, 0xc5, 0x1d, 0x7a, 0x44,
++	0x02, 0x98, 0xa7, 0x16, 0x1c, 0x29, 0x0d, 0x74,
++	0xff, 0x85, 0x40, 0x06, 0xef, 0x2c, 0xa9, 0xc6,
++	0xf5, 0x53, 0x07, 0x06, 0xae, 0xe4, 0xfa, 0x5f,
++	0xd8, 0x39, 0x4d, 0xf1, 0x9b, 0x6b, 0xd9, 0x24,
++	0x84, 0xfe, 0x03, 0x4c, 0xb2, 0x3f, 0xdf, 0xa1,
++	0x05, 0x9e, 0x50, 0x14, 0x5a, 0xd9, 0x1a, 0xa2,
++	0xa7, 0xfa, 0xfa, 0x17, 0xf7, 0x78, 0xd6, 0xb5,
++	0x92, 0x61, 0x91, 0xac, 0x36, 0xfa, 0x56, 0x0d,
++	0x38, 0x32, 0x18, 0x85, 0x08, 0x58, 0x37, 0xf0,
++	0x4b, 0xdb, 0x59, 0xe7, 0xa4, 0x34, 0xc0, 0x1b,
++	0x01, 0xaf, 0x2d, 0xde, 0xa1, 0xaa, 0x5d, 0xd3,
++	0xec, 0xe1, 0xd4, 0xf7, 0xe6, 0x54, 0x68, 0xf0,
++	0x51, 0x97, 0xa7, 0x89, 0xea, 0x24, 0xad, 0xd3,
++	0x6e, 0x47, 0x93, 0x8b, 0x4b, 0xb4, 0xf7, 0x1c,
++	0x42, 0x06, 0x67, 0xe8, 0x99, 0xf6, 0xf5, 0x7b,
++	0x85, 0xb5, 0x65, 0xb5, 0xb5, 0xd2, 0x37, 0xf5,
++	0xf3, 0x02, 0xa6, 0x4d, 0x11, 0xa7, 0xdc, 0x51,
++	0x09, 0x7f, 0xa0, 0xd8, 0x88, 0x1c, 0x13, 0x71,
++	0xae, 0x9c, 0xb7, 0x7b, 0x34, 0xd6, 0x4e, 0x68,
++	0x26, 0x83, 0x51, 0xaf, 0x1d, 0xee, 0x8b, 0xbb,
++	0x69, 0x43, 0x2b, 0x9e, 0x8a, 0xbc, 0x02, 0x0e,
++	0xa0, 0x1b, 0xe0, 0xa8, 0x5f, 0x6f, 0xaf, 0x1b,
++	0x8f, 0xe7, 0x64, 0x71, 0x74, 0x11, 0x7e, 0xa8,
++	0xd8, 0xf9, 0x97, 0x06, 0xc3, 0xb6, 0xfb, 0xfb,
++	0xb7, 0x3d, 0x35, 0x9d, 0x3b, 0x52, 0xed, 0x54,
++	0xca, 0xf4, 0x81, 0x01, 0x2d, 0x1b, 0xc3, 0xa7,
++	0x00, 0x3d, 0x1a, 0x39, 0x54, 0xe1, 0xf6, 0xff,
++	0xed, 0x6f, 0x0b, 0x5a, 0x68, 0xda, 0x58, 0xdd,
++	0xa9, 0xcf, 0x5c, 0x4a, 0xe5, 0x09, 0x4e, 0xde,
++	0x9d, 0xbc, 0x3e, 0xee, 0x5a, 0x00, 0x3b, 0x2c,
++	0x87, 0x10, 0x65, 0x60, 0xdd, 0xd7, 0x56, 0xd1,
++	0x4c, 0x64, 0x45, 0xe4, 0x21, 0xec, 0x78, 0xf8,
++	0x25, 0x7a, 0x3e, 0x16, 0x5d, 0x09, 0x53, 0x14,
++	0xbe, 0x4f, 0xae, 0x87, 0xd8, 0xd1, 0xaa, 0x3c,
++	0xf6, 0x3e, 0xa4, 0x70, 0x8c, 0x5e, 0x70, 0xa4,
++	0xb3, 0x6b, 0x66, 0x73, 0xd3, 0xbf, 0x31, 0x06,
++	0x19, 0x62, 0x93, 0x15, 0xf2, 0x86, 0xe4, 0x52,
++	0x7e, 0x53, 0x4c, 0x12, 0x38, 0xcc, 0x34, 0x7d,
++	0x57, 0xf6, 0x42, 0x93, 0x8a, 0xc4, 0xee, 0x5c,
++	0x8a, 0xe1, 0x52, 0x8f, 0x56, 0x64, 0xf6, 0xa6,
++	0xd1, 0x91, 0x57, 0x70, 0xcd, 0x11, 0x76, 0xf5,
++	0x59, 0x60, 0x60, 0x3c, 0xc1, 0xc3, 0x0b, 0x7f,
++	0x58, 0x1a, 0x50, 0x91, 0xf1, 0x68, 0x8f, 0x6e,
++	0x74, 0x74, 0xa8, 0x51, 0x0b, 0xf7, 0x7a, 0x98,
++	0x37, 0xf2, 0x0a, 0x0e, 0xa4, 0x97, 0x04, 0xb8,
++	0x9b, 0xfd, 0xa0, 0xea, 0xf7, 0x0d, 0xe1, 0xdb,
++	0x03, 0xf0, 0x31, 0x29, 0xf8, 0xdd, 0x6b, 0x8b,
++	0x5d, 0xd8, 0x59, 0xa9, 0x29, 0xcf, 0x9a, 0x79,
++	0x89, 0x19, 0x63, 0x46, 0x09, 0x79, 0x6a, 0x11,
++	0xda, 0x63, 0x68, 0x48, 0x77, 0x23, 0xfb, 0x7d,
++	0x3a, 0x43, 0xcb, 0x02, 0x3b, 0x7a, 0x6d, 0x10,
++	0x2a, 0x9e, 0xac, 0xf1, 0xd4, 0x19, 0xf8, 0x23,
++	0x64, 0x1d, 0x2c, 0x5f, 0xf2, 0xb0, 0x5c, 0x23,
++	0x27, 0xf7, 0x27, 0x30, 0x16, 0x37, 0xb1, 0x90,
++	0xab, 0x38, 0xfb, 0x55, 0xcd, 0x78, 0x58, 0xd4,
++	0x7d, 0x43, 0xf6, 0x45, 0x5e, 0x55, 0x8d, 0xb1,
++	0x02, 0x65, 0x58, 0xb4, 0x13, 0x4b, 0x36, 0xf7,
++	0xcc, 0xfe, 0x3d, 0x0b, 0x82, 0xe2, 0x12, 0x11,
++	0xbb, 0xe6, 0xb8, 0x3a, 0x48, 0x71, 0xc7, 0x50,
++	0x06, 0x16, 0x3a, 0xe6, 0x7c, 0x05, 0xc7, 0xc8,
++	0x4d, 0x2f, 0x08, 0x6a, 0x17, 0x9a, 0x95, 0x97,
++	0x50, 0x68, 0xdc, 0x28, 0x18, 0xc4, 0x61, 0x38,
++	0xb9, 0xe0, 0x3e, 0x78, 0xdb, 0x29, 0xe0, 0x9f,
++	0x52, 0xdd, 0xf8, 0x4f, 0x91, 0xc1, 0xd0, 0x33,
++	0xa1, 0x7a, 0x8e, 0x30, 0x13, 0x82, 0x07, 0x9f,
++	0xd3, 0x31, 0x0f, 0x23, 0xbe, 0x32, 0x5a, 0x75,
++	0xcf, 0x96, 0xb2, 0xec, 0xb5, 0x32, 0xac, 0x21,
++	0xd1, 0x82, 0x33, 0xd3, 0x15, 0x74, 0xbd, 0x90,
++	0xf1, 0x2c, 0xe6, 0x5f, 0x8d, 0xe3, 0x02, 0xe8,
++	0xe9, 0xc4, 0xca, 0x96, 0xeb, 0x0e, 0xbc, 0x91,
++	0xf4, 0xb9, 0xea, 0xd9, 0x1b, 0x75, 0xbd, 0xe1,
++	0xac, 0x2a, 0x05, 0x37, 0x52, 0x9b, 0x1b, 0x3f,
++	0x5a, 0xdc, 0x21, 0xc3, 0x98, 0xbb, 0xaf, 0xa3,
++	0xf2, 0x00, 0xbf, 0x0d, 0x30, 0x89, 0x05, 0xcc,
++	0xa5, 0x76, 0xf5, 0x06, 0xf0, 0xc6, 0x54, 0x8a,
++	0x5d, 0xd4, 0x1e, 0xc1, 0xf2, 0xce, 0xb0, 0x62,
++	0xc8, 0xfc, 0x59, 0x42, 0x9a, 0x90, 0x60, 0x55,
++	0xfe, 0x88, 0xa5, 0x8b, 0xb8, 0x33, 0x0c, 0x23,
++	0x24, 0x0d, 0x15, 0x70, 0x37, 0x1e, 0x3d, 0xf6,
++	0xd2, 0xea, 0x92, 0x10, 0xb2, 0xc4, 0x51, 0xac,
++	0xf2, 0xac, 0xf3, 0x6b, 0x6c, 0xaa, 0xcf, 0x12,
++	0xc5, 0x6c, 0x90, 0x50, 0xb5, 0x0c, 0xfc, 0x1a,
++	0x15, 0x52, 0xe9, 0x26, 0xc6, 0x52, 0xa4, 0xe7,
++	0x81, 0x69, 0xe1, 0xe7, 0x9e, 0x30, 0x01, 0xec,
++	0x84, 0x89, 0xb2, 0x0d, 0x66, 0xdd, 0xce, 0x28,
++	0x5c, 0xec, 0x98, 0x46, 0x68, 0x21, 0x9f, 0x88,
++	0x3f, 0x1f, 0x42, 0x77, 0xce, 0xd0, 0x61, 0xd4,
++	0x20, 0xa7, 0xff, 0x53, 0xad, 0x37, 0xd0, 0x17,
++	0x35, 0xc9, 0xfc, 0xba, 0x0a, 0x78, 0x3f, 0xf2,
++	0xcc, 0x86, 0x89, 0xe8, 0x4b, 0x3c, 0x48, 0x33,
++	0x09, 0x7f, 0xc6, 0xc0, 0xdd, 0xb8, 0xfd, 0x7a,
++	0x66, 0x66, 0x65, 0xeb, 0x47, 0xa7, 0x04, 0x28,
++	0xa3, 0x19, 0x8e, 0xa9, 0xb1, 0x13, 0x67, 0x62,
++	0x70, 0xcf, 0xd7
++};
++static const u8 dec_output013[] __initconst = {
++	0x74, 0xa6, 0x3e, 0xe4, 0xb1, 0xcb, 0xaf, 0xb0,
++	0x40, 0xe5, 0x0f, 0x9e, 0xf1, 0xf2, 0x89, 0xb5,
++	0x42, 0x34, 0x8a, 0xa1, 0x03, 0xb7, 0xe9, 0x57,
++	0x46, 0xbe, 0x20, 0xe4, 0x6e, 0xb0, 0xeb, 0xff,
++	0xea, 0x07, 0x7e, 0xef, 0xe2, 0x55, 0x9f, 0xe5,
++	0x78, 0x3a, 0xb7, 0x83, 0xc2, 0x18, 0x40, 0x7b,
++	0xeb, 0xcd, 0x81, 0xfb, 0x90, 0x12, 0x9e, 0x46,
++	0xa9, 0xd6, 0x4a, 0xba, 0xb0, 0x62, 0xdb, 0x6b,
++	0x99, 0xc4, 0xdb, 0x54, 0x4b, 0xb8, 0xa5, 0x71,
++	0xcb, 0xcd, 0x63, 0x32, 0x55, 0xfb, 0x31, 0xf0,
++	0x38, 0xf5, 0xbe, 0x78, 0xe4, 0x45, 0xce, 0x1b,
++	0x6a, 0x5b, 0x0e, 0xf4, 0x16, 0xe4, 0xb1, 0x3d,
++	0xf6, 0x63, 0x7b, 0xa7, 0x0c, 0xde, 0x6f, 0x8f,
++	0x74, 0xdf, 0xe0, 0x1e, 0x9d, 0xce, 0x8f, 0x24,
++	0xef, 0x23, 0x35, 0x33, 0x7b, 0x83, 0x34, 0x23,
++	0x58, 0x74, 0x14, 0x77, 0x1f, 0xc2, 0x4f, 0x4e,
++	0xc6, 0x89, 0xf9, 0x52, 0x09, 0x37, 0x64, 0x14,
++	0xc4, 0x01, 0x6b, 0x9d, 0x77, 0xe8, 0x90, 0x5d,
++	0xa8, 0x4a, 0x2a, 0xef, 0x5c, 0x7f, 0xeb, 0xbb,
++	0xb2, 0xc6, 0x93, 0x99, 0x66, 0xdc, 0x7f, 0xd4,
++	0x9e, 0x2a, 0xca, 0x8d, 0xdb, 0xe7, 0x20, 0xcf,
++	0xe4, 0x73, 0xae, 0x49, 0x7d, 0x64, 0x0f, 0x0e,
++	0x28, 0x46, 0xa9, 0xa8, 0x32, 0xe4, 0x0e, 0xf6,
++	0x51, 0x53, 0xb8, 0x3c, 0xb1, 0xff, 0xa3, 0x33,
++	0x41, 0x75, 0xff, 0xf1, 0x6f, 0xf1, 0xfb, 0xbb,
++	0x83, 0x7f, 0x06, 0x9b, 0xe7, 0x1b, 0x0a, 0xe0,
++	0x5c, 0x33, 0x60, 0x5b, 0xdb, 0x5b, 0xed, 0xfe,
++	0xa5, 0x16, 0x19, 0x72, 0xa3, 0x64, 0x23, 0x00,
++	0x02, 0xc7, 0xf3, 0x6a, 0x81, 0x3e, 0x44, 0x1d,
++	0x79, 0x15, 0x5f, 0x9a, 0xde, 0xe2, 0xfd, 0x1b,
++	0x73, 0xc1, 0xbc, 0x23, 0xba, 0x31, 0xd2, 0x50,
++	0xd5, 0xad, 0x7f, 0x74, 0xa7, 0xc9, 0xf8, 0x3e,
++	0x2b, 0x26, 0x10, 0xf6, 0x03, 0x36, 0x74, 0xe4,
++	0x0e, 0x6a, 0x72, 0xb7, 0x73, 0x0a, 0x42, 0x28,
++	0xc2, 0xad, 0x5e, 0x03, 0xbe, 0xb8, 0x0b, 0xa8,
++	0x5b, 0xd4, 0xb8, 0xba, 0x52, 0x89, 0xb1, 0x9b,
++	0xc1, 0xc3, 0x65, 0x87, 0xed, 0xa5, 0xf4, 0x86,
++	0xfd, 0x41, 0x80, 0x91, 0x27, 0x59, 0x53, 0x67,
++	0x15, 0x78, 0x54, 0x8b, 0x2d, 0x3d, 0xc7, 0xff,
++	0x02, 0x92, 0x07, 0x5f, 0x7a, 0x4b, 0x60, 0x59,
++	0x3c, 0x6f, 0x5c, 0xd8, 0xec, 0x95, 0xd2, 0xfe,
++	0xa0, 0x3b, 0xd8, 0x3f, 0xd1, 0x69, 0xa6, 0xd6,
++	0x41, 0xb2, 0xf4, 0x4d, 0x12, 0xf4, 0x58, 0x3e,
++	0x66, 0x64, 0x80, 0x31, 0x9b, 0xa8, 0x4c, 0x8b,
++	0x07, 0xb2, 0xec, 0x66, 0x94, 0x66, 0x47, 0x50,
++	0x50, 0x5f, 0x18, 0x0b, 0x0e, 0xd6, 0xc0, 0x39,
++	0x21, 0x13, 0x9e, 0x33, 0xbc, 0x79, 0x36, 0x02,
++	0x96, 0x70, 0xf0, 0x48, 0x67, 0x2f, 0x26, 0xe9,
++	0x6d, 0x10, 0xbb, 0xd6, 0x3f, 0xd1, 0x64, 0x7a,
++	0x2e, 0xbe, 0x0c, 0x61, 0xf0, 0x75, 0x42, 0x38,
++	0x23, 0xb1, 0x9e, 0x9f, 0x7c, 0x67, 0x66, 0xd9,
++	0x58, 0x9a, 0xf1, 0xbb, 0x41, 0x2a, 0x8d, 0x65,
++	0x84, 0x94, 0xfc, 0xdc, 0x6a, 0x50, 0x64, 0xdb,
++	0x56, 0x33, 0x76, 0x00, 0x10, 0xed, 0xbe, 0xd2,
++	0x12, 0xf6, 0xf6, 0x1b, 0xa2, 0x16, 0xde, 0xae,
++	0x31, 0x95, 0xdd, 0xb1, 0x08, 0x7e, 0x4e, 0xee,
++	0xe7, 0xf9, 0xa5, 0xfb, 0x5b, 0x61, 0x43, 0x00,
++	0x40, 0xf6, 0x7e, 0x02, 0x04, 0x32, 0x4e, 0x0c,
++	0xe2, 0x66, 0x0d, 0xd7, 0x07, 0x98, 0x0e, 0xf8,
++	0x72, 0x34, 0x6d, 0x95, 0x86, 0xd7, 0xcb, 0x31,
++	0x54, 0x47, 0xd0, 0x38, 0x29, 0x9c, 0x5a, 0x68,
++	0xd4, 0x87, 0x76, 0xc9, 0xe7, 0x7e, 0xe3, 0xf4,
++	0x81, 0x6d, 0x18, 0xcb, 0xc9, 0x05, 0xaf, 0xa0,
++	0xfb, 0x66, 0xf7, 0xf1, 0x1c, 0xc6, 0x14, 0x11,
++	0x4f, 0x2b, 0x79, 0x42, 0x8b, 0xbc, 0xac, 0xe7,
++	0x6c, 0xfe, 0x0f, 0x58, 0xe7, 0x7c, 0x78, 0x39,
++	0x30, 0xb0, 0x66, 0x2c, 0x9b, 0x6d, 0x3a, 0xe1,
++	0xcf, 0xc9, 0xa4, 0x0e, 0x6d, 0x6d, 0x8a, 0xa1,
++	0x3a, 0xe7, 0x28, 0xd4, 0x78, 0x4c, 0xa6, 0xa2,
++	0x2a, 0xa6, 0x03, 0x30, 0xd7, 0xa8, 0x25, 0x66,
++	0x87, 0x2f, 0x69, 0x5c, 0x4e, 0xdd, 0xa5, 0x49,
++	0x5d, 0x37, 0x4a, 0x59, 0xc4, 0xaf, 0x1f, 0xa2,
++	0xe4, 0xf8, 0xa6, 0x12, 0x97, 0xd5, 0x79, 0xf5,
++	0xe2, 0x4a, 0x2b, 0x5f, 0x61, 0xe4, 0x9e, 0xe3,
++	0xee, 0xb8, 0xa7, 0x5b, 0x2f, 0xf4, 0x9e, 0x6c,
++	0xfb, 0xd1, 0xc6, 0x56, 0x77, 0xba, 0x75, 0xaa,
++	0x3d, 0x1a, 0xa8, 0x0b, 0xb3, 0x68, 0x24, 0x00,
++	0x10, 0x7f, 0xfd, 0xd7, 0xa1, 0x8d, 0x83, 0x54,
++	0x4f, 0x1f, 0xd8, 0x2a, 0xbe, 0x8a, 0x0c, 0x87,
++	0xab, 0xa2, 0xde, 0xc3, 0x39, 0xbf, 0x09, 0x03,
++	0xa5, 0xf3, 0x05, 0x28, 0xe1, 0xe1, 0xee, 0x39,
++	0x70, 0x9c, 0xd8, 0x81, 0x12, 0x1e, 0x02, 0x40,
++	0xd2, 0x6e, 0xf0, 0xeb, 0x1b, 0x3d, 0x22, 0xc6,
++	0xe5, 0xe3, 0xb4, 0x5a, 0x98, 0xbb, 0xf0, 0x22,
++	0x28, 0x8d, 0xe5, 0xd3, 0x16, 0x48, 0x24, 0xa5,
++	0xe6, 0x66, 0x0c, 0xf9, 0x08, 0xf9, 0x7e, 0x1e,
++	0xe1, 0x28, 0x26, 0x22, 0xc7, 0xc7, 0x0a, 0x32,
++	0x47, 0xfa, 0xa3, 0xbe, 0x3c, 0xc4, 0xc5, 0x53,
++	0x0a, 0xd5, 0x94, 0x4a, 0xd7, 0x93, 0xd8, 0x42,
++	0x99, 0xb9, 0x0a, 0xdb, 0x56, 0xf7, 0xb9, 0x1c,
++	0x53, 0x4f, 0xfa, 0xd3, 0x74, 0xad, 0xd9, 0x68,
++	0xf1, 0x1b, 0xdf, 0x61, 0xc6, 0x5e, 0xa8, 0x48,
++	0xfc, 0xd4, 0x4a, 0x4c, 0x3c, 0x32, 0xf7, 0x1c,
++	0x96, 0x21, 0x9b, 0xf9, 0xa3, 0xcc, 0x5a, 0xce,
++	0xd5, 0xd7, 0x08, 0x24, 0xf6, 0x1c, 0xfd, 0xdd,
++	0x38, 0xc2, 0x32, 0xe9, 0xb8, 0xe7, 0xb6, 0xfa,
++	0x9d, 0x45, 0x13, 0x2c, 0x83, 0xfd, 0x4a, 0x69,
++	0x82, 0xcd, 0xdc, 0xb3, 0x76, 0x0c, 0x9e, 0xd8,
++	0xf4, 0x1b, 0x45, 0x15, 0xb4, 0x97, 0xe7, 0x58,
++	0x34, 0xe2, 0x03, 0x29, 0x5a, 0xbf, 0xb6, 0xe0,
++	0x5d, 0x13, 0xd9, 0x2b, 0xb4, 0x80, 0xb2, 0x45,
++	0x81, 0x6a, 0x2e, 0x6c, 0x89, 0x7d, 0xee, 0xbb,
++	0x52, 0xdd, 0x1f, 0x18, 0xe7, 0x13, 0x6b, 0x33,
++	0x0e, 0xea, 0x36, 0x92, 0x77, 0x7b, 0x6d, 0x9c,
++	0x5a, 0x5f, 0x45, 0x7b, 0x7b, 0x35, 0x62, 0x23,
++	0xd1, 0xbf, 0x0f, 0xd0, 0x08, 0x1b, 0x2b, 0x80,
++	0x6b, 0x7e, 0xf1, 0x21, 0x47, 0xb0, 0x57, 0xd1,
++	0x98, 0x72, 0x90, 0x34, 0x1c, 0x20, 0x04, 0xff,
++	0x3d, 0x5c, 0xee, 0x0e, 0x57, 0x5f, 0x6f, 0x24,
++	0x4e, 0x3c, 0xea, 0xfc, 0xa5, 0xa9, 0x83, 0xc9,
++	0x61, 0xb4, 0x51, 0x24, 0xf8, 0x27, 0x5e, 0x46,
++	0x8c, 0xb1, 0x53, 0x02, 0x96, 0x35, 0xba, 0xb8,
++	0x4c, 0x71, 0xd3, 0x15, 0x59, 0x35, 0x22, 0x20,
++	0xad, 0x03, 0x9f, 0x66, 0x44, 0x3b, 0x9c, 0x35,
++	0x37, 0x1f, 0x9b, 0xbb, 0xf3, 0xdb, 0x35, 0x63,
++	0x30, 0x64, 0xaa, 0xa2, 0x06, 0xa8, 0x5d, 0xbb,
++	0xe1, 0x9f, 0x70, 0xec, 0x82, 0x11, 0x06, 0x36,
++	0xec, 0x8b, 0x69, 0x66, 0x24, 0x44, 0xc9, 0x4a,
++	0x57, 0xbb, 0x9b, 0x78, 0x13, 0xce, 0x9c, 0x0c,
++	0xba, 0x92, 0x93, 0x63, 0xb8, 0xe2, 0x95, 0x0f,
++	0x0f, 0x16, 0x39, 0x52, 0xfd, 0x3a, 0x6d, 0x02,
++	0x4b, 0xdf, 0x13, 0xd3, 0x2a, 0x22, 0xb4, 0x03,
++	0x7c, 0x54, 0x49, 0x96, 0x68, 0x54, 0x10, 0xfa,
++	0xef, 0xaa, 0x6c, 0xe8, 0x22, 0xdc, 0x71, 0x16,
++	0x13, 0x1a, 0xf6, 0x28, 0xe5, 0x6d, 0x77, 0x3d,
++	0xcd, 0x30, 0x63, 0xb1, 0x70, 0x52, 0xa1, 0xc5,
++	0x94, 0x5f, 0xcf, 0xe8, 0xb8, 0x26, 0x98, 0xf7,
++	0x06, 0xa0, 0x0a, 0x70, 0xfa, 0x03, 0x80, 0xac,
++	0xc1, 0xec, 0xd6, 0x4c, 0x54, 0xd7, 0xfe, 0x47,
++	0xb6, 0x88, 0x4a, 0xf7, 0x71, 0x24, 0xee, 0xf3,
++	0xd2, 0xc2, 0x4a, 0x7f, 0xfe, 0x61, 0xc7, 0x35,
++	0xc9, 0x37, 0x67, 0xcb, 0x24, 0x35, 0xda, 0x7e,
++	0xca, 0x5f, 0xf3, 0x8d, 0xd4, 0x13, 0x8e, 0xd6,
++	0xcb, 0x4d, 0x53, 0x8f, 0x53, 0x1f, 0xc0, 0x74,
++	0xf7, 0x53, 0xb9, 0x5e, 0x23, 0x37, 0xba, 0x6e,
++	0xe3, 0x9d, 0x07, 0x55, 0x25, 0x7b, 0xe6, 0x2a,
++	0x64, 0xd1, 0x32, 0xdd, 0x54, 0x1b, 0x4b, 0xc0,
++	0xe1, 0xd7, 0x69, 0x58, 0xf8, 0x93, 0x29, 0xc4,
++	0xdd, 0x23, 0x2f, 0xa5, 0xfc, 0x9d, 0x7e, 0xf8,
++	0xd4, 0x90, 0xcd, 0x82, 0x55, 0xdc, 0x16, 0x16,
++	0x9f, 0x07, 0x52, 0x9b, 0x9d, 0x25, 0xed, 0x32,
++	0xc5, 0x7b, 0xdf, 0xf6, 0x83, 0x46, 0x3d, 0x65,
++	0xb7, 0xef, 0x87, 0x7a, 0x12, 0x69, 0x8f, 0x06,
++	0x7c, 0x51, 0x15, 0x4a, 0x08, 0xe8, 0xac, 0x9a,
++	0x0c, 0x24, 0xa7, 0x27, 0xd8, 0x46, 0x2f, 0xe7,
++	0x01, 0x0e, 0x1c, 0xc6, 0x91, 0xb0, 0x6e, 0x85,
++	0x65, 0xf0, 0x29, 0x0d, 0x2e, 0x6b, 0x3b, 0xfb,
++	0x4b, 0xdf, 0xe4, 0x80, 0x93, 0x03, 0x66, 0x46,
++	0x3e, 0x8a, 0x6e, 0xf3, 0x5e, 0x4d, 0x62, 0x0e,
++	0x49, 0x05, 0xaf, 0xd4, 0xf8, 0x21, 0x20, 0x61,
++	0x1d, 0x39, 0x17, 0xf4, 0x61, 0x47, 0x95, 0xfb,
++	0x15, 0x2e, 0xb3, 0x4f, 0xd0, 0x5d, 0xf5, 0x7d,
++	0x40, 0xda, 0x90, 0x3c, 0x6b, 0xcb, 0x17, 0x00,
++	0x13, 0x3b, 0x64, 0x34, 0x1b, 0xf0, 0xf2, 0xe5,
++	0x3b, 0xb2, 0xc7, 0xd3, 0x5f, 0x3a, 0x44, 0xa6,
++	0x9b, 0xb7, 0x78, 0x0e, 0x42, 0x5d, 0x4c, 0xc1,
++	0xe9, 0xd2, 0xcb, 0xb7, 0x78, 0xd1, 0xfe, 0x9a,
++	0xb5, 0x07, 0xe9, 0xe0, 0xbe, 0xe2, 0x8a, 0xa7,
++	0x01, 0x83, 0x00, 0x8c, 0x5c, 0x08, 0xe6, 0x63,
++	0x12, 0x92, 0xb7, 0xb7, 0xa6, 0x19, 0x7d, 0x38,
++	0x13, 0x38, 0x92, 0x87, 0x24, 0xf9, 0x48, 0xb3,
++	0x5e, 0x87, 0x6a, 0x40, 0x39, 0x5c, 0x3f, 0xed,
++	0x8f, 0xee, 0xdb, 0x15, 0x82, 0x06, 0xda, 0x49,
++	0x21, 0x2b, 0xb5, 0xbf, 0x32, 0x7c, 0x9f, 0x42,
++	0x28, 0x63, 0xcf, 0xaf, 0x1e, 0xf8, 0xc6, 0xa0,
++	0xd1, 0x02, 0x43, 0x57, 0x62, 0xec, 0x9b, 0x0f,
++	0x01, 0x9e, 0x71, 0xd8, 0x87, 0x9d, 0x01, 0xc1,
++	0x58, 0x77, 0xd9, 0xaf, 0xb1, 0x10, 0x7e, 0xdd,
++	0xa6, 0x50, 0x96, 0xe5, 0xf0, 0x72, 0x00, 0x6d,
++	0x4b, 0xf8, 0x2a, 0x8f, 0x19, 0xf3, 0x22, 0x88,
++	0x11, 0x4a, 0x8b, 0x7c, 0xfd, 0xb7, 0xed, 0xe1,
++	0xf6, 0x40, 0x39, 0xe0, 0xe9, 0xf6, 0x3d, 0x25,
++	0xe6, 0x74, 0x3c, 0x58, 0x57, 0x7f, 0xe1, 0x22,
++	0x96, 0x47, 0x31, 0x91, 0xba, 0x70, 0x85, 0x28,
++	0x6b, 0x9f, 0x6e, 0x25, 0xac, 0x23, 0x66, 0x2f,
++	0x29, 0x88, 0x28, 0xce, 0x8c, 0x5c, 0x88, 0x53,
++	0xd1, 0x3b, 0xcc, 0x6a, 0x51, 0xb2, 0xe1, 0x28,
++	0x3f, 0x91, 0xb4, 0x0d, 0x00, 0x3a, 0xe3, 0xf8,
++	0xc3, 0x8f, 0xd7, 0x96, 0x62, 0x0e, 0x2e, 0xfc,
++	0xc8, 0x6c, 0x77, 0xa6, 0x1d, 0x22, 0xc1, 0xb8,
++	0xe6, 0x61, 0xd7, 0x67, 0x36, 0x13, 0x7b, 0xbb,
++	0x9b, 0x59, 0x09, 0xa6, 0xdf, 0xf7, 0x6b, 0xa3,
++	0x40, 0x1a, 0xf5, 0x4f, 0xb4, 0xda, 0xd3, 0xf3,
++	0x81, 0x93, 0xc6, 0x18, 0xd9, 0x26, 0xee, 0xac,
++	0xf0, 0xaa, 0xdf, 0xc5, 0x9c, 0xca, 0xc2, 0xa2,
++	0xcc, 0x7b, 0x5c, 0x24, 0xb0, 0xbc, 0xd0, 0x6a,
++	0x4d, 0x89, 0x09, 0xb8, 0x07, 0xfe, 0x87, 0xad,
++	0x0a, 0xea, 0xb8, 0x42, 0xf9, 0x5e, 0xb3, 0x3e,
++	0x36, 0x4c, 0xaf, 0x75, 0x9e, 0x1c, 0xeb, 0xbd,
++	0xbc, 0xbb, 0x80, 0x40, 0xa7, 0x3a, 0x30, 0xbf,
++	0xa8, 0x44, 0xf4, 0xeb, 0x38, 0xad, 0x29, 0xba,
++	0x23, 0xed, 0x41, 0x0c, 0xea, 0xd2, 0xbb, 0x41,
++	0x18, 0xd6, 0xb9, 0xba, 0x65, 0x2b, 0xa3, 0x91,
++	0x6d, 0x1f, 0xa9, 0xf4, 0xd1, 0x25, 0x8d, 0x4d,
++	0x38, 0xff, 0x64, 0xa0, 0xec, 0xde, 0xa6, 0xb6,
++	0x79, 0xab, 0x8e, 0x33, 0x6c, 0x47, 0xde, 0xaf,
++	0x94, 0xa4, 0xa5, 0x86, 0x77, 0x55, 0x09, 0x92,
++	0x81, 0x31, 0x76, 0xc7, 0x34, 0x22, 0x89, 0x8e,
++	0x3d, 0x26, 0x26, 0xd7, 0xfc, 0x1e, 0x16, 0x72,
++	0x13, 0x33, 0x63, 0xd5, 0x22, 0xbe, 0xb8, 0x04,
++	0x34, 0x84, 0x41, 0xbb, 0x80, 0xd0, 0x9f, 0x46,
++	0x48, 0x07, 0xa7, 0xfc, 0x2b, 0x3a, 0x75, 0x55,
++	0x8c, 0xc7, 0x6a, 0xbd, 0x7e, 0x46, 0x08, 0x84,
++	0x0f, 0xd5, 0x74, 0xc0, 0x82, 0x8e, 0xaa, 0x61,
++	0x05, 0x01, 0xb2, 0x47, 0x6e, 0x20, 0x6a, 0x2d,
++	0x58, 0x70, 0x48, 0x32, 0xa7, 0x37, 0xd2, 0xb8,
++	0x82, 0x1a, 0x51, 0xb9, 0x61, 0xdd, 0xfd, 0x9d,
++	0x6b, 0x0e, 0x18, 0x97, 0xf8, 0x45, 0x5f, 0x87,
++	0x10, 0xcf, 0x34, 0x72, 0x45, 0x26, 0x49, 0x70,
++	0xe7, 0xa3, 0x78, 0xe0, 0x52, 0x89, 0x84, 0x94,
++	0x83, 0x82, 0xc2, 0x69, 0x8f, 0xe3, 0xe1, 0x3f,
++	0x60, 0x74, 0x88, 0xc4, 0xf7, 0x75, 0x2c, 0xfb,
++	0xbd, 0xb6, 0xc4, 0x7e, 0x10, 0x0a, 0x6c, 0x90,
++	0x04, 0x9e, 0xc3, 0x3f, 0x59, 0x7c, 0xce, 0x31,
++	0x18, 0x60, 0x57, 0x73, 0x46, 0x94, 0x7d, 0x06,
++	0xa0, 0x6d, 0x44, 0xec, 0xa2, 0x0a, 0x9e, 0x05,
++	0x15, 0xef, 0xca, 0x5c, 0xbf, 0x00, 0xeb, 0xf7,
++	0x3d, 0x32, 0xd4, 0xa5, 0xef, 0x49, 0x89, 0x5e,
++	0x46, 0xb0, 0xa6, 0x63, 0x5b, 0x8a, 0x73, 0xae,
++	0x6f, 0xd5, 0x9d, 0xf8, 0x4f, 0x40, 0xb5, 0xb2,
++	0x6e, 0xd3, 0xb6, 0x01, 0xa9, 0x26, 0xa2, 0x21,
++	0xcf, 0x33, 0x7a, 0x3a, 0xa4, 0x23, 0x13, 0xb0,
++	0x69, 0x6a, 0xee, 0xce, 0xd8, 0x9d, 0x01, 0x1d,
++	0x50, 0xc1, 0x30, 0x6c, 0xb1, 0xcd, 0xa0, 0xf0,
++	0xf0, 0xa2, 0x64, 0x6f, 0xbb, 0xbf, 0x5e, 0xe6,
++	0xab, 0x87, 0xb4, 0x0f, 0x4f, 0x15, 0xaf, 0xb5,
++	0x25, 0xa1, 0xb2, 0xd0, 0x80, 0x2c, 0xfb, 0xf9,
++	0xfe, 0xd2, 0x33, 0xbb, 0x76, 0xfe, 0x7c, 0xa8,
++	0x66, 0xf7, 0xe7, 0x85, 0x9f, 0x1f, 0x85, 0x57,
++	0x88, 0xe1, 0xe9, 0x63, 0xe4, 0xd8, 0x1c, 0xa1,
++	0xfb, 0xda, 0x44, 0x05, 0x2e, 0x1d, 0x3a, 0x1c,
++	0xff, 0xc8, 0x3b, 0xc0, 0xfe, 0xda, 0x22, 0x0b,
++	0x43, 0xd6, 0x88, 0x39, 0x4c, 0x4a, 0xa6, 0x69,
++	0x18, 0x93, 0x42, 0x4e, 0xb5, 0xcc, 0x66, 0x0d,
++	0x09, 0xf8, 0x1e, 0x7c, 0xd3, 0x3c, 0x99, 0x0d,
++	0x50, 0x1d, 0x62, 0xe9, 0x57, 0x06, 0xbf, 0x19,
++	0x88, 0xdd, 0xad, 0x7b, 0x4f, 0xf9, 0xc7, 0x82,
++	0x6d, 0x8d, 0xc8, 0xc4, 0xc5, 0x78, 0x17, 0x20,
++	0x15, 0xc5, 0x52, 0x41, 0xcf, 0x5b, 0xd6, 0x7f,
++	0x94, 0x02, 0x41, 0xe0, 0x40, 0x22, 0x03, 0x5e,
++	0xd1, 0x53, 0xd4, 0x86, 0xd3, 0x2c, 0x9f, 0x0f,
++	0x96, 0xe3, 0x6b, 0x9a, 0x76, 0x32, 0x06, 0x47,
++	0x4b, 0x11, 0xb3, 0xdd, 0x03, 0x65, 0xbd, 0x9b,
++	0x01, 0xda, 0x9c, 0xb9, 0x7e, 0x3f, 0x6a, 0xc4,
++	0x7b, 0xea, 0xd4, 0x3c, 0xb9, 0xfb, 0x5c, 0x6b,
++	0x64, 0x33, 0x52, 0xba, 0x64, 0x78, 0x8f, 0xa4,
++	0xaf, 0x7a, 0x61, 0x8d, 0xbc, 0xc5, 0x73, 0xe9,
++	0x6b, 0x58, 0x97, 0x4b, 0xbf, 0x63, 0x22, 0xd3,
++	0x37, 0x02, 0x54, 0xc5, 0xb9, 0x16, 0x4a, 0xf0,
++	0x19, 0xd8, 0x94, 0x57, 0xb8, 0x8a, 0xb3, 0x16,
++	0x3b, 0xd0, 0x84, 0x8e, 0x67, 0xa6, 0xa3, 0x7d,
++	0x78, 0xec, 0x00
++};
++static const u8 dec_assoc013[] __initconst = {
++	0xb1, 0x69, 0x83, 0x87, 0x30, 0xaa, 0x5d, 0xb8,
++	0x77, 0xe8, 0x21, 0xff, 0x06, 0x59, 0x35, 0xce,
++	0x75, 0xfe, 0x38, 0xef, 0xb8, 0x91, 0x43, 0x8c,
++	0xcf, 0x70, 0xdd, 0x0a, 0x68, 0xbf, 0xd4, 0xbc,
++	0x16, 0x76, 0x99, 0x36, 0x1e, 0x58, 0x79, 0x5e,
++	0xd4, 0x29, 0xf7, 0x33, 0x93, 0x48, 0xdb, 0x5f,
++	0x01, 0xae, 0x9c, 0xb6, 0xe4, 0x88, 0x6d, 0x2b,
++	0x76, 0x75, 0xe0, 0xf3, 0x74, 0xe2, 0xc9
++};
++static const u8 dec_nonce013[] __initconst = {
++	0x05, 0xa3, 0x93, 0xed, 0x30, 0xc5, 0xa2, 0x06
++};
++static const u8 dec_key013[] __initconst = {
++	0xb3, 0x35, 0x50, 0x03, 0x54, 0x2e, 0x40, 0x5e,
++	0x8f, 0x59, 0x8e, 0xc5, 0x90, 0xd5, 0x27, 0x2d,
++	0xba, 0x29, 0x2e, 0xcb, 0x1b, 0x70, 0x44, 0x1e,
++	0x65, 0x91, 0x6e, 0x2a, 0x79, 0x22, 0xda, 0x64
++};
++
++static const struct chacha20poly1305_testvec
++chacha20poly1305_dec_vectors[] __initconst = {
++	{ dec_input001, dec_output001, dec_assoc001, dec_nonce001, dec_key001,
++	  sizeof(dec_input001), sizeof(dec_assoc001), sizeof(dec_nonce001) },
++	{ dec_input002, dec_output002, dec_assoc002, dec_nonce002, dec_key002,
++	  sizeof(dec_input002), sizeof(dec_assoc002), sizeof(dec_nonce002) },
++	{ dec_input003, dec_output003, dec_assoc003, dec_nonce003, dec_key003,
++	  sizeof(dec_input003), sizeof(dec_assoc003), sizeof(dec_nonce003) },
++	{ dec_input004, dec_output004, dec_assoc004, dec_nonce004, dec_key004,
++	  sizeof(dec_input004), sizeof(dec_assoc004), sizeof(dec_nonce004) },
++	{ dec_input005, dec_output005, dec_assoc005, dec_nonce005, dec_key005,
++	  sizeof(dec_input005), sizeof(dec_assoc005), sizeof(dec_nonce005) },
++	{ dec_input006, dec_output006, dec_assoc006, dec_nonce006, dec_key006,
++	  sizeof(dec_input006), sizeof(dec_assoc006), sizeof(dec_nonce006) },
++	{ dec_input007, dec_output007, dec_assoc007, dec_nonce007, dec_key007,
++	  sizeof(dec_input007), sizeof(dec_assoc007), sizeof(dec_nonce007) },
++	{ dec_input008, dec_output008, dec_assoc008, dec_nonce008, dec_key008,
++	  sizeof(dec_input008), sizeof(dec_assoc008), sizeof(dec_nonce008) },
++	{ dec_input009, dec_output009, dec_assoc009, dec_nonce009, dec_key009,
++	  sizeof(dec_input009), sizeof(dec_assoc009), sizeof(dec_nonce009) },
++	{ dec_input010, dec_output010, dec_assoc010, dec_nonce010, dec_key010,
++	  sizeof(dec_input010), sizeof(dec_assoc010), sizeof(dec_nonce010) },
++	{ dec_input011, dec_output011, dec_assoc011, dec_nonce011, dec_key011,
++	  sizeof(dec_input011), sizeof(dec_assoc011), sizeof(dec_nonce011) },
++	{ dec_input012, dec_output012, dec_assoc012, dec_nonce012, dec_key012,
++	  sizeof(dec_input012), sizeof(dec_assoc012), sizeof(dec_nonce012) },
++	{ dec_input013, dec_output013, dec_assoc013, dec_nonce013, dec_key013,
++	  sizeof(dec_input013), sizeof(dec_assoc013), sizeof(dec_nonce013),
++	  true }
++};
++
++static const u8 xenc_input001[] __initconst = {
++	0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
++	0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x73, 0x20,
++	0x61, 0x72, 0x65, 0x20, 0x64, 0x72, 0x61, 0x66,
++	0x74, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65,
++	0x6e, 0x74, 0x73, 0x20, 0x76, 0x61, 0x6c, 0x69,
++	0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20,
++	0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20,
++	0x6f, 0x66, 0x20, 0x73, 0x69, 0x78, 0x20, 0x6d,
++	0x6f, 0x6e, 0x74, 0x68, 0x73, 0x20, 0x61, 0x6e,
++	0x64, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65,
++	0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64,
++	0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63,
++	0x65, 0x64, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x6f,
++	0x62, 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x64,
++	0x20, 0x62, 0x79, 0x20, 0x6f, 0x74, 0x68, 0x65,
++	0x72, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65,
++	0x6e, 0x74, 0x73, 0x20, 0x61, 0x74, 0x20, 0x61,
++	0x6e, 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x2e,
++	0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x69,
++	0x6e, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x70, 0x72,
++	0x69, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20,
++	0x75, 0x73, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65,
++	0x72, 0x6e, 0x65, 0x74, 0x2d, 0x44, 0x72, 0x61,
++	0x66, 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x72,
++	0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65,
++	0x20, 0x6d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61,
++	0x6c, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20,
++	0x63, 0x69, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65,
++	0x6d, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20,
++	0x74, 0x68, 0x61, 0x6e, 0x20, 0x61, 0x73, 0x20,
++	0x2f, 0xe2, 0x80, 0x9c, 0x77, 0x6f, 0x72, 0x6b,
++	0x20, 0x69, 0x6e, 0x20, 0x70, 0x72, 0x6f, 0x67,
++	0x72, 0x65, 0x73, 0x73, 0x2e, 0x2f, 0xe2, 0x80,
++	0x9d
++};
++static const u8 xenc_output001[] __initconst = {
++	0x1a, 0x6e, 0x3a, 0xd9, 0xfd, 0x41, 0x3f, 0x77,
++	0x54, 0x72, 0x0a, 0x70, 0x9a, 0xa0, 0x29, 0x92,
++	0x2e, 0xed, 0x93, 0xcf, 0x0f, 0x71, 0x88, 0x18,
++	0x7a, 0x9d, 0x2d, 0x24, 0xe0, 0xf5, 0xea, 0x3d,
++	0x55, 0x64, 0xd7, 0xad, 0x2a, 0x1a, 0x1f, 0x7e,
++	0x86, 0x6d, 0xb0, 0xce, 0x80, 0x41, 0x72, 0x86,
++	0x26, 0xee, 0x84, 0xd7, 0xef, 0x82, 0x9e, 0xe2,
++	0x60, 0x9d, 0x5a, 0xfc, 0xf0, 0xe4, 0x19, 0x85,
++	0xea, 0x09, 0xc6, 0xfb, 0xb3, 0xa9, 0x50, 0x09,
++	0xec, 0x5e, 0x11, 0x90, 0xa1, 0xc5, 0x4e, 0x49,
++	0xef, 0x50, 0xd8, 0x8f, 0xe0, 0x78, 0xd7, 0xfd,
++	0xb9, 0x3b, 0xc9, 0xf2, 0x91, 0xc8, 0x25, 0xc8,
++	0xa7, 0x63, 0x60, 0xce, 0x10, 0xcd, 0xc6, 0x7f,
++	0xf8, 0x16, 0xf8, 0xe1, 0x0a, 0xd9, 0xde, 0x79,
++	0x50, 0x33, 0xf2, 0x16, 0x0f, 0x17, 0xba, 0xb8,
++	0x5d, 0xd8, 0xdf, 0x4e, 0x51, 0xa8, 0x39, 0xd0,
++	0x85, 0xca, 0x46, 0x6a, 0x10, 0xa7, 0xa3, 0x88,
++	0xef, 0x79, 0xb9, 0xf8, 0x24, 0xf3, 0xe0, 0x71,
++	0x7b, 0x76, 0x28, 0x46, 0x3a, 0x3a, 0x1b, 0x91,
++	0xb6, 0xd4, 0x3e, 0x23, 0xe5, 0x44, 0x15, 0xbf,
++	0x60, 0x43, 0x9d, 0xa4, 0xbb, 0xd5, 0x5f, 0x89,
++	0xeb, 0xef, 0x8e, 0xfd, 0xdd, 0xb4, 0x0d, 0x46,
++	0xf0, 0x69, 0x23, 0x63, 0xae, 0x94, 0xf5, 0x5e,
++	0xa5, 0xad, 0x13, 0x1c, 0x41, 0x76, 0xe6, 0x90,
++	0xd6, 0x6d, 0xa2, 0x8f, 0x97, 0x4c, 0xa8, 0x0b,
++	0xcf, 0x8d, 0x43, 0x2b, 0x9c, 0x9b, 0xc5, 0x58,
++	0xa5, 0xb6, 0x95, 0x9a, 0xbf, 0x81, 0xc6, 0x54,
++	0xc9, 0x66, 0x0c, 0xe5, 0x4f, 0x6a, 0x53, 0xa1,
++	0xe5, 0x0c, 0xba, 0x31, 0xde, 0x34, 0x64, 0x73,
++	0x8a, 0x3b, 0xbd, 0x92, 0x01, 0xdb, 0x71, 0x69,
++	0xf3, 0x58, 0x99, 0xbc, 0xd1, 0xcb, 0x4a, 0x05,
++	0xe2, 0x58, 0x9c, 0x25, 0x17, 0xcd, 0xdc, 0x83,
++	0xb7, 0xff, 0xfb, 0x09, 0x61, 0xad, 0xbf, 0x13,
++	0x5b, 0x5e, 0xed, 0x46, 0x82, 0x6f, 0x22, 0xd8,
++	0x93, 0xa6, 0x85, 0x5b, 0x40, 0x39, 0x5c, 0xc5,
++	0x9c
++};
++static const u8 xenc_assoc001[] __initconst = {
++	0xf3, 0x33, 0x88, 0x86, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x4e, 0x91
++};
++static const u8 xenc_nonce001[] __initconst = {
++	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
++	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
++};
++static const u8 xenc_key001[] __initconst = {
++	0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a,
++	0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0,
++	0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09,
++	0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0
++};
++
++static const struct chacha20poly1305_testvec
++xchacha20poly1305_enc_vectors[] __initconst = {
++	{ xenc_input001, xenc_output001, xenc_assoc001, xenc_nonce001, xenc_key001,
++	  sizeof(xenc_input001), sizeof(xenc_assoc001), sizeof(xenc_nonce001) }
++};
++
++static const u8 xdec_input001[] __initconst = {
++	0x1a, 0x6e, 0x3a, 0xd9, 0xfd, 0x41, 0x3f, 0x77,
++	0x54, 0x72, 0x0a, 0x70, 0x9a, 0xa0, 0x29, 0x92,
++	0x2e, 0xed, 0x93, 0xcf, 0x0f, 0x71, 0x88, 0x18,
++	0x7a, 0x9d, 0x2d, 0x24, 0xe0, 0xf5, 0xea, 0x3d,
++	0x55, 0x64, 0xd7, 0xad, 0x2a, 0x1a, 0x1f, 0x7e,
++	0x86, 0x6d, 0xb0, 0xce, 0x80, 0x41, 0x72, 0x86,
++	0x26, 0xee, 0x84, 0xd7, 0xef, 0x82, 0x9e, 0xe2,
++	0x60, 0x9d, 0x5a, 0xfc, 0xf0, 0xe4, 0x19, 0x85,
++	0xea, 0x09, 0xc6, 0xfb, 0xb3, 0xa9, 0x50, 0x09,
++	0xec, 0x5e, 0x11, 0x90, 0xa1, 0xc5, 0x4e, 0x49,
++	0xef, 0x50, 0xd8, 0x8f, 0xe0, 0x78, 0xd7, 0xfd,
++	0xb9, 0x3b, 0xc9, 0xf2, 0x91, 0xc8, 0x25, 0xc8,
++	0xa7, 0x63, 0x60, 0xce, 0x10, 0xcd, 0xc6, 0x7f,
++	0xf8, 0x16, 0xf8, 0xe1, 0x0a, 0xd9, 0xde, 0x79,
++	0x50, 0x33, 0xf2, 0x16, 0x0f, 0x17, 0xba, 0xb8,
++	0x5d, 0xd8, 0xdf, 0x4e, 0x51, 0xa8, 0x39, 0xd0,
++	0x85, 0xca, 0x46, 0x6a, 0x10, 0xa7, 0xa3, 0x88,
++	0xef, 0x79, 0xb9, 0xf8, 0x24, 0xf3, 0xe0, 0x71,
++	0x7b, 0x76, 0x28, 0x46, 0x3a, 0x3a, 0x1b, 0x91,
++	0xb6, 0xd4, 0x3e, 0x23, 0xe5, 0x44, 0x15, 0xbf,
++	0x60, 0x43, 0x9d, 0xa4, 0xbb, 0xd5, 0x5f, 0x89,
++	0xeb, 0xef, 0x8e, 0xfd, 0xdd, 0xb4, 0x0d, 0x46,
++	0xf0, 0x69, 0x23, 0x63, 0xae, 0x94, 0xf5, 0x5e,
++	0xa5, 0xad, 0x13, 0x1c, 0x41, 0x76, 0xe6, 0x90,
++	0xd6, 0x6d, 0xa2, 0x8f, 0x97, 0x4c, 0xa8, 0x0b,
++	0xcf, 0x8d, 0x43, 0x2b, 0x9c, 0x9b, 0xc5, 0x58,
++	0xa5, 0xb6, 0x95, 0x9a, 0xbf, 0x81, 0xc6, 0x54,
++	0xc9, 0x66, 0x0c, 0xe5, 0x4f, 0x6a, 0x53, 0xa1,
++	0xe5, 0x0c, 0xba, 0x31, 0xde, 0x34, 0x64, 0x73,
++	0x8a, 0x3b, 0xbd, 0x92, 0x01, 0xdb, 0x71, 0x69,
++	0xf3, 0x58, 0x99, 0xbc, 0xd1, 0xcb, 0x4a, 0x05,
++	0xe2, 0x58, 0x9c, 0x25, 0x17, 0xcd, 0xdc, 0x83,
++	0xb7, 0xff, 0xfb, 0x09, 0x61, 0xad, 0xbf, 0x13,
++	0x5b, 0x5e, 0xed, 0x46, 0x82, 0x6f, 0x22, 0xd8,
++	0x93, 0xa6, 0x85, 0x5b, 0x40, 0x39, 0x5c, 0xc5,
++	0x9c
++};
++static const u8 xdec_output001[] __initconst = {
++	0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
++	0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x73, 0x20,
++	0x61, 0x72, 0x65, 0x20, 0x64, 0x72, 0x61, 0x66,
++	0x74, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65,
++	0x6e, 0x74, 0x73, 0x20, 0x76, 0x61, 0x6c, 0x69,
++	0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20,
++	0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20,
++	0x6f, 0x66, 0x20, 0x73, 0x69, 0x78, 0x20, 0x6d,
++	0x6f, 0x6e, 0x74, 0x68, 0x73, 0x20, 0x61, 0x6e,
++	0x64, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65,
++	0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64,
++	0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63,
++	0x65, 0x64, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x6f,
++	0x62, 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x64,
++	0x20, 0x62, 0x79, 0x20, 0x6f, 0x74, 0x68, 0x65,
++	0x72, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65,
++	0x6e, 0x74, 0x73, 0x20, 0x61, 0x74, 0x20, 0x61,
++	0x6e, 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x2e,
++	0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x69,
++	0x6e, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x70, 0x72,
++	0x69, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20,
++	0x75, 0x73, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65,
++	0x72, 0x6e, 0x65, 0x74, 0x2d, 0x44, 0x72, 0x61,
++	0x66, 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x72,
++	0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65,
++	0x20, 0x6d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61,
++	0x6c, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20,
++	0x63, 0x69, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65,
++	0x6d, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20,
++	0x74, 0x68, 0x61, 0x6e, 0x20, 0x61, 0x73, 0x20,
++	0x2f, 0xe2, 0x80, 0x9c, 0x77, 0x6f, 0x72, 0x6b,
++	0x20, 0x69, 0x6e, 0x20, 0x70, 0x72, 0x6f, 0x67,
++	0x72, 0x65, 0x73, 0x73, 0x2e, 0x2f, 0xe2, 0x80,
++	0x9d
++};
++static const u8 xdec_assoc001[] __initconst = {
++	0xf3, 0x33, 0x88, 0x86, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x4e, 0x91
++};
++static const u8 xdec_nonce001[] __initconst = {
++	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
++	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
++};
++static const u8 xdec_key001[] __initconst = {
++	0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a,
++	0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0,
++	0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09,
++	0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0
++};
++
++static const struct chacha20poly1305_testvec
++xchacha20poly1305_dec_vectors[] __initconst = {
++	{ xdec_input001, xdec_output001, xdec_assoc001, xdec_nonce001, xdec_key001,
++	  sizeof(xdec_input001), sizeof(xdec_assoc001), sizeof(xdec_nonce001) }
++};
++
++static void __init
++chacha20poly1305_selftest_encrypt(u8 *dst, const u8 *src, const size_t src_len,
++				  const u8 *ad, const size_t ad_len,
++				  const u8 *nonce, const size_t nonce_len,
++				  const u8 key[CHACHA20POLY1305_KEY_SIZE])
++{
++	if (nonce_len == 8)
++		chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len,
++					 get_unaligned_le64(nonce), key);
++	else
++		BUG();
++}
++
++static bool __init
++decryption_success(bool func_ret, bool expect_failure, int memcmp_result)
++{
++	if (expect_failure)
++		return !func_ret;
++	return func_ret && !memcmp_result;
++}
++
++bool __init chacha20poly1305_selftest(void)
++{
++	enum { MAXIMUM_TEST_BUFFER_LEN = 1UL << 12 };
++	size_t i;
++	u8 *computed_output = NULL, *heap_src = NULL;
++	bool success = true, ret;
++
++	heap_src = kmalloc(MAXIMUM_TEST_BUFFER_LEN, GFP_KERNEL);
++	computed_output = kmalloc(MAXIMUM_TEST_BUFFER_LEN, GFP_KERNEL);
++	if (!heap_src || !computed_output) {
++		pr_err("chacha20poly1305 self-test malloc: FAIL\n");
++		success = false;
++		goto out;
++	}
++
++	for (i = 0; i < ARRAY_SIZE(chacha20poly1305_enc_vectors); ++i) {
++		memset(computed_output, 0, MAXIMUM_TEST_BUFFER_LEN);
++		chacha20poly1305_selftest_encrypt(computed_output,
++					chacha20poly1305_enc_vectors[i].input,
++					chacha20poly1305_enc_vectors[i].ilen,
++					chacha20poly1305_enc_vectors[i].assoc,
++					chacha20poly1305_enc_vectors[i].alen,
++					chacha20poly1305_enc_vectors[i].nonce,
++					chacha20poly1305_enc_vectors[i].nlen,
++					chacha20poly1305_enc_vectors[i].key);
++		if (memcmp(computed_output,
++			   chacha20poly1305_enc_vectors[i].output,
++			   chacha20poly1305_enc_vectors[i].ilen +
++							POLY1305_DIGEST_SIZE)) {
++			pr_err("chacha20poly1305 encryption self-test %zu: FAIL\n",
++			       i + 1);
++			success = false;
++		}
++	}
++
++	for (i = 0; i < ARRAY_SIZE(chacha20poly1305_dec_vectors); ++i) {
++		memset(computed_output, 0, MAXIMUM_TEST_BUFFER_LEN);
++		ret = chacha20poly1305_decrypt(computed_output,
++			chacha20poly1305_dec_vectors[i].input,
++			chacha20poly1305_dec_vectors[i].ilen,
++			chacha20poly1305_dec_vectors[i].assoc,
++			chacha20poly1305_dec_vectors[i].alen,
++			get_unaligned_le64(chacha20poly1305_dec_vectors[i].nonce),
++			chacha20poly1305_dec_vectors[i].key);
++		if (!decryption_success(ret,
++				chacha20poly1305_dec_vectors[i].failure,
++				memcmp(computed_output,
++				       chacha20poly1305_dec_vectors[i].output,
++				       chacha20poly1305_dec_vectors[i].ilen -
++							POLY1305_DIGEST_SIZE))) {
++			pr_err("chacha20poly1305 decryption self-test %zu: FAIL\n",
++			       i + 1);
++			success = false;
++		}
++	}
++
++
++	for (i = 0; i < ARRAY_SIZE(xchacha20poly1305_enc_vectors); ++i) {
++		memset(computed_output, 0, MAXIMUM_TEST_BUFFER_LEN);
++		xchacha20poly1305_encrypt(computed_output,
++					xchacha20poly1305_enc_vectors[i].input,
++					xchacha20poly1305_enc_vectors[i].ilen,
++					xchacha20poly1305_enc_vectors[i].assoc,
++					xchacha20poly1305_enc_vectors[i].alen,
++					xchacha20poly1305_enc_vectors[i].nonce,
++					xchacha20poly1305_enc_vectors[i].key);
++		if (memcmp(computed_output,
++			   xchacha20poly1305_enc_vectors[i].output,
++			   xchacha20poly1305_enc_vectors[i].ilen +
++							POLY1305_DIGEST_SIZE)) {
++			pr_err("xchacha20poly1305 encryption self-test %zu: FAIL\n",
++			       i + 1);
++			success = false;
++		}
++	}
++	for (i = 0; i < ARRAY_SIZE(xchacha20poly1305_dec_vectors); ++i) {
++		memset(computed_output, 0, MAXIMUM_TEST_BUFFER_LEN);
++		ret = xchacha20poly1305_decrypt(computed_output,
++					xchacha20poly1305_dec_vectors[i].input,
++					xchacha20poly1305_dec_vectors[i].ilen,
++					xchacha20poly1305_dec_vectors[i].assoc,
++					xchacha20poly1305_dec_vectors[i].alen,
++					xchacha20poly1305_dec_vectors[i].nonce,
++					xchacha20poly1305_dec_vectors[i].key);
++		if (!decryption_success(ret,
++				xchacha20poly1305_dec_vectors[i].failure,
++				memcmp(computed_output,
++				       xchacha20poly1305_dec_vectors[i].output,
++				       xchacha20poly1305_dec_vectors[i].ilen -
++							POLY1305_DIGEST_SIZE))) {
++			pr_err("xchacha20poly1305 decryption self-test %zu: FAIL\n",
++			       i + 1);
++			success = false;
++		}
++	}
++
++out:
++	kfree(heap_src);
++	kfree(computed_output);
++	return success;
++}
+--- /dev/null
++++ b/lib/crypto/chacha20poly1305.c
+@@ -0,0 +1,219 @@
++// SPDX-License-Identifier: GPL-2.0 OR MIT
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ *
++ * This is an implementation of the ChaCha20Poly1305 AEAD construction.
++ *
++ * Information: https://tools.ietf.org/html/rfc8439
++ */
++
++#include <crypto/algapi.h>
++#include <crypto/chacha20poly1305.h>
++#include <crypto/chacha.h>
++#include <crypto/poly1305.h>
++
++#include <asm/unaligned.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++
++#define CHACHA_KEY_WORDS	(CHACHA_KEY_SIZE / sizeof(u32))
++
++bool __init chacha20poly1305_selftest(void);
++
++static void chacha_load_key(u32 *k, const u8 *in)
++{
++	k[0] = get_unaligned_le32(in);
++	k[1] = get_unaligned_le32(in + 4);
++	k[2] = get_unaligned_le32(in + 8);
++	k[3] = get_unaligned_le32(in + 12);
++	k[4] = get_unaligned_le32(in + 16);
++	k[5] = get_unaligned_le32(in + 20);
++	k[6] = get_unaligned_le32(in + 24);
++	k[7] = get_unaligned_le32(in + 28);
++}
++
++static void xchacha_init(u32 *chacha_state, const u8 *key, const u8 *nonce)
++{
++	u32 k[CHACHA_KEY_WORDS];
++	u8 iv[CHACHA_IV_SIZE];
++
++	memset(iv, 0, 8);
++	memcpy(iv + 8, nonce + 16, 8);
++
++	chacha_load_key(k, key);
++
++	/* Compute the subkey given the original key and first 128 nonce bits */
++	chacha_init(chacha_state, k, nonce);
++	hchacha_block(chacha_state, k, 20);
++
++	chacha_init(chacha_state, k, iv);
++
++	memzero_explicit(k, sizeof(k));
++	memzero_explicit(iv, sizeof(iv));
++}
++
++static void
++__chacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len,
++			   const u8 *ad, const size_t ad_len, u32 *chacha_state)
++{
++	const u8 *pad0 = page_address(ZERO_PAGE(0));
++	struct poly1305_desc_ctx poly1305_state;
++	union {
++		u8 block0[POLY1305_KEY_SIZE];
++		__le64 lens[2];
++	} b;
++
++	chacha_crypt(chacha_state, b.block0, pad0, sizeof(b.block0), 20);
++	poly1305_init(&poly1305_state, b.block0);
++
++	poly1305_update(&poly1305_state, ad, ad_len);
++	if (ad_len & 0xf)
++		poly1305_update(&poly1305_state, pad0, 0x10 - (ad_len & 0xf));
++
++	chacha_crypt(chacha_state, dst, src, src_len, 20);
++
++	poly1305_update(&poly1305_state, dst, src_len);
++	if (src_len & 0xf)
++		poly1305_update(&poly1305_state, pad0, 0x10 - (src_len & 0xf));
++
++	b.lens[0] = cpu_to_le64(ad_len);
++	b.lens[1] = cpu_to_le64(src_len);
++	poly1305_update(&poly1305_state, (u8 *)b.lens, sizeof(b.lens));
++
++	poly1305_final(&poly1305_state, dst + src_len);
++
++	memzero_explicit(chacha_state, CHACHA_STATE_WORDS * sizeof(u32));
++	memzero_explicit(&b, sizeof(b));
++}
++
++void chacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len,
++			      const u8 *ad, const size_t ad_len,
++			      const u64 nonce,
++			      const u8 key[CHACHA20POLY1305_KEY_SIZE])
++{
++	u32 chacha_state[CHACHA_STATE_WORDS];
++	u32 k[CHACHA_KEY_WORDS];
++	__le64 iv[2];
++
++	chacha_load_key(k, key);
++
++	iv[0] = 0;
++	iv[1] = cpu_to_le64(nonce);
++
++	chacha_init(chacha_state, k, (u8 *)iv);
++	__chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, chacha_state);
++
++	memzero_explicit(iv, sizeof(iv));
++	memzero_explicit(k, sizeof(k));
++}
++EXPORT_SYMBOL(chacha20poly1305_encrypt);
++
++void xchacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len,
++			       const u8 *ad, const size_t ad_len,
++			       const u8 nonce[XCHACHA20POLY1305_NONCE_SIZE],
++			       const u8 key[CHACHA20POLY1305_KEY_SIZE])
++{
++	u32 chacha_state[CHACHA_STATE_WORDS];
++
++	xchacha_init(chacha_state, key, nonce);
++	__chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, chacha_state);
++}
++EXPORT_SYMBOL(xchacha20poly1305_encrypt);
++
++static bool
++__chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len,
++			   const u8 *ad, const size_t ad_len, u32 *chacha_state)
++{
++	const u8 *pad0 = page_address(ZERO_PAGE(0));
++	struct poly1305_desc_ctx poly1305_state;
++	size_t dst_len;
++	int ret;
++	union {
++		u8 block0[POLY1305_KEY_SIZE];
++		u8 mac[POLY1305_DIGEST_SIZE];
++		__le64 lens[2];
++	} b;
++
++	if (unlikely(src_len < POLY1305_DIGEST_SIZE))
++		return false;
++
++	chacha_crypt(chacha_state, b.block0, pad0, sizeof(b.block0), 20);
++	poly1305_init(&poly1305_state, b.block0);
++
++	poly1305_update(&poly1305_state, ad, ad_len);
++	if (ad_len & 0xf)
++		poly1305_update(&poly1305_state, pad0, 0x10 - (ad_len & 0xf));
++
++	dst_len = src_len - POLY1305_DIGEST_SIZE;
++	poly1305_update(&poly1305_state, src, dst_len);
++	if (dst_len & 0xf)
++		poly1305_update(&poly1305_state, pad0, 0x10 - (dst_len & 0xf));
++
++	b.lens[0] = cpu_to_le64(ad_len);
++	b.lens[1] = cpu_to_le64(dst_len);
++	poly1305_update(&poly1305_state, (u8 *)b.lens, sizeof(b.lens));
++
++	poly1305_final(&poly1305_state, b.mac);
++
++	ret = crypto_memneq(b.mac, src + dst_len, POLY1305_DIGEST_SIZE);
++	if (likely(!ret))
++		chacha_crypt(chacha_state, dst, src, dst_len, 20);
++
++	memzero_explicit(&b, sizeof(b));
++
++	return !ret;
++}
++
++bool chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len,
++			      const u8 *ad, const size_t ad_len,
++			      const u64 nonce,
++			      const u8 key[CHACHA20POLY1305_KEY_SIZE])
++{
++	u32 chacha_state[CHACHA_STATE_WORDS];
++	u32 k[CHACHA_KEY_WORDS];
++	__le64 iv[2];
++	bool ret;
++
++	chacha_load_key(k, key);
++
++	iv[0] = 0;
++	iv[1] = cpu_to_le64(nonce);
++
++	chacha_init(chacha_state, k, (u8 *)iv);
++	ret = __chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len,
++					 chacha_state);
++
++	memzero_explicit(chacha_state, sizeof(chacha_state));
++	memzero_explicit(iv, sizeof(iv));
++	memzero_explicit(k, sizeof(k));
++	return ret;
++}
++EXPORT_SYMBOL(chacha20poly1305_decrypt);
++
++bool xchacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len,
++			       const u8 *ad, const size_t ad_len,
++			       const u8 nonce[XCHACHA20POLY1305_NONCE_SIZE],
++			       const u8 key[CHACHA20POLY1305_KEY_SIZE])
++{
++	u32 chacha_state[CHACHA_STATE_WORDS];
++
++	xchacha_init(chacha_state, key, nonce);
++	return __chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len,
++					  chacha_state);
++}
++EXPORT_SYMBOL(xchacha20poly1305_decrypt);
++
++static int __init mod_init(void)
++{
++	if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) &&
++	    WARN_ON(!chacha20poly1305_selftest()))
++		return -ENODEV;
++	return 0;
++}
++
++module_init(mod_init);
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("ChaCha20Poly1305 AEAD construction");
++MODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0033-crypto-lib-chacha20poly1305-reimplement-crypt_from_s.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0033-crypto-lib-chacha20poly1305-reimplement-crypt_from_s.patch
new file mode 100644
index 0000000..e4b2b58
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0033-crypto-lib-chacha20poly1305-reimplement-crypt_from_s.patch
@@ -0,0 +1,295 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 8 Nov 2019 13:22:40 +0100
+Subject: [PATCH] crypto: lib/chacha20poly1305 - reimplement crypt_from_sg()
+ routine
+
+commit d95312a3ccc0cd544d374be2fc45aeaa803e5fd9 upstream.
+
+Reimplement the library routines to perform chacha20poly1305 en/decryption
+on scatterlists, without [ab]using the [deprecated] blkcipher interface,
+which is rather heavyweight and does things we don't really need.
+
+Instead, we use the sg_miter API in a novel and clever way, to iterate
+over the scatterlist in-place (i.e., source == destination, which is the
+only way this library is expected to be used). That way, we don't have to
+iterate over two scatterlists in parallel.
+
+Another optimization is that, instead of relying on the blkcipher walker
+to present the input in suitable chunks, we recognize that ChaCha is a
+streamcipher, and so we can simply deal with partial blocks by keeping a
+block of cipherstream on the stack and use crypto_xor() to mix it with
+the in/output.
+
+Finally, we omit the scatterwalk_and_copy() call if the last element of
+the scatterlist covers the MAC as well (which is the common case),
+avoiding the need to walk the scatterlist and kmap() the page twice.
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ include/crypto/chacha20poly1305.h      |  11 ++
+ lib/crypto/chacha20poly1305-selftest.c |  45 ++++++++
+ lib/crypto/chacha20poly1305.c          | 150 +++++++++++++++++++++++++
+ 3 files changed, 206 insertions(+)
+
+--- a/include/crypto/chacha20poly1305.h
++++ b/include/crypto/chacha20poly1305.h
+@@ -7,6 +7,7 @@
+ #define __CHACHA20POLY1305_H
+ 
+ #include <linux/types.h>
++#include <linux/scatterlist.h>
+ 
+ enum chacha20poly1305_lengths {
+ 	XCHACHA20POLY1305_NONCE_SIZE = 24,
+@@ -34,4 +35,14 @@ bool __must_check xchacha20poly1305_decr
+ 	const size_t ad_len, const u8 nonce[XCHACHA20POLY1305_NONCE_SIZE],
+ 	const u8 key[CHACHA20POLY1305_KEY_SIZE]);
+ 
++bool chacha20poly1305_encrypt_sg_inplace(struct scatterlist *src, size_t src_len,
++					 const u8 *ad, const size_t ad_len,
++					 const u64 nonce,
++					 const u8 key[CHACHA20POLY1305_KEY_SIZE]);
++
++bool chacha20poly1305_decrypt_sg_inplace(struct scatterlist *src, size_t src_len,
++					 const u8 *ad, const size_t ad_len,
++					 const u64 nonce,
++					 const u8 key[CHACHA20POLY1305_KEY_SIZE]);
++
+ #endif /* __CHACHA20POLY1305_H */
+--- a/lib/crypto/chacha20poly1305-selftest.c
++++ b/lib/crypto/chacha20poly1305-selftest.c
+@@ -7250,6 +7250,7 @@ bool __init chacha20poly1305_selftest(vo
+ 	enum { MAXIMUM_TEST_BUFFER_LEN = 1UL << 12 };
+ 	size_t i;
+ 	u8 *computed_output = NULL, *heap_src = NULL;
++	struct scatterlist sg_src;
+ 	bool success = true, ret;
+ 
+ 	heap_src = kmalloc(MAXIMUM_TEST_BUFFER_LEN, GFP_KERNEL);
+@@ -7280,6 +7281,29 @@ bool __init chacha20poly1305_selftest(vo
+ 		}
+ 	}
+ 
++	for (i = 0; i < ARRAY_SIZE(chacha20poly1305_enc_vectors); ++i) {
++		if (chacha20poly1305_enc_vectors[i].nlen != 8)
++			continue;
++		memcpy(heap_src, chacha20poly1305_enc_vectors[i].input,
++		       chacha20poly1305_enc_vectors[i].ilen);
++		sg_init_one(&sg_src, heap_src,
++			    chacha20poly1305_enc_vectors[i].ilen + POLY1305_DIGEST_SIZE);
++		chacha20poly1305_encrypt_sg_inplace(&sg_src,
++			chacha20poly1305_enc_vectors[i].ilen,
++			chacha20poly1305_enc_vectors[i].assoc,
++			chacha20poly1305_enc_vectors[i].alen,
++			get_unaligned_le64(chacha20poly1305_enc_vectors[i].nonce),
++			chacha20poly1305_enc_vectors[i].key);
++		if (memcmp(heap_src,
++				   chacha20poly1305_enc_vectors[i].output,
++				   chacha20poly1305_enc_vectors[i].ilen +
++							POLY1305_DIGEST_SIZE)) {
++			pr_err("chacha20poly1305 sg encryption self-test %zu: FAIL\n",
++			       i + 1);
++			success = false;
++		}
++	}
++
+ 	for (i = 0; i < ARRAY_SIZE(chacha20poly1305_dec_vectors); ++i) {
+ 		memset(computed_output, 0, MAXIMUM_TEST_BUFFER_LEN);
+ 		ret = chacha20poly1305_decrypt(computed_output,
+@@ -7301,6 +7325,27 @@ bool __init chacha20poly1305_selftest(vo
+ 		}
+ 	}
+ 
++	for (i = 0; i < ARRAY_SIZE(chacha20poly1305_dec_vectors); ++i) {
++		memcpy(heap_src, chacha20poly1305_dec_vectors[i].input,
++		       chacha20poly1305_dec_vectors[i].ilen);
++		sg_init_one(&sg_src, heap_src,
++			    chacha20poly1305_dec_vectors[i].ilen);
++		ret = chacha20poly1305_decrypt_sg_inplace(&sg_src,
++			chacha20poly1305_dec_vectors[i].ilen,
++			chacha20poly1305_dec_vectors[i].assoc,
++			chacha20poly1305_dec_vectors[i].alen,
++			get_unaligned_le64(chacha20poly1305_dec_vectors[i].nonce),
++			chacha20poly1305_dec_vectors[i].key);
++		if (!decryption_success(ret,
++			chacha20poly1305_dec_vectors[i].failure,
++			memcmp(heap_src, chacha20poly1305_dec_vectors[i].output,
++			       chacha20poly1305_dec_vectors[i].ilen -
++							POLY1305_DIGEST_SIZE))) {
++			pr_err("chacha20poly1305 sg decryption self-test %zu: FAIL\n",
++			       i + 1);
++			success = false;
++		}
++	}
+ 
+ 	for (i = 0; i < ARRAY_SIZE(xchacha20poly1305_enc_vectors); ++i) {
+ 		memset(computed_output, 0, MAXIMUM_TEST_BUFFER_LEN);
+--- a/lib/crypto/chacha20poly1305.c
++++ b/lib/crypto/chacha20poly1305.c
+@@ -11,6 +11,7 @@
+ #include <crypto/chacha20poly1305.h>
+ #include <crypto/chacha.h>
+ #include <crypto/poly1305.h>
++#include <crypto/scatterwalk.h>
+ 
+ #include <asm/unaligned.h>
+ #include <linux/kernel.h>
+@@ -205,6 +206,155 @@ bool xchacha20poly1305_decrypt(u8 *dst,
+ }
+ EXPORT_SYMBOL(xchacha20poly1305_decrypt);
+ 
++static
++bool chacha20poly1305_crypt_sg_inplace(struct scatterlist *src,
++				       const size_t src_len,
++				       const u8 *ad, const size_t ad_len,
++				       const u64 nonce,
++				       const u8 key[CHACHA20POLY1305_KEY_SIZE],
++				       int encrypt)
++{
++	const u8 *pad0 = page_address(ZERO_PAGE(0));
++	struct poly1305_desc_ctx poly1305_state;
++	u32 chacha_state[CHACHA_STATE_WORDS];
++	struct sg_mapping_iter miter;
++	size_t partial = 0;
++	unsigned int flags;
++	bool ret = true;
++	int sl;
++	union {
++		struct {
++			u32 k[CHACHA_KEY_WORDS];
++			__le64 iv[2];
++		};
++		u8 block0[POLY1305_KEY_SIZE];
++		u8 chacha_stream[CHACHA_BLOCK_SIZE];
++		struct {
++			u8 mac[2][POLY1305_DIGEST_SIZE];
++		};
++		__le64 lens[2];
++	} b __aligned(16);
++
++	chacha_load_key(b.k, key);
++
++	b.iv[0] = 0;
++	b.iv[1] = cpu_to_le64(nonce);
++
++	chacha_init(chacha_state, b.k, (u8 *)b.iv);
++	chacha_crypt(chacha_state, b.block0, pad0, sizeof(b.block0), 20);
++	poly1305_init(&poly1305_state, b.block0);
++
++	if (unlikely(ad_len)) {
++		poly1305_update(&poly1305_state, ad, ad_len);
++		if (ad_len & 0xf)
++			poly1305_update(&poly1305_state, pad0, 0x10 - (ad_len & 0xf));
++	}
++
++	flags = SG_MITER_TO_SG;
++	if (!preemptible())
++		flags |= SG_MITER_ATOMIC;
++
++	sg_miter_start(&miter, src, sg_nents(src), flags);
++
++	for (sl = src_len; sl > 0 && sg_miter_next(&miter); sl -= miter.length) {
++		u8 *addr = miter.addr;
++		size_t length = min_t(size_t, sl, miter.length);
++
++		if (!encrypt)
++			poly1305_update(&poly1305_state, addr, length);
++
++		if (unlikely(partial)) {
++			size_t l = min(length, CHACHA_BLOCK_SIZE - partial);
++
++			crypto_xor(addr, b.chacha_stream + partial, l);
++			partial = (partial + l) & (CHACHA_BLOCK_SIZE - 1);
++
++			addr += l;
++			length -= l;
++		}
++
++		if (likely(length >= CHACHA_BLOCK_SIZE || length == sl)) {
++			size_t l = length;
++
++			if (unlikely(length < sl))
++				l &= ~(CHACHA_BLOCK_SIZE - 1);
++			chacha_crypt(chacha_state, addr, addr, l, 20);
++			addr += l;
++			length -= l;
++		}
++
++		if (unlikely(length > 0)) {
++			chacha_crypt(chacha_state, b.chacha_stream, pad0,
++				     CHACHA_BLOCK_SIZE, 20);
++			crypto_xor(addr, b.chacha_stream, length);
++			partial = length;
++		}
++
++		if (encrypt)
++			poly1305_update(&poly1305_state, miter.addr,
++					min_t(size_t, sl, miter.length));
++	}
++
++	if (src_len & 0xf)
++		poly1305_update(&poly1305_state, pad0, 0x10 - (src_len & 0xf));
++
++	b.lens[0] = cpu_to_le64(ad_len);
++	b.lens[1] = cpu_to_le64(src_len);
++	poly1305_update(&poly1305_state, (u8 *)b.lens, sizeof(b.lens));
++
++	if (likely(sl <= -POLY1305_DIGEST_SIZE)) {
++		if (encrypt) {
++			poly1305_final(&poly1305_state,
++				       miter.addr + miter.length + sl);
++			ret = true;
++		} else {
++			poly1305_final(&poly1305_state, b.mac[0]);
++			ret = !crypto_memneq(b.mac[0],
++					     miter.addr + miter.length + sl,
++					     POLY1305_DIGEST_SIZE);
++		}
++	}
++
++	sg_miter_stop(&miter);
++
++	if (unlikely(sl > -POLY1305_DIGEST_SIZE)) {
++		poly1305_final(&poly1305_state, b.mac[1]);
++		scatterwalk_map_and_copy(b.mac[encrypt], src, src_len,
++					 sizeof(b.mac[1]), encrypt);
++		ret = encrypt ||
++		      !crypto_memneq(b.mac[0], b.mac[1], POLY1305_DIGEST_SIZE);
++	}
++
++	memzero_explicit(chacha_state, sizeof(chacha_state));
++	memzero_explicit(&b, sizeof(b));
++
++	return ret;
++}
++
++bool chacha20poly1305_encrypt_sg_inplace(struct scatterlist *src, size_t src_len,
++					 const u8 *ad, const size_t ad_len,
++					 const u64 nonce,
++					 const u8 key[CHACHA20POLY1305_KEY_SIZE])
++{
++	return chacha20poly1305_crypt_sg_inplace(src, src_len, ad, ad_len,
++						 nonce, key, 1);
++}
++EXPORT_SYMBOL(chacha20poly1305_encrypt_sg_inplace);
++
++bool chacha20poly1305_decrypt_sg_inplace(struct scatterlist *src, size_t src_len,
++					 const u8 *ad, const size_t ad_len,
++					 const u64 nonce,
++					 const u8 key[CHACHA20POLY1305_KEY_SIZE])
++{
++	if (unlikely(src_len < POLY1305_DIGEST_SIZE))
++		return false;
++
++	return chacha20poly1305_crypt_sg_inplace(src,
++						 src_len - POLY1305_DIGEST_SIZE,
++						 ad, ad_len, nonce, key, 0);
++}
++EXPORT_SYMBOL(chacha20poly1305_decrypt_sg_inplace);
++
+ static int __init mod_init(void)
+ {
+ 	if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) &&
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0034-crypto-chacha_generic-remove-unnecessary-setkey-func.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0034-crypto-chacha_generic-remove-unnecessary-setkey-func.patch
new file mode 100644
index 0000000..709b1fb
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0034-crypto-chacha_generic-remove-unnecessary-setkey-func.patch
@@ -0,0 +1,68 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@google.com>
+Date: Sun, 17 Nov 2019 23:21:29 -0800
+Subject: [PATCH] crypto: chacha_generic - remove unnecessary setkey()
+ functions
+
+commit 2043323a799a660bc84bbee404cf7a2617ec6157 upstream.
+
+Use chacha20_setkey() and chacha12_setkey() from
+<crypto/internal/chacha.h> instead of defining them again in
+chacha_generic.c.
+
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Acked-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ crypto/chacha_generic.c | 18 +++---------------
+ 1 file changed, 3 insertions(+), 15 deletions(-)
+
+--- a/crypto/chacha_generic.c
++++ b/crypto/chacha_generic.c
+@@ -37,18 +37,6 @@ static int chacha_stream_xor(struct skci
+ 	return err;
+ }
+ 
+-static int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key,
+-				  unsigned int keysize)
+-{
+-	return chacha_setkey(tfm, key, keysize, 20);
+-}
+-
+-static int crypto_chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key,
+-				 unsigned int keysize)
+-{
+-	return chacha_setkey(tfm, key, keysize, 12);
+-}
+-
+ static int crypto_chacha_crypt(struct skcipher_request *req)
+ {
+ 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+@@ -91,7 +79,7 @@ static struct skcipher_alg algs[] = {
+ 		.max_keysize		= CHACHA_KEY_SIZE,
+ 		.ivsize			= CHACHA_IV_SIZE,
+ 		.chunksize		= CHACHA_BLOCK_SIZE,
+-		.setkey			= crypto_chacha20_setkey,
++		.setkey			= chacha20_setkey,
+ 		.encrypt		= crypto_chacha_crypt,
+ 		.decrypt		= crypto_chacha_crypt,
+ 	}, {
+@@ -106,7 +94,7 @@ static struct skcipher_alg algs[] = {
+ 		.max_keysize		= CHACHA_KEY_SIZE,
+ 		.ivsize			= XCHACHA_IV_SIZE,
+ 		.chunksize		= CHACHA_BLOCK_SIZE,
+-		.setkey			= crypto_chacha20_setkey,
++		.setkey			= chacha20_setkey,
+ 		.encrypt		= crypto_xchacha_crypt,
+ 		.decrypt		= crypto_xchacha_crypt,
+ 	}, {
+@@ -121,7 +109,7 @@ static struct skcipher_alg algs[] = {
+ 		.max_keysize		= CHACHA_KEY_SIZE,
+ 		.ivsize			= XCHACHA_IV_SIZE,
+ 		.chunksize		= CHACHA_BLOCK_SIZE,
+-		.setkey			= crypto_chacha12_setkey,
++		.setkey			= chacha12_setkey,
+ 		.encrypt		= crypto_xchacha_crypt,
+ 		.decrypt		= crypto_xchacha_crypt,
+ 	}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0035-crypto-x86-chacha-only-unregister-algorithms-if-regi.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0035-crypto-x86-chacha-only-unregister-algorithms-if-regi.patch
new file mode 100644
index 0000000..4554ea8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0035-crypto-x86-chacha-only-unregister-algorithms-if-regi.patch
@@ -0,0 +1,31 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@google.com>
+Date: Sun, 17 Nov 2019 23:21:58 -0800
+Subject: [PATCH] crypto: x86/chacha - only unregister algorithms if registered
+
+commit b62755aed3a3f5ca9edd2718339ccea3b6bbbe57 upstream.
+
+It's not valid to call crypto_unregister_skciphers() without a prior
+call to crypto_register_skciphers().
+
+Fixes: 84e03fa39fbe ("crypto: x86/chacha - expose SIMD ChaCha routine as library function")
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Acked-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/chacha_glue.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/arch/x86/crypto/chacha_glue.c
++++ b/arch/x86/crypto/chacha_glue.c
+@@ -304,7 +304,8 @@ static int __init chacha_simd_mod_init(v
+ 
+ static void __exit chacha_simd_mod_fini(void)
+ {
+-	crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
++	if (boot_cpu_has(X86_FEATURE_SSSE3))
++		crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
+ }
+ 
+ module_init(chacha_simd_mod_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0036-crypto-lib-chacha20poly1305-use-chacha20_crypt.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0036-crypto-lib-chacha20poly1305-use-chacha20_crypt.patch
new file mode 100644
index 0000000..6ad20b9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0036-crypto-lib-chacha20poly1305-use-chacha20_crypt.patch
@@ -0,0 +1,83 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@google.com>
+Date: Sun, 17 Nov 2019 23:22:16 -0800
+Subject: [PATCH] crypto: lib/chacha20poly1305 - use chacha20_crypt()
+
+commit 413808b71e6204b0cc1eeaa77960f7c3cd381d33 upstream.
+
+Use chacha20_crypt() instead of chacha_crypt(), since it's not really
+appropriate for users of the ChaCha library API to be passing the number
+of rounds as an argument.
+
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Acked-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ lib/crypto/chacha20poly1305.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+--- a/lib/crypto/chacha20poly1305.c
++++ b/lib/crypto/chacha20poly1305.c
+@@ -66,14 +66,14 @@ __chacha20poly1305_encrypt(u8 *dst, cons
+ 		__le64 lens[2];
+ 	} b;
+ 
+-	chacha_crypt(chacha_state, b.block0, pad0, sizeof(b.block0), 20);
++	chacha20_crypt(chacha_state, b.block0, pad0, sizeof(b.block0));
+ 	poly1305_init(&poly1305_state, b.block0);
+ 
+ 	poly1305_update(&poly1305_state, ad, ad_len);
+ 	if (ad_len & 0xf)
+ 		poly1305_update(&poly1305_state, pad0, 0x10 - (ad_len & 0xf));
+ 
+-	chacha_crypt(chacha_state, dst, src, src_len, 20);
++	chacha20_crypt(chacha_state, dst, src, src_len);
+ 
+ 	poly1305_update(&poly1305_state, dst, src_len);
+ 	if (src_len & 0xf)
+@@ -140,7 +140,7 @@ __chacha20poly1305_decrypt(u8 *dst, cons
+ 	if (unlikely(src_len < POLY1305_DIGEST_SIZE))
+ 		return false;
+ 
+-	chacha_crypt(chacha_state, b.block0, pad0, sizeof(b.block0), 20);
++	chacha20_crypt(chacha_state, b.block0, pad0, sizeof(b.block0));
+ 	poly1305_init(&poly1305_state, b.block0);
+ 
+ 	poly1305_update(&poly1305_state, ad, ad_len);
+@@ -160,7 +160,7 @@ __chacha20poly1305_decrypt(u8 *dst, cons
+ 
+ 	ret = crypto_memneq(b.mac, src + dst_len, POLY1305_DIGEST_SIZE);
+ 	if (likely(!ret))
+-		chacha_crypt(chacha_state, dst, src, dst_len, 20);
++		chacha20_crypt(chacha_state, dst, src, dst_len);
+ 
+ 	memzero_explicit(&b, sizeof(b));
+ 
+@@ -241,7 +241,7 @@ bool chacha20poly1305_crypt_sg_inplace(s
+ 	b.iv[1] = cpu_to_le64(nonce);
+ 
+ 	chacha_init(chacha_state, b.k, (u8 *)b.iv);
+-	chacha_crypt(chacha_state, b.block0, pad0, sizeof(b.block0), 20);
++	chacha20_crypt(chacha_state, b.block0, pad0, sizeof(b.block0));
+ 	poly1305_init(&poly1305_state, b.block0);
+ 
+ 	if (unlikely(ad_len)) {
+@@ -278,14 +278,14 @@ bool chacha20poly1305_crypt_sg_inplace(s
+ 
+ 			if (unlikely(length < sl))
+ 				l &= ~(CHACHA_BLOCK_SIZE - 1);
+-			chacha_crypt(chacha_state, addr, addr, l, 20);
++			chacha20_crypt(chacha_state, addr, addr, l);
+ 			addr += l;
+ 			length -= l;
+ 		}
+ 
+ 		if (unlikely(length > 0)) {
+-			chacha_crypt(chacha_state, b.chacha_stream, pad0,
+-				     CHACHA_BLOCK_SIZE, 20);
++			chacha20_crypt(chacha_state, b.chacha_stream, pad0,
++				       CHACHA_BLOCK_SIZE);
+ 			crypto_xor(addr, b.chacha_stream, length);
+ 			partial = length;
+ 		}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0037-crypto-arch-conditionalize-crypto-api-in-arch-glue-f.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0037-crypto-arch-conditionalize-crypto-api-in-arch-glue-f.patch
new file mode 100644
index 0000000..d510438
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0037-crypto-arch-conditionalize-crypto-api-in-arch-glue-f.patch
@@ -0,0 +1,275 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Mon, 25 Nov 2019 11:31:12 +0100
+Subject: [PATCH] crypto: arch - conditionalize crypto api in arch glue for lib
+ code
+
+commit 8394bfec51e0e565556101bcc4e2fe7551104cd8 upstream.
+
+For glue code that's used by Zinc, the actual Crypto API functions might
+not necessarily exist, and don't need to exist either. Before this
+patch, there are valid build configurations that lead to a unbuildable
+kernel. This fixes it to conditionalize those symbols on the existence
+of the proper config entry.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Acked-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm/crypto/chacha-glue.c        | 26 ++++++++++++++++----------
+ arch/arm/crypto/curve25519-glue.c    |  5 +++--
+ arch/arm/crypto/poly1305-glue.c      |  9 ++++++---
+ arch/arm64/crypto/chacha-neon-glue.c |  5 +++--
+ arch/arm64/crypto/poly1305-glue.c    |  5 +++--
+ arch/mips/crypto/chacha-glue.c       |  6 ++++--
+ arch/mips/crypto/poly1305-glue.c     |  6 ++++--
+ arch/x86/crypto/blake2s-glue.c       |  6 ++++--
+ arch/x86/crypto/chacha_glue.c        |  5 +++--
+ arch/x86/crypto/curve25519-x86_64.c  |  7 ++++---
+ arch/x86/crypto/poly1305_glue.c      |  5 +++--
+ 11 files changed, 53 insertions(+), 32 deletions(-)
+
+--- a/arch/arm/crypto/chacha-glue.c
++++ b/arch/arm/crypto/chacha-glue.c
+@@ -286,11 +286,13 @@ static struct skcipher_alg neon_algs[] =
+ 
+ static int __init chacha_simd_mod_init(void)
+ {
+-	int err;
++	int err = 0;
+ 
+-	err = crypto_register_skciphers(arm_algs, ARRAY_SIZE(arm_algs));
+-	if (err)
+-		return err;
++	if (IS_REACHABLE(CONFIG_CRYPTO_BLKCIPHER)) {
++		err = crypto_register_skciphers(arm_algs, ARRAY_SIZE(arm_algs));
++		if (err)
++			return err;
++	}
+ 
+ 	if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && (elf_hwcap & HWCAP_NEON)) {
+ 		int i;
+@@ -310,18 +312,22 @@ static int __init chacha_simd_mod_init(v
+ 			static_branch_enable(&use_neon);
+ 		}
+ 
+-		err = crypto_register_skciphers(neon_algs, ARRAY_SIZE(neon_algs));
+-		if (err)
+-			crypto_unregister_skciphers(arm_algs, ARRAY_SIZE(arm_algs));
++		if (IS_REACHABLE(CONFIG_CRYPTO_BLKCIPHER)) {
++			err = crypto_register_skciphers(neon_algs, ARRAY_SIZE(neon_algs));
++			if (err)
++				crypto_unregister_skciphers(arm_algs, ARRAY_SIZE(arm_algs));
++		}
+ 	}
+ 	return err;
+ }
+ 
+ static void __exit chacha_simd_mod_fini(void)
+ {
+-	crypto_unregister_skciphers(arm_algs, ARRAY_SIZE(arm_algs));
+-	if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && (elf_hwcap & HWCAP_NEON))
+-		crypto_unregister_skciphers(neon_algs, ARRAY_SIZE(neon_algs));
++	if (IS_REACHABLE(CONFIG_CRYPTO_BLKCIPHER)) {
++		crypto_unregister_skciphers(arm_algs, ARRAY_SIZE(arm_algs));
++		if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && (elf_hwcap & HWCAP_NEON))
++			crypto_unregister_skciphers(neon_algs, ARRAY_SIZE(neon_algs));
++	}
+ }
+ 
+ module_init(chacha_simd_mod_init);
+--- a/arch/arm/crypto/curve25519-glue.c
++++ b/arch/arm/crypto/curve25519-glue.c
+@@ -108,14 +108,15 @@ static int __init mod_init(void)
+ {
+ 	if (elf_hwcap & HWCAP_NEON) {
+ 		static_branch_enable(&have_neon);
+-		return crypto_register_kpp(&curve25519_alg);
++		return IS_REACHABLE(CONFIG_CRYPTO_KPP) ?
++			crypto_register_kpp(&curve25519_alg) : 0;
+ 	}
+ 	return 0;
+ }
+ 
+ static void __exit mod_exit(void)
+ {
+-	if (elf_hwcap & HWCAP_NEON)
++	if (IS_REACHABLE(CONFIG_CRYPTO_KPP) && elf_hwcap & HWCAP_NEON)
+ 		crypto_unregister_kpp(&curve25519_alg);
+ }
+ 
+--- a/arch/arm/crypto/poly1305-glue.c
++++ b/arch/arm/crypto/poly1305-glue.c
+@@ -249,16 +249,19 @@ static int __init arm_poly1305_mod_init(
+ 	if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) &&
+ 	    (elf_hwcap & HWCAP_NEON))
+ 		static_branch_enable(&have_neon);
+-	else
++	else if (IS_REACHABLE(CONFIG_CRYPTO_HASH))
+ 		/* register only the first entry */
+ 		return crypto_register_shash(&arm_poly1305_algs[0]);
+ 
+-	return crypto_register_shashes(arm_poly1305_algs,
+-				       ARRAY_SIZE(arm_poly1305_algs));
++	return IS_REACHABLE(CONFIG_CRYPTO_HASH) ?
++		crypto_register_shashes(arm_poly1305_algs,
++					ARRAY_SIZE(arm_poly1305_algs)) : 0;
+ }
+ 
+ static void __exit arm_poly1305_mod_exit(void)
+ {
++	if (!IS_REACHABLE(CONFIG_CRYPTO_HASH))
++		return;
+ 	if (!static_branch_likely(&have_neon)) {
+ 		crypto_unregister_shash(&arm_poly1305_algs[0]);
+ 		return;
+--- a/arch/arm64/crypto/chacha-neon-glue.c
++++ b/arch/arm64/crypto/chacha-neon-glue.c
+@@ -211,12 +211,13 @@ static int __init chacha_simd_mod_init(v
+ 
+ 	static_branch_enable(&have_neon);
+ 
+-	return crypto_register_skciphers(algs, ARRAY_SIZE(algs));
++	return IS_REACHABLE(CONFIG_CRYPTO_BLKCIPHER) ?
++		crypto_register_skciphers(algs, ARRAY_SIZE(algs)) : 0;
+ }
+ 
+ static void __exit chacha_simd_mod_fini(void)
+ {
+-	if (cpu_have_named_feature(ASIMD))
++	if (IS_REACHABLE(CONFIG_CRYPTO_BLKCIPHER) && cpu_have_named_feature(ASIMD))
+ 		crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
+ }
+ 
+--- a/arch/arm64/crypto/poly1305-glue.c
++++ b/arch/arm64/crypto/poly1305-glue.c
+@@ -220,12 +220,13 @@ static int __init neon_poly1305_mod_init
+ 
+ 	static_branch_enable(&have_neon);
+ 
+-	return crypto_register_shash(&neon_poly1305_alg);
++	return IS_REACHABLE(CONFIG_CRYPTO_HASH) ?
++		crypto_register_shash(&neon_poly1305_alg) : 0;
+ }
+ 
+ static void __exit neon_poly1305_mod_exit(void)
+ {
+-	if (cpu_have_named_feature(ASIMD))
++	if (IS_REACHABLE(CONFIG_CRYPTO_HASH) && cpu_have_named_feature(ASIMD))
+ 		crypto_unregister_shash(&neon_poly1305_alg);
+ }
+ 
+--- a/arch/mips/crypto/chacha-glue.c
++++ b/arch/mips/crypto/chacha-glue.c
+@@ -128,12 +128,14 @@ static struct skcipher_alg algs[] = {
+ 
+ static int __init chacha_simd_mod_init(void)
+ {
+-	return crypto_register_skciphers(algs, ARRAY_SIZE(algs));
++	return IS_REACHABLE(CONFIG_CRYPTO_BLKCIPHER) ?
++		crypto_register_skciphers(algs, ARRAY_SIZE(algs)) : 0;
+ }
+ 
+ static void __exit chacha_simd_mod_fini(void)
+ {
+-	crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
++	if (IS_REACHABLE(CONFIG_CRYPTO_BLKCIPHER))
++		crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
+ }
+ 
+ module_init(chacha_simd_mod_init);
+--- a/arch/mips/crypto/poly1305-glue.c
++++ b/arch/mips/crypto/poly1305-glue.c
+@@ -187,12 +187,14 @@ static struct shash_alg mips_poly1305_al
+ 
+ static int __init mips_poly1305_mod_init(void)
+ {
+-	return crypto_register_shash(&mips_poly1305_alg);
++	return IS_REACHABLE(CONFIG_CRYPTO_HASH) ?
++		crypto_register_shash(&mips_poly1305_alg) : 0;
+ }
+ 
+ static void __exit mips_poly1305_mod_exit(void)
+ {
+-	crypto_unregister_shash(&mips_poly1305_alg);
++	if (IS_REACHABLE(CONFIG_CRYPTO_HASH))
++		crypto_unregister_shash(&mips_poly1305_alg);
+ }
+ 
+ module_init(mips_poly1305_mod_init);
+--- a/arch/x86/crypto/blake2s-glue.c
++++ b/arch/x86/crypto/blake2s-glue.c
+@@ -210,12 +210,14 @@ static int __init blake2s_mod_init(void)
+ 			      XFEATURE_MASK_AVX512, NULL))
+ 		static_branch_enable(&blake2s_use_avx512);
+ 
+-	return crypto_register_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs));
++	return IS_REACHABLE(CONFIG_CRYPTO_HASH) ?
++		crypto_register_shashes(blake2s_algs,
++					ARRAY_SIZE(blake2s_algs)) : 0;
+ }
+ 
+ static void __exit blake2s_mod_exit(void)
+ {
+-	if (boot_cpu_has(X86_FEATURE_SSSE3))
++	if (IS_REACHABLE(CONFIG_CRYPTO_HASH) && boot_cpu_has(X86_FEATURE_SSSE3))
+ 		crypto_unregister_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs));
+ }
+ 
+--- a/arch/x86/crypto/chacha_glue.c
++++ b/arch/x86/crypto/chacha_glue.c
+@@ -299,12 +299,13 @@ static int __init chacha_simd_mod_init(v
+ 		    boot_cpu_has(X86_FEATURE_AVX512BW)) /* kmovq */
+ 			static_branch_enable(&chacha_use_avx512vl);
+ 	}
+-	return crypto_register_skciphers(algs, ARRAY_SIZE(algs));
++	return IS_REACHABLE(CONFIG_CRYPTO_BLKCIPHER) ?
++		crypto_register_skciphers(algs, ARRAY_SIZE(algs)) : 0;
+ }
+ 
+ static void __exit chacha_simd_mod_fini(void)
+ {
+-	if (boot_cpu_has(X86_FEATURE_SSSE3))
++	if (IS_REACHABLE(CONFIG_CRYPTO_BLKCIPHER) && boot_cpu_has(X86_FEATURE_SSSE3))
+ 		crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
+ }
+ 
+--- a/arch/x86/crypto/curve25519-x86_64.c
++++ b/arch/x86/crypto/curve25519-x86_64.c
+@@ -2457,13 +2457,14 @@ static int __init curve25519_mod_init(vo
+ 		static_branch_enable(&curve25519_use_adx);
+ 	else
+ 		return 0;
+-	return crypto_register_kpp(&curve25519_alg);
++	return IS_REACHABLE(CONFIG_CRYPTO_KPP) ?
++		crypto_register_kpp(&curve25519_alg) : 0;
+ }
+ 
+ static void __exit curve25519_mod_exit(void)
+ {
+-	if (boot_cpu_has(X86_FEATURE_BMI2) ||
+-	    boot_cpu_has(X86_FEATURE_ADX))
++	if (IS_REACHABLE(CONFIG_CRYPTO_KPP) &&
++	    (boot_cpu_has(X86_FEATURE_BMI2) || boot_cpu_has(X86_FEATURE_ADX)))
+ 		crypto_unregister_kpp(&curve25519_alg);
+ }
+ 
+--- a/arch/x86/crypto/poly1305_glue.c
++++ b/arch/x86/crypto/poly1305_glue.c
+@@ -224,12 +224,13 @@ static int __init poly1305_simd_mod_init
+ 	    cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL))
+ 		static_branch_enable(&poly1305_use_avx2);
+ 
+-	return crypto_register_shash(&alg);
++	return IS_REACHABLE(CONFIG_CRYPTO_HASH) ? crypto_register_shash(&alg) : 0;
+ }
+ 
+ static void __exit poly1305_simd_mod_exit(void)
+ {
+-	crypto_unregister_shash(&alg);
++	if (IS_REACHABLE(CONFIG_CRYPTO_HASH))
++		crypto_unregister_shash(&alg);
+ }
+ 
+ module_init(poly1305_simd_mod_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0038-crypto-chacha-fix-warning-message-in-header-file.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0038-crypto-chacha-fix-warning-message-in-header-file.patch
new file mode 100644
index 0000000..ccd03e3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0038-crypto-chacha-fix-warning-message-in-header-file.patch
@@ -0,0 +1,35 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Valdis=20Kl=C4=93tnieks?= <valdis.kletnieks@vt.edu>
+Date: Thu, 5 Dec 2019 20:58:36 -0500
+Subject: [PATCH] crypto: chacha - fix warning message in header file
+
+commit 579d705cd64e44f3fcda1a6cfd5f37468a5ddf63 upstream.
+
+Building with W=1 causes a warning:
+
+  CC [M]  arch/x86/crypto/chacha_glue.o
+In file included from arch/x86/crypto/chacha_glue.c:10:
+./include/crypto/internal/chacha.h:37:1: warning: 'inline' is not at beginning of declaration [-Wold-style-declaration]
+   37 | static int inline chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key,
+      | ^~~~~~
+
+Straighten out the order to match the rest of the header file.
+
+Signed-off-by: Valdis Kletnieks <valdis.kletnieks@vt.edu>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ include/crypto/internal/chacha.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/include/crypto/internal/chacha.h
++++ b/include/crypto/internal/chacha.h
+@@ -34,7 +34,7 @@ static inline int chacha20_setkey(struct
+ 	return chacha_setkey(tfm, key, keysize, 20);
+ }
+ 
+-static int inline chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key,
++static inline int chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ 				  unsigned int keysize)
+ {
+ 	return chacha_setkey(tfm, key, keysize, 12);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0039-crypto-arm-curve25519-add-arch-specific-key-generati.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0039-crypto-arm-curve25519-add-arch-specific-key-generati.patch
new file mode 100644
index 0000000..67de22d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0039-crypto-arm-curve25519-add-arch-specific-key-generati.patch
@@ -0,0 +1,38 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Wed, 11 Dec 2019 10:26:39 +0100
+Subject: [PATCH] crypto: arm/curve25519 - add arch-specific key generation
+ function
+
+commit 84faa307249b341f6ad8de3e1869d77a65e26669 upstream.
+
+Somehow this was forgotten when Zinc was being split into oddly shaped
+pieces, resulting in linker errors. The x86_64 glue has a specific key
+generation implementation, but the Arm one does not. However, it can
+still receive the NEON speedups by calling the ordinary DH function
+using the base point.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Acked-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm/crypto/curve25519-glue.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/arch/arm/crypto/curve25519-glue.c
++++ b/arch/arm/crypto/curve25519-glue.c
+@@ -38,6 +38,13 @@ void curve25519_arch(u8 out[CURVE25519_K
+ }
+ EXPORT_SYMBOL(curve25519_arch);
+ 
++void curve25519_base_arch(u8 pub[CURVE25519_KEY_SIZE],
++			  const u8 secret[CURVE25519_KEY_SIZE])
++{
++	return curve25519_arch(pub, secret, curve25519_base_point);
++}
++EXPORT_SYMBOL(curve25519_base_arch);
++
+ static int curve25519_set_secret(struct crypto_kpp *tfm, const void *buf,
+ 				 unsigned int len)
+ {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0040-crypto-lib-curve25519-re-add-selftests.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0040-crypto-lib-curve25519-re-add-selftests.patch
new file mode 100644
index 0000000..e43d196
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0040-crypto-lib-curve25519-re-add-selftests.patch
@@ -0,0 +1,1387 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Mon, 16 Dec 2019 19:53:26 +0100
+Subject: [PATCH] crypto: lib/curve25519 - re-add selftests
+
+commit aa127963f1cab2b93c74c9b128a84610203fb674 upstream.
+
+Somehow these were dropped when Zinc was being integrated, which is
+problematic, because testing the library interface for Curve25519 is
+important.. This commit simply adds them back and wires them in in the
+same way that the blake2s selftests are wired in.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ lib/crypto/Makefile              |    1 +
+ lib/crypto/curve25519-selftest.c | 1321 ++++++++++++++++++++++++++++++
+ lib/crypto/curve25519.c          |   17 +
+ 3 files changed, 1339 insertions(+)
+ create mode 100644 lib/crypto/curve25519-selftest.c
+
+--- a/lib/crypto/Makefile
++++ b/lib/crypto/Makefile
+@@ -36,4 +36,5 @@ libsha256-y					:= sha256.o
+ ifneq ($(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS),y)
+ libblake2s-y					+= blake2s-selftest.o
+ libchacha20poly1305-y				+= chacha20poly1305-selftest.o
++libcurve25519-y					+= curve25519-selftest.o
+ endif
+--- /dev/null
++++ b/lib/crypto/curve25519-selftest.c
+@@ -0,0 +1,1321 @@
++// SPDX-License-Identifier: GPL-2.0 OR MIT
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#include <crypto/curve25519.h>
++
++struct curve25519_test_vector {
++	u8 private[CURVE25519_KEY_SIZE];
++	u8 public[CURVE25519_KEY_SIZE];
++	u8 result[CURVE25519_KEY_SIZE];
++	bool valid;
++};
++static const struct curve25519_test_vector curve25519_test_vectors[] __initconst = {
++	{
++		.private = { 0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d,
++			     0x3c, 0x16, 0xc1, 0x72, 0x51, 0xb2, 0x66, 0x45,
++			     0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a,
++			     0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a },
++		.public = { 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4,
++			    0xd3, 0x5b, 0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37,
++			    0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78, 0x67, 0x4d,
++			    0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f },
++		.result = { 0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1,
++			    0x72, 0x8e, 0x3b, 0xf4, 0x80, 0x35, 0x0f, 0x25,
++			    0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1, 0x9e, 0x33,
++			    0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42 },
++		.valid = true
++	},
++	{
++		.private = { 0x5d, 0xab, 0x08, 0x7e, 0x62, 0x4a, 0x8a, 0x4b,
++			     0x79, 0xe1, 0x7f, 0x8b, 0x83, 0x80, 0x0e, 0xe6,
++			     0x6f, 0x3b, 0xb1, 0x29, 0x26, 0x18, 0xb6, 0xfd,
++			     0x1c, 0x2f, 0x8b, 0x27, 0xff, 0x88, 0xe0, 0xeb },
++		.public = { 0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54,
++			    0x74, 0x8b, 0x7d, 0xdc, 0xb4, 0x3e, 0xf7, 0x5a,
++			    0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38, 0x1a, 0xf4,
++			    0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a },
++		.result = { 0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1,
++			    0x72, 0x8e, 0x3b, 0xf4, 0x80, 0x35, 0x0f, 0x25,
++			    0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1, 0x9e, 0x33,
++			    0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42 },
++		.valid = true
++	},
++	{
++		.private = { 1 },
++		.public = { 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.result = { 0x3c, 0x77, 0x77, 0xca, 0xf9, 0x97, 0xb2, 0x64,
++			    0x41, 0x60, 0x77, 0x66, 0x5b, 0x4e, 0x22, 0x9d,
++			    0x0b, 0x95, 0x48, 0xdc, 0x0c, 0xd8, 0x19, 0x98,
++			    0xdd, 0xcd, 0xc5, 0xc8, 0x53, 0x3c, 0x79, 0x7f },
++		.valid = true
++	},
++	{
++		.private = { 1 },
++		.public = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++		.result = { 0xb3, 0x2d, 0x13, 0x62, 0xc2, 0x48, 0xd6, 0x2f,
++			    0xe6, 0x26, 0x19, 0xcf, 0xf0, 0x4d, 0xd4, 0x3d,
++			    0xb7, 0x3f, 0xfc, 0x1b, 0x63, 0x08, 0xed, 0xe3,
++			    0x0b, 0x78, 0xd8, 0x73, 0x80, 0xf1, 0xe8, 0x34 },
++		.valid = true
++	},
++	{
++		.private = { 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d,
++			     0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd,
++			     0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18,
++			     0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4 },
++		.public = { 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb,
++			    0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, 0x5f, 0x7c,
++			    0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b,
++			    0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c },
++		.result = { 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90,
++			    0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, 0x08, 0x4f,
++			    0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7,
++			    0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52 },
++		.valid = true
++	},
++	{
++		.private = { 1, 2, 3, 4 },
++		.public = { 0 },
++		.result = { 0 },
++		.valid = false
++	},
++	{
++		.private = { 2, 4, 6, 8 },
++		.public = { 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae,
++			    0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a,
++			    0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd,
++			    0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8 },
++		.result = { 0 },
++		.valid = false
++	},
++	{
++		.private = { 0xff, 0xff, 0xff, 0xff, 0x0a, 0xff, 0xff, 0xff,
++			     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++		.public = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0x0a, 0x00, 0xfb, 0x9f },
++		.result = { 0x77, 0x52, 0xb6, 0x18, 0xc1, 0x2d, 0x48, 0xd2,
++			    0xc6, 0x93, 0x46, 0x83, 0x81, 0x7c, 0xc6, 0x57,
++			    0xf3, 0x31, 0x03, 0x19, 0x49, 0x48, 0x20, 0x05,
++			    0x42, 0x2b, 0x4e, 0xae, 0x8d, 0x1d, 0x43, 0x23 },
++		.valid = true
++	},
++	{
++		.private = { 0x8e, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.public = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x06 },
++		.result = { 0x5a, 0xdf, 0xaa, 0x25, 0x86, 0x8e, 0x32, 0x3d,
++			    0xae, 0x49, 0x62, 0xc1, 0x01, 0x5c, 0xb3, 0x12,
++			    0xe1, 0xc5, 0xc7, 0x9e, 0x95, 0x3f, 0x03, 0x99,
++			    0xb0, 0xba, 0x16, 0x22, 0xf3, 0xb6, 0xf7, 0x0c },
++		.valid = true
++	},
++	/* wycheproof - normal case */
++	{
++		.private = { 0x48, 0x52, 0x83, 0x4d, 0x9d, 0x6b, 0x77, 0xda,
++			     0xde, 0xab, 0xaa, 0xf2, 0xe1, 0x1d, 0xca, 0x66,
++			     0xd1, 0x9f, 0xe7, 0x49, 0x93, 0xa7, 0xbe, 0xc3,
++			     0x6c, 0x6e, 0x16, 0xa0, 0x98, 0x3f, 0xea, 0xba },
++		.public = { 0x9c, 0x64, 0x7d, 0x9a, 0xe5, 0x89, 0xb9, 0xf5,
++			    0x8f, 0xdc, 0x3c, 0xa4, 0x94, 0x7e, 0xfb, 0xc9,
++			    0x15, 0xc4, 0xb2, 0xe0, 0x8e, 0x74, 0x4a, 0x0e,
++			    0xdf, 0x46, 0x9d, 0xac, 0x59, 0xc8, 0xf8, 0x5a },
++		.result = { 0x87, 0xb7, 0xf2, 0x12, 0xb6, 0x27, 0xf7, 0xa5,
++			    0x4c, 0xa5, 0xe0, 0xbc, 0xda, 0xdd, 0xd5, 0x38,
++			    0x9d, 0x9d, 0xe6, 0x15, 0x6c, 0xdb, 0xcf, 0x8e,
++			    0xbe, 0x14, 0xff, 0xbc, 0xfb, 0x43, 0x65, 0x51 },
++		.valid = true
++	},
++	/* wycheproof - public key on twist */
++	{
++		.private = { 0x58, 0x8c, 0x06, 0x1a, 0x50, 0x80, 0x4a, 0xc4,
++			     0x88, 0xad, 0x77, 0x4a, 0xc7, 0x16, 0xc3, 0xf5,
++			     0xba, 0x71, 0x4b, 0x27, 0x12, 0xe0, 0x48, 0x49,
++			     0x13, 0x79, 0xa5, 0x00, 0x21, 0x19, 0x98, 0xa8 },
++		.public = { 0x63, 0xaa, 0x40, 0xc6, 0xe3, 0x83, 0x46, 0xc5,
++			    0xca, 0xf2, 0x3a, 0x6d, 0xf0, 0xa5, 0xe6, 0xc8,
++			    0x08, 0x89, 0xa0, 0x86, 0x47, 0xe5, 0x51, 0xb3,
++			    0x56, 0x34, 0x49, 0xbe, 0xfc, 0xfc, 0x97, 0x33 },
++		.result = { 0xb1, 0xa7, 0x07, 0x51, 0x94, 0x95, 0xff, 0xff,
++			    0xb2, 0x98, 0xff, 0x94, 0x17, 0x16, 0xb0, 0x6d,
++			    0xfa, 0xb8, 0x7c, 0xf8, 0xd9, 0x11, 0x23, 0xfe,
++			    0x2b, 0xe9, 0xa2, 0x33, 0xdd, 0xa2, 0x22, 0x12 },
++		.valid = true
++	},
++	/* wycheproof - public key on twist */
++	{
++		.private = { 0xb0, 0x5b, 0xfd, 0x32, 0xe5, 0x53, 0x25, 0xd9,
++			     0xfd, 0x64, 0x8c, 0xb3, 0x02, 0x84, 0x80, 0x39,
++			     0x00, 0x0b, 0x39, 0x0e, 0x44, 0xd5, 0x21, 0xe5,
++			     0x8a, 0xab, 0x3b, 0x29, 0xa6, 0x96, 0x0b, 0xa8 },
++		.public = { 0x0f, 0x83, 0xc3, 0x6f, 0xde, 0xd9, 0xd3, 0x2f,
++			    0xad, 0xf4, 0xef, 0xa3, 0xae, 0x93, 0xa9, 0x0b,
++			    0xb5, 0xcf, 0xa6, 0x68, 0x93, 0xbc, 0x41, 0x2c,
++			    0x43, 0xfa, 0x72, 0x87, 0xdb, 0xb9, 0x97, 0x79 },
++		.result = { 0x67, 0xdd, 0x4a, 0x6e, 0x16, 0x55, 0x33, 0x53,
++			    0x4c, 0x0e, 0x3f, 0x17, 0x2e, 0x4a, 0xb8, 0x57,
++			    0x6b, 0xca, 0x92, 0x3a, 0x5f, 0x07, 0xb2, 0xc0,
++			    0x69, 0xb4, 0xc3, 0x10, 0xff, 0x2e, 0x93, 0x5b },
++		.valid = true
++	},
++	/* wycheproof - public key on twist */
++	{
++		.private = { 0x70, 0xe3, 0x4b, 0xcb, 0xe1, 0xf4, 0x7f, 0xbc,
++			     0x0f, 0xdd, 0xfd, 0x7c, 0x1e, 0x1a, 0xa5, 0x3d,
++			     0x57, 0xbf, 0xe0, 0xf6, 0x6d, 0x24, 0x30, 0x67,
++			     0xb4, 0x24, 0xbb, 0x62, 0x10, 0xbe, 0xd1, 0x9c },
++		.public = { 0x0b, 0x82, 0x11, 0xa2, 0xb6, 0x04, 0x90, 0x97,
++			    0xf6, 0x87, 0x1c, 0x6c, 0x05, 0x2d, 0x3c, 0x5f,
++			    0xc1, 0xba, 0x17, 0xda, 0x9e, 0x32, 0xae, 0x45,
++			    0x84, 0x03, 0xb0, 0x5b, 0xb2, 0x83, 0x09, 0x2a },
++		.result = { 0x4a, 0x06, 0x38, 0xcf, 0xaa, 0x9e, 0xf1, 0x93,
++			    0x3b, 0x47, 0xf8, 0x93, 0x92, 0x96, 0xa6, 0xb2,
++			    0x5b, 0xe5, 0x41, 0xef, 0x7f, 0x70, 0xe8, 0x44,
++			    0xc0, 0xbc, 0xc0, 0x0b, 0x13, 0x4d, 0xe6, 0x4a },
++		.valid = true
++	},
++	/* wycheproof - public key on twist */
++	{
++		.private = { 0x68, 0xc1, 0xf3, 0xa6, 0x53, 0xa4, 0xcd, 0xb1,
++			     0xd3, 0x7b, 0xba, 0x94, 0x73, 0x8f, 0x8b, 0x95,
++			     0x7a, 0x57, 0xbe, 0xb2, 0x4d, 0x64, 0x6e, 0x99,
++			     0x4d, 0xc2, 0x9a, 0x27, 0x6a, 0xad, 0x45, 0x8d },
++		.public = { 0x34, 0x3a, 0xc2, 0x0a, 0x3b, 0x9c, 0x6a, 0x27,
++			    0xb1, 0x00, 0x81, 0x76, 0x50, 0x9a, 0xd3, 0x07,
++			    0x35, 0x85, 0x6e, 0xc1, 0xc8, 0xd8, 0xfc, 0xae,
++			    0x13, 0x91, 0x2d, 0x08, 0xd1, 0x52, 0xf4, 0x6c },
++		.result = { 0x39, 0x94, 0x91, 0xfc, 0xe8, 0xdf, 0xab, 0x73,
++			    0xb4, 0xf9, 0xf6, 0x11, 0xde, 0x8e, 0xa0, 0xb2,
++			    0x7b, 0x28, 0xf8, 0x59, 0x94, 0x25, 0x0b, 0x0f,
++			    0x47, 0x5d, 0x58, 0x5d, 0x04, 0x2a, 0xc2, 0x07 },
++		.valid = true
++	},
++	/* wycheproof - public key on twist */
++	{
++		.private = { 0xd8, 0x77, 0xb2, 0x6d, 0x06, 0xdf, 0xf9, 0xd9,
++			     0xf7, 0xfd, 0x4c, 0x5b, 0x37, 0x69, 0xf8, 0xcd,
++			     0xd5, 0xb3, 0x05, 0x16, 0xa5, 0xab, 0x80, 0x6b,
++			     0xe3, 0x24, 0xff, 0x3e, 0xb6, 0x9e, 0xa0, 0xb2 },
++		.public = { 0xfa, 0x69, 0x5f, 0xc7, 0xbe, 0x8d, 0x1b, 0xe5,
++			    0xbf, 0x70, 0x48, 0x98, 0xf3, 0x88, 0xc4, 0x52,
++			    0xba, 0xfd, 0xd3, 0xb8, 0xea, 0xe8, 0x05, 0xf8,
++			    0x68, 0x1a, 0x8d, 0x15, 0xc2, 0xd4, 0xe1, 0x42 },
++		.result = { 0x2c, 0x4f, 0xe1, 0x1d, 0x49, 0x0a, 0x53, 0x86,
++			    0x17, 0x76, 0xb1, 0x3b, 0x43, 0x54, 0xab, 0xd4,
++			    0xcf, 0x5a, 0x97, 0x69, 0x9d, 0xb6, 0xe6, 0xc6,
++			    0x8c, 0x16, 0x26, 0xd0, 0x76, 0x62, 0xf7, 0x58 },
++		.valid = true
++	},
++	/* wycheproof - public key = 0 */
++	{
++		.private = { 0x20, 0x74, 0x94, 0x03, 0x8f, 0x2b, 0xb8, 0x11,
++			     0xd4, 0x78, 0x05, 0xbc, 0xdf, 0x04, 0xa2, 0xac,
++			     0x58, 0x5a, 0xda, 0x7f, 0x2f, 0x23, 0x38, 0x9b,
++			     0xfd, 0x46, 0x58, 0xf9, 0xdd, 0xd4, 0xde, 0xbc },
++		.public = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.valid = false
++	},
++	/* wycheproof - public key = 1 */
++	{
++		.private = { 0x20, 0x2e, 0x89, 0x72, 0xb6, 0x1c, 0x7e, 0x61,
++			     0x93, 0x0e, 0xb9, 0x45, 0x0b, 0x50, 0x70, 0xea,
++			     0xe1, 0xc6, 0x70, 0x47, 0x56, 0x85, 0x54, 0x1f,
++			     0x04, 0x76, 0x21, 0x7e, 0x48, 0x18, 0xcf, 0xab },
++		.public = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.valid = false
++	},
++	/* wycheproof - edge case on twist */
++	{
++		.private = { 0x38, 0xdd, 0xe9, 0xf3, 0xe7, 0xb7, 0x99, 0x04,
++			     0x5f, 0x9a, 0xc3, 0x79, 0x3d, 0x4a, 0x92, 0x77,
++			     0xda, 0xde, 0xad, 0xc4, 0x1b, 0xec, 0x02, 0x90,
++			     0xf8, 0x1f, 0x74, 0x4f, 0x73, 0x77, 0x5f, 0x84 },
++		.public = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.result = { 0x9a, 0x2c, 0xfe, 0x84, 0xff, 0x9c, 0x4a, 0x97,
++			    0x39, 0x62, 0x5c, 0xae, 0x4a, 0x3b, 0x82, 0xa9,
++			    0x06, 0x87, 0x7a, 0x44, 0x19, 0x46, 0xf8, 0xd7,
++			    0xb3, 0xd7, 0x95, 0xfe, 0x8f, 0x5d, 0x16, 0x39 },
++		.valid = true
++	},
++	/* wycheproof - edge case on twist */
++	{
++		.private = { 0x98, 0x57, 0xa9, 0x14, 0xe3, 0xc2, 0x90, 0x36,
++			     0xfd, 0x9a, 0x44, 0x2b, 0xa5, 0x26, 0xb5, 0xcd,
++			     0xcd, 0xf2, 0x82, 0x16, 0x15, 0x3e, 0x63, 0x6c,
++			     0x10, 0x67, 0x7a, 0xca, 0xb6, 0xbd, 0x6a, 0xa5 },
++		.public = { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.result = { 0x4d, 0xa4, 0xe0, 0xaa, 0x07, 0x2c, 0x23, 0x2e,
++			    0xe2, 0xf0, 0xfa, 0x4e, 0x51, 0x9a, 0xe5, 0x0b,
++			    0x52, 0xc1, 0xed, 0xd0, 0x8a, 0x53, 0x4d, 0x4e,
++			    0xf3, 0x46, 0xc2, 0xe1, 0x06, 0xd2, 0x1d, 0x60 },
++		.valid = true
++	},
++	/* wycheproof - edge case on twist */
++	{
++		.private = { 0x48, 0xe2, 0x13, 0x0d, 0x72, 0x33, 0x05, 0xed,
++			     0x05, 0xe6, 0xe5, 0x89, 0x4d, 0x39, 0x8a, 0x5e,
++			     0x33, 0x36, 0x7a, 0x8c, 0x6a, 0xac, 0x8f, 0xcd,
++			     0xf0, 0xa8, 0x8e, 0x4b, 0x42, 0x82, 0x0d, 0xb7 },
++		.public = { 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0xf8, 0xff,
++			    0xff, 0x1f, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
++			    0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x07, 0x00,
++			    0x00, 0xf0, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00 },
++		.result = { 0x9e, 0xd1, 0x0c, 0x53, 0x74, 0x7f, 0x64, 0x7f,
++			    0x82, 0xf4, 0x51, 0x25, 0xd3, 0xde, 0x15, 0xa1,
++			    0xe6, 0xb8, 0x24, 0x49, 0x6a, 0xb4, 0x04, 0x10,
++			    0xff, 0xcc, 0x3c, 0xfe, 0x95, 0x76, 0x0f, 0x3b },
++		.valid = true
++	},
++	/* wycheproof - edge case on twist */
++	{
++		.private = { 0x28, 0xf4, 0x10, 0x11, 0x69, 0x18, 0x51, 0xb3,
++			     0xa6, 0x2b, 0x64, 0x15, 0x53, 0xb3, 0x0d, 0x0d,
++			     0xfd, 0xdc, 0xb8, 0xff, 0xfc, 0xf5, 0x37, 0x00,
++			     0xa7, 0xbe, 0x2f, 0x6a, 0x87, 0x2e, 0x9f, 0xb0 },
++		.public = { 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x07, 0x00,
++			    0x00, 0xe0, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00,
++			    0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0xf8, 0xff,
++			    0xff, 0x0f, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x7f },
++		.result = { 0xcf, 0x72, 0xb4, 0xaa, 0x6a, 0xa1, 0xc9, 0xf8,
++			    0x94, 0xf4, 0x16, 0x5b, 0x86, 0x10, 0x9a, 0xa4,
++			    0x68, 0x51, 0x76, 0x48, 0xe1, 0xf0, 0xcc, 0x70,
++			    0xe1, 0xab, 0x08, 0x46, 0x01, 0x76, 0x50, 0x6b },
++		.valid = true
++	},
++	/* wycheproof - edge case on twist */
++	{
++		.private = { 0x18, 0xa9, 0x3b, 0x64, 0x99, 0xb9, 0xf6, 0xb3,
++			     0x22, 0x5c, 0xa0, 0x2f, 0xef, 0x41, 0x0e, 0x0a,
++			     0xde, 0xc2, 0x35, 0x32, 0x32, 0x1d, 0x2d, 0x8e,
++			     0xf1, 0xa6, 0xd6, 0x02, 0xa8, 0xc6, 0x5b, 0x83 },
++		.public = { 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++			    0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++			    0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
++			    0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x7f },
++		.result = { 0x5d, 0x50, 0xb6, 0x28, 0x36, 0xbb, 0x69, 0x57,
++			    0x94, 0x10, 0x38, 0x6c, 0xf7, 0xbb, 0x81, 0x1c,
++			    0x14, 0xbf, 0x85, 0xb1, 0xc7, 0xb1, 0x7e, 0x59,
++			    0x24, 0xc7, 0xff, 0xea, 0x91, 0xef, 0x9e, 0x12 },
++		.valid = true
++	},
++	/* wycheproof - edge case on twist */
++	{
++		.private = { 0xc0, 0x1d, 0x13, 0x05, 0xa1, 0x33, 0x8a, 0x1f,
++			     0xca, 0xc2, 0xba, 0x7e, 0x2e, 0x03, 0x2b, 0x42,
++			     0x7e, 0x0b, 0x04, 0x90, 0x31, 0x65, 0xac, 0xa9,
++			     0x57, 0xd8, 0xd0, 0x55, 0x3d, 0x87, 0x17, 0xb0 },
++		.public = { 0xea, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++		.result = { 0x19, 0x23, 0x0e, 0xb1, 0x48, 0xd5, 0xd6, 0x7c,
++			    0x3c, 0x22, 0xab, 0x1d, 0xae, 0xff, 0x80, 0xa5,
++			    0x7e, 0xae, 0x42, 0x65, 0xce, 0x28, 0x72, 0x65,
++			    0x7b, 0x2c, 0x80, 0x99, 0xfc, 0x69, 0x8e, 0x50 },
++		.valid = true
++	},
++	/* wycheproof - edge case for public key */
++	{
++		.private = { 0x38, 0x6f, 0x7f, 0x16, 0xc5, 0x07, 0x31, 0xd6,
++			     0x4f, 0x82, 0xe6, 0xa1, 0x70, 0xb1, 0x42, 0xa4,
++			     0xe3, 0x4f, 0x31, 0xfd, 0x77, 0x68, 0xfc, 0xb8,
++			     0x90, 0x29, 0x25, 0xe7, 0xd1, 0xe2, 0x1a, 0xbe },
++		.public = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.result = { 0x0f, 0xca, 0xb5, 0xd8, 0x42, 0xa0, 0x78, 0xd7,
++			    0xa7, 0x1f, 0xc5, 0x9b, 0x57, 0xbf, 0xb4, 0xca,
++			    0x0b, 0xe6, 0x87, 0x3b, 0x49, 0xdc, 0xdb, 0x9f,
++			    0x44, 0xe1, 0x4a, 0xe8, 0xfb, 0xdf, 0xa5, 0x42 },
++		.valid = true
++	},
++	/* wycheproof - edge case for public key */
++	{
++		.private = { 0xe0, 0x23, 0xa2, 0x89, 0xbd, 0x5e, 0x90, 0xfa,
++			     0x28, 0x04, 0xdd, 0xc0, 0x19, 0xa0, 0x5e, 0xf3,
++			     0xe7, 0x9d, 0x43, 0x4b, 0xb6, 0xea, 0x2f, 0x52,
++			     0x2e, 0xcb, 0x64, 0x3a, 0x75, 0x29, 0x6e, 0x95 },
++		.public = { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++			    0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++			    0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++			    0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 },
++		.result = { 0x54, 0xce, 0x8f, 0x22, 0x75, 0xc0, 0x77, 0xe3,
++			    0xb1, 0x30, 0x6a, 0x39, 0x39, 0xc5, 0xe0, 0x3e,
++			    0xef, 0x6b, 0xbb, 0x88, 0x06, 0x05, 0x44, 0x75,
++			    0x8d, 0x9f, 0xef, 0x59, 0xb0, 0xbc, 0x3e, 0x4f },
++		.valid = true
++	},
++	/* wycheproof - edge case for public key */
++	{
++		.private = { 0x68, 0xf0, 0x10, 0xd6, 0x2e, 0xe8, 0xd9, 0x26,
++			     0x05, 0x3a, 0x36, 0x1c, 0x3a, 0x75, 0xc6, 0xea,
++			     0x4e, 0xbd, 0xc8, 0x60, 0x6a, 0xb2, 0x85, 0x00,
++			     0x3a, 0x6f, 0x8f, 0x40, 0x76, 0xb0, 0x1e, 0x83 },
++		.public = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03 },
++		.result = { 0xf1, 0x36, 0x77, 0x5c, 0x5b, 0xeb, 0x0a, 0xf8,
++			    0x11, 0x0a, 0xf1, 0x0b, 0x20, 0x37, 0x23, 0x32,
++			    0x04, 0x3c, 0xab, 0x75, 0x24, 0x19, 0x67, 0x87,
++			    0x75, 0xa2, 0x23, 0xdf, 0x57, 0xc9, 0xd3, 0x0d },
++		.valid = true
++	},
++	/* wycheproof - edge case for public key */
++	{
++		.private = { 0x58, 0xeb, 0xcb, 0x35, 0xb0, 0xf8, 0x84, 0x5c,
++			     0xaf, 0x1e, 0xc6, 0x30, 0xf9, 0x65, 0x76, 0xb6,
++			     0x2c, 0x4b, 0x7b, 0x6c, 0x36, 0xb2, 0x9d, 0xeb,
++			     0x2c, 0xb0, 0x08, 0x46, 0x51, 0x75, 0x5c, 0x96 },
++		.public = { 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xfb, 0xff,
++			    0xff, 0xdf, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff,
++			    0xfe, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xf7, 0xff,
++			    0xff, 0xf7, 0xff, 0xff, 0xbf, 0xff, 0xff, 0x3f },
++		.result = { 0xbf, 0x9a, 0xff, 0xd0, 0x6b, 0x84, 0x40, 0x85,
++			    0x58, 0x64, 0x60, 0x96, 0x2e, 0xf2, 0x14, 0x6f,
++			    0xf3, 0xd4, 0x53, 0x3d, 0x94, 0x44, 0xaa, 0xb0,
++			    0x06, 0xeb, 0x88, 0xcc, 0x30, 0x54, 0x40, 0x7d },
++		.valid = true
++	},
++	/* wycheproof - edge case for public key */
++	{
++		.private = { 0x18, 0x8c, 0x4b, 0xc5, 0xb9, 0xc4, 0x4b, 0x38,
++			     0xbb, 0x65, 0x8b, 0x9b, 0x2a, 0xe8, 0x2d, 0x5b,
++			     0x01, 0x01, 0x5e, 0x09, 0x31, 0x84, 0xb1, 0x7c,
++			     0xb7, 0x86, 0x35, 0x03, 0xa7, 0x83, 0xe1, 0xbb },
++		.public = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f },
++		.result = { 0xd4, 0x80, 0xde, 0x04, 0xf6, 0x99, 0xcb, 0x3b,
++			    0xe0, 0x68, 0x4a, 0x9c, 0xc2, 0xe3, 0x12, 0x81,
++			    0xea, 0x0b, 0xc5, 0xa9, 0xdc, 0xc1, 0x57, 0xd3,
++			    0xd2, 0x01, 0x58, 0xd4, 0x6c, 0xa5, 0x24, 0x6d },
++		.valid = true
++	},
++	/* wycheproof - edge case for public key */
++	{
++		.private = { 0xe0, 0x6c, 0x11, 0xbb, 0x2e, 0x13, 0xce, 0x3d,
++			     0xc7, 0x67, 0x3f, 0x67, 0xf5, 0x48, 0x22, 0x42,
++			     0x90, 0x94, 0x23, 0xa9, 0xae, 0x95, 0xee, 0x98,
++			     0x6a, 0x98, 0x8d, 0x98, 0xfa, 0xee, 0x23, 0xa2 },
++		.public = { 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f,
++			    0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f,
++			    0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f,
++			    0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f },
++		.result = { 0x4c, 0x44, 0x01, 0xcc, 0xe6, 0xb5, 0x1e, 0x4c,
++			    0xb1, 0x8f, 0x27, 0x90, 0x24, 0x6c, 0x9b, 0xf9,
++			    0x14, 0xdb, 0x66, 0x77, 0x50, 0xa1, 0xcb, 0x89,
++			    0x06, 0x90, 0x92, 0xaf, 0x07, 0x29, 0x22, 0x76 },
++		.valid = true
++	},
++	/* wycheproof - edge case for public key */
++	{
++		.private = { 0xc0, 0x65, 0x8c, 0x46, 0xdd, 0xe1, 0x81, 0x29,
++			     0x29, 0x38, 0x77, 0x53, 0x5b, 0x11, 0x62, 0xb6,
++			     0xf9, 0xf5, 0x41, 0x4a, 0x23, 0xcf, 0x4d, 0x2c,
++			     0xbc, 0x14, 0x0a, 0x4d, 0x99, 0xda, 0x2b, 0x8f },
++		.public = { 0xeb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++		.result = { 0x57, 0x8b, 0xa8, 0xcc, 0x2d, 0xbd, 0xc5, 0x75,
++			    0xaf, 0xcf, 0x9d, 0xf2, 0xb3, 0xee, 0x61, 0x89,
++			    0xf5, 0x33, 0x7d, 0x68, 0x54, 0xc7, 0x9b, 0x4c,
++			    0xe1, 0x65, 0xea, 0x12, 0x29, 0x3b, 0x3a, 0x0f },
++		.valid = true
++	},
++	/* wycheproof - public key with low order */
++	{
++		.private = { 0x10, 0x25, 0x5c, 0x92, 0x30, 0xa9, 0x7a, 0x30,
++			     0xa4, 0x58, 0xca, 0x28, 0x4a, 0x62, 0x96, 0x69,
++			     0x29, 0x3a, 0x31, 0x89, 0x0c, 0xda, 0x9d, 0x14,
++			     0x7f, 0xeb, 0xc7, 0xd1, 0xe2, 0x2d, 0x6b, 0xb1 },
++		.public = { 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae,
++			    0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a,
++			    0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd,
++			    0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00 },
++		.result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.valid = false
++	},
++	/* wycheproof - public key with low order */
++	{
++		.private = { 0x78, 0xf1, 0xe8, 0xed, 0xf1, 0x44, 0x81, 0xb3,
++			     0x89, 0x44, 0x8d, 0xac, 0x8f, 0x59, 0xc7, 0x0b,
++			     0x03, 0x8e, 0x7c, 0xf9, 0x2e, 0xf2, 0xc7, 0xef,
++			     0xf5, 0x7a, 0x72, 0x46, 0x6e, 0x11, 0x52, 0x96 },
++		.public = { 0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24,
++			    0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b,
++			    0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86,
++			    0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0x57 },
++		.result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.valid = false
++	},
++	/* wycheproof - public key with low order */
++	{
++		.private = { 0xa0, 0xa0, 0x5a, 0x3e, 0x8f, 0x9f, 0x44, 0x20,
++			     0x4d, 0x5f, 0x80, 0x59, 0xa9, 0x4a, 0xc7, 0xdf,
++			     0xc3, 0x9a, 0x49, 0xac, 0x01, 0x6d, 0xd7, 0x43,
++			     0xdb, 0xfa, 0x43, 0xc5, 0xd6, 0x71, 0xfd, 0x88 },
++		.public = { 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++		.result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.valid = false
++	},
++	/* wycheproof - public key with low order */
++	{
++		.private = { 0xd0, 0xdb, 0xb3, 0xed, 0x19, 0x06, 0x66, 0x3f,
++			     0x15, 0x42, 0x0a, 0xf3, 0x1f, 0x4e, 0xaf, 0x65,
++			     0x09, 0xd9, 0xa9, 0x94, 0x97, 0x23, 0x50, 0x06,
++			     0x05, 0xad, 0x7c, 0x1c, 0x6e, 0x74, 0x50, 0xa9 },
++		.public = { 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++		.result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.valid = false
++	},
++	/* wycheproof - public key with low order */
++	{
++		.private = { 0xc0, 0xb1, 0xd0, 0xeb, 0x22, 0xb2, 0x44, 0xfe,
++			     0x32, 0x91, 0x14, 0x00, 0x72, 0xcd, 0xd9, 0xd9,
++			     0x89, 0xb5, 0xf0, 0xec, 0xd9, 0x6c, 0x10, 0x0f,
++			     0xeb, 0x5b, 0xca, 0x24, 0x1c, 0x1d, 0x9f, 0x8f },
++		.public = { 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++		.result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.valid = false
++	},
++	/* wycheproof - public key with low order */
++	{
++		.private = { 0x48, 0x0b, 0xf4, 0x5f, 0x59, 0x49, 0x42, 0xa8,
++			     0xbc, 0x0f, 0x33, 0x53, 0xc6, 0xe8, 0xb8, 0x85,
++			     0x3d, 0x77, 0xf3, 0x51, 0xf1, 0xc2, 0xca, 0x6c,
++			     0x2d, 0x1a, 0xbf, 0x8a, 0x00, 0xb4, 0x22, 0x9c },
++		.public = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 },
++		.result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.valid = false
++	},
++	/* wycheproof - public key with low order */
++	{
++		.private = { 0x30, 0xf9, 0x93, 0xfc, 0xf8, 0x51, 0x4f, 0xc8,
++			     0x9b, 0xd8, 0xdb, 0x14, 0xcd, 0x43, 0xba, 0x0d,
++			     0x4b, 0x25, 0x30, 0xe7, 0x3c, 0x42, 0x76, 0xa0,
++			     0x5e, 0x1b, 0x14, 0x5d, 0x42, 0x0c, 0xed, 0xb4 },
++		.public = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 },
++		.result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.valid = false
++	},
++	/* wycheproof - public key with low order */
++	{
++		.private = { 0xc0, 0x49, 0x74, 0xb7, 0x58, 0x38, 0x0e, 0x2a,
++			     0x5b, 0x5d, 0xf6, 0xeb, 0x09, 0xbb, 0x2f, 0x6b,
++			     0x34, 0x34, 0xf9, 0x82, 0x72, 0x2a, 0x8e, 0x67,
++			     0x6d, 0x3d, 0xa2, 0x51, 0xd1, 0xb3, 0xde, 0x83 },
++		.public = { 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae,
++			    0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a,
++			    0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd,
++			    0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x80 },
++		.result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.valid = false
++	},
++	/* wycheproof - public key with low order */
++	{
++		.private = { 0x50, 0x2a, 0x31, 0x37, 0x3d, 0xb3, 0x24, 0x46,
++			     0x84, 0x2f, 0xe5, 0xad, 0xd3, 0xe0, 0x24, 0x02,
++			     0x2e, 0xa5, 0x4f, 0x27, 0x41, 0x82, 0xaf, 0xc3,
++			     0xd9, 0xf1, 0xbb, 0x3d, 0x39, 0x53, 0x4e, 0xb5 },
++		.public = { 0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24,
++			    0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b,
++			    0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86,
++			    0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0xd7 },
++		.result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.valid = false
++	},
++	/* wycheproof - public key with low order */
++	{
++		.private = { 0x90, 0xfa, 0x64, 0x17, 0xb0, 0xe3, 0x70, 0x30,
++			     0xfd, 0x6e, 0x43, 0xef, 0xf2, 0xab, 0xae, 0xf1,
++			     0x4c, 0x67, 0x93, 0x11, 0x7a, 0x03, 0x9c, 0xf6,
++			     0x21, 0x31, 0x8b, 0xa9, 0x0f, 0x4e, 0x98, 0xbe },
++		.public = { 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++		.result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.valid = false
++	},
++	/* wycheproof - public key with low order */
++	{
++		.private = { 0x78, 0xad, 0x3f, 0x26, 0x02, 0x7f, 0x1c, 0x9f,
++			     0xdd, 0x97, 0x5a, 0x16, 0x13, 0xb9, 0x47, 0x77,
++			     0x9b, 0xad, 0x2c, 0xf2, 0xb7, 0x41, 0xad, 0xe0,
++			     0x18, 0x40, 0x88, 0x5a, 0x30, 0xbb, 0x97, 0x9c },
++		.public = { 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++		.result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.valid = false
++	},
++	/* wycheproof - public key with low order */
++	{
++		.private = { 0x98, 0xe2, 0x3d, 0xe7, 0xb1, 0xe0, 0x92, 0x6e,
++			     0xd9, 0xc8, 0x7e, 0x7b, 0x14, 0xba, 0xf5, 0x5f,
++			     0x49, 0x7a, 0x1d, 0x70, 0x96, 0xf9, 0x39, 0x77,
++			     0x68, 0x0e, 0x44, 0xdc, 0x1c, 0x7b, 0x7b, 0x8b },
++		.public = { 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++		.result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.valid = false
++	},
++	/* wycheproof - public key >= p */
++	{
++		.private = { 0xf0, 0x1e, 0x48, 0xda, 0xfa, 0xc9, 0xd7, 0xbc,
++			     0xf5, 0x89, 0xcb, 0xc3, 0x82, 0xc8, 0x78, 0xd1,
++			     0x8b, 0xda, 0x35, 0x50, 0x58, 0x9f, 0xfb, 0x5d,
++			     0x50, 0xb5, 0x23, 0xbe, 0xbe, 0x32, 0x9d, 0xae },
++		.public = { 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++		.result = { 0xbd, 0x36, 0xa0, 0x79, 0x0e, 0xb8, 0x83, 0x09,
++			    0x8c, 0x98, 0x8b, 0x21, 0x78, 0x67, 0x73, 0xde,
++			    0x0b, 0x3a, 0x4d, 0xf1, 0x62, 0x28, 0x2c, 0xf1,
++			    0x10, 0xde, 0x18, 0xdd, 0x48, 0x4c, 0xe7, 0x4b },
++		.valid = true
++	},
++	/* wycheproof - public key >= p */
++	{
++		.private = { 0x28, 0x87, 0x96, 0xbc, 0x5a, 0xff, 0x4b, 0x81,
++			     0xa3, 0x75, 0x01, 0x75, 0x7b, 0xc0, 0x75, 0x3a,
++			     0x3c, 0x21, 0x96, 0x47, 0x90, 0xd3, 0x86, 0x99,
++			     0x30, 0x8d, 0xeb, 0xc1, 0x7a, 0x6e, 0xaf, 0x8d },
++		.public = { 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++		.result = { 0xb4, 0xe0, 0xdd, 0x76, 0xda, 0x7b, 0x07, 0x17,
++			    0x28, 0xb6, 0x1f, 0x85, 0x67, 0x71, 0xaa, 0x35,
++			    0x6e, 0x57, 0xed, 0xa7, 0x8a, 0x5b, 0x16, 0x55,
++			    0xcc, 0x38, 0x20, 0xfb, 0x5f, 0x85, 0x4c, 0x5c },
++		.valid = true
++	},
++	/* wycheproof - public key >= p */
++	{
++		.private = { 0x98, 0xdf, 0x84, 0x5f, 0x66, 0x51, 0xbf, 0x11,
++			     0x38, 0x22, 0x1f, 0x11, 0x90, 0x41, 0xf7, 0x2b,
++			     0x6d, 0xbc, 0x3c, 0x4a, 0xce, 0x71, 0x43, 0xd9,
++			     0x9f, 0xd5, 0x5a, 0xd8, 0x67, 0x48, 0x0d, 0xa8 },
++		.public = { 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++		.result = { 0x6f, 0xdf, 0x6c, 0x37, 0x61, 0x1d, 0xbd, 0x53,
++			    0x04, 0xdc, 0x0f, 0x2e, 0xb7, 0xc9, 0x51, 0x7e,
++			    0xb3, 0xc5, 0x0e, 0x12, 0xfd, 0x05, 0x0a, 0xc6,
++			    0xde, 0xc2, 0x70, 0x71, 0xd4, 0xbf, 0xc0, 0x34 },
++		.valid = true
++	},
++	/* wycheproof - public key >= p */
++	{
++		.private = { 0xf0, 0x94, 0x98, 0xe4, 0x6f, 0x02, 0xf8, 0x78,
++			     0x82, 0x9e, 0x78, 0xb8, 0x03, 0xd3, 0x16, 0xa2,
++			     0xed, 0x69, 0x5d, 0x04, 0x98, 0xa0, 0x8a, 0xbd,
++			     0xf8, 0x27, 0x69, 0x30, 0xe2, 0x4e, 0xdc, 0xb0 },
++		.public = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++		.result = { 0x4c, 0x8f, 0xc4, 0xb1, 0xc6, 0xab, 0x88, 0xfb,
++			    0x21, 0xf1, 0x8f, 0x6d, 0x4c, 0x81, 0x02, 0x40,
++			    0xd4, 0xe9, 0x46, 0x51, 0xba, 0x44, 0xf7, 0xa2,
++			    0xc8, 0x63, 0xce, 0xc7, 0xdc, 0x56, 0x60, 0x2d },
++		.valid = true
++	},
++	/* wycheproof - public key >= p */
++	{
++		.private = { 0x18, 0x13, 0xc1, 0x0a, 0x5c, 0x7f, 0x21, 0xf9,
++			     0x6e, 0x17, 0xf2, 0x88, 0xc0, 0xcc, 0x37, 0x60,
++			     0x7c, 0x04, 0xc5, 0xf5, 0xae, 0xa2, 0xdb, 0x13,
++			     0x4f, 0x9e, 0x2f, 0xfc, 0x66, 0xbd, 0x9d, 0xb8 },
++		.public = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 },
++		.result = { 0x1c, 0xd0, 0xb2, 0x82, 0x67, 0xdc, 0x54, 0x1c,
++			    0x64, 0x2d, 0x6d, 0x7d, 0xca, 0x44, 0xa8, 0xb3,
++			    0x8a, 0x63, 0x73, 0x6e, 0xef, 0x5c, 0x4e, 0x65,
++			    0x01, 0xff, 0xbb, 0xb1, 0x78, 0x0c, 0x03, 0x3c },
++		.valid = true
++	},
++	/* wycheproof - public key >= p */
++	{
++		.private = { 0x78, 0x57, 0xfb, 0x80, 0x86, 0x53, 0x64, 0x5a,
++			     0x0b, 0xeb, 0x13, 0x8a, 0x64, 0xf5, 0xf4, 0xd7,
++			     0x33, 0xa4, 0x5e, 0xa8, 0x4c, 0x3c, 0xda, 0x11,
++			     0xa9, 0xc0, 0x6f, 0x7e, 0x71, 0x39, 0x14, 0x9e },
++		.public = { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 },
++		.result = { 0x87, 0x55, 0xbe, 0x01, 0xc6, 0x0a, 0x7e, 0x82,
++			    0x5c, 0xff, 0x3e, 0x0e, 0x78, 0xcb, 0x3a, 0xa4,
++			    0x33, 0x38, 0x61, 0x51, 0x6a, 0xa5, 0x9b, 0x1c,
++			    0x51, 0xa8, 0xb2, 0xa5, 0x43, 0xdf, 0xa8, 0x22 },
++		.valid = true
++	},
++	/* wycheproof - public key >= p */
++	{
++		.private = { 0xe0, 0x3a, 0xa8, 0x42, 0xe2, 0xab, 0xc5, 0x6e,
++			     0x81, 0xe8, 0x7b, 0x8b, 0x9f, 0x41, 0x7b, 0x2a,
++			     0x1e, 0x59, 0x13, 0xc7, 0x23, 0xee, 0xd2, 0x8d,
++			     0x75, 0x2f, 0x8d, 0x47, 0xa5, 0x9f, 0x49, 0x8f },
++		.public = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 },
++		.result = { 0x54, 0xc9, 0xa1, 0xed, 0x95, 0xe5, 0x46, 0xd2,
++			    0x78, 0x22, 0xa3, 0x60, 0x93, 0x1d, 0xda, 0x60,
++			    0xa1, 0xdf, 0x04, 0x9d, 0xa6, 0xf9, 0x04, 0x25,
++			    0x3c, 0x06, 0x12, 0xbb, 0xdc, 0x08, 0x74, 0x76 },
++		.valid = true
++	},
++	/* wycheproof - public key >= p */
++	{
++		.private = { 0xf8, 0xf7, 0x07, 0xb7, 0x99, 0x9b, 0x18, 0xcb,
++			     0x0d, 0x6b, 0x96, 0x12, 0x4f, 0x20, 0x45, 0x97,
++			     0x2c, 0xa2, 0x74, 0xbf, 0xc1, 0x54, 0xad, 0x0c,
++			     0x87, 0x03, 0x8c, 0x24, 0xc6, 0xd0, 0xd4, 0xb2 },
++		.public = { 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++		.result = { 0xcc, 0x1f, 0x40, 0xd7, 0x43, 0xcd, 0xc2, 0x23,
++			    0x0e, 0x10, 0x43, 0xda, 0xba, 0x8b, 0x75, 0xe8,
++			    0x10, 0xf1, 0xfb, 0xab, 0x7f, 0x25, 0x52, 0x69,
++			    0xbd, 0x9e, 0xbb, 0x29, 0xe6, 0xbf, 0x49, 0x4f },
++		.valid = true
++	},
++	/* wycheproof - public key >= p */
++	{
++		.private = { 0xa0, 0x34, 0xf6, 0x84, 0xfa, 0x63, 0x1e, 0x1a,
++			     0x34, 0x81, 0x18, 0xc1, 0xce, 0x4c, 0x98, 0x23,
++			     0x1f, 0x2d, 0x9e, 0xec, 0x9b, 0xa5, 0x36, 0x5b,
++			     0x4a, 0x05, 0xd6, 0x9a, 0x78, 0x5b, 0x07, 0x96 },
++		.public = { 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++		.result = { 0x54, 0x99, 0x8e, 0xe4, 0x3a, 0x5b, 0x00, 0x7b,
++			    0xf4, 0x99, 0xf0, 0x78, 0xe7, 0x36, 0x52, 0x44,
++			    0x00, 0xa8, 0xb5, 0xc7, 0xe9, 0xb9, 0xb4, 0x37,
++			    0x71, 0x74, 0x8c, 0x7c, 0xdf, 0x88, 0x04, 0x12 },
++		.valid = true
++	},
++	/* wycheproof - public key >= p */
++	{
++		.private = { 0x30, 0xb6, 0xc6, 0xa0, 0xf2, 0xff, 0xa6, 0x80,
++			     0x76, 0x8f, 0x99, 0x2b, 0xa8, 0x9e, 0x15, 0x2d,
++			     0x5b, 0xc9, 0x89, 0x3d, 0x38, 0xc9, 0x11, 0x9b,
++			     0xe4, 0xf7, 0x67, 0xbf, 0xab, 0x6e, 0x0c, 0xa5 },
++		.public = { 0xdc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++		.result = { 0xea, 0xd9, 0xb3, 0x8e, 0xfd, 0xd7, 0x23, 0x63,
++			    0x79, 0x34, 0xe5, 0x5a, 0xb7, 0x17, 0xa7, 0xae,
++			    0x09, 0xeb, 0x86, 0xa2, 0x1d, 0xc3, 0x6a, 0x3f,
++			    0xee, 0xb8, 0x8b, 0x75, 0x9e, 0x39, 0x1e, 0x09 },
++		.valid = true
++	},
++	/* wycheproof - public key >= p */
++	{
++		.private = { 0x90, 0x1b, 0x9d, 0xcf, 0x88, 0x1e, 0x01, 0xe0,
++			     0x27, 0x57, 0x50, 0x35, 0xd4, 0x0b, 0x43, 0xbd,
++			     0xc1, 0xc5, 0x24, 0x2e, 0x03, 0x08, 0x47, 0x49,
++			     0x5b, 0x0c, 0x72, 0x86, 0x46, 0x9b, 0x65, 0x91 },
++		.public = { 0xea, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++		.result = { 0x60, 0x2f, 0xf4, 0x07, 0x89, 0xb5, 0x4b, 0x41,
++			    0x80, 0x59, 0x15, 0xfe, 0x2a, 0x62, 0x21, 0xf0,
++			    0x7a, 0x50, 0xff, 0xc2, 0xc3, 0xfc, 0x94, 0xcf,
++			    0x61, 0xf1, 0x3d, 0x79, 0x04, 0xe8, 0x8e, 0x0e },
++		.valid = true
++	},
++	/* wycheproof - public key >= p */
++	{
++		.private = { 0x80, 0x46, 0x67, 0x7c, 0x28, 0xfd, 0x82, 0xc9,
++			     0xa1, 0xbd, 0xb7, 0x1a, 0x1a, 0x1a, 0x34, 0xfa,
++			     0xba, 0x12, 0x25, 0xe2, 0x50, 0x7f, 0xe3, 0xf5,
++			     0x4d, 0x10, 0xbd, 0x5b, 0x0d, 0x86, 0x5f, 0x8e },
++		.public = { 0xeb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++		.result = { 0xe0, 0x0a, 0xe8, 0xb1, 0x43, 0x47, 0x12, 0x47,
++			    0xba, 0x24, 0xf1, 0x2c, 0x88, 0x55, 0x36, 0xc3,
++			    0xcb, 0x98, 0x1b, 0x58, 0xe1, 0xe5, 0x6b, 0x2b,
++			    0xaf, 0x35, 0xc1, 0x2a, 0xe1, 0xf7, 0x9c, 0x26 },
++		.valid = true
++	},
++	/* wycheproof - public key >= p */
++	{
++		.private = { 0x60, 0x2f, 0x7e, 0x2f, 0x68, 0xa8, 0x46, 0xb8,
++			     0x2c, 0xc2, 0x69, 0xb1, 0xd4, 0x8e, 0x93, 0x98,
++			     0x86, 0xae, 0x54, 0xfd, 0x63, 0x6c, 0x1f, 0xe0,
++			     0x74, 0xd7, 0x10, 0x12, 0x7d, 0x47, 0x24, 0x91 },
++		.public = { 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++		.result = { 0x98, 0xcb, 0x9b, 0x50, 0xdd, 0x3f, 0xc2, 0xb0,
++			    0xd4, 0xf2, 0xd2, 0xbf, 0x7c, 0x5c, 0xfd, 0xd1,
++			    0x0c, 0x8f, 0xcd, 0x31, 0xfc, 0x40, 0xaf, 0x1a,
++			    0xd4, 0x4f, 0x47, 0xc1, 0x31, 0x37, 0x63, 0x62 },
++		.valid = true
++	},
++	/* wycheproof - public key >= p */
++	{
++		.private = { 0x60, 0x88, 0x7b, 0x3d, 0xc7, 0x24, 0x43, 0x02,
++			     0x6e, 0xbe, 0xdb, 0xbb, 0xb7, 0x06, 0x65, 0xf4,
++			     0x2b, 0x87, 0xad, 0xd1, 0x44, 0x0e, 0x77, 0x68,
++			     0xfb, 0xd7, 0xe8, 0xe2, 0xce, 0x5f, 0x63, 0x9d },
++		.public = { 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++		.result = { 0x38, 0xd6, 0x30, 0x4c, 0x4a, 0x7e, 0x6d, 0x9f,
++			    0x79, 0x59, 0x33, 0x4f, 0xb5, 0x24, 0x5b, 0xd2,
++			    0xc7, 0x54, 0x52, 0x5d, 0x4c, 0x91, 0xdb, 0x95,
++			    0x02, 0x06, 0x92, 0x62, 0x34, 0xc1, 0xf6, 0x33 },
++		.valid = true
++	},
++	/* wycheproof - public key >= p */
++	{
++		.private = { 0x78, 0xd3, 0x1d, 0xfa, 0x85, 0x44, 0x97, 0xd7,
++			     0x2d, 0x8d, 0xef, 0x8a, 0x1b, 0x7f, 0xb0, 0x06,
++			     0xce, 0xc2, 0xd8, 0xc4, 0x92, 0x46, 0x47, 0xc9,
++			     0x38, 0x14, 0xae, 0x56, 0xfa, 0xed, 0xa4, 0x95 },
++		.public = { 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++		.result = { 0x78, 0x6c, 0xd5, 0x49, 0x96, 0xf0, 0x14, 0xa5,
++			    0xa0, 0x31, 0xec, 0x14, 0xdb, 0x81, 0x2e, 0xd0,
++			    0x83, 0x55, 0x06, 0x1f, 0xdb, 0x5d, 0xe6, 0x80,
++			    0xa8, 0x00, 0xac, 0x52, 0x1f, 0x31, 0x8e, 0x23 },
++		.valid = true
++	},
++	/* wycheproof - public key >= p */
++	{
++		.private = { 0xc0, 0x4c, 0x5b, 0xae, 0xfa, 0x83, 0x02, 0xdd,
++			     0xde, 0xd6, 0xa4, 0xbb, 0x95, 0x77, 0x61, 0xb4,
++			     0xeb, 0x97, 0xae, 0xfa, 0x4f, 0xc3, 0xb8, 0x04,
++			     0x30, 0x85, 0xf9, 0x6a, 0x56, 0x59, 0xb3, 0xa5 },
++		.public = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
++		.result = { 0x29, 0xae, 0x8b, 0xc7, 0x3e, 0x9b, 0x10, 0xa0,
++			    0x8b, 0x4f, 0x68, 0x1c, 0x43, 0xc3, 0xe0, 0xac,
++			    0x1a, 0x17, 0x1d, 0x31, 0xb3, 0x8f, 0x1a, 0x48,
++			    0xef, 0xba, 0x29, 0xae, 0x63, 0x9e, 0xa1, 0x34 },
++		.valid = true
++	},
++	/* wycheproof - RFC 7748 */
++	{
++		.private = { 0xa0, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d,
++			     0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd,
++			     0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18,
++			     0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0x44 },
++		.public = { 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb,
++			    0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, 0x5f, 0x7c,
++			    0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b,
++			    0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c },
++		.result = { 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90,
++			    0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, 0x08, 0x4f,
++			    0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7,
++			    0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52 },
++		.valid = true
++	},
++	/* wycheproof - RFC 7748 */
++	{
++		.private = { 0x48, 0x66, 0xe9, 0xd4, 0xd1, 0xb4, 0x67, 0x3c,
++			     0x5a, 0xd2, 0x26, 0x91, 0x95, 0x7d, 0x6a, 0xf5,
++			     0xc1, 0x1b, 0x64, 0x21, 0xe0, 0xea, 0x01, 0xd4,
++			     0x2c, 0xa4, 0x16, 0x9e, 0x79, 0x18, 0xba, 0x4d },
++		.public = { 0xe5, 0x21, 0x0f, 0x12, 0x78, 0x68, 0x11, 0xd3,
++			    0xf4, 0xb7, 0x95, 0x9d, 0x05, 0x38, 0xae, 0x2c,
++			    0x31, 0xdb, 0xe7, 0x10, 0x6f, 0xc0, 0x3c, 0x3e,
++			    0xfc, 0x4c, 0xd5, 0x49, 0xc7, 0x15, 0xa4, 0x13 },
++		.result = { 0x95, 0xcb, 0xde, 0x94, 0x76, 0xe8, 0x90, 0x7d,
++			    0x7a, 0xad, 0xe4, 0x5c, 0xb4, 0xb8, 0x73, 0xf8,
++			    0x8b, 0x59, 0x5a, 0x68, 0x79, 0x9f, 0xa1, 0x52,
++			    0xe6, 0xf8, 0xf7, 0x64, 0x7a, 0xac, 0x79, 0x57 },
++		.valid = true
++	},
++	/* wycheproof - edge case for shared secret */
++	{
++		.private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++			     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++			     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++			     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++		.public = { 0x0a, 0xb4, 0xe7, 0x63, 0x80, 0xd8, 0x4d, 0xde,
++			    0x4f, 0x68, 0x33, 0xc5, 0x8f, 0x2a, 0x9f, 0xb8,
++			    0xf8, 0x3b, 0xb0, 0x16, 0x9b, 0x17, 0x2b, 0xe4,
++			    0xb6, 0xe0, 0x59, 0x28, 0x87, 0x74, 0x1a, 0x36 },
++		.result = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.valid = true
++	},
++	/* wycheproof - edge case for shared secret */
++	{
++		.private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++			     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++			     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++			     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++		.public = { 0x89, 0xe1, 0x0d, 0x57, 0x01, 0xb4, 0x33, 0x7d,
++			    0x2d, 0x03, 0x21, 0x81, 0x53, 0x8b, 0x10, 0x64,
++			    0xbd, 0x40, 0x84, 0x40, 0x1c, 0xec, 0xa1, 0xfd,
++			    0x12, 0x66, 0x3a, 0x19, 0x59, 0x38, 0x80, 0x00 },
++		.result = { 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.valid = true
++	},
++	/* wycheproof - edge case for shared secret */
++	{
++		.private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++			     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++			     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++			     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++		.public = { 0x2b, 0x55, 0xd3, 0xaa, 0x4a, 0x8f, 0x80, 0xc8,
++			    0xc0, 0xb2, 0xae, 0x5f, 0x93, 0x3e, 0x85, 0xaf,
++			    0x49, 0xbe, 0xac, 0x36, 0xc2, 0xfa, 0x73, 0x94,
++			    0xba, 0xb7, 0x6c, 0x89, 0x33, 0xf8, 0xf8, 0x1d },
++		.result = { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
++		.valid = true
++	},
++	/* wycheproof - edge case for shared secret */
++	{
++		.private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++			     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++			     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++			     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++		.public = { 0x63, 0xe5, 0xb1, 0xfe, 0x96, 0x01, 0xfe, 0x84,
++			    0x38, 0x5d, 0x88, 0x66, 0xb0, 0x42, 0x12, 0x62,
++			    0xf7, 0x8f, 0xbf, 0xa5, 0xaf, 0xf9, 0x58, 0x5e,
++			    0x62, 0x66, 0x79, 0xb1, 0x85, 0x47, 0xd9, 0x59 },
++		.result = { 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f },
++		.valid = true
++	},
++	/* wycheproof - edge case for shared secret */
++	{
++		.private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++			     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++			     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++			     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++		.public = { 0xe4, 0x28, 0xf3, 0xda, 0xc1, 0x78, 0x09, 0xf8,
++			    0x27, 0xa5, 0x22, 0xce, 0x32, 0x35, 0x50, 0x58,
++			    0xd0, 0x73, 0x69, 0x36, 0x4a, 0xa7, 0x89, 0x02,
++			    0xee, 0x10, 0x13, 0x9b, 0x9f, 0x9d, 0xd6, 0x53 },
++		.result = { 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f },
++		.valid = true
++	},
++	/* wycheproof - edge case for shared secret */
++	{
++		.private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++			     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++			     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++			     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++		.public = { 0xb3, 0xb5, 0x0e, 0x3e, 0xd3, 0xa4, 0x07, 0xb9,
++			    0x5d, 0xe9, 0x42, 0xef, 0x74, 0x57, 0x5b, 0x5a,
++			    0xb8, 0xa1, 0x0c, 0x09, 0xee, 0x10, 0x35, 0x44,
++			    0xd6, 0x0b, 0xdf, 0xed, 0x81, 0x38, 0xab, 0x2b },
++		.result = { 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f },
++		.valid = true
++	},
++	/* wycheproof - edge case for shared secret */
++	{
++		.private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++			     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++			     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++			     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++		.public = { 0x21, 0x3f, 0xff, 0xe9, 0x3d, 0x5e, 0xa8, 0xcd,
++			    0x24, 0x2e, 0x46, 0x28, 0x44, 0x02, 0x99, 0x22,
++			    0xc4, 0x3c, 0x77, 0xc9, 0xe3, 0xe4, 0x2f, 0x56,
++			    0x2f, 0x48, 0x5d, 0x24, 0xc5, 0x01, 0xa2, 0x0b },
++		.result = { 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f },
++		.valid = true
++	},
++	/* wycheproof - edge case for shared secret */
++	{
++		.private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++			     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++			     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++			     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++		.public = { 0x91, 0xb2, 0x32, 0xa1, 0x78, 0xb3, 0xcd, 0x53,
++			    0x09, 0x32, 0x44, 0x1e, 0x61, 0x39, 0x41, 0x8f,
++			    0x72, 0x17, 0x22, 0x92, 0xf1, 0xda, 0x4c, 0x18,
++			    0x34, 0xfc, 0x5e, 0xbf, 0xef, 0xb5, 0x1e, 0x3f },
++		.result = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03 },
++		.valid = true
++	},
++	/* wycheproof - edge case for shared secret */
++	{
++		.private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++			     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++			     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++			     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++		.public = { 0x04, 0x5c, 0x6e, 0x11, 0xc5, 0xd3, 0x32, 0x55,
++			    0x6c, 0x78, 0x22, 0xfe, 0x94, 0xeb, 0xf8, 0x9b,
++			    0x56, 0xa3, 0x87, 0x8d, 0xc2, 0x7c, 0xa0, 0x79,
++			    0x10, 0x30, 0x58, 0x84, 0x9f, 0xab, 0xcb, 0x4f },
++		.result = { 0xe5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++		.valid = true
++	},
++	/* wycheproof - edge case for shared secret */
++	{
++		.private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++			     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++			     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++			     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++		.public = { 0x1c, 0xa2, 0x19, 0x0b, 0x71, 0x16, 0x35, 0x39,
++			    0x06, 0x3c, 0x35, 0x77, 0x3b, 0xda, 0x0c, 0x9c,
++			    0x92, 0x8e, 0x91, 0x36, 0xf0, 0x62, 0x0a, 0xeb,
++			    0x09, 0x3f, 0x09, 0x91, 0x97, 0xb7, 0xf7, 0x4e },
++		.result = { 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++		.valid = true
++	},
++	/* wycheproof - edge case for shared secret */
++	{
++		.private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++			     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++			     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++			     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++		.public = { 0xf7, 0x6e, 0x90, 0x10, 0xac, 0x33, 0xc5, 0x04,
++			    0x3b, 0x2d, 0x3b, 0x76, 0xa8, 0x42, 0x17, 0x10,
++			    0x00, 0xc4, 0x91, 0x62, 0x22, 0xe9, 0xe8, 0x58,
++			    0x97, 0xa0, 0xae, 0xc7, 0xf6, 0x35, 0x0b, 0x3c },
++		.result = { 0xdd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++		.valid = true
++	},
++	/* wycheproof - edge case for shared secret */
++	{
++		.private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++			     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++			     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++			     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++		.public = { 0xbb, 0x72, 0x68, 0x8d, 0x8f, 0x8a, 0xa7, 0xa3,
++			    0x9c, 0xd6, 0x06, 0x0c, 0xd5, 0xc8, 0x09, 0x3c,
++			    0xde, 0xc6, 0xfe, 0x34, 0x19, 0x37, 0xc3, 0x88,
++			    0x6a, 0x99, 0x34, 0x6c, 0xd0, 0x7f, 0xaa, 0x55 },
++		.result = { 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f },
++		.valid = true
++	},
++	/* wycheproof - edge case for shared secret */
++	{
++		.private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++			     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++			     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++			     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++		.public = { 0x88, 0xfd, 0xde, 0xa1, 0x93, 0x39, 0x1c, 0x6a,
++			    0x59, 0x33, 0xef, 0x9b, 0x71, 0x90, 0x15, 0x49,
++			    0x44, 0x72, 0x05, 0xaa, 0xe9, 0xda, 0x92, 0x8a,
++			    0x6b, 0x91, 0xa3, 0x52, 0xba, 0x10, 0xf4, 0x1f },
++		.result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 },
++		.valid = true
++	},
++	/* wycheproof - edge case for shared secret */
++	{
++		.private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4,
++			     0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3,
++			     0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc,
++			     0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 },
++		.public = { 0x30, 0x3b, 0x39, 0x2f, 0x15, 0x31, 0x16, 0xca,
++			    0xd9, 0xcc, 0x68, 0x2a, 0x00, 0xcc, 0xc4, 0x4c,
++			    0x95, 0xff, 0x0d, 0x3b, 0xbe, 0x56, 0x8b, 0xeb,
++			    0x6c, 0x4e, 0x73, 0x9b, 0xaf, 0xdc, 0x2c, 0x68 },
++		.result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 },
++		.valid = true
++	},
++	/* wycheproof - checking for overflow */
++	{
++		.private = { 0xc8, 0x17, 0x24, 0x70, 0x40, 0x00, 0xb2, 0x6d,
++			     0x31, 0x70, 0x3c, 0xc9, 0x7e, 0x3a, 0x37, 0x8d,
++			     0x56, 0xfa, 0xd8, 0x21, 0x93, 0x61, 0xc8, 0x8c,
++			     0xca, 0x8b, 0xd7, 0xc5, 0x71, 0x9b, 0x12, 0xb2 },
++		.public = { 0xfd, 0x30, 0x0a, 0xeb, 0x40, 0xe1, 0xfa, 0x58,
++			    0x25, 0x18, 0x41, 0x2b, 0x49, 0xb2, 0x08, 0xa7,
++			    0x84, 0x2b, 0x1e, 0x1f, 0x05, 0x6a, 0x04, 0x01,
++			    0x78, 0xea, 0x41, 0x41, 0x53, 0x4f, 0x65, 0x2d },
++		.result = { 0xb7, 0x34, 0x10, 0x5d, 0xc2, 0x57, 0x58, 0x5d,
++			    0x73, 0xb5, 0x66, 0xcc, 0xb7, 0x6f, 0x06, 0x27,
++			    0x95, 0xcc, 0xbe, 0xc8, 0x91, 0x28, 0xe5, 0x2b,
++			    0x02, 0xf3, 0xe5, 0x96, 0x39, 0xf1, 0x3c, 0x46 },
++		.valid = true
++	},
++	/* wycheproof - checking for overflow */
++	{
++		.private = { 0xc8, 0x17, 0x24, 0x70, 0x40, 0x00, 0xb2, 0x6d,
++			     0x31, 0x70, 0x3c, 0xc9, 0x7e, 0x3a, 0x37, 0x8d,
++			     0x56, 0xfa, 0xd8, 0x21, 0x93, 0x61, 0xc8, 0x8c,
++			     0xca, 0x8b, 0xd7, 0xc5, 0x71, 0x9b, 0x12, 0xb2 },
++		.public = { 0xc8, 0xef, 0x79, 0xb5, 0x14, 0xd7, 0x68, 0x26,
++			    0x77, 0xbc, 0x79, 0x31, 0xe0, 0x6e, 0xe5, 0xc2,
++			    0x7c, 0x9b, 0x39, 0x2b, 0x4a, 0xe9, 0x48, 0x44,
++			    0x73, 0xf5, 0x54, 0xe6, 0x67, 0x8e, 0xcc, 0x2e },
++		.result = { 0x64, 0x7a, 0x46, 0xb6, 0xfc, 0x3f, 0x40, 0xd6,
++			    0x21, 0x41, 0xee, 0x3c, 0xee, 0x70, 0x6b, 0x4d,
++			    0x7a, 0x92, 0x71, 0x59, 0x3a, 0x7b, 0x14, 0x3e,
++			    0x8e, 0x2e, 0x22, 0x79, 0x88, 0x3e, 0x45, 0x50 },
++		.valid = true
++	},
++	/* wycheproof - checking for overflow */
++	{
++		.private = { 0xc8, 0x17, 0x24, 0x70, 0x40, 0x00, 0xb2, 0x6d,
++			     0x31, 0x70, 0x3c, 0xc9, 0x7e, 0x3a, 0x37, 0x8d,
++			     0x56, 0xfa, 0xd8, 0x21, 0x93, 0x61, 0xc8, 0x8c,
++			     0xca, 0x8b, 0xd7, 0xc5, 0x71, 0x9b, 0x12, 0xb2 },
++		.public = { 0x64, 0xae, 0xac, 0x25, 0x04, 0x14, 0x48, 0x61,
++			    0x53, 0x2b, 0x7b, 0xbc, 0xb6, 0xc8, 0x7d, 0x67,
++			    0xdd, 0x4c, 0x1f, 0x07, 0xeb, 0xc2, 0xe0, 0x6e,
++			    0xff, 0xb9, 0x5a, 0xec, 0xc6, 0x17, 0x0b, 0x2c },
++		.result = { 0x4f, 0xf0, 0x3d, 0x5f, 0xb4, 0x3c, 0xd8, 0x65,
++			    0x7a, 0x3c, 0xf3, 0x7c, 0x13, 0x8c, 0xad, 0xce,
++			    0xcc, 0xe5, 0x09, 0xe4, 0xeb, 0xa0, 0x89, 0xd0,
++			    0xef, 0x40, 0xb4, 0xe4, 0xfb, 0x94, 0x61, 0x55 },
++		.valid = true
++	},
++	/* wycheproof - checking for overflow */
++	{
++		.private = { 0xc8, 0x17, 0x24, 0x70, 0x40, 0x00, 0xb2, 0x6d,
++			     0x31, 0x70, 0x3c, 0xc9, 0x7e, 0x3a, 0x37, 0x8d,
++			     0x56, 0xfa, 0xd8, 0x21, 0x93, 0x61, 0xc8, 0x8c,
++			     0xca, 0x8b, 0xd7, 0xc5, 0x71, 0x9b, 0x12, 0xb2 },
++		.public = { 0xbf, 0x68, 0xe3, 0x5e, 0x9b, 0xdb, 0x7e, 0xee,
++			    0x1b, 0x50, 0x57, 0x02, 0x21, 0x86, 0x0f, 0x5d,
++			    0xcd, 0xad, 0x8a, 0xcb, 0xab, 0x03, 0x1b, 0x14,
++			    0x97, 0x4c, 0xc4, 0x90, 0x13, 0xc4, 0x98, 0x31 },
++		.result = { 0x21, 0xce, 0xe5, 0x2e, 0xfd, 0xbc, 0x81, 0x2e,
++			    0x1d, 0x02, 0x1a, 0x4a, 0xf1, 0xe1, 0xd8, 0xbc,
++			    0x4d, 0xb3, 0xc4, 0x00, 0xe4, 0xd2, 0xa2, 0xc5,
++			    0x6a, 0x39, 0x26, 0xdb, 0x4d, 0x99, 0xc6, 0x5b },
++		.valid = true
++	},
++	/* wycheproof - checking for overflow */
++	{
++		.private = { 0xc8, 0x17, 0x24, 0x70, 0x40, 0x00, 0xb2, 0x6d,
++			     0x31, 0x70, 0x3c, 0xc9, 0x7e, 0x3a, 0x37, 0x8d,
++			     0x56, 0xfa, 0xd8, 0x21, 0x93, 0x61, 0xc8, 0x8c,
++			     0xca, 0x8b, 0xd7, 0xc5, 0x71, 0x9b, 0x12, 0xb2 },
++		.public = { 0x53, 0x47, 0xc4, 0x91, 0x33, 0x1a, 0x64, 0xb4,
++			    0x3d, 0xdc, 0x68, 0x30, 0x34, 0xe6, 0x77, 0xf5,
++			    0x3d, 0xc3, 0x2b, 0x52, 0xa5, 0x2a, 0x57, 0x7c,
++			    0x15, 0xa8, 0x3b, 0xf2, 0x98, 0xe9, 0x9f, 0x19 },
++		.result = { 0x18, 0xcb, 0x89, 0xe4, 0xe2, 0x0c, 0x0c, 0x2b,
++			    0xd3, 0x24, 0x30, 0x52, 0x45, 0x26, 0x6c, 0x93,
++			    0x27, 0x69, 0x0b, 0xbe, 0x79, 0xac, 0xb8, 0x8f,
++			    0x5b, 0x8f, 0xb3, 0xf7, 0x4e, 0xca, 0x3e, 0x52 },
++		.valid = true
++	},
++	/* wycheproof - private key == -1 (mod order) */
++	{
++		.private = { 0xa0, 0x23, 0xcd, 0xd0, 0x83, 0xef, 0x5b, 0xb8,
++			     0x2f, 0x10, 0xd6, 0x2e, 0x59, 0xe1, 0x5a, 0x68,
++			     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++			     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50 },
++		.public = { 0x25, 0x8e, 0x04, 0x52, 0x3b, 0x8d, 0x25, 0x3e,
++			    0xe6, 0x57, 0x19, 0xfc, 0x69, 0x06, 0xc6, 0x57,
++			    0x19, 0x2d, 0x80, 0x71, 0x7e, 0xdc, 0x82, 0x8f,
++			    0xa0, 0xaf, 0x21, 0x68, 0x6e, 0x2f, 0xaa, 0x75 },
++		.result = { 0x25, 0x8e, 0x04, 0x52, 0x3b, 0x8d, 0x25, 0x3e,
++			    0xe6, 0x57, 0x19, 0xfc, 0x69, 0x06, 0xc6, 0x57,
++			    0x19, 0x2d, 0x80, 0x71, 0x7e, 0xdc, 0x82, 0x8f,
++			    0xa0, 0xaf, 0x21, 0x68, 0x6e, 0x2f, 0xaa, 0x75 },
++		.valid = true
++	},
++	/* wycheproof - private key == 1 (mod order) on twist */
++	{
++		.private = { 0x58, 0x08, 0x3d, 0xd2, 0x61, 0xad, 0x91, 0xef,
++			     0xf9, 0x52, 0x32, 0x2e, 0xc8, 0x24, 0xc6, 0x82,
++			     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++			     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5f },
++		.public = { 0x2e, 0xae, 0x5e, 0xc3, 0xdd, 0x49, 0x4e, 0x9f,
++			    0x2d, 0x37, 0xd2, 0x58, 0xf8, 0x73, 0xa8, 0xe6,
++			    0xe9, 0xd0, 0xdb, 0xd1, 0xe3, 0x83, 0xef, 0x64,
++			    0xd9, 0x8b, 0xb9, 0x1b, 0x3e, 0x0b, 0xe0, 0x35 },
++		.result = { 0x2e, 0xae, 0x5e, 0xc3, 0xdd, 0x49, 0x4e, 0x9f,
++			    0x2d, 0x37, 0xd2, 0x58, 0xf8, 0x73, 0xa8, 0xe6,
++			    0xe9, 0xd0, 0xdb, 0xd1, 0xe3, 0x83, 0xef, 0x64,
++			    0xd9, 0x8b, 0xb9, 0x1b, 0x3e, 0x0b, 0xe0, 0x35 },
++		.valid = true
++	}
++};
++
++bool __init curve25519_selftest(void)
++{
++	bool success = true, ret, ret2;
++	size_t i = 0, j;
++	u8 in[CURVE25519_KEY_SIZE];
++	u8 out[CURVE25519_KEY_SIZE], out2[CURVE25519_KEY_SIZE],
++	   out3[CURVE25519_KEY_SIZE];
++
++	for (i = 0; i < ARRAY_SIZE(curve25519_test_vectors); ++i) {
++		memset(out, 0, CURVE25519_KEY_SIZE);
++		ret = curve25519(out, curve25519_test_vectors[i].private,
++				 curve25519_test_vectors[i].public);
++		if (ret != curve25519_test_vectors[i].valid ||
++		    memcmp(out, curve25519_test_vectors[i].result,
++			   CURVE25519_KEY_SIZE)) {
++			pr_err("curve25519 self-test %zu: FAIL\n", i + 1);
++			success = false;
++		}
++	}
++
++	for (i = 0; i < 5; ++i) {
++		get_random_bytes(in, sizeof(in));
++		ret = curve25519_generate_public(out, in);
++		ret2 = curve25519(out2, in, (u8[CURVE25519_KEY_SIZE]){ 9 });
++		curve25519_generic(out3, in, (u8[CURVE25519_KEY_SIZE]){ 9 });
++		if (ret != ret2 ||
++		    memcmp(out, out2, CURVE25519_KEY_SIZE) ||
++		    memcmp(out, out3, CURVE25519_KEY_SIZE)) {
++			pr_err("curve25519 basepoint self-test %zu: FAIL: input - 0x",
++			       i + 1);
++			for (j = CURVE25519_KEY_SIZE; j-- > 0;)
++				printk(KERN_CONT "%02x", in[j]);
++			printk(KERN_CONT "\n");
++			success = false;
++		}
++	}
++
++	return success;
++}
+--- a/lib/crypto/curve25519.c
++++ b/lib/crypto/curve25519.c
+@@ -13,6 +13,8 @@
+ #include <linux/module.h>
+ #include <linux/init.h>
+ 
++bool curve25519_selftest(void);
++
+ const u8 curve25519_null_point[CURVE25519_KEY_SIZE] __aligned(32) = { 0 };
+ const u8 curve25519_base_point[CURVE25519_KEY_SIZE] __aligned(32) = { 9 };
+ 
+@@ -20,6 +22,21 @@ EXPORT_SYMBOL(curve25519_null_point);
+ EXPORT_SYMBOL(curve25519_base_point);
+ EXPORT_SYMBOL(curve25519_generic);
+ 
++static int __init mod_init(void)
++{
++	if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) &&
++	    WARN_ON(!curve25519_selftest()))
++		return -ENODEV;
++	return 0;
++}
++
++static void __exit mod_exit(void)
++{
++}
++
++module_init(mod_init);
++module_exit(mod_exit);
++
+ MODULE_LICENSE("GPL v2");
+ MODULE_DESCRIPTION("Curve25519 scalar multiplication");
+ MODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0041-crypto-poly1305-add-new-32-and-64-bit-generic-versio.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0041-crypto-poly1305-add-new-32-and-64-bit-generic-versio.patch
new file mode 100644
index 0000000..c41ef55
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0041-crypto-poly1305-add-new-32-and-64-bit-generic-versio.patch
@@ -0,0 +1,1164 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Sun, 5 Jan 2020 22:40:46 -0500
+Subject: [PATCH] crypto: poly1305 - add new 32 and 64-bit generic versions
+
+commit 1c08a104360f3e18f4ee6346c21cc3923efb952e upstream.
+
+These two C implementations from Zinc -- a 32x32 one and a 64x64 one,
+depending on the platform -- come from Andrew Moon's public domain
+poly1305-donna portable code, modified for usage in the kernel. The
+precomputation in the 32-bit version and the use of 64x64 multiplies in
+the 64-bit version make these perform better than the code it replaces.
+Moon's code is also very widespread and has received many eyeballs of
+scrutiny.
+
+There's a bit of interference between the x86 implementation, which
+relies on internal details of the old scalar implementation. In the next
+commit, the x86 implementation will be replaced with a faster one that
+doesn't rely on this, so none of this matters much. But for now, to keep
+this passing the tests, we inline the bits of the old implementation
+that the x86 implementation relied on. Also, since we now support a
+slightly larger key space, via the union, some offsets had to be fixed
+up.
+
+Nonce calculation was folded in with the emit function, to take
+advantage of 64x64 arithmetic. However, Adiantum appeared to rely on no
+nonce handling in emit, so this path was conditionalized. We also
+introduced a new struct, poly1305_core_key, to represent the precise
+amount of space that particular implementation uses.
+
+Testing with kbench9000, depending on the CPU, the update function for
+the 32x32 version has been improved by 4%-7%, and for the 64x64 by
+19%-30%. The 32x32 gains are small, but I think there's great value in
+having a parallel implementation to the 64x64 one so that the two can be
+compared side-by-side as nice stand-alone units.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/poly1305-avx2-x86_64.S |  20 +--
+ arch/x86/crypto/poly1305_glue.c        | 215 +++++++++++++++++++++++--
+ crypto/adiantum.c                      |   4 +-
+ crypto/nhpoly1305.c                    |   2 +-
+ crypto/poly1305_generic.c              |  25 ++-
+ include/crypto/internal/poly1305.h     |  45 ++----
+ include/crypto/nhpoly1305.h            |   4 +-
+ include/crypto/poly1305.h              |  26 ++-
+ lib/crypto/Makefile                    |   4 +-
+ lib/crypto/poly1305-donna32.c          | 204 +++++++++++++++++++++++
+ lib/crypto/poly1305-donna64.c          | 185 +++++++++++++++++++++
+ lib/crypto/poly1305.c                  | 169 +------------------
+ 12 files changed, 675 insertions(+), 228 deletions(-)
+ create mode 100644 lib/crypto/poly1305-donna32.c
+ create mode 100644 lib/crypto/poly1305-donna64.c
+
+--- a/arch/x86/crypto/poly1305-avx2-x86_64.S
++++ b/arch/x86/crypto/poly1305-avx2-x86_64.S
+@@ -34,16 +34,16 @@ ORMASK:	.octa 0x000000000100000000000000
+ #define u2 0x08(%r8)
+ #define u3 0x0c(%r8)
+ #define u4 0x10(%r8)
+-#define w0 0x14(%r8)
+-#define w1 0x18(%r8)
+-#define w2 0x1c(%r8)
+-#define w3 0x20(%r8)
+-#define w4 0x24(%r8)
+-#define y0 0x28(%r8)
+-#define y1 0x2c(%r8)
+-#define y2 0x30(%r8)
+-#define y3 0x34(%r8)
+-#define y4 0x38(%r8)
++#define w0 0x18(%r8)
++#define w1 0x1c(%r8)
++#define w2 0x20(%r8)
++#define w3 0x24(%r8)
++#define w4 0x28(%r8)
++#define y0 0x30(%r8)
++#define y1 0x34(%r8)
++#define y2 0x38(%r8)
++#define y3 0x3c(%r8)
++#define y4 0x40(%r8)
+ #define m %rsi
+ #define hc0 %ymm0
+ #define hc1 %ymm1
+--- a/arch/x86/crypto/poly1305_glue.c
++++ b/arch/x86/crypto/poly1305_glue.c
+@@ -25,6 +25,21 @@ asmlinkage void poly1305_4block_avx2(u32
+ static __ro_after_init DEFINE_STATIC_KEY_FALSE(poly1305_use_simd);
+ static __ro_after_init DEFINE_STATIC_KEY_FALSE(poly1305_use_avx2);
+ 
++static inline u64 mlt(u64 a, u64 b)
++{
++	return a * b;
++}
++
++static inline u32 sr(u64 v, u_char n)
++{
++	return v >> n;
++}
++
++static inline u32 and(u32 v, u32 mask)
++{
++	return v & mask;
++}
++
+ static void poly1305_simd_mult(u32 *a, const u32 *b)
+ {
+ 	u8 m[POLY1305_BLOCK_SIZE];
+@@ -36,6 +51,168 @@ static void poly1305_simd_mult(u32 *a, c
+ 	poly1305_block_sse2(a, m, b, 1);
+ }
+ 
++static void poly1305_integer_setkey(struct poly1305_key *key, const u8 *raw_key)
++{
++	/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
++	key->r[0] = (get_unaligned_le32(raw_key +  0) >> 0) & 0x3ffffff;
++	key->r[1] = (get_unaligned_le32(raw_key +  3) >> 2) & 0x3ffff03;
++	key->r[2] = (get_unaligned_le32(raw_key +  6) >> 4) & 0x3ffc0ff;
++	key->r[3] = (get_unaligned_le32(raw_key +  9) >> 6) & 0x3f03fff;
++	key->r[4] = (get_unaligned_le32(raw_key + 12) >> 8) & 0x00fffff;
++}
++
++static void poly1305_integer_blocks(struct poly1305_state *state,
++				    const struct poly1305_key *key,
++				    const void *src,
++				    unsigned int nblocks, u32 hibit)
++{
++	u32 r0, r1, r2, r3, r4;
++	u32 s1, s2, s3, s4;
++	u32 h0, h1, h2, h3, h4;
++	u64 d0, d1, d2, d3, d4;
++
++	if (!nblocks)
++		return;
++
++	r0 = key->r[0];
++	r1 = key->r[1];
++	r2 = key->r[2];
++	r3 = key->r[3];
++	r4 = key->r[4];
++
++	s1 = r1 * 5;
++	s2 = r2 * 5;
++	s3 = r3 * 5;
++	s4 = r4 * 5;
++
++	h0 = state->h[0];
++	h1 = state->h[1];
++	h2 = state->h[2];
++	h3 = state->h[3];
++	h4 = state->h[4];
++
++	do {
++		/* h += m[i] */
++		h0 += (get_unaligned_le32(src +  0) >> 0) & 0x3ffffff;
++		h1 += (get_unaligned_le32(src +  3) >> 2) & 0x3ffffff;
++		h2 += (get_unaligned_le32(src +  6) >> 4) & 0x3ffffff;
++		h3 += (get_unaligned_le32(src +  9) >> 6) & 0x3ffffff;
++		h4 += (get_unaligned_le32(src + 12) >> 8) | (hibit << 24);
++
++		/* h *= r */
++		d0 = mlt(h0, r0) + mlt(h1, s4) + mlt(h2, s3) +
++		     mlt(h3, s2) + mlt(h4, s1);
++		d1 = mlt(h0, r1) + mlt(h1, r0) + mlt(h2, s4) +
++		     mlt(h3, s3) + mlt(h4, s2);
++		d2 = mlt(h0, r2) + mlt(h1, r1) + mlt(h2, r0) +
++		     mlt(h3, s4) + mlt(h4, s3);
++		d3 = mlt(h0, r3) + mlt(h1, r2) + mlt(h2, r1) +
++		     mlt(h3, r0) + mlt(h4, s4);
++		d4 = mlt(h0, r4) + mlt(h1, r3) + mlt(h2, r2) +
++		     mlt(h3, r1) + mlt(h4, r0);
++
++		/* (partial) h %= p */
++		d1 += sr(d0, 26);     h0 = and(d0, 0x3ffffff);
++		d2 += sr(d1, 26);     h1 = and(d1, 0x3ffffff);
++		d3 += sr(d2, 26);     h2 = and(d2, 0x3ffffff);
++		d4 += sr(d3, 26);     h3 = and(d3, 0x3ffffff);
++		h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff);
++		h1 += h0 >> 26;       h0 = h0 & 0x3ffffff;
++
++		src += POLY1305_BLOCK_SIZE;
++	} while (--nblocks);
++
++	state->h[0] = h0;
++	state->h[1] = h1;
++	state->h[2] = h2;
++	state->h[3] = h3;
++	state->h[4] = h4;
++}
++
++static void poly1305_integer_emit(const struct poly1305_state *state, void *dst)
++{
++	u32 h0, h1, h2, h3, h4;
++	u32 g0, g1, g2, g3, g4;
++	u32 mask;
++
++	/* fully carry h */
++	h0 = state->h[0];
++	h1 = state->h[1];
++	h2 = state->h[2];
++	h3 = state->h[3];
++	h4 = state->h[4];
++
++	h2 += (h1 >> 26);     h1 = h1 & 0x3ffffff;
++	h3 += (h2 >> 26);     h2 = h2 & 0x3ffffff;
++	h4 += (h3 >> 26);     h3 = h3 & 0x3ffffff;
++	h0 += (h4 >> 26) * 5; h4 = h4 & 0x3ffffff;
++	h1 += (h0 >> 26);     h0 = h0 & 0x3ffffff;
++
++	/* compute h + -p */
++	g0 = h0 + 5;
++	g1 = h1 + (g0 >> 26);             g0 &= 0x3ffffff;
++	g2 = h2 + (g1 >> 26);             g1 &= 0x3ffffff;
++	g3 = h3 + (g2 >> 26);             g2 &= 0x3ffffff;
++	g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x3ffffff;
++
++	/* select h if h < p, or h + -p if h >= p */
++	mask = (g4 >> ((sizeof(u32) * 8) - 1)) - 1;
++	g0 &= mask;
++	g1 &= mask;
++	g2 &= mask;
++	g3 &= mask;
++	g4 &= mask;
++	mask = ~mask;
++	h0 = (h0 & mask) | g0;
++	h1 = (h1 & mask) | g1;
++	h2 = (h2 & mask) | g2;
++	h3 = (h3 & mask) | g3;
++	h4 = (h4 & mask) | g4;
++
++	/* h = h % (2^128) */
++	put_unaligned_le32((h0 >>  0) | (h1 << 26), dst +  0);
++	put_unaligned_le32((h1 >>  6) | (h2 << 20), dst +  4);
++	put_unaligned_le32((h2 >> 12) | (h3 << 14), dst +  8);
++	put_unaligned_le32((h3 >> 18) | (h4 <<  8), dst + 12);
++}
++
++void poly1305_init_arch(struct poly1305_desc_ctx *desc, const u8 *key)
++{
++	poly1305_integer_setkey(desc->opaque_r, key);
++	desc->s[0] = get_unaligned_le32(key + 16);
++	desc->s[1] = get_unaligned_le32(key + 20);
++	desc->s[2] = get_unaligned_le32(key + 24);
++	desc->s[3] = get_unaligned_le32(key + 28);
++	poly1305_core_init(&desc->h);
++	desc->buflen = 0;
++	desc->sset = true;
++	desc->rset = 1;
++}
++EXPORT_SYMBOL_GPL(poly1305_init_arch);
++
++static unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
++					       const u8 *src, unsigned int srclen)
++{
++	if (!dctx->sset) {
++		if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) {
++			poly1305_integer_setkey(dctx->r, src);
++			src += POLY1305_BLOCK_SIZE;
++			srclen -= POLY1305_BLOCK_SIZE;
++			dctx->rset = 1;
++		}
++		if (srclen >= POLY1305_BLOCK_SIZE) {
++			dctx->s[0] = get_unaligned_le32(src +  0);
++			dctx->s[1] = get_unaligned_le32(src +  4);
++			dctx->s[2] = get_unaligned_le32(src +  8);
++			dctx->s[3] = get_unaligned_le32(src + 12);
++			src += POLY1305_BLOCK_SIZE;
++			srclen -= POLY1305_BLOCK_SIZE;
++			dctx->sset = true;
++		}
++	}
++	return srclen;
++}
++
+ static unsigned int poly1305_scalar_blocks(struct poly1305_desc_ctx *dctx,
+ 					   const u8 *src, unsigned int srclen)
+ {
+@@ -47,8 +224,8 @@ static unsigned int poly1305_scalar_bloc
+ 		srclen = datalen;
+ 	}
+ 	if (srclen >= POLY1305_BLOCK_SIZE) {
+-		poly1305_core_blocks(&dctx->h, dctx->r, src,
+-				     srclen / POLY1305_BLOCK_SIZE, 1);
++		poly1305_integer_blocks(&dctx->h, dctx->opaque_r, src,
++					srclen / POLY1305_BLOCK_SIZE, 1);
+ 		srclen %= POLY1305_BLOCK_SIZE;
+ 	}
+ 	return srclen;
+@@ -105,12 +282,6 @@ static unsigned int poly1305_simd_blocks
+ 	return srclen;
+ }
+ 
+-void poly1305_init_arch(struct poly1305_desc_ctx *desc, const u8 *key)
+-{
+-	poly1305_init_generic(desc, key);
+-}
+-EXPORT_SYMBOL(poly1305_init_arch);
+-
+ void poly1305_update_arch(struct poly1305_desc_ctx *dctx, const u8 *src,
+ 			  unsigned int srclen)
+ {
+@@ -158,9 +329,31 @@ void poly1305_update_arch(struct poly130
+ }
+ EXPORT_SYMBOL(poly1305_update_arch);
+ 
+-void poly1305_final_arch(struct poly1305_desc_ctx *desc, u8 *digest)
++void poly1305_final_arch(struct poly1305_desc_ctx *desc, u8 *dst)
+ {
+-	poly1305_final_generic(desc, digest);
++	__le32 digest[4];
++	u64 f = 0;
++
++	if (unlikely(desc->buflen)) {
++		desc->buf[desc->buflen++] = 1;
++		memset(desc->buf + desc->buflen, 0,
++		       POLY1305_BLOCK_SIZE - desc->buflen);
++		poly1305_integer_blocks(&desc->h, desc->opaque_r, desc->buf, 1, 0);
++	}
++
++	poly1305_integer_emit(&desc->h, digest);
++
++	/* mac = (h + s) % (2^128) */
++	f = (f >> 32) + le32_to_cpu(digest[0]) + desc->s[0];
++	put_unaligned_le32(f, dst + 0);
++	f = (f >> 32) + le32_to_cpu(digest[1]) + desc->s[1];
++	put_unaligned_le32(f, dst + 4);
++	f = (f >> 32) + le32_to_cpu(digest[2]) + desc->s[2];
++	put_unaligned_le32(f, dst + 8);
++	f = (f >> 32) + le32_to_cpu(digest[3]) + desc->s[3];
++	put_unaligned_le32(f, dst + 12);
++
++	*desc = (struct poly1305_desc_ctx){};
+ }
+ EXPORT_SYMBOL(poly1305_final_arch);
+ 
+@@ -183,7 +376,7 @@ static int crypto_poly1305_final(struct
+ 	if (unlikely(!dctx->sset))
+ 		return -ENOKEY;
+ 
+-	poly1305_final_generic(dctx, dst);
++	poly1305_final_arch(dctx, dst);
+ 	return 0;
+ }
+ 
+--- a/crypto/adiantum.c
++++ b/crypto/adiantum.c
+@@ -72,7 +72,7 @@ struct adiantum_tfm_ctx {
+ 	struct crypto_skcipher *streamcipher;
+ 	struct crypto_cipher *blockcipher;
+ 	struct crypto_shash *hash;
+-	struct poly1305_key header_hash_key;
++	struct poly1305_core_key header_hash_key;
+ };
+ 
+ struct adiantum_request_ctx {
+@@ -249,7 +249,7 @@ static void adiantum_hash_header(struct
+ 	poly1305_core_blocks(&state, &tctx->header_hash_key, req->iv,
+ 			     TWEAK_SIZE / POLY1305_BLOCK_SIZE, 1);
+ 
+-	poly1305_core_emit(&state, &rctx->header_hash);
++	poly1305_core_emit(&state, NULL, &rctx->header_hash);
+ }
+ 
+ /* Hash the left-hand part (the "bulk") of the message using NHPoly1305 */
+--- a/crypto/nhpoly1305.c
++++ b/crypto/nhpoly1305.c
+@@ -210,7 +210,7 @@ int crypto_nhpoly1305_final_helper(struc
+ 	if (state->nh_remaining)
+ 		process_nh_hash_value(state, key);
+ 
+-	poly1305_core_emit(&state->poly_state, dst);
++	poly1305_core_emit(&state->poly_state, NULL, dst);
+ 	return 0;
+ }
+ EXPORT_SYMBOL(crypto_nhpoly1305_final_helper);
+--- a/crypto/poly1305_generic.c
++++ b/crypto/poly1305_generic.c
+@@ -31,6 +31,29 @@ static int crypto_poly1305_init(struct s
+ 	return 0;
+ }
+ 
++static unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
++					       const u8 *src, unsigned int srclen)
++{
++	if (!dctx->sset) {
++		if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) {
++			poly1305_core_setkey(&dctx->core_r, src);
++			src += POLY1305_BLOCK_SIZE;
++			srclen -= POLY1305_BLOCK_SIZE;
++			dctx->rset = 2;
++		}
++		if (srclen >= POLY1305_BLOCK_SIZE) {
++			dctx->s[0] = get_unaligned_le32(src +  0);
++			dctx->s[1] = get_unaligned_le32(src +  4);
++			dctx->s[2] = get_unaligned_le32(src +  8);
++			dctx->s[3] = get_unaligned_le32(src + 12);
++			src += POLY1305_BLOCK_SIZE;
++			srclen -= POLY1305_BLOCK_SIZE;
++			dctx->sset = true;
++		}
++	}
++	return srclen;
++}
++
+ static void poly1305_blocks(struct poly1305_desc_ctx *dctx, const u8 *src,
+ 			    unsigned int srclen)
+ {
+@@ -42,7 +65,7 @@ static void poly1305_blocks(struct poly1
+ 		srclen = datalen;
+ 	}
+ 
+-	poly1305_core_blocks(&dctx->h, dctx->r, src,
++	poly1305_core_blocks(&dctx->h, &dctx->core_r, src,
+ 			     srclen / POLY1305_BLOCK_SIZE, 1);
+ }
+ 
+--- a/include/crypto/internal/poly1305.h
++++ b/include/crypto/internal/poly1305.h
+@@ -11,48 +11,23 @@
+ #include <crypto/poly1305.h>
+ 
+ /*
+- * Poly1305 core functions.  These implement the ε-almost-∆-universal hash
+- * function underlying the Poly1305 MAC, i.e. they don't add an encrypted nonce
+- * ("s key") at the end.  They also only support block-aligned inputs.
++ * Poly1305 core functions.  These only accept whole blocks; the caller must
++ * handle any needed block buffering and padding.  'hibit' must be 1 for any
++ * full blocks, or 0 for the final block if it had to be padded.  If 'nonce' is
++ * non-NULL, then it's added at the end to compute the Poly1305 MAC.  Otherwise,
++ * only the ε-almost-∆-universal hash function (not the full MAC) is computed.
+  */
+-void poly1305_core_setkey(struct poly1305_key *key, const u8 *raw_key);
++
++void poly1305_core_setkey(struct poly1305_core_key *key, const u8 *raw_key);
+ static inline void poly1305_core_init(struct poly1305_state *state)
+ {
+ 	*state = (struct poly1305_state){};
+ }
+ 
+ void poly1305_core_blocks(struct poly1305_state *state,
+-			  const struct poly1305_key *key, const void *src,
++			  const struct poly1305_core_key *key, const void *src,
+ 			  unsigned int nblocks, u32 hibit);
+-void poly1305_core_emit(const struct poly1305_state *state, void *dst);
+-
+-/*
+- * Poly1305 requires a unique key for each tag, which implies that we can't set
+- * it on the tfm that gets accessed by multiple users simultaneously. Instead we
+- * expect the key as the first 32 bytes in the update() call.
+- */
+-static inline
+-unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
+-					const u8 *src, unsigned int srclen)
+-{
+-	if (!dctx->sset) {
+-		if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) {
+-			poly1305_core_setkey(dctx->r, src);
+-			src += POLY1305_BLOCK_SIZE;
+-			srclen -= POLY1305_BLOCK_SIZE;
+-			dctx->rset = 1;
+-		}
+-		if (srclen >= POLY1305_BLOCK_SIZE) {
+-			dctx->s[0] = get_unaligned_le32(src +  0);
+-			dctx->s[1] = get_unaligned_le32(src +  4);
+-			dctx->s[2] = get_unaligned_le32(src +  8);
+-			dctx->s[3] = get_unaligned_le32(src + 12);
+-			src += POLY1305_BLOCK_SIZE;
+-			srclen -= POLY1305_BLOCK_SIZE;
+-			dctx->sset = true;
+-		}
+-	}
+-	return srclen;
+-}
++void poly1305_core_emit(const struct poly1305_state *state, const u32 nonce[4],
++			void *dst);
+ 
+ #endif
+--- a/include/crypto/nhpoly1305.h
++++ b/include/crypto/nhpoly1305.h
+@@ -7,7 +7,7 @@
+ #define _NHPOLY1305_H
+ 
+ #include <crypto/hash.h>
+-#include <crypto/poly1305.h>
++#include <crypto/internal/poly1305.h>
+ 
+ /* NH parameterization: */
+ 
+@@ -33,7 +33,7 @@
+ #define NHPOLY1305_KEY_SIZE	(POLY1305_BLOCK_SIZE + NH_KEY_BYTES)
+ 
+ struct nhpoly1305_key {
+-	struct poly1305_key poly_key;
++	struct poly1305_core_key poly_key;
+ 	u32 nh_key[NH_KEY_WORDS];
+ };
+ 
+--- a/include/crypto/poly1305.h
++++ b/include/crypto/poly1305.h
+@@ -13,12 +13,29 @@
+ #define POLY1305_KEY_SIZE	32
+ #define POLY1305_DIGEST_SIZE	16
+ 
++/* The poly1305_key and poly1305_state types are mostly opaque and
++ * implementation-defined. Limbs might be in base 2^64 or base 2^26, or
++ * different yet. The union type provided keeps these 64-bit aligned for the
++ * case in which this is implemented using 64x64 multiplies.
++ */
++
+ struct poly1305_key {
+-	u32 r[5];	/* key, base 2^26 */
++	union {
++		u32 r[5];
++		u64 r64[3];
++	};
++};
++
++struct poly1305_core_key {
++	struct poly1305_key key;
++	struct poly1305_key precomputed_s;
+ };
+ 
+ struct poly1305_state {
+-	u32 h[5];	/* accumulator, base 2^26 */
++	union {
++		u32 h[5];
++		u64 h64[3];
++	};
+ };
+ 
+ struct poly1305_desc_ctx {
+@@ -35,7 +52,10 @@ struct poly1305_desc_ctx {
+ 	/* accumulator */
+ 	struct poly1305_state h;
+ 	/* key */
+-	struct poly1305_key r[CONFIG_CRYPTO_LIB_POLY1305_RSIZE];
++	union {
++		struct poly1305_key opaque_r[CONFIG_CRYPTO_LIB_POLY1305_RSIZE];
++		struct poly1305_core_key core_r;
++	};
+ };
+ 
+ void poly1305_init_arch(struct poly1305_desc_ctx *desc, const u8 *key);
+--- a/lib/crypto/Makefile
++++ b/lib/crypto/Makefile
+@@ -28,7 +28,9 @@ obj-$(CONFIG_CRYPTO_LIB_DES)			+= libdes
+ libdes-y					:= des.o
+ 
+ obj-$(CONFIG_CRYPTO_LIB_POLY1305_GENERIC)	+= libpoly1305.o
+-libpoly1305-y					:= poly1305.o
++libpoly1305-y					:= poly1305-donna32.o
++libpoly1305-$(CONFIG_ARCH_SUPPORTS_INT128)	:= poly1305-donna64.o
++libpoly1305-y					+= poly1305.o
+ 
+ obj-$(CONFIG_CRYPTO_LIB_SHA256)			+= libsha256.o
+ libsha256-y					:= sha256.o
+--- /dev/null
++++ b/lib/crypto/poly1305-donna32.c
+@@ -0,0 +1,204 @@
++// SPDX-License-Identifier: GPL-2.0 OR MIT
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ *
++ * This is based in part on Andrew Moon's poly1305-donna, which is in the
++ * public domain.
++ */
++
++#include <linux/kernel.h>
++#include <asm/unaligned.h>
++#include <crypto/internal/poly1305.h>
++
++void poly1305_core_setkey(struct poly1305_core_key *key, const u8 raw_key[16])
++{
++	/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
++	key->key.r[0] = (get_unaligned_le32(&raw_key[0])) & 0x3ffffff;
++	key->key.r[1] = (get_unaligned_le32(&raw_key[3]) >> 2) & 0x3ffff03;
++	key->key.r[2] = (get_unaligned_le32(&raw_key[6]) >> 4) & 0x3ffc0ff;
++	key->key.r[3] = (get_unaligned_le32(&raw_key[9]) >> 6) & 0x3f03fff;
++	key->key.r[4] = (get_unaligned_le32(&raw_key[12]) >> 8) & 0x00fffff;
++
++	/* s = 5*r */
++	key->precomputed_s.r[0] = key->key.r[1] * 5;
++	key->precomputed_s.r[1] = key->key.r[2] * 5;
++	key->precomputed_s.r[2] = key->key.r[3] * 5;
++	key->precomputed_s.r[3] = key->key.r[4] * 5;
++}
++EXPORT_SYMBOL(poly1305_core_setkey);
++
++void poly1305_core_blocks(struct poly1305_state *state,
++			  const struct poly1305_core_key *key, const void *src,
++			  unsigned int nblocks, u32 hibit)
++{
++	const u8 *input = src;
++	u32 r0, r1, r2, r3, r4;
++	u32 s1, s2, s3, s4;
++	u32 h0, h1, h2, h3, h4;
++	u64 d0, d1, d2, d3, d4;
++	u32 c;
++
++	if (!nblocks)
++		return;
++
++	hibit <<= 24;
++
++	r0 = key->key.r[0];
++	r1 = key->key.r[1];
++	r2 = key->key.r[2];
++	r3 = key->key.r[3];
++	r4 = key->key.r[4];
++
++	s1 = key->precomputed_s.r[0];
++	s2 = key->precomputed_s.r[1];
++	s3 = key->precomputed_s.r[2];
++	s4 = key->precomputed_s.r[3];
++
++	h0 = state->h[0];
++	h1 = state->h[1];
++	h2 = state->h[2];
++	h3 = state->h[3];
++	h4 = state->h[4];
++
++	do {
++		/* h += m[i] */
++		h0 += (get_unaligned_le32(&input[0])) & 0x3ffffff;
++		h1 += (get_unaligned_le32(&input[3]) >> 2) & 0x3ffffff;
++		h2 += (get_unaligned_le32(&input[6]) >> 4) & 0x3ffffff;
++		h3 += (get_unaligned_le32(&input[9]) >> 6) & 0x3ffffff;
++		h4 += (get_unaligned_le32(&input[12]) >> 8) | hibit;
++
++		/* h *= r */
++		d0 = ((u64)h0 * r0) + ((u64)h1 * s4) +
++		     ((u64)h2 * s3) + ((u64)h3 * s2) +
++		     ((u64)h4 * s1);
++		d1 = ((u64)h0 * r1) + ((u64)h1 * r0) +
++		     ((u64)h2 * s4) + ((u64)h3 * s3) +
++		     ((u64)h4 * s2);
++		d2 = ((u64)h0 * r2) + ((u64)h1 * r1) +
++		     ((u64)h2 * r0) + ((u64)h3 * s4) +
++		     ((u64)h4 * s3);
++		d3 = ((u64)h0 * r3) + ((u64)h1 * r2) +
++		     ((u64)h2 * r1) + ((u64)h3 * r0) +
++		     ((u64)h4 * s4);
++		d4 = ((u64)h0 * r4) + ((u64)h1 * r3) +
++		     ((u64)h2 * r2) + ((u64)h3 * r1) +
++		     ((u64)h4 * r0);
++
++		/* (partial) h %= p */
++		c = (u32)(d0 >> 26);
++		h0 = (u32)d0 & 0x3ffffff;
++		d1 += c;
++		c = (u32)(d1 >> 26);
++		h1 = (u32)d1 & 0x3ffffff;
++		d2 += c;
++		c = (u32)(d2 >> 26);
++		h2 = (u32)d2 & 0x3ffffff;
++		d3 += c;
++		c = (u32)(d3 >> 26);
++		h3 = (u32)d3 & 0x3ffffff;
++		d4 += c;
++		c = (u32)(d4 >> 26);
++		h4 = (u32)d4 & 0x3ffffff;
++		h0 += c * 5;
++		c = (h0 >> 26);
++		h0 = h0 & 0x3ffffff;
++		h1 += c;
++
++		input += POLY1305_BLOCK_SIZE;
++	} while (--nblocks);
++
++	state->h[0] = h0;
++	state->h[1] = h1;
++	state->h[2] = h2;
++	state->h[3] = h3;
++	state->h[4] = h4;
++}
++EXPORT_SYMBOL(poly1305_core_blocks);
++
++void poly1305_core_emit(const struct poly1305_state *state, const u32 nonce[4],
++			void *dst)
++{
++	u8 *mac = dst;
++	u32 h0, h1, h2, h3, h4, c;
++	u32 g0, g1, g2, g3, g4;
++	u64 f;
++	u32 mask;
++
++	/* fully carry h */
++	h0 = state->h[0];
++	h1 = state->h[1];
++	h2 = state->h[2];
++	h3 = state->h[3];
++	h4 = state->h[4];
++
++	c = h1 >> 26;
++	h1 = h1 & 0x3ffffff;
++	h2 += c;
++	c = h2 >> 26;
++	h2 = h2 & 0x3ffffff;
++	h3 += c;
++	c = h3 >> 26;
++	h3 = h3 & 0x3ffffff;
++	h4 += c;
++	c = h4 >> 26;
++	h4 = h4 & 0x3ffffff;
++	h0 += c * 5;
++	c = h0 >> 26;
++	h0 = h0 & 0x3ffffff;
++	h1 += c;
++
++	/* compute h + -p */
++	g0 = h0 + 5;
++	c = g0 >> 26;
++	g0 &= 0x3ffffff;
++	g1 = h1 + c;
++	c = g1 >> 26;
++	g1 &= 0x3ffffff;
++	g2 = h2 + c;
++	c = g2 >> 26;
++	g2 &= 0x3ffffff;
++	g3 = h3 + c;
++	c = g3 >> 26;
++	g3 &= 0x3ffffff;
++	g4 = h4 + c - (1UL << 26);
++
++	/* select h if h < p, or h + -p if h >= p */
++	mask = (g4 >> ((sizeof(u32) * 8) - 1)) - 1;
++	g0 &= mask;
++	g1 &= mask;
++	g2 &= mask;
++	g3 &= mask;
++	g4 &= mask;
++	mask = ~mask;
++
++	h0 = (h0 & mask) | g0;
++	h1 = (h1 & mask) | g1;
++	h2 = (h2 & mask) | g2;
++	h3 = (h3 & mask) | g3;
++	h4 = (h4 & mask) | g4;
++
++	/* h = h % (2^128) */
++	h0 = ((h0) | (h1 << 26)) & 0xffffffff;
++	h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff;
++	h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;
++	h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff;
++
++	if (likely(nonce)) {
++		/* mac = (h + nonce) % (2^128) */
++		f = (u64)h0 + nonce[0];
++		h0 = (u32)f;
++		f = (u64)h1 + nonce[1] + (f >> 32);
++		h1 = (u32)f;
++		f = (u64)h2 + nonce[2] + (f >> 32);
++		h2 = (u32)f;
++		f = (u64)h3 + nonce[3] + (f >> 32);
++		h3 = (u32)f;
++	}
++
++	put_unaligned_le32(h0, &mac[0]);
++	put_unaligned_le32(h1, &mac[4]);
++	put_unaligned_le32(h2, &mac[8]);
++	put_unaligned_le32(h3, &mac[12]);
++}
++EXPORT_SYMBOL(poly1305_core_emit);
+--- /dev/null
++++ b/lib/crypto/poly1305-donna64.c
+@@ -0,0 +1,185 @@
++// SPDX-License-Identifier: GPL-2.0 OR MIT
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ *
++ * This is based in part on Andrew Moon's poly1305-donna, which is in the
++ * public domain.
++ */
++
++#include <linux/kernel.h>
++#include <asm/unaligned.h>
++#include <crypto/internal/poly1305.h>
++
++typedef __uint128_t u128;
++
++void poly1305_core_setkey(struct poly1305_core_key *key, const u8 raw_key[16])
++{
++	u64 t0, t1;
++
++	/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
++	t0 = get_unaligned_le64(&raw_key[0]);
++	t1 = get_unaligned_le64(&raw_key[8]);
++
++	key->key.r64[0] = t0 & 0xffc0fffffffULL;
++	key->key.r64[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffffULL;
++	key->key.r64[2] = ((t1 >> 24)) & 0x00ffffffc0fULL;
++
++	/* s = 20*r */
++	key->precomputed_s.r64[0] = key->key.r64[1] * 20;
++	key->precomputed_s.r64[1] = key->key.r64[2] * 20;
++}
++EXPORT_SYMBOL(poly1305_core_setkey);
++
++void poly1305_core_blocks(struct poly1305_state *state,
++			  const struct poly1305_core_key *key, const void *src,
++			  unsigned int nblocks, u32 hibit)
++{
++	const u8 *input = src;
++	u64 hibit64;
++	u64 r0, r1, r2;
++	u64 s1, s2;
++	u64 h0, h1, h2;
++	u64 c;
++	u128 d0, d1, d2, d;
++
++	if (!nblocks)
++		return;
++
++	hibit64 = ((u64)hibit) << 40;
++
++	r0 = key->key.r64[0];
++	r1 = key->key.r64[1];
++	r2 = key->key.r64[2];
++
++	h0 = state->h64[0];
++	h1 = state->h64[1];
++	h2 = state->h64[2];
++
++	s1 = key->precomputed_s.r64[0];
++	s2 = key->precomputed_s.r64[1];
++
++	do {
++		u64 t0, t1;
++
++		/* h += m[i] */
++		t0 = get_unaligned_le64(&input[0]);
++		t1 = get_unaligned_le64(&input[8]);
++
++		h0 += t0 & 0xfffffffffffULL;
++		h1 += ((t0 >> 44) | (t1 << 20)) & 0xfffffffffffULL;
++		h2 += (((t1 >> 24)) & 0x3ffffffffffULL) | hibit64;
++
++		/* h *= r */
++		d0 = (u128)h0 * r0;
++		d = (u128)h1 * s2;
++		d0 += d;
++		d = (u128)h2 * s1;
++		d0 += d;
++		d1 = (u128)h0 * r1;
++		d = (u128)h1 * r0;
++		d1 += d;
++		d = (u128)h2 * s2;
++		d1 += d;
++		d2 = (u128)h0 * r2;
++		d = (u128)h1 * r1;
++		d2 += d;
++		d = (u128)h2 * r0;
++		d2 += d;
++
++		/* (partial) h %= p */
++		c = (u64)(d0 >> 44);
++		h0 = (u64)d0 & 0xfffffffffffULL;
++		d1 += c;
++		c = (u64)(d1 >> 44);
++		h1 = (u64)d1 & 0xfffffffffffULL;
++		d2 += c;
++		c = (u64)(d2 >> 42);
++		h2 = (u64)d2 & 0x3ffffffffffULL;
++		h0 += c * 5;
++		c = h0 >> 44;
++		h0 = h0 & 0xfffffffffffULL;
++		h1 += c;
++
++		input += POLY1305_BLOCK_SIZE;
++	} while (--nblocks);
++
++	state->h64[0] = h0;
++	state->h64[1] = h1;
++	state->h64[2] = h2;
++}
++EXPORT_SYMBOL(poly1305_core_blocks);
++
++void poly1305_core_emit(const struct poly1305_state *state, const u32 nonce[4],
++			void *dst)
++{
++	u8 *mac = dst;
++	u64 h0, h1, h2, c;
++	u64 g0, g1, g2;
++	u64 t0, t1;
++
++	/* fully carry h */
++	h0 = state->h64[0];
++	h1 = state->h64[1];
++	h2 = state->h64[2];
++
++	c = h1 >> 44;
++	h1 &= 0xfffffffffffULL;
++	h2 += c;
++	c = h2 >> 42;
++	h2 &= 0x3ffffffffffULL;
++	h0 += c * 5;
++	c = h0 >> 44;
++	h0 &= 0xfffffffffffULL;
++	h1 += c;
++	c = h1 >> 44;
++	h1 &= 0xfffffffffffULL;
++	h2 += c;
++	c = h2 >> 42;
++	h2 &= 0x3ffffffffffULL;
++	h0 += c * 5;
++	c = h0 >> 44;
++	h0 &= 0xfffffffffffULL;
++	h1 += c;
++
++	/* compute h + -p */
++	g0 = h0 + 5;
++	c  = g0 >> 44;
++	g0 &= 0xfffffffffffULL;
++	g1 = h1 + c;
++	c  = g1 >> 44;
++	g1 &= 0xfffffffffffULL;
++	g2 = h2 + c - (1ULL << 42);
++
++	/* select h if h < p, or h + -p if h >= p */
++	c = (g2 >> ((sizeof(u64) * 8) - 1)) - 1;
++	g0 &= c;
++	g1 &= c;
++	g2 &= c;
++	c  = ~c;
++	h0 = (h0 & c) | g0;
++	h1 = (h1 & c) | g1;
++	h2 = (h2 & c) | g2;
++
++	if (likely(nonce)) {
++		/* h = (h + nonce) */
++		t0 = ((u64)nonce[1] << 32) | nonce[0];
++		t1 = ((u64)nonce[3] << 32) | nonce[2];
++
++		h0 += t0 & 0xfffffffffffULL;
++		c = h0 >> 44;
++		h0 &= 0xfffffffffffULL;
++		h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffffULL) + c;
++		c = h1 >> 44;
++		h1 &= 0xfffffffffffULL;
++		h2 += (((t1 >> 24)) & 0x3ffffffffffULL) + c;
++		h2 &= 0x3ffffffffffULL;
++	}
++
++	/* mac = h % (2^128) */
++	h0 = h0 | (h1 << 44);
++	h1 = (h1 >> 20) | (h2 << 24);
++
++	put_unaligned_le64(h0, &mac[0]);
++	put_unaligned_le64(h1, &mac[8]);
++}
++EXPORT_SYMBOL(poly1305_core_emit);
+--- a/lib/crypto/poly1305.c
++++ b/lib/crypto/poly1305.c
+@@ -12,151 +12,9 @@
+ #include <linux/module.h>
+ #include <asm/unaligned.h>
+ 
+-static inline u64 mlt(u64 a, u64 b)
+-{
+-	return a * b;
+-}
+-
+-static inline u32 sr(u64 v, u_char n)
+-{
+-	return v >> n;
+-}
+-
+-static inline u32 and(u32 v, u32 mask)
+-{
+-	return v & mask;
+-}
+-
+-void poly1305_core_setkey(struct poly1305_key *key, const u8 *raw_key)
+-{
+-	/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
+-	key->r[0] = (get_unaligned_le32(raw_key +  0) >> 0) & 0x3ffffff;
+-	key->r[1] = (get_unaligned_le32(raw_key +  3) >> 2) & 0x3ffff03;
+-	key->r[2] = (get_unaligned_le32(raw_key +  6) >> 4) & 0x3ffc0ff;
+-	key->r[3] = (get_unaligned_le32(raw_key +  9) >> 6) & 0x3f03fff;
+-	key->r[4] = (get_unaligned_le32(raw_key + 12) >> 8) & 0x00fffff;
+-}
+-EXPORT_SYMBOL_GPL(poly1305_core_setkey);
+-
+-void poly1305_core_blocks(struct poly1305_state *state,
+-			  const struct poly1305_key *key, const void *src,
+-			  unsigned int nblocks, u32 hibit)
+-{
+-	u32 r0, r1, r2, r3, r4;
+-	u32 s1, s2, s3, s4;
+-	u32 h0, h1, h2, h3, h4;
+-	u64 d0, d1, d2, d3, d4;
+-
+-	if (!nblocks)
+-		return;
+-
+-	r0 = key->r[0];
+-	r1 = key->r[1];
+-	r2 = key->r[2];
+-	r3 = key->r[3];
+-	r4 = key->r[4];
+-
+-	s1 = r1 * 5;
+-	s2 = r2 * 5;
+-	s3 = r3 * 5;
+-	s4 = r4 * 5;
+-
+-	h0 = state->h[0];
+-	h1 = state->h[1];
+-	h2 = state->h[2];
+-	h3 = state->h[3];
+-	h4 = state->h[4];
+-
+-	do {
+-		/* h += m[i] */
+-		h0 += (get_unaligned_le32(src +  0) >> 0) & 0x3ffffff;
+-		h1 += (get_unaligned_le32(src +  3) >> 2) & 0x3ffffff;
+-		h2 += (get_unaligned_le32(src +  6) >> 4) & 0x3ffffff;
+-		h3 += (get_unaligned_le32(src +  9) >> 6) & 0x3ffffff;
+-		h4 += (get_unaligned_le32(src + 12) >> 8) | (hibit << 24);
+-
+-		/* h *= r */
+-		d0 = mlt(h0, r0) + mlt(h1, s4) + mlt(h2, s3) +
+-		     mlt(h3, s2) + mlt(h4, s1);
+-		d1 = mlt(h0, r1) + mlt(h1, r0) + mlt(h2, s4) +
+-		     mlt(h3, s3) + mlt(h4, s2);
+-		d2 = mlt(h0, r2) + mlt(h1, r1) + mlt(h2, r0) +
+-		     mlt(h3, s4) + mlt(h4, s3);
+-		d3 = mlt(h0, r3) + mlt(h1, r2) + mlt(h2, r1) +
+-		     mlt(h3, r0) + mlt(h4, s4);
+-		d4 = mlt(h0, r4) + mlt(h1, r3) + mlt(h2, r2) +
+-		     mlt(h3, r1) + mlt(h4, r0);
+-
+-		/* (partial) h %= p */
+-		d1 += sr(d0, 26);     h0 = and(d0, 0x3ffffff);
+-		d2 += sr(d1, 26);     h1 = and(d1, 0x3ffffff);
+-		d3 += sr(d2, 26);     h2 = and(d2, 0x3ffffff);
+-		d4 += sr(d3, 26);     h3 = and(d3, 0x3ffffff);
+-		h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff);
+-		h1 += h0 >> 26;       h0 = h0 & 0x3ffffff;
+-
+-		src += POLY1305_BLOCK_SIZE;
+-	} while (--nblocks);
+-
+-	state->h[0] = h0;
+-	state->h[1] = h1;
+-	state->h[2] = h2;
+-	state->h[3] = h3;
+-	state->h[4] = h4;
+-}
+-EXPORT_SYMBOL_GPL(poly1305_core_blocks);
+-
+-void poly1305_core_emit(const struct poly1305_state *state, void *dst)
+-{
+-	u32 h0, h1, h2, h3, h4;
+-	u32 g0, g1, g2, g3, g4;
+-	u32 mask;
+-
+-	/* fully carry h */
+-	h0 = state->h[0];
+-	h1 = state->h[1];
+-	h2 = state->h[2];
+-	h3 = state->h[3];
+-	h4 = state->h[4];
+-
+-	h2 += (h1 >> 26);     h1 = h1 & 0x3ffffff;
+-	h3 += (h2 >> 26);     h2 = h2 & 0x3ffffff;
+-	h4 += (h3 >> 26);     h3 = h3 & 0x3ffffff;
+-	h0 += (h4 >> 26) * 5; h4 = h4 & 0x3ffffff;
+-	h1 += (h0 >> 26);     h0 = h0 & 0x3ffffff;
+-
+-	/* compute h + -p */
+-	g0 = h0 + 5;
+-	g1 = h1 + (g0 >> 26);             g0 &= 0x3ffffff;
+-	g2 = h2 + (g1 >> 26);             g1 &= 0x3ffffff;
+-	g3 = h3 + (g2 >> 26);             g2 &= 0x3ffffff;
+-	g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x3ffffff;
+-
+-	/* select h if h < p, or h + -p if h >= p */
+-	mask = (g4 >> ((sizeof(u32) * 8) - 1)) - 1;
+-	g0 &= mask;
+-	g1 &= mask;
+-	g2 &= mask;
+-	g3 &= mask;
+-	g4 &= mask;
+-	mask = ~mask;
+-	h0 = (h0 & mask) | g0;
+-	h1 = (h1 & mask) | g1;
+-	h2 = (h2 & mask) | g2;
+-	h3 = (h3 & mask) | g3;
+-	h4 = (h4 & mask) | g4;
+-
+-	/* h = h % (2^128) */
+-	put_unaligned_le32((h0 >>  0) | (h1 << 26), dst +  0);
+-	put_unaligned_le32((h1 >>  6) | (h2 << 20), dst +  4);
+-	put_unaligned_le32((h2 >> 12) | (h3 << 14), dst +  8);
+-	put_unaligned_le32((h3 >> 18) | (h4 <<  8), dst + 12);
+-}
+-EXPORT_SYMBOL_GPL(poly1305_core_emit);
+-
+ void poly1305_init_generic(struct poly1305_desc_ctx *desc, const u8 *key)
+ {
+-	poly1305_core_setkey(desc->r, key);
++	poly1305_core_setkey(&desc->core_r, key);
+ 	desc->s[0] = get_unaligned_le32(key + 16);
+ 	desc->s[1] = get_unaligned_le32(key + 20);
+ 	desc->s[2] = get_unaligned_le32(key + 24);
+@@ -164,7 +22,7 @@ void poly1305_init_generic(struct poly13
+ 	poly1305_core_init(&desc->h);
+ 	desc->buflen = 0;
+ 	desc->sset = true;
+-	desc->rset = 1;
++	desc->rset = 2;
+ }
+ EXPORT_SYMBOL_GPL(poly1305_init_generic);
+ 
+@@ -181,13 +39,14 @@ void poly1305_update_generic(struct poly
+ 		desc->buflen += bytes;
+ 
+ 		if (desc->buflen == POLY1305_BLOCK_SIZE) {
+-			poly1305_core_blocks(&desc->h, desc->r, desc->buf, 1, 1);
++			poly1305_core_blocks(&desc->h, &desc->core_r, desc->buf,
++					     1, 1);
+ 			desc->buflen = 0;
+ 		}
+ 	}
+ 
+ 	if (likely(nbytes >= POLY1305_BLOCK_SIZE)) {
+-		poly1305_core_blocks(&desc->h, desc->r, src,
++		poly1305_core_blocks(&desc->h, &desc->core_r, src,
+ 				     nbytes / POLY1305_BLOCK_SIZE, 1);
+ 		src += nbytes - (nbytes % POLY1305_BLOCK_SIZE);
+ 		nbytes %= POLY1305_BLOCK_SIZE;
+@@ -202,28 +61,14 @@ EXPORT_SYMBOL_GPL(poly1305_update_generi
+ 
+ void poly1305_final_generic(struct poly1305_desc_ctx *desc, u8 *dst)
+ {
+-	__le32 digest[4];
+-	u64 f = 0;
+-
+ 	if (unlikely(desc->buflen)) {
+ 		desc->buf[desc->buflen++] = 1;
+ 		memset(desc->buf + desc->buflen, 0,
+ 		       POLY1305_BLOCK_SIZE - desc->buflen);
+-		poly1305_core_blocks(&desc->h, desc->r, desc->buf, 1, 0);
++		poly1305_core_blocks(&desc->h, &desc->core_r, desc->buf, 1, 0);
+ 	}
+ 
+-	poly1305_core_emit(&desc->h, digest);
+-
+-	/* mac = (h + s) % (2^128) */
+-	f = (f >> 32) + le32_to_cpu(digest[0]) + desc->s[0];
+-	put_unaligned_le32(f, dst + 0);
+-	f = (f >> 32) + le32_to_cpu(digest[1]) + desc->s[1];
+-	put_unaligned_le32(f, dst + 4);
+-	f = (f >> 32) + le32_to_cpu(digest[2]) + desc->s[2];
+-	put_unaligned_le32(f, dst + 8);
+-	f = (f >> 32) + le32_to_cpu(digest[3]) + desc->s[3];
+-	put_unaligned_le32(f, dst + 12);
+-
++	poly1305_core_emit(&desc->h, desc->s, dst);
+ 	*desc = (struct poly1305_desc_ctx){};
+ }
+ EXPORT_SYMBOL_GPL(poly1305_final_generic);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0042-crypto-x86-poly1305-import-unmodified-cryptogams-imp.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0042-crypto-x86-poly1305-import-unmodified-cryptogams-imp.patch
new file mode 100644
index 0000000..8e52383
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0042-crypto-x86-poly1305-import-unmodified-cryptogams-imp.patch
@@ -0,0 +1,4183 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Sun, 5 Jan 2020 22:40:47 -0500
+Subject: [PATCH] crypto: x86/poly1305 - import unmodified cryptogams
+ implementation
+
+commit 0896ca2a0cb6127e8a129f1f2a680d49b6b0f65c upstream.
+
+These x86_64 vectorized implementations come from Andy Polyakov's
+CRYPTOGAMS implementation, and are included here in raw form without
+modification, so that subsequent commits that fix these up for the
+kernel can see how it has changed.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/poly1305-x86_64-cryptogams.pl | 4159 +++++++++++++++++
+ 1 file changed, 4159 insertions(+)
+ create mode 100644 arch/x86/crypto/poly1305-x86_64-cryptogams.pl
+
+--- /dev/null
++++ b/arch/x86/crypto/poly1305-x86_64-cryptogams.pl
+@@ -0,0 +1,4159 @@
++#! /usr/bin/env perl
++# Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
++#
++# Licensed under the OpenSSL license (the "License").  You may not use
++# this file except in compliance with the License.  You can obtain a copy
++# in the file LICENSE in the source distribution or at
++# https://www.openssl.org/source/license.html
++
++#
++# ====================================================================
++# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
++# project. The module is, however, dual licensed under OpenSSL and
++# CRYPTOGAMS licenses depending on where you obtain it. For further
++# details see http://www.openssl.org/~appro/cryptogams/.
++# ====================================================================
++#
++# This module implements Poly1305 hash for x86_64.
++#
++# March 2015
++#
++# Initial release.
++#
++# December 2016
++#
++# Add AVX512F+VL+BW code path.
++#
++# November 2017
++#
++# Convert AVX512F+VL+BW code path to pure AVX512F, so that it can be
++# executed even on Knights Landing. Trigger for modification was
++# observation that AVX512 code paths can negatively affect overall
++# Skylake-X system performance. Since we are likely to suppress
++# AVX512F capability flag [at least on Skylake-X], conversion serves
++# as kind of "investment protection". Note that next *lake processor,
++# Cannolake, has AVX512IFMA code path to execute...
++#
++# Numbers are cycles per processed byte with poly1305_blocks alone,
++# measured with rdtsc at fixed clock frequency.
++#
++#		IALU/gcc-4.8(*)	AVX(**)		AVX2	AVX-512
++# P4		4.46/+120%	-
++# Core 2	2.41/+90%	-
++# Westmere	1.88/+120%	-
++# Sandy Bridge	1.39/+140%	1.10
++# Haswell	1.14/+175%	1.11		0.65
++# Skylake[-X]	1.13/+120%	0.96		0.51	[0.35]
++# Silvermont	2.83/+95%	-
++# Knights L	3.60/?		1.65		1.10	0.41(***)
++# Goldmont	1.70/+180%	-
++# VIA Nano	1.82/+150%	-
++# Sledgehammer	1.38/+160%	-
++# Bulldozer	2.30/+130%	0.97
++# Ryzen		1.15/+200%	1.08		1.18
++#
++# (*)	improvement coefficients relative to clang are more modest and
++#	are ~50% on most processors, in both cases we are comparing to
++#	__int128 code;
++# (**)	SSE2 implementation was attempted, but among non-AVX processors
++#	it was faster than integer-only code only on older Intel P4 and
++#	Core processors, 50-30%, less newer processor is, but slower on
++#	contemporary ones, for example almost 2x slower on Atom, and as
++#	former are naturally disappearing, SSE2 is deemed unnecessary;
++# (***)	strangely enough performance seems to vary from core to core,
++#	listed result is best case;
++
++$flavour = shift;
++$output  = shift;
++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
++
++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++
++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++die "can't locate x86_64-xlate.pl";
++
++if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++		=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
++	$avx = ($1>=2.19) + ($1>=2.22) + ($1>=2.25) + ($1>=2.26);
++}
++
++if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
++	   `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)(?:\.([0-9]+))?/) {
++	$avx = ($1>=2.09) + ($1>=2.10) + 2 * ($1>=2.12);
++	$avx += 2 if ($1==2.11 && $2>=8);
++}
++
++if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
++	   `ml64 2>&1` =~ /Version ([0-9]+)\./) {
++	$avx = ($1>=10) + ($1>=12);
++}
++
++if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9]\.[0-9]+)/) {
++	$avx = ($2>=3.0) + ($2>3.0);
++}
++
++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++*STDOUT=*OUT;
++
++my ($ctx,$inp,$len,$padbit)=("%rdi","%rsi","%rdx","%rcx");
++my ($mac,$nonce)=($inp,$len);	# *_emit arguments
++my ($d1,$d2,$d3, $r0,$r1,$s1)=map("%r$_",(8..13));
++my ($h0,$h1,$h2)=("%r14","%rbx","%rbp");
++
++sub poly1305_iteration {
++# input:	copy of $r1 in %rax, $h0-$h2, $r0-$r1
++# output:	$h0-$h2 *= $r0-$r1
++$code.=<<___;
++	mulq	$h0			# h0*r1
++	mov	%rax,$d2
++	 mov	$r0,%rax
++	mov	%rdx,$d3
++
++	mulq	$h0			# h0*r0
++	mov	%rax,$h0		# future $h0
++	 mov	$r0,%rax
++	mov	%rdx,$d1
++
++	mulq	$h1			# h1*r0
++	add	%rax,$d2
++	 mov	$s1,%rax
++	adc	%rdx,$d3
++
++	mulq	$h1			# h1*s1
++	 mov	$h2,$h1			# borrow $h1
++	add	%rax,$h0
++	adc	%rdx,$d1
++
++	imulq	$s1,$h1			# h2*s1
++	add	$h1,$d2
++	 mov	$d1,$h1
++	adc	\$0,$d3
++
++	imulq	$r0,$h2			# h2*r0
++	add	$d2,$h1
++	mov	\$-4,%rax		# mask value
++	adc	$h2,$d3
++
++	and	$d3,%rax		# last reduction step
++	mov	$d3,$h2
++	shr	\$2,$d3
++	and	\$3,$h2
++	add	$d3,%rax
++	add	%rax,$h0
++	adc	\$0,$h1
++	adc	\$0,$h2
++___
++}
++
++########################################################################
++# Layout of opaque area is following.
++#
++#	unsigned __int64 h[3];		# current hash value base 2^64
++#	unsigned __int64 r[2];		# key value base 2^64
++
++$code.=<<___;
++.text
++
++.extern	OPENSSL_ia32cap_P
++
++.globl	poly1305_init
++.hidden	poly1305_init
++.globl	poly1305_blocks
++.hidden	poly1305_blocks
++.globl	poly1305_emit
++.hidden	poly1305_emit
++
++.type	poly1305_init,\@function,3
++.align	32
++poly1305_init:
++	xor	%rax,%rax
++	mov	%rax,0($ctx)		# initialize hash value
++	mov	%rax,8($ctx)
++	mov	%rax,16($ctx)
++
++	cmp	\$0,$inp
++	je	.Lno_key
++
++	lea	poly1305_blocks(%rip),%r10
++	lea	poly1305_emit(%rip),%r11
++___
++$code.=<<___	if ($avx);
++	mov	OPENSSL_ia32cap_P+4(%rip),%r9
++	lea	poly1305_blocks_avx(%rip),%rax
++	lea	poly1305_emit_avx(%rip),%rcx
++	bt	\$`60-32`,%r9		# AVX?
++	cmovc	%rax,%r10
++	cmovc	%rcx,%r11
++___
++$code.=<<___	if ($avx>1);
++	lea	poly1305_blocks_avx2(%rip),%rax
++	bt	\$`5+32`,%r9		# AVX2?
++	cmovc	%rax,%r10
++___
++$code.=<<___	if ($avx>3);
++	mov	\$`(1<<31|1<<21|1<<16)`,%rax
++	shr	\$32,%r9
++	and	%rax,%r9
++	cmp	%rax,%r9
++	je	.Linit_base2_44
++___
++$code.=<<___;
++	mov	\$0x0ffffffc0fffffff,%rax
++	mov	\$0x0ffffffc0ffffffc,%rcx
++	and	0($inp),%rax
++	and	8($inp),%rcx
++	mov	%rax,24($ctx)
++	mov	%rcx,32($ctx)
++___
++$code.=<<___	if ($flavour !~ /elf32/);
++	mov	%r10,0(%rdx)
++	mov	%r11,8(%rdx)
++___
++$code.=<<___	if ($flavour =~ /elf32/);
++	mov	%r10d,0(%rdx)
++	mov	%r11d,4(%rdx)
++___
++$code.=<<___;
++	mov	\$1,%eax
++.Lno_key:
++	ret
++.size	poly1305_init,.-poly1305_init
++
++.type	poly1305_blocks,\@function,4
++.align	32
++poly1305_blocks:
++.cfi_startproc
++.Lblocks:
++	shr	\$4,$len
++	jz	.Lno_data		# too short
++
++	push	%rbx
++.cfi_push	%rbx
++	push	%rbp
++.cfi_push	%rbp
++	push	%r12
++.cfi_push	%r12
++	push	%r13
++.cfi_push	%r13
++	push	%r14
++.cfi_push	%r14
++	push	%r15
++.cfi_push	%r15
++.Lblocks_body:
++
++	mov	$len,%r15		# reassign $len
++
++	mov	24($ctx),$r0		# load r
++	mov	32($ctx),$s1
++
++	mov	0($ctx),$h0		# load hash value
++	mov	8($ctx),$h1
++	mov	16($ctx),$h2
++
++	mov	$s1,$r1
++	shr	\$2,$s1
++	mov	$r1,%rax
++	add	$r1,$s1			# s1 = r1 + (r1 >> 2)
++	jmp	.Loop
++
++.align	32
++.Loop:
++	add	0($inp),$h0		# accumulate input
++	adc	8($inp),$h1
++	lea	16($inp),$inp
++	adc	$padbit,$h2
++___
++	&poly1305_iteration();
++$code.=<<___;
++	mov	$r1,%rax
++	dec	%r15			# len-=16
++	jnz	.Loop
++
++	mov	$h0,0($ctx)		# store hash value
++	mov	$h1,8($ctx)
++	mov	$h2,16($ctx)
++
++	mov	0(%rsp),%r15
++.cfi_restore	%r15
++	mov	8(%rsp),%r14
++.cfi_restore	%r14
++	mov	16(%rsp),%r13
++.cfi_restore	%r13
++	mov	24(%rsp),%r12
++.cfi_restore	%r12
++	mov	32(%rsp),%rbp
++.cfi_restore	%rbp
++	mov	40(%rsp),%rbx
++.cfi_restore	%rbx
++	lea	48(%rsp),%rsp
++.cfi_adjust_cfa_offset	-48
++.Lno_data:
++.Lblocks_epilogue:
++	ret
++.cfi_endproc
++.size	poly1305_blocks,.-poly1305_blocks
++
++.type	poly1305_emit,\@function,3
++.align	32
++poly1305_emit:
++.Lemit:
++	mov	0($ctx),%r8	# load hash value
++	mov	8($ctx),%r9
++	mov	16($ctx),%r10
++
++	mov	%r8,%rax
++	add	\$5,%r8		# compare to modulus
++	mov	%r9,%rcx
++	adc	\$0,%r9
++	adc	\$0,%r10
++	shr	\$2,%r10	# did 130-bit value overflow?
++	cmovnz	%r8,%rax
++	cmovnz	%r9,%rcx
++
++	add	0($nonce),%rax	# accumulate nonce
++	adc	8($nonce),%rcx
++	mov	%rax,0($mac)	# write result
++	mov	%rcx,8($mac)
++
++	ret
++.size	poly1305_emit,.-poly1305_emit
++___
++if ($avx) {
++
++########################################################################
++# Layout of opaque area is following.
++#
++#	unsigned __int32 h[5];		# current hash value base 2^26
++#	unsigned __int32 is_base2_26;
++#	unsigned __int64 r[2];		# key value base 2^64
++#	unsigned __int64 pad;
++#	struct { unsigned __int32 r^2, r^1, r^4, r^3; } r[9];
++#
++# where r^n are base 2^26 digits of degrees of multiplier key. There are
++# 5 digits, but last four are interleaved with multiples of 5, totalling
++# in 9 elements: r0, r1, 5*r1, r2, 5*r2, r3, 5*r3, r4, 5*r4.
++
++my ($H0,$H1,$H2,$H3,$H4, $T0,$T1,$T2,$T3,$T4, $D0,$D1,$D2,$D3,$D4, $MASK) =
++    map("%xmm$_",(0..15));
++
++$code.=<<___;
++.type	__poly1305_block,\@abi-omnipotent
++.align	32
++__poly1305_block:
++___
++	&poly1305_iteration();
++$code.=<<___;
++	ret
++.size	__poly1305_block,.-__poly1305_block
++
++.type	__poly1305_init_avx,\@abi-omnipotent
++.align	32
++__poly1305_init_avx:
++	mov	$r0,$h0
++	mov	$r1,$h1
++	xor	$h2,$h2
++
++	lea	48+64($ctx),$ctx	# size optimization
++
++	mov	$r1,%rax
++	call	__poly1305_block	# r^2
++
++	mov	\$0x3ffffff,%eax	# save interleaved r^2 and r base 2^26
++	mov	\$0x3ffffff,%edx
++	mov	$h0,$d1
++	and	$h0#d,%eax
++	mov	$r0,$d2
++	and	$r0#d,%edx
++	mov	%eax,`16*0+0-64`($ctx)
++	shr	\$26,$d1
++	mov	%edx,`16*0+4-64`($ctx)
++	shr	\$26,$d2
++
++	mov	\$0x3ffffff,%eax
++	mov	\$0x3ffffff,%edx
++	and	$d1#d,%eax
++	and	$d2#d,%edx
++	mov	%eax,`16*1+0-64`($ctx)
++	lea	(%rax,%rax,4),%eax	# *5
++	mov	%edx,`16*1+4-64`($ctx)
++	lea	(%rdx,%rdx,4),%edx	# *5
++	mov	%eax,`16*2+0-64`($ctx)
++	shr	\$26,$d1
++	mov	%edx,`16*2+4-64`($ctx)
++	shr	\$26,$d2
++
++	mov	$h1,%rax
++	mov	$r1,%rdx
++	shl	\$12,%rax
++	shl	\$12,%rdx
++	or	$d1,%rax
++	or	$d2,%rdx
++	and	\$0x3ffffff,%eax
++	and	\$0x3ffffff,%edx
++	mov	%eax,`16*3+0-64`($ctx)
++	lea	(%rax,%rax,4),%eax	# *5
++	mov	%edx,`16*3+4-64`($ctx)
++	lea	(%rdx,%rdx,4),%edx	# *5
++	mov	%eax,`16*4+0-64`($ctx)
++	mov	$h1,$d1
++	mov	%edx,`16*4+4-64`($ctx)
++	mov	$r1,$d2
++
++	mov	\$0x3ffffff,%eax
++	mov	\$0x3ffffff,%edx
++	shr	\$14,$d1
++	shr	\$14,$d2
++	and	$d1#d,%eax
++	and	$d2#d,%edx
++	mov	%eax,`16*5+0-64`($ctx)
++	lea	(%rax,%rax,4),%eax	# *5
++	mov	%edx,`16*5+4-64`($ctx)
++	lea	(%rdx,%rdx,4),%edx	# *5
++	mov	%eax,`16*6+0-64`($ctx)
++	shr	\$26,$d1
++	mov	%edx,`16*6+4-64`($ctx)
++	shr	\$26,$d2
++
++	mov	$h2,%rax
++	shl	\$24,%rax
++	or	%rax,$d1
++	mov	$d1#d,`16*7+0-64`($ctx)
++	lea	($d1,$d1,4),$d1		# *5
++	mov	$d2#d,`16*7+4-64`($ctx)
++	lea	($d2,$d2,4),$d2		# *5
++	mov	$d1#d,`16*8+0-64`($ctx)
++	mov	$d2#d,`16*8+4-64`($ctx)
++
++	mov	$r1,%rax
++	call	__poly1305_block	# r^3
++
++	mov	\$0x3ffffff,%eax	# save r^3 base 2^26
++	mov	$h0,$d1
++	and	$h0#d,%eax
++	shr	\$26,$d1
++	mov	%eax,`16*0+12-64`($ctx)
++
++	mov	\$0x3ffffff,%edx
++	and	$d1#d,%edx
++	mov	%edx,`16*1+12-64`($ctx)
++	lea	(%rdx,%rdx,4),%edx	# *5
++	shr	\$26,$d1
++	mov	%edx,`16*2+12-64`($ctx)
++
++	mov	$h1,%rax
++	shl	\$12,%rax
++	or	$d1,%rax
++	and	\$0x3ffffff,%eax
++	mov	%eax,`16*3+12-64`($ctx)
++	lea	(%rax,%rax,4),%eax	# *5
++	mov	$h1,$d1
++	mov	%eax,`16*4+12-64`($ctx)
++
++	mov	\$0x3ffffff,%edx
++	shr	\$14,$d1
++	and	$d1#d,%edx
++	mov	%edx,`16*5+12-64`($ctx)
++	lea	(%rdx,%rdx,4),%edx	# *5
++	shr	\$26,$d1
++	mov	%edx,`16*6+12-64`($ctx)
++
++	mov	$h2,%rax
++	shl	\$24,%rax
++	or	%rax,$d1
++	mov	$d1#d,`16*7+12-64`($ctx)
++	lea	($d1,$d1,4),$d1		# *5
++	mov	$d1#d,`16*8+12-64`($ctx)
++
++	mov	$r1,%rax
++	call	__poly1305_block	# r^4
++
++	mov	\$0x3ffffff,%eax	# save r^4 base 2^26
++	mov	$h0,$d1
++	and	$h0#d,%eax
++	shr	\$26,$d1
++	mov	%eax,`16*0+8-64`($ctx)
++
++	mov	\$0x3ffffff,%edx
++	and	$d1#d,%edx
++	mov	%edx,`16*1+8-64`($ctx)
++	lea	(%rdx,%rdx,4),%edx	# *5
++	shr	\$26,$d1
++	mov	%edx,`16*2+8-64`($ctx)
++
++	mov	$h1,%rax
++	shl	\$12,%rax
++	or	$d1,%rax
++	and	\$0x3ffffff,%eax
++	mov	%eax,`16*3+8-64`($ctx)
++	lea	(%rax,%rax,4),%eax	# *5
++	mov	$h1,$d1
++	mov	%eax,`16*4+8-64`($ctx)
++
++	mov	\$0x3ffffff,%edx
++	shr	\$14,$d1
++	and	$d1#d,%edx
++	mov	%edx,`16*5+8-64`($ctx)
++	lea	(%rdx,%rdx,4),%edx	# *5
++	shr	\$26,$d1
++	mov	%edx,`16*6+8-64`($ctx)
++
++	mov	$h2,%rax
++	shl	\$24,%rax
++	or	%rax,$d1
++	mov	$d1#d,`16*7+8-64`($ctx)
++	lea	($d1,$d1,4),$d1		# *5
++	mov	$d1#d,`16*8+8-64`($ctx)
++
++	lea	-48-64($ctx),$ctx	# size [de-]optimization
++	ret
++.size	__poly1305_init_avx,.-__poly1305_init_avx
++
++.type	poly1305_blocks_avx,\@function,4
++.align	32
++poly1305_blocks_avx:
++.cfi_startproc
++	mov	20($ctx),%r8d		# is_base2_26
++	cmp	\$128,$len
++	jae	.Lblocks_avx
++	test	%r8d,%r8d
++	jz	.Lblocks
++
++.Lblocks_avx:
++	and	\$-16,$len
++	jz	.Lno_data_avx
++
++	vzeroupper
++
++	test	%r8d,%r8d
++	jz	.Lbase2_64_avx
++
++	test	\$31,$len
++	jz	.Leven_avx
++
++	push	%rbx
++.cfi_push	%rbx
++	push	%rbp
++.cfi_push	%rbp
++	push	%r12
++.cfi_push	%r12
++	push	%r13
++.cfi_push	%r13
++	push	%r14
++.cfi_push	%r14
++	push	%r15
++.cfi_push	%r15
++.Lblocks_avx_body:
++
++	mov	$len,%r15		# reassign $len
++
++	mov	0($ctx),$d1		# load hash value
++	mov	8($ctx),$d2
++	mov	16($ctx),$h2#d
++
++	mov	24($ctx),$r0		# load r
++	mov	32($ctx),$s1
++
++	################################# base 2^26 -> base 2^64
++	mov	$d1#d,$h0#d
++	and	\$`-1*(1<<31)`,$d1
++	mov	$d2,$r1			# borrow $r1
++	mov	$d2#d,$h1#d
++	and	\$`-1*(1<<31)`,$d2
++
++	shr	\$6,$d1
++	shl	\$52,$r1
++	add	$d1,$h0
++	shr	\$12,$h1
++	shr	\$18,$d2
++	add	$r1,$h0
++	adc	$d2,$h1
++
++	mov	$h2,$d1
++	shl	\$40,$d1
++	shr	\$24,$h2
++	add	$d1,$h1
++	adc	\$0,$h2			# can be partially reduced...
++
++	mov	\$-4,$d2		# ... so reduce
++	mov	$h2,$d1
++	and	$h2,$d2
++	shr	\$2,$d1
++	and	\$3,$h2
++	add	$d2,$d1			# =*5
++	add	$d1,$h0
++	adc	\$0,$h1
++	adc	\$0,$h2
++
++	mov	$s1,$r1
++	mov	$s1,%rax
++	shr	\$2,$s1
++	add	$r1,$s1			# s1 = r1 + (r1 >> 2)
++
++	add	0($inp),$h0		# accumulate input
++	adc	8($inp),$h1
++	lea	16($inp),$inp
++	adc	$padbit,$h2
++
++	call	__poly1305_block
++
++	test	$padbit,$padbit		# if $padbit is zero,
++	jz	.Lstore_base2_64_avx	# store hash in base 2^64 format
++
++	################################# base 2^64 -> base 2^26
++	mov	$h0,%rax
++	mov	$h0,%rdx
++	shr	\$52,$h0
++	mov	$h1,$r0
++	mov	$h1,$r1
++	shr	\$26,%rdx
++	and	\$0x3ffffff,%rax	# h[0]
++	shl	\$12,$r0
++	and	\$0x3ffffff,%rdx	# h[1]
++	shr	\$14,$h1
++	or	$r0,$h0
++	shl	\$24,$h2
++	and	\$0x3ffffff,$h0		# h[2]
++	shr	\$40,$r1
++	and	\$0x3ffffff,$h1		# h[3]
++	or	$r1,$h2			# h[4]
++
++	sub	\$16,%r15
++	jz	.Lstore_base2_26_avx
++
++	vmovd	%rax#d,$H0
++	vmovd	%rdx#d,$H1
++	vmovd	$h0#d,$H2
++	vmovd	$h1#d,$H3
++	vmovd	$h2#d,$H4
++	jmp	.Lproceed_avx
++
++.align	32
++.Lstore_base2_64_avx:
++	mov	$h0,0($ctx)
++	mov	$h1,8($ctx)
++	mov	$h2,16($ctx)		# note that is_base2_26 is zeroed
++	jmp	.Ldone_avx
++
++.align	16
++.Lstore_base2_26_avx:
++	mov	%rax#d,0($ctx)		# store hash value base 2^26
++	mov	%rdx#d,4($ctx)
++	mov	$h0#d,8($ctx)
++	mov	$h1#d,12($ctx)
++	mov	$h2#d,16($ctx)
++.align	16
++.Ldone_avx:
++	mov	0(%rsp),%r15
++.cfi_restore	%r15
++	mov	8(%rsp),%r14
++.cfi_restore	%r14
++	mov	16(%rsp),%r13
++.cfi_restore	%r13
++	mov	24(%rsp),%r12
++.cfi_restore	%r12
++	mov	32(%rsp),%rbp
++.cfi_restore	%rbp
++	mov	40(%rsp),%rbx
++.cfi_restore	%rbx
++	lea	48(%rsp),%rsp
++.cfi_adjust_cfa_offset	-48
++.Lno_data_avx:
++.Lblocks_avx_epilogue:
++	ret
++.cfi_endproc
++
++.align	32
++.Lbase2_64_avx:
++.cfi_startproc
++	push	%rbx
++.cfi_push	%rbx
++	push	%rbp
++.cfi_push	%rbp
++	push	%r12
++.cfi_push	%r12
++	push	%r13
++.cfi_push	%r13
++	push	%r14
++.cfi_push	%r14
++	push	%r15
++.cfi_push	%r15
++.Lbase2_64_avx_body:
++
++	mov	$len,%r15		# reassign $len
++
++	mov	24($ctx),$r0		# load r
++	mov	32($ctx),$s1
++
++	mov	0($ctx),$h0		# load hash value
++	mov	8($ctx),$h1
++	mov	16($ctx),$h2#d
++
++	mov	$s1,$r1
++	mov	$s1,%rax
++	shr	\$2,$s1
++	add	$r1,$s1			# s1 = r1 + (r1 >> 2)
++
++	test	\$31,$len
++	jz	.Linit_avx
++
++	add	0($inp),$h0		# accumulate input
++	adc	8($inp),$h1
++	lea	16($inp),$inp
++	adc	$padbit,$h2
++	sub	\$16,%r15
++
++	call	__poly1305_block
++
++.Linit_avx:
++	################################# base 2^64 -> base 2^26
++	mov	$h0,%rax
++	mov	$h0,%rdx
++	shr	\$52,$h0
++	mov	$h1,$d1
++	mov	$h1,$d2
++	shr	\$26,%rdx
++	and	\$0x3ffffff,%rax	# h[0]
++	shl	\$12,$d1
++	and	\$0x3ffffff,%rdx	# h[1]
++	shr	\$14,$h1
++	or	$d1,$h0
++	shl	\$24,$h2
++	and	\$0x3ffffff,$h0		# h[2]
++	shr	\$40,$d2
++	and	\$0x3ffffff,$h1		# h[3]
++	or	$d2,$h2			# h[4]
++
++	vmovd	%rax#d,$H0
++	vmovd	%rdx#d,$H1
++	vmovd	$h0#d,$H2
++	vmovd	$h1#d,$H3
++	vmovd	$h2#d,$H4
++	movl	\$1,20($ctx)		# set is_base2_26
++
++	call	__poly1305_init_avx
++
++.Lproceed_avx:
++	mov	%r15,$len
++
++	mov	0(%rsp),%r15
++.cfi_restore	%r15
++	mov	8(%rsp),%r14
++.cfi_restore	%r14
++	mov	16(%rsp),%r13
++.cfi_restore	%r13
++	mov	24(%rsp),%r12
++.cfi_restore	%r12
++	mov	32(%rsp),%rbp
++.cfi_restore	%rbp
++	mov	40(%rsp),%rbx
++.cfi_restore	%rbx
++	lea	48(%rsp),%rax
++	lea	48(%rsp),%rsp
++.cfi_adjust_cfa_offset	-48
++.Lbase2_64_avx_epilogue:
++	jmp	.Ldo_avx
++.cfi_endproc
++
++.align	32
++.Leven_avx:
++.cfi_startproc
++	vmovd		4*0($ctx),$H0		# load hash value
++	vmovd		4*1($ctx),$H1
++	vmovd		4*2($ctx),$H2
++	vmovd		4*3($ctx),$H3
++	vmovd		4*4($ctx),$H4
++
++.Ldo_avx:
++___
++$code.=<<___	if (!$win64);
++	lea		-0x58(%rsp),%r11
++.cfi_def_cfa		%r11,0x60
++	sub		\$0x178,%rsp
++___
++$code.=<<___	if ($win64);
++	lea		-0xf8(%rsp),%r11
++	sub		\$0x218,%rsp
++	vmovdqa		%xmm6,0x50(%r11)
++	vmovdqa		%xmm7,0x60(%r11)
++	vmovdqa		%xmm8,0x70(%r11)
++	vmovdqa		%xmm9,0x80(%r11)
++	vmovdqa		%xmm10,0x90(%r11)
++	vmovdqa		%xmm11,0xa0(%r11)
++	vmovdqa		%xmm12,0xb0(%r11)
++	vmovdqa		%xmm13,0xc0(%r11)
++	vmovdqa		%xmm14,0xd0(%r11)
++	vmovdqa		%xmm15,0xe0(%r11)
++.Ldo_avx_body:
++___
++$code.=<<___;
++	sub		\$64,$len
++	lea		-32($inp),%rax
++	cmovc		%rax,$inp
++
++	vmovdqu		`16*3`($ctx),$D4	# preload r0^2
++	lea		`16*3+64`($ctx),$ctx	# size optimization
++	lea		.Lconst(%rip),%rcx
++
++	################################################################
++	# load input
++	vmovdqu		16*2($inp),$T0
++	vmovdqu		16*3($inp),$T1
++	vmovdqa		64(%rcx),$MASK		# .Lmask26
++
++	vpsrldq		\$6,$T0,$T2		# splat input
++	vpsrldq		\$6,$T1,$T3
++	vpunpckhqdq	$T1,$T0,$T4		# 4
++	vpunpcklqdq	$T1,$T0,$T0		# 0:1
++	vpunpcklqdq	$T3,$T2,$T3		# 2:3
++
++	vpsrlq		\$40,$T4,$T4		# 4
++	vpsrlq		\$26,$T0,$T1
++	vpand		$MASK,$T0,$T0		# 0
++	vpsrlq		\$4,$T3,$T2
++	vpand		$MASK,$T1,$T1		# 1
++	vpsrlq		\$30,$T3,$T3
++	vpand		$MASK,$T2,$T2		# 2
++	vpand		$MASK,$T3,$T3		# 3
++	vpor		32(%rcx),$T4,$T4	# padbit, yes, always
++
++	jbe		.Lskip_loop_avx
++
++	# expand and copy pre-calculated table to stack
++	vmovdqu		`16*1-64`($ctx),$D1
++	vmovdqu		`16*2-64`($ctx),$D2
++	vpshufd		\$0xEE,$D4,$D3		# 34xx -> 3434
++	vpshufd		\$0x44,$D4,$D0		# xx12 -> 1212
++	vmovdqa		$D3,-0x90(%r11)
++	vmovdqa		$D0,0x00(%rsp)
++	vpshufd		\$0xEE,$D1,$D4
++	vmovdqu		`16*3-64`($ctx),$D0
++	vpshufd		\$0x44,$D1,$D1
++	vmovdqa		$D4,-0x80(%r11)
++	vmovdqa		$D1,0x10(%rsp)
++	vpshufd		\$0xEE,$D2,$D3
++	vmovdqu		`16*4-64`($ctx),$D1
++	vpshufd		\$0x44,$D2,$D2
++	vmovdqa		$D3,-0x70(%r11)
++	vmovdqa		$D2,0x20(%rsp)
++	vpshufd		\$0xEE,$D0,$D4
++	vmovdqu		`16*5-64`($ctx),$D2
++	vpshufd		\$0x44,$D0,$D0
++	vmovdqa		$D4,-0x60(%r11)
++	vmovdqa		$D0,0x30(%rsp)
++	vpshufd		\$0xEE,$D1,$D3
++	vmovdqu		`16*6-64`($ctx),$D0
++	vpshufd		\$0x44,$D1,$D1
++	vmovdqa		$D3,-0x50(%r11)
++	vmovdqa		$D1,0x40(%rsp)
++	vpshufd		\$0xEE,$D2,$D4
++	vmovdqu		`16*7-64`($ctx),$D1
++	vpshufd		\$0x44,$D2,$D2
++	vmovdqa		$D4,-0x40(%r11)
++	vmovdqa		$D2,0x50(%rsp)
++	vpshufd		\$0xEE,$D0,$D3
++	vmovdqu		`16*8-64`($ctx),$D2
++	vpshufd		\$0x44,$D0,$D0
++	vmovdqa		$D3,-0x30(%r11)
++	vmovdqa		$D0,0x60(%rsp)
++	vpshufd		\$0xEE,$D1,$D4
++	vpshufd		\$0x44,$D1,$D1
++	vmovdqa		$D4,-0x20(%r11)
++	vmovdqa		$D1,0x70(%rsp)
++	vpshufd		\$0xEE,$D2,$D3
++	 vmovdqa	0x00(%rsp),$D4		# preload r0^2
++	vpshufd		\$0x44,$D2,$D2
++	vmovdqa		$D3,-0x10(%r11)
++	vmovdqa		$D2,0x80(%rsp)
++
++	jmp		.Loop_avx
++
++.align	32
++.Loop_avx:
++	################################################################
++	# ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2
++	# ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r
++	#   \___________________/
++	# ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2
++	# ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r
++	#   \___________________/ \____________________/
++	#
++	# Note that we start with inp[2:3]*r^2. This is because it
++	# doesn't depend on reduction in previous iteration.
++	################################################################
++	# d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
++	# d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
++	# d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
++	# d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
++	# d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
++	#
++	# though note that $Tx and $Hx are "reversed" in this section,
++	# and $D4 is preloaded with r0^2...
++
++	vpmuludq	$T0,$D4,$D0		# d0 = h0*r0
++	vpmuludq	$T1,$D4,$D1		# d1 = h1*r0
++	  vmovdqa	$H2,0x20(%r11)				# offload hash
++	vpmuludq	$T2,$D4,$D2		# d3 = h2*r0
++	 vmovdqa	0x10(%rsp),$H2		# r1^2
++	vpmuludq	$T3,$D4,$D3		# d3 = h3*r0
++	vpmuludq	$T4,$D4,$D4		# d4 = h4*r0
++
++	  vmovdqa	$H0,0x00(%r11)				#
++	vpmuludq	0x20(%rsp),$T4,$H0	# h4*s1
++	  vmovdqa	$H1,0x10(%r11)				#
++	vpmuludq	$T3,$H2,$H1		# h3*r1
++	vpaddq		$H0,$D0,$D0		# d0 += h4*s1
++	vpaddq		$H1,$D4,$D4		# d4 += h3*r1
++	  vmovdqa	$H3,0x30(%r11)				#
++	vpmuludq	$T2,$H2,$H0		# h2*r1
++	vpmuludq	$T1,$H2,$H1		# h1*r1
++	vpaddq		$H0,$D3,$D3		# d3 += h2*r1
++	 vmovdqa	0x30(%rsp),$H3		# r2^2
++	vpaddq		$H1,$D2,$D2		# d2 += h1*r1
++	  vmovdqa	$H4,0x40(%r11)				#
++	vpmuludq	$T0,$H2,$H2		# h0*r1
++	 vpmuludq	$T2,$H3,$H0		# h2*r2
++	vpaddq		$H2,$D1,$D1		# d1 += h0*r1
++
++	 vmovdqa	0x40(%rsp),$H4		# s2^2
++	vpaddq		$H0,$D4,$D4		# d4 += h2*r2
++	vpmuludq	$T1,$H3,$H1		# h1*r2
++	vpmuludq	$T0,$H3,$H3		# h0*r2
++	vpaddq		$H1,$D3,$D3		# d3 += h1*r2
++	 vmovdqa	0x50(%rsp),$H2		# r3^2
++	vpaddq		$H3,$D2,$D2		# d2 += h0*r2
++	vpmuludq	$T4,$H4,$H0		# h4*s2
++	vpmuludq	$T3,$H4,$H4		# h3*s2
++	vpaddq		$H0,$D1,$D1		# d1 += h4*s2
++	 vmovdqa	0x60(%rsp),$H3		# s3^2
++	vpaddq		$H4,$D0,$D0		# d0 += h3*s2
++
++	 vmovdqa	0x80(%rsp),$H4		# s4^2
++	vpmuludq	$T1,$H2,$H1		# h1*r3
++	vpmuludq	$T0,$H2,$H2		# h0*r3
++	vpaddq		$H1,$D4,$D4		# d4 += h1*r3
++	vpaddq		$H2,$D3,$D3		# d3 += h0*r3
++	vpmuludq	$T4,$H3,$H0		# h4*s3
++	vpmuludq	$T3,$H3,$H1		# h3*s3
++	vpaddq		$H0,$D2,$D2		# d2 += h4*s3
++	 vmovdqu	16*0($inp),$H0				# load input
++	vpaddq		$H1,$D1,$D1		# d1 += h3*s3
++	vpmuludq	$T2,$H3,$H3		# h2*s3
++	 vpmuludq	$T2,$H4,$T2		# h2*s4
++	vpaddq		$H3,$D0,$D0		# d0 += h2*s3
++
++	 vmovdqu	16*1($inp),$H1				#
++	vpaddq		$T2,$D1,$D1		# d1 += h2*s4
++	vpmuludq	$T3,$H4,$T3		# h3*s4
++	vpmuludq	$T4,$H4,$T4		# h4*s4
++	 vpsrldq	\$6,$H0,$H2				# splat input
++	vpaddq		$T3,$D2,$D2		# d2 += h3*s4
++	vpaddq		$T4,$D3,$D3		# d3 += h4*s4
++	 vpsrldq	\$6,$H1,$H3				#
++	vpmuludq	0x70(%rsp),$T0,$T4	# h0*r4
++	vpmuludq	$T1,$H4,$T0		# h1*s4
++	 vpunpckhqdq	$H1,$H0,$H4		# 4
++	vpaddq		$T4,$D4,$D4		# d4 += h0*r4
++	 vmovdqa	-0x90(%r11),$T4		# r0^4
++	vpaddq		$T0,$D0,$D0		# d0 += h1*s4
++
++	vpunpcklqdq	$H1,$H0,$H0		# 0:1
++	vpunpcklqdq	$H3,$H2,$H3		# 2:3
++
++	#vpsrlq		\$40,$H4,$H4		# 4
++	vpsrldq		\$`40/8`,$H4,$H4	# 4
++	vpsrlq		\$26,$H0,$H1
++	vpand		$MASK,$H0,$H0		# 0
++	vpsrlq		\$4,$H3,$H2
++	vpand		$MASK,$H1,$H1		# 1
++	vpand		0(%rcx),$H4,$H4		# .Lmask24
++	vpsrlq		\$30,$H3,$H3
++	vpand		$MASK,$H2,$H2		# 2
++	vpand		$MASK,$H3,$H3		# 3
++	vpor		32(%rcx),$H4,$H4	# padbit, yes, always
++
++	vpaddq		0x00(%r11),$H0,$H0	# add hash value
++	vpaddq		0x10(%r11),$H1,$H1
++	vpaddq		0x20(%r11),$H2,$H2
++	vpaddq		0x30(%r11),$H3,$H3
++	vpaddq		0x40(%r11),$H4,$H4
++
++	lea		16*2($inp),%rax
++	lea		16*4($inp),$inp
++	sub		\$64,$len
++	cmovc		%rax,$inp
++
++	################################################################
++	# Now we accumulate (inp[0:1]+hash)*r^4
++	################################################################
++	# d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
++	# d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
++	# d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
++	# d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
++	# d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
++
++	vpmuludq	$H0,$T4,$T0		# h0*r0
++	vpmuludq	$H1,$T4,$T1		# h1*r0
++	vpaddq		$T0,$D0,$D0
++	vpaddq		$T1,$D1,$D1
++	 vmovdqa	-0x80(%r11),$T2		# r1^4
++	vpmuludq	$H2,$T4,$T0		# h2*r0
++	vpmuludq	$H3,$T4,$T1		# h3*r0
++	vpaddq		$T0,$D2,$D2
++	vpaddq		$T1,$D3,$D3
++	vpmuludq	$H4,$T4,$T4		# h4*r0
++	 vpmuludq	-0x70(%r11),$H4,$T0	# h4*s1
++	vpaddq		$T4,$D4,$D4
++
++	vpaddq		$T0,$D0,$D0		# d0 += h4*s1
++	vpmuludq	$H2,$T2,$T1		# h2*r1
++	vpmuludq	$H3,$T2,$T0		# h3*r1
++	vpaddq		$T1,$D3,$D3		# d3 += h2*r1
++	 vmovdqa	-0x60(%r11),$T3		# r2^4
++	vpaddq		$T0,$D4,$D4		# d4 += h3*r1
++	vpmuludq	$H1,$T2,$T1		# h1*r1
++	vpmuludq	$H0,$T2,$T2		# h0*r1
++	vpaddq		$T1,$D2,$D2		# d2 += h1*r1
++	vpaddq		$T2,$D1,$D1		# d1 += h0*r1
++
++	 vmovdqa	-0x50(%r11),$T4		# s2^4
++	vpmuludq	$H2,$T3,$T0		# h2*r2
++	vpmuludq	$H1,$T3,$T1		# h1*r2
++	vpaddq		$T0,$D4,$D4		# d4 += h2*r2
++	vpaddq		$T1,$D3,$D3		# d3 += h1*r2
++	 vmovdqa	-0x40(%r11),$T2		# r3^4
++	vpmuludq	$H0,$T3,$T3		# h0*r2
++	vpmuludq	$H4,$T4,$T0		# h4*s2
++	vpaddq		$T3,$D2,$D2		# d2 += h0*r2
++	vpaddq		$T0,$D1,$D1		# d1 += h4*s2
++	 vmovdqa	-0x30(%r11),$T3		# s3^4
++	vpmuludq	$H3,$T4,$T4		# h3*s2
++	 vpmuludq	$H1,$T2,$T1		# h1*r3
++	vpaddq		$T4,$D0,$D0		# d0 += h3*s2
++
++	 vmovdqa	-0x10(%r11),$T4		# s4^4
++	vpaddq		$T1,$D4,$D4		# d4 += h1*r3
++	vpmuludq	$H0,$T2,$T2		# h0*r3
++	vpmuludq	$H4,$T3,$T0		# h4*s3
++	vpaddq		$T2,$D3,$D3		# d3 += h0*r3
++	vpaddq		$T0,$D2,$D2		# d2 += h4*s3
++	 vmovdqu	16*2($inp),$T0				# load input
++	vpmuludq	$H3,$T3,$T2		# h3*s3
++	vpmuludq	$H2,$T3,$T3		# h2*s3
++	vpaddq		$T2,$D1,$D1		# d1 += h3*s3
++	 vmovdqu	16*3($inp),$T1				#
++	vpaddq		$T3,$D0,$D0		# d0 += h2*s3
++
++	vpmuludq	$H2,$T4,$H2		# h2*s4
++	vpmuludq	$H3,$T4,$H3		# h3*s4
++	 vpsrldq	\$6,$T0,$T2				# splat input
++	vpaddq		$H2,$D1,$D1		# d1 += h2*s4
++	vpmuludq	$H4,$T4,$H4		# h4*s4
++	 vpsrldq	\$6,$T1,$T3				#
++	vpaddq		$H3,$D2,$H2		# h2 = d2 + h3*s4
++	vpaddq		$H4,$D3,$H3		# h3 = d3 + h4*s4
++	vpmuludq	-0x20(%r11),$H0,$H4	# h0*r4
++	vpmuludq	$H1,$T4,$H0
++	 vpunpckhqdq	$T1,$T0,$T4		# 4
++	vpaddq		$H4,$D4,$H4		# h4 = d4 + h0*r4
++	vpaddq		$H0,$D0,$H0		# h0 = d0 + h1*s4
++
++	vpunpcklqdq	$T1,$T0,$T0		# 0:1
++	vpunpcklqdq	$T3,$T2,$T3		# 2:3
++
++	#vpsrlq		\$40,$T4,$T4		# 4
++	vpsrldq		\$`40/8`,$T4,$T4	# 4
++	vpsrlq		\$26,$T0,$T1
++	 vmovdqa	0x00(%rsp),$D4		# preload r0^2
++	vpand		$MASK,$T0,$T0		# 0
++	vpsrlq		\$4,$T3,$T2
++	vpand		$MASK,$T1,$T1		# 1
++	vpand		0(%rcx),$T4,$T4		# .Lmask24
++	vpsrlq		\$30,$T3,$T3
++	vpand		$MASK,$T2,$T2		# 2
++	vpand		$MASK,$T3,$T3		# 3
++	vpor		32(%rcx),$T4,$T4	# padbit, yes, always
++
++	################################################################
++	# lazy reduction as discussed in "NEON crypto" by D.J. Bernstein
++	# and P. Schwabe
++
++	vpsrlq		\$26,$H3,$D3
++	vpand		$MASK,$H3,$H3
++	vpaddq		$D3,$H4,$H4		# h3 -> h4
++
++	vpsrlq		\$26,$H0,$D0
++	vpand		$MASK,$H0,$H0
++	vpaddq		$D0,$D1,$H1		# h0 -> h1
++
++	vpsrlq		\$26,$H4,$D0
++	vpand		$MASK,$H4,$H4
++
++	vpsrlq		\$26,$H1,$D1
++	vpand		$MASK,$H1,$H1
++	vpaddq		$D1,$H2,$H2		# h1 -> h2
++
++	vpaddq		$D0,$H0,$H0
++	vpsllq		\$2,$D0,$D0
++	vpaddq		$D0,$H0,$H0		# h4 -> h0
++
++	vpsrlq		\$26,$H2,$D2
++	vpand		$MASK,$H2,$H2
++	vpaddq		$D2,$H3,$H3		# h2 -> h3
++
++	vpsrlq		\$26,$H0,$D0
++	vpand		$MASK,$H0,$H0
++	vpaddq		$D0,$H1,$H1		# h0 -> h1
++
++	vpsrlq		\$26,$H3,$D3
++	vpand		$MASK,$H3,$H3
++	vpaddq		$D3,$H4,$H4		# h3 -> h4
++
++	ja		.Loop_avx
++
++.Lskip_loop_avx:
++	################################################################
++	# multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1
++
++	vpshufd		\$0x10,$D4,$D4		# r0^n, xx12 -> x1x2
++	add		\$32,$len
++	jnz		.Long_tail_avx
++
++	vpaddq		$H2,$T2,$T2
++	vpaddq		$H0,$T0,$T0
++	vpaddq		$H1,$T1,$T1
++	vpaddq		$H3,$T3,$T3
++	vpaddq		$H4,$T4,$T4
++
++.Long_tail_avx:
++	vmovdqa		$H2,0x20(%r11)
++	vmovdqa		$H0,0x00(%r11)
++	vmovdqa		$H1,0x10(%r11)
++	vmovdqa		$H3,0x30(%r11)
++	vmovdqa		$H4,0x40(%r11)
++
++	# d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
++	# d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
++	# d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
++	# d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
++	# d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
++
++	vpmuludq	$T2,$D4,$D2		# d2 = h2*r0
++	vpmuludq	$T0,$D4,$D0		# d0 = h0*r0
++	 vpshufd	\$0x10,`16*1-64`($ctx),$H2		# r1^n
++	vpmuludq	$T1,$D4,$D1		# d1 = h1*r0
++	vpmuludq	$T3,$D4,$D3		# d3 = h3*r0
++	vpmuludq	$T4,$D4,$D4		# d4 = h4*r0
++
++	vpmuludq	$T3,$H2,$H0		# h3*r1
++	vpaddq		$H0,$D4,$D4		# d4 += h3*r1
++	 vpshufd	\$0x10,`16*2-64`($ctx),$H3		# s1^n
++	vpmuludq	$T2,$H2,$H1		# h2*r1
++	vpaddq		$H1,$D3,$D3		# d3 += h2*r1
++	 vpshufd	\$0x10,`16*3-64`($ctx),$H4		# r2^n
++	vpmuludq	$T1,$H2,$H0		# h1*r1
++	vpaddq		$H0,$D2,$D2		# d2 += h1*r1
++	vpmuludq	$T0,$H2,$H2		# h0*r1
++	vpaddq		$H2,$D1,$D1		# d1 += h0*r1
++	vpmuludq	$T4,$H3,$H3		# h4*s1
++	vpaddq		$H3,$D0,$D0		# d0 += h4*s1
++
++	 vpshufd	\$0x10,`16*4-64`($ctx),$H2		# s2^n
++	vpmuludq	$T2,$H4,$H1		# h2*r2
++	vpaddq		$H1,$D4,$D4		# d4 += h2*r2
++	vpmuludq	$T1,$H4,$H0		# h1*r2
++	vpaddq		$H0,$D3,$D3		# d3 += h1*r2
++	 vpshufd	\$0x10,`16*5-64`($ctx),$H3		# r3^n
++	vpmuludq	$T0,$H4,$H4		# h0*r2
++	vpaddq		$H4,$D2,$D2		# d2 += h0*r2
++	vpmuludq	$T4,$H2,$H1		# h4*s2
++	vpaddq		$H1,$D1,$D1		# d1 += h4*s2
++	 vpshufd	\$0x10,`16*6-64`($ctx),$H4		# s3^n
++	vpmuludq	$T3,$H2,$H2		# h3*s2
++	vpaddq		$H2,$D0,$D0		# d0 += h3*s2
++
++	vpmuludq	$T1,$H3,$H0		# h1*r3
++	vpaddq		$H0,$D4,$D4		# d4 += h1*r3
++	vpmuludq	$T0,$H3,$H3		# h0*r3
++	vpaddq		$H3,$D3,$D3		# d3 += h0*r3
++	 vpshufd	\$0x10,`16*7-64`($ctx),$H2		# r4^n
++	vpmuludq	$T4,$H4,$H1		# h4*s3
++	vpaddq		$H1,$D2,$D2		# d2 += h4*s3
++	 vpshufd	\$0x10,`16*8-64`($ctx),$H3		# s4^n
++	vpmuludq	$T3,$H4,$H0		# h3*s3
++	vpaddq		$H0,$D1,$D1		# d1 += h3*s3
++	vpmuludq	$T2,$H4,$H4		# h2*s3
++	vpaddq		$H4,$D0,$D0		# d0 += h2*s3
++
++	vpmuludq	$T0,$H2,$H2		# h0*r4
++	vpaddq		$H2,$D4,$D4		# h4 = d4 + h0*r4
++	vpmuludq	$T4,$H3,$H1		# h4*s4
++	vpaddq		$H1,$D3,$D3		# h3 = d3 + h4*s4
++	vpmuludq	$T3,$H3,$H0		# h3*s4
++	vpaddq		$H0,$D2,$D2		# h2 = d2 + h3*s4
++	vpmuludq	$T2,$H3,$H1		# h2*s4
++	vpaddq		$H1,$D1,$D1		# h1 = d1 + h2*s4
++	vpmuludq	$T1,$H3,$H3		# h1*s4
++	vpaddq		$H3,$D0,$D0		# h0 = d0 + h1*s4
++
++	jz		.Lshort_tail_avx
++
++	vmovdqu		16*0($inp),$H0		# load input
++	vmovdqu		16*1($inp),$H1
++
++	vpsrldq		\$6,$H0,$H2		# splat input
++	vpsrldq		\$6,$H1,$H3
++	vpunpckhqdq	$H1,$H0,$H4		# 4
++	vpunpcklqdq	$H1,$H0,$H0		# 0:1
++	vpunpcklqdq	$H3,$H2,$H3		# 2:3
++
++	vpsrlq		\$40,$H4,$H4		# 4
++	vpsrlq		\$26,$H0,$H1
++	vpand		$MASK,$H0,$H0		# 0
++	vpsrlq		\$4,$H3,$H2
++	vpand		$MASK,$H1,$H1		# 1
++	vpsrlq		\$30,$H3,$H3
++	vpand		$MASK,$H2,$H2		# 2
++	vpand		$MASK,$H3,$H3		# 3
++	vpor		32(%rcx),$H4,$H4	# padbit, yes, always
++
++	vpshufd		\$0x32,`16*0-64`($ctx),$T4	# r0^n, 34xx -> x3x4
++	vpaddq		0x00(%r11),$H0,$H0
++	vpaddq		0x10(%r11),$H1,$H1
++	vpaddq		0x20(%r11),$H2,$H2
++	vpaddq		0x30(%r11),$H3,$H3
++	vpaddq		0x40(%r11),$H4,$H4
++
++	################################################################
++	# multiply (inp[0:1]+hash) by r^4:r^3 and accumulate
++
++	vpmuludq	$H0,$T4,$T0		# h0*r0
++	vpaddq		$T0,$D0,$D0		# d0 += h0*r0
++	vpmuludq	$H1,$T4,$T1		# h1*r0
++	vpaddq		$T1,$D1,$D1		# d1 += h1*r0
++	vpmuludq	$H2,$T4,$T0		# h2*r0
++	vpaddq		$T0,$D2,$D2		# d2 += h2*r0
++	 vpshufd	\$0x32,`16*1-64`($ctx),$T2		# r1^n
++	vpmuludq	$H3,$T4,$T1		# h3*r0
++	vpaddq		$T1,$D3,$D3		# d3 += h3*r0
++	vpmuludq	$H4,$T4,$T4		# h4*r0
++	vpaddq		$T4,$D4,$D4		# d4 += h4*r0
++
++	vpmuludq	$H3,$T2,$T0		# h3*r1
++	vpaddq		$T0,$D4,$D4		# d4 += h3*r1
++	 vpshufd	\$0x32,`16*2-64`($ctx),$T3		# s1
++	vpmuludq	$H2,$T2,$T1		# h2*r1
++	vpaddq		$T1,$D3,$D3		# d3 += h2*r1
++	 vpshufd	\$0x32,`16*3-64`($ctx),$T4		# r2
++	vpmuludq	$H1,$T2,$T0		# h1*r1
++	vpaddq		$T0,$D2,$D2		# d2 += h1*r1
++	vpmuludq	$H0,$T2,$T2		# h0*r1
++	vpaddq		$T2,$D1,$D1		# d1 += h0*r1
++	vpmuludq	$H4,$T3,$T3		# h4*s1
++	vpaddq		$T3,$D0,$D0		# d0 += h4*s1
++
++	 vpshufd	\$0x32,`16*4-64`($ctx),$T2		# s2
++	vpmuludq	$H2,$T4,$T1		# h2*r2
++	vpaddq		$T1,$D4,$D4		# d4 += h2*r2
++	vpmuludq	$H1,$T4,$T0		# h1*r2
++	vpaddq		$T0,$D3,$D3		# d3 += h1*r2
++	 vpshufd	\$0x32,`16*5-64`($ctx),$T3		# r3
++	vpmuludq	$H0,$T4,$T4		# h0*r2
++	vpaddq		$T4,$D2,$D2		# d2 += h0*r2
++	vpmuludq	$H4,$T2,$T1		# h4*s2
++	vpaddq		$T1,$D1,$D1		# d1 += h4*s2
++	 vpshufd	\$0x32,`16*6-64`($ctx),$T4		# s3
++	vpmuludq	$H3,$T2,$T2		# h3*s2
++	vpaddq		$T2,$D0,$D0		# d0 += h3*s2
++
++	vpmuludq	$H1,$T3,$T0		# h1*r3
++	vpaddq		$T0,$D4,$D4		# d4 += h1*r3
++	vpmuludq	$H0,$T3,$T3		# h0*r3
++	vpaddq		$T3,$D3,$D3		# d3 += h0*r3
++	 vpshufd	\$0x32,`16*7-64`($ctx),$T2		# r4
++	vpmuludq	$H4,$T4,$T1		# h4*s3
++	vpaddq		$T1,$D2,$D2		# d2 += h4*s3
++	 vpshufd	\$0x32,`16*8-64`($ctx),$T3		# s4
++	vpmuludq	$H3,$T4,$T0		# h3*s3
++	vpaddq		$T0,$D1,$D1		# d1 += h3*s3
++	vpmuludq	$H2,$T4,$T4		# h2*s3
++	vpaddq		$T4,$D0,$D0		# d0 += h2*s3
++
++	vpmuludq	$H0,$T2,$T2		# h0*r4
++	vpaddq		$T2,$D4,$D4		# d4 += h0*r4
++	vpmuludq	$H4,$T3,$T1		# h4*s4
++	vpaddq		$T1,$D3,$D3		# d3 += h4*s4
++	vpmuludq	$H3,$T3,$T0		# h3*s4
++	vpaddq		$T0,$D2,$D2		# d2 += h3*s4
++	vpmuludq	$H2,$T3,$T1		# h2*s4
++	vpaddq		$T1,$D1,$D1		# d1 += h2*s4
++	vpmuludq	$H1,$T3,$T3		# h1*s4
++	vpaddq		$T3,$D0,$D0		# d0 += h1*s4
++
++.Lshort_tail_avx:
++	################################################################
++	# horizontal addition
++
++	vpsrldq		\$8,$D4,$T4
++	vpsrldq		\$8,$D3,$T3
++	vpsrldq		\$8,$D1,$T1
++	vpsrldq		\$8,$D0,$T0
++	vpsrldq		\$8,$D2,$T2
++	vpaddq		$T3,$D3,$D3
++	vpaddq		$T4,$D4,$D4
++	vpaddq		$T0,$D0,$D0
++	vpaddq		$T1,$D1,$D1
++	vpaddq		$T2,$D2,$D2
++
++	################################################################
++	# lazy reduction
++
++	vpsrlq		\$26,$D3,$H3
++	vpand		$MASK,$D3,$D3
++	vpaddq		$H3,$D4,$D4		# h3 -> h4
++
++	vpsrlq		\$26,$D0,$H0
++	vpand		$MASK,$D0,$D0
++	vpaddq		$H0,$D1,$D1		# h0 -> h1
++
++	vpsrlq		\$26,$D4,$H4
++	vpand		$MASK,$D4,$D4
++
++	vpsrlq		\$26,$D1,$H1
++	vpand		$MASK,$D1,$D1
++	vpaddq		$H1,$D2,$D2		# h1 -> h2
++
++	vpaddq		$H4,$D0,$D0
++	vpsllq		\$2,$H4,$H4
++	vpaddq		$H4,$D0,$D0		# h4 -> h0
++
++	vpsrlq		\$26,$D2,$H2
++	vpand		$MASK,$D2,$D2
++	vpaddq		$H2,$D3,$D3		# h2 -> h3
++
++	vpsrlq		\$26,$D0,$H0
++	vpand		$MASK,$D0,$D0
++	vpaddq		$H0,$D1,$D1		# h0 -> h1
++
++	vpsrlq		\$26,$D3,$H3
++	vpand		$MASK,$D3,$D3
++	vpaddq		$H3,$D4,$D4		# h3 -> h4
++
++	vmovd		$D0,`4*0-48-64`($ctx)	# save partially reduced
++	vmovd		$D1,`4*1-48-64`($ctx)
++	vmovd		$D2,`4*2-48-64`($ctx)
++	vmovd		$D3,`4*3-48-64`($ctx)
++	vmovd		$D4,`4*4-48-64`($ctx)
++___
++$code.=<<___	if ($win64);
++	vmovdqa		0x50(%r11),%xmm6
++	vmovdqa		0x60(%r11),%xmm7
++	vmovdqa		0x70(%r11),%xmm8
++	vmovdqa		0x80(%r11),%xmm9
++	vmovdqa		0x90(%r11),%xmm10
++	vmovdqa		0xa0(%r11),%xmm11
++	vmovdqa		0xb0(%r11),%xmm12
++	vmovdqa		0xc0(%r11),%xmm13
++	vmovdqa		0xd0(%r11),%xmm14
++	vmovdqa		0xe0(%r11),%xmm15
++	lea		0xf8(%r11),%rsp
++.Ldo_avx_epilogue:
++___
++$code.=<<___	if (!$win64);
++	lea		0x58(%r11),%rsp
++.cfi_def_cfa		%rsp,8
++___
++$code.=<<___;
++	vzeroupper
++	ret
++.cfi_endproc
++.size	poly1305_blocks_avx,.-poly1305_blocks_avx
++
++.type	poly1305_emit_avx,\@function,3
++.align	32
++poly1305_emit_avx:
++	cmpl	\$0,20($ctx)	# is_base2_26?
++	je	.Lemit
++
++	mov	0($ctx),%eax	# load hash value base 2^26
++	mov	4($ctx),%ecx
++	mov	8($ctx),%r8d
++	mov	12($ctx),%r11d
++	mov	16($ctx),%r10d
++
++	shl	\$26,%rcx	# base 2^26 -> base 2^64
++	mov	%r8,%r9
++	shl	\$52,%r8
++	add	%rcx,%rax
++	shr	\$12,%r9
++	add	%rax,%r8	# h0
++	adc	\$0,%r9
++
++	shl	\$14,%r11
++	mov	%r10,%rax
++	shr	\$24,%r10
++	add	%r11,%r9
++	shl	\$40,%rax
++	add	%rax,%r9	# h1
++	adc	\$0,%r10	# h2
++
++	mov	%r10,%rax	# could be partially reduced, so reduce
++	mov	%r10,%rcx
++	and	\$3,%r10
++	shr	\$2,%rax
++	and	\$-4,%rcx
++	add	%rcx,%rax
++	add	%rax,%r8
++	adc	\$0,%r9
++	adc	\$0,%r10
++
++	mov	%r8,%rax
++	add	\$5,%r8		# compare to modulus
++	mov	%r9,%rcx
++	adc	\$0,%r9
++	adc	\$0,%r10
++	shr	\$2,%r10	# did 130-bit value overflow?
++	cmovnz	%r8,%rax
++	cmovnz	%r9,%rcx
++
++	add	0($nonce),%rax	# accumulate nonce
++	adc	8($nonce),%rcx
++	mov	%rax,0($mac)	# write result
++	mov	%rcx,8($mac)
++
++	ret
++.size	poly1305_emit_avx,.-poly1305_emit_avx
++___
++
++if ($avx>1) {
++my ($H0,$H1,$H2,$H3,$H4, $MASK, $T4,$T0,$T1,$T2,$T3, $D0,$D1,$D2,$D3,$D4) =
++    map("%ymm$_",(0..15));
++my $S4=$MASK;
++
++$code.=<<___;
++.type	poly1305_blocks_avx2,\@function,4
++.align	32
++poly1305_blocks_avx2:
++.cfi_startproc
++	mov	20($ctx),%r8d		# is_base2_26
++	cmp	\$128,$len
++	jae	.Lblocks_avx2
++	test	%r8d,%r8d
++	jz	.Lblocks
++
++.Lblocks_avx2:
++	and	\$-16,$len
++	jz	.Lno_data_avx2
++
++	vzeroupper
++
++	test	%r8d,%r8d
++	jz	.Lbase2_64_avx2
++
++	test	\$63,$len
++	jz	.Leven_avx2
++
++	push	%rbx
++.cfi_push	%rbx
++	push	%rbp
++.cfi_push	%rbp
++	push	%r12
++.cfi_push	%r12
++	push	%r13
++.cfi_push	%r13
++	push	%r14
++.cfi_push	%r14
++	push	%r15
++.cfi_push	%r15
++.Lblocks_avx2_body:
++
++	mov	$len,%r15		# reassign $len
++
++	mov	0($ctx),$d1		# load hash value
++	mov	8($ctx),$d2
++	mov	16($ctx),$h2#d
++
++	mov	24($ctx),$r0		# load r
++	mov	32($ctx),$s1
++
++	################################# base 2^26 -> base 2^64
++	mov	$d1#d,$h0#d
++	and	\$`-1*(1<<31)`,$d1
++	mov	$d2,$r1			# borrow $r1
++	mov	$d2#d,$h1#d
++	and	\$`-1*(1<<31)`,$d2
++
++	shr	\$6,$d1
++	shl	\$52,$r1
++	add	$d1,$h0
++	shr	\$12,$h1
++	shr	\$18,$d2
++	add	$r1,$h0
++	adc	$d2,$h1
++
++	mov	$h2,$d1
++	shl	\$40,$d1
++	shr	\$24,$h2
++	add	$d1,$h1
++	adc	\$0,$h2			# can be partially reduced...
++
++	mov	\$-4,$d2		# ... so reduce
++	mov	$h2,$d1
++	and	$h2,$d2
++	shr	\$2,$d1
++	and	\$3,$h2
++	add	$d2,$d1			# =*5
++	add	$d1,$h0
++	adc	\$0,$h1
++	adc	\$0,$h2
++
++	mov	$s1,$r1
++	mov	$s1,%rax
++	shr	\$2,$s1
++	add	$r1,$s1			# s1 = r1 + (r1 >> 2)
++
++.Lbase2_26_pre_avx2:
++	add	0($inp),$h0		# accumulate input
++	adc	8($inp),$h1
++	lea	16($inp),$inp
++	adc	$padbit,$h2
++	sub	\$16,%r15
++
++	call	__poly1305_block
++	mov	$r1,%rax
++
++	test	\$63,%r15
++	jnz	.Lbase2_26_pre_avx2
++
++	test	$padbit,$padbit		# if $padbit is zero,
++	jz	.Lstore_base2_64_avx2	# store hash in base 2^64 format
++
++	################################# base 2^64 -> base 2^26
++	mov	$h0,%rax
++	mov	$h0,%rdx
++	shr	\$52,$h0
++	mov	$h1,$r0
++	mov	$h1,$r1
++	shr	\$26,%rdx
++	and	\$0x3ffffff,%rax	# h[0]
++	shl	\$12,$r0
++	and	\$0x3ffffff,%rdx	# h[1]
++	shr	\$14,$h1
++	or	$r0,$h0
++	shl	\$24,$h2
++	and	\$0x3ffffff,$h0		# h[2]
++	shr	\$40,$r1
++	and	\$0x3ffffff,$h1		# h[3]
++	or	$r1,$h2			# h[4]
++
++	test	%r15,%r15
++	jz	.Lstore_base2_26_avx2
++
++	vmovd	%rax#d,%x#$H0
++	vmovd	%rdx#d,%x#$H1
++	vmovd	$h0#d,%x#$H2
++	vmovd	$h1#d,%x#$H3
++	vmovd	$h2#d,%x#$H4
++	jmp	.Lproceed_avx2
++
++.align	32
++.Lstore_base2_64_avx2:
++	mov	$h0,0($ctx)
++	mov	$h1,8($ctx)
++	mov	$h2,16($ctx)		# note that is_base2_26 is zeroed
++	jmp	.Ldone_avx2
++
++.align	16
++.Lstore_base2_26_avx2:
++	mov	%rax#d,0($ctx)		# store hash value base 2^26
++	mov	%rdx#d,4($ctx)
++	mov	$h0#d,8($ctx)
++	mov	$h1#d,12($ctx)
++	mov	$h2#d,16($ctx)
++.align	16
++.Ldone_avx2:
++	mov	0(%rsp),%r15
++.cfi_restore	%r15
++	mov	8(%rsp),%r14
++.cfi_restore	%r14
++	mov	16(%rsp),%r13
++.cfi_restore	%r13
++	mov	24(%rsp),%r12
++.cfi_restore	%r12
++	mov	32(%rsp),%rbp
++.cfi_restore	%rbp
++	mov	40(%rsp),%rbx
++.cfi_restore	%rbx
++	lea	48(%rsp),%rsp
++.cfi_adjust_cfa_offset	-48
++.Lno_data_avx2:
++.Lblocks_avx2_epilogue:
++	ret
++.cfi_endproc
++
++.align	32
++.Lbase2_64_avx2:
++.cfi_startproc
++	push	%rbx
++.cfi_push	%rbx
++	push	%rbp
++.cfi_push	%rbp
++	push	%r12
++.cfi_push	%r12
++	push	%r13
++.cfi_push	%r13
++	push	%r14
++.cfi_push	%r14
++	push	%r15
++.cfi_push	%r15
++.Lbase2_64_avx2_body:
++
++	mov	$len,%r15		# reassign $len
++
++	mov	24($ctx),$r0		# load r
++	mov	32($ctx),$s1
++
++	mov	0($ctx),$h0		# load hash value
++	mov	8($ctx),$h1
++	mov	16($ctx),$h2#d
++
++	mov	$s1,$r1
++	mov	$s1,%rax
++	shr	\$2,$s1
++	add	$r1,$s1			# s1 = r1 + (r1 >> 2)
++
++	test	\$63,$len
++	jz	.Linit_avx2
++
++.Lbase2_64_pre_avx2:
++	add	0($inp),$h0		# accumulate input
++	adc	8($inp),$h1
++	lea	16($inp),$inp
++	adc	$padbit,$h2
++	sub	\$16,%r15
++
++	call	__poly1305_block
++	mov	$r1,%rax
++
++	test	\$63,%r15
++	jnz	.Lbase2_64_pre_avx2
++
++.Linit_avx2:
++	################################# base 2^64 -> base 2^26
++	mov	$h0,%rax
++	mov	$h0,%rdx
++	shr	\$52,$h0
++	mov	$h1,$d1
++	mov	$h1,$d2
++	shr	\$26,%rdx
++	and	\$0x3ffffff,%rax	# h[0]
++	shl	\$12,$d1
++	and	\$0x3ffffff,%rdx	# h[1]
++	shr	\$14,$h1
++	or	$d1,$h0
++	shl	\$24,$h2
++	and	\$0x3ffffff,$h0		# h[2]
++	shr	\$40,$d2
++	and	\$0x3ffffff,$h1		# h[3]
++	or	$d2,$h2			# h[4]
++
++	vmovd	%rax#d,%x#$H0
++	vmovd	%rdx#d,%x#$H1
++	vmovd	$h0#d,%x#$H2
++	vmovd	$h1#d,%x#$H3
++	vmovd	$h2#d,%x#$H4
++	movl	\$1,20($ctx)		# set is_base2_26
++
++	call	__poly1305_init_avx
++
++.Lproceed_avx2:
++	mov	%r15,$len			# restore $len
++	mov	OPENSSL_ia32cap_P+8(%rip),%r10d
++	mov	\$`(1<<31|1<<30|1<<16)`,%r11d
++
++	mov	0(%rsp),%r15
++.cfi_restore	%r15
++	mov	8(%rsp),%r14
++.cfi_restore	%r14
++	mov	16(%rsp),%r13
++.cfi_restore	%r13
++	mov	24(%rsp),%r12
++.cfi_restore	%r12
++	mov	32(%rsp),%rbp
++.cfi_restore	%rbp
++	mov	40(%rsp),%rbx
++.cfi_restore	%rbx
++	lea	48(%rsp),%rax
++	lea	48(%rsp),%rsp
++.cfi_adjust_cfa_offset	-48
++.Lbase2_64_avx2_epilogue:
++	jmp	.Ldo_avx2
++.cfi_endproc
++
++.align	32
++.Leven_avx2:
++.cfi_startproc
++	mov		OPENSSL_ia32cap_P+8(%rip),%r10d
++	vmovd		4*0($ctx),%x#$H0	# load hash value base 2^26
++	vmovd		4*1($ctx),%x#$H1
++	vmovd		4*2($ctx),%x#$H2
++	vmovd		4*3($ctx),%x#$H3
++	vmovd		4*4($ctx),%x#$H4
++
++.Ldo_avx2:
++___
++$code.=<<___		if ($avx>2);
++	cmp		\$512,$len
++	jb		.Lskip_avx512
++	and		%r11d,%r10d
++	test		\$`1<<16`,%r10d		# check for AVX512F
++	jnz		.Lblocks_avx512
++.Lskip_avx512:
++___
++$code.=<<___	if (!$win64);
++	lea		-8(%rsp),%r11
++.cfi_def_cfa		%r11,16
++	sub		\$0x128,%rsp
++___
++$code.=<<___	if ($win64);
++	lea		-0xf8(%rsp),%r11
++	sub		\$0x1c8,%rsp
++	vmovdqa		%xmm6,0x50(%r11)
++	vmovdqa		%xmm7,0x60(%r11)
++	vmovdqa		%xmm8,0x70(%r11)
++	vmovdqa		%xmm9,0x80(%r11)
++	vmovdqa		%xmm10,0x90(%r11)
++	vmovdqa		%xmm11,0xa0(%r11)
++	vmovdqa		%xmm12,0xb0(%r11)
++	vmovdqa		%xmm13,0xc0(%r11)
++	vmovdqa		%xmm14,0xd0(%r11)
++	vmovdqa		%xmm15,0xe0(%r11)
++.Ldo_avx2_body:
++___
++$code.=<<___;
++	lea		.Lconst(%rip),%rcx
++	lea		48+64($ctx),$ctx	# size optimization
++	vmovdqa		96(%rcx),$T0		# .Lpermd_avx2
++
++	# expand and copy pre-calculated table to stack
++	vmovdqu		`16*0-64`($ctx),%x#$T2
++	and		\$-512,%rsp
++	vmovdqu		`16*1-64`($ctx),%x#$T3
++	vmovdqu		`16*2-64`($ctx),%x#$T4
++	vmovdqu		`16*3-64`($ctx),%x#$D0
++	vmovdqu		`16*4-64`($ctx),%x#$D1
++	vmovdqu		`16*5-64`($ctx),%x#$D2
++	lea		0x90(%rsp),%rax		# size optimization
++	vmovdqu		`16*6-64`($ctx),%x#$D3
++	vpermd		$T2,$T0,$T2		# 00003412 -> 14243444
++	vmovdqu		`16*7-64`($ctx),%x#$D4
++	vpermd		$T3,$T0,$T3
++	vmovdqu		`16*8-64`($ctx),%x#$MASK
++	vpermd		$T4,$T0,$T4
++	vmovdqa		$T2,0x00(%rsp)
++	vpermd		$D0,$T0,$D0
++	vmovdqa		$T3,0x20-0x90(%rax)
++	vpermd		$D1,$T0,$D1
++	vmovdqa		$T4,0x40-0x90(%rax)
++	vpermd		$D2,$T0,$D2
++	vmovdqa		$D0,0x60-0x90(%rax)
++	vpermd		$D3,$T0,$D3
++	vmovdqa		$D1,0x80-0x90(%rax)
++	vpermd		$D4,$T0,$D4
++	vmovdqa		$D2,0xa0-0x90(%rax)
++	vpermd		$MASK,$T0,$MASK
++	vmovdqa		$D3,0xc0-0x90(%rax)
++	vmovdqa		$D4,0xe0-0x90(%rax)
++	vmovdqa		$MASK,0x100-0x90(%rax)
++	vmovdqa		64(%rcx),$MASK		# .Lmask26
++
++	################################################################
++	# load input
++	vmovdqu		16*0($inp),%x#$T0
++	vmovdqu		16*1($inp),%x#$T1
++	vinserti128	\$1,16*2($inp),$T0,$T0
++	vinserti128	\$1,16*3($inp),$T1,$T1
++	lea		16*4($inp),$inp
++
++	vpsrldq		\$6,$T0,$T2		# splat input
++	vpsrldq		\$6,$T1,$T3
++	vpunpckhqdq	$T1,$T0,$T4		# 4
++	vpunpcklqdq	$T3,$T2,$T2		# 2:3
++	vpunpcklqdq	$T1,$T0,$T0		# 0:1
++
++	vpsrlq		\$30,$T2,$T3
++	vpsrlq		\$4,$T2,$T2
++	vpsrlq		\$26,$T0,$T1
++	vpsrlq		\$40,$T4,$T4		# 4
++	vpand		$MASK,$T2,$T2		# 2
++	vpand		$MASK,$T0,$T0		# 0
++	vpand		$MASK,$T1,$T1		# 1
++	vpand		$MASK,$T3,$T3		# 3
++	vpor		32(%rcx),$T4,$T4	# padbit, yes, always
++
++	vpaddq		$H2,$T2,$H2		# accumulate input
++	sub		\$64,$len
++	jz		.Ltail_avx2
++	jmp		.Loop_avx2
++
++.align	32
++.Loop_avx2:
++	################################################################
++	# ((inp[0]*r^4+inp[4])*r^4+inp[ 8])*r^4
++	# ((inp[1]*r^4+inp[5])*r^4+inp[ 9])*r^3
++	# ((inp[2]*r^4+inp[6])*r^4+inp[10])*r^2
++	# ((inp[3]*r^4+inp[7])*r^4+inp[11])*r^1
++	#   \________/\__________/
++	################################################################
++	#vpaddq		$H2,$T2,$H2		# accumulate input
++	vpaddq		$H0,$T0,$H0
++	vmovdqa		`32*0`(%rsp),$T0	# r0^4
++	vpaddq		$H1,$T1,$H1
++	vmovdqa		`32*1`(%rsp),$T1	# r1^4
++	vpaddq		$H3,$T3,$H3
++	vmovdqa		`32*3`(%rsp),$T2	# r2^4
++	vpaddq		$H4,$T4,$H4
++	vmovdqa		`32*6-0x90`(%rax),$T3	# s3^4
++	vmovdqa		`32*8-0x90`(%rax),$S4	# s4^4
++
++	# d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
++	# d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
++	# d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
++	# d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
++	# d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
++	#
++	# however, as h2 is "chronologically" first one available pull
++	# corresponding operations up, so it's
++	#
++	# d4 = h2*r2   + h4*r0 + h3*r1             + h1*r3   + h0*r4
++	# d3 = h2*r1   + h3*r0           + h1*r2   + h0*r3   + h4*5*r4
++	# d2 = h2*r0           + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
++	# d1 = h2*5*r4 + h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3
++	# d0 = h2*5*r3 + h0*r0 + h4*5*r1 + h3*5*r2           + h1*5*r4
++
++	vpmuludq	$H2,$T0,$D2		# d2 = h2*r0
++	vpmuludq	$H2,$T1,$D3		# d3 = h2*r1
++	vpmuludq	$H2,$T2,$D4		# d4 = h2*r2
++	vpmuludq	$H2,$T3,$D0		# d0 = h2*s3
++	vpmuludq	$H2,$S4,$D1		# d1 = h2*s4
++
++	vpmuludq	$H0,$T1,$T4		# h0*r1
++	vpmuludq	$H1,$T1,$H2		# h1*r1, borrow $H2 as temp
++	vpaddq		$T4,$D1,$D1		# d1 += h0*r1
++	vpaddq		$H2,$D2,$D2		# d2 += h1*r1
++	vpmuludq	$H3,$T1,$T4		# h3*r1
++	vpmuludq	`32*2`(%rsp),$H4,$H2	# h4*s1
++	vpaddq		$T4,$D4,$D4		# d4 += h3*r1
++	vpaddq		$H2,$D0,$D0		# d0 += h4*s1
++	 vmovdqa	`32*4-0x90`(%rax),$T1	# s2
++
++	vpmuludq	$H0,$T0,$T4		# h0*r0
++	vpmuludq	$H1,$T0,$H2		# h1*r0
++	vpaddq		$T4,$D0,$D0		# d0 += h0*r0
++	vpaddq		$H2,$D1,$D1		# d1 += h1*r0
++	vpmuludq	$H3,$T0,$T4		# h3*r0
++	vpmuludq	$H4,$T0,$H2		# h4*r0
++	 vmovdqu	16*0($inp),%x#$T0	# load input
++	vpaddq		$T4,$D3,$D3		# d3 += h3*r0
++	vpaddq		$H2,$D4,$D4		# d4 += h4*r0
++	 vinserti128	\$1,16*2($inp),$T0,$T0
++
++	vpmuludq	$H3,$T1,$T4		# h3*s2
++	vpmuludq	$H4,$T1,$H2		# h4*s2
++	 vmovdqu	16*1($inp),%x#$T1
++	vpaddq		$T4,$D0,$D0		# d0 += h3*s2
++	vpaddq		$H2,$D1,$D1		# d1 += h4*s2
++	 vmovdqa	`32*5-0x90`(%rax),$H2	# r3
++	vpmuludq	$H1,$T2,$T4		# h1*r2
++	vpmuludq	$H0,$T2,$T2		# h0*r2
++	vpaddq		$T4,$D3,$D3		# d3 += h1*r2
++	vpaddq		$T2,$D2,$D2		# d2 += h0*r2
++	 vinserti128	\$1,16*3($inp),$T1,$T1
++	 lea		16*4($inp),$inp
++
++	vpmuludq	$H1,$H2,$T4		# h1*r3
++	vpmuludq	$H0,$H2,$H2		# h0*r3
++	 vpsrldq	\$6,$T0,$T2		# splat input
++	vpaddq		$T4,$D4,$D4		# d4 += h1*r3
++	vpaddq		$H2,$D3,$D3		# d3 += h0*r3
++	vpmuludq	$H3,$T3,$T4		# h3*s3
++	vpmuludq	$H4,$T3,$H2		# h4*s3
++	 vpsrldq	\$6,$T1,$T3
++	vpaddq		$T4,$D1,$D1		# d1 += h3*s3
++	vpaddq		$H2,$D2,$D2		# d2 += h4*s3
++	 vpunpckhqdq	$T1,$T0,$T4		# 4
++
++	vpmuludq	$H3,$S4,$H3		# h3*s4
++	vpmuludq	$H4,$S4,$H4		# h4*s4
++	 vpunpcklqdq	$T1,$T0,$T0		# 0:1
++	vpaddq		$H3,$D2,$H2		# h2 = d2 + h3*r4
++	vpaddq		$H4,$D3,$H3		# h3 = d3 + h4*r4
++	 vpunpcklqdq	$T3,$T2,$T3		# 2:3
++	vpmuludq	`32*7-0x90`(%rax),$H0,$H4	# h0*r4
++	vpmuludq	$H1,$S4,$H0		# h1*s4
++	vmovdqa		64(%rcx),$MASK		# .Lmask26
++	vpaddq		$H4,$D4,$H4		# h4 = d4 + h0*r4
++	vpaddq		$H0,$D0,$H0		# h0 = d0 + h1*s4
++
++	################################################################
++	# lazy reduction (interleaved with tail of input splat)
++
++	vpsrlq		\$26,$H3,$D3
++	vpand		$MASK,$H3,$H3
++	vpaddq		$D3,$H4,$H4		# h3 -> h4
++
++	vpsrlq		\$26,$H0,$D0
++	vpand		$MASK,$H0,$H0
++	vpaddq		$D0,$D1,$H1		# h0 -> h1
++
++	vpsrlq		\$26,$H4,$D4
++	vpand		$MASK,$H4,$H4
++
++	 vpsrlq		\$4,$T3,$T2
++
++	vpsrlq		\$26,$H1,$D1
++	vpand		$MASK,$H1,$H1
++	vpaddq		$D1,$H2,$H2		# h1 -> h2
++
++	vpaddq		$D4,$H0,$H0
++	vpsllq		\$2,$D4,$D4
++	vpaddq		$D4,$H0,$H0		# h4 -> h0
++
++	 vpand		$MASK,$T2,$T2		# 2
++	 vpsrlq		\$26,$T0,$T1
++
++	vpsrlq		\$26,$H2,$D2
++	vpand		$MASK,$H2,$H2
++	vpaddq		$D2,$H3,$H3		# h2 -> h3
++
++	 vpaddq		$T2,$H2,$H2		# modulo-scheduled
++	 vpsrlq		\$30,$T3,$T3
++
++	vpsrlq		\$26,$H0,$D0
++	vpand		$MASK,$H0,$H0
++	vpaddq		$D0,$H1,$H1		# h0 -> h1
++
++	 vpsrlq		\$40,$T4,$T4		# 4
++
++	vpsrlq		\$26,$H3,$D3
++	vpand		$MASK,$H3,$H3
++	vpaddq		$D3,$H4,$H4		# h3 -> h4
++
++	 vpand		$MASK,$T0,$T0		# 0
++	 vpand		$MASK,$T1,$T1		# 1
++	 vpand		$MASK,$T3,$T3		# 3
++	 vpor		32(%rcx),$T4,$T4	# padbit, yes, always
++
++	sub		\$64,$len
++	jnz		.Loop_avx2
++
++	.byte		0x66,0x90
++.Ltail_avx2:
++	################################################################
++	# while above multiplications were by r^4 in all lanes, in last
++	# iteration we multiply least significant lane by r^4 and most
++	# significant one by r, so copy of above except that references
++	# to the precomputed table are displaced by 4...
++
++	#vpaddq		$H2,$T2,$H2		# accumulate input
++	vpaddq		$H0,$T0,$H0
++	vmovdqu		`32*0+4`(%rsp),$T0	# r0^4
++	vpaddq		$H1,$T1,$H1
++	vmovdqu		`32*1+4`(%rsp),$T1	# r1^4
++	vpaddq		$H3,$T3,$H3
++	vmovdqu		`32*3+4`(%rsp),$T2	# r2^4
++	vpaddq		$H4,$T4,$H4
++	vmovdqu		`32*6+4-0x90`(%rax),$T3	# s3^4
++	vmovdqu		`32*8+4-0x90`(%rax),$S4	# s4^4
++
++	vpmuludq	$H2,$T0,$D2		# d2 = h2*r0
++	vpmuludq	$H2,$T1,$D3		# d3 = h2*r1
++	vpmuludq	$H2,$T2,$D4		# d4 = h2*r2
++	vpmuludq	$H2,$T3,$D0		# d0 = h2*s3
++	vpmuludq	$H2,$S4,$D1		# d1 = h2*s4
++
++	vpmuludq	$H0,$T1,$T4		# h0*r1
++	vpmuludq	$H1,$T1,$H2		# h1*r1
++	vpaddq		$T4,$D1,$D1		# d1 += h0*r1
++	vpaddq		$H2,$D2,$D2		# d2 += h1*r1
++	vpmuludq	$H3,$T1,$T4		# h3*r1
++	vpmuludq	`32*2+4`(%rsp),$H4,$H2	# h4*s1
++	vpaddq		$T4,$D4,$D4		# d4 += h3*r1
++	vpaddq		$H2,$D0,$D0		# d0 += h4*s1
++
++	vpmuludq	$H0,$T0,$T4		# h0*r0
++	vpmuludq	$H1,$T0,$H2		# h1*r0
++	vpaddq		$T4,$D0,$D0		# d0 += h0*r0
++	 vmovdqu	`32*4+4-0x90`(%rax),$T1	# s2
++	vpaddq		$H2,$D1,$D1		# d1 += h1*r0
++	vpmuludq	$H3,$T0,$T4		# h3*r0
++	vpmuludq	$H4,$T0,$H2		# h4*r0
++	vpaddq		$T4,$D3,$D3		# d3 += h3*r0
++	vpaddq		$H2,$D4,$D4		# d4 += h4*r0
++
++	vpmuludq	$H3,$T1,$T4		# h3*s2
++	vpmuludq	$H4,$T1,$H2		# h4*s2
++	vpaddq		$T4,$D0,$D0		# d0 += h3*s2
++	vpaddq		$H2,$D1,$D1		# d1 += h4*s2
++	 vmovdqu	`32*5+4-0x90`(%rax),$H2	# r3
++	vpmuludq	$H1,$T2,$T4		# h1*r2
++	vpmuludq	$H0,$T2,$T2		# h0*r2
++	vpaddq		$T4,$D3,$D3		# d3 += h1*r2
++	vpaddq		$T2,$D2,$D2		# d2 += h0*r2
++
++	vpmuludq	$H1,$H2,$T4		# h1*r3
++	vpmuludq	$H0,$H2,$H2		# h0*r3
++	vpaddq		$T4,$D4,$D4		# d4 += h1*r3
++	vpaddq		$H2,$D3,$D3		# d3 += h0*r3
++	vpmuludq	$H3,$T3,$T4		# h3*s3
++	vpmuludq	$H4,$T3,$H2		# h4*s3
++	vpaddq		$T4,$D1,$D1		# d1 += h3*s3
++	vpaddq		$H2,$D2,$D2		# d2 += h4*s3
++
++	vpmuludq	$H3,$S4,$H3		# h3*s4
++	vpmuludq	$H4,$S4,$H4		# h4*s4
++	vpaddq		$H3,$D2,$H2		# h2 = d2 + h3*r4
++	vpaddq		$H4,$D3,$H3		# h3 = d3 + h4*r4
++	vpmuludq	`32*7+4-0x90`(%rax),$H0,$H4		# h0*r4
++	vpmuludq	$H1,$S4,$H0		# h1*s4
++	vmovdqa		64(%rcx),$MASK		# .Lmask26
++	vpaddq		$H4,$D4,$H4		# h4 = d4 + h0*r4
++	vpaddq		$H0,$D0,$H0		# h0 = d0 + h1*s4
++
++	################################################################
++	# horizontal addition
++
++	vpsrldq		\$8,$D1,$T1
++	vpsrldq		\$8,$H2,$T2
++	vpsrldq		\$8,$H3,$T3
++	vpsrldq		\$8,$H4,$T4
++	vpsrldq		\$8,$H0,$T0
++	vpaddq		$T1,$D1,$D1
++	vpaddq		$T2,$H2,$H2
++	vpaddq		$T3,$H3,$H3
++	vpaddq		$T4,$H4,$H4
++	vpaddq		$T0,$H0,$H0
++
++	vpermq		\$0x2,$H3,$T3
++	vpermq		\$0x2,$H4,$T4
++	vpermq		\$0x2,$H0,$T0
++	vpermq		\$0x2,$D1,$T1
++	vpermq		\$0x2,$H2,$T2
++	vpaddq		$T3,$H3,$H3
++	vpaddq		$T4,$H4,$H4
++	vpaddq		$T0,$H0,$H0
++	vpaddq		$T1,$D1,$D1
++	vpaddq		$T2,$H2,$H2
++
++	################################################################
++	# lazy reduction
++
++	vpsrlq		\$26,$H3,$D3
++	vpand		$MASK,$H3,$H3
++	vpaddq		$D3,$H4,$H4		# h3 -> h4
++
++	vpsrlq		\$26,$H0,$D0
++	vpand		$MASK,$H0,$H0
++	vpaddq		$D0,$D1,$H1		# h0 -> h1
++
++	vpsrlq		\$26,$H4,$D4
++	vpand		$MASK,$H4,$H4
++
++	vpsrlq		\$26,$H1,$D1
++	vpand		$MASK,$H1,$H1
++	vpaddq		$D1,$H2,$H2		# h1 -> h2
++
++	vpaddq		$D4,$H0,$H0
++	vpsllq		\$2,$D4,$D4
++	vpaddq		$D4,$H0,$H0		# h4 -> h0
++
++	vpsrlq		\$26,$H2,$D2
++	vpand		$MASK,$H2,$H2
++	vpaddq		$D2,$H3,$H3		# h2 -> h3
++
++	vpsrlq		\$26,$H0,$D0
++	vpand		$MASK,$H0,$H0
++	vpaddq		$D0,$H1,$H1		# h0 -> h1
++
++	vpsrlq		\$26,$H3,$D3
++	vpand		$MASK,$H3,$H3
++	vpaddq		$D3,$H4,$H4		# h3 -> h4
++
++	vmovd		%x#$H0,`4*0-48-64`($ctx)# save partially reduced
++	vmovd		%x#$H1,`4*1-48-64`($ctx)
++	vmovd		%x#$H2,`4*2-48-64`($ctx)
++	vmovd		%x#$H3,`4*3-48-64`($ctx)
++	vmovd		%x#$H4,`4*4-48-64`($ctx)
++___
++$code.=<<___	if ($win64);
++	vmovdqa		0x50(%r11),%xmm6
++	vmovdqa		0x60(%r11),%xmm7
++	vmovdqa		0x70(%r11),%xmm8
++	vmovdqa		0x80(%r11),%xmm9
++	vmovdqa		0x90(%r11),%xmm10
++	vmovdqa		0xa0(%r11),%xmm11
++	vmovdqa		0xb0(%r11),%xmm12
++	vmovdqa		0xc0(%r11),%xmm13
++	vmovdqa		0xd0(%r11),%xmm14
++	vmovdqa		0xe0(%r11),%xmm15
++	lea		0xf8(%r11),%rsp
++.Ldo_avx2_epilogue:
++___
++$code.=<<___	if (!$win64);
++	lea		8(%r11),%rsp
++.cfi_def_cfa		%rsp,8
++___
++$code.=<<___;
++	vzeroupper
++	ret
++.cfi_endproc
++.size	poly1305_blocks_avx2,.-poly1305_blocks_avx2
++___
++#######################################################################
++if ($avx>2) {
++# On entry we have input length divisible by 64. But since inner loop
++# processes 128 bytes per iteration, cases when length is not divisible
++# by 128 are handled by passing tail 64 bytes to .Ltail_avx2. For this
++# reason stack layout is kept identical to poly1305_blocks_avx2. If not
++# for this tail, we wouldn't have to even allocate stack frame...
++
++my ($R0,$R1,$R2,$R3,$R4, $S1,$S2,$S3,$S4) = map("%zmm$_",(16..24));
++my ($M0,$M1,$M2,$M3,$M4) = map("%zmm$_",(25..29));
++my $PADBIT="%zmm30";
++
++map(s/%y/%z/,($T4,$T0,$T1,$T2,$T3));		# switch to %zmm domain
++map(s/%y/%z/,($D0,$D1,$D2,$D3,$D4));
++map(s/%y/%z/,($H0,$H1,$H2,$H3,$H4));
++map(s/%y/%z/,($MASK));
++
++$code.=<<___;
++.type	poly1305_blocks_avx512,\@function,4
++.align	32
++poly1305_blocks_avx512:
++.cfi_startproc
++.Lblocks_avx512:
++	mov		\$15,%eax
++	kmovw		%eax,%k2
++___
++$code.=<<___	if (!$win64);
++	lea		-8(%rsp),%r11
++.cfi_def_cfa		%r11,16
++	sub		\$0x128,%rsp
++___
++$code.=<<___	if ($win64);
++	lea		-0xf8(%rsp),%r11
++	sub		\$0x1c8,%rsp
++	vmovdqa		%xmm6,0x50(%r11)
++	vmovdqa		%xmm7,0x60(%r11)
++	vmovdqa		%xmm8,0x70(%r11)
++	vmovdqa		%xmm9,0x80(%r11)
++	vmovdqa		%xmm10,0x90(%r11)
++	vmovdqa		%xmm11,0xa0(%r11)
++	vmovdqa		%xmm12,0xb0(%r11)
++	vmovdqa		%xmm13,0xc0(%r11)
++	vmovdqa		%xmm14,0xd0(%r11)
++	vmovdqa		%xmm15,0xe0(%r11)
++.Ldo_avx512_body:
++___
++$code.=<<___;
++	lea		.Lconst(%rip),%rcx
++	lea		48+64($ctx),$ctx	# size optimization
++	vmovdqa		96(%rcx),%y#$T2		# .Lpermd_avx2
++
++	# expand pre-calculated table
++	vmovdqu		`16*0-64`($ctx),%x#$D0	# will become expanded ${R0}
++	and		\$-512,%rsp
++	vmovdqu		`16*1-64`($ctx),%x#$D1	# will become ... ${R1}
++	mov		\$0x20,%rax
++	vmovdqu		`16*2-64`($ctx),%x#$T0	# ... ${S1}
++	vmovdqu		`16*3-64`($ctx),%x#$D2	# ... ${R2}
++	vmovdqu		`16*4-64`($ctx),%x#$T1	# ... ${S2}
++	vmovdqu		`16*5-64`($ctx),%x#$D3	# ... ${R3}
++	vmovdqu		`16*6-64`($ctx),%x#$T3	# ... ${S3}
++	vmovdqu		`16*7-64`($ctx),%x#$D4	# ... ${R4}
++	vmovdqu		`16*8-64`($ctx),%x#$T4	# ... ${S4}
++	vpermd		$D0,$T2,$R0		# 00003412 -> 14243444
++	vpbroadcastq	64(%rcx),$MASK		# .Lmask26
++	vpermd		$D1,$T2,$R1
++	vpermd		$T0,$T2,$S1
++	vpermd		$D2,$T2,$R2
++	vmovdqa64	$R0,0x00(%rsp){%k2}	# save in case $len%128 != 0
++	 vpsrlq		\$32,$R0,$T0		# 14243444 -> 01020304
++	vpermd		$T1,$T2,$S2
++	vmovdqu64	$R1,0x00(%rsp,%rax){%k2}
++	 vpsrlq		\$32,$R1,$T1
++	vpermd		$D3,$T2,$R3
++	vmovdqa64	$S1,0x40(%rsp){%k2}
++	vpermd		$T3,$T2,$S3
++	vpermd		$D4,$T2,$R4
++	vmovdqu64	$R2,0x40(%rsp,%rax){%k2}
++	vpermd		$T4,$T2,$S4
++	vmovdqa64	$S2,0x80(%rsp){%k2}
++	vmovdqu64	$R3,0x80(%rsp,%rax){%k2}
++	vmovdqa64	$S3,0xc0(%rsp){%k2}
++	vmovdqu64	$R4,0xc0(%rsp,%rax){%k2}
++	vmovdqa64	$S4,0x100(%rsp){%k2}
++
++	################################################################
++	# calculate 5th through 8th powers of the key
++	#
++	# d0 = r0'*r0 + r1'*5*r4 + r2'*5*r3 + r3'*5*r2 + r4'*5*r1
++	# d1 = r0'*r1 + r1'*r0   + r2'*5*r4 + r3'*5*r3 + r4'*5*r2
++	# d2 = r0'*r2 + r1'*r1   + r2'*r0   + r3'*5*r4 + r4'*5*r3
++	# d3 = r0'*r3 + r1'*r2   + r2'*r1   + r3'*r0   + r4'*5*r4
++	# d4 = r0'*r4 + r1'*r3   + r2'*r2   + r3'*r1   + r4'*r0
++
++	vpmuludq	$T0,$R0,$D0		# d0 = r0'*r0
++	vpmuludq	$T0,$R1,$D1		# d1 = r0'*r1
++	vpmuludq	$T0,$R2,$D2		# d2 = r0'*r2
++	vpmuludq	$T0,$R3,$D3		# d3 = r0'*r3
++	vpmuludq	$T0,$R4,$D4		# d4 = r0'*r4
++	 vpsrlq		\$32,$R2,$T2
++
++	vpmuludq	$T1,$S4,$M0
++	vpmuludq	$T1,$R0,$M1
++	vpmuludq	$T1,$R1,$M2
++	vpmuludq	$T1,$R2,$M3
++	vpmuludq	$T1,$R3,$M4
++	 vpsrlq		\$32,$R3,$T3
++	vpaddq		$M0,$D0,$D0		# d0 += r1'*5*r4
++	vpaddq		$M1,$D1,$D1		# d1 += r1'*r0
++	vpaddq		$M2,$D2,$D2		# d2 += r1'*r1
++	vpaddq		$M3,$D3,$D3		# d3 += r1'*r2
++	vpaddq		$M4,$D4,$D4		# d4 += r1'*r3
++
++	vpmuludq	$T2,$S3,$M0
++	vpmuludq	$T2,$S4,$M1
++	vpmuludq	$T2,$R1,$M3
++	vpmuludq	$T2,$R2,$M4
++	vpmuludq	$T2,$R0,$M2
++	 vpsrlq		\$32,$R4,$T4
++	vpaddq		$M0,$D0,$D0		# d0 += r2'*5*r3
++	vpaddq		$M1,$D1,$D1		# d1 += r2'*5*r4
++	vpaddq		$M3,$D3,$D3		# d3 += r2'*r1
++	vpaddq		$M4,$D4,$D4		# d4 += r2'*r2
++	vpaddq		$M2,$D2,$D2		# d2 += r2'*r0
++
++	vpmuludq	$T3,$S2,$M0
++	vpmuludq	$T3,$R0,$M3
++	vpmuludq	$T3,$R1,$M4
++	vpmuludq	$T3,$S3,$M1
++	vpmuludq	$T3,$S4,$M2
++	vpaddq		$M0,$D0,$D0		# d0 += r3'*5*r2
++	vpaddq		$M3,$D3,$D3		# d3 += r3'*r0
++	vpaddq		$M4,$D4,$D4		# d4 += r3'*r1
++	vpaddq		$M1,$D1,$D1		# d1 += r3'*5*r3
++	vpaddq		$M2,$D2,$D2		# d2 += r3'*5*r4
++
++	vpmuludq	$T4,$S4,$M3
++	vpmuludq	$T4,$R0,$M4
++	vpmuludq	$T4,$S1,$M0
++	vpmuludq	$T4,$S2,$M1
++	vpmuludq	$T4,$S3,$M2
++	vpaddq		$M3,$D3,$D3		# d3 += r2'*5*r4
++	vpaddq		$M4,$D4,$D4		# d4 += r2'*r0
++	vpaddq		$M0,$D0,$D0		# d0 += r2'*5*r1
++	vpaddq		$M1,$D1,$D1		# d1 += r2'*5*r2
++	vpaddq		$M2,$D2,$D2		# d2 += r2'*5*r3
++
++	################################################################
++	# load input
++	vmovdqu64	16*0($inp),%z#$T3
++	vmovdqu64	16*4($inp),%z#$T4
++	lea		16*8($inp),$inp
++
++	################################################################
++	# lazy reduction
++
++	vpsrlq		\$26,$D3,$M3
++	vpandq		$MASK,$D3,$D3
++	vpaddq		$M3,$D4,$D4		# d3 -> d4
++
++	vpsrlq		\$26,$D0,$M0
++	vpandq		$MASK,$D0,$D0
++	vpaddq		$M0,$D1,$D1		# d0 -> d1
++
++	vpsrlq		\$26,$D4,$M4
++	vpandq		$MASK,$D4,$D4
++
++	vpsrlq		\$26,$D1,$M1
++	vpandq		$MASK,$D1,$D1
++	vpaddq		$M1,$D2,$D2		# d1 -> d2
++
++	vpaddq		$M4,$D0,$D0
++	vpsllq		\$2,$M4,$M4
++	vpaddq		$M4,$D0,$D0		# d4 -> d0
++
++	vpsrlq		\$26,$D2,$M2
++	vpandq		$MASK,$D2,$D2
++	vpaddq		$M2,$D3,$D3		# d2 -> d3
++
++	vpsrlq		\$26,$D0,$M0
++	vpandq		$MASK,$D0,$D0
++	vpaddq		$M0,$D1,$D1		# d0 -> d1
++
++	vpsrlq		\$26,$D3,$M3
++	vpandq		$MASK,$D3,$D3
++	vpaddq		$M3,$D4,$D4		# d3 -> d4
++
++	################################################################
++	# at this point we have 14243444 in $R0-$S4 and 05060708 in
++	# $D0-$D4, ...
++
++	vpunpcklqdq	$T4,$T3,$T0	# transpose input
++	vpunpckhqdq	$T4,$T3,$T4
++
++	# ... since input 64-bit lanes are ordered as 73625140, we could
++	# "vperm" it to 76543210 (here and in each loop iteration), *or*
++	# we could just flow along, hence the goal for $R0-$S4 is
++	# 1858286838784888 ...
++
++	vmovdqa32	128(%rcx),$M0		# .Lpermd_avx512:
++	mov		\$0x7777,%eax
++	kmovw		%eax,%k1
++
++	vpermd		$R0,$M0,$R0		# 14243444 -> 1---2---3---4---
++	vpermd		$R1,$M0,$R1
++	vpermd		$R2,$M0,$R2
++	vpermd		$R3,$M0,$R3
++	vpermd		$R4,$M0,$R4
++
++	vpermd		$D0,$M0,${R0}{%k1}	# 05060708 -> 1858286838784888
++	vpermd		$D1,$M0,${R1}{%k1}
++	vpermd		$D2,$M0,${R2}{%k1}
++	vpermd		$D3,$M0,${R3}{%k1}
++	vpermd		$D4,$M0,${R4}{%k1}
++
++	vpslld		\$2,$R1,$S1		# *5
++	vpslld		\$2,$R2,$S2
++	vpslld		\$2,$R3,$S3
++	vpslld		\$2,$R4,$S4
++	vpaddd		$R1,$S1,$S1
++	vpaddd		$R2,$S2,$S2
++	vpaddd		$R3,$S3,$S3
++	vpaddd		$R4,$S4,$S4
++
++	vpbroadcastq	32(%rcx),$PADBIT	# .L129
++
++	vpsrlq		\$52,$T0,$T2		# splat input
++	vpsllq		\$12,$T4,$T3
++	vporq		$T3,$T2,$T2
++	vpsrlq		\$26,$T0,$T1
++	vpsrlq		\$14,$T4,$T3
++	vpsrlq		\$40,$T4,$T4		# 4
++	vpandq		$MASK,$T2,$T2		# 2
++	vpandq		$MASK,$T0,$T0		# 0
++	#vpandq		$MASK,$T1,$T1		# 1
++	#vpandq		$MASK,$T3,$T3		# 3
++	#vporq		$PADBIT,$T4,$T4		# padbit, yes, always
++
++	vpaddq		$H2,$T2,$H2		# accumulate input
++	sub		\$192,$len
++	jbe		.Ltail_avx512
++	jmp		.Loop_avx512
++
++.align	32
++.Loop_avx512:
++	################################################################
++	# ((inp[0]*r^8+inp[ 8])*r^8+inp[16])*r^8
++	# ((inp[1]*r^8+inp[ 9])*r^8+inp[17])*r^7
++	# ((inp[2]*r^8+inp[10])*r^8+inp[18])*r^6
++	# ((inp[3]*r^8+inp[11])*r^8+inp[19])*r^5
++	# ((inp[4]*r^8+inp[12])*r^8+inp[20])*r^4
++	# ((inp[5]*r^8+inp[13])*r^8+inp[21])*r^3
++	# ((inp[6]*r^8+inp[14])*r^8+inp[22])*r^2
++	# ((inp[7]*r^8+inp[15])*r^8+inp[23])*r^1
++	#   \________/\___________/
++	################################################################
++	#vpaddq		$H2,$T2,$H2		# accumulate input
++
++	# d4 = h4*r0 + h3*r1   + h2*r2   + h1*r3   + h0*r4
++	# d3 = h3*r0 + h2*r1   + h1*r2   + h0*r3   + h4*5*r4
++	# d2 = h2*r0 + h1*r1   + h0*r2   + h4*5*r3 + h3*5*r4
++	# d1 = h1*r0 + h0*r1   + h4*5*r2 + h3*5*r3 + h2*5*r4
++	# d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
++	#
++	# however, as h2 is "chronologically" first one available pull
++	# corresponding operations up, so it's
++	#
++	# d3 = h2*r1   + h0*r3 + h1*r2   + h3*r0 + h4*5*r4
++	# d4 = h2*r2   + h0*r4 + h1*r3   + h3*r1 + h4*r0
++	# d0 = h2*5*r3 + h0*r0 + h1*5*r4         + h3*5*r2 + h4*5*r1
++	# d1 = h2*5*r4 + h0*r1           + h1*r0 + h3*5*r3 + h4*5*r2
++	# d2 = h2*r0           + h0*r2   + h1*r1 + h3*5*r4 + h4*5*r3
++
++	vpmuludq	$H2,$R1,$D3		# d3 = h2*r1
++	 vpaddq		$H0,$T0,$H0
++	vpmuludq	$H2,$R2,$D4		# d4 = h2*r2
++	 vpandq		$MASK,$T1,$T1		# 1
++	vpmuludq	$H2,$S3,$D0		# d0 = h2*s3
++	 vpandq		$MASK,$T3,$T3		# 3
++	vpmuludq	$H2,$S4,$D1		# d1 = h2*s4
++	 vporq		$PADBIT,$T4,$T4		# padbit, yes, always
++	vpmuludq	$H2,$R0,$D2		# d2 = h2*r0
++	 vpaddq		$H1,$T1,$H1		# accumulate input
++	 vpaddq		$H3,$T3,$H3
++	 vpaddq		$H4,$T4,$H4
++
++	  vmovdqu64	16*0($inp),$T3		# load input
++	  vmovdqu64	16*4($inp),$T4
++	  lea		16*8($inp),$inp
++	vpmuludq	$H0,$R3,$M3
++	vpmuludq	$H0,$R4,$M4
++	vpmuludq	$H0,$R0,$M0
++	vpmuludq	$H0,$R1,$M1
++	vpaddq		$M3,$D3,$D3		# d3 += h0*r3
++	vpaddq		$M4,$D4,$D4		# d4 += h0*r4
++	vpaddq		$M0,$D0,$D0		# d0 += h0*r0
++	vpaddq		$M1,$D1,$D1		# d1 += h0*r1
++
++	vpmuludq	$H1,$R2,$M3
++	vpmuludq	$H1,$R3,$M4
++	vpmuludq	$H1,$S4,$M0
++	vpmuludq	$H0,$R2,$M2
++	vpaddq		$M3,$D3,$D3		# d3 += h1*r2
++	vpaddq		$M4,$D4,$D4		# d4 += h1*r3
++	vpaddq		$M0,$D0,$D0		# d0 += h1*s4
++	vpaddq		$M2,$D2,$D2		# d2 += h0*r2
++
++	  vpunpcklqdq	$T4,$T3,$T0		# transpose input
++	  vpunpckhqdq	$T4,$T3,$T4
++
++	vpmuludq	$H3,$R0,$M3
++	vpmuludq	$H3,$R1,$M4
++	vpmuludq	$H1,$R0,$M1
++	vpmuludq	$H1,$R1,$M2
++	vpaddq		$M3,$D3,$D3		# d3 += h3*r0
++	vpaddq		$M4,$D4,$D4		# d4 += h3*r1
++	vpaddq		$M1,$D1,$D1		# d1 += h1*r0
++	vpaddq		$M2,$D2,$D2		# d2 += h1*r1
++
++	vpmuludq	$H4,$S4,$M3
++	vpmuludq	$H4,$R0,$M4
++	vpmuludq	$H3,$S2,$M0
++	vpmuludq	$H3,$S3,$M1
++	vpaddq		$M3,$D3,$D3		# d3 += h4*s4
++	vpmuludq	$H3,$S4,$M2
++	vpaddq		$M4,$D4,$D4		# d4 += h4*r0
++	vpaddq		$M0,$D0,$D0		# d0 += h3*s2
++	vpaddq		$M1,$D1,$D1		# d1 += h3*s3
++	vpaddq		$M2,$D2,$D2		# d2 += h3*s4
++
++	vpmuludq	$H4,$S1,$M0
++	vpmuludq	$H4,$S2,$M1
++	vpmuludq	$H4,$S3,$M2
++	vpaddq		$M0,$D0,$H0		# h0 = d0 + h4*s1
++	vpaddq		$M1,$D1,$H1		# h1 = d2 + h4*s2
++	vpaddq		$M2,$D2,$H2		# h2 = d3 + h4*s3
++
++	################################################################
++	# lazy reduction (interleaved with input splat)
++
++	 vpsrlq		\$52,$T0,$T2		# splat input
++	 vpsllq		\$12,$T4,$T3
++
++	vpsrlq		\$26,$D3,$H3
++	vpandq		$MASK,$D3,$D3
++	vpaddq		$H3,$D4,$H4		# h3 -> h4
++
++	 vporq		$T3,$T2,$T2
++
++	vpsrlq		\$26,$H0,$D0
++	vpandq		$MASK,$H0,$H0
++	vpaddq		$D0,$H1,$H1		# h0 -> h1
++
++	 vpandq		$MASK,$T2,$T2		# 2
++
++	vpsrlq		\$26,$H4,$D4
++	vpandq		$MASK,$H4,$H4
++
++	vpsrlq		\$26,$H1,$D1
++	vpandq		$MASK,$H1,$H1
++	vpaddq		$D1,$H2,$H2		# h1 -> h2
++
++	vpaddq		$D4,$H0,$H0
++	vpsllq		\$2,$D4,$D4
++	vpaddq		$D4,$H0,$H0		# h4 -> h0
++
++	 vpaddq		$T2,$H2,$H2		# modulo-scheduled
++	 vpsrlq		\$26,$T0,$T1
++
++	vpsrlq		\$26,$H2,$D2
++	vpandq		$MASK,$H2,$H2
++	vpaddq		$D2,$D3,$H3		# h2 -> h3
++
++	 vpsrlq		\$14,$T4,$T3
++
++	vpsrlq		\$26,$H0,$D0
++	vpandq		$MASK,$H0,$H0
++	vpaddq		$D0,$H1,$H1		# h0 -> h1
++
++	 vpsrlq		\$40,$T4,$T4		# 4
++
++	vpsrlq		\$26,$H3,$D3
++	vpandq		$MASK,$H3,$H3
++	vpaddq		$D3,$H4,$H4		# h3 -> h4
++
++	 vpandq		$MASK,$T0,$T0		# 0
++	 #vpandq	$MASK,$T1,$T1		# 1
++	 #vpandq	$MASK,$T3,$T3		# 3
++	 #vporq		$PADBIT,$T4,$T4		# padbit, yes, always
++
++	sub		\$128,$len
++	ja		.Loop_avx512
++
++.Ltail_avx512:
++	################################################################
++	# while above multiplications were by r^8 in all lanes, in last
++	# iteration we multiply least significant lane by r^8 and most
++	# significant one by r, that's why table gets shifted...
++
++	vpsrlq		\$32,$R0,$R0		# 0105020603070408
++	vpsrlq		\$32,$R1,$R1
++	vpsrlq		\$32,$R2,$R2
++	vpsrlq		\$32,$S3,$S3
++	vpsrlq		\$32,$S4,$S4
++	vpsrlq		\$32,$R3,$R3
++	vpsrlq		\$32,$R4,$R4
++	vpsrlq		\$32,$S1,$S1
++	vpsrlq		\$32,$S2,$S2
++
++	################################################################
++	# load either next or last 64 byte of input
++	lea		($inp,$len),$inp
++
++	#vpaddq		$H2,$T2,$H2		# accumulate input
++	vpaddq		$H0,$T0,$H0
++
++	vpmuludq	$H2,$R1,$D3		# d3 = h2*r1
++	vpmuludq	$H2,$R2,$D4		# d4 = h2*r2
++	vpmuludq	$H2,$S3,$D0		# d0 = h2*s3
++	 vpandq		$MASK,$T1,$T1		# 1
++	vpmuludq	$H2,$S4,$D1		# d1 = h2*s4
++	 vpandq		$MASK,$T3,$T3		# 3
++	vpmuludq	$H2,$R0,$D2		# d2 = h2*r0
++	 vporq		$PADBIT,$T4,$T4		# padbit, yes, always
++	 vpaddq		$H1,$T1,$H1		# accumulate input
++	 vpaddq		$H3,$T3,$H3
++	 vpaddq		$H4,$T4,$H4
++
++	  vmovdqu	16*0($inp),%x#$T0
++	vpmuludq	$H0,$R3,$M3
++	vpmuludq	$H0,$R4,$M4
++	vpmuludq	$H0,$R0,$M0
++	vpmuludq	$H0,$R1,$M1
++	vpaddq		$M3,$D3,$D3		# d3 += h0*r3
++	vpaddq		$M4,$D4,$D4		# d4 += h0*r4
++	vpaddq		$M0,$D0,$D0		# d0 += h0*r0
++	vpaddq		$M1,$D1,$D1		# d1 += h0*r1
++
++	  vmovdqu	16*1($inp),%x#$T1
++	vpmuludq	$H1,$R2,$M3
++	vpmuludq	$H1,$R3,$M4
++	vpmuludq	$H1,$S4,$M0
++	vpmuludq	$H0,$R2,$M2
++	vpaddq		$M3,$D3,$D3		# d3 += h1*r2
++	vpaddq		$M4,$D4,$D4		# d4 += h1*r3
++	vpaddq		$M0,$D0,$D0		# d0 += h1*s4
++	vpaddq		$M2,$D2,$D2		# d2 += h0*r2
++
++	  vinserti128	\$1,16*2($inp),%y#$T0,%y#$T0
++	vpmuludq	$H3,$R0,$M3
++	vpmuludq	$H3,$R1,$M4
++	vpmuludq	$H1,$R0,$M1
++	vpmuludq	$H1,$R1,$M2
++	vpaddq		$M3,$D3,$D3		# d3 += h3*r0
++	vpaddq		$M4,$D4,$D4		# d4 += h3*r1
++	vpaddq		$M1,$D1,$D1		# d1 += h1*r0
++	vpaddq		$M2,$D2,$D2		# d2 += h1*r1
++
++	  vinserti128	\$1,16*3($inp),%y#$T1,%y#$T1
++	vpmuludq	$H4,$S4,$M3
++	vpmuludq	$H4,$R0,$M4
++	vpmuludq	$H3,$S2,$M0
++	vpmuludq	$H3,$S3,$M1
++	vpmuludq	$H3,$S4,$M2
++	vpaddq		$M3,$D3,$H3		# h3 = d3 + h4*s4
++	vpaddq		$M4,$D4,$D4		# d4 += h4*r0
++	vpaddq		$M0,$D0,$D0		# d0 += h3*s2
++	vpaddq		$M1,$D1,$D1		# d1 += h3*s3
++	vpaddq		$M2,$D2,$D2		# d2 += h3*s4
++
++	vpmuludq	$H4,$S1,$M0
++	vpmuludq	$H4,$S2,$M1
++	vpmuludq	$H4,$S3,$M2
++	vpaddq		$M0,$D0,$H0		# h0 = d0 + h4*s1
++	vpaddq		$M1,$D1,$H1		# h1 = d2 + h4*s2
++	vpaddq		$M2,$D2,$H2		# h2 = d3 + h4*s3
++
++	################################################################
++	# horizontal addition
++
++	mov		\$1,%eax
++	vpermq		\$0xb1,$H3,$D3
++	vpermq		\$0xb1,$D4,$H4
++	vpermq		\$0xb1,$H0,$D0
++	vpermq		\$0xb1,$H1,$D1
++	vpermq		\$0xb1,$H2,$D2
++	vpaddq		$D3,$H3,$H3
++	vpaddq		$D4,$H4,$H4
++	vpaddq		$D0,$H0,$H0
++	vpaddq		$D1,$H1,$H1
++	vpaddq		$D2,$H2,$H2
++
++	kmovw		%eax,%k3
++	vpermq		\$0x2,$H3,$D3
++	vpermq		\$0x2,$H4,$D4
++	vpermq		\$0x2,$H0,$D0
++	vpermq		\$0x2,$H1,$D1
++	vpermq		\$0x2,$H2,$D2
++	vpaddq		$D3,$H3,$H3
++	vpaddq		$D4,$H4,$H4
++	vpaddq		$D0,$H0,$H0
++	vpaddq		$D1,$H1,$H1
++	vpaddq		$D2,$H2,$H2
++
++	vextracti64x4	\$0x1,$H3,%y#$D3
++	vextracti64x4	\$0x1,$H4,%y#$D4
++	vextracti64x4	\$0x1,$H0,%y#$D0
++	vextracti64x4	\$0x1,$H1,%y#$D1
++	vextracti64x4	\$0x1,$H2,%y#$D2
++	vpaddq		$D3,$H3,${H3}{%k3}{z}	# keep single qword in case
++	vpaddq		$D4,$H4,${H4}{%k3}{z}	# it's passed to .Ltail_avx2
++	vpaddq		$D0,$H0,${H0}{%k3}{z}
++	vpaddq		$D1,$H1,${H1}{%k3}{z}
++	vpaddq		$D2,$H2,${H2}{%k3}{z}
++___
++map(s/%z/%y/,($T0,$T1,$T2,$T3,$T4, $PADBIT));
++map(s/%z/%y/,($H0,$H1,$H2,$H3,$H4, $D0,$D1,$D2,$D3,$D4, $MASK));
++$code.=<<___;
++	################################################################
++	# lazy reduction (interleaved with input splat)
++
++	vpsrlq		\$26,$H3,$D3
++	vpand		$MASK,$H3,$H3
++	 vpsrldq	\$6,$T0,$T2		# splat input
++	 vpsrldq	\$6,$T1,$T3
++	 vpunpckhqdq	$T1,$T0,$T4		# 4
++	vpaddq		$D3,$H4,$H4		# h3 -> h4
++
++	vpsrlq		\$26,$H0,$D0
++	vpand		$MASK,$H0,$H0
++	 vpunpcklqdq	$T3,$T2,$T2		# 2:3
++	 vpunpcklqdq	$T1,$T0,$T0		# 0:1
++	vpaddq		$D0,$H1,$H1		# h0 -> h1
++
++	vpsrlq		\$26,$H4,$D4
++	vpand		$MASK,$H4,$H4
++
++	vpsrlq		\$26,$H1,$D1
++	vpand		$MASK,$H1,$H1
++	 vpsrlq		\$30,$T2,$T3
++	 vpsrlq		\$4,$T2,$T2
++	vpaddq		$D1,$H2,$H2		# h1 -> h2
++
++	vpaddq		$D4,$H0,$H0
++	vpsllq		\$2,$D4,$D4
++	 vpsrlq		\$26,$T0,$T1
++	 vpsrlq		\$40,$T4,$T4		# 4
++	vpaddq		$D4,$H0,$H0		# h4 -> h0
++
++	vpsrlq		\$26,$H2,$D2
++	vpand		$MASK,$H2,$H2
++	 vpand		$MASK,$T2,$T2		# 2
++	 vpand		$MASK,$T0,$T0		# 0
++	vpaddq		$D2,$H3,$H3		# h2 -> h3
++
++	vpsrlq		\$26,$H0,$D0
++	vpand		$MASK,$H0,$H0
++	 vpaddq		$H2,$T2,$H2		# accumulate input for .Ltail_avx2
++	 vpand		$MASK,$T1,$T1		# 1
++	vpaddq		$D0,$H1,$H1		# h0 -> h1
++
++	vpsrlq		\$26,$H3,$D3
++	vpand		$MASK,$H3,$H3
++	 vpand		$MASK,$T3,$T3		# 3
++	 vpor		32(%rcx),$T4,$T4	# padbit, yes, always
++	vpaddq		$D3,$H4,$H4		# h3 -> h4
++
++	lea		0x90(%rsp),%rax		# size optimization for .Ltail_avx2
++	add		\$64,$len
++	jnz		.Ltail_avx2
++
++	vpsubq		$T2,$H2,$H2		# undo input accumulation
++	vmovd		%x#$H0,`4*0-48-64`($ctx)# save partially reduced
++	vmovd		%x#$H1,`4*1-48-64`($ctx)
++	vmovd		%x#$H2,`4*2-48-64`($ctx)
++	vmovd		%x#$H3,`4*3-48-64`($ctx)
++	vmovd		%x#$H4,`4*4-48-64`($ctx)
++	vzeroall
++___
++$code.=<<___	if ($win64);
++	movdqa		0x50(%r11),%xmm6
++	movdqa		0x60(%r11),%xmm7
++	movdqa		0x70(%r11),%xmm8
++	movdqa		0x80(%r11),%xmm9
++	movdqa		0x90(%r11),%xmm10
++	movdqa		0xa0(%r11),%xmm11
++	movdqa		0xb0(%r11),%xmm12
++	movdqa		0xc0(%r11),%xmm13
++	movdqa		0xd0(%r11),%xmm14
++	movdqa		0xe0(%r11),%xmm15
++	lea		0xf8(%r11),%rsp
++.Ldo_avx512_epilogue:
++___
++$code.=<<___	if (!$win64);
++	lea		8(%r11),%rsp
++.cfi_def_cfa		%rsp,8
++___
++$code.=<<___;
++	ret
++.cfi_endproc
++.size	poly1305_blocks_avx512,.-poly1305_blocks_avx512
++___
++if ($avx>3) {
++########################################################################
++# VPMADD52 version using 2^44 radix.
++#
++# One can argue that base 2^52 would be more natural. Well, even though
++# some operations would be more natural, one has to recognize couple of
++# things. Base 2^52 doesn't provide advantage over base 2^44 if you look
++# at amount of multiply-n-accumulate operations. Secondly, it makes it
++# impossible to pre-compute multiples of 5 [referred to as s[]/sN in
++# reference implementations], which means that more such operations
++# would have to be performed in inner loop, which in turn makes critical
++# path longer. In other words, even though base 2^44 reduction might
++# look less elegant, overall critical path is actually shorter...
++
++########################################################################
++# Layout of opaque area is following.
++#
++#	unsigned __int64 h[3];		# current hash value base 2^44
++#	unsigned __int64 s[2];		# key value*20 base 2^44
++#	unsigned __int64 r[3];		# key value base 2^44
++#	struct { unsigned __int64 r^1, r^3, r^2, r^4; } R[4];
++#					# r^n positions reflect
++#					# placement in register, not
++#					# memory, R[3] is R[1]*20
++
++$code.=<<___;
++.type	poly1305_init_base2_44,\@function,3
++.align	32
++poly1305_init_base2_44:
++	xor	%rax,%rax
++	mov	%rax,0($ctx)		# initialize hash value
++	mov	%rax,8($ctx)
++	mov	%rax,16($ctx)
++
++.Linit_base2_44:
++	lea	poly1305_blocks_vpmadd52(%rip),%r10
++	lea	poly1305_emit_base2_44(%rip),%r11
++
++	mov	\$0x0ffffffc0fffffff,%rax
++	mov	\$0x0ffffffc0ffffffc,%rcx
++	and	0($inp),%rax
++	mov	\$0x00000fffffffffff,%r8
++	and	8($inp),%rcx
++	mov	\$0x00000fffffffffff,%r9
++	and	%rax,%r8
++	shrd	\$44,%rcx,%rax
++	mov	%r8,40($ctx)		# r0
++	and	%r9,%rax
++	shr	\$24,%rcx
++	mov	%rax,48($ctx)		# r1
++	lea	(%rax,%rax,4),%rax	# *5
++	mov	%rcx,56($ctx)		# r2
++	shl	\$2,%rax		# magic <<2
++	lea	(%rcx,%rcx,4),%rcx	# *5
++	shl	\$2,%rcx		# magic <<2
++	mov	%rax,24($ctx)		# s1
++	mov	%rcx,32($ctx)		# s2
++	movq	\$-1,64($ctx)		# write impossible value
++___
++$code.=<<___	if ($flavour !~ /elf32/);
++	mov	%r10,0(%rdx)
++	mov	%r11,8(%rdx)
++___
++$code.=<<___	if ($flavour =~ /elf32/);
++	mov	%r10d,0(%rdx)
++	mov	%r11d,4(%rdx)
++___
++$code.=<<___;
++	mov	\$1,%eax
++	ret
++.size	poly1305_init_base2_44,.-poly1305_init_base2_44
++___
++{
++my ($H0,$H1,$H2,$r2r1r0,$r1r0s2,$r0s2s1,$Dlo,$Dhi) = map("%ymm$_",(0..5,16,17));
++my ($T0,$inp_permd,$inp_shift,$PAD) = map("%ymm$_",(18..21));
++my ($reduc_mask,$reduc_rght,$reduc_left) = map("%ymm$_",(22..25));
++
++$code.=<<___;
++.type	poly1305_blocks_vpmadd52,\@function,4
++.align	32
++poly1305_blocks_vpmadd52:
++	shr	\$4,$len
++	jz	.Lno_data_vpmadd52		# too short
++
++	shl	\$40,$padbit
++	mov	64($ctx),%r8			# peek on power of the key
++
++	# if powers of the key are not calculated yet, process up to 3
++	# blocks with this single-block subroutine, otherwise ensure that
++	# length is divisible by 2 blocks and pass the rest down to next
++	# subroutine...
++
++	mov	\$3,%rax
++	mov	\$1,%r10
++	cmp	\$4,$len			# is input long
++	cmovae	%r10,%rax
++	test	%r8,%r8				# is power value impossible?
++	cmovns	%r10,%rax
++
++	and	$len,%rax			# is input of favourable length?
++	jz	.Lblocks_vpmadd52_4x
++
++	sub		%rax,$len
++	mov		\$7,%r10d
++	mov		\$1,%r11d
++	kmovw		%r10d,%k7
++	lea		.L2_44_inp_permd(%rip),%r10
++	kmovw		%r11d,%k1
++
++	vmovq		$padbit,%x#$PAD
++	vmovdqa64	0(%r10),$inp_permd	# .L2_44_inp_permd
++	vmovdqa64	32(%r10),$inp_shift	# .L2_44_inp_shift
++	vpermq		\$0xcf,$PAD,$PAD
++	vmovdqa64	64(%r10),$reduc_mask	# .L2_44_mask
++
++	vmovdqu64	0($ctx),${Dlo}{%k7}{z}		# load hash value
++	vmovdqu64	40($ctx),${r2r1r0}{%k7}{z}	# load keys
++	vmovdqu64	32($ctx),${r1r0s2}{%k7}{z}
++	vmovdqu64	24($ctx),${r0s2s1}{%k7}{z}
++
++	vmovdqa64	96(%r10),$reduc_rght	# .L2_44_shift_rgt
++	vmovdqa64	128(%r10),$reduc_left	# .L2_44_shift_lft
++
++	jmp		.Loop_vpmadd52
++
++.align	32
++.Loop_vpmadd52:
++	vmovdqu32	0($inp),%x#$T0		# load input as ----3210
++	lea		16($inp),$inp
++
++	vpermd		$T0,$inp_permd,$T0	# ----3210 -> --322110
++	vpsrlvq		$inp_shift,$T0,$T0
++	vpandq		$reduc_mask,$T0,$T0
++	vporq		$PAD,$T0,$T0
++
++	vpaddq		$T0,$Dlo,$Dlo		# accumulate input
++
++	vpermq		\$0,$Dlo,${H0}{%k7}{z}	# smash hash value
++	vpermq		\$0b01010101,$Dlo,${H1}{%k7}{z}
++	vpermq		\$0b10101010,$Dlo,${H2}{%k7}{z}
++
++	vpxord		$Dlo,$Dlo,$Dlo
++	vpxord		$Dhi,$Dhi,$Dhi
++
++	vpmadd52luq	$r2r1r0,$H0,$Dlo
++	vpmadd52huq	$r2r1r0,$H0,$Dhi
++
++	vpmadd52luq	$r1r0s2,$H1,$Dlo
++	vpmadd52huq	$r1r0s2,$H1,$Dhi
++
++	vpmadd52luq	$r0s2s1,$H2,$Dlo
++	vpmadd52huq	$r0s2s1,$H2,$Dhi
++
++	vpsrlvq		$reduc_rght,$Dlo,$T0	# 0 in topmost qword
++	vpsllvq		$reduc_left,$Dhi,$Dhi	# 0 in topmost qword
++	vpandq		$reduc_mask,$Dlo,$Dlo
++
++	vpaddq		$T0,$Dhi,$Dhi
++
++	vpermq		\$0b10010011,$Dhi,$Dhi	# 0 in lowest qword
++
++	vpaddq		$Dhi,$Dlo,$Dlo		# note topmost qword :-)
++
++	vpsrlvq		$reduc_rght,$Dlo,$T0	# 0 in topmost word
++	vpandq		$reduc_mask,$Dlo,$Dlo
++
++	vpermq		\$0b10010011,$T0,$T0
++
++	vpaddq		$T0,$Dlo,$Dlo
++
++	vpermq		\$0b10010011,$Dlo,${T0}{%k1}{z}
++
++	vpaddq		$T0,$Dlo,$Dlo
++	vpsllq		\$2,$T0,$T0
++
++	vpaddq		$T0,$Dlo,$Dlo
++
++	dec		%rax			# len-=16
++	jnz		.Loop_vpmadd52
++
++	vmovdqu64	$Dlo,0($ctx){%k7}	# store hash value
++
++	test		$len,$len
++	jnz		.Lblocks_vpmadd52_4x
++
++.Lno_data_vpmadd52:
++	ret
++.size	poly1305_blocks_vpmadd52,.-poly1305_blocks_vpmadd52
++___
++}
++{
++########################################################################
++# As implied by its name 4x subroutine processes 4 blocks in parallel
++# (but handles even 4*n+2 blocks lengths). It takes up to 4th key power
++# and is handled in 256-bit %ymm registers.
++
++my ($H0,$H1,$H2,$R0,$R1,$R2,$S1,$S2) = map("%ymm$_",(0..5,16,17));
++my ($D0lo,$D0hi,$D1lo,$D1hi,$D2lo,$D2hi) = map("%ymm$_",(18..23));
++my ($T0,$T1,$T2,$T3,$mask44,$mask42,$tmp,$PAD) = map("%ymm$_",(24..31));
++
++$code.=<<___;
++.type	poly1305_blocks_vpmadd52_4x,\@function,4
++.align	32
++poly1305_blocks_vpmadd52_4x:
++	shr	\$4,$len
++	jz	.Lno_data_vpmadd52_4x		# too short
++
++	shl	\$40,$padbit
++	mov	64($ctx),%r8			# peek on power of the key
++
++.Lblocks_vpmadd52_4x:
++	vpbroadcastq	$padbit,$PAD
++
++	vmovdqa64	.Lx_mask44(%rip),$mask44
++	mov		\$5,%eax
++	vmovdqa64	.Lx_mask42(%rip),$mask42
++	kmovw		%eax,%k1		# used in 2x path
++
++	test		%r8,%r8			# is power value impossible?
++	js		.Linit_vpmadd52		# if it is, then init R[4]
++
++	vmovq		0($ctx),%x#$H0		# load current hash value
++	vmovq		8($ctx),%x#$H1
++	vmovq		16($ctx),%x#$H2
++
++	test		\$3,$len		# is length 4*n+2?
++	jnz		.Lblocks_vpmadd52_2x_do
++
++.Lblocks_vpmadd52_4x_do:
++	vpbroadcastq	64($ctx),$R0		# load 4th power of the key
++	vpbroadcastq	96($ctx),$R1
++	vpbroadcastq	128($ctx),$R2
++	vpbroadcastq	160($ctx),$S1
++
++.Lblocks_vpmadd52_4x_key_loaded:
++	vpsllq		\$2,$R2,$S2		# S2 = R2*5*4
++	vpaddq		$R2,$S2,$S2
++	vpsllq		\$2,$S2,$S2
++
++	test		\$7,$len		# is len 8*n?
++	jz		.Lblocks_vpmadd52_8x
++
++	vmovdqu64	16*0($inp),$T2		# load data
++	vmovdqu64	16*2($inp),$T3
++	lea		16*4($inp),$inp
++
++	vpunpcklqdq	$T3,$T2,$T1		# transpose data
++	vpunpckhqdq	$T3,$T2,$T3
++
++	# at this point 64-bit lanes are ordered as 3-1-2-0
++
++	vpsrlq		\$24,$T3,$T2		# splat the data
++	vporq		$PAD,$T2,$T2
++	 vpaddq		$T2,$H2,$H2		# accumulate input
++	vpandq		$mask44,$T1,$T0
++	vpsrlq		\$44,$T1,$T1
++	vpsllq		\$20,$T3,$T3
++	vporq		$T3,$T1,$T1
++	vpandq		$mask44,$T1,$T1
++
++	sub		\$4,$len
++	jz		.Ltail_vpmadd52_4x
++	jmp		.Loop_vpmadd52_4x
++	ud2
++
++.align	32
++.Linit_vpmadd52:
++	vmovq		24($ctx),%x#$S1		# load key
++	vmovq		56($ctx),%x#$H2
++	vmovq		32($ctx),%x#$S2
++	vmovq		40($ctx),%x#$R0
++	vmovq		48($ctx),%x#$R1
++
++	vmovdqa		$R0,$H0
++	vmovdqa		$R1,$H1
++	vmovdqa		$H2,$R2
++
++	mov		\$2,%eax
++
++.Lmul_init_vpmadd52:
++	vpxorq		$D0lo,$D0lo,$D0lo
++	vpmadd52luq	$H2,$S1,$D0lo
++	vpxorq		$D0hi,$D0hi,$D0hi
++	vpmadd52huq	$H2,$S1,$D0hi
++	vpxorq		$D1lo,$D1lo,$D1lo
++	vpmadd52luq	$H2,$S2,$D1lo
++	vpxorq		$D1hi,$D1hi,$D1hi
++	vpmadd52huq	$H2,$S2,$D1hi
++	vpxorq		$D2lo,$D2lo,$D2lo
++	vpmadd52luq	$H2,$R0,$D2lo
++	vpxorq		$D2hi,$D2hi,$D2hi
++	vpmadd52huq	$H2,$R0,$D2hi
++
++	vpmadd52luq	$H0,$R0,$D0lo
++	vpmadd52huq	$H0,$R0,$D0hi
++	vpmadd52luq	$H0,$R1,$D1lo
++	vpmadd52huq	$H0,$R1,$D1hi
++	vpmadd52luq	$H0,$R2,$D2lo
++	vpmadd52huq	$H0,$R2,$D2hi
++
++	vpmadd52luq	$H1,$S2,$D0lo
++	vpmadd52huq	$H1,$S2,$D0hi
++	vpmadd52luq	$H1,$R0,$D1lo
++	vpmadd52huq	$H1,$R0,$D1hi
++	vpmadd52luq	$H1,$R1,$D2lo
++	vpmadd52huq	$H1,$R1,$D2hi
++
++	################################################################
++	# partial reduction
++	vpsrlq		\$44,$D0lo,$tmp
++	vpsllq		\$8,$D0hi,$D0hi
++	vpandq		$mask44,$D0lo,$H0
++	vpaddq		$tmp,$D0hi,$D0hi
++
++	vpaddq		$D0hi,$D1lo,$D1lo
++
++	vpsrlq		\$44,$D1lo,$tmp
++	vpsllq		\$8,$D1hi,$D1hi
++	vpandq		$mask44,$D1lo,$H1
++	vpaddq		$tmp,$D1hi,$D1hi
++
++	vpaddq		$D1hi,$D2lo,$D2lo
++
++	vpsrlq		\$42,$D2lo,$tmp
++	vpsllq		\$10,$D2hi,$D2hi
++	vpandq		$mask42,$D2lo,$H2
++	vpaddq		$tmp,$D2hi,$D2hi
++
++	vpaddq		$D2hi,$H0,$H0
++	vpsllq		\$2,$D2hi,$D2hi
++
++	vpaddq		$D2hi,$H0,$H0
++
++	vpsrlq		\$44,$H0,$tmp		# additional step
++	vpandq		$mask44,$H0,$H0
++
++	vpaddq		$tmp,$H1,$H1
++
++	dec		%eax
++	jz		.Ldone_init_vpmadd52
++
++	vpunpcklqdq	$R1,$H1,$R1		# 1,2
++	vpbroadcastq	%x#$H1,%x#$H1		# 2,2
++	vpunpcklqdq	$R2,$H2,$R2
++	vpbroadcastq	%x#$H2,%x#$H2
++	vpunpcklqdq	$R0,$H0,$R0
++	vpbroadcastq	%x#$H0,%x#$H0
++
++	vpsllq		\$2,$R1,$S1		# S1 = R1*5*4
++	vpsllq		\$2,$R2,$S2		# S2 = R2*5*4
++	vpaddq		$R1,$S1,$S1
++	vpaddq		$R2,$S2,$S2
++	vpsllq		\$2,$S1,$S1
++	vpsllq		\$2,$S2,$S2
++
++	jmp		.Lmul_init_vpmadd52
++	ud2
++
++.align	32
++.Ldone_init_vpmadd52:
++	vinserti128	\$1,%x#$R1,$H1,$R1	# 1,2,3,4
++	vinserti128	\$1,%x#$R2,$H2,$R2
++	vinserti128	\$1,%x#$R0,$H0,$R0
++
++	vpermq		\$0b11011000,$R1,$R1	# 1,3,2,4
++	vpermq		\$0b11011000,$R2,$R2
++	vpermq		\$0b11011000,$R0,$R0
++
++	vpsllq		\$2,$R1,$S1		# S1 = R1*5*4
++	vpaddq		$R1,$S1,$S1
++	vpsllq		\$2,$S1,$S1
++
++	vmovq		0($ctx),%x#$H0		# load current hash value
++	vmovq		8($ctx),%x#$H1
++	vmovq		16($ctx),%x#$H2
++
++	test		\$3,$len		# is length 4*n+2?
++	jnz		.Ldone_init_vpmadd52_2x
++
++	vmovdqu64	$R0,64($ctx)		# save key powers
++	vpbroadcastq	%x#$R0,$R0		# broadcast 4th power
++	vmovdqu64	$R1,96($ctx)
++	vpbroadcastq	%x#$R1,$R1
++	vmovdqu64	$R2,128($ctx)
++	vpbroadcastq	%x#$R2,$R2
++	vmovdqu64	$S1,160($ctx)
++	vpbroadcastq	%x#$S1,$S1
++
++	jmp		.Lblocks_vpmadd52_4x_key_loaded
++	ud2
++
++.align	32
++.Ldone_init_vpmadd52_2x:
++	vmovdqu64	$R0,64($ctx)		# save key powers
++	vpsrldq		\$8,$R0,$R0		# 0-1-0-2
++	vmovdqu64	$R1,96($ctx)
++	vpsrldq		\$8,$R1,$R1
++	vmovdqu64	$R2,128($ctx)
++	vpsrldq		\$8,$R2,$R2
++	vmovdqu64	$S1,160($ctx)
++	vpsrldq		\$8,$S1,$S1
++	jmp		.Lblocks_vpmadd52_2x_key_loaded
++	ud2
++
++.align	32
++.Lblocks_vpmadd52_2x_do:
++	vmovdqu64	128+8($ctx),${R2}{%k1}{z}# load 2nd and 1st key powers
++	vmovdqu64	160+8($ctx),${S1}{%k1}{z}
++	vmovdqu64	64+8($ctx),${R0}{%k1}{z}
++	vmovdqu64	96+8($ctx),${R1}{%k1}{z}
++
++.Lblocks_vpmadd52_2x_key_loaded:
++	vmovdqu64	16*0($inp),$T2		# load data
++	vpxorq		$T3,$T3,$T3
++	lea		16*2($inp),$inp
++
++	vpunpcklqdq	$T3,$T2,$T1		# transpose data
++	vpunpckhqdq	$T3,$T2,$T3
++
++	# at this point 64-bit lanes are ordered as x-1-x-0
++
++	vpsrlq		\$24,$T3,$T2		# splat the data
++	vporq		$PAD,$T2,$T2
++	 vpaddq		$T2,$H2,$H2		# accumulate input
++	vpandq		$mask44,$T1,$T0
++	vpsrlq		\$44,$T1,$T1
++	vpsllq		\$20,$T3,$T3
++	vporq		$T3,$T1,$T1
++	vpandq		$mask44,$T1,$T1
++
++	jmp		.Ltail_vpmadd52_2x
++	ud2
++
++.align	32
++.Loop_vpmadd52_4x:
++	#vpaddq		$T2,$H2,$H2		# accumulate input
++	vpaddq		$T0,$H0,$H0
++	vpaddq		$T1,$H1,$H1
++
++	vpxorq		$D0lo,$D0lo,$D0lo
++	vpmadd52luq	$H2,$S1,$D0lo
++	vpxorq		$D0hi,$D0hi,$D0hi
++	vpmadd52huq	$H2,$S1,$D0hi
++	vpxorq		$D1lo,$D1lo,$D1lo
++	vpmadd52luq	$H2,$S2,$D1lo
++	vpxorq		$D1hi,$D1hi,$D1hi
++	vpmadd52huq	$H2,$S2,$D1hi
++	vpxorq		$D2lo,$D2lo,$D2lo
++	vpmadd52luq	$H2,$R0,$D2lo
++	vpxorq		$D2hi,$D2hi,$D2hi
++	vpmadd52huq	$H2,$R0,$D2hi
++
++	 vmovdqu64	16*0($inp),$T2		# load data
++	 vmovdqu64	16*2($inp),$T3
++	 lea		16*4($inp),$inp
++	vpmadd52luq	$H0,$R0,$D0lo
++	vpmadd52huq	$H0,$R0,$D0hi
++	vpmadd52luq	$H0,$R1,$D1lo
++	vpmadd52huq	$H0,$R1,$D1hi
++	vpmadd52luq	$H0,$R2,$D2lo
++	vpmadd52huq	$H0,$R2,$D2hi
++
++	 vpunpcklqdq	$T3,$T2,$T1		# transpose data
++	 vpunpckhqdq	$T3,$T2,$T3
++	vpmadd52luq	$H1,$S2,$D0lo
++	vpmadd52huq	$H1,$S2,$D0hi
++	vpmadd52luq	$H1,$R0,$D1lo
++	vpmadd52huq	$H1,$R0,$D1hi
++	vpmadd52luq	$H1,$R1,$D2lo
++	vpmadd52huq	$H1,$R1,$D2hi
++
++	################################################################
++	# partial reduction (interleaved with data splat)
++	vpsrlq		\$44,$D0lo,$tmp
++	vpsllq		\$8,$D0hi,$D0hi
++	vpandq		$mask44,$D0lo,$H0
++	vpaddq		$tmp,$D0hi,$D0hi
++
++	 vpsrlq		\$24,$T3,$T2
++	 vporq		$PAD,$T2,$T2
++	vpaddq		$D0hi,$D1lo,$D1lo
++
++	vpsrlq		\$44,$D1lo,$tmp
++	vpsllq		\$8,$D1hi,$D1hi
++	vpandq		$mask44,$D1lo,$H1
++	vpaddq		$tmp,$D1hi,$D1hi
++
++	 vpandq		$mask44,$T1,$T0
++	 vpsrlq		\$44,$T1,$T1
++	 vpsllq		\$20,$T3,$T3
++	vpaddq		$D1hi,$D2lo,$D2lo
++
++	vpsrlq		\$42,$D2lo,$tmp
++	vpsllq		\$10,$D2hi,$D2hi
++	vpandq		$mask42,$D2lo,$H2
++	vpaddq		$tmp,$D2hi,$D2hi
++
++	  vpaddq	$T2,$H2,$H2		# accumulate input
++	vpaddq		$D2hi,$H0,$H0
++	vpsllq		\$2,$D2hi,$D2hi
++
++	vpaddq		$D2hi,$H0,$H0
++	 vporq		$T3,$T1,$T1
++	 vpandq		$mask44,$T1,$T1
++
++	vpsrlq		\$44,$H0,$tmp		# additional step
++	vpandq		$mask44,$H0,$H0
++
++	vpaddq		$tmp,$H1,$H1
++
++	sub		\$4,$len		# len-=64
++	jnz		.Loop_vpmadd52_4x
++
++.Ltail_vpmadd52_4x:
++	vmovdqu64	128($ctx),$R2		# load all key powers
++	vmovdqu64	160($ctx),$S1
++	vmovdqu64	64($ctx),$R0
++	vmovdqu64	96($ctx),$R1
++
++.Ltail_vpmadd52_2x:
++	vpsllq		\$2,$R2,$S2		# S2 = R2*5*4
++	vpaddq		$R2,$S2,$S2
++	vpsllq		\$2,$S2,$S2
++
++	#vpaddq		$T2,$H2,$H2		# accumulate input
++	vpaddq		$T0,$H0,$H0
++	vpaddq		$T1,$H1,$H1
++
++	vpxorq		$D0lo,$D0lo,$D0lo
++	vpmadd52luq	$H2,$S1,$D0lo
++	vpxorq		$D0hi,$D0hi,$D0hi
++	vpmadd52huq	$H2,$S1,$D0hi
++	vpxorq		$D1lo,$D1lo,$D1lo
++	vpmadd52luq	$H2,$S2,$D1lo
++	vpxorq		$D1hi,$D1hi,$D1hi
++	vpmadd52huq	$H2,$S2,$D1hi
++	vpxorq		$D2lo,$D2lo,$D2lo
++	vpmadd52luq	$H2,$R0,$D2lo
++	vpxorq		$D2hi,$D2hi,$D2hi
++	vpmadd52huq	$H2,$R0,$D2hi
++
++	vpmadd52luq	$H0,$R0,$D0lo
++	vpmadd52huq	$H0,$R0,$D0hi
++	vpmadd52luq	$H0,$R1,$D1lo
++	vpmadd52huq	$H0,$R1,$D1hi
++	vpmadd52luq	$H0,$R2,$D2lo
++	vpmadd52huq	$H0,$R2,$D2hi
++
++	vpmadd52luq	$H1,$S2,$D0lo
++	vpmadd52huq	$H1,$S2,$D0hi
++	vpmadd52luq	$H1,$R0,$D1lo
++	vpmadd52huq	$H1,$R0,$D1hi
++	vpmadd52luq	$H1,$R1,$D2lo
++	vpmadd52huq	$H1,$R1,$D2hi
++
++	################################################################
++	# horizontal addition
++
++	mov		\$1,%eax
++	kmovw		%eax,%k1
++	vpsrldq		\$8,$D0lo,$T0
++	vpsrldq		\$8,$D0hi,$H0
++	vpsrldq		\$8,$D1lo,$T1
++	vpsrldq		\$8,$D1hi,$H1
++	vpaddq		$T0,$D0lo,$D0lo
++	vpaddq		$H0,$D0hi,$D0hi
++	vpsrldq		\$8,$D2lo,$T2
++	vpsrldq		\$8,$D2hi,$H2
++	vpaddq		$T1,$D1lo,$D1lo
++	vpaddq		$H1,$D1hi,$D1hi
++	 vpermq		\$0x2,$D0lo,$T0
++	 vpermq		\$0x2,$D0hi,$H0
++	vpaddq		$T2,$D2lo,$D2lo
++	vpaddq		$H2,$D2hi,$D2hi
++
++	vpermq		\$0x2,$D1lo,$T1
++	vpermq		\$0x2,$D1hi,$H1
++	vpaddq		$T0,$D0lo,${D0lo}{%k1}{z}
++	vpaddq		$H0,$D0hi,${D0hi}{%k1}{z}
++	vpermq		\$0x2,$D2lo,$T2
++	vpermq		\$0x2,$D2hi,$H2
++	vpaddq		$T1,$D1lo,${D1lo}{%k1}{z}
++	vpaddq		$H1,$D1hi,${D1hi}{%k1}{z}
++	vpaddq		$T2,$D2lo,${D2lo}{%k1}{z}
++	vpaddq		$H2,$D2hi,${D2hi}{%k1}{z}
++
++	################################################################
++	# partial reduction
++	vpsrlq		\$44,$D0lo,$tmp
++	vpsllq		\$8,$D0hi,$D0hi
++	vpandq		$mask44,$D0lo,$H0
++	vpaddq		$tmp,$D0hi,$D0hi
++
++	vpaddq		$D0hi,$D1lo,$D1lo
++
++	vpsrlq		\$44,$D1lo,$tmp
++	vpsllq		\$8,$D1hi,$D1hi
++	vpandq		$mask44,$D1lo,$H1
++	vpaddq		$tmp,$D1hi,$D1hi
++
++	vpaddq		$D1hi,$D2lo,$D2lo
++
++	vpsrlq		\$42,$D2lo,$tmp
++	vpsllq		\$10,$D2hi,$D2hi
++	vpandq		$mask42,$D2lo,$H2
++	vpaddq		$tmp,$D2hi,$D2hi
++
++	vpaddq		$D2hi,$H0,$H0
++	vpsllq		\$2,$D2hi,$D2hi
++
++	vpaddq		$D2hi,$H0,$H0
++
++	vpsrlq		\$44,$H0,$tmp		# additional step
++	vpandq		$mask44,$H0,$H0
++
++	vpaddq		$tmp,$H1,$H1
++						# at this point $len is
++						# either 4*n+2 or 0...
++	sub		\$2,$len		# len-=32
++	ja		.Lblocks_vpmadd52_4x_do
++
++	vmovq		%x#$H0,0($ctx)
++	vmovq		%x#$H1,8($ctx)
++	vmovq		%x#$H2,16($ctx)
++	vzeroall
++
++.Lno_data_vpmadd52_4x:
++	ret
++.size	poly1305_blocks_vpmadd52_4x,.-poly1305_blocks_vpmadd52_4x
++___
++}
++{
++########################################################################
++# As implied by its name 8x subroutine processes 8 blocks in parallel...
++# This is intermediate version, as it's used only in cases when input
++# length is either 8*n, 8*n+1 or 8*n+2...
++
++my ($H0,$H1,$H2,$R0,$R1,$R2,$S1,$S2) = map("%ymm$_",(0..5,16,17));
++my ($D0lo,$D0hi,$D1lo,$D1hi,$D2lo,$D2hi) = map("%ymm$_",(18..23));
++my ($T0,$T1,$T2,$T3,$mask44,$mask42,$tmp,$PAD) = map("%ymm$_",(24..31));
++my ($RR0,$RR1,$RR2,$SS1,$SS2) = map("%ymm$_",(6..10));
++
++$code.=<<___;
++.type	poly1305_blocks_vpmadd52_8x,\@function,4
++.align	32
++poly1305_blocks_vpmadd52_8x:
++	shr	\$4,$len
++	jz	.Lno_data_vpmadd52_8x		# too short
++
++	shl	\$40,$padbit
++	mov	64($ctx),%r8			# peek on power of the key
++
++	vmovdqa64	.Lx_mask44(%rip),$mask44
++	vmovdqa64	.Lx_mask42(%rip),$mask42
++
++	test	%r8,%r8				# is power value impossible?
++	js	.Linit_vpmadd52			# if it is, then init R[4]
++
++	vmovq	0($ctx),%x#$H0			# load current hash value
++	vmovq	8($ctx),%x#$H1
++	vmovq	16($ctx),%x#$H2
++
++.Lblocks_vpmadd52_8x:
++	################################################################
++	# fist we calculate more key powers
++
++	vmovdqu64	128($ctx),$R2		# load 1-3-2-4 powers
++	vmovdqu64	160($ctx),$S1
++	vmovdqu64	64($ctx),$R0
++	vmovdqu64	96($ctx),$R1
++
++	vpsllq		\$2,$R2,$S2		# S2 = R2*5*4
++	vpaddq		$R2,$S2,$S2
++	vpsllq		\$2,$S2,$S2
++
++	vpbroadcastq	%x#$R2,$RR2		# broadcast 4th power
++	vpbroadcastq	%x#$R0,$RR0
++	vpbroadcastq	%x#$R1,$RR1
++
++	vpxorq		$D0lo,$D0lo,$D0lo
++	vpmadd52luq	$RR2,$S1,$D0lo
++	vpxorq		$D0hi,$D0hi,$D0hi
++	vpmadd52huq	$RR2,$S1,$D0hi
++	vpxorq		$D1lo,$D1lo,$D1lo
++	vpmadd52luq	$RR2,$S2,$D1lo
++	vpxorq		$D1hi,$D1hi,$D1hi
++	vpmadd52huq	$RR2,$S2,$D1hi
++	vpxorq		$D2lo,$D2lo,$D2lo
++	vpmadd52luq	$RR2,$R0,$D2lo
++	vpxorq		$D2hi,$D2hi,$D2hi
++	vpmadd52huq	$RR2,$R0,$D2hi
++
++	vpmadd52luq	$RR0,$R0,$D0lo
++	vpmadd52huq	$RR0,$R0,$D0hi
++	vpmadd52luq	$RR0,$R1,$D1lo
++	vpmadd52huq	$RR0,$R1,$D1hi
++	vpmadd52luq	$RR0,$R2,$D2lo
++	vpmadd52huq	$RR0,$R2,$D2hi
++
++	vpmadd52luq	$RR1,$S2,$D0lo
++	vpmadd52huq	$RR1,$S2,$D0hi
++	vpmadd52luq	$RR1,$R0,$D1lo
++	vpmadd52huq	$RR1,$R0,$D1hi
++	vpmadd52luq	$RR1,$R1,$D2lo
++	vpmadd52huq	$RR1,$R1,$D2hi
++
++	################################################################
++	# partial reduction
++	vpsrlq		\$44,$D0lo,$tmp
++	vpsllq		\$8,$D0hi,$D0hi
++	vpandq		$mask44,$D0lo,$RR0
++	vpaddq		$tmp,$D0hi,$D0hi
++
++	vpaddq		$D0hi,$D1lo,$D1lo
++
++	vpsrlq		\$44,$D1lo,$tmp
++	vpsllq		\$8,$D1hi,$D1hi
++	vpandq		$mask44,$D1lo,$RR1
++	vpaddq		$tmp,$D1hi,$D1hi
++
++	vpaddq		$D1hi,$D2lo,$D2lo
++
++	vpsrlq		\$42,$D2lo,$tmp
++	vpsllq		\$10,$D2hi,$D2hi
++	vpandq		$mask42,$D2lo,$RR2
++	vpaddq		$tmp,$D2hi,$D2hi
++
++	vpaddq		$D2hi,$RR0,$RR0
++	vpsllq		\$2,$D2hi,$D2hi
++
++	vpaddq		$D2hi,$RR0,$RR0
++
++	vpsrlq		\$44,$RR0,$tmp		# additional step
++	vpandq		$mask44,$RR0,$RR0
++
++	vpaddq		$tmp,$RR1,$RR1
++
++	################################################################
++	# At this point Rx holds 1324 powers, RRx - 5768, and the goal
++	# is 15263748, which reflects how data is loaded...
++
++	vpunpcklqdq	$R2,$RR2,$T2		# 3748
++	vpunpckhqdq	$R2,$RR2,$R2		# 1526
++	vpunpcklqdq	$R0,$RR0,$T0
++	vpunpckhqdq	$R0,$RR0,$R0
++	vpunpcklqdq	$R1,$RR1,$T1
++	vpunpckhqdq	$R1,$RR1,$R1
++___
++######## switch to %zmm
++map(s/%y/%z/, $H0,$H1,$H2,$R0,$R1,$R2,$S1,$S2);
++map(s/%y/%z/, $D0lo,$D0hi,$D1lo,$D1hi,$D2lo,$D2hi);
++map(s/%y/%z/, $T0,$T1,$T2,$T3,$mask44,$mask42,$tmp,$PAD);
++map(s/%y/%z/, $RR0,$RR1,$RR2,$SS1,$SS2);
++
++$code.=<<___;
++	vshufi64x2	\$0x44,$R2,$T2,$RR2	# 15263748
++	vshufi64x2	\$0x44,$R0,$T0,$RR0
++	vshufi64x2	\$0x44,$R1,$T1,$RR1
++
++	vmovdqu64	16*0($inp),$T2		# load data
++	vmovdqu64	16*4($inp),$T3
++	lea		16*8($inp),$inp
++
++	vpsllq		\$2,$RR2,$SS2		# S2 = R2*5*4
++	vpsllq		\$2,$RR1,$SS1		# S1 = R1*5*4
++	vpaddq		$RR2,$SS2,$SS2
++	vpaddq		$RR1,$SS1,$SS1
++	vpsllq		\$2,$SS2,$SS2
++	vpsllq		\$2,$SS1,$SS1
++
++	vpbroadcastq	$padbit,$PAD
++	vpbroadcastq	%x#$mask44,$mask44
++	vpbroadcastq	%x#$mask42,$mask42
++
++	vpbroadcastq	%x#$SS1,$S1		# broadcast 8th power
++	vpbroadcastq	%x#$SS2,$S2
++	vpbroadcastq	%x#$RR0,$R0
++	vpbroadcastq	%x#$RR1,$R1
++	vpbroadcastq	%x#$RR2,$R2
++
++	vpunpcklqdq	$T3,$T2,$T1		# transpose data
++	vpunpckhqdq	$T3,$T2,$T3
++
++	# at this point 64-bit lanes are ordered as 73625140
++
++	vpsrlq		\$24,$T3,$T2		# splat the data
++	vporq		$PAD,$T2,$T2
++	 vpaddq		$T2,$H2,$H2		# accumulate input
++	vpandq		$mask44,$T1,$T0
++	vpsrlq		\$44,$T1,$T1
++	vpsllq		\$20,$T3,$T3
++	vporq		$T3,$T1,$T1
++	vpandq		$mask44,$T1,$T1
++
++	sub		\$8,$len
++	jz		.Ltail_vpmadd52_8x
++	jmp		.Loop_vpmadd52_8x
++
++.align	32
++.Loop_vpmadd52_8x:
++	#vpaddq		$T2,$H2,$H2		# accumulate input
++	vpaddq		$T0,$H0,$H0
++	vpaddq		$T1,$H1,$H1
++
++	vpxorq		$D0lo,$D0lo,$D0lo
++	vpmadd52luq	$H2,$S1,$D0lo
++	vpxorq		$D0hi,$D0hi,$D0hi
++	vpmadd52huq	$H2,$S1,$D0hi
++	vpxorq		$D1lo,$D1lo,$D1lo
++	vpmadd52luq	$H2,$S2,$D1lo
++	vpxorq		$D1hi,$D1hi,$D1hi
++	vpmadd52huq	$H2,$S2,$D1hi
++	vpxorq		$D2lo,$D2lo,$D2lo
++	vpmadd52luq	$H2,$R0,$D2lo
++	vpxorq		$D2hi,$D2hi,$D2hi
++	vpmadd52huq	$H2,$R0,$D2hi
++
++	 vmovdqu64	16*0($inp),$T2		# load data
++	 vmovdqu64	16*4($inp),$T3
++	 lea		16*8($inp),$inp
++	vpmadd52luq	$H0,$R0,$D0lo
++	vpmadd52huq	$H0,$R0,$D0hi
++	vpmadd52luq	$H0,$R1,$D1lo
++	vpmadd52huq	$H0,$R1,$D1hi
++	vpmadd52luq	$H0,$R2,$D2lo
++	vpmadd52huq	$H0,$R2,$D2hi
++
++	 vpunpcklqdq	$T3,$T2,$T1		# transpose data
++	 vpunpckhqdq	$T3,$T2,$T3
++	vpmadd52luq	$H1,$S2,$D0lo
++	vpmadd52huq	$H1,$S2,$D0hi
++	vpmadd52luq	$H1,$R0,$D1lo
++	vpmadd52huq	$H1,$R0,$D1hi
++	vpmadd52luq	$H1,$R1,$D2lo
++	vpmadd52huq	$H1,$R1,$D2hi
++
++	################################################################
++	# partial reduction (interleaved with data splat)
++	vpsrlq		\$44,$D0lo,$tmp
++	vpsllq		\$8,$D0hi,$D0hi
++	vpandq		$mask44,$D0lo,$H0
++	vpaddq		$tmp,$D0hi,$D0hi
++
++	 vpsrlq		\$24,$T3,$T2
++	 vporq		$PAD,$T2,$T2
++	vpaddq		$D0hi,$D1lo,$D1lo
++
++	vpsrlq		\$44,$D1lo,$tmp
++	vpsllq		\$8,$D1hi,$D1hi
++	vpandq		$mask44,$D1lo,$H1
++	vpaddq		$tmp,$D1hi,$D1hi
++
++	 vpandq		$mask44,$T1,$T0
++	 vpsrlq		\$44,$T1,$T1
++	 vpsllq		\$20,$T3,$T3
++	vpaddq		$D1hi,$D2lo,$D2lo
++
++	vpsrlq		\$42,$D2lo,$tmp
++	vpsllq		\$10,$D2hi,$D2hi
++	vpandq		$mask42,$D2lo,$H2
++	vpaddq		$tmp,$D2hi,$D2hi
++
++	  vpaddq	$T2,$H2,$H2		# accumulate input
++	vpaddq		$D2hi,$H0,$H0
++	vpsllq		\$2,$D2hi,$D2hi
++
++	vpaddq		$D2hi,$H0,$H0
++	 vporq		$T3,$T1,$T1
++	 vpandq		$mask44,$T1,$T1
++
++	vpsrlq		\$44,$H0,$tmp		# additional step
++	vpandq		$mask44,$H0,$H0
++
++	vpaddq		$tmp,$H1,$H1
++
++	sub		\$8,$len		# len-=128
++	jnz		.Loop_vpmadd52_8x
++
++.Ltail_vpmadd52_8x:
++	#vpaddq		$T2,$H2,$H2		# accumulate input
++	vpaddq		$T0,$H0,$H0
++	vpaddq		$T1,$H1,$H1
++
++	vpxorq		$D0lo,$D0lo,$D0lo
++	vpmadd52luq	$H2,$SS1,$D0lo
++	vpxorq		$D0hi,$D0hi,$D0hi
++	vpmadd52huq	$H2,$SS1,$D0hi
++	vpxorq		$D1lo,$D1lo,$D1lo
++	vpmadd52luq	$H2,$SS2,$D1lo
++	vpxorq		$D1hi,$D1hi,$D1hi
++	vpmadd52huq	$H2,$SS2,$D1hi
++	vpxorq		$D2lo,$D2lo,$D2lo
++	vpmadd52luq	$H2,$RR0,$D2lo
++	vpxorq		$D2hi,$D2hi,$D2hi
++	vpmadd52huq	$H2,$RR0,$D2hi
++
++	vpmadd52luq	$H0,$RR0,$D0lo
++	vpmadd52huq	$H0,$RR0,$D0hi
++	vpmadd52luq	$H0,$RR1,$D1lo
++	vpmadd52huq	$H0,$RR1,$D1hi
++	vpmadd52luq	$H0,$RR2,$D2lo
++	vpmadd52huq	$H0,$RR2,$D2hi
++
++	vpmadd52luq	$H1,$SS2,$D0lo
++	vpmadd52huq	$H1,$SS2,$D0hi
++	vpmadd52luq	$H1,$RR0,$D1lo
++	vpmadd52huq	$H1,$RR0,$D1hi
++	vpmadd52luq	$H1,$RR1,$D2lo
++	vpmadd52huq	$H1,$RR1,$D2hi
++
++	################################################################
++	# horizontal addition
++
++	mov		\$1,%eax
++	kmovw		%eax,%k1
++	vpsrldq		\$8,$D0lo,$T0
++	vpsrldq		\$8,$D0hi,$H0
++	vpsrldq		\$8,$D1lo,$T1
++	vpsrldq		\$8,$D1hi,$H1
++	vpaddq		$T0,$D0lo,$D0lo
++	vpaddq		$H0,$D0hi,$D0hi
++	vpsrldq		\$8,$D2lo,$T2
++	vpsrldq		\$8,$D2hi,$H2
++	vpaddq		$T1,$D1lo,$D1lo
++	vpaddq		$H1,$D1hi,$D1hi
++	 vpermq		\$0x2,$D0lo,$T0
++	 vpermq		\$0x2,$D0hi,$H0
++	vpaddq		$T2,$D2lo,$D2lo
++	vpaddq		$H2,$D2hi,$D2hi
++
++	vpermq		\$0x2,$D1lo,$T1
++	vpermq		\$0x2,$D1hi,$H1
++	vpaddq		$T0,$D0lo,$D0lo
++	vpaddq		$H0,$D0hi,$D0hi
++	vpermq		\$0x2,$D2lo,$T2
++	vpermq		\$0x2,$D2hi,$H2
++	vpaddq		$T1,$D1lo,$D1lo
++	vpaddq		$H1,$D1hi,$D1hi
++	 vextracti64x4	\$1,$D0lo,%y#$T0
++	 vextracti64x4	\$1,$D0hi,%y#$H0
++	vpaddq		$T2,$D2lo,$D2lo
++	vpaddq		$H2,$D2hi,$D2hi
++
++	vextracti64x4	\$1,$D1lo,%y#$T1
++	vextracti64x4	\$1,$D1hi,%y#$H1
++	vextracti64x4	\$1,$D2lo,%y#$T2
++	vextracti64x4	\$1,$D2hi,%y#$H2
++___
++######## switch back to %ymm
++map(s/%z/%y/, $H0,$H1,$H2,$R0,$R1,$R2,$S1,$S2);
++map(s/%z/%y/, $D0lo,$D0hi,$D1lo,$D1hi,$D2lo,$D2hi);
++map(s/%z/%y/, $T0,$T1,$T2,$T3,$mask44,$mask42,$tmp,$PAD);
++
++$code.=<<___;
++	vpaddq		$T0,$D0lo,${D0lo}{%k1}{z}
++	vpaddq		$H0,$D0hi,${D0hi}{%k1}{z}
++	vpaddq		$T1,$D1lo,${D1lo}{%k1}{z}
++	vpaddq		$H1,$D1hi,${D1hi}{%k1}{z}
++	vpaddq		$T2,$D2lo,${D2lo}{%k1}{z}
++	vpaddq		$H2,$D2hi,${D2hi}{%k1}{z}
++
++	################################################################
++	# partial reduction
++	vpsrlq		\$44,$D0lo,$tmp
++	vpsllq		\$8,$D0hi,$D0hi
++	vpandq		$mask44,$D0lo,$H0
++	vpaddq		$tmp,$D0hi,$D0hi
++
++	vpaddq		$D0hi,$D1lo,$D1lo
++
++	vpsrlq		\$44,$D1lo,$tmp
++	vpsllq		\$8,$D1hi,$D1hi
++	vpandq		$mask44,$D1lo,$H1
++	vpaddq		$tmp,$D1hi,$D1hi
++
++	vpaddq		$D1hi,$D2lo,$D2lo
++
++	vpsrlq		\$42,$D2lo,$tmp
++	vpsllq		\$10,$D2hi,$D2hi
++	vpandq		$mask42,$D2lo,$H2
++	vpaddq		$tmp,$D2hi,$D2hi
++
++	vpaddq		$D2hi,$H0,$H0
++	vpsllq		\$2,$D2hi,$D2hi
++
++	vpaddq		$D2hi,$H0,$H0
++
++	vpsrlq		\$44,$H0,$tmp		# additional step
++	vpandq		$mask44,$H0,$H0
++
++	vpaddq		$tmp,$H1,$H1
++
++	################################################################
++
++	vmovq		%x#$H0,0($ctx)
++	vmovq		%x#$H1,8($ctx)
++	vmovq		%x#$H2,16($ctx)
++	vzeroall
++
++.Lno_data_vpmadd52_8x:
++	ret
++.size	poly1305_blocks_vpmadd52_8x,.-poly1305_blocks_vpmadd52_8x
++___
++}
++$code.=<<___;
++.type	poly1305_emit_base2_44,\@function,3
++.align	32
++poly1305_emit_base2_44:
++	mov	0($ctx),%r8	# load hash value
++	mov	8($ctx),%r9
++	mov	16($ctx),%r10
++
++	mov	%r9,%rax
++	shr	\$20,%r9
++	shl	\$44,%rax
++	mov	%r10,%rcx
++	shr	\$40,%r10
++	shl	\$24,%rcx
++
++	add	%rax,%r8
++	adc	%rcx,%r9
++	adc	\$0,%r10
++
++	mov	%r8,%rax
++	add	\$5,%r8		# compare to modulus
++	mov	%r9,%rcx
++	adc	\$0,%r9
++	adc	\$0,%r10
++	shr	\$2,%r10	# did 130-bit value overflow?
++	cmovnz	%r8,%rax
++	cmovnz	%r9,%rcx
++
++	add	0($nonce),%rax	# accumulate nonce
++	adc	8($nonce),%rcx
++	mov	%rax,0($mac)	# write result
++	mov	%rcx,8($mac)
++
++	ret
++.size	poly1305_emit_base2_44,.-poly1305_emit_base2_44
++___
++}	}	}
++$code.=<<___;
++.align	64
++.Lconst:
++.Lmask24:
++.long	0x0ffffff,0,0x0ffffff,0,0x0ffffff,0,0x0ffffff,0
++.L129:
++.long	`1<<24`,0,`1<<24`,0,`1<<24`,0,`1<<24`,0
++.Lmask26:
++.long	0x3ffffff,0,0x3ffffff,0,0x3ffffff,0,0x3ffffff,0
++.Lpermd_avx2:
++.long	2,2,2,3,2,0,2,1
++.Lpermd_avx512:
++.long	0,0,0,1, 0,2,0,3, 0,4,0,5, 0,6,0,7
++
++.L2_44_inp_permd:
++.long	0,1,1,2,2,3,7,7
++.L2_44_inp_shift:
++.quad	0,12,24,64
++.L2_44_mask:
++.quad	0xfffffffffff,0xfffffffffff,0x3ffffffffff,0xffffffffffffffff
++.L2_44_shift_rgt:
++.quad	44,44,42,64
++.L2_44_shift_lft:
++.quad	8,8,10,64
++
++.align	64
++.Lx_mask44:
++.quad	0xfffffffffff,0xfffffffffff,0xfffffffffff,0xfffffffffff
++.quad	0xfffffffffff,0xfffffffffff,0xfffffffffff,0xfffffffffff
++.Lx_mask42:
++.quad	0x3ffffffffff,0x3ffffffffff,0x3ffffffffff,0x3ffffffffff
++.quad	0x3ffffffffff,0x3ffffffffff,0x3ffffffffff,0x3ffffffffff
++___
++}
++$code.=<<___;
++.asciz	"Poly1305 for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
++.align	16
++___
++
++{	# chacha20-poly1305 helpers
++my ($out,$inp,$otp,$len)=$win64 ? ("%rcx","%rdx","%r8", "%r9") :  # Win64 order
++                                  ("%rdi","%rsi","%rdx","%rcx");  # Unix order
++$code.=<<___;
++.globl	xor128_encrypt_n_pad
++.type	xor128_encrypt_n_pad,\@abi-omnipotent
++.align	16
++xor128_encrypt_n_pad:
++	sub	$otp,$inp
++	sub	$otp,$out
++	mov	$len,%r10		# put len aside
++	shr	\$4,$len		# len / 16
++	jz	.Ltail_enc
++	nop
++.Loop_enc_xmm:
++	movdqu	($inp,$otp),%xmm0
++	pxor	($otp),%xmm0
++	movdqu	%xmm0,($out,$otp)
++	movdqa	%xmm0,($otp)
++	lea	16($otp),$otp
++	dec	$len
++	jnz	.Loop_enc_xmm
++
++	and	\$15,%r10		# len % 16
++	jz	.Ldone_enc
++
++.Ltail_enc:
++	mov	\$16,$len
++	sub	%r10,$len
++	xor	%eax,%eax
++.Loop_enc_byte:
++	mov	($inp,$otp),%al
++	xor	($otp),%al
++	mov	%al,($out,$otp)
++	mov	%al,($otp)
++	lea	1($otp),$otp
++	dec	%r10
++	jnz	.Loop_enc_byte
++
++	xor	%eax,%eax
++.Loop_enc_pad:
++	mov	%al,($otp)
++	lea	1($otp),$otp
++	dec	$len
++	jnz	.Loop_enc_pad
++
++.Ldone_enc:
++	mov	$otp,%rax
++	ret
++.size	xor128_encrypt_n_pad,.-xor128_encrypt_n_pad
++
++.globl	xor128_decrypt_n_pad
++.type	xor128_decrypt_n_pad,\@abi-omnipotent
++.align	16
++xor128_decrypt_n_pad:
++	sub	$otp,$inp
++	sub	$otp,$out
++	mov	$len,%r10		# put len aside
++	shr	\$4,$len		# len / 16
++	jz	.Ltail_dec
++	nop
++.Loop_dec_xmm:
++	movdqu	($inp,$otp),%xmm0
++	movdqa	($otp),%xmm1
++	pxor	%xmm0,%xmm1
++	movdqu	%xmm1,($out,$otp)
++	movdqa	%xmm0,($otp)
++	lea	16($otp),$otp
++	dec	$len
++	jnz	.Loop_dec_xmm
++
++	pxor	%xmm1,%xmm1
++	and	\$15,%r10		# len % 16
++	jz	.Ldone_dec
++
++.Ltail_dec:
++	mov	\$16,$len
++	sub	%r10,$len
++	xor	%eax,%eax
++	xor	%r11,%r11
++.Loop_dec_byte:
++	mov	($inp,$otp),%r11b
++	mov	($otp),%al
++	xor	%r11b,%al
++	mov	%al,($out,$otp)
++	mov	%r11b,($otp)
++	lea	1($otp),$otp
++	dec	%r10
++	jnz	.Loop_dec_byte
++
++	xor	%eax,%eax
++.Loop_dec_pad:
++	mov	%al,($otp)
++	lea	1($otp),$otp
++	dec	$len
++	jnz	.Loop_dec_pad
++
++.Ldone_dec:
++	mov	$otp,%rax
++	ret
++.size	xor128_decrypt_n_pad,.-xor128_decrypt_n_pad
++___
++}
++
++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
++#		CONTEXT *context,DISPATCHER_CONTEXT *disp)
++if ($win64) {
++$rec="%rcx";
++$frame="%rdx";
++$context="%r8";
++$disp="%r9";
++
++$code.=<<___;
++.extern	__imp_RtlVirtualUnwind
++.type	se_handler,\@abi-omnipotent
++.align	16
++se_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# prologue label
++	cmp	%r10,%rbx		# context->Rip<.Lprologue
++	jb	.Lcommon_seh_tail
++
++	mov	152($context),%rax	# pull context->Rsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=.Lepilogue
++	jae	.Lcommon_seh_tail
++
++	lea	48(%rax),%rax
++
++	mov	-8(%rax),%rbx
++	mov	-16(%rax),%rbp
++	mov	-24(%rax),%r12
++	mov	-32(%rax),%r13
++	mov	-40(%rax),%r14
++	mov	-48(%rax),%r15
++	mov	%rbx,144($context)	# restore context->Rbx
++	mov	%rbp,160($context)	# restore context->Rbp
++	mov	%r12,216($context)	# restore context->R12
++	mov	%r13,224($context)	# restore context->R13
++	mov	%r14,232($context)	# restore context->R14
++	mov	%r15,240($context)	# restore context->R14
++
++	jmp	.Lcommon_seh_tail
++.size	se_handler,.-se_handler
++
++.type	avx_handler,\@abi-omnipotent
++.align	16
++avx_handler:
++	push	%rsi
++	push	%rdi
++	push	%rbx
++	push	%rbp
++	push	%r12
++	push	%r13
++	push	%r14
++	push	%r15
++	pushfq
++	sub	\$64,%rsp
++
++	mov	120($context),%rax	# pull context->Rax
++	mov	248($context),%rbx	# pull context->Rip
++
++	mov	8($disp),%rsi		# disp->ImageBase
++	mov	56($disp),%r11		# disp->HandlerData
++
++	mov	0(%r11),%r10d		# HandlerData[0]
++	lea	(%rsi,%r10),%r10	# prologue label
++	cmp	%r10,%rbx		# context->Rip<prologue label
++	jb	.Lcommon_seh_tail
++
++	mov	152($context),%rax	# pull context->Rsp
++
++	mov	4(%r11),%r10d		# HandlerData[1]
++	lea	(%rsi,%r10),%r10	# epilogue label
++	cmp	%r10,%rbx		# context->Rip>=epilogue label
++	jae	.Lcommon_seh_tail
++
++	mov	208($context),%rax	# pull context->R11
++
++	lea	0x50(%rax),%rsi
++	lea	0xf8(%rax),%rax
++	lea	512($context),%rdi	# &context.Xmm6
++	mov	\$20,%ecx
++	.long	0xa548f3fc		# cld; rep movsq
++
++.Lcommon_seh_tail:
++	mov	8(%rax),%rdi
++	mov	16(%rax),%rsi
++	mov	%rax,152($context)	# restore context->Rsp
++	mov	%rsi,168($context)	# restore context->Rsi
++	mov	%rdi,176($context)	# restore context->Rdi
++
++	mov	40($disp),%rdi		# disp->ContextRecord
++	mov	$context,%rsi		# context
++	mov	\$154,%ecx		# sizeof(CONTEXT)
++	.long	0xa548f3fc		# cld; rep movsq
++
++	mov	$disp,%rsi
++	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
++	mov	0(%rsi),%r8		# arg3, disp->ControlPc
++	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
++	mov	40(%rsi),%r10		# disp->ContextRecord
++	lea	56(%rsi),%r11		# &disp->HandlerData
++	lea	24(%rsi),%r12		# &disp->EstablisherFrame
++	mov	%r10,32(%rsp)		# arg5
++	mov	%r11,40(%rsp)		# arg6
++	mov	%r12,48(%rsp)		# arg7
++	mov	%rcx,56(%rsp)		# arg8, (NULL)
++	call	*__imp_RtlVirtualUnwind(%rip)
++
++	mov	\$1,%eax		# ExceptionContinueSearch
++	add	\$64,%rsp
++	popfq
++	pop	%r15
++	pop	%r14
++	pop	%r13
++	pop	%r12
++	pop	%rbp
++	pop	%rbx
++	pop	%rdi
++	pop	%rsi
++	ret
++.size	avx_handler,.-avx_handler
++
++.section	.pdata
++.align	4
++	.rva	.LSEH_begin_poly1305_init
++	.rva	.LSEH_end_poly1305_init
++	.rva	.LSEH_info_poly1305_init
++
++	.rva	.LSEH_begin_poly1305_blocks
++	.rva	.LSEH_end_poly1305_blocks
++	.rva	.LSEH_info_poly1305_blocks
++
++	.rva	.LSEH_begin_poly1305_emit
++	.rva	.LSEH_end_poly1305_emit
++	.rva	.LSEH_info_poly1305_emit
++___
++$code.=<<___ if ($avx);
++	.rva	.LSEH_begin_poly1305_blocks_avx
++	.rva	.Lbase2_64_avx
++	.rva	.LSEH_info_poly1305_blocks_avx_1
++
++	.rva	.Lbase2_64_avx
++	.rva	.Leven_avx
++	.rva	.LSEH_info_poly1305_blocks_avx_2
++
++	.rva	.Leven_avx
++	.rva	.LSEH_end_poly1305_blocks_avx
++	.rva	.LSEH_info_poly1305_blocks_avx_3
++
++	.rva	.LSEH_begin_poly1305_emit_avx
++	.rva	.LSEH_end_poly1305_emit_avx
++	.rva	.LSEH_info_poly1305_emit_avx
++___
++$code.=<<___ if ($avx>1);
++	.rva	.LSEH_begin_poly1305_blocks_avx2
++	.rva	.Lbase2_64_avx2
++	.rva	.LSEH_info_poly1305_blocks_avx2_1
++
++	.rva	.Lbase2_64_avx2
++	.rva	.Leven_avx2
++	.rva	.LSEH_info_poly1305_blocks_avx2_2
++
++	.rva	.Leven_avx2
++	.rva	.LSEH_end_poly1305_blocks_avx2
++	.rva	.LSEH_info_poly1305_blocks_avx2_3
++___
++$code.=<<___ if ($avx>2);
++	.rva	.LSEH_begin_poly1305_blocks_avx512
++	.rva	.LSEH_end_poly1305_blocks_avx512
++	.rva	.LSEH_info_poly1305_blocks_avx512
++___
++$code.=<<___;
++.section	.xdata
++.align	8
++.LSEH_info_poly1305_init:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.LSEH_begin_poly1305_init,.LSEH_begin_poly1305_init
++
++.LSEH_info_poly1305_blocks:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lblocks_body,.Lblocks_epilogue
++
++.LSEH_info_poly1305_emit:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.LSEH_begin_poly1305_emit,.LSEH_begin_poly1305_emit
++___
++$code.=<<___ if ($avx);
++.LSEH_info_poly1305_blocks_avx_1:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lblocks_avx_body,.Lblocks_avx_epilogue		# HandlerData[]
++
++.LSEH_info_poly1305_blocks_avx_2:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lbase2_64_avx_body,.Lbase2_64_avx_epilogue	# HandlerData[]
++
++.LSEH_info_poly1305_blocks_avx_3:
++	.byte	9,0,0,0
++	.rva	avx_handler
++	.rva	.Ldo_avx_body,.Ldo_avx_epilogue			# HandlerData[]
++
++.LSEH_info_poly1305_emit_avx:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.LSEH_begin_poly1305_emit_avx,.LSEH_begin_poly1305_emit_avx
++___
++$code.=<<___ if ($avx>1);
++.LSEH_info_poly1305_blocks_avx2_1:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lblocks_avx2_body,.Lblocks_avx2_epilogue	# HandlerData[]
++
++.LSEH_info_poly1305_blocks_avx2_2:
++	.byte	9,0,0,0
++	.rva	se_handler
++	.rva	.Lbase2_64_avx2_body,.Lbase2_64_avx2_epilogue	# HandlerData[]
++
++.LSEH_info_poly1305_blocks_avx2_3:
++	.byte	9,0,0,0
++	.rva	avx_handler
++	.rva	.Ldo_avx2_body,.Ldo_avx2_epilogue		# HandlerData[]
++___
++$code.=<<___ if ($avx>2);
++.LSEH_info_poly1305_blocks_avx512:
++	.byte	9,0,0,0
++	.rva	avx_handler
++	.rva	.Ldo_avx512_body,.Ldo_avx512_epilogue		# HandlerData[]
++___
++}
++
++foreach (split('\n',$code)) {
++	s/\`([^\`]*)\`/eval($1)/ge;
++	s/%r([a-z]+)#d/%e$1/g;
++	s/%r([0-9]+)#d/%r$1d/g;
++	s/%x#%[yz]/%x/g or s/%y#%z/%y/g or s/%z#%[yz]/%z/g;
++
++	print $_,"\n";
++}
++close STDOUT;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0043-crypto-x86-poly1305-wire-up-faster-implementations-f.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0043-crypto-x86-poly1305-wire-up-faster-implementations-f.patch
new file mode 100644
index 0000000..0fc8348
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0043-crypto-x86-poly1305-wire-up-faster-implementations-f.patch
@@ -0,0 +1,2927 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Sun, 5 Jan 2020 22:40:48 -0500
+Subject: [PATCH] crypto: x86/poly1305 - wire up faster implementations for
+ kernel
+
+commit d7d7b853566254648df59f7ea27ea05952a6cfa8 upstream.
+
+These x86_64 vectorized implementations support AVX, AVX-2, and AVX512F.
+The AVX-512F implementation is disabled on Skylake, due to throttling,
+but it is quite fast on >= Cannonlake.
+
+On the left is cycle counts on a Core i7 6700HQ using the AVX-2
+codepath, comparing this implementation ("new") to the implementation in
+the current crypto api ("old"). On the right are benchmarks on a Xeon
+Gold 5120 using the AVX-512 codepath. The new implementation is faster
+on all benchmarks.
+
+        AVX-2                  AVX-512
+      ---------              -----------
+
+    size    old     new      size   old     new
+    ----    ----    ----     ----   ----    ----
+    0       70      68       0      74      70
+    16      92      90       16     96      92
+    32      134     104      32     136     106
+    48      172     120      48     184     124
+    64      218     136      64     218     138
+    80      254     158      80     260     160
+    96      298     174      96     300     176
+    112     342     192      112    342     194
+    128     388     212      128    384     212
+    144     428     228      144    420     226
+    160     466     246      160    464     248
+    176     510     264      176    504     264
+    192     550     282      192    544     282
+    208     594     302      208    582     300
+    224     628     316      224    624     318
+    240     676     334      240    662     338
+    256     716     354      256    708     358
+    272     764     374      272    748     372
+    288     802     352      288    788     358
+    304     420     366      304    422     370
+    320     428     360      320    432     364
+    336     484     378      336    486     380
+    352     426     384      352    434     390
+    368     478     400      368    480     408
+    384     488     394      384    490     398
+    400     542     408      400    542     412
+    416     486     416      416    492     426
+    432     534     430      432    538     436
+    448     544     422      448    546     432
+    464     600     438      464    600     448
+    480     540     448      480    548     456
+    496     594     464      496    594     476
+    512     602     456      512    606     470
+    528     656     476      528    656     480
+    544     600     480      544    606     498
+    560     650     494      560    652     512
+    576     664     490      576    662     508
+    592     714     508      592    716     522
+    608     656     514      608    664     538
+    624     708     532      624    710     552
+    640     716     524      640    720     516
+    656     770     536      656    772     526
+    672     716     548      672    722     544
+    688     770     562      688    768     556
+    704     774     552      704    778     556
+    720     826     568      720    832     568
+    736     768     574      736    780     584
+    752     822     592      752    826     600
+    768     830     584      768    836     560
+    784     884     602      784    888     572
+    800     828     610      800    838     588
+    816     884     628      816    884     604
+    832     888     618      832    894     598
+    848     942     632      848    946     612
+    864     884     644      864    896     628
+    880     936     660      880    942     644
+    896     948     652      896    952     608
+    912     1000    664      912    1004    616
+    928     942     676      928    954     634
+    944     994     690      944    1000    646
+    960     1002    680      960    1008    646
+    976     1054    694      976    1062    658
+    992     1002    706      992    1012    674
+    1008    1052    720      1008   1058    690
+
+This commit wires in the prior implementation from Andy, and makes the
+following changes to be suitable for kernel land.
+
+  - Some cosmetic and structural changes, like renaming labels to
+    .Lname, constants, and other Linux conventions, as well as making
+    the code easy for us to maintain moving forward.
+
+  - CPU feature checking is done in C by the glue code.
+
+  - We avoid jumping into the middle of functions, to appease objtool,
+    and instead parameterize shared code.
+
+  - We maintain frame pointers so that stack traces make sense.
+
+  - We remove the dependency on the perl xlate code, which transforms
+    the output into things that assemblers we don't care about use.
+
+Importantly, none of our changes affect the arithmetic or core code, but
+just involve the differing environment of kernel space.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Samuel Neves <sneves@dei.uc.pt>
+Co-developed-by: Samuel Neves <sneves@dei.uc.pt>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/.gitignore                    |   1 +
+ arch/x86/crypto/Makefile                      |  11 +-
+ arch/x86/crypto/poly1305-avx2-x86_64.S        | 390 ----------
+ arch/x86/crypto/poly1305-sse2-x86_64.S        | 590 ---------------
+ arch/x86/crypto/poly1305-x86_64-cryptogams.pl | 682 ++++++++++--------
+ arch/x86/crypto/poly1305_glue.c               | 473 +++++-------
+ lib/crypto/Kconfig                            |   2 +-
+ 7 files changed, 572 insertions(+), 1577 deletions(-)
+ create mode 100644 arch/x86/crypto/.gitignore
+ delete mode 100644 arch/x86/crypto/poly1305-avx2-x86_64.S
+ delete mode 100644 arch/x86/crypto/poly1305-sse2-x86_64.S
+
+--- /dev/null
++++ b/arch/x86/crypto/.gitignore
+@@ -0,0 +1 @@
++poly1305-x86_64.S
+--- a/arch/x86/crypto/Makefile
++++ b/arch/x86/crypto/Makefile
+@@ -73,6 +73,10 @@ aegis128-aesni-y := aegis128-aesni-asm.o
+ 
+ nhpoly1305-sse2-y := nh-sse2-x86_64.o nhpoly1305-sse2-glue.o
+ blake2s-x86_64-y := blake2s-core.o blake2s-glue.o
++poly1305-x86_64-y := poly1305-x86_64-cryptogams.o poly1305_glue.o
++ifneq ($(CONFIG_CRYPTO_POLY1305_X86_64),)
++targets += poly1305-x86_64-cryptogams.S
++endif
+ 
+ ifeq ($(avx_supported),yes)
+ 	camellia-aesni-avx-x86_64-y := camellia-aesni-avx-asm_64.o \
+@@ -101,10 +105,8 @@ aesni-intel-y := aesni-intel_asm.o aesni
+ aesni-intel-$(CONFIG_64BIT) += aesni-intel_avx-x86_64.o aes_ctrby8_avx-x86_64.o
+ ghash-clmulni-intel-y := ghash-clmulni-intel_asm.o ghash-clmulni-intel_glue.o
+ sha1-ssse3-y := sha1_ssse3_asm.o sha1_ssse3_glue.o
+-poly1305-x86_64-y := poly1305-sse2-x86_64.o poly1305_glue.o
+ ifeq ($(avx2_supported),yes)
+ sha1-ssse3-y += sha1_avx2_x86_64_asm.o
+-poly1305-x86_64-y += poly1305-avx2-x86_64.o
+ endif
+ ifeq ($(sha1_ni_supported),yes)
+ sha1-ssse3-y += sha1_ni_asm.o
+@@ -118,3 +120,8 @@ sha256-ssse3-y += sha256_ni_asm.o
+ endif
+ sha512-ssse3-y := sha512-ssse3-asm.o sha512-avx-asm.o sha512-avx2-asm.o sha512_ssse3_glue.o
+ crct10dif-pclmul-y := crct10dif-pcl-asm_64.o crct10dif-pclmul_glue.o
++
++quiet_cmd_perlasm = PERLASM $@
++      cmd_perlasm = $(PERL) $< > $@
++$(obj)/%.S: $(src)/%.pl FORCE
++	$(call if_changed,perlasm)
+--- a/arch/x86/crypto/poly1305-avx2-x86_64.S
++++ /dev/null
+@@ -1,390 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0-or-later */
+-/*
+- * Poly1305 authenticator algorithm, RFC7539, x64 AVX2 functions
+- *
+- * Copyright (C) 2015 Martin Willi
+- */
+-
+-#include <linux/linkage.h>
+-
+-.section	.rodata.cst32.ANMASK, "aM", @progbits, 32
+-.align 32
+-ANMASK:	.octa 0x0000000003ffffff0000000003ffffff
+-	.octa 0x0000000003ffffff0000000003ffffff
+-
+-.section	.rodata.cst32.ORMASK, "aM", @progbits, 32
+-.align 32
+-ORMASK:	.octa 0x00000000010000000000000001000000
+-	.octa 0x00000000010000000000000001000000
+-
+-.text
+-
+-#define h0 0x00(%rdi)
+-#define h1 0x04(%rdi)
+-#define h2 0x08(%rdi)
+-#define h3 0x0c(%rdi)
+-#define h4 0x10(%rdi)
+-#define r0 0x00(%rdx)
+-#define r1 0x04(%rdx)
+-#define r2 0x08(%rdx)
+-#define r3 0x0c(%rdx)
+-#define r4 0x10(%rdx)
+-#define u0 0x00(%r8)
+-#define u1 0x04(%r8)
+-#define u2 0x08(%r8)
+-#define u3 0x0c(%r8)
+-#define u4 0x10(%r8)
+-#define w0 0x18(%r8)
+-#define w1 0x1c(%r8)
+-#define w2 0x20(%r8)
+-#define w3 0x24(%r8)
+-#define w4 0x28(%r8)
+-#define y0 0x30(%r8)
+-#define y1 0x34(%r8)
+-#define y2 0x38(%r8)
+-#define y3 0x3c(%r8)
+-#define y4 0x40(%r8)
+-#define m %rsi
+-#define hc0 %ymm0
+-#define hc1 %ymm1
+-#define hc2 %ymm2
+-#define hc3 %ymm3
+-#define hc4 %ymm4
+-#define hc0x %xmm0
+-#define hc1x %xmm1
+-#define hc2x %xmm2
+-#define hc3x %xmm3
+-#define hc4x %xmm4
+-#define t1 %ymm5
+-#define t2 %ymm6
+-#define t1x %xmm5
+-#define t2x %xmm6
+-#define ruwy0 %ymm7
+-#define ruwy1 %ymm8
+-#define ruwy2 %ymm9
+-#define ruwy3 %ymm10
+-#define ruwy4 %ymm11
+-#define ruwy0x %xmm7
+-#define ruwy1x %xmm8
+-#define ruwy2x %xmm9
+-#define ruwy3x %xmm10
+-#define ruwy4x %xmm11
+-#define svxz1 %ymm12
+-#define svxz2 %ymm13
+-#define svxz3 %ymm14
+-#define svxz4 %ymm15
+-#define d0 %r9
+-#define d1 %r10
+-#define d2 %r11
+-#define d3 %r12
+-#define d4 %r13
+-
+-ENTRY(poly1305_4block_avx2)
+-	# %rdi: Accumulator h[5]
+-	# %rsi: 64 byte input block m
+-	# %rdx: Poly1305 key r[5]
+-	# %rcx: Quadblock count
+-	# %r8:  Poly1305 derived key r^2 u[5], r^3 w[5], r^4 y[5],
+-
+-	# This four-block variant uses loop unrolled block processing. It
+-	# requires 4 Poly1305 keys: r, r^2, r^3 and r^4:
+-	# h = (h + m) * r  =>  h = (h + m1) * r^4 + m2 * r^3 + m3 * r^2 + m4 * r
+-
+-	vzeroupper
+-	push		%rbx
+-	push		%r12
+-	push		%r13
+-
+-	# combine r0,u0,w0,y0
+-	vmovd		y0,ruwy0x
+-	vmovd		w0,t1x
+-	vpunpcklqdq	t1,ruwy0,ruwy0
+-	vmovd		u0,t1x
+-	vmovd		r0,t2x
+-	vpunpcklqdq	t2,t1,t1
+-	vperm2i128	$0x20,t1,ruwy0,ruwy0
+-
+-	# combine r1,u1,w1,y1 and s1=r1*5,v1=u1*5,x1=w1*5,z1=y1*5
+-	vmovd		y1,ruwy1x
+-	vmovd		w1,t1x
+-	vpunpcklqdq	t1,ruwy1,ruwy1
+-	vmovd		u1,t1x
+-	vmovd		r1,t2x
+-	vpunpcklqdq	t2,t1,t1
+-	vperm2i128	$0x20,t1,ruwy1,ruwy1
+-	vpslld		$2,ruwy1,svxz1
+-	vpaddd		ruwy1,svxz1,svxz1
+-
+-	# combine r2,u2,w2,y2 and s2=r2*5,v2=u2*5,x2=w2*5,z2=y2*5
+-	vmovd		y2,ruwy2x
+-	vmovd		w2,t1x
+-	vpunpcklqdq	t1,ruwy2,ruwy2
+-	vmovd		u2,t1x
+-	vmovd		r2,t2x
+-	vpunpcklqdq	t2,t1,t1
+-	vperm2i128	$0x20,t1,ruwy2,ruwy2
+-	vpslld		$2,ruwy2,svxz2
+-	vpaddd		ruwy2,svxz2,svxz2
+-
+-	# combine r3,u3,w3,y3 and s3=r3*5,v3=u3*5,x3=w3*5,z3=y3*5
+-	vmovd		y3,ruwy3x
+-	vmovd		w3,t1x
+-	vpunpcklqdq	t1,ruwy3,ruwy3
+-	vmovd		u3,t1x
+-	vmovd		r3,t2x
+-	vpunpcklqdq	t2,t1,t1
+-	vperm2i128	$0x20,t1,ruwy3,ruwy3
+-	vpslld		$2,ruwy3,svxz3
+-	vpaddd		ruwy3,svxz3,svxz3
+-
+-	# combine r4,u4,w4,y4 and s4=r4*5,v4=u4*5,x4=w4*5,z4=y4*5
+-	vmovd		y4,ruwy4x
+-	vmovd		w4,t1x
+-	vpunpcklqdq	t1,ruwy4,ruwy4
+-	vmovd		u4,t1x
+-	vmovd		r4,t2x
+-	vpunpcklqdq	t2,t1,t1
+-	vperm2i128	$0x20,t1,ruwy4,ruwy4
+-	vpslld		$2,ruwy4,svxz4
+-	vpaddd		ruwy4,svxz4,svxz4
+-
+-.Ldoblock4:
+-	# hc0 = [m[48-51] & 0x3ffffff, m[32-35] & 0x3ffffff,
+-	#	 m[16-19] & 0x3ffffff, m[ 0- 3] & 0x3ffffff + h0]
+-	vmovd		0x00(m),hc0x
+-	vmovd		0x10(m),t1x
+-	vpunpcklqdq	t1,hc0,hc0
+-	vmovd		0x20(m),t1x
+-	vmovd		0x30(m),t2x
+-	vpunpcklqdq	t2,t1,t1
+-	vperm2i128	$0x20,t1,hc0,hc0
+-	vpand		ANMASK(%rip),hc0,hc0
+-	vmovd		h0,t1x
+-	vpaddd		t1,hc0,hc0
+-	# hc1 = [(m[51-54] >> 2) & 0x3ffffff, (m[35-38] >> 2) & 0x3ffffff,
+-	#	 (m[19-22] >> 2) & 0x3ffffff, (m[ 3- 6] >> 2) & 0x3ffffff + h1]
+-	vmovd		0x03(m),hc1x
+-	vmovd		0x13(m),t1x
+-	vpunpcklqdq	t1,hc1,hc1
+-	vmovd		0x23(m),t1x
+-	vmovd		0x33(m),t2x
+-	vpunpcklqdq	t2,t1,t1
+-	vperm2i128	$0x20,t1,hc1,hc1
+-	vpsrld		$2,hc1,hc1
+-	vpand		ANMASK(%rip),hc1,hc1
+-	vmovd		h1,t1x
+-	vpaddd		t1,hc1,hc1
+-	# hc2 = [(m[54-57] >> 4) & 0x3ffffff, (m[38-41] >> 4) & 0x3ffffff,
+-	#	 (m[22-25] >> 4) & 0x3ffffff, (m[ 6- 9] >> 4) & 0x3ffffff + h2]
+-	vmovd		0x06(m),hc2x
+-	vmovd		0x16(m),t1x
+-	vpunpcklqdq	t1,hc2,hc2
+-	vmovd		0x26(m),t1x
+-	vmovd		0x36(m),t2x
+-	vpunpcklqdq	t2,t1,t1
+-	vperm2i128	$0x20,t1,hc2,hc2
+-	vpsrld		$4,hc2,hc2
+-	vpand		ANMASK(%rip),hc2,hc2
+-	vmovd		h2,t1x
+-	vpaddd		t1,hc2,hc2
+-	# hc3 = [(m[57-60] >> 6) & 0x3ffffff, (m[41-44] >> 6) & 0x3ffffff,
+-	#	 (m[25-28] >> 6) & 0x3ffffff, (m[ 9-12] >> 6) & 0x3ffffff + h3]
+-	vmovd		0x09(m),hc3x
+-	vmovd		0x19(m),t1x
+-	vpunpcklqdq	t1,hc3,hc3
+-	vmovd		0x29(m),t1x
+-	vmovd		0x39(m),t2x
+-	vpunpcklqdq	t2,t1,t1
+-	vperm2i128	$0x20,t1,hc3,hc3
+-	vpsrld		$6,hc3,hc3
+-	vpand		ANMASK(%rip),hc3,hc3
+-	vmovd		h3,t1x
+-	vpaddd		t1,hc3,hc3
+-	# hc4 = [(m[60-63] >> 8) | (1<<24), (m[44-47] >> 8) | (1<<24),
+-	#	 (m[28-31] >> 8) | (1<<24), (m[12-15] >> 8) | (1<<24) + h4]
+-	vmovd		0x0c(m),hc4x
+-	vmovd		0x1c(m),t1x
+-	vpunpcklqdq	t1,hc4,hc4
+-	vmovd		0x2c(m),t1x
+-	vmovd		0x3c(m),t2x
+-	vpunpcklqdq	t2,t1,t1
+-	vperm2i128	$0x20,t1,hc4,hc4
+-	vpsrld		$8,hc4,hc4
+-	vpor		ORMASK(%rip),hc4,hc4
+-	vmovd		h4,t1x
+-	vpaddd		t1,hc4,hc4
+-
+-	# t1 = [ hc0[3] * r0, hc0[2] * u0, hc0[1] * w0, hc0[0] * y0 ]
+-	vpmuludq	hc0,ruwy0,t1
+-	# t1 += [ hc1[3] * s4, hc1[2] * v4, hc1[1] * x4, hc1[0] * z4 ]
+-	vpmuludq	hc1,svxz4,t2
+-	vpaddq		t2,t1,t1
+-	# t1 += [ hc2[3] * s3, hc2[2] * v3, hc2[1] * x3, hc2[0] * z3 ]
+-	vpmuludq	hc2,svxz3,t2
+-	vpaddq		t2,t1,t1
+-	# t1 += [ hc3[3] * s2, hc3[2] * v2, hc3[1] * x2, hc3[0] * z2 ]
+-	vpmuludq	hc3,svxz2,t2
+-	vpaddq		t2,t1,t1
+-	# t1 += [ hc4[3] * s1, hc4[2] * v1, hc4[1] * x1, hc4[0] * z1 ]
+-	vpmuludq	hc4,svxz1,t2
+-	vpaddq		t2,t1,t1
+-	# d0 = t1[0] + t1[1] + t[2] + t[3]
+-	vpermq		$0xee,t1,t2
+-	vpaddq		t2,t1,t1
+-	vpsrldq		$8,t1,t2
+-	vpaddq		t2,t1,t1
+-	vmovq		t1x,d0
+-
+-	# t1 = [ hc0[3] * r1, hc0[2] * u1,hc0[1] * w1, hc0[0] * y1 ]
+-	vpmuludq	hc0,ruwy1,t1
+-	# t1 += [ hc1[3] * r0, hc1[2] * u0, hc1[1] * w0, hc1[0] * y0 ]
+-	vpmuludq	hc1,ruwy0,t2
+-	vpaddq		t2,t1,t1
+-	# t1 += [ hc2[3] * s4, hc2[2] * v4, hc2[1] * x4, hc2[0] * z4 ]
+-	vpmuludq	hc2,svxz4,t2
+-	vpaddq		t2,t1,t1
+-	# t1 += [ hc3[3] * s3, hc3[2] * v3, hc3[1] * x3, hc3[0] * z3 ]
+-	vpmuludq	hc3,svxz3,t2
+-	vpaddq		t2,t1,t1
+-	# t1 += [ hc4[3] * s2, hc4[2] * v2, hc4[1] * x2, hc4[0] * z2 ]
+-	vpmuludq	hc4,svxz2,t2
+-	vpaddq		t2,t1,t1
+-	# d1 = t1[0] + t1[1] + t1[3] + t1[4]
+-	vpermq		$0xee,t1,t2
+-	vpaddq		t2,t1,t1
+-	vpsrldq		$8,t1,t2
+-	vpaddq		t2,t1,t1
+-	vmovq		t1x,d1
+-
+-	# t1 = [ hc0[3] * r2, hc0[2] * u2, hc0[1] * w2, hc0[0] * y2 ]
+-	vpmuludq	hc0,ruwy2,t1
+-	# t1 += [ hc1[3] * r1, hc1[2] * u1, hc1[1] * w1, hc1[0] * y1 ]
+-	vpmuludq	hc1,ruwy1,t2
+-	vpaddq		t2,t1,t1
+-	# t1 += [ hc2[3] * r0, hc2[2] * u0, hc2[1] * w0, hc2[0] * y0 ]
+-	vpmuludq	hc2,ruwy0,t2
+-	vpaddq		t2,t1,t1
+-	# t1 += [ hc3[3] * s4, hc3[2] * v4, hc3[1] * x4, hc3[0] * z4 ]
+-	vpmuludq	hc3,svxz4,t2
+-	vpaddq		t2,t1,t1
+-	# t1 += [ hc4[3] * s3, hc4[2] * v3, hc4[1] * x3, hc4[0] * z3 ]
+-	vpmuludq	hc4,svxz3,t2
+-	vpaddq		t2,t1,t1
+-	# d2 = t1[0] + t1[1] + t1[2] + t1[3]
+-	vpermq		$0xee,t1,t2
+-	vpaddq		t2,t1,t1
+-	vpsrldq		$8,t1,t2
+-	vpaddq		t2,t1,t1
+-	vmovq		t1x,d2
+-
+-	# t1 = [ hc0[3] * r3, hc0[2] * u3, hc0[1] * w3, hc0[0] * y3 ]
+-	vpmuludq	hc0,ruwy3,t1
+-	# t1 += [ hc1[3] * r2, hc1[2] * u2, hc1[1] * w2, hc1[0] * y2 ]
+-	vpmuludq	hc1,ruwy2,t2
+-	vpaddq		t2,t1,t1
+-	# t1 += [ hc2[3] * r1, hc2[2] * u1, hc2[1] * w1, hc2[0] * y1 ]
+-	vpmuludq	hc2,ruwy1,t2
+-	vpaddq		t2,t1,t1
+-	# t1 += [ hc3[3] * r0, hc3[2] * u0, hc3[1] * w0, hc3[0] * y0 ]
+-	vpmuludq	hc3,ruwy0,t2
+-	vpaddq		t2,t1,t1
+-	# t1 += [ hc4[3] * s4, hc4[2] * v4, hc4[1] * x4, hc4[0] * z4 ]
+-	vpmuludq	hc4,svxz4,t2
+-	vpaddq		t2,t1,t1
+-	# d3 = t1[0] + t1[1] + t1[2] + t1[3]
+-	vpermq		$0xee,t1,t2
+-	vpaddq		t2,t1,t1
+-	vpsrldq		$8,t1,t2
+-	vpaddq		t2,t1,t1
+-	vmovq		t1x,d3
+-
+-	# t1 = [ hc0[3] * r4, hc0[2] * u4, hc0[1] * w4, hc0[0] * y4 ]
+-	vpmuludq	hc0,ruwy4,t1
+-	# t1 += [ hc1[3] * r3, hc1[2] * u3, hc1[1] * w3, hc1[0] * y3 ]
+-	vpmuludq	hc1,ruwy3,t2
+-	vpaddq		t2,t1,t1
+-	# t1 += [ hc2[3] * r2, hc2[2] * u2, hc2[1] * w2, hc2[0] * y2 ]
+-	vpmuludq	hc2,ruwy2,t2
+-	vpaddq		t2,t1,t1
+-	# t1 += [ hc3[3] * r1, hc3[2] * u1, hc3[1] * w1, hc3[0] * y1 ]
+-	vpmuludq	hc3,ruwy1,t2
+-	vpaddq		t2,t1,t1
+-	# t1 += [ hc4[3] * r0, hc4[2] * u0, hc4[1] * w0, hc4[0] * y0 ]
+-	vpmuludq	hc4,ruwy0,t2
+-	vpaddq		t2,t1,t1
+-	# d4 = t1[0] + t1[1] + t1[2] + t1[3]
+-	vpermq		$0xee,t1,t2
+-	vpaddq		t2,t1,t1
+-	vpsrldq		$8,t1,t2
+-	vpaddq		t2,t1,t1
+-	vmovq		t1x,d4
+-
+-	# Now do a partial reduction mod (2^130)-5, carrying h0 -> h1 -> h2 ->
+-	# h3 -> h4 -> h0 -> h1 to get h0,h2,h3,h4 < 2^26 and h1 < 2^26 + a small
+-	# amount.  Careful: we must not assume the carry bits 'd0 >> 26',
+-	# 'd1 >> 26', 'd2 >> 26', 'd3 >> 26', and '(d4 >> 26) * 5' fit in 32-bit
+-	# integers.  It's true in a single-block implementation, but not here.
+-
+-	# d1 += d0 >> 26
+-	mov		d0,%rax
+-	shr		$26,%rax
+-	add		%rax,d1
+-	# h0 = d0 & 0x3ffffff
+-	mov		d0,%rbx
+-	and		$0x3ffffff,%ebx
+-
+-	# d2 += d1 >> 26
+-	mov		d1,%rax
+-	shr		$26,%rax
+-	add		%rax,d2
+-	# h1 = d1 & 0x3ffffff
+-	mov		d1,%rax
+-	and		$0x3ffffff,%eax
+-	mov		%eax,h1
+-
+-	# d3 += d2 >> 26
+-	mov		d2,%rax
+-	shr		$26,%rax
+-	add		%rax,d3
+-	# h2 = d2 & 0x3ffffff
+-	mov		d2,%rax
+-	and		$0x3ffffff,%eax
+-	mov		%eax,h2
+-
+-	# d4 += d3 >> 26
+-	mov		d3,%rax
+-	shr		$26,%rax
+-	add		%rax,d4
+-	# h3 = d3 & 0x3ffffff
+-	mov		d3,%rax
+-	and		$0x3ffffff,%eax
+-	mov		%eax,h3
+-
+-	# h0 += (d4 >> 26) * 5
+-	mov		d4,%rax
+-	shr		$26,%rax
+-	lea		(%rax,%rax,4),%rax
+-	add		%rax,%rbx
+-	# h4 = d4 & 0x3ffffff
+-	mov		d4,%rax
+-	and		$0x3ffffff,%eax
+-	mov		%eax,h4
+-
+-	# h1 += h0 >> 26
+-	mov		%rbx,%rax
+-	shr		$26,%rax
+-	add		%eax,h1
+-	# h0 = h0 & 0x3ffffff
+-	andl		$0x3ffffff,%ebx
+-	mov		%ebx,h0
+-
+-	add		$0x40,m
+-	dec		%rcx
+-	jnz		.Ldoblock4
+-
+-	vzeroupper
+-	pop		%r13
+-	pop		%r12
+-	pop		%rbx
+-	ret
+-ENDPROC(poly1305_4block_avx2)
+--- a/arch/x86/crypto/poly1305-sse2-x86_64.S
++++ /dev/null
+@@ -1,590 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0-or-later */
+-/*
+- * Poly1305 authenticator algorithm, RFC7539, x64 SSE2 functions
+- *
+- * Copyright (C) 2015 Martin Willi
+- */
+-
+-#include <linux/linkage.h>
+-
+-.section	.rodata.cst16.ANMASK, "aM", @progbits, 16
+-.align 16
+-ANMASK:	.octa 0x0000000003ffffff0000000003ffffff
+-
+-.section	.rodata.cst16.ORMASK, "aM", @progbits, 16
+-.align 16
+-ORMASK:	.octa 0x00000000010000000000000001000000
+-
+-.text
+-
+-#define h0 0x00(%rdi)
+-#define h1 0x04(%rdi)
+-#define h2 0x08(%rdi)
+-#define h3 0x0c(%rdi)
+-#define h4 0x10(%rdi)
+-#define r0 0x00(%rdx)
+-#define r1 0x04(%rdx)
+-#define r2 0x08(%rdx)
+-#define r3 0x0c(%rdx)
+-#define r4 0x10(%rdx)
+-#define s1 0x00(%rsp)
+-#define s2 0x04(%rsp)
+-#define s3 0x08(%rsp)
+-#define s4 0x0c(%rsp)
+-#define m %rsi
+-#define h01 %xmm0
+-#define h23 %xmm1
+-#define h44 %xmm2
+-#define t1 %xmm3
+-#define t2 %xmm4
+-#define t3 %xmm5
+-#define t4 %xmm6
+-#define mask %xmm7
+-#define d0 %r8
+-#define d1 %r9
+-#define d2 %r10
+-#define d3 %r11
+-#define d4 %r12
+-
+-ENTRY(poly1305_block_sse2)
+-	# %rdi: Accumulator h[5]
+-	# %rsi: 16 byte input block m
+-	# %rdx: Poly1305 key r[5]
+-	# %rcx: Block count
+-
+-	# This single block variant tries to improve performance by doing two
+-	# multiplications in parallel using SSE instructions. There is quite
+-	# some quardword packing involved, hence the speedup is marginal.
+-
+-	push		%rbx
+-	push		%r12
+-	sub		$0x10,%rsp
+-
+-	# s1..s4 = r1..r4 * 5
+-	mov		r1,%eax
+-	lea		(%eax,%eax,4),%eax
+-	mov		%eax,s1
+-	mov		r2,%eax
+-	lea		(%eax,%eax,4),%eax
+-	mov		%eax,s2
+-	mov		r3,%eax
+-	lea		(%eax,%eax,4),%eax
+-	mov		%eax,s3
+-	mov		r4,%eax
+-	lea		(%eax,%eax,4),%eax
+-	mov		%eax,s4
+-
+-	movdqa		ANMASK(%rip),mask
+-
+-.Ldoblock:
+-	# h01 = [0, h1, 0, h0]
+-	# h23 = [0, h3, 0, h2]
+-	# h44 = [0, h4, 0, h4]
+-	movd		h0,h01
+-	movd		h1,t1
+-	movd		h2,h23
+-	movd		h3,t2
+-	movd		h4,h44
+-	punpcklqdq	t1,h01
+-	punpcklqdq	t2,h23
+-	punpcklqdq	h44,h44
+-
+-	# h01 += [ (m[3-6] >> 2) & 0x3ffffff, m[0-3] & 0x3ffffff ]
+-	movd		0x00(m),t1
+-	movd		0x03(m),t2
+-	psrld		$2,t2
+-	punpcklqdq	t2,t1
+-	pand		mask,t1
+-	paddd		t1,h01
+-	# h23 += [ (m[9-12] >> 6) & 0x3ffffff, (m[6-9] >> 4) & 0x3ffffff ]
+-	movd		0x06(m),t1
+-	movd		0x09(m),t2
+-	psrld		$4,t1
+-	psrld		$6,t2
+-	punpcklqdq	t2,t1
+-	pand		mask,t1
+-	paddd		t1,h23
+-	# h44 += [ (m[12-15] >> 8) | (1 << 24), (m[12-15] >> 8) | (1 << 24) ]
+-	mov		0x0c(m),%eax
+-	shr		$8,%eax
+-	or		$0x01000000,%eax
+-	movd		%eax,t1
+-	pshufd		$0xc4,t1,t1
+-	paddd		t1,h44
+-
+-	# t1[0] = h0 * r0 + h2 * s3
+-	# t1[1] = h1 * s4 + h3 * s2
+-	movd		r0,t1
+-	movd		s4,t2
+-	punpcklqdq	t2,t1
+-	pmuludq		h01,t1
+-	movd		s3,t2
+-	movd		s2,t3
+-	punpcklqdq	t3,t2
+-	pmuludq		h23,t2
+-	paddq		t2,t1
+-	# t2[0] = h0 * r1 + h2 * s4
+-	# t2[1] = h1 * r0 + h3 * s3
+-	movd		r1,t2
+-	movd		r0,t3
+-	punpcklqdq	t3,t2
+-	pmuludq		h01,t2
+-	movd		s4,t3
+-	movd		s3,t4
+-	punpcklqdq	t4,t3
+-	pmuludq		h23,t3
+-	paddq		t3,t2
+-	# t3[0] = h4 * s1
+-	# t3[1] = h4 * s2
+-	movd		s1,t3
+-	movd		s2,t4
+-	punpcklqdq	t4,t3
+-	pmuludq		h44,t3
+-	# d0 = t1[0] + t1[1] + t3[0]
+-	# d1 = t2[0] + t2[1] + t3[1]
+-	movdqa		t1,t4
+-	punpcklqdq	t2,t4
+-	punpckhqdq	t2,t1
+-	paddq		t4,t1
+-	paddq		t3,t1
+-	movq		t1,d0
+-	psrldq		$8,t1
+-	movq		t1,d1
+-
+-	# t1[0] = h0 * r2 + h2 * r0
+-	# t1[1] = h1 * r1 + h3 * s4
+-	movd		r2,t1
+-	movd		r1,t2
+-	punpcklqdq 	t2,t1
+-	pmuludq		h01,t1
+-	movd		r0,t2
+-	movd		s4,t3
+-	punpcklqdq	t3,t2
+-	pmuludq		h23,t2
+-	paddq		t2,t1
+-	# t2[0] = h0 * r3 + h2 * r1
+-	# t2[1] = h1 * r2 + h3 * r0
+-	movd		r3,t2
+-	movd		r2,t3
+-	punpcklqdq	t3,t2
+-	pmuludq		h01,t2
+-	movd		r1,t3
+-	movd		r0,t4
+-	punpcklqdq	t4,t3
+-	pmuludq		h23,t3
+-	paddq		t3,t2
+-	# t3[0] = h4 * s3
+-	# t3[1] = h4 * s4
+-	movd		s3,t3
+-	movd		s4,t4
+-	punpcklqdq	t4,t3
+-	pmuludq		h44,t3
+-	# d2 = t1[0] + t1[1] + t3[0]
+-	# d3 = t2[0] + t2[1] + t3[1]
+-	movdqa		t1,t4
+-	punpcklqdq	t2,t4
+-	punpckhqdq	t2,t1
+-	paddq		t4,t1
+-	paddq		t3,t1
+-	movq		t1,d2
+-	psrldq		$8,t1
+-	movq		t1,d3
+-
+-	# t1[0] = h0 * r4 + h2 * r2
+-	# t1[1] = h1 * r3 + h3 * r1
+-	movd		r4,t1
+-	movd		r3,t2
+-	punpcklqdq	t2,t1
+-	pmuludq		h01,t1
+-	movd		r2,t2
+-	movd		r1,t3
+-	punpcklqdq	t3,t2
+-	pmuludq		h23,t2
+-	paddq		t2,t1
+-	# t3[0] = h4 * r0
+-	movd		r0,t3
+-	pmuludq		h44,t3
+-	# d4 = t1[0] + t1[1] + t3[0]
+-	movdqa		t1,t4
+-	psrldq		$8,t4
+-	paddq		t4,t1
+-	paddq		t3,t1
+-	movq		t1,d4
+-
+-	# d1 += d0 >> 26
+-	mov		d0,%rax
+-	shr		$26,%rax
+-	add		%rax,d1
+-	# h0 = d0 & 0x3ffffff
+-	mov		d0,%rbx
+-	and		$0x3ffffff,%ebx
+-
+-	# d2 += d1 >> 26
+-	mov		d1,%rax
+-	shr		$26,%rax
+-	add		%rax,d2
+-	# h1 = d1 & 0x3ffffff
+-	mov		d1,%rax
+-	and		$0x3ffffff,%eax
+-	mov		%eax,h1
+-
+-	# d3 += d2 >> 26
+-	mov		d2,%rax
+-	shr		$26,%rax
+-	add		%rax,d3
+-	# h2 = d2 & 0x3ffffff
+-	mov		d2,%rax
+-	and		$0x3ffffff,%eax
+-	mov		%eax,h2
+-
+-	# d4 += d3 >> 26
+-	mov		d3,%rax
+-	shr		$26,%rax
+-	add		%rax,d4
+-	# h3 = d3 & 0x3ffffff
+-	mov		d3,%rax
+-	and		$0x3ffffff,%eax
+-	mov		%eax,h3
+-
+-	# h0 += (d4 >> 26) * 5
+-	mov		d4,%rax
+-	shr		$26,%rax
+-	lea		(%rax,%rax,4),%rax
+-	add		%rax,%rbx
+-	# h4 = d4 & 0x3ffffff
+-	mov		d4,%rax
+-	and		$0x3ffffff,%eax
+-	mov		%eax,h4
+-
+-	# h1 += h0 >> 26
+-	mov		%rbx,%rax
+-	shr		$26,%rax
+-	add		%eax,h1
+-	# h0 = h0 & 0x3ffffff
+-	andl		$0x3ffffff,%ebx
+-	mov		%ebx,h0
+-
+-	add		$0x10,m
+-	dec		%rcx
+-	jnz		.Ldoblock
+-
+-	# Zeroing of key material
+-	mov		%rcx,0x00(%rsp)
+-	mov		%rcx,0x08(%rsp)
+-
+-	add		$0x10,%rsp
+-	pop		%r12
+-	pop		%rbx
+-	ret
+-ENDPROC(poly1305_block_sse2)
+-
+-
+-#define u0 0x00(%r8)
+-#define u1 0x04(%r8)
+-#define u2 0x08(%r8)
+-#define u3 0x0c(%r8)
+-#define u4 0x10(%r8)
+-#define hc0 %xmm0
+-#define hc1 %xmm1
+-#define hc2 %xmm2
+-#define hc3 %xmm5
+-#define hc4 %xmm6
+-#define ru0 %xmm7
+-#define ru1 %xmm8
+-#define ru2 %xmm9
+-#define ru3 %xmm10
+-#define ru4 %xmm11
+-#define sv1 %xmm12
+-#define sv2 %xmm13
+-#define sv3 %xmm14
+-#define sv4 %xmm15
+-#undef d0
+-#define d0 %r13
+-
+-ENTRY(poly1305_2block_sse2)
+-	# %rdi: Accumulator h[5]
+-	# %rsi: 16 byte input block m
+-	# %rdx: Poly1305 key r[5]
+-	# %rcx: Doubleblock count
+-	# %r8:  Poly1305 derived key r^2 u[5]
+-
+-	# This two-block variant further improves performance by using loop
+-	# unrolled block processing. This is more straight forward and does
+-	# less byte shuffling, but requires a second Poly1305 key r^2:
+-	# h = (h + m) * r    =>    h = (h + m1) * r^2 + m2 * r
+-
+-	push		%rbx
+-	push		%r12
+-	push		%r13
+-
+-	# combine r0,u0
+-	movd		u0,ru0
+-	movd		r0,t1
+-	punpcklqdq	t1,ru0
+-
+-	# combine r1,u1 and s1=r1*5,v1=u1*5
+-	movd		u1,ru1
+-	movd		r1,t1
+-	punpcklqdq	t1,ru1
+-	movdqa		ru1,sv1
+-	pslld		$2,sv1
+-	paddd		ru1,sv1
+-
+-	# combine r2,u2 and s2=r2*5,v2=u2*5
+-	movd		u2,ru2
+-	movd		r2,t1
+-	punpcklqdq	t1,ru2
+-	movdqa		ru2,sv2
+-	pslld		$2,sv2
+-	paddd		ru2,sv2
+-
+-	# combine r3,u3 and s3=r3*5,v3=u3*5
+-	movd		u3,ru3
+-	movd		r3,t1
+-	punpcklqdq	t1,ru3
+-	movdqa		ru3,sv3
+-	pslld		$2,sv3
+-	paddd		ru3,sv3
+-
+-	# combine r4,u4 and s4=r4*5,v4=u4*5
+-	movd		u4,ru4
+-	movd		r4,t1
+-	punpcklqdq	t1,ru4
+-	movdqa		ru4,sv4
+-	pslld		$2,sv4
+-	paddd		ru4,sv4
+-
+-.Ldoblock2:
+-	# hc0 = [ m[16-19] & 0x3ffffff, h0 + m[0-3] & 0x3ffffff ]
+-	movd		0x00(m),hc0
+-	movd		0x10(m),t1
+-	punpcklqdq	t1,hc0
+-	pand		ANMASK(%rip),hc0
+-	movd		h0,t1
+-	paddd		t1,hc0
+-	# hc1 = [ (m[19-22] >> 2) & 0x3ffffff, h1 + (m[3-6] >> 2) & 0x3ffffff ]
+-	movd		0x03(m),hc1
+-	movd		0x13(m),t1
+-	punpcklqdq	t1,hc1
+-	psrld		$2,hc1
+-	pand		ANMASK(%rip),hc1
+-	movd		h1,t1
+-	paddd		t1,hc1
+-	# hc2 = [ (m[22-25] >> 4) & 0x3ffffff, h2 + (m[6-9] >> 4) & 0x3ffffff ]
+-	movd		0x06(m),hc2
+-	movd		0x16(m),t1
+-	punpcklqdq	t1,hc2
+-	psrld		$4,hc2
+-	pand		ANMASK(%rip),hc2
+-	movd		h2,t1
+-	paddd		t1,hc2
+-	# hc3 = [ (m[25-28] >> 6) & 0x3ffffff, h3 + (m[9-12] >> 6) & 0x3ffffff ]
+-	movd		0x09(m),hc3
+-	movd		0x19(m),t1
+-	punpcklqdq	t1,hc3
+-	psrld		$6,hc3
+-	pand		ANMASK(%rip),hc3
+-	movd		h3,t1
+-	paddd		t1,hc3
+-	# hc4 = [ (m[28-31] >> 8) | (1<<24), h4 + (m[12-15] >> 8) | (1<<24) ]
+-	movd		0x0c(m),hc4
+-	movd		0x1c(m),t1
+-	punpcklqdq	t1,hc4
+-	psrld		$8,hc4
+-	por		ORMASK(%rip),hc4
+-	movd		h4,t1
+-	paddd		t1,hc4
+-
+-	# t1 = [ hc0[1] * r0, hc0[0] * u0 ]
+-	movdqa		ru0,t1
+-	pmuludq		hc0,t1
+-	# t1 += [ hc1[1] * s4, hc1[0] * v4 ]
+-	movdqa		sv4,t2
+-	pmuludq		hc1,t2
+-	paddq		t2,t1
+-	# t1 += [ hc2[1] * s3, hc2[0] * v3 ]
+-	movdqa		sv3,t2
+-	pmuludq		hc2,t2
+-	paddq		t2,t1
+-	# t1 += [ hc3[1] * s2, hc3[0] * v2 ]
+-	movdqa		sv2,t2
+-	pmuludq		hc3,t2
+-	paddq		t2,t1
+-	# t1 += [ hc4[1] * s1, hc4[0] * v1 ]
+-	movdqa		sv1,t2
+-	pmuludq		hc4,t2
+-	paddq		t2,t1
+-	# d0 = t1[0] + t1[1]
+-	movdqa		t1,t2
+-	psrldq		$8,t2
+-	paddq		t2,t1
+-	movq		t1,d0
+-
+-	# t1 = [ hc0[1] * r1, hc0[0] * u1 ]
+-	movdqa		ru1,t1
+-	pmuludq		hc0,t1
+-	# t1 += [ hc1[1] * r0, hc1[0] * u0 ]
+-	movdqa		ru0,t2
+-	pmuludq		hc1,t2
+-	paddq		t2,t1
+-	# t1 += [ hc2[1] * s4, hc2[0] * v4 ]
+-	movdqa		sv4,t2
+-	pmuludq		hc2,t2
+-	paddq		t2,t1
+-	# t1 += [ hc3[1] * s3, hc3[0] * v3 ]
+-	movdqa		sv3,t2
+-	pmuludq		hc3,t2
+-	paddq		t2,t1
+-	# t1 += [ hc4[1] * s2, hc4[0] * v2 ]
+-	movdqa		sv2,t2
+-	pmuludq		hc4,t2
+-	paddq		t2,t1
+-	# d1 = t1[0] + t1[1]
+-	movdqa		t1,t2
+-	psrldq		$8,t2
+-	paddq		t2,t1
+-	movq		t1,d1
+-
+-	# t1 = [ hc0[1] * r2, hc0[0] * u2 ]
+-	movdqa		ru2,t1
+-	pmuludq		hc0,t1
+-	# t1 += [ hc1[1] * r1, hc1[0] * u1 ]
+-	movdqa		ru1,t2
+-	pmuludq		hc1,t2
+-	paddq		t2,t1
+-	# t1 += [ hc2[1] * r0, hc2[0] * u0 ]
+-	movdqa		ru0,t2
+-	pmuludq		hc2,t2
+-	paddq		t2,t1
+-	# t1 += [ hc3[1] * s4, hc3[0] * v4 ]
+-	movdqa		sv4,t2
+-	pmuludq		hc3,t2
+-	paddq		t2,t1
+-	# t1 += [ hc4[1] * s3, hc4[0] * v3 ]
+-	movdqa		sv3,t2
+-	pmuludq		hc4,t2
+-	paddq		t2,t1
+-	# d2 = t1[0] + t1[1]
+-	movdqa		t1,t2
+-	psrldq		$8,t2
+-	paddq		t2,t1
+-	movq		t1,d2
+-
+-	# t1 = [ hc0[1] * r3, hc0[0] * u3 ]
+-	movdqa		ru3,t1
+-	pmuludq		hc0,t1
+-	# t1 += [ hc1[1] * r2, hc1[0] * u2 ]
+-	movdqa		ru2,t2
+-	pmuludq		hc1,t2
+-	paddq		t2,t1
+-	# t1 += [ hc2[1] * r1, hc2[0] * u1 ]
+-	movdqa		ru1,t2
+-	pmuludq		hc2,t2
+-	paddq		t2,t1
+-	# t1 += [ hc3[1] * r0, hc3[0] * u0 ]
+-	movdqa		ru0,t2
+-	pmuludq		hc3,t2
+-	paddq		t2,t1
+-	# t1 += [ hc4[1] * s4, hc4[0] * v4 ]
+-	movdqa		sv4,t2
+-	pmuludq		hc4,t2
+-	paddq		t2,t1
+-	# d3 = t1[0] + t1[1]
+-	movdqa		t1,t2
+-	psrldq		$8,t2
+-	paddq		t2,t1
+-	movq		t1,d3
+-
+-	# t1 = [ hc0[1] * r4, hc0[0] * u4 ]
+-	movdqa		ru4,t1
+-	pmuludq		hc0,t1
+-	# t1 += [ hc1[1] * r3, hc1[0] * u3 ]
+-	movdqa		ru3,t2
+-	pmuludq		hc1,t2
+-	paddq		t2,t1
+-	# t1 += [ hc2[1] * r2, hc2[0] * u2 ]
+-	movdqa		ru2,t2
+-	pmuludq		hc2,t2
+-	paddq		t2,t1
+-	# t1 += [ hc3[1] * r1, hc3[0] * u1 ]
+-	movdqa		ru1,t2
+-	pmuludq		hc3,t2
+-	paddq		t2,t1
+-	# t1 += [ hc4[1] * r0, hc4[0] * u0 ]
+-	movdqa		ru0,t2
+-	pmuludq		hc4,t2
+-	paddq		t2,t1
+-	# d4 = t1[0] + t1[1]
+-	movdqa		t1,t2
+-	psrldq		$8,t2
+-	paddq		t2,t1
+-	movq		t1,d4
+-
+-	# Now do a partial reduction mod (2^130)-5, carrying h0 -> h1 -> h2 ->
+-	# h3 -> h4 -> h0 -> h1 to get h0,h2,h3,h4 < 2^26 and h1 < 2^26 + a small
+-	# amount.  Careful: we must not assume the carry bits 'd0 >> 26',
+-	# 'd1 >> 26', 'd2 >> 26', 'd3 >> 26', and '(d4 >> 26) * 5' fit in 32-bit
+-	# integers.  It's true in a single-block implementation, but not here.
+-
+-	# d1 += d0 >> 26
+-	mov		d0,%rax
+-	shr		$26,%rax
+-	add		%rax,d1
+-	# h0 = d0 & 0x3ffffff
+-	mov		d0,%rbx
+-	and		$0x3ffffff,%ebx
+-
+-	# d2 += d1 >> 26
+-	mov		d1,%rax
+-	shr		$26,%rax
+-	add		%rax,d2
+-	# h1 = d1 & 0x3ffffff
+-	mov		d1,%rax
+-	and		$0x3ffffff,%eax
+-	mov		%eax,h1
+-
+-	# d3 += d2 >> 26
+-	mov		d2,%rax
+-	shr		$26,%rax
+-	add		%rax,d3
+-	# h2 = d2 & 0x3ffffff
+-	mov		d2,%rax
+-	and		$0x3ffffff,%eax
+-	mov		%eax,h2
+-
+-	# d4 += d3 >> 26
+-	mov		d3,%rax
+-	shr		$26,%rax
+-	add		%rax,d4
+-	# h3 = d3 & 0x3ffffff
+-	mov		d3,%rax
+-	and		$0x3ffffff,%eax
+-	mov		%eax,h3
+-
+-	# h0 += (d4 >> 26) * 5
+-	mov		d4,%rax
+-	shr		$26,%rax
+-	lea		(%rax,%rax,4),%rax
+-	add		%rax,%rbx
+-	# h4 = d4 & 0x3ffffff
+-	mov		d4,%rax
+-	and		$0x3ffffff,%eax
+-	mov		%eax,h4
+-
+-	# h1 += h0 >> 26
+-	mov		%rbx,%rax
+-	shr		$26,%rax
+-	add		%eax,h1
+-	# h0 = h0 & 0x3ffffff
+-	andl		$0x3ffffff,%ebx
+-	mov		%ebx,h0
+-
+-	add		$0x20,m
+-	dec		%rcx
+-	jnz		.Ldoblock2
+-
+-	pop		%r13
+-	pop		%r12
+-	pop		%rbx
+-	ret
+-ENDPROC(poly1305_2block_sse2)
+--- a/arch/x86/crypto/poly1305-x86_64-cryptogams.pl
++++ b/arch/x86/crypto/poly1305-x86_64-cryptogams.pl
+@@ -1,11 +1,14 @@
+-#! /usr/bin/env perl
+-# Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
++#!/usr/bin/env perl
++# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+ #
+-# Licensed under the OpenSSL license (the "License").  You may not use
+-# this file except in compliance with the License.  You can obtain a copy
+-# in the file LICENSE in the source distribution or at
+-# https://www.openssl.org/source/license.html
+-
++# Copyright (C) 2017-2018 Samuel Neves <sneves@dei.uc.pt>. All Rights Reserved.
++# Copyright (C) 2017-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++# Copyright (C) 2006-2017 CRYPTOGAMS by <appro@openssl.org>. All Rights Reserved.
++#
++# This code is taken from the OpenSSL project but the author, Andy Polyakov,
++# has relicensed it under the licenses specified in the SPDX header above.
++# The original headers, including the original license headers, are
++# included below for completeness.
+ #
+ # ====================================================================
+ # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+@@ -32,7 +35,7 @@
+ # Skylake-X system performance. Since we are likely to suppress
+ # AVX512F capability flag [at least on Skylake-X], conversion serves
+ # as kind of "investment protection". Note that next *lake processor,
+-# Cannolake, has AVX512IFMA code path to execute...
++# Cannonlake, has AVX512IFMA code path to execute...
+ #
+ # Numbers are cycles per processed byte with poly1305_blocks alone,
+ # measured with rdtsc at fixed clock frequency.
+@@ -68,39 +71,114 @@ $output  = shift;
+ if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
+ 
+ $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
++$kernel=0; $kernel=1 if (!$flavour && !$output);
+ 
+-$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+-( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
+-( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
+-die "can't locate x86_64-xlate.pl";
+-
+-if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
+-		=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
+-	$avx = ($1>=2.19) + ($1>=2.22) + ($1>=2.25) + ($1>=2.26);
++if (!$kernel) {
++	$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
++	( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
++	( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
++	die "can't locate x86_64-xlate.pl";
++
++	open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
++	*STDOUT=*OUT;
++
++	if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
++	    =~ /GNU assembler version ([2-9]\.[0-9]+)/) {
++		$avx = ($1>=2.19) + ($1>=2.22) + ($1>=2.25);
++	}
++
++	if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
++	    `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)(?:\.([0-9]+))?/) {
++		$avx = ($1>=2.09) + ($1>=2.10) + ($1>=2.12);
++		$avx += 1 if ($1==2.11 && $2>=8);
++	}
++
++	if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
++	    `ml64 2>&1` =~ /Version ([0-9]+)\./) {
++		$avx = ($1>=10) + ($1>=11);
++	}
++
++	if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9]\.[0-9]+)/) {
++		$avx = ($2>=3.0) + ($2>3.0);
++	}
++} else {
++	$avx = 4; # The kernel uses ifdefs for this.
+ }
+ 
+-if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
+-	   `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)(?:\.([0-9]+))?/) {
+-	$avx = ($1>=2.09) + ($1>=2.10) + 2 * ($1>=2.12);
+-	$avx += 2 if ($1==2.11 && $2>=8);
++sub declare_function() {
++	my ($name, $align, $nargs) = @_;
++	if($kernel) {
++		$code .= ".align $align\n";
++		$code .= "ENTRY($name)\n";
++		$code .= ".L$name:\n";
++	} else {
++		$code .= ".globl	$name\n";
++		$code .= ".type	$name,\@function,$nargs\n";
++		$code .= ".align	$align\n";
++		$code .= "$name:\n";
++	}
+ }
+ 
+-if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
+-	   `ml64 2>&1` =~ /Version ([0-9]+)\./) {
+-	$avx = ($1>=10) + ($1>=12);
++sub end_function() {
++	my ($name) = @_;
++	if($kernel) {
++		$code .= "ENDPROC($name)\n";
++	} else {
++		$code .= ".size   $name,.-$name\n";
++	}
+ }
+ 
+-if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9]\.[0-9]+)/) {
+-	$avx = ($2>=3.0) + ($2>3.0);
+-}
++$code.=<<___ if $kernel;
++#include <linux/linkage.h>
++___
+ 
+-open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
+-*STDOUT=*OUT;
++if ($avx) {
++$code.=<<___ if $kernel;
++.section .rodata
++___
++$code.=<<___;
++.align	64
++.Lconst:
++.Lmask24:
++.long	0x0ffffff,0,0x0ffffff,0,0x0ffffff,0,0x0ffffff,0
++.L129:
++.long	`1<<24`,0,`1<<24`,0,`1<<24`,0,`1<<24`,0
++.Lmask26:
++.long	0x3ffffff,0,0x3ffffff,0,0x3ffffff,0,0x3ffffff,0
++.Lpermd_avx2:
++.long	2,2,2,3,2,0,2,1
++.Lpermd_avx512:
++.long	0,0,0,1, 0,2,0,3, 0,4,0,5, 0,6,0,7
++
++.L2_44_inp_permd:
++.long	0,1,1,2,2,3,7,7
++.L2_44_inp_shift:
++.quad	0,12,24,64
++.L2_44_mask:
++.quad	0xfffffffffff,0xfffffffffff,0x3ffffffffff,0xffffffffffffffff
++.L2_44_shift_rgt:
++.quad	44,44,42,64
++.L2_44_shift_lft:
++.quad	8,8,10,64
++
++.align	64
++.Lx_mask44:
++.quad	0xfffffffffff,0xfffffffffff,0xfffffffffff,0xfffffffffff
++.quad	0xfffffffffff,0xfffffffffff,0xfffffffffff,0xfffffffffff
++.Lx_mask42:
++.quad	0x3ffffffffff,0x3ffffffffff,0x3ffffffffff,0x3ffffffffff
++.quad	0x3ffffffffff,0x3ffffffffff,0x3ffffffffff,0x3ffffffffff
++___
++}
++$code.=<<___ if (!$kernel);
++.asciz	"Poly1305 for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
++.align	16
++___
+ 
+ my ($ctx,$inp,$len,$padbit)=("%rdi","%rsi","%rdx","%rcx");
+ my ($mac,$nonce)=($inp,$len);	# *_emit arguments
+-my ($d1,$d2,$d3, $r0,$r1,$s1)=map("%r$_",(8..13));
+-my ($h0,$h1,$h2)=("%r14","%rbx","%rbp");
++my ($d1,$d2,$d3, $r0,$r1,$s1)=("%r8","%r9","%rdi","%r11","%r12","%r13");
++my ($h0,$h1,$h2)=("%r14","%rbx","%r10");
+ 
+ sub poly1305_iteration {
+ # input:	copy of $r1 in %rax, $h0-$h2, $r0-$r1
+@@ -155,19 +233,19 @@ ___
+ 
+ $code.=<<___;
+ .text
+-
++___
++$code.=<<___ if (!$kernel);
+ .extern	OPENSSL_ia32cap_P
+ 
+-.globl	poly1305_init
+-.hidden	poly1305_init
+-.globl	poly1305_blocks
+-.hidden	poly1305_blocks
+-.globl	poly1305_emit
+-.hidden	poly1305_emit
+-
+-.type	poly1305_init,\@function,3
+-.align	32
+-poly1305_init:
++.globl	poly1305_init_x86_64
++.hidden	poly1305_init_x86_64
++.globl	poly1305_blocks_x86_64
++.hidden	poly1305_blocks_x86_64
++.globl	poly1305_emit_x86_64
++.hidden	poly1305_emit_x86_64
++___
++&declare_function("poly1305_init_x86_64", 32, 3);
++$code.=<<___;
+ 	xor	%rax,%rax
+ 	mov	%rax,0($ctx)		# initialize hash value
+ 	mov	%rax,8($ctx)
+@@ -175,11 +253,12 @@ poly1305_init:
+ 
+ 	cmp	\$0,$inp
+ 	je	.Lno_key
+-
+-	lea	poly1305_blocks(%rip),%r10
+-	lea	poly1305_emit(%rip),%r11
+ ___
+-$code.=<<___	if ($avx);
++$code.=<<___ if (!$kernel);
++	lea	poly1305_blocks_x86_64(%rip),%r10
++	lea	poly1305_emit_x86_64(%rip),%r11
++___
++$code.=<<___	if (!$kernel && $avx);
+ 	mov	OPENSSL_ia32cap_P+4(%rip),%r9
+ 	lea	poly1305_blocks_avx(%rip),%rax
+ 	lea	poly1305_emit_avx(%rip),%rcx
+@@ -187,12 +266,12 @@ $code.=<<___	if ($avx);
+ 	cmovc	%rax,%r10
+ 	cmovc	%rcx,%r11
+ ___
+-$code.=<<___	if ($avx>1);
++$code.=<<___	if (!$kernel && $avx>1);
+ 	lea	poly1305_blocks_avx2(%rip),%rax
+ 	bt	\$`5+32`,%r9		# AVX2?
+ 	cmovc	%rax,%r10
+ ___
+-$code.=<<___	if ($avx>3);
++$code.=<<___	if (!$kernel && $avx>3);
+ 	mov	\$`(1<<31|1<<21|1<<16)`,%rax
+ 	shr	\$32,%r9
+ 	and	%rax,%r9
+@@ -207,11 +286,11 @@ $code.=<<___;
+ 	mov	%rax,24($ctx)
+ 	mov	%rcx,32($ctx)
+ ___
+-$code.=<<___	if ($flavour !~ /elf32/);
++$code.=<<___	if (!$kernel && $flavour !~ /elf32/);
+ 	mov	%r10,0(%rdx)
+ 	mov	%r11,8(%rdx)
+ ___
+-$code.=<<___	if ($flavour =~ /elf32/);
++$code.=<<___	if (!$kernel && $flavour =~ /elf32/);
+ 	mov	%r10d,0(%rdx)
+ 	mov	%r11d,4(%rdx)
+ ___
+@@ -219,11 +298,11 @@ $code.=<<___;
+ 	mov	\$1,%eax
+ .Lno_key:
+ 	ret
+-.size	poly1305_init,.-poly1305_init
++___
++&end_function("poly1305_init_x86_64");
+ 
+-.type	poly1305_blocks,\@function,4
+-.align	32
+-poly1305_blocks:
++&declare_function("poly1305_blocks_x86_64", 32, 4);
++$code.=<<___;
+ .cfi_startproc
+ .Lblocks:
+ 	shr	\$4,$len
+@@ -231,8 +310,6 @@ poly1305_blocks:
+ 
+ 	push	%rbx
+ .cfi_push	%rbx
+-	push	%rbp
+-.cfi_push	%rbp
+ 	push	%r12
+ .cfi_push	%r12
+ 	push	%r13
+@@ -241,6 +318,8 @@ poly1305_blocks:
+ .cfi_push	%r14
+ 	push	%r15
+ .cfi_push	%r15
++	push	$ctx
++.cfi_push	$ctx
+ .Lblocks_body:
+ 
+ 	mov	$len,%r15		# reassign $len
+@@ -265,26 +344,29 @@ poly1305_blocks:
+ 	lea	16($inp),$inp
+ 	adc	$padbit,$h2
+ ___
++
+ 	&poly1305_iteration();
++
+ $code.=<<___;
+ 	mov	$r1,%rax
+ 	dec	%r15			# len-=16
+ 	jnz	.Loop
+ 
++	mov	0(%rsp),$ctx
++.cfi_restore	$ctx
++
+ 	mov	$h0,0($ctx)		# store hash value
+ 	mov	$h1,8($ctx)
+ 	mov	$h2,16($ctx)
+ 
+-	mov	0(%rsp),%r15
++	mov	8(%rsp),%r15
+ .cfi_restore	%r15
+-	mov	8(%rsp),%r14
++	mov	16(%rsp),%r14
+ .cfi_restore	%r14
+-	mov	16(%rsp),%r13
++	mov	24(%rsp),%r13
+ .cfi_restore	%r13
+-	mov	24(%rsp),%r12
++	mov	32(%rsp),%r12
+ .cfi_restore	%r12
+-	mov	32(%rsp),%rbp
+-.cfi_restore	%rbp
+ 	mov	40(%rsp),%rbx
+ .cfi_restore	%rbx
+ 	lea	48(%rsp),%rsp
+@@ -293,11 +375,11 @@ $code.=<<___;
+ .Lblocks_epilogue:
+ 	ret
+ .cfi_endproc
+-.size	poly1305_blocks,.-poly1305_blocks
++___
++&end_function("poly1305_blocks_x86_64");
+ 
+-.type	poly1305_emit,\@function,3
+-.align	32
+-poly1305_emit:
++&declare_function("poly1305_emit_x86_64", 32, 3);
++$code.=<<___;
+ .Lemit:
+ 	mov	0($ctx),%r8	# load hash value
+ 	mov	8($ctx),%r9
+@@ -318,10 +400,14 @@ poly1305_emit:
+ 	mov	%rcx,8($mac)
+ 
+ 	ret
+-.size	poly1305_emit,.-poly1305_emit
+ ___
++&end_function("poly1305_emit_x86_64");
+ if ($avx) {
+ 
++if($kernel) {
++	$code .= "#ifdef CONFIG_AS_AVX\n";
++}
++
+ ########################################################################
+ # Layout of opaque area is following.
+ #
+@@ -342,15 +428,19 @@ $code.=<<___;
+ .type	__poly1305_block,\@abi-omnipotent
+ .align	32
+ __poly1305_block:
++	push $ctx
+ ___
+ 	&poly1305_iteration();
+ $code.=<<___;
++	pop $ctx
+ 	ret
+ .size	__poly1305_block,.-__poly1305_block
+ 
+ .type	__poly1305_init_avx,\@abi-omnipotent
+ .align	32
+ __poly1305_init_avx:
++	push %rbp
++	mov %rsp,%rbp
+ 	mov	$r0,$h0
+ 	mov	$r1,$h1
+ 	xor	$h2,$h2
+@@ -507,12 +597,13 @@ __poly1305_init_avx:
+ 	mov	$d1#d,`16*8+8-64`($ctx)
+ 
+ 	lea	-48-64($ctx),$ctx	# size [de-]optimization
++	pop %rbp
+ 	ret
+ .size	__poly1305_init_avx,.-__poly1305_init_avx
++___
+ 
+-.type	poly1305_blocks_avx,\@function,4
+-.align	32
+-poly1305_blocks_avx:
++&declare_function("poly1305_blocks_avx", 32, 4);
++$code.=<<___;
+ .cfi_startproc
+ 	mov	20($ctx),%r8d		# is_base2_26
+ 	cmp	\$128,$len
+@@ -532,10 +623,11 @@ poly1305_blocks_avx:
+ 	test	\$31,$len
+ 	jz	.Leven_avx
+ 
+-	push	%rbx
+-.cfi_push	%rbx
+ 	push	%rbp
+ .cfi_push	%rbp
++	mov 	%rsp,%rbp
++	push	%rbx
++.cfi_push	%rbx
+ 	push	%r12
+ .cfi_push	%r12
+ 	push	%r13
+@@ -645,20 +737,18 @@ poly1305_blocks_avx:
+ 	mov	$h2#d,16($ctx)
+ .align	16
+ .Ldone_avx:
+-	mov	0(%rsp),%r15
++	pop 		%r15
+ .cfi_restore	%r15
+-	mov	8(%rsp),%r14
++	pop 		%r14
+ .cfi_restore	%r14
+-	mov	16(%rsp),%r13
++	pop 		%r13
+ .cfi_restore	%r13
+-	mov	24(%rsp),%r12
++	pop 		%r12
+ .cfi_restore	%r12
+-	mov	32(%rsp),%rbp
+-.cfi_restore	%rbp
+-	mov	40(%rsp),%rbx
++	pop 		%rbx
+ .cfi_restore	%rbx
+-	lea	48(%rsp),%rsp
+-.cfi_adjust_cfa_offset	-48
++	pop 		%rbp
++.cfi_restore	%rbp
+ .Lno_data_avx:
+ .Lblocks_avx_epilogue:
+ 	ret
+@@ -667,10 +757,11 @@ poly1305_blocks_avx:
+ .align	32
+ .Lbase2_64_avx:
+ .cfi_startproc
+-	push	%rbx
+-.cfi_push	%rbx
+ 	push	%rbp
+ .cfi_push	%rbp
++	mov 	%rsp,%rbp
++	push	%rbx
++.cfi_push	%rbx
+ 	push	%r12
+ .cfi_push	%r12
+ 	push	%r13
+@@ -736,22 +827,18 @@ poly1305_blocks_avx:
+ 
+ .Lproceed_avx:
+ 	mov	%r15,$len
+-
+-	mov	0(%rsp),%r15
++	pop 		%r15
+ .cfi_restore	%r15
+-	mov	8(%rsp),%r14
++	pop 		%r14
+ .cfi_restore	%r14
+-	mov	16(%rsp),%r13
++	pop 		%r13
+ .cfi_restore	%r13
+-	mov	24(%rsp),%r12
++	pop 		%r12
+ .cfi_restore	%r12
+-	mov	32(%rsp),%rbp
+-.cfi_restore	%rbp
+-	mov	40(%rsp),%rbx
++	pop 		%rbx
+ .cfi_restore	%rbx
+-	lea	48(%rsp),%rax
+-	lea	48(%rsp),%rsp
+-.cfi_adjust_cfa_offset	-48
++	pop 		%rbp
++.cfi_restore	%rbp
+ .Lbase2_64_avx_epilogue:
+ 	jmp	.Ldo_avx
+ .cfi_endproc
+@@ -768,8 +855,11 @@ poly1305_blocks_avx:
+ .Ldo_avx:
+ ___
+ $code.=<<___	if (!$win64);
++	lea		8(%rsp),%r10
++.cfi_def_cfa_register	%r10
++	and		\$-32,%rsp
++	sub		\$-8,%rsp
+ 	lea		-0x58(%rsp),%r11
+-.cfi_def_cfa		%r11,0x60
+ 	sub		\$0x178,%rsp
+ ___
+ $code.=<<___	if ($win64);
+@@ -1361,18 +1451,18 @@ $code.=<<___	if ($win64);
+ .Ldo_avx_epilogue:
+ ___
+ $code.=<<___	if (!$win64);
+-	lea		0x58(%r11),%rsp
+-.cfi_def_cfa		%rsp,8
++	lea		-8(%r10),%rsp
++.cfi_def_cfa_register	%rsp
+ ___
+ $code.=<<___;
+ 	vzeroupper
+ 	ret
+ .cfi_endproc
+-.size	poly1305_blocks_avx,.-poly1305_blocks_avx
++___
++&end_function("poly1305_blocks_avx");
+ 
+-.type	poly1305_emit_avx,\@function,3
+-.align	32
+-poly1305_emit_avx:
++&declare_function("poly1305_emit_avx", 32, 3);
++$code.=<<___;
+ 	cmpl	\$0,20($ctx)	# is_base2_26?
+ 	je	.Lemit
+ 
+@@ -1423,41 +1513,51 @@ poly1305_emit_avx:
+ 	mov	%rcx,8($mac)
+ 
+ 	ret
+-.size	poly1305_emit_avx,.-poly1305_emit_avx
+ ___
++&end_function("poly1305_emit_avx");
++
++if ($kernel) {
++	$code .= "#endif\n";
++}
+ 
+ if ($avx>1) {
++
++if ($kernel) {
++	$code .= "#ifdef CONFIG_AS_AVX2\n";
++}
++
+ my ($H0,$H1,$H2,$H3,$H4, $MASK, $T4,$T0,$T1,$T2,$T3, $D0,$D1,$D2,$D3,$D4) =
+     map("%ymm$_",(0..15));
+ my $S4=$MASK;
+ 
++sub poly1305_blocks_avxN {
++	my ($avx512) = @_;
++	my $suffix = $avx512 ? "_avx512" : "";
+ $code.=<<___;
+-.type	poly1305_blocks_avx2,\@function,4
+-.align	32
+-poly1305_blocks_avx2:
+ .cfi_startproc
+ 	mov	20($ctx),%r8d		# is_base2_26
+ 	cmp	\$128,$len
+-	jae	.Lblocks_avx2
++	jae	.Lblocks_avx2$suffix
+ 	test	%r8d,%r8d
+ 	jz	.Lblocks
+ 
+-.Lblocks_avx2:
++.Lblocks_avx2$suffix:
+ 	and	\$-16,$len
+-	jz	.Lno_data_avx2
++	jz	.Lno_data_avx2$suffix
+ 
+ 	vzeroupper
+ 
+ 	test	%r8d,%r8d
+-	jz	.Lbase2_64_avx2
++	jz	.Lbase2_64_avx2$suffix
+ 
+ 	test	\$63,$len
+-	jz	.Leven_avx2
++	jz	.Leven_avx2$suffix
+ 
+-	push	%rbx
+-.cfi_push	%rbx
+ 	push	%rbp
+ .cfi_push	%rbp
++	mov 	%rsp,%rbp
++	push	%rbx
++.cfi_push	%rbx
+ 	push	%r12
+ .cfi_push	%r12
+ 	push	%r13
+@@ -1466,7 +1566,7 @@ poly1305_blocks_avx2:
+ .cfi_push	%r14
+ 	push	%r15
+ .cfi_push	%r15
+-.Lblocks_avx2_body:
++.Lblocks_avx2_body$suffix:
+ 
+ 	mov	$len,%r15		# reassign $len
+ 
+@@ -1513,7 +1613,7 @@ poly1305_blocks_avx2:
+ 	shr	\$2,$s1
+ 	add	$r1,$s1			# s1 = r1 + (r1 >> 2)
+ 
+-.Lbase2_26_pre_avx2:
++.Lbase2_26_pre_avx2$suffix:
+ 	add	0($inp),$h0		# accumulate input
+ 	adc	8($inp),$h1
+ 	lea	16($inp),$inp
+@@ -1524,10 +1624,10 @@ poly1305_blocks_avx2:
+ 	mov	$r1,%rax
+ 
+ 	test	\$63,%r15
+-	jnz	.Lbase2_26_pre_avx2
++	jnz	.Lbase2_26_pre_avx2$suffix
+ 
+ 	test	$padbit,$padbit		# if $padbit is zero,
+-	jz	.Lstore_base2_64_avx2	# store hash in base 2^64 format
++	jz	.Lstore_base2_64_avx2$suffix	# store hash in base 2^64 format
+ 
+ 	################################# base 2^64 -> base 2^26
+ 	mov	$h0,%rax
+@@ -1548,57 +1648,56 @@ poly1305_blocks_avx2:
+ 	or	$r1,$h2			# h[4]
+ 
+ 	test	%r15,%r15
+-	jz	.Lstore_base2_26_avx2
++	jz	.Lstore_base2_26_avx2$suffix
+ 
+ 	vmovd	%rax#d,%x#$H0
+ 	vmovd	%rdx#d,%x#$H1
+ 	vmovd	$h0#d,%x#$H2
+ 	vmovd	$h1#d,%x#$H3
+ 	vmovd	$h2#d,%x#$H4
+-	jmp	.Lproceed_avx2
++	jmp	.Lproceed_avx2$suffix
+ 
+ .align	32
+-.Lstore_base2_64_avx2:
++.Lstore_base2_64_avx2$suffix:
+ 	mov	$h0,0($ctx)
+ 	mov	$h1,8($ctx)
+ 	mov	$h2,16($ctx)		# note that is_base2_26 is zeroed
+-	jmp	.Ldone_avx2
++	jmp	.Ldone_avx2$suffix
+ 
+ .align	16
+-.Lstore_base2_26_avx2:
++.Lstore_base2_26_avx2$suffix:
+ 	mov	%rax#d,0($ctx)		# store hash value base 2^26
+ 	mov	%rdx#d,4($ctx)
+ 	mov	$h0#d,8($ctx)
+ 	mov	$h1#d,12($ctx)
+ 	mov	$h2#d,16($ctx)
+ .align	16
+-.Ldone_avx2:
+-	mov	0(%rsp),%r15
++.Ldone_avx2$suffix:
++	pop 		%r15
+ .cfi_restore	%r15
+-	mov	8(%rsp),%r14
++	pop 		%r14
+ .cfi_restore	%r14
+-	mov	16(%rsp),%r13
++	pop 		%r13
+ .cfi_restore	%r13
+-	mov	24(%rsp),%r12
++	pop 		%r12
+ .cfi_restore	%r12
+-	mov	32(%rsp),%rbp
+-.cfi_restore	%rbp
+-	mov	40(%rsp),%rbx
++	pop 		%rbx
+ .cfi_restore	%rbx
+-	lea	48(%rsp),%rsp
+-.cfi_adjust_cfa_offset	-48
+-.Lno_data_avx2:
+-.Lblocks_avx2_epilogue:
++	pop 		%rbp
++.cfi_restore 	%rbp
++.Lno_data_avx2$suffix:
++.Lblocks_avx2_epilogue$suffix:
+ 	ret
+ .cfi_endproc
+ 
+ .align	32
+-.Lbase2_64_avx2:
++.Lbase2_64_avx2$suffix:
+ .cfi_startproc
+-	push	%rbx
+-.cfi_push	%rbx
+ 	push	%rbp
+ .cfi_push	%rbp
++	mov 	%rsp,%rbp
++	push	%rbx
++.cfi_push	%rbx
+ 	push	%r12
+ .cfi_push	%r12
+ 	push	%r13
+@@ -1607,7 +1706,7 @@ poly1305_blocks_avx2:
+ .cfi_push	%r14
+ 	push	%r15
+ .cfi_push	%r15
+-.Lbase2_64_avx2_body:
++.Lbase2_64_avx2_body$suffix:
+ 
+ 	mov	$len,%r15		# reassign $len
+ 
+@@ -1624,9 +1723,9 @@ poly1305_blocks_avx2:
+ 	add	$r1,$s1			# s1 = r1 + (r1 >> 2)
+ 
+ 	test	\$63,$len
+-	jz	.Linit_avx2
++	jz	.Linit_avx2$suffix
+ 
+-.Lbase2_64_pre_avx2:
++.Lbase2_64_pre_avx2$suffix:
+ 	add	0($inp),$h0		# accumulate input
+ 	adc	8($inp),$h1
+ 	lea	16($inp),$inp
+@@ -1637,9 +1736,9 @@ poly1305_blocks_avx2:
+ 	mov	$r1,%rax
+ 
+ 	test	\$63,%r15
+-	jnz	.Lbase2_64_pre_avx2
++	jnz	.Lbase2_64_pre_avx2$suffix
+ 
+-.Linit_avx2:
++.Linit_avx2$suffix:
+ 	################################# base 2^64 -> base 2^26
+ 	mov	$h0,%rax
+ 	mov	$h0,%rdx
+@@ -1667,69 +1766,77 @@ poly1305_blocks_avx2:
+ 
+ 	call	__poly1305_init_avx
+ 
+-.Lproceed_avx2:
++.Lproceed_avx2$suffix:
+ 	mov	%r15,$len			# restore $len
+-	mov	OPENSSL_ia32cap_P+8(%rip),%r10d
++___
++$code.=<<___ if (!$kernel);
++	mov	OPENSSL_ia32cap_P+8(%rip),%r9d
+ 	mov	\$`(1<<31|1<<30|1<<16)`,%r11d
+-
+-	mov	0(%rsp),%r15
++___
++$code.=<<___;
++	pop 		%r15
+ .cfi_restore	%r15
+-	mov	8(%rsp),%r14
++	pop 		%r14
+ .cfi_restore	%r14
+-	mov	16(%rsp),%r13
++	pop 		%r13
+ .cfi_restore	%r13
+-	mov	24(%rsp),%r12
++	pop 		%r12
+ .cfi_restore	%r12
+-	mov	32(%rsp),%rbp
+-.cfi_restore	%rbp
+-	mov	40(%rsp),%rbx
++	pop 		%rbx
+ .cfi_restore	%rbx
+-	lea	48(%rsp),%rax
+-	lea	48(%rsp),%rsp
+-.cfi_adjust_cfa_offset	-48
+-.Lbase2_64_avx2_epilogue:
+-	jmp	.Ldo_avx2
++	pop 		%rbp
++.cfi_restore 	%rbp
++.Lbase2_64_avx2_epilogue$suffix:
++	jmp	.Ldo_avx2$suffix
+ .cfi_endproc
+ 
+ .align	32
+-.Leven_avx2:
++.Leven_avx2$suffix:
+ .cfi_startproc
+-	mov		OPENSSL_ia32cap_P+8(%rip),%r10d
++___
++$code.=<<___ if (!$kernel);
++	mov		OPENSSL_ia32cap_P+8(%rip),%r9d
++___
++$code.=<<___;
+ 	vmovd		4*0($ctx),%x#$H0	# load hash value base 2^26
+ 	vmovd		4*1($ctx),%x#$H1
+ 	vmovd		4*2($ctx),%x#$H2
+ 	vmovd		4*3($ctx),%x#$H3
+ 	vmovd		4*4($ctx),%x#$H4
+ 
+-.Ldo_avx2:
++.Ldo_avx2$suffix:
+ ___
+-$code.=<<___		if ($avx>2);
++$code.=<<___		if (!$kernel && $avx>2);
+ 	cmp		\$512,$len
+ 	jb		.Lskip_avx512
+-	and		%r11d,%r10d
+-	test		\$`1<<16`,%r10d		# check for AVX512F
++	and		%r11d,%r9d
++	test		\$`1<<16`,%r9d		# check for AVX512F
+ 	jnz		.Lblocks_avx512
+-.Lskip_avx512:
++.Lskip_avx512$suffix:
++___
++$code.=<<___ if ($avx > 2 && $avx512 && $kernel);
++	cmp		\$512,$len
++	jae		.Lblocks_avx512
+ ___
+ $code.=<<___	if (!$win64);
+-	lea		-8(%rsp),%r11
+-.cfi_def_cfa		%r11,16
++	lea		8(%rsp),%r10
++.cfi_def_cfa_register	%r10
+ 	sub		\$0x128,%rsp
+ ___
+ $code.=<<___	if ($win64);
+-	lea		-0xf8(%rsp),%r11
++	lea		8(%rsp),%r10
+ 	sub		\$0x1c8,%rsp
+-	vmovdqa		%xmm6,0x50(%r11)
+-	vmovdqa		%xmm7,0x60(%r11)
+-	vmovdqa		%xmm8,0x70(%r11)
+-	vmovdqa		%xmm9,0x80(%r11)
+-	vmovdqa		%xmm10,0x90(%r11)
+-	vmovdqa		%xmm11,0xa0(%r11)
+-	vmovdqa		%xmm12,0xb0(%r11)
+-	vmovdqa		%xmm13,0xc0(%r11)
+-	vmovdqa		%xmm14,0xd0(%r11)
+-	vmovdqa		%xmm15,0xe0(%r11)
+-.Ldo_avx2_body:
++	vmovdqa		%xmm6,-0xb0(%r10)
++	vmovdqa		%xmm7,-0xa0(%r10)
++	vmovdqa		%xmm8,-0x90(%r10)
++	vmovdqa		%xmm9,-0x80(%r10)
++	vmovdqa		%xmm10,-0x70(%r10)
++	vmovdqa		%xmm11,-0x60(%r10)
++	vmovdqa		%xmm12,-0x50(%r10)
++	vmovdqa		%xmm13,-0x40(%r10)
++	vmovdqa		%xmm14,-0x30(%r10)
++	vmovdqa		%xmm15,-0x20(%r10)
++.Ldo_avx2_body$suffix:
+ ___
+ $code.=<<___;
+ 	lea		.Lconst(%rip),%rcx
+@@ -1794,11 +1901,11 @@ $code.=<<___;
+ 
+ 	vpaddq		$H2,$T2,$H2		# accumulate input
+ 	sub		\$64,$len
+-	jz		.Ltail_avx2
+-	jmp		.Loop_avx2
++	jz		.Ltail_avx2$suffix
++	jmp		.Loop_avx2$suffix
+ 
+ .align	32
+-.Loop_avx2:
++.Loop_avx2$suffix:
+ 	################################################################
+ 	# ((inp[0]*r^4+inp[4])*r^4+inp[ 8])*r^4
+ 	# ((inp[1]*r^4+inp[5])*r^4+inp[ 9])*r^3
+@@ -1946,10 +2053,10 @@ $code.=<<___;
+ 	 vpor		32(%rcx),$T4,$T4	# padbit, yes, always
+ 
+ 	sub		\$64,$len
+-	jnz		.Loop_avx2
++	jnz		.Loop_avx2$suffix
+ 
+ 	.byte		0x66,0x90
+-.Ltail_avx2:
++.Ltail_avx2$suffix:
+ 	################################################################
+ 	# while above multiplications were by r^4 in all lanes, in last
+ 	# iteration we multiply least significant lane by r^4 and most
+@@ -2087,37 +2194,29 @@ $code.=<<___;
+ 	vmovd		%x#$H4,`4*4-48-64`($ctx)
+ ___
+ $code.=<<___	if ($win64);
+-	vmovdqa		0x50(%r11),%xmm6
+-	vmovdqa		0x60(%r11),%xmm7
+-	vmovdqa		0x70(%r11),%xmm8
+-	vmovdqa		0x80(%r11),%xmm9
+-	vmovdqa		0x90(%r11),%xmm10
+-	vmovdqa		0xa0(%r11),%xmm11
+-	vmovdqa		0xb0(%r11),%xmm12
+-	vmovdqa		0xc0(%r11),%xmm13
+-	vmovdqa		0xd0(%r11),%xmm14
+-	vmovdqa		0xe0(%r11),%xmm15
+-	lea		0xf8(%r11),%rsp
+-.Ldo_avx2_epilogue:
++	vmovdqa		-0xb0(%r10),%xmm6
++	vmovdqa		-0xa0(%r10),%xmm7
++	vmovdqa		-0x90(%r10),%xmm8
++	vmovdqa		-0x80(%r10),%xmm9
++	vmovdqa		-0x70(%r10),%xmm10
++	vmovdqa		-0x60(%r10),%xmm11
++	vmovdqa		-0x50(%r10),%xmm12
++	vmovdqa		-0x40(%r10),%xmm13
++	vmovdqa		-0x30(%r10),%xmm14
++	vmovdqa		-0x20(%r10),%xmm15
++	lea		-8(%r10),%rsp
++.Ldo_avx2_epilogue$suffix:
+ ___
+ $code.=<<___	if (!$win64);
+-	lea		8(%r11),%rsp
+-.cfi_def_cfa		%rsp,8
++	lea		-8(%r10),%rsp
++.cfi_def_cfa_register	%rsp
+ ___
+ $code.=<<___;
+ 	vzeroupper
+ 	ret
+ .cfi_endproc
+-.size	poly1305_blocks_avx2,.-poly1305_blocks_avx2
+ ___
+-#######################################################################
+-if ($avx>2) {
+-# On entry we have input length divisible by 64. But since inner loop
+-# processes 128 bytes per iteration, cases when length is not divisible
+-# by 128 are handled by passing tail 64 bytes to .Ltail_avx2. For this
+-# reason stack layout is kept identical to poly1305_blocks_avx2. If not
+-# for this tail, we wouldn't have to even allocate stack frame...
+-
++if($avx > 2 && $avx512) {
+ my ($R0,$R1,$R2,$R3,$R4, $S1,$S2,$S3,$S4) = map("%zmm$_",(16..24));
+ my ($M0,$M1,$M2,$M3,$M4) = map("%zmm$_",(25..29));
+ my $PADBIT="%zmm30";
+@@ -2128,32 +2227,29 @@ map(s/%y/%z/,($H0,$H1,$H2,$H3,$H4));
+ map(s/%y/%z/,($MASK));
+ 
+ $code.=<<___;
+-.type	poly1305_blocks_avx512,\@function,4
+-.align	32
+-poly1305_blocks_avx512:
+ .cfi_startproc
+ .Lblocks_avx512:
+ 	mov		\$15,%eax
+ 	kmovw		%eax,%k2
+ ___
+ $code.=<<___	if (!$win64);
+-	lea		-8(%rsp),%r11
+-.cfi_def_cfa		%r11,16
++	lea		8(%rsp),%r10
++.cfi_def_cfa_register	%r10
+ 	sub		\$0x128,%rsp
+ ___
+ $code.=<<___	if ($win64);
+-	lea		-0xf8(%rsp),%r11
++	lea		8(%rsp),%r10
+ 	sub		\$0x1c8,%rsp
+-	vmovdqa		%xmm6,0x50(%r11)
+-	vmovdqa		%xmm7,0x60(%r11)
+-	vmovdqa		%xmm8,0x70(%r11)
+-	vmovdqa		%xmm9,0x80(%r11)
+-	vmovdqa		%xmm10,0x90(%r11)
+-	vmovdqa		%xmm11,0xa0(%r11)
+-	vmovdqa		%xmm12,0xb0(%r11)
+-	vmovdqa		%xmm13,0xc0(%r11)
+-	vmovdqa		%xmm14,0xd0(%r11)
+-	vmovdqa		%xmm15,0xe0(%r11)
++	vmovdqa		%xmm6,-0xb0(%r10)
++	vmovdqa		%xmm7,-0xa0(%r10)
++	vmovdqa		%xmm8,-0x90(%r10)
++	vmovdqa		%xmm9,-0x80(%r10)
++	vmovdqa		%xmm10,-0x70(%r10)
++	vmovdqa		%xmm11,-0x60(%r10)
++	vmovdqa		%xmm12,-0x50(%r10)
++	vmovdqa		%xmm13,-0x40(%r10)
++	vmovdqa		%xmm14,-0x30(%r10)
++	vmovdqa		%xmm15,-0x20(%r10)
+ .Ldo_avx512_body:
+ ___
+ $code.=<<___;
+@@ -2679,7 +2775,7 @@ $code.=<<___;
+ 
+ 	lea		0x90(%rsp),%rax		# size optimization for .Ltail_avx2
+ 	add		\$64,$len
+-	jnz		.Ltail_avx2
++	jnz		.Ltail_avx2$suffix
+ 
+ 	vpsubq		$T2,$H2,$H2		# undo input accumulation
+ 	vmovd		%x#$H0,`4*0-48-64`($ctx)# save partially reduced
+@@ -2690,29 +2786,61 @@ $code.=<<___;
+ 	vzeroall
+ ___
+ $code.=<<___	if ($win64);
+-	movdqa		0x50(%r11),%xmm6
+-	movdqa		0x60(%r11),%xmm7
+-	movdqa		0x70(%r11),%xmm8
+-	movdqa		0x80(%r11),%xmm9
+-	movdqa		0x90(%r11),%xmm10
+-	movdqa		0xa0(%r11),%xmm11
+-	movdqa		0xb0(%r11),%xmm12
+-	movdqa		0xc0(%r11),%xmm13
+-	movdqa		0xd0(%r11),%xmm14
+-	movdqa		0xe0(%r11),%xmm15
+-	lea		0xf8(%r11),%rsp
++	movdqa		-0xb0(%r10),%xmm6
++	movdqa		-0xa0(%r10),%xmm7
++	movdqa		-0x90(%r10),%xmm8
++	movdqa		-0x80(%r10),%xmm9
++	movdqa		-0x70(%r10),%xmm10
++	movdqa		-0x60(%r10),%xmm11
++	movdqa		-0x50(%r10),%xmm12
++	movdqa		-0x40(%r10),%xmm13
++	movdqa		-0x30(%r10),%xmm14
++	movdqa		-0x20(%r10),%xmm15
++	lea		-8(%r10),%rsp
+ .Ldo_avx512_epilogue:
+ ___
+ $code.=<<___	if (!$win64);
+-	lea		8(%r11),%rsp
+-.cfi_def_cfa		%rsp,8
++	lea		-8(%r10),%rsp
++.cfi_def_cfa_register	%rsp
+ ___
+ $code.=<<___;
+ 	ret
+ .cfi_endproc
+-.size	poly1305_blocks_avx512,.-poly1305_blocks_avx512
+ ___
+-if ($avx>3) {
++
++}
++
++}
++
++&declare_function("poly1305_blocks_avx2", 32, 4);
++poly1305_blocks_avxN(0);
++&end_function("poly1305_blocks_avx2");
++
++if($kernel) {
++	$code .= "#endif\n";
++}
++
++#######################################################################
++if ($avx>2) {
++# On entry we have input length divisible by 64. But since inner loop
++# processes 128 bytes per iteration, cases when length is not divisible
++# by 128 are handled by passing tail 64 bytes to .Ltail_avx2. For this
++# reason stack layout is kept identical to poly1305_blocks_avx2. If not
++# for this tail, we wouldn't have to even allocate stack frame...
++
++if($kernel) {
++	$code .= "#ifdef CONFIG_AS_AVX512\n";
++}
++
++&declare_function("poly1305_blocks_avx512", 32, 4);
++poly1305_blocks_avxN(1);
++&end_function("poly1305_blocks_avx512");
++
++if ($kernel) {
++	$code .= "#endif\n";
++}
++
++if (!$kernel && $avx>3) {
+ ########################################################################
+ # VPMADD52 version using 2^44 radix.
+ #
+@@ -3753,45 +3881,9 @@ poly1305_emit_base2_44:
+ .size	poly1305_emit_base2_44,.-poly1305_emit_base2_44
+ ___
+ }	}	}
+-$code.=<<___;
+-.align	64
+-.Lconst:
+-.Lmask24:
+-.long	0x0ffffff,0,0x0ffffff,0,0x0ffffff,0,0x0ffffff,0
+-.L129:
+-.long	`1<<24`,0,`1<<24`,0,`1<<24`,0,`1<<24`,0
+-.Lmask26:
+-.long	0x3ffffff,0,0x3ffffff,0,0x3ffffff,0,0x3ffffff,0
+-.Lpermd_avx2:
+-.long	2,2,2,3,2,0,2,1
+-.Lpermd_avx512:
+-.long	0,0,0,1, 0,2,0,3, 0,4,0,5, 0,6,0,7
+-
+-.L2_44_inp_permd:
+-.long	0,1,1,2,2,3,7,7
+-.L2_44_inp_shift:
+-.quad	0,12,24,64
+-.L2_44_mask:
+-.quad	0xfffffffffff,0xfffffffffff,0x3ffffffffff,0xffffffffffffffff
+-.L2_44_shift_rgt:
+-.quad	44,44,42,64
+-.L2_44_shift_lft:
+-.quad	8,8,10,64
+-
+-.align	64
+-.Lx_mask44:
+-.quad	0xfffffffffff,0xfffffffffff,0xfffffffffff,0xfffffffffff
+-.quad	0xfffffffffff,0xfffffffffff,0xfffffffffff,0xfffffffffff
+-.Lx_mask42:
+-.quad	0x3ffffffffff,0x3ffffffffff,0x3ffffffffff,0x3ffffffffff
+-.quad	0x3ffffffffff,0x3ffffffffff,0x3ffffffffff,0x3ffffffffff
+-___
+ }
+-$code.=<<___;
+-.asciz	"Poly1305 for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
+-.align	16
+-___
+ 
++if (!$kernel)
+ {	# chacha20-poly1305 helpers
+ my ($out,$inp,$otp,$len)=$win64 ? ("%rcx","%rdx","%r8", "%r9") :  # Win64 order
+                                   ("%rdi","%rsi","%rdx","%rcx");  # Unix order
+@@ -4038,17 +4130,17 @@ avx_handler:
+ 
+ .section	.pdata
+ .align	4
+-	.rva	.LSEH_begin_poly1305_init
+-	.rva	.LSEH_end_poly1305_init
+-	.rva	.LSEH_info_poly1305_init
+-
+-	.rva	.LSEH_begin_poly1305_blocks
+-	.rva	.LSEH_end_poly1305_blocks
+-	.rva	.LSEH_info_poly1305_blocks
+-
+-	.rva	.LSEH_begin_poly1305_emit
+-	.rva	.LSEH_end_poly1305_emit
+-	.rva	.LSEH_info_poly1305_emit
++	.rva	.LSEH_begin_poly1305_init_x86_64
++	.rva	.LSEH_end_poly1305_init_x86_64
++	.rva	.LSEH_info_poly1305_init_x86_64
++
++	.rva	.LSEH_begin_poly1305_blocks_x86_64
++	.rva	.LSEH_end_poly1305_blocks_x86_64
++	.rva	.LSEH_info_poly1305_blocks_x86_64
++
++	.rva	.LSEH_begin_poly1305_emit_x86_64
++	.rva	.LSEH_end_poly1305_emit_x86_64
++	.rva	.LSEH_info_poly1305_emit_x86_64
+ ___
+ $code.=<<___ if ($avx);
+ 	.rva	.LSEH_begin_poly1305_blocks_avx
+@@ -4088,20 +4180,20 @@ ___
+ $code.=<<___;
+ .section	.xdata
+ .align	8
+-.LSEH_info_poly1305_init:
++.LSEH_info_poly1305_init_x86_64:
+ 	.byte	9,0,0,0
+ 	.rva	se_handler
+-	.rva	.LSEH_begin_poly1305_init,.LSEH_begin_poly1305_init
++	.rva	.LSEH_begin_poly1305_init_x86_64,.LSEH_begin_poly1305_init_x86_64
+ 
+-.LSEH_info_poly1305_blocks:
++.LSEH_info_poly1305_blocks_x86_64:
+ 	.byte	9,0,0,0
+ 	.rva	se_handler
+ 	.rva	.Lblocks_body,.Lblocks_epilogue
+ 
+-.LSEH_info_poly1305_emit:
++.LSEH_info_poly1305_emit_x86_64:
+ 	.byte	9,0,0,0
+ 	.rva	se_handler
+-	.rva	.LSEH_begin_poly1305_emit,.LSEH_begin_poly1305_emit
++	.rva	.LSEH_begin_poly1305_emit_x86_64,.LSEH_begin_poly1305_emit_x86_64
+ ___
+ $code.=<<___ if ($avx);
+ .LSEH_info_poly1305_blocks_avx_1:
+@@ -4148,12 +4240,26 @@ $code.=<<___ if ($avx>2);
+ ___
+ }
+ 
++open SELF,$0;
++while(<SELF>) {
++	next if (/^#!/);
++	last if (!s/^#/\/\// and !/^$/);
++	print;
++}
++close SELF;
++
+ foreach (split('\n',$code)) {
+ 	s/\`([^\`]*)\`/eval($1)/ge;
+ 	s/%r([a-z]+)#d/%e$1/g;
+ 	s/%r([0-9]+)#d/%r$1d/g;
+ 	s/%x#%[yz]/%x/g or s/%y#%z/%y/g or s/%z#%[yz]/%z/g;
+ 
++	if ($kernel) {
++		s/(^\.type.*),[0-9]+$/\1/;
++		s/(^\.type.*),\@abi-omnipotent+$/\1,\@function/;
++		next if /^\.cfi.*/;
++	}
++
+ 	print $_,"\n";
+ }
+ close STDOUT;
+--- a/arch/x86/crypto/poly1305_glue.c
++++ b/arch/x86/crypto/poly1305_glue.c
+@@ -1,8 +1,6 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
++// SPDX-License-Identifier: GPL-2.0 OR MIT
+ /*
+- * Poly1305 authenticator algorithm, RFC7539, SIMD glue code
+- *
+- * Copyright (C) 2015 Martin Willi
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+  */
+ 
+ #include <crypto/algapi.h>
+@@ -13,279 +11,170 @@
+ #include <linux/jump_label.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
++#include <asm/intel-family.h>
+ #include <asm/simd.h>
+ 
+-asmlinkage void poly1305_block_sse2(u32 *h, const u8 *src,
+-				    const u32 *r, unsigned int blocks);
+-asmlinkage void poly1305_2block_sse2(u32 *h, const u8 *src, const u32 *r,
+-				     unsigned int blocks, const u32 *u);
+-asmlinkage void poly1305_4block_avx2(u32 *h, const u8 *src, const u32 *r,
+-				     unsigned int blocks, const u32 *u);
++asmlinkage void poly1305_init_x86_64(void *ctx,
++				     const u8 key[POLY1305_KEY_SIZE]);
++asmlinkage void poly1305_blocks_x86_64(void *ctx, const u8 *inp,
++				       const size_t len, const u32 padbit);
++asmlinkage void poly1305_emit_x86_64(void *ctx, u8 mac[POLY1305_DIGEST_SIZE],
++				     const u32 nonce[4]);
++asmlinkage void poly1305_emit_avx(void *ctx, u8 mac[POLY1305_DIGEST_SIZE],
++				  const u32 nonce[4]);
++asmlinkage void poly1305_blocks_avx(void *ctx, const u8 *inp, const size_t len,
++				    const u32 padbit);
++asmlinkage void poly1305_blocks_avx2(void *ctx, const u8 *inp, const size_t len,
++				     const u32 padbit);
++asmlinkage void poly1305_blocks_avx512(void *ctx, const u8 *inp,
++				       const size_t len, const u32 padbit);
+ 
+-static __ro_after_init DEFINE_STATIC_KEY_FALSE(poly1305_use_simd);
++static __ro_after_init DEFINE_STATIC_KEY_FALSE(poly1305_use_avx);
+ static __ro_after_init DEFINE_STATIC_KEY_FALSE(poly1305_use_avx2);
++static __ro_after_init DEFINE_STATIC_KEY_FALSE(poly1305_use_avx512);
+ 
+-static inline u64 mlt(u64 a, u64 b)
+-{
+-	return a * b;
+-}
+-
+-static inline u32 sr(u64 v, u_char n)
+-{
+-	return v >> n;
+-}
+-
+-static inline u32 and(u32 v, u32 mask)
+-{
+-	return v & mask;
+-}
+-
+-static void poly1305_simd_mult(u32 *a, const u32 *b)
+-{
+-	u8 m[POLY1305_BLOCK_SIZE];
+-
+-	memset(m, 0, sizeof(m));
+-	/* The poly1305 block function adds a hi-bit to the accumulator which
+-	 * we don't need for key multiplication; compensate for it. */
+-	a[4] -= 1 << 24;
+-	poly1305_block_sse2(a, m, b, 1);
+-}
+-
+-static void poly1305_integer_setkey(struct poly1305_key *key, const u8 *raw_key)
+-{
+-	/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
+-	key->r[0] = (get_unaligned_le32(raw_key +  0) >> 0) & 0x3ffffff;
+-	key->r[1] = (get_unaligned_le32(raw_key +  3) >> 2) & 0x3ffff03;
+-	key->r[2] = (get_unaligned_le32(raw_key +  6) >> 4) & 0x3ffc0ff;
+-	key->r[3] = (get_unaligned_le32(raw_key +  9) >> 6) & 0x3f03fff;
+-	key->r[4] = (get_unaligned_le32(raw_key + 12) >> 8) & 0x00fffff;
+-}
++struct poly1305_arch_internal {
++	union {
++		struct {
++			u32 h[5];
++			u32 is_base2_26;
++		};
++		u64 hs[3];
++	};
++	u64 r[2];
++	u64 pad;
++	struct { u32 r2, r1, r4, r3; } rn[9];
++};
+ 
+-static void poly1305_integer_blocks(struct poly1305_state *state,
+-				    const struct poly1305_key *key,
+-				    const void *src,
+-				    unsigned int nblocks, u32 hibit)
++/* The AVX code uses base 2^26, while the scalar code uses base 2^64. If we hit
++ * the unfortunate situation of using AVX and then having to go back to scalar
++ * -- because the user is silly and has called the update function from two
++ * separate contexts -- then we need to convert back to the original base before
++ * proceeding. It is possible to reason that the initial reduction below is
++ * sufficient given the implementation invariants. However, for an avoidance of
++ * doubt and because this is not performance critical, we do the full reduction
++ * anyway. Z3 proof of below function: https://xn--4db.cc/ltPtHCKN/py
++ */
++static void convert_to_base2_64(void *ctx)
+ {
+-	u32 r0, r1, r2, r3, r4;
+-	u32 s1, s2, s3, s4;
+-	u32 h0, h1, h2, h3, h4;
+-	u64 d0, d1, d2, d3, d4;
++	struct poly1305_arch_internal *state = ctx;
++	u32 cy;
+ 
+-	if (!nblocks)
++	if (!state->is_base2_26)
+ 		return;
+ 
+-	r0 = key->r[0];
+-	r1 = key->r[1];
+-	r2 = key->r[2];
+-	r3 = key->r[3];
+-	r4 = key->r[4];
+-
+-	s1 = r1 * 5;
+-	s2 = r2 * 5;
+-	s3 = r3 * 5;
+-	s4 = r4 * 5;
+-
+-	h0 = state->h[0];
+-	h1 = state->h[1];
+-	h2 = state->h[2];
+-	h3 = state->h[3];
+-	h4 = state->h[4];
+-
+-	do {
+-		/* h += m[i] */
+-		h0 += (get_unaligned_le32(src +  0) >> 0) & 0x3ffffff;
+-		h1 += (get_unaligned_le32(src +  3) >> 2) & 0x3ffffff;
+-		h2 += (get_unaligned_le32(src +  6) >> 4) & 0x3ffffff;
+-		h3 += (get_unaligned_le32(src +  9) >> 6) & 0x3ffffff;
+-		h4 += (get_unaligned_le32(src + 12) >> 8) | (hibit << 24);
+-
+-		/* h *= r */
+-		d0 = mlt(h0, r0) + mlt(h1, s4) + mlt(h2, s3) +
+-		     mlt(h3, s2) + mlt(h4, s1);
+-		d1 = mlt(h0, r1) + mlt(h1, r0) + mlt(h2, s4) +
+-		     mlt(h3, s3) + mlt(h4, s2);
+-		d2 = mlt(h0, r2) + mlt(h1, r1) + mlt(h2, r0) +
+-		     mlt(h3, s4) + mlt(h4, s3);
+-		d3 = mlt(h0, r3) + mlt(h1, r2) + mlt(h2, r1) +
+-		     mlt(h3, r0) + mlt(h4, s4);
+-		d4 = mlt(h0, r4) + mlt(h1, r3) + mlt(h2, r2) +
+-		     mlt(h3, r1) + mlt(h4, r0);
+-
+-		/* (partial) h %= p */
+-		d1 += sr(d0, 26);     h0 = and(d0, 0x3ffffff);
+-		d2 += sr(d1, 26);     h1 = and(d1, 0x3ffffff);
+-		d3 += sr(d2, 26);     h2 = and(d2, 0x3ffffff);
+-		d4 += sr(d3, 26);     h3 = and(d3, 0x3ffffff);
+-		h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff);
+-		h1 += h0 >> 26;       h0 = h0 & 0x3ffffff;
+-
+-		src += POLY1305_BLOCK_SIZE;
+-	} while (--nblocks);
+-
+-	state->h[0] = h0;
+-	state->h[1] = h1;
+-	state->h[2] = h2;
+-	state->h[3] = h3;
+-	state->h[4] = h4;
+-}
+-
+-static void poly1305_integer_emit(const struct poly1305_state *state, void *dst)
+-{
+-	u32 h0, h1, h2, h3, h4;
+-	u32 g0, g1, g2, g3, g4;
+-	u32 mask;
+-
+-	/* fully carry h */
+-	h0 = state->h[0];
+-	h1 = state->h[1];
+-	h2 = state->h[2];
+-	h3 = state->h[3];
+-	h4 = state->h[4];
+-
+-	h2 += (h1 >> 26);     h1 = h1 & 0x3ffffff;
+-	h3 += (h2 >> 26);     h2 = h2 & 0x3ffffff;
+-	h4 += (h3 >> 26);     h3 = h3 & 0x3ffffff;
+-	h0 += (h4 >> 26) * 5; h4 = h4 & 0x3ffffff;
+-	h1 += (h0 >> 26);     h0 = h0 & 0x3ffffff;
+-
+-	/* compute h + -p */
+-	g0 = h0 + 5;
+-	g1 = h1 + (g0 >> 26);             g0 &= 0x3ffffff;
+-	g2 = h2 + (g1 >> 26);             g1 &= 0x3ffffff;
+-	g3 = h3 + (g2 >> 26);             g2 &= 0x3ffffff;
+-	g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x3ffffff;
+-
+-	/* select h if h < p, or h + -p if h >= p */
+-	mask = (g4 >> ((sizeof(u32) * 8) - 1)) - 1;
+-	g0 &= mask;
+-	g1 &= mask;
+-	g2 &= mask;
+-	g3 &= mask;
+-	g4 &= mask;
+-	mask = ~mask;
+-	h0 = (h0 & mask) | g0;
+-	h1 = (h1 & mask) | g1;
+-	h2 = (h2 & mask) | g2;
+-	h3 = (h3 & mask) | g3;
+-	h4 = (h4 & mask) | g4;
+-
+-	/* h = h % (2^128) */
+-	put_unaligned_le32((h0 >>  0) | (h1 << 26), dst +  0);
+-	put_unaligned_le32((h1 >>  6) | (h2 << 20), dst +  4);
+-	put_unaligned_le32((h2 >> 12) | (h3 << 14), dst +  8);
+-	put_unaligned_le32((h3 >> 18) | (h4 <<  8), dst + 12);
+-}
+-
+-void poly1305_init_arch(struct poly1305_desc_ctx *desc, const u8 *key)
+-{
+-	poly1305_integer_setkey(desc->opaque_r, key);
+-	desc->s[0] = get_unaligned_le32(key + 16);
+-	desc->s[1] = get_unaligned_le32(key + 20);
+-	desc->s[2] = get_unaligned_le32(key + 24);
+-	desc->s[3] = get_unaligned_le32(key + 28);
+-	poly1305_core_init(&desc->h);
+-	desc->buflen = 0;
+-	desc->sset = true;
+-	desc->rset = 1;
+-}
+-EXPORT_SYMBOL_GPL(poly1305_init_arch);
+-
+-static unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx,
+-					       const u8 *src, unsigned int srclen)
+-{
+-	if (!dctx->sset) {
+-		if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) {
+-			poly1305_integer_setkey(dctx->r, src);
+-			src += POLY1305_BLOCK_SIZE;
+-			srclen -= POLY1305_BLOCK_SIZE;
+-			dctx->rset = 1;
+-		}
+-		if (srclen >= POLY1305_BLOCK_SIZE) {
+-			dctx->s[0] = get_unaligned_le32(src +  0);
+-			dctx->s[1] = get_unaligned_le32(src +  4);
+-			dctx->s[2] = get_unaligned_le32(src +  8);
+-			dctx->s[3] = get_unaligned_le32(src + 12);
+-			src += POLY1305_BLOCK_SIZE;
+-			srclen -= POLY1305_BLOCK_SIZE;
+-			dctx->sset = true;
+-		}
++	cy = state->h[0] >> 26; state->h[0] &= 0x3ffffff; state->h[1] += cy;
++	cy = state->h[1] >> 26; state->h[1] &= 0x3ffffff; state->h[2] += cy;
++	cy = state->h[2] >> 26; state->h[2] &= 0x3ffffff; state->h[3] += cy;
++	cy = state->h[3] >> 26; state->h[3] &= 0x3ffffff; state->h[4] += cy;
++	state->hs[0] = ((u64)state->h[2] << 52) | ((u64)state->h[1] << 26) | state->h[0];
++	state->hs[1] = ((u64)state->h[4] << 40) | ((u64)state->h[3] << 14) | (state->h[2] >> 12);
++	state->hs[2] = state->h[4] >> 24;
++#define ULT(a, b) ((a ^ ((a ^ b) | ((a - b) ^ b))) >> (sizeof(a) * 8 - 1))
++	cy = (state->hs[2] >> 2) + (state->hs[2] & ~3ULL);
++	state->hs[2] &= 3;
++	state->hs[0] += cy;
++	state->hs[1] += (cy = ULT(state->hs[0], cy));
++	state->hs[2] += ULT(state->hs[1], cy);
++#undef ULT
++	state->is_base2_26 = 0;
++}
++
++static void poly1305_simd_init(void *ctx, const u8 key[POLY1305_KEY_SIZE])
++{
++	poly1305_init_x86_64(ctx, key);
++}
++
++static void poly1305_simd_blocks(void *ctx, const u8 *inp, size_t len,
++				 const u32 padbit)
++{
++	struct poly1305_arch_internal *state = ctx;
++
++	/* SIMD disables preemption, so relax after processing each page. */
++	BUILD_BUG_ON(PAGE_SIZE < POLY1305_BLOCK_SIZE ||
++		     PAGE_SIZE % POLY1305_BLOCK_SIZE);
++
++	if (!IS_ENABLED(CONFIG_AS_AVX) || !static_branch_likely(&poly1305_use_avx) ||
++	    (len < (POLY1305_BLOCK_SIZE * 18) && !state->is_base2_26) ||
++	    !crypto_simd_usable()) {
++		convert_to_base2_64(ctx);
++		poly1305_blocks_x86_64(ctx, inp, len, padbit);
++		return;
+ 	}
+-	return srclen;
+-}
+ 
+-static unsigned int poly1305_scalar_blocks(struct poly1305_desc_ctx *dctx,
+-					   const u8 *src, unsigned int srclen)
+-{
+-	unsigned int datalen;
++	for (;;) {
++		const size_t bytes = min_t(size_t, len, PAGE_SIZE);
+ 
+-	if (unlikely(!dctx->sset)) {
+-		datalen = crypto_poly1305_setdesckey(dctx, src, srclen);
+-		src += srclen - datalen;
+-		srclen = datalen;
+-	}
+-	if (srclen >= POLY1305_BLOCK_SIZE) {
+-		poly1305_integer_blocks(&dctx->h, dctx->opaque_r, src,
+-					srclen / POLY1305_BLOCK_SIZE, 1);
+-		srclen %= POLY1305_BLOCK_SIZE;
++		kernel_fpu_begin();
++		if (IS_ENABLED(CONFIG_AS_AVX512) && static_branch_likely(&poly1305_use_avx512))
++			poly1305_blocks_avx512(ctx, inp, bytes, padbit);
++		else if (IS_ENABLED(CONFIG_AS_AVX2) && static_branch_likely(&poly1305_use_avx2))
++			poly1305_blocks_avx2(ctx, inp, bytes, padbit);
++		else
++			poly1305_blocks_avx(ctx, inp, bytes, padbit);
++		kernel_fpu_end();
++		len -= bytes;
++		if (!len)
++			break;
++		inp += bytes;
+ 	}
+-	return srclen;
+ }
+ 
+-static unsigned int poly1305_simd_blocks(struct poly1305_desc_ctx *dctx,
+-					 const u8 *src, unsigned int srclen)
+-{
+-	unsigned int blocks, datalen;
++static void poly1305_simd_emit(void *ctx, u8 mac[POLY1305_DIGEST_SIZE],
++			       const u32 nonce[4])
++{
++	struct poly1305_arch_internal *state = ctx;
++
++	if (!IS_ENABLED(CONFIG_AS_AVX) || !static_branch_likely(&poly1305_use_avx) ||
++	    !state->is_base2_26 || !crypto_simd_usable()) {
++		convert_to_base2_64(ctx);
++		poly1305_emit_x86_64(ctx, mac, nonce);
++	} else
++		poly1305_emit_avx(ctx, mac, nonce);
++}
++
++void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key)
++{
++	poly1305_simd_init(&dctx->h, key);
++	dctx->s[0] = get_unaligned_le32(&key[16]);
++	dctx->s[1] = get_unaligned_le32(&key[20]);
++	dctx->s[2] = get_unaligned_le32(&key[24]);
++	dctx->s[3] = get_unaligned_le32(&key[28]);
++	dctx->buflen = 0;
++	dctx->sset = true;
++}
++EXPORT_SYMBOL(poly1305_init_arch);
+ 
++static unsigned int crypto_poly1305_setdctxkey(struct poly1305_desc_ctx *dctx,
++					       const u8 *inp, unsigned int len)
++{
++	unsigned int acc = 0;
+ 	if (unlikely(!dctx->sset)) {
+-		datalen = crypto_poly1305_setdesckey(dctx, src, srclen);
+-		src += srclen - datalen;
+-		srclen = datalen;
+-	}
+-
+-	if (IS_ENABLED(CONFIG_AS_AVX2) &&
+-	    static_branch_likely(&poly1305_use_avx2) &&
+-	    srclen >= POLY1305_BLOCK_SIZE * 4) {
+-		if (unlikely(dctx->rset < 4)) {
+-			if (dctx->rset < 2) {
+-				dctx->r[1] = dctx->r[0];
+-				poly1305_simd_mult(dctx->r[1].r, dctx->r[0].r);
+-			}
+-			dctx->r[2] = dctx->r[1];
+-			poly1305_simd_mult(dctx->r[2].r, dctx->r[0].r);
+-			dctx->r[3] = dctx->r[2];
+-			poly1305_simd_mult(dctx->r[3].r, dctx->r[0].r);
+-			dctx->rset = 4;
++		if (!dctx->rset && len >= POLY1305_BLOCK_SIZE) {
++			poly1305_simd_init(&dctx->h, inp);
++			inp += POLY1305_BLOCK_SIZE;
++			len -= POLY1305_BLOCK_SIZE;
++			acc += POLY1305_BLOCK_SIZE;
++			dctx->rset = 1;
+ 		}
+-		blocks = srclen / (POLY1305_BLOCK_SIZE * 4);
+-		poly1305_4block_avx2(dctx->h.h, src, dctx->r[0].r, blocks,
+-				     dctx->r[1].r);
+-		src += POLY1305_BLOCK_SIZE * 4 * blocks;
+-		srclen -= POLY1305_BLOCK_SIZE * 4 * blocks;
+-	}
+-
+-	if (likely(srclen >= POLY1305_BLOCK_SIZE * 2)) {
+-		if (unlikely(dctx->rset < 2)) {
+-			dctx->r[1] = dctx->r[0];
+-			poly1305_simd_mult(dctx->r[1].r, dctx->r[0].r);
+-			dctx->rset = 2;
++		if (len >= POLY1305_BLOCK_SIZE) {
++			dctx->s[0] = get_unaligned_le32(&inp[0]);
++			dctx->s[1] = get_unaligned_le32(&inp[4]);
++			dctx->s[2] = get_unaligned_le32(&inp[8]);
++			dctx->s[3] = get_unaligned_le32(&inp[12]);
++			inp += POLY1305_BLOCK_SIZE;
++			len -= POLY1305_BLOCK_SIZE;
++			acc += POLY1305_BLOCK_SIZE;
++			dctx->sset = true;
+ 		}
+-		blocks = srclen / (POLY1305_BLOCK_SIZE * 2);
+-		poly1305_2block_sse2(dctx->h.h, src, dctx->r[0].r,
+-				     blocks, dctx->r[1].r);
+-		src += POLY1305_BLOCK_SIZE * 2 * blocks;
+-		srclen -= POLY1305_BLOCK_SIZE * 2 * blocks;
+-	}
+-	if (srclen >= POLY1305_BLOCK_SIZE) {
+-		poly1305_block_sse2(dctx->h.h, src, dctx->r[0].r, 1);
+-		srclen -= POLY1305_BLOCK_SIZE;
+ 	}
+-	return srclen;
++	return acc;
+ }
+ 
+ void poly1305_update_arch(struct poly1305_desc_ctx *dctx, const u8 *src,
+ 			  unsigned int srclen)
+ {
+-	unsigned int bytes;
++	unsigned int bytes, used;
+ 
+ 	if (unlikely(dctx->buflen)) {
+ 		bytes = min(srclen, POLY1305_BLOCK_SIZE - dctx->buflen);
+@@ -295,31 +184,19 @@ void poly1305_update_arch(struct poly130
+ 		dctx->buflen += bytes;
+ 
+ 		if (dctx->buflen == POLY1305_BLOCK_SIZE) {
+-			if (static_branch_likely(&poly1305_use_simd) &&
+-			    likely(crypto_simd_usable())) {
+-				kernel_fpu_begin();
+-				poly1305_simd_blocks(dctx, dctx->buf,
+-						     POLY1305_BLOCK_SIZE);
+-				kernel_fpu_end();
+-			} else {
+-				poly1305_scalar_blocks(dctx, dctx->buf,
+-						       POLY1305_BLOCK_SIZE);
+-			}
++			if (likely(!crypto_poly1305_setdctxkey(dctx, dctx->buf, POLY1305_BLOCK_SIZE)))
++				poly1305_simd_blocks(&dctx->h, dctx->buf, POLY1305_BLOCK_SIZE, 1);
+ 			dctx->buflen = 0;
+ 		}
+ 	}
+ 
+ 	if (likely(srclen >= POLY1305_BLOCK_SIZE)) {
+-		if (static_branch_likely(&poly1305_use_simd) &&
+-		    likely(crypto_simd_usable())) {
+-			kernel_fpu_begin();
+-			bytes = poly1305_simd_blocks(dctx, src, srclen);
+-			kernel_fpu_end();
+-		} else {
+-			bytes = poly1305_scalar_blocks(dctx, src, srclen);
+-		}
+-		src += srclen - bytes;
+-		srclen = bytes;
++		bytes = round_down(srclen, POLY1305_BLOCK_SIZE);
++		srclen -= bytes;
++		used = crypto_poly1305_setdctxkey(dctx, src, bytes);
++		if (likely(bytes - used))
++			poly1305_simd_blocks(&dctx->h, src + used, bytes - used, 1);
++		src += bytes;
+ 	}
+ 
+ 	if (unlikely(srclen)) {
+@@ -329,31 +206,17 @@ void poly1305_update_arch(struct poly130
+ }
+ EXPORT_SYMBOL(poly1305_update_arch);
+ 
+-void poly1305_final_arch(struct poly1305_desc_ctx *desc, u8 *dst)
++void poly1305_final_arch(struct poly1305_desc_ctx *dctx, u8 *dst)
+ {
+-	__le32 digest[4];
+-	u64 f = 0;
+-
+-	if (unlikely(desc->buflen)) {
+-		desc->buf[desc->buflen++] = 1;
+-		memset(desc->buf + desc->buflen, 0,
+-		       POLY1305_BLOCK_SIZE - desc->buflen);
+-		poly1305_integer_blocks(&desc->h, desc->opaque_r, desc->buf, 1, 0);
++	if (unlikely(dctx->buflen)) {
++		dctx->buf[dctx->buflen++] = 1;
++		memset(dctx->buf + dctx->buflen, 0,
++		       POLY1305_BLOCK_SIZE - dctx->buflen);
++		poly1305_simd_blocks(&dctx->h, dctx->buf, POLY1305_BLOCK_SIZE, 0);
+ 	}
+ 
+-	poly1305_integer_emit(&desc->h, digest);
+-
+-	/* mac = (h + s) % (2^128) */
+-	f = (f >> 32) + le32_to_cpu(digest[0]) + desc->s[0];
+-	put_unaligned_le32(f, dst + 0);
+-	f = (f >> 32) + le32_to_cpu(digest[1]) + desc->s[1];
+-	put_unaligned_le32(f, dst + 4);
+-	f = (f >> 32) + le32_to_cpu(digest[2]) + desc->s[2];
+-	put_unaligned_le32(f, dst + 8);
+-	f = (f >> 32) + le32_to_cpu(digest[3]) + desc->s[3];
+-	put_unaligned_le32(f, dst + 12);
+-
+-	*desc = (struct poly1305_desc_ctx){};
++	poly1305_simd_emit(&dctx->h, dst, dctx->s);
++	*dctx = (struct poly1305_desc_ctx){};
+ }
+ EXPORT_SYMBOL(poly1305_final_arch);
+ 
+@@ -361,38 +224,34 @@ static int crypto_poly1305_init(struct s
+ {
+ 	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
+ 
+-	poly1305_core_init(&dctx->h);
+-	dctx->buflen = 0;
+-	dctx->rset = 0;
+-	dctx->sset = false;
+-
++	*dctx = (struct poly1305_desc_ctx){};
+ 	return 0;
+ }
+ 
+-static int crypto_poly1305_final(struct shash_desc *desc, u8 *dst)
++static int crypto_poly1305_update(struct shash_desc *desc,
++				  const u8 *src, unsigned int srclen)
+ {
+ 	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
+ 
+-	if (unlikely(!dctx->sset))
+-		return -ENOKEY;
+-
+-	poly1305_final_arch(dctx, dst);
++	poly1305_update_arch(dctx, src, srclen);
+ 	return 0;
+ }
+ 
+-static int poly1305_simd_update(struct shash_desc *desc,
+-				const u8 *src, unsigned int srclen)
++static int crypto_poly1305_final(struct shash_desc *desc, u8 *dst)
+ {
+ 	struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc);
+ 
+-	poly1305_update_arch(dctx, src, srclen);
++	if (unlikely(!dctx->sset))
++		return -ENOKEY;
++
++	poly1305_final_arch(dctx, dst);
+ 	return 0;
+ }
+ 
+ static struct shash_alg alg = {
+ 	.digestsize	= POLY1305_DIGEST_SIZE,
+ 	.init		= crypto_poly1305_init,
+-	.update		= poly1305_simd_update,
++	.update		= crypto_poly1305_update,
+ 	.final		= crypto_poly1305_final,
+ 	.descsize	= sizeof(struct poly1305_desc_ctx),
+ 	.base		= {
+@@ -406,17 +265,19 @@ static struct shash_alg alg = {
+ 
+ static int __init poly1305_simd_mod_init(void)
+ {
+-	if (!boot_cpu_has(X86_FEATURE_XMM2))
+-		return 0;
+-
+-	static_branch_enable(&poly1305_use_simd);
+-
+-	if (IS_ENABLED(CONFIG_AS_AVX2) &&
+-	    boot_cpu_has(X86_FEATURE_AVX) &&
++	if (IS_ENABLED(CONFIG_AS_AVX) && boot_cpu_has(X86_FEATURE_AVX) &&
++	    cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL))
++		static_branch_enable(&poly1305_use_avx);
++	if (IS_ENABLED(CONFIG_AS_AVX2) && boot_cpu_has(X86_FEATURE_AVX) &&
+ 	    boot_cpu_has(X86_FEATURE_AVX2) &&
+ 	    cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL))
+ 		static_branch_enable(&poly1305_use_avx2);
+-
++	if (IS_ENABLED(CONFIG_AS_AVX512) && boot_cpu_has(X86_FEATURE_AVX) &&
++	    boot_cpu_has(X86_FEATURE_AVX2) && boot_cpu_has(X86_FEATURE_AVX512F) &&
++	    cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM | XFEATURE_MASK_AVX512, NULL) &&
++	    /* Skylake downclocks unacceptably much when using zmm, but later generations are fast. */
++	    boot_cpu_data.x86_model != INTEL_FAM6_SKYLAKE_X)
++		static_branch_enable(&poly1305_use_avx512);
+ 	return IS_REACHABLE(CONFIG_CRYPTO_HASH) ? crypto_register_shash(&alg) : 0;
+ }
+ 
+@@ -430,7 +291,7 @@ module_init(poly1305_simd_mod_init);
+ module_exit(poly1305_simd_mod_exit);
+ 
+ MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Martin Willi <martin@strongswan.org>");
++MODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>");
+ MODULE_DESCRIPTION("Poly1305 authenticator");
+ MODULE_ALIAS_CRYPTO("poly1305");
+ MODULE_ALIAS_CRYPTO("poly1305-simd");
+--- a/lib/crypto/Kconfig
++++ b/lib/crypto/Kconfig
+@@ -90,7 +90,7 @@ config CRYPTO_LIB_DES
+ config CRYPTO_LIB_POLY1305_RSIZE
+ 	int
+ 	default 2 if MIPS
+-	default 4 if X86_64
++	default 11 if X86_64
+ 	default 9 if ARM || ARM64
+ 	default 1
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0044-crypto-arm-arm64-mips-poly1305-remove-redundant-non-.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0044-crypto-arm-arm64-mips-poly1305-remove-redundant-non-.patch
new file mode 100644
index 0000000..b95b998
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0044-crypto-arm-arm64-mips-poly1305-remove-redundant-non-.patch
@@ -0,0 +1,171 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Sun, 5 Jan 2020 22:40:49 -0500
+Subject: [PATCH] crypto: {arm,arm64,mips}/poly1305 - remove redundant
+ non-reduction from emit
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit 31899908a0d248b030b4464425b86c717e0007d4 upstream.
+
+This appears to be some kind of copy and paste error, and is actually
+dead code.
+
+Pre: f = 0 ⇒ (f >> 32) = 0
+    f = (f >> 32) + le32_to_cpu(digest[0]);
+Post: 0 ≤ f < 2³²
+    put_unaligned_le32(f, dst);
+
+Pre: 0 ≤ f < 2³² ⇒ (f >> 32) = 0
+    f = (f >> 32) + le32_to_cpu(digest[1]);
+Post: 0 ≤ f < 2³²
+    put_unaligned_le32(f, dst + 4);
+
+Pre: 0 ≤ f < 2³² ⇒ (f >> 32) = 0
+    f = (f >> 32) + le32_to_cpu(digest[2]);
+Post: 0 ≤ f < 2³²
+    put_unaligned_le32(f, dst + 8);
+
+Pre: 0 ≤ f < 2³² ⇒ (f >> 32) = 0
+    f = (f >> 32) + le32_to_cpu(digest[3]);
+Post: 0 ≤ f < 2³²
+    put_unaligned_le32(f, dst + 12);
+
+Therefore this sequence is redundant. And Andy's code appears to handle
+misalignment acceptably.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Tested-by: Ard Biesheuvel <ardb@kernel.org>
+Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm/crypto/poly1305-glue.c   | 18 ++----------------
+ arch/arm64/crypto/poly1305-glue.c | 18 ++----------------
+ arch/mips/crypto/poly1305-glue.c  | 18 ++----------------
+ 3 files changed, 6 insertions(+), 48 deletions(-)
+
+--- a/arch/arm/crypto/poly1305-glue.c
++++ b/arch/arm/crypto/poly1305-glue.c
+@@ -20,7 +20,7 @@
+ 
+ void poly1305_init_arm(void *state, const u8 *key);
+ void poly1305_blocks_arm(void *state, const u8 *src, u32 len, u32 hibit);
+-void poly1305_emit_arm(void *state, __le32 *digest, const u32 *nonce);
++void poly1305_emit_arm(void *state, u8 *digest, const u32 *nonce);
+ 
+ void __weak poly1305_blocks_neon(void *state, const u8 *src, u32 len, u32 hibit)
+ {
+@@ -179,9 +179,6 @@ EXPORT_SYMBOL(poly1305_update_arch);
+ 
+ void poly1305_final_arch(struct poly1305_desc_ctx *dctx, u8 *dst)
+ {
+-	__le32 digest[4];
+-	u64 f = 0;
+-
+ 	if (unlikely(dctx->buflen)) {
+ 		dctx->buf[dctx->buflen++] = 1;
+ 		memset(dctx->buf + dctx->buflen, 0,
+@@ -189,18 +186,7 @@ void poly1305_final_arch(struct poly1305
+ 		poly1305_blocks_arm(&dctx->h, dctx->buf, POLY1305_BLOCK_SIZE, 0);
+ 	}
+ 
+-	poly1305_emit_arm(&dctx->h, digest, dctx->s);
+-
+-	/* mac = (h + s) % (2^128) */
+-	f = (f >> 32) + le32_to_cpu(digest[0]);
+-	put_unaligned_le32(f, dst);
+-	f = (f >> 32) + le32_to_cpu(digest[1]);
+-	put_unaligned_le32(f, dst + 4);
+-	f = (f >> 32) + le32_to_cpu(digest[2]);
+-	put_unaligned_le32(f, dst + 8);
+-	f = (f >> 32) + le32_to_cpu(digest[3]);
+-	put_unaligned_le32(f, dst + 12);
+-
++	poly1305_emit_arm(&dctx->h, dst, dctx->s);
+ 	*dctx = (struct poly1305_desc_ctx){};
+ }
+ EXPORT_SYMBOL(poly1305_final_arch);
+--- a/arch/arm64/crypto/poly1305-glue.c
++++ b/arch/arm64/crypto/poly1305-glue.c
+@@ -21,7 +21,7 @@
+ asmlinkage void poly1305_init_arm64(void *state, const u8 *key);
+ asmlinkage void poly1305_blocks(void *state, const u8 *src, u32 len, u32 hibit);
+ asmlinkage void poly1305_blocks_neon(void *state, const u8 *src, u32 len, u32 hibit);
+-asmlinkage void poly1305_emit(void *state, __le32 *digest, const u32 *nonce);
++asmlinkage void poly1305_emit(void *state, u8 *digest, const u32 *nonce);
+ 
+ static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon);
+ 
+@@ -162,9 +162,6 @@ EXPORT_SYMBOL(poly1305_update_arch);
+ 
+ void poly1305_final_arch(struct poly1305_desc_ctx *dctx, u8 *dst)
+ {
+-	__le32 digest[4];
+-	u64 f = 0;
+-
+ 	if (unlikely(dctx->buflen)) {
+ 		dctx->buf[dctx->buflen++] = 1;
+ 		memset(dctx->buf + dctx->buflen, 0,
+@@ -172,18 +169,7 @@ void poly1305_final_arch(struct poly1305
+ 		poly1305_blocks(&dctx->h, dctx->buf, POLY1305_BLOCK_SIZE, 0);
+ 	}
+ 
+-	poly1305_emit(&dctx->h, digest, dctx->s);
+-
+-	/* mac = (h + s) % (2^128) */
+-	f = (f >> 32) + le32_to_cpu(digest[0]);
+-	put_unaligned_le32(f, dst);
+-	f = (f >> 32) + le32_to_cpu(digest[1]);
+-	put_unaligned_le32(f, dst + 4);
+-	f = (f >> 32) + le32_to_cpu(digest[2]);
+-	put_unaligned_le32(f, dst + 8);
+-	f = (f >> 32) + le32_to_cpu(digest[3]);
+-	put_unaligned_le32(f, dst + 12);
+-
++	poly1305_emit(&dctx->h, dst, dctx->s);
+ 	*dctx = (struct poly1305_desc_ctx){};
+ }
+ EXPORT_SYMBOL(poly1305_final_arch);
+--- a/arch/mips/crypto/poly1305-glue.c
++++ b/arch/mips/crypto/poly1305-glue.c
+@@ -15,7 +15,7 @@
+ 
+ asmlinkage void poly1305_init_mips(void *state, const u8 *key);
+ asmlinkage void poly1305_blocks_mips(void *state, const u8 *src, u32 len, u32 hibit);
+-asmlinkage void poly1305_emit_mips(void *state, __le32 *digest, const u32 *nonce);
++asmlinkage void poly1305_emit_mips(void *state, u8 *digest, const u32 *nonce);
+ 
+ void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key)
+ {
+@@ -134,9 +134,6 @@ EXPORT_SYMBOL(poly1305_update_arch);
+ 
+ void poly1305_final_arch(struct poly1305_desc_ctx *dctx, u8 *dst)
+ {
+-	__le32 digest[4];
+-	u64 f = 0;
+-
+ 	if (unlikely(dctx->buflen)) {
+ 		dctx->buf[dctx->buflen++] = 1;
+ 		memset(dctx->buf + dctx->buflen, 0,
+@@ -144,18 +141,7 @@ void poly1305_final_arch(struct poly1305
+ 		poly1305_blocks_mips(&dctx->h, dctx->buf, POLY1305_BLOCK_SIZE, 0);
+ 	}
+ 
+-	poly1305_emit_mips(&dctx->h, digest, dctx->s);
+-
+-	/* mac = (h + s) % (2^128) */
+-	f = (f >> 32) + le32_to_cpu(digest[0]);
+-	put_unaligned_le32(f, dst);
+-	f = (f >> 32) + le32_to_cpu(digest[1]);
+-	put_unaligned_le32(f, dst + 4);
+-	f = (f >> 32) + le32_to_cpu(digest[2]);
+-	put_unaligned_le32(f, dst + 8);
+-	f = (f >> 32) + le32_to_cpu(digest[3]);
+-	put_unaligned_le32(f, dst + 12);
+-
++	poly1305_emit_mips(&dctx->h, dst, dctx->s);
+ 	*dctx = (struct poly1305_desc_ctx){};
+ }
+ EXPORT_SYMBOL(poly1305_final_arch);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0045-crypto-curve25519-Fix-selftest-build-error.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0045-crypto-curve25519-Fix-selftest-build-error.patch
new file mode 100644
index 0000000..fa8d8fd
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0045-crypto-curve25519-Fix-selftest-build-error.patch
@@ -0,0 +1,102 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Herbert Xu <herbert@gondor.apana.org.au>
+Date: Wed, 8 Jan 2020 12:37:35 +0800
+Subject: [PATCH] crypto: curve25519 - Fix selftest build error
+
+commit a8bdf2c42ee4d1ee42af1f3601f85de94e70a421 upstream.
+
+If CRYPTO_CURVE25519 is y, CRYPTO_LIB_CURVE25519_GENERIC will be
+y, but CRYPTO_LIB_CURVE25519 may be set to m, this causes build
+errors:
+
+lib/crypto/curve25519-selftest.o: In function `curve25519':
+curve25519-selftest.c:(.text.unlikely+0xc): undefined reference to `curve25519_arch'
+lib/crypto/curve25519-selftest.o: In function `curve25519_selftest':
+curve25519-selftest.c:(.init.text+0x17e): undefined reference to `curve25519_base_arch'
+
+This is because the curve25519 self-test code is being controlled
+by the GENERIC option rather than the overall CURVE25519 option,
+as is the case with blake2s.  To recap, the GENERIC and ARCH options
+for CURVE25519 are internal only and selected by users such as
+the Crypto API, or the externally visible CURVE25519 option which
+in turn is selected by wireguard.  The self-test is specific to the
+the external CURVE25519 option and should not be enabled by the
+Crypto API.
+
+This patch fixes this by splitting the GENERIC module from the
+CURVE25519 module with the latter now containing just the self-test.
+
+Reported-by: Hulk Robot <hulkci@huawei.com>
+Fixes: aa127963f1ca ("crypto: lib/curve25519 - re-add selftests")
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Reviewed-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ lib/crypto/Makefile             |  9 ++++++---
+ lib/crypto/curve25519-generic.c | 24 ++++++++++++++++++++++++
+ lib/crypto/curve25519.c         |  7 -------
+ 3 files changed, 30 insertions(+), 10 deletions(-)
+ create mode 100644 lib/crypto/curve25519-generic.c
+
+--- a/lib/crypto/Makefile
++++ b/lib/crypto/Makefile
+@@ -19,9 +19,12 @@ libblake2s-y					+= blake2s.o
+ obj-$(CONFIG_CRYPTO_LIB_CHACHA20POLY1305)	+= libchacha20poly1305.o
+ libchacha20poly1305-y				+= chacha20poly1305.o
+ 
+-obj-$(CONFIG_CRYPTO_LIB_CURVE25519_GENERIC)	+= libcurve25519.o
+-libcurve25519-y					:= curve25519-fiat32.o
+-libcurve25519-$(CONFIG_ARCH_SUPPORTS_INT128)	:= curve25519-hacl64.o
++obj-$(CONFIG_CRYPTO_LIB_CURVE25519_GENERIC)	+= libcurve25519-generic.o
++libcurve25519-generic-y				:= curve25519-fiat32.o
++libcurve25519-generic-$(CONFIG_ARCH_SUPPORTS_INT128)	:= curve25519-hacl64.o
++libcurve25519-generic-y				+= curve25519-generic.o
++
++obj-$(CONFIG_CRYPTO_LIB_CURVE25519)		+= libcurve25519.o
+ libcurve25519-y					+= curve25519.o
+ 
+ obj-$(CONFIG_CRYPTO_LIB_DES)			+= libdes.o
+--- /dev/null
++++ b/lib/crypto/curve25519-generic.c
+@@ -0,0 +1,24 @@
++// SPDX-License-Identifier: GPL-2.0 OR MIT
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ *
++ * This is an implementation of the Curve25519 ECDH algorithm, using either
++ * a 32-bit implementation or a 64-bit implementation with 128-bit integers,
++ * depending on what is supported by the target compiler.
++ *
++ * Information: https://cr.yp.to/ecdh.html
++ */
++
++#include <crypto/curve25519.h>
++#include <linux/module.h>
++
++const u8 curve25519_null_point[CURVE25519_KEY_SIZE] __aligned(32) = { 0 };
++const u8 curve25519_base_point[CURVE25519_KEY_SIZE] __aligned(32) = { 9 };
++
++EXPORT_SYMBOL(curve25519_null_point);
++EXPORT_SYMBOL(curve25519_base_point);
++EXPORT_SYMBOL(curve25519_generic);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("Curve25519 scalar multiplication");
++MODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>");
+--- a/lib/crypto/curve25519.c
++++ b/lib/crypto/curve25519.c
+@@ -15,13 +15,6 @@
+ 
+ bool curve25519_selftest(void);
+ 
+-const u8 curve25519_null_point[CURVE25519_KEY_SIZE] __aligned(32) = { 0 };
+-const u8 curve25519_base_point[CURVE25519_KEY_SIZE] __aligned(32) = { 9 };
+-
+-EXPORT_SYMBOL(curve25519_null_point);
+-EXPORT_SYMBOL(curve25519_base_point);
+-EXPORT_SYMBOL(curve25519_generic);
+-
+ static int __init mod_init(void)
+ {
+ 	if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) &&
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0046-crypto-x86-poly1305-fix-.gitignore-typo.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0046-crypto-x86-poly1305-fix-.gitignore-typo.patch
new file mode 100644
index 0000000..27f0417
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0046-crypto-x86-poly1305-fix-.gitignore-typo.patch
@@ -0,0 +1,23 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Thu, 16 Jan 2020 18:23:55 +0100
+Subject: [PATCH] crypto: x86/poly1305 - fix .gitignore typo
+
+commit 1f6868995326cc82102049e349d8dbd116bdb656 upstream.
+
+Admist the kbuild robot induced changes, the .gitignore file for the
+generated file wasn't updated with the non-clashing filename. This
+commit adjusts that.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/.gitignore | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/x86/crypto/.gitignore
++++ b/arch/x86/crypto/.gitignore
+@@ -1 +1 @@
+-poly1305-x86_64.S
++poly1305-x86_64-cryptogams.S
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0047-crypto-chacha20poly1305-add-back-missing-test-vector.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0047-crypto-chacha20poly1305-add-back-missing-test-vector.patch
new file mode 100644
index 0000000..eda9695
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0047-crypto-chacha20poly1305-add-back-missing-test-vector.patch
@@ -0,0 +1,1858 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Thu, 16 Jan 2020 21:26:34 +0100
+Subject: [PATCH] crypto: chacha20poly1305 - add back missing test vectors and
+ test chunking
+
+commit 72c7943792c9e7788ddd182337bcf8f650cf56f5 upstream.
+
+When this was originally ported, the 12-byte nonce vectors were left out
+to keep things simple. I agree that we don't need nor want a library
+interface for 12-byte nonces. But these test vectors were specially
+crafted to look at issues in the underlying primitives and related
+interactions.  Therefore, we actually want to keep around all of the
+test vectors, and simply have a helper function to test them with.
+
+Secondly, the sglist-based chunking code in the library interface is
+rather complicated, so this adds a developer-only test for ensuring that
+all the book keeping is correct, across a wide array of possibilities.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ lib/crypto/chacha20poly1305-selftest.c | 1712 +++++++++++++++++++++++-
+ 1 file changed, 1698 insertions(+), 14 deletions(-)
+
+--- a/lib/crypto/chacha20poly1305-selftest.c
++++ b/lib/crypto/chacha20poly1305-selftest.c
+@@ -4,6 +4,7 @@
+  */
+ 
+ #include <crypto/chacha20poly1305.h>
++#include <crypto/chacha.h>
+ #include <crypto/poly1305.h>
+ 
+ #include <asm/unaligned.h>
+@@ -1926,6 +1927,1104 @@ static const u8 enc_key012[] __initconst
+ 	0x65, 0x91, 0x6e, 0x2a, 0x79, 0x22, 0xda, 0x64
+ };
+ 
++/* wycheproof - rfc7539 */
++static const u8 enc_input013[] __initconst = {
++	0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,
++	0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
++	0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
++	0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
++	0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,
++	0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
++	0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,
++	0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
++	0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
++	0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,
++	0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,
++	0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
++	0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
++	0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
++	0x74, 0x2e
++};
++static const u8 enc_output013[] __initconst = {
++	0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb,
++	0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
++	0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
++	0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,
++	0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12,
++	0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
++	0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29,
++	0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36,
++	0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
++	0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58,
++	0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94,
++	0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
++	0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d,
++	0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b,
++	0x61, 0x16, 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09,
++	0xe2, 0x6a, 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60,
++	0x06, 0x91
++};
++static const u8 enc_assoc013[] __initconst = {
++	0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
++	0xc4, 0xc5, 0xc6, 0xc7
++};
++static const u8 enc_nonce013[] __initconst = {
++	0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43,
++	0x44, 0x45, 0x46, 0x47
++};
++static const u8 enc_key013[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input014[] __initconst = { };
++static const u8 enc_output014[] __initconst = {
++	0x76, 0xac, 0xb3, 0x42, 0xcf, 0x31, 0x66, 0xa5,
++	0xb6, 0x3c, 0x0c, 0x0e, 0xa1, 0x38, 0x3c, 0x8d
++};
++static const u8 enc_assoc014[] __initconst = { };
++static const u8 enc_nonce014[] __initconst = {
++	0x4d, 0xa5, 0xbf, 0x8d, 0xfd, 0x58, 0x52, 0xc1,
++	0xea, 0x12, 0x37, 0x9d
++};
++static const u8 enc_key014[] __initconst = {
++	0x80, 0xba, 0x31, 0x92, 0xc8, 0x03, 0xce, 0x96,
++	0x5e, 0xa3, 0x71, 0xd5, 0xff, 0x07, 0x3c, 0xf0,
++	0xf4, 0x3b, 0x6a, 0x2a, 0xb5, 0x76, 0xb2, 0x08,
++	0x42, 0x6e, 0x11, 0x40, 0x9c, 0x09, 0xb9, 0xb0
++};
++
++/* wycheproof - misc */
++static const u8 enc_input015[] __initconst = { };
++static const u8 enc_output015[] __initconst = {
++	0x90, 0x6f, 0xa6, 0x28, 0x4b, 0x52, 0xf8, 0x7b,
++	0x73, 0x59, 0xcb, 0xaa, 0x75, 0x63, 0xc7, 0x09
++};
++static const u8 enc_assoc015[] __initconst = {
++	0xbd, 0x50, 0x67, 0x64, 0xf2, 0xd2, 0xc4, 0x10
++};
++static const u8 enc_nonce015[] __initconst = {
++	0xa9, 0x2e, 0xf0, 0xac, 0x99, 0x1d, 0xd5, 0x16,
++	0xa3, 0xc6, 0xf6, 0x89
++};
++static const u8 enc_key015[] __initconst = {
++	0x7a, 0x4c, 0xd7, 0x59, 0x17, 0x2e, 0x02, 0xeb,
++	0x20, 0x4d, 0xb2, 0xc3, 0xf5, 0xc7, 0x46, 0x22,
++	0x7d, 0xf5, 0x84, 0xfc, 0x13, 0x45, 0x19, 0x63,
++	0x91, 0xdb, 0xb9, 0x57, 0x7a, 0x25, 0x07, 0x42
++};
++
++/* wycheproof - misc */
++static const u8 enc_input016[] __initconst = {
++	0x2a
++};
++static const u8 enc_output016[] __initconst = {
++	0x3a, 0xca, 0xc2, 0x7d, 0xec, 0x09, 0x68, 0x80,
++	0x1e, 0x9f, 0x6e, 0xde, 0xd6, 0x9d, 0x80, 0x75,
++	0x22
++};
++static const u8 enc_assoc016[] __initconst = { };
++static const u8 enc_nonce016[] __initconst = {
++	0x99, 0xe2, 0x3e, 0xc4, 0x89, 0x85, 0xbc, 0xcd,
++	0xee, 0xab, 0x60, 0xf1
++};
++static const u8 enc_key016[] __initconst = {
++	0xcc, 0x56, 0xb6, 0x80, 0x55, 0x2e, 0xb7, 0x50,
++	0x08, 0xf5, 0x48, 0x4b, 0x4c, 0xb8, 0x03, 0xfa,
++	0x50, 0x63, 0xeb, 0xd6, 0xea, 0xb9, 0x1f, 0x6a,
++	0xb6, 0xae, 0xf4, 0x91, 0x6a, 0x76, 0x62, 0x73
++};
++
++/* wycheproof - misc */
++static const u8 enc_input017[] __initconst = {
++	0x51
++};
++static const u8 enc_output017[] __initconst = {
++	0xc4, 0x16, 0x83, 0x10, 0xca, 0x45, 0xb1, 0xf7,
++	0xc6, 0x6c, 0xad, 0x4e, 0x99, 0xe4, 0x3f, 0x72,
++	0xb9
++};
++static const u8 enc_assoc017[] __initconst = {
++	0x91, 0xca, 0x6c, 0x59, 0x2c, 0xbc, 0xca, 0x53
++};
++static const u8 enc_nonce017[] __initconst = {
++	0xab, 0x0d, 0xca, 0x71, 0x6e, 0xe0, 0x51, 0xd2,
++	0x78, 0x2f, 0x44, 0x03
++};
++static const u8 enc_key017[] __initconst = {
++	0x46, 0xf0, 0x25, 0x49, 0x65, 0xf7, 0x69, 0xd5,
++	0x2b, 0xdb, 0x4a, 0x70, 0xb4, 0x43, 0x19, 0x9f,
++	0x8e, 0xf2, 0x07, 0x52, 0x0d, 0x12, 0x20, 0xc5,
++	0x5e, 0x4b, 0x70, 0xf0, 0xfd, 0xa6, 0x20, 0xee
++};
++
++/* wycheproof - misc */
++static const u8 enc_input018[] __initconst = {
++	0x5c, 0x60
++};
++static const u8 enc_output018[] __initconst = {
++	0x4d, 0x13, 0x91, 0xe8, 0xb6, 0x1e, 0xfb, 0x39,
++	0xc1, 0x22, 0x19, 0x54, 0x53, 0x07, 0x7b, 0x22,
++	0xe5, 0xe2
++};
++static const u8 enc_assoc018[] __initconst = { };
++static const u8 enc_nonce018[] __initconst = {
++	0x46, 0x1a, 0xf1, 0x22, 0xe9, 0xf2, 0xe0, 0x34,
++	0x7e, 0x03, 0xf2, 0xdb
++};
++static const u8 enc_key018[] __initconst = {
++	0x2f, 0x7f, 0x7e, 0x4f, 0x59, 0x2b, 0xb3, 0x89,
++	0x19, 0x49, 0x89, 0x74, 0x35, 0x07, 0xbf, 0x3e,
++	0xe9, 0xcb, 0xde, 0x17, 0x86, 0xb6, 0x69, 0x5f,
++	0xe6, 0xc0, 0x25, 0xfd, 0x9b, 0xa4, 0xc1, 0x00
++};
++
++/* wycheproof - misc */
++static const u8 enc_input019[] __initconst = {
++	0xdd, 0xf2
++};
++static const u8 enc_output019[] __initconst = {
++	0xb6, 0x0d, 0xea, 0xd0, 0xfd, 0x46, 0x97, 0xec,
++	0x2e, 0x55, 0x58, 0x23, 0x77, 0x19, 0xd0, 0x24,
++	0x37, 0xa2
++};
++static const u8 enc_assoc019[] __initconst = {
++	0x88, 0x36, 0x4f, 0xc8, 0x06, 0x05, 0x18, 0xbf
++};
++static const u8 enc_nonce019[] __initconst = {
++	0x61, 0x54, 0x6b, 0xa5, 0xf1, 0x72, 0x05, 0x90,
++	0xb6, 0x04, 0x0a, 0xc6
++};
++static const u8 enc_key019[] __initconst = {
++	0xc8, 0x83, 0x3d, 0xce, 0x5e, 0xa9, 0xf2, 0x48,
++	0xaa, 0x20, 0x30, 0xea, 0xcf, 0xe7, 0x2b, 0xff,
++	0xe6, 0x9a, 0x62, 0x0c, 0xaf, 0x79, 0x33, 0x44,
++	0xe5, 0x71, 0x8f, 0xe0, 0xd7, 0xab, 0x1a, 0x58
++};
++
++/* wycheproof - misc */
++static const u8 enc_input020[] __initconst = {
++	0xab, 0x85, 0xe9, 0xc1, 0x57, 0x17, 0x31
++};
++static const u8 enc_output020[] __initconst = {
++	0x5d, 0xfe, 0x34, 0x40, 0xdb, 0xb3, 0xc3, 0xed,
++	0x7a, 0x43, 0x4e, 0x26, 0x02, 0xd3, 0x94, 0x28,
++	0x1e, 0x0a, 0xfa, 0x9f, 0xb7, 0xaa, 0x42
++};
++static const u8 enc_assoc020[] __initconst = { };
++static const u8 enc_nonce020[] __initconst = {
++	0x3c, 0x4e, 0x65, 0x4d, 0x66, 0x3f, 0xa4, 0x59,
++	0x6d, 0xc5, 0x5b, 0xb7
++};
++static const u8 enc_key020[] __initconst = {
++	0x55, 0x56, 0x81, 0x58, 0xd3, 0xa6, 0x48, 0x3f,
++	0x1f, 0x70, 0x21, 0xea, 0xb6, 0x9b, 0x70, 0x3f,
++	0x61, 0x42, 0x51, 0xca, 0xdc, 0x1a, 0xf5, 0xd3,
++	0x4a, 0x37, 0x4f, 0xdb, 0xfc, 0x5a, 0xda, 0xc7
++};
++
++/* wycheproof - misc */
++static const u8 enc_input021[] __initconst = {
++	0x4e, 0xe5, 0xcd, 0xa2, 0x0d, 0x42, 0x90
++};
++static const u8 enc_output021[] __initconst = {
++	0x4b, 0xd4, 0x72, 0x12, 0x94, 0x1c, 0xe3, 0x18,
++	0x5f, 0x14, 0x08, 0xee, 0x7f, 0xbf, 0x18, 0xf5,
++	0xab, 0xad, 0x6e, 0x22, 0x53, 0xa1, 0xba
++};
++static const u8 enc_assoc021[] __initconst = {
++	0x84, 0xe4, 0x6b, 0xe8, 0xc0, 0x91, 0x90, 0x53
++};
++static const u8 enc_nonce021[] __initconst = {
++	0x58, 0x38, 0x93, 0x75, 0xc6, 0x9e, 0xe3, 0x98,
++	0xde, 0x94, 0x83, 0x96
++};
++static const u8 enc_key021[] __initconst = {
++	0xe3, 0xc0, 0x9e, 0x7f, 0xab, 0x1a, 0xef, 0xb5,
++	0x16, 0xda, 0x6a, 0x33, 0x02, 0x2a, 0x1d, 0xd4,
++	0xeb, 0x27, 0x2c, 0x80, 0xd5, 0x40, 0xc5, 0xda,
++	0x52, 0xa7, 0x30, 0xf3, 0x4d, 0x84, 0x0d, 0x7f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input022[] __initconst = {
++	0xbe, 0x33, 0x08, 0xf7, 0x2a, 0x2c, 0x6a, 0xed
++};
++static const u8 enc_output022[] __initconst = {
++	0x8e, 0x94, 0x39, 0xa5, 0x6e, 0xee, 0xc8, 0x17,
++	0xfb, 0xe8, 0xa6, 0xed, 0x8f, 0xab, 0xb1, 0x93,
++	0x75, 0x39, 0xdd, 0x6c, 0x00, 0xe9, 0x00, 0x21
++};
++static const u8 enc_assoc022[] __initconst = { };
++static const u8 enc_nonce022[] __initconst = {
++	0x4f, 0x07, 0xaf, 0xed, 0xfd, 0xc3, 0xb6, 0xc2,
++	0x36, 0x18, 0x23, 0xd3
++};
++static const u8 enc_key022[] __initconst = {
++	0x51, 0xe4, 0xbf, 0x2b, 0xad, 0x92, 0xb7, 0xaf,
++	0xf1, 0xa4, 0xbc, 0x05, 0x55, 0x0b, 0xa8, 0x1d,
++	0xf4, 0xb9, 0x6f, 0xab, 0xf4, 0x1c, 0x12, 0xc7,
++	0xb0, 0x0e, 0x60, 0xe4, 0x8d, 0xb7, 0xe1, 0x52
++};
++
++/* wycheproof - misc */
++static const u8 enc_input023[] __initconst = {
++	0xa4, 0xc9, 0xc2, 0x80, 0x1b, 0x71, 0xf7, 0xdf
++};
++static const u8 enc_output023[] __initconst = {
++	0xb9, 0xb9, 0x10, 0x43, 0x3a, 0xf0, 0x52, 0xb0,
++	0x45, 0x30, 0xf5, 0x1a, 0xee, 0xe0, 0x24, 0xe0,
++	0xa4, 0x45, 0xa6, 0x32, 0x8f, 0xa6, 0x7a, 0x18
++};
++static const u8 enc_assoc023[] __initconst = {
++	0x66, 0xc0, 0xae, 0x70, 0x07, 0x6c, 0xb1, 0x4d
++};
++static const u8 enc_nonce023[] __initconst = {
++	0xb4, 0xea, 0x66, 0x6e, 0xe1, 0x19, 0x56, 0x33,
++	0x66, 0x48, 0x4a, 0x78
++};
++static const u8 enc_key023[] __initconst = {
++	0x11, 0x31, 0xc1, 0x41, 0x85, 0x77, 0xa0, 0x54,
++	0xde, 0x7a, 0x4a, 0xc5, 0x51, 0x95, 0x0f, 0x1a,
++	0x05, 0x3f, 0x9a, 0xe4, 0x6e, 0x5b, 0x75, 0xfe,
++	0x4a, 0xbd, 0x56, 0x08, 0xd7, 0xcd, 0xda, 0xdd
++};
++
++/* wycheproof - misc */
++static const u8 enc_input024[] __initconst = {
++	0x42, 0xba, 0xae, 0x59, 0x78, 0xfe, 0xaf, 0x5c,
++	0x36, 0x8d, 0x14, 0xe0
++};
++static const u8 enc_output024[] __initconst = {
++	0xff, 0x7d, 0xc2, 0x03, 0xb2, 0x6c, 0x46, 0x7a,
++	0x6b, 0x50, 0xdb, 0x33, 0x57, 0x8c, 0x0f, 0x27,
++	0x58, 0xc2, 0xe1, 0x4e, 0x36, 0xd4, 0xfc, 0x10,
++	0x6d, 0xcb, 0x29, 0xb4
++};
++static const u8 enc_assoc024[] __initconst = { };
++static const u8 enc_nonce024[] __initconst = {
++	0x9a, 0x59, 0xfc, 0xe2, 0x6d, 0xf0, 0x00, 0x5e,
++	0x07, 0x53, 0x86, 0x56
++};
++static const u8 enc_key024[] __initconst = {
++	0x99, 0xb6, 0x2b, 0xd5, 0xaf, 0xbe, 0x3f, 0xb0,
++	0x15, 0xbd, 0xe9, 0x3f, 0x0a, 0xbf, 0x48, 0x39,
++	0x57, 0xa1, 0xc3, 0xeb, 0x3c, 0xa5, 0x9c, 0xb5,
++	0x0b, 0x39, 0xf7, 0xf8, 0xa9, 0xcc, 0x51, 0xbe
++};
++
++/* wycheproof - misc */
++static const u8 enc_input025[] __initconst = {
++	0xfd, 0xc8, 0x5b, 0x94, 0xa4, 0xb2, 0xa6, 0xb7,
++	0x59, 0xb1, 0xa0, 0xda
++};
++static const u8 enc_output025[] __initconst = {
++	0x9f, 0x88, 0x16, 0xde, 0x09, 0x94, 0xe9, 0x38,
++	0xd9, 0xe5, 0x3f, 0x95, 0xd0, 0x86, 0xfc, 0x6c,
++	0x9d, 0x8f, 0xa9, 0x15, 0xfd, 0x84, 0x23, 0xa7,
++	0xcf, 0x05, 0x07, 0x2f
++};
++static const u8 enc_assoc025[] __initconst = {
++	0xa5, 0x06, 0xe1, 0xa5, 0xc6, 0x90, 0x93, 0xf9
++};
++static const u8 enc_nonce025[] __initconst = {
++	0x58, 0xdb, 0xd4, 0xad, 0x2c, 0x4a, 0xd3, 0x5d,
++	0xd9, 0x06, 0xe9, 0xce
++};
++static const u8 enc_key025[] __initconst = {
++	0x85, 0xf3, 0x5b, 0x62, 0x82, 0xcf, 0xf4, 0x40,
++	0xbc, 0x10, 0x20, 0xc8, 0x13, 0x6f, 0xf2, 0x70,
++	0x31, 0x11, 0x0f, 0xa6, 0x3e, 0xc1, 0x6f, 0x1e,
++	0x82, 0x51, 0x18, 0xb0, 0x06, 0xb9, 0x12, 0x57
++};
++
++/* wycheproof - misc */
++static const u8 enc_input026[] __initconst = {
++	0x51, 0xf8, 0xc1, 0xf7, 0x31, 0xea, 0x14, 0xac,
++	0xdb, 0x21, 0x0a, 0x6d, 0x97, 0x3e, 0x07
++};
++static const u8 enc_output026[] __initconst = {
++	0x0b, 0x29, 0x63, 0x8e, 0x1f, 0xbd, 0xd6, 0xdf,
++	0x53, 0x97, 0x0b, 0xe2, 0x21, 0x00, 0x42, 0x2a,
++	0x91, 0x34, 0x08, 0x7d, 0x67, 0xa4, 0x6e, 0x79,
++	0x17, 0x8d, 0x0a, 0x93, 0xf5, 0xe1, 0xd2
++};
++static const u8 enc_assoc026[] __initconst = { };
++static const u8 enc_nonce026[] __initconst = {
++	0x68, 0xab, 0x7f, 0xdb, 0xf6, 0x19, 0x01, 0xda,
++	0xd4, 0x61, 0xd2, 0x3c
++};
++static const u8 enc_key026[] __initconst = {
++	0x67, 0x11, 0x96, 0x27, 0xbd, 0x98, 0x8e, 0xda,
++	0x90, 0x62, 0x19, 0xe0, 0x8c, 0x0d, 0x0d, 0x77,
++	0x9a, 0x07, 0xd2, 0x08, 0xce, 0x8a, 0x4f, 0xe0,
++	0x70, 0x9a, 0xf7, 0x55, 0xee, 0xec, 0x6d, 0xcb
++};
++
++/* wycheproof - misc */
++static const u8 enc_input027[] __initconst = {
++	0x97, 0x46, 0x9d, 0xa6, 0x67, 0xd6, 0x11, 0x0f,
++	0x9c, 0xbd, 0xa1, 0xd1, 0xa2, 0x06, 0x73
++};
++static const u8 enc_output027[] __initconst = {
++	0x32, 0xdb, 0x66, 0xc4, 0xa3, 0x81, 0x9d, 0x81,
++	0x55, 0x74, 0x55, 0xe5, 0x98, 0x0f, 0xed, 0xfe,
++	0xae, 0x30, 0xde, 0xc9, 0x4e, 0x6a, 0xd3, 0xa9,
++	0xee, 0xa0, 0x6a, 0x0d, 0x70, 0x39, 0x17
++};
++static const u8 enc_assoc027[] __initconst = {
++	0x64, 0x53, 0xa5, 0x33, 0x84, 0x63, 0x22, 0x12
++};
++static const u8 enc_nonce027[] __initconst = {
++	0xd9, 0x5b, 0x32, 0x43, 0xaf, 0xae, 0xf7, 0x14,
++	0xc5, 0x03, 0x5b, 0x6a
++};
++static const u8 enc_key027[] __initconst = {
++	0xe6, 0xf1, 0x11, 0x8d, 0x41, 0xe4, 0xb4, 0x3f,
++	0xb5, 0x82, 0x21, 0xb7, 0xed, 0x79, 0x67, 0x38,
++	0x34, 0xe0, 0xd8, 0xac, 0x5c, 0x4f, 0xa6, 0x0b,
++	0xbc, 0x8b, 0xc4, 0x89, 0x3a, 0x58, 0x89, 0x4d
++};
++
++/* wycheproof - misc */
++static const u8 enc_input028[] __initconst = {
++	0x54, 0x9b, 0x36, 0x5a, 0xf9, 0x13, 0xf3, 0xb0,
++	0x81, 0x13, 0x1c, 0xcb, 0x6b, 0x82, 0x55, 0x88
++};
++static const u8 enc_output028[] __initconst = {
++	0xe9, 0x11, 0x0e, 0x9f, 0x56, 0xab, 0x3c, 0xa4,
++	0x83, 0x50, 0x0c, 0xea, 0xba, 0xb6, 0x7a, 0x13,
++	0x83, 0x6c, 0xca, 0xbf, 0x15, 0xa6, 0xa2, 0x2a,
++	0x51, 0xc1, 0x07, 0x1c, 0xfa, 0x68, 0xfa, 0x0c
++};
++static const u8 enc_assoc028[] __initconst = { };
++static const u8 enc_nonce028[] __initconst = {
++	0x2f, 0xcb, 0x1b, 0x38, 0xa9, 0x9e, 0x71, 0xb8,
++	0x47, 0x40, 0xad, 0x9b
++};
++static const u8 enc_key028[] __initconst = {
++	0x59, 0xd4, 0xea, 0xfb, 0x4d, 0xe0, 0xcf, 0xc7,
++	0xd3, 0xdb, 0x99, 0xa8, 0xf5, 0x4b, 0x15, 0xd7,
++	0xb3, 0x9f, 0x0a, 0xcc, 0x8d, 0xa6, 0x97, 0x63,
++	0xb0, 0x19, 0xc1, 0x69, 0x9f, 0x87, 0x67, 0x4a
++};
++
++/* wycheproof - misc */
++static const u8 enc_input029[] __initconst = {
++	0x55, 0xa4, 0x65, 0x64, 0x4f, 0x5b, 0x65, 0x09,
++	0x28, 0xcb, 0xee, 0x7c, 0x06, 0x32, 0x14, 0xd6
++};
++static const u8 enc_output029[] __initconst = {
++	0xe4, 0xb1, 0x13, 0xcb, 0x77, 0x59, 0x45, 0xf3,
++	0xd3, 0xa8, 0xae, 0x9e, 0xc1, 0x41, 0xc0, 0x0c,
++	0x7c, 0x43, 0xf1, 0x6c, 0xe0, 0x96, 0xd0, 0xdc,
++	0x27, 0xc9, 0x58, 0x49, 0xdc, 0x38, 0x3b, 0x7d
++};
++static const u8 enc_assoc029[] __initconst = {
++	0x03, 0x45, 0x85, 0x62, 0x1a, 0xf8, 0xd7, 0xff
++};
++static const u8 enc_nonce029[] __initconst = {
++	0x11, 0x8a, 0x69, 0x64, 0xc2, 0xd3, 0xe3, 0x80,
++	0x07, 0x1f, 0x52, 0x66
++};
++static const u8 enc_key029[] __initconst = {
++	0xb9, 0x07, 0xa4, 0x50, 0x75, 0x51, 0x3f, 0xe8,
++	0xa8, 0x01, 0x9e, 0xde, 0xe3, 0xf2, 0x59, 0x14,
++	0x87, 0xb2, 0xa0, 0x30, 0xb0, 0x3c, 0x6e, 0x1d,
++	0x77, 0x1c, 0x86, 0x25, 0x71, 0xd2, 0xea, 0x1e
++};
++
++/* wycheproof - misc */
++static const u8 enc_input030[] __initconst = {
++	0x3f, 0xf1, 0x51, 0x4b, 0x1c, 0x50, 0x39, 0x15,
++	0x91, 0x8f, 0x0c, 0x0c, 0x31, 0x09, 0x4a, 0x6e,
++	0x1f
++};
++static const u8 enc_output030[] __initconst = {
++	0x02, 0xcc, 0x3a, 0xcb, 0x5e, 0xe1, 0xfc, 0xdd,
++	0x12, 0xa0, 0x3b, 0xb8, 0x57, 0x97, 0x64, 0x74,
++	0xd3, 0xd8, 0x3b, 0x74, 0x63, 0xa2, 0xc3, 0x80,
++	0x0f, 0xe9, 0x58, 0xc2, 0x8e, 0xaa, 0x29, 0x08,
++	0x13
++};
++static const u8 enc_assoc030[] __initconst = { };
++static const u8 enc_nonce030[] __initconst = {
++	0x45, 0xaa, 0xa3, 0xe5, 0xd1, 0x6d, 0x2d, 0x42,
++	0xdc, 0x03, 0x44, 0x5d
++};
++static const u8 enc_key030[] __initconst = {
++	0x3b, 0x24, 0x58, 0xd8, 0x17, 0x6e, 0x16, 0x21,
++	0xc0, 0xcc, 0x24, 0xc0, 0xc0, 0xe2, 0x4c, 0x1e,
++	0x80, 0xd7, 0x2f, 0x7e, 0xe9, 0x14, 0x9a, 0x4b,
++	0x16, 0x61, 0x76, 0x62, 0x96, 0x16, 0xd0, 0x11
++};
++
++/* wycheproof - misc */
++static const u8 enc_input031[] __initconst = {
++	0x63, 0x85, 0x8c, 0xa3, 0xe2, 0xce, 0x69, 0x88,
++	0x7b, 0x57, 0x8a, 0x3c, 0x16, 0x7b, 0x42, 0x1c,
++	0x9c
++};
++static const u8 enc_output031[] __initconst = {
++	0x35, 0x76, 0x64, 0x88, 0xd2, 0xbc, 0x7c, 0x2b,
++	0x8d, 0x17, 0xcb, 0xbb, 0x9a, 0xbf, 0xad, 0x9e,
++	0x6d, 0x1f, 0x39, 0x1e, 0x65, 0x7b, 0x27, 0x38,
++	0xdd, 0xa0, 0x84, 0x48, 0xcb, 0xa2, 0x81, 0x1c,
++	0xeb
++};
++static const u8 enc_assoc031[] __initconst = {
++	0x9a, 0xaf, 0x29, 0x9e, 0xee, 0xa7, 0x8f, 0x79
++};
++static const u8 enc_nonce031[] __initconst = {
++	0xf0, 0x38, 0x4f, 0xb8, 0x76, 0x12, 0x14, 0x10,
++	0x63, 0x3d, 0x99, 0x3d
++};
++static const u8 enc_key031[] __initconst = {
++	0xf6, 0x0c, 0x6a, 0x1b, 0x62, 0x57, 0x25, 0xf7,
++	0x6c, 0x70, 0x37, 0xb4, 0x8f, 0xe3, 0x57, 0x7f,
++	0xa7, 0xf7, 0xb8, 0x7b, 0x1b, 0xd5, 0xa9, 0x82,
++	0x17, 0x6d, 0x18, 0x23, 0x06, 0xff, 0xb8, 0x70
++};
++
++/* wycheproof - misc */
++static const u8 enc_input032[] __initconst = {
++	0x10, 0xf1, 0xec, 0xf9, 0xc6, 0x05, 0x84, 0x66,
++	0x5d, 0x9a, 0xe5, 0xef, 0xe2, 0x79, 0xe7, 0xf7,
++	0x37, 0x7e, 0xea, 0x69, 0x16, 0xd2, 0xb1, 0x11
++};
++static const u8 enc_output032[] __initconst = {
++	0x42, 0xf2, 0x6c, 0x56, 0xcb, 0x4b, 0xe2, 0x1d,
++	0x9d, 0x8d, 0x0c, 0x80, 0xfc, 0x99, 0xdd, 0xe0,
++	0x0d, 0x75, 0xf3, 0x80, 0x74, 0xbf, 0xe7, 0x64,
++	0x54, 0xaa, 0x7e, 0x13, 0xd4, 0x8f, 0xff, 0x7d,
++	0x75, 0x57, 0x03, 0x94, 0x57, 0x04, 0x0a, 0x3a
++};
++static const u8 enc_assoc032[] __initconst = { };
++static const u8 enc_nonce032[] __initconst = {
++	0xe6, 0xb1, 0xad, 0xf2, 0xfd, 0x58, 0xa8, 0x76,
++	0x2c, 0x65, 0xf3, 0x1b
++};
++static const u8 enc_key032[] __initconst = {
++	0x02, 0x12, 0xa8, 0xde, 0x50, 0x07, 0xed, 0x87,
++	0xb3, 0x3f, 0x1a, 0x70, 0x90, 0xb6, 0x11, 0x4f,
++	0x9e, 0x08, 0xce, 0xfd, 0x96, 0x07, 0xf2, 0xc2,
++	0x76, 0xbd, 0xcf, 0xdb, 0xc5, 0xce, 0x9c, 0xd7
++};
++
++/* wycheproof - misc */
++static const u8 enc_input033[] __initconst = {
++	0x92, 0x22, 0xf9, 0x01, 0x8e, 0x54, 0xfd, 0x6d,
++	0xe1, 0x20, 0x08, 0x06, 0xa9, 0xee, 0x8e, 0x4c,
++	0xc9, 0x04, 0xd2, 0x9f, 0x25, 0xcb, 0xa1, 0x93
++};
++static const u8 enc_output033[] __initconst = {
++	0x12, 0x30, 0x32, 0x43, 0x7b, 0x4b, 0xfd, 0x69,
++	0x20, 0xe8, 0xf7, 0xe7, 0xe0, 0x08, 0x7a, 0xe4,
++	0x88, 0x9e, 0xbe, 0x7a, 0x0a, 0xd0, 0xe9, 0x00,
++	0x3c, 0xf6, 0x8f, 0x17, 0x95, 0x50, 0xda, 0x63,
++	0xd3, 0xb9, 0x6c, 0x2d, 0x55, 0x41, 0x18, 0x65
++};
++static const u8 enc_assoc033[] __initconst = {
++	0x3e, 0x8b, 0xc5, 0xad, 0xe1, 0x82, 0xff, 0x08
++};
++static const u8 enc_nonce033[] __initconst = {
++	0x6b, 0x28, 0x2e, 0xbe, 0xcc, 0x54, 0x1b, 0xcd,
++	0x78, 0x34, 0xed, 0x55
++};
++static const u8 enc_key033[] __initconst = {
++	0xc5, 0xbc, 0x09, 0x56, 0x56, 0x46, 0xe7, 0xed,
++	0xda, 0x95, 0x4f, 0x1f, 0x73, 0x92, 0x23, 0xda,
++	0xda, 0x20, 0xb9, 0x5c, 0x44, 0xab, 0x03, 0x3d,
++	0x0f, 0xae, 0x4b, 0x02, 0x83, 0xd1, 0x8b, 0xe3
++};
++
++/* wycheproof - misc */
++static const u8 enc_input034[] __initconst = {
++	0xb0, 0x53, 0x99, 0x92, 0x86, 0xa2, 0x82, 0x4f,
++	0x42, 0xcc, 0x8c, 0x20, 0x3a, 0xb2, 0x4e, 0x2c,
++	0x97, 0xa6, 0x85, 0xad, 0xcc, 0x2a, 0xd3, 0x26,
++	0x62, 0x55, 0x8e, 0x55, 0xa5, 0xc7, 0x29
++};
++static const u8 enc_output034[] __initconst = {
++	0x45, 0xc7, 0xd6, 0xb5, 0x3a, 0xca, 0xd4, 0xab,
++	0xb6, 0x88, 0x76, 0xa6, 0xe9, 0x6a, 0x48, 0xfb,
++	0x59, 0x52, 0x4d, 0x2c, 0x92, 0xc9, 0xd8, 0xa1,
++	0x89, 0xc9, 0xfd, 0x2d, 0xb9, 0x17, 0x46, 0x56,
++	0x6d, 0x3c, 0xa1, 0x0e, 0x31, 0x1b, 0x69, 0x5f,
++	0x3e, 0xae, 0x15, 0x51, 0x65, 0x24, 0x93
++};
++static const u8 enc_assoc034[] __initconst = { };
++static const u8 enc_nonce034[] __initconst = {
++	0x04, 0xa9, 0xbe, 0x03, 0x50, 0x8a, 0x5f, 0x31,
++	0x37, 0x1a, 0x6f, 0xd2
++};
++static const u8 enc_key034[] __initconst = {
++	0x2e, 0xb5, 0x1c, 0x46, 0x9a, 0xa8, 0xeb, 0x9e,
++	0x6c, 0x54, 0xa8, 0x34, 0x9b, 0xae, 0x50, 0xa2,
++	0x0f, 0x0e, 0x38, 0x27, 0x11, 0xbb, 0xa1, 0x15,
++	0x2c, 0x42, 0x4f, 0x03, 0xb6, 0x67, 0x1d, 0x71
++};
++
++/* wycheproof - misc */
++static const u8 enc_input035[] __initconst = {
++	0xf4, 0x52, 0x06, 0xab, 0xc2, 0x55, 0x52, 0xb2,
++	0xab, 0xc9, 0xab, 0x7f, 0xa2, 0x43, 0x03, 0x5f,
++	0xed, 0xaa, 0xdd, 0xc3, 0xb2, 0x29, 0x39, 0x56,
++	0xf1, 0xea, 0x6e, 0x71, 0x56, 0xe7, 0xeb
++};
++static const u8 enc_output035[] __initconst = {
++	0x46, 0xa8, 0x0c, 0x41, 0x87, 0x02, 0x47, 0x20,
++	0x08, 0x46, 0x27, 0x58, 0x00, 0x80, 0xdd, 0xe5,
++	0xa3, 0xf4, 0xa1, 0x10, 0x93, 0xa7, 0x07, 0x6e,
++	0xd6, 0xf3, 0xd3, 0x26, 0xbc, 0x7b, 0x70, 0x53,
++	0x4d, 0x4a, 0xa2, 0x83, 0x5a, 0x52, 0xe7, 0x2d,
++	0x14, 0xdf, 0x0e, 0x4f, 0x47, 0xf2, 0x5f
++};
++static const u8 enc_assoc035[] __initconst = {
++	0x37, 0x46, 0x18, 0xa0, 0x6e, 0xa9, 0x8a, 0x48
++};
++static const u8 enc_nonce035[] __initconst = {
++	0x47, 0x0a, 0x33, 0x9e, 0xcb, 0x32, 0x19, 0xb8,
++	0xb8, 0x1a, 0x1f, 0x8b
++};
++static const u8 enc_key035[] __initconst = {
++	0x7f, 0x5b, 0x74, 0xc0, 0x7e, 0xd1, 0xb4, 0x0f,
++	0xd1, 0x43, 0x58, 0xfe, 0x2f, 0xf2, 0xa7, 0x40,
++	0xc1, 0x16, 0xc7, 0x70, 0x65, 0x10, 0xe6, 0xa4,
++	0x37, 0xf1, 0x9e, 0xa4, 0x99, 0x11, 0xce, 0xc4
++};
++
++/* wycheproof - misc */
++static const u8 enc_input036[] __initconst = {
++	0xb9, 0xc5, 0x54, 0xcb, 0xc3, 0x6a, 0xc1, 0x8a,
++	0xe8, 0x97, 0xdf, 0x7b, 0xee, 0xca, 0xc1, 0xdb,
++	0xeb, 0x4e, 0xaf, 0xa1, 0x56, 0xbb, 0x60, 0xce,
++	0x2e, 0x5d, 0x48, 0xf0, 0x57, 0x15, 0xe6, 0x78
++};
++static const u8 enc_output036[] __initconst = {
++	0xea, 0x29, 0xaf, 0xa4, 0x9d, 0x36, 0xe8, 0x76,
++	0x0f, 0x5f, 0xe1, 0x97, 0x23, 0xb9, 0x81, 0x1e,
++	0xd5, 0xd5, 0x19, 0x93, 0x4a, 0x44, 0x0f, 0x50,
++	0x81, 0xac, 0x43, 0x0b, 0x95, 0x3b, 0x0e, 0x21,
++	0x22, 0x25, 0x41, 0xaf, 0x46, 0xb8, 0x65, 0x33,
++	0xc6, 0xb6, 0x8d, 0x2f, 0xf1, 0x08, 0xa7, 0xea
++};
++static const u8 enc_assoc036[] __initconst = { };
++static const u8 enc_nonce036[] __initconst = {
++	0x72, 0xcf, 0xd9, 0x0e, 0xf3, 0x02, 0x6c, 0xa2,
++	0x2b, 0x7e, 0x6e, 0x6a
++};
++static const u8 enc_key036[] __initconst = {
++	0xe1, 0x73, 0x1d, 0x58, 0x54, 0xe1, 0xb7, 0x0c,
++	0xb3, 0xff, 0xe8, 0xb7, 0x86, 0xa2, 0xb3, 0xeb,
++	0xf0, 0x99, 0x43, 0x70, 0x95, 0x47, 0x57, 0xb9,
++	0xdc, 0x8c, 0x7b, 0xc5, 0x35, 0x46, 0x34, 0xa3
++};
++
++/* wycheproof - misc */
++static const u8 enc_input037[] __initconst = {
++	0x6b, 0x26, 0x04, 0x99, 0x6c, 0xd3, 0x0c, 0x14,
++	0xa1, 0x3a, 0x52, 0x57, 0xed, 0x6c, 0xff, 0xd3,
++	0xbc, 0x5e, 0x29, 0xd6, 0xb9, 0x7e, 0xb1, 0x79,
++	0x9e, 0xb3, 0x35, 0xe2, 0x81, 0xea, 0x45, 0x1e
++};
++static const u8 enc_output037[] __initconst = {
++	0x6d, 0xad, 0x63, 0x78, 0x97, 0x54, 0x4d, 0x8b,
++	0xf6, 0xbe, 0x95, 0x07, 0xed, 0x4d, 0x1b, 0xb2,
++	0xe9, 0x54, 0xbc, 0x42, 0x7e, 0x5d, 0xe7, 0x29,
++	0xda, 0xf5, 0x07, 0x62, 0x84, 0x6f, 0xf2, 0xf4,
++	0x7b, 0x99, 0x7d, 0x93, 0xc9, 0x82, 0x18, 0x9d,
++	0x70, 0x95, 0xdc, 0x79, 0x4c, 0x74, 0x62, 0x32
++};
++static const u8 enc_assoc037[] __initconst = {
++	0x23, 0x33, 0xe5, 0xce, 0x0f, 0x93, 0xb0, 0x59
++};
++static const u8 enc_nonce037[] __initconst = {
++	0x26, 0x28, 0x80, 0xd4, 0x75, 0xf3, 0xda, 0xc5,
++	0x34, 0x0d, 0xd1, 0xb8
++};
++static const u8 enc_key037[] __initconst = {
++	0x27, 0xd8, 0x60, 0x63, 0x1b, 0x04, 0x85, 0xa4,
++	0x10, 0x70, 0x2f, 0xea, 0x61, 0xbc, 0x87, 0x3f,
++	0x34, 0x42, 0x26, 0x0c, 0xad, 0xed, 0x4a, 0xbd,
++	0xe2, 0x5b, 0x78, 0x6a, 0x2d, 0x97, 0xf1, 0x45
++};
++
++/* wycheproof - misc */
++static const u8 enc_input038[] __initconst = {
++	0x97, 0x3d, 0x0c, 0x75, 0x38, 0x26, 0xba, 0xe4,
++	0x66, 0xcf, 0x9a, 0xbb, 0x34, 0x93, 0x15, 0x2e,
++	0x9d, 0xe7, 0x81, 0x9e, 0x2b, 0xd0, 0xc7, 0x11,
++	0x71, 0x34, 0x6b, 0x4d, 0x2c, 0xeb, 0xf8, 0x04,
++	0x1a, 0xa3, 0xce, 0xdc, 0x0d, 0xfd, 0x7b, 0x46,
++	0x7e, 0x26, 0x22, 0x8b, 0xc8, 0x6c, 0x9a
++};
++static const u8 enc_output038[] __initconst = {
++	0xfb, 0xa7, 0x8a, 0xe4, 0xf9, 0xd8, 0x08, 0xa6,
++	0x2e, 0x3d, 0xa4, 0x0b, 0xe2, 0xcb, 0x77, 0x00,
++	0xc3, 0x61, 0x3d, 0x9e, 0xb2, 0xc5, 0x29, 0xc6,
++	0x52, 0xe7, 0x6a, 0x43, 0x2c, 0x65, 0x8d, 0x27,
++	0x09, 0x5f, 0x0e, 0xb8, 0xf9, 0x40, 0xc3, 0x24,
++	0x98, 0x1e, 0xa9, 0x35, 0xe5, 0x07, 0xf9, 0x8f,
++	0x04, 0x69, 0x56, 0xdb, 0x3a, 0x51, 0x29, 0x08,
++	0xbd, 0x7a, 0xfc, 0x8f, 0x2a, 0xb0, 0xa9
++};
++static const u8 enc_assoc038[] __initconst = { };
++static const u8 enc_nonce038[] __initconst = {
++	0xe7, 0x4a, 0x51, 0x5e, 0x7e, 0x21, 0x02, 0xb9,
++	0x0b, 0xef, 0x55, 0xd2
++};
++static const u8 enc_key038[] __initconst = {
++	0xcf, 0x0d, 0x40, 0xa4, 0x64, 0x4e, 0x5f, 0x51,
++	0x81, 0x51, 0x65, 0xd5, 0x30, 0x1b, 0x22, 0x63,
++	0x1f, 0x45, 0x44, 0xc4, 0x9a, 0x18, 0x78, 0xe3,
++	0xa0, 0xa5, 0xe8, 0xe1, 0xaa, 0xe0, 0xf2, 0x64
++};
++
++/* wycheproof - misc */
++static const u8 enc_input039[] __initconst = {
++	0xa9, 0x89, 0x95, 0x50, 0x4d, 0xf1, 0x6f, 0x74,
++	0x8b, 0xfb, 0x77, 0x85, 0xff, 0x91, 0xee, 0xb3,
++	0xb6, 0x60, 0xea, 0x9e, 0xd3, 0x45, 0x0c, 0x3d,
++	0x5e, 0x7b, 0x0e, 0x79, 0xef, 0x65, 0x36, 0x59,
++	0xa9, 0x97, 0x8d, 0x75, 0x54, 0x2e, 0xf9, 0x1c,
++	0x45, 0x67, 0x62, 0x21, 0x56, 0x40, 0xb9
++};
++static const u8 enc_output039[] __initconst = {
++	0xa1, 0xff, 0xed, 0x80, 0x76, 0x18, 0x29, 0xec,
++	0xce, 0x24, 0x2e, 0x0e, 0x88, 0xb1, 0x38, 0x04,
++	0x90, 0x16, 0xbc, 0xa0, 0x18, 0xda, 0x2b, 0x6e,
++	0x19, 0x98, 0x6b, 0x3e, 0x31, 0x8c, 0xae, 0x8d,
++	0x80, 0x61, 0x98, 0xfb, 0x4c, 0x52, 0x7c, 0xc3,
++	0x93, 0x50, 0xeb, 0xdd, 0xea, 0xc5, 0x73, 0xc4,
++	0xcb, 0xf0, 0xbe, 0xfd, 0xa0, 0xb7, 0x02, 0x42,
++	0xc6, 0x40, 0xd7, 0xcd, 0x02, 0xd7, 0xa3
++};
++static const u8 enc_assoc039[] __initconst = {
++	0xb3, 0xe4, 0x06, 0x46, 0x83, 0xb0, 0x2d, 0x84
++};
++static const u8 enc_nonce039[] __initconst = {
++	0xd4, 0xd8, 0x07, 0x34, 0x16, 0x83, 0x82, 0x5b,
++	0x31, 0xcd, 0x4d, 0x95
++};
++static const u8 enc_key039[] __initconst = {
++	0x6c, 0xbf, 0xd7, 0x1c, 0x64, 0x5d, 0x18, 0x4c,
++	0xf5, 0xd2, 0x3c, 0x40, 0x2b, 0xdb, 0x0d, 0x25,
++	0xec, 0x54, 0x89, 0x8c, 0x8a, 0x02, 0x73, 0xd4,
++	0x2e, 0xb5, 0xbe, 0x10, 0x9f, 0xdc, 0xb2, 0xac
++};
++
++/* wycheproof - misc */
++static const u8 enc_input040[] __initconst = {
++	0xd0, 0x96, 0x80, 0x31, 0x81, 0xbe, 0xef, 0x9e,
++	0x00, 0x8f, 0xf8, 0x5d, 0x5d, 0xdc, 0x38, 0xdd,
++	0xac, 0xf0, 0xf0, 0x9e, 0xe5, 0xf7, 0xe0, 0x7f,
++	0x1e, 0x40, 0x79, 0xcb, 0x64, 0xd0, 0xdc, 0x8f,
++	0x5e, 0x67, 0x11, 0xcd, 0x49, 0x21, 0xa7, 0x88,
++	0x7d, 0xe7, 0x6e, 0x26, 0x78, 0xfd, 0xc6, 0x76,
++	0x18, 0xf1, 0x18, 0x55, 0x86, 0xbf, 0xea, 0x9d,
++	0x4c, 0x68, 0x5d, 0x50, 0xe4, 0xbb, 0x9a, 0x82
++};
++static const u8 enc_output040[] __initconst = {
++	0x9a, 0x4e, 0xf2, 0x2b, 0x18, 0x16, 0x77, 0xb5,
++	0x75, 0x5c, 0x08, 0xf7, 0x47, 0xc0, 0xf8, 0xd8,
++	0xe8, 0xd4, 0xc1, 0x8a, 0x9c, 0xc2, 0x40, 0x5c,
++	0x12, 0xbb, 0x51, 0xbb, 0x18, 0x72, 0xc8, 0xe8,
++	0xb8, 0x77, 0x67, 0x8b, 0xec, 0x44, 0x2c, 0xfc,
++	0xbb, 0x0f, 0xf4, 0x64, 0xa6, 0x4b, 0x74, 0x33,
++	0x2c, 0xf0, 0x72, 0x89, 0x8c, 0x7e, 0x0e, 0xdd,
++	0xf6, 0x23, 0x2e, 0xa6, 0xe2, 0x7e, 0xfe, 0x50,
++	0x9f, 0xf3, 0x42, 0x7a, 0x0f, 0x32, 0xfa, 0x56,
++	0x6d, 0x9c, 0xa0, 0xa7, 0x8a, 0xef, 0xc0, 0x13
++};
++static const u8 enc_assoc040[] __initconst = { };
++static const u8 enc_nonce040[] __initconst = {
++	0xd6, 0x10, 0x40, 0xa3, 0x13, 0xed, 0x49, 0x28,
++	0x23, 0xcc, 0x06, 0x5b
++};
++static const u8 enc_key040[] __initconst = {
++	0x5b, 0x1d, 0x10, 0x35, 0xc0, 0xb1, 0x7e, 0xe0,
++	0xb0, 0x44, 0x47, 0x67, 0xf8, 0x0a, 0x25, 0xb8,
++	0xc1, 0xb7, 0x41, 0xf4, 0xb5, 0x0a, 0x4d, 0x30,
++	0x52, 0x22, 0x6b, 0xaa, 0x1c, 0x6f, 0xb7, 0x01
++};
++
++/* wycheproof - misc */
++static const u8 enc_input041[] __initconst = {
++	0x94, 0xee, 0x16, 0x6d, 0x6d, 0x6e, 0xcf, 0x88,
++	0x32, 0x43, 0x71, 0x36, 0xb4, 0xae, 0x80, 0x5d,
++	0x42, 0x88, 0x64, 0x35, 0x95, 0x86, 0xd9, 0x19,
++	0x3a, 0x25, 0x01, 0x62, 0x93, 0xed, 0xba, 0x44,
++	0x3c, 0x58, 0xe0, 0x7e, 0x7b, 0x71, 0x95, 0xec,
++	0x5b, 0xd8, 0x45, 0x82, 0xa9, 0xd5, 0x6c, 0x8d,
++	0x4a, 0x10, 0x8c, 0x7d, 0x7c, 0xe3, 0x4e, 0x6c,
++	0x6f, 0x8e, 0xa1, 0xbe, 0xc0, 0x56, 0x73, 0x17
++};
++static const u8 enc_output041[] __initconst = {
++	0x5f, 0xbb, 0xde, 0xcc, 0x34, 0xbe, 0x20, 0x16,
++	0x14, 0xf6, 0x36, 0x03, 0x1e, 0xeb, 0x42, 0xf1,
++	0xca, 0xce, 0x3c, 0x79, 0xa1, 0x2c, 0xff, 0xd8,
++	0x71, 0xee, 0x8e, 0x73, 0x82, 0x0c, 0x82, 0x97,
++	0x49, 0xf1, 0xab, 0xb4, 0x29, 0x43, 0x67, 0x84,
++	0x9f, 0xb6, 0xc2, 0xaa, 0x56, 0xbd, 0xa8, 0xa3,
++	0x07, 0x8f, 0x72, 0x3d, 0x7c, 0x1c, 0x85, 0x20,
++	0x24, 0xb0, 0x17, 0xb5, 0x89, 0x73, 0xfb, 0x1e,
++	0x09, 0x26, 0x3d, 0xa7, 0xb4, 0xcb, 0x92, 0x14,
++	0x52, 0xf9, 0x7d, 0xca, 0x40, 0xf5, 0x80, 0xec
++};
++static const u8 enc_assoc041[] __initconst = {
++	0x71, 0x93, 0xf6, 0x23, 0x66, 0x33, 0x21, 0xa2
++};
++static const u8 enc_nonce041[] __initconst = {
++	0xd3, 0x1c, 0x21, 0xab, 0xa1, 0x75, 0xb7, 0x0d,
++	0xe4, 0xeb, 0xb1, 0x9c
++};
++static const u8 enc_key041[] __initconst = {
++	0x97, 0xd6, 0x35, 0xc4, 0xf4, 0x75, 0x74, 0xd9,
++	0x99, 0x8a, 0x90, 0x87, 0x5d, 0xa1, 0xd3, 0xa2,
++	0x84, 0xb7, 0x55, 0xb2, 0xd3, 0x92, 0x97, 0xa5,
++	0x72, 0x52, 0x35, 0x19, 0x0e, 0x10, 0xa9, 0x7e
++};
++
++/* wycheproof - misc */
++static const u8 enc_input042[] __initconst = {
++	0xb4, 0x29, 0xeb, 0x80, 0xfb, 0x8f, 0xe8, 0xba,
++	0xed, 0xa0, 0xc8, 0x5b, 0x9c, 0x33, 0x34, 0x58,
++	0xe7, 0xc2, 0x99, 0x2e, 0x55, 0x84, 0x75, 0x06,
++	0x9d, 0x12, 0xd4, 0x5c, 0x22, 0x21, 0x75, 0x64,
++	0x12, 0x15, 0x88, 0x03, 0x22, 0x97, 0xef, 0xf5,
++	0x67, 0x83, 0x74, 0x2a, 0x5f, 0xc2, 0x2d, 0x74,
++	0x10, 0xff, 0xb2, 0x9d, 0x66, 0x09, 0x86, 0x61,
++	0xd7, 0x6f, 0x12, 0x6c, 0x3c, 0x27, 0x68, 0x9e,
++	0x43, 0xb3, 0x72, 0x67, 0xca, 0xc5, 0xa3, 0xa6,
++	0xd3, 0xab, 0x49, 0xe3, 0x91, 0xda, 0x29, 0xcd,
++	0x30, 0x54, 0xa5, 0x69, 0x2e, 0x28, 0x07, 0xe4,
++	0xc3, 0xea, 0x46, 0xc8, 0x76, 0x1d, 0x50, 0xf5,
++	0x92
++};
++static const u8 enc_output042[] __initconst = {
++	0xd0, 0x10, 0x2f, 0x6c, 0x25, 0x8b, 0xf4, 0x97,
++	0x42, 0xce, 0xc3, 0x4c, 0xf2, 0xd0, 0xfe, 0xdf,
++	0x23, 0xd1, 0x05, 0xfb, 0x4c, 0x84, 0xcf, 0x98,
++	0x51, 0x5e, 0x1b, 0xc9, 0xa6, 0x4f, 0x8a, 0xd5,
++	0xbe, 0x8f, 0x07, 0x21, 0xbd, 0xe5, 0x06, 0x45,
++	0xd0, 0x00, 0x83, 0xc3, 0xa2, 0x63, 0xa3, 0x10,
++	0x53, 0xb7, 0x60, 0x24, 0x5f, 0x52, 0xae, 0x28,
++	0x66, 0xa5, 0xec, 0x83, 0xb1, 0x9f, 0x61, 0xbe,
++	0x1d, 0x30, 0xd5, 0xc5, 0xd9, 0xfe, 0xcc, 0x4c,
++	0xbb, 0xe0, 0x8f, 0xd3, 0x85, 0x81, 0x3a, 0x2a,
++	0xa3, 0x9a, 0x00, 0xff, 0x9c, 0x10, 0xf7, 0xf2,
++	0x37, 0x02, 0xad, 0xd1, 0xe4, 0xb2, 0xff, 0xa3,
++	0x1c, 0x41, 0x86, 0x5f, 0xc7, 0x1d, 0xe1, 0x2b,
++	0x19, 0x61, 0x21, 0x27, 0xce, 0x49, 0x99, 0x3b,
++	0xb0
++};
++static const u8 enc_assoc042[] __initconst = { };
++static const u8 enc_nonce042[] __initconst = {
++	0x17, 0xc8, 0x6a, 0x8a, 0xbb, 0xb7, 0xe0, 0x03,
++	0xac, 0xde, 0x27, 0x99
++};
++static const u8 enc_key042[] __initconst = {
++	0xfe, 0x6e, 0x55, 0xbd, 0xae, 0xd1, 0xf7, 0x28,
++	0x4c, 0xa5, 0xfc, 0x0f, 0x8c, 0x5f, 0x2b, 0x8d,
++	0xf5, 0x6d, 0xc0, 0xf4, 0x9e, 0x8c, 0xa6, 0x6a,
++	0x41, 0x99, 0x5e, 0x78, 0x33, 0x51, 0xf9, 0x01
++};
++
++/* wycheproof - misc */
++static const u8 enc_input043[] __initconst = {
++	0xce, 0xb5, 0x34, 0xce, 0x50, 0xdc, 0x23, 0xff,
++	0x63, 0x8a, 0xce, 0x3e, 0xf6, 0x3a, 0xb2, 0xcc,
++	0x29, 0x73, 0xee, 0xad, 0xa8, 0x07, 0x85, 0xfc,
++	0x16, 0x5d, 0x06, 0xc2, 0xf5, 0x10, 0x0f, 0xf5,
++	0xe8, 0xab, 0x28, 0x82, 0xc4, 0x75, 0xaf, 0xcd,
++	0x05, 0xcc, 0xd4, 0x9f, 0x2e, 0x7d, 0x8f, 0x55,
++	0xef, 0x3a, 0x72, 0xe3, 0xdc, 0x51, 0xd6, 0x85,
++	0x2b, 0x8e, 0x6b, 0x9e, 0x7a, 0xec, 0xe5, 0x7b,
++	0xe6, 0x55, 0x6b, 0x0b, 0x6d, 0x94, 0x13, 0xe3,
++	0x3f, 0xc5, 0xfc, 0x24, 0xa9, 0xa2, 0x05, 0xad,
++	0x59, 0x57, 0x4b, 0xb3, 0x9d, 0x94, 0x4a, 0x92,
++	0xdc, 0x47, 0x97, 0x0d, 0x84, 0xa6, 0xad, 0x31,
++	0x76
++};
++static const u8 enc_output043[] __initconst = {
++	0x75, 0x45, 0x39, 0x1b, 0x51, 0xde, 0x01, 0xd5,
++	0xc5, 0x3d, 0xfa, 0xca, 0x77, 0x79, 0x09, 0x06,
++	0x3e, 0x58, 0xed, 0xee, 0x4b, 0xb1, 0x22, 0x7e,
++	0x71, 0x10, 0xac, 0x4d, 0x26, 0x20, 0xc2, 0xae,
++	0xc2, 0xf8, 0x48, 0xf5, 0x6d, 0xee, 0xb0, 0x37,
++	0xa8, 0xdc, 0xed, 0x75, 0xaf, 0xa8, 0xa6, 0xc8,
++	0x90, 0xe2, 0xde, 0xe4, 0x2f, 0x95, 0x0b, 0xb3,
++	0x3d, 0x9e, 0x24, 0x24, 0xd0, 0x8a, 0x50, 0x5d,
++	0x89, 0x95, 0x63, 0x97, 0x3e, 0xd3, 0x88, 0x70,
++	0xf3, 0xde, 0x6e, 0xe2, 0xad, 0xc7, 0xfe, 0x07,
++	0x2c, 0x36, 0x6c, 0x14, 0xe2, 0xcf, 0x7c, 0xa6,
++	0x2f, 0xb3, 0xd3, 0x6b, 0xee, 0x11, 0x68, 0x54,
++	0x61, 0xb7, 0x0d, 0x44, 0xef, 0x8c, 0x66, 0xc5,
++	0xc7, 0xbb, 0xf1, 0x0d, 0xca, 0xdd, 0x7f, 0xac,
++	0xf6
++};
++static const u8 enc_assoc043[] __initconst = {
++	0xa1, 0x1c, 0x40, 0xb6, 0x03, 0x76, 0x73, 0x30
++};
++static const u8 enc_nonce043[] __initconst = {
++	0x46, 0x36, 0x2f, 0x45, 0xd6, 0x37, 0x9e, 0x63,
++	0xe5, 0x22, 0x94, 0x60
++};
++static const u8 enc_key043[] __initconst = {
++	0xaa, 0xbc, 0x06, 0x34, 0x74, 0xe6, 0x5c, 0x4c,
++	0x3e, 0x9b, 0xdc, 0x48, 0x0d, 0xea, 0x97, 0xb4,
++	0x51, 0x10, 0xc8, 0x61, 0x88, 0x46, 0xff, 0x6b,
++	0x15, 0xbd, 0xd2, 0xa4, 0xa5, 0x68, 0x2c, 0x4e
++};
++
++/* wycheproof - misc */
++static const u8 enc_input044[] __initconst = {
++	0xe5, 0xcc, 0xaa, 0x44, 0x1b, 0xc8, 0x14, 0x68,
++	0x8f, 0x8f, 0x6e, 0x8f, 0x28, 0xb5, 0x00, 0xb2
++};
++static const u8 enc_output044[] __initconst = {
++	0x7e, 0x72, 0xf5, 0xa1, 0x85, 0xaf, 0x16, 0xa6,
++	0x11, 0x92, 0x1b, 0x43, 0x8f, 0x74, 0x9f, 0x0b,
++	0x12, 0x42, 0xc6, 0x70, 0x73, 0x23, 0x34, 0x02,
++	0x9a, 0xdf, 0xe1, 0xc5, 0x00, 0x16, 0x51, 0xe4
++};
++static const u8 enc_assoc044[] __initconst = {
++	0x02
++};
++static const u8 enc_nonce044[] __initconst = {
++	0x87, 0x34, 0x5f, 0x10, 0x55, 0xfd, 0x9e, 0x21,
++	0x02, 0xd5, 0x06, 0x56
++};
++static const u8 enc_key044[] __initconst = {
++	0x7d, 0x00, 0xb4, 0x80, 0x95, 0xad, 0xfa, 0x32,
++	0x72, 0x05, 0x06, 0x07, 0xb2, 0x64, 0x18, 0x50,
++	0x02, 0xba, 0x99, 0x95, 0x7c, 0x49, 0x8b, 0xe0,
++	0x22, 0x77, 0x0f, 0x2c, 0xe2, 0xf3, 0x14, 0x3c
++};
++
++/* wycheproof - misc */
++static const u8 enc_input045[] __initconst = {
++	0x02, 0xcd, 0xe1, 0x68, 0xfb, 0xa3, 0xf5, 0x44,
++	0xbb, 0xd0, 0x33, 0x2f, 0x7a, 0xde, 0xad, 0xa8
++};
++static const u8 enc_output045[] __initconst = {
++	0x85, 0xf2, 0x9a, 0x71, 0x95, 0x57, 0xcd, 0xd1,
++	0x4d, 0x1f, 0x8f, 0xff, 0xab, 0x6d, 0x9e, 0x60,
++	0x73, 0x2c, 0xa3, 0x2b, 0xec, 0xd5, 0x15, 0xa1,
++	0xed, 0x35, 0x3f, 0x54, 0x2e, 0x99, 0x98, 0x58
++};
++static const u8 enc_assoc045[] __initconst = {
++	0xb6, 0x48
++};
++static const u8 enc_nonce045[] __initconst = {
++	0x87, 0xa3, 0x16, 0x3e, 0xc0, 0x59, 0x8a, 0xd9,
++	0x5b, 0x3a, 0xa7, 0x13
++};
++static const u8 enc_key045[] __initconst = {
++	0x64, 0x32, 0x71, 0x7f, 0x1d, 0xb8, 0x5e, 0x41,
++	0xac, 0x78, 0x36, 0xbc, 0xe2, 0x51, 0x85, 0xa0,
++	0x80, 0xd5, 0x76, 0x2b, 0x9e, 0x2b, 0x18, 0x44,
++	0x4b, 0x6e, 0xc7, 0x2c, 0x3b, 0xd8, 0xe4, 0xdc
++};
++
++/* wycheproof - misc */
++static const u8 enc_input046[] __initconst = {
++	0x16, 0xdd, 0xd2, 0x3f, 0xf5, 0x3f, 0x3d, 0x23,
++	0xc0, 0x63, 0x34, 0x48, 0x70, 0x40, 0xeb, 0x47
++};
++static const u8 enc_output046[] __initconst = {
++	0xc1, 0xb2, 0x95, 0x93, 0x6d, 0x56, 0xfa, 0xda,
++	0xc0, 0x3e, 0x5f, 0x74, 0x2b, 0xff, 0x73, 0xa1,
++	0x39, 0xc4, 0x57, 0xdb, 0xab, 0x66, 0x38, 0x2b,
++	0xab, 0xb3, 0xb5, 0x58, 0x00, 0xcd, 0xa5, 0xb8
++};
++static const u8 enc_assoc046[] __initconst = {
++	0xbd, 0x4c, 0xd0, 0x2f, 0xc7, 0x50, 0x2b, 0xbd,
++	0xbd, 0xf6, 0xc9, 0xa3, 0xcb, 0xe8, 0xf0
++};
++static const u8 enc_nonce046[] __initconst = {
++	0x6f, 0x57, 0x3a, 0xa8, 0x6b, 0xaa, 0x49, 0x2b,
++	0xa4, 0x65, 0x96, 0xdf
++};
++static const u8 enc_key046[] __initconst = {
++	0x8e, 0x34, 0xcf, 0x73, 0xd2, 0x45, 0xa1, 0x08,
++	0x2a, 0x92, 0x0b, 0x86, 0x36, 0x4e, 0xb8, 0x96,
++	0xc4, 0x94, 0x64, 0x67, 0xbc, 0xb3, 0xd5, 0x89,
++	0x29, 0xfc, 0xb3, 0x66, 0x90, 0xe6, 0x39, 0x4f
++};
++
++/* wycheproof - misc */
++static const u8 enc_input047[] __initconst = {
++	0x62, 0x3b, 0x78, 0x50, 0xc3, 0x21, 0xe2, 0xcf,
++	0x0c, 0x6f, 0xbc, 0xc8, 0xdf, 0xd1, 0xaf, 0xf2
++};
++static const u8 enc_output047[] __initconst = {
++	0xc8, 0x4c, 0x9b, 0xb7, 0xc6, 0x1c, 0x1b, 0xcb,
++	0x17, 0x77, 0x2a, 0x1c, 0x50, 0x0c, 0x50, 0x95,
++	0xdb, 0xad, 0xf7, 0xa5, 0x13, 0x8c, 0xa0, 0x34,
++	0x59, 0xa2, 0xcd, 0x65, 0x83, 0x1e, 0x09, 0x2f
++};
++static const u8 enc_assoc047[] __initconst = {
++	0x89, 0xcc, 0xe9, 0xfb, 0x47, 0x44, 0x1d, 0x07,
++	0xe0, 0x24, 0x5a, 0x66, 0xfe, 0x8b, 0x77, 0x8b
++};
++static const u8 enc_nonce047[] __initconst = {
++	0x1a, 0x65, 0x18, 0xf0, 0x2e, 0xde, 0x1d, 0xa6,
++	0x80, 0x92, 0x66, 0xd9
++};
++static const u8 enc_key047[] __initconst = {
++	0xcb, 0x55, 0x75, 0xf5, 0xc7, 0xc4, 0x5c, 0x91,
++	0xcf, 0x32, 0x0b, 0x13, 0x9f, 0xb5, 0x94, 0x23,
++	0x75, 0x60, 0xd0, 0xa3, 0xe6, 0xf8, 0x65, 0xa6,
++	0x7d, 0x4f, 0x63, 0x3f, 0x2c, 0x08, 0xf0, 0x16
++};
++
++/* wycheproof - misc */
++static const u8 enc_input048[] __initconst = {
++	0x87, 0xb3, 0xa4, 0xd7, 0xb2, 0x6d, 0x8d, 0x32,
++	0x03, 0xa0, 0xde, 0x1d, 0x64, 0xef, 0x82, 0xe3
++};
++static const u8 enc_output048[] __initconst = {
++	0x94, 0xbc, 0x80, 0x62, 0x1e, 0xd1, 0xe7, 0x1b,
++	0x1f, 0xd2, 0xb5, 0xc3, 0xa1, 0x5e, 0x35, 0x68,
++	0x33, 0x35, 0x11, 0x86, 0x17, 0x96, 0x97, 0x84,
++	0x01, 0x59, 0x8b, 0x96, 0x37, 0x22, 0xf5, 0xb3
++};
++static const u8 enc_assoc048[] __initconst = {
++	0xd1, 0x9f, 0x2d, 0x98, 0x90, 0x95, 0xf7, 0xab,
++	0x03, 0xa5, 0xfd, 0xe8, 0x44, 0x16, 0xe0, 0x0c,
++	0x0e
++};
++static const u8 enc_nonce048[] __initconst = {
++	0x56, 0x4d, 0xee, 0x49, 0xab, 0x00, 0xd2, 0x40,
++	0xfc, 0x10, 0x68, 0xc3
++};
++static const u8 enc_key048[] __initconst = {
++	0xa5, 0x56, 0x9e, 0x72, 0x9a, 0x69, 0xb2, 0x4b,
++	0xa6, 0xe0, 0xff, 0x15, 0xc4, 0x62, 0x78, 0x97,
++	0x43, 0x68, 0x24, 0xc9, 0x41, 0xe9, 0xd0, 0x0b,
++	0x2e, 0x93, 0xfd, 0xdc, 0x4b, 0xa7, 0x76, 0x57
++};
++
++/* wycheproof - misc */
++static const u8 enc_input049[] __initconst = {
++	0xe6, 0x01, 0xb3, 0x85, 0x57, 0x79, 0x7d, 0xa2,
++	0xf8, 0xa4, 0x10, 0x6a, 0x08, 0x9d, 0x1d, 0xa6
++};
++static const u8 enc_output049[] __initconst = {
++	0x29, 0x9b, 0x5d, 0x3f, 0x3d, 0x03, 0xc0, 0x87,
++	0x20, 0x9a, 0x16, 0xe2, 0x85, 0x14, 0x31, 0x11,
++	0x4b, 0x45, 0x4e, 0xd1, 0x98, 0xde, 0x11, 0x7e,
++	0x83, 0xec, 0x49, 0xfa, 0x8d, 0x85, 0x08, 0xd6
++};
++static const u8 enc_assoc049[] __initconst = {
++	0x5e, 0x64, 0x70, 0xfa, 0xcd, 0x99, 0xc1, 0xd8,
++	0x1e, 0x37, 0xcd, 0x44, 0x01, 0x5f, 0xe1, 0x94,
++	0x80, 0xa2, 0xa4, 0xd3, 0x35, 0x2a, 0x4f, 0xf5,
++	0x60, 0xc0, 0x64, 0x0f, 0xdb, 0xda
++};
++static const u8 enc_nonce049[] __initconst = {
++	0xdf, 0x87, 0x13, 0xe8, 0x7e, 0xc3, 0xdb, 0xcf,
++	0xad, 0x14, 0xd5, 0x3e
++};
++static const u8 enc_key049[] __initconst = {
++	0x56, 0x20, 0x74, 0x65, 0xb4, 0xe4, 0x8e, 0x6d,
++	0x04, 0x63, 0x0f, 0x4a, 0x42, 0xf3, 0x5c, 0xfc,
++	0x16, 0x3a, 0xb2, 0x89, 0xc2, 0x2a, 0x2b, 0x47,
++	0x84, 0xf6, 0xf9, 0x29, 0x03, 0x30, 0xbe, 0xe0
++};
++
++/* wycheproof - misc */
++static const u8 enc_input050[] __initconst = {
++	0xdc, 0x9e, 0x9e, 0xaf, 0x11, 0xe3, 0x14, 0x18,
++	0x2d, 0xf6, 0xa4, 0xeb, 0xa1, 0x7a, 0xec, 0x9c
++};
++static const u8 enc_output050[] __initconst = {
++	0x60, 0x5b, 0xbf, 0x90, 0xae, 0xb9, 0x74, 0xf6,
++	0x60, 0x2b, 0xc7, 0x78, 0x05, 0x6f, 0x0d, 0xca,
++	0x38, 0xea, 0x23, 0xd9, 0x90, 0x54, 0xb4, 0x6b,
++	0x42, 0xff, 0xe0, 0x04, 0x12, 0x9d, 0x22, 0x04
++};
++static const u8 enc_assoc050[] __initconst = {
++	0xba, 0x44, 0x6f, 0x6f, 0x9a, 0x0c, 0xed, 0x22,
++	0x45, 0x0f, 0xeb, 0x10, 0x73, 0x7d, 0x90, 0x07,
++	0xfd, 0x69, 0xab, 0xc1, 0x9b, 0x1d, 0x4d, 0x90,
++	0x49, 0xa5, 0x55, 0x1e, 0x86, 0xec, 0x2b, 0x37
++};
++static const u8 enc_nonce050[] __initconst = {
++	0x8d, 0xf4, 0xb1, 0x5a, 0x88, 0x8c, 0x33, 0x28,
++	0x6a, 0x7b, 0x76, 0x51
++};
++static const u8 enc_key050[] __initconst = {
++	0x39, 0x37, 0x98, 0x6a, 0xf8, 0x6d, 0xaf, 0xc1,
++	0xba, 0x0c, 0x46, 0x72, 0xd8, 0xab, 0xc4, 0x6c,
++	0x20, 0x70, 0x62, 0x68, 0x2d, 0x9c, 0x26, 0x4a,
++	0xb0, 0x6d, 0x6c, 0x58, 0x07, 0x20, 0x51, 0x30
++};
++
++/* wycheproof - misc */
++static const u8 enc_input051[] __initconst = {
++	0x81, 0xce, 0x84, 0xed, 0xe9, 0xb3, 0x58, 0x59,
++	0xcc, 0x8c, 0x49, 0xa8, 0xf6, 0xbe, 0x7d, 0xc6
++};
++static const u8 enc_output051[] __initconst = {
++	0x7b, 0x7c, 0xe0, 0xd8, 0x24, 0x80, 0x9a, 0x70,
++	0xde, 0x32, 0x56, 0x2c, 0xcf, 0x2c, 0x2b, 0xbd,
++	0x15, 0xd4, 0x4a, 0x00, 0xce, 0x0d, 0x19, 0xb4,
++	0x23, 0x1f, 0x92, 0x1e, 0x22, 0xbc, 0x0a, 0x43
++};
++static const u8 enc_assoc051[] __initconst = {
++	0xd4, 0x1a, 0x82, 0x8d, 0x5e, 0x71, 0x82, 0x92,
++	0x47, 0x02, 0x19, 0x05, 0x40, 0x2e, 0xa2, 0x57,
++	0xdc, 0xcb, 0xc3, 0xb8, 0x0f, 0xcd, 0x56, 0x75,
++	0x05, 0x6b, 0x68, 0xbb, 0x59, 0xe6, 0x2e, 0x88,
++	0x73
++};
++static const u8 enc_nonce051[] __initconst = {
++	0xbe, 0x40, 0xe5, 0xf1, 0xa1, 0x18, 0x17, 0xa0,
++	0xa8, 0xfa, 0x89, 0x49
++};
++static const u8 enc_key051[] __initconst = {
++	0x36, 0x37, 0x2a, 0xbc, 0xdb, 0x78, 0xe0, 0x27,
++	0x96, 0x46, 0xac, 0x3d, 0x17, 0x6b, 0x96, 0x74,
++	0xe9, 0x15, 0x4e, 0xec, 0xf0, 0xd5, 0x46, 0x9c,
++	0x65, 0x1e, 0xc7, 0xe1, 0x6b, 0x4c, 0x11, 0x99
++};
++
++/* wycheproof - misc */
++static const u8 enc_input052[] __initconst = {
++	0xa6, 0x67, 0x47, 0xc8, 0x9e, 0x85, 0x7a, 0xf3,
++	0xa1, 0x8e, 0x2c, 0x79, 0x50, 0x00, 0x87, 0xed
++};
++static const u8 enc_output052[] __initconst = {
++	0xca, 0x82, 0xbf, 0xf3, 0xe2, 0xf3, 0x10, 0xcc,
++	0xc9, 0x76, 0x67, 0x2c, 0x44, 0x15, 0xe6, 0x9b,
++	0x57, 0x63, 0x8c, 0x62, 0xa5, 0xd8, 0x5d, 0xed,
++	0x77, 0x4f, 0x91, 0x3c, 0x81, 0x3e, 0xa0, 0x32
++};
++static const u8 enc_assoc052[] __initconst = {
++	0x3f, 0x2d, 0xd4, 0x9b, 0xbf, 0x09, 0xd6, 0x9a,
++	0x78, 0xa3, 0xd8, 0x0e, 0xa2, 0x56, 0x66, 0x14,
++	0xfc, 0x37, 0x94, 0x74, 0x19, 0x6c, 0x1a, 0xae,
++	0x84, 0x58, 0x3d, 0xa7, 0x3d, 0x7f, 0xf8, 0x5c,
++	0x6f, 0x42, 0xca, 0x42, 0x05, 0x6a, 0x97, 0x92,
++	0xcc, 0x1b, 0x9f, 0xb3, 0xc7, 0xd2, 0x61
++};
++static const u8 enc_nonce052[] __initconst = {
++	0x84, 0xc8, 0x7d, 0xae, 0x4e, 0xee, 0x27, 0x73,
++	0x0e, 0xc3, 0x5d, 0x12
++};
++static const u8 enc_key052[] __initconst = {
++	0x9f, 0x14, 0x79, 0xed, 0x09, 0x7d, 0x7f, 0xe5,
++	0x29, 0xc1, 0x1f, 0x2f, 0x5a, 0xdd, 0x9a, 0xaf,
++	0xf4, 0xa1, 0xca, 0x0b, 0x68, 0x99, 0x7a, 0x2c,
++	0xb7, 0xf7, 0x97, 0x49, 0xbd, 0x90, 0xaa, 0xf4
++};
++
+ /* wycheproof - misc */
+ static const u8 enc_input053[] __initconst = {
+ 	0x25, 0x6d, 0x40, 0x88, 0x80, 0x94, 0x17, 0x83,
+@@ -2760,6 +3859,126 @@ static const u8 enc_key073[] __initconst
+ };
+ 
+ /* wycheproof - checking for int overflows */
++static const u8 enc_input074[] __initconst = {
++	0xd4, 0x50, 0x0b, 0xf0, 0x09, 0x49, 0x35, 0x51,
++	0xc3, 0x80, 0xad, 0xf5, 0x2c, 0x57, 0x3a, 0x69,
++	0xdf, 0x7e, 0x8b, 0x76, 0x24, 0x63, 0x33, 0x0f,
++	0xac, 0xc1, 0x6a, 0x57, 0x26, 0xbe, 0x71, 0x90,
++	0xc6, 0x3c, 0x5a, 0x1c, 0x92, 0x65, 0x84, 0xa0,
++	0x96, 0x75, 0x68, 0x28, 0xdc, 0xdc, 0x64, 0xac,
++	0xdf, 0x96, 0x3d, 0x93, 0x1b, 0xf1, 0xda, 0xe2,
++	0x38, 0xf3, 0xf1, 0x57, 0x22, 0x4a, 0xc4, 0xb5,
++	0x42, 0xd7, 0x85, 0xb0, 0xdd, 0x84, 0xdb, 0x6b,
++	0xe3, 0xbc, 0x5a, 0x36, 0x63, 0xe8, 0x41, 0x49,
++	0xff, 0xbe, 0xd0, 0x9e, 0x54, 0xf7, 0x8f, 0x16,
++	0xa8, 0x22, 0x3b, 0x24, 0xcb, 0x01, 0x9f, 0x58,
++	0xb2, 0x1b, 0x0e, 0x55, 0x1e, 0x7a, 0xa0, 0x73,
++	0x27, 0x62, 0x95, 0x51, 0x37, 0x6c, 0xcb, 0xc3,
++	0x93, 0x76, 0x71, 0xa0, 0x62, 0x9b, 0xd9, 0x5c,
++	0x99, 0x15, 0xc7, 0x85, 0x55, 0x77, 0x1e, 0x7a
++};
++static const u8 enc_output074[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x0b, 0x30, 0x0d, 0x8d, 0xa5, 0x6c, 0x21, 0x85,
++	0x75, 0x52, 0x79, 0x55, 0x3c, 0x4c, 0x82, 0xca
++};
++static const u8 enc_assoc074[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce074[] __initconst = {
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x00, 0x02, 0x50, 0x6e
++};
++static const u8 enc_key074[] __initconst = {
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30
++};
++
++/* wycheproof - checking for int overflows */
++static const u8 enc_input075[] __initconst = {
++	0x7d, 0xe8, 0x7f, 0x67, 0x29, 0x94, 0x52, 0x75,
++	0xd0, 0x65, 0x5d, 0xa4, 0xc7, 0xfd, 0xe4, 0x56,
++	0x9e, 0x16, 0xf1, 0x11, 0xb5, 0xeb, 0x26, 0xc2,
++	0x2d, 0x85, 0x9e, 0x3f, 0xf8, 0x22, 0xec, 0xed,
++	0x3a, 0x6d, 0xd9, 0xa6, 0x0f, 0x22, 0x95, 0x7f,
++	0x7b, 0x7c, 0x85, 0x7e, 0x88, 0x22, 0xeb, 0x9f,
++	0xe0, 0xb8, 0xd7, 0x02, 0x21, 0x41, 0xf2, 0xd0,
++	0xb4, 0x8f, 0x4b, 0x56, 0x12, 0xd3, 0x22, 0xa8,
++	0x8d, 0xd0, 0xfe, 0x0b, 0x4d, 0x91, 0x79, 0x32,
++	0x4f, 0x7c, 0x6c, 0x9e, 0x99, 0x0e, 0xfb, 0xd8,
++	0x0e, 0x5e, 0xd6, 0x77, 0x58, 0x26, 0x49, 0x8b,
++	0x1e, 0xfe, 0x0f, 0x71, 0xa0, 0xf3, 0xec, 0x5b,
++	0x29, 0xcb, 0x28, 0xc2, 0x54, 0x0a, 0x7d, 0xcd,
++	0x51, 0xb7, 0xda, 0xae, 0xe0, 0xff, 0x4a, 0x7f,
++	0x3a, 0xc1, 0xee, 0x54, 0xc2, 0x9e, 0xe4, 0xc1,
++	0x70, 0xde, 0x40, 0x8f, 0x66, 0x69, 0x21, 0x94
++};
++static const u8 enc_output075[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xc5, 0x78, 0xe2, 0xaa, 0x44, 0xd3, 0x09, 0xb7,
++	0xb6, 0xa5, 0x19, 0x3b, 0xdc, 0x61, 0x18, 0xf5
++};
++static const u8 enc_assoc075[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_nonce075[] __initconst = {
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x00, 0x03, 0x18, 0xa5
++};
++static const u8 enc_key075[] __initconst = {
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
++	0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30
++};
++
++/* wycheproof - checking for int overflows */
+ static const u8 enc_input076[] __initconst = {
+ 	0x1b, 0x99, 0x6f, 0x9a, 0x3c, 0xcc, 0x67, 0x85,
+ 	0xde, 0x22, 0xff, 0x5b, 0x8a, 0xdd, 0x95, 0x02,
+@@ -3349,6 +4568,286 @@ static const u8 enc_key085[] __initconst
+ 	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
+ };
+ 
++/* wycheproof - special case tag */
++static const u8 enc_input086[] __initconst = {
++	0x9a, 0x49, 0xc4, 0x0f, 0x8b, 0x48, 0xd7, 0xc6,
++	0x6d, 0x1d, 0xb4, 0xe5, 0x3f, 0x20, 0xf2, 0xdd,
++	0x4a, 0xaa, 0x24, 0x1d, 0xda, 0xb2, 0x6b, 0x5b,
++	0xc0, 0xe2, 0x18, 0xb7, 0x2c, 0x33, 0x90, 0xf2,
++	0xdf, 0x3e, 0xbd, 0x01, 0x76, 0x70, 0x44, 0x19,
++	0x97, 0x2b, 0xcd, 0xbc, 0x6b, 0xbc, 0xb3, 0xe4,
++	0xe7, 0x4a, 0x71, 0x52, 0x8e, 0xf5, 0x12, 0x63,
++	0xce, 0x24, 0xe0, 0xd5, 0x75, 0xe0, 0xe4, 0x4d
++};
++static const u8 enc_output086[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
++};
++static const u8 enc_assoc086[] __initconst = {
++	0x85, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xa6, 0x90, 0x2f, 0xcb, 0xc8, 0x83, 0xbb, 0xc1,
++	0x80, 0xb2, 0x56, 0xae, 0x34, 0xad, 0x7f, 0x00
++};
++static const u8 enc_nonce086[] __initconst = {
++	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++	0x08, 0x09, 0x0a, 0x0b
++};
++static const u8 enc_key086[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - special case tag */
++static const u8 enc_input087[] __initconst = {
++	0x9a, 0x49, 0xc4, 0x0f, 0x8b, 0x48, 0xd7, 0xc6,
++	0x6d, 0x1d, 0xb4, 0xe5, 0x3f, 0x20, 0xf2, 0xdd,
++	0x4a, 0xaa, 0x24, 0x1d, 0xda, 0xb2, 0x6b, 0x5b,
++	0xc0, 0xe2, 0x18, 0xb7, 0x2c, 0x33, 0x90, 0xf2,
++	0xdf, 0x3e, 0xbd, 0x01, 0x76, 0x70, 0x44, 0x19,
++	0x97, 0x2b, 0xcd, 0xbc, 0x6b, 0xbc, 0xb3, 0xe4,
++	0xe7, 0x4a, 0x71, 0x52, 0x8e, 0xf5, 0x12, 0x63,
++	0xce, 0x24, 0xe0, 0xd5, 0x75, 0xe0, 0xe4, 0x4d
++};
++static const u8 enc_output087[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++};
++static const u8 enc_assoc087[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x24, 0x7e, 0x50, 0x64, 0x2a, 0x1c, 0x0a, 0x2f,
++	0x8f, 0x77, 0x21, 0x96, 0x09, 0xdb, 0xa9, 0x58
++};
++static const u8 enc_nonce087[] __initconst = {
++	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++	0x08, 0x09, 0x0a, 0x0b
++};
++static const u8 enc_key087[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - special case tag */
++static const u8 enc_input088[] __initconst = {
++	0x9a, 0x49, 0xc4, 0x0f, 0x8b, 0x48, 0xd7, 0xc6,
++	0x6d, 0x1d, 0xb4, 0xe5, 0x3f, 0x20, 0xf2, 0xdd,
++	0x4a, 0xaa, 0x24, 0x1d, 0xda, 0xb2, 0x6b, 0x5b,
++	0xc0, 0xe2, 0x18, 0xb7, 0x2c, 0x33, 0x90, 0xf2,
++	0xdf, 0x3e, 0xbd, 0x01, 0x76, 0x70, 0x44, 0x19,
++	0x97, 0x2b, 0xcd, 0xbc, 0x6b, 0xbc, 0xb3, 0xe4,
++	0xe7, 0x4a, 0x71, 0x52, 0x8e, 0xf5, 0x12, 0x63,
++	0xce, 0x24, 0xe0, 0xd5, 0x75, 0xe0, 0xe4, 0x4d
++};
++static const u8 enc_output088[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++};
++static const u8 enc_assoc088[] __initconst = {
++	0x7c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xd9, 0xe7, 0x2c, 0x06, 0x4a, 0xc8, 0x96, 0x1f,
++	0x3f, 0xa5, 0x85, 0xe0, 0xe2, 0xab, 0xd6, 0x00
++};
++static const u8 enc_nonce088[] __initconst = {
++	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++	0x08, 0x09, 0x0a, 0x0b
++};
++static const u8 enc_key088[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - special case tag */
++static const u8 enc_input089[] __initconst = {
++	0x9a, 0x49, 0xc4, 0x0f, 0x8b, 0x48, 0xd7, 0xc6,
++	0x6d, 0x1d, 0xb4, 0xe5, 0x3f, 0x20, 0xf2, 0xdd,
++	0x4a, 0xaa, 0x24, 0x1d, 0xda, 0xb2, 0x6b, 0x5b,
++	0xc0, 0xe2, 0x18, 0xb7, 0x2c, 0x33, 0x90, 0xf2,
++	0xdf, 0x3e, 0xbd, 0x01, 0x76, 0x70, 0x44, 0x19,
++	0x97, 0x2b, 0xcd, 0xbc, 0x6b, 0xbc, 0xb3, 0xe4,
++	0xe7, 0x4a, 0x71, 0x52, 0x8e, 0xf5, 0x12, 0x63,
++	0xce, 0x24, 0xe0, 0xd5, 0x75, 0xe0, 0xe4, 0x4d
++};
++static const u8 enc_output089[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
++	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80
++};
++static const u8 enc_assoc089[] __initconst = {
++	0x65, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x95, 0xaf, 0x0f, 0x4d, 0x0b, 0x68, 0x6e, 0xae,
++	0xcc, 0xca, 0x43, 0x07, 0xd5, 0x96, 0xf5, 0x02
++};
++static const u8 enc_nonce089[] __initconst = {
++	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++	0x08, 0x09, 0x0a, 0x0b
++};
++static const u8 enc_key089[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - special case tag */
++static const u8 enc_input090[] __initconst = {
++	0x9a, 0x49, 0xc4, 0x0f, 0x8b, 0x48, 0xd7, 0xc6,
++	0x6d, 0x1d, 0xb4, 0xe5, 0x3f, 0x20, 0xf2, 0xdd,
++	0x4a, 0xaa, 0x24, 0x1d, 0xda, 0xb2, 0x6b, 0x5b,
++	0xc0, 0xe2, 0x18, 0xb7, 0x2c, 0x33, 0x90, 0xf2,
++	0xdf, 0x3e, 0xbd, 0x01, 0x76, 0x70, 0x44, 0x19,
++	0x97, 0x2b, 0xcd, 0xbc, 0x6b, 0xbc, 0xb3, 0xe4,
++	0xe7, 0x4a, 0x71, 0x52, 0x8e, 0xf5, 0x12, 0x63,
++	0xce, 0x24, 0xe0, 0xd5, 0x75, 0xe0, 0xe4, 0x4d
++};
++static const u8 enc_output090[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
++	0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f
++};
++static const u8 enc_assoc090[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x85, 0x40, 0xb4, 0x64, 0x35, 0x77, 0x07, 0xbe,
++	0x3a, 0x39, 0xd5, 0x5c, 0x34, 0xf8, 0xbc, 0xb3
++};
++static const u8 enc_nonce090[] __initconst = {
++	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++	0x08, 0x09, 0x0a, 0x0b
++};
++static const u8 enc_key090[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - special case tag */
++static const u8 enc_input091[] __initconst = {
++	0x9a, 0x49, 0xc4, 0x0f, 0x8b, 0x48, 0xd7, 0xc6,
++	0x6d, 0x1d, 0xb4, 0xe5, 0x3f, 0x20, 0xf2, 0xdd,
++	0x4a, 0xaa, 0x24, 0x1d, 0xda, 0xb2, 0x6b, 0x5b,
++	0xc0, 0xe2, 0x18, 0xb7, 0x2c, 0x33, 0x90, 0xf2,
++	0xdf, 0x3e, 0xbd, 0x01, 0x76, 0x70, 0x44, 0x19,
++	0x97, 0x2b, 0xcd, 0xbc, 0x6b, 0xbc, 0xb3, 0xe4,
++	0xe7, 0x4a, 0x71, 0x52, 0x8e, 0xf5, 0x12, 0x63,
++	0xce, 0x24, 0xe0, 0xd5, 0x75, 0xe0, 0xe4, 0x4d
++};
++static const u8 enc_output091[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
++	0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
++};
++static const u8 enc_assoc091[] __initconst = {
++	0x4f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x66, 0x23, 0xd9, 0x90, 0xb8, 0x98, 0xd8, 0x30,
++	0xd2, 0x12, 0xaf, 0x23, 0x83, 0x33, 0x07, 0x01
++};
++static const u8 enc_nonce091[] __initconst = {
++	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++	0x08, 0x09, 0x0a, 0x0b
++};
++static const u8 enc_key091[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
++/* wycheproof - special case tag */
++static const u8 enc_input092[] __initconst = {
++	0x9a, 0x49, 0xc4, 0x0f, 0x8b, 0x48, 0xd7, 0xc6,
++	0x6d, 0x1d, 0xb4, 0xe5, 0x3f, 0x20, 0xf2, 0xdd,
++	0x4a, 0xaa, 0x24, 0x1d, 0xda, 0xb2, 0x6b, 0x5b,
++	0xc0, 0xe2, 0x18, 0xb7, 0x2c, 0x33, 0x90, 0xf2,
++	0xdf, 0x3e, 0xbd, 0x01, 0x76, 0x70, 0x44, 0x19,
++	0x97, 0x2b, 0xcd, 0xbc, 0x6b, 0xbc, 0xb3, 0xe4,
++	0xe7, 0x4a, 0x71, 0x52, 0x8e, 0xf5, 0x12, 0x63,
++	0xce, 0x24, 0xe0, 0xd5, 0x75, 0xe0, 0xe4, 0x4d
++};
++static const u8 enc_output092[] __initconst = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++};
++static const u8 enc_assoc092[] __initconst = {
++	0x83, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0x5f, 0x16, 0xd0, 0x9f, 0x17, 0x78, 0x72, 0x11,
++	0xb7, 0xd4, 0x84, 0xe0, 0x24, 0xf8, 0x97, 0x01
++};
++static const u8 enc_nonce092[] __initconst = {
++	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
++	0x08, 0x09, 0x0a, 0x0b
++};
++static const u8 enc_key092[] __initconst = {
++	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
++	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
++	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
++	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
++};
++
+ /* wycheproof - edge case intermediate sums in poly1305 */
+ static const u8 enc_input093[] __initconst = {
+ 	0x00, 0x52, 0x35, 0xd2, 0xa9, 0x19, 0xf2, 0x8d,
+@@ -4455,6 +5954,86 @@ chacha20poly1305_enc_vectors[] __initcon
+ 	  sizeof(enc_input011), sizeof(enc_assoc011), sizeof(enc_nonce011) },
+ 	{ enc_input012, enc_output012, enc_assoc012, enc_nonce012, enc_key012,
+ 	  sizeof(enc_input012), sizeof(enc_assoc012), sizeof(enc_nonce012) },
++	{ enc_input013, enc_output013, enc_assoc013, enc_nonce013, enc_key013,
++	  sizeof(enc_input013), sizeof(enc_assoc013), sizeof(enc_nonce013) },
++	{ enc_input014, enc_output014, enc_assoc014, enc_nonce014, enc_key014,
++	  sizeof(enc_input014), sizeof(enc_assoc014), sizeof(enc_nonce014) },
++	{ enc_input015, enc_output015, enc_assoc015, enc_nonce015, enc_key015,
++	  sizeof(enc_input015), sizeof(enc_assoc015), sizeof(enc_nonce015) },
++	{ enc_input016, enc_output016, enc_assoc016, enc_nonce016, enc_key016,
++	  sizeof(enc_input016), sizeof(enc_assoc016), sizeof(enc_nonce016) },
++	{ enc_input017, enc_output017, enc_assoc017, enc_nonce017, enc_key017,
++	  sizeof(enc_input017), sizeof(enc_assoc017), sizeof(enc_nonce017) },
++	{ enc_input018, enc_output018, enc_assoc018, enc_nonce018, enc_key018,
++	  sizeof(enc_input018), sizeof(enc_assoc018), sizeof(enc_nonce018) },
++	{ enc_input019, enc_output019, enc_assoc019, enc_nonce019, enc_key019,
++	  sizeof(enc_input019), sizeof(enc_assoc019), sizeof(enc_nonce019) },
++	{ enc_input020, enc_output020, enc_assoc020, enc_nonce020, enc_key020,
++	  sizeof(enc_input020), sizeof(enc_assoc020), sizeof(enc_nonce020) },
++	{ enc_input021, enc_output021, enc_assoc021, enc_nonce021, enc_key021,
++	  sizeof(enc_input021), sizeof(enc_assoc021), sizeof(enc_nonce021) },
++	{ enc_input022, enc_output022, enc_assoc022, enc_nonce022, enc_key022,
++	  sizeof(enc_input022), sizeof(enc_assoc022), sizeof(enc_nonce022) },
++	{ enc_input023, enc_output023, enc_assoc023, enc_nonce023, enc_key023,
++	  sizeof(enc_input023), sizeof(enc_assoc023), sizeof(enc_nonce023) },
++	{ enc_input024, enc_output024, enc_assoc024, enc_nonce024, enc_key024,
++	  sizeof(enc_input024), sizeof(enc_assoc024), sizeof(enc_nonce024) },
++	{ enc_input025, enc_output025, enc_assoc025, enc_nonce025, enc_key025,
++	  sizeof(enc_input025), sizeof(enc_assoc025), sizeof(enc_nonce025) },
++	{ enc_input026, enc_output026, enc_assoc026, enc_nonce026, enc_key026,
++	  sizeof(enc_input026), sizeof(enc_assoc026), sizeof(enc_nonce026) },
++	{ enc_input027, enc_output027, enc_assoc027, enc_nonce027, enc_key027,
++	  sizeof(enc_input027), sizeof(enc_assoc027), sizeof(enc_nonce027) },
++	{ enc_input028, enc_output028, enc_assoc028, enc_nonce028, enc_key028,
++	  sizeof(enc_input028), sizeof(enc_assoc028), sizeof(enc_nonce028) },
++	{ enc_input029, enc_output029, enc_assoc029, enc_nonce029, enc_key029,
++	  sizeof(enc_input029), sizeof(enc_assoc029), sizeof(enc_nonce029) },
++	{ enc_input030, enc_output030, enc_assoc030, enc_nonce030, enc_key030,
++	  sizeof(enc_input030), sizeof(enc_assoc030), sizeof(enc_nonce030) },
++	{ enc_input031, enc_output031, enc_assoc031, enc_nonce031, enc_key031,
++	  sizeof(enc_input031), sizeof(enc_assoc031), sizeof(enc_nonce031) },
++	{ enc_input032, enc_output032, enc_assoc032, enc_nonce032, enc_key032,
++	  sizeof(enc_input032), sizeof(enc_assoc032), sizeof(enc_nonce032) },
++	{ enc_input033, enc_output033, enc_assoc033, enc_nonce033, enc_key033,
++	  sizeof(enc_input033), sizeof(enc_assoc033), sizeof(enc_nonce033) },
++	{ enc_input034, enc_output034, enc_assoc034, enc_nonce034, enc_key034,
++	  sizeof(enc_input034), sizeof(enc_assoc034), sizeof(enc_nonce034) },
++	{ enc_input035, enc_output035, enc_assoc035, enc_nonce035, enc_key035,
++	  sizeof(enc_input035), sizeof(enc_assoc035), sizeof(enc_nonce035) },
++	{ enc_input036, enc_output036, enc_assoc036, enc_nonce036, enc_key036,
++	  sizeof(enc_input036), sizeof(enc_assoc036), sizeof(enc_nonce036) },
++	{ enc_input037, enc_output037, enc_assoc037, enc_nonce037, enc_key037,
++	  sizeof(enc_input037), sizeof(enc_assoc037), sizeof(enc_nonce037) },
++	{ enc_input038, enc_output038, enc_assoc038, enc_nonce038, enc_key038,
++	  sizeof(enc_input038), sizeof(enc_assoc038), sizeof(enc_nonce038) },
++	{ enc_input039, enc_output039, enc_assoc039, enc_nonce039, enc_key039,
++	  sizeof(enc_input039), sizeof(enc_assoc039), sizeof(enc_nonce039) },
++	{ enc_input040, enc_output040, enc_assoc040, enc_nonce040, enc_key040,
++	  sizeof(enc_input040), sizeof(enc_assoc040), sizeof(enc_nonce040) },
++	{ enc_input041, enc_output041, enc_assoc041, enc_nonce041, enc_key041,
++	  sizeof(enc_input041), sizeof(enc_assoc041), sizeof(enc_nonce041) },
++	{ enc_input042, enc_output042, enc_assoc042, enc_nonce042, enc_key042,
++	  sizeof(enc_input042), sizeof(enc_assoc042), sizeof(enc_nonce042) },
++	{ enc_input043, enc_output043, enc_assoc043, enc_nonce043, enc_key043,
++	  sizeof(enc_input043), sizeof(enc_assoc043), sizeof(enc_nonce043) },
++	{ enc_input044, enc_output044, enc_assoc044, enc_nonce044, enc_key044,
++	  sizeof(enc_input044), sizeof(enc_assoc044), sizeof(enc_nonce044) },
++	{ enc_input045, enc_output045, enc_assoc045, enc_nonce045, enc_key045,
++	  sizeof(enc_input045), sizeof(enc_assoc045), sizeof(enc_nonce045) },
++	{ enc_input046, enc_output046, enc_assoc046, enc_nonce046, enc_key046,
++	  sizeof(enc_input046), sizeof(enc_assoc046), sizeof(enc_nonce046) },
++	{ enc_input047, enc_output047, enc_assoc047, enc_nonce047, enc_key047,
++	  sizeof(enc_input047), sizeof(enc_assoc047), sizeof(enc_nonce047) },
++	{ enc_input048, enc_output048, enc_assoc048, enc_nonce048, enc_key048,
++	  sizeof(enc_input048), sizeof(enc_assoc048), sizeof(enc_nonce048) },
++	{ enc_input049, enc_output049, enc_assoc049, enc_nonce049, enc_key049,
++	  sizeof(enc_input049), sizeof(enc_assoc049), sizeof(enc_nonce049) },
++	{ enc_input050, enc_output050, enc_assoc050, enc_nonce050, enc_key050,
++	  sizeof(enc_input050), sizeof(enc_assoc050), sizeof(enc_nonce050) },
++	{ enc_input051, enc_output051, enc_assoc051, enc_nonce051, enc_key051,
++	  sizeof(enc_input051), sizeof(enc_assoc051), sizeof(enc_nonce051) },
++	{ enc_input052, enc_output052, enc_assoc052, enc_nonce052, enc_key052,
++	  sizeof(enc_input052), sizeof(enc_assoc052), sizeof(enc_nonce052) },
+ 	{ enc_input053, enc_output053, enc_assoc053, enc_nonce053, enc_key053,
+ 	  sizeof(enc_input053), sizeof(enc_assoc053), sizeof(enc_nonce053) },
+ 	{ enc_input054, enc_output054, enc_assoc054, enc_nonce054, enc_key054,
+@@ -4497,6 +6076,10 @@ chacha20poly1305_enc_vectors[] __initcon
+ 	  sizeof(enc_input072), sizeof(enc_assoc072), sizeof(enc_nonce072) },
+ 	{ enc_input073, enc_output073, enc_assoc073, enc_nonce073, enc_key073,
+ 	  sizeof(enc_input073), sizeof(enc_assoc073), sizeof(enc_nonce073) },
++	{ enc_input074, enc_output074, enc_assoc074, enc_nonce074, enc_key074,
++	  sizeof(enc_input074), sizeof(enc_assoc074), sizeof(enc_nonce074) },
++	{ enc_input075, enc_output075, enc_assoc075, enc_nonce075, enc_key075,
++	  sizeof(enc_input075), sizeof(enc_assoc075), sizeof(enc_nonce075) },
+ 	{ enc_input076, enc_output076, enc_assoc076, enc_nonce076, enc_key076,
+ 	  sizeof(enc_input076), sizeof(enc_assoc076), sizeof(enc_nonce076) },
+ 	{ enc_input077, enc_output077, enc_assoc077, enc_nonce077, enc_key077,
+@@ -4517,6 +6100,20 @@ chacha20poly1305_enc_vectors[] __initcon
+ 	  sizeof(enc_input084), sizeof(enc_assoc084), sizeof(enc_nonce084) },
+ 	{ enc_input085, enc_output085, enc_assoc085, enc_nonce085, enc_key085,
+ 	  sizeof(enc_input085), sizeof(enc_assoc085), sizeof(enc_nonce085) },
++	{ enc_input086, enc_output086, enc_assoc086, enc_nonce086, enc_key086,
++	  sizeof(enc_input086), sizeof(enc_assoc086), sizeof(enc_nonce086) },
++	{ enc_input087, enc_output087, enc_assoc087, enc_nonce087, enc_key087,
++	  sizeof(enc_input087), sizeof(enc_assoc087), sizeof(enc_nonce087) },
++	{ enc_input088, enc_output088, enc_assoc088, enc_nonce088, enc_key088,
++	  sizeof(enc_input088), sizeof(enc_assoc088), sizeof(enc_nonce088) },
++	{ enc_input089, enc_output089, enc_assoc089, enc_nonce089, enc_key089,
++	  sizeof(enc_input089), sizeof(enc_assoc089), sizeof(enc_nonce089) },
++	{ enc_input090, enc_output090, enc_assoc090, enc_nonce090, enc_key090,
++	  sizeof(enc_input090), sizeof(enc_assoc090), sizeof(enc_nonce090) },
++	{ enc_input091, enc_output091, enc_assoc091, enc_nonce091, enc_key091,
++	  sizeof(enc_input091), sizeof(enc_assoc091), sizeof(enc_nonce091) },
++	{ enc_input092, enc_output092, enc_assoc092, enc_nonce092, enc_key092,
++	  sizeof(enc_input092), sizeof(enc_assoc092), sizeof(enc_nonce092) },
+ 	{ enc_input093, enc_output093, enc_assoc093, enc_nonce093, enc_key093,
+ 	  sizeof(enc_input093), sizeof(enc_assoc093), sizeof(enc_nonce093) },
+ 	{ enc_input094, enc_output094, enc_assoc094, enc_nonce094, enc_key094,
+@@ -7224,6 +8821,43 @@ xchacha20poly1305_dec_vectors[] __initco
+ 	  sizeof(xdec_input001), sizeof(xdec_assoc001), sizeof(xdec_nonce001) }
+ };
+ 
++/* This is for the selftests-only, since it is only useful for the purpose of
++ * testing the underlying primitives and interactions.
++ */
++static void __init
++chacha20poly1305_encrypt_bignonce(u8 *dst, const u8 *src, const size_t src_len,
++				  const u8 *ad, const size_t ad_len,
++				  const u8 nonce[12],
++				  const u8 key[CHACHA20POLY1305_KEY_SIZE])
++{
++	const u8 *pad0 = page_address(ZERO_PAGE(0));
++	struct poly1305_desc_ctx poly1305_state;
++	u32 chacha20_state[CHACHA_STATE_WORDS];
++	union {
++		u8 block0[POLY1305_KEY_SIZE];
++		__le64 lens[2];
++	} b = {{ 0 }};
++	u8 bottom_row[16] = { 0 };
++	u32 le_key[8];
++	int i;
++
++	memcpy(&bottom_row[4], nonce, 12);
++	for (i = 0; i < 8; ++i)
++		le_key[i] = get_unaligned_le32(key + sizeof(le_key[i]) * i);
++	chacha_init(chacha20_state, le_key, bottom_row);
++	chacha20_crypt(chacha20_state, b.block0, b.block0, sizeof(b.block0));
++	poly1305_init(&poly1305_state, b.block0);
++	poly1305_update(&poly1305_state, ad, ad_len);
++	poly1305_update(&poly1305_state, pad0, (0x10 - ad_len) & 0xf);
++	chacha20_crypt(chacha20_state, dst, src, src_len);
++	poly1305_update(&poly1305_state, dst, src_len);
++	poly1305_update(&poly1305_state, pad0, (0x10 - src_len) & 0xf);
++	b.lens[0] = cpu_to_le64(ad_len);
++	b.lens[1] = cpu_to_le64(src_len);
++	poly1305_update(&poly1305_state, (u8 *)b.lens, sizeof(b.lens));
++	poly1305_final(&poly1305_state, dst + src_len);
++}
++
+ static void __init
+ chacha20poly1305_selftest_encrypt(u8 *dst, const u8 *src, const size_t src_len,
+ 				  const u8 *ad, const size_t ad_len,
+@@ -7233,6 +8867,9 @@ chacha20poly1305_selftest_encrypt(u8 *ds
+ 	if (nonce_len == 8)
+ 		chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len,
+ 					 get_unaligned_le64(nonce), key);
++	else if (nonce_len == 12)
++		chacha20poly1305_encrypt_bignonce(dst, src, src_len, ad,
++						  ad_len, nonce, key);
+ 	else
+ 		BUG();
+ }
+@@ -7248,14 +8885,14 @@ decryption_success(bool func_ret, bool e
+ bool __init chacha20poly1305_selftest(void)
+ {
+ 	enum { MAXIMUM_TEST_BUFFER_LEN = 1UL << 12 };
+-	size_t i;
+-	u8 *computed_output = NULL, *heap_src = NULL;
+-	struct scatterlist sg_src;
++	size_t i, j, k, total_len;
++	u8 *computed_output = NULL, *input = NULL;
+ 	bool success = true, ret;
++	struct scatterlist sg_src[3];
+ 
+-	heap_src = kmalloc(MAXIMUM_TEST_BUFFER_LEN, GFP_KERNEL);
+ 	computed_output = kmalloc(MAXIMUM_TEST_BUFFER_LEN, GFP_KERNEL);
+-	if (!heap_src || !computed_output) {
++	input = kmalloc(MAXIMUM_TEST_BUFFER_LEN, GFP_KERNEL);
++	if (!computed_output || !input) {
+ 		pr_err("chacha20poly1305 self-test malloc: FAIL\n");
+ 		success = false;
+ 		goto out;
+@@ -7284,17 +8921,17 @@ bool __init chacha20poly1305_selftest(vo
+ 	for (i = 0; i < ARRAY_SIZE(chacha20poly1305_enc_vectors); ++i) {
+ 		if (chacha20poly1305_enc_vectors[i].nlen != 8)
+ 			continue;
+-		memcpy(heap_src, chacha20poly1305_enc_vectors[i].input,
++		memcpy(computed_output, chacha20poly1305_enc_vectors[i].input,
+ 		       chacha20poly1305_enc_vectors[i].ilen);
+-		sg_init_one(&sg_src, heap_src,
++		sg_init_one(sg_src, computed_output,
+ 			    chacha20poly1305_enc_vectors[i].ilen + POLY1305_DIGEST_SIZE);
+-		chacha20poly1305_encrypt_sg_inplace(&sg_src,
++		ret = chacha20poly1305_encrypt_sg_inplace(sg_src,
+ 			chacha20poly1305_enc_vectors[i].ilen,
+ 			chacha20poly1305_enc_vectors[i].assoc,
+ 			chacha20poly1305_enc_vectors[i].alen,
+ 			get_unaligned_le64(chacha20poly1305_enc_vectors[i].nonce),
+ 			chacha20poly1305_enc_vectors[i].key);
+-		if (memcmp(heap_src,
++		if (!ret || memcmp(computed_output,
+ 				   chacha20poly1305_enc_vectors[i].output,
+ 				   chacha20poly1305_enc_vectors[i].ilen +
+ 							POLY1305_DIGEST_SIZE)) {
+@@ -7326,11 +8963,11 @@ bool __init chacha20poly1305_selftest(vo
+ 	}
+ 
+ 	for (i = 0; i < ARRAY_SIZE(chacha20poly1305_dec_vectors); ++i) {
+-		memcpy(heap_src, chacha20poly1305_dec_vectors[i].input,
++		memcpy(computed_output, chacha20poly1305_dec_vectors[i].input,
+ 		       chacha20poly1305_dec_vectors[i].ilen);
+-		sg_init_one(&sg_src, heap_src,
++		sg_init_one(sg_src, computed_output,
+ 			    chacha20poly1305_dec_vectors[i].ilen);
+-		ret = chacha20poly1305_decrypt_sg_inplace(&sg_src,
++		ret = chacha20poly1305_decrypt_sg_inplace(sg_src,
+ 			chacha20poly1305_dec_vectors[i].ilen,
+ 			chacha20poly1305_dec_vectors[i].assoc,
+ 			chacha20poly1305_dec_vectors[i].alen,
+@@ -7338,7 +8975,7 @@ bool __init chacha20poly1305_selftest(vo
+ 			chacha20poly1305_dec_vectors[i].key);
+ 		if (!decryption_success(ret,
+ 			chacha20poly1305_dec_vectors[i].failure,
+-			memcmp(heap_src, chacha20poly1305_dec_vectors[i].output,
++			memcmp(computed_output, chacha20poly1305_dec_vectors[i].output,
+ 			       chacha20poly1305_dec_vectors[i].ilen -
+ 							POLY1305_DIGEST_SIZE))) {
+ 			pr_err("chacha20poly1305 sg decryption self-test %zu: FAIL\n",
+@@ -7365,6 +9002,7 @@ bool __init chacha20poly1305_selftest(vo
+ 			success = false;
+ 		}
+ 	}
++
+ 	for (i = 0; i < ARRAY_SIZE(xchacha20poly1305_dec_vectors); ++i) {
+ 		memset(computed_output, 0, MAXIMUM_TEST_BUFFER_LEN);
+ 		ret = xchacha20poly1305_decrypt(computed_output,
+@@ -7386,8 +9024,54 @@ bool __init chacha20poly1305_selftest(vo
+ 		}
+ 	}
+ 
++	for (total_len = POLY1305_DIGEST_SIZE; IS_ENABLED(DEBUG_CHACHA20POLY1305_SLOW_CHUNK_TEST)
++	     && total_len <= 1 << 10; ++total_len) {
++		for (i = 0; i <= total_len; ++i) {
++			for (j = i; j <= total_len; ++j) {
++				sg_init_table(sg_src, 3);
++				sg_set_buf(&sg_src[0], input, i);
++				sg_set_buf(&sg_src[1], input + i, j - i);
++				sg_set_buf(&sg_src[2], input + j, total_len - j);
++				memset(computed_output, 0, total_len);
++				memset(input, 0, total_len);
++
++				if (!chacha20poly1305_encrypt_sg_inplace(sg_src,
++					total_len - POLY1305_DIGEST_SIZE, NULL, 0,
++					0, enc_key001))
++					goto chunkfail;
++				chacha20poly1305_encrypt(computed_output,
++					computed_output,
++					total_len - POLY1305_DIGEST_SIZE, NULL, 0, 0,
++					enc_key001);
++				if (memcmp(computed_output, input, total_len))
++					goto chunkfail;
++				if (!chacha20poly1305_decrypt(computed_output,
++					input, total_len, NULL, 0, 0, enc_key001))
++					goto chunkfail;
++				for (k = 0; k < total_len - POLY1305_DIGEST_SIZE; ++k) {
++					if (computed_output[k])
++						goto chunkfail;
++				}
++				if (!chacha20poly1305_decrypt_sg_inplace(sg_src,
++					total_len, NULL, 0, 0, enc_key001))
++					goto chunkfail;
++				for (k = 0; k < total_len - POLY1305_DIGEST_SIZE; ++k) {
++					if (input[k])
++						goto chunkfail;
++				}
++				continue;
++
++			chunkfail:
++				pr_err("chacha20poly1305 chunked self-test %zu/%zu/%zu: FAIL\n",
++				       total_len, i, j);
++				success = false;
++			}
++
++		}
++	}
++
+ out:
+-	kfree(heap_src);
+ 	kfree(computed_output);
++	kfree(input);
+ 	return success;
+ }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0048-crypto-x86-poly1305-emit-does-base-conversion-itself.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0048-crypto-x86-poly1305-emit-does-base-conversion-itself.patch
new file mode 100644
index 0000000..8209ca2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0048-crypto-x86-poly1305-emit-does-base-conversion-itself.patch
@@ -0,0 +1,36 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 17 Jan 2020 11:42:22 +0100
+Subject: [PATCH] crypto: x86/poly1305 - emit does base conversion itself
+
+commit f9e7fe32a792726186301423ff63a465d63386e1 upstream.
+
+The emit code does optional base conversion itself in assembly, so we
+don't need to do that here. Also, neither one of these functions uses
+simd instructions, so checking for that doesn't make sense either.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/poly1305_glue.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+--- a/arch/x86/crypto/poly1305_glue.c
++++ b/arch/x86/crypto/poly1305_glue.c
+@@ -123,13 +123,9 @@ static void poly1305_simd_blocks(void *c
+ static void poly1305_simd_emit(void *ctx, u8 mac[POLY1305_DIGEST_SIZE],
+ 			       const u32 nonce[4])
+ {
+-	struct poly1305_arch_internal *state = ctx;
+-
+-	if (!IS_ENABLED(CONFIG_AS_AVX) || !static_branch_likely(&poly1305_use_avx) ||
+-	    !state->is_base2_26 || !crypto_simd_usable()) {
+-		convert_to_base2_64(ctx);
++	if (!IS_ENABLED(CONFIG_AS_AVX) || !static_branch_likely(&poly1305_use_avx))
+ 		poly1305_emit_x86_64(ctx, mac, nonce);
+-	} else
++	else
+ 		poly1305_emit_avx(ctx, mac, nonce);
+ }
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0049-crypto-arm-chacha-fix-build-failured-when-kernel-mod.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0049-crypto-arm-chacha-fix-build-failured-when-kernel-mod.patch
new file mode 100644
index 0000000..354f584
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0049-crypto-arm-chacha-fix-build-failured-when-kernel-mod.patch
@@ -0,0 +1,58 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 17 Jan 2020 17:43:18 +0100
+Subject: [PATCH] crypto: arm/chacha - fix build failured when kernel mode NEON
+ is disabled
+
+commit 0bc81767c5bd9d005fae1099fb39eb3688370cb1 upstream.
+
+When the ARM accelerated ChaCha driver is built as part of a configuration
+that has kernel mode NEON disabled, we expect the compiler to propagate
+the build time constant expression IS_ENABLED(CONFIG_KERNEL_MODE_NEON) in
+a way that eliminates all the cross-object references to the actual NEON
+routines, which allows the chacha-neon-core.o object to be omitted from
+the build entirely.
+
+Unfortunately, this fails to work as expected in some cases, and we may
+end up with a build error such as
+
+  chacha-glue.c:(.text+0xc0): undefined reference to `chacha_4block_xor_neon'
+
+caused by the fact that chacha_doneon() has not been eliminated from the
+object code, even though it will never be called in practice.
+
+Let's fix this by adding some IS_ENABLED(CONFIG_KERNEL_MODE_NEON) tests
+that are not strictly needed from a logical point of view, but should
+help the compiler infer that the NEON code paths are unreachable in
+those cases.
+
+Fixes: b36d8c09e710c71f ("crypto: arm/chacha - remove dependency on generic ...")
+Reported-by: Russell King <linux@armlinux.org.uk>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm/crypto/chacha-glue.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/crypto/chacha-glue.c
++++ b/arch/arm/crypto/chacha-glue.c
+@@ -115,7 +115,7 @@ static int chacha_stream_xor(struct skci
+ 		if (nbytes < walk.total)
+ 			nbytes = round_down(nbytes, walk.stride);
+ 
+-		if (!neon) {
++		if (!IS_ENABLED(CONFIG_KERNEL_MODE_NEON) || !neon) {
+ 			chacha_doarm(walk.dst.virt.addr, walk.src.virt.addr,
+ 				     nbytes, state, ctx->nrounds);
+ 			state[12] += DIV_ROUND_UP(nbytes, CHACHA_BLOCK_SIZE);
+@@ -159,7 +159,7 @@ static int do_xchacha(struct skcipher_re
+ 
+ 	chacha_init_generic(state, ctx->key, req->iv);
+ 
+-	if (!neon) {
++	if (!IS_ENABLED(CONFIG_KERNEL_MODE_NEON) || !neon) {
+ 		hchacha_block_arm(state, subctx.key, ctx->nrounds);
+ 	} else {
+ 		kernel_neon_begin();
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0050-crypto-Kconfig-allow-tests-to-be-disabled-when-manag.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0050-crypto-Kconfig-allow-tests-to-be-disabled-when-manag.patch
new file mode 100644
index 0000000..c52bf0a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0050-crypto-Kconfig-allow-tests-to-be-disabled-when-manag.patch
@@ -0,0 +1,40 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 17 Jan 2020 12:01:36 +0100
+Subject: [PATCH] crypto: Kconfig - allow tests to be disabled when manager is
+ disabled
+
+commit 2343d1529aff8b552589f622c23932035ed7a05d upstream.
+
+The library code uses CRYPTO_MANAGER_DISABLE_TESTS to conditionalize its
+tests, but the library code can also exist without CRYPTO_MANAGER. That
+means on minimal configs, the test code winds up being built with no way
+to disable it.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ crypto/Kconfig | 4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -136,8 +136,6 @@ config CRYPTO_USER
+ 	  Userspace configuration for cryptographic instantiations such as
+ 	  cbc(aes).
+ 
+-if CRYPTO_MANAGER2
+-
+ config CRYPTO_MANAGER_DISABLE_TESTS
+ 	bool "Disable run-time self tests"
+ 	default y
+@@ -155,8 +153,6 @@ config CRYPTO_MANAGER_EXTRA_TESTS
+ 	  This is intended for developer use only, as these tests take much
+ 	  longer to run than the normal self tests.
+ 
+-endif	# if CRYPTO_MANAGER2
+-
+ config CRYPTO_GF128MUL
+ 	tristate
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0051-crypto-chacha20poly1305-prevent-integer-overflow-on-.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0051-crypto-chacha20poly1305-prevent-integer-overflow-on-.patch
new file mode 100644
index 0000000..1ed49e5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0051-crypto-chacha20poly1305-prevent-integer-overflow-on-.patch
@@ -0,0 +1,40 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Thu, 6 Feb 2020 12:42:01 +0100
+Subject: [PATCH] crypto: chacha20poly1305 - prevent integer overflow on large
+ input
+
+commit c9cc0517bba9f0213f1e55172feceb99e5512daf upstream.
+
+This code assigns src_len (size_t) to sl (int), which causes problems
+when src_len is very large. Probably nobody in the kernel should be
+passing this much data to chacha20poly1305 all in one go anyway, so I
+don't think we need to change the algorithm or introduce larger types
+or anything. But we should at least error out early in this case and
+print a warning so that we get reports if this does happen and can look
+into why anybody is possibly passing it that much data or if they're
+accidently passing -1 or similar.
+
+Fixes: d95312a3ccc0 ("crypto: lib/chacha20poly1305 - reimplement crypt_from_sg() routine")
+Cc: Ard Biesheuvel <ardb@kernel.org>
+Cc: stable@vger.kernel.org # 5.5+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Acked-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ lib/crypto/chacha20poly1305.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/lib/crypto/chacha20poly1305.c
++++ b/lib/crypto/chacha20poly1305.c
+@@ -235,6 +235,9 @@ bool chacha20poly1305_crypt_sg_inplace(s
+ 		__le64 lens[2];
+ 	} b __aligned(16);
+ 
++	if (WARN_ON(src_len > INT_MAX))
++		return false;
++
+ 	chacha_load_key(b.k, key);
+ 
+ 	b.iv[0] = 0;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0052-crypto-x86-curve25519-support-assemblers-with-no-adx.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0052-crypto-x86-curve25519-support-assemblers-with-no-adx.patch
new file mode 100644
index 0000000..cd507b1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0052-crypto-x86-curve25519-support-assemblers-with-no-adx.patch
@@ -0,0 +1,84 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Sun, 1 Mar 2020 22:52:35 +0800
+Subject: [PATCH] crypto: x86/curve25519 - support assemblers with no adx
+ support
+
+commit 1579f1bc3b753d17a44de3457d5c6f4a5b14c752 upstream.
+
+Some older version of GAS do not support the ADX instructions, similarly
+to how they also don't support AVX and such. This commit adds the same
+build-time detection mechanisms we use for AVX and others for ADX, and
+then makes sure that the curve25519 library dispatcher calls the right
+functions.
+
+Reported-by: Willy Tarreau <w@1wt.eu>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/Makefile           | 5 +++--
+ arch/x86/crypto/Makefile    | 7 ++++++-
+ include/crypto/curve25519.h | 6 ++++--
+ 3 files changed, 13 insertions(+), 5 deletions(-)
+
+--- a/arch/x86/Makefile
++++ b/arch/x86/Makefile
+@@ -198,9 +198,10 @@ avx2_instr :=$(call as-instr,vpbroadcast
+ avx512_instr :=$(call as-instr,vpmovm2b %k1$(comma)%zmm5,-DCONFIG_AS_AVX512=1)
+ sha1_ni_instr :=$(call as-instr,sha1msg1 %xmm0$(comma)%xmm1,-DCONFIG_AS_SHA1_NI=1)
+ sha256_ni_instr :=$(call as-instr,sha256msg1 %xmm0$(comma)%xmm1,-DCONFIG_AS_SHA256_NI=1)
++adx_instr := $(call as-instr,adox %r10$(comma)%r10,-DCONFIG_AS_ADX=1)
+ 
+-KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) $(avx512_instr) $(sha1_ni_instr) $(sha256_ni_instr)
+-KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) $(avx512_instr) $(sha1_ni_instr) $(sha256_ni_instr)
++KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) $(avx512_instr) $(sha1_ni_instr) $(sha256_ni_instr) $(adx_instr)
++KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) $(avx512_instr) $(sha1_ni_instr) $(sha256_ni_instr) $(adx_instr)
+ 
+ KBUILD_LDFLAGS := -m elf_$(UTS_MACHINE)
+ 
+--- a/arch/x86/crypto/Makefile
++++ b/arch/x86/crypto/Makefile
+@@ -11,6 +11,7 @@ avx2_supported := $(call as-instr,vpgath
+ avx512_supported :=$(call as-instr,vpmovm2b %k1$(comma)%zmm5,yes,no)
+ sha1_ni_supported :=$(call as-instr,sha1msg1 %xmm0$(comma)%xmm1,yes,no)
+ sha256_ni_supported :=$(call as-instr,sha256msg1 %xmm0$(comma)%xmm1,yes,no)
++adx_supported := $(call as-instr,adox %r10$(comma)%r10,yes,no)
+ 
+ obj-$(CONFIG_CRYPTO_GLUE_HELPER_X86) += glue_helper.o
+ 
+@@ -39,7 +40,11 @@ obj-$(CONFIG_CRYPTO_AEGIS128_AESNI_SSE2)
+ 
+ obj-$(CONFIG_CRYPTO_NHPOLY1305_SSE2) += nhpoly1305-sse2.o
+ obj-$(CONFIG_CRYPTO_NHPOLY1305_AVX2) += nhpoly1305-avx2.o
+-obj-$(CONFIG_CRYPTO_CURVE25519_X86) += curve25519-x86_64.o
++
++# These modules require the assembler to support ADX.
++ifeq ($(adx_supported),yes)
++	obj-$(CONFIG_CRYPTO_CURVE25519_X86) += curve25519-x86_64.o
++endif
+ 
+ # These modules require assembler to support AVX.
+ ifeq ($(avx_supported),yes)
+--- a/include/crypto/curve25519.h
++++ b/include/crypto/curve25519.h
+@@ -33,7 +33,8 @@ bool __must_check curve25519(u8 mypublic
+ 			     const u8 secret[CURVE25519_KEY_SIZE],
+ 			     const u8 basepoint[CURVE25519_KEY_SIZE])
+ {
+-	if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519))
++	if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519) &&
++	    (!IS_ENABLED(CONFIG_CRYPTO_CURVE25519_X86) || IS_ENABLED(CONFIG_AS_ADX)))
+ 		curve25519_arch(mypublic, secret, basepoint);
+ 	else
+ 		curve25519_generic(mypublic, secret, basepoint);
+@@ -49,7 +50,8 @@ __must_check curve25519_generate_public(
+ 				    CURVE25519_KEY_SIZE)))
+ 		return false;
+ 
+-	if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519))
++	if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519) &&
++	    (!IS_ENABLED(CONFIG_CRYPTO_CURVE25519_X86) || IS_ENABLED(CONFIG_AS_ADX)))
+ 		curve25519_base_arch(pub, secret);
+ 	else
+ 		curve25519_generic(pub, secret, curve25519_base_point);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0053-crypto-arm64-chacha-correctly-walk-through-blocks.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0053-crypto-arm64-chacha-correctly-walk-through-blocks.patch
new file mode 100644
index 0000000..823a908
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0053-crypto-arm64-chacha-correctly-walk-through-blocks.patch
@@ -0,0 +1,68 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Wed, 18 Mar 2020 20:27:32 -0600
+Subject: [PATCH] crypto: arm64/chacha - correctly walk through blocks
+
+commit c8cfcb78c65877313cda7bcbace624d3dbd1f3b3 upstream.
+
+Prior, passing in chunks of 2, 3, or 4, followed by any additional
+chunks would result in the chacha state counter getting out of sync,
+resulting in incorrect encryption/decryption, which is a pretty nasty
+crypto vuln: "why do images look weird on webpages?" WireGuard users
+never experienced this prior, because we have always, out of tree, used
+a different crypto library, until the recent Frankenzinc addition. This
+commit fixes the issue by advancing the pointers and state counter by
+the actual size processed. It also fixes up a bug in the (optional,
+costly) stride test that prevented it from running on arm64.
+
+Fixes: b3aad5bad26a ("crypto: arm64/chacha - expose arm64 ChaCha routine as library function")
+Reported-and-tested-by: Emil Renner Berthing <kernel@esmil.dk>
+Cc: Ard Biesheuvel <ardb@kernel.org>
+Cc: stable@vger.kernel.org # v5.5+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Reviewed-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm64/crypto/chacha-neon-glue.c   |  8 ++++----
+ lib/crypto/chacha20poly1305-selftest.c | 11 ++++++++---
+ 2 files changed, 12 insertions(+), 7 deletions(-)
+
+--- a/arch/arm64/crypto/chacha-neon-glue.c
++++ b/arch/arm64/crypto/chacha-neon-glue.c
+@@ -55,10 +55,10 @@ static void chacha_doneon(u32 *state, u8
+ 			break;
+ 		}
+ 		chacha_4block_xor_neon(state, dst, src, nrounds, l);
+-		bytes -= CHACHA_BLOCK_SIZE * 5;
+-		src += CHACHA_BLOCK_SIZE * 5;
+-		dst += CHACHA_BLOCK_SIZE * 5;
+-		state[12] += 5;
++		bytes -= l;
++		src += l;
++		dst += l;
++		state[12] += DIV_ROUND_UP(l, CHACHA_BLOCK_SIZE);
+ 	}
+ }
+ 
+--- a/lib/crypto/chacha20poly1305-selftest.c
++++ b/lib/crypto/chacha20poly1305-selftest.c
+@@ -9028,10 +9028,15 @@ bool __init chacha20poly1305_selftest(vo
+ 	     && total_len <= 1 << 10; ++total_len) {
+ 		for (i = 0; i <= total_len; ++i) {
+ 			for (j = i; j <= total_len; ++j) {
++				k = 0;
+ 				sg_init_table(sg_src, 3);
+-				sg_set_buf(&sg_src[0], input, i);
+-				sg_set_buf(&sg_src[1], input + i, j - i);
+-				sg_set_buf(&sg_src[2], input + j, total_len - j);
++				if (i)
++					sg_set_buf(&sg_src[k++], input, i);
++				if (j - i)
++					sg_set_buf(&sg_src[k++], input + i, j - i);
++				if (total_len - j)
++					sg_set_buf(&sg_src[k++], input + j, total_len - j);
++				sg_init_marker(sg_src, k);
+ 				memset(computed_output, 0, total_len);
+ 				memset(input, 0, total_len);
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0054-crypto-x86-curve25519-replace-with-formally-verified.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0054-crypto-x86-curve25519-replace-with-formally-verified.patch
new file mode 100644
index 0000000..938d700
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0054-crypto-x86-curve25519-replace-with-formally-verified.patch
@@ -0,0 +1,3765 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Mon, 20 Jan 2020 18:18:15 +0100
+Subject: [PATCH] crypto: x86/curve25519 - replace with formally verified
+ implementation
+
+commit 07b586fe06625b0b610dc3d3a969c51913d143d4 upstream.
+
+This comes from INRIA's HACL*/Vale. It implements the same algorithm and
+implementation strategy as the code it replaces, only this code has been
+formally verified, sans the base point multiplication, which uses code
+similar to prior, only it uses the formally verified field arithmetic
+alongside reproducable ladder generation steps. This doesn't have a
+pure-bmi2 version, which means haswell no longer benefits, but the
+increased (doubled) code complexity is not worth it for a single
+generation of chips that's already old.
+
+Performance-wise, this is around 1% slower on older microarchitectures,
+and slightly faster on newer microarchitectures, mainly 10nm ones or
+backports of 10nm to 14nm. This implementation is "everest" below:
+
+Xeon E5-2680 v4 (Broadwell)
+
+     armfazh: 133340 cycles per call
+     everest: 133436 cycles per call
+
+Xeon Gold 5120 (Sky Lake Server)
+
+     armfazh: 112636 cycles per call
+     everest: 113906 cycles per call
+
+Core i5-6300U (Sky Lake Client)
+
+     armfazh: 116810 cycles per call
+     everest: 117916 cycles per call
+
+Core i7-7600U (Kaby Lake)
+
+     armfazh: 119523 cycles per call
+     everest: 119040 cycles per call
+
+Core i7-8750H (Coffee Lake)
+
+     armfazh: 113914 cycles per call
+     everest: 113650 cycles per call
+
+Core i9-9880H (Coffee Lake Refresh)
+
+     armfazh: 112616 cycles per call
+     everest: 114082 cycles per call
+
+Core i3-8121U (Cannon Lake)
+
+     armfazh: 113202 cycles per call
+     everest: 111382 cycles per call
+
+Core i7-8265U (Whiskey Lake)
+
+     armfazh: 127307 cycles per call
+     everest: 127697 cycles per call
+
+Core i7-8550U (Kaby Lake Refresh)
+
+     armfazh: 127522 cycles per call
+     everest: 127083 cycles per call
+
+Xeon Platinum 8275CL (Cascade Lake)
+
+     armfazh: 114380 cycles per call
+     everest: 114656 cycles per call
+
+Achieving these kind of results with formally verified code is quite
+remarkable, especialy considering that performance is favorable for
+newer chips.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/curve25519-x86_64.c | 3546 ++++++++++-----------------
+ 1 file changed, 1292 insertions(+), 2254 deletions(-)
+
+--- a/arch/x86/crypto/curve25519-x86_64.c
++++ b/arch/x86/crypto/curve25519-x86_64.c
+@@ -1,8 +1,7 @@
+-// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
++// SPDX-License-Identifier: GPL-2.0 OR MIT
+ /*
+- * Copyright (c) 2017 Armando Faz <armfazh@ic.unicamp.br>. All Rights Reserved.
+- * Copyright (C) 2018-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+- * Copyright (C) 2018 Samuel Neves <sneves@dei.uc.pt>. All Rights Reserved.
++ * Copyright (C) 2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ * Copyright (c) 2016-2020 INRIA, CMU and Microsoft Corporation
+  */
+ 
+ #include <crypto/curve25519.h>
+@@ -16,2337 +15,1378 @@
+ #include <asm/cpufeature.h>
+ #include <asm/processor.h>
+ 
+-static __ro_after_init DEFINE_STATIC_KEY_FALSE(curve25519_use_bmi2);
+-static __ro_after_init DEFINE_STATIC_KEY_FALSE(curve25519_use_adx);
+-
+-enum { NUM_WORDS_ELTFP25519 = 4 };
+-typedef __aligned(32) u64 eltfp25519_1w[NUM_WORDS_ELTFP25519];
+-typedef __aligned(32) u64 eltfp25519_1w_buffer[2 * NUM_WORDS_ELTFP25519];
+-
+-#define mul_eltfp25519_1w_adx(c, a, b) do { \
+-	mul_256x256_integer_adx(m.buffer, a, b); \
+-	red_eltfp25519_1w_adx(c, m.buffer); \
+-} while (0)
+-
+-#define mul_eltfp25519_1w_bmi2(c, a, b) do { \
+-	mul_256x256_integer_bmi2(m.buffer, a, b); \
+-	red_eltfp25519_1w_bmi2(c, m.buffer); \
+-} while (0)
+-
+-#define sqr_eltfp25519_1w_adx(a) do { \
+-	sqr_256x256_integer_adx(m.buffer, a); \
+-	red_eltfp25519_1w_adx(a, m.buffer); \
+-} while (0)
+-
+-#define sqr_eltfp25519_1w_bmi2(a) do { \
+-	sqr_256x256_integer_bmi2(m.buffer, a); \
+-	red_eltfp25519_1w_bmi2(a, m.buffer); \
+-} while (0)
+-
+-#define mul_eltfp25519_2w_adx(c, a, b) do { \
+-	mul2_256x256_integer_adx(m.buffer, a, b); \
+-	red_eltfp25519_2w_adx(c, m.buffer); \
+-} while (0)
+-
+-#define mul_eltfp25519_2w_bmi2(c, a, b) do { \
+-	mul2_256x256_integer_bmi2(m.buffer, a, b); \
+-	red_eltfp25519_2w_bmi2(c, m.buffer); \
+-} while (0)
+-
+-#define sqr_eltfp25519_2w_adx(a) do { \
+-	sqr2_256x256_integer_adx(m.buffer, a); \
+-	red_eltfp25519_2w_adx(a, m.buffer); \
+-} while (0)
+-
+-#define sqr_eltfp25519_2w_bmi2(a) do { \
+-	sqr2_256x256_integer_bmi2(m.buffer, a); \
+-	red_eltfp25519_2w_bmi2(a, m.buffer); \
+-} while (0)
+-
+-#define sqrn_eltfp25519_1w_adx(a, times) do { \
+-	int ____counter = (times); \
+-	while (____counter-- > 0) \
+-		sqr_eltfp25519_1w_adx(a); \
+-} while (0)
+-
+-#define sqrn_eltfp25519_1w_bmi2(a, times) do { \
+-	int ____counter = (times); \
+-	while (____counter-- > 0) \
+-		sqr_eltfp25519_1w_bmi2(a); \
+-} while (0)
+-
+-#define copy_eltfp25519_1w(C, A) do { \
+-	(C)[0] = (A)[0]; \
+-	(C)[1] = (A)[1]; \
+-	(C)[2] = (A)[2]; \
+-	(C)[3] = (A)[3]; \
+-} while (0)
+-
+-#define setzero_eltfp25519_1w(C) do { \
+-	(C)[0] = 0; \
+-	(C)[1] = 0; \
+-	(C)[2] = 0; \
+-	(C)[3] = 0; \
+-} while (0)
+-
+-__aligned(32) static const u64 table_ladder_8k[252 * NUM_WORDS_ELTFP25519] = {
+-	/*   1 */ 0xfffffffffffffff3UL, 0xffffffffffffffffUL,
+-		  0xffffffffffffffffUL, 0x5fffffffffffffffUL,
+-	/*   2 */ 0x6b8220f416aafe96UL, 0x82ebeb2b4f566a34UL,
+-		  0xd5a9a5b075a5950fUL, 0x5142b2cf4b2488f4UL,
+-	/*   3 */ 0x6aaebc750069680cUL, 0x89cf7820a0f99c41UL,
+-		  0x2a58d9183b56d0f4UL, 0x4b5aca80e36011a4UL,
+-	/*   4 */ 0x329132348c29745dUL, 0xf4a2e616e1642fd7UL,
+-		  0x1e45bb03ff67bc34UL, 0x306912d0f42a9b4aUL,
+-	/*   5 */ 0xff886507e6af7154UL, 0x04f50e13dfeec82fUL,
+-		  0xaa512fe82abab5ceUL, 0x174e251a68d5f222UL,
+-	/*   6 */ 0xcf96700d82028898UL, 0x1743e3370a2c02c5UL,
+-		  0x379eec98b4e86eaaUL, 0x0c59888a51e0482eUL,
+-	/*   7 */ 0xfbcbf1d699b5d189UL, 0xacaef0d58e9fdc84UL,
+-		  0xc1c20d06231f7614UL, 0x2938218da274f972UL,
+-	/*   8 */ 0xf6af49beff1d7f18UL, 0xcc541c22387ac9c2UL,
+-		  0x96fcc9ef4015c56bUL, 0x69c1627c690913a9UL,
+-	/*   9 */ 0x7a86fd2f4733db0eUL, 0xfdb8c4f29e087de9UL,
+-		  0x095e4b1a8ea2a229UL, 0x1ad7a7c829b37a79UL,
+-	/*  10 */ 0x342d89cad17ea0c0UL, 0x67bedda6cced2051UL,
+-		  0x19ca31bf2bb42f74UL, 0x3df7b4c84980acbbUL,
+-	/*  11 */ 0xa8c6444dc80ad883UL, 0xb91e440366e3ab85UL,
+-		  0xc215cda00164f6d8UL, 0x3d867c6ef247e668UL,
+-	/*  12 */ 0xc7dd582bcc3e658cUL, 0xfd2c4748ee0e5528UL,
+-		  0xa0fd9b95cc9f4f71UL, 0x7529d871b0675ddfUL,
+-	/*  13 */ 0xb8f568b42d3cbd78UL, 0x1233011b91f3da82UL,
+-		  0x2dce6ccd4a7c3b62UL, 0x75e7fc8e9e498603UL,
+-	/*  14 */ 0x2f4f13f1fcd0b6ecUL, 0xf1a8ca1f29ff7a45UL,
+-		  0xc249c1a72981e29bUL, 0x6ebe0dbb8c83b56aUL,
+-	/*  15 */ 0x7114fa8d170bb222UL, 0x65a2dcd5bf93935fUL,
+-		  0xbdc41f68b59c979aUL, 0x2f0eef79a2ce9289UL,
+-	/*  16 */ 0x42ecbf0c083c37ceUL, 0x2930bc09ec496322UL,
+-		  0xf294b0c19cfeac0dUL, 0x3780aa4bedfabb80UL,
+-	/*  17 */ 0x56c17d3e7cead929UL, 0xe7cb4beb2e5722c5UL,
+-		  0x0ce931732dbfe15aUL, 0x41b883c7621052f8UL,
+-	/*  18 */ 0xdbf75ca0c3d25350UL, 0x2936be086eb1e351UL,
+-		  0xc936e03cb4a9b212UL, 0x1d45bf82322225aaUL,
+-	/*  19 */ 0xe81ab1036a024cc5UL, 0xe212201c304c9a72UL,
+-		  0xc5d73fba6832b1fcUL, 0x20ffdb5a4d839581UL,
+-	/*  20 */ 0xa283d367be5d0fadUL, 0x6c2b25ca8b164475UL,
+-		  0x9d4935467caaf22eUL, 0x5166408eee85ff49UL,
+-	/*  21 */ 0x3c67baa2fab4e361UL, 0xb3e433c67ef35cefUL,
+-		  0x5259729241159b1cUL, 0x6a621892d5b0ab33UL,
+-	/*  22 */ 0x20b74a387555cdcbUL, 0x532aa10e1208923fUL,
+-		  0xeaa17b7762281dd1UL, 0x61ab3443f05c44bfUL,
+-	/*  23 */ 0x257a6c422324def8UL, 0x131c6c1017e3cf7fUL,
+-		  0x23758739f630a257UL, 0x295a407a01a78580UL,
+-	/*  24 */ 0xf8c443246d5da8d9UL, 0x19d775450c52fa5dUL,
+-		  0x2afcfc92731bf83dUL, 0x7d10c8e81b2b4700UL,
+-	/*  25 */ 0xc8e0271f70baa20bUL, 0x993748867ca63957UL,
+-		  0x5412efb3cb7ed4bbUL, 0x3196d36173e62975UL,
+-	/*  26 */ 0xde5bcad141c7dffcUL, 0x47cc8cd2b395c848UL,
+-		  0xa34cd942e11af3cbUL, 0x0256dbf2d04ecec2UL,
+-	/*  27 */ 0x875ab7e94b0e667fUL, 0xcad4dd83c0850d10UL,
+-		  0x47f12e8f4e72c79fUL, 0x5f1a87bb8c85b19bUL,
+-	/*  28 */ 0x7ae9d0b6437f51b8UL, 0x12c7ce5518879065UL,
+-		  0x2ade09fe5cf77aeeUL, 0x23a05a2f7d2c5627UL,
+-	/*  29 */ 0x5908e128f17c169aUL, 0xf77498dd8ad0852dUL,
+-		  0x74b4c4ceab102f64UL, 0x183abadd10139845UL,
+-	/*  30 */ 0xb165ba8daa92aaacUL, 0xd5c5ef9599386705UL,
+-		  0xbe2f8f0cf8fc40d1UL, 0x2701e635ee204514UL,
+-	/*  31 */ 0x629fa80020156514UL, 0xf223868764a8c1ceUL,
+-		  0x5b894fff0b3f060eUL, 0x60d9944cf708a3faUL,
+-	/*  32 */ 0xaeea001a1c7a201fUL, 0xebf16a633ee2ce63UL,
+-		  0x6f7709594c7a07e1UL, 0x79b958150d0208cbUL,
+-	/*  33 */ 0x24b55e5301d410e7UL, 0xe3a34edff3fdc84dUL,
+-		  0xd88768e4904032d8UL, 0x131384427b3aaeecUL,
+-	/*  34 */ 0x8405e51286234f14UL, 0x14dc4739adb4c529UL,
+-		  0xb8a2b5b250634ffdUL, 0x2fe2a94ad8a7ff93UL,
+-	/*  35 */ 0xec5c57efe843faddUL, 0x2843ce40f0bb9918UL,
+-		  0xa4b561d6cf3d6305UL, 0x743629bde8fb777eUL,
+-	/*  36 */ 0x343edd46bbaf738fUL, 0xed981828b101a651UL,
+-		  0xa401760b882c797aUL, 0x1fc223e28dc88730UL,
+-	/*  37 */ 0x48604e91fc0fba0eUL, 0xb637f78f052c6fa4UL,
+-		  0x91ccac3d09e9239cUL, 0x23f7eed4437a687cUL,
+-	/*  38 */ 0x5173b1118d9bd800UL, 0x29d641b63189d4a7UL,
+-		  0xfdbf177988bbc586UL, 0x2959894fcad81df5UL,
+-	/*  39 */ 0xaebc8ef3b4bbc899UL, 0x4148995ab26992b9UL,
+-		  0x24e20b0134f92cfbUL, 0x40d158894a05dee8UL,
+-	/*  40 */ 0x46b00b1185af76f6UL, 0x26bac77873187a79UL,
+-		  0x3dc0bf95ab8fff5fUL, 0x2a608bd8945524d7UL,
+-	/*  41 */ 0x26449588bd446302UL, 0x7c4bc21c0388439cUL,
+-		  0x8e98a4f383bd11b2UL, 0x26218d7bc9d876b9UL,
+-	/*  42 */ 0xe3081542997c178aUL, 0x3c2d29a86fb6606fUL,
+-		  0x5c217736fa279374UL, 0x7dde05734afeb1faUL,
+-	/*  43 */ 0x3bf10e3906d42babUL, 0xe4f7803e1980649cUL,
+-		  0xe6053bf89595bf7aUL, 0x394faf38da245530UL,
+-	/*  44 */ 0x7a8efb58896928f4UL, 0xfbc778e9cc6a113cUL,
+-		  0x72670ce330af596fUL, 0x48f222a81d3d6cf7UL,
+-	/*  45 */ 0xf01fce410d72caa7UL, 0x5a20ecc7213b5595UL,
+-		  0x7bc21165c1fa1483UL, 0x07f89ae31da8a741UL,
+-	/*  46 */ 0x05d2c2b4c6830ff9UL, 0xd43e330fc6316293UL,
+-		  0xa5a5590a96d3a904UL, 0x705edb91a65333b6UL,
+-	/*  47 */ 0x048ee15e0bb9a5f7UL, 0x3240cfca9e0aaf5dUL,
+-		  0x8f4b71ceedc4a40bUL, 0x621c0da3de544a6dUL,
+-	/*  48 */ 0x92872836a08c4091UL, 0xce8375b010c91445UL,
+-		  0x8a72eb524f276394UL, 0x2667fcfa7ec83635UL,
+-	/*  49 */ 0x7f4c173345e8752aUL, 0x061b47feee7079a5UL,
+-		  0x25dd9afa9f86ff34UL, 0x3780cef5425dc89cUL,
+-	/*  50 */ 0x1a46035a513bb4e9UL, 0x3e1ef379ac575adaUL,
+-		  0xc78c5f1c5fa24b50UL, 0x321a967634fd9f22UL,
+-	/*  51 */ 0x946707b8826e27faUL, 0x3dca84d64c506fd0UL,
+-		  0xc189218075e91436UL, 0x6d9284169b3b8484UL,
+-	/*  52 */ 0x3a67e840383f2ddfUL, 0x33eec9a30c4f9b75UL,
+-		  0x3ec7c86fa783ef47UL, 0x26ec449fbac9fbc4UL,
+-	/*  53 */ 0x5c0f38cba09b9e7dUL, 0x81168cc762a3478cUL,
+-		  0x3e23b0d306fc121cUL, 0x5a238aa0a5efdcddUL,
+-	/*  54 */ 0x1ba26121c4ea43ffUL, 0x36f8c77f7c8832b5UL,
+-		  0x88fbea0b0adcf99aUL, 0x5ca9938ec25bebf9UL,
+-	/*  55 */ 0xd5436a5e51fccda0UL, 0x1dbc4797c2cd893bUL,
+-		  0x19346a65d3224a08UL, 0x0f5034e49b9af466UL,
+-	/*  56 */ 0xf23c3967a1e0b96eUL, 0xe58b08fa867a4d88UL,
+-		  0xfb2fabc6a7341679UL, 0x2a75381eb6026946UL,
+-	/*  57 */ 0xc80a3be4c19420acUL, 0x66b1f6c681f2b6dcUL,
+-		  0x7cf7036761e93388UL, 0x25abbbd8a660a4c4UL,
+-	/*  58 */ 0x91ea12ba14fd5198UL, 0x684950fc4a3cffa9UL,
+-		  0xf826842130f5ad28UL, 0x3ea988f75301a441UL,
+-	/*  59 */ 0xc978109a695f8c6fUL, 0x1746eb4a0530c3f3UL,
+-		  0x444d6d77b4459995UL, 0x75952b8c054e5cc7UL,
+-	/*  60 */ 0xa3703f7915f4d6aaUL, 0x66c346202f2647d8UL,
+-		  0xd01469df811d644bUL, 0x77fea47d81a5d71fUL,
+-	/*  61 */ 0xc5e9529ef57ca381UL, 0x6eeeb4b9ce2f881aUL,
+-		  0xb6e91a28e8009bd6UL, 0x4b80be3e9afc3fecUL,
+-	/*  62 */ 0x7e3773c526aed2c5UL, 0x1b4afcb453c9a49dUL,
+-		  0xa920bdd7baffb24dUL, 0x7c54699f122d400eUL,
+-	/*  63 */ 0xef46c8e14fa94bc8UL, 0xe0b074ce2952ed5eUL,
+-		  0xbea450e1dbd885d5UL, 0x61b68649320f712cUL,
+-	/*  64 */ 0x8a485f7309ccbdd1UL, 0xbd06320d7d4d1a2dUL,
+-		  0x25232973322dbef4UL, 0x445dc4758c17f770UL,
+-	/*  65 */ 0xdb0434177cc8933cUL, 0xed6fe82175ea059fUL,
+-		  0x1efebefdc053db34UL, 0x4adbe867c65daf99UL,
+-	/*  66 */ 0x3acd71a2a90609dfUL, 0xe5e991856dd04050UL,
+-		  0x1ec69b688157c23cUL, 0x697427f6885cfe4dUL,
+-	/*  67 */ 0xd7be7b9b65e1a851UL, 0xa03d28d522c536ddUL,
+-		  0x28399d658fd2b645UL, 0x49e5b7e17c2641e1UL,
+-	/*  68 */ 0x6f8c3a98700457a4UL, 0x5078f0a25ebb6778UL,
+-		  0xd13c3ccbc382960fUL, 0x2e003258a7df84b1UL,
+-	/*  69 */ 0x8ad1f39be6296a1cUL, 0xc1eeaa652a5fbfb2UL,
+-		  0x33ee0673fd26f3cbUL, 0x59256173a69d2cccUL,
+-	/*  70 */ 0x41ea07aa4e18fc41UL, 0xd9fc19527c87a51eUL,
+-		  0xbdaacb805831ca6fUL, 0x445b652dc916694fUL,
+-	/*  71 */ 0xce92a3a7f2172315UL, 0x1edc282de11b9964UL,
+-		  0xa1823aafe04c314aUL, 0x790a2d94437cf586UL,
+-	/*  72 */ 0x71c447fb93f6e009UL, 0x8922a56722845276UL,
+-		  0xbf70903b204f5169UL, 0x2f7a89891ba319feUL,
+-	/*  73 */ 0x02a08eb577e2140cUL, 0xed9a4ed4427bdcf4UL,
+-		  0x5253ec44e4323cd1UL, 0x3e88363c14e9355bUL,
+-	/*  74 */ 0xaa66c14277110b8cUL, 0x1ae0391610a23390UL,
+-		  0x2030bd12c93fc2a2UL, 0x3ee141579555c7abUL,
+-	/*  75 */ 0x9214de3a6d6e7d41UL, 0x3ccdd88607f17efeUL,
+-		  0x674f1288f8e11217UL, 0x5682250f329f93d0UL,
+-	/*  76 */ 0x6cf00b136d2e396eUL, 0x6e4cf86f1014debfUL,
+-		  0x5930b1b5bfcc4e83UL, 0x047069b48aba16b6UL,
+-	/*  77 */ 0x0d4ce4ab69b20793UL, 0xb24db91a97d0fb9eUL,
+-		  0xcdfa50f54e00d01dUL, 0x221b1085368bddb5UL,
+-	/*  78 */ 0xe7e59468b1e3d8d2UL, 0x53c56563bd122f93UL,
+-		  0xeee8a903e0663f09UL, 0x61efa662cbbe3d42UL,
+-	/*  79 */ 0x2cf8ddddde6eab2aUL, 0x9bf80ad51435f231UL,
+-		  0x5deadacec9f04973UL, 0x29275b5d41d29b27UL,
+-	/*  80 */ 0xcfde0f0895ebf14fUL, 0xb9aab96b054905a7UL,
+-		  0xcae80dd9a1c420fdUL, 0x0a63bf2f1673bbc7UL,
+-	/*  81 */ 0x092f6e11958fbc8cUL, 0x672a81e804822fadUL,
+-		  0xcac8351560d52517UL, 0x6f3f7722c8f192f8UL,
+-	/*  82 */ 0xf8ba90ccc2e894b7UL, 0x2c7557a438ff9f0dUL,
+-		  0x894d1d855ae52359UL, 0x68e122157b743d69UL,
+-	/*  83 */ 0xd87e5570cfb919f3UL, 0x3f2cdecd95798db9UL,
+-		  0x2121154710c0a2ceUL, 0x3c66a115246dc5b2UL,
+-	/*  84 */ 0xcbedc562294ecb72UL, 0xba7143c36a280b16UL,
+-		  0x9610c2efd4078b67UL, 0x6144735d946a4b1eUL,
+-	/*  85 */ 0x536f111ed75b3350UL, 0x0211db8c2041d81bUL,
+-		  0xf93cb1000e10413cUL, 0x149dfd3c039e8876UL,
+-	/*  86 */ 0xd479dde46b63155bUL, 0xb66e15e93c837976UL,
+-		  0xdafde43b1f13e038UL, 0x5fafda1a2e4b0b35UL,
+-	/*  87 */ 0x3600bbdf17197581UL, 0x3972050bbe3cd2c2UL,
+-		  0x5938906dbdd5be86UL, 0x34fce5e43f9b860fUL,
+-	/*  88 */ 0x75a8a4cd42d14d02UL, 0x828dabc53441df65UL,
+-		  0x33dcabedd2e131d3UL, 0x3ebad76fb814d25fUL,
+-	/*  89 */ 0xd4906f566f70e10fUL, 0x5d12f7aa51690f5aUL,
+-		  0x45adb16e76cefcf2UL, 0x01f768aead232999UL,
+-	/*  90 */ 0x2b6cc77b6248febdUL, 0x3cd30628ec3aaffdUL,
+-		  0xce1c0b80d4ef486aUL, 0x4c3bff2ea6f66c23UL,
+-	/*  91 */ 0x3f2ec4094aeaeb5fUL, 0x61b19b286e372ca7UL,
+-		  0x5eefa966de2a701dUL, 0x23b20565de55e3efUL,
+-	/*  92 */ 0xe301ca5279d58557UL, 0x07b2d4ce27c2874fUL,
+-		  0xa532cd8a9dcf1d67UL, 0x2a52fee23f2bff56UL,
+-	/*  93 */ 0x8624efb37cd8663dUL, 0xbbc7ac20ffbd7594UL,
+-		  0x57b85e9c82d37445UL, 0x7b3052cb86a6ec66UL,
+-	/*  94 */ 0x3482f0ad2525e91eUL, 0x2cb68043d28edca0UL,
+-		  0xaf4f6d052e1b003aUL, 0x185f8c2529781b0aUL,
+-	/*  95 */ 0xaa41de5bd80ce0d6UL, 0x9407b2416853e9d6UL,
+-		  0x563ec36e357f4c3aUL, 0x4cc4b8dd0e297bceUL,
+-	/*  96 */ 0xa2fc1a52ffb8730eUL, 0x1811f16e67058e37UL,
+-		  0x10f9a366cddf4ee1UL, 0x72f4a0c4a0b9f099UL,
+-	/*  97 */ 0x8c16c06f663f4ea7UL, 0x693b3af74e970fbaUL,
+-		  0x2102e7f1d69ec345UL, 0x0ba53cbc968a8089UL,
+-	/*  98 */ 0xca3d9dc7fea15537UL, 0x4c6824bb51536493UL,
+-		  0xb9886314844006b1UL, 0x40d2a72ab454cc60UL,
+-	/*  99 */ 0x5936a1b712570975UL, 0x91b9d648debda657UL,
+-		  0x3344094bb64330eaUL, 0x006ba10d12ee51d0UL,
+-	/* 100 */ 0x19228468f5de5d58UL, 0x0eb12f4c38cc05b0UL,
+-		  0xa1039f9dd5601990UL, 0x4502d4ce4fff0e0bUL,
+-	/* 101 */ 0xeb2054106837c189UL, 0xd0f6544c6dd3b93cUL,
+-		  0x40727064c416d74fUL, 0x6e15c6114b502ef0UL,
+-	/* 102 */ 0x4df2a398cfb1a76bUL, 0x11256c7419f2f6b1UL,
+-		  0x4a497962066e6043UL, 0x705b3aab41355b44UL,
+-	/* 103 */ 0x365ef536d797b1d8UL, 0x00076bd622ddf0dbUL,
+-		  0x3bbf33b0e0575a88UL, 0x3777aa05c8e4ca4dUL,
+-	/* 104 */ 0x392745c85578db5fUL, 0x6fda4149dbae5ae2UL,
+-		  0xb1f0b00b8adc9867UL, 0x09963437d36f1da3UL,
+-	/* 105 */ 0x7e824e90a5dc3853UL, 0xccb5f6641f135cbdUL,
+-		  0x6736d86c87ce8fccUL, 0x625f3ce26604249fUL,
+-	/* 106 */ 0xaf8ac8059502f63fUL, 0x0c05e70a2e351469UL,
+-		  0x35292e9c764b6305UL, 0x1a394360c7e23ac3UL,
+-	/* 107 */ 0xd5c6d53251183264UL, 0x62065abd43c2b74fUL,
+-		  0xb5fbf5d03b973f9bUL, 0x13a3da3661206e5eUL,
+-	/* 108 */ 0xc6bd5837725d94e5UL, 0x18e30912205016c5UL,
+-		  0x2088ce1570033c68UL, 0x7fba1f495c837987UL,
+-	/* 109 */ 0x5a8c7423f2f9079dUL, 0x1735157b34023fc5UL,
+-		  0xe4f9b49ad2fab351UL, 0x6691ff72c878e33cUL,
+-	/* 110 */ 0x122c2adedc5eff3eUL, 0xf8dd4bf1d8956cf4UL,
+-		  0xeb86205d9e9e5bdaUL, 0x049b92b9d975c743UL,
+-	/* 111 */ 0xa5379730b0f6c05aUL, 0x72a0ffacc6f3a553UL,
+-		  0xb0032c34b20dcd6dUL, 0x470e9dbc88d5164aUL,
+-	/* 112 */ 0xb19cf10ca237c047UL, 0xb65466711f6c81a2UL,
+-		  0xb3321bd16dd80b43UL, 0x48c14f600c5fbe8eUL,
+-	/* 113 */ 0x66451c264aa6c803UL, 0xb66e3904a4fa7da6UL,
+-		  0xd45f19b0b3128395UL, 0x31602627c3c9bc10UL,
+-	/* 114 */ 0x3120dc4832e4e10dUL, 0xeb20c46756c717f7UL,
+-		  0x00f52e3f67280294UL, 0x566d4fc14730c509UL,
+-	/* 115 */ 0x7e3a5d40fd837206UL, 0xc1e926dc7159547aUL,
+-		  0x216730fba68d6095UL, 0x22e8c3843f69cea7UL,
+-	/* 116 */ 0x33d074e8930e4b2bUL, 0xb6e4350e84d15816UL,
+-		  0x5534c26ad6ba2365UL, 0x7773c12f89f1f3f3UL,
+-	/* 117 */ 0x8cba404da57962aaUL, 0x5b9897a81999ce56UL,
+-		  0x508e862f121692fcUL, 0x3a81907fa093c291UL,
+-	/* 118 */ 0x0dded0ff4725a510UL, 0x10d8cc10673fc503UL,
+-		  0x5b9d151c9f1f4e89UL, 0x32a5c1d5cb09a44cUL,
+-	/* 119 */ 0x1e0aa442b90541fbUL, 0x5f85eb7cc1b485dbUL,
+-		  0xbee595ce8a9df2e5UL, 0x25e496c722422236UL,
+-	/* 120 */ 0x5edf3c46cd0fe5b9UL, 0x34e75a7ed2a43388UL,
+-		  0xe488de11d761e352UL, 0x0e878a01a085545cUL,
+-	/* 121 */ 0xba493c77e021bb04UL, 0x2b4d1843c7df899aUL,
+-		  0x9ea37a487ae80d67UL, 0x67a9958011e41794UL,
+-	/* 122 */ 0x4b58051a6697b065UL, 0x47e33f7d8d6ba6d4UL,
+-		  0xbb4da8d483ca46c1UL, 0x68becaa181c2db0dUL,
+-	/* 123 */ 0x8d8980e90b989aa5UL, 0xf95eb14a2c93c99bUL,
+-		  0x51c6c7c4796e73a2UL, 0x6e228363b5efb569UL,
+-	/* 124 */ 0xc6bbc0b02dd624c8UL, 0x777eb47dec8170eeUL,
+-		  0x3cde15a004cfafa9UL, 0x1dc6bc087160bf9bUL,
+-	/* 125 */ 0x2e07e043eec34002UL, 0x18e9fc677a68dc7fUL,
+-		  0xd8da03188bd15b9aUL, 0x48fbc3bb00568253UL,
+-	/* 126 */ 0x57547d4cfb654ce1UL, 0xd3565b82a058e2adUL,
+-		  0xf63eaf0bbf154478UL, 0x47531ef114dfbb18UL,
+-	/* 127 */ 0xe1ec630a4278c587UL, 0x5507d546ca8e83f3UL,
+-		  0x85e135c63adc0c2bUL, 0x0aa7efa85682844eUL,
+-	/* 128 */ 0x72691ba8b3e1f615UL, 0x32b4e9701fbe3ffaUL,
+-		  0x97b6d92e39bb7868UL, 0x2cfe53dea02e39e8UL,
+-	/* 129 */ 0x687392cd85cd52b0UL, 0x27ff66c910e29831UL,
+-		  0x97134556a9832d06UL, 0x269bb0360a84f8a0UL,
+-	/* 130 */ 0x706e55457643f85cUL, 0x3734a48c9b597d1bUL,
+-		  0x7aee91e8c6efa472UL, 0x5cd6abc198a9d9e0UL,
+-	/* 131 */ 0x0e04de06cb3ce41aUL, 0xd8c6eb893402e138UL,
+-		  0x904659bb686e3772UL, 0x7215c371746ba8c8UL,
+-	/* 132 */ 0xfd12a97eeae4a2d9UL, 0x9514b7516394f2c5UL,
+-		  0x266fd5809208f294UL, 0x5c847085619a26b9UL,
+-	/* 133 */ 0x52985410fed694eaUL, 0x3c905b934a2ed254UL,
+-		  0x10bb47692d3be467UL, 0x063b3d2d69e5e9e1UL,
+-	/* 134 */ 0x472726eedda57debUL, 0xefb6c4ae10f41891UL,
+-		  0x2b1641917b307614UL, 0x117c554fc4f45b7cUL,
+-	/* 135 */ 0xc07cf3118f9d8812UL, 0x01dbd82050017939UL,
+-		  0xd7e803f4171b2827UL, 0x1015e87487d225eaUL,
+-	/* 136 */ 0xc58de3fed23acc4dUL, 0x50db91c294a7be2dUL,
+-		  0x0b94d43d1c9cf457UL, 0x6b1640fa6e37524aUL,
+-	/* 137 */ 0x692f346c5fda0d09UL, 0x200b1c59fa4d3151UL,
+-		  0xb8c46f760777a296UL, 0x4b38395f3ffdfbcfUL,
+-	/* 138 */ 0x18d25e00be54d671UL, 0x60d50582bec8aba6UL,
+-		  0x87ad8f263b78b982UL, 0x50fdf64e9cda0432UL,
+-	/* 139 */ 0x90f567aac578dcf0UL, 0xef1e9b0ef2a3133bUL,
+-		  0x0eebba9242d9de71UL, 0x15473c9bf03101c7UL,
+-	/* 140 */ 0x7c77e8ae56b78095UL, 0xb678e7666e6f078eUL,
+-		  0x2da0b9615348ba1fUL, 0x7cf931c1ff733f0bUL,
+-	/* 141 */ 0x26b357f50a0a366cUL, 0xe9708cf42b87d732UL,
+-		  0xc13aeea5f91cb2c0UL, 0x35d90c991143bb4cUL,
+-	/* 142 */ 0x47c1c404a9a0d9dcUL, 0x659e58451972d251UL,
+-		  0x3875a8c473b38c31UL, 0x1fbd9ed379561f24UL,
+-	/* 143 */ 0x11fabc6fd41ec28dUL, 0x7ef8dfe3cd2a2dcaUL,
+-		  0x72e73b5d8c404595UL, 0x6135fa4954b72f27UL,
+-	/* 144 */ 0xccfc32a2de24b69cUL, 0x3f55698c1f095d88UL,
+-		  0xbe3350ed5ac3f929UL, 0x5e9bf806ca477eebUL,
+-	/* 145 */ 0xe9ce8fb63c309f68UL, 0x5376f63565e1f9f4UL,
+-		  0xd1afcfb35a6393f1UL, 0x6632a1ede5623506UL,
+-	/* 146 */ 0x0b7d6c390c2ded4cUL, 0x56cb3281df04cb1fUL,
+-		  0x66305a1249ecc3c7UL, 0x5d588b60a38ca72aUL,
+-	/* 147 */ 0xa6ecbf78e8e5f42dUL, 0x86eeb44b3c8a3eecUL,
+-		  0xec219c48fbd21604UL, 0x1aaf1af517c36731UL,
+-	/* 148 */ 0xc306a2836769bde7UL, 0x208280622b1e2adbUL,
+-		  0x8027f51ffbff94a6UL, 0x76cfa1ce1124f26bUL,
+-	/* 149 */ 0x18eb00562422abb6UL, 0xf377c4d58f8c29c3UL,
+-		  0x4dbbc207f531561aUL, 0x0253b7f082128a27UL,
+-	/* 150 */ 0x3d1f091cb62c17e0UL, 0x4860e1abd64628a9UL,
+-		  0x52d17436309d4253UL, 0x356f97e13efae576UL,
+-	/* 151 */ 0xd351e11aa150535bUL, 0x3e6b45bb1dd878ccUL,
+-		  0x0c776128bed92c98UL, 0x1d34ae93032885b8UL,
+-	/* 152 */ 0x4ba0488ca85ba4c3UL, 0x985348c33c9ce6ceUL,
+-		  0x66124c6f97bda770UL, 0x0f81a0290654124aUL,
+-	/* 153 */ 0x9ed09ca6569b86fdUL, 0x811009fd18af9a2dUL,
+-		  0xff08d03f93d8c20aUL, 0x52a148199faef26bUL,
+-	/* 154 */ 0x3e03f9dc2d8d1b73UL, 0x4205801873961a70UL,
+-		  0xc0d987f041a35970UL, 0x07aa1f15a1c0d549UL,
+-	/* 155 */ 0xdfd46ce08cd27224UL, 0x6d0a024f934e4239UL,
+-		  0x808a7a6399897b59UL, 0x0a4556e9e13d95a2UL,
+-	/* 156 */ 0xd21a991fe9c13045UL, 0x9b0e8548fe7751b8UL,
+-		  0x5da643cb4bf30035UL, 0x77db28d63940f721UL,
+-	/* 157 */ 0xfc5eeb614adc9011UL, 0x5229419ae8c411ebUL,
+-		  0x9ec3e7787d1dcf74UL, 0x340d053e216e4cb5UL,
+-	/* 158 */ 0xcac7af39b48df2b4UL, 0xc0faec2871a10a94UL,
+-		  0x140a69245ca575edUL, 0x0cf1c37134273a4cUL,
+-	/* 159 */ 0xc8ee306ac224b8a5UL, 0x57eaee7ccb4930b0UL,
+-		  0xa1e806bdaacbe74fUL, 0x7d9a62742eeb657dUL,
+-	/* 160 */ 0x9eb6b6ef546c4830UL, 0x885cca1fddb36e2eUL,
+-		  0xe6b9f383ef0d7105UL, 0x58654fef9d2e0412UL,
+-	/* 161 */ 0xa905c4ffbe0e8e26UL, 0x942de5df9b31816eUL,
+-		  0x497d723f802e88e1UL, 0x30684dea602f408dUL,
+-	/* 162 */ 0x21e5a278a3e6cb34UL, 0xaefb6e6f5b151dc4UL,
+-		  0xb30b8e049d77ca15UL, 0x28c3c9cf53b98981UL,
+-	/* 163 */ 0x287fb721556cdd2aUL, 0x0d317ca897022274UL,
+-		  0x7468c7423a543258UL, 0x4a7f11464eb5642fUL,
+-	/* 164 */ 0xa237a4774d193aa6UL, 0xd865986ea92129a1UL,
+-		  0x24c515ecf87c1a88UL, 0x604003575f39f5ebUL,
+-	/* 165 */ 0x47b9f189570a9b27UL, 0x2b98cede465e4b78UL,
+-		  0x026df551dbb85c20UL, 0x74fcd91047e21901UL,
+-	/* 166 */ 0x13e2a90a23c1bfa3UL, 0x0cb0074e478519f6UL,
+-		  0x5ff1cbbe3af6cf44UL, 0x67fe5438be812dbeUL,
+-	/* 167 */ 0xd13cf64fa40f05b0UL, 0x054dfb2f32283787UL,
+-		  0x4173915b7f0d2aeaUL, 0x482f144f1f610d4eUL,
+-	/* 168 */ 0xf6210201b47f8234UL, 0x5d0ae1929e70b990UL,
+-		  0xdcd7f455b049567cUL, 0x7e93d0f1f0916f01UL,
+-	/* 169 */ 0xdd79cbf18a7db4faUL, 0xbe8391bf6f74c62fUL,
+-		  0x027145d14b8291bdUL, 0x585a73ea2cbf1705UL,
+-	/* 170 */ 0x485ca03e928a0db2UL, 0x10fc01a5742857e7UL,
+-		  0x2f482edbd6d551a7UL, 0x0f0433b5048fdb8aUL,
+-	/* 171 */ 0x60da2e8dd7dc6247UL, 0x88b4c9d38cd4819aUL,
+-		  0x13033ac001f66697UL, 0x273b24fe3b367d75UL,
+-	/* 172 */ 0xc6e8f66a31b3b9d4UL, 0x281514a494df49d5UL,
+-		  0xd1726fdfc8b23da7UL, 0x4b3ae7d103dee548UL,
+-	/* 173 */ 0xc6256e19ce4b9d7eUL, 0xff5c5cf186e3c61cUL,
+-		  0xacc63ca34b8ec145UL, 0x74621888fee66574UL,
+-	/* 174 */ 0x956f409645290a1eUL, 0xef0bf8e3263a962eUL,
+-		  0xed6a50eb5ec2647bUL, 0x0694283a9dca7502UL,
+-	/* 175 */ 0x769b963643a2dcd1UL, 0x42b7c8ea09fc5353UL,
+-		  0x4f002aee13397eabUL, 0x63005e2c19b7d63aUL,
+-	/* 176 */ 0xca6736da63023beaUL, 0x966c7f6db12a99b7UL,
+-		  0xace09390c537c5e1UL, 0x0b696063a1aa89eeUL,
+-	/* 177 */ 0xebb03e97288c56e5UL, 0x432a9f9f938c8be8UL,
+-		  0xa6a5a93d5b717f71UL, 0x1a5fb4c3e18f9d97UL,
+-	/* 178 */ 0x1c94e7ad1c60cdceUL, 0xee202a43fc02c4a0UL,
+-		  0x8dafe4d867c46a20UL, 0x0a10263c8ac27b58UL,
+-	/* 179 */ 0xd0dea9dfe4432a4aUL, 0x856af87bbe9277c5UL,
+-		  0xce8472acc212c71aUL, 0x6f151b6d9bbb1e91UL,
+-	/* 180 */ 0x26776c527ceed56aUL, 0x7d211cb7fbf8faecUL,
+-		  0x37ae66a6fd4609ccUL, 0x1f81b702d2770c42UL,
+-	/* 181 */ 0x2fb0b057eac58392UL, 0xe1dd89fe29744e9dUL,
+-		  0xc964f8eb17beb4f8UL, 0x29571073c9a2d41eUL,
+-	/* 182 */ 0xa948a18981c0e254UL, 0x2df6369b65b22830UL,
+-		  0xa33eb2d75fcfd3c6UL, 0x078cd6ec4199a01fUL,
+-	/* 183 */ 0x4a584a41ad900d2fUL, 0x32142b78e2c74c52UL,
+-		  0x68c4e8338431c978UL, 0x7f69ea9008689fc2UL,
+-	/* 184 */ 0x52f2c81e46a38265UL, 0xfd78072d04a832fdUL,
+-		  0x8cd7d5fa25359e94UL, 0x4de71b7454cc29d2UL,
+-	/* 185 */ 0x42eb60ad1eda6ac9UL, 0x0aad37dfdbc09c3aUL,
+-		  0x81004b71e33cc191UL, 0x44e6be345122803cUL,
+-	/* 186 */ 0x03fe8388ba1920dbUL, 0xf5d57c32150db008UL,
+-		  0x49c8c4281af60c29UL, 0x21edb518de701aeeUL,
+-	/* 187 */ 0x7fb63e418f06dc99UL, 0xa4460d99c166d7b8UL,
+-		  0x24dd5248ce520a83UL, 0x5ec3ad712b928358UL,
+-	/* 188 */ 0x15022a5fbd17930fUL, 0xa4f64a77d82570e3UL,
+-		  0x12bc8d6915783712UL, 0x498194c0fc620abbUL,
+-	/* 189 */ 0x38a2d9d255686c82UL, 0x785c6bd9193e21f0UL,
+-		  0xe4d5c81ab24a5484UL, 0x56307860b2e20989UL,
+-	/* 190 */ 0x429d55f78b4d74c4UL, 0x22f1834643350131UL,
+-		  0x1e60c24598c71fffUL, 0x59f2f014979983efUL,
+-	/* 191 */ 0x46a47d56eb494a44UL, 0x3e22a854d636a18eUL,
+-		  0xb346e15274491c3bUL, 0x2ceafd4e5390cde7UL,
+-	/* 192 */ 0xba8a8538be0d6675UL, 0x4b9074bb50818e23UL,
+-		  0xcbdab89085d304c3UL, 0x61a24fe0e56192c4UL,
+-	/* 193 */ 0xcb7615e6db525bcbUL, 0xdd7d8c35a567e4caUL,
+-		  0xe6b4153acafcdd69UL, 0x2d668e097f3c9766UL,
+-	/* 194 */ 0xa57e7e265ce55ef0UL, 0x5d9f4e527cd4b967UL,
+-		  0xfbc83606492fd1e5UL, 0x090d52beb7c3f7aeUL,
+-	/* 195 */ 0x09b9515a1e7b4d7cUL, 0x1f266a2599da44c0UL,
+-		  0xa1c49548e2c55504UL, 0x7ef04287126f15ccUL,
+-	/* 196 */ 0xfed1659dbd30ef15UL, 0x8b4ab9eec4e0277bUL,
+-		  0x884d6236a5df3291UL, 0x1fd96ea6bf5cf788UL,
+-	/* 197 */ 0x42a161981f190d9aUL, 0x61d849507e6052c1UL,
+-		  0x9fe113bf285a2cd5UL, 0x7c22d676dbad85d8UL,
+-	/* 198 */ 0x82e770ed2bfbd27dUL, 0x4c05b2ece996f5a5UL,
+-		  0xcd40a9c2b0900150UL, 0x5895319213d9bf64UL,
+-	/* 199 */ 0xe7cc5d703fea2e08UL, 0xb50c491258e2188cUL,
+-		  0xcce30baa48205bf0UL, 0x537c659ccfa32d62UL,
+-	/* 200 */ 0x37b6623a98cfc088UL, 0xfe9bed1fa4d6aca4UL,
+-		  0x04d29b8e56a8d1b0UL, 0x725f71c40b519575UL,
+-	/* 201 */ 0x28c7f89cd0339ce6UL, 0x8367b14469ddc18bUL,
+-		  0x883ada83a6a1652cUL, 0x585f1974034d6c17UL,
+-	/* 202 */ 0x89cfb266f1b19188UL, 0xe63b4863e7c35217UL,
+-		  0xd88c9da6b4c0526aUL, 0x3e035c9df0954635UL,
+-	/* 203 */ 0xdd9d5412fb45de9dUL, 0xdd684532e4cff40dUL,
+-		  0x4b5c999b151d671cUL, 0x2d8c2cc811e7f690UL,
+-	/* 204 */ 0x7f54be1d90055d40UL, 0xa464c5df464aaf40UL,
+-		  0x33979624f0e917beUL, 0x2c018dc527356b30UL,
+-	/* 205 */ 0xa5415024e330b3d4UL, 0x73ff3d96691652d3UL,
+-		  0x94ec42c4ef9b59f1UL, 0x0747201618d08e5aUL,
+-	/* 206 */ 0x4d6ca48aca411c53UL, 0x66415f2fcfa66119UL,
+-		  0x9c4dd40051e227ffUL, 0x59810bc09a02f7ebUL,
+-	/* 207 */ 0x2a7eb171b3dc101dUL, 0x441c5ab99ffef68eUL,
+-		  0x32025c9b93b359eaUL, 0x5e8ce0a71e9d112fUL,
+-	/* 208 */ 0xbfcccb92429503fdUL, 0xd271ba752f095d55UL,
+-		  0x345ead5e972d091eUL, 0x18c8df11a83103baUL,
+-	/* 209 */ 0x90cd949a9aed0f4cUL, 0xc5d1f4cb6660e37eUL,
+-		  0xb8cac52d56c52e0bUL, 0x6e42e400c5808e0dUL,
+-	/* 210 */ 0xa3b46966eeaefd23UL, 0x0c4f1f0be39ecdcaUL,
+-		  0x189dc8c9d683a51dUL, 0x51f27f054c09351bUL,
+-	/* 211 */ 0x4c487ccd2a320682UL, 0x587ea95bb3df1c96UL,
+-		  0xc8ccf79e555cb8e8UL, 0x547dc829a206d73dUL,
+-	/* 212 */ 0xb822a6cd80c39b06UL, 0xe96d54732000d4c6UL,
+-		  0x28535b6f91463b4dUL, 0x228f4660e2486e1dUL,
+-	/* 213 */ 0x98799538de8d3abfUL, 0x8cd8330045ebca6eUL,
+-		  0x79952a008221e738UL, 0x4322e1a7535cd2bbUL,
+-	/* 214 */ 0xb114c11819d1801cUL, 0x2016e4d84f3f5ec7UL,
+-		  0xdd0e2df409260f4cUL, 0x5ec362c0ae5f7266UL,
+-	/* 215 */ 0xc0462b18b8b2b4eeUL, 0x7cc8d950274d1afbUL,
+-		  0xf25f7105436b02d2UL, 0x43bbf8dcbff9ccd3UL,
+-	/* 216 */ 0xb6ad1767a039e9dfUL, 0xb0714da8f69d3583UL,
+-		  0x5e55fa18b42931f5UL, 0x4ed5558f33c60961UL,
+-	/* 217 */ 0x1fe37901c647a5ddUL, 0x593ddf1f8081d357UL,
+-		  0x0249a4fd813fd7a6UL, 0x69acca274e9caf61UL,
+-	/* 218 */ 0x047ba3ea330721c9UL, 0x83423fc20e7e1ea0UL,
+-		  0x1df4c0af01314a60UL, 0x09a62dab89289527UL,
+-	/* 219 */ 0xa5b325a49cc6cb00UL, 0xe94b5dc654b56cb6UL,
+-		  0x3be28779adc994a0UL, 0x4296e8f8ba3a4aadUL,
+-	/* 220 */ 0x328689761e451eabUL, 0x2e4d598bff59594aUL,
+-		  0x49b96853d7a7084aUL, 0x4980a319601420a8UL,
+-	/* 221 */ 0x9565b9e12f552c42UL, 0x8a5318db7100fe96UL,
+-		  0x05c90b4d43add0d7UL, 0x538b4cd66a5d4edaUL,
+-	/* 222 */ 0xf4e94fc3e89f039fUL, 0x592c9af26f618045UL,
+-		  0x08a36eb5fd4b9550UL, 0x25fffaf6c2ed1419UL,
+-	/* 223 */ 0x34434459cc79d354UL, 0xeeecbfb4b1d5476bUL,
+-		  0xddeb34a061615d99UL, 0x5129cecceb64b773UL,
+-	/* 224 */ 0xee43215894993520UL, 0x772f9c7cf14c0b3bUL,
+-		  0xd2e2fce306bedad5UL, 0x715f42b546f06a97UL,
+-	/* 225 */ 0x434ecdceda5b5f1aUL, 0x0da17115a49741a9UL,
+-		  0x680bd77c73edad2eUL, 0x487c02354edd9041UL,
+-	/* 226 */ 0xb8efeff3a70ed9c4UL, 0x56a32aa3e857e302UL,
+-		  0xdf3a68bd48a2a5a0UL, 0x07f650b73176c444UL,
+-	/* 227 */ 0xe38b9b1626e0ccb1UL, 0x79e053c18b09fb36UL,
+-		  0x56d90319c9f94964UL, 0x1ca941e7ac9ff5c4UL,
+-	/* 228 */ 0x49c4df29162fa0bbUL, 0x8488cf3282b33305UL,
+-		  0x95dfda14cabb437dUL, 0x3391f78264d5ad86UL,
+-	/* 229 */ 0x729ae06ae2b5095dUL, 0xd58a58d73259a946UL,
+-		  0xe9834262d13921edUL, 0x27fedafaa54bb592UL,
+-	/* 230 */ 0xa99dc5b829ad48bbUL, 0x5f025742499ee260UL,
+-		  0x802c8ecd5d7513fdUL, 0x78ceb3ef3f6dd938UL,
+-	/* 231 */ 0xc342f44f8a135d94UL, 0x7b9edb44828cdda3UL,
+-		  0x9436d11a0537cfe7UL, 0x5064b164ec1ab4c8UL,
+-	/* 232 */ 0x7020eccfd37eb2fcUL, 0x1f31ea3ed90d25fcUL,
+-		  0x1b930d7bdfa1bb34UL, 0x5344467a48113044UL,
+-	/* 233 */ 0x70073170f25e6dfbUL, 0xe385dc1a50114cc8UL,
+-		  0x2348698ac8fc4f00UL, 0x2a77a55284dd40d8UL,
+-	/* 234 */ 0xfe06afe0c98c6ce4UL, 0xc235df96dddfd6e4UL,
+-		  0x1428d01e33bf1ed3UL, 0x785768ec9300bdafUL,
+-	/* 235 */ 0x9702e57a91deb63bUL, 0x61bdb8bfe5ce8b80UL,
+-		  0x645b426f3d1d58acUL, 0x4804a82227a557bcUL,
+-	/* 236 */ 0x8e57048ab44d2601UL, 0x68d6501a4b3a6935UL,
+-		  0xc39c9ec3f9e1c293UL, 0x4172f257d4de63e2UL,
+-	/* 237 */ 0xd368b450330c6401UL, 0x040d3017418f2391UL,
+-		  0x2c34bb6090b7d90dUL, 0x16f649228fdfd51fUL,
+-	/* 238 */ 0xbea6818e2b928ef5UL, 0xe28ccf91cdc11e72UL,
+-		  0x594aaa68e77a36cdUL, 0x313034806c7ffd0fUL,
+-	/* 239 */ 0x8a9d27ac2249bd65UL, 0x19a3b464018e9512UL,
+-		  0xc26ccff352b37ec7UL, 0x056f68341d797b21UL,
+-	/* 240 */ 0x5e79d6757efd2327UL, 0xfabdbcb6553afe15UL,
+-		  0xd3e7222c6eaf5a60UL, 0x7046c76d4dae743bUL,
+-	/* 241 */ 0x660be872b18d4a55UL, 0x19992518574e1496UL,
+-		  0xc103053a302bdcbbUL, 0x3ed8e9800b218e8eUL,
+-	/* 242 */ 0x7b0b9239fa75e03eUL, 0xefe9fb684633c083UL,
+-		  0x98a35fbe391a7793UL, 0x6065510fe2d0fe34UL,
+-	/* 243 */ 0x55cb668548abad0cUL, 0xb4584548da87e527UL,
+-		  0x2c43ecea0107c1ddUL, 0x526028809372de35UL,
+-	/* 244 */ 0x3415c56af9213b1fUL, 0x5bee1a4d017e98dbUL,
+-		  0x13f6b105b5cf709bUL, 0x5ff20e3482b29ab6UL,
+-	/* 245 */ 0x0aa29c75cc2e6c90UL, 0xfc7d73ca3a70e206UL,
+-		  0x899fc38fc4b5c515UL, 0x250386b124ffc207UL,
+-	/* 246 */ 0x54ea28d5ae3d2b56UL, 0x9913149dd6de60ceUL,
+-		  0x16694fc58f06d6c1UL, 0x46b23975eb018fc7UL,
+-	/* 247 */ 0x470a6a0fb4b7b4e2UL, 0x5d92475a8f7253deUL,
+-		  0xabeee5b52fbd3adbUL, 0x7fa20801a0806968UL,
+-	/* 248 */ 0x76f3faf19f7714d2UL, 0xb3e840c12f4660c3UL,
+-		  0x0fb4cd8df212744eUL, 0x4b065a251d3a2dd2UL,
+-	/* 249 */ 0x5cebde383d77cd4aUL, 0x6adf39df882c9cb1UL,
+-		  0xa2dd242eb09af759UL, 0x3147c0e50e5f6422UL,
+-	/* 250 */ 0x164ca5101d1350dbUL, 0xf8d13479c33fc962UL,
+-		  0xe640ce4d13e5da08UL, 0x4bdee0c45061f8baUL,
+-	/* 251 */ 0xd7c46dc1a4edb1c9UL, 0x5514d7b6437fd98aUL,
+-		  0x58942f6bb2a1c00bUL, 0x2dffb2ab1d70710eUL,
+-	/* 252 */ 0xccdfcf2fc18b6d68UL, 0xa8ebcba8b7806167UL,
+-		  0x980697f95e2937e3UL, 0x02fbba1cd0126e8cUL
+-};
+-
+-/* c is two 512-bit products: c0[0:7]=a0[0:3]*b0[0:3] and c1[8:15]=a1[4:7]*b1[4:7]
+- * a is two 256-bit integers: a0[0:3] and a1[4:7]
+- * b is two 256-bit integers: b0[0:3] and b1[4:7]
+- */
+-static void mul2_256x256_integer_adx(u64 *const c, const u64 *const a,
+-				     const u64 *const b)
+-{
+-	asm volatile(
+-		"xorl %%r14d, %%r14d ;"
+-		"movq   (%1), %%rdx; "	/* A[0] */
+-		"mulx   (%2),  %%r8, %%r15; " /* A[0]*B[0] */
+-		"xorl %%r10d, %%r10d ;"
+-		"movq %%r8, (%0) ;"
+-		"mulx  8(%2), %%r10, %%rax; " /* A[0]*B[1] */
+-		"adox %%r10, %%r15 ;"
+-		"mulx 16(%2),  %%r8, %%rbx; " /* A[0]*B[2] */
+-		"adox  %%r8, %%rax ;"
+-		"mulx 24(%2), %%r10, %%rcx; " /* A[0]*B[3] */
+-		"adox %%r10, %%rbx ;"
+-		/******************************************/
+-		"adox %%r14, %%rcx ;"
+-
+-		"movq  8(%1), %%rdx; "	/* A[1] */
+-		"mulx   (%2),  %%r8,  %%r9; " /* A[1]*B[0] */
+-		"adox %%r15,  %%r8 ;"
+-		"movq  %%r8, 8(%0) ;"
+-		"mulx  8(%2), %%r10, %%r11; " /* A[1]*B[1] */
+-		"adox %%r10,  %%r9 ;"
+-		"adcx  %%r9, %%rax ;"
+-		"mulx 16(%2),  %%r8, %%r13; " /* A[1]*B[2] */
+-		"adox  %%r8, %%r11 ;"
+-		"adcx %%r11, %%rbx ;"
+-		"mulx 24(%2), %%r10, %%r15; " /* A[1]*B[3] */
+-		"adox %%r10, %%r13 ;"
+-		"adcx %%r13, %%rcx ;"
+-		/******************************************/
+-		"adox %%r14, %%r15 ;"
+-		"adcx %%r14, %%r15 ;"
+-
+-		"movq 16(%1), %%rdx; " /* A[2] */
+-		"xorl %%r10d, %%r10d ;"
+-		"mulx   (%2),  %%r8,  %%r9; " /* A[2]*B[0] */
+-		"adox %%rax,  %%r8 ;"
+-		"movq %%r8, 16(%0) ;"
+-		"mulx  8(%2), %%r10, %%r11; " /* A[2]*B[1] */
+-		"adox %%r10,  %%r9 ;"
+-		"adcx  %%r9, %%rbx ;"
+-		"mulx 16(%2),  %%r8, %%r13; " /* A[2]*B[2] */
+-		"adox  %%r8, %%r11 ;"
+-		"adcx %%r11, %%rcx ;"
+-		"mulx 24(%2), %%r10, %%rax; " /* A[2]*B[3] */
+-		"adox %%r10, %%r13 ;"
+-		"adcx %%r13, %%r15 ;"
+-		/******************************************/
+-		"adox %%r14, %%rax ;"
+-		"adcx %%r14, %%rax ;"
+-
+-		"movq 24(%1), %%rdx; " /* A[3] */
+-		"xorl %%r10d, %%r10d ;"
+-		"mulx   (%2),  %%r8,  %%r9; " /* A[3]*B[0] */
+-		"adox %%rbx,  %%r8 ;"
+-		"movq %%r8, 24(%0) ;"
+-		"mulx  8(%2), %%r10, %%r11; " /* A[3]*B[1] */
+-		"adox %%r10,  %%r9 ;"
+-		"adcx  %%r9, %%rcx ;"
+-		"movq %%rcx, 32(%0) ;"
+-		"mulx 16(%2),  %%r8, %%r13; " /* A[3]*B[2] */
+-		"adox  %%r8, %%r11 ;"
+-		"adcx %%r11, %%r15 ;"
+-		"movq %%r15, 40(%0) ;"
+-		"mulx 24(%2), %%r10, %%rbx; " /* A[3]*B[3] */
+-		"adox %%r10, %%r13 ;"
+-		"adcx %%r13, %%rax ;"
+-		"movq %%rax, 48(%0) ;"
+-		/******************************************/
+-		"adox %%r14, %%rbx ;"
+-		"adcx %%r14, %%rbx ;"
+-		"movq %%rbx, 56(%0) ;"
+-
+-		"movq 32(%1), %%rdx; "	/* C[0] */
+-		"mulx 32(%2),  %%r8, %%r15; " /* C[0]*D[0] */
+-		"xorl %%r10d, %%r10d ;"
+-		"movq %%r8, 64(%0);"
+-		"mulx 40(%2), %%r10, %%rax; " /* C[0]*D[1] */
+-		"adox %%r10, %%r15 ;"
+-		"mulx 48(%2),  %%r8, %%rbx; " /* C[0]*D[2] */
+-		"adox  %%r8, %%rax ;"
+-		"mulx 56(%2), %%r10, %%rcx; " /* C[0]*D[3] */
+-		"adox %%r10, %%rbx ;"
+-		/******************************************/
+-		"adox %%r14, %%rcx ;"
+-
+-		"movq 40(%1), %%rdx; " /* C[1] */
+-		"xorl %%r10d, %%r10d ;"
+-		"mulx 32(%2),  %%r8,  %%r9; " /* C[1]*D[0] */
+-		"adox %%r15,  %%r8 ;"
+-		"movq  %%r8, 72(%0);"
+-		"mulx 40(%2), %%r10, %%r11; " /* C[1]*D[1] */
+-		"adox %%r10,  %%r9 ;"
+-		"adcx  %%r9, %%rax ;"
+-		"mulx 48(%2),  %%r8, %%r13; " /* C[1]*D[2] */
+-		"adox  %%r8, %%r11 ;"
+-		"adcx %%r11, %%rbx ;"
+-		"mulx 56(%2), %%r10, %%r15; " /* C[1]*D[3] */
+-		"adox %%r10, %%r13 ;"
+-		"adcx %%r13, %%rcx ;"
+-		/******************************************/
+-		"adox %%r14, %%r15 ;"
+-		"adcx %%r14, %%r15 ;"
+-
+-		"movq 48(%1), %%rdx; " /* C[2] */
+-		"xorl %%r10d, %%r10d ;"
+-		"mulx 32(%2),  %%r8,  %%r9; " /* C[2]*D[0] */
+-		"adox %%rax,  %%r8 ;"
+-		"movq  %%r8, 80(%0);"
+-		"mulx 40(%2), %%r10, %%r11; " /* C[2]*D[1] */
+-		"adox %%r10,  %%r9 ;"
+-		"adcx  %%r9, %%rbx ;"
+-		"mulx 48(%2),  %%r8, %%r13; " /* C[2]*D[2] */
+-		"adox  %%r8, %%r11 ;"
+-		"adcx %%r11, %%rcx ;"
+-		"mulx 56(%2), %%r10, %%rax; " /* C[2]*D[3] */
+-		"adox %%r10, %%r13 ;"
+-		"adcx %%r13, %%r15 ;"
+-		/******************************************/
+-		"adox %%r14, %%rax ;"
+-		"adcx %%r14, %%rax ;"
+-
+-		"movq 56(%1), %%rdx; " /* C[3] */
+-		"xorl %%r10d, %%r10d ;"
+-		"mulx 32(%2),  %%r8,  %%r9; " /* C[3]*D[0] */
+-		"adox %%rbx,  %%r8 ;"
+-		"movq  %%r8, 88(%0);"
+-		"mulx 40(%2), %%r10, %%r11; " /* C[3]*D[1] */
+-		"adox %%r10,  %%r9 ;"
+-		"adcx  %%r9, %%rcx ;"
+-		"movq %%rcx,  96(%0) ;"
+-		"mulx 48(%2),  %%r8, %%r13; " /* C[3]*D[2] */
+-		"adox  %%r8, %%r11 ;"
+-		"adcx %%r11, %%r15 ;"
+-		"movq %%r15, 104(%0) ;"
+-		"mulx 56(%2), %%r10, %%rbx; " /* C[3]*D[3] */
+-		"adox %%r10, %%r13 ;"
+-		"adcx %%r13, %%rax ;"
+-		"movq %%rax, 112(%0) ;"
+-		/******************************************/
+-		"adox %%r14, %%rbx ;"
+-		"adcx %%r14, %%rbx ;"
+-		"movq %%rbx, 120(%0) ;"
+-		:
+-		: "r"(c), "r"(a), "r"(b)
+-		: "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9",
+-		  "%r10", "%r11", "%r13", "%r14", "%r15");
+-}
+-
+-static void mul2_256x256_integer_bmi2(u64 *const c, const u64 *const a,
+-				      const u64 *const b)
++static __always_inline u64 eq_mask(u64 a, u64 b)
+ {
+-	asm volatile(
+-		"movq   (%1), %%rdx; "	/* A[0] */
+-		"mulx   (%2),  %%r8, %%r15; " /* A[0]*B[0] */
+-		"movq %%r8,  (%0) ;"
+-		"mulx  8(%2), %%r10, %%rax; " /* A[0]*B[1] */
+-		"addq %%r10, %%r15 ;"
+-		"mulx 16(%2),  %%r8, %%rbx; " /* A[0]*B[2] */
+-		"adcq  %%r8, %%rax ;"
+-		"mulx 24(%2), %%r10, %%rcx; " /* A[0]*B[3] */
+-		"adcq %%r10, %%rbx ;"
+-		/******************************************/
+-		"adcq    $0, %%rcx ;"
+-
+-		"movq  8(%1), %%rdx; "	/* A[1] */
+-		"mulx   (%2),  %%r8,  %%r9; " /* A[1]*B[0] */
+-		"addq %%r15,  %%r8 ;"
+-		"movq %%r8, 8(%0) ;"
+-		"mulx  8(%2), %%r10, %%r11; " /* A[1]*B[1] */
+-		"adcq %%r10,  %%r9 ;"
+-		"mulx 16(%2),  %%r8, %%r13; " /* A[1]*B[2] */
+-		"adcq  %%r8, %%r11 ;"
+-		"mulx 24(%2), %%r10, %%r15; " /* A[1]*B[3] */
+-		"adcq %%r10, %%r13 ;"
+-		/******************************************/
+-		"adcq    $0, %%r15 ;"
+-
+-		"addq  %%r9, %%rax ;"
+-		"adcq %%r11, %%rbx ;"
+-		"adcq %%r13, %%rcx ;"
+-		"adcq    $0, %%r15 ;"
+-
+-		"movq 16(%1), %%rdx; "	/* A[2] */
+-		"mulx   (%2),  %%r8,  %%r9; " /* A[2]*B[0] */
+-		"addq %%rax,  %%r8 ;"
+-		"movq %%r8, 16(%0) ;"
+-		"mulx  8(%2), %%r10, %%r11; " /* A[2]*B[1] */
+-		"adcq %%r10,  %%r9 ;"
+-		"mulx 16(%2),  %%r8, %%r13; " /* A[2]*B[2] */
+-		"adcq  %%r8, %%r11 ;"
+-		"mulx 24(%2), %%r10, %%rax; " /* A[2]*B[3] */
+-		"adcq %%r10, %%r13 ;"
+-		/******************************************/
+-		"adcq    $0, %%rax ;"
+-
+-		"addq  %%r9, %%rbx ;"
+-		"adcq %%r11, %%rcx ;"
+-		"adcq %%r13, %%r15 ;"
+-		"adcq    $0, %%rax ;"
+-
+-		"movq 24(%1), %%rdx; "	/* A[3] */
+-		"mulx   (%2),  %%r8,  %%r9; " /* A[3]*B[0] */
+-		"addq %%rbx,  %%r8 ;"
+-		"movq %%r8, 24(%0) ;"
+-		"mulx  8(%2), %%r10, %%r11; " /* A[3]*B[1] */
+-		"adcq %%r10,  %%r9 ;"
+-		"mulx 16(%2),  %%r8, %%r13; " /* A[3]*B[2] */
+-		"adcq  %%r8, %%r11 ;"
+-		"mulx 24(%2), %%r10, %%rbx; " /* A[3]*B[3] */
+-		"adcq %%r10, %%r13 ;"
+-		/******************************************/
+-		"adcq    $0, %%rbx ;"
+-
+-		"addq  %%r9, %%rcx ;"
+-		"movq %%rcx, 32(%0) ;"
+-		"adcq %%r11, %%r15 ;"
+-		"movq %%r15, 40(%0) ;"
+-		"adcq %%r13, %%rax ;"
+-		"movq %%rax, 48(%0) ;"
+-		"adcq    $0, %%rbx ;"
+-		"movq %%rbx, 56(%0) ;"
+-
+-		"movq 32(%1), %%rdx; "	/* C[0] */
+-		"mulx 32(%2),  %%r8, %%r15; " /* C[0]*D[0] */
+-		"movq %%r8, 64(%0) ;"
+-		"mulx 40(%2), %%r10, %%rax; " /* C[0]*D[1] */
+-		"addq %%r10, %%r15 ;"
+-		"mulx 48(%2),  %%r8, %%rbx; " /* C[0]*D[2] */
+-		"adcq  %%r8, %%rax ;"
+-		"mulx 56(%2), %%r10, %%rcx; " /* C[0]*D[3] */
+-		"adcq %%r10, %%rbx ;"
+-		/******************************************/
+-		"adcq    $0, %%rcx ;"
+-
+-		"movq 40(%1), %%rdx; "	/* C[1] */
+-		"mulx 32(%2),  %%r8,  %%r9; " /* C[1]*D[0] */
+-		"addq %%r15,  %%r8 ;"
+-		"movq %%r8, 72(%0) ;"
+-		"mulx 40(%2), %%r10, %%r11; " /* C[1]*D[1] */
+-		"adcq %%r10,  %%r9 ;"
+-		"mulx 48(%2),  %%r8, %%r13; " /* C[1]*D[2] */
+-		"adcq  %%r8, %%r11 ;"
+-		"mulx 56(%2), %%r10, %%r15; " /* C[1]*D[3] */
+-		"adcq %%r10, %%r13 ;"
+-		/******************************************/
+-		"adcq    $0, %%r15 ;"
+-
+-		"addq  %%r9, %%rax ;"
+-		"adcq %%r11, %%rbx ;"
+-		"adcq %%r13, %%rcx ;"
+-		"adcq    $0, %%r15 ;"
+-
+-		"movq 48(%1), %%rdx; "	/* C[2] */
+-		"mulx 32(%2),  %%r8,  %%r9; " /* C[2]*D[0] */
+-		"addq %%rax,  %%r8 ;"
+-		"movq %%r8, 80(%0) ;"
+-		"mulx 40(%2), %%r10, %%r11; " /* C[2]*D[1] */
+-		"adcq %%r10,  %%r9 ;"
+-		"mulx 48(%2),  %%r8, %%r13; " /* C[2]*D[2] */
+-		"adcq  %%r8, %%r11 ;"
+-		"mulx 56(%2), %%r10, %%rax; " /* C[2]*D[3] */
+-		"adcq %%r10, %%r13 ;"
+-		/******************************************/
+-		"adcq    $0, %%rax ;"
+-
+-		"addq  %%r9, %%rbx ;"
+-		"adcq %%r11, %%rcx ;"
+-		"adcq %%r13, %%r15 ;"
+-		"adcq    $0, %%rax ;"
+-
+-		"movq 56(%1), %%rdx; "	/* C[3] */
+-		"mulx 32(%2),  %%r8,  %%r9; " /* C[3]*D[0] */
+-		"addq %%rbx,  %%r8 ;"
+-		"movq %%r8, 88(%0) ;"
+-		"mulx 40(%2), %%r10, %%r11; " /* C[3]*D[1] */
+-		"adcq %%r10,  %%r9 ;"
+-		"mulx 48(%2),  %%r8, %%r13; " /* C[3]*D[2] */
+-		"adcq  %%r8, %%r11 ;"
+-		"mulx 56(%2), %%r10, %%rbx; " /* C[3]*D[3] */
+-		"adcq %%r10, %%r13 ;"
+-		/******************************************/
+-		"adcq    $0, %%rbx ;"
+-
+-		"addq  %%r9, %%rcx ;"
+-		"movq %%rcx,  96(%0) ;"
+-		"adcq %%r11, %%r15 ;"
+-		"movq %%r15, 104(%0) ;"
+-		"adcq %%r13, %%rax ;"
+-		"movq %%rax, 112(%0) ;"
+-		"adcq    $0, %%rbx ;"
+-		"movq %%rbx, 120(%0) ;"
+-		:
+-		: "r"(c), "r"(a), "r"(b)
+-		: "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9",
+-		  "%r10", "%r11", "%r13", "%r15");
++	u64 x = a ^ b;
++	u64 minus_x = ~x + (u64)1U;
++	u64 x_or_minus_x = x | minus_x;
++	u64 xnx = x_or_minus_x >> (u32)63U;
++	return xnx - (u64)1U;
+ }
+ 
+-static void sqr2_256x256_integer_adx(u64 *const c, const u64 *const a)
++static __always_inline u64 gte_mask(u64 a, u64 b)
+ {
+-	asm volatile(
+-		"movq   (%1), %%rdx        ;" /* A[0]      */
+-		"mulx  8(%1),  %%r8, %%r14 ;" /* A[1]*A[0] */
+-		"xorl %%r15d, %%r15d;"
+-		"mulx 16(%1),  %%r9, %%r10 ;" /* A[2]*A[0] */
+-		"adcx %%r14,  %%r9 ;"
+-		"mulx 24(%1), %%rax, %%rcx ;" /* A[3]*A[0] */
+-		"adcx %%rax, %%r10 ;"
+-		"movq 24(%1), %%rdx        ;" /* A[3]      */
+-		"mulx  8(%1), %%r11, %%rbx ;" /* A[1]*A[3] */
+-		"adcx %%rcx, %%r11 ;"
+-		"mulx 16(%1), %%rax, %%r13 ;" /* A[2]*A[3] */
+-		"adcx %%rax, %%rbx ;"
+-		"movq  8(%1), %%rdx        ;" /* A[1]      */
+-		"adcx %%r15, %%r13 ;"
+-		"mulx 16(%1), %%rax, %%rcx ;" /* A[2]*A[1] */
+-		"movq    $0, %%r14 ;"
+-		/******************************************/
+-		"adcx %%r15, %%r14 ;"
+-
+-		"xorl %%r15d, %%r15d;"
+-		"adox %%rax, %%r10 ;"
+-		"adcx  %%r8,  %%r8 ;"
+-		"adox %%rcx, %%r11 ;"
+-		"adcx  %%r9,  %%r9 ;"
+-		"adox %%r15, %%rbx ;"
+-		"adcx %%r10, %%r10 ;"
+-		"adox %%r15, %%r13 ;"
+-		"adcx %%r11, %%r11 ;"
+-		"adox %%r15, %%r14 ;"
+-		"adcx %%rbx, %%rbx ;"
+-		"adcx %%r13, %%r13 ;"
+-		"adcx %%r14, %%r14 ;"
+-
+-		"movq   (%1), %%rdx ;"
+-		"mulx %%rdx, %%rax, %%rcx ;" /* A[0]^2 */
+-		/*******************/
+-		"movq %%rax,  0(%0) ;"
+-		"addq %%rcx,  %%r8 ;"
+-		"movq  %%r8,  8(%0) ;"
+-		"movq  8(%1), %%rdx ;"
+-		"mulx %%rdx, %%rax, %%rcx ;" /* A[1]^2 */
+-		"adcq %%rax,  %%r9 ;"
+-		"movq  %%r9, 16(%0) ;"
+-		"adcq %%rcx, %%r10 ;"
+-		"movq %%r10, 24(%0) ;"
+-		"movq 16(%1), %%rdx ;"
+-		"mulx %%rdx, %%rax, %%rcx ;" /* A[2]^2 */
+-		"adcq %%rax, %%r11 ;"
+-		"movq %%r11, 32(%0) ;"
+-		"adcq %%rcx, %%rbx ;"
+-		"movq %%rbx, 40(%0) ;"
+-		"movq 24(%1), %%rdx ;"
+-		"mulx %%rdx, %%rax, %%rcx ;" /* A[3]^2 */
+-		"adcq %%rax, %%r13 ;"
+-		"movq %%r13, 48(%0) ;"
+-		"adcq %%rcx, %%r14 ;"
+-		"movq %%r14, 56(%0) ;"
+-
+-
+-		"movq 32(%1), %%rdx        ;" /* B[0]      */
+-		"mulx 40(%1),  %%r8, %%r14 ;" /* B[1]*B[0] */
+-		"xorl %%r15d, %%r15d;"
+-		"mulx 48(%1),  %%r9, %%r10 ;" /* B[2]*B[0] */
+-		"adcx %%r14,  %%r9 ;"
+-		"mulx 56(%1), %%rax, %%rcx ;" /* B[3]*B[0] */
+-		"adcx %%rax, %%r10 ;"
+-		"movq 56(%1), %%rdx        ;" /* B[3]      */
+-		"mulx 40(%1), %%r11, %%rbx ;" /* B[1]*B[3] */
+-		"adcx %%rcx, %%r11 ;"
+-		"mulx 48(%1), %%rax, %%r13 ;" /* B[2]*B[3] */
+-		"adcx %%rax, %%rbx ;"
+-		"movq 40(%1), %%rdx        ;" /* B[1]      */
+-		"adcx %%r15, %%r13 ;"
+-		"mulx 48(%1), %%rax, %%rcx ;" /* B[2]*B[1] */
+-		"movq    $0, %%r14 ;"
+-		/******************************************/
+-		"adcx %%r15, %%r14 ;"
+-
+-		"xorl %%r15d, %%r15d;"
+-		"adox %%rax, %%r10 ;"
+-		"adcx  %%r8,  %%r8 ;"
+-		"adox %%rcx, %%r11 ;"
+-		"adcx  %%r9,  %%r9 ;"
+-		"adox %%r15, %%rbx ;"
+-		"adcx %%r10, %%r10 ;"
+-		"adox %%r15, %%r13 ;"
+-		"adcx %%r11, %%r11 ;"
+-		"adox %%r15, %%r14 ;"
+-		"adcx %%rbx, %%rbx ;"
+-		"adcx %%r13, %%r13 ;"
+-		"adcx %%r14, %%r14 ;"
+-
+-		"movq 32(%1), %%rdx ;"
+-		"mulx %%rdx, %%rax, %%rcx ;" /* B[0]^2 */
+-		/*******************/
+-		"movq %%rax,  64(%0) ;"
+-		"addq %%rcx,  %%r8 ;"
+-		"movq  %%r8,  72(%0) ;"
+-		"movq 40(%1), %%rdx ;"
+-		"mulx %%rdx, %%rax, %%rcx ;" /* B[1]^2 */
+-		"adcq %%rax,  %%r9 ;"
+-		"movq  %%r9,  80(%0) ;"
+-		"adcq %%rcx, %%r10 ;"
+-		"movq %%r10,  88(%0) ;"
+-		"movq 48(%1), %%rdx ;"
+-		"mulx %%rdx, %%rax, %%rcx ;" /* B[2]^2 */
+-		"adcq %%rax, %%r11 ;"
+-		"movq %%r11,  96(%0) ;"
+-		"adcq %%rcx, %%rbx ;"
+-		"movq %%rbx, 104(%0) ;"
+-		"movq 56(%1), %%rdx ;"
+-		"mulx %%rdx, %%rax, %%rcx ;" /* B[3]^2 */
+-		"adcq %%rax, %%r13 ;"
+-		"movq %%r13, 112(%0) ;"
+-		"adcq %%rcx, %%r14 ;"
+-		"movq %%r14, 120(%0) ;"
+-		:
+-		: "r"(c), "r"(a)
+-		: "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9",
+-		  "%r10", "%r11", "%r13", "%r14", "%r15");
++	u64 x = a;
++	u64 y = b;
++	u64 x_xor_y = x ^ y;
++	u64 x_sub_y = x - y;
++	u64 x_sub_y_xor_y = x_sub_y ^ y;
++	u64 q = x_xor_y | x_sub_y_xor_y;
++	u64 x_xor_q = x ^ q;
++	u64 x_xor_q_ = x_xor_q >> (u32)63U;
++	return x_xor_q_ - (u64)1U;
+ }
+ 
+-static void sqr2_256x256_integer_bmi2(u64 *const c, const u64 *const a)
++/* Computes the addition of four-element f1 with value in f2
++ * and returns the carry (if any) */
++static inline u64 add_scalar(u64 *out, const u64 *f1, u64 f2)
+ {
+-	asm volatile(
+-		"movq  8(%1), %%rdx        ;" /* A[1]      */
+-		"mulx   (%1),  %%r8,  %%r9 ;" /* A[0]*A[1] */
+-		"mulx 16(%1), %%r10, %%r11 ;" /* A[2]*A[1] */
+-		"mulx 24(%1), %%rcx, %%r14 ;" /* A[3]*A[1] */
+-
+-		"movq 16(%1), %%rdx        ;" /* A[2]      */
+-		"mulx 24(%1), %%r15, %%r13 ;" /* A[3]*A[2] */
+-		"mulx   (%1), %%rax, %%rdx ;" /* A[0]*A[2] */
+-
+-		"addq %%rax,  %%r9 ;"
+-		"adcq %%rdx, %%r10 ;"
+-		"adcq %%rcx, %%r11 ;"
+-		"adcq %%r14, %%r15 ;"
+-		"adcq    $0, %%r13 ;"
+-		"movq    $0, %%r14 ;"
+-		"adcq    $0, %%r14 ;"
+-
+-		"movq   (%1), %%rdx        ;" /* A[0]      */
+-		"mulx 24(%1), %%rax, %%rcx ;" /* A[0]*A[3] */
+-
+-		"addq %%rax, %%r10 ;"
+-		"adcq %%rcx, %%r11 ;"
+-		"adcq    $0, %%r15 ;"
+-		"adcq    $0, %%r13 ;"
+-		"adcq    $0, %%r14 ;"
+-
+-		"shldq $1, %%r13, %%r14 ;"
+-		"shldq $1, %%r15, %%r13 ;"
+-		"shldq $1, %%r11, %%r15 ;"
+-		"shldq $1, %%r10, %%r11 ;"
+-		"shldq $1,  %%r9, %%r10 ;"
+-		"shldq $1,  %%r8,  %%r9 ;"
+-		"shlq  $1,  %%r8        ;"
+-
+-		/*******************/
+-		"mulx %%rdx, %%rax, %%rcx ; " /* A[0]^2 */
+-		/*******************/
+-		"movq %%rax,  0(%0) ;"
+-		"addq %%rcx,  %%r8 ;"
+-		"movq  %%r8,  8(%0) ;"
+-		"movq  8(%1), %%rdx ;"
+-		"mulx %%rdx, %%rax, %%rcx ; " /* A[1]^2 */
+-		"adcq %%rax,  %%r9 ;"
+-		"movq  %%r9, 16(%0) ;"
+-		"adcq %%rcx, %%r10 ;"
+-		"movq %%r10, 24(%0) ;"
+-		"movq 16(%1), %%rdx ;"
+-		"mulx %%rdx, %%rax, %%rcx ; " /* A[2]^2 */
+-		"adcq %%rax, %%r11 ;"
+-		"movq %%r11, 32(%0) ;"
+-		"adcq %%rcx, %%r15 ;"
+-		"movq %%r15, 40(%0) ;"
+-		"movq 24(%1), %%rdx ;"
+-		"mulx %%rdx, %%rax, %%rcx ; " /* A[3]^2 */
+-		"adcq %%rax, %%r13 ;"
+-		"movq %%r13, 48(%0) ;"
+-		"adcq %%rcx, %%r14 ;"
+-		"movq %%r14, 56(%0) ;"
+-
+-		"movq 40(%1), %%rdx        ;" /* B[1]      */
+-		"mulx 32(%1),  %%r8,  %%r9 ;" /* B[0]*B[1] */
+-		"mulx 48(%1), %%r10, %%r11 ;" /* B[2]*B[1] */
+-		"mulx 56(%1), %%rcx, %%r14 ;" /* B[3]*B[1] */
+-
+-		"movq 48(%1), %%rdx        ;" /* B[2]      */
+-		"mulx 56(%1), %%r15, %%r13 ;" /* B[3]*B[2] */
+-		"mulx 32(%1), %%rax, %%rdx ;" /* B[0]*B[2] */
+-
+-		"addq %%rax,  %%r9 ;"
+-		"adcq %%rdx, %%r10 ;"
+-		"adcq %%rcx, %%r11 ;"
+-		"adcq %%r14, %%r15 ;"
+-		"adcq    $0, %%r13 ;"
+-		"movq    $0, %%r14 ;"
+-		"adcq    $0, %%r14 ;"
+-
+-		"movq 32(%1), %%rdx        ;" /* B[0]      */
+-		"mulx 56(%1), %%rax, %%rcx ;" /* B[0]*B[3] */
+-
+-		"addq %%rax, %%r10 ;"
+-		"adcq %%rcx, %%r11 ;"
+-		"adcq    $0, %%r15 ;"
+-		"adcq    $0, %%r13 ;"
+-		"adcq    $0, %%r14 ;"
+-
+-		"shldq $1, %%r13, %%r14 ;"
+-		"shldq $1, %%r15, %%r13 ;"
+-		"shldq $1, %%r11, %%r15 ;"
+-		"shldq $1, %%r10, %%r11 ;"
+-		"shldq $1,  %%r9, %%r10 ;"
+-		"shldq $1,  %%r8,  %%r9 ;"
+-		"shlq  $1,  %%r8        ;"
+-
+-		/*******************/
+-		"mulx %%rdx, %%rax, %%rcx ; " /* B[0]^2 */
+-		/*******************/
+-		"movq %%rax,  64(%0) ;"
+-		"addq %%rcx,  %%r8 ;"
+-		"movq  %%r8,  72(%0) ;"
+-		"movq 40(%1), %%rdx ;"
+-		"mulx %%rdx, %%rax, %%rcx ; " /* B[1]^2 */
+-		"adcq %%rax,  %%r9 ;"
+-		"movq  %%r9,  80(%0) ;"
+-		"adcq %%rcx, %%r10 ;"
+-		"movq %%r10,  88(%0) ;"
+-		"movq 48(%1), %%rdx ;"
+-		"mulx %%rdx, %%rax, %%rcx ; " /* B[2]^2 */
+-		"adcq %%rax, %%r11 ;"
+-		"movq %%r11,  96(%0) ;"
+-		"adcq %%rcx, %%r15 ;"
+-		"movq %%r15, 104(%0) ;"
+-		"movq 56(%1), %%rdx ;"
+-		"mulx %%rdx, %%rax, %%rcx ; " /* B[3]^2 */
+-		"adcq %%rax, %%r13 ;"
+-		"movq %%r13, 112(%0) ;"
+-		"adcq %%rcx, %%r14 ;"
+-		"movq %%r14, 120(%0) ;"
+-		:
+-		: "r"(c), "r"(a)
+-		: "memory", "cc", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10",
+-		  "%r11", "%r13", "%r14", "%r15");
+-}
++	u64 carry_r;
+ 
+-static void red_eltfp25519_2w_adx(u64 *const c, const u64 *const a)
+-{
+ 	asm volatile(
+-		"movl    $38, %%edx; "	/* 2*c = 38 = 2^256 */
+-		"mulx 32(%1),  %%r8, %%r10; " /* c*C[4] */
+-		"xorl %%ebx, %%ebx ;"
+-		"adox   (%1),  %%r8 ;"
+-		"mulx 40(%1),  %%r9, %%r11; " /* c*C[5] */
+-		"adcx %%r10,  %%r9 ;"
+-		"adox  8(%1),  %%r9 ;"
+-		"mulx 48(%1), %%r10, %%rax; " /* c*C[6] */
+-		"adcx %%r11, %%r10 ;"
+-		"adox 16(%1), %%r10 ;"
+-		"mulx 56(%1), %%r11, %%rcx; " /* c*C[7] */
+-		"adcx %%rax, %%r11 ;"
+-		"adox 24(%1), %%r11 ;"
+-		/***************************************/
+-		"adcx %%rbx, %%rcx ;"
+-		"adox  %%rbx, %%rcx ;"
+-		"imul %%rdx, %%rcx ;" /* c*C[4], cf=0, of=0 */
+-		"adcx %%rcx,  %%r8 ;"
+-		"adcx %%rbx,  %%r9 ;"
+-		"movq  %%r9,  8(%0) ;"
+-		"adcx %%rbx, %%r10 ;"
+-		"movq %%r10, 16(%0) ;"
+-		"adcx %%rbx, %%r11 ;"
+-		"movq %%r11, 24(%0) ;"
+-		"mov     $0, %%ecx ;"
+-		"cmovc %%edx, %%ecx ;"
+-		"addq %%rcx,  %%r8 ;"
+-		"movq  %%r8,   (%0) ;"
+-
+-		"mulx  96(%1),  %%r8, %%r10; " /* c*C[4] */
+-		"xorl %%ebx, %%ebx ;"
+-		"adox 64(%1),  %%r8 ;"
+-		"mulx 104(%1),  %%r9, %%r11; " /* c*C[5] */
+-		"adcx %%r10,  %%r9 ;"
+-		"adox 72(%1),  %%r9 ;"
+-		"mulx 112(%1), %%r10, %%rax; " /* c*C[6] */
+-		"adcx %%r11, %%r10 ;"
+-		"adox 80(%1), %%r10 ;"
+-		"mulx 120(%1), %%r11, %%rcx; " /* c*C[7] */
+-		"adcx %%rax, %%r11 ;"
+-		"adox 88(%1), %%r11 ;"
+-		/****************************************/
+-		"adcx %%rbx, %%rcx ;"
+-		"adox  %%rbx, %%rcx ;"
+-		"imul %%rdx, %%rcx ;" /* c*C[4], cf=0, of=0 */
+-		"adcx %%rcx,  %%r8 ;"
+-		"adcx %%rbx,  %%r9 ;"
+-		"movq  %%r9, 40(%0) ;"
+-		"adcx %%rbx, %%r10 ;"
+-		"movq %%r10, 48(%0) ;"
+-		"adcx %%rbx, %%r11 ;"
+-		"movq %%r11, 56(%0) ;"
+-		"mov     $0, %%ecx ;"
+-		"cmovc %%edx, %%ecx ;"
+-		"addq %%rcx,  %%r8 ;"
+-		"movq  %%r8, 32(%0) ;"
+-		:
+-		: "r"(c), "r"(a)
+-		: "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9",
+-		  "%r10", "%r11");
+-}
++		/* Clear registers to propagate the carry bit */
++		"  xor %%r8, %%r8;"
++		"  xor %%r9, %%r9;"
++		"  xor %%r10, %%r10;"
++		"  xor %%r11, %%r11;"
++		"  xor %1, %1;"
++
++		/* Begin addition chain */
++		"  addq 0(%3), %0;"
++		"  movq %0, 0(%2);"
++		"  adcxq 8(%3), %%r8;"
++		"  movq %%r8, 8(%2);"
++		"  adcxq 16(%3), %%r9;"
++		"  movq %%r9, 16(%2);"
++		"  adcxq 24(%3), %%r10;"
++		"  movq %%r10, 24(%2);"
++
++		/* Return the carry bit in a register */
++		"  adcx %%r11, %1;"
++	: "+&r" (f2), "=&r" (carry_r)
++	: "r" (out), "r" (f1)
++	: "%r8", "%r9", "%r10", "%r11", "memory", "cc"
++	);
+ 
+-static void red_eltfp25519_2w_bmi2(u64 *const c, const u64 *const a)
+-{
+-	asm volatile(
+-		"movl    $38, %%edx ; "       /* 2*c = 38 = 2^256 */
+-		"mulx 32(%1),  %%r8, %%r10 ;" /* c*C[4] */
+-		"mulx 40(%1),  %%r9, %%r11 ;" /* c*C[5] */
+-		"addq %%r10,  %%r9 ;"
+-		"mulx 48(%1), %%r10, %%rax ;" /* c*C[6] */
+-		"adcq %%r11, %%r10 ;"
+-		"mulx 56(%1), %%r11, %%rcx ;" /* c*C[7] */
+-		"adcq %%rax, %%r11 ;"
+-		/***************************************/
+-		"adcq    $0, %%rcx ;"
+-		"addq   (%1),  %%r8 ;"
+-		"adcq  8(%1),  %%r9 ;"
+-		"adcq 16(%1), %%r10 ;"
+-		"adcq 24(%1), %%r11 ;"
+-		"adcq     $0, %%rcx ;"
+-		"imul %%rdx, %%rcx ;" /* c*C[4], cf=0 */
+-		"addq %%rcx,  %%r8 ;"
+-		"adcq    $0,  %%r9 ;"
+-		"movq  %%r9,  8(%0) ;"
+-		"adcq    $0, %%r10 ;"
+-		"movq %%r10, 16(%0) ;"
+-		"adcq    $0, %%r11 ;"
+-		"movq %%r11, 24(%0) ;"
+-		"mov     $0, %%ecx ;"
+-		"cmovc %%edx, %%ecx ;"
+-		"addq %%rcx,  %%r8 ;"
+-		"movq  %%r8,   (%0) ;"
+-
+-		"mulx  96(%1),  %%r8, %%r10 ;" /* c*C[4] */
+-		"mulx 104(%1),  %%r9, %%r11 ;" /* c*C[5] */
+-		"addq %%r10,  %%r9 ;"
+-		"mulx 112(%1), %%r10, %%rax ;" /* c*C[6] */
+-		"adcq %%r11, %%r10 ;"
+-		"mulx 120(%1), %%r11, %%rcx ;" /* c*C[7] */
+-		"adcq %%rax, %%r11 ;"
+-		/****************************************/
+-		"adcq    $0, %%rcx ;"
+-		"addq 64(%1),  %%r8 ;"
+-		"adcq 72(%1),  %%r9 ;"
+-		"adcq 80(%1), %%r10 ;"
+-		"adcq 88(%1), %%r11 ;"
+-		"adcq     $0, %%rcx ;"
+-		"imul %%rdx, %%rcx ;" /* c*C[4], cf=0 */
+-		"addq %%rcx,  %%r8 ;"
+-		"adcq    $0,  %%r9 ;"
+-		"movq  %%r9, 40(%0) ;"
+-		"adcq    $0, %%r10 ;"
+-		"movq %%r10, 48(%0) ;"
+-		"adcq    $0, %%r11 ;"
+-		"movq %%r11, 56(%0) ;"
+-		"mov     $0, %%ecx ;"
+-		"cmovc %%edx, %%ecx ;"
+-		"addq %%rcx,  %%r8 ;"
+-		"movq  %%r8, 32(%0) ;"
+-		:
+-		: "r"(c), "r"(a)
+-		: "memory", "cc", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10",
+-		  "%r11");
++	return carry_r;
+ }
+ 
+-static void mul_256x256_integer_adx(u64 *const c, const u64 *const a,
+-				    const u64 *const b)
++/* Computes the field addition of two field elements */
++static inline void fadd(u64 *out, const u64 *f1, const u64 *f2)
+ {
+ 	asm volatile(
+-		"movq   (%1), %%rdx; "	/* A[0] */
+-		"mulx   (%2),  %%r8,  %%r9; " /* A[0]*B[0] */
+-		"xorl %%r10d, %%r10d ;"
+-		"movq  %%r8,  (%0) ;"
+-		"mulx  8(%2), %%r10, %%r11; " /* A[0]*B[1] */
+-		"adox  %%r9, %%r10 ;"
+-		"movq %%r10, 8(%0) ;"
+-		"mulx 16(%2), %%r15, %%r13; " /* A[0]*B[2] */
+-		"adox %%r11, %%r15 ;"
+-		"mulx 24(%2), %%r14, %%rdx; " /* A[0]*B[3] */
+-		"adox %%r13, %%r14 ;"
+-		"movq $0, %%rax ;"
+-		/******************************************/
+-		"adox %%rdx, %%rax ;"
+-
+-		"movq  8(%1), %%rdx; "	/* A[1] */
+-		"mulx   (%2),  %%r8,  %%r9; " /* A[1]*B[0] */
+-		"xorl %%r10d, %%r10d ;"
+-		"adcx 8(%0),  %%r8 ;"
+-		"movq  %%r8,  8(%0) ;"
+-		"mulx  8(%2), %%r10, %%r11; " /* A[1]*B[1] */
+-		"adox  %%r9, %%r10 ;"
+-		"adcx %%r15, %%r10 ;"
+-		"movq %%r10, 16(%0) ;"
+-		"mulx 16(%2), %%r15, %%r13; " /* A[1]*B[2] */
+-		"adox %%r11, %%r15 ;"
+-		"adcx %%r14, %%r15 ;"
+-		"movq $0, %%r8  ;"
+-		"mulx 24(%2), %%r14, %%rdx; " /* A[1]*B[3] */
+-		"adox %%r13, %%r14 ;"
+-		"adcx %%rax, %%r14 ;"
+-		"movq $0, %%rax ;"
+-		/******************************************/
+-		"adox %%rdx, %%rax ;"
+-		"adcx  %%r8, %%rax ;"
+-
+-		"movq 16(%1), %%rdx; "	/* A[2] */
+-		"mulx   (%2),  %%r8,  %%r9; " /* A[2]*B[0] */
+-		"xorl %%r10d, %%r10d ;"
+-		"adcx 16(%0), %%r8 ;"
+-		"movq  %%r8, 16(%0) ;"
+-		"mulx  8(%2), %%r10, %%r11; " /* A[2]*B[1] */
+-		"adox  %%r9, %%r10 ;"
+-		"adcx %%r15, %%r10 ;"
+-		"movq %%r10, 24(%0) ;"
+-		"mulx 16(%2), %%r15, %%r13; " /* A[2]*B[2] */
+-		"adox %%r11, %%r15 ;"
+-		"adcx %%r14, %%r15 ;"
+-		"movq $0, %%r8  ;"
+-		"mulx 24(%2), %%r14, %%rdx; " /* A[2]*B[3] */
+-		"adox %%r13, %%r14 ;"
+-		"adcx %%rax, %%r14 ;"
+-		"movq $0, %%rax ;"
+-		/******************************************/
+-		"adox %%rdx, %%rax ;"
+-		"adcx  %%r8, %%rax ;"
+-
+-		"movq 24(%1), %%rdx; "	/* A[3] */
+-		"mulx   (%2),  %%r8,  %%r9; " /* A[3]*B[0] */
+-		"xorl %%r10d, %%r10d ;"
+-		"adcx 24(%0), %%r8 ;"
+-		"movq  %%r8, 24(%0) ;"
+-		"mulx  8(%2), %%r10, %%r11; " /* A[3]*B[1] */
+-		"adox  %%r9, %%r10 ;"
+-		"adcx %%r15, %%r10 ;"
+-		"movq %%r10, 32(%0) ;"
+-		"mulx 16(%2), %%r15, %%r13; " /* A[3]*B[2] */
+-		"adox %%r11, %%r15 ;"
+-		"adcx %%r14, %%r15 ;"
+-		"movq %%r15, 40(%0) ;"
+-		"movq $0, %%r8  ;"
+-		"mulx 24(%2), %%r14, %%rdx; " /* A[3]*B[3] */
+-		"adox %%r13, %%r14 ;"
+-		"adcx %%rax, %%r14 ;"
+-		"movq %%r14, 48(%0) ;"
+-		"movq $0, %%rax ;"
+-		/******************************************/
+-		"adox %%rdx, %%rax ;"
+-		"adcx  %%r8, %%rax ;"
+-		"movq %%rax, 56(%0) ;"
+-		:
+-		: "r"(c), "r"(a), "r"(b)
+-		: "memory", "cc", "%rax", "%rdx", "%r8", "%r9", "%r10", "%r11",
+-		  "%r13", "%r14", "%r15");
++		/* Compute the raw addition of f1 + f2 */
++		"  movq 0(%0), %%r8;"
++		"  addq 0(%2), %%r8;"
++		"  movq 8(%0), %%r9;"
++		"  adcxq 8(%2), %%r9;"
++		"  movq 16(%0), %%r10;"
++		"  adcxq 16(%2), %%r10;"
++		"  movq 24(%0), %%r11;"
++		"  adcxq 24(%2), %%r11;"
++
++		/* Wrap the result back into the field */
++
++		/* Step 1: Compute carry*38 */
++		"  mov $0, %%rax;"
++		"  mov $38, %0;"
++		"  cmovc %0, %%rax;"
++
++		/* Step 2: Add carry*38 to the original sum */
++		"  xor %%rcx, %%rcx;"
++		"  add %%rax, %%r8;"
++		"  adcx %%rcx, %%r9;"
++		"  movq %%r9, 8(%1);"
++		"  adcx %%rcx, %%r10;"
++		"  movq %%r10, 16(%1);"
++		"  adcx %%rcx, %%r11;"
++		"  movq %%r11, 24(%1);"
++
++		/* Step 3: Fold the carry bit back in; guaranteed not to carry at this point */
++		"  mov $0, %%rax;"
++		"  cmovc %0, %%rax;"
++		"  add %%rax, %%r8;"
++		"  movq %%r8, 0(%1);"
++	: "+&r" (f2)
++	: "r" (out), "r" (f1)
++	: "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11", "memory", "cc"
++	);
+ }
+ 
+-static void mul_256x256_integer_bmi2(u64 *const c, const u64 *const a,
+-				     const u64 *const b)
++/* Computes the field substraction of two field elements */
++static inline void fsub(u64 *out, const u64 *f1, const u64 *f2)
+ {
+ 	asm volatile(
+-		"movq   (%1), %%rdx; "	/* A[0] */
+-		"mulx   (%2),  %%r8, %%r15; " /* A[0]*B[0] */
+-		"movq %%r8,  (%0) ;"
+-		"mulx  8(%2), %%r10, %%rax; " /* A[0]*B[1] */
+-		"addq %%r10, %%r15 ;"
+-		"mulx 16(%2),  %%r8, %%rbx; " /* A[0]*B[2] */
+-		"adcq  %%r8, %%rax ;"
+-		"mulx 24(%2), %%r10, %%rcx; " /* A[0]*B[3] */
+-		"adcq %%r10, %%rbx ;"
+-		/******************************************/
+-		"adcq    $0, %%rcx ;"
+-
+-		"movq  8(%1), %%rdx; "	/* A[1] */
+-		"mulx   (%2),  %%r8,  %%r9; " /* A[1]*B[0] */
+-		"addq %%r15,  %%r8 ;"
+-		"movq %%r8, 8(%0) ;"
+-		"mulx  8(%2), %%r10, %%r11; " /* A[1]*B[1] */
+-		"adcq %%r10,  %%r9 ;"
+-		"mulx 16(%2),  %%r8, %%r13; " /* A[1]*B[2] */
+-		"adcq  %%r8, %%r11 ;"
+-		"mulx 24(%2), %%r10, %%r15; " /* A[1]*B[3] */
+-		"adcq %%r10, %%r13 ;"
+-		/******************************************/
+-		"adcq    $0, %%r15 ;"
+-
+-		"addq  %%r9, %%rax ;"
+-		"adcq %%r11, %%rbx ;"
+-		"adcq %%r13, %%rcx ;"
+-		"adcq    $0, %%r15 ;"
+-
+-		"movq 16(%1), %%rdx; "	/* A[2] */
+-		"mulx   (%2),  %%r8,  %%r9; " /* A[2]*B[0] */
+-		"addq %%rax,  %%r8 ;"
+-		"movq %%r8, 16(%0) ;"
+-		"mulx  8(%2), %%r10, %%r11; " /* A[2]*B[1] */
+-		"adcq %%r10,  %%r9 ;"
+-		"mulx 16(%2),  %%r8, %%r13; " /* A[2]*B[2] */
+-		"adcq  %%r8, %%r11 ;"
+-		"mulx 24(%2), %%r10, %%rax; " /* A[2]*B[3] */
+-		"adcq %%r10, %%r13 ;"
+-		/******************************************/
+-		"adcq    $0, %%rax ;"
+-
+-		"addq  %%r9, %%rbx ;"
+-		"adcq %%r11, %%rcx ;"
+-		"adcq %%r13, %%r15 ;"
+-		"adcq    $0, %%rax ;"
+-
+-		"movq 24(%1), %%rdx; "	/* A[3] */
+-		"mulx   (%2),  %%r8,  %%r9; " /* A[3]*B[0] */
+-		"addq %%rbx,  %%r8 ;"
+-		"movq %%r8, 24(%0) ;"
+-		"mulx  8(%2), %%r10, %%r11; " /* A[3]*B[1] */
+-		"adcq %%r10,  %%r9 ;"
+-		"mulx 16(%2),  %%r8, %%r13; " /* A[3]*B[2] */
+-		"adcq  %%r8, %%r11 ;"
+-		"mulx 24(%2), %%r10, %%rbx; " /* A[3]*B[3] */
+-		"adcq %%r10, %%r13 ;"
+-		/******************************************/
+-		"adcq    $0, %%rbx ;"
+-
+-		"addq  %%r9, %%rcx ;"
+-		"movq %%rcx, 32(%0) ;"
+-		"adcq %%r11, %%r15 ;"
+-		"movq %%r15, 40(%0) ;"
+-		"adcq %%r13, %%rax ;"
+-		"movq %%rax, 48(%0) ;"
+-		"adcq    $0, %%rbx ;"
+-		"movq %%rbx, 56(%0) ;"
+-		:
+-		: "r"(c), "r"(a), "r"(b)
+-		: "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9",
+-		  "%r10", "%r11", "%r13", "%r15");
++		/* Compute the raw substraction of f1-f2 */
++		"  movq 0(%1), %%r8;"
++		"  subq 0(%2), %%r8;"
++		"  movq 8(%1), %%r9;"
++		"  sbbq 8(%2), %%r9;"
++		"  movq 16(%1), %%r10;"
++		"  sbbq 16(%2), %%r10;"
++		"  movq 24(%1), %%r11;"
++		"  sbbq 24(%2), %%r11;"
++
++		/* Wrap the result back into the field */
++
++		/* Step 1: Compute carry*38 */
++		"  mov $0, %%rax;"
++		"  mov $38, %%rcx;"
++		"  cmovc %%rcx, %%rax;"
++
++		/* Step 2: Substract carry*38 from the original difference */
++		"  sub %%rax, %%r8;"
++		"  sbb $0, %%r9;"
++		"  sbb $0, %%r10;"
++		"  sbb $0, %%r11;"
++
++		/* Step 3: Fold the carry bit back in; guaranteed not to carry at this point */
++		"  mov $0, %%rax;"
++		"  cmovc %%rcx, %%rax;"
++		"  sub %%rax, %%r8;"
++
++		/* Store the result */
++		"  movq %%r8, 0(%0);"
++		"  movq %%r9, 8(%0);"
++		"  movq %%r10, 16(%0);"
++		"  movq %%r11, 24(%0);"
++	:
++	: "r" (out), "r" (f1), "r" (f2)
++	: "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11", "memory", "cc"
++	);
+ }
+ 
+-static void sqr_256x256_integer_adx(u64 *const c, const u64 *const a)
++/* Computes a field multiplication: out <- f1 * f2
++ * Uses the 8-element buffer tmp for intermediate results */
++static inline void fmul(u64 *out, const u64 *f1, const u64 *f2, u64 *tmp)
+ {
+ 	asm volatile(
+-		"movq   (%1), %%rdx        ;" /* A[0]      */
+-		"mulx  8(%1),  %%r8, %%r14 ;" /* A[1]*A[0] */
+-		"xorl %%r15d, %%r15d;"
+-		"mulx 16(%1),  %%r9, %%r10 ;" /* A[2]*A[0] */
+-		"adcx %%r14,  %%r9 ;"
+-		"mulx 24(%1), %%rax, %%rcx ;" /* A[3]*A[0] */
+-		"adcx %%rax, %%r10 ;"
+-		"movq 24(%1), %%rdx        ;" /* A[3]      */
+-		"mulx  8(%1), %%r11, %%rbx ;" /* A[1]*A[3] */
+-		"adcx %%rcx, %%r11 ;"
+-		"mulx 16(%1), %%rax, %%r13 ;" /* A[2]*A[3] */
+-		"adcx %%rax, %%rbx ;"
+-		"movq  8(%1), %%rdx        ;" /* A[1]      */
+-		"adcx %%r15, %%r13 ;"
+-		"mulx 16(%1), %%rax, %%rcx ;" /* A[2]*A[1] */
+-		"movq    $0, %%r14 ;"
+-		/******************************************/
+-		"adcx %%r15, %%r14 ;"
+-
+-		"xorl %%r15d, %%r15d;"
+-		"adox %%rax, %%r10 ;"
+-		"adcx  %%r8,  %%r8 ;"
+-		"adox %%rcx, %%r11 ;"
+-		"adcx  %%r9,  %%r9 ;"
+-		"adox %%r15, %%rbx ;"
+-		"adcx %%r10, %%r10 ;"
+-		"adox %%r15, %%r13 ;"
+-		"adcx %%r11, %%r11 ;"
+-		"adox %%r15, %%r14 ;"
+-		"adcx %%rbx, %%rbx ;"
+-		"adcx %%r13, %%r13 ;"
+-		"adcx %%r14, %%r14 ;"
+-
+-		"movq   (%1), %%rdx ;"
+-		"mulx %%rdx, %%rax, %%rcx ;" /* A[0]^2 */
+-		/*******************/
+-		"movq %%rax,  0(%0) ;"
+-		"addq %%rcx,  %%r8 ;"
+-		"movq  %%r8,  8(%0) ;"
+-		"movq  8(%1), %%rdx ;"
+-		"mulx %%rdx, %%rax, %%rcx ;" /* A[1]^2 */
+-		"adcq %%rax,  %%r9 ;"
+-		"movq  %%r9, 16(%0) ;"
+-		"adcq %%rcx, %%r10 ;"
+-		"movq %%r10, 24(%0) ;"
+-		"movq 16(%1), %%rdx ;"
+-		"mulx %%rdx, %%rax, %%rcx ;" /* A[2]^2 */
+-		"adcq %%rax, %%r11 ;"
+-		"movq %%r11, 32(%0) ;"
+-		"adcq %%rcx, %%rbx ;"
+-		"movq %%rbx, 40(%0) ;"
+-		"movq 24(%1), %%rdx ;"
+-		"mulx %%rdx, %%rax, %%rcx ;" /* A[3]^2 */
+-		"adcq %%rax, %%r13 ;"
+-		"movq %%r13, 48(%0) ;"
+-		"adcq %%rcx, %%r14 ;"
+-		"movq %%r14, 56(%0) ;"
+-		:
+-		: "r"(c), "r"(a)
+-		: "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9",
+-		  "%r10", "%r11", "%r13", "%r14", "%r15");
+-}
++		/* Compute the raw multiplication: tmp <- src1 * src2 */
+ 
+-static void sqr_256x256_integer_bmi2(u64 *const c, const u64 *const a)
+-{
+-	asm volatile(
+-		"movq  8(%1), %%rdx        ;" /* A[1]      */
+-		"mulx   (%1),  %%r8,  %%r9 ;" /* A[0]*A[1] */
+-		"mulx 16(%1), %%r10, %%r11 ;" /* A[2]*A[1] */
+-		"mulx 24(%1), %%rcx, %%r14 ;" /* A[3]*A[1] */
+-
+-		"movq 16(%1), %%rdx        ;" /* A[2]      */
+-		"mulx 24(%1), %%r15, %%r13 ;" /* A[3]*A[2] */
+-		"mulx   (%1), %%rax, %%rdx ;" /* A[0]*A[2] */
+-
+-		"addq %%rax,  %%r9 ;"
+-		"adcq %%rdx, %%r10 ;"
+-		"adcq %%rcx, %%r11 ;"
+-		"adcq %%r14, %%r15 ;"
+-		"adcq    $0, %%r13 ;"
+-		"movq    $0, %%r14 ;"
+-		"adcq    $0, %%r14 ;"
+-
+-		"movq   (%1), %%rdx        ;" /* A[0]      */
+-		"mulx 24(%1), %%rax, %%rcx ;" /* A[0]*A[3] */
+-
+-		"addq %%rax, %%r10 ;"
+-		"adcq %%rcx, %%r11 ;"
+-		"adcq    $0, %%r15 ;"
+-		"adcq    $0, %%r13 ;"
+-		"adcq    $0, %%r14 ;"
+-
+-		"shldq $1, %%r13, %%r14 ;"
+-		"shldq $1, %%r15, %%r13 ;"
+-		"shldq $1, %%r11, %%r15 ;"
+-		"shldq $1, %%r10, %%r11 ;"
+-		"shldq $1,  %%r9, %%r10 ;"
+-		"shldq $1,  %%r8,  %%r9 ;"
+-		"shlq  $1,  %%r8        ;"
+-
+-		/*******************/
+-		"mulx %%rdx, %%rax, %%rcx ;" /* A[0]^2 */
+-		/*******************/
+-		"movq %%rax,  0(%0) ;"
+-		"addq %%rcx,  %%r8 ;"
+-		"movq  %%r8,  8(%0) ;"
+-		"movq  8(%1), %%rdx ;"
+-		"mulx %%rdx, %%rax, %%rcx ;" /* A[1]^2 */
+-		"adcq %%rax,  %%r9 ;"
+-		"movq  %%r9, 16(%0) ;"
+-		"adcq %%rcx, %%r10 ;"
+-		"movq %%r10, 24(%0) ;"
+-		"movq 16(%1), %%rdx ;"
+-		"mulx %%rdx, %%rax, %%rcx ;" /* A[2]^2 */
+-		"adcq %%rax, %%r11 ;"
+-		"movq %%r11, 32(%0) ;"
+-		"adcq %%rcx, %%r15 ;"
+-		"movq %%r15, 40(%0) ;"
+-		"movq 24(%1), %%rdx ;"
+-		"mulx %%rdx, %%rax, %%rcx ;" /* A[3]^2 */
+-		"adcq %%rax, %%r13 ;"
+-		"movq %%r13, 48(%0) ;"
+-		"adcq %%rcx, %%r14 ;"
+-		"movq %%r14, 56(%0) ;"
+-		:
+-		: "r"(c), "r"(a)
+-		: "memory", "cc", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10",
+-		  "%r11", "%r13", "%r14", "%r15");
++		/* Compute src1[0] * src2 */
++		"  movq 0(%1), %%rdx;"
++		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  movq %%r8, 0(%0);"
++		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  movq %%r10, 8(%0);"
++		"  mulxq 16(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"
++		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  mov $0, %%rax;"
++		                                   "  adox %%rdx, %%rax;"
++		/* Compute src1[1] * src2 */
++		"  movq 8(%1), %%rdx;"
++		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  adcxq 8(%0), %%r8;"    "  movq %%r8, 8(%0);"
++		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%r12, %%r10;"    "  movq %%r10, 16(%0);"
++		"  mulxq 16(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"    "  adcx %%r14, %%r12;"    "  mov $0, %%r8;"
++		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
++		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
++		/* Compute src1[2] * src2 */
++		"  movq 16(%1), %%rdx;"
++		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 16(%0), %%r8;"    "  movq %%r8, 16(%0);"
++		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%r12, %%r10;"    "  movq %%r10, 24(%0);"
++		"  mulxq 16(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"    "  adcx %%r14, %%r12;"    "  mov $0, %%r8;"
++		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
++		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
++		/* Compute src1[3] * src2 */
++		"  movq 24(%1), %%rdx;"
++		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 24(%0), %%r8;"    "  movq %%r8, 24(%0);"
++		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%r12, %%r10;"    "  movq %%r10, 32(%0);"
++		"  mulxq 16(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"    "  adcx %%r14, %%r12;"    "  movq %%r12, 40(%0);"    "  mov $0, %%r8;"
++		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  movq %%r14, 48(%0);"    "  mov $0, %%rax;"
++		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"     "  movq %%rax, 56(%0);"
++		/* Line up pointers */
++		"  mov %0, %1;"
++		"  mov %2, %0;"
++
++		/* Wrap the result back into the field */
++
++		/* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */
++		"  mov $38, %%rdx;"
++		"  mulxq 32(%1), %%r8, %%r13;"
++		"  xor %3, %3;"
++		"  adoxq 0(%1), %%r8;"
++		"  mulxq 40(%1), %%r9, %%r12;"
++		"  adcx %%r13, %%r9;"
++		"  adoxq 8(%1), %%r9;"
++		"  mulxq 48(%1), %%r10, %%r13;"
++		"  adcx %%r12, %%r10;"
++		"  adoxq 16(%1), %%r10;"
++		"  mulxq 56(%1), %%r11, %%rax;"
++		"  adcx %%r13, %%r11;"
++		"  adoxq 24(%1), %%r11;"
++		"  adcx %3, %%rax;"
++		"  adox %3, %%rax;"
++		"  imul %%rdx, %%rax;"
++
++		/* Step 2: Fold the carry back into dst */
++		"  add %%rax, %%r8;"
++		"  adcx %3, %%r9;"
++		"  movq %%r9, 8(%0);"
++		"  adcx %3, %%r10;"
++		"  movq %%r10, 16(%0);"
++		"  adcx %3, %%r11;"
++		"  movq %%r11, 24(%0);"
++
++		/* Step 3: Fold the carry bit back in; guaranteed not to carry at this point */
++		"  mov $0, %%rax;"
++		"  cmovc %%rdx, %%rax;"
++		"  add %%rax, %%r8;"
++		"  movq %%r8, 0(%0);"
++	: "+&r" (tmp), "+&r" (f1), "+&r" (out), "+&r" (f2)
++	:
++	: "%rax", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "memory", "cc"
++	);
+ }
+ 
+-static void red_eltfp25519_1w_adx(u64 *const c, const u64 *const a)
++/* Computes two field multiplications:
++ * out[0] <- f1[0] * f2[0]
++ * out[1] <- f1[1] * f2[1]
++ * Uses the 16-element buffer tmp for intermediate results. */
++static inline void fmul2(u64 *out, const u64 *f1, const u64 *f2, u64 *tmp)
+ {
+ 	asm volatile(
+-		"movl    $38, %%edx ;"	/* 2*c = 38 = 2^256 */
+-		"mulx 32(%1),  %%r8, %%r10 ;" /* c*C[4] */
+-		"xorl %%ebx, %%ebx ;"
+-		"adox   (%1),  %%r8 ;"
+-		"mulx 40(%1),  %%r9, %%r11 ;" /* c*C[5] */
+-		"adcx %%r10,  %%r9 ;"
+-		"adox  8(%1),  %%r9 ;"
+-		"mulx 48(%1), %%r10, %%rax ;" /* c*C[6] */
+-		"adcx %%r11, %%r10 ;"
+-		"adox 16(%1), %%r10 ;"
+-		"mulx 56(%1), %%r11, %%rcx ;" /* c*C[7] */
+-		"adcx %%rax, %%r11 ;"
+-		"adox 24(%1), %%r11 ;"
+-		/***************************************/
+-		"adcx %%rbx, %%rcx ;"
+-		"adox  %%rbx, %%rcx ;"
+-		"imul %%rdx, %%rcx ;" /* c*C[4], cf=0, of=0 */
+-		"adcx %%rcx,  %%r8 ;"
+-		"adcx %%rbx,  %%r9 ;"
+-		"movq  %%r9,  8(%0) ;"
+-		"adcx %%rbx, %%r10 ;"
+-		"movq %%r10, 16(%0) ;"
+-		"adcx %%rbx, %%r11 ;"
+-		"movq %%r11, 24(%0) ;"
+-		"mov     $0, %%ecx ;"
+-		"cmovc %%edx, %%ecx ;"
+-		"addq %%rcx,  %%r8 ;"
+-		"movq  %%r8,   (%0) ;"
+-		:
+-		: "r"(c), "r"(a)
+-		: "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9",
+-		  "%r10", "%r11");
+-}
++		/* Compute the raw multiplication tmp[0] <- f1[0] * f2[0] */
+ 
+-static void red_eltfp25519_1w_bmi2(u64 *const c, const u64 *const a)
+-{
+-	asm volatile(
+-		"movl    $38, %%edx ;"	/* 2*c = 38 = 2^256 */
+-		"mulx 32(%1),  %%r8, %%r10 ;" /* c*C[4] */
+-		"mulx 40(%1),  %%r9, %%r11 ;" /* c*C[5] */
+-		"addq %%r10,  %%r9 ;"
+-		"mulx 48(%1), %%r10, %%rax ;" /* c*C[6] */
+-		"adcq %%r11, %%r10 ;"
+-		"mulx 56(%1), %%r11, %%rcx ;" /* c*C[7] */
+-		"adcq %%rax, %%r11 ;"
+-		/***************************************/
+-		"adcq    $0, %%rcx ;"
+-		"addq   (%1),  %%r8 ;"
+-		"adcq  8(%1),  %%r9 ;"
+-		"adcq 16(%1), %%r10 ;"
+-		"adcq 24(%1), %%r11 ;"
+-		"adcq     $0, %%rcx ;"
+-		"imul %%rdx, %%rcx ;" /* c*C[4], cf=0 */
+-		"addq %%rcx,  %%r8 ;"
+-		"adcq    $0,  %%r9 ;"
+-		"movq  %%r9,  8(%0) ;"
+-		"adcq    $0, %%r10 ;"
+-		"movq %%r10, 16(%0) ;"
+-		"adcq    $0, %%r11 ;"
+-		"movq %%r11, 24(%0) ;"
+-		"mov     $0, %%ecx ;"
+-		"cmovc %%edx, %%ecx ;"
+-		"addq %%rcx,  %%r8 ;"
+-		"movq  %%r8,   (%0) ;"
+-		:
+-		: "r"(c), "r"(a)
+-		: "memory", "cc", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10",
+-		  "%r11");
++		/* Compute src1[0] * src2 */
++		"  movq 0(%1), %%rdx;"
++		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  movq %%r8, 0(%0);"
++		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  movq %%r10, 8(%0);"
++		"  mulxq 16(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"
++		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  mov $0, %%rax;"
++		                                   "  adox %%rdx, %%rax;"
++		/* Compute src1[1] * src2 */
++		"  movq 8(%1), %%rdx;"
++		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  adcxq 8(%0), %%r8;"    "  movq %%r8, 8(%0);"
++		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%r12, %%r10;"    "  movq %%r10, 16(%0);"
++		"  mulxq 16(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"    "  adcx %%r14, %%r12;"    "  mov $0, %%r8;"
++		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
++		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
++		/* Compute src1[2] * src2 */
++		"  movq 16(%1), %%rdx;"
++		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 16(%0), %%r8;"    "  movq %%r8, 16(%0);"
++		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%r12, %%r10;"    "  movq %%r10, 24(%0);"
++		"  mulxq 16(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"    "  adcx %%r14, %%r12;"    "  mov $0, %%r8;"
++		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
++		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
++		/* Compute src1[3] * src2 */
++		"  movq 24(%1), %%rdx;"
++		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 24(%0), %%r8;"    "  movq %%r8, 24(%0);"
++		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%r12, %%r10;"    "  movq %%r10, 32(%0);"
++		"  mulxq 16(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"    "  adcx %%r14, %%r12;"    "  movq %%r12, 40(%0);"    "  mov $0, %%r8;"
++		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  movq %%r14, 48(%0);"    "  mov $0, %%rax;"
++		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"     "  movq %%rax, 56(%0);"
++
++		/* Compute the raw multiplication tmp[1] <- f1[1] * f2[1] */
++
++		/* Compute src1[0] * src2 */
++		"  movq 32(%1), %%rdx;"
++		"  mulxq 32(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  movq %%r8, 64(%0);"
++		"  mulxq 40(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  movq %%r10, 72(%0);"
++		"  mulxq 48(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"
++		"  mulxq 56(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  mov $0, %%rax;"
++		                                   "  adox %%rdx, %%rax;"
++		/* Compute src1[1] * src2 */
++		"  movq 40(%1), %%rdx;"
++		"  mulxq 32(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  adcxq 72(%0), %%r8;"    "  movq %%r8, 72(%0);"
++		"  mulxq 40(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%r12, %%r10;"    "  movq %%r10, 80(%0);"
++		"  mulxq 48(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"    "  adcx %%r14, %%r12;"    "  mov $0, %%r8;"
++		"  mulxq 56(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
++		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
++		/* Compute src1[2] * src2 */
++		"  movq 48(%1), %%rdx;"
++		"  mulxq 32(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 80(%0), %%r8;"    "  movq %%r8, 80(%0);"
++		"  mulxq 40(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%r12, %%r10;"    "  movq %%r10, 88(%0);"
++		"  mulxq 48(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"    "  adcx %%r14, %%r12;"    "  mov $0, %%r8;"
++		"  mulxq 56(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
++		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
++		/* Compute src1[3] * src2 */
++		"  movq 56(%1), %%rdx;"
++		"  mulxq 32(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 88(%0), %%r8;"    "  movq %%r8, 88(%0);"
++		"  mulxq 40(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%r12, %%r10;"    "  movq %%r10, 96(%0);"
++		"  mulxq 48(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"    "  adcx %%r14, %%r12;"    "  movq %%r12, 104(%0);"    "  mov $0, %%r8;"
++		"  mulxq 56(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  movq %%r14, 112(%0);"    "  mov $0, %%rax;"
++		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"     "  movq %%rax, 120(%0);"
++		/* Line up pointers */
++		"  mov %0, %1;"
++		"  mov %2, %0;"
++
++		/* Wrap the results back into the field */
++
++		/* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */
++		"  mov $38, %%rdx;"
++		"  mulxq 32(%1), %%r8, %%r13;"
++		"  xor %3, %3;"
++		"  adoxq 0(%1), %%r8;"
++		"  mulxq 40(%1), %%r9, %%r12;"
++		"  adcx %%r13, %%r9;"
++		"  adoxq 8(%1), %%r9;"
++		"  mulxq 48(%1), %%r10, %%r13;"
++		"  adcx %%r12, %%r10;"
++		"  adoxq 16(%1), %%r10;"
++		"  mulxq 56(%1), %%r11, %%rax;"
++		"  adcx %%r13, %%r11;"
++		"  adoxq 24(%1), %%r11;"
++		"  adcx %3, %%rax;"
++		"  adox %3, %%rax;"
++		"  imul %%rdx, %%rax;"
++
++		/* Step 2: Fold the carry back into dst */
++		"  add %%rax, %%r8;"
++		"  adcx %3, %%r9;"
++		"  movq %%r9, 8(%0);"
++		"  adcx %3, %%r10;"
++		"  movq %%r10, 16(%0);"
++		"  adcx %3, %%r11;"
++		"  movq %%r11, 24(%0);"
++
++		/* Step 3: Fold the carry bit back in; guaranteed not to carry at this point */
++		"  mov $0, %%rax;"
++		"  cmovc %%rdx, %%rax;"
++		"  add %%rax, %%r8;"
++		"  movq %%r8, 0(%0);"
++
++		/* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */
++		"  mov $38, %%rdx;"
++		"  mulxq 96(%1), %%r8, %%r13;"
++		"  xor %3, %3;"
++		"  adoxq 64(%1), %%r8;"
++		"  mulxq 104(%1), %%r9, %%r12;"
++		"  adcx %%r13, %%r9;"
++		"  adoxq 72(%1), %%r9;"
++		"  mulxq 112(%1), %%r10, %%r13;"
++		"  adcx %%r12, %%r10;"
++		"  adoxq 80(%1), %%r10;"
++		"  mulxq 120(%1), %%r11, %%rax;"
++		"  adcx %%r13, %%r11;"
++		"  adoxq 88(%1), %%r11;"
++		"  adcx %3, %%rax;"
++		"  adox %3, %%rax;"
++		"  imul %%rdx, %%rax;"
++
++		/* Step 2: Fold the carry back into dst */
++		"  add %%rax, %%r8;"
++		"  adcx %3, %%r9;"
++		"  movq %%r9, 40(%0);"
++		"  adcx %3, %%r10;"
++		"  movq %%r10, 48(%0);"
++		"  adcx %3, %%r11;"
++		"  movq %%r11, 56(%0);"
++
++		/* Step 3: Fold the carry bit back in; guaranteed not to carry at this point */
++		"  mov $0, %%rax;"
++		"  cmovc %%rdx, %%rax;"
++		"  add %%rax, %%r8;"
++		"  movq %%r8, 32(%0);"
++	: "+&r" (tmp), "+&r" (f1), "+&r" (out), "+&r" (f2)
++	:
++	: "%rax", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "memory", "cc"
++	);
+ }
+ 
+-static __always_inline void
+-add_eltfp25519_1w_adx(u64 *const c, const u64 *const a, const u64 *const b)
++/* Computes the field multiplication of four-element f1 with value in f2 */
++static inline void fmul_scalar(u64 *out, const u64 *f1, u64 f2)
+ {
+-	asm volatile(
+-		"mov     $38, %%eax ;"
+-		"xorl  %%ecx, %%ecx ;"
+-		"movq   (%2),  %%r8 ;"
+-		"adcx   (%1),  %%r8 ;"
+-		"movq  8(%2),  %%r9 ;"
+-		"adcx  8(%1),  %%r9 ;"
+-		"movq 16(%2), %%r10 ;"
+-		"adcx 16(%1), %%r10 ;"
+-		"movq 24(%2), %%r11 ;"
+-		"adcx 24(%1), %%r11 ;"
+-		"cmovc %%eax, %%ecx ;"
+-		"xorl %%eax, %%eax  ;"
+-		"adcx %%rcx,  %%r8  ;"
+-		"adcx %%rax,  %%r9  ;"
+-		"movq  %%r9,  8(%0) ;"
+-		"adcx %%rax, %%r10  ;"
+-		"movq %%r10, 16(%0) ;"
+-		"adcx %%rax, %%r11  ;"
+-		"movq %%r11, 24(%0) ;"
+-		"mov     $38, %%ecx ;"
+-		"cmovc %%ecx, %%eax ;"
+-		"addq %%rax,  %%r8  ;"
+-		"movq  %%r8,   (%0) ;"
+-		:
+-		: "r"(c), "r"(a), "r"(b)
+-		: "memory", "cc", "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11");
+-}
++	register u64 f2_r asm("rdx") = f2;
+ 
+-static __always_inline void
+-add_eltfp25519_1w_bmi2(u64 *const c, const u64 *const a, const u64 *const b)
+-{
+ 	asm volatile(
+-		"mov     $38, %%eax ;"
+-		"movq   (%2),  %%r8 ;"
+-		"addq   (%1),  %%r8 ;"
+-		"movq  8(%2),  %%r9 ;"
+-		"adcq  8(%1),  %%r9 ;"
+-		"movq 16(%2), %%r10 ;"
+-		"adcq 16(%1), %%r10 ;"
+-		"movq 24(%2), %%r11 ;"
+-		"adcq 24(%1), %%r11 ;"
+-		"mov      $0, %%ecx ;"
+-		"cmovc %%eax, %%ecx ;"
+-		"addq %%rcx,  %%r8  ;"
+-		"adcq    $0,  %%r9  ;"
+-		"movq  %%r9,  8(%0) ;"
+-		"adcq    $0, %%r10  ;"
+-		"movq %%r10, 16(%0) ;"
+-		"adcq    $0, %%r11  ;"
+-		"movq %%r11, 24(%0) ;"
+-		"mov     $0, %%ecx  ;"
+-		"cmovc %%eax, %%ecx ;"
+-		"addq %%rcx,  %%r8  ;"
+-		"movq  %%r8,   (%0) ;"
+-		:
+-		: "r"(c), "r"(a), "r"(b)
+-		: "memory", "cc", "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11");
++		/* Compute the raw multiplication of f1*f2 */
++		"  mulxq 0(%2), %%r8, %%rcx;"      /* f1[0]*f2 */
++		"  mulxq 8(%2), %%r9, %%r12;"      /* f1[1]*f2 */
++		"  add %%rcx, %%r9;"
++		"  mov $0, %%rcx;"
++		"  mulxq 16(%2), %%r10, %%r13;"    /* f1[2]*f2 */
++		"  adcx %%r12, %%r10;"
++		"  mulxq 24(%2), %%r11, %%rax;"    /* f1[3]*f2 */
++		"  adcx %%r13, %%r11;"
++		"  adcx %%rcx, %%rax;"
++
++		/* Wrap the result back into the field */
++
++		/* Step 1: Compute carry*38 */
++		"  mov $38, %%rdx;"
++		"  imul %%rdx, %%rax;"
++
++		/* Step 2: Fold the carry back into dst */
++		"  add %%rax, %%r8;"
++		"  adcx %%rcx, %%r9;"
++		"  movq %%r9, 8(%1);"
++		"  adcx %%rcx, %%r10;"
++		"  movq %%r10, 16(%1);"
++		"  adcx %%rcx, %%r11;"
++		"  movq %%r11, 24(%1);"
++
++		/* Step 3: Fold the carry bit back in; guaranteed not to carry at this point */
++		"  mov $0, %%rax;"
++		"  cmovc %%rdx, %%rax;"
++		"  add %%rax, %%r8;"
++		"  movq %%r8, 0(%1);"
++	: "+&r" (f2_r)
++	: "r" (out), "r" (f1)
++	: "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "memory", "cc"
++	);
+ }
+ 
+-static __always_inline void
+-sub_eltfp25519_1w(u64 *const c, const u64 *const a, const u64 *const b)
+-{
+-	asm volatile(
+-		"mov     $38, %%eax ;"
+-		"movq   (%1),  %%r8 ;"
+-		"subq   (%2),  %%r8 ;"
+-		"movq  8(%1),  %%r9 ;"
+-		"sbbq  8(%2),  %%r9 ;"
+-		"movq 16(%1), %%r10 ;"
+-		"sbbq 16(%2), %%r10 ;"
+-		"movq 24(%1), %%r11 ;"
+-		"sbbq 24(%2), %%r11 ;"
+-		"mov      $0, %%ecx ;"
+-		"cmovc %%eax, %%ecx ;"
+-		"subq %%rcx,  %%r8  ;"
+-		"sbbq    $0,  %%r9  ;"
+-		"movq  %%r9,  8(%0) ;"
+-		"sbbq    $0, %%r10  ;"
+-		"movq %%r10, 16(%0) ;"
+-		"sbbq    $0, %%r11  ;"
+-		"movq %%r11, 24(%0) ;"
+-		"mov     $0, %%ecx  ;"
+-		"cmovc %%eax, %%ecx ;"
+-		"subq %%rcx,  %%r8  ;"
+-		"movq  %%r8,   (%0) ;"
+-		:
+-		: "r"(c), "r"(a), "r"(b)
+-		: "memory", "cc", "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11");
+-}
+-
+-/* Multiplication by a24 = (A+2)/4 = (486662+2)/4 = 121666 */
+-static __always_inline void
+-mul_a24_eltfp25519_1w(u64 *const c, const u64 *const a)
++/* Computes p1 <- bit ? p2 : p1 in constant time */
++static inline void cswap2(u64 bit, const u64 *p1, const u64 *p2)
+ {
+-	const u64 a24 = 121666;
+ 	asm volatile(
+-		"movq     %2, %%rdx ;"
+-		"mulx   (%1),  %%r8, %%r10 ;"
+-		"mulx  8(%1),  %%r9, %%r11 ;"
+-		"addq %%r10,  %%r9 ;"
+-		"mulx 16(%1), %%r10, %%rax ;"
+-		"adcq %%r11, %%r10 ;"
+-		"mulx 24(%1), %%r11, %%rcx ;"
+-		"adcq %%rax, %%r11 ;"
+-		/**************************/
+-		"adcq    $0, %%rcx ;"
+-		"movl   $38, %%edx ;" /* 2*c = 38 = 2^256 mod 2^255-19*/
+-		"imul %%rdx, %%rcx ;"
+-		"addq %%rcx,  %%r8 ;"
+-		"adcq    $0,  %%r9 ;"
+-		"movq  %%r9,  8(%0) ;"
+-		"adcq    $0, %%r10 ;"
+-		"movq %%r10, 16(%0) ;"
+-		"adcq    $0, %%r11 ;"
+-		"movq %%r11, 24(%0) ;"
+-		"mov     $0, %%ecx ;"
+-		"cmovc %%edx, %%ecx ;"
+-		"addq %%rcx,  %%r8 ;"
+-		"movq  %%r8,   (%0) ;"
+-		:
+-		: "r"(c), "r"(a), "r"(a24)
+-		: "memory", "cc", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10",
+-		  "%r11");
+-}
+-
+-static void inv_eltfp25519_1w_adx(u64 *const c, const u64 *const a)
+-{
+-	struct {
+-		eltfp25519_1w_buffer buffer;
+-		eltfp25519_1w x0, x1, x2;
+-	} __aligned(32) m;
+-	u64 *T[4];
+-
+-	T[0] = m.x0;
+-	T[1] = c; /* x^(-1) */
+-	T[2] = m.x1;
+-	T[3] = m.x2;
+-
+-	copy_eltfp25519_1w(T[1], a);
+-	sqrn_eltfp25519_1w_adx(T[1], 1);
+-	copy_eltfp25519_1w(T[2], T[1]);
+-	sqrn_eltfp25519_1w_adx(T[2], 2);
+-	mul_eltfp25519_1w_adx(T[0], a, T[2]);
+-	mul_eltfp25519_1w_adx(T[1], T[1], T[0]);
+-	copy_eltfp25519_1w(T[2], T[1]);
+-	sqrn_eltfp25519_1w_adx(T[2], 1);
+-	mul_eltfp25519_1w_adx(T[0], T[0], T[2]);
+-	copy_eltfp25519_1w(T[2], T[0]);
+-	sqrn_eltfp25519_1w_adx(T[2], 5);
+-	mul_eltfp25519_1w_adx(T[0], T[0], T[2]);
+-	copy_eltfp25519_1w(T[2], T[0]);
+-	sqrn_eltfp25519_1w_adx(T[2], 10);
+-	mul_eltfp25519_1w_adx(T[2], T[2], T[0]);
+-	copy_eltfp25519_1w(T[3], T[2]);
+-	sqrn_eltfp25519_1w_adx(T[3], 20);
+-	mul_eltfp25519_1w_adx(T[3], T[3], T[2]);
+-	sqrn_eltfp25519_1w_adx(T[3], 10);
+-	mul_eltfp25519_1w_adx(T[3], T[3], T[0]);
+-	copy_eltfp25519_1w(T[0], T[3]);
+-	sqrn_eltfp25519_1w_adx(T[0], 50);
+-	mul_eltfp25519_1w_adx(T[0], T[0], T[3]);
+-	copy_eltfp25519_1w(T[2], T[0]);
+-	sqrn_eltfp25519_1w_adx(T[2], 100);
+-	mul_eltfp25519_1w_adx(T[2], T[2], T[0]);
+-	sqrn_eltfp25519_1w_adx(T[2], 50);
+-	mul_eltfp25519_1w_adx(T[2], T[2], T[3]);
+-	sqrn_eltfp25519_1w_adx(T[2], 5);
+-	mul_eltfp25519_1w_adx(T[1], T[1], T[2]);
+-
+-	memzero_explicit(&m, sizeof(m));
+-}
+-
+-static void inv_eltfp25519_1w_bmi2(u64 *const c, const u64 *const a)
+-{
+-	struct {
+-		eltfp25519_1w_buffer buffer;
+-		eltfp25519_1w x0, x1, x2;
+-	} __aligned(32) m;
+-	u64 *T[5];
+-
+-	T[0] = m.x0;
+-	T[1] = c; /* x^(-1) */
+-	T[2] = m.x1;
+-	T[3] = m.x2;
+-
+-	copy_eltfp25519_1w(T[1], a);
+-	sqrn_eltfp25519_1w_bmi2(T[1], 1);
+-	copy_eltfp25519_1w(T[2], T[1]);
+-	sqrn_eltfp25519_1w_bmi2(T[2], 2);
+-	mul_eltfp25519_1w_bmi2(T[0], a, T[2]);
+-	mul_eltfp25519_1w_bmi2(T[1], T[1], T[0]);
+-	copy_eltfp25519_1w(T[2], T[1]);
+-	sqrn_eltfp25519_1w_bmi2(T[2], 1);
+-	mul_eltfp25519_1w_bmi2(T[0], T[0], T[2]);
+-	copy_eltfp25519_1w(T[2], T[0]);
+-	sqrn_eltfp25519_1w_bmi2(T[2], 5);
+-	mul_eltfp25519_1w_bmi2(T[0], T[0], T[2]);
+-	copy_eltfp25519_1w(T[2], T[0]);
+-	sqrn_eltfp25519_1w_bmi2(T[2], 10);
+-	mul_eltfp25519_1w_bmi2(T[2], T[2], T[0]);
+-	copy_eltfp25519_1w(T[3], T[2]);
+-	sqrn_eltfp25519_1w_bmi2(T[3], 20);
+-	mul_eltfp25519_1w_bmi2(T[3], T[3], T[2]);
+-	sqrn_eltfp25519_1w_bmi2(T[3], 10);
+-	mul_eltfp25519_1w_bmi2(T[3], T[3], T[0]);
+-	copy_eltfp25519_1w(T[0], T[3]);
+-	sqrn_eltfp25519_1w_bmi2(T[0], 50);
+-	mul_eltfp25519_1w_bmi2(T[0], T[0], T[3]);
+-	copy_eltfp25519_1w(T[2], T[0]);
+-	sqrn_eltfp25519_1w_bmi2(T[2], 100);
+-	mul_eltfp25519_1w_bmi2(T[2], T[2], T[0]);
+-	sqrn_eltfp25519_1w_bmi2(T[2], 50);
+-	mul_eltfp25519_1w_bmi2(T[2], T[2], T[3]);
+-	sqrn_eltfp25519_1w_bmi2(T[2], 5);
+-	mul_eltfp25519_1w_bmi2(T[1], T[1], T[2]);
++		/* Invert the polarity of bit to match cmov expectations */
++		"  add $18446744073709551615, %0;"
+ 
+-	memzero_explicit(&m, sizeof(m));
++		/* cswap p1[0], p2[0] */
++		"  movq 0(%1), %%r8;"
++		"  movq 0(%2), %%r9;"
++		"  mov %%r8, %%r10;"
++		"  cmovc %%r9, %%r8;"
++		"  cmovc %%r10, %%r9;"
++		"  movq %%r8, 0(%1);"
++		"  movq %%r9, 0(%2);"
++
++		/* cswap p1[1], p2[1] */
++		"  movq 8(%1), %%r8;"
++		"  movq 8(%2), %%r9;"
++		"  mov %%r8, %%r10;"
++		"  cmovc %%r9, %%r8;"
++		"  cmovc %%r10, %%r9;"
++		"  movq %%r8, 8(%1);"
++		"  movq %%r9, 8(%2);"
++
++		/* cswap p1[2], p2[2] */
++		"  movq 16(%1), %%r8;"
++		"  movq 16(%2), %%r9;"
++		"  mov %%r8, %%r10;"
++		"  cmovc %%r9, %%r8;"
++		"  cmovc %%r10, %%r9;"
++		"  movq %%r8, 16(%1);"
++		"  movq %%r9, 16(%2);"
++
++		/* cswap p1[3], p2[3] */
++		"  movq 24(%1), %%r8;"
++		"  movq 24(%2), %%r9;"
++		"  mov %%r8, %%r10;"
++		"  cmovc %%r9, %%r8;"
++		"  cmovc %%r10, %%r9;"
++		"  movq %%r8, 24(%1);"
++		"  movq %%r9, 24(%2);"
++
++		/* cswap p1[4], p2[4] */
++		"  movq 32(%1), %%r8;"
++		"  movq 32(%2), %%r9;"
++		"  mov %%r8, %%r10;"
++		"  cmovc %%r9, %%r8;"
++		"  cmovc %%r10, %%r9;"
++		"  movq %%r8, 32(%1);"
++		"  movq %%r9, 32(%2);"
++
++		/* cswap p1[5], p2[5] */
++		"  movq 40(%1), %%r8;"
++		"  movq 40(%2), %%r9;"
++		"  mov %%r8, %%r10;"
++		"  cmovc %%r9, %%r8;"
++		"  cmovc %%r10, %%r9;"
++		"  movq %%r8, 40(%1);"
++		"  movq %%r9, 40(%2);"
++
++		/* cswap p1[6], p2[6] */
++		"  movq 48(%1), %%r8;"
++		"  movq 48(%2), %%r9;"
++		"  mov %%r8, %%r10;"
++		"  cmovc %%r9, %%r8;"
++		"  cmovc %%r10, %%r9;"
++		"  movq %%r8, 48(%1);"
++		"  movq %%r9, 48(%2);"
++
++		/* cswap p1[7], p2[7] */
++		"  movq 56(%1), %%r8;"
++		"  movq 56(%2), %%r9;"
++		"  mov %%r8, %%r10;"
++		"  cmovc %%r9, %%r8;"
++		"  cmovc %%r10, %%r9;"
++		"  movq %%r8, 56(%1);"
++		"  movq %%r9, 56(%2);"
++	: "+&r" (bit)
++	: "r" (p1), "r" (p2)
++	: "%r8", "%r9", "%r10", "memory", "cc"
++	);
+ }
+ 
+-/* Given c, a 256-bit number, fred_eltfp25519_1w updates c
+- * with a number such that 0 <= C < 2**255-19.
+- */
+-static __always_inline void fred_eltfp25519_1w(u64 *const c)
++/* Computes the square of a field element: out <- f * f
++ * Uses the 8-element buffer tmp for intermediate results */
++static inline void fsqr(u64 *out, const u64 *f, u64 *tmp)
+ {
+-	u64 tmp0 = 38, tmp1 = 19;
+ 	asm volatile(
+-		"btrq   $63,    %3 ;" /* Put bit 255 in carry flag and clear */
+-		"cmovncl %k5,   %k4 ;" /* c[255] ? 38 : 19 */
+-
+-		/* Add either 19 or 38 to c */
+-		"addq    %4,   %0 ;"
+-		"adcq    $0,   %1 ;"
+-		"adcq    $0,   %2 ;"
+-		"adcq    $0,   %3 ;"
+-
+-		/* Test for bit 255 again; only triggered on overflow modulo 2^255-19 */
+-		"movl    $0,  %k4 ;"
+-		"cmovnsl %k5,  %k4 ;" /* c[255] ? 0 : 19 */
+-		"btrq   $63,   %3 ;" /* Clear bit 255 */
+-
+-		/* Subtract 19 if necessary */
+-		"subq    %4,   %0 ;"
+-		"sbbq    $0,   %1 ;"
+-		"sbbq    $0,   %2 ;"
+-		"sbbq    $0,   %3 ;"
+-
+-		: "+r"(c[0]), "+r"(c[1]), "+r"(c[2]), "+r"(c[3]), "+r"(tmp0),
+-		  "+r"(tmp1)
+-		:
+-		: "memory", "cc");
+-}
++		/* Compute the raw multiplication: tmp <- f * f */
+ 
+-static __always_inline void cswap(u8 bit, u64 *const px, u64 *const py)
+-{
+-	u64 temp;
+-	asm volatile(
+-		"test %9, %9 ;"
+-		"movq %0, %8 ;"
+-		"cmovnzq %4, %0 ;"
+-		"cmovnzq %8, %4 ;"
+-		"movq %1, %8 ;"
+-		"cmovnzq %5, %1 ;"
+-		"cmovnzq %8, %5 ;"
+-		"movq %2, %8 ;"
+-		"cmovnzq %6, %2 ;"
+-		"cmovnzq %8, %6 ;"
+-		"movq %3, %8 ;"
+-		"cmovnzq %7, %3 ;"
+-		"cmovnzq %8, %7 ;"
+-		: "+r"(px[0]), "+r"(px[1]), "+r"(px[2]), "+r"(px[3]),
+-		  "+r"(py[0]), "+r"(py[1]), "+r"(py[2]), "+r"(py[3]),
+-		  "=r"(temp)
+-		: "r"(bit)
+-		: "cc"
++		/* Step 1: Compute all partial products */
++		"  movq 0(%1), %%rdx;"                                       /* f[0] */
++		"  mulxq 8(%1), %%r8, %%r14;"      "  xor %%r15, %%r15;"     /* f[1]*f[0] */
++		"  mulxq 16(%1), %%r9, %%r10;"     "  adcx %%r14, %%r9;"     /* f[2]*f[0] */
++		"  mulxq 24(%1), %%rax, %%rcx;"    "  adcx %%rax, %%r10;"    /* f[3]*f[0] */
++		"  movq 24(%1), %%rdx;"                                      /* f[3] */
++		"  mulxq 8(%1), %%r11, %%r12;"     "  adcx %%rcx, %%r11;"    /* f[1]*f[3] */
++		"  mulxq 16(%1), %%rax, %%r13;"    "  adcx %%rax, %%r12;"    /* f[2]*f[3] */
++		"  movq 8(%1), %%rdx;"             "  adcx %%r15, %%r13;"    /* f1 */
++		"  mulxq 16(%1), %%rax, %%rcx;"    "  mov $0, %%r14;"        /* f[2]*f[1] */
++
++		/* Step 2: Compute two parallel carry chains */
++		"  xor %%r15, %%r15;"
++		"  adox %%rax, %%r10;"
++		"  adcx %%r8, %%r8;"
++		"  adox %%rcx, %%r11;"
++		"  adcx %%r9, %%r9;"
++		"  adox %%r15, %%r12;"
++		"  adcx %%r10, %%r10;"
++		"  adox %%r15, %%r13;"
++		"  adcx %%r11, %%r11;"
++		"  adox %%r15, %%r14;"
++		"  adcx %%r12, %%r12;"
++		"  adcx %%r13, %%r13;"
++		"  adcx %%r14, %%r14;"
++
++		/* Step 3: Compute intermediate squares */
++		"  movq 0(%1), %%rdx;"     "  mulx %%rdx, %%rax, %%rcx;"    /* f[0]^2 */
++		                           "  movq %%rax, 0(%0);"
++		"  add %%rcx, %%r8;"       "  movq %%r8, 8(%0);"
++		"  movq 8(%1), %%rdx;"     "  mulx %%rdx, %%rax, %%rcx;"    /* f[1]^2 */
++		"  adcx %%rax, %%r9;"      "  movq %%r9, 16(%0);"
++		"  adcx %%rcx, %%r10;"     "  movq %%r10, 24(%0);"
++		"  movq 16(%1), %%rdx;"    "  mulx %%rdx, %%rax, %%rcx;"    /* f[2]^2 */
++		"  adcx %%rax, %%r11;"     "  movq %%r11, 32(%0);"
++		"  adcx %%rcx, %%r12;"     "  movq %%r12, 40(%0);"
++		"  movq 24(%1), %%rdx;"    "  mulx %%rdx, %%rax, %%rcx;"    /* f[3]^2 */
++		"  adcx %%rax, %%r13;"     "  movq %%r13, 48(%0);"
++		"  adcx %%rcx, %%r14;"     "  movq %%r14, 56(%0);"
++
++		/* Line up pointers */
++		"  mov %0, %1;"
++		"  mov %2, %0;"
++
++		/* Wrap the result back into the field */
++
++		/* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */
++		"  mov $38, %%rdx;"
++		"  mulxq 32(%1), %%r8, %%r13;"
++		"  xor %%rcx, %%rcx;"
++		"  adoxq 0(%1), %%r8;"
++		"  mulxq 40(%1), %%r9, %%r12;"
++		"  adcx %%r13, %%r9;"
++		"  adoxq 8(%1), %%r9;"
++		"  mulxq 48(%1), %%r10, %%r13;"
++		"  adcx %%r12, %%r10;"
++		"  adoxq 16(%1), %%r10;"
++		"  mulxq 56(%1), %%r11, %%rax;"
++		"  adcx %%r13, %%r11;"
++		"  adoxq 24(%1), %%r11;"
++		"  adcx %%rcx, %%rax;"
++		"  adox %%rcx, %%rax;"
++		"  imul %%rdx, %%rax;"
++
++		/* Step 2: Fold the carry back into dst */
++		"  add %%rax, %%r8;"
++		"  adcx %%rcx, %%r9;"
++		"  movq %%r9, 8(%0);"
++		"  adcx %%rcx, %%r10;"
++		"  movq %%r10, 16(%0);"
++		"  adcx %%rcx, %%r11;"
++		"  movq %%r11, 24(%0);"
++
++		/* Step 3: Fold the carry bit back in; guaranteed not to carry at this point */
++		"  mov $0, %%rax;"
++		"  cmovc %%rdx, %%rax;"
++		"  add %%rax, %%r8;"
++		"  movq %%r8, 0(%0);"
++	: "+&r" (tmp), "+&r" (f), "+&r" (out)
++	:
++	: "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "memory", "cc"
+ 	);
+ }
+ 
+-static __always_inline void cselect(u8 bit, u64 *const px, const u64 *const py)
++/* Computes two field squarings:
++ * out[0] <- f[0] * f[0]
++ * out[1] <- f[1] * f[1]
++ * Uses the 16-element buffer tmp for intermediate results */
++static inline void fsqr2(u64 *out, const u64 *f, u64 *tmp)
+ {
+ 	asm volatile(
+-		"test %4, %4 ;"
+-		"cmovnzq %5, %0 ;"
+-		"cmovnzq %6, %1 ;"
+-		"cmovnzq %7, %2 ;"
+-		"cmovnzq %8, %3 ;"
+-		: "+r"(px[0]), "+r"(px[1]), "+r"(px[2]), "+r"(px[3])
+-		: "r"(bit), "rm"(py[0]), "rm"(py[1]), "rm"(py[2]), "rm"(py[3])
+-		: "cc"
++		/* Step 1: Compute all partial products */
++		"  movq 0(%1), %%rdx;"                                       /* f[0] */
++		"  mulxq 8(%1), %%r8, %%r14;"      "  xor %%r15, %%r15;"     /* f[1]*f[0] */
++		"  mulxq 16(%1), %%r9, %%r10;"     "  adcx %%r14, %%r9;"     /* f[2]*f[0] */
++		"  mulxq 24(%1), %%rax, %%rcx;"    "  adcx %%rax, %%r10;"    /* f[3]*f[0] */
++		"  movq 24(%1), %%rdx;"                                      /* f[3] */
++		"  mulxq 8(%1), %%r11, %%r12;"     "  adcx %%rcx, %%r11;"    /* f[1]*f[3] */
++		"  mulxq 16(%1), %%rax, %%r13;"    "  adcx %%rax, %%r12;"    /* f[2]*f[3] */
++		"  movq 8(%1), %%rdx;"             "  adcx %%r15, %%r13;"    /* f1 */
++		"  mulxq 16(%1), %%rax, %%rcx;"    "  mov $0, %%r14;"        /* f[2]*f[1] */
++
++		/* Step 2: Compute two parallel carry chains */
++		"  xor %%r15, %%r15;"
++		"  adox %%rax, %%r10;"
++		"  adcx %%r8, %%r8;"
++		"  adox %%rcx, %%r11;"
++		"  adcx %%r9, %%r9;"
++		"  adox %%r15, %%r12;"
++		"  adcx %%r10, %%r10;"
++		"  adox %%r15, %%r13;"
++		"  adcx %%r11, %%r11;"
++		"  adox %%r15, %%r14;"
++		"  adcx %%r12, %%r12;"
++		"  adcx %%r13, %%r13;"
++		"  adcx %%r14, %%r14;"
++
++		/* Step 3: Compute intermediate squares */
++		"  movq 0(%1), %%rdx;"     "  mulx %%rdx, %%rax, %%rcx;"    /* f[0]^2 */
++		                           "  movq %%rax, 0(%0);"
++		"  add %%rcx, %%r8;"       "  movq %%r8, 8(%0);"
++		"  movq 8(%1), %%rdx;"     "  mulx %%rdx, %%rax, %%rcx;"    /* f[1]^2 */
++		"  adcx %%rax, %%r9;"      "  movq %%r9, 16(%0);"
++		"  adcx %%rcx, %%r10;"     "  movq %%r10, 24(%0);"
++		"  movq 16(%1), %%rdx;"    "  mulx %%rdx, %%rax, %%rcx;"    /* f[2]^2 */
++		"  adcx %%rax, %%r11;"     "  movq %%r11, 32(%0);"
++		"  adcx %%rcx, %%r12;"     "  movq %%r12, 40(%0);"
++		"  movq 24(%1), %%rdx;"    "  mulx %%rdx, %%rax, %%rcx;"    /* f[3]^2 */
++		"  adcx %%rax, %%r13;"     "  movq %%r13, 48(%0);"
++		"  adcx %%rcx, %%r14;"     "  movq %%r14, 56(%0);"
++
++		/* Step 1: Compute all partial products */
++		"  movq 32(%1), %%rdx;"                                       /* f[0] */
++		"  mulxq 40(%1), %%r8, %%r14;"      "  xor %%r15, %%r15;"     /* f[1]*f[0] */
++		"  mulxq 48(%1), %%r9, %%r10;"     "  adcx %%r14, %%r9;"     /* f[2]*f[0] */
++		"  mulxq 56(%1), %%rax, %%rcx;"    "  adcx %%rax, %%r10;"    /* f[3]*f[0] */
++		"  movq 56(%1), %%rdx;"                                      /* f[3] */
++		"  mulxq 40(%1), %%r11, %%r12;"     "  adcx %%rcx, %%r11;"    /* f[1]*f[3] */
++		"  mulxq 48(%1), %%rax, %%r13;"    "  adcx %%rax, %%r12;"    /* f[2]*f[3] */
++		"  movq 40(%1), %%rdx;"             "  adcx %%r15, %%r13;"    /* f1 */
++		"  mulxq 48(%1), %%rax, %%rcx;"    "  mov $0, %%r14;"        /* f[2]*f[1] */
++
++		/* Step 2: Compute two parallel carry chains */
++		"  xor %%r15, %%r15;"
++		"  adox %%rax, %%r10;"
++		"  adcx %%r8, %%r8;"
++		"  adox %%rcx, %%r11;"
++		"  adcx %%r9, %%r9;"
++		"  adox %%r15, %%r12;"
++		"  adcx %%r10, %%r10;"
++		"  adox %%r15, %%r13;"
++		"  adcx %%r11, %%r11;"
++		"  adox %%r15, %%r14;"
++		"  adcx %%r12, %%r12;"
++		"  adcx %%r13, %%r13;"
++		"  adcx %%r14, %%r14;"
++
++		/* Step 3: Compute intermediate squares */
++		"  movq 32(%1), %%rdx;"     "  mulx %%rdx, %%rax, %%rcx;"    /* f[0]^2 */
++		                           "  movq %%rax, 64(%0);"
++		"  add %%rcx, %%r8;"       "  movq %%r8, 72(%0);"
++		"  movq 40(%1), %%rdx;"     "  mulx %%rdx, %%rax, %%rcx;"    /* f[1]^2 */
++		"  adcx %%rax, %%r9;"      "  movq %%r9, 80(%0);"
++		"  adcx %%rcx, %%r10;"     "  movq %%r10, 88(%0);"
++		"  movq 48(%1), %%rdx;"    "  mulx %%rdx, %%rax, %%rcx;"    /* f[2]^2 */
++		"  adcx %%rax, %%r11;"     "  movq %%r11, 96(%0);"
++		"  adcx %%rcx, %%r12;"     "  movq %%r12, 104(%0);"
++		"  movq 56(%1), %%rdx;"    "  mulx %%rdx, %%rax, %%rcx;"    /* f[3]^2 */
++		"  adcx %%rax, %%r13;"     "  movq %%r13, 112(%0);"
++		"  adcx %%rcx, %%r14;"     "  movq %%r14, 120(%0);"
++
++		/* Line up pointers */
++		"  mov %0, %1;"
++		"  mov %2, %0;"
++
++		/* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */
++		"  mov $38, %%rdx;"
++		"  mulxq 32(%1), %%r8, %%r13;"
++		"  xor %%rcx, %%rcx;"
++		"  adoxq 0(%1), %%r8;"
++		"  mulxq 40(%1), %%r9, %%r12;"
++		"  adcx %%r13, %%r9;"
++		"  adoxq 8(%1), %%r9;"
++		"  mulxq 48(%1), %%r10, %%r13;"
++		"  adcx %%r12, %%r10;"
++		"  adoxq 16(%1), %%r10;"
++		"  mulxq 56(%1), %%r11, %%rax;"
++		"  adcx %%r13, %%r11;"
++		"  adoxq 24(%1), %%r11;"
++		"  adcx %%rcx, %%rax;"
++		"  adox %%rcx, %%rax;"
++		"  imul %%rdx, %%rax;"
++
++		/* Step 2: Fold the carry back into dst */
++		"  add %%rax, %%r8;"
++		"  adcx %%rcx, %%r9;"
++		"  movq %%r9, 8(%0);"
++		"  adcx %%rcx, %%r10;"
++		"  movq %%r10, 16(%0);"
++		"  adcx %%rcx, %%r11;"
++		"  movq %%r11, 24(%0);"
++
++		/* Step 3: Fold the carry bit back in; guaranteed not to carry at this point */
++		"  mov $0, %%rax;"
++		"  cmovc %%rdx, %%rax;"
++		"  add %%rax, %%r8;"
++		"  movq %%r8, 0(%0);"
++
++		/* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */
++		"  mov $38, %%rdx;"
++		"  mulxq 96(%1), %%r8, %%r13;"
++		"  xor %%rcx, %%rcx;"
++		"  adoxq 64(%1), %%r8;"
++		"  mulxq 104(%1), %%r9, %%r12;"
++		"  adcx %%r13, %%r9;"
++		"  adoxq 72(%1), %%r9;"
++		"  mulxq 112(%1), %%r10, %%r13;"
++		"  adcx %%r12, %%r10;"
++		"  adoxq 80(%1), %%r10;"
++		"  mulxq 120(%1), %%r11, %%rax;"
++		"  adcx %%r13, %%r11;"
++		"  adoxq 88(%1), %%r11;"
++		"  adcx %%rcx, %%rax;"
++		"  adox %%rcx, %%rax;"
++		"  imul %%rdx, %%rax;"
++
++		/* Step 2: Fold the carry back into dst */
++		"  add %%rax, %%r8;"
++		"  adcx %%rcx, %%r9;"
++		"  movq %%r9, 40(%0);"
++		"  adcx %%rcx, %%r10;"
++		"  movq %%r10, 48(%0);"
++		"  adcx %%rcx, %%r11;"
++		"  movq %%r11, 56(%0);"
++
++		/* Step 3: Fold the carry bit back in; guaranteed not to carry at this point */
++		"  mov $0, %%rax;"
++		"  cmovc %%rdx, %%rax;"
++		"  add %%rax, %%r8;"
++		"  movq %%r8, 32(%0);"
++	: "+&r" (tmp), "+&r" (f), "+&r" (out)
++	:
++	: "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "memory", "cc"
+ 	);
+ }
+ 
+-static void curve25519_adx(u8 shared[CURVE25519_KEY_SIZE],
+-			   const u8 private_key[CURVE25519_KEY_SIZE],
+-			   const u8 session_key[CURVE25519_KEY_SIZE])
+-{
+-	struct {
+-		u64 buffer[4 * NUM_WORDS_ELTFP25519];
+-		u64 coordinates[4 * NUM_WORDS_ELTFP25519];
+-		u64 workspace[6 * NUM_WORDS_ELTFP25519];
+-		u8 session[CURVE25519_KEY_SIZE];
+-		u8 private[CURVE25519_KEY_SIZE];
+-	} __aligned(32) m;
+-
+-	int i = 0, j = 0;
+-	u64 prev = 0;
+-	u64 *const X1 = (u64 *)m.session;
+-	u64 *const key = (u64 *)m.private;
+-	u64 *const Px = m.coordinates + 0;
+-	u64 *const Pz = m.coordinates + 4;
+-	u64 *const Qx = m.coordinates + 8;
+-	u64 *const Qz = m.coordinates + 12;
+-	u64 *const X2 = Qx;
+-	u64 *const Z2 = Qz;
+-	u64 *const X3 = Px;
+-	u64 *const Z3 = Pz;
+-	u64 *const X2Z2 = Qx;
+-	u64 *const X3Z3 = Px;
+-
+-	u64 *const A = m.workspace + 0;
+-	u64 *const B = m.workspace + 4;
+-	u64 *const D = m.workspace + 8;
+-	u64 *const C = m.workspace + 12;
+-	u64 *const DA = m.workspace + 16;
+-	u64 *const CB = m.workspace + 20;
+-	u64 *const AB = A;
+-	u64 *const DC = D;
+-	u64 *const DACB = DA;
+-
+-	memcpy(m.private, private_key, sizeof(m.private));
+-	memcpy(m.session, session_key, sizeof(m.session));
+-
+-	curve25519_clamp_secret(m.private);
+-
+-	/* As in the draft:
+-	 * When receiving such an array, implementations of curve25519
+-	 * MUST mask the most-significant bit in the final byte. This
+-	 * is done to preserve compatibility with point formats which
+-	 * reserve the sign bit for use in other protocols and to
+-	 * increase resistance to implementation fingerprinting
+-	 */
+-	m.session[CURVE25519_KEY_SIZE - 1] &= (1 << (255 % 8)) - 1;
+-
+-	copy_eltfp25519_1w(Px, X1);
+-	setzero_eltfp25519_1w(Pz);
+-	setzero_eltfp25519_1w(Qx);
+-	setzero_eltfp25519_1w(Qz);
+-
+-	Pz[0] = 1;
+-	Qx[0] = 1;
+-
+-	/* main-loop */
+-	prev = 0;
+-	j = 62;
+-	for (i = 3; i >= 0; --i) {
+-		while (j >= 0) {
+-			u64 bit = (key[i] >> j) & 0x1;
+-			u64 swap = bit ^ prev;
+-			prev = bit;
+-
+-			add_eltfp25519_1w_adx(A, X2, Z2);	/* A = (X2+Z2) */
+-			sub_eltfp25519_1w(B, X2, Z2);		/* B = (X2-Z2) */
+-			add_eltfp25519_1w_adx(C, X3, Z3);	/* C = (X3+Z3) */
+-			sub_eltfp25519_1w(D, X3, Z3);		/* D = (X3-Z3) */
+-			mul_eltfp25519_2w_adx(DACB, AB, DC);	/* [DA|CB] = [A|B]*[D|C] */
+-
+-			cselect(swap, A, C);
+-			cselect(swap, B, D);
+-
+-			sqr_eltfp25519_2w_adx(AB);		/* [AA|BB] = [A^2|B^2] */
+-			add_eltfp25519_1w_adx(X3, DA, CB);	/* X3 = (DA+CB) */
+-			sub_eltfp25519_1w(Z3, DA, CB);		/* Z3 = (DA-CB) */
+-			sqr_eltfp25519_2w_adx(X3Z3);		/* [X3|Z3] = [(DA+CB)|(DA+CB)]^2 */
+-
+-			copy_eltfp25519_1w(X2, B);		/* X2 = B^2 */
+-			sub_eltfp25519_1w(Z2, A, B);		/* Z2 = E = AA-BB */
+-
+-			mul_a24_eltfp25519_1w(B, Z2);		/* B = a24*E */
+-			add_eltfp25519_1w_adx(B, B, X2);	/* B = a24*E+B */
+-			mul_eltfp25519_2w_adx(X2Z2, X2Z2, AB);	/* [X2|Z2] = [B|E]*[A|a24*E+B] */
+-			mul_eltfp25519_1w_adx(Z3, Z3, X1);	/* Z3 = Z3*X1 */
+-			--j;
+-		}
+-		j = 63;
+-	}
+-
+-	inv_eltfp25519_1w_adx(A, Qz);
+-	mul_eltfp25519_1w_adx((u64 *)shared, Qx, A);
+-	fred_eltfp25519_1w((u64 *)shared);
+-
+-	memzero_explicit(&m, sizeof(m));
+-}
+-
+-static void curve25519_adx_base(u8 session_key[CURVE25519_KEY_SIZE],
+-				const u8 private_key[CURVE25519_KEY_SIZE])
++static void point_add_and_double(u64 *q, u64 *p01_tmp1, u64 *tmp2)
+ {
+-	struct {
+-		u64 buffer[4 * NUM_WORDS_ELTFP25519];
+-		u64 coordinates[4 * NUM_WORDS_ELTFP25519];
+-		u64 workspace[4 * NUM_WORDS_ELTFP25519];
+-		u8 private[CURVE25519_KEY_SIZE];
+-	} __aligned(32) m;
+-
+-	const int ite[4] = { 64, 64, 64, 63 };
+-	const int q = 3;
+-	u64 swap = 1;
+-
+-	int i = 0, j = 0, k = 0;
+-	u64 *const key = (u64 *)m.private;
+-	u64 *const Ur1 = m.coordinates + 0;
+-	u64 *const Zr1 = m.coordinates + 4;
+-	u64 *const Ur2 = m.coordinates + 8;
+-	u64 *const Zr2 = m.coordinates + 12;
+-
+-	u64 *const UZr1 = m.coordinates + 0;
+-	u64 *const ZUr2 = m.coordinates + 8;
+-
+-	u64 *const A = m.workspace + 0;
+-	u64 *const B = m.workspace + 4;
+-	u64 *const C = m.workspace + 8;
+-	u64 *const D = m.workspace + 12;
+-
+-	u64 *const AB = m.workspace + 0;
+-	u64 *const CD = m.workspace + 8;
+-
+-	const u64 *const P = table_ladder_8k;
+-
+-	memcpy(m.private, private_key, sizeof(m.private));
+-
+-	curve25519_clamp_secret(m.private);
+-
+-	setzero_eltfp25519_1w(Ur1);
+-	setzero_eltfp25519_1w(Zr1);
+-	setzero_eltfp25519_1w(Zr2);
+-	Ur1[0] = 1;
+-	Zr1[0] = 1;
+-	Zr2[0] = 1;
+-
+-	/* G-S */
+-	Ur2[3] = 0x1eaecdeee27cab34UL;
+-	Ur2[2] = 0xadc7a0b9235d48e2UL;
+-	Ur2[1] = 0xbbf095ae14b2edf8UL;
+-	Ur2[0] = 0x7e94e1fec82faabdUL;
+-
+-	/* main-loop */
+-	j = q;
+-	for (i = 0; i < NUM_WORDS_ELTFP25519; ++i) {
+-		while (j < ite[i]) {
+-			u64 bit = (key[i] >> j) & 0x1;
+-			k = (64 * i + j - q);
+-			swap = swap ^ bit;
+-			cswap(swap, Ur1, Ur2);
+-			cswap(swap, Zr1, Zr2);
+-			swap = bit;
+-			/* Addition */
+-			sub_eltfp25519_1w(B, Ur1, Zr1);		/* B = Ur1-Zr1 */
+-			add_eltfp25519_1w_adx(A, Ur1, Zr1);	/* A = Ur1+Zr1 */
+-			mul_eltfp25519_1w_adx(C, &P[4 * k], B);	/* C = M0-B */
+-			sub_eltfp25519_1w(B, A, C);		/* B = (Ur1+Zr1) - M*(Ur1-Zr1) */
+-			add_eltfp25519_1w_adx(A, A, C);		/* A = (Ur1+Zr1) + M*(Ur1-Zr1) */
+-			sqr_eltfp25519_2w_adx(AB);		/* A = A^2      |  B = B^2 */
+-			mul_eltfp25519_2w_adx(UZr1, ZUr2, AB);	/* Ur1 = Zr2*A  |  Zr1 = Ur2*B */
+-			++j;
++	u64 *nq = p01_tmp1;
++	u64 *nq_p1 = p01_tmp1 + (u32)8U;
++	u64 *tmp1 = p01_tmp1 + (u32)16U;
++	u64 *x1 = q;
++	u64 *x2 = nq;
++	u64 *z2 = nq + (u32)4U;
++	u64 *z3 = nq_p1 + (u32)4U;
++	u64 *a = tmp1;
++	u64 *b = tmp1 + (u32)4U;
++	u64 *ab = tmp1;
++	u64 *dc = tmp1 + (u32)8U;
++	u64 *x3;
++	u64 *z31;
++	u64 *d0;
++	u64 *c0;
++	u64 *a1;
++	u64 *b1;
++	u64 *d;
++	u64 *c;
++	u64 *ab1;
++	u64 *dc1;
++	fadd(a, x2, z2);
++	fsub(b, x2, z2);
++	x3 = nq_p1;
++	z31 = nq_p1 + (u32)4U;
++	d0 = dc;
++	c0 = dc + (u32)4U;
++	fadd(c0, x3, z31);
++	fsub(d0, x3, z31);
++	fmul2(dc, dc, ab, tmp2);
++	fadd(x3, d0, c0);
++	fsub(z31, d0, c0);
++	a1 = tmp1;
++	b1 = tmp1 + (u32)4U;
++	d = tmp1 + (u32)8U;
++	c = tmp1 + (u32)12U;
++	ab1 = tmp1;
++	dc1 = tmp1 + (u32)8U;
++	fsqr2(dc1, ab1, tmp2);
++	fsqr2(nq_p1, nq_p1, tmp2);
++	a1[0U] = c[0U];
++	a1[1U] = c[1U];
++	a1[2U] = c[2U];
++	a1[3U] = c[3U];
++	fsub(c, d, c);
++	fmul_scalar(b1, c, (u64)121665U);
++	fadd(b1, b1, d);
++	fmul2(nq, dc1, ab1, tmp2);
++	fmul(z3, z3, x1, tmp2);
++}
++
++static void point_double(u64 *nq, u64 *tmp1, u64 *tmp2)
++{
++	u64 *x2 = nq;
++	u64 *z2 = nq + (u32)4U;
++	u64 *a = tmp1;
++	u64 *b = tmp1 + (u32)4U;
++	u64 *d = tmp1 + (u32)8U;
++	u64 *c = tmp1 + (u32)12U;
++	u64 *ab = tmp1;
++	u64 *dc = tmp1 + (u32)8U;
++	fadd(a, x2, z2);
++	fsub(b, x2, z2);
++	fsqr2(dc, ab, tmp2);
++	a[0U] = c[0U];
++	a[1U] = c[1U];
++	a[2U] = c[2U];
++	a[3U] = c[3U];
++	fsub(c, d, c);
++	fmul_scalar(b, c, (u64)121665U);
++	fadd(b, b, d);
++	fmul2(nq, dc, ab, tmp2);
++}
++
++static void montgomery_ladder(u64 *out, const u8 *key, u64 *init1)
++{
++	u64 tmp2[16U] = { 0U };
++	u64 p01_tmp1_swap[33U] = { 0U };
++	u64 *p0 = p01_tmp1_swap;
++	u64 *p01 = p01_tmp1_swap;
++	u64 *p03 = p01;
++	u64 *p11 = p01 + (u32)8U;
++	u64 *x0;
++	u64 *z0;
++	u64 *p01_tmp1;
++	u64 *p01_tmp11;
++	u64 *nq10;
++	u64 *nq_p11;
++	u64 *swap1;
++	u64 sw0;
++	u64 *nq1;
++	u64 *tmp1;
++	memcpy(p11, init1, (u32)8U * sizeof(init1[0U]));
++	x0 = p03;
++	z0 = p03 + (u32)4U;
++	x0[0U] = (u64)1U;
++	x0[1U] = (u64)0U;
++	x0[2U] = (u64)0U;
++	x0[3U] = (u64)0U;
++	z0[0U] = (u64)0U;
++	z0[1U] = (u64)0U;
++	z0[2U] = (u64)0U;
++	z0[3U] = (u64)0U;
++	p01_tmp1 = p01_tmp1_swap;
++	p01_tmp11 = p01_tmp1_swap;
++	nq10 = p01_tmp1_swap;
++	nq_p11 = p01_tmp1_swap + (u32)8U;
++	swap1 = p01_tmp1_swap + (u32)32U;
++	cswap2((u64)1U, nq10, nq_p11);
++	point_add_and_double(init1, p01_tmp11, tmp2);
++	swap1[0U] = (u64)1U;
++	{
++		u32 i;
++		for (i = (u32)0U; i < (u32)251U; i = i + (u32)1U) {
++			u64 *p01_tmp12 = p01_tmp1_swap;
++			u64 *swap2 = p01_tmp1_swap + (u32)32U;
++			u64 *nq2 = p01_tmp12;
++			u64 *nq_p12 = p01_tmp12 + (u32)8U;
++			u64 bit = (u64)(key[((u32)253U - i) / (u32)8U] >> ((u32)253U - i) % (u32)8U & (u8)1U);
++			u64 sw = swap2[0U] ^ bit;
++			cswap2(sw, nq2, nq_p12);
++			point_add_and_double(init1, p01_tmp12, tmp2);
++			swap2[0U] = bit;
+ 		}
+-		j = 0;
+ 	}
+-
+-	/* Doubling */
+-	for (i = 0; i < q; ++i) {
+-		add_eltfp25519_1w_adx(A, Ur1, Zr1);	/*  A = Ur1+Zr1 */
+-		sub_eltfp25519_1w(B, Ur1, Zr1);		/*  B = Ur1-Zr1 */
+-		sqr_eltfp25519_2w_adx(AB);		/*  A = A**2     B = B**2 */
+-		copy_eltfp25519_1w(C, B);		/*  C = B */
+-		sub_eltfp25519_1w(B, A, B);		/*  B = A-B */
+-		mul_a24_eltfp25519_1w(D, B);		/*  D = my_a24*B */
+-		add_eltfp25519_1w_adx(D, D, C);		/*  D = D+C */
+-		mul_eltfp25519_2w_adx(UZr1, AB, CD);	/*  Ur1 = A*B   Zr1 = Zr1*A */
+-	}
+-
+-	/* Convert to affine coordinates */
+-	inv_eltfp25519_1w_adx(A, Zr1);
+-	mul_eltfp25519_1w_adx((u64 *)session_key, Ur1, A);
+-	fred_eltfp25519_1w((u64 *)session_key);
+-
+-	memzero_explicit(&m, sizeof(m));
+-}
+-
+-static void curve25519_bmi2(u8 shared[CURVE25519_KEY_SIZE],
+-			    const u8 private_key[CURVE25519_KEY_SIZE],
+-			    const u8 session_key[CURVE25519_KEY_SIZE])
+-{
+-	struct {
+-		u64 buffer[4 * NUM_WORDS_ELTFP25519];
+-		u64 coordinates[4 * NUM_WORDS_ELTFP25519];
+-		u64 workspace[6 * NUM_WORDS_ELTFP25519];
+-		u8 session[CURVE25519_KEY_SIZE];
+-		u8 private[CURVE25519_KEY_SIZE];
+-	} __aligned(32) m;
+-
+-	int i = 0, j = 0;
+-	u64 prev = 0;
+-	u64 *const X1 = (u64 *)m.session;
+-	u64 *const key = (u64 *)m.private;
+-	u64 *const Px = m.coordinates + 0;
+-	u64 *const Pz = m.coordinates + 4;
+-	u64 *const Qx = m.coordinates + 8;
+-	u64 *const Qz = m.coordinates + 12;
+-	u64 *const X2 = Qx;
+-	u64 *const Z2 = Qz;
+-	u64 *const X3 = Px;
+-	u64 *const Z3 = Pz;
+-	u64 *const X2Z2 = Qx;
+-	u64 *const X3Z3 = Px;
+-
+-	u64 *const A = m.workspace + 0;
+-	u64 *const B = m.workspace + 4;
+-	u64 *const D = m.workspace + 8;
+-	u64 *const C = m.workspace + 12;
+-	u64 *const DA = m.workspace + 16;
+-	u64 *const CB = m.workspace + 20;
+-	u64 *const AB = A;
+-	u64 *const DC = D;
+-	u64 *const DACB = DA;
+-
+-	memcpy(m.private, private_key, sizeof(m.private));
+-	memcpy(m.session, session_key, sizeof(m.session));
+-
+-	curve25519_clamp_secret(m.private);
+-
+-	/* As in the draft:
+-	 * When receiving such an array, implementations of curve25519
+-	 * MUST mask the most-significant bit in the final byte. This
+-	 * is done to preserve compatibility with point formats which
+-	 * reserve the sign bit for use in other protocols and to
+-	 * increase resistance to implementation fingerprinting
+-	 */
+-	m.session[CURVE25519_KEY_SIZE - 1] &= (1 << (255 % 8)) - 1;
+-
+-	copy_eltfp25519_1w(Px, X1);
+-	setzero_eltfp25519_1w(Pz);
+-	setzero_eltfp25519_1w(Qx);
+-	setzero_eltfp25519_1w(Qz);
+-
+-	Pz[0] = 1;
+-	Qx[0] = 1;
+-
+-	/* main-loop */
+-	prev = 0;
+-	j = 62;
+-	for (i = 3; i >= 0; --i) {
+-		while (j >= 0) {
+-			u64 bit = (key[i] >> j) & 0x1;
+-			u64 swap = bit ^ prev;
+-			prev = bit;
+-
+-			add_eltfp25519_1w_bmi2(A, X2, Z2);	/* A = (X2+Z2) */
+-			sub_eltfp25519_1w(B, X2, Z2);		/* B = (X2-Z2) */
+-			add_eltfp25519_1w_bmi2(C, X3, Z3);	/* C = (X3+Z3) */
+-			sub_eltfp25519_1w(D, X3, Z3);		/* D = (X3-Z3) */
+-			mul_eltfp25519_2w_bmi2(DACB, AB, DC);	/* [DA|CB] = [A|B]*[D|C] */
+-
+-			cselect(swap, A, C);
+-			cselect(swap, B, D);
+-
+-			sqr_eltfp25519_2w_bmi2(AB);		/* [AA|BB] = [A^2|B^2] */
+-			add_eltfp25519_1w_bmi2(X3, DA, CB);	/* X3 = (DA+CB) */
+-			sub_eltfp25519_1w(Z3, DA, CB);		/* Z3 = (DA-CB) */
+-			sqr_eltfp25519_2w_bmi2(X3Z3);		/* [X3|Z3] = [(DA+CB)|(DA+CB)]^2 */
+-
+-			copy_eltfp25519_1w(X2, B);		/* X2 = B^2 */
+-			sub_eltfp25519_1w(Z2, A, B);		/* Z2 = E = AA-BB */
+-
+-			mul_a24_eltfp25519_1w(B, Z2);		/* B = a24*E */
+-			add_eltfp25519_1w_bmi2(B, B, X2);	/* B = a24*E+B */
+-			mul_eltfp25519_2w_bmi2(X2Z2, X2Z2, AB);	/* [X2|Z2] = [B|E]*[A|a24*E+B] */
+-			mul_eltfp25519_1w_bmi2(Z3, Z3, X1);	/* Z3 = Z3*X1 */
+-			--j;
++	sw0 = swap1[0U];
++	cswap2(sw0, nq10, nq_p11);
++	nq1 = p01_tmp1;
++	tmp1 = p01_tmp1 + (u32)16U;
++	point_double(nq1, tmp1, tmp2);
++	point_double(nq1, tmp1, tmp2);
++	point_double(nq1, tmp1, tmp2);
++	memcpy(out, p0, (u32)8U * sizeof(p0[0U]));
++
++	memzero_explicit(tmp2, sizeof(tmp2));
++	memzero_explicit(p01_tmp1_swap, sizeof(p01_tmp1_swap));
++}
++
++static void fsquare_times(u64 *o, const u64 *inp, u64 *tmp, u32 n1)
++{
++	u32 i;
++	fsqr(o, inp, tmp);
++	for (i = (u32)0U; i < n1 - (u32)1U; i = i + (u32)1U)
++		fsqr(o, o, tmp);
++}
++
++static void finv(u64 *o, const u64 *i, u64 *tmp)
++{
++	u64 t1[16U] = { 0U };
++	u64 *a0 = t1;
++	u64 *b = t1 + (u32)4U;
++	u64 *c = t1 + (u32)8U;
++	u64 *t00 = t1 + (u32)12U;
++	u64 *tmp1 = tmp;
++	u64 *a;
++	u64 *t0;
++	fsquare_times(a0, i, tmp1, (u32)1U);
++	fsquare_times(t00, a0, tmp1, (u32)2U);
++	fmul(b, t00, i, tmp);
++	fmul(a0, b, a0, tmp);
++	fsquare_times(t00, a0, tmp1, (u32)1U);
++	fmul(b, t00, b, tmp);
++	fsquare_times(t00, b, tmp1, (u32)5U);
++	fmul(b, t00, b, tmp);
++	fsquare_times(t00, b, tmp1, (u32)10U);
++	fmul(c, t00, b, tmp);
++	fsquare_times(t00, c, tmp1, (u32)20U);
++	fmul(t00, t00, c, tmp);
++	fsquare_times(t00, t00, tmp1, (u32)10U);
++	fmul(b, t00, b, tmp);
++	fsquare_times(t00, b, tmp1, (u32)50U);
++	fmul(c, t00, b, tmp);
++	fsquare_times(t00, c, tmp1, (u32)100U);
++	fmul(t00, t00, c, tmp);
++	fsquare_times(t00, t00, tmp1, (u32)50U);
++	fmul(t00, t00, b, tmp);
++	fsquare_times(t00, t00, tmp1, (u32)5U);
++	a = t1;
++	t0 = t1 + (u32)12U;
++	fmul(o, t0, a, tmp);
++}
++
++static void store_felem(u64 *b, u64 *f)
++{
++	u64 f30 = f[3U];
++	u64 top_bit0 = f30 >> (u32)63U;
++	u64 carry0;
++	u64 f31;
++	u64 top_bit;
++	u64 carry;
++	u64 f0;
++	u64 f1;
++	u64 f2;
++	u64 f3;
++	u64 m0;
++	u64 m1;
++	u64 m2;
++	u64 m3;
++	u64 mask;
++	u64 f0_;
++	u64 f1_;
++	u64 f2_;
++	u64 f3_;
++	u64 o0;
++	u64 o1;
++	u64 o2;
++	u64 o3;
++	f[3U] = f30 & (u64)0x7fffffffffffffffU;
++	carry0 = add_scalar(f, f, (u64)19U * top_bit0);
++	f31 = f[3U];
++	top_bit = f31 >> (u32)63U;
++	f[3U] = f31 & (u64)0x7fffffffffffffffU;
++	carry = add_scalar(f, f, (u64)19U * top_bit);
++	f0 = f[0U];
++	f1 = f[1U];
++	f2 = f[2U];
++	f3 = f[3U];
++	m0 = gte_mask(f0, (u64)0xffffffffffffffedU);
++	m1 = eq_mask(f1, (u64)0xffffffffffffffffU);
++	m2 = eq_mask(f2, (u64)0xffffffffffffffffU);
++	m3 = eq_mask(f3, (u64)0x7fffffffffffffffU);
++	mask = ((m0 & m1) & m2) & m3;
++	f0_ = f0 - (mask & (u64)0xffffffffffffffedU);
++	f1_ = f1 - (mask & (u64)0xffffffffffffffffU);
++	f2_ = f2 - (mask & (u64)0xffffffffffffffffU);
++	f3_ = f3 - (mask & (u64)0x7fffffffffffffffU);
++	o0 = f0_;
++	o1 = f1_;
++	o2 = f2_;
++	o3 = f3_;
++	b[0U] = o0;
++	b[1U] = o1;
++	b[2U] = o2;
++	b[3U] = o3;
++}
++
++static void encode_point(u8 *o, const u64 *i)
++{
++	const u64 *x = i;
++	const u64 *z = i + (u32)4U;
++	u64 tmp[4U] = { 0U };
++	u64 tmp_w[16U] = { 0U };
++	finv(tmp, z, tmp_w);
++	fmul(tmp, tmp, x, tmp_w);
++	store_felem((u64 *)o, tmp);
++}
++
++static void curve25519_ever64(u8 *out, const u8 *priv, const u8 *pub)
++{
++	u64 init1[8U] = { 0U };
++	u64 tmp[4U] = { 0U };
++	u64 tmp3;
++	u64 *x;
++	u64 *z;
++	{
++		u32 i;
++		for (i = (u32)0U; i < (u32)4U; i = i + (u32)1U) {
++			u64 *os = tmp;
++			const u8 *bj = pub + i * (u32)8U;
++			u64 u = *(u64 *)bj;
++			u64 r = u;
++			u64 x0 = r;
++			os[i] = x0;
+ 		}
+-		j = 63;
+ 	}
++	tmp3 = tmp[3U];
++	tmp[3U] = tmp3 & (u64)0x7fffffffffffffffU;
++	x = init1;
++	z = init1 + (u32)4U;
++	z[0U] = (u64)1U;
++	z[1U] = (u64)0U;
++	z[2U] = (u64)0U;
++	z[3U] = (u64)0U;
++	x[0U] = tmp[0U];
++	x[1U] = tmp[1U];
++	x[2U] = tmp[2U];
++	x[3U] = tmp[3U];
++	montgomery_ladder(init1, priv, init1);
++	encode_point(out, init1);
++}
++
++/* The below constants were generated using this sage script:
++ *
++ * #!/usr/bin/env sage
++ * import sys
++ * from sage.all import *
++ * def limbs(n):
++ * 	n = int(n)
++ * 	l = ((n >> 0) % 2^64, (n >> 64) % 2^64, (n >> 128) % 2^64, (n >> 192) % 2^64)
++ * 	return "0x%016xULL, 0x%016xULL, 0x%016xULL, 0x%016xULL" % l
++ * ec = EllipticCurve(GF(2^255 - 19), [0, 486662, 0, 1, 0])
++ * p_minus_s = (ec.lift_x(9) - ec.lift_x(1))[0]
++ * print("static const u64 p_minus_s[] = { %s };\n" % limbs(p_minus_s))
++ * print("static const u64 table_ladder[] = {")
++ * p = ec.lift_x(9)
++ * for i in range(252):
++ * 	l = (p[0] + p[2]) / (p[0] - p[2])
++ * 	print(("\t%s" + ("," if i != 251 else "")) % limbs(l))
++ * 	p = p * 2
++ * print("};")
++ *
++ */
+ 
+-	inv_eltfp25519_1w_bmi2(A, Qz);
+-	mul_eltfp25519_1w_bmi2((u64 *)shared, Qx, A);
+-	fred_eltfp25519_1w((u64 *)shared);
++static const u64 p_minus_s[] = { 0x816b1e0137d48290ULL, 0x440f6a51eb4d1207ULL, 0x52385f46dca2b71dULL, 0x215132111d8354cbULL };
+ 
+-	memzero_explicit(&m, sizeof(m));
+-}
++static const u64 table_ladder[] = {
++	0xfffffffffffffff3ULL, 0xffffffffffffffffULL, 0xffffffffffffffffULL, 0x5fffffffffffffffULL,
++	0x6b8220f416aafe96ULL, 0x82ebeb2b4f566a34ULL, 0xd5a9a5b075a5950fULL, 0x5142b2cf4b2488f4ULL,
++	0x6aaebc750069680cULL, 0x89cf7820a0f99c41ULL, 0x2a58d9183b56d0f4ULL, 0x4b5aca80e36011a4ULL,
++	0x329132348c29745dULL, 0xf4a2e616e1642fd7ULL, 0x1e45bb03ff67bc34ULL, 0x306912d0f42a9b4aULL,
++	0xff886507e6af7154ULL, 0x04f50e13dfeec82fULL, 0xaa512fe82abab5ceULL, 0x174e251a68d5f222ULL,
++	0xcf96700d82028898ULL, 0x1743e3370a2c02c5ULL, 0x379eec98b4e86eaaULL, 0x0c59888a51e0482eULL,
++	0xfbcbf1d699b5d189ULL, 0xacaef0d58e9fdc84ULL, 0xc1c20d06231f7614ULL, 0x2938218da274f972ULL,
++	0xf6af49beff1d7f18ULL, 0xcc541c22387ac9c2ULL, 0x96fcc9ef4015c56bULL, 0x69c1627c690913a9ULL,
++	0x7a86fd2f4733db0eULL, 0xfdb8c4f29e087de9ULL, 0x095e4b1a8ea2a229ULL, 0x1ad7a7c829b37a79ULL,
++	0x342d89cad17ea0c0ULL, 0x67bedda6cced2051ULL, 0x19ca31bf2bb42f74ULL, 0x3df7b4c84980acbbULL,
++	0xa8c6444dc80ad883ULL, 0xb91e440366e3ab85ULL, 0xc215cda00164f6d8ULL, 0x3d867c6ef247e668ULL,
++	0xc7dd582bcc3e658cULL, 0xfd2c4748ee0e5528ULL, 0xa0fd9b95cc9f4f71ULL, 0x7529d871b0675ddfULL,
++	0xb8f568b42d3cbd78ULL, 0x1233011b91f3da82ULL, 0x2dce6ccd4a7c3b62ULL, 0x75e7fc8e9e498603ULL,
++	0x2f4f13f1fcd0b6ecULL, 0xf1a8ca1f29ff7a45ULL, 0xc249c1a72981e29bULL, 0x6ebe0dbb8c83b56aULL,
++	0x7114fa8d170bb222ULL, 0x65a2dcd5bf93935fULL, 0xbdc41f68b59c979aULL, 0x2f0eef79a2ce9289ULL,
++	0x42ecbf0c083c37ceULL, 0x2930bc09ec496322ULL, 0xf294b0c19cfeac0dULL, 0x3780aa4bedfabb80ULL,
++	0x56c17d3e7cead929ULL, 0xe7cb4beb2e5722c5ULL, 0x0ce931732dbfe15aULL, 0x41b883c7621052f8ULL,
++	0xdbf75ca0c3d25350ULL, 0x2936be086eb1e351ULL, 0xc936e03cb4a9b212ULL, 0x1d45bf82322225aaULL,
++	0xe81ab1036a024cc5ULL, 0xe212201c304c9a72ULL, 0xc5d73fba6832b1fcULL, 0x20ffdb5a4d839581ULL,
++	0xa283d367be5d0fadULL, 0x6c2b25ca8b164475ULL, 0x9d4935467caaf22eULL, 0x5166408eee85ff49ULL,
++	0x3c67baa2fab4e361ULL, 0xb3e433c67ef35cefULL, 0x5259729241159b1cULL, 0x6a621892d5b0ab33ULL,
++	0x20b74a387555cdcbULL, 0x532aa10e1208923fULL, 0xeaa17b7762281dd1ULL, 0x61ab3443f05c44bfULL,
++	0x257a6c422324def8ULL, 0x131c6c1017e3cf7fULL, 0x23758739f630a257ULL, 0x295a407a01a78580ULL,
++	0xf8c443246d5da8d9ULL, 0x19d775450c52fa5dULL, 0x2afcfc92731bf83dULL, 0x7d10c8e81b2b4700ULL,
++	0xc8e0271f70baa20bULL, 0x993748867ca63957ULL, 0x5412efb3cb7ed4bbULL, 0x3196d36173e62975ULL,
++	0xde5bcad141c7dffcULL, 0x47cc8cd2b395c848ULL, 0xa34cd942e11af3cbULL, 0x0256dbf2d04ecec2ULL,
++	0x875ab7e94b0e667fULL, 0xcad4dd83c0850d10ULL, 0x47f12e8f4e72c79fULL, 0x5f1a87bb8c85b19bULL,
++	0x7ae9d0b6437f51b8ULL, 0x12c7ce5518879065ULL, 0x2ade09fe5cf77aeeULL, 0x23a05a2f7d2c5627ULL,
++	0x5908e128f17c169aULL, 0xf77498dd8ad0852dULL, 0x74b4c4ceab102f64ULL, 0x183abadd10139845ULL,
++	0xb165ba8daa92aaacULL, 0xd5c5ef9599386705ULL, 0xbe2f8f0cf8fc40d1ULL, 0x2701e635ee204514ULL,
++	0x629fa80020156514ULL, 0xf223868764a8c1ceULL, 0x5b894fff0b3f060eULL, 0x60d9944cf708a3faULL,
++	0xaeea001a1c7a201fULL, 0xebf16a633ee2ce63ULL, 0x6f7709594c7a07e1ULL, 0x79b958150d0208cbULL,
++	0x24b55e5301d410e7ULL, 0xe3a34edff3fdc84dULL, 0xd88768e4904032d8ULL, 0x131384427b3aaeecULL,
++	0x8405e51286234f14ULL, 0x14dc4739adb4c529ULL, 0xb8a2b5b250634ffdULL, 0x2fe2a94ad8a7ff93ULL,
++	0xec5c57efe843faddULL, 0x2843ce40f0bb9918ULL, 0xa4b561d6cf3d6305ULL, 0x743629bde8fb777eULL,
++	0x343edd46bbaf738fULL, 0xed981828b101a651ULL, 0xa401760b882c797aULL, 0x1fc223e28dc88730ULL,
++	0x48604e91fc0fba0eULL, 0xb637f78f052c6fa4ULL, 0x91ccac3d09e9239cULL, 0x23f7eed4437a687cULL,
++	0x5173b1118d9bd800ULL, 0x29d641b63189d4a7ULL, 0xfdbf177988bbc586ULL, 0x2959894fcad81df5ULL,
++	0xaebc8ef3b4bbc899ULL, 0x4148995ab26992b9ULL, 0x24e20b0134f92cfbULL, 0x40d158894a05dee8ULL,
++	0x46b00b1185af76f6ULL, 0x26bac77873187a79ULL, 0x3dc0bf95ab8fff5fULL, 0x2a608bd8945524d7ULL,
++	0x26449588bd446302ULL, 0x7c4bc21c0388439cULL, 0x8e98a4f383bd11b2ULL, 0x26218d7bc9d876b9ULL,
++	0xe3081542997c178aULL, 0x3c2d29a86fb6606fULL, 0x5c217736fa279374ULL, 0x7dde05734afeb1faULL,
++	0x3bf10e3906d42babULL, 0xe4f7803e1980649cULL, 0xe6053bf89595bf7aULL, 0x394faf38da245530ULL,
++	0x7a8efb58896928f4ULL, 0xfbc778e9cc6a113cULL, 0x72670ce330af596fULL, 0x48f222a81d3d6cf7ULL,
++	0xf01fce410d72caa7ULL, 0x5a20ecc7213b5595ULL, 0x7bc21165c1fa1483ULL, 0x07f89ae31da8a741ULL,
++	0x05d2c2b4c6830ff9ULL, 0xd43e330fc6316293ULL, 0xa5a5590a96d3a904ULL, 0x705edb91a65333b6ULL,
++	0x048ee15e0bb9a5f7ULL, 0x3240cfca9e0aaf5dULL, 0x8f4b71ceedc4a40bULL, 0x621c0da3de544a6dULL,
++	0x92872836a08c4091ULL, 0xce8375b010c91445ULL, 0x8a72eb524f276394ULL, 0x2667fcfa7ec83635ULL,
++	0x7f4c173345e8752aULL, 0x061b47feee7079a5ULL, 0x25dd9afa9f86ff34ULL, 0x3780cef5425dc89cULL,
++	0x1a46035a513bb4e9ULL, 0x3e1ef379ac575adaULL, 0xc78c5f1c5fa24b50ULL, 0x321a967634fd9f22ULL,
++	0x946707b8826e27faULL, 0x3dca84d64c506fd0ULL, 0xc189218075e91436ULL, 0x6d9284169b3b8484ULL,
++	0x3a67e840383f2ddfULL, 0x33eec9a30c4f9b75ULL, 0x3ec7c86fa783ef47ULL, 0x26ec449fbac9fbc4ULL,
++	0x5c0f38cba09b9e7dULL, 0x81168cc762a3478cULL, 0x3e23b0d306fc121cULL, 0x5a238aa0a5efdcddULL,
++	0x1ba26121c4ea43ffULL, 0x36f8c77f7c8832b5ULL, 0x88fbea0b0adcf99aULL, 0x5ca9938ec25bebf9ULL,
++	0xd5436a5e51fccda0ULL, 0x1dbc4797c2cd893bULL, 0x19346a65d3224a08ULL, 0x0f5034e49b9af466ULL,
++	0xf23c3967a1e0b96eULL, 0xe58b08fa867a4d88ULL, 0xfb2fabc6a7341679ULL, 0x2a75381eb6026946ULL,
++	0xc80a3be4c19420acULL, 0x66b1f6c681f2b6dcULL, 0x7cf7036761e93388ULL, 0x25abbbd8a660a4c4ULL,
++	0x91ea12ba14fd5198ULL, 0x684950fc4a3cffa9ULL, 0xf826842130f5ad28ULL, 0x3ea988f75301a441ULL,
++	0xc978109a695f8c6fULL, 0x1746eb4a0530c3f3ULL, 0x444d6d77b4459995ULL, 0x75952b8c054e5cc7ULL,
++	0xa3703f7915f4d6aaULL, 0x66c346202f2647d8ULL, 0xd01469df811d644bULL, 0x77fea47d81a5d71fULL,
++	0xc5e9529ef57ca381ULL, 0x6eeeb4b9ce2f881aULL, 0xb6e91a28e8009bd6ULL, 0x4b80be3e9afc3fecULL,
++	0x7e3773c526aed2c5ULL, 0x1b4afcb453c9a49dULL, 0xa920bdd7baffb24dULL, 0x7c54699f122d400eULL,
++	0xef46c8e14fa94bc8ULL, 0xe0b074ce2952ed5eULL, 0xbea450e1dbd885d5ULL, 0x61b68649320f712cULL,
++	0x8a485f7309ccbdd1ULL, 0xbd06320d7d4d1a2dULL, 0x25232973322dbef4ULL, 0x445dc4758c17f770ULL,
++	0xdb0434177cc8933cULL, 0xed6fe82175ea059fULL, 0x1efebefdc053db34ULL, 0x4adbe867c65daf99ULL,
++	0x3acd71a2a90609dfULL, 0xe5e991856dd04050ULL, 0x1ec69b688157c23cULL, 0x697427f6885cfe4dULL,
++	0xd7be7b9b65e1a851ULL, 0xa03d28d522c536ddULL, 0x28399d658fd2b645ULL, 0x49e5b7e17c2641e1ULL,
++	0x6f8c3a98700457a4ULL, 0x5078f0a25ebb6778ULL, 0xd13c3ccbc382960fULL, 0x2e003258a7df84b1ULL,
++	0x8ad1f39be6296a1cULL, 0xc1eeaa652a5fbfb2ULL, 0x33ee0673fd26f3cbULL, 0x59256173a69d2cccULL,
++	0x41ea07aa4e18fc41ULL, 0xd9fc19527c87a51eULL, 0xbdaacb805831ca6fULL, 0x445b652dc916694fULL,
++	0xce92a3a7f2172315ULL, 0x1edc282de11b9964ULL, 0xa1823aafe04c314aULL, 0x790a2d94437cf586ULL,
++	0x71c447fb93f6e009ULL, 0x8922a56722845276ULL, 0xbf70903b204f5169ULL, 0x2f7a89891ba319feULL,
++	0x02a08eb577e2140cULL, 0xed9a4ed4427bdcf4ULL, 0x5253ec44e4323cd1ULL, 0x3e88363c14e9355bULL,
++	0xaa66c14277110b8cULL, 0x1ae0391610a23390ULL, 0x2030bd12c93fc2a2ULL, 0x3ee141579555c7abULL,
++	0x9214de3a6d6e7d41ULL, 0x3ccdd88607f17efeULL, 0x674f1288f8e11217ULL, 0x5682250f329f93d0ULL,
++	0x6cf00b136d2e396eULL, 0x6e4cf86f1014debfULL, 0x5930b1b5bfcc4e83ULL, 0x047069b48aba16b6ULL,
++	0x0d4ce4ab69b20793ULL, 0xb24db91a97d0fb9eULL, 0xcdfa50f54e00d01dULL, 0x221b1085368bddb5ULL,
++	0xe7e59468b1e3d8d2ULL, 0x53c56563bd122f93ULL, 0xeee8a903e0663f09ULL, 0x61efa662cbbe3d42ULL,
++	0x2cf8ddddde6eab2aULL, 0x9bf80ad51435f231ULL, 0x5deadacec9f04973ULL, 0x29275b5d41d29b27ULL,
++	0xcfde0f0895ebf14fULL, 0xb9aab96b054905a7ULL, 0xcae80dd9a1c420fdULL, 0x0a63bf2f1673bbc7ULL,
++	0x092f6e11958fbc8cULL, 0x672a81e804822fadULL, 0xcac8351560d52517ULL, 0x6f3f7722c8f192f8ULL,
++	0xf8ba90ccc2e894b7ULL, 0x2c7557a438ff9f0dULL, 0x894d1d855ae52359ULL, 0x68e122157b743d69ULL,
++	0xd87e5570cfb919f3ULL, 0x3f2cdecd95798db9ULL, 0x2121154710c0a2ceULL, 0x3c66a115246dc5b2ULL,
++	0xcbedc562294ecb72ULL, 0xba7143c36a280b16ULL, 0x9610c2efd4078b67ULL, 0x6144735d946a4b1eULL,
++	0x536f111ed75b3350ULL, 0x0211db8c2041d81bULL, 0xf93cb1000e10413cULL, 0x149dfd3c039e8876ULL,
++	0xd479dde46b63155bULL, 0xb66e15e93c837976ULL, 0xdafde43b1f13e038ULL, 0x5fafda1a2e4b0b35ULL,
++	0x3600bbdf17197581ULL, 0x3972050bbe3cd2c2ULL, 0x5938906dbdd5be86ULL, 0x34fce5e43f9b860fULL,
++	0x75a8a4cd42d14d02ULL, 0x828dabc53441df65ULL, 0x33dcabedd2e131d3ULL, 0x3ebad76fb814d25fULL,
++	0xd4906f566f70e10fULL, 0x5d12f7aa51690f5aULL, 0x45adb16e76cefcf2ULL, 0x01f768aead232999ULL,
++	0x2b6cc77b6248febdULL, 0x3cd30628ec3aaffdULL, 0xce1c0b80d4ef486aULL, 0x4c3bff2ea6f66c23ULL,
++	0x3f2ec4094aeaeb5fULL, 0x61b19b286e372ca7ULL, 0x5eefa966de2a701dULL, 0x23b20565de55e3efULL,
++	0xe301ca5279d58557ULL, 0x07b2d4ce27c2874fULL, 0xa532cd8a9dcf1d67ULL, 0x2a52fee23f2bff56ULL,
++	0x8624efb37cd8663dULL, 0xbbc7ac20ffbd7594ULL, 0x57b85e9c82d37445ULL, 0x7b3052cb86a6ec66ULL,
++	0x3482f0ad2525e91eULL, 0x2cb68043d28edca0ULL, 0xaf4f6d052e1b003aULL, 0x185f8c2529781b0aULL,
++	0xaa41de5bd80ce0d6ULL, 0x9407b2416853e9d6ULL, 0x563ec36e357f4c3aULL, 0x4cc4b8dd0e297bceULL,
++	0xa2fc1a52ffb8730eULL, 0x1811f16e67058e37ULL, 0x10f9a366cddf4ee1ULL, 0x72f4a0c4a0b9f099ULL,
++	0x8c16c06f663f4ea7ULL, 0x693b3af74e970fbaULL, 0x2102e7f1d69ec345ULL, 0x0ba53cbc968a8089ULL,
++	0xca3d9dc7fea15537ULL, 0x4c6824bb51536493ULL, 0xb9886314844006b1ULL, 0x40d2a72ab454cc60ULL,
++	0x5936a1b712570975ULL, 0x91b9d648debda657ULL, 0x3344094bb64330eaULL, 0x006ba10d12ee51d0ULL,
++	0x19228468f5de5d58ULL, 0x0eb12f4c38cc05b0ULL, 0xa1039f9dd5601990ULL, 0x4502d4ce4fff0e0bULL,
++	0xeb2054106837c189ULL, 0xd0f6544c6dd3b93cULL, 0x40727064c416d74fULL, 0x6e15c6114b502ef0ULL,
++	0x4df2a398cfb1a76bULL, 0x11256c7419f2f6b1ULL, 0x4a497962066e6043ULL, 0x705b3aab41355b44ULL,
++	0x365ef536d797b1d8ULL, 0x00076bd622ddf0dbULL, 0x3bbf33b0e0575a88ULL, 0x3777aa05c8e4ca4dULL,
++	0x392745c85578db5fULL, 0x6fda4149dbae5ae2ULL, 0xb1f0b00b8adc9867ULL, 0x09963437d36f1da3ULL,
++	0x7e824e90a5dc3853ULL, 0xccb5f6641f135cbdULL, 0x6736d86c87ce8fccULL, 0x625f3ce26604249fULL,
++	0xaf8ac8059502f63fULL, 0x0c05e70a2e351469ULL, 0x35292e9c764b6305ULL, 0x1a394360c7e23ac3ULL,
++	0xd5c6d53251183264ULL, 0x62065abd43c2b74fULL, 0xb5fbf5d03b973f9bULL, 0x13a3da3661206e5eULL,
++	0xc6bd5837725d94e5ULL, 0x18e30912205016c5ULL, 0x2088ce1570033c68ULL, 0x7fba1f495c837987ULL,
++	0x5a8c7423f2f9079dULL, 0x1735157b34023fc5ULL, 0xe4f9b49ad2fab351ULL, 0x6691ff72c878e33cULL,
++	0x122c2adedc5eff3eULL, 0xf8dd4bf1d8956cf4ULL, 0xeb86205d9e9e5bdaULL, 0x049b92b9d975c743ULL,
++	0xa5379730b0f6c05aULL, 0x72a0ffacc6f3a553ULL, 0xb0032c34b20dcd6dULL, 0x470e9dbc88d5164aULL,
++	0xb19cf10ca237c047ULL, 0xb65466711f6c81a2ULL, 0xb3321bd16dd80b43ULL, 0x48c14f600c5fbe8eULL,
++	0x66451c264aa6c803ULL, 0xb66e3904a4fa7da6ULL, 0xd45f19b0b3128395ULL, 0x31602627c3c9bc10ULL,
++	0x3120dc4832e4e10dULL, 0xeb20c46756c717f7ULL, 0x00f52e3f67280294ULL, 0x566d4fc14730c509ULL,
++	0x7e3a5d40fd837206ULL, 0xc1e926dc7159547aULL, 0x216730fba68d6095ULL, 0x22e8c3843f69cea7ULL,
++	0x33d074e8930e4b2bULL, 0xb6e4350e84d15816ULL, 0x5534c26ad6ba2365ULL, 0x7773c12f89f1f3f3ULL,
++	0x8cba404da57962aaULL, 0x5b9897a81999ce56ULL, 0x508e862f121692fcULL, 0x3a81907fa093c291ULL,
++	0x0dded0ff4725a510ULL, 0x10d8cc10673fc503ULL, 0x5b9d151c9f1f4e89ULL, 0x32a5c1d5cb09a44cULL,
++	0x1e0aa442b90541fbULL, 0x5f85eb7cc1b485dbULL, 0xbee595ce8a9df2e5ULL, 0x25e496c722422236ULL,
++	0x5edf3c46cd0fe5b9ULL, 0x34e75a7ed2a43388ULL, 0xe488de11d761e352ULL, 0x0e878a01a085545cULL,
++	0xba493c77e021bb04ULL, 0x2b4d1843c7df899aULL, 0x9ea37a487ae80d67ULL, 0x67a9958011e41794ULL,
++	0x4b58051a6697b065ULL, 0x47e33f7d8d6ba6d4ULL, 0xbb4da8d483ca46c1ULL, 0x68becaa181c2db0dULL,
++	0x8d8980e90b989aa5ULL, 0xf95eb14a2c93c99bULL, 0x51c6c7c4796e73a2ULL, 0x6e228363b5efb569ULL,
++	0xc6bbc0b02dd624c8ULL, 0x777eb47dec8170eeULL, 0x3cde15a004cfafa9ULL, 0x1dc6bc087160bf9bULL,
++	0x2e07e043eec34002ULL, 0x18e9fc677a68dc7fULL, 0xd8da03188bd15b9aULL, 0x48fbc3bb00568253ULL,
++	0x57547d4cfb654ce1ULL, 0xd3565b82a058e2adULL, 0xf63eaf0bbf154478ULL, 0x47531ef114dfbb18ULL,
++	0xe1ec630a4278c587ULL, 0x5507d546ca8e83f3ULL, 0x85e135c63adc0c2bULL, 0x0aa7efa85682844eULL,
++	0x72691ba8b3e1f615ULL, 0x32b4e9701fbe3ffaULL, 0x97b6d92e39bb7868ULL, 0x2cfe53dea02e39e8ULL,
++	0x687392cd85cd52b0ULL, 0x27ff66c910e29831ULL, 0x97134556a9832d06ULL, 0x269bb0360a84f8a0ULL,
++	0x706e55457643f85cULL, 0x3734a48c9b597d1bULL, 0x7aee91e8c6efa472ULL, 0x5cd6abc198a9d9e0ULL,
++	0x0e04de06cb3ce41aULL, 0xd8c6eb893402e138ULL, 0x904659bb686e3772ULL, 0x7215c371746ba8c8ULL,
++	0xfd12a97eeae4a2d9ULL, 0x9514b7516394f2c5ULL, 0x266fd5809208f294ULL, 0x5c847085619a26b9ULL,
++	0x52985410fed694eaULL, 0x3c905b934a2ed254ULL, 0x10bb47692d3be467ULL, 0x063b3d2d69e5e9e1ULL,
++	0x472726eedda57debULL, 0xefb6c4ae10f41891ULL, 0x2b1641917b307614ULL, 0x117c554fc4f45b7cULL,
++	0xc07cf3118f9d8812ULL, 0x01dbd82050017939ULL, 0xd7e803f4171b2827ULL, 0x1015e87487d225eaULL,
++	0xc58de3fed23acc4dULL, 0x50db91c294a7be2dULL, 0x0b94d43d1c9cf457ULL, 0x6b1640fa6e37524aULL,
++	0x692f346c5fda0d09ULL, 0x200b1c59fa4d3151ULL, 0xb8c46f760777a296ULL, 0x4b38395f3ffdfbcfULL,
++	0x18d25e00be54d671ULL, 0x60d50582bec8aba6ULL, 0x87ad8f263b78b982ULL, 0x50fdf64e9cda0432ULL,
++	0x90f567aac578dcf0ULL, 0xef1e9b0ef2a3133bULL, 0x0eebba9242d9de71ULL, 0x15473c9bf03101c7ULL,
++	0x7c77e8ae56b78095ULL, 0xb678e7666e6f078eULL, 0x2da0b9615348ba1fULL, 0x7cf931c1ff733f0bULL,
++	0x26b357f50a0a366cULL, 0xe9708cf42b87d732ULL, 0xc13aeea5f91cb2c0ULL, 0x35d90c991143bb4cULL,
++	0x47c1c404a9a0d9dcULL, 0x659e58451972d251ULL, 0x3875a8c473b38c31ULL, 0x1fbd9ed379561f24ULL,
++	0x11fabc6fd41ec28dULL, 0x7ef8dfe3cd2a2dcaULL, 0x72e73b5d8c404595ULL, 0x6135fa4954b72f27ULL,
++	0xccfc32a2de24b69cULL, 0x3f55698c1f095d88ULL, 0xbe3350ed5ac3f929ULL, 0x5e9bf806ca477eebULL,
++	0xe9ce8fb63c309f68ULL, 0x5376f63565e1f9f4ULL, 0xd1afcfb35a6393f1ULL, 0x6632a1ede5623506ULL,
++	0x0b7d6c390c2ded4cULL, 0x56cb3281df04cb1fULL, 0x66305a1249ecc3c7ULL, 0x5d588b60a38ca72aULL,
++	0xa6ecbf78e8e5f42dULL, 0x86eeb44b3c8a3eecULL, 0xec219c48fbd21604ULL, 0x1aaf1af517c36731ULL,
++	0xc306a2836769bde7ULL, 0x208280622b1e2adbULL, 0x8027f51ffbff94a6ULL, 0x76cfa1ce1124f26bULL,
++	0x18eb00562422abb6ULL, 0xf377c4d58f8c29c3ULL, 0x4dbbc207f531561aULL, 0x0253b7f082128a27ULL,
++	0x3d1f091cb62c17e0ULL, 0x4860e1abd64628a9ULL, 0x52d17436309d4253ULL, 0x356f97e13efae576ULL,
++	0xd351e11aa150535bULL, 0x3e6b45bb1dd878ccULL, 0x0c776128bed92c98ULL, 0x1d34ae93032885b8ULL,
++	0x4ba0488ca85ba4c3ULL, 0x985348c33c9ce6ceULL, 0x66124c6f97bda770ULL, 0x0f81a0290654124aULL,
++	0x9ed09ca6569b86fdULL, 0x811009fd18af9a2dULL, 0xff08d03f93d8c20aULL, 0x52a148199faef26bULL,
++	0x3e03f9dc2d8d1b73ULL, 0x4205801873961a70ULL, 0xc0d987f041a35970ULL, 0x07aa1f15a1c0d549ULL,
++	0xdfd46ce08cd27224ULL, 0x6d0a024f934e4239ULL, 0x808a7a6399897b59ULL, 0x0a4556e9e13d95a2ULL,
++	0xd21a991fe9c13045ULL, 0x9b0e8548fe7751b8ULL, 0x5da643cb4bf30035ULL, 0x77db28d63940f721ULL,
++	0xfc5eeb614adc9011ULL, 0x5229419ae8c411ebULL, 0x9ec3e7787d1dcf74ULL, 0x340d053e216e4cb5ULL,
++	0xcac7af39b48df2b4ULL, 0xc0faec2871a10a94ULL, 0x140a69245ca575edULL, 0x0cf1c37134273a4cULL,
++	0xc8ee306ac224b8a5ULL, 0x57eaee7ccb4930b0ULL, 0xa1e806bdaacbe74fULL, 0x7d9a62742eeb657dULL,
++	0x9eb6b6ef546c4830ULL, 0x885cca1fddb36e2eULL, 0xe6b9f383ef0d7105ULL, 0x58654fef9d2e0412ULL,
++	0xa905c4ffbe0e8e26ULL, 0x942de5df9b31816eULL, 0x497d723f802e88e1ULL, 0x30684dea602f408dULL,
++	0x21e5a278a3e6cb34ULL, 0xaefb6e6f5b151dc4ULL, 0xb30b8e049d77ca15ULL, 0x28c3c9cf53b98981ULL,
++	0x287fb721556cdd2aULL, 0x0d317ca897022274ULL, 0x7468c7423a543258ULL, 0x4a7f11464eb5642fULL,
++	0xa237a4774d193aa6ULL, 0xd865986ea92129a1ULL, 0x24c515ecf87c1a88ULL, 0x604003575f39f5ebULL,
++	0x47b9f189570a9b27ULL, 0x2b98cede465e4b78ULL, 0x026df551dbb85c20ULL, 0x74fcd91047e21901ULL,
++	0x13e2a90a23c1bfa3ULL, 0x0cb0074e478519f6ULL, 0x5ff1cbbe3af6cf44ULL, 0x67fe5438be812dbeULL,
++	0xd13cf64fa40f05b0ULL, 0x054dfb2f32283787ULL, 0x4173915b7f0d2aeaULL, 0x482f144f1f610d4eULL,
++	0xf6210201b47f8234ULL, 0x5d0ae1929e70b990ULL, 0xdcd7f455b049567cULL, 0x7e93d0f1f0916f01ULL,
++	0xdd79cbf18a7db4faULL, 0xbe8391bf6f74c62fULL, 0x027145d14b8291bdULL, 0x585a73ea2cbf1705ULL,
++	0x485ca03e928a0db2ULL, 0x10fc01a5742857e7ULL, 0x2f482edbd6d551a7ULL, 0x0f0433b5048fdb8aULL,
++	0x60da2e8dd7dc6247ULL, 0x88b4c9d38cd4819aULL, 0x13033ac001f66697ULL, 0x273b24fe3b367d75ULL,
++	0xc6e8f66a31b3b9d4ULL, 0x281514a494df49d5ULL, 0xd1726fdfc8b23da7ULL, 0x4b3ae7d103dee548ULL,
++	0xc6256e19ce4b9d7eULL, 0xff5c5cf186e3c61cULL, 0xacc63ca34b8ec145ULL, 0x74621888fee66574ULL,
++	0x956f409645290a1eULL, 0xef0bf8e3263a962eULL, 0xed6a50eb5ec2647bULL, 0x0694283a9dca7502ULL,
++	0x769b963643a2dcd1ULL, 0x42b7c8ea09fc5353ULL, 0x4f002aee13397eabULL, 0x63005e2c19b7d63aULL,
++	0xca6736da63023beaULL, 0x966c7f6db12a99b7ULL, 0xace09390c537c5e1ULL, 0x0b696063a1aa89eeULL,
++	0xebb03e97288c56e5ULL, 0x432a9f9f938c8be8ULL, 0xa6a5a93d5b717f71ULL, 0x1a5fb4c3e18f9d97ULL,
++	0x1c94e7ad1c60cdceULL, 0xee202a43fc02c4a0ULL, 0x8dafe4d867c46a20ULL, 0x0a10263c8ac27b58ULL,
++	0xd0dea9dfe4432a4aULL, 0x856af87bbe9277c5ULL, 0xce8472acc212c71aULL, 0x6f151b6d9bbb1e91ULL,
++	0x26776c527ceed56aULL, 0x7d211cb7fbf8faecULL, 0x37ae66a6fd4609ccULL, 0x1f81b702d2770c42ULL,
++	0x2fb0b057eac58392ULL, 0xe1dd89fe29744e9dULL, 0xc964f8eb17beb4f8ULL, 0x29571073c9a2d41eULL,
++	0xa948a18981c0e254ULL, 0x2df6369b65b22830ULL, 0xa33eb2d75fcfd3c6ULL, 0x078cd6ec4199a01fULL,
++	0x4a584a41ad900d2fULL, 0x32142b78e2c74c52ULL, 0x68c4e8338431c978ULL, 0x7f69ea9008689fc2ULL,
++	0x52f2c81e46a38265ULL, 0xfd78072d04a832fdULL, 0x8cd7d5fa25359e94ULL, 0x4de71b7454cc29d2ULL,
++	0x42eb60ad1eda6ac9ULL, 0x0aad37dfdbc09c3aULL, 0x81004b71e33cc191ULL, 0x44e6be345122803cULL,
++	0x03fe8388ba1920dbULL, 0xf5d57c32150db008ULL, 0x49c8c4281af60c29ULL, 0x21edb518de701aeeULL,
++	0x7fb63e418f06dc99ULL, 0xa4460d99c166d7b8ULL, 0x24dd5248ce520a83ULL, 0x5ec3ad712b928358ULL,
++	0x15022a5fbd17930fULL, 0xa4f64a77d82570e3ULL, 0x12bc8d6915783712ULL, 0x498194c0fc620abbULL,
++	0x38a2d9d255686c82ULL, 0x785c6bd9193e21f0ULL, 0xe4d5c81ab24a5484ULL, 0x56307860b2e20989ULL,
++	0x429d55f78b4d74c4ULL, 0x22f1834643350131ULL, 0x1e60c24598c71fffULL, 0x59f2f014979983efULL,
++	0x46a47d56eb494a44ULL, 0x3e22a854d636a18eULL, 0xb346e15274491c3bULL, 0x2ceafd4e5390cde7ULL,
++	0xba8a8538be0d6675ULL, 0x4b9074bb50818e23ULL, 0xcbdab89085d304c3ULL, 0x61a24fe0e56192c4ULL,
++	0xcb7615e6db525bcbULL, 0xdd7d8c35a567e4caULL, 0xe6b4153acafcdd69ULL, 0x2d668e097f3c9766ULL,
++	0xa57e7e265ce55ef0ULL, 0x5d9f4e527cd4b967ULL, 0xfbc83606492fd1e5ULL, 0x090d52beb7c3f7aeULL,
++	0x09b9515a1e7b4d7cULL, 0x1f266a2599da44c0ULL, 0xa1c49548e2c55504ULL, 0x7ef04287126f15ccULL,
++	0xfed1659dbd30ef15ULL, 0x8b4ab9eec4e0277bULL, 0x884d6236a5df3291ULL, 0x1fd96ea6bf5cf788ULL,
++	0x42a161981f190d9aULL, 0x61d849507e6052c1ULL, 0x9fe113bf285a2cd5ULL, 0x7c22d676dbad85d8ULL,
++	0x82e770ed2bfbd27dULL, 0x4c05b2ece996f5a5ULL, 0xcd40a9c2b0900150ULL, 0x5895319213d9bf64ULL,
++	0xe7cc5d703fea2e08ULL, 0xb50c491258e2188cULL, 0xcce30baa48205bf0ULL, 0x537c659ccfa32d62ULL,
++	0x37b6623a98cfc088ULL, 0xfe9bed1fa4d6aca4ULL, 0x04d29b8e56a8d1b0ULL, 0x725f71c40b519575ULL,
++	0x28c7f89cd0339ce6ULL, 0x8367b14469ddc18bULL, 0x883ada83a6a1652cULL, 0x585f1974034d6c17ULL,
++	0x89cfb266f1b19188ULL, 0xe63b4863e7c35217ULL, 0xd88c9da6b4c0526aULL, 0x3e035c9df0954635ULL,
++	0xdd9d5412fb45de9dULL, 0xdd684532e4cff40dULL, 0x4b5c999b151d671cULL, 0x2d8c2cc811e7f690ULL,
++	0x7f54be1d90055d40ULL, 0xa464c5df464aaf40ULL, 0x33979624f0e917beULL, 0x2c018dc527356b30ULL,
++	0xa5415024e330b3d4ULL, 0x73ff3d96691652d3ULL, 0x94ec42c4ef9b59f1ULL, 0x0747201618d08e5aULL,
++	0x4d6ca48aca411c53ULL, 0x66415f2fcfa66119ULL, 0x9c4dd40051e227ffULL, 0x59810bc09a02f7ebULL,
++	0x2a7eb171b3dc101dULL, 0x441c5ab99ffef68eULL, 0x32025c9b93b359eaULL, 0x5e8ce0a71e9d112fULL,
++	0xbfcccb92429503fdULL, 0xd271ba752f095d55ULL, 0x345ead5e972d091eULL, 0x18c8df11a83103baULL,
++	0x90cd949a9aed0f4cULL, 0xc5d1f4cb6660e37eULL, 0xb8cac52d56c52e0bULL, 0x6e42e400c5808e0dULL,
++	0xa3b46966eeaefd23ULL, 0x0c4f1f0be39ecdcaULL, 0x189dc8c9d683a51dULL, 0x51f27f054c09351bULL,
++	0x4c487ccd2a320682ULL, 0x587ea95bb3df1c96ULL, 0xc8ccf79e555cb8e8ULL, 0x547dc829a206d73dULL,
++	0xb822a6cd80c39b06ULL, 0xe96d54732000d4c6ULL, 0x28535b6f91463b4dULL, 0x228f4660e2486e1dULL,
++	0x98799538de8d3abfULL, 0x8cd8330045ebca6eULL, 0x79952a008221e738ULL, 0x4322e1a7535cd2bbULL,
++	0xb114c11819d1801cULL, 0x2016e4d84f3f5ec7ULL, 0xdd0e2df409260f4cULL, 0x5ec362c0ae5f7266ULL,
++	0xc0462b18b8b2b4eeULL, 0x7cc8d950274d1afbULL, 0xf25f7105436b02d2ULL, 0x43bbf8dcbff9ccd3ULL,
++	0xb6ad1767a039e9dfULL, 0xb0714da8f69d3583ULL, 0x5e55fa18b42931f5ULL, 0x4ed5558f33c60961ULL,
++	0x1fe37901c647a5ddULL, 0x593ddf1f8081d357ULL, 0x0249a4fd813fd7a6ULL, 0x69acca274e9caf61ULL,
++	0x047ba3ea330721c9ULL, 0x83423fc20e7e1ea0ULL, 0x1df4c0af01314a60ULL, 0x09a62dab89289527ULL,
++	0xa5b325a49cc6cb00ULL, 0xe94b5dc654b56cb6ULL, 0x3be28779adc994a0ULL, 0x4296e8f8ba3a4aadULL,
++	0x328689761e451eabULL, 0x2e4d598bff59594aULL, 0x49b96853d7a7084aULL, 0x4980a319601420a8ULL,
++	0x9565b9e12f552c42ULL, 0x8a5318db7100fe96ULL, 0x05c90b4d43add0d7ULL, 0x538b4cd66a5d4edaULL,
++	0xf4e94fc3e89f039fULL, 0x592c9af26f618045ULL, 0x08a36eb5fd4b9550ULL, 0x25fffaf6c2ed1419ULL,
++	0x34434459cc79d354ULL, 0xeeecbfb4b1d5476bULL, 0xddeb34a061615d99ULL, 0x5129cecceb64b773ULL,
++	0xee43215894993520ULL, 0x772f9c7cf14c0b3bULL, 0xd2e2fce306bedad5ULL, 0x715f42b546f06a97ULL,
++	0x434ecdceda5b5f1aULL, 0x0da17115a49741a9ULL, 0x680bd77c73edad2eULL, 0x487c02354edd9041ULL,
++	0xb8efeff3a70ed9c4ULL, 0x56a32aa3e857e302ULL, 0xdf3a68bd48a2a5a0ULL, 0x07f650b73176c444ULL,
++	0xe38b9b1626e0ccb1ULL, 0x79e053c18b09fb36ULL, 0x56d90319c9f94964ULL, 0x1ca941e7ac9ff5c4ULL,
++	0x49c4df29162fa0bbULL, 0x8488cf3282b33305ULL, 0x95dfda14cabb437dULL, 0x3391f78264d5ad86ULL,
++	0x729ae06ae2b5095dULL, 0xd58a58d73259a946ULL, 0xe9834262d13921edULL, 0x27fedafaa54bb592ULL,
++	0xa99dc5b829ad48bbULL, 0x5f025742499ee260ULL, 0x802c8ecd5d7513fdULL, 0x78ceb3ef3f6dd938ULL,
++	0xc342f44f8a135d94ULL, 0x7b9edb44828cdda3ULL, 0x9436d11a0537cfe7ULL, 0x5064b164ec1ab4c8ULL,
++	0x7020eccfd37eb2fcULL, 0x1f31ea3ed90d25fcULL, 0x1b930d7bdfa1bb34ULL, 0x5344467a48113044ULL,
++	0x70073170f25e6dfbULL, 0xe385dc1a50114cc8ULL, 0x2348698ac8fc4f00ULL, 0x2a77a55284dd40d8ULL,
++	0xfe06afe0c98c6ce4ULL, 0xc235df96dddfd6e4ULL, 0x1428d01e33bf1ed3ULL, 0x785768ec9300bdafULL,
++	0x9702e57a91deb63bULL, 0x61bdb8bfe5ce8b80ULL, 0x645b426f3d1d58acULL, 0x4804a82227a557bcULL,
++	0x8e57048ab44d2601ULL, 0x68d6501a4b3a6935ULL, 0xc39c9ec3f9e1c293ULL, 0x4172f257d4de63e2ULL,
++	0xd368b450330c6401ULL, 0x040d3017418f2391ULL, 0x2c34bb6090b7d90dULL, 0x16f649228fdfd51fULL,
++	0xbea6818e2b928ef5ULL, 0xe28ccf91cdc11e72ULL, 0x594aaa68e77a36cdULL, 0x313034806c7ffd0fULL,
++	0x8a9d27ac2249bd65ULL, 0x19a3b464018e9512ULL, 0xc26ccff352b37ec7ULL, 0x056f68341d797b21ULL,
++	0x5e79d6757efd2327ULL, 0xfabdbcb6553afe15ULL, 0xd3e7222c6eaf5a60ULL, 0x7046c76d4dae743bULL,
++	0x660be872b18d4a55ULL, 0x19992518574e1496ULL, 0xc103053a302bdcbbULL, 0x3ed8e9800b218e8eULL,
++	0x7b0b9239fa75e03eULL, 0xefe9fb684633c083ULL, 0x98a35fbe391a7793ULL, 0x6065510fe2d0fe34ULL,
++	0x55cb668548abad0cULL, 0xb4584548da87e527ULL, 0x2c43ecea0107c1ddULL, 0x526028809372de35ULL,
++	0x3415c56af9213b1fULL, 0x5bee1a4d017e98dbULL, 0x13f6b105b5cf709bULL, 0x5ff20e3482b29ab6ULL,
++	0x0aa29c75cc2e6c90ULL, 0xfc7d73ca3a70e206ULL, 0x899fc38fc4b5c515ULL, 0x250386b124ffc207ULL,
++	0x54ea28d5ae3d2b56ULL, 0x9913149dd6de60ceULL, 0x16694fc58f06d6c1ULL, 0x46b23975eb018fc7ULL,
++	0x470a6a0fb4b7b4e2ULL, 0x5d92475a8f7253deULL, 0xabeee5b52fbd3adbULL, 0x7fa20801a0806968ULL,
++	0x76f3faf19f7714d2ULL, 0xb3e840c12f4660c3ULL, 0x0fb4cd8df212744eULL, 0x4b065a251d3a2dd2ULL,
++	0x5cebde383d77cd4aULL, 0x6adf39df882c9cb1ULL, 0xa2dd242eb09af759ULL, 0x3147c0e50e5f6422ULL,
++	0x164ca5101d1350dbULL, 0xf8d13479c33fc962ULL, 0xe640ce4d13e5da08ULL, 0x4bdee0c45061f8baULL,
++	0xd7c46dc1a4edb1c9ULL, 0x5514d7b6437fd98aULL, 0x58942f6bb2a1c00bULL, 0x2dffb2ab1d70710eULL,
++	0xccdfcf2fc18b6d68ULL, 0xa8ebcba8b7806167ULL, 0x980697f95e2937e3ULL, 0x02fbba1cd0126e8cULL
++};
+ 
+-static void curve25519_bmi2_base(u8 session_key[CURVE25519_KEY_SIZE],
+-				 const u8 private_key[CURVE25519_KEY_SIZE])
++static void curve25519_ever64_base(u8 *out, const u8 *priv)
+ {
+-	struct {
+-		u64 buffer[4 * NUM_WORDS_ELTFP25519];
+-		u64 coordinates[4 * NUM_WORDS_ELTFP25519];
+-		u64 workspace[4 * NUM_WORDS_ELTFP25519];
+-		u8 private[CURVE25519_KEY_SIZE];
+-	} __aligned(32) m;
+-
+-	const int ite[4] = { 64, 64, 64, 63 };
+-	const int q = 3;
+ 	u64 swap = 1;
+-
+-	int i = 0, j = 0, k = 0;
+-	u64 *const key = (u64 *)m.private;
+-	u64 *const Ur1 = m.coordinates + 0;
+-	u64 *const Zr1 = m.coordinates + 4;
+-	u64 *const Ur2 = m.coordinates + 8;
+-	u64 *const Zr2 = m.coordinates + 12;
+-
+-	u64 *const UZr1 = m.coordinates + 0;
+-	u64 *const ZUr2 = m.coordinates + 8;
+-
+-	u64 *const A = m.workspace + 0;
+-	u64 *const B = m.workspace + 4;
+-	u64 *const C = m.workspace + 8;
+-	u64 *const D = m.workspace + 12;
+-
+-	u64 *const AB = m.workspace + 0;
+-	u64 *const CD = m.workspace + 8;
+-
+-	const u64 *const P = table_ladder_8k;
+-
+-	memcpy(m.private, private_key, sizeof(m.private));
+-
+-	curve25519_clamp_secret(m.private);
+-
+-	setzero_eltfp25519_1w(Ur1);
+-	setzero_eltfp25519_1w(Zr1);
+-	setzero_eltfp25519_1w(Zr2);
+-	Ur1[0] = 1;
+-	Zr1[0] = 1;
+-	Zr2[0] = 1;
+-
+-	/* G-S */
+-	Ur2[3] = 0x1eaecdeee27cab34UL;
+-	Ur2[2] = 0xadc7a0b9235d48e2UL;
+-	Ur2[1] = 0xbbf095ae14b2edf8UL;
+-	Ur2[0] = 0x7e94e1fec82faabdUL;
+-
+-	/* main-loop */
+-	j = q;
+-	for (i = 0; i < NUM_WORDS_ELTFP25519; ++i) {
+-		while (j < ite[i]) {
+-			u64 bit = (key[i] >> j) & 0x1;
+-			k = (64 * i + j - q);
++	int i, j, k;
++	u64 tmp[16 + 32 + 4];
++	u64 *x1 = &tmp[0];
++	u64 *z1 = &tmp[4];
++	u64 *x2 = &tmp[8];
++	u64 *z2 = &tmp[12];
++	u64 *xz1 = &tmp[0];
++	u64 *xz2 = &tmp[8];
++	u64 *a = &tmp[0 + 16];
++	u64 *b = &tmp[4 + 16];
++	u64 *c = &tmp[8 + 16];
++	u64 *ab = &tmp[0 + 16];
++	u64 *abcd = &tmp[0 + 16];
++	u64 *ef = &tmp[16 + 16];
++	u64 *efgh = &tmp[16 + 16];
++	u64 *key = &tmp[0 + 16 + 32];
++
++	memcpy(key, priv, 32);
++	((u8 *)key)[0] &= 248;
++	((u8 *)key)[31] = (((u8 *)key)[31] & 127) | 64;
++
++	x1[0] = 1, x1[1] = x1[2] = x1[3] = 0;
++	z1[0] = 1, z1[1] = z1[2] = z1[3] = 0;
++	z2[0] = 1, z2[1] = z2[2] = z2[3] = 0;
++	memcpy(x2, p_minus_s, sizeof(p_minus_s));
++
++	j = 3;
++	for (i = 0; i < 4; ++i) {
++		while (j < (const int[]){ 64, 64, 64, 63 }[i]) {
++			u64 bit = (key[i] >> j) & 1;
++			k = (64 * i + j - 3);
+ 			swap = swap ^ bit;
+-			cswap(swap, Ur1, Ur2);
+-			cswap(swap, Zr1, Zr2);
++			cswap2(swap, xz1, xz2);
+ 			swap = bit;
+-			/* Addition */
+-			sub_eltfp25519_1w(B, Ur1, Zr1);		/* B = Ur1-Zr1 */
+-			add_eltfp25519_1w_bmi2(A, Ur1, Zr1);	/* A = Ur1+Zr1 */
+-			mul_eltfp25519_1w_bmi2(C, &P[4 * k], B);/* C = M0-B */
+-			sub_eltfp25519_1w(B, A, C);		/* B = (Ur1+Zr1) - M*(Ur1-Zr1) */
+-			add_eltfp25519_1w_bmi2(A, A, C);	/* A = (Ur1+Zr1) + M*(Ur1-Zr1) */
+-			sqr_eltfp25519_2w_bmi2(AB);		/* A = A^2      |  B = B^2 */
+-			mul_eltfp25519_2w_bmi2(UZr1, ZUr2, AB);	/* Ur1 = Zr2*A  |  Zr1 = Ur2*B */
++			fsub(b, x1, z1);
++			fadd(a, x1, z1);
++			fmul(c, &table_ladder[4 * k], b, ef);
++			fsub(b, a, c);
++			fadd(a, a, c);
++			fsqr2(ab, ab, efgh);
++			fmul2(xz1, xz2, ab, efgh);
+ 			++j;
+ 		}
+ 		j = 0;
+ 	}
+ 
+-	/* Doubling */
+-	for (i = 0; i < q; ++i) {
+-		add_eltfp25519_1w_bmi2(A, Ur1, Zr1);	/*  A = Ur1+Zr1 */
+-		sub_eltfp25519_1w(B, Ur1, Zr1);		/*  B = Ur1-Zr1 */
+-		sqr_eltfp25519_2w_bmi2(AB);		/*  A = A**2     B = B**2 */
+-		copy_eltfp25519_1w(C, B);		/*  C = B */
+-		sub_eltfp25519_1w(B, A, B);		/*  B = A-B */
+-		mul_a24_eltfp25519_1w(D, B);		/*  D = my_a24*B */
+-		add_eltfp25519_1w_bmi2(D, D, C);	/*  D = D+C */
+-		mul_eltfp25519_2w_bmi2(UZr1, AB, CD);	/*  Ur1 = A*B   Zr1 = Zr1*A */
+-	}
+-
+-	/* Convert to affine coordinates */
+-	inv_eltfp25519_1w_bmi2(A, Zr1);
+-	mul_eltfp25519_1w_bmi2((u64 *)session_key, Ur1, A);
+-	fred_eltfp25519_1w((u64 *)session_key);
++	point_double(xz1, abcd, efgh);
++	point_double(xz1, abcd, efgh);
++	point_double(xz1, abcd, efgh);
++	encode_point(out, xz1);
+ 
+-	memzero_explicit(&m, sizeof(m));
++	memzero_explicit(tmp, sizeof(tmp));
+ }
+ 
++static __ro_after_init DEFINE_STATIC_KEY_FALSE(curve25519_use_bmi2_adx);
++
+ void curve25519_arch(u8 mypublic[CURVE25519_KEY_SIZE],
+ 		     const u8 secret[CURVE25519_KEY_SIZE],
+ 		     const u8 basepoint[CURVE25519_KEY_SIZE])
+ {
+-	if (static_branch_likely(&curve25519_use_adx))
+-		curve25519_adx(mypublic, secret, basepoint);
+-	else if (static_branch_likely(&curve25519_use_bmi2))
+-		curve25519_bmi2(mypublic, secret, basepoint);
++	if (static_branch_likely(&curve25519_use_bmi2_adx))
++		curve25519_ever64(mypublic, secret, basepoint);
+ 	else
+ 		curve25519_generic(mypublic, secret, basepoint);
+ }
+@@ -2355,10 +1395,8 @@ EXPORT_SYMBOL(curve25519_arch);
+ void curve25519_base_arch(u8 pub[CURVE25519_KEY_SIZE],
+ 			  const u8 secret[CURVE25519_KEY_SIZE])
+ {
+-	if (static_branch_likely(&curve25519_use_adx))
+-		curve25519_adx_base(pub, secret);
+-	else if (static_branch_likely(&curve25519_use_bmi2))
+-		curve25519_bmi2_base(pub, secret);
++	if (static_branch_likely(&curve25519_use_bmi2_adx))
++		curve25519_ever64_base(pub, secret);
+ 	else
+ 		curve25519_generic(pub, secret, curve25519_base_point);
+ }
+@@ -2449,12 +1487,11 @@ static struct kpp_alg curve25519_alg = {
+ 	.max_size		= curve25519_max_size,
+ };
+ 
++
+ static int __init curve25519_mod_init(void)
+ {
+-	if (boot_cpu_has(X86_FEATURE_BMI2))
+-		static_branch_enable(&curve25519_use_bmi2);
+-	else if (boot_cpu_has(X86_FEATURE_ADX))
+-		static_branch_enable(&curve25519_use_adx);
++	if (boot_cpu_has(X86_FEATURE_BMI2) && boot_cpu_has(X86_FEATURE_ADX))
++		static_branch_enable(&curve25519_use_bmi2_adx);
+ 	else
+ 		return 0;
+ 	return IS_REACHABLE(CONFIG_CRYPTO_KPP) ?
+@@ -2474,3 +1511,4 @@ module_exit(curve25519_mod_exit);
+ MODULE_ALIAS_CRYPTO("curve25519");
+ MODULE_ALIAS_CRYPTO("curve25519-x86");
+ MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0055-crypto-x86-curve25519-leave-r12-as-spare-register.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0055-crypto-x86-curve25519-leave-r12-as-spare-register.patch
new file mode 100644
index 0000000..d5b11e0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0055-crypto-x86-curve25519-leave-r12-as-spare-register.patch
@@ -0,0 +1,376 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Sun, 1 Mar 2020 16:06:56 +0800
+Subject: [PATCH] crypto: x86/curve25519 - leave r12 as spare register
+
+commit dc7fc3a53ae158263196b1892b672aedf67796c5 upstream.
+
+This updates to the newer register selection proved by HACL*, which
+leads to a more compact instruction encoding, and saves around 100
+cycles.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/curve25519-x86_64.c | 110 ++++++++++++++--------------
+ 1 file changed, 55 insertions(+), 55 deletions(-)
+
+--- a/arch/x86/crypto/curve25519-x86_64.c
++++ b/arch/x86/crypto/curve25519-x86_64.c
+@@ -167,28 +167,28 @@ static inline void fmul(u64 *out, const
+ 		"  movq 0(%1), %%rdx;"
+ 		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  movq %%r8, 0(%0);"
+ 		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  movq %%r10, 8(%0);"
+-		"  mulxq 16(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"
++		"  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"
+ 		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"
+ 		/* Compute src1[1] * src2 */
+ 		"  movq 8(%1), %%rdx;"
+ 		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  adcxq 8(%0), %%r8;"    "  movq %%r8, 8(%0);"
+-		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%r12, %%r10;"    "  movq %%r10, 16(%0);"
+-		"  mulxq 16(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"    "  adcx %%r14, %%r12;"    "  mov $0, %%r8;"
++		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 16(%0);"
++		"  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  mov $0, %%r8;"
+ 		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
+ 		/* Compute src1[2] * src2 */
+ 		"  movq 16(%1), %%rdx;"
+ 		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 16(%0), %%r8;"    "  movq %%r8, 16(%0);"
+-		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%r12, %%r10;"    "  movq %%r10, 24(%0);"
+-		"  mulxq 16(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"    "  adcx %%r14, %%r12;"    "  mov $0, %%r8;"
++		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 24(%0);"
++		"  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  mov $0, %%r8;"
+ 		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
+ 		/* Compute src1[3] * src2 */
+ 		"  movq 24(%1), %%rdx;"
+ 		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 24(%0), %%r8;"    "  movq %%r8, 24(%0);"
+-		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%r12, %%r10;"    "  movq %%r10, 32(%0);"
+-		"  mulxq 16(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"    "  adcx %%r14, %%r12;"    "  movq %%r12, 40(%0);"    "  mov $0, %%r8;"
++		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 32(%0);"
++		"  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  movq %%rbx, 40(%0);"    "  mov $0, %%r8;"
+ 		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  movq %%r14, 48(%0);"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"     "  movq %%rax, 56(%0);"
+ 		/* Line up pointers */
+@@ -202,11 +202,11 @@ static inline void fmul(u64 *out, const
+ 		"  mulxq 32(%1), %%r8, %%r13;"
+ 		"  xor %3, %3;"
+ 		"  adoxq 0(%1), %%r8;"
+-		"  mulxq 40(%1), %%r9, %%r12;"
++		"  mulxq 40(%1), %%r9, %%rbx;"
+ 		"  adcx %%r13, %%r9;"
+ 		"  adoxq 8(%1), %%r9;"
+ 		"  mulxq 48(%1), %%r10, %%r13;"
+-		"  adcx %%r12, %%r10;"
++		"  adcx %%rbx, %%r10;"
+ 		"  adoxq 16(%1), %%r10;"
+ 		"  mulxq 56(%1), %%r11, %%rax;"
+ 		"  adcx %%r13, %%r11;"
+@@ -231,7 +231,7 @@ static inline void fmul(u64 *out, const
+ 		"  movq %%r8, 0(%0);"
+ 	: "+&r" (tmp), "+&r" (f1), "+&r" (out), "+&r" (f2)
+ 	:
+-	: "%rax", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "memory", "cc"
++	: "%rax", "%rdx", "%r8", "%r9", "%r10", "%r11", "%rbx", "%r13", "%r14", "memory", "cc"
+ 	);
+ }
+ 
+@@ -248,28 +248,28 @@ static inline void fmul2(u64 *out, const
+ 		"  movq 0(%1), %%rdx;"
+ 		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  movq %%r8, 0(%0);"
+ 		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  movq %%r10, 8(%0);"
+-		"  mulxq 16(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"
++		"  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"
+ 		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"
+ 		/* Compute src1[1] * src2 */
+ 		"  movq 8(%1), %%rdx;"
+ 		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  adcxq 8(%0), %%r8;"    "  movq %%r8, 8(%0);"
+-		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%r12, %%r10;"    "  movq %%r10, 16(%0);"
+-		"  mulxq 16(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"    "  adcx %%r14, %%r12;"    "  mov $0, %%r8;"
++		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 16(%0);"
++		"  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  mov $0, %%r8;"
+ 		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
+ 		/* Compute src1[2] * src2 */
+ 		"  movq 16(%1), %%rdx;"
+ 		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 16(%0), %%r8;"    "  movq %%r8, 16(%0);"
+-		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%r12, %%r10;"    "  movq %%r10, 24(%0);"
+-		"  mulxq 16(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"    "  adcx %%r14, %%r12;"    "  mov $0, %%r8;"
++		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 24(%0);"
++		"  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  mov $0, %%r8;"
+ 		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
+ 		/* Compute src1[3] * src2 */
+ 		"  movq 24(%1), %%rdx;"
+ 		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 24(%0), %%r8;"    "  movq %%r8, 24(%0);"
+-		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%r12, %%r10;"    "  movq %%r10, 32(%0);"
+-		"  mulxq 16(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"    "  adcx %%r14, %%r12;"    "  movq %%r12, 40(%0);"    "  mov $0, %%r8;"
++		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 32(%0);"
++		"  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  movq %%rbx, 40(%0);"    "  mov $0, %%r8;"
+ 		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  movq %%r14, 48(%0);"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"     "  movq %%rax, 56(%0);"
+ 
+@@ -279,28 +279,28 @@ static inline void fmul2(u64 *out, const
+ 		"  movq 32(%1), %%rdx;"
+ 		"  mulxq 32(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  movq %%r8, 64(%0);"
+ 		"  mulxq 40(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  movq %%r10, 72(%0);"
+-		"  mulxq 48(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"
++		"  mulxq 48(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"
+ 		"  mulxq 56(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"
+ 		/* Compute src1[1] * src2 */
+ 		"  movq 40(%1), %%rdx;"
+ 		"  mulxq 32(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  adcxq 72(%0), %%r8;"    "  movq %%r8, 72(%0);"
+-		"  mulxq 40(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%r12, %%r10;"    "  movq %%r10, 80(%0);"
+-		"  mulxq 48(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"    "  adcx %%r14, %%r12;"    "  mov $0, %%r8;"
++		"  mulxq 40(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 80(%0);"
++		"  mulxq 48(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  mov $0, %%r8;"
+ 		"  mulxq 56(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
+ 		/* Compute src1[2] * src2 */
+ 		"  movq 48(%1), %%rdx;"
+ 		"  mulxq 32(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 80(%0), %%r8;"    "  movq %%r8, 80(%0);"
+-		"  mulxq 40(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%r12, %%r10;"    "  movq %%r10, 88(%0);"
+-		"  mulxq 48(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"    "  adcx %%r14, %%r12;"    "  mov $0, %%r8;"
++		"  mulxq 40(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 88(%0);"
++		"  mulxq 48(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  mov $0, %%r8;"
+ 		"  mulxq 56(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
+ 		/* Compute src1[3] * src2 */
+ 		"  movq 56(%1), %%rdx;"
+ 		"  mulxq 32(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 88(%0), %%r8;"    "  movq %%r8, 88(%0);"
+-		"  mulxq 40(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%r12, %%r10;"    "  movq %%r10, 96(%0);"
+-		"  mulxq 48(%3), %%r12, %%r13;"    "  adox %%r11, %%r12;"    "  adcx %%r14, %%r12;"    "  movq %%r12, 104(%0);"    "  mov $0, %%r8;"
++		"  mulxq 40(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 96(%0);"
++		"  mulxq 48(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  movq %%rbx, 104(%0);"    "  mov $0, %%r8;"
+ 		"  mulxq 56(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  movq %%r14, 112(%0);"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"     "  movq %%rax, 120(%0);"
+ 		/* Line up pointers */
+@@ -314,11 +314,11 @@ static inline void fmul2(u64 *out, const
+ 		"  mulxq 32(%1), %%r8, %%r13;"
+ 		"  xor %3, %3;"
+ 		"  adoxq 0(%1), %%r8;"
+-		"  mulxq 40(%1), %%r9, %%r12;"
++		"  mulxq 40(%1), %%r9, %%rbx;"
+ 		"  adcx %%r13, %%r9;"
+ 		"  adoxq 8(%1), %%r9;"
+ 		"  mulxq 48(%1), %%r10, %%r13;"
+-		"  adcx %%r12, %%r10;"
++		"  adcx %%rbx, %%r10;"
+ 		"  adoxq 16(%1), %%r10;"
+ 		"  mulxq 56(%1), %%r11, %%rax;"
+ 		"  adcx %%r13, %%r11;"
+@@ -347,11 +347,11 @@ static inline void fmul2(u64 *out, const
+ 		"  mulxq 96(%1), %%r8, %%r13;"
+ 		"  xor %3, %3;"
+ 		"  adoxq 64(%1), %%r8;"
+-		"  mulxq 104(%1), %%r9, %%r12;"
++		"  mulxq 104(%1), %%r9, %%rbx;"
+ 		"  adcx %%r13, %%r9;"
+ 		"  adoxq 72(%1), %%r9;"
+ 		"  mulxq 112(%1), %%r10, %%r13;"
+-		"  adcx %%r12, %%r10;"
++		"  adcx %%rbx, %%r10;"
+ 		"  adoxq 80(%1), %%r10;"
+ 		"  mulxq 120(%1), %%r11, %%rax;"
+ 		"  adcx %%r13, %%r11;"
+@@ -376,7 +376,7 @@ static inline void fmul2(u64 *out, const
+ 		"  movq %%r8, 32(%0);"
+ 	: "+&r" (tmp), "+&r" (f1), "+&r" (out), "+&r" (f2)
+ 	:
+-	: "%rax", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "memory", "cc"
++	: "%rax", "%rdx", "%r8", "%r9", "%r10", "%r11", "%rbx", "%r13", "%r14", "memory", "cc"
+ 	);
+ }
+ 
+@@ -388,11 +388,11 @@ static inline void fmul_scalar(u64 *out,
+ 	asm volatile(
+ 		/* Compute the raw multiplication of f1*f2 */
+ 		"  mulxq 0(%2), %%r8, %%rcx;"      /* f1[0]*f2 */
+-		"  mulxq 8(%2), %%r9, %%r12;"      /* f1[1]*f2 */
++		"  mulxq 8(%2), %%r9, %%rbx;"      /* f1[1]*f2 */
+ 		"  add %%rcx, %%r9;"
+ 		"  mov $0, %%rcx;"
+ 		"  mulxq 16(%2), %%r10, %%r13;"    /* f1[2]*f2 */
+-		"  adcx %%r12, %%r10;"
++		"  adcx %%rbx, %%r10;"
+ 		"  mulxq 24(%2), %%r11, %%rax;"    /* f1[3]*f2 */
+ 		"  adcx %%r13, %%r11;"
+ 		"  adcx %%rcx, %%rax;"
+@@ -419,7 +419,7 @@ static inline void fmul_scalar(u64 *out,
+ 		"  movq %%r8, 0(%1);"
+ 	: "+&r" (f2_r)
+ 	: "r" (out), "r" (f1)
+-	: "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "memory", "cc"
++	: "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11", "%rbx", "%r13", "memory", "cc"
+ 	);
+ }
+ 
+@@ -520,8 +520,8 @@ static inline void fsqr(u64 *out, const
+ 		"  mulxq 16(%1), %%r9, %%r10;"     "  adcx %%r14, %%r9;"     /* f[2]*f[0] */
+ 		"  mulxq 24(%1), %%rax, %%rcx;"    "  adcx %%rax, %%r10;"    /* f[3]*f[0] */
+ 		"  movq 24(%1), %%rdx;"                                      /* f[3] */
+-		"  mulxq 8(%1), %%r11, %%r12;"     "  adcx %%rcx, %%r11;"    /* f[1]*f[3] */
+-		"  mulxq 16(%1), %%rax, %%r13;"    "  adcx %%rax, %%r12;"    /* f[2]*f[3] */
++		"  mulxq 8(%1), %%r11, %%rbx;"     "  adcx %%rcx, %%r11;"    /* f[1]*f[3] */
++		"  mulxq 16(%1), %%rax, %%r13;"    "  adcx %%rax, %%rbx;"    /* f[2]*f[3] */
+ 		"  movq 8(%1), %%rdx;"             "  adcx %%r15, %%r13;"    /* f1 */
+ 		"  mulxq 16(%1), %%rax, %%rcx;"    "  mov $0, %%r14;"        /* f[2]*f[1] */
+ 
+@@ -531,12 +531,12 @@ static inline void fsqr(u64 *out, const
+ 		"  adcx %%r8, %%r8;"
+ 		"  adox %%rcx, %%r11;"
+ 		"  adcx %%r9, %%r9;"
+-		"  adox %%r15, %%r12;"
++		"  adox %%r15, %%rbx;"
+ 		"  adcx %%r10, %%r10;"
+ 		"  adox %%r15, %%r13;"
+ 		"  adcx %%r11, %%r11;"
+ 		"  adox %%r15, %%r14;"
+-		"  adcx %%r12, %%r12;"
++		"  adcx %%rbx, %%rbx;"
+ 		"  adcx %%r13, %%r13;"
+ 		"  adcx %%r14, %%r14;"
+ 
+@@ -549,7 +549,7 @@ static inline void fsqr(u64 *out, const
+ 		"  adcx %%rcx, %%r10;"     "  movq %%r10, 24(%0);"
+ 		"  movq 16(%1), %%rdx;"    "  mulx %%rdx, %%rax, %%rcx;"    /* f[2]^2 */
+ 		"  adcx %%rax, %%r11;"     "  movq %%r11, 32(%0);"
+-		"  adcx %%rcx, %%r12;"     "  movq %%r12, 40(%0);"
++		"  adcx %%rcx, %%rbx;"     "  movq %%rbx, 40(%0);"
+ 		"  movq 24(%1), %%rdx;"    "  mulx %%rdx, %%rax, %%rcx;"    /* f[3]^2 */
+ 		"  adcx %%rax, %%r13;"     "  movq %%r13, 48(%0);"
+ 		"  adcx %%rcx, %%r14;"     "  movq %%r14, 56(%0);"
+@@ -565,11 +565,11 @@ static inline void fsqr(u64 *out, const
+ 		"  mulxq 32(%1), %%r8, %%r13;"
+ 		"  xor %%rcx, %%rcx;"
+ 		"  adoxq 0(%1), %%r8;"
+-		"  mulxq 40(%1), %%r9, %%r12;"
++		"  mulxq 40(%1), %%r9, %%rbx;"
+ 		"  adcx %%r13, %%r9;"
+ 		"  adoxq 8(%1), %%r9;"
+ 		"  mulxq 48(%1), %%r10, %%r13;"
+-		"  adcx %%r12, %%r10;"
++		"  adcx %%rbx, %%r10;"
+ 		"  adoxq 16(%1), %%r10;"
+ 		"  mulxq 56(%1), %%r11, %%rax;"
+ 		"  adcx %%r13, %%r11;"
+@@ -594,7 +594,7 @@ static inline void fsqr(u64 *out, const
+ 		"  movq %%r8, 0(%0);"
+ 	: "+&r" (tmp), "+&r" (f), "+&r" (out)
+ 	:
+-	: "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "memory", "cc"
++	: "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%rbx", "%r13", "%r14", "%r15", "memory", "cc"
+ 	);
+ }
+ 
+@@ -611,8 +611,8 @@ static inline void fsqr2(u64 *out, const
+ 		"  mulxq 16(%1), %%r9, %%r10;"     "  adcx %%r14, %%r9;"     /* f[2]*f[0] */
+ 		"  mulxq 24(%1), %%rax, %%rcx;"    "  adcx %%rax, %%r10;"    /* f[3]*f[0] */
+ 		"  movq 24(%1), %%rdx;"                                      /* f[3] */
+-		"  mulxq 8(%1), %%r11, %%r12;"     "  adcx %%rcx, %%r11;"    /* f[1]*f[3] */
+-		"  mulxq 16(%1), %%rax, %%r13;"    "  adcx %%rax, %%r12;"    /* f[2]*f[3] */
++		"  mulxq 8(%1), %%r11, %%rbx;"     "  adcx %%rcx, %%r11;"    /* f[1]*f[3] */
++		"  mulxq 16(%1), %%rax, %%r13;"    "  adcx %%rax, %%rbx;"    /* f[2]*f[3] */
+ 		"  movq 8(%1), %%rdx;"             "  adcx %%r15, %%r13;"    /* f1 */
+ 		"  mulxq 16(%1), %%rax, %%rcx;"    "  mov $0, %%r14;"        /* f[2]*f[1] */
+ 
+@@ -622,12 +622,12 @@ static inline void fsqr2(u64 *out, const
+ 		"  adcx %%r8, %%r8;"
+ 		"  adox %%rcx, %%r11;"
+ 		"  adcx %%r9, %%r9;"
+-		"  adox %%r15, %%r12;"
++		"  adox %%r15, %%rbx;"
+ 		"  adcx %%r10, %%r10;"
+ 		"  adox %%r15, %%r13;"
+ 		"  adcx %%r11, %%r11;"
+ 		"  adox %%r15, %%r14;"
+-		"  adcx %%r12, %%r12;"
++		"  adcx %%rbx, %%rbx;"
+ 		"  adcx %%r13, %%r13;"
+ 		"  adcx %%r14, %%r14;"
+ 
+@@ -640,7 +640,7 @@ static inline void fsqr2(u64 *out, const
+ 		"  adcx %%rcx, %%r10;"     "  movq %%r10, 24(%0);"
+ 		"  movq 16(%1), %%rdx;"    "  mulx %%rdx, %%rax, %%rcx;"    /* f[2]^2 */
+ 		"  adcx %%rax, %%r11;"     "  movq %%r11, 32(%0);"
+-		"  adcx %%rcx, %%r12;"     "  movq %%r12, 40(%0);"
++		"  adcx %%rcx, %%rbx;"     "  movq %%rbx, 40(%0);"
+ 		"  movq 24(%1), %%rdx;"    "  mulx %%rdx, %%rax, %%rcx;"    /* f[3]^2 */
+ 		"  adcx %%rax, %%r13;"     "  movq %%r13, 48(%0);"
+ 		"  adcx %%rcx, %%r14;"     "  movq %%r14, 56(%0);"
+@@ -651,8 +651,8 @@ static inline void fsqr2(u64 *out, const
+ 		"  mulxq 48(%1), %%r9, %%r10;"     "  adcx %%r14, %%r9;"     /* f[2]*f[0] */
+ 		"  mulxq 56(%1), %%rax, %%rcx;"    "  adcx %%rax, %%r10;"    /* f[3]*f[0] */
+ 		"  movq 56(%1), %%rdx;"                                      /* f[3] */
+-		"  mulxq 40(%1), %%r11, %%r12;"     "  adcx %%rcx, %%r11;"    /* f[1]*f[3] */
+-		"  mulxq 48(%1), %%rax, %%r13;"    "  adcx %%rax, %%r12;"    /* f[2]*f[3] */
++		"  mulxq 40(%1), %%r11, %%rbx;"     "  adcx %%rcx, %%r11;"    /* f[1]*f[3] */
++		"  mulxq 48(%1), %%rax, %%r13;"    "  adcx %%rax, %%rbx;"    /* f[2]*f[3] */
+ 		"  movq 40(%1), %%rdx;"             "  adcx %%r15, %%r13;"    /* f1 */
+ 		"  mulxq 48(%1), %%rax, %%rcx;"    "  mov $0, %%r14;"        /* f[2]*f[1] */
+ 
+@@ -662,12 +662,12 @@ static inline void fsqr2(u64 *out, const
+ 		"  adcx %%r8, %%r8;"
+ 		"  adox %%rcx, %%r11;"
+ 		"  adcx %%r9, %%r9;"
+-		"  adox %%r15, %%r12;"
++		"  adox %%r15, %%rbx;"
+ 		"  adcx %%r10, %%r10;"
+ 		"  adox %%r15, %%r13;"
+ 		"  adcx %%r11, %%r11;"
+ 		"  adox %%r15, %%r14;"
+-		"  adcx %%r12, %%r12;"
++		"  adcx %%rbx, %%rbx;"
+ 		"  adcx %%r13, %%r13;"
+ 		"  adcx %%r14, %%r14;"
+ 
+@@ -680,7 +680,7 @@ static inline void fsqr2(u64 *out, const
+ 		"  adcx %%rcx, %%r10;"     "  movq %%r10, 88(%0);"
+ 		"  movq 48(%1), %%rdx;"    "  mulx %%rdx, %%rax, %%rcx;"    /* f[2]^2 */
+ 		"  adcx %%rax, %%r11;"     "  movq %%r11, 96(%0);"
+-		"  adcx %%rcx, %%r12;"     "  movq %%r12, 104(%0);"
++		"  adcx %%rcx, %%rbx;"     "  movq %%rbx, 104(%0);"
+ 		"  movq 56(%1), %%rdx;"    "  mulx %%rdx, %%rax, %%rcx;"    /* f[3]^2 */
+ 		"  adcx %%rax, %%r13;"     "  movq %%r13, 112(%0);"
+ 		"  adcx %%rcx, %%r14;"     "  movq %%r14, 120(%0);"
+@@ -694,11 +694,11 @@ static inline void fsqr2(u64 *out, const
+ 		"  mulxq 32(%1), %%r8, %%r13;"
+ 		"  xor %%rcx, %%rcx;"
+ 		"  adoxq 0(%1), %%r8;"
+-		"  mulxq 40(%1), %%r9, %%r12;"
++		"  mulxq 40(%1), %%r9, %%rbx;"
+ 		"  adcx %%r13, %%r9;"
+ 		"  adoxq 8(%1), %%r9;"
+ 		"  mulxq 48(%1), %%r10, %%r13;"
+-		"  adcx %%r12, %%r10;"
++		"  adcx %%rbx, %%r10;"
+ 		"  adoxq 16(%1), %%r10;"
+ 		"  mulxq 56(%1), %%r11, %%rax;"
+ 		"  adcx %%r13, %%r11;"
+@@ -727,11 +727,11 @@ static inline void fsqr2(u64 *out, const
+ 		"  mulxq 96(%1), %%r8, %%r13;"
+ 		"  xor %%rcx, %%rcx;"
+ 		"  adoxq 64(%1), %%r8;"
+-		"  mulxq 104(%1), %%r9, %%r12;"
++		"  mulxq 104(%1), %%r9, %%rbx;"
+ 		"  adcx %%r13, %%r9;"
+ 		"  adoxq 72(%1), %%r9;"
+ 		"  mulxq 112(%1), %%r10, %%r13;"
+-		"  adcx %%r12, %%r10;"
++		"  adcx %%rbx, %%r10;"
+ 		"  adoxq 80(%1), %%r10;"
+ 		"  mulxq 120(%1), %%r11, %%rax;"
+ 		"  adcx %%r13, %%r11;"
+@@ -756,7 +756,7 @@ static inline void fsqr2(u64 *out, const
+ 		"  movq %%r8, 32(%0);"
+ 	: "+&r" (tmp), "+&r" (f), "+&r" (out)
+ 	:
+-	: "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "memory", "cc"
++	: "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%rbx", "%r13", "%r14", "%r15", "memory", "cc"
+ 	);
+ }
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0056-crypto-arm-64-poly1305-add-artifact-to-.gitignore-fi.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0056-crypto-arm-64-poly1305-add-artifact-to-.gitignore-fi.patch
new file mode 100644
index 0000000..6553716
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0056-crypto-arm-64-poly1305-add-artifact-to-.gitignore-fi.patch
@@ -0,0 +1,35 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Thu, 19 Mar 2020 11:56:17 -0600
+Subject: [PATCH] crypto: arm[64]/poly1305 - add artifact to .gitignore files
+
+commit 6e4e00d8b68ca7eb30d08afb740033e0d36abe55 upstream.
+
+The .S_shipped yields a .S, and the pattern in these directories is to
+add that to .gitignore so that git-status doesn't raise a fuss.
+
+Fixes: a6b803b3ddc7 ("crypto: arm/poly1305 - incorporate OpenSSL/CRYPTOGAMS NEON implementation")
+Fixes: f569ca164751 ("crypto: arm64/poly1305 - incorporate OpenSSL/CRYPTOGAMS NEON implementation")
+Reported-by: Emil Renner Berthing <kernel@esmil.dk>
+Cc: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm/crypto/.gitignore   | 1 +
+ arch/arm64/crypto/.gitignore | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/arch/arm/crypto/.gitignore
++++ b/arch/arm/crypto/.gitignore
+@@ -1,3 +1,4 @@
+ aesbs-core.S
+ sha256-core.S
+ sha512-core.S
++poly1305-core.S
+--- a/arch/arm64/crypto/.gitignore
++++ b/arch/arm64/crypto/.gitignore
+@@ -1,2 +1,3 @@
+ sha256-core.S
+ sha512-core.S
++poly1305-core.S
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0057-crypto-arch-lib-limit-simd-usage-to-4k-chunks.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0057-crypto-arch-lib-limit-simd-usage-to-4k-chunks.patch
new file mode 100644
index 0000000..f8828f2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0057-crypto-arch-lib-limit-simd-usage-to-4k-chunks.patch
@@ -0,0 +1,243 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Thu, 23 Apr 2020 15:54:04 -0600
+Subject: [PATCH] crypto: arch/lib - limit simd usage to 4k chunks
+
+commit 706024a52c614b478b63f7728d202532ce6591a9 upstream.
+
+The initial Zinc patchset, after some mailing list discussion, contained
+code to ensure that kernel_fpu_enable would not be kept on for more than
+a 4k chunk, since it disables preemption. The choice of 4k isn't totally
+scientific, but it's not a bad guess either, and it's what's used in
+both the x86 poly1305, blake2s, and nhpoly1305 code already (in the form
+of PAGE_SIZE, which this commit corrects to be explicitly 4k for the
+former two).
+
+Ard did some back of the envelope calculations and found that
+at 5 cycles/byte (overestimate) on a 1ghz processor (pretty slow), 4k
+means we have a maximum preemption disabling of 20us, which Sebastian
+confirmed was probably a good limit.
+
+Unfortunately the chunking appears to have been left out of the final
+patchset that added the glue code. So, this commit adds it back in.
+
+Fixes: 84e03fa39fbe ("crypto: x86/chacha - expose SIMD ChaCha routine as library function")
+Fixes: b3aad5bad26a ("crypto: arm64/chacha - expose arm64 ChaCha routine as library function")
+Fixes: a44a3430d71b ("crypto: arm/chacha - expose ARM ChaCha routine as library function")
+Fixes: d7d7b8535662 ("crypto: x86/poly1305 - wire up faster implementations for kernel")
+Fixes: f569ca164751 ("crypto: arm64/poly1305 - incorporate OpenSSL/CRYPTOGAMS NEON implementation")
+Fixes: a6b803b3ddc7 ("crypto: arm/poly1305 - incorporate OpenSSL/CRYPTOGAMS NEON implementation")
+Fixes: ed0356eda153 ("crypto: blake2s - x86_64 SIMD implementation")
+Cc: Eric Biggers <ebiggers@google.com>
+Cc: Ard Biesheuvel <ardb@kernel.org>
+Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Cc: stable@vger.kernel.org
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm/crypto/chacha-glue.c        | 14 +++++++++++---
+ arch/arm/crypto/poly1305-glue.c      | 15 +++++++++++----
+ arch/arm64/crypto/chacha-neon-glue.c | 14 +++++++++++---
+ arch/arm64/crypto/poly1305-glue.c    | 15 +++++++++++----
+ arch/x86/crypto/blake2s-glue.c       | 10 ++++------
+ arch/x86/crypto/chacha_glue.c        | 14 +++++++++++---
+ arch/x86/crypto/poly1305_glue.c      | 13 ++++++-------
+ 7 files changed, 65 insertions(+), 30 deletions(-)
+
+--- a/arch/arm/crypto/chacha-glue.c
++++ b/arch/arm/crypto/chacha-glue.c
+@@ -91,9 +91,17 @@ void chacha_crypt_arch(u32 *state, u8 *d
+ 		return;
+ 	}
+ 
+-	kernel_neon_begin();
+-	chacha_doneon(state, dst, src, bytes, nrounds);
+-	kernel_neon_end();
++	do {
++		unsigned int todo = min_t(unsigned int, bytes, SZ_4K);
++
++		kernel_neon_begin();
++		chacha_doneon(state, dst, src, todo, nrounds);
++		kernel_neon_end();
++
++		bytes -= todo;
++		src += todo;
++		dst += todo;
++	} while (bytes);
+ }
+ EXPORT_SYMBOL(chacha_crypt_arch);
+ 
+--- a/arch/arm/crypto/poly1305-glue.c
++++ b/arch/arm/crypto/poly1305-glue.c
+@@ -160,13 +160,20 @@ void poly1305_update_arch(struct poly130
+ 		unsigned int len = round_down(nbytes, POLY1305_BLOCK_SIZE);
+ 
+ 		if (static_branch_likely(&have_neon) && do_neon) {
+-			kernel_neon_begin();
+-			poly1305_blocks_neon(&dctx->h, src, len, 1);
+-			kernel_neon_end();
++			do {
++				unsigned int todo = min_t(unsigned int, len, SZ_4K);
++
++				kernel_neon_begin();
++				poly1305_blocks_neon(&dctx->h, src, todo, 1);
++				kernel_neon_end();
++
++				len -= todo;
++				src += todo;
++			} while (len);
+ 		} else {
+ 			poly1305_blocks_arm(&dctx->h, src, len, 1);
++			src += len;
+ 		}
+-		src += len;
+ 		nbytes %= POLY1305_BLOCK_SIZE;
+ 	}
+ 
+--- a/arch/arm64/crypto/chacha-neon-glue.c
++++ b/arch/arm64/crypto/chacha-neon-glue.c
+@@ -87,9 +87,17 @@ void chacha_crypt_arch(u32 *state, u8 *d
+ 	    !crypto_simd_usable())
+ 		return chacha_crypt_generic(state, dst, src, bytes, nrounds);
+ 
+-	kernel_neon_begin();
+-	chacha_doneon(state, dst, src, bytes, nrounds);
+-	kernel_neon_end();
++	do {
++		unsigned int todo = min_t(unsigned int, bytes, SZ_4K);
++
++		kernel_neon_begin();
++		chacha_doneon(state, dst, src, todo, nrounds);
++		kernel_neon_end();
++
++		bytes -= todo;
++		src += todo;
++		dst += todo;
++	} while (bytes);
+ }
+ EXPORT_SYMBOL(chacha_crypt_arch);
+ 
+--- a/arch/arm64/crypto/poly1305-glue.c
++++ b/arch/arm64/crypto/poly1305-glue.c
+@@ -143,13 +143,20 @@ void poly1305_update_arch(struct poly130
+ 		unsigned int len = round_down(nbytes, POLY1305_BLOCK_SIZE);
+ 
+ 		if (static_branch_likely(&have_neon) && crypto_simd_usable()) {
+-			kernel_neon_begin();
+-			poly1305_blocks_neon(&dctx->h, src, len, 1);
+-			kernel_neon_end();
++			do {
++				unsigned int todo = min_t(unsigned int, len, SZ_4K);
++
++				kernel_neon_begin();
++				poly1305_blocks_neon(&dctx->h, src, todo, 1);
++				kernel_neon_end();
++
++				len -= todo;
++				src += todo;
++			} while (len);
+ 		} else {
+ 			poly1305_blocks(&dctx->h, src, len, 1);
++			src += len;
+ 		}
+-		src += len;
+ 		nbytes %= POLY1305_BLOCK_SIZE;
+ 	}
+ 
+--- a/arch/x86/crypto/blake2s-glue.c
++++ b/arch/x86/crypto/blake2s-glue.c
+@@ -32,16 +32,16 @@ void blake2s_compress_arch(struct blake2
+ 			   const u32 inc)
+ {
+ 	/* SIMD disables preemption, so relax after processing each page. */
+-	BUILD_BUG_ON(PAGE_SIZE / BLAKE2S_BLOCK_SIZE < 8);
++	BUILD_BUG_ON(SZ_4K / BLAKE2S_BLOCK_SIZE < 8);
+ 
+ 	if (!static_branch_likely(&blake2s_use_ssse3) || !crypto_simd_usable()) {
+ 		blake2s_compress_generic(state, block, nblocks, inc);
+ 		return;
+ 	}
+ 
+-	for (;;) {
++	do {
+ 		const size_t blocks = min_t(size_t, nblocks,
+-					    PAGE_SIZE / BLAKE2S_BLOCK_SIZE);
++					    SZ_4K / BLAKE2S_BLOCK_SIZE);
+ 
+ 		kernel_fpu_begin();
+ 		if (IS_ENABLED(CONFIG_AS_AVX512) &&
+@@ -52,10 +52,8 @@ void blake2s_compress_arch(struct blake2
+ 		kernel_fpu_end();
+ 
+ 		nblocks -= blocks;
+-		if (!nblocks)
+-			break;
+ 		block += blocks * BLAKE2S_BLOCK_SIZE;
+-	}
++	} while (nblocks);
+ }
+ EXPORT_SYMBOL(blake2s_compress_arch);
+ 
+--- a/arch/x86/crypto/chacha_glue.c
++++ b/arch/x86/crypto/chacha_glue.c
+@@ -154,9 +154,17 @@ void chacha_crypt_arch(u32 *state, u8 *d
+ 	    bytes <= CHACHA_BLOCK_SIZE)
+ 		return chacha_crypt_generic(state, dst, src, bytes, nrounds);
+ 
+-	kernel_fpu_begin();
+-	chacha_dosimd(state, dst, src, bytes, nrounds);
+-	kernel_fpu_end();
++	do {
++		unsigned int todo = min_t(unsigned int, bytes, SZ_4K);
++
++		kernel_fpu_begin();
++		chacha_dosimd(state, dst, src, todo, nrounds);
++		kernel_fpu_end();
++
++		bytes -= todo;
++		src += todo;
++		dst += todo;
++	} while (bytes);
+ }
+ EXPORT_SYMBOL(chacha_crypt_arch);
+ 
+--- a/arch/x86/crypto/poly1305_glue.c
++++ b/arch/x86/crypto/poly1305_glue.c
+@@ -91,8 +91,8 @@ static void poly1305_simd_blocks(void *c
+ 	struct poly1305_arch_internal *state = ctx;
+ 
+ 	/* SIMD disables preemption, so relax after processing each page. */
+-	BUILD_BUG_ON(PAGE_SIZE < POLY1305_BLOCK_SIZE ||
+-		     PAGE_SIZE % POLY1305_BLOCK_SIZE);
++	BUILD_BUG_ON(SZ_4K < POLY1305_BLOCK_SIZE ||
++		     SZ_4K % POLY1305_BLOCK_SIZE);
+ 
+ 	if (!IS_ENABLED(CONFIG_AS_AVX) || !static_branch_likely(&poly1305_use_avx) ||
+ 	    (len < (POLY1305_BLOCK_SIZE * 18) && !state->is_base2_26) ||
+@@ -102,8 +102,8 @@ static void poly1305_simd_blocks(void *c
+ 		return;
+ 	}
+ 
+-	for (;;) {
+-		const size_t bytes = min_t(size_t, len, PAGE_SIZE);
++	do {
++		const size_t bytes = min_t(size_t, len, SZ_4K);
+ 
+ 		kernel_fpu_begin();
+ 		if (IS_ENABLED(CONFIG_AS_AVX512) && static_branch_likely(&poly1305_use_avx512))
+@@ -113,11 +113,10 @@ static void poly1305_simd_blocks(void *c
+ 		else
+ 			poly1305_blocks_avx(ctx, inp, bytes, padbit);
+ 		kernel_fpu_end();
++
+ 		len -= bytes;
+-		if (!len)
+-			break;
+ 		inp += bytes;
+-	}
++	} while (len);
+ }
+ 
+ static void poly1305_simd_emit(void *ctx, u8 mac[POLY1305_DIGEST_SIZE],
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0058-crypto-lib-chacha20poly1305-Add-missing-function-dec.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0058-crypto-lib-chacha20poly1305-Add-missing-function-dec.patch
new file mode 100644
index 0000000..736147f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0058-crypto-lib-chacha20poly1305-Add-missing-function-dec.patch
@@ -0,0 +1,38 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Herbert Xu <herbert@gondor.apana.org.au>
+Date: Wed, 8 Jul 2020 12:41:13 +1000
+Subject: [PATCH] crypto: lib/chacha20poly1305 - Add missing function
+ declaration
+
+commit 06cc2afbbdf9a9e8df3e2f8db724997dd6e1b4ac upstream.
+
+This patch adds a declaration for chacha20poly1305_selftest to
+silence a sparse warning.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ include/crypto/chacha20poly1305.h | 2 ++
+ lib/crypto/chacha20poly1305.c     | 2 --
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/include/crypto/chacha20poly1305.h
++++ b/include/crypto/chacha20poly1305.h
+@@ -45,4 +45,6 @@ bool chacha20poly1305_decrypt_sg_inplace
+ 					 const u64 nonce,
+ 					 const u8 key[CHACHA20POLY1305_KEY_SIZE]);
+ 
++bool chacha20poly1305_selftest(void);
++
+ #endif /* __CHACHA20POLY1305_H */
+--- a/lib/crypto/chacha20poly1305.c
++++ b/lib/crypto/chacha20poly1305.c
+@@ -21,8 +21,6 @@
+ 
+ #define CHACHA_KEY_WORDS	(CHACHA_KEY_SIZE / sizeof(u32))
+ 
+-bool __init chacha20poly1305_selftest(void);
+-
+ static void chacha_load_key(u32 *k, const u8 *in)
+ {
+ 	k[0] = get_unaligned_le32(in);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0059-crypto-x86-chacha-sse3-use-unaligned-loads-for-state.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0059-crypto-x86-chacha-sse3-use-unaligned-loads-for-state.patch
new file mode 100644
index 0000000..5284787
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0059-crypto-x86-chacha-sse3-use-unaligned-loads-for-state.patch
@@ -0,0 +1,147 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Wed, 8 Jul 2020 12:11:18 +0300
+Subject: [PATCH] crypto: x86/chacha-sse3 - use unaligned loads for state array
+
+commit e79a31715193686e92dadb4caedfbb1f5de3659c upstream.
+
+Due to the fact that the x86 port does not support allocating objects
+on the stack with an alignment that exceeds 8 bytes, we have a rather
+ugly hack in the x86 code for ChaCha to ensure that the state array is
+aligned to 16 bytes, allowing the SSE3 implementation of the algorithm
+to use aligned loads.
+
+Given that the performance benefit of using of aligned loads appears to
+be limited (~0.25% for 1k blocks using tcrypt on a Corei7-8650U), and
+the fact that this hack has leaked into generic ChaCha code, let's just
+remove it.
+
+Cc: Martin Willi <martin@strongswan.org>
+Cc: Herbert Xu <herbert@gondor.apana.org.au>
+Cc: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Reviewed-by: Martin Willi <martin@strongswan.org>
+Reviewed-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/chacha-ssse3-x86_64.S | 16 ++++++++--------
+ arch/x86/crypto/chacha_glue.c         | 17 ++---------------
+ include/crypto/chacha.h               |  4 ----
+ 3 files changed, 10 insertions(+), 27 deletions(-)
+
+--- a/arch/x86/crypto/chacha-ssse3-x86_64.S
++++ b/arch/x86/crypto/chacha-ssse3-x86_64.S
+@@ -120,10 +120,10 @@ ENTRY(chacha_block_xor_ssse3)
+ 	FRAME_BEGIN
+ 
+ 	# x0..3 = s0..3
+-	movdqa		0x00(%rdi),%xmm0
+-	movdqa		0x10(%rdi),%xmm1
+-	movdqa		0x20(%rdi),%xmm2
+-	movdqa		0x30(%rdi),%xmm3
++	movdqu		0x00(%rdi),%xmm0
++	movdqu		0x10(%rdi),%xmm1
++	movdqu		0x20(%rdi),%xmm2
++	movdqu		0x30(%rdi),%xmm3
+ 	movdqa		%xmm0,%xmm8
+ 	movdqa		%xmm1,%xmm9
+ 	movdqa		%xmm2,%xmm10
+@@ -205,10 +205,10 @@ ENTRY(hchacha_block_ssse3)
+ 	# %edx: nrounds
+ 	FRAME_BEGIN
+ 
+-	movdqa		0x00(%rdi),%xmm0
+-	movdqa		0x10(%rdi),%xmm1
+-	movdqa		0x20(%rdi),%xmm2
+-	movdqa		0x30(%rdi),%xmm3
++	movdqu		0x00(%rdi),%xmm0
++	movdqu		0x10(%rdi),%xmm1
++	movdqu		0x20(%rdi),%xmm2
++	movdqu		0x30(%rdi),%xmm3
+ 
+ 	mov		%edx,%r8d
+ 	call		chacha_permute
+--- a/arch/x86/crypto/chacha_glue.c
++++ b/arch/x86/crypto/chacha_glue.c
+@@ -14,8 +14,6 @@
+ #include <linux/module.h>
+ #include <asm/simd.h>
+ 
+-#define CHACHA_STATE_ALIGN 16
+-
+ asmlinkage void chacha_block_xor_ssse3(u32 *state, u8 *dst, const u8 *src,
+ 				       unsigned int len, int nrounds);
+ asmlinkage void chacha_4block_xor_ssse3(u32 *state, u8 *dst, const u8 *src,
+@@ -125,8 +123,6 @@ static void chacha_dosimd(u32 *state, u8
+ 
+ void hchacha_block_arch(const u32 *state, u32 *stream, int nrounds)
+ {
+-	state = PTR_ALIGN(state, CHACHA_STATE_ALIGN);
+-
+ 	if (!static_branch_likely(&chacha_use_simd) || !crypto_simd_usable()) {
+ 		hchacha_block_generic(state, stream, nrounds);
+ 	} else {
+@@ -139,8 +135,6 @@ EXPORT_SYMBOL(hchacha_block_arch);
+ 
+ void chacha_init_arch(u32 *state, const u32 *key, const u8 *iv)
+ {
+-	state = PTR_ALIGN(state, CHACHA_STATE_ALIGN);
+-
+ 	chacha_init_generic(state, key, iv);
+ }
+ EXPORT_SYMBOL(chacha_init_arch);
+@@ -148,8 +142,6 @@ EXPORT_SYMBOL(chacha_init_arch);
+ void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src, unsigned int bytes,
+ 		       int nrounds)
+ {
+-	state = PTR_ALIGN(state, CHACHA_STATE_ALIGN);
+-
+ 	if (!static_branch_likely(&chacha_use_simd) || !crypto_simd_usable() ||
+ 	    bytes <= CHACHA_BLOCK_SIZE)
+ 		return chacha_crypt_generic(state, dst, src, bytes, nrounds);
+@@ -171,15 +163,12 @@ EXPORT_SYMBOL(chacha_crypt_arch);
+ static int chacha_simd_stream_xor(struct skcipher_request *req,
+ 				  const struct chacha_ctx *ctx, const u8 *iv)
+ {
+-	u32 *state, state_buf[16 + 2] __aligned(8);
++	u32 state[CHACHA_STATE_WORDS] __aligned(8);
+ 	struct skcipher_walk walk;
+ 	int err;
+ 
+ 	err = skcipher_walk_virt(&walk, req, false);
+ 
+-	BUILD_BUG_ON(CHACHA_STATE_ALIGN != 16);
+-	state = PTR_ALIGN(state_buf + 0, CHACHA_STATE_ALIGN);
+-
+ 	chacha_init_generic(state, ctx->key, iv);
+ 
+ 	while (walk.nbytes > 0) {
+@@ -218,12 +207,10 @@ static int xchacha_simd(struct skcipher_
+ {
+ 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+ 	struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
+-	u32 *state, state_buf[16 + 2] __aligned(8);
++	u32 state[CHACHA_STATE_WORDS] __aligned(8);
+ 	struct chacha_ctx subctx;
+ 	u8 real_iv[16];
+ 
+-	BUILD_BUG_ON(CHACHA_STATE_ALIGN != 16);
+-	state = PTR_ALIGN(state_buf + 0, CHACHA_STATE_ALIGN);
+ 	chacha_init_generic(state, ctx->key, req->iv);
+ 
+ 	if (req->cryptlen > CHACHA_BLOCK_SIZE && crypto_simd_usable()) {
+--- a/include/crypto/chacha.h
++++ b/include/crypto/chacha.h
+@@ -25,11 +25,7 @@
+ #define CHACHA_BLOCK_SIZE	64
+ #define CHACHAPOLY_IV_SIZE	12
+ 
+-#ifdef CONFIG_X86_64
+-#define CHACHA_STATE_WORDS	((CHACHA_BLOCK_SIZE + 12) / sizeof(u32))
+-#else
+ #define CHACHA_STATE_WORDS	(CHACHA_BLOCK_SIZE / sizeof(u32))
+-#endif
+ 
+ /* 192-bit nonce, then 64-bit stream position */
+ #define XCHACHA_IV_SIZE		32
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0060-crypto-x86-curve25519-Remove-unused-carry-variables.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0060-crypto-x86-curve25519-Remove-unused-carry-variables.patch
new file mode 100644
index 0000000..5a2d20a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0060-crypto-x86-curve25519-Remove-unused-carry-variables.patch
@@ -0,0 +1,46 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Herbert Xu <herbert@gondor.apana.org.au>
+Date: Thu, 23 Jul 2020 17:50:48 +1000
+Subject: [PATCH] crypto: x86/curve25519 - Remove unused carry variables
+
+commit 054a5540fb8f7268e2c79e9deab4242db15c8cba upstream.
+
+The carry variables are assigned but never used, which upsets
+the compiler.  This patch removes them.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Reviewed-by: Karthikeyan Bhargavan <karthik.bhargavan@gmail.com>
+Acked-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/curve25519-x86_64.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+--- a/arch/x86/crypto/curve25519-x86_64.c
++++ b/arch/x86/crypto/curve25519-x86_64.c
+@@ -948,10 +948,8 @@ static void store_felem(u64 *b, u64 *f)
+ {
+ 	u64 f30 = f[3U];
+ 	u64 top_bit0 = f30 >> (u32)63U;
+-	u64 carry0;
+ 	u64 f31;
+ 	u64 top_bit;
+-	u64 carry;
+ 	u64 f0;
+ 	u64 f1;
+ 	u64 f2;
+@@ -970,11 +968,11 @@ static void store_felem(u64 *b, u64 *f)
+ 	u64 o2;
+ 	u64 o3;
+ 	f[3U] = f30 & (u64)0x7fffffffffffffffU;
+-	carry0 = add_scalar(f, f, (u64)19U * top_bit0);
++	add_scalar(f, f, (u64)19U * top_bit0);
+ 	f31 = f[3U];
+ 	top_bit = f31 >> (u32)63U;
+ 	f[3U] = f31 & (u64)0x7fffffffffffffffU;
+-	carry = add_scalar(f, f, (u64)19U * top_bit);
++	add_scalar(f, f, (u64)19U * top_bit);
+ 	f0 = f[0U];
+ 	f1 = f[1U];
+ 	f2 = f[2U];
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0061-crypto-arm-curve25519-include-linux-scatterlist.h.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0061-crypto-arm-curve25519-include-linux-scatterlist.h.patch
new file mode 100644
index 0000000..b58fd08
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0061-crypto-arm-curve25519-include-linux-scatterlist.h.patch
@@ -0,0 +1,36 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Fabio Estevam <festevam@gmail.com>
+Date: Mon, 24 Aug 2020 11:09:53 -0300
+Subject: [PATCH] crypto: arm/curve25519 - include <linux/scatterlist.h>
+
+commit 6779d0e6b0fe193ab3010ea201782ca6f75a3862 upstream.
+
+Building ARM allmodconfig leads to the following warnings:
+
+arch/arm/crypto/curve25519-glue.c:73:12: error: implicit declaration of function 'sg_copy_to_buffer' [-Werror=implicit-function-declaration]
+arch/arm/crypto/curve25519-glue.c:74:9: error: implicit declaration of function 'sg_nents_for_len' [-Werror=implicit-function-declaration]
+arch/arm/crypto/curve25519-glue.c:88:11: error: implicit declaration of function 'sg_copy_from_buffer' [-Werror=implicit-function-declaration]
+
+Include <linux/scatterlist.h> to fix such warnings
+
+Reported-by: Olof's autobuilder <build@lixom.net>
+Fixes: 0c3dc787a62a ("crypto: algapi - Remove skbuff.h inclusion")
+Signed-off-by: Fabio Estevam <festevam@gmail.com>
+Acked-by: Ard Biesheuvel <ardb@kernel.org>
+Acked-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm/crypto/curve25519-glue.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm/crypto/curve25519-glue.c
++++ b/arch/arm/crypto/curve25519-glue.c
+@@ -16,6 +16,7 @@
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/jump_label.h>
++#include <linux/scatterlist.h>
+ #include <crypto/curve25519.h>
+ 
+ asmlinkage void curve25519_neon(u8 mypublic[CURVE25519_KEY_SIZE],
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0062-crypto-arm-poly1305-Add-prototype-for-poly1305_block.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0062-crypto-arm-poly1305-Add-prototype-for-poly1305_block.patch
new file mode 100644
index 0000000..cf3724a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0062-crypto-arm-poly1305-Add-prototype-for-poly1305_block.patch
@@ -0,0 +1,33 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Herbert Xu <herbert@gondor.apana.org.au>
+Date: Tue, 25 Aug 2020 11:23:00 +1000
+Subject: [PATCH] crypto: arm/poly1305 - Add prototype for poly1305_blocks_neon
+
+commit 51982ea02aef972132eb35c583d3e4c5b83166e5 upstream.
+
+This patch adds a prototype for poly1305_blocks_neon to slience
+a compiler warning:
+
+  CC [M]  arch/arm/crypto/poly1305-glue.o
+../arch/arm/crypto/poly1305-glue.c:25:13: warning: no previous prototype for `poly1305_blocks_neon' [-Wmissing-prototypes]
+ void __weak poly1305_blocks_neon(void *state, const u8 *src, u32 len, u32 hibit)
+             ^~~~~~~~~~~~~~~~~~~~
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Acked-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm/crypto/poly1305-glue.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm/crypto/poly1305-glue.c
++++ b/arch/arm/crypto/poly1305-glue.c
+@@ -20,6 +20,7 @@
+ 
+ void poly1305_init_arm(void *state, const u8 *key);
+ void poly1305_blocks_arm(void *state, const u8 *src, u32 len, u32 hibit);
++void poly1305_blocks_neon(void *state, const u8 *src, u32 len, u32 hibit);
+ void poly1305_emit_arm(void *state, u8 *digest, const u32 *nonce);
+ 
+ void __weak poly1305_blocks_neon(void *state, const u8 *src, u32 len, u32 hibit)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0063-crypto-curve25519-x86_64-Use-XORL-r32-32.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0063-crypto-curve25519-x86_64-Use-XORL-r32-32.patch
new file mode 100644
index 0000000..dd76e2a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0063-crypto-curve25519-x86_64-Use-XORL-r32-32.patch
@@ -0,0 +1,261 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Uros Bizjak <ubizjak@gmail.com>
+Date: Thu, 27 Aug 2020 19:30:58 +0200
+Subject: [PATCH] crypto: curve25519-x86_64 - Use XORL r32,32
+
+commit db719539fd3889836900bf912755aa30a5985e9a upstream.
+
+x86_64 zero extends 32bit operations, so for 64bit operands,
+XORL r32,r32 is functionally equal to XORL r64,r64, but avoids
+a REX prefix byte when legacy registers are used.
+
+Signed-off-by: Uros Bizjak <ubizjak@gmail.com>
+Cc: Herbert Xu <herbert@gondor.apana.org.au>
+Cc: "David S. Miller" <davem@davemloft.net>
+Acked-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/curve25519-x86_64.c | 68 ++++++++++++++---------------
+ 1 file changed, 34 insertions(+), 34 deletions(-)
+
+--- a/arch/x86/crypto/curve25519-x86_64.c
++++ b/arch/x86/crypto/curve25519-x86_64.c
+@@ -45,11 +45,11 @@ static inline u64 add_scalar(u64 *out, c
+ 
+ 	asm volatile(
+ 		/* Clear registers to propagate the carry bit */
+-		"  xor %%r8, %%r8;"
+-		"  xor %%r9, %%r9;"
+-		"  xor %%r10, %%r10;"
+-		"  xor %%r11, %%r11;"
+-		"  xor %1, %1;"
++		"  xor %%r8d, %%r8d;"
++		"  xor %%r9d, %%r9d;"
++		"  xor %%r10d, %%r10d;"
++		"  xor %%r11d, %%r11d;"
++		"  xor %k1, %k1;"
+ 
+ 		/* Begin addition chain */
+ 		"  addq 0(%3), %0;"
+@@ -93,7 +93,7 @@ static inline void fadd(u64 *out, const
+ 		"  cmovc %0, %%rax;"
+ 
+ 		/* Step 2: Add carry*38 to the original sum */
+-		"  xor %%rcx, %%rcx;"
++		"  xor %%ecx, %%ecx;"
+ 		"  add %%rax, %%r8;"
+ 		"  adcx %%rcx, %%r9;"
+ 		"  movq %%r9, 8(%1);"
+@@ -165,28 +165,28 @@ static inline void fmul(u64 *out, const
+ 
+ 		/* Compute src1[0] * src2 */
+ 		"  movq 0(%1), %%rdx;"
+-		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  movq %%r8, 0(%0);"
++		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10d, %%r10d;"   "  movq %%r8, 0(%0);"
+ 		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  movq %%r10, 8(%0);"
+ 		"  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"
+ 		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"
+ 		/* Compute src1[1] * src2 */
+ 		"  movq 8(%1), %%rdx;"
+-		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  adcxq 8(%0), %%r8;"    "  movq %%r8, 8(%0);"
++		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10d, %%r10d;"   "  adcxq 8(%0), %%r8;"    "  movq %%r8, 8(%0);"
+ 		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 16(%0);"
+ 		"  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  mov $0, %%r8;"
+ 		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
+ 		/* Compute src1[2] * src2 */
+ 		"  movq 16(%1), %%rdx;"
+-		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 16(%0), %%r8;"    "  movq %%r8, 16(%0);"
++		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10d, %%r10d;"   "  adcxq 16(%0), %%r8;"   "  movq %%r8, 16(%0);"
+ 		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 24(%0);"
+ 		"  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  mov $0, %%r8;"
+ 		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
+ 		/* Compute src1[3] * src2 */
+ 		"  movq 24(%1), %%rdx;"
+-		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 24(%0), %%r8;"    "  movq %%r8, 24(%0);"
++		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10d, %%r10d;"   "  adcxq 24(%0), %%r8;"   "  movq %%r8, 24(%0);"
+ 		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 32(%0);"
+ 		"  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  movq %%rbx, 40(%0);"    "  mov $0, %%r8;"
+ 		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  movq %%r14, 48(%0);"    "  mov $0, %%rax;"
+@@ -200,7 +200,7 @@ static inline void fmul(u64 *out, const
+ 		/* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */
+ 		"  mov $38, %%rdx;"
+ 		"  mulxq 32(%1), %%r8, %%r13;"
+-		"  xor %3, %3;"
++		"  xor %k3, %k3;"
+ 		"  adoxq 0(%1), %%r8;"
+ 		"  mulxq 40(%1), %%r9, %%rbx;"
+ 		"  adcx %%r13, %%r9;"
+@@ -246,28 +246,28 @@ static inline void fmul2(u64 *out, const
+ 
+ 		/* Compute src1[0] * src2 */
+ 		"  movq 0(%1), %%rdx;"
+-		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  movq %%r8, 0(%0);"
++		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10d, %%r10d;"   "  movq %%r8, 0(%0);"
+ 		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  movq %%r10, 8(%0);"
+ 		"  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"
+ 		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"
+ 		/* Compute src1[1] * src2 */
+ 		"  movq 8(%1), %%rdx;"
+-		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  adcxq 8(%0), %%r8;"    "  movq %%r8, 8(%0);"
++		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10d, %%r10d;"   "  adcxq 8(%0), %%r8;"    "  movq %%r8, 8(%0);"
+ 		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 16(%0);"
+ 		"  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  mov $0, %%r8;"
+ 		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
+ 		/* Compute src1[2] * src2 */
+ 		"  movq 16(%1), %%rdx;"
+-		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 16(%0), %%r8;"    "  movq %%r8, 16(%0);"
++		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10d, %%r10d;"   "  adcxq 16(%0), %%r8;"   "  movq %%r8, 16(%0);"
+ 		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 24(%0);"
+ 		"  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  mov $0, %%r8;"
+ 		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
+ 		/* Compute src1[3] * src2 */
+ 		"  movq 24(%1), %%rdx;"
+-		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 24(%0), %%r8;"    "  movq %%r8, 24(%0);"
++		"  mulxq 0(%3), %%r8, %%r9;"       "  xor %%r10d, %%r10d;"   "  adcxq 24(%0), %%r8;"   "  movq %%r8, 24(%0);"
+ 		"  mulxq 8(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 32(%0);"
+ 		"  mulxq 16(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  movq %%rbx, 40(%0);"    "  mov $0, %%r8;"
+ 		"  mulxq 24(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  movq %%r14, 48(%0);"    "  mov $0, %%rax;"
+@@ -277,29 +277,29 @@ static inline void fmul2(u64 *out, const
+ 
+ 		/* Compute src1[0] * src2 */
+ 		"  movq 32(%1), %%rdx;"
+-		"  mulxq 32(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  movq %%r8, 64(%0);"
+-		"  mulxq 40(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  movq %%r10, 72(%0);"
++		"  mulxq 32(%3), %%r8, %%r9;"      "  xor %%r10d, %%r10d;"   "  movq %%r8, 64(%0);"
++		"  mulxq 40(%3), %%r10, %%r11;"    "  adox %%r9, %%r10;"     "  movq %%r10, 72(%0);"
+ 		"  mulxq 48(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"
+ 		"  mulxq 56(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"
+ 		/* Compute src1[1] * src2 */
+ 		"  movq 40(%1), %%rdx;"
+-		"  mulxq 32(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"     "  adcxq 72(%0), %%r8;"    "  movq %%r8, 72(%0);"
+-		"  mulxq 40(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 80(%0);"
++		"  mulxq 32(%3), %%r8, %%r9;"      "  xor %%r10d, %%r10d;"   "  adcxq 72(%0), %%r8;"   "  movq %%r8, 72(%0);"
++		"  mulxq 40(%3), %%r10, %%r11;"    "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 80(%0);"
+ 		"  mulxq 48(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  mov $0, %%r8;"
+ 		"  mulxq 56(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
+ 		/* Compute src1[2] * src2 */
+ 		"  movq 48(%1), %%rdx;"
+-		"  mulxq 32(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 80(%0), %%r8;"    "  movq %%r8, 80(%0);"
+-		"  mulxq 40(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 88(%0);"
++		"  mulxq 32(%3), %%r8, %%r9;"      "  xor %%r10d, %%r10d;"   "  adcxq 80(%0), %%r8;"   "  movq %%r8, 80(%0);"
++		"  mulxq 40(%3), %%r10, %%r11;"    "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 88(%0);"
+ 		"  mulxq 48(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  mov $0, %%r8;"
+ 		"  mulxq 56(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"
+ 		/* Compute src1[3] * src2 */
+ 		"  movq 56(%1), %%rdx;"
+-		"  mulxq 32(%3), %%r8, %%r9;"       "  xor %%r10, %%r10;"    "  adcxq 88(%0), %%r8;"    "  movq %%r8, 88(%0);"
+-		"  mulxq 40(%3), %%r10, %%r11;"     "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 96(%0);"
++		"  mulxq 32(%3), %%r8, %%r9;"      "  xor %%r10d, %%r10d;"   "  adcxq 88(%0), %%r8;"   "  movq %%r8, 88(%0);"
++		"  mulxq 40(%3), %%r10, %%r11;"    "  adox %%r9, %%r10;"     "  adcx %%rbx, %%r10;"    "  movq %%r10, 96(%0);"
+ 		"  mulxq 48(%3), %%rbx, %%r13;"    "  adox %%r11, %%rbx;"    "  adcx %%r14, %%rbx;"    "  movq %%rbx, 104(%0);"    "  mov $0, %%r8;"
+ 		"  mulxq 56(%3), %%r14, %%rdx;"    "  adox %%r13, %%r14;"    "  adcx %%rax, %%r14;"    "  movq %%r14, 112(%0);"    "  mov $0, %%rax;"
+ 		                                   "  adox %%rdx, %%rax;"    "  adcx %%r8, %%rax;"     "  movq %%rax, 120(%0);"
+@@ -312,7 +312,7 @@ static inline void fmul2(u64 *out, const
+ 		/* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */
+ 		"  mov $38, %%rdx;"
+ 		"  mulxq 32(%1), %%r8, %%r13;"
+-		"  xor %3, %3;"
++		"  xor %k3, %k3;"
+ 		"  adoxq 0(%1), %%r8;"
+ 		"  mulxq 40(%1), %%r9, %%rbx;"
+ 		"  adcx %%r13, %%r9;"
+@@ -345,7 +345,7 @@ static inline void fmul2(u64 *out, const
+ 		/* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */
+ 		"  mov $38, %%rdx;"
+ 		"  mulxq 96(%1), %%r8, %%r13;"
+-		"  xor %3, %3;"
++		"  xor %k3, %k3;"
+ 		"  adoxq 64(%1), %%r8;"
+ 		"  mulxq 104(%1), %%r9, %%rbx;"
+ 		"  adcx %%r13, %%r9;"
+@@ -516,7 +516,7 @@ static inline void fsqr(u64 *out, const
+ 
+ 		/* Step 1: Compute all partial products */
+ 		"  movq 0(%1), %%rdx;"                                       /* f[0] */
+-		"  mulxq 8(%1), %%r8, %%r14;"      "  xor %%r15, %%r15;"     /* f[1]*f[0] */
++		"  mulxq 8(%1), %%r8, %%r14;"      "  xor %%r15d, %%r15d;"   /* f[1]*f[0] */
+ 		"  mulxq 16(%1), %%r9, %%r10;"     "  adcx %%r14, %%r9;"     /* f[2]*f[0] */
+ 		"  mulxq 24(%1), %%rax, %%rcx;"    "  adcx %%rax, %%r10;"    /* f[3]*f[0] */
+ 		"  movq 24(%1), %%rdx;"                                      /* f[3] */
+@@ -526,7 +526,7 @@ static inline void fsqr(u64 *out, const
+ 		"  mulxq 16(%1), %%rax, %%rcx;"    "  mov $0, %%r14;"        /* f[2]*f[1] */
+ 
+ 		/* Step 2: Compute two parallel carry chains */
+-		"  xor %%r15, %%r15;"
++		"  xor %%r15d, %%r15d;"
+ 		"  adox %%rax, %%r10;"
+ 		"  adcx %%r8, %%r8;"
+ 		"  adox %%rcx, %%r11;"
+@@ -563,7 +563,7 @@ static inline void fsqr(u64 *out, const
+ 		/* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */
+ 		"  mov $38, %%rdx;"
+ 		"  mulxq 32(%1), %%r8, %%r13;"
+-		"  xor %%rcx, %%rcx;"
++		"  xor %%ecx, %%ecx;"
+ 		"  adoxq 0(%1), %%r8;"
+ 		"  mulxq 40(%1), %%r9, %%rbx;"
+ 		"  adcx %%r13, %%r9;"
+@@ -607,7 +607,7 @@ static inline void fsqr2(u64 *out, const
+ 	asm volatile(
+ 		/* Step 1: Compute all partial products */
+ 		"  movq 0(%1), %%rdx;"                                       /* f[0] */
+-		"  mulxq 8(%1), %%r8, %%r14;"      "  xor %%r15, %%r15;"     /* f[1]*f[0] */
++		"  mulxq 8(%1), %%r8, %%r14;"      "  xor %%r15d, %%r15d;"   /* f[1]*f[0] */
+ 		"  mulxq 16(%1), %%r9, %%r10;"     "  adcx %%r14, %%r9;"     /* f[2]*f[0] */
+ 		"  mulxq 24(%1), %%rax, %%rcx;"    "  adcx %%rax, %%r10;"    /* f[3]*f[0] */
+ 		"  movq 24(%1), %%rdx;"                                      /* f[3] */
+@@ -617,7 +617,7 @@ static inline void fsqr2(u64 *out, const
+ 		"  mulxq 16(%1), %%rax, %%rcx;"    "  mov $0, %%r14;"        /* f[2]*f[1] */
+ 
+ 		/* Step 2: Compute two parallel carry chains */
+-		"  xor %%r15, %%r15;"
++		"  xor %%r15d, %%r15d;"
+ 		"  adox %%rax, %%r10;"
+ 		"  adcx %%r8, %%r8;"
+ 		"  adox %%rcx, %%r11;"
+@@ -647,7 +647,7 @@ static inline void fsqr2(u64 *out, const
+ 
+ 		/* Step 1: Compute all partial products */
+ 		"  movq 32(%1), %%rdx;"                                       /* f[0] */
+-		"  mulxq 40(%1), %%r8, %%r14;"      "  xor %%r15, %%r15;"     /* f[1]*f[0] */
++		"  mulxq 40(%1), %%r8, %%r14;"     "  xor %%r15d, %%r15d;"   /* f[1]*f[0] */
+ 		"  mulxq 48(%1), %%r9, %%r10;"     "  adcx %%r14, %%r9;"     /* f[2]*f[0] */
+ 		"  mulxq 56(%1), %%rax, %%rcx;"    "  adcx %%rax, %%r10;"    /* f[3]*f[0] */
+ 		"  movq 56(%1), %%rdx;"                                      /* f[3] */
+@@ -657,7 +657,7 @@ static inline void fsqr2(u64 *out, const
+ 		"  mulxq 48(%1), %%rax, %%rcx;"    "  mov $0, %%r14;"        /* f[2]*f[1] */
+ 
+ 		/* Step 2: Compute two parallel carry chains */
+-		"  xor %%r15, %%r15;"
++		"  xor %%r15d, %%r15d;"
+ 		"  adox %%rax, %%r10;"
+ 		"  adcx %%r8, %%r8;"
+ 		"  adox %%rcx, %%r11;"
+@@ -692,7 +692,7 @@ static inline void fsqr2(u64 *out, const
+ 		/* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */
+ 		"  mov $38, %%rdx;"
+ 		"  mulxq 32(%1), %%r8, %%r13;"
+-		"  xor %%rcx, %%rcx;"
++		"  xor %%ecx, %%ecx;"
+ 		"  adoxq 0(%1), %%r8;"
+ 		"  mulxq 40(%1), %%r9, %%rbx;"
+ 		"  adcx %%r13, %%r9;"
+@@ -725,7 +725,7 @@ static inline void fsqr2(u64 *out, const
+ 		/* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */
+ 		"  mov $38, %%rdx;"
+ 		"  mulxq 96(%1), %%r8, %%r13;"
+-		"  xor %%rcx, %%rcx;"
++		"  xor %%ecx, %%ecx;"
+ 		"  adoxq 64(%1), %%r8;"
+ 		"  mulxq 104(%1), %%r9, %%rbx;"
+ 		"  adcx %%r13, %%r9;"
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0064-crypto-poly1305-x86_64-Use-XORL-r32-32.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0064-crypto-poly1305-x86_64-Use-XORL-r32-32.patch
new file mode 100644
index 0000000..4fcaa1e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0064-crypto-poly1305-x86_64-Use-XORL-r32-32.patch
@@ -0,0 +1,59 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Uros Bizjak <ubizjak@gmail.com>
+Date: Thu, 27 Aug 2020 19:38:31 +0200
+Subject: [PATCH] crypto: poly1305-x86_64 - Use XORL r32,32
+
+commit 7dfd1e01b3dfc13431b1b25720cf2692a7e111ef upstream.
+
+x86_64 zero extends 32bit operations, so for 64bit operands,
+XORL r32,r32 is functionally equal to XORQ r64,r64, but avoids
+a REX prefix byte when legacy registers are used.
+
+Signed-off-by: Uros Bizjak <ubizjak@gmail.com>
+Cc: Herbert Xu <herbert@gondor.apana.org.au>
+Cc: "David S. Miller" <davem@davemloft.net>
+Acked-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/poly1305-x86_64-cryptogams.pl | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/arch/x86/crypto/poly1305-x86_64-cryptogams.pl
++++ b/arch/x86/crypto/poly1305-x86_64-cryptogams.pl
+@@ -246,7 +246,7 @@ $code.=<<___ if (!$kernel);
+ ___
+ &declare_function("poly1305_init_x86_64", 32, 3);
+ $code.=<<___;
+-	xor	%rax,%rax
++	xor	%eax,%eax
+ 	mov	%rax,0($ctx)		# initialize hash value
+ 	mov	%rax,8($ctx)
+ 	mov	%rax,16($ctx)
+@@ -2869,7 +2869,7 @@ $code.=<<___;
+ .type	poly1305_init_base2_44,\@function,3
+ .align	32
+ poly1305_init_base2_44:
+-	xor	%rax,%rax
++	xor	%eax,%eax
+ 	mov	%rax,0($ctx)		# initialize hash value
+ 	mov	%rax,8($ctx)
+ 	mov	%rax,16($ctx)
+@@ -3963,7 +3963,7 @@ xor128_decrypt_n_pad:
+ 	mov	\$16,$len
+ 	sub	%r10,$len
+ 	xor	%eax,%eax
+-	xor	%r11,%r11
++	xor	%r11d,%r11d
+ .Loop_dec_byte:
+ 	mov	($inp,$otp),%r11b
+ 	mov	($otp),%al
+@@ -4101,7 +4101,7 @@ avx_handler:
+ 	.long	0xa548f3fc		# cld; rep movsq
+ 
+ 	mov	$disp,%rsi
+-	xor	%rcx,%rcx		# arg1, UNW_FLAG_NHANDLER
++	xor	%ecx,%ecx		# arg1, UNW_FLAG_NHANDLER
+ 	mov	8(%rsi),%rdx		# arg2, disp->ImageBase
+ 	mov	0(%rsi),%r8		# arg3, disp->ControlPc
+ 	mov	16(%rsi),%r9		# arg4, disp->FunctionEntry
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0065-crypto-x86-poly1305-Remove-assignments-with-no-effec.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0065-crypto-x86-poly1305-Remove-assignments-with-no-effec.patch
new file mode 100644
index 0000000..ee64bfe
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0065-crypto-x86-poly1305-Remove-assignments-with-no-effec.patch
@@ -0,0 +1,29 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Herbert Xu <herbert@gondor.apana.org.au>
+Date: Thu, 24 Sep 2020 13:29:04 +1000
+Subject: [PATCH] crypto: x86/poly1305 - Remove assignments with no effect
+
+commit 4a0c1de64bf9d9027a6f19adfba89fc27893db23 upstream.
+
+This patch removes a few ineffectual assignments from the function
+crypto_poly1305_setdctxkey.
+
+Reported-by: kernel test robot <lkp@intel.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/poly1305_glue.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+--- a/arch/x86/crypto/poly1305_glue.c
++++ b/arch/x86/crypto/poly1305_glue.c
+@@ -157,9 +157,6 @@ static unsigned int crypto_poly1305_setd
+ 			dctx->s[1] = get_unaligned_le32(&inp[4]);
+ 			dctx->s[2] = get_unaligned_le32(&inp[8]);
+ 			dctx->s[3] = get_unaligned_le32(&inp[12]);
+-			inp += POLY1305_BLOCK_SIZE;
+-			len -= POLY1305_BLOCK_SIZE;
+-			acc += POLY1305_BLOCK_SIZE;
+ 			dctx->sset = true;
+ 		}
+ 	}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0066-crypto-x86-poly1305-add-back-a-needed-assignment.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0066-crypto-x86-poly1305-add-back-a-needed-assignment.patch
new file mode 100644
index 0000000..dce8bb9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0066-crypto-x86-poly1305-add-back-a-needed-assignment.patch
@@ -0,0 +1,33 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@google.com>
+Date: Fri, 23 Oct 2020 15:27:48 -0700
+Subject: [PATCH] crypto: x86/poly1305 - add back a needed assignment
+
+commit c3a98c3ad5c0dc60a1ac66bf91147a3f39cac96b upstream.
+
+One of the assignments that was removed by commit 4a0c1de64bf9 ("crypto:
+x86/poly1305 - Remove assignments with no effect") is actually needed,
+since it affects the return value.
+
+This fixes the following crypto self-test failure:
+
+    alg: shash: poly1305-simd test failed (wrong result) on test vector 2, cfg="init+update+final aligned buffer"
+
+Fixes: 4a0c1de64bf9 ("crypto: x86/poly1305 - Remove assignments with no effect")
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/x86/crypto/poly1305_glue.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/x86/crypto/poly1305_glue.c
++++ b/arch/x86/crypto/poly1305_glue.c
+@@ -157,6 +157,7 @@ static unsigned int crypto_poly1305_setd
+ 			dctx->s[1] = get_unaligned_le32(&inp[4]);
+ 			dctx->s[2] = get_unaligned_le32(&inp[8]);
+ 			dctx->s[3] = get_unaligned_le32(&inp[12]);
++			acc += POLY1305_BLOCK_SIZE;
+ 			dctx->sset = true;
+ 		}
+ 	}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0067-crypto-Kconfig-CRYPTO_MANAGER_EXTRA_TESTS-requires-t.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0067-crypto-Kconfig-CRYPTO_MANAGER_EXTRA_TESTS-requires-t.patch
new file mode 100644
index 0000000..31c47df
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0067-crypto-Kconfig-CRYPTO_MANAGER_EXTRA_TESTS-requires-t.patch
@@ -0,0 +1,33 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Mon, 2 Nov 2020 14:48:15 +0100
+Subject: [PATCH] crypto: Kconfig - CRYPTO_MANAGER_EXTRA_TESTS requires the
+ manager
+
+commit 6569e3097f1c4a490bdf2b23d326855e04942dfd upstream.
+
+The extra tests in the manager actually require the manager to be
+selected too. Otherwise the linker gives errors like:
+
+ld: arch/x86/crypto/chacha_glue.o: in function `chacha_simd_stream_xor':
+chacha_glue.c:(.text+0x422): undefined reference to `crypto_simd_disabled_for_test'
+
+Fixes: 2343d1529aff ("crypto: Kconfig - allow tests to be disabled when manager is disabled")
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ crypto/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -145,7 +145,7 @@ config CRYPTO_MANAGER_DISABLE_TESTS
+ 
+ config CRYPTO_MANAGER_EXTRA_TESTS
+ 	bool "Enable extra run-time crypto self tests"
+-	depends on DEBUG_KERNEL && !CRYPTO_MANAGER_DISABLE_TESTS
++	depends on DEBUG_KERNEL && !CRYPTO_MANAGER_DISABLE_TESTS && CRYPTO_MANAGER
+ 	help
+ 	  Enable extra run-time self tests of registered crypto algorithms,
+ 	  including randomized fuzz tests.
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0068-crypto-arm-chacha-neon-optimize-for-non-block-size-m.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0068-crypto-arm-chacha-neon-optimize-for-non-block-size-m.patch
new file mode 100644
index 0000000..b31b8d9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0068-crypto-arm-chacha-neon-optimize-for-non-block-size-m.patch
@@ -0,0 +1,272 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Tue, 3 Nov 2020 17:28:09 +0100
+Subject: [PATCH] crypto: arm/chacha-neon - optimize for non-block size
+ multiples
+
+commit 86cd97ec4b943af35562a74688bc4e909b32c3d1 upstream.
+
+The current NEON based ChaCha implementation for ARM is optimized for
+multiples of 4x the ChaCha block size (64 bytes). This makes sense for
+block encryption, but given that ChaCha is also often used in the
+context of networking, it makes sense to consider arbitrary length
+inputs as well.
+
+For example, WireGuard typically uses 1420 byte packets, and performing
+ChaCha encryption involves 5 invocations of chacha_4block_xor_neon()
+and 3 invocations of chacha_block_xor_neon(), where the last one also
+involves a memcpy() using a buffer on the stack to process the final
+chunk of 1420 % 64 == 12 bytes.
+
+Let's optimize for this case as well, by letting chacha_4block_xor_neon()
+deal with any input size between 64 and 256 bytes, using NEON permutation
+instructions and overlapping loads and stores. This way, the 140 byte
+tail of a 1420 byte input buffer can simply be processed in one go.
+
+This results in the following performance improvements for 1420 byte
+blocks, without significant impact on power-of-2 input sizes. (Note
+that Raspberry Pi is widely used in combination with a 32-bit kernel,
+even though the core is 64-bit capable)
+
+   Cortex-A8  (BeagleBone)       :   7%
+   Cortex-A15 (Calxeda Midway)   :  21%
+   Cortex-A53 (Raspberry Pi 3)   :   3%
+   Cortex-A72 (Raspberry Pi 4)   :  19%
+
+Cc: Eric Biggers <ebiggers@google.com>
+Cc: "Jason A . Donenfeld" <Jason@zx2c4.com>
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm/crypto/chacha-glue.c      | 34 +++++------
+ arch/arm/crypto/chacha-neon-core.S | 97 +++++++++++++++++++++++++++---
+ 2 files changed, 107 insertions(+), 24 deletions(-)
+
+--- a/arch/arm/crypto/chacha-glue.c
++++ b/arch/arm/crypto/chacha-glue.c
+@@ -23,7 +23,7 @@
+ asmlinkage void chacha_block_xor_neon(const u32 *state, u8 *dst, const u8 *src,
+ 				      int nrounds);
+ asmlinkage void chacha_4block_xor_neon(const u32 *state, u8 *dst, const u8 *src,
+-				       int nrounds);
++				       int nrounds, unsigned int nbytes);
+ asmlinkage void hchacha_block_arm(const u32 *state, u32 *out, int nrounds);
+ asmlinkage void hchacha_block_neon(const u32 *state, u32 *out, int nrounds);
+ 
+@@ -42,24 +42,24 @@ static void chacha_doneon(u32 *state, u8
+ {
+ 	u8 buf[CHACHA_BLOCK_SIZE];
+ 
+-	while (bytes >= CHACHA_BLOCK_SIZE * 4) {
+-		chacha_4block_xor_neon(state, dst, src, nrounds);
+-		bytes -= CHACHA_BLOCK_SIZE * 4;
+-		src += CHACHA_BLOCK_SIZE * 4;
+-		dst += CHACHA_BLOCK_SIZE * 4;
+-		state[12] += 4;
+-	}
+-	while (bytes >= CHACHA_BLOCK_SIZE) {
+-		chacha_block_xor_neon(state, dst, src, nrounds);
+-		bytes -= CHACHA_BLOCK_SIZE;
+-		src += CHACHA_BLOCK_SIZE;
+-		dst += CHACHA_BLOCK_SIZE;
+-		state[12]++;
++	while (bytes > CHACHA_BLOCK_SIZE) {
++		unsigned int l = min(bytes, CHACHA_BLOCK_SIZE * 4U);
++
++		chacha_4block_xor_neon(state, dst, src, nrounds, l);
++		bytes -= l;
++		src += l;
++		dst += l;
++		state[12] += DIV_ROUND_UP(l, CHACHA_BLOCK_SIZE);
+ 	}
+ 	if (bytes) {
+-		memcpy(buf, src, bytes);
+-		chacha_block_xor_neon(state, buf, buf, nrounds);
+-		memcpy(dst, buf, bytes);
++		const u8 *s = src;
++		u8 *d = dst;
++
++		if (bytes != CHACHA_BLOCK_SIZE)
++			s = d = memcpy(buf, src, bytes);
++		chacha_block_xor_neon(state, d, s, nrounds);
++		if (d != dst)
++			memcpy(dst, buf, bytes);
+ 	}
+ }
+ 
+--- a/arch/arm/crypto/chacha-neon-core.S
++++ b/arch/arm/crypto/chacha-neon-core.S
+@@ -47,6 +47,7 @@
+   */
+ 
+ #include <linux/linkage.h>
++#include <asm/cache.h>
+ 
+ 	.text
+ 	.fpu		neon
+@@ -205,7 +206,7 @@ ENDPROC(hchacha_block_neon)
+ 
+ 	.align		5
+ ENTRY(chacha_4block_xor_neon)
+-	push		{r4-r5}
++	push		{r4, lr}
+ 	mov		r4, sp			// preserve the stack pointer
+ 	sub		ip, sp, #0x20		// allocate a 32 byte buffer
+ 	bic		ip, ip, #0x1f		// aligned to 32 bytes
+@@ -229,10 +230,10 @@ ENTRY(chacha_4block_xor_neon)
+ 	vld1.32		{q0-q1}, [r0]
+ 	vld1.32		{q2-q3}, [ip]
+ 
+-	adr		r5, .Lctrinc
++	adr		lr, .Lctrinc
+ 	vdup.32		q15, d7[1]
+ 	vdup.32		q14, d7[0]
+-	vld1.32		{q4}, [r5, :128]
++	vld1.32		{q4}, [lr, :128]
+ 	vdup.32		q13, d6[1]
+ 	vdup.32		q12, d6[0]
+ 	vdup.32		q11, d5[1]
+@@ -455,7 +456,7 @@ ENTRY(chacha_4block_xor_neon)
+ 
+ 	// Re-interleave the words in the first two rows of each block (x0..7).
+ 	// Also add the counter values 0-3 to x12[0-3].
+-	  vld1.32	{q8}, [r5, :128]	// load counter values 0-3
++	  vld1.32	{q8}, [lr, :128]	// load counter values 0-3
+ 	vzip.32		q0, q1			// => (0 1 0 1) (0 1 0 1)
+ 	vzip.32		q2, q3			// => (2 3 2 3) (2 3 2 3)
+ 	vzip.32		q4, q5			// => (4 5 4 5) (4 5 4 5)
+@@ -493,6 +494,8 @@ ENTRY(chacha_4block_xor_neon)
+ 
+ 	// Re-interleave the words in the last two rows of each block (x8..15).
+ 	vld1.32		{q8-q9}, [sp, :256]
++	  mov		sp, r4		// restore original stack pointer
++	  ldr		r4, [r4, #8]	// load number of bytes
+ 	vzip.32		q12, q13	// => (12 13 12 13) (12 13 12 13)
+ 	vzip.32		q14, q15	// => (14 15 14 15) (14 15 14 15)
+ 	vzip.32		q8, q9		// => (8 9 8 9) (8 9 8 9)
+@@ -520,41 +523,121 @@ ENTRY(chacha_4block_xor_neon)
+ 	// XOR the rest of the data with the keystream
+ 
+ 	vld1.8		{q0-q1}, [r2]!
++	subs		r4, r4, #96
+ 	veor		q0, q0, q8
+ 	veor		q1, q1, q12
++	ble		.Lle96
+ 	vst1.8		{q0-q1}, [r1]!
+ 
+ 	vld1.8		{q0-q1}, [r2]!
++	subs		r4, r4, #32
+ 	veor		q0, q0, q2
+ 	veor		q1, q1, q6
++	ble		.Lle128
+ 	vst1.8		{q0-q1}, [r1]!
+ 
+ 	vld1.8		{q0-q1}, [r2]!
++	subs		r4, r4, #32
+ 	veor		q0, q0, q10
+ 	veor		q1, q1, q14
++	ble		.Lle160
+ 	vst1.8		{q0-q1}, [r1]!
+ 
+ 	vld1.8		{q0-q1}, [r2]!
++	subs		r4, r4, #32
+ 	veor		q0, q0, q4
+ 	veor		q1, q1, q5
++	ble		.Lle192
+ 	vst1.8		{q0-q1}, [r1]!
+ 
+ 	vld1.8		{q0-q1}, [r2]!
++	subs		r4, r4, #32
+ 	veor		q0, q0, q9
+ 	veor		q1, q1, q13
++	ble		.Lle224
+ 	vst1.8		{q0-q1}, [r1]!
+ 
+ 	vld1.8		{q0-q1}, [r2]!
++	subs		r4, r4, #32
+ 	veor		q0, q0, q3
+ 	veor		q1, q1, q7
++	blt		.Llt256
++.Lout:
+ 	vst1.8		{q0-q1}, [r1]!
+ 
+ 	vld1.8		{q0-q1}, [r2]
+-	  mov		sp, r4		// restore original stack pointer
+ 	veor		q0, q0, q11
+ 	veor		q1, q1, q15
+ 	vst1.8		{q0-q1}, [r1]
+ 
+-	pop		{r4-r5}
+-	bx		lr
++	pop		{r4, pc}
++
++.Lle192:
++	vmov		q4, q9
++	vmov		q5, q13
++
++.Lle160:
++	// nothing to do
++
++.Lfinalblock:
++	// Process the final block if processing less than 4 full blocks.
++	// Entered with 32 bytes of ChaCha cipher stream in q4-q5, and the
++	// previous 32 byte output block that still needs to be written at
++	// [r1] in q0-q1.
++	beq		.Lfullblock
++
++.Lpartialblock:
++	adr		lr, .Lpermute + 32
++	add		r2, r2, r4
++	add		lr, lr, r4
++	add		r4, r4, r1
++
++	vld1.8		{q2-q3}, [lr]
++	vld1.8		{q6-q7}, [r2]
++
++	add		r4, r4, #32
++
++	vtbl.8		d4, {q4-q5}, d4
++	vtbl.8		d5, {q4-q5}, d5
++	vtbl.8		d6, {q4-q5}, d6
++	vtbl.8		d7, {q4-q5}, d7
++
++	veor		q6, q6, q2
++	veor		q7, q7, q3
++
++	vst1.8		{q6-q7}, [r4]	// overlapping stores
++	vst1.8		{q0-q1}, [r1]
++	pop		{r4, pc}
++
++.Lfullblock:
++	vmov		q11, q4
++	vmov		q15, q5
++	b		.Lout
++.Lle96:
++	vmov		q4, q2
++	vmov		q5, q6
++	b		.Lfinalblock
++.Lle128:
++	vmov		q4, q10
++	vmov		q5, q14
++	b		.Lfinalblock
++.Lle224:
++	vmov		q4, q3
++	vmov		q5, q7
++	b		.Lfinalblock
++.Llt256:
++	vmov		q4, q11
++	vmov		q5, q15
++	b		.Lpartialblock
+ ENDPROC(chacha_4block_xor_neon)
++
++	.align		L1_CACHE_SHIFT
++.Lpermute:
++	.byte		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
++	.byte		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
++	.byte		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
++	.byte		0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
++	.byte		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
++	.byte		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
++	.byte		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
++	.byte		0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0069-crypto-arm64-chacha-simplify-tail-block-handling.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0069-crypto-arm64-chacha-simplify-tail-block-handling.patch
new file mode 100644
index 0000000..42e9048
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0069-crypto-arm64-chacha-simplify-tail-block-handling.patch
@@ -0,0 +1,324 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Fri, 6 Nov 2020 17:39:38 +0100
+Subject: [PATCH] crypto: arm64/chacha - simplify tail block handling
+
+commit c4fc6328d6c67690a7e6e03f43a5a976a13120ef upstream.
+
+Based on lessons learnt from optimizing the 32-bit version of this driver,
+we can simplify the arm64 version considerably, by reordering the final
+two stores when the last block is not a multiple of 64 bytes. This removes
+the need to use permutation instructions to calculate the elements that are
+clobbered by the final overlapping store, given that the store of the
+penultimate block now follows it, and that one carries the correct values
+for those elements already.
+
+While at it, simplify the overlapping loads as well, by calculating the
+address of the final overlapping load upfront, and switching to this
+address for every load that would otherwise extend past the end of the
+source buffer.
+
+There is no impact on performance, but the resulting code is substantially
+smaller and easier to follow.
+
+Cc: Eric Biggers <ebiggers@google.com>
+Cc: "Jason A . Donenfeld" <Jason@zx2c4.com>
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm64/crypto/chacha-neon-core.S | 193 ++++++++++-----------------
+ 1 file changed, 69 insertions(+), 124 deletions(-)
+
+--- a/arch/arm64/crypto/chacha-neon-core.S
++++ b/arch/arm64/crypto/chacha-neon-core.S
+@@ -195,7 +195,6 @@ ENTRY(chacha_4block_xor_neon)
+ 	adr_l		x10, .Lpermute
+ 	and		x5, x4, #63
+ 	add		x10, x10, x5
+-	add		x11, x10, #64
+ 
+ 	//
+ 	// This function encrypts four consecutive ChaCha blocks by loading
+@@ -645,11 +644,11 @@ CPU_BE(	  rev		a15, a15	)
+ 	zip2		v31.4s, v14.4s, v15.4s
+ 	  eor		a15, a15, w9
+ 
+-	mov		x3, #64
++	add		x3, x2, x4
++	sub		x3, x3, #128		// start of last block
++
+ 	subs		x5, x4, #128
+-	add		x6, x5, x2
+-	csel		x3, x3, xzr, ge
+-	csel		x2, x2, x6, ge
++	csel		x2, x2, x3, ge
+ 
+ 	// interleave 64-bit words in state n, n+2
+ 	zip1		v0.2d, v16.2d, v18.2d
+@@ -658,13 +657,10 @@ CPU_BE(	  rev		a15, a15	)
+ 	zip1		v8.2d, v17.2d, v19.2d
+ 	zip2		v12.2d, v17.2d, v19.2d
+ 	  stp		a2, a3, [x1, #-56]
+-	ld1		{v16.16b-v19.16b}, [x2], x3
+ 
+ 	subs		x6, x4, #192
+-	ccmp		x3, xzr, #4, lt
+-	add		x7, x6, x2
+-	csel		x3, x3, xzr, eq
+-	csel		x2, x2, x7, eq
++	ld1		{v16.16b-v19.16b}, [x2], #64
++	csel		x2, x2, x3, ge
+ 
+ 	zip1		v1.2d, v20.2d, v22.2d
+ 	zip2		v5.2d, v20.2d, v22.2d
+@@ -672,13 +668,10 @@ CPU_BE(	  rev		a15, a15	)
+ 	zip1		v9.2d, v21.2d, v23.2d
+ 	zip2		v13.2d, v21.2d, v23.2d
+ 	  stp		a6, a7, [x1, #-40]
+-	ld1		{v20.16b-v23.16b}, [x2], x3
+ 
+ 	subs		x7, x4, #256
+-	ccmp		x3, xzr, #4, lt
+-	add		x8, x7, x2
+-	csel		x3, x3, xzr, eq
+-	csel		x2, x2, x8, eq
++	ld1		{v20.16b-v23.16b}, [x2], #64
++	csel		x2, x2, x3, ge
+ 
+ 	zip1		v2.2d, v24.2d, v26.2d
+ 	zip2		v6.2d, v24.2d, v26.2d
+@@ -686,12 +679,10 @@ CPU_BE(	  rev		a15, a15	)
+ 	zip1		v10.2d, v25.2d, v27.2d
+ 	zip2		v14.2d, v25.2d, v27.2d
+ 	  stp		a10, a11, [x1, #-24]
+-	ld1		{v24.16b-v27.16b}, [x2], x3
+ 
+ 	subs		x8, x4, #320
+-	ccmp		x3, xzr, #4, lt
+-	add		x9, x8, x2
+-	csel		x2, x2, x9, eq
++	ld1		{v24.16b-v27.16b}, [x2], #64
++	csel		x2, x2, x3, ge
+ 
+ 	zip1		v3.2d, v28.2d, v30.2d
+ 	zip2		v7.2d, v28.2d, v30.2d
+@@ -699,151 +690,105 @@ CPU_BE(	  rev		a15, a15	)
+ 	zip1		v11.2d, v29.2d, v31.2d
+ 	zip2		v15.2d, v29.2d, v31.2d
+ 	  stp		a14, a15, [x1, #-8]
++
++	tbnz		x5, #63, .Lt128
+ 	ld1		{v28.16b-v31.16b}, [x2]
+ 
+ 	// xor with corresponding input, write to output
+-	tbnz		x5, #63, 0f
+ 	eor		v16.16b, v16.16b, v0.16b
+ 	eor		v17.16b, v17.16b, v1.16b
+ 	eor		v18.16b, v18.16b, v2.16b
+ 	eor		v19.16b, v19.16b, v3.16b
+-	st1		{v16.16b-v19.16b}, [x1], #64
+-	cbz		x5, .Lout
+ 
+-	tbnz		x6, #63, 1f
++	tbnz		x6, #63, .Lt192
++
+ 	eor		v20.16b, v20.16b, v4.16b
+ 	eor		v21.16b, v21.16b, v5.16b
+ 	eor		v22.16b, v22.16b, v6.16b
+ 	eor		v23.16b, v23.16b, v7.16b
+-	st1		{v20.16b-v23.16b}, [x1], #64
+-	cbz		x6, .Lout
+ 
+-	tbnz		x7, #63, 2f
++	st1		{v16.16b-v19.16b}, [x1], #64
++	tbnz		x7, #63, .Lt256
++
+ 	eor		v24.16b, v24.16b, v8.16b
+ 	eor		v25.16b, v25.16b, v9.16b
+ 	eor		v26.16b, v26.16b, v10.16b
+ 	eor		v27.16b, v27.16b, v11.16b
+-	st1		{v24.16b-v27.16b}, [x1], #64
+-	cbz		x7, .Lout
+ 
+-	tbnz		x8, #63, 3f
++	st1		{v20.16b-v23.16b}, [x1], #64
++	tbnz		x8, #63, .Lt320
++
+ 	eor		v28.16b, v28.16b, v12.16b
+ 	eor		v29.16b, v29.16b, v13.16b
+ 	eor		v30.16b, v30.16b, v14.16b
+ 	eor		v31.16b, v31.16b, v15.16b
++
++	st1		{v24.16b-v27.16b}, [x1], #64
+ 	st1		{v28.16b-v31.16b}, [x1]
+ 
+ .Lout:	frame_pop
+ 	ret
+ 
+-	// fewer than 128 bytes of in/output
+-0:	ld1		{v8.16b}, [x10]
+-	ld1		{v9.16b}, [x11]
+-	movi		v10.16b, #16
+-	sub		x2, x1, #64
+-	add		x1, x1, x5
+-	ld1		{v16.16b-v19.16b}, [x2]
+-	tbl		v4.16b, {v0.16b-v3.16b}, v8.16b
+-	tbx		v20.16b, {v16.16b-v19.16b}, v9.16b
+-	add		v8.16b, v8.16b, v10.16b
+-	add		v9.16b, v9.16b, v10.16b
+-	tbl		v5.16b, {v0.16b-v3.16b}, v8.16b
+-	tbx		v21.16b, {v16.16b-v19.16b}, v9.16b
+-	add		v8.16b, v8.16b, v10.16b
+-	add		v9.16b, v9.16b, v10.16b
+-	tbl		v6.16b, {v0.16b-v3.16b}, v8.16b
+-	tbx		v22.16b, {v16.16b-v19.16b}, v9.16b
+-	add		v8.16b, v8.16b, v10.16b
+-	add		v9.16b, v9.16b, v10.16b
+-	tbl		v7.16b, {v0.16b-v3.16b}, v8.16b
+-	tbx		v23.16b, {v16.16b-v19.16b}, v9.16b
+-
+-	eor		v20.16b, v20.16b, v4.16b
+-	eor		v21.16b, v21.16b, v5.16b
+-	eor		v22.16b, v22.16b, v6.16b
+-	eor		v23.16b, v23.16b, v7.16b
+-	st1		{v20.16b-v23.16b}, [x1]
+-	b		.Lout
+-
+ 	// fewer than 192 bytes of in/output
+-1:	ld1		{v8.16b}, [x10]
+-	ld1		{v9.16b}, [x11]
+-	movi		v10.16b, #16
+-	add		x1, x1, x6
+-	tbl		v0.16b, {v4.16b-v7.16b}, v8.16b
+-	tbx		v20.16b, {v16.16b-v19.16b}, v9.16b
+-	add		v8.16b, v8.16b, v10.16b
+-	add		v9.16b, v9.16b, v10.16b
+-	tbl		v1.16b, {v4.16b-v7.16b}, v8.16b
+-	tbx		v21.16b, {v16.16b-v19.16b}, v9.16b
+-	add		v8.16b, v8.16b, v10.16b
+-	add		v9.16b, v9.16b, v10.16b
+-	tbl		v2.16b, {v4.16b-v7.16b}, v8.16b
+-	tbx		v22.16b, {v16.16b-v19.16b}, v9.16b
+-	add		v8.16b, v8.16b, v10.16b
+-	add		v9.16b, v9.16b, v10.16b
+-	tbl		v3.16b, {v4.16b-v7.16b}, v8.16b
+-	tbx		v23.16b, {v16.16b-v19.16b}, v9.16b
+-
+-	eor		v20.16b, v20.16b, v0.16b
+-	eor		v21.16b, v21.16b, v1.16b
+-	eor		v22.16b, v22.16b, v2.16b
+-	eor		v23.16b, v23.16b, v3.16b
+-	st1		{v20.16b-v23.16b}, [x1]
++.Lt192:	cbz		x5, 1f				// exactly 128 bytes?
++	ld1		{v28.16b-v31.16b}, [x10]
++	add		x5, x5, x1
++	tbl		v28.16b, {v4.16b-v7.16b}, v28.16b
++	tbl		v29.16b, {v4.16b-v7.16b}, v29.16b
++	tbl		v30.16b, {v4.16b-v7.16b}, v30.16b
++	tbl		v31.16b, {v4.16b-v7.16b}, v31.16b
++
++0:	eor		v20.16b, v20.16b, v28.16b
++	eor		v21.16b, v21.16b, v29.16b
++	eor		v22.16b, v22.16b, v30.16b
++	eor		v23.16b, v23.16b, v31.16b
++	st1		{v20.16b-v23.16b}, [x5]		// overlapping stores
++1:	st1		{v16.16b-v19.16b}, [x1]
+ 	b		.Lout
+ 
++	// fewer than 128 bytes of in/output
++.Lt128:	ld1		{v28.16b-v31.16b}, [x10]
++	add		x5, x5, x1
++	sub		x1, x1, #64
++	tbl		v28.16b, {v0.16b-v3.16b}, v28.16b
++	tbl		v29.16b, {v0.16b-v3.16b}, v29.16b
++	tbl		v30.16b, {v0.16b-v3.16b}, v30.16b
++	tbl		v31.16b, {v0.16b-v3.16b}, v31.16b
++	ld1		{v16.16b-v19.16b}, [x1]		// reload first output block
++	b		0b
++
+ 	// fewer than 256 bytes of in/output
+-2:	ld1		{v4.16b}, [x10]
+-	ld1		{v5.16b}, [x11]
+-	movi		v6.16b, #16
+-	add		x1, x1, x7
++.Lt256:	cbz		x6, 2f				// exactly 192 bytes?
++	ld1		{v4.16b-v7.16b}, [x10]
++	add		x6, x6, x1
+ 	tbl		v0.16b, {v8.16b-v11.16b}, v4.16b
+-	tbx		v24.16b, {v20.16b-v23.16b}, v5.16b
+-	add		v4.16b, v4.16b, v6.16b
+-	add		v5.16b, v5.16b, v6.16b
+-	tbl		v1.16b, {v8.16b-v11.16b}, v4.16b
+-	tbx		v25.16b, {v20.16b-v23.16b}, v5.16b
+-	add		v4.16b, v4.16b, v6.16b
+-	add		v5.16b, v5.16b, v6.16b
+-	tbl		v2.16b, {v8.16b-v11.16b}, v4.16b
+-	tbx		v26.16b, {v20.16b-v23.16b}, v5.16b
+-	add		v4.16b, v4.16b, v6.16b
+-	add		v5.16b, v5.16b, v6.16b
+-	tbl		v3.16b, {v8.16b-v11.16b}, v4.16b
+-	tbx		v27.16b, {v20.16b-v23.16b}, v5.16b
+-
+-	eor		v24.16b, v24.16b, v0.16b
+-	eor		v25.16b, v25.16b, v1.16b
+-	eor		v26.16b, v26.16b, v2.16b
+-	eor		v27.16b, v27.16b, v3.16b
+-	st1		{v24.16b-v27.16b}, [x1]
++	tbl		v1.16b, {v8.16b-v11.16b}, v5.16b
++	tbl		v2.16b, {v8.16b-v11.16b}, v6.16b
++	tbl		v3.16b, {v8.16b-v11.16b}, v7.16b
++
++	eor		v28.16b, v28.16b, v0.16b
++	eor		v29.16b, v29.16b, v1.16b
++	eor		v30.16b, v30.16b, v2.16b
++	eor		v31.16b, v31.16b, v3.16b
++	st1		{v28.16b-v31.16b}, [x6]		// overlapping stores
++2:	st1		{v20.16b-v23.16b}, [x1]
+ 	b		.Lout
+ 
+ 	// fewer than 320 bytes of in/output
+-3:	ld1		{v4.16b}, [x10]
+-	ld1		{v5.16b}, [x11]
+-	movi		v6.16b, #16
+-	add		x1, x1, x8
++.Lt320:	cbz		x7, 3f				// exactly 256 bytes?
++	ld1		{v4.16b-v7.16b}, [x10]
++	add		x7, x7, x1
+ 	tbl		v0.16b, {v12.16b-v15.16b}, v4.16b
+-	tbx		v28.16b, {v24.16b-v27.16b}, v5.16b
+-	add		v4.16b, v4.16b, v6.16b
+-	add		v5.16b, v5.16b, v6.16b
+-	tbl		v1.16b, {v12.16b-v15.16b}, v4.16b
+-	tbx		v29.16b, {v24.16b-v27.16b}, v5.16b
+-	add		v4.16b, v4.16b, v6.16b
+-	add		v5.16b, v5.16b, v6.16b
+-	tbl		v2.16b, {v12.16b-v15.16b}, v4.16b
+-	tbx		v30.16b, {v24.16b-v27.16b}, v5.16b
+-	add		v4.16b, v4.16b, v6.16b
+-	add		v5.16b, v5.16b, v6.16b
+-	tbl		v3.16b, {v12.16b-v15.16b}, v4.16b
+-	tbx		v31.16b, {v24.16b-v27.16b}, v5.16b
++	tbl		v1.16b, {v12.16b-v15.16b}, v5.16b
++	tbl		v2.16b, {v12.16b-v15.16b}, v6.16b
++	tbl		v3.16b, {v12.16b-v15.16b}, v7.16b
+ 
+ 	eor		v28.16b, v28.16b, v0.16b
+ 	eor		v29.16b, v29.16b, v1.16b
+ 	eor		v30.16b, v30.16b, v2.16b
+ 	eor		v31.16b, v31.16b, v3.16b
+-	st1		{v28.16b-v31.16b}, [x1]
++	st1		{v28.16b-v31.16b}, [x7]		// overlapping stores
++3:	st1		{v24.16b-v27.16b}, [x1]
+ 	b		.Lout
+ ENDPROC(chacha_4block_xor_neon)
+ 
+@@ -851,7 +796,7 @@ ENDPROC(chacha_4block_xor_neon)
+ 	.align		L1_CACHE_SHIFT
+ .Lpermute:
+ 	.set		.Li, 0
+-	.rept		192
++	.rept		128
+ 	.byte		(.Li - 64)
+ 	.set		.Li, .Li + 1
+ 	.endr
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0070-crypto-lib-chacha20poly1305-define-empty-module-exit.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0070-crypto-lib-chacha20poly1305-define-empty-module-exit.patch
new file mode 100644
index 0000000..084ae74
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0070-crypto-lib-chacha20poly1305-define-empty-module-exit.patch
@@ -0,0 +1,37 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 15 Jan 2021 20:30:12 +0100
+Subject: [PATCH] crypto: lib/chacha20poly1305 - define empty module exit
+ function
+
+commit ac88c322d0f2917d41d13553c69e9d7f043c8b6f upstream.
+
+With no mod_exit function, users are unable to unload the module after
+use. I'm not aware of any reason why module unloading should be
+prohibited for this one, so this commit simply adds an empty exit
+function.
+
+Reported-and-tested-by: John Donnelly <john.p.donnelly@oracle.com>
+Acked-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ lib/crypto/chacha20poly1305.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/lib/crypto/chacha20poly1305.c
++++ b/lib/crypto/chacha20poly1305.c
+@@ -364,7 +364,12 @@ static int __init mod_init(void)
+ 	return 0;
+ }
+ 
++static void __exit mod_exit(void)
++{
++}
++
+ module_init(mod_init);
++module_exit(mod_exit);
+ MODULE_LICENSE("GPL v2");
+ MODULE_DESCRIPTION("ChaCha20Poly1305 AEAD construction");
+ MODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0071-crypto-arm-chacha-neon-add-missing-counter-increment.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0071-crypto-arm-chacha-neon-add-missing-counter-increment.patch
new file mode 100644
index 0000000..ea3cc80
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0071-crypto-arm-chacha-neon-add-missing-counter-increment.patch
@@ -0,0 +1,38 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Sun, 13 Dec 2020 15:39:29 +0100
+Subject: [PATCH] crypto: arm/chacha-neon - add missing counter increment
+
+commit fd16931a2f518a32753920ff20895e5cf04c8ff1 upstream.
+
+Commit 86cd97ec4b943af3 ("crypto: arm/chacha-neon - optimize for non-block
+size multiples") refactored the chacha block handling in the glue code in
+a way that may result in the counter increment to be omitted when calling
+chacha_block_xor_neon() to process a full block. This violates the skcipher
+API, which requires that the output IV is suitable for handling more input
+as long as the preceding input has been presented in round multiples of the
+block size. Also, the same code is exposed via the chacha library interface
+whose callers may actually rely on this increment to occur even for final
+blocks that are smaller than the chacha block size.
+
+So increment the counter after calling chacha_block_xor_neon().
+
+Fixes: 86cd97ec4b943af3 ("crypto: arm/chacha-neon - optimize for non-block size multiples")
+Reported-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm/crypto/chacha-glue.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm/crypto/chacha-glue.c
++++ b/arch/arm/crypto/chacha-glue.c
+@@ -60,6 +60,7 @@ static void chacha_doneon(u32 *state, u8
+ 		chacha_block_xor_neon(state, d, s, nrounds);
+ 		if (d != dst)
+ 			memcpy(dst, buf, bytes);
++		state[12]++;
+ 	}
+ }
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0072-net-WireGuard-secure-network-tunnel.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0072-net-WireGuard-secure-network-tunnel.patch
new file mode 100644
index 0000000..9e37bbb
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0072-net-WireGuard-secure-network-tunnel.patch
@@ -0,0 +1,8071 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Mon, 9 Dec 2019 00:27:34 +0100
+Subject: [PATCH] net: WireGuard secure network tunnel
+
+commit e7096c131e5161fa3b8e52a650d7719d2857adfd upstream.
+
+WireGuard is a layer 3 secure networking tunnel made specifically for
+the kernel, that aims to be much simpler and easier to audit than IPsec.
+Extensive documentation and description of the protocol and
+considerations, along with formal proofs of the cryptography, are
+available at:
+
+  * https://www.wireguard.com/
+  * https://www.wireguard.com/papers/wireguard.pdf
+
+This commit implements WireGuard as a simple network device driver,
+accessible in the usual RTNL way used by virtual network drivers. It
+makes use of the udp_tunnel APIs, GRO, GSO, NAPI, and the usual set of
+networking subsystem APIs. It has a somewhat novel multicore queueing
+system designed for maximum throughput and minimal latency of encryption
+operations, but it is implemented modestly using workqueues and NAPI.
+Configuration is done via generic Netlink, and following a review from
+the Netlink maintainer a year ago, several high profile userspace tools
+have already implemented the API.
+
+This commit also comes with several different tests, both in-kernel
+tests and out-of-kernel tests based on network namespaces, taking profit
+of the fact that sockets used by WireGuard intentionally stay in the
+namespace the WireGuard interface was originally created, exactly like
+the semantics of userspace tun devices. See wireguard.com/netns/ for
+pictures and examples.
+
+The source code is fairly short, but rather than combining everything
+into a single file, WireGuard is developed as cleanly separable files,
+making auditing and comprehension easier. Things are laid out as
+follows:
+
+  * noise.[ch], cookie.[ch], messages.h: These implement the bulk of the
+    cryptographic aspects of the protocol, and are mostly data-only in
+    nature, taking in buffers of bytes and spitting out buffers of
+    bytes. They also handle reference counting for their various shared
+    pieces of data, like keys and key lists.
+
+  * ratelimiter.[ch]: Used as an integral part of cookie.[ch] for
+    ratelimiting certain types of cryptographic operations in accordance
+    with particular WireGuard semantics.
+
+  * allowedips.[ch], peerlookup.[ch]: The main lookup structures of
+    WireGuard, the former being trie-like with particular semantics, an
+    integral part of the design of the protocol, and the latter just
+    being nice helper functions around the various hashtables we use.
+
+  * device.[ch]: Implementation of functions for the netdevice and for
+    rtnl, responsible for maintaining the life of a given interface and
+    wiring it up to the rest of WireGuard.
+
+  * peer.[ch]: Each interface has a list of peers, with helper functions
+    available here for creation, destruction, and reference counting.
+
+  * socket.[ch]: Implementation of functions related to udp_socket and
+    the general set of kernel socket APIs, for sending and receiving
+    ciphertext UDP packets, and taking care of WireGuard-specific sticky
+    socket routing semantics for the automatic roaming.
+
+  * netlink.[ch]: Userspace API entry point for configuring WireGuard
+    peers and devices. The API has been implemented by several userspace
+    tools and network management utility, and the WireGuard project
+    distributes the basic wg(8) tool.
+
+  * queueing.[ch]: Shared function on the rx and tx path for handling
+    the various queues used in the multicore algorithms.
+
+  * send.c: Handles encrypting outgoing packets in parallel on
+    multiple cores, before sending them in order on a single core, via
+    workqueues and ring buffers. Also handles sending handshake and cookie
+    messages as part of the protocol, in parallel.
+
+  * receive.c: Handles decrypting incoming packets in parallel on
+    multiple cores, before passing them off in order to be ingested via
+    the rest of the networking subsystem with GRO via the typical NAPI
+    poll function. Also handles receiving handshake and cookie messages
+    as part of the protocol, in parallel.
+
+  * timers.[ch]: Uses the timer wheel to implement protocol particular
+    event timeouts, and gives a set of very simple event-driven entry
+    point functions for callers.
+
+  * main.c, version.h: Initialization and deinitialization of the module.
+
+  * selftest/*.h: Runtime unit tests for some of the most security
+    sensitive functions.
+
+  * tools/testing/selftests/wireguard/netns.sh: Aforementioned testing
+    script using network namespaces.
+
+This commit aims to be as self-contained as possible, implementing
+WireGuard as a standalone module not needing much special handling or
+coordination from the network subsystem. I expect for future
+optimizations to the network stack to positively improve WireGuard, and
+vice-versa, but for the time being, this exists as intentionally
+standalone.
+
+We introduce a menu option for CONFIG_WIREGUARD, as well as providing a
+verbose debug log and self-tests via CONFIG_WIREGUARD_DEBUG.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Cc: David Miller <davem@davemloft.net>
+Cc: Greg KH <gregkh@linuxfoundation.org>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Herbert Xu <herbert@gondor.apana.org.au>
+Cc: linux-crypto@vger.kernel.org
+Cc: linux-kernel@vger.kernel.org
+Cc: netdev@vger.kernel.org
+Signed-off-by: David S. Miller <davem@davemloft.net>
+[Jason: ported to 5.4 by doing the following:
+ - wg_get_device_start uses genl_family_attrbuf
+ - trival skb_redirect_reset change from 2c64605b590e is folded in
+ - skb_list_walk_safe was already backported prior]
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ MAINTAINERS                                  |   8 +
+ drivers/net/Kconfig                          |  41 +
+ drivers/net/Makefile                         |   1 +
+ drivers/net/wireguard/Makefile               |  18 +
+ drivers/net/wireguard/allowedips.c           | 381 +++++++++
+ drivers/net/wireguard/allowedips.h           |  59 ++
+ drivers/net/wireguard/cookie.c               | 236 ++++++
+ drivers/net/wireguard/cookie.h               |  59 ++
+ drivers/net/wireguard/device.c               | 458 ++++++++++
+ drivers/net/wireguard/device.h               |  65 ++
+ drivers/net/wireguard/main.c                 |  64 ++
+ drivers/net/wireguard/messages.h             | 128 +++
+ drivers/net/wireguard/netlink.c              | 648 +++++++++++++++
+ drivers/net/wireguard/netlink.h              |  12 +
+ drivers/net/wireguard/noise.c                | 828 +++++++++++++++++++
+ drivers/net/wireguard/noise.h                | 137 +++
+ drivers/net/wireguard/peer.c                 | 240 ++++++
+ drivers/net/wireguard/peer.h                 |  83 ++
+ drivers/net/wireguard/peerlookup.c           | 221 +++++
+ drivers/net/wireguard/peerlookup.h           |  64 ++
+ drivers/net/wireguard/queueing.c             |  53 ++
+ drivers/net/wireguard/queueing.h             | 197 +++++
+ drivers/net/wireguard/ratelimiter.c          | 223 +++++
+ drivers/net/wireguard/ratelimiter.h          |  19 +
+ drivers/net/wireguard/receive.c              | 595 +++++++++++++
+ drivers/net/wireguard/selftest/allowedips.c  | 683 +++++++++++++++
+ drivers/net/wireguard/selftest/counter.c     | 104 +++
+ drivers/net/wireguard/selftest/ratelimiter.c | 226 +++++
+ drivers/net/wireguard/send.c                 | 413 +++++++++
+ drivers/net/wireguard/socket.c               | 437 ++++++++++
+ drivers/net/wireguard/socket.h               |  44 +
+ drivers/net/wireguard/timers.c               | 243 ++++++
+ drivers/net/wireguard/timers.h               |  31 +
+ drivers/net/wireguard/version.h              |   1 +
+ include/uapi/linux/wireguard.h               | 196 +++++
+ tools/testing/selftests/wireguard/netns.sh   | 537 ++++++++++++
+ 36 files changed, 7753 insertions(+)
+ create mode 100644 drivers/net/wireguard/Makefile
+ create mode 100644 drivers/net/wireguard/allowedips.c
+ create mode 100644 drivers/net/wireguard/allowedips.h
+ create mode 100644 drivers/net/wireguard/cookie.c
+ create mode 100644 drivers/net/wireguard/cookie.h
+ create mode 100644 drivers/net/wireguard/device.c
+ create mode 100644 drivers/net/wireguard/device.h
+ create mode 100644 drivers/net/wireguard/main.c
+ create mode 100644 drivers/net/wireguard/messages.h
+ create mode 100644 drivers/net/wireguard/netlink.c
+ create mode 100644 drivers/net/wireguard/netlink.h
+ create mode 100644 drivers/net/wireguard/noise.c
+ create mode 100644 drivers/net/wireguard/noise.h
+ create mode 100644 drivers/net/wireguard/peer.c
+ create mode 100644 drivers/net/wireguard/peer.h
+ create mode 100644 drivers/net/wireguard/peerlookup.c
+ create mode 100644 drivers/net/wireguard/peerlookup.h
+ create mode 100644 drivers/net/wireguard/queueing.c
+ create mode 100644 drivers/net/wireguard/queueing.h
+ create mode 100644 drivers/net/wireguard/ratelimiter.c
+ create mode 100644 drivers/net/wireguard/ratelimiter.h
+ create mode 100644 drivers/net/wireguard/receive.c
+ create mode 100644 drivers/net/wireguard/selftest/allowedips.c
+ create mode 100644 drivers/net/wireguard/selftest/counter.c
+ create mode 100644 drivers/net/wireguard/selftest/ratelimiter.c
+ create mode 100644 drivers/net/wireguard/send.c
+ create mode 100644 drivers/net/wireguard/socket.c
+ create mode 100644 drivers/net/wireguard/socket.h
+ create mode 100644 drivers/net/wireguard/timers.c
+ create mode 100644 drivers/net/wireguard/timers.h
+ create mode 100644 drivers/net/wireguard/version.h
+ create mode 100644 include/uapi/linux/wireguard.h
+ create mode 100755 tools/testing/selftests/wireguard/netns.sh
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -17584,6 +17584,14 @@ L:	linux-gpio@vger.kernel.org
+ S:	Maintained
+ F:	drivers/gpio/gpio-ws16c48.c
+ 
++WIREGUARD SECURE NETWORK TUNNEL
++M:	Jason A. Donenfeld <Jason@zx2c4.com>
++S:	Maintained
++F:	drivers/net/wireguard/
++F:	tools/testing/selftests/wireguard/
++L:	wireguard@lists.zx2c4.com
++L:	netdev@vger.kernel.org
++
+ WISTRON LAPTOP BUTTON DRIVER
+ M:	Miloslav Trmac <mitr@volny.cz>
+ S:	Maintained
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -71,6 +71,47 @@ config DUMMY
+ 	  To compile this driver as a module, choose M here: the module
+ 	  will be called dummy.
+ 
++config WIREGUARD
++	tristate "WireGuard secure network tunnel"
++	depends on NET && INET
++	depends on IPV6 || !IPV6
++	select NET_UDP_TUNNEL
++	select DST_CACHE
++	select CRYPTO
++	select CRYPTO_LIB_CURVE25519
++	select CRYPTO_LIB_CHACHA20POLY1305
++	select CRYPTO_LIB_BLAKE2S
++	select CRYPTO_CHACHA20_X86_64 if X86 && 64BIT
++	select CRYPTO_POLY1305_X86_64 if X86 && 64BIT
++	select CRYPTO_BLAKE2S_X86 if X86 && 64BIT
++	select CRYPTO_CURVE25519_X86 if X86 && 64BIT
++	select CRYPTO_CHACHA20_NEON if (ARM || ARM64) && KERNEL_MODE_NEON
++	select CRYPTO_POLY1305_NEON if ARM64 && KERNEL_MODE_NEON
++	select CRYPTO_POLY1305_ARM if ARM
++	select CRYPTO_CURVE25519_NEON if ARM && KERNEL_MODE_NEON
++	select CRYPTO_CHACHA_MIPS if CPU_MIPS32_R2
++	select CRYPTO_POLY1305_MIPS if CPU_MIPS32 || (CPU_MIPS64 && 64BIT)
++	help
++	  WireGuard is a secure, fast, and easy to use replacement for IPSec
++	  that uses modern cryptography and clever networking tricks. It's
++	  designed to be fairly general purpose and abstract enough to fit most
++	  use cases, while at the same time remaining extremely simple to
++	  configure. See www.wireguard.com for more info.
++
++	  It's safe to say Y or M here, as the driver is very lightweight and
++	  is only in use when an administrator chooses to add an interface.
++
++config WIREGUARD_DEBUG
++	bool "Debugging checks and verbose messages"
++	depends on WIREGUARD
++	help
++	  This will write log messages for handshake and other events
++	  that occur for a WireGuard interface. It will also perform some
++	  extra validation checks and unit tests at various points. This is
++	  only useful for debugging.
++
++	  Say N here unless you know what you're doing.
++
+ config EQUALIZER
+ 	tristate "EQL (serial line load balancing) support"
+ 	---help---
+--- a/drivers/net/Makefile
++++ b/drivers/net/Makefile
+@@ -10,6 +10,7 @@ obj-$(CONFIG_BONDING) += bonding/
+ obj-$(CONFIG_IPVLAN) += ipvlan/
+ obj-$(CONFIG_IPVTAP) += ipvlan/
+ obj-$(CONFIG_DUMMY) += dummy.o
++obj-$(CONFIG_WIREGUARD) += wireguard/
+ obj-$(CONFIG_EQUALIZER) += eql.o
+ obj-$(CONFIG_IFB) += ifb.o
+ obj-$(CONFIG_MACSEC) += macsec.o
+--- /dev/null
++++ b/drivers/net/wireguard/Makefile
+@@ -0,0 +1,18 @@
++ccflags-y := -O3
++ccflags-y += -D'pr_fmt(fmt)=KBUILD_MODNAME ": " fmt'
++ccflags-$(CONFIG_WIREGUARD_DEBUG) += -DDEBUG
++wireguard-y := main.o
++wireguard-y += noise.o
++wireguard-y += device.o
++wireguard-y += peer.o
++wireguard-y += timers.o
++wireguard-y += queueing.o
++wireguard-y += send.o
++wireguard-y += receive.o
++wireguard-y += socket.o
++wireguard-y += peerlookup.o
++wireguard-y += allowedips.o
++wireguard-y += ratelimiter.o
++wireguard-y += cookie.o
++wireguard-y += netlink.o
++obj-$(CONFIG_WIREGUARD) := wireguard.o
+--- /dev/null
++++ b/drivers/net/wireguard/allowedips.c
+@@ -0,0 +1,381 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#include "allowedips.h"
++#include "peer.h"
++
++static void swap_endian(u8 *dst, const u8 *src, u8 bits)
++{
++	if (bits == 32) {
++		*(u32 *)dst = be32_to_cpu(*(const __be32 *)src);
++	} else if (bits == 128) {
++		((u64 *)dst)[0] = be64_to_cpu(((const __be64 *)src)[0]);
++		((u64 *)dst)[1] = be64_to_cpu(((const __be64 *)src)[1]);
++	}
++}
++
++static void copy_and_assign_cidr(struct allowedips_node *node, const u8 *src,
++				 u8 cidr, u8 bits)
++{
++	node->cidr = cidr;
++	node->bit_at_a = cidr / 8U;
++#ifdef __LITTLE_ENDIAN
++	node->bit_at_a ^= (bits / 8U - 1U) % 8U;
++#endif
++	node->bit_at_b = 7U - (cidr % 8U);
++	node->bitlen = bits;
++	memcpy(node->bits, src, bits / 8U);
++}
++#define CHOOSE_NODE(parent, key) \
++	parent->bit[(key[parent->bit_at_a] >> parent->bit_at_b) & 1]
++
++static void node_free_rcu(struct rcu_head *rcu)
++{
++	kfree(container_of(rcu, struct allowedips_node, rcu));
++}
++
++static void push_rcu(struct allowedips_node **stack,
++		     struct allowedips_node __rcu *p, unsigned int *len)
++{
++	if (rcu_access_pointer(p)) {
++		WARN_ON(IS_ENABLED(DEBUG) && *len >= 128);
++		stack[(*len)++] = rcu_dereference_raw(p);
++	}
++}
++
++static void root_free_rcu(struct rcu_head *rcu)
++{
++	struct allowedips_node *node, *stack[128] = {
++		container_of(rcu, struct allowedips_node, rcu) };
++	unsigned int len = 1;
++
++	while (len > 0 && (node = stack[--len])) {
++		push_rcu(stack, node->bit[0], &len);
++		push_rcu(stack, node->bit[1], &len);
++		kfree(node);
++	}
++}
++
++static void root_remove_peer_lists(struct allowedips_node *root)
++{
++	struct allowedips_node *node, *stack[128] = { root };
++	unsigned int len = 1;
++
++	while (len > 0 && (node = stack[--len])) {
++		push_rcu(stack, node->bit[0], &len);
++		push_rcu(stack, node->bit[1], &len);
++		if (rcu_access_pointer(node->peer))
++			list_del(&node->peer_list);
++	}
++}
++
++static void walk_remove_by_peer(struct allowedips_node __rcu **top,
++				struct wg_peer *peer, struct mutex *lock)
++{
++#define REF(p) rcu_access_pointer(p)
++#define DEREF(p) rcu_dereference_protected(*(p), lockdep_is_held(lock))
++#define PUSH(p) ({                                                             \
++		WARN_ON(IS_ENABLED(DEBUG) && len >= 128);                      \
++		stack[len++] = p;                                              \
++	})
++
++	struct allowedips_node __rcu **stack[128], **nptr;
++	struct allowedips_node *node, *prev;
++	unsigned int len;
++
++	if (unlikely(!peer || !REF(*top)))
++		return;
++
++	for (prev = NULL, len = 0, PUSH(top); len > 0; prev = node) {
++		nptr = stack[len - 1];
++		node = DEREF(nptr);
++		if (!node) {
++			--len;
++			continue;
++		}
++		if (!prev || REF(prev->bit[0]) == node ||
++		    REF(prev->bit[1]) == node) {
++			if (REF(node->bit[0]))
++				PUSH(&node->bit[0]);
++			else if (REF(node->bit[1]))
++				PUSH(&node->bit[1]);
++		} else if (REF(node->bit[0]) == prev) {
++			if (REF(node->bit[1]))
++				PUSH(&node->bit[1]);
++		} else {
++			if (rcu_dereference_protected(node->peer,
++				lockdep_is_held(lock)) == peer) {
++				RCU_INIT_POINTER(node->peer, NULL);
++				list_del_init(&node->peer_list);
++				if (!node->bit[0] || !node->bit[1]) {
++					rcu_assign_pointer(*nptr, DEREF(
++					       &node->bit[!REF(node->bit[0])]));
++					call_rcu(&node->rcu, node_free_rcu);
++					node = DEREF(nptr);
++				}
++			}
++			--len;
++		}
++	}
++
++#undef REF
++#undef DEREF
++#undef PUSH
++}
++
++static unsigned int fls128(u64 a, u64 b)
++{
++	return a ? fls64(a) + 64U : fls64(b);
++}
++
++static u8 common_bits(const struct allowedips_node *node, const u8 *key,
++		      u8 bits)
++{
++	if (bits == 32)
++		return 32U - fls(*(const u32 *)node->bits ^ *(const u32 *)key);
++	else if (bits == 128)
++		return 128U - fls128(
++			*(const u64 *)&node->bits[0] ^ *(const u64 *)&key[0],
++			*(const u64 *)&node->bits[8] ^ *(const u64 *)&key[8]);
++	return 0;
++}
++
++static bool prefix_matches(const struct allowedips_node *node, const u8 *key,
++			   u8 bits)
++{
++	/* This could be much faster if it actually just compared the common
++	 * bits properly, by precomputing a mask bswap(~0 << (32 - cidr)), and
++	 * the rest, but it turns out that common_bits is already super fast on
++	 * modern processors, even taking into account the unfortunate bswap.
++	 * So, we just inline it like this instead.
++	 */
++	return common_bits(node, key, bits) >= node->cidr;
++}
++
++static struct allowedips_node *find_node(struct allowedips_node *trie, u8 bits,
++					 const u8 *key)
++{
++	struct allowedips_node *node = trie, *found = NULL;
++
++	while (node && prefix_matches(node, key, bits)) {
++		if (rcu_access_pointer(node->peer))
++			found = node;
++		if (node->cidr == bits)
++			break;
++		node = rcu_dereference_bh(CHOOSE_NODE(node, key));
++	}
++	return found;
++}
++
++/* Returns a strong reference to a peer */
++static struct wg_peer *lookup(struct allowedips_node __rcu *root, u8 bits,
++			      const void *be_ip)
++{
++	/* Aligned so it can be passed to fls/fls64 */
++	u8 ip[16] __aligned(__alignof(u64));
++	struct allowedips_node *node;
++	struct wg_peer *peer = NULL;
++
++	swap_endian(ip, be_ip, bits);
++
++	rcu_read_lock_bh();
++retry:
++	node = find_node(rcu_dereference_bh(root), bits, ip);
++	if (node) {
++		peer = wg_peer_get_maybe_zero(rcu_dereference_bh(node->peer));
++		if (!peer)
++			goto retry;
++	}
++	rcu_read_unlock_bh();
++	return peer;
++}
++
++static bool node_placement(struct allowedips_node __rcu *trie, const u8 *key,
++			   u8 cidr, u8 bits, struct allowedips_node **rnode,
++			   struct mutex *lock)
++{
++	struct allowedips_node *node = rcu_dereference_protected(trie,
++						lockdep_is_held(lock));
++	struct allowedips_node *parent = NULL;
++	bool exact = false;
++
++	while (node && node->cidr <= cidr && prefix_matches(node, key, bits)) {
++		parent = node;
++		if (parent->cidr == cidr) {
++			exact = true;
++			break;
++		}
++		node = rcu_dereference_protected(CHOOSE_NODE(parent, key),
++						 lockdep_is_held(lock));
++	}
++	*rnode = parent;
++	return exact;
++}
++
++static int add(struct allowedips_node __rcu **trie, u8 bits, const u8 *key,
++	       u8 cidr, struct wg_peer *peer, struct mutex *lock)
++{
++	struct allowedips_node *node, *parent, *down, *newnode;
++
++	if (unlikely(cidr > bits || !peer))
++		return -EINVAL;
++
++	if (!rcu_access_pointer(*trie)) {
++		node = kzalloc(sizeof(*node), GFP_KERNEL);
++		if (unlikely(!node))
++			return -ENOMEM;
++		RCU_INIT_POINTER(node->peer, peer);
++		list_add_tail(&node->peer_list, &peer->allowedips_list);
++		copy_and_assign_cidr(node, key, cidr, bits);
++		rcu_assign_pointer(*trie, node);
++		return 0;
++	}
++	if (node_placement(*trie, key, cidr, bits, &node, lock)) {
++		rcu_assign_pointer(node->peer, peer);
++		list_move_tail(&node->peer_list, &peer->allowedips_list);
++		return 0;
++	}
++
++	newnode = kzalloc(sizeof(*newnode), GFP_KERNEL);
++	if (unlikely(!newnode))
++		return -ENOMEM;
++	RCU_INIT_POINTER(newnode->peer, peer);
++	list_add_tail(&newnode->peer_list, &peer->allowedips_list);
++	copy_and_assign_cidr(newnode, key, cidr, bits);
++
++	if (!node) {
++		down = rcu_dereference_protected(*trie, lockdep_is_held(lock));
++	} else {
++		down = rcu_dereference_protected(CHOOSE_NODE(node, key),
++						 lockdep_is_held(lock));
++		if (!down) {
++			rcu_assign_pointer(CHOOSE_NODE(node, key), newnode);
++			return 0;
++		}
++	}
++	cidr = min(cidr, common_bits(down, key, bits));
++	parent = node;
++
++	if (newnode->cidr == cidr) {
++		rcu_assign_pointer(CHOOSE_NODE(newnode, down->bits), down);
++		if (!parent)
++			rcu_assign_pointer(*trie, newnode);
++		else
++			rcu_assign_pointer(CHOOSE_NODE(parent, newnode->bits),
++					   newnode);
++	} else {
++		node = kzalloc(sizeof(*node), GFP_KERNEL);
++		if (unlikely(!node)) {
++			kfree(newnode);
++			return -ENOMEM;
++		}
++		INIT_LIST_HEAD(&node->peer_list);
++		copy_and_assign_cidr(node, newnode->bits, cidr, bits);
++
++		rcu_assign_pointer(CHOOSE_NODE(node, down->bits), down);
++		rcu_assign_pointer(CHOOSE_NODE(node, newnode->bits), newnode);
++		if (!parent)
++			rcu_assign_pointer(*trie, node);
++		else
++			rcu_assign_pointer(CHOOSE_NODE(parent, node->bits),
++					   node);
++	}
++	return 0;
++}
++
++void wg_allowedips_init(struct allowedips *table)
++{
++	table->root4 = table->root6 = NULL;
++	table->seq = 1;
++}
++
++void wg_allowedips_free(struct allowedips *table, struct mutex *lock)
++{
++	struct allowedips_node __rcu *old4 = table->root4, *old6 = table->root6;
++
++	++table->seq;
++	RCU_INIT_POINTER(table->root4, NULL);
++	RCU_INIT_POINTER(table->root6, NULL);
++	if (rcu_access_pointer(old4)) {
++		struct allowedips_node *node = rcu_dereference_protected(old4,
++							lockdep_is_held(lock));
++
++		root_remove_peer_lists(node);
++		call_rcu(&node->rcu, root_free_rcu);
++	}
++	if (rcu_access_pointer(old6)) {
++		struct allowedips_node *node = rcu_dereference_protected(old6,
++							lockdep_is_held(lock));
++
++		root_remove_peer_lists(node);
++		call_rcu(&node->rcu, root_free_rcu);
++	}
++}
++
++int wg_allowedips_insert_v4(struct allowedips *table, const struct in_addr *ip,
++			    u8 cidr, struct wg_peer *peer, struct mutex *lock)
++{
++	/* Aligned so it can be passed to fls */
++	u8 key[4] __aligned(__alignof(u32));
++
++	++table->seq;
++	swap_endian(key, (const u8 *)ip, 32);
++	return add(&table->root4, 32, key, cidr, peer, lock);
++}
++
++int wg_allowedips_insert_v6(struct allowedips *table, const struct in6_addr *ip,
++			    u8 cidr, struct wg_peer *peer, struct mutex *lock)
++{
++	/* Aligned so it can be passed to fls64 */
++	u8 key[16] __aligned(__alignof(u64));
++
++	++table->seq;
++	swap_endian(key, (const u8 *)ip, 128);
++	return add(&table->root6, 128, key, cidr, peer, lock);
++}
++
++void wg_allowedips_remove_by_peer(struct allowedips *table,
++				  struct wg_peer *peer, struct mutex *lock)
++{
++	++table->seq;
++	walk_remove_by_peer(&table->root4, peer, lock);
++	walk_remove_by_peer(&table->root6, peer, lock);
++}
++
++int wg_allowedips_read_node(struct allowedips_node *node, u8 ip[16], u8 *cidr)
++{
++	const unsigned int cidr_bytes = DIV_ROUND_UP(node->cidr, 8U);
++	swap_endian(ip, node->bits, node->bitlen);
++	memset(ip + cidr_bytes, 0, node->bitlen / 8U - cidr_bytes);
++	if (node->cidr)
++		ip[cidr_bytes - 1U] &= ~0U << (-node->cidr % 8U);
++
++	*cidr = node->cidr;
++	return node->bitlen == 32 ? AF_INET : AF_INET6;
++}
++
++/* Returns a strong reference to a peer */
++struct wg_peer *wg_allowedips_lookup_dst(struct allowedips *table,
++					 struct sk_buff *skb)
++{
++	if (skb->protocol == htons(ETH_P_IP))
++		return lookup(table->root4, 32, &ip_hdr(skb)->daddr);
++	else if (skb->protocol == htons(ETH_P_IPV6))
++		return lookup(table->root6, 128, &ipv6_hdr(skb)->daddr);
++	return NULL;
++}
++
++/* Returns a strong reference to a peer */
++struct wg_peer *wg_allowedips_lookup_src(struct allowedips *table,
++					 struct sk_buff *skb)
++{
++	if (skb->protocol == htons(ETH_P_IP))
++		return lookup(table->root4, 32, &ip_hdr(skb)->saddr);
++	else if (skb->protocol == htons(ETH_P_IPV6))
++		return lookup(table->root6, 128, &ipv6_hdr(skb)->saddr);
++	return NULL;
++}
++
++#include "selftest/allowedips.c"
+--- /dev/null
++++ b/drivers/net/wireguard/allowedips.h
+@@ -0,0 +1,59 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#ifndef _WG_ALLOWEDIPS_H
++#define _WG_ALLOWEDIPS_H
++
++#include <linux/mutex.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++
++struct wg_peer;
++
++struct allowedips_node {
++	struct wg_peer __rcu *peer;
++	struct allowedips_node __rcu *bit[2];
++	/* While it may seem scandalous that we waste space for v4,
++	 * we're alloc'ing to the nearest power of 2 anyway, so this
++	 * doesn't actually make a difference.
++	 */
++	u8 bits[16] __aligned(__alignof(u64));
++	u8 cidr, bit_at_a, bit_at_b, bitlen;
++
++	/* Keep rarely used list at bottom to be beyond cache line. */
++	union {
++		struct list_head peer_list;
++		struct rcu_head rcu;
++	};
++};
++
++struct allowedips {
++	struct allowedips_node __rcu *root4;
++	struct allowedips_node __rcu *root6;
++	u64 seq;
++};
++
++void wg_allowedips_init(struct allowedips *table);
++void wg_allowedips_free(struct allowedips *table, struct mutex *mutex);
++int wg_allowedips_insert_v4(struct allowedips *table, const struct in_addr *ip,
++			    u8 cidr, struct wg_peer *peer, struct mutex *lock);
++int wg_allowedips_insert_v6(struct allowedips *table, const struct in6_addr *ip,
++			    u8 cidr, struct wg_peer *peer, struct mutex *lock);
++void wg_allowedips_remove_by_peer(struct allowedips *table,
++				  struct wg_peer *peer, struct mutex *lock);
++/* The ip input pointer should be __aligned(__alignof(u64))) */
++int wg_allowedips_read_node(struct allowedips_node *node, u8 ip[16], u8 *cidr);
++
++/* These return a strong reference to a peer: */
++struct wg_peer *wg_allowedips_lookup_dst(struct allowedips *table,
++					 struct sk_buff *skb);
++struct wg_peer *wg_allowedips_lookup_src(struct allowedips *table,
++					 struct sk_buff *skb);
++
++#ifdef DEBUG
++bool wg_allowedips_selftest(void);
++#endif
++
++#endif /* _WG_ALLOWEDIPS_H */
+--- /dev/null
++++ b/drivers/net/wireguard/cookie.c
+@@ -0,0 +1,236 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#include "cookie.h"
++#include "peer.h"
++#include "device.h"
++#include "messages.h"
++#include "ratelimiter.h"
++#include "timers.h"
++
++#include <crypto/blake2s.h>
++#include <crypto/chacha20poly1305.h>
++
++#include <net/ipv6.h>
++#include <crypto/algapi.h>
++
++void wg_cookie_checker_init(struct cookie_checker *checker,
++			    struct wg_device *wg)
++{
++	init_rwsem(&checker->secret_lock);
++	checker->secret_birthdate = ktime_get_coarse_boottime_ns();
++	get_random_bytes(checker->secret, NOISE_HASH_LEN);
++	checker->device = wg;
++}
++
++enum { COOKIE_KEY_LABEL_LEN = 8 };
++static const u8 mac1_key_label[COOKIE_KEY_LABEL_LEN] = "mac1----";
++static const u8 cookie_key_label[COOKIE_KEY_LABEL_LEN] = "cookie--";
++
++static void precompute_key(u8 key[NOISE_SYMMETRIC_KEY_LEN],
++			   const u8 pubkey[NOISE_PUBLIC_KEY_LEN],
++			   const u8 label[COOKIE_KEY_LABEL_LEN])
++{
++	struct blake2s_state blake;
++
++	blake2s_init(&blake, NOISE_SYMMETRIC_KEY_LEN);
++	blake2s_update(&blake, label, COOKIE_KEY_LABEL_LEN);
++	blake2s_update(&blake, pubkey, NOISE_PUBLIC_KEY_LEN);
++	blake2s_final(&blake, key);
++}
++
++/* Must hold peer->handshake.static_identity->lock */
++void wg_cookie_checker_precompute_device_keys(struct cookie_checker *checker)
++{
++	if (likely(checker->device->static_identity.has_identity)) {
++		precompute_key(checker->cookie_encryption_key,
++			       checker->device->static_identity.static_public,
++			       cookie_key_label);
++		precompute_key(checker->message_mac1_key,
++			       checker->device->static_identity.static_public,
++			       mac1_key_label);
++	} else {
++		memset(checker->cookie_encryption_key, 0,
++		       NOISE_SYMMETRIC_KEY_LEN);
++		memset(checker->message_mac1_key, 0, NOISE_SYMMETRIC_KEY_LEN);
++	}
++}
++
++void wg_cookie_checker_precompute_peer_keys(struct wg_peer *peer)
++{
++	precompute_key(peer->latest_cookie.cookie_decryption_key,
++		       peer->handshake.remote_static, cookie_key_label);
++	precompute_key(peer->latest_cookie.message_mac1_key,
++		       peer->handshake.remote_static, mac1_key_label);
++}
++
++void wg_cookie_init(struct cookie *cookie)
++{
++	memset(cookie, 0, sizeof(*cookie));
++	init_rwsem(&cookie->lock);
++}
++
++static void compute_mac1(u8 mac1[COOKIE_LEN], const void *message, size_t len,
++			 const u8 key[NOISE_SYMMETRIC_KEY_LEN])
++{
++	len = len - sizeof(struct message_macs) +
++	      offsetof(struct message_macs, mac1);
++	blake2s(mac1, message, key, COOKIE_LEN, len, NOISE_SYMMETRIC_KEY_LEN);
++}
++
++static void compute_mac2(u8 mac2[COOKIE_LEN], const void *message, size_t len,
++			 const u8 cookie[COOKIE_LEN])
++{
++	len = len - sizeof(struct message_macs) +
++	      offsetof(struct message_macs, mac2);
++	blake2s(mac2, message, cookie, COOKIE_LEN, len, COOKIE_LEN);
++}
++
++static void make_cookie(u8 cookie[COOKIE_LEN], struct sk_buff *skb,
++			struct cookie_checker *checker)
++{
++	struct blake2s_state state;
++
++	if (wg_birthdate_has_expired(checker->secret_birthdate,
++				     COOKIE_SECRET_MAX_AGE)) {
++		down_write(&checker->secret_lock);
++		checker->secret_birthdate = ktime_get_coarse_boottime_ns();
++		get_random_bytes(checker->secret, NOISE_HASH_LEN);
++		up_write(&checker->secret_lock);
++	}
++
++	down_read(&checker->secret_lock);
++
++	blake2s_init_key(&state, COOKIE_LEN, checker->secret, NOISE_HASH_LEN);
++	if (skb->protocol == htons(ETH_P_IP))
++		blake2s_update(&state, (u8 *)&ip_hdr(skb)->saddr,
++			       sizeof(struct in_addr));
++	else if (skb->protocol == htons(ETH_P_IPV6))
++		blake2s_update(&state, (u8 *)&ipv6_hdr(skb)->saddr,
++			       sizeof(struct in6_addr));
++	blake2s_update(&state, (u8 *)&udp_hdr(skb)->source, sizeof(__be16));
++	blake2s_final(&state, cookie);
++
++	up_read(&checker->secret_lock);
++}
++
++enum cookie_mac_state wg_cookie_validate_packet(struct cookie_checker *checker,
++						struct sk_buff *skb,
++						bool check_cookie)
++{
++	struct message_macs *macs = (struct message_macs *)
++		(skb->data + skb->len - sizeof(*macs));
++	enum cookie_mac_state ret;
++	u8 computed_mac[COOKIE_LEN];
++	u8 cookie[COOKIE_LEN];
++
++	ret = INVALID_MAC;
++	compute_mac1(computed_mac, skb->data, skb->len,
++		     checker->message_mac1_key);
++	if (crypto_memneq(computed_mac, macs->mac1, COOKIE_LEN))
++		goto out;
++
++	ret = VALID_MAC_BUT_NO_COOKIE;
++
++	if (!check_cookie)
++		goto out;
++
++	make_cookie(cookie, skb, checker);
++
++	compute_mac2(computed_mac, skb->data, skb->len, cookie);
++	if (crypto_memneq(computed_mac, macs->mac2, COOKIE_LEN))
++		goto out;
++
++	ret = VALID_MAC_WITH_COOKIE_BUT_RATELIMITED;
++	if (!wg_ratelimiter_allow(skb, dev_net(checker->device->dev)))
++		goto out;
++
++	ret = VALID_MAC_WITH_COOKIE;
++
++out:
++	return ret;
++}
++
++void wg_cookie_add_mac_to_packet(void *message, size_t len,
++				 struct wg_peer *peer)
++{
++	struct message_macs *macs = (struct message_macs *)
++		((u8 *)message + len - sizeof(*macs));
++
++	down_write(&peer->latest_cookie.lock);
++	compute_mac1(macs->mac1, message, len,
++		     peer->latest_cookie.message_mac1_key);
++	memcpy(peer->latest_cookie.last_mac1_sent, macs->mac1, COOKIE_LEN);
++	peer->latest_cookie.have_sent_mac1 = true;
++	up_write(&peer->latest_cookie.lock);
++
++	down_read(&peer->latest_cookie.lock);
++	if (peer->latest_cookie.is_valid &&
++	    !wg_birthdate_has_expired(peer->latest_cookie.birthdate,
++				COOKIE_SECRET_MAX_AGE - COOKIE_SECRET_LATENCY))
++		compute_mac2(macs->mac2, message, len,
++			     peer->latest_cookie.cookie);
++	else
++		memset(macs->mac2, 0, COOKIE_LEN);
++	up_read(&peer->latest_cookie.lock);
++}
++
++void wg_cookie_message_create(struct message_handshake_cookie *dst,
++			      struct sk_buff *skb, __le32 index,
++			      struct cookie_checker *checker)
++{
++	struct message_macs *macs = (struct message_macs *)
++		((u8 *)skb->data + skb->len - sizeof(*macs));
++	u8 cookie[COOKIE_LEN];
++
++	dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE);
++	dst->receiver_index = index;
++	get_random_bytes_wait(dst->nonce, COOKIE_NONCE_LEN);
++
++	make_cookie(cookie, skb, checker);
++	xchacha20poly1305_encrypt(dst->encrypted_cookie, cookie, COOKIE_LEN,
++				  macs->mac1, COOKIE_LEN, dst->nonce,
++				  checker->cookie_encryption_key);
++}
++
++void wg_cookie_message_consume(struct message_handshake_cookie *src,
++			       struct wg_device *wg)
++{
++	struct wg_peer *peer = NULL;
++	u8 cookie[COOKIE_LEN];
++	bool ret;
++
++	if (unlikely(!wg_index_hashtable_lookup(wg->index_hashtable,
++						INDEX_HASHTABLE_HANDSHAKE |
++						INDEX_HASHTABLE_KEYPAIR,
++						src->receiver_index, &peer)))
++		return;
++
++	down_read(&peer->latest_cookie.lock);
++	if (unlikely(!peer->latest_cookie.have_sent_mac1)) {
++		up_read(&peer->latest_cookie.lock);
++		goto out;
++	}
++	ret = xchacha20poly1305_decrypt(
++		cookie, src->encrypted_cookie, sizeof(src->encrypted_cookie),
++		peer->latest_cookie.last_mac1_sent, COOKIE_LEN, src->nonce,
++		peer->latest_cookie.cookie_decryption_key);
++	up_read(&peer->latest_cookie.lock);
++
++	if (ret) {
++		down_write(&peer->latest_cookie.lock);
++		memcpy(peer->latest_cookie.cookie, cookie, COOKIE_LEN);
++		peer->latest_cookie.birthdate = ktime_get_coarse_boottime_ns();
++		peer->latest_cookie.is_valid = true;
++		peer->latest_cookie.have_sent_mac1 = false;
++		up_write(&peer->latest_cookie.lock);
++	} else {
++		net_dbg_ratelimited("%s: Could not decrypt invalid cookie response\n",
++				    wg->dev->name);
++	}
++
++out:
++	wg_peer_put(peer);
++}
+--- /dev/null
++++ b/drivers/net/wireguard/cookie.h
+@@ -0,0 +1,59 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#ifndef _WG_COOKIE_H
++#define _WG_COOKIE_H
++
++#include "messages.h"
++#include <linux/rwsem.h>
++
++struct wg_peer;
++
++struct cookie_checker {
++	u8 secret[NOISE_HASH_LEN];
++	u8 cookie_encryption_key[NOISE_SYMMETRIC_KEY_LEN];
++	u8 message_mac1_key[NOISE_SYMMETRIC_KEY_LEN];
++	u64 secret_birthdate;
++	struct rw_semaphore secret_lock;
++	struct wg_device *device;
++};
++
++struct cookie {
++	u64 birthdate;
++	bool is_valid;
++	u8 cookie[COOKIE_LEN];
++	bool have_sent_mac1;
++	u8 last_mac1_sent[COOKIE_LEN];
++	u8 cookie_decryption_key[NOISE_SYMMETRIC_KEY_LEN];
++	u8 message_mac1_key[NOISE_SYMMETRIC_KEY_LEN];
++	struct rw_semaphore lock;
++};
++
++enum cookie_mac_state {
++	INVALID_MAC,
++	VALID_MAC_BUT_NO_COOKIE,
++	VALID_MAC_WITH_COOKIE_BUT_RATELIMITED,
++	VALID_MAC_WITH_COOKIE
++};
++
++void wg_cookie_checker_init(struct cookie_checker *checker,
++			    struct wg_device *wg);
++void wg_cookie_checker_precompute_device_keys(struct cookie_checker *checker);
++void wg_cookie_checker_precompute_peer_keys(struct wg_peer *peer);
++void wg_cookie_init(struct cookie *cookie);
++
++enum cookie_mac_state wg_cookie_validate_packet(struct cookie_checker *checker,
++						struct sk_buff *skb,
++						bool check_cookie);
++void wg_cookie_add_mac_to_packet(void *message, size_t len,
++				 struct wg_peer *peer);
++
++void wg_cookie_message_create(struct message_handshake_cookie *src,
++			      struct sk_buff *skb, __le32 index,
++			      struct cookie_checker *checker);
++void wg_cookie_message_consume(struct message_handshake_cookie *src,
++			       struct wg_device *wg);
++
++#endif /* _WG_COOKIE_H */
+--- /dev/null
++++ b/drivers/net/wireguard/device.c
+@@ -0,0 +1,458 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#include "queueing.h"
++#include "socket.h"
++#include "timers.h"
++#include "device.h"
++#include "ratelimiter.h"
++#include "peer.h"
++#include "messages.h"
++
++#include <linux/module.h>
++#include <linux/rtnetlink.h>
++#include <linux/inet.h>
++#include <linux/netdevice.h>
++#include <linux/inetdevice.h>
++#include <linux/if_arp.h>
++#include <linux/icmp.h>
++#include <linux/suspend.h>
++#include <net/icmp.h>
++#include <net/rtnetlink.h>
++#include <net/ip_tunnels.h>
++#include <net/addrconf.h>
++
++static LIST_HEAD(device_list);
++
++static int wg_open(struct net_device *dev)
++{
++	struct in_device *dev_v4 = __in_dev_get_rtnl(dev);
++	struct inet6_dev *dev_v6 = __in6_dev_get(dev);
++	struct wg_device *wg = netdev_priv(dev);
++	struct wg_peer *peer;
++	int ret;
++
++	if (dev_v4) {
++		/* At some point we might put this check near the ip_rt_send_
++		 * redirect call of ip_forward in net/ipv4/ip_forward.c, similar
++		 * to the current secpath check.
++		 */
++		IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false);
++		IPV4_DEVCONF_ALL(dev_net(dev), SEND_REDIRECTS) = false;
++	}
++	if (dev_v6)
++		dev_v6->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_NONE;
++
++	ret = wg_socket_init(wg, wg->incoming_port);
++	if (ret < 0)
++		return ret;
++	mutex_lock(&wg->device_update_lock);
++	list_for_each_entry(peer, &wg->peer_list, peer_list) {
++		wg_packet_send_staged_packets(peer);
++		if (peer->persistent_keepalive_interval)
++			wg_packet_send_keepalive(peer);
++	}
++	mutex_unlock(&wg->device_update_lock);
++	return 0;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int wg_pm_notification(struct notifier_block *nb, unsigned long action,
++			      void *data)
++{
++	struct wg_device *wg;
++	struct wg_peer *peer;
++
++	/* If the machine is constantly suspending and resuming, as part of
++	 * its normal operation rather than as a somewhat rare event, then we
++	 * don't actually want to clear keys.
++	 */
++	if (IS_ENABLED(CONFIG_PM_AUTOSLEEP) || IS_ENABLED(CONFIG_ANDROID))
++		return 0;
++
++	if (action != PM_HIBERNATION_PREPARE && action != PM_SUSPEND_PREPARE)
++		return 0;
++
++	rtnl_lock();
++	list_for_each_entry(wg, &device_list, device_list) {
++		mutex_lock(&wg->device_update_lock);
++		list_for_each_entry(peer, &wg->peer_list, peer_list) {
++			del_timer(&peer->timer_zero_key_material);
++			wg_noise_handshake_clear(&peer->handshake);
++			wg_noise_keypairs_clear(&peer->keypairs);
++		}
++		mutex_unlock(&wg->device_update_lock);
++	}
++	rtnl_unlock();
++	rcu_barrier();
++	return 0;
++}
++
++static struct notifier_block pm_notifier = { .notifier_call = wg_pm_notification };
++#endif
++
++static int wg_stop(struct net_device *dev)
++{
++	struct wg_device *wg = netdev_priv(dev);
++	struct wg_peer *peer;
++
++	mutex_lock(&wg->device_update_lock);
++	list_for_each_entry(peer, &wg->peer_list, peer_list) {
++		wg_packet_purge_staged_packets(peer);
++		wg_timers_stop(peer);
++		wg_noise_handshake_clear(&peer->handshake);
++		wg_noise_keypairs_clear(&peer->keypairs);
++		wg_noise_reset_last_sent_handshake(&peer->last_sent_handshake);
++	}
++	mutex_unlock(&wg->device_update_lock);
++	skb_queue_purge(&wg->incoming_handshakes);
++	wg_socket_reinit(wg, NULL, NULL);
++	return 0;
++}
++
++static netdev_tx_t wg_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++	struct wg_device *wg = netdev_priv(dev);
++	struct sk_buff_head packets;
++	struct wg_peer *peer;
++	struct sk_buff *next;
++	sa_family_t family;
++	u32 mtu;
++	int ret;
++
++	if (unlikely(wg_skb_examine_untrusted_ip_hdr(skb) != skb->protocol)) {
++		ret = -EPROTONOSUPPORT;
++		net_dbg_ratelimited("%s: Invalid IP packet\n", dev->name);
++		goto err;
++	}
++
++	peer = wg_allowedips_lookup_dst(&wg->peer_allowedips, skb);
++	if (unlikely(!peer)) {
++		ret = -ENOKEY;
++		if (skb->protocol == htons(ETH_P_IP))
++			net_dbg_ratelimited("%s: No peer has allowed IPs matching %pI4\n",
++					    dev->name, &ip_hdr(skb)->daddr);
++		else if (skb->protocol == htons(ETH_P_IPV6))
++			net_dbg_ratelimited("%s: No peer has allowed IPs matching %pI6\n",
++					    dev->name, &ipv6_hdr(skb)->daddr);
++		goto err;
++	}
++
++	family = READ_ONCE(peer->endpoint.addr.sa_family);
++	if (unlikely(family != AF_INET && family != AF_INET6)) {
++		ret = -EDESTADDRREQ;
++		net_dbg_ratelimited("%s: No valid endpoint has been configured or discovered for peer %llu\n",
++				    dev->name, peer->internal_id);
++		goto err_peer;
++	}
++
++	mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
++
++	__skb_queue_head_init(&packets);
++	if (!skb_is_gso(skb)) {
++		skb_mark_not_on_list(skb);
++	} else {
++		struct sk_buff *segs = skb_gso_segment(skb, 0);
++
++		if (unlikely(IS_ERR(segs))) {
++			ret = PTR_ERR(segs);
++			goto err_peer;
++		}
++		dev_kfree_skb(skb);
++		skb = segs;
++	}
++
++	skb_list_walk_safe(skb, skb, next) {
++		skb_mark_not_on_list(skb);
++
++		skb = skb_share_check(skb, GFP_ATOMIC);
++		if (unlikely(!skb))
++			continue;
++
++		/* We only need to keep the original dst around for icmp,
++		 * so at this point we're in a position to drop it.
++		 */
++		skb_dst_drop(skb);
++
++		PACKET_CB(skb)->mtu = mtu;
++
++		__skb_queue_tail(&packets, skb);
++	}
++
++	spin_lock_bh(&peer->staged_packet_queue.lock);
++	/* If the queue is getting too big, we start removing the oldest packets
++	 * until it's small again. We do this before adding the new packet, so
++	 * we don't remove GSO segments that are in excess.
++	 */
++	while (skb_queue_len(&peer->staged_packet_queue) > MAX_STAGED_PACKETS) {
++		dev_kfree_skb(__skb_dequeue(&peer->staged_packet_queue));
++		++dev->stats.tx_dropped;
++	}
++	skb_queue_splice_tail(&packets, &peer->staged_packet_queue);
++	spin_unlock_bh(&peer->staged_packet_queue.lock);
++
++	wg_packet_send_staged_packets(peer);
++
++	wg_peer_put(peer);
++	return NETDEV_TX_OK;
++
++err_peer:
++	wg_peer_put(peer);
++err:
++	++dev->stats.tx_errors;
++	if (skb->protocol == htons(ETH_P_IP))
++		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
++	else if (skb->protocol == htons(ETH_P_IPV6))
++		icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
++	kfree_skb(skb);
++	return ret;
++}
++
++static const struct net_device_ops netdev_ops = {
++	.ndo_open		= wg_open,
++	.ndo_stop		= wg_stop,
++	.ndo_start_xmit		= wg_xmit,
++	.ndo_get_stats64	= ip_tunnel_get_stats64
++};
++
++static void wg_destruct(struct net_device *dev)
++{
++	struct wg_device *wg = netdev_priv(dev);
++
++	rtnl_lock();
++	list_del(&wg->device_list);
++	rtnl_unlock();
++	mutex_lock(&wg->device_update_lock);
++	wg->incoming_port = 0;
++	wg_socket_reinit(wg, NULL, NULL);
++	/* The final references are cleared in the below calls to destroy_workqueue. */
++	wg_peer_remove_all(wg);
++	destroy_workqueue(wg->handshake_receive_wq);
++	destroy_workqueue(wg->handshake_send_wq);
++	destroy_workqueue(wg->packet_crypt_wq);
++	wg_packet_queue_free(&wg->decrypt_queue, true);
++	wg_packet_queue_free(&wg->encrypt_queue, true);
++	rcu_barrier(); /* Wait for all the peers to be actually freed. */
++	wg_ratelimiter_uninit();
++	memzero_explicit(&wg->static_identity, sizeof(wg->static_identity));
++	skb_queue_purge(&wg->incoming_handshakes);
++	free_percpu(dev->tstats);
++	free_percpu(wg->incoming_handshakes_worker);
++	if (wg->have_creating_net_ref)
++		put_net(wg->creating_net);
++	kvfree(wg->index_hashtable);
++	kvfree(wg->peer_hashtable);
++	mutex_unlock(&wg->device_update_lock);
++
++	pr_debug("%s: Interface deleted\n", dev->name);
++	free_netdev(dev);
++}
++
++static const struct device_type device_type = { .name = KBUILD_MODNAME };
++
++static void wg_setup(struct net_device *dev)
++{
++	struct wg_device *wg = netdev_priv(dev);
++	enum { WG_NETDEV_FEATURES = NETIF_F_HW_CSUM | NETIF_F_RXCSUM |
++				    NETIF_F_SG | NETIF_F_GSO |
++				    NETIF_F_GSO_SOFTWARE | NETIF_F_HIGHDMA };
++
++	dev->netdev_ops = &netdev_ops;
++	dev->hard_header_len = 0;
++	dev->addr_len = 0;
++	dev->needed_headroom = DATA_PACKET_HEAD_ROOM;
++	dev->needed_tailroom = noise_encrypted_len(MESSAGE_PADDING_MULTIPLE);
++	dev->type = ARPHRD_NONE;
++	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
++	dev->priv_flags |= IFF_NO_QUEUE;
++	dev->features |= NETIF_F_LLTX;
++	dev->features |= WG_NETDEV_FEATURES;
++	dev->hw_features |= WG_NETDEV_FEATURES;
++	dev->hw_enc_features |= WG_NETDEV_FEATURES;
++	dev->mtu = ETH_DATA_LEN - MESSAGE_MINIMUM_LENGTH -
++		   sizeof(struct udphdr) -
++		   max(sizeof(struct ipv6hdr), sizeof(struct iphdr));
++
++	SET_NETDEV_DEVTYPE(dev, &device_type);
++
++	/* We need to keep the dst around in case of icmp replies. */
++	netif_keep_dst(dev);
++
++	memset(wg, 0, sizeof(*wg));
++	wg->dev = dev;
++}
++
++static int wg_newlink(struct net *src_net, struct net_device *dev,
++		      struct nlattr *tb[], struct nlattr *data[],
++		      struct netlink_ext_ack *extack)
++{
++	struct wg_device *wg = netdev_priv(dev);
++	int ret = -ENOMEM;
++
++	wg->creating_net = src_net;
++	init_rwsem(&wg->static_identity.lock);
++	mutex_init(&wg->socket_update_lock);
++	mutex_init(&wg->device_update_lock);
++	skb_queue_head_init(&wg->incoming_handshakes);
++	wg_allowedips_init(&wg->peer_allowedips);
++	wg_cookie_checker_init(&wg->cookie_checker, wg);
++	INIT_LIST_HEAD(&wg->peer_list);
++	wg->device_update_gen = 1;
++
++	wg->peer_hashtable = wg_pubkey_hashtable_alloc();
++	if (!wg->peer_hashtable)
++		return ret;
++
++	wg->index_hashtable = wg_index_hashtable_alloc();
++	if (!wg->index_hashtable)
++		goto err_free_peer_hashtable;
++
++	dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
++	if (!dev->tstats)
++		goto err_free_index_hashtable;
++
++	wg->incoming_handshakes_worker =
++		wg_packet_percpu_multicore_worker_alloc(
++				wg_packet_handshake_receive_worker, wg);
++	if (!wg->incoming_handshakes_worker)
++		goto err_free_tstats;
++
++	wg->handshake_receive_wq = alloc_workqueue("wg-kex-%s",
++			WQ_CPU_INTENSIVE | WQ_FREEZABLE, 0, dev->name);
++	if (!wg->handshake_receive_wq)
++		goto err_free_incoming_handshakes;
++
++	wg->handshake_send_wq = alloc_workqueue("wg-kex-%s",
++			WQ_UNBOUND | WQ_FREEZABLE, 0, dev->name);
++	if (!wg->handshake_send_wq)
++		goto err_destroy_handshake_receive;
++
++	wg->packet_crypt_wq = alloc_workqueue("wg-crypt-%s",
++			WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 0, dev->name);
++	if (!wg->packet_crypt_wq)
++		goto err_destroy_handshake_send;
++
++	ret = wg_packet_queue_init(&wg->encrypt_queue, wg_packet_encrypt_worker,
++				   true, MAX_QUEUED_PACKETS);
++	if (ret < 0)
++		goto err_destroy_packet_crypt;
++
++	ret = wg_packet_queue_init(&wg->decrypt_queue, wg_packet_decrypt_worker,
++				   true, MAX_QUEUED_PACKETS);
++	if (ret < 0)
++		goto err_free_encrypt_queue;
++
++	ret = wg_ratelimiter_init();
++	if (ret < 0)
++		goto err_free_decrypt_queue;
++
++	ret = register_netdevice(dev);
++	if (ret < 0)
++		goto err_uninit_ratelimiter;
++
++	list_add(&wg->device_list, &device_list);
++
++	/* We wait until the end to assign priv_destructor, so that
++	 * register_netdevice doesn't call it for us if it fails.
++	 */
++	dev->priv_destructor = wg_destruct;
++
++	pr_debug("%s: Interface created\n", dev->name);
++	return ret;
++
++err_uninit_ratelimiter:
++	wg_ratelimiter_uninit();
++err_free_decrypt_queue:
++	wg_packet_queue_free(&wg->decrypt_queue, true);
++err_free_encrypt_queue:
++	wg_packet_queue_free(&wg->encrypt_queue, true);
++err_destroy_packet_crypt:
++	destroy_workqueue(wg->packet_crypt_wq);
++err_destroy_handshake_send:
++	destroy_workqueue(wg->handshake_send_wq);
++err_destroy_handshake_receive:
++	destroy_workqueue(wg->handshake_receive_wq);
++err_free_incoming_handshakes:
++	free_percpu(wg->incoming_handshakes_worker);
++err_free_tstats:
++	free_percpu(dev->tstats);
++err_free_index_hashtable:
++	kvfree(wg->index_hashtable);
++err_free_peer_hashtable:
++	kvfree(wg->peer_hashtable);
++	return ret;
++}
++
++static struct rtnl_link_ops link_ops __read_mostly = {
++	.kind			= KBUILD_MODNAME,
++	.priv_size		= sizeof(struct wg_device),
++	.setup			= wg_setup,
++	.newlink		= wg_newlink,
++};
++
++static int wg_netdevice_notification(struct notifier_block *nb,
++				     unsigned long action, void *data)
++{
++	struct net_device *dev = ((struct netdev_notifier_info *)data)->dev;
++	struct wg_device *wg = netdev_priv(dev);
++
++	ASSERT_RTNL();
++
++	if (action != NETDEV_REGISTER || dev->netdev_ops != &netdev_ops)
++		return 0;
++
++	if (dev_net(dev) == wg->creating_net && wg->have_creating_net_ref) {
++		put_net(wg->creating_net);
++		wg->have_creating_net_ref = false;
++	} else if (dev_net(dev) != wg->creating_net &&
++		   !wg->have_creating_net_ref) {
++		wg->have_creating_net_ref = true;
++		get_net(wg->creating_net);
++	}
++	return 0;
++}
++
++static struct notifier_block netdevice_notifier = {
++	.notifier_call = wg_netdevice_notification
++};
++
++int __init wg_device_init(void)
++{
++	int ret;
++
++#ifdef CONFIG_PM_SLEEP
++	ret = register_pm_notifier(&pm_notifier);
++	if (ret)
++		return ret;
++#endif
++
++	ret = register_netdevice_notifier(&netdevice_notifier);
++	if (ret)
++		goto error_pm;
++
++	ret = rtnl_link_register(&link_ops);
++	if (ret)
++		goto error_netdevice;
++
++	return 0;
++
++error_netdevice:
++	unregister_netdevice_notifier(&netdevice_notifier);
++error_pm:
++#ifdef CONFIG_PM_SLEEP
++	unregister_pm_notifier(&pm_notifier);
++#endif
++	return ret;
++}
++
++void wg_device_uninit(void)
++{
++	rtnl_link_unregister(&link_ops);
++	unregister_netdevice_notifier(&netdevice_notifier);
++#ifdef CONFIG_PM_SLEEP
++	unregister_pm_notifier(&pm_notifier);
++#endif
++	rcu_barrier();
++}
+--- /dev/null
++++ b/drivers/net/wireguard/device.h
+@@ -0,0 +1,65 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#ifndef _WG_DEVICE_H
++#define _WG_DEVICE_H
++
++#include "noise.h"
++#include "allowedips.h"
++#include "peerlookup.h"
++#include "cookie.h"
++
++#include <linux/types.h>
++#include <linux/netdevice.h>
++#include <linux/workqueue.h>
++#include <linux/mutex.h>
++#include <linux/net.h>
++#include <linux/ptr_ring.h>
++
++struct wg_device;
++
++struct multicore_worker {
++	void *ptr;
++	struct work_struct work;
++};
++
++struct crypt_queue {
++	struct ptr_ring ring;
++	union {
++		struct {
++			struct multicore_worker __percpu *worker;
++			int last_cpu;
++		};
++		struct work_struct work;
++	};
++};
++
++struct wg_device {
++	struct net_device *dev;
++	struct crypt_queue encrypt_queue, decrypt_queue;
++	struct sock __rcu *sock4, *sock6;
++	struct net *creating_net;
++	struct noise_static_identity static_identity;
++	struct workqueue_struct *handshake_receive_wq, *handshake_send_wq;
++	struct workqueue_struct *packet_crypt_wq;
++	struct sk_buff_head incoming_handshakes;
++	int incoming_handshake_cpu;
++	struct multicore_worker __percpu *incoming_handshakes_worker;
++	struct cookie_checker cookie_checker;
++	struct pubkey_hashtable *peer_hashtable;
++	struct index_hashtable *index_hashtable;
++	struct allowedips peer_allowedips;
++	struct mutex device_update_lock, socket_update_lock;
++	struct list_head device_list, peer_list;
++	unsigned int num_peers, device_update_gen;
++	u32 fwmark;
++	u16 incoming_port;
++	bool have_creating_net_ref;
++};
++
++int wg_device_init(void);
++void wg_device_uninit(void);
++
++#endif /* _WG_DEVICE_H */
+--- /dev/null
++++ b/drivers/net/wireguard/main.c
+@@ -0,0 +1,64 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#include "version.h"
++#include "device.h"
++#include "noise.h"
++#include "queueing.h"
++#include "ratelimiter.h"
++#include "netlink.h"
++
++#include <uapi/linux/wireguard.h>
++
++#include <linux/version.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/genetlink.h>
++#include <net/rtnetlink.h>
++
++static int __init mod_init(void)
++{
++	int ret;
++
++#ifdef DEBUG
++	if (!wg_allowedips_selftest() || !wg_packet_counter_selftest() ||
++	    !wg_ratelimiter_selftest())
++		return -ENOTRECOVERABLE;
++#endif
++	wg_noise_init();
++
++	ret = wg_device_init();
++	if (ret < 0)
++		goto err_device;
++
++	ret = wg_genetlink_init();
++	if (ret < 0)
++		goto err_netlink;
++
++	pr_info("WireGuard " WIREGUARD_VERSION " loaded. See www.wireguard.com for information.\n");
++	pr_info("Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.\n");
++
++	return 0;
++
++err_netlink:
++	wg_device_uninit();
++err_device:
++	return ret;
++}
++
++static void __exit mod_exit(void)
++{
++	wg_genetlink_uninit();
++	wg_device_uninit();
++}
++
++module_init(mod_init);
++module_exit(mod_exit);
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("WireGuard secure network tunnel");
++MODULE_AUTHOR("Jason A. Donenfeld <Jason@zx2c4.com>");
++MODULE_VERSION(WIREGUARD_VERSION);
++MODULE_ALIAS_RTNL_LINK(KBUILD_MODNAME);
++MODULE_ALIAS_GENL_FAMILY(WG_GENL_NAME);
+--- /dev/null
++++ b/drivers/net/wireguard/messages.h
+@@ -0,0 +1,128 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#ifndef _WG_MESSAGES_H
++#define _WG_MESSAGES_H
++
++#include <crypto/curve25519.h>
++#include <crypto/chacha20poly1305.h>
++#include <crypto/blake2s.h>
++
++#include <linux/kernel.h>
++#include <linux/param.h>
++#include <linux/skbuff.h>
++
++enum noise_lengths {
++	NOISE_PUBLIC_KEY_LEN = CURVE25519_KEY_SIZE,
++	NOISE_SYMMETRIC_KEY_LEN = CHACHA20POLY1305_KEY_SIZE,
++	NOISE_TIMESTAMP_LEN = sizeof(u64) + sizeof(u32),
++	NOISE_AUTHTAG_LEN = CHACHA20POLY1305_AUTHTAG_SIZE,
++	NOISE_HASH_LEN = BLAKE2S_HASH_SIZE
++};
++
++#define noise_encrypted_len(plain_len) ((plain_len) + NOISE_AUTHTAG_LEN)
++
++enum cookie_values {
++	COOKIE_SECRET_MAX_AGE = 2 * 60,
++	COOKIE_SECRET_LATENCY = 5,
++	COOKIE_NONCE_LEN = XCHACHA20POLY1305_NONCE_SIZE,
++	COOKIE_LEN = 16
++};
++
++enum counter_values {
++	COUNTER_BITS_TOTAL = 2048,
++	COUNTER_REDUNDANT_BITS = BITS_PER_LONG,
++	COUNTER_WINDOW_SIZE = COUNTER_BITS_TOTAL - COUNTER_REDUNDANT_BITS
++};
++
++enum limits {
++	REKEY_AFTER_MESSAGES = 1ULL << 60,
++	REJECT_AFTER_MESSAGES = U64_MAX - COUNTER_WINDOW_SIZE - 1,
++	REKEY_TIMEOUT = 5,
++	REKEY_TIMEOUT_JITTER_MAX_JIFFIES = HZ / 3,
++	REKEY_AFTER_TIME = 120,
++	REJECT_AFTER_TIME = 180,
++	INITIATIONS_PER_SECOND = 50,
++	MAX_PEERS_PER_DEVICE = 1U << 20,
++	KEEPALIVE_TIMEOUT = 10,
++	MAX_TIMER_HANDSHAKES = 90 / REKEY_TIMEOUT,
++	MAX_QUEUED_INCOMING_HANDSHAKES = 4096, /* TODO: replace this with DQL */
++	MAX_STAGED_PACKETS = 128,
++	MAX_QUEUED_PACKETS = 1024 /* TODO: replace this with DQL */
++};
++
++enum message_type {
++	MESSAGE_INVALID = 0,
++	MESSAGE_HANDSHAKE_INITIATION = 1,
++	MESSAGE_HANDSHAKE_RESPONSE = 2,
++	MESSAGE_HANDSHAKE_COOKIE = 3,
++	MESSAGE_DATA = 4
++};
++
++struct message_header {
++	/* The actual layout of this that we want is:
++	 * u8 type
++	 * u8 reserved_zero[3]
++	 *
++	 * But it turns out that by encoding this as little endian,
++	 * we achieve the same thing, and it makes checking faster.
++	 */
++	__le32 type;
++};
++
++struct message_macs {
++	u8 mac1[COOKIE_LEN];
++	u8 mac2[COOKIE_LEN];
++};
++
++struct message_handshake_initiation {
++	struct message_header header;
++	__le32 sender_index;
++	u8 unencrypted_ephemeral[NOISE_PUBLIC_KEY_LEN];
++	u8 encrypted_static[noise_encrypted_len(NOISE_PUBLIC_KEY_LEN)];
++	u8 encrypted_timestamp[noise_encrypted_len(NOISE_TIMESTAMP_LEN)];
++	struct message_macs macs;
++};
++
++struct message_handshake_response {
++	struct message_header header;
++	__le32 sender_index;
++	__le32 receiver_index;
++	u8 unencrypted_ephemeral[NOISE_PUBLIC_KEY_LEN];
++	u8 encrypted_nothing[noise_encrypted_len(0)];
++	struct message_macs macs;
++};
++
++struct message_handshake_cookie {
++	struct message_header header;
++	__le32 receiver_index;
++	u8 nonce[COOKIE_NONCE_LEN];
++	u8 encrypted_cookie[noise_encrypted_len(COOKIE_LEN)];
++};
++
++struct message_data {
++	struct message_header header;
++	__le32 key_idx;
++	__le64 counter;
++	u8 encrypted_data[];
++};
++
++#define message_data_len(plain_len) \
++	(noise_encrypted_len(plain_len) + sizeof(struct message_data))
++
++enum message_alignments {
++	MESSAGE_PADDING_MULTIPLE = 16,
++	MESSAGE_MINIMUM_LENGTH = message_data_len(0)
++};
++
++#define SKB_HEADER_LEN                                       \
++	(max(sizeof(struct iphdr), sizeof(struct ipv6hdr)) + \
++	 sizeof(struct udphdr) + NET_SKB_PAD)
++#define DATA_PACKET_HEAD_ROOM \
++	ALIGN(sizeof(struct message_data) + SKB_HEADER_LEN, 4)
++
++enum { HANDSHAKE_DSCP = 0x88 /* AF41, plus 00 ECN */ };
++
++#endif /* _WG_MESSAGES_H */
+--- /dev/null
++++ b/drivers/net/wireguard/netlink.c
+@@ -0,0 +1,648 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#include "netlink.h"
++#include "device.h"
++#include "peer.h"
++#include "socket.h"
++#include "queueing.h"
++#include "messages.h"
++
++#include <uapi/linux/wireguard.h>
++
++#include <linux/if.h>
++#include <net/genetlink.h>
++#include <net/sock.h>
++#include <crypto/algapi.h>
++
++static struct genl_family genl_family;
++
++static const struct nla_policy device_policy[WGDEVICE_A_MAX + 1] = {
++	[WGDEVICE_A_IFINDEX]		= { .type = NLA_U32 },
++	[WGDEVICE_A_IFNAME]		= { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
++	[WGDEVICE_A_PRIVATE_KEY]	= { .type = NLA_EXACT_LEN, .len = NOISE_PUBLIC_KEY_LEN },
++	[WGDEVICE_A_PUBLIC_KEY]		= { .type = NLA_EXACT_LEN, .len = NOISE_PUBLIC_KEY_LEN },
++	[WGDEVICE_A_FLAGS]		= { .type = NLA_U32 },
++	[WGDEVICE_A_LISTEN_PORT]	= { .type = NLA_U16 },
++	[WGDEVICE_A_FWMARK]		= { .type = NLA_U32 },
++	[WGDEVICE_A_PEERS]		= { .type = NLA_NESTED }
++};
++
++static const struct nla_policy peer_policy[WGPEER_A_MAX + 1] = {
++	[WGPEER_A_PUBLIC_KEY]				= { .type = NLA_EXACT_LEN, .len = NOISE_PUBLIC_KEY_LEN },
++	[WGPEER_A_PRESHARED_KEY]			= { .type = NLA_EXACT_LEN, .len = NOISE_SYMMETRIC_KEY_LEN },
++	[WGPEER_A_FLAGS]				= { .type = NLA_U32 },
++	[WGPEER_A_ENDPOINT]				= { .type = NLA_MIN_LEN, .len = sizeof(struct sockaddr) },
++	[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]	= { .type = NLA_U16 },
++	[WGPEER_A_LAST_HANDSHAKE_TIME]			= { .type = NLA_EXACT_LEN, .len = sizeof(struct __kernel_timespec) },
++	[WGPEER_A_RX_BYTES]				= { .type = NLA_U64 },
++	[WGPEER_A_TX_BYTES]				= { .type = NLA_U64 },
++	[WGPEER_A_ALLOWEDIPS]				= { .type = NLA_NESTED },
++	[WGPEER_A_PROTOCOL_VERSION]			= { .type = NLA_U32 }
++};
++
++static const struct nla_policy allowedip_policy[WGALLOWEDIP_A_MAX + 1] = {
++	[WGALLOWEDIP_A_FAMILY]		= { .type = NLA_U16 },
++	[WGALLOWEDIP_A_IPADDR]		= { .type = NLA_MIN_LEN, .len = sizeof(struct in_addr) },
++	[WGALLOWEDIP_A_CIDR_MASK]	= { .type = NLA_U8 }
++};
++
++static struct wg_device *lookup_interface(struct nlattr **attrs,
++					  struct sk_buff *skb)
++{
++	struct net_device *dev = NULL;
++
++	if (!attrs[WGDEVICE_A_IFINDEX] == !attrs[WGDEVICE_A_IFNAME])
++		return ERR_PTR(-EBADR);
++	if (attrs[WGDEVICE_A_IFINDEX])
++		dev = dev_get_by_index(sock_net(skb->sk),
++				       nla_get_u32(attrs[WGDEVICE_A_IFINDEX]));
++	else if (attrs[WGDEVICE_A_IFNAME])
++		dev = dev_get_by_name(sock_net(skb->sk),
++				      nla_data(attrs[WGDEVICE_A_IFNAME]));
++	if (!dev)
++		return ERR_PTR(-ENODEV);
++	if (!dev->rtnl_link_ops || !dev->rtnl_link_ops->kind ||
++	    strcmp(dev->rtnl_link_ops->kind, KBUILD_MODNAME)) {
++		dev_put(dev);
++		return ERR_PTR(-EOPNOTSUPP);
++	}
++	return netdev_priv(dev);
++}
++
++static int get_allowedips(struct sk_buff *skb, const u8 *ip, u8 cidr,
++			  int family)
++{
++	struct nlattr *allowedip_nest;
++
++	allowedip_nest = nla_nest_start(skb, 0);
++	if (!allowedip_nest)
++		return -EMSGSIZE;
++
++	if (nla_put_u8(skb, WGALLOWEDIP_A_CIDR_MASK, cidr) ||
++	    nla_put_u16(skb, WGALLOWEDIP_A_FAMILY, family) ||
++	    nla_put(skb, WGALLOWEDIP_A_IPADDR, family == AF_INET6 ?
++		    sizeof(struct in6_addr) : sizeof(struct in_addr), ip)) {
++		nla_nest_cancel(skb, allowedip_nest);
++		return -EMSGSIZE;
++	}
++
++	nla_nest_end(skb, allowedip_nest);
++	return 0;
++}
++
++struct dump_ctx {
++	struct wg_device *wg;
++	struct wg_peer *next_peer;
++	u64 allowedips_seq;
++	struct allowedips_node *next_allowedip;
++};
++
++#define DUMP_CTX(cb) ((struct dump_ctx *)(cb)->args)
++
++static int
++get_peer(struct wg_peer *peer, struct sk_buff *skb, struct dump_ctx *ctx)
++{
++
++	struct nlattr *allowedips_nest, *peer_nest = nla_nest_start(skb, 0);
++	struct allowedips_node *allowedips_node = ctx->next_allowedip;
++	bool fail;
++
++	if (!peer_nest)
++		return -EMSGSIZE;
++
++	down_read(&peer->handshake.lock);
++	fail = nla_put(skb, WGPEER_A_PUBLIC_KEY, NOISE_PUBLIC_KEY_LEN,
++		       peer->handshake.remote_static);
++	up_read(&peer->handshake.lock);
++	if (fail)
++		goto err;
++
++	if (!allowedips_node) {
++		const struct __kernel_timespec last_handshake = {
++			.tv_sec = peer->walltime_last_handshake.tv_sec,
++			.tv_nsec = peer->walltime_last_handshake.tv_nsec
++		};
++
++		down_read(&peer->handshake.lock);
++		fail = nla_put(skb, WGPEER_A_PRESHARED_KEY,
++			       NOISE_SYMMETRIC_KEY_LEN,
++			       peer->handshake.preshared_key);
++		up_read(&peer->handshake.lock);
++		if (fail)
++			goto err;
++
++		if (nla_put(skb, WGPEER_A_LAST_HANDSHAKE_TIME,
++			    sizeof(last_handshake), &last_handshake) ||
++		    nla_put_u16(skb, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
++				peer->persistent_keepalive_interval) ||
++		    nla_put_u64_64bit(skb, WGPEER_A_TX_BYTES, peer->tx_bytes,
++				      WGPEER_A_UNSPEC) ||
++		    nla_put_u64_64bit(skb, WGPEER_A_RX_BYTES, peer->rx_bytes,
++				      WGPEER_A_UNSPEC) ||
++		    nla_put_u32(skb, WGPEER_A_PROTOCOL_VERSION, 1))
++			goto err;
++
++		read_lock_bh(&peer->endpoint_lock);
++		if (peer->endpoint.addr.sa_family == AF_INET)
++			fail = nla_put(skb, WGPEER_A_ENDPOINT,
++				       sizeof(peer->endpoint.addr4),
++				       &peer->endpoint.addr4);
++		else if (peer->endpoint.addr.sa_family == AF_INET6)
++			fail = nla_put(skb, WGPEER_A_ENDPOINT,
++				       sizeof(peer->endpoint.addr6),
++				       &peer->endpoint.addr6);
++		read_unlock_bh(&peer->endpoint_lock);
++		if (fail)
++			goto err;
++		allowedips_node =
++			list_first_entry_or_null(&peer->allowedips_list,
++					struct allowedips_node, peer_list);
++	}
++	if (!allowedips_node)
++		goto no_allowedips;
++	if (!ctx->allowedips_seq)
++		ctx->allowedips_seq = peer->device->peer_allowedips.seq;
++	else if (ctx->allowedips_seq != peer->device->peer_allowedips.seq)
++		goto no_allowedips;
++
++	allowedips_nest = nla_nest_start(skb, WGPEER_A_ALLOWEDIPS);
++	if (!allowedips_nest)
++		goto err;
++
++	list_for_each_entry_from(allowedips_node, &peer->allowedips_list,
++				 peer_list) {
++		u8 cidr, ip[16] __aligned(__alignof(u64));
++		int family;
++
++		family = wg_allowedips_read_node(allowedips_node, ip, &cidr);
++		if (get_allowedips(skb, ip, cidr, family)) {
++			nla_nest_end(skb, allowedips_nest);
++			nla_nest_end(skb, peer_nest);
++			ctx->next_allowedip = allowedips_node;
++			return -EMSGSIZE;
++		}
++	}
++	nla_nest_end(skb, allowedips_nest);
++no_allowedips:
++	nla_nest_end(skb, peer_nest);
++	ctx->next_allowedip = NULL;
++	ctx->allowedips_seq = 0;
++	return 0;
++err:
++	nla_nest_cancel(skb, peer_nest);
++	return -EMSGSIZE;
++}
++
++static int wg_get_device_start(struct netlink_callback *cb)
++{
++	struct nlattr **attrs = genl_family_attrbuf(&genl_family);
++	struct wg_device *wg;
++	int ret;
++
++	ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + genl_family.hdrsize, attrs,
++			  genl_family.maxattr, device_policy, NULL);
++	if (ret < 0)
++		return ret;
++	wg = lookup_interface(attrs, cb->skb);
++	if (IS_ERR(wg))
++		return PTR_ERR(wg);
++	DUMP_CTX(cb)->wg = wg;
++	return 0;
++}
++
++static int wg_get_device_dump(struct sk_buff *skb, struct netlink_callback *cb)
++{
++	struct wg_peer *peer, *next_peer_cursor;
++	struct dump_ctx *ctx = DUMP_CTX(cb);
++	struct wg_device *wg = ctx->wg;
++	struct nlattr *peers_nest;
++	int ret = -EMSGSIZE;
++	bool done = true;
++	void *hdr;
++
++	rtnl_lock();
++	mutex_lock(&wg->device_update_lock);
++	cb->seq = wg->device_update_gen;
++	next_peer_cursor = ctx->next_peer;
++
++	hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
++			  &genl_family, NLM_F_MULTI, WG_CMD_GET_DEVICE);
++	if (!hdr)
++		goto out;
++	genl_dump_check_consistent(cb, hdr);
++
++	if (!ctx->next_peer) {
++		if (nla_put_u16(skb, WGDEVICE_A_LISTEN_PORT,
++				wg->incoming_port) ||
++		    nla_put_u32(skb, WGDEVICE_A_FWMARK, wg->fwmark) ||
++		    nla_put_u32(skb, WGDEVICE_A_IFINDEX, wg->dev->ifindex) ||
++		    nla_put_string(skb, WGDEVICE_A_IFNAME, wg->dev->name))
++			goto out;
++
++		down_read(&wg->static_identity.lock);
++		if (wg->static_identity.has_identity) {
++			if (nla_put(skb, WGDEVICE_A_PRIVATE_KEY,
++				    NOISE_PUBLIC_KEY_LEN,
++				    wg->static_identity.static_private) ||
++			    nla_put(skb, WGDEVICE_A_PUBLIC_KEY,
++				    NOISE_PUBLIC_KEY_LEN,
++				    wg->static_identity.static_public)) {
++				up_read(&wg->static_identity.lock);
++				goto out;
++			}
++		}
++		up_read(&wg->static_identity.lock);
++	}
++
++	peers_nest = nla_nest_start(skb, WGDEVICE_A_PEERS);
++	if (!peers_nest)
++		goto out;
++	ret = 0;
++	/* If the last cursor was removed via list_del_init in peer_remove, then
++	 * we just treat this the same as there being no more peers left. The
++	 * reason is that seq_nr should indicate to userspace that this isn't a
++	 * coherent dump anyway, so they'll try again.
++	 */
++	if (list_empty(&wg->peer_list) ||
++	    (ctx->next_peer && list_empty(&ctx->next_peer->peer_list))) {
++		nla_nest_cancel(skb, peers_nest);
++		goto out;
++	}
++	lockdep_assert_held(&wg->device_update_lock);
++	peer = list_prepare_entry(ctx->next_peer, &wg->peer_list, peer_list);
++	list_for_each_entry_continue(peer, &wg->peer_list, peer_list) {
++		if (get_peer(peer, skb, ctx)) {
++			done = false;
++			break;
++		}
++		next_peer_cursor = peer;
++	}
++	nla_nest_end(skb, peers_nest);
++
++out:
++	if (!ret && !done && next_peer_cursor)
++		wg_peer_get(next_peer_cursor);
++	wg_peer_put(ctx->next_peer);
++	mutex_unlock(&wg->device_update_lock);
++	rtnl_unlock();
++
++	if (ret) {
++		genlmsg_cancel(skb, hdr);
++		return ret;
++	}
++	genlmsg_end(skb, hdr);
++	if (done) {
++		ctx->next_peer = NULL;
++		return 0;
++	}
++	ctx->next_peer = next_peer_cursor;
++	return skb->len;
++
++	/* At this point, we can't really deal ourselves with safely zeroing out
++	 * the private key material after usage. This will need an additional API
++	 * in the kernel for marking skbs as zero_on_free.
++	 */
++}
++
++static int wg_get_device_done(struct netlink_callback *cb)
++{
++	struct dump_ctx *ctx = DUMP_CTX(cb);
++
++	if (ctx->wg)
++		dev_put(ctx->wg->dev);
++	wg_peer_put(ctx->next_peer);
++	return 0;
++}
++
++static int set_port(struct wg_device *wg, u16 port)
++{
++	struct wg_peer *peer;
++
++	if (wg->incoming_port == port)
++		return 0;
++	list_for_each_entry(peer, &wg->peer_list, peer_list)
++		wg_socket_clear_peer_endpoint_src(peer);
++	if (!netif_running(wg->dev)) {
++		wg->incoming_port = port;
++		return 0;
++	}
++	return wg_socket_init(wg, port);
++}
++
++static int set_allowedip(struct wg_peer *peer, struct nlattr **attrs)
++{
++	int ret = -EINVAL;
++	u16 family;
++	u8 cidr;
++
++	if (!attrs[WGALLOWEDIP_A_FAMILY] || !attrs[WGALLOWEDIP_A_IPADDR] ||
++	    !attrs[WGALLOWEDIP_A_CIDR_MASK])
++		return ret;
++	family = nla_get_u16(attrs[WGALLOWEDIP_A_FAMILY]);
++	cidr = nla_get_u8(attrs[WGALLOWEDIP_A_CIDR_MASK]);
++
++	if (family == AF_INET && cidr <= 32 &&
++	    nla_len(attrs[WGALLOWEDIP_A_IPADDR]) == sizeof(struct in_addr))
++		ret = wg_allowedips_insert_v4(
++			&peer->device->peer_allowedips,
++			nla_data(attrs[WGALLOWEDIP_A_IPADDR]), cidr, peer,
++			&peer->device->device_update_lock);
++	else if (family == AF_INET6 && cidr <= 128 &&
++		 nla_len(attrs[WGALLOWEDIP_A_IPADDR]) == sizeof(struct in6_addr))
++		ret = wg_allowedips_insert_v6(
++			&peer->device->peer_allowedips,
++			nla_data(attrs[WGALLOWEDIP_A_IPADDR]), cidr, peer,
++			&peer->device->device_update_lock);
++
++	return ret;
++}
++
++static int set_peer(struct wg_device *wg, struct nlattr **attrs)
++{
++	u8 *public_key = NULL, *preshared_key = NULL;
++	struct wg_peer *peer = NULL;
++	u32 flags = 0;
++	int ret;
++
++	ret = -EINVAL;
++	if (attrs[WGPEER_A_PUBLIC_KEY] &&
++	    nla_len(attrs[WGPEER_A_PUBLIC_KEY]) == NOISE_PUBLIC_KEY_LEN)
++		public_key = nla_data(attrs[WGPEER_A_PUBLIC_KEY]);
++	else
++		goto out;
++	if (attrs[WGPEER_A_PRESHARED_KEY] &&
++	    nla_len(attrs[WGPEER_A_PRESHARED_KEY]) == NOISE_SYMMETRIC_KEY_LEN)
++		preshared_key = nla_data(attrs[WGPEER_A_PRESHARED_KEY]);
++
++	if (attrs[WGPEER_A_FLAGS])
++		flags = nla_get_u32(attrs[WGPEER_A_FLAGS]);
++	ret = -EOPNOTSUPP;
++	if (flags & ~__WGPEER_F_ALL)
++		goto out;
++
++	ret = -EPFNOSUPPORT;
++	if (attrs[WGPEER_A_PROTOCOL_VERSION]) {
++		if (nla_get_u32(attrs[WGPEER_A_PROTOCOL_VERSION]) != 1)
++			goto out;
++	}
++
++	peer = wg_pubkey_hashtable_lookup(wg->peer_hashtable,
++					  nla_data(attrs[WGPEER_A_PUBLIC_KEY]));
++	ret = 0;
++	if (!peer) { /* Peer doesn't exist yet. Add a new one. */
++		if (flags & (WGPEER_F_REMOVE_ME | WGPEER_F_UPDATE_ONLY))
++			goto out;
++
++		/* The peer is new, so there aren't allowed IPs to remove. */
++		flags &= ~WGPEER_F_REPLACE_ALLOWEDIPS;
++
++		down_read(&wg->static_identity.lock);
++		if (wg->static_identity.has_identity &&
++		    !memcmp(nla_data(attrs[WGPEER_A_PUBLIC_KEY]),
++			    wg->static_identity.static_public,
++			    NOISE_PUBLIC_KEY_LEN)) {
++			/* We silently ignore peers that have the same public
++			 * key as the device. The reason we do it silently is
++			 * that we'd like for people to be able to reuse the
++			 * same set of API calls across peers.
++			 */
++			up_read(&wg->static_identity.lock);
++			ret = 0;
++			goto out;
++		}
++		up_read(&wg->static_identity.lock);
++
++		peer = wg_peer_create(wg, public_key, preshared_key);
++		if (IS_ERR(peer)) {
++			/* Similar to the above, if the key is invalid, we skip
++			 * it without fanfare, so that services don't need to
++			 * worry about doing key validation themselves.
++			 */
++			ret = PTR_ERR(peer) == -EKEYREJECTED ? 0 : PTR_ERR(peer);
++			peer = NULL;
++			goto out;
++		}
++		/* Take additional reference, as though we've just been
++		 * looked up.
++		 */
++		wg_peer_get(peer);
++	}
++
++	if (flags & WGPEER_F_REMOVE_ME) {
++		wg_peer_remove(peer);
++		goto out;
++	}
++
++	if (preshared_key) {
++		down_write(&peer->handshake.lock);
++		memcpy(&peer->handshake.preshared_key, preshared_key,
++		       NOISE_SYMMETRIC_KEY_LEN);
++		up_write(&peer->handshake.lock);
++	}
++
++	if (attrs[WGPEER_A_ENDPOINT]) {
++		struct sockaddr *addr = nla_data(attrs[WGPEER_A_ENDPOINT]);
++		size_t len = nla_len(attrs[WGPEER_A_ENDPOINT]);
++
++		if ((len == sizeof(struct sockaddr_in) &&
++		     addr->sa_family == AF_INET) ||
++		    (len == sizeof(struct sockaddr_in6) &&
++		     addr->sa_family == AF_INET6)) {
++			struct endpoint endpoint = { { { 0 } } };
++
++			memcpy(&endpoint.addr, addr, len);
++			wg_socket_set_peer_endpoint(peer, &endpoint);
++		}
++	}
++
++	if (flags & WGPEER_F_REPLACE_ALLOWEDIPS)
++		wg_allowedips_remove_by_peer(&wg->peer_allowedips, peer,
++					     &wg->device_update_lock);
++
++	if (attrs[WGPEER_A_ALLOWEDIPS]) {
++		struct nlattr *attr, *allowedip[WGALLOWEDIP_A_MAX + 1];
++		int rem;
++
++		nla_for_each_nested(attr, attrs[WGPEER_A_ALLOWEDIPS], rem) {
++			ret = nla_parse_nested(allowedip, WGALLOWEDIP_A_MAX,
++					       attr, allowedip_policy, NULL);
++			if (ret < 0)
++				goto out;
++			ret = set_allowedip(peer, allowedip);
++			if (ret < 0)
++				goto out;
++		}
++	}
++
++	if (attrs[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]) {
++		const u16 persistent_keepalive_interval = nla_get_u16(
++				attrs[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]);
++		const bool send_keepalive =
++			!peer->persistent_keepalive_interval &&
++			persistent_keepalive_interval &&
++			netif_running(wg->dev);
++
++		peer->persistent_keepalive_interval = persistent_keepalive_interval;
++		if (send_keepalive)
++			wg_packet_send_keepalive(peer);
++	}
++
++	if (netif_running(wg->dev))
++		wg_packet_send_staged_packets(peer);
++
++out:
++	wg_peer_put(peer);
++	if (attrs[WGPEER_A_PRESHARED_KEY])
++		memzero_explicit(nla_data(attrs[WGPEER_A_PRESHARED_KEY]),
++				 nla_len(attrs[WGPEER_A_PRESHARED_KEY]));
++	return ret;
++}
++
++static int wg_set_device(struct sk_buff *skb, struct genl_info *info)
++{
++	struct wg_device *wg = lookup_interface(info->attrs, skb);
++	u32 flags = 0;
++	int ret;
++
++	if (IS_ERR(wg)) {
++		ret = PTR_ERR(wg);
++		goto out_nodev;
++	}
++
++	rtnl_lock();
++	mutex_lock(&wg->device_update_lock);
++
++	if (info->attrs[WGDEVICE_A_FLAGS])
++		flags = nla_get_u32(info->attrs[WGDEVICE_A_FLAGS]);
++	ret = -EOPNOTSUPP;
++	if (flags & ~__WGDEVICE_F_ALL)
++		goto out;
++
++	ret = -EPERM;
++	if ((info->attrs[WGDEVICE_A_LISTEN_PORT] ||
++	     info->attrs[WGDEVICE_A_FWMARK]) &&
++	    !ns_capable(wg->creating_net->user_ns, CAP_NET_ADMIN))
++		goto out;
++
++	++wg->device_update_gen;
++
++	if (info->attrs[WGDEVICE_A_FWMARK]) {
++		struct wg_peer *peer;
++
++		wg->fwmark = nla_get_u32(info->attrs[WGDEVICE_A_FWMARK]);
++		list_for_each_entry(peer, &wg->peer_list, peer_list)
++			wg_socket_clear_peer_endpoint_src(peer);
++	}
++
++	if (info->attrs[WGDEVICE_A_LISTEN_PORT]) {
++		ret = set_port(wg,
++			nla_get_u16(info->attrs[WGDEVICE_A_LISTEN_PORT]));
++		if (ret)
++			goto out;
++	}
++
++	if (flags & WGDEVICE_F_REPLACE_PEERS)
++		wg_peer_remove_all(wg);
++
++	if (info->attrs[WGDEVICE_A_PRIVATE_KEY] &&
++	    nla_len(info->attrs[WGDEVICE_A_PRIVATE_KEY]) ==
++		    NOISE_PUBLIC_KEY_LEN) {
++		u8 *private_key = nla_data(info->attrs[WGDEVICE_A_PRIVATE_KEY]);
++		u8 public_key[NOISE_PUBLIC_KEY_LEN];
++		struct wg_peer *peer, *temp;
++
++		if (!crypto_memneq(wg->static_identity.static_private,
++				   private_key, NOISE_PUBLIC_KEY_LEN))
++			goto skip_set_private_key;
++
++		/* We remove before setting, to prevent race, which means doing
++		 * two 25519-genpub ops.
++		 */
++		if (curve25519_generate_public(public_key, private_key)) {
++			peer = wg_pubkey_hashtable_lookup(wg->peer_hashtable,
++							  public_key);
++			if (peer) {
++				wg_peer_put(peer);
++				wg_peer_remove(peer);
++			}
++		}
++
++		down_write(&wg->static_identity.lock);
++		wg_noise_set_static_identity_private_key(&wg->static_identity,
++							 private_key);
++		list_for_each_entry_safe(peer, temp, &wg->peer_list,
++					 peer_list) {
++			if (wg_noise_precompute_static_static(peer))
++				wg_noise_expire_current_peer_keypairs(peer);
++			else
++				wg_peer_remove(peer);
++		}
++		wg_cookie_checker_precompute_device_keys(&wg->cookie_checker);
++		up_write(&wg->static_identity.lock);
++	}
++skip_set_private_key:
++
++	if (info->attrs[WGDEVICE_A_PEERS]) {
++		struct nlattr *attr, *peer[WGPEER_A_MAX + 1];
++		int rem;
++
++		nla_for_each_nested(attr, info->attrs[WGDEVICE_A_PEERS], rem) {
++			ret = nla_parse_nested(peer, WGPEER_A_MAX, attr,
++					       peer_policy, NULL);
++			if (ret < 0)
++				goto out;
++			ret = set_peer(wg, peer);
++			if (ret < 0)
++				goto out;
++		}
++	}
++	ret = 0;
++
++out:
++	mutex_unlock(&wg->device_update_lock);
++	rtnl_unlock();
++	dev_put(wg->dev);
++out_nodev:
++	if (info->attrs[WGDEVICE_A_PRIVATE_KEY])
++		memzero_explicit(nla_data(info->attrs[WGDEVICE_A_PRIVATE_KEY]),
++				 nla_len(info->attrs[WGDEVICE_A_PRIVATE_KEY]));
++	return ret;
++}
++
++static const struct genl_ops genl_ops[] = {
++	{
++		.cmd = WG_CMD_GET_DEVICE,
++		.start = wg_get_device_start,
++		.dumpit = wg_get_device_dump,
++		.done = wg_get_device_done,
++		.flags = GENL_UNS_ADMIN_PERM
++	}, {
++		.cmd = WG_CMD_SET_DEVICE,
++		.doit = wg_set_device,
++		.flags = GENL_UNS_ADMIN_PERM
++	}
++};
++
++static struct genl_family genl_family __ro_after_init = {
++	.ops = genl_ops,
++	.n_ops = ARRAY_SIZE(genl_ops),
++	.name = WG_GENL_NAME,
++	.version = WG_GENL_VERSION,
++	.maxattr = WGDEVICE_A_MAX,
++	.module = THIS_MODULE,
++	.policy = device_policy,
++	.netnsok = true
++};
++
++int __init wg_genetlink_init(void)
++{
++	return genl_register_family(&genl_family);
++}
++
++void __exit wg_genetlink_uninit(void)
++{
++	genl_unregister_family(&genl_family);
++}
+--- /dev/null
++++ b/drivers/net/wireguard/netlink.h
+@@ -0,0 +1,12 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#ifndef _WG_NETLINK_H
++#define _WG_NETLINK_H
++
++int wg_genetlink_init(void);
++void wg_genetlink_uninit(void);
++
++#endif /* _WG_NETLINK_H */
+--- /dev/null
++++ b/drivers/net/wireguard/noise.c
+@@ -0,0 +1,828 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#include "noise.h"
++#include "device.h"
++#include "peer.h"
++#include "messages.h"
++#include "queueing.h"
++#include "peerlookup.h"
++
++#include <linux/rcupdate.h>
++#include <linux/slab.h>
++#include <linux/bitmap.h>
++#include <linux/scatterlist.h>
++#include <linux/highmem.h>
++#include <crypto/algapi.h>
++
++/* This implements Noise_IKpsk2:
++ *
++ * <- s
++ * ******
++ * -> e, es, s, ss, {t}
++ * <- e, ee, se, psk, {}
++ */
++
++static const u8 handshake_name[37] = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s";
++static const u8 identifier_name[34] = "WireGuard v1 zx2c4 Jason@zx2c4.com";
++static u8 handshake_init_hash[NOISE_HASH_LEN] __ro_after_init;
++static u8 handshake_init_chaining_key[NOISE_HASH_LEN] __ro_after_init;
++static atomic64_t keypair_counter = ATOMIC64_INIT(0);
++
++void __init wg_noise_init(void)
++{
++	struct blake2s_state blake;
++
++	blake2s(handshake_init_chaining_key, handshake_name, NULL,
++		NOISE_HASH_LEN, sizeof(handshake_name), 0);
++	blake2s_init(&blake, NOISE_HASH_LEN);
++	blake2s_update(&blake, handshake_init_chaining_key, NOISE_HASH_LEN);
++	blake2s_update(&blake, identifier_name, sizeof(identifier_name));
++	blake2s_final(&blake, handshake_init_hash);
++}
++
++/* Must hold peer->handshake.static_identity->lock */
++bool wg_noise_precompute_static_static(struct wg_peer *peer)
++{
++	bool ret = true;
++
++	down_write(&peer->handshake.lock);
++	if (peer->handshake.static_identity->has_identity)
++		ret = curve25519(
++			peer->handshake.precomputed_static_static,
++			peer->handshake.static_identity->static_private,
++			peer->handshake.remote_static);
++	else
++		memset(peer->handshake.precomputed_static_static, 0,
++		       NOISE_PUBLIC_KEY_LEN);
++	up_write(&peer->handshake.lock);
++	return ret;
++}
++
++bool wg_noise_handshake_init(struct noise_handshake *handshake,
++			   struct noise_static_identity *static_identity,
++			   const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN],
++			   const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN],
++			   struct wg_peer *peer)
++{
++	memset(handshake, 0, sizeof(*handshake));
++	init_rwsem(&handshake->lock);
++	handshake->entry.type = INDEX_HASHTABLE_HANDSHAKE;
++	handshake->entry.peer = peer;
++	memcpy(handshake->remote_static, peer_public_key, NOISE_PUBLIC_KEY_LEN);
++	if (peer_preshared_key)
++		memcpy(handshake->preshared_key, peer_preshared_key,
++		       NOISE_SYMMETRIC_KEY_LEN);
++	handshake->static_identity = static_identity;
++	handshake->state = HANDSHAKE_ZEROED;
++	return wg_noise_precompute_static_static(peer);
++}
++
++static void handshake_zero(struct noise_handshake *handshake)
++{
++	memset(&handshake->ephemeral_private, 0, NOISE_PUBLIC_KEY_LEN);
++	memset(&handshake->remote_ephemeral, 0, NOISE_PUBLIC_KEY_LEN);
++	memset(&handshake->hash, 0, NOISE_HASH_LEN);
++	memset(&handshake->chaining_key, 0, NOISE_HASH_LEN);
++	handshake->remote_index = 0;
++	handshake->state = HANDSHAKE_ZEROED;
++}
++
++void wg_noise_handshake_clear(struct noise_handshake *handshake)
++{
++	wg_index_hashtable_remove(
++			handshake->entry.peer->device->index_hashtable,
++			&handshake->entry);
++	down_write(&handshake->lock);
++	handshake_zero(handshake);
++	up_write(&handshake->lock);
++	wg_index_hashtable_remove(
++			handshake->entry.peer->device->index_hashtable,
++			&handshake->entry);
++}
++
++static struct noise_keypair *keypair_create(struct wg_peer *peer)
++{
++	struct noise_keypair *keypair = kzalloc(sizeof(*keypair), GFP_KERNEL);
++
++	if (unlikely(!keypair))
++		return NULL;
++	keypair->internal_id = atomic64_inc_return(&keypair_counter);
++	keypair->entry.type = INDEX_HASHTABLE_KEYPAIR;
++	keypair->entry.peer = peer;
++	kref_init(&keypair->refcount);
++	return keypair;
++}
++
++static void keypair_free_rcu(struct rcu_head *rcu)
++{
++	kzfree(container_of(rcu, struct noise_keypair, rcu));
++}
++
++static void keypair_free_kref(struct kref *kref)
++{
++	struct noise_keypair *keypair =
++		container_of(kref, struct noise_keypair, refcount);
++
++	net_dbg_ratelimited("%s: Keypair %llu destroyed for peer %llu\n",
++			    keypair->entry.peer->device->dev->name,
++			    keypair->internal_id,
++			    keypair->entry.peer->internal_id);
++	wg_index_hashtable_remove(keypair->entry.peer->device->index_hashtable,
++				  &keypair->entry);
++	call_rcu(&keypair->rcu, keypair_free_rcu);
++}
++
++void wg_noise_keypair_put(struct noise_keypair *keypair, bool unreference_now)
++{
++	if (unlikely(!keypair))
++		return;
++	if (unlikely(unreference_now))
++		wg_index_hashtable_remove(
++			keypair->entry.peer->device->index_hashtable,
++			&keypair->entry);
++	kref_put(&keypair->refcount, keypair_free_kref);
++}
++
++struct noise_keypair *wg_noise_keypair_get(struct noise_keypair *keypair)
++{
++	RCU_LOCKDEP_WARN(!rcu_read_lock_bh_held(),
++		"Taking noise keypair reference without holding the RCU BH read lock");
++	if (unlikely(!keypair || !kref_get_unless_zero(&keypair->refcount)))
++		return NULL;
++	return keypair;
++}
++
++void wg_noise_keypairs_clear(struct noise_keypairs *keypairs)
++{
++	struct noise_keypair *old;
++
++	spin_lock_bh(&keypairs->keypair_update_lock);
++
++	/* We zero the next_keypair before zeroing the others, so that
++	 * wg_noise_received_with_keypair returns early before subsequent ones
++	 * are zeroed.
++	 */
++	old = rcu_dereference_protected(keypairs->next_keypair,
++		lockdep_is_held(&keypairs->keypair_update_lock));
++	RCU_INIT_POINTER(keypairs->next_keypair, NULL);
++	wg_noise_keypair_put(old, true);
++
++	old = rcu_dereference_protected(keypairs->previous_keypair,
++		lockdep_is_held(&keypairs->keypair_update_lock));
++	RCU_INIT_POINTER(keypairs->previous_keypair, NULL);
++	wg_noise_keypair_put(old, true);
++
++	old = rcu_dereference_protected(keypairs->current_keypair,
++		lockdep_is_held(&keypairs->keypair_update_lock));
++	RCU_INIT_POINTER(keypairs->current_keypair, NULL);
++	wg_noise_keypair_put(old, true);
++
++	spin_unlock_bh(&keypairs->keypair_update_lock);
++}
++
++void wg_noise_expire_current_peer_keypairs(struct wg_peer *peer)
++{
++	struct noise_keypair *keypair;
++
++	wg_noise_handshake_clear(&peer->handshake);
++	wg_noise_reset_last_sent_handshake(&peer->last_sent_handshake);
++
++	spin_lock_bh(&peer->keypairs.keypair_update_lock);
++	keypair = rcu_dereference_protected(peer->keypairs.next_keypair,
++			lockdep_is_held(&peer->keypairs.keypair_update_lock));
++	if (keypair)
++		keypair->sending.is_valid = false;
++	keypair = rcu_dereference_protected(peer->keypairs.current_keypair,
++			lockdep_is_held(&peer->keypairs.keypair_update_lock));
++	if (keypair)
++		keypair->sending.is_valid = false;
++	spin_unlock_bh(&peer->keypairs.keypair_update_lock);
++}
++
++static void add_new_keypair(struct noise_keypairs *keypairs,
++			    struct noise_keypair *new_keypair)
++{
++	struct noise_keypair *previous_keypair, *next_keypair, *current_keypair;
++
++	spin_lock_bh(&keypairs->keypair_update_lock);
++	previous_keypair = rcu_dereference_protected(keypairs->previous_keypair,
++		lockdep_is_held(&keypairs->keypair_update_lock));
++	next_keypair = rcu_dereference_protected(keypairs->next_keypair,
++		lockdep_is_held(&keypairs->keypair_update_lock));
++	current_keypair = rcu_dereference_protected(keypairs->current_keypair,
++		lockdep_is_held(&keypairs->keypair_update_lock));
++	if (new_keypair->i_am_the_initiator) {
++		/* If we're the initiator, it means we've sent a handshake, and
++		 * received a confirmation response, which means this new
++		 * keypair can now be used.
++		 */
++		if (next_keypair) {
++			/* If there already was a next keypair pending, we
++			 * demote it to be the previous keypair, and free the
++			 * existing current. Note that this means KCI can result
++			 * in this transition. It would perhaps be more sound to
++			 * always just get rid of the unused next keypair
++			 * instead of putting it in the previous slot, but this
++			 * might be a bit less robust. Something to think about
++			 * for the future.
++			 */
++			RCU_INIT_POINTER(keypairs->next_keypair, NULL);
++			rcu_assign_pointer(keypairs->previous_keypair,
++					   next_keypair);
++			wg_noise_keypair_put(current_keypair, true);
++		} else /* If there wasn't an existing next keypair, we replace
++			* the previous with the current one.
++			*/
++			rcu_assign_pointer(keypairs->previous_keypair,
++					   current_keypair);
++		/* At this point we can get rid of the old previous keypair, and
++		 * set up the new keypair.
++		 */
++		wg_noise_keypair_put(previous_keypair, true);
++		rcu_assign_pointer(keypairs->current_keypair, new_keypair);
++	} else {
++		/* If we're the responder, it means we can't use the new keypair
++		 * until we receive confirmation via the first data packet, so
++		 * we get rid of the existing previous one, the possibly
++		 * existing next one, and slide in the new next one.
++		 */
++		rcu_assign_pointer(keypairs->next_keypair, new_keypair);
++		wg_noise_keypair_put(next_keypair, true);
++		RCU_INIT_POINTER(keypairs->previous_keypair, NULL);
++		wg_noise_keypair_put(previous_keypair, true);
++	}
++	spin_unlock_bh(&keypairs->keypair_update_lock);
++}
++
++bool wg_noise_received_with_keypair(struct noise_keypairs *keypairs,
++				    struct noise_keypair *received_keypair)
++{
++	struct noise_keypair *old_keypair;
++	bool key_is_new;
++
++	/* We first check without taking the spinlock. */
++	key_is_new = received_keypair ==
++		     rcu_access_pointer(keypairs->next_keypair);
++	if (likely(!key_is_new))
++		return false;
++
++	spin_lock_bh(&keypairs->keypair_update_lock);
++	/* After locking, we double check that things didn't change from
++	 * beneath us.
++	 */
++	if (unlikely(received_keypair !=
++		    rcu_dereference_protected(keypairs->next_keypair,
++			    lockdep_is_held(&keypairs->keypair_update_lock)))) {
++		spin_unlock_bh(&keypairs->keypair_update_lock);
++		return false;
++	}
++
++	/* When we've finally received the confirmation, we slide the next
++	 * into the current, the current into the previous, and get rid of
++	 * the old previous.
++	 */
++	old_keypair = rcu_dereference_protected(keypairs->previous_keypair,
++		lockdep_is_held(&keypairs->keypair_update_lock));
++	rcu_assign_pointer(keypairs->previous_keypair,
++		rcu_dereference_protected(keypairs->current_keypair,
++			lockdep_is_held(&keypairs->keypair_update_lock)));
++	wg_noise_keypair_put(old_keypair, true);
++	rcu_assign_pointer(keypairs->current_keypair, received_keypair);
++	RCU_INIT_POINTER(keypairs->next_keypair, NULL);
++
++	spin_unlock_bh(&keypairs->keypair_update_lock);
++	return true;
++}
++
++/* Must hold static_identity->lock */
++void wg_noise_set_static_identity_private_key(
++	struct noise_static_identity *static_identity,
++	const u8 private_key[NOISE_PUBLIC_KEY_LEN])
++{
++	memcpy(static_identity->static_private, private_key,
++	       NOISE_PUBLIC_KEY_LEN);
++	curve25519_clamp_secret(static_identity->static_private);
++	static_identity->has_identity = curve25519_generate_public(
++		static_identity->static_public, private_key);
++}
++
++/* This is Hugo Krawczyk's HKDF:
++ *  - https://eprint.iacr.org/2010/264.pdf
++ *  - https://tools.ietf.org/html/rfc5869
++ */
++static void kdf(u8 *first_dst, u8 *second_dst, u8 *third_dst, const u8 *data,
++		size_t first_len, size_t second_len, size_t third_len,
++		size_t data_len, const u8 chaining_key[NOISE_HASH_LEN])
++{
++	u8 output[BLAKE2S_HASH_SIZE + 1];
++	u8 secret[BLAKE2S_HASH_SIZE];
++
++	WARN_ON(IS_ENABLED(DEBUG) &&
++		(first_len > BLAKE2S_HASH_SIZE ||
++		 second_len > BLAKE2S_HASH_SIZE ||
++		 third_len > BLAKE2S_HASH_SIZE ||
++		 ((second_len || second_dst || third_len || third_dst) &&
++		  (!first_len || !first_dst)) ||
++		 ((third_len || third_dst) && (!second_len || !second_dst))));
++
++	/* Extract entropy from data into secret */
++	blake2s256_hmac(secret, data, chaining_key, data_len, NOISE_HASH_LEN);
++
++	if (!first_dst || !first_len)
++		goto out;
++
++	/* Expand first key: key = secret, data = 0x1 */
++	output[0] = 1;
++	blake2s256_hmac(output, output, secret, 1, BLAKE2S_HASH_SIZE);
++	memcpy(first_dst, output, first_len);
++
++	if (!second_dst || !second_len)
++		goto out;
++
++	/* Expand second key: key = secret, data = first-key || 0x2 */
++	output[BLAKE2S_HASH_SIZE] = 2;
++	blake2s256_hmac(output, output, secret, BLAKE2S_HASH_SIZE + 1,
++			BLAKE2S_HASH_SIZE);
++	memcpy(second_dst, output, second_len);
++
++	if (!third_dst || !third_len)
++		goto out;
++
++	/* Expand third key: key = secret, data = second-key || 0x3 */
++	output[BLAKE2S_HASH_SIZE] = 3;
++	blake2s256_hmac(output, output, secret, BLAKE2S_HASH_SIZE + 1,
++			BLAKE2S_HASH_SIZE);
++	memcpy(third_dst, output, third_len);
++
++out:
++	/* Clear sensitive data from stack */
++	memzero_explicit(secret, BLAKE2S_HASH_SIZE);
++	memzero_explicit(output, BLAKE2S_HASH_SIZE + 1);
++}
++
++static void symmetric_key_init(struct noise_symmetric_key *key)
++{
++	spin_lock_init(&key->counter.receive.lock);
++	atomic64_set(&key->counter.counter, 0);
++	memset(key->counter.receive.backtrack, 0,
++	       sizeof(key->counter.receive.backtrack));
++	key->birthdate = ktime_get_coarse_boottime_ns();
++	key->is_valid = true;
++}
++
++static void derive_keys(struct noise_symmetric_key *first_dst,
++			struct noise_symmetric_key *second_dst,
++			const u8 chaining_key[NOISE_HASH_LEN])
++{
++	kdf(first_dst->key, second_dst->key, NULL, NULL,
++	    NOISE_SYMMETRIC_KEY_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, 0,
++	    chaining_key);
++	symmetric_key_init(first_dst);
++	symmetric_key_init(second_dst);
++}
++
++static bool __must_check mix_dh(u8 chaining_key[NOISE_HASH_LEN],
++				u8 key[NOISE_SYMMETRIC_KEY_LEN],
++				const u8 private[NOISE_PUBLIC_KEY_LEN],
++				const u8 public[NOISE_PUBLIC_KEY_LEN])
++{
++	u8 dh_calculation[NOISE_PUBLIC_KEY_LEN];
++
++	if (unlikely(!curve25519(dh_calculation, private, public)))
++		return false;
++	kdf(chaining_key, key, NULL, dh_calculation, NOISE_HASH_LEN,
++	    NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN, chaining_key);
++	memzero_explicit(dh_calculation, NOISE_PUBLIC_KEY_LEN);
++	return true;
++}
++
++static void mix_hash(u8 hash[NOISE_HASH_LEN], const u8 *src, size_t src_len)
++{
++	struct blake2s_state blake;
++
++	blake2s_init(&blake, NOISE_HASH_LEN);
++	blake2s_update(&blake, hash, NOISE_HASH_LEN);
++	blake2s_update(&blake, src, src_len);
++	blake2s_final(&blake, hash);
++}
++
++static void mix_psk(u8 chaining_key[NOISE_HASH_LEN], u8 hash[NOISE_HASH_LEN],
++		    u8 key[NOISE_SYMMETRIC_KEY_LEN],
++		    const u8 psk[NOISE_SYMMETRIC_KEY_LEN])
++{
++	u8 temp_hash[NOISE_HASH_LEN];
++
++	kdf(chaining_key, temp_hash, key, psk, NOISE_HASH_LEN, NOISE_HASH_LEN,
++	    NOISE_SYMMETRIC_KEY_LEN, NOISE_SYMMETRIC_KEY_LEN, chaining_key);
++	mix_hash(hash, temp_hash, NOISE_HASH_LEN);
++	memzero_explicit(temp_hash, NOISE_HASH_LEN);
++}
++
++static void handshake_init(u8 chaining_key[NOISE_HASH_LEN],
++			   u8 hash[NOISE_HASH_LEN],
++			   const u8 remote_static[NOISE_PUBLIC_KEY_LEN])
++{
++	memcpy(hash, handshake_init_hash, NOISE_HASH_LEN);
++	memcpy(chaining_key, handshake_init_chaining_key, NOISE_HASH_LEN);
++	mix_hash(hash, remote_static, NOISE_PUBLIC_KEY_LEN);
++}
++
++static void message_encrypt(u8 *dst_ciphertext, const u8 *src_plaintext,
++			    size_t src_len, u8 key[NOISE_SYMMETRIC_KEY_LEN],
++			    u8 hash[NOISE_HASH_LEN])
++{
++	chacha20poly1305_encrypt(dst_ciphertext, src_plaintext, src_len, hash,
++				 NOISE_HASH_LEN,
++				 0 /* Always zero for Noise_IK */, key);
++	mix_hash(hash, dst_ciphertext, noise_encrypted_len(src_len));
++}
++
++static bool message_decrypt(u8 *dst_plaintext, const u8 *src_ciphertext,
++			    size_t src_len, u8 key[NOISE_SYMMETRIC_KEY_LEN],
++			    u8 hash[NOISE_HASH_LEN])
++{
++	if (!chacha20poly1305_decrypt(dst_plaintext, src_ciphertext, src_len,
++				      hash, NOISE_HASH_LEN,
++				      0 /* Always zero for Noise_IK */, key))
++		return false;
++	mix_hash(hash, src_ciphertext, src_len);
++	return true;
++}
++
++static void message_ephemeral(u8 ephemeral_dst[NOISE_PUBLIC_KEY_LEN],
++			      const u8 ephemeral_src[NOISE_PUBLIC_KEY_LEN],
++			      u8 chaining_key[NOISE_HASH_LEN],
++			      u8 hash[NOISE_HASH_LEN])
++{
++	if (ephemeral_dst != ephemeral_src)
++		memcpy(ephemeral_dst, ephemeral_src, NOISE_PUBLIC_KEY_LEN);
++	mix_hash(hash, ephemeral_src, NOISE_PUBLIC_KEY_LEN);
++	kdf(chaining_key, NULL, NULL, ephemeral_src, NOISE_HASH_LEN, 0, 0,
++	    NOISE_PUBLIC_KEY_LEN, chaining_key);
++}
++
++static void tai64n_now(u8 output[NOISE_TIMESTAMP_LEN])
++{
++	struct timespec64 now;
++
++	ktime_get_real_ts64(&now);
++
++	/* In order to prevent some sort of infoleak from precise timers, we
++	 * round down the nanoseconds part to the closest rounded-down power of
++	 * two to the maximum initiations per second allowed anyway by the
++	 * implementation.
++	 */
++	now.tv_nsec = ALIGN_DOWN(now.tv_nsec,
++		rounddown_pow_of_two(NSEC_PER_SEC / INITIATIONS_PER_SECOND));
++
++	/* https://cr.yp.to/libtai/tai64.html */
++	*(__be64 *)output = cpu_to_be64(0x400000000000000aULL + now.tv_sec);
++	*(__be32 *)(output + sizeof(__be64)) = cpu_to_be32(now.tv_nsec);
++}
++
++bool
++wg_noise_handshake_create_initiation(struct message_handshake_initiation *dst,
++				     struct noise_handshake *handshake)
++{
++	u8 timestamp[NOISE_TIMESTAMP_LEN];
++	u8 key[NOISE_SYMMETRIC_KEY_LEN];
++	bool ret = false;
++
++	/* We need to wait for crng _before_ taking any locks, since
++	 * curve25519_generate_secret uses get_random_bytes_wait.
++	 */
++	wait_for_random_bytes();
++
++	down_read(&handshake->static_identity->lock);
++	down_write(&handshake->lock);
++
++	if (unlikely(!handshake->static_identity->has_identity))
++		goto out;
++
++	dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION);
++
++	handshake_init(handshake->chaining_key, handshake->hash,
++		       handshake->remote_static);
++
++	/* e */
++	curve25519_generate_secret(handshake->ephemeral_private);
++	if (!curve25519_generate_public(dst->unencrypted_ephemeral,
++					handshake->ephemeral_private))
++		goto out;
++	message_ephemeral(dst->unencrypted_ephemeral,
++			  dst->unencrypted_ephemeral, handshake->chaining_key,
++			  handshake->hash);
++
++	/* es */
++	if (!mix_dh(handshake->chaining_key, key, handshake->ephemeral_private,
++		    handshake->remote_static))
++		goto out;
++
++	/* s */
++	message_encrypt(dst->encrypted_static,
++			handshake->static_identity->static_public,
++			NOISE_PUBLIC_KEY_LEN, key, handshake->hash);
++
++	/* ss */
++	kdf(handshake->chaining_key, key, NULL,
++	    handshake->precomputed_static_static, NOISE_HASH_LEN,
++	    NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN,
++	    handshake->chaining_key);
++
++	/* {t} */
++	tai64n_now(timestamp);
++	message_encrypt(dst->encrypted_timestamp, timestamp,
++			NOISE_TIMESTAMP_LEN, key, handshake->hash);
++
++	dst->sender_index = wg_index_hashtable_insert(
++		handshake->entry.peer->device->index_hashtable,
++		&handshake->entry);
++
++	handshake->state = HANDSHAKE_CREATED_INITIATION;
++	ret = true;
++
++out:
++	up_write(&handshake->lock);
++	up_read(&handshake->static_identity->lock);
++	memzero_explicit(key, NOISE_SYMMETRIC_KEY_LEN);
++	return ret;
++}
++
++struct wg_peer *
++wg_noise_handshake_consume_initiation(struct message_handshake_initiation *src,
++				      struct wg_device *wg)
++{
++	struct wg_peer *peer = NULL, *ret_peer = NULL;
++	struct noise_handshake *handshake;
++	bool replay_attack, flood_attack;
++	u8 key[NOISE_SYMMETRIC_KEY_LEN];
++	u8 chaining_key[NOISE_HASH_LEN];
++	u8 hash[NOISE_HASH_LEN];
++	u8 s[NOISE_PUBLIC_KEY_LEN];
++	u8 e[NOISE_PUBLIC_KEY_LEN];
++	u8 t[NOISE_TIMESTAMP_LEN];
++	u64 initiation_consumption;
++
++	down_read(&wg->static_identity.lock);
++	if (unlikely(!wg->static_identity.has_identity))
++		goto out;
++
++	handshake_init(chaining_key, hash, wg->static_identity.static_public);
++
++	/* e */
++	message_ephemeral(e, src->unencrypted_ephemeral, chaining_key, hash);
++
++	/* es */
++	if (!mix_dh(chaining_key, key, wg->static_identity.static_private, e))
++		goto out;
++
++	/* s */
++	if (!message_decrypt(s, src->encrypted_static,
++			     sizeof(src->encrypted_static), key, hash))
++		goto out;
++
++	/* Lookup which peer we're actually talking to */
++	peer = wg_pubkey_hashtable_lookup(wg->peer_hashtable, s);
++	if (!peer)
++		goto out;
++	handshake = &peer->handshake;
++
++	/* ss */
++	kdf(chaining_key, key, NULL, handshake->precomputed_static_static,
++	    NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN,
++	    chaining_key);
++
++	/* {t} */
++	if (!message_decrypt(t, src->encrypted_timestamp,
++			     sizeof(src->encrypted_timestamp), key, hash))
++		goto out;
++
++	down_read(&handshake->lock);
++	replay_attack = memcmp(t, handshake->latest_timestamp,
++			       NOISE_TIMESTAMP_LEN) <= 0;
++	flood_attack = (s64)handshake->last_initiation_consumption +
++			       NSEC_PER_SEC / INITIATIONS_PER_SECOND >
++		       (s64)ktime_get_coarse_boottime_ns();
++	up_read(&handshake->lock);
++	if (replay_attack || flood_attack)
++		goto out;
++
++	/* Success! Copy everything to peer */
++	down_write(&handshake->lock);
++	memcpy(handshake->remote_ephemeral, e, NOISE_PUBLIC_KEY_LEN);
++	if (memcmp(t, handshake->latest_timestamp, NOISE_TIMESTAMP_LEN) > 0)
++		memcpy(handshake->latest_timestamp, t, NOISE_TIMESTAMP_LEN);
++	memcpy(handshake->hash, hash, NOISE_HASH_LEN);
++	memcpy(handshake->chaining_key, chaining_key, NOISE_HASH_LEN);
++	handshake->remote_index = src->sender_index;
++	if ((s64)(handshake->last_initiation_consumption -
++	    (initiation_consumption = ktime_get_coarse_boottime_ns())) < 0)
++		handshake->last_initiation_consumption = initiation_consumption;
++	handshake->state = HANDSHAKE_CONSUMED_INITIATION;
++	up_write(&handshake->lock);
++	ret_peer = peer;
++
++out:
++	memzero_explicit(key, NOISE_SYMMETRIC_KEY_LEN);
++	memzero_explicit(hash, NOISE_HASH_LEN);
++	memzero_explicit(chaining_key, NOISE_HASH_LEN);
++	up_read(&wg->static_identity.lock);
++	if (!ret_peer)
++		wg_peer_put(peer);
++	return ret_peer;
++}
++
++bool wg_noise_handshake_create_response(struct message_handshake_response *dst,
++					struct noise_handshake *handshake)
++{
++	u8 key[NOISE_SYMMETRIC_KEY_LEN];
++	bool ret = false;
++
++	/* We need to wait for crng _before_ taking any locks, since
++	 * curve25519_generate_secret uses get_random_bytes_wait.
++	 */
++	wait_for_random_bytes();
++
++	down_read(&handshake->static_identity->lock);
++	down_write(&handshake->lock);
++
++	if (handshake->state != HANDSHAKE_CONSUMED_INITIATION)
++		goto out;
++
++	dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE);
++	dst->receiver_index = handshake->remote_index;
++
++	/* e */
++	curve25519_generate_secret(handshake->ephemeral_private);
++	if (!curve25519_generate_public(dst->unencrypted_ephemeral,
++					handshake->ephemeral_private))
++		goto out;
++	message_ephemeral(dst->unencrypted_ephemeral,
++			  dst->unencrypted_ephemeral, handshake->chaining_key,
++			  handshake->hash);
++
++	/* ee */
++	if (!mix_dh(handshake->chaining_key, NULL, handshake->ephemeral_private,
++		    handshake->remote_ephemeral))
++		goto out;
++
++	/* se */
++	if (!mix_dh(handshake->chaining_key, NULL, handshake->ephemeral_private,
++		    handshake->remote_static))
++		goto out;
++
++	/* psk */
++	mix_psk(handshake->chaining_key, handshake->hash, key,
++		handshake->preshared_key);
++
++	/* {} */
++	message_encrypt(dst->encrypted_nothing, NULL, 0, key, handshake->hash);
++
++	dst->sender_index = wg_index_hashtable_insert(
++		handshake->entry.peer->device->index_hashtable,
++		&handshake->entry);
++
++	handshake->state = HANDSHAKE_CREATED_RESPONSE;
++	ret = true;
++
++out:
++	up_write(&handshake->lock);
++	up_read(&handshake->static_identity->lock);
++	memzero_explicit(key, NOISE_SYMMETRIC_KEY_LEN);
++	return ret;
++}
++
++struct wg_peer *
++wg_noise_handshake_consume_response(struct message_handshake_response *src,
++				    struct wg_device *wg)
++{
++	enum noise_handshake_state state = HANDSHAKE_ZEROED;
++	struct wg_peer *peer = NULL, *ret_peer = NULL;
++	struct noise_handshake *handshake;
++	u8 key[NOISE_SYMMETRIC_KEY_LEN];
++	u8 hash[NOISE_HASH_LEN];
++	u8 chaining_key[NOISE_HASH_LEN];
++	u8 e[NOISE_PUBLIC_KEY_LEN];
++	u8 ephemeral_private[NOISE_PUBLIC_KEY_LEN];
++	u8 static_private[NOISE_PUBLIC_KEY_LEN];
++
++	down_read(&wg->static_identity.lock);
++
++	if (unlikely(!wg->static_identity.has_identity))
++		goto out;
++
++	handshake = (struct noise_handshake *)wg_index_hashtable_lookup(
++		wg->index_hashtable, INDEX_HASHTABLE_HANDSHAKE,
++		src->receiver_index, &peer);
++	if (unlikely(!handshake))
++		goto out;
++
++	down_read(&handshake->lock);
++	state = handshake->state;
++	memcpy(hash, handshake->hash, NOISE_HASH_LEN);
++	memcpy(chaining_key, handshake->chaining_key, NOISE_HASH_LEN);
++	memcpy(ephemeral_private, handshake->ephemeral_private,
++	       NOISE_PUBLIC_KEY_LEN);
++	up_read(&handshake->lock);
++
++	if (state != HANDSHAKE_CREATED_INITIATION)
++		goto fail;
++
++	/* e */
++	message_ephemeral(e, src->unencrypted_ephemeral, chaining_key, hash);
++
++	/* ee */
++	if (!mix_dh(chaining_key, NULL, ephemeral_private, e))
++		goto fail;
++
++	/* se */
++	if (!mix_dh(chaining_key, NULL, wg->static_identity.static_private, e))
++		goto fail;
++
++	/* psk */
++	mix_psk(chaining_key, hash, key, handshake->preshared_key);
++
++	/* {} */
++	if (!message_decrypt(NULL, src->encrypted_nothing,
++			     sizeof(src->encrypted_nothing), key, hash))
++		goto fail;
++
++	/* Success! Copy everything to peer */
++	down_write(&handshake->lock);
++	/* It's important to check that the state is still the same, while we
++	 * have an exclusive lock.
++	 */
++	if (handshake->state != state) {
++		up_write(&handshake->lock);
++		goto fail;
++	}
++	memcpy(handshake->remote_ephemeral, e, NOISE_PUBLIC_KEY_LEN);
++	memcpy(handshake->hash, hash, NOISE_HASH_LEN);
++	memcpy(handshake->chaining_key, chaining_key, NOISE_HASH_LEN);
++	handshake->remote_index = src->sender_index;
++	handshake->state = HANDSHAKE_CONSUMED_RESPONSE;
++	up_write(&handshake->lock);
++	ret_peer = peer;
++	goto out;
++
++fail:
++	wg_peer_put(peer);
++out:
++	memzero_explicit(key, NOISE_SYMMETRIC_KEY_LEN);
++	memzero_explicit(hash, NOISE_HASH_LEN);
++	memzero_explicit(chaining_key, NOISE_HASH_LEN);
++	memzero_explicit(ephemeral_private, NOISE_PUBLIC_KEY_LEN);
++	memzero_explicit(static_private, NOISE_PUBLIC_KEY_LEN);
++	up_read(&wg->static_identity.lock);
++	return ret_peer;
++}
++
++bool wg_noise_handshake_begin_session(struct noise_handshake *handshake,
++				      struct noise_keypairs *keypairs)
++{
++	struct noise_keypair *new_keypair;
++	bool ret = false;
++
++	down_write(&handshake->lock);
++	if (handshake->state != HANDSHAKE_CREATED_RESPONSE &&
++	    handshake->state != HANDSHAKE_CONSUMED_RESPONSE)
++		goto out;
++
++	new_keypair = keypair_create(handshake->entry.peer);
++	if (!new_keypair)
++		goto out;
++	new_keypair->i_am_the_initiator = handshake->state ==
++					  HANDSHAKE_CONSUMED_RESPONSE;
++	new_keypair->remote_index = handshake->remote_index;
++
++	if (new_keypair->i_am_the_initiator)
++		derive_keys(&new_keypair->sending, &new_keypair->receiving,
++			    handshake->chaining_key);
++	else
++		derive_keys(&new_keypair->receiving, &new_keypair->sending,
++			    handshake->chaining_key);
++
++	handshake_zero(handshake);
++	rcu_read_lock_bh();
++	if (likely(!READ_ONCE(container_of(handshake, struct wg_peer,
++					   handshake)->is_dead))) {
++		add_new_keypair(keypairs, new_keypair);
++		net_dbg_ratelimited("%s: Keypair %llu created for peer %llu\n",
++				    handshake->entry.peer->device->dev->name,
++				    new_keypair->internal_id,
++				    handshake->entry.peer->internal_id);
++		ret = wg_index_hashtable_replace(
++			handshake->entry.peer->device->index_hashtable,
++			&handshake->entry, &new_keypair->entry);
++	} else {
++		kzfree(new_keypair);
++	}
++	rcu_read_unlock_bh();
++
++out:
++	up_write(&handshake->lock);
++	return ret;
++}
+--- /dev/null
++++ b/drivers/net/wireguard/noise.h
+@@ -0,0 +1,137 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++#ifndef _WG_NOISE_H
++#define _WG_NOISE_H
++
++#include "messages.h"
++#include "peerlookup.h"
++
++#include <linux/types.h>
++#include <linux/spinlock.h>
++#include <linux/atomic.h>
++#include <linux/rwsem.h>
++#include <linux/mutex.h>
++#include <linux/kref.h>
++
++union noise_counter {
++	struct {
++		u64 counter;
++		unsigned long backtrack[COUNTER_BITS_TOTAL / BITS_PER_LONG];
++		spinlock_t lock;
++	} receive;
++	atomic64_t counter;
++};
++
++struct noise_symmetric_key {
++	u8 key[NOISE_SYMMETRIC_KEY_LEN];
++	union noise_counter counter;
++	u64 birthdate;
++	bool is_valid;
++};
++
++struct noise_keypair {
++	struct index_hashtable_entry entry;
++	struct noise_symmetric_key sending;
++	struct noise_symmetric_key receiving;
++	__le32 remote_index;
++	bool i_am_the_initiator;
++	struct kref refcount;
++	struct rcu_head rcu;
++	u64 internal_id;
++};
++
++struct noise_keypairs {
++	struct noise_keypair __rcu *current_keypair;
++	struct noise_keypair __rcu *previous_keypair;
++	struct noise_keypair __rcu *next_keypair;
++	spinlock_t keypair_update_lock;
++};
++
++struct noise_static_identity {
++	u8 static_public[NOISE_PUBLIC_KEY_LEN];
++	u8 static_private[NOISE_PUBLIC_KEY_LEN];
++	struct rw_semaphore lock;
++	bool has_identity;
++};
++
++enum noise_handshake_state {
++	HANDSHAKE_ZEROED,
++	HANDSHAKE_CREATED_INITIATION,
++	HANDSHAKE_CONSUMED_INITIATION,
++	HANDSHAKE_CREATED_RESPONSE,
++	HANDSHAKE_CONSUMED_RESPONSE
++};
++
++struct noise_handshake {
++	struct index_hashtable_entry entry;
++
++	enum noise_handshake_state state;
++	u64 last_initiation_consumption;
++
++	struct noise_static_identity *static_identity;
++
++	u8 ephemeral_private[NOISE_PUBLIC_KEY_LEN];
++	u8 remote_static[NOISE_PUBLIC_KEY_LEN];
++	u8 remote_ephemeral[NOISE_PUBLIC_KEY_LEN];
++	u8 precomputed_static_static[NOISE_PUBLIC_KEY_LEN];
++
++	u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN];
++
++	u8 hash[NOISE_HASH_LEN];
++	u8 chaining_key[NOISE_HASH_LEN];
++
++	u8 latest_timestamp[NOISE_TIMESTAMP_LEN];
++	__le32 remote_index;
++
++	/* Protects all members except the immutable (after noise_handshake_
++	 * init): remote_static, precomputed_static_static, static_identity.
++	 */
++	struct rw_semaphore lock;
++};
++
++struct wg_device;
++
++void wg_noise_init(void);
++bool wg_noise_handshake_init(struct noise_handshake *handshake,
++			   struct noise_static_identity *static_identity,
++			   const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN],
++			   const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN],
++			   struct wg_peer *peer);
++void wg_noise_handshake_clear(struct noise_handshake *handshake);
++static inline void wg_noise_reset_last_sent_handshake(atomic64_t *handshake_ns)
++{
++	atomic64_set(handshake_ns, ktime_get_coarse_boottime_ns() -
++				       (u64)(REKEY_TIMEOUT + 1) * NSEC_PER_SEC);
++}
++
++void wg_noise_keypair_put(struct noise_keypair *keypair, bool unreference_now);
++struct noise_keypair *wg_noise_keypair_get(struct noise_keypair *keypair);
++void wg_noise_keypairs_clear(struct noise_keypairs *keypairs);
++bool wg_noise_received_with_keypair(struct noise_keypairs *keypairs,
++				    struct noise_keypair *received_keypair);
++void wg_noise_expire_current_peer_keypairs(struct wg_peer *peer);
++
++void wg_noise_set_static_identity_private_key(
++	struct noise_static_identity *static_identity,
++	const u8 private_key[NOISE_PUBLIC_KEY_LEN]);
++bool wg_noise_precompute_static_static(struct wg_peer *peer);
++
++bool
++wg_noise_handshake_create_initiation(struct message_handshake_initiation *dst,
++				     struct noise_handshake *handshake);
++struct wg_peer *
++wg_noise_handshake_consume_initiation(struct message_handshake_initiation *src,
++				      struct wg_device *wg);
++
++bool wg_noise_handshake_create_response(struct message_handshake_response *dst,
++					struct noise_handshake *handshake);
++struct wg_peer *
++wg_noise_handshake_consume_response(struct message_handshake_response *src,
++				    struct wg_device *wg);
++
++bool wg_noise_handshake_begin_session(struct noise_handshake *handshake,
++				      struct noise_keypairs *keypairs);
++
++#endif /* _WG_NOISE_H */
+--- /dev/null
++++ b/drivers/net/wireguard/peer.c
+@@ -0,0 +1,240 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#include "peer.h"
++#include "device.h"
++#include "queueing.h"
++#include "timers.h"
++#include "peerlookup.h"
++#include "noise.h"
++
++#include <linux/kref.h>
++#include <linux/lockdep.h>
++#include <linux/rcupdate.h>
++#include <linux/list.h>
++
++static atomic64_t peer_counter = ATOMIC64_INIT(0);
++
++struct wg_peer *wg_peer_create(struct wg_device *wg,
++			       const u8 public_key[NOISE_PUBLIC_KEY_LEN],
++			       const u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN])
++{
++	struct wg_peer *peer;
++	int ret = -ENOMEM;
++
++	lockdep_assert_held(&wg->device_update_lock);
++
++	if (wg->num_peers >= MAX_PEERS_PER_DEVICE)
++		return ERR_PTR(ret);
++
++	peer = kzalloc(sizeof(*peer), GFP_KERNEL);
++	if (unlikely(!peer))
++		return ERR_PTR(ret);
++	peer->device = wg;
++
++	if (!wg_noise_handshake_init(&peer->handshake, &wg->static_identity,
++				     public_key, preshared_key, peer)) {
++		ret = -EKEYREJECTED;
++		goto err_1;
++	}
++	if (dst_cache_init(&peer->endpoint_cache, GFP_KERNEL))
++		goto err_1;
++	if (wg_packet_queue_init(&peer->tx_queue, wg_packet_tx_worker, false,
++				 MAX_QUEUED_PACKETS))
++		goto err_2;
++	if (wg_packet_queue_init(&peer->rx_queue, NULL, false,
++				 MAX_QUEUED_PACKETS))
++		goto err_3;
++
++	peer->internal_id = atomic64_inc_return(&peer_counter);
++	peer->serial_work_cpu = nr_cpumask_bits;
++	wg_cookie_init(&peer->latest_cookie);
++	wg_timers_init(peer);
++	wg_cookie_checker_precompute_peer_keys(peer);
++	spin_lock_init(&peer->keypairs.keypair_update_lock);
++	INIT_WORK(&peer->transmit_handshake_work,
++		  wg_packet_handshake_send_worker);
++	rwlock_init(&peer->endpoint_lock);
++	kref_init(&peer->refcount);
++	skb_queue_head_init(&peer->staged_packet_queue);
++	wg_noise_reset_last_sent_handshake(&peer->last_sent_handshake);
++	set_bit(NAPI_STATE_NO_BUSY_POLL, &peer->napi.state);
++	netif_napi_add(wg->dev, &peer->napi, wg_packet_rx_poll,
++		       NAPI_POLL_WEIGHT);
++	napi_enable(&peer->napi);
++	list_add_tail(&peer->peer_list, &wg->peer_list);
++	INIT_LIST_HEAD(&peer->allowedips_list);
++	wg_pubkey_hashtable_add(wg->peer_hashtable, peer);
++	++wg->num_peers;
++	pr_debug("%s: Peer %llu created\n", wg->dev->name, peer->internal_id);
++	return peer;
++
++err_3:
++	wg_packet_queue_free(&peer->tx_queue, false);
++err_2:
++	dst_cache_destroy(&peer->endpoint_cache);
++err_1:
++	kfree(peer);
++	return ERR_PTR(ret);
++}
++
++struct wg_peer *wg_peer_get_maybe_zero(struct wg_peer *peer)
++{
++	RCU_LOCKDEP_WARN(!rcu_read_lock_bh_held(),
++			 "Taking peer reference without holding the RCU read lock");
++	if (unlikely(!peer || !kref_get_unless_zero(&peer->refcount)))
++		return NULL;
++	return peer;
++}
++
++static void peer_make_dead(struct wg_peer *peer)
++{
++	/* Remove from configuration-time lookup structures. */
++	list_del_init(&peer->peer_list);
++	wg_allowedips_remove_by_peer(&peer->device->peer_allowedips, peer,
++				     &peer->device->device_update_lock);
++	wg_pubkey_hashtable_remove(peer->device->peer_hashtable, peer);
++
++	/* Mark as dead, so that we don't allow jumping contexts after. */
++	WRITE_ONCE(peer->is_dead, true);
++
++	/* The caller must now synchronize_rcu() for this to take effect. */
++}
++
++static void peer_remove_after_dead(struct wg_peer *peer)
++{
++	WARN_ON(!peer->is_dead);
++
++	/* No more keypairs can be created for this peer, since is_dead protects
++	 * add_new_keypair, so we can now destroy existing ones.
++	 */
++	wg_noise_keypairs_clear(&peer->keypairs);
++
++	/* Destroy all ongoing timers that were in-flight at the beginning of
++	 * this function.
++	 */
++	wg_timers_stop(peer);
++
++	/* The transition between packet encryption/decryption queues isn't
++	 * guarded by is_dead, but each reference's life is strictly bounded by
++	 * two generations: once for parallel crypto and once for serial
++	 * ingestion, so we can simply flush twice, and be sure that we no
++	 * longer have references inside these queues.
++	 */
++
++	/* a) For encrypt/decrypt. */
++	flush_workqueue(peer->device->packet_crypt_wq);
++	/* b.1) For send (but not receive, since that's napi). */
++	flush_workqueue(peer->device->packet_crypt_wq);
++	/* b.2.1) For receive (but not send, since that's wq). */
++	napi_disable(&peer->napi);
++	/* b.2.1) It's now safe to remove the napi struct, which must be done
++	 * here from process context.
++	 */
++	netif_napi_del(&peer->napi);
++
++	/* Ensure any workstructs we own (like transmit_handshake_work or
++	 * clear_peer_work) no longer are in use.
++	 */
++	flush_workqueue(peer->device->handshake_send_wq);
++
++	/* After the above flushes, a peer might still be active in a few
++	 * different contexts: 1) from xmit(), before hitting is_dead and
++	 * returning, 2) from wg_packet_consume_data(), before hitting is_dead
++	 * and returning, 3) from wg_receive_handshake_packet() after a point
++	 * where it has processed an incoming handshake packet, but where
++	 * all calls to pass it off to timers fails because of is_dead. We won't
++	 * have new references in (1) eventually, because we're removed from
++	 * allowedips; we won't have new references in (2) eventually, because
++	 * wg_index_hashtable_lookup will always return NULL, since we removed
++	 * all existing keypairs and no more can be created; we won't have new
++	 * references in (3) eventually, because we're removed from the pubkey
++	 * hash table, which allows for a maximum of one handshake response,
++	 * via the still-uncleared index hashtable entry, but not more than one,
++	 * and in wg_cookie_message_consume, the lookup eventually gets a peer
++	 * with a refcount of zero, so no new reference is taken.
++	 */
++
++	--peer->device->num_peers;
++	wg_peer_put(peer);
++}
++
++/* We have a separate "remove" function make sure that all active places where
++ * a peer is currently operating will eventually come to an end and not pass
++ * their reference onto another context.
++ */
++void wg_peer_remove(struct wg_peer *peer)
++{
++	if (unlikely(!peer))
++		return;
++	lockdep_assert_held(&peer->device->device_update_lock);
++
++	peer_make_dead(peer);
++	synchronize_rcu();
++	peer_remove_after_dead(peer);
++}
++
++void wg_peer_remove_all(struct wg_device *wg)
++{
++	struct wg_peer *peer, *temp;
++	LIST_HEAD(dead_peers);
++
++	lockdep_assert_held(&wg->device_update_lock);
++
++	/* Avoid having to traverse individually for each one. */
++	wg_allowedips_free(&wg->peer_allowedips, &wg->device_update_lock);
++
++	list_for_each_entry_safe(peer, temp, &wg->peer_list, peer_list) {
++		peer_make_dead(peer);
++		list_add_tail(&peer->peer_list, &dead_peers);
++	}
++	synchronize_rcu();
++	list_for_each_entry_safe(peer, temp, &dead_peers, peer_list)
++		peer_remove_after_dead(peer);
++}
++
++static void rcu_release(struct rcu_head *rcu)
++{
++	struct wg_peer *peer = container_of(rcu, struct wg_peer, rcu);
++
++	dst_cache_destroy(&peer->endpoint_cache);
++	wg_packet_queue_free(&peer->rx_queue, false);
++	wg_packet_queue_free(&peer->tx_queue, false);
++
++	/* The final zeroing takes care of clearing any remaining handshake key
++	 * material and other potentially sensitive information.
++	 */
++	kzfree(peer);
++}
++
++static void kref_release(struct kref *refcount)
++{
++	struct wg_peer *peer = container_of(refcount, struct wg_peer, refcount);
++
++	pr_debug("%s: Peer %llu (%pISpfsc) destroyed\n",
++		 peer->device->dev->name, peer->internal_id,
++		 &peer->endpoint.addr);
++
++	/* Remove ourself from dynamic runtime lookup structures, now that the
++	 * last reference is gone.
++	 */
++	wg_index_hashtable_remove(peer->device->index_hashtable,
++				  &peer->handshake.entry);
++
++	/* Remove any lingering packets that didn't have a chance to be
++	 * transmitted.
++	 */
++	wg_packet_purge_staged_packets(peer);
++
++	/* Free the memory used. */
++	call_rcu(&peer->rcu, rcu_release);
++}
++
++void wg_peer_put(struct wg_peer *peer)
++{
++	if (unlikely(!peer))
++		return;
++	kref_put(&peer->refcount, kref_release);
++}
+--- /dev/null
++++ b/drivers/net/wireguard/peer.h
+@@ -0,0 +1,83 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#ifndef _WG_PEER_H
++#define _WG_PEER_H
++
++#include "device.h"
++#include "noise.h"
++#include "cookie.h"
++
++#include <linux/types.h>
++#include <linux/netfilter.h>
++#include <linux/spinlock.h>
++#include <linux/kref.h>
++#include <net/dst_cache.h>
++
++struct wg_device;
++
++struct endpoint {
++	union {
++		struct sockaddr addr;
++		struct sockaddr_in addr4;
++		struct sockaddr_in6 addr6;
++	};
++	union {
++		struct {
++			struct in_addr src4;
++			/* Essentially the same as addr6->scope_id */
++			int src_if4;
++		};
++		struct in6_addr src6;
++	};
++};
++
++struct wg_peer {
++	struct wg_device *device;
++	struct crypt_queue tx_queue, rx_queue;
++	struct sk_buff_head staged_packet_queue;
++	int serial_work_cpu;
++	struct noise_keypairs keypairs;
++	struct endpoint endpoint;
++	struct dst_cache endpoint_cache;
++	rwlock_t endpoint_lock;
++	struct noise_handshake handshake;
++	atomic64_t last_sent_handshake;
++	struct work_struct transmit_handshake_work, clear_peer_work;
++	struct cookie latest_cookie;
++	struct hlist_node pubkey_hash;
++	u64 rx_bytes, tx_bytes;
++	struct timer_list timer_retransmit_handshake, timer_send_keepalive;
++	struct timer_list timer_new_handshake, timer_zero_key_material;
++	struct timer_list timer_persistent_keepalive;
++	unsigned int timer_handshake_attempts;
++	u16 persistent_keepalive_interval;
++	bool timer_need_another_keepalive;
++	bool sent_lastminute_handshake;
++	struct timespec64 walltime_last_handshake;
++	struct kref refcount;
++	struct rcu_head rcu;
++	struct list_head peer_list;
++	struct list_head allowedips_list;
++	u64 internal_id;
++	struct napi_struct napi;
++	bool is_dead;
++};
++
++struct wg_peer *wg_peer_create(struct wg_device *wg,
++			       const u8 public_key[NOISE_PUBLIC_KEY_LEN],
++			       const u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN]);
++
++struct wg_peer *__must_check wg_peer_get_maybe_zero(struct wg_peer *peer);
++static inline struct wg_peer *wg_peer_get(struct wg_peer *peer)
++{
++	kref_get(&peer->refcount);
++	return peer;
++}
++void wg_peer_put(struct wg_peer *peer);
++void wg_peer_remove(struct wg_peer *peer);
++void wg_peer_remove_all(struct wg_device *wg);
++
++#endif /* _WG_PEER_H */
+--- /dev/null
++++ b/drivers/net/wireguard/peerlookup.c
+@@ -0,0 +1,221 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#include "peerlookup.h"
++#include "peer.h"
++#include "noise.h"
++
++static struct hlist_head *pubkey_bucket(struct pubkey_hashtable *table,
++					const u8 pubkey[NOISE_PUBLIC_KEY_LEN])
++{
++	/* siphash gives us a secure 64bit number based on a random key. Since
++	 * the bits are uniformly distributed, we can then mask off to get the
++	 * bits we need.
++	 */
++	const u64 hash = siphash(pubkey, NOISE_PUBLIC_KEY_LEN, &table->key);
++
++	return &table->hashtable[hash & (HASH_SIZE(table->hashtable) - 1)];
++}
++
++struct pubkey_hashtable *wg_pubkey_hashtable_alloc(void)
++{
++	struct pubkey_hashtable *table = kvmalloc(sizeof(*table), GFP_KERNEL);
++
++	if (!table)
++		return NULL;
++
++	get_random_bytes(&table->key, sizeof(table->key));
++	hash_init(table->hashtable);
++	mutex_init(&table->lock);
++	return table;
++}
++
++void wg_pubkey_hashtable_add(struct pubkey_hashtable *table,
++			     struct wg_peer *peer)
++{
++	mutex_lock(&table->lock);
++	hlist_add_head_rcu(&peer->pubkey_hash,
++			   pubkey_bucket(table, peer->handshake.remote_static));
++	mutex_unlock(&table->lock);
++}
++
++void wg_pubkey_hashtable_remove(struct pubkey_hashtable *table,
++				struct wg_peer *peer)
++{
++	mutex_lock(&table->lock);
++	hlist_del_init_rcu(&peer->pubkey_hash);
++	mutex_unlock(&table->lock);
++}
++
++/* Returns a strong reference to a peer */
++struct wg_peer *
++wg_pubkey_hashtable_lookup(struct pubkey_hashtable *table,
++			   const u8 pubkey[NOISE_PUBLIC_KEY_LEN])
++{
++	struct wg_peer *iter_peer, *peer = NULL;
++
++	rcu_read_lock_bh();
++	hlist_for_each_entry_rcu_bh(iter_peer, pubkey_bucket(table, pubkey),
++				    pubkey_hash) {
++		if (!memcmp(pubkey, iter_peer->handshake.remote_static,
++			    NOISE_PUBLIC_KEY_LEN)) {
++			peer = iter_peer;
++			break;
++		}
++	}
++	peer = wg_peer_get_maybe_zero(peer);
++	rcu_read_unlock_bh();
++	return peer;
++}
++
++static struct hlist_head *index_bucket(struct index_hashtable *table,
++				       const __le32 index)
++{
++	/* Since the indices are random and thus all bits are uniformly
++	 * distributed, we can find its bucket simply by masking.
++	 */
++	return &table->hashtable[(__force u32)index &
++				 (HASH_SIZE(table->hashtable) - 1)];
++}
++
++struct index_hashtable *wg_index_hashtable_alloc(void)
++{
++	struct index_hashtable *table = kvmalloc(sizeof(*table), GFP_KERNEL);
++
++	if (!table)
++		return NULL;
++
++	hash_init(table->hashtable);
++	spin_lock_init(&table->lock);
++	return table;
++}
++
++/* At the moment, we limit ourselves to 2^20 total peers, which generally might
++ * amount to 2^20*3 items in this hashtable. The algorithm below works by
++ * picking a random number and testing it. We can see that these limits mean we
++ * usually succeed pretty quickly:
++ *
++ * >>> def calculation(tries, size):
++ * ...     return (size / 2**32)**(tries - 1) *  (1 - (size / 2**32))
++ * ...
++ * >>> calculation(1, 2**20 * 3)
++ * 0.999267578125
++ * >>> calculation(2, 2**20 * 3)
++ * 0.0007318854331970215
++ * >>> calculation(3, 2**20 * 3)
++ * 5.360489012673497e-07
++ * >>> calculation(4, 2**20 * 3)
++ * 3.9261394135792216e-10
++ *
++ * At the moment, we don't do any masking, so this algorithm isn't exactly
++ * constant time in either the random guessing or in the hash list lookup. We
++ * could require a minimum of 3 tries, which would successfully mask the
++ * guessing. this would not, however, help with the growing hash lengths, which
++ * is another thing to consider moving forward.
++ */
++
++__le32 wg_index_hashtable_insert(struct index_hashtable *table,
++				 struct index_hashtable_entry *entry)
++{
++	struct index_hashtable_entry *existing_entry;
++
++	spin_lock_bh(&table->lock);
++	hlist_del_init_rcu(&entry->index_hash);
++	spin_unlock_bh(&table->lock);
++
++	rcu_read_lock_bh();
++
++search_unused_slot:
++	/* First we try to find an unused slot, randomly, while unlocked. */
++	entry->index = (__force __le32)get_random_u32();
++	hlist_for_each_entry_rcu_bh(existing_entry,
++				    index_bucket(table, entry->index),
++				    index_hash) {
++		if (existing_entry->index == entry->index)
++			/* If it's already in use, we continue searching. */
++			goto search_unused_slot;
++	}
++
++	/* Once we've found an unused slot, we lock it, and then double-check
++	 * that nobody else stole it from us.
++	 */
++	spin_lock_bh(&table->lock);
++	hlist_for_each_entry_rcu_bh(existing_entry,
++				    index_bucket(table, entry->index),
++				    index_hash) {
++		if (existing_entry->index == entry->index) {
++			spin_unlock_bh(&table->lock);
++			/* If it was stolen, we start over. */
++			goto search_unused_slot;
++		}
++	}
++	/* Otherwise, we know we have it exclusively (since we're locked),
++	 * so we insert.
++	 */
++	hlist_add_head_rcu(&entry->index_hash,
++			   index_bucket(table, entry->index));
++	spin_unlock_bh(&table->lock);
++
++	rcu_read_unlock_bh();
++
++	return entry->index;
++}
++
++bool wg_index_hashtable_replace(struct index_hashtable *table,
++				struct index_hashtable_entry *old,
++				struct index_hashtable_entry *new)
++{
++	if (unlikely(hlist_unhashed(&old->index_hash)))
++		return false;
++	spin_lock_bh(&table->lock);
++	new->index = old->index;
++	hlist_replace_rcu(&old->index_hash, &new->index_hash);
++
++	/* Calling init here NULLs out index_hash, and in fact after this
++	 * function returns, it's theoretically possible for this to get
++	 * reinserted elsewhere. That means the RCU lookup below might either
++	 * terminate early or jump between buckets, in which case the packet
++	 * simply gets dropped, which isn't terrible.
++	 */
++	INIT_HLIST_NODE(&old->index_hash);
++	spin_unlock_bh(&table->lock);
++	return true;
++}
++
++void wg_index_hashtable_remove(struct index_hashtable *table,
++			       struct index_hashtable_entry *entry)
++{
++	spin_lock_bh(&table->lock);
++	hlist_del_init_rcu(&entry->index_hash);
++	spin_unlock_bh(&table->lock);
++}
++
++/* Returns a strong reference to a entry->peer */
++struct index_hashtable_entry *
++wg_index_hashtable_lookup(struct index_hashtable *table,
++			  const enum index_hashtable_type type_mask,
++			  const __le32 index, struct wg_peer **peer)
++{
++	struct index_hashtable_entry *iter_entry, *entry = NULL;
++
++	rcu_read_lock_bh();
++	hlist_for_each_entry_rcu_bh(iter_entry, index_bucket(table, index),
++				    index_hash) {
++		if (iter_entry->index == index) {
++			if (likely(iter_entry->type & type_mask))
++				entry = iter_entry;
++			break;
++		}
++	}
++	if (likely(entry)) {
++		entry->peer = wg_peer_get_maybe_zero(entry->peer);
++		if (likely(entry->peer))
++			*peer = entry->peer;
++		else
++			entry = NULL;
++	}
++	rcu_read_unlock_bh();
++	return entry;
++}
+--- /dev/null
++++ b/drivers/net/wireguard/peerlookup.h
+@@ -0,0 +1,64 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#ifndef _WG_PEERLOOKUP_H
++#define _WG_PEERLOOKUP_H
++
++#include "messages.h"
++
++#include <linux/hashtable.h>
++#include <linux/mutex.h>
++#include <linux/siphash.h>
++
++struct wg_peer;
++
++struct pubkey_hashtable {
++	/* TODO: move to rhashtable */
++	DECLARE_HASHTABLE(hashtable, 11);
++	siphash_key_t key;
++	struct mutex lock;
++};
++
++struct pubkey_hashtable *wg_pubkey_hashtable_alloc(void);
++void wg_pubkey_hashtable_add(struct pubkey_hashtable *table,
++			     struct wg_peer *peer);
++void wg_pubkey_hashtable_remove(struct pubkey_hashtable *table,
++				struct wg_peer *peer);
++struct wg_peer *
++wg_pubkey_hashtable_lookup(struct pubkey_hashtable *table,
++			   const u8 pubkey[NOISE_PUBLIC_KEY_LEN]);
++
++struct index_hashtable {
++	/* TODO: move to rhashtable */
++	DECLARE_HASHTABLE(hashtable, 13);
++	spinlock_t lock;
++};
++
++enum index_hashtable_type {
++	INDEX_HASHTABLE_HANDSHAKE = 1U << 0,
++	INDEX_HASHTABLE_KEYPAIR = 1U << 1
++};
++
++struct index_hashtable_entry {
++	struct wg_peer *peer;
++	struct hlist_node index_hash;
++	enum index_hashtable_type type;
++	__le32 index;
++};
++
++struct index_hashtable *wg_index_hashtable_alloc(void);
++__le32 wg_index_hashtable_insert(struct index_hashtable *table,
++				 struct index_hashtable_entry *entry);
++bool wg_index_hashtable_replace(struct index_hashtable *table,
++				struct index_hashtable_entry *old,
++				struct index_hashtable_entry *new);
++void wg_index_hashtable_remove(struct index_hashtable *table,
++			       struct index_hashtable_entry *entry);
++struct index_hashtable_entry *
++wg_index_hashtable_lookup(struct index_hashtable *table,
++			  const enum index_hashtable_type type_mask,
++			  const __le32 index, struct wg_peer **peer);
++
++#endif /* _WG_PEERLOOKUP_H */
+--- /dev/null
++++ b/drivers/net/wireguard/queueing.c
+@@ -0,0 +1,53 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#include "queueing.h"
++
++struct multicore_worker __percpu *
++wg_packet_percpu_multicore_worker_alloc(work_func_t function, void *ptr)
++{
++	int cpu;
++	struct multicore_worker __percpu *worker =
++		alloc_percpu(struct multicore_worker);
++
++	if (!worker)
++		return NULL;
++
++	for_each_possible_cpu(cpu) {
++		per_cpu_ptr(worker, cpu)->ptr = ptr;
++		INIT_WORK(&per_cpu_ptr(worker, cpu)->work, function);
++	}
++	return worker;
++}
++
++int wg_packet_queue_init(struct crypt_queue *queue, work_func_t function,
++			 bool multicore, unsigned int len)
++{
++	int ret;
++
++	memset(queue, 0, sizeof(*queue));
++	ret = ptr_ring_init(&queue->ring, len, GFP_KERNEL);
++	if (ret)
++		return ret;
++	if (function) {
++		if (multicore) {
++			queue->worker = wg_packet_percpu_multicore_worker_alloc(
++				function, queue);
++			if (!queue->worker)
++				return -ENOMEM;
++		} else {
++			INIT_WORK(&queue->work, function);
++		}
++	}
++	return 0;
++}
++
++void wg_packet_queue_free(struct crypt_queue *queue, bool multicore)
++{
++	if (multicore)
++		free_percpu(queue->worker);
++	WARN_ON(!__ptr_ring_empty(&queue->ring));
++	ptr_ring_cleanup(&queue->ring, NULL);
++}
+--- /dev/null
++++ b/drivers/net/wireguard/queueing.h
+@@ -0,0 +1,197 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#ifndef _WG_QUEUEING_H
++#define _WG_QUEUEING_H
++
++#include "peer.h"
++#include <linux/types.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++
++struct wg_device;
++struct wg_peer;
++struct multicore_worker;
++struct crypt_queue;
++struct sk_buff;
++
++/* queueing.c APIs: */
++int wg_packet_queue_init(struct crypt_queue *queue, work_func_t function,
++			 bool multicore, unsigned int len);
++void wg_packet_queue_free(struct crypt_queue *queue, bool multicore);
++struct multicore_worker __percpu *
++wg_packet_percpu_multicore_worker_alloc(work_func_t function, void *ptr);
++
++/* receive.c APIs: */
++void wg_packet_receive(struct wg_device *wg, struct sk_buff *skb);
++void wg_packet_handshake_receive_worker(struct work_struct *work);
++/* NAPI poll function: */
++int wg_packet_rx_poll(struct napi_struct *napi, int budget);
++/* Workqueue worker: */
++void wg_packet_decrypt_worker(struct work_struct *work);
++
++/* send.c APIs: */
++void wg_packet_send_queued_handshake_initiation(struct wg_peer *peer,
++						bool is_retry);
++void wg_packet_send_handshake_response(struct wg_peer *peer);
++void wg_packet_send_handshake_cookie(struct wg_device *wg,
++				     struct sk_buff *initiating_skb,
++				     __le32 sender_index);
++void wg_packet_send_keepalive(struct wg_peer *peer);
++void wg_packet_purge_staged_packets(struct wg_peer *peer);
++void wg_packet_send_staged_packets(struct wg_peer *peer);
++/* Workqueue workers: */
++void wg_packet_handshake_send_worker(struct work_struct *work);
++void wg_packet_tx_worker(struct work_struct *work);
++void wg_packet_encrypt_worker(struct work_struct *work);
++
++enum packet_state {
++	PACKET_STATE_UNCRYPTED,
++	PACKET_STATE_CRYPTED,
++	PACKET_STATE_DEAD
++};
++
++struct packet_cb {
++	u64 nonce;
++	struct noise_keypair *keypair;
++	atomic_t state;
++	u32 mtu;
++	u8 ds;
++};
++
++#define PACKET_CB(skb) ((struct packet_cb *)((skb)->cb))
++#define PACKET_PEER(skb) (PACKET_CB(skb)->keypair->entry.peer)
++
++/* Returns either the correct skb->protocol value, or 0 if invalid. */
++static inline __be16 wg_skb_examine_untrusted_ip_hdr(struct sk_buff *skb)
++{
++	if (skb_network_header(skb) >= skb->head &&
++	    (skb_network_header(skb) + sizeof(struct iphdr)) <=
++		    skb_tail_pointer(skb) &&
++	    ip_hdr(skb)->version == 4)
++		return htons(ETH_P_IP);
++	if (skb_network_header(skb) >= skb->head &&
++	    (skb_network_header(skb) + sizeof(struct ipv6hdr)) <=
++		    skb_tail_pointer(skb) &&
++	    ipv6_hdr(skb)->version == 6)
++		return htons(ETH_P_IPV6);
++	return 0;
++}
++
++static inline void wg_reset_packet(struct sk_buff *skb)
++{
++	const int pfmemalloc = skb->pfmemalloc;
++
++	skb_scrub_packet(skb, true);
++	memset(&skb->headers_start, 0,
++	       offsetof(struct sk_buff, headers_end) -
++		       offsetof(struct sk_buff, headers_start));
++	skb->pfmemalloc = pfmemalloc;
++	skb->queue_mapping = 0;
++	skb->nohdr = 0;
++	skb->peeked = 0;
++	skb->mac_len = 0;
++	skb->dev = NULL;
++#ifdef CONFIG_NET_SCHED
++	skb->tc_index = 0;
++#endif
++	skb_reset_redirect(skb);
++	skb->hdr_len = skb_headroom(skb);
++	skb_reset_mac_header(skb);
++	skb_reset_network_header(skb);
++	skb_reset_transport_header(skb);
++	skb_probe_transport_header(skb);
++	skb_reset_inner_headers(skb);
++}
++
++static inline int wg_cpumask_choose_online(int *stored_cpu, unsigned int id)
++{
++	unsigned int cpu = *stored_cpu, cpu_index, i;
++
++	if (unlikely(cpu == nr_cpumask_bits ||
++		     !cpumask_test_cpu(cpu, cpu_online_mask))) {
++		cpu_index = id % cpumask_weight(cpu_online_mask);
++		cpu = cpumask_first(cpu_online_mask);
++		for (i = 0; i < cpu_index; ++i)
++			cpu = cpumask_next(cpu, cpu_online_mask);
++		*stored_cpu = cpu;
++	}
++	return cpu;
++}
++
++/* This function is racy, in the sense that next is unlocked, so it could return
++ * the same CPU twice. A race-free version of this would be to instead store an
++ * atomic sequence number, do an increment-and-return, and then iterate through
++ * every possible CPU until we get to that index -- choose_cpu. However that's
++ * a bit slower, and it doesn't seem like this potential race actually
++ * introduces any performance loss, so we live with it.
++ */
++static inline int wg_cpumask_next_online(int *next)
++{
++	int cpu = *next;
++
++	while (unlikely(!cpumask_test_cpu(cpu, cpu_online_mask)))
++		cpu = cpumask_next(cpu, cpu_online_mask) % nr_cpumask_bits;
++	*next = cpumask_next(cpu, cpu_online_mask) % nr_cpumask_bits;
++	return cpu;
++}
++
++static inline int wg_queue_enqueue_per_device_and_peer(
++	struct crypt_queue *device_queue, struct crypt_queue *peer_queue,
++	struct sk_buff *skb, struct workqueue_struct *wq, int *next_cpu)
++{
++	int cpu;
++
++	atomic_set_release(&PACKET_CB(skb)->state, PACKET_STATE_UNCRYPTED);
++	/* We first queue this up for the peer ingestion, but the consumer
++	 * will wait for the state to change to CRYPTED or DEAD before.
++	 */
++	if (unlikely(ptr_ring_produce_bh(&peer_queue->ring, skb)))
++		return -ENOSPC;
++	/* Then we queue it up in the device queue, which consumes the
++	 * packet as soon as it can.
++	 */
++	cpu = wg_cpumask_next_online(next_cpu);
++	if (unlikely(ptr_ring_produce_bh(&device_queue->ring, skb)))
++		return -EPIPE;
++	queue_work_on(cpu, wq, &per_cpu_ptr(device_queue->worker, cpu)->work);
++	return 0;
++}
++
++static inline void wg_queue_enqueue_per_peer(struct crypt_queue *queue,
++					     struct sk_buff *skb,
++					     enum packet_state state)
++{
++	/* We take a reference, because as soon as we call atomic_set, the
++	 * peer can be freed from below us.
++	 */
++	struct wg_peer *peer = wg_peer_get(PACKET_PEER(skb));
++
++	atomic_set_release(&PACKET_CB(skb)->state, state);
++	queue_work_on(wg_cpumask_choose_online(&peer->serial_work_cpu,
++					       peer->internal_id),
++		      peer->device->packet_crypt_wq, &queue->work);
++	wg_peer_put(peer);
++}
++
++static inline void wg_queue_enqueue_per_peer_napi(struct sk_buff *skb,
++						  enum packet_state state)
++{
++	/* We take a reference, because as soon as we call atomic_set, the
++	 * peer can be freed from below us.
++	 */
++	struct wg_peer *peer = wg_peer_get(PACKET_PEER(skb));
++
++	atomic_set_release(&PACKET_CB(skb)->state, state);
++	napi_schedule(&peer->napi);
++	wg_peer_put(peer);
++}
++
++#ifdef DEBUG
++bool wg_packet_counter_selftest(void);
++#endif
++
++#endif /* _WG_QUEUEING_H */
+--- /dev/null
++++ b/drivers/net/wireguard/ratelimiter.c
+@@ -0,0 +1,223 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#include "ratelimiter.h"
++#include <linux/siphash.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <net/ip.h>
++
++static struct kmem_cache *entry_cache;
++static hsiphash_key_t key;
++static spinlock_t table_lock = __SPIN_LOCK_UNLOCKED("ratelimiter_table_lock");
++static DEFINE_MUTEX(init_lock);
++static u64 init_refcnt; /* Protected by init_lock, hence not atomic. */
++static atomic_t total_entries = ATOMIC_INIT(0);
++static unsigned int max_entries, table_size;
++static void wg_ratelimiter_gc_entries(struct work_struct *);
++static DECLARE_DEFERRABLE_WORK(gc_work, wg_ratelimiter_gc_entries);
++static struct hlist_head *table_v4;
++#if IS_ENABLED(CONFIG_IPV6)
++static struct hlist_head *table_v6;
++#endif
++
++struct ratelimiter_entry {
++	u64 last_time_ns, tokens, ip;
++	void *net;
++	spinlock_t lock;
++	struct hlist_node hash;
++	struct rcu_head rcu;
++};
++
++enum {
++	PACKETS_PER_SECOND = 20,
++	PACKETS_BURSTABLE = 5,
++	PACKET_COST = NSEC_PER_SEC / PACKETS_PER_SECOND,
++	TOKEN_MAX = PACKET_COST * PACKETS_BURSTABLE
++};
++
++static void entry_free(struct rcu_head *rcu)
++{
++	kmem_cache_free(entry_cache,
++			container_of(rcu, struct ratelimiter_entry, rcu));
++	atomic_dec(&total_entries);
++}
++
++static void entry_uninit(struct ratelimiter_entry *entry)
++{
++	hlist_del_rcu(&entry->hash);
++	call_rcu(&entry->rcu, entry_free);
++}
++
++/* Calling this function with a NULL work uninits all entries. */
++static void wg_ratelimiter_gc_entries(struct work_struct *work)
++{
++	const u64 now = ktime_get_coarse_boottime_ns();
++	struct ratelimiter_entry *entry;
++	struct hlist_node *temp;
++	unsigned int i;
++
++	for (i = 0; i < table_size; ++i) {
++		spin_lock(&table_lock);
++		hlist_for_each_entry_safe(entry, temp, &table_v4[i], hash) {
++			if (unlikely(!work) ||
++			    now - entry->last_time_ns > NSEC_PER_SEC)
++				entry_uninit(entry);
++		}
++#if IS_ENABLED(CONFIG_IPV6)
++		hlist_for_each_entry_safe(entry, temp, &table_v6[i], hash) {
++			if (unlikely(!work) ||
++			    now - entry->last_time_ns > NSEC_PER_SEC)
++				entry_uninit(entry);
++		}
++#endif
++		spin_unlock(&table_lock);
++		if (likely(work))
++			cond_resched();
++	}
++	if (likely(work))
++		queue_delayed_work(system_power_efficient_wq, &gc_work, HZ);
++}
++
++bool wg_ratelimiter_allow(struct sk_buff *skb, struct net *net)
++{
++	/* We only take the bottom half of the net pointer, so that we can hash
++	 * 3 words in the end. This way, siphash's len param fits into the final
++	 * u32, and we don't incur an extra round.
++	 */
++	const u32 net_word = (unsigned long)net;
++	struct ratelimiter_entry *entry;
++	struct hlist_head *bucket;
++	u64 ip;
++
++	if (skb->protocol == htons(ETH_P_IP)) {
++		ip = (u64 __force)ip_hdr(skb)->saddr;
++		bucket = &table_v4[hsiphash_2u32(net_word, ip, &key) &
++				   (table_size - 1)];
++	}
++#if IS_ENABLED(CONFIG_IPV6)
++	else if (skb->protocol == htons(ETH_P_IPV6)) {
++		/* Only use 64 bits, so as to ratelimit the whole /64. */
++		memcpy(&ip, &ipv6_hdr(skb)->saddr, sizeof(ip));
++		bucket = &table_v6[hsiphash_3u32(net_word, ip >> 32, ip, &key) &
++				   (table_size - 1)];
++	}
++#endif
++	else
++		return false;
++	rcu_read_lock();
++	hlist_for_each_entry_rcu(entry, bucket, hash) {
++		if (entry->net == net && entry->ip == ip) {
++			u64 now, tokens;
++			bool ret;
++			/* Quasi-inspired by nft_limit.c, but this is actually a
++			 * slightly different algorithm. Namely, we incorporate
++			 * the burst as part of the maximum tokens, rather than
++			 * as part of the rate.
++			 */
++			spin_lock(&entry->lock);
++			now = ktime_get_coarse_boottime_ns();
++			tokens = min_t(u64, TOKEN_MAX,
++				       entry->tokens + now -
++					       entry->last_time_ns);
++			entry->last_time_ns = now;
++			ret = tokens >= PACKET_COST;
++			entry->tokens = ret ? tokens - PACKET_COST : tokens;
++			spin_unlock(&entry->lock);
++			rcu_read_unlock();
++			return ret;
++		}
++	}
++	rcu_read_unlock();
++
++	if (atomic_inc_return(&total_entries) > max_entries)
++		goto err_oom;
++
++	entry = kmem_cache_alloc(entry_cache, GFP_KERNEL);
++	if (unlikely(!entry))
++		goto err_oom;
++
++	entry->net = net;
++	entry->ip = ip;
++	INIT_HLIST_NODE(&entry->hash);
++	spin_lock_init(&entry->lock);
++	entry->last_time_ns = ktime_get_coarse_boottime_ns();
++	entry->tokens = TOKEN_MAX - PACKET_COST;
++	spin_lock(&table_lock);
++	hlist_add_head_rcu(&entry->hash, bucket);
++	spin_unlock(&table_lock);
++	return true;
++
++err_oom:
++	atomic_dec(&total_entries);
++	return false;
++}
++
++int wg_ratelimiter_init(void)
++{
++	mutex_lock(&init_lock);
++	if (++init_refcnt != 1)
++		goto out;
++
++	entry_cache = KMEM_CACHE(ratelimiter_entry, 0);
++	if (!entry_cache)
++		goto err;
++
++	/* xt_hashlimit.c uses a slightly different algorithm for ratelimiting,
++	 * but what it shares in common is that it uses a massive hashtable. So,
++	 * we borrow their wisdom about good table sizes on different systems
++	 * dependent on RAM. This calculation here comes from there.
++	 */
++	table_size = (totalram_pages() > (1U << 30) / PAGE_SIZE) ? 8192 :
++		max_t(unsigned long, 16, roundup_pow_of_two(
++			(totalram_pages() << PAGE_SHIFT) /
++			(1U << 14) / sizeof(struct hlist_head)));
++	max_entries = table_size * 8;
++
++	table_v4 = kvzalloc(table_size * sizeof(*table_v4), GFP_KERNEL);
++	if (unlikely(!table_v4))
++		goto err_kmemcache;
++
++#if IS_ENABLED(CONFIG_IPV6)
++	table_v6 = kvzalloc(table_size * sizeof(*table_v6), GFP_KERNEL);
++	if (unlikely(!table_v6)) {
++		kvfree(table_v4);
++		goto err_kmemcache;
++	}
++#endif
++
++	queue_delayed_work(system_power_efficient_wq, &gc_work, HZ);
++	get_random_bytes(&key, sizeof(key));
++out:
++	mutex_unlock(&init_lock);
++	return 0;
++
++err_kmemcache:
++	kmem_cache_destroy(entry_cache);
++err:
++	--init_refcnt;
++	mutex_unlock(&init_lock);
++	return -ENOMEM;
++}
++
++void wg_ratelimiter_uninit(void)
++{
++	mutex_lock(&init_lock);
++	if (!init_refcnt || --init_refcnt)
++		goto out;
++
++	cancel_delayed_work_sync(&gc_work);
++	wg_ratelimiter_gc_entries(NULL);
++	rcu_barrier();
++	kvfree(table_v4);
++#if IS_ENABLED(CONFIG_IPV6)
++	kvfree(table_v6);
++#endif
++	kmem_cache_destroy(entry_cache);
++out:
++	mutex_unlock(&init_lock);
++}
++
++#include "selftest/ratelimiter.c"
+--- /dev/null
++++ b/drivers/net/wireguard/ratelimiter.h
+@@ -0,0 +1,19 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#ifndef _WG_RATELIMITER_H
++#define _WG_RATELIMITER_H
++
++#include <linux/skbuff.h>
++
++int wg_ratelimiter_init(void);
++void wg_ratelimiter_uninit(void);
++bool wg_ratelimiter_allow(struct sk_buff *skb, struct net *net);
++
++#ifdef DEBUG
++bool wg_ratelimiter_selftest(void);
++#endif
++
++#endif /* _WG_RATELIMITER_H */
+--- /dev/null
++++ b/drivers/net/wireguard/receive.c
+@@ -0,0 +1,595 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#include "queueing.h"
++#include "device.h"
++#include "peer.h"
++#include "timers.h"
++#include "messages.h"
++#include "cookie.h"
++#include "socket.h"
++
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++#include <linux/udp.h>
++#include <net/ip_tunnels.h>
++
++/* Must be called with bh disabled. */
++static void update_rx_stats(struct wg_peer *peer, size_t len)
++{
++	struct pcpu_sw_netstats *tstats =
++		get_cpu_ptr(peer->device->dev->tstats);
++
++	u64_stats_update_begin(&tstats->syncp);
++	++tstats->rx_packets;
++	tstats->rx_bytes += len;
++	peer->rx_bytes += len;
++	u64_stats_update_end(&tstats->syncp);
++	put_cpu_ptr(tstats);
++}
++
++#define SKB_TYPE_LE32(skb) (((struct message_header *)(skb)->data)->type)
++
++static size_t validate_header_len(struct sk_buff *skb)
++{
++	if (unlikely(skb->len < sizeof(struct message_header)))
++		return 0;
++	if (SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_DATA) &&
++	    skb->len >= MESSAGE_MINIMUM_LENGTH)
++		return sizeof(struct message_data);
++	if (SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION) &&
++	    skb->len == sizeof(struct message_handshake_initiation))
++		return sizeof(struct message_handshake_initiation);
++	if (SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE) &&
++	    skb->len == sizeof(struct message_handshake_response))
++		return sizeof(struct message_handshake_response);
++	if (SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE) &&
++	    skb->len == sizeof(struct message_handshake_cookie))
++		return sizeof(struct message_handshake_cookie);
++	return 0;
++}
++
++static int prepare_skb_header(struct sk_buff *skb, struct wg_device *wg)
++{
++	size_t data_offset, data_len, header_len;
++	struct udphdr *udp;
++
++	if (unlikely(wg_skb_examine_untrusted_ip_hdr(skb) != skb->protocol ||
++		     skb_transport_header(skb) < skb->head ||
++		     (skb_transport_header(skb) + sizeof(struct udphdr)) >
++			     skb_tail_pointer(skb)))
++		return -EINVAL; /* Bogus IP header */
++	udp = udp_hdr(skb);
++	data_offset = (u8 *)udp - skb->data;
++	if (unlikely(data_offset > U16_MAX ||
++		     data_offset + sizeof(struct udphdr) > skb->len))
++		/* Packet has offset at impossible location or isn't big enough
++		 * to have UDP fields.
++		 */
++		return -EINVAL;
++	data_len = ntohs(udp->len);
++	if (unlikely(data_len < sizeof(struct udphdr) ||
++		     data_len > skb->len - data_offset))
++		/* UDP packet is reporting too small of a size or lying about
++		 * its size.
++		 */
++		return -EINVAL;
++	data_len -= sizeof(struct udphdr);
++	data_offset = (u8 *)udp + sizeof(struct udphdr) - skb->data;
++	if (unlikely(!pskb_may_pull(skb,
++				data_offset + sizeof(struct message_header)) ||
++		     pskb_trim(skb, data_len + data_offset) < 0))
++		return -EINVAL;
++	skb_pull(skb, data_offset);
++	if (unlikely(skb->len != data_len))
++		/* Final len does not agree with calculated len */
++		return -EINVAL;
++	header_len = validate_header_len(skb);
++	if (unlikely(!header_len))
++		return -EINVAL;
++	__skb_push(skb, data_offset);
++	if (unlikely(!pskb_may_pull(skb, data_offset + header_len)))
++		return -EINVAL;
++	__skb_pull(skb, data_offset);
++	return 0;
++}
++
++static void wg_receive_handshake_packet(struct wg_device *wg,
++					struct sk_buff *skb)
++{
++	enum cookie_mac_state mac_state;
++	struct wg_peer *peer = NULL;
++	/* This is global, so that our load calculation applies to the whole
++	 * system. We don't care about races with it at all.
++	 */
++	static u64 last_under_load;
++	bool packet_needs_cookie;
++	bool under_load;
++
++	if (SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE)) {
++		net_dbg_skb_ratelimited("%s: Receiving cookie response from %pISpfsc\n",
++					wg->dev->name, skb);
++		wg_cookie_message_consume(
++			(struct message_handshake_cookie *)skb->data, wg);
++		return;
++	}
++
++	under_load = skb_queue_len(&wg->incoming_handshakes) >=
++		     MAX_QUEUED_INCOMING_HANDSHAKES / 8;
++	if (under_load)
++		last_under_load = ktime_get_coarse_boottime_ns();
++	else if (last_under_load)
++		under_load = !wg_birthdate_has_expired(last_under_load, 1);
++	mac_state = wg_cookie_validate_packet(&wg->cookie_checker, skb,
++					      under_load);
++	if ((under_load && mac_state == VALID_MAC_WITH_COOKIE) ||
++	    (!under_load && mac_state == VALID_MAC_BUT_NO_COOKIE)) {
++		packet_needs_cookie = false;
++	} else if (under_load && mac_state == VALID_MAC_BUT_NO_COOKIE) {
++		packet_needs_cookie = true;
++	} else {
++		net_dbg_skb_ratelimited("%s: Invalid MAC of handshake, dropping packet from %pISpfsc\n",
++					wg->dev->name, skb);
++		return;
++	}
++
++	switch (SKB_TYPE_LE32(skb)) {
++	case cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION): {
++		struct message_handshake_initiation *message =
++			(struct message_handshake_initiation *)skb->data;
++
++		if (packet_needs_cookie) {
++			wg_packet_send_handshake_cookie(wg, skb,
++							message->sender_index);
++			return;
++		}
++		peer = wg_noise_handshake_consume_initiation(message, wg);
++		if (unlikely(!peer)) {
++			net_dbg_skb_ratelimited("%s: Invalid handshake initiation from %pISpfsc\n",
++						wg->dev->name, skb);
++			return;
++		}
++		wg_socket_set_peer_endpoint_from_skb(peer, skb);
++		net_dbg_ratelimited("%s: Receiving handshake initiation from peer %llu (%pISpfsc)\n",
++				    wg->dev->name, peer->internal_id,
++				    &peer->endpoint.addr);
++		wg_packet_send_handshake_response(peer);
++		break;
++	}
++	case cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE): {
++		struct message_handshake_response *message =
++			(struct message_handshake_response *)skb->data;
++
++		if (packet_needs_cookie) {
++			wg_packet_send_handshake_cookie(wg, skb,
++							message->sender_index);
++			return;
++		}
++		peer = wg_noise_handshake_consume_response(message, wg);
++		if (unlikely(!peer)) {
++			net_dbg_skb_ratelimited("%s: Invalid handshake response from %pISpfsc\n",
++						wg->dev->name, skb);
++			return;
++		}
++		wg_socket_set_peer_endpoint_from_skb(peer, skb);
++		net_dbg_ratelimited("%s: Receiving handshake response from peer %llu (%pISpfsc)\n",
++				    wg->dev->name, peer->internal_id,
++				    &peer->endpoint.addr);
++		if (wg_noise_handshake_begin_session(&peer->handshake,
++						     &peer->keypairs)) {
++			wg_timers_session_derived(peer);
++			wg_timers_handshake_complete(peer);
++			/* Calling this function will either send any existing
++			 * packets in the queue and not send a keepalive, which
++			 * is the best case, Or, if there's nothing in the
++			 * queue, it will send a keepalive, in order to give
++			 * immediate confirmation of the session.
++			 */
++			wg_packet_send_keepalive(peer);
++		}
++		break;
++	}
++	}
++
++	if (unlikely(!peer)) {
++		WARN(1, "Somehow a wrong type of packet wound up in the handshake queue!\n");
++		return;
++	}
++
++	local_bh_disable();
++	update_rx_stats(peer, skb->len);
++	local_bh_enable();
++
++	wg_timers_any_authenticated_packet_received(peer);
++	wg_timers_any_authenticated_packet_traversal(peer);
++	wg_peer_put(peer);
++}
++
++void wg_packet_handshake_receive_worker(struct work_struct *work)
++{
++	struct wg_device *wg = container_of(work, struct multicore_worker,
++					    work)->ptr;
++	struct sk_buff *skb;
++
++	while ((skb = skb_dequeue(&wg->incoming_handshakes)) != NULL) {
++		wg_receive_handshake_packet(wg, skb);
++		dev_kfree_skb(skb);
++		cond_resched();
++	}
++}
++
++static void keep_key_fresh(struct wg_peer *peer)
++{
++	struct noise_keypair *keypair;
++	bool send = false;
++
++	if (peer->sent_lastminute_handshake)
++		return;
++
++	rcu_read_lock_bh();
++	keypair = rcu_dereference_bh(peer->keypairs.current_keypair);
++	if (likely(keypair && READ_ONCE(keypair->sending.is_valid)) &&
++	    keypair->i_am_the_initiator &&
++	    unlikely(wg_birthdate_has_expired(keypair->sending.birthdate,
++			REJECT_AFTER_TIME - KEEPALIVE_TIMEOUT - REKEY_TIMEOUT)))
++		send = true;
++	rcu_read_unlock_bh();
++
++	if (send) {
++		peer->sent_lastminute_handshake = true;
++		wg_packet_send_queued_handshake_initiation(peer, false);
++	}
++}
++
++static bool decrypt_packet(struct sk_buff *skb, struct noise_symmetric_key *key)
++{
++	struct scatterlist sg[MAX_SKB_FRAGS + 8];
++	struct sk_buff *trailer;
++	unsigned int offset;
++	int num_frags;
++
++	if (unlikely(!key))
++		return false;
++
++	if (unlikely(!READ_ONCE(key->is_valid) ||
++		  wg_birthdate_has_expired(key->birthdate, REJECT_AFTER_TIME) ||
++		  key->counter.receive.counter >= REJECT_AFTER_MESSAGES)) {
++		WRITE_ONCE(key->is_valid, false);
++		return false;
++	}
++
++	PACKET_CB(skb)->nonce =
++		le64_to_cpu(((struct message_data *)skb->data)->counter);
++
++	/* We ensure that the network header is part of the packet before we
++	 * call skb_cow_data, so that there's no chance that data is removed
++	 * from the skb, so that later we can extract the original endpoint.
++	 */
++	offset = skb->data - skb_network_header(skb);
++	skb_push(skb, offset);
++	num_frags = skb_cow_data(skb, 0, &trailer);
++	offset += sizeof(struct message_data);
++	skb_pull(skb, offset);
++	if (unlikely(num_frags < 0 || num_frags > ARRAY_SIZE(sg)))
++		return false;
++
++	sg_init_table(sg, num_frags);
++	if (skb_to_sgvec(skb, sg, 0, skb->len) <= 0)
++		return false;
++
++	if (!chacha20poly1305_decrypt_sg_inplace(sg, skb->len, NULL, 0,
++					         PACKET_CB(skb)->nonce,
++						 key->key))
++		return false;
++
++	/* Another ugly situation of pushing and pulling the header so as to
++	 * keep endpoint information intact.
++	 */
++	skb_push(skb, offset);
++	if (pskb_trim(skb, skb->len - noise_encrypted_len(0)))
++		return false;
++	skb_pull(skb, offset);
++
++	return true;
++}
++
++/* This is RFC6479, a replay detection bitmap algorithm that avoids bitshifts */
++static bool counter_validate(union noise_counter *counter, u64 their_counter)
++{
++	unsigned long index, index_current, top, i;
++	bool ret = false;
++
++	spin_lock_bh(&counter->receive.lock);
++
++	if (unlikely(counter->receive.counter >= REJECT_AFTER_MESSAGES + 1 ||
++		     their_counter >= REJECT_AFTER_MESSAGES))
++		goto out;
++
++	++their_counter;
++
++	if (unlikely((COUNTER_WINDOW_SIZE + their_counter) <
++		     counter->receive.counter))
++		goto out;
++
++	index = their_counter >> ilog2(BITS_PER_LONG);
++
++	if (likely(their_counter > counter->receive.counter)) {
++		index_current = counter->receive.counter >> ilog2(BITS_PER_LONG);
++		top = min_t(unsigned long, index - index_current,
++			    COUNTER_BITS_TOTAL / BITS_PER_LONG);
++		for (i = 1; i <= top; ++i)
++			counter->receive.backtrack[(i + index_current) &
++				((COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1)] = 0;
++		counter->receive.counter = their_counter;
++	}
++
++	index &= (COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1;
++	ret = !test_and_set_bit(their_counter & (BITS_PER_LONG - 1),
++				&counter->receive.backtrack[index]);
++
++out:
++	spin_unlock_bh(&counter->receive.lock);
++	return ret;
++}
++
++#include "selftest/counter.c"
++
++static void wg_packet_consume_data_done(struct wg_peer *peer,
++					struct sk_buff *skb,
++					struct endpoint *endpoint)
++{
++	struct net_device *dev = peer->device->dev;
++	unsigned int len, len_before_trim;
++	struct wg_peer *routed_peer;
++
++	wg_socket_set_peer_endpoint(peer, endpoint);
++
++	if (unlikely(wg_noise_received_with_keypair(&peer->keypairs,
++						    PACKET_CB(skb)->keypair))) {
++		wg_timers_handshake_complete(peer);
++		wg_packet_send_staged_packets(peer);
++	}
++
++	keep_key_fresh(peer);
++
++	wg_timers_any_authenticated_packet_received(peer);
++	wg_timers_any_authenticated_packet_traversal(peer);
++
++	/* A packet with length 0 is a keepalive packet */
++	if (unlikely(!skb->len)) {
++		update_rx_stats(peer, message_data_len(0));
++		net_dbg_ratelimited("%s: Receiving keepalive packet from peer %llu (%pISpfsc)\n",
++				    dev->name, peer->internal_id,
++				    &peer->endpoint.addr);
++		goto packet_processed;
++	}
++
++	wg_timers_data_received(peer);
++
++	if (unlikely(skb_network_header(skb) < skb->head))
++		goto dishonest_packet_size;
++	if (unlikely(!(pskb_network_may_pull(skb, sizeof(struct iphdr)) &&
++		       (ip_hdr(skb)->version == 4 ||
++			(ip_hdr(skb)->version == 6 &&
++			 pskb_network_may_pull(skb, sizeof(struct ipv6hdr)))))))
++		goto dishonest_packet_type;
++
++	skb->dev = dev;
++	/* We've already verified the Poly1305 auth tag, which means this packet
++	 * was not modified in transit. We can therefore tell the networking
++	 * stack that all checksums of every layer of encapsulation have already
++	 * been checked "by the hardware" and therefore is unneccessary to check
++	 * again in software.
++	 */
++	skb->ip_summed = CHECKSUM_UNNECESSARY;
++	skb->csum_level = ~0; /* All levels */
++	skb->protocol = wg_skb_examine_untrusted_ip_hdr(skb);
++	if (skb->protocol == htons(ETH_P_IP)) {
++		len = ntohs(ip_hdr(skb)->tot_len);
++		if (unlikely(len < sizeof(struct iphdr)))
++			goto dishonest_packet_size;
++		if (INET_ECN_is_ce(PACKET_CB(skb)->ds))
++			IP_ECN_set_ce(ip_hdr(skb));
++	} else if (skb->protocol == htons(ETH_P_IPV6)) {
++		len = ntohs(ipv6_hdr(skb)->payload_len) +
++		      sizeof(struct ipv6hdr);
++		if (INET_ECN_is_ce(PACKET_CB(skb)->ds))
++			IP6_ECN_set_ce(skb, ipv6_hdr(skb));
++	} else {
++		goto dishonest_packet_type;
++	}
++
++	if (unlikely(len > skb->len))
++		goto dishonest_packet_size;
++	len_before_trim = skb->len;
++	if (unlikely(pskb_trim(skb, len)))
++		goto packet_processed;
++
++	routed_peer = wg_allowedips_lookup_src(&peer->device->peer_allowedips,
++					       skb);
++	wg_peer_put(routed_peer); /* We don't need the extra reference. */
++
++	if (unlikely(routed_peer != peer))
++		goto dishonest_packet_peer;
++
++	if (unlikely(napi_gro_receive(&peer->napi, skb) == GRO_DROP)) {
++		++dev->stats.rx_dropped;
++		net_dbg_ratelimited("%s: Failed to give packet to userspace from peer %llu (%pISpfsc)\n",
++				    dev->name, peer->internal_id,
++				    &peer->endpoint.addr);
++	} else {
++		update_rx_stats(peer, message_data_len(len_before_trim));
++	}
++	return;
++
++dishonest_packet_peer:
++	net_dbg_skb_ratelimited("%s: Packet has unallowed src IP (%pISc) from peer %llu (%pISpfsc)\n",
++				dev->name, skb, peer->internal_id,
++				&peer->endpoint.addr);
++	++dev->stats.rx_errors;
++	++dev->stats.rx_frame_errors;
++	goto packet_processed;
++dishonest_packet_type:
++	net_dbg_ratelimited("%s: Packet is neither ipv4 nor ipv6 from peer %llu (%pISpfsc)\n",
++			    dev->name, peer->internal_id, &peer->endpoint.addr);
++	++dev->stats.rx_errors;
++	++dev->stats.rx_frame_errors;
++	goto packet_processed;
++dishonest_packet_size:
++	net_dbg_ratelimited("%s: Packet has incorrect size from peer %llu (%pISpfsc)\n",
++			    dev->name, peer->internal_id, &peer->endpoint.addr);
++	++dev->stats.rx_errors;
++	++dev->stats.rx_length_errors;
++	goto packet_processed;
++packet_processed:
++	dev_kfree_skb(skb);
++}
++
++int wg_packet_rx_poll(struct napi_struct *napi, int budget)
++{
++	struct wg_peer *peer = container_of(napi, struct wg_peer, napi);
++	struct crypt_queue *queue = &peer->rx_queue;
++	struct noise_keypair *keypair;
++	struct endpoint endpoint;
++	enum packet_state state;
++	struct sk_buff *skb;
++	int work_done = 0;
++	bool free;
++
++	if (unlikely(budget <= 0))
++		return 0;
++
++	while ((skb = __ptr_ring_peek(&queue->ring)) != NULL &&
++	       (state = atomic_read_acquire(&PACKET_CB(skb)->state)) !=
++		       PACKET_STATE_UNCRYPTED) {
++		__ptr_ring_discard_one(&queue->ring);
++		peer = PACKET_PEER(skb);
++		keypair = PACKET_CB(skb)->keypair;
++		free = true;
++
++		if (unlikely(state != PACKET_STATE_CRYPTED))
++			goto next;
++
++		if (unlikely(!counter_validate(&keypair->receiving.counter,
++					       PACKET_CB(skb)->nonce))) {
++			net_dbg_ratelimited("%s: Packet has invalid nonce %llu (max %llu)\n",
++					    peer->device->dev->name,
++					    PACKET_CB(skb)->nonce,
++					    keypair->receiving.counter.receive.counter);
++			goto next;
++		}
++
++		if (unlikely(wg_socket_endpoint_from_skb(&endpoint, skb)))
++			goto next;
++
++		wg_reset_packet(skb);
++		wg_packet_consume_data_done(peer, skb, &endpoint);
++		free = false;
++
++next:
++		wg_noise_keypair_put(keypair, false);
++		wg_peer_put(peer);
++		if (unlikely(free))
++			dev_kfree_skb(skb);
++
++		if (++work_done >= budget)
++			break;
++	}
++
++	if (work_done < budget)
++		napi_complete_done(napi, work_done);
++
++	return work_done;
++}
++
++void wg_packet_decrypt_worker(struct work_struct *work)
++{
++	struct crypt_queue *queue = container_of(work, struct multicore_worker,
++						 work)->ptr;
++	struct sk_buff *skb;
++
++	while ((skb = ptr_ring_consume_bh(&queue->ring)) != NULL) {
++		enum packet_state state = likely(decrypt_packet(skb,
++				&PACKET_CB(skb)->keypair->receiving)) ?
++				PACKET_STATE_CRYPTED : PACKET_STATE_DEAD;
++		wg_queue_enqueue_per_peer_napi(skb, state);
++	}
++}
++
++static void wg_packet_consume_data(struct wg_device *wg, struct sk_buff *skb)
++{
++	__le32 idx = ((struct message_data *)skb->data)->key_idx;
++	struct wg_peer *peer = NULL;
++	int ret;
++
++	rcu_read_lock_bh();
++	PACKET_CB(skb)->keypair =
++		(struct noise_keypair *)wg_index_hashtable_lookup(
++			wg->index_hashtable, INDEX_HASHTABLE_KEYPAIR, idx,
++			&peer);
++	if (unlikely(!wg_noise_keypair_get(PACKET_CB(skb)->keypair)))
++		goto err_keypair;
++
++	if (unlikely(READ_ONCE(peer->is_dead)))
++		goto err;
++
++	ret = wg_queue_enqueue_per_device_and_peer(&wg->decrypt_queue,
++						   &peer->rx_queue, skb,
++						   wg->packet_crypt_wq,
++						   &wg->decrypt_queue.last_cpu);
++	if (unlikely(ret == -EPIPE))
++		wg_queue_enqueue_per_peer_napi(skb, PACKET_STATE_DEAD);
++	if (likely(!ret || ret == -EPIPE)) {
++		rcu_read_unlock_bh();
++		return;
++	}
++err:
++	wg_noise_keypair_put(PACKET_CB(skb)->keypair, false);
++err_keypair:
++	rcu_read_unlock_bh();
++	wg_peer_put(peer);
++	dev_kfree_skb(skb);
++}
++
++void wg_packet_receive(struct wg_device *wg, struct sk_buff *skb)
++{
++	if (unlikely(prepare_skb_header(skb, wg) < 0))
++		goto err;
++	switch (SKB_TYPE_LE32(skb)) {
++	case cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION):
++	case cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE):
++	case cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE): {
++		int cpu;
++
++		if (skb_queue_len(&wg->incoming_handshakes) >
++			    MAX_QUEUED_INCOMING_HANDSHAKES ||
++		    unlikely(!rng_is_initialized())) {
++			net_dbg_skb_ratelimited("%s: Dropping handshake packet from %pISpfsc\n",
++						wg->dev->name, skb);
++			goto err;
++		}
++		skb_queue_tail(&wg->incoming_handshakes, skb);
++		/* Queues up a call to packet_process_queued_handshake_
++		 * packets(skb):
++		 */
++		cpu = wg_cpumask_next_online(&wg->incoming_handshake_cpu);
++		queue_work_on(cpu, wg->handshake_receive_wq,
++			&per_cpu_ptr(wg->incoming_handshakes_worker, cpu)->work);
++		break;
++	}
++	case cpu_to_le32(MESSAGE_DATA):
++		PACKET_CB(skb)->ds = ip_tunnel_get_dsfield(ip_hdr(skb), skb);
++		wg_packet_consume_data(wg, skb);
++		break;
++	default:
++		net_dbg_skb_ratelimited("%s: Invalid packet from %pISpfsc\n",
++					wg->dev->name, skb);
++		goto err;
++	}
++	return;
++
++err:
++	dev_kfree_skb(skb);
++}
+--- /dev/null
++++ b/drivers/net/wireguard/selftest/allowedips.c
+@@ -0,0 +1,683 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ *
++ * This contains some basic static unit tests for the allowedips data structure.
++ * It also has two additional modes that are disabled and meant to be used by
++ * folks directly playing with this file. If you define the macro
++ * DEBUG_PRINT_TRIE_GRAPHVIZ to be 1, then every time there's a full tree in
++ * memory, it will be printed out as KERN_DEBUG in a format that can be passed
++ * to graphviz (the dot command) to visualize it. If you define the macro
++ * DEBUG_RANDOM_TRIE to be 1, then there will be an extremely costly set of
++ * randomized tests done against a trivial implementation, which may take
++ * upwards of a half-hour to complete. There's no set of users who should be
++ * enabling these, and the only developers that should go anywhere near these
++ * nobs are the ones who are reading this comment.
++ */
++
++#ifdef DEBUG
++
++#include <linux/siphash.h>
++
++static __init void swap_endian_and_apply_cidr(u8 *dst, const u8 *src, u8 bits,
++					      u8 cidr)
++{
++	swap_endian(dst, src, bits);
++	memset(dst + (cidr + 7) / 8, 0, bits / 8 - (cidr + 7) / 8);
++	if (cidr)
++		dst[(cidr + 7) / 8 - 1] &= ~0U << ((8 - (cidr % 8)) % 8);
++}
++
++static __init void print_node(struct allowedips_node *node, u8 bits)
++{
++	char *fmt_connection = KERN_DEBUG "\t\"%p/%d\" -> \"%p/%d\";\n";
++	char *fmt_declaration = KERN_DEBUG
++		"\t\"%p/%d\"[style=%s, color=\"#%06x\"];\n";
++	char *style = "dotted";
++	u8 ip1[16], ip2[16];
++	u32 color = 0;
++
++	if (bits == 32) {
++		fmt_connection = KERN_DEBUG "\t\"%pI4/%d\" -> \"%pI4/%d\";\n";
++		fmt_declaration = KERN_DEBUG
++			"\t\"%pI4/%d\"[style=%s, color=\"#%06x\"];\n";
++	} else if (bits == 128) {
++		fmt_connection = KERN_DEBUG "\t\"%pI6/%d\" -> \"%pI6/%d\";\n";
++		fmt_declaration = KERN_DEBUG
++			"\t\"%pI6/%d\"[style=%s, color=\"#%06x\"];\n";
++	}
++	if (node->peer) {
++		hsiphash_key_t key = { { 0 } };
++
++		memcpy(&key, &node->peer, sizeof(node->peer));
++		color = hsiphash_1u32(0xdeadbeef, &key) % 200 << 16 |
++			hsiphash_1u32(0xbabecafe, &key) % 200 << 8 |
++			hsiphash_1u32(0xabad1dea, &key) % 200;
++		style = "bold";
++	}
++	swap_endian_and_apply_cidr(ip1, node->bits, bits, node->cidr);
++	printk(fmt_declaration, ip1, node->cidr, style, color);
++	if (node->bit[0]) {
++		swap_endian_and_apply_cidr(ip2,
++				rcu_dereference_raw(node->bit[0])->bits, bits,
++				node->cidr);
++		printk(fmt_connection, ip1, node->cidr, ip2,
++		       rcu_dereference_raw(node->bit[0])->cidr);
++		print_node(rcu_dereference_raw(node->bit[0]), bits);
++	}
++	if (node->bit[1]) {
++		swap_endian_and_apply_cidr(ip2,
++				rcu_dereference_raw(node->bit[1])->bits,
++				bits, node->cidr);
++		printk(fmt_connection, ip1, node->cidr, ip2,
++		       rcu_dereference_raw(node->bit[1])->cidr);
++		print_node(rcu_dereference_raw(node->bit[1]), bits);
++	}
++}
++
++static __init void print_tree(struct allowedips_node __rcu *top, u8 bits)
++{
++	printk(KERN_DEBUG "digraph trie {\n");
++	print_node(rcu_dereference_raw(top), bits);
++	printk(KERN_DEBUG "}\n");
++}
++
++enum {
++	NUM_PEERS = 2000,
++	NUM_RAND_ROUTES = 400,
++	NUM_MUTATED_ROUTES = 100,
++	NUM_QUERIES = NUM_RAND_ROUTES * NUM_MUTATED_ROUTES * 30
++};
++
++struct horrible_allowedips {
++	struct hlist_head head;
++};
++
++struct horrible_allowedips_node {
++	struct hlist_node table;
++	union nf_inet_addr ip;
++	union nf_inet_addr mask;
++	u8 ip_version;
++	void *value;
++};
++
++static __init void horrible_allowedips_init(struct horrible_allowedips *table)
++{
++	INIT_HLIST_HEAD(&table->head);
++}
++
++static __init void horrible_allowedips_free(struct horrible_allowedips *table)
++{
++	struct horrible_allowedips_node *node;
++	struct hlist_node *h;
++
++	hlist_for_each_entry_safe(node, h, &table->head, table) {
++		hlist_del(&node->table);
++		kfree(node);
++	}
++}
++
++static __init inline union nf_inet_addr horrible_cidr_to_mask(u8 cidr)
++{
++	union nf_inet_addr mask;
++
++	memset(&mask, 0x00, 128 / 8);
++	memset(&mask, 0xff, cidr / 8);
++	if (cidr % 32)
++		mask.all[cidr / 32] = (__force u32)htonl(
++			(0xFFFFFFFFUL << (32 - (cidr % 32))) & 0xFFFFFFFFUL);
++	return mask;
++}
++
++static __init inline u8 horrible_mask_to_cidr(union nf_inet_addr subnet)
++{
++	return hweight32(subnet.all[0]) + hweight32(subnet.all[1]) +
++	       hweight32(subnet.all[2]) + hweight32(subnet.all[3]);
++}
++
++static __init inline void
++horrible_mask_self(struct horrible_allowedips_node *node)
++{
++	if (node->ip_version == 4) {
++		node->ip.ip &= node->mask.ip;
++	} else if (node->ip_version == 6) {
++		node->ip.ip6[0] &= node->mask.ip6[0];
++		node->ip.ip6[1] &= node->mask.ip6[1];
++		node->ip.ip6[2] &= node->mask.ip6[2];
++		node->ip.ip6[3] &= node->mask.ip6[3];
++	}
++}
++
++static __init inline bool
++horrible_match_v4(const struct horrible_allowedips_node *node,
++		  struct in_addr *ip)
++{
++	return (ip->s_addr & node->mask.ip) == node->ip.ip;
++}
++
++static __init inline bool
++horrible_match_v6(const struct horrible_allowedips_node *node,
++		  struct in6_addr *ip)
++{
++	return (ip->in6_u.u6_addr32[0] & node->mask.ip6[0]) ==
++		       node->ip.ip6[0] &&
++	       (ip->in6_u.u6_addr32[1] & node->mask.ip6[1]) ==
++		       node->ip.ip6[1] &&
++	       (ip->in6_u.u6_addr32[2] & node->mask.ip6[2]) ==
++		       node->ip.ip6[2] &&
++	       (ip->in6_u.u6_addr32[3] & node->mask.ip6[3]) == node->ip.ip6[3];
++}
++
++static __init void
++horrible_insert_ordered(struct horrible_allowedips *table,
++			struct horrible_allowedips_node *node)
++{
++	struct horrible_allowedips_node *other = NULL, *where = NULL;
++	u8 my_cidr = horrible_mask_to_cidr(node->mask);
++
++	hlist_for_each_entry(other, &table->head, table) {
++		if (!memcmp(&other->mask, &node->mask,
++			    sizeof(union nf_inet_addr)) &&
++		    !memcmp(&other->ip, &node->ip,
++			    sizeof(union nf_inet_addr)) &&
++		    other->ip_version == node->ip_version) {
++			other->value = node->value;
++			kfree(node);
++			return;
++		}
++		where = other;
++		if (horrible_mask_to_cidr(other->mask) <= my_cidr)
++			break;
++	}
++	if (!other && !where)
++		hlist_add_head(&node->table, &table->head);
++	else if (!other)
++		hlist_add_behind(&node->table, &where->table);
++	else
++		hlist_add_before(&node->table, &where->table);
++}
++
++static __init int
++horrible_allowedips_insert_v4(struct horrible_allowedips *table,
++			      struct in_addr *ip, u8 cidr, void *value)
++{
++	struct horrible_allowedips_node *node = kzalloc(sizeof(*node),
++							GFP_KERNEL);
++
++	if (unlikely(!node))
++		return -ENOMEM;
++	node->ip.in = *ip;
++	node->mask = horrible_cidr_to_mask(cidr);
++	node->ip_version = 4;
++	node->value = value;
++	horrible_mask_self(node);
++	horrible_insert_ordered(table, node);
++	return 0;
++}
++
++static __init int
++horrible_allowedips_insert_v6(struct horrible_allowedips *table,
++			      struct in6_addr *ip, u8 cidr, void *value)
++{
++	struct horrible_allowedips_node *node = kzalloc(sizeof(*node),
++							GFP_KERNEL);
++
++	if (unlikely(!node))
++		return -ENOMEM;
++	node->ip.in6 = *ip;
++	node->mask = horrible_cidr_to_mask(cidr);
++	node->ip_version = 6;
++	node->value = value;
++	horrible_mask_self(node);
++	horrible_insert_ordered(table, node);
++	return 0;
++}
++
++static __init void *
++horrible_allowedips_lookup_v4(struct horrible_allowedips *table,
++			      struct in_addr *ip)
++{
++	struct horrible_allowedips_node *node;
++	void *ret = NULL;
++
++	hlist_for_each_entry(node, &table->head, table) {
++		if (node->ip_version != 4)
++			continue;
++		if (horrible_match_v4(node, ip)) {
++			ret = node->value;
++			break;
++		}
++	}
++	return ret;
++}
++
++static __init void *
++horrible_allowedips_lookup_v6(struct horrible_allowedips *table,
++			      struct in6_addr *ip)
++{
++	struct horrible_allowedips_node *node;
++	void *ret = NULL;
++
++	hlist_for_each_entry(node, &table->head, table) {
++		if (node->ip_version != 6)
++			continue;
++		if (horrible_match_v6(node, ip)) {
++			ret = node->value;
++			break;
++		}
++	}
++	return ret;
++}
++
++static __init bool randomized_test(void)
++{
++	unsigned int i, j, k, mutate_amount, cidr;
++	u8 ip[16], mutate_mask[16], mutated[16];
++	struct wg_peer **peers, *peer;
++	struct horrible_allowedips h;
++	DEFINE_MUTEX(mutex);
++	struct allowedips t;
++	bool ret = false;
++
++	mutex_init(&mutex);
++
++	wg_allowedips_init(&t);
++	horrible_allowedips_init(&h);
++
++	peers = kcalloc(NUM_PEERS, sizeof(*peers), GFP_KERNEL);
++	if (unlikely(!peers)) {
++		pr_err("allowedips random self-test malloc: FAIL\n");
++		goto free;
++	}
++	for (i = 0; i < NUM_PEERS; ++i) {
++		peers[i] = kzalloc(sizeof(*peers[i]), GFP_KERNEL);
++		if (unlikely(!peers[i])) {
++			pr_err("allowedips random self-test malloc: FAIL\n");
++			goto free;
++		}
++		kref_init(&peers[i]->refcount);
++	}
++
++	mutex_lock(&mutex);
++
++	for (i = 0; i < NUM_RAND_ROUTES; ++i) {
++		prandom_bytes(ip, 4);
++		cidr = prandom_u32_max(32) + 1;
++		peer = peers[prandom_u32_max(NUM_PEERS)];
++		if (wg_allowedips_insert_v4(&t, (struct in_addr *)ip, cidr,
++					    peer, &mutex) < 0) {
++			pr_err("allowedips random self-test malloc: FAIL\n");
++			goto free_locked;
++		}
++		if (horrible_allowedips_insert_v4(&h, (struct in_addr *)ip,
++						  cidr, peer) < 0) {
++			pr_err("allowedips random self-test malloc: FAIL\n");
++			goto free_locked;
++		}
++		for (j = 0; j < NUM_MUTATED_ROUTES; ++j) {
++			memcpy(mutated, ip, 4);
++			prandom_bytes(mutate_mask, 4);
++			mutate_amount = prandom_u32_max(32);
++			for (k = 0; k < mutate_amount / 8; ++k)
++				mutate_mask[k] = 0xff;
++			mutate_mask[k] = 0xff
++					 << ((8 - (mutate_amount % 8)) % 8);
++			for (; k < 4; ++k)
++				mutate_mask[k] = 0;
++			for (k = 0; k < 4; ++k)
++				mutated[k] = (mutated[k] & mutate_mask[k]) |
++					     (~mutate_mask[k] &
++					      prandom_u32_max(256));
++			cidr = prandom_u32_max(32) + 1;
++			peer = peers[prandom_u32_max(NUM_PEERS)];
++			if (wg_allowedips_insert_v4(&t,
++						    (struct in_addr *)mutated,
++						    cidr, peer, &mutex) < 0) {
++				pr_err("allowedips random malloc: FAIL\n");
++				goto free_locked;
++			}
++			if (horrible_allowedips_insert_v4(&h,
++				(struct in_addr *)mutated, cidr, peer)) {
++				pr_err("allowedips random self-test malloc: FAIL\n");
++				goto free_locked;
++			}
++		}
++	}
++
++	for (i = 0; i < NUM_RAND_ROUTES; ++i) {
++		prandom_bytes(ip, 16);
++		cidr = prandom_u32_max(128) + 1;
++		peer = peers[prandom_u32_max(NUM_PEERS)];
++		if (wg_allowedips_insert_v6(&t, (struct in6_addr *)ip, cidr,
++					    peer, &mutex) < 0) {
++			pr_err("allowedips random self-test malloc: FAIL\n");
++			goto free_locked;
++		}
++		if (horrible_allowedips_insert_v6(&h, (struct in6_addr *)ip,
++						  cidr, peer) < 0) {
++			pr_err("allowedips random self-test malloc: FAIL\n");
++			goto free_locked;
++		}
++		for (j = 0; j < NUM_MUTATED_ROUTES; ++j) {
++			memcpy(mutated, ip, 16);
++			prandom_bytes(mutate_mask, 16);
++			mutate_amount = prandom_u32_max(128);
++			for (k = 0; k < mutate_amount / 8; ++k)
++				mutate_mask[k] = 0xff;
++			mutate_mask[k] = 0xff
++					 << ((8 - (mutate_amount % 8)) % 8);
++			for (; k < 4; ++k)
++				mutate_mask[k] = 0;
++			for (k = 0; k < 4; ++k)
++				mutated[k] = (mutated[k] & mutate_mask[k]) |
++					     (~mutate_mask[k] &
++					      prandom_u32_max(256));
++			cidr = prandom_u32_max(128) + 1;
++			peer = peers[prandom_u32_max(NUM_PEERS)];
++			if (wg_allowedips_insert_v6(&t,
++						    (struct in6_addr *)mutated,
++						    cidr, peer, &mutex) < 0) {
++				pr_err("allowedips random self-test malloc: FAIL\n");
++				goto free_locked;
++			}
++			if (horrible_allowedips_insert_v6(
++				    &h, (struct in6_addr *)mutated, cidr,
++				    peer)) {
++				pr_err("allowedips random self-test malloc: FAIL\n");
++				goto free_locked;
++			}
++		}
++	}
++
++	mutex_unlock(&mutex);
++
++	if (IS_ENABLED(DEBUG_PRINT_TRIE_GRAPHVIZ)) {
++		print_tree(t.root4, 32);
++		print_tree(t.root6, 128);
++	}
++
++	for (i = 0; i < NUM_QUERIES; ++i) {
++		prandom_bytes(ip, 4);
++		if (lookup(t.root4, 32, ip) !=
++		    horrible_allowedips_lookup_v4(&h, (struct in_addr *)ip)) {
++			pr_err("allowedips random self-test: FAIL\n");
++			goto free;
++		}
++	}
++
++	for (i = 0; i < NUM_QUERIES; ++i) {
++		prandom_bytes(ip, 16);
++		if (lookup(t.root6, 128, ip) !=
++		    horrible_allowedips_lookup_v6(&h, (struct in6_addr *)ip)) {
++			pr_err("allowedips random self-test: FAIL\n");
++			goto free;
++		}
++	}
++	ret = true;
++
++free:
++	mutex_lock(&mutex);
++free_locked:
++	wg_allowedips_free(&t, &mutex);
++	mutex_unlock(&mutex);
++	horrible_allowedips_free(&h);
++	if (peers) {
++		for (i = 0; i < NUM_PEERS; ++i)
++			kfree(peers[i]);
++	}
++	kfree(peers);
++	return ret;
++}
++
++static __init inline struct in_addr *ip4(u8 a, u8 b, u8 c, u8 d)
++{
++	static struct in_addr ip;
++	u8 *split = (u8 *)&ip;
++
++	split[0] = a;
++	split[1] = b;
++	split[2] = c;
++	split[3] = d;
++	return &ip;
++}
++
++static __init inline struct in6_addr *ip6(u32 a, u32 b, u32 c, u32 d)
++{
++	static struct in6_addr ip;
++	__be32 *split = (__be32 *)&ip;
++
++	split[0] = cpu_to_be32(a);
++	split[1] = cpu_to_be32(b);
++	split[2] = cpu_to_be32(c);
++	split[3] = cpu_to_be32(d);
++	return &ip;
++}
++
++static __init struct wg_peer *init_peer(void)
++{
++	struct wg_peer *peer = kzalloc(sizeof(*peer), GFP_KERNEL);
++
++	if (!peer)
++		return NULL;
++	kref_init(&peer->refcount);
++	INIT_LIST_HEAD(&peer->allowedips_list);
++	return peer;
++}
++
++#define insert(version, mem, ipa, ipb, ipc, ipd, cidr)                       \
++	wg_allowedips_insert_v##version(&t, ip##version(ipa, ipb, ipc, ipd), \
++					cidr, mem, &mutex)
++
++#define maybe_fail() do {                                               \
++		++i;                                                    \
++		if (!_s) {                                              \
++			pr_info("allowedips self-test %zu: FAIL\n", i); \
++			success = false;                                \
++		}                                                       \
++	} while (0)
++
++#define test(version, mem, ipa, ipb, ipc, ipd) do {                          \
++		bool _s = lookup(t.root##version, (version) == 4 ? 32 : 128, \
++				 ip##version(ipa, ipb, ipc, ipd)) == (mem);  \
++		maybe_fail();                                                \
++	} while (0)
++
++#define test_negative(version, mem, ipa, ipb, ipc, ipd) do {                 \
++		bool _s = lookup(t.root##version, (version) == 4 ? 32 : 128, \
++				 ip##version(ipa, ipb, ipc, ipd)) != (mem);  \
++		maybe_fail();                                                \
++	} while (0)
++
++#define test_boolean(cond) do {   \
++		bool _s = (cond); \
++		maybe_fail();     \
++	} while (0)
++
++bool __init wg_allowedips_selftest(void)
++{
++	bool found_a = false, found_b = false, found_c = false, found_d = false,
++	     found_e = false, found_other = false;
++	struct wg_peer *a = init_peer(), *b = init_peer(), *c = init_peer(),
++		       *d = init_peer(), *e = init_peer(), *f = init_peer(),
++		       *g = init_peer(), *h = init_peer();
++	struct allowedips_node *iter_node;
++	bool success = false;
++	struct allowedips t;
++	DEFINE_MUTEX(mutex);
++	struct in6_addr ip;
++	size_t i = 0, count = 0;
++	__be64 part;
++
++	mutex_init(&mutex);
++	mutex_lock(&mutex);
++	wg_allowedips_init(&t);
++
++	if (!a || !b || !c || !d || !e || !f || !g || !h) {
++		pr_err("allowedips self-test malloc: FAIL\n");
++		goto free;
++	}
++
++	insert(4, a, 192, 168, 4, 0, 24);
++	insert(4, b, 192, 168, 4, 4, 32);
++	insert(4, c, 192, 168, 0, 0, 16);
++	insert(4, d, 192, 95, 5, 64, 27);
++	/* replaces previous entry, and maskself is required */
++	insert(4, c, 192, 95, 5, 65, 27);
++	insert(6, d, 0x26075300, 0x60006b00, 0, 0xc05f0543, 128);
++	insert(6, c, 0x26075300, 0x60006b00, 0, 0, 64);
++	insert(4, e, 0, 0, 0, 0, 0);
++	insert(6, e, 0, 0, 0, 0, 0);
++	/* replaces previous entry */
++	insert(6, f, 0, 0, 0, 0, 0);
++	insert(6, g, 0x24046800, 0, 0, 0, 32);
++	/* maskself is required */
++	insert(6, h, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef, 64);
++	insert(6, a, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef, 128);
++	insert(6, c, 0x24446800, 0x40e40800, 0xdeaebeef, 0xdefbeef, 128);
++	insert(6, b, 0x24446800, 0xf0e40800, 0xeeaebeef, 0, 98);
++	insert(4, g, 64, 15, 112, 0, 20);
++	/* maskself is required */
++	insert(4, h, 64, 15, 123, 211, 25);
++	insert(4, a, 10, 0, 0, 0, 25);
++	insert(4, b, 10, 0, 0, 128, 25);
++	insert(4, a, 10, 1, 0, 0, 30);
++	insert(4, b, 10, 1, 0, 4, 30);
++	insert(4, c, 10, 1, 0, 8, 29);
++	insert(4, d, 10, 1, 0, 16, 29);
++
++	if (IS_ENABLED(DEBUG_PRINT_TRIE_GRAPHVIZ)) {
++		print_tree(t.root4, 32);
++		print_tree(t.root6, 128);
++	}
++
++	success = true;
++
++	test(4, a, 192, 168, 4, 20);
++	test(4, a, 192, 168, 4, 0);
++	test(4, b, 192, 168, 4, 4);
++	test(4, c, 192, 168, 200, 182);
++	test(4, c, 192, 95, 5, 68);
++	test(4, e, 192, 95, 5, 96);
++	test(6, d, 0x26075300, 0x60006b00, 0, 0xc05f0543);
++	test(6, c, 0x26075300, 0x60006b00, 0, 0xc02e01ee);
++	test(6, f, 0x26075300, 0x60006b01, 0, 0);
++	test(6, g, 0x24046800, 0x40040806, 0, 0x1006);
++	test(6, g, 0x24046800, 0x40040806, 0x1234, 0x5678);
++	test(6, f, 0x240467ff, 0x40040806, 0x1234, 0x5678);
++	test(6, f, 0x24046801, 0x40040806, 0x1234, 0x5678);
++	test(6, h, 0x24046800, 0x40040800, 0x1234, 0x5678);
++	test(6, h, 0x24046800, 0x40040800, 0, 0);
++	test(6, h, 0x24046800, 0x40040800, 0x10101010, 0x10101010);
++	test(6, a, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef);
++	test(4, g, 64, 15, 116, 26);
++	test(4, g, 64, 15, 127, 3);
++	test(4, g, 64, 15, 123, 1);
++	test(4, h, 64, 15, 123, 128);
++	test(4, h, 64, 15, 123, 129);
++	test(4, a, 10, 0, 0, 52);
++	test(4, b, 10, 0, 0, 220);
++	test(4, a, 10, 1, 0, 2);
++	test(4, b, 10, 1, 0, 6);
++	test(4, c, 10, 1, 0, 10);
++	test(4, d, 10, 1, 0, 20);
++
++	insert(4, a, 1, 0, 0, 0, 32);
++	insert(4, a, 64, 0, 0, 0, 32);
++	insert(4, a, 128, 0, 0, 0, 32);
++	insert(4, a, 192, 0, 0, 0, 32);
++	insert(4, a, 255, 0, 0, 0, 32);
++	wg_allowedips_remove_by_peer(&t, a, &mutex);
++	test_negative(4, a, 1, 0, 0, 0);
++	test_negative(4, a, 64, 0, 0, 0);
++	test_negative(4, a, 128, 0, 0, 0);
++	test_negative(4, a, 192, 0, 0, 0);
++	test_negative(4, a, 255, 0, 0, 0);
++
++	wg_allowedips_free(&t, &mutex);
++	wg_allowedips_init(&t);
++	insert(4, a, 192, 168, 0, 0, 16);
++	insert(4, a, 192, 168, 0, 0, 24);
++	wg_allowedips_remove_by_peer(&t, a, &mutex);
++	test_negative(4, a, 192, 168, 0, 1);
++
++	/* These will hit the WARN_ON(len >= 128) in free_node if something
++	 * goes wrong.
++	 */
++	for (i = 0; i < 128; ++i) {
++		part = cpu_to_be64(~(1LLU << (i % 64)));
++		memset(&ip, 0xff, 16);
++		memcpy((u8 *)&ip + (i < 64) * 8, &part, 8);
++		wg_allowedips_insert_v6(&t, &ip, 128, a, &mutex);
++	}
++
++	wg_allowedips_free(&t, &mutex);
++
++	wg_allowedips_init(&t);
++	insert(4, a, 192, 95, 5, 93, 27);
++	insert(6, a, 0x26075300, 0x60006b00, 0, 0xc05f0543, 128);
++	insert(4, a, 10, 1, 0, 20, 29);
++	insert(6, a, 0x26075300, 0x6d8a6bf8, 0xdab1f1df, 0xc05f1523, 83);
++	insert(6, a, 0x26075300, 0x6d8a6bf8, 0xdab1f1df, 0xc05f1523, 21);
++	list_for_each_entry(iter_node, &a->allowedips_list, peer_list) {
++		u8 cidr, ip[16] __aligned(__alignof(u64));
++		int family = wg_allowedips_read_node(iter_node, ip, &cidr);
++
++		count++;
++
++		if (cidr == 27 && family == AF_INET &&
++		    !memcmp(ip, ip4(192, 95, 5, 64), sizeof(struct in_addr)))
++			found_a = true;
++		else if (cidr == 128 && family == AF_INET6 &&
++			 !memcmp(ip, ip6(0x26075300, 0x60006b00, 0, 0xc05f0543),
++				 sizeof(struct in6_addr)))
++			found_b = true;
++		else if (cidr == 29 && family == AF_INET &&
++			 !memcmp(ip, ip4(10, 1, 0, 16), sizeof(struct in_addr)))
++			found_c = true;
++		else if (cidr == 83 && family == AF_INET6 &&
++			 !memcmp(ip, ip6(0x26075300, 0x6d8a6bf8, 0xdab1e000, 0),
++				 sizeof(struct in6_addr)))
++			found_d = true;
++		else if (cidr == 21 && family == AF_INET6 &&
++			 !memcmp(ip, ip6(0x26075000, 0, 0, 0),
++				 sizeof(struct in6_addr)))
++			found_e = true;
++		else
++			found_other = true;
++	}
++	test_boolean(count == 5);
++	test_boolean(found_a);
++	test_boolean(found_b);
++	test_boolean(found_c);
++	test_boolean(found_d);
++	test_boolean(found_e);
++	test_boolean(!found_other);
++
++	if (IS_ENABLED(DEBUG_RANDOM_TRIE) && success)
++		success = randomized_test();
++
++	if (success)
++		pr_info("allowedips self-tests: pass\n");
++
++free:
++	wg_allowedips_free(&t, &mutex);
++	kfree(a);
++	kfree(b);
++	kfree(c);
++	kfree(d);
++	kfree(e);
++	kfree(f);
++	kfree(g);
++	kfree(h);
++	mutex_unlock(&mutex);
++
++	return success;
++}
++
++#undef test_negative
++#undef test
++#undef remove
++#undef insert
++#undef init_peer
++
++#endif
+--- /dev/null
++++ b/drivers/net/wireguard/selftest/counter.c
+@@ -0,0 +1,104 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#ifdef DEBUG
++bool __init wg_packet_counter_selftest(void)
++{
++	unsigned int test_num = 0, i;
++	union noise_counter counter;
++	bool success = true;
++
++#define T_INIT do {                                               \
++		memset(&counter, 0, sizeof(union noise_counter)); \
++		spin_lock_init(&counter.receive.lock);            \
++	} while (0)
++#define T_LIM (COUNTER_WINDOW_SIZE + 1)
++#define T(n, v) do {                                                  \
++		++test_num;                                           \
++		if (counter_validate(&counter, n) != (v)) {           \
++			pr_err("nonce counter self-test %u: FAIL\n",  \
++			       test_num);                             \
++			success = false;                              \
++		}                                                     \
++	} while (0)
++
++	T_INIT;
++	/*  1 */ T(0, true);
++	/*  2 */ T(1, true);
++	/*  3 */ T(1, false);
++	/*  4 */ T(9, true);
++	/*  5 */ T(8, true);
++	/*  6 */ T(7, true);
++	/*  7 */ T(7, false);
++	/*  8 */ T(T_LIM, true);
++	/*  9 */ T(T_LIM - 1, true);
++	/* 10 */ T(T_LIM - 1, false);
++	/* 11 */ T(T_LIM - 2, true);
++	/* 12 */ T(2, true);
++	/* 13 */ T(2, false);
++	/* 14 */ T(T_LIM + 16, true);
++	/* 15 */ T(3, false);
++	/* 16 */ T(T_LIM + 16, false);
++	/* 17 */ T(T_LIM * 4, true);
++	/* 18 */ T(T_LIM * 4 - (T_LIM - 1), true);
++	/* 19 */ T(10, false);
++	/* 20 */ T(T_LIM * 4 - T_LIM, false);
++	/* 21 */ T(T_LIM * 4 - (T_LIM + 1), false);
++	/* 22 */ T(T_LIM * 4 - (T_LIM - 2), true);
++	/* 23 */ T(T_LIM * 4 + 1 - T_LIM, false);
++	/* 24 */ T(0, false);
++	/* 25 */ T(REJECT_AFTER_MESSAGES, false);
++	/* 26 */ T(REJECT_AFTER_MESSAGES - 1, true);
++	/* 27 */ T(REJECT_AFTER_MESSAGES, false);
++	/* 28 */ T(REJECT_AFTER_MESSAGES - 1, false);
++	/* 29 */ T(REJECT_AFTER_MESSAGES - 2, true);
++	/* 30 */ T(REJECT_AFTER_MESSAGES + 1, false);
++	/* 31 */ T(REJECT_AFTER_MESSAGES + 2, false);
++	/* 32 */ T(REJECT_AFTER_MESSAGES - 2, false);
++	/* 33 */ T(REJECT_AFTER_MESSAGES - 3, true);
++	/* 34 */ T(0, false);
++
++	T_INIT;
++	for (i = 1; i <= COUNTER_WINDOW_SIZE; ++i)
++		T(i, true);
++	T(0, true);
++	T(0, false);
++
++	T_INIT;
++	for (i = 2; i <= COUNTER_WINDOW_SIZE + 1; ++i)
++		T(i, true);
++	T(1, true);
++	T(0, false);
++
++	T_INIT;
++	for (i = COUNTER_WINDOW_SIZE + 1; i-- > 0;)
++		T(i, true);
++
++	T_INIT;
++	for (i = COUNTER_WINDOW_SIZE + 2; i-- > 1;)
++		T(i, true);
++	T(0, false);
++
++	T_INIT;
++	for (i = COUNTER_WINDOW_SIZE + 1; i-- > 1;)
++		T(i, true);
++	T(COUNTER_WINDOW_SIZE + 1, true);
++	T(0, false);
++
++	T_INIT;
++	for (i = COUNTER_WINDOW_SIZE + 1; i-- > 1;)
++		T(i, true);
++	T(0, true);
++	T(COUNTER_WINDOW_SIZE + 1, true);
++
++#undef T
++#undef T_LIM
++#undef T_INIT
++
++	if (success)
++		pr_info("nonce counter self-tests: pass\n");
++	return success;
++}
++#endif
+--- /dev/null
++++ b/drivers/net/wireguard/selftest/ratelimiter.c
+@@ -0,0 +1,226 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#ifdef DEBUG
++
++#include <linux/jiffies.h>
++
++static const struct {
++	bool result;
++	unsigned int msec_to_sleep_before;
++} expected_results[] __initconst = {
++	[0 ... PACKETS_BURSTABLE - 1] = { true, 0 },
++	[PACKETS_BURSTABLE] = { false, 0 },
++	[PACKETS_BURSTABLE + 1] = { true, MSEC_PER_SEC / PACKETS_PER_SECOND },
++	[PACKETS_BURSTABLE + 2] = { false, 0 },
++	[PACKETS_BURSTABLE + 3] = { true, (MSEC_PER_SEC / PACKETS_PER_SECOND) * 2 },
++	[PACKETS_BURSTABLE + 4] = { true, 0 },
++	[PACKETS_BURSTABLE + 5] = { false, 0 }
++};
++
++static __init unsigned int maximum_jiffies_at_index(int index)
++{
++	unsigned int total_msecs = 2 * MSEC_PER_SEC / PACKETS_PER_SECOND / 3;
++	int i;
++
++	for (i = 0; i <= index; ++i)
++		total_msecs += expected_results[i].msec_to_sleep_before;
++	return msecs_to_jiffies(total_msecs);
++}
++
++static __init int timings_test(struct sk_buff *skb4, struct iphdr *hdr4,
++			       struct sk_buff *skb6, struct ipv6hdr *hdr6,
++			       int *test)
++{
++	unsigned long loop_start_time;
++	int i;
++
++	wg_ratelimiter_gc_entries(NULL);
++	rcu_barrier();
++	loop_start_time = jiffies;
++
++	for (i = 0; i < ARRAY_SIZE(expected_results); ++i) {
++		if (expected_results[i].msec_to_sleep_before)
++			msleep(expected_results[i].msec_to_sleep_before);
++
++		if (time_is_before_jiffies(loop_start_time +
++					   maximum_jiffies_at_index(i)))
++			return -ETIMEDOUT;
++		if (wg_ratelimiter_allow(skb4, &init_net) !=
++					expected_results[i].result)
++			return -EXFULL;
++		++(*test);
++
++		hdr4->saddr = htonl(ntohl(hdr4->saddr) + i + 1);
++		if (time_is_before_jiffies(loop_start_time +
++					   maximum_jiffies_at_index(i)))
++			return -ETIMEDOUT;
++		if (!wg_ratelimiter_allow(skb4, &init_net))
++			return -EXFULL;
++		++(*test);
++
++		hdr4->saddr = htonl(ntohl(hdr4->saddr) - i - 1);
++
++#if IS_ENABLED(CONFIG_IPV6)
++		hdr6->saddr.in6_u.u6_addr32[2] = htonl(i);
++		hdr6->saddr.in6_u.u6_addr32[3] = htonl(i);
++		if (time_is_before_jiffies(loop_start_time +
++					   maximum_jiffies_at_index(i)))
++			return -ETIMEDOUT;
++		if (wg_ratelimiter_allow(skb6, &init_net) !=
++					expected_results[i].result)
++			return -EXFULL;
++		++(*test);
++
++		hdr6->saddr.in6_u.u6_addr32[0] =
++			htonl(ntohl(hdr6->saddr.in6_u.u6_addr32[0]) + i + 1);
++		if (time_is_before_jiffies(loop_start_time +
++					   maximum_jiffies_at_index(i)))
++			return -ETIMEDOUT;
++		if (!wg_ratelimiter_allow(skb6, &init_net))
++			return -EXFULL;
++		++(*test);
++
++		hdr6->saddr.in6_u.u6_addr32[0] =
++			htonl(ntohl(hdr6->saddr.in6_u.u6_addr32[0]) - i - 1);
++
++		if (time_is_before_jiffies(loop_start_time +
++					   maximum_jiffies_at_index(i)))
++			return -ETIMEDOUT;
++#endif
++	}
++	return 0;
++}
++
++static __init int capacity_test(struct sk_buff *skb4, struct iphdr *hdr4,
++				int *test)
++{
++	int i;
++
++	wg_ratelimiter_gc_entries(NULL);
++	rcu_barrier();
++
++	if (atomic_read(&total_entries))
++		return -EXFULL;
++	++(*test);
++
++	for (i = 0; i <= max_entries; ++i) {
++		hdr4->saddr = htonl(i);
++		if (wg_ratelimiter_allow(skb4, &init_net) != (i != max_entries))
++			return -EXFULL;
++		++(*test);
++	}
++	return 0;
++}
++
++bool __init wg_ratelimiter_selftest(void)
++{
++	enum { TRIALS_BEFORE_GIVING_UP = 5000 };
++	bool success = false;
++	int test = 0, trials;
++	struct sk_buff *skb4, *skb6;
++	struct iphdr *hdr4;
++	struct ipv6hdr *hdr6;
++
++	if (IS_ENABLED(CONFIG_KASAN) || IS_ENABLED(CONFIG_UBSAN))
++		return true;
++
++	BUILD_BUG_ON(MSEC_PER_SEC % PACKETS_PER_SECOND != 0);
++
++	if (wg_ratelimiter_init())
++		goto out;
++	++test;
++	if (wg_ratelimiter_init()) {
++		wg_ratelimiter_uninit();
++		goto out;
++	}
++	++test;
++	if (wg_ratelimiter_init()) {
++		wg_ratelimiter_uninit();
++		wg_ratelimiter_uninit();
++		goto out;
++	}
++	++test;
++
++	skb4 = alloc_skb(sizeof(struct iphdr), GFP_KERNEL);
++	if (unlikely(!skb4))
++		goto err_nofree;
++	skb4->protocol = htons(ETH_P_IP);
++	hdr4 = (struct iphdr *)skb_put(skb4, sizeof(*hdr4));
++	hdr4->saddr = htonl(8182);
++	skb_reset_network_header(skb4);
++	++test;
++
++#if IS_ENABLED(CONFIG_IPV6)
++	skb6 = alloc_skb(sizeof(struct ipv6hdr), GFP_KERNEL);
++	if (unlikely(!skb6)) {
++		kfree_skb(skb4);
++		goto err_nofree;
++	}
++	skb6->protocol = htons(ETH_P_IPV6);
++	hdr6 = (struct ipv6hdr *)skb_put(skb6, sizeof(*hdr6));
++	hdr6->saddr.in6_u.u6_addr32[0] = htonl(1212);
++	hdr6->saddr.in6_u.u6_addr32[1] = htonl(289188);
++	skb_reset_network_header(skb6);
++	++test;
++#endif
++
++	for (trials = TRIALS_BEFORE_GIVING_UP;;) {
++		int test_count = 0, ret;
++
++		ret = timings_test(skb4, hdr4, skb6, hdr6, &test_count);
++		if (ret == -ETIMEDOUT) {
++			if (!trials--) {
++				test += test_count;
++				goto err;
++			}
++			msleep(500);
++			continue;
++		} else if (ret < 0) {
++			test += test_count;
++			goto err;
++		} else {
++			test += test_count;
++			break;
++		}
++	}
++
++	for (trials = TRIALS_BEFORE_GIVING_UP;;) {
++		int test_count = 0;
++
++		if (capacity_test(skb4, hdr4, &test_count) < 0) {
++			if (!trials--) {
++				test += test_count;
++				goto err;
++			}
++			msleep(50);
++			continue;
++		}
++		test += test_count;
++		break;
++	}
++
++	success = true;
++
++err:
++	kfree_skb(skb4);
++#if IS_ENABLED(CONFIG_IPV6)
++	kfree_skb(skb6);
++#endif
++err_nofree:
++	wg_ratelimiter_uninit();
++	wg_ratelimiter_uninit();
++	wg_ratelimiter_uninit();
++	/* Uninit one extra time to check underflow detection. */
++	wg_ratelimiter_uninit();
++out:
++	if (success)
++		pr_info("ratelimiter self-tests: pass\n");
++	else
++		pr_err("ratelimiter self-test %d: FAIL\n", test);
++
++	return success;
++}
++#endif
+--- /dev/null
++++ b/drivers/net/wireguard/send.c
+@@ -0,0 +1,413 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#include "queueing.h"
++#include "timers.h"
++#include "device.h"
++#include "peer.h"
++#include "socket.h"
++#include "messages.h"
++#include "cookie.h"
++
++#include <linux/uio.h>
++#include <linux/inetdevice.h>
++#include <linux/socket.h>
++#include <net/ip_tunnels.h>
++#include <net/udp.h>
++#include <net/sock.h>
++
++static void wg_packet_send_handshake_initiation(struct wg_peer *peer)
++{
++	struct message_handshake_initiation packet;
++
++	if (!wg_birthdate_has_expired(atomic64_read(&peer->last_sent_handshake),
++				      REKEY_TIMEOUT))
++		return; /* This function is rate limited. */
++
++	atomic64_set(&peer->last_sent_handshake, ktime_get_coarse_boottime_ns());
++	net_dbg_ratelimited("%s: Sending handshake initiation to peer %llu (%pISpfsc)\n",
++			    peer->device->dev->name, peer->internal_id,
++			    &peer->endpoint.addr);
++
++	if (wg_noise_handshake_create_initiation(&packet, &peer->handshake)) {
++		wg_cookie_add_mac_to_packet(&packet, sizeof(packet), peer);
++		wg_timers_any_authenticated_packet_traversal(peer);
++		wg_timers_any_authenticated_packet_sent(peer);
++		atomic64_set(&peer->last_sent_handshake,
++			     ktime_get_coarse_boottime_ns());
++		wg_socket_send_buffer_to_peer(peer, &packet, sizeof(packet),
++					      HANDSHAKE_DSCP);
++		wg_timers_handshake_initiated(peer);
++	}
++}
++
++void wg_packet_handshake_send_worker(struct work_struct *work)
++{
++	struct wg_peer *peer = container_of(work, struct wg_peer,
++					    transmit_handshake_work);
++
++	wg_packet_send_handshake_initiation(peer);
++	wg_peer_put(peer);
++}
++
++void wg_packet_send_queued_handshake_initiation(struct wg_peer *peer,
++						bool is_retry)
++{
++	if (!is_retry)
++		peer->timer_handshake_attempts = 0;
++
++	rcu_read_lock_bh();
++	/* We check last_sent_handshake here in addition to the actual function
++	 * we're queueing up, so that we don't queue things if not strictly
++	 * necessary:
++	 */
++	if (!wg_birthdate_has_expired(atomic64_read(&peer->last_sent_handshake),
++				      REKEY_TIMEOUT) ||
++			unlikely(READ_ONCE(peer->is_dead)))
++		goto out;
++
++	wg_peer_get(peer);
++	/* Queues up calling packet_send_queued_handshakes(peer), where we do a
++	 * peer_put(peer) after:
++	 */
++	if (!queue_work(peer->device->handshake_send_wq,
++			&peer->transmit_handshake_work))
++		/* If the work was already queued, we want to drop the
++		 * extra reference:
++		 */
++		wg_peer_put(peer);
++out:
++	rcu_read_unlock_bh();
++}
++
++void wg_packet_send_handshake_response(struct wg_peer *peer)
++{
++	struct message_handshake_response packet;
++
++	atomic64_set(&peer->last_sent_handshake, ktime_get_coarse_boottime_ns());
++	net_dbg_ratelimited("%s: Sending handshake response to peer %llu (%pISpfsc)\n",
++			    peer->device->dev->name, peer->internal_id,
++			    &peer->endpoint.addr);
++
++	if (wg_noise_handshake_create_response(&packet, &peer->handshake)) {
++		wg_cookie_add_mac_to_packet(&packet, sizeof(packet), peer);
++		if (wg_noise_handshake_begin_session(&peer->handshake,
++						     &peer->keypairs)) {
++			wg_timers_session_derived(peer);
++			wg_timers_any_authenticated_packet_traversal(peer);
++			wg_timers_any_authenticated_packet_sent(peer);
++			atomic64_set(&peer->last_sent_handshake,
++				     ktime_get_coarse_boottime_ns());
++			wg_socket_send_buffer_to_peer(peer, &packet,
++						      sizeof(packet),
++						      HANDSHAKE_DSCP);
++		}
++	}
++}
++
++void wg_packet_send_handshake_cookie(struct wg_device *wg,
++				     struct sk_buff *initiating_skb,
++				     __le32 sender_index)
++{
++	struct message_handshake_cookie packet;
++
++	net_dbg_skb_ratelimited("%s: Sending cookie response for denied handshake message for %pISpfsc\n",
++				wg->dev->name, initiating_skb);
++	wg_cookie_message_create(&packet, initiating_skb, sender_index,
++				 &wg->cookie_checker);
++	wg_socket_send_buffer_as_reply_to_skb(wg, initiating_skb, &packet,
++					      sizeof(packet));
++}
++
++static void keep_key_fresh(struct wg_peer *peer)
++{
++	struct noise_keypair *keypair;
++	bool send = false;
++
++	rcu_read_lock_bh();
++	keypair = rcu_dereference_bh(peer->keypairs.current_keypair);
++	if (likely(keypair && READ_ONCE(keypair->sending.is_valid)) &&
++	    (unlikely(atomic64_read(&keypair->sending.counter.counter) >
++		      REKEY_AFTER_MESSAGES) ||
++	     (keypair->i_am_the_initiator &&
++	      unlikely(wg_birthdate_has_expired(keypair->sending.birthdate,
++						REKEY_AFTER_TIME)))))
++		send = true;
++	rcu_read_unlock_bh();
++
++	if (send)
++		wg_packet_send_queued_handshake_initiation(peer, false);
++}
++
++static unsigned int calculate_skb_padding(struct sk_buff *skb)
++{
++	/* We do this modulo business with the MTU, just in case the networking
++	 * layer gives us a packet that's bigger than the MTU. In that case, we
++	 * wouldn't want the final subtraction to overflow in the case of the
++	 * padded_size being clamped.
++	 */
++	unsigned int last_unit = skb->len % PACKET_CB(skb)->mtu;
++	unsigned int padded_size = ALIGN(last_unit, MESSAGE_PADDING_MULTIPLE);
++
++	if (padded_size > PACKET_CB(skb)->mtu)
++		padded_size = PACKET_CB(skb)->mtu;
++	return padded_size - last_unit;
++}
++
++static bool encrypt_packet(struct sk_buff *skb, struct noise_keypair *keypair)
++{
++	unsigned int padding_len, plaintext_len, trailer_len;
++	struct scatterlist sg[MAX_SKB_FRAGS + 8];
++	struct message_data *header;
++	struct sk_buff *trailer;
++	int num_frags;
++
++	/* Calculate lengths. */
++	padding_len = calculate_skb_padding(skb);
++	trailer_len = padding_len + noise_encrypted_len(0);
++	plaintext_len = skb->len + padding_len;
++
++	/* Expand data section to have room for padding and auth tag. */
++	num_frags = skb_cow_data(skb, trailer_len, &trailer);
++	if (unlikely(num_frags < 0 || num_frags > ARRAY_SIZE(sg)))
++		return false;
++
++	/* Set the padding to zeros, and make sure it and the auth tag are part
++	 * of the skb.
++	 */
++	memset(skb_tail_pointer(trailer), 0, padding_len);
++
++	/* Expand head section to have room for our header and the network
++	 * stack's headers.
++	 */
++	if (unlikely(skb_cow_head(skb, DATA_PACKET_HEAD_ROOM) < 0))
++		return false;
++
++	/* Finalize checksum calculation for the inner packet, if required. */
++	if (unlikely(skb->ip_summed == CHECKSUM_PARTIAL &&
++		     skb_checksum_help(skb)))
++		return false;
++
++	/* Only after checksumming can we safely add on the padding at the end
++	 * and the header.
++	 */
++	skb_set_inner_network_header(skb, 0);
++	header = (struct message_data *)skb_push(skb, sizeof(*header));
++	header->header.type = cpu_to_le32(MESSAGE_DATA);
++	header->key_idx = keypair->remote_index;
++	header->counter = cpu_to_le64(PACKET_CB(skb)->nonce);
++	pskb_put(skb, trailer, trailer_len);
++
++	/* Now we can encrypt the scattergather segments */
++	sg_init_table(sg, num_frags);
++	if (skb_to_sgvec(skb, sg, sizeof(struct message_data),
++			 noise_encrypted_len(plaintext_len)) <= 0)
++		return false;
++	return chacha20poly1305_encrypt_sg_inplace(sg, plaintext_len, NULL, 0,
++						   PACKET_CB(skb)->nonce,
++						   keypair->sending.key);
++}
++
++void wg_packet_send_keepalive(struct wg_peer *peer)
++{
++	struct sk_buff *skb;
++
++	if (skb_queue_empty(&peer->staged_packet_queue)) {
++		skb = alloc_skb(DATA_PACKET_HEAD_ROOM + MESSAGE_MINIMUM_LENGTH,
++				GFP_ATOMIC);
++		if (unlikely(!skb))
++			return;
++		skb_reserve(skb, DATA_PACKET_HEAD_ROOM);
++		skb->dev = peer->device->dev;
++		PACKET_CB(skb)->mtu = skb->dev->mtu;
++		skb_queue_tail(&peer->staged_packet_queue, skb);
++		net_dbg_ratelimited("%s: Sending keepalive packet to peer %llu (%pISpfsc)\n",
++				    peer->device->dev->name, peer->internal_id,
++				    &peer->endpoint.addr);
++	}
++
++	wg_packet_send_staged_packets(peer);
++}
++
++static void wg_packet_create_data_done(struct sk_buff *first,
++				       struct wg_peer *peer)
++{
++	struct sk_buff *skb, *next;
++	bool is_keepalive, data_sent = false;
++
++	wg_timers_any_authenticated_packet_traversal(peer);
++	wg_timers_any_authenticated_packet_sent(peer);
++	skb_list_walk_safe(first, skb, next) {
++		is_keepalive = skb->len == message_data_len(0);
++		if (likely(!wg_socket_send_skb_to_peer(peer, skb,
++				PACKET_CB(skb)->ds) && !is_keepalive))
++			data_sent = true;
++	}
++
++	if (likely(data_sent))
++		wg_timers_data_sent(peer);
++
++	keep_key_fresh(peer);
++}
++
++void wg_packet_tx_worker(struct work_struct *work)
++{
++	struct crypt_queue *queue = container_of(work, struct crypt_queue,
++						 work);
++	struct noise_keypair *keypair;
++	enum packet_state state;
++	struct sk_buff *first;
++	struct wg_peer *peer;
++
++	while ((first = __ptr_ring_peek(&queue->ring)) != NULL &&
++	       (state = atomic_read_acquire(&PACKET_CB(first)->state)) !=
++		       PACKET_STATE_UNCRYPTED) {
++		__ptr_ring_discard_one(&queue->ring);
++		peer = PACKET_PEER(first);
++		keypair = PACKET_CB(first)->keypair;
++
++		if (likely(state == PACKET_STATE_CRYPTED))
++			wg_packet_create_data_done(first, peer);
++		else
++			kfree_skb_list(first);
++
++		wg_noise_keypair_put(keypair, false);
++		wg_peer_put(peer);
++	}
++}
++
++void wg_packet_encrypt_worker(struct work_struct *work)
++{
++	struct crypt_queue *queue = container_of(work, struct multicore_worker,
++						 work)->ptr;
++	struct sk_buff *first, *skb, *next;
++
++	while ((first = ptr_ring_consume_bh(&queue->ring)) != NULL) {
++		enum packet_state state = PACKET_STATE_CRYPTED;
++
++		skb_list_walk_safe(first, skb, next) {
++			if (likely(encrypt_packet(skb,
++					PACKET_CB(first)->keypair))) {
++				wg_reset_packet(skb);
++			} else {
++				state = PACKET_STATE_DEAD;
++				break;
++			}
++		}
++		wg_queue_enqueue_per_peer(&PACKET_PEER(first)->tx_queue, first,
++					  state);
++
++	}
++}
++
++static void wg_packet_create_data(struct sk_buff *first)
++{
++	struct wg_peer *peer = PACKET_PEER(first);
++	struct wg_device *wg = peer->device;
++	int ret = -EINVAL;
++
++	rcu_read_lock_bh();
++	if (unlikely(READ_ONCE(peer->is_dead)))
++		goto err;
++
++	ret = wg_queue_enqueue_per_device_and_peer(&wg->encrypt_queue,
++						   &peer->tx_queue, first,
++						   wg->packet_crypt_wq,
++						   &wg->encrypt_queue.last_cpu);
++	if (unlikely(ret == -EPIPE))
++		wg_queue_enqueue_per_peer(&peer->tx_queue, first,
++					  PACKET_STATE_DEAD);
++err:
++	rcu_read_unlock_bh();
++	if (likely(!ret || ret == -EPIPE))
++		return;
++	wg_noise_keypair_put(PACKET_CB(first)->keypair, false);
++	wg_peer_put(peer);
++	kfree_skb_list(first);
++}
++
++void wg_packet_purge_staged_packets(struct wg_peer *peer)
++{
++	spin_lock_bh(&peer->staged_packet_queue.lock);
++	peer->device->dev->stats.tx_dropped += peer->staged_packet_queue.qlen;
++	__skb_queue_purge(&peer->staged_packet_queue);
++	spin_unlock_bh(&peer->staged_packet_queue.lock);
++}
++
++void wg_packet_send_staged_packets(struct wg_peer *peer)
++{
++	struct noise_symmetric_key *key;
++	struct noise_keypair *keypair;
++	struct sk_buff_head packets;
++	struct sk_buff *skb;
++
++	/* Steal the current queue into our local one. */
++	__skb_queue_head_init(&packets);
++	spin_lock_bh(&peer->staged_packet_queue.lock);
++	skb_queue_splice_init(&peer->staged_packet_queue, &packets);
++	spin_unlock_bh(&peer->staged_packet_queue.lock);
++	if (unlikely(skb_queue_empty(&packets)))
++		return;
++
++	/* First we make sure we have a valid reference to a valid key. */
++	rcu_read_lock_bh();
++	keypair = wg_noise_keypair_get(
++		rcu_dereference_bh(peer->keypairs.current_keypair));
++	rcu_read_unlock_bh();
++	if (unlikely(!keypair))
++		goto out_nokey;
++	key = &keypair->sending;
++	if (unlikely(!READ_ONCE(key->is_valid)))
++		goto out_nokey;
++	if (unlikely(wg_birthdate_has_expired(key->birthdate,
++					      REJECT_AFTER_TIME)))
++		goto out_invalid;
++
++	/* After we know we have a somewhat valid key, we now try to assign
++	 * nonces to all of the packets in the queue. If we can't assign nonces
++	 * for all of them, we just consider it a failure and wait for the next
++	 * handshake.
++	 */
++	skb_queue_walk(&packets, skb) {
++		/* 0 for no outer TOS: no leak. TODO: at some later point, we
++		 * might consider using flowi->tos as outer instead.
++		 */
++		PACKET_CB(skb)->ds = ip_tunnel_ecn_encap(0, ip_hdr(skb), skb);
++		PACKET_CB(skb)->nonce =
++				atomic64_inc_return(&key->counter.counter) - 1;
++		if (unlikely(PACKET_CB(skb)->nonce >= REJECT_AFTER_MESSAGES))
++			goto out_invalid;
++	}
++
++	packets.prev->next = NULL;
++	wg_peer_get(keypair->entry.peer);
++	PACKET_CB(packets.next)->keypair = keypair;
++	wg_packet_create_data(packets.next);
++	return;
++
++out_invalid:
++	WRITE_ONCE(key->is_valid, false);
++out_nokey:
++	wg_noise_keypair_put(keypair, false);
++
++	/* We orphan the packets if we're waiting on a handshake, so that they
++	 * don't block a socket's pool.
++	 */
++	skb_queue_walk(&packets, skb)
++		skb_orphan(skb);
++	/* Then we put them back on the top of the queue. We're not too
++	 * concerned about accidentally getting things a little out of order if
++	 * packets are being added really fast, because this queue is for before
++	 * packets can even be sent and it's small anyway.
++	 */
++	spin_lock_bh(&peer->staged_packet_queue.lock);
++	skb_queue_splice(&packets, &peer->staged_packet_queue);
++	spin_unlock_bh(&peer->staged_packet_queue.lock);
++
++	/* If we're exiting because there's something wrong with the key, it
++	 * means we should initiate a new handshake.
++	 */
++	wg_packet_send_queued_handshake_initiation(peer, false);
++}
+--- /dev/null
++++ b/drivers/net/wireguard/socket.c
+@@ -0,0 +1,437 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#include "device.h"
++#include "peer.h"
++#include "socket.h"
++#include "queueing.h"
++#include "messages.h"
++
++#include <linux/ctype.h>
++#include <linux/net.h>
++#include <linux/if_vlan.h>
++#include <linux/if_ether.h>
++#include <linux/inetdevice.h>
++#include <net/udp_tunnel.h>
++#include <net/ipv6.h>
++
++static int send4(struct wg_device *wg, struct sk_buff *skb,
++		 struct endpoint *endpoint, u8 ds, struct dst_cache *cache)
++{
++	struct flowi4 fl = {
++		.saddr = endpoint->src4.s_addr,
++		.daddr = endpoint->addr4.sin_addr.s_addr,
++		.fl4_dport = endpoint->addr4.sin_port,
++		.flowi4_mark = wg->fwmark,
++		.flowi4_proto = IPPROTO_UDP
++	};
++	struct rtable *rt = NULL;
++	struct sock *sock;
++	int ret = 0;
++
++	skb_mark_not_on_list(skb);
++	skb->dev = wg->dev;
++	skb->mark = wg->fwmark;
++
++	rcu_read_lock_bh();
++	sock = rcu_dereference_bh(wg->sock4);
++
++	if (unlikely(!sock)) {
++		ret = -ENONET;
++		goto err;
++	}
++
++	fl.fl4_sport = inet_sk(sock)->inet_sport;
++
++	if (cache)
++		rt = dst_cache_get_ip4(cache, &fl.saddr);
++
++	if (!rt) {
++		security_sk_classify_flow(sock, flowi4_to_flowi(&fl));
++		if (unlikely(!inet_confirm_addr(sock_net(sock), NULL, 0,
++						fl.saddr, RT_SCOPE_HOST))) {
++			endpoint->src4.s_addr = 0;
++			*(__force __be32 *)&endpoint->src_if4 = 0;
++			fl.saddr = 0;
++			if (cache)
++				dst_cache_reset(cache);
++		}
++		rt = ip_route_output_flow(sock_net(sock), &fl, sock);
++		if (unlikely(endpoint->src_if4 && ((IS_ERR(rt) &&
++			     PTR_ERR(rt) == -EINVAL) || (!IS_ERR(rt) &&
++			     rt->dst.dev->ifindex != endpoint->src_if4)))) {
++			endpoint->src4.s_addr = 0;
++			*(__force __be32 *)&endpoint->src_if4 = 0;
++			fl.saddr = 0;
++			if (cache)
++				dst_cache_reset(cache);
++			if (!IS_ERR(rt))
++				ip_rt_put(rt);
++			rt = ip_route_output_flow(sock_net(sock), &fl, sock);
++		}
++		if (unlikely(IS_ERR(rt))) {
++			ret = PTR_ERR(rt);
++			net_dbg_ratelimited("%s: No route to %pISpfsc, error %d\n",
++					    wg->dev->name, &endpoint->addr, ret);
++			goto err;
++		} else if (unlikely(rt->dst.dev == skb->dev)) {
++			ip_rt_put(rt);
++			ret = -ELOOP;
++			net_dbg_ratelimited("%s: Avoiding routing loop to %pISpfsc\n",
++					    wg->dev->name, &endpoint->addr);
++			goto err;
++		}
++		if (cache)
++			dst_cache_set_ip4(cache, &rt->dst, fl.saddr);
++	}
++
++	skb->ignore_df = 1;
++	udp_tunnel_xmit_skb(rt, sock, skb, fl.saddr, fl.daddr, ds,
++			    ip4_dst_hoplimit(&rt->dst), 0, fl.fl4_sport,
++			    fl.fl4_dport, false, false);
++	goto out;
++
++err:
++	kfree_skb(skb);
++out:
++	rcu_read_unlock_bh();
++	return ret;
++}
++
++static int send6(struct wg_device *wg, struct sk_buff *skb,
++		 struct endpoint *endpoint, u8 ds, struct dst_cache *cache)
++{
++#if IS_ENABLED(CONFIG_IPV6)
++	struct flowi6 fl = {
++		.saddr = endpoint->src6,
++		.daddr = endpoint->addr6.sin6_addr,
++		.fl6_dport = endpoint->addr6.sin6_port,
++		.flowi6_mark = wg->fwmark,
++		.flowi6_oif = endpoint->addr6.sin6_scope_id,
++		.flowi6_proto = IPPROTO_UDP
++		/* TODO: addr->sin6_flowinfo */
++	};
++	struct dst_entry *dst = NULL;
++	struct sock *sock;
++	int ret = 0;
++
++	skb_mark_not_on_list(skb);
++	skb->dev = wg->dev;
++	skb->mark = wg->fwmark;
++
++	rcu_read_lock_bh();
++	sock = rcu_dereference_bh(wg->sock6);
++
++	if (unlikely(!sock)) {
++		ret = -ENONET;
++		goto err;
++	}
++
++	fl.fl6_sport = inet_sk(sock)->inet_sport;
++
++	if (cache)
++		dst = dst_cache_get_ip6(cache, &fl.saddr);
++
++	if (!dst) {
++		security_sk_classify_flow(sock, flowi6_to_flowi(&fl));
++		if (unlikely(!ipv6_addr_any(&fl.saddr) &&
++			     !ipv6_chk_addr(sock_net(sock), &fl.saddr, NULL, 0))) {
++			endpoint->src6 = fl.saddr = in6addr_any;
++			if (cache)
++				dst_cache_reset(cache);
++		}
++		dst = ipv6_stub->ipv6_dst_lookup_flow(sock_net(sock), sock, &fl,
++						      NULL);
++		if (unlikely(IS_ERR(dst))) {
++			ret = PTR_ERR(dst);
++			net_dbg_ratelimited("%s: No route to %pISpfsc, error %d\n",
++					    wg->dev->name, &endpoint->addr, ret);
++			goto err;
++		} else if (unlikely(dst->dev == skb->dev)) {
++			dst_release(dst);
++			ret = -ELOOP;
++			net_dbg_ratelimited("%s: Avoiding routing loop to %pISpfsc\n",
++					    wg->dev->name, &endpoint->addr);
++			goto err;
++		}
++		if (cache)
++			dst_cache_set_ip6(cache, dst, &fl.saddr);
++	}
++
++	skb->ignore_df = 1;
++	udp_tunnel6_xmit_skb(dst, sock, skb, skb->dev, &fl.saddr, &fl.daddr, ds,
++			     ip6_dst_hoplimit(dst), 0, fl.fl6_sport,
++			     fl.fl6_dport, false);
++	goto out;
++
++err:
++	kfree_skb(skb);
++out:
++	rcu_read_unlock_bh();
++	return ret;
++#else
++	return -EAFNOSUPPORT;
++#endif
++}
++
++int wg_socket_send_skb_to_peer(struct wg_peer *peer, struct sk_buff *skb, u8 ds)
++{
++	size_t skb_len = skb->len;
++	int ret = -EAFNOSUPPORT;
++
++	read_lock_bh(&peer->endpoint_lock);
++	if (peer->endpoint.addr.sa_family == AF_INET)
++		ret = send4(peer->device, skb, &peer->endpoint, ds,
++			    &peer->endpoint_cache);
++	else if (peer->endpoint.addr.sa_family == AF_INET6)
++		ret = send6(peer->device, skb, &peer->endpoint, ds,
++			    &peer->endpoint_cache);
++	else
++		dev_kfree_skb(skb);
++	if (likely(!ret))
++		peer->tx_bytes += skb_len;
++	read_unlock_bh(&peer->endpoint_lock);
++
++	return ret;
++}
++
++int wg_socket_send_buffer_to_peer(struct wg_peer *peer, void *buffer,
++				  size_t len, u8 ds)
++{
++	struct sk_buff *skb = alloc_skb(len + SKB_HEADER_LEN, GFP_ATOMIC);
++
++	if (unlikely(!skb))
++		return -ENOMEM;
++
++	skb_reserve(skb, SKB_HEADER_LEN);
++	skb_set_inner_network_header(skb, 0);
++	skb_put_data(skb, buffer, len);
++	return wg_socket_send_skb_to_peer(peer, skb, ds);
++}
++
++int wg_socket_send_buffer_as_reply_to_skb(struct wg_device *wg,
++					  struct sk_buff *in_skb, void *buffer,
++					  size_t len)
++{
++	int ret = 0;
++	struct sk_buff *skb;
++	struct endpoint endpoint;
++
++	if (unlikely(!in_skb))
++		return -EINVAL;
++	ret = wg_socket_endpoint_from_skb(&endpoint, in_skb);
++	if (unlikely(ret < 0))
++		return ret;
++
++	skb = alloc_skb(len + SKB_HEADER_LEN, GFP_ATOMIC);
++	if (unlikely(!skb))
++		return -ENOMEM;
++	skb_reserve(skb, SKB_HEADER_LEN);
++	skb_set_inner_network_header(skb, 0);
++	skb_put_data(skb, buffer, len);
++
++	if (endpoint.addr.sa_family == AF_INET)
++		ret = send4(wg, skb, &endpoint, 0, NULL);
++	else if (endpoint.addr.sa_family == AF_INET6)
++		ret = send6(wg, skb, &endpoint, 0, NULL);
++	/* No other possibilities if the endpoint is valid, which it is,
++	 * as we checked above.
++	 */
++
++	return ret;
++}
++
++int wg_socket_endpoint_from_skb(struct endpoint *endpoint,
++				const struct sk_buff *skb)
++{
++	memset(endpoint, 0, sizeof(*endpoint));
++	if (skb->protocol == htons(ETH_P_IP)) {
++		endpoint->addr4.sin_family = AF_INET;
++		endpoint->addr4.sin_port = udp_hdr(skb)->source;
++		endpoint->addr4.sin_addr.s_addr = ip_hdr(skb)->saddr;
++		endpoint->src4.s_addr = ip_hdr(skb)->daddr;
++		endpoint->src_if4 = skb->skb_iif;
++	} else if (skb->protocol == htons(ETH_P_IPV6)) {
++		endpoint->addr6.sin6_family = AF_INET6;
++		endpoint->addr6.sin6_port = udp_hdr(skb)->source;
++		endpoint->addr6.sin6_addr = ipv6_hdr(skb)->saddr;
++		endpoint->addr6.sin6_scope_id = ipv6_iface_scope_id(
++			&ipv6_hdr(skb)->saddr, skb->skb_iif);
++		endpoint->src6 = ipv6_hdr(skb)->daddr;
++	} else {
++		return -EINVAL;
++	}
++	return 0;
++}
++
++static bool endpoint_eq(const struct endpoint *a, const struct endpoint *b)
++{
++	return (a->addr.sa_family == AF_INET && b->addr.sa_family == AF_INET &&
++		a->addr4.sin_port == b->addr4.sin_port &&
++		a->addr4.sin_addr.s_addr == b->addr4.sin_addr.s_addr &&
++		a->src4.s_addr == b->src4.s_addr && a->src_if4 == b->src_if4) ||
++	       (a->addr.sa_family == AF_INET6 &&
++		b->addr.sa_family == AF_INET6 &&
++		a->addr6.sin6_port == b->addr6.sin6_port &&
++		ipv6_addr_equal(&a->addr6.sin6_addr, &b->addr6.sin6_addr) &&
++		a->addr6.sin6_scope_id == b->addr6.sin6_scope_id &&
++		ipv6_addr_equal(&a->src6, &b->src6)) ||
++	       unlikely(!a->addr.sa_family && !b->addr.sa_family);
++}
++
++void wg_socket_set_peer_endpoint(struct wg_peer *peer,
++				 const struct endpoint *endpoint)
++{
++	/* First we check unlocked, in order to optimize, since it's pretty rare
++	 * that an endpoint will change. If we happen to be mid-write, and two
++	 * CPUs wind up writing the same thing or something slightly different,
++	 * it doesn't really matter much either.
++	 */
++	if (endpoint_eq(endpoint, &peer->endpoint))
++		return;
++	write_lock_bh(&peer->endpoint_lock);
++	if (endpoint->addr.sa_family == AF_INET) {
++		peer->endpoint.addr4 = endpoint->addr4;
++		peer->endpoint.src4 = endpoint->src4;
++		peer->endpoint.src_if4 = endpoint->src_if4;
++	} else if (endpoint->addr.sa_family == AF_INET6) {
++		peer->endpoint.addr6 = endpoint->addr6;
++		peer->endpoint.src6 = endpoint->src6;
++	} else {
++		goto out;
++	}
++	dst_cache_reset(&peer->endpoint_cache);
++out:
++	write_unlock_bh(&peer->endpoint_lock);
++}
++
++void wg_socket_set_peer_endpoint_from_skb(struct wg_peer *peer,
++					  const struct sk_buff *skb)
++{
++	struct endpoint endpoint;
++
++	if (!wg_socket_endpoint_from_skb(&endpoint, skb))
++		wg_socket_set_peer_endpoint(peer, &endpoint);
++}
++
++void wg_socket_clear_peer_endpoint_src(struct wg_peer *peer)
++{
++	write_lock_bh(&peer->endpoint_lock);
++	memset(&peer->endpoint.src6, 0, sizeof(peer->endpoint.src6));
++	dst_cache_reset(&peer->endpoint_cache);
++	write_unlock_bh(&peer->endpoint_lock);
++}
++
++static int wg_receive(struct sock *sk, struct sk_buff *skb)
++{
++	struct wg_device *wg;
++
++	if (unlikely(!sk))
++		goto err;
++	wg = sk->sk_user_data;
++	if (unlikely(!wg))
++		goto err;
++	wg_packet_receive(wg, skb);
++	return 0;
++
++err:
++	kfree_skb(skb);
++	return 0;
++}
++
++static void sock_free(struct sock *sock)
++{
++	if (unlikely(!sock))
++		return;
++	sk_clear_memalloc(sock);
++	udp_tunnel_sock_release(sock->sk_socket);
++}
++
++static void set_sock_opts(struct socket *sock)
++{
++	sock->sk->sk_allocation = GFP_ATOMIC;
++	sock->sk->sk_sndbuf = INT_MAX;
++	sk_set_memalloc(sock->sk);
++}
++
++int wg_socket_init(struct wg_device *wg, u16 port)
++{
++	int ret;
++	struct udp_tunnel_sock_cfg cfg = {
++		.sk_user_data = wg,
++		.encap_type = 1,
++		.encap_rcv = wg_receive
++	};
++	struct socket *new4 = NULL, *new6 = NULL;
++	struct udp_port_cfg port4 = {
++		.family = AF_INET,
++		.local_ip.s_addr = htonl(INADDR_ANY),
++		.local_udp_port = htons(port),
++		.use_udp_checksums = true
++	};
++#if IS_ENABLED(CONFIG_IPV6)
++	int retries = 0;
++	struct udp_port_cfg port6 = {
++		.family = AF_INET6,
++		.local_ip6 = IN6ADDR_ANY_INIT,
++		.use_udp6_tx_checksums = true,
++		.use_udp6_rx_checksums = true,
++		.ipv6_v6only = true
++	};
++#endif
++
++#if IS_ENABLED(CONFIG_IPV6)
++retry:
++#endif
++
++	ret = udp_sock_create(wg->creating_net, &port4, &new4);
++	if (ret < 0) {
++		pr_err("%s: Could not create IPv4 socket\n", wg->dev->name);
++		return ret;
++	}
++	set_sock_opts(new4);
++	setup_udp_tunnel_sock(wg->creating_net, new4, &cfg);
++
++#if IS_ENABLED(CONFIG_IPV6)
++	if (ipv6_mod_enabled()) {
++		port6.local_udp_port = inet_sk(new4->sk)->inet_sport;
++		ret = udp_sock_create(wg->creating_net, &port6, &new6);
++		if (ret < 0) {
++			udp_tunnel_sock_release(new4);
++			if (ret == -EADDRINUSE && !port && retries++ < 100)
++				goto retry;
++			pr_err("%s: Could not create IPv6 socket\n",
++			       wg->dev->name);
++			return ret;
++		}
++		set_sock_opts(new6);
++		setup_udp_tunnel_sock(wg->creating_net, new6, &cfg);
++	}
++#endif
++
++	wg_socket_reinit(wg, new4->sk, new6 ? new6->sk : NULL);
++	return 0;
++}
++
++void wg_socket_reinit(struct wg_device *wg, struct sock *new4,
++		      struct sock *new6)
++{
++	struct sock *old4, *old6;
++
++	mutex_lock(&wg->socket_update_lock);
++	old4 = rcu_dereference_protected(wg->sock4,
++				lockdep_is_held(&wg->socket_update_lock));
++	old6 = rcu_dereference_protected(wg->sock6,
++				lockdep_is_held(&wg->socket_update_lock));
++	rcu_assign_pointer(wg->sock4, new4);
++	rcu_assign_pointer(wg->sock6, new6);
++	if (new4)
++		wg->incoming_port = ntohs(inet_sk(new4)->inet_sport);
++	mutex_unlock(&wg->socket_update_lock);
++	synchronize_rcu();
++	synchronize_net();
++	sock_free(old4);
++	sock_free(old6);
++}
+--- /dev/null
++++ b/drivers/net/wireguard/socket.h
+@@ -0,0 +1,44 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#ifndef _WG_SOCKET_H
++#define _WG_SOCKET_H
++
++#include <linux/netdevice.h>
++#include <linux/udp.h>
++#include <linux/if_vlan.h>
++#include <linux/if_ether.h>
++
++int wg_socket_init(struct wg_device *wg, u16 port);
++void wg_socket_reinit(struct wg_device *wg, struct sock *new4,
++		      struct sock *new6);
++int wg_socket_send_buffer_to_peer(struct wg_peer *peer, void *data,
++				  size_t len, u8 ds);
++int wg_socket_send_skb_to_peer(struct wg_peer *peer, struct sk_buff *skb,
++			       u8 ds);
++int wg_socket_send_buffer_as_reply_to_skb(struct wg_device *wg,
++					  struct sk_buff *in_skb,
++					  void *out_buffer, size_t len);
++
++int wg_socket_endpoint_from_skb(struct endpoint *endpoint,
++				const struct sk_buff *skb);
++void wg_socket_set_peer_endpoint(struct wg_peer *peer,
++				 const struct endpoint *endpoint);
++void wg_socket_set_peer_endpoint_from_skb(struct wg_peer *peer,
++					  const struct sk_buff *skb);
++void wg_socket_clear_peer_endpoint_src(struct wg_peer *peer);
++
++#if defined(CONFIG_DYNAMIC_DEBUG) || defined(DEBUG)
++#define net_dbg_skb_ratelimited(fmt, dev, skb, ...) do {                       \
++		struct endpoint __endpoint;                                    \
++		wg_socket_endpoint_from_skb(&__endpoint, skb);                 \
++		net_dbg_ratelimited(fmt, dev, &__endpoint.addr,                \
++				    ##__VA_ARGS__);                            \
++	} while (0)
++#else
++#define net_dbg_skb_ratelimited(fmt, skb, ...)
++#endif
++
++#endif /* _WG_SOCKET_H */
+--- /dev/null
++++ b/drivers/net/wireguard/timers.c
+@@ -0,0 +1,243 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#include "timers.h"
++#include "device.h"
++#include "peer.h"
++#include "queueing.h"
++#include "socket.h"
++
++/*
++ * - Timer for retransmitting the handshake if we don't hear back after
++ * `REKEY_TIMEOUT + jitter` ms.
++ *
++ * - Timer for sending empty packet if we have received a packet but after have
++ * not sent one for `KEEPALIVE_TIMEOUT` ms.
++ *
++ * - Timer for initiating new handshake if we have sent a packet but after have
++ * not received one (even empty) for `(KEEPALIVE_TIMEOUT + REKEY_TIMEOUT) +
++ * jitter` ms.
++ *
++ * - Timer for zeroing out all ephemeral keys after `(REJECT_AFTER_TIME * 3)` ms
++ * if no new keys have been received.
++ *
++ * - Timer for, if enabled, sending an empty authenticated packet every user-
++ * specified seconds.
++ */
++
++static inline void mod_peer_timer(struct wg_peer *peer,
++				  struct timer_list *timer,
++				  unsigned long expires)
++{
++	rcu_read_lock_bh();
++	if (likely(netif_running(peer->device->dev) &&
++		   !READ_ONCE(peer->is_dead)))
++		mod_timer(timer, expires);
++	rcu_read_unlock_bh();
++}
++
++static void wg_expired_retransmit_handshake(struct timer_list *timer)
++{
++	struct wg_peer *peer = from_timer(peer, timer,
++					  timer_retransmit_handshake);
++
++	if (peer->timer_handshake_attempts > MAX_TIMER_HANDSHAKES) {
++		pr_debug("%s: Handshake for peer %llu (%pISpfsc) did not complete after %d attempts, giving up\n",
++			 peer->device->dev->name, peer->internal_id,
++			 &peer->endpoint.addr, MAX_TIMER_HANDSHAKES + 2);
++
++		del_timer(&peer->timer_send_keepalive);
++		/* We drop all packets without a keypair and don't try again,
++		 * if we try unsuccessfully for too long to make a handshake.
++		 */
++		wg_packet_purge_staged_packets(peer);
++
++		/* We set a timer for destroying any residue that might be left
++		 * of a partial exchange.
++		 */
++		if (!timer_pending(&peer->timer_zero_key_material))
++			mod_peer_timer(peer, &peer->timer_zero_key_material,
++				       jiffies + REJECT_AFTER_TIME * 3 * HZ);
++	} else {
++		++peer->timer_handshake_attempts;
++		pr_debug("%s: Handshake for peer %llu (%pISpfsc) did not complete after %d seconds, retrying (try %d)\n",
++			 peer->device->dev->name, peer->internal_id,
++			 &peer->endpoint.addr, REKEY_TIMEOUT,
++			 peer->timer_handshake_attempts + 1);
++
++		/* We clear the endpoint address src address, in case this is
++		 * the cause of trouble.
++		 */
++		wg_socket_clear_peer_endpoint_src(peer);
++
++		wg_packet_send_queued_handshake_initiation(peer, true);
++	}
++}
++
++static void wg_expired_send_keepalive(struct timer_list *timer)
++{
++	struct wg_peer *peer = from_timer(peer, timer, timer_send_keepalive);
++
++	wg_packet_send_keepalive(peer);
++	if (peer->timer_need_another_keepalive) {
++		peer->timer_need_another_keepalive = false;
++		mod_peer_timer(peer, &peer->timer_send_keepalive,
++			       jiffies + KEEPALIVE_TIMEOUT * HZ);
++	}
++}
++
++static void wg_expired_new_handshake(struct timer_list *timer)
++{
++	struct wg_peer *peer = from_timer(peer, timer, timer_new_handshake);
++
++	pr_debug("%s: Retrying handshake with peer %llu (%pISpfsc) because we stopped hearing back after %d seconds\n",
++		 peer->device->dev->name, peer->internal_id,
++		 &peer->endpoint.addr, KEEPALIVE_TIMEOUT + REKEY_TIMEOUT);
++	/* We clear the endpoint address src address, in case this is the cause
++	 * of trouble.
++	 */
++	wg_socket_clear_peer_endpoint_src(peer);
++	wg_packet_send_queued_handshake_initiation(peer, false);
++}
++
++static void wg_expired_zero_key_material(struct timer_list *timer)
++{
++	struct wg_peer *peer = from_timer(peer, timer, timer_zero_key_material);
++
++	rcu_read_lock_bh();
++	if (!READ_ONCE(peer->is_dead)) {
++		wg_peer_get(peer);
++		if (!queue_work(peer->device->handshake_send_wq,
++				&peer->clear_peer_work))
++			/* If the work was already on the queue, we want to drop
++			 * the extra reference.
++			 */
++			wg_peer_put(peer);
++	}
++	rcu_read_unlock_bh();
++}
++
++static void wg_queued_expired_zero_key_material(struct work_struct *work)
++{
++	struct wg_peer *peer = container_of(work, struct wg_peer,
++					    clear_peer_work);
++
++	pr_debug("%s: Zeroing out all keys for peer %llu (%pISpfsc), since we haven't received a new one in %d seconds\n",
++		 peer->device->dev->name, peer->internal_id,
++		 &peer->endpoint.addr, REJECT_AFTER_TIME * 3);
++	wg_noise_handshake_clear(&peer->handshake);
++	wg_noise_keypairs_clear(&peer->keypairs);
++	wg_peer_put(peer);
++}
++
++static void wg_expired_send_persistent_keepalive(struct timer_list *timer)
++{
++	struct wg_peer *peer = from_timer(peer, timer,
++					  timer_persistent_keepalive);
++
++	if (likely(peer->persistent_keepalive_interval))
++		wg_packet_send_keepalive(peer);
++}
++
++/* Should be called after an authenticated data packet is sent. */
++void wg_timers_data_sent(struct wg_peer *peer)
++{
++	if (!timer_pending(&peer->timer_new_handshake))
++		mod_peer_timer(peer, &peer->timer_new_handshake,
++			jiffies + (KEEPALIVE_TIMEOUT + REKEY_TIMEOUT) * HZ +
++			prandom_u32_max(REKEY_TIMEOUT_JITTER_MAX_JIFFIES));
++}
++
++/* Should be called after an authenticated data packet is received. */
++void wg_timers_data_received(struct wg_peer *peer)
++{
++	if (likely(netif_running(peer->device->dev))) {
++		if (!timer_pending(&peer->timer_send_keepalive))
++			mod_peer_timer(peer, &peer->timer_send_keepalive,
++				       jiffies + KEEPALIVE_TIMEOUT * HZ);
++		else
++			peer->timer_need_another_keepalive = true;
++	}
++}
++
++/* Should be called after any type of authenticated packet is sent, whether
++ * keepalive, data, or handshake.
++ */
++void wg_timers_any_authenticated_packet_sent(struct wg_peer *peer)
++{
++	del_timer(&peer->timer_send_keepalive);
++}
++
++/* Should be called after any type of authenticated packet is received, whether
++ * keepalive, data, or handshake.
++ */
++void wg_timers_any_authenticated_packet_received(struct wg_peer *peer)
++{
++	del_timer(&peer->timer_new_handshake);
++}
++
++/* Should be called after a handshake initiation message is sent. */
++void wg_timers_handshake_initiated(struct wg_peer *peer)
++{
++	mod_peer_timer(peer, &peer->timer_retransmit_handshake,
++		       jiffies + REKEY_TIMEOUT * HZ +
++		       prandom_u32_max(REKEY_TIMEOUT_JITTER_MAX_JIFFIES));
++}
++
++/* Should be called after a handshake response message is received and processed
++ * or when getting key confirmation via the first data message.
++ */
++void wg_timers_handshake_complete(struct wg_peer *peer)
++{
++	del_timer(&peer->timer_retransmit_handshake);
++	peer->timer_handshake_attempts = 0;
++	peer->sent_lastminute_handshake = false;
++	ktime_get_real_ts64(&peer->walltime_last_handshake);
++}
++
++/* Should be called after an ephemeral key is created, which is before sending a
++ * handshake response or after receiving a handshake response.
++ */
++void wg_timers_session_derived(struct wg_peer *peer)
++{
++	mod_peer_timer(peer, &peer->timer_zero_key_material,
++		       jiffies + REJECT_AFTER_TIME * 3 * HZ);
++}
++
++/* Should be called before a packet with authentication, whether
++ * keepalive, data, or handshakem is sent, or after one is received.
++ */
++void wg_timers_any_authenticated_packet_traversal(struct wg_peer *peer)
++{
++	if (peer->persistent_keepalive_interval)
++		mod_peer_timer(peer, &peer->timer_persistent_keepalive,
++			jiffies + peer->persistent_keepalive_interval * HZ);
++}
++
++void wg_timers_init(struct wg_peer *peer)
++{
++	timer_setup(&peer->timer_retransmit_handshake,
++		    wg_expired_retransmit_handshake, 0);
++	timer_setup(&peer->timer_send_keepalive, wg_expired_send_keepalive, 0);
++	timer_setup(&peer->timer_new_handshake, wg_expired_new_handshake, 0);
++	timer_setup(&peer->timer_zero_key_material,
++		    wg_expired_zero_key_material, 0);
++	timer_setup(&peer->timer_persistent_keepalive,
++		    wg_expired_send_persistent_keepalive, 0);
++	INIT_WORK(&peer->clear_peer_work, wg_queued_expired_zero_key_material);
++	peer->timer_handshake_attempts = 0;
++	peer->sent_lastminute_handshake = false;
++	peer->timer_need_another_keepalive = false;
++}
++
++void wg_timers_stop(struct wg_peer *peer)
++{
++	del_timer_sync(&peer->timer_retransmit_handshake);
++	del_timer_sync(&peer->timer_send_keepalive);
++	del_timer_sync(&peer->timer_new_handshake);
++	del_timer_sync(&peer->timer_zero_key_material);
++	del_timer_sync(&peer->timer_persistent_keepalive);
++	flush_work(&peer->clear_peer_work);
++}
+--- /dev/null
++++ b/drivers/net/wireguard/timers.h
+@@ -0,0 +1,31 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#ifndef _WG_TIMERS_H
++#define _WG_TIMERS_H
++
++#include <linux/ktime.h>
++
++struct wg_peer;
++
++void wg_timers_init(struct wg_peer *peer);
++void wg_timers_stop(struct wg_peer *peer);
++void wg_timers_data_sent(struct wg_peer *peer);
++void wg_timers_data_received(struct wg_peer *peer);
++void wg_timers_any_authenticated_packet_sent(struct wg_peer *peer);
++void wg_timers_any_authenticated_packet_received(struct wg_peer *peer);
++void wg_timers_handshake_initiated(struct wg_peer *peer);
++void wg_timers_handshake_complete(struct wg_peer *peer);
++void wg_timers_session_derived(struct wg_peer *peer);
++void wg_timers_any_authenticated_packet_traversal(struct wg_peer *peer);
++
++static inline bool wg_birthdate_has_expired(u64 birthday_nanoseconds,
++					    u64 expiration_seconds)
++{
++	return (s64)(birthday_nanoseconds + expiration_seconds * NSEC_PER_SEC)
++		<= (s64)ktime_get_coarse_boottime_ns();
++}
++
++#endif /* _WG_TIMERS_H */
+--- /dev/null
++++ b/drivers/net/wireguard/version.h
+@@ -0,0 +1 @@
++#define WIREGUARD_VERSION "1.0.0"
+--- /dev/null
++++ b/include/uapi/linux/wireguard.h
+@@ -0,0 +1,196 @@
++/* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR MIT */
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ *
++ * Documentation
++ * =============
++ *
++ * The below enums and macros are for interfacing with WireGuard, using generic
++ * netlink, with family WG_GENL_NAME and version WG_GENL_VERSION. It defines two
++ * methods: get and set. Note that while they share many common attributes,
++ * these two functions actually accept a slightly different set of inputs and
++ * outputs.
++ *
++ * WG_CMD_GET_DEVICE
++ * -----------------
++ *
++ * May only be called via NLM_F_REQUEST | NLM_F_DUMP. The command should contain
++ * one but not both of:
++ *
++ *    WGDEVICE_A_IFINDEX: NLA_U32
++ *    WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMESIZ - 1
++ *
++ * The kernel will then return several messages (NLM_F_MULTI) containing the
++ * following tree of nested items:
++ *
++ *    WGDEVICE_A_IFINDEX: NLA_U32
++ *    WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMESIZ - 1
++ *    WGDEVICE_A_PRIVATE_KEY: NLA_EXACT_LEN, len WG_KEY_LEN
++ *    WGDEVICE_A_PUBLIC_KEY: NLA_EXACT_LEN, len WG_KEY_LEN
++ *    WGDEVICE_A_LISTEN_PORT: NLA_U16
++ *    WGDEVICE_A_FWMARK: NLA_U32
++ *    WGDEVICE_A_PEERS: NLA_NESTED
++ *        0: NLA_NESTED
++ *            WGPEER_A_PUBLIC_KEY: NLA_EXACT_LEN, len WG_KEY_LEN
++ *            WGPEER_A_PRESHARED_KEY: NLA_EXACT_LEN, len WG_KEY_LEN
++ *            WGPEER_A_ENDPOINT: NLA_MIN_LEN(struct sockaddr), struct sockaddr_in or struct sockaddr_in6
++ *            WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL: NLA_U16
++ *            WGPEER_A_LAST_HANDSHAKE_TIME: NLA_EXACT_LEN, struct __kernel_timespec
++ *            WGPEER_A_RX_BYTES: NLA_U64
++ *            WGPEER_A_TX_BYTES: NLA_U64
++ *            WGPEER_A_ALLOWEDIPS: NLA_NESTED
++ *                0: NLA_NESTED
++ *                    WGALLOWEDIP_A_FAMILY: NLA_U16
++ *                    WGALLOWEDIP_A_IPADDR: NLA_MIN_LEN(struct in_addr), struct in_addr or struct in6_addr
++ *                    WGALLOWEDIP_A_CIDR_MASK: NLA_U8
++ *                0: NLA_NESTED
++ *                    ...
++ *                0: NLA_NESTED
++ *                    ...
++ *                ...
++ *            WGPEER_A_PROTOCOL_VERSION: NLA_U32
++ *        0: NLA_NESTED
++ *            ...
++ *        ...
++ *
++ * It is possible that all of the allowed IPs of a single peer will not
++ * fit within a single netlink message. In that case, the same peer will
++ * be written in the following message, except it will only contain
++ * WGPEER_A_PUBLIC_KEY and WGPEER_A_ALLOWEDIPS. This may occur several
++ * times in a row for the same peer. It is then up to the receiver to
++ * coalesce adjacent peers. Likewise, it is possible that all peers will
++ * not fit within a single message. So, subsequent peers will be sent
++ * in following messages, except those will only contain WGDEVICE_A_IFNAME
++ * and WGDEVICE_A_PEERS. It is then up to the receiver to coalesce these
++ * messages to form the complete list of peers.
++ *
++ * Since this is an NLA_F_DUMP command, the final message will always be
++ * NLMSG_DONE, even if an error occurs. However, this NLMSG_DONE message
++ * contains an integer error code. It is either zero or a negative error
++ * code corresponding to the errno.
++ *
++ * WG_CMD_SET_DEVICE
++ * -----------------
++ *
++ * May only be called via NLM_F_REQUEST. The command should contain the
++ * following tree of nested items, containing one but not both of
++ * WGDEVICE_A_IFINDEX and WGDEVICE_A_IFNAME:
++ *
++ *    WGDEVICE_A_IFINDEX: NLA_U32
++ *    WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMESIZ - 1
++ *    WGDEVICE_A_FLAGS: NLA_U32, 0 or WGDEVICE_F_REPLACE_PEERS if all current
++ *                      peers should be removed prior to adding the list below.
++ *    WGDEVICE_A_PRIVATE_KEY: len WG_KEY_LEN, all zeros to remove
++ *    WGDEVICE_A_LISTEN_PORT: NLA_U16, 0 to choose randomly
++ *    WGDEVICE_A_FWMARK: NLA_U32, 0 to disable
++ *    WGDEVICE_A_PEERS: NLA_NESTED
++ *        0: NLA_NESTED
++ *            WGPEER_A_PUBLIC_KEY: len WG_KEY_LEN
++ *            WGPEER_A_FLAGS: NLA_U32, 0 and/or WGPEER_F_REMOVE_ME if the
++ *                            specified peer should not exist at the end of the
++ *                            operation, rather than added/updated and/or
++ *                            WGPEER_F_REPLACE_ALLOWEDIPS if all current allowed
++ *                            IPs of this peer should be removed prior to adding
++ *                            the list below and/or WGPEER_F_UPDATE_ONLY if the
++ *                            peer should only be set if it already exists.
++ *            WGPEER_A_PRESHARED_KEY: len WG_KEY_LEN, all zeros to remove
++ *            WGPEER_A_ENDPOINT: struct sockaddr_in or struct sockaddr_in6
++ *            WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL: NLA_U16, 0 to disable
++ *            WGPEER_A_ALLOWEDIPS: NLA_NESTED
++ *                0: NLA_NESTED
++ *                    WGALLOWEDIP_A_FAMILY: NLA_U16
++ *                    WGALLOWEDIP_A_IPADDR: struct in_addr or struct in6_addr
++ *                    WGALLOWEDIP_A_CIDR_MASK: NLA_U8
++ *                0: NLA_NESTED
++ *                    ...
++ *                0: NLA_NESTED
++ *                    ...
++ *                ...
++ *            WGPEER_A_PROTOCOL_VERSION: NLA_U32, should not be set or used at
++ *                                       all by most users of this API, as the
++ *                                       most recent protocol will be used when
++ *                                       this is unset. Otherwise, must be set
++ *                                       to 1.
++ *        0: NLA_NESTED
++ *            ...
++ *        ...
++ *
++ * It is possible that the amount of configuration data exceeds that of
++ * the maximum message length accepted by the kernel. In that case, several
++ * messages should be sent one after another, with each successive one
++ * filling in information not contained in the prior. Note that if
++ * WGDEVICE_F_REPLACE_PEERS is specified in the first message, it probably
++ * should not be specified in fragments that come after, so that the list
++ * of peers is only cleared the first time but appened after. Likewise for
++ * peers, if WGPEER_F_REPLACE_ALLOWEDIPS is specified in the first message
++ * of a peer, it likely should not be specified in subsequent fragments.
++ *
++ * If an error occurs, NLMSG_ERROR will reply containing an errno.
++ */
++
++#ifndef _WG_UAPI_WIREGUARD_H
++#define _WG_UAPI_WIREGUARD_H
++
++#define WG_GENL_NAME "wireguard"
++#define WG_GENL_VERSION 1
++
++#define WG_KEY_LEN 32
++
++enum wg_cmd {
++	WG_CMD_GET_DEVICE,
++	WG_CMD_SET_DEVICE,
++	__WG_CMD_MAX
++};
++#define WG_CMD_MAX (__WG_CMD_MAX - 1)
++
++enum wgdevice_flag {
++	WGDEVICE_F_REPLACE_PEERS = 1U << 0,
++	__WGDEVICE_F_ALL = WGDEVICE_F_REPLACE_PEERS
++};
++enum wgdevice_attribute {
++	WGDEVICE_A_UNSPEC,
++	WGDEVICE_A_IFINDEX,
++	WGDEVICE_A_IFNAME,
++	WGDEVICE_A_PRIVATE_KEY,
++	WGDEVICE_A_PUBLIC_KEY,
++	WGDEVICE_A_FLAGS,
++	WGDEVICE_A_LISTEN_PORT,
++	WGDEVICE_A_FWMARK,
++	WGDEVICE_A_PEERS,
++	__WGDEVICE_A_LAST
++};
++#define WGDEVICE_A_MAX (__WGDEVICE_A_LAST - 1)
++
++enum wgpeer_flag {
++	WGPEER_F_REMOVE_ME = 1U << 0,
++	WGPEER_F_REPLACE_ALLOWEDIPS = 1U << 1,
++	WGPEER_F_UPDATE_ONLY = 1U << 2,
++	__WGPEER_F_ALL = WGPEER_F_REMOVE_ME | WGPEER_F_REPLACE_ALLOWEDIPS |
++			 WGPEER_F_UPDATE_ONLY
++};
++enum wgpeer_attribute {
++	WGPEER_A_UNSPEC,
++	WGPEER_A_PUBLIC_KEY,
++	WGPEER_A_PRESHARED_KEY,
++	WGPEER_A_FLAGS,
++	WGPEER_A_ENDPOINT,
++	WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,
++	WGPEER_A_LAST_HANDSHAKE_TIME,
++	WGPEER_A_RX_BYTES,
++	WGPEER_A_TX_BYTES,
++	WGPEER_A_ALLOWEDIPS,
++	WGPEER_A_PROTOCOL_VERSION,
++	__WGPEER_A_LAST
++};
++#define WGPEER_A_MAX (__WGPEER_A_LAST - 1)
++
++enum wgallowedip_attribute {
++	WGALLOWEDIP_A_UNSPEC,
++	WGALLOWEDIP_A_FAMILY,
++	WGALLOWEDIP_A_IPADDR,
++	WGALLOWEDIP_A_CIDR_MASK,
++	__WGALLOWEDIP_A_LAST
++};
++#define WGALLOWEDIP_A_MAX (__WGALLOWEDIP_A_LAST - 1)
++
++#endif /* _WG_UAPI_WIREGUARD_H */
+--- /dev/null
++++ b/tools/testing/selftests/wireguard/netns.sh
+@@ -0,0 +1,537 @@
++#!/bin/bash
++# SPDX-License-Identifier: GPL-2.0
++#
++# Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++#
++# This script tests the below topology:
++#
++# ┌─────────────────────┐   ┌──────────────────────────────────┐   ┌─────────────────────┐
++# │   $ns1 namespace    │   │          $ns0 namespace          │   │   $ns2 namespace    │
++# │                     │   │                                  │   │                     │
++# │┌────────┐           │   │            ┌────────┐            │   │           ┌────────┐│
++# ││  wg0   │───────────┼───┼────────────│   lo   │────────────┼───┼───────────│  wg0   ││
++# │├────────┴──────────┐│   │    ┌───────┴────────┴────────┐   │   │┌──────────┴────────┤│
++# ││192.168.241.1/24   ││   │    │(ns1)         (ns2)      │   │   ││192.168.241.2/24   ││
++# ││fd00::1/24         ││   │    │127.0.0.1:1   127.0.0.1:2│   │   ││fd00::2/24         ││
++# │└───────────────────┘│   │    │[::]:1        [::]:2     │   │   │└───────────────────┘│
++# └─────────────────────┘   │    └─────────────────────────┘   │   └─────────────────────┘
++#                           └──────────────────────────────────┘
++#
++# After the topology is prepared we run a series of TCP/UDP iperf3 tests between the
++# wireguard peers in $ns1 and $ns2. Note that $ns0 is the endpoint for the wg0
++# interfaces in $ns1 and $ns2. See https://www.wireguard.com/netns/ for further
++# details on how this is accomplished.
++set -e
++
++exec 3>&1
++export WG_HIDE_KEYS=never
++netns0="wg-test-$$-0"
++netns1="wg-test-$$-1"
++netns2="wg-test-$$-2"
++pretty() { echo -e "\x1b[32m\x1b[1m[+] ${1:+NS$1: }${2}\x1b[0m" >&3; }
++pp() { pretty "" "$*"; "$@"; }
++maybe_exec() { if [[ $BASHPID -eq $$ ]]; then "$@"; else exec "$@"; fi; }
++n0() { pretty 0 "$*"; maybe_exec ip netns exec $netns0 "$@"; }
++n1() { pretty 1 "$*"; maybe_exec ip netns exec $netns1 "$@"; }
++n2() { pretty 2 "$*"; maybe_exec ip netns exec $netns2 "$@"; }
++ip0() { pretty 0 "ip $*"; ip -n $netns0 "$@"; }
++ip1() { pretty 1 "ip $*"; ip -n $netns1 "$@"; }
++ip2() { pretty 2 "ip $*"; ip -n $netns2 "$@"; }
++sleep() { read -t "$1" -N 0 || true; }
++waitiperf() { pretty "${1//*-}" "wait for iperf:5201"; while [[ $(ss -N "$1" -tlp 'sport = 5201') != *iperf3* ]]; do sleep 0.1; done; }
++waitncatudp() { pretty "${1//*-}" "wait for udp:1111"; while [[ $(ss -N "$1" -ulp 'sport = 1111') != *ncat* ]]; do sleep 0.1; done; }
++waitncattcp() { pretty "${1//*-}" "wait for tcp:1111"; while [[ $(ss -N "$1" -tlp 'sport = 1111') != *ncat* ]]; do sleep 0.1; done; }
++waitiface() { pretty "${1//*-}" "wait for $2 to come up"; ip netns exec "$1" bash -c "while [[ \$(< \"/sys/class/net/$2/operstate\") != up ]]; do read -t .1 -N 0 || true; done;"; }
++
++cleanup() {
++	set +e
++	exec 2>/dev/null
++	printf "$orig_message_cost" > /proc/sys/net/core/message_cost
++	ip0 link del dev wg0
++	ip1 link del dev wg0
++	ip2 link del dev wg0
++	local to_kill="$(ip netns pids $netns0) $(ip netns pids $netns1) $(ip netns pids $netns2)"
++	[[ -n $to_kill ]] && kill $to_kill
++	pp ip netns del $netns1
++	pp ip netns del $netns2
++	pp ip netns del $netns0
++	exit
++}
++
++orig_message_cost="$(< /proc/sys/net/core/message_cost)"
++trap cleanup EXIT
++printf 0 > /proc/sys/net/core/message_cost
++
++ip netns del $netns0 2>/dev/null || true
++ip netns del $netns1 2>/dev/null || true
++ip netns del $netns2 2>/dev/null || true
++pp ip netns add $netns0
++pp ip netns add $netns1
++pp ip netns add $netns2
++ip0 link set up dev lo
++
++ip0 link add dev wg0 type wireguard
++ip0 link set wg0 netns $netns1
++ip0 link add dev wg0 type wireguard
++ip0 link set wg0 netns $netns2
++key1="$(pp wg genkey)"
++key2="$(pp wg genkey)"
++key3="$(pp wg genkey)"
++pub1="$(pp wg pubkey <<<"$key1")"
++pub2="$(pp wg pubkey <<<"$key2")"
++pub3="$(pp wg pubkey <<<"$key3")"
++psk="$(pp wg genpsk)"
++[[ -n $key1 && -n $key2 && -n $psk ]]
++
++configure_peers() {
++	ip1 addr add 192.168.241.1/24 dev wg0
++	ip1 addr add fd00::1/24 dev wg0
++
++	ip2 addr add 192.168.241.2/24 dev wg0
++	ip2 addr add fd00::2/24 dev wg0
++
++	n1 wg set wg0 \
++		private-key <(echo "$key1") \
++		listen-port 1 \
++		peer "$pub2" \
++			preshared-key <(echo "$psk") \
++			allowed-ips 192.168.241.2/32,fd00::2/128
++	n2 wg set wg0 \
++		private-key <(echo "$key2") \
++		listen-port 2 \
++		peer "$pub1" \
++			preshared-key <(echo "$psk") \
++			allowed-ips 192.168.241.1/32,fd00::1/128
++
++	ip1 link set up dev wg0
++	ip2 link set up dev wg0
++}
++configure_peers
++
++tests() {
++	# Ping over IPv4
++	n2 ping -c 10 -f -W 1 192.168.241.1
++	n1 ping -c 10 -f -W 1 192.168.241.2
++
++	# Ping over IPv6
++	n2 ping6 -c 10 -f -W 1 fd00::1
++	n1 ping6 -c 10 -f -W 1 fd00::2
++
++	# TCP over IPv4
++	n2 iperf3 -s -1 -B 192.168.241.2 &
++	waitiperf $netns2
++	n1 iperf3 -Z -t 3 -c 192.168.241.2
++
++	# TCP over IPv6
++	n1 iperf3 -s -1 -B fd00::1 &
++	waitiperf $netns1
++	n2 iperf3 -Z -t 3 -c fd00::1
++
++	# UDP over IPv4
++	n1 iperf3 -s -1 -B 192.168.241.1 &
++	waitiperf $netns1
++	n2 iperf3 -Z -t 3 -b 0 -u -c 192.168.241.1
++
++	# UDP over IPv6
++	n2 iperf3 -s -1 -B fd00::2 &
++	waitiperf $netns2
++	n1 iperf3 -Z -t 3 -b 0 -u -c fd00::2
++}
++
++[[ $(ip1 link show dev wg0) =~ mtu\ ([0-9]+) ]] && orig_mtu="${BASH_REMATCH[1]}"
++big_mtu=$(( 34816 - 1500 + $orig_mtu ))
++
++# Test using IPv4 as outer transport
++n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2
++n2 wg set wg0 peer "$pub1" endpoint 127.0.0.1:1
++# Before calling tests, we first make sure that the stats counters and timestamper are working
++n2 ping -c 10 -f -W 1 192.168.241.1
++{ read _; read _; read _; read rx_bytes _; read _; read tx_bytes _; } < <(ip2 -stats link show dev wg0)
++(( rx_bytes == 1372 && (tx_bytes == 1428 || tx_bytes == 1460) ))
++{ read _; read _; read _; read rx_bytes _; read _; read tx_bytes _; } < <(ip1 -stats link show dev wg0)
++(( tx_bytes == 1372 && (rx_bytes == 1428 || rx_bytes == 1460) ))
++read _ rx_bytes tx_bytes < <(n2 wg show wg0 transfer)
++(( rx_bytes == 1372 && (tx_bytes == 1428 || tx_bytes == 1460) ))
++read _ rx_bytes tx_bytes < <(n1 wg show wg0 transfer)
++(( tx_bytes == 1372 && (rx_bytes == 1428 || rx_bytes == 1460) ))
++read _ timestamp < <(n1 wg show wg0 latest-handshakes)
++(( timestamp != 0 ))
++
++tests
++ip1 link set wg0 mtu $big_mtu
++ip2 link set wg0 mtu $big_mtu
++tests
++
++ip1 link set wg0 mtu $orig_mtu
++ip2 link set wg0 mtu $orig_mtu
++
++# Test using IPv6 as outer transport
++n1 wg set wg0 peer "$pub2" endpoint [::1]:2
++n2 wg set wg0 peer "$pub1" endpoint [::1]:1
++tests
++ip1 link set wg0 mtu $big_mtu
++ip2 link set wg0 mtu $big_mtu
++tests
++
++# Test that route MTUs work with the padding
++ip1 link set wg0 mtu 1300
++ip2 link set wg0 mtu 1300
++n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2
++n2 wg set wg0 peer "$pub1" endpoint 127.0.0.1:1
++n0 iptables -A INPUT -m length --length 1360 -j DROP
++n1 ip route add 192.168.241.2/32 dev wg0 mtu 1299
++n2 ip route add 192.168.241.1/32 dev wg0 mtu 1299
++n2 ping -c 1 -W 1 -s 1269 192.168.241.1
++n2 ip route delete 192.168.241.1/32 dev wg0 mtu 1299
++n1 ip route delete 192.168.241.2/32 dev wg0 mtu 1299
++n0 iptables -F INPUT
++
++ip1 link set wg0 mtu $orig_mtu
++ip2 link set wg0 mtu $orig_mtu
++
++# Test using IPv4 that roaming works
++ip0 -4 addr del 127.0.0.1/8 dev lo
++ip0 -4 addr add 127.212.121.99/8 dev lo
++n1 wg set wg0 listen-port 9999
++n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2
++n1 ping6 -W 1 -c 1 fd00::2
++[[ $(n2 wg show wg0 endpoints) == "$pub1	127.212.121.99:9999" ]]
++
++# Test using IPv6 that roaming works
++n1 wg set wg0 listen-port 9998
++n1 wg set wg0 peer "$pub2" endpoint [::1]:2
++n1 ping -W 1 -c 1 192.168.241.2
++[[ $(n2 wg show wg0 endpoints) == "$pub1	[::1]:9998" ]]
++
++# Test that crypto-RP filter works
++n1 wg set wg0 peer "$pub2" allowed-ips 192.168.241.0/24
++exec 4< <(n1 ncat -l -u -p 1111)
++ncat_pid=$!
++waitncatudp $netns1
++n2 ncat -u 192.168.241.1 1111 <<<"X"
++read -r -N 1 -t 1 out <&4 && [[ $out == "X" ]]
++kill $ncat_pid
++more_specific_key="$(pp wg genkey | pp wg pubkey)"
++n1 wg set wg0 peer "$more_specific_key" allowed-ips 192.168.241.2/32
++n2 wg set wg0 listen-port 9997
++exec 4< <(n1 ncat -l -u -p 1111)
++ncat_pid=$!
++waitncatudp $netns1
++n2 ncat -u 192.168.241.1 1111 <<<"X"
++! read -r -N 1 -t 1 out <&4 || false
++kill $ncat_pid
++n1 wg set wg0 peer "$more_specific_key" remove
++[[ $(n1 wg show wg0 endpoints) == "$pub2	[::1]:9997" ]]
++
++# Test that we can change private keys keys and immediately handshake
++n1 wg set wg0 private-key <(echo "$key1") peer "$pub2" preshared-key <(echo "$psk") allowed-ips 192.168.241.2/32 endpoint 127.0.0.1:2
++n2 wg set wg0 private-key <(echo "$key2") listen-port 2 peer "$pub1" preshared-key <(echo "$psk") allowed-ips 192.168.241.1/32
++n1 ping -W 1 -c 1 192.168.241.2
++n1 wg set wg0 private-key <(echo "$key3")
++n2 wg set wg0 peer "$pub3" preshared-key <(echo "$psk") allowed-ips 192.168.241.1/32 peer "$pub1" remove
++n1 ping -W 1 -c 1 192.168.241.2
++
++ip1 link del wg0
++ip2 link del wg0
++
++# Test using NAT. We now change the topology to this:
++# ┌────────────────────────────────────────┐    ┌────────────────────────────────────────────────┐     ┌────────────────────────────────────────┐
++# │             $ns1 namespace             │    │                 $ns0 namespace                 │     │             $ns2 namespace             │
++# │                                        │    │                                                │     │                                        │
++# │  ┌─────┐             ┌─────┐           │    │    ┌──────┐              ┌──────┐              │     │  ┌─────┐            ┌─────┐            │
++# │  │ wg0 │─────────────│vethc│───────────┼────┼────│vethrc│              │vethrs│──────────────┼─────┼──│veths│────────────│ wg0 │            │
++# │  ├─────┴──────────┐  ├─────┴──────────┐│    │    ├──────┴─────────┐    ├──────┴────────────┐ │     │  ├─────┴──────────┐ ├─────┴──────────┐ │
++# │  │192.168.241.1/24│  │192.168.1.100/24││    │    │192.168.1.1/24  │    │10.0.0.1/24        │ │     │  │10.0.0.100/24   │ │192.168.241.2/24│ │
++# │  │fd00::1/24      │  │                ││    │    │                │    │SNAT:192.168.1.0/24│ │     │  │                │ │fd00::2/24      │ │
++# │  └────────────────┘  └────────────────┘│    │    └────────────────┘    └───────────────────┘ │     │  └────────────────┘ └────────────────┘ │
++# └────────────────────────────────────────┘    └────────────────────────────────────────────────┘     └────────────────────────────────────────┘
++
++ip1 link add dev wg0 type wireguard
++ip2 link add dev wg0 type wireguard
++configure_peers
++
++ip0 link add vethrc type veth peer name vethc
++ip0 link add vethrs type veth peer name veths
++ip0 link set vethc netns $netns1
++ip0 link set veths netns $netns2
++ip0 link set vethrc up
++ip0 link set vethrs up
++ip0 addr add 192.168.1.1/24 dev vethrc
++ip0 addr add 10.0.0.1/24 dev vethrs
++ip1 addr add 192.168.1.100/24 dev vethc
++ip1 link set vethc up
++ip1 route add default via 192.168.1.1
++ip2 addr add 10.0.0.100/24 dev veths
++ip2 link set veths up
++waitiface $netns0 vethrc
++waitiface $netns0 vethrs
++waitiface $netns1 vethc
++waitiface $netns2 veths
++
++n0 bash -c 'printf 1 > /proc/sys/net/ipv4/ip_forward'
++n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout'
++n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream'
++n0 iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 10.0.0.0/24 -j SNAT --to 10.0.0.1
++
++n1 wg set wg0 peer "$pub2" endpoint 10.0.0.100:2 persistent-keepalive 1
++n1 ping -W 1 -c 1 192.168.241.2
++n2 ping -W 1 -c 1 192.168.241.1
++[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.1:1" ]]
++# Demonstrate n2 can still send packets to n1, since persistent-keepalive will prevent connection tracking entry from expiring (to see entries: `n0 conntrack -L`).
++pp sleep 3
++n2 ping -W 1 -c 1 192.168.241.1
++n1 wg set wg0 peer "$pub2" persistent-keepalive 0
++
++# Do a wg-quick(8)-style policy routing for the default route, making sure vethc has a v6 address to tease out bugs.
++ip1 -6 addr add fc00::9/96 dev vethc
++ip1 -6 route add default via fc00::1
++ip2 -4 addr add 192.168.99.7/32 dev wg0
++ip2 -6 addr add abab::1111/128 dev wg0
++n1 wg set wg0 fwmark 51820 peer "$pub2" allowed-ips 192.168.99.7,abab::1111
++ip1 -6 route add default dev wg0 table 51820
++ip1 -6 rule add not fwmark 51820 table 51820
++ip1 -6 rule add table main suppress_prefixlength 0
++ip1 -4 route add default dev wg0 table 51820
++ip1 -4 rule add not fwmark 51820 table 51820
++ip1 -4 rule add table main suppress_prefixlength 0
++# suppress_prefixlength only got added in 3.12, and we want to support 3.10+.
++if [[ $(ip1 -4 rule show all) == *suppress_prefixlength* ]]; then
++	# Flood the pings instead of sending just one, to trigger routing table reference counting bugs.
++	n1 ping -W 1 -c 100 -f 192.168.99.7
++	n1 ping -W 1 -c 100 -f abab::1111
++fi
++
++n0 iptables -t nat -F
++ip0 link del vethrc
++ip0 link del vethrs
++ip1 link del wg0
++ip2 link del wg0
++
++# Test that saddr routing is sticky but not too sticky, changing to this topology:
++# ┌────────────────────────────────────────┐    ┌────────────────────────────────────────┐
++# │             $ns1 namespace             │    │             $ns2 namespace             │
++# │                                        │    │                                        │
++# │  ┌─────┐             ┌─────┐           │    │  ┌─────┐            ┌─────┐            │
++# │  │ wg0 │─────────────│veth1│───────────┼────┼──│veth2│────────────│ wg0 │            │
++# │  ├─────┴──────────┐  ├─────┴──────────┐│    │  ├─────┴──────────┐ ├─────┴──────────┐ │
++# │  │192.168.241.1/24│  │10.0.0.1/24     ││    │  │10.0.0.2/24     │ │192.168.241.2/24│ │
++# │  │fd00::1/24      │  │fd00:aa::1/96   ││    │  │fd00:aa::2/96   │ │fd00::2/24      │ │
++# │  └────────────────┘  └────────────────┘│    │  └────────────────┘ └────────────────┘ │
++# └────────────────────────────────────────┘    └────────────────────────────────────────┘
++
++ip1 link add dev wg0 type wireguard
++ip2 link add dev wg0 type wireguard
++configure_peers
++ip1 link add veth1 type veth peer name veth2
++ip1 link set veth2 netns $netns2
++n1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/all/accept_dad'
++n2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/all/accept_dad'
++n1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth1/accept_dad'
++n2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth2/accept_dad'
++n1 bash -c 'printf 1 > /proc/sys/net/ipv4/conf/veth1/promote_secondaries'
++
++# First we check that we aren't overly sticky and can fall over to new IPs when old ones are removed
++ip1 addr add 10.0.0.1/24 dev veth1
++ip1 addr add fd00:aa::1/96 dev veth1
++ip2 addr add 10.0.0.2/24 dev veth2
++ip2 addr add fd00:aa::2/96 dev veth2
++ip1 link set veth1 up
++ip2 link set veth2 up
++waitiface $netns1 veth1
++waitiface $netns2 veth2
++n1 wg set wg0 peer "$pub2" endpoint 10.0.0.2:2
++n1 ping -W 1 -c 1 192.168.241.2
++ip1 addr add 10.0.0.10/24 dev veth1
++ip1 addr del 10.0.0.1/24 dev veth1
++n1 ping -W 1 -c 1 192.168.241.2
++n1 wg set wg0 peer "$pub2" endpoint [fd00:aa::2]:2
++n1 ping -W 1 -c 1 192.168.241.2
++ip1 addr add fd00:aa::10/96 dev veth1
++ip1 addr del fd00:aa::1/96 dev veth1
++n1 ping -W 1 -c 1 192.168.241.2
++
++# Now we show that we can successfully do reply to sender routing
++ip1 link set veth1 down
++ip2 link set veth2 down
++ip1 addr flush dev veth1
++ip2 addr flush dev veth2
++ip1 addr add 10.0.0.1/24 dev veth1
++ip1 addr add 10.0.0.2/24 dev veth1
++ip1 addr add fd00:aa::1/96 dev veth1
++ip1 addr add fd00:aa::2/96 dev veth1
++ip2 addr add 10.0.0.3/24 dev veth2
++ip2 addr add fd00:aa::3/96 dev veth2
++ip1 link set veth1 up
++ip2 link set veth2 up
++waitiface $netns1 veth1
++waitiface $netns2 veth2
++n2 wg set wg0 peer "$pub1" endpoint 10.0.0.1:1
++n2 ping -W 1 -c 1 192.168.241.1
++[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.1:1" ]]
++n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::1]:1
++n2 ping -W 1 -c 1 192.168.241.1
++[[ $(n2 wg show wg0 endpoints) == "$pub1	[fd00:aa::1]:1" ]]
++n2 wg set wg0 peer "$pub1" endpoint 10.0.0.2:1
++n2 ping -W 1 -c 1 192.168.241.1
++[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.2:1" ]]
++n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::2]:1
++n2 ping -W 1 -c 1 192.168.241.1
++[[ $(n2 wg show wg0 endpoints) == "$pub1	[fd00:aa::2]:1" ]]
++
++# What happens if the inbound destination address belongs to a different interface as the default route?
++ip1 link add dummy0 type dummy
++ip1 addr add 10.50.0.1/24 dev dummy0
++ip1 link set dummy0 up
++ip2 route add 10.50.0.0/24 dev veth2
++n2 wg set wg0 peer "$pub1" endpoint 10.50.0.1:1
++n2 ping -W 1 -c 1 192.168.241.1
++[[ $(n2 wg show wg0 endpoints) == "$pub1	10.50.0.1:1" ]]
++
++ip1 link del dummy0
++ip1 addr flush dev veth1
++ip2 addr flush dev veth2
++ip1 route flush dev veth1
++ip2 route flush dev veth2
++
++# Now we see what happens if another interface route takes precedence over an ongoing one
++ip1 link add veth3 type veth peer name veth4
++ip1 link set veth4 netns $netns2
++ip1 addr add 10.0.0.1/24 dev veth1
++ip2 addr add 10.0.0.2/24 dev veth2
++ip1 addr add 10.0.0.3/24 dev veth3
++ip1 link set veth1 up
++ip2 link set veth2 up
++ip1 link set veth3 up
++ip2 link set veth4 up
++waitiface $netns1 veth1
++waitiface $netns2 veth2
++waitiface $netns1 veth3
++waitiface $netns2 veth4
++ip1 route flush dev veth1
++ip1 route flush dev veth3
++ip1 route add 10.0.0.0/24 dev veth1 src 10.0.0.1 metric 2
++n1 wg set wg0 peer "$pub2" endpoint 10.0.0.2:2
++n1 ping -W 1 -c 1 192.168.241.2
++[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.1:1" ]]
++ip1 route add 10.0.0.0/24 dev veth3 src 10.0.0.3 metric 1
++n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/veth1/rp_filter'
++n2 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/veth4/rp_filter'
++n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/all/rp_filter'
++n2 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/all/rp_filter'
++n1 ping -W 1 -c 1 192.168.241.2
++[[ $(n2 wg show wg0 endpoints) == "$pub1	10.0.0.3:1" ]]
++
++ip1 link del veth1
++ip1 link del veth3
++ip1 link del wg0
++ip2 link del wg0
++
++# We test that Netlink/IPC is working properly by doing things that usually cause split responses
++ip0 link add dev wg0 type wireguard
++config=( "[Interface]" "PrivateKey=$(wg genkey)" "[Peer]" "PublicKey=$(wg genkey)" )
++for a in {1..255}; do
++	for b in {0..255}; do
++		config+=( "AllowedIPs=$a.$b.0.0/16,$a::$b/128" )
++	done
++done
++n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
++i=0
++for ip in $(n0 wg show wg0 allowed-ips); do
++	((++i))
++done
++((i == 255*256*2+1))
++ip0 link del wg0
++ip0 link add dev wg0 type wireguard
++config=( "[Interface]" "PrivateKey=$(wg genkey)" )
++for a in {1..40}; do
++	config+=( "[Peer]" "PublicKey=$(wg genkey)" )
++	for b in {1..52}; do
++		config+=( "AllowedIPs=$a.$b.0.0/16" )
++	done
++done
++n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
++i=0
++while read -r line; do
++	j=0
++	for ip in $line; do
++		((++j))
++	done
++	((j == 53))
++	((++i))
++done < <(n0 wg show wg0 allowed-ips)
++((i == 40))
++ip0 link del wg0
++ip0 link add wg0 type wireguard
++config=( )
++for i in {1..29}; do
++	config+=( "[Peer]" "PublicKey=$(wg genkey)" )
++done
++config+=( "[Peer]" "PublicKey=$(wg genkey)" "AllowedIPs=255.2.3.4/32,abcd::255/128" )
++n0 wg setconf wg0 <(printf '%s\n' "${config[@]}")
++n0 wg showconf wg0 > /dev/null
++ip0 link del wg0
++
++allowedips=( )
++for i in {1..197}; do
++        allowedips+=( abcd::$i )
++done
++saved_ifs="$IFS"
++IFS=,
++allowedips="${allowedips[*]}"
++IFS="$saved_ifs"
++ip0 link add wg0 type wireguard
++n0 wg set wg0 peer "$pub1"
++n0 wg set wg0 peer "$pub2" allowed-ips "$allowedips"
++{
++	read -r pub allowedips
++	[[ $pub == "$pub1" && $allowedips == "(none)" ]]
++	read -r pub allowedips
++	[[ $pub == "$pub2" ]]
++	i=0
++	for _ in $allowedips; do
++		((++i))
++	done
++	((i == 197))
++} < <(n0 wg show wg0 allowed-ips)
++ip0 link del wg0
++
++! n0 wg show doesnotexist || false
++
++ip0 link add wg0 type wireguard
++n0 wg set wg0 private-key <(echo "$key1") peer "$pub2" preshared-key <(echo "$psk")
++[[ $(n0 wg show wg0 private-key) == "$key1" ]]
++[[ $(n0 wg show wg0 preshared-keys) == "$pub2	$psk" ]]
++n0 wg set wg0 private-key /dev/null peer "$pub2" preshared-key /dev/null
++[[ $(n0 wg show wg0 private-key) == "(none)" ]]
++[[ $(n0 wg show wg0 preshared-keys) == "$pub2	(none)" ]]
++n0 wg set wg0 peer "$pub2"
++n0 wg set wg0 private-key <(echo "$key2")
++[[ $(n0 wg show wg0 public-key) == "$pub2" ]]
++[[ -z $(n0 wg show wg0 peers) ]]
++n0 wg set wg0 peer "$pub2"
++[[ -z $(n0 wg show wg0 peers) ]]
++n0 wg set wg0 private-key <(echo "$key1")
++n0 wg set wg0 peer "$pub2"
++[[ $(n0 wg show wg0 peers) == "$pub2" ]]
++n0 wg set wg0 private-key <(echo "/${key1:1}")
++[[ $(n0 wg show wg0 private-key) == "+${key1:1}" ]]
++n0 wg set wg0 peer "$pub2" allowed-ips 0.0.0.0/0,10.0.0.0/8,100.0.0.0/10,172.16.0.0/12,192.168.0.0/16
++n0 wg set wg0 peer "$pub2" allowed-ips 0.0.0.0/0
++n0 wg set wg0 peer "$pub2" allowed-ips ::/0,1700::/111,5000::/4,e000::/37,9000::/75
++n0 wg set wg0 peer "$pub2" allowed-ips ::/0
++ip0 link del wg0
++
++declare -A objects
++while read -t 0.1 -r line 2>/dev/null || [[ $? -ne 142 ]]; do
++	[[ $line =~ .*(wg[0-9]+:\ [A-Z][a-z]+\ [0-9]+)\ .*(created|destroyed).* ]] || continue
++	objects["${BASH_REMATCH[1]}"]+="${BASH_REMATCH[2]}"
++done < /dev/kmsg
++alldeleted=1
++for object in "${!objects[@]}"; do
++	if [[ ${objects["$object"]} != *createddestroyed ]]; then
++		echo "Error: $object: merely ${objects["$object"]}" >&3
++		alldeleted=0
++	fi
++done
++[[ $alldeleted -eq 1 ]]
++pretty "" "Objects that were created were also destroyed."
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0073-wireguard-selftests-import-harness-makefile-for-test.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0073-wireguard-selftests-import-harness-makefile-for-test.patch
new file mode 100644
index 0000000..ca3853a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0073-wireguard-selftests-import-harness-makefile-for-test.patch
@@ -0,0 +1,1078 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Sun, 15 Dec 2019 22:08:00 +0100
+Subject: [PATCH] wireguard: selftests: import harness makefile for test suite
+
+commit 65d88d04114bca7d85faebd5fed61069cb2b632c upstream.
+
+WireGuard has been using this on build.wireguard.com for the last
+several years with considerable success. It allows for very quick and
+iterative development cycles, and supports several platforms.
+
+To run the test suite on your current platform in QEMU:
+
+  $ make -C tools/testing/selftests/wireguard/qemu -j$(nproc)
+
+To run it with KASAN and such turned on:
+
+  $ DEBUG_KERNEL=yes make -C tools/testing/selftests/wireguard/qemu -j$(nproc)
+
+To run it emulated for another platform in QEMU:
+
+  $ ARCH=arm make -C tools/testing/selftests/wireguard/qemu -j$(nproc)
+
+At the moment, we support aarch64_be, aarch64, arm, armeb, i686, m68k,
+mips64, mips64el, mips, mipsel, powerpc64le, powerpc, and x86_64.
+
+The system supports incremental rebuilding, so it should be very fast to
+change a single file and then test it out and have immediate feedback.
+
+This requires for the right toolchain and qemu to be installed prior.
+I've had success with those from musl.cc.
+
+This is tailored for WireGuard at the moment, though later projects
+might generalize it for other network testing.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ .../selftests/wireguard/qemu/.gitignore       |   2 +
+ .../testing/selftests/wireguard/qemu/Makefile | 385 ++++++++++++++++++
+ .../wireguard/qemu/arch/aarch64.config        |   5 +
+ .../wireguard/qemu/arch/aarch64_be.config     |   6 +
+ .../selftests/wireguard/qemu/arch/arm.config  |   9 +
+ .../wireguard/qemu/arch/armeb.config          |  10 +
+ .../selftests/wireguard/qemu/arch/i686.config |   5 +
+ .../selftests/wireguard/qemu/arch/m68k.config |   9 +
+ .../selftests/wireguard/qemu/arch/mips.config |  11 +
+ .../wireguard/qemu/arch/mips64.config         |  14 +
+ .../wireguard/qemu/arch/mips64el.config       |  15 +
+ .../wireguard/qemu/arch/mipsel.config         |  12 +
+ .../wireguard/qemu/arch/powerpc.config        |  10 +
+ .../wireguard/qemu/arch/powerpc64le.config    |  12 +
+ .../wireguard/qemu/arch/x86_64.config         |   5 +
+ .../selftests/wireguard/qemu/debug.config     |  67 +++
+ tools/testing/selftests/wireguard/qemu/init.c | 284 +++++++++++++
+ .../selftests/wireguard/qemu/kernel.config    |  86 ++++
+ 18 files changed, 947 insertions(+)
+ create mode 100644 tools/testing/selftests/wireguard/qemu/.gitignore
+ create mode 100644 tools/testing/selftests/wireguard/qemu/Makefile
+ create mode 100644 tools/testing/selftests/wireguard/qemu/arch/aarch64.config
+ create mode 100644 tools/testing/selftests/wireguard/qemu/arch/aarch64_be.config
+ create mode 100644 tools/testing/selftests/wireguard/qemu/arch/arm.config
+ create mode 100644 tools/testing/selftests/wireguard/qemu/arch/armeb.config
+ create mode 100644 tools/testing/selftests/wireguard/qemu/arch/i686.config
+ create mode 100644 tools/testing/selftests/wireguard/qemu/arch/m68k.config
+ create mode 100644 tools/testing/selftests/wireguard/qemu/arch/mips.config
+ create mode 100644 tools/testing/selftests/wireguard/qemu/arch/mips64.config
+ create mode 100644 tools/testing/selftests/wireguard/qemu/arch/mips64el.config
+ create mode 100644 tools/testing/selftests/wireguard/qemu/arch/mipsel.config
+ create mode 100644 tools/testing/selftests/wireguard/qemu/arch/powerpc.config
+ create mode 100644 tools/testing/selftests/wireguard/qemu/arch/powerpc64le.config
+ create mode 100644 tools/testing/selftests/wireguard/qemu/arch/x86_64.config
+ create mode 100644 tools/testing/selftests/wireguard/qemu/debug.config
+ create mode 100644 tools/testing/selftests/wireguard/qemu/init.c
+ create mode 100644 tools/testing/selftests/wireguard/qemu/kernel.config
+
+--- /dev/null
++++ b/tools/testing/selftests/wireguard/qemu/.gitignore
+@@ -0,0 +1,2 @@
++build/
++distfiles/
+--- /dev/null
++++ b/tools/testing/selftests/wireguard/qemu/Makefile
+@@ -0,0 +1,385 @@
++# SPDX-License-Identifier: GPL-2.0
++#
++# Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++
++PWD := $(shell pwd)
++
++CHOST := $(shell gcc -dumpmachine)
++ifneq (,$(ARCH))
++CBUILD := $(subst -gcc,,$(lastword $(subst /, ,$(firstword $(wildcard $(foreach bindir,$(subst :, ,$(PATH)),$(bindir)/$(ARCH)-*-gcc))))))
++ifeq (,$(CBUILD))
++$(error The toolchain for $(ARCH) is not installed)
++endif
++else
++CBUILD := $(CHOST)
++ARCH := $(firstword $(subst -, ,$(CBUILD)))
++endif
++
++# Set these from the environment to override
++KERNEL_PATH ?= $(PWD)/../../../../..
++BUILD_PATH ?= $(PWD)/build/$(ARCH)
++DISTFILES_PATH ?= $(PWD)/distfiles
++NR_CPUS ?= 4
++
++MIRROR := https://download.wireguard.com/qemu-test/distfiles/
++
++default: qemu
++
++# variable name, tarball project name, version, tarball extension, default URI base
++define tar_download =
++$(1)_VERSION := $(3)
++$(1)_NAME := $(2)-$$($(1)_VERSION)
++$(1)_TAR := $(DISTFILES_PATH)/$$($(1)_NAME)$(4)
++$(1)_PATH := $(BUILD_PATH)/$$($(1)_NAME)
++$(call file_download,$$($(1)_NAME)$(4),$(5),$(6))
++endef
++
++define file_download =
++$(DISTFILES_PATH)/$(1):
++	mkdir -p $(DISTFILES_PATH)
++	flock -x $$@.lock -c '[ -f $$@ ] && exit 0; wget -O $$@.tmp $(MIRROR)$(1) || wget -t inf --retry-on-http-error=404 -O $$@.tmp $(2)$(1) || rm -f $$@.tmp'
++	if echo "$(3)  $$@.tmp" | sha256sum -c -; then mv $$@.tmp $$@; else rm -f $$@.tmp; exit 71; fi
++endef
++
++$(eval $(call tar_download,MUSL,musl,1.1.20,.tar.gz,https://www.musl-libc.org/releases/,44be8771d0e6c6b5f82dd15662eb2957c9a3173a19a8b49966ac0542bbd40d61))
++$(eval $(call tar_download,LIBMNL,libmnl,1.0.4,.tar.bz2,https://www.netfilter.org/projects/libmnl/files/,171f89699f286a5854b72b91d06e8f8e3683064c5901fb09d954a9ab6f551f81))
++$(eval $(call tar_download,IPERF,iperf,3.1.7,.tar.gz,http://downloads.es.net/pub/iperf/,a4ef73406fe92250602b8da2ae89ec53211f805df97a1d1d629db5a14043734f))
++$(eval $(call tar_download,BASH,bash,5.0,.tar.gz,https://ftp.gnu.org/gnu/bash/,b4a80f2ac66170b2913efbfb9f2594f1f76c7b1afd11f799e22035d63077fb4d))
++$(eval $(call tar_download,IPROUTE2,iproute2,5.1.0,.tar.gz,https://www.kernel.org/pub/linux/utils/net/iproute2/,9b43707d6075ecdca14803ca8ce0c8553848c49fa1586d12fd508d66577243f2))
++$(eval $(call tar_download,IPTABLES,iptables,1.6.1,.tar.bz2,https://www.netfilter.org/projects/iptables/files/,0fc2d7bd5d7be11311726466789d4c65fb4c8e096c9182b56ce97440864f0cf5))
++$(eval $(call tar_download,NMAP,nmap,7.60,.tar.bz2,https://nmap.org/dist/,a8796ecc4fa6c38aad6139d9515dc8113023a82e9d787e5a5fb5fa1b05516f21))
++$(eval $(call tar_download,IPUTILS,iputils,s20161105,.tar.gz,https://github.com/iputils/iputils/archive/s20161105.tar.gz/#,f813092f03d17294fd23544b129b95cdb87fe19f7970a51908a6b88509acad8a))
++$(eval $(call tar_download,WIREGUARD_TOOLS,WireGuard,0.0.20191212,.tar.xz,https://git.zx2c4.com/WireGuard/snapshot/,b0d718380f7a8822b2f12d75e462fa4eafa3a77871002981f367cd4fe2a1b071))
++
++KERNEL_BUILD_PATH := $(BUILD_PATH)/kernel$(if $(findstring yes,$(DEBUG_KERNEL)),-debug)
++rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))
++WIREGUARD_SOURCES := $(call rwildcard,$(KERNEL_PATH)/drivers/net/wireguard/,*)
++
++export CFLAGS ?= -O3 -pipe
++export LDFLAGS ?=
++export CPPFLAGS := -I$(BUILD_PATH)/include
++
++ifeq ($(CHOST),$(CBUILD))
++CROSS_COMPILE_FLAG := --host=$(CHOST)
++NOPIE_GCC := gcc -fno-PIE
++CFLAGS += -march=native
++STRIP := strip
++else
++$(info Cross compilation: building for $(CBUILD) using $(CHOST))
++CROSS_COMPILE_FLAG := --build=$(CBUILD) --host=$(CHOST)
++export CROSS_COMPILE=$(CBUILD)-
++NOPIE_GCC := $(CBUILD)-gcc -fno-PIE
++STRIP := $(CBUILD)-strip
++endif
++ifeq ($(ARCH),aarch64)
++QEMU_ARCH := aarch64
++KERNEL_ARCH := arm64
++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/arm64/boot/Image
++ifeq ($(CHOST),$(CBUILD))
++QEMU_MACHINE := -cpu host -machine virt,gic_version=host,accel=kvm
++else
++QEMU_MACHINE := -cpu cortex-a53 -machine virt
++CFLAGS += -march=armv8-a -mtune=cortex-a53
++endif
++else ifeq ($(ARCH),aarch64_be)
++QEMU_ARCH := aarch64
++KERNEL_ARCH := arm64
++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/arm64/boot/Image
++ifeq ($(CHOST),$(CBUILD))
++QEMU_MACHINE := -cpu host -machine virt,gic_version=host,accel=kvm
++else
++QEMU_MACHINE := -cpu cortex-a53 -machine virt
++CFLAGS += -march=armv8-a -mtune=cortex-a53
++endif
++else ifeq ($(ARCH),arm)
++QEMU_ARCH := arm
++KERNEL_ARCH := arm
++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/arm/boot/zImage
++ifeq ($(CHOST),$(CBUILD))
++QEMU_MACHINE := -cpu host -machine virt,gic_version=host,accel=kvm
++else
++QEMU_MACHINE := -cpu cortex-a15 -machine virt
++CFLAGS += -march=armv7-a -mtune=cortex-a15 -mabi=aapcs-linux
++endif
++else ifeq ($(ARCH),armeb)
++QEMU_ARCH := arm
++KERNEL_ARCH := arm
++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/arm/boot/zImage
++ifeq ($(CHOST),$(CBUILD))
++QEMU_MACHINE := -cpu host -machine virt,gic_version=host,accel=kvm
++else
++QEMU_MACHINE := -cpu cortex-a15 -machine virt
++CFLAGS += -march=armv7-a -mabi=aapcs-linux # We don't pass -mtune=cortex-a15 due to a compiler bug on big endian.
++LDFLAGS += -Wl,--be8
++endif
++else ifeq ($(ARCH),x86_64)
++QEMU_ARCH := x86_64
++KERNEL_ARCH := x86_64
++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/x86/boot/bzImage
++ifeq ($(CHOST),$(CBUILD))
++QEMU_MACHINE := -cpu host -machine q35,accel=kvm
++else
++QEMU_MACHINE := -cpu Skylake-Server -machine q35
++CFLAGS += -march=skylake-avx512
++endif
++else ifeq ($(ARCH),i686)
++QEMU_ARCH := i386
++KERNEL_ARCH := x86
++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/x86/boot/bzImage
++ifeq ($(subst i686,x86_64,$(CBUILD)),$(CHOST))
++QEMU_MACHINE := -cpu host -machine q35,accel=kvm
++else
++QEMU_MACHINE := -cpu coreduo -machine q35
++CFLAGS += -march=prescott
++endif
++else ifeq ($(ARCH),mips64)
++QEMU_ARCH := mips64
++KERNEL_ARCH := mips
++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux
++ifeq ($(CHOST),$(CBUILD))
++QEMU_MACHINE := -cpu host -machine malta,accel=kvm
++CFLAGS += -EB
++else
++QEMU_MACHINE := -cpu MIPS64R2-generic -machine malta -smp 1
++CFLAGS += -march=mips64r2 -EB
++endif
++else ifeq ($(ARCH),mips64el)
++QEMU_ARCH := mips64el
++KERNEL_ARCH := mips
++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux
++ifeq ($(CHOST),$(CBUILD))
++QEMU_MACHINE := -cpu host -machine malta,accel=kvm
++CFLAGS += -EL
++else
++QEMU_MACHINE := -cpu MIPS64R2-generic -machine malta -smp 1
++CFLAGS += -march=mips64r2 -EL
++endif
++else ifeq ($(ARCH),mips)
++QEMU_ARCH := mips
++KERNEL_ARCH := mips
++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux
++ifeq ($(CHOST),$(CBUILD))
++QEMU_MACHINE := -cpu host -machine malta,accel=kvm
++CFLAGS += -EB
++else
++QEMU_MACHINE := -cpu 24Kf -machine malta -smp 1
++CFLAGS += -march=mips32r2 -EB
++endif
++else ifeq ($(ARCH),mipsel)
++QEMU_ARCH := mipsel
++KERNEL_ARCH := mips
++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux
++ifeq ($(CHOST),$(CBUILD))
++QEMU_MACHINE := -cpu host -machine malta,accel=kvm
++CFLAGS += -EL
++else
++QEMU_MACHINE := -cpu 24Kf -machine malta -smp 1
++CFLAGS += -march=mips32r2 -EL
++endif
++else ifeq ($(ARCH),powerpc64le)
++QEMU_ARCH := ppc64
++KERNEL_ARCH := powerpc
++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux
++ifeq ($(CHOST),$(CBUILD))
++QEMU_MACHINE := -cpu host,accel=kvm -machine pseries
++else
++QEMU_MACHINE := -machine pseries
++endif
++CFLAGS += -mcpu=powerpc64le -mlong-double-64
++else ifeq ($(ARCH),powerpc)
++QEMU_ARCH := ppc
++KERNEL_ARCH := powerpc
++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/powerpc/boot/uImage
++ifeq ($(CHOST),$(CBUILD))
++QEMU_MACHINE := -cpu host,accel=kvm -machine ppce500
++else
++QEMU_MACHINE := -machine ppce500
++endif
++CFLAGS += -mcpu=powerpc -mlong-double-64 -msecure-plt
++else ifeq ($(ARCH),m68k)
++QEMU_ARCH := m68k
++KERNEL_ARCH := m68k
++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux
++ifeq ($(CHOST),$(CBUILD))
++QEMU_MACHINE := -cpu host,accel=kvm -machine q800
++else
++QEMU_MACHINE := -machine q800
++endif
++else
++$(error I only build: x86_64, i686, arm, armeb, aarch64, aarch64_be, mips, mipsel, mips64, mips64el, powerpc64le, powerpc, m68k)
++endif
++
++REAL_CC := $(CBUILD)-gcc
++MUSL_CC := $(BUILD_PATH)/musl-gcc
++export CC := $(MUSL_CC)
++USERSPACE_DEPS := $(MUSL_CC) $(BUILD_PATH)/include/.installed $(BUILD_PATH)/include/linux/.installed
++
++build: $(KERNEL_BZIMAGE)
++qemu: $(KERNEL_BZIMAGE)
++	rm -f $(BUILD_PATH)/result
++	timeout --foreground 20m qemu-system-$(QEMU_ARCH) \
++		-nodefaults \
++		-nographic \
++		-smp $(NR_CPUS) \
++		$(QEMU_MACHINE) \
++		-m $$(grep -q CONFIG_DEBUG_KMEMLEAK=y $(KERNEL_BUILD_PATH)/.config && echo 1G || echo 256M) \
++		-serial stdio \
++		-serial file:$(BUILD_PATH)/result \
++		-no-reboot \
++		-monitor none \
++		-kernel $<
++	grep -Fq success $(BUILD_PATH)/result
++
++$(BUILD_PATH)/init-cpio-spec.txt:
++	mkdir -p $(BUILD_PATH)
++	echo "file /init $(BUILD_PATH)/init 755 0 0" > $@
++	echo "file /init.sh $(PWD)/../netns.sh 755 0 0" >> $@
++	echo "dir /dev 755 0 0" >> $@
++	echo "nod /dev/console 644 0 0 c 5 1" >> $@
++	echo "dir /bin 755 0 0" >> $@
++	echo "file /bin/iperf3 $(IPERF_PATH)/src/iperf3 755 0 0" >> $@
++	echo "file /bin/wg $(WIREGUARD_TOOLS_PATH)/src/tools/wg 755 0 0" >> $@
++	echo "file /bin/bash $(BASH_PATH)/bash 755 0 0" >> $@
++	echo "file /bin/ip $(IPROUTE2_PATH)/ip/ip 755 0 0" >> $@
++	echo "file /bin/ss $(IPROUTE2_PATH)/misc/ss 755 0 0" >> $@
++	echo "file /bin/ping $(IPUTILS_PATH)/ping 755 0 0" >> $@
++	echo "file /bin/ncat $(NMAP_PATH)/ncat/ncat 755 0 0" >> $@
++	echo "file /bin/xtables-multi $(IPTABLES_PATH)/iptables/xtables-multi 755 0 0" >> $@
++	echo "slink /bin/iptables xtables-multi 777 0 0" >> $@
++	echo "slink /bin/ping6 ping 777 0 0" >> $@
++	echo "dir /lib 755 0 0" >> $@
++	echo "file /lib/libc.so $(MUSL_PATH)/lib/libc.so 755 0 0" >> $@
++	echo "slink /lib/ld-linux.so.1 libc.so 777 0 0" >> $@
++
++$(KERNEL_BUILD_PATH)/.config: kernel.config arch/$(ARCH).config
++	mkdir -p $(KERNEL_BUILD_PATH)
++	cp kernel.config $(KERNEL_BUILD_PATH)/minimal.config
++	printf 'CONFIG_NR_CPUS=$(NR_CPUS)\nCONFIG_INITRAMFS_SOURCE="$(BUILD_PATH)/init-cpio-spec.txt"\n' >> $(KERNEL_BUILD_PATH)/minimal.config
++	cat arch/$(ARCH).config >> $(KERNEL_BUILD_PATH)/minimal.config
++	$(MAKE) -C $(KERNEL_PATH) O=$(KERNEL_BUILD_PATH) ARCH=$(KERNEL_ARCH) allnoconfig
++	cd $(KERNEL_BUILD_PATH) && ARCH=$(KERNEL_ARCH) $(KERNEL_PATH)/scripts/kconfig/merge_config.sh -n $(KERNEL_BUILD_PATH)/.config $(KERNEL_BUILD_PATH)/minimal.config
++	$(if $(findstring yes,$(DEBUG_KERNEL)),cp debug.config $(KERNEL_BUILD_PATH) && cd $(KERNEL_BUILD_PATH) && ARCH=$(KERNEL_ARCH) $(KERNEL_PATH)/scripts/kconfig/merge_config.sh -n $(KERNEL_BUILD_PATH)/.config debug.config,)
++
++$(KERNEL_BZIMAGE): $(KERNEL_BUILD_PATH)/.config $(BUILD_PATH)/init-cpio-spec.txt $(MUSL_PATH)/lib/libc.so $(IPERF_PATH)/src/iperf3 $(IPUTILS_PATH)/ping $(BASH_PATH)/bash $(IPROUTE2_PATH)/misc/ss $(IPROUTE2_PATH)/ip/ip $(IPTABLES_PATH)/iptables/xtables-multi $(NMAP_PATH)/ncat/ncat $(WIREGUARD_TOOLS_PATH)/src/tools/wg $(BUILD_PATH)/init ../netns.sh $(WIREGUARD_SOURCES)
++	$(MAKE) -C $(KERNEL_PATH) O=$(KERNEL_BUILD_PATH) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(CROSS_COMPILE) CC="$(NOPIE_GCC)"
++
++$(BUILD_PATH)/include/linux/.installed: | $(KERNEL_BUILD_PATH)/.config
++	$(MAKE) -C $(KERNEL_PATH) O=$(KERNEL_BUILD_PATH) INSTALL_HDR_PATH=$(BUILD_PATH) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(CROSS_COMPILE) headers_install
++	touch $@
++
++$(MUSL_PATH)/lib/libc.so: $(MUSL_TAR)
++	mkdir -p $(BUILD_PATH)
++	flock -s $<.lock tar -C $(BUILD_PATH) -xf $<
++	cd $(MUSL_PATH) && CC=$(REAL_CC) ./configure --prefix=/ --disable-static --build=$(CBUILD)
++	$(MAKE) -C $(MUSL_PATH)
++	$(STRIP) -s $@
++
++$(BUILD_PATH)/include/.installed: $(MUSL_PATH)/lib/libc.so
++	$(MAKE) -C $(MUSL_PATH) DESTDIR=$(BUILD_PATH) install-headers
++	touch $@
++
++$(MUSL_CC): $(MUSL_PATH)/lib/libc.so
++	sh $(MUSL_PATH)/tools/musl-gcc.specs.sh $(BUILD_PATH)/include $(MUSL_PATH)/lib /lib/ld-linux.so.1 > $(BUILD_PATH)/musl-gcc.specs
++	printf '#!/bin/sh\nexec "$(REAL_CC)" --specs="$(BUILD_PATH)/musl-gcc.specs" -fno-stack-protector -no-pie "$$@"\n' > $(BUILD_PATH)/musl-gcc
++	chmod +x $(BUILD_PATH)/musl-gcc
++
++$(IPERF_PATH)/.installed: $(IPERF_TAR)
++	mkdir -p $(BUILD_PATH)
++	flock -s $<.lock tar -C $(BUILD_PATH) -xf $<
++	sed -i '1s/^/#include <stdint.h>/' $(IPERF_PATH)/src/cjson.h $(IPERF_PATH)/src/timer.h
++	sed -i -r 's/-p?g//g' $(IPERF_PATH)/src/Makefile*
++	touch $@
++
++$(IPERF_PATH)/src/iperf3: | $(IPERF_PATH)/.installed $(USERSPACE_DEPS)
++	cd $(IPERF_PATH) && CFLAGS="$(CFLAGS) -D_GNU_SOURCE" ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared
++	$(MAKE) -C $(IPERF_PATH)
++	$(STRIP) -s $@
++
++$(LIBMNL_PATH)/.installed: $(LIBMNL_TAR)
++	flock -s $<.lock tar -C $(BUILD_PATH) -xf $<
++	touch $@
++
++$(LIBMNL_PATH)/src/.libs/libmnl.a: | $(LIBMNL_PATH)/.installed $(USERSPACE_DEPS)
++	cd $(LIBMNL_PATH) && ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared
++	$(MAKE) -C $(LIBMNL_PATH)
++	sed -i 's:prefix=.*:prefix=$(LIBMNL_PATH):' $(LIBMNL_PATH)/libmnl.pc
++
++$(WIREGUARD_TOOLS_PATH)/.installed: $(WIREGUARD_TOOLS_TAR)
++	flock -s $<.lock tar -C $(BUILD_PATH) -xf $<
++	touch $@
++
++$(WIREGUARD_TOOLS_PATH)/src/tools/wg: | $(WIREGUARD_TOOLS_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS)
++	LDFLAGS="$(LDFLAGS) -L$(LIBMNL_PATH)/src/.libs" $(MAKE) -C $(WIREGUARD_TOOLS_PATH)/src/tools LIBMNL_CFLAGS="-I$(LIBMNL_PATH)/include" LIBMNL_LDLIBS="-lmnl" wg
++	$(STRIP) -s $@
++
++$(BUILD_PATH)/init: init.c | $(USERSPACE_DEPS)
++	mkdir -p $(BUILD_PATH)
++	$(MUSL_CC) -o $@ $(CFLAGS) $(LDFLAGS) -std=gnu11 $<
++	$(STRIP) -s $@
++
++$(IPUTILS_PATH)/.installed: $(IPUTILS_TAR)
++	mkdir -p $(BUILD_PATH)
++	flock -s $<.lock tar -C $(BUILD_PATH) -xf $<
++	touch $@
++
++$(IPUTILS_PATH)/ping: | $(IPUTILS_PATH)/.installed $(USERSPACE_DEPS)
++	$(MAKE) -C $(IPUTILS_PATH) USE_CAP=no USE_IDN=no USE_NETTLE=no USE_CRYPTO=no ping
++	$(STRIP) -s $@
++
++$(BASH_PATH)/.installed: $(BASH_TAR)
++	mkdir -p $(BUILD_PATH)
++	flock -s $<.lock tar -C $(BUILD_PATH) -xf $<
++	touch $@
++
++$(BASH_PATH)/bash: | $(BASH_PATH)/.installed $(USERSPACE_DEPS)
++	cd $(BASH_PATH) && ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --without-bash-malloc --disable-debugger --disable-help-builtin --disable-history --disable-multibyte --disable-progcomp --disable-readline --disable-mem-scramble
++	$(MAKE) -C $(BASH_PATH)
++	$(STRIP) -s $@
++
++$(IPROUTE2_PATH)/.installed: $(IPROUTE2_TAR)
++	mkdir -p $(BUILD_PATH)
++	flock -s $<.lock tar -C $(BUILD_PATH) -xf $<
++	printf 'CC:=$(CC)\nPKG_CONFIG:=pkg-config\nTC_CONFIG_XT:=n\nTC_CONFIG_ATM:=n\nTC_CONFIG_IPSET:=n\nIP_CONFIG_SETNS:=y\nHAVE_ELF:=n\nHAVE_MNL:=y\nHAVE_BERKELEY_DB:=n\nHAVE_LATEX:=n\nHAVE_PDFLATEX:=n\nCFLAGS+=-DHAVE_SETNS -DHAVE_LIBMNL -I$(LIBMNL_PATH)/include\nLDLIBS+=-lmnl' > $(IPROUTE2_PATH)/config.mk
++	printf 'lib: snapshot\n\t$$(MAKE) -C lib\nip/ip: lib\n\t$$(MAKE) -C ip ip\nmisc/ss: lib\n\t$$(MAKE) -C misc ss\n' >> $(IPROUTE2_PATH)/Makefile
++	touch $@
++
++$(IPROUTE2_PATH)/ip/ip: | $(IPROUTE2_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS)
++	LDFLAGS="$(LDFLAGS) -L$(LIBMNL_PATH)/src/.libs" PKG_CONFIG_LIBDIR="$(LIBMNL_PATH)" $(MAKE) -C $(IPROUTE2_PATH) PREFIX=/ ip/ip
++	$(STRIP) -s $(IPROUTE2_PATH)/ip/ip
++
++$(IPROUTE2_PATH)/misc/ss: | $(IPROUTE2_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS)
++	LDFLAGS="$(LDFLAGS) -L$(LIBMNL_PATH)/src/.libs" PKG_CONFIG_LIBDIR="$(LIBMNL_PATH)" $(MAKE) -C $(IPROUTE2_PATH) PREFIX=/ misc/ss
++	$(STRIP) -s $(IPROUTE2_PATH)/misc/ss
++
++$(IPTABLES_PATH)/.installed: $(IPTABLES_TAR)
++	mkdir -p $(BUILD_PATH)
++	flock -s $<.lock tar -C $(BUILD_PATH) -xf $<
++	sed -i -e "/nfnetlink=[01]/s:=[01]:=0:" -e "/nfconntrack=[01]/s:=[01]:=0:" $(IPTABLES_PATH)/configure
++	touch $@
++
++$(IPTABLES_PATH)/iptables/xtables-multi: | $(IPTABLES_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS)
++	cd $(IPTABLES_PATH) && PKG_CONFIG_LIBDIR="$(LIBMNL_PATH)" ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared --disable-nftables --disable-bpf-compiler --disable-nfsynproxy --disable-libipq --with-kernel=$(BUILD_PATH)/include
++	$(MAKE) -C $(IPTABLES_PATH)
++	$(STRIP) -s $@
++
++$(NMAP_PATH)/.installed: $(NMAP_TAR)
++	mkdir -p $(BUILD_PATH)
++	flock -s $<.lock tar -C $(BUILD_PATH) -xf $<
++	touch $@
++
++$(NMAP_PATH)/ncat/ncat: | $(NMAP_PATH)/.installed $(USERSPACE_DEPS)
++	cd $(NMAP_PATH) && ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared --without-ndiff --without-zenmap --without-nping --with-libpcap=included --with-libpcre=included --with-libdnet=included --without-liblua --with-liblinear=included --without-nmap-update --without-openssl --with-pcap=linux
++	$(MAKE) -C $(NMAP_PATH) build-ncat
++	$(STRIP) -s $@
++
++clean:
++	rm -rf $(BUILD_PATH)
++
++distclean: clean
++	rm -rf $(DISTFILES_PATH)
++
++menuconfig: $(KERNEL_BUILD_PATH)/.config
++	$(MAKE) -C $(KERNEL_PATH) O=$(KERNEL_BUILD_PATH) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(CROSS_COMPILE) CC="$(NOPIE_GCC)" menuconfig
++
++.PHONY: qemu build clean distclean menuconfig
++.DELETE_ON_ERROR:
+--- /dev/null
++++ b/tools/testing/selftests/wireguard/qemu/arch/aarch64.config
+@@ -0,0 +1,5 @@
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="console=ttyAMA0 wg.success=ttyAMA1"
++CONFIG_FRAME_WARN=1280
+--- /dev/null
++++ b/tools/testing/selftests/wireguard/qemu/arch/aarch64_be.config
+@@ -0,0 +1,6 @@
++CONFIG_CPU_BIG_ENDIAN=y
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="console=ttyAMA0 wg.success=ttyAMA1"
++CONFIG_FRAME_WARN=1280
+--- /dev/null
++++ b/tools/testing/selftests/wireguard/qemu/arch/arm.config
+@@ -0,0 +1,9 @@
++CONFIG_MMU=y
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_VIRT=y
++CONFIG_THUMB2_KERNEL=n
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="console=ttyAMA0 wg.success=ttyAMA1"
++CONFIG_FRAME_WARN=1024
+--- /dev/null
++++ b/tools/testing/selftests/wireguard/qemu/arch/armeb.config
+@@ -0,0 +1,10 @@
++CONFIG_MMU=y
++CONFIG_ARCH_MULTI_V7=y
++CONFIG_ARCH_VIRT=y
++CONFIG_THUMB2_KERNEL=n
++CONFIG_SERIAL_AMBA_PL011=y
++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="console=ttyAMA0 wg.success=ttyAMA1"
++CONFIG_CPU_BIG_ENDIAN=y
++CONFIG_FRAME_WARN=1024
+--- /dev/null
++++ b/tools/testing/selftests/wireguard/qemu/arch/i686.config
+@@ -0,0 +1,5 @@
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1"
++CONFIG_FRAME_WARN=1024
+--- /dev/null
++++ b/tools/testing/selftests/wireguard/qemu/arch/m68k.config
+@@ -0,0 +1,9 @@
++CONFIG_MMU=y
++CONFIG_M68040=y
++CONFIG_MAC=y
++CONFIG_SERIAL_PMACZILOG=y
++CONFIG_SERIAL_PMACZILOG_TTYS=y
++CONFIG_SERIAL_PMACZILOG_CONSOLE=y
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1"
++CONFIG_FRAME_WARN=1024
+--- /dev/null
++++ b/tools/testing/selftests/wireguard/qemu/arch/mips.config
+@@ -0,0 +1,11 @@
++CONFIG_CPU_MIPS32_R2=y
++CONFIG_MIPS_MALTA=y
++CONFIG_MIPS_CPS=y
++CONFIG_MIPS_FP_SUPPORT=y
++CONFIG_POWER_RESET=y
++CONFIG_POWER_RESET_SYSCON=y
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1"
++CONFIG_FRAME_WARN=1024
+--- /dev/null
++++ b/tools/testing/selftests/wireguard/qemu/arch/mips64.config
+@@ -0,0 +1,14 @@
++CONFIG_64BIT=y
++CONFIG_CPU_MIPS64_R2=y
++CONFIG_MIPS32_N32=y
++CONFIG_CPU_HAS_MSA=y
++CONFIG_MIPS_MALTA=y
++CONFIG_MIPS_CPS=y
++CONFIG_MIPS_FP_SUPPORT=y
++CONFIG_POWER_RESET=y
++CONFIG_POWER_RESET_SYSCON=y
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1"
++CONFIG_FRAME_WARN=1280
+--- /dev/null
++++ b/tools/testing/selftests/wireguard/qemu/arch/mips64el.config
+@@ -0,0 +1,15 @@
++CONFIG_64BIT=y
++CONFIG_CPU_MIPS64_R2=y
++CONFIG_MIPS32_N32=y
++CONFIG_CPU_HAS_MSA=y
++CONFIG_MIPS_MALTA=y
++CONFIG_CPU_LITTLE_ENDIAN=y
++CONFIG_MIPS_CPS=y
++CONFIG_MIPS_FP_SUPPORT=y
++CONFIG_POWER_RESET=y
++CONFIG_POWER_RESET_SYSCON=y
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1"
++CONFIG_FRAME_WARN=1280
+--- /dev/null
++++ b/tools/testing/selftests/wireguard/qemu/arch/mipsel.config
+@@ -0,0 +1,12 @@
++CONFIG_CPU_MIPS32_R2=y
++CONFIG_MIPS_MALTA=y
++CONFIG_CPU_LITTLE_ENDIAN=y
++CONFIG_MIPS_CPS=y
++CONFIG_MIPS_FP_SUPPORT=y
++CONFIG_POWER_RESET=y
++CONFIG_POWER_RESET_SYSCON=y
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1"
++CONFIG_FRAME_WARN=1024
+--- /dev/null
++++ b/tools/testing/selftests/wireguard/qemu/arch/powerpc.config
+@@ -0,0 +1,10 @@
++CONFIG_PPC_QEMU_E500=y
++CONFIG_FSL_SOC_BOOKE=y
++CONFIG_PPC_85xx=y
++CONFIG_PHYS_64BIT=y
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_MATH_EMULATION=y
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1"
++CONFIG_FRAME_WARN=1024
+--- /dev/null
++++ b/tools/testing/selftests/wireguard/qemu/arch/powerpc64le.config
+@@ -0,0 +1,12 @@
++CONFIG_PPC64=y
++CONFIG_PPC_PSERIES=y
++CONFIG_ALTIVEC=y
++CONFIG_VSX=y
++CONFIG_PPC_OF_BOOT_TRAMPOLINE=y
++CONFIG_PPC_RADIX_MMU=y
++CONFIG_HVC_CONSOLE=y
++CONFIG_CPU_LITTLE_ENDIAN=y
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="console=hvc0 wg.success=hvc1"
++CONFIG_SECTION_MISMATCH_WARN_ONLY=y
++CONFIG_FRAME_WARN=1280
+--- /dev/null
++++ b/tools/testing/selftests/wireguard/qemu/arch/x86_64.config
+@@ -0,0 +1,5 @@
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1"
++CONFIG_FRAME_WARN=1280
+--- /dev/null
++++ b/tools/testing/selftests/wireguard/qemu/debug.config
+@@ -0,0 +1,67 @@
++CONFIG_LOCALVERSION="-debug"
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_POINTER=y
++CONFIG_STACK_VALIDATION=y
++CONFIG_DEBUG_KERNEL=y
++CONFIG_DEBUG_INFO=y
++CONFIG_DEBUG_INFO_DWARF4=y
++CONFIG_PAGE_EXTENSION=y
++CONFIG_PAGE_POISONING=y
++CONFIG_DEBUG_OBJECTS=y
++CONFIG_DEBUG_OBJECTS_FREE=y
++CONFIG_DEBUG_OBJECTS_TIMERS=y
++CONFIG_DEBUG_OBJECTS_WORK=y
++CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
++CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
++CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT=1
++CONFIG_SLUB_DEBUG_ON=y
++CONFIG_DEBUG_VM=y
++CONFIG_DEBUG_MEMORY_INIT=y
++CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
++CONFIG_DEBUG_STACKOVERFLOW=y
++CONFIG_HAVE_ARCH_KMEMCHECK=y
++CONFIG_HAVE_ARCH_KASAN=y
++CONFIG_KASAN=y
++CONFIG_KASAN_INLINE=y
++CONFIG_UBSAN=y
++CONFIG_UBSAN_SANITIZE_ALL=y
++CONFIG_UBSAN_NO_ALIGNMENT=y
++CONFIG_UBSAN_NULL=y
++CONFIG_DEBUG_KMEMLEAK=y
++CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=8192
++CONFIG_DEBUG_STACK_USAGE=y
++CONFIG_DEBUG_SHIRQ=y
++CONFIG_WQ_WATCHDOG=y
++CONFIG_SCHED_DEBUG=y
++CONFIG_SCHED_INFO=y
++CONFIG_SCHEDSTATS=y
++CONFIG_SCHED_STACK_END_CHECK=y
++CONFIG_DEBUG_TIMEKEEPING=y
++CONFIG_TIMER_STATS=y
++CONFIG_DEBUG_PREEMPT=y
++CONFIG_DEBUG_RT_MUTEXES=y
++CONFIG_DEBUG_SPINLOCK=y
++CONFIG_DEBUG_MUTEXES=y
++CONFIG_DEBUG_LOCK_ALLOC=y
++CONFIG_PROVE_LOCKING=y
++CONFIG_LOCKDEP=y
++CONFIG_DEBUG_ATOMIC_SLEEP=y
++CONFIG_TRACE_IRQFLAGS=y
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_LIST=y
++CONFIG_DEBUG_PI_LIST=y
++CONFIG_PROVE_RCU=y
++CONFIG_SPARSE_RCU_POINTER=y
++CONFIG_RCU_CPU_STALL_TIMEOUT=21
++CONFIG_RCU_TRACE=y
++CONFIG_RCU_EQS_DEBUG=y
++CONFIG_USER_STACKTRACE_SUPPORT=y
++CONFIG_DEBUG_SG=y
++CONFIG_DEBUG_NOTIFIERS=y
++CONFIG_DOUBLEFAULT=y
++CONFIG_X86_DEBUG_FPU=y
++CONFIG_DEBUG_SECTION_MISMATCH=y
++CONFIG_DEBUG_PAGEALLOC=y
++CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y
++CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y
+--- /dev/null
++++ b/tools/testing/selftests/wireguard/qemu/init.c
+@@ -0,0 +1,284 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
++ */
++
++#define _GNU_SOURCE
++#include <unistd.h>
++#include <errno.h>
++#include <string.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <stdbool.h>
++#include <fcntl.h>
++#include <sys/wait.h>
++#include <sys/mount.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <sys/types.h>
++#include <sys/io.h>
++#include <sys/ioctl.h>
++#include <sys/reboot.h>
++#include <sys/utsname.h>
++#include <sys/sendfile.h>
++#include <linux/random.h>
++#include <linux/version.h>
++
++__attribute__((noreturn)) static void poweroff(void)
++{
++	fflush(stdout);
++	fflush(stderr);
++	reboot(RB_AUTOBOOT);
++	sleep(30);
++	fprintf(stderr, "\x1b[37m\x1b[41m\x1b[1mFailed to power off!!!\x1b[0m\n");
++	exit(1);
++}
++
++static void panic(const char *what)
++{
++	fprintf(stderr, "\n\n\x1b[37m\x1b[41m\x1b[1mSOMETHING WENT HORRIBLY WRONG\x1b[0m\n\n    \x1b[31m\x1b[1m%s: %s\x1b[0m\n\n\x1b[37m\x1b[44m\x1b[1mPower off...\x1b[0m\n\n", what, strerror(errno));
++	poweroff();
++}
++
++#define pretty_message(msg) puts("\x1b[32m\x1b[1m" msg "\x1b[0m")
++
++static void print_banner(void)
++{
++	struct utsname utsname;
++	int len;
++
++	if (uname(&utsname) < 0)
++		panic("uname");
++
++	len = strlen("    WireGuard Test Suite on       ") + strlen(utsname.sysname) + strlen(utsname.release) + strlen(utsname.machine);
++	printf("\x1b[45m\x1b[33m\x1b[1m%*.s\x1b[0m\n\x1b[45m\x1b[33m\x1b[1m    WireGuard Test Suite on %s %s %s    \x1b[0m\n\x1b[45m\x1b[33m\x1b[1m%*.s\x1b[0m\n\n", len, "", utsname.sysname, utsname.release, utsname.machine, len, "");
++}
++
++static void seed_rng(void)
++{
++	int fd;
++	struct {
++		int entropy_count;
++		int buffer_size;
++		unsigned char buffer[256];
++	} entropy = {
++		.entropy_count = sizeof(entropy.buffer) * 8,
++		.buffer_size = sizeof(entropy.buffer),
++		.buffer = "Adding real entropy is not actually important for these tests. Don't try this at home, kids!"
++	};
++
++	if (mknod("/dev/urandom", S_IFCHR | 0644, makedev(1, 9)))
++		panic("mknod(/dev/urandom)");
++	fd = open("/dev/urandom", O_WRONLY);
++	if (fd < 0)
++		panic("open(urandom)");
++	for (int i = 0; i < 256; ++i) {
++		if (ioctl(fd, RNDADDENTROPY, &entropy) < 0)
++			panic("ioctl(urandom)");
++	}
++	close(fd);
++}
++
++static void mount_filesystems(void)
++{
++	pretty_message("[+] Mounting filesystems...");
++	mkdir("/dev", 0755);
++	mkdir("/proc", 0755);
++	mkdir("/sys", 0755);
++	mkdir("/tmp", 0755);
++	mkdir("/run", 0755);
++	mkdir("/var", 0755);
++	if (mount("none", "/dev", "devtmpfs", 0, NULL))
++		panic("devtmpfs mount");
++	if (mount("none", "/proc", "proc", 0, NULL))
++		panic("procfs mount");
++	if (mount("none", "/sys", "sysfs", 0, NULL))
++		panic("sysfs mount");
++	if (mount("none", "/tmp", "tmpfs", 0, NULL))
++		panic("tmpfs mount");
++	if (mount("none", "/run", "tmpfs", 0, NULL))
++		panic("tmpfs mount");
++	if (mount("none", "/sys/kernel/debug", "debugfs", 0, NULL))
++		; /* Not a problem if it fails.*/
++	if (symlink("/run", "/var/run"))
++		panic("run symlink");
++	if (symlink("/proc/self/fd", "/dev/fd"))
++		panic("fd symlink");
++}
++
++static void enable_logging(void)
++{
++	int fd;
++	pretty_message("[+] Enabling logging...");
++	fd = open("/proc/sys/kernel/printk", O_WRONLY);
++	if (fd >= 0) {
++		if (write(fd, "9\n", 2) != 2)
++			panic("write(printk)");
++		close(fd);
++	}
++	fd = open("/proc/sys/debug/exception-trace", O_WRONLY);
++	if (fd >= 0) {
++		if (write(fd, "1\n", 2) != 2)
++			panic("write(exception-trace)");
++		close(fd);
++	}
++	fd = open("/proc/sys/kernel/panic_on_warn", O_WRONLY);
++	if (fd >= 0) {
++		if (write(fd, "1\n", 2) != 2)
++			panic("write(panic_on_warn)");
++		close(fd);
++	}
++}
++
++static void kmod_selftests(void)
++{
++	FILE *file;
++	char line[2048], *start, *pass;
++	bool success = true;
++	pretty_message("[+] Module self-tests:");
++	file = fopen("/proc/kmsg", "r");
++	if (!file)
++		panic("fopen(kmsg)");
++	if (fcntl(fileno(file), F_SETFL, O_NONBLOCK) < 0)
++		panic("fcntl(kmsg, nonblock)");
++	while (fgets(line, sizeof(line), file)) {
++		start = strstr(line, "wireguard: ");
++		if (!start)
++			continue;
++		start += 11;
++		*strchrnul(start, '\n') = '\0';
++		if (strstr(start, "www.wireguard.com"))
++			break;
++		pass = strstr(start, ": pass");
++		if (!pass || pass[6] != '\0') {
++			success = false;
++			printf(" \x1b[31m*  %s\x1b[0m\n", start);
++		} else
++			printf(" \x1b[32m*  %s\x1b[0m\n", start);
++	}
++	fclose(file);
++	if (!success) {
++		puts("\x1b[31m\x1b[1m[-] Tests failed! \u2639\x1b[0m");
++		poweroff();
++	}
++}
++
++static void launch_tests(void)
++{
++	char cmdline[4096], *success_dev;
++	int status, fd;
++	pid_t pid;
++
++	pretty_message("[+] Launching tests...");
++	pid = fork();
++	if (pid == -1)
++		panic("fork");
++	else if (pid == 0) {
++		execl("/init.sh", "init", NULL);
++		panic("exec");
++	}
++	if (waitpid(pid, &status, 0) < 0)
++		panic("waitpid");
++	if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
++		pretty_message("[+] Tests successful! :-)");
++		fd = open("/proc/cmdline", O_RDONLY);
++		if (fd < 0)
++			panic("open(/proc/cmdline)");
++		if (read(fd, cmdline, sizeof(cmdline) - 1) <= 0)
++			panic("read(/proc/cmdline)");
++		cmdline[sizeof(cmdline) - 1] = '\0';
++		for (success_dev = strtok(cmdline, " \n"); success_dev; success_dev = strtok(NULL, " \n")) {
++			if (strncmp(success_dev, "wg.success=", 11))
++				continue;
++			memcpy(success_dev + 11 - 5, "/dev/", 5);
++			success_dev += 11 - 5;
++			break;
++		}
++		if (!success_dev || !strlen(success_dev))
++			panic("Unable to find success device");
++
++		fd = open(success_dev, O_WRONLY);
++		if (fd < 0)
++			panic("open(success_dev)");
++		if (write(fd, "success\n", 8) != 8)
++			panic("write(success_dev)");
++		close(fd);
++	} else {
++		const char *why = "unknown cause";
++		int what = -1;
++
++		if (WIFEXITED(status)) {
++			why = "exit code";
++			what = WEXITSTATUS(status);
++		} else if (WIFSIGNALED(status)) {
++			why = "signal";
++			what = WTERMSIG(status);
++		}
++		printf("\x1b[31m\x1b[1m[-] Tests failed with %s %d! \u2639\x1b[0m\n", why, what);
++	}
++}
++
++static void ensure_console(void)
++{
++	for (unsigned int i = 0; i < 1000; ++i) {
++		int fd = open("/dev/console", O_RDWR);
++		if (fd < 0) {
++			usleep(50000);
++			continue;
++		}
++		dup2(fd, 0);
++		dup2(fd, 1);
++		dup2(fd, 2);
++		close(fd);
++		if (write(1, "\0\0\0\0\n", 5) == 5)
++			return;
++	}
++	panic("Unable to open console device");
++}
++
++static void clear_leaks(void)
++{
++	int fd;
++
++	fd = open("/sys/kernel/debug/kmemleak", O_WRONLY);
++	if (fd < 0)
++		return;
++	pretty_message("[+] Starting memory leak detection...");
++	write(fd, "clear\n", 5);
++	close(fd);
++}
++
++static void check_leaks(void)
++{
++	int fd;
++
++	fd = open("/sys/kernel/debug/kmemleak", O_WRONLY);
++	if (fd < 0)
++		return;
++	pretty_message("[+] Scanning for memory leaks...");
++	sleep(2); /* Wait for any grace periods. */
++	write(fd, "scan\n", 5);
++	close(fd);
++
++	fd = open("/sys/kernel/debug/kmemleak", O_RDONLY);
++	if (fd < 0)
++		return;
++	if (sendfile(1, fd, NULL, 0x7ffff000) > 0)
++		panic("Memory leaks encountered");
++	close(fd);
++}
++
++int main(int argc, char *argv[])
++{
++	seed_rng();
++	ensure_console();
++	print_banner();
++	mount_filesystems();
++	kmod_selftests();
++	enable_logging();
++	clear_leaks();
++	launch_tests();
++	check_leaks();
++	poweroff();
++	return 1;
++}
+--- /dev/null
++++ b/tools/testing/selftests/wireguard/qemu/kernel.config
+@@ -0,0 +1,86 @@
++CONFIG_LOCALVERSION=""
++CONFIG_NET=y
++CONFIG_NETDEVICES=y
++CONFIG_NET_CORE=y
++CONFIG_NET_IPIP=y
++CONFIG_DUMMY=y
++CONFIG_VETH=y
++CONFIG_MULTIUSER=y
++CONFIG_NAMESPACES=y
++CONFIG_NET_NS=y
++CONFIG_UNIX=y
++CONFIG_INET=y
++CONFIG_IPV6=y
++CONFIG_NETFILTER=y
++CONFIG_NETFILTER_ADVANCED=y
++CONFIG_NF_CONNTRACK=y
++CONFIG_NF_NAT=y
++CONFIG_NETFILTER_XTABLES=y
++CONFIG_NETFILTER_XT_NAT=y
++CONFIG_NETFILTER_XT_MATCH_LENGTH=y
++CONFIG_NF_CONNTRACK_IPV4=y
++CONFIG_NF_NAT_IPV4=y
++CONFIG_IP_NF_IPTABLES=y
++CONFIG_IP_NF_FILTER=y
++CONFIG_IP_NF_NAT=y
++CONFIG_IP_ADVANCED_ROUTER=y
++CONFIG_IP_MULTIPLE_TABLES=y
++CONFIG_IPV6_MULTIPLE_TABLES=y
++CONFIG_TTY=y
++CONFIG_BINFMT_ELF=y
++CONFIG_BINFMT_SCRIPT=y
++CONFIG_VDSO=y
++CONFIG_VIRTUALIZATION=y
++CONFIG_HYPERVISOR_GUEST=y
++CONFIG_PARAVIRT=y
++CONFIG_KVM_GUEST=y
++CONFIG_PARAVIRT_SPINLOCKS=y
++CONFIG_PRINTK=y
++CONFIG_KALLSYMS=y
++CONFIG_BUG=y
++CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
++CONFIG_EMBEDDED=n
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_SHMEM=y
++CONFIG_SLUB=y
++CONFIG_SPARSEMEM_VMEMMAP=y
++CONFIG_SMP=y
++CONFIG_SCHED_SMT=y
++CONFIG_SCHED_MC=y
++CONFIG_NUMA=y
++CONFIG_PREEMPT=y
++CONFIG_NO_HZ=y
++CONFIG_NO_HZ_IDLE=y
++CONFIG_NO_HZ_FULL=n
++CONFIG_HZ_PERIODIC=n
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_ARCH_RANDOM=y
++CONFIG_FILE_LOCKING=y
++CONFIG_POSIX_TIMERS=y
++CONFIG_DEVTMPFS=y
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++CONFIG_CONSOLE_LOGLEVEL_DEFAULT=15
++CONFIG_PRINTK_TIME=y
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_LEGACY_VSYSCALL_NONE=y
++CONFIG_KERNEL_GZIP=y
++CONFIG_PANIC_ON_OOPS=y
++CONFIG_BUG_ON_DATA_CORRUPTION=y
++CONFIG_LOCKUP_DETECTOR=y
++CONFIG_SOFTLOCKUP_DETECTOR=y
++CONFIG_HARDLOCKUP_DETECTOR=y
++CONFIG_WQ_WATCHDOG=y
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
++CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y
++CONFIG_PANIC_TIMEOUT=-1
++CONFIG_STACKTRACE=y
++CONFIG_EARLY_PRINTK=y
++CONFIG_GDB_SCRIPTS=y
++CONFIG_WIREGUARD=y
++CONFIG_WIREGUARD_DEBUG=y
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0074-wireguard-Kconfig-select-parent-dependency-for-crypt.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0074-wireguard-Kconfig-select-parent-dependency-for-crypt.patch
new file mode 100644
index 0000000..c2f8f77
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0074-wireguard-Kconfig-select-parent-dependency-for-crypt.patch
@@ -0,0 +1,30 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Sun, 15 Dec 2019 22:08:01 +0100
+Subject: [PATCH] wireguard: Kconfig: select parent dependency for crypto
+
+commit d7c68a38bb4f9b7c1a2e4a772872c752ee5c44a6 upstream.
+
+This fixes the crypto selection submenu depenencies. Otherwise, we'd
+wind up issuing warnings in which certain dependencies we also select
+couldn't be satisfied. This condition was triggered by the addition of
+the test suite autobuilder in the previous commit.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/Kconfig | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -85,6 +85,8 @@ config WIREGUARD
+ 	select CRYPTO_POLY1305_X86_64 if X86 && 64BIT
+ 	select CRYPTO_BLAKE2S_X86 if X86 && 64BIT
+ 	select CRYPTO_CURVE25519_X86 if X86 && 64BIT
++	select ARM_CRYPTO if ARM
++	select ARM64_CRYPTO if ARM64
+ 	select CRYPTO_CHACHA20_NEON if (ARM || ARM64) && KERNEL_MODE_NEON
+ 	select CRYPTO_POLY1305_NEON if ARM64 && KERNEL_MODE_NEON
+ 	select CRYPTO_POLY1305_ARM if ARM
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0075-wireguard-global-fix-spelling-mistakes-in-comments.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0075-wireguard-global-fix-spelling-mistakes-in-comments.patch
new file mode 100644
index 0000000..9b34e66
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0075-wireguard-global-fix-spelling-mistakes-in-comments.patch
@@ -0,0 +1,66 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Josh Soref <jsoref@gmail.com>
+Date: Sun, 15 Dec 2019 22:08:02 +0100
+Subject: [PATCH] wireguard: global: fix spelling mistakes in comments
+
+commit a2ec8b5706944d228181c8b91d815f41d6dd8e7b upstream.
+
+This fixes two spelling errors in source code comments.
+
+Signed-off-by: Josh Soref <jsoref@gmail.com>
+[Jason: rewrote commit message]
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/receive.c | 2 +-
+ include/uapi/linux/wireguard.h  | 8 ++++----
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/wireguard/receive.c
++++ b/drivers/net/wireguard/receive.c
+@@ -380,7 +380,7 @@ static void wg_packet_consume_data_done(
+ 	/* We've already verified the Poly1305 auth tag, which means this packet
+ 	 * was not modified in transit. We can therefore tell the networking
+ 	 * stack that all checksums of every layer of encapsulation have already
+-	 * been checked "by the hardware" and therefore is unneccessary to check
++	 * been checked "by the hardware" and therefore is unnecessary to check
+ 	 * again in software.
+ 	 */
+ 	skb->ip_summed = CHECKSUM_UNNECESSARY;
+--- a/include/uapi/linux/wireguard.h
++++ b/include/uapi/linux/wireguard.h
+@@ -18,13 +18,13 @@
+  * one but not both of:
+  *
+  *    WGDEVICE_A_IFINDEX: NLA_U32
+- *    WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMESIZ - 1
++ *    WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMSIZ - 1
+  *
+  * The kernel will then return several messages (NLM_F_MULTI) containing the
+  * following tree of nested items:
+  *
+  *    WGDEVICE_A_IFINDEX: NLA_U32
+- *    WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMESIZ - 1
++ *    WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMSIZ - 1
+  *    WGDEVICE_A_PRIVATE_KEY: NLA_EXACT_LEN, len WG_KEY_LEN
+  *    WGDEVICE_A_PUBLIC_KEY: NLA_EXACT_LEN, len WG_KEY_LEN
+  *    WGDEVICE_A_LISTEN_PORT: NLA_U16
+@@ -77,7 +77,7 @@
+  * WGDEVICE_A_IFINDEX and WGDEVICE_A_IFNAME:
+  *
+  *    WGDEVICE_A_IFINDEX: NLA_U32
+- *    WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMESIZ - 1
++ *    WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMSIZ - 1
+  *    WGDEVICE_A_FLAGS: NLA_U32, 0 or WGDEVICE_F_REPLACE_PEERS if all current
+  *                      peers should be removed prior to adding the list below.
+  *    WGDEVICE_A_PRIVATE_KEY: len WG_KEY_LEN, all zeros to remove
+@@ -121,7 +121,7 @@
+  * filling in information not contained in the prior. Note that if
+  * WGDEVICE_F_REPLACE_PEERS is specified in the first message, it probably
+  * should not be specified in fragments that come after, so that the list
+- * of peers is only cleared the first time but appened after. Likewise for
++ * of peers is only cleared the first time but appended after. Likewise for
+  * peers, if WGPEER_F_REPLACE_ALLOWEDIPS is specified in the first message
+  * of a peer, it likely should not be specified in subsequent fragments.
+  *
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0076-wireguard-main-remove-unused-include-linux-version.h.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0076-wireguard-main-remove-unused-include-linux-version.h.patch
new file mode 100644
index 0000000..3cc0b56
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0076-wireguard-main-remove-unused-include-linux-version.h.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: YueHaibing <yuehaibing@huawei.com>
+Date: Sun, 15 Dec 2019 22:08:03 +0100
+Subject: [PATCH] wireguard: main: remove unused include <linux/version.h>
+
+commit 43967b6ff91e53bcce5ae08c16a0588a475b53a1 upstream.
+
+Remove <linux/version.h> from the includes for main.c, which is unused.
+
+Signed-off-by: YueHaibing <yuehaibing@huawei.com>
+[Jason: reworded commit message]
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/main.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/net/wireguard/main.c
++++ b/drivers/net/wireguard/main.c
+@@ -12,7 +12,6 @@
+ 
+ #include <uapi/linux/wireguard.h>
+ 
+-#include <linux/version.h>
+ #include <linux/init.h>
+ #include <linux/module.h>
+ #include <linux/genetlink.h>
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0077-wireguard-allowedips-use-kfree_rcu-instead-of-call_r.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0077-wireguard-allowedips-use-kfree_rcu-instead-of-call_r.patch
new file mode 100644
index 0000000..edd9048
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0077-wireguard-allowedips-use-kfree_rcu-instead-of-call_r.patch
@@ -0,0 +1,41 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Wei Yongjun <weiyongjun1@huawei.com>
+Date: Sun, 15 Dec 2019 22:08:04 +0100
+Subject: [PATCH] wireguard: allowedips: use kfree_rcu() instead of call_rcu()
+
+commit d89ee7d5c73af15c1c6f12b016cdf469742b5726 upstream.
+
+The callback function of call_rcu() just calls a kfree(), so we
+can use kfree_rcu() instead of call_rcu() + callback function.
+
+Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/allowedips.c | 7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+--- a/drivers/net/wireguard/allowedips.c
++++ b/drivers/net/wireguard/allowedips.c
+@@ -31,11 +31,6 @@ static void copy_and_assign_cidr(struct
+ #define CHOOSE_NODE(parent, key) \
+ 	parent->bit[(key[parent->bit_at_a] >> parent->bit_at_b) & 1]
+ 
+-static void node_free_rcu(struct rcu_head *rcu)
+-{
+-	kfree(container_of(rcu, struct allowedips_node, rcu));
+-}
+-
+ static void push_rcu(struct allowedips_node **stack,
+ 		     struct allowedips_node __rcu *p, unsigned int *len)
+ {
+@@ -112,7 +107,7 @@ static void walk_remove_by_peer(struct a
+ 				if (!node->bit[0] || !node->bit[1]) {
+ 					rcu_assign_pointer(*nptr, DEREF(
+ 					       &node->bit[!REF(node->bit[0])]));
+-					call_rcu(&node->rcu, node_free_rcu);
++					kfree_rcu(node, rcu);
+ 					node = DEREF(nptr);
+ 				}
+ 			}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0078-wireguard-selftests-remove-ancient-kernel-compatibil.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0078-wireguard-selftests-remove-ancient-kernel-compatibil.patch
new file mode 100644
index 0000000..6ff0dd9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0078-wireguard-selftests-remove-ancient-kernel-compatibil.patch
@@ -0,0 +1,373 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Thu, 2 Jan 2020 17:47:49 +0100
+Subject: [PATCH] wireguard: selftests: remove ancient kernel compatibility
+ code
+
+commit 9a69a4c8802adf642bc4a13d471b5a86b44ed434 upstream.
+
+Quite a bit of the test suite was designed to work with ancient kernels.
+Thankfully we no longer have to deal with this. This commit updates
+things that we can finally update and removes things that we can finally
+remove, to avoid the build-up of the last several years as a result of
+having to support ancient kernels. We can finally rely on suppress_
+prefixlength being available. On the build side of things, the no-PIE
+hack is no longer required, and we can bump some of the tools, repair
+our m68k and i686-kvm support, and get better coverage of the static
+branches used in the crypto lib and in udp_tunnel.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ tools/testing/selftests/wireguard/netns.sh    | 11 +--
+ .../testing/selftests/wireguard/qemu/Makefile | 82 ++++++++++---------
+ .../selftests/wireguard/qemu/arch/m68k.config |  2 +-
+ tools/testing/selftests/wireguard/qemu/init.c |  1 +
+ .../selftests/wireguard/qemu/kernel.config    |  2 +
+ 5 files changed, 50 insertions(+), 48 deletions(-)
+
+--- a/tools/testing/selftests/wireguard/netns.sh
++++ b/tools/testing/selftests/wireguard/netns.sh
+@@ -37,7 +37,7 @@ n2() { pretty 2 "$*"; maybe_exec ip netn
+ ip0() { pretty 0 "ip $*"; ip -n $netns0 "$@"; }
+ ip1() { pretty 1 "ip $*"; ip -n $netns1 "$@"; }
+ ip2() { pretty 2 "ip $*"; ip -n $netns2 "$@"; }
+-sleep() { read -t "$1" -N 0 || true; }
++sleep() { read -t "$1" -N 1 || true; }
+ waitiperf() { pretty "${1//*-}" "wait for iperf:5201"; while [[ $(ss -N "$1" -tlp 'sport = 5201') != *iperf3* ]]; do sleep 0.1; done; }
+ waitncatudp() { pretty "${1//*-}" "wait for udp:1111"; while [[ $(ss -N "$1" -ulp 'sport = 1111') != *ncat* ]]; do sleep 0.1; done; }
+ waitncattcp() { pretty "${1//*-}" "wait for tcp:1111"; while [[ $(ss -N "$1" -tlp 'sport = 1111') != *ncat* ]]; do sleep 0.1; done; }
+@@ -294,12 +294,9 @@ ip1 -6 rule add table main suppress_pref
+ ip1 -4 route add default dev wg0 table 51820
+ ip1 -4 rule add not fwmark 51820 table 51820
+ ip1 -4 rule add table main suppress_prefixlength 0
+-# suppress_prefixlength only got added in 3.12, and we want to support 3.10+.
+-if [[ $(ip1 -4 rule show all) == *suppress_prefixlength* ]]; then
+-	# Flood the pings instead of sending just one, to trigger routing table reference counting bugs.
+-	n1 ping -W 1 -c 100 -f 192.168.99.7
+-	n1 ping -W 1 -c 100 -f abab::1111
+-fi
++# Flood the pings instead of sending just one, to trigger routing table reference counting bugs.
++n1 ping -W 1 -c 100 -f 192.168.99.7
++n1 ping -W 1 -c 100 -f abab::1111
+ 
+ n0 iptables -t nat -F
+ ip0 link del vethrc
+--- a/tools/testing/selftests/wireguard/qemu/Makefile
++++ b/tools/testing/selftests/wireguard/qemu/Makefile
+@@ -5,6 +5,7 @@
+ PWD := $(shell pwd)
+ 
+ CHOST := $(shell gcc -dumpmachine)
++HOST_ARCH := $(firstword $(subst -, ,$(CHOST)))
+ ifneq (,$(ARCH))
+ CBUILD := $(subst -gcc,,$(lastword $(subst /, ,$(firstword $(wildcard $(foreach bindir,$(subst :, ,$(PATH)),$(bindir)/$(ARCH)-*-gcc))))))
+ ifeq (,$(CBUILD))
+@@ -37,19 +38,19 @@ endef
+ define file_download =
+ $(DISTFILES_PATH)/$(1):
+ 	mkdir -p $(DISTFILES_PATH)
+-	flock -x $$@.lock -c '[ -f $$@ ] && exit 0; wget -O $$@.tmp $(MIRROR)$(1) || wget -t inf --retry-on-http-error=404 -O $$@.tmp $(2)$(1) || rm -f $$@.tmp'
++	flock -x $$@.lock -c '[ -f $$@ ] && exit 0; wget -O $$@.tmp $(MIRROR)$(1) || wget -O $$@.tmp $(2)$(1) || rm -f $$@.tmp'
+ 	if echo "$(3)  $$@.tmp" | sha256sum -c -; then mv $$@.tmp $$@; else rm -f $$@.tmp; exit 71; fi
+ endef
+ 
+-$(eval $(call tar_download,MUSL,musl,1.1.20,.tar.gz,https://www.musl-libc.org/releases/,44be8771d0e6c6b5f82dd15662eb2957c9a3173a19a8b49966ac0542bbd40d61))
++$(eval $(call tar_download,MUSL,musl,1.1.24,.tar.gz,https://www.musl-libc.org/releases/,1370c9a812b2cf2a7d92802510cca0058cc37e66a7bedd70051f0a34015022a3))
+ $(eval $(call tar_download,LIBMNL,libmnl,1.0.4,.tar.bz2,https://www.netfilter.org/projects/libmnl/files/,171f89699f286a5854b72b91d06e8f8e3683064c5901fb09d954a9ab6f551f81))
+-$(eval $(call tar_download,IPERF,iperf,3.1.7,.tar.gz,http://downloads.es.net/pub/iperf/,a4ef73406fe92250602b8da2ae89ec53211f805df97a1d1d629db5a14043734f))
++$(eval $(call tar_download,IPERF,iperf,3.7,.tar.gz,https://downloads.es.net/pub/iperf/,d846040224317caf2f75c843d309a950a7db23f9b44b94688ccbe557d6d1710c))
+ $(eval $(call tar_download,BASH,bash,5.0,.tar.gz,https://ftp.gnu.org/gnu/bash/,b4a80f2ac66170b2913efbfb9f2594f1f76c7b1afd11f799e22035d63077fb4d))
+-$(eval $(call tar_download,IPROUTE2,iproute2,5.1.0,.tar.gz,https://www.kernel.org/pub/linux/utils/net/iproute2/,9b43707d6075ecdca14803ca8ce0c8553848c49fa1586d12fd508d66577243f2))
+-$(eval $(call tar_download,IPTABLES,iptables,1.6.1,.tar.bz2,https://www.netfilter.org/projects/iptables/files/,0fc2d7bd5d7be11311726466789d4c65fb4c8e096c9182b56ce97440864f0cf5))
+-$(eval $(call tar_download,NMAP,nmap,7.60,.tar.bz2,https://nmap.org/dist/,a8796ecc4fa6c38aad6139d9515dc8113023a82e9d787e5a5fb5fa1b05516f21))
+-$(eval $(call tar_download,IPUTILS,iputils,s20161105,.tar.gz,https://github.com/iputils/iputils/archive/s20161105.tar.gz/#,f813092f03d17294fd23544b129b95cdb87fe19f7970a51908a6b88509acad8a))
+-$(eval $(call tar_download,WIREGUARD_TOOLS,WireGuard,0.0.20191212,.tar.xz,https://git.zx2c4.com/WireGuard/snapshot/,b0d718380f7a8822b2f12d75e462fa4eafa3a77871002981f367cd4fe2a1b071))
++$(eval $(call tar_download,IPROUTE2,iproute2,5.4.0,.tar.xz,https://www.kernel.org/pub/linux/utils/net/iproute2/,fe97aa60a0d4c5ac830be18937e18dc3400ca713a33a89ad896ff1e3d46086ae))
++$(eval $(call tar_download,IPTABLES,iptables,1.8.4,.tar.bz2,https://www.netfilter.org/projects/iptables/files/,993a3a5490a544c2cbf2ef15cf7e7ed21af1845baf228318d5c36ef8827e157c))
++$(eval $(call tar_download,NMAP,nmap,7.80,.tar.bz2,https://nmap.org/dist/,fcfa5a0e42099e12e4bf7a68ebe6fde05553383a682e816a7ec9256ab4773faa))
++$(eval $(call tar_download,IPUTILS,iputils,s20190709,.tar.gz,https://github.com/iputils/iputils/archive/s20190709.tar.gz/#,a15720dd741d7538dd2645f9f516d193636ae4300ff7dbc8bfca757bf166490a))
++$(eval $(call tar_download,WIREGUARD_TOOLS,wireguard-tools,1.0.20191226,.tar.xz,https://git.zx2c4.com/wireguard-tools/snapshot/,aa8af0fdc9872d369d8c890a84dbc2a2466b55795dccd5b47721b2d97644b04f))
+ 
+ KERNEL_BUILD_PATH := $(BUILD_PATH)/kernel$(if $(findstring yes,$(DEBUG_KERNEL)),-debug)
+ rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))
+@@ -59,23 +60,21 @@ export CFLAGS ?= -O3 -pipe
+ export LDFLAGS ?=
+ export CPPFLAGS := -I$(BUILD_PATH)/include
+ 
+-ifeq ($(CHOST),$(CBUILD))
++ifeq ($(HOST_ARCH),$(ARCH))
+ CROSS_COMPILE_FLAG := --host=$(CHOST)
+-NOPIE_GCC := gcc -fno-PIE
+ CFLAGS += -march=native
+ STRIP := strip
+ else
+ $(info Cross compilation: building for $(CBUILD) using $(CHOST))
+ CROSS_COMPILE_FLAG := --build=$(CBUILD) --host=$(CHOST)
+ export CROSS_COMPILE=$(CBUILD)-
+-NOPIE_GCC := $(CBUILD)-gcc -fno-PIE
+ STRIP := $(CBUILD)-strip
+ endif
+ ifeq ($(ARCH),aarch64)
+ QEMU_ARCH := aarch64
+ KERNEL_ARCH := arm64
+ KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/arm64/boot/Image
+-ifeq ($(CHOST),$(CBUILD))
++ifeq ($(HOST_ARCH),$(ARCH))
+ QEMU_MACHINE := -cpu host -machine virt,gic_version=host,accel=kvm
+ else
+ QEMU_MACHINE := -cpu cortex-a53 -machine virt
+@@ -85,7 +84,7 @@ else ifeq ($(ARCH),aarch64_be)
+ QEMU_ARCH := aarch64
+ KERNEL_ARCH := arm64
+ KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/arm64/boot/Image
+-ifeq ($(CHOST),$(CBUILD))
++ifeq ($(HOST_ARCH),$(ARCH))
+ QEMU_MACHINE := -cpu host -machine virt,gic_version=host,accel=kvm
+ else
+ QEMU_MACHINE := -cpu cortex-a53 -machine virt
+@@ -95,7 +94,7 @@ else ifeq ($(ARCH),arm)
+ QEMU_ARCH := arm
+ KERNEL_ARCH := arm
+ KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/arm/boot/zImage
+-ifeq ($(CHOST),$(CBUILD))
++ifeq ($(HOST_ARCH),$(ARCH))
+ QEMU_MACHINE := -cpu host -machine virt,gic_version=host,accel=kvm
+ else
+ QEMU_MACHINE := -cpu cortex-a15 -machine virt
+@@ -105,7 +104,7 @@ else ifeq ($(ARCH),armeb)
+ QEMU_ARCH := arm
+ KERNEL_ARCH := arm
+ KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/arm/boot/zImage
+-ifeq ($(CHOST),$(CBUILD))
++ifeq ($(HOST_ARCH),$(ARCH))
+ QEMU_MACHINE := -cpu host -machine virt,gic_version=host,accel=kvm
+ else
+ QEMU_MACHINE := -cpu cortex-a15 -machine virt
+@@ -116,7 +115,7 @@ else ifeq ($(ARCH),x86_64)
+ QEMU_ARCH := x86_64
+ KERNEL_ARCH := x86_64
+ KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/x86/boot/bzImage
+-ifeq ($(CHOST),$(CBUILD))
++ifeq ($(HOST_ARCH),$(ARCH))
+ QEMU_MACHINE := -cpu host -machine q35,accel=kvm
+ else
+ QEMU_MACHINE := -cpu Skylake-Server -machine q35
+@@ -126,7 +125,7 @@ else ifeq ($(ARCH),i686)
+ QEMU_ARCH := i386
+ KERNEL_ARCH := x86
+ KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/x86/boot/bzImage
+-ifeq ($(subst i686,x86_64,$(CBUILD)),$(CHOST))
++ifeq ($(subst x86_64,i686,$(HOST_ARCH)),$(ARCH))
+ QEMU_MACHINE := -cpu host -machine q35,accel=kvm
+ else
+ QEMU_MACHINE := -cpu coreduo -machine q35
+@@ -136,7 +135,7 @@ else ifeq ($(ARCH),mips64)
+ QEMU_ARCH := mips64
+ KERNEL_ARCH := mips
+ KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux
+-ifeq ($(CHOST),$(CBUILD))
++ifeq ($(HOST_ARCH),$(ARCH))
+ QEMU_MACHINE := -cpu host -machine malta,accel=kvm
+ CFLAGS += -EB
+ else
+@@ -147,7 +146,7 @@ else ifeq ($(ARCH),mips64el)
+ QEMU_ARCH := mips64el
+ KERNEL_ARCH := mips
+ KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux
+-ifeq ($(CHOST),$(CBUILD))
++ifeq ($(HOST_ARCH),$(ARCH))
+ QEMU_MACHINE := -cpu host -machine malta,accel=kvm
+ CFLAGS += -EL
+ else
+@@ -158,7 +157,7 @@ else ifeq ($(ARCH),mips)
+ QEMU_ARCH := mips
+ KERNEL_ARCH := mips
+ KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux
+-ifeq ($(CHOST),$(CBUILD))
++ifeq ($(HOST_ARCH),$(ARCH))
+ QEMU_MACHINE := -cpu host -machine malta,accel=kvm
+ CFLAGS += -EB
+ else
+@@ -169,7 +168,7 @@ else ifeq ($(ARCH),mipsel)
+ QEMU_ARCH := mipsel
+ KERNEL_ARCH := mips
+ KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux
+-ifeq ($(CHOST),$(CBUILD))
++ifeq ($(HOST_ARCH),$(ARCH))
+ QEMU_MACHINE := -cpu host -machine malta,accel=kvm
+ CFLAGS += -EL
+ else
+@@ -180,7 +179,7 @@ else ifeq ($(ARCH),powerpc64le)
+ QEMU_ARCH := ppc64
+ KERNEL_ARCH := powerpc
+ KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux
+-ifeq ($(CHOST),$(CBUILD))
++ifeq ($(HOST_ARCH),$(ARCH))
+ QEMU_MACHINE := -cpu host,accel=kvm -machine pseries
+ else
+ QEMU_MACHINE := -machine pseries
+@@ -190,7 +189,7 @@ else ifeq ($(ARCH),powerpc)
+ QEMU_ARCH := ppc
+ KERNEL_ARCH := powerpc
+ KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/powerpc/boot/uImage
+-ifeq ($(CHOST),$(CBUILD))
++ifeq ($(HOST_ARCH),$(ARCH))
+ QEMU_MACHINE := -cpu host,accel=kvm -machine ppce500
+ else
+ QEMU_MACHINE := -machine ppce500
+@@ -200,10 +199,11 @@ else ifeq ($(ARCH),m68k)
+ QEMU_ARCH := m68k
+ KERNEL_ARCH := m68k
+ KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux
+-ifeq ($(CHOST),$(CBUILD))
+-QEMU_MACHINE := -cpu host,accel=kvm -machine q800
++KERNEL_CMDLINE := $(shell sed -n 's/CONFIG_CMDLINE=\(.*\)/\1/p' arch/m68k.config)
++ifeq ($(HOST_ARCH),$(ARCH))
++QEMU_MACHINE := -cpu host,accel=kvm -machine q800 -smp 1 -append $(KERNEL_CMDLINE)
+ else
+-QEMU_MACHINE := -machine q800
++QEMU_MACHINE := -machine q800 -smp 1 -append $(KERNEL_CMDLINE)
+ endif
+ else
+ $(error I only build: x86_64, i686, arm, armeb, aarch64, aarch64_be, mips, mipsel, mips64, mips64el, powerpc64le, powerpc, m68k)
+@@ -238,14 +238,14 @@ $(BUILD_PATH)/init-cpio-spec.txt:
+ 	echo "nod /dev/console 644 0 0 c 5 1" >> $@
+ 	echo "dir /bin 755 0 0" >> $@
+ 	echo "file /bin/iperf3 $(IPERF_PATH)/src/iperf3 755 0 0" >> $@
+-	echo "file /bin/wg $(WIREGUARD_TOOLS_PATH)/src/tools/wg 755 0 0" >> $@
++	echo "file /bin/wg $(WIREGUARD_TOOLS_PATH)/src/wg 755 0 0" >> $@
+ 	echo "file /bin/bash $(BASH_PATH)/bash 755 0 0" >> $@
+ 	echo "file /bin/ip $(IPROUTE2_PATH)/ip/ip 755 0 0" >> $@
+ 	echo "file /bin/ss $(IPROUTE2_PATH)/misc/ss 755 0 0" >> $@
+ 	echo "file /bin/ping $(IPUTILS_PATH)/ping 755 0 0" >> $@
+ 	echo "file /bin/ncat $(NMAP_PATH)/ncat/ncat 755 0 0" >> $@
+-	echo "file /bin/xtables-multi $(IPTABLES_PATH)/iptables/xtables-multi 755 0 0" >> $@
+-	echo "slink /bin/iptables xtables-multi 777 0 0" >> $@
++	echo "file /bin/xtables-legacy-multi $(IPTABLES_PATH)/iptables/xtables-legacy-multi 755 0 0" >> $@
++	echo "slink /bin/iptables xtables-legacy-multi 777 0 0" >> $@
+ 	echo "slink /bin/ping6 ping 777 0 0" >> $@
+ 	echo "dir /lib 755 0 0" >> $@
+ 	echo "file /lib/libc.so $(MUSL_PATH)/lib/libc.so 755 0 0" >> $@
+@@ -260,8 +260,8 @@ $(KERNEL_BUILD_PATH)/.config: kernel.con
+ 	cd $(KERNEL_BUILD_PATH) && ARCH=$(KERNEL_ARCH) $(KERNEL_PATH)/scripts/kconfig/merge_config.sh -n $(KERNEL_BUILD_PATH)/.config $(KERNEL_BUILD_PATH)/minimal.config
+ 	$(if $(findstring yes,$(DEBUG_KERNEL)),cp debug.config $(KERNEL_BUILD_PATH) && cd $(KERNEL_BUILD_PATH) && ARCH=$(KERNEL_ARCH) $(KERNEL_PATH)/scripts/kconfig/merge_config.sh -n $(KERNEL_BUILD_PATH)/.config debug.config,)
+ 
+-$(KERNEL_BZIMAGE): $(KERNEL_BUILD_PATH)/.config $(BUILD_PATH)/init-cpio-spec.txt $(MUSL_PATH)/lib/libc.so $(IPERF_PATH)/src/iperf3 $(IPUTILS_PATH)/ping $(BASH_PATH)/bash $(IPROUTE2_PATH)/misc/ss $(IPROUTE2_PATH)/ip/ip $(IPTABLES_PATH)/iptables/xtables-multi $(NMAP_PATH)/ncat/ncat $(WIREGUARD_TOOLS_PATH)/src/tools/wg $(BUILD_PATH)/init ../netns.sh $(WIREGUARD_SOURCES)
+-	$(MAKE) -C $(KERNEL_PATH) O=$(KERNEL_BUILD_PATH) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(CROSS_COMPILE) CC="$(NOPIE_GCC)"
++$(KERNEL_BZIMAGE): $(KERNEL_BUILD_PATH)/.config $(BUILD_PATH)/init-cpio-spec.txt $(MUSL_PATH)/lib/libc.so $(IPERF_PATH)/src/iperf3 $(IPUTILS_PATH)/ping $(BASH_PATH)/bash $(IPROUTE2_PATH)/misc/ss $(IPROUTE2_PATH)/ip/ip $(IPTABLES_PATH)/iptables/xtables-legacy-multi $(NMAP_PATH)/ncat/ncat $(WIREGUARD_TOOLS_PATH)/src/wg $(BUILD_PATH)/init ../netns.sh $(WIREGUARD_SOURCES)
++	$(MAKE) -C $(KERNEL_PATH) O=$(KERNEL_BUILD_PATH) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(CROSS_COMPILE)
+ 
+ $(BUILD_PATH)/include/linux/.installed: | $(KERNEL_BUILD_PATH)/.config
+ 	$(MAKE) -C $(KERNEL_PATH) O=$(KERNEL_BUILD_PATH) INSTALL_HDR_PATH=$(BUILD_PATH) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(CROSS_COMPILE) headers_install
+@@ -280,7 +280,7 @@ $(BUILD_PATH)/include/.installed: $(MUSL
+ 
+ $(MUSL_CC): $(MUSL_PATH)/lib/libc.so
+ 	sh $(MUSL_PATH)/tools/musl-gcc.specs.sh $(BUILD_PATH)/include $(MUSL_PATH)/lib /lib/ld-linux.so.1 > $(BUILD_PATH)/musl-gcc.specs
+-	printf '#!/bin/sh\nexec "$(REAL_CC)" --specs="$(BUILD_PATH)/musl-gcc.specs" -fno-stack-protector -no-pie "$$@"\n' > $(BUILD_PATH)/musl-gcc
++	printf '#!/bin/sh\nexec "$(REAL_CC)" --specs="$(BUILD_PATH)/musl-gcc.specs" "$$@"\n' > $(BUILD_PATH)/musl-gcc
+ 	chmod +x $(BUILD_PATH)/musl-gcc
+ 
+ $(IPERF_PATH)/.installed: $(IPERF_TAR)
+@@ -291,7 +291,7 @@ $(IPERF_PATH)/.installed: $(IPERF_TAR)
+ 	touch $@
+ 
+ $(IPERF_PATH)/src/iperf3: | $(IPERF_PATH)/.installed $(USERSPACE_DEPS)
+-	cd $(IPERF_PATH) && CFLAGS="$(CFLAGS) -D_GNU_SOURCE" ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared
++	cd $(IPERF_PATH) && CFLAGS="$(CFLAGS) -D_GNU_SOURCE" ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared --with-openssl=no
+ 	$(MAKE) -C $(IPERF_PATH)
+ 	$(STRIP) -s $@
+ 
+@@ -308,8 +308,8 @@ $(WIREGUARD_TOOLS_PATH)/.installed: $(WI
+ 	flock -s $<.lock tar -C $(BUILD_PATH) -xf $<
+ 	touch $@
+ 
+-$(WIREGUARD_TOOLS_PATH)/src/tools/wg: | $(WIREGUARD_TOOLS_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS)
+-	LDFLAGS="$(LDFLAGS) -L$(LIBMNL_PATH)/src/.libs" $(MAKE) -C $(WIREGUARD_TOOLS_PATH)/src/tools LIBMNL_CFLAGS="-I$(LIBMNL_PATH)/include" LIBMNL_LDLIBS="-lmnl" wg
++$(WIREGUARD_TOOLS_PATH)/src/wg: | $(WIREGUARD_TOOLS_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS)
++	LDFLAGS="$(LDFLAGS) -L$(LIBMNL_PATH)/src/.libs" $(MAKE) -C $(WIREGUARD_TOOLS_PATH)/src LIBMNL_CFLAGS="-I$(LIBMNL_PATH)/include" LIBMNL_LDLIBS="-lmnl" wg
+ 	$(STRIP) -s $@
+ 
+ $(BUILD_PATH)/init: init.c | $(USERSPACE_DEPS)
+@@ -323,7 +323,8 @@ $(IPUTILS_PATH)/.installed: $(IPUTILS_TA
+ 	touch $@
+ 
+ $(IPUTILS_PATH)/ping: | $(IPUTILS_PATH)/.installed $(USERSPACE_DEPS)
+-	$(MAKE) -C $(IPUTILS_PATH) USE_CAP=no USE_IDN=no USE_NETTLE=no USE_CRYPTO=no ping
++	sed -i /atexit/d $(IPUTILS_PATH)/ping.c
++	cd $(IPUTILS_PATH) && $(CC) $(CFLAGS) -std=c99 -o $@ ping.c ping_common.c ping6_common.c iputils_common.c -D_GNU_SOURCE -D'IPUTILS_VERSION(f)=f' -lresolv $(LDFLAGS)
+ 	$(STRIP) -s $@
+ 
+ $(BASH_PATH)/.installed: $(BASH_TAR)
+@@ -357,7 +358,7 @@ $(IPTABLES_PATH)/.installed: $(IPTABLES_
+ 	sed -i -e "/nfnetlink=[01]/s:=[01]:=0:" -e "/nfconntrack=[01]/s:=[01]:=0:" $(IPTABLES_PATH)/configure
+ 	touch $@
+ 
+-$(IPTABLES_PATH)/iptables/xtables-multi: | $(IPTABLES_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS)
++$(IPTABLES_PATH)/iptables/xtables-legacy-multi: | $(IPTABLES_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS)
+ 	cd $(IPTABLES_PATH) && PKG_CONFIG_LIBDIR="$(LIBMNL_PATH)" ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared --disable-nftables --disable-bpf-compiler --disable-nfsynproxy --disable-libipq --with-kernel=$(BUILD_PATH)/include
+ 	$(MAKE) -C $(IPTABLES_PATH)
+ 	$(STRIP) -s $@
+@@ -368,8 +369,9 @@ $(NMAP_PATH)/.installed: $(NMAP_TAR)
+ 	touch $@
+ 
+ $(NMAP_PATH)/ncat/ncat: | $(NMAP_PATH)/.installed $(USERSPACE_DEPS)
+-	cd $(NMAP_PATH) && ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared --without-ndiff --without-zenmap --without-nping --with-libpcap=included --with-libpcre=included --with-libdnet=included --without-liblua --with-liblinear=included --without-nmap-update --without-openssl --with-pcap=linux
+-	$(MAKE) -C $(NMAP_PATH) build-ncat
++	cd $(NMAP_PATH) && ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared --without-ndiff --without-zenmap --without-nping --with-libpcap=included --with-libpcre=included --with-libdnet=included --without-liblua --with-liblinear=included --without-nmap-update --without-openssl --with-pcap=linux --without-libssh
++	$(MAKE) -C $(NMAP_PATH)/libpcap
++	$(MAKE) -C $(NMAP_PATH)/ncat
+ 	$(STRIP) -s $@
+ 
+ clean:
+@@ -379,7 +381,7 @@ distclean: clean
+ 	rm -rf $(DISTFILES_PATH)
+ 
+ menuconfig: $(KERNEL_BUILD_PATH)/.config
+-	$(MAKE) -C $(KERNEL_PATH) O=$(KERNEL_BUILD_PATH) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(CROSS_COMPILE) CC="$(NOPIE_GCC)" menuconfig
++	$(MAKE) -C $(KERNEL_PATH) O=$(KERNEL_BUILD_PATH) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(CROSS_COMPILE) menuconfig
+ 
+ .PHONY: qemu build clean distclean menuconfig
+ .DELETE_ON_ERROR:
+--- a/tools/testing/selftests/wireguard/qemu/arch/m68k.config
++++ b/tools/testing/selftests/wireguard/qemu/arch/m68k.config
+@@ -1,9 +1,9 @@
+ CONFIG_MMU=y
++CONFIG_M68KCLASSIC=y
+ CONFIG_M68040=y
+ CONFIG_MAC=y
+ CONFIG_SERIAL_PMACZILOG=y
+ CONFIG_SERIAL_PMACZILOG_TTYS=y
+ CONFIG_SERIAL_PMACZILOG_CONSOLE=y
+-CONFIG_CMDLINE_BOOL=y
+ CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1"
+ CONFIG_FRAME_WARN=1024
+--- a/tools/testing/selftests/wireguard/qemu/init.c
++++ b/tools/testing/selftests/wireguard/qemu/init.c
+@@ -21,6 +21,7 @@
+ #include <sys/reboot.h>
+ #include <sys/utsname.h>
+ #include <sys/sendfile.h>
++#include <sys/sysmacros.h>
+ #include <linux/random.h>
+ #include <linux/version.h>
+ 
+--- a/tools/testing/selftests/wireguard/qemu/kernel.config
++++ b/tools/testing/selftests/wireguard/qemu/kernel.config
+@@ -39,6 +39,7 @@ CONFIG_PRINTK=y
+ CONFIG_KALLSYMS=y
+ CONFIG_BUG=y
+ CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
++CONFIG_JUMP_LABEL=y
+ CONFIG_EMBEDDED=n
+ CONFIG_BASE_FULL=y
+ CONFIG_FUTEX=y
+@@ -55,6 +56,7 @@ CONFIG_NO_HZ_IDLE=y
+ CONFIG_NO_HZ_FULL=n
+ CONFIG_HZ_PERIODIC=n
+ CONFIG_HIGH_RES_TIMERS=y
++CONFIG_COMPAT_32BIT_TIME=y
+ CONFIG_ARCH_RANDOM=y
+ CONFIG_FILE_LOCKING=y
+ CONFIG_POSIX_TIMERS=y
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0079-wireguard-queueing-do-not-account-for-pfmemalloc-whe.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0079-wireguard-queueing-do-not-account-for-pfmemalloc-whe.patch
new file mode 100644
index 0000000..fb03b1b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0079-wireguard-queueing-do-not-account-for-pfmemalloc-whe.patch
@@ -0,0 +1,39 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Thu, 2 Jan 2020 17:47:50 +0100
+Subject: [PATCH] wireguard: queueing: do not account for pfmemalloc when
+ clearing skb header
+
+commit 04d2ea92a18417619182cbb79063f154892b0150 upstream.
+
+Before 8b7008620b84 ("net: Don't copy pfmemalloc flag in __copy_skb_
+header()"), the pfmemalloc flag used to be between headers_start and
+headers_end, which is a region we clear when preparing the packet for
+encryption/decryption. This is a parameter we certainly want to
+preserve, which is why 8b7008620b84 moved it out of there. The code here
+was written in a world before 8b7008620b84, though, where we had to
+manually account for it. This commit brings things up to speed.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/queueing.h | 3 ---
+ 1 file changed, 3 deletions(-)
+
+--- a/drivers/net/wireguard/queueing.h
++++ b/drivers/net/wireguard/queueing.h
+@@ -83,13 +83,10 @@ static inline __be16 wg_skb_examine_untr
+ 
+ static inline void wg_reset_packet(struct sk_buff *skb)
+ {
+-	const int pfmemalloc = skb->pfmemalloc;
+-
+ 	skb_scrub_packet(skb, true);
+ 	memset(&skb->headers_start, 0,
+ 	       offsetof(struct sk_buff, headers_end) -
+ 		       offsetof(struct sk_buff, headers_start));
+-	skb->pfmemalloc = pfmemalloc;
+ 	skb->queue_mapping = 0;
+ 	skb->nohdr = 0;
+ 	skb->peeked = 0;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0080-wireguard-socket-mark-skbs-as-not-on-list-when-recei.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0080-wireguard-socket-mark-skbs-as-not-on-list-when-recei.patch
new file mode 100644
index 0000000..779491c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0080-wireguard-socket-mark-skbs-as-not-on-list-when-recei.patch
@@ -0,0 +1,34 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Thu, 2 Jan 2020 17:47:51 +0100
+Subject: [PATCH] wireguard: socket: mark skbs as not on list when receiving
+ via gro
+
+commit 736775d06bac60d7a353e405398b48b2bd8b1e54 upstream.
+
+Certain drivers will pass gro skbs to udp, at which point the udp driver
+simply iterates through them and passes them off to encap_rcv, which is
+where we pick up. At the moment, we're not attempting to coalesce these
+into bundles, but we also don't want to wind up having cascaded lists of
+skbs treated separately. The right behavior here, then, is to just mark
+each incoming one as not on a list. This can be seen in practice, for
+example, with Qualcomm's rmnet_perf driver.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Tested-by: Yaroslav Furman <yaro330@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/socket.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/wireguard/socket.c
++++ b/drivers/net/wireguard/socket.c
+@@ -333,6 +333,7 @@ static int wg_receive(struct sock *sk, s
+ 	wg = sk->sk_user_data;
+ 	if (unlikely(!wg))
+ 		goto err;
++	skb_mark_not_on_list(skb);
+ 	wg_packet_receive(wg, skb);
+ 	return 0;
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0081-wireguard-allowedips-fix-use-after-free-in-root_remo.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0081-wireguard-allowedips-fix-use-after-free-in-root_remo.patch
new file mode 100644
index 0000000..e77ab58
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0081-wireguard-allowedips-fix-use-after-free-in-root_remo.patch
@@ -0,0 +1,164 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <edumazet@google.com>
+Date: Tue, 4 Feb 2020 22:17:25 +0100
+Subject: [PATCH] wireguard: allowedips: fix use-after-free in
+ root_remove_peer_lists
+
+commit 9981159fc3b677b357f84e069a11de5a5ec8a2a8 upstream.
+
+In the unlikely case a new node could not be allocated, we need to
+remove @newnode from @peer->allowedips_list before freeing it.
+
+syzbot reported:
+
+BUG: KASAN: use-after-free in __list_del_entry_valid+0xdc/0xf5 lib/list_debug.c:54
+Read of size 8 at addr ffff88809881a538 by task syz-executor.4/30133
+
+CPU: 0 PID: 30133 Comm: syz-executor.4 Not tainted 5.5.0-syzkaller #0
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
+Call Trace:
+ __dump_stack lib/dump_stack.c:77 [inline]
+ dump_stack+0x197/0x210 lib/dump_stack.c:118
+ print_address_description.constprop.0.cold+0xd4/0x30b mm/kasan/report.c:374
+ __kasan_report.cold+0x1b/0x32 mm/kasan/report.c:506
+ kasan_report+0x12/0x20 mm/kasan/common.c:639
+ __asan_report_load8_noabort+0x14/0x20 mm/kasan/generic_report.c:135
+ __list_del_entry_valid+0xdc/0xf5 lib/list_debug.c:54
+ __list_del_entry include/linux/list.h:132 [inline]
+ list_del include/linux/list.h:146 [inline]
+ root_remove_peer_lists+0x24f/0x4b0 drivers/net/wireguard/allowedips.c:65
+ wg_allowedips_free+0x232/0x390 drivers/net/wireguard/allowedips.c:300
+ wg_peer_remove_all+0xd5/0x620 drivers/net/wireguard/peer.c:187
+ wg_set_device+0xd01/0x1350 drivers/net/wireguard/netlink.c:542
+ genl_family_rcv_msg_doit net/netlink/genetlink.c:672 [inline]
+ genl_family_rcv_msg net/netlink/genetlink.c:717 [inline]
+ genl_rcv_msg+0x67d/0xea0 net/netlink/genetlink.c:734
+ netlink_rcv_skb+0x177/0x450 net/netlink/af_netlink.c:2477
+ genl_rcv+0x29/0x40 net/netlink/genetlink.c:745
+ netlink_unicast_kernel net/netlink/af_netlink.c:1302 [inline]
+ netlink_unicast+0x59e/0x7e0 net/netlink/af_netlink.c:1328
+ netlink_sendmsg+0x91c/0xea0 net/netlink/af_netlink.c:1917
+ sock_sendmsg_nosec net/socket.c:652 [inline]
+ sock_sendmsg+0xd7/0x130 net/socket.c:672
+ ____sys_sendmsg+0x753/0x880 net/socket.c:2343
+ ___sys_sendmsg+0x100/0x170 net/socket.c:2397
+ __sys_sendmsg+0x105/0x1d0 net/socket.c:2430
+ __do_sys_sendmsg net/socket.c:2439 [inline]
+ __se_sys_sendmsg net/socket.c:2437 [inline]
+ __x64_sys_sendmsg+0x78/0xb0 net/socket.c:2437
+ do_syscall_64+0xfa/0x790 arch/x86/entry/common.c:294
+ entry_SYSCALL_64_after_hwframe+0x49/0xbe
+RIP: 0033:0x45b399
+Code: ad b6 fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 7b b6 fb ff c3 66 2e 0f 1f 84 00 00 00 00
+RSP: 002b:00007f99a9bcdc78 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
+RAX: ffffffffffffffda RBX: 00007f99a9bce6d4 RCX: 000000000045b399
+RDX: 0000000000000000 RSI: 0000000020001340 RDI: 0000000000000003
+RBP: 000000000075bf20 R08: 0000000000000000 R09: 0000000000000000
+R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000004
+R13: 00000000000009ba R14: 00000000004cb2b8 R15: 0000000000000009
+
+Allocated by task 30103:
+ save_stack+0x23/0x90 mm/kasan/common.c:72
+ set_track mm/kasan/common.c:80 [inline]
+ __kasan_kmalloc mm/kasan/common.c:513 [inline]
+ __kasan_kmalloc.constprop.0+0xcf/0xe0 mm/kasan/common.c:486
+ kasan_kmalloc+0x9/0x10 mm/kasan/common.c:527
+ kmem_cache_alloc_trace+0x158/0x790 mm/slab.c:3551
+ kmalloc include/linux/slab.h:556 [inline]
+ kzalloc include/linux/slab.h:670 [inline]
+ add+0x70a/0x1970 drivers/net/wireguard/allowedips.c:236
+ wg_allowedips_insert_v4+0xf6/0x160 drivers/net/wireguard/allowedips.c:320
+ set_allowedip drivers/net/wireguard/netlink.c:343 [inline]
+ set_peer+0xfb9/0x1150 drivers/net/wireguard/netlink.c:468
+ wg_set_device+0xbd4/0x1350 drivers/net/wireguard/netlink.c:591
+ genl_family_rcv_msg_doit net/netlink/genetlink.c:672 [inline]
+ genl_family_rcv_msg net/netlink/genetlink.c:717 [inline]
+ genl_rcv_msg+0x67d/0xea0 net/netlink/genetlink.c:734
+ netlink_rcv_skb+0x177/0x450 net/netlink/af_netlink.c:2477
+ genl_rcv+0x29/0x40 net/netlink/genetlink.c:745
+ netlink_unicast_kernel net/netlink/af_netlink.c:1302 [inline]
+ netlink_unicast+0x59e/0x7e0 net/netlink/af_netlink.c:1328
+ netlink_sendmsg+0x91c/0xea0 net/netlink/af_netlink.c:1917
+ sock_sendmsg_nosec net/socket.c:652 [inline]
+ sock_sendmsg+0xd7/0x130 net/socket.c:672
+ ____sys_sendmsg+0x753/0x880 net/socket.c:2343
+ ___sys_sendmsg+0x100/0x170 net/socket.c:2397
+ __sys_sendmsg+0x105/0x1d0 net/socket.c:2430
+ __do_sys_sendmsg net/socket.c:2439 [inline]
+ __se_sys_sendmsg net/socket.c:2437 [inline]
+ __x64_sys_sendmsg+0x78/0xb0 net/socket.c:2437
+ do_syscall_64+0xfa/0x790 arch/x86/entry/common.c:294
+ entry_SYSCALL_64_after_hwframe+0x49/0xbe
+
+Freed by task 30103:
+ save_stack+0x23/0x90 mm/kasan/common.c:72
+ set_track mm/kasan/common.c:80 [inline]
+ kasan_set_free_info mm/kasan/common.c:335 [inline]
+ __kasan_slab_free+0x102/0x150 mm/kasan/common.c:474
+ kasan_slab_free+0xe/0x10 mm/kasan/common.c:483
+ __cache_free mm/slab.c:3426 [inline]
+ kfree+0x10a/0x2c0 mm/slab.c:3757
+ add+0x12d2/0x1970 drivers/net/wireguard/allowedips.c:266
+ wg_allowedips_insert_v4+0xf6/0x160 drivers/net/wireguard/allowedips.c:320
+ set_allowedip drivers/net/wireguard/netlink.c:343 [inline]
+ set_peer+0xfb9/0x1150 drivers/net/wireguard/netlink.c:468
+ wg_set_device+0xbd4/0x1350 drivers/net/wireguard/netlink.c:591
+ genl_family_rcv_msg_doit net/netlink/genetlink.c:672 [inline]
+ genl_family_rcv_msg net/netlink/genetlink.c:717 [inline]
+ genl_rcv_msg+0x67d/0xea0 net/netlink/genetlink.c:734
+ netlink_rcv_skb+0x177/0x450 net/netlink/af_netlink.c:2477
+ genl_rcv+0x29/0x40 net/netlink/genetlink.c:745
+ netlink_unicast_kernel net/netlink/af_netlink.c:1302 [inline]
+ netlink_unicast+0x59e/0x7e0 net/netlink/af_netlink.c:1328
+ netlink_sendmsg+0x91c/0xea0 net/netlink/af_netlink.c:1917
+ sock_sendmsg_nosec net/socket.c:652 [inline]
+ sock_sendmsg+0xd7/0x130 net/socket.c:672
+ ____sys_sendmsg+0x753/0x880 net/socket.c:2343
+ ___sys_sendmsg+0x100/0x170 net/socket.c:2397
+ __sys_sendmsg+0x105/0x1d0 net/socket.c:2430
+ __do_sys_sendmsg net/socket.c:2439 [inline]
+ __se_sys_sendmsg net/socket.c:2437 [inline]
+ __x64_sys_sendmsg+0x78/0xb0 net/socket.c:2437
+ do_syscall_64+0xfa/0x790 arch/x86/entry/common.c:294
+ entry_SYSCALL_64_after_hwframe+0x49/0xbe
+
+The buggy address belongs to the object at ffff88809881a500
+ which belongs to the cache kmalloc-64 of size 64
+The buggy address is located 56 bytes inside of
+ 64-byte region [ffff88809881a500, ffff88809881a540)
+The buggy address belongs to the page:
+page:ffffea0002620680 refcount:1 mapcount:0 mapping:ffff8880aa400380 index:0x0
+raw: 00fffe0000000200 ffffea000250b748 ffffea000254bac8 ffff8880aa400380
+raw: 0000000000000000 ffff88809881a000 0000000100000020 0000000000000000
+page dumped because: kasan: bad access detected
+
+Memory state around the buggy address:
+ ffff88809881a400: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
+ ffff88809881a480: 00 00 00 00 00 fc fc fc fc fc fc fc fc fc fc fc
+>ffff88809881a500: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
+                                        ^
+ ffff88809881a580: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
+ ffff88809881a600: 00 00 00 00 00 00 fc fc fc fc fc fc fc fc fc fc
+
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reported-by: syzbot <syzkaller@googlegroups.com>
+Cc: Jason A. Donenfeld <Jason@zx2c4.com>
+Cc: wireguard@lists.zx2c4.com
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/allowedips.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/wireguard/allowedips.c
++++ b/drivers/net/wireguard/allowedips.c
+@@ -263,6 +263,7 @@ static int add(struct allowedips_node __
+ 	} else {
+ 		node = kzalloc(sizeof(*node), GFP_KERNEL);
+ 		if (unlikely(!node)) {
++			list_del(&newnode->peer_list);
+ 			kfree(newnode);
+ 			return -ENOMEM;
+ 		}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0082-wireguard-noise-reject-peers-with-low-order-public-k.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0082-wireguard-noise-reject-peers-with-low-order-public-k.patch
new file mode 100644
index 0000000..55bb276
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0082-wireguard-noise-reject-peers-with-low-order-public-k.patch
@@ -0,0 +1,233 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Tue, 4 Feb 2020 22:17:26 +0100
+Subject: [PATCH] wireguard: noise: reject peers with low order public keys
+
+commit ec31c2676a10e064878927b243fada8c2fb0c03c upstream.
+
+Our static-static calculation returns a failure if the public key is of
+low order. We check for this when peers are added, and don't allow them
+to be added if they're low order, except in the case where we haven't
+yet been given a private key. In that case, we would defer the removal
+of the peer until we're given a private key, since at that point we're
+doing new static-static calculations which incur failures we can act on.
+This meant, however, that we wound up removing peers rather late in the
+configuration flow.
+
+Syzkaller points out that peer_remove calls flush_workqueue, which in
+turn might then wait for sending a handshake initiation to complete.
+Since handshake initiation needs the static identity lock, holding the
+static identity lock while calling peer_remove can result in a rare
+deadlock. We have precisely this case in this situation of late-stage
+peer removal based on an invalid public key. We can't drop the lock when
+removing, because then incoming handshakes might interact with a bogus
+static-static calculation.
+
+While the band-aid patch for this would involve breaking up the peer
+removal into two steps like wg_peer_remove_all does, in order to solve
+the locking issue, there's actually a much more elegant way of fixing
+this:
+
+If the static-static calculation succeeds with one private key, it
+*must* succeed with all others, because all 32-byte strings map to valid
+private keys, thanks to clamping. That means we can get rid of this
+silly dance and locking headaches of removing peers late in the
+configuration flow, and instead just reject them early on, regardless of
+whether the device has yet been assigned a private key. For the case
+where the device doesn't yet have a private key, we safely use zeros
+just for the purposes of checking for low order points by way of
+checking the output of the calculation.
+
+The following PoC will trigger the deadlock:
+
+ip link add wg0 type wireguard
+ip addr add 10.0.0.1/24 dev wg0
+ip link set wg0 up
+ping -f 10.0.0.2 &
+while true; do
+        wg set wg0 private-key /dev/null peer AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= allowed-ips 10.0.0.0/24 endpoint 10.0.0.3:1234
+        wg set wg0 private-key <(echo AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=)
+done
+
+[    0.949105] ======================================================
+[    0.949550] WARNING: possible circular locking dependency detected
+[    0.950143] 5.5.0-debug+ #18 Not tainted
+[    0.950431] ------------------------------------------------------
+[    0.950959] wg/89 is trying to acquire lock:
+[    0.951252] ffff8880333e2128 ((wq_completion)wg-kex-wg0){+.+.}, at: flush_workqueue+0xe3/0x12f0
+[    0.951865]
+[    0.951865] but task is already holding lock:
+[    0.952280] ffff888032819bc0 (&wg->static_identity.lock){++++}, at: wg_set_device+0x95d/0xcc0
+[    0.953011]
+[    0.953011] which lock already depends on the new lock.
+[    0.953011]
+[    0.953651]
+[    0.953651] the existing dependency chain (in reverse order) is:
+[    0.954292]
+[    0.954292] -> #2 (&wg->static_identity.lock){++++}:
+[    0.954804]        lock_acquire+0x127/0x350
+[    0.955133]        down_read+0x83/0x410
+[    0.955428]        wg_noise_handshake_create_initiation+0x97/0x700
+[    0.955885]        wg_packet_send_handshake_initiation+0x13a/0x280
+[    0.956401]        wg_packet_handshake_send_worker+0x10/0x20
+[    0.956841]        process_one_work+0x806/0x1500
+[    0.957167]        worker_thread+0x8c/0xcb0
+[    0.957549]        kthread+0x2ee/0x3b0
+[    0.957792]        ret_from_fork+0x24/0x30
+[    0.958234]
+[    0.958234] -> #1 ((work_completion)(&peer->transmit_handshake_work)){+.+.}:
+[    0.958808]        lock_acquire+0x127/0x350
+[    0.959075]        process_one_work+0x7ab/0x1500
+[    0.959369]        worker_thread+0x8c/0xcb0
+[    0.959639]        kthread+0x2ee/0x3b0
+[    0.959896]        ret_from_fork+0x24/0x30
+[    0.960346]
+[    0.960346] -> #0 ((wq_completion)wg-kex-wg0){+.+.}:
+[    0.960945]        check_prev_add+0x167/0x1e20
+[    0.961351]        __lock_acquire+0x2012/0x3170
+[    0.961725]        lock_acquire+0x127/0x350
+[    0.961990]        flush_workqueue+0x106/0x12f0
+[    0.962280]        peer_remove_after_dead+0x160/0x220
+[    0.962600]        wg_set_device+0xa24/0xcc0
+[    0.962994]        genl_rcv_msg+0x52f/0xe90
+[    0.963298]        netlink_rcv_skb+0x111/0x320
+[    0.963618]        genl_rcv+0x1f/0x30
+[    0.963853]        netlink_unicast+0x3f6/0x610
+[    0.964245]        netlink_sendmsg+0x700/0xb80
+[    0.964586]        __sys_sendto+0x1dd/0x2c0
+[    0.964854]        __x64_sys_sendto+0xd8/0x1b0
+[    0.965141]        do_syscall_64+0x90/0xd9a
+[    0.965408]        entry_SYSCALL_64_after_hwframe+0x49/0xbe
+[    0.965769]
+[    0.965769] other info that might help us debug this:
+[    0.965769]
+[    0.966337] Chain exists of:
+[    0.966337]   (wq_completion)wg-kex-wg0 --> (work_completion)(&peer->transmit_handshake_work) --> &wg->static_identity.lock
+[    0.966337]
+[    0.967417]  Possible unsafe locking scenario:
+[    0.967417]
+[    0.967836]        CPU0                    CPU1
+[    0.968155]        ----                    ----
+[    0.968497]   lock(&wg->static_identity.lock);
+[    0.968779]                                lock((work_completion)(&peer->transmit_handshake_work));
+[    0.969345]                                lock(&wg->static_identity.lock);
+[    0.969809]   lock((wq_completion)wg-kex-wg0);
+[    0.970146]
+[    0.970146]  *** DEADLOCK ***
+[    0.970146]
+[    0.970531] 5 locks held by wg/89:
+[    0.970908]  #0: ffffffff827433c8 (cb_lock){++++}, at: genl_rcv+0x10/0x30
+[    0.971400]  #1: ffffffff82743480 (genl_mutex){+.+.}, at: genl_rcv_msg+0x642/0xe90
+[    0.971924]  #2: ffffffff827160c0 (rtnl_mutex){+.+.}, at: wg_set_device+0x9f/0xcc0
+[    0.972488]  #3: ffff888032819de0 (&wg->device_update_lock){+.+.}, at: wg_set_device+0xb0/0xcc0
+[    0.973095]  #4: ffff888032819bc0 (&wg->static_identity.lock){++++}, at: wg_set_device+0x95d/0xcc0
+[    0.973653]
+[    0.973653] stack backtrace:
+[    0.973932] CPU: 1 PID: 89 Comm: wg Not tainted 5.5.0-debug+ #18
+[    0.974476] Call Trace:
+[    0.974638]  dump_stack+0x97/0xe0
+[    0.974869]  check_noncircular+0x312/0x3e0
+[    0.975132]  ? print_circular_bug+0x1f0/0x1f0
+[    0.975410]  ? __kernel_text_address+0x9/0x30
+[    0.975727]  ? unwind_get_return_address+0x51/0x90
+[    0.976024]  check_prev_add+0x167/0x1e20
+[    0.976367]  ? graph_lock+0x70/0x160
+[    0.976682]  __lock_acquire+0x2012/0x3170
+[    0.976998]  ? register_lock_class+0x1140/0x1140
+[    0.977323]  lock_acquire+0x127/0x350
+[    0.977627]  ? flush_workqueue+0xe3/0x12f0
+[    0.977890]  flush_workqueue+0x106/0x12f0
+[    0.978147]  ? flush_workqueue+0xe3/0x12f0
+[    0.978410]  ? find_held_lock+0x2c/0x110
+[    0.978662]  ? lock_downgrade+0x6e0/0x6e0
+[    0.978919]  ? queue_rcu_work+0x60/0x60
+[    0.979166]  ? netif_napi_del+0x151/0x3b0
+[    0.979501]  ? peer_remove_after_dead+0x160/0x220
+[    0.979871]  peer_remove_after_dead+0x160/0x220
+[    0.980232]  wg_set_device+0xa24/0xcc0
+[    0.980516]  ? deref_stack_reg+0x8e/0xc0
+[    0.980801]  ? set_peer+0xe10/0xe10
+[    0.981040]  ? __ww_mutex_check_waiters+0x150/0x150
+[    0.981430]  ? __nla_validate_parse+0x163/0x270
+[    0.981719]  ? genl_family_rcv_msg_attrs_parse+0x13f/0x310
+[    0.982078]  genl_rcv_msg+0x52f/0xe90
+[    0.982348]  ? genl_family_rcv_msg_attrs_parse+0x310/0x310
+[    0.982690]  ? register_lock_class+0x1140/0x1140
+[    0.983049]  netlink_rcv_skb+0x111/0x320
+[    0.983298]  ? genl_family_rcv_msg_attrs_parse+0x310/0x310
+[    0.983645]  ? netlink_ack+0x880/0x880
+[    0.983888]  genl_rcv+0x1f/0x30
+[    0.984168]  netlink_unicast+0x3f6/0x610
+[    0.984443]  ? netlink_detachskb+0x60/0x60
+[    0.984729]  ? find_held_lock+0x2c/0x110
+[    0.984976]  netlink_sendmsg+0x700/0xb80
+[    0.985220]  ? netlink_broadcast_filtered+0xa60/0xa60
+[    0.985533]  __sys_sendto+0x1dd/0x2c0
+[    0.985763]  ? __x64_sys_getpeername+0xb0/0xb0
+[    0.986039]  ? sockfd_lookup_light+0x17/0x160
+[    0.986397]  ? __sys_recvmsg+0x8c/0xf0
+[    0.986711]  ? __sys_recvmsg_sock+0xd0/0xd0
+[    0.987018]  __x64_sys_sendto+0xd8/0x1b0
+[    0.987283]  ? lockdep_hardirqs_on+0x39b/0x5a0
+[    0.987666]  do_syscall_64+0x90/0xd9a
+[    0.987903]  entry_SYSCALL_64_after_hwframe+0x49/0xbe
+[    0.988223] RIP: 0033:0x7fe77c12003e
+[    0.988508] Code: c3 8b 07 85 c0 75 24 49 89 fb 48 89 f0 48 89 d7 48 89 ce 4c 89 c2 4d 89 ca 4c 8b 44 24 08 4c 8b 4c 24 10 4c 4
+[    0.989666] RSP: 002b:00007fffada2ed58 EFLAGS: 00000246 ORIG_RAX: 000000000000002c
+[    0.990137] RAX: ffffffffffffffda RBX: 00007fe77c159d48 RCX: 00007fe77c12003e
+[    0.990583] RDX: 0000000000000040 RSI: 000055fd1d38e020 RDI: 0000000000000004
+[    0.991091] RBP: 000055fd1d38e020 R08: 000055fd1cb63358 R09: 000000000000000c
+[    0.991568] R10: 0000000000000000 R11: 0000000000000246 R12: 000000000000002c
+[    0.992014] R13: 0000000000000004 R14: 000055fd1d38e020 R15: 0000000000000001
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Reported-by: syzbot <syzkaller@googlegroups.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/netlink.c |  6 ++----
+ drivers/net/wireguard/noise.c   | 10 +++++++---
+ 2 files changed, 9 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/wireguard/netlink.c
++++ b/drivers/net/wireguard/netlink.c
+@@ -575,10 +575,8 @@ static int wg_set_device(struct sk_buff
+ 							 private_key);
+ 		list_for_each_entry_safe(peer, temp, &wg->peer_list,
+ 					 peer_list) {
+-			if (wg_noise_precompute_static_static(peer))
+-				wg_noise_expire_current_peer_keypairs(peer);
+-			else
+-				wg_peer_remove(peer);
++			BUG_ON(!wg_noise_precompute_static_static(peer));
++			wg_noise_expire_current_peer_keypairs(peer);
+ 		}
+ 		wg_cookie_checker_precompute_device_keys(&wg->cookie_checker);
+ 		up_write(&wg->static_identity.lock);
+--- a/drivers/net/wireguard/noise.c
++++ b/drivers/net/wireguard/noise.c
+@@ -46,17 +46,21 @@ void __init wg_noise_init(void)
+ /* Must hold peer->handshake.static_identity->lock */
+ bool wg_noise_precompute_static_static(struct wg_peer *peer)
+ {
+-	bool ret = true;
++	bool ret;
+ 
+ 	down_write(&peer->handshake.lock);
+-	if (peer->handshake.static_identity->has_identity)
++	if (peer->handshake.static_identity->has_identity) {
+ 		ret = curve25519(
+ 			peer->handshake.precomputed_static_static,
+ 			peer->handshake.static_identity->static_private,
+ 			peer->handshake.remote_static);
+-	else
++	} else {
++		u8 empty[NOISE_PUBLIC_KEY_LEN] = { 0 };
++
++		ret = curve25519(empty, empty, peer->handshake.remote_static);
+ 		memset(peer->handshake.precomputed_static_static, 0,
+ 		       NOISE_PUBLIC_KEY_LEN);
++	}
+ 	up_write(&peer->handshake.lock);
+ 	return ret;
+ }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0083-wireguard-selftests-ensure-non-addition-of-peers-wit.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0083-wireguard-selftests-ensure-non-addition-of-peers-wit.patch
new file mode 100644
index 0000000..86877a6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0083-wireguard-selftests-ensure-non-addition-of-peers-wit.patch
@@ -0,0 +1,34 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Tue, 4 Feb 2020 22:17:27 +0100
+Subject: [PATCH] wireguard: selftests: ensure non-addition of peers with
+ failed precomputation
+
+commit f9398acba6a4ae9cb98bfe4d56414d376eff8d57 upstream.
+
+Ensure that peers with low order points are ignored, both in the case
+where we already have a device private key and in the case where we do
+not. This adds points that naturally give a zero output.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ tools/testing/selftests/wireguard/netns.sh | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/tools/testing/selftests/wireguard/netns.sh
++++ b/tools/testing/selftests/wireguard/netns.sh
+@@ -516,6 +516,12 @@ n0 wg set wg0 peer "$pub2" allowed-ips 0
+ n0 wg set wg0 peer "$pub2" allowed-ips 0.0.0.0/0
+ n0 wg set wg0 peer "$pub2" allowed-ips ::/0,1700::/111,5000::/4,e000::/37,9000::/75
+ n0 wg set wg0 peer "$pub2" allowed-ips ::/0
++n0 wg set wg0 peer "$pub2" remove
++low_order_points=( AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 4Ot6fDtBuK4WVuP68Z/EatoJjeucMrH9hmIFFl9JuAA= X5yVvKNQjCSx0LFVnIPvWwREXMRYHI6G2CJO3dCfEVc= 7P///////////////////////////////////////38= 7f///////////////////////////////////////38= 7v///////////////////////////////////////38= )
++n0 wg set wg0 private-key /dev/null ${low_order_points[@]/#/peer }
++[[ -z $(n0 wg show wg0 peers) ]]
++n0 wg set wg0 private-key <(echo "$key1") ${low_order_points[@]/#/peer }
++[[ -z $(n0 wg show wg0 peers) ]]
+ ip0 link del wg0
+ 
+ declare -A objects
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0084-wireguard-selftests-tie-socket-waiting-to-target-pid.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0084-wireguard-selftests-tie-socket-waiting-to-target-pid.patch
new file mode 100644
index 0000000..4530f0f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0084-wireguard-selftests-tie-socket-waiting-to-target-pid.patch
@@ -0,0 +1,77 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Tue, 4 Feb 2020 22:17:29 +0100
+Subject: [PATCH] wireguard: selftests: tie socket waiting to target pid
+
+commit 88f404a9b1d75388225b1c67b6dd327cb2182777 upstream.
+
+Without this, we wind up proceeding too early sometimes when the
+previous process has just used the same listening port. So, we tie the
+listening socket query to the specific pid we're interested in.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ tools/testing/selftests/wireguard/netns.sh | 17 ++++++++---------
+ 1 file changed, 8 insertions(+), 9 deletions(-)
+
+--- a/tools/testing/selftests/wireguard/netns.sh
++++ b/tools/testing/selftests/wireguard/netns.sh
+@@ -38,9 +38,8 @@ ip0() { pretty 0 "ip $*"; ip -n $netns0
+ ip1() { pretty 1 "ip $*"; ip -n $netns1 "$@"; }
+ ip2() { pretty 2 "ip $*"; ip -n $netns2 "$@"; }
+ sleep() { read -t "$1" -N 1 || true; }
+-waitiperf() { pretty "${1//*-}" "wait for iperf:5201"; while [[ $(ss -N "$1" -tlp 'sport = 5201') != *iperf3* ]]; do sleep 0.1; done; }
+-waitncatudp() { pretty "${1//*-}" "wait for udp:1111"; while [[ $(ss -N "$1" -ulp 'sport = 1111') != *ncat* ]]; do sleep 0.1; done; }
+-waitncattcp() { pretty "${1//*-}" "wait for tcp:1111"; while [[ $(ss -N "$1" -tlp 'sport = 1111') != *ncat* ]]; do sleep 0.1; done; }
++waitiperf() { pretty "${1//*-}" "wait for iperf:5201 pid $2"; while [[ $(ss -N "$1" -tlpH 'sport = 5201') != *\"iperf3\",pid=$2,fd=* ]]; do sleep 0.1; done; }
++waitncatudp() { pretty "${1//*-}" "wait for udp:1111 pid $2"; while [[ $(ss -N "$1" -ulpH 'sport = 1111') != *\"ncat\",pid=$2,fd=* ]]; do sleep 0.1; done; }
+ waitiface() { pretty "${1//*-}" "wait for $2 to come up"; ip netns exec "$1" bash -c "while [[ \$(< \"/sys/class/net/$2/operstate\") != up ]]; do read -t .1 -N 0 || true; done;"; }
+ 
+ cleanup() {
+@@ -119,22 +118,22 @@ tests() {
+ 
+ 	# TCP over IPv4
+ 	n2 iperf3 -s -1 -B 192.168.241.2 &
+-	waitiperf $netns2
++	waitiperf $netns2 $!
+ 	n1 iperf3 -Z -t 3 -c 192.168.241.2
+ 
+ 	# TCP over IPv6
+ 	n1 iperf3 -s -1 -B fd00::1 &
+-	waitiperf $netns1
++	waitiperf $netns1 $!
+ 	n2 iperf3 -Z -t 3 -c fd00::1
+ 
+ 	# UDP over IPv4
+ 	n1 iperf3 -s -1 -B 192.168.241.1 &
+-	waitiperf $netns1
++	waitiperf $netns1 $!
+ 	n2 iperf3 -Z -t 3 -b 0 -u -c 192.168.241.1
+ 
+ 	# UDP over IPv6
+ 	n2 iperf3 -s -1 -B fd00::2 &
+-	waitiperf $netns2
++	waitiperf $netns2 $!
+ 	n1 iperf3 -Z -t 3 -b 0 -u -c fd00::2
+ }
+ 
+@@ -207,7 +206,7 @@ n1 ping -W 1 -c 1 192.168.241.2
+ n1 wg set wg0 peer "$pub2" allowed-ips 192.168.241.0/24
+ exec 4< <(n1 ncat -l -u -p 1111)
+ ncat_pid=$!
+-waitncatudp $netns1
++waitncatudp $netns1 $ncat_pid
+ n2 ncat -u 192.168.241.1 1111 <<<"X"
+ read -r -N 1 -t 1 out <&4 && [[ $out == "X" ]]
+ kill $ncat_pid
+@@ -216,7 +215,7 @@ n1 wg set wg0 peer "$more_specific_key"
+ n2 wg set wg0 listen-port 9997
+ exec 4< <(n1 ncat -l -u -p 1111)
+ ncat_pid=$!
+-waitncatudp $netns1
++waitncatudp $netns1 $ncat_pid
+ n2 ncat -u 192.168.241.1 1111 <<<"X"
+ ! read -r -N 1 -t 1 out <&4 || false
+ kill $ncat_pid
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0085-wireguard-device-use-icmp_ndo_send-helper.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0085-wireguard-device-use-icmp_ndo_send-helper.patch
new file mode 100644
index 0000000..321db18
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0085-wireguard-device-use-icmp_ndo_send-helper.patch
@@ -0,0 +1,64 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Tue, 11 Feb 2020 20:47:08 +0100
+Subject: [PATCH] wireguard: device: use icmp_ndo_send helper
+
+commit a12d7f3cbdc72c7625881c8dc2660fc2c979fdf2 upstream.
+
+Because wireguard is calling icmp from network device context, it should
+use the ndo helper so that the rate limiting applies correctly.  This
+commit adds a small test to the wireguard test suite to ensure that the
+new functions continue doing the right thing in the context of
+wireguard. It does this by setting up a condition that will definately
+evoke an icmp error message from the driver, but along a nat'd path.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/device.c             |  4 ++--
+ tools/testing/selftests/wireguard/netns.sh | 11 +++++++++++
+ 2 files changed, 13 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/wireguard/device.c
++++ b/drivers/net/wireguard/device.c
+@@ -203,9 +203,9 @@ err_peer:
+ err:
+ 	++dev->stats.tx_errors;
+ 	if (skb->protocol == htons(ETH_P_IP))
+-		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
++		icmp_ndo_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
+ 	else if (skb->protocol == htons(ETH_P_IPV6))
+-		icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
++		icmpv6_ndo_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
+ 	kfree_skb(skb);
+ 	return ret;
+ }
+--- a/tools/testing/selftests/wireguard/netns.sh
++++ b/tools/testing/selftests/wireguard/netns.sh
+@@ -24,6 +24,7 @@
+ set -e
+ 
+ exec 3>&1
++export LANG=C
+ export WG_HIDE_KEYS=never
+ netns0="wg-test-$$-0"
+ netns1="wg-test-$$-1"
+@@ -297,7 +298,17 @@ ip1 -4 rule add table main suppress_pref
+ n1 ping -W 1 -c 100 -f 192.168.99.7
+ n1 ping -W 1 -c 100 -f abab::1111
+ 
++# Have ns2 NAT into wg0 packets from ns0, but return an icmp error along the right route.
++n2 iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -d 192.168.241.0/24 -j SNAT --to 192.168.241.2
++n0 iptables -t filter -A INPUT \! -s 10.0.0.0/24 -i vethrs -j DROP # Manual rpfilter just to be explicit.
++n2 bash -c 'printf 1 > /proc/sys/net/ipv4/ip_forward'
++ip0 -4 route add 192.168.241.1 via 10.0.0.100
++n2 wg set wg0 peer "$pub1" remove
++[[ $(! n0 ping -W 1 -c 1 192.168.241.1 || false) == *"From 10.0.0.100 icmp_seq=1 Destination Host Unreachable"* ]]
++
+ n0 iptables -t nat -F
++n0 iptables -t filter -F
++n2 iptables -t nat -F
+ ip0 link del vethrc
+ ip0 link del vethrs
+ ip1 link del wg0
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0086-wireguard-selftests-reduce-complexity-and-fix-make-r.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0086-wireguard-selftests-reduce-complexity-and-fix-make-r.patch
new file mode 100644
index 0000000..ac292a8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0086-wireguard-selftests-reduce-complexity-and-fix-make-r.patch
@@ -0,0 +1,104 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 14 Feb 2020 23:57:20 +0100
+Subject: [PATCH] wireguard: selftests: reduce complexity and fix make races
+
+commit 04ddf1208f03e1dbc39a4619c40eba640051b950 upstream.
+
+This gives us fewer dependencies and shortens build time, fixes up some
+hash checking race conditions, and also fixes missing directory creation
+that caused issues on massively parallel builds.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ .../testing/selftests/wireguard/qemu/Makefile | 38 +++++++------------
+ 1 file changed, 14 insertions(+), 24 deletions(-)
+
+--- a/tools/testing/selftests/wireguard/qemu/Makefile
++++ b/tools/testing/selftests/wireguard/qemu/Makefile
+@@ -38,19 +38,17 @@ endef
+ define file_download =
+ $(DISTFILES_PATH)/$(1):
+ 	mkdir -p $(DISTFILES_PATH)
+-	flock -x $$@.lock -c '[ -f $$@ ] && exit 0; wget -O $$@.tmp $(MIRROR)$(1) || wget -O $$@.tmp $(2)$(1) || rm -f $$@.tmp'
+-	if echo "$(3)  $$@.tmp" | sha256sum -c -; then mv $$@.tmp $$@; else rm -f $$@.tmp; exit 71; fi
++	flock -x $$@.lock -c '[ -f $$@ ] && exit 0; wget -O $$@.tmp $(MIRROR)$(1) || wget -O $$@.tmp $(2)$(1) || rm -f $$@.tmp; [ -f $$@.tmp ] || exit 1; if echo "$(3)  $$@.tmp" | sha256sum -c -; then mv $$@.tmp $$@; else rm -f $$@.tmp; exit 71; fi'
+ endef
+ 
+ $(eval $(call tar_download,MUSL,musl,1.1.24,.tar.gz,https://www.musl-libc.org/releases/,1370c9a812b2cf2a7d92802510cca0058cc37e66a7bedd70051f0a34015022a3))
+-$(eval $(call tar_download,LIBMNL,libmnl,1.0.4,.tar.bz2,https://www.netfilter.org/projects/libmnl/files/,171f89699f286a5854b72b91d06e8f8e3683064c5901fb09d954a9ab6f551f81))
+ $(eval $(call tar_download,IPERF,iperf,3.7,.tar.gz,https://downloads.es.net/pub/iperf/,d846040224317caf2f75c843d309a950a7db23f9b44b94688ccbe557d6d1710c))
+ $(eval $(call tar_download,BASH,bash,5.0,.tar.gz,https://ftp.gnu.org/gnu/bash/,b4a80f2ac66170b2913efbfb9f2594f1f76c7b1afd11f799e22035d63077fb4d))
+ $(eval $(call tar_download,IPROUTE2,iproute2,5.4.0,.tar.xz,https://www.kernel.org/pub/linux/utils/net/iproute2/,fe97aa60a0d4c5ac830be18937e18dc3400ca713a33a89ad896ff1e3d46086ae))
+ $(eval $(call tar_download,IPTABLES,iptables,1.8.4,.tar.bz2,https://www.netfilter.org/projects/iptables/files/,993a3a5490a544c2cbf2ef15cf7e7ed21af1845baf228318d5c36ef8827e157c))
+ $(eval $(call tar_download,NMAP,nmap,7.80,.tar.bz2,https://nmap.org/dist/,fcfa5a0e42099e12e4bf7a68ebe6fde05553383a682e816a7ec9256ab4773faa))
+ $(eval $(call tar_download,IPUTILS,iputils,s20190709,.tar.gz,https://github.com/iputils/iputils/archive/s20190709.tar.gz/#,a15720dd741d7538dd2645f9f516d193636ae4300ff7dbc8bfca757bf166490a))
+-$(eval $(call tar_download,WIREGUARD_TOOLS,wireguard-tools,1.0.20191226,.tar.xz,https://git.zx2c4.com/wireguard-tools/snapshot/,aa8af0fdc9872d369d8c890a84dbc2a2466b55795dccd5b47721b2d97644b04f))
++$(eval $(call tar_download,WIREGUARD_TOOLS,wireguard-tools,1.0.20200206,.tar.xz,https://git.zx2c4.com/wireguard-tools/snapshot/,f5207248c6a3c3e3bfc9ab30b91c1897b00802ed861e1f9faaed873366078c64))
+ 
+ KERNEL_BUILD_PATH := $(BUILD_PATH)/kernel$(if $(findstring yes,$(DEBUG_KERNEL)),-debug)
+ rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))
+@@ -295,21 +293,13 @@ $(IPERF_PATH)/src/iperf3: | $(IPERF_PATH
+ 	$(MAKE) -C $(IPERF_PATH)
+ 	$(STRIP) -s $@
+ 
+-$(LIBMNL_PATH)/.installed: $(LIBMNL_TAR)
+-	flock -s $<.lock tar -C $(BUILD_PATH) -xf $<
+-	touch $@
+-
+-$(LIBMNL_PATH)/src/.libs/libmnl.a: | $(LIBMNL_PATH)/.installed $(USERSPACE_DEPS)
+-	cd $(LIBMNL_PATH) && ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared
+-	$(MAKE) -C $(LIBMNL_PATH)
+-	sed -i 's:prefix=.*:prefix=$(LIBMNL_PATH):' $(LIBMNL_PATH)/libmnl.pc
+-
+ $(WIREGUARD_TOOLS_PATH)/.installed: $(WIREGUARD_TOOLS_TAR)
++	mkdir -p $(BUILD_PATH)
+ 	flock -s $<.lock tar -C $(BUILD_PATH) -xf $<
+ 	touch $@
+ 
+-$(WIREGUARD_TOOLS_PATH)/src/wg: | $(WIREGUARD_TOOLS_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS)
+-	LDFLAGS="$(LDFLAGS) -L$(LIBMNL_PATH)/src/.libs" $(MAKE) -C $(WIREGUARD_TOOLS_PATH)/src LIBMNL_CFLAGS="-I$(LIBMNL_PATH)/include" LIBMNL_LDLIBS="-lmnl" wg
++$(WIREGUARD_TOOLS_PATH)/src/wg: | $(WIREGUARD_TOOLS_PATH)/.installed $(USERSPACE_DEPS)
++	$(MAKE) -C $(WIREGUARD_TOOLS_PATH)/src wg
+ 	$(STRIP) -s $@
+ 
+ $(BUILD_PATH)/init: init.c | $(USERSPACE_DEPS)
+@@ -340,17 +330,17 @@ $(BASH_PATH)/bash: | $(BASH_PATH)/.insta
+ $(IPROUTE2_PATH)/.installed: $(IPROUTE2_TAR)
+ 	mkdir -p $(BUILD_PATH)
+ 	flock -s $<.lock tar -C $(BUILD_PATH) -xf $<
+-	printf 'CC:=$(CC)\nPKG_CONFIG:=pkg-config\nTC_CONFIG_XT:=n\nTC_CONFIG_ATM:=n\nTC_CONFIG_IPSET:=n\nIP_CONFIG_SETNS:=y\nHAVE_ELF:=n\nHAVE_MNL:=y\nHAVE_BERKELEY_DB:=n\nHAVE_LATEX:=n\nHAVE_PDFLATEX:=n\nCFLAGS+=-DHAVE_SETNS -DHAVE_LIBMNL -I$(LIBMNL_PATH)/include\nLDLIBS+=-lmnl' > $(IPROUTE2_PATH)/config.mk
++	printf 'CC:=$(CC)\nPKG_CONFIG:=pkg-config\nTC_CONFIG_XT:=n\nTC_CONFIG_ATM:=n\nTC_CONFIG_IPSET:=n\nIP_CONFIG_SETNS:=y\nHAVE_ELF:=n\nHAVE_MNL:=n\nHAVE_BERKELEY_DB:=n\nHAVE_LATEX:=n\nHAVE_PDFLATEX:=n\nCFLAGS+=-DHAVE_SETNS\n' > $(IPROUTE2_PATH)/config.mk
+ 	printf 'lib: snapshot\n\t$$(MAKE) -C lib\nip/ip: lib\n\t$$(MAKE) -C ip ip\nmisc/ss: lib\n\t$$(MAKE) -C misc ss\n' >> $(IPROUTE2_PATH)/Makefile
+ 	touch $@
+ 
+-$(IPROUTE2_PATH)/ip/ip: | $(IPROUTE2_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS)
+-	LDFLAGS="$(LDFLAGS) -L$(LIBMNL_PATH)/src/.libs" PKG_CONFIG_LIBDIR="$(LIBMNL_PATH)" $(MAKE) -C $(IPROUTE2_PATH) PREFIX=/ ip/ip
+-	$(STRIP) -s $(IPROUTE2_PATH)/ip/ip
+-
+-$(IPROUTE2_PATH)/misc/ss: | $(IPROUTE2_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS)
+-	LDFLAGS="$(LDFLAGS) -L$(LIBMNL_PATH)/src/.libs" PKG_CONFIG_LIBDIR="$(LIBMNL_PATH)" $(MAKE) -C $(IPROUTE2_PATH) PREFIX=/ misc/ss
+-	$(STRIP) -s $(IPROUTE2_PATH)/misc/ss
++$(IPROUTE2_PATH)/ip/ip: | $(IPROUTE2_PATH)/.installed $(USERSPACE_DEPS)
++	$(MAKE) -C $(IPROUTE2_PATH) PREFIX=/ ip/ip
++	$(STRIP) -s $@
++
++$(IPROUTE2_PATH)/misc/ss: | $(IPROUTE2_PATH)/.installed $(USERSPACE_DEPS)
++	$(MAKE) -C $(IPROUTE2_PATH) PREFIX=/ misc/ss
++	$(STRIP) -s $@
+ 
+ $(IPTABLES_PATH)/.installed: $(IPTABLES_TAR)
+ 	mkdir -p $(BUILD_PATH)
+@@ -358,8 +348,8 @@ $(IPTABLES_PATH)/.installed: $(IPTABLES_
+ 	sed -i -e "/nfnetlink=[01]/s:=[01]:=0:" -e "/nfconntrack=[01]/s:=[01]:=0:" $(IPTABLES_PATH)/configure
+ 	touch $@
+ 
+-$(IPTABLES_PATH)/iptables/xtables-legacy-multi: | $(IPTABLES_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS)
+-	cd $(IPTABLES_PATH) && PKG_CONFIG_LIBDIR="$(LIBMNL_PATH)" ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared --disable-nftables --disable-bpf-compiler --disable-nfsynproxy --disable-libipq --with-kernel=$(BUILD_PATH)/include
++$(IPTABLES_PATH)/iptables/xtables-legacy-multi: | $(IPTABLES_PATH)/.installed $(USERSPACE_DEPS)
++	cd $(IPTABLES_PATH) && ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared --disable-nftables --disable-bpf-compiler --disable-nfsynproxy --disable-libipq --disable-connlabel --with-kernel=$(BUILD_PATH)/include
+ 	$(MAKE) -C $(IPTABLES_PATH)
+ 	$(STRIP) -s $@
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0087-wireguard-receive-reset-last_under_load-to-zero.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0087-wireguard-receive-reset-last_under_load-to-zero.patch
new file mode 100644
index 0000000..193d28a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0087-wireguard-receive-reset-last_under_load-to-zero.patch
@@ -0,0 +1,38 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 14 Feb 2020 23:57:21 +0100
+Subject: [PATCH] wireguard: receive: reset last_under_load to zero
+
+commit 2a8a4df36462aa85b0db87b7c5ea145ba67e34a8 upstream.
+
+This is a small optimization that prevents more expensive comparisons
+from happening when they are no longer necessary, by clearing the
+last_under_load variable whenever we wind up in a state where we were
+under load but we no longer are.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Suggested-by: Matt Dunwoodie <ncon@noconroy.net>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/receive.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/wireguard/receive.c
++++ b/drivers/net/wireguard/receive.c
+@@ -118,10 +118,13 @@ static void wg_receive_handshake_packet(
+ 
+ 	under_load = skb_queue_len(&wg->incoming_handshakes) >=
+ 		     MAX_QUEUED_INCOMING_HANDSHAKES / 8;
+-	if (under_load)
++	if (under_load) {
+ 		last_under_load = ktime_get_coarse_boottime_ns();
+-	else if (last_under_load)
++	} else if (last_under_load) {
+ 		under_load = !wg_birthdate_has_expired(last_under_load, 1);
++		if (!under_load)
++			last_under_load = 0;
++	}
+ 	mac_state = wg_cookie_validate_packet(&wg->cookie_checker, skb,
+ 					      under_load);
+ 	if ((under_load && mac_state == VALID_MAC_WITH_COOKIE) ||
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0088-wireguard-send-account-for-mtu-0-devices.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0088-wireguard-send-account-for-mtu-0-devices.patch
new file mode 100644
index 0000000..d84efe2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0088-wireguard-send-account-for-mtu-0-devices.patch
@@ -0,0 +1,95 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 14 Feb 2020 23:57:22 +0100
+Subject: [PATCH] wireguard: send: account for mtu=0 devices
+
+commit 175f1ca9a9ed8689d2028da1a7c624bb4fb4ff7e upstream.
+
+It turns out there's an easy way to get packets queued up while still
+having an MTU of zero, and that's via persistent keep alive. This commit
+makes sure that in whatever condition, we don't wind up dividing by
+zero. Note that an MTU of zero for a wireguard interface is something
+quasi-valid, so I don't think the correct fix is to limit it via
+min_mtu. This can be reproduced easily with:
+
+ip link add wg0 type wireguard
+ip link add wg1 type wireguard
+ip link set wg0 up mtu 0
+ip link set wg1 up
+wg set wg0 private-key <(wg genkey)
+wg set wg1 listen-port 1 private-key <(wg genkey) peer $(wg show wg0 public-key)
+wg set wg0 peer $(wg show wg1 public-key) persistent-keepalive 1 endpoint 127.0.0.1:1
+
+However, while min_mtu=0 seems fine, it makes sense to restrict the
+max_mtu. This commit also restricts the maximum MTU to the greatest
+number for which rounding up to the padding multiple won't overflow a
+signed integer. Packets this large were always rejected anyway
+eventually, due to checks deeper in, but it seems more sound not to even
+let the administrator configure something that won't work anyway.
+
+We use this opportunity to clean up this function a bit so that it's
+clear which paths we're expecting.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Cc: Eric Dumazet <eric.dumazet@gmail.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/device.c |  7 ++++---
+ drivers/net/wireguard/send.c   | 16 +++++++++++-----
+ 2 files changed, 15 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/wireguard/device.c
++++ b/drivers/net/wireguard/device.c
+@@ -258,6 +258,8 @@ static void wg_setup(struct net_device *
+ 	enum { WG_NETDEV_FEATURES = NETIF_F_HW_CSUM | NETIF_F_RXCSUM |
+ 				    NETIF_F_SG | NETIF_F_GSO |
+ 				    NETIF_F_GSO_SOFTWARE | NETIF_F_HIGHDMA };
++	const int overhead = MESSAGE_MINIMUM_LENGTH + sizeof(struct udphdr) +
++			     max(sizeof(struct ipv6hdr), sizeof(struct iphdr));
+ 
+ 	dev->netdev_ops = &netdev_ops;
+ 	dev->hard_header_len = 0;
+@@ -271,9 +273,8 @@ static void wg_setup(struct net_device *
+ 	dev->features |= WG_NETDEV_FEATURES;
+ 	dev->hw_features |= WG_NETDEV_FEATURES;
+ 	dev->hw_enc_features |= WG_NETDEV_FEATURES;
+-	dev->mtu = ETH_DATA_LEN - MESSAGE_MINIMUM_LENGTH -
+-		   sizeof(struct udphdr) -
+-		   max(sizeof(struct ipv6hdr), sizeof(struct iphdr));
++	dev->mtu = ETH_DATA_LEN - overhead;
++	dev->max_mtu = round_down(INT_MAX, MESSAGE_PADDING_MULTIPLE) - overhead;
+ 
+ 	SET_NETDEV_DEVTYPE(dev, &device_type);
+ 
+--- a/drivers/net/wireguard/send.c
++++ b/drivers/net/wireguard/send.c
+@@ -143,16 +143,22 @@ static void keep_key_fresh(struct wg_pee
+ 
+ static unsigned int calculate_skb_padding(struct sk_buff *skb)
+ {
++	unsigned int padded_size, last_unit = skb->len;
++
++	if (unlikely(!PACKET_CB(skb)->mtu))
++		return ALIGN(last_unit, MESSAGE_PADDING_MULTIPLE) - last_unit;
++
+ 	/* We do this modulo business with the MTU, just in case the networking
+ 	 * layer gives us a packet that's bigger than the MTU. In that case, we
+ 	 * wouldn't want the final subtraction to overflow in the case of the
+-	 * padded_size being clamped.
++	 * padded_size being clamped. Fortunately, that's very rarely the case,
++	 * so we optimize for that not happening.
+ 	 */
+-	unsigned int last_unit = skb->len % PACKET_CB(skb)->mtu;
+-	unsigned int padded_size = ALIGN(last_unit, MESSAGE_PADDING_MULTIPLE);
++	if (unlikely(last_unit > PACKET_CB(skb)->mtu))
++		last_unit %= PACKET_CB(skb)->mtu;
+ 
+-	if (padded_size > PACKET_CB(skb)->mtu)
+-		padded_size = PACKET_CB(skb)->mtu;
++	padded_size = min(PACKET_CB(skb)->mtu,
++			  ALIGN(last_unit, MESSAGE_PADDING_MULTIPLE));
+ 	return padded_size - last_unit;
+ }
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0089-wireguard-socket-remove-extra-call-to-synchronize_ne.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0089-wireguard-socket-remove-extra-call-to-synchronize_ne.patch
new file mode 100644
index 0000000..458e9d5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0089-wireguard-socket-remove-extra-call-to-synchronize_ne.patch
@@ -0,0 +1,32 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 14 Feb 2020 23:57:23 +0100
+Subject: [PATCH] wireguard: socket: remove extra call to synchronize_net
+
+commit 1fbc33b0a7feb6ca72bf7dc8a05d81485ee8ee2e upstream.
+
+synchronize_net() is a wrapper around synchronize_rcu(), so there's no
+point in having synchronize_net and synchronize_rcu back to back,
+despite the documentation comment suggesting maybe it's somewhat useful,
+"Wait for packets currently being received to be done." This commit
+removes the extra call.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Suggested-by: Eric Dumazet <eric.dumazet@gmail.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/socket.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/net/wireguard/socket.c
++++ b/drivers/net/wireguard/socket.c
+@@ -432,7 +432,6 @@ void wg_socket_reinit(struct wg_device *
+ 		wg->incoming_port = ntohs(inet_sk(new4)->inet_sport);
+ 	mutex_unlock(&wg->socket_update_lock);
+ 	synchronize_rcu();
+-	synchronize_net();
+ 	sock_free(old4);
+ 	sock_free(old6);
+ }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0090-wireguard-selftests-remove-duplicated-include-sys-ty.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0090-wireguard-selftests-remove-duplicated-include-sys-ty.patch
new file mode 100644
index 0000000..93545e6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0090-wireguard-selftests-remove-duplicated-include-sys-ty.patch
@@ -0,0 +1,27 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: YueHaibing <yuehaibing@huawei.com>
+Date: Wed, 18 Mar 2020 18:30:43 -0600
+Subject: [PATCH] wireguard: selftests: remove duplicated include <sys/types.h>
+
+commit 166391159c5deb84795d2ff46e95f276177fa5fb upstream.
+
+This commit removes a duplicated include.
+
+Signed-off-by: YueHaibing <yuehaibing@huawei.com>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ tools/testing/selftests/wireguard/qemu/init.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/tools/testing/selftests/wireguard/qemu/init.c
++++ b/tools/testing/selftests/wireguard/qemu/init.c
+@@ -13,7 +13,6 @@
+ #include <fcntl.h>
+ #include <sys/wait.h>
+ #include <sys/mount.h>
+-#include <sys/types.h>
+ #include <sys/stat.h>
+ #include <sys/types.h>
+ #include <sys/io.h>
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0091-wireguard-queueing-account-for-skb-protocol-0.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0091-wireguard-queueing-account-for-skb-protocol-0.patch
new file mode 100644
index 0000000..a9ca655
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0091-wireguard-queueing-account-for-skb-protocol-0.patch
@@ -0,0 +1,100 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Wed, 18 Mar 2020 18:30:45 -0600
+Subject: [PATCH] wireguard: queueing: account for skb->protocol==0
+
+commit a5588604af448664e796daf3c1d5a4523c60667b upstream.
+
+We carry out checks to the effect of:
+
+  if (skb->protocol != wg_examine_packet_protocol(skb))
+    goto err;
+
+By having wg_skb_examine_untrusted_ip_hdr return 0 on failure, this
+means that the check above still passes in the case where skb->protocol
+is zero, which is possible to hit with AF_PACKET:
+
+  struct sockaddr_pkt saddr = { .spkt_device = "wg0" };
+  unsigned char buffer[5] = { 0 };
+  sendto(socket(AF_PACKET, SOCK_PACKET, /* skb->protocol = */ 0),
+         buffer, sizeof(buffer), 0, (const struct sockaddr *)&saddr, sizeof(saddr));
+
+Additional checks mean that this isn't actually a problem in the code
+base, but I could imagine it becoming a problem later if the function is
+used more liberally.
+
+I would prefer to fix this by having wg_examine_packet_protocol return a
+32-bit ~0 value on failure, which will never match any value of
+skb->protocol, which would simply change the generated code from a mov
+to a movzx. However, sparse complains, and adding __force casts doesn't
+seem like a good idea, so instead we just add a simple helper function
+to check for the zero return value. Since wg_examine_packet_protocol
+itself gets inlined, this winds up not adding an additional branch to
+the generated code, since the 0 return value already happens in a
+mergable branch.
+
+Reported-by: Fabian Freyer <fabianfreyer@radicallyopensecurity.com>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/device.c   | 2 +-
+ drivers/net/wireguard/queueing.h | 8 +++++++-
+ drivers/net/wireguard/receive.c  | 4 ++--
+ 3 files changed, 10 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/wireguard/device.c
++++ b/drivers/net/wireguard/device.c
+@@ -122,7 +122,7 @@ static netdev_tx_t wg_xmit(struct sk_buf
+ 	u32 mtu;
+ 	int ret;
+ 
+-	if (unlikely(wg_skb_examine_untrusted_ip_hdr(skb) != skb->protocol)) {
++	if (unlikely(!wg_check_packet_protocol(skb))) {
+ 		ret = -EPROTONOSUPPORT;
+ 		net_dbg_ratelimited("%s: Invalid IP packet\n", dev->name);
+ 		goto err;
+--- a/drivers/net/wireguard/queueing.h
++++ b/drivers/net/wireguard/queueing.h
+@@ -66,7 +66,7 @@ struct packet_cb {
+ #define PACKET_PEER(skb) (PACKET_CB(skb)->keypair->entry.peer)
+ 
+ /* Returns either the correct skb->protocol value, or 0 if invalid. */
+-static inline __be16 wg_skb_examine_untrusted_ip_hdr(struct sk_buff *skb)
++static inline __be16 wg_examine_packet_protocol(struct sk_buff *skb)
+ {
+ 	if (skb_network_header(skb) >= skb->head &&
+ 	    (skb_network_header(skb) + sizeof(struct iphdr)) <=
+@@ -81,6 +81,12 @@ static inline __be16 wg_skb_examine_untr
+ 	return 0;
+ }
+ 
++static inline bool wg_check_packet_protocol(struct sk_buff *skb)
++{
++	__be16 real_protocol = wg_examine_packet_protocol(skb);
++	return real_protocol && skb->protocol == real_protocol;
++}
++
+ static inline void wg_reset_packet(struct sk_buff *skb)
+ {
+ 	skb_scrub_packet(skb, true);
+--- a/drivers/net/wireguard/receive.c
++++ b/drivers/net/wireguard/receive.c
+@@ -56,7 +56,7 @@ static int prepare_skb_header(struct sk_
+ 	size_t data_offset, data_len, header_len;
+ 	struct udphdr *udp;
+ 
+-	if (unlikely(wg_skb_examine_untrusted_ip_hdr(skb) != skb->protocol ||
++	if (unlikely(!wg_check_packet_protocol(skb) ||
+ 		     skb_transport_header(skb) < skb->head ||
+ 		     (skb_transport_header(skb) + sizeof(struct udphdr)) >
+ 			     skb_tail_pointer(skb)))
+@@ -388,7 +388,7 @@ static void wg_packet_consume_data_done(
+ 	 */
+ 	skb->ip_summed = CHECKSUM_UNNECESSARY;
+ 	skb->csum_level = ~0; /* All levels */
+-	skb->protocol = wg_skb_examine_untrusted_ip_hdr(skb);
++	skb->protocol = wg_examine_packet_protocol(skb);
+ 	if (skb->protocol == htons(ETH_P_IP)) {
+ 		len = ntohs(ip_hdr(skb)->tot_len);
+ 		if (unlikely(len < sizeof(struct iphdr)))
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0092-wireguard-receive-remove-dead-code-from-default-pack.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0092-wireguard-receive-remove-dead-code-from-default-pack.patch
new file mode 100644
index 0000000..bcd4fbf
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0092-wireguard-receive-remove-dead-code-from-default-pack.patch
@@ -0,0 +1,35 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Wed, 18 Mar 2020 18:30:46 -0600
+Subject: [PATCH] wireguard: receive: remove dead code from default packet type
+ case
+
+commit 2b8765c52db24c0fbcc81bac9b5e8390f2c7d3c8 upstream.
+
+The situation in which we wind up hitting the default case here
+indicates a major bug in earlier parsing code. It is not a usual thing
+that should ever happen, which means a "friendly" message for it doesn't
+make sense. Rather, replace this with a WARN_ON, just like we do earlier
+in the file for a similar situation, so that somebody sends us a bug
+report and we can fix it.
+
+Reported-by: Fabian Freyer <fabianfreyer@radicallyopensecurity.com>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/receive.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/net/wireguard/receive.c
++++ b/drivers/net/wireguard/receive.c
+@@ -587,8 +587,7 @@ void wg_packet_receive(struct wg_device
+ 		wg_packet_consume_data(wg, skb);
+ 		break;
+ 	default:
+-		net_dbg_skb_ratelimited("%s: Invalid packet from %pISpfsc\n",
+-					wg->dev->name, skb);
++		WARN(1, "Non-exhaustive parsing of packet header lead to unknown packet type!\n");
+ 		goto err;
+ 	}
+ 	return;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0093-wireguard-noise-error-out-precomputed-DH-during-hand.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0093-wireguard-noise-error-out-precomputed-DH-during-hand.patch
new file mode 100644
index 0000000..dac3046
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0093-wireguard-noise-error-out-precomputed-DH-during-hand.patch
@@ -0,0 +1,224 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Wed, 18 Mar 2020 18:30:47 -0600
+Subject: [PATCH] wireguard: noise: error out precomputed DH during handshake
+ rather than config
+
+commit 11a7686aa99c7fe4b3f80f6dcccd54129817984d upstream.
+
+We precompute the static-static ECDH during configuration time, in order
+to save an expensive computation later when receiving network packets.
+However, not all ECDH computations yield a contributory result. Prior,
+we were just not letting those peers be added to the interface. However,
+this creates a strange inconsistency, since it was still possible to add
+other weird points, like a valid public key plus a low-order point, and,
+like points that result in zeros, a handshake would not complete. In
+order to make the behavior more uniform and less surprising, simply
+allow all peers to be added. Then, we'll error out later when doing the
+crypto if there's an issue. This also adds more separation between the
+crypto layer and the configuration layer.
+
+Discussed-with: Mathias Hall-Andersen <mathias@hall-andersen.dk>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/netlink.c            |  8 +---
+ drivers/net/wireguard/noise.c              | 55 ++++++++++++----------
+ drivers/net/wireguard/noise.h              | 12 ++---
+ drivers/net/wireguard/peer.c               |  7 +--
+ tools/testing/selftests/wireguard/netns.sh | 15 ++++--
+ 5 files changed, 49 insertions(+), 48 deletions(-)
+
+--- a/drivers/net/wireguard/netlink.c
++++ b/drivers/net/wireguard/netlink.c
+@@ -417,11 +417,7 @@ static int set_peer(struct wg_device *wg
+ 
+ 		peer = wg_peer_create(wg, public_key, preshared_key);
+ 		if (IS_ERR(peer)) {
+-			/* Similar to the above, if the key is invalid, we skip
+-			 * it without fanfare, so that services don't need to
+-			 * worry about doing key validation themselves.
+-			 */
+-			ret = PTR_ERR(peer) == -EKEYREJECTED ? 0 : PTR_ERR(peer);
++			ret = PTR_ERR(peer);
+ 			peer = NULL;
+ 			goto out;
+ 		}
+@@ -575,7 +571,7 @@ static int wg_set_device(struct sk_buff
+ 							 private_key);
+ 		list_for_each_entry_safe(peer, temp, &wg->peer_list,
+ 					 peer_list) {
+-			BUG_ON(!wg_noise_precompute_static_static(peer));
++			wg_noise_precompute_static_static(peer);
+ 			wg_noise_expire_current_peer_keypairs(peer);
+ 		}
+ 		wg_cookie_checker_precompute_device_keys(&wg->cookie_checker);
+--- a/drivers/net/wireguard/noise.c
++++ b/drivers/net/wireguard/noise.c
+@@ -44,32 +44,23 @@ void __init wg_noise_init(void)
+ }
+ 
+ /* Must hold peer->handshake.static_identity->lock */
+-bool wg_noise_precompute_static_static(struct wg_peer *peer)
++void wg_noise_precompute_static_static(struct wg_peer *peer)
+ {
+-	bool ret;
+-
+ 	down_write(&peer->handshake.lock);
+-	if (peer->handshake.static_identity->has_identity) {
+-		ret = curve25519(
+-			peer->handshake.precomputed_static_static,
++	if (!peer->handshake.static_identity->has_identity ||
++	    !curve25519(peer->handshake.precomputed_static_static,
+ 			peer->handshake.static_identity->static_private,
+-			peer->handshake.remote_static);
+-	} else {
+-		u8 empty[NOISE_PUBLIC_KEY_LEN] = { 0 };
+-
+-		ret = curve25519(empty, empty, peer->handshake.remote_static);
++			peer->handshake.remote_static))
+ 		memset(peer->handshake.precomputed_static_static, 0,
+ 		       NOISE_PUBLIC_KEY_LEN);
+-	}
+ 	up_write(&peer->handshake.lock);
+-	return ret;
+ }
+ 
+-bool wg_noise_handshake_init(struct noise_handshake *handshake,
+-			   struct noise_static_identity *static_identity,
+-			   const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN],
+-			   const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN],
+-			   struct wg_peer *peer)
++void wg_noise_handshake_init(struct noise_handshake *handshake,
++			     struct noise_static_identity *static_identity,
++			     const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN],
++			     const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN],
++			     struct wg_peer *peer)
+ {
+ 	memset(handshake, 0, sizeof(*handshake));
+ 	init_rwsem(&handshake->lock);
+@@ -81,7 +72,7 @@ bool wg_noise_handshake_init(struct nois
+ 		       NOISE_SYMMETRIC_KEY_LEN);
+ 	handshake->static_identity = static_identity;
+ 	handshake->state = HANDSHAKE_ZEROED;
+-	return wg_noise_precompute_static_static(peer);
++	wg_noise_precompute_static_static(peer);
+ }
+ 
+ static void handshake_zero(struct noise_handshake *handshake)
+@@ -403,6 +394,19 @@ static bool __must_check mix_dh(u8 chain
+ 	return true;
+ }
+ 
++static bool __must_check mix_precomputed_dh(u8 chaining_key[NOISE_HASH_LEN],
++					    u8 key[NOISE_SYMMETRIC_KEY_LEN],
++					    const u8 precomputed[NOISE_PUBLIC_KEY_LEN])
++{
++	static u8 zero_point[NOISE_PUBLIC_KEY_LEN];
++	if (unlikely(!crypto_memneq(precomputed, zero_point, NOISE_PUBLIC_KEY_LEN)))
++		return false;
++	kdf(chaining_key, key, NULL, precomputed, NOISE_HASH_LEN,
++	    NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN,
++	    chaining_key);
++	return true;
++}
++
+ static void mix_hash(u8 hash[NOISE_HASH_LEN], const u8 *src, size_t src_len)
+ {
+ 	struct blake2s_state blake;
+@@ -531,10 +535,9 @@ wg_noise_handshake_create_initiation(str
+ 			NOISE_PUBLIC_KEY_LEN, key, handshake->hash);
+ 
+ 	/* ss */
+-	kdf(handshake->chaining_key, key, NULL,
+-	    handshake->precomputed_static_static, NOISE_HASH_LEN,
+-	    NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN,
+-	    handshake->chaining_key);
++	if (!mix_precomputed_dh(handshake->chaining_key, key,
++				handshake->precomputed_static_static))
++		goto out;
+ 
+ 	/* {t} */
+ 	tai64n_now(timestamp);
+@@ -595,9 +598,9 @@ wg_noise_handshake_consume_initiation(st
+ 	handshake = &peer->handshake;
+ 
+ 	/* ss */
+-	kdf(chaining_key, key, NULL, handshake->precomputed_static_static,
+-	    NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN,
+-	    chaining_key);
++	if (!mix_precomputed_dh(chaining_key, key,
++				handshake->precomputed_static_static))
++	    goto out;
+ 
+ 	/* {t} */
+ 	if (!message_decrypt(t, src->encrypted_timestamp,
+--- a/drivers/net/wireguard/noise.h
++++ b/drivers/net/wireguard/noise.h
+@@ -94,11 +94,11 @@ struct noise_handshake {
+ struct wg_device;
+ 
+ void wg_noise_init(void);
+-bool wg_noise_handshake_init(struct noise_handshake *handshake,
+-			   struct noise_static_identity *static_identity,
+-			   const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN],
+-			   const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN],
+-			   struct wg_peer *peer);
++void wg_noise_handshake_init(struct noise_handshake *handshake,
++			     struct noise_static_identity *static_identity,
++			     const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN],
++			     const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN],
++			     struct wg_peer *peer);
+ void wg_noise_handshake_clear(struct noise_handshake *handshake);
+ static inline void wg_noise_reset_last_sent_handshake(atomic64_t *handshake_ns)
+ {
+@@ -116,7 +116,7 @@ void wg_noise_expire_current_peer_keypai
+ void wg_noise_set_static_identity_private_key(
+ 	struct noise_static_identity *static_identity,
+ 	const u8 private_key[NOISE_PUBLIC_KEY_LEN]);
+-bool wg_noise_precompute_static_static(struct wg_peer *peer);
++void wg_noise_precompute_static_static(struct wg_peer *peer);
+ 
+ bool
+ wg_noise_handshake_create_initiation(struct message_handshake_initiation *dst,
+--- a/drivers/net/wireguard/peer.c
++++ b/drivers/net/wireguard/peer.c
+@@ -34,11 +34,8 @@ struct wg_peer *wg_peer_create(struct wg
+ 		return ERR_PTR(ret);
+ 	peer->device = wg;
+ 
+-	if (!wg_noise_handshake_init(&peer->handshake, &wg->static_identity,
+-				     public_key, preshared_key, peer)) {
+-		ret = -EKEYREJECTED;
+-		goto err_1;
+-	}
++	wg_noise_handshake_init(&peer->handshake, &wg->static_identity,
++				public_key, preshared_key, peer);
+ 	if (dst_cache_init(&peer->endpoint_cache, GFP_KERNEL))
+ 		goto err_1;
+ 	if (wg_packet_queue_init(&peer->tx_queue, wg_packet_tx_worker, false,
+--- a/tools/testing/selftests/wireguard/netns.sh
++++ b/tools/testing/selftests/wireguard/netns.sh
+@@ -527,11 +527,16 @@ n0 wg set wg0 peer "$pub2" allowed-ips 0
+ n0 wg set wg0 peer "$pub2" allowed-ips ::/0,1700::/111,5000::/4,e000::/37,9000::/75
+ n0 wg set wg0 peer "$pub2" allowed-ips ::/0
+ n0 wg set wg0 peer "$pub2" remove
+-low_order_points=( AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 4Ot6fDtBuK4WVuP68Z/EatoJjeucMrH9hmIFFl9JuAA= X5yVvKNQjCSx0LFVnIPvWwREXMRYHI6G2CJO3dCfEVc= 7P///////////////////////////////////////38= 7f///////////////////////////////////////38= 7v///////////////////////////////////////38= )
+-n0 wg set wg0 private-key /dev/null ${low_order_points[@]/#/peer }
+-[[ -z $(n0 wg show wg0 peers) ]]
+-n0 wg set wg0 private-key <(echo "$key1") ${low_order_points[@]/#/peer }
+-[[ -z $(n0 wg show wg0 peers) ]]
++for low_order_point in AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 4Ot6fDtBuK4WVuP68Z/EatoJjeucMrH9hmIFFl9JuAA= X5yVvKNQjCSx0LFVnIPvWwREXMRYHI6G2CJO3dCfEVc= 7P///////////////////////////////////////38= 7f///////////////////////////////////////38= 7v///////////////////////////////////////38=; do
++	n0 wg set wg0 peer "$low_order_point" persistent-keepalive 1 endpoint 127.0.0.1:1111
++done
++[[ -n $(n0 wg show wg0 peers) ]]
++exec 4< <(n0 ncat -l -u -p 1111)
++ncat_pid=$!
++waitncatudp $netns0 $ncat_pid
++ip0 link set wg0 up
++! read -r -n 1 -t 2 <&4 || false
++kill $ncat_pid
+ ip0 link del wg0
+ 
+ declare -A objects
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0094-wireguard-send-remove-errant-newline-from-packet_enc.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0094-wireguard-send-remove-errant-newline-from-packet_enc.patch
new file mode 100644
index 0000000..c92b6a7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0094-wireguard-send-remove-errant-newline-from-packet_enc.patch
@@ -0,0 +1,29 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Sultan Alsawaf <sultan@kerneltoast.com>
+Date: Wed, 29 Apr 2020 14:59:20 -0600
+Subject: [PATCH] wireguard: send: remove errant newline from
+ packet_encrypt_worker
+
+commit d6833e42786e050e7522d6a91a9361e54085897d upstream.
+
+This commit removes a useless newline at the end of a scope, which
+doesn't add anything in the way of organization or readability.
+
+Signed-off-by: Sultan Alsawaf <sultan@kerneltoast.com>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/send.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/drivers/net/wireguard/send.c
++++ b/drivers/net/wireguard/send.c
+@@ -304,7 +304,6 @@ void wg_packet_encrypt_worker(struct wor
+ 		}
+ 		wg_queue_enqueue_per_peer(&PACKET_PEER(first)->tx_queue, first,
+ 					  state);
+-
+ 	}
+ }
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0095-wireguard-queueing-cleanup-ptr_ring-in-error-path-of.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0095-wireguard-queueing-cleanup-ptr_ring-in-error-path-of.patch
new file mode 100644
index 0000000..a72c509
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0095-wireguard-queueing-cleanup-ptr_ring-in-error-path-of.patch
@@ -0,0 +1,35 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Wed, 29 Apr 2020 14:59:21 -0600
+Subject: [PATCH] wireguard: queueing: cleanup ptr_ring in error path of
+ packet_queue_init
+
+commit 130c58606171326c81841a49cc913cd354113dd9 upstream.
+
+Prior, if the alloc_percpu of packet_percpu_multicore_worker_alloc
+failed, the previously allocated ptr_ring wouldn't be freed. This commit
+adds the missing call to ptr_ring_cleanup in the error case.
+
+Reported-by: Sultan Alsawaf <sultan@kerneltoast.com>
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/queueing.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/wireguard/queueing.c
++++ b/drivers/net/wireguard/queueing.c
+@@ -35,8 +35,10 @@ int wg_packet_queue_init(struct crypt_qu
+ 		if (multicore) {
+ 			queue->worker = wg_packet_percpu_multicore_worker_alloc(
+ 				function, queue);
+-			if (!queue->worker)
++			if (!queue->worker) {
++				ptr_ring_cleanup(&queue->ring, NULL);
+ 				return -ENOMEM;
++			}
+ 		} else {
+ 			INIT_WORK(&queue->work, function);
+ 		}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0096-wireguard-receive-use-tunnel-helpers-for-decapsulati.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0096-wireguard-receive-use-tunnel-helpers-for-decapsulati.patch
new file mode 100644
index 0000000..a72358c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0096-wireguard-receive-use-tunnel-helpers-for-decapsulati.patch
@@ -0,0 +1,50 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@redhat.com>
+Date: Wed, 29 Apr 2020 14:59:22 -0600
+Subject: [PATCH] wireguard: receive: use tunnel helpers for decapsulating ECN
+ markings
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit eebabcb26ea1e3295704477c6cd4e772c96a9559 upstream.
+
+WireGuard currently only propagates ECN markings on tunnel decap according
+to the old RFC3168 specification. However, the spec has since been updated
+in RFC6040 to recommend slightly different decapsulation semantics. This
+was implemented in the kernel as a set of common helpers for ECN
+decapsulation, so let's just switch over WireGuard to using those, so it
+can benefit from this enhancement and any future tweaks. We do not drop
+packets with invalid ECN marking combinations, because WireGuard is
+frequently used to work around broken ISPs, which could be doing that.
+
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Reported-by: Olivier Tilmans <olivier.tilmans@nokia-bell-labs.com>
+Cc: Dave Taht <dave.taht@gmail.com>
+Cc: Rodney W. Grimes <ietf@gndrsh.dnsmgr.net>
+Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/receive.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/wireguard/receive.c
++++ b/drivers/net/wireguard/receive.c
+@@ -393,13 +393,11 @@ static void wg_packet_consume_data_done(
+ 		len = ntohs(ip_hdr(skb)->tot_len);
+ 		if (unlikely(len < sizeof(struct iphdr)))
+ 			goto dishonest_packet_size;
+-		if (INET_ECN_is_ce(PACKET_CB(skb)->ds))
+-			IP_ECN_set_ce(ip_hdr(skb));
++		INET_ECN_decapsulate(skb, PACKET_CB(skb)->ds, ip_hdr(skb)->tos);
+ 	} else if (skb->protocol == htons(ETH_P_IPV6)) {
+ 		len = ntohs(ipv6_hdr(skb)->payload_len) +
+ 		      sizeof(struct ipv6hdr);
+-		if (INET_ECN_is_ce(PACKET_CB(skb)->ds))
+-			IP6_ECN_set_ce(skb, ipv6_hdr(skb));
++		INET_ECN_decapsulate(skb, PACKET_CB(skb)->ds, ipv6_get_dsfield(ipv6_hdr(skb)));
+ 	} else {
+ 		goto dishonest_packet_type;
+ 	}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0097-wireguard-selftests-use-normal-kernel-stack-size-on-.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0097-wireguard-selftests-use-normal-kernel-stack-size-on-.patch
new file mode 100644
index 0000000..f4543d2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0097-wireguard-selftests-use-normal-kernel-stack-size-on-.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Wed, 6 May 2020 15:33:02 -0600
+Subject: [PATCH] wireguard: selftests: use normal kernel stack size on ppc64
+
+commit a0fd7cc87a018df1a17f9d3f0bd994c1f22c6b34 upstream.
+
+While at some point it might have made sense to be running these tests
+on ppc64 with 4k stacks, the kernel hasn't actually used 4k stacks on
+64-bit powerpc in a long time, and more interesting things that we test
+don't really work when we deviate from the default (16k). So, we stop
+pushing our luck in this commit, and return to the default instead of
+the minimum.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ tools/testing/selftests/wireguard/qemu/arch/powerpc64le.config | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/tools/testing/selftests/wireguard/qemu/arch/powerpc64le.config
++++ b/tools/testing/selftests/wireguard/qemu/arch/powerpc64le.config
+@@ -10,3 +10,4 @@ CONFIG_CMDLINE_BOOL=y
+ CONFIG_CMDLINE="console=hvc0 wg.success=hvc1"
+ CONFIG_SECTION_MISMATCH_WARN_ONLY=y
+ CONFIG_FRAME_WARN=1280
++CONFIG_THREAD_SHIFT=14
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0098-wireguard-socket-remove-errant-restriction-on-loopin.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0098-wireguard-socket-remove-errant-restriction-on-loopin.patch
new file mode 100644
index 0000000..6dafa47
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0098-wireguard-socket-remove-errant-restriction-on-loopin.patch
@@ -0,0 +1,162 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Wed, 6 May 2020 15:33:03 -0600
+Subject: [PATCH] wireguard: socket: remove errant restriction on looping to
+ self
+
+commit b673e24aad36981f327a6570412ffa7754de8911 upstream.
+
+It's already possible to create two different interfaces and loop
+packets between them. This has always been possible with tunnels in the
+kernel, and isn't specific to wireguard. Therefore, the networking stack
+already needs to deal with that. At the very least, the packet winds up
+exceeding the MTU and is discarded at that point. So, since this is
+already something that happens, there's no need to forbid the not very
+exceptional case of routing a packet back to the same interface; this
+loop is no different than others, and we shouldn't special case it, but
+rather rely on generic handling of loops in general. This also makes it
+easier to do interesting things with wireguard such as onion routing.
+
+At the same time, we add a selftest for this, ensuring that both onion
+routing works and infinite routing loops do not crash the kernel. We
+also add a test case for wireguard interfaces nesting packets and
+sending traffic between each other, as well as the loop in this case
+too. We make sure to send some throughput-heavy traffic for this use
+case, to stress out any possible recursion issues with the locks around
+workqueues.
+
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/socket.c             | 12 -----
+ tools/testing/selftests/wireguard/netns.sh | 54 ++++++++++++++++++++--
+ 2 files changed, 51 insertions(+), 15 deletions(-)
+
+--- a/drivers/net/wireguard/socket.c
++++ b/drivers/net/wireguard/socket.c
+@@ -76,12 +76,6 @@ static int send4(struct wg_device *wg, s
+ 			net_dbg_ratelimited("%s: No route to %pISpfsc, error %d\n",
+ 					    wg->dev->name, &endpoint->addr, ret);
+ 			goto err;
+-		} else if (unlikely(rt->dst.dev == skb->dev)) {
+-			ip_rt_put(rt);
+-			ret = -ELOOP;
+-			net_dbg_ratelimited("%s: Avoiding routing loop to %pISpfsc\n",
+-					    wg->dev->name, &endpoint->addr);
+-			goto err;
+ 		}
+ 		if (cache)
+ 			dst_cache_set_ip4(cache, &rt->dst, fl.saddr);
+@@ -149,12 +143,6 @@ static int send6(struct wg_device *wg, s
+ 			net_dbg_ratelimited("%s: No route to %pISpfsc, error %d\n",
+ 					    wg->dev->name, &endpoint->addr, ret);
+ 			goto err;
+-		} else if (unlikely(dst->dev == skb->dev)) {
+-			dst_release(dst);
+-			ret = -ELOOP;
+-			net_dbg_ratelimited("%s: Avoiding routing loop to %pISpfsc\n",
+-					    wg->dev->name, &endpoint->addr);
+-			goto err;
+ 		}
+ 		if (cache)
+ 			dst_cache_set_ip6(cache, dst, &fl.saddr);
+--- a/tools/testing/selftests/wireguard/netns.sh
++++ b/tools/testing/selftests/wireguard/netns.sh
+@@ -48,8 +48,11 @@ cleanup() {
+ 	exec 2>/dev/null
+ 	printf "$orig_message_cost" > /proc/sys/net/core/message_cost
+ 	ip0 link del dev wg0
++	ip0 link del dev wg1
+ 	ip1 link del dev wg0
++	ip1 link del dev wg1
+ 	ip2 link del dev wg0
++	ip2 link del dev wg1
+ 	local to_kill="$(ip netns pids $netns0) $(ip netns pids $netns1) $(ip netns pids $netns2)"
+ 	[[ -n $to_kill ]] && kill $to_kill
+ 	pp ip netns del $netns1
+@@ -77,18 +80,20 @@ ip0 link set wg0 netns $netns2
+ key1="$(pp wg genkey)"
+ key2="$(pp wg genkey)"
+ key3="$(pp wg genkey)"
++key4="$(pp wg genkey)"
+ pub1="$(pp wg pubkey <<<"$key1")"
+ pub2="$(pp wg pubkey <<<"$key2")"
+ pub3="$(pp wg pubkey <<<"$key3")"
++pub4="$(pp wg pubkey <<<"$key4")"
+ psk="$(pp wg genpsk)"
+ [[ -n $key1 && -n $key2 && -n $psk ]]
+ 
+ configure_peers() {
+ 	ip1 addr add 192.168.241.1/24 dev wg0
+-	ip1 addr add fd00::1/24 dev wg0
++	ip1 addr add fd00::1/112 dev wg0
+ 
+ 	ip2 addr add 192.168.241.2/24 dev wg0
+-	ip2 addr add fd00::2/24 dev wg0
++	ip2 addr add fd00::2/112 dev wg0
+ 
+ 	n1 wg set wg0 \
+ 		private-key <(echo "$key1") \
+@@ -230,9 +235,38 @@ n1 ping -W 1 -c 1 192.168.241.2
+ n1 wg set wg0 private-key <(echo "$key3")
+ n2 wg set wg0 peer "$pub3" preshared-key <(echo "$psk") allowed-ips 192.168.241.1/32 peer "$pub1" remove
+ n1 ping -W 1 -c 1 192.168.241.2
++n2 wg set wg0 peer "$pub3" remove
+ 
+-ip1 link del wg0
++# Test that we can route wg through wg
++ip1 addr flush dev wg0
++ip2 addr flush dev wg0
++ip1 addr add fd00::5:1/112 dev wg0
++ip2 addr add fd00::5:2/112 dev wg0
++n1 wg set wg0 private-key <(echo "$key1") peer "$pub2" preshared-key <(echo "$psk") allowed-ips fd00::5:2/128 endpoint 127.0.0.1:2
++n2 wg set wg0 private-key <(echo "$key2") listen-port 2 peer "$pub1" preshared-key <(echo "$psk") allowed-ips fd00::5:1/128 endpoint 127.212.121.99:9998
++ip1 link add wg1 type wireguard
++ip2 link add wg1 type wireguard
++ip1 addr add 192.168.241.1/24 dev wg1
++ip1 addr add fd00::1/112 dev wg1
++ip2 addr add 192.168.241.2/24 dev wg1
++ip2 addr add fd00::2/112 dev wg1
++ip1 link set mtu 1340 up dev wg1
++ip2 link set mtu 1340 up dev wg1
++n1 wg set wg1 listen-port 5 private-key <(echo "$key3") peer "$pub4" allowed-ips 192.168.241.2/32,fd00::2/128 endpoint [fd00::5:2]:5
++n2 wg set wg1 listen-port 5 private-key <(echo "$key4") peer "$pub3" allowed-ips 192.168.241.1/32,fd00::1/128 endpoint [fd00::5:1]:5
++tests
++# Try to set up a routing loop between the two namespaces
++ip1 link set netns $netns0 dev wg1
++ip0 addr add 192.168.241.1/24 dev wg1
++ip0 link set up dev wg1
++n0 ping -W 1 -c 1 192.168.241.2
++n1 wg set wg0 peer "$pub2" endpoint 192.168.241.2:7
+ ip2 link del wg0
++ip2 link del wg1
++! n0 ping -W 1 -c 10 -f 192.168.241.2 || false # Should not crash kernel
++
++ip0 link del wg1
++ip1 link del wg0
+ 
+ # Test using NAT. We now change the topology to this:
+ # ┌────────────────────────────────────────┐    ┌────────────────────────────────────────────────┐     ┌────────────────────────────────────────┐
+@@ -282,6 +316,20 @@ pp sleep 3
+ n2 ping -W 1 -c 1 192.168.241.1
+ n1 wg set wg0 peer "$pub2" persistent-keepalive 0
+ 
++# Test that onion routing works, even when it loops
++n1 wg set wg0 peer "$pub3" allowed-ips 192.168.242.2/32 endpoint 192.168.241.2:5
++ip1 addr add 192.168.242.1/24 dev wg0
++ip2 link add wg1 type wireguard
++ip2 addr add 192.168.242.2/24 dev wg1
++n2 wg set wg1 private-key <(echo "$key3") listen-port 5 peer "$pub1" allowed-ips 192.168.242.1/32
++ip2 link set wg1 up
++n1 ping -W 1 -c 1 192.168.242.2
++ip2 link del wg1
++n1 wg set wg0 peer "$pub3" endpoint 192.168.242.2:5
++! n1 ping -W 1 -c 1 192.168.242.2 || false # Should not crash kernel
++n1 wg set wg0 peer "$pub3" remove
++ip1 addr del 192.168.242.1/24 dev wg0
++
+ # Do a wg-quick(8)-style policy routing for the default route, making sure vethc has a v6 address to tease out bugs.
+ ip1 -6 addr add fc00::9/96 dev vethc
+ ip1 -6 route add default via fc00::1
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0099-wireguard-send-receive-cond_resched-when-processing-.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0099-wireguard-send-receive-cond_resched-when-processing-.patch
new file mode 100644
index 0000000..499b36b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0099-wireguard-send-receive-cond_resched-when-processing-.patch
@@ -0,0 +1,58 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Wed, 6 May 2020 15:33:04 -0600
+Subject: [PATCH] wireguard: send/receive: cond_resched() when processing
+ worker ringbuffers
+
+commit 4005f5c3c9d006157ba716594e0d70c88a235c5e upstream.
+
+Users with pathological hardware reported CPU stalls on CONFIG_
+PREEMPT_VOLUNTARY=y, because the ringbuffers would stay full, meaning
+these workers would never terminate. That turned out not to be okay on
+systems without forced preemption, which Sultan observed. This commit
+adds a cond_resched() to the bottom of each loop iteration, so that
+these workers don't hog the core. Note that we don't need this on the
+napi poll worker, since that terminates after its budget is expended.
+
+Suggested-by: Sultan Alsawaf <sultan@kerneltoast.com>
+Reported-by: Wang Jian <larkwang@gmail.com>
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/receive.c | 2 ++
+ drivers/net/wireguard/send.c    | 4 ++++
+ 2 files changed, 6 insertions(+)
+
+--- a/drivers/net/wireguard/receive.c
++++ b/drivers/net/wireguard/receive.c
+@@ -516,6 +516,8 @@ void wg_packet_decrypt_worker(struct wor
+ 				&PACKET_CB(skb)->keypair->receiving)) ?
+ 				PACKET_STATE_CRYPTED : PACKET_STATE_DEAD;
+ 		wg_queue_enqueue_per_peer_napi(skb, state);
++		if (need_resched())
++			cond_resched();
+ 	}
+ }
+ 
+--- a/drivers/net/wireguard/send.c
++++ b/drivers/net/wireguard/send.c
+@@ -281,6 +281,8 @@ void wg_packet_tx_worker(struct work_str
+ 
+ 		wg_noise_keypair_put(keypair, false);
+ 		wg_peer_put(peer);
++		if (need_resched())
++			cond_resched();
+ 	}
+ }
+ 
+@@ -304,6 +306,8 @@ void wg_packet_encrypt_worker(struct wor
+ 		}
+ 		wg_queue_enqueue_per_peer(&PACKET_PEER(first)->tx_queue, first,
+ 					  state);
++		if (need_resched())
++			cond_resched();
+ 	}
+ }
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0100-wireguard-selftests-initalize-ipv6-members-to-NULL-t.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0100-wireguard-selftests-initalize-ipv6-members-to-NULL-t.patch
new file mode 100644
index 0000000..c1124be
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0100-wireguard-selftests-initalize-ipv6-members-to-NULL-t.patch
@@ -0,0 +1,51 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Wed, 6 May 2020 15:33:05 -0600
+Subject: [PATCH] wireguard: selftests: initalize ipv6 members to NULL to
+ squelch clang warning
+
+commit 4fed818ef54b08d4b29200e416cce65546ad5312 upstream.
+
+Without setting these to NULL, clang complains in certain
+configurations that have CONFIG_IPV6=n:
+
+In file included from drivers/net/wireguard/ratelimiter.c:223:
+drivers/net/wireguard/selftest/ratelimiter.c:173:34: error: variable 'skb6' is uninitialized when used here [-Werror,-Wuninitialized]
+                ret = timings_test(skb4, hdr4, skb6, hdr6, &test_count);
+                                               ^~~~
+drivers/net/wireguard/selftest/ratelimiter.c:123:29: note: initialize the variable 'skb6' to silence this warning
+        struct sk_buff *skb4, *skb6;
+                                   ^
+                                    = NULL
+drivers/net/wireguard/selftest/ratelimiter.c:173:40: error: variable 'hdr6' is uninitialized when used here [-Werror,-Wuninitialized]
+                ret = timings_test(skb4, hdr4, skb6, hdr6, &test_count);
+                                                     ^~~~
+drivers/net/wireguard/selftest/ratelimiter.c:125:22: note: initialize the variable 'hdr6' to silence this warning
+        struct ipv6hdr *hdr6;
+                            ^
+
+We silence this warning by setting the variables to NULL as the warning
+suggests.
+
+Reported-by: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/selftest/ratelimiter.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/wireguard/selftest/ratelimiter.c
++++ b/drivers/net/wireguard/selftest/ratelimiter.c
+@@ -120,9 +120,9 @@ bool __init wg_ratelimiter_selftest(void
+ 	enum { TRIALS_BEFORE_GIVING_UP = 5000 };
+ 	bool success = false;
+ 	int test = 0, trials;
+-	struct sk_buff *skb4, *skb6;
++	struct sk_buff *skb4, *skb6 = NULL;
+ 	struct iphdr *hdr4;
+-	struct ipv6hdr *hdr6;
++	struct ipv6hdr *hdr6 = NULL;
+ 
+ 	if (IS_ENABLED(CONFIG_KASAN) || IS_ENABLED(CONFIG_UBSAN))
+ 		return true;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0101-wireguard-send-receive-use-explicit-unlikely-branch-.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0101-wireguard-send-receive-use-explicit-unlikely-branch-.patch
new file mode 100644
index 0000000..900e2f2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0101-wireguard-send-receive-use-explicit-unlikely-branch-.patch
@@ -0,0 +1,88 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Wed, 6 May 2020 15:33:06 -0600
+Subject: [PATCH] wireguard: send/receive: use explicit unlikely branch instead
+ of implicit coalescing
+
+commit 243f2148937adc72bcaaa590d482d599c936efde upstream.
+
+It's very unlikely that send will become true. It's nearly always false
+between 0 and 120 seconds of a session, and in most cases becomes true
+only between 120 and 121 seconds before becoming false again. So,
+unlikely(send) is clearly the right option here.
+
+What happened before was that we had this complex boolean expression
+with multiple likely and unlikely clauses nested. Since this is
+evaluated left-to-right anyway, the whole thing got converted to
+unlikely. So, we can clean this up to better represent what's going on.
+
+The generated code is the same.
+
+Suggested-by: Sultan Alsawaf <sultan@kerneltoast.com>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/receive.c | 13 ++++++-------
+ drivers/net/wireguard/send.c    | 15 ++++++---------
+ 2 files changed, 12 insertions(+), 16 deletions(-)
+
+--- a/drivers/net/wireguard/receive.c
++++ b/drivers/net/wireguard/receive.c
+@@ -226,21 +226,20 @@ void wg_packet_handshake_receive_worker(
+ static void keep_key_fresh(struct wg_peer *peer)
+ {
+ 	struct noise_keypair *keypair;
+-	bool send = false;
++	bool send;
+ 
+ 	if (peer->sent_lastminute_handshake)
+ 		return;
+ 
+ 	rcu_read_lock_bh();
+ 	keypair = rcu_dereference_bh(peer->keypairs.current_keypair);
+-	if (likely(keypair && READ_ONCE(keypair->sending.is_valid)) &&
+-	    keypair->i_am_the_initiator &&
+-	    unlikely(wg_birthdate_has_expired(keypair->sending.birthdate,
+-			REJECT_AFTER_TIME - KEEPALIVE_TIMEOUT - REKEY_TIMEOUT)))
+-		send = true;
++	send = keypair && READ_ONCE(keypair->sending.is_valid) &&
++	       keypair->i_am_the_initiator &&
++	       wg_birthdate_has_expired(keypair->sending.birthdate,
++			REJECT_AFTER_TIME - KEEPALIVE_TIMEOUT - REKEY_TIMEOUT);
+ 	rcu_read_unlock_bh();
+ 
+-	if (send) {
++	if (unlikely(send)) {
+ 		peer->sent_lastminute_handshake = true;
+ 		wg_packet_send_queued_handshake_initiation(peer, false);
+ 	}
+--- a/drivers/net/wireguard/send.c
++++ b/drivers/net/wireguard/send.c
+@@ -124,20 +124,17 @@ void wg_packet_send_handshake_cookie(str
+ static void keep_key_fresh(struct wg_peer *peer)
+ {
+ 	struct noise_keypair *keypair;
+-	bool send = false;
++	bool send;
+ 
+ 	rcu_read_lock_bh();
+ 	keypair = rcu_dereference_bh(peer->keypairs.current_keypair);
+-	if (likely(keypair && READ_ONCE(keypair->sending.is_valid)) &&
+-	    (unlikely(atomic64_read(&keypair->sending.counter.counter) >
+-		      REKEY_AFTER_MESSAGES) ||
+-	     (keypair->i_am_the_initiator &&
+-	      unlikely(wg_birthdate_has_expired(keypair->sending.birthdate,
+-						REKEY_AFTER_TIME)))))
+-		send = true;
++	send = keypair && READ_ONCE(keypair->sending.is_valid) &&
++	       (atomic64_read(&keypair->sending.counter.counter) > REKEY_AFTER_MESSAGES ||
++		(keypair->i_am_the_initiator &&
++		 wg_birthdate_has_expired(keypair->sending.birthdate, REKEY_AFTER_TIME)));
+ 	rcu_read_unlock_bh();
+ 
+-	if (send)
++	if (unlikely(send))
+ 		wg_packet_send_queued_handshake_initiation(peer, false);
+ }
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0102-wireguard-selftests-use-newer-iproute2-for-gcc-10.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0102-wireguard-selftests-use-newer-iproute2-for-gcc-10.patch
new file mode 100644
index 0000000..d4efe37
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0102-wireguard-selftests-use-newer-iproute2-for-gcc-10.patch
@@ -0,0 +1,31 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Tue, 19 May 2020 22:49:27 -0600
+Subject: [PATCH] wireguard: selftests: use newer iproute2 for gcc-10
+
+commit ee3c1aa3f34b7842c1557cfe5d8c3f7b8c692de8 upstream.
+
+gcc-10 switched to defaulting to -fno-common, which broke iproute2-5.4.
+This was fixed in iproute-5.6, so switch to that. Because we're after a
+stable testing surface, we generally don't like to bump these
+unnecessarily, but in this case, being able to actually build is a basic
+necessity.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ tools/testing/selftests/wireguard/qemu/Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/tools/testing/selftests/wireguard/qemu/Makefile
++++ b/tools/testing/selftests/wireguard/qemu/Makefile
+@@ -44,7 +44,7 @@ endef
+ $(eval $(call tar_download,MUSL,musl,1.1.24,.tar.gz,https://www.musl-libc.org/releases/,1370c9a812b2cf2a7d92802510cca0058cc37e66a7bedd70051f0a34015022a3))
+ $(eval $(call tar_download,IPERF,iperf,3.7,.tar.gz,https://downloads.es.net/pub/iperf/,d846040224317caf2f75c843d309a950a7db23f9b44b94688ccbe557d6d1710c))
+ $(eval $(call tar_download,BASH,bash,5.0,.tar.gz,https://ftp.gnu.org/gnu/bash/,b4a80f2ac66170b2913efbfb9f2594f1f76c7b1afd11f799e22035d63077fb4d))
+-$(eval $(call tar_download,IPROUTE2,iproute2,5.4.0,.tar.xz,https://www.kernel.org/pub/linux/utils/net/iproute2/,fe97aa60a0d4c5ac830be18937e18dc3400ca713a33a89ad896ff1e3d46086ae))
++$(eval $(call tar_download,IPROUTE2,iproute2,5.6.0,.tar.xz,https://www.kernel.org/pub/linux/utils/net/iproute2/,1b5b0e25ce6e23da7526ea1da044e814ad85ba761b10dd29c2b027c056b04692))
+ $(eval $(call tar_download,IPTABLES,iptables,1.8.4,.tar.bz2,https://www.netfilter.org/projects/iptables/files/,993a3a5490a544c2cbf2ef15cf7e7ed21af1845baf228318d5c36ef8827e157c))
+ $(eval $(call tar_download,NMAP,nmap,7.80,.tar.bz2,https://nmap.org/dist/,fcfa5a0e42099e12e4bf7a68ebe6fde05553383a682e816a7ec9256ab4773faa))
+ $(eval $(call tar_download,IPUTILS,iputils,s20190709,.tar.gz,https://github.com/iputils/iputils/archive/s20190709.tar.gz/#,a15720dd741d7538dd2645f9f516d193636ae4300ff7dbc8bfca757bf166490a))
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0103-wireguard-noise-read-preshared-key-while-taking-lock.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0103-wireguard-noise-read-preshared-key-while-taking-lock.patch
new file mode 100644
index 0000000..2dac4b7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0103-wireguard-noise-read-preshared-key-while-taking-lock.patch
@@ -0,0 +1,61 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Tue, 19 May 2020 22:49:28 -0600
+Subject: [PATCH] wireguard: noise: read preshared key while taking lock
+
+commit bc67d371256f5c47d824e2eec51e46c8d62d022e upstream.
+
+Prior we read the preshared key after dropping the handshake lock, which
+isn't an actual crypto issue if it races, but it's still not quite
+correct. So copy that part of the state into a temporary like we do with
+the rest of the handshake state variables. Then we can release the lock,
+operate on the temporary, and zero it out at the end of the function. In
+performance tests, the impact of this was entirely unnoticable, probably
+because those bytes are coming from the same cacheline as other things
+that are being copied out in the same manner.
+
+Reported-by: Matt Dunwoodie <ncon@noconroy.net>
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/noise.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/wireguard/noise.c
++++ b/drivers/net/wireguard/noise.c
+@@ -715,6 +715,7 @@ wg_noise_handshake_consume_response(stru
+ 	u8 e[NOISE_PUBLIC_KEY_LEN];
+ 	u8 ephemeral_private[NOISE_PUBLIC_KEY_LEN];
+ 	u8 static_private[NOISE_PUBLIC_KEY_LEN];
++	u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN];
+ 
+ 	down_read(&wg->static_identity.lock);
+ 
+@@ -733,6 +734,8 @@ wg_noise_handshake_consume_response(stru
+ 	memcpy(chaining_key, handshake->chaining_key, NOISE_HASH_LEN);
+ 	memcpy(ephemeral_private, handshake->ephemeral_private,
+ 	       NOISE_PUBLIC_KEY_LEN);
++	memcpy(preshared_key, handshake->preshared_key,
++	       NOISE_SYMMETRIC_KEY_LEN);
+ 	up_read(&handshake->lock);
+ 
+ 	if (state != HANDSHAKE_CREATED_INITIATION)
+@@ -750,7 +753,7 @@ wg_noise_handshake_consume_response(stru
+ 		goto fail;
+ 
+ 	/* psk */
+-	mix_psk(chaining_key, hash, key, handshake->preshared_key);
++	mix_psk(chaining_key, hash, key, preshared_key);
+ 
+ 	/* {} */
+ 	if (!message_decrypt(NULL, src->encrypted_nothing,
+@@ -783,6 +786,7 @@ out:
+ 	memzero_explicit(chaining_key, NOISE_HASH_LEN);
+ 	memzero_explicit(ephemeral_private, NOISE_PUBLIC_KEY_LEN);
+ 	memzero_explicit(static_private, NOISE_PUBLIC_KEY_LEN);
++	memzero_explicit(preshared_key, NOISE_SYMMETRIC_KEY_LEN);
+ 	up_read(&wg->static_identity.lock);
+ 	return ret_peer;
+ }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0104-wireguard-queueing-preserve-flow-hash-across-packet-.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0104-wireguard-queueing-preserve-flow-hash-across-packet-.patch
new file mode 100644
index 0000000..31deadb
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0104-wireguard-queueing-preserve-flow-hash-across-packet-.patch
@@ -0,0 +1,116 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Tue, 19 May 2020 22:49:29 -0600
+Subject: [PATCH] wireguard: queueing: preserve flow hash across packet
+ scrubbing
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit c78a0b4a78839d572d8a80f6a62221c0d7843135 upstream.
+
+It's important that we clear most header fields during encapsulation and
+decapsulation, because the packet is substantially changed, and we don't
+want any info leak or logic bug due to an accidental correlation. But,
+for encapsulation, it's wrong to clear skb->hash, since it's used by
+fq_codel and flow dissection in general. Without it, classification does
+not proceed as usual. This change might make it easier to estimate the
+number of innerflows by examining clustering of out of order packets,
+but this shouldn't open up anything that can't already be inferred
+otherwise (e.g. syn packet size inference), and fq_codel can be disabled
+anyway.
+
+Furthermore, it might be the case that the hash isn't used or queried at
+all until after wireguard transmits the encrypted UDP packet, which
+means skb->hash might still be zero at this point, and thus no hash
+taken over the inner packet data. In order to address this situation, we
+force a calculation of skb->hash before encrypting packet data.
+
+Of course this means that fq_codel might transmit packets slightly more
+out of order than usual. Toke did some testing on beefy machines with
+high quantities of parallel flows and found that increasing the
+reply-attack counter to 8192 takes care of the most pathological cases
+pretty well.
+
+Reported-by: Dave Taht <dave.taht@gmail.com>
+Reviewed-and-tested-by: Toke Høiland-Jørgensen <toke@toke.dk>
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/messages.h |  2 +-
+ drivers/net/wireguard/queueing.h | 10 +++++++++-
+ drivers/net/wireguard/receive.c  |  2 +-
+ drivers/net/wireguard/send.c     |  7 ++++++-
+ 4 files changed, 17 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/wireguard/messages.h
++++ b/drivers/net/wireguard/messages.h
+@@ -32,7 +32,7 @@ enum cookie_values {
+ };
+ 
+ enum counter_values {
+-	COUNTER_BITS_TOTAL = 2048,
++	COUNTER_BITS_TOTAL = 8192,
+ 	COUNTER_REDUNDANT_BITS = BITS_PER_LONG,
+ 	COUNTER_WINDOW_SIZE = COUNTER_BITS_TOTAL - COUNTER_REDUNDANT_BITS
+ };
+--- a/drivers/net/wireguard/queueing.h
++++ b/drivers/net/wireguard/queueing.h
+@@ -87,12 +87,20 @@ static inline bool wg_check_packet_proto
+ 	return real_protocol && skb->protocol == real_protocol;
+ }
+ 
+-static inline void wg_reset_packet(struct sk_buff *skb)
++static inline void wg_reset_packet(struct sk_buff *skb, bool encapsulating)
+ {
++	u8 l4_hash = skb->l4_hash;
++	u8 sw_hash = skb->sw_hash;
++	u32 hash = skb->hash;
+ 	skb_scrub_packet(skb, true);
+ 	memset(&skb->headers_start, 0,
+ 	       offsetof(struct sk_buff, headers_end) -
+ 		       offsetof(struct sk_buff, headers_start));
++	if (encapsulating) {
++		skb->l4_hash = l4_hash;
++		skb->sw_hash = sw_hash;
++		skb->hash = hash;
++	}
+ 	skb->queue_mapping = 0;
+ 	skb->nohdr = 0;
+ 	skb->peeked = 0;
+--- a/drivers/net/wireguard/receive.c
++++ b/drivers/net/wireguard/receive.c
+@@ -484,7 +484,7 @@ int wg_packet_rx_poll(struct napi_struct
+ 		if (unlikely(wg_socket_endpoint_from_skb(&endpoint, skb)))
+ 			goto next;
+ 
+-		wg_reset_packet(skb);
++		wg_reset_packet(skb, false);
+ 		wg_packet_consume_data_done(peer, skb, &endpoint);
+ 		free = false;
+ 
+--- a/drivers/net/wireguard/send.c
++++ b/drivers/net/wireguard/send.c
+@@ -167,6 +167,11 @@ static bool encrypt_packet(struct sk_buf
+ 	struct sk_buff *trailer;
+ 	int num_frags;
+ 
++	/* Force hash calculation before encryption so that flow analysis is
++	 * consistent over the inner packet.
++	 */
++	skb_get_hash(skb);
++
+ 	/* Calculate lengths. */
+ 	padding_len = calculate_skb_padding(skb);
+ 	trailer_len = padding_len + noise_encrypted_len(0);
+@@ -295,7 +300,7 @@ void wg_packet_encrypt_worker(struct wor
+ 		skb_list_walk_safe(first, skb, next) {
+ 			if (likely(encrypt_packet(skb,
+ 					PACKET_CB(first)->keypair))) {
+-				wg_reset_packet(skb);
++				wg_reset_packet(skb, true);
+ 			} else {
+ 				state = PACKET_STATE_DEAD;
+ 				break;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0105-wireguard-noise-separate-receive-counter-from-send-c.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0105-wireguard-noise-separate-receive-counter-from-send-c.patch
new file mode 100644
index 0000000..87d38d3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0105-wireguard-noise-separate-receive-counter-from-send-c.patch
@@ -0,0 +1,330 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Tue, 19 May 2020 22:49:30 -0600
+Subject: [PATCH] wireguard: noise: separate receive counter from send counter
+
+commit a9e90d9931f3a474f04bab782ccd9d77904941e9 upstream.
+
+In "wireguard: queueing: preserve flow hash across packet scrubbing", we
+were required to slightly increase the size of the receive replay
+counter to something still fairly small, but an increase nonetheless.
+It turns out that we can recoup some of the additional memory overhead
+by splitting up the prior union type into two distinct types. Before, we
+used the same "noise_counter" union for both sending and receiving, with
+sending just using a simple atomic64_t, while receiving used the full
+replay counter checker. This meant that most of the memory being
+allocated for the sending counter was being wasted. Since the old
+"noise_counter" type increased in size in the prior commit, now is a
+good time to split up that union type into a distinct "noise_replay_
+counter" for receiving and a boring atomic64_t for sending, each using
+neither more nor less memory than required.
+
+Also, since sometimes the replay counter is accessed without
+necessitating additional accesses to the bitmap, we can reduce cache
+misses by hoisting the always-necessary lock above the bitmap in the
+struct layout. We also change a "noise_replay_counter" stack allocation
+to kmalloc in a -DDEBUG selftest so that KASAN doesn't trigger a stack
+frame warning.
+
+All and all, removing a bit of abstraction in this commit makes the code
+simpler and smaller, in addition to the motivating memory usage
+recuperation. For example, passing around raw "noise_symmetric_key"
+structs is something that really only makes sense within noise.c, in the
+one place where the sending and receiving keys can safely be thought of
+as the same type of object; subsequent to that, it's important that we
+uniformly access these through keypair->{sending,receiving}, where their
+distinct roles are always made explicit. So this patch allows us to draw
+that distinction clearly as well.
+
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/noise.c            | 16 +++------
+ drivers/net/wireguard/noise.h            | 14 ++++----
+ drivers/net/wireguard/receive.c          | 42 ++++++++++++------------
+ drivers/net/wireguard/selftest/counter.c | 17 +++++++---
+ drivers/net/wireguard/send.c             | 12 +++----
+ 5 files changed, 48 insertions(+), 53 deletions(-)
+
+--- a/drivers/net/wireguard/noise.c
++++ b/drivers/net/wireguard/noise.c
+@@ -104,6 +104,7 @@ static struct noise_keypair *keypair_cre
+ 
+ 	if (unlikely(!keypair))
+ 		return NULL;
++	spin_lock_init(&keypair->receiving_counter.lock);
+ 	keypair->internal_id = atomic64_inc_return(&keypair_counter);
+ 	keypair->entry.type = INDEX_HASHTABLE_KEYPAIR;
+ 	keypair->entry.peer = peer;
+@@ -358,25 +359,16 @@ out:
+ 	memzero_explicit(output, BLAKE2S_HASH_SIZE + 1);
+ }
+ 
+-static void symmetric_key_init(struct noise_symmetric_key *key)
+-{
+-	spin_lock_init(&key->counter.receive.lock);
+-	atomic64_set(&key->counter.counter, 0);
+-	memset(key->counter.receive.backtrack, 0,
+-	       sizeof(key->counter.receive.backtrack));
+-	key->birthdate = ktime_get_coarse_boottime_ns();
+-	key->is_valid = true;
+-}
+-
+ static void derive_keys(struct noise_symmetric_key *first_dst,
+ 			struct noise_symmetric_key *second_dst,
+ 			const u8 chaining_key[NOISE_HASH_LEN])
+ {
++	u64 birthdate = ktime_get_coarse_boottime_ns();
+ 	kdf(first_dst->key, second_dst->key, NULL, NULL,
+ 	    NOISE_SYMMETRIC_KEY_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, 0,
+ 	    chaining_key);
+-	symmetric_key_init(first_dst);
+-	symmetric_key_init(second_dst);
++	first_dst->birthdate = second_dst->birthdate = birthdate;
++	first_dst->is_valid = second_dst->is_valid = true;
+ }
+ 
+ static bool __must_check mix_dh(u8 chaining_key[NOISE_HASH_LEN],
+--- a/drivers/net/wireguard/noise.h
++++ b/drivers/net/wireguard/noise.h
+@@ -15,18 +15,14 @@
+ #include <linux/mutex.h>
+ #include <linux/kref.h>
+ 
+-union noise_counter {
+-	struct {
+-		u64 counter;
+-		unsigned long backtrack[COUNTER_BITS_TOTAL / BITS_PER_LONG];
+-		spinlock_t lock;
+-	} receive;
+-	atomic64_t counter;
++struct noise_replay_counter {
++	u64 counter;
++	spinlock_t lock;
++	unsigned long backtrack[COUNTER_BITS_TOTAL / BITS_PER_LONG];
+ };
+ 
+ struct noise_symmetric_key {
+ 	u8 key[NOISE_SYMMETRIC_KEY_LEN];
+-	union noise_counter counter;
+ 	u64 birthdate;
+ 	bool is_valid;
+ };
+@@ -34,7 +30,9 @@ struct noise_symmetric_key {
+ struct noise_keypair {
+ 	struct index_hashtable_entry entry;
+ 	struct noise_symmetric_key sending;
++	atomic64_t sending_counter;
+ 	struct noise_symmetric_key receiving;
++	struct noise_replay_counter receiving_counter;
+ 	__le32 remote_index;
+ 	bool i_am_the_initiator;
+ 	struct kref refcount;
+--- a/drivers/net/wireguard/receive.c
++++ b/drivers/net/wireguard/receive.c
+@@ -245,20 +245,20 @@ static void keep_key_fresh(struct wg_pee
+ 	}
+ }
+ 
+-static bool decrypt_packet(struct sk_buff *skb, struct noise_symmetric_key *key)
++static bool decrypt_packet(struct sk_buff *skb, struct noise_keypair *keypair)
+ {
+ 	struct scatterlist sg[MAX_SKB_FRAGS + 8];
+ 	struct sk_buff *trailer;
+ 	unsigned int offset;
+ 	int num_frags;
+ 
+-	if (unlikely(!key))
++	if (unlikely(!keypair))
+ 		return false;
+ 
+-	if (unlikely(!READ_ONCE(key->is_valid) ||
+-		  wg_birthdate_has_expired(key->birthdate, REJECT_AFTER_TIME) ||
+-		  key->counter.receive.counter >= REJECT_AFTER_MESSAGES)) {
+-		WRITE_ONCE(key->is_valid, false);
++	if (unlikely(!READ_ONCE(keypair->receiving.is_valid) ||
++		  wg_birthdate_has_expired(keypair->receiving.birthdate, REJECT_AFTER_TIME) ||
++		  keypair->receiving_counter.counter >= REJECT_AFTER_MESSAGES)) {
++		WRITE_ONCE(keypair->receiving.is_valid, false);
+ 		return false;
+ 	}
+ 
+@@ -283,7 +283,7 @@ static bool decrypt_packet(struct sk_buf
+ 
+ 	if (!chacha20poly1305_decrypt_sg_inplace(sg, skb->len, NULL, 0,
+ 					         PACKET_CB(skb)->nonce,
+-						 key->key))
++						 keypair->receiving.key))
+ 		return false;
+ 
+ 	/* Another ugly situation of pushing and pulling the header so as to
+@@ -298,41 +298,41 @@ static bool decrypt_packet(struct sk_buf
+ }
+ 
+ /* This is RFC6479, a replay detection bitmap algorithm that avoids bitshifts */
+-static bool counter_validate(union noise_counter *counter, u64 their_counter)
++static bool counter_validate(struct noise_replay_counter *counter, u64 their_counter)
+ {
+ 	unsigned long index, index_current, top, i;
+ 	bool ret = false;
+ 
+-	spin_lock_bh(&counter->receive.lock);
++	spin_lock_bh(&counter->lock);
+ 
+-	if (unlikely(counter->receive.counter >= REJECT_AFTER_MESSAGES + 1 ||
++	if (unlikely(counter->counter >= REJECT_AFTER_MESSAGES + 1 ||
+ 		     their_counter >= REJECT_AFTER_MESSAGES))
+ 		goto out;
+ 
+ 	++their_counter;
+ 
+ 	if (unlikely((COUNTER_WINDOW_SIZE + their_counter) <
+-		     counter->receive.counter))
++		     counter->counter))
+ 		goto out;
+ 
+ 	index = their_counter >> ilog2(BITS_PER_LONG);
+ 
+-	if (likely(their_counter > counter->receive.counter)) {
+-		index_current = counter->receive.counter >> ilog2(BITS_PER_LONG);
++	if (likely(their_counter > counter->counter)) {
++		index_current = counter->counter >> ilog2(BITS_PER_LONG);
+ 		top = min_t(unsigned long, index - index_current,
+ 			    COUNTER_BITS_TOTAL / BITS_PER_LONG);
+ 		for (i = 1; i <= top; ++i)
+-			counter->receive.backtrack[(i + index_current) &
++			counter->backtrack[(i + index_current) &
+ 				((COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1)] = 0;
+-		counter->receive.counter = their_counter;
++		counter->counter = their_counter;
+ 	}
+ 
+ 	index &= (COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1;
+ 	ret = !test_and_set_bit(their_counter & (BITS_PER_LONG - 1),
+-				&counter->receive.backtrack[index]);
++				&counter->backtrack[index]);
+ 
+ out:
+-	spin_unlock_bh(&counter->receive.lock);
++	spin_unlock_bh(&counter->lock);
+ 	return ret;
+ }
+ 
+@@ -472,12 +472,12 @@ int wg_packet_rx_poll(struct napi_struct
+ 		if (unlikely(state != PACKET_STATE_CRYPTED))
+ 			goto next;
+ 
+-		if (unlikely(!counter_validate(&keypair->receiving.counter,
++		if (unlikely(!counter_validate(&keypair->receiving_counter,
+ 					       PACKET_CB(skb)->nonce))) {
+ 			net_dbg_ratelimited("%s: Packet has invalid nonce %llu (max %llu)\n",
+ 					    peer->device->dev->name,
+ 					    PACKET_CB(skb)->nonce,
+-					    keypair->receiving.counter.receive.counter);
++					    keypair->receiving_counter.counter);
+ 			goto next;
+ 		}
+ 
+@@ -511,8 +511,8 @@ void wg_packet_decrypt_worker(struct wor
+ 	struct sk_buff *skb;
+ 
+ 	while ((skb = ptr_ring_consume_bh(&queue->ring)) != NULL) {
+-		enum packet_state state = likely(decrypt_packet(skb,
+-				&PACKET_CB(skb)->keypair->receiving)) ?
++		enum packet_state state =
++			likely(decrypt_packet(skb, PACKET_CB(skb)->keypair)) ?
+ 				PACKET_STATE_CRYPTED : PACKET_STATE_DEAD;
+ 		wg_queue_enqueue_per_peer_napi(skb, state);
+ 		if (need_resched())
+--- a/drivers/net/wireguard/selftest/counter.c
++++ b/drivers/net/wireguard/selftest/counter.c
+@@ -6,18 +6,24 @@
+ #ifdef DEBUG
+ bool __init wg_packet_counter_selftest(void)
+ {
++	struct noise_replay_counter *counter;
+ 	unsigned int test_num = 0, i;
+-	union noise_counter counter;
+ 	bool success = true;
+ 
+-#define T_INIT do {                                               \
+-		memset(&counter, 0, sizeof(union noise_counter)); \
+-		spin_lock_init(&counter.receive.lock);            \
++	counter = kmalloc(sizeof(*counter), GFP_KERNEL);
++	if (unlikely(!counter)) {
++		pr_err("nonce counter self-test malloc: FAIL\n");
++		return false;
++	}
++
++#define T_INIT do {                                    \
++		memset(counter, 0, sizeof(*counter));  \
++		spin_lock_init(&counter->lock);        \
+ 	} while (0)
+ #define T_LIM (COUNTER_WINDOW_SIZE + 1)
+ #define T(n, v) do {                                                  \
+ 		++test_num;                                           \
+-		if (counter_validate(&counter, n) != (v)) {           \
++		if (counter_validate(counter, n) != (v)) {            \
+ 			pr_err("nonce counter self-test %u: FAIL\n",  \
+ 			       test_num);                             \
+ 			success = false;                              \
+@@ -99,6 +105,7 @@ bool __init wg_packet_counter_selftest(v
+ 
+ 	if (success)
+ 		pr_info("nonce counter self-tests: pass\n");
++	kfree(counter);
+ 	return success;
+ }
+ #endif
+--- a/drivers/net/wireguard/send.c
++++ b/drivers/net/wireguard/send.c
+@@ -129,7 +129,7 @@ static void keep_key_fresh(struct wg_pee
+ 	rcu_read_lock_bh();
+ 	keypair = rcu_dereference_bh(peer->keypairs.current_keypair);
+ 	send = keypair && READ_ONCE(keypair->sending.is_valid) &&
+-	       (atomic64_read(&keypair->sending.counter.counter) > REKEY_AFTER_MESSAGES ||
++	       (atomic64_read(&keypair->sending_counter) > REKEY_AFTER_MESSAGES ||
+ 		(keypair->i_am_the_initiator &&
+ 		 wg_birthdate_has_expired(keypair->sending.birthdate, REKEY_AFTER_TIME)));
+ 	rcu_read_unlock_bh();
+@@ -349,7 +349,6 @@ void wg_packet_purge_staged_packets(stru
+ 
+ void wg_packet_send_staged_packets(struct wg_peer *peer)
+ {
+-	struct noise_symmetric_key *key;
+ 	struct noise_keypair *keypair;
+ 	struct sk_buff_head packets;
+ 	struct sk_buff *skb;
+@@ -369,10 +368,9 @@ void wg_packet_send_staged_packets(struc
+ 	rcu_read_unlock_bh();
+ 	if (unlikely(!keypair))
+ 		goto out_nokey;
+-	key = &keypair->sending;
+-	if (unlikely(!READ_ONCE(key->is_valid)))
++	if (unlikely(!READ_ONCE(keypair->sending.is_valid)))
+ 		goto out_nokey;
+-	if (unlikely(wg_birthdate_has_expired(key->birthdate,
++	if (unlikely(wg_birthdate_has_expired(keypair->sending.birthdate,
+ 					      REJECT_AFTER_TIME)))
+ 		goto out_invalid;
+ 
+@@ -387,7 +385,7 @@ void wg_packet_send_staged_packets(struc
+ 		 */
+ 		PACKET_CB(skb)->ds = ip_tunnel_ecn_encap(0, ip_hdr(skb), skb);
+ 		PACKET_CB(skb)->nonce =
+-				atomic64_inc_return(&key->counter.counter) - 1;
++				atomic64_inc_return(&keypair->sending_counter) - 1;
+ 		if (unlikely(PACKET_CB(skb)->nonce >= REJECT_AFTER_MESSAGES))
+ 			goto out_invalid;
+ 	}
+@@ -399,7 +397,7 @@ void wg_packet_send_staged_packets(struc
+ 	return;
+ 
+ out_invalid:
+-	WRITE_ONCE(key->is_valid, false);
++	WRITE_ONCE(keypair->sending.is_valid, false);
+ out_nokey:
+ 	wg_noise_keypair_put(keypair, false);
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0106-wireguard-noise-do-not-assign-initiation-time-in-if-.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0106-wireguard-noise-do-not-assign-initiation-time-in-if-.patch
new file mode 100644
index 0000000..a53c764
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0106-wireguard-noise-do-not-assign-initiation-time-in-if-.patch
@@ -0,0 +1,33 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Frank Werner-Krippendorf <mail@hb9fxq.ch>
+Date: Tue, 23 Jun 2020 03:59:44 -0600
+Subject: [PATCH] wireguard: noise: do not assign initiation time in if
+ condition
+
+commit 558b353c9c2a717509f291c066c6bd8f5f5e21be upstream.
+
+Fixes an error condition reported by checkpatch.pl which caused by
+assigning a variable in an if condition in wg_noise_handshake_consume_
+initiation().
+
+Signed-off-by: Frank Werner-Krippendorf <mail@hb9fxq.ch>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/noise.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/wireguard/noise.c
++++ b/drivers/net/wireguard/noise.c
+@@ -617,8 +617,8 @@ wg_noise_handshake_consume_initiation(st
+ 	memcpy(handshake->hash, hash, NOISE_HASH_LEN);
+ 	memcpy(handshake->chaining_key, chaining_key, NOISE_HASH_LEN);
+ 	handshake->remote_index = src->sender_index;
+-	if ((s64)(handshake->last_initiation_consumption -
+-	    (initiation_consumption = ktime_get_coarse_boottime_ns())) < 0)
++	initiation_consumption = ktime_get_coarse_boottime_ns();
++	if ((s64)(handshake->last_initiation_consumption - initiation_consumption) < 0)
+ 		handshake->last_initiation_consumption = initiation_consumption;
+ 	handshake->state = HANDSHAKE_CONSUMED_INITIATION;
+ 	up_write(&handshake->lock);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0107-wireguard-device-avoid-circular-netns-references.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0107-wireguard-device-avoid-circular-netns-references.patch
new file mode 100644
index 0000000..013023a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0107-wireguard-device-avoid-circular-netns-references.patch
@@ -0,0 +1,296 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Tue, 23 Jun 2020 03:59:45 -0600
+Subject: [PATCH] wireguard: device: avoid circular netns references
+
+commit 900575aa33a3eaaef802b31de187a85c4a4b4bd0 upstream.
+
+Before, we took a reference to the creating netns if the new netns was
+different. This caused issues with circular references, with two
+wireguard interfaces swapping namespaces. The solution is to rather not
+take any extra references at all, but instead simply invalidate the
+creating netns pointer when that netns is deleted.
+
+In order to prevent this from happening again, this commit improves the
+rough object leak tracking by allowing it to account for created and
+destroyed interfaces, aside from just peers and keys. That then makes it
+possible to check for the object leak when having two interfaces take a
+reference to each others' namespaces.
+
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/device.c             | 58 ++++++++++------------
+ drivers/net/wireguard/device.h             |  3 +-
+ drivers/net/wireguard/netlink.c            | 14 ++++--
+ drivers/net/wireguard/socket.c             | 25 +++++++---
+ tools/testing/selftests/wireguard/netns.sh | 13 ++++-
+ 5 files changed, 67 insertions(+), 46 deletions(-)
+
+--- a/drivers/net/wireguard/device.c
++++ b/drivers/net/wireguard/device.c
+@@ -45,17 +45,18 @@ static int wg_open(struct net_device *de
+ 	if (dev_v6)
+ 		dev_v6->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_NONE;
+ 
++	mutex_lock(&wg->device_update_lock);
+ 	ret = wg_socket_init(wg, wg->incoming_port);
+ 	if (ret < 0)
+-		return ret;
+-	mutex_lock(&wg->device_update_lock);
++		goto out;
+ 	list_for_each_entry(peer, &wg->peer_list, peer_list) {
+ 		wg_packet_send_staged_packets(peer);
+ 		if (peer->persistent_keepalive_interval)
+ 			wg_packet_send_keepalive(peer);
+ 	}
++out:
+ 	mutex_unlock(&wg->device_update_lock);
+-	return 0;
++	return ret;
+ }
+ 
+ #ifdef CONFIG_PM_SLEEP
+@@ -225,6 +226,7 @@ static void wg_destruct(struct net_devic
+ 	list_del(&wg->device_list);
+ 	rtnl_unlock();
+ 	mutex_lock(&wg->device_update_lock);
++	rcu_assign_pointer(wg->creating_net, NULL);
+ 	wg->incoming_port = 0;
+ 	wg_socket_reinit(wg, NULL, NULL);
+ 	/* The final references are cleared in the below calls to destroy_workqueue. */
+@@ -240,13 +242,11 @@ static void wg_destruct(struct net_devic
+ 	skb_queue_purge(&wg->incoming_handshakes);
+ 	free_percpu(dev->tstats);
+ 	free_percpu(wg->incoming_handshakes_worker);
+-	if (wg->have_creating_net_ref)
+-		put_net(wg->creating_net);
+ 	kvfree(wg->index_hashtable);
+ 	kvfree(wg->peer_hashtable);
+ 	mutex_unlock(&wg->device_update_lock);
+ 
+-	pr_debug("%s: Interface deleted\n", dev->name);
++	pr_debug("%s: Interface destroyed\n", dev->name);
+ 	free_netdev(dev);
+ }
+ 
+@@ -292,7 +292,7 @@ static int wg_newlink(struct net *src_ne
+ 	struct wg_device *wg = netdev_priv(dev);
+ 	int ret = -ENOMEM;
+ 
+-	wg->creating_net = src_net;
++	rcu_assign_pointer(wg->creating_net, src_net);
+ 	init_rwsem(&wg->static_identity.lock);
+ 	mutex_init(&wg->socket_update_lock);
+ 	mutex_init(&wg->device_update_lock);
+@@ -393,30 +393,26 @@ static struct rtnl_link_ops link_ops __r
+ 	.newlink		= wg_newlink,
+ };
+ 
+-static int wg_netdevice_notification(struct notifier_block *nb,
+-				     unsigned long action, void *data)
++static void wg_netns_pre_exit(struct net *net)
+ {
+-	struct net_device *dev = ((struct netdev_notifier_info *)data)->dev;
+-	struct wg_device *wg = netdev_priv(dev);
+-
+-	ASSERT_RTNL();
+-
+-	if (action != NETDEV_REGISTER || dev->netdev_ops != &netdev_ops)
+-		return 0;
++	struct wg_device *wg;
+ 
+-	if (dev_net(dev) == wg->creating_net && wg->have_creating_net_ref) {
+-		put_net(wg->creating_net);
+-		wg->have_creating_net_ref = false;
+-	} else if (dev_net(dev) != wg->creating_net &&
+-		   !wg->have_creating_net_ref) {
+-		wg->have_creating_net_ref = true;
+-		get_net(wg->creating_net);
++	rtnl_lock();
++	list_for_each_entry(wg, &device_list, device_list) {
++		if (rcu_access_pointer(wg->creating_net) == net) {
++			pr_debug("%s: Creating namespace exiting\n", wg->dev->name);
++			netif_carrier_off(wg->dev);
++			mutex_lock(&wg->device_update_lock);
++			rcu_assign_pointer(wg->creating_net, NULL);
++			wg_socket_reinit(wg, NULL, NULL);
++			mutex_unlock(&wg->device_update_lock);
++		}
+ 	}
+-	return 0;
++	rtnl_unlock();
+ }
+ 
+-static struct notifier_block netdevice_notifier = {
+-	.notifier_call = wg_netdevice_notification
++static struct pernet_operations pernet_ops = {
++	.pre_exit = wg_netns_pre_exit
+ };
+ 
+ int __init wg_device_init(void)
+@@ -429,18 +425,18 @@ int __init wg_device_init(void)
+ 		return ret;
+ #endif
+ 
+-	ret = register_netdevice_notifier(&netdevice_notifier);
++	ret = register_pernet_device(&pernet_ops);
+ 	if (ret)
+ 		goto error_pm;
+ 
+ 	ret = rtnl_link_register(&link_ops);
+ 	if (ret)
+-		goto error_netdevice;
++		goto error_pernet;
+ 
+ 	return 0;
+ 
+-error_netdevice:
+-	unregister_netdevice_notifier(&netdevice_notifier);
++error_pernet:
++	unregister_pernet_device(&pernet_ops);
+ error_pm:
+ #ifdef CONFIG_PM_SLEEP
+ 	unregister_pm_notifier(&pm_notifier);
+@@ -451,7 +447,7 @@ error_pm:
+ void wg_device_uninit(void)
+ {
+ 	rtnl_link_unregister(&link_ops);
+-	unregister_netdevice_notifier(&netdevice_notifier);
++	unregister_pernet_device(&pernet_ops);
+ #ifdef CONFIG_PM_SLEEP
+ 	unregister_pm_notifier(&pm_notifier);
+ #endif
+--- a/drivers/net/wireguard/device.h
++++ b/drivers/net/wireguard/device.h
+@@ -40,7 +40,7 @@ struct wg_device {
+ 	struct net_device *dev;
+ 	struct crypt_queue encrypt_queue, decrypt_queue;
+ 	struct sock __rcu *sock4, *sock6;
+-	struct net *creating_net;
++	struct net __rcu *creating_net;
+ 	struct noise_static_identity static_identity;
+ 	struct workqueue_struct *handshake_receive_wq, *handshake_send_wq;
+ 	struct workqueue_struct *packet_crypt_wq;
+@@ -56,7 +56,6 @@ struct wg_device {
+ 	unsigned int num_peers, device_update_gen;
+ 	u32 fwmark;
+ 	u16 incoming_port;
+-	bool have_creating_net_ref;
+ };
+ 
+ int wg_device_init(void);
+--- a/drivers/net/wireguard/netlink.c
++++ b/drivers/net/wireguard/netlink.c
+@@ -517,11 +517,15 @@ static int wg_set_device(struct sk_buff
+ 	if (flags & ~__WGDEVICE_F_ALL)
+ 		goto out;
+ 
+-	ret = -EPERM;
+-	if ((info->attrs[WGDEVICE_A_LISTEN_PORT] ||
+-	     info->attrs[WGDEVICE_A_FWMARK]) &&
+-	    !ns_capable(wg->creating_net->user_ns, CAP_NET_ADMIN))
+-		goto out;
++	if (info->attrs[WGDEVICE_A_LISTEN_PORT] || info->attrs[WGDEVICE_A_FWMARK]) {
++		struct net *net;
++		rcu_read_lock();
++		net = rcu_dereference(wg->creating_net);
++		ret = !net || !ns_capable(net->user_ns, CAP_NET_ADMIN) ? -EPERM : 0;
++		rcu_read_unlock();
++		if (ret)
++			goto out;
++	}
+ 
+ 	++wg->device_update_gen;
+ 
+--- a/drivers/net/wireguard/socket.c
++++ b/drivers/net/wireguard/socket.c
+@@ -347,6 +347,7 @@ static void set_sock_opts(struct socket
+ 
+ int wg_socket_init(struct wg_device *wg, u16 port)
+ {
++	struct net *net;
+ 	int ret;
+ 	struct udp_tunnel_sock_cfg cfg = {
+ 		.sk_user_data = wg,
+@@ -371,37 +372,47 @@ int wg_socket_init(struct wg_device *wg,
+ 	};
+ #endif
+ 
++	rcu_read_lock();
++	net = rcu_dereference(wg->creating_net);
++	net = net ? maybe_get_net(net) : NULL;
++	rcu_read_unlock();
++	if (unlikely(!net))
++		return -ENONET;
++
+ #if IS_ENABLED(CONFIG_IPV6)
+ retry:
+ #endif
+ 
+-	ret = udp_sock_create(wg->creating_net, &port4, &new4);
++	ret = udp_sock_create(net, &port4, &new4);
+ 	if (ret < 0) {
+ 		pr_err("%s: Could not create IPv4 socket\n", wg->dev->name);
+-		return ret;
++		goto out;
+ 	}
+ 	set_sock_opts(new4);
+-	setup_udp_tunnel_sock(wg->creating_net, new4, &cfg);
++	setup_udp_tunnel_sock(net, new4, &cfg);
+ 
+ #if IS_ENABLED(CONFIG_IPV6)
+ 	if (ipv6_mod_enabled()) {
+ 		port6.local_udp_port = inet_sk(new4->sk)->inet_sport;
+-		ret = udp_sock_create(wg->creating_net, &port6, &new6);
++		ret = udp_sock_create(net, &port6, &new6);
+ 		if (ret < 0) {
+ 			udp_tunnel_sock_release(new4);
+ 			if (ret == -EADDRINUSE && !port && retries++ < 100)
+ 				goto retry;
+ 			pr_err("%s: Could not create IPv6 socket\n",
+ 			       wg->dev->name);
+-			return ret;
++			goto out;
+ 		}
+ 		set_sock_opts(new6);
+-		setup_udp_tunnel_sock(wg->creating_net, new6, &cfg);
++		setup_udp_tunnel_sock(net, new6, &cfg);
+ 	}
+ #endif
+ 
+ 	wg_socket_reinit(wg, new4->sk, new6 ? new6->sk : NULL);
+-	return 0;
++	ret = 0;
++out:
++	put_net(net);
++	return ret;
+ }
+ 
+ void wg_socket_reinit(struct wg_device *wg, struct sock *new4,
+--- a/tools/testing/selftests/wireguard/netns.sh
++++ b/tools/testing/selftests/wireguard/netns.sh
+@@ -587,9 +587,20 @@ ip0 link set wg0 up
+ kill $ncat_pid
+ ip0 link del wg0
+ 
++# Ensure there aren't circular reference loops
++ip1 link add wg1 type wireguard
++ip2 link add wg2 type wireguard
++ip1 link set wg1 netns $netns2
++ip2 link set wg2 netns $netns1
++pp ip netns delete $netns1
++pp ip netns delete $netns2
++pp ip netns add $netns1
++pp ip netns add $netns2
++
++sleep 2 # Wait for cleanup and grace periods
+ declare -A objects
+ while read -t 0.1 -r line 2>/dev/null || [[ $? -ne 142 ]]; do
+-	[[ $line =~ .*(wg[0-9]+:\ [A-Z][a-z]+\ [0-9]+)\ .*(created|destroyed).* ]] || continue
++	[[ $line =~ .*(wg[0-9]+:\ [A-Z][a-z]+\ ?[0-9]*)\ .*(created|destroyed).* ]] || continue
+ 	objects["${BASH_REMATCH[1]}"]+="${BASH_REMATCH[2]}"
+ done < /dev/kmsg
+ alldeleted=1
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0108-wireguard-receive-account-for-napi_gro_receive-never.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0108-wireguard-receive-account-for-napi_gro_receive-never.patch
new file mode 100644
index 0000000..eceb0b9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0108-wireguard-receive-account-for-napi_gro_receive-never.patch
@@ -0,0 +1,42 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Wed, 24 Jun 2020 16:06:03 -0600
+Subject: [PATCH] wireguard: receive: account for napi_gro_receive never
+ returning GRO_DROP
+
+commit df08126e3833e9dca19e2407db5f5860a7c194fb upstream.
+
+The napi_gro_receive function no longer returns GRO_DROP ever, making
+handling GRO_DROP dead code. This commit removes that dead code.
+Further, it's not even clear that device drivers have any business in
+taking action after passing off received packets; that's arguably out of
+their hands.
+
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Fixes: 6570bc79c0df ("net: core: use listified Rx for GRO_NORMAL in napi_gro_receive()")
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/receive.c | 10 ++--------
+ 1 file changed, 2 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/wireguard/receive.c
++++ b/drivers/net/wireguard/receive.c
+@@ -414,14 +414,8 @@ static void wg_packet_consume_data_done(
+ 	if (unlikely(routed_peer != peer))
+ 		goto dishonest_packet_peer;
+ 
+-	if (unlikely(napi_gro_receive(&peer->napi, skb) == GRO_DROP)) {
+-		++dev->stats.rx_dropped;
+-		net_dbg_ratelimited("%s: Failed to give packet to userspace from peer %llu (%pISpfsc)\n",
+-				    dev->name, peer->internal_id,
+-				    &peer->endpoint.addr);
+-	} else {
+-		update_rx_stats(peer, message_data_len(len_before_trim));
+-	}
++	napi_gro_receive(&peer->napi, skb);
++	update_rx_stats(peer, message_data_len(len_before_trim));
+ 	return;
+ 
+ dishonest_packet_peer:
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0109-net-ip_tunnel-add-header_ops-for-layer-3-devices.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0109-net-ip_tunnel-add-header_ops-for-layer-3-devices.patch
new file mode 100644
index 0000000..cfd6b14
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0109-net-ip_tunnel-add-header_ops-for-layer-3-devices.patch
@@ -0,0 +1,58 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Mon, 29 Jun 2020 19:06:18 -0600
+Subject: [PATCH] net: ip_tunnel: add header_ops for layer 3 devices
+
+commit 2606aff916854b61234bf85001be9777bab2d5f8 upstream.
+
+Some devices that take straight up layer 3 packets benefit from having a
+shared header_ops so that AF_PACKET sockets can inject packets that are
+recognized. This shared infrastructure will be used by other drivers
+that currently can't inject packets using AF_PACKET. It also exposes the
+parser function, as it is useful in standalone form too.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Acked-by: Willem de Bruijn <willemb@google.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ include/net/ip_tunnels.h  |  3 +++
+ net/ipv4/ip_tunnel_core.c | 18 ++++++++++++++++++
+ 2 files changed, 21 insertions(+)
+
+--- a/include/net/ip_tunnels.h
++++ b/include/net/ip_tunnels.h
+@@ -289,6 +289,9 @@ int ip_tunnel_newlink(struct net_device
+ 		      struct ip_tunnel_parm *p, __u32 fwmark);
+ void ip_tunnel_setup(struct net_device *dev, unsigned int net_id);
+ 
++extern const struct header_ops ip_tunnel_header_ops;
++__be16 ip_tunnel_parse_protocol(const struct sk_buff *skb);
++
+ struct ip_tunnel_encap_ops {
+ 	size_t (*encap_hlen)(struct ip_tunnel_encap *e);
+ 	int (*build_header)(struct sk_buff *skb, struct ip_tunnel_encap *e,
+--- a/net/ipv4/ip_tunnel_core.c
++++ b/net/ipv4/ip_tunnel_core.c
+@@ -446,3 +446,21 @@ void ip_tunnel_unneed_metadata(void)
+ 	static_branch_dec(&ip_tunnel_metadata_cnt);
+ }
+ EXPORT_SYMBOL_GPL(ip_tunnel_unneed_metadata);
++
++/* Returns either the correct skb->protocol value, or 0 if invalid. */
++__be16 ip_tunnel_parse_protocol(const struct sk_buff *skb)
++{
++	if (skb_network_header(skb) >= skb->head &&
++	    (skb_network_header(skb) + sizeof(struct iphdr)) <= skb_tail_pointer(skb) &&
++	    ip_hdr(skb)->version == 4)
++		return htons(ETH_P_IP);
++	if (skb_network_header(skb) >= skb->head &&
++	    (skb_network_header(skb) + sizeof(struct ipv6hdr)) <= skb_tail_pointer(skb) &&
++	    ipv6_hdr(skb)->version == 6)
++		return htons(ETH_P_IPV6);
++	return 0;
++}
++EXPORT_SYMBOL(ip_tunnel_parse_protocol);
++
++const struct header_ops ip_tunnel_header_ops = { .parse_protocol = ip_tunnel_parse_protocol };
++EXPORT_SYMBOL(ip_tunnel_header_ops);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0110-wireguard-implement-header_ops-parse_protocol-for-AF.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0110-wireguard-implement-header_ops-parse_protocol-for-AF.patch
new file mode 100644
index 0000000..415ecff
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0110-wireguard-implement-header_ops-parse_protocol-for-AF.patch
@@ -0,0 +1,36 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Mon, 29 Jun 2020 19:06:20 -0600
+Subject: [PATCH] wireguard: implement header_ops->parse_protocol for AF_PACKET
+
+commit 01a4967c71c004f8ecad4ab57021348636502fa9 upstream.
+
+WireGuard uses skb->protocol to determine packet type, and bails out if
+it's not set or set to something it's not expecting. For AF_PACKET
+injection, we need to support its call chain of:
+
+    packet_sendmsg -> packet_snd -> packet_parse_headers ->
+      dev_parse_header_protocol -> parse_protocol
+
+Without a valid parse_protocol, this returns zero, and wireguard then
+rejects the skb. So, this wires up the ip_tunnel handler for layer 3
+packets for that case.
+
+Reported-by: Hans Wippel <ndev@hwipl.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/device.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/wireguard/device.c
++++ b/drivers/net/wireguard/device.c
+@@ -262,6 +262,7 @@ static void wg_setup(struct net_device *
+ 			     max(sizeof(struct ipv6hdr), sizeof(struct iphdr));
+ 
+ 	dev->netdev_ops = &netdev_ops;
++	dev->header_ops = &ip_tunnel_header_ops;
+ 	dev->hard_header_len = 0;
+ 	dev->addr_len = 0;
+ 	dev->needed_headroom = DATA_PACKET_HEAD_ROOM;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0111-wireguard-queueing-make-use-of-ip_tunnel_parse_proto.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0111-wireguard-queueing-make-use-of-ip_tunnel_parse_proto.patch
new file mode 100644
index 0000000..a777732
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0111-wireguard-queueing-make-use-of-ip_tunnel_parse_proto.patch
@@ -0,0 +1,68 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Mon, 29 Jun 2020 19:06:21 -0600
+Subject: [PATCH] wireguard: queueing: make use of ip_tunnel_parse_protocol
+
+commit 1a574074ae7d1d745c16f7710655f38a53174c27 upstream.
+
+Now that wg_examine_packet_protocol has been added for general
+consumption as ip_tunnel_parse_protocol, it's possible to remove
+wg_examine_packet_protocol and simply use the new
+ip_tunnel_parse_protocol function directly.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/queueing.h | 19 ++-----------------
+ drivers/net/wireguard/receive.c  |  2 +-
+ 2 files changed, 3 insertions(+), 18 deletions(-)
+
+--- a/drivers/net/wireguard/queueing.h
++++ b/drivers/net/wireguard/queueing.h
+@@ -11,6 +11,7 @@
+ #include <linux/skbuff.h>
+ #include <linux/ip.h>
+ #include <linux/ipv6.h>
++#include <net/ip_tunnels.h>
+ 
+ struct wg_device;
+ struct wg_peer;
+@@ -65,25 +66,9 @@ struct packet_cb {
+ #define PACKET_CB(skb) ((struct packet_cb *)((skb)->cb))
+ #define PACKET_PEER(skb) (PACKET_CB(skb)->keypair->entry.peer)
+ 
+-/* Returns either the correct skb->protocol value, or 0 if invalid. */
+-static inline __be16 wg_examine_packet_protocol(struct sk_buff *skb)
+-{
+-	if (skb_network_header(skb) >= skb->head &&
+-	    (skb_network_header(skb) + sizeof(struct iphdr)) <=
+-		    skb_tail_pointer(skb) &&
+-	    ip_hdr(skb)->version == 4)
+-		return htons(ETH_P_IP);
+-	if (skb_network_header(skb) >= skb->head &&
+-	    (skb_network_header(skb) + sizeof(struct ipv6hdr)) <=
+-		    skb_tail_pointer(skb) &&
+-	    ipv6_hdr(skb)->version == 6)
+-		return htons(ETH_P_IPV6);
+-	return 0;
+-}
+-
+ static inline bool wg_check_packet_protocol(struct sk_buff *skb)
+ {
+-	__be16 real_protocol = wg_examine_packet_protocol(skb);
++	__be16 real_protocol = ip_tunnel_parse_protocol(skb);
+ 	return real_protocol && skb->protocol == real_protocol;
+ }
+ 
+--- a/drivers/net/wireguard/receive.c
++++ b/drivers/net/wireguard/receive.c
+@@ -387,7 +387,7 @@ static void wg_packet_consume_data_done(
+ 	 */
+ 	skb->ip_summed = CHECKSUM_UNNECESSARY;
+ 	skb->csum_level = ~0; /* All levels */
+-	skb->protocol = wg_examine_packet_protocol(skb);
++	skb->protocol = ip_tunnel_parse_protocol(skb);
+ 	if (skb->protocol == htons(ETH_P_IP)) {
+ 		len = ntohs(ip_hdr(skb)->tot_len);
+ 		if (unlikely(len < sizeof(struct iphdr)))
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0112-netlink-consistently-use-NLA_POLICY_EXACT_LEN.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0112-netlink-consistently-use-NLA_POLICY_EXACT_LEN.patch
new file mode 100644
index 0000000..4b2712b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0112-netlink-consistently-use-NLA_POLICY_EXACT_LEN.patch
@@ -0,0 +1,49 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Tue, 18 Aug 2020 10:17:31 +0200
+Subject: [PATCH] netlink: consistently use NLA_POLICY_EXACT_LEN()
+
+commit 8140860c817f3e9f78bcd1e420b9777ddcbaa629 upstream.
+
+Change places that open-code NLA_POLICY_EXACT_LEN() to
+use the macro instead, giving us flexibility in how we
+handle the details of the macro.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Acked-by: Matthieu Baerts <matthieu.baerts@tessares.net>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+[Jason: only picked the drivers/net/wireguard/* part]
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/netlink.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/wireguard/netlink.c
++++ b/drivers/net/wireguard/netlink.c
+@@ -22,8 +22,8 @@ static struct genl_family genl_family;
+ static const struct nla_policy device_policy[WGDEVICE_A_MAX + 1] = {
+ 	[WGDEVICE_A_IFINDEX]		= { .type = NLA_U32 },
+ 	[WGDEVICE_A_IFNAME]		= { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
+-	[WGDEVICE_A_PRIVATE_KEY]	= { .type = NLA_EXACT_LEN, .len = NOISE_PUBLIC_KEY_LEN },
+-	[WGDEVICE_A_PUBLIC_KEY]		= { .type = NLA_EXACT_LEN, .len = NOISE_PUBLIC_KEY_LEN },
++	[WGDEVICE_A_PRIVATE_KEY]	= NLA_POLICY_EXACT_LEN(NOISE_PUBLIC_KEY_LEN),
++	[WGDEVICE_A_PUBLIC_KEY]		= NLA_POLICY_EXACT_LEN(NOISE_PUBLIC_KEY_LEN),
+ 	[WGDEVICE_A_FLAGS]		= { .type = NLA_U32 },
+ 	[WGDEVICE_A_LISTEN_PORT]	= { .type = NLA_U16 },
+ 	[WGDEVICE_A_FWMARK]		= { .type = NLA_U32 },
+@@ -31,12 +31,12 @@ static const struct nla_policy device_po
+ };
+ 
+ static const struct nla_policy peer_policy[WGPEER_A_MAX + 1] = {
+-	[WGPEER_A_PUBLIC_KEY]				= { .type = NLA_EXACT_LEN, .len = NOISE_PUBLIC_KEY_LEN },
+-	[WGPEER_A_PRESHARED_KEY]			= { .type = NLA_EXACT_LEN, .len = NOISE_SYMMETRIC_KEY_LEN },
++	[WGPEER_A_PUBLIC_KEY]				= NLA_POLICY_EXACT_LEN(NOISE_PUBLIC_KEY_LEN),
++	[WGPEER_A_PRESHARED_KEY]			= NLA_POLICY_EXACT_LEN(NOISE_SYMMETRIC_KEY_LEN),
+ 	[WGPEER_A_FLAGS]				= { .type = NLA_U32 },
+ 	[WGPEER_A_ENDPOINT]				= { .type = NLA_MIN_LEN, .len = sizeof(struct sockaddr) },
+ 	[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]	= { .type = NLA_U16 },
+-	[WGPEER_A_LAST_HANDSHAKE_TIME]			= { .type = NLA_EXACT_LEN, .len = sizeof(struct __kernel_timespec) },
++	[WGPEER_A_LAST_HANDSHAKE_TIME]			= NLA_POLICY_EXACT_LEN(sizeof(struct __kernel_timespec)),
+ 	[WGPEER_A_RX_BYTES]				= { .type = NLA_U64 },
+ 	[WGPEER_A_TX_BYTES]				= { .type = NLA_U64 },
+ 	[WGPEER_A_ALLOWEDIPS]				= { .type = NLA_NESTED },
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0113-netlink-consistently-use-NLA_POLICY_MIN_LEN.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0113-netlink-consistently-use-NLA_POLICY_MIN_LEN.patch
new file mode 100644
index 0000000..4b414bc
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0113-netlink-consistently-use-NLA_POLICY_MIN_LEN.patch
@@ -0,0 +1,39 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Tue, 18 Aug 2020 10:17:32 +0200
+Subject: [PATCH] netlink: consistently use NLA_POLICY_MIN_LEN()
+
+commit bc0435855041d7fff0b83dd992fc4be34aa11afb upstream.
+
+Change places that open-code NLA_POLICY_MIN_LEN() to
+use the macro instead, giving us flexibility in how we
+handle the details of the macro.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+[Jason: only picked the drivers/net/wireguard/* part]
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/netlink.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/wireguard/netlink.c
++++ b/drivers/net/wireguard/netlink.c
+@@ -34,7 +34,7 @@ static const struct nla_policy peer_poli
+ 	[WGPEER_A_PUBLIC_KEY]				= NLA_POLICY_EXACT_LEN(NOISE_PUBLIC_KEY_LEN),
+ 	[WGPEER_A_PRESHARED_KEY]			= NLA_POLICY_EXACT_LEN(NOISE_SYMMETRIC_KEY_LEN),
+ 	[WGPEER_A_FLAGS]				= { .type = NLA_U32 },
+-	[WGPEER_A_ENDPOINT]				= { .type = NLA_MIN_LEN, .len = sizeof(struct sockaddr) },
++	[WGPEER_A_ENDPOINT]				= NLA_POLICY_MIN_LEN(sizeof(struct sockaddr)),
+ 	[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]	= { .type = NLA_U16 },
+ 	[WGPEER_A_LAST_HANDSHAKE_TIME]			= NLA_POLICY_EXACT_LEN(sizeof(struct __kernel_timespec)),
+ 	[WGPEER_A_RX_BYTES]				= { .type = NLA_U64 },
+@@ -45,7 +45,7 @@ static const struct nla_policy peer_poli
+ 
+ static const struct nla_policy allowedip_policy[WGALLOWEDIP_A_MAX + 1] = {
+ 	[WGALLOWEDIP_A_FAMILY]		= { .type = NLA_U16 },
+-	[WGALLOWEDIP_A_IPADDR]		= { .type = NLA_MIN_LEN, .len = sizeof(struct in_addr) },
++	[WGALLOWEDIP_A_IPADDR]		= NLA_POLICY_MIN_LEN(sizeof(struct in_addr)),
+ 	[WGALLOWEDIP_A_CIDR_MASK]	= { .type = NLA_U8 }
+ };
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0114-wireguard-noise-take-lock-when-removing-handshake-en.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0114-wireguard-noise-take-lock-when-removing-handshake-en.patch
new file mode 100644
index 0000000..e80528c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0114-wireguard-noise-take-lock-when-removing-handshake-en.patch
@@ -0,0 +1,127 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Wed, 9 Sep 2020 13:58:14 +0200
+Subject: [PATCH] wireguard: noise: take lock when removing handshake entry
+ from table
+
+commit 9179ba31367bcf481c3c79b5f028c94faad9f30a upstream.
+
+Eric reported that syzkaller found a race of this variety:
+
+CPU 1                                       CPU 2
+-------------------------------------------|---------------------------------------
+wg_index_hashtable_replace(old, ...)       |
+  if (hlist_unhashed(&old->index_hash))    |
+                                           | wg_index_hashtable_remove(old)
+                                           |   hlist_del_init_rcu(&old->index_hash)
+				           |     old->index_hash.pprev = NULL
+  hlist_replace_rcu(&old->index_hash, ...) |
+    *old->index_hash.pprev                 |
+
+Syzbot wasn't actually able to reproduce this more than once or create a
+reproducer, because the race window between checking "hlist_unhashed" and
+calling "hlist_replace_rcu" is just so small. Adding an mdelay(5) or
+similar there helps make this demonstrable using this simple script:
+
+    #!/bin/bash
+    set -ex
+    trap 'kill $pid1; kill $pid2; ip link del wg0; ip link del wg1' EXIT
+    ip link add wg0 type wireguard
+    ip link add wg1 type wireguard
+    wg set wg0 private-key <(wg genkey) listen-port 9999
+    wg set wg1 private-key <(wg genkey) peer $(wg show wg0 public-key) endpoint 127.0.0.1:9999 persistent-keepalive 1
+    wg set wg0 peer $(wg show wg1 public-key)
+    ip link set wg0 up
+    yes link set wg1 up | ip -force -batch - &
+    pid1=$!
+    yes link set wg1 down | ip -force -batch - &
+    pid2=$!
+    wait
+
+The fundumental underlying problem is that we permit calls to wg_index_
+hashtable_remove(handshake.entry) without requiring the caller to take
+the handshake mutex that is intended to protect members of handshake
+during mutations. This is consistently the case with calls to wg_index_
+hashtable_insert(handshake.entry) and wg_index_hashtable_replace(
+handshake.entry), but it's missing from a pertinent callsite of wg_
+index_hashtable_remove(handshake.entry). So, this patch makes sure that
+mutex is taken.
+
+The original code was a little bit funky though, in the form of:
+
+    remove(handshake.entry)
+    lock(), memzero(handshake.some_members), unlock()
+    remove(handshake.entry)
+
+The original intention of that double removal pattern outside the lock
+appears to be some attempt to prevent insertions that might happen while
+locks are dropped during expensive crypto operations, but actually, all
+callers of wg_index_hashtable_insert(handshake.entry) take the write
+lock and then explicitly check handshake.state, as they should, which
+the aforementioned memzero clears, which means an insertion should
+already be impossible. And regardless, the original intention was
+necessarily racy, since it wasn't guaranteed that something else would
+run after the unlock() instead of after the remove(). So, from a
+soundness perspective, it seems positive to remove what looks like a
+hack at best.
+
+The crash from both syzbot and from the script above is as follows:
+
+  general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN
+  KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
+  CPU: 0 PID: 7395 Comm: kworker/0:3 Not tainted 5.9.0-rc4-syzkaller #0
+  Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
+  Workqueue: wg-kex-wg1 wg_packet_handshake_receive_worker
+  RIP: 0010:hlist_replace_rcu include/linux/rculist.h:505 [inline]
+  RIP: 0010:wg_index_hashtable_replace+0x176/0x330 drivers/net/wireguard/peerlookup.c:174
+  Code: 00 fc ff df 48 89 f9 48 c1 e9 03 80 3c 01 00 0f 85 44 01 00 00 48 b9 00 00 00 00 00 fc ff df 48 8b 45 10 48 89 c6 48 c1 ee 03 <80> 3c 0e 00 0f 85 06 01 00 00 48 85 d2 4c 89 28 74 47 e8 a3 4f b5
+  RSP: 0018:ffffc90006a97bf8 EFLAGS: 00010246
+  RAX: 0000000000000000 RBX: ffff888050ffc4f8 RCX: dffffc0000000000
+  RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff88808e04e010
+  RBP: ffff88808e04e000 R08: 0000000000000001 R09: ffff8880543d0000
+  R10: ffffed100a87a000 R11: 000000000000016e R12: ffff8880543d0000
+  R13: ffff88808e04e008 R14: ffff888050ffc508 R15: ffff888050ffc500
+  FS:  0000000000000000(0000) GS:ffff8880ae600000(0000) knlGS:0000000000000000
+  CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+  CR2: 00000000f5505db0 CR3: 0000000097cf7000 CR4: 00000000001526f0
+  DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+  DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
+  Call Trace:
+  wg_noise_handshake_begin_session+0x752/0xc9a drivers/net/wireguard/noise.c:820
+  wg_receive_handshake_packet drivers/net/wireguard/receive.c:183 [inline]
+  wg_packet_handshake_receive_worker+0x33b/0x730 drivers/net/wireguard/receive.c:220
+  process_one_work+0x94c/0x1670 kernel/workqueue.c:2269
+  worker_thread+0x64c/0x1120 kernel/workqueue.c:2415
+  kthread+0x3b5/0x4a0 kernel/kthread.c:292
+  ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:294
+
+Reported-by: syzbot <syzkaller@googlegroups.com>
+Reported-by: Eric Dumazet <edumazet@google.com>
+Link: https://lore.kernel.org/wireguard/20200908145911.4090480-1-edumazet@google.com/
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/noise.c | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+--- a/drivers/net/wireguard/noise.c
++++ b/drivers/net/wireguard/noise.c
+@@ -87,15 +87,12 @@ static void handshake_zero(struct noise_
+ 
+ void wg_noise_handshake_clear(struct noise_handshake *handshake)
+ {
++	down_write(&handshake->lock);
+ 	wg_index_hashtable_remove(
+ 			handshake->entry.peer->device->index_hashtable,
+ 			&handshake->entry);
+-	down_write(&handshake->lock);
+ 	handshake_zero(handshake);
+ 	up_write(&handshake->lock);
+-	wg_index_hashtable_remove(
+-			handshake->entry.peer->device->index_hashtable,
+-			&handshake->entry);
+ }
+ 
+ static struct noise_keypair *keypair_create(struct wg_peer *peer)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0115-wireguard-peerlookup-take-lock-before-checking-hash-.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0115-wireguard-peerlookup-take-lock-before-checking-hash-.patch
new file mode 100644
index 0000000..e7f46dd
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0115-wireguard-peerlookup-take-lock-before-checking-hash-.patch
@@ -0,0 +1,62 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Wed, 9 Sep 2020 13:58:15 +0200
+Subject: [PATCH] wireguard: peerlookup: take lock before checking hash in
+ replace operation
+
+commit 6147f7b1e90ff09bd52afc8b9206a7fcd133daf7 upstream.
+
+Eric's suggested fix for the previous commit's mentioned race condition
+was to simply take the table->lock in wg_index_hashtable_replace(). The
+table->lock of the hash table is supposed to protect the bucket heads,
+not the entires, but actually, since all the mutator functions are
+already taking it, it makes sense to take it too for the test to
+hlist_unhashed, as a defense in depth measure, so that it no longer
+races with deletions, regardless of what other locks are protecting
+individual entries. This is sensible from a performance perspective
+because, as Eric pointed out, the case of being unhashed is already the
+unlikely case, so this won't add common contention. And comparing
+instructions, this basically doesn't make much of a difference other
+than pushing and popping %r13, used by the new `bool ret`. More
+generally, I like the idea of locking consistency across table mutator
+functions, and this might let me rest slightly easier at night.
+
+Suggested-by: Eric Dumazet <edumazet@google.com>
+Link: https://lore.kernel.org/wireguard/20200908145911.4090480-1-edumazet@google.com/
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/peerlookup.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/wireguard/peerlookup.c
++++ b/drivers/net/wireguard/peerlookup.c
+@@ -167,9 +167,13 @@ bool wg_index_hashtable_replace(struct i
+ 				struct index_hashtable_entry *old,
+ 				struct index_hashtable_entry *new)
+ {
+-	if (unlikely(hlist_unhashed(&old->index_hash)))
+-		return false;
++	bool ret;
++
+ 	spin_lock_bh(&table->lock);
++	ret = !hlist_unhashed(&old->index_hash);
++	if (unlikely(!ret))
++		goto out;
++
+ 	new->index = old->index;
+ 	hlist_replace_rcu(&old->index_hash, &new->index_hash);
+ 
+@@ -180,8 +184,9 @@ bool wg_index_hashtable_replace(struct i
+ 	 * simply gets dropped, which isn't terrible.
+ 	 */
+ 	INIT_HLIST_NODE(&old->index_hash);
++out:
+ 	spin_unlock_bh(&table->lock);
+-	return true;
++	return ret;
+ }
+ 
+ void wg_index_hashtable_remove(struct index_hashtable *table,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0116-wireguard-selftests-check-that-route_me_harder-packe.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0116-wireguard-selftests-check-that-route_me_harder-packe.patch
new file mode 100644
index 0000000..09c1b0b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0116-wireguard-selftests-check-that-route_me_harder-packe.patch
@@ -0,0 +1,56 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Thu, 29 Oct 2020 03:56:05 +0100
+Subject: [PATCH] wireguard: selftests: check that route_me_harder packets use
+ the right sk
+
+commit af8afcf1fdd5f365f70e2386c2d8c7a1abd853d7 upstream.
+
+If netfilter changes the packet mark, the packet is rerouted. The
+ip_route_me_harder family of functions fails to use the right sk, opting
+to instead use skb->sk, resulting in a routing loop when used with
+tunnels. With the next change fixing this issue in netfilter, test for
+the relevant condition inside our test suite, since wireguard was where
+the bug was discovered.
+
+Reported-by: Chen Minqiang <ptpt52@gmail.com>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ tools/testing/selftests/wireguard/netns.sh           | 8 ++++++++
+ tools/testing/selftests/wireguard/qemu/kernel.config | 2 ++
+ 2 files changed, 10 insertions(+)
+
+--- a/tools/testing/selftests/wireguard/netns.sh
++++ b/tools/testing/selftests/wireguard/netns.sh
+@@ -316,6 +316,14 @@ pp sleep 3
+ n2 ping -W 1 -c 1 192.168.241.1
+ n1 wg set wg0 peer "$pub2" persistent-keepalive 0
+ 
++# Test that sk_bound_dev_if works
++n1 ping -I wg0 -c 1 -W 1 192.168.241.2
++# What about when the mark changes and the packet must be rerouted?
++n1 iptables -t mangle -I OUTPUT -j MARK --set-xmark 1
++n1 ping -c 1 -W 1 192.168.241.2 # First the boring case
++n1 ping -I wg0 -c 1 -W 1 192.168.241.2 # Then the sk_bound_dev_if case
++n1 iptables -t mangle -D OUTPUT -j MARK --set-xmark 1
++
+ # Test that onion routing works, even when it loops
+ n1 wg set wg0 peer "$pub3" allowed-ips 192.168.242.2/32 endpoint 192.168.241.2:5
+ ip1 addr add 192.168.242.1/24 dev wg0
+--- a/tools/testing/selftests/wireguard/qemu/kernel.config
++++ b/tools/testing/selftests/wireguard/qemu/kernel.config
+@@ -18,10 +18,12 @@ CONFIG_NF_NAT=y
+ CONFIG_NETFILTER_XTABLES=y
+ CONFIG_NETFILTER_XT_NAT=y
+ CONFIG_NETFILTER_XT_MATCH_LENGTH=y
++CONFIG_NETFILTER_XT_MARK=y
+ CONFIG_NF_CONNTRACK_IPV4=y
+ CONFIG_NF_NAT_IPV4=y
+ CONFIG_IP_NF_IPTABLES=y
+ CONFIG_IP_NF_FILTER=y
++CONFIG_IP_NF_MANGLE=y
+ CONFIG_IP_NF_NAT=y
+ CONFIG_IP_ADVANCED_ROUTER=y
+ CONFIG_IP_MULTIPLE_TABLES=y
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0117-wireguard-avoid-double-unlikely-notation-when-using-.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0117-wireguard-avoid-double-unlikely-notation-when-using-.patch
new file mode 100644
index 0000000..7dfc1bb
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0117-wireguard-avoid-double-unlikely-notation-when-using-.patch
@@ -0,0 +1,55 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Antonio Quartulli <a@unstable.cc>
+Date: Mon, 22 Feb 2021 17:25:43 +0100
+Subject: [PATCH] wireguard: avoid double unlikely() notation when using
+ IS_ERR()
+
+commit 30ac4e2f54ec067b7b9ca0db27e75681581378d6 upstream.
+
+The definition of IS_ERR() already applies the unlikely() notation
+when checking the error status of the passed pointer. For this
+reason there is no need to have the same notation outside of
+IS_ERR() itself.
+
+Clean up code by removing redundant notation.
+
+Signed-off-by: Antonio Quartulli <a@unstable.cc>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/device.c | 2 +-
+ drivers/net/wireguard/socket.c | 4 ++--
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/wireguard/device.c
++++ b/drivers/net/wireguard/device.c
+@@ -157,7 +157,7 @@ static netdev_tx_t wg_xmit(struct sk_buf
+ 	} else {
+ 		struct sk_buff *segs = skb_gso_segment(skb, 0);
+ 
+-		if (unlikely(IS_ERR(segs))) {
++		if (IS_ERR(segs)) {
+ 			ret = PTR_ERR(segs);
+ 			goto err_peer;
+ 		}
+--- a/drivers/net/wireguard/socket.c
++++ b/drivers/net/wireguard/socket.c
+@@ -71,7 +71,7 @@ static int send4(struct wg_device *wg, s
+ 				ip_rt_put(rt);
+ 			rt = ip_route_output_flow(sock_net(sock), &fl, sock);
+ 		}
+-		if (unlikely(IS_ERR(rt))) {
++		if (IS_ERR(rt)) {
+ 			ret = PTR_ERR(rt);
+ 			net_dbg_ratelimited("%s: No route to %pISpfsc, error %d\n",
+ 					    wg->dev->name, &endpoint->addr, ret);
+@@ -138,7 +138,7 @@ static int send6(struct wg_device *wg, s
+ 		}
+ 		dst = ipv6_stub->ipv6_dst_lookup_flow(sock_net(sock), sock, &fl,
+ 						      NULL);
+-		if (unlikely(IS_ERR(dst))) {
++		if (IS_ERR(dst)) {
+ 			ret = PTR_ERR(dst);
+ 			net_dbg_ratelimited("%s: No route to %pISpfsc, error %d\n",
+ 					    wg->dev->name, &endpoint->addr, ret);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0118-wireguard-socket-remove-bogus-__be32-annotation.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0118-wireguard-socket-remove-bogus-__be32-annotation.patch
new file mode 100644
index 0000000..1796f54
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0118-wireguard-socket-remove-bogus-__be32-annotation.patch
@@ -0,0 +1,52 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jann Horn <jannh@google.com>
+Date: Mon, 22 Feb 2021 17:25:44 +0100
+Subject: [PATCH] wireguard: socket: remove bogus __be32 annotation
+
+commit 7f57bd8dc22de35ddd895294aa554003e4f19a72 upstream.
+
+The endpoint->src_if4 has nothing to do with fixed-endian numbers; remove
+the bogus annotation.
+
+This was introduced in
+https://git.zx2c4.com/wireguard-monolithic-historical/commit?id=14e7d0a499a676ec55176c0de2f9fcbd34074a82
+in the historical WireGuard repo because the old code used to
+zero-initialize multiple members as follows:
+
+    endpoint->src4.s_addr = endpoint->src_if4 = fl.saddr = 0;
+
+Because fl.saddr is fixed-endian and an assignment returns a value with the
+type of its left operand, this meant that sparse detected an assignment
+between values of different endianness.
+
+Since then, this assignment was already split up into separate statements;
+just the cast survived.
+
+Signed-off-by: Jann Horn <jannh@google.com>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/socket.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/wireguard/socket.c
++++ b/drivers/net/wireguard/socket.c
+@@ -53,7 +53,7 @@ static int send4(struct wg_device *wg, s
+ 		if (unlikely(!inet_confirm_addr(sock_net(sock), NULL, 0,
+ 						fl.saddr, RT_SCOPE_HOST))) {
+ 			endpoint->src4.s_addr = 0;
+-			*(__force __be32 *)&endpoint->src_if4 = 0;
++			endpoint->src_if4 = 0;
+ 			fl.saddr = 0;
+ 			if (cache)
+ 				dst_cache_reset(cache);
+@@ -63,7 +63,7 @@ static int send4(struct wg_device *wg, s
+ 			     PTR_ERR(rt) == -EINVAL) || (!IS_ERR(rt) &&
+ 			     rt->dst.dev->ifindex != endpoint->src_if4)))) {
+ 			endpoint->src4.s_addr = 0;
+-			*(__force __be32 *)&endpoint->src_if4 = 0;
++			endpoint->src_if4 = 0;
+ 			fl.saddr = 0;
+ 			if (cache)
+ 				dst_cache_reset(cache);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0119-wireguard-selftests-test-multiple-parallel-streams.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0119-wireguard-selftests-test-multiple-parallel-streams.patch
new file mode 100644
index 0000000..3093de4
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0119-wireguard-selftests-test-multiple-parallel-streams.patch
@@ -0,0 +1,52 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Mon, 22 Feb 2021 17:25:45 +0100
+Subject: [PATCH] wireguard: selftests: test multiple parallel streams
+
+commit d5a49aa6c3e264a93a7d08485d66e346be0969dd upstream.
+
+In order to test ndo_start_xmit being called in parallel, explicitly add
+separate tests, which should all run on different cores. This should
+help tease out bugs associated with queueing up packets from different
+cores in parallel. Currently, it hasn't found those types of bugs, but
+given future planned work, this is a useful regression to avoid.
+
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ tools/testing/selftests/wireguard/netns.sh | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+--- a/tools/testing/selftests/wireguard/netns.sh
++++ b/tools/testing/selftests/wireguard/netns.sh
+@@ -39,7 +39,7 @@ ip0() { pretty 0 "ip $*"; ip -n $netns0
+ ip1() { pretty 1 "ip $*"; ip -n $netns1 "$@"; }
+ ip2() { pretty 2 "ip $*"; ip -n $netns2 "$@"; }
+ sleep() { read -t "$1" -N 1 || true; }
+-waitiperf() { pretty "${1//*-}" "wait for iperf:5201 pid $2"; while [[ $(ss -N "$1" -tlpH 'sport = 5201') != *\"iperf3\",pid=$2,fd=* ]]; do sleep 0.1; done; }
++waitiperf() { pretty "${1//*-}" "wait for iperf:${3:-5201} pid $2"; while [[ $(ss -N "$1" -tlpH "sport = ${3:-5201}") != *\"iperf3\",pid=$2,fd=* ]]; do sleep 0.1; done; }
+ waitncatudp() { pretty "${1//*-}" "wait for udp:1111 pid $2"; while [[ $(ss -N "$1" -ulpH 'sport = 1111') != *\"ncat\",pid=$2,fd=* ]]; do sleep 0.1; done; }
+ waitiface() { pretty "${1//*-}" "wait for $2 to come up"; ip netns exec "$1" bash -c "while [[ \$(< \"/sys/class/net/$2/operstate\") != up ]]; do read -t .1 -N 0 || true; done;"; }
+ 
+@@ -141,6 +141,19 @@ tests() {
+ 	n2 iperf3 -s -1 -B fd00::2 &
+ 	waitiperf $netns2 $!
+ 	n1 iperf3 -Z -t 3 -b 0 -u -c fd00::2
++
++	# TCP over IPv4, in parallel
++	for max in 4 5 50; do
++		local pids=( )
++		for ((i=0; i < max; ++i)) do
++			n2 iperf3 -p $(( 5200 + i )) -s -1 -B 192.168.241.2 &
++			pids+=( $! ); waitiperf $netns2 $! $(( 5200 + i ))
++		done
++		for ((i=0; i < max; ++i)) do
++			n1 iperf3 -Z -t 3 -p $(( 5200 + i )) -c 192.168.241.2 &
++		done
++		wait "${pids[@]}"
++	done
+ }
+ 
+ [[ $(ip1 link show dev wg0) =~ mtu\ ([0-9]+) ]] && orig_mtu="${BASH_REMATCH[1]}"
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0120-wireguard-peer-put-frequently-used-members-above-cac.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0120-wireguard-peer-put-frequently-used-members-above-cac.patch
new file mode 100644
index 0000000..69e76b9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0120-wireguard-peer-put-frequently-used-members-above-cac.patch
@@ -0,0 +1,42 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Mon, 22 Feb 2021 17:25:46 +0100
+Subject: [PATCH] wireguard: peer: put frequently used members above cache
+ lines
+
+commit 5a0598695634a6bb4126818902dd9140cd9df8b6 upstream.
+
+The is_dead boolean is checked for every single packet, while the
+internal_id member is used basically only for pr_debug messages. So it
+makes sense to hoist up is_dead into some space formerly unused by a
+struct hole, while demoting internal_api to below the lowest struct
+cache line.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/peer.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/wireguard/peer.h
++++ b/drivers/net/wireguard/peer.h
+@@ -39,6 +39,7 @@ struct wg_peer {
+ 	struct crypt_queue tx_queue, rx_queue;
+ 	struct sk_buff_head staged_packet_queue;
+ 	int serial_work_cpu;
++	bool is_dead;
+ 	struct noise_keypairs keypairs;
+ 	struct endpoint endpoint;
+ 	struct dst_cache endpoint_cache;
+@@ -61,9 +62,8 @@ struct wg_peer {
+ 	struct rcu_head rcu;
+ 	struct list_head peer_list;
+ 	struct list_head allowedips_list;
+-	u64 internal_id;
+ 	struct napi_struct napi;
+-	bool is_dead;
++	u64 internal_id;
+ };
+ 
+ struct wg_peer *wg_peer_create(struct wg_device *wg,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0121-wireguard-device-do-not-generate-ICMP-for-non-IP-pac.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0121-wireguard-device-do-not-generate-ICMP-for-non-IP-pac.patch
new file mode 100644
index 0000000..073ee9b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0121-wireguard-device-do-not-generate-ICMP-for-non-IP-pac.patch
@@ -0,0 +1,47 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Mon, 22 Feb 2021 17:25:47 +0100
+Subject: [PATCH] wireguard: device: do not generate ICMP for non-IP packets
+
+commit 99fff5264e7ab06f45b0ad60243475be0a8d0559 upstream.
+
+If skb->protocol doesn't match the actual skb->data header, it's
+probably not a good idea to pass it off to icmp{,v6}_ndo_send, which is
+expecting to reply to a valid IP packet. So this commit has that early
+mismatch case jump to a later error label.
+
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/device.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/wireguard/device.c
++++ b/drivers/net/wireguard/device.c
+@@ -138,7 +138,7 @@ static netdev_tx_t wg_xmit(struct sk_buf
+ 		else if (skb->protocol == htons(ETH_P_IPV6))
+ 			net_dbg_ratelimited("%s: No peer has allowed IPs matching %pI6\n",
+ 					    dev->name, &ipv6_hdr(skb)->daddr);
+-		goto err;
++		goto err_icmp;
+ 	}
+ 
+ 	family = READ_ONCE(peer->endpoint.addr.sa_family);
+@@ -201,12 +201,13 @@ static netdev_tx_t wg_xmit(struct sk_buf
+ 
+ err_peer:
+ 	wg_peer_put(peer);
+-err:
+-	++dev->stats.tx_errors;
++err_icmp:
+ 	if (skb->protocol == htons(ETH_P_IP))
+ 		icmp_ndo_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
+ 	else if (skb->protocol == htons(ETH_P_IPV6))
+ 		icmpv6_ndo_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0);
++err:
++	++dev->stats.tx_errors;
+ 	kfree_skb(skb);
+ 	return ret;
+ }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0122-wireguard-queueing-get-rid-of-per-peer-ring-buffers.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0122-wireguard-queueing-get-rid-of-per-peer-ring-buffers.patch
new file mode 100644
index 0000000..9dc7dda
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0122-wireguard-queueing-get-rid-of-per-peer-ring-buffers.patch
@@ -0,0 +1,560 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Mon, 22 Feb 2021 17:25:48 +0100
+Subject: [PATCH] wireguard: queueing: get rid of per-peer ring buffers
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit 8b5553ace83cced775eefd0f3f18b5c6214ccf7a upstream.
+
+Having two ring buffers per-peer means that every peer results in two
+massive ring allocations. On an 8-core x86_64 machine, this commit
+reduces the per-peer allocation from 18,688 bytes to 1,856 bytes, which
+is an 90% reduction. Ninety percent! With some single-machine
+deployments approaching 500,000 peers, we're talking about a reduction
+from 7 gigs of memory down to 700 megs of memory.
+
+In order to get rid of these per-peer allocations, this commit switches
+to using a list-based queueing approach. Currently GSO fragments are
+chained together using the skb->next pointer (the skb_list_* singly
+linked list approach), so we form the per-peer queue around the unused
+skb->prev pointer (which sort of makes sense because the links are
+pointing backwards). Use of skb_queue_* is not possible here, because
+that is based on doubly linked lists and spinlocks. Multiple cores can
+write into the queue at any given time, because its writes occur in the
+start_xmit path or in the udp_recv path. But reads happen in a single
+workqueue item per-peer, amounting to a multi-producer, single-consumer
+paradigm.
+
+The MPSC queue is implemented locklessly and never blocks. However, it
+is not linearizable (though it is serializable), with a very tight and
+unlikely race on writes, which, when hit (some tiny fraction of the
+0.15% of partial adds on a fully loaded 16-core x86_64 system), causes
+the queue reader to terminate early. However, because every packet sent
+queues up the same workqueue item after it is fully added, the worker
+resumes again, and stopping early isn't actually a problem, since at
+that point the packet wouldn't have yet been added to the encryption
+queue. These properties allow us to avoid disabling interrupts or
+spinning. The design is based on Dmitry Vyukov's algorithm [1].
+
+Performance-wise, ordinarily list-based queues aren't preferable to
+ringbuffers, because of cache misses when following pointers around.
+However, we *already* have to follow the adjacent pointers when working
+through fragments, so there shouldn't actually be any change there. A
+potential downside is that dequeueing is a bit more complicated, but the
+ptr_ring structure used prior had a spinlock when dequeueing, so all and
+all the difference appears to be a wash.
+
+Actually, from profiling, the biggest performance hit, by far, of this
+commit winds up being atomic_add_unless(count, 1, max) and atomic_
+dec(count), which account for the majority of CPU time, according to
+perf. In that sense, the previous ring buffer was superior in that it
+could check if it was full by head==tail, which the list-based approach
+cannot do.
+
+But all and all, this enables us to get massive memory savings, allowing
+WireGuard to scale for real world deployments, without taking much of a
+performance hit.
+
+[1] http://www.1024cores.net/home/lock-free-algorithms/queues/intrusive-mpsc-node-based-queue
+
+Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
+Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/device.c   | 12 ++---
+ drivers/net/wireguard/device.h   | 15 +++---
+ drivers/net/wireguard/peer.c     | 28 ++++-------
+ drivers/net/wireguard/peer.h     |  4 +-
+ drivers/net/wireguard/queueing.c | 86 +++++++++++++++++++++++++-------
+ drivers/net/wireguard/queueing.h | 45 ++++++++++++-----
+ drivers/net/wireguard/receive.c  | 16 +++---
+ drivers/net/wireguard/send.c     | 31 ++++--------
+ 8 files changed, 144 insertions(+), 93 deletions(-)
+
+--- a/drivers/net/wireguard/device.c
++++ b/drivers/net/wireguard/device.c
+@@ -235,8 +235,8 @@ static void wg_destruct(struct net_devic
+ 	destroy_workqueue(wg->handshake_receive_wq);
+ 	destroy_workqueue(wg->handshake_send_wq);
+ 	destroy_workqueue(wg->packet_crypt_wq);
+-	wg_packet_queue_free(&wg->decrypt_queue, true);
+-	wg_packet_queue_free(&wg->encrypt_queue, true);
++	wg_packet_queue_free(&wg->decrypt_queue);
++	wg_packet_queue_free(&wg->encrypt_queue);
+ 	rcu_barrier(); /* Wait for all the peers to be actually freed. */
+ 	wg_ratelimiter_uninit();
+ 	memzero_explicit(&wg->static_identity, sizeof(wg->static_identity));
+@@ -338,12 +338,12 @@ static int wg_newlink(struct net *src_ne
+ 		goto err_destroy_handshake_send;
+ 
+ 	ret = wg_packet_queue_init(&wg->encrypt_queue, wg_packet_encrypt_worker,
+-				   true, MAX_QUEUED_PACKETS);
++				   MAX_QUEUED_PACKETS);
+ 	if (ret < 0)
+ 		goto err_destroy_packet_crypt;
+ 
+ 	ret = wg_packet_queue_init(&wg->decrypt_queue, wg_packet_decrypt_worker,
+-				   true, MAX_QUEUED_PACKETS);
++				   MAX_QUEUED_PACKETS);
+ 	if (ret < 0)
+ 		goto err_free_encrypt_queue;
+ 
+@@ -368,9 +368,9 @@ static int wg_newlink(struct net *src_ne
+ err_uninit_ratelimiter:
+ 	wg_ratelimiter_uninit();
+ err_free_decrypt_queue:
+-	wg_packet_queue_free(&wg->decrypt_queue, true);
++	wg_packet_queue_free(&wg->decrypt_queue);
+ err_free_encrypt_queue:
+-	wg_packet_queue_free(&wg->encrypt_queue, true);
++	wg_packet_queue_free(&wg->encrypt_queue);
+ err_destroy_packet_crypt:
+ 	destroy_workqueue(wg->packet_crypt_wq);
+ err_destroy_handshake_send:
+--- a/drivers/net/wireguard/device.h
++++ b/drivers/net/wireguard/device.h
+@@ -27,13 +27,14 @@ struct multicore_worker {
+ 
+ struct crypt_queue {
+ 	struct ptr_ring ring;
+-	union {
+-		struct {
+-			struct multicore_worker __percpu *worker;
+-			int last_cpu;
+-		};
+-		struct work_struct work;
+-	};
++	struct multicore_worker __percpu *worker;
++	int last_cpu;
++};
++
++struct prev_queue {
++	struct sk_buff *head, *tail, *peeked;
++	struct { struct sk_buff *next, *prev; } empty; // Match first 2 members of struct sk_buff.
++	atomic_t count;
+ };
+ 
+ struct wg_device {
+--- a/drivers/net/wireguard/peer.c
++++ b/drivers/net/wireguard/peer.c
+@@ -32,27 +32,22 @@ struct wg_peer *wg_peer_create(struct wg
+ 	peer = kzalloc(sizeof(*peer), GFP_KERNEL);
+ 	if (unlikely(!peer))
+ 		return ERR_PTR(ret);
+-	peer->device = wg;
++	if (dst_cache_init(&peer->endpoint_cache, GFP_KERNEL))
++		goto err;
+ 
++	peer->device = wg;
+ 	wg_noise_handshake_init(&peer->handshake, &wg->static_identity,
+ 				public_key, preshared_key, peer);
+-	if (dst_cache_init(&peer->endpoint_cache, GFP_KERNEL))
+-		goto err_1;
+-	if (wg_packet_queue_init(&peer->tx_queue, wg_packet_tx_worker, false,
+-				 MAX_QUEUED_PACKETS))
+-		goto err_2;
+-	if (wg_packet_queue_init(&peer->rx_queue, NULL, false,
+-				 MAX_QUEUED_PACKETS))
+-		goto err_3;
+-
+ 	peer->internal_id = atomic64_inc_return(&peer_counter);
+ 	peer->serial_work_cpu = nr_cpumask_bits;
+ 	wg_cookie_init(&peer->latest_cookie);
+ 	wg_timers_init(peer);
+ 	wg_cookie_checker_precompute_peer_keys(peer);
+ 	spin_lock_init(&peer->keypairs.keypair_update_lock);
+-	INIT_WORK(&peer->transmit_handshake_work,
+-		  wg_packet_handshake_send_worker);
++	INIT_WORK(&peer->transmit_handshake_work, wg_packet_handshake_send_worker);
++	INIT_WORK(&peer->transmit_packet_work, wg_packet_tx_worker);
++	wg_prev_queue_init(&peer->tx_queue);
++	wg_prev_queue_init(&peer->rx_queue);
+ 	rwlock_init(&peer->endpoint_lock);
+ 	kref_init(&peer->refcount);
+ 	skb_queue_head_init(&peer->staged_packet_queue);
+@@ -68,11 +63,7 @@ struct wg_peer *wg_peer_create(struct wg
+ 	pr_debug("%s: Peer %llu created\n", wg->dev->name, peer->internal_id);
+ 	return peer;
+ 
+-err_3:
+-	wg_packet_queue_free(&peer->tx_queue, false);
+-err_2:
+-	dst_cache_destroy(&peer->endpoint_cache);
+-err_1:
++err:
+ 	kfree(peer);
+ 	return ERR_PTR(ret);
+ }
+@@ -197,8 +188,7 @@ static void rcu_release(struct rcu_head
+ 	struct wg_peer *peer = container_of(rcu, struct wg_peer, rcu);
+ 
+ 	dst_cache_destroy(&peer->endpoint_cache);
+-	wg_packet_queue_free(&peer->rx_queue, false);
+-	wg_packet_queue_free(&peer->tx_queue, false);
++	WARN_ON(wg_prev_queue_peek(&peer->tx_queue) || wg_prev_queue_peek(&peer->rx_queue));
+ 
+ 	/* The final zeroing takes care of clearing any remaining handshake key
+ 	 * material and other potentially sensitive information.
+--- a/drivers/net/wireguard/peer.h
++++ b/drivers/net/wireguard/peer.h
+@@ -36,7 +36,7 @@ struct endpoint {
+ 
+ struct wg_peer {
+ 	struct wg_device *device;
+-	struct crypt_queue tx_queue, rx_queue;
++	struct prev_queue tx_queue, rx_queue;
+ 	struct sk_buff_head staged_packet_queue;
+ 	int serial_work_cpu;
+ 	bool is_dead;
+@@ -46,7 +46,7 @@ struct wg_peer {
+ 	rwlock_t endpoint_lock;
+ 	struct noise_handshake handshake;
+ 	atomic64_t last_sent_handshake;
+-	struct work_struct transmit_handshake_work, clear_peer_work;
++	struct work_struct transmit_handshake_work, clear_peer_work, transmit_packet_work;
+ 	struct cookie latest_cookie;
+ 	struct hlist_node pubkey_hash;
+ 	u64 rx_bytes, tx_bytes;
+--- a/drivers/net/wireguard/queueing.c
++++ b/drivers/net/wireguard/queueing.c
+@@ -9,8 +9,7 @@ struct multicore_worker __percpu *
+ wg_packet_percpu_multicore_worker_alloc(work_func_t function, void *ptr)
+ {
+ 	int cpu;
+-	struct multicore_worker __percpu *worker =
+-		alloc_percpu(struct multicore_worker);
++	struct multicore_worker __percpu *worker = alloc_percpu(struct multicore_worker);
+ 
+ 	if (!worker)
+ 		return NULL;
+@@ -23,7 +22,7 @@ wg_packet_percpu_multicore_worker_alloc(
+ }
+ 
+ int wg_packet_queue_init(struct crypt_queue *queue, work_func_t function,
+-			 bool multicore, unsigned int len)
++			 unsigned int len)
+ {
+ 	int ret;
+ 
+@@ -31,25 +30,78 @@ int wg_packet_queue_init(struct crypt_qu
+ 	ret = ptr_ring_init(&queue->ring, len, GFP_KERNEL);
+ 	if (ret)
+ 		return ret;
+-	if (function) {
+-		if (multicore) {
+-			queue->worker = wg_packet_percpu_multicore_worker_alloc(
+-				function, queue);
+-			if (!queue->worker) {
+-				ptr_ring_cleanup(&queue->ring, NULL);
+-				return -ENOMEM;
+-			}
+-		} else {
+-			INIT_WORK(&queue->work, function);
+-		}
++	queue->worker = wg_packet_percpu_multicore_worker_alloc(function, queue);
++	if (!queue->worker) {
++		ptr_ring_cleanup(&queue->ring, NULL);
++		return -ENOMEM;
+ 	}
+ 	return 0;
+ }
+ 
+-void wg_packet_queue_free(struct crypt_queue *queue, bool multicore)
++void wg_packet_queue_free(struct crypt_queue *queue)
+ {
+-	if (multicore)
+-		free_percpu(queue->worker);
++	free_percpu(queue->worker);
+ 	WARN_ON(!__ptr_ring_empty(&queue->ring));
+ 	ptr_ring_cleanup(&queue->ring, NULL);
+ }
++
++#define NEXT(skb) ((skb)->prev)
++#define STUB(queue) ((struct sk_buff *)&queue->empty)
++
++void wg_prev_queue_init(struct prev_queue *queue)
++{
++	NEXT(STUB(queue)) = NULL;
++	queue->head = queue->tail = STUB(queue);
++	queue->peeked = NULL;
++	atomic_set(&queue->count, 0);
++	BUILD_BUG_ON(
++		offsetof(struct sk_buff, next) != offsetof(struct prev_queue, empty.next) -
++							offsetof(struct prev_queue, empty) ||
++		offsetof(struct sk_buff, prev) != offsetof(struct prev_queue, empty.prev) -
++							 offsetof(struct prev_queue, empty));
++}
++
++static void __wg_prev_queue_enqueue(struct prev_queue *queue, struct sk_buff *skb)
++{
++	WRITE_ONCE(NEXT(skb), NULL);
++	WRITE_ONCE(NEXT(xchg_release(&queue->head, skb)), skb);
++}
++
++bool wg_prev_queue_enqueue(struct prev_queue *queue, struct sk_buff *skb)
++{
++	if (!atomic_add_unless(&queue->count, 1, MAX_QUEUED_PACKETS))
++		return false;
++	__wg_prev_queue_enqueue(queue, skb);
++	return true;
++}
++
++struct sk_buff *wg_prev_queue_dequeue(struct prev_queue *queue)
++{
++	struct sk_buff *tail = queue->tail, *next = smp_load_acquire(&NEXT(tail));
++
++	if (tail == STUB(queue)) {
++		if (!next)
++			return NULL;
++		queue->tail = next;
++		tail = next;
++		next = smp_load_acquire(&NEXT(next));
++	}
++	if (next) {
++		queue->tail = next;
++		atomic_dec(&queue->count);
++		return tail;
++	}
++	if (tail != READ_ONCE(queue->head))
++		return NULL;
++	__wg_prev_queue_enqueue(queue, STUB(queue));
++	next = smp_load_acquire(&NEXT(tail));
++	if (next) {
++		queue->tail = next;
++		atomic_dec(&queue->count);
++		return tail;
++	}
++	return NULL;
++}
++
++#undef NEXT
++#undef STUB
+--- a/drivers/net/wireguard/queueing.h
++++ b/drivers/net/wireguard/queueing.h
+@@ -17,12 +17,13 @@ struct wg_device;
+ struct wg_peer;
+ struct multicore_worker;
+ struct crypt_queue;
++struct prev_queue;
+ struct sk_buff;
+ 
+ /* queueing.c APIs: */
+ int wg_packet_queue_init(struct crypt_queue *queue, work_func_t function,
+-			 bool multicore, unsigned int len);
+-void wg_packet_queue_free(struct crypt_queue *queue, bool multicore);
++			 unsigned int len);
++void wg_packet_queue_free(struct crypt_queue *queue);
+ struct multicore_worker __percpu *
+ wg_packet_percpu_multicore_worker_alloc(work_func_t function, void *ptr);
+ 
+@@ -135,8 +136,31 @@ static inline int wg_cpumask_next_online
+ 	return cpu;
+ }
+ 
++void wg_prev_queue_init(struct prev_queue *queue);
++
++/* Multi producer */
++bool wg_prev_queue_enqueue(struct prev_queue *queue, struct sk_buff *skb);
++
++/* Single consumer */
++struct sk_buff *wg_prev_queue_dequeue(struct prev_queue *queue);
++
++/* Single consumer */
++static inline struct sk_buff *wg_prev_queue_peek(struct prev_queue *queue)
++{
++	if (queue->peeked)
++		return queue->peeked;
++	queue->peeked = wg_prev_queue_dequeue(queue);
++	return queue->peeked;
++}
++
++/* Single consumer */
++static inline void wg_prev_queue_drop_peeked(struct prev_queue *queue)
++{
++	queue->peeked = NULL;
++}
++
+ static inline int wg_queue_enqueue_per_device_and_peer(
+-	struct crypt_queue *device_queue, struct crypt_queue *peer_queue,
++	struct crypt_queue *device_queue, struct prev_queue *peer_queue,
+ 	struct sk_buff *skb, struct workqueue_struct *wq, int *next_cpu)
+ {
+ 	int cpu;
+@@ -145,8 +169,9 @@ static inline int wg_queue_enqueue_per_d
+ 	/* We first queue this up for the peer ingestion, but the consumer
+ 	 * will wait for the state to change to CRYPTED or DEAD before.
+ 	 */
+-	if (unlikely(ptr_ring_produce_bh(&peer_queue->ring, skb)))
++	if (unlikely(!wg_prev_queue_enqueue(peer_queue, skb)))
+ 		return -ENOSPC;
++
+ 	/* Then we queue it up in the device queue, which consumes the
+ 	 * packet as soon as it can.
+ 	 */
+@@ -157,9 +182,7 @@ static inline int wg_queue_enqueue_per_d
+ 	return 0;
+ }
+ 
+-static inline void wg_queue_enqueue_per_peer(struct crypt_queue *queue,
+-					     struct sk_buff *skb,
+-					     enum packet_state state)
++static inline void wg_queue_enqueue_per_peer_tx(struct sk_buff *skb, enum packet_state state)
+ {
+ 	/* We take a reference, because as soon as we call atomic_set, the
+ 	 * peer can be freed from below us.
+@@ -167,14 +190,12 @@ static inline void wg_queue_enqueue_per_
+ 	struct wg_peer *peer = wg_peer_get(PACKET_PEER(skb));
+ 
+ 	atomic_set_release(&PACKET_CB(skb)->state, state);
+-	queue_work_on(wg_cpumask_choose_online(&peer->serial_work_cpu,
+-					       peer->internal_id),
+-		      peer->device->packet_crypt_wq, &queue->work);
++	queue_work_on(wg_cpumask_choose_online(&peer->serial_work_cpu, peer->internal_id),
++		      peer->device->packet_crypt_wq, &peer->transmit_packet_work);
+ 	wg_peer_put(peer);
+ }
+ 
+-static inline void wg_queue_enqueue_per_peer_napi(struct sk_buff *skb,
+-						  enum packet_state state)
++static inline void wg_queue_enqueue_per_peer_rx(struct sk_buff *skb, enum packet_state state)
+ {
+ 	/* We take a reference, because as soon as we call atomic_set, the
+ 	 * peer can be freed from below us.
+--- a/drivers/net/wireguard/receive.c
++++ b/drivers/net/wireguard/receive.c
+@@ -444,7 +444,6 @@ packet_processed:
+ int wg_packet_rx_poll(struct napi_struct *napi, int budget)
+ {
+ 	struct wg_peer *peer = container_of(napi, struct wg_peer, napi);
+-	struct crypt_queue *queue = &peer->rx_queue;
+ 	struct noise_keypair *keypair;
+ 	struct endpoint endpoint;
+ 	enum packet_state state;
+@@ -455,11 +454,10 @@ int wg_packet_rx_poll(struct napi_struct
+ 	if (unlikely(budget <= 0))
+ 		return 0;
+ 
+-	while ((skb = __ptr_ring_peek(&queue->ring)) != NULL &&
++	while ((skb = wg_prev_queue_peek(&peer->rx_queue)) != NULL &&
+ 	       (state = atomic_read_acquire(&PACKET_CB(skb)->state)) !=
+ 		       PACKET_STATE_UNCRYPTED) {
+-		__ptr_ring_discard_one(&queue->ring);
+-		peer = PACKET_PEER(skb);
++		wg_prev_queue_drop_peeked(&peer->rx_queue);
+ 		keypair = PACKET_CB(skb)->keypair;
+ 		free = true;
+ 
+@@ -508,7 +506,7 @@ void wg_packet_decrypt_worker(struct wor
+ 		enum packet_state state =
+ 			likely(decrypt_packet(skb, PACKET_CB(skb)->keypair)) ?
+ 				PACKET_STATE_CRYPTED : PACKET_STATE_DEAD;
+-		wg_queue_enqueue_per_peer_napi(skb, state);
++		wg_queue_enqueue_per_peer_rx(skb, state);
+ 		if (need_resched())
+ 			cond_resched();
+ 	}
+@@ -531,12 +529,10 @@ static void wg_packet_consume_data(struc
+ 	if (unlikely(READ_ONCE(peer->is_dead)))
+ 		goto err;
+ 
+-	ret = wg_queue_enqueue_per_device_and_peer(&wg->decrypt_queue,
+-						   &peer->rx_queue, skb,
+-						   wg->packet_crypt_wq,
+-						   &wg->decrypt_queue.last_cpu);
++	ret = wg_queue_enqueue_per_device_and_peer(&wg->decrypt_queue, &peer->rx_queue, skb,
++						   wg->packet_crypt_wq, &wg->decrypt_queue.last_cpu);
+ 	if (unlikely(ret == -EPIPE))
+-		wg_queue_enqueue_per_peer_napi(skb, PACKET_STATE_DEAD);
++		wg_queue_enqueue_per_peer_rx(skb, PACKET_STATE_DEAD);
+ 	if (likely(!ret || ret == -EPIPE)) {
+ 		rcu_read_unlock_bh();
+ 		return;
+--- a/drivers/net/wireguard/send.c
++++ b/drivers/net/wireguard/send.c
+@@ -239,8 +239,7 @@ void wg_packet_send_keepalive(struct wg_
+ 	wg_packet_send_staged_packets(peer);
+ }
+ 
+-static void wg_packet_create_data_done(struct sk_buff *first,
+-				       struct wg_peer *peer)
++static void wg_packet_create_data_done(struct wg_peer *peer, struct sk_buff *first)
+ {
+ 	struct sk_buff *skb, *next;
+ 	bool is_keepalive, data_sent = false;
+@@ -262,22 +261,19 @@ static void wg_packet_create_data_done(s
+ 
+ void wg_packet_tx_worker(struct work_struct *work)
+ {
+-	struct crypt_queue *queue = container_of(work, struct crypt_queue,
+-						 work);
++	struct wg_peer *peer = container_of(work, struct wg_peer, transmit_packet_work);
+ 	struct noise_keypair *keypair;
+ 	enum packet_state state;
+ 	struct sk_buff *first;
+-	struct wg_peer *peer;
+ 
+-	while ((first = __ptr_ring_peek(&queue->ring)) != NULL &&
++	while ((first = wg_prev_queue_peek(&peer->tx_queue)) != NULL &&
+ 	       (state = atomic_read_acquire(&PACKET_CB(first)->state)) !=
+ 		       PACKET_STATE_UNCRYPTED) {
+-		__ptr_ring_discard_one(&queue->ring);
+-		peer = PACKET_PEER(first);
++		wg_prev_queue_drop_peeked(&peer->tx_queue);
+ 		keypair = PACKET_CB(first)->keypair;
+ 
+ 		if (likely(state == PACKET_STATE_CRYPTED))
+-			wg_packet_create_data_done(first, peer);
++			wg_packet_create_data_done(peer, first);
+ 		else
+ 			kfree_skb_list(first);
+ 
+@@ -306,16 +302,14 @@ void wg_packet_encrypt_worker(struct wor
+ 				break;
+ 			}
+ 		}
+-		wg_queue_enqueue_per_peer(&PACKET_PEER(first)->tx_queue, first,
+-					  state);
++		wg_queue_enqueue_per_peer_tx(first, state);
+ 		if (need_resched())
+ 			cond_resched();
+ 	}
+ }
+ 
+-static void wg_packet_create_data(struct sk_buff *first)
++static void wg_packet_create_data(struct wg_peer *peer, struct sk_buff *first)
+ {
+-	struct wg_peer *peer = PACKET_PEER(first);
+ 	struct wg_device *wg = peer->device;
+ 	int ret = -EINVAL;
+ 
+@@ -323,13 +317,10 @@ static void wg_packet_create_data(struct
+ 	if (unlikely(READ_ONCE(peer->is_dead)))
+ 		goto err;
+ 
+-	ret = wg_queue_enqueue_per_device_and_peer(&wg->encrypt_queue,
+-						   &peer->tx_queue, first,
+-						   wg->packet_crypt_wq,
+-						   &wg->encrypt_queue.last_cpu);
++	ret = wg_queue_enqueue_per_device_and_peer(&wg->encrypt_queue, &peer->tx_queue, first,
++						   wg->packet_crypt_wq, &wg->encrypt_queue.last_cpu);
+ 	if (unlikely(ret == -EPIPE))
+-		wg_queue_enqueue_per_peer(&peer->tx_queue, first,
+-					  PACKET_STATE_DEAD);
++		wg_queue_enqueue_per_peer_tx(first, PACKET_STATE_DEAD);
+ err:
+ 	rcu_read_unlock_bh();
+ 	if (likely(!ret || ret == -EPIPE))
+@@ -393,7 +384,7 @@ void wg_packet_send_staged_packets(struc
+ 	packets.prev->next = NULL;
+ 	wg_peer_get(keypair->entry.peer);
+ 	PACKET_CB(packets.next)->keypair = keypair;
+-	wg_packet_create_data(packets.next);
++	wg_packet_create_data(peer, packets.next);
+ 	return;
+ 
+ out_invalid:
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0123-wireguard-kconfig-use-arm-chacha-even-with-no-neon.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0123-wireguard-kconfig-use-arm-chacha-even-with-no-neon.patch
new file mode 100644
index 0000000..9a25149
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0123-wireguard-kconfig-use-arm-chacha-even-with-no-neon.patch
@@ -0,0 +1,30 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Mon, 22 Feb 2021 17:25:49 +0100
+Subject: [PATCH] wireguard: kconfig: use arm chacha even with no neon
+
+commit bce2473927af8de12ad131a743f55d69d358c0b9 upstream.
+
+The condition here was incorrect: a non-neon fallback implementation is
+available on arm32 when NEON is not supported.
+
+Reported-by: Ilya Lipnitskiy <ilya.lipnitskiy@gmail.com>
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -87,7 +87,7 @@ config WIREGUARD
+ 	select CRYPTO_CURVE25519_X86 if X86 && 64BIT
+ 	select ARM_CRYPTO if ARM
+ 	select ARM64_CRYPTO if ARM64
+-	select CRYPTO_CHACHA20_NEON if (ARM || ARM64) && KERNEL_MODE_NEON
++	select CRYPTO_CHACHA20_NEON if ARM || (ARM64 && KERNEL_MODE_NEON)
+ 	select CRYPTO_POLY1305_NEON if ARM64 && KERNEL_MODE_NEON
+ 	select CRYPTO_POLY1305_ARM if ARM
+ 	select CRYPTO_CURVE25519_NEON if ARM && KERNEL_MODE_NEON
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0124-crypto-mips-poly1305-enable-for-all-MIPS-processors.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0124-crypto-mips-poly1305-enable-for-all-MIPS-processors.patch
new file mode 100644
index 0000000..c0ee841
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0124-crypto-mips-poly1305-enable-for-all-MIPS-processors.patch
@@ -0,0 +1,60 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Maciej W. Rozycki" <macro@orcam.me.uk>
+Date: Thu, 11 Mar 2021 21:50:47 -0700
+Subject: [PATCH] crypto: mips/poly1305 - enable for all MIPS processors
+
+commit 6c810cf20feef0d4338e9b424ab7f2644a8b353e upstream.
+
+The MIPS Poly1305 implementation is generic MIPS code written such as to
+support down to the original MIPS I and MIPS III ISA for the 32-bit and
+64-bit variant respectively.  Lift the current limitation then to enable
+code for MIPSr1 ISA or newer processors only and have it available for
+all MIPS processors.
+
+Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
+Fixes: a11d055e7a64 ("crypto: mips/poly1305 - incorporate OpenSSL/CRYPTOGAMS optimized implementation")
+Cc: stable@vger.kernel.org # v5.5+
+Acked-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/mips/crypto/Makefile | 4 ++--
+ crypto/Kconfig            | 2 +-
+ drivers/net/Kconfig       | 2 +-
+ 3 files changed, 4 insertions(+), 4 deletions(-)
+
+--- a/arch/mips/crypto/Makefile
++++ b/arch/mips/crypto/Makefile
+@@ -12,8 +12,8 @@ AFLAGS_chacha-core.o += -O2 # needed to
+ obj-$(CONFIG_CRYPTO_POLY1305_MIPS) += poly1305-mips.o
+ poly1305-mips-y := poly1305-core.o poly1305-glue.o
+ 
+-perlasm-flavour-$(CONFIG_CPU_MIPS32) := o32
+-perlasm-flavour-$(CONFIG_CPU_MIPS64) := 64
++perlasm-flavour-$(CONFIG_32BIT) := o32
++perlasm-flavour-$(CONFIG_64BIT) := 64
+ 
+ quiet_cmd_perlasm = PERLASM $@
+       cmd_perlasm = $(PERL) $(<) $(perlasm-flavour-y) $(@)
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -740,7 +740,7 @@ config CRYPTO_POLY1305_X86_64
+ 
+ config CRYPTO_POLY1305_MIPS
+ 	tristate "Poly1305 authenticator algorithm (MIPS optimized)"
+-	depends on CPU_MIPS32 || (CPU_MIPS64 && 64BIT)
++	depends on MIPS
+ 	select CRYPTO_ARCH_HAVE_LIB_POLY1305
+ 
+ config CRYPTO_MD4
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -92,7 +92,7 @@ config WIREGUARD
+ 	select CRYPTO_POLY1305_ARM if ARM
+ 	select CRYPTO_CURVE25519_NEON if ARM && KERNEL_MODE_NEON
+ 	select CRYPTO_CHACHA_MIPS if CPU_MIPS32_R2
+-	select CRYPTO_POLY1305_MIPS if CPU_MIPS32 || (CPU_MIPS64 && 64BIT)
++	select CRYPTO_POLY1305_MIPS if MIPS
+ 	help
+ 	  WireGuard is a secure, fast, and easy to use replacement for IPSec
+ 	  that uses modern cryptography and clever networking tricks. It's
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0125-crypto-mips-add-poly1305-core.S-to-.gitignore.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0125-crypto-mips-add-poly1305-core.S-to-.gitignore.patch
new file mode 100644
index 0000000..856d67d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0125-crypto-mips-add-poly1305-core.S-to-.gitignore.patch
@@ -0,0 +1,24 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ilya Lipnitskiy <ilya.lipnitskiy@gmail.com>
+Date: Sat, 27 Mar 2021 19:39:43 -0700
+Subject: [PATCH] crypto: mips: add poly1305-core.S to .gitignore
+
+commit dc92d0df51dc61de88bf6f4884a17bf73d5c6326 upstream.
+
+poly1305-core.S is an auto-generated file, so it should be ignored.
+
+Fixes: a11d055e7a64 ("crypto: mips/poly1305 - incorporate OpenSSL/CRYPTOGAMS optimized implementation")
+Signed-off-by: Ilya Lipnitskiy <ilya.lipnitskiy@gmail.com>
+Cc: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/mips/crypto/.gitignore | 2 ++
+ 1 file changed, 2 insertions(+)
+ create mode 100644 arch/mips/crypto/.gitignore
+
+--- /dev/null
++++ b/arch/mips/crypto/.gitignore
+@@ -0,0 +1,2 @@
++# SPDX-License-Identifier: GPL-2.0-only
++poly1305-core.S
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0126-crypto-poly1305-fix-poly1305_core_setkey-declaration.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0126-crypto-poly1305-fix-poly1305_core_setkey-declaration.patch
new file mode 100644
index 0000000..ded6625
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0126-crypto-poly1305-fix-poly1305_core_setkey-declaration.patch
@@ -0,0 +1,172 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Mon, 22 Mar 2021 18:05:15 +0100
+Subject: [PATCH] crypto: poly1305 - fix poly1305_core_setkey() declaration
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit 8d195e7a8ada68928f2aedb2c18302a4518fe68e upstream.
+
+gcc-11 points out a mismatch between the declaration and the definition
+of poly1305_core_setkey():
+
+lib/crypto/poly1305-donna32.c:13:67: error: argument 2 of type ‘const u8[16]’ {aka ‘const unsigned char[16]’} with mismatched bound [-Werror=array-parameter=]
+   13 | void poly1305_core_setkey(struct poly1305_core_key *key, const u8 raw_key[16])
+      |                                                          ~~~~~~~~~^~~~~~~~~~~
+In file included from lib/crypto/poly1305-donna32.c:11:
+include/crypto/internal/poly1305.h:21:68: note: previously declared as ‘const u8 *’ {aka ‘const unsigned char *’}
+   21 | void poly1305_core_setkey(struct poly1305_core_key *key, const u8 *raw_key);
+
+This is harmless in principle, as the calling conventions are the same,
+but the more specific prototype allows better type checking in the
+caller.
+
+Change the declaration to match the actual function definition.
+The poly1305_simd_init() is a bit suspicious here, as it previously
+had a 32-byte argument type, but looks like it needs to take the
+16-byte POLY1305_BLOCK_SIZE array instead.
+
+Fixes: 1c08a104360f ("crypto: poly1305 - add new 32 and 64-bit generic versions")
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
+Reviewed-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/arm/crypto/poly1305-glue.c    | 2 +-
+ arch/arm64/crypto/poly1305-glue.c  | 2 +-
+ arch/mips/crypto/poly1305-glue.c   | 2 +-
+ arch/x86/crypto/poly1305_glue.c    | 6 +++---
+ include/crypto/internal/poly1305.h | 3 ++-
+ include/crypto/poly1305.h          | 6 ++++--
+ lib/crypto/poly1305-donna32.c      | 3 ++-
+ lib/crypto/poly1305-donna64.c      | 3 ++-
+ lib/crypto/poly1305.c              | 3 ++-
+ 9 files changed, 18 insertions(+), 12 deletions(-)
+
+--- a/arch/arm/crypto/poly1305-glue.c
++++ b/arch/arm/crypto/poly1305-glue.c
+@@ -29,7 +29,7 @@ void __weak poly1305_blocks_neon(void *s
+ 
+ static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon);
+ 
+-void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key)
++void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 key[POLY1305_KEY_SIZE])
+ {
+ 	poly1305_init_arm(&dctx->h, key);
+ 	dctx->s[0] = get_unaligned_le32(key + 16);
+--- a/arch/arm64/crypto/poly1305-glue.c
++++ b/arch/arm64/crypto/poly1305-glue.c
+@@ -25,7 +25,7 @@ asmlinkage void poly1305_emit(void *stat
+ 
+ static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon);
+ 
+-void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key)
++void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 key[POLY1305_KEY_SIZE])
+ {
+ 	poly1305_init_arm64(&dctx->h, key);
+ 	dctx->s[0] = get_unaligned_le32(key + 16);
+--- a/arch/mips/crypto/poly1305-glue.c
++++ b/arch/mips/crypto/poly1305-glue.c
+@@ -17,7 +17,7 @@ asmlinkage void poly1305_init_mips(void
+ asmlinkage void poly1305_blocks_mips(void *state, const u8 *src, u32 len, u32 hibit);
+ asmlinkage void poly1305_emit_mips(void *state, u8 *digest, const u32 *nonce);
+ 
+-void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key)
++void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 key[POLY1305_KEY_SIZE])
+ {
+ 	poly1305_init_mips(&dctx->h, key);
+ 	dctx->s[0] = get_unaligned_le32(key + 16);
+--- a/arch/x86/crypto/poly1305_glue.c
++++ b/arch/x86/crypto/poly1305_glue.c
+@@ -15,7 +15,7 @@
+ #include <asm/simd.h>
+ 
+ asmlinkage void poly1305_init_x86_64(void *ctx,
+-				     const u8 key[POLY1305_KEY_SIZE]);
++				     const u8 key[POLY1305_BLOCK_SIZE]);
+ asmlinkage void poly1305_blocks_x86_64(void *ctx, const u8 *inp,
+ 				       const size_t len, const u32 padbit);
+ asmlinkage void poly1305_emit_x86_64(void *ctx, u8 mac[POLY1305_DIGEST_SIZE],
+@@ -80,7 +80,7 @@ static void convert_to_base2_64(void *ct
+ 	state->is_base2_26 = 0;
+ }
+ 
+-static void poly1305_simd_init(void *ctx, const u8 key[POLY1305_KEY_SIZE])
++static void poly1305_simd_init(void *ctx, const u8 key[POLY1305_BLOCK_SIZE])
+ {
+ 	poly1305_init_x86_64(ctx, key);
+ }
+@@ -128,7 +128,7 @@ static void poly1305_simd_emit(void *ctx
+ 		poly1305_emit_avx(ctx, mac, nonce);
+ }
+ 
+-void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key)
++void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 key[POLY1305_KEY_SIZE])
+ {
+ 	poly1305_simd_init(&dctx->h, key);
+ 	dctx->s[0] = get_unaligned_le32(&key[16]);
+--- a/include/crypto/internal/poly1305.h
++++ b/include/crypto/internal/poly1305.h
+@@ -18,7 +18,8 @@
+  * only the ε-almost-∆-universal hash function (not the full MAC) is computed.
+  */
+ 
+-void poly1305_core_setkey(struct poly1305_core_key *key, const u8 *raw_key);
++void poly1305_core_setkey(struct poly1305_core_key *key,
++			  const u8 raw_key[POLY1305_BLOCK_SIZE]);
+ static inline void poly1305_core_init(struct poly1305_state *state)
+ {
+ 	*state = (struct poly1305_state){};
+--- a/include/crypto/poly1305.h
++++ b/include/crypto/poly1305.h
+@@ -58,8 +58,10 @@ struct poly1305_desc_ctx {
+ 	};
+ };
+ 
+-void poly1305_init_arch(struct poly1305_desc_ctx *desc, const u8 *key);
+-void poly1305_init_generic(struct poly1305_desc_ctx *desc, const u8 *key);
++void poly1305_init_arch(struct poly1305_desc_ctx *desc,
++			const u8 key[POLY1305_KEY_SIZE]);
++void poly1305_init_generic(struct poly1305_desc_ctx *desc,
++			   const u8 key[POLY1305_KEY_SIZE]);
+ 
+ static inline void poly1305_init(struct poly1305_desc_ctx *desc, const u8 *key)
+ {
+--- a/lib/crypto/poly1305-donna32.c
++++ b/lib/crypto/poly1305-donna32.c
+@@ -10,7 +10,8 @@
+ #include <asm/unaligned.h>
+ #include <crypto/internal/poly1305.h>
+ 
+-void poly1305_core_setkey(struct poly1305_core_key *key, const u8 raw_key[16])
++void poly1305_core_setkey(struct poly1305_core_key *key,
++			  const u8 raw_key[POLY1305_BLOCK_SIZE])
+ {
+ 	/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
+ 	key->key.r[0] = (get_unaligned_le32(&raw_key[0])) & 0x3ffffff;
+--- a/lib/crypto/poly1305-donna64.c
++++ b/lib/crypto/poly1305-donna64.c
+@@ -12,7 +12,8 @@
+ 
+ typedef __uint128_t u128;
+ 
+-void poly1305_core_setkey(struct poly1305_core_key *key, const u8 raw_key[16])
++void poly1305_core_setkey(struct poly1305_core_key *key,
++			  const u8 raw_key[POLY1305_BLOCK_SIZE])
+ {
+ 	u64 t0, t1;
+ 
+--- a/lib/crypto/poly1305.c
++++ b/lib/crypto/poly1305.c
+@@ -12,7 +12,8 @@
+ #include <linux/module.h>
+ #include <asm/unaligned.h>
+ 
+-void poly1305_init_generic(struct poly1305_desc_ctx *desc, const u8 *key)
++void poly1305_init_generic(struct poly1305_desc_ctx *desc,
++			   const u8 key[POLY1305_KEY_SIZE])
+ {
+ 	poly1305_core_setkey(&desc->core_r, key);
+ 	desc->s[0] = get_unaligned_le32(key + 16);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0127-wireguard-selftests-remove-old-conntrack-kconfig-val.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0127-wireguard-selftests-remove-old-conntrack-kconfig-val.patch
new file mode 100644
index 0000000..3e7d1a8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0127-wireguard-selftests-remove-old-conntrack-kconfig-val.patch
@@ -0,0 +1,29 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 4 Jun 2021 17:17:30 +0200
+Subject: [PATCH] wireguard: selftests: remove old conntrack kconfig value
+
+commit acf2492b51c9a3c4dfb947f4d3477a86d315150f upstream.
+
+On recent kernels, this config symbol is no longer used.
+
+Reported-by: Rui Salvaterra <rsalvaterra@gmail.com>
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Cc: stable@vger.kernel.org
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ tools/testing/selftests/wireguard/qemu/kernel.config | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/tools/testing/selftests/wireguard/qemu/kernel.config
++++ b/tools/testing/selftests/wireguard/qemu/kernel.config
+@@ -19,7 +19,6 @@ CONFIG_NETFILTER_XTABLES=y
+ CONFIG_NETFILTER_XT_NAT=y
+ CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+ CONFIG_NETFILTER_XT_MARK=y
+-CONFIG_NF_CONNTRACK_IPV4=y
+ CONFIG_NF_NAT_IPV4=y
+ CONFIG_IP_NF_IPTABLES=y
+ CONFIG_IP_NF_FILTER=y
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0128-wireguard-selftests-make-sure-rp_filter-is-disabled-.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0128-wireguard-selftests-make-sure-rp_filter-is-disabled-.patch
new file mode 100644
index 0000000..22d0f3e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0128-wireguard-selftests-make-sure-rp_filter-is-disabled-.patch
@@ -0,0 +1,31 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 4 Jun 2021 17:17:31 +0200
+Subject: [PATCH] wireguard: selftests: make sure rp_filter is disabled on
+ vethc
+
+commit f8873d11d4121aad35024f9379e431e0c83abead upstream.
+
+Some distros may enable strict rp_filter by default, which will prevent
+vethc from receiving the packets with an unrouteable reverse path address.
+
+Reported-by: Hangbin Liu <liuhangbin@gmail.com>
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Cc: stable@vger.kernel.org
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ tools/testing/selftests/wireguard/netns.sh | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/tools/testing/selftests/wireguard/netns.sh
++++ b/tools/testing/selftests/wireguard/netns.sh
+@@ -363,6 +363,7 @@ ip1 -6 rule add table main suppress_pref
+ ip1 -4 route add default dev wg0 table 51820
+ ip1 -4 rule add not fwmark 51820 table 51820
+ ip1 -4 rule add table main suppress_prefixlength 0
++n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/vethc/rp_filter'
+ # Flood the pings instead of sending just one, to trigger routing table reference counting bugs.
+ n1 ping -W 1 -c 100 -f 192.168.99.7
+ n1 ping -W 1 -c 100 -f abab::1111
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0129-wireguard-do-not-use-O3.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0129-wireguard-do-not-use-O3.patch
new file mode 100644
index 0000000..a7890a7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0129-wireguard-do-not-use-O3.patch
@@ -0,0 +1,33 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 4 Jun 2021 17:17:32 +0200
+Subject: [PATCH] wireguard: do not use -O3
+
+commit cc5060ca0285efe2728bced399a1955a7ce808b2 upstream.
+
+Apparently, various versions of gcc have O3-related miscompiles. Looking
+at the difference between -O2 and -O3 for gcc 11 doesn't indicate
+miscompiles, but the difference also doesn't seem so significant for
+performance that it's worth risking.
+
+Link: https://lore.kernel.org/lkml/CAHk-=wjuoGyxDhAF8SsrTkN0-YfCx7E6jUN3ikC_tn2AKWTTsA@mail.gmail.com/
+Link: https://lore.kernel.org/lkml/CAHmME9otB5Wwxp7H8bR_i2uH2esEMvoBMC8uEXBMH9p0q1s6Bw@mail.gmail.com/
+Reported-by: Linus Torvalds <torvalds@linux-foundation.org>
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Cc: stable@vger.kernel.org
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/Makefile | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/net/wireguard/Makefile
++++ b/drivers/net/wireguard/Makefile
+@@ -1,5 +1,4 @@
+-ccflags-y := -O3
+-ccflags-y += -D'pr_fmt(fmt)=KBUILD_MODNAME ": " fmt'
++ccflags-y := -D'pr_fmt(fmt)=KBUILD_MODNAME ": " fmt'
+ ccflags-$(CONFIG_WIREGUARD_DEBUG) += -DDEBUG
+ wireguard-y := main.o
+ wireguard-y += noise.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0130-wireguard-use-synchronize_net-rather-than-synchroniz.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0130-wireguard-use-synchronize_net-rather-than-synchroniz.patch
new file mode 100644
index 0000000..309fe36
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0130-wireguard-use-synchronize_net-rather-than-synchroniz.patch
@@ -0,0 +1,66 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 4 Jun 2021 17:17:33 +0200
+Subject: [PATCH] wireguard: use synchronize_net rather than synchronize_rcu
+
+commit 24b70eeeb4f46c09487f8155239ebfb1f875774a upstream.
+
+Many of the synchronization points are sometimes called under the rtnl
+lock, which means we should use synchronize_net rather than
+synchronize_rcu. Under the hood, this expands to using the expedited
+flavor of function in the event that rtnl is held, in order to not stall
+other concurrent changes.
+
+This fixes some very, very long delays when removing multiple peers at
+once, which would cause some operations to take several minutes.
+
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Cc: stable@vger.kernel.org
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/peer.c   | 6 +++---
+ drivers/net/wireguard/socket.c | 2 +-
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/wireguard/peer.c
++++ b/drivers/net/wireguard/peer.c
+@@ -88,7 +88,7 @@ static void peer_make_dead(struct wg_pee
+ 	/* Mark as dead, so that we don't allow jumping contexts after. */
+ 	WRITE_ONCE(peer->is_dead, true);
+ 
+-	/* The caller must now synchronize_rcu() for this to take effect. */
++	/* The caller must now synchronize_net() for this to take effect. */
+ }
+ 
+ static void peer_remove_after_dead(struct wg_peer *peer)
+@@ -160,7 +160,7 @@ void wg_peer_remove(struct wg_peer *peer
+ 	lockdep_assert_held(&peer->device->device_update_lock);
+ 
+ 	peer_make_dead(peer);
+-	synchronize_rcu();
++	synchronize_net();
+ 	peer_remove_after_dead(peer);
+ }
+ 
+@@ -178,7 +178,7 @@ void wg_peer_remove_all(struct wg_device
+ 		peer_make_dead(peer);
+ 		list_add_tail(&peer->peer_list, &dead_peers);
+ 	}
+-	synchronize_rcu();
++	synchronize_net();
+ 	list_for_each_entry_safe(peer, temp, &dead_peers, peer_list)
+ 		peer_remove_after_dead(peer);
+ }
+--- a/drivers/net/wireguard/socket.c
++++ b/drivers/net/wireguard/socket.c
+@@ -430,7 +430,7 @@ void wg_socket_reinit(struct wg_device *
+ 	if (new4)
+ 		wg->incoming_port = ntohs(inet_sk(new4)->inet_sport);
+ 	mutex_unlock(&wg->socket_update_lock);
+-	synchronize_rcu();
++	synchronize_net();
+ 	sock_free(old4);
+ 	sock_free(old6);
+ }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0131-wireguard-peer-allocate-in-kmem_cache.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0131-wireguard-peer-allocate-in-kmem_cache.patch
new file mode 100644
index 0000000..32ae327
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0131-wireguard-peer-allocate-in-kmem_cache.patch
@@ -0,0 +1,125 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 4 Jun 2021 17:17:34 +0200
+Subject: [PATCH] wireguard: peer: allocate in kmem_cache
+
+commit a4e9f8e3287c9eb6bf70df982870980dd3341863 upstream.
+
+With deployments having upwards of 600k peers now, this somewhat heavy
+structure could benefit from more fine-grained allocations.
+Specifically, instead of using a 2048-byte slab for a 1544-byte object,
+we can now use 1544-byte objects directly, thus saving almost 25%
+per-peer, or with 600k peers, that's a savings of 303 MiB. This also
+makes wireguard's memory usage more transparent in tools like slabtop
+and /proc/slabinfo.
+
+Fixes: 8b5553ace83c ("wireguard: queueing: get rid of per-peer ring buffers")
+Suggested-by: Arnd Bergmann <arnd@arndb.de>
+Suggested-by: Matthew Wilcox <willy@infradead.org>
+Cc: stable@vger.kernel.org
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/main.c |  7 +++++++
+ drivers/net/wireguard/peer.c | 21 +++++++++++++++++----
+ drivers/net/wireguard/peer.h |  3 +++
+ 3 files changed, 27 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/wireguard/main.c
++++ b/drivers/net/wireguard/main.c
+@@ -28,6 +28,10 @@ static int __init mod_init(void)
+ #endif
+ 	wg_noise_init();
+ 
++	ret = wg_peer_init();
++	if (ret < 0)
++		goto err_peer;
++
+ 	ret = wg_device_init();
+ 	if (ret < 0)
+ 		goto err_device;
+@@ -44,6 +48,8 @@ static int __init mod_init(void)
+ err_netlink:
+ 	wg_device_uninit();
+ err_device:
++	wg_peer_uninit();
++err_peer:
+ 	return ret;
+ }
+ 
+@@ -51,6 +57,7 @@ static void __exit mod_exit(void)
+ {
+ 	wg_genetlink_uninit();
+ 	wg_device_uninit();
++	wg_peer_uninit();
+ }
+ 
+ module_init(mod_init);
+--- a/drivers/net/wireguard/peer.c
++++ b/drivers/net/wireguard/peer.c
+@@ -15,6 +15,7 @@
+ #include <linux/rcupdate.h>
+ #include <linux/list.h>
+ 
++static struct kmem_cache *peer_cache;
+ static atomic64_t peer_counter = ATOMIC64_INIT(0);
+ 
+ struct wg_peer *wg_peer_create(struct wg_device *wg,
+@@ -29,10 +30,10 @@ struct wg_peer *wg_peer_create(struct wg
+ 	if (wg->num_peers >= MAX_PEERS_PER_DEVICE)
+ 		return ERR_PTR(ret);
+ 
+-	peer = kzalloc(sizeof(*peer), GFP_KERNEL);
++	peer = kmem_cache_zalloc(peer_cache, GFP_KERNEL);
+ 	if (unlikely(!peer))
+ 		return ERR_PTR(ret);
+-	if (dst_cache_init(&peer->endpoint_cache, GFP_KERNEL))
++	if (unlikely(dst_cache_init(&peer->endpoint_cache, GFP_KERNEL)))
+ 		goto err;
+ 
+ 	peer->device = wg;
+@@ -64,7 +65,7 @@ struct wg_peer *wg_peer_create(struct wg
+ 	return peer;
+ 
+ err:
+-	kfree(peer);
++	kmem_cache_free(peer_cache, peer);
+ 	return ERR_PTR(ret);
+ }
+ 
+@@ -193,7 +194,8 @@ static void rcu_release(struct rcu_head
+ 	/* The final zeroing takes care of clearing any remaining handshake key
+ 	 * material and other potentially sensitive information.
+ 	 */
+-	kzfree(peer);
++	memzero_explicit(peer, sizeof(*peer));
++	kmem_cache_free(peer_cache, peer);
+ }
+ 
+ static void kref_release(struct kref *refcount)
+@@ -225,3 +227,14 @@ void wg_peer_put(struct wg_peer *peer)
+ 		return;
+ 	kref_put(&peer->refcount, kref_release);
+ }
++
++int __init wg_peer_init(void)
++{
++	peer_cache = KMEM_CACHE(wg_peer, 0);
++	return peer_cache ? 0 : -ENOMEM;
++}
++
++void wg_peer_uninit(void)
++{
++	kmem_cache_destroy(peer_cache);
++}
+--- a/drivers/net/wireguard/peer.h
++++ b/drivers/net/wireguard/peer.h
+@@ -80,4 +80,7 @@ void wg_peer_put(struct wg_peer *peer);
+ void wg_peer_remove(struct wg_peer *peer);
+ void wg_peer_remove_all(struct wg_device *wg);
+ 
++int wg_peer_init(void);
++void wg_peer_uninit(void);
++
+ #endif /* _WG_PEER_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0132-wireguard-allowedips-initialize-list-head-in-selftes.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0132-wireguard-allowedips-initialize-list-head-in-selftes.patch
new file mode 100644
index 0000000..ce4e5dc
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0132-wireguard-allowedips-initialize-list-head-in-selftes.patch
@@ -0,0 +1,43 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 4 Jun 2021 17:17:35 +0200
+Subject: [PATCH] wireguard: allowedips: initialize list head in selftest
+
+commit 46cfe8eee285cde465b420637507884551f5d7ca upstream.
+
+The randomized trie tests weren't initializing the dummy peer list head,
+resulting in a NULL pointer dereference when used. Fix this by
+initializing it in the randomized trie test, just like we do for the
+static unit test.
+
+While we're at it, all of the other strings like this have the word
+"self-test", so add it to the missing place here.
+
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Cc: stable@vger.kernel.org
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/selftest/allowedips.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/wireguard/selftest/allowedips.c
++++ b/drivers/net/wireguard/selftest/allowedips.c
+@@ -296,6 +296,7 @@ static __init bool randomized_test(void)
+ 			goto free;
+ 		}
+ 		kref_init(&peers[i]->refcount);
++		INIT_LIST_HEAD(&peers[i]->allowedips_list);
+ 	}
+ 
+ 	mutex_lock(&mutex);
+@@ -333,7 +334,7 @@ static __init bool randomized_test(void)
+ 			if (wg_allowedips_insert_v4(&t,
+ 						    (struct in_addr *)mutated,
+ 						    cidr, peer, &mutex) < 0) {
+-				pr_err("allowedips random malloc: FAIL\n");
++				pr_err("allowedips random self-test malloc: FAIL\n");
+ 				goto free_locked;
+ 			}
+ 			if (horrible_allowedips_insert_v4(&h,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0133-wireguard-allowedips-remove-nodes-in-O-1.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0133-wireguard-allowedips-remove-nodes-in-O-1.patch
new file mode 100644
index 0000000..78da24e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0133-wireguard-allowedips-remove-nodes-in-O-1.patch
@@ -0,0 +1,237 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 4 Jun 2021 17:17:36 +0200
+Subject: [PATCH] wireguard: allowedips: remove nodes in O(1)
+
+commit f634f418c227c912e7ea95a3299efdc9b10e4022 upstream.
+
+Previously, deleting peers would require traversing the entire trie in
+order to rebalance nodes and safely free them. This meant that removing
+1000 peers from a trie with a half million nodes would take an extremely
+long time, during which we're holding the rtnl lock. Large-scale users
+were reporting 200ms latencies added to the networking stack as a whole
+every time their userspace software would queue up significant removals.
+That's a serious situation.
+
+This commit fixes that by maintaining a double pointer to the parent's
+bit pointer for each node, and then using the already existing node list
+belonging to each peer to go directly to the node, fix up its pointers,
+and free it with RCU. This means removal is O(1) instead of O(n), and we
+don't use gobs of stack.
+
+The removal algorithm has the same downside as the code that it fixes:
+it won't collapse needlessly long runs of fillers.  We can enhance that
+in the future if it ever becomes a problem. This commit documents that
+limitation with a TODO comment in code, a small but meaningful
+improvement over the prior situation.
+
+Currently the biggest flaw, which the next commit addresses, is that
+because this increases the node size on 64-bit machines from 60 bytes to
+68 bytes. 60 rounds up to 64, but 68 rounds up to 128. So we wind up
+using twice as much memory per node, because of power-of-two
+allocations, which is a big bummer. We'll need to figure something out
+there.
+
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Cc: stable@vger.kernel.org
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/allowedips.c | 132 ++++++++++++-----------------
+ drivers/net/wireguard/allowedips.h |   9 +-
+ 2 files changed, 57 insertions(+), 84 deletions(-)
+
+--- a/drivers/net/wireguard/allowedips.c
++++ b/drivers/net/wireguard/allowedips.c
+@@ -66,60 +66,6 @@ static void root_remove_peer_lists(struc
+ 	}
+ }
+ 
+-static void walk_remove_by_peer(struct allowedips_node __rcu **top,
+-				struct wg_peer *peer, struct mutex *lock)
+-{
+-#define REF(p) rcu_access_pointer(p)
+-#define DEREF(p) rcu_dereference_protected(*(p), lockdep_is_held(lock))
+-#define PUSH(p) ({                                                             \
+-		WARN_ON(IS_ENABLED(DEBUG) && len >= 128);                      \
+-		stack[len++] = p;                                              \
+-	})
+-
+-	struct allowedips_node __rcu **stack[128], **nptr;
+-	struct allowedips_node *node, *prev;
+-	unsigned int len;
+-
+-	if (unlikely(!peer || !REF(*top)))
+-		return;
+-
+-	for (prev = NULL, len = 0, PUSH(top); len > 0; prev = node) {
+-		nptr = stack[len - 1];
+-		node = DEREF(nptr);
+-		if (!node) {
+-			--len;
+-			continue;
+-		}
+-		if (!prev || REF(prev->bit[0]) == node ||
+-		    REF(prev->bit[1]) == node) {
+-			if (REF(node->bit[0]))
+-				PUSH(&node->bit[0]);
+-			else if (REF(node->bit[1]))
+-				PUSH(&node->bit[1]);
+-		} else if (REF(node->bit[0]) == prev) {
+-			if (REF(node->bit[1]))
+-				PUSH(&node->bit[1]);
+-		} else {
+-			if (rcu_dereference_protected(node->peer,
+-				lockdep_is_held(lock)) == peer) {
+-				RCU_INIT_POINTER(node->peer, NULL);
+-				list_del_init(&node->peer_list);
+-				if (!node->bit[0] || !node->bit[1]) {
+-					rcu_assign_pointer(*nptr, DEREF(
+-					       &node->bit[!REF(node->bit[0])]));
+-					kfree_rcu(node, rcu);
+-					node = DEREF(nptr);
+-				}
+-			}
+-			--len;
+-		}
+-	}
+-
+-#undef REF
+-#undef DEREF
+-#undef PUSH
+-}
+-
+ static unsigned int fls128(u64 a, u64 b)
+ {
+ 	return a ? fls64(a) + 64U : fls64(b);
+@@ -224,6 +170,7 @@ static int add(struct allowedips_node __
+ 		RCU_INIT_POINTER(node->peer, peer);
+ 		list_add_tail(&node->peer_list, &peer->allowedips_list);
+ 		copy_and_assign_cidr(node, key, cidr, bits);
++		rcu_assign_pointer(node->parent_bit, trie);
+ 		rcu_assign_pointer(*trie, node);
+ 		return 0;
+ 	}
+@@ -243,9 +190,9 @@ static int add(struct allowedips_node __
+ 	if (!node) {
+ 		down = rcu_dereference_protected(*trie, lockdep_is_held(lock));
+ 	} else {
+-		down = rcu_dereference_protected(CHOOSE_NODE(node, key),
+-						 lockdep_is_held(lock));
++		down = rcu_dereference_protected(CHOOSE_NODE(node, key), lockdep_is_held(lock));
+ 		if (!down) {
++			rcu_assign_pointer(newnode->parent_bit, &CHOOSE_NODE(node, key));
+ 			rcu_assign_pointer(CHOOSE_NODE(node, key), newnode);
+ 			return 0;
+ 		}
+@@ -254,29 +201,37 @@ static int add(struct allowedips_node __
+ 	parent = node;
+ 
+ 	if (newnode->cidr == cidr) {
++		rcu_assign_pointer(down->parent_bit, &CHOOSE_NODE(newnode, down->bits));
+ 		rcu_assign_pointer(CHOOSE_NODE(newnode, down->bits), down);
+-		if (!parent)
++		if (!parent) {
++			rcu_assign_pointer(newnode->parent_bit, trie);
+ 			rcu_assign_pointer(*trie, newnode);
+-		else
+-			rcu_assign_pointer(CHOOSE_NODE(parent, newnode->bits),
+-					   newnode);
+-	} else {
+-		node = kzalloc(sizeof(*node), GFP_KERNEL);
+-		if (unlikely(!node)) {
+-			list_del(&newnode->peer_list);
+-			kfree(newnode);
+-			return -ENOMEM;
++		} else {
++			rcu_assign_pointer(newnode->parent_bit, &CHOOSE_NODE(parent, newnode->bits));
++			rcu_assign_pointer(CHOOSE_NODE(parent, newnode->bits), newnode);
+ 		}
+-		INIT_LIST_HEAD(&node->peer_list);
+-		copy_and_assign_cidr(node, newnode->bits, cidr, bits);
++		return 0;
++	}
++
++	node = kzalloc(sizeof(*node), GFP_KERNEL);
++	if (unlikely(!node)) {
++		list_del(&newnode->peer_list);
++		kfree(newnode);
++		return -ENOMEM;
++	}
++	INIT_LIST_HEAD(&node->peer_list);
++	copy_and_assign_cidr(node, newnode->bits, cidr, bits);
+ 
+-		rcu_assign_pointer(CHOOSE_NODE(node, down->bits), down);
+-		rcu_assign_pointer(CHOOSE_NODE(node, newnode->bits), newnode);
+-		if (!parent)
+-			rcu_assign_pointer(*trie, node);
+-		else
+-			rcu_assign_pointer(CHOOSE_NODE(parent, node->bits),
+-					   node);
++	rcu_assign_pointer(down->parent_bit, &CHOOSE_NODE(node, down->bits));
++	rcu_assign_pointer(CHOOSE_NODE(node, down->bits), down);
++	rcu_assign_pointer(newnode->parent_bit, &CHOOSE_NODE(node, newnode->bits));
++	rcu_assign_pointer(CHOOSE_NODE(node, newnode->bits), newnode);
++	if (!parent) {
++		rcu_assign_pointer(node->parent_bit, trie);
++		rcu_assign_pointer(*trie, node);
++	} else {
++		rcu_assign_pointer(node->parent_bit, &CHOOSE_NODE(parent, node->bits));
++		rcu_assign_pointer(CHOOSE_NODE(parent, node->bits), node);
+ 	}
+ 	return 0;
+ }
+@@ -335,9 +290,30 @@ int wg_allowedips_insert_v6(struct allow
+ void wg_allowedips_remove_by_peer(struct allowedips *table,
+ 				  struct wg_peer *peer, struct mutex *lock)
+ {
++	struct allowedips_node *node, *child, *tmp;
++
++	if (list_empty(&peer->allowedips_list))
++		return;
+ 	++table->seq;
+-	walk_remove_by_peer(&table->root4, peer, lock);
+-	walk_remove_by_peer(&table->root6, peer, lock);
++	list_for_each_entry_safe(node, tmp, &peer->allowedips_list, peer_list) {
++		list_del_init(&node->peer_list);
++		RCU_INIT_POINTER(node->peer, NULL);
++		if (node->bit[0] && node->bit[1])
++			continue;
++		child = rcu_dereference_protected(
++				node->bit[!rcu_access_pointer(node->bit[0])],
++				lockdep_is_held(lock));
++		if (child)
++			child->parent_bit = node->parent_bit;
++		*rcu_dereference_protected(node->parent_bit, lockdep_is_held(lock)) = child;
++		kfree_rcu(node, rcu);
++
++		/* TODO: Note that we currently don't walk up and down in order to
++		 * free any potential filler nodes. This means that this function
++		 * doesn't free up as much as it could, which could be revisited
++		 * at some point.
++		 */
++	}
+ }
+ 
+ int wg_allowedips_read_node(struct allowedips_node *node, u8 ip[16], u8 *cidr)
+--- a/drivers/net/wireguard/allowedips.h
++++ b/drivers/net/wireguard/allowedips.h
+@@ -15,14 +15,11 @@ struct wg_peer;
+ struct allowedips_node {
+ 	struct wg_peer __rcu *peer;
+ 	struct allowedips_node __rcu *bit[2];
+-	/* While it may seem scandalous that we waste space for v4,
+-	 * we're alloc'ing to the nearest power of 2 anyway, so this
+-	 * doesn't actually make a difference.
+-	 */
+-	u8 bits[16] __aligned(__alignof(u64));
+ 	u8 cidr, bit_at_a, bit_at_b, bitlen;
++	u8 bits[16] __aligned(__alignof(u64));
+ 
+-	/* Keep rarely used list at bottom to be beyond cache line. */
++	/* Keep rarely used members at bottom to be beyond cache line. */
++	struct allowedips_node *__rcu *parent_bit; /* XXX: this puts us at 68->128 bytes instead of 60->64 bytes!! */
+ 	union {
+ 		struct list_head peer_list;
+ 		struct rcu_head rcu;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0134-wireguard-allowedips-allocate-nodes-in-kmem_cache.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0134-wireguard-allowedips-allocate-nodes-in-kmem_cache.patch
new file mode 100644
index 0000000..65b31b0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0134-wireguard-allowedips-allocate-nodes-in-kmem_cache.patch
@@ -0,0 +1,173 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 4 Jun 2021 17:17:37 +0200
+Subject: [PATCH] wireguard: allowedips: allocate nodes in kmem_cache
+
+commit dc680de28ca849dfe589dc15ac56d22505f0ef11 upstream.
+
+The previous commit moved from O(n) to O(1) for removal, but in the
+process introduced an additional pointer member to a struct that
+increased the size from 60 to 68 bytes, putting nodes in the 128-byte
+slab. With deployed systems having as many as 2 million nodes, this
+represents a significant doubling in memory usage (128 MiB -> 256 MiB).
+Fix this by using our own kmem_cache, that's sized exactly right. This
+also makes wireguard's memory usage more transparent in tools like
+slabtop and /proc/slabinfo.
+
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Suggested-by: Arnd Bergmann <arnd@arndb.de>
+Suggested-by: Matthew Wilcox <willy@infradead.org>
+Cc: stable@vger.kernel.org
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/allowedips.c | 31 ++++++++++++++++++++++++------
+ drivers/net/wireguard/allowedips.h |  5 ++++-
+ drivers/net/wireguard/main.c       | 10 +++++++++-
+ 3 files changed, 38 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/wireguard/allowedips.c
++++ b/drivers/net/wireguard/allowedips.c
+@@ -6,6 +6,8 @@
+ #include "allowedips.h"
+ #include "peer.h"
+ 
++static struct kmem_cache *node_cache;
++
+ static void swap_endian(u8 *dst, const u8 *src, u8 bits)
+ {
+ 	if (bits == 32) {
+@@ -40,6 +42,11 @@ static void push_rcu(struct allowedips_n
+ 	}
+ }
+ 
++static void node_free_rcu(struct rcu_head *rcu)
++{
++	kmem_cache_free(node_cache, container_of(rcu, struct allowedips_node, rcu));
++}
++
+ static void root_free_rcu(struct rcu_head *rcu)
+ {
+ 	struct allowedips_node *node, *stack[128] = {
+@@ -49,7 +56,7 @@ static void root_free_rcu(struct rcu_hea
+ 	while (len > 0 && (node = stack[--len])) {
+ 		push_rcu(stack, node->bit[0], &len);
+ 		push_rcu(stack, node->bit[1], &len);
+-		kfree(node);
++		kmem_cache_free(node_cache, node);
+ 	}
+ }
+ 
+@@ -164,7 +171,7 @@ static int add(struct allowedips_node __
+ 		return -EINVAL;
+ 
+ 	if (!rcu_access_pointer(*trie)) {
+-		node = kzalloc(sizeof(*node), GFP_KERNEL);
++		node = kmem_cache_zalloc(node_cache, GFP_KERNEL);
+ 		if (unlikely(!node))
+ 			return -ENOMEM;
+ 		RCU_INIT_POINTER(node->peer, peer);
+@@ -180,7 +187,7 @@ static int add(struct allowedips_node __
+ 		return 0;
+ 	}
+ 
+-	newnode = kzalloc(sizeof(*newnode), GFP_KERNEL);
++	newnode = kmem_cache_zalloc(node_cache, GFP_KERNEL);
+ 	if (unlikely(!newnode))
+ 		return -ENOMEM;
+ 	RCU_INIT_POINTER(newnode->peer, peer);
+@@ -213,10 +220,10 @@ static int add(struct allowedips_node __
+ 		return 0;
+ 	}
+ 
+-	node = kzalloc(sizeof(*node), GFP_KERNEL);
++	node = kmem_cache_zalloc(node_cache, GFP_KERNEL);
+ 	if (unlikely(!node)) {
+ 		list_del(&newnode->peer_list);
+-		kfree(newnode);
++		kmem_cache_free(node_cache, newnode);
+ 		return -ENOMEM;
+ 	}
+ 	INIT_LIST_HEAD(&node->peer_list);
+@@ -306,7 +313,7 @@ void wg_allowedips_remove_by_peer(struct
+ 		if (child)
+ 			child->parent_bit = node->parent_bit;
+ 		*rcu_dereference_protected(node->parent_bit, lockdep_is_held(lock)) = child;
+-		kfree_rcu(node, rcu);
++		call_rcu(&node->rcu, node_free_rcu);
+ 
+ 		/* TODO: Note that we currently don't walk up and down in order to
+ 		 * free any potential filler nodes. This means that this function
+@@ -350,4 +357,16 @@ struct wg_peer *wg_allowedips_lookup_src
+ 	return NULL;
+ }
+ 
++int __init wg_allowedips_slab_init(void)
++{
++	node_cache = KMEM_CACHE(allowedips_node, 0);
++	return node_cache ? 0 : -ENOMEM;
++}
++
++void wg_allowedips_slab_uninit(void)
++{
++	rcu_barrier();
++	kmem_cache_destroy(node_cache);
++}
++
+ #include "selftest/allowedips.c"
+--- a/drivers/net/wireguard/allowedips.h
++++ b/drivers/net/wireguard/allowedips.h
+@@ -19,7 +19,7 @@ struct allowedips_node {
+ 	u8 bits[16] __aligned(__alignof(u64));
+ 
+ 	/* Keep rarely used members at bottom to be beyond cache line. */
+-	struct allowedips_node *__rcu *parent_bit; /* XXX: this puts us at 68->128 bytes instead of 60->64 bytes!! */
++	struct allowedips_node *__rcu *parent_bit;
+ 	union {
+ 		struct list_head peer_list;
+ 		struct rcu_head rcu;
+@@ -53,4 +53,7 @@ struct wg_peer *wg_allowedips_lookup_src
+ bool wg_allowedips_selftest(void);
+ #endif
+ 
++int wg_allowedips_slab_init(void);
++void wg_allowedips_slab_uninit(void);
++
+ #endif /* _WG_ALLOWEDIPS_H */
+--- a/drivers/net/wireguard/main.c
++++ b/drivers/net/wireguard/main.c
+@@ -21,10 +21,15 @@ static int __init mod_init(void)
+ {
+ 	int ret;
+ 
++	ret = wg_allowedips_slab_init();
++	if (ret < 0)
++		goto err_allowedips;
++
+ #ifdef DEBUG
++	ret = -ENOTRECOVERABLE;
+ 	if (!wg_allowedips_selftest() || !wg_packet_counter_selftest() ||
+ 	    !wg_ratelimiter_selftest())
+-		return -ENOTRECOVERABLE;
++		goto err_peer;
+ #endif
+ 	wg_noise_init();
+ 
+@@ -50,6 +55,8 @@ err_netlink:
+ err_device:
+ 	wg_peer_uninit();
+ err_peer:
++	wg_allowedips_slab_uninit();
++err_allowedips:
+ 	return ret;
+ }
+ 
+@@ -58,6 +65,7 @@ static void __exit mod_exit(void)
+ 	wg_genetlink_uninit();
+ 	wg_device_uninit();
+ 	wg_peer_uninit();
++	wg_allowedips_slab_uninit();
+ }
+ 
+ module_init(mod_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0135-wireguard-allowedips-free-empty-intermediate-nodes-w.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0135-wireguard-allowedips-free-empty-intermediate-nodes-w.patch
new file mode 100644
index 0000000..c044ad2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/080-wireguard-0135-wireguard-allowedips-free-empty-intermediate-nodes-w.patch
@@ -0,0 +1,521 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Fri, 4 Jun 2021 17:17:38 +0200
+Subject: [PATCH] wireguard: allowedips: free empty intermediate nodes when
+ removing single node
+
+commit bf7b042dc62a31f66d3a41dd4dfc7806f267b307 upstream.
+
+When removing single nodes, it's possible that that node's parent is an
+empty intermediate node, in which case, it too should be removed.
+Otherwise the trie fills up and never is fully emptied, leading to
+gradual memory leaks over time for tries that are modified often. There
+was originally code to do this, but was removed during refactoring in
+2016 and never reworked. Now that we have proper parent pointers from
+the previous commits, we can implement this properly.
+
+In order to reduce branching and expensive comparisons, we want to keep
+the double pointer for parent assignment (which lets us easily chain up
+to the root), but we still need to actually get the parent's base
+address. So encode the bit number into the last two bits of the pointer,
+and pack and unpack it as needed. This is a little bit clumsy but is the
+fastest and less memory wasteful of the compromises. Note that we align
+the root struct here to a minimum of 4, because it's embedded into a
+larger struct, and we're relying on having the bottom two bits for our
+flag, which would only be 16-bit aligned on m68k.
+
+The existing macro-based helpers were a bit unwieldy for adding the bit
+packing to, so this commit replaces them with safer and clearer ordinary
+functions.
+
+We add a test to the randomized/fuzzer part of the selftests, to free
+the randomized tries by-peer, refuzz it, and repeat, until it's supposed
+to be empty, and then then see if that actually resulted in the whole
+thing being emptied. That combined with kmemcheck should hopefully make
+sure this commit is doing what it should. Along the way this resulted in
+various other cleanups of the tests and fixes for recent graphviz.
+
+Fixes: e7096c131e51 ("net: WireGuard secure network tunnel")
+Cc: stable@vger.kernel.org
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ drivers/net/wireguard/allowedips.c          | 102 ++++++------
+ drivers/net/wireguard/allowedips.h          |   4 +-
+ drivers/net/wireguard/selftest/allowedips.c | 162 ++++++++++----------
+ 3 files changed, 137 insertions(+), 131 deletions(-)
+
+--- a/drivers/net/wireguard/allowedips.c
++++ b/drivers/net/wireguard/allowedips.c
+@@ -30,8 +30,11 @@ static void copy_and_assign_cidr(struct
+ 	node->bitlen = bits;
+ 	memcpy(node->bits, src, bits / 8U);
+ }
+-#define CHOOSE_NODE(parent, key) \
+-	parent->bit[(key[parent->bit_at_a] >> parent->bit_at_b) & 1]
++
++static inline u8 choose(struct allowedips_node *node, const u8 *key)
++{
++	return (key[node->bit_at_a] >> node->bit_at_b) & 1;
++}
+ 
+ static void push_rcu(struct allowedips_node **stack,
+ 		     struct allowedips_node __rcu *p, unsigned int *len)
+@@ -112,7 +115,7 @@ static struct allowedips_node *find_node
+ 			found = node;
+ 		if (node->cidr == bits)
+ 			break;
+-		node = rcu_dereference_bh(CHOOSE_NODE(node, key));
++		node = rcu_dereference_bh(node->bit[choose(node, key)]);
+ 	}
+ 	return found;
+ }
+@@ -144,8 +147,7 @@ static bool node_placement(struct allowe
+ 			   u8 cidr, u8 bits, struct allowedips_node **rnode,
+ 			   struct mutex *lock)
+ {
+-	struct allowedips_node *node = rcu_dereference_protected(trie,
+-						lockdep_is_held(lock));
++	struct allowedips_node *node = rcu_dereference_protected(trie, lockdep_is_held(lock));
+ 	struct allowedips_node *parent = NULL;
+ 	bool exact = false;
+ 
+@@ -155,13 +157,24 @@ static bool node_placement(struct allowe
+ 			exact = true;
+ 			break;
+ 		}
+-		node = rcu_dereference_protected(CHOOSE_NODE(parent, key),
+-						 lockdep_is_held(lock));
++		node = rcu_dereference_protected(parent->bit[choose(parent, key)], lockdep_is_held(lock));
+ 	}
+ 	*rnode = parent;
+ 	return exact;
+ }
+ 
++static inline void connect_node(struct allowedips_node **parent, u8 bit, struct allowedips_node *node)
++{
++	node->parent_bit_packed = (unsigned long)parent | bit;
++	rcu_assign_pointer(*parent, node);
++}
++
++static inline void choose_and_connect_node(struct allowedips_node *parent, struct allowedips_node *node)
++{
++	u8 bit = choose(parent, node->bits);
++	connect_node(&parent->bit[bit], bit, node);
++}
++
+ static int add(struct allowedips_node __rcu **trie, u8 bits, const u8 *key,
+ 	       u8 cidr, struct wg_peer *peer, struct mutex *lock)
+ {
+@@ -177,8 +190,7 @@ static int add(struct allowedips_node __
+ 		RCU_INIT_POINTER(node->peer, peer);
+ 		list_add_tail(&node->peer_list, &peer->allowedips_list);
+ 		copy_and_assign_cidr(node, key, cidr, bits);
+-		rcu_assign_pointer(node->parent_bit, trie);
+-		rcu_assign_pointer(*trie, node);
++		connect_node(trie, 2, node);
+ 		return 0;
+ 	}
+ 	if (node_placement(*trie, key, cidr, bits, &node, lock)) {
+@@ -197,10 +209,10 @@ static int add(struct allowedips_node __
+ 	if (!node) {
+ 		down = rcu_dereference_protected(*trie, lockdep_is_held(lock));
+ 	} else {
+-		down = rcu_dereference_protected(CHOOSE_NODE(node, key), lockdep_is_held(lock));
++		const u8 bit = choose(node, key);
++		down = rcu_dereference_protected(node->bit[bit], lockdep_is_held(lock));
+ 		if (!down) {
+-			rcu_assign_pointer(newnode->parent_bit, &CHOOSE_NODE(node, key));
+-			rcu_assign_pointer(CHOOSE_NODE(node, key), newnode);
++			connect_node(&node->bit[bit], bit, newnode);
+ 			return 0;
+ 		}
+ 	}
+@@ -208,15 +220,11 @@ static int add(struct allowedips_node __
+ 	parent = node;
+ 
+ 	if (newnode->cidr == cidr) {
+-		rcu_assign_pointer(down->parent_bit, &CHOOSE_NODE(newnode, down->bits));
+-		rcu_assign_pointer(CHOOSE_NODE(newnode, down->bits), down);
+-		if (!parent) {
+-			rcu_assign_pointer(newnode->parent_bit, trie);
+-			rcu_assign_pointer(*trie, newnode);
+-		} else {
+-			rcu_assign_pointer(newnode->parent_bit, &CHOOSE_NODE(parent, newnode->bits));
+-			rcu_assign_pointer(CHOOSE_NODE(parent, newnode->bits), newnode);
+-		}
++		choose_and_connect_node(newnode, down);
++		if (!parent)
++			connect_node(trie, 2, newnode);
++		else
++			choose_and_connect_node(parent, newnode);
+ 		return 0;
+ 	}
+ 
+@@ -229,17 +237,12 @@ static int add(struct allowedips_node __
+ 	INIT_LIST_HEAD(&node->peer_list);
+ 	copy_and_assign_cidr(node, newnode->bits, cidr, bits);
+ 
+-	rcu_assign_pointer(down->parent_bit, &CHOOSE_NODE(node, down->bits));
+-	rcu_assign_pointer(CHOOSE_NODE(node, down->bits), down);
+-	rcu_assign_pointer(newnode->parent_bit, &CHOOSE_NODE(node, newnode->bits));
+-	rcu_assign_pointer(CHOOSE_NODE(node, newnode->bits), newnode);
+-	if (!parent) {
+-		rcu_assign_pointer(node->parent_bit, trie);
+-		rcu_assign_pointer(*trie, node);
+-	} else {
+-		rcu_assign_pointer(node->parent_bit, &CHOOSE_NODE(parent, node->bits));
+-		rcu_assign_pointer(CHOOSE_NODE(parent, node->bits), node);
+-	}
++	choose_and_connect_node(node, down);
++	choose_and_connect_node(node, newnode);
++	if (!parent)
++		connect_node(trie, 2, node);
++	else
++		choose_and_connect_node(parent, node);
+ 	return 0;
+ }
+ 
+@@ -297,7 +300,8 @@ int wg_allowedips_insert_v6(struct allow
+ void wg_allowedips_remove_by_peer(struct allowedips *table,
+ 				  struct wg_peer *peer, struct mutex *lock)
+ {
+-	struct allowedips_node *node, *child, *tmp;
++	struct allowedips_node *node, *child, **parent_bit, *parent, *tmp;
++	bool free_parent;
+ 
+ 	if (list_empty(&peer->allowedips_list))
+ 		return;
+@@ -307,19 +311,29 @@ void wg_allowedips_remove_by_peer(struct
+ 		RCU_INIT_POINTER(node->peer, NULL);
+ 		if (node->bit[0] && node->bit[1])
+ 			continue;
+-		child = rcu_dereference_protected(
+-				node->bit[!rcu_access_pointer(node->bit[0])],
+-				lockdep_is_held(lock));
++		child = rcu_dereference_protected(node->bit[!rcu_access_pointer(node->bit[0])],
++						  lockdep_is_held(lock));
+ 		if (child)
+-			child->parent_bit = node->parent_bit;
+-		*rcu_dereference_protected(node->parent_bit, lockdep_is_held(lock)) = child;
++			child->parent_bit_packed = node->parent_bit_packed;
++		parent_bit = (struct allowedips_node **)(node->parent_bit_packed & ~3UL);
++		*parent_bit = child;
++		parent = (void *)parent_bit -
++			 offsetof(struct allowedips_node, bit[node->parent_bit_packed & 1]);
++		free_parent = !rcu_access_pointer(node->bit[0]) &&
++			      !rcu_access_pointer(node->bit[1]) &&
++			      (node->parent_bit_packed & 3) <= 1 &&
++			      !rcu_access_pointer(parent->peer);
++		if (free_parent)
++			child = rcu_dereference_protected(
++					parent->bit[!(node->parent_bit_packed & 1)],
++					lockdep_is_held(lock));
+ 		call_rcu(&node->rcu, node_free_rcu);
+-
+-		/* TODO: Note that we currently don't walk up and down in order to
+-		 * free any potential filler nodes. This means that this function
+-		 * doesn't free up as much as it could, which could be revisited
+-		 * at some point.
+-		 */
++		if (!free_parent)
++			continue;
++		if (child)
++			child->parent_bit_packed = parent->parent_bit_packed;
++		*(struct allowedips_node **)(parent->parent_bit_packed & ~3UL) = child;
++		call_rcu(&parent->rcu, node_free_rcu);
+ 	}
+ }
+ 
+--- a/drivers/net/wireguard/allowedips.h
++++ b/drivers/net/wireguard/allowedips.h
+@@ -19,7 +19,7 @@ struct allowedips_node {
+ 	u8 bits[16] __aligned(__alignof(u64));
+ 
+ 	/* Keep rarely used members at bottom to be beyond cache line. */
+-	struct allowedips_node *__rcu *parent_bit;
++	unsigned long parent_bit_packed;
+ 	union {
+ 		struct list_head peer_list;
+ 		struct rcu_head rcu;
+@@ -30,7 +30,7 @@ struct allowedips {
+ 	struct allowedips_node __rcu *root4;
+ 	struct allowedips_node __rcu *root6;
+ 	u64 seq;
+-};
++} __aligned(4); /* We pack the lower 2 bits of &root, but m68k only gives 16-bit alignment. */
+ 
+ void wg_allowedips_init(struct allowedips *table);
+ void wg_allowedips_free(struct allowedips *table, struct mutex *mutex);
+--- a/drivers/net/wireguard/selftest/allowedips.c
++++ b/drivers/net/wireguard/selftest/allowedips.c
+@@ -19,32 +19,22 @@
+ 
+ #include <linux/siphash.h>
+ 
+-static __init void swap_endian_and_apply_cidr(u8 *dst, const u8 *src, u8 bits,
+-					      u8 cidr)
+-{
+-	swap_endian(dst, src, bits);
+-	memset(dst + (cidr + 7) / 8, 0, bits / 8 - (cidr + 7) / 8);
+-	if (cidr)
+-		dst[(cidr + 7) / 8 - 1] &= ~0U << ((8 - (cidr % 8)) % 8);
+-}
+-
+ static __init void print_node(struct allowedips_node *node, u8 bits)
+ {
+ 	char *fmt_connection = KERN_DEBUG "\t\"%p/%d\" -> \"%p/%d\";\n";
+-	char *fmt_declaration = KERN_DEBUG
+-		"\t\"%p/%d\"[style=%s, color=\"#%06x\"];\n";
++	char *fmt_declaration = KERN_DEBUG "\t\"%p/%d\"[style=%s, color=\"#%06x\"];\n";
++	u8 ip1[16], ip2[16], cidr1, cidr2;
+ 	char *style = "dotted";
+-	u8 ip1[16], ip2[16];
+ 	u32 color = 0;
+ 
++	if (node == NULL)
++		return;
+ 	if (bits == 32) {
+ 		fmt_connection = KERN_DEBUG "\t\"%pI4/%d\" -> \"%pI4/%d\";\n";
+-		fmt_declaration = KERN_DEBUG
+-			"\t\"%pI4/%d\"[style=%s, color=\"#%06x\"];\n";
++		fmt_declaration = KERN_DEBUG "\t\"%pI4/%d\"[style=%s, color=\"#%06x\"];\n";
+ 	} else if (bits == 128) {
+ 		fmt_connection = KERN_DEBUG "\t\"%pI6/%d\" -> \"%pI6/%d\";\n";
+-		fmt_declaration = KERN_DEBUG
+-			"\t\"%pI6/%d\"[style=%s, color=\"#%06x\"];\n";
++		fmt_declaration = KERN_DEBUG "\t\"%pI6/%d\"[style=%s, color=\"#%06x\"];\n";
+ 	}
+ 	if (node->peer) {
+ 		hsiphash_key_t key = { { 0 } };
+@@ -55,24 +45,20 @@ static __init void print_node(struct all
+ 			hsiphash_1u32(0xabad1dea, &key) % 200;
+ 		style = "bold";
+ 	}
+-	swap_endian_and_apply_cidr(ip1, node->bits, bits, node->cidr);
+-	printk(fmt_declaration, ip1, node->cidr, style, color);
++	wg_allowedips_read_node(node, ip1, &cidr1);
++	printk(fmt_declaration, ip1, cidr1, style, color);
+ 	if (node->bit[0]) {
+-		swap_endian_and_apply_cidr(ip2,
+-				rcu_dereference_raw(node->bit[0])->bits, bits,
+-				node->cidr);
+-		printk(fmt_connection, ip1, node->cidr, ip2,
+-		       rcu_dereference_raw(node->bit[0])->cidr);
+-		print_node(rcu_dereference_raw(node->bit[0]), bits);
++		wg_allowedips_read_node(rcu_dereference_raw(node->bit[0]), ip2, &cidr2);
++		printk(fmt_connection, ip1, cidr1, ip2, cidr2);
+ 	}
+ 	if (node->bit[1]) {
+-		swap_endian_and_apply_cidr(ip2,
+-				rcu_dereference_raw(node->bit[1])->bits,
+-				bits, node->cidr);
+-		printk(fmt_connection, ip1, node->cidr, ip2,
+-		       rcu_dereference_raw(node->bit[1])->cidr);
+-		print_node(rcu_dereference_raw(node->bit[1]), bits);
++		wg_allowedips_read_node(rcu_dereference_raw(node->bit[1]), ip2, &cidr2);
++		printk(fmt_connection, ip1, cidr1, ip2, cidr2);
+ 	}
++	if (node->bit[0])
++		print_node(rcu_dereference_raw(node->bit[0]), bits);
++	if (node->bit[1])
++		print_node(rcu_dereference_raw(node->bit[1]), bits);
+ }
+ 
+ static __init void print_tree(struct allowedips_node __rcu *top, u8 bits)
+@@ -121,8 +107,8 @@ static __init inline union nf_inet_addr
+ {
+ 	union nf_inet_addr mask;
+ 
+-	memset(&mask, 0x00, 128 / 8);
+-	memset(&mask, 0xff, cidr / 8);
++	memset(&mask, 0, sizeof(mask));
++	memset(&mask.all, 0xff, cidr / 8);
+ 	if (cidr % 32)
+ 		mask.all[cidr / 32] = (__force u32)htonl(
+ 			(0xFFFFFFFFUL << (32 - (cidr % 32))) & 0xFFFFFFFFUL);
+@@ -149,42 +135,36 @@ horrible_mask_self(struct horrible_allow
+ }
+ 
+ static __init inline bool
+-horrible_match_v4(const struct horrible_allowedips_node *node,
+-		  struct in_addr *ip)
++horrible_match_v4(const struct horrible_allowedips_node *node, struct in_addr *ip)
+ {
+ 	return (ip->s_addr & node->mask.ip) == node->ip.ip;
+ }
+ 
+ static __init inline bool
+-horrible_match_v6(const struct horrible_allowedips_node *node,
+-		  struct in6_addr *ip)
++horrible_match_v6(const struct horrible_allowedips_node *node, struct in6_addr *ip)
+ {
+-	return (ip->in6_u.u6_addr32[0] & node->mask.ip6[0]) ==
+-		       node->ip.ip6[0] &&
+-	       (ip->in6_u.u6_addr32[1] & node->mask.ip6[1]) ==
+-		       node->ip.ip6[1] &&
+-	       (ip->in6_u.u6_addr32[2] & node->mask.ip6[2]) ==
+-		       node->ip.ip6[2] &&
++	return (ip->in6_u.u6_addr32[0] & node->mask.ip6[0]) == node->ip.ip6[0] &&
++	       (ip->in6_u.u6_addr32[1] & node->mask.ip6[1]) == node->ip.ip6[1] &&
++	       (ip->in6_u.u6_addr32[2] & node->mask.ip6[2]) == node->ip.ip6[2] &&
+ 	       (ip->in6_u.u6_addr32[3] & node->mask.ip6[3]) == node->ip.ip6[3];
+ }
+ 
+ static __init void
+-horrible_insert_ordered(struct horrible_allowedips *table,
+-			struct horrible_allowedips_node *node)
++horrible_insert_ordered(struct horrible_allowedips *table, struct horrible_allowedips_node *node)
+ {
+ 	struct horrible_allowedips_node *other = NULL, *where = NULL;
+ 	u8 my_cidr = horrible_mask_to_cidr(node->mask);
+ 
+ 	hlist_for_each_entry(other, &table->head, table) {
+-		if (!memcmp(&other->mask, &node->mask,
+-			    sizeof(union nf_inet_addr)) &&
+-		    !memcmp(&other->ip, &node->ip,
+-			    sizeof(union nf_inet_addr)) &&
+-		    other->ip_version == node->ip_version) {
++		if (other->ip_version == node->ip_version &&
++		    !memcmp(&other->mask, &node->mask, sizeof(union nf_inet_addr)) &&
++		    !memcmp(&other->ip, &node->ip, sizeof(union nf_inet_addr))) {
+ 			other->value = node->value;
+ 			kfree(node);
+ 			return;
+ 		}
++	}
++	hlist_for_each_entry(other, &table->head, table) {
+ 		where = other;
+ 		if (horrible_mask_to_cidr(other->mask) <= my_cidr)
+ 			break;
+@@ -201,8 +181,7 @@ static __init int
+ horrible_allowedips_insert_v4(struct horrible_allowedips *table,
+ 			      struct in_addr *ip, u8 cidr, void *value)
+ {
+-	struct horrible_allowedips_node *node = kzalloc(sizeof(*node),
+-							GFP_KERNEL);
++	struct horrible_allowedips_node *node = kzalloc(sizeof(*node), GFP_KERNEL);
+ 
+ 	if (unlikely(!node))
+ 		return -ENOMEM;
+@@ -219,8 +198,7 @@ static __init int
+ horrible_allowedips_insert_v6(struct horrible_allowedips *table,
+ 			      struct in6_addr *ip, u8 cidr, void *value)
+ {
+-	struct horrible_allowedips_node *node = kzalloc(sizeof(*node),
+-							GFP_KERNEL);
++	struct horrible_allowedips_node *node = kzalloc(sizeof(*node), GFP_KERNEL);
+ 
+ 	if (unlikely(!node))
+ 		return -ENOMEM;
+@@ -234,39 +212,43 @@ horrible_allowedips_insert_v6(struct hor
+ }
+ 
+ static __init void *
+-horrible_allowedips_lookup_v4(struct horrible_allowedips *table,
+-			      struct in_addr *ip)
++horrible_allowedips_lookup_v4(struct horrible_allowedips *table, struct in_addr *ip)
+ {
+ 	struct horrible_allowedips_node *node;
+-	void *ret = NULL;
+ 
+ 	hlist_for_each_entry(node, &table->head, table) {
+-		if (node->ip_version != 4)
+-			continue;
+-		if (horrible_match_v4(node, ip)) {
+-			ret = node->value;
+-			break;
+-		}
++		if (node->ip_version == 4 && horrible_match_v4(node, ip))
++			return node->value;
+ 	}
+-	return ret;
++	return NULL;
+ }
+ 
+ static __init void *
+-horrible_allowedips_lookup_v6(struct horrible_allowedips *table,
+-			      struct in6_addr *ip)
++horrible_allowedips_lookup_v6(struct horrible_allowedips *table, struct in6_addr *ip)
+ {
+ 	struct horrible_allowedips_node *node;
+-	void *ret = NULL;
+ 
+ 	hlist_for_each_entry(node, &table->head, table) {
+-		if (node->ip_version != 6)
++		if (node->ip_version == 6 && horrible_match_v6(node, ip))
++			return node->value;
++	}
++	return NULL;
++}
++
++
++static __init void
++horrible_allowedips_remove_by_value(struct horrible_allowedips *table, void *value)
++{
++	struct horrible_allowedips_node *node;
++	struct hlist_node *h;
++
++	hlist_for_each_entry_safe(node, h, &table->head, table) {
++		if (node->value != value)
+ 			continue;
+-		if (horrible_match_v6(node, ip)) {
+-			ret = node->value;
+-			break;
+-		}
++		hlist_del(&node->table);
++		kfree(node);
+ 	}
+-	return ret;
++
+ }
+ 
+ static __init bool randomized_test(void)
+@@ -397,23 +379,33 @@ static __init bool randomized_test(void)
+ 		print_tree(t.root6, 128);
+ 	}
+ 
+-	for (i = 0; i < NUM_QUERIES; ++i) {
+-		prandom_bytes(ip, 4);
+-		if (lookup(t.root4, 32, ip) !=
+-		    horrible_allowedips_lookup_v4(&h, (struct in_addr *)ip)) {
+-			pr_err("allowedips random self-test: FAIL\n");
+-			goto free;
++	for (j = 0;; ++j) {
++		for (i = 0; i < NUM_QUERIES; ++i) {
++			prandom_bytes(ip, 4);
++			if (lookup(t.root4, 32, ip) != horrible_allowedips_lookup_v4(&h, (struct in_addr *)ip)) {
++				horrible_allowedips_lookup_v4(&h, (struct in_addr *)ip);
++				pr_err("allowedips random v4 self-test: FAIL\n");
++				goto free;
++			}
++			prandom_bytes(ip, 16);
++			if (lookup(t.root6, 128, ip) != horrible_allowedips_lookup_v6(&h, (struct in6_addr *)ip)) {
++				pr_err("allowedips random v6 self-test: FAIL\n");
++				goto free;
++			}
+ 		}
++		if (j >= NUM_PEERS)
++			break;
++		mutex_lock(&mutex);
++		wg_allowedips_remove_by_peer(&t, peers[j], &mutex);
++		mutex_unlock(&mutex);
++		horrible_allowedips_remove_by_value(&h, peers[j]);
+ 	}
+ 
+-	for (i = 0; i < NUM_QUERIES; ++i) {
+-		prandom_bytes(ip, 16);
+-		if (lookup(t.root6, 128, ip) !=
+-		    horrible_allowedips_lookup_v6(&h, (struct in6_addr *)ip)) {
+-			pr_err("allowedips random self-test: FAIL\n");
+-			goto free;
+-		}
++	if (t.root4 || t.root6) {
++		pr_err("allowedips random self-test removal: FAIL\n");
++		goto free;
+ 	}
++
+ 	ret = true;
+ 
+ free:
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/300-MIPS-Exclude-more-dsemul-code-when-CONFIG_MIPS_FP_SU.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/300-MIPS-Exclude-more-dsemul-code-when-CONFIG_MIPS_FP_SU.patch
new file mode 100644
index 0000000..0bc58e7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/300-MIPS-Exclude-more-dsemul-code-when-CONFIG_MIPS_FP_SU.patch
@@ -0,0 +1,134 @@
+From d96c3157f9ca177727fbad960fcf6f52f145f471 Mon Sep 17 00:00:00 2001
+From: Yousong Zhou <yszhou4tech@gmail.com>
+Date: Thu, 9 Jan 2020 11:33:19 +0800
+Subject: [PATCH] MIPS: Exclude more dsemul code when CONFIG_MIPS_FP_SUPPORT=n
+
+This furthers what commit 42b10815d559 ("MIPS: Don't compile math-emu
+when CONFIG_MIPS_FP_SUPPORT=n") has done
+
+Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
+---
+ arch/mips/include/asm/processor.h | 12 ++++++------
+ arch/mips/kernel/process.c        | 10 ++++++++--
+ arch/mips/kernel/vdso.c           | 26 +++++++++++++++-----------
+ 3 files changed, 29 insertions(+), 19 deletions(-)
+
+--- a/arch/mips/include/asm/processor.h
++++ b/arch/mips/include/asm/processor.h
+@@ -253,13 +253,13 @@ struct thread_struct {
+ #ifdef CONFIG_MIPS_FP_SUPPORT
+ 	/* Saved fpu/fpu emulator stuff. */
+ 	struct mips_fpu_struct fpu FPU_ALIGN;
+-#endif
+ 	/* Assigned branch delay slot 'emulation' frame */
+ 	atomic_t bd_emu_frame;
+ 	/* PC of the branch from a branch delay slot 'emulation' */
+ 	unsigned long bd_emu_branch_pc;
+ 	/* PC to continue from following a branch delay slot 'emulation' */
+ 	unsigned long bd_emu_cont_pc;
++#endif
+ #ifdef CONFIG_MIPS_MT_FPAFF
+ 	/* Emulated instruction count */
+ 	unsigned long emulated_fp;
+@@ -302,7 +302,11 @@ struct thread_struct {
+ 		.fpr		= {{{0,},},},			\
+ 		.fcr31		= 0,				\
+ 		.msacsr		= 0,				\
+-	},
++	},							\
++	/* Delay slot emulation */				\
++	.bd_emu_frame = ATOMIC_INIT(BD_EMUFRAME_NONE),		\
++	.bd_emu_branch_pc = 0,					\
++	.bd_emu_cont_pc = 0,
+ #else
+ # define FPU_INIT
+ #endif
+@@ -334,10 +338,6 @@ struct thread_struct {
+ 	 * FPU affinity state (null if not FPAFF)		\
+ 	 */							\
+ 	FPAFF_INIT						\
+-	/* Delay slot emulation */				\
+-	.bd_emu_frame = ATOMIC_INIT(BD_EMUFRAME_NONE),		\
+-	.bd_emu_branch_pc = 0,					\
+-	.bd_emu_cont_pc = 0,					\
+ 	/*							\
+ 	 * Saved DSP stuff					\
+ 	 */							\
+--- a/arch/mips/kernel/process.c
++++ b/arch/mips/kernel/process.c
+@@ -75,7 +75,9 @@ void start_thread(struct pt_regs * regs,
+ 	lose_fpu(0);
+ 	clear_thread_flag(TIF_MSA_CTX_LIVE);
+ 	clear_used_math();
++#ifdef CONFIG_MIPS_FP_SUPPORT
+ 	atomic_set(&current->thread.bd_emu_frame, BD_EMUFRAME_NONE);
++#endif
+ 	init_dsp();
+ 	regs->cp0_epc = pc;
+ 	regs->regs[29] = sp;
+@@ -176,7 +178,9 @@ int copy_thread_tls(unsigned long clone_
+ 	clear_tsk_thread_flag(p, TIF_FPUBOUND);
+ #endif /* CONFIG_MIPS_MT_FPAFF */
+ 
++#ifdef CONFIG_MIPS_FP_SUPPORT
+ 	atomic_set(&p->thread.bd_emu_frame, BD_EMUFRAME_NONE);
++#endif
+ 
+ 	if (clone_flags & CLONE_SETTLS)
+ 		ti->tp_value = tls;
+@@ -650,8 +654,10 @@ unsigned long mips_stack_top(void)
+ {
+ 	unsigned long top = TASK_SIZE & PAGE_MASK;
+ 
+-	/* One page for branch delay slot "emulation" */
+-	top -= PAGE_SIZE;
++	if (IS_ENABLED(CONFIG_MIPS_FP_SUPPORT)) {
++		/* One page for branch delay slot "emulation" */
++		top -= PAGE_SIZE;
++	}
+ 
+ 	/* Space for the VDSO, data page & GIC user page */
+ 	top -= PAGE_ALIGN(current->thread.abi->vdso->size);
+--- a/arch/mips/kernel/vdso.c
++++ b/arch/mips/kernel/vdso.c
+@@ -71,10 +71,12 @@ subsys_initcall(init_vdso);
+ 
+ static unsigned long vdso_base(void)
+ {
+-	unsigned long base;
++	unsigned long base = STACK_TOP;
+ 
+-	/* Skip the delay slot emulation page */
+-	base = STACK_TOP + PAGE_SIZE;
++	if (IS_ENABLED(CONFIG_MIPS_FP_SUPPORT)) {
++		/* Skip the delay slot emulation page */
++		base += PAGE_SIZE;
++	}
+ 
+ 	if (current->flags & PF_RANDOMIZE) {
+ 		base += get_random_int() & (VDSO_RANDOMIZE_SIZE - 1);
+@@ -95,14 +97,16 @@ int arch_setup_additional_pages(struct l
+ 	if (down_write_killable(&mm->mmap_sem))
+ 		return -EINTR;
+ 
+-	/* Map delay slot emulation page */
+-	base = mmap_region(NULL, STACK_TOP, PAGE_SIZE,
+-			   VM_READ | VM_EXEC |
+-			   VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
+-			   0, NULL);
+-	if (IS_ERR_VALUE(base)) {
+-		ret = base;
+-		goto out;
++	if (IS_ENABLED(CONFIG_MIPS_FP_SUPPORT)) {
++		/* Map delay slot emulation page */
++		base = mmap_region(NULL, STACK_TOP, PAGE_SIZE,
++				VM_READ | VM_EXEC |
++				VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
++				0, NULL);
++		if (IS_ERR_VALUE(base)) {
++			ret = base;
++			goto out;
++		}
+ 	}
+ 
+ 	/*
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/310-mips-Kconfig-Add-ARCH_HAS_FORTIFY_SOURCE.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/310-mips-Kconfig-Add-ARCH_HAS_FORTIFY_SOURCE.patch
new file mode 100644
index 0000000..e02f103
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/310-mips-Kconfig-Add-ARCH_HAS_FORTIFY_SOURCE.patch
@@ -0,0 +1,32 @@
+From a8d2bb0559b5fefa5173ff4e7496cc6250db2c8a Mon Sep 17 00:00:00 2001
+From: Dmitry Korotin <dkorotin@wavecomp.com>
+Date: Thu, 12 Sep 2019 22:53:45 +0000
+Subject: [PATCH] mips: Kconfig: Add ARCH_HAS_FORTIFY_SOURCE
+
+FORTIFY_SOURCE detects various overflows at compile and run time.
+(6974f0c4555e ("include/linux/string.h:
+add the option of fortified string.h functions)
+
+ARCH_HAS_FORTIFY_SOURCE means that the architecture can be built and
+run with CONFIG_FORTIFY_SOURCE.
+
+Since mips can be built and run with that flag,
+select ARCH_HAS_FORTIFY_SOURCE as default.
+
+Signed-off-by: Dmitry Korotin <dkorotin@wavecomp.com>
+Signed-off-by: Paul Burton <paul.burton@mips.com>
+Cc: linux-mips@vger.kernel.org
+---
+ arch/mips/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -7,6 +7,7 @@ config MIPS
+ 	select ARCH_CLOCKSOURCE_DATA
+ 	select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
+ 	select ARCH_HAS_UBSAN_SANITIZE_ALL
++	select ARCH_HAS_FORTIFY_SOURCE
+ 	select ARCH_SUPPORTS_UPROBES
+ 	select ARCH_USE_BUILTIN_BSWAP
+ 	select ARCH_USE_CMPXCHG_LOCKREF if 64BIT
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/310-v5.6-mips-vdso-fix-jalr-t9-crash-in-vdso-code.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/310-v5.6-mips-vdso-fix-jalr-t9-crash-in-vdso-code.patch
new file mode 100644
index 0000000..51eef4b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/310-v5.6-mips-vdso-fix-jalr-t9-crash-in-vdso-code.patch
@@ -0,0 +1,54 @@
+From d3f703c4359ff06619b2322b91f69710453e6b6d Mon Sep 17 00:00:00 2001
+From: Victor Kamensky <kamensky@cisco.com>
+Date: Tue, 11 Feb 2020 11:24:33 -0800
+Subject: [PATCH] mips: vdso: fix 'jalr t9' crash in vdso code
+
+Observed that when kernel is built with Yocto mips64-poky-linux-gcc,
+and mips64-poky-linux-gnun32-gcc toolchain, resulting vdso contains
+'jalr t9' instructions in its code and since in vdso case nobody
+sets GOT table code crashes when instruction reached. On other hand
+observed that when kernel is built mips-poky-linux-gcc toolchain, the
+same 'jalr t9' instruction are replaced with PC relative function
+calls using 'bal' instructions.
+
+The difference boils down to -mrelax-pic-calls and -mexplicit-relocs
+gcc options that gets different default values depending on gcc
+target triplets and corresponding binutils. -mrelax-pic-calls got
+enabled by default only in mips-poky-linux-gcc case. MIPS binutils
+ld relies on R_MIPS_JALR relocation to convert 'jalr t9' into 'bal'
+and such relocation is generated only if -mrelax-pic-calls option
+is on.
+
+Please note 'jalr t9' conversion to 'bal' can happen only to static
+functions. These static PIC calls use mips local GOT entries that
+are supposed to be filled with start of DSO value by run-time linker
+(missing in VDSO case) and they do not have dynamic relocations.
+Global mips GOT entries must have dynamic relocations and they should
+be prevented by cmd_vdso_check Makefile rule.
+
+Solution call out -mrelax-pic-calls and -mexplicit-relocs options
+explicitly while compiling MIPS vdso code. That would get correct
+and consistent between different toolchains behaviour.
+
+Reported-by: Bruce Ashfield <bruce.ashfield@gmail.com>
+Signed-off-by: Victor Kamensky <kamensky@cisco.com>
+Signed-off-by: Paul Burton <paulburton@kernel.org>
+Cc: linux-mips@vger.kernel.org
+Cc: Ralf Baechle <ralf@linux-mips.org>
+Cc: James Hogan <jhogan@kernel.org>
+Cc: Vincenzo Frascino <vincenzo.frascino@arm.com>
+Cc: richard.purdie@linuxfoundation.org
+---
+ arch/mips/vdso/Makefile | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/mips/vdso/Makefile
++++ b/arch/mips/vdso/Makefile
+@@ -26,6 +26,7 @@ ccflags-vdso := \
+ cflags-vdso := $(ccflags-vdso) \
+ 	$(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \
+ 	-O3 -g -fPIC -fno-strict-aliasing -fno-common -fno-builtin -G 0 \
++	-mrelax-pic-calls -mexplicit-relocs \
+ 	-fno-stack-protector -fno-jump-tables -DDISABLE_BRANCH_PROFILING \
+ 	$(call cc-option, -fno-asynchronous-unwind-tables) \
+ 	$(call cc-option, -fno-stack-protector)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/311-MIPS-Fix-exception-handler-memcpy.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/311-MIPS-Fix-exception-handler-memcpy.patch
new file mode 100644
index 0000000..5a6725c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/311-MIPS-Fix-exception-handler-memcpy.patch
@@ -0,0 +1,107 @@
+From e01c91a360793298c9e1656a61faceff01487a43 Mon Sep 17 00:00:00 2001
+From: Ben Hutchings <ben@decadent.org.uk>
+Date: Sat, 23 May 2020 23:50:34 +0800
+Subject: [PATCH] MIPS: Fix exception handler memcpy()
+
+The exception handler subroutines are declared as a single char, but
+when copied to the required addresses the copy length is 0x80.
+
+When range checks are enabled for memcpy() this results in a build
+failure, with error messages such as:
+
+In file included from arch/mips/mti-malta/malta-init.c:15:
+In function 'memcpy',
+    inlined from 'mips_nmi_setup' at arch/mips/mti-malta/malta-init.c:98:2:
+include/linux/string.h:376:4: error: call to '__read_overflow2' declared with attribute error: detected read beyond size of object passed as 2nd parameter
+  376 |    __read_overflow2();
+      |    ^~~~~~~~~~~~~~~~~~
+
+Change the declarations to use type char[].
+
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: YunQiang Su <syq@debian.org>
+Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+---
+ arch/mips/loongson64/common/init.c | 4 ++--
+ arch/mips/mti-malta/malta-init.c   | 8 ++++----
+ arch/mips/pistachio/init.c         | 8 ++++----
+ 3 files changed, 10 insertions(+), 10 deletions(-)
+
+--- a/arch/mips/loongson64/common/init.c
++++ b/arch/mips/loongson64/common/init.c
+@@ -18,10 +18,10 @@ unsigned long __maybe_unused _loongson_a
+ static void __init mips_nmi_setup(void)
+ {
+ 	void *base;
+-	extern char except_vec_nmi;
++	extern char except_vec_nmi[];
+ 
+ 	base = (void *)(CAC_BASE + 0x380);
+-	memcpy(base, &except_vec_nmi, 0x80);
++	memcpy(base, except_vec_nmi, 0x80);
+ 	flush_icache_range((unsigned long)base, (unsigned long)base + 0x80);
+ }
+ 
+--- a/arch/mips/mti-malta/malta-init.c
++++ b/arch/mips/mti-malta/malta-init.c
+@@ -90,24 +90,24 @@ static void __init console_config(void)
+ static void __init mips_nmi_setup(void)
+ {
+ 	void *base;
+-	extern char except_vec_nmi;
++	extern char except_vec_nmi[];
+ 
+ 	base = cpu_has_veic ?
+ 		(void *)(CAC_BASE + 0xa80) :
+ 		(void *)(CAC_BASE + 0x380);
+-	memcpy(base, &except_vec_nmi, 0x80);
++	memcpy(base, except_vec_nmi, 0x80);
+ 	flush_icache_range((unsigned long)base, (unsigned long)base + 0x80);
+ }
+ 
+ static void __init mips_ejtag_setup(void)
+ {
+ 	void *base;
+-	extern char except_vec_ejtag_debug;
++	extern char except_vec_ejtag_debug[];
+ 
+ 	base = cpu_has_veic ?
+ 		(void *)(CAC_BASE + 0xa00) :
+ 		(void *)(CAC_BASE + 0x300);
+-	memcpy(base, &except_vec_ejtag_debug, 0x80);
++	memcpy(base, except_vec_ejtag_debug, 0x80);
+ 	flush_icache_range((unsigned long)base, (unsigned long)base + 0x80);
+ }
+ 
+--- a/arch/mips/pistachio/init.c
++++ b/arch/mips/pistachio/init.c
+@@ -83,12 +83,12 @@ phys_addr_t mips_cdmm_phys_base(void)
+ static void __init mips_nmi_setup(void)
+ {
+ 	void *base;
+-	extern char except_vec_nmi;
++	extern char except_vec_nmi[];
+ 
+ 	base = cpu_has_veic ?
+ 		(void *)(CAC_BASE + 0xa80) :
+ 		(void *)(CAC_BASE + 0x380);
+-	memcpy(base, &except_vec_nmi, 0x80);
++	memcpy(base, except_vec_nmi, 0x80);
+ 	flush_icache_range((unsigned long)base,
+ 			   (unsigned long)base + 0x80);
+ }
+@@ -96,12 +96,12 @@ static void __init mips_nmi_setup(void)
+ static void __init mips_ejtag_setup(void)
+ {
+ 	void *base;
+-	extern char except_vec_ejtag_debug;
++	extern char except_vec_ejtag_debug[];
+ 
+ 	base = cpu_has_veic ?
+ 		(void *)(CAC_BASE + 0xa00) :
+ 		(void *)(CAC_BASE + 0x300);
+-	memcpy(base, &except_vec_ejtag_debug, 0x80);
++	memcpy(base, except_vec_ejtag_debug, 0x80);
+ 	flush_icache_range((unsigned long)base,
+ 			   (unsigned long)base + 0x80);
+ }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/343-netfilter-nft_flow_offload-handle-netdevice-events-f.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/343-netfilter-nft_flow_offload-handle-netdevice-events-f.patch
new file mode 100644
index 0000000..501f42d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/343-netfilter-nft_flow_offload-handle-netdevice-events-f.patch
@@ -0,0 +1,99 @@
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Thu, 25 Jan 2018 12:58:55 +0100
+Subject: [PATCH] netfilter: nft_flow_offload: handle netdevice events from
+ nf_flow_table
+
+Move the code that deals with device events to the core.
+
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+---
+
+--- a/net/netfilter/nf_flow_table_core.c
++++ b/net/netfilter/nf_flow_table_core.c
+@@ -529,5 +529,35 @@ void nf_flow_table_free(struct nf_flowta
+ }
+ EXPORT_SYMBOL_GPL(nf_flow_table_free);
+ 
++static int nf_flow_table_netdev_event(struct notifier_block *this,
++				      unsigned long event, void *ptr)
++{
++	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
++
++	if (event != NETDEV_DOWN)
++		return NOTIFY_DONE;
++
++	nf_flow_table_cleanup(dev);
++
++	return NOTIFY_DONE;
++}
++
++static struct notifier_block flow_offload_netdev_notifier = {
++	.notifier_call	= nf_flow_table_netdev_event,
++};
++
++static int __init nf_flow_table_module_init(void)
++{
++	return register_netdevice_notifier(&flow_offload_netdev_notifier);
++}
++
++static void __exit nf_flow_table_module_exit(void)
++{
++	unregister_netdevice_notifier(&flow_offload_netdev_notifier);
++}
++
++module_init(nf_flow_table_module_init);
++module_exit(nf_flow_table_module_exit);
++
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
+--- a/net/netfilter/nft_flow_offload.c
++++ b/net/netfilter/nft_flow_offload.c
+@@ -234,47 +234,14 @@ static struct nft_expr_type nft_flow_off
+ 	.owner		= THIS_MODULE,
+ };
+ 
+-static int flow_offload_netdev_event(struct notifier_block *this,
+-				     unsigned long event, void *ptr)
+-{
+-	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+-
+-	if (event != NETDEV_DOWN)
+-		return NOTIFY_DONE;
+-
+-	nf_flow_table_cleanup(dev);
+-
+-	return NOTIFY_DONE;
+-}
+-
+-static struct notifier_block flow_offload_netdev_notifier = {
+-	.notifier_call	= flow_offload_netdev_event,
+-};
+-
+ static int __init nft_flow_offload_module_init(void)
+ {
+-	int err;
+-
+-	err = register_netdevice_notifier(&flow_offload_netdev_notifier);
+-	if (err)
+-		goto err;
+-
+-	err = nft_register_expr(&nft_flow_offload_type);
+-	if (err < 0)
+-		goto register_expr;
+-
+-	return 0;
+-
+-register_expr:
+-	unregister_netdevice_notifier(&flow_offload_netdev_notifier);
+-err:
+-	return err;
++	return nft_register_expr(&nft_flow_offload_type);
+ }
+ 
+ static void __exit nft_flow_offload_module_exit(void)
+ {
+ 	nft_unregister_expr(&nft_flow_offload_type);
+-	unregister_netdevice_notifier(&flow_offload_netdev_notifier);
+ }
+ 
+ module_init(nft_flow_offload_module_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/370-netfilter-nf_flow_table-fix-offloaded-connection-tim.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/370-netfilter-nf_flow_table-fix-offloaded-connection-tim.patch
new file mode 100644
index 0000000..373a156
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/370-netfilter-nf_flow_table-fix-offloaded-connection-tim.patch
@@ -0,0 +1,114 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 13 Jun 2018 12:33:39 +0200
+Subject: [PATCH] netfilter: nf_flow_table: fix offloaded connection timeout
+ corner case
+
+The full teardown of offloaded flows is deferred to a gc work item,
+however processing of packets by netfilter needs to happen immediately
+after a teardown is requested, because the conntrack state needs to be
+fixed up.
+
+Since the IPS_OFFLOAD_BIT is still kept until the teardown is complete,
+the netfilter conntrack gc can accidentally bump the timeout of a
+connection where offload was just stopped, causing a conntrack entry
+leak.
+
+Fix this by moving the conntrack timeout bumping from conntrack core to
+the nf_flow_offload and add a check to prevent bogus timeout bumps.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/netfilter/nf_conntrack_core.c
++++ b/net/netfilter/nf_conntrack_core.c
+@@ -1207,18 +1207,6 @@ static bool gc_worker_can_early_drop(con
+ 	return false;
+ }
+ 
+-#define	DAY	(86400 * HZ)
+-
+-/* Set an arbitrary timeout large enough not to ever expire, this save
+- * us a check for the IPS_OFFLOAD_BIT from the packet path via
+- * nf_ct_is_expired().
+- */
+-static void nf_ct_offload_timeout(struct nf_conn *ct)
+-{
+-	if (nf_ct_expires(ct) < DAY / 2)
+-		ct->timeout = nfct_time_stamp + DAY;
+-}
+-
+ static void gc_worker(struct work_struct *work)
+ {
+ 	unsigned long end_time = jiffies + GC_SCAN_MAX_DURATION;
+@@ -1250,10 +1238,8 @@ static void gc_worker(struct work_struct
+ 
+ 			tmp = nf_ct_tuplehash_to_ctrack(h);
+ 
+-			if (test_bit(IPS_OFFLOAD_BIT, &tmp->status)) {
+-				nf_ct_offload_timeout(tmp);
++			if (test_bit(IPS_OFFLOAD_BIT, &tmp->status))
+ 				continue;
+-			}
+ 
+ 			if (nf_ct_is_expired(tmp)) {
+ 				nf_ct_gc_expired(tmp);
+--- a/net/netfilter/nf_flow_table_core.c
++++ b/net/netfilter/nf_flow_table_core.c
+@@ -198,10 +198,29 @@ static const struct rhashtable_params nf
+ 	.automatic_shrinking	= true,
+ };
+ 
++#define        DAY     (86400 * HZ)
++
++/* Set an arbitrary timeout large enough not to ever expire, this save
++ * us a check for the IPS_OFFLOAD_BIT from the packet path via
++ * nf_ct_is_expired().
++ */
++static void nf_ct_offload_timeout(struct flow_offload *flow)
++{
++	struct flow_offload_entry *entry;
++	struct nf_conn *ct;
++
++	entry = container_of(flow, struct flow_offload_entry, flow);
++	ct = entry->ct;
++
++	if (nf_ct_expires(ct) < DAY / 2)
++		ct->timeout = nfct_time_stamp + DAY;
++}
++
+ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
+ {
+ 	int err;
+ 
++	nf_ct_offload_timeout(flow);
+ 	flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT;
+ 
+ 	err = rhashtable_insert_fast(&flow_table->rhashtable,
+@@ -304,6 +323,7 @@ nf_flow_table_iterate(struct nf_flowtabl
+ 	rhashtable_walk_start(&hti);
+ 
+ 	while ((tuplehash = rhashtable_walk_next(&hti))) {
++
+ 		if (IS_ERR(tuplehash)) {
+ 			if (PTR_ERR(tuplehash) != -EAGAIN) {
+ 				err = PTR_ERR(tuplehash);
+@@ -328,10 +348,17 @@ static void nf_flow_offload_gc_step(stru
+ {
+ 	struct nf_flowtable *flow_table = data;
+ 	struct flow_offload_entry *e;
++	bool teardown;
+ 
+ 	e = container_of(flow, struct flow_offload_entry, flow);
+-	if (nf_flow_has_expired(flow) || nf_ct_is_dying(e->ct) ||
+-	    (flow->flags & (FLOW_OFFLOAD_DYING | FLOW_OFFLOAD_TEARDOWN)))
++
++	teardown = flow->flags & (FLOW_OFFLOAD_DYING |
++				  FLOW_OFFLOAD_TEARDOWN);
++
++	if (!teardown)
++		nf_ct_offload_timeout(flow);
++
++	if (nf_flow_has_expired(flow) || teardown)
+ 		flow_offload_del(flow_table, flow);
+ }
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/371-netfilter-nf_flow_table-fix-up-ct-state-of-flows-aft.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/371-netfilter-nf_flow_table-fix-up-ct-state-of-flows-aft.patch
new file mode 100644
index 0000000..383641d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/371-netfilter-nf_flow_table-fix-up-ct-state-of-flows-aft.patch
@@ -0,0 +1,24 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 14 Jun 2018 11:20:09 +0200
+Subject: [PATCH] netfilter: nf_flow_table: fix up ct state of flows after
+ timeout
+
+If a connection simply times out instead of being torn down, it is left
+active with a long timeout. Fix this by calling flow_offload_fixup_ct_state
+here as well.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/netfilter/nf_flow_table_core.c
++++ b/net/netfilter/nf_flow_table_core.c
+@@ -268,6 +268,9 @@ static void flow_offload_del(struct nf_f
+ 	else if (flow->flags & FLOW_OFFLOAD_TEARDOWN)
+ 		flow_offload_fixup_ct_timeout(e->ct);
+ 
++	if (!(flow->flags & FLOW_OFFLOAD_TEARDOWN))
++		flow_offload_fixup_ct_state(e->ct);
++
+ 	flow_offload_free(flow);
+ }
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/393-v5.5-sch_cake-drop-unused-variable-tin_quantum_prio.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/393-v5.5-sch_cake-drop-unused-variable-tin_quantum_prio.patch
new file mode 100644
index 0000000..6c9e8ad
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/393-v5.5-sch_cake-drop-unused-variable-tin_quantum_prio.patch
@@ -0,0 +1,158 @@
+From d7e1738f0a0b0573ac93cf570ba3df9dee61b68e Mon Sep 17 00:00:00 2001
+From: Kevin 'ldir' Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
+Date: Wed, 18 Dec 2019 14:05:13 +0000
+Subject: [PATCH 2/2] sch_cake: drop unused variable tin_quantum_prio
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Turns out tin_quantum_prio isn't used anymore and is a leftover from a
+previous implementation of diffserv tins.  Since the variable isn't used
+in any calculations it can be eliminated.
+
+Drop variable and places where it was set.  Rename remaining variable
+and consolidate naming of intermediate variables that set it.
+
+Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
+Acked-by: Toke Høiland-Jørgensen <toke@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ net/sched/sch_cake.c | 59 ++++++++++++++------------------------------
+ 1 file changed, 18 insertions(+), 41 deletions(-)
+
+--- a/net/sched/sch_cake.c
++++ b/net/sched/sch_cake.c
+@@ -173,8 +173,7 @@ struct cake_tin_data {
+ 	u64	tin_rate_bps;
+ 	u16	tin_rate_shft;
+ 
+-	u16	tin_quantum_prio;
+-	u16	tin_quantum_band;
++	u16	tin_quantum;
+ 	s32	tin_deficit;
+ 	u32	tin_backlog;
+ 	u32	tin_dropped;
+@@ -1947,7 +1946,7 @@ begin:
+ 		while (b->tin_deficit < 0 ||
+ 		       !(b->sparse_flow_count + b->bulk_flow_count)) {
+ 			if (b->tin_deficit <= 0)
+-				b->tin_deficit += b->tin_quantum_band;
++				b->tin_deficit += b->tin_quantum;
+ 			if (b->sparse_flow_count + b->bulk_flow_count)
+ 				empty = false;
+ 
+@@ -2269,8 +2268,7 @@ static int cake_config_besteffort(struct
+ 
+ 	cake_set_rate(b, rate, mtu,
+ 		      us_to_ns(q->target), us_to_ns(q->interval));
+-	b->tin_quantum_band = 65535;
+-	b->tin_quantum_prio = 65535;
++	b->tin_quantum = 65535;
+ 
+ 	return 0;
+ }
+@@ -2281,8 +2279,7 @@ static int cake_config_precedence(struct
+ 	struct cake_sched_data *q = qdisc_priv(sch);
+ 	u32 mtu = psched_mtu(qdisc_dev(sch));
+ 	u64 rate = q->rate_bps;
+-	u32 quantum1 = 256;
+-	u32 quantum2 = 256;
++	u32 quantum = 256;
+ 	u32 i;
+ 
+ 	q->tin_cnt = 8;
+@@ -2295,18 +2292,14 @@ static int cake_config_precedence(struct
+ 		cake_set_rate(b, rate, mtu, us_to_ns(q->target),
+ 			      us_to_ns(q->interval));
+ 
+-		b->tin_quantum_prio = max_t(u16, 1U, quantum1);
+-		b->tin_quantum_band = max_t(u16, 1U, quantum2);
++		b->tin_quantum = max_t(u16, 1U, quantum);
+ 
+ 		/* calculate next class's parameters */
+ 		rate  *= 7;
+ 		rate >>= 3;
+ 
+-		quantum1  *= 3;
+-		quantum1 >>= 1;
+-
+-		quantum2  *= 7;
+-		quantum2 >>= 3;
++		quantum  *= 7;
++		quantum >>= 3;
+ 	}
+ 
+ 	return 0;
+@@ -2375,8 +2368,7 @@ static int cake_config_diffserv8(struct
+ 	struct cake_sched_data *q = qdisc_priv(sch);
+ 	u32 mtu = psched_mtu(qdisc_dev(sch));
+ 	u64 rate = q->rate_bps;
+-	u32 quantum1 = 256;
+-	u32 quantum2 = 256;
++	u32 quantum = 256;
+ 	u32 i;
+ 
+ 	q->tin_cnt = 8;
+@@ -2392,18 +2384,14 @@ static int cake_config_diffserv8(struct
+ 		cake_set_rate(b, rate, mtu, us_to_ns(q->target),
+ 			      us_to_ns(q->interval));
+ 
+-		b->tin_quantum_prio = max_t(u16, 1U, quantum1);
+-		b->tin_quantum_band = max_t(u16, 1U, quantum2);
++		b->tin_quantum = max_t(u16, 1U, quantum);
+ 
+ 		/* calculate next class's parameters */
+ 		rate  *= 7;
+ 		rate >>= 3;
+ 
+-		quantum1  *= 3;
+-		quantum1 >>= 1;
+-
+-		quantum2  *= 7;
+-		quantum2 >>= 3;
++		quantum  *= 7;
++		quantum >>= 3;
+ 	}
+ 
+ 	return 0;
+@@ -2442,17 +2430,11 @@ static int cake_config_diffserv4(struct
+ 	cake_set_rate(&q->tins[3], rate >> 2, mtu,
+ 		      us_to_ns(q->target), us_to_ns(q->interval));
+ 
+-	/* priority weights */
+-	q->tins[0].tin_quantum_prio = quantum;
+-	q->tins[1].tin_quantum_prio = quantum >> 4;
+-	q->tins[2].tin_quantum_prio = quantum << 2;
+-	q->tins[3].tin_quantum_prio = quantum << 4;
+-
+ 	/* bandwidth-sharing weights */
+-	q->tins[0].tin_quantum_band = quantum;
+-	q->tins[1].tin_quantum_band = quantum >> 4;
+-	q->tins[2].tin_quantum_band = quantum >> 1;
+-	q->tins[3].tin_quantum_band = quantum >> 2;
++	q->tins[0].tin_quantum = quantum;
++	q->tins[1].tin_quantum = quantum >> 4;
++	q->tins[2].tin_quantum = quantum >> 1;
++	q->tins[3].tin_quantum = quantum >> 2;
+ 
+ 	return 0;
+ }
+@@ -2483,15 +2465,10 @@ static int cake_config_diffserv3(struct
+ 	cake_set_rate(&q->tins[2], rate >> 2, mtu,
+ 		      us_to_ns(q->target), us_to_ns(q->interval));
+ 
+-	/* priority weights */
+-	q->tins[0].tin_quantum_prio = quantum;
+-	q->tins[1].tin_quantum_prio = quantum >> 4;
+-	q->tins[2].tin_quantum_prio = quantum << 4;
+-
+ 	/* bandwidth-sharing weights */
+-	q->tins[0].tin_quantum_band = quantum;
+-	q->tins[1].tin_quantum_band = quantum >> 4;
+-	q->tins[2].tin_quantum_band = quantum >> 2;
++	q->tins[0].tin_quantum = quantum;
++	q->tins[1].tin_quantum = quantum >> 4;
++	q->tins[2].tin_quantum = quantum >> 2;
+ 
+ 	return 0;
+ }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/395-v5.8-net-sch_cake-Take-advantage-of-skb-hash-where-appropriate.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/395-v5.8-net-sch_cake-Take-advantage-of-skb-hash-where-appropriate.patch
new file mode 100644
index 0000000..a4981ac
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/395-v5.8-net-sch_cake-Take-advantage-of-skb-hash-where-appropriate.patch
@@ -0,0 +1,170 @@
+From b0c19ed6088ab41dd2a727b60594b7297c15d6ce Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@redhat.com>
+Date: Fri, 29 May 2020 14:43:44 +0200
+Subject: [PATCH] sch_cake: Take advantage of skb->hash where appropriate
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+While the other fq-based qdiscs take advantage of skb->hash and doesn't
+recompute it if it is already set, sch_cake does not.
+
+This was a deliberate choice because sch_cake hashes various parts of the
+packet header to support its advanced flow isolation modes. However,
+foregoing the use of skb->hash entirely loses a few important benefits:
+
+- When skb->hash is set by hardware, a few CPU cycles can be saved by not
+  hashing again in software.
+
+- Tunnel encapsulations will generally preserve the value of skb->hash from
+  before the encapsulation, which allows flow-based qdiscs to distinguish
+  between flows even though the outer packet header no longer has flow
+  information.
+
+It turns out that we can preserve these desirable properties in many cases,
+while still supporting the advanced flow isolation properties of sch_cake.
+This patch does so by reusing the skb->hash value as the flow_hash part of
+the hashing procedure in cake_hash() only in the following conditions:
+
+- If the skb->hash is marked as covering the flow headers (skb->l4_hash is
+  set)
+
+AND
+
+- NAT header rewriting is either disabled, or did not change any values
+  used for hashing. The latter is important to match local-origin packets
+  such as those of a tunnel endpoint.
+
+The immediate motivation for fixing this was the recent patch to WireGuard
+to preserve the skb->hash on encapsulation. As such, this is also what I
+tested against; with this patch, added latency under load for competing
+flows drops from ~8 ms to sub-1ms on an RRUL test over a WireGuard tunnel
+going through a virtual link shaped to 1Gbps using sch_cake. This matches
+the results we saw with a similar setup using sch_fq_codel when testing the
+WireGuard patch.
+
+Fixes: 046f6fd5daef ("sched: Add Common Applications Kept Enhanced (cake) qdisc")
+Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
+---
+ net/sched/sch_cake.c | 65 ++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 51 insertions(+), 14 deletions(-)
+
+--- a/net/sched/sch_cake.c
++++ b/net/sched/sch_cake.c
+@@ -584,26 +584,48 @@ static bool cobalt_should_drop(struct co
+ 	return drop;
+ }
+ 
+-static void cake_update_flowkeys(struct flow_keys *keys,
++static bool cake_update_flowkeys(struct flow_keys *keys,
+ 				 const struct sk_buff *skb)
+ {
+ #if IS_ENABLED(CONFIG_NF_CONNTRACK)
+ 	struct nf_conntrack_tuple tuple = {};
+-	bool rev = !skb->_nfct;
++	bool rev = !skb->_nfct, upd = false;
++	__be32 ip;
+ 
+ 	if (skb_protocol(skb, true) != htons(ETH_P_IP))
+-		return;
++		return false;
+ 
+ 	if (!nf_ct_get_tuple_skb(&tuple, skb))
+-		return;
++		return false;
+ 
+-	keys->addrs.v4addrs.src = rev ? tuple.dst.u3.ip : tuple.src.u3.ip;
+-	keys->addrs.v4addrs.dst = rev ? tuple.src.u3.ip : tuple.dst.u3.ip;
++	ip = rev ? tuple.dst.u3.ip : tuple.src.u3.ip;
++	if (ip != keys->addrs.v4addrs.src) {
++		keys->addrs.v4addrs.src = ip;
++		upd = true;
++	}
++	ip = rev ? tuple.src.u3.ip : tuple.dst.u3.ip;
++	if (ip != keys->addrs.v4addrs.dst) {
++		keys->addrs.v4addrs.dst = ip;
++		upd = true;
++	}
+ 
+ 	if (keys->ports.ports) {
+-		keys->ports.src = rev ? tuple.dst.u.all : tuple.src.u.all;
+-		keys->ports.dst = rev ? tuple.src.u.all : tuple.dst.u.all;
++		__be16 port;
++
++		port = rev ? tuple.dst.u.all : tuple.src.u.all;
++		if (port != keys->ports.src) {
++			keys->ports.src = port;
++			upd = true;
++		}
++		port = rev ? tuple.src.u.all : tuple.dst.u.all;
++		if (port != keys->ports.dst) {
++			port = keys->ports.dst;
++			upd = true;
++		}
+ 	}
++	return upd;
++#else
++	return false;
+ #endif
+ }
+ 
+@@ -624,23 +646,36 @@ static bool cake_ddst(int flow_mode)
+ static u32 cake_hash(struct cake_tin_data *q, const struct sk_buff *skb,
+ 		     int flow_mode, u16 flow_override, u16 host_override)
+ {
++	bool hash_flows = (!flow_override && !!(flow_mode & CAKE_FLOW_FLOWS));
++	bool hash_hosts = (!host_override && !!(flow_mode & CAKE_FLOW_HOSTS));
++	bool nat_enabled = !!(flow_mode & CAKE_FLOW_NAT_FLAG);
+ 	u32 flow_hash = 0, srchost_hash = 0, dsthost_hash = 0;
+ 	u16 reduced_hash, srchost_idx, dsthost_idx;
+ 	struct flow_keys keys, host_keys;
++	bool use_skbhash = skb->l4_hash;
+ 
+ 	if (unlikely(flow_mode == CAKE_FLOW_NONE))
+ 		return 0;
+ 
+-	/* If both overrides are set we can skip packet dissection entirely */
+-	if ((flow_override || !(flow_mode & CAKE_FLOW_FLOWS)) &&
+-	    (host_override || !(flow_mode & CAKE_FLOW_HOSTS)))
++	/* If both overrides are set, or we can use the SKB hash and nat mode is
++	 * disabled, we can skip packet dissection entirely. If nat mode is
++	 * enabled there's another check below after doing the conntrack lookup.
++	 */
++	if ((!hash_flows || (use_skbhash && !nat_enabled)) && !hash_hosts)
+ 		goto skip_hash;
+ 
+ 	skb_flow_dissect_flow_keys(skb, &keys,
+ 				   FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL);
+ 
+-	if (flow_mode & CAKE_FLOW_NAT_FLAG)
+-		cake_update_flowkeys(&keys, skb);
++	/* Don't use the SKB hash if we change the lookup keys from conntrack */
++	if (nat_enabled && cake_update_flowkeys(&keys, skb))
++		use_skbhash = false;
++
++	/* If we can still use the SKB hash and don't need the host hash, we can
++	 * skip the rest of the hashing procedure
++	 */
++	if (use_skbhash && !hash_hosts)
++		goto skip_hash;
+ 
+ 	/* flow_hash_from_keys() sorts the addresses by value, so we have
+ 	 * to preserve their order in a separate data structure to treat
+@@ -679,12 +714,14 @@ static u32 cake_hash(struct cake_tin_dat
+ 	/* This *must* be after the above switch, since as a
+ 	 * side-effect it sorts the src and dst addresses.
+ 	 */
+-	if (flow_mode & CAKE_FLOW_FLOWS)
++	if (hash_flows && !use_skbhash)
+ 		flow_hash = flow_hash_from_keys(&keys);
+ 
+ skip_hash:
+ 	if (flow_override)
+ 		flow_hash = flow_override - 1;
++	else if (use_skbhash)
++		flow_hash = skb->hash;
+ 	if (host_override) {
+ 		dsthost_hash = host_override - 1;
+ 		srchost_hash = host_override - 1;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/399-5.9-sch_cake-add-RFC-8622-LE-PHB-support-to-CAKE-diffser.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/399-5.9-sch_cake-add-RFC-8622-LE-PHB-support-to-CAKE-diffser.patch
new file mode 100644
index 0000000..e171b4c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/399-5.9-sch_cake-add-RFC-8622-LE-PHB-support-to-CAKE-diffser.patch
@@ -0,0 +1,57 @@
+From b8392808eb3fc28e523e28cb258c81ca246deb9b Mon Sep 17 00:00:00 2001
+From: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
+Date: Thu, 25 Jun 2020 22:18:00 +0200
+Subject: [PATCH] sch_cake: add RFC 8622 LE PHB support to CAKE diffserv
+ handling
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Change tin mapping on diffserv3, 4 & 8 for LE PHB support, in essence
+making LE a member of the Bulk tin.
+
+Bulk has the least priority and minimum of 1/16th total bandwidth in the
+face of higher priority traffic.
+
+NB: Diffserv 3 & 4 swap tin 0 & 1 priorities from the default order as
+found in diffserv8, in case anyone is wondering why it looks a bit odd.
+
+Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
+[ reword commit message slightly ]
+Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ net/sched/sch_cake.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/net/sched/sch_cake.c
++++ b/net/sched/sch_cake.c
+@@ -312,8 +312,8 @@ static const u8 precedence[] = {
+ };
+ 
+ static const u8 diffserv8[] = {
+-	2, 5, 1, 2, 4, 2, 2, 2,
+-	0, 2, 1, 2, 1, 2, 1, 2,
++	2, 0, 1, 2, 4, 2, 2, 2,
++	1, 2, 1, 2, 1, 2, 1, 2,
+ 	5, 2, 4, 2, 4, 2, 4, 2,
+ 	3, 2, 3, 2, 3, 2, 3, 2,
+ 	6, 2, 3, 2, 3, 2, 3, 2,
+@@ -323,7 +323,7 @@ static const u8 diffserv8[] = {
+ };
+ 
+ static const u8 diffserv4[] = {
+-	0, 2, 0, 0, 2, 0, 0, 0,
++	0, 1, 0, 0, 2, 0, 0, 0,
+ 	1, 0, 0, 0, 0, 0, 0, 0,
+ 	2, 0, 2, 0, 2, 0, 2, 0,
+ 	2, 0, 2, 0, 2, 0, 2, 0,
+@@ -334,7 +334,7 @@ static const u8 diffserv4[] = {
+ };
+ 
+ static const u8 diffserv3[] = {
+-	0, 0, 0, 0, 2, 0, 0, 0,
++	0, 1, 0, 0, 2, 0, 0, 0,
+ 	1, 0, 0, 0, 0, 0, 0, 0,
+ 	0, 0, 0, 0, 0, 0, 0, 0,
+ 	0, 0, 0, 0, 0, 0, 0, 0,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/400-v5.8-dt-bindings-mtd-partition-Document-the-slc-mode-prop.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/400-v5.8-dt-bindings-mtd-partition-Document-the-slc-mode-prop.patch
new file mode 100644
index 0000000..7926843
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/400-v5.8-dt-bindings-mtd-partition-Document-the-slc-mode-prop.patch
@@ -0,0 +1,28 @@
+From 422928a040fe17d17ded69c57903c7908423c7ef Mon Sep 17 00:00:00 2001
+From: Boris Brezillon <bbrezillon@kernel.org>
+Date: Sun, 3 May 2020 17:53:38 +0200
+Subject: [PATCH] dt-bindings: mtd: partition: Document the slc-mode property
+
+Add a boolean property to force a specific partition attached to an MLC
+NAND to be accessed in an emulated SLC mode this making this partition
+immune to paired-pages corruptions.
+
+Signed-off-by: Boris Brezillon <bbrezillon@kernel.org>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Link: https://lore.kernel.org/linux-mtd/20200503155341.16712-6-miquel.raynal@bootlin.com
+---
+ Documentation/devicetree/bindings/mtd/partition.txt | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/Documentation/devicetree/bindings/mtd/partition.txt
++++ b/Documentation/devicetree/bindings/mtd/partition.txt
+@@ -61,6 +61,9 @@ Optional properties:
+   clobbered.
+ - lock : Do not unlock the partition at initialization time (not supported on
+   all devices)
++- slc-mode: This parameter, if present, allows one to emulate SLC mode on a
++  partition attached to an MLC NAND thus making this partition immune to
++  paired-pages corruptions
+ 
+ Examples:
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/401-v5.11-dt-bindings-mtd-convert-fixed-partitions-to-the-json.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/401-v5.11-dt-bindings-mtd-convert-fixed-partitions-to-the-json.patch
new file mode 100644
index 0000000..8aded43
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/401-v5.11-dt-bindings-mtd-convert-fixed-partitions-to-the-json.patch
@@ -0,0 +1,324 @@
+From 04e9ab75267489224364fa510a88ada83e11c325 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Thu, 10 Dec 2020 18:23:52 +0100
+Subject: [PATCH] dt-bindings: mtd: convert "fixed-partitions" to the
+ json-schema
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This standardizes its documentation, allows validating with Makefile
+checks and helps writing DTS files.
+
+Noticeable changes:
+1. Dropped "Partitions can be represented by sub-nodes of a flash
+   device." as we also support subpartitions (don't have to be part of
+   flash device node)
+2. Dropped "to Linux" as bindings are meant to be os agnostic.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Link: https://lore.kernel.org/r/20201210172352.31632-1-zajec5@gmail.com
+Signed-off-by: Rob Herring <robh@kernel.org>
+---
+ .../devicetree/bindings/mtd/partition.txt     | 131 +--------------
+ .../mtd/partitions/fixed-partitions.yaml      | 152 ++++++++++++++++++
+ 2 files changed, 154 insertions(+), 129 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml
+
+--- a/Documentation/devicetree/bindings/mtd/partition.txt
++++ b/Documentation/devicetree/bindings/mtd/partition.txt
+@@ -24,137 +24,10 @@ another partitioning method.
+ Available bindings are listed in the "partitions" subdirectory.
+ 
+ 
+-Fixed Partitions
+-================
+-
+-Partitions can be represented by sub-nodes of a flash device. This can be used
+-on platforms which have strong conventions about which portions of a flash are
+-used for what purposes, but which don't use an on-flash partition table such
+-as RedBoot.
+-
+-The partition table should be a subnode of the flash node and should be named
+-'partitions'. This node should have the following property:
+-- compatible : (required) must be "fixed-partitions"
+-Partitions are then defined in subnodes of the partitions node.
++Deprecated: partitions defined in flash node
++============================================
+ 
+ For backwards compatibility partitions as direct subnodes of the flash device are
+ supported. This use is discouraged.
+ NOTE: also for backwards compatibility, direct subnodes that have a compatible
+ string are not considered partitions, as they may be used for other bindings.
+-
+-#address-cells & #size-cells must both be present in the partitions subnode of the
+-flash device. There are two valid values for both:
+-<1>: for partitions that require a single 32-bit cell to represent their
+-     size/address (aka the value is below 4 GiB)
+-<2>: for partitions that require two 32-bit cells to represent their
+-     size/address (aka the value is 4 GiB or greater).
+-
+-Required properties:
+-- reg : The partition's offset and size within the flash
+-
+-Optional properties:
+-- label : The label / name for this partition.  If omitted, the label is taken
+-  from the node name (excluding the unit address).
+-- read-only : This parameter, if present, is a hint to Linux that this
+-  partition should only be mounted read-only. This is usually used for flash
+-  partitions containing early-boot firmware images or data which should not be
+-  clobbered.
+-- lock : Do not unlock the partition at initialization time (not supported on
+-  all devices)
+-- slc-mode: This parameter, if present, allows one to emulate SLC mode on a
+-  partition attached to an MLC NAND thus making this partition immune to
+-  paired-pages corruptions
+-
+-Examples:
+-
+-
+-flash@0 {
+-	partitions {
+-		compatible = "fixed-partitions";
+-		#address-cells = <1>;
+-		#size-cells = <1>;
+-
+-		partition@0 {
+-			label = "u-boot";
+-			reg = <0x0000000 0x100000>;
+-			read-only;
+-		};
+-
+-		uimage@100000 {
+-			reg = <0x0100000 0x200000>;
+-		};
+-	};
+-};
+-
+-flash@1 {
+-	partitions {
+-		compatible = "fixed-partitions";
+-		#address-cells = <1>;
+-		#size-cells = <2>;
+-
+-		/* a 4 GiB partition */
+-		partition@0 {
+-			label = "filesystem";
+-			reg = <0x00000000 0x1 0x00000000>;
+-		};
+-	};
+-};
+-
+-flash@2 {
+-	partitions {
+-		compatible = "fixed-partitions";
+-		#address-cells = <2>;
+-		#size-cells = <2>;
+-
+-		/* an 8 GiB partition */
+-		partition@0 {
+-			label = "filesystem #1";
+-			reg = <0x0 0x00000000 0x2 0x00000000>;
+-		};
+-
+-		/* a 4 GiB partition */
+-		partition@200000000 {
+-			label = "filesystem #2";
+-			reg = <0x2 0x00000000 0x1 0x00000000>;
+-		};
+-	};
+-};
+-
+-flash@3 {
+-	partitions {
+-		compatible = "fixed-partitions";
+-		#address-cells = <1>;
+-		#size-cells = <1>;
+-
+-		partition@0 {
+-			label = "bootloader";
+-			reg = <0x000000 0x100000>;
+-			read-only;
+-		};
+-
+-		firmware@100000 {
+-			label = "firmware";
+-			reg = <0x100000 0xe00000>;
+-			compatible = "brcm,trx";
+-		};
+-
+-		calibration@f00000 {
+-			label = "calibration";
+-			reg = <0xf00000 0x100000>;
+-			compatible = "fixed-partitions";
+-			ranges = <0 0xf00000 0x100000>;
+-			#address-cells = <1>;
+-			#size-cells = <1>;
+-
+-			partition@0 {
+-				label = "wifi0";
+-				reg = <0x000000 0x080000>;
+-			};
+-
+-			partition@80000 {
+-				label = "wifi1";
+-				reg = <0x080000 0x080000>;
+-			};
+-		};
+-	};
+-};
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml
+@@ -0,0 +1,152 @@
++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/mtd/partitions/fixed-partitions.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Fixed partitions
++
++description: |
++  This binding can be used on platforms which have strong conventions about
++  which portions of a flash are used for what purposes, but which don't use an
++  on-flash partition table such as RedBoot.
++
++  The partition table should be a node named "partitions". Partitions are then
++  defined as subnodes.
++
++maintainers:
++  - Rafał Miłecki <rafal@milecki.pl>
++
++properties:
++  compatible:
++    const: fixed-partitions
++
++  "#address-cells": true
++
++  "#size-cells": true
++
++patternProperties:
++  "@[0-9a-f]+$":
++    description: node describing a single flash partition
++    type: object
++
++    properties:
++      reg:
++        description: partition's offset and size within the flash
++        maxItems: 1
++
++      label:
++        description: The label / name for this partition. If omitted, the label
++          is taken from the node name (excluding the unit address).
++
++      read-only:
++        description: This parameter, if present, is a hint that this partition
++          should only be mounted read-only. This is usually used for flash
++          partitions containing early-boot firmware images or data which should
++          not be clobbered.
++        type: boolean
++
++      lock:
++        description: Do not unlock the partition at initialization time (not
++          supported on all devices)
++        type: boolean
++
++      slc-mode:
++        description: This parameter, if present, allows one to emulate SLC mode
++          on a partition attached to an MLC NAND thus making this partition
++          immune to paired-pages corruptions
++        type: boolean
++
++    required:
++      - reg
++
++required:
++  - "#address-cells"
++  - "#size-cells"
++
++additionalProperties: true
++
++examples:
++  - |
++    partitions {
++        compatible = "fixed-partitions";
++        #address-cells = <1>;
++        #size-cells = <1>;
++
++        partition@0 {
++            label = "u-boot";
++            reg = <0x0000000 0x100000>;
++            read-only;
++        };
++
++        uimage@100000 {
++            reg = <0x0100000 0x200000>;
++        };
++    };
++  - |
++    partitions {
++        compatible = "fixed-partitions";
++        #address-cells = <1>;
++        #size-cells = <2>;
++
++        /* a 4 GiB partition */
++        partition@0 {
++            label = "filesystem";
++            reg = <0x00000000 0x1 0x00000000>;
++        };
++    };
++  - |
++    partitions {
++        compatible = "fixed-partitions";
++        #address-cells = <2>;
++        #size-cells = <2>;
++
++        /* an 8 GiB partition */
++        partition@0 {
++            label = "filesystem #1";
++            reg = <0x0 0x00000000 0x2 0x00000000>;
++        };
++
++        /* a 4 GiB partition */
++        partition@200000000 {
++            label = "filesystem #2";
++            reg = <0x2 0x00000000 0x1 0x00000000>;
++        };
++    };
++  - |
++    partitions {
++        compatible = "fixed-partitions";
++        #address-cells = <1>;
++        #size-cells = <1>;
++
++        partition@0 {
++            label = "bootloader";
++            reg = <0x000000 0x100000>;
++            read-only;
++        };
++
++        firmware@100000 {
++            compatible = "brcm,trx";
++            label = "firmware";
++            reg = <0x100000 0xe00000>;
++        };
++
++        calibration@f00000 {
++            compatible = "fixed-partitions";
++            label = "calibration";
++            reg = <0xf00000 0x100000>;
++            ranges = <0 0xf00000 0x100000>;
++            #address-cells = <1>;
++            #size-cells = <1>;
++
++            partition@0 {
++                label = "wifi0";
++                reg = <0x000000 0x080000>;
++            };
++
++            partition@80000 {
++                label = "wifi1";
++                reg = <0x080000 0x080000>;
++            };
++        };
++    };
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/402-v5.12-0001-dt-bindings-mtd-move-partition-binding-to-its-own-fi.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/402-v5.12-0001-dt-bindings-mtd-move-partition-binding-to-its-own-fi.patch
new file mode 100644
index 0000000..f3b1179
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/402-v5.12-0001-dt-bindings-mtd-move-partition-binding-to-its-own-fi.patch
@@ -0,0 +1,115 @@
+From 6418522022c706fd867b00b2571edba48b8fa8c7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Thu, 11 Feb 2021 23:04:25 +0100
+Subject: [PATCH] dt-bindings: mtd: move partition binding to its own file
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Single partition binding is quite common and may be:
+1. Used by multiple parsers
+2. Extended for more specific cases
+
+Move it to separated file to avoid code duplication.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Reviewed-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Richard Weinberger <richard@nod.at>
+---
+ .../mtd/partitions/fixed-partitions.yaml      | 33 +------------
+ .../bindings/mtd/partitions/partition.yaml    | 47 +++++++++++++++++++
+ 2 files changed, 48 insertions(+), 32 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/mtd/partitions/partition.yaml
+
+--- a/Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml
++++ b/Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml
+@@ -27,38 +27,7 @@ properties:
+ 
+ patternProperties:
+   "@[0-9a-f]+$":
+-    description: node describing a single flash partition
+-    type: object
+-
+-    properties:
+-      reg:
+-        description: partition's offset and size within the flash
+-        maxItems: 1
+-
+-      label:
+-        description: The label / name for this partition. If omitted, the label
+-          is taken from the node name (excluding the unit address).
+-
+-      read-only:
+-        description: This parameter, if present, is a hint that this partition
+-          should only be mounted read-only. This is usually used for flash
+-          partitions containing early-boot firmware images or data which should
+-          not be clobbered.
+-        type: boolean
+-
+-      lock:
+-        description: Do not unlock the partition at initialization time (not
+-          supported on all devices)
+-        type: boolean
+-
+-      slc-mode:
+-        description: This parameter, if present, allows one to emulate SLC mode
+-          on a partition attached to an MLC NAND thus making this partition
+-          immune to paired-pages corruptions
+-        type: boolean
+-
+-    required:
+-      - reg
++    $ref: "partition.yaml#"
+ 
+ required:
+   - "#address-cells"
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mtd/partitions/partition.yaml
+@@ -0,0 +1,47 @@
++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/mtd/partitions/partition.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Partition
++
++description: |
++  This binding describes a single flash partition. Each partition must have its
++  relative offset and size specified. Depending on partition function extra
++  properties can be used.
++
++maintainers:
++  - Rafał Miłecki <rafal@milecki.pl>
++
++properties:
++  reg:
++    description: partition's offset and size within the flash
++    maxItems: 1
++
++  label:
++    description: The label / name for this partition. If omitted, the label
++      is taken from the node name (excluding the unit address).
++
++  read-only:
++    description: This parameter, if present, is a hint that this partition
++      should only be mounted read-only. This is usually used for flash
++      partitions containing early-boot firmware images or data which should
++      not be clobbered.
++    type: boolean
++
++  lock:
++    description: Do not unlock the partition at initialization time (not
++      supported on all devices)
++    type: boolean
++
++  slc-mode:
++    description: This parameter, if present, allows one to emulate SLC mode
++      on a partition attached to an MLC NAND thus making this partition
++      immune to paired-pages corruptions
++    type: boolean
++
++required:
++  - reg
++
++additionalProperties: true
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/402-v5.12-0002-dt-bindings-mtd-add-binding-for-BCM4908-partitions.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/402-v5.12-0002-dt-bindings-mtd-add-binding-for-BCM4908-partitions.patch
new file mode 100644
index 0000000..8576c7d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/402-v5.12-0002-dt-bindings-mtd-add-binding-for-BCM4908-partitions.patch
@@ -0,0 +1,92 @@
+From 6e9dff6fe3fbc452f16566e4a7e293b0decefdba Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Thu, 11 Feb 2021 23:04:26 +0100
+Subject: [PATCH] dt-bindings: mtd: add binding for BCM4908 partitions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+BCM4908 uses fixed partitions layout but function of some partitions may
+vary. Some devices use multiple firmware partitions and those partitions
+should be marked to let system discover their purpose.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Richard Weinberger <richard@nod.at>
+---
+ .../partitions/brcm,bcm4908-partitions.yaml   | 70 +++++++++++++++++++
+ 1 file changed, 70 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/mtd/partitions/brcm,bcm4908-partitions.yaml
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm4908-partitions.yaml
+@@ -0,0 +1,70 @@
++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/mtd/partitions/brcm,bcm4908-partitions.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Broadcom BCM4908 partitioning
++
++description: |
++  Broadcom BCM4908 CFE bootloader supports two firmware partitions. One is used
++  for regular booting, the other is treated as fallback.
++
++  This binding allows defining all fixed partitions and marking those containing
++  firmware. System can use that information e.g. for booting or flashing
++  purposes.
++
++maintainers:
++  - Rafał Miłecki <rafal@milecki.pl>
++
++properties:
++  compatible:
++    const: brcm,bcm4908-partitions
++
++  "#address-cells":
++    enum: [ 1, 2 ]
++
++  "#size-cells":
++    enum: [ 1, 2 ]
++
++patternProperties:
++  "^partition@[0-9a-f]+$":
++    $ref: "partition.yaml#"
++    properties:
++      compatible:
++        const: brcm,bcm4908-firmware
++    unevaluatedProperties: false
++
++required:
++  - "#address-cells"
++  - "#size-cells"
++
++additionalProperties: false
++
++examples:
++  - |
++    partitions {
++        compatible = "brcm,bcm4908-partitions";
++        #address-cells = <1>;
++        #size-cells = <1>;
++
++        partition@0 {
++            label = "cferom";
++            reg = <0x0 0x100000>;
++        };
++
++        partition@100000 {
++            compatible = "brcm,bcm4908-firmware";
++            reg = <0x100000 0xf00000>;
++        };
++
++        partition@1000000 {
++            compatible = "brcm,bcm4908-firmware";
++            reg = <0x1000000 0xf00000>;
++        };
++
++        partition@1f00000 {
++            label = "calibration";
++            reg = <0x1f00000 0x100000>;
++        };
++    };
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/403-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/403-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch
new file mode 100644
index 0000000..8f292bd
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/403-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch
@@ -0,0 +1,648 @@
+From afbef8efb591792579c633a7c545f914c6165f82 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Thu, 11 Feb 2021 23:04:27 +0100
+Subject: [PATCH] mtd: parsers: ofpart: support BCM4908 fixed partitions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Some devices use fixed partitioning with some partitions requiring some
+extra logic. E.g. BCM4908 may have multiple firmware partitions but
+detecting currently used one requires checking bootloader parameters.
+
+To support such cases without duplicating a lot of code (without copying
+most of the ofpart.c code) support for post-parsing callback was added.
+
+BCM4908 support in ofpart can be enabled using config option and results
+in compiling & executing a specific callback. It simply reads offset of
+currently used firmware partition from the DT. Bootloader specifies it
+using the "brcm_blparms" property.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+---
+ drivers/mtd/parsers/Kconfig                   |  9 +++
+ drivers/mtd/parsers/Makefile                  |  2 +
+ drivers/mtd/parsers/ofpart_bcm4908.c          | 64 +++++++++++++++++++
+ drivers/mtd/parsers/ofpart_bcm4908.h          | 15 +++++
+ .../mtd/parsers/{ofpart.c => ofpart_core.c}   | 28 +++++++-
+ 5 files changed, 116 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/mtd/parsers/ofpart_bcm4908.c
+ create mode 100644 drivers/mtd/parsers/ofpart_bcm4908.h
+ rename drivers/mtd/parsers/{ofpart.c => ofpart_core.c} (88%)
+
+--- a/drivers/mtd/parsers/Kconfig
++++ b/drivers/mtd/parsers/Kconfig
+@@ -67,6 +67,15 @@ config MTD_OF_PARTS
+ 	  flash memory node, as described in
+ 	  Documentation/devicetree/bindings/mtd/partition.txt.
+ 
++config MTD_OF_PARTS_BCM4908
++	bool "BCM4908 partitioning support"
++	depends on MTD_OF_PARTS && (ARCH_BCM4908 || COMPILE_TEST)
++	default ARCH_BCM4908
++	help
++	  This provides partitions parser for BCM4908 family devices
++	  that can have multiple "firmware" partitions. It takes care of
++	  finding currently used one and backup ones.
++
+ config MTD_PARSER_IMAGETAG
+ 	tristate "Parser for BCM963XX Image Tag format partitions"
+ 	depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
+--- a/drivers/mtd/parsers/Makefile
++++ b/drivers/mtd/parsers/Makefile
+@@ -4,6 +4,8 @@ obj-$(CONFIG_MTD_BCM47XX_PARTS)		+= bcm4
+ obj-$(CONFIG_MTD_BCM63XX_PARTS)		+= bcm63xxpart.o
+ obj-$(CONFIG_MTD_CMDLINE_PARTS)		+= cmdlinepart.o
+ obj-$(CONFIG_MTD_OF_PARTS)		+= ofpart.o
++ofpart-y				+= ofpart_core.o
++ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908)	+= ofpart_bcm4908.o
+ obj-$(CONFIG_MTD_PARSER_IMAGETAG)	+= parser_imagetag.o
+ obj-$(CONFIG_MTD_AFS_PARTS)		+= afs.o
+ obj-$(CONFIG_MTD_PARSER_TRX)		+= parser_trx.o
+--- /dev/null
++++ b/drivers/mtd/parsers/ofpart_bcm4908.c
+@@ -0,0 +1,64 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/of.h>
++#include <linux/mtd/mtd.h>
++#include <linux/slab.h>
++#include <linux/mtd/partitions.h>
++
++#include "ofpart_bcm4908.h"
++
++#define BLPARAMS_FW_OFFSET		"NAND_RFS_OFS"
++
++static long long bcm4908_partitions_fw_offset(void)
++{
++	struct device_node *root;
++	struct property *prop;
++	const char *s;
++
++	root = of_find_node_by_path("/");
++	if (!root)
++		return -ENOENT;
++
++	of_property_for_each_string(root, "brcm_blparms", prop, s) {
++		size_t len = strlen(BLPARAMS_FW_OFFSET);
++		unsigned long offset;
++		int err;
++
++		if (strncmp(s, BLPARAMS_FW_OFFSET, len) || s[len] != '=')
++			continue;
++
++		err = kstrtoul(s + len + 1, 0, &offset);
++		if (err) {
++			pr_err("failed to parse %s\n", s + len + 1);
++			return err;
++		}
++
++		return offset << 10;
++	}
++
++	return -ENOENT;
++}
++
++int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts)
++{
++	long long fw_offset;
++	int i;
++
++	fw_offset = bcm4908_partitions_fw_offset();
++
++	for (i = 0; i < nr_parts; i++) {
++		if (of_device_is_compatible(parts[i].of_node, "brcm,bcm4908-firmware")) {
++			if (fw_offset < 0 || parts[i].offset == fw_offset)
++				parts[i].name = "firmware";
++			else
++				parts[i].name = "backup";
++		}
++	}
++
++	return 0;
++}
+--- /dev/null
++++ b/drivers/mtd/parsers/ofpart_bcm4908.h
+@@ -0,0 +1,15 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef __BCM4908_PARTITIONS_H
++#define __BCM4908_PARTITIONS_H
++
++#ifdef CONFIG_MTD_OF_PARTS_BCM4908
++int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts);
++#else
++static inline int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts,
++						int nr_parts)
++{
++	return -EOPNOTSUPP;
++}
++#endif
++
++#endif
+--- a/drivers/mtd/parsers/ofpart.c
++++ /dev/null
+@@ -1,236 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-/*
+- * Flash partitions described by the OF (or flattened) device tree
+- *
+- * Copyright © 2006 MontaVista Software Inc.
+- * Author: Vitaly Wool <vwool@ru.mvista.com>
+- *
+- * Revised to handle newer style flash binding by:
+- *   Copyright © 2007 David Gibson, IBM Corporation.
+- */
+-
+-#include <linux/module.h>
+-#include <linux/init.h>
+-#include <linux/of.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/slab.h>
+-#include <linux/mtd/partitions.h>
+-
+-static bool node_has_compatible(struct device_node *pp)
+-{
+-	return of_get_property(pp, "compatible", NULL);
+-}
+-
+-static int parse_fixed_partitions(struct mtd_info *master,
+-				  const struct mtd_partition **pparts,
+-				  struct mtd_part_parser_data *data)
+-{
+-	struct mtd_partition *parts;
+-	struct device_node *mtd_node;
+-	struct device_node *ofpart_node;
+-	const char *partname;
+-	struct device_node *pp;
+-	int nr_parts, i, ret = 0;
+-	bool dedicated = true;
+-
+-
+-	/* Pull of_node from the master device node */
+-	mtd_node = mtd_get_of_node(master);
+-	if (!mtd_node)
+-		return 0;
+-
+-	ofpart_node = of_get_child_by_name(mtd_node, "partitions");
+-	if (!ofpart_node) {
+-		/*
+-		 * We might get here even when ofpart isn't used at all (e.g.,
+-		 * when using another parser), so don't be louder than
+-		 * KERN_DEBUG
+-		 */
+-		pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n",
+-			 master->name, mtd_node);
+-		ofpart_node = mtd_node;
+-		dedicated = false;
+-	} else if (!of_device_is_compatible(ofpart_node, "fixed-partitions")) {
+-		/* The 'partitions' subnode might be used by another parser */
+-		return 0;
+-	}
+-
+-	/* First count the subnodes */
+-	nr_parts = 0;
+-	for_each_child_of_node(ofpart_node,  pp) {
+-		if (!dedicated && node_has_compatible(pp))
+-			continue;
+-
+-		nr_parts++;
+-	}
+-
+-	if (nr_parts == 0)
+-		return 0;
+-
+-	parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
+-	if (!parts)
+-		return -ENOMEM;
+-
+-	i = 0;
+-	for_each_child_of_node(ofpart_node,  pp) {
+-		const __be32 *reg;
+-		int len;
+-		int a_cells, s_cells;
+-
+-		if (!dedicated && node_has_compatible(pp))
+-			continue;
+-
+-		reg = of_get_property(pp, "reg", &len);
+-		if (!reg) {
+-			if (dedicated) {
+-				pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n",
+-					 master->name, pp,
+-					 mtd_node);
+-				goto ofpart_fail;
+-			} else {
+-				nr_parts--;
+-				continue;
+-			}
+-		}
+-
+-		a_cells = of_n_addr_cells(pp);
+-		s_cells = of_n_size_cells(pp);
+-		if (len / 4 != a_cells + s_cells) {
+-			pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n",
+-				 master->name, pp,
+-				 mtd_node);
+-			goto ofpart_fail;
+-		}
+-
+-		parts[i].offset = of_read_number(reg, a_cells);
+-		parts[i].size = of_read_number(reg + a_cells, s_cells);
+-		parts[i].of_node = pp;
+-
+-		partname = of_get_property(pp, "label", &len);
+-		if (!partname)
+-			partname = of_get_property(pp, "name", &len);
+-		parts[i].name = partname;
+-
+-		if (of_get_property(pp, "read-only", &len))
+-			parts[i].mask_flags |= MTD_WRITEABLE;
+-
+-		if (of_get_property(pp, "lock", &len))
+-			parts[i].mask_flags |= MTD_POWERUP_LOCK;
+-
+-		i++;
+-	}
+-
+-	if (!nr_parts)
+-		goto ofpart_none;
+-
+-	*pparts = parts;
+-	return nr_parts;
+-
+-ofpart_fail:
+-	pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n",
+-	       master->name, pp, mtd_node);
+-	ret = -EINVAL;
+-ofpart_none:
+-	of_node_put(pp);
+-	kfree(parts);
+-	return ret;
+-}
+-
+-static const struct of_device_id parse_ofpart_match_table[] = {
+-	{ .compatible = "fixed-partitions" },
+-	{},
+-};
+-MODULE_DEVICE_TABLE(of, parse_ofpart_match_table);
+-
+-static struct mtd_part_parser ofpart_parser = {
+-	.parse_fn = parse_fixed_partitions,
+-	.name = "fixed-partitions",
+-	.of_match_table = parse_ofpart_match_table,
+-};
+-
+-static int parse_ofoldpart_partitions(struct mtd_info *master,
+-				      const struct mtd_partition **pparts,
+-				      struct mtd_part_parser_data *data)
+-{
+-	struct mtd_partition *parts;
+-	struct device_node *dp;
+-	int i, plen, nr_parts;
+-	const struct {
+-		__be32 offset, len;
+-	} *part;
+-	const char *names;
+-
+-	/* Pull of_node from the master device node */
+-	dp = mtd_get_of_node(master);
+-	if (!dp)
+-		return 0;
+-
+-	part = of_get_property(dp, "partitions", &plen);
+-	if (!part)
+-		return 0; /* No partitions found */
+-
+-	pr_warn("Device tree uses obsolete partition map binding: %pOF\n", dp);
+-
+-	nr_parts = plen / sizeof(part[0]);
+-
+-	parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
+-	if (!parts)
+-		return -ENOMEM;
+-
+-	names = of_get_property(dp, "partition-names", &plen);
+-
+-	for (i = 0; i < nr_parts; i++) {
+-		parts[i].offset = be32_to_cpu(part->offset);
+-		parts[i].size   = be32_to_cpu(part->len) & ~1;
+-		/* bit 0 set signifies read only partition */
+-		if (be32_to_cpu(part->len) & 1)
+-			parts[i].mask_flags = MTD_WRITEABLE;
+-
+-		if (names && (plen > 0)) {
+-			int len = strlen(names) + 1;
+-
+-			parts[i].name = names;
+-			plen -= len;
+-			names += len;
+-		} else {
+-			parts[i].name = "unnamed";
+-		}
+-
+-		part++;
+-	}
+-
+-	*pparts = parts;
+-	return nr_parts;
+-}
+-
+-static struct mtd_part_parser ofoldpart_parser = {
+-	.parse_fn = parse_ofoldpart_partitions,
+-	.name = "ofoldpart",
+-};
+-
+-static int __init ofpart_parser_init(void)
+-{
+-	register_mtd_parser(&ofpart_parser);
+-	register_mtd_parser(&ofoldpart_parser);
+-	return 0;
+-}
+-
+-static void __exit ofpart_parser_exit(void)
+-{
+-	deregister_mtd_parser(&ofpart_parser);
+-	deregister_mtd_parser(&ofoldpart_parser);
+-}
+-
+-module_init(ofpart_parser_init);
+-module_exit(ofpart_parser_exit);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree");
+-MODULE_AUTHOR("Vitaly Wool, David Gibson");
+-/*
+- * When MTD core cannot find the requested parser, it tries to load the module
+- * with the same name. Since we provide the ofoldpart parser, we should have
+- * the corresponding alias.
+- */
+-MODULE_ALIAS("fixed-partitions");
+-MODULE_ALIAS("ofoldpart");
+--- /dev/null
++++ b/drivers/mtd/parsers/ofpart_core.c
+@@ -0,0 +1,260 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * Flash partitions described by the OF (or flattened) device tree
++ *
++ * Copyright © 2006 MontaVista Software Inc.
++ * Author: Vitaly Wool <vwool@ru.mvista.com>
++ *
++ * Revised to handle newer style flash binding by:
++ *   Copyright © 2007 David Gibson, IBM Corporation.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/of.h>
++#include <linux/mtd/mtd.h>
++#include <linux/slab.h>
++#include <linux/mtd/partitions.h>
++
++#include "ofpart_bcm4908.h"
++
++struct fixed_partitions_quirks {
++	int (*post_parse)(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts);
++};
++
++struct fixed_partitions_quirks bcm4908_partitions_quirks = {
++	.post_parse = bcm4908_partitions_post_parse,
++};
++
++static const struct of_device_id parse_ofpart_match_table[];
++
++static bool node_has_compatible(struct device_node *pp)
++{
++	return of_get_property(pp, "compatible", NULL);
++}
++
++static int parse_fixed_partitions(struct mtd_info *master,
++				  const struct mtd_partition **pparts,
++				  struct mtd_part_parser_data *data)
++{
++	const struct fixed_partitions_quirks *quirks;
++	const struct of_device_id *of_id;
++	struct mtd_partition *parts;
++	struct device_node *mtd_node;
++	struct device_node *ofpart_node;
++	const char *partname;
++	struct device_node *pp;
++	int nr_parts, i, ret = 0;
++	bool dedicated = true;
++
++	/* Pull of_node from the master device node */
++	mtd_node = mtd_get_of_node(master);
++	if (!mtd_node)
++		return 0;
++
++	ofpart_node = of_get_child_by_name(mtd_node, "partitions");
++	if (!ofpart_node) {
++		/*
++		 * We might get here even when ofpart isn't used at all (e.g.,
++		 * when using another parser), so don't be louder than
++		 * KERN_DEBUG
++		 */
++		pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n",
++			 master->name, mtd_node);
++		ofpart_node = mtd_node;
++		dedicated = false;
++	}
++
++	of_id = of_match_node(parse_ofpart_match_table, ofpart_node);
++	if (dedicated && !of_id) {
++		/* The 'partitions' subnode might be used by another parser */
++		return 0;
++	}
++
++	quirks = of_id ? of_id->data : NULL;
++
++	/* First count the subnodes */
++	nr_parts = 0;
++	for_each_child_of_node(ofpart_node,  pp) {
++		if (!dedicated && node_has_compatible(pp))
++			continue;
++
++		nr_parts++;
++	}
++
++	if (nr_parts == 0)
++		return 0;
++
++	parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
++	if (!parts)
++		return -ENOMEM;
++
++	i = 0;
++	for_each_child_of_node(ofpart_node,  pp) {
++		const __be32 *reg;
++		int len;
++		int a_cells, s_cells;
++
++		if (!dedicated && node_has_compatible(pp))
++			continue;
++
++		reg = of_get_property(pp, "reg", &len);
++		if (!reg) {
++			if (dedicated) {
++				pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n",
++					 master->name, pp,
++					 mtd_node);
++				goto ofpart_fail;
++			} else {
++				nr_parts--;
++				continue;
++			}
++		}
++
++		a_cells = of_n_addr_cells(pp);
++		s_cells = of_n_size_cells(pp);
++		if (len / 4 != a_cells + s_cells) {
++			pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n",
++				 master->name, pp,
++				 mtd_node);
++			goto ofpart_fail;
++		}
++
++		parts[i].offset = of_read_number(reg, a_cells);
++		parts[i].size = of_read_number(reg + a_cells, s_cells);
++		parts[i].of_node = pp;
++
++		partname = of_get_property(pp, "label", &len);
++		if (!partname)
++			partname = of_get_property(pp, "name", &len);
++		parts[i].name = partname;
++
++		if (of_get_property(pp, "read-only", &len))
++			parts[i].mask_flags |= MTD_WRITEABLE;
++
++		if (of_get_property(pp, "lock", &len))
++			parts[i].mask_flags |= MTD_POWERUP_LOCK;
++
++		i++;
++	}
++
++	if (!nr_parts)
++		goto ofpart_none;
++
++	if (quirks && quirks->post_parse)
++		quirks->post_parse(master, parts, nr_parts);
++
++	*pparts = parts;
++	return nr_parts;
++
++ofpart_fail:
++	pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n",
++	       master->name, pp, mtd_node);
++	ret = -EINVAL;
++ofpart_none:
++	of_node_put(pp);
++	kfree(parts);
++	return ret;
++}
++
++static const struct of_device_id parse_ofpart_match_table[] = {
++	/* Generic */
++	{ .compatible = "fixed-partitions" },
++	/* Customized */
++	{ .compatible = "brcm,bcm4908-partitions", .data = &bcm4908_partitions_quirks, },
++	{},
++};
++MODULE_DEVICE_TABLE(of, parse_ofpart_match_table);
++
++static struct mtd_part_parser ofpart_parser = {
++	.parse_fn = parse_fixed_partitions,
++	.name = "fixed-partitions",
++	.of_match_table = parse_ofpart_match_table,
++};
++
++static int parse_ofoldpart_partitions(struct mtd_info *master,
++				      const struct mtd_partition **pparts,
++				      struct mtd_part_parser_data *data)
++{
++	struct mtd_partition *parts;
++	struct device_node *dp;
++	int i, plen, nr_parts;
++	const struct {
++		__be32 offset, len;
++	} *part;
++	const char *names;
++
++	/* Pull of_node from the master device node */
++	dp = mtd_get_of_node(master);
++	if (!dp)
++		return 0;
++
++	part = of_get_property(dp, "partitions", &plen);
++	if (!part)
++		return 0; /* No partitions found */
++
++	pr_warn("Device tree uses obsolete partition map binding: %pOF\n", dp);
++
++	nr_parts = plen / sizeof(part[0]);
++
++	parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
++	if (!parts)
++		return -ENOMEM;
++
++	names = of_get_property(dp, "partition-names", &plen);
++
++	for (i = 0; i < nr_parts; i++) {
++		parts[i].offset = be32_to_cpu(part->offset);
++		parts[i].size   = be32_to_cpu(part->len) & ~1;
++		/* bit 0 set signifies read only partition */
++		if (be32_to_cpu(part->len) & 1)
++			parts[i].mask_flags = MTD_WRITEABLE;
++
++		if (names && (plen > 0)) {
++			int len = strlen(names) + 1;
++
++			parts[i].name = names;
++			plen -= len;
++			names += len;
++		} else {
++			parts[i].name = "unnamed";
++		}
++
++		part++;
++	}
++
++	*pparts = parts;
++	return nr_parts;
++}
++
++static struct mtd_part_parser ofoldpart_parser = {
++	.parse_fn = parse_ofoldpart_partitions,
++	.name = "ofoldpart",
++};
++
++static int __init ofpart_parser_init(void)
++{
++	register_mtd_parser(&ofpart_parser);
++	register_mtd_parser(&ofoldpart_parser);
++	return 0;
++}
++
++static void __exit ofpart_parser_exit(void)
++{
++	deregister_mtd_parser(&ofpart_parser);
++	deregister_mtd_parser(&ofoldpart_parser);
++}
++
++module_init(ofpart_parser_init);
++module_exit(ofpart_parser_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree");
++MODULE_AUTHOR("Vitaly Wool, David Gibson");
++/*
++ * When MTD core cannot find the requested parser, it tries to load the module
++ * with the same name. Since we provide the ofoldpart parser, we should have
++ * the corresponding alias.
++ */
++MODULE_ALIAS("fixed-partitions");
++MODULE_ALIAS("ofoldpart");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/404-v5.13-mtd-parsers-ofpart-limit-parsing-of-deprecated-DT-sy.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/404-v5.13-mtd-parsers-ofpart-limit-parsing-of-deprecated-DT-sy.patch
new file mode 100644
index 0000000..35058ad
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/404-v5.13-mtd-parsers-ofpart-limit-parsing-of-deprecated-DT-sy.patch
@@ -0,0 +1,69 @@
+From 2d751203aacf86a1b301a188d8551c7da91043ab Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Tue, 2 Mar 2021 20:00:12 +0100
+Subject: [PATCH] mtd: parsers: ofpart: limit parsing of deprecated DT syntax
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+For backward compatibility ofpart still supports the old syntax like:
+spi-flash@0 {
+	compatible = "jedec,spi-nor";
+	reg = <0x0>;
+
+	partition@0 {
+		label = "bootloader";
+		reg = <0x0 0x100000>;
+	};
+};
+(without "partitions" subnode).
+
+There is no reason however to support nested partitions without a clear
+"compatible" string like:
+partitions {
+	compatible = "fixed-partitions";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	partition@0 {
+		label = "bootloader";
+		reg = <0x0 0x100000>;
+
+		partition@0 {
+			label = "config";
+			reg = <0x80000 0x80000>;
+		};
+	};
+};
+(we never officially supported or documented that).
+
+Make sure ofpart doesn't attempt to parse above.
+
+Cc: Ansuel Smith <ansuelsmth@gmail.com>
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Link: https://lore.kernel.org/linux-mtd/20210302190012.1255-1-zajec5@gmail.com
+---
+ drivers/mtd/parsers/ofpart_core.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/mtd/parsers/ofpart_core.c
++++ b/drivers/mtd/parsers/ofpart_core.c
+@@ -53,7 +53,7 @@ static int parse_fixed_partitions(struct
+ 		return 0;
+ 
+ 	ofpart_node = of_get_child_by_name(mtd_node, "partitions");
+-	if (!ofpart_node) {
++	if (!ofpart_node && !mtd_is_partition(master)) {
+ 		/*
+ 		 * We might get here even when ofpart isn't used at all (e.g.,
+ 		 * when using another parser), so don't be louder than
+@@ -64,6 +64,8 @@ static int parse_fixed_partitions(struct
+ 		ofpart_node = mtd_node;
+ 		dedicated = false;
+ 	}
++	if (!ofpart_node)
++		return 0;
+ 
+ 	of_id = of_match_node(parse_ofpart_match_table, ofpart_node);
+ 	if (dedicated && !of_id) {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/405-v5.13-mtd-parsers-ofpart-make-symbol-bcm4908_partitions_qu.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/405-v5.13-mtd-parsers-ofpart-make-symbol-bcm4908_partitions_qu.patch
new file mode 100644
index 0000000..f1b778a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/405-v5.13-mtd-parsers-ofpart-make-symbol-bcm4908_partitions_qu.patch
@@ -0,0 +1,34 @@
+From b87b6d2d6f540e29c3f98e1572d64e560d73d6c1 Mon Sep 17 00:00:00 2001
+From: Wei Yongjun <weiyongjun1@huawei.com>
+Date: Thu, 4 Mar 2021 06:46:00 +0000
+Subject: [PATCH] mtd: parsers: ofpart: make symbol 'bcm4908_partitions_quirks'
+ static
+
+The sparse tool complains as follows:
+
+drivers/mtd/parsers/ofpart_core.c:25:32: warning:
+ symbol 'bcm4908_partitions_quirks' was not declared. Should it be static?
+
+This symbol is not used outside of ofpart_core.c, so this
+commit marks it static.
+
+Fixes: 457da931b608 ("mtd: parsers: ofpart: support BCM4908 fixed partitions")
+Reported-by: Hulk Robot <hulkci@huawei.com>
+Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Link: https://lore.kernel.org/linux-mtd/20210304064600.3279138-1-weiyongjun1@huawei.com
+---
+ drivers/mtd/parsers/ofpart_core.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/mtd/parsers/ofpart_core.c
++++ b/drivers/mtd/parsers/ofpart_core.c
+@@ -22,7 +22,7 @@ struct fixed_partitions_quirks {
+ 	int (*post_parse)(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts);
+ };
+ 
+-struct fixed_partitions_quirks bcm4908_partitions_quirks = {
++static struct fixed_partitions_quirks bcm4908_partitions_quirks = {
+ 	.post_parse = bcm4908_partitions_post_parse,
+ };
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/406-v5.13-0001-mtd-core-add-nvmem-cells-compatible-to-parse-mtd-as-.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/406-v5.13-0001-mtd-core-add-nvmem-cells-compatible-to-parse-mtd-as-.patch
new file mode 100644
index 0000000..ecea743
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/406-v5.13-0001-mtd-core-add-nvmem-cells-compatible-to-parse-mtd-as-.patch
@@ -0,0 +1,40 @@
+From 658c4448bbbf02a143abf1b89d09a3337ebd3ba6 Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth@gmail.com>
+Date: Fri, 12 Mar 2021 07:28:19 +0100
+Subject: [PATCH] mtd: core: add nvmem-cells compatible to parse mtd as nvmem
+ cells
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Partitions that contains the nvmem-cells compatible will register
+their direct subonodes as nvmem cells and the node will be treated as a
+nvmem provider.
+
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Tested-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Link: https://lore.kernel.org/linux-mtd/20210312062830.20548-1-ansuelsmth@gmail.com
+---
+ drivers/mtd/mtdcore.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/mtd/mtdcore.c
++++ b/drivers/mtd/mtdcore.c
+@@ -559,6 +559,7 @@ static int mtd_nvmem_reg_read(void *priv
+ 
+ static int mtd_nvmem_add(struct mtd_info *mtd)
+ {
++	struct device_node *node = mtd_get_of_node(mtd);
+ 	struct nvmem_config config = {};
+ 
+ 	config.id = -1;
+@@ -571,7 +572,7 @@ static int mtd_nvmem_add(struct mtd_info
+ 	config.stride = 1;
+ 	config.read_only = true;
+ 	config.root_only = true;
+-	config.no_of_node = true;
++	config.no_of_node = !of_device_is_compatible(node, "nvmem-cells");
+ 	config.priv = mtd;
+ 
+ 	mtd->nvmem = nvmem_register(&config);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/406-v5.13-0002-dt-bindings-nvmem-drop-nodename-restriction.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/406-v5.13-0002-dt-bindings-nvmem-drop-nodename-restriction.patch
new file mode 100644
index 0000000..c0515bd
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/406-v5.13-0002-dt-bindings-nvmem-drop-nodename-restriction.patch
@@ -0,0 +1,28 @@
+From 52981a0fa9f7d68641e0e6bb584054c6d9eb2056 Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth@gmail.com>
+Date: Fri, 12 Mar 2021 07:28:20 +0100
+Subject: [PATCH] dt-bindings: nvmem: drop $nodename restriction
+
+Drop $nodename restriction as now mtd partition can also be used as
+nvmem provider.
+
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Reviewed-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Link: https://lore.kernel.org/linux-mtd/20210312062830.20548-2-ansuelsmth@gmail.com
+---
+ Documentation/devicetree/bindings/nvmem/nvmem.yaml | 3 ---
+ 1 file changed, 3 deletions(-)
+
+--- a/Documentation/devicetree/bindings/nvmem/nvmem.yaml
++++ b/Documentation/devicetree/bindings/nvmem/nvmem.yaml
+@@ -20,9 +20,6 @@ description: |
+   storage device.
+ 
+ properties:
+-  $nodename:
+-    pattern: "^(eeprom|efuse|nvram)(@.*|-[0-9a-f])*$"
+-
+   "#address-cells":
+     const: 1
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/406-v5.13-0003-dt-bindings-mtd-Document-use-of-nvmem-cells-compatib.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/406-v5.13-0003-dt-bindings-mtd-Document-use-of-nvmem-cells-compatib.patch
new file mode 100644
index 0000000..552919f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/406-v5.13-0003-dt-bindings-mtd-Document-use-of-nvmem-cells-compatib.patch
@@ -0,0 +1,119 @@
+From ac42c46f983e4a9003a7bb91ad44a23ab7b8f534 Mon Sep 17 00:00:00 2001
+From: Ansuel Smith <ansuelsmth@gmail.com>
+Date: Fri, 12 Mar 2021 07:28:21 +0100
+Subject: [PATCH] dt-bindings: mtd: Document use of nvmem-cells compatible
+
+Document nvmem-cells compatible used to treat mtd partitions as a
+nvmem provider.
+
+Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+Reviewed-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Link: https://lore.kernel.org/linux-mtd/20210312062830.20548-3-ansuelsmth@gmail.com
+---
+ .../bindings/mtd/partitions/nvmem-cells.yaml  | 99 +++++++++++++++++++
+ 1 file changed, 99 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
+@@ -0,0 +1,99 @@
++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/mtd/partitions/nvmem-cells.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Nvmem cells
++
++description: |
++  Any partition containing the compatible "nvmem-cells" will register as a
++  nvmem provider.
++  Each direct subnodes represents a nvmem cell following the nvmem binding.
++  Nvmem binding to declare nvmem-cells can be found in:
++  Documentation/devicetree/bindings/nvmem/nvmem.yaml
++
++maintainers:
++  - Ansuel Smith <ansuelsmth@gmail.com>
++
++allOf:
++  - $ref: /schemas/nvmem/nvmem.yaml#
++
++properties:
++  compatible:
++    const: nvmem-cells
++
++required:
++  - compatible
++
++additionalProperties: true
++
++examples:
++  - |
++    partitions {
++      compatible = "fixed-partitions";
++      #address-cells = <1>;
++      #size-cells = <1>;
++
++      /* ... */
++
++      };
++      art: art@1200000 {
++        compatible = "nvmem-cells";
++        reg = <0x1200000 0x0140000>;
++        label = "art";
++        read-only;
++        #address-cells = <1>;
++        #size-cells = <1>;
++
++        macaddr_gmac1: macaddr_gmac1@0 {
++          reg = <0x0 0x6>;
++        };
++
++        macaddr_gmac2: macaddr_gmac2@6 {
++          reg = <0x6 0x6>;
++        };
++
++        pre_cal_24g: pre_cal_24g@1000 {
++          reg = <0x1000 0x2f20>;
++        };
++
++        pre_cal_5g: pre_cal_5g@5000{
++          reg = <0x5000 0x2f20>;
++        };
++      };
++  - |
++    partitions {
++        compatible = "fixed-partitions";
++        #address-cells = <1>;
++        #size-cells = <1>;
++
++        partition@0 {
++            label = "bootloader";
++            reg = <0x000000 0x100000>;
++            read-only;
++        };
++
++        firmware@100000 {
++            compatible = "brcm,trx";
++            label = "firmware";
++            reg = <0x100000 0xe00000>;
++        };
++
++        calibration@f00000 {
++            compatible = "nvmem-cells";
++            label = "calibration";
++            reg = <0xf00000 0x100000>;
++            ranges = <0 0xf00000 0x100000>;
++            #address-cells = <1>;
++            #size-cells = <1>;
++
++            wifi0@0 {
++                reg = <0x000000 0x080000>;
++            };
++
++            wifi1@80000 {
++                reg = <0x080000 0x080000>;
++            };
++        };
++    };
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/407-v5.13-0001-dt-bindings-mtd-add-binding-for-Linksys-Northstar-pa.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/407-v5.13-0001-dt-bindings-mtd-add-binding-for-Linksys-Northstar-pa.patch
new file mode 100644
index 0000000..35a4afd
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/407-v5.13-0001-dt-bindings-mtd-add-binding-for-Linksys-Northstar-pa.patch
@@ -0,0 +1,98 @@
+From 2fa7294175c76e1ec568aa75c1891fd908728c8d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Fri, 12 Mar 2021 14:49:18 +0100
+Subject: [PATCH] dt-bindings: mtd: add binding for Linksys Northstar
+ partitions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Linksys on Broadcom Northstar devices uses fixed flash layout with
+multiple firmware partitions.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Reviewed-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Link: https://lore.kernel.org/linux-mtd/20210312134919.7767-1-zajec5@gmail.com
+---
+ .../mtd/partitions/linksys,ns-partitions.yaml | 74 +++++++++++++++++++
+ 1 file changed, 74 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml
+@@ -0,0 +1,74 @@
++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/mtd/partitions/linksys,ns-partitions.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Linksys Northstar partitioning
++
++description: |
++  Linksys devices based on Broadcom Northstar architecture often use two
++  firmware partitions. One is used for regular booting, the other is treated as
++  fallback.
++
++  This binding allows defining all fixed partitions and marking those containing
++  firmware. System can use that information e.g. for booting or flashing
++  purposes.
++
++maintainers:
++  - Rafał Miłecki <rafal@milecki.pl>
++
++properties:
++  compatible:
++    const: linksys,ns-partitions
++
++  "#address-cells":
++    enum: [ 1, 2 ]
++
++  "#size-cells":
++    enum: [ 1, 2 ]
++
++patternProperties:
++  "^partition@[0-9a-f]+$":
++    $ref: "partition.yaml#"
++    properties:
++      compatible:
++        items:
++          - const: linksys,ns-firmware
++          - const: brcm,trx
++    unevaluatedProperties: false
++
++required:
++  - "#address-cells"
++  - "#size-cells"
++
++additionalProperties: false
++
++examples:
++  - |
++    partitions {
++        compatible = "linksys,ns-partitions";
++        #address-cells = <1>;
++        #size-cells = <1>;
++
++        partition@0 {
++            label = "boot";
++            reg = <0x0 0x100000>;
++            read-only;
++        };
++
++        partition@100000 {
++            label = "nvram";
++            reg = <0x100000 0x100000>;
++        };
++
++        partition@200000 {
++            compatible = "linksys,ns-firmware", "brcm,trx";
++            reg = <0x200000 0xf00000>;
++        };
++
++        partition@1100000 {
++            compatible = "linksys,ns-firmware", "brcm,trx";
++            reg = <0x1100000 0xf00000>;
++        };
++    };
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/407-v5.13-0002-mtd-parsers-ofpart-support-Linksys-Northstar-partiti.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/407-v5.13-0002-mtd-parsers-ofpart-support-Linksys-Northstar-partiti.patch
new file mode 100644
index 0000000..75eb939
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/407-v5.13-0002-mtd-parsers-ofpart-support-Linksys-Northstar-partiti.patch
@@ -0,0 +1,156 @@
+From 7134a2d026d942210b4d26d6059c9d979ca7866e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Fri, 12 Mar 2021 14:49:19 +0100
+Subject: [PATCH] mtd: parsers: ofpart: support Linksys Northstar partitions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This allows extending ofpart parser with support for Linksys Northstar
+devices. That support uses recently added quirks mechanism.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Link: https://lore.kernel.org/linux-mtd/20210312134919.7767-2-zajec5@gmail.com
+---
+ drivers/mtd/parsers/Kconfig             | 10 +++++
+ drivers/mtd/parsers/Makefile            |  1 +
+ drivers/mtd/parsers/ofpart_core.c       |  6 +++
+ drivers/mtd/parsers/ofpart_linksys_ns.c | 50 +++++++++++++++++++++++++
+ drivers/mtd/parsers/ofpart_linksys_ns.h | 18 +++++++++
+ 5 files changed, 85 insertions(+)
+ create mode 100644 drivers/mtd/parsers/ofpart_linksys_ns.c
+ create mode 100644 drivers/mtd/parsers/ofpart_linksys_ns.h
+
+--- a/drivers/mtd/parsers/Kconfig
++++ b/drivers/mtd/parsers/Kconfig
+@@ -76,6 +76,16 @@ config MTD_OF_PARTS_BCM4908
+ 	  that can have multiple "firmware" partitions. It takes care of
+ 	  finding currently used one and backup ones.
+ 
++config MTD_OF_PARTS_LINKSYS_NS
++	bool "Linksys Northstar partitioning support"
++	depends on MTD_OF_PARTS && (ARCH_BCM_5301X || ARCH_BCM4908 || COMPILE_TEST)
++	default ARCH_BCM_5301X
++	help
++	  This provides partitions parser for Linksys devices based on Broadcom
++	  Northstar architecture. Linksys commonly uses fixed flash layout with
++	  two "firmware" partitions. Currently used firmware has to be detected
++	  using CFE environment variable.
++
+ config MTD_PARSER_IMAGETAG
+ 	tristate "Parser for BCM963XX Image Tag format partitions"
+ 	depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
+--- a/drivers/mtd/parsers/Makefile
++++ b/drivers/mtd/parsers/Makefile
+@@ -6,6 +6,7 @@ obj-$(CONFIG_MTD_CMDLINE_PARTS)		+= cmdl
+ obj-$(CONFIG_MTD_OF_PARTS)		+= ofpart.o
+ ofpart-y				+= ofpart_core.o
+ ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908)	+= ofpart_bcm4908.o
++ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS)+= ofpart_linksys_ns.o
+ obj-$(CONFIG_MTD_PARSER_IMAGETAG)	+= parser_imagetag.o
+ obj-$(CONFIG_MTD_AFS_PARTS)		+= afs.o
+ obj-$(CONFIG_MTD_PARSER_TRX)		+= parser_trx.o
+--- a/drivers/mtd/parsers/ofpart_core.c
++++ b/drivers/mtd/parsers/ofpart_core.c
+@@ -17,6 +17,7 @@
+ #include <linux/mtd/partitions.h>
+ 
+ #include "ofpart_bcm4908.h"
++#include "ofpart_linksys_ns.h"
+ 
+ struct fixed_partitions_quirks {
+ 	int (*post_parse)(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts);
+@@ -26,6 +27,10 @@ static struct fixed_partitions_quirks bc
+ 	.post_parse = bcm4908_partitions_post_parse,
+ };
+ 
++static struct fixed_partitions_quirks linksys_ns_partitions_quirks = {
++	.post_parse = linksys_ns_partitions_post_parse,
++};
++
+ static const struct of_device_id parse_ofpart_match_table[];
+ 
+ static bool node_has_compatible(struct device_node *pp)
+@@ -164,6 +169,7 @@ static const struct of_device_id parse_o
+ 	{ .compatible = "fixed-partitions" },
+ 	/* Customized */
+ 	{ .compatible = "brcm,bcm4908-partitions", .data = &bcm4908_partitions_quirks, },
++	{ .compatible = "linksys,ns-partitions", .data = &linksys_ns_partitions_quirks, },
+ 	{},
+ };
+ MODULE_DEVICE_TABLE(of, parse_ofpart_match_table);
+--- /dev/null
++++ b/drivers/mtd/parsers/ofpart_linksys_ns.c
+@@ -0,0 +1,50 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
++ */
++
++#include <linux/bcm47xx_nvram.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include "ofpart_linksys_ns.h"
++
++#define NVRAM_BOOT_PART		"bootpartition"
++
++static int ofpart_linksys_ns_bootpartition(void)
++{
++	char buf[4];
++	int bootpartition;
++
++	/* Check CFE environment variable */
++	if (bcm47xx_nvram_getenv(NVRAM_BOOT_PART, buf, sizeof(buf)) > 0) {
++		if (!kstrtoint(buf, 0, &bootpartition))
++			return bootpartition;
++		pr_warn("Failed to parse %s value \"%s\"\n", NVRAM_BOOT_PART,
++			buf);
++	} else {
++		pr_warn("Failed to get NVRAM \"%s\"\n", NVRAM_BOOT_PART);
++	}
++
++	return 0;
++}
++
++int linksys_ns_partitions_post_parse(struct mtd_info *mtd,
++				     struct mtd_partition *parts,
++				     int nr_parts)
++{
++	int bootpartition = ofpart_linksys_ns_bootpartition();
++	int trx_idx = 0;
++	int i;
++
++	for (i = 0; i < nr_parts; i++) {
++		if (of_device_is_compatible(parts[i].of_node, "linksys,ns-firmware")) {
++			if (trx_idx++ == bootpartition)
++				parts[i].name = "firmware";
++			else
++				parts[i].name = "backup";
++		}
++	}
++
++	return 0;
++}
+--- /dev/null
++++ b/drivers/mtd/parsers/ofpart_linksys_ns.h
+@@ -0,0 +1,18 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef __OFPART_LINKSYS_NS_H
++#define __OFPART_LINKSYS_NS_H
++
++#ifdef CONFIG_MTD_OF_PARTS_LINKSYS_NS
++int linksys_ns_partitions_post_parse(struct mtd_info *mtd,
++				     struct mtd_partition *parts,
++				     int nr_parts);
++#else
++static inline int linksys_ns_partitions_post_parse(struct mtd_info *mtd,
++						   struct mtd_partition *parts,
++						   int nr_parts)
++{
++	return -EOPNOTSUPP;
++}
++#endif
++
++#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/410-mtd-fix-calculating-partition-end-address.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/410-mtd-fix-calculating-partition-end-address.patch
new file mode 100644
index 0000000..1eae015
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/410-mtd-fix-calculating-partition-end-address.patch
@@ -0,0 +1,28 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Mon, 9 Mar 2020 08:30:19 +0100
+Subject: [PATCH] mtd: fix calculating partition end address
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This fixes check for partitions that don't start at beginning of their
+parents. Missing partition's offset in formula could result in forcing
+read-only incorrectly.
+
+Fixes: 6750f61a13a0 ("mtd: improve calculating partition boundaries when checking for alignment")
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+---
+ drivers/mtd/mtdpart.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -524,7 +524,7 @@ static struct mtd_part *allocate_partiti
+ 			part->name);
+ 	}
+ 
+-	tmp = part_absolute_offset(parent) + slave->mtd.size;
++	tmp = part_absolute_offset(parent) + slave->offset + slave->mtd.size;
+ 	remainder = do_div(tmp, wr_alignment);
+ 	if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {
+ 		slave->mtd.flags &= ~MTD_WRITEABLE;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/600-v5.12-net-extract-napi-poll-functionality-to-__napi_poll.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/600-v5.12-net-extract-napi-poll-functionality-to-__napi_poll.patch
new file mode 100644
index 0000000..35aeb96
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/600-v5.12-net-extract-napi-poll-functionality-to-__napi_poll.patch
@@ -0,0 +1,88 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Mon, 8 Feb 2021 11:34:08 -0800
+Subject: [PATCH] net: extract napi poll functionality to __napi_poll()
+
+This commit introduces a new function __napi_poll() which does the main
+logic of the existing napi_poll() function, and will be called by other
+functions in later commits.
+This idea and implementation is done by Felix Fietkau <nbd@nbd.name> and
+is proposed as part of the patch to move napi work to work_queue
+context.
+This commit by itself is a code restructure.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Wei Wang <weiwan@google.com>
+Reviewed-by: Alexander Duyck <alexanderduyck@fb.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -6325,15 +6325,10 @@ void netif_napi_del(struct napi_struct *
+ }
+ EXPORT_SYMBOL(netif_napi_del);
+ 
+-static int napi_poll(struct napi_struct *n, struct list_head *repoll)
++static int __napi_poll(struct napi_struct *n, bool *repoll)
+ {
+-	void *have;
+ 	int work, weight;
+ 
+-	list_del_init(&n->poll_list);
+-
+-	have = netpoll_poll_lock(n);
+-
+ 	weight = n->weight;
+ 
+ 	/* This NAPI_STATE_SCHED test is for avoiding a race
+@@ -6351,7 +6346,7 @@ static int napi_poll(struct napi_struct
+ 	WARN_ON_ONCE(work > weight);
+ 
+ 	if (likely(work < weight))
+-		goto out_unlock;
++		return work;
+ 
+ 	/* Drivers must not modify the NAPI state if they
+ 	 * consume the entire weight.  In such cases this code
+@@ -6360,7 +6355,7 @@ static int napi_poll(struct napi_struct
+ 	 */
+ 	if (unlikely(napi_disable_pending(n))) {
+ 		napi_complete(n);
+-		goto out_unlock;
++		return work;
+ 	}
+ 
+ 	if (n->gro_bitmask) {
+@@ -6378,12 +6373,29 @@ static int napi_poll(struct napi_struct
+ 	if (unlikely(!list_empty(&n->poll_list))) {
+ 		pr_warn_once("%s: Budget exhausted after napi rescheduled\n",
+ 			     n->dev ? n->dev->name : "backlog");
+-		goto out_unlock;
++		return work;
+ 	}
+ 
+-	list_add_tail(&n->poll_list, repoll);
++	*repoll = true;
++
++	return work;
++}
++
++static int napi_poll(struct napi_struct *n, struct list_head *repoll)
++{
++	bool do_repoll = false;
++	void *have;
++	int work;
++
++	list_del_init(&n->poll_list);
++
++	have = netpoll_poll_lock(n);
++
++	work = __napi_poll(n, &do_repoll);
++
++	if (do_repoll)
++		list_add_tail(&n->poll_list, repoll);
+ 
+-out_unlock:
+ 	netpoll_poll_unlock(have);
+ 
+ 	return work;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/601-v5.12-net-implement-threaded-able-napi-poll-loop-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/601-v5.12-net-implement-threaded-able-napi-poll-loop-support.patch
new file mode 100644
index 0000000..0c548f3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/601-v5.12-net-implement-threaded-able-napi-poll-loop-support.patch
@@ -0,0 +1,261 @@
+From: Wei Wang <weiwan@google.com>
+Date: Mon, 8 Feb 2021 11:34:09 -0800
+Subject: [PATCH] net: implement threaded-able napi poll loop support
+
+This patch allows running each napi poll loop inside its own
+kernel thread.
+The kthread is created during netif_napi_add() if dev->threaded
+is set. And threaded mode is enabled in napi_enable(). We will
+provide a way to set dev->threaded and enable threaded mode
+without a device up/down in the following patch.
+
+Once that threaded mode is enabled and the kthread is
+started, napi_schedule() will wake-up such thread instead
+of scheduling the softirq.
+
+The threaded poll loop behaves quite likely the net_rx_action,
+but it does not have to manipulate local irqs and uses
+an explicit scheduling point based on netdev_budget.
+
+Co-developed-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Co-developed-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
+Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
+Co-developed-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Wei Wang <weiwan@google.com>
+Reviewed-by: Alexander Duyck <alexanderduyck@fb.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -340,6 +340,7 @@ struct napi_struct {
+ 	struct list_head	dev_list;
+ 	struct hlist_node	napi_hash_node;
+ 	unsigned int		napi_id;
++	struct task_struct	*thread;
+ };
+ 
+ enum {
+@@ -350,6 +351,7 @@ enum {
+ 	NAPI_STATE_HASHED,	/* In NAPI hash (busy polling possible) */
+ 	NAPI_STATE_NO_BUSY_POLL,/* Do not add in napi_hash, no busy polling */
+ 	NAPI_STATE_IN_BUSY_POLL,/* sk_busy_loop() owns this NAPI */
++	NAPI_STATE_THREADED,		/* The poll is performed inside its own thread*/
+ };
+ 
+ enum {
+@@ -360,6 +362,7 @@ enum {
+ 	NAPIF_STATE_HASHED	 = BIT(NAPI_STATE_HASHED),
+ 	NAPIF_STATE_NO_BUSY_POLL = BIT(NAPI_STATE_NO_BUSY_POLL),
+ 	NAPIF_STATE_IN_BUSY_POLL = BIT(NAPI_STATE_IN_BUSY_POLL),
++	NAPIF_STATE_THREADED	 = BIT(NAPI_STATE_THREADED),
+ };
+ 
+ enum gro_result {
+@@ -504,20 +507,7 @@ bool napi_hash_del(struct napi_struct *n
+  */
+ void napi_disable(struct napi_struct *n);
+ 
+-/**
+- *	napi_enable - enable NAPI scheduling
+- *	@n: NAPI context
+- *
+- * Resume NAPI from being scheduled on this context.
+- * Must be paired with napi_disable.
+- */
+-static inline void napi_enable(struct napi_struct *n)
+-{
+-	BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state));
+-	smp_mb__before_atomic();
+-	clear_bit(NAPI_STATE_SCHED, &n->state);
+-	clear_bit(NAPI_STATE_NPSVC, &n->state);
+-}
++void napi_enable(struct napi_struct *n);
+ 
+ /**
+  *	napi_synchronize - wait until NAPI is not running
+@@ -1783,6 +1773,8 @@ enum netdev_ml_priv_type {
+  *
+  *	@wol_enabled:	Wake-on-LAN is enabled
+  *
++ *	@threaded:	napi threaded mode is enabled
++ *
+  *	FIXME: cleanup struct net_device such that network protocol info
+  *	moves out.
+  */
+@@ -2075,6 +2067,7 @@ struct net_device {
+ 	struct lock_class_key	addr_list_lock_key;
+ 	bool			proto_down;
+ 	unsigned		wol_enabled:1;
++	unsigned		threaded:1;
+ };
+ #define to_net_dev(d) container_of(d, struct net_device, dev)
+ 
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -91,6 +91,7 @@
+ #include <linux/etherdevice.h>
+ #include <linux/ethtool.h>
+ #include <linux/skbuff.h>
++#include <linux/kthread.h>
+ #include <linux/bpf.h>
+ #include <linux/bpf_trace.h>
+ #include <net/net_namespace.h>
+@@ -1289,6 +1290,27 @@ void netdev_notify_peers(struct net_devi
+ }
+ EXPORT_SYMBOL(netdev_notify_peers);
+ 
++static int napi_threaded_poll(void *data);
++
++static int napi_kthread_create(struct napi_struct *n)
++{
++	int err = 0;
++
++	/* Create and wake up the kthread once to put it in
++	 * TASK_INTERRUPTIBLE mode to avoid the blocked task
++	 * warning and work with loadavg.
++	 */
++	n->thread = kthread_run(napi_threaded_poll, n, "napi/%s-%d",
++				n->dev->name, n->napi_id);
++	if (IS_ERR(n->thread)) {
++		err = PTR_ERR(n->thread);
++		pr_err("kthread_run failed with err %d\n", err);
++		n->thread = NULL;
++	}
++
++	return err;
++}
++
+ static int __dev_open(struct net_device *dev, struct netlink_ext_ack *extack)
+ {
+ 	const struct net_device_ops *ops = dev->netdev_ops;
+@@ -3888,6 +3910,21 @@ int gro_normal_batch __read_mostly = 8;
+ static inline void ____napi_schedule(struct softnet_data *sd,
+ 				     struct napi_struct *napi)
+ {
++	struct task_struct *thread;
++
++	if (test_bit(NAPI_STATE_THREADED, &napi->state)) {
++		/* Paired with smp_mb__before_atomic() in
++		 * napi_enable(). Use READ_ONCE() to guarantee
++		 * a complete read on napi->thread. Only call
++		 * wake_up_process() when it's not NULL.
++		 */
++		thread = READ_ONCE(napi->thread);
++		if (thread) {
++			wake_up_process(thread);
++			return;
++		}
++	}
++
+ 	list_add_tail(&napi->poll_list, &sd->poll_list);
+ 	__raise_softirq_irqoff(NET_RX_SOFTIRQ);
+ }
+@@ -6279,6 +6316,12 @@ void netif_napi_add(struct net_device *d
+ 	set_bit(NAPI_STATE_NPSVC, &napi->state);
+ 	list_add_rcu(&napi->dev_list, &dev->napi_list);
+ 	napi_hash_add(napi);
++	/* Create kthread for this napi if dev->threaded is set.
++	 * Clear dev->threaded if kthread creation failed so that
++	 * threaded mode will not be enabled in napi_enable().
++	 */
++	if (dev->threaded && napi_kthread_create(napi))
++		dev->threaded = 0;
+ }
+ EXPORT_SYMBOL(netif_napi_add);
+ 
+@@ -6295,9 +6338,28 @@ void napi_disable(struct napi_struct *n)
+ 	hrtimer_cancel(&n->timer);
+ 
+ 	clear_bit(NAPI_STATE_DISABLE, &n->state);
++	clear_bit(NAPI_STATE_THREADED, &n->state);
+ }
+ EXPORT_SYMBOL(napi_disable);
+ 
++/**
++ *	napi_enable - enable NAPI scheduling
++ *	@n: NAPI context
++ *
++ * Resume NAPI from being scheduled on this context.
++ * Must be paired with napi_disable.
++ */
++void napi_enable(struct napi_struct *n)
++{
++	BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state));
++	smp_mb__before_atomic();
++	clear_bit(NAPI_STATE_SCHED, &n->state);
++	clear_bit(NAPI_STATE_NPSVC, &n->state);
++	if (n->dev->threaded && n->thread)
++		set_bit(NAPI_STATE_THREADED, &n->state);
++}
++EXPORT_SYMBOL(napi_enable);
++
+ static void flush_gro_hash(struct napi_struct *napi)
+ {
+ 	int i;
+@@ -6322,6 +6384,11 @@ void netif_napi_del(struct napi_struct *
+ 
+ 	flush_gro_hash(napi);
+ 	napi->gro_bitmask = 0;
++
++	if (napi->thread) {
++		kthread_stop(napi->thread);
++		napi->thread = NULL;
++	}
+ }
+ EXPORT_SYMBOL(netif_napi_del);
+ 
+@@ -6401,6 +6468,51 @@ static int napi_poll(struct napi_struct
+ 	return work;
+ }
+ 
++static int napi_thread_wait(struct napi_struct *napi)
++{
++	set_current_state(TASK_INTERRUPTIBLE);
++
++	while (!kthread_should_stop() && !napi_disable_pending(napi)) {
++		if (test_bit(NAPI_STATE_SCHED, &napi->state)) {
++			WARN_ON(!list_empty(&napi->poll_list));
++			__set_current_state(TASK_RUNNING);
++			return 0;
++		}
++
++		schedule();
++		set_current_state(TASK_INTERRUPTIBLE);
++	}
++	__set_current_state(TASK_RUNNING);
++	return -1;
++}
++
++static int napi_threaded_poll(void *data)
++{
++	struct napi_struct *napi = data;
++	void *have;
++
++	while (!napi_thread_wait(napi)) {
++		for (;;) {
++			bool repoll = false;
++
++			local_bh_disable();
++
++			have = netpoll_poll_lock(napi);
++			__napi_poll(napi, &repoll);
++			netpoll_poll_unlock(have);
++
++			__kfree_skb_flush();
++			local_bh_enable();
++
++			if (!repoll)
++				break;
++
++			cond_resched();
++		}
++	}
++	return 0;
++}
++
+ static __latent_entropy void net_rx_action(struct softirq_action *h)
+ {
+ 	struct softnet_data *sd = this_cpu_ptr(&softnet_data);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/602-v5.12-net-add-sysfs-attribute-to-control-napi-threaded-mod.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/602-v5.12-net-add-sysfs-attribute-to-control-napi-threaded-mod.patch
new file mode 100644
index 0000000..bdc34a1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/602-v5.12-net-add-sysfs-attribute-to-control-napi-threaded-mod.patch
@@ -0,0 +1,177 @@
+From: Wei Wang <weiwan@google.com>
+Date: Mon, 8 Feb 2021 11:34:10 -0800
+Subject: [PATCH] net: add sysfs attribute to control napi threaded mode
+
+This patch adds a new sysfs attribute to the network device class.
+Said attribute provides a per-device control to enable/disable the
+threaded mode for all the napi instances of the given network device,
+without the need for a device up/down.
+User sets it to 1 or 0 to enable or disable threaded mode.
+Note: when switching between threaded and the current softirq based mode
+for a napi instance, it will not immediately take effect if the napi is
+currently being polled. The mode switch will happen for the next time
+napi_schedule() is called.
+
+Co-developed-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Co-developed-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
+Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
+Co-developed-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Wei Wang <weiwan@google.com>
+Reviewed-by: Alexander Duyck <alexanderduyck@fb.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/Documentation/ABI/testing/sysfs-class-net
++++ b/Documentation/ABI/testing/sysfs-class-net
+@@ -301,3 +301,18 @@ Contact:	netdev@vger.kernel.org
+ Description:
+ 		32-bit unsigned integer counting the number of times the link has
+ 		been down
++
++What:		/sys/class/net/<iface>/threaded
++Date:		Jan 2021
++KernelVersion:	5.12
++Contact:	netdev@vger.kernel.org
++Description:
++		Boolean value to control the threaded mode per device. User could
++		set this value to enable/disable threaded mode for all napi
++		belonging to this device, without the need to do device up/down.
++
++		Possible values:
++		== ==================================
++		0  threaded mode disabled for this dev
++		1  threaded mode enabled for this dev
++		== ==================================
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -498,6 +498,8 @@ static inline bool napi_complete(struct
+  */
+ bool napi_hash_del(struct napi_struct *napi);
+ 
++int dev_set_threaded(struct net_device *dev, bool threaded);
++
+ /**
+  *	napi_disable - prevent NAPI from scheduling
+  *	@n: NAPI context
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -3914,8 +3914,9 @@ static inline void ____napi_schedule(str
+ 
+ 	if (test_bit(NAPI_STATE_THREADED, &napi->state)) {
+ 		/* Paired with smp_mb__before_atomic() in
+-		 * napi_enable(). Use READ_ONCE() to guarantee
+-		 * a complete read on napi->thread. Only call
++		 * napi_enable()/dev_set_threaded().
++		 * Use READ_ONCE() to guarantee a complete
++		 * read on napi->thread. Only call
+ 		 * wake_up_process() when it's not NULL.
+ 		 */
+ 		thread = READ_ONCE(napi->thread);
+@@ -6293,6 +6294,49 @@ static void init_gro_hash(struct napi_st
+ 	napi->gro_bitmask = 0;
+ }
+ 
++int dev_set_threaded(struct net_device *dev, bool threaded)
++{
++	struct napi_struct *napi;
++	int err = 0;
++
++	if (dev->threaded == threaded)
++		return 0;
++
++	if (threaded) {
++		list_for_each_entry(napi, &dev->napi_list, dev_list) {
++			if (!napi->thread) {
++				err = napi_kthread_create(napi);
++				if (err) {
++					threaded = false;
++					break;
++				}
++			}
++		}
++	}
++
++	dev->threaded = threaded;
++
++	/* Make sure kthread is created before THREADED bit
++	 * is set.
++	 */
++	smp_mb__before_atomic();
++
++	/* Setting/unsetting threaded mode on a napi might not immediately
++	 * take effect, if the current napi instance is actively being
++	 * polled. In this case, the switch between threaded mode and
++	 * softirq mode will happen in the next round of napi_schedule().
++	 * This should not cause hiccups/stalls to the live traffic.
++	 */
++	list_for_each_entry(napi, &dev->napi_list, dev_list) {
++		if (threaded)
++			set_bit(NAPI_STATE_THREADED, &napi->state);
++		else
++			clear_bit(NAPI_STATE_THREADED, &napi->state);
++	}
++
++	return err;
++}
++
+ void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
+ 		    int (*poll)(struct napi_struct *, int), int weight)
+ {
+--- a/net/core/net-sysfs.c
++++ b/net/core/net-sysfs.c
+@@ -557,6 +557,45 @@ static ssize_t phys_switch_id_show(struc
+ }
+ static DEVICE_ATTR_RO(phys_switch_id);
+ 
++static ssize_t threaded_show(struct device *dev,
++			     struct device_attribute *attr, char *buf)
++{
++	struct net_device *netdev = to_net_dev(dev);
++	ssize_t ret = -EINVAL;
++
++	if (!rtnl_trylock())
++		return restart_syscall();
++
++	if (dev_isalive(netdev))
++		ret = sprintf(buf, fmt_dec, netdev->threaded);
++
++	rtnl_unlock();
++	return ret;
++}
++
++static int modify_napi_threaded(struct net_device *dev, unsigned long val)
++{
++	int ret;
++
++	if (list_empty(&dev->napi_list))
++		return -EOPNOTSUPP;
++
++	if (val != 0 && val != 1)
++		return -EOPNOTSUPP;
++
++	ret = dev_set_threaded(dev, val);
++
++	return ret;
++}
++
++static ssize_t threaded_store(struct device *dev,
++			      struct device_attribute *attr,
++			      const char *buf, size_t len)
++{
++	return netdev_store(dev, attr, buf, len, modify_napi_threaded);
++}
++static DEVICE_ATTR_RW(threaded);
++
+ static struct attribute *net_class_attrs[] __ro_after_init = {
+ 	&dev_attr_netdev_group.attr,
+ 	&dev_attr_type.attr,
+@@ -587,6 +626,7 @@ static struct attribute *net_class_attrs
+ 	&dev_attr_proto_down.attr,
+ 	&dev_attr_carrier_up_count.attr,
+ 	&dev_attr_carrier_down_count.attr,
++	&dev_attr_threaded.attr,
+ 	NULL,
+ };
+ ATTRIBUTE_GROUPS(net_class);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/603-v5.12-net-fix-race-between-napi-kthread-mode-and-busy-poll.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/603-v5.12-net-fix-race-between-napi-kthread-mode-and-busy-poll.patch
new file mode 100644
index 0000000..764f33e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/603-v5.12-net-fix-race-between-napi-kthread-mode-and-busy-poll.patch
@@ -0,0 +1,93 @@
+From: Wei Wang <weiwan@google.com>
+Date: Mon, 1 Mar 2021 17:21:13 -0800
+Subject: [PATCH] net: fix race between napi kthread mode and busy poll
+
+Currently, napi_thread_wait() checks for NAPI_STATE_SCHED bit to
+determine if the kthread owns this napi and could call napi->poll() on
+it. However, if socket busy poll is enabled, it is possible that the
+busy poll thread grabs this SCHED bit (after the previous napi->poll()
+invokes napi_complete_done() and clears SCHED bit) and tries to poll
+on the same napi. napi_disable() could grab the SCHED bit as well.
+This patch tries to fix this race by adding a new bit
+NAPI_STATE_SCHED_THREADED in napi->state. This bit gets set in
+____napi_schedule() if the threaded mode is enabled, and gets cleared
+in napi_complete_done(), and we only poll the napi in kthread if this
+bit is set. This helps distinguish the ownership of the napi between
+kthread and other scenarios and fixes the race issue.
+
+Fixes: 29863d41bb6e ("net: implement threaded-able napi poll loop support")
+Reported-by: Martin Zaharinov <micron10@gmail.com>
+Suggested-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Wei Wang <weiwan@google.com>
+Cc: Alexander Duyck <alexanderduyck@fb.com>
+Cc: Eric Dumazet <edumazet@google.com>
+Cc: Paolo Abeni <pabeni@redhat.com>
+Cc: Hannes Frederic Sowa <hannes@stressinduktion.org>
+---
+
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -352,6 +352,7 @@ enum {
+ 	NAPI_STATE_NO_BUSY_POLL,/* Do not add in napi_hash, no busy polling */
+ 	NAPI_STATE_IN_BUSY_POLL,/* sk_busy_loop() owns this NAPI */
+ 	NAPI_STATE_THREADED,		/* The poll is performed inside its own thread*/
++	NAPI_STATE_SCHED_THREADED,	/* Napi is currently scheduled in threaded mode */
+ };
+ 
+ enum {
+@@ -363,6 +364,7 @@ enum {
+ 	NAPIF_STATE_NO_BUSY_POLL = BIT(NAPI_STATE_NO_BUSY_POLL),
+ 	NAPIF_STATE_IN_BUSY_POLL = BIT(NAPI_STATE_IN_BUSY_POLL),
+ 	NAPIF_STATE_THREADED	 = BIT(NAPI_STATE_THREADED),
++	NAPIF_STATE_SCHED_THREADED	= BIT(NAPI_STATE_SCHED_THREADED),
+ };
+ 
+ enum gro_result {
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -3921,6 +3921,8 @@ static inline void ____napi_schedule(str
+ 		 */
+ 		thread = READ_ONCE(napi->thread);
+ 		if (thread) {
++			if (thread->state != TASK_INTERRUPTIBLE)
++				set_bit(NAPI_STATE_SCHED_THREADED, &napi->state);
+ 			wake_up_process(thread);
+ 			return;
+ 		}
+@@ -6081,7 +6083,8 @@ bool napi_complete_done(struct napi_stru
+ 
+ 		WARN_ON_ONCE(!(val & NAPIF_STATE_SCHED));
+ 
+-		new = val & ~(NAPIF_STATE_MISSED | NAPIF_STATE_SCHED);
++		new = val & ~(NAPIF_STATE_MISSED | NAPIF_STATE_SCHED |
++			      NAPIF_STATE_SCHED_THREADED);
+ 
+ 		/* If STATE_MISSED was set, leave STATE_SCHED set,
+ 		 * because we will call napi->poll() one more time.
+@@ -6514,16 +6517,25 @@ static int napi_poll(struct napi_struct
+ 
+ static int napi_thread_wait(struct napi_struct *napi)
+ {
++	bool woken = false;
++
+ 	set_current_state(TASK_INTERRUPTIBLE);
+ 
+ 	while (!kthread_should_stop() && !napi_disable_pending(napi)) {
+-		if (test_bit(NAPI_STATE_SCHED, &napi->state)) {
++		/* Testing SCHED_THREADED bit here to make sure the current
++		 * kthread owns this napi and could poll on this napi.
++		 * Testing SCHED bit is not enough because SCHED bit might be
++		 * set by some other busy poll thread or by napi_disable().
++		 */
++		if (test_bit(NAPI_STATE_SCHED_THREADED, &napi->state) || woken) {
+ 			WARN_ON(!list_empty(&napi->poll_list));
+ 			__set_current_state(TASK_RUNNING);
+ 			return 0;
+ 		}
+ 
+ 		schedule();
++		/* woken being true indicates this thread owns this napi. */
++		woken = true;
+ 		set_current_state(TASK_INTERRUPTIBLE);
+ 	}
+ 	__set_current_state(TASK_RUNNING);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/604-v5.12-net-fix-hangup-on-napi_disable-for-threaded-napi.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/604-v5.12-net-fix-hangup-on-napi_disable-for-threaded-napi.patch
new file mode 100644
index 0000000..5c48fdf
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/604-v5.12-net-fix-hangup-on-napi_disable-for-threaded-napi.patch
@@ -0,0 +1,53 @@
+From: Paolo Abeni <pabeni@redhat.com>
+Date: Fri, 9 Apr 2021 17:24:17 +0200
+Subject: [PATCH] net: fix hangup on napi_disable for threaded napi
+
+napi_disable() is subject to an hangup, when the threaded
+mode is enabled and the napi is under heavy traffic.
+
+If the relevant napi has been scheduled and the napi_disable()
+kicks in before the next napi_threaded_wait() completes - so
+that the latter quits due to the napi_disable_pending() condition,
+the existing code leaves the NAPI_STATE_SCHED bit set and the
+napi_disable() loop waiting for such bit will hang.
+
+This patch addresses the issue by dropping the NAPI_STATE_DISABLE
+bit test in napi_thread_wait(). The later napi_threaded_poll()
+iteration will take care of clearing the NAPI_STATE_SCHED.
+
+This also addresses a related problem reported by Jakub:
+before this patch a napi_disable()/napi_enable() pair killed
+the napi thread, effectively disabling the threaded mode.
+On the patched kernel napi_disable() simply stops scheduling
+the relevant thread.
+
+v1 -> v2:
+  - let the main napi_thread_poll() loop clear the SCHED bit
+
+Reported-by: Jakub Kicinski <kuba@kernel.org>
+Fixes: 29863d41bb6e ("net: implement threaded-able napi poll loop support")
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://lore.kernel.org/r/883923fa22745a9589e8610962b7dc59df09fb1f.1617981844.git.pabeni@redhat.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -6521,7 +6521,7 @@ static int napi_thread_wait(struct napi_
+ 
+ 	set_current_state(TASK_INTERRUPTIBLE);
+ 
+-	while (!kthread_should_stop() && !napi_disable_pending(napi)) {
++	while (!kthread_should_stop()) {
+ 		/* Testing SCHED_THREADED bit here to make sure the current
+ 		 * kthread owns this napi and could poll on this napi.
+ 		 * Testing SCHED bit is not enough because SCHED bit might be
+@@ -6539,6 +6539,7 @@ static int napi_thread_wait(struct napi_
+ 		set_current_state(TASK_INTERRUPTIBLE);
+ 	}
+ 	__set_current_state(TASK_RUNNING);
++
+ 	return -1;
+ }
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/610-v5.9-net-bridge-clear-bridge-s-private-skb-space-on-xmit.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/610-v5.9-net-bridge-clear-bridge-s-private-skb-space-on-xmit.patch
new file mode 100644
index 0000000..5704d05
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/610-v5.9-net-bridge-clear-bridge-s-private-skb-space-on-xmit.patch
@@ -0,0 +1,28 @@
+From: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
+Date: Fri, 31 Jul 2020 19:26:16 +0300
+Subject: [PATCH] net: bridge: clear bridge's private skb space on xmit
+
+We need to clear all of the bridge private skb variables as they can be
+stale due to the packet being recirculated through the stack and then
+transmitted through the bridge device. Similar memset is already done on
+bridge's input. We've seen cases where proxyarp_replied was 1 on routed
+multicast packets transmitted through the bridge to ports with neigh
+suppress which were getting dropped. Same thing can in theory happen with
+the port isolation bit as well.
+
+Fixes: 821f1b21cabb ("bridge: add new BR_NEIGH_SUPPRESS port flag to suppress arp and nd flood")
+Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/bridge/br_device.c
++++ b/net/bridge/br_device.c
+@@ -35,6 +35,8 @@ netdev_tx_t br_dev_xmit(struct sk_buff *
+ 	const unsigned char *dest;
+ 	u16 vid = 0;
+ 
++	memset(skb->cb, 0, sizeof(struct br_input_skb_cb));
++
+ 	rcu_read_lock();
+ 	nf_ops = rcu_dereference(nf_br_ops);
+ 	if (nf_ops && nf_ops->br_dev_xmit_hook(skb)) {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/700-v5.5-net-core-allow-fast-GRO-for-skbs-with-Ethernet-heade.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/700-v5.5-net-core-allow-fast-GRO-for-skbs-with-Ethernet-heade.patch
new file mode 100644
index 0000000..24b76cd
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/700-v5.5-net-core-allow-fast-GRO-for-skbs-with-Ethernet-heade.patch
@@ -0,0 +1,78 @@
+From: Alexander Lobakin <alobakin@dlink.ru>
+Date: Fri, 15 Nov 2019 12:11:35 +0300
+Subject: [PATCH] net: core: allow fast GRO for skbs with Ethernet header in
+ head
+
+Commit 78d3fd0b7de8 ("gro: Only use skb_gro_header for completely
+non-linear packets") back in May'09 (v2.6.31-rc1) has changed the
+original condition '!skb_headlen(skb)' to
+'skb->mac_header == skb->tail' in gro_reset_offset() saying: "Since
+the drivers that need this optimisation all provide completely
+non-linear packets" (note that this condition has become the current
+'skb_mac_header(skb) == skb_tail_pointer(skb)' later with commmit
+ced14f6804a9 ("net: Correct comparisons and calculations using
+skb->tail and skb-transport_header") without any functional changes).
+
+For now, we have the following rough statistics for v5.4-rc7:
+1) napi_gro_frags: 14
+2) napi_gro_receive with skb->head containing (most of) payload: 83
+3) napi_gro_receive with skb->head containing all the headers: 20
+4) napi_gro_receive with skb->head containing only Ethernet header: 2
+
+With the current condition, fast GRO with the usage of
+NAPI_GRO_CB(skb)->frag0 is available only in the [1] case.
+Packets pushed by [2] and [3] go through the 'slow' path, but
+it's not a problem for them as they already contain all the needed
+headers in skb->head, so pskb_may_pull() only moves skb->data.
+
+The layout of skbs in the fourth [4] case at the moment of
+dev_gro_receive() is identical to skbs that have come through [1],
+as napi_frags_skb() pulls Ethernet header to skb->head. The only
+difference is that the mentioned condition is always false for them,
+because skb_put() and friends irreversibly alter the tail pointer.
+They also go through the 'slow' path, but now every single
+pskb_may_pull() in every single .gro_receive() will call the *really*
+slow __pskb_pull_tail() to pull headers to head. This significantly
+decreases the overall performance for no visible reasons.
+
+The only two users of method [4] is:
+* drivers/staging/qlge
+* drivers/net/wireless/iwlwifi (all three variants: dvm, mvm, mvm-mq)
+
+Note that in case with wireless drivers we can't use [1]
+(napi_gro_frags()) at least for now and mac80211 stack always
+performs pushes and pulls anyways, so performance hit is inavoidable.
+
+At the moment of v2.6.31 the mentioned change was necessary (that's
+why I don't add the "Fixes:" tag), but it became obsolete since
+skb_gro_mac_header() has gone in commit a50e233c50db ("net-gro:
+restore frag0 optimization"), so we can simply revert the condition
+in gro_reset_offset() to allow skbs from [4] go through the 'fast'
+path just like in case [1].
+
+This was tested on a 600 MHz MIPS CPU and a custom driver and this
+patch gave boosts up to 40 Mbps to method [4] in both directions
+comparing to net-next, which made overall performance relatively
+close to [1] (without it, [4] is the slowest).
+
+v2:
+- Add more references and explanations to commit message
+- Fix some typos ibid
+- No functional changes
+
+Signed-off-by: Alexander Lobakin <alobakin@dlink.ru>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -5475,8 +5475,7 @@ static inline void skb_gro_reset_offset(
+ 	NAPI_GRO_CB(skb)->frag0 = NULL;
+ 	NAPI_GRO_CB(skb)->frag0_len = 0;
+ 
+-	if (skb_mac_header(skb) == skb_tail_pointer(skb) &&
+-	    pinfo->nr_frags &&
++	if (!skb_headlen(skb) && pinfo->nr_frags &&
+ 	    !PageHighMem(skb_frag_page(frag0)) &&
+ 	    (!NET_IP_ALIGN || !((skb_frag_off(frag0) + nhoff) & 3))) {
+ 		NAPI_GRO_CB(skb)->frag0 = skb_frag_address(frag0);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/716-v5.5-net-sfp-move-fwnode-parsing-into-sfp-bus-layer.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/716-v5.5-net-sfp-move-fwnode-parsing-into-sfp-bus-layer.patch
new file mode 100644
index 0000000..82c9fa5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/716-v5.5-net-sfp-move-fwnode-parsing-into-sfp-bus-layer.patch
@@ -0,0 +1,189 @@
+From 4054955f0da08c81d42220cb445820d474f1ac92 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Sat, 14 Sep 2019 14:21:22 +0100
+Subject: [PATCH 614/660] net: sfp: move fwnode parsing into sfp-bus layer
+
+Rather than parsing the sfp firmware node in phylink, parse it in the
+sfp-bus code, so we can re-use this code for PHYs without having to
+duplicate the parsing.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phylink.c | 21 ++++---------
+ drivers/net/phy/sfp-bus.c | 65 +++++++++++++++++++++++++--------------
+ include/linux/sfp.h       | 10 +++---
+ 3 files changed, 53 insertions(+), 43 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -565,31 +565,17 @@ static const struct sfp_upstream_ops sfp
+ static int phylink_register_sfp(struct phylink *pl,
+ 				struct fwnode_handle *fwnode)
+ {
+-	struct fwnode_reference_args ref;
++	struct sfp_bus *bus;
+ 	int ret;
+ 
+-	if (!fwnode)
+-		return 0;
+-
+-	ret = fwnode_property_get_reference_args(fwnode, "sfp", NULL,
+-						 0, 0, &ref);
+-	if (ret < 0) {
+-		if (ret == -ENOENT)
+-			return 0;
+-
+-		phylink_err(pl, "unable to parse \"sfp\" node: %d\n",
+-			    ret);
++	bus = sfp_register_upstream_node(fwnode, pl, &sfp_phylink_ops);
++	if (IS_ERR(bus)) {
++		ret = PTR_ERR(bus);
++		phylink_err(pl, "unable to attach SFP bus: %d\n", ret);
+ 		return ret;
+ 	}
+ 
+-	if (!fwnode_device_is_available(ref.fwnode)) {
+-		fwnode_handle_put(ref.fwnode);
+-		return 0;
+-	}
+-
+-	pl->sfp_bus = sfp_register_upstream(ref.fwnode, pl, &sfp_phylink_ops);
+-	if (!pl->sfp_bus)
+-		return -ENOMEM;
++	pl->sfp_bus = bus;
+ 
+ 	return 0;
+ }
+--- a/drivers/net/phy/sfp-bus.c
++++ b/drivers/net/phy/sfp-bus.c
+@@ -4,6 +4,7 @@
+ #include <linux/list.h>
+ #include <linux/mutex.h>
+ #include <linux/phylink.h>
++#include <linux/property.h>
+ #include <linux/rtnetlink.h>
+ #include <linux/slab.h>
+ 
+@@ -520,45 +521,68 @@ static void sfp_upstream_clear(struct sf
+ }
+ 
+ /**
+- * sfp_register_upstream() - Register the neighbouring device
+- * @fwnode: firmware node for the SFP bus
++ * sfp_register_upstream_node() - parse and register the neighbouring device
++ * @fwnode: firmware node for the parent device (MAC or PHY)
+  * @upstream: the upstream private data
+  * @ops: the upstream's &struct sfp_upstream_ops
+  *
+- * Register the upstream device (eg, PHY) with the SFP bus. MAC drivers
+- * should use phylink, which will call this function for them. Returns
+- * a pointer to the allocated &struct sfp_bus.
++ * Parse the parent device's firmware node for a SFP bus, and register the
++ * SFP bus using sfp_register_upstream().
+  *
+- * On error, returns %NULL.
++ * Returns: on success, a pointer to the sfp_bus structure,
++ *	    %NULL if no SFP is specified,
++ * 	    on failure, an error pointer value:
++ * 		corresponding to the errors detailed for
++ * 		fwnode_property_get_reference_args().
++ * 	        %-ENOMEM if we failed to allocate the bus.
++ *		an error from the upstream's connect_phy() method.
+  */
+-struct sfp_bus *sfp_register_upstream(struct fwnode_handle *fwnode,
+-				      void *upstream,
+-				      const struct sfp_upstream_ops *ops)
+-{
+-	struct sfp_bus *bus = sfp_bus_get(fwnode);
+-	int ret = 0;
+-
+-	if (bus) {
+-		rtnl_lock();
+-		bus->upstream_ops = ops;
+-		bus->upstream = upstream;
++struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode,
++					   void *upstream,
++					   const struct sfp_upstream_ops *ops)
++{
++	struct fwnode_reference_args ref;
++	struct sfp_bus *bus;
++	int ret;
+ 
+-		if (bus->sfp) {
+-			ret = sfp_register_bus(bus);
+-			if (ret)
+-				sfp_upstream_clear(bus);
+-		}
+-		rtnl_unlock();
++	ret = fwnode_property_get_reference_args(fwnode, "sfp", NULL,
++						 0, 0, &ref);
++	if (ret == -ENOENT)
++		return NULL;
++	else if (ret < 0)
++		return ERR_PTR(ret);
++
++	if (!fwnode_device_is_available(ref.fwnode)) {
++		fwnode_handle_put(ref.fwnode);
++		return NULL;
++	}
++
++	bus = sfp_bus_get(ref.fwnode);
++	fwnode_handle_put(ref.fwnode);
++	if (!bus)
++		return ERR_PTR(-ENOMEM);
++
++	rtnl_lock();
++	bus->upstream_ops = ops;
++	bus->upstream = upstream;
++
++	if (bus->sfp) {
++		ret = sfp_register_bus(bus);
++		if (ret)
++			sfp_upstream_clear(bus);
++	} else {
++		ret = 0;
+ 	}
++	rtnl_unlock();
+ 
+ 	if (ret) {
+ 		sfp_bus_put(bus);
+-		bus = NULL;
++		bus = ERR_PTR(ret);
+ 	}
+ 
+ 	return bus;
+ }
+-EXPORT_SYMBOL_GPL(sfp_register_upstream);
++EXPORT_SYMBOL_GPL(sfp_register_upstream_node);
+ 
+ /**
+  * sfp_unregister_upstream() - Unregister sfp bus
+--- a/include/linux/sfp.h
++++ b/include/linux/sfp.h
+@@ -508,9 +508,9 @@ int sfp_get_module_eeprom(struct sfp_bus
+ 			  u8 *data);
+ void sfp_upstream_start(struct sfp_bus *bus);
+ void sfp_upstream_stop(struct sfp_bus *bus);
+-struct sfp_bus *sfp_register_upstream(struct fwnode_handle *fwnode,
+-				      void *upstream,
+-				      const struct sfp_upstream_ops *ops);
++struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode,
++					   void *upstream,
++					   const struct sfp_upstream_ops *ops);
+ void sfp_unregister_upstream(struct sfp_bus *bus);
+ #else
+ static inline int sfp_parse_port(struct sfp_bus *bus,
+@@ -553,11 +553,11 @@ static inline void sfp_upstream_stop(str
+ {
+ }
+ 
+-static inline struct sfp_bus *sfp_register_upstream(
++static inline struct sfp_bus *sfp_register_upstream_node(
+ 	struct fwnode_handle *fwnode, void *upstream,
+ 	const struct sfp_upstream_ops *ops)
+ {
+-	return (struct sfp_bus *)-1;
++	return NULL;
+ }
+ 
+ static inline void sfp_unregister_upstream(struct sfp_bus *bus)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/717-v5.5-net-sfp-rework-upstream-interface.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/717-v5.5-net-sfp-rework-upstream-interface.patch
new file mode 100644
index 0000000..907b9dc
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/717-v5.5-net-sfp-rework-upstream-interface.patch
@@ -0,0 +1,254 @@
+From 863b5b6941f9f43b924393b6ba2b36647e7dee42 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Thu, 7 Nov 2019 17:06:08 +0000
+Subject: [PATCH 615/660] net: sfp: rework upstream interface
+
+The current upstream interface is an all-or-nothing, which is
+sub-optimal for future changes, as it doesn't allow the upstream driver
+to prepare for the SFP module becoming available, as it is at boot.
+
+Switch to a find-sfp-bus, add-upstream, del-upstream, put-sfp-bus
+interface structure instead, which allows the upstream driver to
+prepare for a module being available as soon as add-upstream is called.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phylink.c | 10 +++--
+ drivers/net/phy/sfp-bus.c | 92 +++++++++++++++++++++++++++------------
+ include/linux/sfp.h       | 25 +++++++----
+ 3 files changed, 88 insertions(+), 39 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -568,7 +568,7 @@ static int phylink_register_sfp(struct p
+ 	struct sfp_bus *bus;
+ 	int ret;
+ 
+-	bus = sfp_register_upstream_node(fwnode, pl, &sfp_phylink_ops);
++	bus = sfp_bus_find_fwnode(fwnode);
+ 	if (IS_ERR(bus)) {
+ 		ret = PTR_ERR(bus);
+ 		phylink_err(pl, "unable to attach SFP bus: %d\n", ret);
+@@ -577,7 +577,10 @@ static int phylink_register_sfp(struct p
+ 
+ 	pl->sfp_bus = bus;
+ 
+-	return 0;
++	ret = sfp_bus_add_upstream(bus, pl, &sfp_phylink_ops);
++	sfp_bus_put(bus);
++
++	return ret;
+ }
+ 
+ /**
+@@ -675,8 +678,7 @@ EXPORT_SYMBOL_GPL(phylink_create);
+  */
+ void phylink_destroy(struct phylink *pl)
+ {
+-	if (pl->sfp_bus)
+-		sfp_unregister_upstream(pl->sfp_bus);
++	sfp_bus_del_upstream(pl->sfp_bus);
+ 	if (pl->link_gpio)
+ 		gpiod_put(pl->link_gpio);
+ 
+--- a/drivers/net/phy/sfp-bus.c
++++ b/drivers/net/phy/sfp-bus.c
+@@ -404,10 +404,19 @@ static void sfp_bus_release(struct kref
+ 	kfree(bus);
+ }
+ 
+-static void sfp_bus_put(struct sfp_bus *bus)
++/**
++ * sfp_bus_put() - put a reference on the &struct sfp_bus
++ * bus: the &struct sfp_bus found via sfp_bus_find_fwnode()
++ *
++ * Put a reference on the &struct sfp_bus and free the underlying structure
++ * if this was the last reference.
++ */
++void sfp_bus_put(struct sfp_bus *bus)
+ {
+-	kref_put_mutex(&bus->kref, sfp_bus_release, &sfp_mutex);
++	if (bus)
++		kref_put_mutex(&bus->kref, sfp_bus_release, &sfp_mutex);
+ }
++EXPORT_SYMBOL_GPL(sfp_bus_put);
+ 
+ static int sfp_register_bus(struct sfp_bus *bus)
+ {
+@@ -423,11 +432,11 @@ static int sfp_register_bus(struct sfp_b
+ 				return ret;
+ 		}
+ 	}
++	bus->registered = true;
+ 	bus->socket_ops->attach(bus->sfp);
+ 	if (bus->started)
+ 		bus->socket_ops->start(bus->sfp);
+ 	bus->upstream_ops->attach(bus->upstream, bus);
+-	bus->registered = true;
+ 	return 0;
+ }
+ 
+@@ -521,13 +530,12 @@ static void sfp_upstream_clear(struct sf
+ }
+ 
+ /**
+- * sfp_register_upstream_node() - parse and register the neighbouring device
++ * sfp_bus_find_fwnode() - parse and locate the SFP bus from fwnode
+  * @fwnode: firmware node for the parent device (MAC or PHY)
+- * @upstream: the upstream private data
+- * @ops: the upstream's &struct sfp_upstream_ops
+  *
+- * Parse the parent device's firmware node for a SFP bus, and register the
+- * SFP bus using sfp_register_upstream().
++ * Parse the parent device's firmware node for a SFP bus, and locate
++ * the sfp_bus structure, incrementing its reference count.  This must
++ * be put via sfp_bus_put() when done.
+  *
+  * Returns: on success, a pointer to the sfp_bus structure,
+  *	    %NULL if no SFP is specified,
+@@ -537,9 +545,7 @@ static void sfp_upstream_clear(struct sf
+  * 	        %-ENOMEM if we failed to allocate the bus.
+  *		an error from the upstream's connect_phy() method.
+  */
+-struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode,
+-					   void *upstream,
+-					   const struct sfp_upstream_ops *ops)
++struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode)
+ {
+ 	struct fwnode_reference_args ref;
+ 	struct sfp_bus *bus;
+@@ -562,7 +568,39 @@ struct sfp_bus *sfp_register_upstream_no
+ 	if (!bus)
+ 		return ERR_PTR(-ENOMEM);
+ 
++	return bus;
++}
++EXPORT_SYMBOL_GPL(sfp_bus_find_fwnode);
++
++/**
++ * sfp_bus_add_upstream() - parse and register the neighbouring device
++ * @bus: the &struct sfp_bus found via sfp_bus_find_fwnode()
++ * @upstream: the upstream private data
++ * @ops: the upstream's &struct sfp_upstream_ops
++ *
++ * Add upstream driver for the SFP bus, and if the bus is complete, register
++ * the SFP bus using sfp_register_upstream().  This takes a reference on the
++ * bus, so it is safe to put the bus after this call.
++ *
++ * Returns: on success, a pointer to the sfp_bus structure,
++ *	    %NULL if no SFP is specified,
++ * 	    on failure, an error pointer value:
++ * 		corresponding to the errors detailed for
++ * 		fwnode_property_get_reference_args().
++ * 	        %-ENOMEM if we failed to allocate the bus.
++ *		an error from the upstream's connect_phy() method.
++ */
++int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
++			 const struct sfp_upstream_ops *ops)
++{
++	int ret;
++
++	/* If no bus, return success */
++	if (!bus)
++		return 0;
++
+ 	rtnl_lock();
++	kref_get(&bus->kref);
+ 	bus->upstream_ops = ops;
+ 	bus->upstream = upstream;
+ 
+@@ -575,33 +613,33 @@ struct sfp_bus *sfp_register_upstream_no
+ 	}
+ 	rtnl_unlock();
+ 
+-	if (ret) {
++	if (ret)
+ 		sfp_bus_put(bus);
+-		bus = ERR_PTR(ret);
+-	}
+ 
+-	return bus;
++	return ret;
+ }
+-EXPORT_SYMBOL_GPL(sfp_register_upstream_node);
++EXPORT_SYMBOL_GPL(sfp_bus_add_upstream);
+ 
+ /**
+- * sfp_unregister_upstream() - Unregister sfp bus
++ * sfp_bus_del_upstream() - Delete a sfp bus
+  * @bus: a pointer to the &struct sfp_bus structure for the sfp module
+  *
+- * Unregister a previously registered upstream connection for the SFP
+- * module. @bus is returned from sfp_register_upstream().
++ * Delete a previously registered upstream connection for the SFP
++ * module. @bus should have been added by sfp_bus_add_upstream().
+  */
+-void sfp_unregister_upstream(struct sfp_bus *bus)
++void sfp_bus_del_upstream(struct sfp_bus *bus)
+ {
+-	rtnl_lock();
+-	if (bus->sfp)
+-		sfp_unregister_bus(bus);
+-	sfp_upstream_clear(bus);
+-	rtnl_unlock();
++	if (bus) {
++		rtnl_lock();
++		if (bus->sfp)
++			sfp_unregister_bus(bus);
++		sfp_upstream_clear(bus);
++		rtnl_unlock();
+ 
+-	sfp_bus_put(bus);
++		sfp_bus_put(bus);
++	}
+ }
+-EXPORT_SYMBOL_GPL(sfp_unregister_upstream);
++EXPORT_SYMBOL_GPL(sfp_bus_del_upstream);
+ 
+ /* Socket driver entry points */
+ int sfp_add_phy(struct sfp_bus *bus, struct phy_device *phydev)
+--- a/include/linux/sfp.h
++++ b/include/linux/sfp.h
+@@ -508,10 +508,11 @@ int sfp_get_module_eeprom(struct sfp_bus
+ 			  u8 *data);
+ void sfp_upstream_start(struct sfp_bus *bus);
+ void sfp_upstream_stop(struct sfp_bus *bus);
+-struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode,
+-					   void *upstream,
+-					   const struct sfp_upstream_ops *ops);
+-void sfp_unregister_upstream(struct sfp_bus *bus);
++void sfp_bus_put(struct sfp_bus *bus);
++struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode);
++int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
++			 const struct sfp_upstream_ops *ops);
++void sfp_bus_del_upstream(struct sfp_bus *bus);
+ #else
+ static inline int sfp_parse_port(struct sfp_bus *bus,
+ 				 const struct sfp_eeprom_id *id,
+@@ -553,14 +554,22 @@ static inline void sfp_upstream_stop(str
+ {
+ }
+ 
+-static inline struct sfp_bus *sfp_register_upstream_node(
+-	struct fwnode_handle *fwnode, void *upstream,
+-	const struct sfp_upstream_ops *ops)
++static inline void sfp_bus_put(struct sfp_bus *bus)
++{
++}
++
++static inline struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode)
+ {
+ 	return NULL;
+ }
+ 
+-static inline void sfp_unregister_upstream(struct sfp_bus *bus)
++static int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
++				const struct sfp_upstream_ops *ops)
++{
++	return 0;
++}
++
++static inline void sfp_bus_del_upstream(struct sfp_bus *bus)
+ {
+ }
+ #endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/718-v5.5-net-sfp-fix-sfp_bus_put-kernel-documentation.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/718-v5.5-net-sfp-fix-sfp_bus_put-kernel-documentation.patch
new file mode 100644
index 0000000..c7bfd8a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/718-v5.5-net-sfp-fix-sfp_bus_put-kernel-documentation.patch
@@ -0,0 +1,27 @@
+From ea7bfd81921827d334c2a23bd11ef0e4e2abafd2 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Sat, 9 Nov 2019 08:13:50 +0000
+Subject: [PATCH 616/660] net: sfp: fix sfp_bus_put() kernel documentation
+
+The kbuild test robot found a problem with htmldocs with the recent
+change to the SFP interfaces.  Fix the kernel documentation for
+sfp_bus_put() which was missing an '@' before the argument name
+description.
+
+Fixes: 727b3668b730 ("net: sfp: rework upstream interface")
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp-bus.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/phy/sfp-bus.c
++++ b/drivers/net/phy/sfp-bus.c
+@@ -406,7 +406,7 @@ static void sfp_bus_release(struct kref
+ 
+ /**
+  * sfp_bus_put() - put a reference on the &struct sfp_bus
+- * bus: the &struct sfp_bus found via sfp_bus_find_fwnode()
++ * @bus: the &struct sfp_bus found via sfp_bus_find_fwnode()
+  *
+  * Put a reference on the &struct sfp_bus and free the underlying structure
+  * if this was the last reference.
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/719-v5.5-net-sfp-fix-sfp_bus_add_upstream-warning.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/719-v5.5-net-sfp-fix-sfp_bus_add_upstream-warning.patch
new file mode 100644
index 0000000..9528049
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/719-v5.5-net-sfp-fix-sfp_bus_add_upstream-warning.patch
@@ -0,0 +1,27 @@
+From f76d84cd85f8bd3f083495f7ca723822cba8abc9 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Mon, 11 Nov 2019 10:23:35 +0000
+Subject: [PATCH 617/660] net: sfp: fix sfp_bus_add_upstream() warning
+
+When building with SFP disabled, the stub for sfp_bus_add_upstream()
+missed "inline".  Add it.
+
+Fixes: 727b3668b730 ("net: sfp: rework upstream interface")
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ include/linux/sfp.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/include/linux/sfp.h
++++ b/include/linux/sfp.h
+@@ -563,8 +563,8 @@ static inline struct sfp_bus *sfp_bus_fi
+ 	return NULL;
+ }
+ 
+-static int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
+-				const struct sfp_upstream_ops *ops)
++static inline int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
++				       const struct sfp_upstream_ops *ops)
+ {
+ 	return 0;
+ }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/720-v5.5-net-sfp-move-sfp-sub-state-machines-into-separate-fu.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/720-v5.5-net-sfp-move-sfp-sub-state-machines-into-separate-fu.patch
new file mode 100644
index 0000000..e4ca85b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/720-v5.5-net-sfp-move-sfp-sub-state-machines-into-separate-fu.patch
@@ -0,0 +1,124 @@
+From b9d6ed5cdb67533feda7f221eb06f2f9f1ff5047 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 11 Oct 2019 19:33:58 +0100
+Subject: [PATCH 618/660] net: sfp: move sfp sub-state machines into separate
+ functions
+
+Move the SFP sub-state machines out of the main state machine function,
+in preparation for it doing a bit more with the device state.  By doing
+so, we ensure that our debug after the main state machine is always
+printed.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 74 +++++++++++++++++++++++++------------------
+ 1 file changed, 43 insertions(+), 31 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -1544,19 +1544,34 @@ static void sfp_sm_mod_remove(struct sfp
+ 	dev_info(sfp->dev, "module removed\n");
+ }
+ 
+-static void sfp_sm_event(struct sfp *sfp, unsigned int event)
++/* This state machine tracks the netdev up/down state */
++static void sfp_sm_device(struct sfp *sfp, unsigned int event)
+ {
+-	mutex_lock(&sfp->sm_mutex);
++	switch (sfp->sm_dev_state) {
++	default:
++		if (event == SFP_E_DEV_UP)
++			sfp->sm_dev_state = SFP_DEV_UP;
++		break;
+ 
+-	dev_dbg(sfp->dev, "SM: enter %s:%s:%s event %s\n",
+-		mod_state_to_str(sfp->sm_mod_state),
+-		dev_state_to_str(sfp->sm_dev_state),
+-		sm_state_to_str(sfp->sm_state),
+-		event_to_str(event));
++	case SFP_DEV_UP:
++		if (event == SFP_E_DEV_DOWN) {
++			/* If the module has a PHY, avoid raising TX disable
++			 * as this resets the PHY. Otherwise, raise it to
++			 * turn the laser off.
++			 */
++			if (!sfp->mod_phy)
++				sfp_module_tx_disable(sfp);
++			sfp->sm_dev_state = SFP_DEV_DOWN;
++		}
++		break;
++	}
++}
+ 
+-	/* This state machine tracks the insert/remove state of
+-	 * the module, and handles probing the on-board EEPROM.
+-	 */
++/* This state machine tracks the insert/remove state of
++ * the module, and handles probing the on-board EEPROM.
++ */
++static void sfp_sm_module(struct sfp *sfp, unsigned int event)
++{
+ 	switch (sfp->sm_mod_state) {
+ 	default:
+ 		if (event == SFP_E_INSERT && sfp->attached) {
+@@ -1596,27 +1611,10 @@ static void sfp_sm_event(struct sfp *sfp
+ 		}
+ 		break;
+ 	}
++}
+ 
+-	/* This state machine tracks the netdev up/down state */
+-	switch (sfp->sm_dev_state) {
+-	default:
+-		if (event == SFP_E_DEV_UP)
+-			sfp->sm_dev_state = SFP_DEV_UP;
+-		break;
+-
+-	case SFP_DEV_UP:
+-		if (event == SFP_E_DEV_DOWN) {
+-			/* If the module has a PHY, avoid raising TX disable
+-			 * as this resets the PHY. Otherwise, raise it to
+-			 * turn the laser off.
+-			 */
+-			if (!sfp->mod_phy)
+-				sfp_module_tx_disable(sfp);
+-			sfp->sm_dev_state = SFP_DEV_DOWN;
+-		}
+-		break;
+-	}
+-
++static void sfp_sm_main(struct sfp *sfp, unsigned int event)
++{
+ 	/* Some events are global */
+ 	if (sfp->sm_state != SFP_S_DOWN &&
+ 	    (sfp->sm_mod_state != SFP_MOD_PRESENT ||
+@@ -1627,7 +1625,6 @@ static void sfp_sm_event(struct sfp *sfp
+ 		if (sfp->mod_phy)
+ 			sfp_sm_phy_detach(sfp);
+ 		sfp_sm_next(sfp, SFP_S_DOWN, 0);
+-		mutex_unlock(&sfp->sm_mutex);
+ 		return;
+ 	}
+ 
+@@ -1682,6 +1679,21 @@ static void sfp_sm_event(struct sfp *sfp
+ 	case SFP_S_TX_DISABLE:
+ 		break;
+ 	}
++}
++
++static void sfp_sm_event(struct sfp *sfp, unsigned int event)
++{
++	mutex_lock(&sfp->sm_mutex);
++
++	dev_dbg(sfp->dev, "SM: enter %s:%s:%s event %s\n",
++		mod_state_to_str(sfp->sm_mod_state),
++		dev_state_to_str(sfp->sm_dev_state),
++		sm_state_to_str(sfp->sm_state),
++		event_to_str(event));
++
++	sfp_sm_module(sfp, event);
++	sfp_sm_device(sfp, event);
++	sfp_sm_main(sfp, event);
+ 
+ 	dev_dbg(sfp->dev, "SM: exit %s:%s:%s\n",
+ 		mod_state_to_str(sfp->sm_mod_state),
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/721-v5.5-net-sfp-move-tx-disable-on-device-down-to-main-state.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/721-v5.5-net-sfp-move-tx-disable-on-device-down-to-main-state.patch
new file mode 100644
index 0000000..71021c8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/721-v5.5-net-sfp-move-tx-disable-on-device-down-to-main-state.patch
@@ -0,0 +1,41 @@
+From 7e89b737c97a9e7a81dd1584000bc136b92f12fd Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 11 Oct 2019 22:14:47 +0100
+Subject: [PATCH 619/660] net: sfp: move tx disable on device down to main
+ state machine
+
+Move the tx disable assertion on device down to the main state
+machine.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 10 ++--------
+ 1 file changed, 2 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -1554,15 +1554,8 @@ static void sfp_sm_device(struct sfp *sf
+ 		break;
+ 
+ 	case SFP_DEV_UP:
+-		if (event == SFP_E_DEV_DOWN) {
+-			/* If the module has a PHY, avoid raising TX disable
+-			 * as this resets the PHY. Otherwise, raise it to
+-			 * turn the laser off.
+-			 */
+-			if (!sfp->mod_phy)
+-				sfp_module_tx_disable(sfp);
++		if (event == SFP_E_DEV_DOWN)
+ 			sfp->sm_dev_state = SFP_DEV_DOWN;
+-		}
+ 		break;
+ 	}
+ }
+@@ -1624,6 +1617,7 @@ static void sfp_sm_main(struct sfp *sfp,
+ 			sfp_sm_link_down(sfp);
+ 		if (sfp->mod_phy)
+ 			sfp_sm_phy_detach(sfp);
++		sfp_module_tx_disable(sfp);
+ 		sfp_sm_next(sfp, SFP_S_DOWN, 0);
+ 		return;
+ 	}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/722-v5.5-net-sfp-rename-sfp_sm_ins_next-as-sfp_sm_mod_next.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/722-v5.5-net-sfp-rename-sfp_sm_ins_next-as-sfp_sm_mod_next.patch
new file mode 100644
index 0000000..2974586
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/722-v5.5-net-sfp-rename-sfp_sm_ins_next-as-sfp_sm_mod_next.patch
@@ -0,0 +1,71 @@
+From f2a1ccfc4ad4f97c98c3cc18eb32992151ce089a Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 11 Oct 2019 22:27:21 +0100
+Subject: [PATCH 620/660] net: sfp: rename sfp_sm_ins_next() as
+ sfp_sm_mod_next()
+
+sfp_sm_ins_next() modifies the module state machine.  Change it's name
+to reflect this.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -1245,7 +1245,7 @@ static void sfp_sm_next(struct sfp *sfp,
+ 	sfp_sm_set_timer(sfp, timeout);
+ }
+ 
+-static void sfp_sm_ins_next(struct sfp *sfp, unsigned int state,
++static void sfp_sm_mod_next(struct sfp *sfp, unsigned int state,
+ 			    unsigned int timeout)
+ {
+ 	sfp->sm_mod_state = state;
+@@ -1569,22 +1569,22 @@ static void sfp_sm_module(struct sfp *sf
+ 	default:
+ 		if (event == SFP_E_INSERT && sfp->attached) {
+ 			sfp_module_tx_disable(sfp);
+-			sfp_sm_ins_next(sfp, SFP_MOD_PROBE, T_PROBE_INIT);
++			sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_PROBE_INIT);
+ 		}
+ 		break;
+ 
+ 	case SFP_MOD_PROBE:
+ 		if (event == SFP_E_REMOVE) {
+-			sfp_sm_ins_next(sfp, SFP_MOD_EMPTY, 0);
++			sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
+ 		} else if (event == SFP_E_TIMEOUT) {
+ 			int val = sfp_sm_mod_probe(sfp);
+ 
+ 			if (val == 0)
+-				sfp_sm_ins_next(sfp, SFP_MOD_PRESENT, 0);
++				sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0);
+ 			else if (val > 0)
+-				sfp_sm_ins_next(sfp, SFP_MOD_HPOWER, val);
++				sfp_sm_mod_next(sfp, SFP_MOD_HPOWER, val);
+ 			else if (val != -EAGAIN)
+-				sfp_sm_ins_next(sfp, SFP_MOD_ERROR, 0);
++				sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
+ 			else
+ 				sfp_sm_set_timer(sfp, T_PROBE_RETRY);
+ 		}
+@@ -1592,7 +1592,7 @@ static void sfp_sm_module(struct sfp *sf
+ 
+ 	case SFP_MOD_HPOWER:
+ 		if (event == SFP_E_TIMEOUT) {
+-			sfp_sm_ins_next(sfp, SFP_MOD_PRESENT, 0);
++			sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0);
+ 			break;
+ 		}
+ 		/* fallthrough */
+@@ -1600,7 +1600,7 @@ static void sfp_sm_module(struct sfp *sf
+ 	case SFP_MOD_ERROR:
+ 		if (event == SFP_E_REMOVE) {
+ 			sfp_sm_mod_remove(sfp);
+-			sfp_sm_ins_next(sfp, SFP_MOD_EMPTY, 0);
++			sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
+ 		}
+ 		break;
+ 	}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/723-v5.5-net-sfp-handle-module-remove-outside-state-machine.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/723-v5.5-net-sfp-handle-module-remove-outside-state-machine.patch
new file mode 100644
index 0000000..62cdb8a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/723-v5.5-net-sfp-handle-module-remove-outside-state-machine.patch
@@ -0,0 +1,53 @@
+From d2591ea5520e2ee8fa557f96bb64c23cafac4b20 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 15 Oct 2019 10:33:13 +0100
+Subject: [PATCH 621/660] net: sfp: handle module remove outside state machine
+
+Removing a module resets the module state machine back to its initial
+state.  Rather than explicitly handling this in every state, handle it
+early on outside of the state machine.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 16 +++++++++-------
+ 1 file changed, 9 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -1565,6 +1565,14 @@ static void sfp_sm_device(struct sfp *sf
+  */
+ static void sfp_sm_module(struct sfp *sfp, unsigned int event)
+ {
++	/* Handle remove event globally, it resets this state machine */
++	if (event == SFP_E_REMOVE) {
++		if (sfp->sm_mod_state > SFP_MOD_PROBE)
++			sfp_sm_mod_remove(sfp);
++		sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
++		return;
++	}
++
+ 	switch (sfp->sm_mod_state) {
+ 	default:
+ 		if (event == SFP_E_INSERT && sfp->attached) {
+@@ -1574,9 +1582,7 @@ static void sfp_sm_module(struct sfp *sf
+ 		break;
+ 
+ 	case SFP_MOD_PROBE:
+-		if (event == SFP_E_REMOVE) {
+-			sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
+-		} else if (event == SFP_E_TIMEOUT) {
++		if (event == SFP_E_TIMEOUT) {
+ 			int val = sfp_sm_mod_probe(sfp);
+ 
+ 			if (val == 0)
+@@ -1598,10 +1604,6 @@ static void sfp_sm_module(struct sfp *sf
+ 		/* fallthrough */
+ 	case SFP_MOD_PRESENT:
+ 	case SFP_MOD_ERROR:
+-		if (event == SFP_E_REMOVE) {
+-			sfp_sm_mod_remove(sfp);
+-			sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
+-		}
+ 		break;
+ 	}
+ }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/724-v5.5-net-sfp-rename-T_PROBE_WAIT-to-T_SERIAL.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/724-v5.5-net-sfp-rename-T_PROBE_WAIT-to-T_SERIAL.patch
new file mode 100644
index 0000000..780e7d7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/724-v5.5-net-sfp-rename-T_PROBE_WAIT-to-T_SERIAL.patch
@@ -0,0 +1,51 @@
+From 615090acb3c0b41691f3a03522ea38350387c0e4 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 15 Oct 2019 10:54:15 +0100
+Subject: [PATCH 622/660] net: sfp: rename T_PROBE_WAIT to T_SERIAL
+
+SFF-8472 rev 12.2 defines the time for the serial bus to become ready
+using t_serial.  Use this as our identifier for this timeout to make
+it clear what we are referring to.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -149,11 +149,10 @@ static const enum gpiod_flags gpio_flags
+  * the same length on the PCB, which means it's possible for MOD DEF 0 to
+  * connect before the I2C bus on MOD DEF 1/2.
+  *
+- * The SFP MSA specifies 300ms as t_init (the time taken for TX_FAULT to
+- * be deasserted) but makes no mention of the earliest time before we can
+- * access the I2C EEPROM.  However, Avago modules require 300ms.
++ * The SFF-8472 specifies t_serial ("Time from power on until module is
++ * ready for data transmission over the two wire serial bus.") as 300ms.
+  */
+-#define T_PROBE_INIT	msecs_to_jiffies(300)
++#define T_SERIAL	msecs_to_jiffies(300)
+ #define T_HPOWER_LEVEL	msecs_to_jiffies(300)
+ #define T_PROBE_RETRY	msecs_to_jiffies(100)
+ 
+@@ -1560,8 +1559,8 @@ static void sfp_sm_device(struct sfp *sf
+ 	}
+ }
+ 
+-/* This state machine tracks the insert/remove state of
+- * the module, and handles probing the on-board EEPROM.
++/* This state machine tracks the insert/remove state of the module, probes
++ * the on-board EEPROM, and sets up the power level.
+  */
+ static void sfp_sm_module(struct sfp *sfp, unsigned int event)
+ {
+@@ -1577,7 +1576,7 @@ static void sfp_sm_module(struct sfp *sf
+ 	default:
+ 		if (event == SFP_E_INSERT && sfp->attached) {
+ 			sfp_module_tx_disable(sfp);
+-			sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_PROBE_INIT);
++			sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL);
+ 		}
+ 		break;
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/725-v5.5-net-sfp-parse-SFP-power-requirement-earlier.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/725-v5.5-net-sfp-parse-SFP-power-requirement-earlier.patch
new file mode 100644
index 0000000..df5ef9f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/725-v5.5-net-sfp-parse-SFP-power-requirement-earlier.patch
@@ -0,0 +1,115 @@
+From d4b8746219e8c0361e5ed6e440ab3a8a600d1f76 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 11 Oct 2019 17:24:40 +0100
+Subject: [PATCH 623/660] net: sfp: parse SFP power requirement earlier
+
+Parse the SFP power requirement earlier, in preparation for moving the
+power level setup code.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 42 +++++++++++++++++++++++++++++-------------
+ 1 file changed, 29 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -198,6 +198,8 @@ struct sfp {
+ 	unsigned int sm_retries;
+ 
+ 	struct sfp_eeprom_id id;
++	unsigned int module_power_mW;
++
+ #if IS_ENABLED(CONFIG_HWMON)
+ 	struct sfp_diag diag;
+ 	struct device *hwmon_dev;
+@@ -1374,17 +1376,14 @@ static void sfp_sm_mod_init(struct sfp *
+ 		sfp_sm_probe_phy(sfp);
+ }
+ 
+-static int sfp_sm_mod_hpower(struct sfp *sfp)
++static int sfp_module_parse_power(struct sfp *sfp)
+ {
+-	u32 power;
+-	u8 val;
+-	int err;
++	u32 power_mW = 1000;
+ 
+-	power = 1000;
+ 	if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_POWER_DECL))
+-		power = 1500;
++		power_mW = 1500;
+ 	if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_HIGH_POWER_LEVEL))
+-		power = 2000;
++		power_mW = 2000;
+ 
+ 	if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE &&
+ 	    (sfp->id.ext.diagmon & (SFP_DIAGMON_DDM | SFP_DIAGMON_ADDRMODE)) !=
+@@ -1393,23 +1392,33 @@ static int sfp_sm_mod_hpower(struct sfp
+ 		 * or requires an address change sequence, so assume that
+ 		 * the module powers up in the indicated power mode.
+ 		 */
+-		if (power > sfp->max_power_mW) {
++		if (power_mW > sfp->max_power_mW) {
+ 			dev_err(sfp->dev,
+ 				"Host does not support %u.%uW modules\n",
+-				power / 1000, (power / 100) % 10);
++				power_mW / 1000, (power_mW / 100) % 10);
+ 			return -EINVAL;
+ 		}
+ 		return 0;
+ 	}
+ 
+-	if (power > sfp->max_power_mW) {
++	if (power_mW > sfp->max_power_mW) {
+ 		dev_warn(sfp->dev,
+ 			 "Host does not support %u.%uW modules, module left in power mode 1\n",
+-			 power / 1000, (power / 100) % 10);
++			 power_mW / 1000, (power_mW / 100) % 10);
+ 		return 0;
+ 	}
+ 
+-	if (power <= 1000)
++	sfp->module_power_mW = power_mW;
++
++	return 0;
++}
++
++static int sfp_sm_mod_hpower(struct sfp *sfp)
++{
++	u8 val;
++	int err;
++
++	if (sfp->module_power_mW <= 1000)
+ 		return 0;
+ 
+ 	err = sfp_read(sfp, true, SFP_EXT_STATUS, &val, sizeof(val));
+@@ -1429,7 +1438,8 @@ static int sfp_sm_mod_hpower(struct sfp
+ 	}
+ 
+ 	dev_info(sfp->dev, "Module switched to %u.%uW power level\n",
+-		 power / 1000, (power / 100) % 10);
++		 sfp->module_power_mW / 1000,
++		 (sfp->module_power_mW / 100) % 10);
+ 	return T_HPOWER_LEVEL;
+ 
+ err:
+@@ -1516,6 +1526,11 @@ static int sfp_sm_mod_probe(struct sfp *
+ 		dev_warn(sfp->dev,
+ 			 "module address swap to access page 0xA2 is not supported.\n");
+ 
++	/* Parse the module power requirement */
++	ret = sfp_module_parse_power(sfp);
++	if (ret < 0)
++		return ret;
++
+ 	ret = sfp_hwmon_insert(sfp);
+ 	if (ret < 0)
+ 		return ret;
+@@ -1539,6 +1554,7 @@ static void sfp_sm_mod_remove(struct sfp
+ 	sfp_module_tx_disable(sfp);
+ 
+ 	memset(&sfp->id, 0, sizeof(sfp->id));
++	sfp->module_power_mW = 0;
+ 
+ 	dev_info(sfp->dev, "module removed\n");
+ }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/726-v5.5-net-sfp-avoid-power-switch-on-address-change-modules.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/726-v5.5-net-sfp-avoid-power-switch-on-address-change-modules.patch
new file mode 100644
index 0000000..5237f55
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/726-v5.5-net-sfp-avoid-power-switch-on-address-change-modules.patch
@@ -0,0 +1,65 @@
+From dca678b8838945572cf50584cb33a7199c1fd397 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Thu, 17 Oct 2019 00:24:18 +0100
+Subject: [PATCH 624/660] net: sfp: avoid power switch on address-change
+ modules
+
+If the module indicates that it requires an address change sequence to
+switch between address 0x50 and 0x51, which we don't support, we can't
+write to the register that controls the power mode to switch to high
+power mode.  Warn the user that the module may not be functional in
+this case, and don't try to change the power mode.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 31 ++++++++++++++++++++-----------
+ 1 file changed, 20 insertions(+), 11 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -1385,25 +1385,34 @@ static int sfp_module_parse_power(struct
+ 	if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_HIGH_POWER_LEVEL))
+ 		power_mW = 2000;
+ 
+-	if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE &&
+-	    (sfp->id.ext.diagmon & (SFP_DIAGMON_DDM | SFP_DIAGMON_ADDRMODE)) !=
+-	    SFP_DIAGMON_DDM) {
+-		/* The module appears not to implement bus address 0xa2,
+-		 * or requires an address change sequence, so assume that
+-		 * the module powers up in the indicated power mode.
+-		 */
+-		if (power_mW > sfp->max_power_mW) {
++	if (power_mW > sfp->max_power_mW) {
++		/* Module power specification exceeds the allowed maximum. */
++		if (sfp->id.ext.sff8472_compliance ==
++			SFP_SFF8472_COMPLIANCE_NONE &&
++		    !(sfp->id.ext.diagmon & SFP_DIAGMON_DDM)) {
++			/* The module appears not to implement bus address
++			 * 0xa2, so assume that the module powers up in the
++			 * indicated mode.
++			 */
+ 			dev_err(sfp->dev,
+ 				"Host does not support %u.%uW modules\n",
+ 				power_mW / 1000, (power_mW / 100) % 10);
+ 			return -EINVAL;
++		} else {
++			dev_warn(sfp->dev,
++				 "Host does not support %u.%uW modules, module left in power mode 1\n",
++				 power_mW / 1000, (power_mW / 100) % 10);
++			return 0;
+ 		}
+-		return 0;
+ 	}
+ 
+-	if (power_mW > sfp->max_power_mW) {
++	/* If the module requires a higher power mode, but also requires
++	 * an address change sequence, warn the user that the module may
++	 * not be functional.
++	 */
++	if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE && power_mW > 1000) {
+ 		dev_warn(sfp->dev,
+-			 "Host does not support %u.%uW modules, module left in power mode 1\n",
++			 "Address Change Sequence not supported but module requies %u.%uW, module may not be functional\n",
+ 			 power_mW / 1000, (power_mW / 100) % 10);
+ 		return 0;
+ 	}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/727-v5.5-net-sfp-control-TX_DISABLE-and-phy-only-from-main-st.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/727-v5.5-net-sfp-control-TX_DISABLE-and-phy-only-from-main-st.patch
new file mode 100644
index 0000000..eebcac6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/727-v5.5-net-sfp-control-TX_DISABLE-and-phy-only-from-main-st.patch
@@ -0,0 +1,52 @@
+From df5c4d93c5a59cba0f7479a4cd4e22b50726ce88 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Thu, 17 Oct 2019 11:12:42 +0100
+Subject: [PATCH 625/660] net: sfp: control TX_DISABLE and phy only from main
+ state machine
+
+We initialise TX_DISABLE when the sfp cage is probed, and then
+maintain its state in the main state machine.  However, the module
+state machine:
+- negates it when detecting a newly inserted module when it's already
+  guaranteed to be negated.
+- negates it when the module is removed, but the main state machine
+  will do this anyway.
+
+Make TX_DISABLE entirely controlled by the main state machine.
+
+The main state machine also probes the module for a PHY, and removes
+the PHY when the the module is removed.  Hence, removing the PHY in
+sfp_sm_module_remove() is also redundant, and is a left-over from
+when we tried to probe for the PHY from the module state machine.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 9 +--------
+ 1 file changed, 1 insertion(+), 8 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -1557,11 +1557,6 @@ static void sfp_sm_mod_remove(struct sfp
+ 
+ 	sfp_hwmon_remove(sfp);
+ 
+-	if (sfp->mod_phy)
+-		sfp_sm_phy_detach(sfp);
+-
+-	sfp_module_tx_disable(sfp);
+-
+ 	memset(&sfp->id, 0, sizeof(sfp->id));
+ 	sfp->module_power_mW = 0;
+ 
+@@ -1599,10 +1594,8 @@ static void sfp_sm_module(struct sfp *sf
+ 
+ 	switch (sfp->sm_mod_state) {
+ 	default:
+-		if (event == SFP_E_INSERT && sfp->attached) {
+-			sfp_module_tx_disable(sfp);
++		if (event == SFP_E_INSERT && sfp->attached)
+ 			sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL);
+-		}
+ 		break;
+ 
+ 	case SFP_MOD_PROBE:
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/728-v5.5-net-sfp-split-the-PHY-probe-from-sfp_sm_mod_init.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/728-v5.5-net-sfp-split-the-PHY-probe-from-sfp_sm_mod_init.patch
new file mode 100644
index 0000000..92df26c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/728-v5.5-net-sfp-split-the-PHY-probe-from-sfp_sm_mod_init.patch
@@ -0,0 +1,53 @@
+From 5ed0bd49b2d3ac4439c2d7f44e5a82b7cf6f409a Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 18 Oct 2019 10:09:02 +0100
+Subject: [PATCH 626/660] net: sfp: split the PHY probe from sfp_sm_mod_init()
+
+Move the PHY probe into a separate function, splitting it from
+sfp_sm_mod_init().  This will allow us to eliminate the 50ms mdelay()
+inside the state machine.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 21 +++++++++++++--------
+ 1 file changed, 13 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -1353,14 +1353,10 @@ static void sfp_sm_fault(struct sfp *sfp
+ static void sfp_sm_mod_init(struct sfp *sfp)
+ {
+ 	sfp_module_tx_enable(sfp);
++}
+ 
+-	/* Wait t_init before indicating that the link is up, provided the
+-	 * current state indicates no TX_FAULT.  If TX_FAULT clears before
+-	 * this time, that's fine too.
+-	 */
+-	sfp_sm_next(sfp, SFP_S_INIT, T_INIT_JIFFIES);
+-	sfp->sm_retries = 5;
+-
++static void sfp_sm_probe_for_phy(struct sfp *sfp)
++{
+ 	/* Setting the serdes link mode is guesswork: there's no
+ 	 * field in the EEPROM which indicates what mode should
+ 	 * be used.
+@@ -1645,8 +1641,17 @@ static void sfp_sm_main(struct sfp *sfp,
+ 	switch (sfp->sm_state) {
+ 	case SFP_S_DOWN:
+ 		if (sfp->sm_mod_state == SFP_MOD_PRESENT &&
+-		    sfp->sm_dev_state == SFP_DEV_UP)
++		    sfp->sm_dev_state == SFP_DEV_UP) {
+ 			sfp_sm_mod_init(sfp);
++			sfp_sm_probe_for_phy(sfp);
++
++			/* Wait t_init before indicating that the link is up,
++			 * provided the current state indicates no TX_FAULT. If
++			 * TX_FAULT clears before this time, that's fine too.
++			 */
++			sfp_sm_next(sfp, SFP_S_INIT, T_INIT_JIFFIES);
++			sfp->sm_retries = 5;
++		}
+ 		break;
+ 
+ 	case SFP_S_INIT:
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/729-v5.5-net-sfp-eliminate-mdelay-from-PHY-probe.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/729-v5.5-net-sfp-eliminate-mdelay-from-PHY-probe.patch
new file mode 100644
index 0000000..e26a727
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/729-v5.5-net-sfp-eliminate-mdelay-from-PHY-probe.patch
@@ -0,0 +1,130 @@
+From 0fe72afaa31f98ebd71bd6683fc47021105d0157 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 18 Oct 2019 10:21:46 +0100
+Subject: [PATCH 627/660] net: sfp: eliminate mdelay() from PHY probe
+
+Rather than using mdelay() to wait before probing the PHY (which holds
+several locks, including the rtnl lock), add an extra wait state to
+the state machine to introduce the 50ms delay without holding any
+locks.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 52 +++++++++++++++++++++++++++++++++----------
+ 1 file changed, 40 insertions(+), 12 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -54,6 +54,7 @@ enum {
+ 	SFP_DEV_UP,
+ 
+ 	SFP_S_DOWN = 0,
++	SFP_S_WAIT,
+ 	SFP_S_INIT,
+ 	SFP_S_WAIT_LOS,
+ 	SFP_S_LINK_UP,
+@@ -110,6 +111,7 @@ static const char *event_to_str(unsigned
+ 
+ static const char * const sm_state_strings[] = {
+ 	[SFP_S_DOWN] = "down",
++	[SFP_S_WAIT] = "wait",
+ 	[SFP_S_INIT] = "init",
+ 	[SFP_S_WAIT_LOS] = "wait_los",
+ 	[SFP_S_LINK_UP] = "link_up",
+@@ -141,6 +143,7 @@ static const enum gpiod_flags gpio_flags
+ 	GPIOD_ASIS,
+ };
+ 
++#define T_WAIT		msecs_to_jiffies(50)
+ #define T_INIT_JIFFIES	msecs_to_jiffies(300)
+ #define T_RESET_US	10
+ #define T_FAULT_RECOVER	msecs_to_jiffies(1000)
+@@ -161,9 +164,6 @@ static const enum gpiod_flags gpio_flags
+  */
+ #define SFP_PHY_ADDR	22
+ 
+-/* Give this long for the PHY to reset. */
+-#define T_PHY_RESET_MS	50
+-
+ struct sff_data {
+ 	unsigned int gpios;
+ 	bool (*module_supported)(const struct sfp_eeprom_id *id);
+@@ -1267,8 +1267,6 @@ static void sfp_sm_probe_phy(struct sfp
+ 	struct phy_device *phy;
+ 	int err;
+ 
+-	msleep(T_PHY_RESET_MS);
+-
+ 	phy = mdiobus_scan(sfp->i2c_mii, SFP_PHY_ADDR);
+ 	if (phy == ERR_PTR(-ENODEV)) {
+ 		dev_info(sfp->dev, "no PHY detected\n");
+@@ -1623,6 +1621,8 @@ static void sfp_sm_module(struct sfp *sf
+ 
+ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
+ {
++	unsigned long timeout;
++
+ 	/* Some events are global */
+ 	if (sfp->sm_state != SFP_S_DOWN &&
+ 	    (sfp->sm_mod_state != SFP_MOD_PRESENT ||
+@@ -1640,17 +1640,45 @@ static void sfp_sm_main(struct sfp *sfp,
+ 	/* The main state machine */
+ 	switch (sfp->sm_state) {
+ 	case SFP_S_DOWN:
+-		if (sfp->sm_mod_state == SFP_MOD_PRESENT &&
+-		    sfp->sm_dev_state == SFP_DEV_UP) {
+-			sfp_sm_mod_init(sfp);
+-			sfp_sm_probe_for_phy(sfp);
++		if (sfp->sm_mod_state != SFP_MOD_PRESENT ||
++		    sfp->sm_dev_state != SFP_DEV_UP)
++			break;
++
++		sfp_sm_mod_init(sfp);
++
++		/* Initialise the fault clearance retries */
++		sfp->sm_retries = 5;
++
++		/* We need to check the TX_FAULT state, which is not defined
++		 * while TX_DISABLE is asserted. The earliest we want to do
++		 * anything (such as probe for a PHY) is 50ms.
++		 */
++		sfp_sm_next(sfp, SFP_S_WAIT, T_WAIT);
++		break;
++
++	case SFP_S_WAIT:
++		if (event != SFP_E_TIMEOUT)
++			break;
++
++		sfp_sm_probe_for_phy(sfp);
+ 
++		if (sfp->state & SFP_F_TX_FAULT) {
+ 			/* Wait t_init before indicating that the link is up,
+ 			 * provided the current state indicates no TX_FAULT. If
+ 			 * TX_FAULT clears before this time, that's fine too.
+ 			 */
+-			sfp_sm_next(sfp, SFP_S_INIT, T_INIT_JIFFIES);
+-			sfp->sm_retries = 5;
++			timeout = T_INIT_JIFFIES;
++			if (timeout > T_WAIT)
++				timeout -= T_WAIT;
++			else
++				timeout = 1;
++
++			sfp_sm_next(sfp, SFP_S_INIT, timeout);
++		} else {
++			/* TX_FAULT is not asserted, assume the module has
++			 * finished initialising.
++			 */
++			goto init_done;
+ 		}
+ 		break;
+ 
+@@ -1658,7 +1686,7 @@ static void sfp_sm_main(struct sfp *sfp,
+ 		if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT)
+ 			sfp_sm_fault(sfp, true);
+ 		else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR)
+-			sfp_sm_link_check_los(sfp);
++	init_done:	sfp_sm_link_check_los(sfp);
+ 		break;
+ 
+ 	case SFP_S_WAIT_LOS:
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/730-v5.5-net-sfp-allow-fault-processing-to-transition-to-othe.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/730-v5.5-net-sfp-allow-fault-processing-to-transition-to-othe.patch
new file mode 100644
index 0000000..d45b061
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/730-v5.5-net-sfp-allow-fault-processing-to-transition-to-othe.patch
@@ -0,0 +1,69 @@
+From 2aa424ee7fbe43e2cd24e28c2f6388c4e1796bd2 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 18 Oct 2019 09:58:33 +0100
+Subject: [PATCH 628/660] net: sfp: allow fault processing to transition to
+ other states
+
+Add the next state to sfp_sm_fault() so that it can branch to other
+states. This will be necessary to improve the initialisation path.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -1334,7 +1334,7 @@ static bool sfp_los_event_inactive(struc
+ 		event == SFP_E_LOS_LOW);
+ }
+ 
+-static void sfp_sm_fault(struct sfp *sfp, bool warn)
++static void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn)
+ {
+ 	if (sfp->sm_retries && !--sfp->sm_retries) {
+ 		dev_err(sfp->dev,
+@@ -1344,7 +1344,7 @@ static void sfp_sm_fault(struct sfp *sfp
+ 		if (warn)
+ 			dev_err(sfp->dev, "module transmit fault indicated\n");
+ 
+-		sfp_sm_next(sfp, SFP_S_TX_FAULT, T_FAULT_RECOVER);
++		sfp_sm_next(sfp, next_state, T_FAULT_RECOVER);
+ 	}
+ }
+ 
+@@ -1684,14 +1684,14 @@ static void sfp_sm_main(struct sfp *sfp,
+ 
+ 	case SFP_S_INIT:
+ 		if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT)
+-			sfp_sm_fault(sfp, true);
++			sfp_sm_fault(sfp, SFP_S_TX_FAULT, true);
+ 		else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR)
+ 	init_done:	sfp_sm_link_check_los(sfp);
+ 		break;
+ 
+ 	case SFP_S_WAIT_LOS:
+ 		if (event == SFP_E_TX_FAULT)
+-			sfp_sm_fault(sfp, true);
++			sfp_sm_fault(sfp, SFP_S_TX_FAULT, true);
+ 		else if (sfp_los_event_inactive(sfp, event))
+ 			sfp_sm_link_up(sfp);
+ 		break;
+@@ -1699,7 +1699,7 @@ static void sfp_sm_main(struct sfp *sfp,
+ 	case SFP_S_LINK_UP:
+ 		if (event == SFP_E_TX_FAULT) {
+ 			sfp_sm_link_down(sfp);
+-			sfp_sm_fault(sfp, true);
++			sfp_sm_fault(sfp, SFP_S_TX_FAULT, true);
+ 		} else if (sfp_los_event_active(sfp, event)) {
+ 			sfp_sm_link_down(sfp);
+ 			sfp_sm_next(sfp, SFP_S_WAIT_LOS, 0);
+@@ -1715,7 +1715,7 @@ static void sfp_sm_main(struct sfp *sfp,
+ 
+ 	case SFP_S_REINIT:
+ 		if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT) {
+-			sfp_sm_fault(sfp, false);
++			sfp_sm_fault(sfp, SFP_S_TX_FAULT, false);
+ 		} else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) {
+ 			dev_info(sfp->dev, "module transmit fault recovered\n");
+ 			sfp_sm_link_check_los(sfp);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/731-v5.5-net-sfp-ensure-TX_FAULT-has-deasserted-before-probin.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/731-v5.5-net-sfp-ensure-TX_FAULT-has-deasserted-before-probin.patch
new file mode 100644
index 0000000..acca29b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/731-v5.5-net-sfp-ensure-TX_FAULT-has-deasserted-before-probin.patch
@@ -0,0 +1,80 @@
+From 38b62a12231be4b86fc5ca5477579d29831c02a5 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 18 Oct 2019 10:31:07 +0100
+Subject: [PATCH 629/660] net: sfp: ensure TX_FAULT has deasserted before
+ probing the PHY
+
+TX_FAULT should be deasserted to indicate that the module has completed
+its initialisation.  This may include the on-board PHY, so wait until
+the module has deasserted TX_FAULT before probing the PHY.
+
+This means that we need an extra state to handle a TX_FAULT that
+remains set for longer than t_init, since using the existing handling
+state would bypass the PHY probe.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 31 +++++++++++++++++++++++++------
+ 1 file changed, 25 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -56,6 +56,7 @@ enum {
+ 	SFP_S_DOWN = 0,
+ 	SFP_S_WAIT,
+ 	SFP_S_INIT,
++	SFP_S_INIT_TX_FAULT,
+ 	SFP_S_WAIT_LOS,
+ 	SFP_S_LINK_UP,
+ 	SFP_S_TX_FAULT,
+@@ -113,6 +114,7 @@ static const char * const sm_state_strin
+ 	[SFP_S_DOWN] = "down",
+ 	[SFP_S_WAIT] = "wait",
+ 	[SFP_S_INIT] = "init",
++	[SFP_S_INIT_TX_FAULT] = "init_tx_fault",
+ 	[SFP_S_WAIT_LOS] = "wait_los",
+ 	[SFP_S_LINK_UP] = "link_up",
+ 	[SFP_S_TX_FAULT] = "tx_fault",
+@@ -1660,8 +1662,6 @@ static void sfp_sm_main(struct sfp *sfp,
+ 		if (event != SFP_E_TIMEOUT)
+ 			break;
+ 
+-		sfp_sm_probe_for_phy(sfp);
+-
+ 		if (sfp->state & SFP_F_TX_FAULT) {
+ 			/* Wait t_init before indicating that the link is up,
+ 			 * provided the current state indicates no TX_FAULT. If
+@@ -1683,10 +1683,29 @@ static void sfp_sm_main(struct sfp *sfp,
+ 		break;
+ 
+ 	case SFP_S_INIT:
+-		if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT)
+-			sfp_sm_fault(sfp, SFP_S_TX_FAULT, true);
+-		else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR)
+-	init_done:	sfp_sm_link_check_los(sfp);
++		if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT) {
++			/* TX_FAULT is still asserted after t_init, so assume
++			 * there is a fault.
++			 */
++			sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT,
++				     sfp->sm_retries == 5);
++		} else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) {
++	init_done:	/* TX_FAULT deasserted or we timed out with TX_FAULT
++			 * clear.  Probe for the PHY and check the LOS state.
++			 */
++			sfp_sm_probe_for_phy(sfp);
++			sfp_sm_link_check_los(sfp);
++
++			/* Reset the fault retry count */
++			sfp->sm_retries = 5;
++		}
++		break;
++
++	case SFP_S_INIT_TX_FAULT:
++		if (event == SFP_E_TIMEOUT) {
++			sfp_module_tx_fault_reset(sfp);
++			sfp_sm_next(sfp, SFP_S_INIT, T_INIT_JIFFIES);
++		}
+ 		break;
+ 
+ 	case SFP_S_WAIT_LOS:
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/732-v5.5-net-sfp-track-upstream-s-attachment-state-in-state-m.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/732-v5.5-net-sfp-track-upstream-s-attachment-state-in-state-m.patch
new file mode 100644
index 0000000..714d783
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/732-v5.5-net-sfp-track-upstream-s-attachment-state-in-state-m.patch
@@ -0,0 +1,153 @@
+From ec6036a58f979c66bbd5cd9d0d1c783a98c2c644 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 5 Nov 2019 12:57:40 +0000
+Subject: [PATCH 630/660] net: sfp: track upstream's attachment state in state
+ machine
+
+Track the upstream's attachment state in the state machine rather than
+maintaining a boolean, which ensures that we have a strict order of
+ATTACH followed by an UP event - we can never believe that a newly
+attached upstream will be anything but down.
+
+Rearrange the order of state machines so we run the module state
+machine after the upstream device's state machine, so the module state
+machine can check the current state of the device and take action to
+e.g. reset back to empty state when the upstream is detached.
+
+This is to allow the module detection to run independently of the
+network device becoming available.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 42 +++++++++++++++++++++++++++++-------------
+ 1 file changed, 29 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -36,6 +36,8 @@ enum {
+ 
+ 	SFP_E_INSERT = 0,
+ 	SFP_E_REMOVE,
++	SFP_E_DEV_ATTACH,
++	SFP_E_DEV_DETACH,
+ 	SFP_E_DEV_DOWN,
+ 	SFP_E_DEV_UP,
+ 	SFP_E_TX_FAULT,
+@@ -50,7 +52,8 @@ enum {
+ 	SFP_MOD_PRESENT,
+ 	SFP_MOD_ERROR,
+ 
+-	SFP_DEV_DOWN = 0,
++	SFP_DEV_DETACHED = 0,
++	SFP_DEV_DOWN,
+ 	SFP_DEV_UP,
+ 
+ 	SFP_S_DOWN = 0,
+@@ -80,6 +83,7 @@ static const char *mod_state_to_str(unsi
+ }
+ 
+ static const char * const dev_state_strings[] = {
++	[SFP_DEV_DETACHED] = "detached",
+ 	[SFP_DEV_DOWN] = "down",
+ 	[SFP_DEV_UP] = "up",
+ };
+@@ -94,6 +98,8 @@ static const char *dev_state_to_str(unsi
+ static const char * const event_strings[] = {
+ 	[SFP_E_INSERT] = "insert",
+ 	[SFP_E_REMOVE] = "remove",
++	[SFP_E_DEV_ATTACH] = "dev_attach",
++	[SFP_E_DEV_DETACH] = "dev_detach",
+ 	[SFP_E_DEV_DOWN] = "dev_down",
+ 	[SFP_E_DEV_UP] = "dev_up",
+ 	[SFP_E_TX_FAULT] = "tx_fault",
+@@ -188,7 +194,6 @@ struct sfp {
+ 	struct gpio_desc *gpio[GPIO_MAX];
+ 	int gpio_irq[GPIO_MAX];
+ 
+-	bool attached;
+ 	struct mutex st_mutex;			/* Protects state */
+ 	unsigned int state;
+ 	struct delayed_work poll;
+@@ -1559,17 +1564,26 @@ static void sfp_sm_mod_remove(struct sfp
+ 	dev_info(sfp->dev, "module removed\n");
+ }
+ 
+-/* This state machine tracks the netdev up/down state */
++/* This state machine tracks the upstream's state */
+ static void sfp_sm_device(struct sfp *sfp, unsigned int event)
+ {
+ 	switch (sfp->sm_dev_state) {
+ 	default:
+-		if (event == SFP_E_DEV_UP)
++		if (event == SFP_E_DEV_ATTACH)
++			sfp->sm_dev_state = SFP_DEV_DOWN;
++		break;
++
++	case SFP_DEV_DOWN:
++		if (event == SFP_E_DEV_DETACH)
++			sfp->sm_dev_state = SFP_DEV_DETACHED;
++		else if (event == SFP_E_DEV_UP)
+ 			sfp->sm_dev_state = SFP_DEV_UP;
+ 		break;
+ 
+ 	case SFP_DEV_UP:
+-		if (event == SFP_E_DEV_DOWN)
++		if (event == SFP_E_DEV_DETACH)
++			sfp->sm_dev_state = SFP_DEV_DETACHED;
++		else if (event == SFP_E_DEV_DOWN)
+ 			sfp->sm_dev_state = SFP_DEV_DOWN;
+ 		break;
+ 	}
+@@ -1580,17 +1594,20 @@ static void sfp_sm_device(struct sfp *sf
+  */
+ static void sfp_sm_module(struct sfp *sfp, unsigned int event)
+ {
+-	/* Handle remove event globally, it resets this state machine */
+-	if (event == SFP_E_REMOVE) {
++	/* Handle remove event globally, it resets this state machine.
++	 * Also deal with upstream detachment.
++	 */
++	if (event == SFP_E_REMOVE || sfp->sm_dev_state < SFP_DEV_DOWN) {
+ 		if (sfp->sm_mod_state > SFP_MOD_PROBE)
+ 			sfp_sm_mod_remove(sfp);
+-		sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
++		if (sfp->sm_mod_state != SFP_MOD_EMPTY)
++			sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
+ 		return;
+ 	}
+ 
+ 	switch (sfp->sm_mod_state) {
+ 	default:
+-		if (event == SFP_E_INSERT && sfp->attached)
++		if (event == SFP_E_INSERT)
+ 			sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL);
+ 		break;
+ 
+@@ -1756,8 +1773,8 @@ static void sfp_sm_event(struct sfp *sfp
+ 		sm_state_to_str(sfp->sm_state),
+ 		event_to_str(event));
+ 
+-	sfp_sm_module(sfp, event);
+ 	sfp_sm_device(sfp, event);
++	sfp_sm_module(sfp, event);
+ 	sfp_sm_main(sfp, event);
+ 
+ 	dev_dbg(sfp->dev, "SM: exit %s:%s:%s\n",
+@@ -1770,15 +1787,14 @@ static void sfp_sm_event(struct sfp *sfp
+ 
+ static void sfp_attach(struct sfp *sfp)
+ {
+-	sfp->attached = true;
++	sfp_sm_event(sfp, SFP_E_DEV_ATTACH);
+ 	if (sfp->state & SFP_F_PRESENT)
+ 		sfp_sm_event(sfp, SFP_E_INSERT);
+ }
+ 
+ static void sfp_detach(struct sfp *sfp)
+ {
+-	sfp->attached = false;
+-	sfp_sm_event(sfp, SFP_E_REMOVE);
++	sfp_sm_event(sfp, SFP_E_DEV_DETACH);
+ }
+ 
+ static void sfp_start(struct sfp *sfp)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/733-v5.5-net-sfp-split-power-mode-switching-from-probe.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/733-v5.5-net-sfp-split-power-mode-switching-from-probe.patch
new file mode 100644
index 0000000..f645e44
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/733-v5.5-net-sfp-split-power-mode-switching-from-probe.patch
@@ -0,0 +1,184 @@
+From fdff863a4ce3677907f64396e34c45025abb6600 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 5 Nov 2019 12:59:36 +0000
+Subject: [PATCH 631/660] net: sfp: split power mode switching from probe
+
+Switch the power mode switching from the probe, so that we don't
+repeatedly re-probe the SFP device if there is a problem accessing
+the registers at I2C address 0x51.
+
+In splitting this out, we can also fix a bug where we leave the module
+in high-power mode when the upstream device is detached but the module
+is still inserted.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 101 ++++++++++++++++++++++++++----------------
+ 1 file changed, 64 insertions(+), 37 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -49,6 +49,7 @@ enum {
+ 	SFP_MOD_EMPTY = 0,
+ 	SFP_MOD_PROBE,
+ 	SFP_MOD_HPOWER,
++	SFP_MOD_WAITPWR,
+ 	SFP_MOD_PRESENT,
+ 	SFP_MOD_ERROR,
+ 
+@@ -71,6 +72,7 @@ static const char  * const mod_state_str
+ 	[SFP_MOD_EMPTY] = "empty",
+ 	[SFP_MOD_PROBE] = "probe",
+ 	[SFP_MOD_HPOWER] = "hpower",
++	[SFP_MOD_WAITPWR] = "waitpwr",
+ 	[SFP_MOD_PRESENT] = "present",
+ 	[SFP_MOD_ERROR] = "error",
+ };
+@@ -1423,37 +1425,34 @@ static int sfp_module_parse_power(struct
+ 	return 0;
+ }
+ 
+-static int sfp_sm_mod_hpower(struct sfp *sfp)
++static int sfp_sm_mod_hpower(struct sfp *sfp, bool enable)
+ {
+ 	u8 val;
+ 	int err;
+ 
+-	if (sfp->module_power_mW <= 1000)
+-		return 0;
+-
+ 	err = sfp_read(sfp, true, SFP_EXT_STATUS, &val, sizeof(val));
+ 	if (err != sizeof(val)) {
+ 		dev_err(sfp->dev, "Failed to read EEPROM: %d\n", err);
+-		err = -EAGAIN;
+-		goto err;
++		return -EAGAIN;
+ 	}
+ 
+-	val |= BIT(0);
++	if (enable)
++		val |= BIT(0);
++	else
++		val &= ~BIT(0);
+ 
+ 	err = sfp_write(sfp, true, SFP_EXT_STATUS, &val, sizeof(val));
+ 	if (err != sizeof(val)) {
+ 		dev_err(sfp->dev, "Failed to write EEPROM: %d\n", err);
+-		err = -EAGAIN;
+-		goto err;
++		return -EAGAIN;
+ 	}
+ 
+-	dev_info(sfp->dev, "Module switched to %u.%uW power level\n",
+-		 sfp->module_power_mW / 1000,
+-		 (sfp->module_power_mW / 100) % 10);
+-	return T_HPOWER_LEVEL;
++	if (enable)
++		dev_info(sfp->dev, "Module switched to %u.%uW power level\n",
++			 sfp->module_power_mW / 1000,
++			 (sfp->module_power_mW / 100) % 10);
+ 
+-err:
+-	return err;
++	return 0;
+ }
+ 
+ static int sfp_sm_mod_probe(struct sfp *sfp)
+@@ -1549,7 +1548,7 @@ static int sfp_sm_mod_probe(struct sfp *
+ 	if (ret < 0)
+ 		return ret;
+ 
+-	return sfp_sm_mod_hpower(sfp);
++	return 0;
+ }
+ 
+ static void sfp_sm_mod_remove(struct sfp *sfp)
+@@ -1594,13 +1593,22 @@ static void sfp_sm_device(struct sfp *sf
+  */
+ static void sfp_sm_module(struct sfp *sfp, unsigned int event)
+ {
+-	/* Handle remove event globally, it resets this state machine.
+-	 * Also deal with upstream detachment.
+-	 */
+-	if (event == SFP_E_REMOVE || sfp->sm_dev_state < SFP_DEV_DOWN) {
++	int err;
++
++	/* Handle remove event globally, it resets this state machine */
++	if (event == SFP_E_REMOVE) {
+ 		if (sfp->sm_mod_state > SFP_MOD_PROBE)
+ 			sfp_sm_mod_remove(sfp);
+-		if (sfp->sm_mod_state != SFP_MOD_EMPTY)
++		sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
++		return;
++	}
++
++	/* Handle device detach globally */
++	if (sfp->sm_dev_state < SFP_DEV_DOWN) {
++		if (sfp->module_power_mW > 1000 &&
++		    sfp->sm_mod_state > SFP_MOD_HPOWER)
++			sfp_sm_mod_hpower(sfp, false);
++		if (sfp->sm_mod_state > SFP_MOD_EMPTY)
+ 			sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
+ 		return;
+ 	}
+@@ -1612,26 +1620,45 @@ static void sfp_sm_module(struct sfp *sf
+ 		break;
+ 
+ 	case SFP_MOD_PROBE:
+-		if (event == SFP_E_TIMEOUT) {
+-			int val = sfp_sm_mod_probe(sfp);
++		if (event != SFP_E_TIMEOUT)
++			break;
+ 
+-			if (val == 0)
+-				sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0);
+-			else if (val > 0)
+-				sfp_sm_mod_next(sfp, SFP_MOD_HPOWER, val);
+-			else if (val != -EAGAIN)
+-				sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
+-			else
+-				sfp_sm_set_timer(sfp, T_PROBE_RETRY);
++		err = sfp_sm_mod_probe(sfp);
++		if (err == -EAGAIN) {
++			sfp_sm_set_timer(sfp, T_PROBE_RETRY);
++			break;
+ 		}
+-		break;
++		if (err < 0) {
++			sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
++			break;
++		}
++
++		/* If this is a power level 1 module, we are done */
++		if (sfp->module_power_mW <= 1000)
++			goto insert;
+ 
++		sfp_sm_mod_next(sfp, SFP_MOD_HPOWER, 0);
++		/* fall through */
+ 	case SFP_MOD_HPOWER:
+-		if (event == SFP_E_TIMEOUT) {
+-			sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0);
++		/* Enable high power mode */
++		err = sfp_sm_mod_hpower(sfp, true);
++		if (err == 0)
++			sfp_sm_mod_next(sfp, SFP_MOD_WAITPWR, T_HPOWER_LEVEL);
++		else if (err != -EAGAIN)
++			sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
++		else
++			sfp_sm_set_timer(sfp, T_PROBE_RETRY);
++		break;
++
++	case SFP_MOD_WAITPWR:
++		/* Wait for T_HPOWER_LEVEL to time out */
++		if (event != SFP_E_TIMEOUT)
+ 			break;
+-		}
+-		/* fallthrough */
++
++	insert:
++		sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0);
++		break;
++
+ 	case SFP_MOD_PRESENT:
+ 	case SFP_MOD_ERROR:
+ 		break;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/734-v5.5-net-sfp-move-module-insert-reporting-out-of-probe.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/734-v5.5-net-sfp-move-module-insert-reporting-out-of-probe.patch
new file mode 100644
index 0000000..e49bde2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/734-v5.5-net-sfp-move-module-insert-reporting-out-of-probe.patch
@@ -0,0 +1,159 @@
+From 57cbf7453551db1df619b79410d79fc418d862d5 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 5 Nov 2019 13:00:45 +0000
+Subject: [PATCH 632/660] net: sfp: move module insert reporting out of probe
+
+Move the module insertion reporting out of the probe handling, but
+after we have detected that the upstream has attached (since that is
+whom we are reporting insertion to.)
+
+Only report module removal if we had previously reported a module
+insertion.
+
+This gives cleaner semantics, and means we can probe the module before
+we have an upstream attached.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 58 +++++++++++++++++++++++++++++--------------
+ 1 file changed, 40 insertions(+), 18 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -47,11 +47,12 @@ enum {
+ 	SFP_E_TIMEOUT,
+ 
+ 	SFP_MOD_EMPTY = 0,
++	SFP_MOD_ERROR,
+ 	SFP_MOD_PROBE,
++	SFP_MOD_WAITDEV,
+ 	SFP_MOD_HPOWER,
+ 	SFP_MOD_WAITPWR,
+ 	SFP_MOD_PRESENT,
+-	SFP_MOD_ERROR,
+ 
+ 	SFP_DEV_DETACHED = 0,
+ 	SFP_DEV_DOWN,
+@@ -70,11 +71,12 @@ enum {
+ 
+ static const char  * const mod_state_strings[] = {
+ 	[SFP_MOD_EMPTY] = "empty",
++	[SFP_MOD_ERROR] = "error",
+ 	[SFP_MOD_PROBE] = "probe",
++	[SFP_MOD_WAITDEV] = "waitdev",
+ 	[SFP_MOD_HPOWER] = "hpower",
+ 	[SFP_MOD_WAITPWR] = "waitpwr",
+ 	[SFP_MOD_PRESENT] = "present",
+-	[SFP_MOD_ERROR] = "error",
+ };
+ 
+ static const char *mod_state_to_str(unsigned short mod_state)
+@@ -1544,16 +1546,13 @@ static int sfp_sm_mod_probe(struct sfp *
+ 	if (ret < 0)
+ 		return ret;
+ 
+-	ret = sfp_module_insert(sfp->sfp_bus, &sfp->id);
+-	if (ret < 0)
+-		return ret;
+-
+ 	return 0;
+ }
+ 
+ static void sfp_sm_mod_remove(struct sfp *sfp)
+ {
+-	sfp_module_remove(sfp->sfp_bus);
++	if (sfp->sm_mod_state > SFP_MOD_WAITDEV)
++		sfp_module_remove(sfp->sfp_bus);
+ 
+ 	sfp_hwmon_remove(sfp);
+ 
+@@ -1604,12 +1603,12 @@ static void sfp_sm_module(struct sfp *sf
+ 	}
+ 
+ 	/* Handle device detach globally */
+-	if (sfp->sm_dev_state < SFP_DEV_DOWN) {
++	if (sfp->sm_dev_state < SFP_DEV_DOWN &&
++	    sfp->sm_mod_state > SFP_MOD_WAITDEV) {
+ 		if (sfp->module_power_mW > 1000 &&
+ 		    sfp->sm_mod_state > SFP_MOD_HPOWER)
+ 			sfp_sm_mod_hpower(sfp, false);
+-		if (sfp->sm_mod_state > SFP_MOD_EMPTY)
+-			sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
++		sfp_sm_mod_next(sfp, SFP_MOD_WAITDEV, 0);
+ 		return;
+ 	}
+ 
+@@ -1620,6 +1619,7 @@ static void sfp_sm_module(struct sfp *sf
+ 		break;
+ 
+ 	case SFP_MOD_PROBE:
++		/* Wait for T_PROBE_INIT to time out */
+ 		if (event != SFP_E_TIMEOUT)
+ 			break;
+ 
+@@ -1633,6 +1633,20 @@ static void sfp_sm_module(struct sfp *sf
+ 			break;
+ 		}
+ 
++		sfp_sm_mod_next(sfp, SFP_MOD_WAITDEV, 0);
++		/* fall through */
++	case SFP_MOD_WAITDEV:
++		/* Ensure that the device is attached before proceeding */
++		if (sfp->sm_dev_state < SFP_DEV_DOWN)
++			break;
++
++		/* Report the module insertion to the upstream device */
++		err = sfp_module_insert(sfp->sfp_bus, &sfp->id);
++		if (err < 0) {
++			sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
++			break;
++		}
++
+ 		/* If this is a power level 1 module, we are done */
+ 		if (sfp->module_power_mW <= 1000)
+ 			goto insert;
+@@ -1642,12 +1656,17 @@ static void sfp_sm_module(struct sfp *sf
+ 	case SFP_MOD_HPOWER:
+ 		/* Enable high power mode */
+ 		err = sfp_sm_mod_hpower(sfp, true);
+-		if (err == 0)
+-			sfp_sm_mod_next(sfp, SFP_MOD_WAITPWR, T_HPOWER_LEVEL);
+-		else if (err != -EAGAIN)
+-			sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
+-		else
+-			sfp_sm_set_timer(sfp, T_PROBE_RETRY);
++		if (err < 0) {
++			if (err != -EAGAIN) {
++				sfp_module_remove(sfp->sfp_bus);
++				sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
++			} else {
++				sfp_sm_set_timer(sfp, T_PROBE_RETRY);
++			}
++			break;
++		}
++
++		sfp_sm_mod_next(sfp, SFP_MOD_WAITPWR, T_HPOWER_LEVEL);
+ 		break;
+ 
+ 	case SFP_MOD_WAITPWR:
+@@ -1815,8 +1834,6 @@ static void sfp_sm_event(struct sfp *sfp
+ static void sfp_attach(struct sfp *sfp)
+ {
+ 	sfp_sm_event(sfp, SFP_E_DEV_ATTACH);
+-	if (sfp->state & SFP_F_PRESENT)
+-		sfp_sm_event(sfp, SFP_E_INSERT);
+ }
+ 
+ static void sfp_detach(struct sfp *sfp)
+@@ -2084,6 +2101,11 @@ static int sfp_probe(struct platform_dev
+ 		sfp->state |= SFP_F_RATE_SELECT;
+ 	sfp_set_state(sfp, sfp->state);
+ 	sfp_module_tx_disable(sfp);
++	if (sfp->state & SFP_F_PRESENT) {
++		rtnl_lock();
++		sfp_sm_event(sfp, SFP_E_INSERT);
++		rtnl_unlock();
++	}
+ 
+ 	for (i = 0; i < GPIO_MAX; i++) {
+ 		if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i])
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/735-v5.5-net-sfp-allow-sfp-to-probe-slow-to-initialise-GPON-m.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/735-v5.5-net-sfp-allow-sfp-to-probe-slow-to-initialise-GPON-m.patch
new file mode 100644
index 0000000..ab1ae75
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/735-v5.5-net-sfp-allow-sfp-to-probe-slow-to-initialise-GPON-m.patch
@@ -0,0 +1,110 @@
+From fb56cd08880aff8fb030e684fa4311bef712a499 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 5 Nov 2019 13:02:30 +0000
+Subject: [PATCH 633/660] net: sfp: allow sfp to probe slow to initialise GPON
+ modules
+
+Some GPON modules (e.g. Huawei MA5671A) take a significant amount of
+time to start responding on the I2C bus, contary to the SFF
+specifications.
+
+Work around this by implementing a two-level timeout strategy, where
+we initially quickly retry for the module, and then use a slower retry
+after we exceed a maximum number of quick attempts.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 38 ++++++++++++++++++++++++++++----------
+ 1 file changed, 28 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -167,9 +167,12 @@ static const enum gpiod_flags gpio_flags
+  * The SFF-8472 specifies t_serial ("Time from power on until module is
+  * ready for data transmission over the two wire serial bus.") as 300ms.
+  */
+-#define T_SERIAL	msecs_to_jiffies(300)
+-#define T_HPOWER_LEVEL	msecs_to_jiffies(300)
+-#define T_PROBE_RETRY	msecs_to_jiffies(100)
++#define T_SERIAL		msecs_to_jiffies(300)
++#define T_HPOWER_LEVEL		msecs_to_jiffies(300)
++#define T_PROBE_RETRY_INIT	msecs_to_jiffies(100)
++#define R_PROBE_RETRY_INIT	10
++#define T_PROBE_RETRY_SLOW	msecs_to_jiffies(5000)
++#define R_PROBE_RETRY_SLOW	12
+ 
+ /* SFP modules appear to always have their PHY configured for bus address
+  * 0x56 (which with mdio-i2c, translates to a PHY address of 22).
+@@ -204,6 +207,8 @@ struct sfp {
+ 	struct delayed_work timeout;
+ 	struct mutex sm_mutex;			/* Protects state machine */
+ 	unsigned char sm_mod_state;
++	unsigned char sm_mod_tries_init;
++	unsigned char sm_mod_tries;
+ 	unsigned char sm_dev_state;
+ 	unsigned short sm_state;
+ 	unsigned int sm_retries;
+@@ -1457,7 +1462,7 @@ static int sfp_sm_mod_hpower(struct sfp
+ 	return 0;
+ }
+ 
+-static int sfp_sm_mod_probe(struct sfp *sfp)
++static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
+ {
+ 	/* SFP module inserted - read I2C data */
+ 	struct sfp_eeprom_id id;
+@@ -1467,7 +1472,8 @@ static int sfp_sm_mod_probe(struct sfp *
+ 
+ 	ret = sfp_read(sfp, false, 0, &id, sizeof(id));
+ 	if (ret < 0) {
+-		dev_err(sfp->dev, "failed to read EEPROM: %d\n", ret);
++		if (report)
++			dev_err(sfp->dev, "failed to read EEPROM: %d\n", ret);
+ 		return -EAGAIN;
+ 	}
+ 
+@@ -1614,8 +1620,11 @@ static void sfp_sm_module(struct sfp *sf
+ 
+ 	switch (sfp->sm_mod_state) {
+ 	default:
+-		if (event == SFP_E_INSERT)
++		if (event == SFP_E_INSERT) {
+ 			sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL);
++			sfp->sm_mod_tries_init = R_PROBE_RETRY_INIT;
++			sfp->sm_mod_tries = R_PROBE_RETRY_SLOW;
++		}
+ 		break;
+ 
+ 	case SFP_MOD_PROBE:
+@@ -1623,10 +1632,19 @@ static void sfp_sm_module(struct sfp *sf
+ 		if (event != SFP_E_TIMEOUT)
+ 			break;
+ 
+-		err = sfp_sm_mod_probe(sfp);
++		err = sfp_sm_mod_probe(sfp, sfp->sm_mod_tries == 1);
+ 		if (err == -EAGAIN) {
+-			sfp_sm_set_timer(sfp, T_PROBE_RETRY);
+-			break;
++			if (sfp->sm_mod_tries_init &&
++			   --sfp->sm_mod_tries_init) {
++				sfp_sm_set_timer(sfp, T_PROBE_RETRY_INIT);
++				break;
++			} else if (sfp->sm_mod_tries && --sfp->sm_mod_tries) {
++				if (sfp->sm_mod_tries == R_PROBE_RETRY_SLOW - 1)
++					dev_warn(sfp->dev,
++						 "please wait, module slow to respond\n");
++				sfp_sm_set_timer(sfp, T_PROBE_RETRY_SLOW);
++				break;
++			}
+ 		}
+ 		if (err < 0) {
+ 			sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
+@@ -1661,7 +1679,7 @@ static void sfp_sm_module(struct sfp *sf
+ 				sfp_module_remove(sfp->sfp_bus);
+ 				sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
+ 			} else {
+-				sfp_sm_set_timer(sfp, T_PROBE_RETRY);
++				sfp_sm_set_timer(sfp, T_PROBE_RETRY_INIT);
+ 			}
+ 			break;
+ 		}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/736-v5.5-net-sfp-allow-modules-with-slow-diagnostics-to-probe.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/736-v5.5-net-sfp-allow-modules-with-slow-diagnostics-to-probe.patch
new file mode 100644
index 0000000..e6c1fd7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/736-v5.5-net-sfp-allow-modules-with-slow-diagnostics-to-probe.patch
@@ -0,0 +1,198 @@
+From 559391fc20fae506adcb311b904cc544c76436c0 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Thu, 7 Nov 2019 18:52:07 +0000
+Subject: [PATCH 634/660] net: sfp: allow modules with slow diagnostics to
+ probe
+
+When a module is inserted, we attempt to read read the ID from address
+0x50.  Once we are able to read the ID, we immediately attempt to
+initialise the hwmon support by reading from address 0x51.  If this
+fails, then we fall into error state, and assume that the module is
+not usable.
+
+Modules such as the ALCATELLUCENT 3FE46541AA use a real EEPROM for
+I2C address 0x50, which responds immediately.  However, address 0x51
+is an emulated, which only becomes available once the on-board firmware
+has booted.  This prompts us to fall into the error state.
+
+Since the module may be usable without diagnostics, arrange for the
+hwmon probe independent of the rest of the SFP itself, retrying every
+5s for up to about 60s for the monitoring to become available, and
+print an error message if it doesn't become available.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 96 +++++++++++++++++++++++++++++++++----------
+ 1 file changed, 74 insertions(+), 22 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -218,6 +218,8 @@ struct sfp {
+ 
+ #if IS_ENABLED(CONFIG_HWMON)
+ 	struct sfp_diag diag;
++	struct delayed_work hwmon_probe;
++	unsigned int hwmon_tries;
+ 	struct device *hwmon_dev;
+ 	char *hwmon_name;
+ #endif
+@@ -1159,29 +1161,27 @@ static const struct hwmon_chip_info sfp_
+ 	.info = sfp_hwmon_info,
+ };
+ 
+-static int sfp_hwmon_insert(struct sfp *sfp)
++static void sfp_hwmon_probe(struct work_struct *work)
+ {
++	struct sfp *sfp = container_of(work, struct sfp, hwmon_probe.work);
+ 	int err, i;
+ 
+-	if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE)
+-		return 0;
+-
+-	if (!(sfp->id.ext.diagmon & SFP_DIAGMON_DDM))
+-		return 0;
+-
+-	if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE)
+-		/* This driver in general does not support address
+-		 * change.
+-		 */
+-		return 0;
+-
+ 	err = sfp_read(sfp, true, 0, &sfp->diag, sizeof(sfp->diag));
+-	if (err < 0)
+-		return err;
++	if (err < 0) {
++		if (sfp->hwmon_tries--) {
++			mod_delayed_work(system_wq, &sfp->hwmon_probe,
++					 T_PROBE_RETRY_SLOW);
++		} else {
++			dev_warn(sfp->dev, "hwmon probe failed: %d\n", err);
++		}
++		return;
++	}
+ 
+ 	sfp->hwmon_name = kstrdup(dev_name(sfp->dev), GFP_KERNEL);
+-	if (!sfp->hwmon_name)
+-		return -ENODEV;
++	if (!sfp->hwmon_name) {
++		dev_err(sfp->dev, "out of memory for hwmon name\n");
++		return;
++	}
+ 
+ 	for (i = 0; sfp->hwmon_name[i]; i++)
+ 		if (hwmon_is_bad_char(sfp->hwmon_name[i]))
+@@ -1191,18 +1191,52 @@ static int sfp_hwmon_insert(struct sfp *
+ 							 sfp->hwmon_name, sfp,
+ 							 &sfp_hwmon_chip_info,
+ 							 NULL);
++	if (IS_ERR(sfp->hwmon_dev))
++		dev_err(sfp->dev, "failed to register hwmon device: %ld\n",
++			PTR_ERR(sfp->hwmon_dev));
++}
++
++static int sfp_hwmon_insert(struct sfp *sfp)
++{
++	if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE)
++		return 0;
++
++	if (!(sfp->id.ext.diagmon & SFP_DIAGMON_DDM))
++		return 0;
++
++	if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE)
++		/* This driver in general does not support address
++		 * change.
++		 */
++		return 0;
++
++	mod_delayed_work(system_wq, &sfp->hwmon_probe, 1);
++	sfp->hwmon_tries = R_PROBE_RETRY_SLOW;
+ 
+-	return PTR_ERR_OR_ZERO(sfp->hwmon_dev);
++	return 0;
+ }
+ 
+ static void sfp_hwmon_remove(struct sfp *sfp)
+ {
++	cancel_delayed_work_sync(&sfp->hwmon_probe);
+ 	if (!IS_ERR_OR_NULL(sfp->hwmon_dev)) {
+ 		hwmon_device_unregister(sfp->hwmon_dev);
+ 		sfp->hwmon_dev = NULL;
+ 		kfree(sfp->hwmon_name);
+ 	}
+ }
++
++static int sfp_hwmon_init(struct sfp *sfp)
++{
++	INIT_DELAYED_WORK(&sfp->hwmon_probe, sfp_hwmon_probe);
++
++	return 0;
++}
++
++static void sfp_hwmon_exit(struct sfp *sfp)
++{
++	cancel_delayed_work_sync(&sfp->hwmon_probe);
++}
+ #else
+ static int sfp_hwmon_insert(struct sfp *sfp)
+ {
+@@ -1212,6 +1246,15 @@ static int sfp_hwmon_insert(struct sfp *
+ static void sfp_hwmon_remove(struct sfp *sfp)
+ {
+ }
++
++static int sfp_hwmon_init(struct sfp *sfp)
++{
++	return 0;
++}
++
++static void sfp_hwmon_exit(struct sfp *sfp)
++{
++}
+ #endif
+ 
+ /* Helpers */
+@@ -1548,10 +1591,6 @@ static int sfp_sm_mod_probe(struct sfp *
+ 	if (ret < 0)
+ 		return ret;
+ 
+-	ret = sfp_hwmon_insert(sfp);
+-	if (ret < 0)
+-		return ret;
+-
+ 	return 0;
+ }
+ 
+@@ -1700,6 +1739,15 @@ static void sfp_sm_module(struct sfp *sf
+ 	case SFP_MOD_ERROR:
+ 		break;
+ 	}
++
++#if IS_ENABLED(CONFIG_HWMON)
++	if (sfp->sm_mod_state >= SFP_MOD_WAITDEV &&
++	    IS_ERR_OR_NULL(sfp->hwmon_dev)) {
++		err = sfp_hwmon_insert(sfp);
++		if (err)
++			dev_warn(sfp->dev, "hwmon probe failed: %d\n", err);
++	}
++#endif
+ }
+ 
+ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
+@@ -2001,6 +2049,8 @@ static struct sfp *sfp_alloc(struct devi
+ 	INIT_DELAYED_WORK(&sfp->poll, sfp_poll);
+ 	INIT_DELAYED_WORK(&sfp->timeout, sfp_timeout);
+ 
++	sfp_hwmon_init(sfp);
++
+ 	return sfp;
+ }
+ 
+@@ -2008,6 +2058,8 @@ static void sfp_cleanup(void *data)
+ {
+ 	struct sfp *sfp = data;
+ 
++	sfp_hwmon_exit(sfp);
++
+ 	cancel_delayed_work_sync(&sfp->poll);
+ 	cancel_delayed_work_sync(&sfp->timeout);
+ 	if (sfp->i2c_mii) {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/737-v5.5-net-phy-add-core-phylib-sfp-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/737-v5.5-net-phy-add-core-phylib-sfp-support.patch
new file mode 100644
index 0000000..edfe151
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/737-v5.5-net-phy-add-core-phylib-sfp-support.patch
@@ -0,0 +1,183 @@
+From eb156db588ac583cdae7b91eaac9c0ad3a358e63 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Sun, 15 Sep 2019 20:05:34 +0100
+Subject: [PATCH 635/660] net: phy: add core phylib sfp support
+
+Add core phylib help for supporting SFP sockets on PHYs.  This provides
+a mechanism to inform the SFP layer about PHY up/down events, and also
+unregister the SFP bus when the PHY is going away.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phy.c        |  7 ++++
+ drivers/net/phy/phy_device.c | 66 ++++++++++++++++++++++++++++++++++++
+ include/linux/phy.h          | 11 ++++++
+ 3 files changed, 84 insertions(+)
+
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -23,6 +23,7 @@
+ #include <linux/ethtool.h>
+ #include <linux/phy.h>
+ #include <linux/phy_led_triggers.h>
++#include <linux/sfp.h>
+ #include <linux/workqueue.h>
+ #include <linux/mdio.h>
+ #include <linux/io.h>
+@@ -863,6 +864,9 @@ void phy_stop(struct phy_device *phydev)
+ 
+ 	mutex_lock(&phydev->lock);
+ 
++	if (phydev->sfp_bus)
++		sfp_upstream_stop(phydev->sfp_bus);
++
+ 	phydev->state = PHY_HALTED;
+ 
+ 	mutex_unlock(&phydev->lock);
+@@ -925,6 +929,9 @@ void phy_state_machine(struct work_struc
+ 
+ 	old_state = phydev->state;
+ 
++	if (phydev->sfp_bus)
++		sfp_upstream_start(phydev->sfp_bus);
++
+ 	switch (phydev->state) {
+ 	case PHY_DOWN:
+ 	case PHY_READY:
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -27,6 +27,7 @@
+ #include <linux/bitmap.h>
+ #include <linux/phy.h>
+ #include <linux/phy_led_triggers.h>
++#include <linux/sfp.h>
+ #include <linux/mdio.h>
+ #include <linux/io.h>
+ #include <linux/uaccess.h>
+@@ -1185,6 +1186,65 @@ phy_standalone_show(struct device *dev,
+ static DEVICE_ATTR_RO(phy_standalone);
+ 
+ /**
++ * phy_sfp_attach - attach the SFP bus to the PHY upstream network device
++ * @upstream: pointer to the phy device
++ * @bus: sfp bus representing cage being attached
++ *
++ * This is used to fill in the sfp_upstream_ops .attach member.
++ */
++void phy_sfp_attach(void *upstream, struct sfp_bus *bus)
++{
++	struct phy_device *phydev = upstream;
++
++	if (phydev->attached_dev)
++		phydev->attached_dev->sfp_bus = bus;
++	phydev->sfp_bus_attached = true;
++}
++EXPORT_SYMBOL(phy_sfp_attach);
++
++/**
++ * phy_sfp_detach - detach the SFP bus from the PHY upstream network device
++ * @upstream: pointer to the phy device
++ * @bus: sfp bus representing cage being attached
++ *
++ * This is used to fill in the sfp_upstream_ops .detach member.
++ */
++void phy_sfp_detach(void *upstream, struct sfp_bus *bus)
++{
++	struct phy_device *phydev = upstream;
++
++	if (phydev->attached_dev)
++		phydev->attached_dev->sfp_bus = NULL;
++	phydev->sfp_bus_attached = false;
++}
++EXPORT_SYMBOL(phy_sfp_detach);
++
++/**
++ * phy_sfp_probe - probe for a SFP cage attached to this PHY device
++ * @phydev: Pointer to phy_device
++ * @ops: SFP's upstream operations
++ */
++int phy_sfp_probe(struct phy_device *phydev,
++		  const struct sfp_upstream_ops *ops)
++{
++	struct sfp_bus *bus;
++	int ret;
++
++	if (phydev->mdio.dev.fwnode) {
++		bus = sfp_bus_find_fwnode(phydev->mdio.dev.fwnode);
++		if (IS_ERR(bus))
++			return PTR_ERR(bus);
++
++		phydev->sfp_bus = bus;
++
++		ret = sfp_bus_add_upstream(bus, phydev, ops);
++		sfp_bus_put(bus);
++	}
++	return 0;
++}
++EXPORT_SYMBOL(phy_sfp_probe);
++
++/**
+  * phy_attach_direct - attach a network device to a given PHY device pointer
+  * @dev: network device to attach
+  * @phydev: Pointer to phy_device to attach
+@@ -1261,6 +1321,9 @@ int phy_attach_direct(struct net_device
+ 		dev->phydev = phydev;
+ 	}
+ 
++	if (phydev->sfp_bus_attached)
++		dev->sfp_bus = phydev->sfp_bus;
++
+ 	/* Some Ethernet drivers try to connect to a PHY device before
+ 	 * calling register_netdevice() -> netdev_register_kobject() and
+ 	 * does the dev->dev.kobj initialization. Here we only check for
+@@ -2291,6 +2354,9 @@ static int phy_remove(struct device *dev
+ 	phydev->state = PHY_DOWN;
+ 	mutex_unlock(&phydev->lock);
+ 
++	sfp_bus_del_upstream(phydev->sfp_bus);
++	phydev->sfp_bus = NULL;
++
+ 	if (phydev->drv && phydev->drv->remove) {
+ 		phydev->drv->remove(phydev);
+ 
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -203,6 +203,8 @@ static inline const char *phy_modes(phy_
+ 
+ struct device;
+ struct phylink;
++struct sfp_bus;
++struct sfp_upstream_ops;
+ struct sk_buff;
+ 
+ /*
+@@ -343,6 +345,8 @@ struct phy_c45_device_ids {
+  * dev_flags: Device-specific flags used by the PHY driver.
+  * irq: IRQ number of the PHY's interrupt (-1 if none)
+  * phy_timer: The timer for handling the state machine
++ * sfp_bus_attached: flag indicating whether the SFP bus has been attached
++ * sfp_bus: SFP bus attached to this PHY's fiber port
+  * attached_dev: The attached enet driver's device instance ptr
+  * adjust_link: Callback for the enet controller to respond to
+  * changes in the link state.
+@@ -434,6 +438,9 @@ struct phy_device {
+ 
+ 	struct mutex lock;
+ 
++	/* This may be modified under the rtnl lock */
++	bool sfp_bus_attached;
++	struct sfp_bus *sfp_bus;
+ 	struct phylink *phylink;
+ 	struct net_device *attached_dev;
+ 
+@@ -1023,6 +1030,10 @@ int phy_suspend(struct phy_device *phyde
+ int phy_resume(struct phy_device *phydev);
+ int __phy_resume(struct phy_device *phydev);
+ int phy_loopback(struct phy_device *phydev, bool enable);
++void phy_sfp_attach(void *upstream, struct sfp_bus *bus);
++void phy_sfp_detach(void *upstream, struct sfp_bus *bus);
++int phy_sfp_probe(struct phy_device *phydev,
++	          const struct sfp_upstream_ops *ops);
+ struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
+ 			      phy_interface_t interface);
+ struct phy_device *phy_find_first(struct mii_bus *bus);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/738-v5.5-net-phy-marvell10g-add-SFP-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/738-v5.5-net-phy-marvell10g-add-SFP-support.patch
new file mode 100644
index 0000000..40a666a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/738-v5.5-net-phy-marvell10g-add-SFP-support.patch
@@ -0,0 +1,67 @@
+From 0836d9fb41ed90090ef4af0d7abe784ee7706f80 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 14 Apr 2017 14:21:25 +0100
+Subject: [PATCH 636/660] net: phy: marvell10g: add SFP+ support
+
+Add support for SFP+ cages to the Marvell 10G PHY driver. This is
+slightly complicated by the way phylib works in that we need to use
+a multi-step process to attach the SFP bus, and we also need to track
+the phylink state machine to know when the module's transmit disable
+signal should change state.
+
+With appropriate DT changes, this allows the SFP+ canges on the
+Macchiatobin platform to be functional.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/marvell10g.c | 25 ++++++++++++++++++++++++-
+ 1 file changed, 24 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/phy/marvell10g.c
++++ b/drivers/net/phy/marvell10g.c
+@@ -26,6 +26,7 @@
+ #include <linux/hwmon.h>
+ #include <linux/marvell_phy.h>
+ #include <linux/phy.h>
++#include <linux/sfp.h>
+ 
+ #define MV_PHY_ALASKA_NBT_QUIRK_MASK	0xfffffffe
+ #define MV_PHY_ALASKA_NBT_QUIRK_REV	(MARVELL_PHY_ID_88X3310 | 0xa)
+@@ -206,6 +207,28 @@ static int mv3310_hwmon_probe(struct phy
+ }
+ #endif
+ 
++static int mv3310_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
++{
++	struct phy_device *phydev = upstream;
++	__ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
++	phy_interface_t iface;
++
++	sfp_parse_support(phydev->sfp_bus, id, support);
++	iface = sfp_select_interface(phydev->sfp_bus, id, support);
++
++	if (iface != PHY_INTERFACE_MODE_10GKR) {
++		dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n");
++		return -EINVAL;
++	}
++	return 0;
++}
++
++static const struct sfp_upstream_ops mv3310_sfp_ops = {
++	.attach = phy_sfp_attach,
++	.detach = phy_sfp_detach,
++	.module_insert = mv3310_sfp_insert,
++};
++
+ static int mv3310_probe(struct phy_device *phydev)
+ {
+ 	struct mv3310_priv *priv;
+@@ -236,7 +259,7 @@ static int mv3310_probe(struct phy_devic
+ 	if (ret)
+ 		return ret;
+ 
+-	return 0;
++	return phy_sfp_probe(phydev, &mv3310_sfp_ops);
+ }
+ 
+ static int mv3310_suspend(struct phy_device *phydev)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/739-v5.5-net-phylink-update-to-use-phy_support_asym_pause.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/739-v5.5-net-phylink-update-to-use-phy_support_asym_pause.patch
new file mode 100644
index 0000000..84a8214
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/739-v5.5-net-phylink-update-to-use-phy_support_asym_pause.patch
@@ -0,0 +1,43 @@
+From 09d7d8395ec61fba4392b35baa6f71c4e36489df Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 8 Nov 2019 15:18:02 +0000
+Subject: [PATCH 637/660] net: phylink: update to use phy_support_asym_pause()
+
+Use phy_support_asym_pause() rather than open-coding it.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phylink.c | 17 +++++++----------
+ 1 file changed, 7 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -718,11 +718,6 @@ static int phylink_bringup_phy(struct ph
+ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
+ 	int ret;
+ 
+-	memset(&config, 0, sizeof(config));
+-	linkmode_copy(supported, phy->supported);
+-	linkmode_copy(config.advertising, phy->advertising);
+-	config.interface = pl->link_config.interface;
+-
+ 	/*
+ 	 * This is the new way of dealing with flow control for PHYs,
+ 	 * as described by Timur Tabi in commit 529ed1275263 ("net: phy:
+@@ -730,10 +725,12 @@ static int phylink_bringup_phy(struct ph
+ 	 * using our validate call to the MAC, we rely upon the MAC
+ 	 * clearing the bits from both supported and advertising fields.
+ 	 */
+-	if (phylink_test(supported, Pause))
+-		phylink_set(config.advertising, Pause);
+-	if (phylink_test(supported, Asym_Pause))
+-		phylink_set(config.advertising, Asym_Pause);
++	phy_support_asym_pause(phy);
++
++	memset(&config, 0, sizeof(config));
++	linkmode_copy(supported, phy->supported);
++	linkmode_copy(config.advertising, phy->advertising);
++	config.interface = pl->link_config.interface;
+ 
+ 	ret = phylink_validate(pl, supported, &config);
+ 	if (ret)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/744-v5.5-net-sfp-soft-status-and-control-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/744-v5.5-net-sfp-soft-status-and-control-support.patch
new file mode 100644
index 0000000..abc9f65
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/744-v5.5-net-sfp-soft-status-and-control-support.patch
@@ -0,0 +1,225 @@
+From 40e0b3b15f7da92e6b065292b14af7b9bfb1c6e0 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 13 Sep 2019 23:00:35 +0100
+Subject: [PATCH 642/660] net: sfp: soft status and control support
+
+Add support for the soft status and control register, which allows
+TX_FAULT and RX_LOS to be monitored and TX_DISABLE to be set.  We
+make use of this when the board does not support GPIOs for these
+signals.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 110 ++++++++++++++++++++++++++++++++++--------
+ include/linux/sfp.h   |   4 ++
+ 2 files changed, 94 insertions(+), 20 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -201,7 +201,10 @@ struct sfp {
+ 	struct gpio_desc *gpio[GPIO_MAX];
+ 	int gpio_irq[GPIO_MAX];
+ 
++	bool need_poll;
++
+ 	struct mutex st_mutex;			/* Protects state */
++	unsigned int state_soft_mask;
+ 	unsigned int state;
+ 	struct delayed_work poll;
+ 	struct delayed_work timeout;
+@@ -395,24 +398,90 @@ static int sfp_i2c_configure(struct sfp
+ }
+ 
+ /* Interface */
+-static unsigned int sfp_get_state(struct sfp *sfp)
++static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
+ {
+-	return sfp->get_state(sfp);
++	return sfp->read(sfp, a2, addr, buf, len);
+ }
+ 
+-static void sfp_set_state(struct sfp *sfp, unsigned int state)
++static int sfp_write(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
+ {
+-	sfp->set_state(sfp, state);
++	return sfp->write(sfp, a2, addr, buf, len);
+ }
+ 
+-static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
++static unsigned int sfp_soft_get_state(struct sfp *sfp)
+ {
+-	return sfp->read(sfp, a2, addr, buf, len);
++	unsigned int state = 0;
++	u8 status;
++
++	if (sfp_read(sfp, true, SFP_STATUS, &status, sizeof(status)) ==
++		     sizeof(status)) {
++		if (status & SFP_STATUS_RX_LOS)
++			state |= SFP_F_LOS;
++		if (status & SFP_STATUS_TX_FAULT)
++			state |= SFP_F_TX_FAULT;
++	}
++
++	return state & sfp->state_soft_mask;
+ }
+ 
+-static int sfp_write(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
++static void sfp_soft_set_state(struct sfp *sfp, unsigned int state)
+ {
+-	return sfp->write(sfp, a2, addr, buf, len);
++	u8 status;
++
++	if (sfp_read(sfp, true, SFP_STATUS, &status, sizeof(status)) ==
++		     sizeof(status)) {
++		if (state & SFP_F_TX_DISABLE)
++			status |= SFP_STATUS_TX_DISABLE_FORCE;
++		else
++			status &= ~SFP_STATUS_TX_DISABLE_FORCE;
++
++		sfp_write(sfp, true, SFP_STATUS, &status, sizeof(status));
++	}
++}
++
++static void sfp_soft_start_poll(struct sfp *sfp)
++{
++	const struct sfp_eeprom_id *id = &sfp->id;
++
++	sfp->state_soft_mask = 0;
++	if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_DISABLE &&
++	    !sfp->gpio[GPIO_TX_DISABLE])
++		sfp->state_soft_mask |= SFP_F_TX_DISABLE;
++	if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_FAULT &&
++	    !sfp->gpio[GPIO_TX_FAULT])
++		sfp->state_soft_mask |= SFP_F_TX_FAULT;
++	if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS &&
++	    !sfp->gpio[GPIO_LOS])
++		sfp->state_soft_mask |= SFP_F_LOS;
++
++	if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) &&
++	    !sfp->need_poll)
++		mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
++}
++
++static void sfp_soft_stop_poll(struct sfp *sfp)
++{
++	sfp->state_soft_mask = 0;
++}
++
++static unsigned int sfp_get_state(struct sfp *sfp)
++{
++	unsigned int state = sfp->get_state(sfp);
++
++	if (state & SFP_F_PRESENT &&
++	    sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT))
++		state |= sfp_soft_get_state(sfp);
++
++	return state;
++}
++
++static void sfp_set_state(struct sfp *sfp, unsigned int state)
++{
++	sfp->set_state(sfp, state);
++
++	if (state & SFP_F_PRESENT &&
++	    sfp->state_soft_mask & SFP_F_TX_DISABLE)
++		sfp_soft_set_state(sfp, state);
+ }
+ 
+ static unsigned int sfp_check(void *buf, size_t len)
+@@ -1407,11 +1476,6 @@ static void sfp_sm_fault(struct sfp *sfp
+ 	}
+ }
+ 
+-static void sfp_sm_mod_init(struct sfp *sfp)
+-{
+-	sfp_module_tx_enable(sfp);
+-}
+-
+ static void sfp_sm_probe_for_phy(struct sfp *sfp)
+ {
+ 	/* Setting the serdes link mode is guesswork: there's no
+@@ -1574,7 +1638,7 @@ static int sfp_sm_mod_probe(struct sfp *
+ 		 (int)sizeof(id.ext.datecode), id.ext.datecode);
+ 
+ 	/* Check whether we support this module */
+-	if (!sfp->type->module_supported(&sfp->id)) {
++	if (!sfp->type->module_supported(&id)) {
+ 		dev_err(sfp->dev,
+ 			"module is not supported - phys id 0x%02x 0x%02x\n",
+ 			sfp->id.base.phys_id, sfp->id.base.phys_ext_id);
+@@ -1764,6 +1828,7 @@ static void sfp_sm_main(struct sfp *sfp,
+ 		if (sfp->mod_phy)
+ 			sfp_sm_phy_detach(sfp);
+ 		sfp_module_tx_disable(sfp);
++		sfp_soft_stop_poll(sfp);
+ 		sfp_sm_next(sfp, SFP_S_DOWN, 0);
+ 		return;
+ 	}
+@@ -1775,7 +1840,10 @@ static void sfp_sm_main(struct sfp *sfp,
+ 		    sfp->sm_dev_state != SFP_DEV_UP)
+ 			break;
+ 
+-		sfp_sm_mod_init(sfp);
++		if (!(sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE))
++			sfp_soft_start_poll(sfp);
++
++		sfp_module_tx_enable(sfp);
+ 
+ 		/* Initialise the fault clearance retries */
+ 		sfp->sm_retries = 5;
+@@ -2031,7 +2099,10 @@ static void sfp_poll(struct work_struct
+ 	struct sfp *sfp = container_of(work, struct sfp, poll.work);
+ 
+ 	sfp_check_state(sfp);
+-	mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
++
++	if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) ||
++	    sfp->need_poll)
++		mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
+ }
+ 
+ static struct sfp *sfp_alloc(struct device *dev)
+@@ -2076,7 +2147,6 @@ static int sfp_probe(struct platform_dev
+ 	const struct sff_data *sff;
+ 	struct i2c_adapter *i2c;
+ 	struct sfp *sfp;
+-	bool poll = false;
+ 	int err, i;
+ 
+ 	sfp = sfp_alloc(&pdev->dev);
+@@ -2184,7 +2254,7 @@ static int sfp_probe(struct platform_dev
+ 		sfp->gpio_irq[i] = gpiod_to_irq(sfp->gpio[i]);
+ 		if (sfp->gpio_irq[i] < 0) {
+ 			sfp->gpio_irq[i] = 0;
+-			poll = true;
++			sfp->need_poll = true;
+ 			continue;
+ 		}
+ 
+@@ -2196,11 +2266,11 @@ static int sfp_probe(struct platform_dev
+ 						dev_name(sfp->dev), sfp);
+ 		if (err) {
+ 			sfp->gpio_irq[i] = 0;
+-			poll = true;
++			sfp->need_poll = true;
+ 		}
+ 	}
+ 
+-	if (poll)
++	if (sfp->need_poll)
+ 		mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
+ 
+ 	/* We could have an issue in cases no Tx disable pin is available or
+--- a/include/linux/sfp.h
++++ b/include/linux/sfp.h
+@@ -428,6 +428,10 @@ enum {
+ 	SFP_TEC_CUR			= 0x6c,
+ 
+ 	SFP_STATUS			= 0x6e,
++	SFP_STATUS_TX_DISABLE		= BIT(7),
++	SFP_STATUS_TX_DISABLE_FORCE	= BIT(6),
++	SFP_STATUS_TX_FAULT		= BIT(2),
++	SFP_STATUS_RX_LOS		= BIT(1),
+ 	SFP_ALARM0			= 0x70,
+ 	SFP_ALARM0_TEMP_HIGH		= BIT(7),
+ 	SFP_ALARM0_TEMP_LOW		= BIT(6),
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/745-v5.7-net-dsa-mt7530-add-support-for-port-mirroring.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/745-v5.7-net-dsa-mt7530-add-support-for-port-mirroring.patch
new file mode 100644
index 0000000..71a0699
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/745-v5.7-net-dsa-mt7530-add-support-for-port-mirroring.patch
@@ -0,0 +1,123 @@
+From 37feab6076aa816ed72fe836759a485353241916 Mon Sep 17 00:00:00 2001
+From: DENG Qingfang <dqfext@gmail.com>
+Date: Fri, 6 Mar 2020 20:35:35 +0800
+Subject: net: dsa: mt7530: add support for port mirroring
+
+Add support for configuring port mirroring through the cls_matchall
+classifier. We do a full ingress and/or egress capture towards a
+capture port.
+MT7530 supports one monitor port and multiple mirrored ports.
+
+Signed-off-by: DENG Qingfang <dqfext@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mt7530.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/net/dsa/mt7530.h |  7 ++++++
+ 2 files changed, 67 insertions(+)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -1143,6 +1143,64 @@ mt7530_port_vlan_del(struct dsa_switch *
+ 	return 0;
+ }
+ 
++static int mt7530_port_mirror_add(struct dsa_switch *ds, int port,
++				  struct dsa_mall_mirror_tc_entry *mirror,
++				  bool ingress)
++{
++	struct mt7530_priv *priv = ds->priv;
++	u32 val;
++
++	/* Check for existent entry */
++	if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port))
++		return -EEXIST;
++
++	val = mt7530_read(priv, MT7530_MFC);
++
++	/* MT7530 only supports one monitor port */
++	if (val & MIRROR_EN && MIRROR_PORT(val) != mirror->to_local_port)
++		return -EEXIST;
++
++	val |= MIRROR_EN;
++	val &= ~MIRROR_MASK;
++	val |= mirror->to_local_port;
++	mt7530_write(priv, MT7530_MFC, val);
++
++	val = mt7530_read(priv, MT7530_PCR_P(port));
++	if (ingress) {
++		val |= PORT_RX_MIR;
++		priv->mirror_rx |= BIT(port);
++	} else {
++		val |= PORT_TX_MIR;
++		priv->mirror_tx |= BIT(port);
++	}
++	mt7530_write(priv, MT7530_PCR_P(port), val);
++
++	return 0;
++}
++
++static void mt7530_port_mirror_del(struct dsa_switch *ds, int port,
++				   struct dsa_mall_mirror_tc_entry *mirror)
++{
++	struct mt7530_priv *priv = ds->priv;
++	u32 val;
++
++	val = mt7530_read(priv, MT7530_PCR_P(port));
++	if (mirror->ingress) {
++		val &= ~PORT_RX_MIR;
++		priv->mirror_rx &= ~BIT(port);
++	} else {
++		val &= ~PORT_TX_MIR;
++		priv->mirror_tx &= ~BIT(port);
++	}
++	mt7530_write(priv, MT7530_PCR_P(port), val);
++
++	if (!priv->mirror_rx && !priv->mirror_tx) {
++		val = mt7530_read(priv, MT7530_MFC);
++		val &= ~MIRROR_EN;
++		mt7530_write(priv, MT7530_MFC, val);
++	}
++}
++
+ static enum dsa_tag_protocol
+ mtk_get_tag_protocol(struct dsa_switch *ds, int port)
+ {
+@@ -1520,6 +1578,8 @@ static const struct dsa_switch_ops mt753
+ 	.port_vlan_prepare	= mt7530_port_vlan_prepare,
+ 	.port_vlan_add		= mt7530_port_vlan_add,
+ 	.port_vlan_del		= mt7530_port_vlan_del,
++	.port_mirror_add	= mt7530_port_mirror_add,
++	.port_mirror_del	= mt7530_port_mirror_del,
+ 	.phylink_validate	= mt7530_phylink_validate,
+ 	.phylink_mac_link_state = mt7530_phylink_mac_link_state,
+ 	.phylink_mac_config	= mt7530_phylink_mac_config,
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -37,6 +37,9 @@ enum {
+ #define  CPU_EN				BIT(7)
+ #define  CPU_PORT(x)			((x) << 4)
+ #define  CPU_MASK			(0xf << 4)
++#define  MIRROR_EN			BIT(3)
++#define  MIRROR_PORT(x)			((x) & 0x7)
++#define  MIRROR_MASK			0x7
+ 
+ /* Registers for address table access */
+ #define MT7530_ATA1			0x74
+@@ -142,6 +145,8 @@ enum mt7530_stp_state {
+ 
+ /* Register for port control */
+ #define MT7530_PCR_P(x)			(0x2004 + ((x) * 0x100))
++#define  PORT_TX_MIR			BIT(9)
++#define  PORT_RX_MIR			BIT(8)
+ #define  PORT_VLAN(x)			((x) & 0x3)
+ 
+ enum mt7530_port_mode {
+@@ -464,6 +469,8 @@ struct mt7530_priv {
+ 	phy_interface_t		p6_interface;
+ 	phy_interface_t		p5_interface;
+ 	unsigned int		p5_intf_sel;
++	u8			mirror_rx;
++	u8			mirror_tx;
+ 
+ 	struct mt7530_port	ports[MT7530_NUM_PORTS];
+ 	/* protect among processes for registers access*/
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/746-v5.5-net-dsa-mv88e6xxx-Split-monitor-port-configuration.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/746-v5.5-net-dsa-mv88e6xxx-Split-monitor-port-configuration.patch
new file mode 100644
index 0000000..6831787
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/746-v5.5-net-dsa-mv88e6xxx-Split-monitor-port-configuration.patch
@@ -0,0 +1,149 @@
+From 5c74c54ce6fff719999ff48f128cf4150ee4ff59 Mon Sep 17 00:00:00 2001
+From: Iwan R Timmer <irtimmer@gmail.com>
+Date: Thu, 7 Nov 2019 22:11:13 +0100
+Subject: [PATCH] net: dsa: mv88e6xxx: Split monitor port configuration
+
+Separate the configuration of the egress and ingress monitor port.
+This allows the port mirror functionality to do ingress and egress
+port mirroring to separate ports.
+
+Signed-off-by: Iwan R Timmer <irtimmer@gmail.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mv88e6xxx/chip.c    |  9 ++++++-
+ drivers/net/dsa/mv88e6xxx/chip.h    |  9 ++++++-
+ drivers/net/dsa/mv88e6xxx/global1.c | 42 ++++++++++++++++++++---------
+ drivers/net/dsa/mv88e6xxx/global1.h |  8 ++++--
+ 4 files changed, 52 insertions(+), 16 deletions(-)
+
+--- a/drivers/net/dsa/mv88e6xxx/chip.c
++++ b/drivers/net/dsa/mv88e6xxx/chip.c
+@@ -2384,7 +2384,14 @@ static int mv88e6xxx_setup_upstream_port
+ 
+ 		if (chip->info->ops->set_egress_port) {
+ 			err = chip->info->ops->set_egress_port(chip,
+-							       upstream_port);
++						MV88E6XXX_EGRESS_DIR_INGRESS,
++						upstream_port);
++			if (err)
++				return err;
++
++			err = chip->info->ops->set_egress_port(chip,
++						MV88E6XXX_EGRESS_DIR_EGRESS,
++						upstream_port);
+ 			if (err)
+ 				return err;
+ 		}
+--- a/drivers/net/dsa/mv88e6xxx/chip.h
++++ b/drivers/net/dsa/mv88e6xxx/chip.h
+@@ -33,6 +33,11 @@ enum mv88e6xxx_egress_mode {
+ 	MV88E6XXX_EGRESS_MODE_ETHERTYPE,
+ };
+ 
++enum mv88e6xxx_egress_direction {
++        MV88E6XXX_EGRESS_DIR_INGRESS,
++        MV88E6XXX_EGRESS_DIR_EGRESS,
++};
++
+ enum mv88e6xxx_frame_mode {
+ 	MV88E6XXX_FRAME_MODE_NORMAL,
+ 	MV88E6XXX_FRAME_MODE_DSA,
+@@ -464,7 +469,9 @@ struct mv88e6xxx_ops {
+ 	int (*stats_get_stats)(struct mv88e6xxx_chip *chip,  int port,
+ 			       uint64_t *data);
+ 	int (*set_cpu_port)(struct mv88e6xxx_chip *chip, int port);
+-	int (*set_egress_port)(struct mv88e6xxx_chip *chip, int port);
++	int (*set_egress_port)(struct mv88e6xxx_chip *chip,
++			       enum mv88e6xxx_egress_direction direction,
++			       int port);
+ 
+ #define MV88E6XXX_CASCADE_PORT_NONE		0xe
+ #define MV88E6XXX_CASCADE_PORT_MULTIPLE		0xf
+--- a/drivers/net/dsa/mv88e6xxx/global1.c
++++ b/drivers/net/dsa/mv88e6xxx/global1.c
+@@ -294,7 +294,9 @@ int mv88e6250_g1_ieee_pri_map(struct mv8
+ /* Offset 0x1a: Monitor Control */
+ /* Offset 0x1a: Monitor & MGMT Control on some devices */
+ 
+-int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port)
++int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip,
++				 enum mv88e6xxx_egress_direction direction,
++				 int port)
+ {
+ 	u16 reg;
+ 	int err;
+@@ -303,11 +305,20 @@ int mv88e6095_g1_set_egress_port(struct
+ 	if (err)
+ 		return err;
+ 
+-	reg &= ~(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK |
+-		 MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK);
+-
+-	reg |= port << __bf_shf(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK) |
+-		port << __bf_shf(MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK);
++	switch (direction) {
++	case MV88E6XXX_EGRESS_DIR_INGRESS:
++		reg &= MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK;
++		reg |= port <<
++		       __bf_shf(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK);
++		break;
++	case MV88E6XXX_EGRESS_DIR_EGRESS:
++		reg &= MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK;
++		reg |= port <<
++		       __bf_shf(MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK);
++		break;
++	default:
++		return -EINVAL;
++	}
+ 
+ 	return mv88e6xxx_g1_write(chip, MV88E6185_G1_MONITOR_CTL, reg);
+ }
+@@ -341,17 +352,24 @@ static int mv88e6390_g1_monitor_write(st
+ 	return mv88e6xxx_g1_write(chip, MV88E6390_G1_MONITOR_MGMT_CTL, reg);
+ }
+ 
+-int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port)
++int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip,
++				 enum mv88e6xxx_egress_direction direction,
++				 int port)
+ {
+ 	u16 ptr;
+ 	int err;
+ 
+-	ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_INGRESS_DEST;
+-	err = mv88e6390_g1_monitor_write(chip, ptr, port);
+-	if (err)
+-		return err;
++	switch (direction) {
++	case MV88E6XXX_EGRESS_DIR_INGRESS:
++		ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_INGRESS_DEST;
++		break;
++	case MV88E6XXX_EGRESS_DIR_EGRESS:
++		ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_EGRESS_DEST;
++		break;
++	default:
++		return -EINVAL;
++	}
+ 
+-	ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_EGRESS_DEST;
+ 	err = mv88e6390_g1_monitor_write(chip, ptr, port);
+ 	if (err)
+ 		return err;
+--- a/drivers/net/dsa/mv88e6xxx/global1.h
++++ b/drivers/net/dsa/mv88e6xxx/global1.h
+@@ -289,8 +289,12 @@ int mv88e6095_g1_stats_set_histogram(str
+ int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip);
+ void mv88e6xxx_g1_stats_read(struct mv88e6xxx_chip *chip, int stat, u32 *val);
+ int mv88e6xxx_g1_stats_clear(struct mv88e6xxx_chip *chip);
+-int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port);
+-int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port);
++int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip,
++				 enum mv88e6xxx_egress_direction direction,
++				 int port);
++int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip,
++				 enum mv88e6xxx_egress_direction direction,
++				 int port);
+ int mv88e6095_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port);
+ int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port);
+ int mv88e6390_g1_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/747-v5.5-net-dsa-mv88e6xxx-Add-support-for-port-mirroring.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/747-v5.5-net-dsa-mv88e6xxx-Add-support-for-port-mirroring.patch
new file mode 100644
index 0000000..a23f450
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/747-v5.5-net-dsa-mv88e6xxx-Add-support-for-port-mirroring.patch
@@ -0,0 +1,266 @@
+From f0942e00a1abb6404ca4302c66497fc623676c11 Mon Sep 17 00:00:00 2001
+From: Iwan R Timmer <irtimmer@gmail.com>
+Date: Thu, 7 Nov 2019 22:11:14 +0100
+Subject: [PATCH] net: dsa: mv88e6xxx: Add support for port mirroring
+
+Add support for configuring port mirroring through the cls_matchall
+classifier. We do a full ingress and/or egress capture towards a
+capture port. It allows setting a different capture port for ingress
+and egress traffic.
+
+It keeps track of the mirrored ports and the destination ports to
+prevent changes to the capture port while other ports are being
+mirrored.
+
+Signed-off-by: Iwan R Timmer <irtimmer@gmail.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mv88e6xxx/chip.c    | 76 +++++++++++++++++++++++++++++
+ drivers/net/dsa/mv88e6xxx/chip.h    |  6 +++
+ drivers/net/dsa/mv88e6xxx/global1.c | 18 +++++--
+ drivers/net/dsa/mv88e6xxx/port.c    | 37 ++++++++++++++
+ drivers/net/dsa/mv88e6xxx/port.h    |  3 ++
+ 5 files changed, 136 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/dsa/mv88e6xxx/chip.c
++++ b/drivers/net/dsa/mv88e6xxx/chip.c
+@@ -4926,6 +4926,80 @@ static int mv88e6xxx_port_mdb_del(struct
+ 	return err;
+ }
+ 
++static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port,
++				     struct dsa_mall_mirror_tc_entry *mirror,
++				     bool ingress)
++{
++	enum mv88e6xxx_egress_direction direction = ingress ?
++						MV88E6XXX_EGRESS_DIR_INGRESS :
++						MV88E6XXX_EGRESS_DIR_EGRESS;
++	struct mv88e6xxx_chip *chip = ds->priv;
++	bool other_mirrors = false;
++	int i;
++	int err;
++
++	if (!chip->info->ops->set_egress_port)
++		return -EOPNOTSUPP;
++
++	mutex_lock(&chip->reg_lock);
++	if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) !=
++	    mirror->to_local_port) {
++		for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
++			other_mirrors |= ingress ?
++					 chip->ports[i].mirror_ingress :
++					 chip->ports[i].mirror_egress;
++
++		/* Can't change egress port when other mirror is active */
++		if (other_mirrors) {
++			err = -EBUSY;
++			goto out;
++		}
++
++		err = chip->info->ops->set_egress_port(chip,
++						       direction,
++						       mirror->to_local_port);
++		if (err)
++			goto out;
++	}
++
++	err = mv88e6xxx_port_set_mirror(chip, port, direction, true);
++out:
++	mutex_unlock(&chip->reg_lock);
++
++	return err;
++}
++
++static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port,
++				      struct dsa_mall_mirror_tc_entry *mirror)
++{
++	enum mv88e6xxx_egress_direction direction = mirror->ingress ?
++						MV88E6XXX_EGRESS_DIR_INGRESS :
++						MV88E6XXX_EGRESS_DIR_EGRESS;
++	struct mv88e6xxx_chip *chip = ds->priv;
++	bool other_mirrors = false;
++	int i;
++
++	mutex_lock(&chip->reg_lock);
++	if (mv88e6xxx_port_set_mirror(chip, port, direction, false))
++		dev_err(ds->dev, "p%d: failed to disable mirroring\n", port);
++
++	for (i = 0; i < mv88e6xxx_num_ports(chip); i++)
++		other_mirrors |= mirror->ingress ?
++				 chip->ports[i].mirror_ingress :
++				 chip->ports[i].mirror_egress;
++
++	/* Reset egress port when no other mirror is active */
++	if (!other_mirrors) {
++		if (chip->info->ops->set_egress_port(chip,
++						     direction,
++						     dsa_upstream_port(ds,
++								       port)));
++			dev_err(ds->dev, "failed to set egress port\n");
++	}
++
++	mutex_unlock(&chip->reg_lock);
++}
++
+ static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port,
+ 					 bool unicast, bool multicast)
+ {
+@@ -4980,6 +5054,8 @@ static const struct dsa_switch_ops mv88e
+ 	.port_mdb_prepare       = mv88e6xxx_port_mdb_prepare,
+ 	.port_mdb_add           = mv88e6xxx_port_mdb_add,
+ 	.port_mdb_del           = mv88e6xxx_port_mdb_del,
++	.port_mirror_add	= mv88e6xxx_port_mirror_add,
++	.port_mirror_del	= mv88e6xxx_port_mirror_del,
+ 	.crosschip_bridge_join	= mv88e6xxx_crosschip_bridge_join,
+ 	.crosschip_bridge_leave	= mv88e6xxx_crosschip_bridge_leave,
+ 	.port_hwtstamp_set	= mv88e6xxx_port_hwtstamp_set,
+--- a/drivers/net/dsa/mv88e6xxx/chip.h
++++ b/drivers/net/dsa/mv88e6xxx/chip.h
+@@ -232,6 +232,8 @@ struct mv88e6xxx_port {
+ 	u64 vtu_member_violation;
+ 	u64 vtu_miss_violation;
+ 	u8 cmode;
++	bool mirror_ingress;
++	bool mirror_egress;
+ 	unsigned int serdes_irq;
+ };
+ 
+@@ -315,6 +317,10 @@ struct mv88e6xxx_chip {
+ 	u16 evcap_config;
+ 	u16 enable_count;
+ 
++	/* Current ingress and egress monitor ports */
++	int egress_dest_port;
++	int ingress_dest_port;
++
+ 	/* Per-port timestamping resources. */
+ 	struct mv88e6xxx_port_hwtstamp port_hwtstamp[DSA_MAX_PORTS];
+ 
+--- a/drivers/net/dsa/mv88e6xxx/global1.c
++++ b/drivers/net/dsa/mv88e6xxx/global1.c
+@@ -298,6 +298,7 @@ int mv88e6095_g1_set_egress_port(struct
+ 				 enum mv88e6xxx_egress_direction direction,
+ 				 int port)
+ {
++	int *dest_port_chip;
+ 	u16 reg;
+ 	int err;
+ 
+@@ -307,11 +308,13 @@ int mv88e6095_g1_set_egress_port(struct
+ 
+ 	switch (direction) {
+ 	case MV88E6XXX_EGRESS_DIR_INGRESS:
++		dest_port_chip = &chip->ingress_dest_port;
+ 		reg &= MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK;
+ 		reg |= port <<
+ 		       __bf_shf(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK);
+ 		break;
+ 	case MV88E6XXX_EGRESS_DIR_EGRESS:
++		dest_port_chip = &chip->egress_dest_port;
+ 		reg &= MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK;
+ 		reg |= port <<
+ 		       __bf_shf(MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK);
+@@ -320,7 +323,11 @@ int mv88e6095_g1_set_egress_port(struct
+ 		return -EINVAL;
+ 	}
+ 
+-	return mv88e6xxx_g1_write(chip, MV88E6185_G1_MONITOR_CTL, reg);
++	err = mv88e6xxx_g1_write(chip, MV88E6185_G1_MONITOR_CTL, reg);
++	if (!err)
++		*dest_port_chip = port;
++
++	return err;
+ }
+ 
+ /* Older generations also call this the ARP destination. It has been
+@@ -356,14 +363,17 @@ int mv88e6390_g1_set_egress_port(struct
+ 				 enum mv88e6xxx_egress_direction direction,
+ 				 int port)
+ {
++	int *dest_port_chip;
+ 	u16 ptr;
+ 	int err;
+ 
+ 	switch (direction) {
+ 	case MV88E6XXX_EGRESS_DIR_INGRESS:
++		dest_port_chip = &chip->ingress_dest_port;
+ 		ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_INGRESS_DEST;
+ 		break;
+ 	case MV88E6XXX_EGRESS_DIR_EGRESS:
++		dest_port_chip = &chip->egress_dest_port;
+ 		ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_EGRESS_DEST;
+ 		break;
+ 	default:
+@@ -371,10 +381,10 @@ int mv88e6390_g1_set_egress_port(struct
+ 	}
+ 
+ 	err = mv88e6390_g1_monitor_write(chip, ptr, port);
+-	if (err)
+-		return err;
++	if (!err)
++		*dest_port_chip = port;
+ 
+-	return 0;
++	return err;
+ }
+ 
+ int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port)
+--- a/drivers/net/dsa/mv88e6xxx/port.c
++++ b/drivers/net/dsa/mv88e6xxx/port.c
+@@ -1181,6 +1181,43 @@ int mv88e6095_port_set_upstream_port(str
+ 	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
+ }
+ 
++int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,
++			      enum mv88e6xxx_egress_direction direction,
++			      bool mirror)
++{
++	bool *mirror_port;
++	u16 reg;
++	u16 bit;
++	int err;
++
++	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);
++	if (err)
++		return err;
++
++	switch (direction) {
++	case MV88E6XXX_EGRESS_DIR_INGRESS:
++		bit = MV88E6XXX_PORT_CTL2_INGRESS_MONITOR;
++		mirror_port = &chip->ports[port].mirror_ingress;
++		break;
++	case MV88E6XXX_EGRESS_DIR_EGRESS:
++		bit = MV88E6XXX_PORT_CTL2_EGRESS_MONITOR;
++		mirror_port = &chip->ports[port].mirror_egress;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	reg &= ~bit;
++	if (mirror)
++		reg |= bit;
++
++	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);
++	if (!err)
++		*mirror_port = mirror;
++
++	return err;
++}
++
+ int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port,
+ 				  u16 mode)
+ {
+--- a/drivers/net/dsa/mv88e6xxx/port.h
++++ b/drivers/net/dsa/mv88e6xxx/port.h
+@@ -368,6 +368,9 @@ int mv88e6352_port_link_state(struct mv8
+ int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port);
+ int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,
+ 				     int upstream_port);
++int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,
++			      enum mv88e6xxx_egress_direction direction,
++			      bool mirror);
+ 
+ int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port);
+ int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/748-v5.5-net-dsa-mv88e6xxx-fix-broken-if-statement-because-of.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/748-v5.5-net-dsa-mv88e6xxx-fix-broken-if-statement-because-of.patch
new file mode 100644
index 0000000..37e7a7f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/748-v5.5-net-dsa-mv88e6xxx-fix-broken-if-statement-because-of.patch
@@ -0,0 +1,30 @@
+From 4e4637b10374ede3cd33d7e1b389e6cea6343ea3 Mon Sep 17 00:00:00 2001
+From: Colin Ian King <colin.king@canonical.com>
+Date: Tue, 12 Nov 2019 13:05:23 +0000
+Subject: [PATCH] net: dsa: mv88e6xxx: fix broken if statement because of a
+ stray semicolon
+
+There is a stray semicolon in an if statement that will cause a dev_err
+message to be printed unconditionally. Fix this by removing the stray
+semicolon.
+
+Addresses-Coverity: ("Stay semicolon")
+Fixes: f0942e00a1ab ("net: dsa: mv88e6xxx: Add support for port mirroring")
+Signed-off-by: Colin Ian King <colin.king@canonical.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mv88e6xxx/chip.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/dsa/mv88e6xxx/chip.c
++++ b/drivers/net/dsa/mv88e6xxx/chip.c
+@@ -4993,7 +4993,7 @@ static void mv88e6xxx_port_mirror_del(st
+ 		if (chip->info->ops->set_egress_port(chip,
+ 						     direction,
+ 						     dsa_upstream_port(ds,
+-								       port)));
++								       port)))
+ 			dev_err(ds->dev, "failed to set egress port\n");
+ 	}
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/749-v5.5-net-dsa-mv88e6xxx-Fix-masking-of-egress-port.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/749-v5.5-net-dsa-mv88e6xxx-Fix-masking-of-egress-port.patch
new file mode 100644
index 0000000..497a808
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/749-v5.5-net-dsa-mv88e6xxx-Fix-masking-of-egress-port.patch
@@ -0,0 +1,34 @@
+From 3ee339eb28959629db33aaa2b8cde4c63c6289eb Mon Sep 17 00:00:00 2001
+From: Andrew Lunn <andrew@lunn.ch>
+Date: Thu, 27 Feb 2020 21:20:49 +0100
+Subject: [PATCH] net: dsa: mv88e6xxx: Fix masking of egress port
+
+Add missing ~ to the usage of the mask.
+
+Reported-by: Kevin Benson <Kevin.Benson@zii.aero>
+Reported-by: Chris Healy <Chris.Healy@zii.aero>
+Fixes: 5c74c54ce6ff ("net: dsa: mv88e6xxx: Split monitor port configuration")
+Signed-off-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mv88e6xxx/global1.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/dsa/mv88e6xxx/global1.c
++++ b/drivers/net/dsa/mv88e6xxx/global1.c
+@@ -309,13 +309,13 @@ int mv88e6095_g1_set_egress_port(struct
+ 	switch (direction) {
+ 	case MV88E6XXX_EGRESS_DIR_INGRESS:
+ 		dest_port_chip = &chip->ingress_dest_port;
+-		reg &= MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK;
++		reg &= ~MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK;
+ 		reg |= port <<
+ 		       __bf_shf(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK);
+ 		break;
+ 	case MV88E6XXX_EGRESS_DIR_EGRESS:
+ 		dest_port_chip = &chip->egress_dest_port;
+-		reg &= MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK;
++		reg &= ~MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK;
+ 		reg |= port <<
+ 		       __bf_shf(MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK);
+ 		break;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/750-v5.5-net-phy-add-support-for-clause-37-auto-negotiation.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/750-v5.5-net-phy-add-support-for-clause-37-auto-negotiation.patch
new file mode 100644
index 0000000..69c56ec
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/750-v5.5-net-phy-add-support-for-clause-37-auto-negotiation.patch
@@ -0,0 +1,195 @@
+From fa6e98cee558622565c97924e922b97340aeabd8 Mon Sep 17 00:00:00 2001
+From: Heiner Kallweit <hkallweit1@gmail.com>
+Date: Tue, 22 Oct 2019 11:31:07 -0700
+Subject: [PATCH] net: phy: add support for clause 37 auto-negotiation
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch adds support for clause 37 1000Base-X auto-negotiation.
+
+Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
+Signed-off-by: Tao Ren <taoren@fb.com>
+Tested-by: René van Dorst <opensource@vdorst.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/phy_device.c | 139 +++++++++++++++++++++++++++++++++++
+ include/linux/phy.h          |   4 +
+ 2 files changed, 143 insertions(+)
+
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -1682,6 +1682,40 @@ static int genphy_config_advert(struct p
+ }
+ 
+ /**
++ * genphy_c37_config_advert - sanitize and advertise auto-negotiation parameters
++ * @phydev: target phy_device struct
++ *
++ * Description: Writes MII_ADVERTISE with the appropriate values,
++ *   after sanitizing the values to make sure we only advertise
++ *   what is supported.  Returns < 0 on error, 0 if the PHY's advertisement
++ *   hasn't changed, and > 0 if it has changed. This function is intended
++ *   for Clause 37 1000Base-X mode.
++ */
++static int genphy_c37_config_advert(struct phy_device *phydev)
++{
++	u16 adv = 0;
++
++	/* Only allow advertising what this PHY supports */
++	linkmode_and(phydev->advertising, phydev->advertising,
++		     phydev->supported);
++
++	if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
++			      phydev->advertising))
++		adv |= ADVERTISE_1000XFULL;
++	if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
++			      phydev->advertising))
++		adv |= ADVERTISE_1000XPAUSE;
++	if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
++			      phydev->advertising))
++		adv |= ADVERTISE_1000XPSE_ASYM;
++
++	return phy_modify_changed(phydev, MII_ADVERTISE,
++				  ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE |
++				  ADVERTISE_1000XHALF | ADVERTISE_1000XPSE_ASYM,
++				  adv);
++}
++
++/**
+  * genphy_config_eee_advert - disable unwanted eee mode advertisement
+  * @phydev: target phy_device struct
+  *
+@@ -1790,6 +1824,54 @@ int __genphy_config_aneg(struct phy_devi
+ EXPORT_SYMBOL(__genphy_config_aneg);
+ 
+ /**
++ * genphy_c37_config_aneg - restart auto-negotiation or write BMCR
++ * @phydev: target phy_device struct
++ *
++ * Description: If auto-negotiation is enabled, we configure the
++ *   advertising, and then restart auto-negotiation.  If it is not
++ *   enabled, then we write the BMCR. This function is intended
++ *   for use with Clause 37 1000Base-X mode.
++ */
++int genphy_c37_config_aneg(struct phy_device *phydev)
++{
++	int err, changed;
++
++	if (phydev->autoneg != AUTONEG_ENABLE)
++		return genphy_setup_forced(phydev);
++
++	err = phy_modify(phydev, MII_BMCR, BMCR_SPEED1000 | BMCR_SPEED100,
++			 BMCR_SPEED1000);
++	if (err)
++		return err;
++
++	changed = genphy_c37_config_advert(phydev);
++	if (changed < 0) /* error */
++		return changed;
++
++	if (!changed) {
++		/* Advertisement hasn't changed, but maybe aneg was never on to
++		 * begin with?  Or maybe phy was isolated?
++		 */
++		int ctl = phy_read(phydev, MII_BMCR);
++
++		if (ctl < 0)
++			return ctl;
++
++		if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE))
++			changed = 1; /* do restart aneg */
++	}
++
++	/* Only restart aneg if we are advertising something different
++	 * than we were before.
++	 */
++	if (changed > 0)
++		return genphy_restart_aneg(phydev);
++
++	return 0;
++}
++EXPORT_SYMBOL(genphy_c37_config_aneg);
++
++/**
+  * genphy_aneg_done - return auto-negotiation status
+  * @phydev: target phy_device struct
+  *
+@@ -1962,6 +2044,63 @@ int genphy_read_status(struct phy_device
+ EXPORT_SYMBOL(genphy_read_status);
+ 
+ /**
++ * genphy_c37_read_status - check the link status and update current link state
++ * @phydev: target phy_device struct
++ *
++ * Description: Check the link, then figure out the current state
++ *   by comparing what we advertise with what the link partner
++ *   advertises. This function is for Clause 37 1000Base-X mode.
++ */
++int genphy_c37_read_status(struct phy_device *phydev)
++{
++	int lpa, err, old_link = phydev->link;
++
++	/* Update the link, but return if there was an error */
++	err = genphy_update_link(phydev);
++	if (err)
++		return err;
++
++	/* why bother the PHY if nothing can have changed */
++	if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
++		return 0;
++
++	phydev->duplex = DUPLEX_UNKNOWN;
++	phydev->pause = 0;
++	phydev->asym_pause = 0;
++
++	if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) {
++		lpa = phy_read(phydev, MII_LPA);
++		if (lpa < 0)
++			return lpa;
++
++		linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
++				 phydev->lp_advertising, lpa & LPA_LPACK);
++		linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
++				 phydev->lp_advertising, lpa & LPA_1000XFULL);
++		linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT,
++				 phydev->lp_advertising, lpa & LPA_1000XPAUSE);
++		linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
++				 phydev->lp_advertising,
++				 lpa & LPA_1000XPAUSE_ASYM);
++
++		phy_resolve_aneg_linkmode(phydev);
++	} else if (phydev->autoneg == AUTONEG_DISABLE) {
++		int bmcr = phy_read(phydev, MII_BMCR);
++
++		if (bmcr < 0)
++			return bmcr;
++
++		if (bmcr & BMCR_FULLDPLX)
++			phydev->duplex = DUPLEX_FULL;
++		else
++			phydev->duplex = DUPLEX_HALF;
++	}
++
++	return 0;
++}
++EXPORT_SYMBOL(genphy_c37_read_status);
++
++/**
+  * genphy_soft_reset - software reset the PHY via BMCR_RESET bit
+  * @phydev: target phy_device struct
+  *
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -1120,6 +1120,10 @@ int genphy_read_mmd_unsupported(struct p
+ int genphy_write_mmd_unsupported(struct phy_device *phdev, int devnum,
+ 				 u16 regnum, u16 val);
+ 
++/* Clause 37 */
++int genphy_c37_config_aneg(struct phy_device *phydev);
++int genphy_c37_read_status(struct phy_device *phydev);
++
+ /* Clause 45 PHY */
+ int genphy_c45_restart_aneg(struct phy_device *phydev);
+ int genphy_c45_check_and_restart_aneg(struct phy_device *phydev, bool restart);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/751-v5.6-net-mvmdio-avoid-error-message-for-optional-IRQ.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/751-v5.6-net-mvmdio-avoid-error-message-for-optional-IRQ.patch
new file mode 100644
index 0000000..6d51de8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/751-v5.6-net-mvmdio-avoid-error-message-for-optional-IRQ.patch
@@ -0,0 +1,33 @@
+From fa2632f74e57bbc869c8ad37751a11b6147a3acc Mon Sep 17 00:00:00 2001
+From: Chris Packham <chris.packham@alliedtelesis.co.nz>
+Date: Mon, 16 Mar 2020 20:49:07 +1300
+Subject: [PATCH] net: mvmdio: avoid error message for optional IRQ
+
+Per the dt-binding the interrupt is optional so use
+platform_get_irq_optional() instead of platform_get_irq(). Since
+commit 7723f4c5ecdb ("driver core: platform: Add an error message to
+platform_get_irq*()") platform_get_irq() produces an error message
+
+  orion-mdio f1072004.mdio: IRQ index 0 not found
+
+which is perfectly normal if one hasn't specified the optional property
+in the device tree.
+
+Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/marvell/mvmdio.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/marvell/mvmdio.c
++++ b/drivers/net/ethernet/marvell/mvmdio.c
+@@ -347,7 +347,7 @@ static int orion_mdio_probe(struct platf
+ 	}
+ 
+ 
+-	dev->err_interrupt = platform_get_irq(pdev, 0);
++	dev->err_interrupt = platform_get_irq_optional(pdev, 0);
+ 	if (dev->err_interrupt > 0 &&
+ 	    resource_size(r) < MVMDIO_ERR_INT_MASK + 4) {
+ 		dev_err(&pdev->dev,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/752-v5.8-net-dsa-provide-an-option-for-drivers-to-always-rece.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/752-v5.8-net-dsa-provide-an-option-for-drivers-to-always-rece.patch
new file mode 100644
index 0000000..52d9351
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/752-v5.8-net-dsa-provide-an-option-for-drivers-to-always-rece.patch
@@ -0,0 +1,121 @@
+From 54a0ed0df49609f4e3f098f8943e38e389dc2e15 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 12 May 2020 20:20:25 +0300
+Subject: net: dsa: provide an option for drivers to always receive bridge
+ VLANs
+
+DSA assumes that a bridge which has vlan filtering disabled is not
+vlan aware, and ignores all vlan configuration. However, the kernel
+software bridge code allows configuration in this state.
+
+This causes the kernel's idea of the bridge vlan state and the
+hardware state to disagree, so "bridge vlan show" indicates a correct
+configuration but the hardware lacks all configuration. Even worse,
+enabling vlan filtering on a DSA bridge immediately blocks all traffic
+which, given the output of "bridge vlan show", is very confusing.
+
+Provide an option that drivers can set to indicate they want to receive
+vlan configuration even when vlan filtering is disabled. At the very
+least, this is safe for Marvell DSA bridges, which do not look up
+ingress traffic in the VTU if the port is in 8021Q disabled state. It is
+also safe for the Ocelot switch family. Whether this change is suitable
+for all DSA bridges is not known.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ include/net/dsa.h  |  7 +++++++
+ net/dsa/dsa_priv.h |  1 +
+ net/dsa/port.c     | 14 ++++++++++++++
+ net/dsa/slave.c    |  8 ++++----
+ 4 files changed, 26 insertions(+), 4 deletions(-)
+
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -270,6 +270,13 @@ struct dsa_switch {
+ 	 */
+ 	bool			vlan_filtering_is_global;
+ 
++	/* Pass .port_vlan_add and .port_vlan_del to drivers even for bridges
++	 * that have vlan_filtering=0. All drivers should ideally set this (and
++	 * then the option would get removed), but it is unknown whether this
++	 * would break things or not.
++	 */
++	bool			configure_vlan_while_not_filtering;
++
+ 	/* In case vlan_filtering_is_global is set, the VLAN awareness state
+ 	 * should be retrieved from here and not from the per-port settings.
+ 	 */
+--- a/net/dsa/dsa_priv.h
++++ b/net/dsa/dsa_priv.h
+@@ -139,6 +139,7 @@ int dsa_port_bridge_join(struct dsa_port
+ void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br);
+ int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
+ 			    struct switchdev_trans *trans);
++bool dsa_port_skip_vlan_configuration(struct dsa_port *dp);
+ int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock,
+ 			 struct switchdev_trans *trans);
+ int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr,
+--- a/net/dsa/port.c
++++ b/net/dsa/port.c
+@@ -238,6 +238,20 @@ int dsa_port_vlan_filtering(struct dsa_p
+ 	return 0;
+ }
+ 
++/* This enforces legacy behavior for switch drivers which assume they can't
++ * receive VLAN configuration when enslaved to a bridge with vlan_filtering=0
++ */
++bool dsa_port_skip_vlan_configuration(struct dsa_port *dp)
++{
++	struct dsa_switch *ds = dp->ds;
++
++	if (!dp->bridge_dev)
++		return false;
++
++	return (!ds->configure_vlan_while_not_filtering &&
++		!br_vlan_enabled(dp->bridge_dev));
++}
++
+ int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock,
+ 			 struct switchdev_trans *trans)
+ {
+--- a/net/dsa/slave.c
++++ b/net/dsa/slave.c
+@@ -319,7 +319,7 @@ static int dsa_slave_vlan_add(struct net
+ 	if (obj->orig_dev != dev)
+ 		return -EOPNOTSUPP;
+ 
+-	if (dp->bridge_dev && !br_vlan_enabled(dp->bridge_dev))
++	if (dsa_port_skip_vlan_configuration(dp))
+ 		return 0;
+ 
+ 	vlan = *SWITCHDEV_OBJ_PORT_VLAN(obj);
+@@ -386,7 +386,7 @@ static int dsa_slave_vlan_del(struct net
+ 	if (obj->orig_dev != dev)
+ 		return -EOPNOTSUPP;
+ 
+-	if (dp->bridge_dev && !br_vlan_enabled(dp->bridge_dev))
++	if (dsa_port_skip_vlan_configuration(dp))
+ 		return 0;
+ 
+ 	/* Do not deprogram the CPU port as it may be shared with other user
+@@ -1120,7 +1120,7 @@ static int dsa_slave_vlan_rx_add_vid(str
+ 	 * need to emulate the switchdev prepare + commit phase.
+ 	 */
+ 	if (dp->bridge_dev) {
+-		if (!br_vlan_enabled(dp->bridge_dev))
++		if (dsa_port_skip_vlan_configuration(dp))
+ 			return 0;
+ 
+ 		/* br_vlan_get_info() returns -EINVAL or -ENOENT if the
+@@ -1154,7 +1154,7 @@ static int dsa_slave_vlan_rx_kill_vid(st
+ 	 * need to emulate the switchdev prepare + commit phase.
+ 	 */
+ 	if (dp->bridge_dev) {
+-		if (!br_vlan_enabled(dp->bridge_dev))
++		if (dsa_port_skip_vlan_configuration(dp))
+ 			return 0;
+ 
+ 		/* br_vlan_get_info() returns -EINVAL or -ENOENT if the
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/753-v5.8-net-dsa-mt7530-fix-VLAN-setup.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/753-v5.8-net-dsa-mt7530-fix-VLAN-setup.patch
new file mode 100644
index 0000000..0804cea
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/753-v5.8-net-dsa-mt7530-fix-VLAN-setup.patch
@@ -0,0 +1,51 @@
+From 0141792f8b7300006b874dda1c35acd0abd90d9d Mon Sep 17 00:00:00 2001
+From: DENG Qingfang <dqfext@gmail.com>
+Date: Fri, 15 May 2020 23:25:55 +0800
+Subject: net: dsa: mt7530: fix VLAN setup
+
+Allow DSA to add VLAN entries even if VLAN filtering is disabled, so
+enabling it will not block the traffic of existent ports in the bridge
+
+Signed-off-by: DENG Qingfang <dqfext@gmail.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mt7530.c | 13 +------------
+ 1 file changed, 1 insertion(+), 12 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -1083,12 +1083,6 @@ mt7530_port_vlan_add(struct dsa_switch *
+ 	struct mt7530_priv *priv = ds->priv;
+ 	u16 vid;
+ 
+-	/* The port is kept as VLAN-unaware if bridge with vlan_filtering not
+-	 * being set.
+-	 */
+-	if (!dsa_port_is_vlan_filtering(&ds->ports[port]))
+-		return;
+-
+ 	mutex_lock(&priv->reg_mutex);
+ 
+ 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
+@@ -1114,12 +1108,6 @@ mt7530_port_vlan_del(struct dsa_switch *
+ 	struct mt7530_priv *priv = ds->priv;
+ 	u16 vid, pvid;
+ 
+-	/* The port is kept as VLAN-unaware if bridge with vlan_filtering not
+-	 * being set.
+-	 */
+-	if (!dsa_port_is_vlan_filtering(&ds->ports[port]))
+-		return 0;
+-
+ 	mutex_lock(&priv->reg_mutex);
+ 
+ 	pvid = priv->ports[port].pvid;
+@@ -1232,6 +1220,7 @@ mt7530_setup(struct dsa_switch *ds)
+ 	 * as two netdev instances.
+ 	 */
+ 	dn = ds->ports[MT7530_CPU_PORT].master->dev.of_node->parent;
++	ds->configure_vlan_while_not_filtering = true;
+ 
+ 	if (priv->id == ID_MT7530) {
+ 		regulator_set_voltage(priv->core_pwr, 1000000, 1000000);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/756-v5.8-net-dsa-rtl8366-Pass-GENMASK-signed-bits.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/756-v5.8-net-dsa-rtl8366-Pass-GENMASK-signed-bits.patch
new file mode 100644
index 0000000..b0ab598
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/756-v5.8-net-dsa-rtl8366-Pass-GENMASK-signed-bits.patch
@@ -0,0 +1,27 @@
+From 733993f502f254912b1415e13f73651d9f2e74ef Mon Sep 17 00:00:00 2001
+From: Andrew Lunn <andrew@lunn.ch>
+Date: Sun, 5 Jul 2020 22:42:27 +0200
+Subject: [PATCH 1/5] net: dsa: rtl8366: Pass GENMASK() signed bits
+
+Oddly, GENMASK() requires signed bit numbers, so that it can compare
+them for < 0. If passed an unsigned type, we get warnings about the
+test never being true.
+
+Signed-off-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/rtl8366.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/dsa/rtl8366.c
++++ b/drivers/net/dsa/rtl8366.c
+@@ -311,7 +311,7 @@ int rtl8366_init_vlan(struct realtek_smi
+ 			/* For the CPU port, make all ports members of this
+ 			 * VLAN.
+ 			 */
+-			mask = GENMASK(smi->num_ports - 1, 0);
++			mask = GENMASK((int)smi->num_ports - 1, 0);
+ 		else
+ 			/* For all other ports, enable itself plus the
+ 			 * CPU port.
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/757-v5.8-net-dsa-tag_rtl4_a-Implement-Realtek-4-byte-A-tag.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/757-v5.8-net-dsa-tag_rtl4_a-Implement-Realtek-4-byte-A-tag.patch
new file mode 100644
index 0000000..70d7000
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/757-v5.8-net-dsa-tag_rtl4_a-Implement-Realtek-4-byte-A-tag.patch
@@ -0,0 +1,232 @@
+From 078ced30af696b52a450a016a16eb47499d68117 Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Wed, 8 Jul 2020 14:25:36 +0200
+Subject: [PATCH 2/5] net: dsa: tag_rtl4_a: Implement Realtek 4 byte A tag
+
+This implements the known parts of the Realtek 4 byte
+tag protocol version 0xA, as found in the RTL8366RB
+DSA switch.
+
+It is designated as protocol version 0xA as a
+different Realtek 4 byte tag format with protocol
+version 0x9 is known to exist in the Realtek RTL8306
+chips.
+
+The tag and switch chip lacks public documentation, so
+the tag format has been reverse-engineered from
+packet dumps. As only ingress traffic has been available
+for analysis an egress tag has not been possible to
+develop (even using educated guesses about bit fields)
+so this is as far as it gets. It is not known if the
+switch even supports egress tagging.
+
+Excessive attempts to figure out the egress tag format
+was made. When nothing else worked, I just tried all bit
+combinations with 0xannp where a is protocol and p is
+port. I looped through all values several times trying
+to get a response from ping, without any positive
+result.
+
+Using just these ingress tags however, the switch
+functionality is vastly improved and the packets find
+their way into the destination port without any
+tricky VLAN configuration. On the D-Link DIR-685 the
+LAN ports now come up and respond to ping without
+any command line configuration so this is a real
+improvement for users.
+
+Egress packets need to be restricted to the proper
+target ports using VLAN, which the RTL8366RB DSA
+switch driver already sets up.
+
+Cc: DENG Qingfang <dqfext@gmail.com>
+Cc: Mauri Sandberg <sandberg@mailfence.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ include/net/dsa.h    |   2 +
+ net/dsa/Kconfig      |   7 +++
+ net/dsa/Makefile     |   1 +
+ net/dsa/tag_rtl4_a.c | 130 +++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 140 insertions(+)
+ create mode 100644 net/dsa/tag_rtl4_a.c
+
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -42,6 +42,7 @@ struct phylink_link_state;
+ #define DSA_TAG_PROTO_8021Q_VALUE		12
+ #define DSA_TAG_PROTO_SJA1105_VALUE		13
+ #define DSA_TAG_PROTO_KSZ8795_VALUE		14
++#define DSA_TAG_PROTO_RTL4_A_VALUE		17
+ 
+ enum dsa_tag_protocol {
+ 	DSA_TAG_PROTO_NONE		= DSA_TAG_PROTO_NONE_VALUE,
+@@ -59,6 +60,7 @@ enum dsa_tag_protocol {
+ 	DSA_TAG_PROTO_8021Q		= DSA_TAG_PROTO_8021Q_VALUE,
+ 	DSA_TAG_PROTO_SJA1105		= DSA_TAG_PROTO_SJA1105_VALUE,
+ 	DSA_TAG_PROTO_KSZ8795		= DSA_TAG_PROTO_KSZ8795_VALUE,
++	DSA_TAG_PROTO_RTL4_A		= DSA_TAG_PROTO_RTL4_A_VALUE,
+ };
+ 
+ struct packet_type;
+--- a/net/dsa/Kconfig
++++ b/net/dsa/Kconfig
+@@ -80,6 +80,13 @@ config NET_DSA_TAG_KSZ
+ 	  Say Y if you want to enable support for tagging frames for the
+ 	  Microchip 8795/9477/9893 families of switches.
+ 
++config NET_DSA_TAG_RTL4_A
++	tristate "Tag driver for Realtek 4 byte protocol A tags"
++	help
++	  Say Y or M if you want to enable support for tagging frames for the
++	  Realtek switches with 4 byte protocol A tags, sich as found in
++	  the Realtek RTL8366RB.
++
+ config NET_DSA_TAG_QCA
+ 	tristate "Tag driver for Qualcomm Atheros QCA8K switches"
+ 	help
+--- a/net/dsa/Makefile
++++ b/net/dsa/Makefile
+@@ -10,6 +10,7 @@ obj-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa
+ obj-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
+ obj-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_gswip.o
+ obj-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o
++obj-$(CONFIG_NET_DSA_TAG_RTL4_A) += tag_rtl4_a.o
+ obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o
+ obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o
+ obj-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o
+--- /dev/null
++++ b/net/dsa/tag_rtl4_a.c
+@@ -0,0 +1,130 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Handler for Realtek 4 byte DSA switch tags
++ * Currently only supports protocol "A" found in RTL8366RB
++ * Copyright (c) 2020 Linus Walleij <linus.walleij@linaro.org>
++ *
++ * This "proprietary tag" header looks like so:
++ *
++ * -------------------------------------------------
++ * | MAC DA | MAC SA | 0x8899 | 2 bytes tag | Type |
++ * -------------------------------------------------
++ *
++ * The 2 bytes tag form a 16 bit big endian word. The exact
++ * meaning has been guessed from packet dumps from ingress
++ * frames, as no working egress traffic has been available
++ * we do not know the format of the egress tags or if they
++ * are even supported.
++ */
++
++#include <linux/etherdevice.h>
++#include <linux/bits.h>
++
++#include "dsa_priv.h"
++
++#define RTL4_A_HDR_LEN		4
++#define RTL4_A_ETHERTYPE	0x8899
++#define RTL4_A_PROTOCOL_SHIFT	12
++/*
++ * 0x1 = Realtek Remote Control protocol (RRCP)
++ * 0x2/0x3 seems to be used for loopback testing
++ * 0x9 = RTL8306 DSA protocol
++ * 0xa = RTL8366RB DSA protocol
++ */
++#define RTL4_A_PROTOCOL_RTL8366RB	0xa
++
++static struct sk_buff *rtl4a_tag_xmit(struct sk_buff *skb,
++				      struct net_device *dev)
++{
++	/*
++	 * Just let it pass thru, we don't know if it is possible
++	 * to tag a frame with the 0x8899 ethertype and direct it
++	 * to a specific port, all attempts at reverse-engineering have
++	 * ended up with the frames getting dropped.
++	 *
++	 * The VLAN set-up needs to restrict the frames to the right port.
++	 *
++	 * If you have documentation on the tagging format for RTL8366RB
++	 * (tag type A) then please contribute.
++	 */
++	return skb;
++}
++
++static struct sk_buff *rtl4a_tag_rcv(struct sk_buff *skb,
++				     struct net_device *dev,
++				     struct packet_type *pt)
++{
++	u16 protport;
++	__be16 *p;
++	u16 etype;
++	u8 *tag;
++	u8 prot;
++	u8 port;
++
++	if (unlikely(!pskb_may_pull(skb, RTL4_A_HDR_LEN)))
++		return NULL;
++
++	/* The RTL4 header has its own custom Ethertype 0x8899 and that
++	 * starts right at the beginning of the packet, after the src
++	 * ethernet addr. Apparantly skb->data always points 2 bytes in,
++	 * behind the Ethertype.
++	 */
++	tag = skb->data - 2;
++	p = (__be16 *)tag;
++	etype = ntohs(*p);
++	if (etype != RTL4_A_ETHERTYPE) {
++		/* Not custom, just pass through */
++		netdev_dbg(dev, "non-realtek ethertype 0x%04x\n", etype);
++		return skb;
++	}
++	p = (__be16 *)(tag + 2);
++	protport = ntohs(*p);
++	/* The 4 upper bits are the protocol */
++	prot = (protport >> RTL4_A_PROTOCOL_SHIFT) & 0x0f;
++	if (prot != RTL4_A_PROTOCOL_RTL8366RB) {
++		netdev_err(dev, "unknown realtek protocol 0x%01x\n", prot);
++		return NULL;
++	}
++	port = protport & 0xff;
++
++	skb->dev = dsa_master_find_slave(dev, 0, port);
++	if (!skb->dev) {
++		netdev_dbg(dev, "could not find slave for port %d\n", port);
++		return NULL;
++	}
++
++	/* Remove RTL4 tag and recalculate checksum */
++	skb_pull_rcsum(skb, RTL4_A_HDR_LEN);
++
++	/* Move ethernet DA and SA in front of the data */
++	memmove(skb->data - ETH_HLEN,
++		skb->data - ETH_HLEN - RTL4_A_HDR_LEN,
++		2 * ETH_ALEN);
++
++	skb->offload_fwd_mark = 1;
++
++	return skb;
++}
++
++static int rtl4a_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
++				  int *offset)
++{
++	*offset = RTL4_A_HDR_LEN;
++	/* Skip past the tag and fetch the encapsulated Ethertype */
++	*proto = ((__be16 *)skb->data)[1];
++
++	return 0;
++}
++
++static const struct dsa_device_ops rtl4a_netdev_ops = {
++	.name	= "rtl4a",
++	.proto	= DSA_TAG_PROTO_RTL4_A,
++	.xmit	= rtl4a_tag_xmit,
++	.rcv	= rtl4a_tag_rcv,
++	.flow_dissect = rtl4a_tag_flow_dissect,
++	.overhead = RTL4_A_HDR_LEN,
++};
++module_dsa_tag_driver(rtl4a_netdev_ops);
++
++MODULE_LICENSE("GPL");
++MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_RTL4_A);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/758-v5.8-net-dsa-rtl8366rb-Support-the-CPU-DSA-tag.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/758-v5.8-net-dsa-rtl8366rb-Support-the-CPU-DSA-tag.patch
new file mode 100644
index 0000000..b68c033
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/758-v5.8-net-dsa-rtl8366rb-Support-the-CPU-DSA-tag.patch
@@ -0,0 +1,100 @@
+From c633ba43b7a9c2bfdb992ffd198d4c661520466f Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Wed, 8 Jul 2020 14:25:37 +0200
+Subject: [PATCH 3/5] net: dsa: rtl8366rb: Support the CPU DSA tag
+
+This activates the support to use the CPU tag to properly
+direct ingress traffic to the right port.
+
+Bit 15 in register RTL8368RB_CPU_CTRL_REG can be set to
+1 to disable the insertion of the CPU tag which is what
+the code currently does. The bit 15 define calls this
+setting RTL8368RB_CPU_INSTAG which is confusing since the
+inverse meaning is implied: programmers may think that
+setting this bit to 1 will *enable* inserting the tag
+rather than disabling it, so rename this setting in
+bit 15 to RTL8368RB_CPU_NO_TAG which is more to the
+point.
+
+After this e.g. ping works out-of-the-box with the
+RTL8366RB.
+
+Cc: DENG Qingfang <dqfext@gmail.com>
+Cc: Mauri Sandberg <sandberg@mailfence.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/Kconfig     |  1 +
+ drivers/net/dsa/rtl8366rb.c | 31 ++++++++-----------------------
+ 2 files changed, 9 insertions(+), 23 deletions(-)
+
+--- a/drivers/net/dsa/Kconfig
++++ b/drivers/net/dsa/Kconfig
+@@ -66,6 +66,7 @@ config NET_DSA_QCA8K
+ config NET_DSA_REALTEK_SMI
+ 	tristate "Realtek SMI Ethernet switch family support"
+ 	depends on NET_DSA
++	select NET_DSA_TAG_RTL4_A
+ 	select FIXED_PHY
+ 	select IRQ_DOMAIN
+ 	select REALTEK_PHY
+--- a/drivers/net/dsa/rtl8366rb.c
++++ b/drivers/net/dsa/rtl8366rb.c
+@@ -109,8 +109,8 @@
+ /* CPU port control reg */
+ #define RTL8368RB_CPU_CTRL_REG		0x0061
+ #define RTL8368RB_CPU_PORTS_MSK		0x00FF
+-/* Enables inserting custom tag length/type 0x8899 */
+-#define RTL8368RB_CPU_INSTAG		BIT(15)
++/* Disables inserting custom tag length/type 0x8899 */
++#define RTL8368RB_CPU_NO_TAG		BIT(15)
+ 
+ #define RTL8366RB_SMAR0			0x0070 /* bits 0..15 */
+ #define RTL8366RB_SMAR1			0x0071 /* bits 16..31 */
+@@ -844,16 +844,14 @@ static int rtl8366rb_setup(struct dsa_sw
+ 	if (ret)
+ 		return ret;
+ 
+-	/* Enable CPU port and enable inserting CPU tag
++	/* Enable CPU port with custom DSA tag 8899.
+ 	 *
+-	 * Disabling RTL8368RB_CPU_INSTAG here will change the behaviour
+-	 * of the switch totally and it will start talking Realtek RRCP
+-	 * internally. It is probably possible to experiment with this,
+-	 * but then the kernel needs to understand and handle RRCP first.
++	 * If you set RTL8368RB_CPU_NO_TAG (bit 15) in this registers
++	 * the custom tag is turned off.
+ 	 */
+ 	ret = regmap_update_bits(smi->map, RTL8368RB_CPU_CTRL_REG,
+ 				 0xFFFF,
+-				 RTL8368RB_CPU_INSTAG | BIT(smi->cpu_port));
++				 BIT(smi->cpu_port));
+ 	if (ret)
+ 		return ret;
+ 
+@@ -966,21 +964,8 @@ static int rtl8366rb_setup(struct dsa_sw
+ static enum dsa_tag_protocol rtl8366_get_tag_protocol(struct dsa_switch *ds,
+ 						      int port)
+ {
+-	/* For now, the RTL switches are handled without any custom tags.
+-	 *
+-	 * It is possible to turn on "custom tags" by removing the
+-	 * RTL8368RB_CPU_INSTAG flag when enabling the port but what it
+-	 * does is unfamiliar to DSA: ethernet frames of type 8899, the Realtek
+-	 * Remote Control Protocol (RRCP) start to appear on the CPU port of
+-	 * the device. So this is not the ordinary few extra bytes in the
+-	 * frame. Instead it appears that the switch starts to talk Realtek
+-	 * RRCP internally which means a pretty complex RRCP implementation
+-	 * decoding and responding the RRCP protocol is needed to exploit this.
+-	 *
+-	 * The OpenRRCP project (dormant since 2009) have reverse-egineered
+-	 * parts of the protocol.
+-	 */
+-	return DSA_TAG_PROTO_NONE;
++	/* This switch uses the 4 byte protocol A Realtek DSA tag */
++	return DSA_TAG_PROTO_RTL4_A;
+ }
+ 
+ static void rtl8366rb_adjust_link(struct dsa_switch *ds, int port,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/765-v5.12-net-dsa-automatically-bring-up-DSA-master-when-openi.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/765-v5.12-net-dsa-automatically-bring-up-DSA-master-when-openi.patch
new file mode 100644
index 0000000..7ec2689
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/765-v5.12-net-dsa-automatically-bring-up-DSA-master-when-openi.patch
@@ -0,0 +1,85 @@
+From 9d5ef190e5615a7b63af89f88c4106a5bc127974 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Fri, 5 Feb 2021 15:37:10 +0200
+Subject: [PATCH] net: dsa: automatically bring up DSA master when opening user
+ port
+
+DSA wants the master interface to be open before the user port is due to
+historical reasons. The promiscuity of interfaces that are down used to
+have issues, as referenced Lennert Buytenhek in commit df02c6ff2e39
+("dsa: fix master interface allmulti/promisc handling").
+
+The bugfix mentioned there, commit b6c40d68ff64 ("net: only invoke
+dev->change_rx_flags when device is UP"), was basically a "don't do
+that" approach to working around the promiscuity while down issue.
+
+Further work done by Vlad Yasevich in commit d2615bf45069 ("net: core:
+Always propagate flag changes to interfaces") has resolved the
+underlying issue, and it is strictly up to the DSA and 8021q drivers
+now, it is no longer mandated by the networking core that the master
+interface must be up when changing its promiscuity.
+
+From DSA's point of view, deciding to error out in dsa_slave_open
+because the master isn't up is
+(a) a bad user experience and
+(b) knocking at an open door.
+Even if there still was an issue with promiscuity while down, DSA could
+still just open the master and avoid it.
+
+Doing it this way has the additional benefit that user space can now
+remove DSA-specific workarounds, like systemd-networkd with BindCarrier:
+https://github.com/systemd/systemd/issues/7478
+
+And we can finally remove one of the 2 bullets in the "Common pitfalls
+using DSA setups" chapter.
+
+Tested with two cascaded DSA switches:
+
+$ ip link set sw0p2 up
+fsl_enetc 0000:00:00.2 eno2: configuring for fixed/internal link mode
+fsl_enetc 0000:00:00.2 eno2: Link is Up - 1Gbps/Full - flow control rx/tx
+mscc_felix 0000:00:00.5 swp0: configuring for fixed/sgmii link mode
+mscc_felix 0000:00:00.5 swp0: Link is Up - 1Gbps/Full - flow control off
+8021q: adding VLAN 0 to HW filter on device swp0
+sja1105 spi2.0 sw0p2: configuring for phy/rgmii-id link mode
+IPv6: ADDRCONF(NETDEV_CHANGE): eno2: link becomes ready
+IPv6: ADDRCONF(NETDEV_CHANGE): swp0: link becomes ready
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ Documentation/networking/dsa/dsa.rst | 4 ----
+ net/dsa/slave.c                      | 7 +++++--
+ 2 files changed, 5 insertions(+), 6 deletions(-)
+
+--- a/Documentation/networking/dsa/dsa.rst
++++ b/Documentation/networking/dsa/dsa.rst
+@@ -273,10 +273,6 @@ will not make us go through the switch t
+ the Ethernet switch on the other end, expecting a tag will typically drop this
+ frame.
+ 
+-Slave network devices check that the master network device is UP before allowing
+-you to administratively bring UP these slave network devices. A common
+-configuration mistake is forgetting to bring UP the master network device first.
+-
+ Interactions with other subsystems
+ ==================================
+ 
+--- a/net/dsa/slave.c
++++ b/net/dsa/slave.c
+@@ -70,8 +70,11 @@ static int dsa_slave_open(struct net_dev
+ 	struct dsa_port *dp = dsa_slave_to_port(dev);
+ 	int err;
+ 
+-	if (!(master->flags & IFF_UP))
+-		return -ENETDOWN;
++	err = dev_open(master, NULL);
++	if (err < 0) {
++		netdev_err(dev, "failed to open master %s\n", master->name);
++		goto out;
++	}
+ 
+ 	if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) {
+ 		err = dev_uc_add(master, dev->dev_addr);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/770-v5.12-net-bridge-notify-switchdev-of-disappearance-of-old-.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/770-v5.12-net-bridge-notify-switchdev-of-disappearance-of-old-.patch
new file mode 100644
index 0000000..df4e74c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/770-v5.12-net-bridge-notify-switchdev-of-disappearance-of-old-.patch
@@ -0,0 +1,126 @@
+From 90dc8fd36078a536671adae884d0b929cce6480a Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Wed, 6 Jan 2021 11:51:30 +0200
+Subject: [PATCH] net: bridge: notify switchdev of disappearance of old FDB
+ entry upon migration
+
+Currently the bridge emits atomic switchdev notifications for
+dynamically learnt FDB entries. Monitoring these notifications works
+wonders for switchdev drivers that want to keep their hardware FDB in
+sync with the bridge's FDB.
+
+For example station A wants to talk to station B in the diagram below,
+and we are concerned with the behavior of the bridge on the DUT device:
+
+                   DUT
+ +-------------------------------------+
+ |                 br0                 |
+ | +------+ +------+ +------+ +------+ |
+ | |      | |      | |      | |      | |
+ | | swp0 | | swp1 | | swp2 | | eth0 | |
+ +-------------------------------------+
+      |        |                  |
+  Station A    |                  |
+               |                  |
+         +--+------+--+    +--+------+--+
+         |  |      |  |    |  |      |  |
+         |  | swp0 |  |    |  | swp0 |  |
+ Another |  +------+  |    |  +------+  | Another
+  switch |     br0    |    |     br0    | switch
+         |  +------+  |    |  +------+  |
+         |  |      |  |    |  |      |  |
+         |  | swp1 |  |    |  | swp1 |  |
+         +--+------+--+    +--+------+--+
+                                  |
+                              Station B
+
+Interfaces swp0, swp1, swp2 are handled by a switchdev driver that has
+the following property: frames injected from its control interface bypass
+the internal address analyzer logic, and therefore, this hardware does
+not learn from the source address of packets transmitted by the network
+stack through it. So, since bridging between eth0 (where Station B is
+attached) and swp0 (where Station A is attached) is done in software,
+the switchdev hardware will never learn the source address of Station B.
+So the traffic towards that destination will be treated as unknown, i.e.
+flooded.
+
+This is where the bridge notifications come in handy. When br0 on the
+DUT sees frames with Station B's MAC address on eth0, the switchdev
+driver gets these notifications and can install a rule to send frames
+towards Station B's address that are incoming from swp0, swp1, swp2,
+only towards the control interface. This is all switchdev driver private
+business, which the notification makes possible.
+
+All is fine until someone unplugs Station B's cable and moves it to the
+other switch:
+
+                   DUT
+ +-------------------------------------+
+ |                 br0                 |
+ | +------+ +------+ +------+ +------+ |
+ | |      | |      | |      | |      | |
+ | | swp0 | | swp1 | | swp2 | | eth0 | |
+ +-------------------------------------+
+      |        |                  |
+  Station A    |                  |
+               |                  |
+         +--+------+--+    +--+------+--+
+         |  |      |  |    |  |      |  |
+         |  | swp0 |  |    |  | swp0 |  |
+ Another |  +------+  |    |  +------+  | Another
+  switch |     br0    |    |     br0    | switch
+         |  +------+  |    |  +------+  |
+         |  |      |  |    |  |      |  |
+         |  | swp1 |  |    |  | swp1 |  |
+         +--+------+--+    +--+------+--+
+               |
+           Station B
+
+Luckily for the use cases we care about, Station B is noisy enough that
+the DUT hears it (on swp1 this time). swp1 receives the frames and
+delivers them to the bridge, who enters the unlikely path in br_fdb_update
+of updating an existing entry. It moves the entry in the software bridge
+to swp1 and emits an addition notification towards that.
+
+As far as the switchdev driver is concerned, all that it needs to ensure
+is that traffic between Station A and Station B is not forever broken.
+If it does nothing, then the stale rule to send frames for Station B
+towards the control interface remains in place. But Station B is no
+longer reachable via the control interface, but via a port that can
+offload the bridge port learning attribute. It's just that the port is
+prevented from learning this address, since the rule overrides FDB
+updates. So the rule needs to go. The question is via what mechanism.
+
+It sure would be possible for this switchdev driver to keep track of all
+addresses which are sent to the control interface, and then also listen
+for bridge notifier events on its own ports, searching for the ones that
+have a MAC address which was previously sent to the control interface.
+But this is cumbersome and inefficient. Instead, with one small change,
+the bridge could notify of the address deletion from the old port, in a
+symmetrical manner with how it did for the insertion. Then the switchdev
+driver would not be required to monitor learn/forget events for its own
+ports. It could just delete the rule towards the control interface upon
+bridge entry migration. This would make hardware address learning be
+possible again. Then it would take a few more packets until the hardware
+and software FDB would be in sync again.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Acked-by: Nikolay Aleksandrov <nikolay@nvidia.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ net/bridge/br_fdb.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/net/bridge/br_fdb.c
++++ b/net/bridge/br_fdb.c
+@@ -581,6 +581,7 @@ void br_fdb_update(struct net_bridge *br
+ 
+ 			/* fastpath: update of existing entry */
+ 			if (unlikely(source != fdb->dst && !fdb->is_sticky)) {
++				br_switchdev_fdb_notify(fdb, RTM_DELNEIGH);
+ 				fdb->dst = source;
+ 				fdb_modified = true;
+ 				/* Take over HW learned entry */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/771-v5.12-net-dsa-be-louder-when-a-non-legacy-FDB-operation-fa.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/771-v5.12-net-dsa-be-louder-when-a-non-legacy-FDB-operation-fa.patch
new file mode 100644
index 0000000..893eb71
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/771-v5.12-net-dsa-be-louder-when-a-non-legacy-FDB-operation-fa.patch
@@ -0,0 +1,52 @@
+From 2fd186501b1cff155cc4a755c210793cfc0dffb5 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Wed, 6 Jan 2021 11:51:31 +0200
+Subject: [PATCH] net: dsa: be louder when a non-legacy FDB operation fails
+
+The dev_close() call was added in commit c9eb3e0f8701 ("net: dsa: Add
+support for learning FDB through notification") "to indicate inconsistent
+situation" when we could not delete an FDB entry from the port.
+
+bridge fdb del d8:58:d7:00:ca:6d dev swp0 self master
+
+It is a bit drastic and at the same time not helpful if the above fails
+to only print with netdev_dbg log level, but on the other hand to bring
+the interface down.
+
+So increase the verbosity of the error message, and drop dev_close().
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ net/dsa/slave.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+--- a/net/dsa/slave.c
++++ b/net/dsa/slave.c
+@@ -1593,7 +1593,9 @@ static void dsa_slave_switchdev_event_wo
+ 
+ 		err = dsa_port_fdb_add(dp, fdb_info->addr, fdb_info->vid);
+ 		if (err) {
+-			netdev_dbg(dev, "fdb add failed err=%d\n", err);
++			netdev_err(dev,
++				   "failed to add %pM vid %d to fdb: %d\n",
++				   fdb_info->addr, fdb_info->vid, err);
+ 			break;
+ 		}
+ 		fdb_info->offloaded = true;
+@@ -1608,9 +1610,11 @@ static void dsa_slave_switchdev_event_wo
+ 
+ 		err = dsa_port_fdb_del(dp, fdb_info->addr, fdb_info->vid);
+ 		if (err) {
+-			netdev_dbg(dev, "fdb del failed err=%d\n", err);
+-			dev_close(dev);
++			netdev_err(dev,
++				   "failed to delete %pM vid %d from fdb: %d\n",
++				   fdb_info->addr, fdb_info->vid, err);
+ 		}
++
+ 		break;
+ 	}
+ 	rtnl_unlock();
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/772-v5.12-net-dsa-don-t-use-switchdev_notifier_fdb_info-in-dsa.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/772-v5.12-net-dsa-don-t-use-switchdev_notifier_fdb_info-in-dsa.patch
new file mode 100644
index 0000000..275870d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/772-v5.12-net-dsa-don-t-use-switchdev_notifier_fdb_info-in-dsa.patch
@@ -0,0 +1,226 @@
+From c4bb76a9a0ef87c4cc1f636defed5f12deb9f5a7 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Wed, 6 Jan 2021 11:51:32 +0200
+Subject: [PATCH] net: dsa: don't use switchdev_notifier_fdb_info in
+ dsa_switchdev_event_work
+
+Currently DSA doesn't add FDB entries on the CPU port, because it only
+does so through switchdev, which is associated with a net_device, and
+there are none of those for the CPU port.
+
+But actually FDB addresses on the CPU port have some use cases of their
+own, if the switchdev operations are initiated from within the DSA
+layer. There is just one problem with the existing code: it passes a
+structure in dsa_switchdev_event_work which was retrieved directly from
+switchdev, so it contains a net_device. We need to generalize the
+contents to something that covers the CPU port as well: the "ds, port"
+tuple is fine for that.
+
+Note that the new procedure for notifying the successful FDB offload is
+inspired from the rocker model.
+
+Also, nothing was being done if added_by_user was false. Let's check for
+that a lot earlier, and don't actually bother to schedule the worker
+for nothing.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ net/dsa/dsa_priv.h |  12 +++++
+ net/dsa/slave.c    | 106 ++++++++++++++++++++++-----------------------
+ 2 files changed, 65 insertions(+), 53 deletions(-)
+
+--- a/net/dsa/dsa_priv.h
++++ b/net/dsa/dsa_priv.h
+@@ -62,6 +62,18 @@ struct dsa_notifier_vlan_info {
+ 	int port;
+ };
+ 
++struct dsa_switchdev_event_work {
++	struct dsa_switch *ds;
++	int port;
++	struct work_struct work;
++	unsigned long event;
++	/* Specific for SWITCHDEV_FDB_ADD_TO_DEVICE and
++	 * SWITCHDEV_FDB_DEL_TO_DEVICE
++	 */
++	unsigned char addr[ETH_ALEN];
++	u16 vid;
++};
++
+ struct dsa_slave_priv {
+ 	/* Copy of CPU port xmit for faster access in slave transmit hot path */
+ 	struct sk_buff *	(*xmit)(struct sk_buff *skb,
+--- a/net/dsa/slave.c
++++ b/net/dsa/slave.c
+@@ -1568,76 +1568,66 @@ static int dsa_slave_netdevice_event(str
+ 	return NOTIFY_DONE;
+ }
+ 
+-struct dsa_switchdev_event_work {
+-	struct work_struct work;
+-	struct switchdev_notifier_fdb_info fdb_info;
+-	struct net_device *dev;
+-	unsigned long event;
+-};
++static void
++dsa_fdb_offload_notify(struct dsa_switchdev_event_work *switchdev_work)
++{
++	struct dsa_switch *ds = switchdev_work->ds;
++	struct switchdev_notifier_fdb_info info;
++	struct dsa_port *dp;
++
++	if (!dsa_is_user_port(ds, switchdev_work->port))
++		return;
++
++	info.addr = switchdev_work->addr;
++	info.vid = switchdev_work->vid;
++	info.offloaded = true;
++	dp = dsa_to_port(ds, switchdev_work->port);
++	call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED,
++				 dp->slave, &info.info, NULL);
++}
+ 
+ static void dsa_slave_switchdev_event_work(struct work_struct *work)
+ {
+ 	struct dsa_switchdev_event_work *switchdev_work =
+ 		container_of(work, struct dsa_switchdev_event_work, work);
+-	struct net_device *dev = switchdev_work->dev;
+-	struct switchdev_notifier_fdb_info *fdb_info;
+-	struct dsa_port *dp = dsa_slave_to_port(dev);
++	struct dsa_switch *ds = switchdev_work->ds;
++	struct dsa_port *dp;
+ 	int err;
+ 
++	dp = dsa_to_port(ds, switchdev_work->port);
++
+ 	rtnl_lock();
+ 	switch (switchdev_work->event) {
+ 	case SWITCHDEV_FDB_ADD_TO_DEVICE:
+-		fdb_info = &switchdev_work->fdb_info;
+-		if (!fdb_info->added_by_user)
+-			break;
+-
+-		err = dsa_port_fdb_add(dp, fdb_info->addr, fdb_info->vid);
++		err = dsa_port_fdb_add(dp, switchdev_work->addr,
++				       switchdev_work->vid);
+ 		if (err) {
+-			netdev_err(dev,
+-				   "failed to add %pM vid %d to fdb: %d\n",
+-				   fdb_info->addr, fdb_info->vid, err);
++			dev_err(ds->dev,
++				"port %d failed to add %pM vid %d to fdb: %d\n",
++				dp->index, switchdev_work->addr,
++				switchdev_work->vid, err);
+ 			break;
+ 		}
+-		fdb_info->offloaded = true;
+-		call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, dev,
+-					 &fdb_info->info, NULL);
++		dsa_fdb_offload_notify(switchdev_work);
+ 		break;
+ 
+ 	case SWITCHDEV_FDB_DEL_TO_DEVICE:
+-		fdb_info = &switchdev_work->fdb_info;
+-		if (!fdb_info->added_by_user)
+-			break;
+-
+-		err = dsa_port_fdb_del(dp, fdb_info->addr, fdb_info->vid);
++		err = dsa_port_fdb_del(dp, switchdev_work->addr,
++				       switchdev_work->vid);
+ 		if (err) {
+-			netdev_err(dev,
+-				   "failed to delete %pM vid %d from fdb: %d\n",
+-				   fdb_info->addr, fdb_info->vid, err);
++			dev_err(ds->dev,
++				"port %d failed to delete %pM vid %d from fdb: %d\n",
++				dp->index, switchdev_work->addr,
++				switchdev_work->vid, err);
+ 		}
+ 
+ 		break;
+ 	}
+ 	rtnl_unlock();
+ 
+-	kfree(switchdev_work->fdb_info.addr);
+ 	kfree(switchdev_work);
+-	dev_put(dev);
+-}
+-
+-static int
+-dsa_slave_switchdev_fdb_work_init(struct dsa_switchdev_event_work *
+-				  switchdev_work,
+-				  const struct switchdev_notifier_fdb_info *
+-				  fdb_info)
+-{
+-	memcpy(&switchdev_work->fdb_info, fdb_info,
+-	       sizeof(switchdev_work->fdb_info));
+-	switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);
+-	if (!switchdev_work->fdb_info.addr)
+-		return -ENOMEM;
+-	ether_addr_copy((u8 *)switchdev_work->fdb_info.addr,
+-			fdb_info->addr);
+-	return 0;
++	if (dsa_is_user_port(ds, dp->index))
++		dev_put(dp->slave);
+ }
+ 
+ /* Called under rcu_read_lock() */
+@@ -1645,7 +1635,9 @@ static int dsa_slave_switchdev_event(str
+ 				     unsigned long event, void *ptr)
+ {
+ 	struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
++	const struct switchdev_notifier_fdb_info *fdb_info;
+ 	struct dsa_switchdev_event_work *switchdev_work;
++	struct dsa_port *dp;
+ 	int err;
+ 
+ 	if (event == SWITCHDEV_PORT_ATTR_SET) {
+@@ -1658,20 +1650,32 @@ static int dsa_slave_switchdev_event(str
+ 	if (!dsa_slave_dev_check(dev))
+ 		return NOTIFY_DONE;
+ 
++	dp = dsa_slave_to_port(dev);
++
+ 	switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
+ 	if (!switchdev_work)
+ 		return NOTIFY_BAD;
+ 
+ 	INIT_WORK(&switchdev_work->work,
+ 		  dsa_slave_switchdev_event_work);
+-	switchdev_work->dev = dev;
++	switchdev_work->ds = dp->ds;
++	switchdev_work->port = dp->index;
+ 	switchdev_work->event = event;
+ 
+ 	switch (event) {
+ 	case SWITCHDEV_FDB_ADD_TO_DEVICE: /* fall through */
+ 	case SWITCHDEV_FDB_DEL_TO_DEVICE:
+-		if (dsa_slave_switchdev_fdb_work_init(switchdev_work, ptr))
+-			goto err_fdb_work_init;
++		fdb_info = ptr;
++
++		if (!fdb_info->added_by_user) {
++			kfree(switchdev_work);
++			return NOTIFY_OK;
++		}
++
++		ether_addr_copy(switchdev_work->addr,
++				fdb_info->addr);
++		switchdev_work->vid = fdb_info->vid;
++
+ 		dev_hold(dev);
+ 		break;
+ 	default:
+@@ -1681,10 +1685,6 @@ static int dsa_slave_switchdev_event(str
+ 
+ 	dsa_schedule_work(&switchdev_work->work);
+ 	return NOTIFY_OK;
+-
+-err_fdb_work_init:
+-	kfree(switchdev_work);
+-	return NOTIFY_BAD;
+ }
+ 
+ static int dsa_slave_switchdev_blocking_event(struct notifier_block *unused,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/773-v5.12-net-dsa-move-switchdev-event-implementation-under-th.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/773-v5.12-net-dsa-move-switchdev-event-implementation-under-th.patch
new file mode 100644
index 0000000..b70986f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/773-v5.12-net-dsa-move-switchdev-event-implementation-under-th.patch
@@ -0,0 +1,85 @@
+From 447d290a58bd335d68f665713842365d3d6447df Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Wed, 6 Jan 2021 11:51:33 +0200
+Subject: [PATCH] net: dsa: move switchdev event implementation under the same
+ switch/case statement
+
+We'll need to start listening to SWITCHDEV_FDB_{ADD,DEL}_TO_DEVICE
+events even for interfaces where dsa_slave_dev_check returns false, so
+we need that check inside the switch-case statement for SWITCHDEV_FDB_*.
+
+This movement also avoids a useless allocation / free of switchdev_work
+on the untreated "default event" case.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ net/dsa/slave.c | 35 ++++++++++++++++-------------------
+ 1 file changed, 16 insertions(+), 19 deletions(-)
+
+--- a/net/dsa/slave.c
++++ b/net/dsa/slave.c
+@@ -1640,31 +1640,29 @@ static int dsa_slave_switchdev_event(str
+ 	struct dsa_port *dp;
+ 	int err;
+ 
+-	if (event == SWITCHDEV_PORT_ATTR_SET) {
++	switch (event) {
++	case SWITCHDEV_PORT_ATTR_SET:
+ 		err = switchdev_handle_port_attr_set(dev, ptr,
+ 						     dsa_slave_dev_check,
+ 						     dsa_slave_port_attr_set);
+ 		return notifier_from_errno(err);
+-	}
+-
+-	if (!dsa_slave_dev_check(dev))
+-		return NOTIFY_DONE;
++	case SWITCHDEV_FDB_ADD_TO_DEVICE:
++	case SWITCHDEV_FDB_DEL_TO_DEVICE:
++		if (!dsa_slave_dev_check(dev))
++			return NOTIFY_DONE;
+ 
+-	dp = dsa_slave_to_port(dev);
++		dp = dsa_slave_to_port(dev);
+ 
+-	switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
+-	if (!switchdev_work)
+-		return NOTIFY_BAD;
+-
+-	INIT_WORK(&switchdev_work->work,
+-		  dsa_slave_switchdev_event_work);
+-	switchdev_work->ds = dp->ds;
+-	switchdev_work->port = dp->index;
+-	switchdev_work->event = event;
++		switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
++		if (!switchdev_work)
++			return NOTIFY_BAD;
++
++		INIT_WORK(&switchdev_work->work,
++			  dsa_slave_switchdev_event_work);
++		switchdev_work->ds = dp->ds;
++		switchdev_work->port = dp->index;
++		switchdev_work->event = event;
+ 
+-	switch (event) {
+-	case SWITCHDEV_FDB_ADD_TO_DEVICE: /* fall through */
+-	case SWITCHDEV_FDB_DEL_TO_DEVICE:
+ 		fdb_info = ptr;
+ 
+ 		if (!fdb_info->added_by_user) {
+@@ -1677,13 +1675,12 @@ static int dsa_slave_switchdev_event(str
+ 		switchdev_work->vid = fdb_info->vid;
+ 
+ 		dev_hold(dev);
++		dsa_schedule_work(&switchdev_work->work);
+ 		break;
+ 	default:
+-		kfree(switchdev_work);
+ 		return NOTIFY_DONE;
+ 	}
+ 
+-	dsa_schedule_work(&switchdev_work->work);
+ 	return NOTIFY_OK;
+ }
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/774-v5.12-net-dsa-exit-early-in-dsa_slave_switchdev_event-if-w.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/774-v5.12-net-dsa-exit-early-in-dsa_slave_switchdev_event-if-w.patch
new file mode 100644
index 0000000..c7ed406
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/774-v5.12-net-dsa-exit-early-in-dsa_slave_switchdev_event-if-w.patch
@@ -0,0 +1,42 @@
+From 5fb4a451a87d8ed3363d28b63a3295399373d6c4 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Wed, 6 Jan 2021 11:51:34 +0200
+Subject: [PATCH] net: dsa: exit early in dsa_slave_switchdev_event if we can't
+ program the FDB
+
+Right now, the following would happen for a switch driver that does not
+implement .port_fdb_add or .port_fdb_del.
+
+dsa_slave_switchdev_event returns NOTIFY_OK and schedules:
+-> dsa_slave_switchdev_event_work
+   -> dsa_port_fdb_add
+      -> dsa_port_notify(DSA_NOTIFIER_FDB_ADD)
+         -> dsa_switch_fdb_add
+            -> if (!ds->ops->port_fdb_add) return -EOPNOTSUPP;
+   -> an error is printed with dev_dbg, and
+      dsa_fdb_offload_notify(switchdev_work) is not called.
+
+We can avoid scheduling the worker for nothing and say NOTIFY_DONE.
+Because we don't call dsa_fdb_offload_notify, the static FDB entry will
+remain just in the software bridge.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ net/dsa/slave.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/net/dsa/slave.c
++++ b/net/dsa/slave.c
+@@ -1653,6 +1653,9 @@ static int dsa_slave_switchdev_event(str
+ 
+ 		dp = dsa_slave_to_port(dev);
+ 
++		if (!dp->ds->ops->port_fdb_add || !dp->ds->ops->port_fdb_del)
++			return NOTIFY_DONE;
++
+ 		switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
+ 		if (!switchdev_work)
+ 			return NOTIFY_BAD;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/775-v5.12-net-dsa-listen-for-SWITCHDEV_-FDB-DEL-_ADD_TO_DEVICE.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/775-v5.12-net-dsa-listen-for-SWITCHDEV_-FDB-DEL-_ADD_TO_DEVICE.patch
new file mode 100644
index 0000000..e4ed6e8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/775-v5.12-net-dsa-listen-for-SWITCHDEV_-FDB-DEL-_ADD_TO_DEVICE.patch
@@ -0,0 +1,263 @@
+From d5f19486cee79d04c054427577ac96ed123706db Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Wed, 6 Jan 2021 11:51:35 +0200
+Subject: [PATCH] net: dsa: listen for SWITCHDEV_{FDB,DEL}_ADD_TO_DEVICE on
+ foreign bridge neighbors
+
+Some DSA switches (and not only) cannot learn source MAC addresses from
+packets injected from the CPU. They only perform hardware address
+learning from inbound traffic.
+
+This can be problematic when we have a bridge spanning some DSA switch
+ports and some non-DSA ports (which we'll call "foreign interfaces" from
+DSA's perspective).
+
+There are 2 classes of problems created by the lack of learning on
+CPU-injected traffic:
+- excessive flooding, due to the fact that DSA treats those addresses as
+  unknown
+- the risk of stale routes, which can lead to temporary packet loss
+
+To illustrate the second class, consider the following situation, which
+is common in production equipment (wireless access points, where there
+is a WLAN interface and an Ethernet switch, and these form a single
+bridging domain).
+
+ AP 1:
+ +------------------------------------------------------------------------+
+ |                                          br0                           |
+ +------------------------------------------------------------------------+
+ +------------+ +------------+ +------------+ +------------+ +------------+
+ |    swp0    | |    swp1    | |    swp2    | |    swp3    | |    wlan0   |
+ +------------+ +------------+ +------------+ +------------+ +------------+
+       |                                                       ^        ^
+       |                                                       |        |
+       |                                                       |        |
+       |                                                    Client A  Client B
+       |
+       |
+       |
+ +------------+ +------------+ +------------+ +------------+ +------------+
+ |    swp0    | |    swp1    | |    swp2    | |    swp3    | |    wlan0   |
+ +------------+ +------------+ +------------+ +------------+ +------------+
+ +------------------------------------------------------------------------+
+ |                                          br0                           |
+ +------------------------------------------------------------------------+
+ AP 2
+
+- br0 of AP 1 will know that Clients A and B are reachable via wlan0
+- the hardware fdb of a DSA switch driver today is not kept in sync with
+  the software entries on other bridge ports, so it will not know that
+  clients A and B are reachable via the CPU port UNLESS the hardware
+  switch itself performs SA learning from traffic injected from the CPU.
+  Nonetheless, a substantial number of switches don't.
+- the hardware fdb of the DSA switch on AP 2 may autonomously learn that
+  Client A and B are reachable through swp0. Therefore, the software br0
+  of AP 2 also may or may not learn this. In the example we're
+  illustrating, some Ethernet traffic has been going on, and br0 from AP
+  2 has indeed learnt that it can reach Client B through swp0.
+
+One of the wireless clients, say Client B, disconnects from AP 1 and
+roams to AP 2. The topology now looks like this:
+
+ AP 1:
+ +------------------------------------------------------------------------+
+ |                                          br0                           |
+ +------------------------------------------------------------------------+
+ +------------+ +------------+ +------------+ +------------+ +------------+
+ |    swp0    | |    swp1    | |    swp2    | |    swp3    | |    wlan0   |
+ +------------+ +------------+ +------------+ +------------+ +------------+
+       |                                                            ^
+       |                                                            |
+       |                                                         Client A
+       |
+       |
+       |                                                         Client B
+       |                                                            |
+       |                                                            v
+ +------------+ +------------+ +------------+ +------------+ +------------+
+ |    swp0    | |    swp1    | |    swp2    | |    swp3    | |    wlan0   |
+ +------------+ +------------+ +------------+ +------------+ +------------+
+ +------------------------------------------------------------------------+
+ |                                          br0                           |
+ +------------------------------------------------------------------------+
+ AP 2
+
+- br0 of AP 1 still knows that Client A is reachable via wlan0 (no change)
+- br0 of AP 1 will (possibly) know that Client B has left wlan0. There
+  are cases where it might never find out though. Either way, DSA today
+  does not process that notification in any way.
+- the hardware FDB of the DSA switch on AP 1 may learn autonomously that
+  Client B can be reached via swp0, if it receives any packet with
+  Client 1's source MAC address over Ethernet.
+- the hardware FDB of the DSA switch on AP 2 still thinks that Client B
+  can be reached via swp0. It does not know that it has roamed to wlan0,
+  because it doesn't perform SA learning from the CPU port.
+
+Now Client A contacts Client B.
+AP 1 routes the packet fine towards swp0 and delivers it on the Ethernet
+segment.
+AP 2 sees a frame on swp0 and its fdb says that the destination is swp0.
+Hairpinning is disabled => drop.
+
+This problem comes from the fact that these switches have a 'blind spot'
+for addresses coming from software bridging. The generic solution is not
+to assume that hardware learning can be enabled somehow, but to listen
+to more bridge learning events. It turns out that the bridge driver does
+learn in software from all inbound frames, in __br_handle_local_finish.
+A proper SWITCHDEV_FDB_ADD_TO_DEVICE notification is emitted for the
+addresses serviced by the bridge on 'foreign' interfaces. The software
+bridge also does the right thing on migration, by notifying that the old
+entry is deleted, so that does not need to be special-cased in DSA. When
+it is deleted, we just need to delete our static FDB entry towards the
+CPU too, and wait.
+
+The problem is that DSA currently only cares about SWITCHDEV_FDB_ADD_TO_DEVICE
+events received on its own interfaces, such as static FDB entries.
+
+Luckily we can change that, and DSA can listen to all switchdev FDB
+add/del events in the system and figure out if those events were emitted
+by a bridge that spans at least one of DSA's own ports. In case that is
+true, DSA will also offload that address towards its own CPU port, in
+the eventuality that there might be bridge clients attached to the DSA
+switch who want to talk to the station connected to the foreign
+interface.
+
+In terms of implementation, we need to keep the fdb_info->added_by_user
+check for the case where the switchdev event was targeted directly at a
+DSA switch port. But we don't need to look at that flag for snooped
+events. So the check is currently too late, we need to move it earlier.
+This also simplifies the code a bit, since we avoid uselessly allocating
+and freeing switchdev_work.
+
+We could probably do some improvements in the future. For example,
+multi-bridge support is rudimentary at the moment. If there are two
+bridges spanning a DSA switch's ports, and both of them need to service
+the same MAC address, then what will happen is that the migration of one
+of those stations will trigger the deletion of the FDB entry from the
+CPU port while it is still used by other bridge. That could be improved
+with reference counting but is left for another time.
+
+This behavior needs to be enabled at driver level by setting
+ds->assisted_learning_on_cpu_port = true. This is because we don't want
+to inflict a potential performance penalty (accesses through
+MDIO/I2C/SPI are expensive) to hardware that really doesn't need it
+because address learning on the CPU port works there.
+
+Reported-by: DENG Qingfang <dqfext@gmail.com>
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[Backported to linux-5.4.y]
+Signed-off-by: DENG Qingfang <dqfext@gmail.com>
+---
+ include/net/dsa.h |  5 ++++
+ net/dsa/slave.c   | 63 ++++++++++++++++++++++++++++++++++++++---------
+ 2 files changed, 57 insertions(+), 11 deletions(-)
+
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -279,6 +279,11 @@ struct dsa_switch {
+ 	 */
+ 	bool			configure_vlan_while_not_filtering;
+ 
++	/* Let DSA manage the FDB entries towards the CPU, based on the
++	 * software bridge database.
++	 */
++	bool			assisted_learning_on_cpu_port;
++
+ 	/* In case vlan_filtering_is_global is set, the VLAN awareness state
+ 	 * should be retrieved from here and not from the per-port settings.
+ 	 */
+--- a/net/dsa/slave.c
++++ b/net/dsa/slave.c
+@@ -1630,6 +1630,25 @@ static void dsa_slave_switchdev_event_wo
+ 		dev_put(dp->slave);
+ }
+ 
++static int dsa_lower_dev_walk(struct net_device *lower_dev, void *data)
++{
++	if (dsa_slave_dev_check(lower_dev)) {
++		*((void **)data) = (void *)netdev_priv(lower_dev);
++		return 1;
++	}
++
++	return 0;
++}
++
++static struct dsa_slave_priv *dsa_slave_dev_lower_find(struct net_device *dev)
++{
++	struct dsa_slave_priv *data = NULL;
++
++	netdev_walk_all_lower_dev_rcu(dev, dsa_lower_dev_walk, (void **) &data);
++
++	return data;
++}
++
+ /* Called under rcu_read_lock() */
+ static int dsa_slave_switchdev_event(struct notifier_block *unused,
+ 				     unsigned long event, void *ptr)
+@@ -1648,10 +1667,37 @@ static int dsa_slave_switchdev_event(str
+ 		return notifier_from_errno(err);
+ 	case SWITCHDEV_FDB_ADD_TO_DEVICE:
+ 	case SWITCHDEV_FDB_DEL_TO_DEVICE:
+-		if (!dsa_slave_dev_check(dev))
+-			return NOTIFY_DONE;
++		fdb_info = ptr;
++
++		if (dsa_slave_dev_check(dev)) {
++			if (!fdb_info->added_by_user)
++				return NOTIFY_OK;
++
++			dp = dsa_slave_to_port(dev);
++		} else {
++			/* Snoop addresses learnt on foreign interfaces
++			 * bridged with us, for switches that don't
++			 * automatically learn SA from CPU-injected traffic
++			 */
++			struct net_device *br_dev;
++			struct dsa_slave_priv *p;
++
++			br_dev = netdev_master_upper_dev_get_rcu(dev);
++			if (!br_dev)
++				return NOTIFY_DONE;
++
++			if (!netif_is_bridge_master(br_dev))
++				return NOTIFY_DONE;
++
++			p = dsa_slave_dev_lower_find(br_dev);
++			if (!p)
++				return NOTIFY_DONE;
+ 
+-		dp = dsa_slave_to_port(dev);
++			dp = p->dp->cpu_dp;
++
++			if (!dp->ds->assisted_learning_on_cpu_port)
++				return NOTIFY_DONE;
++		}
+ 
+ 		if (!dp->ds->ops->port_fdb_add || !dp->ds->ops->port_fdb_del)
+ 			return NOTIFY_DONE;
+@@ -1666,18 +1712,13 @@ static int dsa_slave_switchdev_event(str
+ 		switchdev_work->port = dp->index;
+ 		switchdev_work->event = event;
+ 
+-		fdb_info = ptr;
+-
+-		if (!fdb_info->added_by_user) {
+-			kfree(switchdev_work);
+-			return NOTIFY_OK;
+-		}
+-
+ 		ether_addr_copy(switchdev_work->addr,
+ 				fdb_info->addr);
+ 		switchdev_work->vid = fdb_info->vid;
+ 
+-		dev_hold(dev);
++		/* Hold a reference on the slave for dsa_fdb_offload_notify */
++		if (dsa_is_user_port(dp->ds, dp->index))
++			dev_hold(dev);
+ 		dsa_schedule_work(&switchdev_work->work);
+ 		break;
+ 	default:
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/780-net-dsa-mt7530-setup-core-clock-even-in-TRGMII-mode.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/780-net-dsa-mt7530-setup-core-clock-even-in-TRGMII-mode.patch
new file mode 100644
index 0000000..7ad7cd3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/780-net-dsa-mt7530-setup-core-clock-even-in-TRGMII-mode.patch
@@ -0,0 +1,84 @@
+From c3b8e07909dbe67b0d580416c1a5257643a73be7 Mon Sep 17 00:00:00 2001
+From: Ilya Lipnitskiy <ilya.lipnitskiy@gmail.com>
+Date: Fri, 12 Mar 2021 00:07:03 -0800
+Subject: [PATCH] net: dsa: mt7530: setup core clock even in TRGMII mode
+
+A recent change to MIPS ralink reset logic made it so mt7530 actually
+resets the switch on platforms such as mt7621 (where bit 2 is the reset
+line for the switch). That exposed an issue where the switch would not
+function properly in TRGMII mode after a reset.
+
+Reconfigure core clock in TRGMII mode to fix the issue.
+
+Tested on Ubiquiti ER-X (MT7621) with TRGMII mode enabled.
+
+Fixes: 3f9ef7785a9c ("MIPS: ralink: manage low reset lines")
+Signed-off-by: Ilya Lipnitskiy <ilya.lipnitskiy@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mt7530.c | 52 +++++++++++++++++++---------------------
+ 1 file changed, 25 insertions(+), 27 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -428,34 +428,32 @@ mt7530_pad_clk_setup(struct dsa_switch *
+ 			     TD_DM_DRVP(8) | TD_DM_DRVN(8));
+ 
+ 	/* Setup core clock for MT7530 */
+-	if (!trgint) {
+-		/* Disable MT7530 core clock */
+-		core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
+-
+-		/* Disable PLL, since phy_device has not yet been created
+-		 * provided for phy_[read,write]_mmd_indirect is called, we
+-		 * provide our own core_write_mmd_indirect to complete this
+-		 * function.
+-		 */
+-		core_write_mmd_indirect(priv,
+-					CORE_GSWPLL_GRP1,
+-					MDIO_MMD_VEND2,
+-					0);
+-
+-		/* Set core clock into 500Mhz */
+-		core_write(priv, CORE_GSWPLL_GRP2,
+-			   RG_GSWPLL_POSDIV_500M(1) |
+-			   RG_GSWPLL_FBKDIV_500M(25));
+-
+-		/* Enable PLL */
+-		core_write(priv, CORE_GSWPLL_GRP1,
+-			   RG_GSWPLL_EN_PRE |
+-			   RG_GSWPLL_POSDIV_200M(2) |
+-			   RG_GSWPLL_FBKDIV_200M(32));
+-
+-		/* Enable MT7530 core clock */
+-		core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
+-	}
++	/* Disable MT7530 core clock */
++	core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
++
++	/* Disable PLL, since phy_device has not yet been created
++	 * provided for phy_[read,write]_mmd_indirect is called, we
++	 * provide our own core_write_mmd_indirect to complete this
++	 * function.
++	 */
++	core_write_mmd_indirect(priv,
++				CORE_GSWPLL_GRP1,
++				MDIO_MMD_VEND2,
++				0);
++
++	/* Set core clock into 500Mhz */
++	core_write(priv, CORE_GSWPLL_GRP2,
++		   RG_GSWPLL_POSDIV_500M(1) |
++		   RG_GSWPLL_FBKDIV_500M(25));
++
++	/* Enable PLL */
++	core_write(priv, CORE_GSWPLL_GRP1,
++		   RG_GSWPLL_EN_PRE |
++		   RG_GSWPLL_POSDIV_200M(2) |
++		   RG_GSWPLL_FBKDIV_200M(32));
++
++	/* Enable MT7530 core clock */
++	core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
+ 
+ 	/* Setup the MT7530 TRGMII Tx Clock */
+ 	core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/800-v5.5-iio-imu-Add-support-for-the-FXOS8700-IMU.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/800-v5.5-iio-imu-Add-support-for-the-FXOS8700-IMU.patch
new file mode 100644
index 0000000..b9cd276
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/800-v5.5-iio-imu-Add-support-for-the-FXOS8700-IMU.patch
@@ -0,0 +1,893 @@
+From 84e5ddd5c46ea3bf0cad670da32028994cad5936 Mon Sep 17 00:00:00 2001
+From: Robert Jones <rjones@gateworks.com>
+Date: Mon, 14 Oct 2019 11:49:21 -0700
+Subject: [PATCH] iio: imu: Add support for the FXOS8700 IMU
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+FXOS8700CQ is a small, low-power, 3-axis linear accelerometer and 3-axis
+magnetometer combined into a single package. The device features a
+selectable I2C or point-to-point SPI serial interface with 14-bit
+accelerometer and 16-bit magnetometer ADC resolution along with
+smart-embedded functions.
+
+FXOS8700CQ has dynamically selectable accelerationfull-scale ranges of
+±2 g/±4 g/±8 g and a fixed magnetic measurement range of ±1200 μT.
+Output data rates (ODR) from 1.563 Hz to 800 Hz are selectable by the user
+for each sensor. Interleaved magnetic and acceleration data is available
+at ODR rates of up to 400 Hz. FXOS8700CQ is available in a plastic QFN
+package and it is guaranteed to operate over the extended temperature
+range of –40 °C to +85 °C.
+
+TODO: Trigger and IRQ configuration support
+
+Datasheet:
+  http://cache.freescale.com/files/sensors/doc/data_sheet/FXOS8700CQ.pdf
+
+Signed-off-by: Robert Jones <rjones@gateworks.com>
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+---
+ drivers/iio/imu/Kconfig         |  27 ++
+ drivers/iio/imu/Makefile        |   5 +
+ drivers/iio/imu/fxos8700.h      |  10 +
+ drivers/iio/imu/fxos8700_core.c | 649 ++++++++++++++++++++++++++++++++++++++++
+ drivers/iio/imu/fxos8700_i2c.c  |  71 +++++
+ drivers/iio/imu/fxos8700_spi.c  |  59 ++++
+ 6 files changed, 821 insertions(+)
+ create mode 100644 drivers/iio/imu/fxos8700.h
+ create mode 100644 drivers/iio/imu/fxos8700_core.c
+ create mode 100644 drivers/iio/imu/fxos8700_i2c.c
+ create mode 100644 drivers/iio/imu/fxos8700_spi.c
+
+--- a/drivers/iio/imu/Kconfig
++++ b/drivers/iio/imu/Kconfig
+@@ -40,6 +40,33 @@ config ADIS16480
+ 
+ source "drivers/iio/imu/bmi160/Kconfig"
+ 
++config FXOS8700
++	tristate
++
++config FXOS8700_I2C
++	tristate "NXP FXOS8700 I2C driver"
++	depends on I2C
++	select FXOS8700
++	select REGMAP_I2C
++	help
++	  Say yes here to build support for the NXP FXOS8700 m+g combo
++	  sensor on I2C.
++
++	  This driver can also be built as a module. If so, the module will be
++	  called fxos8700_i2c.
++
++config FXOS8700_SPI
++	tristate "NXP FXOS8700 SPI driver"
++	depends on SPI
++	select FXOS8700
++	select REGMAP_SPI
++	help
++	  Say yes here to build support for the NXP FXOS8700 m+g combo
++	  sensor on SPI.
++
++	  This driver can also be built as a module. If so, the module will be
++	  called fxos8700_spi.
++
+ config KMX61
+ 	tristate "Kionix KMX61 6-axis accelerometer and magnetometer"
+ 	depends on I2C
+--- a/drivers/iio/imu/Makefile
++++ b/drivers/iio/imu/Makefile
+@@ -14,6 +14,11 @@ adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) +
+ obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o
+ 
+ obj-y += bmi160/
++
++obj-$(CONFIG_FXOS8700) += fxos8700_core.o
++obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o
++obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o
++
+ obj-y += inv_mpu6050/
+ 
+ obj-$(CONFIG_KMX61) += kmx61.o
+--- /dev/null
++++ b/drivers/iio/imu/fxos8700.h
+@@ -0,0 +1,10 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef FXOS8700_H_
++#define FXOS8700_H_
++
++extern const struct regmap_config fxos8700_regmap_config;
++
++int fxos8700_core_probe(struct device *dev, struct regmap *regmap,
++			const char *name, bool use_spi);
++
++#endif  /* FXOS8700_H_ */
+--- /dev/null
++++ b/drivers/iio/imu/fxos8700_core.c
+@@ -0,0 +1,649 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * FXOS8700 - NXP IMU (accelerometer plus magnetometer)
++ *
++ * IIO core driver for FXOS8700, with support for I2C/SPI busses
++ *
++ * TODO: Buffer, trigger, and IRQ support
++ */
++#include <linux/module.h>
++#include <linux/regmap.h>
++#include <linux/acpi.h>
++#include <linux/bitops.h>
++
++#include <linux/iio/iio.h>
++#include <linux/iio/sysfs.h>
++
++#include "fxos8700.h"
++
++/* Register Definitions */
++#define FXOS8700_STATUS             0x00
++#define FXOS8700_OUT_X_MSB          0x01
++#define FXOS8700_OUT_X_LSB          0x02
++#define FXOS8700_OUT_Y_MSB          0x03
++#define FXOS8700_OUT_Y_LSB          0x04
++#define FXOS8700_OUT_Z_MSB          0x05
++#define FXOS8700_OUT_Z_LSB          0x06
++#define FXOS8700_F_SETUP            0x09
++#define FXOS8700_TRIG_CFG           0x0a
++#define FXOS8700_SYSMOD             0x0b
++#define FXOS8700_INT_SOURCE         0x0c
++#define FXOS8700_WHO_AM_I           0x0d
++#define FXOS8700_XYZ_DATA_CFG       0x0e
++#define FXOS8700_HP_FILTER_CUTOFF   0x0f
++#define FXOS8700_PL_STATUS          0x10
++#define FXOS8700_PL_CFG             0x11
++#define FXOS8700_PL_COUNT           0x12
++#define FXOS8700_PL_BF_ZCOMP        0x13
++#define FXOS8700_PL_THS_REG         0x14
++#define FXOS8700_A_FFMT_CFG         0x15
++#define FXOS8700_A_FFMT_SRC         0x16
++#define FXOS8700_A_FFMT_THS         0x17
++#define FXOS8700_A_FFMT_COUNT       0x18
++#define FXOS8700_TRANSIENT_CFG      0x1d
++#define FXOS8700_TRANSIENT_SRC      0x1e
++#define FXOS8700_TRANSIENT_THS      0x1f
++#define FXOS8700_TRANSIENT_COUNT    0x20
++#define FXOS8700_PULSE_CFG          0x21
++#define FXOS8700_PULSE_SRC          0x22
++#define FXOS8700_PULSE_THSX         0x23
++#define FXOS8700_PULSE_THSY         0x24
++#define FXOS8700_PULSE_THSZ         0x25
++#define FXOS8700_PULSE_TMLT         0x26
++#define FXOS8700_PULSE_LTCY         0x27
++#define FXOS8700_PULSE_WIND         0x28
++#define FXOS8700_ASLP_COUNT         0x29
++#define FXOS8700_CTRL_REG1          0x2a
++#define FXOS8700_CTRL_REG2          0x2b
++#define FXOS8700_CTRL_REG3          0x2c
++#define FXOS8700_CTRL_REG4          0x2d
++#define FXOS8700_CTRL_REG5          0x2e
++#define FXOS8700_OFF_X              0x2f
++#define FXOS8700_OFF_Y              0x30
++#define FXOS8700_OFF_Z              0x31
++#define FXOS8700_M_DR_STATUS        0x32
++#define FXOS8700_M_OUT_X_MSB        0x33
++#define FXOS8700_M_OUT_X_LSB        0x34
++#define FXOS8700_M_OUT_Y_MSB        0x35
++#define FXOS8700_M_OUT_Y_LSB        0x36
++#define FXOS8700_M_OUT_Z_MSB        0x37
++#define FXOS8700_M_OUT_Z_LSB        0x38
++#define FXOS8700_CMP_X_MSB          0x39
++#define FXOS8700_CMP_X_LSB          0x3a
++#define FXOS8700_CMP_Y_MSB          0x3b
++#define FXOS8700_CMP_Y_LSB          0x3c
++#define FXOS8700_CMP_Z_MSB          0x3d
++#define FXOS8700_CMP_Z_LSB          0x3e
++#define FXOS8700_M_OFF_X_MSB        0x3f
++#define FXOS8700_M_OFF_X_LSB        0x40
++#define FXOS8700_M_OFF_Y_MSB        0x41
++#define FXOS8700_M_OFF_Y_LSB        0x42
++#define FXOS8700_M_OFF_Z_MSB        0x43
++#define FXOS8700_M_OFF_Z_LSB        0x44
++#define FXOS8700_MAX_X_MSB          0x45
++#define FXOS8700_MAX_X_LSB          0x46
++#define FXOS8700_MAX_Y_MSB          0x47
++#define FXOS8700_MAX_Y_LSB          0x48
++#define FXOS8700_MAX_Z_MSB          0x49
++#define FXOS8700_MAX_Z_LSB          0x4a
++#define FXOS8700_MIN_X_MSB          0x4b
++#define FXOS8700_MIN_X_LSB          0x4c
++#define FXOS8700_MIN_Y_MSB          0x4d
++#define FXOS8700_MIN_Y_LSB          0x4e
++#define FXOS8700_MIN_Z_MSB          0x4f
++#define FXOS8700_MIN_Z_LSB          0x50
++#define FXOS8700_TEMP               0x51
++#define FXOS8700_M_THS_CFG          0x52
++#define FXOS8700_M_THS_SRC          0x53
++#define FXOS8700_M_THS_X_MSB        0x54
++#define FXOS8700_M_THS_X_LSB        0x55
++#define FXOS8700_M_THS_Y_MSB        0x56
++#define FXOS8700_M_THS_Y_LSB        0x57
++#define FXOS8700_M_THS_Z_MSB        0x58
++#define FXOS8700_M_THS_Z_LSB        0x59
++#define FXOS8700_M_THS_COUNT        0x5a
++#define FXOS8700_M_CTRL_REG1        0x5b
++#define FXOS8700_M_CTRL_REG2        0x5c
++#define FXOS8700_M_CTRL_REG3        0x5d
++#define FXOS8700_M_INT_SRC          0x5e
++#define FXOS8700_A_VECM_CFG         0x5f
++#define FXOS8700_A_VECM_THS_MSB     0x60
++#define FXOS8700_A_VECM_THS_LSB     0x61
++#define FXOS8700_A_VECM_CNT         0x62
++#define FXOS8700_A_VECM_INITX_MSB   0x63
++#define FXOS8700_A_VECM_INITX_LSB   0x64
++#define FXOS8700_A_VECM_INITY_MSB   0x65
++#define FXOS8700_A_VECM_INITY_LSB   0x66
++#define FXOS8700_A_VECM_INITZ_MSB   0x67
++#define FXOS8700_A_VECM_INITZ_LSB   0x68
++#define FXOS8700_M_VECM_CFG         0x69
++#define FXOS8700_M_VECM_THS_MSB     0x6a
++#define FXOS8700_M_VECM_THS_LSB     0x6b
++#define FXOS8700_M_VECM_CNT         0x6c
++#define FXOS8700_M_VECM_INITX_MSB   0x6d
++#define FXOS8700_M_VECM_INITX_LSB   0x6e
++#define FXOS8700_M_VECM_INITY_MSB   0x6f
++#define FXOS8700_M_VECM_INITY_LSB   0x70
++#define FXOS8700_M_VECM_INITZ_MSB   0x71
++#define FXOS8700_M_VECM_INITZ_LSB   0x72
++#define FXOS8700_A_FFMT_THS_X_MSB   0x73
++#define FXOS8700_A_FFMT_THS_X_LSB   0x74
++#define FXOS8700_A_FFMT_THS_Y_MSB   0x75
++#define FXOS8700_A_FFMT_THS_Y_LSB   0x76
++#define FXOS8700_A_FFMT_THS_Z_MSB   0x77
++#define FXOS8700_A_FFMT_THS_Z_LSB   0x78
++#define FXOS8700_A_TRAN_INIT_MSB    0x79
++#define FXOS8700_A_TRAN_INIT_LSB_X  0x7a
++#define FXOS8700_A_TRAN_INIT_LSB_Y  0x7b
++#define FXOS8700_A_TRAN_INIT_LSB_Z  0x7d
++#define FXOS8700_TM_NVM_LOCK        0x7e
++#define FXOS8700_NVM_DATA0_35       0x80
++#define FXOS8700_NVM_DATA_BNK3      0xa4
++#define FXOS8700_NVM_DATA_BNK2      0xa5
++#define FXOS8700_NVM_DATA_BNK1      0xa6
++#define FXOS8700_NVM_DATA_BNK0      0xa7
++
++/* Bit definitions for FXOS8700_CTRL_REG1 */
++#define FXOS8700_CTRL_ODR_MSK       0x38
++#define FXOS8700_CTRL_ODR_MAX       0x00
++#define FXOS8700_CTRL_ODR_MIN       GENMASK(4, 3)
++
++/* Bit definitions for FXOS8700_M_CTRL_REG1 */
++#define FXOS8700_HMS_MASK           GENMASK(1, 0)
++#define FXOS8700_OS_MASK            GENMASK(4, 2)
++
++/* Bit definitions for FXOS8700_M_CTRL_REG2 */
++#define FXOS8700_MAXMIN_RST         BIT(2)
++#define FXOS8700_MAXMIN_DIS_THS     BIT(3)
++#define FXOS8700_MAXMIN_DIS         BIT(4)
++
++#define FXOS8700_ACTIVE             0x01
++#define FXOS8700_ACTIVE_MIN_USLEEP  4000 /* from table 6 in datasheet */
++
++#define FXOS8700_DEVICE_ID          0xC7
++#define FXOS8700_PRE_DEVICE_ID      0xC4
++#define FXOS8700_DATA_BUF_SIZE      3
++
++struct fxos8700_data {
++	struct regmap *regmap;
++	struct iio_trigger *trig;
++	__be16 buf[FXOS8700_DATA_BUF_SIZE] ____cacheline_aligned;
++};
++
++/* Regmap info */
++static const struct regmap_range read_range[] = {
++	{
++		.range_min = FXOS8700_STATUS,
++		.range_max = FXOS8700_A_FFMT_COUNT,
++	}, {
++		.range_min = FXOS8700_TRANSIENT_CFG,
++		.range_max = FXOS8700_A_FFMT_THS_Z_LSB,
++	},
++};
++
++static const struct regmap_range write_range[] = {
++	{
++		.range_min = FXOS8700_F_SETUP,
++		.range_max = FXOS8700_TRIG_CFG,
++	}, {
++		.range_min = FXOS8700_XYZ_DATA_CFG,
++		.range_max = FXOS8700_HP_FILTER_CUTOFF,
++	}, {
++		.range_min = FXOS8700_PL_CFG,
++		.range_max = FXOS8700_A_FFMT_CFG,
++	}, {
++		.range_min = FXOS8700_A_FFMT_THS,
++		.range_max = FXOS8700_TRANSIENT_CFG,
++	}, {
++		.range_min = FXOS8700_TRANSIENT_THS,
++		.range_max = FXOS8700_PULSE_CFG,
++	}, {
++		.range_min = FXOS8700_PULSE_THSX,
++		.range_max = FXOS8700_OFF_Z,
++	}, {
++		.range_min = FXOS8700_M_OFF_X_MSB,
++		.range_max = FXOS8700_M_OFF_Z_LSB,
++	}, {
++		.range_min = FXOS8700_M_THS_CFG,
++		.range_max = FXOS8700_M_THS_CFG,
++	}, {
++		.range_min = FXOS8700_M_THS_X_MSB,
++		.range_max = FXOS8700_M_CTRL_REG3,
++	}, {
++		.range_min = FXOS8700_A_VECM_CFG,
++		.range_max = FXOS8700_A_FFMT_THS_Z_LSB,
++	},
++};
++
++static const struct regmap_access_table driver_read_table = {
++	.yes_ranges =   read_range,
++	.n_yes_ranges = ARRAY_SIZE(read_range),
++};
++
++static const struct regmap_access_table driver_write_table = {
++	.yes_ranges =   write_range,
++	.n_yes_ranges = ARRAY_SIZE(write_range),
++};
++
++const struct regmap_config fxos8700_regmap_config = {
++	.reg_bits = 8,
++	.val_bits = 8,
++	.max_register = FXOS8700_NVM_DATA_BNK0,
++	.rd_table = &driver_read_table,
++	.wr_table = &driver_write_table,
++};
++EXPORT_SYMBOL(fxos8700_regmap_config);
++
++#define FXOS8700_CHANNEL(_type, _axis) {			\
++	.type = _type,						\
++	.modified = 1,						\
++	.channel2 = IIO_MOD_##_axis,				\
++	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
++	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |  \
++		BIT(IIO_CHAN_INFO_SAMP_FREQ),			\
++}
++
++enum fxos8700_accel_scale_bits {
++	MODE_2G = 0,
++	MODE_4G,
++	MODE_8G,
++};
++
++/* scan indexes follow DATA register order */
++enum fxos8700_scan_axis {
++	FXOS8700_SCAN_ACCEL_X = 0,
++	FXOS8700_SCAN_ACCEL_Y,
++	FXOS8700_SCAN_ACCEL_Z,
++	FXOS8700_SCAN_MAGN_X,
++	FXOS8700_SCAN_MAGN_Y,
++	FXOS8700_SCAN_MAGN_Z,
++	FXOS8700_SCAN_RHALL,
++	FXOS8700_SCAN_TIMESTAMP,
++};
++
++enum fxos8700_sensor {
++	FXOS8700_ACCEL	= 0,
++	FXOS8700_MAGN,
++	FXOS8700_NUM_SENSORS /* must be last */
++};
++
++enum fxos8700_int_pin {
++	FXOS8700_PIN_INT1,
++	FXOS8700_PIN_INT2
++};
++
++struct fxos8700_scale {
++	u8 bits;
++	int uscale;
++};
++
++struct fxos8700_odr {
++	u8 bits;
++	int odr;
++	int uodr;
++};
++
++static const struct fxos8700_scale fxos8700_accel_scale[] = {
++	{ MODE_2G, 244},
++	{ MODE_4G, 488},
++	{ MODE_8G, 976},
++};
++
++/*
++ * Accellerometer and magnetometer have the same ODR options, set in the
++ * CTRL_REG1 register. ODR is halved when using both sensors at once in
++ * hybrid mode.
++ */
++static const struct fxos8700_odr fxos8700_odr[] = {
++	{0x00, 800, 0},
++	{0x01, 400, 0},
++	{0x02, 200, 0},
++	{0x03, 100, 0},
++	{0x04, 50, 0},
++	{0x05, 12, 500000},
++	{0x06, 6, 250000},
++	{0x07, 1, 562500},
++};
++
++static const struct iio_chan_spec fxos8700_channels[] = {
++	FXOS8700_CHANNEL(IIO_ACCEL, X),
++	FXOS8700_CHANNEL(IIO_ACCEL, Y),
++	FXOS8700_CHANNEL(IIO_ACCEL, Z),
++	FXOS8700_CHANNEL(IIO_MAGN, X),
++	FXOS8700_CHANNEL(IIO_MAGN, Y),
++	FXOS8700_CHANNEL(IIO_MAGN, Z),
++	IIO_CHAN_SOFT_TIMESTAMP(FXOS8700_SCAN_TIMESTAMP),
++};
++
++static enum fxos8700_sensor fxos8700_to_sensor(enum iio_chan_type iio_type)
++{
++	switch (iio_type) {
++	case IIO_ACCEL:
++		return FXOS8700_ACCEL;
++	case IIO_ANGL_VEL:
++		return FXOS8700_MAGN;
++	default:
++		return -EINVAL;
++	}
++}
++
++static int fxos8700_set_active_mode(struct fxos8700_data *data,
++				    enum fxos8700_sensor t, bool mode)
++{
++	int ret;
++
++	ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, mode);
++	if (ret)
++		return ret;
++
++	usleep_range(FXOS8700_ACTIVE_MIN_USLEEP,
++		     FXOS8700_ACTIVE_MIN_USLEEP + 1000);
++
++	return 0;
++}
++
++static int fxos8700_set_scale(struct fxos8700_data *data,
++			      enum fxos8700_sensor t, int uscale)
++{
++	int i;
++	static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale);
++	struct device *dev = regmap_get_device(data->regmap);
++
++	if (t == FXOS8700_MAGN) {
++		dev_err(dev, "Magnetometer scale is locked at 1200uT\n");
++		return -EINVAL;
++	}
++
++	for (i = 0; i < scale_num; i++)
++		if (fxos8700_accel_scale[i].uscale == uscale)
++			break;
++
++	if (i == scale_num)
++		return -EINVAL;
++
++	return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG,
++			    fxos8700_accel_scale[i].bits);
++}
++
++static int fxos8700_get_scale(struct fxos8700_data *data,
++			      enum fxos8700_sensor t, int *uscale)
++{
++	int i, ret, val;
++	static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale);
++
++	if (t == FXOS8700_MAGN) {
++		*uscale = 1200; /* Magnetometer is locked at 1200uT */
++		return 0;
++	}
++
++	ret = regmap_read(data->regmap, FXOS8700_XYZ_DATA_CFG, &val);
++	if (ret)
++		return ret;
++
++	for (i = 0; i < scale_num; i++) {
++		if (fxos8700_accel_scale[i].bits == (val & 0x3)) {
++			*uscale = fxos8700_accel_scale[i].uscale;
++			return 0;
++		}
++	}
++
++	return -EINVAL;
++}
++
++static int fxos8700_get_data(struct fxos8700_data *data, int chan_type,
++			     int axis, int *val)
++{
++	u8 base, reg;
++	int ret;
++	enum fxos8700_sensor type = fxos8700_to_sensor(chan_type);
++
++	base = type ? FXOS8700_OUT_X_MSB : FXOS8700_M_OUT_X_MSB;
++
++	/* Block read 6 bytes of device output registers to avoid data loss */
++	ret = regmap_bulk_read(data->regmap, base, data->buf,
++			       FXOS8700_DATA_BUF_SIZE);
++	if (ret)
++		return ret;
++
++	/* Convert axis to buffer index */
++	reg = axis - IIO_MOD_X;
++
++	/* Convert to native endianness */
++	*val = sign_extend32(be16_to_cpu(data->buf[reg]), 15);
++
++	return 0;
++}
++
++static int fxos8700_set_odr(struct fxos8700_data *data, enum fxos8700_sensor t,
++			    int odr, int uodr)
++{
++	int i, ret, val;
++	bool active_mode;
++	static const int odr_num = ARRAY_SIZE(fxos8700_odr);
++
++	ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val);
++	if (ret)
++		return ret;
++
++	active_mode = val & FXOS8700_ACTIVE;
++
++	if (active_mode) {
++		/*
++		 * The device must be in standby mode to change any of the
++		 * other fields within CTRL_REG1
++		 */
++		ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1,
++				   val & ~FXOS8700_ACTIVE);
++		if (ret)
++			return ret;
++	}
++
++	for (i = 0; i < odr_num; i++)
++		if (fxos8700_odr[i].odr == odr && fxos8700_odr[i].uodr == uodr)
++			break;
++
++	if (i >= odr_num)
++		return -EINVAL;
++
++	return regmap_update_bits(data->regmap,
++				  FXOS8700_CTRL_REG1,
++				  FXOS8700_CTRL_ODR_MSK + FXOS8700_ACTIVE,
++				  fxos8700_odr[i].bits << 3 | active_mode);
++}
++
++static int fxos8700_get_odr(struct fxos8700_data *data, enum fxos8700_sensor t,
++			    int *odr, int *uodr)
++{
++	int i, val, ret;
++	static const int odr_num = ARRAY_SIZE(fxos8700_odr);
++
++	ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val);
++	if (ret)
++		return ret;
++
++	val &= FXOS8700_CTRL_ODR_MSK;
++
++	for (i = 0; i < odr_num; i++)
++		if (val == fxos8700_odr[i].bits)
++			break;
++
++	if (i >= odr_num)
++		return -EINVAL;
++
++	*odr = fxos8700_odr[i].odr;
++	*uodr = fxos8700_odr[i].uodr;
++
++	return 0;
++}
++
++static int fxos8700_read_raw(struct iio_dev *indio_dev,
++			     struct iio_chan_spec const *chan,
++			     int *val, int *val2, long mask)
++{
++	int ret;
++	struct fxos8700_data *data = iio_priv(indio_dev);
++
++	switch (mask) {
++	case IIO_CHAN_INFO_RAW:
++		ret = fxos8700_get_data(data, chan->type, chan->channel2, val);
++		if (ret)
++			return ret;
++		return IIO_VAL_INT;
++	case IIO_CHAN_INFO_SCALE:
++		*val = 0;
++		ret = fxos8700_get_scale(data, fxos8700_to_sensor(chan->type),
++					 val2);
++		return ret ? ret : IIO_VAL_INT_PLUS_MICRO;
++	case IIO_CHAN_INFO_SAMP_FREQ:
++		ret = fxos8700_get_odr(data, fxos8700_to_sensor(chan->type),
++				       val, val2);
++		return ret ? ret : IIO_VAL_INT_PLUS_MICRO;
++	default:
++		return -EINVAL;
++	}
++}
++
++static int fxos8700_write_raw(struct iio_dev *indio_dev,
++			      struct iio_chan_spec const *chan,
++			      int val, int val2, long mask)
++{
++	struct fxos8700_data *data = iio_priv(indio_dev);
++
++	switch (mask) {
++	case IIO_CHAN_INFO_SCALE:
++		return fxos8700_set_scale(data, fxos8700_to_sensor(chan->type),
++					  val2);
++	case IIO_CHAN_INFO_SAMP_FREQ:
++		return fxos8700_set_odr(data, fxos8700_to_sensor(chan->type),
++					val, val2);
++	default:
++		return -EINVAL;
++	}
++}
++
++static IIO_CONST_ATTR(in_accel_sampling_frequency_available,
++		      "1.5625 6.25 12.5 50 100 200 400 800");
++static IIO_CONST_ATTR(in_magn_sampling_frequency_available,
++		      "1.5625 6.25 12.5 50 100 200 400 800");
++static IIO_CONST_ATTR(in_accel_scale_available, "0.000244 0.000488 0.000976");
++static IIO_CONST_ATTR(in_magn_scale_available, "0.000001200");
++
++static struct attribute *fxos8700_attrs[] = {
++	&iio_const_attr_in_accel_sampling_frequency_available.dev_attr.attr,
++	&iio_const_attr_in_magn_sampling_frequency_available.dev_attr.attr,
++	&iio_const_attr_in_accel_scale_available.dev_attr.attr,
++	&iio_const_attr_in_magn_scale_available.dev_attr.attr,
++	NULL,
++};
++
++static const struct attribute_group fxos8700_attrs_group = {
++	.attrs = fxos8700_attrs,
++};
++
++static const struct iio_info fxos8700_info = {
++	.read_raw = fxos8700_read_raw,
++	.write_raw = fxos8700_write_raw,
++	.attrs = &fxos8700_attrs_group,
++};
++
++static int fxos8700_chip_init(struct fxos8700_data *data, bool use_spi)
++{
++	int ret;
++	unsigned int val;
++	struct device *dev = regmap_get_device(data->regmap);
++
++	ret = regmap_read(data->regmap, FXOS8700_WHO_AM_I, &val);
++	if (ret) {
++		dev_err(dev, "Error reading chip id\n");
++		return ret;
++	}
++	if (val != FXOS8700_DEVICE_ID && val != FXOS8700_PRE_DEVICE_ID) {
++		dev_err(dev, "Wrong chip id, got %x expected %x or %x\n",
++			val, FXOS8700_DEVICE_ID, FXOS8700_PRE_DEVICE_ID);
++		return -ENODEV;
++	}
++
++	ret = fxos8700_set_active_mode(data, FXOS8700_ACCEL, true);
++	if (ret)
++		return ret;
++
++	ret = fxos8700_set_active_mode(data, FXOS8700_MAGN, true);
++	if (ret)
++		return ret;
++
++	/*
++	 * The device must be in standby mode to change any of the other fields
++	 * within CTRL_REG1
++	 */
++	ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, 0x00);
++	if (ret)
++		return ret;
++
++	/* Set max oversample ratio (OSR) and both devices active */
++	ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG1,
++			   FXOS8700_HMS_MASK | FXOS8700_OS_MASK);
++	if (ret)
++		return ret;
++
++	/* Disable and rst min/max measurements & threshold */
++	ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG2,
++			   FXOS8700_MAXMIN_RST | FXOS8700_MAXMIN_DIS_THS |
++			   FXOS8700_MAXMIN_DIS);
++	if (ret)
++		return ret;
++
++	/* Max ODR (800Hz individual or 400Hz hybrid), active mode */
++	ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1,
++			   FXOS8700_CTRL_ODR_MAX | FXOS8700_ACTIVE);
++	if (ret)
++		return ret;
++
++	/* Set for max full-scale range (+/-8G) */
++	return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, MODE_8G);
++}
++
++static void fxos8700_chip_uninit(void *data)
++{
++	struct fxos8700_data *fxos8700_data = data;
++
++	fxos8700_set_active_mode(fxos8700_data, FXOS8700_ACCEL, false);
++	fxos8700_set_active_mode(fxos8700_data, FXOS8700_MAGN, false);
++}
++
++int fxos8700_core_probe(struct device *dev, struct regmap *regmap,
++			const char *name, bool use_spi)
++{
++	struct iio_dev *indio_dev;
++	struct fxos8700_data *data;
++	int ret;
++
++	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
++	if (!indio_dev)
++		return -ENOMEM;
++
++	data = iio_priv(indio_dev);
++	dev_set_drvdata(dev, indio_dev);
++	data->regmap = regmap;
++
++	ret = fxos8700_chip_init(data, use_spi);
++	if (ret)
++		return ret;
++
++	ret = devm_add_action_or_reset(dev, fxos8700_chip_uninit, data);
++	if (ret)
++		return ret;
++
++	indio_dev->dev.parent = dev;
++	indio_dev->channels = fxos8700_channels;
++	indio_dev->num_channels = ARRAY_SIZE(fxos8700_channels);
++	indio_dev->name = name ? name : "fxos8700";
++	indio_dev->modes = INDIO_DIRECT_MODE;
++	indio_dev->info = &fxos8700_info;
++
++	return devm_iio_device_register(dev, indio_dev);
++}
++EXPORT_SYMBOL_GPL(fxos8700_core_probe);
++
++MODULE_AUTHOR("Robert Jones <rjones@gateworks.com>");
++MODULE_DESCRIPTION("FXOS8700 6-Axis Acc and Mag Combo Sensor driver");
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/drivers/iio/imu/fxos8700_i2c.c
+@@ -0,0 +1,71 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * FXOS8700 - NXP IMU, I2C bits
++ *
++ * 7-bit I2C slave address determined by SA1 and SA0 logic level
++ * inputs represented in the following table:
++ *      SA1  |  SA0  |  Slave Address
++ *      0    |  0    |  0x1E
++ *      0    |  1    |  0x1D
++ *      1    |  0    |  0x1C
++ *      1    |  1    |  0x1F
++ */
++#include <linux/acpi.h>
++#include <linux/i2c.h>
++#include <linux/module.h>
++#include <linux/mod_devicetable.h>
++#include <linux/regmap.h>
++
++#include "fxos8700.h"
++
++static int fxos8700_i2c_probe(struct i2c_client *client,
++			      const struct i2c_device_id *id)
++{
++	struct regmap *regmap;
++	const char *name = NULL;
++
++	regmap = devm_regmap_init_i2c(client, &fxos8700_regmap_config);
++	if (IS_ERR(regmap)) {
++		dev_err(&client->dev, "Failed to register i2c regmap %d\n",
++			(int)PTR_ERR(regmap));
++		return PTR_ERR(regmap);
++	}
++
++	if (id)
++		name = id->name;
++
++	return fxos8700_core_probe(&client->dev, regmap, name, false);
++}
++
++static const struct i2c_device_id fxos8700_i2c_id[] = {
++	{"fxos8700", 0},
++	{ }
++};
++MODULE_DEVICE_TABLE(i2c, fxos8700_i2c_id);
++
++static const struct acpi_device_id fxos8700_acpi_match[] = {
++	{"FXOS8700", 0},
++	{ }
++};
++MODULE_DEVICE_TABLE(acpi, fxos8700_acpi_match);
++
++static const struct of_device_id fxos8700_of_match[] = {
++	{ .compatible = "nxp,fxos8700" },
++	{ }
++};
++MODULE_DEVICE_TABLE(of, fxos8700_of_match);
++
++static struct i2c_driver fxos8700_i2c_driver = {
++	.driver = {
++		.name                   = "fxos8700_i2c",
++		.acpi_match_table       = ACPI_PTR(fxos8700_acpi_match),
++		.of_match_table         = fxos8700_of_match,
++	},
++	.probe          = fxos8700_i2c_probe,
++	.id_table       = fxos8700_i2c_id,
++};
++module_i2c_driver(fxos8700_i2c_driver);
++
++MODULE_AUTHOR("Robert Jones <rjones@gateworks.com>");
++MODULE_DESCRIPTION("FXOS8700 I2C driver");
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/drivers/iio/imu/fxos8700_spi.c
+@@ -0,0 +1,59 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * FXOS8700 - NXP IMU, SPI bits
++ */
++#include <linux/acpi.h>
++#include <linux/module.h>
++#include <linux/mod_devicetable.h>
++#include <linux/regmap.h>
++#include <linux/spi/spi.h>
++
++#include "fxos8700.h"
++
++static int fxos8700_spi_probe(struct spi_device *spi)
++{
++	struct regmap *regmap;
++	const struct spi_device_id *id = spi_get_device_id(spi);
++
++	regmap = devm_regmap_init_spi(spi, &fxos8700_regmap_config);
++	if (IS_ERR(regmap)) {
++		dev_err(&spi->dev, "Failed to register spi regmap %d\n",
++			(int)PTR_ERR(regmap));
++		return PTR_ERR(regmap);
++	}
++
++	return fxos8700_core_probe(&spi->dev, regmap, id->name, true);
++}
++
++static const struct spi_device_id fxos8700_spi_id[] = {
++	{"fxos8700", 0},
++	{ }
++};
++MODULE_DEVICE_TABLE(spi, fxos8700_spi_id);
++
++static const struct acpi_device_id fxos8700_acpi_match[] = {
++	{"FXOS8700", 0},
++	{ }
++};
++MODULE_DEVICE_TABLE(acpi, fxos8700_acpi_match);
++
++static const struct of_device_id fxos8700_of_match[] = {
++	{ .compatible = "nxp,fxos8700" },
++	{ }
++};
++MODULE_DEVICE_TABLE(of, fxos8700_of_match);
++
++static struct spi_driver fxos8700_spi_driver = {
++	.probe          = fxos8700_spi_probe,
++	.id_table       = fxos8700_spi_id,
++	.driver = {
++		.acpi_match_table       = ACPI_PTR(fxos8700_acpi_match),
++		.of_match_table         = fxos8700_of_match,
++		.name                   = "fxos8700_spi",
++	},
++};
++module_spi_driver(fxos8700_spi_driver);
++
++MODULE_AUTHOR("Robert Jones <rjones@gateworks.com>");
++MODULE_DESCRIPTION("FXOS8700 SPI driver");
++MODULE_LICENSE("GPL v2");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/800-v5.5-scsi-core-Add-sysfs-attributes-for-VPD-pages-0h-and-.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/800-v5.5-scsi-core-Add-sysfs-attributes-for-VPD-pages-0h-and-.patch
new file mode 100644
index 0000000..2133280
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/800-v5.5-scsi-core-Add-sysfs-attributes-for-VPD-pages-0h-and-.patch
@@ -0,0 +1,122 @@
+From d188b0675b21d5a6ca27b3e741381813983f4719 Mon Sep 17 00:00:00 2001
+From: Ryan Attard <ryanattard@ryanattard.info>
+Date: Thu, 26 Sep 2019 11:22:17 -0500
+Subject: [PATCH] scsi: core: Add sysfs attributes for VPD pages 0h and 89h
+
+Add sysfs attributes for the ATA information page and Supported VPD Pages
+page.
+
+Link: https://lore.kernel.org/r/20190926162216.56591-1-ryanattard@ryanattard.info
+Signed-off-by: Ryan Attard <ryanattard@ryanattard.info>
+Reviewed-by: Bart Van Assche <bvanassche@acm.org>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+---
+ drivers/scsi/scsi.c        |  4 ++++
+ drivers/scsi/scsi_sysfs.c  | 19 +++++++++++++++++++
+ include/scsi/scsi_device.h |  2 ++
+ 3 files changed, 25 insertions(+)
+
+--- a/drivers/scsi/scsi.c
++++ b/drivers/scsi/scsi.c
+@@ -465,10 +465,14 @@ void scsi_attach_vpd(struct scsi_device
+ 		return;
+ 
+ 	for (i = 4; i < vpd_buf->len; i++) {
++		if (vpd_buf->data[i] == 0x0)
++			scsi_update_vpd_page(sdev, 0x0, &sdev->vpd_pg0);
+ 		if (vpd_buf->data[i] == 0x80)
+ 			scsi_update_vpd_page(sdev, 0x80, &sdev->vpd_pg80);
+ 		if (vpd_buf->data[i] == 0x83)
+ 			scsi_update_vpd_page(sdev, 0x83, &sdev->vpd_pg83);
++		if (vpd_buf->data[i] == 0x89)
++			scsi_update_vpd_page(sdev, 0x89, &sdev->vpd_pg89);
+ 	}
+ 	kfree(vpd_buf);
+ }
+--- a/drivers/scsi/scsi_sysfs.c
++++ b/drivers/scsi/scsi_sysfs.c
+@@ -437,6 +437,7 @@ static void scsi_device_dev_release_user
+ 	struct device *parent;
+ 	struct list_head *this, *tmp;
+ 	struct scsi_vpd *vpd_pg80 = NULL, *vpd_pg83 = NULL;
++	struct scsi_vpd *vpd_pg0 = NULL, *vpd_pg89 = NULL;
+ 	unsigned long flags;
+ 	struct module *mod;
+ 
+@@ -469,16 +470,24 @@ static void scsi_device_dev_release_user
+ 	sdev->request_queue = NULL;
+ 
+ 	mutex_lock(&sdev->inquiry_mutex);
++	rcu_swap_protected(sdev->vpd_pg0, vpd_pg0,
++			   lockdep_is_held(&sdev->inquiry_mutex));
+ 	rcu_swap_protected(sdev->vpd_pg80, vpd_pg80,
+ 			   lockdep_is_held(&sdev->inquiry_mutex));
+ 	rcu_swap_protected(sdev->vpd_pg83, vpd_pg83,
+ 			   lockdep_is_held(&sdev->inquiry_mutex));
++	rcu_swap_protected(sdev->vpd_pg89, vpd_pg89,
++			   lockdep_is_held(&sdev->inquiry_mutex));
+ 	mutex_unlock(&sdev->inquiry_mutex);
+ 
++	if (vpd_pg0)
++		kfree_rcu(vpd_pg0, rcu);
+ 	if (vpd_pg83)
+ 		kfree_rcu(vpd_pg83, rcu);
+ 	if (vpd_pg80)
+ 		kfree_rcu(vpd_pg80, rcu);
++	if (vpd_pg89)
++		kfree_rcu(vpd_pg89, rcu);
+ 	kfree(sdev->inquiry);
+ 	kfree(sdev);
+ 
+@@ -891,6 +900,8 @@ static struct bin_attribute dev_attr_vpd
+ 
+ sdev_vpd_pg_attr(pg83);
+ sdev_vpd_pg_attr(pg80);
++sdev_vpd_pg_attr(pg89);
++sdev_vpd_pg_attr(pg0);
+ 
+ static ssize_t show_inquiry(struct file *filep, struct kobject *kobj,
+ 			    struct bin_attribute *bin_attr,
+@@ -1223,12 +1234,18 @@ static umode_t scsi_sdev_bin_attr_is_vis
+ 	struct scsi_device *sdev = to_scsi_device(dev);
+ 
+ 
++	if (attr == &dev_attr_vpd_pg0 && !sdev->vpd_pg0)
++		return 0;
++
+ 	if (attr == &dev_attr_vpd_pg80 && !sdev->vpd_pg80)
+ 		return 0;
+ 
+ 	if (attr == &dev_attr_vpd_pg83 && !sdev->vpd_pg83)
+ 		return 0;
+ 
++	if (attr == &dev_attr_vpd_pg89 && !sdev->vpd_pg89)
++		return 0;
++
+ 	return S_IRUGO;
+ }
+ 
+@@ -1271,8 +1288,10 @@ static struct attribute *scsi_sdev_attrs
+ };
+ 
+ static struct bin_attribute *scsi_sdev_bin_attrs[] = {
++	&dev_attr_vpd_pg0,
+ 	&dev_attr_vpd_pg83,
+ 	&dev_attr_vpd_pg80,
++	&dev_attr_vpd_pg89,
+ 	&dev_attr_inquiry,
+ 	NULL
+ };
+--- a/include/scsi/scsi_device.h
++++ b/include/scsi/scsi_device.h
+@@ -140,8 +140,10 @@ struct scsi_device {
+ 	const char * rev;		/* ... "nullnullnullnull" before scan */
+ 
+ #define SCSI_VPD_PG_LEN                255
++	struct scsi_vpd __rcu *vpd_pg0;
+ 	struct scsi_vpd __rcu *vpd_pg83;
+ 	struct scsi_vpd __rcu *vpd_pg80;
++	struct scsi_vpd __rcu *vpd_pg89;
+ 	unsigned char current_tag;	/* current tag */
+ 	struct scsi_target      *sdev_target;   /* used only for single_lun */
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/801-v5.5-hwmon-Driver-for-disk-and-solid-state-drives-with-te.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/801-v5.5-hwmon-Driver-for-disk-and-solid-state-drives-with-te.patch
new file mode 100644
index 0000000..32a6297
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/801-v5.5-hwmon-Driver-for-disk-and-solid-state-drives-with-te.patch
@@ -0,0 +1,737 @@
+From 5b46903d8bf372e563bf2150d46b87fff197a109 Mon Sep 17 00:00:00 2001
+From: Guenter Roeck <linux@roeck-us.net>
+Date: Thu, 28 Nov 2019 21:34:40 -0800
+Subject: [PATCH] hwmon: Driver for disk and solid state drives with
+ temperature sensors
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reading the temperature of ATA drives has been supported for years
+by userspace tools such as smarttools or hddtemp. The downside of
+such tools is that they need to run with super-user privilege, that
+the temperatures are not reported by standard tools such as 'sensors'
+or 'libsensors', and that drive temperatures are not available for use
+in the kernel's thermal subsystem.
+
+This driver solves this problem by adding support for reading the
+temperature of ATA drives from the kernel using the hwmon API and
+by adding a temperature zone for each drive.
+
+With this driver, the hard disk temperature can be read using the
+unprivileged 'sensors' application:
+
+$ sensors drivetemp-scsi-1-0
+drivetemp-scsi-1-0
+Adapter: SCSI adapter
+temp1:        +23.0°C
+
+or directly from sysfs:
+
+$ grep . /sys/class/hwmon/hwmon9/{name,temp1_input}
+/sys/class/hwmon/hwmon9/name:drivetemp
+/sys/class/hwmon/hwmon9/temp1_input:23000
+
+If the drive supports SCT transport and reports temperature limits,
+those are reported as well.
+
+drivetemp-scsi-0-0
+Adapter: SCSI adapter
+temp1:        +27.0°C  (low  =  +0.0°C, high = +60.0°C)
+                       (crit low = -41.0°C, crit = +85.0°C)
+                       (lowest = +23.0°C, highest = +34.0°C)
+
+The driver attempts to use SCT Command Transport to read the drive
+temperature. If the SCT Command Transport feature set is not available,
+or if it does not report the drive temperature, drive temperatures may
+be readable through SMART attributes. Since SMART attributes are not well
+defined, this method is only used as fallback mechanism.
+
+Cc: Chris Healy <cphealy@gmail.com>
+Cc: Linus Walleij <linus.walleij@linaro.org>
+Cc: Martin K. Petersen <martin.petersen@oracle.com>
+Cc: Bart Van Assche <bvanassche@acm.org>
+Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
+Tested-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+---
+ Documentation/hwmon/drivetemp.rst |  52 +++
+ Documentation/hwmon/index.rst     |   1 +
+ drivers/hwmon/Kconfig             |  10 +
+ drivers/hwmon/Makefile            |   1 +
+ drivers/hwmon/drivetemp.c         | 574 ++++++++++++++++++++++++++++++
+ 5 files changed, 638 insertions(+)
+ create mode 100644 Documentation/hwmon/drivetemp.rst
+ create mode 100644 drivers/hwmon/drivetemp.c
+
+--- /dev/null
++++ b/Documentation/hwmon/drivetemp.rst
+@@ -0,0 +1,52 @@
++.. SPDX-License-Identifier: GPL-2.0
++
++Kernel driver drivetemp
++=======================
++
++
++References
++----------
++
++ANS T13/1699-D
++Information technology - AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS)
++
++ANS Project T10/BSR INCITS 513
++Information technology - SCSI Primary Commands - 4 (SPC-4)
++
++ANS Project INCITS 557
++Information technology - SCSI / ATA Translation - 5 (SAT-5)
++
++
++Description
++-----------
++
++This driver supports reporting the temperature of disk and solid state
++drives with temperature sensors.
++
++If supported, it uses the ATA SCT Command Transport feature to read
++the current drive temperature and, if available, temperature limits
++as well as historic minimum and maximum temperatures. If SCT Command
++Transport is not supported, the driver uses SMART attributes to read
++the drive temperature.
++
++
++Sysfs entries
++-------------
++
++Only the temp1_input attribute is always available. Other attributes are
++available only if reported by the drive. All temperatures are reported in
++milli-degrees Celsius.
++
++=======================	=====================================================
++temp1_input		Current drive temperature
++temp1_lcrit		Minimum temperature limit. Operating the device below
++			this temperature may cause physical damage to the
++			device.
++temp1_min		Minimum recommended continuous operating limit
++temp1_max		Maximum recommended continuous operating temperature
++temp1_crit		Maximum temperature limit. Operating the device above
++			this temperature may cause physical damage to the
++			device.
++temp1_lowest		Minimum temperature seen this power cycle
++temp1_highest		Maximum temperature seen this power cycle
++=======================	=====================================================
+--- a/Documentation/hwmon/index.rst
++++ b/Documentation/hwmon/index.rst
+@@ -45,6 +45,7 @@ Hardware Monitoring Kernel Drivers
+    da9052
+    da9055
+    dme1737
++   drivetemp
+    ds1621
+    ds620
+    emc1403
+--- a/drivers/hwmon/Kconfig
++++ b/drivers/hwmon/Kconfig
+@@ -385,6 +385,16 @@ config SENSORS_ATXP1
+ 	  This driver can also be built as a module. If so, the module
+ 	  will be called atxp1.
+ 
++config SENSORS_DRIVETEMP
++	tristate "Hard disk drives with temperature sensors"
++	depends on SCSI && ATA
++	help
++	  If you say yes you get support for the temperature sensor on
++	  hard disk drives.
++
++	  This driver can also be built as a module. If so, the module
++	  will be called satatemp.
++
+ config SENSORS_DS620
+ 	tristate "Dallas Semiconductor DS620"
+ 	depends on I2C
+--- a/drivers/hwmon/Makefile
++++ b/drivers/hwmon/Makefile
+@@ -56,6 +56,7 @@ obj-$(CONFIG_SENSORS_DA9052_ADC)+= da905
+ obj-$(CONFIG_SENSORS_DA9055)+= da9055-hwmon.o
+ obj-$(CONFIG_SENSORS_DELL_SMM)	+= dell-smm-hwmon.o
+ obj-$(CONFIG_SENSORS_DME1737)	+= dme1737.o
++obj-$(CONFIG_SENSORS_DRIVETEMP)	+= drivetemp.o
+ obj-$(CONFIG_SENSORS_DS620)	+= ds620.o
+ obj-$(CONFIG_SENSORS_DS1621)	+= ds1621.o
+ obj-$(CONFIG_SENSORS_EMC1403)	+= emc1403.o
+--- /dev/null
++++ b/drivers/hwmon/drivetemp.c
+@@ -0,0 +1,574 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Hwmon client for disk and solid state drives with temperature sensors
++ * Copyright (C) 2019 Zodiac Inflight Innovations
++ *
++ * With input from:
++ *    Hwmon client for S.M.A.R.T. hard disk drives with temperature sensors.
++ *    (C) 2018 Linus Walleij
++ *
++ *    hwmon: Driver for SCSI/ATA temperature sensors
++ *    by Constantin Baranov <const@mimas.ru>, submitted September 2009
++ *
++ * This drive supports reporting the temperatire of SATA drives. It can be
++ * easily extended to report the temperature of SCSI drives.
++ *
++ * The primary means to read drive temperatures and temperature limits
++ * for ATA drives is the SCT Command Transport feature set as specified in
++ * ATA8-ACS.
++ * It can be used to read the current drive temperature, temperature limits,
++ * and historic minimum and maximum temperatures. The SCT Command Transport
++ * feature set is documented in "AT Attachment 8 - ATA/ATAPI Command Set
++ * (ATA8-ACS)".
++ *
++ * If the SCT Command Transport feature set is not available, drive temperatures
++ * may be readable through SMART attributes. Since SMART attributes are not well
++ * defined, this method is only used as fallback mechanism.
++ *
++ * There are three SMART attributes which may report drive temperatures.
++ * Those are defined as follows (from
++ * http://www.cropel.com/library/smart-attribute-list.aspx).
++ *
++ * 190	Temperature	Temperature, monitored by a sensor somewhere inside
++ *			the drive. Raw value typicaly holds the actual
++ *			temperature (hexadecimal) in its rightmost two digits.
++ *
++ * 194	Temperature	Temperature, monitored by a sensor somewhere inside
++ *			the drive. Raw value typicaly holds the actual
++ *			temperature (hexadecimal) in its rightmost two digits.
++ *
++ * 231	Temperature	Temperature, monitored by a sensor somewhere inside
++ *			the drive. Raw value typicaly holds the actual
++ *			temperature (hexadecimal) in its rightmost two digits.
++ *
++ * Wikipedia defines attributes a bit differently.
++ *
++ * 190	Temperature	Value is equal to (100-temp. °C), allowing manufacturer
++ *	Difference or	to set a minimum threshold which corresponds to a
++ *	Airflow		maximum temperature. This also follows the convention of
++ *	Temperature	100 being a best-case value and lower values being
++ *			undesirable. However, some older drives may instead
++ *			report raw Temperature (identical to 0xC2) or
++ *			Temperature minus 50 here.
++ * 194	Temperature or	Indicates the device temperature, if the appropriate
++ *	Temperature	sensor is fitted. Lowest byte of the raw value contains
++ *	Celsius		the exact temperature value (Celsius degrees).
++ * 231	Life Left	Indicates the approximate SSD life left, in terms of
++ *	(SSDs) or	program/erase cycles or available reserved blocks.
++ *	Temperature	A normalized value of 100 represents a new drive, with
++ *			a threshold value at 10 indicating a need for
++ *			replacement. A value of 0 may mean that the drive is
++ *			operating in read-only mode to allow data recovery.
++ *			Previously (pre-2010) occasionally used for Drive
++ *			Temperature (more typically reported at 0xC2).
++ *
++ * Common denominator is that the first raw byte reports the temperature
++ * in degrees C on almost all drives. Some drives may report a fractional
++ * temperature in the second raw byte.
++ *
++ * Known exceptions (from libatasmart):
++ * - SAMSUNG SV0412H and SAMSUNG SV1204H) report the temperature in 10th
++ *   degrees C in the first two raw bytes.
++ * - A few Maxtor drives report an unknown or bad value in attribute 194.
++ * - Certain Apple SSD drives report an unknown value in attribute 190.
++ *   Only certain firmware versions are affected.
++ *
++ * Those exceptions affect older ATA drives and are currently ignored.
++ * Also, the second raw byte (possibly reporting the fractional temperature)
++ * is currently ignored.
++ *
++ * Many drives also report temperature limits in additional SMART data raw
++ * bytes. The format of those is not well defined and varies widely.
++ * The driver does not currently attempt to report those limits.
++ *
++ * According to data in smartmontools, attribute 231 is rarely used to report
++ * drive temperatures. At the same time, several drives report SSD life left
++ * in attribute 231, but do not support temperature sensors. For this reason,
++ * attribute 231 is currently ignored.
++ *
++ * Following above definitions, temperatures are reported as follows.
++ *   If SCT Command Transport is supported, it is used to read the
++ *   temperature and, if available, temperature limits.
++ * - Otherwise, if SMART attribute 194 is supported, it is used to read
++ *   the temperature.
++ * - Otherwise, if SMART attribute 190 is supported, it is used to read
++ *   the temperature.
++ */
++
++#include <linux/ata.h>
++#include <linux/bits.h>
++#include <linux/device.h>
++#include <linux/hwmon.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <scsi/scsi_cmnd.h>
++#include <scsi/scsi_device.h>
++#include <scsi/scsi_driver.h>
++#include <scsi/scsi_proto.h>
++
++struct drivetemp_data {
++	struct list_head list;		/* list of instantiated devices */
++	struct mutex lock;		/* protect data buffer accesses */
++	struct scsi_device *sdev;	/* SCSI device */
++	struct device *dev;		/* instantiating device */
++	struct device *hwdev;		/* hardware monitoring device */
++	u8 smartdata[ATA_SECT_SIZE];	/* local buffer */
++	int (*get_temp)(struct drivetemp_data *st, u32 attr, long *val);
++	bool have_temp_lowest;		/* lowest temp in SCT status */
++	bool have_temp_highest;		/* highest temp in SCT status */
++	bool have_temp_min;		/* have min temp */
++	bool have_temp_max;		/* have max temp */
++	bool have_temp_lcrit;		/* have lower critical limit */
++	bool have_temp_crit;		/* have critical limit */
++	int temp_min;			/* min temp */
++	int temp_max;			/* max temp */
++	int temp_lcrit;			/* lower critical limit */
++	int temp_crit;			/* critical limit */
++};
++
++static LIST_HEAD(drivetemp_devlist);
++
++#define ATA_MAX_SMART_ATTRS	30
++#define SMART_TEMP_PROP_190	190
++#define SMART_TEMP_PROP_194	194
++
++#define SCT_STATUS_REQ_ADDR	0xe0
++#define  SCT_STATUS_VERSION_LOW		0	/* log byte offsets */
++#define  SCT_STATUS_VERSION_HIGH	1
++#define  SCT_STATUS_TEMP		200
++#define  SCT_STATUS_TEMP_LOWEST		201
++#define  SCT_STATUS_TEMP_HIGHEST	202
++#define SCT_READ_LOG_ADDR	0xe1
++#define  SMART_READ_LOG			0xd5
++#define  SMART_WRITE_LOG		0xd6
++
++#define INVALID_TEMP		0x80
++
++#define temp_is_valid(temp)	((temp) != INVALID_TEMP)
++#define temp_from_sct(temp)	(((s8)(temp)) * 1000)
++
++static inline bool ata_id_smart_supported(u16 *id)
++{
++	return id[ATA_ID_COMMAND_SET_1] & BIT(0);
++}
++
++static inline bool ata_id_smart_enabled(u16 *id)
++{
++	return id[ATA_ID_CFS_ENABLE_1] & BIT(0);
++}
++
++static int drivetemp_scsi_command(struct drivetemp_data *st,
++				 u8 ata_command, u8 feature,
++				 u8 lba_low, u8 lba_mid, u8 lba_high)
++{
++	u8 scsi_cmd[MAX_COMMAND_SIZE];
++	int data_dir;
++
++	memset(scsi_cmd, 0, sizeof(scsi_cmd));
++	scsi_cmd[0] = ATA_16;
++	if (ata_command == ATA_CMD_SMART && feature == SMART_WRITE_LOG) {
++		scsi_cmd[1] = (5 << 1);	/* PIO Data-out */
++		/*
++		 * No off.line or cc, write to dev, block count in sector count
++		 * field.
++		 */
++		scsi_cmd[2] = 0x06;
++		data_dir = DMA_TO_DEVICE;
++	} else {
++		scsi_cmd[1] = (4 << 1);	/* PIO Data-in */
++		/*
++		 * No off.line or cc, read from dev, block count in sector count
++		 * field.
++		 */
++		scsi_cmd[2] = 0x0e;
++		data_dir = DMA_FROM_DEVICE;
++	}
++	scsi_cmd[4] = feature;
++	scsi_cmd[6] = 1;	/* 1 sector */
++	scsi_cmd[8] = lba_low;
++	scsi_cmd[10] = lba_mid;
++	scsi_cmd[12] = lba_high;
++	scsi_cmd[14] = ata_command;
++
++	return scsi_execute_req(st->sdev, scsi_cmd, data_dir,
++				st->smartdata, ATA_SECT_SIZE, NULL, HZ, 5,
++				NULL);
++}
++
++static int drivetemp_ata_command(struct drivetemp_data *st, u8 feature,
++				 u8 select)
++{
++	return drivetemp_scsi_command(st, ATA_CMD_SMART, feature, select,
++				     ATA_SMART_LBAM_PASS, ATA_SMART_LBAH_PASS);
++}
++
++static int drivetemp_get_smarttemp(struct drivetemp_data *st, u32 attr,
++				  long *temp)
++{
++	u8 *buf = st->smartdata;
++	bool have_temp = false;
++	u8 temp_raw;
++	u8 csum;
++	int err;
++	int i;
++
++	err = drivetemp_ata_command(st, ATA_SMART_READ_VALUES, 0);
++	if (err)
++		return err;
++
++	/* Checksum the read value table */
++	csum = 0;
++	for (i = 0; i < ATA_SECT_SIZE; i++)
++		csum += buf[i];
++	if (csum) {
++		dev_dbg(&st->sdev->sdev_gendev,
++			"checksum error reading SMART values\n");
++		return -EIO;
++	}
++
++	for (i = 0; i < ATA_MAX_SMART_ATTRS; i++) {
++		u8 *attr = buf + i * 12;
++		int id = attr[2];
++
++		if (!id)
++			continue;
++
++		if (id == SMART_TEMP_PROP_190) {
++			temp_raw = attr[7];
++			have_temp = true;
++		}
++		if (id == SMART_TEMP_PROP_194) {
++			temp_raw = attr[7];
++			have_temp = true;
++			break;
++		}
++	}
++
++	if (have_temp) {
++		*temp = temp_raw * 1000;
++		return 0;
++	}
++
++	return -ENXIO;
++}
++
++static int drivetemp_get_scttemp(struct drivetemp_data *st, u32 attr, long *val)
++{
++	u8 *buf = st->smartdata;
++	int err;
++
++	err = drivetemp_ata_command(st, SMART_READ_LOG, SCT_STATUS_REQ_ADDR);
++	if (err)
++		return err;
++	switch (attr) {
++	case hwmon_temp_input:
++		*val = temp_from_sct(buf[SCT_STATUS_TEMP]);
++		break;
++	case hwmon_temp_lowest:
++		*val = temp_from_sct(buf[SCT_STATUS_TEMP_LOWEST]);
++		break;
++	case hwmon_temp_highest:
++		*val = temp_from_sct(buf[SCT_STATUS_TEMP_HIGHEST]);
++		break;
++	default:
++		err = -EINVAL;
++		break;
++	}
++	return err;
++}
++
++static int drivetemp_identify_sata(struct drivetemp_data *st)
++{
++	struct scsi_device *sdev = st->sdev;
++	u8 *buf = st->smartdata;
++	struct scsi_vpd *vpd;
++	bool is_ata, is_sata;
++	bool have_sct_data_table;
++	bool have_sct_temp;
++	bool have_smart;
++	bool have_sct;
++	u16 *ata_id;
++	u16 version;
++	long temp;
++	int err;
++
++	/* SCSI-ATA Translation present? */
++	rcu_read_lock();
++	vpd = rcu_dereference(sdev->vpd_pg89);
++
++	/*
++	 * Verify that ATA IDENTIFY DEVICE data is included in ATA Information
++	 * VPD and that the drive implements the SATA protocol.
++	 */
++	if (!vpd || vpd->len < 572 || vpd->data[56] != ATA_CMD_ID_ATA ||
++	    vpd->data[36] != 0x34) {
++		rcu_read_unlock();
++		return -ENODEV;
++	}
++	ata_id = (u16 *)&vpd->data[60];
++	is_ata = ata_id_is_ata(ata_id);
++	is_sata = ata_id_is_sata(ata_id);
++	have_sct = ata_id_sct_supported(ata_id);
++	have_sct_data_table = ata_id_sct_data_tables(ata_id);
++	have_smart = ata_id_smart_supported(ata_id) &&
++				ata_id_smart_enabled(ata_id);
++
++	rcu_read_unlock();
++
++	/* bail out if this is not a SATA device */
++	if (!is_ata || !is_sata)
++		return -ENODEV;
++	if (!have_sct)
++		goto skip_sct;
++
++	err = drivetemp_ata_command(st, SMART_READ_LOG, SCT_STATUS_REQ_ADDR);
++	if (err)
++		goto skip_sct;
++
++	version = (buf[SCT_STATUS_VERSION_HIGH] << 8) |
++		  buf[SCT_STATUS_VERSION_LOW];
++	if (version != 2 && version != 3)
++		goto skip_sct;
++
++	have_sct_temp = temp_is_valid(buf[SCT_STATUS_TEMP]);
++	if (!have_sct_temp)
++		goto skip_sct;
++
++	st->have_temp_lowest = temp_is_valid(buf[SCT_STATUS_TEMP_LOWEST]);
++	st->have_temp_highest = temp_is_valid(buf[SCT_STATUS_TEMP_HIGHEST]);
++
++	if (!have_sct_data_table)
++		goto skip_sct;
++
++	/* Request and read temperature history table */
++	memset(buf, '\0', sizeof(st->smartdata));
++	buf[0] = 5;	/* data table command */
++	buf[2] = 1;	/* read table */
++	buf[4] = 2;	/* temperature history table */
++
++	err = drivetemp_ata_command(st, SMART_WRITE_LOG, SCT_STATUS_REQ_ADDR);
++	if (err)
++		goto skip_sct_data;
++
++	err = drivetemp_ata_command(st, SMART_READ_LOG, SCT_READ_LOG_ADDR);
++	if (err)
++		goto skip_sct_data;
++
++	/*
++	 * Temperature limits per AT Attachment 8 -
++	 * ATA/ATAPI Command Set (ATA8-ACS)
++	 */
++	st->have_temp_max = temp_is_valid(buf[6]);
++	st->have_temp_crit = temp_is_valid(buf[7]);
++	st->have_temp_min = temp_is_valid(buf[8]);
++	st->have_temp_lcrit = temp_is_valid(buf[9]);
++
++	st->temp_max = temp_from_sct(buf[6]);
++	st->temp_crit = temp_from_sct(buf[7]);
++	st->temp_min = temp_from_sct(buf[8]);
++	st->temp_lcrit = temp_from_sct(buf[9]);
++
++skip_sct_data:
++	if (have_sct_temp) {
++		st->get_temp = drivetemp_get_scttemp;
++		return 0;
++	}
++skip_sct:
++	if (!have_smart)
++		return -ENODEV;
++	st->get_temp = drivetemp_get_smarttemp;
++	return drivetemp_get_smarttemp(st, hwmon_temp_input, &temp);
++}
++
++static int drivetemp_identify(struct drivetemp_data *st)
++{
++	struct scsi_device *sdev = st->sdev;
++
++	/* Bail out immediately if there is no inquiry data */
++	if (!sdev->inquiry || sdev->inquiry_len < 16)
++		return -ENODEV;
++
++	/* Disk device? */
++	if (sdev->type != TYPE_DISK && sdev->type != TYPE_ZBC)
++		return -ENODEV;
++
++	return drivetemp_identify_sata(st);
++}
++
++static int drivetemp_read(struct device *dev, enum hwmon_sensor_types type,
++			 u32 attr, int channel, long *val)
++{
++	struct drivetemp_data *st = dev_get_drvdata(dev);
++	int err = 0;
++
++	if (type != hwmon_temp)
++		return -EINVAL;
++
++	switch (attr) {
++	case hwmon_temp_input:
++	case hwmon_temp_lowest:
++	case hwmon_temp_highest:
++		mutex_lock(&st->lock);
++		err = st->get_temp(st, attr, val);
++		mutex_unlock(&st->lock);
++		break;
++	case hwmon_temp_lcrit:
++		*val = st->temp_lcrit;
++		break;
++	case hwmon_temp_min:
++		*val = st->temp_min;
++		break;
++	case hwmon_temp_max:
++		*val = st->temp_max;
++		break;
++	case hwmon_temp_crit:
++		*val = st->temp_crit;
++		break;
++	default:
++		err = -EINVAL;
++		break;
++	}
++	return err;
++}
++
++static umode_t drivetemp_is_visible(const void *data,
++				   enum hwmon_sensor_types type,
++				   u32 attr, int channel)
++{
++	const struct drivetemp_data *st = data;
++
++	switch (type) {
++	case hwmon_temp:
++		switch (attr) {
++		case hwmon_temp_input:
++			return 0444;
++		case hwmon_temp_lowest:
++			if (st->have_temp_lowest)
++				return 0444;
++			break;
++		case hwmon_temp_highest:
++			if (st->have_temp_highest)
++				return 0444;
++			break;
++		case hwmon_temp_min:
++			if (st->have_temp_min)
++				return 0444;
++			break;
++		case hwmon_temp_max:
++			if (st->have_temp_max)
++				return 0444;
++			break;
++		case hwmon_temp_lcrit:
++			if (st->have_temp_lcrit)
++				return 0444;
++			break;
++		case hwmon_temp_crit:
++			if (st->have_temp_crit)
++				return 0444;
++			break;
++		default:
++			break;
++		}
++		break;
++	default:
++		break;
++	}
++	return 0;
++}
++
++static const struct hwmon_channel_info *drivetemp_info[] = {
++	HWMON_CHANNEL_INFO(chip,
++			   HWMON_C_REGISTER_TZ),
++	HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT |
++			   HWMON_T_LOWEST | HWMON_T_HIGHEST |
++			   HWMON_T_MIN | HWMON_T_MAX |
++			   HWMON_T_LCRIT | HWMON_T_CRIT),
++	NULL
++};
++
++static const struct hwmon_ops drivetemp_ops = {
++	.is_visible = drivetemp_is_visible,
++	.read = drivetemp_read,
++};
++
++static const struct hwmon_chip_info drivetemp_chip_info = {
++	.ops = &drivetemp_ops,
++	.info = drivetemp_info,
++};
++
++/*
++ * The device argument points to sdev->sdev_dev. Its parent is
++ * sdev->sdev_gendev, which we can use to get the scsi_device pointer.
++ */
++static int drivetemp_add(struct device *dev, struct class_interface *intf)
++{
++	struct scsi_device *sdev = to_scsi_device(dev->parent);
++	struct drivetemp_data *st;
++	int err;
++
++	st = kzalloc(sizeof(*st), GFP_KERNEL);
++	if (!st)
++		return -ENOMEM;
++
++	st->sdev = sdev;
++	st->dev = dev;
++	mutex_init(&st->lock);
++
++	if (drivetemp_identify(st)) {
++		err = -ENODEV;
++		goto abort;
++	}
++
++	st->hwdev = hwmon_device_register_with_info(dev->parent, "drivetemp",
++						    st, &drivetemp_chip_info,
++						    NULL);
++	if (IS_ERR(st->hwdev)) {
++		err = PTR_ERR(st->hwdev);
++		goto abort;
++	}
++
++	list_add(&st->list, &drivetemp_devlist);
++	return 0;
++
++abort:
++	kfree(st);
++	return err;
++}
++
++static void drivetemp_remove(struct device *dev, struct class_interface *intf)
++{
++	struct drivetemp_data *st, *tmp;
++
++	list_for_each_entry_safe(st, tmp, &drivetemp_devlist, list) {
++		if (st->dev == dev) {
++			list_del(&st->list);
++			hwmon_device_unregister(st->hwdev);
++			kfree(st);
++			break;
++		}
++	}
++}
++
++static struct class_interface drivetemp_interface = {
++	.add_dev = drivetemp_add,
++	.remove_dev = drivetemp_remove,
++};
++
++static int __init drivetemp_init(void)
++{
++	return scsi_register_interface(&drivetemp_interface);
++}
++
++static void __exit drivetemp_exit(void)
++{
++	scsi_unregister_interface(&drivetemp_interface);
++}
++
++module_init(drivetemp_init);
++module_exit(drivetemp_exit);
++
++MODULE_AUTHOR("Guenter Roeck <linus@roeck-us.net>");
++MODULE_DESCRIPTION("Hard drive temperature monitor");
++MODULE_LICENSE("GPL");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/801-v5.6-leds-populate-the-device-s-of_node.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/801-v5.6-leds-populate-the-device-s-of_node.patch
new file mode 100644
index 0000000..5c3b58c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/801-v5.6-leds-populate-the-device-s-of_node.patch
@@ -0,0 +1,36 @@
+From 7a349e8c535d7327bf80710323c725df47149b8d Mon Sep 17 00:00:00 2001
+From: Jean-Jacques Hiblot <jjhiblot@ti.com>
+Date: Sun, 5 Jan 2020 23:31:14 +0100
+Subject: [PATCH] leds: populate the device's of_node
+
+If initialization data is available and its fwnode is actually a
+of_node, store this information in the led device's structure. This
+will allow the device to use or provide OF-based API such (devm_xxx).
+
+Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
+Signed-off-by: Pavel Machek <pavel@ucw.cz>
+[backport to 5.4]
+---
+
+--- a/drivers/leds/led-class.c
++++ b/drivers/leds/led-class.c
+@@ -19,6 +19,7 @@
+ #include <linux/spinlock.h>
+ #include <linux/timer.h>
+ #include <uapi/linux/uleds.h>
++#include <linux/of.h>
+ #include "leds.h"
+ 
+ static struct class *leds_class;
+@@ -277,8 +278,10 @@ int led_classdev_register_ext(struct dev
+ 		mutex_unlock(&led_cdev->led_access);
+ 		return PTR_ERR(led_cdev->dev);
+ 	}
+-	if (init_data && init_data->fwnode)
++	if (init_data && init_data->fwnode) {
+ 		led_cdev->dev->fwnode = init_data->fwnode;
++		led_cdev->dev->of_node = to_of_node(init_data->fwnode);
++	}
+ 
+ 	if (ret)
+ 		dev_warn(parent, "Led %s renamed to %s due to name collision",
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/803-v5.8-i2c-pxa-use-official-address-byte-helper.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/803-v5.8-i2c-pxa-use-official-address-byte-helper.patch
new file mode 100644
index 0000000..a937b52
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/803-v5.8-i2c-pxa-use-official-address-byte-helper.patch
@@ -0,0 +1,59 @@
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Bcc: linux@mail.armlinux.org.uk
+Cc: linux-i2c@vger.kernel.org
+Subject: [PATCH 01/17] i2c: pxa: use official address byte helper
+MIME-Version: 1.0
+Content-Disposition: inline
+Content-Transfer-Encoding: 8bit
+Content-Type: text/plain; charset="utf-8"
+
+i2c-pxa was created before i2c_8bit_addr_from_msg() was implemented,
+and used its own i2c_pxa_addr_byte() which is functionally the same.
+Sadly, it was never updated to use this new helper. Switch it over.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/i2c/busses/i2c-pxa.c | 21 +++++++--------------
+ 1 file changed, 7 insertions(+), 14 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-pxa.c
++++ b/drivers/i2c/busses/i2c-pxa.c
+@@ -674,16 +674,6 @@ static void i2c_pxa_slave_stop(struct px
+  * PXA I2C Master mode
+  */
+ 
+-static inline unsigned int i2c_pxa_addr_byte(struct i2c_msg *msg)
+-{
+-	unsigned int addr = (msg->addr & 0x7f) << 1;
+-
+-	if (msg->flags & I2C_M_RD)
+-		addr |= 1;
+-
+-	return addr;
+-}
+-
+ static inline void i2c_pxa_start_message(struct pxa_i2c *i2c)
+ {
+ 	u32 icr;
+@@ -691,8 +681,8 @@ static inline void i2c_pxa_start_message
+ 	/*
+ 	 * Step 1: target slave address into IDBR
+ 	 */
+-	writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c));
+-	i2c->req_slave_addr = i2c_pxa_addr_byte(i2c->msg);
++	i2c->req_slave_addr = i2c_8bit_addr_from_msg(i2c->msg);
++	writel(i2c->req_slave_addr, _IDBR(i2c));
+ 
+ 	/*
+ 	 * Step 2: initiate the write.
+@@ -1003,8 +993,8 @@ static void i2c_pxa_irq_txempty(struct p
+ 		/*
+ 		 * Write the next address.
+ 		 */
+-		writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c));
+-		i2c->req_slave_addr = i2c_pxa_addr_byte(i2c->msg);
++		i2c->req_slave_addr = i2c_8bit_addr_from_msg(i2c->msg);
++		writel(i2c->req_slave_addr, _IDBR(i2c));
+ 
+ 		/*
+ 		 * And trigger a repeated start, and send the byte.
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/804-v5.8-i2c-pxa-remove-unneeded-includes.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/804-v5.8-i2c-pxa-remove-unneeded-includes.patch
new file mode 100644
index 0000000..6a91132
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/804-v5.8-i2c-pxa-remove-unneeded-includes.patch
@@ -0,0 +1,37 @@
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Bcc: linux@mail.armlinux.org.uk
+Cc: linux-i2c@vger.kernel.org
+Subject: [PATCH 02/17] i2c: pxa: remove unneeded includes
+MIME-Version: 1.0
+Content-Disposition: inline
+Content-Transfer-Encoding: 8bit
+Content-Type: text/plain; charset="utf-8"
+
+i2c-pxa does not need linux/sched.h nor linux/time.h includes, so
+remove these.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/i2c/busses/i2c-pxa.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-pxa.c
++++ b/drivers/i2c/busses/i2c-pxa.c
+@@ -20,8 +20,6 @@
+ #include <linux/module.h>
+ #include <linux/i2c.h>
+ #include <linux/init.h>
+-#include <linux/time.h>
+-#include <linux/sched.h>
+ #include <linux/delay.h>
+ #include <linux/errno.h>
+ #include <linux/interrupt.h>
+@@ -35,8 +33,6 @@
+ #include <linux/io.h>
+ #include <linux/platform_data/i2c-pxa.h>
+ 
+-#include <asm/irq.h>
+-
+ struct pxa_reg_layout {
+ 	u32 ibmr;
+ 	u32 idbr;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/805-v5.8-i2c-pxa-re-arrange-includes-to-be-in-alphabetical-or.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/805-v5.8-i2c-pxa-re-arrange-includes-to-be-in-alphabetical-or.patch
new file mode 100644
index 0000000..4d6dc7f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/805-v5.8-i2c-pxa-re-arrange-includes-to-be-in-alphabetical-or.patch
@@ -0,0 +1,52 @@
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Bcc: linux@mail.armlinux.org.uk
+Cc: linux-i2c@vger.kernel.org
+Subject: [PATCH 03/17] i2c: pxa: re-arrange includes to be in alphabetical
+ order
+MIME-Version: 1.0
+Content-Disposition: inline
+Content-Transfer-Encoding: 8bit
+Content-Type: text/plain; charset="utf-8"
+
+Arrange the includes to be in alphabetical order to help avoid
+duplicated includes.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/i2c/busses/i2c-pxa.c | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-pxa.c
++++ b/drivers/i2c/busses/i2c-pxa.c
+@@ -16,22 +16,22 @@
+  *    Dec 2004: Added support for PXA27x and slave device probing [Liam Girdwood]
+  *    Feb 2005: Rework slave mode handling [RMK]
+  */
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/i2c.h>
+-#include <linux/init.h>
++#include <linux/clk.h>
+ #include <linux/delay.h>
++#include <linux/err.h>
+ #include <linux/errno.h>
+-#include <linux/interrupt.h>
++#include <linux/i2c.h>
+ #include <linux/i2c-pxa.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
+ #include <linux/of.h>
+ #include <linux/of_device.h>
+ #include <linux/platform_device.h>
+-#include <linux/err.h>
+-#include <linux/clk.h>
+-#include <linux/slab.h>
+-#include <linux/io.h>
+ #include <linux/platform_data/i2c-pxa.h>
++#include <linux/slab.h>
+ 
+ struct pxa_reg_layout {
+ 	u32 ibmr;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/806-v5.8-i2c-pxa-re-arrange-functions-to-flow-better.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/806-v5.8-i2c-pxa-re-arrange-functions-to-flow-better.patch
new file mode 100644
index 0000000..9f09f9d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/806-v5.8-i2c-pxa-re-arrange-functions-to-flow-better.patch
@@ -0,0 +1,380 @@
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Bcc: linux@mail.armlinux.org.uk
+Cc: linux-i2c@vger.kernel.org
+Subject: [PATCH 04/17] i2c: pxa: re-arrange functions to flow better
+MIME-Version: 1.0
+Content-Disposition: inline
+Content-Transfer-Encoding: 8bit
+Content-Type: text/plain; charset="utf-8"
+
+Re-arrange the PXA I2C code to avoid forward declarations, and keep
+similar functionality (e.g. the non-IRQ mode support) together. This
+improves code readability.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/i2c/busses/i2c-pxa.c | 325 +++++++++++++++++------------------
+ 1 file changed, 162 insertions(+), 163 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-pxa.c
++++ b/drivers/i2c/busses/i2c-pxa.c
+@@ -326,7 +326,6 @@ static void i2c_pxa_scream_blue_murder(s
+ #endif /* ifdef DEBUG / else */
+ 
+ static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret);
+-static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id);
+ 
+ static inline int i2c_pxa_is_slavemode(struct pxa_i2c *i2c)
+ {
+@@ -697,34 +696,6 @@ static inline void i2c_pxa_stop_message(
+ 	writel(icr, _ICR(i2c));
+ }
+ 
+-static int i2c_pxa_pio_set_master(struct pxa_i2c *i2c)
+-{
+-	/* make timeout the same as for interrupt based functions */
+-	long timeout = 2 * DEF_TIMEOUT;
+-
+-	/*
+-	 * Wait for the bus to become free.
+-	 */
+-	while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) {
+-		udelay(1000);
+-		show_state(i2c);
+-	}
+-
+-	if (timeout < 0) {
+-		show_state(i2c);
+-		dev_err(&i2c->adap.dev,
+-			"i2c_pxa: timeout waiting for bus free\n");
+-		return I2C_RETRY;
+-	}
+-
+-	/*
+-	 * Set master mode.
+-	 */
+-	writel(readl(_ICR(i2c)) | ICR_SCLE, _ICR(i2c));
+-
+-	return 0;
+-}
+-
+ /*
+  * PXA I2C send master code
+  * 1. Load master code to IDBR and send it.
+@@ -753,140 +724,6 @@ static int i2c_pxa_send_mastercode(struc
+ 	return (timeout == 0) ? I2C_RETRY : 0;
+ }
+ 
+-static int i2c_pxa_do_pio_xfer(struct pxa_i2c *i2c,
+-			       struct i2c_msg *msg, int num)
+-{
+-	unsigned long timeout = 500000; /* 5 seconds */
+-	int ret = 0;
+-
+-	ret = i2c_pxa_pio_set_master(i2c);
+-	if (ret)
+-		goto out;
+-
+-	i2c->msg = msg;
+-	i2c->msg_num = num;
+-	i2c->msg_idx = 0;
+-	i2c->msg_ptr = 0;
+-	i2c->irqlogidx = 0;
+-
+-	i2c_pxa_start_message(i2c);
+-
+-	while (i2c->msg_num > 0 && --timeout) {
+-		i2c_pxa_handler(0, i2c);
+-		udelay(10);
+-	}
+-
+-	i2c_pxa_stop_message(i2c);
+-
+-	/*
+-	 * We place the return code in i2c->msg_idx.
+-	 */
+-	ret = i2c->msg_idx;
+-
+-out:
+-	if (timeout == 0) {
+-		i2c_pxa_scream_blue_murder(i2c, "timeout");
+-		ret = I2C_RETRY;
+-	}
+-
+-	return ret;
+-}
+-
+-/*
+- * We are protected by the adapter bus mutex.
+- */
+-static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num)
+-{
+-	long timeout;
+-	int ret;
+-
+-	/*
+-	 * Wait for the bus to become free.
+-	 */
+-	ret = i2c_pxa_wait_bus_not_busy(i2c);
+-	if (ret) {
+-		dev_err(&i2c->adap.dev, "i2c_pxa: timeout waiting for bus free\n");
+-		goto out;
+-	}
+-
+-	/*
+-	 * Set master mode.
+-	 */
+-	ret = i2c_pxa_set_master(i2c);
+-	if (ret) {
+-		dev_err(&i2c->adap.dev, "i2c_pxa_set_master: error %d\n", ret);
+-		goto out;
+-	}
+-
+-	if (i2c->high_mode) {
+-		ret = i2c_pxa_send_mastercode(i2c);
+-		if (ret) {
+-			dev_err(&i2c->adap.dev, "i2c_pxa_send_mastercode timeout\n");
+-			goto out;
+-			}
+-	}
+-
+-	spin_lock_irq(&i2c->lock);
+-
+-	i2c->msg = msg;
+-	i2c->msg_num = num;
+-	i2c->msg_idx = 0;
+-	i2c->msg_ptr = 0;
+-	i2c->irqlogidx = 0;
+-
+-	i2c_pxa_start_message(i2c);
+-
+-	spin_unlock_irq(&i2c->lock);
+-
+-	/*
+-	 * The rest of the processing occurs in the interrupt handler.
+-	 */
+-	timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
+-	i2c_pxa_stop_message(i2c);
+-
+-	/*
+-	 * We place the return code in i2c->msg_idx.
+-	 */
+-	ret = i2c->msg_idx;
+-
+-	if (!timeout && i2c->msg_num) {
+-		i2c_pxa_scream_blue_murder(i2c, "timeout");
+-		ret = I2C_RETRY;
+-	}
+-
+- out:
+-	return ret;
+-}
+-
+-static int i2c_pxa_pio_xfer(struct i2c_adapter *adap,
+-			    struct i2c_msg msgs[], int num)
+-{
+-	struct pxa_i2c *i2c = adap->algo_data;
+-	int ret, i;
+-
+-	/* If the I2C controller is disabled we need to reset it
+-	  (probably due to a suspend/resume destroying state). We do
+-	  this here as we can then avoid worrying about resuming the
+-	  controller before its users. */
+-	if (!(readl(_ICR(i2c)) & ICR_IUE))
+-		i2c_pxa_reset(i2c);
+-
+-	for (i = adap->retries; i >= 0; i--) {
+-		ret = i2c_pxa_do_pio_xfer(i2c, msgs, num);
+-		if (ret != I2C_RETRY)
+-			goto out;
+-
+-		if (i2c_debug)
+-			dev_dbg(&adap->dev, "Retrying transmission\n");
+-		udelay(100);
+-	}
+-	i2c_pxa_scream_blue_murder(i2c, "exhausted retries");
+-	ret = -EREMOTEIO;
+- out:
+-	i2c_pxa_set_slave(i2c, ret);
+-	return ret;
+-}
+-
+ /*
+  * i2c_pxa_master_complete - complete the message and wake up.
+  */
+@@ -1093,6 +930,71 @@ static irqreturn_t i2c_pxa_handler(int t
+ 	return IRQ_HANDLED;
+ }
+ 
++/*
++ * We are protected by the adapter bus mutex.
++ */
++static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num)
++{
++	long timeout;
++	int ret;
++
++	/*
++	 * Wait for the bus to become free.
++	 */
++	ret = i2c_pxa_wait_bus_not_busy(i2c);
++	if (ret) {
++		dev_err(&i2c->adap.dev, "i2c_pxa: timeout waiting for bus free\n");
++		goto out;
++	}
++
++	/*
++	 * Set master mode.
++	 */
++	ret = i2c_pxa_set_master(i2c);
++	if (ret) {
++		dev_err(&i2c->adap.dev, "i2c_pxa_set_master: error %d\n", ret);
++		goto out;
++	}
++
++	if (i2c->high_mode) {
++		ret = i2c_pxa_send_mastercode(i2c);
++		if (ret) {
++			dev_err(&i2c->adap.dev, "i2c_pxa_send_mastercode timeout\n");
++			goto out;
++			}
++	}
++
++	spin_lock_irq(&i2c->lock);
++
++	i2c->msg = msg;
++	i2c->msg_num = num;
++	i2c->msg_idx = 0;
++	i2c->msg_ptr = 0;
++	i2c->irqlogidx = 0;
++
++	i2c_pxa_start_message(i2c);
++
++	spin_unlock_irq(&i2c->lock);
++
++	/*
++	 * The rest of the processing occurs in the interrupt handler.
++	 */
++	timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
++	i2c_pxa_stop_message(i2c);
++
++	/*
++	 * We place the return code in i2c->msg_idx.
++	 */
++	ret = i2c->msg_idx;
++
++	if (!timeout && i2c->msg_num) {
++		i2c_pxa_scream_blue_murder(i2c, "timeout");
++		ret = I2C_RETRY;
++	}
++
++ out:
++	return ret;
++}
+ 
+ static int i2c_pxa_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+ {
+@@ -1126,6 +1028,103 @@ static const struct i2c_algorithm i2c_px
+ 	.functionality	= i2c_pxa_functionality,
+ };
+ 
++/* Non-interrupt mode support */
++static int i2c_pxa_pio_set_master(struct pxa_i2c *i2c)
++{
++	/* make timeout the same as for interrupt based functions */
++	long timeout = 2 * DEF_TIMEOUT;
++
++	/*
++	 * Wait for the bus to become free.
++	 */
++	while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) {
++		udelay(1000);
++		show_state(i2c);
++	}
++
++	if (timeout < 0) {
++		show_state(i2c);
++		dev_err(&i2c->adap.dev,
++			"i2c_pxa: timeout waiting for bus free\n");
++		return I2C_RETRY;
++	}
++
++	/*
++	 * Set master mode.
++	 */
++	writel(readl(_ICR(i2c)) | ICR_SCLE, _ICR(i2c));
++
++	return 0;
++}
++
++static int i2c_pxa_do_pio_xfer(struct pxa_i2c *i2c,
++			       struct i2c_msg *msg, int num)
++{
++	unsigned long timeout = 500000; /* 5 seconds */
++	int ret = 0;
++
++	ret = i2c_pxa_pio_set_master(i2c);
++	if (ret)
++		goto out;
++
++	i2c->msg = msg;
++	i2c->msg_num = num;
++	i2c->msg_idx = 0;
++	i2c->msg_ptr = 0;
++	i2c->irqlogidx = 0;
++
++	i2c_pxa_start_message(i2c);
++
++	while (i2c->msg_num > 0 && --timeout) {
++		i2c_pxa_handler(0, i2c);
++		udelay(10);
++	}
++
++	i2c_pxa_stop_message(i2c);
++
++	/*
++	 * We place the return code in i2c->msg_idx.
++	 */
++	ret = i2c->msg_idx;
++
++out:
++	if (timeout == 0) {
++		i2c_pxa_scream_blue_murder(i2c, "timeout");
++		ret = I2C_RETRY;
++	}
++
++	return ret;
++}
++
++static int i2c_pxa_pio_xfer(struct i2c_adapter *adap,
++			    struct i2c_msg msgs[], int num)
++{
++	struct pxa_i2c *i2c = adap->algo_data;
++	int ret, i;
++
++	/* If the I2C controller is disabled we need to reset it
++	  (probably due to a suspend/resume destroying state). We do
++	  this here as we can then avoid worrying about resuming the
++	  controller before its users. */
++	if (!(readl(_ICR(i2c)) & ICR_IUE))
++		i2c_pxa_reset(i2c);
++
++	for (i = adap->retries; i >= 0; i--) {
++		ret = i2c_pxa_do_pio_xfer(i2c, msgs, num);
++		if (ret != I2C_RETRY)
++			goto out;
++
++		if (i2c_debug)
++			dev_dbg(&adap->dev, "Retrying transmission\n");
++		udelay(100);
++	}
++	i2c_pxa_scream_blue_murder(i2c, "exhausted retries");
++	ret = -EREMOTEIO;
++ out:
++	i2c_pxa_set_slave(i2c, ret);
++	return ret;
++}
++
+ static const struct i2c_algorithm i2c_pxa_pio_algorithm = {
+ 	.master_xfer	= i2c_pxa_pio_xfer,
+ 	.functionality	= i2c_pxa_functionality,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/807-v5.8-i2c-pxa-re-arrange-register-field-definitions.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/807-v5.8-i2c-pxa-re-arrange-register-field-definitions.patch
new file mode 100644
index 0000000..afade04
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/807-v5.8-i2c-pxa-re-arrange-register-field-definitions.patch
@@ -0,0 +1,161 @@
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Bcc: linux@mail.armlinux.org.uk
+Cc: linux-i2c@vger.kernel.org
+Subject: [PATCH 05/17] i2c: pxa: re-arrange register field definitions
+MIME-Version: 1.0
+Content-Disposition: inline
+Content-Transfer-Encoding: 8bit
+Content-Type: text/plain; charset="utf-8"
+
+Arrange the register field definitions to be grouped together, rather
+than the Armada-3700 definitions being separated from the rest of the
+definitions.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/i2c/busses/i2c-pxa.c | 113 ++++++++++++++++-------------------
+ 1 file changed, 53 insertions(+), 60 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-pxa.c
++++ b/drivers/i2c/busses/i2c-pxa.c
+@@ -33,6 +33,56 @@
+ #include <linux/platform_data/i2c-pxa.h>
+ #include <linux/slab.h>
+ 
++/* I2C register field definitions */
++#define ICR_START	(1 << 0)	   /* start bit */
++#define ICR_STOP	(1 << 1)	   /* stop bit */
++#define ICR_ACKNAK	(1 << 2)	   /* send ACK(0) or NAK(1) */
++#define ICR_TB		(1 << 3)	   /* transfer byte bit */
++#define ICR_MA		(1 << 4)	   /* master abort */
++#define ICR_SCLE	(1 << 5)	   /* master clock enable */
++#define ICR_IUE		(1 << 6)	   /* unit enable */
++#define ICR_GCD		(1 << 7)	   /* general call disable */
++#define ICR_ITEIE	(1 << 8)	   /* enable tx interrupts */
++#define ICR_IRFIE	(1 << 9)	   /* enable rx interrupts */
++#define ICR_BEIE	(1 << 10)	   /* enable bus error ints */
++#define ICR_SSDIE	(1 << 11)	   /* slave STOP detected int enable */
++#define ICR_ALDIE	(1 << 12)	   /* enable arbitration interrupt */
++#define ICR_SADIE	(1 << 13)	   /* slave address detected int enable */
++#define ICR_UR		(1 << 14)	   /* unit reset */
++#define ICR_FM		(1 << 15)	   /* fast mode */
++#define ICR_HS		(1 << 16)	   /* High Speed mode */
++#define ICR_A3700_FM	(1 << 16)	   /* fast mode for armada-3700 */
++#define ICR_A3700_HS	(1 << 17)	   /* high speed mode for armada-3700 */
++#define ICR_GPIOEN	(1 << 19)	   /* enable GPIO mode for SCL in HS */
++
++#define ISR_RWM		(1 << 0)	   /* read/write mode */
++#define ISR_ACKNAK	(1 << 1)	   /* ack/nak status */
++#define ISR_UB		(1 << 2)	   /* unit busy */
++#define ISR_IBB		(1 << 3)	   /* bus busy */
++#define ISR_SSD		(1 << 4)	   /* slave stop detected */
++#define ISR_ALD		(1 << 5)	   /* arbitration loss detected */
++#define ISR_ITE		(1 << 6)	   /* tx buffer empty */
++#define ISR_IRF		(1 << 7)	   /* rx buffer full */
++#define ISR_GCAD	(1 << 8)	   /* general call address detected */
++#define ISR_SAD		(1 << 9)	   /* slave address detected */
++#define ISR_BED		(1 << 10)	   /* bus error no ACK/NAK */
++
++#define ILCR_SLV_SHIFT		0
++#define ILCR_SLV_MASK		(0x1FF << ILCR_SLV_SHIFT)
++#define ILCR_FLV_SHIFT		9
++#define ILCR_FLV_MASK		(0x1FF << ILCR_FLV_SHIFT)
++#define ILCR_HLVL_SHIFT		18
++#define ILCR_HLVL_MASK		(0x1FF << ILCR_HLVL_SHIFT)
++#define ILCR_HLVH_SHIFT		27
++#define ILCR_HLVH_MASK		(0x1F << ILCR_HLVH_SHIFT)
++
++#define IWCR_CNT_SHIFT		0
++#define IWCR_CNT_MASK		(0x1F << IWCR_CNT_SHIFT)
++#define IWCR_HS_CNT1_SHIFT	5
++#define IWCR_HS_CNT1_MASK	(0x1F << IWCR_HS_CNT1_SHIFT)
++#define IWCR_HS_CNT2_SHIFT	10
++#define IWCR_HS_CNT2_MASK	(0x1F << IWCR_HS_CNT2_SHIFT)
++
+ struct pxa_reg_layout {
+ 	u32 ibmr;
+ 	u32 idbr;
+@@ -53,12 +103,7 @@ enum pxa_i2c_types {
+ 	REGS_A3700,
+ };
+ 
+-#define ICR_BUSMODE_FM	(1 << 16)	   /* shifted fast mode for armada-3700 */
+-#define ICR_BUSMODE_HS	(1 << 17)	   /* shifted high speed mode for armada-3700 */
+-
+-/*
+- * I2C registers definitions
+- */
++/* I2C register layout definitions */
+ static struct pxa_reg_layout pxa_reg_layout[] = {
+ 	[REGS_PXA2XX] = {
+ 		.ibmr =	0x00,
+@@ -96,8 +141,8 @@ static struct pxa_reg_layout pxa_reg_lay
+ 		.icr =	0x08,
+ 		.isr =	0x0c,
+ 		.isar =	0x10,
+-		.fm = ICR_BUSMODE_FM,
+-		.hs = ICR_BUSMODE_HS,
++		.fm = ICR_A3700_FM,
++		.hs = ICR_A3700_HS,
+ 	},
+ };
+ 
+@@ -111,58 +156,6 @@ static const struct platform_device_id i
+ };
+ MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table);
+ 
+-/*
+- * I2C bit definitions
+- */
+-
+-#define ICR_START	(1 << 0)	   /* start bit */
+-#define ICR_STOP	(1 << 1)	   /* stop bit */
+-#define ICR_ACKNAK	(1 << 2)	   /* send ACK(0) or NAK(1) */
+-#define ICR_TB		(1 << 3)	   /* transfer byte bit */
+-#define ICR_MA		(1 << 4)	   /* master abort */
+-#define ICR_SCLE	(1 << 5)	   /* master clock enable */
+-#define ICR_IUE		(1 << 6)	   /* unit enable */
+-#define ICR_GCD		(1 << 7)	   /* general call disable */
+-#define ICR_ITEIE	(1 << 8)	   /* enable tx interrupts */
+-#define ICR_IRFIE	(1 << 9)	   /* enable rx interrupts */
+-#define ICR_BEIE	(1 << 10)	   /* enable bus error ints */
+-#define ICR_SSDIE	(1 << 11)	   /* slave STOP detected int enable */
+-#define ICR_ALDIE	(1 << 12)	   /* enable arbitration interrupt */
+-#define ICR_SADIE	(1 << 13)	   /* slave address detected int enable */
+-#define ICR_UR		(1 << 14)	   /* unit reset */
+-#define ICR_FM		(1 << 15)	   /* fast mode */
+-#define ICR_HS		(1 << 16)	   /* High Speed mode */
+-#define ICR_GPIOEN	(1 << 19)	   /* enable GPIO mode for SCL in HS */
+-
+-#define ISR_RWM		(1 << 0)	   /* read/write mode */
+-#define ISR_ACKNAK	(1 << 1)	   /* ack/nak status */
+-#define ISR_UB		(1 << 2)	   /* unit busy */
+-#define ISR_IBB		(1 << 3)	   /* bus busy */
+-#define ISR_SSD		(1 << 4)	   /* slave stop detected */
+-#define ISR_ALD		(1 << 5)	   /* arbitration loss detected */
+-#define ISR_ITE		(1 << 6)	   /* tx buffer empty */
+-#define ISR_IRF		(1 << 7)	   /* rx buffer full */
+-#define ISR_GCAD	(1 << 8)	   /* general call address detected */
+-#define ISR_SAD		(1 << 9)	   /* slave address detected */
+-#define ISR_BED		(1 << 10)	   /* bus error no ACK/NAK */
+-
+-/* bit field shift & mask */
+-#define ILCR_SLV_SHIFT		0
+-#define ILCR_SLV_MASK		(0x1FF << ILCR_SLV_SHIFT)
+-#define ILCR_FLV_SHIFT		9
+-#define ILCR_FLV_MASK		(0x1FF << ILCR_FLV_SHIFT)
+-#define ILCR_HLVL_SHIFT		18
+-#define ILCR_HLVL_MASK		(0x1FF << ILCR_HLVL_SHIFT)
+-#define ILCR_HLVH_SHIFT		27
+-#define ILCR_HLVH_MASK		(0x1F << ILCR_HLVH_SHIFT)
+-
+-#define IWCR_CNT_SHIFT		0
+-#define IWCR_CNT_MASK		(0x1F << IWCR_CNT_SHIFT)
+-#define IWCR_HS_CNT1_SHIFT	5
+-#define IWCR_HS_CNT1_MASK	(0x1F << IWCR_HS_CNT1_SHIFT)
+-#define IWCR_HS_CNT2_SHIFT	10
+-#define IWCR_HS_CNT2_MASK	(0x1F << IWCR_HS_CNT2_SHIFT)
+-
+ struct pxa_i2c {
+ 	spinlock_t		lock;
+ 	wait_queue_head_t	wait;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/808-v5.8-i2c-pxa-add-and-use-definitions-for-IBMR-register.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/808-v5.8-i2c-pxa-add-and-use-definitions-for-IBMR-register.patch
new file mode 100644
index 0000000..f197808
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/808-v5.8-i2c-pxa-add-and-use-definitions-for-IBMR-register.patch
@@ -0,0 +1,66 @@
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Bcc: linux@mail.armlinux.org.uk
+Cc: linux-i2c@vger.kernel.org
+Subject: [PATCH 06/17] i2c: pxa: add and use definitions for IBMR register
+MIME-Version: 1.0
+Content-Disposition: inline
+Content-Transfer-Encoding: 8bit
+Content-Type: text/plain; charset="utf-8"
+
+Add definitions for the bits in the IBMR register, and use them in the
+code. This improves readability.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/i2c/busses/i2c-pxa.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-pxa.c
++++ b/drivers/i2c/busses/i2c-pxa.c
+@@ -34,6 +34,9 @@
+ #include <linux/slab.h>
+ 
+ /* I2C register field definitions */
++#define IBMR_SDAS	(1 << 0)
++#define IBMR_SCLS	(1 << 1)
++
+ #define ICR_START	(1 << 0)	   /* start bit */
+ #define ICR_STOP	(1 << 1)	   /* stop bit */
+ #define ICR_ACKNAK	(1 << 2)	   /* send ACK(0) or NAK(1) */
+@@ -334,7 +337,7 @@ static void i2c_pxa_abort(struct pxa_i2c
+ 		return;
+ 	}
+ 
+-	while ((i > 0) && (readl(_IBMR(i2c)) & 0x1) == 0) {
++	while ((i > 0) && (readl(_IBMR(i2c)) & IBMR_SDAS) == 0) {
+ 		unsigned long icr = readl(_ICR(i2c));
+ 
+ 		icr &= ~ICR_START;
+@@ -389,7 +392,8 @@ static int i2c_pxa_wait_master(struct px
+ 		 * quick check of the i2c lines themselves to ensure they've
+ 		 * gone high...
+ 		 */
+-		if ((readl(_ISR(i2c)) & (ISR_UB | ISR_IBB)) == 0 && readl(_IBMR(i2c)) == 3) {
++		if ((readl(_ISR(i2c)) & (ISR_UB | ISR_IBB)) == 0 &&
++		    readl(_IBMR(i2c)) == (IBMR_SCLS | IBMR_SDAS)) {
+ 			if (i2c_debug > 0)
+ 				dev_dbg(&i2c->adap.dev, "%s: done\n", __func__);
+ 			return 1;
+@@ -574,7 +578,7 @@ static void i2c_pxa_slave_start(struct p
+ 	timeout = 0x10000;
+ 
+ 	while (1) {
+-		if ((readl(_IBMR(i2c)) & 2) == 2)
++		if ((readl(_IBMR(i2c)) & IBMR_SCLS) == IBMR_SCLS)
+ 			break;
+ 
+ 		timeout--;
+@@ -637,7 +641,7 @@ static void i2c_pxa_slave_start(struct p
+ 	timeout = 0x10000;
+ 
+ 	while (1) {
+-		if ((readl(_IBMR(i2c)) & 2) == 2)
++		if ((readl(_IBMR(i2c)) & IBMR_SCLS) == IBMR_SCLS)
+ 			break;
+ 
+ 		timeout--;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/809-v5.8-i2c-pxa-always-set-fm-and-hs-members-for-each-type.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/809-v5.8-i2c-pxa-always-set-fm-and-hs-members-for-each-type.patch
new file mode 100644
index 0000000..9b1dee6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/809-v5.8-i2c-pxa-always-set-fm-and-hs-members-for-each-type.patch
@@ -0,0 +1,66 @@
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Bcc: linux@mail.armlinux.org.uk
+Cc: linux-i2c@vger.kernel.org
+Subject: [PATCH 07/17] i2c: pxa: always set fm and hs members for each type
+MIME-Version: 1.0
+Content-Disposition: inline
+Content-Transfer-Encoding: 8bit
+Content-Type: text/plain; charset="utf-8"
+
+Always set the fm and hs members of struct pxa_reg_layout. These
+members are already taking space, we don't need code as well.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/i2c/busses/i2c-pxa.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-pxa.c
++++ b/drivers/i2c/busses/i2c-pxa.c
+@@ -114,6 +114,8 @@ static struct pxa_reg_layout pxa_reg_lay
+ 		.icr =	0x10,
+ 		.isr =	0x18,
+ 		.isar =	0x20,
++		.fm = ICR_FM,
++		.hs = ICR_HS,
+ 	},
+ 	[REGS_PXA3XX] = {
+ 		.ibmr =	0x00,
+@@ -121,6 +123,8 @@ static struct pxa_reg_layout pxa_reg_lay
+ 		.icr =	0x08,
+ 		.isr =	0x0c,
+ 		.isar =	0x10,
++		.fm = ICR_FM,
++		.hs = ICR_HS,
+ 	},
+ 	[REGS_CE4100] = {
+ 		.ibmr =	0x14,
+@@ -128,6 +132,8 @@ static struct pxa_reg_layout pxa_reg_lay
+ 		.icr =	0x00,
+ 		.isr =	0x04,
+ 		/* no isar register */
++		.fm = ICR_FM,
++		.hs = ICR_HS,
+ 	},
+ 	[REGS_PXA910] = {
+ 		.ibmr = 0x00,
+@@ -137,6 +143,8 @@ static struct pxa_reg_layout pxa_reg_lay
+ 		.isar = 0x20,
+ 		.ilcr = 0x28,
+ 		.iwcr = 0x30,
++		.fm = ICR_FM,
++		.hs = ICR_HS,
+ 	},
+ 	[REGS_A3700] = {
+ 		.ibmr =	0x00,
+@@ -1229,8 +1237,8 @@ static int i2c_pxa_probe(struct platform
+ 	i2c->reg_idbr = i2c->reg_base + pxa_reg_layout[i2c_type].idbr;
+ 	i2c->reg_icr = i2c->reg_base + pxa_reg_layout[i2c_type].icr;
+ 	i2c->reg_isr = i2c->reg_base + pxa_reg_layout[i2c_type].isr;
+-	i2c->fm_mask = pxa_reg_layout[i2c_type].fm ? : ICR_FM;
+-	i2c->hs_mask = pxa_reg_layout[i2c_type].hs ? : ICR_HS;
++	i2c->fm_mask = pxa_reg_layout[i2c_type].fm;
++	i2c->hs_mask = pxa_reg_layout[i2c_type].hs;
+ 
+ 	if (i2c_type != REGS_CE4100)
+ 		i2c->reg_isar = i2c->reg_base + pxa_reg_layout[i2c_type].isar;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/810-v5.8-i2c-pxa-move-private-definitions-to-i2c-pxa.c.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/810-v5.8-i2c-pxa-move-private-definitions-to-i2c-pxa.c.patch
new file mode 100644
index 0000000..dda4630
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/810-v5.8-i2c-pxa-move-private-definitions-to-i2c-pxa.c.patch
@@ -0,0 +1,128 @@
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Bcc: linux@mail.armlinux.org.uk
+Cc: linux-i2c@vger.kernel.org
+Subject: [PATCH 08/17] i2c: pxa: move private definitions to i2c-pxa.c
+MIME-Version: 1.0
+Content-Disposition: inline
+Content-Transfer-Encoding: 8bit
+Content-Type: text/plain; charset="utf-8"
+
+Move driver-private definitions out of the i2c-pxa.h platform data
+header file into the driver itself. Nothing outside of the driver
+makes use of these constants.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/i2c/busses/i2c-pxa.c          | 43 ++++++++++++++++++++++++
+ include/linux/platform_data/i2c-pxa.h | 48 ---------------------------
+ 2 files changed, 43 insertions(+), 48 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-pxa.c
++++ b/drivers/i2c/busses/i2c-pxa.c
+@@ -86,6 +86,49 @@
+ #define IWCR_HS_CNT2_SHIFT	10
+ #define IWCR_HS_CNT2_MASK	(0x1F << IWCR_HS_CNT2_SHIFT)
+ 
++/* need a longer timeout if we're dealing with the fact we may well be
++ * looking at a multi-master environment
++ */
++#define DEF_TIMEOUT             32
++
++#define BUS_ERROR               (-EREMOTEIO)
++#define XFER_NAKED              (-ECONNREFUSED)
++#define I2C_RETRY               (-2000) /* an error has occurred retry transmit */
++
++/* ICR initialize bit values
++ *
++ * 15 FM     0 (100 kHz operation)
++ * 14 UR     0 (No unit reset)
++ * 13 SADIE  0 (Disables the unit from interrupting on slave addresses
++ *              matching its slave address)
++ * 12 ALDIE  0 (Disables the unit from interrupt when it loses arbitration
++ *              in master mode)
++ * 11 SSDIE  0 (Disables interrupts from a slave stop detected, in slave mode)
++ * 10 BEIE   1 (Enable interrupts from detected bus errors, no ACK sent)
++ *  9 IRFIE  1 (Enable interrupts from full buffer received)
++ *  8 ITEIE  1 (Enables the I2C unit to interrupt when transmit buffer empty)
++ *  7 GCD    1 (Disables i2c unit response to general call messages as a slave)
++ *  6 IUE    0 (Disable unit until we change settings)
++ *  5 SCLE   1 (Enables the i2c clock output for master mode (drives SCL)
++ *  4 MA     0 (Only send stop with the ICR stop bit)
++ *  3 TB     0 (We are not transmitting a byte initially)
++ *  2 ACKNAK 0 (Send an ACK after the unit receives a byte)
++ *  1 STOP   0 (Do not send a STOP)
++ *  0 START  0 (Do not send a START)
++ */
++#define I2C_ICR_INIT	(ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE)
++
++/* I2C status register init values
++ *
++ * 10 BED    1 (Clear bus error detected)
++ *  9 SAD    1 (Clear slave address detected)
++ *  7 IRF    1 (Clear IDBR Receive Full)
++ *  6 ITE    1 (Clear IDBR Transmit Empty)
++ *  5 ALD    1 (Clear Arbitration Loss Detected)
++ *  4 SSD    1 (Clear Slave Stop Detected)
++ */
++#define I2C_ISR_INIT	0x7FF  /* status register init */
++
+ struct pxa_reg_layout {
+ 	u32 ibmr;
+ 	u32 idbr;
+--- a/include/linux/platform_data/i2c-pxa.h
++++ b/include/linux/platform_data/i2c-pxa.h
+@@ -7,54 +7,6 @@
+ #ifndef _I2C_PXA_H_
+ #define _I2C_PXA_H_
+ 
+-#if 0
+-#define DEF_TIMEOUT             3
+-#else
+-/* need a longer timeout if we're dealing with the fact we may well be
+- * looking at a multi-master environment
+-*/
+-#define DEF_TIMEOUT             32
+-#endif
+-
+-#define BUS_ERROR               (-EREMOTEIO)
+-#define XFER_NAKED              (-ECONNREFUSED)
+-#define I2C_RETRY               (-2000) /* an error has occurred retry transmit */
+-
+-/* ICR initialize bit values
+-*
+-*  15. FM       0 (100 Khz operation)
+-*  14. UR       0 (No unit reset)
+-*  13. SADIE    0 (Disables the unit from interrupting on slave addresses
+-*                                       matching its slave address)
+-*  12. ALDIE    0 (Disables the unit from interrupt when it loses arbitration
+-*                                       in master mode)
+-*  11. SSDIE    0 (Disables interrupts from a slave stop detected, in slave mode)
+-*  10. BEIE     1 (Enable interrupts from detected bus errors, no ACK sent)
+-*  9.  IRFIE    1 (Enable interrupts from full buffer received)
+-*  8.  ITEIE    1 (Enables the I2C unit to interrupt when transmit buffer empty)
+-*  7.  GCD      1 (Disables i2c unit response to general call messages as a slave)
+-*  6.  IUE      0 (Disable unit until we change settings)
+-*  5.  SCLE     1 (Enables the i2c clock output for master mode (drives SCL)
+-*  4.  MA       0 (Only send stop with the ICR stop bit)
+-*  3.  TB       0 (We are not transmitting a byte initially)
+-*  2.  ACKNAK   0 (Send an ACK after the unit receives a byte)
+-*  1.  STOP     0 (Do not send a STOP)
+-*  0.  START    0 (Do not send a START)
+-*
+-*/
+-#define I2C_ICR_INIT	(ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE)
+-
+-/* I2C status register init values
+- *
+- * 10. BED      1 (Clear bus error detected)
+- * 9.  SAD      1 (Clear slave address detected)
+- * 7.  IRF      1 (Clear IDBR Receive Full)
+- * 6.  ITE      1 (Clear IDBR Transmit Empty)
+- * 5.  ALD      1 (Clear Arbitration Loss Detected)
+- * 4.  SSD      1 (Clear Slave Stop Detected)
+- */
+-#define I2C_ISR_INIT	0x7FF  /* status register init */
+-
+ struct i2c_slave_client;
+ 
+ struct i2c_pxa_platform_data {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/811-v5.8-i2c-pxa-move-DT-IDs-along-side-platform-IDs.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/811-v5.8-i2c-pxa-move-DT-IDs-along-side-platform-IDs.patch
new file mode 100644
index 0000000..0256522
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/811-v5.8-i2c-pxa-move-DT-IDs-along-side-platform-IDs.patch
@@ -0,0 +1,50 @@
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Bcc: linux@mail.armlinux.org.uk
+Cc: linux-i2c@vger.kernel.org
+Subject: [PATCH 09/17] i2c: pxa: move DT IDs along side platform IDs
+MIME-Version: 1.0
+Content-Disposition: inline
+Content-Transfer-Encoding: 8bit
+Content-Type: text/plain; charset="utf-8"
+
+Move the ID tables into one place, near the device dependent data.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/i2c/busses/i2c-pxa.c | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-pxa.c
++++ b/drivers/i2c/busses/i2c-pxa.c
+@@ -200,6 +200,15 @@ static struct pxa_reg_layout pxa_reg_lay
+ 	},
+ };
+ 
++static const struct of_device_id i2c_pxa_dt_ids[] = {
++	{ .compatible = "mrvl,pxa-i2c", .data = (void *)REGS_PXA2XX },
++	{ .compatible = "mrvl,pwri2c", .data = (void *)REGS_PXA3XX },
++	{ .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA910 },
++	{ .compatible = "marvell,armada-3700-i2c", .data = (void *)REGS_A3700 },
++	{}
++};
++MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids);
++
+ static const struct platform_device_id i2c_pxa_id_table[] = {
+ 	{ "pxa2xx-i2c",		REGS_PXA2XX },
+ 	{ "pxa3xx-pwri2c",	REGS_PXA3XX },
+@@ -1178,15 +1187,6 @@ static const struct i2c_algorithm i2c_px
+ 	.functionality	= i2c_pxa_functionality,
+ };
+ 
+-static const struct of_device_id i2c_pxa_dt_ids[] = {
+-	{ .compatible = "mrvl,pxa-i2c", .data = (void *)REGS_PXA2XX },
+-	{ .compatible = "mrvl,pwri2c", .data = (void *)REGS_PXA3XX },
+-	{ .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA910 },
+-	{ .compatible = "marvell,armada-3700-i2c", .data = (void *)REGS_A3700 },
+-	{}
+-};
+-MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids);
+-
+ static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c,
+ 			    enum pxa_i2c_types *i2c_types)
+ {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/813-v5.8-i2c-pxa-clean-up-decode_bits.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/813-v5.8-i2c-pxa-clean-up-decode_bits.patch
new file mode 100644
index 0000000..adcf969
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/813-v5.8-i2c-pxa-clean-up-decode_bits.patch
@@ -0,0 +1,53 @@
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Bcc: linux@mail.armlinux.org.uk
+Cc: linux-i2c@vger.kernel.org
+Subject: [PATCH 11/17] i2c: pxa: clean up decode_bits()
+MIME-Version: 1.0
+Content-Disposition: inline
+Content-Transfer-Encoding: 8bit
+Content-Type: text/plain; charset="utf-8"
+
+Clean up decode_bits() to use pr_cont(), and move the newline into the
+function rather than at its two callsites. Avoid printing an
+unnecessary space before the newline.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/i2c/busses/i2c-pxa.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-pxa.c
++++ b/drivers/i2c/busses/i2c-pxa.c
+@@ -287,13 +287,14 @@ struct bits {
+ static inline void
+ decode_bits(const char *prefix, const struct bits *bits, int num, u32 val)
+ {
+-	printk("%s %08x: ", prefix, val);
++	printk("%s %08x:", prefix, val);
+ 	while (num--) {
+ 		const char *str = val & bits->mask ? bits->set : bits->unset;
+ 		if (str)
+-			printk("%s ", str);
++			pr_cont(" %s", str);
+ 		bits++;
+ 	}
++	pr_cont("\n");
+ }
+ 
+ static const struct bits isr_bits[] = {
+@@ -313,7 +314,6 @@ static const struct bits isr_bits[] = {
+ static void decode_ISR(unsigned int val)
+ {
+ 	decode_bits(KERN_DEBUG "ISR", isr_bits, ARRAY_SIZE(isr_bits), val);
+-	printk("\n");
+ }
+ 
+ static const struct bits icr_bits[] = {
+@@ -338,7 +338,6 @@ static const struct bits icr_bits[] = {
+ static void decode_ICR(unsigned int val)
+ {
+ 	decode_bits(KERN_DEBUG "ICR", icr_bits, ARRAY_SIZE(icr_bits), val);
+-	printk("\n");
+ }
+ #endif
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/814-v5.8-i2c-pxa-fix-i2c_pxa_wait_bus_not_busy-boundary-condi.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/814-v5.8-i2c-pxa-fix-i2c_pxa_wait_bus_not_busy-boundary-condi.patch
new file mode 100644
index 0000000..2aadecc
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/814-v5.8-i2c-pxa-fix-i2c_pxa_wait_bus_not_busy-boundary-condi.patch
@@ -0,0 +1,53 @@
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Bcc: linux@mail.armlinux.org.uk
+Cc: linux-i2c@vger.kernel.org
+Subject: [PATCH 12/17] i2c: pxa: fix i2c_pxa_wait_bus_not_busy() boundary
+ condition
+MIME-Version: 1.0
+Content-Disposition: inline
+Content-Transfer-Encoding: 8bit
+Content-Type: text/plain; charset="utf-8"
+
+Fix i2c_pxa_wait_bus_not_busy()'s boundary conditions, so that a
+coincidental success and timeout results in the function returning
+success.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/i2c/busses/i2c-pxa.c | 17 ++++++++++++-----
+ 1 file changed, 12 insertions(+), 5 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-pxa.c
++++ b/drivers/i2c/busses/i2c-pxa.c
+@@ -417,19 +417,26 @@ static void i2c_pxa_abort(struct pxa_i2c
+ static int i2c_pxa_wait_bus_not_busy(struct pxa_i2c *i2c)
+ {
+ 	int timeout = DEF_TIMEOUT;
++	u32 isr;
+ 
+-	while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) {
+-		if ((readl(_ISR(i2c)) & ISR_SAD) != 0)
++	while (1) {
++		isr = readl(_ISR(i2c));
++		if (!(isr & (ISR_IBB | ISR_UB)))
++			return 0;
++
++		if (isr & ISR_SAD)
+ 			timeout += 4;
+ 
++		if (!timeout--)
++			break;
++
+ 		msleep(2);
+ 		show_state(i2c);
+ 	}
+ 
+-	if (timeout < 0)
+-		show_state(i2c);
++	show_state(i2c);
+ 
+-	return timeout < 0 ? I2C_RETRY : 0;
++	return I2C_RETRY;
+ }
+ 
+ static int i2c_pxa_wait_master(struct pxa_i2c *i2c)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/815-v5.8-i2c-pxa-consolidate-i2c_pxa_-xfer-implementations.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/815-v5.8-i2c-pxa-consolidate-i2c_pxa_-xfer-implementations.patch
new file mode 100644
index 0000000..2debd4c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/815-v5.8-i2c-pxa-consolidate-i2c_pxa_-xfer-implementations.patch
@@ -0,0 +1,91 @@
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Bcc: linux@mail.armlinux.org.uk
+Subject: [PATCH 1/7] i2c: pxa: consolidate i2c_pxa_*xfer() implementations
+MIME-Version: 1.0
+Content-Disposition: inline
+Content-Transfer-Encoding: 8bit
+Content-Type: text/plain; charset="utf-8"
+
+Most of i2c_pxa_pio_xfer() and i2c_pxa_xfer() are identical; the only
+differences are that i2c_pxa_pio_xfer() may reset the bus, and they
+use different underlying transfer functions. The retry loop is the
+same. Consolidate these two functions.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/i2c/busses/i2c-pxa.c | 36 ++++++++++++++++--------------------
+ 1 file changed, 16 insertions(+), 20 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-pxa.c
++++ b/drivers/i2c/busses/i2c-pxa.c
+@@ -1059,18 +1059,20 @@ static int i2c_pxa_do_xfer(struct pxa_i2
+ 	return ret;
+ }
+ 
+-static int i2c_pxa_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
++static int i2c_pxa_internal_xfer(struct pxa_i2c *i2c,
++				 struct i2c_msg *msgs, int num,
++				 int (*xfer)(struct pxa_i2c *,
++					     struct i2c_msg *, int num))
+ {
+-	struct pxa_i2c *i2c = adap->algo_data;
+ 	int ret, i;
+ 
+-	for (i = adap->retries; i >= 0; i--) {
+-		ret = i2c_pxa_do_xfer(i2c, msgs, num);
++	for (i = i2c->adap.retries; i >= 0; i--) {
++		ret = xfer(i2c, msgs, num);
+ 		if (ret != I2C_RETRY)
+ 			goto out;
+ 
+ 		if (i2c_debug)
+-			dev_dbg(&adap->dev, "Retrying transmission\n");
++			dev_dbg(&i2c->adap.dev, "Retrying transmission\n");
+ 		udelay(100);
+ 	}
+ 	i2c_pxa_scream_blue_murder(i2c, "exhausted retries");
+@@ -1080,6 +1082,14 @@ static int i2c_pxa_xfer(struct i2c_adapt
+ 	return ret;
+ }
+ 
++static int i2c_pxa_xfer(struct i2c_adapter *adap,
++			struct i2c_msg msgs[], int num)
++{
++	struct pxa_i2c *i2c = adap->algo_data;
++
++	return i2c_pxa_internal_xfer(i2c, msgs, num, i2c_pxa_do_xfer);
++}
++
+ static u32 i2c_pxa_functionality(struct i2c_adapter *adap)
+ {
+ 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+@@ -1163,7 +1173,6 @@ static int i2c_pxa_pio_xfer(struct i2c_a
+ 			    struct i2c_msg msgs[], int num)
+ {
+ 	struct pxa_i2c *i2c = adap->algo_data;
+-	int ret, i;
+ 
+ 	/* If the I2C controller is disabled we need to reset it
+ 	  (probably due to a suspend/resume destroying state). We do
+@@ -1172,20 +1181,7 @@ static int i2c_pxa_pio_xfer(struct i2c_a
+ 	if (!(readl(_ICR(i2c)) & ICR_IUE))
+ 		i2c_pxa_reset(i2c);
+ 
+-	for (i = adap->retries; i >= 0; i--) {
+-		ret = i2c_pxa_do_pio_xfer(i2c, msgs, num);
+-		if (ret != I2C_RETRY)
+-			goto out;
+-
+-		if (i2c_debug)
+-			dev_dbg(&adap->dev, "Retrying transmission\n");
+-		udelay(100);
+-	}
+-	i2c_pxa_scream_blue_murder(i2c, "exhausted retries");
+-	ret = -EREMOTEIO;
+- out:
+-	i2c_pxa_set_slave(i2c, ret);
+-	return ret;
++	return i2c_pxa_internal_xfer(i2c, msgs, num, i2c_pxa_do_pio_xfer);
+ }
+ 
+ static const struct i2c_algorithm i2c_pxa_pio_algorithm = {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/816-v5.8-i2c-pxa-avoid-complaints-with-non-responsive-slaves.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/816-v5.8-i2c-pxa-avoid-complaints-with-non-responsive-slaves.patch
new file mode 100644
index 0000000..63e6db8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/816-v5.8-i2c-pxa-avoid-complaints-with-non-responsive-slaves.patch
@@ -0,0 +1,67 @@
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Bcc: linux@mail.armlinux.org.uk
+Subject: [PATCH 2/7] i2c: pxa: avoid complaints with non-responsive slaves
+MIME-Version: 1.0
+Content-Disposition: inline
+Content-Transfer-Encoding: 8bit
+Content-Type: text/plain; charset="utf-8"
+
+Running i2cdetect on a PXA I2C adapter is very noisy; it complains
+whenever a slave fails to respond to the address cycle.  Since it is
+normal to probe for slaves in this way, we should not fill the kernel
+log.  This is especially true with SFP modules that take a while to
+respond on the I2C bus, and probing via the I2C bus is the only way to
+detect that they are ready.
+
+Fix this by changing the internal transfer return code from I2C_RETRY
+to a new NO_SLAVE code (mapped to -ENXIO, as per the I2C documentation
+for this condition, but we still return -EREMOTEIO to the I2C stack to
+maintain long established driver behaviour.)
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/i2c/busses/i2c-pxa.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-pxa.c
++++ b/drivers/i2c/busses/i2c-pxa.c
+@@ -91,6 +91,7 @@
+  */
+ #define DEF_TIMEOUT             32
+ 
++#define NO_SLAVE		(-ENXIO)
+ #define BUS_ERROR               (-EREMOTEIO)
+ #define XFER_NAKED              (-ECONNREFUSED)
+ #define I2C_RETRY               (-2000) /* an error has occurred retry transmit */
+@@ -838,7 +839,7 @@ static void i2c_pxa_irq_txempty(struct p
+ 		 */
+ 		if (isr & ISR_ACKNAK) {
+ 			if (i2c->msg_ptr == 0 && i2c->msg_idx == 0)
+-				ret = I2C_RETRY;
++				ret = NO_SLAVE;
+ 			else
+ 				ret = XFER_NAKED;
+ 		}
+@@ -1066,16 +1067,19 @@ static int i2c_pxa_internal_xfer(struct
+ {
+ 	int ret, i;
+ 
+-	for (i = i2c->adap.retries; i >= 0; i--) {
++	for (i = 0; ; ) {
+ 		ret = xfer(i2c, msgs, num);
+-		if (ret != I2C_RETRY)
++		if (ret != I2C_RETRY && ret != NO_SLAVE)
+ 			goto out;
++		if (++i >= i2c->adap.retries)
++			break;
+ 
+ 		if (i2c_debug)
+ 			dev_dbg(&i2c->adap.dev, "Retrying transmission\n");
+ 		udelay(100);
+ 	}
+-	i2c_pxa_scream_blue_murder(i2c, "exhausted retries");
++	if (ret != NO_SLAVE)
++		i2c_pxa_scream_blue_murder(i2c, "exhausted retries");
+ 	ret = -EREMOTEIO;
+  out:
+ 	i2c_pxa_set_slave(i2c, ret);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/817-v5.8-i2c-pxa-ensure-timeout-messages-are-unique.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/817-v5.8-i2c-pxa-ensure-timeout-messages-are-unique.patch
new file mode 100644
index 0000000..37a77b6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/817-v5.8-i2c-pxa-ensure-timeout-messages-are-unique.patch
@@ -0,0 +1,45 @@
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Bcc: linux@mail.armlinux.org.uk
+Subject: [PATCH 3/7] i2c: pxa: ensure timeout messages are unique
+MIME-Version: 1.0
+Content-Disposition: inline
+Content-Transfer-Encoding: 8bit
+Content-Type: text/plain; charset="utf-8"
+
+Ensure that the various timeout messages can identify where in the code
+they were produced from to aid debugging.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/i2c/busses/i2c-pxa.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-pxa.c
++++ b/drivers/i2c/busses/i2c-pxa.c
+@@ -1052,7 +1052,7 @@ static int i2c_pxa_do_xfer(struct pxa_i2
+ 	ret = i2c->msg_idx;
+ 
+ 	if (!timeout && i2c->msg_num) {
+-		i2c_pxa_scream_blue_murder(i2c, "timeout");
++		i2c_pxa_scream_blue_murder(i2c, "timeout with active message");
+ 		ret = I2C_RETRY;
+ 	}
+ 
+@@ -1122,7 +1122,7 @@ static int i2c_pxa_pio_set_master(struct
+ 	if (timeout < 0) {
+ 		show_state(i2c);
+ 		dev_err(&i2c->adap.dev,
+-			"i2c_pxa: timeout waiting for bus free\n");
++			"i2c_pxa: timeout waiting for bus free (set_master)\n");
+ 		return I2C_RETRY;
+ 	}
+ 
+@@ -1166,7 +1166,7 @@ static int i2c_pxa_do_pio_xfer(struct px
+ 
+ out:
+ 	if (timeout == 0) {
+-		i2c_pxa_scream_blue_murder(i2c, "timeout");
++		i2c_pxa_scream_blue_murder(i2c, "timeout (do_pio_xfer)");
+ 		ret = I2C_RETRY;
+ 	}
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/818-v5.8-i2c-pxa-remove-some-unnecessary-debug.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/818-v5.8-i2c-pxa-remove-some-unnecessary-debug.patch
new file mode 100644
index 0000000..5438588
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/818-v5.8-i2c-pxa-remove-some-unnecessary-debug.patch
@@ -0,0 +1,34 @@
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Bcc: linux@mail.armlinux.org.uk
+Subject: [PATCH 4/7] i2c: pxa: remove some unnecessary debug
+MIME-Version: 1.0
+Content-Disposition: inline
+Content-Transfer-Encoding: 8bit
+Content-Type: text/plain; charset="utf-8"
+
+Remove unnecessary show_state() in the loop inside
+i2c_pxa_pio_set_master(), which can be unnecessarily verbose.
+
+Remove the i2c_pxa_scream_blue_murder() in i2c_pxa_pio_xfer(), which
+will trigger if we are probing the I2C bus and a slave does not
+respond; this is a normal event, and not something to report.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/i2c/busses/i2c-pxa.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-pxa.c
++++ b/drivers/i2c/busses/i2c-pxa.c
+@@ -1114,10 +1114,8 @@ static int i2c_pxa_pio_set_master(struct
+ 	/*
+ 	 * Wait for the bus to become free.
+ 	 */
+-	while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) {
++	while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB))
+ 		udelay(1000);
+-		show_state(i2c);
+-	}
+ 
+ 	if (timeout < 0) {
+ 		show_state(i2c);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/820-v5.8-i2c-pxa-use-master-abort-for-device-probes.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/820-v5.8-i2c-pxa-use-master-abort-for-device-probes.patch
new file mode 100644
index 0000000..cde9e3f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/820-v5.8-i2c-pxa-use-master-abort-for-device-probes.patch
@@ -0,0 +1,35 @@
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Bcc: linux@mail.armlinux.org.uk
+Subject: [PATCH 6/7] i2c: pxa: use master-abort for device probes
+MIME-Version: 1.0
+Content-Disposition: inline
+Content-Transfer-Encoding: 8bit
+Content-Type: text/plain; charset="utf-8"
+
+Use master-abort to send the stop condition after an address cycle
+rather than resetting the controller.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/i2c/busses/i2c-pxa.c | 10 ++--------
+ 1 file changed, 2 insertions(+), 8 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-pxa.c
++++ b/drivers/i2c/busses/i2c-pxa.c
+@@ -899,14 +899,8 @@ static void i2c_pxa_irq_txempty(struct p
+ 		icr &= ~ICR_ALDIE;
+ 		icr |= ICR_START | ICR_TB;
+ 	} else {
+-		if (i2c->msg->len == 0) {
+-			/*
+-			 * Device probes have a message length of zero
+-			 * and need the bus to be reset before it can
+-			 * be used again.
+-			 */
+-			i2c_pxa_reset(i2c);
+-		}
++		if (i2c->msg->len == 0)
++			icr |= ICR_MA;
+ 		i2c_pxa_master_complete(i2c, 0);
+ 	}
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/821-v5.8-i2c-pxa-implement-generic-i2c-bus-recovery.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/821-v5.8-i2c-pxa-implement-generic-i2c-bus-recovery.patch
new file mode 100644
index 0000000..592b763
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/821-v5.8-i2c-pxa-implement-generic-i2c-bus-recovery.patch
@@ -0,0 +1,285 @@
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Bcc: linux@mail.armlinux.org.uk
+Subject: [PATCH 7/7] i2c: pxa: implement generic i2c bus recovery
+MIME-Version: 1.0
+Content-Disposition: inline
+Content-Transfer-Encoding: 8bit
+Content-Type: text/plain; charset="utf-8"
+
+Implement generic GPIO-based I2C bus recovery for the PXA I2C driver.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/i2c/busses/i2c-pxa.c | 176 +++++++++++++++++++++++++++++++----
+ 1 file changed, 159 insertions(+), 17 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-pxa.c
++++ b/drivers/i2c/busses/i2c-pxa.c
+@@ -20,6 +20,7 @@
+ #include <linux/delay.h>
+ #include <linux/err.h>
+ #include <linux/errno.h>
++#include <linux/gpio/consumer.h>
+ #include <linux/i2c.h>
+ #include <linux/i2c-pxa.h>
+ #include <linux/init.h>
+@@ -29,6 +30,7 @@
+ #include <linux/module.h>
+ #include <linux/of.h>
+ #include <linux/of_device.h>
++#include <linux/pinctrl/consumer.h>
+ #include <linux/platform_device.h>
+ #include <linux/platform_data/i2c-pxa.h>
+ #include <linux/slab.h>
+@@ -261,6 +263,11 @@ struct pxa_i2c {
+ 	bool			highmode_enter;
+ 	u32			fm_mask;
+ 	u32			hs_mask;
++
++	struct i2c_bus_recovery_info recovery;
++	struct pinctrl		*pinctrl;
++	struct pinctrl_state	*pinctrl_default;
++	struct pinctrl_state	*pinctrl_recovery;
+ };
+ 
+ #define _IBMR(i2c)	((i2c)->reg_ibmr)
+@@ -560,13 +567,8 @@ static void i2c_pxa_set_slave(struct pxa
+ #define i2c_pxa_set_slave(i2c, err)	do { } while (0)
+ #endif
+ 
+-static void i2c_pxa_reset(struct pxa_i2c *i2c)
++static void i2c_pxa_do_reset(struct pxa_i2c *i2c)
+ {
+-	pr_debug("Resetting I2C Controller Unit\n");
+-
+-	/* abort any transfer currently under way */
+-	i2c_pxa_abort(i2c);
+-
+ 	/* reset according to 9.8 */
+ 	writel(ICR_UR, _ICR(i2c));
+ 	writel(I2C_ISR_INIT, _ISR(i2c));
+@@ -585,12 +587,25 @@ static void i2c_pxa_reset(struct pxa_i2c
+ #endif
+ 
+ 	i2c_pxa_set_slave(i2c, 0);
++}
+ 
++static void i2c_pxa_enable(struct pxa_i2c *i2c)
++{
+ 	/* enable unit */
+ 	writel(readl(_ICR(i2c)) | ICR_IUE, _ICR(i2c));
+ 	udelay(100);
+ }
+ 
++static void i2c_pxa_reset(struct pxa_i2c *i2c)
++{
++	pr_debug("Resetting I2C Controller Unit\n");
++
++	/* abort any transfer currently under way */
++	i2c_pxa_abort(i2c);
++	i2c_pxa_do_reset(i2c);
++	i2c_pxa_enable(i2c);
++}
++
+ 
+ #ifdef CONFIG_I2C_PXA_SLAVE
+ /*
+@@ -1002,6 +1017,7 @@ static int i2c_pxa_do_xfer(struct pxa_i2
+ 	ret = i2c_pxa_wait_bus_not_busy(i2c);
+ 	if (ret) {
+ 		dev_err(&i2c->adap.dev, "i2c_pxa: timeout waiting for bus free\n");
++		i2c_recover_bus(&i2c->adap);
+ 		goto out;
+ 	}
+ 
+@@ -1047,6 +1063,7 @@ static int i2c_pxa_do_xfer(struct pxa_i2
+ 
+ 	if (!timeout && i2c->msg_num) {
+ 		i2c_pxa_scream_blue_murder(i2c, "timeout with active message");
++		i2c_recover_bus(&i2c->adap);
+ 		ret = I2C_RETRY;
+ 	}
+ 
+@@ -1228,6 +1245,129 @@ static int i2c_pxa_probe_pdata(struct pl
+ 	return 0;
+ }
+ 
++static void i2c_pxa_prepare_recovery(struct i2c_adapter *adap)
++{
++	struct pxa_i2c *i2c = adap->algo_data;
++	u32 ibmr = readl(_IBMR(i2c));
++
++	/*
++	 * Program the GPIOs to reflect the current I2C bus state while
++	 * we transition to recovery; this avoids glitching the bus.
++	 */
++	gpiod_set_value(i2c->recovery.scl_gpiod, ibmr & IBMR_SCLS);
++	gpiod_set_value(i2c->recovery.sda_gpiod, ibmr & IBMR_SDAS);
++
++	WARN_ON(pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_recovery));
++}
++
++static void i2c_pxa_unprepare_recovery(struct i2c_adapter *adap)
++{
++	struct pxa_i2c *i2c = adap->algo_data;
++	u32 isr;
++
++	/*
++	 * The bus should now be free. Clear up the I2C controller before
++	 * handing control of the bus back to avoid the bus changing state.
++	 */
++	isr = readl(_ISR(i2c));
++	if (isr & (ISR_UB | ISR_IBB)) {
++		dev_dbg(&i2c->adap.dev,
++			"recovery: resetting controller, ISR=0x%08x\n", isr);
++		i2c_pxa_do_reset(i2c);
++	}
++
++	WARN_ON(pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_default));
++
++	dev_dbg(&i2c->adap.dev, "recovery: IBMR 0x%08x ISR 0x%08x\n",
++	        readl(_IBMR(i2c)), readl(_ISR(i2c)));
++
++	i2c_pxa_enable(i2c);
++}
++
++static int i2c_pxa_init_recovery(struct pxa_i2c *i2c)
++{
++	struct i2c_bus_recovery_info *bri = &i2c->recovery;
++	struct device *dev = i2c->adap.dev.parent;
++
++	/*
++	 * When slave mode is enabled, we are not the only master on the bus.
++	 * Bus recovery can only be performed when we are the master, which
++	 * we can't be certain of. Therefore, when slave mode is enabled, do
++	 * not configure bus recovery.
++	 */
++	if (IS_ENABLED(CONFIG_I2C_PXA_SLAVE))
++		return 0;
++
++	i2c->pinctrl = devm_pinctrl_get(dev);
++	if (IS_ERR(i2c->pinctrl))
++		return PTR_ERR(i2c->pinctrl);
++
++	if (!i2c->pinctrl)
++		return 0;
++
++	i2c->pinctrl_default = pinctrl_lookup_state(i2c->pinctrl,
++						    PINCTRL_STATE_DEFAULT);
++	i2c->pinctrl_recovery = pinctrl_lookup_state(i2c->pinctrl, "recovery");
++
++	if (IS_ERR(i2c->pinctrl_default) || IS_ERR(i2c->pinctrl_recovery)) {
++		dev_info(dev, "missing pinmux recovery information: %ld %ld\n",
++			 PTR_ERR(i2c->pinctrl_default),
++			 PTR_ERR(i2c->pinctrl_recovery));
++		return 0;
++	}
++
++	/*
++	 * Claiming GPIOs can influence the pinmux state, and may glitch the
++	 * I2C bus. Do this carefully.
++	 */
++	bri->scl_gpiod = devm_gpiod_get(dev, "scl", GPIOD_OUT_HIGH_OPEN_DRAIN);
++	if (bri->scl_gpiod == ERR_PTR(-EPROBE_DEFER))
++		return -EPROBE_DEFER;
++	if (IS_ERR(bri->scl_gpiod)) {
++		dev_info(dev, "missing scl gpio recovery information: %pe\n",
++			 bri->scl_gpiod);
++		return 0;
++	}
++
++	/*
++	 * We have SCL. Pull SCL low and wait a bit so that SDA glitches
++	 * have no effect.
++	 */
++	gpiod_direction_output(bri->scl_gpiod, 0);
++	udelay(10);
++	bri->sda_gpiod = devm_gpiod_get(dev, "sda", GPIOD_OUT_HIGH_OPEN_DRAIN);
++
++	/* Wait a bit in case of a SDA glitch, and then release SCL. */
++	udelay(10);
++	gpiod_direction_output(bri->scl_gpiod, 1);
++
++	if (bri->sda_gpiod == ERR_PTR(-EPROBE_DEFER))
++		return -EPROBE_DEFER;
++
++	if (IS_ERR(bri->sda_gpiod)) {
++		dev_info(dev, "missing sda gpio recovery information: %pe\n",
++			 bri->sda_gpiod);
++		return 0;
++	}
++
++	bri->prepare_recovery = i2c_pxa_prepare_recovery;
++	bri->unprepare_recovery = i2c_pxa_unprepare_recovery;
++	bri->recover_bus = i2c_generic_scl_recovery;
++
++	i2c->adap.bus_recovery_info = bri;
++
++	/*
++	 * Claiming GPIOs can change the pinmux state, which confuses the
++	 * pinctrl since pinctrl's idea of the current setting is unaffected
++	 * by the pinmux change caused by claiming the GPIO. Work around that
++	 * by switching pinctrl to the GPIO state here. We do it this way to
++	 * avoid glitching the I2C bus.
++	 */
++	pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_recovery);
++
++	return pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_default);
++}
++
+ static int i2c_pxa_probe(struct platform_device *dev)
+ {
+ 	struct i2c_pxa_platform_data *plat = dev_get_platdata(&dev->dev);
+@@ -1240,6 +1380,16 @@ static int i2c_pxa_probe(struct platform
+ 	if (!i2c)
+ 		return -ENOMEM;
+ 
++	/* Default adapter num to device id; i2c_pxa_probe_dt can override. */
++	i2c->adap.nr = dev->id;
++	i2c->adap.owner   = THIS_MODULE;
++	i2c->adap.retries = 5;
++	i2c->adap.algo_data = i2c;
++	i2c->adap.dev.parent = &dev->dev;
++#ifdef CONFIG_OF
++	i2c->adap.dev.of_node = dev->dev.of_node;
++#endif
++
+ 	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ 	i2c->reg_base = devm_ioremap_resource(&dev->dev, res);
+ 	if (IS_ERR(i2c->reg_base))
+@@ -1251,8 +1401,9 @@ static int i2c_pxa_probe(struct platform
+ 		return irq;
+ 	}
+ 
+-	/* Default adapter num to device id; i2c_pxa_probe_dt can override. */
+-	i2c->adap.nr = dev->id;
++	ret = i2c_pxa_init_recovery(i2c);
++	if (ret)
++		return ret;
+ 
+ 	ret = i2c_pxa_probe_dt(dev, i2c, &i2c_type);
+ 	if (ret > 0)
+@@ -1260,9 +1411,6 @@ static int i2c_pxa_probe(struct platform
+ 	if (ret < 0)
+ 		return ret;
+ 
+-	i2c->adap.owner   = THIS_MODULE;
+-	i2c->adap.retries = 5;
+-
+ 	spin_lock_init(&i2c->lock);
+ 	init_waitqueue_head(&i2c->wait);
+ 
+@@ -1332,12 +1480,6 @@ static int i2c_pxa_probe(struct platform
+ 
+ 	i2c_pxa_reset(i2c);
+ 
+-	i2c->adap.algo_data = i2c;
+-	i2c->adap.dev.parent = &dev->dev;
+-#ifdef CONFIG_OF
+-	i2c->adap.dev.of_node = dev->dev.of_node;
+-#endif
+-
+ 	ret = i2c_add_numbered_adapter(&i2c->adap);
+ 	if (ret < 0)
+ 		goto ereqirq;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/825-v5.8-spi-rb4xx-null-pointer-bug-fix.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/825-v5.8-spi-rb4xx-null-pointer-bug-fix.patch
new file mode 100644
index 0000000..71e26d5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/825-v5.8-spi-rb4xx-null-pointer-bug-fix.patch
@@ -0,0 +1,48 @@
+From: Christopher Hill <ch6574@gmail.com>
+To: Mark Brown <broonie@kernel.org>
+Cc: Christopher Hill <ch6574@gmail.com>, linux-spi@vger.kernel.org,
+        linux-kernel@vger.kernel.org
+Subject: [PATCH 1/3] spi: rb4xx: null pointer bug fix
+Date: Thu, 21 May 2020 14:36:29 -0400
+Message-Id: <20200521183631.37806-1-ch6574@gmail.com>
+X-Mailer: git-send-email 2.25.1
+MIME-Version: 1.0
+Sender: linux-spi-owner@vger.kernel.org
+Precedence: bulk
+List-ID: <linux-spi.vger.kernel.org>
+X-Mailing-List: linux-spi@vger.kernel.org
+
+This patch fixes a null pointer bug in the spi driver spi-rb4xx.c by
+moving the private data initialization to earlier in probe
+
+Signed-off-by: Christopher Hill <ch6574@gmail.com>
+---
+ drivers/spi/spi-rb4xx.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/spi/spi-rb4xx.c
++++ b/drivers/spi/spi-rb4xx.c
+@@ -158,6 +158,11 @@ static int rb4xx_spi_probe(struct platfo
+ 	master->transfer_one = rb4xx_transfer_one;
+ 	master->set_cs = rb4xx_set_cs;
+ 
++	rbspi = spi_master_get_devdata(master);
++	rbspi->base = spi_base;
++	rbspi->clk = ahb_clk;
++	platform_set_drvdata(pdev, rbspi);
++
+ 	err = devm_spi_register_master(&pdev->dev, master);
+ 	if (err) {
+ 		dev_err(&pdev->dev, "failed to register SPI master\n");
+@@ -168,11 +173,6 @@ static int rb4xx_spi_probe(struct platfo
+ 	if (err)
+ 		return err;
+ 
+-	rbspi = spi_master_get_devdata(master);
+-	rbspi->base = spi_base;
+-	rbspi->clk = ahb_clk;
+-	platform_set_drvdata(pdev, rbspi);
+-
+ 	/* Enable SPI */
+ 	rb4xx_write(rbspi, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO);
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/826-v5.8-spi-rb4xx-update-driver-to-be-device-tree-aware.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/826-v5.8-spi-rb4xx-update-driver-to-be-device-tree-aware.patch
new file mode 100644
index 0000000..0ce4f2b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/826-v5.8-spi-rb4xx-update-driver-to-be-device-tree-aware.patch
@@ -0,0 +1,60 @@
+From: Christopher Hill <ch6574@gmail.com>
+To: Mark Brown <broonie@kernel.org>
+Cc: Christopher Hill <ch6574@gmail.com>, linux-spi@vger.kernel.org,
+        linux-kernel@vger.kernel.org
+Subject: [PATCH 2/3] spi: rb4xx: update driver to be device tree aware
+Date: Thu, 21 May 2020 14:36:30 -0400
+Message-Id: <20200521183631.37806-2-ch6574@gmail.com>
+X-Mailer: git-send-email 2.25.1
+In-Reply-To: <20200521183631.37806-1-ch6574@gmail.com>
+References: <20200521183631.37806-1-ch6574@gmail.com>
+MIME-Version: 1.0
+Sender: linux-spi-owner@vger.kernel.org
+Precedence: bulk
+List-ID: <linux-spi.vger.kernel.org>
+X-Mailing-List: linux-spi@vger.kernel.org
+
+This patch updates the spi driver spi-rb4xx.c to be device tree aware
+
+Signed-off-by: Christopher Hill <ch6574@gmail.com>
+---
+ drivers/spi/spi-rb4xx.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/spi/spi-rb4xx.c
++++ b/drivers/spi/spi-rb4xx.c
+@@ -14,6 +14,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/clk.h>
+ #include <linux/spi/spi.h>
++#include <linux/of.h>
+ 
+ #include <asm/mach-ath79/ar71xx_regs.h>
+ 
+@@ -150,6 +151,7 @@ static int rb4xx_spi_probe(struct platfo
+ 	if (IS_ERR(ahb_clk))
+ 		return PTR_ERR(ahb_clk);
+ 
++	master->dev.of_node = pdev->dev.of_node;
+ 	master->bus_num = 0;
+ 	master->num_chipselect = 3;
+ 	master->mode_bits = SPI_TX_DUAL;
+@@ -188,11 +190,18 @@ static int rb4xx_spi_remove(struct platf
+ 	return 0;
+ }
+ 
++static const struct of_device_id rb4xx_spi_dt_match[] = {
++	{ .compatible = "mikrotik,rb4xx-spi" },
++	{ },
++};
++MODULE_DEVICE_TABLE(of, rb4xx_spi_dt_match);
++
+ static struct platform_driver rb4xx_spi_drv = {
+ 	.probe = rb4xx_spi_probe,
+ 	.remove = rb4xx_spi_remove,
+ 	.driver = {
+ 		.name = "rb4xx-spi",
++		.of_match_table = of_match_ptr(rb4xx_spi_dt_match),
+ 	},
+ };
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/827-v5.16-spi-add-power-control-when-set_cs.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/827-v5.16-spi-add-power-control-when-set_cs.patch
new file mode 100644
index 0000000..f3e7940
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/827-v5.16-spi-add-power-control-when-set_cs.patch
@@ -0,0 +1,47 @@
+drivers: spi: backport PM improvement for SPI framework
+
+Fix PM improvement for SPI framework.
+As to set_cs takes effect immediately, power spi
+is needed when setup spi.
+
+(cherry picked from commit d948e6ca189985495a21cd622c31e30e72b6b688)
+Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/spi/spi.c?h=v5.16-rc4&id=d948e6ca189985495a21cd622c31e30e72b6b688
+(cherry picked from commit 57a9460705f105e1d79d1410c5cfe285beda8986)
+Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/spi/spi.c?h=v5.16-rc4&id=57a9460705f105e1d79d1410c5cfe285beda8986
+
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -3170,7 +3170,29 @@ int spi_setup(struct spi_device *spi)
+ 	if (spi->controller->setup)
+ 		status = spi->controller->setup(spi);
+ 
+-	spi_set_cs(spi, false);
++	if (spi->controller->auto_runtime_pm && spi->controller->set_cs) {
++		status = pm_runtime_get_sync(spi->controller->dev.parent);
++		if (status < 0) {
++			pm_runtime_put_noidle(spi->controller->dev.parent);
++			dev_err(&spi->controller->dev, "Failed to power device: %d\n",
++				status);
++			return status;
++		}
++
++		/*
++		 * We do not want to return positive value from pm_runtime_get,
++		 * there are many instances of devices calling spi_setup() and
++		 * checking for a non-zero return value instead of a negative
++		 * return value.
++		 */
++		status = 0;
++
++		spi_set_cs(spi, false);
++		pm_runtime_mark_last_busy(spi->controller->dev.parent);
++		pm_runtime_put_autosuspend(spi->controller->dev.parent);
++	} else {
++		spi_set_cs(spi, false);
++	}
+ 
+ 	if (spi->rt && !spi->controller->rt) {
+ 		spi->controller->rt = true;
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/831-v5.13-0001-firmware-bcm47xx_nvram-rename-finding-function-and-i.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/831-v5.13-0001-firmware-bcm47xx_nvram-rename-finding-function-and-i.patch
new file mode 100644
index 0000000..1993870
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/831-v5.13-0001-firmware-bcm47xx_nvram-rename-finding-function-and-i.patch
@@ -0,0 +1,80 @@
+From fb009cbdd0693bd633f11e99526617b3d392cfad Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Mon, 8 Mar 2021 10:03:16 +0100
+Subject: [PATCH] firmware: bcm47xx_nvram: rename finding function and its
+ variables
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+1. Use "bcm47xx_" function name prefix for consistency
+2. It takes flash start as argument so s/iobase/flash_start/
+3. "off" was used for finding flash end so just call it "flash_size"
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+---
+ drivers/firmware/broadcom/bcm47xx_nvram.c | 24 ++++++++++++-----------
+ 1 file changed, 13 insertions(+), 11 deletions(-)
+
+--- a/drivers/firmware/broadcom/bcm47xx_nvram.c
++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c
+@@ -48,11 +48,13 @@ static u32 find_nvram_size(void __iomem
+ 	return 0;
+ }
+ 
+-/* Probe for NVRAM header */
+-static int nvram_find_and_copy(void __iomem *iobase, u32 lim)
++/**
++ * bcm47xx_nvram_find_and_copy - find NVRAM on flash mapping & copy it
++ */
++static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_size)
+ {
+ 	struct nvram_header __iomem *header;
+-	u32 off;
++	size_t flash_size;
+ 	u32 size;
+ 
+ 	if (nvram_len) {
+@@ -61,25 +63,25 @@ static int nvram_find_and_copy(void __io
+ 	}
+ 
+ 	/* TODO: when nvram is on nand flash check for bad blocks first. */
+-	off = FLASH_MIN;
+-	while (off <= lim) {
++	flash_size = FLASH_MIN;
++	while (flash_size <= res_size) {
+ 		/* Windowed flash access */
+-		size = find_nvram_size(iobase + off);
++		size = find_nvram_size(flash_start + flash_size);
+ 		if (size) {
+-			header = (struct nvram_header *)(iobase + off - size);
++			header = (struct nvram_header *)(flash_start + flash_size - size);
+ 			goto found;
+ 		}
+-		off <<= 1;
++		flash_size <<= 1;
+ 	}
+ 
+ 	/* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
+-	header = (struct nvram_header *)(iobase + 4096);
++	header = (struct nvram_header *)(flash_start + 4096);
+ 	if (header->magic == NVRAM_MAGIC) {
+ 		size = NVRAM_SPACE;
+ 		goto found;
+ 	}
+ 
+-	header = (struct nvram_header *)(iobase + 1024);
++	header = (struct nvram_header *)(flash_start + 1024);
+ 	if (header->magic == NVRAM_MAGIC) {
+ 		size = NVRAM_SPACE;
+ 		goto found;
+@@ -124,7 +126,7 @@ int bcm47xx_nvram_init_from_mem(u32 base
+ 	if (!iobase)
+ 		return -ENOMEM;
+ 
+-	err = nvram_find_and_copy(iobase, lim);
++	err = bcm47xx_nvram_find_and_copy(iobase, lim);
+ 
+ 	iounmap(iobase);
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/831-v5.13-0002-firmware-bcm47xx_nvram-add-helper-checking-for-NVRAM.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/831-v5.13-0002-firmware-bcm47xx_nvram-add-helper-checking-for-NVRAM.patch
new file mode 100644
index 0000000..6ab0728
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/831-v5.13-0002-firmware-bcm47xx_nvram-add-helper-checking-for-NVRAM.patch
@@ -0,0 +1,90 @@
+From 0a24b51a3264a3f942a75025ea5ff6133c8989b0 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Mon, 8 Mar 2021 10:03:17 +0100
+Subject: [PATCH] firmware: bcm47xx_nvram: add helper checking for NVRAM
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This avoids duplicating code doing casting and checking for NVRAM magic.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+---
+ drivers/firmware/broadcom/bcm47xx_nvram.c | 30 ++++++++++++++---------
+ 1 file changed, 18 insertions(+), 12 deletions(-)
+
+--- a/drivers/firmware/broadcom/bcm47xx_nvram.c
++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c
+@@ -34,14 +34,20 @@ static char nvram_buf[NVRAM_SPACE];
+ static size_t nvram_len;
+ static const u32 nvram_sizes[] = {0x6000, 0x8000, 0xF000, 0x10000};
+ 
++/**
++ * bcm47xx_nvram_is_valid - check for a valid NVRAM at specified memory
++ */
++static bool bcm47xx_nvram_is_valid(void __iomem *nvram)
++{
++	return ((struct nvram_header *)nvram)->magic == NVRAM_MAGIC;
++}
++
+ static u32 find_nvram_size(void __iomem *end)
+ {
+-	struct nvram_header __iomem *header;
+ 	int i;
+ 
+ 	for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) {
+-		header = (struct nvram_header *)(end - nvram_sizes[i]);
+-		if (header->magic == NVRAM_MAGIC)
++		if (bcm47xx_nvram_is_valid(end - nvram_sizes[i]))
+ 			return nvram_sizes[i];
+ 	}
+ 
+@@ -55,6 +61,7 @@ static int bcm47xx_nvram_find_and_copy(v
+ {
+ 	struct nvram_header __iomem *header;
+ 	size_t flash_size;
++	size_t offset;
+ 	u32 size;
+ 
+ 	if (nvram_len) {
+@@ -68,31 +75,30 @@ static int bcm47xx_nvram_find_and_copy(v
+ 		/* Windowed flash access */
+ 		size = find_nvram_size(flash_start + flash_size);
+ 		if (size) {
+-			header = (struct nvram_header *)(flash_start + flash_size - size);
++			offset = flash_size - size;
+ 			goto found;
+ 		}
+ 		flash_size <<= 1;
+ 	}
+ 
+ 	/* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
+-	header = (struct nvram_header *)(flash_start + 4096);
+-	if (header->magic == NVRAM_MAGIC) {
+-		size = NVRAM_SPACE;
++
++	offset = 4096;
++	if (bcm47xx_nvram_is_valid(flash_start + offset))
+ 		goto found;
+-	}
+ 
+-	header = (struct nvram_header *)(flash_start + 1024);
+-	if (header->magic == NVRAM_MAGIC) {
+-		size = NVRAM_SPACE;
++	offset = 1024;
++	if (bcm47xx_nvram_is_valid(flash_start + offset))
+ 		goto found;
+-	}
+ 
+ 	pr_err("no nvram found\n");
+ 	return -ENXIO;
+ 
+ found:
++	header = (struct nvram_header *)(flash_start + offset);
+ 	__ioread32_copy(nvram_buf, header, sizeof(*header) / 4);
+ 	nvram_len = ((struct nvram_header *)(nvram_buf))->len;
++	size = res_size - offset;
+ 	if (nvram_len > size) {
+ 		pr_err("The nvram size according to the header seems to be bigger than the partition on flash\n");
+ 		nvram_len = size;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/831-v5.13-0003-firmware-bcm47xx_nvram-extract-code-copying-NVRAM.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/831-v5.13-0003-firmware-bcm47xx_nvram-extract-code-copying-NVRAM.patch
new file mode 100644
index 0000000..a1351f1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/831-v5.13-0003-firmware-bcm47xx_nvram-extract-code-copying-NVRAM.patch
@@ -0,0 +1,80 @@
+From 298923cf999cecd2ef06df126f85a3d68da8c4d8 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Mon, 8 Mar 2021 10:03:18 +0100
+Subject: [PATCH] firmware: bcm47xx_nvram: extract code copying NVRAM
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This simplifies function finding NVRAM. It doesn't directly deal with
+NVRAM structure anymore and is a bit smaller.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+---
+ drivers/firmware/broadcom/bcm47xx_nvram.c | 43 +++++++++++++----------
+ 1 file changed, 25 insertions(+), 18 deletions(-)
+
+--- a/drivers/firmware/broadcom/bcm47xx_nvram.c
++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c
+@@ -55,11 +55,34 @@ static u32 find_nvram_size(void __iomem
+ }
+ 
+ /**
++ * bcm47xx_nvram_copy - copy NVRAM to internal buffer
++ */
++static void bcm47xx_nvram_copy(void __iomem *nvram_start, size_t res_size)
++{
++	struct nvram_header __iomem *header = nvram_start;
++	size_t copy_size;
++
++	copy_size = header->len;
++	if (copy_size > res_size) {
++		pr_err("The nvram size according to the header seems to be bigger than the partition on flash\n");
++		copy_size = res_size;
++	}
++	if (copy_size >= NVRAM_SPACE) {
++		pr_err("nvram on flash (%zu bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n",
++		       copy_size, NVRAM_SPACE - 1);
++		copy_size = NVRAM_SPACE - 1;
++	}
++
++	__ioread32_copy(nvram_buf, nvram_start, DIV_ROUND_UP(copy_size, 4));
++	nvram_buf[NVRAM_SPACE - 1] = '\0';
++	nvram_len = copy_size;
++}
++
++/**
+  * bcm47xx_nvram_find_and_copy - find NVRAM on flash mapping & copy it
+  */
+ static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_size)
+ {
+-	struct nvram_header __iomem *header;
+ 	size_t flash_size;
+ 	size_t offset;
+ 	u32 size;
+@@ -95,23 +118,7 @@ static int bcm47xx_nvram_find_and_copy(v
+ 	return -ENXIO;
+ 
+ found:
+-	header = (struct nvram_header *)(flash_start + offset);
+-	__ioread32_copy(nvram_buf, header, sizeof(*header) / 4);
+-	nvram_len = ((struct nvram_header *)(nvram_buf))->len;
+-	size = res_size - offset;
+-	if (nvram_len > size) {
+-		pr_err("The nvram size according to the header seems to be bigger than the partition on flash\n");
+-		nvram_len = size;
+-	}
+-	if (nvram_len >= NVRAM_SPACE) {
+-		pr_err("nvram on flash (%zu bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n",
+-		       nvram_len, NVRAM_SPACE - 1);
+-		nvram_len = NVRAM_SPACE - 1;
+-	}
+-	/* proceed reading data after header */
+-	__ioread32_copy(nvram_buf + sizeof(*header), header + 1,
+-			DIV_ROUND_UP(nvram_len, 4));
+-	nvram_buf[NVRAM_SPACE - 1] = '\0';
++	bcm47xx_nvram_copy(flash_start + offset, res_size - offset);
+ 
+ 	return 0;
+ }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/831-v5.13-0004-firmware-bcm47xx_nvram-look-for-NVRAM-with-for-inste.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/831-v5.13-0004-firmware-bcm47xx_nvram-look-for-NVRAM-with-for-inste.patch
new file mode 100644
index 0000000..059a132
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/831-v5.13-0004-firmware-bcm47xx_nvram-look-for-NVRAM-with-for-inste.patch
@@ -0,0 +1,37 @@
+From 98b68324f67236e8c9152976535dc1f27fb67ba8 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Mon, 8 Mar 2021 10:03:19 +0100
+Subject: [PATCH] firmware: bcm47xx_nvram: look for NVRAM with for instead of
+ while
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This loop requires variable initialization, stop condition and post
+iteration increment. It's pretty much a for loop definition.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+---
+ drivers/firmware/broadcom/bcm47xx_nvram.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/firmware/broadcom/bcm47xx_nvram.c
++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c
+@@ -93,15 +93,13 @@ static int bcm47xx_nvram_find_and_copy(v
+ 	}
+ 
+ 	/* TODO: when nvram is on nand flash check for bad blocks first. */
+-	flash_size = FLASH_MIN;
+-	while (flash_size <= res_size) {
++	for (flash_size = FLASH_MIN; flash_size <= res_size; flash_size <<= 1) {
+ 		/* Windowed flash access */
+ 		size = find_nvram_size(flash_start + flash_size);
+ 		if (size) {
+ 			offset = flash_size - size;
+ 			goto found;
+ 		}
+-		flash_size <<= 1;
+ 	}
+ 
+ 	/* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/831-v5.13-0005-firmware-bcm47xx_nvram-inline-code-checking-NVRAM-si.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/831-v5.13-0005-firmware-bcm47xx_nvram-inline-code-checking-NVRAM-si.patch
new file mode 100644
index 0000000..21d2500
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/831-v5.13-0005-firmware-bcm47xx_nvram-inline-code-checking-NVRAM-si.patch
@@ -0,0 +1,70 @@
+From f52da4ccfec9192e17f5c16260dfdd6d3ea76f65 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Mon, 8 Mar 2021 10:03:20 +0100
+Subject: [PATCH] firmware: bcm47xx_nvram: inline code checking NVRAM size
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Separated function was not improving code quality much (or at all).
+Moreover it expected possible flash end address as argument and it was
+returning NVRAM size.
+
+The new code always operates on offsets which means less logic and less
+calculations.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+---
+ drivers/firmware/broadcom/bcm47xx_nvram.c | 25 +++++++----------------
+ 1 file changed, 7 insertions(+), 18 deletions(-)
+
+--- a/drivers/firmware/broadcom/bcm47xx_nvram.c
++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c
+@@ -42,18 +42,6 @@ static bool bcm47xx_nvram_is_valid(void
+ 	return ((struct nvram_header *)nvram)->magic == NVRAM_MAGIC;
+ }
+ 
+-static u32 find_nvram_size(void __iomem *end)
+-{
+-	int i;
+-
+-	for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) {
+-		if (bcm47xx_nvram_is_valid(end - nvram_sizes[i]))
+-			return nvram_sizes[i];
+-	}
+-
+-	return 0;
+-}
+-
+ /**
+  * bcm47xx_nvram_copy - copy NVRAM to internal buffer
+  */
+@@ -85,7 +73,7 @@ static int bcm47xx_nvram_find_and_copy(v
+ {
+ 	size_t flash_size;
+ 	size_t offset;
+-	u32 size;
++	int i;
+ 
+ 	if (nvram_len) {
+ 		pr_warn("nvram already initialized\n");
+@@ -93,12 +81,13 @@ static int bcm47xx_nvram_find_and_copy(v
+ 	}
+ 
+ 	/* TODO: when nvram is on nand flash check for bad blocks first. */
++
++	/* Try every possible flash size and check for NVRAM at its end */
+ 	for (flash_size = FLASH_MIN; flash_size <= res_size; flash_size <<= 1) {
+-		/* Windowed flash access */
+-		size = find_nvram_size(flash_start + flash_size);
+-		if (size) {
+-			offset = flash_size - size;
+-			goto found;
++		for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) {
++			offset = flash_size - nvram_sizes[i];
++			if (bcm47xx_nvram_is_valid(flash_start + offset))
++				goto found;
+ 		}
+ 	}
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/852-v5.10-0001-net-sfp-VSOL-V2801F-CarlitoxxPro-CPGOS03-0490-v2.0-w.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/852-v5.10-0001-net-sfp-VSOL-V2801F-CarlitoxxPro-CPGOS03-0490-v2.0-w.patch
new file mode 100644
index 0000000..1901054
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/852-v5.10-0001-net-sfp-VSOL-V2801F-CarlitoxxPro-CPGOS03-0490-v2.0-w.patch
@@ -0,0 +1,144 @@
+From 0d035bed2a4a6c4878518749348be61bf082d12a Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Wed, 9 Dec 2020 11:22:49 +0000
+Subject: [PATCH] net: sfp: VSOL V2801F / CarlitoxxPro CPGOS03-0490 v2.0
+ workaround
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add a workaround for the detection of VSOL V2801F / CarlitoxxPro
+CPGOS03-0490 v2.0 GPON module which CarlitoxxPro states needs single
+byte I2C reads to the EEPROM.
+
+Pali Rohár reports that he also has a CarlitoxxPro-based V2801F module,
+which reports a manufacturer of "OEM". This manufacturer can't be
+matched as it appears in many different modules, so also match the part
+number too.
+
+Reported-by: Thomas Schreiber <tschreibe@gmail.com>
+Reported-by: Pali Rohár <pali@kernel.org>
+Tested-by: Pali Rohár <pali@kernel.org>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/sfp.c | 63 +++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 58 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -191,6 +191,7 @@ struct sfp {
+ 	struct sfp_bus *sfp_bus;
+ 	struct phy_device *mod_phy;
+ 	const struct sff_data *type;
++	size_t i2c_block_size;
+ 	u32 max_power_mW;
+ 
+ 	unsigned int (*get_state)(struct sfp *);
+@@ -305,10 +306,19 @@ static int sfp_i2c_read(struct sfp *sfp,
+ 			size_t len)
+ {
+ 	struct i2c_msg msgs[2];
+-	u8 bus_addr = a2 ? 0x51 : 0x50;
++	size_t block_size;
+ 	size_t this_len;
++	u8 bus_addr;
+ 	int ret;
+ 
++	if (a2) {
++		block_size = 16;
++		bus_addr = 0x51;
++	} else {
++		block_size = sfp->i2c_block_size;
++		bus_addr = 0x50;
++	}
++
+ 	msgs[0].addr = bus_addr;
+ 	msgs[0].flags = 0;
+ 	msgs[0].len = 1;
+@@ -320,8 +330,8 @@ static int sfp_i2c_read(struct sfp *sfp,
+ 
+ 	while (len) {
+ 		this_len = len;
+-		if (this_len > 16)
+-			this_len = 16;
++		if (this_len > block_size)
++			this_len = block_size;
+ 
+ 		msgs[1].len = this_len;
+ 
+@@ -1569,6 +1579,28 @@ static int sfp_sm_mod_hpower(struct sfp
+ 	return 0;
+ }
+ 
++/* Some modules (Nokia 3FE46541AA) lock up if byte 0x51 is read as a
++ * single read. Switch back to reading 16 byte blocks unless we have
++ * a CarlitoxxPro module (rebranded VSOL V2801F). Even more annoyingly,
++ * some VSOL V2801F have the vendor name changed to OEM.
++ */
++static int sfp_quirk_i2c_block_size(const struct sfp_eeprom_base *base)
++{
++	if (!memcmp(base->vendor_name, "VSOL            ", 16))
++		return 1;
++	if (!memcmp(base->vendor_name, "OEM             ", 16) &&
++	    !memcmp(base->vendor_pn,   "V2801F          ", 16))
++		return 1;
++
++	/* Some modules can't cope with long reads */
++	return 16;
++}
++
++static void sfp_quirks_base(struct sfp *sfp, const struct sfp_eeprom_base *base)
++{
++	sfp->i2c_block_size = sfp_quirk_i2c_block_size(base);
++}
++
+ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
+ {
+ 	/* SFP module inserted - read I2C data */
+@@ -1577,14 +1609,20 @@ static int sfp_sm_mod_probe(struct sfp *
+ 	u8 check;
+ 	int ret;
+ 
+-	ret = sfp_read(sfp, false, 0, &id, sizeof(id));
++	/* Some modules (CarlitoxxPro CPGOS03-0490) do not support multibyte
++	 * reads from the EEPROM, so start by reading the base identifying
++	 * information one byte at a time.
++	 */
++	sfp->i2c_block_size = 1;
++
++	ret = sfp_read(sfp, false, 0, &id.base, sizeof(id.base));
+ 	if (ret < 0) {
+ 		if (report)
+ 			dev_err(sfp->dev, "failed to read EEPROM: %d\n", ret);
+ 		return -EAGAIN;
+ 	}
+ 
+-	if (ret != sizeof(id)) {
++	if (ret != sizeof(id.base)) {
+ 		dev_err(sfp->dev, "EEPROM short read: %d\n", ret);
+ 		return -EAGAIN;
+ 	}
+@@ -1612,6 +1650,21 @@ static int sfp_sm_mod_probe(struct sfp *
+ 		}
+ 	}
+ 
++	/* Apply any early module-specific quirks */
++	sfp_quirks_base(sfp, &id.base);
++
++	ret = sfp_read(sfp, false, SFP_CC_BASE + 1, &id.ext, sizeof(id.ext));
++	if (ret < 0) {
++		if (report)
++			dev_err(sfp->dev, "failed to read EEPROM: %d\n", ret);
++		return -EAGAIN;
++	}
++
++	if (ret != sizeof(id.ext)) {
++		dev_err(sfp->dev, "EEPROM short read: %d\n", ret);
++		return -EAGAIN;
++	}
++
+ 	check = sfp_check(&id.ext, sizeof(id.ext) - 1);
+ 	if (check != id.ext.cc_ext) {
+ 		if (cotsworks) {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/852-v5.10-0002-net-sfp-add-workaround-for-Realtek-RTL8672-and-RTL96.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/852-v5.10-0002-net-sfp-add-workaround-for-Realtek-RTL8672-and-RTL96.patch
new file mode 100644
index 0000000..27ae97c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/852-v5.10-0002-net-sfp-add-workaround-for-Realtek-RTL8672-and-RTL96.patch
@@ -0,0 +1,211 @@
+From 426c6cbc409cbda9ab1a9dbf15d3c2ef947eb8c1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
+Date: Mon, 25 Jan 2021 16:02:27 +0100
+Subject: [PATCH] net: sfp: add workaround for Realtek RTL8672 and RTL9601C
+ chips
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The workaround for VSOL V2801F brand based GPON SFP modules added in commit
+0d035bed2a4a ("net: sfp: VSOL V2801F / CarlitoxxPro CPGOS03-0490 v2.0
+workaround") works only for IDs added explicitly to the list. Since there
+are rebranded modules where OEM vendors put different strings into the
+vendor name field, we cannot base workaround on IDs only.
+
+Moreover the issue which the above mentioned commit tried to work around is
+generic not only to VSOL based modules, but rather to all GPON modules
+based on Realtek RTL8672 and RTL9601C chips.
+
+These include at least the following GPON modules:
+* V-SOL V2801F
+* C-Data FD511GX-RM0
+* OPTON GP801R
+* BAUDCOM BD-1234-SFM
+* CPGOS03-0490 v2.0
+* Ubiquiti U-Fiber Instant
+* EXOT EGS1
+
+These Realtek chips have broken EEPROM emulator which for N-byte read
+operation returns just the first byte of EEPROM data, followed by N-1
+zeros.
+
+Introduce a new function, sfp_id_needs_byte_io(), which detects SFP modules
+with broken EEPROM emulator based on N-1 zeros and switch to 1 byte EEPROM
+reading operation.
+
+Function sfp_i2c_read() now always uses single byte reading when it is
+required and when function sfp_hwmon_probe() detects single byte access,
+it disables registration of hwmon device, because in this case we cannot
+reliably and atomically read 2 bytes as is required by the standard for
+retrieving values from diagnostic area.
+
+(These Realtek chips are broken in a way that violates SFP standards for
+diagnostic interface. Kernel in this case simply cannot do anything less
+of skipping registration of the hwmon interface.)
+
+This patch fixes reading of EEPROM content from SFP modules based on
+Realtek RTL8672 and RTL9601C chips. Diagnostic interface of EEPROM stays
+broken and cannot be fixed.
+
+Fixes: 0d035bed2a4a ("net: sfp: VSOL V2801F / CarlitoxxPro CPGOS03-0490 v2.0 workaround")
+Co-developed-by: Russell King <rmk+kernel@armlinux.org.uk>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/phy/sfp.c | 100 ++++++++++++++++++++++++++++--------------
+ 1 file changed, 67 insertions(+), 33 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -306,19 +306,11 @@ static int sfp_i2c_read(struct sfp *sfp,
+ 			size_t len)
+ {
+ 	struct i2c_msg msgs[2];
+-	size_t block_size;
++	u8 bus_addr = a2 ? 0x51 : 0x50;
++	size_t block_size = sfp->i2c_block_size;
+ 	size_t this_len;
+-	u8 bus_addr;
+ 	int ret;
+ 
+-	if (a2) {
+-		block_size = 16;
+-		bus_addr = 0x51;
+-	} else {
+-		block_size = sfp->i2c_block_size;
+-		bus_addr = 0x50;
+-	}
+-
+ 	msgs[0].addr = bus_addr;
+ 	msgs[0].flags = 0;
+ 	msgs[0].len = 1;
+@@ -1245,6 +1237,20 @@ static void sfp_hwmon_probe(struct work_
+ 	struct sfp *sfp = container_of(work, struct sfp, hwmon_probe.work);
+ 	int err, i;
+ 
++	/* hwmon interface needs to access 16bit registers in atomic way to
++	 * guarantee coherency of the diagnostic monitoring data. If it is not
++	 * possible to guarantee coherency because EEPROM is broken in such way
++	 * that does not support atomic 16bit read operation then we have to
++	 * skip registration of hwmon device.
++	 */
++	if (sfp->i2c_block_size < 2) {
++		dev_info(sfp->dev,
++			 "skipping hwmon device registration due to broken EEPROM\n");
++		dev_info(sfp->dev,
++			 "diagnostic EEPROM area cannot be read atomically to guarantee data coherency\n");
++		return;
++	}
++
+ 	err = sfp_read(sfp, true, 0, &sfp->diag, sizeof(sfp->diag));
+ 	if (err < 0) {
+ 		if (sfp->hwmon_tries--) {
+@@ -1579,26 +1585,30 @@ static int sfp_sm_mod_hpower(struct sfp
+ 	return 0;
+ }
+ 
+-/* Some modules (Nokia 3FE46541AA) lock up if byte 0x51 is read as a
+- * single read. Switch back to reading 16 byte blocks unless we have
+- * a CarlitoxxPro module (rebranded VSOL V2801F). Even more annoyingly,
+- * some VSOL V2801F have the vendor name changed to OEM.
++/* GPON modules based on Realtek RTL8672 and RTL9601C chips (e.g. V-SOL
++ * V2801F, CarlitoxxPro CPGOS03-0490, Ubiquiti U-Fiber Instant, ...) do
++ * not support multibyte reads from the EEPROM. Each multi-byte read
++ * operation returns just one byte of EEPROM followed by zeros. There is
++ * no way to identify which modules are using Realtek RTL8672 and RTL9601C
++ * chips. Moreover every OEM of V-SOL V2801F module puts its own vendor
++ * name and vendor id into EEPROM, so there is even no way to detect if
++ * module is V-SOL V2801F. Therefore check for those zeros in the read
++ * data and then based on check switch to reading EEPROM to one byte
++ * at a time.
+  */
+-static int sfp_quirk_i2c_block_size(const struct sfp_eeprom_base *base)
++static bool sfp_id_needs_byte_io(struct sfp *sfp, void *buf, size_t len)
+ {
+-	if (!memcmp(base->vendor_name, "VSOL            ", 16))
+-		return 1;
+-	if (!memcmp(base->vendor_name, "OEM             ", 16) &&
+-	    !memcmp(base->vendor_pn,   "V2801F          ", 16))
+-		return 1;
++	size_t i, block_size = sfp->i2c_block_size;
+ 
+-	/* Some modules can't cope with long reads */
+-	return 16;
+-}
++	/* Already using byte IO */
++	if (block_size == 1)
++		return false;
+ 
+-static void sfp_quirks_base(struct sfp *sfp, const struct sfp_eeprom_base *base)
+-{
+-	sfp->i2c_block_size = sfp_quirk_i2c_block_size(base);
++	for (i = 1; i < len; i += block_size) {
++		if (memchr_inv(buf + i, '\0', min(block_size - 1, len - i)))
++			return false;
++	}
++	return true;
+ }
+ 
+ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
+@@ -1609,11 +1619,11 @@ static int sfp_sm_mod_probe(struct sfp *
+ 	u8 check;
+ 	int ret;
+ 
+-	/* Some modules (CarlitoxxPro CPGOS03-0490) do not support multibyte
+-	 * reads from the EEPROM, so start by reading the base identifying
+-	 * information one byte at a time.
++	/* Some SFP modules and also some Linux I2C drivers do not like reads
++	 * longer than 16 bytes, so read the EEPROM in chunks of 16 bytes at
++	 * a time.
+ 	 */
+-	sfp->i2c_block_size = 1;
++	sfp->i2c_block_size = 16;
+ 
+ 	ret = sfp_read(sfp, false, 0, &id.base, sizeof(id.base));
+ 	if (ret < 0) {
+@@ -1627,6 +1637,33 @@ static int sfp_sm_mod_probe(struct sfp *
+ 		return -EAGAIN;
+ 	}
+ 
++	/* Some SFP modules (e.g. Nokia 3FE46541AA) lock up if read from
++	 * address 0x51 is just one byte at a time. Also SFF-8472 requires
++	 * that EEPROM supports atomic 16bit read operation for diagnostic
++	 * fields, so do not switch to one byte reading at a time unless it
++	 * is really required and we have no other option.
++	 */
++	if (sfp_id_needs_byte_io(sfp, &id.base, sizeof(id.base))) {
++		dev_info(sfp->dev,
++			 "Detected broken RTL8672/RTL9601C emulated EEPROM\n");
++		dev_info(sfp->dev,
++			 "Switching to reading EEPROM to one byte at a time\n");
++		sfp->i2c_block_size = 1;
++
++		ret = sfp_read(sfp, false, 0, &id.base, sizeof(id.base));
++		if (ret < 0) {
++			if (report)
++				dev_err(sfp->dev, "failed to read EEPROM: %d\n",
++					ret);
++			return -EAGAIN;
++		}
++
++		if (ret != sizeof(id.base)) {
++			dev_err(sfp->dev, "EEPROM short read: %d\n", ret);
++			return -EAGAIN;
++		}
++	}
++
+ 	/* Cotsworks do not seem to update the checksums when they
+ 	 * do the final programming with the final module part number,
+ 	 * serial number and date code.
+@@ -1650,9 +1687,6 @@ static int sfp_sm_mod_probe(struct sfp *
+ 		}
+ 	}
+ 
+-	/* Apply any early module-specific quirks */
+-	sfp_quirks_base(sfp, &id.base);
+-
+ 	ret = sfp_read(sfp, false, SFP_CC_BASE + 1, &id.ext, sizeof(id.ext));
+ 	if (ret < 0) {
+ 		if (report)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/900-v5.9-0001-dt-bindings-Add-multicolor-class-dt-bindings-documen.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/900-v5.9-0001-dt-bindings-Add-multicolor-class-dt-bindings-documen.patch
new file mode 100644
index 0000000..acc32b6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/900-v5.9-0001-dt-bindings-Add-multicolor-class-dt-bindings-documen.patch
@@ -0,0 +1,76 @@
+From 5c7f8ffe741daae7f8d811a2037b2693f02c90c5 Mon Sep 17 00:00:00 2001
+From: Dan Murphy <dmurphy@ti.com>
+Date: Mon, 13 Jul 2020 10:45:31 -0500
+Subject: [PATCH] dt: bindings: Add multicolor class dt bindings documention
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add DT bindings for the LEDs multicolor class framework.
+Add multicolor ID to the color ID list for device tree bindings.
+
+CC: Rob Herring <robh@kernel.org>
+Reviewed-by: Rob Herring <robh@kernel.org>
+Acked-by: Pavel Machek <pavel@ucw.cz>
+Acked-by: Jacek Anaszewski <jacek.anaszewski@gmail.com>
+Signed-off-by: Dan Murphy <dmurphy@ti.com>
+Reviewed-by: Marek Behún <marek.behun@nic.cz>
+Signed-off-by: Pavel Machek <pavel@ucw.cz>
+---
+ .../bindings/leds/leds-class-multicolor.yaml  | 37 +++++++++++++++++++
+ include/dt-bindings/leds/common.h             |  3 +-
+ 2 files changed, 39 insertions(+), 1 deletion(-)
+ create mode 100644 Documentation/devicetree/bindings/leds/leds-class-multicolor.yaml
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/leds/leds-class-multicolor.yaml
+@@ -0,0 +1,37 @@
++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/leds/leds-class-multicolor.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Common properties for the multicolor LED class.
++
++maintainers:
++  - Dan Murphy <dmurphy@ti.com>
++
++description: |
++  Bindings for multi color LEDs show how to describe current outputs of
++  either integrated multi-color LED elements (like RGB, RGBW, RGBWA-UV
++  etc.) or standalone LEDs, to achieve logically grouped multi-color LED
++  modules. This is achieved by adding multi-led nodes layer to the
++  monochrome LED bindings.
++  The nodes and properties defined in this document are unique to the multicolor
++  LED class.  Common LED nodes and properties are inherited from the common.txt
++  within this documentation directory.
++
++patternProperties:
++  "^multi-led@([0-9a-f])$":
++    type: object
++    description: Represents the LEDs that are to be grouped.
++    properties:
++      color:
++        const: 8  # LED_COLOR_ID_MULTI
++        description: |
++          For multicolor LED support this property should be defined as
++          LED_COLOR_ID_MULTI which can be found in include/linux/leds/common.h.
++
++    $ref: "common.yaml#"
++
++    required:
++      - color
++...
+--- a/include/dt-bindings/leds/common.h
++++ b/include/dt-bindings/leds/common.h
+@@ -29,7 +29,8 @@
+ #define LED_COLOR_ID_VIOLET	5
+ #define LED_COLOR_ID_YELLOW	6
+ #define LED_COLOR_ID_IR		7
+-#define LED_COLOR_ID_MAX	8
++#define LED_COLOR_ID_MULTI	8
++#define LED_COLOR_ID_MAX	9
+ 
+ /* Standard LED functions */
+ #define LED_FUNCTION_ACTIVITY "activity"
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/900-v5.9-0002-leds-Add-multicolor-ID-to-the-color-ID-list.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/900-v5.9-0002-leds-Add-multicolor-ID-to-the-color-ID-list.patch
new file mode 100644
index 0000000..5de5dbd
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/900-v5.9-0002-leds-Add-multicolor-ID-to-the-color-ID-list.patch
@@ -0,0 +1,29 @@
+From 10d3e0d815879129e916cd83e1034438e06efdaa Mon Sep 17 00:00:00 2001
+From: Dan Murphy <dmurphy@ti.com>
+Date: Mon, 13 Jul 2020 10:45:32 -0500
+Subject: [PATCH] leds: Add multicolor ID to the color ID list
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add a new color ID that is declared as MULTICOLOR as with the
+multicolor framework declaring a definitive color is not accurate
+as the node can contain multiple colors.
+
+Signed-off-by: Dan Murphy <dmurphy@ti.com>
+Reviewed-by: Marek Behún <marek.behun@nic.cz>
+Signed-off-by: Pavel Machek <pavel@ucw.cz>
+---
+ drivers/leds/led-core.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/leds/led-core.c
++++ b/drivers/leds/led-core.c
+@@ -34,6 +34,7 @@ const char * const led_colors[LED_COLOR_
+ 	[LED_COLOR_ID_VIOLET] = "violet",
+ 	[LED_COLOR_ID_YELLOW] = "yellow",
+ 	[LED_COLOR_ID_IR] = "ir",
++	[LED_COLOR_ID_MULTI] = "multicolor",
+ };
+ EXPORT_SYMBOL_GPL(led_colors);
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/900-v5.9-0003-leds-add-RGB-color-option-as-that-is-different-from-.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/900-v5.9-0003-leds-add-RGB-color-option-as-that-is-different-from-.patch
new file mode 100644
index 0000000..17c2814
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/900-v5.9-0003-leds-add-RGB-color-option-as-that-is-different-from-.patch
@@ -0,0 +1,48 @@
+From 54212f5a1ba3123281877e54c1e5f672bf7563d8 Mon Sep 17 00:00:00 2001
+From: Pavel Machek <pavel@ucw.cz>
+Date: Mon, 3 Aug 2020 13:20:06 +0200
+Subject: [PATCH] leds: add RGB color option, as that is different from
+ multicolor.
+
+Multicolor is a bit too abstract. Yes, we can have
+Green-Magenta-Ultraviolet LED, but so far all the LEDs we support are
+RGB, and not even RGB-White or RGB-Yellow variants emerged.
+
+Multicolor is not a good fit for RGB LED. It does not really know
+about LED color.  In particular, there's no way to make LED "white".
+
+Userspace is interested in knowing "this LED can produce arbitrary
+color", which not all multicolor LEDs can.
+
+Signed-off-by: Pavel Machek <pavel@ucw.cz>
+---
+ drivers/leds/led-core.c           | 1 +
+ drivers/leds/leds-lp55xx-common.c | 2 +-
+ include/dt-bindings/leds/common.h | 6 ++++--
+ 3 files changed, 6 insertions(+), 3 deletions(-)
+
+--- a/drivers/leds/led-core.c
++++ b/drivers/leds/led-core.c
+@@ -35,6 +35,7 @@ const char * const led_colors[LED_COLOR_
+ 	[LED_COLOR_ID_YELLOW] = "yellow",
+ 	[LED_COLOR_ID_IR] = "ir",
+ 	[LED_COLOR_ID_MULTI] = "multicolor",
++	[LED_COLOR_ID_RGB] = "rgb",
+ };
+ EXPORT_SYMBOL_GPL(led_colors);
+ 
+--- a/include/dt-bindings/leds/common.h
++++ b/include/dt-bindings/leds/common.h
+@@ -29,8 +29,10 @@
+ #define LED_COLOR_ID_VIOLET	5
+ #define LED_COLOR_ID_YELLOW	6
+ #define LED_COLOR_ID_IR		7
+-#define LED_COLOR_ID_MULTI	8
+-#define LED_COLOR_ID_MAX	9
++#define LED_COLOR_ID_MULTI	8	/* For multicolor LEDs */
++#define LED_COLOR_ID_RGB	9	/* For multicolor LEDs that can do arbitrary color,
++					   so this would include RGBW and similar */
++#define LED_COLOR_ID_MAX	10
+ 
+ /* Standard LED functions */
+ #define LED_FUNCTION_ACTIVITY "activity"
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
new file mode 100644
index 0000000..d050883
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/backport-5.4.inc
@@ -0,0 +1,253 @@
+#patch backport-5.4 (come from openwrt/lede/target/linux/mediatek)
+SRC_URI_append = " \
+    file://010-Kbuild-don-t-hardcode-path-to-awk-in-scripts-ld-vers.patch \
+    file://011-kbuild-export-SUBARCH.patch \
+    file://030-modpost-add-a-helper-to-get-data-pointed-by-a-symbol.patch \
+    file://031-modpost-refactor-namespace_from_kstrtabns-to-not-har.patch \
+    file://041-v5.5-arm64-Implement-optimised-checksum-routine.patch \
+    file://042-v5.5-arm64-csum-Fix-pathological-zero-length-calls.patch \
+    file://080-wireguard-0001-crypto-lib-tidy-up-lib-crypto-Kconfig-and-Makefile.patch \
+    file://080-wireguard-0002-crypto-chacha-move-existing-library-code-into-lib-cr.patch \
+    file://080-wireguard-0003-crypto-x86-chacha-depend-on-generic-chacha-library-i.patch \
+    file://080-wireguard-0004-crypto-x86-chacha-expose-SIMD-ChaCha-routine-as-libr.patch \
+    file://080-wireguard-0005-crypto-arm64-chacha-depend-on-generic-chacha-library.patch \
+    file://080-wireguard-0006-crypto-arm64-chacha-expose-arm64-ChaCha-routine-as-l.patch \
+    file://080-wireguard-0007-crypto-arm-chacha-import-Eric-Biggers-s-scalar-accel.patch \
+    file://080-wireguard-0008-crypto-arm-chacha-remove-dependency-on-generic-ChaCh.patch \
+    file://080-wireguard-0009-crypto-arm-chacha-expose-ARM-ChaCha-routine-as-libra.patch \
+    file://080-wireguard-0010-crypto-mips-chacha-import-32r2-ChaCha-code-from-Zinc.patch \
+    file://080-wireguard-0011-crypto-mips-chacha-wire-up-accelerated-32r2-code-fro.patch \
+    file://080-wireguard-0012-crypto-chacha-unexport-chacha_generic-routines.patch \
+    file://080-wireguard-0013-crypto-poly1305-move-core-routines-into-a-separate-l.patch \
+    file://080-wireguard-0014-crypto-x86-poly1305-unify-Poly1305-state-struct-with.patch \
+    file://080-wireguard-0015-crypto-poly1305-expose-init-update-final-library-int.patch \
+    file://080-wireguard-0016-crypto-x86-poly1305-depend-on-generic-library-not-ge.patch \
+    file://080-wireguard-0017-crypto-x86-poly1305-expose-existing-driver-as-poly13.patch \
+    file://080-wireguard-0018-crypto-arm64-poly1305-incorporate-OpenSSL-CRYPTOGAMS.patch \
+    file://080-wireguard-0019-crypto-arm-poly1305-incorporate-OpenSSL-CRYPTOGAMS-N.patch \
+    file://080-wireguard-0020-crypto-mips-poly1305-incorporate-OpenSSL-CRYPTOGAMS-.patch \
+    file://080-wireguard-0021-crypto-blake2s-generic-C-library-implementation-and-.patch \
+    file://080-wireguard-0022-crypto-testmgr-add-test-cases-for-Blake2s.patch \
+    file://080-wireguard-0023-crypto-blake2s-implement-generic-shash-driver.patch \
+    file://080-wireguard-0024-crypto-blake2s-x86_64-SIMD-implementation.patch \
+    file://080-wireguard-0025-crypto-curve25519-generic-C-library-implementations.patch \
+    file://080-wireguard-0026-crypto-curve25519-add-kpp-selftest.patch \
+    file://080-wireguard-0027-crypto-curve25519-implement-generic-KPP-driver.patch \
+    file://080-wireguard-0028-crypto-lib-curve25519-work-around-Clang-stack-spilli.patch \
+    file://080-wireguard-0029-crypto-curve25519-x86_64-library-and-KPP-implementat.patch \
+    file://080-wireguard-0030-crypto-arm-curve25519-import-Bernstein-and-Schwabe-s.patch \
+    file://080-wireguard-0031-crypto-arm-curve25519-wire-up-NEON-implementation.patch \
+    file://080-wireguard-0032-crypto-chacha20poly1305-import-construction-and-self.patch \
+    file://080-wireguard-0033-crypto-lib-chacha20poly1305-reimplement-crypt_from_s.patch \
+    file://080-wireguard-0034-crypto-chacha_generic-remove-unnecessary-setkey-func.patch \
+    file://080-wireguard-0035-crypto-x86-chacha-only-unregister-algorithms-if-regi.patch \
+    file://080-wireguard-0036-crypto-lib-chacha20poly1305-use-chacha20_crypt.patch \
+    file://080-wireguard-0037-crypto-arch-conditionalize-crypto-api-in-arch-glue-f.patch \
+    file://080-wireguard-0038-crypto-chacha-fix-warning-message-in-header-file.patch \
+    file://080-wireguard-0039-crypto-arm-curve25519-add-arch-specific-key-generati.patch \
+    file://080-wireguard-0040-crypto-lib-curve25519-re-add-selftests.patch \
+    file://080-wireguard-0041-crypto-poly1305-add-new-32-and-64-bit-generic-versio.patch \
+    file://080-wireguard-0042-crypto-x86-poly1305-import-unmodified-cryptogams-imp.patch \
+    file://080-wireguard-0043-crypto-x86-poly1305-wire-up-faster-implementations-f.patch \
+    file://080-wireguard-0044-crypto-arm-arm64-mips-poly1305-remove-redundant-non-.patch \
+    file://080-wireguard-0045-crypto-curve25519-Fix-selftest-build-error.patch \
+    file://080-wireguard-0046-crypto-x86-poly1305-fix-.gitignore-typo.patch \
+    file://080-wireguard-0047-crypto-chacha20poly1305-add-back-missing-test-vector.patch \
+    file://080-wireguard-0048-crypto-x86-poly1305-emit-does-base-conversion-itself.patch \
+    file://080-wireguard-0049-crypto-arm-chacha-fix-build-failured-when-kernel-mod.patch \
+    file://080-wireguard-0050-crypto-Kconfig-allow-tests-to-be-disabled-when-manag.patch \
+    file://080-wireguard-0051-crypto-chacha20poly1305-prevent-integer-overflow-on-.patch \
+    file://080-wireguard-0052-crypto-x86-curve25519-support-assemblers-with-no-adx.patch \
+    file://080-wireguard-0053-crypto-arm64-chacha-correctly-walk-through-blocks.patch \
+    file://080-wireguard-0054-crypto-x86-curve25519-replace-with-formally-verified.patch \
+    file://080-wireguard-0055-crypto-x86-curve25519-leave-r12-as-spare-register.patch \
+    file://080-wireguard-0056-crypto-arm-64-poly1305-add-artifact-to-.gitignore-fi.patch \
+    file://080-wireguard-0057-crypto-arch-lib-limit-simd-usage-to-4k-chunks.patch \
+    file://080-wireguard-0058-crypto-lib-chacha20poly1305-Add-missing-function-dec.patch \
+    file://080-wireguard-0059-crypto-x86-chacha-sse3-use-unaligned-loads-for-state.patch \
+    file://080-wireguard-0060-crypto-x86-curve25519-Remove-unused-carry-variables.patch \
+    file://080-wireguard-0061-crypto-arm-curve25519-include-linux-scatterlist.h.patch \
+    file://080-wireguard-0062-crypto-arm-poly1305-Add-prototype-for-poly1305_block.patch \
+    file://080-wireguard-0063-crypto-curve25519-x86_64-Use-XORL-r32-32.patch \
+    file://080-wireguard-0064-crypto-poly1305-x86_64-Use-XORL-r32-32.patch \
+    file://080-wireguard-0065-crypto-x86-poly1305-Remove-assignments-with-no-effec.patch \
+    file://080-wireguard-0066-crypto-x86-poly1305-add-back-a-needed-assignment.patch \
+    file://080-wireguard-0067-crypto-Kconfig-CRYPTO_MANAGER_EXTRA_TESTS-requires-t.patch \
+    file://080-wireguard-0068-crypto-arm-chacha-neon-optimize-for-non-block-size-m.patch \
+    file://080-wireguard-0069-crypto-arm64-chacha-simplify-tail-block-handling.patch \
+    file://080-wireguard-0070-crypto-lib-chacha20poly1305-define-empty-module-exit.patch \
+    file://080-wireguard-0071-crypto-arm-chacha-neon-add-missing-counter-increment.patch \
+    file://080-wireguard-0072-net-WireGuard-secure-network-tunnel.patch \
+    file://080-wireguard-0073-wireguard-selftests-import-harness-makefile-for-test.patch \
+    file://080-wireguard-0074-wireguard-Kconfig-select-parent-dependency-for-crypt.patch \
+    file://080-wireguard-0075-wireguard-global-fix-spelling-mistakes-in-comments.patch \
+    file://080-wireguard-0076-wireguard-main-remove-unused-include-linux-version.h.patch \
+    file://080-wireguard-0077-wireguard-allowedips-use-kfree_rcu-instead-of-call_r.patch \
+    file://080-wireguard-0078-wireguard-selftests-remove-ancient-kernel-compatibil.patch \
+    file://080-wireguard-0079-wireguard-queueing-do-not-account-for-pfmemalloc-whe.patch \
+    file://080-wireguard-0080-wireguard-socket-mark-skbs-as-not-on-list-when-recei.patch \
+    file://080-wireguard-0081-wireguard-allowedips-fix-use-after-free-in-root_remo.patch \
+    file://080-wireguard-0082-wireguard-noise-reject-peers-with-low-order-public-k.patch \
+    file://080-wireguard-0083-wireguard-selftests-ensure-non-addition-of-peers-wit.patch \
+    file://080-wireguard-0084-wireguard-selftests-tie-socket-waiting-to-target-pid.patch \
+    file://080-wireguard-0085-wireguard-device-use-icmp_ndo_send-helper.patch \
+    file://080-wireguard-0086-wireguard-selftests-reduce-complexity-and-fix-make-r.patch \
+    file://080-wireguard-0087-wireguard-receive-reset-last_under_load-to-zero.patch \
+    file://080-wireguard-0088-wireguard-send-account-for-mtu-0-devices.patch \
+    file://080-wireguard-0089-wireguard-socket-remove-extra-call-to-synchronize_ne.patch \
+    file://080-wireguard-0090-wireguard-selftests-remove-duplicated-include-sys-ty.patch \
+    file://080-wireguard-0091-wireguard-queueing-account-for-skb-protocol-0.patch \
+    file://080-wireguard-0092-wireguard-receive-remove-dead-code-from-default-pack.patch \
+    file://080-wireguard-0093-wireguard-noise-error-out-precomputed-DH-during-hand.patch \
+    file://080-wireguard-0094-wireguard-send-remove-errant-newline-from-packet_enc.patch \
+    file://080-wireguard-0095-wireguard-queueing-cleanup-ptr_ring-in-error-path-of.patch \
+    file://080-wireguard-0096-wireguard-receive-use-tunnel-helpers-for-decapsulati.patch \
+    file://080-wireguard-0097-wireguard-selftests-use-normal-kernel-stack-size-on-.patch \
+    file://080-wireguard-0098-wireguard-socket-remove-errant-restriction-on-loopin.patch \
+    file://080-wireguard-0099-wireguard-send-receive-cond_resched-when-processing-.patch \
+    file://080-wireguard-0100-wireguard-selftests-initalize-ipv6-members-to-NULL-t.patch \
+    file://080-wireguard-0101-wireguard-send-receive-use-explicit-unlikely-branch-.patch \
+    file://080-wireguard-0102-wireguard-selftests-use-newer-iproute2-for-gcc-10.patch \
+    file://080-wireguard-0103-wireguard-noise-read-preshared-key-while-taking-lock.patch \
+    file://080-wireguard-0104-wireguard-queueing-preserve-flow-hash-across-packet-.patch \
+    file://080-wireguard-0105-wireguard-noise-separate-receive-counter-from-send-c.patch \
+    file://080-wireguard-0106-wireguard-noise-do-not-assign-initiation-time-in-if-.patch \
+    file://080-wireguard-0107-wireguard-device-avoid-circular-netns-references.patch \
+    file://080-wireguard-0108-wireguard-receive-account-for-napi_gro_receive-never.patch \
+    file://080-wireguard-0109-net-ip_tunnel-add-header_ops-for-layer-3-devices.patch \
+    file://080-wireguard-0110-wireguard-implement-header_ops-parse_protocol-for-AF.patch \
+    file://080-wireguard-0111-wireguard-queueing-make-use-of-ip_tunnel_parse_proto.patch \
+    file://080-wireguard-0112-netlink-consistently-use-NLA_POLICY_EXACT_LEN.patch \
+    file://080-wireguard-0113-netlink-consistently-use-NLA_POLICY_MIN_LEN.patch \
+    file://080-wireguard-0114-wireguard-noise-take-lock-when-removing-handshake-en.patch \
+    file://080-wireguard-0115-wireguard-peerlookup-take-lock-before-checking-hash-.patch \
+    file://080-wireguard-0116-wireguard-selftests-check-that-route_me_harder-packe.patch \
+    file://080-wireguard-0117-wireguard-avoid-double-unlikely-notation-when-using-.patch \
+    file://080-wireguard-0118-wireguard-socket-remove-bogus-__be32-annotation.patch \
+    file://080-wireguard-0119-wireguard-selftests-test-multiple-parallel-streams.patch \
+    file://080-wireguard-0120-wireguard-peer-put-frequently-used-members-above-cac.patch \
+    file://080-wireguard-0121-wireguard-device-do-not-generate-ICMP-for-non-IP-pac.patch \
+    file://080-wireguard-0122-wireguard-queueing-get-rid-of-per-peer-ring-buffers.patch \
+    file://080-wireguard-0123-wireguard-kconfig-use-arm-chacha-even-with-no-neon.patch \
+    file://080-wireguard-0124-crypto-mips-poly1305-enable-for-all-MIPS-processors.patch \
+    file://080-wireguard-0125-crypto-mips-add-poly1305-core.S-to-.gitignore.patch \
+    file://080-wireguard-0126-crypto-poly1305-fix-poly1305_core_setkey-declaration.patch \
+    file://080-wireguard-0127-wireguard-selftests-remove-old-conntrack-kconfig-val.patch \
+    file://080-wireguard-0128-wireguard-selftests-make-sure-rp_filter-is-disabled-.patch \
+    file://080-wireguard-0129-wireguard-do-not-use-O3.patch \
+    file://080-wireguard-0130-wireguard-use-synchronize_net-rather-than-synchroniz.patch \
+    file://080-wireguard-0131-wireguard-peer-allocate-in-kmem_cache.patch \
+    file://080-wireguard-0132-wireguard-allowedips-initialize-list-head-in-selftes.patch \
+    file://080-wireguard-0133-wireguard-allowedips-remove-nodes-in-O-1.patch \
+    file://080-wireguard-0134-wireguard-allowedips-allocate-nodes-in-kmem_cache.patch \
+    file://080-wireguard-0135-wireguard-allowedips-free-empty-intermediate-nodes-w.patch \
+    file://300-MIPS-Exclude-more-dsemul-code-when-CONFIG_MIPS_FP_SU.patch \
+    file://310-mips-Kconfig-Add-ARCH_HAS_FORTIFY_SOURCE.patch \
+    file://310-v5.6-mips-vdso-fix-jalr-t9-crash-in-vdso-code.patch \
+    file://311-MIPS-Fix-exception-handler-memcpy.patch \
+    file://343-netfilter-nft_flow_offload-handle-netdevice-events-f.patch \
+    file://370-netfilter-nf_flow_table-fix-offloaded-connection-tim.patch \
+    file://371-netfilter-nf_flow_table-fix-up-ct-state-of-flows-aft.patch \
+    file://393-v5.5-sch_cake-drop-unused-variable-tin_quantum_prio.patch \
+    file://395-v5.8-net-sch_cake-Take-advantage-of-skb-hash-where-appropriate.patch \
+    file://399-5.9-sch_cake-add-RFC-8622-LE-PHB-support-to-CAKE-diffser.patch \
+    file://400-v5.8-dt-bindings-mtd-partition-Document-the-slc-mode-prop.patch \
+    file://401-v5.11-dt-bindings-mtd-convert-fixed-partitions-to-the-json.patch \
+    file://402-v5.12-0001-dt-bindings-mtd-move-partition-binding-to-its-own-fi.patch \
+    file://402-v5.12-0002-dt-bindings-mtd-add-binding-for-BCM4908-partitions.patch \
+    file://403-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch \
+    file://404-v5.13-mtd-parsers-ofpart-limit-parsing-of-deprecated-DT-sy.patch \
+    file://405-v5.13-mtd-parsers-ofpart-make-symbol-bcm4908_partitions_qu.patch \
+    file://406-v5.13-0001-mtd-core-add-nvmem-cells-compatible-to-parse-mtd-as-.patch \
+    file://406-v5.13-0002-dt-bindings-nvmem-drop-nodename-restriction.patch \
+    file://406-v5.13-0003-dt-bindings-mtd-Document-use-of-nvmem-cells-compatib.patch \
+    file://407-v5.13-0001-dt-bindings-mtd-add-binding-for-Linksys-Northstar-pa.patch \
+    file://407-v5.13-0002-mtd-parsers-ofpart-support-Linksys-Northstar-partiti.patch \
+    file://410-mtd-fix-calculating-partition-end-address.patch \
+    file://600-v5.12-net-extract-napi-poll-functionality-to-__napi_poll.patch \
+    file://601-v5.12-net-implement-threaded-able-napi-poll-loop-support.patch \
+    file://602-v5.12-net-add-sysfs-attribute-to-control-napi-threaded-mod.patch \
+    file://603-v5.12-net-fix-race-between-napi-kthread-mode-and-busy-poll.patch \
+    file://604-v5.12-net-fix-hangup-on-napi_disable-for-threaded-napi.patch \
+    file://610-v5.9-net-bridge-clear-bridge-s-private-skb-space-on-xmit.patch \
+    file://700-v5.5-net-core-allow-fast-GRO-for-skbs-with-Ethernet-heade.patch \
+    file://716-v5.5-net-sfp-move-fwnode-parsing-into-sfp-bus-layer.patch \
+    file://717-v5.5-net-sfp-rework-upstream-interface.patch \
+    file://718-v5.5-net-sfp-fix-sfp_bus_put-kernel-documentation.patch \
+    file://719-v5.5-net-sfp-fix-sfp_bus_add_upstream-warning.patch \
+    file://720-v5.5-net-sfp-move-sfp-sub-state-machines-into-separate-fu.patch \
+    file://721-v5.5-net-sfp-move-tx-disable-on-device-down-to-main-state.patch \
+    file://722-v5.5-net-sfp-rename-sfp_sm_ins_next-as-sfp_sm_mod_next.patch \
+    file://723-v5.5-net-sfp-handle-module-remove-outside-state-machine.patch \
+    file://724-v5.5-net-sfp-rename-T_PROBE_WAIT-to-T_SERIAL.patch \
+    file://725-v5.5-net-sfp-parse-SFP-power-requirement-earlier.patch \
+    file://726-v5.5-net-sfp-avoid-power-switch-on-address-change-modules.patch \
+    file://727-v5.5-net-sfp-control-TX_DISABLE-and-phy-only-from-main-st.patch \
+    file://728-v5.5-net-sfp-split-the-PHY-probe-from-sfp_sm_mod_init.patch \
+    file://729-v5.5-net-sfp-eliminate-mdelay-from-PHY-probe.patch \
+    file://730-v5.5-net-sfp-allow-fault-processing-to-transition-to-othe.patch \
+    file://731-v5.5-net-sfp-ensure-TX_FAULT-has-deasserted-before-probin.patch \
+    file://732-v5.5-net-sfp-track-upstream-s-attachment-state-in-state-m.patch \
+    file://733-v5.5-net-sfp-split-power-mode-switching-from-probe.patch \
+    file://734-v5.5-net-sfp-move-module-insert-reporting-out-of-probe.patch \
+    file://735-v5.5-net-sfp-allow-sfp-to-probe-slow-to-initialise-GPON-m.patch \
+    file://736-v5.5-net-sfp-allow-modules-with-slow-diagnostics-to-probe.patch \
+    file://737-v5.5-net-phy-add-core-phylib-sfp-support.patch \
+    file://738-v5.5-net-phy-marvell10g-add-SFP-support.patch \
+    file://739-v5.5-net-phylink-update-to-use-phy_support_asym_pause.patch \
+    file://744-v5.5-net-sfp-soft-status-and-control-support.patch \
+    file://745-v5.7-net-dsa-mt7530-add-support-for-port-mirroring.patch \
+    file://746-v5.5-net-dsa-mv88e6xxx-Split-monitor-port-configuration.patch \
+    file://747-v5.5-net-dsa-mv88e6xxx-Add-support-for-port-mirroring.patch \
+    file://748-v5.5-net-dsa-mv88e6xxx-fix-broken-if-statement-because-of.patch \
+    file://749-v5.5-net-dsa-mv88e6xxx-Fix-masking-of-egress-port.patch \
+    file://750-v5.5-net-phy-add-support-for-clause-37-auto-negotiation.patch \
+    file://751-v5.6-net-mvmdio-avoid-error-message-for-optional-IRQ.patch \
+    file://752-v5.8-net-dsa-provide-an-option-for-drivers-to-always-rece.patch \
+    file://753-v5.8-net-dsa-mt7530-fix-VLAN-setup.patch \
+    file://756-v5.8-net-dsa-rtl8366-Pass-GENMASK-signed-bits.patch \
+    file://757-v5.8-net-dsa-tag_rtl4_a-Implement-Realtek-4-byte-A-tag.patch \
+    file://758-v5.8-net-dsa-rtl8366rb-Support-the-CPU-DSA-tag.patch \
+    file://765-v5.12-net-dsa-automatically-bring-up-DSA-master-when-openi.patch \
+    file://770-v5.12-net-bridge-notify-switchdev-of-disappearance-of-old-.patch \
+    file://771-v5.12-net-dsa-be-louder-when-a-non-legacy-FDB-operation-fa.patch \
+    file://772-v5.12-net-dsa-don-t-use-switchdev_notifier_fdb_info-in-dsa.patch \
+    file://773-v5.12-net-dsa-move-switchdev-event-implementation-under-th.patch \
+    file://774-v5.12-net-dsa-exit-early-in-dsa_slave_switchdev_event-if-w.patch \
+    file://775-v5.12-net-dsa-listen-for-SWITCHDEV_-FDB-DEL-_ADD_TO_DEVICE.patch \
+    file://780-net-dsa-mt7530-setup-core-clock-even-in-TRGMII-mode.patch \
+    file://800-v5.5-iio-imu-Add-support-for-the-FXOS8700-IMU.patch \
+    file://800-v5.5-scsi-core-Add-sysfs-attributes-for-VPD-pages-0h-and-.patch \
+    file://801-v5.5-hwmon-Driver-for-disk-and-solid-state-drives-with-te.patch \
+    file://801-v5.6-leds-populate-the-device-s-of_node.patch \
+    file://803-v5.8-i2c-pxa-use-official-address-byte-helper.patch \
+    file://804-v5.8-i2c-pxa-remove-unneeded-includes.patch \
+    file://805-v5.8-i2c-pxa-re-arrange-includes-to-be-in-alphabetical-or.patch \
+    file://806-v5.8-i2c-pxa-re-arrange-functions-to-flow-better.patch \
+    file://807-v5.8-i2c-pxa-re-arrange-register-field-definitions.patch \
+    file://808-v5.8-i2c-pxa-add-and-use-definitions-for-IBMR-register.patch \
+    file://809-v5.8-i2c-pxa-always-set-fm-and-hs-members-for-each-type.patch \
+    file://810-v5.8-i2c-pxa-move-private-definitions-to-i2c-pxa.c.patch \
+    file://811-v5.8-i2c-pxa-move-DT-IDs-along-side-platform-IDs.patch \
+    file://813-v5.8-i2c-pxa-clean-up-decode_bits.patch \
+    file://814-v5.8-i2c-pxa-fix-i2c_pxa_wait_bus_not_busy-boundary-condi.patch \
+    file://815-v5.8-i2c-pxa-consolidate-i2c_pxa_-xfer-implementations.patch \
+    file://816-v5.8-i2c-pxa-avoid-complaints-with-non-responsive-slaves.patch \
+    file://817-v5.8-i2c-pxa-ensure-timeout-messages-are-unique.patch \
+    file://818-v5.8-i2c-pxa-remove-some-unnecessary-debug.patch \
+    file://820-v5.8-i2c-pxa-use-master-abort-for-device-probes.patch \
+    file://821-v5.8-i2c-pxa-implement-generic-i2c-bus-recovery.patch \
+    file://825-v5.8-spi-rb4xx-null-pointer-bug-fix.patch \
+    file://826-v5.8-spi-rb4xx-update-driver-to-be-device-tree-aware.patch \
+    file://827-v5.16-spi-add-power-control-when-set_cs.patch \
+    file://831-v5.13-0001-firmware-bcm47xx_nvram-rename-finding-function-and-i.patch \
+    file://831-v5.13-0002-firmware-bcm47xx_nvram-add-helper-checking-for-NVRAM.patch \
+    file://831-v5.13-0003-firmware-bcm47xx_nvram-extract-code-copying-NVRAM.patch \
+    file://831-v5.13-0004-firmware-bcm47xx_nvram-look-for-NVRAM-with-for-inste.patch \
+    file://831-v5.13-0005-firmware-bcm47xx_nvram-inline-code-checking-NVRAM-si.patch \
+    file://852-v5.10-0001-net-sfp-VSOL-V2801F-CarlitoxxPro-CPGOS03-0490-v2.0-w.patch \
+    file://852-v5.10-0002-net-sfp-add-workaround-for-Realtek-RTL8672-and-RTL96.patch \
+    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 \
+    "
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/defconfig b/recipes-kernel/linux/linux-mediatek-5.4/generic/defconfig
new file mode 100644
index 0000000..aba2911
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/defconfig
@@ -0,0 +1,6560 @@
+# CONFIG_104_QUAD_8 is not set
+CONFIG_32BIT=y
+CONFIG_64BIT_TIME=y
+# CONFIG_6LOWPAN is not set
+# CONFIG_6LOWPAN_DEBUGFS is not set
+# CONFIG_6PACK is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_9P_FS is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_AB8500_CORE is not set
+# CONFIG_ABP060MG is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_ACENIC is not set
+# CONFIG_ACERHDF is not set
+# CONFIG_ACER_WIRELESS is not set
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_ACPI_ALS is not set
+# CONFIG_ACPI_APEI is not set
+# CONFIG_ACPI_BUTTON is not set
+# CONFIG_ACPI_CONFIGFS is not set
+# CONFIG_ACPI_CUSTOM_METHOD is not set
+# CONFIG_ACPI_EXTLOG is not set
+# CONFIG_ACPI_HED is not set
+# CONFIG_ACPI_NFIT is not set
+# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set
+# CONFIG_ACPI_TABLE_UPGRADE is not set
+# CONFIG_ACPI_VIDEO is not set
+# CONFIG_AD2S1200 is not set
+# CONFIG_AD2S1210 is not set
+# CONFIG_AD2S90 is not set
+# CONFIG_AD5064 is not set
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_AD5272 is not set
+# CONFIG_AD5360 is not set
+# CONFIG_AD5380 is not set
+# CONFIG_AD5421 is not set
+# CONFIG_AD5446 is not set
+# CONFIG_AD5449 is not set
+# CONFIG_AD5504 is not set
+# CONFIG_AD5592R is not set
+# CONFIG_AD5593R is not set
+# CONFIG_AD5624R_SPI is not set
+# CONFIG_AD5686 is not set
+# CONFIG_AD5686_SPI is not set
+# CONFIG_AD5696_I2C is not set
+# CONFIG_AD5755 is not set
+# CONFIG_AD5758 is not set
+# CONFIG_AD5761 is not set
+# CONFIG_AD5764 is not set
+# CONFIG_AD5791 is not set
+# CONFIG_AD5933 is not set
+# CONFIG_AD7124 is not set
+# CONFIG_AD7150 is not set
+# CONFIG_AD7152 is not set
+# CONFIG_AD7192 is not set
+# CONFIG_AD7266 is not set
+# CONFIG_AD7280 is not set
+# CONFIG_AD7291 is not set
+# CONFIG_AD7298 is not set
+# CONFIG_AD7303 is not set
+# CONFIG_AD7476 is not set
+# CONFIG_AD7606 is not set
+# CONFIG_AD7606_IFACE_PARALLEL is not set
+# CONFIG_AD7606_IFACE_SPI is not set
+# CONFIG_AD7746 is not set
+# CONFIG_AD7766 is not set
+# CONFIG_AD7768_1 is not set
+# CONFIG_AD7780 is not set
+# CONFIG_AD7791 is not set
+# CONFIG_AD7793 is not set
+# CONFIG_AD7816 is not set
+# CONFIG_AD7887 is not set
+# CONFIG_AD7923 is not set
+# CONFIG_AD7949 is not set
+# CONFIG_AD799X is not set
+# CONFIG_AD8366 is not set
+# CONFIG_AD8801 is not set
+# CONFIG_AD9523 is not set
+# CONFIG_AD9832 is not set
+# CONFIG_AD9834 is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_ADE7854 is not set
+# CONFIG_ADF4350 is not set
+# CONFIG_ADF4371 is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADIN_PHY is not set
+# CONFIG_ADIS16080 is not set
+# CONFIG_ADIS16130 is not set
+# CONFIG_ADIS16136 is not set
+# CONFIG_ADIS16201 is not set
+# CONFIG_ADIS16203 is not set
+# CONFIG_ADIS16209 is not set
+# CONFIG_ADIS16240 is not set
+# CONFIG_ADIS16260 is not set
+# CONFIG_ADIS16400 is not set
+# CONFIG_ADIS16460 is not set
+# CONFIG_ADIS16480 is not set
+# CONFIG_ADJD_S311 is not set
+# CONFIG_ADM6996_PHY is not set
+# CONFIG_ADM8211 is not set
+# CONFIG_ADT7316 is not set
+CONFIG_ADVISE_SYSCALLS=y
+# CONFIG_ADXL345_I2C is not set
+# CONFIG_ADXL345_SPI is not set
+# CONFIG_ADXL372_I2C is not set
+# CONFIG_ADXL372_SPI is not set
+# CONFIG_ADXRS450 is not set
+CONFIG_AEABI=y
+# CONFIG_AFE4403 is not set
+# CONFIG_AFE4404 is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_AFS_DEBUG_CURSOR is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_AF_KCM is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_AF_RXRPC_INJECT_LOSS is not set
+# CONFIG_AF_RXRPC_IPV6 is not set
+# CONFIG_AGP is not set
+# CONFIG_AHCI_CEVA is not set
+# CONFIG_AHCI_IMX is not set
+# CONFIG_AHCI_MVEBU is not set
+# CONFIG_AHCI_QORIQ is not set
+CONFIG_AIO=y
+# CONFIG_AIRO is not set
+# CONFIG_AIRO_CS is not set
+# CONFIG_AIX_PARTITION is not set
+# CONFIG_AK09911 is not set
+# CONFIG_AK8974 is not set
+# CONFIG_AK8975 is not set
+# CONFIG_AL3320A is not set
+# CONFIG_ALIM7101_WDT is not set
+CONFIG_ALLOW_DEV_COREDUMP=y
+# CONFIG_ALTERA_MBOX is not set
+# CONFIG_ALTERA_MSGDMA is not set
+# CONFIG_ALTERA_STAPL is not set
+# CONFIG_ALTERA_TSE is not set
+# CONFIG_ALX is not set
+# CONFIG_AL_FIC is not set
+# CONFIG_AM2315 is not set
+# CONFIG_AM335X_PHY_USB is not set
+# CONFIG_AMBA_PL08X is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_AMD_MEM_ENCRYPT is not set
+# CONFIG_AMD_PHY is not set
+# CONFIG_AMD_XGBE is not set
+# CONFIG_AMD_XGBE_HAVE_ECC is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_AMILO_RFKILL is not set
+# CONFIG_ANDROID is not set
+CONFIG_ANON_INODES=y
+# CONFIG_APDS9300 is not set
+# CONFIG_APDS9802ALS is not set
+# CONFIG_APDS9960 is not set
+# CONFIG_APM8018X is not set
+# CONFIG_APM_EMULATION is not set
+# CONFIG_APPLE_GMUX is not set
+# CONFIG_APPLE_PROPERTIES is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_AQTION is not set
+# CONFIG_AQUANTIA_PHY is not set
+# CONFIG_AR5523 is not set
+# CONFIG_AR7 is not set
+# CONFIG_AR8216_PHY is not set
+# CONFIG_AR8216_PHY_LEDS is not set
+# CONFIG_ARCH_ACTIONS is not set
+# CONFIG_ARCH_AGILEX is not set
+# CONFIG_ARCH_ALPINE is not set
+# CONFIG_ARCH_ARTPEC is not set
+# CONFIG_ARCH_ASPEED is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_AXXIA is not set
+# CONFIG_ARCH_BCM is not set
+# CONFIG_ARCH_BCM2835 is not set
+# CONFIG_ARCH_BCM_21664 is not set
+# CONFIG_ARCH_BCM_23550 is not set
+# CONFIG_ARCH_BCM_281XX is not set
+# CONFIG_ARCH_BCM_5301X is not set
+# CONFIG_ARCH_BCM_53573 is not set
+# CONFIG_ARCH_BCM_63XX is not set
+# CONFIG_ARCH_BCM_CYGNUS is not set
+# CONFIG_ARCH_BCM_IPROC is not set
+# CONFIG_ARCH_BCM_NSP is not set
+# CONFIG_ARCH_BERLIN is not set
+# CONFIG_ARCH_BITMAIN is not set
+# CONFIG_ARCH_BRCMSTB is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_DIGICOLOR is not set
+# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_EXYNOS is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_GEMINI is not set
+CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y
+# CONFIG_ARCH_HI3xxx is not set
+# CONFIG_ARCH_HIGHBANK is not set
+# CONFIG_ARCH_HISI is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_K3 is not set
+# CONFIG_ARCH_KEYSTONE is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_LAYERSCAPE is not set
+# CONFIG_ARCH_LG1K is not set
+# CONFIG_ARCH_LPC32XX is not set
+# CONFIG_ARCH_MEDIATEK is not set
+# CONFIG_ARCH_MESON is not set
+# CONFIG_ARCH_MILBEAUT is not set
+CONFIG_ARCH_MMAP_RND_BITS=8
+CONFIG_ARCH_MMAP_RND_BITS_MAX=16
+CONFIG_ARCH_MMAP_RND_BITS_MIN=8
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_MULTIPLATFORM is not set
+# CONFIG_ARCH_MULTI_V6 is not set
+# CONFIG_ARCH_MULTI_V7 is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MVEBU is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_MXS is not set
+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_NPCM is not set
+# CONFIG_ARCH_NSPIRE is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+# CONFIG_ARCH_OMAP2PLUS is not set
+# CONFIG_ARCH_OMAP3 is not set
+# CONFIG_ARCH_OMAP4 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_OXNAS is not set
+# CONFIG_ARCH_PICOXCELL is not set
+# CONFIG_ARCH_PRIMA2 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_QCOM is not set
+# CONFIG_ARCH_RDA is not set
+# CONFIG_ARCH_REALTEK is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_RENESAS is not set
+# CONFIG_ARCH_ROCKCHIP is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_S3C24XX is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_SEATTLE is not set
+# CONFIG_ARCH_SHMOBILE is not set
+# CONFIG_ARCH_SIRF is not set
+# CONFIG_ARCH_SOCFPGA is not set
+# CONFIG_ARCH_SPRD is not set
+# CONFIG_ARCH_STI is not set
+# CONFIG_ARCH_STM32 is not set
+# CONFIG_ARCH_STRATIX10 is not set
+# CONFIG_ARCH_SUNXI is not set
+# CONFIG_ARCH_SYNQUACER is not set
+# CONFIG_ARCH_TANGO is not set
+# CONFIG_ARCH_TEGRA is not set
+# CONFIG_ARCH_THUNDER is not set
+# CONFIG_ARCH_THUNDER2 is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_UNIPHIER is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_VEXPRESS is not set
+# CONFIG_ARCH_VIRT is not set
+# CONFIG_ARCH_VT8500 is not set
+# CONFIG_ARCH_VULCAN is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_WANTS_THP_SWAP is not set
+# CONFIG_ARCH_WM8505 is not set
+# CONFIG_ARCH_WM8750 is not set
+# CONFIG_ARCH_WM8850 is not set
+# CONFIG_ARCH_XGENE is not set
+# CONFIG_ARCH_ZX is not set
+# CONFIG_ARCH_ZYNQ is not set
+# CONFIG_ARCH_ZYNQMP is not set
+# CONFIG_ARCNET is not set
+# CONFIG_ARC_EMAC is not set
+# CONFIG_ARC_IRQ_NO_AUTOSAVE is not set
+# CONFIG_ARM64_16K_PAGES is not set
+# CONFIG_ARM64_64K_PAGES is not set
+# CONFIG_ARM64_CRYPTO is not set
+# CONFIG_ARM64_ERRATUM_1024718 is not set
+# CONFIG_ARM64_ERRATUM_1463225 is not set
+# CONFIG_ARM64_ERRATUM_1542419 is not set
+# CONFIG_ARM64_ERRATUM_819472 is not set
+# CONFIG_ARM64_ERRATUM_824069 is not set
+# CONFIG_ARM64_ERRATUM_826319 is not set
+# CONFIG_ARM64_ERRATUM_827319 is not set
+# CONFIG_ARM64_ERRATUM_832075 is not set
+# CONFIG_ARM64_ERRATUM_834220 is not set
+# CONFIG_ARM64_ERRATUM_843419 is not set
+# CONFIG_ARM64_ERRATUM_845719 is not set
+# CONFIG_ARM64_ERRATUM_858921 is not set
+# CONFIG_ARM64_HW_AFDBM is not set
+# CONFIG_ARM64_LSE_ATOMICS is not set
+# CONFIG_ARM64_MODULE_PLTS is not set
+# CONFIG_ARM64_PAN is not set
+# CONFIG_ARM64_PMEM is not set
+# CONFIG_ARM64_PSEUDO_NMI is not set
+# CONFIG_ARM64_PTDUMP_DEBUGFS is not set
+# CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET is not set
+# CONFIG_ARM64_RAS_EXTN is not set
+# CONFIG_ARM64_RELOC_TEST is not set
+CONFIG_ARM64_SW_TTBR0_PAN=y
+# CONFIG_ARM64_UAO is not set
+# CONFIG_ARM64_VA_BITS_48 is not set
+# CONFIG_ARM64_VHE is not set
+# CONFIG_ARM_APPENDED_DTB is not set
+# CONFIG_ARM_ARCH_TIMER is not set
+# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND is not set
+# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set
+# CONFIG_ARM_CCI is not set
+# CONFIG_ARM_CCI400_PMU is not set
+# CONFIG_ARM_CCI5xx_PMU is not set
+# CONFIG_ARM_CCI_PMU is not set
+# CONFIG_ARM_CCN is not set
+# CONFIG_ARM_CPUIDLE is not set
+CONFIG_ARM_CPU_TOPOLOGY=y
+# CONFIG_ARM_CRYPTO is not set
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+# CONFIG_ARM_DSU_PMU is not set
+# CONFIG_ARM_ERRATA_326103 is not set
+# CONFIG_ARM_ERRATA_364296 is not set
+# CONFIG_ARM_ERRATA_411920 is not set
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+# CONFIG_ARM_ERRATA_643719 is not set
+# CONFIG_ARM_ERRATA_720789 is not set
+# CONFIG_ARM_ERRATA_742230 is not set
+# CONFIG_ARM_ERRATA_742231 is not set
+# CONFIG_ARM_ERRATA_743622 is not set
+# CONFIG_ARM_ERRATA_751472 is not set
+# CONFIG_ARM_ERRATA_754322 is not set
+# CONFIG_ARM_ERRATA_754327 is not set
+# CONFIG_ARM_ERRATA_764369 is not set
+# CONFIG_ARM_ERRATA_773022 is not set
+# CONFIG_ARM_ERRATA_775420 is not set
+# CONFIG_ARM_ERRATA_798181 is not set
+# CONFIG_ARM_ERRATA_814220 is not set
+# CONFIG_ARM_ERRATA_818325_852422 is not set
+# CONFIG_ARM_ERRATA_821420 is not set
+# CONFIG_ARM_ERRATA_825619 is not set
+# CONFIG_ARM_ERRATA_852421 is not set
+# CONFIG_ARM_ERRATA_852423 is not set
+# CONFIG_ARM_ERRATA_857271 is not set
+# CONFIG_ARM_ERRATA_857272 is not set
+CONFIG_ARM_GIC_MAX_NR=1
+# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
+# CONFIG_ARM_KPROBES_TEST is not set
+# CONFIG_ARM_LPAE is not set
+# CONFIG_ARM_MHU is not set
+# CONFIG_ARM_MODULE_PLTS is not set
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+# CONFIG_ARM_PSCI is not set
+# CONFIG_ARM_PSCI_CHECKER is not set
+# CONFIG_ARM_PSCI_CPUIDLE is not set
+# CONFIG_ARM_PTDUMP_DEBUGFS is not set
+# CONFIG_ARM_SBSA_WATCHDOG is not set
+# CONFIG_ARM_SCPI_PROTOCOL is not set
+# CONFIG_ARM_SDE_INTERFACE is not set
+# CONFIG_ARM_SP805_WATCHDOG is not set
+# CONFIG_ARM_SPE_PMU is not set
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_ARM_TIMER_SP804 is not set
+# CONFIG_ARM_UNWIND is not set
+# CONFIG_ARM_VIRT_EXT is not set
+# CONFIG_AS3935 is not set
+# CONFIG_ASM9260_TIMER is not set
+# CONFIG_ASUS_LAPTOP is not set
+# CONFIG_ASUS_WIRELESS is not set
+# CONFIG_ASYMMETRIC_KEY_TYPE is not set
+# CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE is not set
+# CONFIG_ASYNC_RAID6_TEST is not set
+# CONFIG_ASYNC_TX_DMA is not set
+# CONFIG_AT76C50X_USB is not set
+# CONFIG_AT803X_PHY is not set
+# CONFIG_AT91_SAMA5D2_ADC is not set
+# CONFIG_ATA is not set
+# CONFIG_ATAGS is not set
+CONFIG_ATAGS_PROC=y
+# CONFIG_ATALK is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_ATA_ACPI is not set
+CONFIG_ATA_BMDMA=y
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_ATA_LEDS is not set
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_ATA_PIIX is not set
+CONFIG_ATA_SFF=y
+# CONFIG_ATA_VERBOSE_ERROR is not set
+# CONFIG_ATH10K is not set
+# CONFIG_ATH25 is not set
+# CONFIG_ATH5K is not set
+# CONFIG_ATH6KL is not set
+# CONFIG_ATH79 is not set
+# CONFIG_ATH9K is not set
+# CONFIG_ATH9K_HTC is not set
+# CONFIG_ATH_DEBUG is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1C is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL2 is not set
+# CONFIG_ATLAS_PH_SENSOR is not set
+# CONFIG_ATM is not set
+# CONFIG_ATMEL is not set
+# CONFIG_ATMEL_PIT is not set
+# CONFIG_ATMEL_SSC is not set
+# CONFIG_ATM_AMBASSADOR is not set
+# CONFIG_ATM_BR2684 is not set
+CONFIG_ATM_BR2684_IPFILTER=y
+# CONFIG_ATM_CLIP is not set
+CONFIG_ATM_CLIP_NO_ICMP=y
+# CONFIG_ATM_DRIVERS is not set
+# CONFIG_ATM_DUMMY is not set
+# CONFIG_ATM_ENI is not set
+# CONFIG_ATM_FIRESTREAM is not set
+# CONFIG_ATM_FORE200E is not set
+# CONFIG_ATM_HE is not set
+# CONFIG_ATM_HORIZON is not set
+# CONFIG_ATM_IA is not set
+# CONFIG_ATM_IDT77252 is not set
+# CONFIG_ATM_LANAI is not set
+# CONFIG_ATM_LANE is not set
+# CONFIG_ATM_MPOA is not set
+# CONFIG_ATM_NICSTAR is not set
+# CONFIG_ATM_SOLOS is not set
+# CONFIG_ATM_TCP is not set
+# CONFIG_ATM_ZATM is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_ATP is not set
+# CONFIG_AUDIT is not set
+# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
+# CONFIG_AURORA_NB8800 is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTO_ZRELADDR is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_AX25 is not set
+# CONFIG_AX25_DAMA_SLAVE is not set
+# CONFIG_AX88796 is not set
+# CONFIG_AX88796B_PHY is not set
+# CONFIG_AXP20X_ADC is not set
+# CONFIG_AXP20X_POWER is not set
+# CONFIG_AXP288_ADC is not set
+# CONFIG_AXP288_FUEL_GAUGE is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_B44 is not set
+# CONFIG_B53 is not set
+# CONFIG_BACKLIGHT_ADP8860 is not set
+# CONFIG_BACKLIGHT_ADP8870 is not set
+# CONFIG_BACKLIGHT_APPLE is not set
+# CONFIG_BACKLIGHT_ARCXCNN is not set
+# CONFIG_BACKLIGHT_BD6107 is not set
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
+# CONFIG_BACKLIGHT_GENERIC is not set
+# CONFIG_BACKLIGHT_GPIO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_BACKLIGHT_LM3630A is not set
+# CONFIG_BACKLIGHT_LM3639 is not set
+# CONFIG_BACKLIGHT_LP855X is not set
+# CONFIG_BACKLIGHT_LV5207LP is not set
+# CONFIG_BACKLIGHT_PANDORA is not set
+# CONFIG_BACKLIGHT_PM8941_WLED is not set
+# CONFIG_BACKLIGHT_PWM is not set
+# CONFIG_BACKLIGHT_RPI is not set
+# CONFIG_BACKLIGHT_SAHARA is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+CONFIG_BASE_FULL=y
+CONFIG_BASE_SMALL=0
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_BATTERY_BQ27XXX is not set
+# CONFIG_BATTERY_BQ27XXX_HDQ is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_DS2780 is not set
+# CONFIG_BATTERY_DS2781 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_GAUGE_LTC2941 is not set
+# CONFIG_BATTERY_GOLDFISH is not set
+# CONFIG_BATTERY_LEGO_EV3 is not set
+# CONFIG_BATTERY_MAX17040 is not set
+# CONFIG_BATTERY_MAX17042 is not set
+# CONFIG_BATTERY_MAX1721X is not set
+# CONFIG_BATTERY_RT5033 is not set
+# CONFIG_BATTERY_SBS is not set
+# CONFIG_BAYCOM_EPP is not set
+# CONFIG_BAYCOM_PAR is not set
+# CONFIG_BAYCOM_SER_FDX is not set
+# CONFIG_BAYCOM_SER_HDX is not set
+# CONFIG_BCACHE is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_BCM63XX is not set
+# CONFIG_BCM63XX_PHY is not set
+# CONFIG_BCM7038_WDT is not set
+# CONFIG_BCM7XXX_PHY is not set
+# CONFIG_BCM84881_PHY is not set
+# CONFIG_BCM87XX_PHY is not set
+# CONFIG_BCMA is not set
+# CONFIG_BCMA_DRIVER_GPIO is not set
+CONFIG_BCMA_POSSIBLE=y
+# CONFIG_BCMGENET is not set
+# CONFIG_BCM_IPROC_ADC is not set
+# CONFIG_BCM_KONA_USB2_PHY is not set
+# CONFIG_BCM_SBA_RAID is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_BE2ISCSI is not set
+# CONFIG_BE2NET is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_BGMAC is not set
+# CONFIG_BH1750 is not set
+# CONFIG_BH1780 is not set
+# CONFIG_BIG_KEYS is not set
+# CONFIG_BIG_LITTLE is not set
+# CONFIG_BINARY_PRINTF is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_ELF_FDPIC is not set
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_SCRIPT=y
+CONFIG_BITREVERSE=y
+# CONFIG_BLK_CGROUP_IOCOST is not set
+# CONFIG_BLK_CGROUP_IOLATENCY is not set
+# CONFIG_BLK_CMDLINE_PARSER is not set
+# CONFIG_BLK_DEBUG_FS is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_BLK_DEV_4DRIVES is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI14XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_ATIIXP is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_BSGLIB is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_CS5535 is not set
+# CONFIG_BLK_DEV_CS5536 is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_DELKIN is not set
+# CONFIG_BLK_DEV_DRBD is not set
+# CONFIG_BLK_DEV_DTC2278 is not set
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_HT6560B is not set
+# CONFIG_BLK_DEV_IDEACPI is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_IDEPCI is not set
+# CONFIG_BLK_DEV_IDEPNP is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDE_AU1XXX is not set
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_INTEGRITY is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_IT8172 is not set
+# CONFIG_BLK_DEV_IT8213 is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_JMICRON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_NULL_BLK is not set
+# CONFIG_BLK_DEV_NVME is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_PLATFORM is not set
+# CONFIG_BLK_DEV_PMEM is not set
+# CONFIG_BLK_DEV_QD65XX is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_RBD is not set
+# CONFIG_BLK_DEV_RSXX is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_SD is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SKD is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_TC86C001 is not set
+# CONFIG_BLK_DEV_THROTTLING is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_UMC8672 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_BLK_DEV_ZONED is not set
+# CONFIG_BLK_SED_OPAL is not set
+# CONFIG_BLK_WBT is not set
+CONFIG_BLOCK=y
+# CONFIG_BMA180 is not set
+# CONFIG_BMA220 is not set
+# CONFIG_BMC150_ACCEL is not set
+# CONFIG_BMC150_MAGN is not set
+# CONFIG_BMC150_MAGN_I2C is not set
+# CONFIG_BMC150_MAGN_SPI is not set
+# CONFIG_BME680 is not set
+# CONFIG_BMG160 is not set
+# CONFIG_BMI160_I2C is not set
+# CONFIG_BMI160_SPI is not set
+# CONFIG_BMIPS_GENERIC is not set
+# CONFIG_BMP280 is not set
+# CONFIG_BNA is not set
+# CONFIG_BNX2 is not set
+# CONFIG_BNX2X is not set
+# CONFIG_BNX2X_SRIOV is not set
+# CONFIG_BNXT is not set
+# CONFIG_BONDING is not set
+# CONFIG_BOOKE_WDT is not set
+CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT=3
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+CONFIG_BOOT_RAW=y
+CONFIG_BPF=y
+# CONFIG_BPFILTER is not set
+CONFIG_BPF_JIT=y
+# CONFIG_BPF_JIT_ALWAYS_ON is not set
+# CONFIG_BPF_STREAM_PARSER is not set
+CONFIG_BPF_SYSCALL=y
+# CONFIG_BPQETHER is not set
+CONFIG_BQL=y
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_BRCMFMAC is not set
+# CONFIG_BRCMSMAC is not set
+# CONFIG_BRCMSTB_GISB_ARB is not set
+CONFIG_BRIDGE=y
+# CONFIG_BRIDGE_EBT_802_3 is not set
+# CONFIG_BRIDGE_EBT_AMONG is not set
+# CONFIG_BRIDGE_EBT_ARP is not set
+# CONFIG_BRIDGE_EBT_ARPREPLY is not set
+# CONFIG_BRIDGE_EBT_BROUTE is not set
+# CONFIG_BRIDGE_EBT_DNAT is not set
+# CONFIG_BRIDGE_EBT_IP is not set
+# CONFIG_BRIDGE_EBT_IP6 is not set
+# CONFIG_BRIDGE_EBT_LIMIT is not set
+# CONFIG_BRIDGE_EBT_LOG is not set
+# CONFIG_BRIDGE_EBT_MARK is not set
+# CONFIG_BRIDGE_EBT_MARK_T is not set
+# CONFIG_BRIDGE_EBT_NFLOG is not set
+# CONFIG_BRIDGE_EBT_PKTTYPE is not set
+# CONFIG_BRIDGE_EBT_REDIRECT is not set
+# CONFIG_BRIDGE_EBT_SNAT is not set
+# CONFIG_BRIDGE_EBT_STP is not set
+# CONFIG_BRIDGE_EBT_T_FILTER is not set
+# CONFIG_BRIDGE_EBT_T_NAT is not set
+# CONFIG_BRIDGE_EBT_VLAN is not set
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+# CONFIG_BRIDGE_NETFILTER is not set
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+CONFIG_BRIDGE_VLAN_FILTERING=y
+# CONFIG_BROADCOM_PHY is not set
+CONFIG_BROKEN_ON_SMP=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_BT is not set
+# CONFIG_BTRFS_ASSERT is not set
+# CONFIG_BTRFS_DEBUG is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_BTRFS_FS_POSIX_ACL is not set
+# CONFIG_BTRFS_FS_REF_VERIFY is not set
+# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set
+# CONFIG_BT_ATH3K is not set
+# CONFIG_BT_BNEP is not set
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+# CONFIG_BT_BREDR is not set
+# CONFIG_BT_CMTP is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIBLUECARD is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBT3C is not set
+# CONFIG_BT_HCIBTSDIO is not set
+# CONFIG_BT_HCIBTUSB is not set
+# CONFIG_BT_HCIBTUSB_AUTOSUSPEND is not set
+# CONFIG_BT_HCIBTUSB_MTK is not set
+# CONFIG_BT_HCIBTUSB_RTL is not set
+# CONFIG_BT_HCIDTL1 is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIUART_3WIRE is not set
+# CONFIG_BT_HCIUART_AG6XX is not set
+# CONFIG_BT_HCIUART_ATH3K is not set
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_H4=y
+# CONFIG_BT_HCIUART_LL is not set
+# CONFIG_BT_HCIUART_MRVL is not set
+# CONFIG_BT_HCIUART_QCA is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_BT_HIDP is not set
+# CONFIG_BT_HS is not set
+# CONFIG_BT_LE is not set
+# CONFIG_BT_LEDS is not set
+# CONFIG_BT_MRVL is not set
+# CONFIG_BT_MTKSDIO is not set
+# CONFIG_BT_MTKUART is not set
+# CONFIG_BT_RFCOMM is not set
+CONFIG_BT_RFCOMM_TTY=y
+# CONFIG_BT_SELFTEST is not set
+CONFIG_BUG=y
+# CONFIG_BUG_ON_DATA_CORRUPTION is not set
+CONFIG_BUILDTIME_EXTABLE_SORT=y
+# CONFIG_BUILD_BIN2C is not set
+CONFIG_BUILD_SALT=""
+# CONFIG_C2PORT is not set
+CONFIG_CACHE_L2X0_PMU=y
+# CONFIG_CADENCE_WATCHDOG is not set
+# CONFIG_CAIF is not set
+# CONFIG_CAN is not set
+# CONFIG_CAN_BCM is not set
+# CONFIG_CAN_DEBUG_DEVICES is not set
+# CONFIG_CAN_DEV is not set
+# CONFIG_CAN_GS_USB is not set
+# CONFIG_CAN_GW is not set
+# CONFIG_CAN_HI311X is not set
+# CONFIG_CAN_IFI_CANFD is not set
+# CONFIG_CAN_J1939 is not set
+# CONFIG_CAN_KVASER_PCIEFD is not set
+# CONFIG_CAN_MCBA_USB is not set
+# CONFIG_CAN_M_CAN is not set
+# CONFIG_CAN_PEAK_PCIEFD is not set
+# CONFIG_CAN_RAW is not set
+# CONFIG_CAN_RCAR is not set
+# CONFIG_CAN_RCAR_CANFD is not set
+# CONFIG_CAN_SLCAN is not set
+# CONFIG_CAN_SUN4I is not set
+# CONFIG_CAN_UCAN is not set
+# CONFIG_CAN_VCAN is not set
+# CONFIG_CAN_VXCAN is not set
+# CONFIG_CAPI_AVM is not set
+# CONFIG_CAPI_EICON is not set
+# CONFIG_CAPI_TRACE is not set
+CONFIG_CARDBUS=y
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_CARL9170 is not set
+# CONFIG_CASSINI is not set
+# CONFIG_CAVIUM_CPT is not set
+# CONFIG_CAVIUM_ERRATUM_22375 is not set
+# CONFIG_CAVIUM_ERRATUM_23144 is not set
+# CONFIG_CAVIUM_ERRATUM_23154 is not set
+# CONFIG_CAVIUM_ERRATUM_27456 is not set
+# CONFIG_CAVIUM_ERRATUM_30115 is not set
+# CONFIG_CAVIUM_OCTEON_SOC is not set
+# CONFIG_CAVIUM_PTP is not set
+# CONFIG_CB710_CORE is not set
+# CONFIG_CC10001_ADC is not set
+# CONFIG_CCS811 is not set
+CONFIG_CC_CAN_LINK=y
+CONFIG_CC_HAS_ASM_INLINE=y
+CONFIG_CC_HAS_SANCOV_TRACE_PC=y
+CONFIG_CC_HAS_STACKPROTECTOR_NONE=y
+CONFIG_CC_HAS_WARN_MAYBE_UNINITIALIZED=y
+CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_CEPH_FS is not set
+# CONFIG_CEPH_LIB is not set
+# CONFIG_CFG80211 is not set
+# CONFIG_CFG80211_CERTIFICATION_ONUS is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_CHARGER_ADP5061 is not set
+# CONFIG_CHARGER_BQ2415X is not set
+# CONFIG_CHARGER_BQ24190 is not set
+# CONFIG_CHARGER_BQ24257 is not set
+# CONFIG_CHARGER_BQ24735 is not set
+# CONFIG_CHARGER_BQ25890 is not set
+# CONFIG_CHARGER_DETECTOR_MAX14656 is not set
+# CONFIG_CHARGER_GPIO is not set
+# CONFIG_CHARGER_ISP1704 is not set
+# CONFIG_CHARGER_LP8727 is not set
+# CONFIG_CHARGER_LT3651 is not set
+# CONFIG_CHARGER_LTC3651 is not set
+# CONFIG_CHARGER_MANAGER is not set
+# CONFIG_CHARGER_MAX8903 is not set
+# CONFIG_CHARGER_RT9455 is not set
+# CONFIG_CHARGER_SBS is not set
+# CONFIG_CHARGER_SMB347 is not set
+# CONFIG_CHARGER_TWL4030 is not set
+# CONFIG_CHARGER_UCS1002 is not set
+# CONFIG_CHASH_SELFTEST is not set
+# CONFIG_CHASH_STATS is not set
+# CONFIG_CHECKPOINT_RESTORE is not set
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_CHELSIO_T4 is not set
+# CONFIG_CHELSIO_T4VF is not set
+# CONFIG_CHROME_PLATFORMS is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_CIFS is not set
+# CONFIG_CIFS_ACL is not set
+CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y
+# CONFIG_CIFS_DEBUG is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_FSCACHE is not set
+# CONFIG_CIFS_NFSD_EXPORT is not set
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_SMB2 is not set
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_STATS2 is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+CONFIG_CIFS_XATTR=y
+# CONFIG_CIO_DAC is not set
+CONFIG_CLANG_VERSION=0
+# CONFIG_CLEANCACHE is not set
+# CONFIG_CLKSRC_VERSATILE is not set
+# CONFIG_CLK_HSDK is not set
+# CONFIG_CLK_QORIQ is not set
+# CONFIG_CLOCK_THERMAL is not set
+CONFIG_CLS_U32_MARK=y
+# CONFIG_CLS_U32_PERF is not set
+# CONFIG_CM32181 is not set
+# CONFIG_CM3232 is not set
+# CONFIG_CM3323 is not set
+# CONFIG_CM3605 is not set
+# CONFIG_CM36651 is not set
+# CONFIG_CMA is not set
+CONFIG_CMDLINE=""
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_CMDLINE_EXTEND is not set
+# CONFIG_CMDLINE_FORCE is not set
+# CONFIG_CMDLINE_FROM_BOOTLOADER is not set
+# CONFIG_CMDLINE_PARTITION is not set
+# CONFIG_CNIC is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_CODE_PATCHING_SELFTEST is not set
+# CONFIG_COMEDI is not set
+# CONFIG_COMMON_CLK_CDCE706 is not set
+# CONFIG_COMMON_CLK_CDCE925 is not set
+# CONFIG_COMMON_CLK_CS2000_CP is not set
+# CONFIG_COMMON_CLK_FIXED_MMIO is not set
+# CONFIG_COMMON_CLK_IPROC is not set
+# CONFIG_COMMON_CLK_MAX9485 is not set
+# CONFIG_COMMON_CLK_NXP is not set
+# CONFIG_COMMON_CLK_PIC32 is not set
+# CONFIG_COMMON_CLK_PWM is not set
+# CONFIG_COMMON_CLK_PXA is not set
+# CONFIG_COMMON_CLK_QCOM is not set
+# CONFIG_COMMON_CLK_SI514 is not set
+# CONFIG_COMMON_CLK_SI5341 is not set
+# CONFIG_COMMON_CLK_SI5351 is not set
+# CONFIG_COMMON_CLK_SI544 is not set
+# CONFIG_COMMON_CLK_SI570 is not set
+# CONFIG_COMMON_CLK_VC5 is not set
+# CONFIG_COMMON_CLK_VERSATILE is not set
+# CONFIG_COMMON_CLK_XGENE is not set
+# CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set
+CONFIG_COMPACTION=y
+# CONFIG_COMPAL_LAPTOP is not set
+# CONFIG_COMPAT is not set
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_COMPILE_TEST is not set
+# CONFIG_CONFIGFS_FS is not set
+# CONFIG_CONFIG_KVM_AMD_SEV is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7
+CONFIG_CONSOLE_LOGLEVEL_QUIET=4
+CONFIG_CONSTRUCTORS=y
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_COPS is not set
+# CONFIG_CORDIC is not set
+# CONFIG_COREDUMP is not set
+# CONFIG_CORESIGHT is not set
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_CORTINA_PHY is not set
+# CONFIG_COUNTER is not set
+# CONFIG_CPA_DEBUG is not set
+# CONFIG_CPU_BIG_ENDIAN is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_GOV_SCHEDUTIL is not set
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND is not set
+# CONFIG_CPU_IDLE is not set
+# CONFIG_CPU_IDLE_GOV_LADDER is not set
+# CONFIG_CPU_IDLE_GOV_MENU is not set
+# CONFIG_CPU_IDLE_GOV_TEO is not set
+# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set
+# CONFIG_CPU_ISOLATION is not set
+# CONFIG_CPU_NO_EFFICIENT_FFS is not set
+CONFIG_CPU_SW_DOMAIN_PAN=y
+# CONFIG_CRAMFS is not set
+CONFIG_CRAMFS_BLOCKDEV=y
+# CONFIG_CRAMFS_MTD is not set
+CONFIG_CRASHLOG=y
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_CRC32_BIT is not set
+CONFIG_CRC32_SARWATE=y
+# CONFIG_CRC32_SELFTEST is not set
+# CONFIG_CRC32_SLICEBY4 is not set
+# CONFIG_CRC32_SLICEBY8 is not set
+# CONFIG_CRC4 is not set
+# CONFIG_CRC64 is not set
+# CONFIG_CRC7 is not set
+# CONFIG_CRC8 is not set
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC_ITU_T is not set
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CROSS_COMPILE=""
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_842 is not set
+# CONFIG_CRYPTO_ADIANTUM is not set
+# CONFIG_CRYPTO_AEAD is not set
+# CONFIG_CRYPTO_AEGIS128 is not set
+# CONFIG_CRYPTO_AEGIS128L is not set
+# CONFIG_CRYPTO_AEGIS128L_AESNI_SSE2 is not set
+# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set
+# CONFIG_CRYPTO_AEGIS256 is not set
+# CONFIG_CRYPTO_AEGIS256_AESNI_SSE2 is not set
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_AES_586 is not set
+# CONFIG_CRYPTO_AES_ARM is not set
+# CONFIG_CRYPTO_AES_ARM_BS is not set
+# CONFIG_CRYPTO_AES_ARM_CE is not set
+# CONFIG_CRYPTO_AES_ARM64 is not set
+# CONFIG_CRYPTO_AES_ARM64_BS is not set
+# CONFIG_CRYPTO_AES_ARM64_CE is not set
+# CONFIG_CRYPTO_AES_ARM64_CE_BLK is not set
+# CONFIG_CRYPTO_AES_ARM64_CE_CCM is not set
+# CONFIG_CRYPTO_AES_ARM64_NEON_BLK is not set
+# CONFIG_CRYPTO_AES_NI_INTEL is not set
+# CONFIG_CRYPTO_AES_TI is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_BLAKE2S is not set
+# CONFIG_CRYPTO_BLAKE2S_X86 is not set
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_CFB is not set
+# CONFIG_CRYPTO_CHACHA20 is not set
+# CONFIG_CRYPTO_CHACHA20POLY1305 is not set
+# CONFIG_CRYPTO_CHACHA20_NEON is not set
+# CONFIG_CRYPTO_CHACHA_MIPS is not set
+# CONFIG_CRYPTO_CMAC is not set
+# CONFIG_CRYPTO_CRC32 is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CRC32C_INTEL is not set
+# CONFIG_CRYPTO_CRC32_ARM_CE is not set
+# CONFIG_CRYPTO_CRCT10DIF is not set
+# CONFIG_CRYPTO_CRCT10DIF_ARM_CE is not set
+# CONFIG_CRYPTO_CRCT10DIF_ARM64_CE is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_CURVE25519 is not set
+# CONFIG_CRYPTO_CURVE25519_NEON is not set
+# CONFIG_CRYPTO_CURVE25519_X86 is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_DEV_ATMEL_AES is not set
+# CONFIG_CRYPTO_DEV_ATMEL_AUTHENC is not set
+# CONFIG_CRYPTO_DEV_ATMEL_ECC is not set
+# CONFIG_CRYPTO_DEV_ATMEL_SHA is not set
+# CONFIG_CRYPTO_DEV_ATMEL_SHA204A is not set
+# CONFIG_CRYPTO_DEV_ATMEL_TDES is not set
+# CONFIG_CRYPTO_DEV_CAVIUM_ZIP is not set
+# CONFIG_CRYPTO_DEV_CCP is not set
+# CONFIG_CRYPTO_DEV_CCP_DEBUGFS is not set
+# CONFIG_CRYPTO_DEV_CCREE is not set
+# CONFIG_CRYPTO_DEV_FSL_CAAM is not set
+# CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC is not set
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_CRYPTO_DEV_HISI_SEC is not set
+# CONFIG_CRYPTO_DEV_HISI_ZIP is not set
+# CONFIG_CRYPTO_DEV_IMGTEC_HASH is not set
+# CONFIG_CRYPTO_DEV_MARVELL_CESA is not set
+# CONFIG_CRYPTO_DEV_MV_CESA is not set
+# CONFIG_CRYPTO_DEV_MXC_SCC is not set
+# CONFIG_CRYPTO_DEV_MXS_DCP is not set
+# CONFIG_CRYPTO_DEV_NITROX_CNN55XX is not set
+# CONFIG_CRYPTO_DEV_QAT_C3XXX is not set
+# CONFIG_CRYPTO_DEV_QAT_C3XXXVF is not set
+# CONFIG_CRYPTO_DEV_QAT_C62X is not set
+# CONFIG_CRYPTO_DEV_QAT_C62XVF is not set
+# CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set
+# CONFIG_CRYPTO_DEV_QAT_DH895xCCVF is not set
+# CONFIG_CRYPTO_DEV_QCE is not set
+# CONFIG_CRYPTO_DEV_S5P is not set
+# CONFIG_CRYPTO_DEV_SAFEXCEL is not set
+# CONFIG_CRYPTO_DEV_SAHARA is not set
+# CONFIG_CRYPTO_DEV_SP_PSP is not set
+# CONFIG_CRYPTO_DEV_TALITOS is not set
+# CONFIG_CRYPTO_DEV_VIRTIO is not set
+# CONFIG_CRYPTO_DH is not set
+# CONFIG_CRYPTO_DRBG_CTR is not set
+# CONFIG_CRYPTO_DRBG_HASH is not set
+# CONFIG_CRYPTO_DRBG_MENU is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_ECDH is not set
+# CONFIG_CRYPTO_ECHAINIV is not set
+# CONFIG_CRYPTO_ECRDSA is not set
+# CONFIG_CRYPTO_ESSIV is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_FIPS is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_GHASH_ARM_CE is not set
+# CONFIG_CRYPTO_GHASH_ARM64_CE is not set
+# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set
+# CONFIG_CRYPTO_HASH is not set
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_CRYPTO_JITTERENTROPY is not set
+# CONFIG_CRYPTO_KEYWRAP is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+CONFIG_CRYPTO_LIB_AES=y
+CONFIG_CRYPTO_LIB_ARC4=y
+# CONFIG_CRYPTO_LIB_BLAKE2S is not set
+# CONFIG_CRYPTO_LIB_CHACHA is not set
+# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set
+# CONFIG_CRYPTO_LIB_CURVE25519 is not set
+# CONFIG_CRYPTO_LIB_POLY1305 is not set
+CONFIG_CRYPTO_LIB_POLY1305_RSIZE=9
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_LZ4 is not set
+# CONFIG_CRYPTO_LZ4HC is not set
+# CONFIG_CRYPTO_LZO is not set
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+# CONFIG_CRYPTO_MCRYPTD is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_MORUS1280 is not set
+# CONFIG_CRYPTO_MORUS1280_AVX2 is not set
+# CONFIG_CRYPTO_MORUS1280_SSE2 is not set
+# CONFIG_CRYPTO_MORUS640 is not set
+# CONFIG_CRYPTO_MORUS640_SSE2 is not set
+# CONFIG_CRYPTO_NHPOLY1305_NEON is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_OFB is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_PCOMP is not set
+# CONFIG_CRYPTO_PCOMP2 is not set
+CONFIG_CRYPTO_PCRYPT=y
+# CONFIG_CRYPTO_POLY1305 is not set
+# CONFIG_CRYPTO_POLY1305_ARM is not set
+# CONFIG_CRYPTO_POLY1305_MIPS is not set
+# CONFIG_CRYPTO_POLY1305_NEON is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_RNG is not set
+# CONFIG_CRYPTO_RSA is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SALSA20_586 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SEQIV is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA1_ARM is not set
+# CONFIG_CRYPTO_SHA1_ARM_CE is not set
+# CONFIG_CRYPTO_SHA1_ARM_NEON is not set
+# CONFIG_CRYPTO_SHA1_ARM64_CE is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA256_ARM is not set
+# CONFIG_CRYPTO_SHA256_ARM64 is not set
+# CONFIG_CRYPTO_SHA2_ARM_CE is not set
+# CONFIG_CRYPTO_SHA2_ARM64_CE is not set
+# CONFIG_CRYPTO_SHA3 is not set
+# CONFIG_CRYPTO_SHA3_ARM64 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_SHA512_ARM is not set
+# CONFIG_CRYPTO_SHA512_ARM64 is not set
+# CONFIG_CRYPTO_SHA512_ARM64_CE is not set
+# CONFIG_CRYPTO_SIMD is not set
+# CONFIG_CRYPTO_SM3 is not set
+# CONFIG_CRYPTO_SM3_ARM64_CE is not set
+# CONFIG_CRYPTO_SM4 is not set
+# CONFIG_CRYPTO_SM4_ARM64_CE is not set
+# CONFIG_CRYPTO_SPECK is not set
+# CONFIG_CRYPTO_STATS is not set
+# CONFIG_CRYPTO_STREEBOG is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_TWOFISH_586 is not set
+# CONFIG_CRYPTO_TWOFISH_COMMON is not set
+# CONFIG_CRYPTO_USER is not set
+# CONFIG_CRYPTO_USER_API_AEAD is not set
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_RNG is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+# CONFIG_CRYPTO_VMAC is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_XXHASH is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_ZSTD is not set
+# CONFIG_CS5535_MFGPT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_CUSE is not set
+# CONFIG_CW1200 is not set
+# CONFIG_CXL_AFU_DRIVER_OPS is not set
+# CONFIG_CXL_BASE is not set
+# CONFIG_CXL_EEH is not set
+# CONFIG_CXL_KERNEL_API is not set
+# CONFIG_CXL_LIB is not set
+# CONFIG_CYPRESS_FIRMWARE is not set
+# CONFIG_DA280 is not set
+# CONFIG_DA311 is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_DAX is not set
+# CONFIG_DCB is not set
+# CONFIG_DDR is not set
+# CONFIG_DEBUG_ALIGN_RODATA is not set
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_EFI is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_INFO_BTF is not set
+# CONFIG_DEBUG_INFO_DWARF4 is not set
+CONFIG_DEBUG_INFO_REDUCED=y
+# CONFIG_DEBUG_INFO_SPLIT is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_KOBJECT_RELEASE is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_LL is not set
+# CONFIG_DEBUG_LL_UART_8250 is not set
+# CONFIG_DEBUG_LL_UART_PL01X is not set
+# CONFIG_DEBUG_LOCKDEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_MISC is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_NX_TEST is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_DEBUG_PAGE_REF is not set
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+# CONFIG_DEBUG_PER_CPU_MAPS is not set
+# CONFIG_DEBUG_PINCTRL is not set
+# CONFIG_DEBUG_PI_LIST is not set
+# CONFIG_DEBUG_PLIST is not set
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_DEBUG_RODATA_TEST is not set
+# CONFIG_DEBUG_RSEQ is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+# CONFIG_DEBUG_SEMIHOSTING is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set
+# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set
+# CONFIG_DEBUG_TIMEKEEPING is not set
+# CONFIG_DEBUG_UART_8250_PALMCHIP is not set
+# CONFIG_DEBUG_UART_BCM63XX is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_VIRTUAL is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set
+# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
+# CONFIG_DEBUG_WX is not set
+# CONFIG_DEBUG_ZBOOT is not set
+# CONFIG_DECNET is not set
+CONFIG_DEFAULT_CUBIC=y
+CONFIG_DEFAULT_DEADLINE=y
+CONFIG_DEFAULT_HOSTNAME="(none)"
+CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
+CONFIG_DEFAULT_IOSCHED="deadline"
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_DEFAULT_NOOP is not set
+# CONFIG_DEFAULT_RENO is not set
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_DEFAULT_SECURITY_DAC=y
+# CONFIG_DEFAULT_SECURITY_SELINUX is not set
+CONFIG_DEFAULT_TCP_CONG="cubic"
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set
+# CONFIG_DELL_LAPTOP is not set
+# CONFIG_DELL_RBTN is not set
+# CONFIG_DELL_SMBIOS is not set
+# CONFIG_DELL_SMO8800 is not set
+# CONFIG_DEPRECATED_PARAM_STRUCT is not set
+# CONFIG_DETECT_HUNG_TASK is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_DEVMEM is not set
+CONFIG_DEVPORT=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_DEVTMPFS is not set
+# CONFIG_DEVTMPFS_MOUNT is not set
+# CONFIG_DEV_DAX is not set
+# CONFIG_DGAP is not set
+# CONFIG_DGNC is not set
+# CONFIG_DHT11 is not set
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_DISPLAY_CONNECTOR_ANALOG_TV is not set
+# CONFIG_DISPLAY_CONNECTOR_DVI is not set
+# CONFIG_DISPLAY_CONNECTOR_HDMI is not set
+# CONFIG_DISPLAY_ENCODER_TFP410 is not set
+# CONFIG_DISPLAY_ENCODER_TPD12S015 is not set
+# CONFIG_DISPLAY_PANEL_DPI is not set
+# CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02 is not set
+# CONFIG_DISPLAY_PANEL_TPO_TD028TTEC1 is not set
+# CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1 is not set
+# CONFIG_DL2K is not set
+# CONFIG_DLM is not set
+# CONFIG_DM9000 is not set
+# CONFIG_DMABUF_SELFTESTS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_DMADEVICES_DEBUG is not set
+# CONFIG_DMARD06 is not set
+# CONFIG_DMARD09 is not set
+# CONFIG_DMARD10 is not set
+# CONFIG_DMASCC is not set
+# CONFIG_DMATEST is not set
+# CONFIG_DMA_API_DEBUG is not set
+CONFIG_DMA_DECLARE_COHERENT=y
+# CONFIG_DMA_ENGINE is not set
+# CONFIG_DMA_FENCE_TRACE is not set
+# CONFIG_DMA_JZ4780 is not set
+# CONFIG_DMA_NOOP_OPS is not set
+# CONFIG_DMA_SHARED_BUFFER is not set
+# CONFIG_DMA_VIRT_OPS is not set
+# CONFIG_DM_CACHE is not set
+# CONFIG_DM_CLONE is not set
+# CONFIG_DM_DEBUG is not set
+# CONFIG_DM_DELAY is not set
+# CONFIG_DM_DUST is not set
+# CONFIG_DM_ERA is not set
+# CONFIG_DM_FLAKEY is not set
+# CONFIG_DM_INTEGRITY is not set
+# CONFIG_DM_LOG_USERSPACE is not set
+# CONFIG_DM_LOG_WRITES is not set
+# CONFIG_DM_MQ_DEFAULT is not set
+# CONFIG_DM_MULTIPATH is not set
+# CONFIG_DM_RAID is not set
+# CONFIG_DM_SWITCH is not set
+# CONFIG_DM_THIN_PROVISIONING is not set
+# CONFIG_DM_UEVENT is not set
+# CONFIG_DM_UNSTRIPED is not set
+# CONFIG_DM_VERITY is not set
+# CONFIG_DM_WRITECACHE is not set
+# CONFIG_DM_ZERO is not set
+# CONFIG_DNET is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_DNS_RESOLVER is not set
+CONFIG_DOUBLEFAULT=y
+# CONFIG_DP83822_PHY is not set
+# CONFIG_DP83848_PHY is not set
+# CONFIG_DP83867_PHY is not set
+# CONFIG_DP83TC811_PHY is not set
+# CONFIG_DPOT_DAC is not set
+# CONFIG_DPS310 is not set
+CONFIG_DQL=y
+# CONFIG_DRAGONRISE_FF is not set
+# CONFIG_DRM is not set
+# CONFIG_DRM_AMDGPU is not set
+# CONFIG_DRM_AMDGPU_CIK is not set
+# CONFIG_DRM_AMDGPU_GART_DEBUGFS is not set
+# CONFIG_DRM_AMDGPU_SI is not set
+# CONFIG_DRM_AMDGPU_USERPTR is not set
+# CONFIG_DRM_AMD_ACP is not set
+# CONFIG_DRM_AMD_DC_DCN2_0 is not set
+# CONFIG_DRM_ANALOGIX_ANX78XX is not set
+# CONFIG_DRM_ARCPGU is not set
+# CONFIG_DRM_ARMADA is not set
+# CONFIG_DRM_AST is not set
+# CONFIG_DRM_BOCHS is not set
+# CONFIG_DRM_CDNS_DSI is not set
+# CONFIG_DRM_CIRRUS_QEMU is not set
+# CONFIG_DRM_DEBUG_MM is not set
+# CONFIG_DRM_DEBUG_SELFTEST is not set
+# CONFIG_DRM_DP_AUX_CHARDEV is not set
+# CONFIG_DRM_DP_CEC is not set
+# CONFIG_DRM_DUMB_VGA_DAC is not set
+# CONFIG_DRM_DW_HDMI_CEC is not set
+# CONFIG_DRM_ETNAVIV is not set
+# CONFIG_DRM_EXYNOS is not set
+# CONFIG_DRM_FBDEV_EMULATION is not set
+# CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM is not set
+# CONFIG_DRM_FSL_DCU is not set
+# CONFIG_DRM_GM12U320 is not set
+# CONFIG_DRM_GMA500 is not set
+# CONFIG_DRM_HDLCD is not set
+# CONFIG_DRM_HISI_HIBMC is not set
+# CONFIG_DRM_HISI_KIRIN is not set
+# CONFIG_DRM_I2C_ADV7511 is not set
+# CONFIG_DRM_I2C_CH7006 is not set
+# CONFIG_DRM_I2C_NXP_TDA9950 is not set
+# CONFIG_DRM_I2C_NXP_TDA998X is not set
+# CONFIG_DRM_I2C_SIL164 is not set
+# CONFIG_DRM_I915 is not set
+# CONFIG_DRM_KOMEDA is not set
+# CONFIG_DRM_LEGACY is not set
+# CONFIG_DRM_LIB_RANDOM is not set
+# CONFIG_DRM_LIMA is not set
+# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set
+# CONFIG_DRM_LVDS_ENCODER is not set
+# CONFIG_DRM_MALI_DISPLAY is not set
+# CONFIG_DRM_MCDE is not set
+# CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW is not set
+# CONFIG_DRM_MGAG200 is not set
+# CONFIG_DRM_MXSFB is not set
+# CONFIG_DRM_NOUVEAU is not set
+# CONFIG_DRM_NXP_PTN3460 is not set
+# CONFIG_DRM_OMAP is not set
+# CONFIG_DRM_PANEL_ARM_VERSATILE is not set
+# CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D is not set
+# CONFIG_DRM_PANEL_ILITEK_IL9322 is not set
+# CONFIG_DRM_PANEL_ILITEK_ILI9881C is not set
+# CONFIG_DRM_PANEL_INNOLUX_P079ZCA is not set
+# CONFIG_DRM_PANEL_JDI_LT070ME05000 is not set
+# CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04 is not set
+# CONFIG_DRM_PANEL_LG_LB035Q02 is not set
+# CONFIG_DRM_PANEL_LG_LG4573 is not set
+# CONFIG_DRM_PANEL_LVDS is not set
+# CONFIG_DRM_PANEL_NEC_NL8048HL11 is not set
+# CONFIG_DRM_PANEL_NOVATEK_NT39016 is not set
+# CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO is not set
+# CONFIG_DRM_PANEL_ORISETECH_OTM8009A is not set
+# CONFIG_DRM_PANEL_OSD_OSD101T2587_53TS is not set
+# CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00 is not set
+# CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN is not set
+# CONFIG_DRM_PANEL_RAYDIUM_RM67191 is not set
+# CONFIG_DRM_PANEL_RAYDIUM_RM68200 is not set
+# CONFIG_DRM_PANEL_ROCKTECH_JH057N00900 is not set
+# CONFIG_DRM_PANEL_RONBO_RB070D30 is not set
+# CONFIG_DRM_PANEL_SAMSUNG_LD9040 is not set
+# CONFIG_DRM_PANEL_SAMSUNG_S6D16D0 is not set
+# CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2 is not set
+# CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03 is not set
+# CONFIG_DRM_PANEL_SAMSUNG_S6E63M0 is not set
+# CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set
+# CONFIG_DRM_PANEL_SEIKO_43WVF1G is not set
+# CONFIG_DRM_PANEL_SHARP_LQ101R1SX01 is not set
+# CONFIG_DRM_PANEL_SHARP_LS037V7DW01 is not set
+# CONFIG_DRM_PANEL_SHARP_LS043T1LE01 is not set
+# CONFIG_DRM_PANEL_SIMPLE is not set
+# CONFIG_DRM_PANEL_SITRONIX_ST7701 is not set
+# CONFIG_DRM_PANEL_SITRONIX_ST7789V is not set
+# CONFIG_DRM_PANEL_SONY_ACX565AKM is not set
+# CONFIG_DRM_PANEL_TPO_TD028TTEC1 is not set
+# CONFIG_DRM_PANEL_TPO_TD043MTEA1 is not set
+# CONFIG_DRM_PANEL_TPO_TPG110 is not set
+# CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA is not set
+# CONFIG_DRM_PANFROST is not set
+# CONFIG_DRM_PARADE_PS8622 is not set
+# CONFIG_DRM_PL111 is not set
+# CONFIG_DRM_QXL is not set
+# CONFIG_DRM_RADEON is not set
+# CONFIG_DRM_RADEON_USERPTR is not set
+# CONFIG_DRM_RCAR_DW_HDMI is not set
+# CONFIG_DRM_RCAR_LVDS is not set
+# CONFIG_DRM_SII902X is not set
+# CONFIG_DRM_SII9234 is not set
+# CONFIG_DRM_SIL_SII8620 is not set
+# CONFIG_DRM_STI is not set
+# CONFIG_DRM_STM is not set
+# CONFIG_DRM_SUN4I is not set
+# CONFIG_DRM_THINE_THC63LVD1024 is not set
+# CONFIG_DRM_TILCDC is not set
+# CONFIG_DRM_TINYDRM is not set
+# CONFIG_DRM_TI_SN65DSI86 is not set
+# CONFIG_DRM_TI_TFP410 is not set
+# CONFIG_DRM_TOSHIBA_TC358764 is not set
+# CONFIG_DRM_TOSHIBA_TC358767 is not set
+# CONFIG_DRM_UDL is not set
+# CONFIG_DRM_VBOXVIDEO is not set
+# CONFIG_DRM_VC4_HDMI_CEC is not set
+# CONFIG_DRM_VGEM is not set
+# CONFIG_DRM_VIRTIO_GPU is not set
+# CONFIG_DRM_VKMS is not set
+# CONFIG_DRM_VMWGFX is not set
+# CONFIG_DRM_XEN is not set
+# CONFIG_DS1682 is not set
+# CONFIG_DS1803 is not set
+# CONFIG_DS4424 is not set
+# CONFIG_DST_CACHE is not set
+# CONFIG_DTLK is not set
+# CONFIG_DUMMY is not set
+CONFIG_DUMMY_CONSOLE_COLUMNS=80
+CONFIG_DUMMY_CONSOLE_ROWS=25
+# CONFIG_DUMMY_IRQ is not set
+# CONFIG_DVB_AU8522_V4L is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DVB_DUMMY_FE is not set
+# CONFIG_DVB_TUNER_DIB0070 is not set
+# CONFIG_DVB_TUNER_DIB0090 is not set
+# CONFIG_DWC_XLGMAC is not set
+# CONFIG_DWMAC_DWC_QOS_ETH is not set
+# CONFIG_DWMAC_IPQ806X is not set
+# CONFIG_DWMAC_LPC18XX is not set
+# CONFIG_DWMAC_MESON is not set
+# CONFIG_DWMAC_ROCKCHIP is not set
+# CONFIG_DWMAC_SOCFPGA is not set
+# CONFIG_DWMAC_STI is not set
+# CONFIG_DW_AXI_DMAC is not set
+# CONFIG_DW_DMAC is not set
+# CONFIG_DW_DMAC_PCI is not set
+# CONFIG_DW_EDMA is not set
+# CONFIG_DW_EDMA_PCIE is not set
+# CONFIG_DW_WATCHDOG is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_E100 is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_E1000E_HWTS is not set
+# CONFIG_EARLY_PRINTK_8250 is not set
+# CONFIG_EARLY_PRINTK_USB_XDBC is not set
+# CONFIG_EBC_C384_WDT is not set
+# CONFIG_ECHO is not set
+# CONFIG_ECRYPT_FS is not set
+# CONFIG_EDAC is not set
+# CONFIG_EEEPC_LAPTOP is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_EEPROM_93XX46 is not set
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_DIGSY_MTC_CFG is not set
+# CONFIG_EEPROM_EE1004 is not set
+# CONFIG_EEPROM_IDT_89HPESX is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EFI is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_EFS_FS is not set
+CONFIG_ELFCORE=y
+# CONFIG_ELF_CORE is not set
+# CONFIG_EMAC_ROCKCHIP is not set
+CONFIG_EMBEDDED=y
+# CONFIG_EM_TIMER_STI is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+# CONFIG_ENA_ETHERNET is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ENCRYPTED_KEYS is not set
+# CONFIG_ENCX24J600 is not set
+# CONFIG_ENERGY_MODEL is not set
+# CONFIG_ENIC is not set
+# CONFIG_ENVELOPE_DETECTOR is not set
+# CONFIG_EPAPR_PARAVIRT is not set
+# CONFIG_EPIC100 is not set
+CONFIG_EPOLL=y
+# CONFIG_EQUALIZER is not set
+# CONFIG_EROFS_FS is not set
+# CONFIG_ET131X is not set
+CONFIG_ETHERNET=y
+# CONFIG_ETHOC is not set
+CONFIG_EVENTFD=y
+# CONFIG_EVM is not set
+# CONFIG_EXFAT_FS is not set
+CONFIG_EXPERT=y
+CONFIG_EXPORTFS=y
+# CONFIG_EXPORTFS_BLOCK_OPS is not set
+# CONFIG_EXT2_FS is not set
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_DEBUG is not set
+# CONFIG_EXT4_ENCRYPTION is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_EXT4_FS_POSIX_ACL is not set
+# CONFIG_EXT4_FS_SECURITY is not set
+CONFIG_EXT4_USE_FOR_EXT2=y
+# CONFIG_EXTCON is not set
+# CONFIG_EXTCON_ADC_JACK is not set
+# CONFIG_EXTCON_ARIZONA is not set
+# CONFIG_EXTCON_AXP288 is not set
+# CONFIG_EXTCON_FSA9480 is not set
+# CONFIG_EXTCON_GPIO is not set
+# CONFIG_EXTCON_INTEL_INT3496 is not set
+# CONFIG_EXTCON_MAX3355 is not set
+# CONFIG_EXTCON_PTN5150 is not set
+# CONFIG_EXTCON_QCOM_SPMI_MISC is not set
+# CONFIG_EXTCON_RT8973A is not set
+# CONFIG_EXTCON_SM5502 is not set
+# CONFIG_EXTCON_USB_GPIO is not set
+CONFIG_EXTRA_FIRMWARE=""
+CONFIG_EXTRA_TARGETS=""
+# CONFIG_EXYNOS_ADC is not set
+# CONFIG_EXYNOS_VIDEO is not set
+# CONFIG_EZCHIP_NPS_MANAGEMENT_ENET is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_F2FS_CHECK_FS is not set
+# CONFIG_F2FS_FAULT_INJECTION is not set
+# CONFIG_F2FS_FS is not set
+# CONFIG_F2FS_FS_ENCRYPTION is not set
+# CONFIG_F2FS_FS_POSIX_ACL is not set
+# CONFIG_F2FS_FS_SECURITY is not set
+CONFIG_F2FS_FS_XATTR=y
+# CONFIG_F2FS_IO_TRACE is not set
+CONFIG_F2FS_STAT_FS=y
+# CONFIG_FAILOVER is not set
+# CONFIG_FAIR_GROUP_SCHED is not set
+# CONFIG_FANOTIFY is not set
+# CONFIG_FANOTIFY_ACCESS_PERMISSIONS is not set
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_FAT_DEFAULT_UTF8 is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_FB is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_ARC is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_ARMCLCD is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_AUO_K190X is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_BIG_ENDIAN is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_BOTH_ENDIAN is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_FB_CARMINE is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_DA8XX is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_FLEX is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_GEODE is not set
+# CONFIG_FB_GOLDFISH is not set
+# CONFIG_FB_HGA is not set
+# CONFIG_FB_I740 is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_IMX is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_LE80578 is not set
+# CONFIG_FB_LITTLE_ENDIAN is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_MXS is not set
+# CONFIG_FB_N411 is not set
+# CONFIG_FB_NEOMAGIC is not set
+CONFIG_FB_NOTIFY=y
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_OF is not set
+# CONFIG_FB_OMAP2 is not set
+# CONFIG_FB_OPENCORES is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_PS3 is not set
+# CONFIG_FB_PXA is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIMPLE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_SM712 is not set
+# CONFIG_FB_SM750 is not set
+# CONFIG_FB_SMSCUFX is not set
+# CONFIG_FB_SSD1307 is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_TFT is not set
+# CONFIG_FB_TFT_AGM1264K_FL is not set
+# CONFIG_FB_TFT_BD663474 is not set
+# CONFIG_FB_TFT_FBTFT_DEVICE is not set
+# CONFIG_FB_TFT_HX8340BN is not set
+# CONFIG_FB_TFT_HX8347D is not set
+# CONFIG_FB_TFT_HX8353D is not set
+# CONFIG_FB_TFT_HX8357D is not set
+# CONFIG_FB_TFT_ILI9163 is not set
+# CONFIG_FB_TFT_ILI9320 is not set
+# CONFIG_FB_TFT_ILI9325 is not set
+# CONFIG_FB_TFT_ILI9340 is not set
+# CONFIG_FB_TFT_ILI9341 is not set
+# CONFIG_FB_TFT_ILI9481 is not set
+# CONFIG_FB_TFT_ILI9486 is not set
+# CONFIG_FB_TFT_PCD8544 is not set
+# CONFIG_FB_TFT_RA8875 is not set
+# CONFIG_FB_TFT_S6D02A1 is not set
+# CONFIG_FB_TFT_S6D1121 is not set
+# CONFIG_FB_TFT_SH1106 is not set
+# CONFIG_FB_TFT_SSD1289 is not set
+# CONFIG_FB_TFT_SSD1305 is not set
+# CONFIG_FB_TFT_SSD1306 is not set
+# CONFIG_FB_TFT_SSD1325 is not set
+# CONFIG_FB_TFT_SSD1331 is not set
+# CONFIG_FB_TFT_SSD1351 is not set
+# CONFIG_FB_TFT_ST7735R is not set
+# CONFIG_FB_TFT_ST7789V is not set
+# CONFIG_FB_TFT_TINYLCD is not set
+# CONFIG_FB_TFT_TLS8204 is not set
+# CONFIG_FB_TFT_UC1611 is not set
+# CONFIG_FB_TFT_UC1701 is not set
+# CONFIG_FB_TFT_UPD161704 is not set
+# CONFIG_FB_TFT_WATTEROTT is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_TMIO is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_UDL is not set
+# CONFIG_FB_UVESA is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_VIA is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_XGI is not set
+# CONFIG_FCOE is not set
+# CONFIG_FCOE_FNIC is not set
+# CONFIG_FDDI is not set
+# CONFIG_FEALNX is not set
+# CONFIG_FENCE_TRACE is not set
+# CONFIG_FHANDLE is not set
+CONFIG_FIB_RULES=y
+# CONFIG_FIELDBUS_DEV is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_FIND_BIT_BENCHMARK is not set
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+# CONFIG_FIREWIRE_SERIAL is not set
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+# CONFIG_FIRMWARE_MEMMAP is not set
+# CONFIG_FIXED_PHY is not set
+CONFIG_FLATMEM=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_FM10K is not set
+# CONFIG_FMC is not set
+# CONFIG_FONTS is not set
+# CONFIG_FONT_TER16x32 is not set
+# CONFIG_FORCEDETH is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_FORTIFY_SOURCE=y
+# CONFIG_FPGA is not set
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER is not set
+# CONFIG_FRAME_POINTER is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_FREEZER is not set
+# CONFIG_FRONTSWAP is not set
+# CONFIG_FSCACHE is not set
+# CONFIG_FSI is not set
+# CONFIG_FSL_EDMA is not set
+# CONFIG_FSL_ERRATUM_A008585 is not set
+# CONFIG_FSL_MC_BUS is not set
+# CONFIG_FSL_PQ_MDIO is not set
+# CONFIG_FSL_QDMA is not set
+# CONFIG_FSL_XGMAC_MDIO is not set
+CONFIG_FSNOTIFY=y
+# CONFIG_FS_DAX is not set
+# CONFIG_FS_ENCRYPTION is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_FS_VERITY is not set
+# CONFIG_FTGMAC100 is not set
+# CONFIG_FTL is not set
+# CONFIG_FTMAC100 is not set
+# CONFIG_FTRACE is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_FTR_FIXUP_SELFTEST is not set
+# CONFIG_FTWDT010_WATCHDOG is not set
+# CONFIG_FUJITSU_ES is not set
+# CONFIG_FUJITSU_LAPTOP is not set
+# CONFIG_FUJITSU_TABLET is not set
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_FUSE_FS is not set
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+# CONFIG_FUSION_SPI is not set
+CONFIG_FUTEX=y
+CONFIG_FUTEX_PI=y
+# CONFIG_FW_CFG_SYSFS is not set
+CONFIG_FW_LOADER=y
+# CONFIG_FW_LOADER_COMPRESS is not set
+CONFIG_FW_LOADER_USER_HELPER=y
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+# CONFIG_FXAS21002C is not set
+# CONFIG_FXOS8700_I2C is not set
+# CONFIG_FXOS8700_SPI is not set
+CONFIG_GACT_PROB=y
+# CONFIG_GADGET_UAC1 is not set
+# CONFIG_GAMEPORT is not set
+# CONFIG_GATEWORKS_GW16083 is not set
+# CONFIG_GCC_PLUGINS is not set
+# CONFIG_GCOV is not set
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_GDB_SCRIPTS is not set
+# CONFIG_GEMINI_ETHERNET is not set
+# CONFIG_GENERIC_ADC_BATTERY is not set
+# CONFIG_GENERIC_ADC_THERMAL is not set
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+# CONFIG_GENERIC_CPU_DEVICES is not set
+CONFIG_GENERIC_HWEIGHT=y
+# CONFIG_GENERIC_IRQ_DEBUGFS is not set
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_NET_UTILS=y
+# CONFIG_GENERIC_PHY is not set
+# CONFIG_GENEVE is not set
+# CONFIG_GENWQE is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_GIGASET_CAPI is not set
+# CONFIG_GIGASET_DEBUG is not set
+# CONFIG_GIGASET_DUMMYLL is not set
+# CONFIG_GLOB_SELFTEST is not set
+# CONFIG_GNSS is not set
+# CONFIG_GOLDFISH is not set
+# CONFIG_GOOGLE_FIRMWARE is not set
+# CONFIG_GP2AP020A00F is not set
+# CONFIG_GPD_POCKET_FAN is not set
+# CONFIG_GPIOLIB is not set
+CONFIG_GPIOLIB_FASTPATH_LIMIT=512
+# CONFIG_GPIO_104_DIO_48E is not set
+# CONFIG_GPIO_104_IDIO_16 is not set
+# CONFIG_GPIO_104_IDI_48 is not set
+# CONFIG_GPIO_74X164 is not set
+# CONFIG_GPIO_74XX_MMIO is not set
+# CONFIG_GPIO_ADNP is not set
+# CONFIG_GPIO_ADP5588 is not set
+# CONFIG_GPIO_ALTERA is not set
+# CONFIG_GPIO_AMD8111 is not set
+# CONFIG_GPIO_AMDPT is not set
+# CONFIG_GPIO_AMD_FCH is not set
+# CONFIG_GPIO_BCM_KONA is not set
+# CONFIG_GPIO_BT8XX is not set
+# CONFIG_GPIO_CADENCE is not set
+# CONFIG_GPIO_CS5535 is not set
+# CONFIG_GPIO_DWAPB is not set
+# CONFIG_GPIO_EM is not set
+# CONFIG_GPIO_EXAR is not set
+# CONFIG_GPIO_F7188X is not set
+# CONFIG_GPIO_FTGPIO010 is not set
+# CONFIG_GPIO_GENERIC_PLATFORM is not set
+# CONFIG_GPIO_GPIO_MM is not set
+# CONFIG_GPIO_GRGPIO is not set
+# CONFIG_GPIO_GW_PLD is not set
+# CONFIG_GPIO_HLWD is not set
+# CONFIG_GPIO_ICH is not set
+# CONFIG_GPIO_IT87 is not set
+# CONFIG_GPIO_LYNXPOINT is not set
+# CONFIG_GPIO_MAX3191X is not set
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_MB86S7X is not set
+# CONFIG_GPIO_MC33880 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_ML_IOH is not set
+# CONFIG_GPIO_MOCKUP is not set
+# CONFIG_GPIO_MPC8XXX is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_PCH is not set
+# CONFIG_GPIO_PCIE_IDIO_24 is not set
+# CONFIG_GPIO_PCI_IDIO_16 is not set
+# CONFIG_GPIO_PISOSR is not set
+# CONFIG_GPIO_PL061 is not set
+# CONFIG_GPIO_RCAR is not set
+# CONFIG_GPIO_RDC321X is not set
+# CONFIG_GPIO_SAMA5D2_PIOBU is not set
+# CONFIG_GPIO_SCH is not set
+# CONFIG_GPIO_SCH311X is not set
+# CONFIG_GPIO_SX150X is not set
+# CONFIG_GPIO_SYSCON is not set
+CONFIG_GPIO_SYSFS=y
+# CONFIG_GPIO_TPIC2810 is not set
+# CONFIG_GPIO_TS4900 is not set
+# CONFIG_GPIO_TS5500 is not set
+# CONFIG_GPIO_VX855 is not set
+# CONFIG_GPIO_WATCHDOG is not set
+# CONFIG_GPIO_WINBOND is not set
+# CONFIG_GPIO_WS16C48 is not set
+# CONFIG_GPIO_XGENE is not set
+# CONFIG_GPIO_XILINX is not set
+# CONFIG_GPIO_XRA1403 is not set
+# CONFIG_GPIO_ZEVIO is not set
+# CONFIG_GPIO_ZX is not set
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_GREYBUS is not set
+# CONFIG_GS_FPGABOOT is not set
+# CONFIG_GTP is not set
+# CONFIG_GUP_BENCHMARK is not set
+# CONFIG_GVE is not set
+# CONFIG_HABANA_AI is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_HAPPYMEAL is not set
+CONFIG_HARDENED_USERCOPY=y
+# CONFIG_HARDENED_USERCOPY_FALLBACK is not set
+# CONFIG_HARDENED_USERCOPY_PAGESPAN is not set
+CONFIG_HARDEN_EL2_VECTORS=y
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+# CONFIG_HAVE_AOUT is not set
+CONFIG_HAVE_ARCH_HARDENED_USERCOPY=y
+# CONFIG_HAVE_ARCH_HASH is not set
+CONFIG_HAVE_ARCH_MMAP_RND_BITS=y
+# CONFIG_HAVE_ARCH_VMAP_STACK is not set
+CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y
+# CONFIG_HAVE_ARM_ARCH_TIMER is not set
+CONFIG_HAVE_EXIT_THREAD=y
+CONFIG_HAVE_GCC_PLUGINS=y
+CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y
+CONFIG_HAVE_KERNEL_BZIP2=y
+CONFIG_HAVE_KERNEL_CAT=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZ4=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_NMI=y
+CONFIG_HAVE_STACKPROTECTOR=y
+# CONFIG_HCALL_STATS is not set
+# CONFIG_HDC100X is not set
+# CONFIG_HDLC is not set
+# CONFIG_HDLC_CISCO is not set
+# CONFIG_HDLC_FR is not set
+# CONFIG_HDLC_PPP is not set
+# CONFIG_HDLC_RAW is not set
+# CONFIG_HDLC_RAW_ETH is not set
+# CONFIG_HDMI_LPE_AUDIO is not set
+# CONFIG_HDQ_MASTER_OMAP is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_HEADERS_INSTALL is not set
+# CONFIG_HEADER_TEST is not set
+# CONFIG_HERMES is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_HFSPLUS_FS_POSIX_ACL is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFS_FS_POSIX_ACL is not set
+# CONFIG_HI8435 is not set
+# CONFIG_HIBERNATION is not set
+# CONFIG_HID is not set
+# CONFIG_HIDRAW is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_ACCUTOUCH is not set
+# CONFIG_HID_ACRUX is not set
+# CONFIG_HID_ACRUX_FF is not set
+# CONFIG_HID_ALPS is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_APPLEIR is not set
+# CONFIG_HID_ASUS is not set
+# CONFIG_HID_AUREAL is not set
+# CONFIG_HID_BATTERY_STRENGTH is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_BETOP_FF is not set
+# CONFIG_HID_BIGBEN_FF is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CMEDIA is not set
+# CONFIG_HID_CORSAIR is not set
+# CONFIG_HID_COUGAR is not set
+# CONFIG_HID_CP2112 is not set
+# CONFIG_HID_CREATIVE_SB0540 is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_ELAN is not set
+# CONFIG_HID_ELECOM is not set
+# CONFIG_HID_ELO is not set
+# CONFIG_HID_EMS_FF is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_GEMBIRD is not set
+# CONFIG_HID_GENERIC is not set
+# CONFIG_HID_GFRM is not set
+# CONFIG_HID_GOOGLE_HAMMER is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_GT683R is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_HOLTEK is not set
+# CONFIG_HID_ICADE is not set
+# CONFIG_HID_ITE is not set
+# CONFIG_HID_JABRA is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_KEYTOUCH is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_LCPOWER is not set
+# CONFIG_HID_LED is not set
+# CONFIG_HID_LENOVO is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_LOGITECH_DJ is not set
+# CONFIG_HID_LOGITECH_HIDPP is not set
+# CONFIG_HID_MACALLY is not set
+# CONFIG_HID_MAGICMOUSE is not set
+# CONFIG_HID_MALTRON is not set
+# CONFIG_HID_MAYFLASH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_MULTITOUCH is not set
+# CONFIG_HID_NTI is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PENMOUNT is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_PID is not set
+# CONFIG_HID_PLANTRONICS is not set
+# CONFIG_HID_PRIMAX is not set
+# CONFIG_HID_PRODIKEYS is not set
+# CONFIG_HID_REDRAGON is not set
+# CONFIG_HID_RETRODE is not set
+# CONFIG_HID_RMI is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_SAITEK is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SENSOR_HUB is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SPEEDLINK is not set
+# CONFIG_HID_STEAM is not set
+# CONFIG_HID_STEELSERIES is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_THINGM is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_TIVO is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_U2FZERO is not set
+# CONFIG_HID_UCLOGIC is not set
+# CONFIG_HID_UDRAW_PS3 is not set
+# CONFIG_HID_VIEWSONIC is not set
+# CONFIG_HID_WACOM is not set
+# CONFIG_HID_WALTOP is not set
+# CONFIG_HID_WIIMOTE is not set
+# CONFIG_HID_XINMO is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_HIGH_RES_TIMERS=y
+# CONFIG_HINIC is not set
+# CONFIG_HIP04_ETH is not set
+# CONFIG_HIPPI is not set
+# CONFIG_HISILICON_ERRATUM_161010101 is not set
+# CONFIG_HISILICON_ERRATUM_161600802 is not set
+# CONFIG_HISI_FEMAC is not set
+# CONFIG_HIX5HD2_GMAC is not set
+# CONFIG_HMC6352 is not set
+# CONFIG_HNS is not set
+# CONFIG_HNS3 is not set
+# CONFIG_HNS_DSAF is not set
+# CONFIG_HNS_ENET is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_HOSTAP_CS is not set
+# CONFIG_HOSTAP_PCI is not set
+# CONFIG_HOSTAP_PLX is not set
+# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HP03 is not set
+# CONFIG_HP100 is not set
+# CONFIG_HP206C is not set
+CONFIG_HPET_MMAP_DEFAULT=y
+# CONFIG_HPFS_FS is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_HP_WIRELESS is not set
+# CONFIG_HSA_AMD is not set
+# CONFIG_HSI is not set
+# CONFIG_HSR is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_I2CPLD is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_HTS221 is not set
+# CONFIG_HTU21 is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_HVC_DCC is not set
+# CONFIG_HVC_UDBG is not set
+# CONFIG_HWLAT_TRACER is not set
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWSPINLOCK is not set
+# CONFIG_HWSPINLOCK_OMAP is not set
+CONFIG_HW_PERF_EVENTS=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HW_RANDOM_AMD is not set
+# CONFIG_HW_RANDOM_ATMEL is not set
+# CONFIG_HW_RANDOM_CAVIUM is not set
+# CONFIG_HW_RANDOM_EXYNOS is not set
+# CONFIG_HW_RANDOM_GEODE is not set
+# CONFIG_HW_RANDOM_INTEL is not set
+# CONFIG_HW_RANDOM_IPROC_RNG200 is not set
+# CONFIG_HW_RANDOM_OMAP is not set
+# CONFIG_HW_RANDOM_OMAP3_ROM is not set
+# CONFIG_HW_RANDOM_PPC4XX is not set
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+CONFIG_HW_RANDOM_TPM=y
+# CONFIG_HW_RANDOM_VIA is not set
+# CONFIG_HW_RANDOM_VIRTIO is not set
+# CONFIG_HX711 is not set
+# CONFIG_HYPERV is not set
+# CONFIG_HYPERV_TSCPAGE is not set
+# CONFIG_HYSDN is not set
+# CONFIG_HZ is not set
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_200 is not set
+# CONFIG_HZ_24 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_48 is not set
+# CONFIG_HZ_500 is not set
+# CONFIG_HZ_PERIODIC is not set
+# CONFIG_I2C is not set
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCA is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set
+# CONFIG_I2C_AU1550 is not set
+# CONFIG_I2C_BCM2835 is not set
+# CONFIG_I2C_BCM_IPROC is not set
+# CONFIG_I2C_CADENCE is not set
+# CONFIG_I2C_CBUS_GPIO is not set
+# CONFIG_I2C_CHARDEV is not set
+# CONFIG_I2C_COMPAT is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEMUX_PINCTRL is not set
+# CONFIG_I2C_DESIGNWARE_PCI is not set
+# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
+# CONFIG_I2C_DIOLAN_U2C is not set
+# CONFIG_I2C_EG20T is not set
+# CONFIG_I2C_ELEKTOR is not set
+# CONFIG_I2C_EMEV2 is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_GPIO_FAULT_INJECTOR is not set
+# CONFIG_I2C_HELPER_AUTO is not set
+# CONFIG_I2C_HID is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_IBM_IIC is not set
+# CONFIG_I2C_IMG is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_ISMT is not set
+# CONFIG_I2C_JZ4780 is not set
+# CONFIG_I2C_MLXCPLD is not set
+# CONFIG_I2C_MPC is not set
+# CONFIG_I2C_MUX is not set
+# CONFIG_I2C_MUX_GPIO is not set
+# CONFIG_I2C_MUX_GPMUX is not set
+# CONFIG_I2C_MUX_LTC4306 is not set
+# CONFIG_I2C_MUX_MLXCPLD is not set
+# CONFIG_I2C_MUX_PCA9541 is not set
+# CONFIG_I2C_MUX_PCA954x is not set
+# CONFIG_I2C_MUX_PINCTRL is not set
+# CONFIG_I2C_MUX_REG is not set
+# CONFIG_I2C_MV64XXX is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_NOMADIK is not set
+# CONFIG_I2C_NVIDIA_GPU is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_OCTEON is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PCA_ISA is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_PXA_PCI is not set
+# CONFIG_I2C_RCAR is not set
+# CONFIG_I2C_RK3X is not set
+# CONFIG_I2C_ROBOTFUZZ_OSIF is not set
+# CONFIG_I2C_S3C2410 is not set
+# CONFIG_I2C_SCMI is not set
+# CONFIG_I2C_SH_MOBILE is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_SLAVE is not set
+# CONFIG_I2C_SLAVE_EEPROM is not set
+# CONFIG_I2C_SMBUS is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_THUNDERX is not set
+# CONFIG_I2C_TINY_USB is not set
+# CONFIG_I2C_VERSATILE is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_XILINX is not set
+# CONFIG_I3C is not set
+# CONFIG_I40E is not set
+# CONFIG_I40EVF is not set
+# CONFIG_I6300ESB_WDT is not set
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+# CONFIG_IAQCORE is not set
+# CONFIG_IBM_ASM is not set
+# CONFIG_IBM_EMAC_DEBUG is not set
+# CONFIG_IBM_EMAC_EMAC4 is not set
+# CONFIG_IBM_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_IBM_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_EMAC_RGMII is not set
+# CONFIG_IBM_EMAC_TAH is not set
+# CONFIG_IBM_EMAC_ZMII is not set
+# CONFIG_ICE is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_IDE is not set
+# CONFIG_IDEAPAD_LAPTOP is not set
+# CONFIG_IDE_GD is not set
+# CONFIG_IDE_PROC_FS is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDLE_PAGE_TRACKING is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_IEEE802154_ADF7242 is not set
+# CONFIG_IEEE802154_ATUSB is not set
+# CONFIG_IEEE802154_CA8210 is not set
+# CONFIG_IEEE802154_HWSIM is not set
+# CONFIG_IEEE802154_MCR20A is not set
+# CONFIG_IFB is not set
+# CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
+# CONFIG_IGC is not set
+# CONFIG_IIO is not set
+# CONFIG_IIO_BUFFER is not set
+# CONFIG_IIO_BUFFER_CB is not set
+# CONFIG_IIO_BUFFER_HW_CONSUMER is not set
+# CONFIG_IIO_CONFIGFS is not set
+CONFIG_IIO_CONSUMERS_PER_TRIGGER=2
+# CONFIG_IIO_CROS_EC_ACCEL_LEGACY is not set
+# CONFIG_IIO_INTERRUPT_TRIGGER is not set
+# CONFIG_IIO_MUX is not set
+# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set
+# CONFIG_IIO_RESCALE is not set
+# CONFIG_IIO_SIMPLE_DUMMY is not set
+# CONFIG_IIO_SSP_SENSORHUB is not set
+# CONFIG_IIO_ST_ACCEL_3AXIS is not set
+# CONFIG_IIO_ST_GYRO_3AXIS is not set
+# CONFIG_IIO_ST_LSM6DSX is not set
+# CONFIG_IIO_ST_MAGN_3AXIS is not set
+# CONFIG_IIO_ST_PRESS is not set
+# CONFIG_IIO_SW_DEVICE is not set
+# CONFIG_IIO_SW_TRIGGER is not set
+# CONFIG_IIO_SYSFS_TRIGGER is not set
+# CONFIG_IIO_TRIGGER is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_IKCONFIG_PROC is not set
+# CONFIG_IKHEADERS is not set
+# CONFIG_IMA is not set
+# CONFIG_IMAGE_CMDLINE_HACK is not set
+# CONFIG_IMGPDC_WDT is not set
+# CONFIG_IMG_MDC_DMA is not set
+# CONFIG_IMX7D_ADC is not set
+# CONFIG_IMX_IPUV3_CORE is not set
+# CONFIG_IMX_THERMAL is not set
+# CONFIG_INA2XX_ADC is not set
+# CONFIG_INDIRECT_PIO is not set
+CONFIG_INET=y
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_BEET is not set
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_TCP_DIAG is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_UDP_DIAG is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_INFTL is not set
+# CONFIG_INGENIC_ADC is not set
+# CONFIG_INGENIC_CGU_JZ4725B is not set
+# CONFIG_INGENIC_CGU_JZ4740 is not set
+# CONFIG_INGENIC_CGU_JZ4770 is not set
+# CONFIG_INGENIC_CGU_JZ4780 is not set
+# CONFIG_INGENIC_TCU_CLK is not set
+# CONFIG_INGENIC_TCU_IRQ is not set
+# CONFIG_INGENIC_TIMER is not set
+CONFIG_INIT_ENV_ARG_LIMIT=32
+# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set
+# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set
+CONFIG_INIT_STACK_NONE=y
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_AD714X is not set
+# CONFIG_INPUT_ADXL34X is not set
+# CONFIG_INPUT_APANEL is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_ATLAS_BTNS is not set
+# CONFIG_INPUT_ATMEL_CAPTOUCH is not set
+# CONFIG_INPUT_AXP20X_PEK is not set
+# CONFIG_INPUT_BMA150 is not set
+# CONFIG_INPUT_CM109 is not set
+# CONFIG_INPUT_CMA3000 is not set
+# CONFIG_INPUT_DRV260X_HAPTICS is not set
+# CONFIG_INPUT_DRV2665_HAPTICS is not set
+# CONFIG_INPUT_DRV2667_HAPTICS is not set
+# CONFIG_INPUT_E3X0_BUTTON is not set
+# CONFIG_INPUT_EVBUG is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_GP2A is not set
+# CONFIG_INPUT_GPIO_BEEPER is not set
+# CONFIG_INPUT_GPIO_DECODER is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_GPIO_TILT_POLLED is not set
+# CONFIG_INPUT_GPIO_VIBRA is not set
+# CONFIG_INPUT_IDEAPAD_SLIDEBAR is not set
+# CONFIG_INPUT_IMS_PCU is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_KXTJ9 is not set
+# CONFIG_INPUT_LEDS is not set
+# CONFIG_INPUT_MATRIXKMAP is not set
+# CONFIG_INPUT_MAX8997_HAPTIC is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_MMA8450 is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_MPU3050 is not set
+# CONFIG_INPUT_MSM_VIBRATOR is not set
+# CONFIG_INPUT_PALMAS_PWRBUTTON is not set
+# CONFIG_INPUT_PCF8574 is not set
+# CONFIG_INPUT_PCSPKR is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_PWM_BEEPER is not set
+# CONFIG_INPUT_PWM_VIBRA is not set
+# CONFIG_INPUT_REGULATOR_HAPTIC is not set
+# CONFIG_INPUT_SOC_BUTTON_ARRAY is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_TPS65218_PWRBUTTON is not set
+# CONFIG_INPUT_TWL4030_PWRBUTTON is not set
+# CONFIG_INPUT_TWL4030_VIBRA is not set
+# CONFIG_INPUT_TWL6040_VIBRA is not set
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_INPUT_WISTRON_BTNS is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INT340X_THERMAL is not set
+# CONFIG_INTEGRITY is not set
+# CONFIG_INTEGRITY_AUDIT is not set
+# CONFIG_INTEGRITY_SIGNATURE is not set
+# CONFIG_INTEL_ATOMISP2_PM is not set
+# CONFIG_INTEL_CHT_INT33FE is not set
+# CONFIG_INTEL_HID_EVENT is not set
+# CONFIG_INTEL_IDLE is not set
+# CONFIG_INTEL_IDMA64 is not set
+# CONFIG_INTEL_IOATDMA is not set
+# CONFIG_INTEL_ISH_HID is not set
+# CONFIG_INTEL_MEI is not set
+# CONFIG_INTEL_MEI_ME is not set
+# CONFIG_INTEL_MEI_TXE is not set
+# CONFIG_INTEL_MIC_CARD is not set
+# CONFIG_INTEL_MIC_HOST is not set
+# CONFIG_INTEL_MID_PTI is not set
+# CONFIG_INTEL_OAKTRAIL is not set
+# CONFIG_INTEL_PMC_CORE is not set
+# CONFIG_INTEL_PUNIT_IPC is not set
+# CONFIG_INTEL_RST is not set
+# CONFIG_INTEL_SMARTCONNECT is not set
+# CONFIG_INTEL_SOC_PMIC is not set
+# CONFIG_INTEL_SOC_PMIC_CHTDC_TI is not set
+# CONFIG_INTEL_SOC_PMIC_CHTWC is not set
+# CONFIG_INTEL_TH is not set
+# CONFIG_INTEL_VBTN is not set
+# CONFIG_INTEL_XWAY_PHY is not set
+# CONFIG_INTERCONNECT is not set
+# CONFIG_INTERVAL_TREE_TEST is not set
+# CONFIG_INV_MPU6050_I2C is not set
+# CONFIG_INV_MPU6050_IIO is not set
+# CONFIG_INV_MPU6050_SPI is not set
+# CONFIG_IOMMU_SUPPORT is not set
+# CONFIG_IONIC is not set
+# CONFIG_IOSCHED_BFQ is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IO_STRICT_DEVMEM=y
+# CONFIG_IO_URING is not set
+# CONFIG_IP17XX_PHY is not set
+# CONFIG_IP6_NF_FILTER is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+# CONFIG_IP6_NF_MANGLE is not set
+# CONFIG_IP6_NF_MATCH_AH is not set
+# CONFIG_IP6_NF_MATCH_EUI64 is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+# CONFIG_IP6_NF_MATCH_MH is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_RPFILTER is not set
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_MATCH_SRH is not set
+# CONFIG_IP6_NF_NAT is not set
+# CONFIG_IP6_NF_RAW is not set
+# CONFIG_IP6_NF_SECURITY is not set
+# CONFIG_IP6_NF_TARGET_HL is not set
+# CONFIG_IP6_NF_TARGET_MASQUERADE is not set
+# CONFIG_IP6_NF_TARGET_REJECT is not set
+# CONFIG_IP6_NF_TARGET_SYNPROXY is not set
+# CONFIG_IPACK_BUS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_IPMB_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPV6 is not set
+# CONFIG_IPV6_FOU is not set
+# CONFIG_IPV6_FOU_TUNNEL is not set
+# CONFIG_IPV6_ILA is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_ROUTE_INFO is not set
+# CONFIG_IPV6_SEG6_HMAC is not set
+# CONFIG_IPV6_SIT is not set
+# CONFIG_IPV6_SIT_6RD is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_VTI is not set
+# CONFIG_IPVLAN is not set
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2100_DEBUG is not set
+CONFIG_IPW2100_MONITOR=y
+# CONFIG_IPW2200 is not set
+# CONFIG_IPW2200_DEBUG is not set
+CONFIG_IPW2200_MONITOR=y
+# CONFIG_IPW2200_PROMISCUOUS is not set
+# CONFIG_IPW2200_QOS is not set
+# CONFIG_IPW2200_RADIOTAP is not set
+# CONFIG_IPWIRELESS is not set
+# CONFIG_IPX is not set
+CONFIG_IP_ADVANCED_ROUTER=y
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_FIB_TRIE_STATS is not set
+# CONFIG_IP_MROUTE is not set
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_MULTIPLE_TABLES=y
+# CONFIG_IP_NF_ARPFILTER is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_NF_ARP_MANGLE is not set
+# CONFIG_IP_NF_FILTER is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_RPFILTER is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_SECURITY is not set
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_MASQUERADE is not set
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_REDIRECT is not set
+# CONFIG_IP_NF_TARGET_REJECT is not set
+# CONFIG_IP_NF_TARGET_SYNPROXY is not set
+# CONFIG_IP_NF_TARGET_TTL is not set
+# CONFIG_IP_PIMSM_V1 is not set
+# CONFIG_IP_PIMSM_V2 is not set
+# CONFIG_IP_PNP is not set
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_SCTP is not set
+# CONFIG_IP_SET is not set
+# CONFIG_IP_SET_HASH_IPMAC is not set
+# CONFIG_IP_VS is not set
+# CONFIG_IP_VS_MH is not set
+CONFIG_IP_VS_MH_TAB_INDEX=10
+# CONFIG_IRDA is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_IRQ_ALL_CPUS is not set
+# CONFIG_IRQ_DOMAIN_DEBUG is not set
+# CONFIG_IRQ_POLL is not set
+# CONFIG_IRQ_TIME_ACCOUNTING is not set
+# CONFIG_IR_GPIO_CIR is not set
+# CONFIG_IR_HIX5HD2 is not set
+# CONFIG_IR_IGORPLUGUSB is not set
+# CONFIG_IR_IGUANA is not set
+# CONFIG_IR_IMG is not set
+# CONFIG_IR_IMON is not set
+# CONFIG_IR_JVC_DECODER is not set
+# CONFIG_IR_LIRC_CODEC is not set
+# CONFIG_IR_MCEUSB is not set
+# CONFIG_IR_NEC_DECODER is not set
+# CONFIG_IR_RC5_DECODER is not set
+# CONFIG_IR_RC6_DECODER is not set
+# CONFIG_IR_REDRAT3 is not set
+# CONFIG_IR_SONY_DECODER is not set
+# CONFIG_IR_STREAMZAP is not set
+# CONFIG_IR_TTUSBIR is not set
+# CONFIG_ISA_BUS is not set
+# CONFIG_ISA_BUS_API is not set
+# CONFIG_ISCSI_BOOT_SYSFS is not set
+# CONFIG_ISCSI_TCP is not set
+CONFIG_ISDN=y
+# CONFIG_ISDN_AUDIO is not set
+# CONFIG_ISDN_CAPI is not set
+# CONFIG_ISDN_CAPI_CAPIDRV is not set
+# CONFIG_ISDN_DIVERSION is not set
+# CONFIG_ISDN_DRV_ACT2000 is not set
+# CONFIG_ISDN_DRV_GIGASET is not set
+# CONFIG_ISDN_DRV_HISAX is not set
+# CONFIG_ISDN_DRV_ICN is not set
+# CONFIG_ISDN_DRV_LOOP is not set
+# CONFIG_ISDN_DRV_PCBIT is not set
+# CONFIG_ISDN_DRV_SC is not set
+# CONFIG_ISDN_I4L is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_ISL29020 is not set
+# CONFIG_ISL29125 is not set
+# CONFIG_ISL29501 is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_ISS4xx is not set
+# CONFIG_ITG3200 is not set
+# CONFIG_IWL3945 is not set
+# CONFIG_IWLWIFI is not set
+# CONFIG_IXGB is not set
+# CONFIG_IXGBE is not set
+# CONFIG_IXGBEVF is not set
+# CONFIG_JAILHOUSE_GUEST is not set
+# CONFIG_JBD2_DEBUG is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_POSIX_ACL is not set
+# CONFIG_JFFS2_FS_SECURITY is not set
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_LZMA=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_ZLIB is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_JME is not set
+CONFIG_JOLIET=y
+# CONFIG_JSA1212 is not set
+# CONFIG_JUMP_LABEL is not set
+# CONFIG_KALLSYMS is not set
+# CONFIG_KALLSYMS_ABSOLUTE_PERCPU is not set
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_BASE_RELATIVE=y
+# CONFIG_KALLSYMS_UNCOMPRESSED is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_KASAN is not set
+CONFIG_KASAN_STACK=1
+# CONFIG_KCOV is not set
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_CAT is not set
+# CONFIG_KERNEL_GZIP is not set
+# CONFIG_KERNEL_LZ4 is not set
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+CONFIG_KERNEL_MODE_NEON=y
+CONFIG_KERNEL_XZ=y
+CONFIG_KERNFS=y
+# CONFIG_KEXEC is not set
+# CONFIG_KEXEC_FILE is not set
+# CONFIG_KEYBOARD_ADC is not set
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ADP5589 is not set
+# CONFIG_KEYBOARD_APPLESPI is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_BCM is not set
+# CONFIG_KEYBOARD_CAP11XX is not set
+# CONFIG_KEYBOARD_DLINK_DIR685 is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_GPIO_POLLED is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_LM8333 is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_MCS is not set
+# CONFIG_KEYBOARD_MPR121 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OMAP4 is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_PXA27x is not set
+# CONFIG_KEYBOARD_QT1050 is not set
+# CONFIG_KEYBOARD_QT1070 is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_SAMSUNG is not set
+# CONFIG_KEYBOARD_SH_KEYSC is not set
+# CONFIG_KEYBOARD_SNVS_PWRKEY is not set
+# CONFIG_KEYBOARD_STMPE is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_TCA8418 is not set
+# CONFIG_KEYBOARD_TEGRA is not set
+# CONFIG_KEYBOARD_TM2_TOUCHKEY is not set
+# CONFIG_KEYBOARD_TWL4030 is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYS is not set
+# CONFIG_KEYS_REQUEST_CACHE is not set
+# CONFIG_KEY_DH_OPERATIONS is not set
+# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_KMX61 is not set
+# CONFIG_KPROBES is not set
+# CONFIG_KPROBES_SANITY_TEST is not set
+# CONFIG_KS7010 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_KSM is not set
+# CONFIG_KSZ884X_PCI is not set
+CONFIG_KUSER_HELPERS=y
+# CONFIG_KVM_AMD is not set
+# CONFIG_KVM_GUEST is not set
+# CONFIG_KVM_INTEL is not set
+# CONFIG_KXCJK1013 is not set
+# CONFIG_KXSD9 is not set
+# CONFIG_L2TP is not set
+# CONFIG_L2TP_ETH is not set
+# CONFIG_L2TP_IP is not set
+# CONFIG_L2TP_V3 is not set
+# CONFIG_LAN743X is not set
+# CONFIG_LANMEDIA is not set
+# CONFIG_LANTIQ is not set
+# CONFIG_LAPB is not set
+# CONFIG_LASAT is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_LATTICE_ECP3_CONFIG is not set
+CONFIG_LBDAF=y
+# CONFIG_LCD_AMS369FG06 is not set
+# CONFIG_LCD_CLASS_DEVICE is not set
+# CONFIG_LCD_HX8357 is not set
+# CONFIG_LCD_ILI922X is not set
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_L4F00242T03 is not set
+# CONFIG_LCD_LD9040 is not set
+# CONFIG_LCD_LMS283GF05 is not set
+# CONFIG_LCD_LMS501KF03 is not set
+# CONFIG_LCD_LTV350QV is not set
+# CONFIG_LCD_OTM3225A is not set
+# CONFIG_LCD_S6E63M0 is not set
+# CONFIG_LCD_TDO24M is not set
+# CONFIG_LCD_VGG2432A4 is not set
+CONFIG_LDISC_AUTOLOAD=y
+# CONFIG_LDM_PARTITION is not set
+CONFIG_LD_DEAD_CODE_DATA_ELIMINATION=y
+# CONFIG_LEDS_AN30259A is not set
+# CONFIG_LEDS_APU is not set
+# CONFIG_LEDS_BCM6328 is not set
+# CONFIG_LEDS_BCM6358 is not set
+# CONFIG_LEDS_BD2802 is not set
+# CONFIG_LEDS_BLINKM is not set
+CONFIG_LEDS_BRIGHTNESS_HW_CHANGED=y
+CONFIG_LEDS_CLASS=y
+# CONFIG_LEDS_CLASS_FLASH is not set
+# CONFIG_LEDS_CR0014114 is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_GPIO is not set
+# CONFIG_LEDS_INTEL_SS4200 is not set
+# CONFIG_LEDS_IS31FL319X is not set
+# CONFIG_LEDS_IS31FL32XX is not set
+# CONFIG_LEDS_LM3530 is not set
+# CONFIG_LEDS_LM3532 is not set
+# CONFIG_LEDS_LM355x is not set
+# CONFIG_LEDS_LM3642 is not set
+# CONFIG_LEDS_LM3692X is not set
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_LP3952 is not set
+# CONFIG_LEDS_LP5521 is not set
+# CONFIG_LEDS_LP5523 is not set
+# CONFIG_LEDS_LP5562 is not set
+# CONFIG_LEDS_LP8501 is not set
+# CONFIG_LEDS_LP8860 is not set
+# CONFIG_LEDS_LT3593 is not set
+# CONFIG_LEDS_MLXCPLD is not set
+# CONFIG_LEDS_MLXREG is not set
+# CONFIG_LEDS_NIC78BX is not set
+# CONFIG_LEDS_NS2 is not set
+# CONFIG_LEDS_OT200 is not set
+# CONFIG_LEDS_PCA9532 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_PCA963X is not set
+# CONFIG_LEDS_PWM is not set
+# CONFIG_LEDS_REGULATOR is not set
+# CONFIG_LEDS_SPI_BYTE is not set
+# CONFIG_LEDS_SYSCON is not set
+# CONFIG_LEDS_TCA6507 is not set
+# CONFIG_LEDS_TI_LMU_COMMON is not set
+# CONFIG_LEDS_TLC591XX is not set
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_LEDS_TRIGGER_ACTIVITY is not set
+# CONFIG_LEDS_TRIGGER_AUDIO is not set
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_CAMERA is not set
+# CONFIG_LEDS_TRIGGER_CPU is not set
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+# CONFIG_LEDS_TRIGGER_DISK is not set
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_LEDS_TRIGGER_MTD is not set
+CONFIG_LEDS_TRIGGER_NETDEV=y
+# CONFIG_LEDS_TRIGGER_ONESHOT is not set
+# CONFIG_LEDS_TRIGGER_PANIC is not set
+# CONFIG_LEDS_TRIGGER_PATTERN is not set
+CONFIG_LEDS_TRIGGER_TIMER=y
+# CONFIG_LEDS_TRIGGER_TRANSIENT is not set
+# CONFIG_LEDS_USER is not set
+# CONFIG_LED_TRIGGER_PHY is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_LGUEST is not set
+# CONFIG_LIB80211 is not set
+# CONFIG_LIB80211_CRYPT_CCMP is not set
+# CONFIG_LIB80211_CRYPT_TKIP is not set
+# CONFIG_LIB80211_CRYPT_WEP is not set
+# CONFIG_LIB80211_DEBUG is not set
+# CONFIG_LIBCRC32C is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_LIBERTAS_USB is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_LIBIPW_DEBUG is not set
+# CONFIG_LIBNVDIMM is not set
+# CONFIG_LIDAR_LITE_V2 is not set
+# CONFIG_LIQUIDIO is not set
+# CONFIG_LIQUIDIO_VF is not set
+# CONFIG_LIS3L02DQ is not set
+# CONFIG_LKDTM is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_LMP91000 is not set
+# CONFIG_LNET is not set
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_LOCKD is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_LOCKD_V4=y
+# CONFIG_LOCKUP_DETECTOR is not set
+# CONFIG_LOCK_EVENT_COUNTS is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_LOCK_TORTURE_TEST is not set
+# CONFIG_LOGFS is not set
+# CONFIG_LOGIG940_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIWHEELS_FF is not set
+# CONFIG_LOGO is not set
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
+# CONFIG_LOONGSON_MC146818 is not set
+# CONFIG_LPC_ICH is not set
+# CONFIG_LPC_SCH is not set
+# CONFIG_LP_CONSOLE is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity"
+CONFIG_LSM_MMAP_MIN_ADDR=65536
+# CONFIG_LTC1660 is not set
+# CONFIG_LTC2471 is not set
+# CONFIG_LTC2485 is not set
+# CONFIG_LTC2497 is not set
+# CONFIG_LTC2632 is not set
+# CONFIG_LTE_GDM724X is not set
+# CONFIG_LTPC is not set
+# CONFIG_LTR501 is not set
+# CONFIG_LUSTRE_FS is not set
+# CONFIG_LV0104CS is not set
+# CONFIG_LWTUNNEL is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_LZ4HC_COMPRESS is not set
+# CONFIG_LZ4_COMPRESS is not set
+# CONFIG_LZ4_DECOMPRESS is not set
+CONFIG_LZMA_COMPRESS=y
+CONFIG_LZMA_DECOMPRESS=y
+# CONFIG_LZO_COMPRESS is not set
+# CONFIG_LZO_DECOMPRESS is not set
+# CONFIG_M62332 is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_MAC80211_MESSAGE_TRACING is not set
+CONFIG_MAC80211_STA_HASH_MAX_SIZE=0
+# CONFIG_MACB is not set
+# CONFIG_MACH_ASM9260 is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_INGENIC is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_MACH_JZ4740 is not set
+# CONFIG_MACH_LOONGSON32 is not set
+# CONFIG_MACH_LOONGSON64 is not set
+# CONFIG_MACH_PIC32 is not set
+# CONFIG_MACH_PISTACHIO is not set
+# CONFIG_MACH_TX39XX is not set
+# CONFIG_MACH_TX49XX is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_MACH_XILFPGA is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+# CONFIG_MACSEC is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_MACVTAP is not set
+# CONFIG_MAC_EMUMOUSEBTN is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MAG3110 is not set
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
+# CONFIG_MAGIC_SYSRQ_SERIAL is not set
+# CONFIG_MAILBOX is not set
+# CONFIG_MANAGER_SBS is not set
+# CONFIG_MANDATORY_FILE_LOCKING is not set
+# CONFIG_MANGLE_BOOTARGS is not set
+# CONFIG_MARVELL_10G_PHY is not set
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_MAX1027 is not set
+# CONFIG_MAX11100 is not set
+# CONFIG_MAX1118 is not set
+# CONFIG_MAX1363 is not set
+# CONFIG_MAX30100 is not set
+# CONFIG_MAX30102 is not set
+# CONFIG_MAX31856 is not set
+# CONFIG_MAX44000 is not set
+# CONFIG_MAX44009 is not set
+# CONFIG_MAX517 is not set
+# CONFIG_MAX5432 is not set
+# CONFIG_MAX5481 is not set
+# CONFIG_MAX5487 is not set
+# CONFIG_MAX5821 is not set
+# CONFIG_MAX63XX_WATCHDOG is not set
+# CONFIG_MAX9611 is not set
+# CONFIG_MAXIM_THERMOCOUPLE is not set
+CONFIG_MAY_USE_DEVLINK=y
+# CONFIG_MB1232 is not set
+# CONFIG_MC3230 is not set
+# CONFIG_MCB is not set
+# CONFIG_MCP320X is not set
+# CONFIG_MCP3422 is not set
+# CONFIG_MCP3911 is not set
+# CONFIG_MCP4018 is not set
+# CONFIG_MCP41010 is not set
+# CONFIG_MCP4131 is not set
+# CONFIG_MCP4531 is not set
+# CONFIG_MCP4725 is not set
+# CONFIG_MCP4922 is not set
+# CONFIG_MCPM is not set
+# CONFIG_MD is not set
+# CONFIG_MDIO_BCM_UNIMAC is not set
+# CONFIG_MDIO_BITBANG is not set
+# CONFIG_MDIO_BUS_MUX_GPIO is not set
+# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
+# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set
+# CONFIG_MDIO_DEVICE is not set
+# CONFIG_MDIO_HISI_FEMAC is not set
+# CONFIG_MDIO_MSCC_MIIM is not set
+# CONFIG_MDIO_OCTEON is not set
+# CONFIG_MDIO_THUNDER is not set
+# CONFIG_MD_FAULTY is not set
+# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
+# CONFIG_MEDIA_ATTACH is not set
+# CONFIG_MEDIA_CAMERA_SUPPORT is not set
+# CONFIG_MEDIA_CEC_SUPPORT is not set
+# CONFIG_MEDIA_CONTROLLER is not set
+# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
+# CONFIG_MEDIA_PCI_SUPPORT is not set
+# CONFIG_MEDIA_RADIO_SUPPORT is not set
+# CONFIG_MEDIA_RC_SUPPORT is not set
+# CONFIG_MEDIA_SDR_SUPPORT is not set
+# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
+# CONFIG_MEDIA_SUPPORT is not set
+# CONFIG_MEDIA_USB_SUPPORT is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_MELLANOX_PLATFORM is not set
+CONFIG_MEMBARRIER=y
+# CONFIG_MEMORY is not set
+# CONFIG_MEMORY_FAILURE is not set
+# CONFIG_MEMORY_HOTPLUG is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_MEMTEST is not set
+# CONFIG_MEN_A21_WDT is not set
+# CONFIG_MESON_SM is not set
+CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
+# CONFIG_MFD_88PM800 is not set
+# CONFIG_MFD_88PM805 is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_AAT2870_CORE is not set
+# CONFIG_MFD_AC100 is not set
+# CONFIG_MFD_ACT8945A is not set
+# CONFIG_MFD_ARIZONA_I2C is not set
+# CONFIG_MFD_ARIZONA_SPI is not set
+# CONFIG_MFD_AS3711 is not set
+# CONFIG_MFD_AS3722 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_MFD_ATMEL_FLEXCOM is not set
+# CONFIG_MFD_ATMEL_HLCDC is not set
+# CONFIG_MFD_AXP20X is not set
+# CONFIG_MFD_AXP20X_I2C is not set
+# CONFIG_MFD_BCM590XX is not set
+# CONFIG_MFD_BD9571MWV is not set
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_CPCAP is not set
+# CONFIG_MFD_CROS_EC is not set
+# CONFIG_MFD_CS5535 is not set
+# CONFIG_MFD_DA9052_I2C is not set
+# CONFIG_MFD_DA9052_SPI is not set
+# CONFIG_MFD_DA9055 is not set
+# CONFIG_MFD_DA9062 is not set
+# CONFIG_MFD_DA9063 is not set
+# CONFIG_MFD_DA9150 is not set
+# CONFIG_MFD_DLN2 is not set
+# CONFIG_MFD_EXYNOS_LPASS is not set
+# CONFIG_MFD_HI6421_PMIC is not set
+# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+# CONFIG_MFD_KEMPLD is not set
+# CONFIG_MFD_LM3533 is not set
+# CONFIG_MFD_LOCHNAGAR is not set
+# CONFIG_MFD_LP3943 is not set
+# CONFIG_MFD_LP8788 is not set
+# CONFIG_MFD_MADERA is not set
+# CONFIG_MFD_MAX14577 is not set
+# CONFIG_MFD_MAX77620 is not set
+# CONFIG_MFD_MAX77650 is not set
+# CONFIG_MFD_MAX77686 is not set
+# CONFIG_MFD_MAX77693 is not set
+# CONFIG_MFD_MAX77843 is not set
+# CONFIG_MFD_MAX8907 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8997 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_MC13XXX is not set
+# CONFIG_MFD_MC13XXX_I2C is not set
+# CONFIG_MFD_MC13XXX_SPI is not set
+# CONFIG_MFD_MENF21BMC is not set
+# CONFIG_MFD_MT6397 is not set
+# CONFIG_MFD_OMAP_USB_HOST is not set
+# CONFIG_MFD_PALMAS is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_PM8921_CORE is not set
+# CONFIG_MFD_PM8XXX is not set
+# CONFIG_MFD_RC5T583 is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_RETU is not set
+# CONFIG_MFD_RK808 is not set
+# CONFIG_MFD_RN5T618 is not set
+# CONFIG_MFD_ROHM_BD70528 is not set
+# CONFIG_MFD_ROHM_BD718XX is not set
+# CONFIG_MFD_RT5033 is not set
+# CONFIG_MFD_RTSX_PCI is not set
+# CONFIG_MFD_RTSX_USB is not set
+# CONFIG_MFD_SEC_CORE is not set
+# CONFIG_MFD_SI476X_CORE is not set
+# CONFIG_MFD_SKY81452 is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_SMSC is not set
+# CONFIG_MFD_STMFX is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_STPMIC1 is not set
+# CONFIG_MFD_SYSCON is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC3589X is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_MFD_TIMBERDALE is not set
+# CONFIG_MFD_TI_AM335X_TSCADC is not set
+# CONFIG_MFD_TI_LMU is not set
+# CONFIG_MFD_TI_LP873X is not set
+# CONFIG_MFD_TI_LP87565 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_TPS65086 is not set
+# CONFIG_MFD_TPS65090 is not set
+# CONFIG_MFD_TPS65217 is not set
+# CONFIG_MFD_TPS65218 is not set
+# CONFIG_MFD_TPS6586X is not set
+# CONFIG_MFD_TPS65910 is not set
+# CONFIG_MFD_TPS65912 is not set
+# CONFIG_MFD_TPS65912_I2C is not set
+# CONFIG_MFD_TPS65912_SPI is not set
+# CONFIG_MFD_TPS68470 is not set
+# CONFIG_MFD_TPS80031 is not set
+# CONFIG_MFD_TQMX86 is not set
+# CONFIG_MFD_VIPERBOARD is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM831X_SPI is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MG_DISK is not set
+# CONFIG_MICREL_KS8995MA is not set
+# CONFIG_MICREL_PHY is not set
+# CONFIG_MICROCHIP_KSZ is not set
+# CONFIG_MICROCHIP_PHY is not set
+# CONFIG_MICROCHIP_T1_PHY is not set
+# CONFIG_MICROSEMI_PHY is not set
+# CONFIG_MIGRATION is not set
+CONFIG_MII=y
+# CONFIG_MIKROTIK is not set
+# CONFIG_MIKROTIK_RB532 is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_MIPS_ALCHEMY is not set
+# CONFIG_MIPS_CDMM is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MIPS_FPU_EMULATOR is not set
+# CONFIG_MIPS_FP_SUPPORT is not set
+# CONFIG_MIPS_GENERIC is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_O32_FP64_SUPPORT is not set
+# CONFIG_MIPS_PARAVIRT is not set
+# CONFIG_MIPS_PLATFORM_DEVICES is not set
+# CONFIG_MIPS_SEAD3 is not set
+# CONFIG_MISC_ALCOR_PCI is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_MISC_RTSX_PCI is not set
+# CONFIG_MISC_RTSX_USB is not set
+# CONFIG_MISDN is not set
+# CONFIG_MISDN_AVMFRITZ is not set
+# CONFIG_MISDN_HFCPCI is not set
+# CONFIG_MISDN_HFCUSB is not set
+# CONFIG_MISDN_INFINEON is not set
+# CONFIG_MISDN_NETJET is not set
+# CONFIG_MISDN_SPEEDFAX is not set
+# CONFIG_MISDN_W6692 is not set
+# CONFIG_MKISS is not set
+# CONFIG_MLX4_CORE is not set
+# CONFIG_MLX4_EN is not set
+# CONFIG_MLX5_CORE is not set
+# CONFIG_MLX90614 is not set
+# CONFIG_MLX90632 is not set
+# CONFIG_MLXFW is not set
+# CONFIG_MLXSW_CORE is not set
+# CONFIG_MLX_CPLD_PLATFORM is not set
+# CONFIG_MLX_PLATFORM is not set
+# CONFIG_MMA7455_I2C is not set
+# CONFIG_MMA7455_SPI is not set
+# CONFIG_MMA7660 is not set
+# CONFIG_MMA8452 is not set
+# CONFIG_MMA9551 is not set
+# CONFIG_MMA9553 is not set
+# CONFIG_MMC is not set
+# CONFIG_MMC35240 is not set
+# CONFIG_MMC_ARMMMCI is not set
+# CONFIG_MMC_AU1X is not set
+# CONFIG_MMC_BLOCK is not set
+CONFIG_MMC_BLOCK_BOUNCE=y
+CONFIG_MMC_BLOCK_MINORS=8
+# CONFIG_MMC_CAVIUM_THUNDERX is not set
+# CONFIG_MMC_CB710 is not set
+# CONFIG_MMC_CQHCI is not set
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_DW is not set
+# CONFIG_MMC_JZ4740 is not set
+# CONFIG_MMC_MTK is not set
+# CONFIG_MMC_MVSDIO is not set
+# CONFIG_MMC_S3C is not set
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_SDHCI_ACPI is not set
+# CONFIG_MMC_SDHCI_AM654 is not set
+# CONFIG_MMC_SDHCI_BCM_KONA is not set
+# CONFIG_MMC_SDHCI_CADENCE is not set
+# CONFIG_MMC_SDHCI_F_SDH30 is not set
+# CONFIG_MMC_SDHCI_IPROC is not set
+# CONFIG_MMC_SDHCI_MSM is not set
+# CONFIG_MMC_SDHCI_OF_ARASAN is not set
+# CONFIG_MMC_SDHCI_OF_ASPEED is not set
+# CONFIG_MMC_SDHCI_OF_AT91 is not set
+# CONFIG_MMC_SDHCI_OF_DWCMSHC is not set
+# CONFIG_MMC_SDHCI_OF_ESDHC is not set
+# CONFIG_MMC_SDHCI_OF_HLWD is not set
+# CONFIG_MMC_SDHCI_OMAP is not set
+# CONFIG_MMC_SDHCI_PXAV2 is not set
+# CONFIG_MMC_SDHCI_PXAV3 is not set
+# CONFIG_MMC_SDHCI_S3C is not set
+# CONFIG_MMC_SDHCI_XENON is not set
+# CONFIG_MMC_SDRICOH_CS is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_MMC_STM32_SDMMC is not set
+# CONFIG_MMC_TEST is not set
+# CONFIG_MMC_TIFM_SD is not set
+# CONFIG_MMC_TOSHIBA_PCI is not set
+# CONFIG_MMC_USDHI6ROL0 is not set
+# CONFIG_MMC_USHC is not set
+# CONFIG_MMC_VIA_SDMMC is not set
+# CONFIG_MMC_VUB300 is not set
+# CONFIG_MMIOTRACE is not set
+CONFIG_MMU=y
+CONFIG_MODULES=y
+# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set
+# CONFIG_MODULE_COMPRESS is not set
+# CONFIG_MODULE_FORCE_LOAD is not set
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODULE_SIG is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_MODULE_STRIPPED=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MOST is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_ELAN_I2C is not set
+# CONFIG_MOUSE_GPIO is not set
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_MOUSE_PS2_FOCALTECH is not set
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
+# CONFIG_MOUSE_SYNAPTICS_USB is not set
+# CONFIG_MOXTET is not set
+# CONFIG_MPL115 is not set
+# CONFIG_MPL115_I2C is not set
+# CONFIG_MPL115_SPI is not set
+# CONFIG_MPL3115 is not set
+# CONFIG_MPLS is not set
+# CONFIG_MPU3050_I2C is not set
+# CONFIG_MQ_IOSCHED_DEADLINE is not set
+# CONFIG_MQ_IOSCHED_KYBER is not set
+# CONFIG_MS5611 is not set
+# CONFIG_MS5637 is not set
+# CONFIG_MSCC_OCELOT_SWITCH is not set
+# CONFIG_MSDOS_FS is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_MSI_BITMAP_SELFTEST is not set
+# CONFIG_MSI_LAPTOP is not set
+CONFIG_MTD=y
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_MTD_BLOCK2MTD is not set
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_DOCG3 is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_GPIO_ADDR is not set
+# CONFIG_MTD_HYPERBUS is not set
+# CONFIG_MTD_IMPA7 is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_JEDECPROBE is not set
+# CONFIG_MTD_LATCH_ADDR is not set
+# CONFIG_MTD_LPDDR is not set
+# CONFIG_MTD_LPDDR2_NVM is not set
+# CONFIG_MTD_M25P80 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MCHP23K256 is not set
+# CONFIG_MTD_MT81xx_NOR is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_MYLOADER_PARTS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_NAND_AMS_DELTA is not set
+# CONFIG_MTD_NAND_AR934X is not set
+# CONFIG_MTD_NAND_AR934X_HW_ECC is not set
+# CONFIG_MTD_NAND_ATMEL is not set
+# CONFIG_MTD_NAND_AU1550 is not set
+# CONFIG_MTD_NAND_BCH is not set
+# CONFIG_MTD_NAND_BF5XX is not set
+# CONFIG_MTD_NAND_BRCMNAND is not set
+# CONFIG_MTD_NAND_CAFE is not set
+# CONFIG_MTD_NAND_CM_X270 is not set
+# CONFIG_MTD_NAND_CS553X is not set
+# CONFIG_MTD_NAND_DAVINCI is not set
+# CONFIG_MTD_NAND_DENALI is not set
+# CONFIG_MTD_NAND_DENALI_DT is not set
+# CONFIG_MTD_NAND_DENALI_PCI is not set
+CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xff108018
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_DOCG4 is not set
+# CONFIG_MTD_NAND_ECC is not set
+# CONFIG_MTD_NAND_ECC_BCH is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_ECC_SW_BCH is not set
+# CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC is not set
+# CONFIG_MTD_NAND_FSL_ELBC is not set
+# CONFIG_MTD_NAND_FSL_IFC is not set
+# CONFIG_MTD_NAND_FSL_UPM is not set
+# CONFIG_MTD_NAND_FSMC is not set
+# CONFIG_MTD_NAND_GPIO is not set
+# CONFIG_MTD_NAND_GPMI_NAND is not set
+# CONFIG_MTD_NAND_HISI504 is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_JZ4740 is not set
+# CONFIG_MTD_NAND_MPC5121_NFC is not set
+# CONFIG_MTD_NAND_MTK is not set
+# CONFIG_MTD_NAND_MXC is not set
+# CONFIG_MTD_NAND_MXIC is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_NDFC is not set
+# CONFIG_MTD_NAND_NUC900 is not set
+# CONFIG_MTD_NAND_OMAP2 is not set
+# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set
+# CONFIG_MTD_NAND_ORION is not set
+# CONFIG_MTD_NAND_PASEMI is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_NAND_PXA3xx is not set
+# CONFIG_MTD_NAND_RB4XX is not set
+# CONFIG_MTD_NAND_RB750 is not set
+# CONFIG_MTD_NAND_RICOH is not set
+# CONFIG_MTD_NAND_S3C2410 is not set
+# CONFIG_MTD_NAND_SHARPSL is not set
+# CONFIG_MTD_NAND_SH_FLCTL is not set
+# CONFIG_MTD_NAND_SOCRATES is not set
+# CONFIG_MTD_NAND_TMIO is not set
+# CONFIG_MTD_NAND_TXX9NDFMC is not set
+CONFIG_MTD_OF_PARTS=y
+# CONFIG_MTD_ONENAND is not set
+# CONFIG_MTD_OOPS is not set
+# CONFIG_MTD_OTP is not set
+# CONFIG_MTD_PARTITIONED_MASTER is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PCMCIA is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_PHYSMAP_GEMINI is not set
+# CONFIG_MTD_PHYSMAP_GPIO_ADDR is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_PHYSMAP_OF_GEMINI is not set
+# CONFIG_MTD_PHYSMAP_OF_VERSATILE is not set
+# CONFIG_MTD_PHYSMAP_VERSATILE is not set
+# CONFIG_MTD_PLATRAM is not set
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_RAW_NAND is not set
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_ROM is not set
+CONFIG_MTD_ROOTFS_ROOT_DEV=y
+# CONFIG_MTD_ROUTERBOOT_PARTS is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_SM_COMMON is not set
+# CONFIG_MTD_SPINAND_MT29F is not set
+# CONFIG_MTD_SPI_NAND is not set
+# CONFIG_MTD_SPI_NOR is not set
+# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
+CONFIG_MTD_SPI_NOR_USE_4K_SECTORS_LIMIT=4096
+CONFIG_MTD_SPLIT=y
+# CONFIG_MTD_SPLIT_BCM_WFI_FW is not set
+# CONFIG_MTD_SPLIT_BRNIMAGE_FW is not set
+# CONFIG_MTD_SPLIT_ELF_FW is not set
+# CONFIG_MTD_SPLIT_EVA_FW is not set
+# CONFIG_MTD_SPLIT_FIRMWARE is not set
+CONFIG_MTD_SPLIT_FIRMWARE_NAME="firmware"
+# CONFIG_MTD_SPLIT_FIT_FW is not set
+# CONFIG_MTD_SPLIT_JIMAGE_FW is not set
+# CONFIG_MTD_SPLIT_LZMA_FW is not set
+# CONFIG_MTD_SPLIT_MINOR_FW is not set
+# CONFIG_MTD_SPLIT_SEAMA_FW is not set
+CONFIG_MTD_SPLIT_SQUASHFS_ROOT=y
+CONFIG_MTD_SPLIT_SUPPORT=y
+# CONFIG_MTD_SPLIT_TPLINK_FW is not set
+# CONFIG_MTD_SPLIT_TRX_FW is not set
+# CONFIG_MTD_SPLIT_UIMAGE_FW is not set
+# CONFIG_MTD_SPLIT_WRGG_FW is not set
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SWAP is not set
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_UBI is not set
+# CONFIG_MTD_UBI_FASTMAP is not set
+# CONFIG_MTD_UBI_GLUEBI is not set
+# CONFIG_MTD_UIMAGE_SPLIT is not set
+# CONFIG_MTD_VIRT_CONCAT is not set
+# CONFIG_MTK_MMC is not set
+# CONFIG_MTK_SPI_NAND is not set
+CONFIG_MULTIUSER=y
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+# CONFIG_MV643XX_ETH is not set
+# CONFIG_MVMDIO is not set
+# CONFIG_MVNETA_BM is not set
+# CONFIG_MVSWITCH_PHY is not set
+# CONFIG_MV_XOR_V2 is not set
+# CONFIG_MWAVE is not set
+# CONFIG_MWL8K is not set
+# CONFIG_MXC4005 is not set
+# CONFIG_MXC6255 is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NAU7802 is not set
+# CONFIG_NBPFAXI_DMA is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NE2000 is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NEC_MARKEINS is not set
+CONFIG_NET=y
+# CONFIG_NETCONSOLE is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVSIM is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_NETFILTER_ADVANCED is not set
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_NETFILTER_INGRESS is not set
+# CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NETFILTER_NETLINK_ACCT is not set
+# CONFIG_NETFILTER_NETLINK_GLUE_CT is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NETFILTER_NETLINK_OSF is not set
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_XTABLES is not set
+# CONFIG_NETFILTER_XT_CONNMARK is not set
+# CONFIG_NETFILTER_XT_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_BPF is not set
+# CONFIG_NETFILTER_XT_MATCH_CGROUP is not set
+# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_CPU is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ECN is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
+# CONFIG_NETFILTER_XT_MATCH_HL is not set
+# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+# CONFIG_NETFILTER_XT_MATCH_L2TP is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
+# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set
+# CONFIG_NETFILTER_XT_MATCH_OSF is not set
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set
+# CONFIG_NETFILTER_XT_MATCH_STATE is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set
+# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_CT is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+# CONFIG_NETFILTER_XT_TARGET_HL is not set
+# CONFIG_NETFILTER_XT_TARGET_HMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set
+# CONFIG_NETFILTER_XT_TARGET_LED is not set
+# CONFIG_NETFILTER_XT_TARGET_LOG is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+# CONFIG_NETFILTER_XT_TARGET_REDIRECT is not set
+# CONFIG_NETFILTER_XT_TARGET_SECMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
+# CONFIG_NETFILTER_XT_TARGET_TEE is not set
+# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETLINK_DIAG is not set
+# CONFIG_NETLINK_MMAP is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NETROM is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETXEN_NIC is not set
+# CONFIG_NET_9P is not set
+# CONFIG_NET_ACT_BPF is not set
+# CONFIG_NET_ACT_CSUM is not set
+# CONFIG_NET_ACT_CT is not set
+# CONFIG_NET_ACT_GACT is not set
+# CONFIG_NET_ACT_IFE is not set
+# CONFIG_NET_ACT_IPT is not set
+# CONFIG_NET_ACT_MIRRED is not set
+# CONFIG_NET_ACT_MPLS is not set
+# CONFIG_NET_ACT_NAT is not set
+# CONFIG_NET_ACT_PEDIT is not set
+# CONFIG_NET_ACT_POLICE is not set
+# CONFIG_NET_ACT_SAMPLE is not set
+# CONFIG_NET_ACT_SIMP is not set
+# CONFIG_NET_ACT_SKBEDIT is not set
+# CONFIG_NET_ACT_SKBMOD is not set
+# CONFIG_NET_ACT_TUNNEL_KEY is not set
+# CONFIG_NET_ACT_VLAN is not set
+CONFIG_NET_CADENCE=y
+# CONFIG_NET_CALXEDA_XGMAC is not set
+CONFIG_NET_CLS=y
+# CONFIG_NET_CLS_ACT is not set
+# CONFIG_NET_CLS_BASIC is not set
+# CONFIG_NET_CLS_BPF is not set
+# CONFIG_NET_CLS_FLOW is not set
+# CONFIG_NET_CLS_FLOWER is not set
+# CONFIG_NET_CLS_FW is not set
+CONFIG_NET_CLS_IND=y
+# CONFIG_NET_CLS_MATCHALL is not set
+# CONFIG_NET_CLS_ROUTE4 is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_CLS_TCINDEX is not set
+# CONFIG_NET_CLS_U32 is not set
+CONFIG_NET_CORE=y
+# CONFIG_NET_DEVLINK is not set
+# CONFIG_NET_DROP_MONITOR is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_NET_DSA_BCM_SF2 is not set
+# CONFIG_NET_DSA_LANTIQ_GSWIP is not set
+# CONFIG_NET_DSA_LEGACY is not set
+# CONFIG_NET_DSA_LOOP is not set
+# CONFIG_NET_DSA_MICROCHIP_KSZ8795 is not set
+# CONFIG_NET_DSA_MICROCHIP_KSZ9477 is not set
+# CONFIG_NET_DSA_MT7530 is not set
+# CONFIG_NET_DSA_MV88E6060 is not set
+# CONFIG_NET_DSA_MV88E6123_61_65 is not set
+# CONFIG_NET_DSA_MV88E6131 is not set
+# CONFIG_NET_DSA_MV88E6171 is not set
+# CONFIG_NET_DSA_MV88E6352 is not set
+# CONFIG_NET_DSA_MV88E6XXX is not set
+# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set
+# CONFIG_NET_DSA_QCA8K is not set
+# CONFIG_NET_DSA_REALTEK_SMI is not set
+# CONFIG_NET_DSA_SJA1105 is not set
+# CONFIG_NET_DSA_SMSC_LAN9303_I2C is not set
+# CONFIG_NET_DSA_SMSC_LAN9303_MDIO is not set
+# CONFIG_NET_DSA_TAG_8021Q is not set
+# CONFIG_NET_DSA_TAG_BRCM is not set
+# CONFIG_NET_DSA_TAG_BRCM_PREPEND is not set
+# CONFIG_NET_DSA_TAG_DSA is not set
+# CONFIG_NET_DSA_TAG_EDSA is not set
+# CONFIG_NET_DSA_TAG_GSWIP is not set
+# CONFIG_NET_DSA_TAG_KSZ is not set
+# CONFIG_NET_DSA_TAG_LAN9303 is not set
+# CONFIG_NET_DSA_TAG_MTK is not set
+# CONFIG_NET_DSA_TAG_QCA is not set
+# CONFIG_NET_DSA_TAG_RTL4_A is not set
+# CONFIG_NET_DSA_TAG_SJA1105 is not set
+# CONFIG_NET_DSA_TAG_TRAILER is not set
+# CONFIG_NET_DSA_VITESSE_VSC73XX is not set
+# CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM is not set
+# CONFIG_NET_DSA_VITESSE_VSC73XX_SPI is not set
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_EMATCH_CANID is not set
+# CONFIG_NET_EMATCH_CMP is not set
+# CONFIG_NET_EMATCH_IPT is not set
+# CONFIG_NET_EMATCH_META is not set
+# CONFIG_NET_EMATCH_NBYTE is not set
+CONFIG_NET_EMATCH_STACK=32
+# CONFIG_NET_EMATCH_TEXT is not set
+# CONFIG_NET_EMATCH_U32 is not set
+# CONFIG_NET_FAILOVER is not set
+# CONFIG_NET_FC is not set
+# CONFIG_NET_FOU is not set
+# CONFIG_NET_FOU_IP_TUNNELS is not set
+# CONFIG_NET_IFE is not set
+# CONFIG_NET_IPGRE is not set
+CONFIG_NET_IPGRE_BROADCAST=y
+# CONFIG_NET_IPGRE_DEMUX is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPVTI is not set
+# CONFIG_NET_IP_TUNNEL is not set
+# CONFIG_NET_KEY is not set
+# CONFIG_NET_KEY_MIGRATE is not set
+# CONFIG_NET_L3_MASTER_DEV is not set
+# CONFIG_NET_MPLS_GSO is not set
+# CONFIG_NET_NCSI is not set
+# CONFIG_NET_NSH is not set
+# CONFIG_NET_PACKET_ENGINE is not set
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_NET_PTP_CLASSIFY is not set
+CONFIG_NET_RX_BUSY_POLL=y
+# CONFIG_NET_SB1000 is not set
+CONFIG_NET_SCHED=y
+# CONFIG_NET_SCH_ATM is not set
+# CONFIG_NET_SCH_CAKE is not set
+# CONFIG_NET_SCH_CBQ is not set
+# CONFIG_NET_SCH_CBS is not set
+# CONFIG_NET_SCH_CHOKE is not set
+# CONFIG_NET_SCH_CODEL is not set
+# CONFIG_NET_SCH_DEFAULT is not set
+# CONFIG_NET_SCH_DRR is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_ETF is not set
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_NET_SCH_FQ is not set
+CONFIG_NET_SCH_FQ_CODEL=y
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_HHF is not set
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_INGRESS is not set
+# CONFIG_NET_SCH_MQPRIO is not set
+# CONFIG_NET_SCH_MULTIQ is not set
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_SCH_PIE is not set
+# CONFIG_NET_SCH_PLUG is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_QFQ is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFB is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_SKBPRIO is not set
+# CONFIG_NET_SCH_TAPRIO is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_SCTPPROBE is not set
+# CONFIG_NET_SWITCHDEV is not set
+# CONFIG_NET_TCPPROBE is not set
+# CONFIG_NET_TC_SKB_EXT is not set
+# CONFIG_NET_TEAM is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_NET_UDP_TUNNEL is not set
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_NET_VENDOR_8390=y
+CONFIG_NET_VENDOR_ADAPTEC=y
+CONFIG_NET_VENDOR_AGERE=y
+CONFIG_NET_VENDOR_ALACRITECH=y
+CONFIG_NET_VENDOR_ALTEON=y
+CONFIG_NET_VENDOR_AMAZON=y
+CONFIG_NET_VENDOR_AMD=y
+CONFIG_NET_VENDOR_AQUANTIA=y
+CONFIG_NET_VENDOR_ARC=y
+CONFIG_NET_VENDOR_ATHEROS=y
+CONFIG_NET_VENDOR_AURORA=y
+CONFIG_NET_VENDOR_BROADCOM=y
+CONFIG_NET_VENDOR_BROCADE=y
+CONFIG_NET_VENDOR_CADENCE=y
+CONFIG_NET_VENDOR_CAVIUM=y
+CONFIG_NET_VENDOR_CHELSIO=y
+CONFIG_NET_VENDOR_CIRRUS=y
+CONFIG_NET_VENDOR_CISCO=y
+CONFIG_NET_VENDOR_CORTINA=y
+CONFIG_NET_VENDOR_DEC=y
+CONFIG_NET_VENDOR_DLINK=y
+CONFIG_NET_VENDOR_EMULEX=y
+CONFIG_NET_VENDOR_EXAR=y
+CONFIG_NET_VENDOR_EZCHIP=y
+CONFIG_NET_VENDOR_FARADAY=y
+CONFIG_NET_VENDOR_FREESCALE=y
+CONFIG_NET_VENDOR_FUJITSU=y
+CONFIG_NET_VENDOR_GOOGLE=y
+CONFIG_NET_VENDOR_HISILICON=y
+CONFIG_NET_VENDOR_HP=y
+CONFIG_NET_VENDOR_HUAWEI=y
+CONFIG_NET_VENDOR_I825XX=y
+CONFIG_NET_VENDOR_IBM=y
+CONFIG_NET_VENDOR_INTEL=y
+CONFIG_NET_VENDOR_MARVELL=y
+CONFIG_NET_VENDOR_MELLANOX=y
+CONFIG_NET_VENDOR_MICREL=y
+CONFIG_NET_VENDOR_MICROCHIP=y
+CONFIG_NET_VENDOR_MICROSEMI=y
+CONFIG_NET_VENDOR_MYRI=y
+CONFIG_NET_VENDOR_NATSEMI=y
+CONFIG_NET_VENDOR_NETERION=y
+CONFIG_NET_VENDOR_NETRONOME=y
+CONFIG_NET_VENDOR_NI=y
+CONFIG_NET_VENDOR_NVIDIA=y
+CONFIG_NET_VENDOR_OKI=y
+CONFIG_NET_VENDOR_PACKET_ENGINES=y
+CONFIG_NET_VENDOR_PENSANDO=y
+CONFIG_NET_VENDOR_QLOGIC=y
+CONFIG_NET_VENDOR_QUALCOMM=y
+CONFIG_NET_VENDOR_RDC=y
+CONFIG_NET_VENDOR_REALTEK=y
+CONFIG_NET_VENDOR_RENESAS=y
+CONFIG_NET_VENDOR_ROCKER=y
+CONFIG_NET_VENDOR_SAMSUNG=y
+CONFIG_NET_VENDOR_SEEQ=y
+CONFIG_NET_VENDOR_SILAN=y
+CONFIG_NET_VENDOR_SIS=y
+CONFIG_NET_VENDOR_SMSC=y
+CONFIG_NET_VENDOR_SOCIONEXT=y
+CONFIG_NET_VENDOR_SOLARFLARE=y
+CONFIG_NET_VENDOR_STMICRO=y
+CONFIG_NET_VENDOR_SUN=y
+CONFIG_NET_VENDOR_SYNOPSYS=y
+CONFIG_NET_VENDOR_TEHUTI=y
+CONFIG_NET_VENDOR_TI=y
+CONFIG_NET_VENDOR_TOSHIBA=y
+CONFIG_NET_VENDOR_VIA=y
+CONFIG_NET_VENDOR_WIZNET=y
+CONFIG_NET_VENDOR_XILINX=y
+CONFIG_NET_VENDOR_XIRCOM=y
+# CONFIG_NET_VRF is not set
+# CONFIG_NET_XGENE is not set
+CONFIG_NEW_LEDS=y
+# CONFIG_NFC is not set
+# CONFIG_NFP is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V2_ACL is not set
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+# CONFIG_NFS_ACL_SUPPORT is not set
+CONFIG_NFS_COMMON=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFS_FSCACHE is not set
+# CONFIG_NFS_SWAP is not set
+# CONFIG_NFS_V2 is not set
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_V4_1 is not set
+# CONFIG_NFTL is not set
+# CONFIG_NFT_BRIDGE_META is not set
+# CONFIG_NFT_BRIDGE_REJECT is not set
+# CONFIG_NFT_CONNLIMIT is not set
+# CONFIG_NFT_DUP_IPV4 is not set
+# CONFIG_NFT_DUP_IPV6 is not set
+# CONFIG_NFT_FIB_IPV4 is not set
+# CONFIG_NFT_FIB_IPV6 is not set
+# CONFIG_NFT_FIB_NETDEV is not set
+# CONFIG_NFT_FLOW_OFFLOAD is not set
+# CONFIG_NFT_OBJREF is not set
+# CONFIG_NFT_OSF is not set
+# CONFIG_NFT_RT is not set
+# CONFIG_NFT_SET_BITMAP is not set
+# CONFIG_NFT_SOCKET is not set
+# CONFIG_NFT_SYNPROXY is not set
+# CONFIG_NFT_TPROXY is not set
+# CONFIG_NFT_TUNNEL is not set
+# CONFIG_NFT_XFRM is not set
+# CONFIG_NF_CONNTRACK is not set
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+# CONFIG_NF_CONNTRACK_BRIDGE is not set
+# CONFIG_NF_CONNTRACK_EVENTS is not set
+# CONFIG_NF_CONNTRACK_FTP is not set
+# CONFIG_NF_CONNTRACK_H323 is not set
+# CONFIG_NF_CONNTRACK_IPV4 is not set
+# CONFIG_NF_CONNTRACK_IPV6 is not set
+# CONFIG_NF_CONNTRACK_IRC is not set
+# CONFIG_NF_CONNTRACK_LABELS is not set
+# CONFIG_NF_CONNTRACK_MARK is not set
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+CONFIG_NF_CONNTRACK_PROCFS=y
+# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
+# CONFIG_NF_CONNTRACK_SANE is not set
+# CONFIG_NF_CONNTRACK_SECMARK is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+# CONFIG_NF_CONNTRACK_SNMP is not set
+# CONFIG_NF_CONNTRACK_TFTP is not set
+# CONFIG_NF_CONNTRACK_TIMEOUT is not set
+# CONFIG_NF_CONNTRACK_TIMESTAMP is not set
+# CONFIG_NF_CONNTRACK_ZONES is not set
+# CONFIG_NF_CT_NETLINK is not set
+# CONFIG_NF_CT_NETLINK_TIMEOUT is not set
+# CONFIG_NF_CT_NETLINK_HELPER is not set
+# CONFIG_NF_CT_PROTO_DCCP is not set
+# CONFIG_NF_CT_PROTO_GRE is not set
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CT_PROTO_UDPLITE is not set
+# CONFIG_NF_DEFRAG_IPV4 is not set
+# CONFIG_NF_DUP_IPV4 is not set
+# CONFIG_NF_DUP_IPV6 is not set
+# CONFIG_NF_FLOW_TABLE is not set
+# CONFIG_NF_LOG_ARP is not set
+# CONFIG_NF_LOG_BRIDGE is not set
+# CONFIG_NF_LOG_IPV4 is not set
+# CONFIG_NF_LOG_NETDEV is not set
+# CONFIG_NF_NAT is not set
+# CONFIG_NF_NAT_AMANDA is not set
+# CONFIG_NF_NAT_FTP is not set
+# CONFIG_NF_NAT_H323 is not set
+# CONFIG_NF_NAT_IRC is not set
+# CONFIG_NF_NAT_MASQUERADE is not set
+# CONFIG_NF_NAT_NEEDED is not set
+# CONFIG_NF_NAT_PPTP is not set
+# CONFIG_NF_NAT_PROTO_GRE is not set
+# CONFIG_NF_NAT_SIP is not set
+# CONFIG_NF_NAT_SNMP_BASIC is not set
+# CONFIG_NF_NAT_TFTP is not set
+# CONFIG_NF_REJECT_IPV4 is not set
+# CONFIG_NF_REJECT_IPV6 is not set
+# CONFIG_NF_SOCKET_IPV4 is not set
+# CONFIG_NF_SOCKET_IPV6 is not set
+# CONFIG_NF_TABLES is not set
+CONFIG_NF_TABLES_ARP=y
+CONFIG_NF_TABLES_BRIDGE=y
+CONFIG_NF_TABLES_INET=y
+CONFIG_NF_TABLES_IPV4=y
+CONFIG_NF_TABLES_IPV6=y
+CONFIG_NF_TABLES_NETDEV=y
+# CONFIG_NF_TABLES_SET is not set
+# CONFIG_NF_TPROXY_IPV4 is not set
+# CONFIG_NF_TPROXY_IPV6 is not set
+# CONFIG_NI65 is not set
+# CONFIG_NI903X_WDT is not set
+# CONFIG_NIC7018_WDT is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_NIU is not set
+# CONFIG_NI_XGE_MANAGEMENT_ENET is not set
+CONFIG_NLATTR=y
+# CONFIG_NLMON is not set
+# CONFIG_NLM_XLP_BOARD is not set
+# CONFIG_NLM_XLR_BOARD is not set
+# CONFIG_NLS is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_MAC_CELTIC is not set
+# CONFIG_NLS_MAC_CENTEURO is not set
+# CONFIG_NLS_MAC_CROATIAN is not set
+# CONFIG_NLS_MAC_CYRILLIC is not set
+# CONFIG_NLS_MAC_GAELIC is not set
+# CONFIG_NLS_MAC_GREEK is not set
+# CONFIG_NLS_MAC_ICELAND is not set
+# CONFIG_NLS_MAC_INUIT is not set
+# CONFIG_NLS_MAC_ROMAN is not set
+# CONFIG_NLS_MAC_ROMANIAN is not set
+# CONFIG_NLS_MAC_TURKISH is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_NMBM is not set
+CONFIG_NMI_LOG_BUF_SHIFT=13
+# CONFIG_NOA1305 is not set
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_NORTEL_HERMES is not set
+# CONFIG_NOTIFIER_ERROR_INJECTION is not set
+# CONFIG_NOUVEAU_LEGACY_CTX_SUPPORT is not set
+# CONFIG_NOZOMI is not set
+# CONFIG_NO_BOOTMEM is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_NO_HZ_FULL is not set
+# CONFIG_NO_HZ_IDLE is not set
+# CONFIG_NS83820 is not set
+# CONFIG_NTB is not set
+# CONFIG_NTFS_DEBUG is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_NTP_PPS is not set
+# CONFIG_NULL_TTY is not set
+# CONFIG_NUMA is not set
+# CONFIG_NVM is not set
+# CONFIG_NVMEM is not set
+# CONFIG_NVMEM_BCM_OCOTP is not set
+# CONFIG_NVMEM_IMX_OCOTP is not set
+# CONFIG_NVMEM_REBOOT_MODE is not set
+# CONFIG_NVMEM_SYSFS is not set
+# CONFIG_NVME_FC is not set
+# CONFIG_NVME_TARGET is not set
+# CONFIG_NVME_TCP is not set
+# CONFIG_NVRAM is not set
+# CONFIG_NV_TCO is not set
+# CONFIG_NXP_STB220 is not set
+# CONFIG_NXP_STB225 is not set
+# CONFIG_NXP_TJA11XX_PHY is not set
+# CONFIG_N_GSM is not set
+# CONFIG_OABI_COMPAT is not set
+# CONFIG_OBS600 is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_OCTEONTX2_AF is not set
+# CONFIG_OF_OVERLAY is not set
+CONFIG_OF_RESERVED_MEM=y
+# CONFIG_OF_UNITTEST is not set
+# CONFIG_OMAP2_DSS_DEBUG is not set
+# CONFIG_OMAP2_DSS_DEBUGFS is not set
+# CONFIG_OMAP2_DSS_SDI is not set
+# CONFIG_OMAP_OCP2SCP is not set
+# CONFIG_OMAP_USB2 is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_OPENVSWITCH is not set
+# CONFIG_OPROFILE is not set
+# CONFIG_OPROFILE_EVENT_MULTIPLEX is not set
+# CONFIG_OPT3001 is not set
+CONFIG_OPTIMIZE_INLINING=y
+# CONFIG_ORANGEFS_FS is not set
+# CONFIG_ORION_WATCHDOG is not set
+# CONFIG_OSF_PARTITION is not set
+CONFIG_OVERLAY_FS=y
+# CONFIG_OVERLAY_FS_INDEX is not set
+# CONFIG_OVERLAY_FS_METACOPY is not set
+CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y
+# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set
+CONFIG_OVERLAY_FS_XINO_AUTO=y
+# CONFIG_OWL_LOADER is not set
+# CONFIG_P54_COMMON is not set
+# CONFIG_PA12203001 is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_DIAG is not set
+# CONFIG_PACKING is not set
+# CONFIG_PAGE_EXTENSION is not set
+# CONFIG_PAGE_OWNER is not set
+# CONFIG_PAGE_POISONING is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_32KB is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_64KB is not set
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PALMAS_GPADC is not set
+# CONFIG_PANASONIC_LAPTOP is not set
+# CONFIG_PANEL is not set
+CONFIG_PANIC_ON_OOPS=y
+CONFIG_PANIC_ON_OOPS_VALUE=1
+CONFIG_PANIC_TIMEOUT=1
+# CONFIG_PANTHERLORD_FF is not set
+# CONFIG_PARAVIRT is not set
+# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set
+# CONFIG_PARPORT is not set
+# CONFIG_PARPORT_1284 is not set
+# CONFIG_PARPORT_AX88796 is not set
+# CONFIG_PARPORT_GSC is not set
+# CONFIG_PARPORT_PC is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARASAN_CF is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_ATP867X is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CS5535 is not set
+# CONFIG_PATA_CS5536 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IMX is not set
+# CONFIG_PATA_ISAPNP is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_LEGACY is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OCTEON_CF is not set
+# CONFIG_PATA_OF_PLATFORM is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PCMCIA is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_QDI is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RDC is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_TOSHIBA is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_WINBOND_VLB is not set
+# CONFIG_PC104 is not set
+# CONFIG_PC300TOO is not set
+# CONFIG_PCCARD is not set
+# CONFIG_PCH_DMA is not set
+# CONFIG_PCH_GBE is not set
+# CONFIG_PCH_PHUB is not set
+# CONFIG_PCI is not set
+# CONFIG_PCI200SYN is not set
+# CONFIG_PCIEAER is not set
+# CONFIG_PCIEAER_INJECT is not set
+# CONFIG_PCIEASPM is not set
+# CONFIG_PCIEPORTBUS is not set
+# CONFIG_PCIE_AL is not set
+# CONFIG_PCIE_ALTERA is not set
+# CONFIG_PCIE_ARMADA_8K is not set
+# CONFIG_PCIE_BW is not set
+# CONFIG_PCIE_CADENCE_HOST is not set
+# CONFIG_PCIE_DPC is not set
+# CONFIG_PCIE_DW_PLAT is not set
+# CONFIG_PCIE_DW_PLAT_HOST is not set
+# CONFIG_PCIE_ECRC is not set
+# CONFIG_PCIE_IPROC is not set
+# CONFIG_PCIE_KIRIN is not set
+# CONFIG_PCIE_PTM is not set
+# CONFIG_PCIE_XILINX is not set
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_PCI_ATMEL is not set
+# CONFIG_PCI_CNB20LE_QUIRK is not set
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_DISABLE_COMMON_QUIRKS is not set
+# CONFIG_PCI_ENDPOINT is not set
+# CONFIG_PCI_ENDPOINT_TEST is not set
+# CONFIG_PCI_FTPCI100 is not set
+# CONFIG_PCI_HERMES is not set
+# CONFIG_PCI_HISI is not set
+# CONFIG_PCI_HOST_GENERIC is not set
+# CONFIG_PCI_HOST_THUNDER_ECAM is not set
+# CONFIG_PCI_HOST_THUNDER_PEM is not set
+# CONFIG_PCI_IOV is not set
+# CONFIG_PCI_LAYERSCAPE is not set
+# CONFIG_PCI_MESON is not set
+# CONFIG_PCI_MSI is not set
+# CONFIG_PCI_PASID is not set
+# CONFIG_PCI_PF_STUB is not set
+# CONFIG_PCI_PRI is not set
+CONFIG_PCI_QUIRKS=y
+# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_SW_SWITCHTEC is not set
+CONFIG_PCI_SYSCALL=y
+# CONFIG_PCI_V3_SEMI is not set
+# CONFIG_PCI_XGENE is not set
+# CONFIG_PCMCIA is not set
+# CONFIG_PCMCIA_3C574 is not set
+# CONFIG_PCMCIA_3C589 is not set
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_ATMEL is not set
+# CONFIG_PCMCIA_AXNET is not set
+# CONFIG_PCMCIA_DEBUG is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_FMVJ18X is not set
+# CONFIG_PCMCIA_HERMES is not set
+# CONFIG_PCMCIA_LOAD_CIS is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_NMCLAN is not set
+# CONFIG_PCMCIA_PCNET is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+# CONFIG_PCMCIA_RAYCS is not set
+# CONFIG_PCMCIA_SMC91C92 is not set
+# CONFIG_PCMCIA_SPECTRUM is not set
+# CONFIG_PCMCIA_SYM53C500 is not set
+# CONFIG_PCMCIA_WL3501 is not set
+# CONFIG_PCMCIA_XIRC2PS is not set
+# CONFIG_PCMCIA_XIRCOM is not set
+# CONFIG_PCNET32 is not set
+# CONFIG_PCSPKR_PLATFORM is not set
+# CONFIG_PD6729 is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_PERCPU_STATS is not set
+# CONFIG_PERCPU_TEST is not set
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_EVENTS_AMD_POWER is not set
+# CONFIG_PERSISTENT_KEYRINGS is not set
+# CONFIG_PHANTOM is not set
+# CONFIG_PHONET is not set
+# CONFIG_PHYLIB is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+# CONFIG_PHY_CADENCE_DP is not set
+# CONFIG_PHY_CADENCE_DPHY is not set
+# CONFIG_PHY_CADENCE_SIERRA is not set
+# CONFIG_PHY_CPCAP_USB is not set
+# CONFIG_PHY_EXYNOS_DP_VIDEO is not set
+# CONFIG_PHY_EXYNOS_MIPI_VIDEO is not set
+# CONFIG_PHY_FSL_IMX8MQ_USB is not set
+# CONFIG_PHY_MAPPHONE_MDM6600 is not set
+# CONFIG_PHY_MIXEL_MIPI_DPHY is not set
+# CONFIG_PHY_OCELOT_SERDES is not set
+# CONFIG_PHY_PXA_28NM_HSIC is not set
+# CONFIG_PHY_PXA_28NM_USB2 is not set
+# CONFIG_PHY_QCOM_DWC3 is not set
+# CONFIG_PHY_QCOM_USB_HS is not set
+# CONFIG_PHY_QCOM_USB_HSIC is not set
+# CONFIG_PHY_SAMSUNG_USB2 is not set
+# CONFIG_PHY_TUSB1210 is not set
+# CONFIG_PHY_XGENE is not set
+# CONFIG_PI433 is not set
+# CONFIG_PID_IN_CONTEXTIDR is not set
+# CONFIG_PID_NS is not set
+CONFIG_PINCONF=y
+# CONFIG_PINCTRL is not set
+# CONFIG_PINCTRL_AMD is not set
+# CONFIG_PINCTRL_AXP209 is not set
+# CONFIG_PINCTRL_CEDARFORK is not set
+# CONFIG_PINCTRL_EXYNOS is not set
+# CONFIG_PINCTRL_EXYNOS5440 is not set
+# CONFIG_PINCTRL_ICELAKE is not set
+# CONFIG_PINCTRL_INGENIC is not set
+# CONFIG_PINCTRL_MCP23S08 is not set
+# CONFIG_PINCTRL_MSM8X74 is not set
+# CONFIG_PINCTRL_OCELOT is not set
+CONFIG_PINCTRL_SINGLE=y
+# CONFIG_PINCTRL_STMFX is not set
+# CONFIG_PINCTRL_SX150X is not set
+CONFIG_PINMUX=y
+# CONFIG_PKCS7_MESSAGE_PARSER is not set
+# CONFIG_PL310_ERRATA_588369 is not set
+# CONFIG_PL310_ERRATA_727915 is not set
+# CONFIG_PL310_ERRATA_753970 is not set
+# CONFIG_PL310_ERRATA_769419 is not set
+# CONFIG_PL320_MBOX is not set
+# CONFIG_PL330_DMA is not set
+# CONFIG_PLATFORM_MHU is not set
+# CONFIG_PLAT_SPEAR is not set
+# CONFIG_PLIP is not set
+CONFIG_PLUGIN_HOSTCC=""
+# CONFIG_PLX_HERMES is not set
+# CONFIG_PM is not set
+# CONFIG_PMBUS is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMS7003 is not set
+# CONFIG_PM_AUTOSLEEP is not set
+# CONFIG_PM_DEBUG is not set
+# CONFIG_PM_DEVFREQ is not set
+# CONFIG_PM_WAKELOCKS is not set
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_POSIX_TIMERS=y
+# CONFIG_POWERCAP is not set
+# CONFIG_POWER_AVS is not set
+# CONFIG_POWER_RESET is not set
+# CONFIG_POWER_RESET_BRCMKONA is not set
+# CONFIG_POWER_RESET_BRCMSTB is not set
+# CONFIG_POWER_RESET_GPIO is not set
+# CONFIG_POWER_RESET_GPIO_RESTART is not set
+# CONFIG_POWER_RESET_LTC2952 is not set
+# CONFIG_POWER_RESET_PIIX4_POWEROFF is not set
+# CONFIG_POWER_RESET_RESTART is not set
+# CONFIG_POWER_RESET_SYSCON is not set
+# CONFIG_POWER_RESET_SYSCON_POWEROFF is not set
+# CONFIG_POWER_RESET_VERSATILE is not set
+# CONFIG_POWER_RESET_XGENE is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_POWER_SUPPLY_HWMON is not set
+# CONFIG_PPC4xx_GPIO is not set
+# CONFIG_PPC_16K_PAGES is not set
+# CONFIG_PPC_256K_PAGES is not set
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_64K_PAGES is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+# CONFIG_PPC_EMULATED_STATS is not set
+# CONFIG_PPC_EPAPR_HV_BYTECHAN is not set
+# CONFIG_PPP is not set
+# CONFIG_PPPOATM is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_DEFLATE is not set
+CONFIG_PPP_FILTER=y
+# CONFIG_PPP_MPPE is not set
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPS is not set
+# CONFIG_PPS_CLIENT_GPIO is not set
+# CONFIG_PPS_CLIENT_KTIMER is not set
+# CONFIG_PPS_CLIENT_LDISC is not set
+# CONFIG_PPS_CLIENT_PARPORT is not set
+# CONFIG_PPS_DEBUG is not set
+# CONFIG_PPTP is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_PREEMPTIRQ_DELAY_TEST is not set
+# CONFIG_PREEMPTIRQ_EVENTS is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_PRINTK=y
+# CONFIG_PRINTK_CALLER is not set
+CONFIG_PRINTK_NMI=y
+CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13
+# CONFIG_PRINTK_TIME is not set
+CONFIG_PRINT_STACK_DEPTH=64
+# CONFIG_PRISM2_USB is not set
+# CONFIG_PRISM54 is not set
+# CONFIG_PROC_CHILDREN is not set
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+# CONFIG_PROC_PAGE_MONITOR is not set
+# CONFIG_PROC_STRIPPED is not set
+CONFIG_PROC_SYSCTL=y
+# CONFIG_PROC_VMCORE_DEVICE_DUMP is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILING is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_PROVE_RCU is not set
+# CONFIG_PROVE_RCU_LIST is not set
+# CONFIG_PROVE_RCU_REPEATEDLY is not set
+# CONFIG_PSAMPLE is not set
+# CONFIG_PSB6970_PHY is not set
+# CONFIG_PSI is not set
+# CONFIG_PSTORE is not set
+# CONFIG_PTP_1588_CLOCK is not set
+# CONFIG_PTP_1588_CLOCK_IXP46X is not set
+# CONFIG_PTP_1588_CLOCK_KVM is not set
+# CONFIG_PTP_1588_CLOCK_PCH is not set
+# CONFIG_PUBLIC_KEY_ALGO_RSA is not set
+# CONFIG_PVPANIC is not set
+# CONFIG_PWM is not set
+# CONFIG_PWM_FSL_FTM is not set
+# CONFIG_PWM_PCA9685 is not set
+CONFIG_PWRSEQ_EMMC=y
+# CONFIG_PWRSEQ_SD8787 is not set
+CONFIG_PWRSEQ_SIMPLE=y
+# CONFIG_QCA7000 is not set
+# CONFIG_QCA7000_SPI is not set
+# CONFIG_QCA7000_UART is not set
+# CONFIG_QCOM_EMAC is not set
+# CONFIG_QCOM_FALKOR_ERRATUM_1003 is not set
+# CONFIG_QCOM_FALKOR_ERRATUM_1009 is not set
+# CONFIG_QCOM_FALKOR_ERRATUM_E1041 is not set
+# CONFIG_QCOM_HIDMA is not set
+# CONFIG_QCOM_HIDMA_MGMT is not set
+# CONFIG_QCOM_QDF2400_ERRATUM_0065 is not set
+# CONFIG_QCOM_SPMI_ADC5 is not set
+# CONFIG_QCOM_SPMI_IADC is not set
+# CONFIG_QCOM_SPMI_TEMP_ALARM is not set
+# CONFIG_QCOM_SPMI_VADC is not set
+# CONFIG_QED is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_QLCNIC is not set
+# CONFIG_QLGE is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX6FS_FS is not set
+# CONFIG_QORIQ_CPUFREQ is not set
+# CONFIG_QORIQ_THERMAL is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_QUEUED_LOCK_STAT is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+# CONFIG_QUOTA_DEBUG is not set
+# CONFIG_R3964 is not set
+# CONFIG_R6040 is not set
+# CONFIG_R8169 is not set
+# CONFIG_R8188EU is not set
+# CONFIG_R8712U is not set
+# CONFIG_R8723AU is not set
+# CONFIG_RADIO_ADAPTERS is not set
+# CONFIG_RADIO_AZTECH is not set
+# CONFIG_RADIO_CADET is not set
+# CONFIG_RADIO_GEMTEK is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_RTRACK is not set
+# CONFIG_RADIO_RTRACK2 is not set
+# CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_SF16FMR2 is not set
+# CONFIG_RADIO_TERRATEC is not set
+# CONFIG_RADIO_TRUST is not set
+# CONFIG_RADIO_TYPHOON is not set
+# CONFIG_RADIO_ZOLTRIX is not set
+# CONFIG_RAID6_PQ_BENCHMARK is not set
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_RALINK is not set
+# CONFIG_RANDOM32_SELFTEST is not set
+# CONFIG_RANDOMIZE_BASE is not set
+# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
+# CONFIG_RANDOM_TRUST_CPU is not set
+# CONFIG_RAPIDIO is not set
+# CONFIG_RAS is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_RBTREE_TEST is not set
+# CONFIG_RCU_BOOST is not set
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+# CONFIG_RCU_EQS_DEBUG is not set
+# CONFIG_RCU_EXPEDITE_BOOT is not set
+CONFIG_RCU_EXPERT=y
+CONFIG_RCU_FANOUT=32
+CONFIG_RCU_FANOUT_LEAF=16
+# CONFIG_RCU_FAST_NO_HZ is not set
+CONFIG_RCU_KTHREAD_PRIO=0
+# CONFIG_RCU_NOCB_CPU is not set
+# CONFIG_RCU_PERF_TEST is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY=3
+# CONFIG_RCU_TRACE is not set
+# CONFIG_RC_ATI_REMOTE is not set
+# CONFIG_RC_CORE is not set
+# CONFIG_RC_DECODERS is not set
+# CONFIG_RC_LOOPBACK is not set
+# CONFIG_RC_MAP is not set
+# CONFIG_RDS is not set
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_GZIP is not set
+# CONFIG_RD_LZ4 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_READABLE_ASM is not set
+# CONFIG_READ_ONLY_THP_FOR_FS is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_REDWOOD is not set
+# CONFIG_REED_SOLOMON_TEST is not set
+# CONFIG_REFCOUNT_FULL is not set
+# CONFIG_REGMAP is not set
+# CONFIG_REGMAP_I2C is not set
+# CONFIG_REGMAP_MMIO is not set
+# CONFIG_REGMAP_SPI is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_88PG86X is not set
+# CONFIG_REGULATOR_ACT8865 is not set
+# CONFIG_REGULATOR_AD5398 is not set
+# CONFIG_REGULATOR_ANATOP is not set
+# CONFIG_REGULATOR_DA9210 is not set
+# CONFIG_REGULATOR_DA9211 is not set
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_FAN53555 is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_GPIO is not set
+# CONFIG_REGULATOR_ISL6271A is not set
+# CONFIG_REGULATOR_ISL9305 is not set
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_LP3972 is not set
+# CONFIG_REGULATOR_LP872X is not set
+# CONFIG_REGULATOR_LP8755 is not set
+# CONFIG_REGULATOR_LTC3589 is not set
+# CONFIG_REGULATOR_LTC3676 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_MAX8649 is not set
+# CONFIG_REGULATOR_MAX8660 is not set
+# CONFIG_REGULATOR_MAX8952 is not set
+# CONFIG_REGULATOR_MAX8973 is not set
+# CONFIG_REGULATOR_MCP16502 is not set
+# CONFIG_REGULATOR_MT6311 is not set
+# CONFIG_REGULATOR_PFUZE100 is not set
+# CONFIG_REGULATOR_PV88060 is not set
+# CONFIG_REGULATOR_PV88080 is not set
+# CONFIG_REGULATOR_PV88090 is not set
+# CONFIG_REGULATOR_PWM is not set
+# CONFIG_REGULATOR_SLG51000 is not set
+# CONFIG_REGULATOR_SY8106A is not set
+# CONFIG_REGULATOR_SY8824X is not set
+# CONFIG_REGULATOR_TI_ABB is not set
+# CONFIG_REGULATOR_TPS51632 is not set
+# CONFIG_REGULATOR_TPS62360 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+# CONFIG_REGULATOR_TPS65132 is not set
+# CONFIG_REGULATOR_TPS6524X is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_VCTRL is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_FS_POSIX_ACL is not set
+# CONFIG_REISERFS_FS_SECURITY is not set
+CONFIG_REISERFS_FS_XATTR=y
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_RELAY is not set
+# CONFIG_RELOCATABLE is not set
+# CONFIG_REMOTEPROC is not set
+# CONFIG_RENESAS_PHY is not set
+# CONFIG_RESET_ATH79 is not set
+# CONFIG_RESET_BERLIN is not set
+# CONFIG_RESET_CONTROLLER is not set
+# CONFIG_RESET_IMX7 is not set
+# CONFIG_RESET_LANTIQ is not set
+# CONFIG_RESET_LPC18XX is not set
+# CONFIG_RESET_MESON is not set
+# CONFIG_RESET_PISTACHIO is not set
+# CONFIG_RESET_SOCFPGA is not set
+# CONFIG_RESET_STM32 is not set
+# CONFIG_RESET_SUNXI is not set
+# CONFIG_RESET_TEGRA_BPMP is not set
+# CONFIG_RESET_TI_SYSCON is not set
+# CONFIG_RESET_ZYNQ is not set
+# CONFIG_RFD77402 is not set
+# CONFIG_RFD_FTL is not set
+CONFIG_RFKILL=y
+# CONFIG_RFKILL_FULL is not set
+# CONFIG_RFKILL_GPIO is not set
+# CONFIG_RFKILL_INPUT is not set
+# CONFIG_RFKILL_LEDS is not set
+# CONFIG_RFKILL_REGULATOR is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_RING_BUFFER_STARTUP_TEST is not set
+# CONFIG_RMI4_CORE is not set
+# CONFIG_RMNET is not set
+# CONFIG_ROCKCHIP_PHY is not set
+# CONFIG_ROCKER is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_ROSE is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPMSG_QCOM_GLINK_RPM is not set
+# CONFIG_RPMSG_VIRTIO is not set
+# CONFIG_RPR0521 is not set
+# CONFIG_RSEQ is not set
+# CONFIG_RT2X00 is not set
+# CONFIG_RTC_CLASS is not set
+# CONFIG_RTC_DEBUG is not set
+# CONFIG_RTC_DRV_ABB5ZES3 is not set
+# CONFIG_RTC_DRV_ABEOZ9 is not set
+# CONFIG_RTC_DRV_ABX80X is not set
+# CONFIG_RTC_DRV_ARMADA38X is not set
+# CONFIG_RTC_DRV_AU1XXX is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_CADENCE is not set
+CONFIG_RTC_DRV_CMOS=y
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1302 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1307_CENTURY is not set
+# CONFIG_RTC_DRV_DS1307_HWMON is not set
+# CONFIG_RTC_DRV_DS1343 is not set
+# CONFIG_RTC_DRV_DS1347 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS1685_FAMILY is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_DS2404 is not set
+# CONFIG_RTC_DRV_DS3232 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_EM3027 is not set
+# CONFIG_RTC_DRV_EP93XX is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_FTRTC010 is not set
+# CONFIG_RTC_DRV_GENERIC is not set
+# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set
+# CONFIG_RTC_DRV_HYM8563 is not set
+# CONFIG_RTC_DRV_ISL12022 is not set
+# CONFIG_RTC_DRV_ISL12026 is not set
+# CONFIG_RTC_DRV_ISL12057 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_JZ4740 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_M41T93 is not set
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_MAX6916 is not set
+# CONFIG_RTC_DRV_MCP795 is not set
+# CONFIG_RTC_DRV_MOXART is not set
+# CONFIG_RTC_DRV_MPC5121 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_OMAP is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+# CONFIG_RTC_DRV_PCF2127 is not set
+# CONFIG_RTC_DRV_PCF85063 is not set
+# CONFIG_RTC_DRV_PCF8523 is not set
+# CONFIG_RTC_DRV_PCF85363 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_PL030 is not set
+# CONFIG_RTC_DRV_PL031 is not set
+# CONFIG_RTC_DRV_PS3 is not set
+# CONFIG_RTC_DRV_PT7C4338 is not set
+# CONFIG_RTC_DRV_R7301 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_RTC7301 is not set
+# CONFIG_RTC_DRV_RV3028 is not set
+# CONFIG_RTC_DRV_RV3029C2 is not set
+# CONFIG_RTC_DRV_RV8803 is not set
+# CONFIG_RTC_DRV_RX4581 is not set
+# CONFIG_RTC_DRV_RX6110 is not set
+# CONFIG_RTC_DRV_RX8010 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_SD3078 is not set
+# CONFIG_RTC_DRV_SNVS is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_SUN6I is not set
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_V3020 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_XGENE is not set
+# CONFIG_RTC_DRV_ZYNQMP is not set
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_NVMEM is not set
+CONFIG_RTC_SYSTOHC=y
+CONFIG_RTC_SYSTOHC_DEVICE="rtc0"
+# CONFIG_RTL8180 is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_RTL8192E is not set
+# CONFIG_RTL8192U is not set
+# CONFIG_RTL8306_PHY is not set
+# CONFIG_RTL8366RB_PHY is not set
+# CONFIG_RTL8366S_PHY is not set
+# CONFIG_RTL8366_SMI is not set
+# CONFIG_RTL8366_SMI_DEBUG_FS is not set
+# CONFIG_RTL8367B_PHY is not set
+# CONFIG_RTL8367_PHY is not set
+# CONFIG_RTLLIB is not set
+# CONFIG_RTL_CARDS is not set
+# CONFIG_RTS5208 is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_RUNTIME_DEBUG is not set
+CONFIG_RUNTIME_TESTING_MENU=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_RXKAD=y
+# CONFIG_S2IO is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_SAMSUNG_LAPTOP is not set
+# CONFIG_SATA_ACARD_AHCI is not set
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_AHCI_PLATFORM is not set
+# CONFIG_SATA_DWC is not set
+# CONFIG_SATA_FSL is not set
+# CONFIG_SATA_HIGHBANK is not set
+# CONFIG_SATA_INIC162X is not set
+CONFIG_SATA_MOBILE_LPM_POLICY=0
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_SATA_PMP is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_RCAR is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SBC_FITPC2_WATCHDOG is not set
+CONFIG_SBITMAP=y
+# CONFIG_SC92031 is not set
+# CONFIG_SCA3000 is not set
+# CONFIG_SCACHE_DEBUGFS is not set
+# CONFIG_SCC is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_SCHED_AUTOGROUP is not set
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHED_HRTICK=y
+# CONFIG_SCHED_MC is not set
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+# CONFIG_SCHED_SMT is not set
+# CONFIG_SCHED_STACK_END_CHECK is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_SCR24X is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_3W_SAS is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_SCSI_BFA_FC is not set
+# CONFIG_SCSI_BNX2X_FCOE is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CHELSIO_FCOE is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_CXGB4_ISCSI is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_ESAS2R is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_FDOMAIN_PCI is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_HISI_SAS is not set
+# CONFIG_SCSI_HPSA is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_ISCI is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_LOGGING is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
+# CONFIG_SCSI_LPFC is not set
+CONFIG_SCSI_MOD=y
+# CONFIG_SCSI_MPT2SAS is not set
+# CONFIG_SCSI_MPT3SAS is not set
+# CONFIG_SCSI_MQ_DEFAULT is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_MVSAS_DEBUG is not set
+# CONFIG_SCSI_MVUMI is not set
+# CONFIG_SCSI_MYRB is not set
+# CONFIG_SCSI_MYRS is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PM8001 is not set
+# CONFIG_SCSI_PMCRAID is not set
+CONFIG_SCSI_PROC_FS=y
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+# CONFIG_SCSI_SMARTPQI is not set
+# CONFIG_SCSI_SNIC is not set
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_UFSHCD is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_VIRTIO is not set
+# CONFIG_SCSI_WD719X is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_SDIO_UART is not set
+# CONFIG_SD_ADC_MODULATOR is not set
+# CONFIG_SECCOMP is not set
+CONFIG_SECTION_MISMATCH_WARN_ONLY=y
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_APPARMOR is not set
+CONFIG_SECURITY_DMESG_RESTRICT=y
+# CONFIG_SECURITY_LOADPIN is not set
+# CONFIG_SECURITY_LOCKDOWN_LSM is not set
+# CONFIG_SECURITY_PATH is not set
+# CONFIG_SECURITY_SAFESETID is not set
+# CONFIG_SECURITY_SELINUX_AVC_STATS is not set
+# CONFIG_SECURITY_SELINUX_BOOTPARAM is not set
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=0
+# CONFIG_SECURITY_SELINUX_DEVELOP is not set
+# CONFIG_SECURITY_SELINUX_DISABLE is not set
+# CONFIG_SECURITY_SMACK is not set
+# CONFIG_SECURITY_TOMOYO is not set
+# CONFIG_SECURITY_YAMA is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_SENSIRION_SGP30 is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
+# CONFIG_SENSORS_ACPI_POWER is not set
+# CONFIG_SENSORS_AD7314 is not set
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADC128D818 is not set
+# CONFIG_SENSORS_ADCXX is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM1275 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADS1015 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_ADS7871 is not set
+# CONFIG_SENSORS_ADT7310 is not set
+# CONFIG_SENSORS_ADT7410 is not set
+# CONFIG_SENSORS_ADT7411 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_AMC6821 is not set
+# CONFIG_SENSORS_APDS990X is not set
+# CONFIG_SENSORS_APPLESMC is not set
+# CONFIG_SENSORS_AS370 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ASC7621 is not set
+# CONFIG_SENSORS_ASPEED is not set
+# CONFIG_SENSORS_ATK0110 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_SENSORS_CORETEMP is not set
+# CONFIG_SENSORS_DELL_SMM is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_DS620 is not set
+# CONFIG_SENSORS_EMC1403 is not set
+# CONFIG_SENSORS_EMC2103 is not set
+# CONFIG_SENSORS_EMC6W201 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_FAM15H_POWER is not set
+# CONFIG_SENSORS_FSCHMD is not set
+# CONFIG_SENSORS_FTSTEUTATES is not set
+# CONFIG_SENSORS_G760A is not set
+# CONFIG_SENSORS_G762 is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_GPIO_FAN is not set
+# CONFIG_SENSORS_GSC is not set
+# CONFIG_SENSORS_HDAPS is not set
+# CONFIG_SENSORS_HIH6130 is not set
+# CONFIG_SENSORS_HMC5843 is not set
+# CONFIG_SENSORS_HMC5843_I2C is not set
+# CONFIG_SENSORS_HMC5843_SPI is not set
+# CONFIG_SENSORS_HTU21 is not set
+# CONFIG_SENSORS_I5500 is not set
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_IBM_CFFPS is not set
+# CONFIG_SENSORS_IIO_HWMON is not set
+# CONFIG_SENSORS_INA209 is not set
+# CONFIG_SENSORS_INA2XX is not set
+# CONFIG_SENSORS_INA3221 is not set
+# CONFIG_SENSORS_INSPUR_IPSPS is not set
+# CONFIG_SENSORS_IR35221 is not set
+# CONFIG_SENSORS_IR38064 is not set
+# CONFIG_SENSORS_IRPS5401 is not set
+# CONFIG_SENSORS_ISL29018 is not set
+# CONFIG_SENSORS_ISL29028 is not set
+# CONFIG_SENSORS_ISL68137 is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_JC42 is not set
+# CONFIG_SENSORS_K10TEMP is not set
+# CONFIG_SENSORS_K8TEMP is not set
+# CONFIG_SENSORS_LINEAGE is not set
+# CONFIG_SENSORS_LIS3LV02D is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
+# CONFIG_SENSORS_LIS3_SPI is not set
+# CONFIG_SENSORS_LM25066 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM73 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LM95234 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_LM95245 is not set
+# CONFIG_SENSORS_LTC2945 is not set
+# CONFIG_SENSORS_LTC2978 is not set
+# CONFIG_SENSORS_LTC2990 is not set
+# CONFIG_SENSORS_LTC3815 is not set
+# CONFIG_SENSORS_LTC4151 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4222 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LTC4260 is not set
+# CONFIG_SENSORS_LTC4261 is not set
+# CONFIG_SENSORS_LTQ_CPUTEMP is not set
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX16064 is not set
+# CONFIG_SENSORS_MAX16065 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX1668 is not set
+# CONFIG_SENSORS_MAX197 is not set
+# CONFIG_SENSORS_MAX20751 is not set
+# CONFIG_SENSORS_MAX31722 is not set
+# CONFIG_SENSORS_MAX31785 is not set
+# CONFIG_SENSORS_MAX31790 is not set
+# CONFIG_SENSORS_MAX34440 is not set
+# CONFIG_SENSORS_MAX6621 is not set
+# CONFIG_SENSORS_MAX6639 is not set
+# CONFIG_SENSORS_MAX6642 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_MAX6697 is not set
+# CONFIG_SENSORS_MAX8688 is not set
+# CONFIG_SENSORS_MCP3021 is not set
+# CONFIG_SENSORS_NCT6683 is not set
+# CONFIG_SENSORS_NCT6775 is not set
+# CONFIG_SENSORS_NCT7802 is not set
+# CONFIG_SENSORS_NCT7904 is not set
+# CONFIG_SENSORS_NPCM7XX is not set
+# CONFIG_SENSORS_NSA320 is not set
+# CONFIG_SENSORS_NTC_THERMISTOR is not set
+# CONFIG_SENSORS_OCC_P8_I2C is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_PMBUS is not set
+# CONFIG_SENSORS_POWR1220 is not set
+# CONFIG_SENSORS_PWM_FAN is not set
+# CONFIG_SENSORS_PXE1610 is not set
+# CONFIG_SENSORS_RM3100_I2C is not set
+# CONFIG_SENSORS_RM3100_SPI is not set
+# CONFIG_SENSORS_SCH5627 is not set
+# CONFIG_SENSORS_SCH5636 is not set
+# CONFIG_SENSORS_SCH56XX_COMMON is not set
+# CONFIG_SENSORS_SHT15 is not set
+# CONFIG_SENSORS_SHT21 is not set
+# CONFIG_SENSORS_SHT3x is not set
+# CONFIG_SENSORS_SHTC1 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMM665 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_STTS751 is not set
+# CONFIG_SENSORS_TC654 is not set
+# CONFIG_SENSORS_TC74 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP102 is not set
+# CONFIG_SENSORS_TMP103 is not set
+# CONFIG_SENSORS_TMP108 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
+# CONFIG_SENSORS_TPS40422 is not set
+# CONFIG_SENSORS_TPS53679 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_TSL2563 is not set
+# CONFIG_SENSORS_UCD9000 is not set
+# CONFIG_SENSORS_UCD9200 is not set
+# CONFIG_SENSORS_VEXPRESS is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VIA_CPUTEMP is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83773G is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83795 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_XGENE is not set
+# CONFIG_SENSORS_ZL6100 is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_ACCENT is not set
+# CONFIG_SERIAL_8250_ASPEED_VUART is not set
+# CONFIG_SERIAL_8250_BOCA is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_CS is not set
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+CONFIG_SERIAL_8250_DMA=y
+# CONFIG_SERIAL_8250_DW is not set
+# CONFIG_SERIAL_8250_EM is not set
+# CONFIG_SERIAL_8250_EXAR is not set
+# CONFIG_SERIAL_8250_EXAR_ST16C554 is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_FINTEK is not set
+# CONFIG_SERIAL_8250_FOURPORT is not set
+# CONFIG_SERIAL_8250_HUB6 is not set
+# CONFIG_SERIAL_8250_INGENIC is not set
+# CONFIG_SERIAL_8250_LPSS is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_MID is not set
+# CONFIG_SERIAL_8250_MOXA is not set
+CONFIG_SERIAL_8250_NR_UARTS=2
+# CONFIG_SERIAL_8250_PCI is not set
+# CONFIG_SERIAL_8250_RSA is not set
+# CONFIG_SERIAL_8250_RT288X is not set
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_AMBA_PL010 is not set
+# CONFIG_SERIAL_AMBA_PL011 is not set
+# CONFIG_SERIAL_ARC is not set
+# CONFIG_SERIAL_BCM63XX is not set
+# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_DEV_BUS is not set
+CONFIG_SERIAL_EARLYCON=y
+# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
+# CONFIG_SERIAL_FSL_LINFLEXUART is not set
+# CONFIG_SERIAL_FSL_LPUART is not set
+# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set
+# CONFIG_SERIAL_IFX6X60 is not set
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_MAX3100 is not set
+# CONFIG_SERIAL_MAX310X is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_SERIAL_OF_PLATFORM is not set
+# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set
+# CONFIG_SERIAL_PCH_UART is not set
+# CONFIG_SERIAL_RP2 is not set
+# CONFIG_SERIAL_SC16IS7XX is not set
+# CONFIG_SERIAL_SCCNXP is not set
+# CONFIG_SERIAL_SH_SCI is not set
+# CONFIG_SERIAL_SIFIVE is not set
+# CONFIG_SERIAL_STM32 is not set
+# CONFIG_SERIAL_ST_ASC is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_UARTLITE is not set
+# CONFIG_SERIAL_XILINX_PS_UART is not set
+# CONFIG_SERIO is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_SERIO_AMBAKMI is not set
+# CONFIG_SERIO_APBPS2 is not set
+# CONFIG_SERIO_ARC_PS2 is not set
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_GPIO_PS2 is not set
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_PS2MULT is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_SUN4I_PS2 is not set
+# CONFIG_SFC is not set
+# CONFIG_SFC_FALCON is not set
+# CONFIG_SFI is not set
+# CONFIG_SFP is not set
+# CONFIG_SGETMASK_SYSCALL is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP28 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_SG_POOL is not set
+# CONFIG_SG_SPLIT is not set
+CONFIG_SHMEM=y
+# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set
+# CONFIG_SH_ETH is not set
+# CONFIG_SH_TIMER_CMT is not set
+# CONFIG_SH_TIMER_MTU2 is not set
+# CONFIG_SH_TIMER_TMU is not set
+# CONFIG_SI1133 is not set
+# CONFIG_SI1145 is not set
+# CONFIG_SI7005 is not set
+# CONFIG_SI7020 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_SWARM is not set
+CONFIG_SIGNALFD=y
+# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set
+# CONFIG_SIMPLE_GPIO is not set
+# CONFIG_SIMPLE_PM_BUS is not set
+# CONFIG_SIOX is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SKY2_DEBUG is not set
+# CONFIG_SLAB is not set
+CONFIG_SLABINFO=y
+# CONFIG_SLAB_FREELIST_HARDENED is not set
+# CONFIG_SLAB_FREELIST_RANDOM is not set
+CONFIG_SLAB_MERGE_DEFAULT=y
+# CONFIG_SLHC is not set
+# CONFIG_SLICOSS is not set
+# CONFIG_SLIMBUS is not set
+# CONFIG_SLIP is not set
+# CONFIG_SLOB is not set
+CONFIG_SLUB=y
+CONFIG_SLUB_CPU_PARTIAL=y
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_MEMCG_SYSFS_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_SMARTJOYPLUS_FF is not set
+# CONFIG_SMC911X is not set
+# CONFIG_SMC9194 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_SMP is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_SMSC9420 is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_SM_FTL is not set
+# CONFIG_SND is not set
+# CONFIG_SND_AC97_POWER_SAVE is not set
+# CONFIG_SND_AD1816A is not set
+# CONFIG_SND_AD1848 is not set
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ADLIB is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ALOOP is not set
+# CONFIG_SND_ALS100 is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_ARM is not set
+# CONFIG_SND_ASIHPI is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_ATMEL_AC97C is not set
+# CONFIG_SND_ATMEL_SOC is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AUDIO_GRAPH_CARD is not set
+# CONFIG_SND_AUDIO_GRAPH_SCU_CARD is not set
+# CONFIG_SND_AW2 is not set
+# CONFIG_SND_AZT2320 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BCD2000 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMI8330 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_CS4231 is not set
+# CONFIG_SND_CS4236 is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS5530 is not set
+# CONFIG_SND_CS5535AUDIO is not set
+# CONFIG_SND_CTXFI is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_DESIGNWARE_I2S is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_EDMA_SOC is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1688 is not set
+# CONFIG_SND_ES18XX is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FIREWIRE is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_GUSCLASSIC is not set
+# CONFIG_SND_GUSEXTREME is not set
+# CONFIG_SND_GUSMAX is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDA_INTEL_DETECT_DMIC is not set
+CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0
+CONFIG_SND_HDA_PREALLOC_SIZE=64
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_HWDEP is not set
+# CONFIG_SND_I2S_HI6210_I2S is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_INDIGODJX is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGOIOX is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_INTERWAVE is not set
+# CONFIG_SND_INTERWAVE_STB is not set
+# CONFIG_SND_ISA is not set
+# CONFIG_SND_JZ4740_SOC_I2S is not set
+# CONFIG_SND_KIRKWOOD_SOC is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_LOLA is not set
+# CONFIG_SND_LX6464ES is not set
+# CONFIG_SND_MAESTRO3 is not set
+CONFIG_SND_MAX_CARDS=16
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_MIPS is not set
+# CONFIG_SND_MIRO is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MPC52xx_SOC_EFIKA is not set
+# CONFIG_SND_MPU401 is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_MTS64 is not set
+# CONFIG_SND_MXS_SOC is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_OPL3SA2 is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_OPTI92X_AD1848 is not set
+# CONFIG_SND_OPTI92X_CS4231 is not set
+# CONFIG_SND_OPTI93X is not set
+CONFIG_SND_OSSEMUL=y
+# CONFIG_SND_OXYGEN is not set
+CONFIG_SND_PCI=y
+# CONFIG_SND_PCM is not set
+# CONFIG_SND_PCMCIA is not set
+# CONFIG_SND_PCM_OSS is not set
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_PCM_TIMER is not set
+# CONFIG_SND_PCM_XRUN_DEBUG is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_PDAUDIOCF is not set
+# CONFIG_SND_PORTMAN2X4 is not set
+# CONFIG_SND_POWERPC_SOC is not set
+# CONFIG_SND_PPC is not set
+CONFIG_SND_PROC_FS=y
+# CONFIG_SND_RAWMIDI is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_RIPTIDE is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_RTCTIMER is not set
+# CONFIG_SND_SB16 is not set
+# CONFIG_SND_SB8 is not set
+# CONFIG_SND_SBAWE is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_SE6X is not set
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_SIMPLE_CARD is not set
+# CONFIG_SND_SIMPLE_SCU_CARD is not set
+# CONFIG_SND_SIS7019 is not set
+# CONFIG_SND_SOC is not set
+# CONFIG_SND_SOC_AC97_CODEC is not set
+# CONFIG_SND_SOC_ADAU1701 is not set
+# CONFIG_SND_SOC_ADAU1761_I2C is not set
+# CONFIG_SND_SOC_ADAU1761_SPI is not set
+# CONFIG_SND_SOC_ADAU7002 is not set
+# CONFIG_SND_SOC_AK4104 is not set
+# CONFIG_SND_SOC_AK4118 is not set
+# CONFIG_SND_SOC_AK4458 is not set
+# CONFIG_SND_SOC_AK4554 is not set
+# CONFIG_SND_SOC_AK4613 is not set
+# CONFIG_SND_SOC_AK4642 is not set
+# CONFIG_SND_SOC_AK5386 is not set
+# CONFIG_SND_SOC_AK5558 is not set
+# CONFIG_SND_SOC_ALC5623 is not set
+# CONFIG_SND_SOC_AMD_ACP is not set
+# CONFIG_SND_SOC_AMD_ACP3x is not set
+# CONFIG_SND_SOC_AU1XAUDIO is not set
+# CONFIG_SND_SOC_AU1XPSC is not set
+# CONFIG_SND_SOC_BD28623 is not set
+# CONFIG_SND_SOC_BT_SCO is not set
+# CONFIG_SND_SOC_CS35L32 is not set
+# CONFIG_SND_SOC_CS35L33 is not set
+# CONFIG_SND_SOC_CS35L34 is not set
+# CONFIG_SND_SOC_CS35L35 is not set
+# CONFIG_SND_SOC_CS35L36 is not set
+# CONFIG_SND_SOC_CS4265 is not set
+# CONFIG_SND_SOC_CS4270 is not set
+# CONFIG_SND_SOC_CS4271 is not set
+# CONFIG_SND_SOC_CS4271_I2C is not set
+# CONFIG_SND_SOC_CS4271_SPI is not set
+# CONFIG_SND_SOC_CS42L42 is not set
+# CONFIG_SND_SOC_CS42L51_I2C is not set
+# CONFIG_SND_SOC_CS42L52 is not set
+# CONFIG_SND_SOC_CS42L56 is not set
+# CONFIG_SND_SOC_CS42L73 is not set
+# CONFIG_SND_SOC_CS42XX8_I2C is not set
+# CONFIG_SND_SOC_CS43130 is not set
+# CONFIG_SND_SOC_CS4341 is not set
+# CONFIG_SND_SOC_CS4349 is not set
+# CONFIG_SND_SOC_CS53L30 is not set
+# CONFIG_SND_SOC_CX2072X is not set
+# CONFIG_SND_SOC_DIO2125 is not set
+# CONFIG_SND_SOC_DMIC is not set
+# CONFIG_SND_SOC_ES7134 is not set
+# CONFIG_SND_SOC_ES7241 is not set
+# CONFIG_SND_SOC_ES8316 is not set
+# CONFIG_SND_SOC_ES8328 is not set
+# CONFIG_SND_SOC_ES8328_I2C is not set
+# CONFIG_SND_SOC_ES8328_SPI is not set
+# CONFIG_SND_SOC_EUKREA_TLV320 is not set
+# CONFIG_SND_SOC_FSL_ASOC_CARD is not set
+# CONFIG_SND_SOC_FSL_ASRC is not set
+# CONFIG_SND_SOC_FSL_AUDMIX is not set
+# CONFIG_SND_SOC_FSL_ESAI is not set
+# CONFIG_SND_SOC_FSL_MICFIL is not set
+# CONFIG_SND_SOC_FSL_SAI is not set
+# CONFIG_SND_SOC_FSL_SPDIF is not set
+# CONFIG_SND_SOC_FSL_SSI is not set
+# CONFIG_SND_SOC_GTM601 is not set
+# CONFIG_SND_SOC_ICS43432 is not set
+# CONFIG_SND_SOC_IMG is not set
+# CONFIG_SND_SOC_IMX_AUDMIX is not set
+# CONFIG_SND_SOC_IMX_AUDMUX is not set
+# CONFIG_SND_SOC_IMX_ES8328 is not set
+# CONFIG_SND_SOC_IMX_SPDIF is not set
+# CONFIG_SND_SOC_IMX_WM8962 is not set
+# CONFIG_SND_SOC_INNO_RK3036 is not set
+# CONFIG_SND_SOC_INTEL_APL is not set
+# CONFIG_SND_SOC_INTEL_BAYTRAIL is not set
+# CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH is not set
+# CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH is not set
+# CONFIG_SND_SOC_INTEL_BXT_RT298_MACH is not set
+# CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH is not set
+# CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH is not set
+# CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH is not set
+# CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH is not set
+# CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH is not set
+# CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH is not set
+# CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH is not set
+# CONFIG_SND_SOC_INTEL_CFL is not set
+# CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH is not set
+# CONFIG_SND_SOC_INTEL_CHT_BSW_NAU8824_MACH is not set
+# CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH is not set
+# CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH is not set
+# CONFIG_SND_SOC_INTEL_CML_H is not set
+# CONFIG_SND_SOC_INTEL_CML_LP is not set
+# CONFIG_SND_SOC_INTEL_CNL is not set
+# CONFIG_SND_SOC_INTEL_GLK is not set
+# CONFIG_SND_SOC_INTEL_HASWELL is not set
+# CONFIG_SND_SOC_INTEL_KBL is not set
+# CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH is not set
+# CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH is not set
+# CONFIG_SND_SOC_INTEL_SKL is not set
+# CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH is not set
+# CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH is not set
+# CONFIG_SND_SOC_INTEL_SKL_RT286_MACH is not set
+# CONFIG_SND_SOC_INTEL_SKYLAKE is not set
+# CONFIG_SND_SOC_INTEL_SST is not set
+CONFIG_SND_SOC_INTEL_SST_TOPLEVEL=y
+# CONFIG_SND_SOC_JZ4725B_CODEC is not set
+# CONFIG_SND_SOC_JZ4740_CODEC is not set
+# CONFIG_SND_SOC_MA120X0P is not set
+# CONFIG_SND_SOC_MAX9759 is not set
+# CONFIG_SND_SOC_MAX98088 is not set
+# CONFIG_SND_SOC_MAX98357A is not set
+# CONFIG_SND_SOC_MAX98373 is not set
+# CONFIG_SND_SOC_MAX98504 is not set
+# CONFIG_SND_SOC_MAX9860 is not set
+# CONFIG_SND_SOC_MAX9867 is not set
+# CONFIG_SND_SOC_MAX98927 is not set
+# CONFIG_SND_SOC_MEDIATEK is not set
+# CONFIG_SND_SOC_MPC5200_AC97 is not set
+# CONFIG_SND_SOC_MPC5200_I2S is not set
+# CONFIG_SND_SOC_MSM8916_WCD_ANALOG is not set
+# CONFIG_SND_SOC_MSM8916_WCD_DIGITAL is not set
+# CONFIG_SND_SOC_MT2701 is not set
+# CONFIG_SND_SOC_MT6351 is not set
+# CONFIG_SND_SOC_MT6358 is not set
+# CONFIG_SND_SOC_MT8173 is not set
+# CONFIG_SND_SOC_MTK_BTCVSD is not set
+# CONFIG_SND_SOC_NAU8540 is not set
+# CONFIG_SND_SOC_NAU8810 is not set
+# CONFIG_SND_SOC_NAU8822 is not set
+# CONFIG_SND_SOC_NAU8824 is not set
+# CONFIG_SND_SOC_PCM1681 is not set
+# CONFIG_SND_SOC_PCM1789_I2C is not set
+# CONFIG_SND_SOC_PCM1792A is not set
+# CONFIG_SND_SOC_PCM179X_I2C is not set
+# CONFIG_SND_SOC_PCM179X_SPI is not set
+# CONFIG_SND_SOC_PCM186X_I2C is not set
+# CONFIG_SND_SOC_PCM186X_SPI is not set
+# CONFIG_SND_SOC_PCM3060_I2C is not set
+# CONFIG_SND_SOC_PCM3060_SPI is not set
+# CONFIG_SND_SOC_PCM3168A_I2C is not set
+# CONFIG_SND_SOC_PCM3168A_SPI is not set
+# CONFIG_SND_SOC_PCM512x_I2C is not set
+# CONFIG_SND_SOC_PCM512x_SPI is not set
+# CONFIG_SND_SOC_QCOM is not set
+# CONFIG_SND_SOC_RK3328 is not set
+# CONFIG_SND_SOC_RT5616 is not set
+# CONFIG_SND_SOC_RT5631 is not set
+# CONFIG_SND_SOC_RT5677_SPI is not set
+# CONFIG_SND_SOC_SGTL5000 is not set
+# CONFIG_SND_SOC_SIMPLE_AMPLIFIER is not set
+# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set
+# CONFIG_SND_SOC_SOF_TOPLEVEL is not set
+# CONFIG_SND_SOC_SPDIF is not set
+# CONFIG_SND_SOC_SSM2305 is not set
+# CONFIG_SND_SOC_SSM2602_I2C is not set
+# CONFIG_SND_SOC_SSM2602_SPI is not set
+# CONFIG_SND_SOC_SSM4567 is not set
+# CONFIG_SND_SOC_STA32X is not set
+# CONFIG_SND_SOC_STA350 is not set
+# CONFIG_SND_SOC_STI_SAS is not set
+# CONFIG_SND_SOC_TAS2552 is not set
+# CONFIG_SND_SOC_TAS5086 is not set
+# CONFIG_SND_SOC_TAS571X is not set
+# CONFIG_SND_SOC_TAS5720 is not set
+# CONFIG_SND_SOC_TAS6424 is not set
+# CONFIG_SND_SOC_TDA7419 is not set
+# CONFIG_SND_SOC_TFA9879 is not set
+# CONFIG_SND_SOC_TLV320AIC23_I2C is not set
+# CONFIG_SND_SOC_TLV320AIC23_SPI is not set
+# CONFIG_SND_SOC_TLV320AIC31XX is not set
+# CONFIG_SND_SOC_TLV320AIC32X4_I2C is not set
+# CONFIG_SND_SOC_TLV320AIC32X4_SPI is not set
+# CONFIG_SND_SOC_TLV320AIC3X is not set
+# CONFIG_SND_SOC_TPA6130A2 is not set
+# CONFIG_SND_SOC_TS3A227E is not set
+# CONFIG_SND_SOC_TSCS42XX is not set
+# CONFIG_SND_SOC_TSCS454 is not set
+# CONFIG_SND_SOC_UDA1334 is not set
+# CONFIG_SND_SOC_WM8510 is not set
+# CONFIG_SND_SOC_WM8523 is not set
+# CONFIG_SND_SOC_WM8524 is not set
+# CONFIG_SND_SOC_WM8580 is not set
+# CONFIG_SND_SOC_WM8711 is not set
+# CONFIG_SND_SOC_WM8728 is not set
+# CONFIG_SND_SOC_WM8731 is not set
+# CONFIG_SND_SOC_WM8737 is not set
+# CONFIG_SND_SOC_WM8741 is not set
+# CONFIG_SND_SOC_WM8750 is not set
+# CONFIG_SND_SOC_WM8753 is not set
+# CONFIG_SND_SOC_WM8770 is not set
+# CONFIG_SND_SOC_WM8776 is not set
+# CONFIG_SND_SOC_WM8782 is not set
+# CONFIG_SND_SOC_WM8804_I2C is not set
+# CONFIG_SND_SOC_WM8804_SPI is not set
+# CONFIG_SND_SOC_WM8903 is not set
+# CONFIG_SND_SOC_WM8904 is not set
+# CONFIG_SND_SOC_WM8960 is not set
+# CONFIG_SND_SOC_WM8962 is not set
+# CONFIG_SND_SOC_WM8974 is not set
+# CONFIG_SND_SOC_WM8978 is not set
+# CONFIG_SND_SOC_WM8985 is not set
+# CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER is not set
+# CONFIG_SND_SOC_XILINX_I2S is not set
+# CONFIG_SND_SOC_XILINX_SPDIF is not set
+# CONFIG_SND_SOC_XTFPGA_I2S is not set
+# CONFIG_SND_SOC_ZX_AUD96P22 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_SPI is not set
+# CONFIG_SND_SSCAPE is not set
+# CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI is not set
+# CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_PCI is not set
+# CONFIG_SND_SUN4I_CODEC is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_TIMER is not set
+# CONFIG_SND_TRIDENT is not set
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_6FIRE is not set
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+# CONFIG_SND_USB_HIFACE is not set
+# CONFIG_SND_USB_POD is not set
+# CONFIG_SND_USB_PODHD is not set
+# CONFIG_SND_USB_TONEPORT is not set
+# CONFIG_SND_USB_UA101 is not set
+# CONFIG_SND_USB_US122L is not set
+# CONFIG_SND_USB_USX2Y is not set
+# CONFIG_SND_USB_VARIAX is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VIRTUOSO is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_VXPOCKET is not set
+# CONFIG_SND_WAVEFRONT is not set
+CONFIG_SND_X86=y
+# CONFIG_SND_XEN_FRONTEND is not set
+# CONFIG_SND_YMFPCI is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_SOCIONEXT_SYNQUACER_PREITS is not set
+# CONFIG_SOCK_CGROUP_DATA is not set
+# CONFIG_SOC_AM33XX is not set
+# CONFIG_SOC_AM43XX is not set
+# CONFIG_SOC_BRCMSTB is not set
+# CONFIG_SOC_CAMERA is not set
+# CONFIG_SOC_DRA7XX is not set
+# CONFIG_SOC_HAS_OMAP2_SDRC is not set
+# CONFIG_SOC_OMAP5 is not set
+# CONFIG_SOC_TI is not set
+# CONFIG_SOFTLOCKUP_DETECTOR is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_SONYPI is not set
+# CONFIG_SONY_LAPTOP is not set
+# CONFIG_SOUND is not set
+# CONFIG_SOUNDWIRE is not set
+# CONFIG_SOUND_OSS_CORE is not set
+# CONFIG_SOUND_OSS_CORE_PRECLAIM is not set
+# CONFIG_SOUND_PRIME is not set
+# CONFIG_SP5100_TCO is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+# CONFIG_SPARSE_IRQ is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_SPEAKUP is not set
+# CONFIG_SPI is not set
+# CONFIG_SPINLOCK_TEST is not set
+# CONFIG_SPI_ALTERA is not set
+# CONFIG_SPI_AU1550 is not set
+# CONFIG_SPI_AXI_SPI_ENGINE is not set
+# CONFIG_SPI_BCM2835 is not set
+# CONFIG_SPI_BCM_QSPI is not set
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_BUTTERFLY is not set
+# CONFIG_SPI_CADENCE is not set
+# CONFIG_SPI_CADENCE_QUADSPI is not set
+# CONFIG_SPI_DEBUG is not set
+# CONFIG_SPI_DESIGNWARE is not set
+# CONFIG_SPI_FSL_DSPI is not set
+# CONFIG_SPI_FSL_ESPI is not set
+# CONFIG_SPI_FSL_SPI is not set
+# CONFIG_SPI_GPIO is not set
+# CONFIG_SPI_GPIO_OLD is not set
+# CONFIG_SPI_IMG_SPFI is not set
+# CONFIG_SPI_LM70_LLP is not set
+# CONFIG_SPI_LOOPBACK_TEST is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_SPI_MEM is not set
+# CONFIG_SPI_MPC52xx is not set
+# CONFIG_SPI_MPC52xx_PSC is not set
+# CONFIG_SPI_MTK_QUADSPI is not set
+# CONFIG_SPI_MXIC is not set
+# CONFIG_SPI_NXP_FLEXSPI is not set
+# CONFIG_SPI_OCTEON is not set
+# CONFIG_SPI_OC_TINY is not set
+# CONFIG_SPI_ORION is not set
+# CONFIG_SPI_PL022 is not set
+# CONFIG_SPI_PPC4xx is not set
+# CONFIG_SPI_PXA2XX is not set
+# CONFIG_SPI_PXA2XX_PCI is not set
+# CONFIG_SPI_QCOM_QSPI is not set
+# CONFIG_SPI_ROCKCHIP is not set
+# CONFIG_SPI_S3C64XX is not set
+# CONFIG_SPI_SC18IS602 is not set
+# CONFIG_SPI_SIFIVE is not set
+# CONFIG_SPI_SLAVE is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_THUNDERX is not set
+# CONFIG_SPI_TI_QSPI is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_SPI_TOPCLIFF_PCH is not set
+# CONFIG_SPI_XCOMM is not set
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_XWAY is not set
+# CONFIG_SPI_ZYNQMP_GQSPI is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_SPMI is not set
+# CONFIG_SPS30 is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
+# CONFIG_SQUASHFS_DECOMP_MULTI is not set
+CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y
+# CONFIG_SQUASHFS_DECOMP_SINGLE is not set
+CONFIG_SQUASHFS_EMBEDDED=y
+# CONFIG_SQUASHFS_FILE_CACHE is not set
+CONFIG_SQUASHFS_FILE_DIRECT=y
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_SQUASHFS_LZ4 is not set
+# CONFIG_SQUASHFS_LZO is not set
+# CONFIG_SQUASHFS_XATTR is not set
+CONFIG_SQUASHFS_XZ=y
+# CONFIG_SQUASHFS_ZLIB is not set
+# CONFIG_SQUASHFS_ZSTD is not set
+# CONFIG_SRAM is not set
+# CONFIG_SRF04 is not set
+# CONFIG_SRF08 is not set
+# CONFIG_SSB is not set
+# CONFIG_SSB_DEBUG is not set
+# CONFIG_SSB_DRIVER_GPIO is not set
+# CONFIG_SSB_HOST_SOC is not set
+# CONFIG_SSB_PCMCIAHOST is not set
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB_SDIOHOST is not set
+# CONFIG_SSB_SILENT is not set
+# CONFIG_SSFDC is not set
+# CONFIG_STACKPROTECTOR is not set
+# CONFIG_STACKPROTECTOR_STRONG is not set
+# CONFIG_STACKTRACE is not set
+CONFIG_STACKTRACE_SUPPORT=y
+# CONFIG_STACK_TRACER is not set
+# CONFIG_STACK_VALIDATION is not set
+CONFIG_STAGING=y
+# CONFIG_STAGING_BOARD is not set
+# CONFIG_STAGING_GASKET_FRAMEWORK is not set
+# CONFIG_STAGING_MEDIA is not set
+CONFIG_STANDALONE=y
+# CONFIG_STATIC_KEYS_SELFTEST is not set
+# CONFIG_STATIC_USERMODEHELPER is not set
+CONFIG_STDBINUTILS=y
+# CONFIG_STE10XP is not set
+# CONFIG_STE_MODEM_RPROC is not set
+# CONFIG_STK3310 is not set
+# CONFIG_STK8312 is not set
+# CONFIG_STK8BA50 is not set
+# CONFIG_STM is not set
+# CONFIG_STMMAC_ETH is not set
+# CONFIG_STMMAC_PCI is not set
+# CONFIG_STMMAC_PLATFORM is not set
+# CONFIG_STM_DUMMY is not set
+# CONFIG_STM_SOURCE_CONSOLE is not set
+CONFIG_STP=y
+# CONFIG_STREAM_PARSER is not set
+# CONFIG_STRICT_DEVMEM is not set
+CONFIG_STRICT_KERNEL_RWX=y
+CONFIG_STRICT_MODULE_RWX=y
+# CONFIG_STRING_SELFTEST is not set
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_STX104 is not set
+# CONFIG_ST_UVIS25 is not set
+# CONFIG_SUN4I_GPADC is not set
+# CONFIG_SUN50I_DE2_BUS is not set
+# CONFIG_SUN50I_ERRATUM_UNKNOWN1 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_SUNRPC is not set
+# CONFIG_SUNRPC_DEBUG is not set
+CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES=y
+# CONFIG_SUNRPC_GSS is not set
+# CONFIG_SUNXI_SRAM is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_SURFACE_3_BUTTON is not set
+# CONFIG_SUSPEND is not set
+# CONFIG_SUSPEND_SKIP_SYNC is not set
+CONFIG_SWAP=y
+# CONFIG_SWCONFIG is not set
+# CONFIG_SWCONFIG_B53 is not set
+# CONFIG_SWCONFIG_B53_MDIO_DRIVER is not set
+# CONFIG_SWCONFIG_B53_MMAP_DRIVER is not set
+# CONFIG_SWCONFIG_B53_SPI_DRIVER is not set
+# CONFIG_SWCONFIG_B53_SRAB_DRIVER is not set
+# CONFIG_SWCONFIG_LEDS is not set
+# CONFIG_SW_SYNC is not set
+# CONFIG_SX9500 is not set
+# CONFIG_SXGBE_ETH is not set
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_SYNC_FILE is not set
+# CONFIG_SYNOPSYS_DWC_ETH_QOS is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_SYSCON_REBOOT_MODE is not set
+CONFIG_SYSCTL=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_SYSFS=y
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_SYSFS_SYSCALL is not set
+# CONFIG_SYSTEMPORT is not set
+# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set
+# CONFIG_SYSTEM_DATA_VERIFICATION is not set
+# CONFIG_SYSTEM_TRUSTED_KEYRING is not set
+CONFIG_SYSTEM_TRUSTED_KEYS=""
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_T5403 is not set
+# CONFIG_TARGET_CORE is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_TASKS_RCU is not set
+# CONFIG_TASK_XACCT is not set
+# CONFIG_TC35815 is not set
+# CONFIG_TCG_ATMEL is not set
+# CONFIG_TCG_CRB is not set
+# CONFIG_TCG_FTPM_TEE is not set
+# CONFIG_TCG_INFINEON is not set
+# CONFIG_TCG_NSC is not set
+# CONFIG_TCG_ST33_I2C is not set
+# CONFIG_TCG_TIS is not set
+# CONFIG_TCG_TIS_I2C_ATMEL is not set
+# CONFIG_TCG_TIS_I2C_INFINEON is not set
+# CONFIG_TCG_TIS_I2C_NUVOTON is not set
+# CONFIG_TCG_TIS_SPI is not set
+# CONFIG_TCG_TIS_ST33ZP24_I2C is not set
+# CONFIG_TCG_TIS_ST33ZP24_SPI is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_TCG_VTPM_PROXY is not set
+# CONFIG_TCG_XEN is not set
+# CONFIG_TCIC is not set
+CONFIG_TCP_CONG_ADVANCED=y
+# CONFIG_TCP_CONG_BBR is not set
+# CONFIG_TCP_CONG_BIC is not set
+# CONFIG_TCP_CONG_CDG is not set
+CONFIG_TCP_CONG_CUBIC=y
+# CONFIG_TCP_CONG_DCTCP is not set
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_ILLINOIS is not set
+# CONFIG_TCP_CONG_LP is not set
+# CONFIG_TCP_CONG_NV is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_VENO is not set
+# CONFIG_TCP_CONG_WESTWOOD is not set
+# CONFIG_TCP_CONG_YEAH is not set
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_TCS3414 is not set
+# CONFIG_TCS3472 is not set
+# CONFIG_TEE is not set
+# CONFIG_TEGRA_AHB is not set
+# CONFIG_TEGRA_HOST1X is not set
+# CONFIG_TEHUTI is not set
+# CONFIG_TERANETICS_PHY is not set
+# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set
+# CONFIG_TEST_BITFIELD is not set
+# CONFIG_TEST_BITMAP is not set
+# CONFIG_TEST_BLACKHOLE_DEV is not set
+# CONFIG_TEST_BPF is not set
+# CONFIG_TEST_FIRMWARE is not set
+# CONFIG_TEST_HASH is not set
+# CONFIG_TEST_HEXDUMP is not set
+# CONFIG_TEST_IDA is not set
+# CONFIG_TEST_KMOD is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_TEST_LKM is not set
+# CONFIG_TEST_MEMCAT_P is not set
+# CONFIG_TEST_MEMINIT is not set
+# CONFIG_TEST_OVERFLOW is not set
+# CONFIG_TEST_POWER is not set
+# CONFIG_TEST_PRINTF is not set
+# CONFIG_TEST_RHASHTABLE is not set
+# CONFIG_TEST_SORT is not set
+# CONFIG_TEST_STACKINIT is not set
+# CONFIG_TEST_STATIC_KEYS is not set
+# CONFIG_TEST_STRING_HELPERS is not set
+# CONFIG_TEST_STRSCPY is not set
+# CONFIG_TEST_SYSCTL is not set
+# CONFIG_TEST_UDELAY is not set
+# CONFIG_TEST_USER_COPY is not set
+# CONFIG_TEST_UUID is not set
+# CONFIG_TEST_VMALLOC is not set
+# CONFIG_TEST_XARRAY is not set
+CONFIG_TEXTSEARCH=y
+# CONFIG_TEXTSEARCH_BM is not set
+# CONFIG_TEXTSEARCH_FSM is not set
+# CONFIG_TEXTSEARCH_KMP is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
+# CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR is not set
+# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
+# CONFIG_THERMAL_EMULATION is not set
+# CONFIG_THERMAL_GOV_BANG_BANG is not set
+# CONFIG_THERMAL_GOV_FAIR_SHARE is not set
+# CONFIG_THERMAL_GOV_POWER_ALLOCATOR is not set
+# CONFIG_THERMAL_GOV_USER_SPACE is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_THERMAL_MMIO is not set
+# CONFIG_THERMAL_STATISTICS is not set
+# CONFIG_THERMAL_WRITABLE_TRIPS is not set
+# CONFIG_THINKPAD_ACPI is not set
+CONFIG_THIN_ARCHIVES=y
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_THUMB2_KERNEL is not set
+# CONFIG_THUNDERBOLT is not set
+# CONFIG_THUNDER_NIC_BGX is not set
+# CONFIG_THUNDER_NIC_PF is not set
+# CONFIG_THUNDER_NIC_RGX is not set
+# CONFIG_THUNDER_NIC_VF is not set
+# CONFIG_TICK_CPU_ACCOUNTING is not set
+CONFIG_TICK_ONESHOT=y
+# CONFIG_TIFM_CORE is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_TIMB_DMA is not set
+CONFIG_TIMERFD=y
+# CONFIG_TIMER_STATS is not set
+# CONFIG_TINYDRM_HX8357D is not set
+# CONFIG_TINYDRM_ILI9225 is not set
+# CONFIG_TINYDRM_ILI9341 is not set
+# CONFIG_TINYDRM_MI0283QT is not set
+# CONFIG_TINYDRM_REPAPER is not set
+# CONFIG_TINYDRM_ST7586 is not set
+# CONFIG_TINYDRM_ST7735R is not set
+CONFIG_TINY_RCU=y
+# CONFIG_TIPC is not set
+# CONFIG_TI_ADC081C is not set
+# CONFIG_TI_ADC0832 is not set
+# CONFIG_TI_ADC084S021 is not set
+# CONFIG_TI_ADC108S102 is not set
+# CONFIG_TI_ADC12138 is not set
+# CONFIG_TI_ADC128S052 is not set
+# CONFIG_TI_ADC161S626 is not set
+# CONFIG_TI_ADS1015 is not set
+# CONFIG_TI_ADS124S08 is not set
+# CONFIG_TI_ADS7950 is not set
+# CONFIG_TI_ADS8344 is not set
+# CONFIG_TI_ADS8688 is not set
+# CONFIG_TI_AM335X_ADC is not set
+# CONFIG_TI_CPSW is not set
+# CONFIG_TI_CPSW_ALE is not set
+# CONFIG_TI_CPSW_PHY_SEL is not set
+# CONFIG_TI_CPTS is not set
+# CONFIG_TI_DAC082S085 is not set
+# CONFIG_TI_DAC5571 is not set
+# CONFIG_TI_DAC7311 is not set
+# CONFIG_TI_DAC7512 is not set
+# CONFIG_TI_DAC7612 is not set
+# CONFIG_TI_DAVINCI_CPDMA is not set
+# CONFIG_TI_DAVINCI_MDIO is not set
+# CONFIG_TI_ST is not set
+# CONFIG_TI_SYSCON_RESET is not set
+# CONFIG_TI_TLC4541 is not set
+# CONFIG_TLAN is not set
+# CONFIG_TLS is not set
+# CONFIG_TMD_HERMES is not set
+# CONFIG_TMP006 is not set
+# CONFIG_TMP007 is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_TMPFS_XATTR=y
+# CONFIG_TOPSTAR_LAPTOP is not set
+# CONFIG_TORTURE_TEST is not set
+# CONFIG_TOSHIBA_HAPS is not set
+# CONFIG_TOUCHSCREEN_88PM860X is not set
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
+# CONFIG_TOUCHSCREEN_ADC is not set
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_AR1021_I2C is not set
+# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set
+# CONFIG_TOUCHSCREEN_ATMEL_MXT_T37 is not set
+# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set
+# CONFIG_TOUCHSCREEN_BU21013 is not set
+# CONFIG_TOUCHSCREEN_BU21029 is not set
+# CONFIG_TOUCHSCREEN_CHIPONE_ICN8318 is not set
+# CONFIG_TOUCHSCREEN_CHIPONE_ICN8505 is not set
+# CONFIG_TOUCHSCREEN_COLIBRI_VF50 is not set
+# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set
+# CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set
+# CONFIG_TOUCHSCREEN_CYTTSP4_I2C is not set
+# CONFIG_TOUCHSCREEN_CYTTSP4_SPI is not set
+# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set
+# CONFIG_TOUCHSCREEN_CYTTSP_I2C is not set
+# CONFIG_TOUCHSCREEN_CYTTSP_SPI is not set
+# CONFIG_TOUCHSCREEN_DA9034 is not set
+# CONFIG_TOUCHSCREEN_DA9052 is not set
+# CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# CONFIG_TOUCHSCREEN_EGALAX is not set
+# CONFIG_TOUCHSCREEN_EGALAX_SERIAL is not set
+# CONFIG_TOUCHSCREEN_EKTF2127 is not set
+# CONFIG_TOUCHSCREEN_ELAN is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_EXC3000 is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GOODIX is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
+# CONFIG_TOUCHSCREEN_HIDEEP is not set
+# CONFIG_TOUCHSCREEN_HP600 is not set
+# CONFIG_TOUCHSCREEN_HP7XX is not set
+# CONFIG_TOUCHSCREEN_HTCPEN is not set
+# CONFIG_TOUCHSCREEN_ILI210X is not set
+# CONFIG_TOUCHSCREEN_IMX6UL_TSC is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_IPAQ_MICRO is not set
+# CONFIG_TOUCHSCREEN_IPROC is not set
+# CONFIG_TOUCHSCREEN_IQS5XX is not set
+# CONFIG_TOUCHSCREEN_LPC32XX is not set
+# CONFIG_TOUCHSCREEN_MAX11801 is not set
+# CONFIG_TOUCHSCREEN_MC13783 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
+# CONFIG_TOUCHSCREEN_MELFAS_MIP4 is not set
+# CONFIG_TOUCHSCREEN_MIGOR is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_MMS114 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MX25 is not set
+# CONFIG_TOUCHSCREEN_MXS_LRADC is not set
+# CONFIG_TOUCHSCREEN_PCAP is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_PIXCIR is not set
+# CONFIG_TOUCHSCREEN_PROPERTIES is not set
+# CONFIG_TOUCHSCREEN_RASPBERRYPI_FW is not set
+# CONFIG_TOUCHSCREEN_RM_TS is not set
+# CONFIG_TOUCHSCREEN_ROHM_BU21023 is not set
+# CONFIG_TOUCHSCREEN_RPI_FT5406 is not set
+# CONFIG_TOUCHSCREEN_S3C2410 is not set
+# CONFIG_TOUCHSCREEN_S6SY761 is not set
+# CONFIG_TOUCHSCREEN_SILEAD is not set
+# CONFIG_TOUCHSCREEN_SIS_I2C is not set
+# CONFIG_TOUCHSCREEN_ST1232 is not set
+# CONFIG_TOUCHSCREEN_STMFTS is not set
+# CONFIG_TOUCHSCREEN_STMPE is not set
+# CONFIG_TOUCHSCREEN_SUN4I is not set
+# CONFIG_TOUCHSCREEN_SUR40 is not set
+# CONFIG_TOUCHSCREEN_SURFACE3_SPI is not set
+# CONFIG_TOUCHSCREEN_SX8654 is not set
+# CONFIG_TOUCHSCREEN_TI_AM335X_TSC is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_TPS6507X is not set
+# CONFIG_TOUCHSCREEN_TS4800 is not set
+# CONFIG_TOUCHSCREEN_TSC2004 is not set
+# CONFIG_TOUCHSCREEN_TSC2005 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_TSC2007_IIO is not set
+# CONFIG_TOUCHSCREEN_TSC200X_CORE is not set
+# CONFIG_TOUCHSCREEN_TSC_SERIO is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_USB_3M is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_USB_DMC_TSC10 is not set
+# CONFIG_TOUCHSCREEN_USB_E2I is not set
+# CONFIG_TOUCHSCREEN_USB_EASYTOUCH is not set
+# CONFIG_TOUCHSCREEN_USB_EGALAX is not set
+# CONFIG_TOUCHSCREEN_USB_ELO is not set
+# CONFIG_TOUCHSCREEN_USB_ETT_TC45USB is not set
+# CONFIG_TOUCHSCREEN_USB_ETURBO is not set
+# CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH is not set
+# CONFIG_TOUCHSCREEN_USB_GOTOP is not set
+# CONFIG_TOUCHSCREEN_USB_GUNZE is not set
+# CONFIG_TOUCHSCREEN_USB_IDEALTEK is not set
+# CONFIG_TOUCHSCREEN_USB_IRTOUCH is not set
+# CONFIG_TOUCHSCREEN_USB_ITM is not set
+# CONFIG_TOUCHSCREEN_USB_JASTEC is not set
+# CONFIG_TOUCHSCREEN_USB_NEXIO is not set
+# CONFIG_TOUCHSCREEN_USB_PANJIT is not set
+# CONFIG_TOUCHSCREEN_USB_ZYTRONIC is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+# CONFIG_TOUCHSCREEN_WACOM_I2C is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_WDT87XX_I2C is not set
+# CONFIG_TOUCHSCREEN_WM831X is not set
+# CONFIG_TOUCHSCREEN_WM9705 is not set
+# CONFIG_TOUCHSCREEN_WM9712 is not set
+# CONFIG_TOUCHSCREEN_WM9713 is not set
+# CONFIG_TOUCHSCREEN_WM97XX is not set
+# CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE is not set
+# CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE is not set
+# CONFIG_TOUCHSCREEN_ZET6223 is not set
+# CONFIG_TOUCHSCREEN_ZFORCE is not set
+# CONFIG_TPL0102 is not set
+# CONFIG_TPS6105X is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TRACEPOINT_BENCHMARK is not set
+# CONFIG_TRACER_SNAPSHOT is not set
+# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_TRACE_EVAL_MAP_FILE is not set
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_TRACE_SINK is not set
+# CONFIG_TRACING_EVENTS_GPIO is not set
+CONFIG_TRACING_SUPPORT=y
+CONFIG_TRAD_SIGNALS=y
+# CONFIG_TRANSPARENT_HUGEPAGE is not set
+# CONFIG_TREE_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_TRIM_UNUSED_KSYMS is not set
+# CONFIG_TRUSTED_FOUNDATIONS is not set
+# CONFIG_TRUSTED_KEYS is not set
+# CONFIG_TSL2583 is not set
+# CONFIG_TSL2772 is not set
+# CONFIG_TSL2x7x is not set
+# CONFIG_TSL4531 is not set
+# CONFIG_TSYS01 is not set
+# CONFIG_TSYS02D is not set
+# CONFIG_TTPCI_EEPROM is not set
+CONFIG_TTY=y
+# CONFIG_TTY_PRINTK is not set
+# CONFIG_TUN is not set
+# CONFIG_TUN_VNET_CROSS_LE is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_TWL4030_MADC is not set
+# CONFIG_TWL6030_GPADC is not set
+# CONFIG_TWL6040_CORE is not set
+# CONFIG_TYPEC is not set
+# CONFIG_TYPEC_TCPM is not set
+# CONFIG_TYPEC_UCSI is not set
+# CONFIG_TYPHOON is not set
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+# CONFIG_UBIFS_ATIME_SUPPORT is not set
+# CONFIG_UBIFS_FS_AUTHENTICATION is not set
+# CONFIG_UBIFS_FS_ENCRYPTION is not set
+# CONFIG_UBIFS_FS_SECURITY is not set
+# CONFIG_UBIFS_FS_ZLIB is not set
+# CONFIG_UBIFS_FS_ZSTD is not set
+CONFIG_UBIFS_FS_XATTR=y
+# CONFIG_UBSAN is not set
+CONFIG_UBSAN_ALIGNMENT=y
+# CONFIG_UCB1400_CORE is not set
+# CONFIG_UCSI is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDMABUF is not set
+CONFIG_UEVENT_HELPER=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_UFS_FS is not set
+# CONFIG_UHID is not set
+CONFIG_UID16=y
+# CONFIG_UIO is not set
+# CONFIG_ULTRA is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_UNICODE is not set
+# CONFIG_UNISYSSPAR is not set
+# CONFIG_UNISYS_VISORBUS is not set
+CONFIG_UNIX=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_UNIX_DIAG is not set
+CONFIG_UNIX_SCM=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_UNWINDER_FRAME_POINTER is not set
+# CONFIG_UPROBES is not set
+# CONFIG_UPROBE_EVENTS is not set
+# CONFIG_US5182D is not set
+# CONFIG_USB is not set
+# CONFIG_USBIP_CORE is not set
+CONFIG_USBIP_VHCI_HC_PORTS=8
+CONFIG_USBIP_VHCI_NR_HCS=1
+# CONFIG_USBIP_VUDC is not set
+# CONFIG_USBPCWATCHDOG is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_ADUTUX is not set
+CONFIG_USB_ALI_M5632=y
+# CONFIG_USB_AMD5536UDC is not set
+CONFIG_USB_AN2720=y
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_ATM is not set
+CONFIG_USB_AUTOSUSPEND_DELAY=2
+# CONFIG_USB_BDC_UDC is not set
+CONFIG_USB_BELKIN=y
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+# CONFIG_USB_CDNS3 is not set
+# CONFIG_USB_CHAOSKEY is not set
+# CONFIG_USB_CHIPIDEA is not set
+# CONFIG_USB_CONFIGFS is not set
+# CONFIG_USB_CONN_GPIO is not set
+# CONFIG_USB_CXACRU is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+CONFIG_USB_DEFAULT_PERSIST=y
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DUMMY_HCD is not set
+# CONFIG_USB_DWC2 is not set
+# CONFIG_USB_DWC2_DEBUG is not set
+# CONFIG_USB_DWC2_DUAL_ROLE is not set
+# CONFIG_USB_DWC2_HOST is not set
+# CONFIG_USB_DWC2_PERIPHERAL is not set
+# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set
+# CONFIG_USB_DWC3 is not set
+# CONFIG_USB_DWC3_EXYNOS is not set
+# CONFIG_USB_DWC3_HAPS is not set
+# CONFIG_USB_DWC3_KEYSTONE is not set
+# CONFIG_USB_DWC3_OF_SIMPLE is not set
+# CONFIG_USB_DWC3_PCI is not set
+# CONFIG_USB_DWC3_QCOM is not set
+# CONFIG_USB_DWC3_ULPI is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_EG20T is not set
+# CONFIG_USB_EHCI_ATH79 is not set
+# CONFIG_USB_EHCI_FSL is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_EHCI_HCD_AT91 is not set
+# CONFIG_USB_EHCI_HCD_OMAP is not set
+# CONFIG_USB_EHCI_HCD_PPC_OF is not set
+# CONFIG_USB_EHCI_MSM is not set
+# CONFIG_USB_EHCI_MV is not set
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+# CONFIG_USB_EHSET_TEST_FIXTURE is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_EZUSB_FX2 is not set
+# CONFIG_USB_FOTG210_HCD is not set
+# CONFIG_USB_FOTG210_UDC is not set
+# CONFIG_USB_FSL_USB2 is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_FUNCTIONFS is not set
+# CONFIG_USB_FUSB300 is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
+CONFIG_USB_GADGET_VBUS_DRAW=2
+# CONFIG_USB_GADGET_XILINX is not set
+# CONFIG_USB_GL860 is not set
+# CONFIG_USB_GOKU is not set
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_USB_GR_UDC is not set
+# CONFIG_USB_GSPCA is not set
+# CONFIG_USB_GSPCA_BENQ is not set
+# CONFIG_USB_GSPCA_CONEX is not set
+# CONFIG_USB_GSPCA_CPIA1 is not set
+# CONFIG_USB_GSPCA_DTCS033 is not set
+# CONFIG_USB_GSPCA_ETOMS is not set
+# CONFIG_USB_GSPCA_FINEPIX is not set
+# CONFIG_USB_GSPCA_JEILINJ is not set
+# CONFIG_USB_GSPCA_JL2005BCD is not set
+# CONFIG_USB_GSPCA_KINECT is not set
+# CONFIG_USB_GSPCA_KONICA is not set
+# CONFIG_USB_GSPCA_MARS is not set
+# CONFIG_USB_GSPCA_MR97310A is not set
+# CONFIG_USB_GSPCA_NW80X is not set
+# CONFIG_USB_GSPCA_OV519 is not set
+# CONFIG_USB_GSPCA_OV534 is not set
+# CONFIG_USB_GSPCA_OV534_9 is not set
+# CONFIG_USB_GSPCA_PAC207 is not set
+# CONFIG_USB_GSPCA_PAC7302 is not set
+# CONFIG_USB_GSPCA_PAC7311 is not set
+# CONFIG_USB_GSPCA_SE401 is not set
+# CONFIG_USB_GSPCA_SN9C2028 is not set
+# CONFIG_USB_GSPCA_SN9C20X is not set
+# CONFIG_USB_GSPCA_SONIXB is not set
+# CONFIG_USB_GSPCA_SONIXJ is not set
+# CONFIG_USB_GSPCA_SPCA1528 is not set
+# CONFIG_USB_GSPCA_SPCA500 is not set
+# CONFIG_USB_GSPCA_SPCA501 is not set
+# CONFIG_USB_GSPCA_SPCA505 is not set
+# CONFIG_USB_GSPCA_SPCA506 is not set
+# CONFIG_USB_GSPCA_SPCA508 is not set
+# CONFIG_USB_GSPCA_SPCA561 is not set
+# CONFIG_USB_GSPCA_SQ905 is not set
+# CONFIG_USB_GSPCA_SQ905C is not set
+# CONFIG_USB_GSPCA_SQ930X is not set
+# CONFIG_USB_GSPCA_STK014 is not set
+# CONFIG_USB_GSPCA_STK1135 is not set
+# CONFIG_USB_GSPCA_STV0680 is not set
+# CONFIG_USB_GSPCA_SUNPLUS is not set
+# CONFIG_USB_GSPCA_T613 is not set
+# CONFIG_USB_GSPCA_TOPRO is not set
+# CONFIG_USB_GSPCA_TOUPTEK is not set
+# CONFIG_USB_GSPCA_TV8532 is not set
+# CONFIG_USB_GSPCA_VC032X is not set
+# CONFIG_USB_GSPCA_VICAM is not set
+# CONFIG_USB_GSPCA_XIRLINK_CIT is not set
+# CONFIG_USB_GSPCA_ZC3XX is not set
+# CONFIG_USB_G_ACM_MS is not set
+# CONFIG_USB_G_DBGP is not set
+# CONFIG_USB_G_HID is not set
+# CONFIG_USB_G_MULTI is not set
+# CONFIG_USB_G_NCM is not set
+# CONFIG_USB_G_NOKIA is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_G_WEBCAM is not set
+# CONFIG_USB_HCD_TEST_MODE is not set
+# CONFIG_USB_HID is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_HSIC_USB3503 is not set
+# CONFIG_USB_HSIC_USB4604 is not set
+# CONFIG_USB_HSO is not set
+# CONFIG_USB_HUB_USB251XB is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_IMX21_HCD is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_IPHETH is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1301 is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_ISP1760 is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_KC2190 is not set
+# CONFIG_USB_LAN78XX is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set
+# CONFIG_USB_LED_TRIG is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LINK_LAYER_TEST is not set
+# CONFIG_USB_M5602 is not set
+# CONFIG_USB_M66592 is not set
+# CONFIG_USB_MASS_STORAGE is not set
+# CONFIG_USB_MAX3421_HCD is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_MSM_OTG is not set
+# CONFIG_USB_MTU3 is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_MV_U3D is not set
+# CONFIG_USB_MV_UDC is not set
+# CONFIG_USB_MXS_PHY is not set
+# CONFIG_USB_NET2272 is not set
+# CONFIG_USB_NET2280 is not set
+# CONFIG_USB_NET_AQC111 is not set
+# CONFIG_USB_NET_AX88179_178A is not set
+# CONFIG_USB_NET_AX8817X is not set
+# CONFIG_USB_NET_CDCETHER is not set
+# CONFIG_USB_NET_CDC_EEM is not set
+# CONFIG_USB_NET_CDC_MBIM is not set
+# CONFIG_USB_NET_CDC_NCM is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+# CONFIG_USB_NET_CH9200 is not set
+# CONFIG_USB_NET_CX82310_ETH is not set
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_DRIVERS is not set
+# CONFIG_USB_NET_GL620A is not set
+# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_USB_NET_KALMIA is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_QMI_WWAN is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_USB_NET_SMSC75XX is not set
+# CONFIG_USB_NET_SMSC95XX is not set
+# CONFIG_USB_NET_SR9700 is not set
+# CONFIG_USB_NET_SR9800 is not set
+# CONFIG_USB_NET_ZAURUS is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_OHCI_HCD_PCI is not set
+# CONFIG_USB_OHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OHCI_HCD_PPC_OF_BE is not set
+# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
+# CONFIG_USB_OHCI_HCD_SSB is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_OTG_FSM is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_PCI is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_PHY is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_PWC_INPUT_EVDEV is not set
+# CONFIG_USB_PXA27X is not set
+# CONFIG_USB_R8A66597 is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_RCAR_PHY is not set
+# CONFIG_USB_RENESAS_USBHS is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_ROLE_SWITCH is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_RTL8152 is not set
+# CONFIG_USB_S2255 is not set
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
+# CONFIG_USB_SERIAL_CP210X is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_F81232 is not set
+# CONFIG_USB_SERIAL_F8153X is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_IUU is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_METRO is not set
+# CONFIG_USB_SERIAL_MOS7715_PARPORT is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MXUPORT is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_OPTICON is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_QCAUX is not set
+# CONFIG_USB_SERIAL_QT2 is not set
+# CONFIG_USB_SERIAL_QUALCOMM is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+CONFIG_USB_SERIAL_SAFE_PADDED=y
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_SIMPLE is not set
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
+# CONFIG_USB_SERIAL_SSU100 is not set
+# CONFIG_USB_SERIAL_SYMBOL is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_UPD78F0730 is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_WISHBONE is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_XSENS_MT is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_SIERRA_NET is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_SNP_UDC_PLAT is not set
+# CONFIG_USB_SPEEDTOUCH is not set
+# CONFIG_USB_STKWEBCAM is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_ENE_UB6250 is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_REALTEK is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STV06XX is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_USB_SWITCH_FSA9480 is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_TMC is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_UAS is not set
+# CONFIG_USB_UEAGLEATM is not set
+# CONFIG_USB_ULPI is not set
+# CONFIG_USB_ULPI_BUS is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_USS720 is not set
+# CONFIG_USB_VIDEO_CLASS is not set
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
+# CONFIG_USB_VL600 is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_WHCI_HCD is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+# CONFIG_USB_XHCI_DBGCAP is not set
+# CONFIG_USB_XHCI_HCD is not set
+# CONFIG_USB_XHCI_MVEBU is not set
+# CONFIG_USB_XUSBATM is not set
+# CONFIG_USB_YUREX is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_ZR364XX is not set
+# CONFIG_USELIB is not set
+# CONFIG_USERFAULTFD is not set
+# CONFIG_USE_OF is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_UWB is not set
+# CONFIG_U_SERIAL_CONSOLE is not set
+# CONFIG_V4L_MEM2MEM_DRIVERS is not set
+# CONFIG_V4L_TEST_DRIVERS is not set
+# CONFIG_VALIDATE_FS_PARSER is not set
+# CONFIG_VBOXGUEST is not set
+# CONFIG_VCNL4000 is not set
+# CONFIG_VCNL4035 is not set
+CONFIG_VDSO=y
+# CONFIG_VEML6070 is not set
+# CONFIG_VETH is not set
+# CONFIG_VEXPRESS_CONFIG is not set
+# CONFIG_VF610_ADC is not set
+# CONFIG_VF610_DAC is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_VFIO is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VGA_ARB is not set
+# CONFIG_VGA_SWITCHEROO is not set
+# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set
+# CONFIG_VHOST_NET is not set
+# CONFIG_VHOST_VSOCK is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_VIDEO_ADV7170 is not set
+# CONFIG_VIDEO_ADV7175 is not set
+# CONFIG_VIDEO_ADV7180 is not set
+# CONFIG_VIDEO_ADV7183 is not set
+# CONFIG_VIDEO_ADV7343 is not set
+# CONFIG_VIDEO_ADV7393 is not set
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_AK881X is not set
+# CONFIG_VIDEO_ASPEED is not set
+# CONFIG_VIDEO_BT819 is not set
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_BT856 is not set
+# CONFIG_VIDEO_BT866 is not set
+# CONFIG_VIDEO_CADENCE is not set
+# CONFIG_VIDEO_CAFE_CCIC is not set
+# CONFIG_VIDEO_CS3308 is not set
+# CONFIG_VIDEO_CS5345 is not set
+# CONFIG_VIDEO_CS53L32A is not set
+# CONFIG_VIDEO_CX231XX is not set
+# CONFIG_VIDEO_CX2341X is not set
+# CONFIG_VIDEO_CX25840 is not set
+# CONFIG_VIDEO_CX88 is not set
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_VIDEO_DM6446_CCDC is not set
+# CONFIG_VIDEO_DT3155 is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+# CONFIG_VIDEO_GO7007 is not set
+# CONFIG_VIDEO_HDPVR is not set
+# CONFIG_VIDEO_HEXIUM_GEMINI is not set
+# CONFIG_VIDEO_HEXIUM_ORION is not set
+# CONFIG_VIDEO_I2C is not set
+# CONFIG_VIDEO_IR_I2C is not set
+# CONFIG_VIDEO_IVTV is not set
+# CONFIG_VIDEO_KS0127 is not set
+# CONFIG_VIDEO_M52790 is not set
+# CONFIG_VIDEO_ML86V7667 is not set
+# CONFIG_VIDEO_MSP3400 is not set
+# CONFIG_VIDEO_MT9M111 is not set
+# CONFIG_VIDEO_MT9T112 is not set
+# CONFIG_VIDEO_MT9V011 is not set
+# CONFIG_VIDEO_MT9V111 is not set
+# CONFIG_VIDEO_MXB is not set
+# CONFIG_VIDEO_NOON010PC30 is not set
+# CONFIG_VIDEO_OMAP2_VOUT is not set
+# CONFIG_VIDEO_OV2640 is not set
+# CONFIG_VIDEO_OV2659 is not set
+# CONFIG_VIDEO_OV5695 is not set
+# CONFIG_VIDEO_OV6650 is not set
+# CONFIG_VIDEO_OV7640 is not set
+# CONFIG_VIDEO_OV7670 is not set
+# CONFIG_VIDEO_OV772X is not set
+# CONFIG_VIDEO_OV7740 is not set
+# CONFIG_VIDEO_OV9640 is not set
+# CONFIG_VIDEO_PVRUSB2 is not set
+# CONFIG_VIDEO_RJ54N1 is not set
+# CONFIG_VIDEO_SAA6588 is not set
+# CONFIG_VIDEO_SAA6752HS is not set
+# CONFIG_VIDEO_SAA7110 is not set
+# CONFIG_VIDEO_SAA711X is not set
+# CONFIG_VIDEO_SAA7127 is not set
+# CONFIG_VIDEO_SAA7134 is not set
+# CONFIG_VIDEO_SAA717X is not set
+# CONFIG_VIDEO_SAA7185 is not set
+# CONFIG_VIDEO_SH_MOBILE_CEU is not set
+# CONFIG_VIDEO_SONY_BTF_MPX is not set
+# CONFIG_VIDEO_SR030PC30 is not set
+# CONFIG_VIDEO_TDA7432 is not set
+# CONFIG_VIDEO_TDA9840 is not set
+# CONFIG_VIDEO_TEA6415C is not set
+# CONFIG_VIDEO_TEA6420 is not set
+# CONFIG_VIDEO_THS7303 is not set
+# CONFIG_VIDEO_THS8200 is not set
+# CONFIG_VIDEO_TIMBERDALE is not set
+# CONFIG_VIDEO_TLV320AIC23B is not set
+# CONFIG_VIDEO_TM6000 is not set
+# CONFIG_VIDEO_TVAUDIO is not set
+# CONFIG_VIDEO_TVP514X is not set
+# CONFIG_VIDEO_TVP5150 is not set
+# CONFIG_VIDEO_TVP7002 is not set
+# CONFIG_VIDEO_TW2804 is not set
+# CONFIG_VIDEO_TW9903 is not set
+# CONFIG_VIDEO_TW9906 is not set
+# CONFIG_VIDEO_TW9910 is not set
+# CONFIG_VIDEO_UDA1342 is not set
+# CONFIG_VIDEO_UPD64031A is not set
+# CONFIG_VIDEO_UPD64083 is not set
+# CONFIG_VIDEO_USBTV is not set
+# CONFIG_VIDEO_USBVISION is not set
+# CONFIG_VIDEO_V4L2 is not set
+# CONFIG_VIDEO_VP27SMPX is not set
+# CONFIG_VIDEO_VPX3220 is not set
+# CONFIG_VIDEO_VS6624 is not set
+# CONFIG_VIDEO_WM8739 is not set
+# CONFIG_VIDEO_WM8775 is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIRTIO_BALLOON is not set
+# CONFIG_VIRTIO_BLK_SCSI is not set
+# CONFIG_VIRTIO_FS is not set
+# CONFIG_VIRTIO_INPUT is not set
+CONFIG_VIRTIO_MENU=y
+# CONFIG_VIRTIO_MMIO is not set
+# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set
+# CONFIG_VIRTIO_PCI is not set
+# CONFIG_VIRTUALIZATION is not set
+# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
+# CONFIG_VIRT_DRIVERS is not set
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_VL53L0X_I2C is not set
+# CONFIG_VL6180 is not set
+CONFIG_VLAN_8021Q=y
+# CONFIG_VLAN_8021Q_GVRP is not set
+# CONFIG_VLAN_8021Q_MVRP is not set
+# CONFIG_VME_BUS is not set
+# CONFIG_VMSPLIT_1G is not set
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_2G_OPT is not set
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_3G_OPT is not set
+# CONFIG_VMWARE_PVSCSI is not set
+# CONFIG_VMXNET3 is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_VOP_BUS is not set
+# CONFIG_VORTEX is not set
+# CONFIG_VSOCKETS is not set
+# CONFIG_VSOCKETS_DIAG is not set
+# CONFIG_VT is not set
+# CONFIG_VT6655 is not set
+# CONFIG_VT6656 is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_VXGE is not set
+# CONFIG_VXLAN is not set
+# CONFIG_VZ89X is not set
+# CONFIG_W1 is not set
+# CONFIG_W1_CON is not set
+# CONFIG_W1_MASTER_DS1WM is not set
+# CONFIG_W1_MASTER_DS2482 is not set
+# CONFIG_W1_MASTER_DS2490 is not set
+# CONFIG_W1_MASTER_GPIO is not set
+# CONFIG_W1_MASTER_MATROX is not set
+# CONFIG_W1_MASTER_SGI is not set
+# CONFIG_W1_SLAVE_DS2405 is not set
+# CONFIG_W1_SLAVE_DS2406 is not set
+# CONFIG_W1_SLAVE_DS2408 is not set
+# CONFIG_W1_SLAVE_DS2413 is not set
+# CONFIG_W1_SLAVE_DS2423 is not set
+# CONFIG_W1_SLAVE_DS2431 is not set
+# CONFIG_W1_SLAVE_DS2433 is not set
+# CONFIG_W1_SLAVE_DS2438 is not set
+# CONFIG_W1_SLAVE_DS250X is not set
+# CONFIG_W1_SLAVE_DS2780 is not set
+# CONFIG_W1_SLAVE_DS2781 is not set
+# CONFIG_W1_SLAVE_DS2805 is not set
+# CONFIG_W1_SLAVE_DS28E04 is not set
+# CONFIG_W1_SLAVE_DS28E17 is not set
+# CONFIG_W1_SLAVE_SMEM is not set
+# CONFIG_W1_SLAVE_THERM is not set
+# CONFIG_W83627HF_WDT is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_W83977F_WDT is not set
+# CONFIG_WAN is not set
+# CONFIG_WANXL is not set
+# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_CORE is not set
+CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+CONFIG_WATCHDOG_OPEN_TIMEOUT=0
+# CONFIG_WATCHDOG_PRETIMEOUT_GOV is not set
+# CONFIG_WATCHDOG_SYSFS is not set
+# CONFIG_WD80x3 is not set
+# CONFIG_WDAT_WDT is not set
+# CONFIG_WDTPCI is not set
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PRIV=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_SPY=y
+CONFIG_WILINK_PLATFORM_DATA=y
+# CONFIG_WIMAX is not set
+# CONFIG_WIREGUARD is not set
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+# CONFIG_WIRELESS_WDS is not set
+# CONFIG_WIZNET_W5100 is not set
+# CONFIG_WIZNET_W5300 is not set
+# CONFIG_WL1251 is not set
+# CONFIG_WL12XX is not set
+# CONFIG_WL18XX is not set
+CONFIG_WLAN=y
+# CONFIG_WLAN_VENDOR_ADMTEK is not set
+# CONFIG_WLAN_VENDOR_ATH is not set
+# CONFIG_WLAN_VENDOR_ATMEL is not set
+# CONFIG_WLAN_VENDOR_BROADCOM is not set
+# CONFIG_WLAN_VENDOR_CISCO is not set
+# CONFIG_WLAN_VENDOR_INTEL is not set
+# CONFIG_WLAN_VENDOR_INTERSIL is not set
+# CONFIG_WLAN_VENDOR_MARVELL is not set
+# CONFIG_WLAN_VENDOR_MEDIATEK is not set
+# CONFIG_WLAN_VENDOR_QUANTENNA is not set
+# CONFIG_WLAN_VENDOR_RALINK is not set
+# CONFIG_WLAN_VENDOR_REALTEK is not set
+# CONFIG_WLAN_VENDOR_RSI is not set
+# CONFIG_WLAN_VENDOR_ST is not set
+# CONFIG_WLAN_VENDOR_TI is not set
+# CONFIG_WLAN_VENDOR_ZYDAS is not set
+# CONFIG_WLCORE is not set
+CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y
+# CONFIG_WQ_WATCHDOG is not set
+# CONFIG_WW_MUTEX_SELFTEST is not set
+# CONFIG_X25 is not set
+# CONFIG_X509_CERTIFICATE_PARSER is not set
+# CONFIG_X86_PKG_TEMP_THERMAL is not set
+CONFIG_X86_SYSFB=y
+# CONFIG_XDP_SOCKETS is not set
+# CONFIG_XEN is not set
+# CONFIG_XEN_GRANT_DMA_ALLOC is not set
+# CONFIG_XEN_PVCALLS_FRONTEND is not set
+CONFIG_XEN_SCRUB_PAGES_DEFAULT=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_INTERFACE is not set
+# CONFIG_XFRM_IPCOMP is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFS_DEBUG is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_XFS_ONLINE_SCRUB is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_WARN is not set
+# CONFIG_XILINX_AXI_EMAC is not set
+# CONFIG_XILINX_DMA is not set
+# CONFIG_XILINX_EMACLITE is not set
+# CONFIG_XILINX_GMII2RGMII is not set
+# CONFIG_XILINX_LL_TEMAC is not set
+# CONFIG_XILINX_SDFEC is not set
+# CONFIG_XILINX_VCU is not set
+# CONFIG_XILINX_WATCHDOG is not set
+# CONFIG_XILINX_XADC is not set
+# CONFIG_XILINX_ZYNQMP_DMA is not set
+# CONFIG_XILLYBUS is not set
+# CONFIG_XIL_AXIS_FIFO is not set
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_XMON is not set
+CONFIG_XZ_DEC=y
+# CONFIG_XZ_DEC_ARM is not set
+# CONFIG_XZ_DEC_ARMTHUMB is not set
+# CONFIG_XZ_DEC_BCJ is not set
+# CONFIG_XZ_DEC_IA64 is not set
+# CONFIG_XZ_DEC_POWERPC is not set
+# CONFIG_XZ_DEC_SPARC is not set
+# CONFIG_XZ_DEC_TEST is not set
+# CONFIG_XZ_DEC_X86 is not set
+# CONFIG_YAM is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_YENTA is not set
+# CONFIG_YENTA_O2 is not set
+# CONFIG_YENTA_RICOH is not set
+# CONFIG_YENTA_TI is not set
+# CONFIG_YENTA_TOSHIBA is not set
+# CONFIG_ZBUD is not set
+# CONFIG_ZD1211RW is not set
+# CONFIG_ZD1211RW_DEBUG is not set
+# CONFIG_ZEROPLUS_FF is not set
+# CONFIG_ZIIRAVE_WATCHDOG is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_ZLIB_DEFLATE is not set
+# CONFIG_ZLIB_INFLATE is not set
+CONFIG_ZONE_DMA=y
+# CONFIG_ZOPT2201 is not set
+# CONFIG_ZPA2326 is not set
+# CONFIG_ZPOOL is not set
+# CONFIG_ZRAM is not set
+# CONFIG_ZRAM_MEMORY_TRACKING is not set
+# CONFIG_ZSMALLOC is not set
+# CONFIG_ZX_TDM is not set
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/drivers/mtd/nmbm/Kconfig b/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/drivers/mtd/nmbm/Kconfig
new file mode 100644
index 0000000..98df305
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/drivers/mtd/nmbm/Kconfig
@@ -0,0 +1,35 @@
+
+config NMBM
+	bool "Enable NAND mapping block management"
+	default n
+	select CRC32
+
+choice
+	prompt "Default log level"
+	depends on NMBM
+	default NMBM_LOG_LEVEL_INFO
+
+config NMBM_LOG_LEVEL_DEBUG
+	bool "0 - Debug"
+
+config NMBM_LOG_LEVEL_INFO
+	bool "1 - Info"
+
+config NMBM_LOG_LEVEL_WARN
+	bool "2 - Warn"
+
+config NMBM_LOG_LEVEL_ERR
+	bool "3 - Error"
+
+config NMBM_LOG_LEVEL_EMERG
+	bool "4 - Emergency"
+
+config NMBM_LOG_LEVEL_NONE
+	bool "5 - None"
+
+endchoice
+
+config NMBM_MTD
+	bool "Enable MTD based NAND mapping block management"
+	default n
+	depends on NMBM
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/drivers/mtd/nmbm/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/drivers/mtd/nmbm/Makefile
new file mode 100644
index 0000000..46e6d50
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/drivers/mtd/nmbm/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# (C) Copyright 2020 MediaTek Inc. All rights reserved.
+
+obj-$(CONFIG_NMBM) += nmbm-core.o
+obj-$(CONFIG_NMBM_MTD) += nmbm-mtd.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/drivers/mtd/nmbm/nmbm-core.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/drivers/mtd/nmbm/nmbm-core.c
new file mode 100644
index 0000000..18dfb6a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/drivers/mtd/nmbm/nmbm-core.c
@@ -0,0 +1,2936 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * Copyright (C) 2021 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include "nmbm-private.h"
+
+#include "nmbm-debug.h"
+
+#define NMBM_VER_MAJOR			1
+#define NMBM_VER_MINOR			0
+#define NMBM_VER			NMBM_VERSION_MAKE(NMBM_VER_MAJOR, \
+							  NMBM_VER_MINOR)
+
+#define NMBM_ALIGN(v, a)		(((v) + (a) - 1) & ~((a) - 1))
+
+/*****************************************************************************/
+/* Logging related functions */
+/*****************************************************************************/
+
+/*
+ * nmbm_log_lower - Print log using OS specific routine
+ * @nld: NMBM lower device structure
+ * @level: log level
+ * @fmt: format string
+ */
+static void nmbm_log_lower(struct nmbm_lower_device *nld,
+			   enum nmbm_log_category level, const char *fmt, ...)
+{
+	va_list ap;
+
+	if (!nld->logprint)
+		return;
+
+	va_start(ap, fmt);
+	nld->logprint(nld->arg, level, fmt, ap);
+	va_end(ap);
+}
+
+/*
+ * nmbm_log - Print log using OS specific routine
+ * @ni: NMBM instance structure
+ * @level: log level
+ * @fmt: format string
+ */
+static void nmbm_log(struct nmbm_instance *ni, enum nmbm_log_category level,
+		     const char *fmt, ...)
+{
+	va_list ap;
+
+	if (!ni)
+		return;
+
+	if (!ni->lower.logprint || level < ni->log_display_level)
+		return;
+
+	va_start(ap, fmt);
+	ni->lower.logprint(ni->lower.arg, level, fmt, ap);
+	va_end(ap);
+}
+
+/*
+ * nmbm_set_log_level - Set log display level
+ * @ni: NMBM instance structure
+ * @level: log display level
+ */
+enum nmbm_log_category nmbm_set_log_level(struct nmbm_instance *ni,
+					  enum nmbm_log_category level)
+{
+	enum nmbm_log_category old;
+
+	if (!ni)
+		return __NMBM_LOG_MAX;
+
+	old = ni->log_display_level;
+	ni->log_display_level = level;
+	return old;
+}
+
+/*
+ * nlog_table_creation - Print log of table creation event
+ * @ni: NMBM instance structure
+ * @main_table: whether the table is main info table
+ * @start_ba: start block address of the table
+ * @end_ba: block address after the end of the table
+ */
+static void nlog_table_creation(struct nmbm_instance *ni, bool main_table,
+			       uint32_t start_ba, uint32_t end_ba)
+{
+	if (start_ba == end_ba - 1)
+		nlog_info(ni, "%s info table has been written to block %u\n",
+			 main_table ? "Main" : "Backup", start_ba);
+	else
+		nlog_info(ni, "%s info table has been written to block %u-%u\n",
+			 main_table ? "Main" : "Backup", start_ba, end_ba - 1);
+
+	nmbm_mark_block_color_info_table(ni, start_ba, end_ba - 1);
+}
+
+/*
+ * nlog_table_update - Print log of table update event
+ * @ni: NMBM instance structure
+ * @main_table: whether the table is main info table
+ * @start_ba: start block address of the table
+ * @end_ba: block address after the end of the table
+ */
+static void nlog_table_update(struct nmbm_instance *ni, bool main_table,
+			     uint32_t start_ba, uint32_t end_ba)
+{
+	if (start_ba == end_ba - 1)
+		nlog_debug(ni, "%s info table has been updated in block %u\n",
+			  main_table ? "Main" : "Backup", start_ba);
+	else
+		nlog_debug(ni, "%s info table has been updated in block %u-%u\n",
+			  main_table ? "Main" : "Backup", start_ba, end_ba - 1);
+
+	nmbm_mark_block_color_info_table(ni, start_ba, end_ba - 1);
+}
+
+/*
+ * nlog_table_found - Print log of table found event
+ * @ni: NMBM instance structure
+ * @first_table: whether the table is first found info table
+ * @write_count: write count of the info table
+ * @start_ba: start block address of the table
+ * @end_ba: block address after the end of the table
+ */
+static void nlog_table_found(struct nmbm_instance *ni, bool first_table,
+			    uint32_t write_count, uint32_t start_ba,
+			    uint32_t end_ba)
+{
+	if (start_ba == end_ba - 1)
+		nlog_info(ni, "%s info table with writecount %u found in block %u\n",
+			 first_table ? "First" : "Second", write_count,
+			 start_ba);
+	else
+		nlog_info(ni, "%s info table with writecount %u found in block %u-%u\n",
+			 first_table ? "First" : "Second", write_count,
+			 start_ba, end_ba - 1);
+
+	nmbm_mark_block_color_info_table(ni, start_ba, end_ba - 1);
+}
+
+/*****************************************************************************/
+/* Address conversion functions */
+/*****************************************************************************/
+
+/*
+ * addr2ba - Convert a linear address to block address
+ * @ni: NMBM instance structure
+ * @addr: Linear address
+ */
+static uint32_t addr2ba(struct nmbm_instance *ni, uint64_t addr)
+{
+	return addr >> ni->erasesize_shift;
+}
+
+/*
+ * ba2addr - Convert a block address to linear address
+ * @ni: NMBM instance structure
+ * @ba: Block address
+ */
+static uint64_t ba2addr(struct nmbm_instance *ni, uint32_t ba)
+{
+	return (uint64_t)ba << ni->erasesize_shift;
+}
+/*
+ * size2blk - Get minimum required blocks for storing specific size of data
+ * @ni: NMBM instance structure
+ * @size: size for storing
+ */
+static uint32_t size2blk(struct nmbm_instance *ni, uint64_t size)
+{
+	return (size + ni->lower.erasesize - 1) >> ni->erasesize_shift;
+}
+
+/*****************************************************************************/
+/* High level NAND chip APIs */
+/*****************************************************************************/
+
+/*
+ * nmbm_reset_chip - Reset NAND device
+ * @nld: Lower NAND chip structure
+ */
+static void nmbm_reset_chip(struct nmbm_instance *ni)
+{
+	if (ni->lower.reset_chip)
+		ni->lower.reset_chip(ni->lower.arg);
+}
+
+/*
+ * nmbm_read_phys_page - Read page with retry
+ * @ni: NMBM instance structure
+ * @addr: linear address where the data will be read from
+ * @data: the main data to be read
+ * @oob: the oob data to be read
+ * @mode: mode for processing oob data
+ *
+ * Read a page for at most NMBM_TRY_COUNT times.
+ *
+ * Return 0 for success, positive value for corrected bitflip count,
+ * -EBADMSG for ecc error, other negative values for other errors
+ */
+static int nmbm_read_phys_page(struct nmbm_instance *ni, uint64_t addr,
+			       void *data, void *oob, enum nmbm_oob_mode mode)
+{
+	int tries, ret;
+
+	for (tries = 0; tries < NMBM_TRY_COUNT; tries++) {
+		ret = ni->lower.read_page(ni->lower.arg, addr, data, oob, mode);
+		if (ret >= 0)
+			return ret;
+
+		nmbm_reset_chip(ni);
+	}
+
+	if (ret != -EBADMSG)
+		nlog_err(ni, "Page read failed at address 0x%08llx\n", addr);
+
+	return ret;
+}
+
+/*
+ * nmbm_write_phys_page - Write page with retry
+ * @ni: NMBM instance structure
+ * @addr: linear address where the data will be written to
+ * @data: the main data to be written
+ * @oob: the oob data to be written
+ * @mode: mode for processing oob data
+ *
+ * Write a page for at most NMBM_TRY_COUNT times.
+ */
+static bool nmbm_write_phys_page(struct nmbm_instance *ni, uint64_t addr,
+				 const void *data, const void *oob,
+				 enum nmbm_oob_mode mode)
+{
+	int tries, ret;
+
+	if (ni->lower.flags & NMBM_F_READ_ONLY) {
+		nlog_err(ni, "%s called with NMBM_F_READ_ONLY set\n", addr);
+		return false;
+	}
+
+	for (tries = 0; tries < NMBM_TRY_COUNT; tries++) {
+		ret = ni->lower.write_page(ni->lower.arg, addr, data, oob, mode);
+		if (!ret)
+			return true;
+
+		nmbm_reset_chip(ni);
+	}
+
+	nlog_err(ni, "Page write failed at address 0x%08llx\n", addr);
+
+	return false;
+}
+
+/*
+ * nmbm_erase_phys_block - Erase a block with retry
+ * @ni: NMBM instance structure
+ * @addr: Linear address
+ *
+ * Erase a block for at most NMBM_TRY_COUNT times.
+ */
+static bool nmbm_erase_phys_block(struct nmbm_instance *ni, uint64_t addr)
+{
+	int tries, ret;
+
+	if (ni->lower.flags & NMBM_F_READ_ONLY) {
+		nlog_err(ni, "%s called with NMBM_F_READ_ONLY set\n", addr);
+		return false;
+	}
+
+	for (tries = 0; tries < NMBM_TRY_COUNT; tries++) {
+		ret = ni->lower.erase_block(ni->lower.arg, addr);
+		if (!ret)
+			return true;
+
+		nmbm_reset_chip(ni);
+	}
+
+	nlog_err(ni, "Block erasure failed at address 0x%08llx\n", addr);
+
+	return false;
+}
+
+/*
+ * nmbm_check_bad_phys_block - Check whether a block is marked bad in OOB
+ * @ni: NMBM instance structure
+ * @ba: block address
+ */
+static bool nmbm_check_bad_phys_block(struct nmbm_instance *ni, uint32_t ba)
+{
+	uint64_t addr = ba2addr(ni, ba);
+	int ret;
+
+	if (ni->lower.is_bad_block)
+		return ni->lower.is_bad_block(ni->lower.arg, addr);
+
+	/* Treat ECC error as read success */
+	ret = nmbm_read_phys_page(ni, addr, NULL,
+				  ni->page_cache + ni->lower.writesize,
+				  NMBM_MODE_RAW);
+	if (ret < 0 && ret != -EBADMSG)
+		return true;
+
+	return ni->page_cache[ni->lower.writesize] != 0xff;
+}
+
+/*
+ * nmbm_mark_phys_bad_block - Mark a block bad
+ * @ni: NMBM instance structure
+ * @addr: Linear address
+ */
+static int nmbm_mark_phys_bad_block(struct nmbm_instance *ni, uint32_t ba)
+{
+	uint64_t addr = ba2addr(ni, ba);
+	enum nmbm_log_category level;
+	uint32_t off;
+
+	if (ni->lower.flags & NMBM_F_READ_ONLY) {
+		nlog_err(ni, "%s called with NMBM_F_READ_ONLY set\n", addr);
+		return false;
+	}
+
+	nlog_info(ni, "Block %u [0x%08llx] will be marked bad\n", ba, addr);
+
+	if (ni->lower.mark_bad_block)
+		return ni->lower.mark_bad_block(ni->lower.arg, addr);
+
+	/* Whole page set to 0x00 */
+	memset(ni->page_cache, 0, ni->rawpage_size);
+
+	/* Write to all pages within this block, disable all errors */
+	level = nmbm_set_log_level(ni, __NMBM_LOG_MAX);
+
+	for (off = 0; off < ni->lower.erasesize; off += ni->lower.writesize) {
+		nmbm_write_phys_page(ni, addr + off, ni->page_cache,
+				     ni->page_cache + ni->lower.writesize,
+				     NMBM_MODE_RAW);
+	}
+
+	nmbm_set_log_level(ni, level);
+
+	return 0;
+}
+
+/*****************************************************************************/
+/* NMBM related functions */
+/*****************************************************************************/
+
+/*
+ * nmbm_check_header - Check whether a NMBM structure is valid
+ * @data: pointer to a NMBM structure with a NMBM header at beginning
+ * @size: Size of the buffer pointed by @header
+ *
+ * The size of the NMBM structure may be larger than NMBM header,
+ * e.g. block mapping table and block state table.
+ */
+static bool nmbm_check_header(const void *data, uint32_t size)
+{
+	const struct nmbm_header *header = data;
+	struct nmbm_header nhdr;
+	uint32_t new_checksum;
+
+	/*
+	 * Make sure expected structure size is equal or smaller than
+	 * buffer size.
+	 */
+	if (header->size > size)
+		return false;
+
+	memcpy(&nhdr, data, sizeof(nhdr));
+
+	nhdr.checksum = 0;
+	new_checksum = nmbm_crc32(0, &nhdr, sizeof(nhdr));
+	if (header->size > sizeof(nhdr))
+		new_checksum = nmbm_crc32(new_checksum,
+			(const uint8_t *)data + sizeof(nhdr),
+			header->size - sizeof(nhdr));
+
+	if (header->checksum != new_checksum)
+		return false;
+
+	return true;
+}
+
+/*
+ * nmbm_update_checksum - Update checksum of a NMBM structure
+ * @header: pointer to a NMBM structure with a NMBM header at beginning
+ *
+ * The size of the NMBM structure must be specified by @header->size
+ */
+static void nmbm_update_checksum(struct nmbm_header *header)
+{
+	header->checksum = 0;
+	header->checksum = nmbm_crc32(0, header, header->size);
+}
+
+/*
+ * nmbm_get_spare_block_count - Calculate number of blocks should be reserved
+ * @block_count: number of blocks of data
+ *
+ * Calculate number of blocks should be reserved for data
+ */
+static uint32_t nmbm_get_spare_block_count(uint32_t block_count)
+{
+	uint32_t val;
+
+	val = (block_count + NMBM_SPARE_BLOCK_DIV / 2) / NMBM_SPARE_BLOCK_DIV;
+	val *= NMBM_SPARE_BLOCK_MULTI;
+
+	if (val < NMBM_SPARE_BLOCK_MIN)
+		val = NMBM_SPARE_BLOCK_MIN;
+
+	return val;
+}
+
+/*
+ * nmbm_get_block_state_raw - Get state of a block from raw block state table
+ * @block_state: pointer to raw block state table (bitmap)
+ * @ba: block address
+ */
+static uint32_t nmbm_get_block_state_raw(nmbm_bitmap_t *block_state,
+					 uint32_t ba)
+{
+	uint32_t unit, shift;
+
+	unit = ba / NMBM_BITMAP_BLOCKS_PER_UNIT;
+	shift = (ba % NMBM_BITMAP_BLOCKS_PER_UNIT) * NMBM_BITMAP_BITS_PER_BLOCK;
+
+	return (block_state[unit] >> shift) & BLOCK_ST_MASK;
+}
+
+/*
+ * nmbm_get_block_state - Get state of a block from block state table
+ * @ni: NMBM instance structure
+ * @ba: block address
+ */
+static uint32_t nmbm_get_block_state(struct nmbm_instance *ni, uint32_t ba)
+{
+	return nmbm_get_block_state_raw(ni->block_state, ba);
+}
+
+/*
+ * nmbm_set_block_state - Set state of a block to block state table
+ * @ni: NMBM instance structure
+ * @ba: block address
+ * @state: block state
+ *
+ * Set state of a block. If the block state changed, ni->block_state_changed
+ * will be increased.
+ */
+static bool nmbm_set_block_state(struct nmbm_instance *ni, uint32_t ba,
+				 uint32_t state)
+{
+	uint32_t unit, shift, orig;
+	nmbm_bitmap_t uv;
+
+	unit = ba / NMBM_BITMAP_BLOCKS_PER_UNIT;
+	shift = (ba % NMBM_BITMAP_BLOCKS_PER_UNIT) * NMBM_BITMAP_BITS_PER_BLOCK;
+
+	orig = (ni->block_state[unit] >> shift) & BLOCK_ST_MASK;
+	state &= BLOCK_ST_MASK;
+
+	uv = ni->block_state[unit] & (~(BLOCK_ST_MASK << shift));
+	uv |= state << shift;
+	ni->block_state[unit] = uv;
+
+	if (state == BLOCK_ST_BAD)
+		nmbm_mark_block_color_bad(ni, ba);
+
+	if (orig != state) {
+		ni->block_state_changed++;
+		return true;
+	}
+
+	return false;
+}
+
+/*
+ * nmbm_block_walk_asc - Skip specified number of good blocks, ascending addr.
+ * @ni: NMBM instance structure
+ * @ba: start physical block address
+ * @nba: return physical block address after walk
+ * @count: number of good blocks to be skipped
+ * @limit: highest block address allowed for walking
+ *
+ * Start from @ba, skipping any bad blocks, counting @count good blocks, and
+ * return the next good block address.
+ *
+ * If no enough good blocks counted while @limit reached, false will be returned.
+ *
+ * If @count == 0, nearest good block address will be returned.
+ * @limit is not counted in walking.
+ */
+static bool nmbm_block_walk_asc(struct nmbm_instance *ni, uint32_t ba,
+				uint32_t *nba, uint32_t count,
+				uint32_t limit)
+{
+	int32_t nblock = count;
+
+	if (limit >= ni->block_count)
+		limit = ni->block_count - 1;
+
+	while (ba < limit) {
+		if (nmbm_get_block_state(ni, ba) == BLOCK_ST_GOOD)
+			nblock--;
+
+		if (nblock < 0) {
+			*nba = ba;
+			return true;
+		}
+
+		ba++;
+	}
+
+	return false;
+}
+
+/*
+ * nmbm_block_walk_desc - Skip specified number of good blocks, descending addr
+ * @ni: NMBM instance structure
+ * @ba: start physical block address
+ * @nba: return physical block address after walk
+ * @count: number of good blocks to be skipped
+ * @limit: lowest block address allowed for walking
+ *
+ * Start from @ba, skipping any bad blocks, counting @count good blocks, and
+ * return the next good block address.
+ *
+ * If no enough good blocks counted while @limit reached, false will be returned.
+ *
+ * If @count == 0, nearest good block address will be returned.
+ * @limit is not counted in walking.
+ */
+static bool nmbm_block_walk_desc(struct nmbm_instance *ni, uint32_t ba,
+				 uint32_t *nba, uint32_t count, uint32_t limit)
+{
+	int32_t nblock = count;
+
+	if (limit >= ni->block_count)
+		limit = ni->block_count - 1;
+
+	while (ba > limit) {
+		if (nmbm_get_block_state(ni, ba) == BLOCK_ST_GOOD)
+			nblock--;
+
+		if (nblock < 0) {
+			*nba = ba;
+			return true;
+		}
+
+		ba--;
+	}
+
+	return false;
+}
+
+/*
+ * nmbm_block_walk - Skip specified number of good blocks from curr. block addr
+ * @ni: NMBM instance structure
+ * @ascending: whether to walk ascending
+ * @ba: start physical block address
+ * @nba: return physical block address after walk
+ * @count: number of good blocks to be skipped
+ * @limit: highest/lowest block address allowed for walking
+ *
+ * Start from @ba, skipping any bad blocks, counting @count good blocks, and
+ * return the next good block address.
+ *
+ * If no enough good blocks counted while @limit reached, false will be returned.
+ *
+ * If @count == 0, nearest good block address will be returned.
+ * @limit can be set to negative if no limit required.
+ * @limit is not counted in walking.
+ */
+static bool nmbm_block_walk(struct nmbm_instance *ni, bool ascending,
+			    uint32_t ba, uint32_t *nba, int32_t count,
+			    int32_t limit)
+{
+	if (ascending)
+		return nmbm_block_walk_asc(ni, ba, nba, count, limit);
+
+	return nmbm_block_walk_desc(ni, ba, nba, count, limit);
+}
+
+/*
+ * nmbm_scan_badblocks - Scan and record all bad blocks
+ * @ni: NMBM instance structure
+ *
+ * Scan the entire lower NAND chip and record all bad blocks in to block state
+ * table.
+ */
+static void nmbm_scan_badblocks(struct nmbm_instance *ni)
+{
+	uint32_t ba;
+
+	for (ba = 0; ba < ni->block_count; ba++) {
+		if (nmbm_check_bad_phys_block(ni, ba)) {
+			nmbm_set_block_state(ni, ba, BLOCK_ST_BAD);
+			nlog_info(ni, "Bad block %u [0x%08llx]\n", ba,
+				 ba2addr(ni, ba));
+		}
+	}
+}
+
+/*
+ * nmbm_build_mapping_table - Build initial block mapping table
+ * @ni: NMBM instance structure
+ *
+ * The initial mapping table will be compatible with the stratage of
+ * factory production.
+ */
+static void nmbm_build_mapping_table(struct nmbm_instance *ni)
+{
+	uint32_t pb, lb;
+
+	for (pb = 0, lb = 0; pb < ni->mgmt_start_ba; pb++) {
+		if (nmbm_get_block_state(ni, pb) == BLOCK_ST_BAD)
+			continue;
+
+		/* Always map to the next good block */
+		ni->block_mapping[lb++] = pb;
+	}
+
+	ni->data_block_count = lb;
+
+	/* Unusable/Management blocks */
+	for (pb = lb; pb < ni->block_count; pb++)
+		ni->block_mapping[pb] = -1;
+}
+
+/*
+ * nmbm_erase_block_and_check - Erase a block and check its usability
+ * @ni: NMBM instance structure
+ * @ba: block address to be erased
+ *
+ * Erase a block anc check its usability
+ *
+ * Return true if the block is usable, false if erasure failure or the block
+ * has too many bitflips.
+ */
+static bool nmbm_erase_block_and_check(struct nmbm_instance *ni, uint32_t ba)
+{
+	uint64_t addr, off;
+	bool success;
+	int ret;
+
+	success = nmbm_erase_phys_block(ni, ba2addr(ni, ba));
+	if (!success)
+		return false;
+
+	if (!(ni->lower.flags & NMBM_F_EMPTY_PAGE_ECC_OK))
+		return true;
+
+	/* Check every page to make sure there aren't too many bitflips */
+
+	addr = ba2addr(ni, ba);
+
+	for (off = 0; off < ni->lower.erasesize; off += ni->lower.writesize) {
+		WATCHDOG_RESET();
+
+		ret = nmbm_read_phys_page(ni, addr + off, ni->page_cache, NULL,
+					  NMBM_MODE_PLACE_OOB);
+		if (ret == -EBADMSG) {
+			/*
+			 * NMBM_F_EMPTY_PAGE_ECC_OK means the empty page is
+			 * still protected by ECC. So reading pages with ECC
+			 * enabled and -EBADMSG means there are too many
+			 * bitflips that can't be recovered, and the block
+			 * containing the page should be marked bad.
+			 */
+			nlog_err(ni,
+				 "Too many bitflips in empty page at 0x%llx\n",
+				 addr + off);
+			return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * nmbm_erase_range - Erase a range of blocks
+ * @ni: NMBM instance structure
+ * @ba: block address where the erasure will start
+ * @limit: top block address allowed for erasure
+ *
+ * Erase blocks within the specific range. Newly-found bad blocks will be
+ * marked.
+ *
+ * @limit is not counted into the allowed erasure address.
+ */
+static void nmbm_erase_range(struct nmbm_instance *ni, uint32_t ba,
+			     uint32_t limit)
+{
+	bool success;
+
+	while (ba < limit) {
+		WATCHDOG_RESET();
+
+		if (nmbm_get_block_state(ni, ba) != BLOCK_ST_GOOD)
+			goto next_block;
+
+		/* Insurance to detect unexpected bad block marked by user */
+		if (nmbm_check_bad_phys_block(ni, ba)) {
+			nmbm_set_block_state(ni, ba, BLOCK_ST_BAD);
+			goto next_block;
+		}
+
+		success = nmbm_erase_block_and_check(ni, ba);
+		if (success)
+			goto next_block;
+
+		nmbm_mark_phys_bad_block(ni, ba);
+		nmbm_set_block_state(ni, ba, BLOCK_ST_BAD);
+
+	next_block:
+		ba++;
+	}
+}
+
+/*
+ * nmbm_write_repeated_data - Write critical data to a block with retry
+ * @ni: NMBM instance structure
+ * @ba: block address where the data will be written to
+ * @data: the data to be written
+ * @size: size of the data
+ *
+ * Write data to every page of the block. Success only if all pages within
+ * this block have been successfully written.
+ *
+ * Make sure data size is not bigger than one page.
+ *
+ * This function will write and verify every page for at most
+ * NMBM_TRY_COUNT times.
+ */
+static bool nmbm_write_repeated_data(struct nmbm_instance *ni, uint32_t ba,
+				     const void *data, uint32_t size)
+{
+	uint64_t addr, off;
+	bool success;
+	int ret;
+
+	if (size > ni->lower.writesize)
+		return false;
+
+	addr = ba2addr(ni, ba);
+
+	for (off = 0; off < ni->lower.erasesize; off += ni->lower.writesize) {
+		WATCHDOG_RESET();
+
+		/* Prepare page data. fill 0xff to unused region */
+		memcpy(ni->page_cache, data, size);
+		memset(ni->page_cache + size, 0xff, ni->rawpage_size - size);
+
+		success = nmbm_write_phys_page(ni, addr + off, ni->page_cache,
+					       NULL, NMBM_MODE_PLACE_OOB);
+		if (!success)
+			return false;
+
+		/* Verify the data just written. ECC error indicates failure */
+		ret = nmbm_read_phys_page(ni, addr + off, ni->page_cache, NULL,
+					  NMBM_MODE_PLACE_OOB);
+		if (ret < 0)
+			return false;
+
+		if (memcmp(ni->page_cache, data, size))
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * nmbm_write_signature - Write signature to NAND chip
+ * @ni: NMBM instance structure
+ * @limit: top block address allowed for writing
+ * @signature: the signature to be written
+ * @signature_ba: the actual block address where signature is written to
+ *
+ * Write signature within a specific range, from chip bottom to limit.
+ * At most one block will be written.
+ *
+ * @limit is not counted into the allowed write address.
+ */
+static bool nmbm_write_signature(struct nmbm_instance *ni, uint32_t limit,
+				 const struct nmbm_signature *signature,
+				 uint32_t *signature_ba)
+{
+	uint32_t ba = ni->block_count - 1;
+	bool success;
+
+	while (ba > limit) {
+		WATCHDOG_RESET();
+
+		if (nmbm_get_block_state(ni, ba) != BLOCK_ST_GOOD)
+			goto next_block;
+
+		/* Insurance to detect unexpected bad block marked by user */
+		if (nmbm_check_bad_phys_block(ni, ba)) {
+			nmbm_set_block_state(ni, ba, BLOCK_ST_BAD);
+			goto next_block;
+		}
+
+		success = nmbm_erase_block_and_check(ni, ba);
+		if (!success)
+			goto skip_bad_block;
+
+		success = nmbm_write_repeated_data(ni, ba, signature,
+						   sizeof(*signature));
+		if (success) {
+			*signature_ba = ba;
+			return true;
+		}
+
+	skip_bad_block:
+		nmbm_mark_phys_bad_block(ni, ba);
+		nmbm_set_block_state(ni, ba, BLOCK_ST_BAD);
+
+	next_block:
+		ba--;
+	};
+
+	return false;
+}
+
+/*
+ * nmbn_read_data - Read data
+ * @ni: NMBM instance structure
+ * @addr: linear address where the data will be read from
+ * @data: the data to be read
+ * @size: the size of data
+ *
+ * Read data range.
+ * Every page will be tried for at most NMBM_TRY_COUNT times.
+ *
+ * Return 0 for success, positive value for corrected bitflip count,
+ * -EBADMSG for ecc error, other negative values for other errors
+ */
+static int nmbn_read_data(struct nmbm_instance *ni, uint64_t addr, void *data,
+			  uint32_t size)
+{
+	uint64_t off = addr;
+	uint8_t *ptr = data;
+	uint32_t sizeremain = size, chunksize, leading;
+	int ret;
+
+	while (sizeremain) {
+		WATCHDOG_RESET();
+
+		leading = off & ni->writesize_mask;
+		chunksize = ni->lower.writesize - leading;
+		if (chunksize > sizeremain)
+			chunksize = sizeremain;
+
+		if (chunksize == ni->lower.writesize) {
+			ret = nmbm_read_phys_page(ni, off - leading, ptr, NULL,
+						  NMBM_MODE_PLACE_OOB);
+			if (ret < 0)
+				return ret;
+		} else {
+			ret = nmbm_read_phys_page(ni, off - leading,
+						  ni->page_cache, NULL,
+						  NMBM_MODE_PLACE_OOB);
+			if (ret < 0)
+				return ret;
+
+			memcpy(ptr, ni->page_cache + leading, chunksize);
+		}
+
+		off += chunksize;
+		ptr += chunksize;
+		sizeremain -= chunksize;
+	}
+
+	return 0;
+}
+
+/*
+ * nmbn_write_verify_data - Write data with validation
+ * @ni: NMBM instance structure
+ * @addr: linear address where the data will be written to
+ * @data: the data to be written
+ * @size: the size of data
+ *
+ * Write data and verify.
+ * Every page will be tried for at most NMBM_TRY_COUNT times.
+ */
+static bool nmbn_write_verify_data(struct nmbm_instance *ni, uint64_t addr,
+				   const void *data, uint32_t size)
+{
+	uint64_t off = addr;
+	const uint8_t *ptr = data;
+	uint32_t sizeremain = size, chunksize, leading;
+	bool success;
+	int ret;
+
+	while (sizeremain) {
+		WATCHDOG_RESET();
+
+		leading = off & ni->writesize_mask;
+		chunksize = ni->lower.writesize - leading;
+		if (chunksize > sizeremain)
+			chunksize = sizeremain;
+
+		/* Prepare page data. fill 0xff to unused region */
+		memset(ni->page_cache, 0xff, ni->rawpage_size);
+		memcpy(ni->page_cache + leading, ptr, chunksize);
+
+		success = nmbm_write_phys_page(ni, off - leading,
+					       ni->page_cache, NULL,
+					       NMBM_MODE_PLACE_OOB);
+		if (!success)
+			return false;
+
+		/* Verify the data just written. ECC error indicates failure */
+		ret = nmbm_read_phys_page(ni, off - leading, ni->page_cache,
+					  NULL, NMBM_MODE_PLACE_OOB);
+		if (ret < 0)
+			return false;
+
+		if (memcmp(ni->page_cache + leading, ptr, chunksize))
+			return false;
+
+		off += chunksize;
+		ptr += chunksize;
+		sizeremain -= chunksize;
+	}
+
+	return true;
+}
+
+/*
+ * nmbm_write_mgmt_range - Write management data into NAND within a range
+ * @ni: NMBM instance structure
+ * @addr: preferred start block address for writing
+ * @limit: highest block address allowed for writing
+ * @data: the data to be written
+ * @size: the size of data
+ * @actual_start_ba: actual start block address of data
+ * @actual_end_ba: block address after the end of data
+ *
+ * @limit is not counted into the allowed write address.
+ */
+static bool nmbm_write_mgmt_range(struct nmbm_instance *ni, uint32_t ba,
+				  uint32_t limit, const void *data,
+				  uint32_t size, uint32_t *actual_start_ba,
+				  uint32_t *actual_end_ba)
+{
+	const uint8_t *ptr = data;
+	uint32_t sizeremain = size, chunksize;
+	bool success;
+
+	while (sizeremain && ba < limit) {
+		WATCHDOG_RESET();
+
+		chunksize = sizeremain;
+		if (chunksize > ni->lower.erasesize)
+			chunksize = ni->lower.erasesize;
+
+		if (nmbm_get_block_state(ni, ba) != BLOCK_ST_GOOD)
+			goto next_block;
+
+		/* Insurance to detect unexpected bad block marked by user */
+		if (nmbm_check_bad_phys_block(ni, ba)) {
+			nmbm_set_block_state(ni, ba, BLOCK_ST_BAD);
+			goto next_block;
+		}
+
+		success = nmbm_erase_block_and_check(ni, ba);
+		if (!success)
+			goto skip_bad_block;
+
+		success = nmbn_write_verify_data(ni, ba2addr(ni, ba), ptr,
+						 chunksize);
+		if (!success)
+			goto skip_bad_block;
+
+		if (sizeremain == size)
+			*actual_start_ba = ba;
+
+		ptr += chunksize;
+		sizeremain -= chunksize;
+
+		goto next_block;
+
+	skip_bad_block:
+		nmbm_mark_phys_bad_block(ni, ba);
+		nmbm_set_block_state(ni, ba, BLOCK_ST_BAD);
+
+	next_block:
+		ba++;
+	}
+
+	if (sizeremain)
+		return false;
+
+	*actual_end_ba = ba;
+
+	return true;
+}
+
+/*
+ * nmbm_generate_info_table_cache - Generate info table cache data
+ * @ni: NMBM instance structure
+ *
+ * Generate info table cache data to be written into flash.
+ */
+static bool nmbm_generate_info_table_cache(struct nmbm_instance *ni)
+{
+	bool changed = false;
+
+	memset(ni->info_table_cache, 0xff, ni->info_table_size);
+
+	memcpy(ni->info_table_cache + ni->info_table.state_table_off,
+	       ni->block_state, ni->state_table_size);
+
+	memcpy(ni->info_table_cache + ni->info_table.mapping_table_off,
+		ni->block_mapping, ni->mapping_table_size);
+
+	ni->info_table.header.magic = NMBM_MAGIC_INFO_TABLE;
+	ni->info_table.header.version = NMBM_VER;
+	ni->info_table.header.size = ni->info_table_size;
+
+	if (ni->block_state_changed || ni->block_mapping_changed) {
+		ni->info_table.write_count++;
+		changed = true;
+	}
+
+	memcpy(ni->info_table_cache, &ni->info_table, sizeof(ni->info_table));
+
+	nmbm_update_checksum((struct nmbm_header *)ni->info_table_cache);
+
+	return changed;
+}
+
+/*
+ * nmbm_write_info_table - Write info table into NAND within a range
+ * @ni: NMBM instance structure
+ * @ba: preferred start block address for writing
+ * @limit: highest block address allowed for writing
+ * @actual_start_ba: actual start block address of info table
+ * @actual_end_ba: block address after the end of info table
+ *
+ * @limit is counted into the allowed write address.
+ */
+static bool nmbm_write_info_table(struct nmbm_instance *ni, uint32_t ba,
+				  uint32_t limit, uint32_t *actual_start_ba,
+				  uint32_t *actual_end_ba)
+{
+	return nmbm_write_mgmt_range(ni, ba, limit, ni->info_table_cache,
+				     ni->info_table_size, actual_start_ba,
+				     actual_end_ba);
+}
+
+/*
+ * nmbm_mark_tables_clean - Mark info table `clean'
+ * @ni: NMBM instance structure
+ */
+static void nmbm_mark_tables_clean(struct nmbm_instance *ni)
+{
+	ni->block_state_changed = 0;
+	ni->block_mapping_changed = 0;
+}
+
+/*
+ * nmbm_try_reserve_blocks - Reserve blocks with compromisation
+ * @ni: NMBM instance structure
+ * @ba: start physical block address
+ * @nba: return physical block address after reservation
+ * @count: number of good blocks to be skipped
+ * @min_count: minimum number of good blocks to be skipped
+ * @limit: highest/lowest block address allowed for walking
+ *
+ * Reserve specific blocks. If failed, try to reserve as many as possible.
+ */
+static bool nmbm_try_reserve_blocks(struct nmbm_instance *ni, uint32_t ba,
+				    uint32_t *nba, uint32_t count,
+				    int32_t min_count, int32_t limit)
+{
+	int32_t nblocks = count;
+	bool success;
+
+	while (nblocks >= min_count) {
+		success = nmbm_block_walk(ni, true, ba, nba, nblocks, limit);
+		if (success)
+			return true;
+
+		nblocks--;
+	}
+
+	return false;
+}
+
+/*
+ * nmbm_rebuild_info_table - Build main & backup info table from scratch
+ * @ni: NMBM instance structure
+ * @allow_no_gap: allow no spare blocks between two tables
+ */
+static bool nmbm_rebuild_info_table(struct nmbm_instance *ni)
+{
+	uint32_t table_start_ba, table_end_ba, next_start_ba;
+	uint32_t main_table_end_ba;
+	bool success;
+
+	/* Set initial value */
+	ni->main_table_ba = 0;
+	ni->backup_table_ba = 0;
+	ni->mapping_blocks_ba = ni->mapping_blocks_top_ba;
+
+	/* Write main table */
+	success = nmbm_write_info_table(ni, ni->mgmt_start_ba,
+					ni->mapping_blocks_top_ba,
+					&table_start_ba, &table_end_ba);
+	if (!success) {
+		/* Failed to write main table, data will be lost */
+		nlog_emerg(ni, "Unable to write at least one info table!\n");
+		nlog_emerg(ni, "Please save your data before power off!\n");
+		ni->protected = 1;
+		return false;
+	}
+
+	/* Main info table is successfully written, record its offset */
+	ni->main_table_ba = table_start_ba;
+	main_table_end_ba = table_end_ba;
+
+	/* Adjust mapping_blocks_ba */
+	ni->mapping_blocks_ba = table_end_ba;
+
+	nmbm_mark_tables_clean(ni);
+
+	nlog_table_creation(ni, true, table_start_ba, table_end_ba);
+
+	/* Reserve spare blocks for main info table. */
+	success = nmbm_try_reserve_blocks(ni, table_end_ba,
+					  &next_start_ba,
+					  ni->info_table_spare_blocks, 0,
+					  ni->mapping_blocks_top_ba -
+					  size2blk(ni, ni->info_table_size));
+	if (!success) {
+		/* There is no spare block. */
+		nlog_debug(ni, "No room for backup info table\n");
+		return true;
+	}
+
+	/* Write backup info table. */
+	success = nmbm_write_info_table(ni, next_start_ba,
+					ni->mapping_blocks_top_ba,
+					&table_start_ba, &table_end_ba);
+	if (!success) {
+		/* There is no enough blocks for backup table. */
+		nlog_debug(ni, "No room for backup info table\n");
+		return true;
+	}
+
+	/* Backup table is successfully written, record its offset */
+	ni->backup_table_ba = table_start_ba;
+
+	/* Adjust mapping_blocks_off */
+	ni->mapping_blocks_ba = table_end_ba;
+
+	/* Erase spare blocks of main table to clean possible interference data */
+	nmbm_erase_range(ni, main_table_end_ba, ni->backup_table_ba);
+
+	nlog_table_creation(ni, false, table_start_ba, table_end_ba);
+
+	return true;
+}
+
+/*
+ * nmbm_rescue_single_info_table - Rescue when there is only one info table
+ * @ni: NMBM instance structure
+ *
+ * This function is called when there is only one info table exists.
+ * This function may fail if we can't write new info table
+ */
+static bool nmbm_rescue_single_info_table(struct nmbm_instance *ni)
+{
+	uint32_t table_start_ba, table_end_ba, write_ba;
+	bool success;
+
+	/* Try to write new info table in front of existing table */
+	success = nmbm_write_info_table(ni, ni->mgmt_start_ba,
+					ni->main_table_ba,
+					&table_start_ba,
+					&table_end_ba);
+	if (success) {
+		/*
+		 * New table becomes the main table, existing table becomes
+		 * the backup table.
+		 */
+		ni->backup_table_ba = ni->main_table_ba;
+		ni->main_table_ba = table_start_ba;
+
+		nmbm_mark_tables_clean(ni);
+
+		/* Erase spare blocks of main table to clean possible interference data */
+		nmbm_erase_range(ni, table_end_ba, ni->backup_table_ba);
+
+		nlog_table_creation(ni, true, table_start_ba, table_end_ba);
+
+		return true;
+	}
+
+	/* Try to reserve spare blocks for existing table */
+	success = nmbm_try_reserve_blocks(ni, ni->mapping_blocks_ba, &write_ba,
+					  ni->info_table_spare_blocks, 0,
+					  ni->mapping_blocks_top_ba -
+					  size2blk(ni, ni->info_table_size));
+	if (!success) {
+		nlog_warn(ni, "Failed to rescue single info table\n");
+		return false;
+	}
+
+	/* Try to write new info table next to the existing table */
+	while (write_ba >= ni->mapping_blocks_ba) {
+		WATCHDOG_RESET();
+
+		success = nmbm_write_info_table(ni, write_ba,
+						ni->mapping_blocks_top_ba,
+						&table_start_ba,
+						&table_end_ba);
+		if (success)
+			break;
+
+		write_ba--;
+	}
+
+	if (success) {
+		/* Erase spare blocks of main table to clean possible interference data */
+		nmbm_erase_range(ni, ni->mapping_blocks_ba, table_start_ba);
+
+		/* New table becomes the backup table */
+		ni->backup_table_ba = table_start_ba;
+		ni->mapping_blocks_ba = table_end_ba;
+
+		nmbm_mark_tables_clean(ni);
+
+		nlog_table_creation(ni, false, table_start_ba, table_end_ba);
+
+		return true;
+	}
+
+	nlog_warn(ni, "Failed to rescue single info table\n");
+	return false;
+}
+
+/*
+ * nmbm_update_single_info_table - Update specific one info table
+ * @ni: NMBM instance structure
+ */
+static bool nmbm_update_single_info_table(struct nmbm_instance *ni,
+					  bool update_main_table)
+{
+	uint32_t write_start_ba, write_limit, table_start_ba, table_end_ba;
+	bool success;
+
+	/* Determine the write range */
+	if (update_main_table) {
+		write_start_ba = ni->main_table_ba;
+		write_limit = ni->backup_table_ba;
+	} else {
+		write_start_ba = ni->backup_table_ba;
+		write_limit = ni->mapping_blocks_top_ba;
+	}
+
+	nmbm_mark_block_color_mgmt(ni, write_start_ba, write_limit - 1);
+
+	success = nmbm_write_info_table(ni, write_start_ba, write_limit,
+					&table_start_ba, &table_end_ba);
+	if (success) {
+		if (update_main_table) {
+			ni->main_table_ba = table_start_ba;
+		} else {
+			ni->backup_table_ba = table_start_ba;
+			ni->mapping_blocks_ba = table_end_ba;
+		}
+
+		nmbm_mark_tables_clean(ni);
+
+		nlog_table_update(ni, update_main_table, table_start_ba,
+				 table_end_ba);
+
+		return true;
+	}
+
+	if (update_main_table) {
+		/*
+		 * If failed to update main table, make backup table the new
+		 * main table, and call nmbm_rescue_single_info_table()
+		 */
+		nlog_warn(ni, "Unable to update %s info table\n",
+			 update_main_table ? "Main" : "Backup");
+
+		ni->main_table_ba = ni->backup_table_ba;
+		ni->backup_table_ba = 0;
+		return nmbm_rescue_single_info_table(ni);
+	}
+
+	/* Only one table left */
+	ni->mapping_blocks_ba = ni->backup_table_ba;
+	ni->backup_table_ba = 0;
+
+	return false;
+}
+
+/*
+ * nmbm_rescue_main_info_table - Rescue when failed to write main info table
+ * @ni: NMBM instance structure
+ *
+ * This function is called when main info table failed to be written, and
+ *    backup info table exists.
+ */
+static bool nmbm_rescue_main_info_table(struct nmbm_instance *ni)
+{
+	uint32_t tmp_table_start_ba, tmp_table_end_ba, main_table_start_ba;
+	uint32_t main_table_end_ba, write_ba;
+	uint32_t info_table_erasesize = size2blk(ni, ni->info_table_size);
+	bool success;
+
+	/* Try to reserve spare blocks for existing backup info table */
+	success = nmbm_try_reserve_blocks(ni, ni->mapping_blocks_ba, &write_ba,
+					  ni->info_table_spare_blocks, 0,
+					  ni->mapping_blocks_top_ba -
+					  info_table_erasesize);
+	if (!success) {
+		/* There is no spare block. Backup info table becomes the main table. */
+		nlog_err(ni, "No room for temporary info table\n");
+		ni->main_table_ba = ni->backup_table_ba;
+		ni->backup_table_ba = 0;
+		return true;
+	}
+
+	/* Try to write temporary info table into spare unmapped blocks */
+	while (write_ba >= ni->mapping_blocks_ba) {
+		WATCHDOG_RESET();
+
+		success = nmbm_write_info_table(ni, write_ba,
+						ni->mapping_blocks_top_ba,
+						&tmp_table_start_ba,
+						&tmp_table_end_ba);
+		if (success)
+			break;
+
+		write_ba--;
+	}
+
+	if (!success) {
+		/* Backup info table becomes the main table */
+		nlog_err(ni, "Failed to update main info table\n");
+		ni->main_table_ba = ni->backup_table_ba;
+		ni->backup_table_ba = 0;
+		return true;
+	}
+
+	/* Adjust mapping_blocks_off */
+	ni->mapping_blocks_ba = tmp_table_end_ba;
+
+	nmbm_mark_block_color_mgmt(ni, ni->backup_table_ba,
+				   tmp_table_end_ba - 1);
+
+	/*
+	 * Now write main info table at the beginning of management area.
+	 * This operation will generally destroy the original backup info
+	 * table.
+	 */
+	success = nmbm_write_info_table(ni, ni->mgmt_start_ba,
+					tmp_table_start_ba,
+					&main_table_start_ba,
+					&main_table_end_ba);
+	if (!success) {
+		/* Temporary info table becomes the main table */
+		ni->main_table_ba = tmp_table_start_ba;
+		ni->backup_table_ba = 0;
+
+		nmbm_mark_tables_clean(ni);
+
+		nlog_err(ni, "Failed to update main info table\n");
+		nmbm_mark_block_color_info_table(ni, tmp_table_start_ba,
+						 tmp_table_end_ba - 1);
+
+		return true;
+	}
+
+	/* Main info table has been successfully written, record its offset */
+	ni->main_table_ba = main_table_start_ba;
+
+	nmbm_mark_tables_clean(ni);
+
+	nlog_table_creation(ni, true, main_table_start_ba, main_table_end_ba);
+
+	/*
+	 * Temporary info table becomes the new backup info table if it's
+	 * not overwritten.
+	 */
+	if (main_table_end_ba <= tmp_table_start_ba) {
+		ni->backup_table_ba = tmp_table_start_ba;
+
+		nlog_table_creation(ni, false, tmp_table_start_ba,
+				   tmp_table_end_ba);
+
+		return true;
+	}
+
+	/* Adjust mapping_blocks_off */
+	ni->mapping_blocks_ba = main_table_end_ba;
+
+	/* Try to reserve spare blocks for new main info table */
+	success = nmbm_try_reserve_blocks(ni, main_table_end_ba, &write_ba,
+					  ni->info_table_spare_blocks, 0,
+					  ni->mapping_blocks_top_ba -
+					  info_table_erasesize);
+	if (!success) {
+		/* There is no spare block. Only main table exists. */
+		nlog_err(ni, "No room for backup info table\n");
+		ni->backup_table_ba = 0;
+		return true;
+	}
+
+	/* Write new backup info table. */
+	while (write_ba >= main_table_end_ba) {
+		WATCHDOG_RESET();
+
+		success = nmbm_write_info_table(ni, write_ba,
+						ni->mapping_blocks_top_ba,
+						&tmp_table_start_ba,
+						&tmp_table_end_ba);
+		if (success)
+			break;
+
+		write_ba--;
+	}
+
+	if (!success) {
+		nlog_err(ni, "No room for backup info table\n");
+		ni->backup_table_ba = 0;
+		return true;
+	}
+
+	/* Backup info table has been successfully written, record its offset */
+	ni->backup_table_ba = tmp_table_start_ba;
+
+	/* Adjust mapping_blocks_off */
+	ni->mapping_blocks_ba = tmp_table_end_ba;
+
+	/* Erase spare blocks of main table to clean possible interference data */
+	nmbm_erase_range(ni, main_table_end_ba, ni->backup_table_ba);
+
+	nlog_table_creation(ni, false, tmp_table_start_ba, tmp_table_end_ba);
+
+	return true;
+}
+
+/*
+ * nmbm_update_info_table_once - Update info table once
+ * @ni: NMBM instance structure
+ * @force: force update
+ *
+ * Update both main and backup info table. Return true if at least one info
+ * table has been successfully written.
+ * This function only try to update info table once regard less of the result.
+ */
+static bool nmbm_update_info_table_once(struct nmbm_instance *ni, bool force)
+{
+	uint32_t table_start_ba, table_end_ba;
+	uint32_t main_table_limit;
+	bool success;
+
+	/* Do nothing if there is no change */
+	if (!nmbm_generate_info_table_cache(ni) && !force)
+		return true;
+
+	/* Check whether both two tables exist */
+	if (!ni->backup_table_ba) {
+		main_table_limit = ni->mapping_blocks_top_ba;
+		goto write_main_table;
+	}
+
+	nmbm_mark_block_color_mgmt(ni, ni->backup_table_ba,
+				   ni->mapping_blocks_ba - 1);
+
+	/*
+	 * Write backup info table in its current range.
+	 * Note that limit is set to mapping_blocks_top_off to provide as many
+	 * spare blocks as possible for the backup table. If at last
+	 * unmapped blocks are used by backup table, mapping_blocks_off will
+	 * be adjusted.
+	 */
+	success = nmbm_write_info_table(ni, ni->backup_table_ba,
+					ni->mapping_blocks_top_ba,
+					&table_start_ba, &table_end_ba);
+	if (!success) {
+		/*
+		 * There is nothing to do if failed to write backup table.
+		 * Write the main table now.
+		 */
+		nlog_err(ni, "No room for backup table\n");
+		ni->mapping_blocks_ba = ni->backup_table_ba;
+		ni->backup_table_ba = 0;
+		main_table_limit = ni->mapping_blocks_top_ba;
+		goto write_main_table;
+	}
+
+	/* Backup table is successfully written, record its offset */
+	ni->backup_table_ba = table_start_ba;
+
+	/* Adjust mapping_blocks_off */
+	ni->mapping_blocks_ba = table_end_ba;
+
+	nmbm_mark_tables_clean(ni);
+
+	/* The normal limit of main table */
+	main_table_limit = ni->backup_table_ba;
+
+	nlog_table_update(ni, false, table_start_ba, table_end_ba);
+
+write_main_table:
+	if (!ni->main_table_ba)
+		goto rebuild_tables;
+
+	if (!ni->backup_table_ba)
+		nmbm_mark_block_color_mgmt(ni, ni->mgmt_start_ba,
+					   ni->mapping_blocks_ba - 1);
+	else
+		nmbm_mark_block_color_mgmt(ni, ni->mgmt_start_ba,
+					   ni->backup_table_ba - 1);
+
+	/* Write main info table in its current range */
+	success = nmbm_write_info_table(ni, ni->main_table_ba,
+					main_table_limit, &table_start_ba,
+					&table_end_ba);
+	if (!success) {
+		/* If failed to write main table, go rescue procedure */
+		if (!ni->backup_table_ba)
+			goto rebuild_tables;
+
+		return nmbm_rescue_main_info_table(ni);
+	}
+
+	/* Main info table is successfully written, record its offset */
+	ni->main_table_ba = table_start_ba;
+
+	/* Adjust mapping_blocks_off */
+	if (!ni->backup_table_ba)
+		ni->mapping_blocks_ba = table_end_ba;
+
+	nmbm_mark_tables_clean(ni);
+
+	nlog_table_update(ni, true, table_start_ba, table_end_ba);
+
+	return true;
+
+rebuild_tables:
+	return nmbm_rebuild_info_table(ni);
+}
+
+/*
+ * nmbm_update_info_table - Update info table
+ * @ni: NMBM instance structure
+ *
+ * Update both main and backup info table. Return true if at least one table
+ * has been successfully written.
+ * This function will try to update info table repeatedly until no new bad
+ * block found during updating.
+ */
+static bool nmbm_update_info_table(struct nmbm_instance *ni)
+{
+	bool success;
+
+	if (ni->protected)
+		return true;
+
+	while (ni->block_state_changed || ni->block_mapping_changed) {
+		success = nmbm_update_info_table_once(ni, false);
+		if (!success) {
+			nlog_err(ni, "Failed to update info table\n");
+			return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * nmbm_map_block - Map a bad block to a unused spare block
+ * @ni: NMBM instance structure
+ * @lb: logic block addr to map
+ */
+static bool nmbm_map_block(struct nmbm_instance *ni, uint32_t lb)
+{
+	uint32_t pb;
+	bool success;
+
+	if (ni->mapping_blocks_ba == ni->mapping_blocks_top_ba) {
+		nlog_warn(ni, "No spare unmapped blocks.\n");
+		return false;
+	}
+
+	success = nmbm_block_walk(ni, false, ni->mapping_blocks_top_ba, &pb, 0,
+				  ni->mapping_blocks_ba);
+	if (!success) {
+		nlog_warn(ni, "No spare unmapped blocks.\n");
+		nmbm_update_info_table(ni);
+		ni->mapping_blocks_top_ba = ni->mapping_blocks_ba;
+		return false;
+	}
+
+	ni->block_mapping[lb] = pb;
+	ni->mapping_blocks_top_ba--;
+	ni->block_mapping_changed++;
+
+	nlog_info(ni, "Logic block %u mapped to physical blcok %u\n", lb, pb);
+	nmbm_mark_block_color_mapped(ni, pb);
+
+	return true;
+}
+
+/*
+ * nmbm_create_info_table - Create info table(s)
+ * @ni: NMBM instance structure
+ *
+ * This function assumes that the chip has no existing info table(s)
+ */
+static bool nmbm_create_info_table(struct nmbm_instance *ni)
+{
+	uint32_t lb;
+	bool success;
+
+	/* Set initial mapping_blocks_top_off  */
+	success = nmbm_block_walk(ni, false, ni->signature_ba,
+				  &ni->mapping_blocks_top_ba, 1,
+				  ni->mgmt_start_ba);
+	if (!success) {
+		nlog_err(ni, "No room for spare blocks\n");
+		return false;
+	}
+
+	/* Generate info table cache */
+	nmbm_generate_info_table_cache(ni);
+
+	/* Write info table */
+	success = nmbm_rebuild_info_table(ni);
+	if (!success) {
+		nlog_err(ni, "Failed to build info tables\n");
+		return false;
+	}
+
+	/* Remap bad block(s) at end of data area */
+	for (lb = ni->data_block_count; lb < ni->mgmt_start_ba; lb++) {
+		success = nmbm_map_block(ni, lb);
+		if (!success)
+			break;
+
+		ni->data_block_count++;
+	}
+
+	/* If state table and/or mapping table changed, update info table. */
+	success = nmbm_update_info_table(ni);
+	if (!success)
+		return false;
+
+	return true;
+}
+
+/*
+ * nmbm_create_new - Create NMBM on a new chip
+ * @ni: NMBM instance structure
+ */
+static bool nmbm_create_new(struct nmbm_instance *ni)
+{
+	bool success;
+
+	/* Determine the boundary of management blocks */
+	ni->mgmt_start_ba = ni->block_count * (NMBM_MGMT_DIV - ni->lower.max_ratio) / NMBM_MGMT_DIV;
+
+	if (ni->lower.max_reserved_blocks && ni->block_count - ni->mgmt_start_ba > ni->lower.max_reserved_blocks)
+		ni->mgmt_start_ba = ni->block_count - ni->lower.max_reserved_blocks;
+
+	nlog_info(ni, "NMBM management region starts at block %u [0x%08llx]\n",
+		  ni->mgmt_start_ba, ba2addr(ni, ni->mgmt_start_ba));
+	nmbm_mark_block_color_mgmt(ni, ni->mgmt_start_ba, ni->block_count - 1);
+
+	/* Fill block state table & mapping table */
+	nmbm_scan_badblocks(ni);
+	nmbm_build_mapping_table(ni);
+
+	/* Write signature */
+	ni->signature.header.magic = NMBM_MAGIC_SIGNATURE;
+	ni->signature.header.version = NMBM_VER;
+	ni->signature.header.size = sizeof(ni->signature);
+	ni->signature.nand_size = ni->lower.size;
+	ni->signature.block_size = ni->lower.erasesize;
+	ni->signature.page_size = ni->lower.writesize;
+	ni->signature.spare_size = ni->lower.oobsize;
+	ni->signature.mgmt_start_pb = ni->mgmt_start_ba;
+	ni->signature.max_try_count = NMBM_TRY_COUNT;
+	nmbm_update_checksum(&ni->signature.header);
+
+	if (ni->lower.flags & NMBM_F_READ_ONLY) {
+		nlog_info(ni, "NMBM has been initialized in read-only mode\n");
+		return true;
+	}
+
+	success = nmbm_write_signature(ni, ni->mgmt_start_ba,
+				       &ni->signature, &ni->signature_ba);
+	if (!success) {
+		nlog_err(ni, "Failed to write signature to a proper offset\n");
+		return false;
+	}
+
+	nlog_info(ni, "Signature has been written to block %u [0x%08llx]\n",
+		 ni->signature_ba, ba2addr(ni, ni->signature_ba));
+	nmbm_mark_block_color_signature(ni, ni->signature_ba);
+
+	/* Write info table(s) */
+	success = nmbm_create_info_table(ni);
+	if (success) {
+		nlog_info(ni, "NMBM has been successfully created\n");
+		return true;
+	}
+
+	return false;
+}
+
+/*
+ * nmbm_check_info_table_header - Check if a info table header is valid
+ * @ni: NMBM instance structure
+ * @data: pointer to the info table header
+ */
+static bool nmbm_check_info_table_header(struct nmbm_instance *ni, void *data)
+{
+	struct nmbm_info_table_header *ifthdr = data;
+
+	if (ifthdr->header.magic != NMBM_MAGIC_INFO_TABLE)
+		return false;
+
+	if (ifthdr->header.size != ni->info_table_size)
+		return false;
+
+	if (ifthdr->mapping_table_off - ifthdr->state_table_off < ni->state_table_size)
+		return false;
+
+	if (ni->info_table_size - ifthdr->mapping_table_off < ni->mapping_table_size)
+		return false;
+
+	return true;
+}
+
+/*
+ * nmbm_check_info_table - Check if a whole info table is valid
+ * @ni: NMBM instance structure
+ * @start_ba: start block address of this table
+ * @end_ba: end block address of this table
+ * @data: pointer to the info table header
+ * @mapping_blocks_top_ba: return the block address of top remapped block
+ */
+static bool nmbm_check_info_table(struct nmbm_instance *ni, uint32_t start_ba,
+				  uint32_t end_ba, void *data,
+				  uint32_t *mapping_blocks_top_ba)
+{
+	struct nmbm_info_table_header *ifthdr = data;
+	int32_t *block_mapping = (int32_t *)((uintptr_t)data + ifthdr->mapping_table_off);
+	nmbm_bitmap_t *block_state = (nmbm_bitmap_t *)((uintptr_t)data + ifthdr->state_table_off);
+	uint32_t minimum_mapping_pb = ni->signature_ba;
+	uint32_t ba;
+
+	for (ba = 0; ba < ni->data_block_count; ba++) {
+		if ((block_mapping[ba] >= ni->data_block_count && block_mapping[ba] < end_ba) ||
+		    block_mapping[ba] == ni->signature_ba)
+			return false;
+
+		if (block_mapping[ba] >= end_ba && block_mapping[ba] < minimum_mapping_pb)
+			minimum_mapping_pb = block_mapping[ba];
+	}
+
+	for (ba = start_ba; ba < end_ba; ba++) {
+		if (nmbm_get_block_state(ni, ba) != BLOCK_ST_GOOD)
+			continue;
+
+		if (nmbm_get_block_state_raw(block_state, ba) != BLOCK_ST_GOOD)
+			return false;
+	}
+
+	*mapping_blocks_top_ba = minimum_mapping_pb - 1;
+
+	return true;
+}
+
+/*
+ * nmbm_try_load_info_table - Try to load info table from a address
+ * @ni: NMBM instance structure
+ * @ba: start block address of the info table
+ * @eba: return the block address after end of the table
+ * @write_count: return the write count of this table
+ * @mapping_blocks_top_ba: return the block address of top remapped block
+ * @table_loaded: used to record whether ni->info_table has valid data
+ */
+static bool nmbm_try_load_info_table(struct nmbm_instance *ni, uint32_t ba,
+				     uint32_t *eba, uint32_t *write_count,
+				     uint32_t *mapping_blocks_top_ba,
+				     bool table_loaded)
+{
+	struct nmbm_info_table_header *ifthdr = (void *)ni->info_table_cache;
+	uint8_t *off = ni->info_table_cache;
+	uint32_t limit = ba + size2blk(ni, ni->info_table_size);
+	uint32_t start_ba = 0, chunksize, sizeremain = ni->info_table_size;
+	bool success, checkhdr = true;
+	int ret;
+
+	while (sizeremain && ba < limit) {
+		WATCHDOG_RESET();
+
+		if (nmbm_get_block_state(ni, ba) != BLOCK_ST_GOOD)
+			goto next_block;
+
+		if (nmbm_check_bad_phys_block(ni, ba)) {
+			nmbm_set_block_state(ni, ba, BLOCK_ST_BAD);
+			goto next_block;
+		}
+
+		chunksize = sizeremain;
+		if (chunksize > ni->lower.erasesize)
+			chunksize = ni->lower.erasesize;
+
+		/* Assume block with ECC error has no info table data */
+		ret = nmbn_read_data(ni, ba2addr(ni, ba), off, chunksize);
+		if (ret < 0)
+			goto skip_bad_block;
+		else if (ret > 0)
+			return false;
+
+		if (checkhdr) {
+			success = nmbm_check_info_table_header(ni, off);
+			if (!success)
+				return false;
+
+			start_ba = ba;
+			checkhdr = false;
+		}
+
+		off += chunksize;
+		sizeremain -= chunksize;
+
+		goto next_block;
+
+	skip_bad_block:
+		/* Only mark bad in memory */
+		nmbm_set_block_state(ni, ba, BLOCK_ST_BAD);
+
+	next_block:
+		ba++;
+	}
+
+	if (sizeremain)
+		return false;
+
+	success = nmbm_check_header(ni->info_table_cache, ni->info_table_size);
+	if (!success)
+		return false;
+
+	*eba = ba;
+	*write_count = ifthdr->write_count;
+
+	success = nmbm_check_info_table(ni, start_ba, ba, ni->info_table_cache,
+					mapping_blocks_top_ba);
+	if (!success)
+		return false;
+
+	if (!table_loaded || ifthdr->write_count > ni->info_table.write_count) {
+		memcpy(&ni->info_table, ifthdr, sizeof(ni->info_table));
+		memcpy(ni->block_state,
+		       (uint8_t *)ifthdr + ifthdr->state_table_off,
+		       ni->state_table_size);
+		memcpy(ni->block_mapping,
+		       (uint8_t *)ifthdr + ifthdr->mapping_table_off,
+		       ni->mapping_table_size);
+		ni->info_table.write_count = ifthdr->write_count;
+	}
+
+	return true;
+}
+
+/*
+ * nmbm_search_info_table - Search info table from specific address
+ * @ni: NMBM instance structure
+ * @ba: start block address to search
+ * @limit: highest block address allowed for searching
+ * @table_start_ba: return the start block address of this table
+ * @table_end_ba: return the block address after end of this table
+ * @write_count: return the write count of this table
+ * @mapping_blocks_top_ba: return the block address of top remapped block
+ * @table_loaded: used to record whether ni->info_table has valid data
+ */
+static bool nmbm_search_info_table(struct nmbm_instance *ni, uint32_t ba,
+				   uint32_t limit, uint32_t *table_start_ba,
+				   uint32_t *table_end_ba,
+				   uint32_t *write_count,
+				   uint32_t *mapping_blocks_top_ba,
+				   bool table_loaded)
+{
+	bool success;
+
+	while (ba < limit - size2blk(ni, ni->info_table_size)) {
+		WATCHDOG_RESET();
+
+		success = nmbm_try_load_info_table(ni, ba, table_end_ba,
+						   write_count,
+						   mapping_blocks_top_ba,
+						   table_loaded);
+		if (success) {
+			*table_start_ba = ba;
+			return true;
+		}
+
+		ba++;
+	}
+
+	return false;
+}
+
+/*
+ * nmbm_load_info_table - Load info table(s) from a chip
+ * @ni: NMBM instance structure
+ * @ba: start block address to search info table
+ * @limit: highest block address allowed for searching
+ */
+static bool nmbm_load_info_table(struct nmbm_instance *ni, uint32_t ba,
+				 uint32_t limit)
+{
+	uint32_t main_table_end_ba, backup_table_end_ba, table_end_ba;
+	uint32_t main_mapping_blocks_top_ba, backup_mapping_blocks_top_ba;
+	uint32_t main_table_write_count, backup_table_write_count;
+	uint32_t i;
+	bool success;
+
+	/* Set initial value */
+	ni->main_table_ba = 0;
+	ni->backup_table_ba = 0;
+	ni->info_table.write_count = 0;
+	ni->mapping_blocks_top_ba = ni->signature_ba - 1;
+	ni->data_block_count = ni->signature.mgmt_start_pb;
+
+	/* Find first info table */
+	success = nmbm_search_info_table(ni, ba, limit, &ni->main_table_ba,
+		&main_table_end_ba, &main_table_write_count,
+		&main_mapping_blocks_top_ba, false);
+	if (!success) {
+		nlog_warn(ni, "No valid info table found\n");
+		return false;
+	}
+
+	table_end_ba = main_table_end_ba;
+
+	nlog_table_found(ni, true, main_table_write_count, ni->main_table_ba,
+			main_table_end_ba);
+
+	/* Find second info table */
+	success = nmbm_search_info_table(ni, main_table_end_ba, limit,
+		&ni->backup_table_ba, &backup_table_end_ba,
+		&backup_table_write_count, &backup_mapping_blocks_top_ba, true);
+	if (!success) {
+		nlog_warn(ni, "Second info table not found\n");
+	} else {
+		table_end_ba = backup_table_end_ba;
+
+		nlog_table_found(ni, false, backup_table_write_count,
+				ni->backup_table_ba, backup_table_end_ba);
+	}
+
+	/* Pick mapping_blocks_top_ba */
+	if (!ni->backup_table_ba) {
+		ni->mapping_blocks_top_ba= main_mapping_blocks_top_ba;
+	} else {
+		if (main_table_write_count >= backup_table_write_count)
+			ni->mapping_blocks_top_ba = main_mapping_blocks_top_ba;
+		else
+			ni->mapping_blocks_top_ba = backup_mapping_blocks_top_ba;
+	}
+
+	/* Set final mapping_blocks_ba */
+	ni->mapping_blocks_ba = table_end_ba;
+
+	/* Set final data_block_count */
+	for (i = ni->signature.mgmt_start_pb; i > 0; i--) {
+		if (ni->block_mapping[i - 1] >= 0) {
+			ni->data_block_count = i;
+			break;
+		}
+	}
+
+	/* Debug purpose: mark mapped blocks and bad blocks */
+	for (i = 0; i < ni->data_block_count; i++) {
+		if (ni->block_mapping[i] > ni->mapping_blocks_top_ba)
+			nmbm_mark_block_color_mapped(ni, ni->block_mapping[i]);
+	}
+
+	for (i = 0; i < ni->block_count; i++) {
+		if (nmbm_get_block_state(ni, i) == BLOCK_ST_BAD)
+			nmbm_mark_block_color_bad(ni, i);
+	}
+
+	/* Regenerate the info table cache from the final selected info table */
+	nmbm_generate_info_table_cache(ni);
+
+	if (ni->lower.flags & NMBM_F_READ_ONLY)
+		return true;
+
+	/*
+	 * If only one table exists, try to write another table.
+	 * If two tables have different write count, try to update info table
+	 */
+	if (!ni->backup_table_ba) {
+		success = nmbm_rescue_single_info_table(ni);
+	} else if (main_table_write_count != backup_table_write_count) {
+		/* Mark state & mapping tables changed */
+		ni->block_state_changed = 1;
+		ni->block_mapping_changed = 1;
+
+		success = nmbm_update_single_info_table(ni,
+			main_table_write_count < backup_table_write_count);
+	} else {
+		success = true;
+	}
+
+	/*
+	 * If there is no spare unmapped blocks, or still only one table
+	 * exists, set the chip to read-only
+	 */
+	if (ni->mapping_blocks_ba == ni->mapping_blocks_top_ba) {
+		nlog_warn(ni, "No spare unmapped blocks. Device is now read-only\n");
+		ni->protected = 1;
+	} else if (!success) {
+		nlog_warn(ni, "Only one info table found. Device is now read-only\n");
+		ni->protected = 1;
+	}
+
+	return true;
+}
+
+/*
+ * nmbm_load_existing - Load NMBM from a new chip
+ * @ni: NMBM instance structure
+ */
+static bool nmbm_load_existing(struct nmbm_instance *ni)
+{
+	bool success;
+
+	/* Calculate the boundary of management blocks */
+	ni->mgmt_start_ba = ni->signature.mgmt_start_pb;
+
+	nlog_debug(ni, "NMBM management region starts at block %u [0x%08llx]\n",
+		  ni->mgmt_start_ba, ba2addr(ni, ni->mgmt_start_ba));
+	nmbm_mark_block_color_mgmt(ni, ni->mgmt_start_ba,
+				   ni->signature_ba - 1);
+
+	/* Look for info table(s) */
+	success = nmbm_load_info_table(ni, ni->mgmt_start_ba,
+		ni->signature_ba);
+	if (success) {
+		nlog_info(ni, "NMBM has been successfully attached %s\n",
+			  (ni->lower.flags & NMBM_F_READ_ONLY) ? "in read-only mode" : "");
+		return true;
+	}
+
+	if (!(ni->lower.flags & NMBM_F_CREATE))
+		return false;
+
+	/* Fill block state table & mapping table */
+	nmbm_scan_badblocks(ni);
+	nmbm_build_mapping_table(ni);
+
+	if (ni->lower.flags & NMBM_F_READ_ONLY) {
+		nlog_info(ni, "NMBM has been initialized in read-only mode\n");
+		return true;
+	}
+
+	/* Write info table(s) */
+	success = nmbm_create_info_table(ni);
+	if (success) {
+		nlog_info(ni, "NMBM has been successfully created\n");
+		return true;
+	}
+
+	return false;
+}
+
+/*
+ * nmbm_find_signature - Find signature in the lower NAND chip
+ * @ni: NMBM instance structure
+ * @signature_ba: used for storing block address of the signature
+ * @signature_ba: return the actual block address of signature block
+ *
+ * Find a valid signature from a specific range in the lower NAND chip,
+ * from bottom (highest address) to top (lowest address)
+ *
+ * Return true if found.
+ */
+static bool nmbm_find_signature(struct nmbm_instance *ni,
+				struct nmbm_signature *signature,
+				uint32_t *signature_ba)
+{
+	struct nmbm_signature sig;
+	uint64_t off, addr;
+	uint32_t block_count, ba, limit;
+	bool success;
+	int ret;
+
+	/* Calculate top and bottom block address */
+	block_count = ni->lower.size >> ni->erasesize_shift;
+	ba = block_count;
+	limit = (block_count / NMBM_MGMT_DIV) * (NMBM_MGMT_DIV - ni->lower.max_ratio);
+	if (ni->lower.max_reserved_blocks && block_count - limit > ni->lower.max_reserved_blocks)
+		limit = block_count - ni->lower.max_reserved_blocks;
+
+	while (ba >= limit) {
+		WATCHDOG_RESET();
+
+		ba--;
+		addr = ba2addr(ni, ba);
+
+		if (nmbm_check_bad_phys_block(ni, ba))
+			continue;
+
+		/* Check every page.
+		 * As long as at leaset one page contains valid signature,
+		 * the block is treated as a valid signature block.
+		 */
+		for (off = 0; off < ni->lower.erasesize;
+		     off += ni->lower.writesize) {
+			WATCHDOG_RESET();
+
+			ret = nmbn_read_data(ni, addr + off, &sig,
+					     sizeof(sig));
+			if (ret)
+				continue;
+
+			/* Check for header size and checksum */
+			success = nmbm_check_header(&sig, sizeof(sig));
+			if (!success)
+				continue;
+
+			/* Check for header magic */
+			if (sig.header.magic == NMBM_MAGIC_SIGNATURE) {
+				/* Found it */
+				memcpy(signature, &sig, sizeof(sig));
+				*signature_ba = ba;
+				return true;
+			}
+		}
+	};
+
+	return false;
+}
+
+/*
+ * is_power_of_2_u64 - Check whether a 64-bit integer is power of 2
+ * @n: number to check
+ */
+static bool is_power_of_2_u64(uint64_t n)
+{
+	return (n != 0 && ((n & (n - 1)) == 0));
+}
+
+/*
+ * nmbm_check_lower_members - Validate the members of lower NAND device
+ * @nld: Lower NAND chip structure
+ */
+static bool nmbm_check_lower_members(struct nmbm_lower_device *nld)
+{
+
+	if (!nld->size || !is_power_of_2_u64(nld->size)) {
+		nmbm_log_lower(nld, NMBM_LOG_ERR,
+			       "Chip size %llu is not valid\n", nld->size);
+		return false;
+	}
+
+	if (!nld->erasesize || !is_power_of_2(nld->erasesize)) {
+		nmbm_log_lower(nld, NMBM_LOG_ERR,
+			       "Block size %u is not valid\n", nld->erasesize);
+		return false;
+	}
+
+	if (!nld->writesize || !is_power_of_2(nld->writesize)) {
+		nmbm_log_lower(nld, NMBM_LOG_ERR,
+			       "Page size %u is not valid\n", nld->writesize);
+		return false;
+	}
+
+	if (!nld->oobsize || !is_power_of_2(nld->oobsize)) {
+		nmbm_log_lower(nld, NMBM_LOG_ERR,
+			       "Page spare size %u is not valid\n", nld->oobsize);
+		return false;
+	}
+
+	if (!nld->read_page) {
+		nmbm_log_lower(nld, NMBM_LOG_ERR, "read_page() is required\n");
+		return false;
+	}
+
+	if (!(nld->flags & NMBM_F_READ_ONLY) && (!nld->write_page || !nld->erase_block)) {
+		nmbm_log_lower(nld, NMBM_LOG_ERR,
+			       "write_page() and erase_block() are required\n");
+		return false;
+	}
+
+	/* Data sanity check */
+	if (!nld->max_ratio)
+		nld->max_ratio = 1;
+
+	if (nld->max_ratio >= NMBM_MGMT_DIV - 1) {
+		nmbm_log_lower(nld, NMBM_LOG_ERR,
+			       "max ratio %u is invalid\n", nld->max_ratio);
+		return false;
+	}
+
+	if (nld->max_reserved_blocks && nld->max_reserved_blocks < NMBM_MGMT_BLOCKS_MIN) {
+		nmbm_log_lower(nld, NMBM_LOG_ERR,
+			       "max reserved blocks %u is too small\n", nld->max_reserved_blocks);
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ * nmbm_calc_structure_size - Calculate the instance structure size
+ * @nld: NMBM lower device structure
+ */
+size_t nmbm_calc_structure_size(struct nmbm_lower_device *nld)
+{
+	uint32_t state_table_size, mapping_table_size, info_table_size;
+	uint32_t block_count;
+
+	block_count = nmbm_lldiv(nld->size, nld->erasesize);
+
+	/* Calculate info table size */
+	state_table_size = ((block_count + NMBM_BITMAP_BLOCKS_PER_UNIT - 1) /
+		NMBM_BITMAP_BLOCKS_PER_UNIT) * NMBM_BITMAP_UNIT_SIZE;
+	mapping_table_size = block_count * sizeof(int32_t);
+
+	info_table_size = NMBM_ALIGN(sizeof(struct nmbm_info_table_header),
+				     nld->writesize);
+	info_table_size += NMBM_ALIGN(state_table_size, nld->writesize);
+	info_table_size += NMBM_ALIGN(mapping_table_size, nld->writesize);
+
+	return info_table_size + state_table_size + mapping_table_size +
+		nld->writesize + nld->oobsize + sizeof(struct nmbm_instance);
+}
+
+/*
+ * nmbm_init_structure - Initialize members of instance structure
+ * @ni: NMBM instance structure
+ */
+static void nmbm_init_structure(struct nmbm_instance *ni)
+{
+	uint32_t pages_per_block, blocks_per_chip;
+	uintptr_t ptr;
+
+	pages_per_block = ni->lower.erasesize / ni->lower.writesize;
+	blocks_per_chip = nmbm_lldiv(ni->lower.size, ni->lower.erasesize);
+
+	ni->rawpage_size = ni->lower.writesize + ni->lower.oobsize;
+	ni->rawblock_size = pages_per_block * ni->rawpage_size;
+	ni->rawchip_size = blocks_per_chip * ni->rawblock_size;
+
+	ni->writesize_mask = ni->lower.writesize - 1;
+	ni->erasesize_mask = ni->lower.erasesize - 1;
+
+	ni->writesize_shift = ffs(ni->lower.writesize) - 1;
+	ni->erasesize_shift = ffs(ni->lower.erasesize) - 1;
+
+	/* Calculate number of block this chip */
+	ni->block_count = ni->lower.size >> ni->erasesize_shift;
+
+	/* Calculate info table size */
+	ni->state_table_size = ((ni->block_count + NMBM_BITMAP_BLOCKS_PER_UNIT - 1) /
+		NMBM_BITMAP_BLOCKS_PER_UNIT) * NMBM_BITMAP_UNIT_SIZE;
+	ni->mapping_table_size = ni->block_count * sizeof(*ni->block_mapping);
+
+	ni->info_table_size = NMBM_ALIGN(sizeof(ni->info_table),
+					 ni->lower.writesize);
+	ni->info_table.state_table_off = ni->info_table_size;
+
+	ni->info_table_size += NMBM_ALIGN(ni->state_table_size,
+					  ni->lower.writesize);
+	ni->info_table.mapping_table_off = ni->info_table_size;
+
+	ni->info_table_size += NMBM_ALIGN(ni->mapping_table_size,
+					  ni->lower.writesize);
+
+	ni->info_table_spare_blocks = nmbm_get_spare_block_count(
+		size2blk(ni, ni->info_table_size));
+
+	/* Assign memory to members */
+	ptr = (uintptr_t)ni + sizeof(*ni);
+
+	ni->info_table_cache = (void *)ptr;
+	ptr += ni->info_table_size;
+
+	ni->block_state = (void *)ptr;
+	ptr += ni->state_table_size;
+
+	ni->block_mapping = (void *)ptr;
+	ptr += ni->mapping_table_size;
+
+	ni->page_cache = (uint8_t *)ptr;
+
+	/* Initialize block state table */
+	ni->block_state_changed = 0;
+	memset(ni->block_state, 0xff, ni->state_table_size);
+
+	/* Initialize block mapping table */
+	ni->block_mapping_changed = 0;
+}
+
+/*
+ * nmbm_attach - Attach to a lower device
+ * @nld: NMBM lower device structure
+ * @ni: NMBM instance structure
+ */
+int nmbm_attach(struct nmbm_lower_device *nld, struct nmbm_instance *ni)
+{
+	bool success;
+
+	if (!nld || !ni)
+		return -EINVAL;
+
+	/* Set default log level */
+	ni->log_display_level = NMBM_DEFAULT_LOG_LEVEL;
+
+	/* Check lower members */
+	success = nmbm_check_lower_members(nld);
+	if (!success)
+		return -EINVAL;
+
+	/* Initialize NMBM instance */
+	memcpy(&ni->lower, nld, sizeof(struct nmbm_lower_device));
+	nmbm_init_structure(ni);
+
+	success = nmbm_find_signature(ni, &ni->signature, &ni->signature_ba);
+	if (!success) {
+		if (!(nld->flags & NMBM_F_CREATE)) {
+			nlog_err(ni, "Signature not found\n");
+			return -ENODEV;
+		}
+
+		success = nmbm_create_new(ni);
+		if (!success)
+			return -ENODEV;
+
+		return 0;
+	}
+
+	nlog_info(ni, "Signature found at block %u [0x%08llx]\n",
+		 ni->signature_ba, ba2addr(ni, ni->signature_ba));
+	nmbm_mark_block_color_signature(ni, ni->signature_ba);
+
+	if (ni->signature.header.version != NMBM_VER) {
+		nlog_err(ni, "NMBM version %u.%u is not supported\n",
+			NMBM_VERSION_MAJOR_GET(ni->signature.header.version),
+			NMBM_VERSION_MINOR_GET(ni->signature.header.version));
+		return -EINVAL;
+	}
+
+	if (ni->signature.nand_size != nld->size ||
+	    ni->signature.block_size != nld->erasesize ||
+	    ni->signature.page_size != nld->writesize ||
+	    ni->signature.spare_size != nld->oobsize) {
+		nlog_err(ni, "NMBM configuration mismatch\n");
+		return -EINVAL;
+	}
+
+	success = nmbm_load_existing(ni);
+	if (!success)
+		return -ENODEV;
+
+	return 0;
+}
+
+/*
+ * nmbm_detach - Detach from a lower device, and save all tables
+ * @ni: NMBM instance structure
+ */
+int nmbm_detach(struct nmbm_instance *ni)
+{
+	if (!ni)
+		return -EINVAL;
+
+	if (!(ni->lower.flags & NMBM_F_READ_ONLY))
+		nmbm_update_info_table(ni);
+
+	nmbm_mark_block_color_normal(ni, 0, ni->block_count - 1);
+
+	return 0;
+}
+
+/*
+ * nmbm_erase_logic_block - Erase a logic block
+ * @ni: NMBM instance structure
+ * @nmbm_erase_logic_block: logic block address
+ *
+ * Logic block will be mapped to physical block before erasing.
+ * Bad block found during erasinh will be remapped to a good block if there is
+ * still at least one good spare block available.
+ */
+static int nmbm_erase_logic_block(struct nmbm_instance *ni, uint32_t block_addr)
+{
+	uint32_t pb;
+	bool success;
+
+retry:
+	/* Map logic block to physical block */
+	pb = ni->block_mapping[block_addr];
+
+	/* Whether the logic block is good (has valid mapping) */
+	if ((int32_t)pb < 0) {
+		nlog_debug(ni, "Logic block %u is a bad block\n", block_addr);
+		return -EIO;
+	}
+
+	/* Remap logic block if current physical block is a bad block */
+	if (nmbm_get_block_state(ni, pb) == BLOCK_ST_BAD ||
+	    nmbm_get_block_state(ni, pb) == BLOCK_ST_NEED_REMAP)
+		goto remap_logic_block;
+
+	/* Insurance to detect unexpected bad block marked by user */
+	if (nmbm_check_bad_phys_block(ni, pb)) {
+		nlog_warn(ni, "Found unexpected bad block possibly marked by user\n");
+		nmbm_set_block_state(ni, pb, BLOCK_ST_BAD);
+		goto remap_logic_block;
+	}
+
+	success = nmbm_erase_block_and_check(ni, pb);
+	if (success)
+		return 0;
+
+	/* Mark bad block */
+	nmbm_mark_phys_bad_block(ni, pb);
+	nmbm_set_block_state(ni, pb, BLOCK_ST_BAD);
+
+remap_logic_block:
+	/* Try to assign a new block */
+	success = nmbm_map_block(ni, block_addr);
+	if (!success) {
+		/* Mark logic block unusable, and update info table */
+		ni->block_mapping[block_addr] = -1;
+		if (nmbm_get_block_state(ni, pb) != BLOCK_ST_NEED_REMAP)
+			nmbm_set_block_state(ni, pb, BLOCK_ST_BAD);
+		nmbm_update_info_table(ni);
+		return -EIO;
+	}
+
+	/* Update info table before erasing */
+	if (nmbm_get_block_state(ni, pb) != BLOCK_ST_NEED_REMAP)
+		nmbm_set_block_state(ni, pb, BLOCK_ST_BAD);
+	nmbm_update_info_table(ni);
+
+	goto retry;
+}
+
+/*
+ * nmbm_erase_block_range - Erase logic blocks
+ * @ni: NMBM instance structure
+ * @addr: logic linear address
+ * @size: erase range
+ * @failed_addr: return failed block address if error occurs
+ */
+int nmbm_erase_block_range(struct nmbm_instance *ni, uint64_t addr,
+			   uint64_t size, uint64_t *failed_addr)
+{
+	uint32_t start_ba, end_ba;
+	int ret;
+
+	if (!ni)
+		return -EINVAL;
+
+	/* Sanity check */
+	if (ni->protected || (ni->lower.flags & NMBM_F_READ_ONLY)) {
+		nlog_debug(ni, "Device is forced read-only\n");
+		return -EROFS;
+	}
+
+	if (addr >= ba2addr(ni, ni->data_block_count)) {
+		nlog_err(ni, "Address 0x%llx is invalid\n", addr);
+		return -EINVAL;
+	}
+
+	if (addr + size > ba2addr(ni, ni->data_block_count)) {
+		nlog_err(ni, "Erase range 0xllxu is too large\n", size);
+		return -EINVAL;
+	}
+
+	if (!size) {
+		nlog_warn(ni, "No blocks to be erased\n");
+		return 0;
+	}
+
+	start_ba = addr2ba(ni, addr);
+	end_ba = addr2ba(ni, addr + size - 1);
+
+	while (start_ba <= end_ba) {
+		WATCHDOG_RESET();
+
+		ret = nmbm_erase_logic_block(ni, start_ba);
+		if (ret) {
+			if (failed_addr)
+				*failed_addr = ba2addr(ni, start_ba);
+			return ret;
+		}
+
+		start_ba++;
+	}
+
+	return 0;
+}
+
+/*
+ * nmbm_read_logic_page - Read page based on logic address
+ * @ni: NMBM instance structure
+ * @addr: logic linear address
+ * @data: buffer to store main data. optional.
+ * @oob: buffer to store oob data. optional.
+ * @mode: read mode
+ *
+ * Return 0 for success, positive value for corrected bitflip count,
+ * -EBADMSG for ecc error, other negative values for other errors
+ */
+static int nmbm_read_logic_page(struct nmbm_instance *ni, uint64_t addr,
+				void *data, void *oob, enum nmbm_oob_mode mode)
+{
+	uint32_t lb, pb, offset;
+	uint64_t paddr;
+
+	/* Extract block address and in-block offset */
+	lb = addr2ba(ni, addr);
+	offset = addr & ni->erasesize_mask;
+
+	/* Map logic block to physical block */
+	pb = ni->block_mapping[lb];
+
+	/* Whether the logic block is good (has valid mapping) */
+	if ((int32_t)pb < 0) {
+		nlog_debug(ni, "Logic block %u is a bad block\n", lb);
+		return -EIO;
+	}
+
+	/* Fail if physical block is marked bad */
+	if (nmbm_get_block_state(ni, pb) == BLOCK_ST_BAD)
+		return -EIO;
+
+	/* Assemble new address */
+	paddr = ba2addr(ni, pb) + offset;
+
+	return nmbm_read_phys_page(ni, paddr, data, oob, mode);
+}
+
+/*
+ * nmbm_read_single_page - Read one page based on logic address
+ * @ni: NMBM instance structure
+ * @addr: logic linear address
+ * @data: buffer to store main data. optional.
+ * @oob: buffer to store oob data. optional.
+ * @mode: read mode
+ *
+ * Return 0 for success, positive value for corrected bitflip count,
+ * -EBADMSG for ecc error, other negative values for other errors
+ */
+int nmbm_read_single_page(struct nmbm_instance *ni, uint64_t addr, void *data,
+			  void *oob, enum nmbm_oob_mode mode)
+{
+	if (!ni)
+		return -EINVAL;
+
+	/* Sanity check */
+	if (ni->protected) {
+		nlog_debug(ni, "Device is forced read-only\n");
+		return -EROFS;
+	}
+
+	if (addr >= ba2addr(ni, ni->data_block_count)) {
+		nlog_err(ni, "Address 0x%llx is invalid\n", addr);
+		return -EINVAL;
+	}
+
+	return nmbm_read_logic_page(ni, addr, data, oob, mode);
+}
+
+/*
+ * nmbm_read_range - Read data without oob
+ * @ni: NMBM instance structure
+ * @addr: logic linear address
+ * @size: data size to read
+ * @data: buffer to store main data to be read
+ * @mode: read mode
+ * @retlen: return actual data size read
+ *
+ * Return 0 for success, positive value for corrected bitflip count,
+ * -EBADMSG for ecc error, other negative values for other errors
+ */
+int nmbm_read_range(struct nmbm_instance *ni, uint64_t addr, size_t size,
+		    void *data, enum nmbm_oob_mode mode, size_t *retlen)
+{
+	uint64_t off = addr;
+	uint8_t *ptr = data;
+	size_t sizeremain = size, chunksize, leading;
+	bool has_ecc_err = false;
+	int ret, max_bitflips = 0;
+
+	if (!ni)
+		return -EINVAL;
+
+	/* Sanity check */
+	if (ni->protected) {
+		nlog_debug(ni, "Device is forced read-only\n");
+		return -EROFS;
+	}
+
+	if (addr >= ba2addr(ni, ni->data_block_count)) {
+		nlog_err(ni, "Address 0x%llx is invalid\n", addr);
+		return -EINVAL;
+	}
+
+	if (addr + size > ba2addr(ni, ni->data_block_count)) {
+		nlog_err(ni, "Read range 0x%llx is too large\n", size);
+		return -EINVAL;
+	}
+
+	if (!size) {
+		nlog_warn(ni, "No data to be read\n");
+		return 0;
+	}
+
+	while (sizeremain) {
+		WATCHDOG_RESET();
+
+		leading = off & ni->writesize_mask;
+		chunksize = ni->lower.writesize - leading;
+		if (chunksize > sizeremain)
+			chunksize = sizeremain;
+
+		if (chunksize == ni->lower.writesize) {
+			ret = nmbm_read_logic_page(ni, off - leading, ptr,
+							NULL, mode);
+			if (ret < 0 && ret != -EBADMSG)
+				break;
+		} else {
+			ret = nmbm_read_logic_page(ni, off - leading,
+							ni->page_cache, NULL,
+							mode);
+			if (ret < 0 && ret != -EBADMSG)
+				break;
+
+			memcpy(ptr, ni->page_cache + leading, chunksize);
+		}
+
+		if (ret == -EBADMSG)
+			has_ecc_err = true;
+
+		if (ret > max_bitflips)
+			max_bitflips = ret;
+
+		off += chunksize;
+		ptr += chunksize;
+		sizeremain -= chunksize;
+	}
+
+	if (retlen)
+		*retlen = size - sizeremain;
+
+	if (ret < 0 && ret != -EBADMSG)
+		return ret;
+
+	if (has_ecc_err)
+		return -EBADMSG;
+
+	return max_bitflips;
+}
+
+/*
+ * nmbm_write_logic_page - Read page based on logic address
+ * @ni: NMBM instance structure
+ * @addr: logic linear address
+ * @data: buffer contains main data. optional.
+ * @oob: buffer contains oob data. optional.
+ * @mode: write mode
+ */
+static int nmbm_write_logic_page(struct nmbm_instance *ni, uint64_t addr,
+				  const void *data, const void *oob,
+				  enum nmbm_oob_mode mode)
+{
+	uint32_t lb, pb, offset;
+	uint64_t paddr;
+	bool success;
+
+	/* Extract block address and in-block offset */
+	lb = addr2ba(ni, addr);
+	offset = addr & ni->erasesize_mask;
+
+	/* Map logic block to physical block */
+	pb = ni->block_mapping[lb];
+
+	/* Whether the logic block is good (has valid mapping) */
+	if ((int32_t)pb < 0) {
+		nlog_debug(ni, "Logic block %u is a bad block\n", lb);
+		return -EIO;
+	}
+
+	/* Fail if physical block is marked bad */
+	if (nmbm_get_block_state(ni, pb) == BLOCK_ST_BAD)
+		return -EIO;
+
+	/* Assemble new address */
+	paddr = ba2addr(ni, pb) + offset;
+
+	success = nmbm_write_phys_page(ni, paddr, data, oob, mode);
+	if (success)
+		return 0;
+
+	/*
+	 * Do not remap bad block here. Just mark this block in state table.
+	 * Remap this block on erasing.
+	 */
+	nmbm_set_block_state(ni, pb, BLOCK_ST_NEED_REMAP);
+	nmbm_update_info_table(ni);
+
+	return -EIO;
+}
+
+/*
+ * nmbm_write_single_page - Write one page based on logic address
+ * @ni: NMBM instance structure
+ * @addr: logic linear address
+ * @data: buffer contains main data. optional.
+ * @oob: buffer contains oob data. optional.
+ * @mode: write mode
+ */
+int nmbm_write_single_page(struct nmbm_instance *ni, uint64_t addr,
+			   const void *data, const void *oob,
+			   enum nmbm_oob_mode mode)
+{
+	if (!ni)
+		return -EINVAL;
+
+	/* Sanity check */
+	if (ni->protected || (ni->lower.flags & NMBM_F_READ_ONLY)) {
+		nlog_debug(ni, "Device is forced read-only\n");
+		return -EROFS;
+	}
+
+	if (addr >= ba2addr(ni, ni->data_block_count)) {
+		nlog_err(ni, "Address 0x%llx is invalid\n", addr);
+		return -EINVAL;
+	}
+
+	return nmbm_write_logic_page(ni, addr, data, oob, mode);
+}
+
+/*
+ * nmbm_write_range - Write data without oob
+ * @ni: NMBM instance structure
+ * @addr: logic linear address
+ * @size: data size to write
+ * @data: buffer contains data to be written
+ * @mode: write mode
+ * @retlen: return actual data size written
+ */
+int nmbm_write_range(struct nmbm_instance *ni, uint64_t addr, size_t size,
+		     const void *data, enum nmbm_oob_mode mode,
+		     size_t *retlen)
+{
+	uint64_t off = addr;
+	const uint8_t *ptr = data;
+	size_t sizeremain = size, chunksize, leading;
+	int ret;
+
+	if (!ni)
+		return -EINVAL;
+
+	/* Sanity check */
+	if (ni->protected || (ni->lower.flags & NMBM_F_READ_ONLY)) {
+		nlog_debug(ni, "Device is forced read-only\n");
+		return -EROFS;
+	}
+
+	if (addr >= ba2addr(ni, ni->data_block_count)) {
+		nlog_err(ni, "Address 0x%llx is invalid\n", addr);
+		return -EINVAL;
+	}
+
+	if (addr + size > ba2addr(ni, ni->data_block_count)) {
+		nlog_err(ni, "Write size 0x%zx is too large\n", size);
+		return -EINVAL;
+	}
+
+	if (!size) {
+		nlog_warn(ni, "No data to be written\n");
+		return 0;
+	}
+
+	while (sizeremain) {
+		WATCHDOG_RESET();
+
+		leading = off & ni->writesize_mask;
+		chunksize = ni->lower.writesize - leading;
+		if (chunksize > sizeremain)
+			chunksize = sizeremain;
+
+		if (chunksize == ni->lower.writesize) {
+			ret = nmbm_write_logic_page(ni, off - leading, ptr,
+							 NULL, mode);
+			if (ret)
+				break;
+		} else {
+			memset(ni->page_cache, 0xff, leading);
+			memcpy(ni->page_cache + leading, ptr, chunksize);
+
+			ret = nmbm_write_logic_page(ni, off - leading,
+							 ni->page_cache, NULL,
+							 mode);
+			if (ret)
+				break;
+		}
+
+		off += chunksize;
+		ptr += chunksize;
+		sizeremain -= chunksize;
+	}
+
+	if (retlen)
+		*retlen = size - sizeremain;
+
+	return ret;
+}
+
+/*
+ * nmbm_check_bad_block - Check whether a logic block is usable
+ * @ni: NMBM instance structure
+ * @addr: logic linear address
+ */
+int nmbm_check_bad_block(struct nmbm_instance *ni, uint64_t addr)
+{
+	uint32_t lb, pb;
+
+	if (!ni)
+		return -EINVAL;
+
+	if (addr >= ba2addr(ni, ni->data_block_count)) {
+		nlog_err(ni, "Address 0x%llx is invalid\n", addr);
+		return -EINVAL;
+	}
+
+	lb = addr2ba(ni, addr);
+
+	/* Map logic block to physical block */
+	pb = ni->block_mapping[lb];
+
+	if ((int32_t)pb < 0)
+		return 1;
+
+	if (nmbm_get_block_state(ni, pb) == BLOCK_ST_BAD)
+		return 1;
+
+	return 0;
+}
+
+/*
+ * nmbm_mark_bad_block - Mark a logic block unusable
+ * @ni: NMBM instance structure
+ * @addr: logic linear address
+ */
+int nmbm_mark_bad_block(struct nmbm_instance *ni, uint64_t addr)
+{
+	uint32_t lb, pb;
+
+	if (!ni)
+		return -EINVAL;
+
+	/* Sanity check */
+	if (ni->protected || (ni->lower.flags & NMBM_F_READ_ONLY)) {
+		nlog_debug(ni, "Device is forced read-only\n");
+		return -EROFS;
+	}
+
+	if (addr >= ba2addr(ni, ni->data_block_count)) {
+		nlog_err(ni, "Address 0x%llx is invalid\n", addr);
+		return -EINVAL;
+	}
+
+	lb = addr2ba(ni, addr);
+
+	/* Map logic block to physical block */
+	pb = ni->block_mapping[lb];
+
+	if ((int32_t)pb < 0)
+		return 0;
+
+	ni->block_mapping[lb] = -1;
+	nmbm_mark_phys_bad_block(ni, pb);
+	nmbm_set_block_state(ni, pb, BLOCK_ST_BAD);
+	nmbm_update_info_table(ni);
+
+	return 0;
+}
+
+/*
+ * nmbm_get_avail_size - Get available user data size
+ * @ni: NMBM instance structure
+ */
+uint64_t nmbm_get_avail_size(struct nmbm_instance *ni)
+{
+	if (!ni)
+		return 0;
+
+	return (uint64_t)ni->data_block_count << ni->erasesize_shift;
+}
+
+/*
+ * nmbm_get_lower_device - Get lower device structure
+ * @ni: NMBM instance structure
+ * @nld: pointer to hold the data of lower device structure
+ */
+int nmbm_get_lower_device(struct nmbm_instance *ni, struct nmbm_lower_device *nld)
+{
+	if (!ni)
+		return -EINVAL;
+
+	if (nld)
+		memcpy(nld, &ni->lower, sizeof(*nld));
+
+	return 0;
+}
+
+#include "nmbm-debug.inl"
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/drivers/mtd/nmbm/nmbm-debug.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/drivers/mtd/nmbm/nmbm-debug.h
new file mode 100644
index 0000000..5821183
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/drivers/mtd/nmbm/nmbm-debug.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */

+/*

+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.

+ *

+ * Debug addons for NAND Mapped-block Management (NMBM)

+ *

+ * Author: Weijie Gao <weijie.gao@mediatek.com>

+ */

+

+#ifndef _NMBM_DEBUG_H_

+#define _NMBM_DEBUG_H_

+

+#define nmbm_mark_block_color_normal(ni, start_ba, end_ba)

+#define nmbm_mark_block_color_bad(ni, ba)

+#define nmbm_mark_block_color_mgmt(ni, start_ba, end_ba)

+#define nmbm_mark_block_color_signature(ni, ba)

+#define nmbm_mark_block_color_info_table(ni, start_ba, end_ba)

+#define nmbm_mark_block_color_mapped(ni, ba)

+

+#endif /* _NMBM_DEBUG_H_ */

diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/drivers/mtd/nmbm/nmbm-debug.inl b/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/drivers/mtd/nmbm/nmbm-debug.inl
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/drivers/mtd/nmbm/nmbm-debug.inl
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/drivers/mtd/nmbm/nmbm-mtd.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/drivers/mtd/nmbm/nmbm-mtd.c
new file mode 100644
index 0000000..a3e9e18
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/drivers/mtd/nmbm/nmbm-mtd.c
@@ -0,0 +1,795 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MTD layer for NAND Mapped-block Management (NMBM)
+ *
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/flashchip.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of_platform.h>
+#include <linux/kern_levels.h>
+
+#include "nmbm-private.h"
+#include "nmbm-debug.h"
+
+#define NMBM_MAX_RATIO_DEFAULT			1
+#define NMBM_MAX_BLOCKS_DEFAULT			256
+
+struct nmbm_mtd {
+	struct mtd_info upper;
+	struct mtd_info *lower;
+
+	struct nmbm_instance *ni;
+	uint8_t *page_cache;
+
+	flstate_t state;
+	spinlock_t lock;
+	wait_queue_head_t wq;
+
+	struct device *dev;
+	struct list_head node;
+};
+
+struct list_head nmbm_devs;
+static DEFINE_MUTEX(nmbm_devs_lock);
+
+static int nmbm_lower_read_page(void *arg, uint64_t addr, void *buf, void *oob,
+				enum nmbm_oob_mode mode)
+{
+	struct nmbm_mtd *nm = arg;
+	struct mtd_oob_ops ops;
+	int ret;
+
+	memset(&ops, 0, sizeof(ops));
+
+	switch (mode) {
+	case NMBM_MODE_PLACE_OOB:
+		ops.mode = MTD_OPS_PLACE_OOB;
+		break;
+	case NMBM_MODE_AUTO_OOB:
+		ops.mode = MTD_OPS_AUTO_OOB;
+		break;
+	case NMBM_MODE_RAW:
+		ops.mode = MTD_OPS_RAW;
+		break;
+	default:
+		pr_debug("%s: unsupported NMBM mode: %u\n", __func__, mode);
+		return -ENOTSUPP;
+	}
+
+	if (buf) {
+		ops.datbuf = buf;
+		ops.len = nm->lower->writesize;
+	}
+
+	if (oob) {
+		ops.oobbuf = oob;
+		ops.ooblen = mtd_oobavail(nm->lower, &ops);
+	}
+
+	ret = mtd_read_oob(nm->lower, addr, &ops);
+	nm->upper.ecc_stats.corrected = nm->lower->ecc_stats.corrected;
+	nm->upper.ecc_stats.failed = nm->lower->ecc_stats.failed;
+
+	/* Report error on failure (including ecc error) */
+	if (ret < 0 && ret != -EUCLEAN)
+		return ret;
+
+	/*
+	 * Since mtd_read_oob() won't report exact bitflips, what we can know
+	 * is whether bitflips exceeds the threshold.
+	 * We want the -EUCLEAN to be passed to the upper layer, but not the
+	 * error value itself. To achieve this, report bitflips above the
+	 * threshold.
+	 */
+
+	if (ret == -EUCLEAN) {
+		return min_t(u32, nm->lower->bitflip_threshold + 1,
+			     nm->lower->ecc_strength);
+	}
+
+	/* For bitflips less than the threshold, return 0 */
+	return 0;
+}
+
+static int nmbm_lower_write_page(void *arg, uint64_t addr, const void *buf,
+				 const void *oob, enum nmbm_oob_mode mode)
+{
+	struct nmbm_mtd *nm = arg;
+	struct mtd_oob_ops ops;
+
+	memset(&ops, 0, sizeof(ops));
+
+	switch (mode) {
+	case NMBM_MODE_PLACE_OOB:
+		ops.mode = MTD_OPS_PLACE_OOB;
+		break;
+	case NMBM_MODE_AUTO_OOB:
+		ops.mode = MTD_OPS_AUTO_OOB;
+		break;
+	case NMBM_MODE_RAW:
+		ops.mode = MTD_OPS_RAW;
+		break;
+	default:
+		pr_debug("%s: unsupported NMBM mode: %u\n", __func__, mode);
+		return -ENOTSUPP;
+	}
+
+	if (buf) {
+		ops.datbuf = (uint8_t *)buf;
+		ops.len = nm->lower->writesize;
+	}
+
+	if (oob) {
+		ops.oobbuf = (uint8_t *)oob;
+		ops.ooblen = mtd_oobavail(nm->lower, &ops);
+	}
+
+	return mtd_write_oob(nm->lower, addr, &ops);
+}
+
+static int nmbm_lower_erase_block(void *arg, uint64_t addr)
+{
+	struct nmbm_mtd *nm = arg;
+	struct erase_info ei;
+
+	memset(&ei, 0, sizeof(ei));
+
+	ei.addr = addr;
+	ei.len = nm->lower->erasesize;
+
+	return mtd_erase(nm->lower, &ei);
+}
+
+static int nmbm_lower_is_bad_block(void *arg, uint64_t addr)
+{
+	struct nmbm_mtd *nm = arg;
+
+	return mtd_block_isbad(nm->lower, addr);
+}
+
+static int nmbm_lower_mark_bad_block(void *arg, uint64_t addr)
+{
+	struct nmbm_mtd *nm = arg;
+
+	return mtd_block_markbad(nm->lower, addr);
+}
+
+static void nmbm_lower_log(void *arg, enum nmbm_log_category level,
+			   const char *fmt, va_list ap)
+{
+	struct nmbm_mtd *nm = arg;
+	char *msg;
+	char *kl;
+
+	msg = kvasprintf(GFP_KERNEL, fmt, ap);
+	if (!msg) {
+		dev_warn(nm->dev, "unable to print log\n");
+		return;
+	}
+
+	switch (level) {
+	case NMBM_LOG_DEBUG:
+		kl = KERN_DEBUG;
+		break;
+	case NMBM_LOG_WARN:
+		kl = KERN_WARNING;
+		break;
+	case NMBM_LOG_ERR:
+		kl = KERN_ERR;
+		break;
+	case NMBM_LOG_EMERG:
+		kl = KERN_EMERG;
+		break;
+	default:
+		kl = KERN_INFO ;
+	}
+
+	dev_printk(kl, nm->dev, "%s", msg);
+
+	kfree(msg);
+}
+
+static int nmbm_get_device(struct nmbm_mtd *nm, int new_state)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+retry:
+	spin_lock(&nm->lock);
+
+	if (nm->state == FL_READY) {
+		nm->state = new_state;
+		spin_unlock(&nm->lock);
+		return 0;
+	}
+
+	if (new_state == FL_PM_SUSPENDED) {
+		if (nm->state == FL_PM_SUSPENDED) {
+			spin_unlock(&nm->lock);
+			return 0;
+		}
+	}
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	add_wait_queue(&nm->wq, &wait);
+	spin_unlock(&nm->lock);
+	schedule();
+	remove_wait_queue(&nm->wq, &wait);
+	goto retry;
+}
+
+static void nmbm_release_device(struct nmbm_mtd *nm)
+{
+	spin_lock(&nm->lock);
+	nm->state = FL_READY;
+	wake_up(&nm->wq);
+	spin_unlock(&nm->lock);
+}
+
+static int nmbm_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct nmbm_mtd *nm = container_of(mtd, struct nmbm_mtd, upper);
+	int ret;
+
+	nmbm_get_device(nm, FL_ERASING);
+
+	ret = nmbm_erase_block_range(nm->ni, instr->addr, instr->len,
+				     &instr->fail_addr);
+
+	nmbm_release_device(nm);
+
+	if (!ret)
+		return 0;
+
+	return -EIO;
+}
+
+static int nmbm_mtd_read_data(struct nmbm_mtd *nm, uint64_t addr,
+			      struct mtd_oob_ops *ops, enum nmbm_oob_mode mode)
+{
+	size_t len, ooblen, maxooblen, chklen;
+	uint32_t col, ooboffs;
+	uint8_t *datcache, *oobcache;
+	bool has_ecc_err = false;
+	int ret, max_bitflips = 0;
+
+	col = addr & nm->lower->writesize_mask;
+	addr &= ~nm->lower->writesize_mask;
+	maxooblen = mtd_oobavail(nm->lower, ops);
+	ooboffs = ops->ooboffs;
+	ooblen = ops->ooblen;
+	len = ops->len;
+
+	datcache = len ? nm->page_cache : NULL;
+	oobcache = ooblen ? nm->page_cache + nm->lower->writesize : NULL;
+
+	ops->oobretlen = 0;
+	ops->retlen = 0;
+
+	while (len || ooblen) {
+		ret = nmbm_read_single_page(nm->ni, addr, datcache, oobcache,
+					    mode);
+		if (ret < 0 && ret != -EBADMSG)
+			return ret;
+
+		/* Continue reading on ecc error */
+		if (ret == -EBADMSG)
+			has_ecc_err = true;
+
+		/* Record the maximum bitflips between pages */
+		if (ret > max_bitflips)
+			max_bitflips = ret;
+
+		if (len) {
+			/* Move data */
+			chklen = nm->lower->writesize - col;
+			if (chklen > len)
+				chklen = len;
+
+			memcpy(ops->datbuf + ops->retlen, datcache + col,
+			       chklen);
+			len -= chklen;
+			col = 0; /* (col + chklen) %  */
+			ops->retlen += chklen;
+		}
+
+		if (ooblen) {
+			/* Move oob */
+			chklen = maxooblen - ooboffs;
+			if (chklen > ooblen)
+				chklen = ooblen;
+
+			memcpy(ops->oobbuf + ops->oobretlen, oobcache + ooboffs,
+			       chklen);
+			ooblen -= chklen;
+			ooboffs = 0; /* (ooboffs + chklen) % maxooblen; */
+			ops->oobretlen += chklen;
+		}
+
+		addr += nm->lower->writesize;
+	}
+
+	if (has_ecc_err)
+		return -EBADMSG;
+
+	return max_bitflips;
+}
+
+static int nmbm_mtd_read_oob(struct mtd_info *mtd, loff_t from,
+			     struct mtd_oob_ops *ops)
+{
+	struct nmbm_mtd *nm = container_of(mtd, struct nmbm_mtd, upper);
+	uint32_t maxooblen;
+	enum nmbm_oob_mode mode;
+	int ret;
+
+	if (!ops->oobbuf && !ops->datbuf) {
+		if (ops->ooblen || ops->len)
+			return -EINVAL;
+
+		return 0;
+	}
+
+	switch (ops->mode) {
+	case MTD_OPS_PLACE_OOB:
+		mode = NMBM_MODE_PLACE_OOB;
+		break;
+	case MTD_OPS_AUTO_OOB:
+		mode = NMBM_MODE_AUTO_OOB;
+		break;
+	case MTD_OPS_RAW:
+		mode = NMBM_MODE_RAW;
+		break;
+	default:
+		pr_debug("%s: unsupported oob mode: %u\n", __func__, ops->mode);
+		return -ENOTSUPP;
+	}
+
+	maxooblen = mtd_oobavail(mtd, ops);
+
+	/* Do not allow read past end of device */
+	if (ops->datbuf && (from + ops->len) > mtd->size) {
+		pr_debug("%s: attempt to read beyond end of device\n",
+			 __func__);
+		return -EINVAL;
+	}
+
+	if (!ops->oobbuf) {
+		nmbm_get_device(nm, FL_READING);
+
+		/* Optimized for reading data only */
+		ret = nmbm_read_range(nm->ni, from, ops->len, ops->datbuf,
+				      mode, &ops->retlen);
+
+		nmbm_release_device(nm);
+
+		return ret;
+	}
+
+	if (unlikely(ops->ooboffs >= maxooblen)) {
+		pr_debug("%s: attempt to start read outside oob\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(from >= mtd->size ||
+	    ops->ooboffs + ops->ooblen > ((mtd->size >> mtd->writesize_shift) -
+	    (from >> mtd->writesize_shift)) * maxooblen)) {
+		pr_debug("%s: attempt to read beyond end of device\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	nmbm_get_device(nm, FL_READING);
+	ret = nmbm_mtd_read_data(nm, from, ops, mode);
+	nmbm_release_device(nm);
+
+	return ret;
+}
+
+static int nmbm_mtd_write_data(struct nmbm_mtd *nm, uint64_t addr,
+			       struct mtd_oob_ops *ops, enum nmbm_oob_mode mode)
+{
+	size_t len, ooblen, maxooblen, chklen;
+	uint32_t col, ooboffs;
+	uint8_t *datcache, *oobcache;
+	int ret;
+
+	col = addr & nm->lower->writesize_mask;
+	addr &= ~nm->lower->writesize_mask;
+	maxooblen = mtd_oobavail(nm->lower, ops);
+	ooboffs = ops->ooboffs;
+	ooblen = ops->ooblen;
+	len = ops->len;
+
+	datcache = len ? nm->page_cache : NULL;
+	oobcache = ooblen ? nm->page_cache + nm->lower->writesize : NULL;
+
+	ops->oobretlen = 0;
+	ops->retlen = 0;
+
+	while (len || ooblen) {
+		if (len) {
+			/* Move data */
+			chklen = nm->lower->writesize - col;
+			if (chklen > len)
+				chklen = len;
+
+			memset(datcache, 0xff, col);
+			memcpy(datcache + col, ops->datbuf + ops->retlen,
+			       chklen);
+			memset(datcache + col + chklen, 0xff,
+			       nm->lower->writesize - col - chklen);
+			len -= chklen;
+			col = 0; /* (col + chklen) %  */
+			ops->retlen += chklen;
+		}
+
+		if (ooblen) {
+			/* Move oob */
+			chklen = maxooblen - ooboffs;
+			if (chklen > ooblen)
+				chklen = ooblen;
+
+			memset(oobcache, 0xff, ooboffs);
+			memcpy(oobcache + ooboffs,
+			       ops->oobbuf + ops->oobretlen, chklen);
+			memset(oobcache + ooboffs + chklen, 0xff,
+			       nm->lower->oobsize - ooboffs - chklen);
+			ooblen -= chklen;
+			ooboffs = 0; /* (ooboffs + chklen) % maxooblen; */
+			ops->oobretlen += chklen;
+		}
+
+		ret = nmbm_write_single_page(nm->ni, addr, datcache, oobcache,
+					     mode);
+		if (ret)
+			return ret;
+
+		addr += nm->lower->writesize;
+	}
+
+	return 0;
+}
+
+static int nmbm_mtd_write_oob(struct mtd_info *mtd, loff_t to,
+			      struct mtd_oob_ops *ops)
+{
+	struct nmbm_mtd *nm = container_of(mtd, struct nmbm_mtd, upper);
+	enum nmbm_oob_mode mode;
+	uint32_t maxooblen;
+	int ret;
+
+	if (!ops->oobbuf && !ops->datbuf) {
+		if (ops->ooblen || ops->len)
+			return -EINVAL;
+
+		return 0;
+	}
+
+	switch (ops->mode) {
+	case MTD_OPS_PLACE_OOB:
+		mode = NMBM_MODE_PLACE_OOB;
+		break;
+	case MTD_OPS_AUTO_OOB:
+		mode = NMBM_MODE_AUTO_OOB;
+		break;
+	case MTD_OPS_RAW:
+		mode = NMBM_MODE_RAW;
+		break;
+	default:
+		pr_debug("%s: unsupported oob mode: %u\n", __func__,
+			 ops->mode);
+		return -ENOTSUPP;
+	}
+
+	maxooblen = mtd_oobavail(mtd, ops);
+
+	/* Do not allow write past end of device */
+	if (ops->datbuf && (to + ops->len) > mtd->size) {
+		pr_debug("%s: attempt to write beyond end of device\n",
+			 __func__);
+		return -EINVAL;
+	}
+
+	if (!ops->oobbuf) {
+		nmbm_get_device(nm, FL_WRITING);
+
+		/* Optimized for writing data only */
+		ret = nmbm_write_range(nm->ni, to, ops->len, ops->datbuf,
+				       mode, &ops->retlen);
+
+		nmbm_release_device(nm);
+
+		return ret;
+	}
+
+	if (unlikely(ops->ooboffs >= maxooblen)) {
+		pr_debug("%s: attempt to start write outside oob\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (unlikely(to >= mtd->size ||
+	    ops->ooboffs + ops->ooblen > ((mtd->size >> mtd->writesize_shift) -
+	    (to >> mtd->writesize_shift)) * maxooblen)) {
+		pr_debug("%s: attempt to write beyond end of device\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	nmbm_get_device(nm, FL_WRITING);
+	ret = nmbm_mtd_write_data(nm, to, ops, mode);
+	nmbm_release_device(nm);
+
+	return ret;
+}
+
+static int nmbm_mtd_block_isbad(struct mtd_info *mtd, loff_t offs)
+{
+	struct nmbm_mtd *nm = container_of(mtd, struct nmbm_mtd, upper);
+	int ret;
+
+	nmbm_get_device(nm, FL_READING);
+	ret = nmbm_check_bad_block(nm->ni, offs);
+	nmbm_release_device(nm);
+
+	return ret;
+}
+
+static int nmbm_mtd_block_markbad(struct mtd_info *mtd, loff_t offs)
+{
+	struct nmbm_mtd *nm = container_of(mtd, struct nmbm_mtd, upper);
+	int ret;
+
+	nmbm_get_device(nm, FL_WRITING);
+	ret = nmbm_mark_bad_block(nm->ni, offs);
+	nmbm_release_device(nm);
+
+	return ret;
+}
+
+static void nmbm_mtd_shutdown(struct mtd_info *mtd)
+{
+	struct nmbm_mtd *nm = container_of(mtd, struct nmbm_mtd, upper);
+
+	nmbm_get_device(nm, FL_PM_SUSPENDED);
+}
+
+static int nmbm_probe(struct platform_device *pdev)
+{
+	struct device_node *mtd_np, *np = pdev->dev.of_node;
+	uint32_t max_ratio, max_reserved_blocks, alloc_size;
+	bool forced_create, empty_page_ecc_ok;
+	struct nmbm_lower_device nld;
+	struct mtd_info *lower, *mtd;
+	struct nmbm_mtd *nm;
+	const char *mtdname;
+	int ret;
+
+	mtd_np = of_parse_phandle(np, "lower-mtd-device", 0);
+	if (mtd_np) {
+		lower = get_mtd_device_by_node(mtd_np);
+		if (!IS_ERR(lower))
+			goto do_attach_mtd;
+
+		dev_dbg(&pdev->dev, "failed to find mtd device by phandle\n");
+		return -EPROBE_DEFER;
+	}
+
+	ret = of_property_read_string(np, "lower-mtd-name", &mtdname);
+	if (!ret) {
+		lower = get_mtd_device_nm(mtdname);
+		if (!IS_ERR(lower))
+			goto do_attach_mtd;
+
+		dev_dbg(&pdev->dev, "failed to find mtd device by name '%s'\n",
+			mtdname);
+		return -EPROBE_DEFER;
+	}
+
+do_attach_mtd:
+	if (of_property_read_u32(np, "max-ratio", &max_ratio))
+		max_ratio = NMBM_MAX_RATIO_DEFAULT;
+
+	if (of_property_read_u32(np, "max-reserved-blocks",
+				 &max_reserved_blocks))
+		max_reserved_blocks = NMBM_MAX_BLOCKS_DEFAULT;
+
+	forced_create = of_property_read_bool(np, "forced-create");
+	empty_page_ecc_ok = of_property_read_bool(np,
+						  "empty-page-ecc-protected");
+
+	memset(&nld, 0, sizeof(nld));
+
+	nld.flags = 0;
+
+	if (forced_create)
+		nld.flags |= NMBM_F_CREATE;
+
+	if (empty_page_ecc_ok)
+		nld.flags |= NMBM_F_EMPTY_PAGE_ECC_OK;
+
+	nld.max_ratio = max_ratio;
+	nld.max_reserved_blocks = max_reserved_blocks;
+
+	nld.size = lower->size;
+	nld.erasesize = lower->erasesize;
+	nld.writesize = lower->writesize;
+	nld.oobsize = lower->oobsize;
+	nld.oobavail = lower->oobavail;
+
+	nld.read_page = nmbm_lower_read_page;
+	nld.write_page = nmbm_lower_write_page;
+	nld.erase_block = nmbm_lower_erase_block;
+	nld.is_bad_block = nmbm_lower_is_bad_block;
+	nld.mark_bad_block = nmbm_lower_mark_bad_block;
+
+	nld.logprint = nmbm_lower_log;
+
+	alloc_size = nmbm_calc_structure_size(&nld);
+
+	nm = devm_kzalloc(&pdev->dev, sizeof(*nm) + alloc_size +
+			  lower->writesize + lower->oobsize, GFP_KERNEL);
+	if (!nm) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	nm->ni = (void *)nm + sizeof(*nm);
+	nm->page_cache = (uint8_t *)nm->ni + alloc_size;
+	nm->lower = lower;
+	nm->dev = &pdev->dev;
+
+	INIT_LIST_HEAD(&nm->node);
+	spin_lock_init(&nm->lock);
+	init_waitqueue_head(&nm->wq);
+
+	nld.arg = nm;
+
+	ret = nmbm_attach(&nld, nm->ni);
+	if (ret)
+		goto out;
+
+	/* Initialize upper mtd */
+	mtd = &nm->upper;
+
+	mtd->owner = THIS_MODULE;
+	mtd->dev.parent = &pdev->dev;
+	mtd->type = lower->type;
+	mtd->flags = lower->flags;
+
+	mtd->size = (uint64_t)nm->ni->data_block_count * lower->erasesize;
+	mtd->erasesize = lower->erasesize;
+	mtd->writesize = lower->writesize;
+	mtd->writebufsize = lower->writesize;
+	mtd->oobsize = lower->oobsize;
+	mtd->oobavail = lower->oobavail;
+
+	mtd->erasesize_shift = lower->erasesize_shift;
+	mtd->writesize_shift = lower->writesize_shift;
+	mtd->erasesize_mask = lower->erasesize_mask;
+	mtd->writesize_mask = lower->writesize_mask;
+
+	mtd->bitflip_threshold = lower->bitflip_threshold;
+
+	mtd->ooblayout = lower->ooblayout;
+
+	mtd->ecc_step_size = lower->ecc_step_size;
+	mtd->ecc_strength = lower->ecc_strength;
+
+	mtd->numeraseregions = lower->numeraseregions;
+	mtd->eraseregions = lower->eraseregions;
+
+	mtd->_erase = nmbm_mtd_erase;
+	mtd->_read_oob = nmbm_mtd_read_oob;
+	mtd->_write_oob = nmbm_mtd_write_oob;
+	mtd->_block_isbad = nmbm_mtd_block_isbad;
+	mtd->_block_markbad = nmbm_mtd_block_markbad;
+	mtd->_reboot = nmbm_mtd_shutdown;
+
+	mtd_set_of_node(mtd, np);
+
+	ret = mtd_device_register(mtd, NULL, 0);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register mtd device\n");
+		nmbm_detach(nm->ni);
+		goto out;
+	}
+
+	platform_set_drvdata(pdev, nm);
+
+	mutex_lock(&nmbm_devs_lock);
+	list_add_tail(&nm->node, &nmbm_devs);
+	mutex_unlock(&nmbm_devs_lock);
+
+	return 0;
+
+out:
+	if (nm)
+		devm_kfree(&pdev->dev, nm);
+
+	put_mtd_device(lower);
+
+	return ret;
+}
+
+static int nmbm_remove(struct platform_device *pdev)
+{
+	struct nmbm_mtd *nm = platform_get_drvdata(pdev);
+	struct mtd_info *lower = nm->lower;
+	int ret;
+
+	ret = mtd_device_unregister(&nm->upper);
+	if (ret)
+		return ret;
+
+	nmbm_detach(nm->ni);
+
+	mutex_lock(&nmbm_devs_lock);
+	list_add_tail(&nm->node, &nmbm_devs);
+	mutex_unlock(&nmbm_devs_lock);
+
+	devm_kfree(&pdev->dev, nm);
+
+	put_mtd_device(lower);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static const struct of_device_id nmbm_ids[] = {
+	{ .compatible = "generic,nmbm" },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(of, nmbm_ids);
+
+static struct platform_driver nmbm_driver = {
+	.probe = nmbm_probe,
+	.remove = nmbm_remove,
+	.driver = {
+		.name = "nmbm",
+		.of_match_table = nmbm_ids,
+	},
+};
+
+static int __init nmbm_init(void)
+{
+	int ret;
+
+	INIT_LIST_HEAD(&nmbm_devs);
+
+	ret = platform_driver_register(&nmbm_driver);
+	if (ret) {
+		pr_err("failed to register nmbm driver\n");
+		return ret;
+	}
+
+	return 0;
+}
+module_init(nmbm_init);
+
+static void __exit nmbm_exit(void)
+{
+	platform_driver_unregister(&nmbm_driver);
+}
+module_exit(nmbm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Weijie Gao <weijie.gao@mediatek.com>");
+MODULE_DESCRIPTION("NAND mapping block management");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/drivers/mtd/nmbm/nmbm-private.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/drivers/mtd/nmbm/nmbm-private.h
new file mode 100644
index 0000000..c285aeb
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/drivers/mtd/nmbm/nmbm-private.h
@@ -0,0 +1,137 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Definitions for NAND Mapped-block Management (NMBM)
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#ifndef _NMBM_PRIVATE_H_
+#define _NMBM_PRIVATE_H_
+
+#include <nmbm/nmbm.h>
+
+#define NMBM_MAGIC_SIGNATURE			0x304d4d4e	/* NMM0 */
+#define NMBM_MAGIC_INFO_TABLE			0x314d4d4e	/* NMM1 */
+
+#define NMBM_VERSION_MAJOR_S			0
+#define NMBM_VERSION_MAJOR_M			0xffff
+#define NMBM_VERSION_MINOR_S			16
+#define NMBM_VERSION_MINOR_M			0xffff
+#define NMBM_VERSION_MAKE(major, minor)		(((major) & NMBM_VERSION_MAJOR_M) | \
+						(((minor) & NMBM_VERSION_MINOR_M) << \
+						NMBM_VERSION_MINOR_S))
+#define NMBM_VERSION_MAJOR_GET(ver)		(((ver) >> NMBM_VERSION_MAJOR_S) & \
+						NMBM_VERSION_MAJOR_M)
+#define NMBM_VERSION_MINOR_GET(ver)		(((ver) >> NMBM_VERSION_MINOR_S) & \
+						NMBM_VERSION_MINOR_M)
+
+typedef uint32_t				nmbm_bitmap_t;
+#define NMBM_BITMAP_UNIT_SIZE			(sizeof(nmbm_bitmap_t))
+#define NMBM_BITMAP_BITS_PER_BLOCK		2
+#define NMBM_BITMAP_BITS_PER_UNIT		(8 * sizeof(nmbm_bitmap_t))
+#define NMBM_BITMAP_BLOCKS_PER_UNIT		(NMBM_BITMAP_BITS_PER_UNIT / \
+						 NMBM_BITMAP_BITS_PER_BLOCK)
+
+#define NMBM_SPARE_BLOCK_MULTI			1
+#define NMBM_SPARE_BLOCK_DIV			2
+#define NMBM_SPARE_BLOCK_MIN			2
+
+#define NMBM_MGMT_DIV				16
+#define NMBM_MGMT_BLOCKS_MIN			32
+
+#define NMBM_TRY_COUNT				3
+
+#define BLOCK_ST_BAD				0
+#define BLOCK_ST_NEED_REMAP			2
+#define BLOCK_ST_GOOD				3
+#define BLOCK_ST_MASK				3
+
+struct nmbm_header {
+	uint32_t magic;
+	uint32_t version;
+	uint32_t size;
+	uint32_t checksum;
+};
+
+struct nmbm_signature {
+	struct nmbm_header header;
+	uint64_t nand_size;
+	uint32_t block_size;
+	uint32_t page_size;
+	uint32_t spare_size;
+	uint32_t mgmt_start_pb;
+	uint8_t max_try_count;
+	uint8_t padding[3];
+};
+
+struct nmbm_info_table_header {
+	struct nmbm_header header;
+	uint32_t write_count;
+	uint32_t state_table_off;
+	uint32_t mapping_table_off;
+	uint32_t padding;
+};
+
+struct nmbm_instance {
+	struct nmbm_lower_device lower;
+
+	uint32_t rawpage_size;
+	uint32_t rawblock_size;
+	uint32_t rawchip_size;
+
+	uint32_t writesize_mask;
+	uint32_t erasesize_mask;
+	uint16_t writesize_shift;
+	uint16_t erasesize_shift;
+
+	struct nmbm_signature signature;
+
+	uint8_t *info_table_cache;
+	uint32_t info_table_size;
+	uint32_t info_table_spare_blocks;
+	struct nmbm_info_table_header info_table;
+
+	nmbm_bitmap_t *block_state;
+	uint32_t block_state_changed;
+	uint32_t state_table_size;
+
+	int32_t *block_mapping;
+	uint32_t block_mapping_changed;
+	uint32_t mapping_table_size;
+
+	uint8_t *page_cache;
+
+	int protected;
+
+	uint32_t block_count;
+	uint32_t data_block_count;
+
+	uint32_t mgmt_start_ba;
+	uint32_t main_table_ba;
+	uint32_t backup_table_ba;
+	uint32_t mapping_blocks_ba;
+	uint32_t mapping_blocks_top_ba;
+	uint32_t signature_ba;
+
+	enum nmbm_log_category log_display_level;
+};
+
+/* Log utilities */
+#define nlog_debug(ni, fmt, ...) \
+	nmbm_log(ni, NMBM_LOG_DEBUG, fmt, ##__VA_ARGS__)
+
+#define nlog_info(ni, fmt, ...) \
+	nmbm_log(ni, NMBM_LOG_INFO, fmt, ##__VA_ARGS__)
+
+#define nlog_warn(ni, fmt, ...) \
+	nmbm_log(ni, NMBM_LOG_WARN, fmt, ##__VA_ARGS__)
+
+#define nlog_err(ni, fmt, ...) \
+	nmbm_log(ni, NMBM_LOG_ERR, fmt, ##__VA_ARGS__)
+
+#define nlog_emerg(ni, fmt, ...) \
+	nmbm_log(ni, NMBM_LOG_EMERG, fmt, ##__VA_ARGS__)
+
+#endif /* _NMBM_PRIVATE_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/include/nmbm/nmbm-os.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/include/nmbm/nmbm-os.h
new file mode 100644
index 0000000..1cae854
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/include/nmbm/nmbm-os.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * OS-dependent definitions for NAND Mapped-block Management (NMBM)
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#ifndef _NMBM_OS_H_
+#define _NMBM_OS_H_
+
+#include <linux/kernel.h>
+#include <linux/limits.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/crc32.h>
+#include <linux/log2.h>
+#include <asm/div64.h>
+
+static inline uint32_t nmbm_crc32(uint32_t crcval, const void *buf, size_t size)
+{
+	uint chksz;
+	const unsigned char *p = buf;
+
+	while (size) {
+		if (size > UINT_MAX)
+			chksz = UINT_MAX;
+		else
+			chksz = (uint)size;
+
+		crcval = crc32_le(crcval, p, chksz);
+		size -= chksz;
+		p += chksz;
+	}
+
+	return crcval;
+}
+
+static inline uint32_t nmbm_lldiv(uint64_t dividend, uint32_t divisor)
+{
+#if BITS_PER_LONG == 64
+	return dividend / divisor;
+#else
+	do_div(dividend, divisor);
+	return dividend;
+#endif
+}
+
+#define WATCHDOG_RESET()
+
+#ifdef CONFIG_NMBM_LOG_LEVEL_DEBUG
+#define NMBM_DEFAULT_LOG_LEVEL		0
+#elif defined(NMBM_LOG_LEVEL_INFO)
+#define NMBM_DEFAULT_LOG_LEVEL		1
+#elif defined(NMBM_LOG_LEVEL_WARN)
+#define NMBM_DEFAULT_LOG_LEVEL		2
+#elif defined(NMBM_LOG_LEVEL_ERR)
+#define NMBM_DEFAULT_LOG_LEVEL		3
+#elif defined(NMBM_LOG_LEVEL_EMERG)
+#define NMBM_DEFAULT_LOG_LEVEL		4
+#elif defined(NMBM_LOG_LEVEL_NONE)
+#define NMBM_DEFAULT_LOG_LEVEL		5
+#else
+#define NMBM_DEFAULT_LOG_LEVEL		1
+#endif
+
+#endif /* _NMBM_OS_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/include/nmbm/nmbm.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/include/nmbm/nmbm.h
new file mode 100644
index 0000000..c040098
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files-5.4/include/nmbm/nmbm.h
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Definitions for NAND Mapped-block Management (NMBM)
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#ifndef _NMBM_H_
+#define _NMBM_H_
+
+#include <nmbm/nmbm-os.h>
+
+enum nmbm_log_category {
+	NMBM_LOG_DEBUG,
+	NMBM_LOG_INFO,
+	NMBM_LOG_WARN,
+	NMBM_LOG_ERR,
+	NMBM_LOG_EMERG,
+
+	__NMBM_LOG_MAX
+};
+
+enum nmbm_oob_mode {
+	NMBM_MODE_PLACE_OOB,
+	NMBM_MODE_AUTO_OOB,
+	NMBM_MODE_RAW,
+
+	__NMBM_MODE_MAX
+};
+
+struct nmbm_lower_device {
+	uint32_t max_ratio;
+	uint32_t max_reserved_blocks;
+	int flags;
+
+	uint64_t size;
+	uint32_t erasesize;
+	uint32_t writesize;
+	uint32_t oobsize;
+	uint32_t oobavail;
+
+	void *arg;
+	int (*reset_chip)(void *arg);
+
+	/*
+	 * read_page:
+	 *    return 0 if succeeds
+	 *    return positive number for ecc error
+	 *    return negative number for other errors
+	 */
+	int (*read_page)(void *arg, uint64_t addr, void *buf, void *oob, enum nmbm_oob_mode mode);
+	int (*write_page)(void *arg, uint64_t addr, const void *buf, const void *oob, enum nmbm_oob_mode mode);
+	int (*erase_block)(void *arg, uint64_t addr);
+
+	int (*is_bad_block)(void *arg, uint64_t addr);
+	int (*mark_bad_block)(void *arg, uint64_t addr);
+
+	/* OS-dependent logging function */
+	void (*logprint)(void *arg, enum nmbm_log_category level, const char *fmt, va_list ap);
+};
+
+struct nmbm_instance;
+
+/* Create NMBM if management area not found, or not complete */
+#define NMBM_F_CREATE			0x01
+
+/* Empty page is also protected by ECC, and bitflip(s) can be corrected */
+#define NMBM_F_EMPTY_PAGE_ECC_OK	0x02
+
+/* Do not write anything back to flash */
+#define NMBM_F_READ_ONLY		0x04
+
+size_t nmbm_calc_structure_size(struct nmbm_lower_device *nld);
+int nmbm_attach(struct nmbm_lower_device *nld, struct nmbm_instance *ni);
+int nmbm_detach(struct nmbm_instance *ni);
+
+enum nmbm_log_category nmbm_set_log_level(struct nmbm_instance *ni,
+					  enum nmbm_log_category level);
+
+int nmbm_erase_block_range(struct nmbm_instance *ni, uint64_t addr,
+			   uint64_t size, uint64_t *failed_addr);
+int nmbm_read_single_page(struct nmbm_instance *ni, uint64_t addr, void *data,
+			  void *oob, enum nmbm_oob_mode mode);
+int nmbm_read_range(struct nmbm_instance *ni, uint64_t addr, size_t size,
+		    void *data, enum nmbm_oob_mode mode, size_t *retlen);
+int nmbm_write_single_page(struct nmbm_instance *ni, uint64_t addr,
+			   const void *data, const void *oob,
+			   enum nmbm_oob_mode mode);
+int nmbm_write_range(struct nmbm_instance *ni, uint64_t addr, size_t size,
+		     const void *data, enum nmbm_oob_mode mode,
+		     size_t *retlen);
+
+int nmbm_check_bad_block(struct nmbm_instance *ni, uint64_t addr);
+int nmbm_mark_bad_block(struct nmbm_instance *ni, uint64_t addr);
+
+uint64_t nmbm_get_avail_size(struct nmbm_instance *ni);
+
+int nmbm_get_lower_device(struct nmbm_instance *ni, struct nmbm_lower_device *nld);
+
+#endif /* _NMBM_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/Documentation/devicetree/bindings/mtd/partitions/openwrt,uimage.yaml b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/Documentation/devicetree/bindings/mtd/partitions/openwrt,uimage.yaml
new file mode 100644
index 0000000..d052ab1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/Documentation/devicetree/bindings/mtd/partitions/openwrt,uimage.yaml
@@ -0,0 +1,91 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mtd/partitions/openwrt,uimage.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: OpenWrt variations of U-Boot Image partitions
+
+maintainers:
+  - Bjørn Mork <bjorn@mork.no>
+
+description: |
+  The image format defined by the boot loader "Das U-Boot" is often
+  modified or extended by device vendors. This defines a few optional
+  properties which can be used to describe such modifications.
+
+# partition.txt defines common properties, but has not yet been
+# converted to YAML
+#allOf:
+#  - $ref: ../partition.yaml#
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - openwrt,uimage
+      - const: denx,uimage
+
+  openwrt,padding:
+    description: Number of padding bytes between header and data
+    $ref: /schemas/types.yaml#/definitions/uint32
+    default: 0
+
+  openwrt,ih-magic:
+    description: U-Boot Image Header magic number.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    default: 0x27051956 # IH_MAGIC
+
+  openwrt,ih-type:
+    description: U-Boot Image type
+    $ref: /schemas/types.yaml#/definitions/uint32
+    default: 2 # IH_TYPE_KERNEL
+
+  openwrt,offset:
+    description:
+      Offset between partition start and U-Boot Image in bytes
+    $ref: /schemas/types.yaml#/definitions/uint32
+    default: 0
+
+  openwrt,partition-magic:
+    description:
+      Magic number found at the start of the partition. Will only be
+      validated if both this property and openwrt,offset is non-zero
+    $ref: /schemas/types.yaml#/definitions/uint32
+    default: 0
+
+required:
+  - compatible
+  - reg
+
+#unevaluatedProperties: false
+additionalProperties: false
+
+examples:
+  - |
+    // device with non-default magic
+    partition@300000 {
+          compatible = "openwrt,uimage", "denx,uimage";
+          reg = <0x00300000 0xe80000>;
+          label = "firmware";
+          openwrt,ih-magic = <0x4e474520>;
+    };
+  - |
+    // device with U-Boot Image at an offset, with a partition magic value
+    partition@70000 {
+          compatible = "openwrt,uimage", "denx,uimage";
+          reg = <0x00070000 0x00790000>;
+          label = "firmware";
+          openwrt,offset = <20>;
+          openwrt,partition-magic = <0x43535953>;
+    };
+  - |
+    // device using a non-default image type
+    #include "dt-bindings/mtd/partitions/uimage.h"
+    partition@6c0000 {
+          compatible = "openwrt,uimage", "denx,uimage";
+          reg = <0x6c0000 0x1900000>;
+          label = "firmware";
+          openwrt,ih-magic = <0x33373033>;
+          openwrt,ih-type = <IH_TYPE_FILESYSTEM>;
+    };
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/Documentation/networking/adm6996.txt b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/Documentation/networking/adm6996.txt
new file mode 100644
index 0000000..ab59f1d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/Documentation/networking/adm6996.txt
@@ -0,0 +1,110 @@
+------- 
+
+ADM6996FC / ADM6996M switch chip driver
+
+
+1. General information
+
+  This driver supports the FC and M models only. The ADM6996F and L are
+  completely different chips.
+  
+  Support for the FC model is extremely limited at the moment. There is no VLAN
+  support as of yet. The driver will not offer an swconfig interface for the FC
+  chip.
+ 
+1.1 VLAN IDs
+
+  It is possible to define 16 different VLANs. Every VLAN has an identifier, its
+  VLAN ID. It is easiest if you use at most VLAN IDs 0-15. In that case, the
+  swconfig based configuration is very straightforward. To define two VLANs with
+  IDs 4 and 5, you can invoke, for example:
+  
+      # swconfig dev ethX vlan 4 set ports '0 1t 2 5t' 
+      # swconfig dev ethX vlan 5 set ports '0t 1t 5t'
+  
+  The swconfig framework will automatically invoke 'port Y set pvid Z' for every
+  port that is an untagged member of VLAN Y, setting its Primary VLAN ID. In
+  this example, ports 0 and 2 would get "pvid 4". The Primary VLAN ID of a port
+  is the VLAN ID associated with untagged packets coming in on that port.
+  
+  But if you wish to use VLAN IDs outside the range 0-15, this automatic
+  behaviour of the swconfig framework becomes a problem. The 16 VLANs that
+  swconfig can configure on the ADM6996 also have a "vid" setting. By default,
+  this is the same as the number of the VLAN entry, to make the simple behaviour
+  above possible. To still support a VLAN with a VLAN ID higher than 15
+  (presumably because you are in a network where such VLAN IDs are already in
+  use), you can change the "vid" setting of the VLAN to anything in the range
+  0-1023. But suppose you did the following:
+  
+      # swconfig dev ethX vlan 0 set vid 998 
+      # swconfig dev ethX vlan 0 set ports '0 2 5t'
+ 
+  Now the swconfig framework will issue 'port 0 set pvid 0' and 'port 2 set pvid
+  0'. But the "pvid" should be set to 998, so you are responsible for manually
+  fixing this!
+
+1.2 VLAN filtering
+
+  The switch is configured to apply source port filtering. This means that
+  packets are only accepted when the port the packets came in on is a member of
+  the VLAN the packet should go to.
+
+  Only membership of a VLAN is tested, it does not matter whether it is a tagged
+  or untagged membership.
+
+  For untagged packets, the destination VLAN is the Primary VLAN ID of the
+  incoming port. So if the PVID of a port is 0, but that port is not a member of
+  the VLAN with ID 0, this means that untagged packets on that port are dropped.
+  This can be used as a roundabout way of dropping untagged packets from a port,
+  a mode often referred to as "Admit only tagged packets".
+
+1.3 Reset
+
+  The two supported chip models do not have a sofware-initiated reset. When the
+  driver is initialised, as well as when the 'reset' swconfig option is invoked,
+  the driver will set those registers it knows about and supports to the correct
+  default value. But there are a lot of registers in the chip that the driver
+  does not support. If something changed those registers, invoking 'reset' or
+  performing a warm reboot might still leave the chip in a "broken" state. Only
+  a hardware reset will bring it back in the default state.
+
+2. Technical details on PHYs and the ADM6996
+
+  From the viewpoint of the Linux kernel, it is common that an Ethernet adapter
+  can be seen as a separate MAC entity and a separate PHY entity. The PHY entity
+  can be queried and set through registers accessible via an MDIO bus. A PHY
+  normally has a single address on that bus, in the range 0 through 31.
+
+  The ADM6996 has special-purpose registers in the range of PHYs 0 through 10.
+  Even though all these registers control a single ADM6996 chip, the Linux
+  kernel treats this as 11 separate PHYs.  The driver will bind to these
+  addresses to prevent a different PHY driver from binding and corrupting these
+  registers.
+
+  What Linux sees as the PHY on address 0 is meant for the Ethernet MAC
+  connected to the CPU port of the ADM6996 switch chip (port 5). This is the
+  Ethernet MAC you will use to send and receive data through the switch.
+
+  The PHYs at addresses 16 through 20 map to the PHYs on ports 0 through 4 of
+  the switch chip. These can be accessed with the Generic PHY driver, as the
+  registers have the common layout.
+
+  If a second Ethernet MAC on your board is wired to the port 4 PHY, that MAC
+  needs to bind to PHY address 20 for the port to work correctly.
+
+  The ADM6996 switch driver will reset the ports 0 through 3 on startup and when
+  'reset' is invoked. This could clash with a different PHY driver if the kernel
+  binds a PHY driver to address 16 through 19.
+
+  If Linux binds a PHY on addresses 1 through 10 to an Ethernet MAC, the ADM6996
+  driver will simply always report a connected 100 Mbit/s full-duplex link for
+  that PHY, and provide no other functionality. This is most likely not what you
+  want. So if you see a message in your log
+
+  	ethX: PHY overlaps ADM6996, providing fixed PHY yy.
+
+  This is most likely an indication that ethX will not work properly, and your
+  kernel needs to be configured to attach a different PHY to that Ethernet MAC.
+
+  Controlling the mapping between MACs and PHYs is usually done in platform- or
+  board-specific fixup code. The ADM6996 driver has no influence over this.
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/arch/mips/fw/myloader/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/arch/mips/fw/myloader/Makefile
new file mode 100644
index 0000000..34acfd0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/arch/mips/fw/myloader/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Compex's MyLoader support on MIPS architecture
+#
+
+lib-y += myloader.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/arch/mips/fw/myloader/myloader.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/arch/mips/fw/myloader/myloader.c
new file mode 100644
index 0000000..a26f9ad
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/arch/mips/fw/myloader/myloader.c
@@ -0,0 +1,63 @@
+/*
+ *  Compex's MyLoader specific prom routines
+ *
+ *  Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/string.h>
+
+#include <asm/addrspace.h>
+#include <asm/fw/myloader/myloader.h>
+
+#define SYS_PARAMS_ADDR		KSEG1ADDR(0x80000800)
+#define BOARD_PARAMS_ADDR	KSEG1ADDR(0x80000A00)
+#define PART_TABLE_ADDR		KSEG1ADDR(0x80000C00)
+#define BOOT_PARAMS_ADDR	KSEG1ADDR(0x80000E00)
+
+static struct myloader_info myloader_info __initdata;
+static int myloader_found __initdata;
+
+struct myloader_info * __init myloader_get_info(void)
+{
+	struct mylo_system_params *sysp;
+	struct mylo_board_params *boardp;
+	struct mylo_partition_table *parts;
+
+	if (myloader_found)
+		return &myloader_info;
+
+	sysp = (struct mylo_system_params *)(SYS_PARAMS_ADDR);
+	boardp = (struct mylo_board_params *)(BOARD_PARAMS_ADDR);
+	parts = (struct mylo_partition_table *)(PART_TABLE_ADDR);
+
+	printk(KERN_DEBUG "MyLoader: sysp=%08x, boardp=%08x, parts=%08x\n",
+		sysp->magic, boardp->magic, parts->magic);
+
+	/* Check for some magic numbers */
+	if (sysp->magic != MYLO_MAGIC_SYS_PARAMS ||
+	    boardp->magic != MYLO_MAGIC_BOARD_PARAMS ||
+	    le32_to_cpu(parts->magic) != MYLO_MAGIC_PARTITIONS)
+		return NULL;
+
+	printk(KERN_DEBUG "MyLoader: id=%04x:%04x, sub_id=%04x:%04x\n",
+		sysp->vid, sysp->did, sysp->svid, sysp->sdid);
+
+	myloader_info.vid = sysp->vid;
+	myloader_info.did = sysp->did;
+	myloader_info.svid = sysp->svid;
+	myloader_info.sdid = sysp->sdid;
+
+	memcpy(myloader_info.macs, boardp->addr, sizeof(myloader_info.macs));
+
+	myloader_found = 1;
+
+	return &myloader_info;
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/Kconfig b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/Kconfig
new file mode 100644
index 0000000..4832b8d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/Kconfig
@@ -0,0 +1,98 @@
+config MTD_SPLIT
+	def_bool n
+	help
+	  Generic MTD split support.
+
+config MTD_SPLIT_SUPPORT
+	def_bool MTD = y
+
+comment "Rootfs partition parsers"
+
+config MTD_SPLIT_SQUASHFS_ROOT
+	bool "Squashfs based root partition parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+	default n
+	help
+	  This provides a parsing function which allows to detect the
+	  offset and size of the unused portion of a rootfs partition
+	  containing a squashfs.
+
+comment "Firmware partition parsers"
+
+config MTD_SPLIT_BCM_WFI_FW
+	bool "Broadcom Whole Flash Image parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+
+config MTD_SPLIT_CFE_BOOTFS
+	bool "Parser finding rootfs appended to the CFE bootfs"
+	depends on MTD_SPLIT_SUPPORT && ARCH_BCM4908
+	select MTD_SPLIT
+	help
+	  cferom on BCM4908 (and bcm63xx) uses JFFS2 bootfs partition
+	  for storing kernel, cferam and some device specific files.
+	  There isn't any straight way of storing rootfs so it gets
+	  appended to the JFFS2 bootfs partition. Kernel needs to find
+	  it and run init from it. This parser is responsible for
+	  finding appended rootfs.
+
+config MTD_SPLIT_SEAMA_FW
+	bool "Seama firmware parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+
+config MTD_SPLIT_WRGG_FW
+	bool "WRGG firmware parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+
+config MTD_SPLIT_UIMAGE_FW
+	bool "uImage based firmware partition parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+
+config MTD_SPLIT_FIT_FW
+	bool "FIT based firmware partition parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+
+config MTD_SPLIT_LZMA_FW
+	bool "LZMA compressed kernel based firmware partition parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+
+config MTD_SPLIT_TPLINK_FW
+	bool "TP-Link firmware parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+
+config MTD_SPLIT_TRX_FW
+	bool "TRX image based firmware partition parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+
+config MTD_SPLIT_BRNIMAGE_FW
+	bool "brnImage (brnboot image) firmware parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+
+config MTD_SPLIT_EVA_FW
+	bool "EVA image based firmware partition parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+
+config MTD_SPLIT_MINOR_FW
+	bool "Mikrotik NOR image based firmware partition parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+
+config MTD_SPLIT_JIMAGE_FW
+	bool "JBOOT Image based firmware partition parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
+
+config MTD_SPLIT_ELF_FW
+	bool "ELF loader firmware partition parser"
+	depends on MTD_SPLIT_SUPPORT
+	select MTD_SPLIT
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/Makefile
new file mode 100644
index 0000000..9217d8f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/Makefile
@@ -0,0 +1,16 @@
+obj-$(CONFIG_MTD_SPLIT)		+= mtdsplit.o
+obj-$(CONFIG_MTD_SPLIT_BCM_WFI_FW) += mtdsplit_bcm_wfi.o
+obj-$(CONFIG_MTD_SPLIT_CFE_BOOTFS) += mtdsplit_cfe_bootfs.o
+obj-$(CONFIG_MTD_SPLIT_SEAMA_FW) += mtdsplit_seama.o
+obj-$(CONFIG_MTD_SPLIT_SQUASHFS_ROOT) += mtdsplit_squashfs.o
+obj-$(CONFIG_MTD_SPLIT_UIMAGE_FW) += mtdsplit_uimage.o
+obj-$(CONFIG_MTD_SPLIT_FIT_FW) += mtdsplit_fit.o
+obj-$(CONFIG_MTD_SPLIT_LZMA_FW) += mtdsplit_lzma.o
+obj-$(CONFIG_MTD_SPLIT_TPLINK_FW) += mtdsplit_tplink.o
+obj-$(CONFIG_MTD_SPLIT_TRX_FW) += mtdsplit_trx.o
+obj-$(CONFIG_MTD_SPLIT_BRNIMAGE_FW) += mtdsplit_brnimage.o
+obj-$(CONFIG_MTD_SPLIT_EVA_FW) += mtdsplit_eva.o
+obj-$(CONFIG_MTD_SPLIT_WRGG_FW) += mtdsplit_wrgg.o
+obj-$(CONFIG_MTD_SPLIT_MINOR_FW) += mtdsplit_minor.o
+obj-$(CONFIG_MTD_SPLIT_JIMAGE_FW) += mtdsplit_jimage.o
+obj-$(CONFIG_MTD_SPLIT_ELF_FW) += mtdsplit_elf.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit.c
new file mode 100644
index 0000000..b2e51dc
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2009-2013 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2009-2013 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2012 Jonas Gorski <jogo@openwrt.org>
+ * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#define pr_fmt(fmt)	"mtdsplit: " fmt
+
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/magic.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/byteorder/generic.h>
+
+#include "mtdsplit.h"
+
+#define UBI_EC_MAGIC			0x55424923	/* UBI# */
+
+struct squashfs_super_block {
+	__le32 s_magic;
+	__le32 pad0[9];
+	__le64 bytes_used;
+};
+
+int mtd_get_squashfs_len(struct mtd_info *master,
+			 size_t offset,
+			 size_t *squashfs_len)
+{
+	struct squashfs_super_block sb;
+	size_t retlen;
+	int err;
+
+	err = mtd_read(master, offset, sizeof(sb), &retlen, (void *)&sb);
+	if (err || (retlen != sizeof(sb))) {
+		pr_alert("error occured while reading from \"%s\"\n",
+			 master->name);
+		return -EIO;
+	}
+
+	if (le32_to_cpu(sb.s_magic) != SQUASHFS_MAGIC) {
+		pr_alert("no squashfs found in \"%s\"\n", master->name);
+		return -EINVAL;
+	}
+
+	retlen = le64_to_cpu(sb.bytes_used);
+	if (retlen <= 0) {
+		pr_alert("squashfs is empty in \"%s\"\n", master->name);
+		return -ENODEV;
+	}
+
+	if (offset + retlen > master->size) {
+		pr_alert("squashfs has invalid size in \"%s\"\n",
+			 master->name);
+		return -EINVAL;
+	}
+
+	*squashfs_len = retlen;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mtd_get_squashfs_len);
+
+static ssize_t mtd_next_eb(struct mtd_info *mtd, size_t offset)
+{
+	return mtd_rounddown_to_eb(offset, mtd) + mtd->erasesize;
+}
+
+int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset,
+			   enum mtdsplit_part_type *type)
+{
+	u32 magic;
+	size_t retlen;
+	int ret;
+
+	ret = mtd_read(mtd, offset, sizeof(magic), &retlen,
+		       (unsigned char *) &magic);
+	if (ret)
+		return ret;
+
+	if (retlen != sizeof(magic))
+		return -EIO;
+
+	if (le32_to_cpu(magic) == SQUASHFS_MAGIC) {
+		if (type)
+			*type = MTDSPLIT_PART_TYPE_SQUASHFS;
+		return 0;
+	} else if (magic == 0x19852003) {
+		if (type)
+			*type = MTDSPLIT_PART_TYPE_JFFS2;
+		return 0;
+	} else if (be32_to_cpu(magic) == UBI_EC_MAGIC) {
+		if (type)
+			*type = MTDSPLIT_PART_TYPE_UBI;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(mtd_check_rootfs_magic);
+
+int mtd_find_rootfs_from(struct mtd_info *mtd,
+			 size_t from,
+			 size_t limit,
+			 size_t *ret_offset,
+			 enum mtdsplit_part_type *type)
+{
+	size_t offset;
+	int err;
+
+	for (offset = from; offset < limit;
+	     offset = mtd_next_eb(mtd, offset)) {
+		err = mtd_check_rootfs_magic(mtd, offset, type);
+		if (err)
+			continue;
+
+		*ret_offset = offset;
+		return 0;
+	}
+
+	return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(mtd_find_rootfs_from);
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit.h
new file mode 100644
index 0000000..71d62a8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2009-2013 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2009-2013 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2012 Jonas Gorski <jogo@openwrt.org>
+ * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#ifndef _MTDSPLIT_H
+#define _MTDSPLIT_H
+
+#define KERNEL_PART_NAME	"kernel"
+#define ROOTFS_PART_NAME	"rootfs"
+#define UBI_PART_NAME		"ubi"
+
+#define ROOTFS_SPLIT_NAME	"rootfs_data"
+
+enum mtdsplit_part_type {
+	MTDSPLIT_PART_TYPE_UNK = 0,
+	MTDSPLIT_PART_TYPE_SQUASHFS,
+	MTDSPLIT_PART_TYPE_JFFS2,
+	MTDSPLIT_PART_TYPE_UBI,
+};
+
+#ifdef CONFIG_MTD_SPLIT
+int mtd_get_squashfs_len(struct mtd_info *master,
+			 size_t offset,
+			 size_t *squashfs_len);
+
+int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset,
+			   enum mtdsplit_part_type *type);
+
+int mtd_find_rootfs_from(struct mtd_info *mtd,
+			 size_t from,
+			 size_t limit,
+			 size_t *ret_offset,
+			 enum mtdsplit_part_type *type);
+
+#else
+static inline int mtd_get_squashfs_len(struct mtd_info *master,
+				       size_t offset,
+				       size_t *squashfs_len)
+{
+	return -ENODEV;
+}
+
+static inline int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset,
+					 enum mtdsplit_part_type *type)
+{
+	return -EINVAL;
+}
+
+static inline int mtd_find_rootfs_from(struct mtd_info *mtd,
+				       size_t from,
+				       size_t limit,
+				       size_t *ret_offset,
+				       enum mtdsplit_part_type *type)
+{
+	return -ENODEV;
+}
+#endif /* CONFIG_MTD_SPLIT */
+
+#endif /* _MTDSPLIT_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c
new file mode 100644
index 0000000..1ddcf67
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c
@@ -0,0 +1,523 @@
+/*
+ * MTD split for Broadcom Whole Flash Image
+ *
+ * Copyright (C) 2020 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#define je16_to_cpu(x) ((x).v16)
+#define je32_to_cpu(x) ((x).v32)
+
+#include <linux/crc32.h>
+#include <linux/init.h>
+#include <linux/jffs2.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/byteorder/generic.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include "mtdsplit.h"
+
+#define char_to_num(c)		((c >= '0' && c <= '9') ? (c - '0') : (0))
+
+#define BCM_WFI_PARTS		3
+#define BCM_WFI_SPLIT_PARTS	2
+
+#define CFERAM_NAME		"cferam"
+#define CFERAM_NAME_LEN		(sizeof(CFERAM_NAME) - 1)
+#define KERNEL_NAME		"vmlinux.lz"
+#define KERNEL_NAME_LEN		(sizeof(KERNEL_NAME) - 1)
+#define OPENWRT_NAME		"1-openwrt"
+#define OPENWRT_NAME_LEN	(sizeof(OPENWRT_NAME) - 1)
+
+#define UBI_MAGIC		0x55424923
+
+#define CFE_MAGIC_PFX		"cferam."
+#define CFE_MAGIC_PFX_LEN	(sizeof(CFE_MAGIC_PFX) - 1)
+#define CFE_MAGIC		"cferam.000"
+#define CFE_MAGIC_LEN		(sizeof(CFE_MAGIC) - 1)
+#define SERCOMM_MAGIC_PFX	"eRcOmM."
+#define SERCOMM_MAGIC_PFX_LEN	(sizeof(SERCOMM_MAGIC_PFX) - 1)
+#define SERCOMM_MAGIC		"eRcOmM.000"
+#define SERCOMM_MAGIC_LEN	(sizeof(SERCOMM_MAGIC) - 1)
+
+#define PART_CFERAM		"cferam"
+#define PART_FIRMWARE		"firmware"
+#define PART_IMAGE_1		"img1"
+#define PART_IMAGE_2		"img2"
+
+static u32 jffs2_dirent_crc(struct jffs2_raw_dirent *node)
+{
+	return crc32(0, node, sizeof(struct jffs2_raw_dirent) - 8);
+}
+
+static bool jffs2_dirent_valid(struct jffs2_raw_dirent *node)
+{
+	return ((je16_to_cpu(node->magic) == JFFS2_MAGIC_BITMASK) &&
+		(je16_to_cpu(node->nodetype) == JFFS2_NODETYPE_DIRENT) &&
+		je32_to_cpu(node->ino) &&
+		je32_to_cpu(node->node_crc) == jffs2_dirent_crc(node));
+}
+
+static int jffs2_find_file(struct mtd_info *mtd, uint8_t *buf,
+			   const char *name, size_t name_len,
+			   loff_t *offs, loff_t size,
+			   char **out_name, size_t *out_name_len)
+{
+	const loff_t end = *offs + size;
+	struct jffs2_raw_dirent *node;
+	bool valid = false;
+	size_t retlen;
+	uint16_t magic;
+	int rc;
+
+	for (; *offs < end; *offs += mtd->erasesize) {
+		unsigned int block_offs = 0;
+
+		/* Skip CFE erased blocks */
+		rc = mtd_read(mtd, *offs, sizeof(magic), &retlen,
+			      (void *) &magic);
+		if (rc || retlen != sizeof(magic)) {
+			continue;
+		}
+
+		/* Skip blocks not starting with JFFS2 magic */
+		if (magic != JFFS2_MAGIC_BITMASK)
+			continue;
+
+		/* Read full block */
+		rc = mtd_read(mtd, *offs, mtd->erasesize, &retlen,
+			      (void *) buf);
+		if (rc)
+			return rc;
+		if (retlen != mtd->erasesize)
+			return -EINVAL;
+
+		while (block_offs < mtd->erasesize) {
+			node = (struct jffs2_raw_dirent *) &buf[block_offs];
+
+			if (!jffs2_dirent_valid(node)) {
+				block_offs += 4;
+				continue;
+			}
+
+			if (!memcmp(node->name, OPENWRT_NAME,
+				    OPENWRT_NAME_LEN)) {
+				valid = true;
+			} else if (!memcmp(node->name, name, name_len)) {
+				if (!valid)
+					return -EINVAL;
+
+				if (out_name)
+					*out_name = kstrndup(node->name,
+							     node->nsize,
+							     GFP_KERNEL);
+
+				if (out_name_len)
+					*out_name_len = node->nsize;
+
+				return 0;
+			}
+
+			block_offs += je32_to_cpu(node->totlen);
+			block_offs = (block_offs + 0x3) & ~0x3;
+		}
+	}
+
+	return -ENOENT;
+}
+
+static int ubifs_find(struct mtd_info *mtd, loff_t *offs, loff_t size)
+{
+	const loff_t end = *offs + size;
+	uint32_t magic;
+	size_t retlen;
+	int rc;
+
+	for (; *offs < end; *offs += mtd->erasesize) {
+		rc = mtd_read(mtd, *offs, sizeof(magic), &retlen,
+			      (unsigned char *) &magic);
+		if (rc || retlen != sizeof(magic))
+			continue;
+
+		if (be32_to_cpu(magic) == UBI_MAGIC)
+			return 0;
+	}
+
+	return -ENOENT;
+}
+
+static int parse_bcm_wfi(struct mtd_info *master,
+			 const struct mtd_partition **pparts,
+			 uint8_t *buf, loff_t off, loff_t size, bool cfe_part)
+{
+	struct mtd_partition *parts;
+	loff_t cfe_off, kernel_off, rootfs_off;
+	unsigned int num_parts = BCM_WFI_PARTS, cur_part = 0;
+	int ret;
+
+	if (cfe_part) {
+		num_parts++;
+		cfe_off = off;
+
+		ret = jffs2_find_file(master, buf, CFERAM_NAME,
+				      CFERAM_NAME_LEN, &cfe_off,
+				      size - (cfe_off - off), NULL, NULL);
+		if (ret)
+			return ret;
+
+		kernel_off = cfe_off + master->erasesize;
+	} else {
+		kernel_off = off;
+	}
+
+	ret = jffs2_find_file(master, buf, KERNEL_NAME, KERNEL_NAME_LEN,
+			      &kernel_off, size - (kernel_off - off),
+			      NULL, NULL);
+	if (ret)
+		return ret;
+
+	rootfs_off = kernel_off + master->erasesize;
+	ret = ubifs_find(master, &rootfs_off, size - (rootfs_off - off));
+	if (ret)
+		return ret;
+
+	parts = kzalloc(num_parts * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	if (cfe_part) {
+		parts[cur_part].name = PART_CFERAM;
+		parts[cur_part].mask_flags = MTD_WRITEABLE;
+		parts[cur_part].offset = cfe_off;
+		parts[cur_part].size = kernel_off - cfe_off;
+		cur_part++;
+	}
+
+	parts[cur_part].name = PART_FIRMWARE;
+	parts[cur_part].offset = kernel_off;
+	parts[cur_part].size = size - (kernel_off - off);
+	cur_part++;
+
+	parts[cur_part].name = KERNEL_PART_NAME;
+	parts[cur_part].offset = kernel_off;
+	parts[cur_part].size = rootfs_off - kernel_off;
+	cur_part++;
+
+	parts[cur_part].name = UBI_PART_NAME;
+	parts[cur_part].offset = rootfs_off;
+	parts[cur_part].size = size - (rootfs_off - off);
+	cur_part++;
+
+	*pparts = parts;
+
+	return num_parts;
+}
+
+static int mtdsplit_parse_bcm_wfi(struct mtd_info *master,
+				  const struct mtd_partition **pparts,
+				  struct mtd_part_parser_data *data)
+{
+	struct device_node *mtd_node;
+	bool cfe_part = true;
+	uint8_t *buf;
+	int ret;
+
+	mtd_node = mtd_get_of_node(master);
+	if (!mtd_node)
+		return -EINVAL;
+
+	buf = kzalloc(master->erasesize, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	if (of_property_read_bool(mtd_node, "brcm,no-cferam"))
+		cfe_part = false;
+
+	ret = parse_bcm_wfi(master, pparts, buf, 0, master->size, cfe_part);
+
+	kfree(buf);
+
+	return ret;
+}
+
+static const struct of_device_id mtdsplit_bcm_wfi_of_match[] = {
+	{ .compatible = "brcm,wfi" },
+	{ },
+};
+
+static struct mtd_part_parser mtdsplit_bcm_wfi_parser = {
+	.owner = THIS_MODULE,
+	.name = "bcm-wfi-fw",
+	.of_match_table = mtdsplit_bcm_wfi_of_match,
+	.parse_fn = mtdsplit_parse_bcm_wfi,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+static int cferam_bootflag_value(const char *name, size_t name_len)
+{
+	int rc = -ENOENT;
+
+	if (name &&
+	    (name_len >= CFE_MAGIC_LEN) &&
+	    !memcmp(name, CFE_MAGIC_PFX, CFE_MAGIC_PFX_LEN)) {
+		rc = char_to_num(name[CFE_MAGIC_PFX_LEN + 0]) * 100;
+		rc += char_to_num(name[CFE_MAGIC_PFX_LEN + 1]) * 10;
+		rc += char_to_num(name[CFE_MAGIC_PFX_LEN + 2]) * 1;
+	}
+
+	return rc;
+}
+
+static int mtdsplit_parse_bcm_wfi_split(struct mtd_info *master,
+					const struct mtd_partition **pparts,
+					struct mtd_part_parser_data *data)
+{
+	struct mtd_partition *parts;
+	loff_t cfe_off;
+	loff_t img1_off = 0;
+	loff_t img2_off = master->size / 2;
+	loff_t img1_size = (img2_off - img1_off);
+	loff_t img2_size = (master->size - img2_off);
+	loff_t active_off, inactive_off;
+	loff_t active_size, inactive_size;
+	const char *inactive_name;
+	uint8_t *buf;
+	char *cfe1_name = NULL, *cfe2_name = NULL;
+	size_t cfe1_size = 0, cfe2_size = 0;
+	int ret;
+	int bf1, bf2;
+
+	buf = kzalloc(master->erasesize, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	cfe_off = img1_off;
+	ret = jffs2_find_file(master, buf, CFERAM_NAME, CFERAM_NAME_LEN,
+			      &cfe_off, img1_size, &cfe1_name, &cfe1_size);
+
+	cfe_off = img2_off;
+	ret = jffs2_find_file(master, buf, CFERAM_NAME, CFERAM_NAME_LEN,
+			      &cfe_off, img2_size, &cfe2_name, &cfe2_size);
+
+	bf1 = cferam_bootflag_value(cfe1_name, cfe1_size);
+	if (bf1 >= 0)
+		printk("cferam: bootflag1=%d\n", bf1);
+
+	bf2 = cferam_bootflag_value(cfe2_name, cfe2_size);
+	if (bf2 >= 0)
+		printk("cferam: bootflag2=%d\n", bf2);
+
+	kfree(cfe1_name);
+	kfree(cfe2_name);
+
+	if (bf1 >= bf2) {
+		active_off = img1_off;
+		active_size = img1_size;
+		inactive_off = img2_off;
+		inactive_size = img2_size;
+		inactive_name = PART_IMAGE_2;
+	} else {
+		active_off = img2_off;
+		active_size = img2_size;
+		inactive_off = img1_off;
+		inactive_size = img1_size;
+		inactive_name = PART_IMAGE_1;
+	}
+
+	ret = parse_bcm_wfi(master, pparts, buf, active_off, active_size, true);
+
+	kfree(buf);
+
+	if (ret > 0) {
+		parts = kzalloc((ret + 1) * sizeof(*parts), GFP_KERNEL);
+		if (!parts)
+			return -ENOMEM;
+
+		memcpy(parts, *pparts, ret * sizeof(*parts));
+		kfree(*pparts);
+
+		parts[ret].name = inactive_name;
+		parts[ret].offset = inactive_off;
+		parts[ret].size = inactive_size;
+		ret++;
+
+		*pparts = parts;
+	} else {
+		parts = kzalloc(BCM_WFI_SPLIT_PARTS * sizeof(*parts), GFP_KERNEL);
+
+		parts[0].name = PART_IMAGE_1;
+		parts[0].offset = img1_off;
+		parts[0].size = img1_size;
+
+		parts[1].name = PART_IMAGE_2;
+		parts[1].offset = img2_off;
+		parts[1].size = img2_size;
+
+		*pparts = parts;
+	}
+
+	return ret;
+}
+
+static const struct of_device_id mtdsplit_bcm_wfi_split_of_match[] = {
+	{ .compatible = "brcm,wfi-split" },
+	{ },
+};
+
+static struct mtd_part_parser mtdsplit_bcm_wfi_split_parser = {
+	.owner = THIS_MODULE,
+	.name = "bcm-wfi-split-fw",
+	.of_match_table = mtdsplit_bcm_wfi_split_of_match,
+	.parse_fn = mtdsplit_parse_bcm_wfi_split,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+static int sercomm_bootflag_value(struct mtd_info *mtd, uint8_t *buf)
+{
+	size_t retlen;
+	loff_t offs;
+	int rc;
+
+	for (offs = 0; offs < mtd->size; offs += mtd->erasesize) {
+		rc = mtd_read(mtd, offs, SERCOMM_MAGIC_LEN, &retlen, buf);
+		if (rc || retlen != SERCOMM_MAGIC_LEN)
+			continue;
+
+		if (memcmp(buf, SERCOMM_MAGIC_PFX, SERCOMM_MAGIC_PFX_LEN))
+			continue;
+
+		rc = char_to_num(buf[SERCOMM_MAGIC_PFX_LEN + 0]) * 100;
+		rc += char_to_num(buf[SERCOMM_MAGIC_PFX_LEN + 1]) * 10;
+		rc += char_to_num(buf[SERCOMM_MAGIC_PFX_LEN + 2]) * 1;
+
+		return rc;
+	}
+
+	return -ENOENT;
+}
+
+static int mtdsplit_parse_ser_wfi(struct mtd_info *master,
+				  const struct mtd_partition **pparts,
+				  struct mtd_part_parser_data *data)
+{
+	struct mtd_partition *parts;
+	struct mtd_info *mtd_bf1, *mtd_bf2;
+	loff_t img1_off = 0;
+	loff_t img2_off = master->size / 2;
+	loff_t img1_size = (img2_off - img1_off);
+	loff_t img2_size = (master->size - img2_off);
+	loff_t active_off, inactive_off;
+	loff_t active_size, inactive_size;
+	const char *inactive_name;
+	uint8_t *buf;
+	int bf1, bf2;
+	int ret;
+
+	mtd_bf1 = get_mtd_device_nm("bootflag1");
+	if (IS_ERR(mtd_bf1))
+		return -ENOENT;
+
+	mtd_bf2 = get_mtd_device_nm("bootflag2");
+	if (IS_ERR(mtd_bf2))
+		return -ENOENT;
+
+	buf = kzalloc(master->erasesize, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	bf1 = sercomm_bootflag_value(mtd_bf1, buf);
+	if (bf1 >= 0)
+		printk("sercomm: bootflag1=%d\n", bf1);
+
+	bf2 = sercomm_bootflag_value(mtd_bf2, buf);
+	if (bf2 >= 0)
+		printk("sercomm: bootflag2=%d\n", bf2);
+
+	if (bf1 == bf2 && bf2 >= 0) {
+		struct erase_info bf_erase;
+
+		bf2 = -ENOENT;
+		bf_erase.addr = 0;
+		bf_erase.len = mtd_bf2->size;
+		mtd_erase(mtd_bf2, &bf_erase);
+	}
+
+	if (bf1 >= bf2) {
+		active_off = img1_off;
+		active_size = img1_size;
+		inactive_off = img2_off;
+		inactive_size = img2_size;
+		inactive_name = PART_IMAGE_2;
+	} else {
+		active_off = img2_off;
+		active_size = img2_size;
+		inactive_off = img1_off;
+		inactive_size = img1_size;
+		inactive_name = PART_IMAGE_1;
+	}
+
+	ret = parse_bcm_wfi(master, pparts, buf, active_off, active_size, false);
+
+	kfree(buf);
+
+	if (ret > 0) {
+		parts = kzalloc((ret + 1) * sizeof(*parts), GFP_KERNEL);
+		if (!parts)
+			return -ENOMEM;
+
+		memcpy(parts, *pparts, ret * sizeof(*parts));
+		kfree(*pparts);
+
+		parts[ret].name = inactive_name;
+		parts[ret].offset = inactive_off;
+		parts[ret].size = inactive_size;
+		ret++;
+
+		*pparts = parts;
+	} else {
+		parts = kzalloc(BCM_WFI_SPLIT_PARTS * sizeof(*parts), GFP_KERNEL);
+
+		parts[0].name = PART_IMAGE_1;
+		parts[0].offset = img1_off;
+		parts[0].size = img1_size;
+
+		parts[1].name = PART_IMAGE_2;
+		parts[1].offset = img2_off;
+		parts[1].size = img2_size;
+
+		*pparts = parts;
+	}
+
+	return ret;
+}
+
+static const struct of_device_id mtdsplit_ser_wfi_of_match[] = {
+	{ .compatible = "sercomm,wfi" },
+	{ },
+};
+
+static struct mtd_part_parser mtdsplit_ser_wfi_parser = {
+	.owner = THIS_MODULE,
+	.name = "ser-wfi-fw",
+	.of_match_table = mtdsplit_ser_wfi_of_match,
+	.parse_fn = mtdsplit_parse_ser_wfi,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+static int __init mtdsplit_bcm_wfi_init(void)
+{
+	register_mtd_parser(&mtdsplit_bcm_wfi_parser);
+	register_mtd_parser(&mtdsplit_bcm_wfi_split_parser);
+	register_mtd_parser(&mtdsplit_ser_wfi_parser);
+
+	return 0;
+}
+
+module_init(mtdsplit_bcm_wfi_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_brnimage.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_brnimage.c
new file mode 100644
index 0000000..3f2d796
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_brnimage.c
@@ -0,0 +1,104 @@
+/*
+ *  Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ *  Copyright (C) 2015 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/byteorder/generic.h>
+
+#include "mtdsplit.h"
+
+#define BRNIMAGE_NR_PARTS	2
+
+#define BRNIMAGE_ALIGN_BYTES	0x400
+#define BRNIMAGE_FOOTER_SIZE	12
+
+#define BRNIMAGE_MIN_OVERHEAD	(BRNIMAGE_FOOTER_SIZE)
+#define BRNIMAGE_MAX_OVERHEAD	(BRNIMAGE_ALIGN_BYTES + BRNIMAGE_FOOTER_SIZE)
+
+static int mtdsplit_parse_brnimage(struct mtd_info *master,
+				const struct mtd_partition **pparts,
+				struct mtd_part_parser_data *data)
+{
+	struct mtd_partition *parts;
+	uint32_t buf;
+	unsigned long rootfs_offset, rootfs_size, kernel_size;
+	size_t len;
+	int ret = 0;
+
+	for (rootfs_offset = 0; rootfs_offset < master->size;
+	     rootfs_offset += BRNIMAGE_ALIGN_BYTES) {
+		ret = mtd_check_rootfs_magic(master, rootfs_offset, NULL);
+		if (!ret)
+			break;
+	}
+
+	if (ret)
+		return ret;
+
+	if (rootfs_offset >= master->size)
+		return -EINVAL;
+
+	ret = mtd_read(master, rootfs_offset - BRNIMAGE_FOOTER_SIZE, 4, &len,
+			(void *)&buf);
+	if (ret)
+		return ret;
+
+	if (len != 4)
+		return -EIO;
+
+	kernel_size = le32_to_cpu(buf);
+
+	if (kernel_size > (rootfs_offset - BRNIMAGE_MIN_OVERHEAD))
+		return -EINVAL;
+
+	if (kernel_size < (rootfs_offset - BRNIMAGE_MAX_OVERHEAD))
+		return -EINVAL;
+
+	/*
+	 * The footer must be untouched as it contains the checksum of the
+	 * original brnImage (kernel + squashfs)!
+	 */
+	rootfs_size = master->size - rootfs_offset - BRNIMAGE_FOOTER_SIZE;
+
+	parts = kzalloc(BRNIMAGE_NR_PARTS * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	parts[0].name = KERNEL_PART_NAME;
+	parts[0].offset = 0;
+	parts[0].size = kernel_size;
+
+	parts[1].name = ROOTFS_PART_NAME;
+	parts[1].offset = rootfs_offset;
+	parts[1].size = rootfs_size;
+
+	*pparts = parts;
+	return BRNIMAGE_NR_PARTS;
+}
+
+static struct mtd_part_parser mtdsplit_brnimage_parser = {
+	.owner = THIS_MODULE,
+	.name = "brnimage-fw",
+	.parse_fn = mtdsplit_parse_brnimage,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+static int __init mtdsplit_brnimage_init(void)
+{
+	register_mtd_parser(&mtdsplit_brnimage_parser);
+
+	return 0;
+}
+
+subsys_initcall(mtdsplit_brnimage_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_cfe_bootfs.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_cfe_bootfs.c
new file mode 100644
index 0000000..a3474c9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_cfe_bootfs.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
+ */
+
+#include <linux/init.h>
+#include <linux/jffs2.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+#include "mtdsplit.h"
+
+#define je16_to_cpu(x) ((x).v16)
+#define je32_to_cpu(x) ((x).v32)
+
+#define NR_PARTS		2
+
+static int mtdsplit_cfe_bootfs_parse(struct mtd_info *mtd,
+				     const struct mtd_partition **pparts,
+				     struct mtd_part_parser_data *data)
+{
+	struct jffs2_raw_dirent node;
+	enum mtdsplit_part_type type;
+	struct mtd_partition *parts;
+	size_t rootfs_offset;
+	size_t retlen;
+	size_t offset;
+	int err;
+
+	/* Don't parse backup partitions */
+	if (strcmp(mtd->name, "firmware"))
+		return -EINVAL;
+
+	/* Find the end of JFFS2 bootfs partition */
+	offset = 0;
+	do {
+		err = mtd_read(mtd, offset, sizeof(node), &retlen, (void *)&node);
+		if (err || retlen != sizeof(node))
+			break;
+
+		if (je16_to_cpu(node.magic) != JFFS2_MAGIC_BITMASK)
+			break;
+
+		offset += je32_to_cpu(node.totlen);
+		offset = (offset + 0x3) & ~0x3;
+	} while (offset < mtd->size);
+
+	/* Find rootfs partition that follows the bootfs */
+	err = mtd_find_rootfs_from(mtd, mtd->erasesize, mtd->size, &rootfs_offset, &type);
+	if (err)
+		return err;
+
+	parts = kzalloc(NR_PARTS * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	parts[0].name = "bootfs";
+	parts[0].offset = 0;
+	parts[0].size = rootfs_offset;
+
+	if (type == MTDSPLIT_PART_TYPE_UBI)
+		parts[1].name = UBI_PART_NAME;
+	else
+		parts[1].name = ROOTFS_PART_NAME;
+	parts[1].offset = rootfs_offset;
+	parts[1].size = mtd->size - rootfs_offset;
+
+	*pparts = parts;
+
+	return NR_PARTS;
+}
+
+static const struct of_device_id mtdsplit_cfe_bootfs_of_match_table[] = {
+	{ .compatible = "brcm,bcm4908-firmware" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mtdsplit_cfe_bootfs_of_match_table);
+
+static struct mtd_part_parser mtdsplit_cfe_bootfs_parser = {
+	.owner = THIS_MODULE,
+	.name = "cfe-bootfs",
+	.of_match_table = mtdsplit_cfe_bootfs_of_match_table,
+	.parse_fn = mtdsplit_cfe_bootfs_parse,
+};
+
+module_mtd_part_parser(mtdsplit_cfe_bootfs_parser);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_elf.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_elf.c
new file mode 100644
index 0000000..4781841
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_elf.c
@@ -0,0 +1,287 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ *  MTD splitter for ELF loader firmware partitions
+ *
+ *  Copyright (C) 2020 Sander Vanheule <sander@svanheule.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; version 2.
+ *
+ *  To parse the ELF kernel loader, a small ELF parser is used that can
+ *  handle both ELF32 or ELF64 class loaders. The splitter assumes that the
+ *  kernel is always located before the rootfs, whether it is embedded in the
+ *  loader or not.
+ *
+ *  The kernel image is preferably embedded inside the ELF loader, so the end
+ *  of the loader equals the end of the kernel partition. This is due to the
+ *  way mtd_find_rootfs_from searches for the the rootfs:
+ *  - if the kernel image is embedded in the loader, the appended rootfs may
+ *    follow the loader immediately, within the same erase block.
+ *  - if the kernel image is not embedded in the loader, but placed at some
+ *    offset behind the loader (OKLI-style loader), the rootfs must be
+ *    aligned to an erase-block after the loader and kernel image.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+#include <linux/byteorder/generic.h>
+
+#include "mtdsplit.h"
+
+#define ELF_NR_PARTS	2
+
+#define ELF_MAGIC	0x7f454c46 /* 0x7f E L F */
+#define ELF_CLASS_32	1
+#define ELF_CLASS_64	2
+
+struct elf_header_ident {
+	uint32_t magic;
+	uint8_t class;
+	uint8_t data;
+	uint8_t version;
+	uint8_t osabi;
+	uint8_t abiversion;
+	uint8_t pad[7];
+};
+
+struct elf_header_32 {
+	uint16_t type;
+	uint16_t machine;
+	uint32_t version;
+	uint32_t entry;
+	uint32_t phoff;
+	uint32_t shoff;
+	uint32_t flags;
+	uint16_t ehsize;
+	uint16_t phentsize;
+	uint16_t phnum;
+	uint16_t shentsize;
+	uint16_t shnum;
+	uint16_t shstrndx;
+};
+
+struct elf_header_64 {
+	uint16_t type;
+	uint16_t machine;
+	uint32_t version;
+	uint64_t entry;
+	uint64_t phoff;
+	uint64_t shoff;
+	uint32_t flags;
+	uint16_t ehsize;
+	uint16_t phentsize;
+	uint16_t phnum;
+	uint16_t shentsize;
+	uint16_t shnum;
+	uint16_t shstrndx;
+};
+
+struct elf_header {
+	struct elf_header_ident ident;
+	union {
+		struct elf_header_32 elf32;
+		struct elf_header_64 elf64;
+	};
+};
+
+struct elf_program_header_32 {
+	uint32_t type;
+	uint32_t offset;
+	uint32_t vaddr;
+	uint32_t paddr;
+	uint32_t filesize;
+	uint32_t memsize;
+	uint32_t flags;
+};
+
+struct elf_program_header_64 {
+	uint32_t type;
+	uint32_t flags;
+	uint64_t offset;
+	uint64_t vaddr;
+	uint64_t paddr;
+	uint64_t filesize;
+	uint64_t memsize;
+};
+
+
+static int mtdsplit_elf_read_mtd(struct mtd_info *mtd, size_t offset,
+				 uint8_t *dst, size_t len)
+{
+	size_t retlen;
+	int ret;
+
+	ret = mtd_read(mtd, offset, len, &retlen, dst);
+	if (ret) {
+		pr_debug("read error in \"%s\"\n", mtd->name);
+		return ret;
+	}
+
+	if (retlen != len) {
+		pr_debug("short read in \"%s\"\n", mtd->name);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int elf32_determine_size(struct mtd_info *mtd, struct elf_header *hdr,
+				size_t *size)
+{
+	struct elf_header_32 *hdr32 = &(hdr->elf32);
+	int err;
+	size_t section_end, ph_table_end, ph_entry;
+	struct elf_program_header_32 ph;
+
+	*size = 0;
+
+	if (hdr32->shoff > 0) {
+		*size = hdr32->shoff + hdr32->shentsize * hdr32->shnum;
+		return 0;
+	}
+
+	ph_entry = hdr32->phoff;
+	ph_table_end = hdr32->phoff + hdr32->phentsize * hdr32->phnum;
+
+	while (ph_entry < ph_table_end) {
+		err = mtdsplit_elf_read_mtd(mtd, ph_entry, (uint8_t *)(&ph),
+					    sizeof(ph));
+		if (err)
+			return err;
+
+		section_end = ph.offset + ph.filesize;
+		if (section_end > *size)
+			*size = section_end;
+
+		ph_entry += hdr32->phentsize;
+	}
+
+	return 0;
+}
+
+static int elf64_determine_size(struct mtd_info *mtd, struct elf_header *hdr,
+				size_t *size)
+{
+	struct elf_header_64 *hdr64 = &(hdr->elf64);
+	int err;
+	size_t section_end, ph_table_end, ph_entry;
+	struct elf_program_header_64 ph;
+
+	*size = 0;
+
+	if (hdr64->shoff > 0) {
+		*size = hdr64->shoff + hdr64->shentsize * hdr64->shnum;
+		return 0;
+	}
+
+	ph_entry = hdr64->phoff;
+	ph_table_end = hdr64->phoff + hdr64->phentsize * hdr64->phnum;
+
+	while (ph_entry < ph_table_end) {
+		err = mtdsplit_elf_read_mtd(mtd, ph_entry, (uint8_t *)(&ph),
+					    sizeof(ph));
+		if (err)
+			return err;
+
+		section_end = ph.offset + ph.filesize;
+		if (section_end > *size)
+			*size = section_end;
+
+		ph_entry += hdr64->phentsize;
+	}
+
+	return 0;
+}
+
+static int mtdsplit_parse_elf(struct mtd_info *mtd,
+			      const struct mtd_partition **pparts,
+			      struct mtd_part_parser_data *data)
+{
+	struct elf_header hdr;
+	size_t loader_size, rootfs_offset;
+	enum mtdsplit_part_type type;
+	struct mtd_partition *parts;
+	int err;
+
+	err = mtdsplit_elf_read_mtd(mtd, 0, (uint8_t *)&hdr, sizeof(hdr));
+	if (err)
+		return err;
+
+	if (be32_to_cpu(hdr.ident.magic) != ELF_MAGIC) {
+		pr_debug("invalid ELF magic %08x\n",
+			 be32_to_cpu(hdr.ident.magic));
+		return -EINVAL;
+	}
+
+	switch (hdr.ident.class) {
+	case ELF_CLASS_32:
+		err = elf32_determine_size(mtd, &hdr, &loader_size);
+		break;
+	case ELF_CLASS_64:
+		err = elf64_determine_size(mtd, &hdr, &loader_size);
+		break;
+	default:
+		pr_debug("invalid ELF class %i\n", hdr.ident.class);
+		err = -EINVAL;
+	}
+
+	if (err)
+		return err;
+
+	err = mtd_find_rootfs_from(mtd, loader_size, mtd->size,
+				   &rootfs_offset, &type);
+	if (err)
+		return err;
+
+	if (rootfs_offset == mtd->size) {
+		pr_debug("no rootfs found in \"%s\"\n", mtd->name);
+		return -ENODEV;
+	}
+
+	parts = kzalloc(ELF_NR_PARTS * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	parts[0].name = KERNEL_PART_NAME;
+	parts[0].offset = 0;
+	parts[0].size = rootfs_offset;
+
+	if (type == MTDSPLIT_PART_TYPE_UBI)
+		parts[1].name = UBI_PART_NAME;
+	else
+		parts[1].name = ROOTFS_PART_NAME;
+	parts[1].offset = rootfs_offset;
+	parts[1].size = mtd->size - rootfs_offset;
+
+	*pparts = parts;
+	return ELF_NR_PARTS;
+}
+
+static const struct of_device_id mtdsplit_elf_of_match_table[] = {
+	{ .compatible = "openwrt,elf" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mtdsplit_elf_of_match_table);
+
+static struct mtd_part_parser mtdsplit_elf_parser = {
+	.owner = THIS_MODULE,
+	.name = "elf-loader-fw",
+	.of_match_table = mtdsplit_elf_of_match_table,
+	.parse_fn = mtdsplit_parse_elf,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+static int __init mtdsplit_elf_init(void)
+{
+	register_mtd_parser(&mtdsplit_elf_parser);
+
+	return 0;
+}
+
+subsys_initcall(mtdsplit_elf_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_eva.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_eva.c
new file mode 100644
index 0000000..55004a6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_eva.c
@@ -0,0 +1,103 @@
+/*
+ *  Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ *  Copyright (C) 2015 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/byteorder/generic.h>
+#include <linux/of.h>
+
+#include "mtdsplit.h"
+
+#define EVA_NR_PARTS		2
+#define EVA_MAGIC		0xfeed1281
+#define EVA_FOOTER_SIZE		0x18
+#define EVA_DUMMY_SQUASHFS_SIZE	0x100
+
+struct eva_image_header {
+	uint32_t	magic;
+	uint32_t	size;
+};
+
+static int mtdsplit_parse_eva(struct mtd_info *master,
+				const struct mtd_partition **pparts,
+				struct mtd_part_parser_data *data)
+{
+	struct mtd_partition *parts;
+	struct eva_image_header hdr;
+	size_t retlen;
+	unsigned long kernel_size, rootfs_offset;
+	int err;
+
+	err = mtd_read(master, 0, sizeof(hdr), &retlen, (void *) &hdr);
+	if (err)
+		return err;
+
+	if (retlen != sizeof(hdr))
+		return -EIO;
+
+	if (le32_to_cpu(hdr.magic) != EVA_MAGIC)
+		return -EINVAL;
+
+	kernel_size = le32_to_cpu(hdr.size) + EVA_FOOTER_SIZE;
+
+	/* rootfs starts at the next 0x10000 boundary: */
+	rootfs_offset = round_up(kernel_size, 0x10000);
+
+	/* skip the dummy EVA squashfs partition (with wrong endianness): */
+	rootfs_offset += EVA_DUMMY_SQUASHFS_SIZE;
+
+	if (rootfs_offset >= master->size)
+		return -EINVAL;
+
+	err = mtd_check_rootfs_magic(master, rootfs_offset, NULL);
+	if (err)
+		return err;
+
+	parts = kzalloc(EVA_NR_PARTS * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	parts[0].name = KERNEL_PART_NAME;
+	parts[0].offset = 0;
+	parts[0].size = kernel_size;
+
+	parts[1].name = ROOTFS_PART_NAME;
+	parts[1].offset = rootfs_offset;
+	parts[1].size = master->size - rootfs_offset;
+
+	*pparts = parts;
+	return EVA_NR_PARTS;
+}
+
+static const struct of_device_id mtdsplit_eva_of_match_table[] = {
+	{ .compatible = "avm,eva-firmware" },
+	{},
+};
+
+static struct mtd_part_parser mtdsplit_eva_parser = {
+	.owner = THIS_MODULE,
+	.name = "eva-fw",
+	.of_match_table = mtdsplit_eva_of_match_table,
+	.parse_fn = mtdsplit_parse_eva,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+static int __init mtdsplit_eva_init(void)
+{
+	register_mtd_parser(&mtdsplit_eva_parser);
+
+	return 0;
+}
+
+subsys_initcall(mtdsplit_eva_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c
new file mode 100644
index 0000000..67ee33d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2015 The Linux Foundation
+ * Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/types.h>
+#include <linux/byteorder/generic.h>
+#include <linux/slab.h>
+#include <linux/of_fdt.h>
+
+#include "mtdsplit.h"
+
+struct fdt_header {
+	uint32_t magic;			 /* magic word FDT_MAGIC */
+	uint32_t totalsize;		 /* total size of DT block */
+	uint32_t off_dt_struct;		 /* offset to structure */
+	uint32_t off_dt_strings;	 /* offset to strings */
+	uint32_t off_mem_rsvmap;	 /* offset to memory reserve map */
+	uint32_t version;		 /* format version */
+	uint32_t last_comp_version;	 /* last compatible version */
+
+	/* version 2 fields below */
+	uint32_t boot_cpuid_phys;	 /* Which physical CPU id we're
+					    booting on */
+	/* version 3 fields below */
+	uint32_t size_dt_strings;	 /* size of the strings block */
+
+	/* version 17 fields below */
+	uint32_t size_dt_struct;	 /* size of the structure block */
+};
+
+static int
+mtdsplit_fit_parse(struct mtd_info *mtd,
+		   const struct mtd_partition **pparts,
+	           struct mtd_part_parser_data *data)
+{
+	struct fdt_header hdr;
+	size_t hdr_len, retlen;
+	size_t offset;
+	size_t fit_offset, fit_size;
+	size_t rootfs_offset, rootfs_size;
+	struct mtd_partition *parts;
+	int ret;
+
+	hdr_len = sizeof(struct fdt_header);
+
+	/* Parse the MTD device & search for the FIT image location */
+	for(offset = 0; offset + hdr_len <= mtd->size; offset += mtd->erasesize) {
+		ret = mtd_read(mtd, offset, hdr_len, &retlen, (void*) &hdr);
+		if (ret) {
+			pr_err("read error in \"%s\" at offset 0x%llx\n",
+			       mtd->name, (unsigned long long) offset);
+			return ret;
+		}
+
+		if (retlen != hdr_len) {
+			pr_err("short read in \"%s\"\n", mtd->name);
+			return -EIO;
+		}
+
+		/* Check the magic - see if this is a FIT image */
+		if (be32_to_cpu(hdr.magic) != OF_DT_HEADER) {
+			pr_debug("no valid FIT image found in \"%s\" at offset %llx\n",
+				 mtd->name, (unsigned long long) offset);
+			continue;
+		}
+
+		/* We found a FIT image. Let's keep going */
+		break;
+	}
+
+	fit_offset = offset;
+	fit_size = be32_to_cpu(hdr.totalsize);
+
+	if (fit_size == 0) {
+		pr_err("FIT image in \"%s\" at offset %llx has null size\n",
+		       mtd->name, (unsigned long long) fit_offset);
+		return -ENODEV;
+	}
+
+	/* Search for the rootfs partition after the FIT image */
+	ret = mtd_find_rootfs_from(mtd, fit_offset + fit_size, mtd->size,
+				   &rootfs_offset, NULL);
+	if (ret) {
+		pr_info("no rootfs found after FIT image in \"%s\"\n",
+			mtd->name);
+		return ret;
+	}
+
+	rootfs_size = mtd->size - rootfs_offset;
+
+	parts = kzalloc(2 * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	parts[0].name = KERNEL_PART_NAME;
+	parts[0].offset = fit_offset;
+	parts[0].size = mtd_rounddown_to_eb(fit_size, mtd) + mtd->erasesize;
+
+	parts[1].name = ROOTFS_PART_NAME;
+	parts[1].offset = rootfs_offset;
+	parts[1].size = rootfs_size;
+
+	*pparts = parts;
+	return 2;
+}
+
+static const struct of_device_id mtdsplit_fit_of_match_table[] = {
+	{ .compatible = "denx,fit" },
+	{},
+};
+
+static struct mtd_part_parser uimage_parser = {
+	.owner = THIS_MODULE,
+	.name = "fit-fw",
+	.of_match_table = mtdsplit_fit_of_match_table,
+	.parse_fn = mtdsplit_fit_parse,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+/**************************************************
+ * Init
+ **************************************************/
+
+static int __init mtdsplit_fit_init(void)
+{
+	register_mtd_parser(&uimage_parser);
+
+	return 0;
+}
+
+module_init(mtdsplit_fit_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_jimage.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_jimage.c
new file mode 100644
index 0000000..1770dd4
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_jimage.c
@@ -0,0 +1,284 @@
+/*
+ *  Copyright (C) 2018 Paweł Dembicki <paweldembicki@gmail.com> 
+ *
+ *  Based on: mtdsplit_uimage.c
+ *  Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/byteorder/generic.h>
+#include <linux/of.h>
+
+#include "mtdsplit.h"
+
+#define MAX_HEADER_LEN ( STAG_SIZE + SCH2_SIZE )
+
+#define STAG_SIZE 16
+#define STAG_ID 0x04
+#define STAG_MAGIC 0x2B24
+
+#define SCH2_SIZE 40
+#define SCH2_MAGIC 0x2124
+#define SCH2_VER 0x02
+
+/*
+ * Jboot image header,
+ * all data in little endian.
+ */
+
+struct jimage_header		//stag + sch2 jboot joined headers
+{
+	uint8_t stag_cmark;		// in factory 0xFF , in sysupgrade must be the same as stag_id
+	uint8_t stag_id;		// 0x04
+	uint16_t stag_magic;		//magic 0x2B24
+	uint32_t stag_time_stamp;	// timestamp calculated in jboot way
+	uint32_t stag_image_length;	// lentgh of kernel + sch2 header
+	uint16_t stag_image_checksum;	// negated jboot_checksum of sch2 + kernel
+	uint16_t stag_tag_checksum;	// negated jboot_checksum of stag header data
+	uint16_t sch2_magic;		// magic 0x2124
+	uint8_t sch2_cp_type;	// 0x00 for flat, 0x01 for jz, 0x02 for gzip, 0x03 for lzma
+	uint8_t sch2_version;	// 0x02 for sch2
+	uint32_t sch2_ram_addr;	// ram entry address
+	uint32_t sch2_image_len;	// kernel image length
+	uint32_t sch2_image_crc32;	// kernel image crc
+	uint32_t sch2_start_addr;	// ram start address
+	uint32_t sch2_rootfs_addr;	// rootfs flash address
+	uint32_t sch2_rootfs_len;	// rootfls length
+	uint32_t sch2_rootfs_crc32;	// rootfs crc32
+	uint32_t sch2_header_crc32;	// sch2 header crc32, durring calculation this area is replaced by zero
+	uint16_t sch2_header_length;	// sch2 header length: 0x28
+	uint16_t sch2_cmd_line_length;	// cmd line length, known zeros
+};
+
+static int
+read_jimage_header(struct mtd_info *mtd, size_t offset, u_char *buf,
+		   size_t header_len)
+{
+	size_t retlen;
+	int ret;
+
+	ret = mtd_read(mtd, offset, header_len, &retlen, buf);
+	if (ret) {
+		pr_debug("read error in \"%s\"\n", mtd->name);
+		return ret;
+	}
+
+	if (retlen != header_len) {
+		pr_debug("short read in \"%s\"\n", mtd->name);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/**
+ * __mtdsplit_parse_jimage - scan partition and create kernel + rootfs parts
+ *
+ * @find_header: function to call for a block of data that will return offset
+ *      of a valid jImage header if found
+ */
+static int __mtdsplit_parse_jimage(struct mtd_info *master,
+				   const struct mtd_partition **pparts,
+				   struct mtd_part_parser_data *data,
+				   ssize_t (*find_header)(u_char *buf, size_t len))
+{
+	struct mtd_partition *parts;
+	u_char *buf;
+	int nr_parts;
+	size_t offset;
+	size_t jimage_offset;
+	size_t jimage_size = 0;
+	size_t rootfs_offset;
+	size_t rootfs_size = 0;
+	int jimage_part, rf_part;
+	int ret;
+	enum mtdsplit_part_type type;
+
+	nr_parts = 2;
+	parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	buf = vmalloc(MAX_HEADER_LEN);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto err_free_parts;
+	}
+
+	/* find jImage on erase block boundaries */
+	for (offset = 0; offset < master->size; offset += master->erasesize) {
+		struct jimage_header *header;
+
+		jimage_size = 0;
+
+		ret = read_jimage_header(master, offset, buf, MAX_HEADER_LEN);
+		if (ret)
+			continue;
+
+		ret = find_header(buf, MAX_HEADER_LEN);
+		if (ret < 0) {
+			pr_debug("no valid jImage found in \"%s\" at offset %llx\n",
+				 master->name, (unsigned long long) offset);
+			continue;
+		}
+		header = (struct jimage_header *)(buf + ret);
+
+		jimage_size = sizeof(*header) + header->sch2_image_len + ret;
+		if ((offset + jimage_size) > master->size) {
+			pr_debug("jImage exceeds MTD device \"%s\"\n",
+				 master->name);
+			continue;
+		}
+		break;
+	}
+
+	if (jimage_size == 0) {
+		pr_debug("no jImage found in \"%s\"\n", master->name);
+		ret = -ENODEV;
+		goto err_free_buf;
+	}
+
+	jimage_offset = offset;
+
+	if (jimage_offset == 0) {
+		jimage_part = 0;
+		rf_part = 1;
+
+		/* find the roots after the jImage */
+		ret = mtd_find_rootfs_from(master, jimage_offset + jimage_size,
+					   master->size, &rootfs_offset, &type);
+		if (ret) {
+			pr_debug("no rootfs after jImage in \"%s\"\n",
+				 master->name);
+			goto err_free_buf;
+		}
+
+		rootfs_size = master->size - rootfs_offset;
+		jimage_size = rootfs_offset - jimage_offset;
+	} else {
+		rf_part = 0;
+		jimage_part = 1;
+
+		/* check rootfs presence at offset 0 */
+		ret = mtd_check_rootfs_magic(master, 0, &type);
+		if (ret) {
+			pr_debug("no rootfs before jImage in \"%s\"\n",
+				 master->name);
+			goto err_free_buf;
+		}
+
+		rootfs_offset = 0;
+		rootfs_size = jimage_offset;
+	}
+
+	if (rootfs_size == 0) {
+		pr_debug("no rootfs found in \"%s\"\n", master->name);
+		ret = -ENODEV;
+		goto err_free_buf;
+	}
+
+	parts[jimage_part].name = KERNEL_PART_NAME;
+	parts[jimage_part].offset = jimage_offset;
+	parts[jimage_part].size = jimage_size;
+
+	if (type == MTDSPLIT_PART_TYPE_UBI)
+		parts[rf_part].name = UBI_PART_NAME;
+	else
+		parts[rf_part].name = ROOTFS_PART_NAME;
+	parts[rf_part].offset = rootfs_offset;
+	parts[rf_part].size = rootfs_size;
+
+	vfree(buf);
+
+	*pparts = parts;
+	return nr_parts;
+
+err_free_buf:
+	vfree(buf);
+
+err_free_parts:
+	kfree(parts);
+	return ret;
+}
+
+static ssize_t jimage_verify_default(u_char *buf, size_t len)
+{
+	struct jimage_header *header = (struct jimage_header *)buf;
+
+	/* default sanity checks */
+	if (header->stag_magic != STAG_MAGIC) {
+		pr_debug("invalid jImage stag header magic: %04x\n",
+			 header->stag_magic);
+		return -EINVAL;
+	}
+	if (header->sch2_magic != SCH2_MAGIC) {
+		pr_debug("invalid jImage sch2 header magic: %04x\n",
+			 header->stag_magic);
+		return -EINVAL;
+	}
+	if (header->stag_cmark != header->stag_id) {
+		pr_debug("invalid jImage stag header cmark: %02x\n",
+			 header->stag_magic);
+		return -EINVAL;
+	}
+	if (header->stag_id != STAG_ID) {
+		pr_debug("invalid jImage stag header id: %02x\n",
+			 header->stag_magic);
+		return -EINVAL;
+	}
+	if (header->sch2_version != SCH2_VER) {
+		pr_debug("invalid jImage sch2 header version: %02x\n",
+			 header->stag_magic);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+mtdsplit_jimage_parse_generic(struct mtd_info *master,
+			      const struct mtd_partition **pparts,
+			      struct mtd_part_parser_data *data)
+{
+	return __mtdsplit_parse_jimage(master, pparts, data,
+				      jimage_verify_default);
+}
+
+static const struct of_device_id mtdsplit_jimage_of_match_table[] = {
+	{ .compatible = "amit,jimage" },
+	{},
+};
+
+static struct mtd_part_parser jimage_generic_parser = {
+	.owner = THIS_MODULE,
+	.name = "jimage-fw",
+	.of_match_table = mtdsplit_jimage_of_match_table,
+	.parse_fn = mtdsplit_jimage_parse_generic,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+/**************************************************
+ * Init
+ **************************************************/
+
+static int __init mtdsplit_jimage_init(void)
+{
+	register_mtd_parser(&jimage_generic_parser);
+
+	return 0;
+}
+
+module_init(mtdsplit_jimage_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_lzma.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_lzma.c
new file mode 100644
index 0000000..c58f7ae
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_lzma.c
@@ -0,0 +1,104 @@
+/*
+ *  Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+
+#include <asm/unaligned.h>
+
+#include "mtdsplit.h"
+
+#define LZMA_NR_PARTS		2
+#define LZMA_PROPERTIES_SIZE	5
+
+struct lzma_header {
+	u8 props[LZMA_PROPERTIES_SIZE];
+	u8 size_low[4];
+	u8 size_high[4];
+};
+
+static int mtdsplit_parse_lzma(struct mtd_info *master,
+			       const struct mtd_partition **pparts,
+			       struct mtd_part_parser_data *data)
+{
+	struct lzma_header hdr;
+	size_t hdr_len, retlen;
+	size_t rootfs_offset;
+	u32 t;
+	struct mtd_partition *parts;
+	int err;
+
+	hdr_len = sizeof(hdr);
+	err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr);
+	if (err)
+		return err;
+
+	if (retlen != hdr_len)
+		return -EIO;
+
+	/* verify LZMA properties */
+	if (hdr.props[0] >= (9 * 5 * 5))
+		return -EINVAL;
+
+	t = get_unaligned_le32(&hdr.props[1]);
+	if (!is_power_of_2(t))
+		return -EINVAL;
+
+	t = get_unaligned_le32(&hdr.size_high);
+	if (t)
+		return -EINVAL;
+
+	err = mtd_find_rootfs_from(master, master->erasesize, master->size,
+				   &rootfs_offset, NULL);
+	if (err)
+		return err;
+
+	parts = kzalloc(LZMA_NR_PARTS * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	parts[0].name = KERNEL_PART_NAME;
+	parts[0].offset = 0;
+	parts[0].size = rootfs_offset;
+
+	parts[1].name = ROOTFS_PART_NAME;
+	parts[1].offset = rootfs_offset;
+	parts[1].size = master->size - rootfs_offset;
+
+	*pparts = parts;
+	return LZMA_NR_PARTS;
+}
+
+static const struct of_device_id mtdsplit_lzma_of_match_table[] = {
+	{ .compatible = "lzma" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mtdsplit_lzma_of_match_table);
+
+static struct mtd_part_parser mtdsplit_lzma_parser = {
+	.owner = THIS_MODULE,
+	.name = "lzma-fw",
+	.of_match_table = mtdsplit_lzma_of_match_table,
+	.parse_fn = mtdsplit_parse_lzma,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+static int __init mtdsplit_lzma_init(void)
+{
+	register_mtd_parser(&mtdsplit_lzma_parser);
+
+	return 0;
+}
+
+subsys_initcall(mtdsplit_lzma_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_minor.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_minor.c
new file mode 100644
index 0000000..af6822e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_minor.c
@@ -0,0 +1,125 @@
+/*
+ *  MTD splitter for MikroTik NOR devices
+ *
+ *  Copyright (C) 2017 Thibaut VARENE <varenet@parisc-linux.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ *  The rootfs is expected at erase-block boundary due to the use of
+ *  mtd_find_rootfs_from(). We use a trimmed down version of the yaffs header
+ *  for two main reasons:
+ *  - the original header uses weakly defined types (int, enum...) which can
+ *    vary in length depending on build host (and the struct is not packed),
+ *    and the name field can have a different total length depending on
+ *    whether or not the yaffs code was _built_ with unicode support.
+ *  - the only field that could be of real use here (file_size_low) contains
+ *    invalid data in the header generated by kernel2minor, so we cannot use
+ *    it to infer the exact position of the rootfs and do away with
+ *    mtd_find_rootfs_from() (and thus have non-EB-aligned rootfs).
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/string.h>
+#include <linux/of.h>
+
+#include "mtdsplit.h"
+
+#define YAFFS_OBJECT_TYPE_FILE	0x1
+#define YAFFS_OBJECTID_ROOT	0x1
+#define YAFFS_SUM_UNUSED	0xFFFF
+#define YAFFS_NAME		"kernel"
+
+#define MINOR_NR_PARTS		2
+
+/*
+ * This structure is based on yaffs_obj_hdr from yaffs_guts.h
+ * The weak types match upstream. The fields have cpu-endianness
+ */
+struct minor_header {
+	int yaffs_type;
+	int yaffs_obj_id;
+	u16 yaffs_sum_unused;
+	char yaffs_name[sizeof(YAFFS_NAME)];
+};
+
+static int mtdsplit_parse_minor(struct mtd_info *master,
+				const struct mtd_partition **pparts,
+				struct mtd_part_parser_data *data)
+{
+	struct minor_header hdr;
+	size_t hdr_len, retlen;
+	size_t rootfs_offset;
+	struct mtd_partition *parts;
+	int err;
+
+	hdr_len = sizeof(hdr);
+	err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr);
+	if (err)
+		return err;
+
+	if (retlen != hdr_len)
+		return -EIO;
+
+	/* match header */
+	if (hdr.yaffs_type != YAFFS_OBJECT_TYPE_FILE)
+		return -EINVAL;
+
+	if (hdr.yaffs_obj_id != YAFFS_OBJECTID_ROOT)
+		return -EINVAL;
+
+	if (hdr.yaffs_sum_unused != YAFFS_SUM_UNUSED)
+		return -EINVAL;
+
+	if (memcmp(hdr.yaffs_name, YAFFS_NAME, sizeof(YAFFS_NAME)))
+		return -EINVAL;
+
+	err = mtd_find_rootfs_from(master, master->erasesize, master->size,
+				   &rootfs_offset, NULL);
+	if (err)
+		return err;
+
+	parts = kzalloc(MINOR_NR_PARTS * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	parts[0].name = KERNEL_PART_NAME;
+	parts[0].offset = 0;
+	parts[0].size = rootfs_offset;
+
+	parts[1].name = ROOTFS_PART_NAME;
+	parts[1].offset = rootfs_offset;
+	parts[1].size = master->size - rootfs_offset;
+
+	*pparts = parts;
+	return MINOR_NR_PARTS;
+}
+
+static const struct of_device_id mtdsplit_minor_of_match_table[] = {
+	{ .compatible = "mikrotik,minor" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mtdsplit_minor_of_match_table);
+
+static struct mtd_part_parser mtdsplit_minor_parser = {
+	.owner = THIS_MODULE,
+	.name = "minor-fw",
+	.of_match_table = mtdsplit_minor_of_match_table,
+	.parse_fn = mtdsplit_parse_minor,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+static int __init mtdsplit_minor_init(void)
+{
+	register_mtd_parser(&mtdsplit_minor_parser);
+
+	return 0;
+}
+
+subsys_initcall(mtdsplit_minor_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_seama.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_seama.c
new file mode 100644
index 0000000..5d49171
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_seama.c
@@ -0,0 +1,118 @@
+/*
+ *  Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/byteorder/generic.h>
+#include <linux/of.h>
+
+#include "mtdsplit.h"
+
+#define SEAMA_MAGIC		0x5EA3A417
+#define SEAMA_NR_PARTS		2
+#define SEAMA_MIN_ROOTFS_OFFS	0x80000	/* 512KiB */
+
+struct seama_header {
+	__be32	magic;		/* should always be SEAMA_MAGIC. */
+	__be16	reserved;	/* reserved for  */
+	__be16	metasize;	/* size of the META data */
+	__be32	size;		/* size of the image */
+	u8	md5[16];	/* digest */
+};
+
+static int mtdsplit_parse_seama(struct mtd_info *master,
+				const struct mtd_partition **pparts,
+				struct mtd_part_parser_data *data)
+{
+	struct seama_header hdr;
+	size_t hdr_len, retlen, kernel_ent_size;
+	size_t rootfs_offset;
+	struct mtd_partition *parts;
+	enum mtdsplit_part_type type;
+	int err;
+
+	hdr_len = sizeof(hdr);
+	err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr);
+	if (err)
+		return err;
+
+	if (retlen != hdr_len)
+		return -EIO;
+
+	/* sanity checks */
+	if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC)
+		return -EINVAL;
+
+	kernel_ent_size = hdr_len + be32_to_cpu(hdr.size) +
+			  be16_to_cpu(hdr.metasize);
+	if (kernel_ent_size > master->size)
+		return -EINVAL;
+
+	/* Check for the rootfs right after Seama entity with a kernel. */
+	err = mtd_check_rootfs_magic(master, kernel_ent_size, &type);
+	if (!err) {
+		rootfs_offset = kernel_ent_size;
+	} else {
+		/*
+		 * On some devices firmware entity might contain both: kernel
+		 * and rootfs. We can't determine kernel size so we just have to
+		 * look for rootfs magic.
+		 * Start the search from an arbitrary offset.
+		 */
+		err = mtd_find_rootfs_from(master, SEAMA_MIN_ROOTFS_OFFS,
+					   master->size, &rootfs_offset, &type);
+		if (err)
+			return err;
+	}
+
+	parts = kzalloc(SEAMA_NR_PARTS * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	parts[0].name = KERNEL_PART_NAME;
+	parts[0].offset = sizeof hdr + be16_to_cpu(hdr.metasize);
+	parts[0].size = rootfs_offset - parts[0].offset;
+
+	if (type == MTDSPLIT_PART_TYPE_UBI)
+		parts[1].name = UBI_PART_NAME;
+	else
+		parts[1].name = ROOTFS_PART_NAME;
+	parts[1].offset = rootfs_offset;
+	parts[1].size = master->size - rootfs_offset;
+
+	*pparts = parts;
+	return SEAMA_NR_PARTS;
+}
+
+static const struct of_device_id mtdsplit_seama_of_match_table[] = {
+	{ .compatible = "seama" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mtdsplit_seama_of_match_table);
+
+static struct mtd_part_parser mtdsplit_seama_parser = {
+	.owner = THIS_MODULE,
+	.name = "seama-fw",
+	.of_match_table = mtdsplit_seama_of_match_table,
+	.parse_fn = mtdsplit_parse_seama,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+static int __init mtdsplit_seama_init(void)
+{
+	register_mtd_parser(&mtdsplit_seama_parser);
+
+	return 0;
+}
+
+subsys_initcall(mtdsplit_seama_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_squashfs.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_squashfs.c
new file mode 100644
index 0000000..f6353da
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_squashfs.c
@@ -0,0 +1,72 @@
+/*
+ *  Copyright (C) 2013 Felix Fietkau <nbd@nbd.name>
+ *  Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/magic.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/byteorder/generic.h>
+
+#include "mtdsplit.h"
+
+static int
+mtdsplit_parse_squashfs(struct mtd_info *master,
+			const struct mtd_partition **pparts,
+			struct mtd_part_parser_data *data)
+{
+	struct mtd_partition *part;
+	struct mtd_info *parent_mtd;
+	size_t part_offset;
+	size_t squashfs_len;
+	int err;
+
+	err = mtd_get_squashfs_len(master, 0, &squashfs_len);
+	if (err)
+		return err;
+
+	parent_mtd = mtd_get_master(master);
+	part_offset = mtdpart_get_offset(master);
+
+	part = kzalloc(sizeof(*part), GFP_KERNEL);
+	if (!part) {
+		pr_alert("unable to allocate memory for \"%s\" partition\n",
+			 ROOTFS_SPLIT_NAME);
+		return -ENOMEM;
+	}
+
+	part->name = ROOTFS_SPLIT_NAME;
+	part->offset = mtd_roundup_to_eb(part_offset + squashfs_len,
+					 parent_mtd) - part_offset;
+	part->size = mtd_rounddown_to_eb(master->size - part->offset, master);
+
+	*pparts = part;
+	return 1;
+}
+
+static struct mtd_part_parser mtdsplit_squashfs_parser = {
+	.owner = THIS_MODULE,
+	.name = "squashfs-split",
+	.parse_fn = mtdsplit_parse_squashfs,
+	.type = MTD_PARSER_TYPE_ROOTFS,
+};
+
+static int __init mtdsplit_squashfs_init(void)
+{
+	register_mtd_parser(&mtdsplit_squashfs_parser);
+
+	return 0;
+}
+
+subsys_initcall(mtdsplit_squashfs_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_tplink.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_tplink.c
new file mode 100644
index 0000000..8909c10
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_tplink.c
@@ -0,0 +1,176 @@
+/*
+ *  Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2014 Felix Fietkau <nbd@nbd.name>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/byteorder/generic.h>
+#include <linux/of.h>
+
+#include "mtdsplit.h"
+
+#define TPLINK_NR_PARTS		2
+#define TPLINK_MIN_ROOTFS_OFFS	0x80000	/* 512KiB */
+
+#define MD5SUM_LEN  16
+
+struct fw_v1 {
+	char		vendor_name[24];
+	char		fw_version[36];
+	uint32_t	hw_id;		/* hardware id */
+	uint32_t	hw_rev;		/* hardware revision */
+	uint32_t	unk1;
+	uint8_t		md5sum1[MD5SUM_LEN];
+	uint32_t	unk2;
+	uint8_t		md5sum2[MD5SUM_LEN];
+	uint32_t	unk3;
+	uint32_t	kernel_la;	/* kernel load address */
+	uint32_t	kernel_ep;	/* kernel entry point */
+	uint32_t	fw_length;	/* total length of the firmware */
+	uint32_t	kernel_ofs;	/* kernel data offset */
+	uint32_t	kernel_len;	/* kernel data length */
+	uint32_t	rootfs_ofs;	/* rootfs data offset */
+	uint32_t	rootfs_len;	/* rootfs data length */
+	uint32_t	boot_ofs;	/* bootloader data offset */
+	uint32_t	boot_len;	/* bootloader data length */
+	uint8_t		pad[360];
+} __attribute__ ((packed));
+
+struct fw_v2 {
+	char		fw_version[48]; /* 0x04: fw version string */
+	uint32_t	hw_id;		/* 0x34: hardware id */
+	uint32_t	hw_rev;		/* 0x38: FIXME: hardware revision? */
+	uint32_t	unk1;	        /* 0x3c: 0x00000000 */
+	uint8_t		md5sum1[MD5SUM_LEN]; /* 0x40 */
+	uint32_t	unk2;		/* 0x50: 0x00000000 */
+	uint8_t		md5sum2[MD5SUM_LEN]; /* 0x54 */
+	uint32_t	unk3;		/* 0x64: 0xffffffff */
+
+	uint32_t	kernel_la;	/* 0x68: kernel load address */
+	uint32_t	kernel_ep;	/* 0x6c: kernel entry point */
+	uint32_t	fw_length;	/* 0x70: total length of the image */
+	uint32_t	kernel_ofs;	/* 0x74: kernel data offset */
+	uint32_t	kernel_len;	/* 0x78: kernel data length */
+	uint32_t	rootfs_ofs;	/* 0x7c: rootfs data offset */
+	uint32_t	rootfs_len;	/* 0x80: rootfs data length */
+	uint32_t	boot_ofs;	/* 0x84: FIXME: seems to be unused */
+	uint32_t	boot_len;	/* 0x88: FIXME: seems to be unused */
+	uint16_t	unk4;		/* 0x8c: 0x55aa */
+	uint8_t		sver_hi;	/* 0x8e */
+	uint8_t		sver_lo;	/* 0x8f */
+	uint8_t		unk5;		/* 0x90: magic: 0xa5 */
+	uint8_t		ver_hi;         /* 0x91 */
+	uint8_t		ver_mid;        /* 0x92 */
+	uint8_t		ver_lo;         /* 0x93 */
+	uint8_t		pad[364];
+} __attribute__ ((packed));
+
+struct tplink_fw_header {
+	uint32_t version;
+	union {
+		struct fw_v1 v1;
+		struct fw_v2 v2;
+	};
+};
+
+static int mtdsplit_parse_tplink(struct mtd_info *master,
+				 const struct mtd_partition **pparts,
+				 struct mtd_part_parser_data *data)
+{
+	struct tplink_fw_header hdr;
+	size_t hdr_len, retlen, kernel_size;
+	size_t rootfs_offset;
+	struct mtd_partition *parts;
+	int err;
+
+	hdr_len = sizeof(hdr);
+	err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr);
+	if (err)
+		return err;
+
+	if (retlen != hdr_len)
+		return -EIO;
+
+	switch (le32_to_cpu(hdr.version)) {
+	case 1:
+		if (be32_to_cpu(hdr.v1.kernel_ofs) != sizeof(hdr))
+			return -EINVAL;
+
+		kernel_size = sizeof(hdr) + be32_to_cpu(hdr.v1.kernel_len);
+		rootfs_offset = be32_to_cpu(hdr.v1.rootfs_ofs);
+		break;
+	case 2:
+	case 3:
+		if (be32_to_cpu(hdr.v2.kernel_ofs) != sizeof(hdr))
+			return -EINVAL;
+
+		kernel_size = sizeof(hdr) + be32_to_cpu(hdr.v2.kernel_len);
+		rootfs_offset = be32_to_cpu(hdr.v2.rootfs_ofs);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (kernel_size > master->size)
+		return -EINVAL;
+
+	/* Find the rootfs */
+	err = mtd_check_rootfs_magic(master, rootfs_offset, NULL);
+	if (err) {
+		/*
+		 * The size in the header might cover the rootfs as well.
+		 * Start the search from an arbitrary offset.
+		 */
+		err = mtd_find_rootfs_from(master, TPLINK_MIN_ROOTFS_OFFS,
+					   master->size, &rootfs_offset, NULL);
+		if (err)
+			return err;
+	}
+
+	parts = kzalloc(TPLINK_NR_PARTS * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	parts[0].name = KERNEL_PART_NAME;
+	parts[0].offset = 0;
+	parts[0].size = kernel_size;
+
+	parts[1].name = ROOTFS_PART_NAME;
+	parts[1].offset = rootfs_offset;
+	parts[1].size = master->size - rootfs_offset;
+
+	*pparts = parts;
+	return TPLINK_NR_PARTS;
+}
+
+static const struct of_device_id mtdsplit_tplink_of_match_table[] = {
+	{ .compatible = "tplink,firmware" },
+	{},
+};
+
+static struct mtd_part_parser mtdsplit_tplink_parser = {
+	.owner = THIS_MODULE,
+	.name = "tplink-fw",
+	.of_match_table = mtdsplit_tplink_of_match_table,
+	.parse_fn = mtdsplit_parse_tplink,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+static int __init mtdsplit_tplink_init(void)
+{
+	register_mtd_parser(&mtdsplit_tplink_parser);
+
+	return 0;
+}
+
+subsys_initcall(mtdsplit_tplink_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_trx.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_trx.c
new file mode 100644
index 0000000..b853ec9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_trx.c
@@ -0,0 +1,155 @@
+/*
+ *  Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2014 Felix Fietkau <nbd@nbd.name>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/byteorder/generic.h>
+#include <linux/of.h>
+
+#include "mtdsplit.h"
+
+#define TRX_MAGIC   0x30524448  /* "HDR0" */
+
+struct trx_header {
+	__le32 magic;
+	__le32 len;
+	__le32 crc32;
+	__le32 flag_version;
+	__le32 offset[4];
+};
+
+static int
+read_trx_header(struct mtd_info *mtd, size_t offset,
+		   struct trx_header *header)
+{
+	size_t header_len;
+	size_t retlen;
+	int ret;
+
+	header_len = sizeof(*header);
+	ret = mtd_read(mtd, offset, header_len, &retlen,
+		       (unsigned char *) header);
+	if (ret) {
+		pr_debug("read error in \"%s\"\n", mtd->name);
+		return ret;
+	}
+
+	if (retlen != header_len) {
+		pr_debug("short read in \"%s\"\n", mtd->name);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int
+mtdsplit_parse_trx(struct mtd_info *master,
+		   const struct mtd_partition **pparts,
+		   struct mtd_part_parser_data *data)
+{
+	struct mtd_partition *parts;
+	struct trx_header hdr;
+	int nr_parts;
+	size_t offset;
+	size_t trx_offset;
+	size_t trx_size = 0;
+	size_t rootfs_offset;
+	size_t rootfs_size = 0;
+	int ret;
+
+	nr_parts = 2;
+	parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	/* find trx image on erase block boundaries */
+	for (offset = 0; offset < master->size; offset += master->erasesize) {
+		trx_size = 0;
+
+		ret = read_trx_header(master, offset, &hdr);
+		if (ret)
+			continue;
+
+		if (hdr.magic != cpu_to_le32(TRX_MAGIC)) {
+			pr_debug("no valid trx header found in \"%s\" at offset %llx\n",
+				 master->name, (unsigned long long) offset);
+			continue;
+		}
+
+		trx_size = le32_to_cpu(hdr.len);
+		if ((offset + trx_size) > master->size) {
+			pr_debug("trx image exceeds MTD device \"%s\"\n",
+				 master->name);
+			continue;
+		}
+		break;
+	}
+
+	if (trx_size == 0) {
+		pr_debug("no trx header found in \"%s\"\n", master->name);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	trx_offset = offset + hdr.offset[0];
+	rootfs_offset = offset + hdr.offset[1];
+	rootfs_size = master->size - rootfs_offset;
+	trx_size = rootfs_offset - trx_offset;
+
+	if (rootfs_size == 0) {
+		pr_debug("no rootfs found in \"%s\"\n", master->name);
+		ret = -ENODEV;
+		goto err;
+	}
+
+	parts[0].name = KERNEL_PART_NAME;
+	parts[0].offset = trx_offset;
+	parts[0].size = trx_size;
+
+	parts[1].name = ROOTFS_PART_NAME;
+	parts[1].offset = rootfs_offset;
+	parts[1].size = rootfs_size;
+
+	*pparts = parts;
+	return nr_parts;
+
+err:
+	kfree(parts);
+	return ret;
+}
+
+static const struct of_device_id trx_parser_of_match_table[] = {
+	{ .compatible = "openwrt,trx" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, trx_parser_of_match_table);
+
+static struct mtd_part_parser trx_parser = {
+	.owner = THIS_MODULE,
+	.name = "trx-fw",
+	.of_match_table = trx_parser_of_match_table,
+	.parse_fn = mtdsplit_parse_trx,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+static int __init mtdsplit_trx_init(void)
+{
+	register_mtd_parser(&trx_parser);
+
+	return 0;
+}
+
+module_init(mtdsplit_trx_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c
new file mode 100644
index 0000000..a3e55fb
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c
@@ -0,0 +1,282 @@
+/*
+ *  Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/version.h>
+#include <linux/byteorder/generic.h>
+#include <linux/of.h>
+#include <dt-bindings/mtd/partitions/uimage.h>
+
+#include "mtdsplit.h"
+
+/*
+ * Legacy format image header,
+ * all data in network byte order (aka natural aka bigendian).
+ */
+struct uimage_header {
+	uint32_t	ih_magic;	/* Image Header Magic Number	*/
+	uint32_t	ih_hcrc;	/* Image Header CRC Checksum	*/
+	uint32_t	ih_time;	/* Image Creation Timestamp	*/
+	uint32_t	ih_size;	/* Image Data Size		*/
+	uint32_t	ih_load;	/* Data	 Load  Address		*/
+	uint32_t	ih_ep;		/* Entry Point Address		*/
+	uint32_t	ih_dcrc;	/* Image Data CRC Checksum	*/
+	uint8_t		ih_os;		/* Operating System		*/
+	uint8_t		ih_arch;	/* CPU architecture		*/
+	uint8_t		ih_type;	/* Image Type			*/
+	uint8_t		ih_comp;	/* Compression Type		*/
+	uint8_t		ih_name[IH_NMLEN];	/* Image Name		*/
+};
+
+static int
+read_uimage_header(struct mtd_info *mtd, size_t offset, u_char *buf,
+		   size_t header_len)
+{
+	size_t retlen;
+	int ret;
+
+	ret = mtd_read(mtd, offset, header_len, &retlen, buf);
+	if (ret) {
+		pr_debug("read error in \"%s\"\n", mtd->name);
+		return ret;
+	}
+
+	if (retlen != header_len) {
+		pr_debug("short read in \"%s\"\n", mtd->name);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static void uimage_parse_dt(struct mtd_info *master, int *extralen,
+			    u32 *ih_magic, u32 *ih_type,
+			    u32 *header_offset, u32 *part_magic)
+{
+	struct device_node *np = mtd_get_of_node(master);
+
+	if (!np || !of_device_is_compatible(np, "openwrt,uimage"))
+		return;
+
+	if (!of_property_read_u32(np, "openwrt,padding", extralen))
+		pr_debug("got openwrt,padding=%d from device-tree\n", *extralen);
+	if (!of_property_read_u32(np, "openwrt,ih-magic", ih_magic))
+		pr_debug("got openwrt,ih-magic=%08x from device-tree\n", *ih_magic);
+	if (!of_property_read_u32(np, "openwrt,ih-type", ih_type))
+		pr_debug("got openwrt,ih-type=%08x from device-tree\n", *ih_type);
+	if (!of_property_read_u32(np, "openwrt,offset", header_offset))
+		pr_debug("got ih-start=%u from device-tree\n", *header_offset);
+	if (!of_property_read_u32(np, "openwrt,partition-magic", part_magic))
+		pr_debug("got openwrt,partition-magic=%08x from device-tree\n", *part_magic);
+}
+
+static ssize_t uimage_verify_default(u_char *buf, u32 ih_magic, u32 ih_type)
+{
+	struct uimage_header *header = (struct uimage_header *)buf;
+
+	/* default sanity checks */
+	if (be32_to_cpu(header->ih_magic) != ih_magic) {
+		pr_debug("invalid uImage magic: %08x != %08x\n",
+			 be32_to_cpu(header->ih_magic), ih_magic);
+		return -EINVAL;
+	}
+
+	if (header->ih_os != IH_OS_LINUX) {
+		pr_debug("invalid uImage OS: %08x != %08x\n",
+			 be32_to_cpu(header->ih_os), IH_OS_LINUX);
+		return -EINVAL;
+	}
+
+	if (header->ih_type != ih_type) {
+		pr_debug("invalid uImage type: %08x != %08x\n",
+			 be32_to_cpu(header->ih_type), ih_type);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * __mtdsplit_parse_uimage - scan partition and create kernel + rootfs parts
+ *
+ * @find_header: function to call for a block of data that will return offset
+ *      and tail padding length of a valid uImage header if found
+ */
+static int __mtdsplit_parse_uimage(struct mtd_info *master,
+				   const struct mtd_partition **pparts,
+				   struct mtd_part_parser_data *data)
+{
+	struct mtd_partition *parts;
+	u_char *buf;
+	int nr_parts;
+	size_t offset;
+	size_t uimage_offset;
+	size_t uimage_size = 0;
+	size_t rootfs_offset;
+	size_t rootfs_size = 0;
+	size_t buflen;
+	int uimage_part, rf_part;
+	int ret;
+	int extralen = 0;
+	u32 ih_magic = IH_MAGIC;
+	u32 ih_type = IH_TYPE_KERNEL;
+	u32 header_offset = 0;
+	u32 part_magic = 0;
+	enum mtdsplit_part_type type;
+
+	nr_parts = 2;
+	parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	uimage_parse_dt(master, &extralen, &ih_magic, &ih_type, &header_offset, &part_magic);
+	buflen = sizeof(struct uimage_header) + header_offset;
+	buf = vmalloc(buflen);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto err_free_parts;
+	}
+
+	/* find uImage on erase block boundaries */
+	for (offset = 0; offset < master->size; offset += master->erasesize) {
+		struct uimage_header *header;
+
+		uimage_size = 0;
+
+		ret = read_uimage_header(master, offset, buf, buflen);
+		if (ret)
+			continue;
+
+		/* verify optional partition magic before uimage header */
+		if (header_offset && part_magic && (be32_to_cpu(*(u32 *)buf) != part_magic))
+			continue;
+
+		ret = uimage_verify_default(buf + header_offset, ih_magic, ih_type);
+		if (ret < 0) {
+			pr_debug("no valid uImage found in \"%s\" at offset %llx\n",
+				 master->name, (unsigned long long) offset);
+			continue;
+		}
+
+		header = (struct uimage_header *)(buf + header_offset);
+
+		uimage_size = sizeof(*header) +
+				be32_to_cpu(header->ih_size) + header_offset + extralen;
+
+		if ((offset + uimage_size) > master->size) {
+			pr_debug("uImage exceeds MTD device \"%s\"\n",
+				 master->name);
+			continue;
+		}
+		break;
+	}
+
+	if (uimage_size == 0) {
+		pr_debug("no uImage found in \"%s\"\n", master->name);
+		ret = -ENODEV;
+		goto err_free_buf;
+	}
+
+	uimage_offset = offset;
+
+	if (uimage_offset == 0) {
+		uimage_part = 0;
+		rf_part = 1;
+
+		/* find the roots after the uImage */
+		ret = mtd_find_rootfs_from(master, uimage_offset + uimage_size,
+					   master->size, &rootfs_offset, &type);
+		if (ret) {
+			pr_debug("no rootfs after uImage in \"%s\"\n",
+				 master->name);
+			goto err_free_buf;
+		}
+
+		rootfs_size = master->size - rootfs_offset;
+		uimage_size = rootfs_offset - uimage_offset;
+	} else {
+		rf_part = 0;
+		uimage_part = 1;
+
+		/* check rootfs presence at offset 0 */
+		ret = mtd_check_rootfs_magic(master, 0, &type);
+		if (ret) {
+			pr_debug("no rootfs before uImage in \"%s\"\n",
+				 master->name);
+			goto err_free_buf;
+		}
+
+		rootfs_offset = 0;
+		rootfs_size = uimage_offset;
+	}
+
+	if (rootfs_size == 0) {
+		pr_debug("no rootfs found in \"%s\"\n", master->name);
+		ret = -ENODEV;
+		goto err_free_buf;
+	}
+
+	parts[uimage_part].name = KERNEL_PART_NAME;
+	parts[uimage_part].offset = uimage_offset;
+	parts[uimage_part].size = uimage_size;
+
+	if (type == MTDSPLIT_PART_TYPE_UBI)
+		parts[rf_part].name = UBI_PART_NAME;
+	else
+		parts[rf_part].name = ROOTFS_PART_NAME;
+	parts[rf_part].offset = rootfs_offset;
+	parts[rf_part].size = rootfs_size;
+
+	vfree(buf);
+
+	*pparts = parts;
+	return nr_parts;
+
+err_free_buf:
+	vfree(buf);
+
+err_free_parts:
+	kfree(parts);
+	return ret;
+}
+
+static const struct of_device_id mtdsplit_uimage_of_match_table[] = {
+	{ .compatible = "denx,uimage" },
+	{ .compatible = "openwrt,uimage" },
+	{},
+};
+
+static struct mtd_part_parser uimage_generic_parser = {
+	.owner = THIS_MODULE,
+	.name = "uimage-fw",
+	.of_match_table = mtdsplit_uimage_of_match_table,
+	.parse_fn = __mtdsplit_parse_uimage,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+/**************************************************
+ * Init
+ **************************************************/
+
+static int __init mtdsplit_uimage_init(void)
+{
+	register_mtd_parser(&uimage_generic_parser);
+
+	return 0;
+}
+
+module_init(mtdsplit_uimage_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_wrgg.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_wrgg.c
new file mode 100644
index 0000000..dfd6058
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/mtdsplit/mtdsplit_wrgg.c
@@ -0,0 +1,142 @@
+/*
+ *  Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2014 Felix Fietkau <nbd@nbd.name>
+ *  Copyright (C) 2016 Stijn Tintel <stijn@linux-ipv6.be>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/byteorder/generic.h>
+#include <linux/of.h>
+
+#include "mtdsplit.h"
+
+#define WRGG_NR_PARTS		2
+#define WRGG_MIN_ROOTFS_OFFS	0x80000	/* 512KiB */
+#define WRGG03_MAGIC		0x20080321
+#define WRG_MAGIC		0x20040220
+
+struct wrgg03_header {
+	char		signature[32];
+	uint32_t	magic1;
+	uint32_t	magic2;
+	char		version[16];
+	char		model[16];
+	uint32_t	flag[2];
+	uint32_t	reserve[2];
+	char		buildno[16];
+	uint32_t	size;
+	uint32_t	offset;
+	char		devname[32];
+	char		digest[16];
+} __attribute__ ((packed));
+
+struct wrg_header {
+	char		signature[32];
+	uint32_t	magic1;
+	uint32_t	magic2;
+	uint32_t	size;
+	uint32_t	offset;
+	char		devname[32];
+	char		digest[16];
+} __attribute__ ((packed));
+
+
+static int mtdsplit_parse_wrgg(struct mtd_info *master,
+			       const struct mtd_partition **pparts,
+			       struct mtd_part_parser_data *data)
+{
+	struct wrgg03_header hdr;
+	size_t hdr_len, retlen, kernel_ent_size;
+	size_t rootfs_offset;
+	struct mtd_partition *parts;
+	enum mtdsplit_part_type type;
+	int err;
+
+	hdr_len = sizeof(hdr);
+	err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr);
+	if (err)
+		return err;
+
+	if (retlen != hdr_len)
+		return -EIO;
+
+	/* sanity checks */
+	if (le32_to_cpu(hdr.magic1) == WRGG03_MAGIC) {
+		kernel_ent_size = hdr_len + be32_to_cpu(hdr.size);
+		/*
+		 * If this becomes silly big it's probably because the
+		 * WRGG image is little-endian.
+		 */
+		if (kernel_ent_size > master->size)
+			kernel_ent_size = hdr_len + le32_to_cpu(hdr.size);
+
+		/* Now what ?! It's neither */
+		if (kernel_ent_size > master->size)
+			return -EINVAL;
+	} else if (le32_to_cpu(hdr.magic1) == WRG_MAGIC) {
+		kernel_ent_size = sizeof(struct wrg_header) + le32_to_cpu(
+		                  ((struct wrg_header*)&hdr)->size);
+	} else {
+		return -EINVAL;
+	}
+
+	if (kernel_ent_size > master->size)
+		return -EINVAL;
+
+	/*
+	 * The size in the header covers the rootfs as well.
+	 * Start the search from an arbitrary offset.
+	 */
+	err = mtd_find_rootfs_from(master, WRGG_MIN_ROOTFS_OFFS,
+				   master->size, &rootfs_offset, &type);
+	if (err)
+		return err;
+
+	parts = kzalloc(WRGG_NR_PARTS * sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	parts[0].name = KERNEL_PART_NAME;
+	parts[0].offset = 0;
+	parts[0].size = rootfs_offset;
+
+	parts[1].name = ROOTFS_PART_NAME;
+	parts[1].offset = rootfs_offset;
+	parts[1].size = master->size - rootfs_offset;
+
+	*pparts = parts;
+	return WRGG_NR_PARTS;
+}
+
+static const struct of_device_id mtdsplit_wrgg_of_match_table[] = {
+	{ .compatible = "wrg" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mtdsplit_wrgg_of_match_table);
+
+static struct mtd_part_parser mtdsplit_wrgg_parser = {
+	.owner = THIS_MODULE,
+	.name = "wrgg-fw",
+	.of_match_table = mtdsplit_wrgg_of_match_table,
+	.parse_fn = mtdsplit_parse_wrgg,
+	.type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
+static int __init mtdsplit_wrgg_init(void)
+{
+	register_mtd_parser(&mtdsplit_wrgg_parser);
+
+	return 0;
+}
+
+subsys_initcall(mtdsplit_wrgg_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/parsers/routerbootpart.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/parsers/routerbootpart.c
new file mode 100644
index 0000000..f9bba0f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/mtd/parsers/routerbootpart.c
@@ -0,0 +1,365 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Parser for MikroTik RouterBoot partitions.
+ *
+ * Copyright (C) 2020 Thibaut VARÈNE <hacks+kernel@slashdirt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This parser builds from the "fixed-partitions" one (see ofpart.c), but it can
+ * handle dynamic partitions as found on routerboot devices.
+ *
+ * DTS nodes are defined as follows:
+ * For fixed partitions:
+ *	node-name@unit-address {
+ *		reg = <prop-encoded-array>;
+ *		label = <string>;
+ *		read-only;
+ *		lock;
+ *	};
+ *
+ * reg property is mandatory; other properties are optional.
+ * reg format is <address length>. length can be 0 if the next partition is
+ * another fixed partition or a "well-known" partition as defined below: in that
+ * case the partition will extend up to the next one.
+ *
+ * For dynamic partitions:
+ *	node-name {
+ *		size = <prop-encoded-array>;
+ *		label = <string>;
+ *		read-only;
+ *		lock;
+ *	};
+ *
+ * size property is normally mandatory. It can only be omitted (or set to 0) if:
+ *	- the partition is a "well-known" one (as defined below), in which case
+ *	  the partition size will be automatically adjusted; or
+ *	- the next partition is a fixed one or a "well-known" one, in which case
+ *	  the current partition will extend up to the next one.
+ * Other properties are optional.
+ * size format is <length>.
+ * By default dynamic partitions are appended after the preceding one, except
+ * for "well-known" ones which are automatically located on flash.
+ *
+ * Well-known partitions (matched via label or node-name):
+ * - "hard_config"
+ * - "soft_config"
+ * - "dtb_config"
+ *
+ * Note: this parser will happily register 0-sized partitions if misused.
+ *
+ * This parser requires the DTS to list partitions in ascending order as
+ * expected on the MTD device.
+ *
+ * Since only the "hard_config" and "soft_config" partitions are used in OpenWRT,
+ * a minimal working DTS could define only these two partitions dynamically (in
+ * the right order, usually hard_config then soft_config).
+ *
+ * Note: some mips RB devices encode the hard_config offset and length in two
+ * consecutive u32 located at offset 0x14 (for ramips) or 0x24 (for ath79) on
+ * the SPI NOR flash. Unfortunately this seems inconsistent across machines and
+ * does not apply to e.g. ipq-based ones, so we ignore that information.
+ *
+ * Note: To find well-known partitions, this parser will go through the entire
+ * top mtd partition parsed, _before_ the DTS nodes are processed. This works
+ * well in the current state of affairs, and is a simpler implementation than
+ * searching for known partitions in the "holes" left between fixed-partition,
+ * _after_ processing DTS nodes.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/libfdt_env.h>
+#include <linux/string.h>
+
+#define RB_MAGIC_HARD	(('H') | ('a' << 8) | ('r' << 16) | ('d' << 24))
+#define RB_MAGIC_SOFT	(('S') | ('o' << 8) | ('f' << 16) | ('t' << 24))
+#define RB_BLOCK_SIZE	0x1000
+
+struct routerboot_dynpart {
+	const char * const name;
+	const u32 magic;
+	int (* const size_fixup)(struct mtd_info *, struct routerboot_dynpart *);
+	size_t offset;
+	size_t size;
+	bool found;
+};
+
+static int routerboot_dtbsfixup(struct mtd_info *, struct routerboot_dynpart *);
+
+static struct routerboot_dynpart rb_dynparts[] = {
+	{
+		.name = "hard_config",
+		.magic = RB_MAGIC_HARD,	// stored in CPU-endianness on flash
+		.size_fixup = NULL,
+		.offset = 0x0,
+		.size = RB_BLOCK_SIZE,
+		.found = false,
+	}, {
+		.name = "soft_config",
+		.magic = RB_MAGIC_SOFT,	// stored in CPU-endianness on flash
+		.size_fixup = NULL,
+		.offset = 0x0,
+		.size = RB_BLOCK_SIZE,
+		.found = false,
+	}, {
+		.name = "dtb_config",
+		.magic = fdt32_to_cpu(OF_DT_HEADER),	// stored BE on flash
+		.size_fixup = routerboot_dtbsfixup,
+		.offset = 0x0,
+		.size = 0x0,
+		.found = false,
+	}
+};
+
+static int routerboot_dtbsfixup(struct mtd_info *master, struct routerboot_dynpart *rbdpart)
+{
+	int err;
+	size_t bytes_read, psize;
+	struct {
+		fdt32_t magic;
+		fdt32_t totalsize;
+		fdt32_t off_dt_struct;
+		fdt32_t off_dt_strings;
+		fdt32_t off_mem_rsvmap;
+		fdt32_t version;
+		fdt32_t last_comp_version;
+		fdt32_t boot_cpuid_phys;
+		fdt32_t size_dt_strings;
+		fdt32_t size_dt_struct;
+	} fdt_header;
+
+	err = mtd_read(master, rbdpart->offset, sizeof(fdt_header),
+		       &bytes_read, (u8 *)&fdt_header);
+	if (err)
+		return err;
+
+	if (bytes_read != sizeof(fdt_header))
+		return -EIO;
+
+	psize = fdt32_to_cpu(fdt_header.totalsize);
+	if (!psize)
+		return -EINVAL;
+
+	rbdpart->size = psize;
+	return 0;
+}
+
+static void routerboot_find_dynparts(struct mtd_info *master)
+{
+	size_t bytes_read, offset;
+	bool allfound;
+	int err, i;
+	u32 buf;
+
+	/*
+	 * Dynamic RouterBoot partitions offsets are aligned to RB_BLOCK_SIZE:
+	 * read the whole partition at RB_BLOCK_SIZE intervals to find sigs.
+	 * Skip partition content when possible.
+	 */
+	offset = 0;
+	while (offset < master->size) {
+		err = mtd_read(master, offset, sizeof(buf), &bytes_read, (u8 *)&buf);
+		if (err) {
+			pr_err("%s: mtd_read error while parsing (offset: 0x%X): %d\n",
+			       master->name, offset, err);
+			continue;
+		}
+
+		allfound = true;
+
+		for (i = 0; i < ARRAY_SIZE(rb_dynparts); i++) {
+			if (rb_dynparts[i].found)
+				continue;
+
+			allfound = false;
+
+			if (rb_dynparts[i].magic == buf) {
+				rb_dynparts[i].offset = offset;
+
+				if (rb_dynparts[i].size_fixup) {
+					err = rb_dynparts[i].size_fixup(master, &rb_dynparts[i]);
+					if (err) {
+						pr_err("%s: size fixup error while parsing \"%s\": %d\n",
+						       master->name, rb_dynparts[i].name, err);
+						continue;
+					}
+				}
+
+				rb_dynparts[i].found = true;
+
+				/*
+				 * move offset to skip the whole partition on
+				 * next iteration if size > RB_BLOCK_SIZE.
+				 */
+				if (rb_dynparts[i].size > RB_BLOCK_SIZE)
+					offset += ALIGN_DOWN((rb_dynparts[i].size - RB_BLOCK_SIZE), RB_BLOCK_SIZE);
+
+				break;
+			}
+		}
+
+		offset += RB_BLOCK_SIZE;
+
+		if (allfound)
+			break;
+	}
+}
+
+static int routerboot_partitions_parse(struct mtd_info *master,
+				       const struct mtd_partition **pparts,
+				       struct mtd_part_parser_data *data)
+{
+	struct device_node *rbpart_node, *pp;
+	struct mtd_partition *parts;
+	const char *partname;
+	size_t master_ofs;
+	int np;
+
+	/* Pull of_node from the master device node */
+	rbpart_node = mtd_get_of_node(master);
+	if (!rbpart_node)
+		return 0;
+
+	/* First count the subnodes */
+	np = 0;
+	for_each_child_of_node(rbpart_node,  pp)
+		np++;
+
+	if (!np)
+		return 0;
+
+	parts = kcalloc(np, sizeof(*parts), GFP_KERNEL);
+	if (!parts)
+		return -ENOMEM;
+
+	/* Preemptively look for known parts in flash */
+	routerboot_find_dynparts(master);
+
+	np = 0;
+	master_ofs = 0;
+	for_each_child_of_node(rbpart_node, pp) {
+		const __be32 *reg, *sz;
+		size_t offset, size;
+		int i, len, a_cells, s_cells;
+
+		partname = of_get_property(pp, "label", &len);
+		/* Allow deprecated use of "name" instead of "label" */
+		if (!partname)
+			partname = of_get_property(pp, "name", &len);
+		/* Fallback to node name per spec if all else fails: partname is always set */
+		if (!partname)
+			partname = pp->name;
+		parts[np].name = partname;
+
+		reg = of_get_property(pp, "reg", &len);
+		if (reg) {
+			/* Fixed partition */
+			a_cells = of_n_addr_cells(pp);
+			s_cells = of_n_size_cells(pp);
+
+			if ((len / 4) != (a_cells + s_cells)) {
+				pr_debug("%s: routerboot partition %pOF (%pOF) error parsing reg property.\n",
+					 master->name, pp, rbpart_node);
+				goto rbpart_fail;
+			}
+
+			offset = of_read_number(reg, a_cells);
+			size = of_read_number(reg + a_cells, s_cells);
+		} else {
+			/* Dynamic partition */
+			/* Default: part starts at current offset, 0 size */
+			offset = master_ofs;
+			size = 0;
+
+			/* Check if well-known partition */
+			for (i = 0; i < ARRAY_SIZE(rb_dynparts); i++) {
+				if (!strcmp(partname, rb_dynparts[i].name) && rb_dynparts[i].found) {
+					offset = rb_dynparts[i].offset;
+					size = rb_dynparts[i].size;
+					break;
+				}
+			}
+
+			/* Standalone 'size' property? Override size */
+			sz = of_get_property(pp, "size", &len);
+			if (sz) {
+				s_cells = of_n_size_cells(pp);
+				if ((len / 4) != s_cells) {
+					pr_debug("%s: routerboot partition %pOF (%pOF) error parsing size property.\n",
+						 master->name, pp, rbpart_node);
+					goto rbpart_fail;
+				}
+
+				size = of_read_number(sz, s_cells);
+			}
+		}
+
+		if (np > 0) {
+			/* Minor sanity check for overlaps */
+			if (offset < (parts[np-1].offset + parts[np-1].size)) {
+				pr_err("%s: routerboot partition %pOF (%pOF) \"%s\" overlaps with previous partition \"%s\".\n",
+				       master->name, pp, rbpart_node,
+				       partname, parts[np-1].name);
+				goto rbpart_fail;
+			}
+
+			/* Fixup end of previous partition if necessary */
+			if (!parts[np-1].size)
+				parts[np-1].size = (offset - parts[np-1].offset);
+		}
+
+		if ((offset + size) > master->size) {
+			pr_err("%s: routerboot partition %pOF (%pOF) \"%s\" extends past end of segment.\n",
+			       master->name, pp, rbpart_node, partname);
+			goto rbpart_fail;
+		}
+
+		parts[np].offset = offset;
+		parts[np].size = size;
+		parts[np].of_node = pp;
+
+		if (of_get_property(pp, "read-only", &len))
+			parts[np].mask_flags |= MTD_WRITEABLE;
+
+		if (of_get_property(pp, "lock", &len))
+			parts[np].mask_flags |= MTD_POWERUP_LOCK;
+
+		/* Keep master offset aligned to RB_BLOCK_SIZE */
+		master_ofs = ALIGN(offset + size, RB_BLOCK_SIZE);
+		np++;
+	}
+
+	*pparts = parts;
+	return np;
+
+rbpart_fail:
+	pr_err("%s: error parsing routerboot partition %pOF (%pOF)\n",
+	       master->name, pp, rbpart_node);
+	of_node_put(pp);
+	kfree(parts);
+	return -EINVAL;
+}
+
+static const struct of_device_id parse_routerbootpart_match_table[] = {
+	{ .compatible = "mikrotik,routerboot-partitions" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, parse_routerbootpart_match_table);
+
+static struct mtd_part_parser routerbootpart_parser = {
+	.parse_fn = routerboot_partitions_parse,
+	.name = "routerbootpart",
+	.of_match_table = parse_routerbootpart_match_table,
+};
+module_mtd_part_parser(routerbootpart_parser);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MTD partitioning for RouterBoot");
+MODULE_AUTHOR("Thibaut VARENE");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/adm6996.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/adm6996.c
new file mode 100644
index 0000000..66013f2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/adm6996.c
@@ -0,0 +1,1243 @@
+/*
+ * ADM6996 switch driver
+ *
+ * swconfig interface based on ar8216.c
+ *
+ * Copyright (c) 2008 Felix Fietkau <nbd@nbd.name>
+ * VLAN support Copyright (c) 2010, 2011 Peter Lebbing <peter@digitalbrains.com>
+ * Copyright (c) 2013 Hauke Mehrtens <hauke@hauke-m.de>
+ * Copyright (c) 2014 Matti Laakso <malaakso@elisanet.fi>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+/*#define DEBUG 1*/
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/adm6996-gpio.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/switch.h>
+#include <linux/version.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include "adm6996.h"
+
+MODULE_DESCRIPTION("Infineon ADM6996 Switch");
+MODULE_AUTHOR("Felix Fietkau, Peter Lebbing <peter@digitalbrains.com>");
+MODULE_LICENSE("GPL");
+
+static const char * const adm6996_model_name[] =
+{
+	NULL,
+	"ADM6996FC",
+	"ADM6996M",
+	"ADM6996L"
+};
+
+struct adm6996_mib_desc {
+	unsigned int offset;
+	const char *name;
+};
+
+struct adm6996_priv {
+	struct switch_dev dev;
+	void *priv;
+
+	u8 eecs;
+	u8 eesk;
+	u8 eedi;
+
+	enum adm6996_model model;
+
+	bool enable_vlan;
+	bool vlan_enabled;	/* Current hardware state */
+
+#ifdef DEBUG
+	u16 addr;		/* Debugging: register address to operate on */
+#endif
+
+	u16 pvid[ADM_NUM_PORTS];	/* Primary VLAN ID */
+	u8 tagged_ports;
+
+	u16 vlan_id[ADM_NUM_VLANS];
+	u8 vlan_table[ADM_NUM_VLANS];	/* bitmap, 1 = port is member */
+	u8 vlan_tagged[ADM_NUM_VLANS];	/* bitmap, 1 = tagged member */
+	
+	struct mutex mib_lock;
+	char buf[2048];
+
+	struct mutex reg_mutex;
+
+	/* use abstraction for regops, we want to add gpio support in the future */
+	u16 (*read)(struct adm6996_priv *priv, enum admreg reg);
+	void (*write)(struct adm6996_priv *priv, enum admreg reg, u16 val);
+};
+
+#define to_adm(_dev) container_of(_dev, struct adm6996_priv, dev)
+#define phy_to_adm(_phy) ((struct adm6996_priv *) (_phy)->priv)
+
+#define MIB_DESC(_o, _n)	\
+	{			\
+		.offset = (_o),	\
+		.name = (_n),	\
+	}
+
+static const struct adm6996_mib_desc adm6996_mibs[] = {
+	MIB_DESC(ADM_CL0, "RxPacket"),
+	MIB_DESC(ADM_CL6, "RxByte"),
+	MIB_DESC(ADM_CL12, "TxPacket"),
+	MIB_DESC(ADM_CL18, "TxByte"),
+	MIB_DESC(ADM_CL24, "Collision"),
+	MIB_DESC(ADM_CL30, "Error"),
+};
+
+#define ADM6996_MIB_RXB_ID	1
+#define ADM6996_MIB_TXB_ID	3
+
+static inline u16
+r16(struct adm6996_priv *priv, enum admreg reg)
+{
+	return priv->read(priv, reg);
+}
+
+static inline void
+w16(struct adm6996_priv *priv, enum admreg reg, u16 val)
+{
+	priv->write(priv, reg, val);
+}
+
+/* Minimum timing constants */
+#define EECK_EDGE_TIME  3   /* 3us - max(adm 2.5us, 93c 1us) */
+#define EEDI_SETUP_TIME 1   /* 1us - max(adm 10ns, 93c 400ns) */
+#define EECS_SETUP_TIME 1   /* 1us - max(adm no, 93c 200ns) */
+
+static void adm6996_gpio_write(struct adm6996_priv *priv, int cs, char *buf, unsigned int bits)
+{
+	int i, len = (bits + 7) / 8;
+	u8 mask;
+
+	gpio_set_value(priv->eecs, cs);
+	udelay(EECK_EDGE_TIME);
+
+	/* Byte assemble from MSB to LSB */
+	for (i = 0; i < len; i++) {
+		/* Bit bang from MSB to LSB */
+		for (mask = 0x80; mask && bits > 0; mask >>= 1, bits --) {
+			/* Clock low */
+			gpio_set_value(priv->eesk, 0);
+			udelay(EECK_EDGE_TIME);
+
+			/* Output on rising edge */
+			gpio_set_value(priv->eedi, (mask & buf[i]));
+			udelay(EEDI_SETUP_TIME);
+
+			/* Clock high */
+			gpio_set_value(priv->eesk, 1);
+			udelay(EECK_EDGE_TIME);
+		}
+	}
+
+	/* Clock low */
+	gpio_set_value(priv->eesk, 0);
+	udelay(EECK_EDGE_TIME);
+
+	if (cs)
+		gpio_set_value(priv->eecs, 0);
+}
+
+static void adm6996_gpio_read(struct adm6996_priv *priv, int cs, char *buf, unsigned int bits)
+{
+	int i, len = (bits + 7) / 8;
+	u8 mask;
+
+	gpio_set_value(priv->eecs, cs);
+	udelay(EECK_EDGE_TIME);
+
+	/* Byte assemble from MSB to LSB */
+	for (i = 0; i < len; i++) {
+		u8 byte;
+
+		/* Bit bang from MSB to LSB */
+		for (mask = 0x80, byte = 0; mask && bits > 0; mask >>= 1, bits --) {
+			u8 gp;
+
+			/* Clock low */
+			gpio_set_value(priv->eesk, 0);
+			udelay(EECK_EDGE_TIME);
+
+			/* Input on rising edge */
+			gp = gpio_get_value(priv->eedi);
+			if (gp)
+				byte |= mask;
+
+			/* Clock high */
+			gpio_set_value(priv->eesk, 1);
+			udelay(EECK_EDGE_TIME);
+		}
+
+		*buf++ = byte;
+	}
+
+	/* Clock low */
+	gpio_set_value(priv->eesk, 0);
+	udelay(EECK_EDGE_TIME);
+
+	if (cs)
+		gpio_set_value(priv->eecs, 0);
+}
+
+/* Advance clock(s) */
+static void adm6996_gpio_adclk(struct adm6996_priv *priv, int clocks)
+{
+	int i;
+	for (i = 0; i < clocks; i++) {
+		/* Clock high */
+		gpio_set_value(priv->eesk, 1);
+		udelay(EECK_EDGE_TIME);
+
+		/* Clock low */
+		gpio_set_value(priv->eesk, 0);
+		udelay(EECK_EDGE_TIME);
+	}
+}
+
+static u16
+adm6996_read_gpio_reg(struct adm6996_priv *priv, enum admreg reg)
+{
+	/* cmd: 01 10 T DD R RRRRRR */
+	u8 bits[6] = {
+		0xFF, 0xFF, 0xFF, 0xFF,
+		(0x06 << 4) | ((0 & 0x01) << 3 | (reg&64)>>6),
+		((reg&63)<<2)
+	};
+
+	u8 rbits[4];
+
+	/* Enable GPIO outputs with all pins to 0 */
+	gpio_direction_output(priv->eecs, 0);
+	gpio_direction_output(priv->eesk, 0);
+	gpio_direction_output(priv->eedi, 0);
+
+	adm6996_gpio_write(priv, 0, bits, 46);
+	gpio_direction_input(priv->eedi);
+	adm6996_gpio_adclk(priv, 2);
+	adm6996_gpio_read(priv, 0, rbits, 32);
+
+	/* Extra clock(s) required per datasheet */
+	adm6996_gpio_adclk(priv, 2);
+
+	/* Disable GPIO outputs */
+	gpio_direction_input(priv->eecs);
+	gpio_direction_input(priv->eesk);
+
+	 /* EEPROM has 16-bit registers, but pumps out two registers in one request */
+	return (reg & 0x01 ?  (rbits[0]<<8) | rbits[1] : (rbits[2]<<8) | (rbits[3]));
+}
+
+/* Write chip configuration register */
+/* Follow 93c66 timing and chip's min EEPROM timing requirement */
+static void
+adm6996_write_gpio_reg(struct adm6996_priv *priv, enum admreg reg, u16 val)
+{
+	/* cmd(27bits): sb(1) + opc(01) + addr(bbbbbbbb) + data(bbbbbbbbbbbbbbbb) */
+	u8 bits[4] = {
+		(0x05 << 5) | (reg >> 3),
+		(reg << 5) | (u8)(val >> 11),
+		(u8)(val >> 3),
+		(u8)(val << 5)
+	};
+
+	/* Enable GPIO outputs with all pins to 0 */
+	gpio_direction_output(priv->eecs, 0);
+	gpio_direction_output(priv->eesk, 0);
+	gpio_direction_output(priv->eedi, 0);
+
+	/* Write cmd. Total 27 bits */
+	adm6996_gpio_write(priv, 1, bits, 27);
+
+	/* Extra clock(s) required per datasheet */
+	adm6996_gpio_adclk(priv, 2);
+
+	/* Disable GPIO outputs */
+	gpio_direction_input(priv->eecs);
+	gpio_direction_input(priv->eesk);
+	gpio_direction_input(priv->eedi);
+}
+
+static u16
+adm6996_read_mii_reg(struct adm6996_priv *priv, enum admreg reg)
+{
+	struct phy_device *phydev = priv->priv;
+	struct mii_bus *bus = phydev->mdio.bus;
+
+	return bus->read(bus, PHYADDR(reg));
+}
+
+static void
+adm6996_write_mii_reg(struct adm6996_priv *priv, enum admreg reg, u16 val)
+{
+	struct phy_device *phydev = priv->priv;
+	struct mii_bus *bus = phydev->mdio.bus;
+
+	bus->write(bus, PHYADDR(reg), val);
+}
+
+static int
+adm6996_set_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	if (val->value.i > 1)
+		return -EINVAL;
+
+	priv->enable_vlan = val->value.i;
+
+	return 0;
+};
+
+static int
+adm6996_get_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	val->value.i = priv->enable_vlan;
+
+	return 0;
+};
+
+#ifdef DEBUG
+
+static int
+adm6996_set_addr(struct switch_dev *dev, const struct switch_attr *attr,
+		 struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	if (val->value.i > 1023)
+		return -EINVAL;
+
+	priv->addr = val->value.i;
+
+	return 0;
+};
+
+static int
+adm6996_get_addr(struct switch_dev *dev, const struct switch_attr *attr,
+		 struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	val->value.i = priv->addr;
+
+	return 0;
+};
+
+static int
+adm6996_set_data(struct switch_dev *dev, const struct switch_attr *attr,
+		 struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	if (val->value.i > 65535)
+		return -EINVAL;
+
+	w16(priv, priv->addr, val->value.i);
+
+	return 0;
+};
+
+static int
+adm6996_get_data(struct switch_dev *dev, const struct switch_attr *attr,
+		 struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	val->value.i = r16(priv, priv->addr);
+
+	return 0;
+};
+
+#endif /* def DEBUG */
+
+static int
+adm6996_set_pvid(struct switch_dev *dev, int port, int vlan)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	pr_devel("set_pvid port %d vlan %d\n", port, vlan);
+
+	if (vlan > ADM_VLAN_MAX_ID)
+		return -EINVAL;
+
+	priv->pvid[port] = vlan;
+
+	return 0;
+}
+
+static int
+adm6996_get_pvid(struct switch_dev *dev, int port, int *vlan)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	pr_devel("get_pvid port %d\n", port);
+	*vlan = priv->pvid[port];
+
+	return 0;
+}
+
+static int
+adm6996_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
+		struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	pr_devel("set_vid port %d vid %d\n", val->port_vlan, val->value.i);
+
+	if (val->value.i > ADM_VLAN_MAX_ID)
+		return -EINVAL;
+
+	priv->vlan_id[val->port_vlan] = val->value.i;
+
+	return 0;
+};
+
+static int
+adm6996_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
+		struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	pr_devel("get_vid port %d\n", val->port_vlan);
+
+	val->value.i = priv->vlan_id[val->port_vlan];
+
+	return 0;
+};
+
+static int
+adm6996_get_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+	u8 ports = priv->vlan_table[val->port_vlan];
+	u8 tagged = priv->vlan_tagged[val->port_vlan];
+	int i;
+
+	pr_devel("get_ports port_vlan %d\n", val->port_vlan);
+
+	val->len = 0;
+
+	for (i = 0; i < ADM_NUM_PORTS; i++) {
+		struct switch_port *p;
+
+		if (!(ports & (1 << i)))
+			continue;
+
+		p = &val->value.ports[val->len++];
+		p->id = i;
+		if (tagged & (1 << i))
+			p->flags = (1 << SWITCH_PORT_FLAG_TAGGED);
+		else
+			p->flags = 0;
+	}
+
+	return 0;
+};
+
+static int
+adm6996_set_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+	u8 *ports = &priv->vlan_table[val->port_vlan];
+	u8 *tagged = &priv->vlan_tagged[val->port_vlan];
+	int i;
+
+	pr_devel("set_ports port_vlan %d ports", val->port_vlan);
+
+	*ports = 0;
+	*tagged = 0;
+
+	for (i = 0; i < val->len; i++) {
+		struct switch_port *p = &val->value.ports[i];
+
+#ifdef DEBUG
+		pr_cont(" %d%s", p->id,
+		       ((p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) ? "T" :
+			""));
+#endif
+
+		if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) {
+			*tagged |= (1 << p->id);
+			priv->tagged_ports |= (1 << p->id);
+		}
+
+		*ports |= (1 << p->id);
+	}
+
+#ifdef DEBUG
+	pr_cont("\n");
+#endif
+
+	return 0;
+};
+
+/*
+ * Precondition: reg_mutex must be held
+ */
+static void
+adm6996_enable_vlan(struct adm6996_priv *priv)
+{
+	u16 reg;
+
+	reg = r16(priv, ADM_OTBE_P2_PVID);
+	reg &= ~(ADM_OTBE_MASK);
+	w16(priv, ADM_OTBE_P2_PVID, reg);
+	reg = r16(priv, ADM_IFNTE);
+	reg &= ~(ADM_IFNTE_MASK);
+	w16(priv, ADM_IFNTE, reg);
+	reg = r16(priv, ADM_VID_CHECK);
+	reg |= ADM_VID_CHECK_MASK;
+	w16(priv, ADM_VID_CHECK, reg);
+	reg = r16(priv, ADM_SYSC0);
+	reg |= ADM_NTTE;
+	reg &= ~(ADM_RVID1);
+	w16(priv, ADM_SYSC0, reg);
+	reg = r16(priv, ADM_SYSC3);
+	reg |= ADM_TBV;
+	w16(priv, ADM_SYSC3, reg);
+}
+
+static void
+adm6996_enable_vlan_6996l(struct adm6996_priv *priv)
+{
+	u16 reg;
+
+	reg = r16(priv, ADM_SYSC3);
+	reg |= ADM_TBV;
+	reg |= ADM_MAC_CLONE;
+	w16(priv, ADM_SYSC3, reg);
+}
+
+/*
+ * Disable VLANs
+ *
+ * Sets VLAN mapping for port-based VLAN with all ports connected to
+ * eachother (this is also the power-on default).
+ *
+ * Precondition: reg_mutex must be held
+ */
+static void
+adm6996_disable_vlan(struct adm6996_priv *priv)
+{
+	u16 reg;
+	int i;
+
+	for (i = 0; i < ADM_NUM_VLANS; i++) {
+		reg = ADM_VLAN_FILT_MEMBER_MASK;
+		w16(priv, ADM_VLAN_FILT_L(i), reg);
+		reg = ADM_VLAN_FILT_VALID | ADM_VLAN_FILT_VID(1);
+		w16(priv, ADM_VLAN_FILT_H(i), reg);
+	}
+
+	reg = r16(priv, ADM_OTBE_P2_PVID);
+	reg |= ADM_OTBE_MASK;
+	w16(priv, ADM_OTBE_P2_PVID, reg);
+	reg = r16(priv, ADM_IFNTE);
+	reg |= ADM_IFNTE_MASK;
+	w16(priv, ADM_IFNTE, reg);
+	reg = r16(priv, ADM_VID_CHECK);
+	reg &= ~(ADM_VID_CHECK_MASK);
+	w16(priv, ADM_VID_CHECK, reg);
+	reg = r16(priv, ADM_SYSC0);
+	reg &= ~(ADM_NTTE);
+	reg |= ADM_RVID1;
+	w16(priv, ADM_SYSC0, reg);
+	reg = r16(priv, ADM_SYSC3);
+	reg &= ~(ADM_TBV);
+	w16(priv, ADM_SYSC3, reg);
+}
+
+/*
+ * Disable VLANs
+ *
+ * Sets VLAN mapping for port-based VLAN with all ports connected to
+ * eachother (this is also the power-on default).
+ *
+ * Precondition: reg_mutex must be held
+ */
+static void
+adm6996_disable_vlan_6996l(struct adm6996_priv *priv)
+{
+	u16 reg;
+	int i;
+
+	for (i = 0; i < ADM_NUM_VLANS; i++) {
+		w16(priv, ADM_VLAN_MAP(i), 0);
+	}
+
+	reg = r16(priv, ADM_SYSC3);
+	reg &= ~(ADM_TBV);
+	reg &= ~(ADM_MAC_CLONE);
+	w16(priv, ADM_SYSC3, reg);
+}
+
+/*
+ * Precondition: reg_mutex must be held
+ */
+static void
+adm6996_apply_port_pvids(struct adm6996_priv *priv)
+{
+	u16 reg;
+	int i;
+
+	for (i = 0; i < ADM_NUM_PORTS; i++) {
+		reg = r16(priv, adm_portcfg[i]);
+		reg &= ~(ADM_PORTCFG_PVID_MASK);
+		reg |= ADM_PORTCFG_PVID(priv->pvid[i]);
+		if (priv->model == ADM6996L) {
+			if (priv->tagged_ports & (1 << i))
+				reg |= (1 << 4);
+			else
+				reg &= ~(1 << 4);
+		}
+		w16(priv, adm_portcfg[i], reg);
+	}
+
+	w16(priv, ADM_P0_PVID, ADM_P0_PVID_VAL(priv->pvid[0]));
+	w16(priv, ADM_P1_PVID, ADM_P1_PVID_VAL(priv->pvid[1]));
+	reg = r16(priv, ADM_OTBE_P2_PVID);
+	reg &= ~(ADM_P2_PVID_MASK);
+	reg |= ADM_P2_PVID_VAL(priv->pvid[2]);
+	w16(priv, ADM_OTBE_P2_PVID, reg);
+	reg = ADM_P3_PVID_VAL(priv->pvid[3]);
+	reg |= ADM_P4_PVID_VAL(priv->pvid[4]);
+	w16(priv, ADM_P3_P4_PVID, reg);
+	reg = r16(priv, ADM_P5_PVID);
+	reg &= ~(ADM_P2_PVID_MASK);
+	reg |= ADM_P5_PVID_VAL(priv->pvid[5]);
+	w16(priv, ADM_P5_PVID, reg);
+}
+
+/*
+ * Precondition: reg_mutex must be held
+ */
+static void
+adm6996_apply_vlan_filters(struct adm6996_priv *priv)
+{
+	u8 ports, tagged;
+	u16 vid, reg;
+	int i;
+
+	for (i = 0; i < ADM_NUM_VLANS; i++) {
+		vid = priv->vlan_id[i];
+		ports = priv->vlan_table[i];
+		tagged = priv->vlan_tagged[i];
+
+		if (ports == 0) {
+			/* Disable VLAN entry */
+			w16(priv, ADM_VLAN_FILT_H(i), 0);
+			w16(priv, ADM_VLAN_FILT_L(i), 0);
+			continue;
+		}
+
+		reg = ADM_VLAN_FILT_MEMBER(ports);
+		reg |= ADM_VLAN_FILT_TAGGED(tagged);
+		w16(priv, ADM_VLAN_FILT_L(i), reg);
+		reg = ADM_VLAN_FILT_VALID | ADM_VLAN_FILT_VID(vid);
+		w16(priv, ADM_VLAN_FILT_H(i), reg);
+	}
+}
+
+static void
+adm6996_apply_vlan_filters_6996l(struct adm6996_priv *priv)
+{
+	u8 ports;
+	u16 reg;
+	int i;
+
+	for (i = 0; i < ADM_NUM_VLANS; i++) {
+		ports = priv->vlan_table[i];
+
+		if (ports == 0) {
+			/* Disable VLAN entry */
+			w16(priv, ADM_VLAN_MAP(i), 0);
+			continue;
+		} else {
+			reg = ADM_VLAN_FILT(ports);
+			w16(priv, ADM_VLAN_MAP(i), reg);
+		}
+	}
+}
+
+static int
+adm6996_hw_apply(struct switch_dev *dev)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	pr_devel("hw_apply\n");
+
+	mutex_lock(&priv->reg_mutex);
+
+	if (!priv->enable_vlan) {
+		if (priv->vlan_enabled) {
+			if (priv->model == ADM6996L)
+				adm6996_disable_vlan_6996l(priv);
+			else
+				adm6996_disable_vlan(priv);
+			priv->vlan_enabled = 0;
+		}
+		goto out;
+	}
+
+	if (!priv->vlan_enabled) {
+		if (priv->model == ADM6996L)
+			adm6996_enable_vlan_6996l(priv);
+		else
+			adm6996_enable_vlan(priv);
+		priv->vlan_enabled = 1;
+	}
+
+	adm6996_apply_port_pvids(priv);
+	if (priv->model == ADM6996L)
+		adm6996_apply_vlan_filters_6996l(priv);
+	else
+		adm6996_apply_vlan_filters(priv);
+
+out:
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+/*
+ * Reset the switch
+ *
+ * The ADM6996 can't do a software-initiated reset, so we just initialise the
+ * registers we support in this driver.
+ *
+ * Precondition: reg_mutex must be held
+ */
+static void
+adm6996_perform_reset (struct adm6996_priv *priv)
+{
+	int i;
+
+	/* initialize port and vlan settings */
+	for (i = 0; i < ADM_NUM_PORTS - 1; i++) {
+		w16(priv, adm_portcfg[i], ADM_PORTCFG_INIT |
+			ADM_PORTCFG_PVID(0));
+	}
+	w16(priv, adm_portcfg[5], ADM_PORTCFG_CPU);
+
+	if (priv->model == ADM6996M || priv->model == ADM6996FC) {
+		/* reset all PHY ports */
+		for (i = 0; i < ADM_PHY_PORTS; i++) {
+			w16(priv, ADM_PHY_PORT(i), ADM_PHYCFG_INIT);
+		}
+	}
+
+	priv->enable_vlan = 0;
+	priv->vlan_enabled = 0;
+
+	for (i = 0; i < ADM_NUM_PORTS; i++) {
+		priv->pvid[i] = 0;
+	}
+
+	for (i = 0; i < ADM_NUM_VLANS; i++) {
+		priv->vlan_id[i] = i;
+		priv->vlan_table[i] = 0;
+		priv->vlan_tagged[i] = 0;
+	}
+
+	if (priv->model == ADM6996M) {
+		/* Clear VLAN priority map so prio's are unused */
+		w16 (priv, ADM_VLAN_PRIOMAP, 0);
+
+		adm6996_disable_vlan(priv);
+		adm6996_apply_port_pvids(priv);
+	} else if (priv->model == ADM6996L) {
+		/* Clear VLAN priority map so prio's are unused */
+		w16 (priv, ADM_VLAN_PRIOMAP, 0);
+
+		adm6996_disable_vlan_6996l(priv);
+		adm6996_apply_port_pvids(priv);
+	}
+}
+
+static int
+adm6996_reset_switch(struct switch_dev *dev)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+
+	pr_devel("reset\n");
+
+	mutex_lock(&priv->reg_mutex);
+	adm6996_perform_reset (priv);
+	mutex_unlock(&priv->reg_mutex);
+	return 0;
+}
+
+static int
+adm6996_get_port_link(struct switch_dev *dev, int port,
+		struct switch_port_link *link)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+	
+	u16 reg = 0;
+	
+	if (port >= ADM_NUM_PORTS)
+		return -EINVAL;
+	
+	switch (port) {
+	case 0:
+		reg = r16(priv, ADM_PS0);
+		break;
+	case 1:
+		reg = r16(priv, ADM_PS0);
+		reg = reg >> 8;
+		break;
+	case 2:
+		reg = r16(priv, ADM_PS1);
+		break;
+	case 3:
+		reg = r16(priv, ADM_PS1);
+		reg = reg >> 8;
+		break;
+	case 4:
+		reg = r16(priv, ADM_PS1);
+		reg = reg >> 12;
+		break;
+	case 5:
+		reg = r16(priv, ADM_PS2);
+		/* Bits 0, 1, 3 and 4. */
+		reg = (reg & 3) | ((reg & 24) >> 1);
+		break;
+	default:
+		return -EINVAL;
+	}
+	
+	link->link = reg & ADM_PS_LS;
+	if (!link->link)
+		return 0;
+	link->aneg = true;
+	link->duplex = reg & ADM_PS_DS;
+	link->tx_flow = reg & ADM_PS_FCS;
+	link->rx_flow = reg & ADM_PS_FCS;
+	if (reg & ADM_PS_SS)
+		link->speed = SWITCH_PORT_SPEED_100;
+	else
+		link->speed = SWITCH_PORT_SPEED_10;
+
+	return 0;
+}
+
+static int
+adm6996_sw_get_port_mib(struct switch_dev *dev,
+		       const struct switch_attr *attr,
+		       struct switch_val *val)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+	int port;
+	char *buf = priv->buf;
+	int i, len = 0;
+	u32 reg = 0;
+
+	port = val->port_vlan;
+	if (port >= ADM_NUM_PORTS)
+		return -EINVAL;
+
+	mutex_lock(&priv->mib_lock);
+
+	len += snprintf(buf + len, sizeof(priv->buf) - len,
+			"Port %d MIB counters\n",
+			port);
+
+	for (i = 0; i < ARRAY_SIZE(adm6996_mibs); i++) {
+		reg = r16(priv, adm6996_mibs[i].offset + ADM_OFFSET_PORT(port));
+		reg += r16(priv, adm6996_mibs[i].offset + ADM_OFFSET_PORT(port) + 1) << 16;
+		len += snprintf(buf + len, sizeof(priv->buf) - len,
+				"%-12s: %u\n",
+				adm6996_mibs[i].name,
+				reg);
+	}
+
+	mutex_unlock(&priv->mib_lock);
+
+	val->value.s = buf;
+	val->len = len;
+
+	return 0;
+}
+
+static int
+adm6996_get_port_stats(struct switch_dev *dev, int port,
+			struct switch_port_stats *stats)
+{
+	struct adm6996_priv *priv = to_adm(dev);
+	int id;
+	u32 reg = 0;
+
+	if (port >= ADM_NUM_PORTS)
+		return -EINVAL;
+
+	mutex_lock(&priv->mib_lock);
+
+	id = ADM6996_MIB_TXB_ID;
+	reg = r16(priv, adm6996_mibs[id].offset + ADM_OFFSET_PORT(port));
+	reg += r16(priv, adm6996_mibs[id].offset + ADM_OFFSET_PORT(port) + 1) << 16;
+	stats->tx_bytes = reg;
+
+	id = ADM6996_MIB_RXB_ID;
+	reg = r16(priv, adm6996_mibs[id].offset + ADM_OFFSET_PORT(port));
+	reg += r16(priv, adm6996_mibs[id].offset + ADM_OFFSET_PORT(port) + 1) << 16;
+	stats->rx_bytes = reg;
+
+	mutex_unlock(&priv->mib_lock);
+
+	return 0;
+}
+
+static struct switch_attr adm6996_globals[] = {
+	{
+	 .type = SWITCH_TYPE_INT,
+	 .name = "enable_vlan",
+	 .description = "Enable VLANs",
+	 .set = adm6996_set_enable_vlan,
+	 .get = adm6996_get_enable_vlan,
+	},
+#ifdef DEBUG
+	{
+	 .type = SWITCH_TYPE_INT,
+	 .name = "addr",
+	 .description =
+	 "Direct register access: set register address (0 - 1023)",
+	 .set = adm6996_set_addr,
+	 .get = adm6996_get_addr,
+	 },
+	{
+	 .type = SWITCH_TYPE_INT,
+	 .name = "data",
+	 .description =
+	 "Direct register access: read/write to register (0 - 65535)",
+	 .set = adm6996_set_data,
+	 .get = adm6996_get_data,
+	 },
+#endif /* def DEBUG */
+};
+
+static struct switch_attr adm6996_port[] = {
+	{
+	 .type = SWITCH_TYPE_STRING,
+	 .name = "mib",
+	 .description = "Get port's MIB counters",
+	 .set = NULL,
+	 .get = adm6996_sw_get_port_mib,
+	},
+};
+
+static struct switch_attr adm6996_vlan[] = {
+	{
+	 .type = SWITCH_TYPE_INT,
+	 .name = "vid",
+	 .description = "VLAN ID",
+	 .set = adm6996_set_vid,
+	 .get = adm6996_get_vid,
+	 },
+};
+
+static struct switch_dev_ops adm6996_ops = {
+	.attr_global = {
+			.attr = adm6996_globals,
+			.n_attr = ARRAY_SIZE(adm6996_globals),
+			},
+	.attr_port = {
+		      .attr = adm6996_port,
+		      .n_attr = ARRAY_SIZE(adm6996_port),
+		      },
+	.attr_vlan = {
+		      .attr = adm6996_vlan,
+		      .n_attr = ARRAY_SIZE(adm6996_vlan),
+		      },
+	.get_port_pvid = adm6996_get_pvid,
+	.set_port_pvid = adm6996_set_pvid,
+	.get_vlan_ports = adm6996_get_ports,
+	.set_vlan_ports = adm6996_set_ports,
+	.apply_config = adm6996_hw_apply,
+	.reset_switch = adm6996_reset_switch,
+	.get_port_link = adm6996_get_port_link,
+	.get_port_stats = adm6996_get_port_stats,
+};
+
+static int adm6996_switch_init(struct adm6996_priv *priv, const char *alias, struct net_device *netdev)
+{
+	struct switch_dev *swdev;
+	u16 test, old;
+
+	if (!priv->model) {
+		/* Detect type of chip */
+		old = r16(priv, ADM_VID_CHECK);
+		test = old ^ (1 << 12);
+		w16(priv, ADM_VID_CHECK, test);
+		test ^= r16(priv, ADM_VID_CHECK);
+		if (test & (1 << 12)) {
+			/* 
+			 * Bit 12 of this register is read-only. 
+			 * This is the FC model. 
+			 */
+			priv->model = ADM6996FC;
+		} else {
+			/* Bit 12 is read-write. This is the M model. */
+			priv->model = ADM6996M;
+			w16(priv, ADM_VID_CHECK, old);
+		}
+	}
+
+	swdev = &priv->dev;
+	swdev->name = (adm6996_model_name[priv->model]);
+	swdev->cpu_port = ADM_CPU_PORT;
+	swdev->ports = ADM_NUM_PORTS;
+	swdev->vlans = ADM_NUM_VLANS;
+	swdev->ops = &adm6996_ops;
+	swdev->alias = alias;
+
+	/* The ADM6996L connected through GPIOs does not support any switch
+	   status calls */
+	if (priv->model == ADM6996L) {
+		adm6996_ops.attr_port.n_attr = 0;
+		adm6996_ops.get_port_link = NULL;
+	}
+
+	pr_info ("%s: %s model PHY found.\n", alias, swdev->name);
+
+	mutex_lock(&priv->reg_mutex);
+	adm6996_perform_reset (priv);
+	mutex_unlock(&priv->reg_mutex);
+
+	if (priv->model == ADM6996M || priv->model == ADM6996L) {
+		return register_switch(swdev, netdev);
+	}
+
+	return -ENODEV;
+}
+
+static int adm6996_config_init(struct phy_device *pdev)
+{
+	struct adm6996_priv *priv;
+	int ret;
+
+	linkmode_zero(pdev->supported);
+	linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, pdev->supported);
+	linkmode_copy(pdev->advertising, pdev->supported);
+
+	if (pdev->mdio.addr != 0) {
+		pr_info ("%s: PHY overlaps ADM6996, providing fixed PHY 0x%x.\n"
+				, pdev->attached_dev->name, pdev->mdio.addr);
+		return 0;
+	}
+
+	priv = devm_kzalloc(&pdev->mdio.dev, sizeof(struct adm6996_priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	mutex_init(&priv->reg_mutex);
+	mutex_init(&priv->mib_lock);
+	priv->priv = pdev;
+	priv->read = adm6996_read_mii_reg;
+	priv->write = adm6996_write_mii_reg;
+
+	ret = adm6996_switch_init(priv, pdev->attached_dev->name, pdev->attached_dev);
+	if (ret < 0)
+		return ret;
+
+	pdev->priv = priv;
+
+	return 0;
+}
+
+/*
+ * Warning: phydev->priv is NULL if phydev->mdio.addr != 0
+ */
+static int adm6996_read_status(struct phy_device *phydev)
+{
+	phydev->speed = SPEED_100;
+	phydev->duplex = DUPLEX_FULL;
+	phydev->link = 1;
+
+	phydev->state = PHY_RUNNING;
+	netif_carrier_on(phydev->attached_dev);
+	phydev->adjust_link(phydev->attached_dev);
+
+	return 0;
+}
+
+/*
+ * Warning: phydev->priv is NULL if phydev->mdio.addr != 0
+ */
+static int adm6996_config_aneg(struct phy_device *phydev)
+{
+	return 0;
+}
+
+static int adm6996_fixup(struct phy_device *dev)
+{
+	struct mii_bus *bus = dev->mdio.bus;
+	u16 reg;
+
+	/* Our custom registers are at PHY addresses 0-10. Claim those. */
+	if (dev->mdio.addr > 10)
+		return 0;
+
+	/* look for the switch on the bus */
+	reg = bus->read(bus, PHYADDR(ADM_SIG0)) & ADM_SIG0_MASK;
+	if (reg != ADM_SIG0_VAL)
+		return 0;
+
+	reg = bus->read(bus, PHYADDR(ADM_SIG1)) & ADM_SIG1_MASK;
+	if (reg != ADM_SIG1_VAL)
+		return 0;
+
+	dev->phy_id = (ADM_SIG0_VAL << 16) | ADM_SIG1_VAL;
+
+	return 0;
+}
+
+static int adm6996_probe(struct phy_device *pdev)
+{
+	return 0;
+}
+
+static void adm6996_remove(struct phy_device *pdev)
+{
+	struct adm6996_priv *priv = phy_to_adm(pdev);
+
+	if (priv && (priv->model == ADM6996M || priv->model == ADM6996L))
+		unregister_switch(&priv->dev);
+}
+
+static int adm6996_soft_reset(struct phy_device *phydev)
+{
+	/* we don't need an extra reset */
+	return 0;
+}
+
+static struct phy_driver adm6996_phy_driver = {
+	.name		= "Infineon ADM6996",
+	.phy_id		= (ADM_SIG0_VAL << 16) | ADM_SIG1_VAL,
+	.phy_id_mask	= 0xffffffff,
+	.features	= PHY_BASIC_FEATURES,
+	.probe		= adm6996_probe,
+	.remove		= adm6996_remove,
+	.config_init	= &adm6996_config_init,
+	.config_aneg	= &adm6996_config_aneg,
+	.read_status	= &adm6996_read_status,
+	.soft_reset	= adm6996_soft_reset,
+};
+
+static int adm6996_gpio_probe(struct platform_device *pdev)
+{
+	struct adm6996_gpio_platform_data *pdata = pdev->dev.platform_data;
+	struct adm6996_priv *priv;
+	int ret;
+
+	if (!pdata)
+		return -EINVAL;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(struct adm6996_priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	mutex_init(&priv->reg_mutex);
+	mutex_init(&priv->mib_lock);
+
+	priv->eecs = pdata->eecs;
+	priv->eedi = pdata->eedi;
+	priv->eesk = pdata->eesk;
+
+	priv->model = pdata->model;
+	priv->read = adm6996_read_gpio_reg;
+	priv->write = adm6996_write_gpio_reg;
+
+	ret = devm_gpio_request(&pdev->dev, priv->eecs, "adm_eecs");
+	if (ret)
+		return ret;
+	ret = devm_gpio_request(&pdev->dev, priv->eedi, "adm_eedi");
+	if (ret)
+		return ret;
+	ret = devm_gpio_request(&pdev->dev, priv->eesk, "adm_eesk");
+	if (ret)
+		return ret;
+
+	ret = adm6996_switch_init(priv, dev_name(&pdev->dev), NULL);
+	if (ret < 0)
+		return ret;
+
+	platform_set_drvdata(pdev, priv);
+
+	return 0;
+}
+
+static int adm6996_gpio_remove(struct platform_device *pdev)
+{
+	struct adm6996_priv *priv = platform_get_drvdata(pdev);
+
+	if (priv && (priv->model == ADM6996M || priv->model == ADM6996L))
+		unregister_switch(&priv->dev);
+
+	return 0;
+}
+
+static struct platform_driver adm6996_gpio_driver = {
+	.probe = adm6996_gpio_probe,
+	.remove = adm6996_gpio_remove,
+	.driver = {
+		.name = "adm6996_gpio",
+	},
+};
+
+static int __init adm6996_init(void)
+{
+	int err;
+
+	phy_register_fixup_for_id(PHY_ANY_ID, adm6996_fixup);
+	err = phy_driver_register(&adm6996_phy_driver, THIS_MODULE);
+	if (err)
+		return err;
+
+	err = platform_driver_register(&adm6996_gpio_driver);
+	if (err)
+		phy_driver_unregister(&adm6996_phy_driver);
+
+	return err;
+}
+
+static void __exit adm6996_exit(void)
+{
+	platform_driver_unregister(&adm6996_gpio_driver);
+	phy_driver_unregister(&adm6996_phy_driver);
+}
+
+module_init(adm6996_init);
+module_exit(adm6996_exit);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/adm6996.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/adm6996.h
new file mode 100644
index 0000000..6fd460a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/adm6996.h
@@ -0,0 +1,186 @@
+/*
+ * ADM6996 switch driver
+ *
+ * Copyright (c) 2008 Felix Fietkau <nbd@nbd.name>
+ * Copyright (c) 2010,2011 Peter Lebbing <peter@digitalbrains.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation
+ */
+#ifndef __ADM6996_H
+#define __ADM6996_H
+
+/*
+ * ADM_PHY_PORTS: Number of ports with a PHY.
+ * We only control ports 0 to 3, because if 4 is connected, it is most likely
+ * not connected to the switch but to a separate MII and MAC for the WAN port.
+ */
+#define ADM_PHY_PORTS	4
+#define ADM_NUM_PORTS	6
+#define ADM_CPU_PORT	5
+
+#define ADM_NUM_VLANS 16
+#define ADM_VLAN_MAX_ID 4094
+
+enum admreg {
+	ADM_EEPROM_BASE		= 0x0,
+		ADM_P0_CFG		= ADM_EEPROM_BASE + 1,
+		ADM_P1_CFG		= ADM_EEPROM_BASE + 3,
+		ADM_P2_CFG		= ADM_EEPROM_BASE + 5,
+		ADM_P3_CFG		= ADM_EEPROM_BASE + 7,
+		ADM_P4_CFG		= ADM_EEPROM_BASE + 8,
+		ADM_P5_CFG		= ADM_EEPROM_BASE + 9,
+		ADM_SYSC0		= ADM_EEPROM_BASE + 0xa,
+		ADM_VLAN_PRIOMAP	= ADM_EEPROM_BASE + 0xe,
+		ADM_SYSC3		= ADM_EEPROM_BASE + 0x11,
+		/* Input Force No Tag Enable */
+		ADM_IFNTE		= ADM_EEPROM_BASE + 0x20,
+		ADM_VID_CHECK		= ADM_EEPROM_BASE + 0x26,
+		ADM_P0_PVID		= ADM_EEPROM_BASE + 0x28,
+		ADM_P1_PVID		= ADM_EEPROM_BASE + 0x29,
+		/* Output Tag Bypass Enable and P2 PVID */
+		ADM_OTBE_P2_PVID	= ADM_EEPROM_BASE + 0x2a,
+		ADM_P3_P4_PVID		= ADM_EEPROM_BASE + 0x2b,
+		ADM_P5_PVID		= ADM_EEPROM_BASE + 0x2c,
+	ADM_EEPROM_EXT_BASE	= 0x40,
+#define ADM_VLAN_FILT_L(n) (ADM_EEPROM_EXT_BASE + 2 * (n))
+#define ADM_VLAN_FILT_H(n) (ADM_EEPROM_EXT_BASE + 1 + 2 * (n))
+#define ADM_VLAN_MAP(n) (ADM_EEPROM_BASE + 0x13 + n)
+	ADM_COUNTER_BASE	= 0xa0,
+		ADM_SIG0		= ADM_COUNTER_BASE + 0,
+		ADM_SIG1		= ADM_COUNTER_BASE + 1,
+		ADM_PS0		= ADM_COUNTER_BASE + 2,
+		ADM_PS1		= ADM_COUNTER_BASE + 3,
+		ADM_PS2		= ADM_COUNTER_BASE + 4,
+		ADM_CL0		= ADM_COUNTER_BASE + 8, /* RxPacket */
+		ADM_CL6		= ADM_COUNTER_BASE + 0x1a, /* RxByte */
+		ADM_CL12		= ADM_COUNTER_BASE + 0x2c, /* TxPacket */
+		ADM_CL18		= ADM_COUNTER_BASE + 0x3e, /* TxByte */
+		ADM_CL24		= ADM_COUNTER_BASE + 0x50, /* Coll */
+		ADM_CL30		= ADM_COUNTER_BASE + 0x62, /* Err */
+#define ADM_OFFSET_PORT(n) ((n * 4) - (n / 4) * 2 - (n / 5) * 2)
+	ADM_PHY_BASE		= 0x200,
+#define ADM_PHY_PORT(n) (ADM_PHY_BASE + (0x20 * n))
+};
+
+/* Chip identification patterns */
+#define	ADM_SIG0_MASK	0xffff
+#define ADM_SIG0_VAL	0x1023
+#define ADM_SIG1_MASK	0xffff
+#define ADM_SIG1_VAL	0x0007
+
+enum {
+	ADM_PHYCFG_COLTST     = (1 << 7),	/* Enable collision test */
+	ADM_PHYCFG_DPLX       = (1 << 8),	/* Enable full duplex */
+	ADM_PHYCFG_ANEN_RST   = (1 << 9),	/* Restart auto negotiation (self clear) */
+	ADM_PHYCFG_ISO        = (1 << 10),	/* Isolate PHY */
+	ADM_PHYCFG_PDN        = (1 << 11),	/* Power down PHY */
+	ADM_PHYCFG_ANEN       = (1 << 12),	/* Enable auto negotiation */
+	ADM_PHYCFG_SPEED_100  = (1 << 13),	/* Enable 100 Mbit/s */
+	ADM_PHYCFG_LPBK       = (1 << 14),	/* Enable loopback operation */
+	ADM_PHYCFG_RST        = (1 << 15),	/* Reset the port (self clear) */
+	ADM_PHYCFG_INIT = (
+		ADM_PHYCFG_RST |
+		ADM_PHYCFG_SPEED_100 |
+		ADM_PHYCFG_ANEN |
+		ADM_PHYCFG_ANEN_RST
+	)
+};
+
+enum {
+	ADM_PORTCFG_FC        = (1 << 0),	/* Enable 802.x flow control */
+	ADM_PORTCFG_AN        = (1 << 1),	/* Enable auto-negotiation */
+	ADM_PORTCFG_SPEED_100 = (1 << 2),	/* Enable 100 Mbit/s */
+	ADM_PORTCFG_DPLX      = (1 << 3),	/* Enable full duplex */
+	ADM_PORTCFG_OT        = (1 << 4),	/* Output tagged packets */
+	ADM_PORTCFG_PD        = (1 << 5),	/* Port disable */
+	ADM_PORTCFG_TV_PRIO   = (1 << 6),	/* 0 = VLAN based priority
+	                                 	 * 1 = TOS based priority */
+	ADM_PORTCFG_PPE       = (1 << 7),	/* Port based priority enable */
+	ADM_PORTCFG_PP_S      = (1 << 8),	/* Port based priority, 2 bits */
+	ADM_PORTCFG_PVID_BASE = (1 << 10),	/* Primary VLAN id, 4 bits */
+	ADM_PORTCFG_FSE	      = (1 << 14),	/* Fx select enable */
+	ADM_PORTCFG_CAM       = (1 << 15),	/* Crossover Auto MDIX */
+
+	ADM_PORTCFG_INIT = (
+		ADM_PORTCFG_FC |
+		ADM_PORTCFG_AN |
+		ADM_PORTCFG_SPEED_100 |
+		ADM_PORTCFG_DPLX |
+		ADM_PORTCFG_CAM
+	),
+	ADM_PORTCFG_CPU = (
+		ADM_PORTCFG_FC |
+		ADM_PORTCFG_SPEED_100 |
+		ADM_PORTCFG_OT |
+		ADM_PORTCFG_DPLX
+	),
+};
+
+#define ADM_PORTCFG_PPID(n) ((n & 0x3) << 8)
+#define ADM_PORTCFG_PVID(n) ((n & 0xf) << 10)
+#define ADM_PORTCFG_PVID_MASK (0xf << 10)
+
+#define ADM_IFNTE_MASK (0x3f << 9)
+#define ADM_VID_CHECK_MASK (0x3f << 6)
+
+#define ADM_P0_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0)
+#define ADM_P1_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0)
+#define ADM_P2_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0)
+#define ADM_P3_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0)
+#define ADM_P4_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 8)
+#define ADM_P5_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0)
+#define ADM_P2_PVID_MASK 0xff
+
+#define ADM_OTBE(n) (((n) & 0x3f) << 8)
+#define ADM_OTBE_MASK (0x3f << 8)
+
+/* ADM_SYSC0 */
+enum {
+	ADM_NTTE	= (1 << 2),	/* New Tag Transmit Enable */
+	ADM_RVID1	= (1 << 8)	/* Replace VLAN ID 1 */
+};
+
+/* Tag Based VLAN in ADM_SYSC3 */
+#define ADM_MAC_CLONE	BIT(4)
+#define ADM_TBV		BIT(5)
+
+static const u8 adm_portcfg[] = {
+	[0] = ADM_P0_CFG,
+	[1] = ADM_P1_CFG,
+	[2] = ADM_P2_CFG,
+	[3] = ADM_P3_CFG,
+	[4] = ADM_P4_CFG,
+	[5] = ADM_P5_CFG,
+};
+
+/* Fields in ADM_VLAN_FILT_L(x) */
+#define ADM_VLAN_FILT_FID(n) (((n) & 0xf) << 12)
+#define ADM_VLAN_FILT_TAGGED(n) (((n) & 0x3f) << 6)
+#define ADM_VLAN_FILT_MEMBER(n) (((n) & 0x3f) << 0)
+#define ADM_VLAN_FILT_MEMBER_MASK 0x3f
+/* Fields in ADM_VLAN_FILT_H(x) */
+#define ADM_VLAN_FILT_VALID (1 << 15)
+#define ADM_VLAN_FILT_VID(n) (((n) & 0xfff) << 0)
+
+/* Convert ports to a form for ADM6996L VLAN map */
+#define ADM_VLAN_FILT(ports) ((ports & 0x01) | ((ports & 0x02) << 1) | \
+			((ports & 0x04) << 2) | ((ports & 0x08) << 3) | \
+			((ports & 0x10) << 3) | ((ports & 0x20) << 3))
+
+/* Port status register */
+enum {
+	ADM_PS_LS = (1 << 0),	/* Link status */
+	ADM_PS_SS = (1 << 1),	/* Speed status */
+	ADM_PS_DS = (1 << 2),	/* Duplex status */
+	ADM_PS_FCS = (1 << 3)	/* Flow control status */
+};
+
+/*
+ * Split the register address in phy id and register
+ * it will get combined again by the mdio bus op
+ */
+#define PHYADDR(_reg)	((_reg >> 5) & 0xff), (_reg & 0x1f)
+
+#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/ar8216.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/ar8216.c
new file mode 100644
index 0000000..556c3c8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/ar8216.c
@@ -0,0 +1,2909 @@
+/*
+ * ar8216.c: AR8216 switch driver
+ *
+ * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/if.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/netlink.h>
+#include <linux/of_device.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/bitops.h>
+#include <net/genetlink.h>
+#include <linux/switch.h>
+#include <linux/delay.h>
+#include <linux/phy.h>
+#include <linux/etherdevice.h>
+#include <linux/lockdep.h>
+#include <linux/ar8216_platform.h>
+#include <linux/workqueue.h>
+#include <linux/version.h>
+
+#include "ar8216.h"
+
+extern const struct ar8xxx_chip ar8327_chip;
+extern const struct ar8xxx_chip ar8337_chip;
+
+#define MIB_DESC_BASIC(_s , _o, _n)		\
+	{					\
+		.size = (_s),			\
+		.offset = (_o),			\
+		.name = (_n),			\
+		.type = AR8XXX_MIB_BASIC,	\
+	}
+
+#define MIB_DESC_EXT(_s , _o, _n)		\
+	{					\
+		.size = (_s),			\
+		.offset = (_o),			\
+		.name = (_n),			\
+		.type = AR8XXX_MIB_EXTENDED,	\
+	}
+
+static const struct ar8xxx_mib_desc ar8216_mibs[] = {
+	MIB_DESC_EXT(1, AR8216_STATS_RXBROAD, "RxBroad"),
+	MIB_DESC_EXT(1, AR8216_STATS_RXPAUSE, "RxPause"),
+	MIB_DESC_EXT(1, AR8216_STATS_RXMULTI, "RxMulti"),
+	MIB_DESC_EXT(1, AR8216_STATS_RXFCSERR, "RxFcsErr"),
+	MIB_DESC_EXT(1, AR8216_STATS_RXALIGNERR, "RxAlignErr"),
+	MIB_DESC_EXT(1, AR8216_STATS_RXRUNT, "RxRunt"),
+	MIB_DESC_EXT(1, AR8216_STATS_RXFRAGMENT, "RxFragment"),
+	MIB_DESC_EXT(1, AR8216_STATS_RX64BYTE, "Rx64Byte"),
+	MIB_DESC_EXT(1, AR8216_STATS_RX128BYTE, "Rx128Byte"),
+	MIB_DESC_EXT(1, AR8216_STATS_RX256BYTE, "Rx256Byte"),
+	MIB_DESC_EXT(1, AR8216_STATS_RX512BYTE, "Rx512Byte"),
+	MIB_DESC_EXT(1, AR8216_STATS_RX1024BYTE, "Rx1024Byte"),
+	MIB_DESC_EXT(1, AR8216_STATS_RXMAXBYTE, "RxMaxByte"),
+	MIB_DESC_EXT(1, AR8216_STATS_RXTOOLONG, "RxTooLong"),
+	MIB_DESC_BASIC(2, AR8216_STATS_RXGOODBYTE, "RxGoodByte"),
+	MIB_DESC_EXT(2, AR8216_STATS_RXBADBYTE, "RxBadByte"),
+	MIB_DESC_EXT(1, AR8216_STATS_RXOVERFLOW, "RxOverFlow"),
+	MIB_DESC_EXT(1, AR8216_STATS_FILTERED, "Filtered"),
+	MIB_DESC_EXT(1, AR8216_STATS_TXBROAD, "TxBroad"),
+	MIB_DESC_EXT(1, AR8216_STATS_TXPAUSE, "TxPause"),
+	MIB_DESC_EXT(1, AR8216_STATS_TXMULTI, "TxMulti"),
+	MIB_DESC_EXT(1, AR8216_STATS_TXUNDERRUN, "TxUnderRun"),
+	MIB_DESC_EXT(1, AR8216_STATS_TX64BYTE, "Tx64Byte"),
+	MIB_DESC_EXT(1, AR8216_STATS_TX128BYTE, "Tx128Byte"),
+	MIB_DESC_EXT(1, AR8216_STATS_TX256BYTE, "Tx256Byte"),
+	MIB_DESC_EXT(1, AR8216_STATS_TX512BYTE, "Tx512Byte"),
+	MIB_DESC_EXT(1, AR8216_STATS_TX1024BYTE, "Tx1024Byte"),
+	MIB_DESC_EXT(1, AR8216_STATS_TXMAXBYTE, "TxMaxByte"),
+	MIB_DESC_EXT(1, AR8216_STATS_TXOVERSIZE, "TxOverSize"),
+	MIB_DESC_BASIC(2, AR8216_STATS_TXBYTE, "TxByte"),
+	MIB_DESC_EXT(1, AR8216_STATS_TXCOLLISION, "TxCollision"),
+	MIB_DESC_EXT(1, AR8216_STATS_TXABORTCOL, "TxAbortCol"),
+	MIB_DESC_EXT(1, AR8216_STATS_TXMULTICOL, "TxMultiCol"),
+	MIB_DESC_EXT(1, AR8216_STATS_TXSINGLECOL, "TxSingleCol"),
+	MIB_DESC_EXT(1, AR8216_STATS_TXEXCDEFER, "TxExcDefer"),
+	MIB_DESC_EXT(1, AR8216_STATS_TXDEFER, "TxDefer"),
+	MIB_DESC_EXT(1, AR8216_STATS_TXLATECOL, "TxLateCol"),
+};
+
+const struct ar8xxx_mib_desc ar8236_mibs[39] = {
+	MIB_DESC_EXT(1, AR8236_STATS_RXBROAD, "RxBroad"),
+	MIB_DESC_EXT(1, AR8236_STATS_RXPAUSE, "RxPause"),
+	MIB_DESC_EXT(1, AR8236_STATS_RXMULTI, "RxMulti"),
+	MIB_DESC_EXT(1, AR8236_STATS_RXFCSERR, "RxFcsErr"),
+	MIB_DESC_EXT(1, AR8236_STATS_RXALIGNERR, "RxAlignErr"),
+	MIB_DESC_EXT(1, AR8236_STATS_RXRUNT, "RxRunt"),
+	MIB_DESC_EXT(1, AR8236_STATS_RXFRAGMENT, "RxFragment"),
+	MIB_DESC_EXT(1, AR8236_STATS_RX64BYTE, "Rx64Byte"),
+	MIB_DESC_EXT(1, AR8236_STATS_RX128BYTE, "Rx128Byte"),
+	MIB_DESC_EXT(1, AR8236_STATS_RX256BYTE, "Rx256Byte"),
+	MIB_DESC_EXT(1, AR8236_STATS_RX512BYTE, "Rx512Byte"),
+	MIB_DESC_EXT(1, AR8236_STATS_RX1024BYTE, "Rx1024Byte"),
+	MIB_DESC_EXT(1, AR8236_STATS_RX1518BYTE, "Rx1518Byte"),
+	MIB_DESC_EXT(1, AR8236_STATS_RXMAXBYTE, "RxMaxByte"),
+	MIB_DESC_EXT(1, AR8236_STATS_RXTOOLONG, "RxTooLong"),
+	MIB_DESC_BASIC(2, AR8236_STATS_RXGOODBYTE, "RxGoodByte"),
+	MIB_DESC_EXT(2, AR8236_STATS_RXBADBYTE, "RxBadByte"),
+	MIB_DESC_EXT(1, AR8236_STATS_RXOVERFLOW, "RxOverFlow"),
+	MIB_DESC_EXT(1, AR8236_STATS_FILTERED, "Filtered"),
+	MIB_DESC_EXT(1, AR8236_STATS_TXBROAD, "TxBroad"),
+	MIB_DESC_EXT(1, AR8236_STATS_TXPAUSE, "TxPause"),
+	MIB_DESC_EXT(1, AR8236_STATS_TXMULTI, "TxMulti"),
+	MIB_DESC_EXT(1, AR8236_STATS_TXUNDERRUN, "TxUnderRun"),
+	MIB_DESC_EXT(1, AR8236_STATS_TX64BYTE, "Tx64Byte"),
+	MIB_DESC_EXT(1, AR8236_STATS_TX128BYTE, "Tx128Byte"),
+	MIB_DESC_EXT(1, AR8236_STATS_TX256BYTE, "Tx256Byte"),
+	MIB_DESC_EXT(1, AR8236_STATS_TX512BYTE, "Tx512Byte"),
+	MIB_DESC_EXT(1, AR8236_STATS_TX1024BYTE, "Tx1024Byte"),
+	MIB_DESC_EXT(1, AR8236_STATS_TX1518BYTE, "Tx1518Byte"),
+	MIB_DESC_EXT(1, AR8236_STATS_TXMAXBYTE, "TxMaxByte"),
+	MIB_DESC_EXT(1, AR8236_STATS_TXOVERSIZE, "TxOverSize"),
+	MIB_DESC_BASIC(2, AR8236_STATS_TXBYTE, "TxByte"),
+	MIB_DESC_EXT(1, AR8236_STATS_TXCOLLISION, "TxCollision"),
+	MIB_DESC_EXT(1, AR8236_STATS_TXABORTCOL, "TxAbortCol"),
+	MIB_DESC_EXT(1, AR8236_STATS_TXMULTICOL, "TxMultiCol"),
+	MIB_DESC_EXT(1, AR8236_STATS_TXSINGLECOL, "TxSingleCol"),
+	MIB_DESC_EXT(1, AR8236_STATS_TXEXCDEFER, "TxExcDefer"),
+	MIB_DESC_EXT(1, AR8236_STATS_TXDEFER, "TxDefer"),
+	MIB_DESC_EXT(1, AR8236_STATS_TXLATECOL, "TxLateCol"),
+};
+
+static DEFINE_MUTEX(ar8xxx_dev_list_lock);
+static LIST_HEAD(ar8xxx_dev_list);
+
+static void
+ar8xxx_mib_start(struct ar8xxx_priv *priv);
+static void
+ar8xxx_mib_stop(struct ar8xxx_priv *priv);
+
+/* inspired by phy_poll_reset in drivers/net/phy/phy_device.c */
+static int
+ar8xxx_phy_poll_reset(struct mii_bus *bus)
+{
+        unsigned int sleep_msecs = 20;
+        int ret, elapsed, i;
+
+        for (elapsed = sleep_msecs; elapsed <= 600;
+	     elapsed += sleep_msecs) {
+                msleep(sleep_msecs);
+                for (i = 0; i < AR8XXX_NUM_PHYS; i++) {
+                        ret = mdiobus_read(bus, i, MII_BMCR);
+                        if (ret < 0)
+				return ret;
+                        if (ret & BMCR_RESET)
+				break;
+                        if (i == AR8XXX_NUM_PHYS - 1) {
+                                usleep_range(1000, 2000);
+                                return 0;
+                        }
+                }
+        }
+        return -ETIMEDOUT;
+}
+
+static int
+ar8xxx_phy_check_aneg(struct phy_device *phydev)
+{
+	int ret;
+
+	if (phydev->autoneg != AUTONEG_ENABLE)
+		return 0;
+	/*
+	 * BMCR_ANENABLE might have been cleared
+	 * by phy_init_hw in certain kernel versions
+	 * therefore check for it
+	 */
+	ret = phy_read(phydev, MII_BMCR);
+	if (ret < 0)
+		return ret;
+	if (ret & BMCR_ANENABLE)
+		return 0;
+
+	dev_info(&phydev->mdio.dev, "ANEG disabled, re-enabling ...\n");
+	ret |= BMCR_ANENABLE | BMCR_ANRESTART;
+	return phy_write(phydev, MII_BMCR, ret);
+}
+
+void
+ar8xxx_phy_init(struct ar8xxx_priv *priv)
+{
+	int i;
+	struct mii_bus *bus;
+
+	bus = priv->sw_mii_bus ?: priv->mii_bus;
+	for (i = 0; i < AR8XXX_NUM_PHYS; i++) {
+		if (priv->chip->phy_fixup)
+			priv->chip->phy_fixup(priv, i);
+
+		/* initialize the port itself */
+		mdiobus_write(bus, i, MII_ADVERTISE,
+			ADVERTISE_ALL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
+		if (ar8xxx_has_gige(priv))
+			mdiobus_write(bus, i, MII_CTRL1000, ADVERTISE_1000FULL);
+		mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
+	}
+
+	ar8xxx_phy_poll_reset(bus);
+}
+
+u32
+ar8xxx_mii_read32(struct ar8xxx_priv *priv, int phy_id, int regnum)
+{
+	struct mii_bus *bus = priv->mii_bus;
+	u16 lo, hi;
+
+	lo = bus->read(bus, phy_id, regnum);
+	hi = bus->read(bus, phy_id, regnum + 1);
+
+	return (hi << 16) | lo;
+}
+
+void
+ar8xxx_mii_write32(struct ar8xxx_priv *priv, int phy_id, int regnum, u32 val)
+{
+	struct mii_bus *bus = priv->mii_bus;
+	u16 lo, hi;
+
+	lo = val & 0xffff;
+	hi = (u16) (val >> 16);
+
+	if (priv->chip->mii_lo_first)
+	{
+		bus->write(bus, phy_id, regnum, lo);
+		bus->write(bus, phy_id, regnum + 1, hi);
+	} else {
+		bus->write(bus, phy_id, regnum + 1, hi);
+		bus->write(bus, phy_id, regnum, lo);
+	}
+}
+
+u32
+ar8xxx_read(struct ar8xxx_priv *priv, int reg)
+{
+	struct mii_bus *bus = priv->mii_bus;
+	u16 r1, r2, page;
+	u32 val;
+
+	split_addr((u32) reg, &r1, &r2, &page);
+
+	mutex_lock(&bus->mdio_lock);
+
+	bus->write(bus, 0x18, 0, page);
+	wait_for_page_switch();
+	val = ar8xxx_mii_read32(priv, 0x10 | r2, r1);
+
+	mutex_unlock(&bus->mdio_lock);
+
+	return val;
+}
+
+void
+ar8xxx_write(struct ar8xxx_priv *priv, int reg, u32 val)
+{
+	struct mii_bus *bus = priv->mii_bus;
+	u16 r1, r2, page;
+
+	split_addr((u32) reg, &r1, &r2, &page);
+
+	mutex_lock(&bus->mdio_lock);
+
+	bus->write(bus, 0x18, 0, page);
+	wait_for_page_switch();
+	ar8xxx_mii_write32(priv, 0x10 | r2, r1, val);
+
+	mutex_unlock(&bus->mdio_lock);
+}
+
+u32
+ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val)
+{
+	struct mii_bus *bus = priv->mii_bus;
+	u16 r1, r2, page;
+	u32 ret;
+
+	split_addr((u32) reg, &r1, &r2, &page);
+
+	mutex_lock(&bus->mdio_lock);
+
+	bus->write(bus, 0x18, 0, page);
+	wait_for_page_switch();
+
+	ret = ar8xxx_mii_read32(priv, 0x10 | r2, r1);
+	ret &= ~mask;
+	ret |= val;
+	ar8xxx_mii_write32(priv, 0x10 | r2, r1, ret);
+
+	mutex_unlock(&bus->mdio_lock);
+
+	return ret;
+}
+void
+ar8xxx_phy_dbg_read(struct ar8xxx_priv *priv, int phy_addr,
+           u16 dbg_addr, u16 *dbg_data)
+{
+       struct mii_bus *bus = priv->mii_bus;
+
+       mutex_lock(&bus->mdio_lock);
+       bus->write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr);
+       *dbg_data = bus->read(bus, phy_addr, MII_ATH_DBG_DATA);
+       mutex_unlock(&bus->mdio_lock);
+}
+
+void
+ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr,
+		     u16 dbg_addr, u16 dbg_data)
+{
+	struct mii_bus *bus = priv->mii_bus;
+
+	mutex_lock(&bus->mdio_lock);
+	bus->write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr);
+	bus->write(bus, phy_addr, MII_ATH_DBG_DATA, dbg_data);
+	mutex_unlock(&bus->mdio_lock);
+}
+
+static inline void
+ar8xxx_phy_mmd_prep(struct mii_bus *bus, int phy_addr, u16 addr, u16 reg)
+{
+	bus->write(bus, phy_addr, MII_ATH_MMD_ADDR, addr);
+	bus->write(bus, phy_addr, MII_ATH_MMD_DATA, reg);
+	bus->write(bus, phy_addr, MII_ATH_MMD_ADDR, addr | 0x4000);
+}
+
+void
+ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg, u16 data)
+{
+	struct mii_bus *bus = priv->mii_bus;
+
+	mutex_lock(&bus->mdio_lock);
+	ar8xxx_phy_mmd_prep(bus, phy_addr, addr, reg);
+	bus->write(bus, phy_addr, MII_ATH_MMD_DATA, data);
+	mutex_unlock(&bus->mdio_lock);
+}
+
+u16
+ar8xxx_phy_mmd_read(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg)
+{
+	struct mii_bus *bus = priv->mii_bus;
+	u16 data;
+
+	mutex_lock(&bus->mdio_lock);
+	ar8xxx_phy_mmd_prep(bus, phy_addr, addr, reg);
+	data = bus->read(bus, phy_addr, MII_ATH_MMD_DATA);
+	mutex_unlock(&bus->mdio_lock);
+
+	return data;
+}
+
+static int
+ar8xxx_reg_wait(struct ar8xxx_priv *priv, u32 reg, u32 mask, u32 val,
+		unsigned timeout)
+{
+	int i;
+
+	for (i = 0; i < timeout; i++) {
+		u32 t;
+
+		t = ar8xxx_read(priv, reg);
+		if ((t & mask) == val)
+			return 0;
+
+		usleep_range(1000, 2000);
+		cond_resched();
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int
+ar8xxx_mib_op(struct ar8xxx_priv *priv, u32 op)
+{
+	unsigned mib_func = priv->chip->mib_func;
+	int ret;
+
+	lockdep_assert_held(&priv->mib_lock);
+
+	/* Capture the hardware statistics for all ports */
+	ar8xxx_rmw(priv, mib_func, AR8216_MIB_FUNC, (op << AR8216_MIB_FUNC_S));
+
+	/* Wait for the capturing to complete. */
+	ret = ar8xxx_reg_wait(priv, mib_func, AR8216_MIB_BUSY, 0, 10);
+	if (ret)
+		goto out;
+
+	ret = 0;
+
+out:
+	return ret;
+}
+
+static int
+ar8xxx_mib_capture(struct ar8xxx_priv *priv)
+{
+	return ar8xxx_mib_op(priv, AR8216_MIB_FUNC_CAPTURE);
+}
+
+static int
+ar8xxx_mib_flush(struct ar8xxx_priv *priv)
+{
+	return ar8xxx_mib_op(priv, AR8216_MIB_FUNC_FLUSH);
+}
+
+static void
+ar8xxx_mib_fetch_port_stat(struct ar8xxx_priv *priv, int port, bool flush)
+{
+	unsigned int base;
+	u64 *mib_stats;
+	int i;
+
+	WARN_ON(port >= priv->dev.ports);
+
+	lockdep_assert_held(&priv->mib_lock);
+
+	base = priv->chip->reg_port_stats_start +
+	       priv->chip->reg_port_stats_length * port;
+
+	mib_stats = &priv->mib_stats[port * priv->chip->num_mibs];
+	for (i = 0; i < priv->chip->num_mibs; i++) {
+		const struct ar8xxx_mib_desc *mib;
+		u64 t;
+
+		mib = &priv->chip->mib_decs[i];
+		if (mib->type > priv->mib_type)
+			continue;
+		t = ar8xxx_read(priv, base + mib->offset);
+		if (mib->size == 2) {
+			u64 hi;
+
+			hi = ar8xxx_read(priv, base + mib->offset + 4);
+			t |= hi << 32;
+		}
+
+		if (flush)
+			mib_stats[i] = 0;
+		else
+			mib_stats[i] += t;
+		cond_resched();
+	}
+}
+
+static void
+ar8216_read_port_link(struct ar8xxx_priv *priv, int port,
+		      struct switch_port_link *link)
+{
+	u32 status;
+	u32 speed;
+
+	memset(link, '\0', sizeof(*link));
+
+	status = priv->chip->read_port_status(priv, port);
+
+	link->aneg = !!(status & AR8216_PORT_STATUS_LINK_AUTO);
+	if (link->aneg) {
+		link->link = !!(status & AR8216_PORT_STATUS_LINK_UP);
+	} else {
+		link->link = true;
+
+		if (priv->get_port_link) {
+			int err;
+
+			err = priv->get_port_link(port);
+			if (err >= 0)
+				link->link = !!err;
+		}
+	}
+
+	if (!link->link)
+		return;
+
+	link->duplex = !!(status & AR8216_PORT_STATUS_DUPLEX);
+	link->tx_flow = !!(status & AR8216_PORT_STATUS_TXFLOW);
+	link->rx_flow = !!(status & AR8216_PORT_STATUS_RXFLOW);
+
+	if (link->aneg && link->duplex && priv->chip->read_port_eee_status)
+		link->eee = priv->chip->read_port_eee_status(priv, port);
+
+	speed = (status & AR8216_PORT_STATUS_SPEED) >>
+		 AR8216_PORT_STATUS_SPEED_S;
+
+	switch (speed) {
+	case AR8216_PORT_SPEED_10M:
+		link->speed = SWITCH_PORT_SPEED_10;
+		break;
+	case AR8216_PORT_SPEED_100M:
+		link->speed = SWITCH_PORT_SPEED_100;
+		break;
+	case AR8216_PORT_SPEED_1000M:
+		link->speed = SWITCH_PORT_SPEED_1000;
+		break;
+	default:
+		link->speed = SWITCH_PORT_SPEED_UNKNOWN;
+		break;
+	}
+}
+
+static struct sk_buff *
+ar8216_mangle_tx(struct net_device *dev, struct sk_buff *skb)
+{
+	struct ar8xxx_priv *priv = dev->phy_ptr;
+	unsigned char *buf;
+
+	if (unlikely(!priv))
+		goto error;
+
+	if (!priv->vlan)
+		goto send;
+
+	if (unlikely(skb_headroom(skb) < 2)) {
+		if (pskb_expand_head(skb, 2, 0, GFP_ATOMIC) < 0)
+			goto error;
+	}
+
+	buf = skb_push(skb, 2);
+	buf[0] = 0x10;
+	buf[1] = 0x80;
+
+send:
+	return skb;
+
+error:
+	dev_kfree_skb_any(skb);
+	return NULL;
+}
+
+static void
+ar8216_mangle_rx(struct net_device *dev, struct sk_buff *skb)
+{
+	struct ar8xxx_priv *priv;
+	unsigned char *buf;
+	int port, vlan;
+
+	priv = dev->phy_ptr;
+	if (!priv)
+		return;
+
+	/* don't strip the header if vlan mode is disabled */
+	if (!priv->vlan)
+		return;
+
+	/* strip header, get vlan id */
+	buf = skb->data;
+	skb_pull(skb, 2);
+
+	/* check for vlan header presence */
+	if ((buf[12 + 2] != 0x81) || (buf[13 + 2] != 0x00))
+		return;
+
+	port = buf[0] & 0x7;
+
+	/* no need to fix up packets coming from a tagged source */
+	if (priv->vlan_tagged & (1 << port))
+		return;
+
+	/* lookup port vid from local table, the switch passes an invalid vlan id */
+	vlan = priv->vlan_id[priv->pvid[port]];
+
+	buf[14 + 2] &= 0xf0;
+	buf[14 + 2] |= vlan >> 8;
+	buf[15 + 2] = vlan & 0xff;
+}
+
+int
+ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val)
+{
+	int timeout = 20;
+	u32 t = 0;
+
+	while (1) {
+		t = ar8xxx_read(priv, reg);
+		if ((t & mask) == val)
+			return 0;
+
+		if (timeout-- <= 0)
+			break;
+
+		udelay(10);
+		cond_resched();
+	}
+
+	pr_err("ar8216: timeout on reg %08x: %08x & %08x != %08x\n",
+	       (unsigned int) reg, t, mask, val);
+	return -ETIMEDOUT;
+}
+
+static void
+ar8216_vtu_op(struct ar8xxx_priv *priv, u32 op, u32 val)
+{
+	if (ar8216_wait_bit(priv, AR8216_REG_VTU, AR8216_VTU_ACTIVE, 0))
+		return;
+	if ((op & AR8216_VTU_OP) == AR8216_VTU_OP_LOAD) {
+		val &= AR8216_VTUDATA_MEMBER;
+		val |= AR8216_VTUDATA_VALID;
+		ar8xxx_write(priv, AR8216_REG_VTU_DATA, val);
+	}
+	op |= AR8216_VTU_ACTIVE;
+	ar8xxx_write(priv, AR8216_REG_VTU, op);
+}
+
+static void
+ar8216_vtu_flush(struct ar8xxx_priv *priv)
+{
+	ar8216_vtu_op(priv, AR8216_VTU_OP_FLUSH, 0);
+}
+
+static void
+ar8216_vtu_load_vlan(struct ar8xxx_priv *priv, u32 vid, u32 port_mask)
+{
+	u32 op;
+
+	op = AR8216_VTU_OP_LOAD | (vid << AR8216_VTU_VID_S);
+	ar8216_vtu_op(priv, op, port_mask);
+}
+
+static int
+ar8216_atu_flush(struct ar8xxx_priv *priv)
+{
+	int ret;
+
+	ret = ar8216_wait_bit(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_ACTIVE, 0);
+	if (!ret)
+		ar8xxx_write(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_OP_FLUSH |
+							 AR8216_ATU_ACTIVE);
+
+	return ret;
+}
+
+static int
+ar8216_atu_flush_port(struct ar8xxx_priv *priv, int port)
+{
+	u32 t;
+	int ret;
+
+	ret = ar8216_wait_bit(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_ACTIVE, 0);
+	if (!ret) {
+		t = (port << AR8216_ATU_PORT_NUM_S) | AR8216_ATU_OP_FLUSH_PORT;
+		t |= AR8216_ATU_ACTIVE;
+		ar8xxx_write(priv, AR8216_REG_ATU_FUNC0, t);
+	}
+
+	return ret;
+}
+
+static u32
+ar8216_read_port_status(struct ar8xxx_priv *priv, int port)
+{
+	return ar8xxx_read(priv, AR8216_REG_PORT_STATUS(port));
+}
+
+static void
+__ar8216_setup_port(struct ar8xxx_priv *priv, int port, u32 members,
+		    bool ath_hdr_en)
+{
+	u32 header;
+	u32 egress, ingress;
+	u32 pvid;
+
+	if (priv->vlan) {
+		pvid = priv->vlan_id[priv->pvid[port]];
+		if (priv->vlan_tagged & (1 << port))
+			egress = AR8216_OUT_ADD_VLAN;
+		else
+			egress = AR8216_OUT_STRIP_VLAN;
+		ingress = AR8216_IN_SECURE;
+	} else {
+		pvid = port;
+		egress = AR8216_OUT_KEEP;
+		ingress = AR8216_IN_PORT_ONLY;
+	}
+
+	header = ath_hdr_en ? AR8216_PORT_CTRL_HEADER : 0;
+
+	ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port),
+		   AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE |
+		   AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE |
+		   AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK,
+		   AR8216_PORT_CTRL_LEARN | header |
+		   (egress << AR8216_PORT_CTRL_VLAN_MODE_S) |
+		   (AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S));
+
+	ar8xxx_rmw(priv, AR8216_REG_PORT_VLAN(port),
+		   AR8216_PORT_VLAN_DEST_PORTS | AR8216_PORT_VLAN_MODE |
+		   AR8216_PORT_VLAN_DEFAULT_ID,
+		   (members << AR8216_PORT_VLAN_DEST_PORTS_S) |
+		   (ingress << AR8216_PORT_VLAN_MODE_S) |
+		   (pvid << AR8216_PORT_VLAN_DEFAULT_ID_S));
+}
+
+static void
+ar8216_setup_port(struct ar8xxx_priv *priv, int port, u32 members)
+{
+	return __ar8216_setup_port(priv, port, members,
+				   chip_is_ar8216(priv) && priv->vlan &&
+				   port == AR8216_PORT_CPU);
+}
+
+static int
+ar8216_hw_init(struct ar8xxx_priv *priv)
+{
+	if (priv->initialized)
+		return 0;
+
+	ar8xxx_write(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET);
+	ar8xxx_reg_wait(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET, 0, 1000);
+
+	ar8xxx_phy_init(priv);
+
+	priv->initialized = true;
+	return 0;
+}
+
+static void
+ar8216_init_globals(struct ar8xxx_priv *priv)
+{
+	/* standard atheros magic */
+	ar8xxx_write(priv, 0x38, 0xc000050e);
+
+	ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL,
+		   AR8216_GCTRL_MTU, 1518 + 8 + 2);
+}
+
+static void
+__ar8216_init_port(struct ar8xxx_priv *priv, int port,
+		   bool cpu_ge, bool flow_en)
+{
+	/* Enable port learning and tx */
+	ar8xxx_write(priv, AR8216_REG_PORT_CTRL(port),
+		AR8216_PORT_CTRL_LEARN |
+		(4 << AR8216_PORT_CTRL_STATE_S));
+
+	ar8xxx_write(priv, AR8216_REG_PORT_VLAN(port), 0);
+
+	if (port == AR8216_PORT_CPU) {
+		ar8xxx_write(priv, AR8216_REG_PORT_STATUS(port),
+			AR8216_PORT_STATUS_LINK_UP |
+			(cpu_ge ? AR8216_PORT_SPEED_1000M : AR8216_PORT_SPEED_100M) |
+			AR8216_PORT_STATUS_TXMAC |
+			AR8216_PORT_STATUS_RXMAC |
+			(flow_en ? AR8216_PORT_STATUS_RXFLOW : 0) |
+			(flow_en ? AR8216_PORT_STATUS_TXFLOW : 0) |
+			AR8216_PORT_STATUS_DUPLEX);
+	} else {
+		ar8xxx_write(priv, AR8216_REG_PORT_STATUS(port),
+			AR8216_PORT_STATUS_LINK_AUTO);
+	}
+}
+
+static void
+ar8216_init_port(struct ar8xxx_priv *priv, int port)
+{
+	__ar8216_init_port(priv, port, ar8xxx_has_gige(priv),
+			   chip_is_ar8316(priv));
+}
+
+static void
+ar8216_wait_atu_ready(struct ar8xxx_priv *priv, u16 r2, u16 r1)
+{
+	int timeout = 20;
+
+	while (ar8xxx_mii_read32(priv, r2, r1) & AR8216_ATU_ACTIVE && --timeout) {
+		udelay(10);
+		cond_resched();
+	}
+
+	if (!timeout)
+		pr_err("ar8216: timeout waiting for atu to become ready\n");
+}
+
+static void ar8216_get_arl_entry(struct ar8xxx_priv *priv,
+				 struct arl_entry *a, u32 *status, enum arl_op op)
+{
+	struct mii_bus *bus = priv->mii_bus;
+	u16 r2, page;
+	u16 r1_func0, r1_func1, r1_func2;
+	u32 t, val0, val1, val2;
+
+	split_addr(AR8216_REG_ATU_FUNC0, &r1_func0, &r2, &page);
+	r2 |= 0x10;
+
+	r1_func1 = (AR8216_REG_ATU_FUNC1 >> 1) & 0x1e;
+	r1_func2 = (AR8216_REG_ATU_FUNC2 >> 1) & 0x1e;
+
+	switch (op) {
+	case AR8XXX_ARL_INITIALIZE:
+		/* all ATU registers are on the same page
+		* therefore set page only once
+		*/
+		bus->write(bus, 0x18, 0, page);
+		wait_for_page_switch();
+
+		ar8216_wait_atu_ready(priv, r2, r1_func0);
+
+		ar8xxx_mii_write32(priv, r2, r1_func0, AR8216_ATU_OP_GET_NEXT);
+		ar8xxx_mii_write32(priv, r2, r1_func1, 0);
+		ar8xxx_mii_write32(priv, r2, r1_func2, 0);
+		break;
+	case AR8XXX_ARL_GET_NEXT:
+		t = ar8xxx_mii_read32(priv, r2, r1_func0);
+		t |= AR8216_ATU_ACTIVE;
+		ar8xxx_mii_write32(priv, r2, r1_func0, t);
+		ar8216_wait_atu_ready(priv, r2, r1_func0);
+
+		val0 = ar8xxx_mii_read32(priv, r2, r1_func0);
+		val1 = ar8xxx_mii_read32(priv, r2, r1_func1);
+		val2 = ar8xxx_mii_read32(priv, r2, r1_func2);
+
+		*status = (val2 & AR8216_ATU_STATUS) >> AR8216_ATU_STATUS_S;
+		if (!*status)
+			break;
+
+		a->portmap = (val2 & AR8216_ATU_PORTS) >> AR8216_ATU_PORTS_S;
+		a->mac[0] = (val0 & AR8216_ATU_ADDR5) >> AR8216_ATU_ADDR5_S;
+		a->mac[1] = (val0 & AR8216_ATU_ADDR4) >> AR8216_ATU_ADDR4_S;
+		a->mac[2] = (val1 & AR8216_ATU_ADDR3) >> AR8216_ATU_ADDR3_S;
+		a->mac[3] = (val1 & AR8216_ATU_ADDR2) >> AR8216_ATU_ADDR2_S;
+		a->mac[4] = (val1 & AR8216_ATU_ADDR1) >> AR8216_ATU_ADDR1_S;
+		a->mac[5] = (val1 & AR8216_ATU_ADDR0) >> AR8216_ATU_ADDR0_S;
+		break;
+	}
+}
+
+static int
+ar8216_phy_read(struct ar8xxx_priv *priv, int addr, int regnum)
+{
+	u32 t, val = 0xffff;
+	int err;
+
+	if (addr >= AR8216_NUM_PORTS)
+		return 0xffff;
+	t = (regnum << AR8216_MDIO_CTRL_REG_ADDR_S) |
+	    (addr << AR8216_MDIO_CTRL_PHY_ADDR_S) |
+	    AR8216_MDIO_CTRL_MASTER_EN |
+	    AR8216_MDIO_CTRL_BUSY |
+	    AR8216_MDIO_CTRL_CMD_READ;
+
+	ar8xxx_write(priv, AR8216_REG_MDIO_CTRL, t);
+	err = ar8xxx_reg_wait(priv, AR8216_REG_MDIO_CTRL,
+			      AR8216_MDIO_CTRL_BUSY, 0, 5);
+	if (!err)
+		val = ar8xxx_read(priv, AR8216_REG_MDIO_CTRL);
+
+	return val & AR8216_MDIO_CTRL_DATA_M;
+}
+
+static int
+ar8216_phy_write(struct ar8xxx_priv *priv, int addr, int regnum, u16 val)
+{
+	u32 t;
+	int ret;
+
+	if (addr >= AR8216_NUM_PORTS)
+		return -EINVAL;
+
+	t = (addr << AR8216_MDIO_CTRL_PHY_ADDR_S) |
+	    (regnum << AR8216_MDIO_CTRL_REG_ADDR_S) |
+	    AR8216_MDIO_CTRL_MASTER_EN |
+	    AR8216_MDIO_CTRL_BUSY |
+	    AR8216_MDIO_CTRL_CMD_WRITE |
+	    val;
+
+	ar8xxx_write(priv, AR8216_REG_MDIO_CTRL, t);
+	ret = ar8xxx_reg_wait(priv, AR8216_REG_MDIO_CTRL,
+			      AR8216_MDIO_CTRL_BUSY, 0, 5);
+
+	return ret;
+}
+
+static int
+ar8229_hw_init(struct ar8xxx_priv *priv)
+{
+	int phy_if_mode;
+
+	if (priv->initialized)
+		return 0;
+
+	ar8xxx_write(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET);
+	ar8xxx_reg_wait(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET, 0, 1000);
+
+	phy_if_mode = of_get_phy_mode(priv->pdev->of_node);
+
+	if (phy_if_mode == PHY_INTERFACE_MODE_GMII) {
+		ar8xxx_write(priv, AR8229_REG_OPER_MODE0,
+				 AR8229_OPER_MODE0_MAC_GMII_EN);
+	} else if (phy_if_mode == PHY_INTERFACE_MODE_MII) {
+		ar8xxx_write(priv, AR8229_REG_OPER_MODE0,
+				 AR8229_OPER_MODE0_PHY_MII_EN);
+	} else {
+		pr_err("ar8229: unsupported mii mode\n");
+		return -EINVAL;
+	}
+
+	if (priv->port4_phy) {
+		ar8xxx_write(priv, AR8229_REG_OPER_MODE1,
+			     AR8229_REG_OPER_MODE1_PHY4_MII_EN);
+		/* disable port5 to prevent mii conflict */
+		ar8xxx_write(priv, AR8216_REG_PORT_STATUS(5), 0);
+	}
+
+	ar8xxx_phy_init(priv);
+
+	priv->initialized = true;
+	return 0;
+}
+
+static void
+ar8229_init_globals(struct ar8xxx_priv *priv)
+{
+
+	/* Enable CPU port, and disable mirror port */
+	ar8xxx_write(priv, AR8216_REG_GLOBAL_CPUPORT,
+		     AR8216_GLOBAL_CPUPORT_EN |
+		     (15 << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S));
+
+	/* Setup TAG priority mapping */
+	ar8xxx_write(priv, AR8216_REG_TAG_PRIORITY, 0xfa50);
+
+	/* Enable aging, MAC replacing */
+	ar8xxx_write(priv, AR8216_REG_ATU_CTRL,
+		     0x2b /* 5 min age time */ |
+		     AR8216_ATU_CTRL_AGE_EN |
+		     AR8216_ATU_CTRL_LEARN_CHANGE);
+
+	/* Enable ARP frame acknowledge */
+	ar8xxx_reg_set(priv, AR8229_REG_QM_CTRL,
+		       AR8229_QM_CTRL_ARP_EN);
+
+	/*
+	 * Enable Broadcast/unknown multicast and unicast frames
+	 * transmitted to the CPU port.
+	 */
+	ar8xxx_reg_set(priv, AR8216_REG_FLOOD_MASK,
+		       AR8229_FLOOD_MASK_BC_DP(0) |
+		       AR8229_FLOOD_MASK_MC_DP(0) |
+		       AR8229_FLOOD_MASK_UC_DP(0));
+
+	/* setup MTU */
+	ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL,
+		   AR8236_GCTRL_MTU, AR8236_GCTRL_MTU);
+
+	/* Enable MIB counters */
+	ar8xxx_reg_set(priv, AR8216_REG_MIB_FUNC,
+		       AR8236_MIB_EN);
+
+	/* setup Service TAG */
+	ar8xxx_rmw(priv, AR8216_REG_SERVICE_TAG, AR8216_SERVICE_TAG_M, 0);
+}
+
+static void
+ar8229_init_port(struct ar8xxx_priv *priv, int port)
+{
+	__ar8216_init_port(priv, port, true, true);
+}
+
+
+static int
+ar7240sw_hw_init(struct ar8xxx_priv *priv)
+{
+	if (priv->initialized)
+		return 0;
+
+	ar8xxx_write(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET);
+	ar8xxx_reg_wait(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET, 0, 1000);
+
+	priv->port4_phy = 1;
+	/* disable port5 to prevent mii conflict */
+	ar8xxx_write(priv, AR8216_REG_PORT_STATUS(5), 0);
+
+	ar8xxx_phy_init(priv);
+
+	priv->initialized = true;
+	return 0;
+}
+
+static void
+ar7240sw_init_globals(struct ar8xxx_priv *priv)
+{
+
+	/* Enable CPU port, and disable mirror port */
+	ar8xxx_write(priv, AR8216_REG_GLOBAL_CPUPORT,
+		     AR8216_GLOBAL_CPUPORT_EN |
+		     (15 << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S));
+
+	/* Setup TAG priority mapping */
+	ar8xxx_write(priv, AR8216_REG_TAG_PRIORITY, 0xfa50);
+
+	/* Enable ARP frame acknowledge, aging, MAC replacing */
+	ar8xxx_write(priv, AR8216_REG_ATU_CTRL,
+		AR8216_ATU_CTRL_RESERVED |
+		0x2b /* 5 min age time */ |
+		AR8216_ATU_CTRL_AGE_EN |
+		AR8216_ATU_CTRL_ARP_EN |
+		AR8216_ATU_CTRL_LEARN_CHANGE);
+
+	/* Enable Broadcast frames transmitted to the CPU */
+	ar8xxx_reg_set(priv, AR8216_REG_FLOOD_MASK,
+		       AR8216_FM_CPU_BROADCAST_EN);
+
+	/* setup MTU */
+	ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL,
+		   AR8216_GCTRL_MTU,
+		   AR8216_GCTRL_MTU);
+
+	/* setup Service TAG */
+	ar8xxx_rmw(priv, AR8216_REG_SERVICE_TAG, AR8216_SERVICE_TAG_M, 0);
+}
+
+static void
+ar7240sw_setup_port(struct ar8xxx_priv *priv, int port, u32 members)
+{
+	return __ar8216_setup_port(priv, port, members, false);
+}
+
+static void
+ar8236_setup_port(struct ar8xxx_priv *priv, int port, u32 members)
+{
+	u32 egress, ingress;
+	u32 pvid;
+
+	if (priv->vlan) {
+		pvid = priv->vlan_id[priv->pvid[port]];
+		if (priv->vlan_tagged & (1 << port))
+			egress = AR8216_OUT_ADD_VLAN;
+		else
+			egress = AR8216_OUT_STRIP_VLAN;
+		ingress = AR8216_IN_SECURE;
+	} else {
+		pvid = port;
+		egress = AR8216_OUT_KEEP;
+		ingress = AR8216_IN_PORT_ONLY;
+	}
+
+	ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port),
+		   AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE |
+		   AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE |
+		   AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK,
+		   AR8216_PORT_CTRL_LEARN |
+		   (egress << AR8216_PORT_CTRL_VLAN_MODE_S) |
+		   (AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S));
+
+	ar8xxx_rmw(priv, AR8236_REG_PORT_VLAN(port),
+		   AR8236_PORT_VLAN_DEFAULT_ID,
+		   (pvid << AR8236_PORT_VLAN_DEFAULT_ID_S));
+
+	ar8xxx_rmw(priv, AR8236_REG_PORT_VLAN2(port),
+		   AR8236_PORT_VLAN2_VLAN_MODE |
+		   AR8236_PORT_VLAN2_MEMBER,
+		   (ingress << AR8236_PORT_VLAN2_VLAN_MODE_S) |
+		   (members << AR8236_PORT_VLAN2_MEMBER_S));
+}
+
+static void
+ar8236_init_globals(struct ar8xxx_priv *priv)
+{
+	/* enable jumbo frames */
+	ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL,
+		   AR8316_GCTRL_MTU, 9018 + 8 + 2);
+
+	/* enable cpu port to receive arp frames */
+	ar8xxx_reg_set(priv, AR8216_REG_ATU_CTRL,
+		   AR8236_ATU_CTRL_RES);
+
+	/*
+	 * Enable Broadcast/unknown multicast and unicast frames
+	 * transmitted to the CPU port.
+	 */
+	ar8xxx_reg_set(priv, AR8216_REG_FLOOD_MASK,
+		       AR8229_FLOOD_MASK_BC_DP(0) |
+		       AR8229_FLOOD_MASK_MC_DP(0) |
+		       AR8229_FLOOD_MASK_UC_DP(0));
+
+	/* Enable MIB counters */
+	ar8xxx_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN,
+		   (AR8216_MIB_FUNC_NO_OP << AR8216_MIB_FUNC_S) |
+		   AR8236_MIB_EN);
+}
+
+static int
+ar8316_hw_init(struct ar8xxx_priv *priv)
+{
+	u32 val, newval;
+
+	val = ar8xxx_read(priv, AR8316_REG_POSTRIP);
+
+	if (priv->phy->interface == PHY_INTERFACE_MODE_RGMII) {
+		if (priv->port4_phy) {
+			/* value taken from Ubiquiti RouterStation Pro */
+			newval = 0x81461bea;
+			pr_info("ar8316: Using port 4 as PHY\n");
+		} else {
+			newval = 0x01261be2;
+			pr_info("ar8316: Using port 4 as switch port\n");
+		}
+	} else if (priv->phy->interface == PHY_INTERFACE_MODE_GMII) {
+		/* value taken from AVM Fritz!Box 7390 sources */
+		newval = 0x010e5b71;
+	} else {
+		/* no known value for phy interface */
+		pr_err("ar8316: unsupported mii mode: %d.\n",
+		       priv->phy->interface);
+		return -EINVAL;
+	}
+
+	if (val == newval)
+		goto out;
+
+	ar8xxx_write(priv, AR8316_REG_POSTRIP, newval);
+
+	if (priv->port4_phy &&
+	    priv->phy->interface == PHY_INTERFACE_MODE_RGMII) {
+		/* work around for phy4 rgmii mode */
+		ar8xxx_phy_dbg_write(priv, 4, 0x12, 0x480c);
+		/* rx delay */
+		ar8xxx_phy_dbg_write(priv, 4, 0x0, 0x824e);
+		/* tx delay */
+		ar8xxx_phy_dbg_write(priv, 4, 0x5, 0x3d47);
+		msleep(1000);
+	}
+
+	ar8xxx_phy_init(priv);
+
+out:
+	priv->initialized = true;
+	return 0;
+}
+
+static void
+ar8316_init_globals(struct ar8xxx_priv *priv)
+{
+	/* standard atheros magic */
+	ar8xxx_write(priv, 0x38, 0xc000050e);
+
+	/* enable cpu port to receive multicast and broadcast frames */
+	ar8xxx_write(priv, AR8216_REG_FLOOD_MASK, 0x003f003f);
+
+	/* enable jumbo frames */
+	ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL,
+		   AR8316_GCTRL_MTU, 9018 + 8 + 2);
+
+	/* Enable MIB counters */
+	ar8xxx_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN,
+		   (AR8216_MIB_FUNC_NO_OP << AR8216_MIB_FUNC_S) |
+		   AR8236_MIB_EN);
+}
+
+int
+ar8xxx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr,
+		   struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	priv->vlan = !!val->value.i;
+	return 0;
+}
+
+int
+ar8xxx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr,
+		   struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	val->value.i = priv->vlan;
+	return 0;
+}
+
+
+int
+ar8xxx_sw_set_pvid(struct switch_dev *dev, int port, int vlan)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	/* make sure no invalid PVIDs get set */
+
+	if (vlan < 0 || vlan >= dev->vlans ||
+	    port < 0 || port >= AR8X16_MAX_PORTS)
+		return -EINVAL;
+
+	priv->pvid[port] = vlan;
+	return 0;
+}
+
+int
+ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	if (port < 0 || port >= AR8X16_MAX_PORTS)
+		return -EINVAL;
+
+	*vlan = priv->pvid[port];
+	return 0;
+}
+
+static int
+ar8xxx_sw_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
+		  struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	if (val->port_vlan >= dev->vlans)
+		return -EINVAL;
+
+	priv->vlan_id[val->port_vlan] = val->value.i;
+	return 0;
+}
+
+static int
+ar8xxx_sw_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
+		  struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	val->value.i = priv->vlan_id[val->port_vlan];
+	return 0;
+}
+
+int
+ar8xxx_sw_get_port_link(struct switch_dev *dev, int port,
+			struct switch_port_link *link)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	ar8216_read_port_link(priv, port, link);
+	return 0;
+}
+
+static int
+ar8xxx_sw_get_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	u8 ports;
+	int i;
+
+	if (val->port_vlan >= dev->vlans)
+		return -EINVAL;
+
+	ports = priv->vlan_table[val->port_vlan];
+	val->len = 0;
+	for (i = 0; i < dev->ports; i++) {
+		struct switch_port *p;
+
+		if (!(ports & (1 << i)))
+			continue;
+
+		p = &val->value.ports[val->len++];
+		p->id = i;
+		if (priv->vlan_tagged & (1 << i))
+			p->flags = (1 << SWITCH_PORT_FLAG_TAGGED);
+		else
+			p->flags = 0;
+	}
+	return 0;
+}
+
+static int
+ar8xxx_sw_set_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	u8 *vt = &priv->vlan_table[val->port_vlan];
+	int i, j;
+
+	*vt = 0;
+	for (i = 0; i < val->len; i++) {
+		struct switch_port *p = &val->value.ports[i];
+
+		if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) {
+			priv->vlan_tagged |= (1 << p->id);
+		} else {
+			priv->vlan_tagged &= ~(1 << p->id);
+			priv->pvid[p->id] = val->port_vlan;
+
+			/* make sure that an untagged port does not
+			 * appear in other vlans */
+			for (j = 0; j < dev->vlans; j++) {
+				if (j == val->port_vlan)
+					continue;
+				priv->vlan_table[j] &= ~(1 << p->id);
+			}
+		}
+
+		*vt |= 1 << p->id;
+	}
+	return 0;
+}
+
+static void
+ar8216_set_mirror_regs(struct ar8xxx_priv *priv)
+{
+	int port;
+
+	/* reset all mirror registers */
+	ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT,
+		   AR8216_GLOBAL_CPUPORT_MIRROR_PORT,
+		   (0xF << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S));
+	for (port = 0; port < AR8216_NUM_PORTS; port++) {
+		ar8xxx_reg_clear(priv, AR8216_REG_PORT_CTRL(port),
+			   AR8216_PORT_CTRL_MIRROR_RX);
+
+		ar8xxx_reg_clear(priv, AR8216_REG_PORT_CTRL(port),
+			   AR8216_PORT_CTRL_MIRROR_TX);
+	}
+
+	/* now enable mirroring if necessary */
+	if (priv->source_port >= AR8216_NUM_PORTS ||
+	    priv->monitor_port >= AR8216_NUM_PORTS ||
+	    priv->source_port == priv->monitor_port) {
+		return;
+	}
+
+	ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT,
+		   AR8216_GLOBAL_CPUPORT_MIRROR_PORT,
+		   (priv->monitor_port << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S));
+
+	if (priv->mirror_rx)
+		ar8xxx_reg_set(priv, AR8216_REG_PORT_CTRL(priv->source_port),
+			   AR8216_PORT_CTRL_MIRROR_RX);
+
+	if (priv->mirror_tx)
+		ar8xxx_reg_set(priv, AR8216_REG_PORT_CTRL(priv->source_port),
+			   AR8216_PORT_CTRL_MIRROR_TX);
+}
+
+static inline u32
+ar8xxx_age_time_val(int age_time)
+{
+	return (age_time + AR8XXX_REG_ARL_CTRL_AGE_TIME_SECS / 2) /
+	       AR8XXX_REG_ARL_CTRL_AGE_TIME_SECS;
+}
+
+static inline void
+ar8xxx_set_age_time(struct ar8xxx_priv *priv, int reg)
+{
+	u32 age_time = ar8xxx_age_time_val(priv->arl_age_time);
+	ar8xxx_rmw(priv, reg, AR8216_ATU_CTRL_AGE_TIME, age_time << AR8216_ATU_CTRL_AGE_TIME_S);
+}
+
+int
+ar8xxx_sw_hw_apply(struct switch_dev *dev)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	const struct ar8xxx_chip *chip = priv->chip;
+	u8 portmask[AR8X16_MAX_PORTS];
+	int i, j;
+
+	mutex_lock(&priv->reg_mutex);
+	/* flush all vlan translation unit entries */
+	priv->chip->vtu_flush(priv);
+
+	memset(portmask, 0, sizeof(portmask));
+	if (!priv->init) {
+		/* calculate the port destination masks and load vlans
+		 * into the vlan translation unit */
+		for (j = 0; j < dev->vlans; j++) {
+			u8 vp = priv->vlan_table[j];
+
+			if (!vp)
+				continue;
+
+			for (i = 0; i < dev->ports; i++) {
+				u8 mask = (1 << i);
+				if (vp & mask)
+					portmask[i] |= vp & ~mask;
+			}
+
+			chip->vtu_load_vlan(priv, priv->vlan_id[j],
+					    priv->vlan_table[j]);
+		}
+	} else {
+		/* vlan disabled:
+		 * isolate all ports, but connect them to the cpu port */
+		for (i = 0; i < dev->ports; i++) {
+			if (i == AR8216_PORT_CPU)
+				continue;
+
+			portmask[i] = 1 << AR8216_PORT_CPU;
+			portmask[AR8216_PORT_CPU] |= (1 << i);
+		}
+	}
+
+	/* update the port destination mask registers and tag settings */
+	for (i = 0; i < dev->ports; i++) {
+		chip->setup_port(priv, i, portmask[i]);
+	}
+
+	chip->set_mirror_regs(priv);
+
+	/* set age time */
+	if (chip->reg_arl_ctrl)
+		ar8xxx_set_age_time(priv, chip->reg_arl_ctrl);
+
+	mutex_unlock(&priv->reg_mutex);
+	return 0;
+}
+
+int
+ar8xxx_sw_reset_switch(struct switch_dev *dev)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	const struct ar8xxx_chip *chip = priv->chip;
+	int i;
+
+	mutex_lock(&priv->reg_mutex);
+	memset(&priv->vlan, 0, sizeof(struct ar8xxx_priv) -
+		offsetof(struct ar8xxx_priv, vlan));
+
+	for (i = 0; i < dev->vlans; i++)
+		priv->vlan_id[i] = i;
+
+	/* Configure all ports */
+	for (i = 0; i < dev->ports; i++)
+		chip->init_port(priv, i);
+
+	priv->mirror_rx = false;
+	priv->mirror_tx = false;
+	priv->source_port = 0;
+	priv->monitor_port = 0;
+	priv->arl_age_time = AR8XXX_DEFAULT_ARL_AGE_TIME;
+
+	chip->init_globals(priv);
+	chip->atu_flush(priv);
+
+	mutex_unlock(&priv->reg_mutex);
+
+	return chip->sw_hw_apply(dev);
+}
+
+int
+ar8xxx_sw_set_reset_mibs(struct switch_dev *dev,
+			 const struct switch_attr *attr,
+			 struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	unsigned int len;
+	int ret;
+
+	if (!ar8xxx_has_mib_counters(priv))
+		return -EOPNOTSUPP;
+
+	mutex_lock(&priv->mib_lock);
+
+	len = priv->dev.ports * priv->chip->num_mibs *
+	      sizeof(*priv->mib_stats);
+	memset(priv->mib_stats, '\0', len);
+	ret = ar8xxx_mib_flush(priv);
+	if (ret)
+		goto unlock;
+
+	ret = 0;
+
+unlock:
+	mutex_unlock(&priv->mib_lock);
+	return ret;
+}
+
+int
+ar8xxx_sw_set_mib_poll_interval(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	if (!ar8xxx_has_mib_counters(priv))
+		return -EOPNOTSUPP;
+
+	ar8xxx_mib_stop(priv);
+	priv->mib_poll_interval = val->value.i;
+	ar8xxx_mib_start(priv);
+
+	return 0;
+}
+
+int
+ar8xxx_sw_get_mib_poll_interval(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	if (!ar8xxx_has_mib_counters(priv))
+		return -EOPNOTSUPP;
+	val->value.i = priv->mib_poll_interval;
+	return 0;
+}
+
+int
+ar8xxx_sw_set_mib_type(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	if (!ar8xxx_has_mib_counters(priv))
+		return -EOPNOTSUPP;
+	priv->mib_type = val->value.i;
+	return 0;
+}
+
+int
+ar8xxx_sw_get_mib_type(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	if (!ar8xxx_has_mib_counters(priv))
+		return -EOPNOTSUPP;
+	val->value.i = priv->mib_type;
+	return 0;
+}
+
+int
+ar8xxx_sw_set_mirror_rx_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	mutex_lock(&priv->reg_mutex);
+	priv->mirror_rx = !!val->value.i;
+	priv->chip->set_mirror_regs(priv);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8xxx_sw_get_mirror_rx_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	val->value.i = priv->mirror_rx;
+	return 0;
+}
+
+int
+ar8xxx_sw_set_mirror_tx_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	mutex_lock(&priv->reg_mutex);
+	priv->mirror_tx = !!val->value.i;
+	priv->chip->set_mirror_regs(priv);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8xxx_sw_get_mirror_tx_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	val->value.i = priv->mirror_tx;
+	return 0;
+}
+
+int
+ar8xxx_sw_set_mirror_monitor_port(struct switch_dev *dev,
+				  const struct switch_attr *attr,
+				  struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	mutex_lock(&priv->reg_mutex);
+	priv->monitor_port = val->value.i;
+	priv->chip->set_mirror_regs(priv);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8xxx_sw_get_mirror_monitor_port(struct switch_dev *dev,
+				  const struct switch_attr *attr,
+				  struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	val->value.i = priv->monitor_port;
+	return 0;
+}
+
+int
+ar8xxx_sw_set_mirror_source_port(struct switch_dev *dev,
+				 const struct switch_attr *attr,
+				 struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	mutex_lock(&priv->reg_mutex);
+	priv->source_port = val->value.i;
+	priv->chip->set_mirror_regs(priv);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev,
+				 const struct switch_attr *attr,
+				 struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	val->value.i = priv->source_port;
+	return 0;
+}
+
+int
+ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev,
+			     const struct switch_attr *attr,
+			     struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port;
+	int ret;
+
+	if (!ar8xxx_has_mib_counters(priv))
+		return -EOPNOTSUPP;
+
+	port = val->port_vlan;
+	if (port >= dev->ports)
+		return -EINVAL;
+
+	mutex_lock(&priv->mib_lock);
+	ret = ar8xxx_mib_capture(priv);
+	if (ret)
+		goto unlock;
+
+	ar8xxx_mib_fetch_port_stat(priv, port, true);
+
+	ret = 0;
+
+unlock:
+	mutex_unlock(&priv->mib_lock);
+	return ret;
+}
+
+static void
+ar8xxx_byte_to_str(char *buf, int len, u64 byte)
+{
+	unsigned long b;
+	const char *unit;
+
+	if (byte >= 0x40000000) { /* 1 GiB */
+		b = byte * 10 / 0x40000000;
+		unit = "GiB";
+	} else if (byte >= 0x100000) { /* 1 MiB */
+		b = byte * 10 / 0x100000;
+		unit = "MiB";
+	} else if (byte >= 0x400) { /* 1 KiB */
+		b = byte * 10 / 0x400;
+		unit = "KiB";
+	} else {
+		b = byte;
+		unit = "Byte";
+	}
+	if (strcmp(unit, "Byte"))
+		snprintf(buf, len, "%lu.%lu %s", b / 10, b % 10, unit);
+	else
+		snprintf(buf, len, "%lu %s", b, unit);
+}
+
+int
+ar8xxx_sw_get_port_mib(struct switch_dev *dev,
+		       const struct switch_attr *attr,
+		       struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	const struct ar8xxx_chip *chip = priv->chip;
+	u64 *mib_stats, mib_data;
+	unsigned int port;
+	int ret;
+	char *buf = priv->buf;
+	char buf1[64];
+	const char *mib_name;
+	int i, len = 0;
+	bool mib_stats_empty = true;
+
+	if (!ar8xxx_has_mib_counters(priv) || !priv->mib_poll_interval)
+		return -EOPNOTSUPP;
+
+	port = val->port_vlan;
+	if (port >= dev->ports)
+		return -EINVAL;
+
+	mutex_lock(&priv->mib_lock);
+	ret = ar8xxx_mib_capture(priv);
+	if (ret)
+		goto unlock;
+
+	ar8xxx_mib_fetch_port_stat(priv, port, false);
+
+	len += snprintf(buf + len, sizeof(priv->buf) - len,
+			"MIB counters\n");
+
+	mib_stats = &priv->mib_stats[port * chip->num_mibs];
+	for (i = 0; i < chip->num_mibs; i++) {
+		if (chip->mib_decs[i].type > priv->mib_type)
+			continue;
+		mib_name = chip->mib_decs[i].name;
+		mib_data = mib_stats[i];
+		len += snprintf(buf + len, sizeof(priv->buf) - len,
+				"%-12s: %llu\n", mib_name, mib_data);
+		if ((!strcmp(mib_name, "TxByte") ||
+		    !strcmp(mib_name, "RxGoodByte")) &&
+		    mib_data >= 1024) {
+			ar8xxx_byte_to_str(buf1, sizeof(buf1), mib_data);
+			--len; /* discard newline at the end of buf */
+			len += snprintf(buf + len, sizeof(priv->buf) - len,
+					" (%s)\n", buf1);
+		}
+		if (mib_stats_empty && mib_data)
+			mib_stats_empty = false;
+	}
+
+	if (mib_stats_empty)
+		len = snprintf(buf, sizeof(priv->buf), "No MIB data");
+
+	val->value.s = buf;
+	val->len = len;
+
+	ret = 0;
+
+unlock:
+	mutex_unlock(&priv->mib_lock);
+	return ret;
+}
+
+int
+ar8xxx_sw_set_arl_age_time(struct switch_dev *dev, const struct switch_attr *attr,
+			   struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int age_time = val->value.i;
+	u32 age_time_val;
+
+	if (age_time < 0)
+		return -EINVAL;
+
+	age_time_val = ar8xxx_age_time_val(age_time);
+	if (age_time_val == 0 || age_time_val > 0xffff)
+		return -EINVAL;
+
+	priv->arl_age_time = age_time;
+	return 0;
+}
+
+int
+ar8xxx_sw_get_arl_age_time(struct switch_dev *dev, const struct switch_attr *attr,
+                   struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	val->value.i = priv->arl_age_time;
+	return 0;
+}
+
+int
+ar8xxx_sw_get_arl_table(struct switch_dev *dev,
+			const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	struct mii_bus *bus = priv->mii_bus;
+	const struct ar8xxx_chip *chip = priv->chip;
+	char *buf = priv->arl_buf;
+	int i, j, k, len = 0;
+	struct arl_entry *a, *a1;
+	u32 status;
+
+	if (!chip->get_arl_entry)
+		return -EOPNOTSUPP;
+
+	mutex_lock(&priv->reg_mutex);
+	mutex_lock(&bus->mdio_lock);
+
+	chip->get_arl_entry(priv, NULL, NULL, AR8XXX_ARL_INITIALIZE);
+
+	for(i = 0; i < AR8XXX_NUM_ARL_RECORDS; ++i) {
+		a = &priv->arl_table[i];
+		duplicate:
+		chip->get_arl_entry(priv, a, &status, AR8XXX_ARL_GET_NEXT);
+
+		if (!status)
+			break;
+
+		/* avoid duplicates
+		 * ARL table can include multiple valid entries
+		 * per MAC, just with differing status codes
+		 */
+		for (j = 0; j < i; ++j) {
+			a1 = &priv->arl_table[j];
+			if (!memcmp(a->mac, a1->mac, sizeof(a->mac))) {
+				/* ignore ports already seen in former entry */
+				a->portmap &= ~a1->portmap;
+				if (!a->portmap)
+					goto duplicate;
+			}
+		}
+	}
+
+	mutex_unlock(&bus->mdio_lock);
+
+	len += snprintf(buf + len, sizeof(priv->arl_buf) - len,
+                        "address resolution table\n");
+
+	if (i == AR8XXX_NUM_ARL_RECORDS)
+		len += snprintf(buf + len, sizeof(priv->arl_buf) - len,
+				"Too many entries found, displaying the first %d only!\n",
+				AR8XXX_NUM_ARL_RECORDS);
+
+	for (j = 0; j < priv->dev.ports; ++j) {
+		for (k = 0; k < i; ++k) {
+			a = &priv->arl_table[k];
+			if (!(a->portmap & BIT(j)))
+				continue;
+			len += snprintf(buf + len, sizeof(priv->arl_buf) - len,
+					"Port %d: MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+					j,
+					a->mac[5], a->mac[4], a->mac[3],
+					a->mac[2], a->mac[1], a->mac[0]);
+		}
+	}
+
+	val->value.s = buf;
+	val->len = len;
+
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8xxx_sw_set_flush_arl_table(struct switch_dev *dev,
+			      const struct switch_attr *attr,
+			      struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int ret;
+
+	mutex_lock(&priv->reg_mutex);
+	ret = priv->chip->atu_flush(priv);
+	mutex_unlock(&priv->reg_mutex);
+
+	return ret;
+}
+
+int
+ar8xxx_sw_set_flush_port_arl_table(struct switch_dev *dev,
+				   const struct switch_attr *attr,
+				   struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port, ret;
+
+	port = val->port_vlan;
+	if (port >= dev->ports)
+		return -EINVAL;
+
+	mutex_lock(&priv->reg_mutex);
+	ret = priv->chip->atu_flush_port(priv, port);
+	mutex_unlock(&priv->reg_mutex);
+
+	return ret;
+}
+
+int
+ar8xxx_sw_get_port_stats(struct switch_dev *dev, int port,
+			struct switch_port_stats *stats)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	u64 *mib_stats;
+
+	if (!ar8xxx_has_mib_counters(priv) || !priv->mib_poll_interval)
+		return -EOPNOTSUPP;
+
+	if (!(priv->chip->mib_rxb_id || priv->chip->mib_txb_id))
+		return -EOPNOTSUPP;
+
+	if (port >= dev->ports)
+		return -EINVAL;
+
+	mutex_lock(&priv->mib_lock);
+
+	mib_stats = &priv->mib_stats[port * priv->chip->num_mibs];
+
+	stats->tx_bytes = mib_stats[priv->chip->mib_txb_id];
+	stats->rx_bytes = mib_stats[priv->chip->mib_rxb_id];
+
+	mutex_unlock(&priv->mib_lock);
+	return 0;
+}
+
+static int
+ar8xxx_phy_read(struct mii_bus *bus, int phy_addr, int reg_addr)
+{
+	struct ar8xxx_priv *priv = bus->priv;
+	return priv->chip->phy_read(priv, phy_addr, reg_addr);
+}
+
+static int
+ar8xxx_phy_write(struct mii_bus *bus, int phy_addr, int reg_addr,
+		 u16 reg_val)
+{
+	struct ar8xxx_priv *priv = bus->priv;
+	return priv->chip->phy_write(priv, phy_addr, reg_addr, reg_val);
+}
+
+static const struct switch_attr ar8xxx_sw_attr_globals[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.set = ar8xxx_sw_set_vlan,
+		.get = ar8xxx_sw_get_vlan,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mibs",
+		.description = "Reset all MIB counters",
+		.set = ar8xxx_sw_set_reset_mibs,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "ar8xxx_mib_poll_interval",
+		.description = "MIB polling interval in msecs (0 to disable)",
+		.set = ar8xxx_sw_set_mib_poll_interval,
+		.get = ar8xxx_sw_get_mib_poll_interval
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "ar8xxx_mib_type",
+		.description = "MIB type (0=basic 1=extended)",
+		.set = ar8xxx_sw_set_mib_type,
+		.get = ar8xxx_sw_get_mib_type
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_mirror_rx",
+		.description = "Enable mirroring of RX packets",
+		.set = ar8xxx_sw_set_mirror_rx_enable,
+		.get = ar8xxx_sw_get_mirror_rx_enable,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_mirror_tx",
+		.description = "Enable mirroring of TX packets",
+		.set = ar8xxx_sw_set_mirror_tx_enable,
+		.get = ar8xxx_sw_get_mirror_tx_enable,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "mirror_monitor_port",
+		.description = "Mirror monitor port",
+		.set = ar8xxx_sw_set_mirror_monitor_port,
+		.get = ar8xxx_sw_get_mirror_monitor_port,
+		.max = AR8216_NUM_PORTS - 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "mirror_source_port",
+		.description = "Mirror source port",
+		.set = ar8xxx_sw_set_mirror_source_port,
+		.get = ar8xxx_sw_get_mirror_source_port,
+		.max = AR8216_NUM_PORTS - 1
+ 	},
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "arl_table",
+		.description = "Get ARL table",
+		.set = NULL,
+		.get = ar8xxx_sw_get_arl_table,
+	},
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "flush_arl_table",
+		.description = "Flush ARL table",
+		.set = ar8xxx_sw_set_flush_arl_table,
+	},
+};
+
+const struct switch_attr ar8xxx_sw_attr_port[] = {
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mib",
+		.description = "Reset single port MIB counters",
+		.set = ar8xxx_sw_set_port_reset_mib,
+	},
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "mib",
+		.description = "Get port's MIB counters",
+		.set = NULL,
+		.get = ar8xxx_sw_get_port_mib,
+	},
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "flush_arl_table",
+		.description = "Flush port's ARL table entries",
+		.set = ar8xxx_sw_set_flush_port_arl_table,
+	},
+};
+
+const struct switch_attr ar8xxx_sw_attr_vlan[1] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "vid",
+		.description = "VLAN ID (0-4094)",
+		.set = ar8xxx_sw_set_vid,
+		.get = ar8xxx_sw_get_vid,
+		.max = 4094,
+	},
+};
+
+static const struct switch_dev_ops ar8xxx_sw_ops = {
+	.attr_global = {
+		.attr = ar8xxx_sw_attr_globals,
+		.n_attr = ARRAY_SIZE(ar8xxx_sw_attr_globals),
+	},
+	.attr_port = {
+		.attr = ar8xxx_sw_attr_port,
+		.n_attr = ARRAY_SIZE(ar8xxx_sw_attr_port),
+	},
+	.attr_vlan = {
+		.attr = ar8xxx_sw_attr_vlan,
+		.n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan),
+	},
+	.get_port_pvid = ar8xxx_sw_get_pvid,
+	.set_port_pvid = ar8xxx_sw_set_pvid,
+	.get_vlan_ports = ar8xxx_sw_get_ports,
+	.set_vlan_ports = ar8xxx_sw_set_ports,
+	.apply_config = ar8xxx_sw_hw_apply,
+	.reset_switch = ar8xxx_sw_reset_switch,
+	.get_port_link = ar8xxx_sw_get_port_link,
+	.get_port_stats = ar8xxx_sw_get_port_stats,
+};
+
+static const struct ar8xxx_chip ar7240sw_chip = {
+	.caps = AR8XXX_CAP_MIB_COUNTERS,
+
+	.reg_port_stats_start = 0x20000,
+	.reg_port_stats_length = 0x100,
+	.reg_arl_ctrl = AR8216_REG_ATU_CTRL,
+
+	.name = "Atheros AR724X/AR933X built-in",
+	.ports = AR7240SW_NUM_PORTS,
+	.vlans = AR8216_NUM_VLANS,
+	.swops = &ar8xxx_sw_ops,
+
+	.hw_init = ar7240sw_hw_init,
+	.init_globals = ar7240sw_init_globals,
+	.init_port = ar8229_init_port,
+	.phy_read = ar8216_phy_read,
+	.phy_write = ar8216_phy_write,
+	.setup_port = ar7240sw_setup_port,
+	.read_port_status = ar8216_read_port_status,
+	.atu_flush = ar8216_atu_flush,
+	.atu_flush_port = ar8216_atu_flush_port,
+	.vtu_flush = ar8216_vtu_flush,
+	.vtu_load_vlan = ar8216_vtu_load_vlan,
+	.set_mirror_regs = ar8216_set_mirror_regs,
+	.get_arl_entry = ar8216_get_arl_entry,
+	.sw_hw_apply = ar8xxx_sw_hw_apply,
+
+	.num_mibs = ARRAY_SIZE(ar8236_mibs),
+	.mib_decs = ar8236_mibs,
+	.mib_func = AR8216_REG_MIB_FUNC,
+	.mib_rxb_id = AR8236_MIB_RXB_ID,
+	.mib_txb_id = AR8236_MIB_TXB_ID,
+};
+
+static const struct ar8xxx_chip ar8216_chip = {
+	.caps = AR8XXX_CAP_MIB_COUNTERS,
+
+	.reg_port_stats_start = 0x19000,
+	.reg_port_stats_length = 0xa0,
+	.reg_arl_ctrl = AR8216_REG_ATU_CTRL,
+
+	.name = "Atheros AR8216",
+	.ports = AR8216_NUM_PORTS,
+	.vlans = AR8216_NUM_VLANS,
+	.swops = &ar8xxx_sw_ops,
+
+	.hw_init = ar8216_hw_init,
+	.init_globals = ar8216_init_globals,
+	.init_port = ar8216_init_port,
+	.setup_port = ar8216_setup_port,
+	.read_port_status = ar8216_read_port_status,
+	.atu_flush = ar8216_atu_flush,
+	.atu_flush_port = ar8216_atu_flush_port,
+	.vtu_flush = ar8216_vtu_flush,
+	.vtu_load_vlan = ar8216_vtu_load_vlan,
+	.set_mirror_regs = ar8216_set_mirror_regs,
+	.get_arl_entry = ar8216_get_arl_entry,
+	.sw_hw_apply = ar8xxx_sw_hw_apply,
+
+	.num_mibs = ARRAY_SIZE(ar8216_mibs),
+	.mib_decs = ar8216_mibs,
+	.mib_func = AR8216_REG_MIB_FUNC,
+	.mib_rxb_id = AR8216_MIB_RXB_ID,
+	.mib_txb_id = AR8216_MIB_TXB_ID,
+};
+
+static const struct ar8xxx_chip ar8229_chip = {
+	.caps = AR8XXX_CAP_MIB_COUNTERS,
+
+	.reg_port_stats_start = 0x20000,
+	.reg_port_stats_length = 0x100,
+	.reg_arl_ctrl = AR8216_REG_ATU_CTRL,
+
+	.name = "Atheros AR8229",
+	.ports = AR8216_NUM_PORTS,
+	.vlans = AR8216_NUM_VLANS,
+	.swops = &ar8xxx_sw_ops,
+
+	.hw_init = ar8229_hw_init,
+	.init_globals = ar8229_init_globals,
+	.init_port = ar8229_init_port,
+	.phy_read = ar8216_phy_read,
+	.phy_write = ar8216_phy_write,
+	.setup_port = ar8236_setup_port,
+	.read_port_status = ar8216_read_port_status,
+	.atu_flush = ar8216_atu_flush,
+	.atu_flush_port = ar8216_atu_flush_port,
+	.vtu_flush = ar8216_vtu_flush,
+	.vtu_load_vlan = ar8216_vtu_load_vlan,
+	.set_mirror_regs = ar8216_set_mirror_regs,
+	.get_arl_entry = ar8216_get_arl_entry,
+	.sw_hw_apply = ar8xxx_sw_hw_apply,
+
+	.num_mibs = ARRAY_SIZE(ar8236_mibs),
+	.mib_decs = ar8236_mibs,
+	.mib_func = AR8216_REG_MIB_FUNC,
+	.mib_rxb_id = AR8236_MIB_RXB_ID,
+	.mib_txb_id = AR8236_MIB_TXB_ID,
+};
+
+static const struct ar8xxx_chip ar8236_chip = {
+	.caps = AR8XXX_CAP_MIB_COUNTERS,
+
+	.reg_port_stats_start = 0x20000,
+	.reg_port_stats_length = 0x100,
+	.reg_arl_ctrl = AR8216_REG_ATU_CTRL,
+
+	.name = "Atheros AR8236",
+	.ports = AR8216_NUM_PORTS,
+	.vlans = AR8216_NUM_VLANS,
+	.swops = &ar8xxx_sw_ops,
+
+	.hw_init = ar8216_hw_init,
+	.init_globals = ar8236_init_globals,
+	.init_port = ar8216_init_port,
+	.setup_port = ar8236_setup_port,
+	.read_port_status = ar8216_read_port_status,
+	.atu_flush = ar8216_atu_flush,
+	.atu_flush_port = ar8216_atu_flush_port,
+	.vtu_flush = ar8216_vtu_flush,
+	.vtu_load_vlan = ar8216_vtu_load_vlan,
+	.set_mirror_regs = ar8216_set_mirror_regs,
+	.get_arl_entry = ar8216_get_arl_entry,
+	.sw_hw_apply = ar8xxx_sw_hw_apply,
+
+	.num_mibs = ARRAY_SIZE(ar8236_mibs),
+	.mib_decs = ar8236_mibs,
+	.mib_func = AR8216_REG_MIB_FUNC,
+	.mib_rxb_id = AR8236_MIB_RXB_ID,
+	.mib_txb_id = AR8236_MIB_TXB_ID,
+};
+
+static const struct ar8xxx_chip ar8316_chip = {
+	.caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS,
+
+	.reg_port_stats_start = 0x20000,
+	.reg_port_stats_length = 0x100,
+	.reg_arl_ctrl = AR8216_REG_ATU_CTRL,
+
+	.name = "Atheros AR8316",
+	.ports = AR8216_NUM_PORTS,
+	.vlans = AR8X16_MAX_VLANS,
+	.swops = &ar8xxx_sw_ops,
+
+	.hw_init = ar8316_hw_init,
+	.init_globals = ar8316_init_globals,
+	.init_port = ar8216_init_port,
+	.setup_port = ar8216_setup_port,
+	.read_port_status = ar8216_read_port_status,
+	.atu_flush = ar8216_atu_flush,
+	.atu_flush_port = ar8216_atu_flush_port,
+	.vtu_flush = ar8216_vtu_flush,
+	.vtu_load_vlan = ar8216_vtu_load_vlan,
+	.set_mirror_regs = ar8216_set_mirror_regs,
+	.get_arl_entry = ar8216_get_arl_entry,
+	.sw_hw_apply = ar8xxx_sw_hw_apply,
+
+	.num_mibs = ARRAY_SIZE(ar8236_mibs),
+	.mib_decs = ar8236_mibs,
+	.mib_func = AR8216_REG_MIB_FUNC,
+	.mib_rxb_id = AR8236_MIB_RXB_ID,
+	.mib_txb_id = AR8236_MIB_TXB_ID,
+};
+
+static int
+ar8xxx_read_id(struct ar8xxx_priv *priv)
+{
+	u32 val;
+	u16 id;
+	int i;
+
+	val = ar8xxx_read(priv, AR8216_REG_CTRL);
+	if (val == ~0)
+		return -ENODEV;
+
+	id = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION);
+	for (i = 0; i < AR8X16_PROBE_RETRIES; i++) {
+		u16 t;
+
+		val = ar8xxx_read(priv, AR8216_REG_CTRL);
+		if (val == ~0)
+			return -ENODEV;
+
+		t = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION);
+		if (t != id)
+			return -ENODEV;
+	}
+
+	priv->chip_ver = (id & AR8216_CTRL_VERSION) >> AR8216_CTRL_VERSION_S;
+	priv->chip_rev = (id & AR8216_CTRL_REVISION);
+	return 0;
+}
+
+static int
+ar8xxx_id_chip(struct ar8xxx_priv *priv)
+{
+	int ret;
+
+	ret = ar8xxx_read_id(priv);
+	if(ret)
+		return ret;
+
+	switch (priv->chip_ver) {
+	case AR8XXX_VER_AR8216:
+		priv->chip = &ar8216_chip;
+		break;
+	case AR8XXX_VER_AR8236:
+		priv->chip = &ar8236_chip;
+		break;
+	case AR8XXX_VER_AR8316:
+		priv->chip = &ar8316_chip;
+		break;
+	case AR8XXX_VER_AR8327:
+		priv->chip = &ar8327_chip;
+		break;
+	case AR8XXX_VER_AR8337:
+		priv->chip = &ar8337_chip;
+		break;
+	default:
+		pr_err("ar8216: Unknown Atheros device [ver=%d, rev=%d]\n",
+		       priv->chip_ver, priv->chip_rev);
+
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void
+ar8xxx_mib_work_func(struct work_struct *work)
+{
+	struct ar8xxx_priv *priv;
+	int err, i;
+
+	priv = container_of(work, struct ar8xxx_priv, mib_work.work);
+
+	mutex_lock(&priv->mib_lock);
+
+	err = ar8xxx_mib_capture(priv);
+	if (err)
+		goto next_attempt;
+
+	for (i = 0; i < priv->dev.ports; i++)
+		ar8xxx_mib_fetch_port_stat(priv, i, false);
+
+next_attempt:
+	mutex_unlock(&priv->mib_lock);
+	schedule_delayed_work(&priv->mib_work,
+			      msecs_to_jiffies(priv->mib_poll_interval));
+}
+
+static int
+ar8xxx_mib_init(struct ar8xxx_priv *priv)
+{
+	unsigned int len;
+
+	if (!ar8xxx_has_mib_counters(priv))
+		return 0;
+
+	BUG_ON(!priv->chip->mib_decs || !priv->chip->num_mibs);
+
+	len = priv->dev.ports * priv->chip->num_mibs *
+	      sizeof(*priv->mib_stats);
+	priv->mib_stats = kzalloc(len, GFP_KERNEL);
+
+	if (!priv->mib_stats)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void
+ar8xxx_mib_start(struct ar8xxx_priv *priv)
+{
+	if (!ar8xxx_has_mib_counters(priv) || !priv->mib_poll_interval)
+		return;
+
+	schedule_delayed_work(&priv->mib_work,
+			      msecs_to_jiffies(priv->mib_poll_interval));
+}
+
+static void
+ar8xxx_mib_stop(struct ar8xxx_priv *priv)
+{
+	if (!ar8xxx_has_mib_counters(priv) || !priv->mib_poll_interval)
+		return;
+
+	cancel_delayed_work_sync(&priv->mib_work);
+}
+
+static struct ar8xxx_priv *
+ar8xxx_create(void)
+{
+	struct ar8xxx_priv *priv;
+
+	priv = kzalloc(sizeof(struct ar8xxx_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	mutex_init(&priv->reg_mutex);
+	mutex_init(&priv->mib_lock);
+	INIT_DELAYED_WORK(&priv->mib_work, ar8xxx_mib_work_func);
+
+	return priv;
+}
+
+static void
+ar8xxx_free(struct ar8xxx_priv *priv)
+{
+	if (priv->chip && priv->chip->cleanup)
+		priv->chip->cleanup(priv);
+
+	kfree(priv->chip_data);
+	kfree(priv->mib_stats);
+	kfree(priv);
+}
+
+static int
+ar8xxx_probe_switch(struct ar8xxx_priv *priv)
+{
+	const struct ar8xxx_chip *chip;
+	struct switch_dev *swdev;
+	int ret;
+
+	chip = priv->chip;
+
+	swdev = &priv->dev;
+	swdev->cpu_port = AR8216_PORT_CPU;
+	swdev->name = chip->name;
+	swdev->vlans = chip->vlans;
+	swdev->ports = chip->ports;
+	swdev->ops = chip->swops;
+
+	ret = ar8xxx_mib_init(priv);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int
+ar8xxx_start(struct ar8xxx_priv *priv)
+{
+	int ret;
+
+	priv->init = true;
+
+	ret = priv->chip->hw_init(priv);
+	if (ret)
+		return ret;
+
+	ret = ar8xxx_sw_reset_switch(&priv->dev);
+	if (ret)
+		return ret;
+
+	priv->init = false;
+
+	ar8xxx_mib_start(priv);
+
+	return 0;
+}
+
+static int
+ar8xxx_phy_config_init(struct phy_device *phydev)
+{
+	struct ar8xxx_priv *priv = phydev->priv;
+	struct net_device *dev = phydev->attached_dev;
+	int ret;
+
+	if (WARN_ON(!priv))
+		return -ENODEV;
+
+	if (priv->chip->config_at_probe)
+		return ar8xxx_phy_check_aneg(phydev);
+
+	priv->phy = phydev;
+
+	if (phydev->mdio.addr != 0) {
+		if (chip_is_ar8316(priv)) {
+			/* switch device has been initialized, reinit */
+			priv->dev.ports = (AR8216_NUM_PORTS - 1);
+			priv->initialized = false;
+			priv->port4_phy = true;
+			ar8316_hw_init(priv);
+			return 0;
+		}
+
+		return 0;
+	}
+
+	ret = ar8xxx_start(priv);
+	if (ret)
+		return ret;
+
+	/* VID fixup only needed on ar8216 */
+	if (chip_is_ar8216(priv)) {
+		dev->phy_ptr = priv;
+		dev->priv_flags |= IFF_NO_IP_ALIGN;
+		dev->eth_mangle_rx = ar8216_mangle_rx;
+		dev->eth_mangle_tx = ar8216_mangle_tx;
+	}
+
+	return 0;
+}
+
+static bool
+ar8xxx_check_link_states(struct ar8xxx_priv *priv)
+{
+	bool link_new, changed = false;
+	u32 status;
+	int i;
+
+	mutex_lock(&priv->reg_mutex);
+
+	for (i = 0; i < priv->dev.ports; i++) {
+		status = priv->chip->read_port_status(priv, i);
+		link_new = !!(status & AR8216_PORT_STATUS_LINK_UP);
+		if (link_new == priv->link_up[i])
+			continue;
+
+		priv->link_up[i] = link_new;
+		changed = true;
+		/* flush ARL entries for this port if it went down*/
+		if (!link_new)
+			priv->chip->atu_flush_port(priv, i);
+		dev_info(&priv->phy->mdio.dev, "Port %d is %s\n",
+			 i, link_new ? "up" : "down");
+	}
+
+	mutex_unlock(&priv->reg_mutex);
+
+	return changed;
+}
+
+static int
+ar8xxx_phy_read_status(struct phy_device *phydev)
+{
+	struct ar8xxx_priv *priv = phydev->priv;
+	struct switch_port_link link;
+
+	/* check for switch port link changes */
+	ar8xxx_check_link_states(priv);
+
+	if (phydev->mdio.addr != 0)
+		return genphy_read_status(phydev);
+
+	ar8216_read_port_link(priv, phydev->mdio.addr, &link);
+	phydev->link = !!link.link;
+	if (!phydev->link)
+		return 0;
+
+	switch (link.speed) {
+	case SWITCH_PORT_SPEED_10:
+		phydev->speed = SPEED_10;
+		break;
+	case SWITCH_PORT_SPEED_100:
+		phydev->speed = SPEED_100;
+		break;
+	case SWITCH_PORT_SPEED_1000:
+		phydev->speed = SPEED_1000;
+		break;
+	default:
+		phydev->speed = 0;
+	}
+	phydev->duplex = link.duplex ? DUPLEX_FULL : DUPLEX_HALF;
+
+	phydev->state = PHY_RUNNING;
+	netif_carrier_on(phydev->attached_dev);
+	if (phydev->adjust_link)
+		phydev->adjust_link(phydev->attached_dev);
+
+	return 0;
+}
+
+static int
+ar8xxx_phy_config_aneg(struct phy_device *phydev)
+{
+	if (phydev->mdio.addr == 0)
+		return 0;
+
+	return genphy_config_aneg(phydev);
+}
+
+static int
+ar8xxx_get_features(struct phy_device *phydev)
+{
+	struct ar8xxx_priv *priv = phydev->priv;
+
+	linkmode_copy(phydev->supported, PHY_BASIC_FEATURES);
+	if (ar8xxx_has_gige(priv))
+		linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, phydev->supported);
+
+	return 0;
+}
+
+static const u32 ar8xxx_phy_ids[] = {
+	0x004dd033,
+	0x004dd034, /* AR8327 */
+	0x004dd036, /* AR8337 */
+	0x004dd041,
+	0x004dd042,
+	0x004dd043, /* AR8236 */
+};
+
+static bool
+ar8xxx_phy_match(u32 phy_id)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ar8xxx_phy_ids); i++)
+		if (phy_id == ar8xxx_phy_ids[i])
+			return true;
+
+	return false;
+}
+
+static bool
+ar8xxx_is_possible(struct mii_bus *bus)
+{
+	unsigned int i, found_phys = 0;
+
+	for (i = 0; i < 5; i++) {
+		u32 phy_id;
+
+		phy_id = mdiobus_read(bus, i, MII_PHYSID1) << 16;
+		phy_id |= mdiobus_read(bus, i, MII_PHYSID2);
+		if (ar8xxx_phy_match(phy_id)) {
+			found_phys++;
+		} else if (phy_id) {
+			pr_debug("ar8xxx: unknown PHY at %s:%02x id:%08x\n",
+				 dev_name(&bus->dev), i, phy_id);
+		}
+	}
+	return !!found_phys;
+}
+
+static int
+ar8xxx_phy_probe(struct phy_device *phydev)
+{
+	struct ar8xxx_priv *priv;
+	struct switch_dev *swdev;
+	int ret;
+
+	/* skip PHYs at unused adresses */
+	if (phydev->mdio.addr != 0 && phydev->mdio.addr != 3 && phydev->mdio.addr != 4)
+		return -ENODEV;
+
+	if (!ar8xxx_is_possible(phydev->mdio.bus))
+		return -ENODEV;
+
+	mutex_lock(&ar8xxx_dev_list_lock);
+	list_for_each_entry(priv, &ar8xxx_dev_list, list)
+		if (priv->mii_bus == phydev->mdio.bus)
+			goto found;
+
+	priv = ar8xxx_create();
+	if (priv == NULL) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	priv->mii_bus = phydev->mdio.bus;
+	priv->pdev = &phydev->mdio.dev;
+
+	ret = of_property_read_u32(priv->pdev->of_node, "qca,mib-poll-interval",
+				   &priv->mib_poll_interval);
+	if (ret)
+		priv->mib_poll_interval = 0;
+
+	ret = ar8xxx_id_chip(priv);
+	if (ret)
+		goto free_priv;
+
+	ret = ar8xxx_probe_switch(priv);
+	if (ret)
+		goto free_priv;
+
+	swdev = &priv->dev;
+	swdev->alias = dev_name(&priv->mii_bus->dev);
+	ret = register_switch(swdev, NULL);
+	if (ret)
+		goto free_priv;
+
+	pr_info("%s: %s rev. %u switch registered on %s\n",
+		swdev->devname, swdev->name, priv->chip_rev,
+		dev_name(&priv->mii_bus->dev));
+
+	list_add(&priv->list, &ar8xxx_dev_list);
+
+found:
+	priv->use_count++;
+
+	if (phydev->mdio.addr == 0 && priv->chip->config_at_probe) {
+		priv->phy = phydev;
+
+		ret = ar8xxx_start(priv);
+		if (ret)
+			goto err_unregister_switch;
+	} else if (priv->chip->phy_rgmii_set) {
+		priv->chip->phy_rgmii_set(priv, phydev);
+	}
+
+	phydev->priv = priv;
+
+	mutex_unlock(&ar8xxx_dev_list_lock);
+
+	return 0;
+
+err_unregister_switch:
+	if (--priv->use_count)
+		goto unlock;
+
+	unregister_switch(&priv->dev);
+
+free_priv:
+	ar8xxx_free(priv);
+unlock:
+	mutex_unlock(&ar8xxx_dev_list_lock);
+	return ret;
+}
+
+static void
+ar8xxx_phy_detach(struct phy_device *phydev)
+{
+	struct net_device *dev = phydev->attached_dev;
+
+	if (!dev)
+		return;
+
+	dev->phy_ptr = NULL;
+	dev->priv_flags &= ~IFF_NO_IP_ALIGN;
+	dev->eth_mangle_rx = NULL;
+	dev->eth_mangle_tx = NULL;
+}
+
+static void
+ar8xxx_phy_remove(struct phy_device *phydev)
+{
+	struct ar8xxx_priv *priv = phydev->priv;
+
+	if (WARN_ON(!priv))
+		return;
+
+	phydev->priv = NULL;
+
+	mutex_lock(&ar8xxx_dev_list_lock);
+
+	if (--priv->use_count > 0) {
+		mutex_unlock(&ar8xxx_dev_list_lock);
+		return;
+	}
+
+	list_del(&priv->list);
+	mutex_unlock(&ar8xxx_dev_list_lock);
+
+	unregister_switch(&priv->dev);
+	ar8xxx_mib_stop(priv);
+	ar8xxx_free(priv);
+}
+
+static int
+ar8xxx_phy_soft_reset(struct phy_device *phydev)
+{
+	/* we don't need an extra reset */
+	return 0;
+}
+
+static struct phy_driver ar8xxx_phy_driver[] = {
+	{
+		.phy_id		= 0x004d0000,
+		.name		= "Atheros AR8216/AR8236/AR8316",
+		.phy_id_mask	= 0xffff0000,
+		.probe		= ar8xxx_phy_probe,
+		.remove		= ar8xxx_phy_remove,
+		.detach		= ar8xxx_phy_detach,
+		.config_init	= ar8xxx_phy_config_init,
+		.config_aneg	= ar8xxx_phy_config_aneg,
+		.read_status	= ar8xxx_phy_read_status,
+		.soft_reset	= ar8xxx_phy_soft_reset,
+		.get_features	= ar8xxx_get_features,
+	}
+};
+
+static const struct of_device_id ar8xxx_mdiodev_of_match[] = {
+	{
+		.compatible = "qca,ar7240sw",
+		.data = &ar7240sw_chip,
+	}, {
+		.compatible = "qca,ar8229",
+		.data = &ar8229_chip,
+	}, {
+		.compatible = "qca,ar8236",
+		.data = &ar8236_chip,
+	}, {
+		.compatible = "qca,ar8327",
+		.data = &ar8327_chip,
+	},
+	{ /* sentinel */ },
+};
+
+static int
+ar8xxx_mdiodev_probe(struct mdio_device *mdiodev)
+{
+	const struct of_device_id *match;
+	struct ar8xxx_priv *priv;
+	struct switch_dev *swdev;
+	struct device_node *mdio_node;
+	int ret;
+
+	match = of_match_device(ar8xxx_mdiodev_of_match, &mdiodev->dev);
+	if (!match)
+		return -EINVAL;
+
+	priv = ar8xxx_create();
+	if (priv == NULL)
+		return -ENOMEM;
+
+	priv->mii_bus = mdiodev->bus;
+	priv->pdev = &mdiodev->dev;
+	priv->chip = (const struct ar8xxx_chip *) match->data;
+
+	ret = of_property_read_u32(priv->pdev->of_node, "qca,mib-poll-interval",
+				   &priv->mib_poll_interval);
+	if (ret)
+		priv->mib_poll_interval = 0;
+
+	ret = ar8xxx_read_id(priv);
+	if (ret)
+		goto free_priv;
+
+	ret = ar8xxx_probe_switch(priv);
+	if (ret)
+		goto free_priv;
+
+	if (priv->chip->phy_read && priv->chip->phy_write) {
+		priv->sw_mii_bus = devm_mdiobus_alloc(&mdiodev->dev);
+		priv->sw_mii_bus->name = "ar8xxx-mdio";
+		priv->sw_mii_bus->read = ar8xxx_phy_read;
+		priv->sw_mii_bus->write = ar8xxx_phy_write;
+		priv->sw_mii_bus->priv = priv;
+		priv->sw_mii_bus->parent = &mdiodev->dev;
+		snprintf(priv->sw_mii_bus->id, MII_BUS_ID_SIZE, "%s",
+			 dev_name(&mdiodev->dev));
+		mdio_node = of_get_child_by_name(priv->pdev->of_node, "mdio-bus");
+		ret = of_mdiobus_register(priv->sw_mii_bus, mdio_node);
+		if (ret)
+			goto free_priv;
+	}
+
+	swdev = &priv->dev;
+	swdev->alias = dev_name(&mdiodev->dev);
+
+	if (of_property_read_bool(priv->pdev->of_node, "qca,phy4-mii-enable")) {
+		priv->port4_phy = true;
+		swdev->ports--;
+	}
+
+	ret = register_switch(swdev, NULL);
+	if (ret)
+		goto free_priv;
+
+	pr_info("%s: %s rev. %u switch registered on %s\n",
+		swdev->devname, swdev->name, priv->chip_rev,
+		dev_name(&priv->mii_bus->dev));
+
+	mutex_lock(&ar8xxx_dev_list_lock);
+	list_add(&priv->list, &ar8xxx_dev_list);
+	mutex_unlock(&ar8xxx_dev_list_lock);
+
+	priv->use_count++;
+
+	ret = ar8xxx_start(priv);
+	if (ret)
+		goto err_unregister_switch;
+
+	dev_set_drvdata(&mdiodev->dev, priv);
+
+	return 0;
+
+err_unregister_switch:
+	if (--priv->use_count)
+		return ret;
+
+	unregister_switch(&priv->dev);
+
+free_priv:
+	ar8xxx_free(priv);
+	return ret;
+}
+
+static void
+ar8xxx_mdiodev_remove(struct mdio_device *mdiodev)
+{
+	struct ar8xxx_priv *priv = dev_get_drvdata(&mdiodev->dev);
+
+	if (WARN_ON(!priv))
+		return;
+
+	mutex_lock(&ar8xxx_dev_list_lock);
+
+	if (--priv->use_count > 0) {
+		mutex_unlock(&ar8xxx_dev_list_lock);
+		return;
+	}
+
+	list_del(&priv->list);
+	mutex_unlock(&ar8xxx_dev_list_lock);
+
+	unregister_switch(&priv->dev);
+	ar8xxx_mib_stop(priv);
+	if(priv->sw_mii_bus)
+		mdiobus_unregister(priv->sw_mii_bus);
+	ar8xxx_free(priv);
+}
+
+static struct mdio_driver ar8xxx_mdio_driver = {
+	.probe  = ar8xxx_mdiodev_probe,
+	.remove = ar8xxx_mdiodev_remove,
+	.mdiodrv.driver = {
+		.name = "ar8xxx-switch",
+		.of_match_table = ar8xxx_mdiodev_of_match,
+	},
+};
+
+static int __init ar8216_init(void)
+{
+	int ret;
+
+	ret = phy_drivers_register(ar8xxx_phy_driver,
+				   ARRAY_SIZE(ar8xxx_phy_driver),
+				   THIS_MODULE);
+	if (ret)
+		return ret;
+
+	ret = mdio_driver_register(&ar8xxx_mdio_driver);
+	if (ret)
+		phy_drivers_unregister(ar8xxx_phy_driver,
+				       ARRAY_SIZE(ar8xxx_phy_driver));
+
+	return ret;
+}
+module_init(ar8216_init);
+
+static void __exit ar8216_exit(void)
+{
+	mdio_driver_unregister(&ar8xxx_mdio_driver);
+	phy_drivers_unregister(ar8xxx_phy_driver,
+			        ARRAY_SIZE(ar8xxx_phy_driver));
+}
+module_exit(ar8216_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/ar8216.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/ar8216.h
new file mode 100644
index 0000000..d62cf60
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/ar8216.h
@@ -0,0 +1,723 @@
+/*
+ * ar8216.h: AR8216 switch driver
+ *
+ * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __AR8216_H
+#define __AR8216_H
+
+#define BITS(_s, _n)	(((1UL << (_n)) - 1) << _s)
+
+#define AR8XXX_CAP_GIGE			BIT(0)
+#define AR8XXX_CAP_MIB_COUNTERS		BIT(1)
+
+#define AR8XXX_NUM_PHYS 	5
+#define AR8216_PORT_CPU	0
+#define AR8216_NUM_PORTS	6
+#define AR8216_NUM_VLANS	16
+#define AR7240SW_NUM_PORTS	5
+#define AR8316_NUM_VLANS	4096
+
+/* size of the vlan table */
+#define AR8X16_MAX_VLANS	128
+#define AR83X7_MAX_VLANS	4096
+#define AR8XXX_MAX_VLANS	AR83X7_MAX_VLANS
+
+#define AR8X16_PROBE_RETRIES	10
+#define AR8X16_MAX_PORTS	8
+
+#define AR8XXX_REG_ARL_CTRL_AGE_TIME_SECS	7
+#define AR8XXX_DEFAULT_ARL_AGE_TIME		300
+
+/* Atheros specific MII registers */
+#define MII_ATH_MMD_ADDR		0x0d
+#define MII_ATH_MMD_DATA		0x0e
+#define MII_ATH_DBG_ADDR		0x1d
+#define MII_ATH_DBG_DATA		0x1e
+
+#define AR8216_REG_CTRL			0x0000
+#define   AR8216_CTRL_REVISION		BITS(0, 8)
+#define   AR8216_CTRL_REVISION_S	0
+#define   AR8216_CTRL_VERSION		BITS(8, 8)
+#define   AR8216_CTRL_VERSION_S		8
+#define   AR8216_CTRL_RESET		BIT(31)
+
+#define AR8216_REG_FLOOD_MASK		0x002C
+#define   AR8216_FM_UNI_DEST_PORTS	BITS(0, 6)
+#define   AR8216_FM_MULTI_DEST_PORTS	BITS(16, 6)
+#define   AR8216_FM_CPU_BROADCAST_EN	BIT(26)
+#define   AR8229_FLOOD_MASK_UC_DP(_p)	BIT(_p)
+#define   AR8229_FLOOD_MASK_MC_DP(_p)	BIT(16 + (_p))
+#define   AR8229_FLOOD_MASK_BC_DP(_p)	BIT(25 + (_p))
+
+#define AR8216_REG_GLOBAL_CTRL		0x0030
+#define   AR8216_GCTRL_MTU		BITS(0, 11)
+#define   AR8236_GCTRL_MTU		BITS(0, 14)
+#define   AR8316_GCTRL_MTU		BITS(0, 14)
+
+#define AR8216_REG_VTU			0x0040
+#define   AR8216_VTU_OP			BITS(0, 3)
+#define   AR8216_VTU_OP_NOOP		0x0
+#define   AR8216_VTU_OP_FLUSH		0x1
+#define   AR8216_VTU_OP_LOAD		0x2
+#define   AR8216_VTU_OP_PURGE		0x3
+#define   AR8216_VTU_OP_REMOVE_PORT	0x4
+#define   AR8216_VTU_ACTIVE		BIT(3)
+#define   AR8216_VTU_FULL		BIT(4)
+#define   AR8216_VTU_PORT		BITS(8, 4)
+#define   AR8216_VTU_PORT_S		8
+#define   AR8216_VTU_VID		BITS(16, 12)
+#define   AR8216_VTU_VID_S		16
+#define   AR8216_VTU_PRIO		BITS(28, 3)
+#define   AR8216_VTU_PRIO_S		28
+#define   AR8216_VTU_PRIO_EN		BIT(31)
+
+#define AR8216_REG_VTU_DATA		0x0044
+#define   AR8216_VTUDATA_MEMBER		BITS(0, 10)
+#define   AR8236_VTUDATA_MEMBER		BITS(0, 7)
+#define   AR8216_VTUDATA_VALID		BIT(11)
+
+#define AR8216_REG_ATU_FUNC0		0x0050
+#define   AR8216_ATU_OP			BITS(0, 3)
+#define   AR8216_ATU_OP_NOOP		0x0
+#define   AR8216_ATU_OP_FLUSH		0x1
+#define   AR8216_ATU_OP_LOAD		0x2
+#define   AR8216_ATU_OP_PURGE		0x3
+#define   AR8216_ATU_OP_FLUSH_UNLOCKED	0x4
+#define   AR8216_ATU_OP_FLUSH_PORT	0x5
+#define   AR8216_ATU_OP_GET_NEXT	0x6
+#define   AR8216_ATU_ACTIVE		BIT(3)
+#define   AR8216_ATU_PORT_NUM		BITS(8, 4)
+#define   AR8216_ATU_PORT_NUM_S		8
+#define   AR8216_ATU_FULL_VIO		BIT(12)
+#define   AR8216_ATU_ADDR5		BITS(16, 8)
+#define   AR8216_ATU_ADDR5_S		16
+#define   AR8216_ATU_ADDR4		BITS(24, 8)
+#define   AR8216_ATU_ADDR4_S		24
+
+#define AR8216_REG_ATU_FUNC1		0x0054
+#define   AR8216_ATU_ADDR3		BITS(0, 8)
+#define   AR8216_ATU_ADDR3_S		0
+#define   AR8216_ATU_ADDR2		BITS(8, 8)
+#define   AR8216_ATU_ADDR2_S		8
+#define   AR8216_ATU_ADDR1		BITS(16, 8)
+#define   AR8216_ATU_ADDR1_S		16
+#define   AR8216_ATU_ADDR0		BITS(24, 8)
+#define   AR8216_ATU_ADDR0_S		24
+
+#define AR8216_REG_ATU_FUNC2		0x0058
+#define   AR8216_ATU_PORTS		BITS(0, 6)
+#define   AR8216_ATU_PORTS_S		0
+#define   AR8216_ATU_PORT0		BIT(0)
+#define   AR8216_ATU_PORT1		BIT(1)
+#define   AR8216_ATU_PORT2		BIT(2)
+#define   AR8216_ATU_PORT3		BIT(3)
+#define   AR8216_ATU_PORT4		BIT(4)
+#define   AR8216_ATU_PORT5		BIT(5)
+#define   AR8216_ATU_STATUS		BITS(16, 4)
+#define   AR8216_ATU_STATUS_S		16
+
+#define AR8216_REG_ATU_CTRL		0x005C
+#define   AR8216_ATU_CTRL_AGE_EN	BIT(17)
+#define   AR8216_ATU_CTRL_AGE_TIME	BITS(0, 16)
+#define   AR8216_ATU_CTRL_AGE_TIME_S	0
+#define   AR8236_ATU_CTRL_RES		BIT(20)
+#define   AR8216_ATU_CTRL_LEARN_CHANGE	BIT(18)
+#define   AR8216_ATU_CTRL_RESERVED	BIT(19)
+#define   AR8216_ATU_CTRL_ARP_EN	BIT(20)
+
+#define AR8216_REG_TAG_PRIORITY	0x0070
+
+#define AR8216_REG_SERVICE_TAG		0x0074
+#define  AR8216_SERVICE_TAG_M		BITS(0, 16)
+
+#define AR8216_REG_MIB_FUNC		0x0080
+#define   AR8216_MIB_TIMER		BITS(0, 16)
+#define   AR8216_MIB_AT_HALF_EN		BIT(16)
+#define   AR8216_MIB_BUSY		BIT(17)
+#define   AR8216_MIB_FUNC		BITS(24, 3)
+#define   AR8216_MIB_FUNC_S		24
+#define   AR8216_MIB_FUNC_NO_OP		0x0
+#define   AR8216_MIB_FUNC_FLUSH		0x1
+#define   AR8216_MIB_FUNC_CAPTURE	0x3
+#define   AR8236_MIB_EN			BIT(30)
+
+#define AR8216_REG_GLOBAL_CPUPORT		0x0078
+#define   AR8216_GLOBAL_CPUPORT_MIRROR_PORT	BITS(4, 4)
+#define   AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S	4
+#define   AR8216_GLOBAL_CPUPORT_EN		BIT(8)
+
+#define AR8216_REG_MDIO_CTRL		0x98
+#define   AR8216_MDIO_CTRL_DATA_M	BITS(0, 16)
+#define   AR8216_MDIO_CTRL_REG_ADDR_S	16
+#define   AR8216_MDIO_CTRL_PHY_ADDR_S	21
+#define   AR8216_MDIO_CTRL_CMD_WRITE	0
+#define   AR8216_MDIO_CTRL_CMD_READ	BIT(27)
+#define   AR8216_MDIO_CTRL_MASTER_EN	BIT(30)
+#define   AR8216_MDIO_CTRL_BUSY	BIT(31)
+
+#define AR8216_PORT_OFFSET(_i)		(0x0100 * (_i + 1))
+#define AR8216_REG_PORT_STATUS(_i)	(AR8216_PORT_OFFSET(_i) + 0x0000)
+#define   AR8216_PORT_STATUS_SPEED	BITS(0,2)
+#define   AR8216_PORT_STATUS_SPEED_S	0
+#define   AR8216_PORT_STATUS_TXMAC	BIT(2)
+#define   AR8216_PORT_STATUS_RXMAC	BIT(3)
+#define   AR8216_PORT_STATUS_TXFLOW	BIT(4)
+#define   AR8216_PORT_STATUS_RXFLOW	BIT(5)
+#define   AR8216_PORT_STATUS_DUPLEX	BIT(6)
+#define   AR8216_PORT_STATUS_LINK_UP	BIT(8)
+#define   AR8216_PORT_STATUS_LINK_AUTO	BIT(9)
+#define   AR8216_PORT_STATUS_LINK_PAUSE	BIT(10)
+#define   AR8216_PORT_STATUS_FLOW_CONTROL  BIT(12)
+
+#define AR8216_REG_PORT_CTRL(_i)	(AR8216_PORT_OFFSET(_i) + 0x0004)
+
+/* port forwarding state */
+#define   AR8216_PORT_CTRL_STATE	BITS(0, 3)
+#define   AR8216_PORT_CTRL_STATE_S	0
+
+#define   AR8216_PORT_CTRL_LEARN_LOCK	BIT(7)
+
+/* egress 802.1q mode */
+#define   AR8216_PORT_CTRL_VLAN_MODE	BITS(8, 2)
+#define   AR8216_PORT_CTRL_VLAN_MODE_S	8
+
+#define   AR8216_PORT_CTRL_IGMP_SNOOP	BIT(10)
+#define   AR8216_PORT_CTRL_HEADER	BIT(11)
+#define   AR8216_PORT_CTRL_MAC_LOOP	BIT(12)
+#define   AR8216_PORT_CTRL_SINGLE_VLAN	BIT(13)
+#define   AR8216_PORT_CTRL_LEARN	BIT(14)
+#define   AR8216_PORT_CTRL_MIRROR_TX	BIT(16)
+#define   AR8216_PORT_CTRL_MIRROR_RX	BIT(17)
+
+#define AR8216_REG_PORT_VLAN(_i)	(AR8216_PORT_OFFSET(_i) + 0x0008)
+
+#define   AR8216_PORT_VLAN_DEFAULT_ID	BITS(0, 12)
+#define   AR8216_PORT_VLAN_DEFAULT_ID_S	0
+
+#define   AR8216_PORT_VLAN_DEST_PORTS	BITS(16, 9)
+#define   AR8216_PORT_VLAN_DEST_PORTS_S	16
+
+/* bit0 added to the priority field of egress frames */
+#define   AR8216_PORT_VLAN_TX_PRIO	BIT(27)
+
+/* port default priority */
+#define   AR8216_PORT_VLAN_PRIORITY	BITS(28, 2)
+#define   AR8216_PORT_VLAN_PRIORITY_S	28
+
+/* ingress 802.1q mode */
+#define   AR8216_PORT_VLAN_MODE		BITS(30, 2)
+#define   AR8216_PORT_VLAN_MODE_S	30
+
+#define AR8216_REG_PORT_RATE(_i)	(AR8216_PORT_OFFSET(_i) + 0x000c)
+#define AR8216_REG_PORT_PRIO(_i)	(AR8216_PORT_OFFSET(_i) + 0x0010)
+
+#define AR8216_STATS_RXBROAD		0x00
+#define AR8216_STATS_RXPAUSE		0x04
+#define AR8216_STATS_RXMULTI		0x08
+#define AR8216_STATS_RXFCSERR		0x0c
+#define AR8216_STATS_RXALIGNERR		0x10
+#define AR8216_STATS_RXRUNT		0x14
+#define AR8216_STATS_RXFRAGMENT		0x18
+#define AR8216_STATS_RX64BYTE		0x1c
+#define AR8216_STATS_RX128BYTE		0x20
+#define AR8216_STATS_RX256BYTE		0x24
+#define AR8216_STATS_RX512BYTE		0x28
+#define AR8216_STATS_RX1024BYTE		0x2c
+#define AR8216_STATS_RXMAXBYTE		0x30
+#define AR8216_STATS_RXTOOLONG		0x34
+#define AR8216_STATS_RXGOODBYTE		0x38
+#define AR8216_STATS_RXBADBYTE		0x40
+#define AR8216_STATS_RXOVERFLOW		0x48
+#define AR8216_STATS_FILTERED		0x4c
+#define AR8216_STATS_TXBROAD		0x50
+#define AR8216_STATS_TXPAUSE		0x54
+#define AR8216_STATS_TXMULTI		0x58
+#define AR8216_STATS_TXUNDERRUN		0x5c
+#define AR8216_STATS_TX64BYTE		0x60
+#define AR8216_STATS_TX128BYTE		0x64
+#define AR8216_STATS_TX256BYTE		0x68
+#define AR8216_STATS_TX512BYTE		0x6c
+#define AR8216_STATS_TX1024BYTE		0x70
+#define AR8216_STATS_TXMAXBYTE		0x74
+#define AR8216_STATS_TXOVERSIZE		0x78
+#define AR8216_STATS_TXBYTE		0x7c
+#define AR8216_STATS_TXCOLLISION	0x84
+#define AR8216_STATS_TXABORTCOL		0x88
+#define AR8216_STATS_TXMULTICOL		0x8c
+#define AR8216_STATS_TXSINGLECOL	0x90
+#define AR8216_STATS_TXEXCDEFER		0x94
+#define AR8216_STATS_TXDEFER		0x98
+#define AR8216_STATS_TXLATECOL		0x9c
+
+#define AR8216_MIB_RXB_ID		14	/* RxGoodByte */
+#define AR8216_MIB_TXB_ID		29	/* TxByte */
+
+#define AR8229_REG_OPER_MODE0		0x04
+#define   AR8229_OPER_MODE0_MAC_GMII_EN	BIT(6)
+#define   AR8229_OPER_MODE0_PHY_MII_EN	BIT(10)
+
+#define AR8229_REG_OPER_MODE1		0x08
+#define   AR8229_REG_OPER_MODE1_PHY4_MII_EN	BIT(28)
+
+#define AR8229_REG_QM_CTRL		0x3c
+#define   AR8229_QM_CTRL_ARP_EN		BIT(15)
+
+#define AR8236_REG_PORT_VLAN(_i)	(AR8216_PORT_OFFSET((_i)) + 0x0008)
+#define   AR8236_PORT_VLAN_DEFAULT_ID	BITS(16, 12)
+#define   AR8236_PORT_VLAN_DEFAULT_ID_S	16
+#define   AR8236_PORT_VLAN_PRIORITY	BITS(29, 3)
+#define   AR8236_PORT_VLAN_PRIORITY_S	28
+
+#define AR8236_REG_PORT_VLAN2(_i)	(AR8216_PORT_OFFSET((_i)) + 0x000c)
+#define   AR8236_PORT_VLAN2_MEMBER	BITS(16, 7)
+#define   AR8236_PORT_VLAN2_MEMBER_S	16
+#define   AR8236_PORT_VLAN2_TX_PRIO	BIT(23)
+#define   AR8236_PORT_VLAN2_VLAN_MODE	BITS(30, 2)
+#define   AR8236_PORT_VLAN2_VLAN_MODE_S	30
+
+#define AR8236_STATS_RXBROAD		0x00
+#define AR8236_STATS_RXPAUSE		0x04
+#define AR8236_STATS_RXMULTI		0x08
+#define AR8236_STATS_RXFCSERR		0x0c
+#define AR8236_STATS_RXALIGNERR		0x10
+#define AR8236_STATS_RXRUNT		0x14
+#define AR8236_STATS_RXFRAGMENT		0x18
+#define AR8236_STATS_RX64BYTE		0x1c
+#define AR8236_STATS_RX128BYTE		0x20
+#define AR8236_STATS_RX256BYTE		0x24
+#define AR8236_STATS_RX512BYTE		0x28
+#define AR8236_STATS_RX1024BYTE		0x2c
+#define AR8236_STATS_RX1518BYTE		0x30
+#define AR8236_STATS_RXMAXBYTE		0x34
+#define AR8236_STATS_RXTOOLONG		0x38
+#define AR8236_STATS_RXGOODBYTE		0x3c
+#define AR8236_STATS_RXBADBYTE		0x44
+#define AR8236_STATS_RXOVERFLOW		0x4c
+#define AR8236_STATS_FILTERED		0x50
+#define AR8236_STATS_TXBROAD		0x54
+#define AR8236_STATS_TXPAUSE		0x58
+#define AR8236_STATS_TXMULTI		0x5c
+#define AR8236_STATS_TXUNDERRUN		0x60
+#define AR8236_STATS_TX64BYTE		0x64
+#define AR8236_STATS_TX128BYTE		0x68
+#define AR8236_STATS_TX256BYTE		0x6c
+#define AR8236_STATS_TX512BYTE		0x70
+#define AR8236_STATS_TX1024BYTE		0x74
+#define AR8236_STATS_TX1518BYTE		0x78
+#define AR8236_STATS_TXMAXBYTE		0x7c
+#define AR8236_STATS_TXOVERSIZE		0x80
+#define AR8236_STATS_TXBYTE		0x84
+#define AR8236_STATS_TXCOLLISION	0x8c
+#define AR8236_STATS_TXABORTCOL		0x90
+#define AR8236_STATS_TXMULTICOL		0x94
+#define AR8236_STATS_TXSINGLECOL	0x98
+#define AR8236_STATS_TXEXCDEFER		0x9c
+#define AR8236_STATS_TXDEFER		0xa0
+#define AR8236_STATS_TXLATECOL		0xa4
+
+#define AR8236_MIB_RXB_ID		15	/* RxGoodByte */
+#define AR8236_MIB_TXB_ID		31	/* TxByte */
+
+#define AR8316_REG_POSTRIP			0x0008
+#define   AR8316_POSTRIP_MAC0_GMII_EN		BIT(0)
+#define   AR8316_POSTRIP_MAC0_RGMII_EN		BIT(1)
+#define   AR8316_POSTRIP_PHY4_GMII_EN		BIT(2)
+#define   AR8316_POSTRIP_PHY4_RGMII_EN		BIT(3)
+#define   AR8316_POSTRIP_MAC0_MAC_MODE		BIT(4)
+#define   AR8316_POSTRIP_RTL_MODE		BIT(5)
+#define   AR8316_POSTRIP_RGMII_RXCLK_DELAY_EN	BIT(6)
+#define   AR8316_POSTRIP_RGMII_TXCLK_DELAY_EN	BIT(7)
+#define   AR8316_POSTRIP_SERDES_EN		BIT(8)
+#define   AR8316_POSTRIP_SEL_ANA_RST		BIT(9)
+#define   AR8316_POSTRIP_GATE_25M_EN		BIT(10)
+#define   AR8316_POSTRIP_SEL_CLK25M		BIT(11)
+#define   AR8316_POSTRIP_HIB_PULSE_HW		BIT(12)
+#define   AR8316_POSTRIP_DBG_MODE_I		BIT(13)
+#define   AR8316_POSTRIP_MAC5_MAC_MODE		BIT(14)
+#define   AR8316_POSTRIP_MAC5_PHY_MODE		BIT(15)
+#define   AR8316_POSTRIP_POWER_DOWN_HW		BIT(16)
+#define   AR8316_POSTRIP_LPW_STATE_EN		BIT(17)
+#define   AR8316_POSTRIP_MAN_EN			BIT(18)
+#define   AR8316_POSTRIP_PHY_PLL_ON		BIT(19)
+#define   AR8316_POSTRIP_LPW_EXIT		BIT(20)
+#define   AR8316_POSTRIP_TXDELAY_S0		BIT(21)
+#define   AR8316_POSTRIP_TXDELAY_S1		BIT(22)
+#define   AR8316_POSTRIP_RXDELAY_S0		BIT(23)
+#define   AR8316_POSTRIP_LED_OPEN_EN		BIT(24)
+#define   AR8316_POSTRIP_SPI_EN			BIT(25)
+#define   AR8316_POSTRIP_RXDELAY_S1		BIT(26)
+#define   AR8316_POSTRIP_POWER_ON_SEL		BIT(31)
+
+/* port speed */
+enum {
+        AR8216_PORT_SPEED_10M = 0,
+        AR8216_PORT_SPEED_100M = 1,
+        AR8216_PORT_SPEED_1000M = 2,
+        AR8216_PORT_SPEED_ERR = 3,
+};
+
+/* ingress 802.1q mode */
+enum {
+	AR8216_IN_PORT_ONLY = 0,
+	AR8216_IN_PORT_FALLBACK = 1,
+	AR8216_IN_VLAN_ONLY = 2,
+	AR8216_IN_SECURE = 3
+};
+
+/* egress 802.1q mode */
+enum {
+	AR8216_OUT_KEEP = 0,
+	AR8216_OUT_STRIP_VLAN = 1,
+	AR8216_OUT_ADD_VLAN = 2
+};
+
+/* port forwarding state */
+enum {
+	AR8216_PORT_STATE_DISABLED = 0,
+	AR8216_PORT_STATE_BLOCK = 1,
+	AR8216_PORT_STATE_LISTEN = 2,
+	AR8216_PORT_STATE_LEARN = 3,
+	AR8216_PORT_STATE_FORWARD = 4
+};
+
+/* mib counter type */
+enum {
+	AR8XXX_MIB_BASIC = 0,
+	AR8XXX_MIB_EXTENDED = 1
+};
+
+enum {
+	AR8XXX_VER_AR8216 = 0x01,
+	AR8XXX_VER_AR8236 = 0x03,
+	AR8XXX_VER_AR8316 = 0x10,
+	AR8XXX_VER_AR8327 = 0x12,
+	AR8XXX_VER_AR8337 = 0x13,
+};
+
+#define AR8XXX_NUM_ARL_RECORDS	100
+
+enum arl_op {
+	AR8XXX_ARL_INITIALIZE,
+	AR8XXX_ARL_GET_NEXT
+};
+
+struct arl_entry {
+	u16 portmap;
+	u8 mac[6];
+};
+
+struct ar8xxx_priv;
+
+struct ar8xxx_mib_desc {
+	unsigned int size;
+	unsigned int offset;
+	const char *name;
+	u8 type;
+};
+
+struct ar8xxx_chip {
+	unsigned long caps;
+	bool config_at_probe;
+	bool mii_lo_first;
+
+	/* parameters to calculate REG_PORT_STATS_BASE */
+	unsigned reg_port_stats_start;
+	unsigned reg_port_stats_length;
+
+	unsigned reg_arl_ctrl;
+
+	int (*hw_init)(struct ar8xxx_priv *priv);
+	void (*cleanup)(struct ar8xxx_priv *priv);
+
+	const char *name;
+	int vlans;
+	int ports;
+	const struct switch_dev_ops *swops;
+
+	void (*init_globals)(struct ar8xxx_priv *priv);
+	void (*init_port)(struct ar8xxx_priv *priv, int port);
+	void (*setup_port)(struct ar8xxx_priv *priv, int port, u32 members);
+	u32 (*read_port_status)(struct ar8xxx_priv *priv, int port);
+	u32 (*read_port_eee_status)(struct ar8xxx_priv *priv, int port);
+	int (*atu_flush)(struct ar8xxx_priv *priv);
+	int (*atu_flush_port)(struct ar8xxx_priv *priv, int port);
+	void (*vtu_flush)(struct ar8xxx_priv *priv);
+	void (*vtu_load_vlan)(struct ar8xxx_priv *priv, u32 vid, u32 port_mask);
+	void (*phy_fixup)(struct ar8xxx_priv *priv, int phy);
+	void (*set_mirror_regs)(struct ar8xxx_priv *priv);
+	void (*get_arl_entry)(struct ar8xxx_priv *priv, struct arl_entry *a,
+			      u32 *status, enum arl_op op);
+	int (*sw_hw_apply)(struct switch_dev *dev);
+	void (*phy_rgmii_set)(struct ar8xxx_priv *priv, struct phy_device *phydev);
+	int (*phy_read)(struct ar8xxx_priv *priv, int addr, int regnum);
+	int (*phy_write)(struct ar8xxx_priv *priv, int addr, int regnum, u16 val);
+
+	const struct ar8xxx_mib_desc *mib_decs;
+	unsigned num_mibs;
+	unsigned mib_func;
+	int mib_rxb_id;
+	int mib_txb_id;
+};
+
+struct ar8xxx_priv {
+	struct switch_dev dev;
+	struct mii_bus *mii_bus;
+	struct mii_bus *sw_mii_bus;
+	struct phy_device *phy;
+	struct device *pdev;
+
+	int (*get_port_link)(unsigned port);
+
+	const struct net_device_ops *ndo_old;
+	struct net_device_ops ndo;
+	struct mutex reg_mutex;
+	u8 chip_ver;
+	u8 chip_rev;
+	const struct ar8xxx_chip *chip;
+	void *chip_data;
+	bool initialized;
+	bool port4_phy;
+	char buf[2048];
+	struct arl_entry arl_table[AR8XXX_NUM_ARL_RECORDS];
+	char arl_buf[AR8XXX_NUM_ARL_RECORDS * 32 + 256];
+	bool link_up[AR8X16_MAX_PORTS];
+
+	bool init;
+
+	struct mutex mib_lock;
+	struct delayed_work mib_work;
+	u64 *mib_stats;
+	u32 mib_poll_interval;
+	u8 mib_type;
+
+	struct list_head list;
+	unsigned int use_count;
+
+	/* all fields below are cleared on reset */
+	bool vlan;
+
+	u16 vlan_id[AR8XXX_MAX_VLANS];
+	u8 vlan_table[AR8XXX_MAX_VLANS];
+	u8 vlan_tagged;
+	u16 pvid[AR8X16_MAX_PORTS];
+	int arl_age_time;
+
+	/* mirroring */
+	bool mirror_rx;
+	bool mirror_tx;
+	int source_port;
+	int monitor_port;
+	u8 port_vlan_prio[AR8X16_MAX_PORTS];
+};
+
+u32
+ar8xxx_mii_read32(struct ar8xxx_priv *priv, int phy_id, int regnum);
+void
+ar8xxx_mii_write32(struct ar8xxx_priv *priv, int phy_id, int regnum, u32 val);
+u32
+ar8xxx_read(struct ar8xxx_priv *priv, int reg);
+void
+ar8xxx_write(struct ar8xxx_priv *priv, int reg, u32 val);
+u32
+ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val);
+
+void
+ar8xxx_phy_dbg_read(struct ar8xxx_priv *priv, int phy_addr,
+		u16 dbg_addr, u16 *dbg_data);
+void
+ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr,
+		     u16 dbg_addr, u16 dbg_data);
+void
+ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg, u16 data);
+u16
+ar8xxx_phy_mmd_read(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg);
+void
+ar8xxx_phy_init(struct ar8xxx_priv *priv);
+int
+ar8xxx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr,
+		   struct switch_val *val);
+int
+ar8xxx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr,
+		   struct switch_val *val);
+int
+ar8xxx_sw_set_reset_mibs(struct switch_dev *dev,
+			 const struct switch_attr *attr,
+			 struct switch_val *val);
+int
+ar8xxx_sw_set_mib_poll_interval(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val);
+int
+ar8xxx_sw_get_mib_poll_interval(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val);
+int
+ar8xxx_sw_set_mib_type(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val);
+int
+ar8xxx_sw_get_mib_type(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val);
+int
+ar8xxx_sw_set_mirror_rx_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val);
+int
+ar8xxx_sw_get_mirror_rx_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val);
+int
+ar8xxx_sw_set_mirror_tx_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val);
+int
+ar8xxx_sw_get_mirror_tx_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val);
+int
+ar8xxx_sw_set_mirror_monitor_port(struct switch_dev *dev,
+				  const struct switch_attr *attr,
+				  struct switch_val *val);
+int
+ar8xxx_sw_get_mirror_monitor_port(struct switch_dev *dev,
+				  const struct switch_attr *attr,
+				  struct switch_val *val);
+int
+ar8xxx_sw_set_mirror_source_port(struct switch_dev *dev,
+				 const struct switch_attr *attr,
+				 struct switch_val *val);
+int
+ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev,
+				 const struct switch_attr *attr,
+				 struct switch_val *val);
+int
+ar8xxx_sw_set_pvid(struct switch_dev *dev, int port, int vlan);
+int
+ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan);
+int
+ar8xxx_sw_hw_apply(struct switch_dev *dev);
+int
+ar8xxx_sw_reset_switch(struct switch_dev *dev);
+int
+ar8xxx_sw_get_port_link(struct switch_dev *dev, int port,
+			struct switch_port_link *link);
+int
+ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev,
+                             const struct switch_attr *attr,
+                             struct switch_val *val);
+int
+ar8xxx_sw_get_port_mib(struct switch_dev *dev,
+                       const struct switch_attr *attr,
+                       struct switch_val *val);
+int
+ar8xxx_sw_get_arl_age_time(struct switch_dev *dev,
+			   const struct switch_attr *attr,
+			   struct switch_val *val);
+int
+ar8xxx_sw_set_arl_age_time(struct switch_dev *dev,
+			   const struct switch_attr *attr,
+			   struct switch_val *val);
+int
+ar8xxx_sw_get_arl_table(struct switch_dev *dev,
+			const struct switch_attr *attr,
+			struct switch_val *val);
+int
+ar8xxx_sw_set_flush_arl_table(struct switch_dev *dev,
+			      const struct switch_attr *attr,
+			      struct switch_val *val);
+int
+ar8xxx_sw_set_flush_port_arl_table(struct switch_dev *dev,
+				   const struct switch_attr *attr,
+				   struct switch_val *val);
+int
+ar8xxx_sw_get_port_stats(struct switch_dev *dev, int port,
+			struct switch_port_stats *stats);
+int
+ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val);
+
+static inline struct ar8xxx_priv *
+swdev_to_ar8xxx(struct switch_dev *swdev)
+{
+	return container_of(swdev, struct ar8xxx_priv, dev);
+}
+
+static inline bool ar8xxx_has_gige(struct ar8xxx_priv *priv)
+{
+	return priv->chip->caps & AR8XXX_CAP_GIGE;
+}
+
+static inline bool ar8xxx_has_mib_counters(struct ar8xxx_priv *priv)
+{
+	return priv->chip->caps & AR8XXX_CAP_MIB_COUNTERS;
+}
+
+static inline bool chip_is_ar8216(struct ar8xxx_priv *priv)
+{
+	return priv->chip_ver == AR8XXX_VER_AR8216;
+}
+
+static inline bool chip_is_ar8236(struct ar8xxx_priv *priv)
+{
+	return priv->chip_ver == AR8XXX_VER_AR8236;
+}
+
+static inline bool chip_is_ar8316(struct ar8xxx_priv *priv)
+{
+	return priv->chip_ver == AR8XXX_VER_AR8316;
+}
+
+static inline bool chip_is_ar8327(struct ar8xxx_priv *priv)
+{
+	return priv->chip_ver == AR8XXX_VER_AR8327;
+}
+
+static inline bool chip_is_ar8337(struct ar8xxx_priv *priv)
+{
+	return priv->chip_ver == AR8XXX_VER_AR8337;
+}
+
+static inline void
+ar8xxx_reg_set(struct ar8xxx_priv *priv, int reg, u32 val)
+{
+	ar8xxx_rmw(priv, reg, 0, val);
+}
+
+static inline void
+ar8xxx_reg_clear(struct ar8xxx_priv *priv, int reg, u32 val)
+{
+	ar8xxx_rmw(priv, reg, val, 0);
+}
+
+static inline void
+split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page)
+{
+	regaddr >>= 1;
+	*r1 = regaddr & 0x1e;
+
+	regaddr >>= 5;
+	*r2 = regaddr & 0x7;
+
+	regaddr >>= 3;
+	*page = regaddr & 0x1ff;
+}
+
+static inline void
+wait_for_page_switch(void)
+{
+	udelay(5);
+}
+
+#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/ar8327.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/ar8327.c
new file mode 100644
index 0000000..dce52ce
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/ar8327.c
@@ -0,0 +1,1550 @@
+/*
+ * ar8327.c: AR8216 switch driver
+ *
+ * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/list.h>
+#include <linux/bitops.h>
+#include <linux/switch.h>
+#include <linux/delay.h>
+#include <linux/phy.h>
+#include <linux/lockdep.h>
+#include <linux/ar8216_platform.h>
+#include <linux/workqueue.h>
+#include <linux/of_device.h>
+#include <linux/leds.h>
+#include <linux/mdio.h>
+
+#include "ar8216.h"
+#include "ar8327.h"
+
+extern const struct ar8xxx_mib_desc ar8236_mibs[39];
+extern const struct switch_attr ar8xxx_sw_attr_vlan[1];
+
+static u32
+ar8327_get_pad_cfg(struct ar8327_pad_cfg *cfg)
+{
+	u32 t;
+
+	if (!cfg)
+		return 0;
+
+	t = 0;
+	switch (cfg->mode) {
+	case AR8327_PAD_NC:
+		break;
+
+	case AR8327_PAD_MAC2MAC_MII:
+		t = AR8327_PAD_MAC_MII_EN;
+		if (cfg->rxclk_sel)
+			t |= AR8327_PAD_MAC_MII_RXCLK_SEL;
+		if (cfg->txclk_sel)
+			t |= AR8327_PAD_MAC_MII_TXCLK_SEL;
+		break;
+
+	case AR8327_PAD_MAC2MAC_GMII:
+		t = AR8327_PAD_MAC_GMII_EN;
+		if (cfg->rxclk_sel)
+			t |= AR8327_PAD_MAC_GMII_RXCLK_SEL;
+		if (cfg->txclk_sel)
+			t |= AR8327_PAD_MAC_GMII_TXCLK_SEL;
+		break;
+
+	case AR8327_PAD_MAC_SGMII:
+		t = AR8327_PAD_SGMII_EN;
+
+		/*
+		 * WAR for the QUalcomm Atheros AP136 board.
+		 * It seems that RGMII TX/RX delay settings needs to be
+		 * applied for SGMII mode as well, The ethernet is not
+		 * reliable without this.
+		 */
+		t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S;
+		t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S;
+		if (cfg->rxclk_delay_en)
+			t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN;
+		if (cfg->txclk_delay_en)
+			t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN;
+
+		if (cfg->sgmii_delay_en)
+			t |= AR8327_PAD_SGMII_DELAY_EN;
+
+		break;
+
+	case AR8327_PAD_MAC2PHY_MII:
+		t = AR8327_PAD_PHY_MII_EN;
+		if (cfg->rxclk_sel)
+			t |= AR8327_PAD_PHY_MII_RXCLK_SEL;
+		if (cfg->txclk_sel)
+			t |= AR8327_PAD_PHY_MII_TXCLK_SEL;
+		break;
+
+	case AR8327_PAD_MAC2PHY_GMII:
+		t = AR8327_PAD_PHY_GMII_EN;
+		if (cfg->pipe_rxclk_sel)
+			t |= AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL;
+		if (cfg->rxclk_sel)
+			t |= AR8327_PAD_PHY_GMII_RXCLK_SEL;
+		if (cfg->txclk_sel)
+			t |= AR8327_PAD_PHY_GMII_TXCLK_SEL;
+		break;
+
+	case AR8327_PAD_MAC_RGMII:
+		t = AR8327_PAD_RGMII_EN;
+		t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S;
+		t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S;
+		if (cfg->rxclk_delay_en)
+			t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN;
+		if (cfg->txclk_delay_en)
+			t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN;
+		break;
+
+	case AR8327_PAD_PHY_GMII:
+		t = AR8327_PAD_PHYX_GMII_EN;
+		break;
+
+	case AR8327_PAD_PHY_RGMII:
+		t = AR8327_PAD_PHYX_RGMII_EN;
+		break;
+
+	case AR8327_PAD_PHY_MII:
+		t = AR8327_PAD_PHYX_MII_EN;
+		break;
+	}
+
+	return t;
+}
+
+static void
+ar8327_phy_rgmii_set(struct ar8xxx_priv *priv, struct phy_device *phydev)
+{
+	u16 phy_val = 0;
+	int phyaddr = phydev->mdio.addr;
+	struct device_node *np = phydev->mdio.dev.of_node;
+
+	if (!np)
+		return;
+
+	if (!of_property_read_bool(np, "qca,phy-rgmii-en")) {
+		pr_err("ar8327: qca,phy-rgmii-en is not specified\n");
+		return;
+	}
+	ar8xxx_phy_dbg_read(priv, phyaddr,
+				AR8327_PHY_MODE_SEL, &phy_val);
+	phy_val |= AR8327_PHY_MODE_SEL_RGMII;
+	ar8xxx_phy_dbg_write(priv, phyaddr,
+				AR8327_PHY_MODE_SEL, phy_val);
+
+	/* set rgmii tx clock delay if needed */
+	if (!of_property_read_bool(np, "qca,txclk-delay-en")) {
+		pr_err("ar8327: qca,txclk-delay-en is not specified\n");
+		return;
+	}
+	ar8xxx_phy_dbg_read(priv, phyaddr,
+				AR8327_PHY_SYS_CTRL, &phy_val);
+	phy_val |= AR8327_PHY_SYS_CTRL_RGMII_TX_DELAY;
+	ar8xxx_phy_dbg_write(priv, phyaddr,
+				AR8327_PHY_SYS_CTRL, phy_val);
+
+	/* set rgmii rx clock delay if needed */
+	if (!of_property_read_bool(np, "qca,rxclk-delay-en")) {
+		pr_err("ar8327: qca,rxclk-delay-en is not specified\n");
+		return;
+	}
+	ar8xxx_phy_dbg_read(priv, phyaddr,
+				AR8327_PHY_TEST_CTRL, &phy_val);
+	phy_val |= AR8327_PHY_TEST_CTRL_RGMII_RX_DELAY;
+	ar8xxx_phy_dbg_write(priv, phyaddr,
+				AR8327_PHY_TEST_CTRL, phy_val);
+}
+
+static void
+ar8327_phy_fixup(struct ar8xxx_priv *priv, int phy)
+{
+	switch (priv->chip_rev) {
+	case 1:
+		/* For 100M waveform */
+		ar8xxx_phy_dbg_write(priv, phy, 0, 0x02ea);
+		/* Turn on Gigabit clock */
+		ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x68a0);
+		break;
+
+	case 2:
+		ar8xxx_phy_mmd_write(priv, phy, 0x7, 0x3c, 0x0);
+		/* fallthrough */
+	case 4:
+		ar8xxx_phy_mmd_write(priv, phy, 0x3, 0x800d, 0x803f);
+		ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x6860);
+		ar8xxx_phy_dbg_write(priv, phy, 0x5, 0x2c46);
+		ar8xxx_phy_dbg_write(priv, phy, 0x3c, 0x6000);
+		break;
+	}
+}
+
+static u32
+ar8327_get_port_init_status(struct ar8327_port_cfg *cfg)
+{
+	u32 t;
+
+	if (!cfg->force_link)
+		return AR8216_PORT_STATUS_LINK_AUTO;
+
+	t = AR8216_PORT_STATUS_TXMAC | AR8216_PORT_STATUS_RXMAC;
+	t |= cfg->duplex ? AR8216_PORT_STATUS_DUPLEX : 0;
+	t |= cfg->rxpause ? AR8216_PORT_STATUS_RXFLOW : 0;
+	t |= cfg->txpause ? AR8216_PORT_STATUS_TXFLOW : 0;
+
+	switch (cfg->speed) {
+	case AR8327_PORT_SPEED_10:
+		t |= AR8216_PORT_SPEED_10M;
+		break;
+	case AR8327_PORT_SPEED_100:
+		t |= AR8216_PORT_SPEED_100M;
+		break;
+	case AR8327_PORT_SPEED_1000:
+		t |= AR8216_PORT_SPEED_1000M;
+		break;
+	}
+
+	return t;
+}
+
+#define AR8327_LED_ENTRY(_num, _reg, _shift) \
+	[_num] = { .reg = (_reg), .shift = (_shift) }
+
+static const struct ar8327_led_entry
+ar8327_led_map[AR8327_NUM_LEDS] = {
+	AR8327_LED_ENTRY(AR8327_LED_PHY0_0, 0, 14),
+	AR8327_LED_ENTRY(AR8327_LED_PHY0_1, 1, 14),
+	AR8327_LED_ENTRY(AR8327_LED_PHY0_2, 2, 14),
+
+	AR8327_LED_ENTRY(AR8327_LED_PHY1_0, 3, 8),
+	AR8327_LED_ENTRY(AR8327_LED_PHY1_1, 3, 10),
+	AR8327_LED_ENTRY(AR8327_LED_PHY1_2, 3, 12),
+
+	AR8327_LED_ENTRY(AR8327_LED_PHY2_0, 3, 14),
+	AR8327_LED_ENTRY(AR8327_LED_PHY2_1, 3, 16),
+	AR8327_LED_ENTRY(AR8327_LED_PHY2_2, 3, 18),
+
+	AR8327_LED_ENTRY(AR8327_LED_PHY3_0, 3, 20),
+	AR8327_LED_ENTRY(AR8327_LED_PHY3_1, 3, 22),
+	AR8327_LED_ENTRY(AR8327_LED_PHY3_2, 3, 24),
+
+	AR8327_LED_ENTRY(AR8327_LED_PHY4_0, 0, 30),
+	AR8327_LED_ENTRY(AR8327_LED_PHY4_1, 1, 30),
+	AR8327_LED_ENTRY(AR8327_LED_PHY4_2, 2, 30),
+};
+
+static void
+ar8327_set_led_pattern(struct ar8xxx_priv *priv, unsigned int led_num,
+		       enum ar8327_led_pattern pattern)
+{
+	const struct ar8327_led_entry *entry;
+
+	entry = &ar8327_led_map[led_num];
+	ar8xxx_rmw(priv, AR8327_REG_LED_CTRL(entry->reg),
+		   (3 << entry->shift), pattern << entry->shift);
+}
+
+static void
+ar8327_led_work_func(struct work_struct *work)
+{
+	struct ar8327_led *aled;
+	u8 pattern;
+
+	aled = container_of(work, struct ar8327_led, led_work);
+
+	pattern = aled->pattern;
+
+	ar8327_set_led_pattern(aled->sw_priv, aled->led_num,
+			       pattern);
+}
+
+static void
+ar8327_led_schedule_change(struct ar8327_led *aled, u8 pattern)
+{
+	if (aled->pattern == pattern)
+		return;
+
+	aled->pattern = pattern;
+	schedule_work(&aled->led_work);
+}
+
+static inline struct ar8327_led *
+led_cdev_to_ar8327_led(struct led_classdev *led_cdev)
+{
+	return container_of(led_cdev, struct ar8327_led, cdev);
+}
+
+static int
+ar8327_led_blink_set(struct led_classdev *led_cdev,
+		     unsigned long *delay_on,
+		     unsigned long *delay_off)
+{
+	struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev);
+
+	if (*delay_on == 0 && *delay_off == 0) {
+		*delay_on = 125;
+		*delay_off = 125;
+	}
+
+	if (*delay_on != 125 || *delay_off != 125) {
+		/*
+		 * The hardware only supports blinking at 4Hz. Fall back
+		 * to software implementation in other cases.
+		 */
+		return -EINVAL;
+	}
+
+	spin_lock(&aled->lock);
+
+	aled->enable_hw_mode = false;
+	ar8327_led_schedule_change(aled, AR8327_LED_PATTERN_BLINK);
+
+	spin_unlock(&aled->lock);
+
+	return 0;
+}
+
+static void
+ar8327_led_set_brightness(struct led_classdev *led_cdev,
+			  enum led_brightness brightness)
+{
+	struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev);
+	u8 pattern;
+	bool active;
+
+	active = (brightness != LED_OFF);
+	active ^= aled->active_low;
+
+	pattern = (active) ? AR8327_LED_PATTERN_ON :
+			     AR8327_LED_PATTERN_OFF;
+
+	spin_lock(&aled->lock);
+
+	aled->enable_hw_mode = false;
+	ar8327_led_schedule_change(aled, pattern);
+
+	spin_unlock(&aled->lock);
+}
+
+static ssize_t
+ar8327_led_enable_hw_mode_show(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev);
+	ssize_t ret = 0;
+
+	ret += scnprintf(buf, PAGE_SIZE, "%d\n", aled->enable_hw_mode);
+
+	return ret;
+}
+
+static ssize_t
+ar8327_led_enable_hw_mode_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf,
+				size_t size)
+{
+        struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev);
+	u8 pattern;
+	u8 value;
+	int ret;
+
+	ret = kstrtou8(buf, 10, &value);
+	if (ret < 0)
+		return -EINVAL;
+
+	spin_lock(&aled->lock);
+
+	aled->enable_hw_mode = !!value;
+	if (aled->enable_hw_mode)
+		pattern = AR8327_LED_PATTERN_RULE;
+	else
+		pattern = AR8327_LED_PATTERN_OFF;
+
+	ar8327_led_schedule_change(aled, pattern);
+
+	spin_unlock(&aled->lock);
+
+	return size;
+}
+
+static DEVICE_ATTR(enable_hw_mode,  S_IRUGO | S_IWUSR,
+		   ar8327_led_enable_hw_mode_show,
+		   ar8327_led_enable_hw_mode_store);
+
+static int
+ar8327_led_register(struct ar8327_led *aled)
+{
+	int ret;
+
+	ret = led_classdev_register(NULL, &aled->cdev);
+	if (ret < 0)
+		return ret;
+
+	if (aled->mode == AR8327_LED_MODE_HW) {
+		ret = device_create_file(aled->cdev.dev,
+					 &dev_attr_enable_hw_mode);
+		if (ret)
+			goto err_unregister;
+	}
+
+	return 0;
+
+err_unregister:
+	led_classdev_unregister(&aled->cdev);
+	return ret;
+}
+
+static void
+ar8327_led_unregister(struct ar8327_led *aled)
+{
+	if (aled->mode == AR8327_LED_MODE_HW)
+		device_remove_file(aled->cdev.dev, &dev_attr_enable_hw_mode);
+
+	led_classdev_unregister(&aled->cdev);
+	cancel_work_sync(&aled->led_work);
+}
+
+static int
+ar8327_led_create(struct ar8xxx_priv *priv,
+		  const struct ar8327_led_info *led_info)
+{
+	struct ar8327_data *data = priv->chip_data;
+	struct ar8327_led *aled;
+	int ret;
+
+	if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS))
+		return 0;
+
+	if (!led_info->name)
+		return -EINVAL;
+
+	if (led_info->led_num >= AR8327_NUM_LEDS)
+		return -EINVAL;
+
+	aled = kzalloc(sizeof(*aled) + strlen(led_info->name) + 1,
+		       GFP_KERNEL);
+	if (!aled)
+		return -ENOMEM;
+
+	aled->sw_priv = priv;
+	aled->led_num = led_info->led_num;
+	aled->active_low = led_info->active_low;
+	aled->mode = led_info->mode;
+
+	if (aled->mode == AR8327_LED_MODE_HW)
+		aled->enable_hw_mode = true;
+
+	aled->name = (char *)(aled + 1);
+	strcpy(aled->name, led_info->name);
+
+	aled->cdev.name = aled->name;
+	aled->cdev.brightness_set = ar8327_led_set_brightness;
+	aled->cdev.blink_set = ar8327_led_blink_set;
+	aled->cdev.default_trigger = led_info->default_trigger;
+
+	spin_lock_init(&aled->lock);
+	mutex_init(&aled->mutex);
+	INIT_WORK(&aled->led_work, ar8327_led_work_func);
+
+	ret = ar8327_led_register(aled);
+	if (ret)
+		goto err_free;
+
+	data->leds[data->num_leds++] = aled;
+
+	return 0;
+
+err_free:
+	kfree(aled);
+	return ret;
+}
+
+static void
+ar8327_led_destroy(struct ar8327_led *aled)
+{
+	ar8327_led_unregister(aled);
+	kfree(aled);
+}
+
+static void
+ar8327_leds_init(struct ar8xxx_priv *priv)
+{
+	struct ar8327_data *data = priv->chip_data;
+	unsigned i;
+
+	if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS))
+		return;
+
+	for (i = 0; i < data->num_leds; i++) {
+		struct ar8327_led *aled;
+
+		aled = data->leds[i];
+
+		if (aled->enable_hw_mode)
+			aled->pattern = AR8327_LED_PATTERN_RULE;
+		else
+			aled->pattern = AR8327_LED_PATTERN_OFF;
+
+		ar8327_set_led_pattern(priv, aled->led_num, aled->pattern);
+	}
+}
+
+static void
+ar8327_leds_cleanup(struct ar8xxx_priv *priv)
+{
+	struct ar8327_data *data = priv->chip_data;
+	unsigned i;
+
+	if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS))
+		return;
+
+	for (i = 0; i < data->num_leds; i++) {
+		struct ar8327_led *aled;
+
+		aled = data->leds[i];
+		ar8327_led_destroy(aled);
+	}
+
+	kfree(data->leds);
+}
+
+static int
+ar8327_hw_config_pdata(struct ar8xxx_priv *priv,
+		       struct ar8327_platform_data *pdata)
+{
+	struct ar8327_led_cfg *led_cfg;
+	struct ar8327_data *data = priv->chip_data;
+	u32 pos, new_pos;
+	u32 t;
+
+	if (!pdata)
+		return -EINVAL;
+
+	priv->get_port_link = pdata->get_port_link;
+
+	data->port0_status = ar8327_get_port_init_status(&pdata->port0_cfg);
+	data->port6_status = ar8327_get_port_init_status(&pdata->port6_cfg);
+
+	t = ar8327_get_pad_cfg(pdata->pad0_cfg);
+	if (chip_is_ar8337(priv) && !pdata->pad0_cfg->mac06_exchange_dis)
+	    t |= AR8337_PAD_MAC06_EXCHANGE_EN;
+	ar8xxx_write(priv, AR8327_REG_PAD0_MODE, t);
+
+	t = ar8327_get_pad_cfg(pdata->pad5_cfg);
+	ar8xxx_write(priv, AR8327_REG_PAD5_MODE, t);
+	t = ar8327_get_pad_cfg(pdata->pad6_cfg);
+	ar8xxx_write(priv, AR8327_REG_PAD6_MODE, t);
+
+	pos = ar8xxx_read(priv, AR8327_REG_POWER_ON_STRAP);
+	new_pos = pos;
+
+	led_cfg = pdata->led_cfg;
+	if (led_cfg) {
+		if (led_cfg->open_drain)
+			new_pos |= AR8327_POWER_ON_STRAP_LED_OPEN_EN;
+		else
+			new_pos &= ~AR8327_POWER_ON_STRAP_LED_OPEN_EN;
+
+		ar8xxx_write(priv, AR8327_REG_LED_CTRL0, led_cfg->led_ctrl0);
+		ar8xxx_write(priv, AR8327_REG_LED_CTRL1, led_cfg->led_ctrl1);
+		ar8xxx_write(priv, AR8327_REG_LED_CTRL2, led_cfg->led_ctrl2);
+		ar8xxx_write(priv, AR8327_REG_LED_CTRL3, led_cfg->led_ctrl3);
+
+		if (new_pos != pos)
+			new_pos |= AR8327_POWER_ON_STRAP_POWER_ON_SEL;
+	}
+
+	if (pdata->sgmii_cfg) {
+		t = pdata->sgmii_cfg->sgmii_ctrl;
+		if (priv->chip_rev == 1)
+			t |= AR8327_SGMII_CTRL_EN_PLL |
+			     AR8327_SGMII_CTRL_EN_RX |
+			     AR8327_SGMII_CTRL_EN_TX;
+		else
+			t &= ~(AR8327_SGMII_CTRL_EN_PLL |
+			       AR8327_SGMII_CTRL_EN_RX |
+			       AR8327_SGMII_CTRL_EN_TX);
+
+		ar8xxx_write(priv, AR8327_REG_SGMII_CTRL, t);
+
+		if (pdata->sgmii_cfg->serdes_aen)
+			new_pos &= ~AR8327_POWER_ON_STRAP_SERDES_AEN;
+		else
+			new_pos |= AR8327_POWER_ON_STRAP_SERDES_AEN;
+	}
+
+	ar8xxx_write(priv, AR8327_REG_POWER_ON_STRAP, new_pos);
+
+	if (pdata->leds && pdata->num_leds) {
+		int i;
+
+		data->leds = kzalloc(pdata->num_leds * sizeof(void *),
+				     GFP_KERNEL);
+		if (!data->leds)
+			return -ENOMEM;
+
+		for (i = 0; i < pdata->num_leds; i++)
+			ar8327_led_create(priv, &pdata->leds[i]);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static int
+ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np)
+{
+	struct ar8327_data *data = priv->chip_data;
+	const __be32 *paddr;
+	int len;
+	int i;
+
+	paddr = of_get_property(np, "qca,ar8327-initvals", &len);
+	if (!paddr || len < (2 * sizeof(*paddr)))
+		return -EINVAL;
+
+	len /= sizeof(*paddr);
+
+	for (i = 0; i < len - 1; i += 2) {
+		u32 reg;
+		u32 val;
+
+		reg = be32_to_cpup(paddr + i);
+		val = be32_to_cpup(paddr + i + 1);
+
+		switch (reg) {
+		case AR8327_REG_PORT_STATUS(0):
+			data->port0_status = val;
+			break;
+		case AR8327_REG_PORT_STATUS(6):
+			data->port6_status = val;
+			break;
+		default:
+			ar8xxx_write(priv, reg, val);
+			break;
+		}
+	}
+
+	return 0;
+}
+#else
+static inline int
+ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np)
+{
+	return -EINVAL;
+}
+#endif
+
+static int
+ar8327_hw_init(struct ar8xxx_priv *priv)
+{
+	int ret;
+
+	priv->chip_data = kzalloc(sizeof(struct ar8327_data), GFP_KERNEL);
+	if (!priv->chip_data)
+		return -ENOMEM;
+
+	if (priv->pdev->of_node)
+		ret = ar8327_hw_config_of(priv, priv->pdev->of_node);
+	else
+		ret = ar8327_hw_config_pdata(priv,
+					     priv->phy->mdio.dev.platform_data);
+
+	if (ret)
+		return ret;
+
+	ar8327_leds_init(priv);
+
+	ar8xxx_phy_init(priv);
+
+	return 0;
+}
+
+static void
+ar8327_cleanup(struct ar8xxx_priv *priv)
+{
+	ar8327_leds_cleanup(priv);
+}
+
+static void
+ar8327_init_globals(struct ar8xxx_priv *priv)
+{
+	struct ar8327_data *data = priv->chip_data;
+	u32 t;
+	int i;
+
+	/* enable CPU port and disable mirror port */
+	t = AR8327_FWD_CTRL0_CPU_PORT_EN |
+	    AR8327_FWD_CTRL0_MIRROR_PORT;
+	ar8xxx_write(priv, AR8327_REG_FWD_CTRL0, t);
+
+	/* forward multicast and broadcast frames to CPU */
+	t = (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_UC_FLOOD_S) |
+	    (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_MC_FLOOD_S) |
+	    (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_BC_FLOOD_S);
+	ar8xxx_write(priv, AR8327_REG_FWD_CTRL1, t);
+
+	/* enable jumbo frames */
+	ar8xxx_rmw(priv, AR8327_REG_MAX_FRAME_SIZE,
+		   AR8327_MAX_FRAME_SIZE_MTU, 9018 + 8 + 2);
+
+	/* Enable MIB counters */
+	ar8xxx_reg_set(priv, AR8327_REG_MODULE_EN,
+		       AR8327_MODULE_EN_MIB);
+
+	/* Disable EEE on all phy's due to stability issues */
+	for (i = 0; i < AR8XXX_NUM_PHYS; i++)
+		data->eee[i] = false;
+}
+
+static void
+ar8327_init_port(struct ar8xxx_priv *priv, int port)
+{
+	struct ar8327_data *data = priv->chip_data;
+	u32 t;
+
+	if (port == AR8216_PORT_CPU)
+		t = data->port0_status;
+	else if (port == 6)
+		t = data->port6_status;
+	else
+		t = AR8216_PORT_STATUS_LINK_AUTO;
+
+	if (port != AR8216_PORT_CPU && port != 6) {
+		/*hw limitation:if configure mac when there is traffic,
+		port MAC may work abnormal. Need disable lan&wan mac at fisrt*/
+		ar8xxx_write(priv, AR8327_REG_PORT_STATUS(port), 0);
+		msleep(100);
+		t |= AR8216_PORT_STATUS_FLOW_CONTROL;
+		ar8xxx_write(priv, AR8327_REG_PORT_STATUS(port), t);
+	} else {
+		ar8xxx_write(priv, AR8327_REG_PORT_STATUS(port), t);
+	}
+
+	ar8xxx_write(priv, AR8327_REG_PORT_HEADER(port), 0);
+
+	ar8xxx_write(priv, AR8327_REG_PORT_VLAN0(port), 0);
+
+	t = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH << AR8327_PORT_VLAN1_OUT_MODE_S;
+	ar8xxx_write(priv, AR8327_REG_PORT_VLAN1(port), t);
+
+	t = AR8327_PORT_LOOKUP_LEARN;
+	t |= AR8216_PORT_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S;
+	ar8xxx_write(priv, AR8327_REG_PORT_LOOKUP(port), t);
+}
+
+static u32
+ar8327_read_port_status(struct ar8xxx_priv *priv, int port)
+{
+	u32 t;
+
+	t = ar8xxx_read(priv, AR8327_REG_PORT_STATUS(port));
+	/* map the flow control autoneg result bits to the flow control bits
+	 * used in forced mode to allow ar8216_read_port_link detect
+	 * flow control properly if autoneg is used
+	 */
+	if (t & AR8216_PORT_STATUS_LINK_UP &&
+	    t & AR8216_PORT_STATUS_LINK_AUTO) {
+		t &= ~(AR8216_PORT_STATUS_TXFLOW | AR8216_PORT_STATUS_RXFLOW);
+		if (t & AR8327_PORT_STATUS_TXFLOW_AUTO)
+			t |= AR8216_PORT_STATUS_TXFLOW;
+		if (t & AR8327_PORT_STATUS_RXFLOW_AUTO)
+			t |= AR8216_PORT_STATUS_RXFLOW;
+	}
+
+	return t;
+}
+
+static u32
+ar8327_read_port_eee_status(struct ar8xxx_priv *priv, int port)
+{
+	int phy;
+	u16 t;
+
+	if (port >= priv->dev.ports)
+		return 0;
+
+	if (port == 0 || port == 6)
+		return 0;
+
+	phy = port - 1;
+
+	/* EEE Ability Auto-negotiation Result */
+	t = ar8xxx_phy_mmd_read(priv, phy, 0x7, 0x8000);
+
+	return mmd_eee_adv_to_ethtool_adv_t(t);
+}
+
+static int
+ar8327_atu_flush(struct ar8xxx_priv *priv)
+{
+	int ret;
+
+	ret = ar8216_wait_bit(priv, AR8327_REG_ATU_FUNC,
+			      AR8327_ATU_FUNC_BUSY, 0);
+	if (!ret)
+		ar8xxx_write(priv, AR8327_REG_ATU_FUNC,
+			     AR8327_ATU_FUNC_OP_FLUSH |
+			     AR8327_ATU_FUNC_BUSY);
+
+	return ret;
+}
+
+static int
+ar8327_atu_flush_port(struct ar8xxx_priv *priv, int port)
+{
+	u32 t;
+	int ret;
+
+	ret = ar8216_wait_bit(priv, AR8327_REG_ATU_FUNC,
+			      AR8327_ATU_FUNC_BUSY, 0);
+	if (!ret) {
+		t = (port << AR8327_ATU_PORT_NUM_S);
+		t |= AR8327_ATU_FUNC_OP_FLUSH_PORT;
+		t |= AR8327_ATU_FUNC_BUSY;
+		ar8xxx_write(priv, AR8327_REG_ATU_FUNC, t);
+	}
+
+	return ret;
+}
+
+static int
+ar8327_get_port_igmp(struct ar8xxx_priv *priv, int port)
+{
+	u32 fwd_ctrl, frame_ack;
+
+	fwd_ctrl = (BIT(port) << AR8327_FWD_CTRL1_IGMP_S);
+	frame_ack = ((AR8327_FRAME_ACK_CTRL_IGMP_MLD |
+		      AR8327_FRAME_ACK_CTRL_IGMP_JOIN |
+		      AR8327_FRAME_ACK_CTRL_IGMP_LEAVE) <<
+		     AR8327_FRAME_ACK_CTRL_S(port));
+
+	return (ar8xxx_read(priv, AR8327_REG_FWD_CTRL1) &
+			fwd_ctrl) == fwd_ctrl &&
+		(ar8xxx_read(priv, AR8327_REG_FRAME_ACK_CTRL(port)) &
+			frame_ack) == frame_ack;
+}
+
+static void
+ar8327_set_port_igmp(struct ar8xxx_priv *priv, int port, int enable)
+{
+	int reg_frame_ack = AR8327_REG_FRAME_ACK_CTRL(port);
+	u32 val_frame_ack = (AR8327_FRAME_ACK_CTRL_IGMP_MLD |
+			  AR8327_FRAME_ACK_CTRL_IGMP_JOIN |
+			  AR8327_FRAME_ACK_CTRL_IGMP_LEAVE) <<
+			 AR8327_FRAME_ACK_CTRL_S(port);
+
+	if (enable) {
+		ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL1,
+			   BIT(port) << AR8327_FWD_CTRL1_MC_FLOOD_S,
+			   BIT(port) << AR8327_FWD_CTRL1_IGMP_S);
+		ar8xxx_reg_set(priv, reg_frame_ack, val_frame_ack);
+	} else {
+		ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL1,
+			   BIT(port) << AR8327_FWD_CTRL1_IGMP_S,
+			   BIT(port) << AR8327_FWD_CTRL1_MC_FLOOD_S);
+		ar8xxx_reg_clear(priv, reg_frame_ack, val_frame_ack);
+	}
+}
+
+static void
+ar8327_vtu_op(struct ar8xxx_priv *priv, u32 op, u32 val)
+{
+	if (ar8216_wait_bit(priv, AR8327_REG_VTU_FUNC1,
+			    AR8327_VTU_FUNC1_BUSY, 0))
+		return;
+
+	if ((op & AR8327_VTU_FUNC1_OP) == AR8327_VTU_FUNC1_OP_LOAD)
+		ar8xxx_write(priv, AR8327_REG_VTU_FUNC0, val);
+
+	op |= AR8327_VTU_FUNC1_BUSY;
+	ar8xxx_write(priv, AR8327_REG_VTU_FUNC1, op);
+}
+
+static void
+ar8327_vtu_flush(struct ar8xxx_priv *priv)
+{
+	ar8327_vtu_op(priv, AR8327_VTU_FUNC1_OP_FLUSH, 0);
+}
+
+static void
+ar8327_vtu_load_vlan(struct ar8xxx_priv *priv, u32 vid, u32 port_mask)
+{
+	u32 op;
+	u32 val;
+	int i;
+
+	op = AR8327_VTU_FUNC1_OP_LOAD | (vid << AR8327_VTU_FUNC1_VID_S);
+	val = AR8327_VTU_FUNC0_VALID | AR8327_VTU_FUNC0_IVL;
+	for (i = 0; i < AR8327_NUM_PORTS; i++) {
+		u32 mode;
+
+		if ((port_mask & BIT(i)) == 0)
+			mode = AR8327_VTU_FUNC0_EG_MODE_NOT;
+		else if (priv->vlan == 0)
+			mode = AR8327_VTU_FUNC0_EG_MODE_KEEP;
+		else if ((priv->vlan_tagged & BIT(i)) || (priv->vlan_id[priv->pvid[i]] != vid))
+			mode = AR8327_VTU_FUNC0_EG_MODE_TAG;
+		else
+			mode = AR8327_VTU_FUNC0_EG_MODE_UNTAG;
+
+		val |= mode << AR8327_VTU_FUNC0_EG_MODE_S(i);
+	}
+	ar8327_vtu_op(priv, op, val);
+}
+
+static void
+ar8327_setup_port(struct ar8xxx_priv *priv, int port, u32 members)
+{
+	u32 t;
+	u32 egress, ingress;
+	u32 pvid = priv->vlan_id[priv->pvid[port]];
+
+	if (priv->vlan) {
+		egress = AR8327_PORT_VLAN1_OUT_MODE_UNMOD;
+		ingress = AR8216_IN_SECURE;
+	} else {
+		egress = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH;
+		ingress = AR8216_IN_PORT_ONLY;
+	}
+
+	t = pvid << AR8327_PORT_VLAN0_DEF_SVID_S;
+	t |= pvid << AR8327_PORT_VLAN0_DEF_CVID_S;
+	if (priv->vlan && priv->port_vlan_prio[port]) {
+		u32 prio = priv->port_vlan_prio[port];
+
+		t |= prio << AR8327_PORT_VLAN0_DEF_SPRI_S;
+		t |= prio << AR8327_PORT_VLAN0_DEF_CPRI_S;
+	}
+	ar8xxx_write(priv, AR8327_REG_PORT_VLAN0(port), t);
+
+	t = AR8327_PORT_VLAN1_PORT_VLAN_PROP;
+	t |= egress << AR8327_PORT_VLAN1_OUT_MODE_S;
+	if (priv->vlan && priv->port_vlan_prio[port])
+		t |= AR8327_PORT_VLAN1_VLAN_PRI_PROP;
+
+	ar8xxx_write(priv, AR8327_REG_PORT_VLAN1(port), t);
+
+	t = members;
+	t |= AR8327_PORT_LOOKUP_LEARN;
+	t |= ingress << AR8327_PORT_LOOKUP_IN_MODE_S;
+	t |= AR8216_PORT_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S;
+	ar8xxx_write(priv, AR8327_REG_PORT_LOOKUP(port), t);
+}
+
+static int
+ar8327_sw_get_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	u8 ports = priv->vlan_table[val->port_vlan];
+	int i;
+
+	val->len = 0;
+	for (i = 0; i < dev->ports; i++) {
+		struct switch_port *p;
+
+		if (!(ports & (1 << i)))
+			continue;
+
+		p = &val->value.ports[val->len++];
+		p->id = i;
+		if ((priv->vlan_tagged & (1 << i)) || (priv->pvid[i] != val->port_vlan))
+			p->flags = (1 << SWITCH_PORT_FLAG_TAGGED);
+		else
+			p->flags = 0;
+	}
+	return 0;
+}
+
+static int
+ar8327_sw_set_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	u8 *vt = &priv->vlan_table[val->port_vlan];
+	int i;
+
+	*vt = 0;
+	for (i = 0; i < val->len; i++) {
+		struct switch_port *p = &val->value.ports[i];
+
+		if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) {
+			if (val->port_vlan == priv->pvid[p->id]) {
+				priv->vlan_tagged |= (1 << p->id);
+			}
+		} else {
+			priv->vlan_tagged &= ~(1 << p->id);
+			priv->pvid[p->id] = val->port_vlan;
+		}
+
+		*vt |= 1 << p->id;
+	}
+	return 0;
+}
+
+static void
+ar8327_set_mirror_regs(struct ar8xxx_priv *priv)
+{
+	int port;
+
+	/* reset all mirror registers */
+	ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0,
+		   AR8327_FWD_CTRL0_MIRROR_PORT,
+		   (0xF << AR8327_FWD_CTRL0_MIRROR_PORT_S));
+	for (port = 0; port < AR8327_NUM_PORTS; port++) {
+		ar8xxx_reg_clear(priv, AR8327_REG_PORT_LOOKUP(port),
+			   AR8327_PORT_LOOKUP_ING_MIRROR_EN);
+
+		ar8xxx_reg_clear(priv, AR8327_REG_PORT_HOL_CTRL1(port),
+			   AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN);
+	}
+
+	/* now enable mirroring if necessary */
+	if (priv->source_port >= AR8327_NUM_PORTS ||
+	    priv->monitor_port >= AR8327_NUM_PORTS ||
+	    priv->source_port == priv->monitor_port) {
+		return;
+	}
+
+	ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0,
+		   AR8327_FWD_CTRL0_MIRROR_PORT,
+		   (priv->monitor_port << AR8327_FWD_CTRL0_MIRROR_PORT_S));
+
+	if (priv->mirror_rx)
+		ar8xxx_reg_set(priv, AR8327_REG_PORT_LOOKUP(priv->source_port),
+			   AR8327_PORT_LOOKUP_ING_MIRROR_EN);
+
+	if (priv->mirror_tx)
+		ar8xxx_reg_set(priv, AR8327_REG_PORT_HOL_CTRL1(priv->source_port),
+			   AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN);
+}
+
+static int
+ar8327_sw_set_eee(struct switch_dev *dev,
+		  const struct switch_attr *attr,
+		  struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	struct ar8327_data *data = priv->chip_data;
+	int port = val->port_vlan;
+	int phy;
+
+	if (port >= dev->ports)
+		return -EINVAL;
+	if (port == 0 || port == 6)
+		return -EOPNOTSUPP;
+
+	phy = port - 1;
+
+	data->eee[phy] = !!(val->value.i);
+
+	return 0;
+}
+
+static int
+ar8327_sw_get_eee(struct switch_dev *dev,
+		  const struct switch_attr *attr,
+		  struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	const struct ar8327_data *data = priv->chip_data;
+	int port = val->port_vlan;
+	int phy;
+
+	if (port >= dev->ports)
+		return -EINVAL;
+	if (port == 0 || port == 6)
+		return -EOPNOTSUPP;
+
+	phy = port - 1;
+
+	val->value.i = data->eee[phy];
+
+	return 0;
+}
+
+static void
+ar8327_wait_atu_ready(struct ar8xxx_priv *priv, u16 r2, u16 r1)
+{
+	int timeout = 20;
+
+	while (ar8xxx_mii_read32(priv, r2, r1) & AR8327_ATU_FUNC_BUSY && --timeout) {
+		udelay(10);
+		cond_resched();
+	}
+
+	if (!timeout)
+		pr_err("ar8327: timeout waiting for atu to become ready\n");
+}
+
+static void ar8327_get_arl_entry(struct ar8xxx_priv *priv,
+				 struct arl_entry *a, u32 *status, enum arl_op op)
+{
+	struct mii_bus *bus = priv->mii_bus;
+	u16 r2, page;
+	u16 r1_data0, r1_data1, r1_data2, r1_func;
+	u32 val0, val1, val2;
+
+	split_addr(AR8327_REG_ATU_DATA0, &r1_data0, &r2, &page);
+	r2 |= 0x10;
+
+	r1_data1 = (AR8327_REG_ATU_DATA1 >> 1) & 0x1e;
+	r1_data2 = (AR8327_REG_ATU_DATA2 >> 1) & 0x1e;
+	r1_func  = (AR8327_REG_ATU_FUNC >> 1) & 0x1e;
+
+	switch (op) {
+	case AR8XXX_ARL_INITIALIZE:
+		/* all ATU registers are on the same page
+		* therefore set page only once
+		*/
+		bus->write(bus, 0x18, 0, page);
+		wait_for_page_switch();
+
+		ar8327_wait_atu_ready(priv, r2, r1_func);
+
+		ar8xxx_mii_write32(priv, r2, r1_data0, 0);
+		ar8xxx_mii_write32(priv, r2, r1_data1, 0);
+		ar8xxx_mii_write32(priv, r2, r1_data2, 0);
+		break;
+	case AR8XXX_ARL_GET_NEXT:
+		ar8xxx_mii_write32(priv, r2, r1_func,
+				   AR8327_ATU_FUNC_OP_GET_NEXT |
+				   AR8327_ATU_FUNC_BUSY);
+		ar8327_wait_atu_ready(priv, r2, r1_func);
+
+		val0 = ar8xxx_mii_read32(priv, r2, r1_data0);
+		val1 = ar8xxx_mii_read32(priv, r2, r1_data1);
+		val2 = ar8xxx_mii_read32(priv, r2, r1_data2);
+
+		*status = val2 & AR8327_ATU_STATUS;
+		if (!*status)
+			break;
+
+		a->portmap = (val1 & AR8327_ATU_PORTS) >> AR8327_ATU_PORTS_S;
+		a->mac[0] = (val0 & AR8327_ATU_ADDR0) >> AR8327_ATU_ADDR0_S;
+		a->mac[1] = (val0 & AR8327_ATU_ADDR1) >> AR8327_ATU_ADDR1_S;
+		a->mac[2] = (val0 & AR8327_ATU_ADDR2) >> AR8327_ATU_ADDR2_S;
+		a->mac[3] = (val0 & AR8327_ATU_ADDR3) >> AR8327_ATU_ADDR3_S;
+		a->mac[4] = (val1 & AR8327_ATU_ADDR4) >> AR8327_ATU_ADDR4_S;
+		a->mac[5] = (val1 & AR8327_ATU_ADDR5) >> AR8327_ATU_ADDR5_S;
+		break;
+	}
+}
+
+static int
+ar8327_sw_hw_apply(struct switch_dev *dev)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	const struct ar8327_data *data = priv->chip_data;
+	int ret, i;
+
+	ret = ar8xxx_sw_hw_apply(dev);
+	if (ret)
+		return ret;
+
+	for (i=0; i < AR8XXX_NUM_PHYS; i++) {
+		if (data->eee[i])
+			ar8xxx_reg_clear(priv, AR8327_REG_EEE_CTRL,
+			       AR8327_EEE_CTRL_DISABLE_PHY(i));
+		else
+			ar8xxx_reg_set(priv, AR8327_REG_EEE_CTRL,
+			       AR8327_EEE_CTRL_DISABLE_PHY(i));
+	}
+
+	return 0;
+}
+
+int
+ar8327_sw_get_port_igmp_snooping(struct switch_dev *dev,
+				 const struct switch_attr *attr,
+				 struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port = val->port_vlan;
+
+	if (port >= dev->ports)
+		return -EINVAL;
+
+	mutex_lock(&priv->reg_mutex);
+	val->value.i = ar8327_get_port_igmp(priv, port);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_set_port_igmp_snooping(struct switch_dev *dev,
+				 const struct switch_attr *attr,
+				 struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port = val->port_vlan;
+
+	if (port >= dev->ports)
+		return -EINVAL;
+
+	mutex_lock(&priv->reg_mutex);
+	ar8327_set_port_igmp(priv, port, val->value.i);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_get_igmp_snooping(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	int port;
+
+	for (port = 0; port < dev->ports; port++) {
+		val->port_vlan = port;
+		if (ar8327_sw_get_port_igmp_snooping(dev, attr, val) ||
+		    !val->value.i)
+			break;
+	}
+
+	return 0;
+}
+
+int
+ar8327_sw_set_igmp_snooping(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	int port;
+
+	for (port = 0; port < dev->ports; port++) {
+		val->port_vlan = port;
+		if (ar8327_sw_set_port_igmp_snooping(dev, attr, val))
+			break;
+	}
+
+	return 0;
+}
+
+int
+ar8327_sw_get_igmp_v3(struct switch_dev *dev,
+		      const struct switch_attr *attr,
+		      struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	u32 val_reg;
+
+	mutex_lock(&priv->reg_mutex);
+	val_reg = ar8xxx_read(priv, AR8327_REG_FRAME_ACK_CTRL1);
+	val->value.i = ((val_reg & AR8327_FRAME_ACK_CTRL_IGMP_V3_EN) != 0);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_set_igmp_v3(struct switch_dev *dev,
+		      const struct switch_attr *attr,
+		      struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	mutex_lock(&priv->reg_mutex);
+	if (val->value.i)
+		ar8xxx_reg_set(priv, AR8327_REG_FRAME_ACK_CTRL1,
+			       AR8327_FRAME_ACK_CTRL_IGMP_V3_EN);
+	else
+		ar8xxx_reg_clear(priv, AR8327_REG_FRAME_ACK_CTRL1,
+				 AR8327_FRAME_ACK_CTRL_IGMP_V3_EN);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+static int
+ar8327_sw_set_port_vlan_prio(struct switch_dev *dev, const struct switch_attr *attr,
+			     struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port = val->port_vlan;
+
+	if (port >= dev->ports)
+		return -EINVAL;
+	if (port == 0 || port == 6)
+		return -EOPNOTSUPP;
+	if (val->value.i < 0 || val->value.i > 7)
+		return -EINVAL;
+
+	priv->port_vlan_prio[port] = val->value.i;
+
+	return 0;
+}
+
+static int
+ar8327_sw_get_port_vlan_prio(struct switch_dev *dev, const struct switch_attr *attr,
+                  struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port = val->port_vlan;
+
+	val->value.i = priv->port_vlan_prio[port];
+
+	return 0;
+}
+
+static const struct switch_attr ar8327_sw_attr_globals[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.set = ar8xxx_sw_set_vlan,
+		.get = ar8xxx_sw_get_vlan,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mibs",
+		.description = "Reset all MIB counters",
+		.set = ar8xxx_sw_set_reset_mibs,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "ar8xxx_mib_poll_interval",
+		.description = "MIB polling interval in msecs (0 to disable)",
+		.set = ar8xxx_sw_set_mib_poll_interval,
+		.get = ar8xxx_sw_get_mib_poll_interval
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "ar8xxx_mib_type",
+		.description = "MIB type (0=basic 1=extended)",
+		.set = ar8xxx_sw_set_mib_type,
+		.get = ar8xxx_sw_get_mib_type
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_mirror_rx",
+		.description = "Enable mirroring of RX packets",
+		.set = ar8xxx_sw_set_mirror_rx_enable,
+		.get = ar8xxx_sw_get_mirror_rx_enable,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_mirror_tx",
+		.description = "Enable mirroring of TX packets",
+		.set = ar8xxx_sw_set_mirror_tx_enable,
+		.get = ar8xxx_sw_get_mirror_tx_enable,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "mirror_monitor_port",
+		.description = "Mirror monitor port",
+		.set = ar8xxx_sw_set_mirror_monitor_port,
+		.get = ar8xxx_sw_get_mirror_monitor_port,
+		.max = AR8327_NUM_PORTS - 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "mirror_source_port",
+		.description = "Mirror source port",
+		.set = ar8xxx_sw_set_mirror_source_port,
+		.get = ar8xxx_sw_get_mirror_source_port,
+		.max = AR8327_NUM_PORTS - 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "arl_age_time",
+		.description = "ARL age time (secs)",
+		.set = ar8xxx_sw_set_arl_age_time,
+		.get = ar8xxx_sw_get_arl_age_time,
+	},
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "arl_table",
+		.description = "Get ARL table",
+		.set = NULL,
+		.get = ar8xxx_sw_get_arl_table,
+	},
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "flush_arl_table",
+		.description = "Flush ARL table",
+		.set = ar8xxx_sw_set_flush_arl_table,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "igmp_snooping",
+		.description = "Enable IGMP Snooping",
+		.set = ar8327_sw_set_igmp_snooping,
+		.get = ar8327_sw_get_igmp_snooping,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "igmp_v3",
+		.description = "Enable IGMPv3 support",
+		.set = ar8327_sw_set_igmp_v3,
+		.get = ar8327_sw_get_igmp_v3,
+		.max = 1
+	},
+};
+
+static const struct switch_attr ar8327_sw_attr_port[] = {
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mib",
+		.description = "Reset single port MIB counters",
+		.set = ar8xxx_sw_set_port_reset_mib,
+	},
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "mib",
+		.description = "Get port's MIB counters",
+		.set = NULL,
+		.get = ar8xxx_sw_get_port_mib,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_eee",
+		.description = "Enable EEE PHY sleep mode",
+		.set = ar8327_sw_set_eee,
+		.get = ar8327_sw_get_eee,
+		.max = 1,
+	},
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "flush_arl_table",
+		.description = "Flush port's ARL table entries",
+		.set = ar8xxx_sw_set_flush_port_arl_table,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "igmp_snooping",
+		.description = "Enable port's IGMP Snooping",
+		.set = ar8327_sw_set_port_igmp_snooping,
+		.get = ar8327_sw_get_port_igmp_snooping,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "vlan_prio",
+		.description = "Port VLAN default priority (VLAN PCP) (0-7)",
+		.set = ar8327_sw_set_port_vlan_prio,
+		.get = ar8327_sw_get_port_vlan_prio,
+		.max = 7,
+	},
+};
+
+static const struct switch_dev_ops ar8327_sw_ops = {
+	.attr_global = {
+		.attr = ar8327_sw_attr_globals,
+		.n_attr = ARRAY_SIZE(ar8327_sw_attr_globals),
+	},
+	.attr_port = {
+		.attr = ar8327_sw_attr_port,
+		.n_attr = ARRAY_SIZE(ar8327_sw_attr_port),
+	},
+	.attr_vlan = {
+		.attr = ar8xxx_sw_attr_vlan,
+		.n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan),
+	},
+	.get_port_pvid = ar8xxx_sw_get_pvid,
+	.set_port_pvid = ar8xxx_sw_set_pvid,
+	.get_vlan_ports = ar8327_sw_get_ports,
+	.set_vlan_ports = ar8327_sw_set_ports,
+	.apply_config = ar8327_sw_hw_apply,
+	.reset_switch = ar8xxx_sw_reset_switch,
+	.get_port_link = ar8xxx_sw_get_port_link,
+	.get_port_stats = ar8xxx_sw_get_port_stats,
+};
+
+const struct ar8xxx_chip ar8327_chip = {
+	.caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS,
+	.config_at_probe = true,
+	.mii_lo_first = true,
+
+	.name = "Atheros AR8327",
+	.ports = AR8327_NUM_PORTS,
+	.vlans = AR83X7_MAX_VLANS,
+	.swops = &ar8327_sw_ops,
+
+	.reg_port_stats_start = 0x1000,
+	.reg_port_stats_length = 0x100,
+	.reg_arl_ctrl = AR8327_REG_ARL_CTRL,
+
+	.hw_init = ar8327_hw_init,
+	.cleanup = ar8327_cleanup,
+	.init_globals = ar8327_init_globals,
+	.init_port = ar8327_init_port,
+	.setup_port = ar8327_setup_port,
+	.read_port_status = ar8327_read_port_status,
+	.read_port_eee_status = ar8327_read_port_eee_status,
+	.atu_flush = ar8327_atu_flush,
+	.atu_flush_port = ar8327_atu_flush_port,
+	.vtu_flush = ar8327_vtu_flush,
+	.vtu_load_vlan = ar8327_vtu_load_vlan,
+	.phy_fixup = ar8327_phy_fixup,
+	.set_mirror_regs = ar8327_set_mirror_regs,
+	.get_arl_entry = ar8327_get_arl_entry,
+	.sw_hw_apply = ar8327_sw_hw_apply,
+
+	.num_mibs = ARRAY_SIZE(ar8236_mibs),
+	.mib_decs = ar8236_mibs,
+	.mib_func = AR8327_REG_MIB_FUNC,
+	.mib_rxb_id = AR8236_MIB_RXB_ID,
+	.mib_txb_id = AR8236_MIB_TXB_ID,
+};
+
+const struct ar8xxx_chip ar8337_chip = {
+	.caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS,
+	.config_at_probe = true,
+	.mii_lo_first = true,
+
+	.name = "Atheros AR8337",
+	.ports = AR8327_NUM_PORTS,
+	.vlans = AR83X7_MAX_VLANS,
+	.swops = &ar8327_sw_ops,
+
+	.reg_port_stats_start = 0x1000,
+	.reg_port_stats_length = 0x100,
+	.reg_arl_ctrl = AR8327_REG_ARL_CTRL,
+
+	.hw_init = ar8327_hw_init,
+	.cleanup = ar8327_cleanup,
+	.init_globals = ar8327_init_globals,
+	.init_port = ar8327_init_port,
+	.setup_port = ar8327_setup_port,
+	.read_port_status = ar8327_read_port_status,
+	.read_port_eee_status = ar8327_read_port_eee_status,
+	.atu_flush = ar8327_atu_flush,
+	.atu_flush_port = ar8327_atu_flush_port,
+	.vtu_flush = ar8327_vtu_flush,
+	.vtu_load_vlan = ar8327_vtu_load_vlan,
+	.phy_fixup = ar8327_phy_fixup,
+	.set_mirror_regs = ar8327_set_mirror_regs,
+	.get_arl_entry = ar8327_get_arl_entry,
+	.sw_hw_apply = ar8327_sw_hw_apply,
+	.phy_rgmii_set = ar8327_phy_rgmii_set,
+
+	.num_mibs = ARRAY_SIZE(ar8236_mibs),
+	.mib_decs = ar8236_mibs,
+	.mib_func = AR8327_REG_MIB_FUNC,
+	.mib_rxb_id = AR8236_MIB_RXB_ID,
+	.mib_txb_id = AR8236_MIB_TXB_ID,
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/ar8327.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/ar8327.h
new file mode 100644
index 0000000..088b288
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/ar8327.h
@@ -0,0 +1,333 @@
+/*
+ * ar8327.h: AR8216 switch driver
+ *
+ * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __AR8327_H
+#define __AR8327_H
+
+#define AR8327_NUM_PORTS	7
+#define AR8327_NUM_LEDS		15
+#define AR8327_PORTS_ALL	0x7f
+#define AR8327_NUM_LED_CTRL_REGS	4
+
+#define AR8327_REG_MASK				0x000
+
+#define AR8327_REG_PAD0_MODE			0x004
+#define AR8327_REG_PAD5_MODE			0x008
+#define AR8327_REG_PAD6_MODE			0x00c
+#define   AR8327_PAD_MAC_MII_RXCLK_SEL		BIT(0)
+#define   AR8327_PAD_MAC_MII_TXCLK_SEL		BIT(1)
+#define   AR8327_PAD_MAC_MII_EN			BIT(2)
+#define   AR8327_PAD_MAC_GMII_RXCLK_SEL		BIT(4)
+#define   AR8327_PAD_MAC_GMII_TXCLK_SEL		BIT(5)
+#define   AR8327_PAD_MAC_GMII_EN		BIT(6)
+#define   AR8327_PAD_SGMII_EN			BIT(7)
+#define   AR8327_PAD_PHY_MII_RXCLK_SEL		BIT(8)
+#define   AR8327_PAD_PHY_MII_TXCLK_SEL		BIT(9)
+#define   AR8327_PAD_PHY_MII_EN			BIT(10)
+#define   AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL	BIT(11)
+#define   AR8327_PAD_PHY_GMII_RXCLK_SEL		BIT(12)
+#define   AR8327_PAD_PHY_GMII_TXCLK_SEL		BIT(13)
+#define   AR8327_PAD_PHY_GMII_EN		BIT(14)
+#define   AR8327_PAD_PHYX_GMII_EN		BIT(16)
+#define   AR8327_PAD_PHYX_RGMII_EN		BIT(17)
+#define   AR8327_PAD_PHYX_MII_EN		BIT(18)
+#define   AR8327_PAD_SGMII_DELAY_EN		BIT(19)
+#define   AR8327_PAD_RGMII_RXCLK_DELAY_SEL	BITS(20, 2)
+#define   AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S	20
+#define   AR8327_PAD_RGMII_TXCLK_DELAY_SEL	BITS(22, 2)
+#define   AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S	22
+#define   AR8327_PAD_RGMII_RXCLK_DELAY_EN	BIT(24)
+#define   AR8327_PAD_RGMII_TXCLK_DELAY_EN	BIT(25)
+#define   AR8327_PAD_RGMII_EN			BIT(26)
+
+#define AR8327_REG_POWER_ON_STRAP		0x010
+#define   AR8327_POWER_ON_STRAP_POWER_ON_SEL	BIT(31)
+#define   AR8327_POWER_ON_STRAP_LED_OPEN_EN	BIT(24)
+#define   AR8327_POWER_ON_STRAP_SERDES_AEN	BIT(7)
+
+#define AR8327_REG_INT_STATUS0			0x020
+#define   AR8327_INT0_VT_DONE			BIT(20)
+
+#define AR8327_REG_INT_STATUS1			0x024
+#define AR8327_REG_INT_MASK0			0x028
+#define AR8327_REG_INT_MASK1			0x02c
+
+#define AR8327_REG_MODULE_EN			0x030
+#define   AR8327_MODULE_EN_MIB			BIT(0)
+
+#define AR8327_REG_MIB_FUNC			0x034
+#define   AR8327_MIB_CPU_KEEP			BIT(20)
+
+#define AR8327_REG_SERVICE_TAG			0x048
+#define AR8327_REG_LED_CTRL(_i)			(0x050 + (_i) * 4)
+#define AR8327_REG_LED_CTRL0			0x050
+#define AR8327_REG_LED_CTRL1			0x054
+#define AR8327_REG_LED_CTRL2			0x058
+#define AR8327_REG_LED_CTRL3			0x05c
+#define AR8327_REG_MAC_ADDR0			0x060
+#define AR8327_REG_MAC_ADDR1			0x064
+
+#define AR8327_REG_MAX_FRAME_SIZE		0x078
+#define   AR8327_MAX_FRAME_SIZE_MTU		BITS(0, 14)
+
+#define AR8327_REG_PORT_STATUS(_i)		(0x07c + (_i) * 4)
+#define   AR8327_PORT_STATUS_TXFLOW_AUTO	BIT(10)
+#define   AR8327_PORT_STATUS_RXFLOW_AUTO	BIT(11)
+
+#define AR8327_REG_HEADER_CTRL			0x098
+#define AR8327_REG_PORT_HEADER(_i)		(0x09c + (_i) * 4)
+
+#define AR8327_REG_SGMII_CTRL			0x0e0
+#define   AR8327_SGMII_CTRL_EN_PLL		BIT(1)
+#define   AR8327_SGMII_CTRL_EN_RX		BIT(2)
+#define   AR8327_SGMII_CTRL_EN_TX		BIT(3)
+
+#define AR8327_REG_EEE_CTRL			0x100
+#define   AR8327_EEE_CTRL_DISABLE_PHY(_i)	BIT(4 + (_i) * 2)
+
+#define AR8327_REG_FRAME_ACK_CTRL0		0x210
+#define   AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN0	BIT(0)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN0	BIT(1)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN0	BIT(2)
+#define   AR8327_FRAME_ACK_CTRL_EAPOL_EN0	BIT(3)
+#define   AR8327_FRAME_ACK_CTRL_DHCP_EN0	BIT(4)
+#define   AR8327_FRAME_ACK_CTRL_ARP_ACK_EN0	BIT(5)
+#define   AR8327_FRAME_ACK_CTRL_ARP_REQ_EN0	BIT(6)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN1	BIT(8)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN1	BIT(9)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN1	BIT(10)
+#define   AR8327_FRAME_ACK_CTRL_EAPOL_EN1	BIT(11)
+#define   AR8327_FRAME_ACK_CTRL_DHCP_EN1	BIT(12)
+#define   AR8327_FRAME_ACK_CTRL_ARP_ACK_EN1	BIT(13)
+#define   AR8327_FRAME_ACK_CTRL_ARP_REQ_EN1	BIT(14)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN2	BIT(16)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN2	BIT(17)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN2	BIT(18)
+#define   AR8327_FRAME_ACK_CTRL_EAPOL_EN2	BIT(19)
+#define   AR8327_FRAME_ACK_CTRL_DHCP_EN2	BIT(20)
+#define   AR8327_FRAME_ACK_CTRL_ARP_ACK_EN2	BIT(21)
+#define   AR8327_FRAME_ACK_CTRL_ARP_REQ_EN2	BIT(22)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN3	BIT(24)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN3	BIT(25)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN3	BIT(26)
+#define   AR8327_FRAME_ACK_CTRL_EAPOL_EN3	BIT(27)
+#define   AR8327_FRAME_ACK_CTRL_DHCP_EN3	BIT(28)
+#define   AR8327_FRAME_ACK_CTRL_ARP_ACK_EN3	BIT(29)
+#define   AR8327_FRAME_ACK_CTRL_ARP_REQ_EN3	BIT(30)
+
+#define AR8327_REG_FRAME_ACK_CTRL1		0x214
+#define   AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN4	BIT(0)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN4	BIT(1)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN4	BIT(2)
+#define   AR8327_FRAME_ACK_CTRL_EAPOL_EN4	BIT(3)
+#define   AR8327_FRAME_ACK_CTRL_DHCP_EN4	BIT(4)
+#define   AR8327_FRAME_ACK_CTRL_ARP_ACK_EN4	BIT(5)
+#define   AR8327_FRAME_ACK_CTRL_ARP_REQ_EN4	BIT(6)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN5	BIT(8)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN5	BIT(9)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN5	BIT(10)
+#define   AR8327_FRAME_ACK_CTRL_EAPOL_EN5	BIT(11)
+#define   AR8327_FRAME_ACK_CTRL_DHCP_EN5	BIT(12)
+#define   AR8327_FRAME_ACK_CTRL_ARP_ACK_EN5	BIT(13)
+#define   AR8327_FRAME_ACK_CTRL_ARP_REQ_EN5	BIT(14)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN6	BIT(16)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN6	BIT(17)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN6	BIT(18)
+#define   AR8327_FRAME_ACK_CTRL_EAPOL_EN6	BIT(19)
+#define   AR8327_FRAME_ACK_CTRL_DHCP_EN6	BIT(20)
+#define   AR8327_FRAME_ACK_CTRL_ARP_ACK_EN6	BIT(21)
+#define   AR8327_FRAME_ACK_CTRL_ARP_REQ_EN6	BIT(22)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_V3_EN	BIT(24)
+#define   AR8327_FRAME_ACK_CTRL_PPPOE_EN	BIT(25)
+
+#define AR8327_REG_FRAME_ACK_CTRL(_i)		(0x210 + ((_i) / 4) * 0x4)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_MLD	BIT(0)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_JOIN	BIT(1)
+#define   AR8327_FRAME_ACK_CTRL_IGMP_LEAVE	BIT(2)
+#define   AR8327_FRAME_ACK_CTRL_EAPOL		BIT(3)
+#define   AR8327_FRAME_ACK_CTRL_DHCP		BIT(4)
+#define   AR8327_FRAME_ACK_CTRL_ARP_ACK		BIT(5)
+#define   AR8327_FRAME_ACK_CTRL_ARP_REQ		BIT(6)
+#define   AR8327_FRAME_ACK_CTRL_S(_i)		(((_i) % 4) * 8)
+
+#define AR8327_REG_PORT_VLAN0(_i)		(0x420 + (_i) * 0x8)
+#define   AR8327_PORT_VLAN0_DEF_PRI_MASK	BITS(0, 3)
+#define   AR8327_PORT_VLAN0_DEF_SVID		BITS(0, 12)
+#define   AR8327_PORT_VLAN0_DEF_SVID_S		0
+#define   AR8327_PORT_VLAN0_DEF_SPRI		BITS(13, 3)
+#define   AR8327_PORT_VLAN0_DEF_SPRI_S		13
+#define   AR8327_PORT_VLAN0_DEF_CVID		BITS(16, 12)
+#define   AR8327_PORT_VLAN0_DEF_CVID_S		16
+#define   AR8327_PORT_VLAN0_DEF_CPRI		BITS(29, 3)
+#define   AR8327_PORT_VLAN0_DEF_CPRI_S		29
+
+#define AR8327_REG_PORT_VLAN1(_i)		(0x424 + (_i) * 0x8)
+#define   AR8327_PORT_VLAN1_VLAN_PRI_PROP	BIT(4)
+#define   AR8327_PORT_VLAN1_PORT_VLAN_PROP	BIT(6)
+#define   AR8327_PORT_VLAN1_OUT_MODE		BITS(12, 2)
+#define   AR8327_PORT_VLAN1_OUT_MODE_S		12
+#define   AR8327_PORT_VLAN1_OUT_MODE_UNMOD	0
+#define   AR8327_PORT_VLAN1_OUT_MODE_UNTAG	1
+#define   AR8327_PORT_VLAN1_OUT_MODE_TAG	2
+#define   AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH	3
+
+#define AR8327_REG_ATU_DATA0			0x600
+#define   AR8327_ATU_ADDR0			BITS(0, 8)
+#define   AR8327_ATU_ADDR0_S			0
+#define   AR8327_ATU_ADDR1			BITS(8, 8)
+#define   AR8327_ATU_ADDR1_S			8
+#define   AR8327_ATU_ADDR2			BITS(16, 8)
+#define   AR8327_ATU_ADDR2_S			16
+#define   AR8327_ATU_ADDR3			BITS(24, 8)
+#define   AR8327_ATU_ADDR3_S			24
+#define AR8327_REG_ATU_DATA1			0x604
+#define   AR8327_ATU_ADDR4			BITS(0, 8)
+#define   AR8327_ATU_ADDR4_S			0
+#define   AR8327_ATU_ADDR5			BITS(8, 8)
+#define   AR8327_ATU_ADDR5_S			8
+#define   AR8327_ATU_PORTS			BITS(16, 7)
+#define   AR8327_ATU_PORTS_S			16
+#define   AR8327_ATU_PORT0			BIT(16)
+#define   AR8327_ATU_PORT1			BIT(17)
+#define   AR8327_ATU_PORT2			BIT(18)
+#define   AR8327_ATU_PORT3			BIT(19)
+#define   AR8327_ATU_PORT4			BIT(20)
+#define   AR8327_ATU_PORT5			BIT(21)
+#define   AR8327_ATU_PORT6			BIT(22)
+#define AR8327_REG_ATU_DATA2			0x608
+#define   AR8327_ATU_STATUS			BITS(0, 4)
+
+#define AR8327_REG_ATU_FUNC			0x60c
+#define   AR8327_ATU_FUNC_OP			BITS(0, 4)
+#define   AR8327_ATU_FUNC_OP_NOOP		0x0
+#define   AR8327_ATU_FUNC_OP_FLUSH		0x1
+#define   AR8327_ATU_FUNC_OP_LOAD		0x2
+#define   AR8327_ATU_FUNC_OP_PURGE		0x3
+#define   AR8327_ATU_FUNC_OP_FLUSH_UNLOCKED	0x4
+#define   AR8327_ATU_FUNC_OP_FLUSH_PORT		0x5
+#define   AR8327_ATU_FUNC_OP_GET_NEXT		0x6
+#define   AR8327_ATU_FUNC_OP_SEARCH_MAC		0x7
+#define   AR8327_ATU_FUNC_OP_CHANGE_TRUNK	0x8
+#define   AR8327_ATU_PORT_NUM			BITS(8, 4)
+#define   AR8327_ATU_PORT_NUM_S			8
+#define   AR8327_ATU_FUNC_BUSY			BIT(31)
+
+#define AR8327_REG_VTU_FUNC0			0x0610
+#define   AR8327_VTU_FUNC0_EG_MODE		BITS(4, 14)
+#define   AR8327_VTU_FUNC0_EG_MODE_S(_i)	(4 + (_i) * 2)
+#define   AR8327_VTU_FUNC0_EG_MODE_KEEP		0
+#define   AR8327_VTU_FUNC0_EG_MODE_UNTAG	1
+#define   AR8327_VTU_FUNC0_EG_MODE_TAG		2
+#define   AR8327_VTU_FUNC0_EG_MODE_NOT		3
+#define   AR8327_VTU_FUNC0_IVL			BIT(19)
+#define   AR8327_VTU_FUNC0_VALID		BIT(20)
+
+#define AR8327_REG_VTU_FUNC1			0x0614
+#define   AR8327_VTU_FUNC1_OP			BITS(0, 3)
+#define   AR8327_VTU_FUNC1_OP_NOOP		0
+#define   AR8327_VTU_FUNC1_OP_FLUSH		1
+#define   AR8327_VTU_FUNC1_OP_LOAD		2
+#define   AR8327_VTU_FUNC1_OP_PURGE		3
+#define   AR8327_VTU_FUNC1_OP_REMOVE_PORT	4
+#define   AR8327_VTU_FUNC1_OP_GET_NEXT		5
+#define   AR8327_VTU_FUNC1_OP_GET_ONE		6
+#define   AR8327_VTU_FUNC1_FULL			BIT(4)
+#define   AR8327_VTU_FUNC1_PORT			BIT(8, 4)
+#define   AR8327_VTU_FUNC1_PORT_S		8
+#define   AR8327_VTU_FUNC1_VID			BIT(16, 12)
+#define   AR8327_VTU_FUNC1_VID_S		16
+#define   AR8327_VTU_FUNC1_BUSY			BIT(31)
+
+#define AR8327_REG_ARL_CTRL			0x0618
+
+#define AR8327_REG_FWD_CTRL0			0x620
+#define   AR8327_FWD_CTRL0_CPU_PORT_EN		BIT(10)
+#define   AR8327_FWD_CTRL0_MIRROR_PORT		BITS(4, 4)
+#define   AR8327_FWD_CTRL0_MIRROR_PORT_S	4
+
+#define AR8327_REG_FWD_CTRL1			0x624
+#define   AR8327_FWD_CTRL1_UC_FLOOD		BITS(0, 7)
+#define   AR8327_FWD_CTRL1_UC_FLOOD_S		0
+#define   AR8327_FWD_CTRL1_MC_FLOOD		BITS(8, 7)
+#define   AR8327_FWD_CTRL1_MC_FLOOD_S		8
+#define   AR8327_FWD_CTRL1_BC_FLOOD		BITS(16, 7)
+#define   AR8327_FWD_CTRL1_BC_FLOOD_S		16
+#define   AR8327_FWD_CTRL1_IGMP			BITS(24, 7)
+#define   AR8327_FWD_CTRL1_IGMP_S		24
+
+#define AR8327_REG_PORT_LOOKUP(_i)		(0x660 + (_i) * 0xc)
+#define   AR8327_PORT_LOOKUP_MEMBER		BITS(0, 7)
+#define   AR8327_PORT_LOOKUP_IN_MODE		BITS(8, 2)
+#define   AR8327_PORT_LOOKUP_IN_MODE_S		8
+#define   AR8327_PORT_LOOKUP_STATE		BITS(16, 3)
+#define   AR8327_PORT_LOOKUP_STATE_S		16
+#define   AR8327_PORT_LOOKUP_LEARN		BIT(20)
+#define   AR8327_PORT_LOOKUP_ING_MIRROR_EN	BIT(25)
+
+#define AR8327_REG_PORT_PRIO(_i)		(0x664 + (_i) * 0xc)
+
+#define AR8327_REG_PORT_HOL_CTRL1(_i)		(0x974 + (_i) * 0x8)
+#define   AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN	BIT(16)
+
+#define AR8337_PAD_MAC06_EXCHANGE_EN		BIT(31)
+
+#define AR8327_PHY_MODE_SEL			0x12
+#define   AR8327_PHY_MODE_SEL_RGMII		BIT(3)
+#define AR8327_PHY_TEST_CTRL			0x0
+#define   AR8327_PHY_TEST_CTRL_RGMII_RX_DELAY	BIT(15)
+#define AR8327_PHY_SYS_CTRL			0x5
+#define   AR8327_PHY_SYS_CTRL_RGMII_TX_DELAY	BIT(8)
+
+enum ar8327_led_pattern {
+	AR8327_LED_PATTERN_OFF = 0,
+	AR8327_LED_PATTERN_BLINK,
+	AR8327_LED_PATTERN_ON,
+	AR8327_LED_PATTERN_RULE,
+};
+
+struct ar8327_led_entry {
+	unsigned reg;
+	unsigned shift;
+};
+
+struct ar8327_led {
+	struct led_classdev cdev;
+	struct ar8xxx_priv *sw_priv;
+
+	char *name;
+	bool active_low;
+	u8 led_num;
+	enum ar8327_led_mode mode;
+
+	struct mutex mutex;
+	spinlock_t lock;
+	struct work_struct led_work;
+	bool enable_hw_mode;
+	enum ar8327_led_pattern pattern;
+};
+
+struct ar8327_data {
+	u32 port0_status;
+	u32 port6_status;
+
+	struct ar8327_led **leds;
+	unsigned int num_leds;
+
+	/* all fields below are cleared on reset */
+	bool eee[AR8XXX_NUM_PHYS];
+};
+
+#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/Kconfig b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/Kconfig
new file mode 100644
index 0000000..08287e7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/Kconfig
@@ -0,0 +1,37 @@
+menuconfig SWCONFIG_B53
+	tristate "Broadcom bcm53xx managed switch support"
+	depends on SWCONFIG
+	help
+	  This driver adds support for Broadcom managed switch chips. It supports
+	  BCM5325E, BCM5365, BCM539x, BCM53115 and BCM53125 as well as BCM63XX
+	  integrated switches.
+
+config SWCONFIG_B53_SPI_DRIVER
+	tristate "B53 SPI connected switch driver"
+	depends on SWCONFIG_B53 && SPI
+	help
+	  Select to enable support for registering switches configured through SPI.
+
+config SWCONFIG_B53_PHY_DRIVER
+	tristate "B53 MDIO connected switch driver"
+	depends on SWCONFIG_B53
+	select SWCONFIG_B53_PHY_FIXUP
+	help
+	  Select to enable support for registering switches configured through MDIO.
+
+config SWCONFIG_B53_MMAP_DRIVER
+	tristate "B53 MMAP connected switch driver"
+	depends on SWCONFIG_B53
+	help
+	  Select to enable support for memory-mapped switches like the BCM63XX
+	  integrated switches.
+
+config SWCONFIG_B53_SRAB_DRIVER
+	tristate "B53 SRAB connected switch driver"
+	depends on SWCONFIG_B53
+	help
+	  Select to enable support for memory-mapped Switch Register Access
+	  Bridge Registers (SRAB) like it is found on the BCM53010
+
+config SWCONFIG_B53_PHY_FIXUP
+	bool
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/Makefile
new file mode 100644
index 0000000..13ff366
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/Makefile
@@ -0,0 +1,10 @@
+obj-$(CONFIG_SWCONFIG_B53)		+= b53_common.o
+
+obj-$(CONFIG_SWCONFIG_B53_PHY_FIXUP)	+= b53_phy_fixup.o
+
+obj-$(CONFIG_SWCONFIG_B53_MMAP_DRIVER)	+= b53_mmap.o
+obj-$(CONFIG_SWCONFIG_B53_SRAB_DRIVER)	+= b53_srab.o
+obj-$(CONFIG_SWCONFIG_B53_PHY_DRIVER)	+= b53_mdio.o
+obj-$(CONFIG_SWCONFIG_B53_SPI_DRIVER)	+= b53_spi.o
+
+ccflags-y				+= -Werror
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_common.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_common.c
new file mode 100644
index 0000000..030c5c8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_common.c
@@ -0,0 +1,1730 @@
+/*
+ * B53 switch driver main logic
+ *
+ * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/switch.h>
+#include <linux/phy.h>
+#include <linux/of.h>
+#include <linux/of_net.h>
+#include <linux/platform_data/b53.h>
+
+#include "b53_regs.h"
+#include "b53_priv.h"
+
+/* buffer size needed for displaying all MIBs with max'd values */
+#define B53_BUF_SIZE	1188
+
+struct b53_mib_desc {
+	u8 size;
+	u8 offset;
+	const char *name;
+};
+
+/* BCM5365 MIB counters */
+static const struct b53_mib_desc b53_mibs_65[] = {
+	{ 8, 0x00, "TxOctets" },
+	{ 4, 0x08, "TxDropPkts" },
+	{ 4, 0x10, "TxBroadcastPkts" },
+	{ 4, 0x14, "TxMulticastPkts" },
+	{ 4, 0x18, "TxUnicastPkts" },
+	{ 4, 0x1c, "TxCollisions" },
+	{ 4, 0x20, "TxSingleCollision" },
+	{ 4, 0x24, "TxMultipleCollision" },
+	{ 4, 0x28, "TxDeferredTransmit" },
+	{ 4, 0x2c, "TxLateCollision" },
+	{ 4, 0x30, "TxExcessiveCollision" },
+	{ 4, 0x38, "TxPausePkts" },
+	{ 8, 0x44, "RxOctets" },
+	{ 4, 0x4c, "RxUndersizePkts" },
+	{ 4, 0x50, "RxPausePkts" },
+	{ 4, 0x54, "Pkts64Octets" },
+	{ 4, 0x58, "Pkts65to127Octets" },
+	{ 4, 0x5c, "Pkts128to255Octets" },
+	{ 4, 0x60, "Pkts256to511Octets" },
+	{ 4, 0x64, "Pkts512to1023Octets" },
+	{ 4, 0x68, "Pkts1024to1522Octets" },
+	{ 4, 0x6c, "RxOversizePkts" },
+	{ 4, 0x70, "RxJabbers" },
+	{ 4, 0x74, "RxAlignmentErrors" },
+	{ 4, 0x78, "RxFCSErrors" },
+	{ 8, 0x7c, "RxGoodOctets" },
+	{ 4, 0x84, "RxDropPkts" },
+	{ 4, 0x88, "RxUnicastPkts" },
+	{ 4, 0x8c, "RxMulticastPkts" },
+	{ 4, 0x90, "RxBroadcastPkts" },
+	{ 4, 0x94, "RxSAChanges" },
+	{ 4, 0x98, "RxFragments" },
+	{ },
+};
+
+#define B63XX_MIB_TXB_ID	0	/* TxOctets */
+#define B63XX_MIB_RXB_ID	14	/* RxOctets */
+
+/* BCM63xx MIB counters */
+static const struct b53_mib_desc b53_mibs_63xx[] = {
+	{ 8, 0x00, "TxOctets" },
+	{ 4, 0x08, "TxDropPkts" },
+	{ 4, 0x0c, "TxQoSPkts" },
+	{ 4, 0x10, "TxBroadcastPkts" },
+	{ 4, 0x14, "TxMulticastPkts" },
+	{ 4, 0x18, "TxUnicastPkts" },
+	{ 4, 0x1c, "TxCollisions" },
+	{ 4, 0x20, "TxSingleCollision" },
+	{ 4, 0x24, "TxMultipleCollision" },
+	{ 4, 0x28, "TxDeferredTransmit" },
+	{ 4, 0x2c, "TxLateCollision" },
+	{ 4, 0x30, "TxExcessiveCollision" },
+	{ 4, 0x38, "TxPausePkts" },
+	{ 8, 0x3c, "TxQoSOctets" },
+	{ 8, 0x44, "RxOctets" },
+	{ 4, 0x4c, "RxUndersizePkts" },
+	{ 4, 0x50, "RxPausePkts" },
+	{ 4, 0x54, "Pkts64Octets" },
+	{ 4, 0x58, "Pkts65to127Octets" },
+	{ 4, 0x5c, "Pkts128to255Octets" },
+	{ 4, 0x60, "Pkts256to511Octets" },
+	{ 4, 0x64, "Pkts512to1023Octets" },
+	{ 4, 0x68, "Pkts1024to1522Octets" },
+	{ 4, 0x6c, "RxOversizePkts" },
+	{ 4, 0x70, "RxJabbers" },
+	{ 4, 0x74, "RxAlignmentErrors" },
+	{ 4, 0x78, "RxFCSErrors" },
+	{ 8, 0x7c, "RxGoodOctets" },
+	{ 4, 0x84, "RxDropPkts" },
+	{ 4, 0x88, "RxUnicastPkts" },
+	{ 4, 0x8c, "RxMulticastPkts" },
+	{ 4, 0x90, "RxBroadcastPkts" },
+	{ 4, 0x94, "RxSAChanges" },
+	{ 4, 0x98, "RxFragments" },
+	{ 4, 0xa0, "RxSymbolErrors" },
+	{ 4, 0xa4, "RxQoSPkts" },
+	{ 8, 0xa8, "RxQoSOctets" },
+	{ 4, 0xb0, "Pkts1523to2047Octets" },
+	{ 4, 0xb4, "Pkts2048to4095Octets" },
+	{ 4, 0xb8, "Pkts4096to8191Octets" },
+	{ 4, 0xbc, "Pkts8192to9728Octets" },
+	{ 4, 0xc0, "RxDiscarded" },
+	{ }
+};
+
+#define B53XX_MIB_TXB_ID	0	/* TxOctets */
+#define B53XX_MIB_RXB_ID	12	/* RxOctets */
+
+/* MIB counters */
+static const struct b53_mib_desc b53_mibs[] = {
+	{ 8, 0x00, "TxOctets" },
+	{ 4, 0x08, "TxDropPkts" },
+	{ 4, 0x10, "TxBroadcastPkts" },
+	{ 4, 0x14, "TxMulticastPkts" },
+	{ 4, 0x18, "TxUnicastPkts" },
+	{ 4, 0x1c, "TxCollisions" },
+	{ 4, 0x20, "TxSingleCollision" },
+	{ 4, 0x24, "TxMultipleCollision" },
+	{ 4, 0x28, "TxDeferredTransmit" },
+	{ 4, 0x2c, "TxLateCollision" },
+	{ 4, 0x30, "TxExcessiveCollision" },
+	{ 4, 0x38, "TxPausePkts" },
+	{ 8, 0x50, "RxOctets" },
+	{ 4, 0x58, "RxUndersizePkts" },
+	{ 4, 0x5c, "RxPausePkts" },
+	{ 4, 0x60, "Pkts64Octets" },
+	{ 4, 0x64, "Pkts65to127Octets" },
+	{ 4, 0x68, "Pkts128to255Octets" },
+	{ 4, 0x6c, "Pkts256to511Octets" },
+	{ 4, 0x70, "Pkts512to1023Octets" },
+	{ 4, 0x74, "Pkts1024to1522Octets" },
+	{ 4, 0x78, "RxOversizePkts" },
+	{ 4, 0x7c, "RxJabbers" },
+	{ 4, 0x80, "RxAlignmentErrors" },
+	{ 4, 0x84, "RxFCSErrors" },
+	{ 8, 0x88, "RxGoodOctets" },
+	{ 4, 0x90, "RxDropPkts" },
+	{ 4, 0x94, "RxUnicastPkts" },
+	{ 4, 0x98, "RxMulticastPkts" },
+	{ 4, 0x9c, "RxBroadcastPkts" },
+	{ 4, 0xa0, "RxSAChanges" },
+	{ 4, 0xa4, "RxFragments" },
+	{ 4, 0xa8, "RxJumboPkts" },
+	{ 4, 0xac, "RxSymbolErrors" },
+	{ 4, 0xc0, "RxDiscarded" },
+	{ }
+};
+
+static int b53_do_vlan_op(struct b53_device *dev, u8 op)
+{
+	unsigned int i;
+
+	b53_write8(dev, B53_ARLIO_PAGE, dev->vta_regs[0], VTA_START_CMD | op);
+
+	for (i = 0; i < 10; i++) {
+		u8 vta;
+
+		b53_read8(dev, B53_ARLIO_PAGE, dev->vta_regs[0], &vta);
+		if (!(vta & VTA_START_CMD))
+			return 0;
+
+		usleep_range(100, 200);
+	}
+
+	return -EIO;
+}
+
+static void b53_set_vlan_entry(struct b53_device *dev, u16 vid, u16 members,
+			       u16 untag)
+{
+	if (is5325(dev)) {
+		u32 entry = 0;
+
+		if (members) {
+			entry = ((untag & VA_UNTAG_MASK_25) << VA_UNTAG_S_25) |
+				members;
+			if (dev->core_rev >= 3)
+				entry |= VA_VALID_25_R4 | vid << VA_VID_HIGH_S;
+			else
+				entry |= VA_VALID_25;
+		}
+
+		b53_write32(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_25, entry);
+		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, vid |
+			    VTA_RW_STATE_WR | VTA_RW_OP_EN);
+	} else if (is5365(dev)) {
+		u16 entry = 0;
+
+		if (members)
+			entry = ((untag & VA_UNTAG_MASK_65) << VA_UNTAG_S_65) |
+				members | VA_VALID_65;
+
+		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_65, entry);
+		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_65, vid |
+			    VTA_RW_STATE_WR | VTA_RW_OP_EN);
+	} else {
+		b53_write16(dev, B53_ARLIO_PAGE, dev->vta_regs[1], vid);
+		b53_write32(dev, B53_ARLIO_PAGE, dev->vta_regs[2],
+			    (untag << VTE_UNTAG_S) | members);
+
+		b53_do_vlan_op(dev, VTA_CMD_WRITE);
+	}
+}
+
+void b53_set_forwarding(struct b53_device *dev, int enable)
+{
+	u8 mgmt;
+
+	b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
+
+	if (enable)
+		mgmt |= SM_SW_FWD_EN;
+	else
+		mgmt &= ~SM_SW_FWD_EN;
+
+	b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
+}
+
+static void b53_enable_vlan(struct b53_device *dev, int enable)
+{
+	u8 mgmt, vc0, vc1, vc4 = 0, vc5;
+
+	b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
+	b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, &vc0);
+	b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, &vc1);
+
+	if (is5325(dev) || is5365(dev)) {
+		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4);
+		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, &vc5);
+	} else if (is63xx(dev)) {
+		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, &vc4);
+		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, &vc5);
+	} else {
+		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, &vc4);
+		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, &vc5);
+	}
+
+	mgmt &= ~SM_SW_FWD_MODE;
+
+	if (enable) {
+		vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID;
+		vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN;
+		vc4 &= ~VC4_ING_VID_CHECK_MASK;
+		vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S;
+		vc5 |= VC5_DROP_VTABLE_MISS;
+
+		if (is5325(dev))
+			vc0 &= ~VC0_RESERVED_1;
+
+		if (is5325(dev) || is5365(dev))
+			vc1 |= VC1_RX_MCST_TAG_EN;
+
+		if (!is5325(dev) && !is5365(dev)) {
+			if (dev->allow_vid_4095)
+				vc5 |= VC5_VID_FFF_EN;
+			else
+				vc5 &= ~VC5_VID_FFF_EN;
+		}
+	} else {
+		vc0 &= ~(VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID);
+		vc1 &= ~(VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN);
+		vc4 &= ~VC4_ING_VID_CHECK_MASK;
+		vc5 &= ~VC5_DROP_VTABLE_MISS;
+
+		if (is5325(dev) || is5365(dev))
+			vc4 |= VC4_ING_VID_VIO_FWD << VC4_ING_VID_CHECK_S;
+		else
+			vc4 |= VC4_ING_VID_VIO_TO_IMP << VC4_ING_VID_CHECK_S;
+
+		if (is5325(dev) || is5365(dev))
+			vc1 &= ~VC1_RX_MCST_TAG_EN;
+
+		if (!is5325(dev) && !is5365(dev))
+			vc5 &= ~VC5_VID_FFF_EN;
+	}
+
+	b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, vc0);
+	b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, vc1);
+
+	if (is5325(dev) || is5365(dev)) {
+		/* enable the high 8 bit vid check on 5325 */
+		if (is5325(dev) && enable)
+			b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3,
+				   VC3_HIGH_8BIT_EN);
+		else
+			b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0);
+
+		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, vc4);
+		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, vc5);
+	} else if (is63xx(dev)) {
+		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3_63XX, 0);
+		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, vc4);
+		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, vc5);
+	} else {
+		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0);
+		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, vc4);
+		b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, vc5);
+	}
+
+	b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
+}
+
+static int b53_set_jumbo(struct b53_device *dev, int enable, int allow_10_100)
+{
+	u32 port_mask = 0;
+	u16 max_size = JMS_MIN_SIZE;
+
+	if (is5325(dev) || is5365(dev))
+		return -EINVAL;
+
+	if (enable) {
+		port_mask = dev->enabled_ports;
+		max_size = JMS_MAX_SIZE;
+		if (allow_10_100)
+			port_mask |= JPM_10_100_JUMBO_EN;
+	}
+
+	b53_write32(dev, B53_JUMBO_PAGE, dev->jumbo_pm_reg, port_mask);
+	return b53_write16(dev, B53_JUMBO_PAGE, dev->jumbo_size_reg, max_size);
+}
+
+static int b53_flush_arl(struct b53_device *dev)
+{
+	unsigned int i;
+
+	b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL,
+		   FAST_AGE_DONE | FAST_AGE_DYNAMIC | FAST_AGE_STATIC);
+
+	for (i = 0; i < 10; i++) {
+		u8 fast_age_ctrl;
+
+		b53_read8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL,
+			  &fast_age_ctrl);
+
+		if (!(fast_age_ctrl & FAST_AGE_DONE))
+			return 0;
+
+		mdelay(1);
+	}
+
+	pr_warn("time out while flushing ARL\n");
+
+	return -EINVAL;
+}
+
+static void b53_enable_ports(struct b53_device *dev)
+{
+	unsigned i;
+
+	b53_for_each_port(dev, i) {
+		u8 port_ctrl;
+		u16 pvlan_mask;
+
+		/*
+		 * prevent leaking packets between wan and lan in unmanaged
+		 * mode through port vlans.
+		 */
+		if (dev->enable_vlan || is_cpu_port(dev, i))
+			pvlan_mask = 0x1ff;
+		else if (is531x5(dev) || is5301x(dev))
+			/* BCM53115 may use a different port as cpu port */
+			pvlan_mask = BIT(dev->sw_dev.cpu_port);
+		else
+			pvlan_mask = BIT(B53_CPU_PORT);
+
+		/* BCM5325 CPU port is at 8 */
+		if ((is5325(dev) || is5365(dev)) && i == B53_CPU_PORT_25)
+			i = B53_CPU_PORT;
+
+		if (dev->chip_id == BCM5398_DEVICE_ID && (i == 6 || i == 7))
+			/* disable unused ports 6 & 7 */
+			port_ctrl = PORT_CTRL_RX_DISABLE | PORT_CTRL_TX_DISABLE;
+		else if (i == B53_CPU_PORT)
+			port_ctrl = PORT_CTRL_RX_BCST_EN |
+				    PORT_CTRL_RX_MCST_EN |
+				    PORT_CTRL_RX_UCST_EN;
+		else
+			port_ctrl = 0;
+
+		b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i),
+			    pvlan_mask);
+
+		/* port state is handled by bcm63xx_enet driver */
+		if (!is63xx(dev) && !(is5301x(dev) && i == 6))
+			b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(i),
+				   port_ctrl);
+	}
+}
+
+static void b53_enable_mib(struct b53_device *dev)
+{
+	u8 gc;
+
+	b53_read8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc);
+
+	gc &= ~(GC_RESET_MIB | GC_MIB_AC_EN);
+
+	b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc);
+}
+
+static int b53_apply(struct b53_device *dev)
+{
+	int i;
+
+	/* clear all vlan entries */
+	if (is5325(dev) || is5365(dev)) {
+		for (i = 1; i < dev->sw_dev.vlans; i++)
+			b53_set_vlan_entry(dev, i, 0, 0);
+	} else {
+		b53_do_vlan_op(dev, VTA_CMD_CLEAR);
+	}
+
+	b53_enable_vlan(dev, dev->enable_vlan);
+
+	/* fill VLAN table */
+	if (dev->enable_vlan) {
+		for (i = 0; i < dev->sw_dev.vlans; i++) {
+			struct b53_vlan *vlan = &dev->vlans[i];
+
+			if (!vlan->members)
+				continue;
+
+			b53_set_vlan_entry(dev, i, vlan->members, vlan->untag);
+		}
+
+		b53_for_each_port(dev, i)
+			b53_write16(dev, B53_VLAN_PAGE,
+				    B53_VLAN_PORT_DEF_TAG(i),
+				    dev->ports[i].pvid);
+	} else {
+		b53_for_each_port(dev, i)
+			b53_write16(dev, B53_VLAN_PAGE,
+				    B53_VLAN_PORT_DEF_TAG(i), 1);
+
+	}
+
+	b53_enable_ports(dev);
+
+	if (!is5325(dev) && !is5365(dev))
+		b53_set_jumbo(dev, dev->enable_jumbo, 1);
+
+	return 0;
+}
+
+static void b53_switch_reset_gpio(struct b53_device *dev)
+{
+	int gpio = dev->reset_gpio;
+
+	if (gpio < 0)
+		return;
+
+	/*
+	 * Reset sequence: RESET low(50ms)->high(20ms)
+	 */
+	gpio_set_value(gpio, 0);
+	mdelay(50);
+
+	gpio_set_value(gpio, 1);
+	mdelay(20);
+
+	dev->current_page = 0xff;
+}
+
+static int b53_configure_ports_of(struct b53_device *dev)
+{
+	struct device_node *dn, *pn;
+	u32 port_num;
+
+	dn = of_get_child_by_name(dev_of_node(dev->dev), "ports");
+
+	for_each_available_child_of_node(dn, pn) {
+		struct device_node *fixed_link;
+
+		if (of_property_read_u32(pn, "reg", &port_num))
+			continue;
+
+		if (port_num > B53_CPU_PORT)
+			continue;
+
+		fixed_link = of_get_child_by_name(pn, "fixed-link");
+		if (fixed_link) {
+			u32 spd;
+			u8 po = GMII_PO_LINK;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)
+			phy_interface_t mode;
+#else
+			int mode = of_get_phy_mode(pn);
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)
+			of_get_phy_mode(pn, &mode);
+#endif
+
+			if (!of_property_read_u32(fixed_link, "speed", &spd)) {
+				switch (spd) {
+				case 10:
+					po |= GMII_PO_SPEED_10M;
+					break;
+				case 100:
+					po |= GMII_PO_SPEED_100M;
+					break;
+				case 2000:
+					if (is_imp_port(dev, port_num))
+						po |= PORT_OVERRIDE_SPEED_2000M;
+					else
+						po |= GMII_PO_SPEED_2000M;
+					/* fall through */
+				case 1000:
+					po |= GMII_PO_SPEED_1000M;
+					break;
+				}
+			}
+
+			if (of_property_read_bool(fixed_link, "full-duplex"))
+				po |= PORT_OVERRIDE_FULL_DUPLEX;
+			if (of_property_read_bool(fixed_link, "pause"))
+				po |= GMII_PO_RX_FLOW;
+			if (of_property_read_bool(fixed_link, "asym-pause"))
+				po |= GMII_PO_TX_FLOW;
+
+			if (is_imp_port(dev, port_num)) {
+				po |= PORT_OVERRIDE_EN;
+
+				if (is5325(dev) &&
+				    mode == PHY_INTERFACE_MODE_REVMII)
+					po |= PORT_OVERRIDE_RV_MII_25;
+
+				b53_write8(dev, B53_CTRL_PAGE,
+					   B53_PORT_OVERRIDE_CTRL, po);
+
+				if (is5325(dev) &&
+				    mode == PHY_INTERFACE_MODE_REVMII) {
+					b53_read8(dev, B53_CTRL_PAGE,
+						  B53_PORT_OVERRIDE_CTRL, &po);
+					if (!(po & PORT_OVERRIDE_RV_MII_25))
+					pr_err("Failed to enable reverse MII mode\n");
+					return -EINVAL;
+				}
+			} else {
+				po |= GMII_PO_EN;
+				b53_write8(dev, B53_CTRL_PAGE,
+					   B53_GMII_PORT_OVERRIDE_CTRL(port_num),
+					   po);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int b53_configure_ports(struct b53_device *dev)
+{
+	u8 cpu_port = dev->sw_dev.cpu_port;
+
+	/* configure MII port if necessary */
+	if (is5325(dev)) {
+		u8 mii_port_override;
+
+		b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
+			  &mii_port_override);
+		/* reverse mii needs to be enabled */
+		if (!(mii_port_override & PORT_OVERRIDE_RV_MII_25)) {
+			b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
+				   mii_port_override | PORT_OVERRIDE_RV_MII_25);
+			b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
+				  &mii_port_override);
+
+			if (!(mii_port_override & PORT_OVERRIDE_RV_MII_25)) {
+				pr_err("Failed to enable reverse MII mode\n");
+				return -EINVAL;
+			}
+		}
+	} else if (is531x5(dev) && cpu_port == B53_CPU_PORT) {
+		u8 mii_port_override;
+
+		b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
+			  &mii_port_override);
+		b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
+			   mii_port_override | PORT_OVERRIDE_EN |
+			   PORT_OVERRIDE_LINK);
+
+		/* BCM47189 has another interface connected to the port 5 */
+		if (dev->enabled_ports & BIT(5)) {
+			u8 po_reg = B53_GMII_PORT_OVERRIDE_CTRL(5);
+			u8 gmii_po;
+
+			b53_read8(dev, B53_CTRL_PAGE, po_reg, &gmii_po);
+			gmii_po |= GMII_PO_LINK |
+				   GMII_PO_RX_FLOW |
+				   GMII_PO_TX_FLOW |
+				   GMII_PO_EN;
+			b53_write8(dev, B53_CTRL_PAGE, po_reg, gmii_po);
+		}
+	} else if (is5301x(dev)) {
+		if (cpu_port == 8) {
+			u8 mii_port_override;
+
+			b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
+				  &mii_port_override);
+			mii_port_override |= PORT_OVERRIDE_LINK |
+					     PORT_OVERRIDE_RX_FLOW |
+					     PORT_OVERRIDE_TX_FLOW |
+					     PORT_OVERRIDE_SPEED_2000M |
+					     PORT_OVERRIDE_EN;
+			b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
+				   mii_port_override);
+
+			/* TODO: Ports 5 & 7 require some extra handling */
+		} else {
+			u8 po_reg = B53_GMII_PORT_OVERRIDE_CTRL(cpu_port);
+			u8 gmii_po;
+
+			b53_read8(dev, B53_CTRL_PAGE, po_reg, &gmii_po);
+			gmii_po |= GMII_PO_LINK |
+				   GMII_PO_RX_FLOW |
+				   GMII_PO_TX_FLOW |
+				   GMII_PO_EN |
+				   GMII_PO_SPEED_2000M;
+			b53_write8(dev, B53_CTRL_PAGE, po_reg, gmii_po);
+		}
+	}
+
+	return 0;
+}
+
+static int b53_switch_reset(struct b53_device *dev)
+{
+	int ret = 0;
+	u8 mgmt;
+
+	b53_switch_reset_gpio(dev);
+
+	if (is539x(dev)) {
+		b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x83);
+		b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x00);
+	}
+
+	b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
+
+	if (!(mgmt & SM_SW_FWD_EN)) {
+		mgmt &= ~SM_SW_FWD_MODE;
+		mgmt |= SM_SW_FWD_EN;
+
+		b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
+		b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
+
+		if (!(mgmt & SM_SW_FWD_EN)) {
+			pr_err("Failed to enable switch!\n");
+			return -EINVAL;
+		}
+	}
+
+	/* enable all ports */
+	b53_enable_ports(dev);
+
+	if (dev->dev->of_node)
+		ret = b53_configure_ports_of(dev);
+	else
+		ret = b53_configure_ports(dev);
+
+	if (ret)
+		return ret;
+
+	b53_enable_mib(dev);
+
+	return b53_flush_arl(dev);
+}
+
+/*
+ * Swconfig glue functions
+ */
+
+static int b53_global_get_vlan_enable(struct switch_dev *dev,
+				      const struct switch_attr *attr,
+				      struct switch_val *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	val->value.i = priv->enable_vlan;
+
+	return 0;
+}
+
+static int b53_global_set_vlan_enable(struct switch_dev *dev,
+				      const struct switch_attr *attr,
+				      struct switch_val *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	priv->enable_vlan = val->value.i;
+
+	return 0;
+}
+
+static int b53_global_get_jumbo_enable(struct switch_dev *dev,
+				       const struct switch_attr *attr,
+				       struct switch_val *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	val->value.i = priv->enable_jumbo;
+
+	return 0;
+}
+
+static int b53_global_set_jumbo_enable(struct switch_dev *dev,
+				       const struct switch_attr *attr,
+				       struct switch_val *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	priv->enable_jumbo = val->value.i;
+
+	return 0;
+}
+
+static int b53_global_get_4095_enable(struct switch_dev *dev,
+				      const struct switch_attr *attr,
+				      struct switch_val *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	val->value.i = priv->allow_vid_4095;
+
+	return 0;
+}
+
+static int b53_global_set_4095_enable(struct switch_dev *dev,
+				      const struct switch_attr *attr,
+				      struct switch_val *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	priv->allow_vid_4095 = val->value.i;
+
+	return 0;
+}
+
+static int b53_global_get_ports(struct switch_dev *dev,
+				const struct switch_attr *attr,
+				struct switch_val *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	val->len = snprintf(priv->buf, B53_BUF_SIZE, "0x%04x",
+			    priv->enabled_ports);
+	val->value.s = priv->buf;
+
+	return 0;
+}
+
+static int b53_port_get_pvid(struct switch_dev *dev, int port, int *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	*val = priv->ports[port].pvid;
+
+	return 0;
+}
+
+static int b53_port_set_pvid(struct switch_dev *dev, int port, int val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	if (val > 15 && is5325(priv))
+		return -EINVAL;
+	if (val == 4095 && !priv->allow_vid_4095)
+		return -EINVAL;
+
+	priv->ports[port].pvid = val;
+
+	return 0;
+}
+
+static int b53_vlan_get_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+	struct switch_port *port = &val->value.ports[0];
+	struct b53_vlan *vlan = &priv->vlans[val->port_vlan];
+	int i;
+
+	val->len = 0;
+
+	if (!vlan->members)
+		return 0;
+
+	for (i = 0; i < dev->ports; i++) {
+		if (!(vlan->members & BIT(i)))
+			continue;
+
+
+		if (!(vlan->untag & BIT(i)))
+			port->flags = BIT(SWITCH_PORT_FLAG_TAGGED);
+		else
+			port->flags = 0;
+
+		port->id = i;
+		val->len++;
+		port++;
+	}
+
+	return 0;
+}
+
+static int b53_vlan_set_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+	struct switch_port *port;
+	struct b53_vlan *vlan = &priv->vlans[val->port_vlan];
+	int i;
+
+	/* only BCM5325 and BCM5365 supports VID 0 */
+	if (val->port_vlan == 0 && !is5325(priv) && !is5365(priv))
+		return -EINVAL;
+
+	/* VLAN 4095 needs special handling */
+	if (val->port_vlan == 4095 && !priv->allow_vid_4095)
+		return -EINVAL;
+
+	port = &val->value.ports[0];
+	vlan->members = 0;
+	vlan->untag = 0;
+	for (i = 0; i < val->len; i++, port++) {
+		vlan->members |= BIT(port->id);
+
+		if (!(port->flags & BIT(SWITCH_PORT_FLAG_TAGGED))) {
+			vlan->untag |= BIT(port->id);
+			priv->ports[port->id].pvid = val->port_vlan;
+		};
+	}
+
+	/* ignore disabled ports */
+	vlan->members &= priv->enabled_ports;
+	vlan->untag &= priv->enabled_ports;
+
+	return 0;
+}
+
+static int b53_port_get_link(struct switch_dev *dev, int port,
+			     struct switch_port_link *link)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	if (is_cpu_port(priv, port)) {
+		link->link = 1;
+		link->duplex = 1;
+		link->speed = is5325(priv) || is5365(priv) ?
+				SWITCH_PORT_SPEED_100 : SWITCH_PORT_SPEED_1000;
+		link->aneg = 0;
+	} else if (priv->enabled_ports & BIT(port)) {
+		u32 speed;
+		u16 lnk, duplex;
+
+		b53_read16(priv, B53_STAT_PAGE, B53_LINK_STAT, &lnk);
+		b53_read16(priv, B53_STAT_PAGE, priv->duplex_reg, &duplex);
+
+		lnk = (lnk >> port) & 1;
+		duplex = (duplex >> port) & 1;
+
+		if (is5325(priv) || is5365(priv)) {
+			u16 tmp;
+
+			b53_read16(priv, B53_STAT_PAGE, B53_SPEED_STAT, &tmp);
+			speed = SPEED_PORT_FE(tmp, port);
+		} else {
+			b53_read32(priv, B53_STAT_PAGE, B53_SPEED_STAT, &speed);
+			speed = SPEED_PORT_GE(speed, port);
+		}
+
+		link->link = lnk;
+		if (lnk) {
+			link->duplex = duplex;
+			switch (speed) {
+			case SPEED_STAT_10M:
+				link->speed = SWITCH_PORT_SPEED_10;
+				break;
+			case SPEED_STAT_100M:
+				link->speed = SWITCH_PORT_SPEED_100;
+				break;
+			case SPEED_STAT_1000M:
+				link->speed = SWITCH_PORT_SPEED_1000;
+				break;
+			}
+		}
+
+		link->aneg = 1;
+	} else {
+		link->link = 0;
+	}
+
+	return 0;
+
+}
+
+static int b53_port_set_link(struct switch_dev *sw_dev, int port,
+			     struct switch_port_link *link)
+{
+	struct b53_device *dev = sw_to_b53(sw_dev);
+
+	/*
+	 * TODO: BCM63XX requires special handling as it can have external phys
+	 * and ports might be GE or only FE
+	 */
+	if (is63xx(dev))
+		return -ENOTSUPP;
+
+	if (port == sw_dev->cpu_port)
+		return -EINVAL;
+
+	if (!(BIT(port) & dev->enabled_ports))
+		return -EINVAL;
+
+	if (link->speed == SWITCH_PORT_SPEED_1000 &&
+	    (is5325(dev) || is5365(dev)))
+		return -EINVAL;
+
+	if (link->speed == SWITCH_PORT_SPEED_1000 && !link->duplex)
+		return -EINVAL;
+
+	return switch_generic_set_link(sw_dev, port, link);
+}
+
+static int b53_phy_read16(struct switch_dev *dev, int addr, u8 reg, u16 *value)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	if (priv->ops->phy_read16)
+		return priv->ops->phy_read16(priv, addr, reg, value);
+
+	return b53_read16(priv, B53_PORT_MII_PAGE(addr), reg, value);
+}
+
+static int b53_phy_write16(struct switch_dev *dev, int addr, u8 reg, u16 value)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	if (priv->ops->phy_write16)
+		return priv->ops->phy_write16(priv, addr, reg, value);
+
+	return b53_write16(priv, B53_PORT_MII_PAGE(addr), reg, value);
+}
+
+static int b53_global_reset_switch(struct switch_dev *dev)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	/* reset vlans */
+	priv->enable_vlan = 0;
+	priv->enable_jumbo = 0;
+	priv->allow_vid_4095 = 0;
+
+	memset(priv->vlans, 0, sizeof(*priv->vlans) * dev->vlans);
+	memset(priv->ports, 0, sizeof(*priv->ports) * dev->ports);
+
+	return b53_switch_reset(priv);
+}
+
+static int b53_global_apply_config(struct switch_dev *dev)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+
+	/* disable switching */
+	b53_set_forwarding(priv, 0);
+
+	b53_apply(priv);
+
+	/* enable switching */
+	b53_set_forwarding(priv, 1);
+
+	return 0;
+}
+
+
+static int b53_global_reset_mib(struct switch_dev *dev,
+				const struct switch_attr *attr,
+				struct switch_val *val)
+{
+	struct b53_device *priv = sw_to_b53(dev);
+	u8 gc;
+
+	b53_read8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc);
+
+	b53_write8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc | GC_RESET_MIB);
+	mdelay(1);
+	b53_write8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc & ~GC_RESET_MIB);
+	mdelay(1);
+
+	return 0;
+}
+
+static int b53_port_get_mib(struct switch_dev *sw_dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct b53_device *dev = sw_to_b53(sw_dev);
+	const struct b53_mib_desc *mibs;
+	int port = val->port_vlan;
+	int len = 0;
+
+	if (!(BIT(port) & dev->enabled_ports))
+		return -1;
+
+	if (is5365(dev)) {
+		if (port == 5)
+			port = 8;
+
+		mibs = b53_mibs_65;
+	} else if (is63xx(dev)) {
+		mibs = b53_mibs_63xx;
+	} else {
+		mibs = b53_mibs;
+	}
+
+	dev->buf[0] = 0;
+
+	for (; mibs->size > 0; mibs++) {
+		u64 val;
+
+		if (mibs->size == 8) {
+			b53_read64(dev, B53_MIB_PAGE(port), mibs->offset, &val);
+		} else {
+			u32 val32;
+
+			b53_read32(dev, B53_MIB_PAGE(port), mibs->offset,
+				   &val32);
+			val = val32;
+		}
+
+		len += snprintf(dev->buf + len, B53_BUF_SIZE - len,
+				"%-20s: %llu\n", mibs->name, val);
+	}
+
+	val->len = len;
+	val->value.s = dev->buf;
+
+	return 0;
+}
+
+static int b53_port_get_stats(struct switch_dev *sw_dev, int port,
+				struct switch_port_stats *stats)
+{
+	struct b53_device *dev = sw_to_b53(sw_dev);
+	const struct b53_mib_desc *mibs;
+	int txb_id, rxb_id;
+	u64 rxb, txb;
+
+	if (!(BIT(port) & dev->enabled_ports))
+		return -EINVAL;
+
+	txb_id = B53XX_MIB_TXB_ID;
+	rxb_id = B53XX_MIB_RXB_ID;
+
+	if (is5365(dev)) {
+		if (port == 5)
+			port = 8;
+
+		mibs = b53_mibs_65;
+	} else if (is63xx(dev)) {
+		mibs = b53_mibs_63xx;
+		txb_id = B63XX_MIB_TXB_ID;
+		rxb_id = B63XX_MIB_RXB_ID;
+	} else {
+		mibs = b53_mibs;
+	}
+
+	dev->buf[0] = 0;
+
+	if (mibs->size == 8) {
+		b53_read64(dev, B53_MIB_PAGE(port), mibs[txb_id].offset, &txb);
+		b53_read64(dev, B53_MIB_PAGE(port), mibs[rxb_id].offset, &rxb);
+	} else {
+		u32 val32;
+
+		b53_read32(dev, B53_MIB_PAGE(port), mibs[txb_id].offset, &val32);
+		txb = val32;
+
+		b53_read32(dev, B53_MIB_PAGE(port), mibs[rxb_id].offset, &val32);
+		rxb = val32;
+	}
+
+	stats->tx_bytes = txb;
+	stats->rx_bytes = rxb;
+
+	return 0;
+}
+
+static struct switch_attr b53_global_ops_25[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.set = b53_global_set_vlan_enable,
+		.get = b53_global_get_vlan_enable,
+		.max = 1,
+	},
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "ports",
+		.description = "Available ports (as bitmask)",
+		.get = b53_global_get_ports,
+	},
+};
+
+static struct switch_attr b53_global_ops_65[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.set = b53_global_set_vlan_enable,
+		.get = b53_global_get_vlan_enable,
+		.max = 1,
+	},
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "ports",
+		.description = "Available ports (as bitmask)",
+		.get = b53_global_get_ports,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "reset_mib",
+		.description = "Reset MIB counters",
+		.set = b53_global_reset_mib,
+	},
+};
+
+static struct switch_attr b53_global_ops[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.set = b53_global_set_vlan_enable,
+		.get = b53_global_get_vlan_enable,
+		.max = 1,
+	},
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "ports",
+		.description = "Available Ports (as bitmask)",
+		.get = b53_global_get_ports,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "reset_mib",
+		.description = "Reset MIB counters",
+		.set = b53_global_reset_mib,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_jumbo",
+		.description = "Enable Jumbo Frames",
+		.set = b53_global_set_jumbo_enable,
+		.get = b53_global_get_jumbo_enable,
+		.max = 1,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "allow_vid_4095",
+		.description = "Allow VID 4095",
+		.set = b53_global_set_4095_enable,
+		.get = b53_global_get_4095_enable,
+		.max = 1,
+	},
+};
+
+static struct switch_attr b53_port_ops[] = {
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "mib",
+		.description = "Get port's MIB counters",
+		.get = b53_port_get_mib,
+	},
+};
+
+static struct switch_attr b53_no_ops[] = {
+};
+
+static const struct switch_dev_ops b53_switch_ops_25 = {
+	.attr_global = {
+		.attr = b53_global_ops_25,
+		.n_attr = ARRAY_SIZE(b53_global_ops_25),
+	},
+	.attr_port = {
+		.attr = b53_no_ops,
+		.n_attr = ARRAY_SIZE(b53_no_ops),
+	},
+	.attr_vlan = {
+		.attr = b53_no_ops,
+		.n_attr = ARRAY_SIZE(b53_no_ops),
+	},
+
+	.get_vlan_ports = b53_vlan_get_ports,
+	.set_vlan_ports = b53_vlan_set_ports,
+	.get_port_pvid = b53_port_get_pvid,
+	.set_port_pvid = b53_port_set_pvid,
+	.apply_config = b53_global_apply_config,
+	.reset_switch = b53_global_reset_switch,
+	.get_port_link = b53_port_get_link,
+	.set_port_link = b53_port_set_link,
+	.get_port_stats = b53_port_get_stats,
+	.phy_read16 = b53_phy_read16,
+	.phy_write16 = b53_phy_write16,
+};
+
+static const struct switch_dev_ops b53_switch_ops_65 = {
+	.attr_global = {
+		.attr = b53_global_ops_65,
+		.n_attr = ARRAY_SIZE(b53_global_ops_65),
+	},
+	.attr_port = {
+		.attr = b53_port_ops,
+		.n_attr = ARRAY_SIZE(b53_port_ops),
+	},
+	.attr_vlan = {
+		.attr = b53_no_ops,
+		.n_attr = ARRAY_SIZE(b53_no_ops),
+	},
+
+	.get_vlan_ports = b53_vlan_get_ports,
+	.set_vlan_ports = b53_vlan_set_ports,
+	.get_port_pvid = b53_port_get_pvid,
+	.set_port_pvid = b53_port_set_pvid,
+	.apply_config = b53_global_apply_config,
+	.reset_switch = b53_global_reset_switch,
+	.get_port_link = b53_port_get_link,
+	.set_port_link = b53_port_set_link,
+	.get_port_stats = b53_port_get_stats,
+	.phy_read16 = b53_phy_read16,
+	.phy_write16 = b53_phy_write16,
+};
+
+static const struct switch_dev_ops b53_switch_ops = {
+	.attr_global = {
+		.attr = b53_global_ops,
+		.n_attr = ARRAY_SIZE(b53_global_ops),
+	},
+	.attr_port = {
+		.attr = b53_port_ops,
+		.n_attr = ARRAY_SIZE(b53_port_ops),
+	},
+	.attr_vlan = {
+		.attr = b53_no_ops,
+		.n_attr = ARRAY_SIZE(b53_no_ops),
+	},
+
+	.get_vlan_ports = b53_vlan_get_ports,
+	.set_vlan_ports = b53_vlan_set_ports,
+	.get_port_pvid = b53_port_get_pvid,
+	.set_port_pvid = b53_port_set_pvid,
+	.apply_config = b53_global_apply_config,
+	.reset_switch = b53_global_reset_switch,
+	.get_port_link = b53_port_get_link,
+	.set_port_link = b53_port_set_link,
+	.get_port_stats = b53_port_get_stats,
+	.phy_read16 = b53_phy_read16,
+	.phy_write16 = b53_phy_write16,
+};
+
+struct b53_chip_data {
+	u32 chip_id;
+	const char *dev_name;
+	const char *alias;
+	u16 vlans;
+	u16 enabled_ports;
+	u8 cpu_port;
+	u8 vta_regs[3];
+	u8 duplex_reg;
+	u8 jumbo_pm_reg;
+	u8 jumbo_size_reg;
+	const struct switch_dev_ops *sw_ops;
+};
+
+#define B53_VTA_REGS	\
+	{ B53_VT_ACCESS, B53_VT_INDEX, B53_VT_ENTRY }
+#define B53_VTA_REGS_9798 \
+	{ B53_VT_ACCESS_9798, B53_VT_INDEX_9798, B53_VT_ENTRY_9798 }
+#define B53_VTA_REGS_63XX \
+	{ B53_VT_ACCESS_63XX, B53_VT_INDEX_63XX, B53_VT_ENTRY_63XX }
+
+static const struct b53_chip_data b53_switch_chips[] = {
+	{
+		.chip_id = BCM5325_DEVICE_ID,
+		.dev_name = "BCM5325",
+		.alias = "bcm5325",
+		.vlans = 16,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT_25,
+		.duplex_reg = B53_DUPLEX_STAT_FE,
+		.sw_ops = &b53_switch_ops_25,
+	},
+	{
+		.chip_id = BCM5365_DEVICE_ID,
+		.dev_name = "BCM5365",
+		.alias = "bcm5365",
+		.vlans = 256,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT_25,
+		.duplex_reg = B53_DUPLEX_STAT_FE,
+		.sw_ops = &b53_switch_ops_65,
+	},
+	{
+		.chip_id = BCM5395_DEVICE_ID,
+		.dev_name = "BCM5395",
+		.alias = "bcm5395",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT,
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM5397_DEVICE_ID,
+		.dev_name = "BCM5397",
+		.alias = "bcm5397",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT,
+		.vta_regs = B53_VTA_REGS_9798,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM5398_DEVICE_ID,
+		.dev_name = "BCM5398",
+		.alias = "bcm5398",
+		.vlans = 4096,
+		.enabled_ports = 0x7f,
+		.cpu_port = B53_CPU_PORT,
+		.vta_regs = B53_VTA_REGS_9798,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM53115_DEVICE_ID,
+		.dev_name = "BCM53115",
+		.alias = "bcm53115",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.vta_regs = B53_VTA_REGS,
+		.cpu_port = B53_CPU_PORT,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM53125_DEVICE_ID,
+		.dev_name = "BCM53125",
+		.alias = "bcm53125",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT,
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM53128_DEVICE_ID,
+		.dev_name = "BCM53128",
+		.alias = "bcm53128",
+		.vlans = 4096,
+		.enabled_ports = 0x1ff,
+		.cpu_port = B53_CPU_PORT,
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM63XX_DEVICE_ID,
+		.dev_name = "BCM63xx",
+		.alias = "bcm63xx",
+		.vlans = 4096,
+		.enabled_ports = 0, /* pdata must provide them */
+		.cpu_port = B53_CPU_PORT,
+		.vta_regs = B53_VTA_REGS_63XX,
+		.duplex_reg = B53_DUPLEX_STAT_63XX,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK_63XX,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM53010_DEVICE_ID,
+		.dev_name = "BCM53010",
+		.alias = "bcm53011",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM53011_DEVICE_ID,
+		.dev_name = "BCM53011",
+		.alias = "bcm53011",
+		.vlans = 4096,
+		.enabled_ports = 0x1bf,
+		.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM53012_DEVICE_ID,
+		.dev_name = "BCM53012",
+		.alias = "bcm53011",
+		.vlans = 4096,
+		.enabled_ports = 0x1bf,
+		.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM53018_DEVICE_ID,
+		.dev_name = "BCM53018",
+		.alias = "bcm53018",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+	{
+		.chip_id = BCM53019_DEVICE_ID,
+		.dev_name = "BCM53019",
+		.alias = "bcm53019",
+		.vlans = 4096,
+		.enabled_ports = 0x1f,
+		.cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */
+		.vta_regs = B53_VTA_REGS,
+		.duplex_reg = B53_DUPLEX_STAT_GE,
+		.jumbo_pm_reg = B53_JUMBO_PORT_MASK,
+		.jumbo_size_reg = B53_JUMBO_MAX_SIZE,
+		.sw_ops = &b53_switch_ops,
+	},
+};
+
+static int b53_switch_init_of(struct b53_device *dev)
+{
+	struct device_node *dn, *pn;
+	const char *alias;
+	u32 port_num;
+	u16 ports = 0;
+
+	dn = of_get_child_by_name(dev_of_node(dev->dev), "ports");
+	if (!dn)
+		return -EINVAL;
+
+	for_each_available_child_of_node(dn, pn) {
+		const char *label;
+		int len;
+
+		if (of_property_read_u32(pn, "reg", &port_num))
+			continue;
+
+		if (port_num > B53_CPU_PORT)
+			continue;
+
+		ports |= BIT(port_num);
+
+		label = of_get_property(pn, "label", &len);
+		if (label && !strcmp(label, "cpu"))
+			dev->sw_dev.cpu_port = port_num;
+	}
+
+	dev->enabled_ports = ports;
+
+	if (!of_property_read_string(dev_of_node(dev->dev), "lede,alias",
+						 &alias))
+		dev->sw_dev.alias = devm_kstrdup(dev->dev, alias, GFP_KERNEL);
+
+	return 0;
+}
+
+static int b53_switch_init(struct b53_device *dev)
+{
+	struct switch_dev *sw_dev = &dev->sw_dev;
+	unsigned i;
+	int ret;
+
+	for (i = 0; i < ARRAY_SIZE(b53_switch_chips); i++) {
+		const struct b53_chip_data *chip = &b53_switch_chips[i];
+
+		if (chip->chip_id == dev->chip_id) {
+			sw_dev->name = chip->dev_name;
+			if (!sw_dev->alias)
+				sw_dev->alias = chip->alias;
+			if (!dev->enabled_ports)
+				dev->enabled_ports = chip->enabled_ports;
+			dev->duplex_reg = chip->duplex_reg;
+			dev->vta_regs[0] = chip->vta_regs[0];
+			dev->vta_regs[1] = chip->vta_regs[1];
+			dev->vta_regs[2] = chip->vta_regs[2];
+			dev->jumbo_pm_reg = chip->jumbo_pm_reg;
+			sw_dev->ops = chip->sw_ops;
+			sw_dev->cpu_port = chip->cpu_port;
+			sw_dev->vlans = chip->vlans;
+			break;
+		}
+	}
+
+	if (!sw_dev->name)
+		return -EINVAL;
+
+	/* check which BCM5325x version we have */
+	if (is5325(dev)) {
+		u8 vc4;
+
+		b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4);
+
+		/* check reserved bits */
+		switch (vc4 & 3) {
+		case 1:
+			/* BCM5325E */
+			break;
+		case 3:
+			/* BCM5325F - do not use port 4 */
+			dev->enabled_ports &= ~BIT(4);
+			break;
+		default:
+/* On the BCM47XX SoCs this is the supported internal switch.*/
+#ifndef CONFIG_BCM47XX
+			/* BCM5325M */
+			return -EINVAL;
+#else
+			break;
+#endif
+		}
+	} else if (dev->chip_id == BCM53115_DEVICE_ID) {
+		u64 strap_value;
+
+		b53_read48(dev, B53_STAT_PAGE, B53_STRAP_VALUE, &strap_value);
+		/* use second IMP port if GMII is enabled */
+		if (strap_value & SV_GMII_CTRL_115)
+			sw_dev->cpu_port = 5;
+	}
+
+	if (dev_of_node(dev->dev)) {
+		ret = b53_switch_init_of(dev);
+		if (ret)
+			return ret;
+	}
+
+	dev->enabled_ports |= BIT(sw_dev->cpu_port);
+	sw_dev->ports = fls(dev->enabled_ports);
+
+	dev->ports = devm_kzalloc(dev->dev,
+				  sizeof(struct b53_port) * sw_dev->ports,
+				  GFP_KERNEL);
+	if (!dev->ports)
+		return -ENOMEM;
+
+	dev->vlans = devm_kzalloc(dev->dev,
+				  sizeof(struct b53_vlan) * sw_dev->vlans,
+				  GFP_KERNEL);
+	if (!dev->vlans)
+		return -ENOMEM;
+
+	dev->buf = devm_kzalloc(dev->dev, B53_BUF_SIZE, GFP_KERNEL);
+	if (!dev->buf)
+		return -ENOMEM;
+
+	dev->reset_gpio = b53_switch_get_reset_gpio(dev);
+	if (dev->reset_gpio >= 0) {
+		ret = devm_gpio_request_one(dev->dev, dev->reset_gpio,
+					    GPIOF_OUT_INIT_HIGH, "robo_reset");
+		if (ret)
+			return ret;
+	}
+
+	return b53_switch_reset(dev);
+}
+
+struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops,
+				    void *priv)
+{
+	struct b53_device *dev;
+
+	dev = devm_kzalloc(base, sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return NULL;
+
+	dev->dev = base;
+	dev->ops = ops;
+	dev->priv = priv;
+	mutex_init(&dev->reg_mutex);
+
+	return dev;
+}
+EXPORT_SYMBOL(b53_switch_alloc);
+
+int b53_switch_detect(struct b53_device *dev)
+{
+	u32 id32;
+	u16 tmp;
+	u8 id8;
+	int ret;
+
+	ret = b53_read8(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id8);
+	if (ret)
+		return ret;
+
+	switch (id8) {
+	case 0:
+		/*
+		 * BCM5325 and BCM5365 do not have this register so reads
+		 * return 0. But the read operation did succeed, so assume
+		 * this is one of them.
+		 *
+		 * Next check if we can write to the 5325's VTA register; for
+		 * 5365 it is read only.
+		 */
+
+		b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, 0xf);
+		b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, &tmp);
+
+		if (tmp == 0xf)
+			dev->chip_id = BCM5325_DEVICE_ID;
+		else
+			dev->chip_id = BCM5365_DEVICE_ID;
+		break;
+	case BCM5395_DEVICE_ID:
+	case BCM5397_DEVICE_ID:
+	case BCM5398_DEVICE_ID:
+		dev->chip_id = id8;
+		break;
+	default:
+		ret = b53_read32(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id32);
+		if (ret)
+			return ret;
+
+		switch (id32) {
+		case BCM53115_DEVICE_ID:
+		case BCM53125_DEVICE_ID:
+		case BCM53128_DEVICE_ID:
+		case BCM53010_DEVICE_ID:
+		case BCM53011_DEVICE_ID:
+		case BCM53012_DEVICE_ID:
+		case BCM53018_DEVICE_ID:
+		case BCM53019_DEVICE_ID:
+			dev->chip_id = id32;
+			break;
+		default:
+			pr_err("unsupported switch detected (BCM53%02x/BCM%x)\n",
+			       id8, id32);
+			return -ENODEV;
+		}
+	}
+
+	if (dev->chip_id == BCM5325_DEVICE_ID)
+		return b53_read8(dev, B53_STAT_PAGE, B53_REV_ID_25,
+				 &dev->core_rev);
+	else
+		return b53_read8(dev, B53_MGMT_PAGE, B53_REV_ID,
+				 &dev->core_rev);
+}
+EXPORT_SYMBOL(b53_switch_detect);
+
+int b53_switch_register(struct b53_device *dev)
+{
+	int ret;
+
+	if (dev->pdata) {
+		dev->chip_id = dev->pdata->chip_id;
+		dev->enabled_ports = dev->pdata->enabled_ports;
+		dev->sw_dev.alias = dev->pdata->alias;
+	}
+
+	if (!dev->chip_id && b53_switch_detect(dev))
+		return -EINVAL;
+
+	ret = b53_switch_init(dev);
+	if (ret)
+		return ret;
+
+	pr_info("found switch: %s, rev %i\n", dev->sw_dev.name, dev->core_rev);
+
+	return register_switch(&dev->sw_dev, NULL);
+}
+EXPORT_SYMBOL(b53_switch_register);
+
+MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
+MODULE_DESCRIPTION("B53 switch library");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_mdio.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_mdio.c
new file mode 100644
index 0000000..98cdbff
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_mdio.c
@@ -0,0 +1,468 @@
+/*
+ * B53 register access through MII registers
+ *
+ * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/phy.h>
+#include <linux/module.h>
+
+#include "b53_priv.h"
+
+#define B53_PSEUDO_PHY	0x1e /* Register Access Pseudo PHY */
+
+/* MII registers */
+#define REG_MII_PAGE    0x10    /* MII Page register */
+#define REG_MII_ADDR    0x11    /* MII Address register */
+#define REG_MII_DATA0   0x18    /* MII Data register 0 */
+#define REG_MII_DATA1   0x19    /* MII Data register 1 */
+#define REG_MII_DATA2   0x1a    /* MII Data register 2 */
+#define REG_MII_DATA3   0x1b    /* MII Data register 3 */
+
+#define REG_MII_PAGE_ENABLE     BIT(0)
+#define REG_MII_ADDR_WRITE      BIT(0)
+#define REG_MII_ADDR_READ       BIT(1)
+
+static int b53_mdio_op(struct b53_device *dev, u8 page, u8 reg, u16 op)
+{
+	int i;
+	u16 v;
+	int ret;
+	struct mii_bus *bus = dev->priv;
+
+	if (dev->current_page != page) {
+		/* set page number */
+		v = (page << 8) | REG_MII_PAGE_ENABLE;
+		ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_PAGE, v);
+		if (ret)
+			return ret;
+		dev->current_page = page;
+	}
+
+	/* set register address */
+	v = (reg << 8) | op;
+	ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_ADDR, v);
+	if (ret)
+		return ret;
+
+	/* check if operation completed */
+	for (i = 0; i < 5; ++i) {
+		v = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_ADDR);
+		if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ)))
+			break;
+		usleep_range(10, 100);
+	}
+
+	if (WARN_ON(i == 5))
+		return -EIO;
+
+	return 0;
+}
+
+static int b53_mdio_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
+{
+	struct mii_bus *bus = dev->priv;
+	int ret;
+
+	ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
+	if (ret)
+		return ret;
+
+	*val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0) & 0xff;
+
+	return 0;
+}
+
+static int b53_mdio_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
+{
+	struct mii_bus *bus = dev->priv;
+	int ret;
+
+	ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
+	if (ret)
+		return ret;
+
+	*val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0);
+
+	return 0;
+}
+
+static int b53_mdio_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
+{
+	struct mii_bus *bus = dev->priv;
+	int ret;
+
+	ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
+	if (ret)
+		return ret;
+
+	*val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0);
+	*val |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA1) << 16;
+
+	return 0;
+}
+
+static int b53_mdio_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	struct mii_bus *bus = dev->priv;
+	u64 temp = 0;
+	int i;
+	int ret;
+
+	ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
+	if (ret)
+		return ret;
+
+	for (i = 2; i >= 0; i--) {
+		temp <<= 16;
+		temp |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i);
+	}
+
+	*val = temp;
+
+	return 0;
+}
+
+static int b53_mdio_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	struct mii_bus *bus = dev->priv;
+	u64 temp = 0;
+	int i;
+	int ret;
+
+	ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
+	if (ret)
+		return ret;
+
+	for (i = 3; i >= 0; i--) {
+		temp <<= 16;
+		temp |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i);
+	}
+
+	*val = temp;
+
+	return 0;
+}
+
+static int b53_mdio_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
+{
+	struct mii_bus *bus = dev->priv;
+	int ret;
+
+	ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0, value);
+	if (ret)
+		return ret;
+
+	return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
+}
+
+static int b53_mdio_write16(struct b53_device *dev, u8 page, u8 reg,
+			     u16 value)
+{
+	struct mii_bus *bus = dev->priv;
+	int ret;
+
+	ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0, value);
+	if (ret)
+		return ret;
+
+	return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
+}
+
+static int b53_mdio_write32(struct b53_device *dev, u8 page, u8 reg,
+				    u32 value)
+{
+	struct mii_bus *bus = dev->priv;
+	unsigned int i;
+	u32 temp = value;
+
+	for (i = 0; i < 2; i++) {
+		int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i,
+				    temp & 0xffff);
+		if (ret)
+			return ret;
+		temp >>= 16;
+	}
+
+	return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
+
+}
+
+static int b53_mdio_write48(struct b53_device *dev, u8 page, u8 reg,
+				    u64 value)
+{
+	struct mii_bus *bus = dev->priv;
+	unsigned i;
+	u64 temp = value;
+
+	for (i = 0; i < 3; i++) {
+		int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i,
+				    temp & 0xffff);
+		if (ret)
+			return ret;
+		temp >>= 16;
+	}
+
+	return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
+
+}
+
+static int b53_mdio_write64(struct b53_device *dev, u8 page, u8 reg,
+			     u64 value)
+{
+	struct mii_bus *bus = dev->priv;
+	unsigned i;
+	u64 temp = value;
+
+	for (i = 0; i < 4; i++) {
+		int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i,
+				    temp & 0xffff);
+		if (ret)
+			return ret;
+		temp >>= 16;
+	}
+
+	return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
+}
+
+static int b53_mdio_phy_read16(struct b53_device *dev, int addr, u8 reg,
+			       u16 *value)
+{
+	struct mii_bus *bus = dev->priv;
+
+	*value = mdiobus_read(bus, addr, reg);
+
+	return 0;
+}
+
+static int b53_mdio_phy_write16(struct b53_device *dev, int addr, u8 reg,
+				u16 value)
+{
+	struct mii_bus *bus = dev->priv;
+
+	return mdiobus_write(bus, addr, reg, value);
+}
+
+static struct b53_io_ops b53_mdio_ops = {
+	.read8 = b53_mdio_read8,
+	.read16 = b53_mdio_read16,
+	.read32 = b53_mdio_read32,
+	.read48 = b53_mdio_read48,
+	.read64 = b53_mdio_read64,
+	.write8 = b53_mdio_write8,
+	.write16 = b53_mdio_write16,
+	.write32 = b53_mdio_write32,
+	.write48 = b53_mdio_write48,
+	.write64 = b53_mdio_write64,
+	.phy_read16 = b53_mdio_phy_read16,
+	.phy_write16 = b53_mdio_phy_write16,
+};
+
+static int b53_phy_probe(struct phy_device *phydev)
+{
+	struct b53_device *dev;
+	int ret;
+
+	/* allow the generic phy driver to take over */
+	if (phydev->mdio.addr != B53_PSEUDO_PHY && phydev->mdio.addr != 0)
+		return -ENODEV;
+
+	dev = b53_switch_alloc(&phydev->mdio.dev, &b53_mdio_ops, phydev->mdio.bus);
+	if (!dev)
+		return -ENOMEM;
+
+	dev->current_page = 0xff;
+	dev->priv = phydev->mdio.bus;
+	dev->ops = &b53_mdio_ops;
+	dev->pdata = NULL;
+	mutex_init(&dev->reg_mutex);
+
+	ret = b53_switch_detect(dev);
+	if (ret)
+		return ret;
+
+	linkmode_zero(phydev->supported);
+	if (is5325(dev) || is5365(dev))
+		linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, phydev->supported);
+	else
+		linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, phydev->supported);
+
+	linkmode_copy(phydev->advertising, phydev->supported);
+
+	ret = b53_switch_register(dev);
+	if (ret) {
+		dev_err(dev->dev, "failed to register switch: %i\n", ret);
+		return ret;
+	}
+
+	phydev->priv = dev;
+
+	return 0;
+}
+
+static int b53_phy_config_init(struct phy_device *phydev)
+{
+	struct b53_device *dev = phydev->priv;
+
+	/* we don't use page 0xff, so force a page set */
+	dev->current_page = 0xff;
+	/* force the ethX as alias */
+	dev->sw_dev.alias = phydev->attached_dev->name;
+
+	return 0;
+}
+
+static void b53_phy_remove(struct phy_device *phydev)
+{
+	struct b53_device *priv = phydev->priv;
+
+	if (!priv)
+		return;
+
+	b53_switch_remove(priv);
+
+	phydev->priv = NULL;
+}
+
+static int b53_phy_config_aneg(struct phy_device *phydev)
+{
+	return 0;
+}
+
+static int b53_phy_read_status(struct phy_device *phydev)
+{
+	struct b53_device *priv = phydev->priv;
+
+	if (is5325(priv) || is5365(priv))
+		phydev->speed = 100;
+	else
+		phydev->speed = 1000;
+
+	phydev->duplex = DUPLEX_FULL;
+	phydev->link = 1;
+	phydev->state = PHY_RUNNING;
+
+	netif_carrier_on(phydev->attached_dev);
+	phydev->adjust_link(phydev->attached_dev);
+
+	return 0;
+}
+
+static const struct of_device_id b53_of_match_1[] = {
+	{ .compatible = "brcm,bcm5325" },
+	{ .compatible = "brcm,bcm5395" },
+	{ .compatible = "brcm,bcm5397" },
+	{ .compatible = "brcm,bcm5398" },
+	{ /* sentinel */ },
+};
+
+static const struct of_device_id b53_of_match_2[] = {
+	{ .compatible = "brcm,bcm53115" },
+	{ .compatible = "brcm,bcm53125" },
+	{ .compatible = "brcm,bcm53128" },
+	{ /* sentinel */ },
+};
+
+static const struct of_device_id b53_of_match_3[] = {
+	{ .compatible = "brcm,bcm5365" },
+	{ /* sentinel */ },
+};
+
+/* BCM5325, BCM539x */
+static struct phy_driver b53_phy_driver_id1 = {
+	.phy_id		= 0x0143bc00,
+	.name		= "Broadcom B53 (1)",
+	.phy_id_mask	= 0x1ffffc00,
+	.features	= 0,
+	.probe		= b53_phy_probe,
+	.remove		= b53_phy_remove,
+	.config_aneg	= b53_phy_config_aneg,
+	.config_init	= b53_phy_config_init,
+	.read_status	= b53_phy_read_status,
+	.mdiodrv.driver = {
+		.name = "bcm539x",
+		.of_match_table = b53_of_match_1,
+	},
+};
+
+/* BCM53125, BCM53128 */
+static struct phy_driver b53_phy_driver_id2 = {
+	.phy_id		= 0x03625c00,
+	.name		= "Broadcom B53 (2)",
+	.phy_id_mask	= 0x1ffffc00,
+	.features	= 0,
+	.probe		= b53_phy_probe,
+	.remove		= b53_phy_remove,
+	.config_aneg	= b53_phy_config_aneg,
+	.config_init	= b53_phy_config_init,
+	.read_status	= b53_phy_read_status,
+	.mdiodrv.driver = {
+		.name = "bcm531xx",
+		.of_match_table = b53_of_match_2,
+	},
+};
+
+/* BCM5365 */
+static struct phy_driver b53_phy_driver_id3 = {
+	.phy_id		= 0x00406300,
+	.name		= "Broadcom B53 (3)",
+	.phy_id_mask	= 0x1fffff00,
+	.features	= 0,
+	.probe		= b53_phy_probe,
+	.remove		= b53_phy_remove,
+	.config_aneg	= b53_phy_config_aneg,
+	.config_init	= b53_phy_config_init,
+	.read_status	= b53_phy_read_status,
+	.mdiodrv.driver = {
+		.name = "bcm5365",
+		.of_match_table = b53_of_match_3,
+	},
+};
+
+int __init b53_phy_driver_register(void)
+{
+	int ret;
+
+	ret = phy_driver_register(&b53_phy_driver_id1, THIS_MODULE);
+	if (ret)
+		return ret;
+
+	ret = phy_driver_register(&b53_phy_driver_id2, THIS_MODULE);
+	if (ret)
+		goto err1;
+
+	ret = phy_driver_register(&b53_phy_driver_id3, THIS_MODULE);
+	if (!ret)
+		return 0;
+
+	phy_driver_unregister(&b53_phy_driver_id2);
+err1:
+	phy_driver_unregister(&b53_phy_driver_id1);
+	return ret;
+}
+
+void __exit b53_phy_driver_unregister(void)
+{
+	phy_driver_unregister(&b53_phy_driver_id3);
+	phy_driver_unregister(&b53_phy_driver_id2);
+	phy_driver_unregister(&b53_phy_driver_id1);
+}
+
+module_init(b53_phy_driver_register);
+module_exit(b53_phy_driver_unregister);
+
+MODULE_DESCRIPTION("B53 MDIO access driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_mmap.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_mmap.c
new file mode 100644
index 0000000..ab1895e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_mmap.c
@@ -0,0 +1,241 @@
+/*
+ * B53 register access through memory mapped registers
+ *
+ * Copyright (C) 2012-2013 Jonas Gorski <jogo@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/b53.h>
+
+#include "b53_priv.h"
+
+static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
+{
+	u8 __iomem *regs = dev->priv;
+
+	*val = readb(regs + (page << 8) + reg);
+
+	return 0;
+}
+
+static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
+{
+	u8 __iomem *regs = dev->priv;
+
+	if (WARN_ON(reg % 2))
+		return -EINVAL;
+
+	if (dev->pdata && dev->pdata->big_endian)
+		*val = readw_be(regs + (page << 8) + reg);
+	else
+		*val = readw(regs + (page << 8) + reg);
+
+	return 0;
+}
+
+static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
+{
+	u8 __iomem *regs = dev->priv;
+
+	if (WARN_ON(reg % 4))
+		return -EINVAL;
+
+	if (dev->pdata && dev->pdata->big_endian)
+		*val = readl_be(regs + (page << 8) + reg);
+	else
+		*val = readl(regs + (page << 8) + reg);
+
+	return 0;
+}
+
+static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	if (WARN_ON(reg % 2))
+		return -EINVAL;
+
+	if (reg % 4) {
+		u16 lo;
+		u32 hi;
+
+		b53_mmap_read16(dev, page, reg, &lo);
+		b53_mmap_read32(dev, page, reg + 2, &hi);
+
+		*val = ((u64)hi << 16) | lo;
+	} else {
+		u32 lo;
+		u16 hi;
+
+		b53_mmap_read32(dev, page, reg, &lo);
+		b53_mmap_read16(dev, page, reg + 4, &hi);
+
+		*val = ((u64)hi << 32) | lo;
+	}
+
+	return 0;
+}
+
+static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	u32 hi, lo;
+
+	if (WARN_ON(reg % 4))
+		return -EINVAL;
+
+	b53_mmap_read32(dev, page, reg, &lo);
+	b53_mmap_read32(dev, page, reg + 4, &hi);
+
+	*val = ((u64)hi << 32) | lo;
+
+	return 0;
+}
+
+static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
+{
+	u8 __iomem *regs = dev->priv;
+
+	writeb(value, regs + (page << 8) + reg);
+
+	return 0;
+}
+
+static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg,
+			     u16 value)
+{
+	u8 __iomem *regs = dev->priv;
+
+	if (WARN_ON(reg % 2))
+		return -EINVAL;
+
+	if (dev->pdata && dev->pdata->big_endian)
+		writew_be(value, regs + (page << 8) + reg);
+	else
+		writew(value, regs + (page << 8) + reg);
+
+	return 0;
+}
+
+static int b53_mmap_write32(struct b53_device *dev, u8 page, u8 reg,
+				    u32 value)
+{
+	u8 __iomem *regs = dev->priv;
+
+	if (WARN_ON(reg % 4))
+		return -EINVAL;
+
+	if (dev->pdata && dev->pdata->big_endian)
+		writel_be(value, regs + (page << 8) + reg);
+	else
+		writel(value, regs + (page << 8) + reg);
+
+	return 0;
+}
+
+static int b53_mmap_write48(struct b53_device *dev, u8 page, u8 reg,
+				    u64 value)
+{
+	if (WARN_ON(reg % 2))
+		return -EINVAL;
+
+	if (reg % 4) {
+		u32 hi = (u32)(value >> 16);
+		u16 lo = (u16)value;
+
+		b53_mmap_write16(dev, page, reg, lo);
+		b53_mmap_write32(dev, page, reg + 2, hi);
+	} else {
+		u16 hi = (u16)(value >> 32);
+		u32 lo = (u32)value;
+
+		b53_mmap_write32(dev, page, reg, lo);
+		b53_mmap_write16(dev, page, reg + 4, hi);
+	}
+
+	return 0;
+}
+
+static int b53_mmap_write64(struct b53_device *dev, u8 page, u8 reg,
+			     u64 value)
+{
+	u32 hi, lo;
+
+	hi = (u32)(value >> 32);
+	lo = (u32)value;
+
+	if (WARN_ON(reg % 4))
+		return -EINVAL;
+
+	b53_mmap_write32(dev, page, reg, lo);
+	b53_mmap_write32(dev, page, reg + 4, hi);
+
+	return 0;
+}
+
+static struct b53_io_ops b53_mmap_ops = {
+	.read8 = b53_mmap_read8,
+	.read16 = b53_mmap_read16,
+	.read32 = b53_mmap_read32,
+	.read48 = b53_mmap_read48,
+	.read64 = b53_mmap_read64,
+	.write8 = b53_mmap_write8,
+	.write16 = b53_mmap_write16,
+	.write32 = b53_mmap_write32,
+	.write48 = b53_mmap_write48,
+	.write64 = b53_mmap_write64,
+};
+
+static int b53_mmap_probe(struct platform_device *pdev)
+{
+	struct b53_platform_data *pdata = pdev->dev.platform_data;
+	struct b53_device *dev;
+
+	if (!pdata)
+		return -EINVAL;
+
+	dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, pdata->regs);
+	if (!dev)
+		return -ENOMEM;
+
+	if (pdata)
+		dev->pdata = pdata;
+
+	platform_set_drvdata(pdev, dev);
+
+	return b53_switch_register(dev);
+}
+
+static int b53_mmap_remove(struct platform_device *pdev)
+{
+	struct b53_device *dev = platform_get_drvdata(pdev);
+
+	if (dev)
+		b53_switch_remove(dev);
+
+	return 0;
+}
+
+static struct platform_driver b53_mmap_driver = {
+	.probe = b53_mmap_probe,
+	.remove = b53_mmap_remove,
+	.driver = {
+		.name = "b53-switch",
+	},
+};
+
+module_platform_driver(b53_mmap_driver);
+MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
+MODULE_DESCRIPTION("B53 MMAP access driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_phy_fixup.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_phy_fixup.c
new file mode 100644
index 0000000..a19ecce
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_phy_fixup.c
@@ -0,0 +1,55 @@
+/*
+ * B53 PHY Fixup call
+ *
+ * Copyright (C) 2013 Jonas Gorski <jogo@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/phy.h>
+
+#define B53_PSEUDO_PHY	0x1e /* Register Access Pseudo PHY */
+
+#define B53_BRCM_OUI_1	0x0143bc00
+#define B53_BRCM_OUI_2	0x03625c00
+#define B53_BRCM_OUI_3	0x00406300
+
+static int b53_phy_fixup(struct phy_device *dev)
+{
+	struct mii_bus *bus = dev->mdio.bus;
+	u32 phy_id;
+
+	if (dev->mdio.addr != B53_PSEUDO_PHY)
+		return 0;
+
+	/* read the first port's id */
+	phy_id = mdiobus_read(bus, 0, 2) << 16;
+	phy_id |= mdiobus_read(bus, 0, 3);
+
+	if ((phy_id & 0xfffffc00) == B53_BRCM_OUI_1 ||
+	    (phy_id & 0xfffffc00) == B53_BRCM_OUI_2 ||
+	    (phy_id & 0xffffff00) == B53_BRCM_OUI_3) {
+		dev->phy_id = phy_id;
+	}
+
+	return 0;
+}
+
+int __init b53_phy_fixup_register(void)
+{
+	return phy_register_fixup_for_id(PHY_ANY_ID, b53_phy_fixup);
+}
+
+subsys_initcall(b53_phy_fixup_register);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_priv.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_priv.h
new file mode 100644
index 0000000..37c17ae
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_priv.h
@@ -0,0 +1,336 @@
+/*
+ * B53 common definitions
+ *
+ * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __B53_PRIV_H
+#define __B53_PRIV_H
+
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/switch.h>
+
+struct b53_device;
+
+struct b53_io_ops {
+	int (*read8)(struct b53_device *dev, u8 page, u8 reg, u8 *value);
+	int (*read16)(struct b53_device *dev, u8 page, u8 reg, u16 *value);
+	int (*read32)(struct b53_device *dev, u8 page, u8 reg, u32 *value);
+	int (*read48)(struct b53_device *dev, u8 page, u8 reg, u64 *value);
+	int (*read64)(struct b53_device *dev, u8 page, u8 reg, u64 *value);
+	int (*write8)(struct b53_device *dev, u8 page, u8 reg, u8 value);
+	int (*write16)(struct b53_device *dev, u8 page, u8 reg, u16 value);
+	int (*write32)(struct b53_device *dev, u8 page, u8 reg, u32 value);
+	int (*write48)(struct b53_device *dev, u8 page, u8 reg, u64 value);
+	int (*write64)(struct b53_device *dev, u8 page, u8 reg, u64 value);
+	int (*phy_read16)(struct b53_device *dev, int addr, u8 reg, u16 *value);
+	int (*phy_write16)(struct b53_device *dev, int addr, u8 reg, u16 value);
+};
+
+enum {
+	BCM5325_DEVICE_ID = 0x25,
+	BCM5365_DEVICE_ID = 0x65,
+	BCM5395_DEVICE_ID = 0x95,
+	BCM5397_DEVICE_ID = 0x97,
+	BCM5398_DEVICE_ID = 0x98,
+	BCM53115_DEVICE_ID = 0x53115,
+	BCM53125_DEVICE_ID = 0x53125,
+	BCM53128_DEVICE_ID = 0x53128,
+	BCM63XX_DEVICE_ID = 0x6300,
+	BCM53010_DEVICE_ID = 0x53010,
+	BCM53011_DEVICE_ID = 0x53011,
+	BCM53012_DEVICE_ID = 0x53012,
+	BCM53018_DEVICE_ID = 0x53018,
+	BCM53019_DEVICE_ID = 0x53019,
+};
+
+#define B53_N_PORTS	9
+#define B53_N_PORTS_25	6
+
+struct b53_vlan {
+	unsigned int	members:B53_N_PORTS;
+	unsigned int	untag:B53_N_PORTS;
+};
+
+struct b53_port {
+	unsigned int	pvid:12;
+};
+
+struct b53_device {
+	struct switch_dev sw_dev;
+	struct b53_platform_data *pdata;
+
+	struct mutex reg_mutex;
+	const struct b53_io_ops *ops;
+
+	/* chip specific data */
+	u32 chip_id;
+	u8 core_rev;
+	u8 vta_regs[3];
+	u8 duplex_reg;
+	u8 jumbo_pm_reg;
+	u8 jumbo_size_reg;
+	int reset_gpio;
+
+	/* used ports mask */
+	u16 enabled_ports;
+
+	/* connect specific data */
+	u8 current_page;
+	struct device *dev;
+	void *priv;
+
+	/* run time configuration */
+	unsigned enable_vlan:1;
+	unsigned enable_jumbo:1;
+	unsigned allow_vid_4095:1;
+
+	struct b53_port *ports;
+	struct b53_vlan *vlans;
+
+	char *buf;
+};
+
+#define b53_for_each_port(dev, i) \
+	for (i = 0; i < B53_N_PORTS; i++) \
+		if (dev->enabled_ports & BIT(i))
+
+
+
+static inline int is5325(struct b53_device *dev)
+{
+	return dev->chip_id == BCM5325_DEVICE_ID;
+}
+
+static inline int is5365(struct b53_device *dev)
+{
+#ifdef CONFIG_BCM47XX
+	return dev->chip_id == BCM5365_DEVICE_ID;
+#else
+	return 0;
+#endif
+}
+
+static inline int is5397_98(struct b53_device *dev)
+{
+	return dev->chip_id == BCM5397_DEVICE_ID ||
+		dev->chip_id == BCM5398_DEVICE_ID;
+}
+
+static inline int is539x(struct b53_device *dev)
+{
+	return dev->chip_id == BCM5395_DEVICE_ID ||
+		dev->chip_id == BCM5397_DEVICE_ID ||
+		dev->chip_id == BCM5398_DEVICE_ID;
+}
+
+static inline int is531x5(struct b53_device *dev)
+{
+	return dev->chip_id == BCM53115_DEVICE_ID ||
+		dev->chip_id == BCM53125_DEVICE_ID ||
+		dev->chip_id == BCM53128_DEVICE_ID;
+}
+
+static inline int is63xx(struct b53_device *dev)
+{
+#ifdef CONFIG_BCM63XX
+	return dev->chip_id == BCM63XX_DEVICE_ID;
+#else
+	return 0;
+#endif
+}
+
+static inline int is5301x(struct b53_device *dev)
+{
+	return dev->chip_id == BCM53010_DEVICE_ID ||
+		dev->chip_id == BCM53011_DEVICE_ID ||
+		dev->chip_id == BCM53012_DEVICE_ID ||
+		dev->chip_id == BCM53018_DEVICE_ID ||
+		dev->chip_id == BCM53019_DEVICE_ID;
+}
+
+#define B53_CPU_PORT_25	5
+#define B53_CPU_PORT	8
+
+static inline int is_cpu_port(struct b53_device *dev, int port)
+{
+	return dev->sw_dev.cpu_port == port;
+}
+
+static inline int is_imp_port(struct b53_device *dev, int port)
+{
+	if (is5325(dev) || is5365(dev))
+		return port == B53_CPU_PORT_25;
+	else
+		return port == B53_CPU_PORT;
+}
+
+static inline struct b53_device *sw_to_b53(struct switch_dev *sw)
+{
+	return container_of(sw, struct b53_device, sw_dev);
+}
+
+struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops,
+				    void *priv);
+
+int b53_switch_detect(struct b53_device *dev);
+
+int b53_switch_register(struct b53_device *dev);
+
+static inline void b53_switch_remove(struct b53_device *dev)
+{
+	unregister_switch(&dev->sw_dev);
+}
+
+static inline int b53_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->read8(dev, page, reg, val);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->read16(dev, page, reg, val);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->read32(dev, page, reg, val);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->read48(dev, page, reg, val);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->read64(dev, page, reg, val);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->write8(dev, page, reg, value);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_write16(struct b53_device *dev, u8 page, u8 reg,
+			      u16 value)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->write16(dev, page, reg, value);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_write32(struct b53_device *dev, u8 page, u8 reg,
+			      u32 value)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->write32(dev, page, reg, value);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_write48(struct b53_device *dev, u8 page, u8 reg,
+			      u64 value)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->write48(dev, page, reg, value);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+static inline int b53_write64(struct b53_device *dev, u8 page, u8 reg,
+			       u64 value)
+{
+	int ret;
+
+	mutex_lock(&dev->reg_mutex);
+	ret = dev->ops->write64(dev, page, reg, value);
+	mutex_unlock(&dev->reg_mutex);
+
+	return ret;
+}
+
+#ifdef CONFIG_BCM47XX
+#include <bcm47xx_board.h>
+#endif
+
+#include <linux/version.h>
+#include <linux/bcm47xx_nvram.h>
+
+static inline int b53_switch_get_reset_gpio(struct b53_device *dev)
+{
+#ifdef CONFIG_BCM47XX
+	enum bcm47xx_board board = bcm47xx_board_get();
+
+	switch (board) {
+	case BCM47XX_BOARD_LINKSYS_WRT300NV11:
+	case BCM47XX_BOARD_LINKSYS_WRT310NV1:
+		return 8;
+	default:
+		break;
+	}
+#endif
+
+	return bcm47xx_nvram_gpio_pin("robo_reset");
+}
+
+#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_regs.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_regs.h
new file mode 100644
index 0000000..f0bf674
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_regs.h
@@ -0,0 +1,348 @@
+/*
+ * B53 register definitions
+ *
+ * Copyright (C) 2004 Broadcom Corporation
+ * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __B53_REGS_H
+#define __B53_REGS_H
+
+/* Management Port (SMP) Page offsets */
+#define B53_CTRL_PAGE			0x00 /* Control */
+#define B53_STAT_PAGE			0x01 /* Status */
+#define B53_MGMT_PAGE			0x02 /* Management Mode */
+#define B53_MIB_AC_PAGE			0x03 /* MIB Autocast */
+#define B53_ARLCTRL_PAGE		0x04 /* ARL Control */
+#define B53_ARLIO_PAGE			0x05 /* ARL Access */
+#define B53_FRAMEBUF_PAGE		0x06 /* Management frame access */
+#define B53_MEM_ACCESS_PAGE		0x08 /* Memory access */
+
+/* PHY Registers */
+#define B53_PORT_MII_PAGE(i)		(0x10 + (i)) /* Port i MII Registers */
+#define B53_IM_PORT_PAGE		0x18 /* Inverse MII Port (to EMAC) */
+#define B53_ALL_PORT_PAGE		0x19 /* All ports MII (broadcast) */
+
+/* MIB registers */
+#define B53_MIB_PAGE(i)			(0x20 + (i))
+
+/* Quality of Service (QoS) Registers */
+#define B53_QOS_PAGE			0x30
+
+/* Port VLAN Page */
+#define B53_PVLAN_PAGE			0x31
+
+/* VLAN Registers */
+#define B53_VLAN_PAGE			0x34
+
+/* Jumbo Frame Registers */
+#define B53_JUMBO_PAGE			0x40
+
+/* CFP Configuration Registers Page */
+#define B53_CFP_PAGE			0xa1
+
+/*************************************************************************
+ * Control Page registers
+ *************************************************************************/
+
+/* Port Control Register (8 bit) */
+#define B53_PORT_CTRL(i)		(0x00 + (i))
+#define   PORT_CTRL_RX_DISABLE		BIT(0)
+#define   PORT_CTRL_TX_DISABLE		BIT(1)
+#define   PORT_CTRL_RX_BCST_EN		BIT(2) /* Broadcast RX (P8 only) */
+#define   PORT_CTRL_RX_MCST_EN		BIT(3) /* Multicast RX (P8 only) */
+#define   PORT_CTRL_RX_UCST_EN		BIT(4) /* Unicast RX (P8 only) */
+#define	  PORT_CTRL_STP_STATE_S		5
+#define   PORT_CTRL_STP_STATE_MASK	(0x7 << PORT_CTRL_STP_STATE_S)
+
+/* SMP Control Register (8 bit) */
+#define B53_SMP_CTRL			0x0a
+
+/* Switch Mode Control Register (8 bit) */
+#define B53_SWITCH_MODE			0x0b
+#define   SM_SW_FWD_MODE		BIT(0)	/* 1 = Managed Mode */
+#define   SM_SW_FWD_EN			BIT(1)	/* Forwarding Enable */
+
+/* IMP Port state override register (8 bit) */
+#define B53_PORT_OVERRIDE_CTRL		0x0e
+#define   PORT_OVERRIDE_LINK		BIT(0)
+#define   PORT_OVERRIDE_FULL_DUPLEX	BIT(1) /* 0 = Half Duplex */
+#define   PORT_OVERRIDE_SPEED_S		2
+#define   PORT_OVERRIDE_SPEED_10M	(0 << PORT_OVERRIDE_SPEED_S)
+#define   PORT_OVERRIDE_SPEED_100M	(1 << PORT_OVERRIDE_SPEED_S)
+#define   PORT_OVERRIDE_SPEED_1000M	(2 << PORT_OVERRIDE_SPEED_S)
+#define   PORT_OVERRIDE_RV_MII_25	BIT(4) /* BCM5325 only */
+#define   PORT_OVERRIDE_RX_FLOW		BIT(4)
+#define   PORT_OVERRIDE_TX_FLOW		BIT(5)
+#define   PORT_OVERRIDE_SPEED_2000M	BIT(6) /* BCM5301X only, requires setting 1000M */
+#define   PORT_OVERRIDE_EN		BIT(7) /* Use the register contents */
+
+/* Power-down mode control */
+#define B53_PD_MODE_CTRL_25		0x0f
+
+/* IP Multicast control (8 bit) */
+#define B53_IP_MULTICAST_CTRL		0x21
+#define  B53_IPMC_FWD_EN		BIT(1)
+#define  B53_UC_FWD_EN			BIT(6)
+#define  B53_MC_FWD_EN			BIT(7)
+
+/* (16 bit) */
+#define B53_UC_FLOOD_MASK		0x32
+#define B53_MC_FLOOD_MASK		0x34
+#define B53_IPMC_FLOOD_MASK		0x36
+
+/*
+ * Override Ports 0-7 State on devices with xMII interfaces (8 bit)
+ *
+ * For port 8 still use B53_PORT_OVERRIDE_CTRL
+ * Please note that not all ports are available on every hardware, e.g. BCM5301X
+ * don't include overriding port 6, BCM63xx also have some limitations.
+ */
+#define B53_GMII_PORT_OVERRIDE_CTRL(i)	(0x58 + (i))
+#define   GMII_PO_LINK			BIT(0)
+#define   GMII_PO_FULL_DUPLEX		BIT(1) /* 0 = Half Duplex */
+#define   GMII_PO_SPEED_S		2
+#define   GMII_PO_SPEED_10M		(0 << GMII_PO_SPEED_S)
+#define   GMII_PO_SPEED_100M		(1 << GMII_PO_SPEED_S)
+#define   GMII_PO_SPEED_1000M		(2 << GMII_PO_SPEED_S)
+#define   GMII_PO_RX_FLOW		BIT(4)
+#define   GMII_PO_TX_FLOW		BIT(5)
+#define   GMII_PO_EN			BIT(6) /* Use the register contents */
+#define   GMII_PO_SPEED_2000M		BIT(7) /* BCM5301X only, requires setting 1000M */
+
+/* Software reset register (8 bit) */
+#define B53_SOFTRESET			0x79
+
+/* Fast Aging Control register (8 bit) */
+#define B53_FAST_AGE_CTRL		0x88
+#define   FAST_AGE_STATIC		BIT(0)
+#define   FAST_AGE_DYNAMIC		BIT(1)
+#define   FAST_AGE_PORT			BIT(2)
+#define   FAST_AGE_VLAN			BIT(3)
+#define   FAST_AGE_STP			BIT(4)
+#define   FAST_AGE_MC			BIT(5)
+#define   FAST_AGE_DONE			BIT(7)
+
+/*************************************************************************
+ * Status Page registers
+ *************************************************************************/
+
+/* Link Status Summary Register (16bit) */
+#define B53_LINK_STAT			0x00
+
+/* Link Status Change Register (16 bit) */
+#define B53_LINK_STAT_CHANGE		0x02
+
+/* Port Speed Summary Register (16 bit for FE, 32 bit for GE) */
+#define B53_SPEED_STAT			0x04
+#define  SPEED_PORT_FE(reg, port)	(((reg) >> (port)) & 1)
+#define  SPEED_PORT_GE(reg, port)	(((reg) >> 2 * (port)) & 3)
+#define  SPEED_STAT_10M			0
+#define  SPEED_STAT_100M		1
+#define  SPEED_STAT_1000M		2
+
+/* Duplex Status Summary (16 bit) */
+#define B53_DUPLEX_STAT_FE		0x06
+#define B53_DUPLEX_STAT_GE		0x08
+#define B53_DUPLEX_STAT_63XX		0x0c
+
+/* Revision ID register for BCM5325 */
+#define B53_REV_ID_25			0x50
+
+/* Strap Value (48 bit) */
+#define B53_STRAP_VALUE			0x70
+#define   SV_GMII_CTRL_115		BIT(27)
+
+/*************************************************************************
+ * Management Mode Page Registers
+ *************************************************************************/
+
+/* Global Management Config Register (8 bit) */
+#define B53_GLOBAL_CONFIG		0x00
+#define   GC_RESET_MIB			0x01
+#define   GC_RX_BPDU_EN			0x02
+#define   GC_MIB_AC_HDR_EN		0x10
+#define   GC_MIB_AC_EN			0x20
+#define   GC_FRM_MGMT_PORT_M		0xC0
+#define   GC_FRM_MGMT_PORT_04		0x00
+#define   GC_FRM_MGMT_PORT_MII		0x80
+
+/* Broadcom Header control register (8 bit) */
+#define B53_BRCM_HDR			0x03
+#define   BRCM_HDR_P8_EN		BIT(0) /* Enable tagging on port 8 */
+#define   BRCM_HDR_P5_EN		BIT(1) /* Enable tagging on port 5 */
+
+/* Device ID register (8 or 32 bit) */
+#define B53_DEVICE_ID			0x30
+
+/* Revision ID register (8 bit) */
+#define B53_REV_ID			0x40
+
+/*************************************************************************
+ * ARL Access Page Registers
+ *************************************************************************/
+
+/* VLAN Table Access Register (8 bit) */
+#define B53_VT_ACCESS			0x80
+#define B53_VT_ACCESS_9798		0x60 /* for BCM5397/BCM5398 */
+#define B53_VT_ACCESS_63XX		0x60 /* for BCM6328/62/68 */
+#define   VTA_CMD_WRITE			0
+#define   VTA_CMD_READ			1
+#define   VTA_CMD_CLEAR			2
+#define   VTA_START_CMD			BIT(7)
+
+/* VLAN Table Index Register (16 bit) */
+#define B53_VT_INDEX			0x81
+#define B53_VT_INDEX_9798		0x61
+#define B53_VT_INDEX_63XX		0x62
+
+/* VLAN Table Entry Register (32 bit) */
+#define B53_VT_ENTRY			0x83
+#define B53_VT_ENTRY_9798		0x63
+#define B53_VT_ENTRY_63XX		0x64
+#define   VTE_MEMBERS			0x1ff
+#define   VTE_UNTAG_S			9
+#define   VTE_UNTAG			(0x1ff << 9)
+
+/*************************************************************************
+ * Port VLAN Registers
+ *************************************************************************/
+
+/* Port VLAN mask (16 bit) IMP port is always 8, also on 5325 & co */
+#define B53_PVLAN_PORT_MASK(i)		((i) * 2)
+
+/*************************************************************************
+ * 802.1Q Page Registers
+ *************************************************************************/
+
+/* Global QoS Control (8 bit) */
+#define B53_QOS_GLOBAL_CTL		0x00
+
+/* Enable 802.1Q for individual Ports (16 bit) */
+#define B53_802_1P_EN			0x04
+
+/*************************************************************************
+ * VLAN Page Registers
+ *************************************************************************/
+
+/* VLAN Control 0 (8 bit) */
+#define B53_VLAN_CTRL0			0x00
+#define   VC0_8021PF_CTRL_MASK		0x3
+#define   VC0_8021PF_CTRL_NONE		0x0
+#define   VC0_8021PF_CTRL_CHANGE_PRI	0x1
+#define   VC0_8021PF_CTRL_CHANGE_VID	0x2
+#define   VC0_8021PF_CTRL_CHANGE_BOTH	0x3
+#define   VC0_8021QF_CTRL_MASK		0xc
+#define   VC0_8021QF_CTRL_CHANGE_PRI	0x1
+#define   VC0_8021QF_CTRL_CHANGE_VID	0x2
+#define   VC0_8021QF_CTRL_CHANGE_BOTH	0x3
+#define   VC0_RESERVED_1		BIT(1)
+#define   VC0_DROP_VID_MISS		BIT(4)
+#define   VC0_VID_HASH_VID		BIT(5)
+#define   VC0_VID_CHK_EN		BIT(6)	/* Use VID,DA or VID,SA */
+#define   VC0_VLAN_EN			BIT(7)	/* 802.1Q VLAN Enabled */
+
+/* VLAN Control 1 (8 bit) */
+#define B53_VLAN_CTRL1			0x01
+#define   VC1_RX_MCST_TAG_EN		BIT(1)
+#define   VC1_RX_MCST_FWD_EN		BIT(2)
+#define   VC1_RX_MCST_UNTAG_EN		BIT(3)
+
+/* VLAN Control 2 (8 bit) */
+#define B53_VLAN_CTRL2			0x02
+
+/* VLAN Control 3 (8 bit when BCM5325, 16 bit else) */
+#define B53_VLAN_CTRL3			0x03
+#define B53_VLAN_CTRL3_63XX		0x04
+#define   VC3_MAXSIZE_1532		BIT(6) /* 5325 only */
+#define   VC3_HIGH_8BIT_EN		BIT(7) /* 5325 only */
+
+/* VLAN Control 4 (8 bit) */
+#define B53_VLAN_CTRL4			0x05
+#define B53_VLAN_CTRL4_25		0x04
+#define B53_VLAN_CTRL4_63XX		0x06
+#define   VC4_ING_VID_CHECK_S		6
+#define   VC4_ING_VID_CHECK_MASK	(0x3 << VC4_ING_VID_CHECK_S)
+#define   VC4_ING_VID_VIO_FWD		0 /* forward, but do not learn */
+#define   VC4_ING_VID_VIO_DROP		1 /* drop VID violations */
+#define   VC4_NO_ING_VID_CHK		2 /* do not check */
+#define   VC4_ING_VID_VIO_TO_IMP	3 /* redirect to MII port */
+
+/* VLAN Control 5 (8 bit) */
+#define B53_VLAN_CTRL5			0x06
+#define B53_VLAN_CTRL5_25		0x05
+#define B53_VLAN_CTRL5_63XX		0x07
+#define   VC5_VID_FFF_EN		BIT(2)
+#define   VC5_DROP_VTABLE_MISS		BIT(3)
+
+/* VLAN Control 6 (8 bit) */
+#define B53_VLAN_CTRL6			0x07
+#define B53_VLAN_CTRL6_63XX		0x08
+
+/* VLAN Table Access Register (16 bit) */
+#define B53_VLAN_TABLE_ACCESS_25	0x06	/* BCM5325E/5350 */
+#define B53_VLAN_TABLE_ACCESS_65	0x08	/* BCM5365 */
+#define   VTA_VID_LOW_MASK_25		0xf
+#define   VTA_VID_LOW_MASK_65		0xff
+#define   VTA_VID_HIGH_S_25		4
+#define   VTA_VID_HIGH_S_65		8
+#define   VTA_VID_HIGH_MASK_25		(0xff << VTA_VID_HIGH_S_25E)
+#define   VTA_VID_HIGH_MASK_65		(0xf << VTA_VID_HIGH_S_65)
+#define   VTA_RW_STATE			BIT(12)
+#define   VTA_RW_STATE_RD		0
+#define   VTA_RW_STATE_WR		BIT(12)
+#define   VTA_RW_OP_EN			BIT(13)
+
+/* VLAN Read/Write Registers for (16/32 bit) */
+#define B53_VLAN_WRITE_25		0x08
+#define B53_VLAN_WRITE_65		0x0a
+#define B53_VLAN_READ			0x0c
+#define   VA_MEMBER_MASK		0x3f
+#define   VA_UNTAG_S_25			6
+#define   VA_UNTAG_MASK_25		0x3f
+#define   VA_UNTAG_S_65			7
+#define   VA_UNTAG_MASK_65		0x1f
+#define   VA_VID_HIGH_S			12
+#define   VA_VID_HIGH_MASK		(0xffff << VA_VID_HIGH_S)
+#define   VA_VALID_25			BIT(20)
+#define   VA_VALID_25_R4		BIT(24)
+#define   VA_VALID_65			BIT(14)
+
+/* VLAN Port Default Tag (16 bit) */
+#define B53_VLAN_PORT_DEF_TAG(i)	(0x10 + 2 * (i))
+
+/*************************************************************************
+ * Jumbo Frame Page Registers
+ *************************************************************************/
+
+/* Jumbo Enable Port Mask (bit i == port i enabled) (32 bit) */
+#define B53_JUMBO_PORT_MASK		0x01
+#define B53_JUMBO_PORT_MASK_63XX	0x04
+#define   JPM_10_100_JUMBO_EN		BIT(24) /* GigE always enabled */
+
+/* Good Frame Max Size without 802.1Q TAG (16 bit) */
+#define B53_JUMBO_MAX_SIZE		0x05
+#define B53_JUMBO_MAX_SIZE_63XX		0x08
+#define   JMS_MIN_SIZE			1518
+#define   JMS_MAX_SIZE			9724
+
+/*************************************************************************
+ * CFP Configuration Page Registers
+ *************************************************************************/
+
+/* CFP Control Register with ports map (8 bit) */
+#define B53_CFP_CTRL			0x00
+
+#endif /* !__B53_REGS_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_spi.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_spi.c
new file mode 100644
index 0000000..efc8f7e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_spi.c
@@ -0,0 +1,344 @@
+/*
+ * B53 register access through SPI
+ *
+ * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <asm/unaligned.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/of.h>
+#include <linux/platform_data/b53.h>
+
+#include "b53_priv.h"
+
+#define B53_SPI_DATA		0xf0
+
+#define B53_SPI_STATUS		0xfe
+#define B53_SPI_CMD_SPIF	BIT(7)
+#define B53_SPI_CMD_RACK	BIT(5)
+
+#define B53_SPI_CMD_READ	0x00
+#define B53_SPI_CMD_WRITE	0x01
+#define B53_SPI_CMD_NORMAL	0x60
+#define B53_SPI_CMD_FAST	0x10
+
+#define B53_SPI_PAGE_SELECT	0xff
+
+static inline int b53_spi_read_reg(struct spi_device *spi, u8 reg, u8 *val,
+				     unsigned len)
+{
+	u8 txbuf[2];
+
+	txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_READ;
+	txbuf[1] = reg;
+
+	return spi_write_then_read(spi, txbuf, 2, val, len);
+}
+
+static inline int b53_spi_clear_status(struct spi_device *spi)
+{
+	unsigned int i;
+	u8 rxbuf;
+	int ret;
+
+	for (i = 0; i < 10; i++) {
+		ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1);
+		if (ret)
+			return ret;
+
+		if (!(rxbuf & B53_SPI_CMD_SPIF))
+			break;
+
+		mdelay(1);
+	}
+
+	if (i == 10)
+		return -EIO;
+
+	return 0;
+}
+
+static inline int b53_spi_set_page(struct spi_device *spi, u8 page)
+{
+	u8 txbuf[3];
+
+	txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
+	txbuf[1] = B53_SPI_PAGE_SELECT;
+	txbuf[2] = page;
+
+	return spi_write(spi, txbuf, sizeof(txbuf));
+}
+
+static inline int b53_prepare_reg_access(struct spi_device *spi, u8 page)
+{
+	int ret = b53_spi_clear_status(spi);
+
+	if (ret)
+		return ret;
+
+	return b53_spi_set_page(spi, page);
+}
+
+static int b53_spi_prepare_reg_read(struct spi_device *spi, u8 reg)
+{
+	u8 rxbuf;
+	int retry_count;
+	int ret;
+
+	ret = b53_spi_read_reg(spi, reg, &rxbuf, 1);
+	if (ret)
+		return ret;
+
+	for (retry_count = 0; retry_count < 10; retry_count++) {
+		ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1);
+		if (ret)
+			return ret;
+
+		if (rxbuf & B53_SPI_CMD_RACK)
+			break;
+
+		mdelay(1);
+	}
+
+	if (retry_count == 10)
+		return -EIO;
+
+	return 0;
+}
+
+static int b53_spi_read(struct b53_device *dev, u8 page, u8 reg, u8 *data,
+			unsigned len)
+{
+	struct spi_device *spi = dev->priv;
+	int ret;
+
+	ret = b53_prepare_reg_access(spi, page);
+	if (ret)
+		return ret;
+
+	ret = b53_spi_prepare_reg_read(spi, reg);
+	if (ret)
+		return ret;
+
+	return b53_spi_read_reg(spi, B53_SPI_DATA, data, len);
+}
+
+static int b53_spi_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
+{
+	return b53_spi_read(dev, page, reg, val, 1);
+}
+
+static int b53_spi_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
+{
+	int ret = b53_spi_read(dev, page, reg, (u8 *)val, 2);
+
+	if (!ret)
+		*val = le16_to_cpu(*val);
+
+	return ret;
+}
+
+static int b53_spi_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
+{
+	int ret = b53_spi_read(dev, page, reg, (u8 *)val, 4);
+
+	if (!ret)
+		*val = le32_to_cpu(*val);
+
+	return ret;
+}
+
+static int b53_spi_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	int ret;
+
+	*val = 0;
+	ret = b53_spi_read(dev, page, reg, (u8 *)val, 6);
+	if (!ret)
+		*val = le64_to_cpu(*val);
+
+	return ret;
+}
+
+static int b53_spi_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	int ret = b53_spi_read(dev, page, reg, (u8 *)val, 8);
+
+	if (!ret)
+		*val = le64_to_cpu(*val);
+
+	return ret;
+}
+
+static int b53_spi_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
+{
+	struct spi_device *spi = dev->priv;
+	int ret;
+	u8 txbuf[3];
+
+	ret = b53_prepare_reg_access(spi, page);
+	if (ret)
+		return ret;
+
+	txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
+	txbuf[1] = reg;
+	txbuf[2] = value;
+
+	return spi_write(spi, txbuf, sizeof(txbuf));
+}
+
+static int b53_spi_write16(struct b53_device *dev, u8 page, u8 reg, u16 value)
+{
+	struct spi_device *spi = dev->priv;
+	int ret;
+	u8 txbuf[4];
+
+	ret = b53_prepare_reg_access(spi, page);
+	if (ret)
+		return ret;
+
+	txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
+	txbuf[1] = reg;
+	put_unaligned_le16(value, &txbuf[2]);
+
+	return spi_write(spi, txbuf, sizeof(txbuf));
+}
+
+static int b53_spi_write32(struct b53_device *dev, u8 page, u8 reg, u32 value)
+{
+	struct spi_device *spi = dev->priv;
+	int ret;
+	u8 txbuf[6];
+
+	ret = b53_prepare_reg_access(spi, page);
+	if (ret)
+		return ret;
+
+	txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
+	txbuf[1] = reg;
+	put_unaligned_le32(value, &txbuf[2]);
+
+	return spi_write(spi, txbuf, sizeof(txbuf));
+}
+
+static int b53_spi_write48(struct b53_device *dev, u8 page, u8 reg, u64 value)
+{
+	struct spi_device *spi = dev->priv;
+	int ret;
+	u8 txbuf[10];
+
+	ret = b53_prepare_reg_access(spi, page);
+	if (ret)
+		return ret;
+
+	txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
+	txbuf[1] = reg;
+	put_unaligned_le64(value, &txbuf[2]);
+
+	return spi_write(spi, txbuf, sizeof(txbuf) - 2);
+}
+
+static int b53_spi_write64(struct b53_device *dev, u8 page, u8 reg, u64 value)
+{
+	struct spi_device *spi = dev->priv;
+	int ret;
+	u8 txbuf[10];
+
+	ret = b53_prepare_reg_access(spi, page);
+	if (ret)
+		return ret;
+
+	txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
+	txbuf[1] = reg;
+	put_unaligned_le64(value, &txbuf[2]);
+
+	return spi_write(spi, txbuf, sizeof(txbuf));
+}
+
+static struct b53_io_ops b53_spi_ops = {
+	.read8 = b53_spi_read8,
+	.read16 = b53_spi_read16,
+	.read32 = b53_spi_read32,
+	.read48 = b53_spi_read48,
+	.read64 = b53_spi_read64,
+	.write8 = b53_spi_write8,
+	.write16 = b53_spi_write16,
+	.write32 = b53_spi_write32,
+	.write48 = b53_spi_write48,
+	.write64 = b53_spi_write64,
+};
+
+static int b53_spi_probe(struct spi_device *spi)
+{
+	struct b53_device *dev;
+	int ret;
+
+	dev = b53_switch_alloc(&spi->dev, &b53_spi_ops, spi);
+	if (!dev)
+		return -ENOMEM;
+
+	if (spi->dev.platform_data)
+		dev->pdata = spi->dev.platform_data;
+
+	ret = b53_switch_register(dev);
+	if (ret)
+		return ret;
+
+	spi_set_drvdata(spi, dev);
+
+	return 0;
+}
+
+static int b53_spi_remove(struct spi_device *spi)
+{
+	struct b53_device *dev = spi_get_drvdata(spi);
+
+	if (dev)
+		b53_switch_remove(dev);
+
+	return 0;
+}
+
+static const struct of_device_id b53_of_match[] = {
+	{ .compatible = "brcm,bcm5325" },
+	{ .compatible = "brcm,bcm53115" },
+	{ .compatible = "brcm,bcm53125" },
+	{ .compatible = "brcm,bcm53128" },
+	{ .compatible = "brcm,bcm5365" },
+	{ .compatible = "brcm,bcm5395" },
+	{ .compatible = "brcm,bcm5397" },
+	{ .compatible = "brcm,bcm5398" },
+	{ /* sentinel */ },
+};
+
+static struct spi_driver b53_spi_driver = {
+	.driver = {
+		.name	= "b53-switch",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+		.of_match_table = b53_of_match,
+	},
+	.probe	= b53_spi_probe,
+	.remove	= b53_spi_remove,
+};
+
+module_spi_driver(b53_spi_driver);
+
+MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
+MODULE_DESCRIPTION("B53 SPI access driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_srab.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_srab.c
new file mode 100644
index 0000000..012daa3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/b53/b53_srab.c
@@ -0,0 +1,378 @@
+/*
+ * B53 register access through Switch Register Access Bridge Registers
+ *
+ * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/b53.h>
+
+#include "b53_priv.h"
+
+/* command and status register of the SRAB */
+#define B53_SRAB_CMDSTAT		0x2c
+#define  B53_SRAB_CMDSTAT_RST		BIT(2)
+#define  B53_SRAB_CMDSTAT_WRITE		BIT(1)
+#define  B53_SRAB_CMDSTAT_GORDYN	BIT(0)
+#define  B53_SRAB_CMDSTAT_PAGE		24
+#define  B53_SRAB_CMDSTAT_REG		16
+
+/* high order word of write data to switch registe */
+#define B53_SRAB_WD_H			0x30
+
+/* low order word of write data to switch registe */
+#define B53_SRAB_WD_L			0x34
+
+/* high order word of read data from switch register */
+#define B53_SRAB_RD_H			0x38
+
+/* low order word of read data from switch register */
+#define B53_SRAB_RD_L			0x3c
+
+/* command and status register of the SRAB */
+#define B53_SRAB_CTRLS			0x40
+#define  B53_SRAB_CTRLS_RCAREQ		BIT(3)
+#define  B53_SRAB_CTRLS_RCAGNT		BIT(4)
+#define  B53_SRAB_CTRLS_SW_INIT_DONE	BIT(6)
+
+/* the register captures interrupt pulses from the switch */
+#define B53_SRAB_INTR			0x44
+
+static int b53_srab_request_grant(struct b53_device *dev)
+{
+	u8 __iomem *regs = dev->priv;
+	u32 ctrls;
+	int i;
+
+	ctrls = readl(regs + B53_SRAB_CTRLS);
+	ctrls |= B53_SRAB_CTRLS_RCAREQ;
+	writel(ctrls, regs + B53_SRAB_CTRLS);
+
+	for (i = 0; i < 20; i++) {
+		ctrls = readl(regs + B53_SRAB_CTRLS);
+		if (ctrls & B53_SRAB_CTRLS_RCAGNT)
+			break;
+		usleep_range(10, 100);
+	}
+	if (WARN_ON(i == 5))
+		return -EIO;
+
+	return 0;
+}
+
+static void b53_srab_release_grant(struct b53_device *dev)
+{
+	u8 __iomem *regs = dev->priv;
+	u32 ctrls;
+
+	ctrls = readl(regs + B53_SRAB_CTRLS);
+	ctrls &= ~B53_SRAB_CTRLS_RCAREQ;
+	writel(ctrls, regs + B53_SRAB_CTRLS);
+}
+
+static int b53_srab_op(struct b53_device *dev, u8 page, u8 reg, u32 op)
+{
+	int i;
+	u32 cmdstat;
+	u8 __iomem *regs = dev->priv;
+
+	/* set register address */
+	cmdstat = (page << B53_SRAB_CMDSTAT_PAGE) |
+		  (reg << B53_SRAB_CMDSTAT_REG) |
+		  B53_SRAB_CMDSTAT_GORDYN |
+		  op;
+	writel(cmdstat, regs + B53_SRAB_CMDSTAT);
+
+	/* check if operation completed */
+	for (i = 0; i < 5; ++i) {
+		cmdstat = readl(regs + B53_SRAB_CMDSTAT);
+		if (!(cmdstat & B53_SRAB_CMDSTAT_GORDYN))
+			break;
+		usleep_range(10, 100);
+	}
+
+	if (WARN_ON(i == 5))
+		return -EIO;
+
+	return 0;
+}
+
+static int b53_srab_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
+{
+	u8 __iomem *regs = dev->priv;
+	int ret = 0;
+
+	ret = b53_srab_request_grant(dev);
+	if (ret)
+		goto err;
+
+	ret = b53_srab_op(dev, page, reg, 0);
+	if (ret)
+		goto err;
+
+	*val = readl(regs + B53_SRAB_RD_L) & 0xff;
+
+err:
+	b53_srab_release_grant(dev);
+
+	return ret;
+}
+
+static int b53_srab_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
+{
+	u8 __iomem *regs = dev->priv;
+	int ret = 0;
+
+	ret = b53_srab_request_grant(dev);
+	if (ret)
+		goto err;
+
+	ret = b53_srab_op(dev, page, reg, 0);
+	if (ret)
+		goto err;
+
+	*val = readl(regs + B53_SRAB_RD_L) & 0xffff;
+
+err:
+	b53_srab_release_grant(dev);
+
+	return ret;
+}
+
+static int b53_srab_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
+{
+	u8 __iomem *regs = dev->priv;
+	int ret = 0;
+
+	ret = b53_srab_request_grant(dev);
+	if (ret)
+		goto err;
+
+	ret = b53_srab_op(dev, page, reg, 0);
+	if (ret)
+		goto err;
+
+	*val = readl(regs + B53_SRAB_RD_L);
+
+err:
+	b53_srab_release_grant(dev);
+
+	return ret;
+}
+
+static int b53_srab_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	u8 __iomem *regs = dev->priv;
+	int ret = 0;
+
+	ret = b53_srab_request_grant(dev);
+	if (ret)
+		goto err;
+
+	ret = b53_srab_op(dev, page, reg, 0);
+	if (ret)
+		goto err;
+
+	*val = readl(regs + B53_SRAB_RD_L);
+	*val += ((u64)readl(regs + B53_SRAB_RD_H) & 0xffff) << 32;
+
+err:
+	b53_srab_release_grant(dev);
+
+	return ret;
+}
+
+static int b53_srab_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
+{
+	u8 __iomem *regs = dev->priv;
+	int ret = 0;
+
+	ret = b53_srab_request_grant(dev);
+	if (ret)
+		goto err;
+
+	ret = b53_srab_op(dev, page, reg, 0);
+	if (ret)
+		goto err;
+
+	*val = readl(regs + B53_SRAB_RD_L);
+	*val += (u64)readl(regs + B53_SRAB_RD_H) << 32;
+
+err:
+	b53_srab_release_grant(dev);
+
+	return ret;
+}
+
+static int b53_srab_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
+{
+	u8 __iomem *regs = dev->priv;
+	int ret = 0;
+
+	ret = b53_srab_request_grant(dev);
+	if (ret)
+		goto err;
+
+	writel(value, regs + B53_SRAB_WD_L);
+
+	ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
+
+err:
+	b53_srab_release_grant(dev);
+
+	return ret;
+}
+
+static int b53_srab_write16(struct b53_device *dev, u8 page, u8 reg,
+			     u16 value)
+{
+	u8 __iomem *regs = dev->priv;
+	int ret = 0;
+
+	ret = b53_srab_request_grant(dev);
+	if (ret)
+		goto err;
+
+	writel(value, regs + B53_SRAB_WD_L);
+
+	ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
+
+err:
+	b53_srab_release_grant(dev);
+
+	return ret;
+}
+
+static int b53_srab_write32(struct b53_device *dev, u8 page, u8 reg,
+				    u32 value)
+{
+	u8 __iomem *regs = dev->priv;
+	int ret = 0;
+
+	ret = b53_srab_request_grant(dev);
+	if (ret)
+		goto err;
+
+	writel(value, regs + B53_SRAB_WD_L);
+
+	ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
+
+err:
+	b53_srab_release_grant(dev);
+
+	return ret;
+
+}
+
+static int b53_srab_write48(struct b53_device *dev, u8 page, u8 reg,
+				    u64 value)
+{
+	u8 __iomem *regs = dev->priv;
+	int ret = 0;
+
+	ret = b53_srab_request_grant(dev);
+	if (ret)
+		goto err;
+
+	writel((u32)value, regs + B53_SRAB_WD_L);
+	writel((u16)(value >> 32), regs + B53_SRAB_WD_H);
+
+	ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
+
+err:
+	b53_srab_release_grant(dev);
+
+	return ret;
+
+}
+
+static int b53_srab_write64(struct b53_device *dev, u8 page, u8 reg,
+			     u64 value)
+{
+	u8 __iomem *regs = dev->priv;
+	int ret = 0;
+
+	ret = b53_srab_request_grant(dev);
+	if (ret)
+		goto err;
+
+	writel((u32)value, regs + B53_SRAB_WD_L);
+	writel((u32)(value >> 32), regs + B53_SRAB_WD_H);
+
+	ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
+
+err:
+	b53_srab_release_grant(dev);
+
+	return ret;
+}
+
+static struct b53_io_ops b53_srab_ops = {
+	.read8 = b53_srab_read8,
+	.read16 = b53_srab_read16,
+	.read32 = b53_srab_read32,
+	.read48 = b53_srab_read48,
+	.read64 = b53_srab_read64,
+	.write8 = b53_srab_write8,
+	.write16 = b53_srab_write16,
+	.write32 = b53_srab_write32,
+	.write48 = b53_srab_write48,
+	.write64 = b53_srab_write64,
+};
+
+static int b53_srab_probe(struct platform_device *pdev)
+{
+	struct b53_platform_data *pdata = pdev->dev.platform_data;
+	struct b53_device *dev;
+
+	if (!pdata)
+		return -EINVAL;
+
+	dev = b53_switch_alloc(&pdev->dev, &b53_srab_ops, pdata->regs);
+	if (!dev)
+		return -ENOMEM;
+
+	if (pdata)
+		dev->pdata = pdata;
+
+	platform_set_drvdata(pdev, dev);
+
+	return b53_switch_register(dev);
+}
+
+static int b53_srab_remove(struct platform_device *pdev)
+{
+	struct b53_device *dev = platform_get_drvdata(pdev);
+
+	if (dev)
+		b53_switch_remove(dev);
+
+	return 0;
+}
+
+static struct platform_driver b53_srab_driver = {
+	.probe = b53_srab_probe,
+	.remove = b53_srab_remove,
+	.driver = {
+		.name = "b53-srab-switch",
+	},
+};
+
+module_platform_driver(b53_srab_driver);
+MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
+MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/ip17xx.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/ip17xx.c
new file mode 100644
index 0000000..c369803
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/ip17xx.c
@@ -0,0 +1,1370 @@
+/*
+ * ip17xx.c: Swconfig configuration for IC+ IP17xx switch family
+ *
+ * Copyright (C) 2008 Patrick Horn <patrick.horn@gmail.com>
+ * Copyright (C) 2008, 2010 Martin Mares <mj@ucw.cz>
+ * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/delay.h>
+#include <linux/switch.h>
+#include <linux/device.h>
+
+#define MAX_VLANS 16
+#define MAX_PORTS 9
+#undef DUMP_MII_IO
+
+typedef struct ip17xx_reg {
+	u16 p;			// phy
+	u16 m;			// mii
+} reg;
+typedef char bitnum;
+
+#define NOTSUPPORTED {-1,-1}
+
+#define REG_SUPP(x) (((x).m != ((u16)-1)) && ((x).p != (u16)-1))
+
+struct ip17xx_state;
+
+/*********** CONSTANTS ***********/
+struct register_mappings {
+	char *NAME;
+	u16 MODEL_NO;			// Compare to bits 4-9 of MII register 0,3.
+	bitnum NUM_PORTS;
+	bitnum CPU_PORT;
+
+/* The default VLAN for each port.
+	 Default: 0x0001 for Ports 0,1,2,3
+		  0x0002 for Ports 4,5 */
+	reg VLAN_DEFAULT_TAG_REG[MAX_PORTS];
+
+/* These ports are tagged.
+	 Default: 0x00 */
+	reg ADD_TAG_REG;
+	reg REMOVE_TAG_REG;
+	bitnum ADD_TAG_BIT[MAX_PORTS];
+/* These ports are untagged.
+	 Default: 0x00 (i.e. do not alter any VLAN tags...)
+	 Maybe set to 0 if user disables VLANs. */
+	bitnum REMOVE_TAG_BIT[MAX_PORTS];
+
+/* Port M and Port N are on the same VLAN.
+	 Default: All ports on all VLANs. */
+// Use register {29, 19+N/2}
+	reg VLAN_LOOKUP_REG;
+// Port 5 uses register {30, 18} but same as odd bits.
+	reg VLAN_LOOKUP_REG_5;		// in a different register on IP175C.
+	bitnum VLAN_LOOKUP_EVEN_BIT[MAX_PORTS];
+	bitnum VLAN_LOOKUP_ODD_BIT[MAX_PORTS];
+
+/* This VLAN corresponds to which ports.
+	 Default: 0x2f,0x30,0x3f,0x3f... */
+	reg TAG_VLAN_MASK_REG;
+	bitnum TAG_VLAN_MASK_EVEN_BIT[MAX_PORTS];
+	bitnum TAG_VLAN_MASK_ODD_BIT[MAX_PORTS];
+
+	int RESET_VAL;
+	reg RESET_REG;
+
+	reg MODE_REG;
+	int MODE_VAL;
+
+/* General flags */
+	reg ROUTER_CONTROL_REG;
+	reg VLAN_CONTROL_REG;
+	bitnum TAG_VLAN_BIT;
+	bitnum ROUTER_EN_BIT;
+	bitnum NUMLAN_GROUPS_MAX;
+	bitnum NUMLAN_GROUPS_BIT;
+
+	reg MII_REGISTER_EN;
+	bitnum MII_REGISTER_EN_BIT;
+
+	// set to 1 for 178C, 0 for 175C.
+	bitnum SIMPLE_VLAN_REGISTERS;	// 175C has two vlans per register but 178C has only one.
+
+	// Pointers to functions which manipulate hardware state
+	int (*update_state)(struct ip17xx_state *state);
+	int (*set_vlan_mode)(struct ip17xx_state *state);
+	int (*reset)(struct ip17xx_state *state);
+};
+
+static int ip175c_update_state(struct ip17xx_state *state);
+static int ip175c_set_vlan_mode(struct ip17xx_state *state);
+static int ip175c_reset(struct ip17xx_state *state);
+
+static const struct register_mappings IP178C = {
+	.NAME = "IP178C",
+	.MODEL_NO = 0x18,
+	.VLAN_DEFAULT_TAG_REG = {
+		{30,3},{30,4},{30,5},{30,6},{30,7},{30,8},
+		{30,9},{30,10},{30,11},
+	},
+
+	.ADD_TAG_REG = {30,12},
+	.ADD_TAG_BIT = {0,1,2,3,4,5,6,7,8},
+	.REMOVE_TAG_REG = {30,13},
+	.REMOVE_TAG_BIT = {4,5,6,7,8,9,10,11,12},
+
+	.SIMPLE_VLAN_REGISTERS = 1,
+
+	.VLAN_LOOKUP_REG = {31,0},// +N
+	.VLAN_LOOKUP_REG_5 = NOTSUPPORTED, // not used with SIMPLE_VLAN_REGISTERS
+	.VLAN_LOOKUP_EVEN_BIT = {0,1,2,3,4,5,6,7,8},
+	.VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,5,6,7,8},
+
+	.TAG_VLAN_MASK_REG = {30,14}, // +N
+	.TAG_VLAN_MASK_EVEN_BIT = {0,1,2,3,4,5,6,7,8},
+	.TAG_VLAN_MASK_ODD_BIT = {0,1,2,3,4,5,6,7,8},
+
+	.RESET_VAL = 0x55AA,
+	.RESET_REG = {30,0},
+	.MODE_VAL = 0,
+	.MODE_REG = NOTSUPPORTED,
+
+	.ROUTER_CONTROL_REG = {30,30},
+	.ROUTER_EN_BIT = 11,
+	.NUMLAN_GROUPS_MAX = 8,
+	.NUMLAN_GROUPS_BIT = 8, // {0-2}
+
+	.VLAN_CONTROL_REG = {30,13},
+	.TAG_VLAN_BIT = 3,
+
+	.CPU_PORT = 8,
+	.NUM_PORTS = 9,
+
+	.MII_REGISTER_EN = NOTSUPPORTED,
+
+	.update_state = ip175c_update_state,
+	.set_vlan_mode = ip175c_set_vlan_mode,
+	.reset = ip175c_reset,
+};
+
+static const struct register_mappings IP175C = {
+	.NAME = "IP175C",
+	.MODEL_NO = 0x18,
+	.VLAN_DEFAULT_TAG_REG = {
+		{29,24},{29,25},{29,26},{29,27},{29,28},{29,30},
+		NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED
+	},
+
+	.ADD_TAG_REG = {29,23},
+	.REMOVE_TAG_REG = {29,23},
+	.ADD_TAG_BIT = {11,12,13,14,15,1,-1,-1,-1},
+	.REMOVE_TAG_BIT = {6,7,8,9,10,0,-1,-1,-1},
+
+	.SIMPLE_VLAN_REGISTERS = 0,
+
+	.VLAN_LOOKUP_REG = {29,19},// +N/2
+	.VLAN_LOOKUP_REG_5 = {30,18},
+	.VLAN_LOOKUP_EVEN_BIT = {8,9,10,11,12,15,-1,-1,-1},
+	.VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,7,-1,-1,-1},
+
+	.TAG_VLAN_MASK_REG = {30,1}, // +N/2
+	.TAG_VLAN_MASK_EVEN_BIT = {0,1,2,3,4,5,-1,-1,-1},
+	.TAG_VLAN_MASK_ODD_BIT = {8,9,10,11,12,13,-1,-1,-1},
+
+	.RESET_VAL = 0x175C,
+	.RESET_REG = {30,0},
+	.MODE_VAL = 0x175C,
+	.MODE_REG = {29,31},
+
+	.ROUTER_CONTROL_REG = {30,9},
+	.ROUTER_EN_BIT = 3,
+	.NUMLAN_GROUPS_MAX = 8,
+	.NUMLAN_GROUPS_BIT = 0, // {0-2}
+
+	.VLAN_CONTROL_REG = {30,9},
+	.TAG_VLAN_BIT = 7,
+
+	.NUM_PORTS = 6,
+	.CPU_PORT = 5,
+
+	.MII_REGISTER_EN = NOTSUPPORTED,
+
+	.update_state = ip175c_update_state,
+	.set_vlan_mode = ip175c_set_vlan_mode,
+	.reset = ip175c_reset,
+};
+
+static const struct register_mappings IP175A = {
+	.NAME = "IP175A",
+	.MODEL_NO = 0x05,
+	.VLAN_DEFAULT_TAG_REG = {
+		{0,24},{0,25},{0,26},{0,27},{0,28},NOTSUPPORTED,
+		NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED
+	},
+
+	.ADD_TAG_REG = {0,23},
+	.REMOVE_TAG_REG = {0,23},
+	.ADD_TAG_BIT = {11,12,13,14,15,-1,-1,-1,-1},
+	.REMOVE_TAG_BIT = {6,7,8,9,10,-1,-1,-1,-1},
+
+	.SIMPLE_VLAN_REGISTERS = 0,
+
+	// Only programmable via EEPROM
+	.VLAN_LOOKUP_REG = NOTSUPPORTED,// +N/2
+	.VLAN_LOOKUP_REG_5 = NOTSUPPORTED,
+	.VLAN_LOOKUP_EVEN_BIT = {8,9,10,11,12,-1,-1,-1,-1},
+	.VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,-1,-1,-1,-1},
+
+	.TAG_VLAN_MASK_REG = NOTSUPPORTED, // +N/2,
+	.TAG_VLAN_MASK_EVEN_BIT = {-1,-1,-1,-1,-1,-1,-1,-1,-1},
+	.TAG_VLAN_MASK_ODD_BIT = {-1,-1,-1,-1,-1,-1,-1,-1,-1},
+
+	.RESET_VAL = -1,
+	.RESET_REG = NOTSUPPORTED,
+	.MODE_VAL = 0,
+	.MODE_REG = NOTSUPPORTED,
+
+	.ROUTER_CONTROL_REG = NOTSUPPORTED,
+	.VLAN_CONTROL_REG = NOTSUPPORTED,
+	.TAG_VLAN_BIT = -1,
+	.ROUTER_EN_BIT = -1,
+	.NUMLAN_GROUPS_MAX = -1,
+	.NUMLAN_GROUPS_BIT = -1, // {0-2}
+
+	.NUM_PORTS = 5,
+	.CPU_PORT = 4,
+
+	.MII_REGISTER_EN = {0, 18},
+	.MII_REGISTER_EN_BIT = 7,
+
+	.update_state = ip175c_update_state,
+	.set_vlan_mode = ip175c_set_vlan_mode,
+	.reset = ip175c_reset,
+};
+
+
+static int ip175d_update_state(struct ip17xx_state *state);
+static int ip175d_set_vlan_mode(struct ip17xx_state *state);
+static int ip175d_reset(struct ip17xx_state *state);
+
+static const struct register_mappings IP175D = {
+	.NAME = "IP175D",
+	.MODEL_NO = 0x18,
+
+	// The IP175D has a completely different interface, so we leave most
+	// of the registers undefined and switch to different code paths.
+
+	.VLAN_DEFAULT_TAG_REG = {
+		NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,
+		NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,
+	},
+
+	.ADD_TAG_REG = NOTSUPPORTED,
+	.REMOVE_TAG_REG = NOTSUPPORTED,
+
+	.SIMPLE_VLAN_REGISTERS = 0,
+
+	.VLAN_LOOKUP_REG = NOTSUPPORTED,
+	.VLAN_LOOKUP_REG_5 = NOTSUPPORTED,
+	.TAG_VLAN_MASK_REG = NOTSUPPORTED,
+
+	.RESET_VAL = 0x175D,
+	.RESET_REG = {20,2},
+	.MODE_REG = NOTSUPPORTED,
+
+	.ROUTER_CONTROL_REG = NOTSUPPORTED,
+	.ROUTER_EN_BIT = -1,
+	.NUMLAN_GROUPS_BIT = -1,
+
+	.VLAN_CONTROL_REG = NOTSUPPORTED,
+	.TAG_VLAN_BIT = -1,
+
+	.NUM_PORTS = 6,
+	.CPU_PORT = 5,
+
+	.MII_REGISTER_EN = NOTSUPPORTED,
+
+	.update_state = ip175d_update_state,
+	.set_vlan_mode = ip175d_set_vlan_mode,
+	.reset = ip175d_reset,
+};
+
+struct ip17xx_state {
+	struct switch_dev dev;
+	struct mii_bus *mii_bus;
+	bool registered;
+
+	int router_mode;		// ROUTER_EN
+	int vlan_enabled;		// TAG_VLAN_EN
+	struct port_state {
+		u16 pvid;
+		unsigned int shareports;
+	} ports[MAX_PORTS];
+	unsigned int add_tag;
+	unsigned int remove_tag;
+	int num_vlans;
+	struct vlan_state {
+		unsigned int ports;
+		unsigned int tag;	// VLAN tag (IP175D only)
+	} vlans[MAX_VLANS];
+	const struct register_mappings *regs;
+	reg proc_mii; 	// phy/reg for the low level register access via swconfig
+
+	char buf[80];
+};
+
+#define get_state(_dev) container_of((_dev), struct ip17xx_state, dev)
+
+static int ip_phy_read(struct ip17xx_state *state, int port, int reg)
+{
+	int val = mdiobus_read(state->mii_bus, port, reg);
+	if (val < 0)
+		pr_warn("IP17xx: Unable to get MII register %d,%d: error %d\n", port, reg, -val);
+#ifdef DUMP_MII_IO
+	else
+		pr_debug("IP17xx: Read MII(%d,%d) -> %04x\n", port, reg, val);
+#endif
+	return val;
+}
+
+static int ip_phy_write(struct ip17xx_state *state, int port, int reg, u16 val)
+{
+	int err;
+
+#ifdef DUMP_MII_IO
+	pr_debug("IP17xx: Write MII(%d,%d) <- %04x\n", port, reg, val);
+#endif
+	err = mdiobus_write(state->mii_bus, port, reg, val);
+	if (err < 0)
+		pr_warn("IP17xx: Unable to write MII register %d,%d: error %d\n", port, reg, -err);
+	return err;
+}
+
+static int ip_phy_write_masked(struct ip17xx_state *state, int port, int reg, unsigned int mask, unsigned int data)
+{
+	int val = ip_phy_read(state, port, reg);
+	if (val < 0)
+		return 0;
+	return ip_phy_write(state, port, reg, (val & ~mask) | data);
+}
+
+static int getPhy(struct ip17xx_state *state, reg mii)
+{
+	if (!REG_SUPP(mii))
+		return -EFAULT;
+	return ip_phy_read(state, mii.p, mii.m);
+}
+
+static int setPhy(struct ip17xx_state *state, reg mii, u16 value)
+{
+	int err;
+
+	if (!REG_SUPP(mii))
+		return -EFAULT;
+	err = ip_phy_write(state, mii.p, mii.m, value);
+	if (err < 0)
+		return err;
+	mdelay(2);
+	getPhy(state, mii);
+	return 0;
+}
+
+
+/**
+ * These two macros are to simplify the mapping of logical bits to the bits in hardware.
+ * NOTE: these macros will return if there is an error!
+ */
+
+#define GET_PORT_BITS(state, bits, addr, bit_lookup)		\
+	do {							\
+		int i, val = getPhy((state), (addr));		\
+		if (val < 0)					\
+			return val;				\
+		(bits) = 0;					\
+		for (i = 0; i < MAX_PORTS; i++) {		\
+			if ((bit_lookup)[i] == -1) continue;	\
+			if (val & (1<<(bit_lookup)[i]))		\
+				(bits) |= (1<<i);		\
+		}						\
+	} while (0)
+
+#define SET_PORT_BITS(state, bits, addr, bit_lookup)		\
+	do {							\
+		int i, val = getPhy((state), (addr));		\
+		if (val < 0)					\
+			return val;				\
+		for (i = 0; i < MAX_PORTS; i++) {		\
+			unsigned int newmask = ((bits)&(1<<i));	\
+			if ((bit_lookup)[i] == -1) continue;	\
+			val &= ~(1<<(bit_lookup)[i]);		\
+			val |= ((newmask>>i)<<(bit_lookup)[i]);	\
+		}						\
+		val = setPhy((state), (addr), val);		\
+		if (val < 0)					\
+			return val;				\
+	} while (0)
+
+
+static int get_model(struct ip17xx_state *state)
+{
+	int id1, id2;
+	int oui_id, model_no, rev_no, chip_no;
+
+	id1 = ip_phy_read(state, 0, 2);
+	id2 = ip_phy_read(state, 0, 3);
+	oui_id = (id1 << 6) | ((id2 >> 10) & 0x3f);
+	model_no = (id2 >> 4) & 0x3f;
+	rev_no = id2 & 0xf;
+	pr_debug("IP17xx: Identified oui=%06x model=%02x rev=%X\n", oui_id, model_no, rev_no);
+
+	if (oui_id != 0x0090c3)  // No other oui_id should have reached us anyway
+		return -ENODEV;
+
+	if (model_no == IP175A.MODEL_NO) {
+		state->regs = &IP175A;
+	} else if (model_no == IP175C.MODEL_NO) {
+		/*
+		 *  Several models share the same model_no:
+		 *  178C has more PHYs, so we try whether the device responds to a read from PHY5
+		 *  175D has a new chip ID register
+		 *  175C has neither
+		 */
+		if (ip_phy_read(state, 5, 2) == 0x0243) {
+			state->regs = &IP178C;
+		} else {
+			chip_no = ip_phy_read(state, 20, 0);
+			pr_debug("IP17xx: Chip ID register reads %04x\n", chip_no);
+			if (chip_no == 0x175d) {
+				state->regs = &IP175D;
+			} else {
+				state->regs = &IP175C;
+			}
+		}
+	} else {
+		pr_warn("IP17xx: Found an unknown IC+ switch with model number %02x, revision %X.\n", model_no, rev_no);
+		return -EPERM;
+	}
+	return 0;
+}
+
+/*** Low-level functions for the older models ***/
+
+/** Only set vlan and router flags in the switch **/
+static int ip175c_set_flags(struct ip17xx_state *state)
+{
+	int val;
+
+	if (!REG_SUPP(state->regs->ROUTER_CONTROL_REG)) {
+		return 0;
+	}
+
+	val = getPhy(state, state->regs->ROUTER_CONTROL_REG);
+	if (val < 0) {
+		return val;
+	}
+	if (state->regs->ROUTER_EN_BIT >= 0) {
+		if (state->router_mode) {
+			val |= (1<<state->regs->ROUTER_EN_BIT);
+		} else {
+			val &= (~(1<<state->regs->ROUTER_EN_BIT));
+		}
+	}
+	if (state->regs->TAG_VLAN_BIT >= 0) {
+		if (state->vlan_enabled) {
+			val |= (1<<state->regs->TAG_VLAN_BIT);
+		} else {
+			val &= (~(1<<state->regs->TAG_VLAN_BIT));
+		}
+	}
+	if (state->regs->NUMLAN_GROUPS_BIT >= 0) {
+		val &= (~((state->regs->NUMLAN_GROUPS_MAX-1)<<state->regs->NUMLAN_GROUPS_BIT));
+		if (state->num_vlans > state->regs->NUMLAN_GROUPS_MAX) {
+			val |= state->regs->NUMLAN_GROUPS_MAX << state->regs->NUMLAN_GROUPS_BIT;
+		} else if (state->num_vlans >= 1) {
+			val |= (state->num_vlans-1) << state->regs->NUMLAN_GROUPS_BIT;
+		}
+	}
+	return setPhy(state, state->regs->ROUTER_CONTROL_REG, val);
+}
+
+/** Set all VLAN and port state.  Usually you should call "correct_vlan_state" first. **/
+static int ip175c_set_state(struct ip17xx_state *state)
+{
+	int j;
+	int i;
+	SET_PORT_BITS(state, state->add_tag,
+				  state->regs->ADD_TAG_REG, state->regs->ADD_TAG_BIT);
+	SET_PORT_BITS(state, state->remove_tag,
+				  state->regs->REMOVE_TAG_REG, state->regs->REMOVE_TAG_BIT);
+
+	if (REG_SUPP(state->regs->VLAN_LOOKUP_REG)) {
+		for (j=0; j<state->regs->NUM_PORTS; j++) {
+			reg addr;
+			const bitnum *bit_lookup = (j%2==0)?
+				state->regs->VLAN_LOOKUP_EVEN_BIT:
+				state->regs->VLAN_LOOKUP_ODD_BIT;
+
+			addr = state->regs->VLAN_LOOKUP_REG;
+			if (state->regs->SIMPLE_VLAN_REGISTERS) {
+				addr.m += j;
+			} else {
+				switch (j) {
+				case 0:
+				case 1:
+					break;
+				case 2:
+				case 3:
+					addr.m+=1;
+					break;
+				case 4:
+					addr.m+=2;
+					break;
+				case 5:
+					addr = state->regs->VLAN_LOOKUP_REG_5;
+					break;
+				default:
+					addr.m = -1; // shouldn't get here, but...
+					break;
+				}
+			}
+			//printf("shareports for %d is %02X\n",j,state->ports[j].shareports);
+			if (REG_SUPP(addr)) {
+				SET_PORT_BITS(state, state->ports[j].shareports, addr, bit_lookup);
+			}
+		}
+	}
+	if (REG_SUPP(state->regs->TAG_VLAN_MASK_REG)) {
+		for (j=0; j<MAX_VLANS; j++) {
+			reg addr = state->regs->TAG_VLAN_MASK_REG;
+			const bitnum *bit_lookup = (j%2==0)?
+				state->regs->TAG_VLAN_MASK_EVEN_BIT:
+				state->regs->TAG_VLAN_MASK_ODD_BIT;
+			unsigned int vlan_mask;
+			if (state->regs->SIMPLE_VLAN_REGISTERS) {
+				addr.m += j;
+			} else {
+				addr.m += j/2;
+			}
+			vlan_mask = state->vlans[j].ports;
+			SET_PORT_BITS(state, vlan_mask, addr, bit_lookup);
+		}
+	}
+
+	for (i=0; i<MAX_PORTS; i++) {
+		if (REG_SUPP(state->regs->VLAN_DEFAULT_TAG_REG[i])) {
+			int err = setPhy(state, state->regs->VLAN_DEFAULT_TAG_REG[i],
+					state->ports[i].pvid);
+			if (err < 0) {
+				return err;
+			}
+		}
+	}
+
+	return ip175c_set_flags(state);
+}
+
+/**
+ *  Uses only the VLAN port mask and the add tag mask to generate the other fields:
+ *  which ports are part of the same VLAN, removing vlan tags, and VLAN tag ids.
+ */
+static void ip175c_correct_vlan_state(struct ip17xx_state *state)
+{
+	int i, j;
+	state->num_vlans = 0;
+	for (i=0; i<MAX_VLANS; i++) {
+		if (state->vlans[i].ports != 0) {
+			state->num_vlans = i+1; // Hack -- we need to store the "set" vlans somewhere...
+		}
+	}
+
+	for (i=0; i<state->regs->NUM_PORTS; i++) {
+		unsigned int portmask = (1<<i);
+		if (!state->vlan_enabled) {
+			// Share with everybody!
+			state->ports[i].shareports = (1<<state->regs->NUM_PORTS)-1;
+			continue;
+		}
+		state->ports[i].shareports = portmask;
+		for (j=0; j<MAX_VLANS; j++) {
+			if (state->vlans[j].ports & portmask)
+				state->ports[i].shareports |= state->vlans[j].ports;
+		}
+	}
+}
+
+static int ip175c_update_state(struct ip17xx_state *state)
+{
+	ip175c_correct_vlan_state(state);
+	return ip175c_set_state(state);
+}
+
+static int ip175c_set_vlan_mode(struct ip17xx_state *state)
+{
+	return ip175c_update_state(state);
+}
+
+static int ip175c_reset(struct ip17xx_state *state)
+{
+	int err;
+
+	if (REG_SUPP(state->regs->MODE_REG)) {
+		err = setPhy(state, state->regs->MODE_REG, state->regs->MODE_VAL);
+		if (err < 0)
+			return err;
+		err = getPhy(state, state->regs->MODE_REG);
+		if (err < 0)
+			return err;
+	}
+
+	return ip175c_update_state(state);
+}
+
+/*** Low-level functions for IP175D ***/
+
+static int ip175d_update_state(struct ip17xx_state *state)
+{
+	unsigned int filter_mask = 0;
+	unsigned int ports[16], add[16], rem[16];
+	int i, j;
+	int err = 0;
+
+	for (i = 0; i < 16; i++) {
+		ports[i] = 0;
+		add[i] = 0;
+		rem[i] = 0;
+		if (!state->vlan_enabled) {
+			err |= ip_phy_write(state, 22, 14+i, i+1);	// default tags
+			ports[i] = 0x3f;
+			continue;
+		}
+		if (!state->vlans[i].tag) {
+			// Reset the filter
+			err |= ip_phy_write(state, 22, 14+i, 0);	// tag
+			continue;
+		}
+		filter_mask |= 1 << i;
+		err |= ip_phy_write(state, 22, 14+i, state->vlans[i].tag);
+		ports[i] = state->vlans[i].ports;
+		for (j = 0; j < 6; j++) {
+			if (ports[i] & (1 << j)) {
+				if (state->add_tag & (1 << j))
+					add[i] |= 1 << j;
+				if (state->remove_tag & (1 << j))
+					rem[i] |= 1 << j;
+			}
+		}
+	}
+
+	// Port masks, tag adds and removals
+	for (i = 0; i < 8; i++) {
+		err |= ip_phy_write(state, 23, i, ports[2*i] | (ports[2*i+1] << 8));
+		err |= ip_phy_write(state, 23, 8+i, add[2*i] | (add[2*i+1] << 8));
+		err |= ip_phy_write(state, 23, 16+i, rem[2*i] | (rem[2*i+1] << 8));
+	}
+	err |= ip_phy_write(state, 22, 10, filter_mask);
+
+	// Default VLAN tag for each port
+	for (i = 0; i < 6; i++)
+		err |= ip_phy_write(state, 22, 4+i, state->vlans[state->ports[i].pvid].tag);
+
+	return (err ? -EIO : 0);
+}
+
+static int ip175d_set_vlan_mode(struct ip17xx_state *state)
+{
+	int i;
+	int err = 0;
+
+	if (state->vlan_enabled) {
+		// VLAN classification rules: tag-based VLANs, use VID to classify,
+		// drop packets that cannot be classified.
+		err |= ip_phy_write_masked(state, 22, 0, 0x3fff, 0x003f);
+
+		// Ingress rules: CFI=1 dropped, null VID is untagged, VID=1 passed,
+		// VID=0xfff discarded, admin both tagged and untagged, ingress
+		// filters enabled.
+		err |= ip_phy_write_masked(state, 22, 1, 0x0fff, 0x0c3f);
+
+		// Egress rules: IGMP processing off, keep VLAN header off
+		err |= ip_phy_write_masked(state, 22, 2, 0x0fff, 0x0000);
+	} else {
+		// VLAN classification rules: everything off & clear table
+		err |= ip_phy_write_masked(state, 22, 0, 0xbfff, 0x8000);
+
+		// Ingress and egress rules: set to defaults
+		err |= ip_phy_write_masked(state, 22, 1, 0x0fff, 0x0c3f);
+		err |= ip_phy_write_masked(state, 22, 2, 0x0fff, 0x0000);
+	}
+
+	// Reset default VLAN for each port to 0
+	for (i = 0; i < 6; i++)
+		state->ports[i].pvid = 0;
+
+	err |= ip175d_update_state(state);
+
+	return (err ? -EIO : 0);
+}
+
+static int ip175d_reset(struct ip17xx_state *state)
+{
+	int err = 0;
+
+	// Disable the special tagging mode
+	err |= ip_phy_write_masked(state, 21, 22, 0x0003, 0x0000);
+
+	// Set 802.1q protocol type
+	err |= ip_phy_write(state, 22, 3, 0x8100);
+
+	state->vlan_enabled = 0;
+	err |= ip175d_set_vlan_mode(state);
+
+	return (err ? -EIO : 0);
+}
+
+/*** High-level functions ***/
+
+static int ip17xx_get_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+
+	val->value.i = state->vlan_enabled;
+	return 0;
+}
+
+static void ip17xx_reset_vlan_config(struct ip17xx_state *state)
+{
+	int i;
+
+	state->remove_tag = (state->vlan_enabled ? ((1<<state->regs->NUM_PORTS)-1) : 0x0000);
+	state->add_tag = 0x0000;
+	for (i = 0; i < MAX_VLANS; i++) {
+		state->vlans[i].ports = 0x0000;
+		state->vlans[i].tag = (i ? i : 16);
+	}
+	for (i = 0; i < MAX_PORTS; i++)
+		state->ports[i].pvid = 0;
+}
+
+static int ip17xx_set_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int enable;
+
+	enable = val->value.i;
+	if (state->vlan_enabled == enable) {
+		// Do not change any state.
+		return 0;
+	}
+	state->vlan_enabled = enable;
+
+	// Otherwise, if we are switching state, set fields to a known default.
+	ip17xx_reset_vlan_config(state);
+
+	return state->regs->set_vlan_mode(state);
+}
+
+static int ip17xx_get_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int b;
+	int ind;
+	unsigned int ports;
+
+	if (val->port_vlan >= dev->vlans || val->port_vlan < 0)
+		return -EINVAL;
+
+	ports = state->vlans[val->port_vlan].ports;
+	b = 0;
+	ind = 0;
+	while (b < MAX_PORTS) {
+		if (ports&1) {
+			int istagged = ((state->add_tag >> b) & 1);
+			val->value.ports[ind].id = b;
+			val->value.ports[ind].flags = (istagged << SWITCH_PORT_FLAG_TAGGED);
+			ind++;
+		}
+		b++;
+		ports >>= 1;
+	}
+	val->len = ind;
+
+	return 0;
+}
+
+static int ip17xx_set_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int i;
+
+	if (val->port_vlan >= dev->vlans || val->port_vlan < 0)
+		return -EINVAL;
+
+	state->vlans[val->port_vlan].ports = 0;
+	for (i = 0; i < val->len; i++) {
+		unsigned int bitmask = (1<<val->value.ports[i].id);
+		state->vlans[val->port_vlan].ports |= bitmask;
+		if (val->value.ports[i].flags & (1<<SWITCH_PORT_FLAG_TAGGED)) {
+			state->add_tag |= bitmask;
+			state->remove_tag &= (~bitmask);
+		} else {
+			state->add_tag &= (~bitmask);
+			state->remove_tag |= bitmask;
+		}
+	}
+
+	return state->regs->update_state(state);
+}
+
+static int ip17xx_apply(struct switch_dev *dev)
+{
+	struct ip17xx_state *state = get_state(dev);
+
+	if (REG_SUPP(state->regs->MII_REGISTER_EN)) {
+		int val = getPhy(state, state->regs->MII_REGISTER_EN);
+		if (val < 0) {
+			return val;
+		}
+		val |= (1<<state->regs->MII_REGISTER_EN_BIT);
+		return setPhy(state, state->regs->MII_REGISTER_EN, val);
+	}
+	return 0;
+}
+
+static int ip17xx_reset(struct switch_dev *dev)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int i, err;
+
+	if (REG_SUPP(state->regs->RESET_REG)) {
+		err = setPhy(state, state->regs->RESET_REG, state->regs->RESET_VAL);
+		if (err < 0)
+			return err;
+		err = getPhy(state, state->regs->RESET_REG);
+
+		/*
+		 *  Data sheet specifies reset period to be 2 msec.
+		 *  (I don't see any mention of the 2ms delay in the IP178C spec, only
+		 *  in IP175C, but it can't hurt.)
+		 */
+		mdelay(2);
+	}
+
+	/* reset switch ports */
+	for (i = 0; i < state->regs->NUM_PORTS-1; i++) {
+		err = ip_phy_write(state, i, MII_BMCR, BMCR_RESET);
+		if (err < 0)
+			return err;
+	}
+
+	state->router_mode = 0;
+	state->vlan_enabled = 0;
+	ip17xx_reset_vlan_config(state);
+
+	return state->regs->reset(state);
+}
+
+static int ip17xx_get_tagged(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+
+	if (state->add_tag & (1<<val->port_vlan)) {
+		if (state->remove_tag & (1<<val->port_vlan))
+			val->value.i = 3; // shouldn't ever happen.
+		else
+			val->value.i = 1;
+	} else {
+		if (state->remove_tag & (1<<val->port_vlan))
+			val->value.i = 0;
+		else
+			val->value.i = 2;
+	}
+	return 0;
+}
+
+static int ip17xx_set_tagged(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+
+	state->add_tag &= ~(1<<val->port_vlan);
+	state->remove_tag &= ~(1<<val->port_vlan);
+
+	if (val->value.i == 0)
+		state->remove_tag |= (1<<val->port_vlan);
+	if (val->value.i == 1)
+		state->add_tag |= (1<<val->port_vlan);
+
+	return state->regs->update_state(state);
+}
+
+/** Get the current phy address */
+static int ip17xx_get_phy(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+
+	val->value.i = state->proc_mii.p;
+	return 0;
+}
+
+/** Set a new phy address for low level access to registers */
+static int ip17xx_set_phy(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int new_reg = val->value.i;
+
+	if (new_reg < 0 || new_reg > 31)
+		state->proc_mii.p = (u16)-1;
+	else
+		state->proc_mii.p = (u16)new_reg;
+	return 0;
+}
+
+/** Get the current register number */
+static int ip17xx_get_reg(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+
+	val->value.i = state->proc_mii.m;
+	return 0;
+}
+
+/** Set a new register address for low level access to registers */
+static int ip17xx_set_reg(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int new_reg = val->value.i;
+
+	if (new_reg < 0 || new_reg > 31)
+		state->proc_mii.m = (u16)-1;
+	else
+		state->proc_mii.m = (u16)new_reg;
+	return 0;
+}
+
+/** Get the register content of state->proc_mii */
+static int ip17xx_get_val(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int retval = -EINVAL;
+	if (REG_SUPP(state->proc_mii))
+		retval = getPhy(state, state->proc_mii);
+
+	if (retval < 0) {
+		return retval;
+	} else {
+		val->value.i = retval;
+		return 0;
+	}
+}
+
+/** Write a value to the register defined by phy/reg above */
+static int ip17xx_set_val(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int myval, err = -EINVAL;
+
+	myval = val->value.i;
+	if (myval <= 0xffff && myval >= 0 && REG_SUPP(state->proc_mii)) {
+		err = setPhy(state, state->proc_mii, (u16)myval);
+	}
+	return err;
+}
+
+static int ip17xx_read_name(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	val->value.s = state->regs->NAME; // Just a const pointer, won't be freed by swconfig.
+	return 0;
+}
+
+static int ip17xx_get_tag(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int vlan = val->port_vlan;
+
+	if (vlan < 0 || vlan >= MAX_VLANS)
+		return -EINVAL;
+
+	val->value.i = state->vlans[vlan].tag;
+	return 0;
+}
+
+static int ip17xx_set_tag(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int vlan = val->port_vlan;
+	int tag = val->value.i;
+
+	if (vlan < 0 || vlan >= MAX_VLANS)
+		return -EINVAL;
+
+	if (tag < 0 || tag > 4095)
+		return -EINVAL;
+
+	state->vlans[vlan].tag = tag;
+	return state->regs->update_state(state);
+}
+
+static int ip17xx_set_port_speed(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int nr = val->port_vlan;
+	int ctrl;
+	int autoneg;
+	int speed;
+	if (val->value.i == 100) {
+		speed = 1;
+		autoneg = 0;
+	} else if (val->value.i == 10) {
+		speed = 0;
+		autoneg = 0;
+	} else {
+		autoneg = 1;
+		speed = 1;
+	}
+
+	/* Can't set speed for cpu port */
+	if (nr == state->regs->CPU_PORT)
+		return -EINVAL;
+
+	if (nr >= dev->ports || nr < 0)
+		return -EINVAL;
+
+	ctrl = ip_phy_read(state, nr, 0);
+	if (ctrl < 0)
+		return -EIO;
+
+	ctrl &= (~(1<<12));
+	ctrl &= (~(1<<13));
+	ctrl |= (autoneg<<12);
+	ctrl |= (speed<<13);
+
+	return ip_phy_write(state, nr, 0, ctrl);
+}
+
+static int ip17xx_get_port_speed(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int nr = val->port_vlan;
+	int speed, status;
+
+	if (nr == state->regs->CPU_PORT) {
+		val->value.i = 100;
+		return 0;
+	}
+
+	if (nr >= dev->ports || nr < 0)
+		return -EINVAL;
+
+	status = ip_phy_read(state, nr, 1);
+	speed = ip_phy_read(state, nr, 18);
+	if (status < 0 || speed < 0)
+		return -EIO;
+
+	if (status & 4)
+		val->value.i = ((speed & (1<<11)) ? 100 : 10);
+	else
+		val->value.i = 0;
+
+	return 0;
+}
+
+static int ip17xx_get_port_status(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+	int ctrl, speed, status;
+	int nr = val->port_vlan;
+	int len;
+	char *buf = state->buf; // fixed-length at 80.
+
+	if (nr == state->regs->CPU_PORT) {
+		sprintf(buf, "up, 100 Mbps, cpu port");
+		val->value.s = buf;
+		return 0;
+	}
+
+	if (nr >= dev->ports || nr < 0)
+		return -EINVAL;
+
+	ctrl = ip_phy_read(state, nr, 0);
+	status = ip_phy_read(state, nr, 1);
+	speed = ip_phy_read(state, nr, 18);
+	if (ctrl < 0 || status < 0 || speed < 0)
+		return -EIO;
+
+	if (status & 4)
+		len = sprintf(buf, "up, %d Mbps, %s duplex",
+			((speed & (1<<11)) ? 100 : 10),
+			((speed & (1<<10)) ? "full" : "half"));
+	else
+		len = sprintf(buf, "down");
+
+	if (ctrl & (1<<12)) {
+		len += sprintf(buf+len, ", auto-negotiate");
+		if (!(status & (1<<5)))
+			len += sprintf(buf+len, " (in progress)");
+	} else {
+		len += sprintf(buf+len, ", fixed speed (%d)",
+			((ctrl & (1<<13)) ? 100 : 10));
+	}
+
+	buf[len] = '\0';
+	val->value.s = buf;
+	return 0;
+}
+
+static int ip17xx_get_pvid(struct switch_dev *dev, int port, int *val)
+{
+	struct ip17xx_state *state = get_state(dev);
+
+	*val = state->ports[port].pvid;
+	return 0;
+}
+
+static int ip17xx_set_pvid(struct switch_dev *dev, int port, int val)
+{
+	struct ip17xx_state *state = get_state(dev);
+
+	if (val < 0 || val >= MAX_VLANS)
+		return -EINVAL;
+
+	state->ports[port].pvid = val;
+	return state->regs->update_state(state);
+}
+
+
+enum Ports {
+	IP17XX_PORT_STATUS,
+	IP17XX_PORT_LINK,
+	IP17XX_PORT_TAGGED,
+	IP17XX_PORT_PVID,
+};
+
+enum Globals {
+	IP17XX_ENABLE_VLAN,
+	IP17XX_GET_NAME,
+	IP17XX_REGISTER_PHY,
+	IP17XX_REGISTER_MII,
+	IP17XX_REGISTER_VALUE,
+	IP17XX_REGISTER_ERRNO,
+};
+
+enum Vlans {
+	IP17XX_VLAN_TAG,
+};
+
+static const struct switch_attr ip17xx_global[] = {
+	[IP17XX_ENABLE_VLAN] = {
+		.id = IP17XX_ENABLE_VLAN,
+		.type = SWITCH_TYPE_INT,
+		.name  = "enable_vlan",
+		.description = "Flag to enable or disable VLANs and tagging",
+		.get  = ip17xx_get_enable_vlan,
+		.set = ip17xx_set_enable_vlan,
+	},
+	[IP17XX_GET_NAME] = {
+		.id = IP17XX_GET_NAME,
+		.type = SWITCH_TYPE_STRING,
+		.description = "Returns the type of IC+ chip.",
+		.name  = "name",
+		.get  = ip17xx_read_name,
+		.set = NULL,
+	},
+	/* jal: added for low level debugging etc. */
+	[IP17XX_REGISTER_PHY] = {
+		.id = IP17XX_REGISTER_PHY,
+		.type = SWITCH_TYPE_INT,
+		.description = "Direct register access: set PHY (0-4, or 29,30,31)",
+		.name  = "phy",
+		.get  = ip17xx_get_phy,
+		.set = ip17xx_set_phy,
+	},
+	[IP17XX_REGISTER_MII] = {
+		.id = IP17XX_REGISTER_MII,
+		.type = SWITCH_TYPE_INT,
+		.description = "Direct register access: set MII register number (0-31)",
+		.name  = "reg",
+		.get  = ip17xx_get_reg,
+		.set = ip17xx_set_reg,
+	},
+	[IP17XX_REGISTER_VALUE] = {
+		.id = IP17XX_REGISTER_VALUE,
+		.type = SWITCH_TYPE_INT,
+		.description = "Direct register access: read/write to register (0-65535)",
+		.name  = "val",
+		.get  = ip17xx_get_val,
+		.set = ip17xx_set_val,
+	},
+};
+
+static const struct switch_attr ip17xx_vlan[] = {
+	[IP17XX_VLAN_TAG] = {
+		.id = IP17XX_VLAN_TAG,
+		.type = SWITCH_TYPE_INT,
+		.description = "VLAN ID (0-4095) [IP175D only]",
+		.name = "vid",
+		.get = ip17xx_get_tag,
+		.set = ip17xx_set_tag,
+	}
+};
+
+static const struct switch_attr ip17xx_port[] = {
+	[IP17XX_PORT_STATUS] = {
+		.id = IP17XX_PORT_STATUS,
+		.type = SWITCH_TYPE_STRING,
+		.description = "Returns Detailed port status",
+		.name  = "status",
+		.get  = ip17xx_get_port_status,
+		.set = NULL,
+	},
+	[IP17XX_PORT_LINK] = {
+		.id = IP17XX_PORT_LINK,
+		.type = SWITCH_TYPE_INT,
+		.description = "Link speed. Can write 0 for auto-negotiate, or 10 or 100",
+		.name  = "link",
+		.get  = ip17xx_get_port_speed,
+		.set = ip17xx_set_port_speed,
+	},
+	[IP17XX_PORT_TAGGED] = {
+		.id = IP17XX_PORT_LINK,
+		.type = SWITCH_TYPE_INT,
+		.description = "0 = untag, 1 = add tags, 2 = do not alter (This value is reset if vlans are altered)",
+		.name  = "tagged",
+		.get  = ip17xx_get_tagged,
+		.set = ip17xx_set_tagged,
+	},
+};
+
+static const struct switch_dev_ops ip17xx_ops = {
+	.attr_global = {
+		.attr = ip17xx_global,
+		.n_attr = ARRAY_SIZE(ip17xx_global),
+	},
+	.attr_port = {
+		.attr = ip17xx_port,
+		.n_attr = ARRAY_SIZE(ip17xx_port),
+	},
+	.attr_vlan = {
+		.attr = ip17xx_vlan,
+		.n_attr = ARRAY_SIZE(ip17xx_vlan),
+	},
+
+	.get_port_pvid = ip17xx_get_pvid,
+	.set_port_pvid = ip17xx_set_pvid,
+	.get_vlan_ports = ip17xx_get_ports,
+	.set_vlan_ports = ip17xx_set_ports,
+	.apply_config = ip17xx_apply,
+	.reset_switch = ip17xx_reset,
+};
+
+static int ip17xx_probe(struct phy_device *pdev)
+{
+	struct ip17xx_state *state;
+	struct switch_dev *dev;
+	int err;
+
+	/* We only attach to PHY 0, but use all available PHYs */
+	if (pdev->mdio.addr != 0)
+		return -ENODEV;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	dev = &state->dev;
+
+	pdev->priv = state;
+	state->mii_bus = pdev->mdio.bus;
+
+	err = get_model(state);
+	if (err < 0)
+		goto error;
+
+	dev->vlans = MAX_VLANS;
+	dev->cpu_port = state->regs->CPU_PORT;
+	dev->ports = state->regs->NUM_PORTS;
+	dev->name = state->regs->NAME;
+	dev->ops = &ip17xx_ops;
+
+	pr_info("IP17xx: Found %s at %s\n", dev->name, dev_name(&pdev->mdio.dev));
+	return 0;
+
+error:
+	kfree(state);
+	return err;
+}
+
+static int ip17xx_config_init(struct phy_device *pdev)
+{
+	struct ip17xx_state *state = pdev->priv;
+	struct net_device *dev = pdev->attached_dev;
+	int err;
+
+	err = register_switch(&state->dev, dev);
+	if (err < 0)
+		return err;
+
+	state->registered = true;
+	ip17xx_reset(&state->dev);
+	return 0;
+}
+
+static void ip17xx_remove(struct phy_device *pdev)
+{
+	struct ip17xx_state *state = pdev->priv;
+
+	if (state->registered)
+		unregister_switch(&state->dev);
+	kfree(state);
+}
+
+static int ip17xx_config_aneg(struct phy_device *pdev)
+{
+	return 0;
+}
+
+static int ip17xx_aneg_done(struct phy_device *pdev)
+{
+	return 1;	/* Return any positive value */
+}
+
+static int ip17xx_read_status(struct phy_device *pdev)
+{
+	pdev->speed = SPEED_100;
+	pdev->duplex = DUPLEX_FULL;
+	pdev->pause = pdev->asym_pause = 0;
+	pdev->link = 1;
+
+	return 0;
+}
+
+static struct phy_driver ip17xx_driver[] = {
+	{
+		.name		= "IC+ IP17xx",
+		.phy_id		= 0x02430c00,
+		.phy_id_mask	= 0x0ffffc00,
+		.features	= PHY_BASIC_FEATURES,
+		.probe		= ip17xx_probe,
+		.remove		= ip17xx_remove,
+		.config_init	= ip17xx_config_init,
+		.config_aneg	= ip17xx_config_aneg,
+		.aneg_done	= ip17xx_aneg_done,
+		.read_status	= ip17xx_read_status,
+	}
+};
+
+module_phy_driver(ip17xx_driver);
+
+MODULE_AUTHOR("Patrick Horn <patrick.horn@gmail.com>");
+MODULE_AUTHOR("Felix Fietkau <nbd@nbd.name>");
+MODULE_AUTHOR("Martin Mares <mj@ucw.cz>");
+MODULE_LICENSE("GPL");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/mvswitch.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/mvswitch.c
new file mode 100644
index 0000000..bd3b9e1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/mvswitch.c
@@ -0,0 +1,446 @@
+/*
+ * Marvell 88E6060 switch driver
+ * Copyright (c) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/if_vlan.h>
+#include <linux/version.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include "mvswitch.h"
+
+/* Undefine this to use trailer mode instead.
+ * I don't know if header mode works with all chips */
+#define HEADER_MODE	1
+
+MODULE_DESCRIPTION("Marvell 88E6060 Switch driver");
+MODULE_AUTHOR("Felix Fietkau");
+MODULE_LICENSE("GPL");
+
+#define MVSWITCH_MAGIC 0x88E6060
+
+struct mvswitch_priv {
+	netdev_features_t orig_features;
+	u8 vlans[16];
+};
+
+#define to_mvsw(_phy) ((struct mvswitch_priv *) (_phy)->priv)
+
+static inline u16
+r16(struct phy_device *phydev, int addr, int reg)
+{
+	struct mii_bus *bus = phydev->mdio.bus;
+
+	return bus->read(bus, addr, reg);
+}
+
+static inline void
+w16(struct phy_device *phydev, int addr, int reg, u16 val)
+{
+	struct mii_bus *bus = phydev->mdio.bus;
+
+	bus->write(bus, addr, reg, val);
+}
+
+
+static struct sk_buff *
+mvswitch_mangle_tx(struct net_device *dev, struct sk_buff *skb)
+{
+	struct mvswitch_priv *priv;
+	char *buf = NULL;
+	u16 vid;
+
+	priv = dev->phy_ptr;
+	if (unlikely(!priv))
+		goto error;
+
+	if (unlikely(skb->len < 16))
+		goto error;
+
+#ifdef HEADER_MODE
+	if (__vlan_hwaccel_get_tag(skb, &vid))
+		goto error;
+
+	if (skb_cloned(skb) || (skb->len <= 62) || (skb_headroom(skb) < MV_HEADER_SIZE)) {
+		if (pskb_expand_head(skb, MV_HEADER_SIZE, (skb->len < 62 ? 62 - skb->len : 0), GFP_ATOMIC))
+			goto error_expand;
+		if (skb->len < 62)
+			skb->len = 62;
+	}
+	buf = skb_push(skb, MV_HEADER_SIZE);
+#else
+	if (__vlan_get_tag(skb, &vid))
+		goto error;
+
+	if (unlikely((vid > 15 || !priv->vlans[vid])))
+		goto error;
+
+	if (skb->len <= 64) {
+		if (pskb_expand_head(skb, 0, 64 + MV_TRAILER_SIZE - skb->len, GFP_ATOMIC))
+			goto error_expand;
+
+		buf = skb->data + 64;
+		skb->len = 64 + MV_TRAILER_SIZE;
+	} else {
+		if (skb_cloned(skb) || unlikely(skb_tailroom(skb) < 4)) {
+			if (pskb_expand_head(skb, 0, 4, GFP_ATOMIC))
+				goto error_expand;
+		}
+		buf = skb_put(skb, 4);
+	}
+
+	/* move the ethernet header 4 bytes forward, overwriting the vlan tag */
+	memmove(skb->data + 4, skb->data, 12);
+	skb->data += 4;
+	skb->len -= 4;
+	skb->mac_header += 4;
+#endif
+
+	if (!buf)
+		goto error;
+
+
+#ifdef HEADER_MODE
+	/* prepend the tag */
+	*((__be16 *) buf) = cpu_to_be16(
+		((vid << MV_HEADER_VLAN_S) & MV_HEADER_VLAN_M) |
+		((priv->vlans[vid] << MV_HEADER_PORTS_S) & MV_HEADER_PORTS_M)
+	);
+#else
+	/* append the tag */
+	*((__be32 *) buf) = cpu_to_be32((
+		(MV_TRAILER_OVERRIDE << MV_TRAILER_FLAGS_S) |
+		((priv->vlans[vid] & MV_TRAILER_PORTS_M) << MV_TRAILER_PORTS_S)
+	));
+#endif
+
+	return skb;
+
+error_expand:
+	if (net_ratelimit())
+		printk("%s: failed to expand/update skb for the switch\n", dev->name);
+
+error:
+	/* any errors? drop the packet! */
+	dev_kfree_skb_any(skb);
+	return NULL;
+}
+
+static void
+mvswitch_mangle_rx(struct net_device *dev, struct sk_buff *skb)
+{
+	struct mvswitch_priv *priv;
+	unsigned char *buf;
+	int vlan = -1;
+	int i;
+
+	priv = dev->phy_ptr;
+	if (WARN_ON_ONCE(!priv))
+		return;
+
+#ifdef HEADER_MODE
+	buf = skb->data;
+	skb_pull(skb, MV_HEADER_SIZE);
+#else
+	buf = skb->data + skb->len - MV_TRAILER_SIZE;
+	if (buf[0] != 0x80)
+		return;
+#endif
+
+	/* look for the vlan matching the incoming port */
+	for (i = 0; i < ARRAY_SIZE(priv->vlans); i++) {
+		if ((1 << buf[1]) & priv->vlans[i])
+			vlan = i;
+	}
+
+	if (vlan == -1)
+		return;
+
+	__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan);
+}
+
+
+static int
+mvswitch_wait_mask(struct phy_device *pdev, int addr, int reg, u16 mask, u16 val)
+{
+	int i = 100;
+	u16 r;
+
+	do {
+		r = r16(pdev, addr, reg) & mask;
+		if (r == val)
+			return 0;
+	} while(--i > 0);
+	return -ETIMEDOUT;
+}
+
+static int
+mvswitch_config_init(struct phy_device *pdev)
+{
+	struct mvswitch_priv *priv = to_mvsw(pdev);
+	struct net_device *dev = pdev->attached_dev;
+	u8 vlmap = 0;
+	int i;
+
+	if (!dev)
+		return -EINVAL;
+
+	printk("%s: Marvell 88E6060 PHY driver attached.\n", dev->name);
+	linkmode_zero(pdev->supported);
+	linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, pdev->supported);
+	linkmode_copy(pdev->advertising, pdev->supported);
+	dev->phy_ptr = priv;
+	pdev->irq = PHY_POLL;
+#ifdef HEADER_MODE
+	dev->flags |= IFF_PROMISC;
+#endif
+
+	/* initialize default vlans */
+	for (i = 0; i < MV_PORTS; i++)
+		priv->vlans[(i == MV_WANPORT ? 2 : 1)] |= (1 << i);
+
+	/* before entering reset, disable all ports */
+	for (i = 0; i < MV_PORTS; i++)
+		w16(pdev, MV_PORTREG(CONTROL, i), 0x00);
+
+	msleep(2); /* wait for the status change to settle in */
+
+	/* put the ATU in reset */
+	w16(pdev, MV_SWITCHREG(ATU_CTRL), MV_ATUCTL_RESET);
+
+	i = mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_CTRL), MV_ATUCTL_RESET, 0);
+	if (i < 0) {
+		printk("%s: Timeout waiting for the switch to reset.\n", dev->name);
+		return i;
+	}
+
+	/* set the ATU flags */
+	w16(pdev, MV_SWITCHREG(ATU_CTRL),
+		MV_ATUCTL_NO_LEARN |
+		MV_ATUCTL_ATU_1K |
+		MV_ATUCTL_AGETIME(MV_ATUCTL_AGETIME_MIN) /* minimum without disabling ageing */
+	);
+
+	/* initialize the cpu port */
+	w16(pdev, MV_PORTREG(CONTROL, MV_CPUPORT),
+#ifdef HEADER_MODE
+		MV_PORTCTRL_HEADER |
+#else
+		MV_PORTCTRL_RXTR |
+		MV_PORTCTRL_TXTR |
+#endif
+		MV_PORTCTRL_ENABLED
+	);
+	/* wait for the phy change to settle in */
+	msleep(2);
+	for (i = 0; i < MV_PORTS; i++) {
+		u8 pvid = 0;
+		int j;
+
+		vlmap = 0;
+
+		/* look for the matching vlan */
+		for (j = 0; j < ARRAY_SIZE(priv->vlans); j++) {
+			if (priv->vlans[j] & (1 << i)) {
+				vlmap = priv->vlans[j];
+				pvid = j;
+			}
+		}
+		/* leave port unconfigured if it's not part of a vlan */
+		if (!vlmap)
+			continue;
+
+		/* add the cpu port to the allowed destinations list */
+		vlmap |= (1 << MV_CPUPORT);
+
+		/* take port out of its own vlan destination map */
+		vlmap &= ~(1 << i);
+
+		/* apply vlan settings */
+		w16(pdev, MV_PORTREG(VLANMAP, i),
+			MV_PORTVLAN_PORTS(vlmap) |
+			MV_PORTVLAN_ID(i)
+		);
+
+		/* re-enable port */
+		w16(pdev, MV_PORTREG(CONTROL, i),
+			MV_PORTCTRL_ENABLED
+		);
+	}
+
+	w16(pdev, MV_PORTREG(VLANMAP, MV_CPUPORT),
+		MV_PORTVLAN_ID(MV_CPUPORT)
+	);
+
+	/* set the port association vector */
+	for (i = 0; i <= MV_PORTS; i++) {
+		w16(pdev, MV_PORTREG(ASSOC, i),
+			MV_PORTASSOC_PORTS(1 << i)
+		);
+	}
+
+	/* init switch control */
+	w16(pdev, MV_SWITCHREG(CTRL),
+		MV_SWITCHCTL_MSIZE |
+		MV_SWITCHCTL_DROP
+	);
+
+	dev->eth_mangle_rx = mvswitch_mangle_rx;
+	dev->eth_mangle_tx = mvswitch_mangle_tx;
+	priv->orig_features = dev->features;
+
+#ifdef HEADER_MODE
+	dev->priv_flags |= IFF_NO_IP_ALIGN;
+	dev->features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX;
+#else
+	dev->features |= NETIF_F_HW_VLAN_CTAG_RX;
+#endif
+
+	return 0;
+}
+
+static int
+mvswitch_read_status(struct phy_device *pdev)
+{
+	pdev->speed = SPEED_100;
+	pdev->duplex = DUPLEX_FULL;
+	pdev->link = 1;
+
+	/* XXX ugly workaround: we can't force the switch
+	 * to gracefully handle hosts moving from one port to another,
+	 * so we have to regularly clear the ATU database */
+
+	/* wait for the ATU to become available */
+	mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_OP), MV_ATUOP_INPROGRESS, 0);
+
+	/* flush the ATU */
+	w16(pdev, MV_SWITCHREG(ATU_OP),
+		MV_ATUOP_INPROGRESS |
+		MV_ATUOP_FLUSH_ALL
+	);
+
+	/* wait for operation to complete */
+	mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_OP), MV_ATUOP_INPROGRESS, 0);
+
+	return 0;
+}
+
+static int
+mvswitch_aneg_done(struct phy_device *phydev)
+{
+	return 1;	/* Return any positive value */
+}
+
+static int
+mvswitch_config_aneg(struct phy_device *phydev)
+{
+	return 0;
+}
+
+static void
+mvswitch_detach(struct phy_device *pdev)
+{
+	struct mvswitch_priv *priv = to_mvsw(pdev);
+	struct net_device *dev = pdev->attached_dev;
+
+	if (!dev)
+		return;
+
+	dev->phy_ptr = NULL;
+	dev->eth_mangle_rx = NULL;
+	dev->eth_mangle_tx = NULL;
+	dev->features = priv->orig_features;
+	dev->priv_flags &= ~IFF_NO_IP_ALIGN;
+}
+
+static void
+mvswitch_remove(struct phy_device *pdev)
+{
+	struct mvswitch_priv *priv = to_mvsw(pdev);
+
+	kfree(priv);
+}
+
+static int
+mvswitch_probe(struct phy_device *pdev)
+{
+	struct mvswitch_priv *priv;
+
+	priv = kzalloc(sizeof(struct mvswitch_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+
+	pdev->priv = priv;
+
+	return 0;
+}
+
+static int
+mvswitch_fixup(struct phy_device *dev)
+{
+	struct mii_bus *bus = dev->mdio.bus;
+	u16 reg;
+
+	if (dev->mdio.addr != 0x10)
+		return 0;
+
+	reg = bus->read(bus, MV_PORTREG(IDENT, 0)) & MV_IDENT_MASK;
+	if (reg != MV_IDENT_VALUE)
+		return 0;
+
+	dev->phy_id = MVSWITCH_MAGIC;
+	return 0;
+}
+
+
+static struct phy_driver mvswitch_driver = {
+	.name		= "Marvell 88E6060",
+	.phy_id		= MVSWITCH_MAGIC,
+	.phy_id_mask	= 0xffffffff,
+	.features	= PHY_BASIC_FEATURES,
+	.probe		= &mvswitch_probe,
+	.remove		= &mvswitch_remove,
+	.detach		= &mvswitch_detach,
+	.config_init	= &mvswitch_config_init,
+	.config_aneg	= &mvswitch_config_aneg,
+	.aneg_done	= &mvswitch_aneg_done,
+	.read_status	= &mvswitch_read_status,
+};
+
+static int __init
+mvswitch_init(void)
+{
+	phy_register_fixup_for_id(PHY_ANY_ID, mvswitch_fixup);
+	return phy_driver_register(&mvswitch_driver, THIS_MODULE);
+}
+
+static void __exit
+mvswitch_exit(void)
+{
+	phy_driver_unregister(&mvswitch_driver);
+}
+
+module_init(mvswitch_init);
+module_exit(mvswitch_exit);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/mvswitch.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/mvswitch.h
new file mode 100644
index 0000000..ab2a1a1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/mvswitch.h
@@ -0,0 +1,145 @@
+/*
+ * Marvell 88E6060 switch driver
+ * Copyright (c) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation
+ */
+#ifndef __MVSWITCH_H
+#define __MVSWITCH_H
+
+#define MV_HEADER_SIZE	2
+#define MV_HEADER_PORTS_M	0x001f
+#define MV_HEADER_PORTS_S	0
+#define MV_HEADER_VLAN_M	0xf000
+#define MV_HEADER_VLAN_S	12
+
+#define MV_TRAILER_SIZE	4
+#define MV_TRAILER_PORTS_M	0x1f
+#define MV_TRAILER_PORTS_S	16
+#define MV_TRAILER_FLAGS_S	24
+#define MV_TRAILER_OVERRIDE	0x80
+
+
+#define MV_PORTS	5
+#define MV_WANPORT	4
+#define MV_CPUPORT	5
+
+#define MV_BASE		0x10
+
+#define MV_PHYPORT_BASE		(MV_BASE + 0x0)
+#define MV_PHYPORT(_n)		(MV_PHYPORT_BASE + (_n))
+#define MV_SWITCHPORT_BASE	(MV_BASE + 0x8)
+#define MV_SWITCHPORT(_n)	(MV_SWITCHPORT_BASE + (_n))
+#define MV_SWITCHREGS		(MV_BASE + 0xf)
+
+enum {
+	MV_PHY_CONTROL      = 0x00,
+	MV_PHY_STATUS       = 0x01,
+	MV_PHY_IDENT0       = 0x02,
+	MV_PHY_IDENT1       = 0x03,
+	MV_PHY_ANEG         = 0x04,
+	MV_PHY_LINK_ABILITY = 0x05,
+	MV_PHY_ANEG_EXPAND  = 0x06,
+	MV_PHY_XMIT_NEXTP   = 0x07,
+	MV_PHY_LINK_NEXTP   = 0x08,
+	MV_PHY_CONTROL1     = 0x10,
+	MV_PHY_STATUS1      = 0x11,
+	MV_PHY_INTR_EN      = 0x12,
+	MV_PHY_INTR_STATUS  = 0x13,
+	MV_PHY_INTR_PORT    = 0x14,
+	MV_PHY_RECV_COUNTER = 0x16,
+	MV_PHY_LED_PARALLEL = 0x16,
+	MV_PHY_LED_STREAM   = 0x17,
+	MV_PHY_LED_CTRL     = 0x18,
+	MV_PHY_LED_OVERRIDE = 0x19,
+	MV_PHY_VCT_CTRL     = 0x1a,
+	MV_PHY_VCT_STATUS   = 0x1b,
+	MV_PHY_CONTROL2     = 0x1e
+};
+#define MV_PHYREG(_type, _port) MV_PHYPORT(_port), MV_PHY_##_type
+
+enum {
+	MV_PORT_STATUS      = 0x00,
+	MV_PORT_IDENT       = 0x03,
+	MV_PORT_CONTROL     = 0x04,
+	MV_PORT_VLANMAP     = 0x06,
+	MV_PORT_ASSOC       = 0x0b,
+	MV_PORT_RXCOUNT     = 0x10,
+	MV_PORT_TXCOUNT     = 0x11,
+};
+#define MV_PORTREG(_type, _port) MV_SWITCHPORT(_port), MV_PORT_##_type
+
+enum {
+	MV_PORTCTRL_BLOCK   =  (1 << 0),
+	MV_PORTCTRL_LEARN   =  (2 << 0),
+	MV_PORTCTRL_ENABLED =  (3 << 0),
+	MV_PORTCTRL_VLANTUN =  (1 << 7),	/* Enforce VLANs on packets */
+	MV_PORTCTRL_RXTR    =  (1 << 8),	/* Enable Marvell packet trailer for ingress */
+	MV_PORTCTRL_HEADER	= (1 << 11),	/* Enable Marvell packet header mode for port */
+	MV_PORTCTRL_TXTR    = (1 << 14),	/* Enable Marvell packet trailer for egress */
+	MV_PORTCTRL_FORCEFL = (1 << 15),	/* force flow control */
+};
+
+#define MV_PORTVLAN_ID(_n) (((_n) & 0xf) << 12)
+#define MV_PORTVLAN_PORTS(_n) ((_n) & 0x3f)
+
+#define MV_PORTASSOC_PORTS(_n) ((_n) & 0x1f)
+#define MV_PORTASSOC_MONITOR	(1 << 15)
+
+enum {
+	MV_SWITCH_MAC0      = 0x01,
+	MV_SWITCH_MAC1      = 0x02,
+	MV_SWITCH_MAC2      = 0x03,
+	MV_SWITCH_CTRL      = 0x04,
+	MV_SWITCH_ATU_CTRL  = 0x0a,
+	MV_SWITCH_ATU_OP    = 0x0b,
+	MV_SWITCH_ATU_DATA  = 0x0c,
+	MV_SWITCH_ATU_MAC0  = 0x0d,
+	MV_SWITCH_ATU_MAC1  = 0x0e,
+	MV_SWITCH_ATU_MAC2  = 0x0f,
+};
+#define MV_SWITCHREG(_type) MV_SWITCHREGS, MV_SWITCH_##_type
+
+enum {
+	MV_SWITCHCTL_EEIE   =  (1 << 0),	/* EEPROM interrupt enable */
+	MV_SWITCHCTL_PHYIE  =  (1 << 1),	/* PHY interrupt enable */
+	MV_SWITCHCTL_ATUDONE=  (1 << 2),	/* ATU done interrupt enable */
+	MV_SWITCHCTL_ATUIE  =  (1 << 3),	/* ATU interrupt enable */
+	MV_SWITCHCTL_CTRMODE=  (1 << 8),	/* statistics for rx and tx errors */
+	MV_SWITCHCTL_RELOAD =  (1 << 9),	/* reload registers from eeprom */
+	MV_SWITCHCTL_MSIZE  = (1 << 10),	/* increase maximum frame size */
+	MV_SWITCHCTL_DROP   = (1 << 13),	/* discard frames with excessive collisions */
+};
+
+enum {
+#define MV_ATUCTL_AGETIME_MIN	16
+#define MV_ATUCTL_AGETIME_MAX	4080
+#define MV_ATUCTL_AGETIME(_n)	((((_n) / 16) & 0xff) << 4)
+	MV_ATUCTL_ATU_256   = (0 << 12),
+	MV_ATUCTL_ATU_512   = (1 << 12),
+	MV_ATUCTL_ATU_1K	= (2 << 12),
+	MV_ATUCTL_ATUMASK   = (3 << 12),
+	MV_ATUCTL_NO_LEARN  = (1 << 14),
+	MV_ATUCTL_RESET     = (1 << 15),
+};
+
+enum {
+#define MV_ATUOP_DBNUM(_n)	((_n) & 0x0f)
+
+	MV_ATUOP_NOOP       = (0 << 12),
+	MV_ATUOP_FLUSH_ALL  = (1 << 12),
+	MV_ATUOP_FLUSH_U    = (2 << 12),
+	MV_ATUOP_LOAD_DB    = (3 << 12),
+	MV_ATUOP_GET_NEXT   = (4 << 12),
+	MV_ATUOP_FLUSH_DB   = (5 << 12),
+	MV_ATUOP_FLUSH_DB_UU= (6 << 12),
+
+	MV_ATUOP_INPROGRESS = (1 << 15),
+};
+
+#define MV_IDENT_MASK		0xfff0
+#define MV_IDENT_VALUE		0x0600
+
+#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/psb6970.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/psb6970.c
new file mode 100644
index 0000000..6cee757
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/psb6970.c
@@ -0,0 +1,444 @@
+/*
+ * Lantiq PSB6970 (Tantos) Switch driver
+ *
+ * Copyright (c) 2009,2010 Team Embedded.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation.
+ *
+ * The switch programming done in this driver follows the 
+ * "Ethernet Traffic Separation using VLAN" Application Note as
+ * published by Lantiq.
+ */
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/switch.h>
+#include <linux/phy.h>
+#include <linux/version.h>
+
+#define PSB6970_MAX_VLANS		16
+#define PSB6970_NUM_PORTS		7
+#define PSB6970_DEFAULT_PORT_CPU	6
+#define PSB6970_IS_CPU_PORT(x)		((x) > 4)
+
+#define PHYADDR(_reg)		((_reg >> 5) & 0xff), (_reg & 0x1f)
+
+/* --- Identification --- */
+#define PSB6970_CI0		0x0100
+#define PSB6970_CI0_MASK	0x000f
+#define PSB6970_CI1		0x0101
+#define PSB6970_CI1_VAL		0x2599
+#define PSB6970_CI1_MASK	0xffff
+
+/* --- VLAN filter table --- */
+#define PSB6970_VFxL(i)		((i)*2+0x10)	/* VLAN Filter Low */
+#define PSB6970_VFxL_VV		(1 << 15)	/* VLAN_Valid */
+
+#define PSB6970_VFxH(i)		((i)*2+0x11)	/* VLAN Filter High */
+#define PSB6970_VFxH_TM_SHIFT	7		/* Tagged Member */
+
+/* --- Port registers --- */
+#define PSB6970_EC(p)		((p)*0x20+2)	/* Extended Control */
+#define PSB6970_EC_IFNTE	(1 << 1)	/* Input Force No Tag Enable */
+
+#define PSB6970_PBVM(p)		((p)*0x20+3)	/* Port Base VLAN Map */
+#define PSB6970_PBVM_VMCE	(1 << 8)
+#define PSB6970_PBVM_AOVTP	(1 << 9)
+#define PSB6970_PBVM_VSD	(1 << 10)
+#define PSB6970_PBVM_VC		(1 << 11)	/* VID Check with VID table */
+#define PSB6970_PBVM_TBVE	(1 << 13)	/* Tag-Based VLAN enable */
+
+#define PSB6970_DVID(p)		((p)*0x20+4)	/* Default VLAN ID & Priority */
+
+struct psb6970_priv {
+	struct switch_dev dev;
+	struct phy_device *phy;
+	u16 (*read) (struct phy_device* phydev, int reg);
+	void (*write) (struct phy_device* phydev, int reg, u16 val);
+	struct mutex reg_mutex;
+
+	/* all fields below are cleared on reset */
+	bool vlan;
+	u16 vlan_id[PSB6970_MAX_VLANS];
+	u8 vlan_table[PSB6970_MAX_VLANS];
+	u8 vlan_tagged;
+	u16 pvid[PSB6970_NUM_PORTS];
+};
+
+#define to_psb6970(_dev) container_of(_dev, struct psb6970_priv, dev)
+
+static u16 psb6970_mii_read(struct phy_device *phydev, int reg)
+{
+	struct mii_bus *bus = phydev->mdio.bus;
+
+	return bus->read(bus, PHYADDR(reg));
+}
+
+static void psb6970_mii_write(struct phy_device *phydev, int reg, u16 val)
+{
+	struct mii_bus *bus = phydev->mdio.bus;
+
+	bus->write(bus, PHYADDR(reg), val);
+}
+
+static int
+psb6970_set_vlan(struct switch_dev *dev, const struct switch_attr *attr,
+		 struct switch_val *val)
+{
+	struct psb6970_priv *priv = to_psb6970(dev);
+	priv->vlan = !!val->value.i;
+	return 0;
+}
+
+static int
+psb6970_get_vlan(struct switch_dev *dev, const struct switch_attr *attr,
+		 struct switch_val *val)
+{
+	struct psb6970_priv *priv = to_psb6970(dev);
+	val->value.i = priv->vlan;
+	return 0;
+}
+
+static int psb6970_set_pvid(struct switch_dev *dev, int port, int vlan)
+{
+	struct psb6970_priv *priv = to_psb6970(dev);
+
+	/* make sure no invalid PVIDs get set */
+	if (vlan >= dev->vlans)
+		return -EINVAL;
+
+	priv->pvid[port] = vlan;
+	return 0;
+}
+
+static int psb6970_get_pvid(struct switch_dev *dev, int port, int *vlan)
+{
+	struct psb6970_priv *priv = to_psb6970(dev);
+	*vlan = priv->pvid[port];
+	return 0;
+}
+
+static int
+psb6970_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
+		struct switch_val *val)
+{
+	struct psb6970_priv *priv = to_psb6970(dev);
+	priv->vlan_id[val->port_vlan] = val->value.i;
+	return 0;
+}
+
+static int
+psb6970_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
+		struct switch_val *val)
+{
+	struct psb6970_priv *priv = to_psb6970(dev);
+	val->value.i = priv->vlan_id[val->port_vlan];
+	return 0;
+}
+
+static struct switch_attr psb6970_globals[] = {
+	{
+	 .type = SWITCH_TYPE_INT,
+	 .name = "enable_vlan",
+	 .description = "Enable VLAN mode",
+	 .set = psb6970_set_vlan,
+	 .get = psb6970_get_vlan,
+	 .max = 1},
+};
+
+static struct switch_attr psb6970_port[] = {
+};
+
+static struct switch_attr psb6970_vlan[] = {
+	{
+	 .type = SWITCH_TYPE_INT,
+	 .name = "vid",
+	 .description = "VLAN ID (0-4094)",
+	 .set = psb6970_set_vid,
+	 .get = psb6970_get_vid,
+	 .max = 4094,
+	 },
+};
+
+static int psb6970_get_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct psb6970_priv *priv = to_psb6970(dev);
+	u8 ports = priv->vlan_table[val->port_vlan];
+	int i;
+
+	val->len = 0;
+	for (i = 0; i < PSB6970_NUM_PORTS; i++) {
+		struct switch_port *p;
+
+		if (!(ports & (1 << i)))
+			continue;
+
+		p = &val->value.ports[val->len++];
+		p->id = i;
+		if (priv->vlan_tagged & (1 << i))
+			p->flags = (1 << SWITCH_PORT_FLAG_TAGGED);
+		else
+			p->flags = 0;
+	}
+	return 0;
+}
+
+static int psb6970_set_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct psb6970_priv *priv = to_psb6970(dev);
+	u8 *vt = &priv->vlan_table[val->port_vlan];
+	int i, j;
+
+	*vt = 0;
+	for (i = 0; i < val->len; i++) {
+		struct switch_port *p = &val->value.ports[i];
+
+		if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED))
+			priv->vlan_tagged |= (1 << p->id);
+		else {
+			priv->vlan_tagged &= ~(1 << p->id);
+			priv->pvid[p->id] = val->port_vlan;
+
+			/* make sure that an untagged port does not
+			 * appear in other vlans */
+			for (j = 0; j < PSB6970_MAX_VLANS; j++) {
+				if (j == val->port_vlan)
+					continue;
+				priv->vlan_table[j] &= ~(1 << p->id);
+			}
+		}
+
+		*vt |= 1 << p->id;
+	}
+	return 0;
+}
+
+static int psb6970_hw_apply(struct switch_dev *dev)
+{
+	struct psb6970_priv *priv = to_psb6970(dev);
+	int i, j;
+
+	mutex_lock(&priv->reg_mutex);
+
+	if (priv->vlan) {
+		/* into the vlan translation unit */
+		for (j = 0; j < PSB6970_MAX_VLANS; j++) {
+			u8 vp = priv->vlan_table[j];
+
+			if (vp) {
+				priv->write(priv->phy, PSB6970_VFxL(j),
+					    PSB6970_VFxL_VV | priv->vlan_id[j]);
+				priv->write(priv->phy, PSB6970_VFxH(j),
+					    ((vp & priv->
+					      vlan_tagged) <<
+					     PSB6970_VFxH_TM_SHIFT) | vp);
+			} else	/* clear VLAN Valid flag for unused vlans */
+				priv->write(priv->phy, PSB6970_VFxL(j), 0);
+
+		}
+	}
+
+	/* update the port destination mask registers and tag settings */
+	for (i = 0; i < PSB6970_NUM_PORTS; i++) {
+		int dvid = 1, pbvm = 0x7f | PSB6970_PBVM_VSD, ec = 0;
+
+		if (priv->vlan) {
+			ec = PSB6970_EC_IFNTE;
+			dvid = priv->vlan_id[priv->pvid[i]];
+			pbvm |= PSB6970_PBVM_TBVE | PSB6970_PBVM_VMCE;
+
+			if ((i << 1) & priv->vlan_tagged)
+				pbvm |= PSB6970_PBVM_AOVTP | PSB6970_PBVM_VC;
+		}
+
+		priv->write(priv->phy, PSB6970_PBVM(i), pbvm);
+
+		if (!PSB6970_IS_CPU_PORT(i)) {
+			priv->write(priv->phy, PSB6970_EC(i), ec);
+			priv->write(priv->phy, PSB6970_DVID(i), dvid);
+		}
+	}
+
+	mutex_unlock(&priv->reg_mutex);
+	return 0;
+}
+
+static int psb6970_reset_switch(struct switch_dev *dev)
+{
+	struct psb6970_priv *priv = to_psb6970(dev);
+	int i;
+
+	mutex_lock(&priv->reg_mutex);
+
+	memset(&priv->vlan, 0, sizeof(struct psb6970_priv) -
+	       offsetof(struct psb6970_priv, vlan));
+
+	for (i = 0; i < PSB6970_MAX_VLANS; i++)
+		priv->vlan_id[i] = i;
+
+	mutex_unlock(&priv->reg_mutex);
+
+	return psb6970_hw_apply(dev);
+}
+
+static const struct switch_dev_ops psb6970_ops = {
+	.attr_global = {
+			.attr = psb6970_globals,
+			.n_attr = ARRAY_SIZE(psb6970_globals),
+			},
+	.attr_port = {
+		      .attr = psb6970_port,
+		      .n_attr = ARRAY_SIZE(psb6970_port),
+		      },
+	.attr_vlan = {
+		      .attr = psb6970_vlan,
+		      .n_attr = ARRAY_SIZE(psb6970_vlan),
+		      },
+	.get_port_pvid = psb6970_get_pvid,
+	.set_port_pvid = psb6970_set_pvid,
+	.get_vlan_ports = psb6970_get_ports,
+	.set_vlan_ports = psb6970_set_ports,
+	.apply_config = psb6970_hw_apply,
+	.reset_switch = psb6970_reset_switch,
+};
+
+static int psb6970_config_init(struct phy_device *pdev)
+{
+	struct psb6970_priv *priv;
+	struct net_device *dev = pdev->attached_dev;
+	struct switch_dev *swdev;
+	int ret;
+
+	priv = kzalloc(sizeof(struct psb6970_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+
+	priv->phy = pdev;
+
+	if (pdev->mdio.addr == 0)
+		printk(KERN_INFO "%s: psb6970 switch driver attached.\n",
+		       pdev->attached_dev->name);
+
+	if (pdev->mdio.addr != 0) {
+		kfree(priv);
+		return 0;
+	}
+
+	linkmode_zero(pdev->supported);
+	linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, pdev->supported);
+	linkmode_copy(pdev->advertising, pdev->supported);
+
+	mutex_init(&priv->reg_mutex);
+	priv->read = psb6970_mii_read;
+	priv->write = psb6970_mii_write;
+
+	pdev->priv = priv;
+
+	swdev = &priv->dev;
+	swdev->cpu_port = PSB6970_DEFAULT_PORT_CPU;
+	swdev->ops = &psb6970_ops;
+
+	swdev->name = "Lantiq PSB6970";
+	swdev->vlans = PSB6970_MAX_VLANS;
+	swdev->ports = PSB6970_NUM_PORTS;
+
+	if ((ret = register_switch(&priv->dev, pdev->attached_dev)) < 0) {
+		kfree(priv);
+		goto done;
+	}
+
+	ret = psb6970_reset_switch(&priv->dev);
+	if (ret) {
+		kfree(priv);
+		goto done;
+	}
+
+	dev->phy_ptr = priv;
+
+done:
+	return ret;
+}
+
+static int psb6970_read_status(struct phy_device *phydev)
+{
+	phydev->speed = SPEED_100;
+	phydev->duplex = DUPLEX_FULL;
+	phydev->link = 1;
+
+	phydev->state = PHY_RUNNING;
+	netif_carrier_on(phydev->attached_dev);
+	phydev->adjust_link(phydev->attached_dev);
+
+	return 0;
+}
+
+static int psb6970_config_aneg(struct phy_device *phydev)
+{
+	return 0;
+}
+
+static int psb6970_probe(struct phy_device *pdev)
+{
+	return 0;
+}
+
+static void psb6970_remove(struct phy_device *pdev)
+{
+	struct psb6970_priv *priv = pdev->priv;
+
+	if (!priv)
+		return;
+
+	if (pdev->mdio.addr == 0)
+		unregister_switch(&priv->dev);
+	kfree(priv);
+}
+
+static int psb6970_fixup(struct phy_device *dev)
+{
+	struct mii_bus *bus = dev->mdio.bus;
+	u16 reg;
+
+	/* look for the switch on the bus */
+	reg = bus->read(bus, PHYADDR(PSB6970_CI1)) & PSB6970_CI1_MASK;
+	if (reg != PSB6970_CI1_VAL)
+		return 0;
+
+	dev->phy_id = (reg << 16);
+	dev->phy_id |= bus->read(bus, PHYADDR(PSB6970_CI0)) & PSB6970_CI0_MASK;
+
+	return 0;
+}
+
+static struct phy_driver psb6970_driver = {
+	.name = "Lantiq PSB6970",
+	.phy_id = PSB6970_CI1_VAL << 16,
+	.phy_id_mask = 0xffff0000,
+	.features = PHY_BASIC_FEATURES,
+	.probe = psb6970_probe,
+	.remove = psb6970_remove,
+	.config_init = &psb6970_config_init,
+	.config_aneg = &psb6970_config_aneg,
+	.read_status = &psb6970_read_status,
+};
+
+int __init psb6970_init(void)
+{
+	phy_register_fixup_for_id(PHY_ANY_ID, psb6970_fixup);
+	return phy_driver_register(&psb6970_driver, THIS_MODULE);
+}
+
+module_init(psb6970_init);
+
+void __exit psb6970_exit(void)
+{
+	phy_driver_unregister(&psb6970_driver);
+}
+
+module_exit(psb6970_exit);
+
+MODULE_DESCRIPTION("Lantiq PSB6970 Switch");
+MODULE_AUTHOR("Ithamar R. Adema <ithamar.adema@team-embedded.nl>");
+MODULE_LICENSE("GPL");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/rtl8306.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/rtl8306.c
new file mode 100644
index 0000000..31bc758
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/rtl8306.c
@@ -0,0 +1,1063 @@
+/*
+ * rtl8306.c: RTL8306S switch driver
+ *
+ * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/if.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/netlink.h>
+#include <net/genetlink.h>
+#include <linux/switch.h>
+#include <linux/delay.h>
+#include <linux/phy.h>
+#include <linux/version.h>
+
+//#define DEBUG 1
+
+/* Global (PHY0) */
+#define RTL8306_REG_PAGE		16
+#define RTL8306_REG_PAGE_LO		(1 << 15)
+#define RTL8306_REG_PAGE_HI		(1 << 1) /* inverted */
+
+#define RTL8306_NUM_VLANS		16
+#define RTL8306_NUM_PORTS		6
+#define RTL8306_PORT_CPU		5
+#define RTL8306_NUM_PAGES		4
+#define RTL8306_NUM_REGS		32
+
+#define RTL_NAME_S          "RTL8306S"
+#define RTL_NAME_SD         "RTL8306SD"
+#define RTL_NAME_SDM        "RTL8306SDM"
+#define RTL_NAME_UNKNOWN    "RTL8306(unknown)"
+
+#define RTL8306_MAGIC	0x8306
+
+static LIST_HEAD(phydevs);
+
+struct rtl_priv {
+	struct list_head list;
+	struct switch_dev dev;
+	int page;
+	int type;
+	int do_cpu;
+	struct mii_bus *bus;
+	char hwname[sizeof(RTL_NAME_UNKNOWN)];
+	bool fixup;
+};
+
+struct rtl_phyregs {
+	int nway;
+	int speed;
+	int duplex;
+};
+
+#define to_rtl(_dev) container_of(_dev, struct rtl_priv, dev)
+
+enum {
+	RTL_TYPE_S,
+	RTL_TYPE_SD,
+	RTL_TYPE_SDM,
+};
+
+struct rtl_reg {
+	int page;
+	int phy;
+	int reg;
+	int bits;
+	int shift;
+	int inverted;
+};
+
+#define RTL_VLAN_REGOFS(name) \
+	(RTL_REG_VLAN1_##name - RTL_REG_VLAN0_##name)
+
+#define RTL_PORT_REGOFS(name) \
+	(RTL_REG_PORT1_##name - RTL_REG_PORT0_##name)
+
+#define RTL_PORT_REG(id, reg) \
+	(RTL_REG_PORT0_##reg + (id * RTL_PORT_REGOFS(reg)))
+
+#define RTL_VLAN_REG(id, reg) \
+	(RTL_REG_VLAN0_##reg + (id * RTL_VLAN_REGOFS(reg)))
+
+#define RTL_GLOBAL_REGATTR(reg) \
+	.id = RTL_REG_##reg, \
+	.type = SWITCH_TYPE_INT, \
+	.ofs = 0, \
+	.set = rtl_attr_set_int, \
+	.get = rtl_attr_get_int
+
+#define RTL_PORT_REGATTR(reg) \
+	.id = RTL_REG_PORT0_##reg, \
+	.type = SWITCH_TYPE_INT, \
+	.ofs = RTL_PORT_REGOFS(reg), \
+	.set = rtl_attr_set_port_int, \
+	.get = rtl_attr_get_port_int
+
+#define RTL_VLAN_REGATTR(reg) \
+	.id = RTL_REG_VLAN0_##reg, \
+	.type = SWITCH_TYPE_INT, \
+	.ofs = RTL_VLAN_REGOFS(reg), \
+	.set = rtl_attr_set_vlan_int, \
+	.get = rtl_attr_get_vlan_int
+
+enum rtl_regidx {
+	RTL_REG_CHIPID,
+	RTL_REG_CHIPVER,
+	RTL_REG_CHIPTYPE,
+	RTL_REG_CPUPORT,
+
+	RTL_REG_EN_CPUPORT,
+	RTL_REG_EN_TAG_OUT,
+	RTL_REG_EN_TAG_CLR,
+	RTL_REG_EN_TAG_IN,
+	RTL_REG_TRAP_CPU,
+	RTL_REG_CPU_LINKUP,
+	RTL_REG_TRUNK_PORTSEL,
+	RTL_REG_EN_TRUNK,
+	RTL_REG_RESET,
+
+	RTL_REG_VLAN_ENABLE,
+	RTL_REG_VLAN_FILTER,
+	RTL_REG_VLAN_TAG_ONLY,
+	RTL_REG_VLAN_TAG_AWARE,
+#define RTL_VLAN_ENUM(id) \
+	RTL_REG_VLAN##id##_VID, \
+	RTL_REG_VLAN##id##_PORTMASK
+	RTL_VLAN_ENUM(0),
+	RTL_VLAN_ENUM(1),
+	RTL_VLAN_ENUM(2),
+	RTL_VLAN_ENUM(3),
+	RTL_VLAN_ENUM(4),
+	RTL_VLAN_ENUM(5),
+	RTL_VLAN_ENUM(6),
+	RTL_VLAN_ENUM(7),
+	RTL_VLAN_ENUM(8),
+	RTL_VLAN_ENUM(9),
+	RTL_VLAN_ENUM(10),
+	RTL_VLAN_ENUM(11),
+	RTL_VLAN_ENUM(12),
+	RTL_VLAN_ENUM(13),
+	RTL_VLAN_ENUM(14),
+	RTL_VLAN_ENUM(15),
+#define RTL_PORT_ENUM(id) \
+	RTL_REG_PORT##id##_PVID, \
+	RTL_REG_PORT##id##_NULL_VID_REPLACE, \
+	RTL_REG_PORT##id##_NON_PVID_DISCARD, \
+	RTL_REG_PORT##id##_VID_INSERT, \
+	RTL_REG_PORT##id##_TAG_INSERT, \
+	RTL_REG_PORT##id##_LINK, \
+	RTL_REG_PORT##id##_SPEED, \
+	RTL_REG_PORT##id##_NWAY, \
+	RTL_REG_PORT##id##_NRESTART, \
+	RTL_REG_PORT##id##_DUPLEX, \
+	RTL_REG_PORT##id##_RXEN, \
+	RTL_REG_PORT##id##_TXEN
+	RTL_PORT_ENUM(0),
+	RTL_PORT_ENUM(1),
+	RTL_PORT_ENUM(2),
+	RTL_PORT_ENUM(3),
+	RTL_PORT_ENUM(4),
+	RTL_PORT_ENUM(5),
+};
+
+static const struct rtl_reg rtl_regs[] = {
+	[RTL_REG_CHIPID]         = { 0, 4, 30, 16,  0, 0 },
+	[RTL_REG_CHIPVER]        = { 0, 4, 31,  8,  0, 0 },
+	[RTL_REG_CHIPTYPE]       = { 0, 4, 31,  2,  8, 0 },
+
+	/* CPU port number */
+	[RTL_REG_CPUPORT]        = { 2, 4, 21,  3,  0, 0 },
+	/* Enable CPU port function */
+	[RTL_REG_EN_CPUPORT]     = { 3, 2, 21,  1, 15, 1 },
+	/* Enable CPU port tag insertion */
+	[RTL_REG_EN_TAG_OUT]     = { 3, 2, 21,  1, 12, 0 },
+	/* Enable CPU port tag removal */
+	[RTL_REG_EN_TAG_CLR]     = { 3, 2, 21,  1, 11, 0 },
+	/* Enable CPU port tag checking */
+	[RTL_REG_EN_TAG_IN]      = { 0, 4, 21,  1,  7, 0 },
+	[RTL_REG_EN_TRUNK]       = { 0, 0, 19,  1, 11, 1 },
+	[RTL_REG_TRUNK_PORTSEL]  = { 0, 0, 16,  1,  6, 1 },
+	[RTL_REG_RESET]          = { 0, 0, 16,  1, 12, 0 },
+
+	[RTL_REG_TRAP_CPU]       = { 3, 2, 22,  1,  6, 0 },
+	[RTL_REG_CPU_LINKUP]     = { 0, 6, 22,  1, 15, 0 },
+
+	[RTL_REG_VLAN_TAG_ONLY]  = { 0, 0, 16,  1,  8, 1 },
+	[RTL_REG_VLAN_FILTER]    = { 0, 0, 16,  1,  9, 1 },
+	[RTL_REG_VLAN_TAG_AWARE] = { 0, 0, 16,  1, 10, 1 },
+	[RTL_REG_VLAN_ENABLE]    = { 0, 0, 18,  1,  8, 1 },
+
+#define RTL_VLAN_REGS(id, phy, page, regofs) \
+	[RTL_REG_VLAN##id##_VID] = { page, phy, 25 + regofs, 12, 0, 0 }, \
+	[RTL_REG_VLAN##id##_PORTMASK] = { page, phy, 24 + regofs, 6, 0, 0 }
+	RTL_VLAN_REGS( 0, 0, 0, 0),
+	RTL_VLAN_REGS( 1, 1, 0, 0),
+	RTL_VLAN_REGS( 2, 2, 0, 0),
+	RTL_VLAN_REGS( 3, 3, 0, 0),
+	RTL_VLAN_REGS( 4, 4, 0, 0),
+	RTL_VLAN_REGS( 5, 0, 1, 2),
+	RTL_VLAN_REGS( 6, 1, 1, 2),
+	RTL_VLAN_REGS( 7, 2, 1, 2),
+	RTL_VLAN_REGS( 8, 3, 1, 2),
+	RTL_VLAN_REGS( 9, 4, 1, 2),
+	RTL_VLAN_REGS(10, 0, 1, 4),
+	RTL_VLAN_REGS(11, 1, 1, 4),
+	RTL_VLAN_REGS(12, 2, 1, 4),
+	RTL_VLAN_REGS(13, 3, 1, 4),
+	RTL_VLAN_REGS(14, 4, 1, 4),
+	RTL_VLAN_REGS(15, 0, 1, 6),
+
+#define REG_PORT_SETTING(port, phy) \
+	[RTL_REG_PORT##port##_SPEED] = { 0, phy, 0, 1, 13, 0 }, \
+	[RTL_REG_PORT##port##_NWAY] = { 0, phy, 0, 1, 12, 0 }, \
+	[RTL_REG_PORT##port##_NRESTART] = { 0, phy, 0, 1, 9, 0 }, \
+	[RTL_REG_PORT##port##_DUPLEX] = { 0, phy, 0, 1, 8, 0 }, \
+	[RTL_REG_PORT##port##_TXEN] = { 0, phy, 24, 1, 11, 0 }, \
+	[RTL_REG_PORT##port##_RXEN] = { 0, phy, 24, 1, 10, 0 }, \
+	[RTL_REG_PORT##port##_LINK] = { 0, phy, 1, 1, 2, 0 }, \
+	[RTL_REG_PORT##port##_NULL_VID_REPLACE] = { 0, phy, 22, 1, 12, 0 }, \
+	[RTL_REG_PORT##port##_NON_PVID_DISCARD] = { 0, phy, 22, 1, 11, 0 }, \
+	[RTL_REG_PORT##port##_VID_INSERT] = { 0, phy, 22, 2, 9, 0 }, \
+	[RTL_REG_PORT##port##_TAG_INSERT] = { 0, phy, 22, 2, 0, 0 }
+
+	REG_PORT_SETTING(0, 0),
+	REG_PORT_SETTING(1, 1),
+	REG_PORT_SETTING(2, 2),
+	REG_PORT_SETTING(3, 3),
+	REG_PORT_SETTING(4, 4),
+	REG_PORT_SETTING(5, 6),
+
+#define REG_PORT_PVID(phy, page, regofs) \
+	{ page, phy, 24 + regofs, 4, 12, 0 }
+	[RTL_REG_PORT0_PVID] = REG_PORT_PVID(0, 0, 0),
+	[RTL_REG_PORT1_PVID] = REG_PORT_PVID(1, 0, 0),
+	[RTL_REG_PORT2_PVID] = REG_PORT_PVID(2, 0, 0),
+	[RTL_REG_PORT3_PVID] = REG_PORT_PVID(3, 0, 0),
+	[RTL_REG_PORT4_PVID] = REG_PORT_PVID(4, 0, 0),
+	[RTL_REG_PORT5_PVID] = REG_PORT_PVID(0, 1, 2),
+};
+
+
+static inline void
+rtl_set_page(struct rtl_priv *priv, unsigned int page)
+{
+	struct mii_bus *bus = priv->bus;
+	u16 pgsel;
+
+	if (priv->fixup)
+		return;
+
+	if (priv->page == page)
+		return;
+
+	BUG_ON(page > RTL8306_NUM_PAGES);
+	pgsel = bus->read(bus, 0, RTL8306_REG_PAGE);
+	pgsel &= ~(RTL8306_REG_PAGE_LO | RTL8306_REG_PAGE_HI);
+	if (page & (1 << 0))
+		pgsel |= RTL8306_REG_PAGE_LO;
+	if (!(page & (1 << 1))) /* bit is inverted */
+		pgsel |= RTL8306_REG_PAGE_HI;
+	bus->write(bus, 0, RTL8306_REG_PAGE, pgsel);
+}
+
+static inline int
+rtl_w16(struct switch_dev *dev, unsigned int page, unsigned int phy, unsigned int reg, u16 val)
+{
+	struct rtl_priv *priv = to_rtl(dev);
+	struct mii_bus *bus = priv->bus;
+
+	rtl_set_page(priv, page);
+	bus->write(bus, phy, reg, val);
+	bus->read(bus, phy, reg); /* flush */
+	return 0;
+}
+
+static inline int
+rtl_r16(struct switch_dev *dev, unsigned int page, unsigned int phy, unsigned int reg)
+{
+	struct rtl_priv *priv = to_rtl(dev);
+	struct mii_bus *bus = priv->bus;
+
+	rtl_set_page(priv, page);
+	return bus->read(bus, phy, reg);
+}
+
+static inline u16
+rtl_rmw(struct switch_dev *dev, unsigned int page, unsigned int phy, unsigned int reg, u16 mask, u16 val)
+{
+	struct rtl_priv *priv = to_rtl(dev);
+	struct mii_bus *bus = priv->bus;
+	u16 r;
+
+	rtl_set_page(priv, page);
+	r = bus->read(bus, phy, reg);
+	r &= ~mask;
+	r |= val;
+	bus->write(bus, phy, reg, r);
+	return bus->read(bus, phy, reg); /* flush */
+}
+
+
+static inline int
+rtl_get(struct switch_dev *dev, enum rtl_regidx s)
+{
+	const struct rtl_reg *r = &rtl_regs[s];
+	u16 val;
+
+	BUG_ON(s >= ARRAY_SIZE(rtl_regs));
+	if (r->bits == 0) /* unimplemented */
+		return 0;
+
+	val = rtl_r16(dev, r->page, r->phy, r->reg);
+
+	if (r->shift > 0)
+		val >>= r->shift;
+
+	if (r->inverted)
+		val = ~val;
+
+	val &= (1 << r->bits) - 1;
+
+	return val;
+}
+
+static int
+rtl_set(struct switch_dev *dev, enum rtl_regidx s, unsigned int val)
+{
+	const struct rtl_reg *r = &rtl_regs[s];
+	u16 mask = 0xffff;
+
+	BUG_ON(s >= ARRAY_SIZE(rtl_regs));
+
+	if (r->bits == 0) /* unimplemented */
+		return 0;
+
+	if (r->shift > 0)
+		val <<= r->shift;
+
+	if (r->inverted)
+		val = ~val;
+
+	if (r->bits != 16) {
+		mask = (1 << r->bits) - 1;
+		mask <<= r->shift;
+	}
+	val &= mask;
+	return rtl_rmw(dev, r->page, r->phy, r->reg, mask, val);
+}
+
+static void
+rtl_phy_save(struct switch_dev *dev, int port, struct rtl_phyregs *regs)
+{
+	regs->nway = rtl_get(dev, RTL_PORT_REG(port, NWAY));
+	regs->speed = rtl_get(dev, RTL_PORT_REG(port, SPEED));
+	regs->duplex = rtl_get(dev, RTL_PORT_REG(port, DUPLEX));
+}
+
+static void
+rtl_phy_restore(struct switch_dev *dev, int port, struct rtl_phyregs *regs)
+{
+	rtl_set(dev, RTL_PORT_REG(port, NWAY), regs->nway);
+	rtl_set(dev, RTL_PORT_REG(port, SPEED), regs->speed);
+	rtl_set(dev, RTL_PORT_REG(port, DUPLEX), regs->duplex);
+}
+
+static void
+rtl_port_set_enable(struct switch_dev *dev, int port, int enabled)
+{
+	rtl_set(dev, RTL_PORT_REG(port, RXEN), enabled);
+	rtl_set(dev, RTL_PORT_REG(port, TXEN), enabled);
+
+	if ((port >= 5) || !enabled)
+		return;
+
+	/* restart autonegotiation if enabled */
+	rtl_set(dev, RTL_PORT_REG(port, NRESTART), 1);
+}
+
+static int
+rtl_hw_apply(struct switch_dev *dev)
+{
+	int i;
+	int trunk_en, trunk_psel;
+	struct rtl_phyregs port5;
+
+	rtl_phy_save(dev, 5, &port5);
+
+	/* disable rx/tx from PHYs */
+	for (i = 0; i < RTL8306_NUM_PORTS - 1; i++) {
+		rtl_port_set_enable(dev, i, 0);
+	}
+
+	/* save trunking status */
+	trunk_en = rtl_get(dev, RTL_REG_EN_TRUNK);
+	trunk_psel = rtl_get(dev, RTL_REG_TRUNK_PORTSEL);
+
+	/* trunk port 3 and 4
+	 * XXX: Big WTF, but RealTek seems to do it */
+	rtl_set(dev, RTL_REG_EN_TRUNK, 1);
+	rtl_set(dev, RTL_REG_TRUNK_PORTSEL, 1);
+
+	/* execute the software reset */
+	rtl_set(dev, RTL_REG_RESET, 1);
+
+	/* wait for the reset to complete,
+	 * but don't wait for too long */
+	for (i = 0; i < 10; i++) {
+		if (rtl_get(dev, RTL_REG_RESET) == 0)
+			break;
+
+		msleep(1);
+	}
+
+	/* enable rx/tx from PHYs */
+	for (i = 0; i < RTL8306_NUM_PORTS - 1; i++) {
+		rtl_port_set_enable(dev, i, 1);
+	}
+
+	/* restore trunking settings */
+	rtl_set(dev, RTL_REG_EN_TRUNK, trunk_en);
+	rtl_set(dev, RTL_REG_TRUNK_PORTSEL, trunk_psel);
+	rtl_phy_restore(dev, 5, &port5);
+
+	rtl_set(dev, RTL_REG_CPU_LINKUP, 1);
+
+	return 0;
+}
+
+static void
+rtl_hw_init(struct switch_dev *dev)
+{
+	struct rtl_priv *priv = to_rtl(dev);
+	int cpu_mask = 1 << dev->cpu_port;
+	int i;
+
+	rtl_set(dev, RTL_REG_VLAN_ENABLE, 0);
+	rtl_set(dev, RTL_REG_VLAN_FILTER, 0);
+	rtl_set(dev, RTL_REG_EN_TRUNK, 0);
+	rtl_set(dev, RTL_REG_TRUNK_PORTSEL, 0);
+
+	/* initialize cpu port settings */
+	if (priv->do_cpu) {
+		rtl_set(dev, RTL_REG_CPUPORT, dev->cpu_port);
+		rtl_set(dev, RTL_REG_EN_CPUPORT, 1);
+	} else {
+		rtl_set(dev, RTL_REG_CPUPORT, 7);
+		rtl_set(dev, RTL_REG_EN_CPUPORT, 0);
+	}
+	rtl_set(dev, RTL_REG_EN_TAG_OUT, 0);
+	rtl_set(dev, RTL_REG_EN_TAG_IN, 0);
+	rtl_set(dev, RTL_REG_EN_TAG_CLR, 0);
+
+	/* reset all vlans */
+	for (i = 0; i < RTL8306_NUM_VLANS; i++) {
+		rtl_set(dev, RTL_VLAN_REG(i, VID), i);
+		rtl_set(dev, RTL_VLAN_REG(i, PORTMASK), 0);
+	}
+
+	/* default to port isolation */
+	for (i = 0; i < RTL8306_NUM_PORTS; i++) {
+		unsigned long mask;
+
+		if ((1 << i) == cpu_mask)
+			mask = ((1 << RTL8306_NUM_PORTS) - 1) & ~cpu_mask; /* all bits set */
+		else
+			mask = cpu_mask | (1 << i);
+
+		rtl_set(dev, RTL_VLAN_REG(i, PORTMASK), mask);
+		rtl_set(dev, RTL_PORT_REG(i, PVID), i);
+		rtl_set(dev, RTL_PORT_REG(i, NULL_VID_REPLACE), 1);
+		rtl_set(dev, RTL_PORT_REG(i, VID_INSERT), 1);
+		rtl_set(dev, RTL_PORT_REG(i, TAG_INSERT), 3);
+	}
+	rtl_hw_apply(dev);
+}
+
+#ifdef DEBUG
+static int
+rtl_set_use_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct rtl_priv *priv = to_rtl(dev);
+	priv->do_cpu = val->value.i;
+	rtl_hw_init(dev);
+	return 0;
+}
+
+static int
+rtl_get_use_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct rtl_priv *priv = to_rtl(dev);
+	val->value.i = priv->do_cpu;
+	return 0;
+}
+
+static int
+rtl_set_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	dev->cpu_port = val->value.i;
+	rtl_hw_init(dev);
+	return 0;
+}
+
+static int
+rtl_get_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	val->value.i = dev->cpu_port;
+	return 0;
+}
+#endif
+
+static int
+rtl_reset(struct switch_dev *dev)
+{
+	rtl_hw_init(dev);
+	return 0;
+}
+
+static int
+rtl_attr_set_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	int idx = attr->id + (val->port_vlan * attr->ofs);
+	struct rtl_phyregs port;
+
+	if (attr->id >= ARRAY_SIZE(rtl_regs))
+		return -EINVAL;
+
+	if ((attr->max > 0) && (val->value.i > attr->max))
+		return -EINVAL;
+
+	/* access to phy register 22 on port 4/5
+	 * needs phy status save/restore */
+	if ((val->port_vlan > 3) &&
+		(rtl_regs[idx].reg == 22) &&
+		(rtl_regs[idx].page == 0)) {
+
+		rtl_phy_save(dev, val->port_vlan, &port);
+		rtl_set(dev, idx, val->value.i);
+		rtl_phy_restore(dev, val->port_vlan, &port);
+	} else {
+		rtl_set(dev, idx, val->value.i);
+	}
+
+	return 0;
+}
+
+static int
+rtl_attr_get_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	int idx = attr->id + (val->port_vlan * attr->ofs);
+
+	if (idx >= ARRAY_SIZE(rtl_regs))
+		return -EINVAL;
+
+	val->value.i = rtl_get(dev, idx);
+	return 0;
+}
+
+static int
+rtl_attr_set_port_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	if (val->port_vlan >= RTL8306_NUM_PORTS)
+		return -EINVAL;
+
+	return rtl_attr_set_int(dev, attr, val);
+}
+
+static int
+rtl_attr_get_port_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	if (val->port_vlan >= RTL8306_NUM_PORTS)
+		return -EINVAL;
+	return rtl_attr_get_int(dev, attr, val);
+}
+
+static int 
+rtl_get_port_link(struct switch_dev *dev, int port, struct switch_port_link *link)
+{
+	if (port >= RTL8306_NUM_PORTS)
+		return -EINVAL;
+
+	/* in case the link changes from down to up, the register is only updated on read */
+	link->link = rtl_get(dev, RTL_PORT_REG(port, LINK));
+	if (!link->link)
+		link->link = rtl_get(dev, RTL_PORT_REG(port, LINK));
+
+	if (!link->link)
+		return 0;
+
+	link->duplex = rtl_get(dev, RTL_PORT_REG(port, DUPLEX));
+	link->aneg = rtl_get(dev, RTL_PORT_REG(port, NWAY));
+
+	if (rtl_get(dev, RTL_PORT_REG(port, SPEED)))
+		link->speed = SWITCH_PORT_SPEED_100;
+	else
+		link->speed = SWITCH_PORT_SPEED_10;
+
+	return 0;
+}
+
+static int
+rtl_attr_set_vlan_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	if (val->port_vlan >= dev->vlans)
+		return -EINVAL;
+
+	return rtl_attr_set_int(dev, attr, val);
+}
+
+static int
+rtl_attr_get_vlan_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	if (val->port_vlan >= dev->vlans)
+		return -EINVAL;
+
+	return rtl_attr_get_int(dev, attr, val);
+}
+
+static int
+rtl_get_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	unsigned int i, mask;
+
+	mask = rtl_get(dev, RTL_VLAN_REG(val->port_vlan, PORTMASK));
+	for (i = 0; i < RTL8306_NUM_PORTS; i++) {
+		struct switch_port *port;
+
+		if (!(mask & (1 << i)))
+			continue;
+
+		port = &val->value.ports[val->len];
+		port->id = i;
+		if (rtl_get(dev, RTL_PORT_REG(i, TAG_INSERT)) == 2 || i == dev->cpu_port)
+			port->flags = (1 << SWITCH_PORT_FLAG_TAGGED);
+		val->len++;
+	}
+
+	return 0;
+}
+
+static int
+rtl_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	struct rtl_priv *priv = to_rtl(dev);
+	struct rtl_phyregs port;
+	int en = val->value.i;
+	int i;
+
+	rtl_set(dev, RTL_REG_EN_TAG_OUT, en && priv->do_cpu);
+	rtl_set(dev, RTL_REG_EN_TAG_IN, en && priv->do_cpu);
+	rtl_set(dev, RTL_REG_EN_TAG_CLR, en && priv->do_cpu);
+	rtl_set(dev, RTL_REG_VLAN_TAG_AWARE, en);
+	if (en)
+		rtl_set(dev, RTL_REG_VLAN_FILTER, en);
+
+	for (i = 0; i < RTL8306_NUM_PORTS; i++) {
+		if (i > 3)
+			rtl_phy_save(dev, val->port_vlan, &port);
+		rtl_set(dev, RTL_PORT_REG(i, NULL_VID_REPLACE), 1);
+		rtl_set(dev, RTL_PORT_REG(i, VID_INSERT), (en ? (i == dev->cpu_port ? 0 : 1) : 1));
+		rtl_set(dev, RTL_PORT_REG(i, TAG_INSERT), (en ? (i == dev->cpu_port ? 2 : 1) : 3));
+		if (i > 3)
+			rtl_phy_restore(dev, val->port_vlan, &port);
+	}
+	rtl_set(dev, RTL_REG_VLAN_ENABLE, en);
+
+	return 0;
+}
+
+static int
+rtl_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
+{
+	val->value.i = rtl_get(dev, RTL_REG_VLAN_ENABLE);
+	return 0;
+}
+
+static int
+rtl_set_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	unsigned int mask = 0;
+	unsigned int oldmask;
+	int i;
+
+	for(i = 0; i < val->len; i++)
+	{
+		struct switch_port *port = &val->value.ports[i];
+		bool tagged = false;
+
+		mask |= (1 << port->id);
+
+		if (port->id == dev->cpu_port)
+			continue;
+
+		if ((i == dev->cpu_port) ||
+			(port->flags & (1 << SWITCH_PORT_FLAG_TAGGED)))
+			tagged = true;
+
+		/* fix up PVIDs for added ports */
+		if (!tagged)
+			rtl_set(dev, RTL_PORT_REG(port->id, PVID), val->port_vlan);
+
+		rtl_set(dev, RTL_PORT_REG(port->id, NON_PVID_DISCARD), (tagged ? 0 : 1));
+		rtl_set(dev, RTL_PORT_REG(port->id, VID_INSERT), (tagged ? 0 : 1));
+		rtl_set(dev, RTL_PORT_REG(port->id, TAG_INSERT), (tagged ? 2 : 1));
+	}
+
+	oldmask = rtl_get(dev, RTL_VLAN_REG(val->port_vlan, PORTMASK));
+	rtl_set(dev, RTL_VLAN_REG(val->port_vlan, PORTMASK), mask);
+
+	/* fix up PVIDs for removed ports, default to last vlan */
+	oldmask &= ~mask;
+	for (i = 0; i < RTL8306_NUM_PORTS; i++) {
+		if (!(oldmask & (1 << i)))
+			continue;
+
+		if (i == dev->cpu_port)
+			continue;
+
+		if (rtl_get(dev, RTL_PORT_REG(i, PVID)) == val->port_vlan)
+			rtl_set(dev, RTL_PORT_REG(i, PVID), dev->vlans - 1);
+	}
+
+	return 0;
+}
+
+static struct switch_attr rtl_globals[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.max = 1,
+		.set = rtl_set_vlan,
+		.get = rtl_get_vlan,
+	},
+	{
+		RTL_GLOBAL_REGATTR(EN_TRUNK),
+		.name = "trunk",
+		.description = "Enable port trunking",
+		.max = 1,
+	},
+	{
+		RTL_GLOBAL_REGATTR(TRUNK_PORTSEL),
+		.name = "trunk_sel",
+		.description = "Select ports for trunking (0: 0,1 - 1: 3,4)",
+		.max = 1,
+	},
+#ifdef DEBUG
+	{
+		RTL_GLOBAL_REGATTR(VLAN_FILTER),
+		.name = "vlan_filter",
+		.description = "Filter incoming packets for allowed VLANS",
+		.max = 1,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "cpuport",
+		.description = "CPU Port",
+		.set = rtl_set_cpuport,
+		.get = rtl_get_cpuport,
+		.max = RTL8306_NUM_PORTS,
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "use_cpuport",
+		.description = "CPU Port handling flag",
+		.set = rtl_set_use_cpuport,
+		.get = rtl_get_use_cpuport,
+		.max = RTL8306_NUM_PORTS,
+	},
+	{
+		RTL_GLOBAL_REGATTR(TRAP_CPU),
+		.name = "trap_cpu",
+		.description = "VLAN trap to CPU",
+		.max = 1,
+	},
+	{
+		RTL_GLOBAL_REGATTR(VLAN_TAG_AWARE),
+		.name = "vlan_tag_aware",
+		.description = "Enable VLAN tag awareness",
+		.max = 1,
+	},
+	{
+		RTL_GLOBAL_REGATTR(VLAN_TAG_ONLY),
+		.name = "tag_only",
+		.description = "Only accept tagged packets",
+		.max = 1,
+	},
+#endif
+};
+static struct switch_attr rtl_port[] = {
+	{
+		RTL_PORT_REGATTR(PVID),
+		.name = "pvid",
+		.description = "Port VLAN ID",
+		.max = RTL8306_NUM_VLANS - 1,
+	},
+#ifdef DEBUG
+	{
+		RTL_PORT_REGATTR(NULL_VID_REPLACE),
+		.name = "null_vid",
+		.description = "NULL VID gets replaced by port default vid",
+		.max = 1,
+	},
+	{
+		RTL_PORT_REGATTR(NON_PVID_DISCARD),
+		.name = "non_pvid_discard",
+		.description = "discard packets with VID != PVID",
+		.max = 1,
+	},
+	{
+		RTL_PORT_REGATTR(VID_INSERT),
+		.name = "vid_insert_remove",
+		.description = "how should the switch insert and remove vids ?",
+		.max = 3,
+	},
+	{
+		RTL_PORT_REGATTR(TAG_INSERT),
+		.name = "tag_insert",
+		.description = "tag insertion handling",
+		.max = 3,
+	},
+#endif
+};
+
+static struct switch_attr rtl_vlan[] = {
+	{
+		RTL_VLAN_REGATTR(VID),
+		.name = "vid",
+		.description = "VLAN ID (1-4095)",
+		.max = 4095,
+	},
+};
+
+static const struct switch_dev_ops rtl8306_ops = {
+	.attr_global = {
+		.attr = rtl_globals,
+		.n_attr = ARRAY_SIZE(rtl_globals),
+	},
+	.attr_port = {
+		.attr = rtl_port,
+		.n_attr = ARRAY_SIZE(rtl_port),
+	},
+	.attr_vlan = {
+		.attr = rtl_vlan,
+		.n_attr = ARRAY_SIZE(rtl_vlan),
+	},
+
+	.get_vlan_ports = rtl_get_ports,
+	.set_vlan_ports = rtl_set_ports,
+	.apply_config = rtl_hw_apply,
+	.reset_switch = rtl_reset,
+	.get_port_link = rtl_get_port_link,
+};
+
+static int
+rtl8306_config_init(struct phy_device *pdev)
+{
+	struct net_device *netdev = pdev->attached_dev;
+	struct rtl_priv *priv = pdev->priv;
+	struct switch_dev *dev = &priv->dev;
+	struct switch_val val;
+	unsigned int chipid, chipver, chiptype;
+	int err;
+
+	/* Only init the switch for the primary PHY */
+	if (pdev->mdio.addr != 0)
+		return 0;
+
+	val.value.i = 1;
+	priv->dev.cpu_port = RTL8306_PORT_CPU;
+	priv->dev.ports = RTL8306_NUM_PORTS;
+	priv->dev.vlans = RTL8306_NUM_VLANS;
+	priv->dev.ops = &rtl8306_ops;
+	priv->do_cpu = 0;
+	priv->page = -1;
+	priv->bus = pdev->mdio.bus;
+
+	chipid = rtl_get(dev, RTL_REG_CHIPID);
+	chipver = rtl_get(dev, RTL_REG_CHIPVER);
+	chiptype = rtl_get(dev, RTL_REG_CHIPTYPE);
+	switch(chiptype) {
+	case 0:
+	case 2:
+		strncpy(priv->hwname, RTL_NAME_S, sizeof(priv->hwname));
+		priv->type = RTL_TYPE_S;
+		break;
+	case 1:
+		strncpy(priv->hwname, RTL_NAME_SD, sizeof(priv->hwname));
+		priv->type = RTL_TYPE_SD;
+		break;
+	case 3:
+		strncpy(priv->hwname, RTL_NAME_SDM, sizeof(priv->hwname));
+		priv->type = RTL_TYPE_SDM;
+		break;
+	default:
+		strncpy(priv->hwname, RTL_NAME_UNKNOWN, sizeof(priv->hwname));
+		break;
+	}
+
+	dev->name = priv->hwname;
+	rtl_hw_init(dev);
+
+	printk(KERN_INFO "Registering %s switch with Chip ID: 0x%04x, version: 0x%04x\n", priv->hwname, chipid, chipver);
+
+	err = register_switch(dev, netdev);
+	if (err < 0) {
+		kfree(priv);
+		return err;
+	}
+
+	return 0;
+}
+
+
+static int
+rtl8306_fixup(struct phy_device *pdev)
+{
+	struct rtl_priv priv;
+	u16 chipid;
+
+	/* Attach to primary LAN port and WAN port */
+	if (pdev->mdio.addr != 0 && pdev->mdio.addr != 4)
+		return 0;
+
+	memset(&priv, 0, sizeof(priv));
+	priv.fixup = true;
+	priv.page = -1;
+	priv.bus = pdev->mdio.bus;
+	chipid = rtl_get(&priv.dev, RTL_REG_CHIPID);
+	if (chipid == 0x5988)
+		pdev->phy_id = RTL8306_MAGIC;
+
+	return 0;
+}
+
+static int
+rtl8306_probe(struct phy_device *pdev)
+{
+	struct rtl_priv *priv;
+
+	list_for_each_entry(priv, &phydevs, list) {
+		/*
+		 * share one rtl_priv instance between virtual phy
+		 * devices on the same bus
+		 */
+		if (priv->bus == pdev->mdio.bus)
+			goto found;
+	}
+	priv = kzalloc(sizeof(struct rtl_priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->bus = pdev->mdio.bus;
+
+found:
+	pdev->priv = priv;
+	return 0;
+}
+
+static void
+rtl8306_remove(struct phy_device *pdev)
+{
+	struct rtl_priv *priv = pdev->priv;
+	unregister_switch(&priv->dev);
+	kfree(priv);
+}
+
+static int
+rtl8306_config_aneg(struct phy_device *pdev)
+{
+	struct rtl_priv *priv = pdev->priv;
+
+	/* Only for WAN */
+	if (pdev->mdio.addr == 0)
+		return 0;
+
+	/* Restart autonegotiation */
+	rtl_set(&priv->dev, RTL_PORT_REG(4, NWAY), 1);
+	rtl_set(&priv->dev, RTL_PORT_REG(4, NRESTART), 1);
+
+	return 0;
+}
+
+static int
+rtl8306_read_status(struct phy_device *pdev)
+{
+	struct rtl_priv *priv = pdev->priv;
+	struct switch_dev *dev = &priv->dev;
+
+	if (pdev->mdio.addr == 4) {
+		/* WAN */
+		pdev->speed = rtl_get(dev, RTL_PORT_REG(4, SPEED)) ? SPEED_100 : SPEED_10;
+		pdev->duplex = rtl_get(dev, RTL_PORT_REG(4, DUPLEX)) ? DUPLEX_FULL : DUPLEX_HALF;
+		pdev->link = !!rtl_get(dev, RTL_PORT_REG(4, LINK));
+	} else {
+		/* LAN */
+		pdev->speed = SPEED_100;
+		pdev->duplex = DUPLEX_FULL;
+		pdev->link = 1;
+	}
+
+	/*
+	 * Bypass generic PHY status read,
+	 * it doesn't work with this switch
+	 */
+	if (pdev->link) {
+		pdev->state = PHY_RUNNING;
+		netif_carrier_on(pdev->attached_dev);
+		pdev->adjust_link(pdev->attached_dev);
+	} else {
+		pdev->state = PHY_NOLINK;
+		netif_carrier_off(pdev->attached_dev);
+		pdev->adjust_link(pdev->attached_dev);
+	}
+
+	return 0;
+}
+
+
+static struct phy_driver rtl8306_driver = {
+	.name		= "Realtek RTL8306S",
+	.phy_id		= RTL8306_MAGIC,
+	.phy_id_mask	= 0xffffffff,
+	.features	= PHY_BASIC_FEATURES,
+	.probe		= &rtl8306_probe,
+	.remove		= &rtl8306_remove,
+	.config_init	= &rtl8306_config_init,
+	.config_aneg	= &rtl8306_config_aneg,
+	.read_status	= &rtl8306_read_status,
+};
+
+
+static int __init
+rtl_init(void)
+{
+	phy_register_fixup_for_id(PHY_ANY_ID, rtl8306_fixup);
+	return phy_driver_register(&rtl8306_driver, THIS_MODULE);
+}
+
+static void __exit
+rtl_exit(void)
+{
+	phy_driver_unregister(&rtl8306_driver);
+}
+
+module_init(rtl_init);
+module_exit(rtl_exit);
+MODULE_LICENSE("GPL");
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/rtl8366_smi.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/rtl8366_smi.c
new file mode 100644
index 0000000..e8375e5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/rtl8366_smi.c
@@ -0,0 +1,1624 @@
+/*
+ * Realtek RTL8366 SMI interface driver
+ *
+ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/rtl8366.h>
+#include <linux/version.h>
+#include <linux/of_mdio.h>
+
+#ifdef CONFIG_RTL8366_SMI_DEBUG_FS
+#include <linux/debugfs.h>
+#endif
+
+#include "rtl8366_smi.h"
+
+#define RTL8366_SMI_ACK_RETRY_COUNT         5
+
+#define RTL8366_SMI_HW_STOP_DELAY		25	/* msecs */
+#define RTL8366_SMI_HW_START_DELAY		100	/* msecs */
+
+static inline void rtl8366_smi_clk_delay(struct rtl8366_smi *smi)
+{
+	ndelay(smi->clk_delay);
+}
+
+static void rtl8366_smi_start(struct rtl8366_smi *smi)
+{
+	unsigned int sda = smi->gpio_sda;
+	unsigned int sck = smi->gpio_sck;
+
+	/*
+	 * Set GPIO pins to output mode, with initial state:
+	 * SCK = 0, SDA = 1
+	 */
+	gpio_direction_output(sck, 0);
+	gpio_direction_output(sda, 1);
+	rtl8366_smi_clk_delay(smi);
+
+	/* CLK 1: 0 -> 1, 1 -> 0 */
+	gpio_set_value(sck, 1);
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sck, 0);
+	rtl8366_smi_clk_delay(smi);
+
+	/* CLK 2: */
+	gpio_set_value(sck, 1);
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sda, 0);
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sck, 0);
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sda, 1);
+}
+
+static void rtl8366_smi_stop(struct rtl8366_smi *smi)
+{
+	unsigned int sda = smi->gpio_sda;
+	unsigned int sck = smi->gpio_sck;
+
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sda, 0);
+	gpio_set_value(sck, 1);
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sda, 1);
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sck, 1);
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sck, 0);
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sck, 1);
+
+	/* add a click */
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sck, 0);
+	rtl8366_smi_clk_delay(smi);
+	gpio_set_value(sck, 1);
+
+	/* set GPIO pins to input mode */
+	gpio_direction_input(sda);
+	gpio_direction_input(sck);
+}
+
+static void rtl8366_smi_write_bits(struct rtl8366_smi *smi, u32 data, u32 len)
+{
+	unsigned int sda = smi->gpio_sda;
+	unsigned int sck = smi->gpio_sck;
+
+	for (; len > 0; len--) {
+		rtl8366_smi_clk_delay(smi);
+
+		/* prepare data */
+		gpio_set_value(sda, !!(data & ( 1 << (len - 1))));
+		rtl8366_smi_clk_delay(smi);
+
+		/* clocking */
+		gpio_set_value(sck, 1);
+		rtl8366_smi_clk_delay(smi);
+		gpio_set_value(sck, 0);
+	}
+}
+
+static void rtl8366_smi_read_bits(struct rtl8366_smi *smi, u32 len, u32 *data)
+{
+	unsigned int sda = smi->gpio_sda;
+	unsigned int sck = smi->gpio_sck;
+
+	gpio_direction_input(sda);
+
+	for (*data = 0; len > 0; len--) {
+		u32 u;
+
+		rtl8366_smi_clk_delay(smi);
+
+		/* clocking */
+		gpio_set_value(sck, 1);
+		rtl8366_smi_clk_delay(smi);
+		u = !!gpio_get_value(sda);
+		gpio_set_value(sck, 0);
+
+		*data |= (u << (len - 1));
+	}
+
+	gpio_direction_output(sda, 0);
+}
+
+static int rtl8366_smi_wait_for_ack(struct rtl8366_smi *smi)
+{
+	int retry_cnt;
+
+	retry_cnt = 0;
+	do {
+		u32 ack;
+
+		rtl8366_smi_read_bits(smi, 1, &ack);
+		if (ack == 0)
+			break;
+
+		if (++retry_cnt > RTL8366_SMI_ACK_RETRY_COUNT) {
+			dev_err(smi->parent, "ACK timeout\n");
+			return -ETIMEDOUT;
+		}
+	} while (1);
+
+	return 0;
+}
+
+static int rtl8366_smi_write_byte(struct rtl8366_smi *smi, u8 data)
+{
+	rtl8366_smi_write_bits(smi, data, 8);
+	return rtl8366_smi_wait_for_ack(smi);
+}
+
+static int rtl8366_smi_write_byte_noack(struct rtl8366_smi *smi, u8 data)
+{
+	rtl8366_smi_write_bits(smi, data, 8);
+	return 0;
+}
+
+static int rtl8366_smi_read_byte0(struct rtl8366_smi *smi, u8 *data)
+{
+	u32 t;
+
+	/* read data */
+	rtl8366_smi_read_bits(smi, 8, &t);
+	*data = (t & 0xff);
+
+	/* send an ACK */
+	rtl8366_smi_write_bits(smi, 0x00, 1);
+
+	return 0;
+}
+
+static int rtl8366_smi_read_byte1(struct rtl8366_smi *smi, u8 *data)
+{
+	u32 t;
+
+	/* read data */
+	rtl8366_smi_read_bits(smi, 8, &t);
+	*data = (t & 0xff);
+
+	/* send an ACK */
+	rtl8366_smi_write_bits(smi, 0x01, 1);
+
+	return 0;
+}
+
+static int __rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data)
+{
+	unsigned long flags;
+	u8 lo = 0;
+	u8 hi = 0;
+	int ret;
+
+	spin_lock_irqsave(&smi->lock, flags);
+
+	rtl8366_smi_start(smi);
+
+	/* send READ command */
+	ret = rtl8366_smi_write_byte(smi, smi->cmd_read);
+	if (ret)
+		goto out;
+
+	/* set ADDR[7:0] */
+	ret = rtl8366_smi_write_byte(smi, addr & 0xff);
+	if (ret)
+		goto out;
+
+	/* set ADDR[15:8] */
+	ret = rtl8366_smi_write_byte(smi, addr >> 8);
+	if (ret)
+		goto out;
+
+	/* read DATA[7:0] */
+	rtl8366_smi_read_byte0(smi, &lo);
+	/* read DATA[15:8] */
+	rtl8366_smi_read_byte1(smi, &hi);
+
+	*data = ((u32) lo) | (((u32) hi) << 8);
+
+	ret = 0;
+
+ out:
+	rtl8366_smi_stop(smi);
+	spin_unlock_irqrestore(&smi->lock, flags);
+
+	return ret;
+}
+/* Read/write via mdiobus */
+#define MDC_MDIO_CTRL0_REG		31
+#define MDC_MDIO_START_REG		29
+#define MDC_MDIO_CTRL1_REG		21
+#define MDC_MDIO_ADDRESS_REG		23
+#define MDC_MDIO_DATA_WRITE_REG		24
+#define MDC_MDIO_DATA_READ_REG		25
+
+#define MDC_MDIO_START_OP		0xFFFF
+#define MDC_MDIO_ADDR_OP		0x000E
+#define MDC_MDIO_READ_OP		0x0001
+#define MDC_MDIO_WRITE_OP		0x0003
+#define MDC_REALTEK_PHY_ADDR		0x0
+
+int __rtl8366_mdio_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data)
+{
+	u32 phy_id = MDC_REALTEK_PHY_ADDR;
+	struct mii_bus *mbus = smi->ext_mbus;
+
+	BUG_ON(in_interrupt());
+
+	mutex_lock(&mbus->mdio_lock);
+	/* Write Start command to register 29 */
+	mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP);
+
+	/* Write address control code to register 31 */
+	mbus->write(mbus, phy_id, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP);
+
+	/* Write Start command to register 29 */
+	mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP);
+
+	/* Write address to register 23 */
+	mbus->write(mbus, phy_id, MDC_MDIO_ADDRESS_REG, addr);
+
+	/* Write Start command to register 29 */
+	mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP);
+
+	/* Write read control code to register 21 */
+	mbus->write(mbus, phy_id, MDC_MDIO_CTRL1_REG, MDC_MDIO_READ_OP);
+
+	/* Write Start command to register 29 */
+	mbus->write(smi->ext_mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP);
+
+	/* Read data from register 25 */
+	*data = mbus->read(mbus, phy_id, MDC_MDIO_DATA_READ_REG);
+
+	mutex_unlock(&mbus->mdio_lock);
+
+	return 0;
+}
+
+static int __rtl8366_mdio_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data)
+{
+	u32 phy_id = MDC_REALTEK_PHY_ADDR;
+	struct mii_bus *mbus = smi->ext_mbus;
+
+	BUG_ON(in_interrupt());
+
+	mutex_lock(&mbus->mdio_lock);
+
+	/* Write Start command to register 29 */
+	mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP);
+
+	/* Write address control code to register 31 */
+	mbus->write(mbus, phy_id, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP);
+
+	/* Write Start command to register 29 */
+	mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP);
+
+	/* Write address to register 23 */
+	mbus->write(mbus, phy_id, MDC_MDIO_ADDRESS_REG, addr);
+
+	/* Write Start command to register 29 */
+	mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP);
+
+	/* Write data to register 24 */
+	mbus->write(mbus, phy_id, MDC_MDIO_DATA_WRITE_REG, data);
+
+	/* Write Start command to register 29 */
+	mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP);
+
+	/* Write data control code to register 21 */
+	mbus->write(mbus, phy_id, MDC_MDIO_CTRL1_REG, MDC_MDIO_WRITE_OP);
+
+	mutex_unlock(&mbus->mdio_lock);
+	return 0;
+}
+
+int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data)
+{
+	if (smi->ext_mbus)
+		return __rtl8366_mdio_read_reg(smi, addr, data);
+	else
+		return __rtl8366_smi_read_reg(smi, addr, data);
+}
+EXPORT_SYMBOL_GPL(rtl8366_smi_read_reg);
+
+static int __rtl8366_smi_write_reg(struct rtl8366_smi *smi,
+				   u32 addr, u32 data, bool ack)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&smi->lock, flags);
+
+	rtl8366_smi_start(smi);
+
+	/* send WRITE command */
+	ret = rtl8366_smi_write_byte(smi, smi->cmd_write);
+	if (ret)
+		goto out;
+
+	/* set ADDR[7:0] */
+	ret = rtl8366_smi_write_byte(smi, addr & 0xff);
+	if (ret)
+		goto out;
+
+	/* set ADDR[15:8] */
+	ret = rtl8366_smi_write_byte(smi, addr >> 8);
+	if (ret)
+		goto out;
+
+	/* write DATA[7:0] */
+	ret = rtl8366_smi_write_byte(smi, data & 0xff);
+	if (ret)
+		goto out;
+
+	/* write DATA[15:8] */
+	if (ack)
+		ret = rtl8366_smi_write_byte(smi, data >> 8);
+	else
+		ret = rtl8366_smi_write_byte_noack(smi, data >> 8);
+	if (ret)
+		goto out;
+
+	ret = 0;
+
+ out:
+	rtl8366_smi_stop(smi);
+	spin_unlock_irqrestore(&smi->lock, flags);
+
+	return ret;
+}
+
+int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data)
+{
+	if (smi->ext_mbus)
+		return __rtl8366_mdio_write_reg(smi, addr, data);
+	else
+		return __rtl8366_smi_write_reg(smi, addr, data, true);
+}
+EXPORT_SYMBOL_GPL(rtl8366_smi_write_reg);
+
+int rtl8366_smi_write_reg_noack(struct rtl8366_smi *smi, u32 addr, u32 data)
+{
+	return __rtl8366_smi_write_reg(smi, addr, data, false);
+}
+EXPORT_SYMBOL_GPL(rtl8366_smi_write_reg_noack);
+
+int rtl8366_smi_rmwr(struct rtl8366_smi *smi, u32 addr, u32 mask, u32 data)
+{
+	u32 t;
+	int err;
+
+	err = rtl8366_smi_read_reg(smi, addr, &t);
+	if (err)
+		return err;
+
+	err = rtl8366_smi_write_reg(smi, addr, (t & ~mask) | data);
+	return err;
+
+}
+EXPORT_SYMBOL_GPL(rtl8366_smi_rmwr);
+
+static int rtl8366_reset(struct rtl8366_smi *smi)
+{
+	if (smi->hw_reset) {
+		smi->hw_reset(smi, true);
+		msleep(RTL8366_SMI_HW_STOP_DELAY);
+		smi->hw_reset(smi, false);
+		msleep(RTL8366_SMI_HW_START_DELAY);
+		return 0;
+	}
+
+	return smi->ops->reset_chip(smi);
+}
+
+static int rtl8366_mc_is_used(struct rtl8366_smi *smi, int mc_index, int *used)
+{
+	int err;
+	int i;
+
+	*used = 0;
+	for (i = 0; i < smi->num_ports; i++) {
+		int index = 0;
+
+		err = smi->ops->get_mc_index(smi, i, &index);
+		if (err)
+			return err;
+
+		if (mc_index == index) {
+			*used = 1;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int rtl8366_set_vlan(struct rtl8366_smi *smi, int vid, u32 member,
+			    u32 untag, u32 fid)
+{
+	struct rtl8366_vlan_4k vlan4k;
+	int err;
+	int i;
+
+	/* Update the 4K table */
+	err = smi->ops->get_vlan_4k(smi, vid, &vlan4k);
+	if (err)
+		return err;
+
+	vlan4k.member = member;
+	vlan4k.untag = untag;
+	vlan4k.fid = fid;
+	err = smi->ops->set_vlan_4k(smi, &vlan4k);
+	if (err)
+		return err;
+
+	/* Try to find an existing MC entry for this VID */
+	for (i = 0; i < smi->num_vlan_mc; i++) {
+		struct rtl8366_vlan_mc vlanmc;
+
+		err = smi->ops->get_vlan_mc(smi, i, &vlanmc);
+		if (err)
+			return err;
+
+		if (vid == vlanmc.vid) {
+			/* update the MC entry */
+			vlanmc.member = member;
+			vlanmc.untag = untag;
+			vlanmc.fid = fid;
+
+			err = smi->ops->set_vlan_mc(smi, i, &vlanmc);
+			break;
+		}
+	}
+
+	return err;
+}
+
+static int rtl8366_get_pvid(struct rtl8366_smi *smi, int port, int *val)
+{
+	struct rtl8366_vlan_mc vlanmc;
+	int err;
+	int index;
+
+	err = smi->ops->get_mc_index(smi, port, &index);
+	if (err)
+		return err;
+
+	err = smi->ops->get_vlan_mc(smi, index, &vlanmc);
+	if (err)
+		return err;
+
+	*val = vlanmc.vid;
+	return 0;
+}
+
+static int rtl8366_set_pvid(struct rtl8366_smi *smi, unsigned port,
+			    unsigned vid)
+{
+	struct rtl8366_vlan_mc vlanmc;
+	struct rtl8366_vlan_4k vlan4k;
+	int err;
+	int i;
+
+	/* Try to find an existing MC entry for this VID */
+	for (i = 0; i < smi->num_vlan_mc; i++) {
+		err = smi->ops->get_vlan_mc(smi, i, &vlanmc);
+		if (err)
+			return err;
+
+		if (vid == vlanmc.vid) {
+			err = smi->ops->set_vlan_mc(smi, i, &vlanmc);
+			if (err)
+				return err;
+
+			err = smi->ops->set_mc_index(smi, port, i);
+			return err;
+		}
+	}
+
+	/* We have no MC entry for this VID, try to find an empty one */
+	for (i = 0; i < smi->num_vlan_mc; i++) {
+		err = smi->ops->get_vlan_mc(smi, i, &vlanmc);
+		if (err)
+			return err;
+
+		if (vlanmc.vid == 0 && vlanmc.member == 0) {
+			/* Update the entry from the 4K table */
+			err = smi->ops->get_vlan_4k(smi, vid, &vlan4k);
+			if (err)
+				return err;
+
+			vlanmc.vid = vid;
+			vlanmc.member = vlan4k.member;
+			vlanmc.untag = vlan4k.untag;
+			vlanmc.fid = vlan4k.fid;
+			err = smi->ops->set_vlan_mc(smi, i, &vlanmc);
+			if (err)
+				return err;
+
+			err = smi->ops->set_mc_index(smi, port, i);
+			return err;
+		}
+	}
+
+	/* MC table is full, try to find an unused entry and replace it */
+	for (i = 0; i < smi->num_vlan_mc; i++) {
+		int used;
+
+		err = rtl8366_mc_is_used(smi, i, &used);
+		if (err)
+			return err;
+
+		if (!used) {
+			/* Update the entry from the 4K table */
+			err = smi->ops->get_vlan_4k(smi, vid, &vlan4k);
+			if (err)
+				return err;
+
+			vlanmc.vid = vid;
+			vlanmc.member = vlan4k.member;
+			vlanmc.untag = vlan4k.untag;
+			vlanmc.fid = vlan4k.fid;
+			err = smi->ops->set_vlan_mc(smi, i, &vlanmc);
+			if (err)
+				return err;
+
+			err = smi->ops->set_mc_index(smi, port, i);
+			return err;
+		}
+	}
+
+	dev_err(smi->parent,
+		"all VLAN member configurations are in use\n");
+
+	return -ENOSPC;
+}
+
+int rtl8366_enable_vlan(struct rtl8366_smi *smi, int enable)
+{
+	int err;
+
+	err = smi->ops->enable_vlan(smi, enable);
+	if (err)
+		return err;
+
+	smi->vlan_enabled = enable;
+
+	if (!enable) {
+		smi->vlan4k_enabled = 0;
+		err = smi->ops->enable_vlan4k(smi, enable);
+	}
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(rtl8366_enable_vlan);
+
+static int rtl8366_enable_vlan4k(struct rtl8366_smi *smi, int enable)
+{
+	int err;
+
+	if (enable) {
+		err = smi->ops->enable_vlan(smi, enable);
+		if (err)
+			return err;
+
+		smi->vlan_enabled = enable;
+	}
+
+	err = smi->ops->enable_vlan4k(smi, enable);
+	if (err)
+		return err;
+
+	smi->vlan4k_enabled = enable;
+	return 0;
+}
+
+int rtl8366_enable_all_ports(struct rtl8366_smi *smi, int enable)
+{
+	int port;
+	int err;
+
+	for (port = 0; port < smi->num_ports; port++) {
+		err = smi->ops->enable_port(smi, port, enable);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtl8366_enable_all_ports);
+
+int rtl8366_reset_vlan(struct rtl8366_smi *smi)
+{
+	struct rtl8366_vlan_mc vlanmc;
+	int err;
+	int i;
+
+	rtl8366_enable_vlan(smi, 0);
+	rtl8366_enable_vlan4k(smi, 0);
+
+	/* clear VLAN member configurations */
+	vlanmc.vid = 0;
+	vlanmc.priority = 0;
+	vlanmc.member = 0;
+	vlanmc.untag = 0;
+	vlanmc.fid = 0;
+	for (i = 0; i < smi->num_vlan_mc; i++) {
+		err = smi->ops->set_vlan_mc(smi, i, &vlanmc);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtl8366_reset_vlan);
+
+static int rtl8366_init_vlan(struct rtl8366_smi *smi)
+{
+	int port;
+	int err;
+
+	err = rtl8366_reset_vlan(smi);
+	if (err)
+		return err;
+
+	for (port = 0; port < smi->num_ports; port++) {
+		u32 mask;
+
+		if (port == smi->cpu_port)
+			mask = (1 << smi->num_ports) - 1;
+		else
+			mask = (1 << port) | (1 << smi->cpu_port);
+
+		err = rtl8366_set_vlan(smi, (port + 1), mask, mask, 0);
+		if (err)
+			return err;
+
+		err = rtl8366_set_pvid(smi, port, (port + 1));
+		if (err)
+			return err;
+	}
+
+	return rtl8366_enable_vlan(smi, 1);
+}
+
+#ifdef CONFIG_RTL8366_SMI_DEBUG_FS
+int rtl8366_debugfs_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtl8366_debugfs_open);
+
+static ssize_t rtl8366_read_debugfs_vlan_mc(struct file *file,
+					      char __user *user_buf,
+					      size_t count, loff_t *ppos)
+{
+	struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data;
+	int i, len = 0;
+	char *buf = smi->buf;
+
+	len += snprintf(buf + len, sizeof(smi->buf) - len,
+			"%2s %6s %4s %6s %6s %3s\n",
+			"id", "vid","prio", "member", "untag", "fid");
+
+	for (i = 0; i < smi->num_vlan_mc; ++i) {
+		struct rtl8366_vlan_mc vlanmc;
+
+		smi->ops->get_vlan_mc(smi, i, &vlanmc);
+
+		len += snprintf(buf + len, sizeof(smi->buf) - len,
+				"%2d %6d %4d 0x%04x 0x%04x %3d\n",
+				i, vlanmc.vid, vlanmc.priority,
+				vlanmc.member, vlanmc.untag, vlanmc.fid);
+	}
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+#define RTL8366_VLAN4K_PAGE_SIZE	64
+#define RTL8366_VLAN4K_NUM_PAGES	(4096 / RTL8366_VLAN4K_PAGE_SIZE)
+
+static ssize_t rtl8366_read_debugfs_vlan_4k(struct file *file,
+					    char __user *user_buf,
+					    size_t count, loff_t *ppos)
+{
+	struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data;
+	int i, len = 0;
+	int offset;
+	char *buf = smi->buf;
+
+	if (smi->dbg_vlan_4k_page >= RTL8366_VLAN4K_NUM_PAGES) {
+		len += snprintf(buf + len, sizeof(smi->buf) - len,
+				"invalid page: %u\n", smi->dbg_vlan_4k_page);
+		return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	}
+
+	len += snprintf(buf + len, sizeof(smi->buf) - len,
+			"%4s %6s %6s %3s\n",
+			"vid", "member", "untag", "fid");
+
+	offset = RTL8366_VLAN4K_PAGE_SIZE * smi->dbg_vlan_4k_page;
+	for (i = 0; i < RTL8366_VLAN4K_PAGE_SIZE; i++) {
+		struct rtl8366_vlan_4k vlan4k;
+
+		smi->ops->get_vlan_4k(smi, offset + i, &vlan4k);
+
+		len += snprintf(buf + len, sizeof(smi->buf) - len,
+				"%4d 0x%04x 0x%04x %3d\n",
+				vlan4k.vid, vlan4k.member,
+				vlan4k.untag, vlan4k.fid);
+	}
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t rtl8366_read_debugfs_pvid(struct file *file,
+					 char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data;
+	char *buf = smi->buf;
+	int len = 0;
+	int i;
+
+	len += snprintf(buf + len, sizeof(smi->buf) - len, "%4s %4s\n",
+			"port", "pvid");
+
+	for (i = 0; i < smi->num_ports; i++) {
+		int pvid;
+		int err;
+
+		err = rtl8366_get_pvid(smi, i, &pvid);
+		if (err)
+			len += snprintf(buf + len, sizeof(smi->buf) - len,
+				"%4d error\n", i);
+		else
+			len += snprintf(buf + len, sizeof(smi->buf) - len,
+				"%4d %4d\n", i, pvid);
+	}
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t rtl8366_read_debugfs_reg(struct file *file,
+					 char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data;
+	u32 t, reg = smi->dbg_reg;
+	int err, len = 0;
+	char *buf = smi->buf;
+
+	memset(buf, '\0', sizeof(smi->buf));
+
+	err = rtl8366_smi_read_reg(smi, reg, &t);
+	if (err) {
+		len += snprintf(buf, sizeof(smi->buf),
+				"Read failed (reg: 0x%04x)\n", reg);
+		return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+	}
+
+	len += snprintf(buf, sizeof(smi->buf), "reg = 0x%04x, val = 0x%04x\n",
+			reg, t);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t rtl8366_write_debugfs_reg(struct file *file,
+					  const char __user *user_buf,
+					  size_t count, loff_t *ppos)
+{
+	struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data;
+	unsigned long data;
+	u32 reg = smi->dbg_reg;
+	int err;
+	size_t len;
+	char *buf = smi->buf;
+
+	len = min(count, sizeof(smi->buf) - 1);
+	if (copy_from_user(buf, user_buf, len)) {
+		dev_err(smi->parent, "copy from user failed\n");
+		return -EFAULT;
+	}
+
+	buf[len] = '\0';
+	if (len > 0 && buf[len - 1] == '\n')
+		buf[len - 1] = '\0';
+
+
+	if (kstrtoul(buf, 16, &data)) {
+		dev_err(smi->parent, "Invalid reg value %s\n", buf);
+	} else {
+		err = rtl8366_smi_write_reg(smi, reg, data);
+		if (err) {
+			dev_err(smi->parent,
+				"writing reg 0x%04x val 0x%04lx failed\n",
+				reg, data);
+		}
+	}
+
+	return count;
+}
+
+static ssize_t rtl8366_read_debugfs_mibs(struct file *file,
+					 char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	struct rtl8366_smi *smi = file->private_data;
+	int i, j, len = 0;
+	char *buf = smi->buf;
+
+	len += snprintf(buf + len, sizeof(smi->buf) - len, "%-36s",
+			"Counter");
+
+	for (i = 0; i < smi->num_ports; i++) {
+		char port_buf[10];
+
+		snprintf(port_buf, sizeof(port_buf), "Port %d", i);
+		len += snprintf(buf + len, sizeof(smi->buf) - len, " %12s",
+				port_buf);
+	}
+	len += snprintf(buf + len, sizeof(smi->buf) - len, "\n");
+
+	for (i = 0; i < smi->num_mib_counters; i++) {
+		len += snprintf(buf + len, sizeof(smi->buf) - len, "%-36s ",
+				smi->mib_counters[i].name);
+		for (j = 0; j < smi->num_ports; j++) {
+			unsigned long long counter = 0;
+
+			if (!smi->ops->get_mib_counter(smi, i, j, &counter))
+				len += snprintf(buf + len,
+						sizeof(smi->buf) - len,
+						"%12llu ", counter);
+			else
+				len += snprintf(buf + len,
+						sizeof(smi->buf) - len,
+						"%12s ", "error");
+		}
+		len += snprintf(buf + len, sizeof(smi->buf) - len, "\n");
+	}
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_rtl8366_regs = {
+	.read	= rtl8366_read_debugfs_reg,
+	.write	= rtl8366_write_debugfs_reg,
+	.open	= rtl8366_debugfs_open,
+	.owner	= THIS_MODULE
+};
+
+static const struct file_operations fops_rtl8366_vlan_mc = {
+	.read	= rtl8366_read_debugfs_vlan_mc,
+	.open	= rtl8366_debugfs_open,
+	.owner	= THIS_MODULE
+};
+
+static const struct file_operations fops_rtl8366_vlan_4k = {
+	.read	= rtl8366_read_debugfs_vlan_4k,
+	.open	= rtl8366_debugfs_open,
+	.owner	= THIS_MODULE
+};
+
+static const struct file_operations fops_rtl8366_pvid = {
+	.read	= rtl8366_read_debugfs_pvid,
+	.open	= rtl8366_debugfs_open,
+	.owner	= THIS_MODULE
+};
+
+static const struct file_operations fops_rtl8366_mibs = {
+	.read = rtl8366_read_debugfs_mibs,
+	.open = rtl8366_debugfs_open,
+	.owner = THIS_MODULE
+};
+
+static void rtl8366_debugfs_init(struct rtl8366_smi *smi)
+{
+	struct dentry *node;
+	struct dentry *root;
+
+	if (!smi->debugfs_root)
+		smi->debugfs_root = debugfs_create_dir(dev_name(smi->parent),
+						       NULL);
+
+	if (!smi->debugfs_root) {
+		dev_err(smi->parent, "Unable to create debugfs dir\n");
+		return;
+	}
+	root = smi->debugfs_root;
+
+	node = debugfs_create_x16("reg", S_IRUGO | S_IWUSR, root,
+				  &smi->dbg_reg);
+	if (!node) {
+		dev_err(smi->parent, "Creating debugfs file '%s' failed\n",
+			"reg");
+		return;
+	}
+
+	node = debugfs_create_file("val", S_IRUGO | S_IWUSR, root, smi,
+				   &fops_rtl8366_regs);
+	if (!node) {
+		dev_err(smi->parent, "Creating debugfs file '%s' failed\n",
+			"val");
+		return;
+	}
+
+	node = debugfs_create_file("vlan_mc", S_IRUSR, root, smi,
+				   &fops_rtl8366_vlan_mc);
+	if (!node) {
+		dev_err(smi->parent, "Creating debugfs file '%s' failed\n",
+			"vlan_mc");
+		return;
+	}
+
+	node = debugfs_create_u8("vlan_4k_page", S_IRUGO | S_IWUSR, root,
+				  &smi->dbg_vlan_4k_page);
+	if (!node) {
+		dev_err(smi->parent, "Creating debugfs file '%s' failed\n",
+			"vlan_4k_page");
+		return;
+	}
+
+	node = debugfs_create_file("vlan_4k", S_IRUSR, root, smi,
+				   &fops_rtl8366_vlan_4k);
+	if (!node) {
+		dev_err(smi->parent, "Creating debugfs file '%s' failed\n",
+			"vlan_4k");
+		return;
+	}
+
+	node = debugfs_create_file("pvid", S_IRUSR, root, smi,
+				   &fops_rtl8366_pvid);
+	if (!node) {
+		dev_err(smi->parent, "Creating debugfs file '%s' failed\n",
+			"pvid");
+		return;
+	}
+
+	node = debugfs_create_file("mibs", S_IRUSR, smi->debugfs_root, smi,
+				   &fops_rtl8366_mibs);
+	if (!node)
+		dev_err(smi->parent, "Creating debugfs file '%s' failed\n",
+			"mibs");
+}
+
+static void rtl8366_debugfs_remove(struct rtl8366_smi *smi)
+{
+	if (smi->debugfs_root) {
+		debugfs_remove_recursive(smi->debugfs_root);
+		smi->debugfs_root = NULL;
+	}
+}
+#else
+static inline void rtl8366_debugfs_init(struct rtl8366_smi *smi) {}
+static inline void rtl8366_debugfs_remove(struct rtl8366_smi *smi) {}
+#endif /* CONFIG_RTL8366_SMI_DEBUG_FS */
+
+static int rtl8366_smi_mii_init(struct rtl8366_smi *smi)
+{
+	int ret;
+
+#ifdef CONFIG_OF
+	struct device_node *np = NULL;
+
+	np = of_get_child_by_name(smi->parent->of_node, "mdio-bus");
+#endif
+
+	smi->mii_bus = mdiobus_alloc();
+	if (smi->mii_bus == NULL) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	smi->mii_bus->priv = (void *) smi;
+	smi->mii_bus->name = dev_name(smi->parent);
+	smi->mii_bus->read = smi->ops->mii_read;
+	smi->mii_bus->write = smi->ops->mii_write;
+	snprintf(smi->mii_bus->id, MII_BUS_ID_SIZE, "%s",
+		 dev_name(smi->parent));
+	smi->mii_bus->parent = smi->parent;
+	smi->mii_bus->phy_mask = ~(0x1f);
+
+#ifdef CONFIG_OF
+	if (np)
+		ret = of_mdiobus_register(smi->mii_bus, np);
+	else
+#endif
+		ret = mdiobus_register(smi->mii_bus);
+
+	if (ret)
+		goto err_free;
+
+	return 0;
+
+ err_free:
+	mdiobus_free(smi->mii_bus);
+ err:
+	return ret;
+}
+
+static void rtl8366_smi_mii_cleanup(struct rtl8366_smi *smi)
+{
+	mdiobus_unregister(smi->mii_bus);
+	mdiobus_free(smi->mii_bus);
+}
+
+int rtl8366_sw_reset_switch(struct switch_dev *dev)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	int err;
+
+	err = rtl8366_reset(smi);
+	if (err)
+		return err;
+
+	err = smi->ops->setup(smi);
+	if (err)
+		return err;
+
+	err = rtl8366_reset_vlan(smi);
+	if (err)
+		return err;
+
+	err = rtl8366_enable_vlan(smi, 1);
+	if (err)
+		return err;
+
+	return rtl8366_enable_all_ports(smi, 1);
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_reset_switch);
+
+int rtl8366_sw_get_port_pvid(struct switch_dev *dev, int port, int *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	return rtl8366_get_pvid(smi, port, val);
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_get_port_pvid);
+
+int rtl8366_sw_set_port_pvid(struct switch_dev *dev, int port, int val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	return rtl8366_set_pvid(smi, port, val);
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_set_port_pvid);
+
+int rtl8366_sw_get_port_mib(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	int i, len = 0;
+	unsigned long long counter = 0;
+	char *buf = smi->buf;
+
+	if (val->port_vlan >= smi->num_ports)
+		return -EINVAL;
+
+	len += snprintf(buf + len, sizeof(smi->buf) - len,
+			"Port %d MIB counters\n",
+			val->port_vlan);
+
+	for (i = 0; i < smi->num_mib_counters; ++i) {
+		len += snprintf(buf + len, sizeof(smi->buf) - len,
+				"%-36s: ", smi->mib_counters[i].name);
+		if (!smi->ops->get_mib_counter(smi, i, val->port_vlan,
+					       &counter))
+			len += snprintf(buf + len, sizeof(smi->buf) - len,
+					"%llu\n", counter);
+		else
+			len += snprintf(buf + len, sizeof(smi->buf) - len,
+					"%s\n", "error");
+	}
+
+	val->value.s = buf;
+	val->len = len;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_get_port_mib);
+
+int rtl8366_sw_get_port_stats(struct switch_dev *dev, int port,
+				struct switch_port_stats *stats,
+				int txb_id, int rxb_id)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	unsigned long long counter = 0;
+	int ret;
+
+	if (port >= smi->num_ports)
+		return -EINVAL;
+
+	ret = smi->ops->get_mib_counter(smi, txb_id, port, &counter);
+	if (ret)
+		return ret;
+
+	stats->tx_bytes = counter;
+
+	ret = smi->ops->get_mib_counter(smi, rxb_id, port, &counter);
+	if (ret)
+		return ret;
+
+	stats->rx_bytes = counter;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_get_port_stats);
+
+int rtl8366_sw_get_vlan_info(struct switch_dev *dev,
+			     const struct switch_attr *attr,
+			     struct switch_val *val)
+{
+	int i;
+	u32 len = 0;
+	struct rtl8366_vlan_4k vlan4k;
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	char *buf = smi->buf;
+	int err;
+
+	if (!smi->ops->is_vlan_valid(smi, val->port_vlan))
+		return -EINVAL;
+
+	memset(buf, '\0', sizeof(smi->buf));
+
+	err = smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k);
+	if (err)
+		return err;
+
+	len += snprintf(buf + len, sizeof(smi->buf) - len,
+			"VLAN %d: Ports: '", vlan4k.vid);
+
+	for (i = 0; i < smi->num_ports; i++) {
+		if (!(vlan4k.member & (1 << i)))
+			continue;
+
+		len += snprintf(buf + len, sizeof(smi->buf) - len, "%d%s", i,
+				(vlan4k.untag & (1 << i)) ? "" : "t");
+	}
+
+	len += snprintf(buf + len, sizeof(smi->buf) - len,
+			"', members=%04x, untag=%04x, fid=%u",
+			vlan4k.member, vlan4k.untag, vlan4k.fid);
+
+	val->value.s = buf;
+	val->len = len;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_info);
+
+int rtl8366_sw_get_vlan_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	struct switch_port *port;
+	struct rtl8366_vlan_4k vlan4k;
+	int i;
+
+	if (!smi->ops->is_vlan_valid(smi, val->port_vlan))
+		return -EINVAL;
+
+	smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k);
+
+	port = &val->value.ports[0];
+	val->len = 0;
+	for (i = 0; i < smi->num_ports; i++) {
+		if (!(vlan4k.member & BIT(i)))
+			continue;
+
+		port->id = i;
+		port->flags = (vlan4k.untag & BIT(i)) ?
+					0 : BIT(SWITCH_PORT_FLAG_TAGGED);
+		val->len++;
+		port++;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_ports);
+
+int rtl8366_sw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	struct switch_port *port;
+	u32 member = 0;
+	u32 untag = 0;
+	int err;
+	int i;
+
+	if (!smi->ops->is_vlan_valid(smi, val->port_vlan))
+		return -EINVAL;
+
+	port = &val->value.ports[0];
+	for (i = 0; i < val->len; i++, port++) {
+		int pvid = 0;
+		member |= BIT(port->id);
+
+		if (!(port->flags & BIT(SWITCH_PORT_FLAG_TAGGED)))
+			untag |= BIT(port->id);
+
+		/*
+		 * To ensure that we have a valid MC entry for this VLAN,
+		 * initialize the port VLAN ID here.
+		 */
+		err = rtl8366_get_pvid(smi, port->id, &pvid);
+		if (err < 0)
+			return err;
+		if (pvid == 0) {
+			err = rtl8366_set_pvid(smi, port->id, val->port_vlan);
+			if (err < 0)
+				return err;
+		}
+	}
+
+	return rtl8366_set_vlan(smi, val->port_vlan, member, untag, 0);
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_set_vlan_ports);
+
+int rtl8366_sw_get_vlan_fid(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct rtl8366_vlan_4k vlan4k;
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	int err;
+
+	if (!smi->ops->is_vlan_valid(smi, val->port_vlan))
+		return -EINVAL;
+
+	err = smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k);
+	if (err)
+		return err;
+
+	val->value.i = vlan4k.fid;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_fid);
+
+int rtl8366_sw_set_vlan_fid(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct rtl8366_vlan_4k vlan4k;
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	int err;
+
+	if (!smi->ops->is_vlan_valid(smi, val->port_vlan))
+		return -EINVAL;
+
+	if (val->value.i < 0 || val->value.i > attr->max)
+		return -EINVAL;
+
+	err = smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k);
+	if (err)
+		return err;
+
+	return rtl8366_set_vlan(smi, val->port_vlan,
+				vlan4k.member,
+				vlan4k.untag,
+				val->value.i);
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_set_vlan_fid);
+
+int rtl8366_sw_get_vlan_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	if (attr->ofs > 2)
+		return -EINVAL;
+
+	if (attr->ofs == 1)
+		val->value.i = smi->vlan_enabled;
+	else
+		val->value.i = smi->vlan4k_enabled;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_enable);
+
+int rtl8366_sw_set_vlan_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	int err;
+
+	if (attr->ofs > 2)
+		return -EINVAL;
+
+	if (attr->ofs == 1)
+		err = rtl8366_enable_vlan(smi, val->value.i);
+	else
+		err = rtl8366_enable_vlan4k(smi, val->value.i);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(rtl8366_sw_set_vlan_enable);
+
+struct rtl8366_smi *rtl8366_smi_alloc(struct device *parent)
+{
+	struct rtl8366_smi *smi;
+
+	BUG_ON(!parent);
+
+	smi = kzalloc(sizeof(*smi), GFP_KERNEL);
+	if (!smi) {
+		dev_err(parent, "no memory for private data\n");
+		return NULL;
+	}
+
+	smi->parent = parent;
+	return smi;
+}
+EXPORT_SYMBOL_GPL(rtl8366_smi_alloc);
+
+static int __rtl8366_smi_init(struct rtl8366_smi *smi, const char *name)
+{
+	int err;
+
+	if (!smi->ext_mbus) {
+		err = gpio_request(smi->gpio_sda, name);
+		if (err) {
+			printk(KERN_ERR "rtl8366_smi: gpio_request failed for %u, err=%d\n",
+				smi->gpio_sda, err);
+			goto err_out;
+		}
+
+		err = gpio_request(smi->gpio_sck, name);
+		if (err) {
+			printk(KERN_ERR "rtl8366_smi: gpio_request failed for %u, err=%d\n",
+				smi->gpio_sck, err);
+			goto err_free_sda;
+		}
+	}
+
+	spin_lock_init(&smi->lock);
+
+	/* start the switch */
+	if (smi->hw_reset) {
+		smi->hw_reset(smi, false);
+		msleep(RTL8366_SMI_HW_START_DELAY);
+	}
+
+	return 0;
+
+ err_free_sda:
+	gpio_free(smi->gpio_sda);
+ err_out:
+	return err;
+}
+
+static void __rtl8366_smi_cleanup(struct rtl8366_smi *smi)
+{
+	if (smi->hw_reset)
+		smi->hw_reset(smi, true);
+
+	if (!smi->ext_mbus) {
+		gpio_free(smi->gpio_sck);
+		gpio_free(smi->gpio_sda);
+	}
+}
+
+enum rtl8366_type rtl8366_smi_detect(struct rtl8366_platform_data *pdata)
+{
+	static struct rtl8366_smi smi;
+	enum rtl8366_type type = RTL8366_TYPE_UNKNOWN;
+	u32 reg = 0;
+
+	memset(&smi, 0, sizeof(smi));
+	smi.gpio_sda = pdata->gpio_sda;
+	smi.gpio_sck = pdata->gpio_sck;
+	smi.clk_delay = 10;
+	smi.cmd_read  = 0xa9;
+	smi.cmd_write = 0xa8;
+
+	if (__rtl8366_smi_init(&smi, "rtl8366"))
+		goto out;
+
+	if (rtl8366_smi_read_reg(&smi, 0x5c, &reg))
+		goto cleanup;
+
+	switch(reg) {
+	case 0x6027:
+		printk("Found an RTL8366S switch\n");
+		type = RTL8366_TYPE_S;
+		break;
+	case 0x5937:
+		printk("Found an RTL8366RB switch\n");
+		type = RTL8366_TYPE_RB;
+		break;
+	default:
+		printk("Found an Unknown RTL8366 switch (id=0x%04x)\n", reg);
+		break;
+	}
+
+cleanup:
+	__rtl8366_smi_cleanup(&smi);
+out:
+	return type;
+}
+
+int rtl8366_smi_init(struct rtl8366_smi *smi)
+{
+	int err;
+
+	if (!smi->ops)
+		return -EINVAL;
+
+	err = __rtl8366_smi_init(smi, dev_name(smi->parent));
+	if (err)
+		goto err_out;
+
+	if (!smi->ext_mbus)
+		dev_info(smi->parent, "using GPIO pins %u (SDA) and %u (SCK)\n",
+			 smi->gpio_sda, smi->gpio_sck);
+	else
+		dev_info(smi->parent, "using MDIO bus '%s'\n", smi->ext_mbus->name);
+
+	err = smi->ops->detect(smi);
+	if (err) {
+		dev_err(smi->parent, "chip detection failed, err=%d\n", err);
+		goto err_free_sck;
+	}
+
+	err = rtl8366_reset(smi);
+	if (err)
+		goto err_free_sck;
+
+	err = smi->ops->setup(smi);
+	if (err) {
+		dev_err(smi->parent, "chip setup failed, err=%d\n", err);
+		goto err_free_sck;
+	}
+
+	err = rtl8366_init_vlan(smi);
+	if (err) {
+		dev_err(smi->parent, "VLAN initialization failed, err=%d\n",
+			err);
+		goto err_free_sck;
+	}
+
+	err = rtl8366_enable_all_ports(smi, 1);
+	if (err)
+		goto err_free_sck;
+
+	err = rtl8366_smi_mii_init(smi);
+	if (err)
+		goto err_free_sck;
+
+	rtl8366_debugfs_init(smi);
+
+	return 0;
+
+ err_free_sck:
+	__rtl8366_smi_cleanup(smi);
+ err_out:
+	return err;
+}
+EXPORT_SYMBOL_GPL(rtl8366_smi_init);
+
+void rtl8366_smi_cleanup(struct rtl8366_smi *smi)
+{
+	rtl8366_debugfs_remove(smi);
+	rtl8366_smi_mii_cleanup(smi);
+	__rtl8366_smi_cleanup(smi);
+}
+EXPORT_SYMBOL_GPL(rtl8366_smi_cleanup);
+
+#ifdef CONFIG_OF
+static void rtl8366_smi_reset(struct rtl8366_smi *smi, bool active)
+{
+	if (active)
+		reset_control_assert(smi->reset);
+	else
+		reset_control_deassert(smi->reset);
+}
+
+int rtl8366_smi_probe_of(struct platform_device *pdev, struct rtl8366_smi *smi)
+{
+	int sck = of_get_named_gpio(pdev->dev.of_node, "gpio-sck", 0);
+	int sda = of_get_named_gpio(pdev->dev.of_node, "gpio-sda", 0);
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *mdio_node;
+
+	mdio_node = of_parse_phandle(np, "mii-bus", 0);
+	if (!mdio_node) {
+		dev_err(&pdev->dev, "cannot find mdio node phandle");
+		goto try_gpio;
+	}
+
+	smi->ext_mbus = of_mdio_find_bus(mdio_node);
+	if (!smi->ext_mbus) {
+		dev_info(&pdev->dev,
+			"cannot find mdio bus from bus handle (yet)");
+		goto try_gpio;
+	}
+
+	return 0;
+
+try_gpio:
+	if (!gpio_is_valid(sck) || !gpio_is_valid(sda)) {
+		if (!mdio_node) {
+			dev_err(&pdev->dev, "gpios missing in devictree\n");
+			return -EINVAL;
+		} else {
+			return -EPROBE_DEFER;
+		}
+	}
+
+	smi->gpio_sda = sda;
+	smi->gpio_sck = sck;
+	smi->reset = devm_reset_control_get(&pdev->dev, "switch");
+	if (!IS_ERR(smi->reset))
+		smi->hw_reset = rtl8366_smi_reset;
+
+	return 0;
+}
+#else
+static inline int rtl8366_smi_probe_of(struct platform_device *pdev, struct rtl8366_smi *smi)
+{
+	return -ENODEV;
+}
+#endif
+
+int rtl8366_smi_probe_plat(struct platform_device *pdev, struct rtl8366_smi *smi)
+{
+	struct rtl8366_platform_data *pdata = pdev->dev.platform_data;
+
+	if (!pdev->dev.platform_data) {
+		dev_err(&pdev->dev, "no platform data specified\n");
+		return -EINVAL;
+	}
+
+	smi->gpio_sda = pdata->gpio_sda;
+	smi->gpio_sck = pdata->gpio_sck;
+	smi->hw_reset = pdata->hw_reset;
+
+	return 0;
+}
+
+
+struct rtl8366_smi *rtl8366_smi_probe(struct platform_device *pdev)
+{
+	struct rtl8366_smi *smi;
+	int err;
+
+	smi = rtl8366_smi_alloc(&pdev->dev);
+	if (!smi)
+		return NULL;
+
+	if (pdev->dev.of_node)
+		err = rtl8366_smi_probe_of(pdev, smi);
+	else
+		err = rtl8366_smi_probe_plat(pdev, smi);
+
+	if (err)
+		goto free_smi;
+
+	return smi;
+
+free_smi:
+	kfree(smi);
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(rtl8366_smi_probe);
+
+MODULE_DESCRIPTION("Realtek RTL8366 SMI interface driver");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/rtl8366_smi.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/rtl8366_smi.h
new file mode 100644
index 0000000..d1d988a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/rtl8366_smi.h
@@ -0,0 +1,160 @@
+/*
+ * Realtek RTL8366 SMI interface driver defines
+ *
+ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef _RTL8366_SMI_H
+#define _RTL8366_SMI_H
+
+#include <linux/phy.h>
+#include <linux/switch.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+struct rtl8366_smi_ops;
+struct rtl8366_vlan_ops;
+struct mii_bus;
+struct dentry;
+struct inode;
+struct file;
+
+struct rtl8366_mib_counter {
+	unsigned	base;
+	unsigned	offset;
+	unsigned	length;
+	const char	*name;
+};
+
+struct rtl8366_smi {
+	struct device		*parent;
+	unsigned int		gpio_sda;
+	unsigned int		gpio_sck;
+	void			(*hw_reset)(struct rtl8366_smi *smi, bool active);
+	unsigned int		clk_delay;	/* ns */
+	u8			cmd_read;
+	u8			cmd_write;
+	spinlock_t		lock;
+	struct mii_bus		*mii_bus;
+	int			mii_irq[PHY_MAX_ADDR];
+	struct switch_dev	sw_dev;
+
+	unsigned int		cpu_port;
+	unsigned int		num_ports;
+	unsigned int		num_vlan_mc;
+	unsigned int		num_mib_counters;
+	struct rtl8366_mib_counter *mib_counters;
+
+	struct rtl8366_smi_ops	*ops;
+
+	int			vlan_enabled;
+	int			vlan4k_enabled;
+
+	char			buf[4096];
+
+	struct reset_control	*reset;
+
+#ifdef CONFIG_RTL8366_SMI_DEBUG_FS
+	struct dentry           *debugfs_root;
+	u16			dbg_reg;
+	u8			dbg_vlan_4k_page;
+#endif
+	struct mii_bus		*ext_mbus;
+};
+
+struct rtl8366_vlan_mc {
+	u16	vid;
+	u16	untag;
+	u16	member;
+	u8	fid;
+	u8	priority;
+};
+
+struct rtl8366_vlan_4k {
+	u16	vid;
+	u16	untag;
+	u16	member;
+	u8	fid;
+};
+
+struct rtl8366_smi_ops {
+	int	(*detect)(struct rtl8366_smi *smi);
+	int	(*reset_chip)(struct rtl8366_smi *smi);
+	int	(*setup)(struct rtl8366_smi *smi);
+
+	int	(*mii_read)(struct mii_bus *bus, int addr, int reg);
+	int	(*mii_write)(struct mii_bus *bus, int addr, int reg, u16 val);
+
+	int	(*get_vlan_mc)(struct rtl8366_smi *smi, u32 index,
+			       struct rtl8366_vlan_mc *vlanmc);
+	int	(*set_vlan_mc)(struct rtl8366_smi *smi, u32 index,
+			       const struct rtl8366_vlan_mc *vlanmc);
+	int	(*get_vlan_4k)(struct rtl8366_smi *smi, u32 vid,
+			       struct rtl8366_vlan_4k *vlan4k);
+	int	(*set_vlan_4k)(struct rtl8366_smi *smi,
+			       const struct rtl8366_vlan_4k *vlan4k);
+	int	(*get_mc_index)(struct rtl8366_smi *smi, int port, int *val);
+	int	(*set_mc_index)(struct rtl8366_smi *smi, int port, int index);
+	int	(*get_mib_counter)(struct rtl8366_smi *smi, int counter,
+				   int port, unsigned long long *val);
+	int	(*is_vlan_valid)(struct rtl8366_smi *smi, unsigned vlan);
+	int	(*enable_vlan)(struct rtl8366_smi *smi, int enable);
+	int	(*enable_vlan4k)(struct rtl8366_smi *smi, int enable);
+	int	(*enable_port)(struct rtl8366_smi *smi, int port, int enable);
+};
+
+struct rtl8366_smi *rtl8366_smi_alloc(struct device *parent);
+int rtl8366_smi_init(struct rtl8366_smi *smi);
+void rtl8366_smi_cleanup(struct rtl8366_smi *smi);
+int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data);
+int rtl8366_smi_write_reg_noack(struct rtl8366_smi *smi, u32 addr, u32 data);
+int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data);
+int rtl8366_smi_rmwr(struct rtl8366_smi *smi, u32 addr, u32 mask, u32 data);
+
+int rtl8366_reset_vlan(struct rtl8366_smi *smi);
+int rtl8366_enable_vlan(struct rtl8366_smi *smi, int enable);
+int rtl8366_enable_all_ports(struct rtl8366_smi *smi, int enable);
+
+#ifdef CONFIG_RTL8366_SMI_DEBUG_FS
+int rtl8366_debugfs_open(struct inode *inode, struct file *file);
+#endif
+
+static inline struct rtl8366_smi *sw_to_rtl8366_smi(struct switch_dev *sw)
+{
+	return container_of(sw, struct rtl8366_smi, sw_dev);
+}
+
+int rtl8366_sw_reset_switch(struct switch_dev *dev);
+int rtl8366_sw_get_port_pvid(struct switch_dev *dev, int port, int *val);
+int rtl8366_sw_set_port_pvid(struct switch_dev *dev, int port, int val);
+int rtl8366_sw_get_port_mib(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val);
+int rtl8366_sw_get_vlan_info(struct switch_dev *dev,
+			     const struct switch_attr *attr,
+			     struct switch_val *val);
+int rtl8366_sw_get_vlan_fid(struct switch_dev *dev,
+			     const struct switch_attr *attr,
+			     struct switch_val *val);
+int rtl8366_sw_set_vlan_fid(struct switch_dev *dev,
+			     const struct switch_attr *attr,
+			     struct switch_val *val);
+int rtl8366_sw_get_vlan_ports(struct switch_dev *dev, struct switch_val *val);
+int rtl8366_sw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val);
+int rtl8366_sw_get_vlan_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val);
+int rtl8366_sw_set_vlan_enable(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val);
+int rtl8366_sw_get_port_stats(struct switch_dev *dev, int port,
+				struct switch_port_stats *stats,
+				int txb_id, int rxb_id);
+
+struct rtl8366_smi* rtl8366_smi_probe(struct platform_device *pdev);
+
+#endif /*  _RTL8366_SMI_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/rtl8366rb.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/rtl8366rb.c
new file mode 100644
index 0000000..0e01160
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/rtl8366rb.c
@@ -0,0 +1,1532 @@
+/*
+ * Platform driver for the Realtek RTL8366RB ethernet switch
+ *
+ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2010 Antti Seppälä <a.seppala@gmail.com>
+ * Copyright (C) 2010 Roman Yeryomin <roman@advem.lv>
+ * Copyright (C) 2011 Colin Leitner <colin.leitner@googlemail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/rtl8366.h>
+
+#include "rtl8366_smi.h"
+
+#define RTL8366RB_DRIVER_DESC	"Realtek RTL8366RB ethernet switch driver"
+#define RTL8366RB_DRIVER_VER	"0.2.4"
+
+#define RTL8366RB_PHY_NO_MAX	4
+#define RTL8366RB_PHY_PAGE_MAX	7
+#define RTL8366RB_PHY_ADDR_MAX	31
+
+/* Switch Global Configuration register */
+#define RTL8366RB_SGCR				0x0000
+#define RTL8366RB_SGCR_EN_BC_STORM_CTRL		BIT(0)
+#define RTL8366RB_SGCR_MAX_LENGTH(_x)		(_x << 4)
+#define RTL8366RB_SGCR_MAX_LENGTH_MASK		RTL8366RB_SGCR_MAX_LENGTH(0x3)
+#define RTL8366RB_SGCR_MAX_LENGTH_1522		RTL8366RB_SGCR_MAX_LENGTH(0x0)
+#define RTL8366RB_SGCR_MAX_LENGTH_1536		RTL8366RB_SGCR_MAX_LENGTH(0x1)
+#define RTL8366RB_SGCR_MAX_LENGTH_1552		RTL8366RB_SGCR_MAX_LENGTH(0x2)
+#define RTL8366RB_SGCR_MAX_LENGTH_9216		RTL8366RB_SGCR_MAX_LENGTH(0x3)
+#define RTL8366RB_SGCR_EN_VLAN			BIT(13)
+#define RTL8366RB_SGCR_EN_VLAN_4KTB		BIT(14)
+
+/* Port Enable Control register */
+#define RTL8366RB_PECR				0x0001
+
+/* Port Mirror Control Register */
+#define RTL8366RB_PMCR				0x0007
+#define RTL8366RB_PMCR_SOURCE_PORT(_x)		(_x)
+#define RTL8366RB_PMCR_SOURCE_PORT_MASK		0x000f
+#define RTL8366RB_PMCR_MONITOR_PORT(_x)		((_x) << 4)
+#define RTL8366RB_PMCR_MONITOR_PORT_MASK	0x00f0
+#define RTL8366RB_PMCR_MIRROR_RX		BIT(8)
+#define RTL8366RB_PMCR_MIRROR_TX		BIT(9)
+#define RTL8366RB_PMCR_MIRROR_SPC		BIT(10)
+#define RTL8366RB_PMCR_MIRROR_ISO		BIT(11)
+
+/* Switch Security Control registers */
+#define RTL8366RB_SSCR0				0x0002
+#define RTL8366RB_SSCR1				0x0003
+#define RTL8366RB_SSCR2				0x0004
+#define RTL8366RB_SSCR2_DROP_UNKNOWN_DA		BIT(0)
+
+#define RTL8366RB_RESET_CTRL_REG		0x0100
+#define RTL8366RB_CHIP_CTRL_RESET_HW		1
+#define RTL8366RB_CHIP_CTRL_RESET_SW		(1 << 1)
+
+#define RTL8366RB_CHIP_VERSION_CTRL_REG		0x050A
+#define RTL8366RB_CHIP_VERSION_MASK		0xf
+#define RTL8366RB_CHIP_ID_REG			0x0509
+#define RTL8366RB_CHIP_ID_8366			0x5937
+
+/* PHY registers control */
+#define RTL8366RB_PHY_ACCESS_CTRL_REG		0x8000
+#define RTL8366RB_PHY_ACCESS_DATA_REG		0x8002
+
+#define RTL8366RB_PHY_CTRL_READ			1
+#define RTL8366RB_PHY_CTRL_WRITE		0
+
+#define RTL8366RB_PHY_REG_MASK			0x1f
+#define RTL8366RB_PHY_PAGE_OFFSET		5
+#define RTL8366RB_PHY_PAGE_MASK			(0xf << 5)
+#define RTL8366RB_PHY_NO_OFFSET			9
+#define RTL8366RB_PHY_NO_MASK			(0x1f << 9)
+
+#define RTL8366RB_VLAN_INGRESS_CTRL2_REG	0x037f
+
+/* LED control registers */
+#define RTL8366RB_LED_BLINKRATE_REG		0x0430
+#define RTL8366RB_LED_BLINKRATE_BIT		0
+#define RTL8366RB_LED_BLINKRATE_MASK		0x0007
+
+#define RTL8366RB_LED_CTRL_REG			0x0431
+#define RTL8366RB_LED_0_1_CTRL_REG		0x0432
+#define RTL8366RB_LED_2_3_CTRL_REG		0x0433
+
+#define RTL8366RB_MIB_COUNT			33
+#define RTL8366RB_GLOBAL_MIB_COUNT		1
+#define RTL8366RB_MIB_COUNTER_PORT_OFFSET	0x0050
+#define RTL8366RB_MIB_COUNTER_BASE		0x1000
+#define RTL8366RB_MIB_CTRL_REG			0x13F0
+#define RTL8366RB_MIB_CTRL_USER_MASK		0x0FFC
+#define RTL8366RB_MIB_CTRL_BUSY_MASK		BIT(0)
+#define RTL8366RB_MIB_CTRL_RESET_MASK		BIT(1)
+#define RTL8366RB_MIB_CTRL_PORT_RESET(_p)	BIT(2 + (_p))
+#define RTL8366RB_MIB_CTRL_GLOBAL_RESET		BIT(11)
+
+#define RTL8366RB_PORT_VLAN_CTRL_BASE		0x0063
+#define RTL8366RB_PORT_VLAN_CTRL_REG(_p)  \
+		(RTL8366RB_PORT_VLAN_CTRL_BASE + (_p) / 4)
+#define RTL8366RB_PORT_VLAN_CTRL_MASK		0xf
+#define RTL8366RB_PORT_VLAN_CTRL_SHIFT(_p)	(4 * ((_p) % 4))
+
+
+#define RTL8366RB_VLAN_TABLE_READ_BASE		0x018C
+#define RTL8366RB_VLAN_TABLE_WRITE_BASE		0x0185
+
+
+#define RTL8366RB_TABLE_ACCESS_CTRL_REG		0x0180
+#define RTL8366RB_TABLE_VLAN_READ_CTRL		0x0E01
+#define RTL8366RB_TABLE_VLAN_WRITE_CTRL		0x0F01
+
+#define RTL8366RB_VLAN_MC_BASE(_x)		(0x0020 + (_x) * 3)
+
+
+#define RTL8366RB_PORT_LINK_STATUS_BASE		0x0014
+#define RTL8366RB_PORT_STATUS_SPEED_MASK	0x0003
+#define RTL8366RB_PORT_STATUS_DUPLEX_MASK	0x0004
+#define RTL8366RB_PORT_STATUS_LINK_MASK		0x0010
+#define RTL8366RB_PORT_STATUS_TXPAUSE_MASK	0x0020
+#define RTL8366RB_PORT_STATUS_RXPAUSE_MASK	0x0040
+#define RTL8366RB_PORT_STATUS_AN_MASK		0x0080
+
+
+#define RTL8366RB_PORT_NUM_CPU		5
+#define RTL8366RB_NUM_PORTS		6
+#define RTL8366RB_NUM_VLANS		16
+#define RTL8366RB_NUM_LEDGROUPS		4
+#define RTL8366RB_NUM_VIDS		4096
+#define RTL8366RB_PRIORITYMAX		7
+#define RTL8366RB_FIDMAX		7
+
+
+#define RTL8366RB_PORT_1		(1 << 0) /* In userspace port 0 */
+#define RTL8366RB_PORT_2		(1 << 1) /* In userspace port 1 */
+#define RTL8366RB_PORT_3		(1 << 2) /* In userspace port 2 */
+#define RTL8366RB_PORT_4		(1 << 3) /* In userspace port 3 */
+#define RTL8366RB_PORT_5		(1 << 4) /* In userspace port 4 */
+
+#define RTL8366RB_PORT_CPU		(1 << 5) /* CPU port */
+
+#define RTL8366RB_PORT_ALL		(RTL8366RB_PORT_1 |	\
+					 RTL8366RB_PORT_2 |	\
+					 RTL8366RB_PORT_3 |	\
+					 RTL8366RB_PORT_4 |	\
+					 RTL8366RB_PORT_5 |	\
+					 RTL8366RB_PORT_CPU)
+
+#define RTL8366RB_PORT_ALL_BUT_CPU	(RTL8366RB_PORT_1 |	\
+					 RTL8366RB_PORT_2 |	\
+					 RTL8366RB_PORT_3 |	\
+					 RTL8366RB_PORT_4 |	\
+					 RTL8366RB_PORT_5)
+
+#define RTL8366RB_PORT_ALL_EXTERNAL	(RTL8366RB_PORT_1 |	\
+					 RTL8366RB_PORT_2 |	\
+					 RTL8366RB_PORT_3 |	\
+					 RTL8366RB_PORT_4)
+
+#define RTL8366RB_PORT_ALL_INTERNAL	 RTL8366RB_PORT_CPU
+
+#define RTL8366RB_VLAN_VID_MASK		0xfff
+#define RTL8366RB_VLAN_PRIORITY_SHIFT	12
+#define RTL8366RB_VLAN_PRIORITY_MASK	0x7
+#define RTL8366RB_VLAN_UNTAG_SHIFT	8
+#define RTL8366RB_VLAN_UNTAG_MASK	0xff
+#define RTL8366RB_VLAN_MEMBER_MASK	0xff
+#define RTL8366RB_VLAN_FID_MASK		0x7
+
+
+/* Port ingress bandwidth control */
+#define RTL8366RB_IB_BASE		0x0200
+#define RTL8366RB_IB_REG(pnum)		(RTL8366RB_IB_BASE + pnum)
+#define RTL8366RB_IB_BDTH_MASK		0x3fff
+#define RTL8366RB_IB_PREIFG_OFFSET	14
+#define RTL8366RB_IB_PREIFG_MASK	(1 << RTL8366RB_IB_PREIFG_OFFSET)
+
+/* Port egress bandwidth control */
+#define RTL8366RB_EB_BASE		0x02d1
+#define RTL8366RB_EB_REG(pnum)		(RTL8366RB_EB_BASE + pnum)
+#define RTL8366RB_EB_BDTH_MASK		0x3fff
+#define RTL8366RB_EB_PREIFG_REG	0x02f8
+#define RTL8366RB_EB_PREIFG_OFFSET	9
+#define RTL8366RB_EB_PREIFG_MASK	(1 << RTL8366RB_EB_PREIFG_OFFSET)
+
+#define RTL8366RB_BDTH_SW_MAX		1048512
+#define RTL8366RB_BDTH_UNIT		64
+#define RTL8366RB_BDTH_REG_DEFAULT	16383
+
+/* QOS */
+#define RTL8366RB_QOS_BIT		15
+#define RTL8366RB_QOS_MASK		(1 << RTL8366RB_QOS_BIT)
+/* Include/Exclude Preamble and IFG (20 bytes). 0:Exclude, 1:Include. */
+#define RTL8366RB_QOS_DEFAULT_PREIFG	1
+
+
+#define RTL8366RB_MIB_RXB_ID		0	/* IfInOctets */
+#define RTL8366RB_MIB_TXB_ID		20	/* IfOutOctets */
+
+static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = {
+	{ 0,  0, 4, "IfInOctets"				},
+	{ 0,  4, 4, "EtherStatsOctets"				},
+	{ 0,  8, 2, "EtherStatsUnderSizePkts"			},
+	{ 0, 10, 2, "EtherFragments"				},
+	{ 0, 12, 2, "EtherStatsPkts64Octets"			},
+	{ 0, 14, 2, "EtherStatsPkts65to127Octets"		},
+	{ 0, 16, 2, "EtherStatsPkts128to255Octets"		},
+	{ 0, 18, 2, "EtherStatsPkts256to511Octets"		},
+	{ 0, 20, 2, "EtherStatsPkts512to1023Octets"		},
+	{ 0, 22, 2, "EtherStatsPkts1024to1518Octets"		},
+	{ 0, 24, 2, "EtherOversizeStats"			},
+	{ 0, 26, 2, "EtherStatsJabbers"				},
+	{ 0, 28, 2, "IfInUcastPkts"				},
+	{ 0, 30, 2, "EtherStatsMulticastPkts"			},
+	{ 0, 32, 2, "EtherStatsBroadcastPkts"			},
+	{ 0, 34, 2, "EtherStatsDropEvents"			},
+	{ 0, 36, 2, "Dot3StatsFCSErrors"			},
+	{ 0, 38, 2, "Dot3StatsSymbolErrors"			},
+	{ 0, 40, 2, "Dot3InPauseFrames"				},
+	{ 0, 42, 2, "Dot3ControlInUnknownOpcodes"		},
+	{ 0, 44, 4, "IfOutOctets"				},
+	{ 0, 48, 2, "Dot3StatsSingleCollisionFrames"		},
+	{ 0, 50, 2, "Dot3StatMultipleCollisionFrames"		},
+	{ 0, 52, 2, "Dot3sDeferredTransmissions"		},
+	{ 0, 54, 2, "Dot3StatsLateCollisions"			},
+	{ 0, 56, 2, "EtherStatsCollisions"			},
+	{ 0, 58, 2, "Dot3StatsExcessiveCollisions"		},
+	{ 0, 60, 2, "Dot3OutPauseFrames"			},
+	{ 0, 62, 2, "Dot1dBasePortDelayExceededDiscards"	},
+	{ 0, 64, 2, "Dot1dTpPortInDiscards"			},
+	{ 0, 66, 2, "IfOutUcastPkts"				},
+	{ 0, 68, 2, "IfOutMulticastPkts"			},
+	{ 0, 70, 2, "IfOutBroadcastPkts"			},
+};
+
+#define REG_WR(_smi, _reg, _val)					\
+	do {								\
+		err = rtl8366_smi_write_reg(_smi, _reg, _val);		\
+		if (err)						\
+			return err;					\
+	} while (0)
+
+#define REG_RMW(_smi, _reg, _mask, _val)				\
+	do {								\
+		err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val);	\
+		if (err)						\
+			return err;					\
+	} while (0)
+
+static int rtl8366rb_reset_chip(struct rtl8366_smi *smi)
+{
+	int timeout = 10;
+	u32 data;
+
+	rtl8366_smi_write_reg_noack(smi, RTL8366RB_RESET_CTRL_REG,
+			 	    RTL8366RB_CHIP_CTRL_RESET_HW);
+	do {
+		msleep(1);
+		if (rtl8366_smi_read_reg(smi, RTL8366RB_RESET_CTRL_REG, &data))
+			return -EIO;
+
+		if (!(data & RTL8366RB_CHIP_CTRL_RESET_HW))
+			break;
+	} while (--timeout);
+
+	if (!timeout) {
+		printk("Timeout waiting for the switch to reset\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int rtl8366rb_setup(struct rtl8366_smi *smi)
+{
+	int err;
+#ifdef CONFIG_OF
+	unsigned i;
+	struct device_node *np;
+	unsigned num_initvals;
+	const __be32 *paddr;
+
+	np = smi->parent->of_node;
+
+	paddr = of_get_property(np, "realtek,initvals", &num_initvals);
+	if (paddr) {
+		dev_info(smi->parent, "applying initvals from DTS\n");
+
+		if (num_initvals < (2 * sizeof(*paddr)))
+			return -EINVAL;
+
+		num_initvals /= sizeof(*paddr);
+
+		for (i = 0; i < num_initvals - 1; i += 2) {
+			u32 reg = be32_to_cpup(paddr + i);
+			u32 val = be32_to_cpup(paddr + i + 1);
+
+			REG_WR(smi, reg, val);
+		}
+	}
+#endif
+
+	/* set maximum packet length to 1536 bytes */
+	REG_RMW(smi, RTL8366RB_SGCR, RTL8366RB_SGCR_MAX_LENGTH_MASK,
+		RTL8366RB_SGCR_MAX_LENGTH_1536);
+
+	/* enable learning for all ports */
+	REG_WR(smi, RTL8366RB_SSCR0, 0);
+
+	/* enable auto ageing for all ports */
+	REG_WR(smi, RTL8366RB_SSCR1, 0);
+
+	/*
+	 * discard VLAN tagged packets if the port is not a member of
+	 * the VLAN with which the packets is associated.
+	 */
+	REG_WR(smi, RTL8366RB_VLAN_INGRESS_CTRL2_REG, RTL8366RB_PORT_ALL);
+
+	/* don't drop packets whose DA has not been learned */
+	REG_RMW(smi, RTL8366RB_SSCR2, RTL8366RB_SSCR2_DROP_UNKNOWN_DA, 0);
+
+	return 0;
+}
+
+static int rtl8366rb_read_phy_reg(struct rtl8366_smi *smi,
+				 u32 phy_no, u32 page, u32 addr, u32 *data)
+{
+	u32 reg;
+	int ret;
+
+	if (phy_no > RTL8366RB_PHY_NO_MAX)
+		return -EINVAL;
+
+	if (page > RTL8366RB_PHY_PAGE_MAX)
+		return -EINVAL;
+
+	if (addr > RTL8366RB_PHY_ADDR_MAX)
+		return -EINVAL;
+
+	ret = rtl8366_smi_write_reg(smi, RTL8366RB_PHY_ACCESS_CTRL_REG,
+				    RTL8366RB_PHY_CTRL_READ);
+	if (ret)
+		return ret;
+
+	reg = 0x8000 | (1 << (phy_no + RTL8366RB_PHY_NO_OFFSET)) |
+	      ((page << RTL8366RB_PHY_PAGE_OFFSET) & RTL8366RB_PHY_PAGE_MASK) |
+	      (addr & RTL8366RB_PHY_REG_MASK);
+
+	ret = rtl8366_smi_write_reg(smi, reg, 0);
+	if (ret)
+		return ret;
+
+	ret = rtl8366_smi_read_reg(smi, RTL8366RB_PHY_ACCESS_DATA_REG, data);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int rtl8366rb_write_phy_reg(struct rtl8366_smi *smi,
+				  u32 phy_no, u32 page, u32 addr, u32 data)
+{
+	u32 reg;
+	int ret;
+
+	if (phy_no > RTL8366RB_PHY_NO_MAX)
+		return -EINVAL;
+
+	if (page > RTL8366RB_PHY_PAGE_MAX)
+		return -EINVAL;
+
+	if (addr > RTL8366RB_PHY_ADDR_MAX)
+		return -EINVAL;
+
+	ret = rtl8366_smi_write_reg(smi, RTL8366RB_PHY_ACCESS_CTRL_REG,
+				    RTL8366RB_PHY_CTRL_WRITE);
+	if (ret)
+		return ret;
+
+	reg = 0x8000 | (1 << (phy_no + RTL8366RB_PHY_NO_OFFSET)) |
+	      ((page << RTL8366RB_PHY_PAGE_OFFSET) & RTL8366RB_PHY_PAGE_MASK) |
+	      (addr & RTL8366RB_PHY_REG_MASK);
+
+	ret = rtl8366_smi_write_reg(smi, reg, data);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int rtl8366rb_get_mib_counter(struct rtl8366_smi *smi, int counter,
+				     int port, unsigned long long *val)
+{
+	int i;
+	int err;
+	u32 addr, data;
+	u64 mibvalue;
+
+	if (port > RTL8366RB_NUM_PORTS || counter >= RTL8366RB_MIB_COUNT)
+		return -EINVAL;
+
+	addr = RTL8366RB_MIB_COUNTER_BASE +
+	       RTL8366RB_MIB_COUNTER_PORT_OFFSET * (port) +
+	       rtl8366rb_mib_counters[counter].offset;
+
+	/*
+	 * Writing access counter address first
+	 * then ASIC will prepare 64bits counter wait for being retrived
+	 */
+	data = 0; /* writing data will be discard by ASIC */
+	err = rtl8366_smi_write_reg(smi, addr, data);
+	if (err)
+		return err;
+
+	/* read MIB control register */
+	err =  rtl8366_smi_read_reg(smi, RTL8366RB_MIB_CTRL_REG, &data);
+	if (err)
+		return err;
+
+	if (data & RTL8366RB_MIB_CTRL_BUSY_MASK)
+		return -EBUSY;
+
+	if (data & RTL8366RB_MIB_CTRL_RESET_MASK)
+		return -EIO;
+
+	mibvalue = 0;
+	for (i = rtl8366rb_mib_counters[counter].length; i > 0; i--) {
+		err = rtl8366_smi_read_reg(smi, addr + (i - 1), &data);
+		if (err)
+			return err;
+
+		mibvalue = (mibvalue << 16) | (data & 0xFFFF);
+	}
+
+	*val = mibvalue;
+	return 0;
+}
+
+static int rtl8366rb_get_vlan_4k(struct rtl8366_smi *smi, u32 vid,
+				 struct rtl8366_vlan_4k *vlan4k)
+{
+	u32 data[3];
+	int err;
+	int i;
+
+	memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k));
+
+	if (vid >= RTL8366RB_NUM_VIDS)
+		return -EINVAL;
+
+	/* write VID */
+	err = rtl8366_smi_write_reg(smi, RTL8366RB_VLAN_TABLE_WRITE_BASE,
+				    vid & RTL8366RB_VLAN_VID_MASK);
+	if (err)
+		return err;
+
+	/* write table access control word */
+	err = rtl8366_smi_write_reg(smi, RTL8366RB_TABLE_ACCESS_CTRL_REG,
+				    RTL8366RB_TABLE_VLAN_READ_CTRL);
+	if (err)
+		return err;
+
+	for (i = 0; i < 3; i++) {
+		err = rtl8366_smi_read_reg(smi,
+					   RTL8366RB_VLAN_TABLE_READ_BASE + i,
+					   &data[i]);
+		if (err)
+			return err;
+	}
+
+	vlan4k->vid = vid;
+	vlan4k->untag = (data[1] >> RTL8366RB_VLAN_UNTAG_SHIFT) &
+			RTL8366RB_VLAN_UNTAG_MASK;
+	vlan4k->member = data[1] & RTL8366RB_VLAN_MEMBER_MASK;
+	vlan4k->fid = data[2] & RTL8366RB_VLAN_FID_MASK;
+
+	return 0;
+}
+
+static int rtl8366rb_set_vlan_4k(struct rtl8366_smi *smi,
+				 const struct rtl8366_vlan_4k *vlan4k)
+{
+	u32 data[3];
+	int err;
+	int i;
+
+	if (vlan4k->vid >= RTL8366RB_NUM_VIDS ||
+	    vlan4k->member > RTL8366RB_VLAN_MEMBER_MASK ||
+	    vlan4k->untag > RTL8366RB_VLAN_UNTAG_MASK ||
+	    vlan4k->fid > RTL8366RB_FIDMAX)
+		return -EINVAL;
+
+	data[0] = vlan4k->vid & RTL8366RB_VLAN_VID_MASK;
+	data[1] = (vlan4k->member & RTL8366RB_VLAN_MEMBER_MASK) |
+		  ((vlan4k->untag & RTL8366RB_VLAN_UNTAG_MASK) <<
+			RTL8366RB_VLAN_UNTAG_SHIFT);
+	data[2] = vlan4k->fid & RTL8366RB_VLAN_FID_MASK;
+
+	for (i = 0; i < 3; i++) {
+		err = rtl8366_smi_write_reg(smi,
+					    RTL8366RB_VLAN_TABLE_WRITE_BASE + i,
+					    data[i]);
+		if (err)
+			return err;
+	}
+
+	/* write table access control word */
+	err = rtl8366_smi_write_reg(smi, RTL8366RB_TABLE_ACCESS_CTRL_REG,
+				    RTL8366RB_TABLE_VLAN_WRITE_CTRL);
+
+	return err;
+}
+
+static int rtl8366rb_get_vlan_mc(struct rtl8366_smi *smi, u32 index,
+				 struct rtl8366_vlan_mc *vlanmc)
+{
+	u32 data[3];
+	int err;
+	int i;
+
+	memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc));
+
+	if (index >= RTL8366RB_NUM_VLANS)
+		return -EINVAL;
+
+	for (i = 0; i < 3; i++) {
+		err = rtl8366_smi_read_reg(smi,
+					   RTL8366RB_VLAN_MC_BASE(index) + i,
+					   &data[i]);
+		if (err)
+			return err;
+	}
+
+	vlanmc->vid = data[0] & RTL8366RB_VLAN_VID_MASK;
+	vlanmc->priority = (data[0] >> RTL8366RB_VLAN_PRIORITY_SHIFT) &
+			   RTL8366RB_VLAN_PRIORITY_MASK;
+	vlanmc->untag = (data[1] >> RTL8366RB_VLAN_UNTAG_SHIFT) &
+			RTL8366RB_VLAN_UNTAG_MASK;
+	vlanmc->member = data[1] & RTL8366RB_VLAN_MEMBER_MASK;
+	vlanmc->fid = data[2] & RTL8366RB_VLAN_FID_MASK;
+
+	return 0;
+}
+
+static int rtl8366rb_set_vlan_mc(struct rtl8366_smi *smi, u32 index,
+				 const struct rtl8366_vlan_mc *vlanmc)
+{
+	u32 data[3];
+	int err;
+	int i;
+
+	if (index >= RTL8366RB_NUM_VLANS ||
+	    vlanmc->vid >= RTL8366RB_NUM_VIDS ||
+	    vlanmc->priority > RTL8366RB_PRIORITYMAX ||
+	    vlanmc->member > RTL8366RB_VLAN_MEMBER_MASK ||
+	    vlanmc->untag > RTL8366RB_VLAN_UNTAG_MASK ||
+	    vlanmc->fid > RTL8366RB_FIDMAX)
+		return -EINVAL;
+
+	data[0] = (vlanmc->vid & RTL8366RB_VLAN_VID_MASK) |
+		  ((vlanmc->priority & RTL8366RB_VLAN_PRIORITY_MASK) <<
+			RTL8366RB_VLAN_PRIORITY_SHIFT);
+	data[1] = (vlanmc->member & RTL8366RB_VLAN_MEMBER_MASK) |
+		  ((vlanmc->untag & RTL8366RB_VLAN_UNTAG_MASK) <<
+			RTL8366RB_VLAN_UNTAG_SHIFT);
+	data[2] = vlanmc->fid & RTL8366RB_VLAN_FID_MASK;
+
+	for (i = 0; i < 3; i++) {
+		err = rtl8366_smi_write_reg(smi,
+					    RTL8366RB_VLAN_MC_BASE(index) + i,
+					    data[i]);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int rtl8366rb_get_mc_index(struct rtl8366_smi *smi, int port, int *val)
+{
+	u32 data;
+	int err;
+
+	if (port >= RTL8366RB_NUM_PORTS)
+		return -EINVAL;
+
+	err = rtl8366_smi_read_reg(smi, RTL8366RB_PORT_VLAN_CTRL_REG(port),
+				   &data);
+	if (err)
+		return err;
+
+	*val = (data >> RTL8366RB_PORT_VLAN_CTRL_SHIFT(port)) &
+	       RTL8366RB_PORT_VLAN_CTRL_MASK;
+
+	return 0;
+
+}
+
+static int rtl8366rb_set_mc_index(struct rtl8366_smi *smi, int port, int index)
+{
+	if (port >= RTL8366RB_NUM_PORTS || index >= RTL8366RB_NUM_VLANS)
+		return -EINVAL;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_PORT_VLAN_CTRL_REG(port),
+				RTL8366RB_PORT_VLAN_CTRL_MASK <<
+					RTL8366RB_PORT_VLAN_CTRL_SHIFT(port),
+				(index & RTL8366RB_PORT_VLAN_CTRL_MASK) <<
+					RTL8366RB_PORT_VLAN_CTRL_SHIFT(port));
+}
+
+static int rtl8366rb_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan)
+{
+	unsigned max = RTL8366RB_NUM_VLANS;
+
+	if (smi->vlan4k_enabled)
+		max = RTL8366RB_NUM_VIDS - 1;
+
+	if (vlan == 0 || vlan >= max)
+		return 0;
+
+	return 1;
+}
+
+static int rtl8366rb_enable_vlan(struct rtl8366_smi *smi, int enable)
+{
+	return rtl8366_smi_rmwr(smi, RTL8366RB_SGCR, RTL8366RB_SGCR_EN_VLAN,
+				(enable) ? RTL8366RB_SGCR_EN_VLAN : 0);
+}
+
+static int rtl8366rb_enable_vlan4k(struct rtl8366_smi *smi, int enable)
+{
+	return rtl8366_smi_rmwr(smi, RTL8366RB_SGCR,
+				RTL8366RB_SGCR_EN_VLAN_4KTB,
+				(enable) ? RTL8366RB_SGCR_EN_VLAN_4KTB : 0);
+}
+
+static int rtl8366rb_enable_port(struct rtl8366_smi *smi, int port, int enable)
+{
+	return rtl8366_smi_rmwr(smi, RTL8366RB_PECR, (1 << port),
+				(enable) ? 0 : (1 << port));
+}
+
+static int rtl8366rb_sw_reset_mibs(struct switch_dev *dev,
+				  const struct switch_attr *attr,
+				  struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_MIB_CTRL_REG, 0,
+			        RTL8366RB_MIB_CTRL_GLOBAL_RESET);
+}
+
+static int rtl8366rb_sw_get_blinkrate(struct switch_dev *dev,
+				     const struct switch_attr *attr,
+				     struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_LED_BLINKRATE_REG, &data);
+
+	val->value.i = (data & (RTL8366RB_LED_BLINKRATE_MASK));
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_blinkrate(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	if (val->value.i >= 6)
+		return -EINVAL;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_LED_BLINKRATE_REG,
+				RTL8366RB_LED_BLINKRATE_MASK,
+				val->value.i);
+}
+
+static int rtl8366rb_sw_get_learning_enable(struct switch_dev *dev,
+				       const struct switch_attr *attr,
+				       struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_SSCR0, &data);
+	val->value.i = !data;
+
+	return 0;
+}
+
+
+static int rtl8366rb_sw_set_learning_enable(struct switch_dev *dev,
+				       const struct switch_attr *attr,
+				       struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 portmask = 0;
+	int err = 0;
+
+	if (!val->value.i)
+		portmask = RTL8366RB_PORT_ALL;
+
+	/* set learning for all ports */
+	REG_WR(smi, RTL8366RB_SSCR0, portmask);
+
+	/* set auto ageing for all ports */
+	REG_WR(smi, RTL8366RB_SSCR1, portmask);
+
+	return 0;
+}
+
+static int rtl8366rb_sw_get_port_link(struct switch_dev *dev,
+				     int port,
+				     struct switch_port_link *link)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data = 0;
+	u32 speed;
+
+	if (port >= RTL8366RB_NUM_PORTS)
+		return -EINVAL;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_PORT_LINK_STATUS_BASE + (port / 2),
+			     &data);
+
+	if (port % 2)
+		data = data >> 8;
+
+	link->link = !!(data & RTL8366RB_PORT_STATUS_LINK_MASK);
+	if (!link->link)
+		return 0;
+
+	link->duplex = !!(data & RTL8366RB_PORT_STATUS_DUPLEX_MASK);
+	link->rx_flow = !!(data & RTL8366RB_PORT_STATUS_RXPAUSE_MASK);
+	link->tx_flow = !!(data & RTL8366RB_PORT_STATUS_TXPAUSE_MASK);
+	link->aneg = !!(data & RTL8366RB_PORT_STATUS_AN_MASK);
+
+	speed = (data & RTL8366RB_PORT_STATUS_SPEED_MASK);
+	switch (speed) {
+	case 0:
+		link->speed = SWITCH_PORT_SPEED_10;
+		break;
+	case 1:
+		link->speed = SWITCH_PORT_SPEED_100;
+		break;
+	case 2:
+		link->speed = SWITCH_PORT_SPEED_1000;
+		break;
+	default:
+		link->speed = SWITCH_PORT_SPEED_UNKNOWN;
+		break;
+	}
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_port_led(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+	u32 mask;
+	u32 reg;
+
+	if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+		return -EINVAL;
+
+	if (val->port_vlan == RTL8366RB_PORT_NUM_CPU) {
+		reg = RTL8366RB_LED_BLINKRATE_REG;
+		mask = 0xF << 4;
+		data = val->value.i << 4;
+	} else {
+		reg = RTL8366RB_LED_CTRL_REG;
+		mask = 0xF << (val->port_vlan * 4),
+		data = val->value.i << (val->port_vlan * 4);
+	}
+
+	return rtl8366_smi_rmwr(smi, reg, mask, data);
+}
+
+static int rtl8366rb_sw_get_port_led(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data = 0;
+
+	if (val->port_vlan >= RTL8366RB_NUM_LEDGROUPS)
+		return -EINVAL;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_LED_CTRL_REG, &data);
+	val->value.i = (data >> (val->port_vlan * 4)) & 0x000F;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_port_disable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 mask, data;
+
+	if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+		return -EINVAL;
+
+	mask = 1 << val->port_vlan ;
+	if (val->value.i)
+		data = mask;
+	else
+		data = 0;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_PECR, mask, data);
+}
+
+static int rtl8366rb_sw_get_port_disable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+		return -EINVAL;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_PECR, &data);
+	if (data & (1 << val->port_vlan))
+		val->value.i = 1;
+	else
+		val->value.i = 0;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_port_rate_in(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+		return -EINVAL;
+
+	if (val->value.i > 0 && val->value.i < RTL8366RB_BDTH_SW_MAX)
+		val->value.i = (val->value.i - 1) / RTL8366RB_BDTH_UNIT;
+	else
+		val->value.i = RTL8366RB_BDTH_REG_DEFAULT;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_IB_REG(val->port_vlan),
+		RTL8366RB_IB_BDTH_MASK | RTL8366RB_IB_PREIFG_MASK,
+		val->value.i |
+		(RTL8366RB_QOS_DEFAULT_PREIFG << RTL8366RB_IB_PREIFG_OFFSET));
+
+}
+
+static int rtl8366rb_sw_get_port_rate_in(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+		return -EINVAL;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_IB_REG(val->port_vlan), &data);
+	data &= RTL8366RB_IB_BDTH_MASK;
+	if (data < RTL8366RB_IB_BDTH_MASK)
+		data += 1;
+
+	val->value.i = (int)data * RTL8366RB_BDTH_UNIT;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_port_rate_out(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+		return -EINVAL;
+
+	rtl8366_smi_rmwr(smi, RTL8366RB_EB_PREIFG_REG,
+		RTL8366RB_EB_PREIFG_MASK,
+		(RTL8366RB_QOS_DEFAULT_PREIFG << RTL8366RB_EB_PREIFG_OFFSET));
+
+	if (val->value.i > 0 && val->value.i < RTL8366RB_BDTH_SW_MAX)
+		val->value.i = (val->value.i - 1) / RTL8366RB_BDTH_UNIT;
+	else
+		val->value.i = RTL8366RB_BDTH_REG_DEFAULT;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_EB_REG(val->port_vlan),
+			RTL8366RB_EB_BDTH_MASK, val->value.i );
+
+}
+
+static int rtl8366rb_sw_get_port_rate_out(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+		return -EINVAL;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_EB_REG(val->port_vlan), &data);
+	data &= RTL8366RB_EB_BDTH_MASK;
+	if (data < RTL8366RB_EB_BDTH_MASK)
+		data += 1;
+
+	val->value.i = (int)data * RTL8366RB_BDTH_UNIT;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_qos_enable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	if (val->value.i)
+		data = RTL8366RB_QOS_MASK;
+	else
+		data = 0;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_SGCR, RTL8366RB_QOS_MASK, data);
+}
+
+static int rtl8366rb_sw_get_qos_enable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_SGCR, &data);
+	if (data & RTL8366RB_QOS_MASK)
+		val->value.i = 1;
+	else
+		val->value.i = 0;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_mirror_rx_enable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	if (val->value.i)
+		data = RTL8366RB_PMCR_MIRROR_RX;
+	else
+		data = 0;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_RX, data);
+}
+
+static int rtl8366rb_sw_get_mirror_rx_enable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data);
+	if (data & RTL8366RB_PMCR_MIRROR_RX)
+		val->value.i = 1;
+	else
+		val->value.i = 0;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_mirror_tx_enable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	if (val->value.i)
+		data = RTL8366RB_PMCR_MIRROR_TX;
+	else
+		data = 0;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_TX, data);
+}
+
+static int rtl8366rb_sw_get_mirror_tx_enable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data);
+	if (data & RTL8366RB_PMCR_MIRROR_TX)
+		val->value.i = 1;
+	else
+		val->value.i = 0;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_monitor_isolation_enable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	if (val->value.i)
+		data = RTL8366RB_PMCR_MIRROR_ISO;
+	else
+		data = 0;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_ISO, data);
+}
+
+static int rtl8366rb_sw_get_monitor_isolation_enable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data);
+	if (data & RTL8366RB_PMCR_MIRROR_ISO)
+		val->value.i = 1;
+	else
+		val->value.i = 0;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_mirror_pause_frames_enable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	if (val->value.i)
+		data = RTL8366RB_PMCR_MIRROR_SPC;
+	else
+		data = 0;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_SPC, data);
+}
+
+static int rtl8366rb_sw_get_mirror_pause_frames_enable(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data);
+	if (data & RTL8366RB_PMCR_MIRROR_SPC)
+		val->value.i = 1;
+	else
+		val->value.i = 0;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_mirror_monitor_port(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	data = RTL8366RB_PMCR_MONITOR_PORT(val->value.i);
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MONITOR_PORT_MASK, data);
+}
+
+static int rtl8366rb_sw_get_mirror_monitor_port(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data);
+	val->value.i = (data & RTL8366RB_PMCR_MONITOR_PORT_MASK) >> 4;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_set_mirror_source_port(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	data = RTL8366RB_PMCR_SOURCE_PORT(val->value.i);
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_SOURCE_PORT_MASK, data);
+}
+
+static int rtl8366rb_sw_get_mirror_source_port(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data);
+	val->value.i = data & RTL8366RB_PMCR_SOURCE_PORT_MASK;
+
+	return 0;
+}
+
+static int rtl8366rb_sw_reset_port_mibs(struct switch_dev *dev,
+				       const struct switch_attr *attr,
+				       struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	if (val->port_vlan >= RTL8366RB_NUM_PORTS)
+		return -EINVAL;
+
+	return rtl8366_smi_rmwr(smi, RTL8366RB_MIB_CTRL_REG, 0,
+				RTL8366RB_MIB_CTRL_PORT_RESET(val->port_vlan));
+}
+
+static int rtl8366rb_sw_get_port_stats(struct switch_dev *dev, int port,
+					struct switch_port_stats *stats)
+{
+	return (rtl8366_sw_get_port_stats(dev, port, stats,
+				RTL8366RB_MIB_TXB_ID, RTL8366RB_MIB_RXB_ID));
+}
+
+static struct switch_attr rtl8366rb_globals[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_learning",
+		.description = "Enable learning, enable aging",
+		.set = rtl8366rb_sw_set_learning_enable,
+		.get = rtl8366rb_sw_get_learning_enable,
+		.max = 1
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.set = rtl8366_sw_set_vlan_enable,
+		.get = rtl8366_sw_get_vlan_enable,
+		.max = 1,
+		.ofs = 1
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan4k",
+		.description = "Enable VLAN 4K mode",
+		.set = rtl8366_sw_set_vlan_enable,
+		.get = rtl8366_sw_get_vlan_enable,
+		.max = 1,
+		.ofs = 2
+	}, {
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mibs",
+		.description = "Reset all MIB counters",
+		.set = rtl8366rb_sw_reset_mibs,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "blinkrate",
+		.description = "Get/Set LED blinking rate (0 = 43ms, 1 = 84ms,"
+		" 2 = 120ms, 3 = 170ms, 4 = 340ms, 5 = 670ms)",
+		.set = rtl8366rb_sw_set_blinkrate,
+		.get = rtl8366rb_sw_get_blinkrate,
+		.max = 5
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_qos",
+		.description = "Enable QOS",
+		.set = rtl8366rb_sw_set_qos_enable,
+		.get = rtl8366rb_sw_get_qos_enable,
+		.max = 1
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_mirror_rx",
+		.description = "Enable mirroring of RX packets",
+		.set = rtl8366rb_sw_set_mirror_rx_enable,
+		.get = rtl8366rb_sw_get_mirror_rx_enable,
+		.max = 1
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_mirror_tx",
+		.description = "Enable mirroring of TX packets",
+		.set = rtl8366rb_sw_set_mirror_tx_enable,
+		.get = rtl8366rb_sw_get_mirror_tx_enable,
+		.max = 1
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_monitor_isolation",
+		.description = "Enable isolation of monitor port (TX packets will be dropped)",
+		.set = rtl8366rb_sw_set_monitor_isolation_enable,
+		.get = rtl8366rb_sw_get_monitor_isolation_enable,
+		.max = 1
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_mirror_pause_frames",
+		.description = "Enable mirroring of RX pause frames",
+		.set = rtl8366rb_sw_set_mirror_pause_frames_enable,
+		.get = rtl8366rb_sw_get_mirror_pause_frames_enable,
+		.max = 1
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "mirror_monitor_port",
+		.description = "Mirror monitor port",
+		.set = rtl8366rb_sw_set_mirror_monitor_port,
+		.get = rtl8366rb_sw_get_mirror_monitor_port,
+		.max = 5
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "mirror_source_port",
+		.description = "Mirror source port",
+		.set = rtl8366rb_sw_set_mirror_source_port,
+		.get = rtl8366rb_sw_get_mirror_source_port,
+		.max = 5
+	},
+};
+
+static struct switch_attr rtl8366rb_port[] = {
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mib",
+		.description = "Reset single port MIB counters",
+		.set = rtl8366rb_sw_reset_port_mibs,
+	}, {
+		.type = SWITCH_TYPE_STRING,
+		.name = "mib",
+		.description = "Get MIB counters for port",
+		.max = 33,
+		.set = NULL,
+		.get = rtl8366_sw_get_port_mib,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "led",
+		.description = "Get/Set port group (0 - 3) led mode (0 - 15)",
+		.max = 15,
+		.set = rtl8366rb_sw_set_port_led,
+		.get = rtl8366rb_sw_get_port_led,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "disable",
+		.description = "Get/Set port state (enabled or disabled)",
+		.max = 1,
+		.set = rtl8366rb_sw_set_port_disable,
+		.get = rtl8366rb_sw_get_port_disable,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "rate_in",
+		.description = "Get/Set port ingress (incoming) bandwidth limit in kbps",
+		.max = RTL8366RB_BDTH_SW_MAX,
+		.set = rtl8366rb_sw_set_port_rate_in,
+		.get = rtl8366rb_sw_get_port_rate_in,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "rate_out",
+		.description = "Get/Set port egress (outgoing) bandwidth limit in kbps",
+		.max = RTL8366RB_BDTH_SW_MAX,
+		.set = rtl8366rb_sw_set_port_rate_out,
+		.get = rtl8366rb_sw_get_port_rate_out,
+	},
+};
+
+static struct switch_attr rtl8366rb_vlan[] = {
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "info",
+		.description = "Get vlan information",
+		.max = 1,
+		.set = NULL,
+		.get = rtl8366_sw_get_vlan_info,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "fid",
+		.description = "Get/Set vlan FID",
+		.max = RTL8366RB_FIDMAX,
+		.set = rtl8366_sw_set_vlan_fid,
+		.get = rtl8366_sw_get_vlan_fid,
+	},
+};
+
+static const struct switch_dev_ops rtl8366_ops = {
+	.attr_global = {
+		.attr = rtl8366rb_globals,
+		.n_attr = ARRAY_SIZE(rtl8366rb_globals),
+	},
+	.attr_port = {
+		.attr = rtl8366rb_port,
+		.n_attr = ARRAY_SIZE(rtl8366rb_port),
+	},
+	.attr_vlan = {
+		.attr = rtl8366rb_vlan,
+		.n_attr = ARRAY_SIZE(rtl8366rb_vlan),
+	},
+
+	.get_vlan_ports = rtl8366_sw_get_vlan_ports,
+	.set_vlan_ports = rtl8366_sw_set_vlan_ports,
+	.get_port_pvid = rtl8366_sw_get_port_pvid,
+	.set_port_pvid = rtl8366_sw_set_port_pvid,
+	.reset_switch = rtl8366_sw_reset_switch,
+	.get_port_link = rtl8366rb_sw_get_port_link,
+	.get_port_stats = rtl8366rb_sw_get_port_stats,
+};
+
+static int rtl8366rb_switch_init(struct rtl8366_smi *smi)
+{
+	struct switch_dev *dev = &smi->sw_dev;
+	int err;
+
+	dev->name = "RTL8366RB";
+	dev->cpu_port = RTL8366RB_PORT_NUM_CPU;
+	dev->ports = RTL8366RB_NUM_PORTS;
+	dev->vlans = RTL8366RB_NUM_VIDS;
+	dev->ops = &rtl8366_ops;
+	dev->alias = dev_name(smi->parent);
+
+	err = register_switch(dev, NULL);
+	if (err)
+		dev_err(smi->parent, "switch registration failed\n");
+
+	return err;
+}
+
+static void rtl8366rb_switch_cleanup(struct rtl8366_smi *smi)
+{
+	unregister_switch(&smi->sw_dev);
+}
+
+static int rtl8366rb_mii_read(struct mii_bus *bus, int addr, int reg)
+{
+	struct rtl8366_smi *smi = bus->priv;
+	u32 val = 0;
+	int err;
+
+	err = rtl8366rb_read_phy_reg(smi, addr, 0, reg, &val);
+	if (err)
+		return 0xffff;
+
+	return val;
+}
+
+static int rtl8366rb_mii_write(struct mii_bus *bus, int addr, int reg, u16 val)
+{
+	struct rtl8366_smi *smi = bus->priv;
+	u32 t;
+	int err;
+
+	err = rtl8366rb_write_phy_reg(smi, addr, 0, reg, val);
+	/* flush write */
+	(void) rtl8366rb_read_phy_reg(smi, addr, 0, reg, &t);
+
+	return err;
+}
+
+static int rtl8366rb_detect(struct rtl8366_smi *smi)
+{
+	u32 chip_id = 0;
+	u32 chip_ver = 0;
+	int ret;
+
+	ret = rtl8366_smi_read_reg(smi, RTL8366RB_CHIP_ID_REG, &chip_id);
+	if (ret) {
+		dev_err(smi->parent, "unable to read chip id\n");
+		return ret;
+	}
+
+	switch (chip_id) {
+	case RTL8366RB_CHIP_ID_8366:
+		break;
+	default:
+		dev_err(smi->parent, "unknown chip id (%04x)\n", chip_id);
+		return -ENODEV;
+	}
+
+	ret = rtl8366_smi_read_reg(smi, RTL8366RB_CHIP_VERSION_CTRL_REG,
+				   &chip_ver);
+	if (ret) {
+		dev_err(smi->parent, "unable to read chip version\n");
+		return ret;
+	}
+
+	dev_info(smi->parent, "RTL%04x ver. %u chip found\n",
+		 chip_id, chip_ver & RTL8366RB_CHIP_VERSION_MASK);
+
+	return 0;
+}
+
+static struct rtl8366_smi_ops rtl8366rb_smi_ops = {
+	.detect		= rtl8366rb_detect,
+	.reset_chip	= rtl8366rb_reset_chip,
+	.setup		= rtl8366rb_setup,
+
+	.mii_read	= rtl8366rb_mii_read,
+	.mii_write	= rtl8366rb_mii_write,
+
+	.get_vlan_mc	= rtl8366rb_get_vlan_mc,
+	.set_vlan_mc	= rtl8366rb_set_vlan_mc,
+	.get_vlan_4k	= rtl8366rb_get_vlan_4k,
+	.set_vlan_4k	= rtl8366rb_set_vlan_4k,
+	.get_mc_index	= rtl8366rb_get_mc_index,
+	.set_mc_index	= rtl8366rb_set_mc_index,
+	.get_mib_counter = rtl8366rb_get_mib_counter,
+	.is_vlan_valid	= rtl8366rb_is_vlan_valid,
+	.enable_vlan	= rtl8366rb_enable_vlan,
+	.enable_vlan4k	= rtl8366rb_enable_vlan4k,
+	.enable_port	= rtl8366rb_enable_port,
+};
+
+static int rtl8366rb_probe(struct platform_device *pdev)
+{
+	static int rtl8366_smi_version_printed;
+	struct rtl8366_smi *smi;
+	int err;
+
+	if (!rtl8366_smi_version_printed++)
+		printk(KERN_NOTICE RTL8366RB_DRIVER_DESC
+		       " version " RTL8366RB_DRIVER_VER"\n");
+
+	smi = rtl8366_smi_probe(pdev);
+	if (IS_ERR(smi))
+		return PTR_ERR(smi);
+
+	smi->clk_delay = 10;
+	smi->cmd_read = 0xa9;
+	smi->cmd_write = 0xa8;
+	smi->ops = &rtl8366rb_smi_ops;
+	smi->cpu_port = RTL8366RB_PORT_NUM_CPU;
+	smi->num_ports = RTL8366RB_NUM_PORTS;
+	smi->num_vlan_mc = RTL8366RB_NUM_VLANS;
+	smi->mib_counters = rtl8366rb_mib_counters;
+	smi->num_mib_counters = ARRAY_SIZE(rtl8366rb_mib_counters);
+
+	err = rtl8366_smi_init(smi);
+	if (err)
+		goto err_free_smi;
+
+	platform_set_drvdata(pdev, smi);
+
+	err = rtl8366rb_switch_init(smi);
+	if (err)
+		goto err_clear_drvdata;
+
+	return 0;
+
+ err_clear_drvdata:
+	platform_set_drvdata(pdev, NULL);
+	rtl8366_smi_cleanup(smi);
+ err_free_smi:
+	kfree(smi);
+	return err;
+}
+
+static int rtl8366rb_remove(struct platform_device *pdev)
+{
+	struct rtl8366_smi *smi = platform_get_drvdata(pdev);
+
+	if (smi) {
+		rtl8366rb_switch_cleanup(smi);
+		platform_set_drvdata(pdev, NULL);
+		rtl8366_smi_cleanup(smi);
+		kfree(smi);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id rtl8366rb_match[] = {
+	{ .compatible = "realtek,rtl8366rb" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rtl8366rb_match);
+#endif
+
+static struct platform_driver rtl8366rb_driver = {
+	.driver = {
+		.name		= RTL8366RB_DRIVER_NAME,
+		.owner		= THIS_MODULE,
+		.of_match_table = of_match_ptr(rtl8366rb_match),
+	},
+	.probe		= rtl8366rb_probe,
+	.remove		= rtl8366rb_remove,
+};
+
+static int __init rtl8366rb_module_init(void)
+{
+	return platform_driver_register(&rtl8366rb_driver);
+}
+module_init(rtl8366rb_module_init);
+
+static void __exit rtl8366rb_module_exit(void)
+{
+	platform_driver_unregister(&rtl8366rb_driver);
+}
+module_exit(rtl8366rb_module_exit);
+
+MODULE_DESCRIPTION(RTL8366RB_DRIVER_DESC);
+MODULE_VERSION(RTL8366RB_DRIVER_VER);
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_AUTHOR("Antti Seppälä <a.seppala@gmail.com>");
+MODULE_AUTHOR("Roman Yeryomin <roman@advem.lv>");
+MODULE_AUTHOR("Colin Leitner <colin.leitner@googlemail.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" RTL8366RB_DRIVER_NAME);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/rtl8366s.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/rtl8366s.c
new file mode 100644
index 0000000..8c74677
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/rtl8366s.c
@@ -0,0 +1,1320 @@
+/*
+ * Platform driver for the Realtek RTL8366S ethernet switch
+ *
+ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2010 Antti Seppälä <a.seppala@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/rtl8366.h>
+
+#include "rtl8366_smi.h"
+
+#define RTL8366S_DRIVER_DESC	"Realtek RTL8366S ethernet switch driver"
+#define RTL8366S_DRIVER_VER	"0.2.2"
+
+#define RTL8366S_PHY_NO_MAX	4
+#define RTL8366S_PHY_PAGE_MAX	7
+#define RTL8366S_PHY_ADDR_MAX	31
+
+/* Switch Global Configuration register */
+#define RTL8366S_SGCR				0x0000
+#define RTL8366S_SGCR_EN_BC_STORM_CTRL		BIT(0)
+#define RTL8366S_SGCR_MAX_LENGTH(_x)		(_x << 4)
+#define RTL8366S_SGCR_MAX_LENGTH_MASK		RTL8366S_SGCR_MAX_LENGTH(0x3)
+#define RTL8366S_SGCR_MAX_LENGTH_1522		RTL8366S_SGCR_MAX_LENGTH(0x0)
+#define RTL8366S_SGCR_MAX_LENGTH_1536		RTL8366S_SGCR_MAX_LENGTH(0x1)
+#define RTL8366S_SGCR_MAX_LENGTH_1552		RTL8366S_SGCR_MAX_LENGTH(0x2)
+#define RTL8366S_SGCR_MAX_LENGTH_16000		RTL8366S_SGCR_MAX_LENGTH(0x3)
+#define RTL8366S_SGCR_EN_VLAN			BIT(13)
+
+/* Port Enable Control register */
+#define RTL8366S_PECR				0x0001
+
+/* Green Ethernet Feature (based on GPL_BELKIN_F5D8235-4_v1000 v1.01.24) */
+#define RTL8366S_GREEN_ETHERNET_CTRL_REG	0x000a
+#define RTL8366S_GREEN_ETHERNET_CTRL_MASK	0x0018
+#define RTL8366S_GREEN_ETHERNET_TX_BIT		(1 << 3)
+#define RTL8366S_GREEN_ETHERNET_RX_BIT		(1 << 4)
+
+/* Switch Security Control registers */
+#define RTL8366S_SSCR0				0x0002
+#define RTL8366S_SSCR1				0x0003
+#define RTL8366S_SSCR2				0x0004
+#define RTL8366S_SSCR2_DROP_UNKNOWN_DA		BIT(0)
+
+#define RTL8366S_RESET_CTRL_REG			0x0100
+#define RTL8366S_CHIP_CTRL_RESET_HW		1
+#define RTL8366S_CHIP_CTRL_RESET_SW		(1 << 1)
+
+#define RTL8366S_CHIP_VERSION_CTRL_REG		0x0104
+#define RTL8366S_CHIP_VERSION_MASK		0xf
+#define RTL8366S_CHIP_ID_REG			0x0105
+#define RTL8366S_CHIP_ID_8366			0x8366
+
+/* PHY registers control */
+#define RTL8366S_PHY_ACCESS_CTRL_REG		0x8028
+#define RTL8366S_PHY_ACCESS_DATA_REG		0x8029
+
+#define RTL8366S_PHY_CTRL_READ			1
+#define RTL8366S_PHY_CTRL_WRITE			0
+
+#define RTL8366S_PHY_REG_MASK			0x1f
+#define RTL8366S_PHY_PAGE_OFFSET		5
+#define RTL8366S_PHY_PAGE_MASK			(0x7 << 5)
+#define RTL8366S_PHY_NO_OFFSET			9
+#define RTL8366S_PHY_NO_MASK			(0x1f << 9)
+
+/* Green Ethernet Feature for PHY ports */
+#define RTL8366S_PHY_POWER_SAVING_CTRL_REG	12
+#define RTL8366S_PHY_POWER_SAVING_MASK		0x1000
+
+/* LED control registers */
+#define RTL8366S_LED_BLINKRATE_REG		0x0420
+#define RTL8366S_LED_BLINKRATE_BIT		0
+#define RTL8366S_LED_BLINKRATE_MASK		0x0007
+
+#define RTL8366S_LED_CTRL_REG			0x0421
+#define RTL8366S_LED_0_1_CTRL_REG		0x0422
+#define RTL8366S_LED_2_3_CTRL_REG		0x0423
+
+#define RTL8366S_MIB_COUNT			33
+#define RTL8366S_GLOBAL_MIB_COUNT		1
+#define RTL8366S_MIB_COUNTER_PORT_OFFSET	0x0040
+#define RTL8366S_MIB_COUNTER_BASE		0x1000
+#define RTL8366S_MIB_COUNTER_PORT_OFFSET2	0x0008
+#define RTL8366S_MIB_COUNTER_BASE2		0x1180
+#define RTL8366S_MIB_CTRL_REG			0x11F0
+#define RTL8366S_MIB_CTRL_USER_MASK		0x01FF
+#define RTL8366S_MIB_CTRL_BUSY_MASK		0x0001
+#define RTL8366S_MIB_CTRL_RESET_MASK		0x0002
+
+#define RTL8366S_MIB_CTRL_GLOBAL_RESET_MASK	0x0004
+#define RTL8366S_MIB_CTRL_PORT_RESET_BIT	0x0003
+#define RTL8366S_MIB_CTRL_PORT_RESET_MASK	0x01FC
+
+
+#define RTL8366S_PORT_VLAN_CTRL_BASE		0x0058
+#define RTL8366S_PORT_VLAN_CTRL_REG(_p)  \
+		(RTL8366S_PORT_VLAN_CTRL_BASE + (_p) / 4)
+#define RTL8366S_PORT_VLAN_CTRL_MASK		0xf
+#define RTL8366S_PORT_VLAN_CTRL_SHIFT(_p)	(4 * ((_p) % 4))
+
+
+#define RTL8366S_VLAN_TABLE_READ_BASE		0x018B
+#define RTL8366S_VLAN_TABLE_WRITE_BASE		0x0185
+
+#define RTL8366S_VLAN_TB_CTRL_REG		0x010F
+
+#define RTL8366S_TABLE_ACCESS_CTRL_REG		0x0180
+#define RTL8366S_TABLE_VLAN_READ_CTRL		0x0E01
+#define RTL8366S_TABLE_VLAN_WRITE_CTRL		0x0F01
+
+#define RTL8366S_VLAN_MC_BASE(_x)		(0x0016 + (_x) * 2)
+
+#define RTL8366S_VLAN_MEMBERINGRESS_REG		0x0379
+
+#define RTL8366S_PORT_LINK_STATUS_BASE		0x0060
+#define RTL8366S_PORT_STATUS_SPEED_MASK		0x0003
+#define RTL8366S_PORT_STATUS_DUPLEX_MASK	0x0004
+#define RTL8366S_PORT_STATUS_LINK_MASK		0x0010
+#define RTL8366S_PORT_STATUS_TXPAUSE_MASK	0x0020
+#define RTL8366S_PORT_STATUS_RXPAUSE_MASK	0x0040
+#define RTL8366S_PORT_STATUS_AN_MASK		0x0080
+
+
+#define RTL8366S_PORT_NUM_CPU		5
+#define RTL8366S_NUM_PORTS		6
+#define RTL8366S_NUM_VLANS		16
+#define RTL8366S_NUM_LEDGROUPS		4
+#define RTL8366S_NUM_VIDS		4096
+#define RTL8366S_PRIORITYMAX		7
+#define RTL8366S_FIDMAX			7
+
+
+#define RTL8366S_PORT_1			(1 << 0) /* In userspace port 0 */
+#define RTL8366S_PORT_2			(1 << 1) /* In userspace port 1 */
+#define RTL8366S_PORT_3			(1 << 2) /* In userspace port 2 */
+#define RTL8366S_PORT_4			(1 << 3) /* In userspace port 3 */
+
+#define RTL8366S_PORT_UNKNOWN		(1 << 4) /* No known connection */
+#define RTL8366S_PORT_CPU		(1 << 5) /* CPU port */
+
+#define RTL8366S_PORT_ALL		(RTL8366S_PORT_1 |	\
+					 RTL8366S_PORT_2 |	\
+					 RTL8366S_PORT_3 |	\
+					 RTL8366S_PORT_4 |	\
+					 RTL8366S_PORT_UNKNOWN | \
+					 RTL8366S_PORT_CPU)
+
+#define RTL8366S_PORT_ALL_BUT_CPU	(RTL8366S_PORT_1 |	\
+					 RTL8366S_PORT_2 |	\
+					 RTL8366S_PORT_3 |	\
+					 RTL8366S_PORT_4 |	\
+					 RTL8366S_PORT_UNKNOWN)
+
+#define RTL8366S_PORT_ALL_EXTERNAL	(RTL8366S_PORT_1 |	\
+					 RTL8366S_PORT_2 |	\
+					 RTL8366S_PORT_3 |	\
+					 RTL8366S_PORT_4)
+
+#define RTL8366S_PORT_ALL_INTERNAL	(RTL8366S_PORT_UNKNOWN | \
+					 RTL8366S_PORT_CPU)
+
+#define RTL8366S_VLAN_VID_MASK		0xfff
+#define RTL8366S_VLAN_PRIORITY_SHIFT	12
+#define RTL8366S_VLAN_PRIORITY_MASK	0x7
+#define RTL8366S_VLAN_MEMBER_MASK	0x3f
+#define RTL8366S_VLAN_UNTAG_SHIFT	6
+#define RTL8366S_VLAN_UNTAG_MASK	0x3f
+#define RTL8366S_VLAN_FID_SHIFT		12
+#define RTL8366S_VLAN_FID_MASK		0x7
+
+#define RTL8366S_MIB_RXB_ID		0	/* IfInOctets */
+#define RTL8366S_MIB_TXB_ID		20	/* IfOutOctets */
+
+static struct rtl8366_mib_counter rtl8366s_mib_counters[] = {
+	{ 0,  0, 4, "IfInOctets"				},
+	{ 0,  4, 4, "EtherStatsOctets"				},
+	{ 0,  8, 2, "EtherStatsUnderSizePkts"			},
+	{ 0, 10, 2, "EtherFragments"				},
+	{ 0, 12, 2, "EtherStatsPkts64Octets"			},
+	{ 0, 14, 2, "EtherStatsPkts65to127Octets"		},
+	{ 0, 16, 2, "EtherStatsPkts128to255Octets"		},
+	{ 0, 18, 2, "EtherStatsPkts256to511Octets"		},
+	{ 0, 20, 2, "EtherStatsPkts512to1023Octets"		},
+	{ 0, 22, 2, "EtherStatsPkts1024to1518Octets"		},
+	{ 0, 24, 2, "EtherOversizeStats"			},
+	{ 0, 26, 2, "EtherStatsJabbers"				},
+	{ 0, 28, 2, "IfInUcastPkts"				},
+	{ 0, 30, 2, "EtherStatsMulticastPkts"			},
+	{ 0, 32, 2, "EtherStatsBroadcastPkts"			},
+	{ 0, 34, 2, "EtherStatsDropEvents"			},
+	{ 0, 36, 2, "Dot3StatsFCSErrors"			},
+	{ 0, 38, 2, "Dot3StatsSymbolErrors"			},
+	{ 0, 40, 2, "Dot3InPauseFrames"				},
+	{ 0, 42, 2, "Dot3ControlInUnknownOpcodes"		},
+	{ 0, 44, 4, "IfOutOctets"				},
+	{ 0, 48, 2, "Dot3StatsSingleCollisionFrames"		},
+	{ 0, 50, 2, "Dot3StatMultipleCollisionFrames"		},
+	{ 0, 52, 2, "Dot3sDeferredTransmissions"		},
+	{ 0, 54, 2, "Dot3StatsLateCollisions"			},
+	{ 0, 56, 2, "EtherStatsCollisions"			},
+	{ 0, 58, 2, "Dot3StatsExcessiveCollisions"		},
+	{ 0, 60, 2, "Dot3OutPauseFrames"			},
+	{ 0, 62, 2, "Dot1dBasePortDelayExceededDiscards"	},
+
+	/*
+	 * The following counters are accessible at a different
+	 * base address.
+	 */
+	{ 1,  0, 2, "Dot1dTpPortInDiscards"			},
+	{ 1,  2, 2, "IfOutUcastPkts"				},
+	{ 1,  4, 2, "IfOutMulticastPkts"			},
+	{ 1,  6, 2, "IfOutBroadcastPkts"			},
+};
+
+#define REG_WR(_smi, _reg, _val)					\
+	do {								\
+		err = rtl8366_smi_write_reg(_smi, _reg, _val);		\
+		if (err)						\
+			return err;					\
+	} while (0)
+
+#define REG_RMW(_smi, _reg, _mask, _val)				\
+	do {								\
+		err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val);	\
+		if (err)						\
+			return err;					\
+	} while (0)
+
+static int rtl8366s_reset_chip(struct rtl8366_smi *smi)
+{
+	int timeout = 10;
+	u32 data;
+
+	rtl8366_smi_write_reg_noack(smi, RTL8366S_RESET_CTRL_REG,
+				    RTL8366S_CHIP_CTRL_RESET_HW);
+	do {
+		msleep(1);
+		if (rtl8366_smi_read_reg(smi, RTL8366S_RESET_CTRL_REG, &data))
+			return -EIO;
+
+		if (!(data & RTL8366S_CHIP_CTRL_RESET_HW))
+			break;
+	} while (--timeout);
+
+	if (!timeout) {
+		printk("Timeout waiting for the switch to reset\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int rtl8366s_read_phy_reg(struct rtl8366_smi *smi,
+				 u32 phy_no, u32 page, u32 addr, u32 *data)
+{
+	u32 reg;
+	int ret;
+
+	if (phy_no > RTL8366S_PHY_NO_MAX)
+		return -EINVAL;
+
+	if (page > RTL8366S_PHY_PAGE_MAX)
+		return -EINVAL;
+
+	if (addr > RTL8366S_PHY_ADDR_MAX)
+		return -EINVAL;
+
+	ret = rtl8366_smi_write_reg(smi, RTL8366S_PHY_ACCESS_CTRL_REG,
+				    RTL8366S_PHY_CTRL_READ);
+	if (ret)
+		return ret;
+
+	reg = 0x8000 | (1 << (phy_no + RTL8366S_PHY_NO_OFFSET)) |
+	      ((page << RTL8366S_PHY_PAGE_OFFSET) & RTL8366S_PHY_PAGE_MASK) |
+	      (addr & RTL8366S_PHY_REG_MASK);
+
+	ret = rtl8366_smi_write_reg(smi, reg, 0);
+	if (ret)
+		return ret;
+
+	ret = rtl8366_smi_read_reg(smi, RTL8366S_PHY_ACCESS_DATA_REG, data);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int rtl8366s_write_phy_reg(struct rtl8366_smi *smi,
+				  u32 phy_no, u32 page, u32 addr, u32 data)
+{
+	u32 reg;
+	int ret;
+
+	if (phy_no > RTL8366S_PHY_NO_MAX)
+		return -EINVAL;
+
+	if (page > RTL8366S_PHY_PAGE_MAX)
+		return -EINVAL;
+
+	if (addr > RTL8366S_PHY_ADDR_MAX)
+		return -EINVAL;
+
+	ret = rtl8366_smi_write_reg(smi, RTL8366S_PHY_ACCESS_CTRL_REG,
+				    RTL8366S_PHY_CTRL_WRITE);
+	if (ret)
+		return ret;
+
+	reg = 0x8000 | (1 << (phy_no + RTL8366S_PHY_NO_OFFSET)) |
+	      ((page << RTL8366S_PHY_PAGE_OFFSET) & RTL8366S_PHY_PAGE_MASK) |
+	      (addr & RTL8366S_PHY_REG_MASK);
+
+	ret = rtl8366_smi_write_reg(smi, reg, data);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int rtl8366s_set_green_port(struct rtl8366_smi *smi, int port, int enable)
+{
+	int err;
+	u32 phyData;
+
+	if (port >= RTL8366S_NUM_PORTS)
+		return -EINVAL;
+
+	err = rtl8366s_read_phy_reg(smi, port, 0, RTL8366S_PHY_POWER_SAVING_CTRL_REG, &phyData);
+	if (err)
+		return err;
+
+	if (enable)
+		phyData |= RTL8366S_PHY_POWER_SAVING_MASK;
+	else
+		phyData &= ~RTL8366S_PHY_POWER_SAVING_MASK;
+
+	err = rtl8366s_write_phy_reg(smi, port, 0, RTL8366S_PHY_POWER_SAVING_CTRL_REG, phyData);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int rtl8366s_set_green(struct rtl8366_smi *smi, int enable)
+{
+	int err;
+	unsigned i;
+	u32 data = 0;
+
+	if (!enable) {
+		for (i = 0; i <= RTL8366S_PHY_NO_MAX; i++) {
+			rtl8366s_set_green_port(smi, i, 0);
+		}
+	}
+
+	if (enable)
+		data = (RTL8366S_GREEN_ETHERNET_TX_BIT | RTL8366S_GREEN_ETHERNET_RX_BIT);
+
+	REG_RMW(smi, RTL8366S_GREEN_ETHERNET_CTRL_REG, RTL8366S_GREEN_ETHERNET_CTRL_MASK, data);
+
+	return 0;
+}
+
+static int rtl8366s_setup(struct rtl8366_smi *smi)
+{
+	struct rtl8366_platform_data *pdata;
+	int err;
+	unsigned i;
+#ifdef CONFIG_OF
+	struct device_node *np;
+	unsigned num_initvals;
+	const __be32 *paddr;
+#endif
+
+	pdata = smi->parent->platform_data;
+	if (pdata && pdata->num_initvals && pdata->initvals) {
+		dev_info(smi->parent, "applying initvals\n");
+		for (i = 0; i < pdata->num_initvals; i++)
+			REG_WR(smi, pdata->initvals[i].reg,
+			       pdata->initvals[i].val);
+	}
+
+#ifdef CONFIG_OF
+	np = smi->parent->of_node;
+
+	paddr = of_get_property(np, "realtek,initvals", &num_initvals);
+	if (paddr) {
+		dev_info(smi->parent, "applying initvals from DTS\n");
+
+		if (num_initvals < (2 * sizeof(*paddr)))
+			return -EINVAL;
+
+		num_initvals /= sizeof(*paddr);
+
+		for (i = 0; i < num_initvals - 1; i += 2) {
+			u32 reg = be32_to_cpup(paddr + i);
+			u32 val = be32_to_cpup(paddr + i + 1);
+
+			REG_WR(smi, reg, val);
+		}
+	}
+
+	if (of_property_read_bool(np, "realtek,green-ethernet-features")) {
+		dev_info(smi->parent, "activating Green Ethernet features\n");
+
+		err = rtl8366s_set_green(smi, 1);
+		if (err)
+			return err;
+
+		for (i = 0; i <= RTL8366S_PHY_NO_MAX; i++) {
+			err = rtl8366s_set_green_port(smi, i, 1);
+			if (err)
+				return err;
+		}
+	}
+#endif
+
+	/* set maximum packet length to 1536 bytes */
+	REG_RMW(smi, RTL8366S_SGCR, RTL8366S_SGCR_MAX_LENGTH_MASK,
+		RTL8366S_SGCR_MAX_LENGTH_1536);
+
+	/* enable learning for all ports */
+	REG_WR(smi, RTL8366S_SSCR0, 0);
+
+	/* enable auto ageing for all ports */
+	REG_WR(smi, RTL8366S_SSCR1, 0);
+
+	/*
+	 * discard VLAN tagged packets if the port is not a member of
+	 * the VLAN with which the packets is associated.
+	 */
+	REG_WR(smi, RTL8366S_VLAN_MEMBERINGRESS_REG, RTL8366S_PORT_ALL);
+
+	/* don't drop packets whose DA has not been learned */
+	REG_RMW(smi, RTL8366S_SSCR2, RTL8366S_SSCR2_DROP_UNKNOWN_DA, 0);
+
+	return 0;
+}
+
+static int rtl8366_get_mib_counter(struct rtl8366_smi *smi, int counter,
+				   int port, unsigned long long *val)
+{
+	int i;
+	int err;
+	u32 addr, data;
+	u64 mibvalue;
+
+	if (port > RTL8366S_NUM_PORTS || counter >= RTL8366S_MIB_COUNT)
+		return -EINVAL;
+
+	switch (rtl8366s_mib_counters[counter].base) {
+	case 0:
+		addr = RTL8366S_MIB_COUNTER_BASE +
+		       RTL8366S_MIB_COUNTER_PORT_OFFSET * port;
+		break;
+
+	case 1:
+		addr = RTL8366S_MIB_COUNTER_BASE2 +
+			RTL8366S_MIB_COUNTER_PORT_OFFSET2 * port;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	addr += rtl8366s_mib_counters[counter].offset;
+
+	/*
+	 * Writing access counter address first
+	 * then ASIC will prepare 64bits counter wait for being retrived
+	 */
+	data = 0; /* writing data will be discard by ASIC */
+	err = rtl8366_smi_write_reg(smi, addr, data);
+	if (err)
+		return err;
+
+	/* read MIB control register */
+	err =  rtl8366_smi_read_reg(smi, RTL8366S_MIB_CTRL_REG, &data);
+	if (err)
+		return err;
+
+	if (data & RTL8366S_MIB_CTRL_BUSY_MASK)
+		return -EBUSY;
+
+	if (data & RTL8366S_MIB_CTRL_RESET_MASK)
+		return -EIO;
+
+	mibvalue = 0;
+	for (i = rtl8366s_mib_counters[counter].length; i > 0; i--) {
+		err = rtl8366_smi_read_reg(smi, addr + (i - 1), &data);
+		if (err)
+			return err;
+
+		mibvalue = (mibvalue << 16) | (data & 0xFFFF);
+	}
+
+	*val = mibvalue;
+	return 0;
+}
+
+static int rtl8366s_get_vlan_4k(struct rtl8366_smi *smi, u32 vid,
+				struct rtl8366_vlan_4k *vlan4k)
+{
+	u32 data[2];
+	int err;
+	int i;
+
+	memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k));
+
+	if (vid >= RTL8366S_NUM_VIDS)
+		return -EINVAL;
+
+	/* write VID */
+	err = rtl8366_smi_write_reg(smi, RTL8366S_VLAN_TABLE_WRITE_BASE,
+				    vid & RTL8366S_VLAN_VID_MASK);
+	if (err)
+		return err;
+
+	/* write table access control word */
+	err = rtl8366_smi_write_reg(smi, RTL8366S_TABLE_ACCESS_CTRL_REG,
+				    RTL8366S_TABLE_VLAN_READ_CTRL);
+	if (err)
+		return err;
+
+	for (i = 0; i < 2; i++) {
+		err = rtl8366_smi_read_reg(smi,
+					   RTL8366S_VLAN_TABLE_READ_BASE + i,
+					   &data[i]);
+		if (err)
+			return err;
+	}
+
+	vlan4k->vid = vid;
+	vlan4k->untag = (data[1] >> RTL8366S_VLAN_UNTAG_SHIFT) &
+			RTL8366S_VLAN_UNTAG_MASK;
+	vlan4k->member = data[1] & RTL8366S_VLAN_MEMBER_MASK;
+	vlan4k->fid = (data[1] >> RTL8366S_VLAN_FID_SHIFT) &
+			RTL8366S_VLAN_FID_MASK;
+
+	return 0;
+}
+
+static int rtl8366s_set_vlan_4k(struct rtl8366_smi *smi,
+				const struct rtl8366_vlan_4k *vlan4k)
+{
+	u32 data[2];
+	int err;
+	int i;
+
+	if (vlan4k->vid >= RTL8366S_NUM_VIDS ||
+	    vlan4k->member > RTL8366S_VLAN_MEMBER_MASK ||
+	    vlan4k->untag > RTL8366S_VLAN_UNTAG_MASK ||
+	    vlan4k->fid > RTL8366S_FIDMAX)
+		return -EINVAL;
+
+	data[0] = vlan4k->vid & RTL8366S_VLAN_VID_MASK;
+	data[1] = (vlan4k->member & RTL8366S_VLAN_MEMBER_MASK) |
+		  ((vlan4k->untag & RTL8366S_VLAN_UNTAG_MASK) <<
+			RTL8366S_VLAN_UNTAG_SHIFT) |
+		  ((vlan4k->fid & RTL8366S_VLAN_FID_MASK) <<
+			RTL8366S_VLAN_FID_SHIFT);
+
+	for (i = 0; i < 2; i++) {
+		err = rtl8366_smi_write_reg(smi,
+					    RTL8366S_VLAN_TABLE_WRITE_BASE + i,
+					    data[i]);
+		if (err)
+			return err;
+	}
+
+	/* write table access control word */
+	err = rtl8366_smi_write_reg(smi, RTL8366S_TABLE_ACCESS_CTRL_REG,
+				    RTL8366S_TABLE_VLAN_WRITE_CTRL);
+
+	return err;
+}
+
+static int rtl8366s_get_vlan_mc(struct rtl8366_smi *smi, u32 index,
+				struct rtl8366_vlan_mc *vlanmc)
+{
+	u32 data[2];
+	int err;
+	int i;
+
+	memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc));
+
+	if (index >= RTL8366S_NUM_VLANS)
+		return -EINVAL;
+
+	for (i = 0; i < 2; i++) {
+		err = rtl8366_smi_read_reg(smi,
+					   RTL8366S_VLAN_MC_BASE(index) + i,
+					   &data[i]);
+		if (err)
+			return err;
+	}
+
+	vlanmc->vid = data[0] & RTL8366S_VLAN_VID_MASK;
+	vlanmc->priority = (data[0] >> RTL8366S_VLAN_PRIORITY_SHIFT) &
+			   RTL8366S_VLAN_PRIORITY_MASK;
+	vlanmc->untag = (data[1] >> RTL8366S_VLAN_UNTAG_SHIFT) &
+			RTL8366S_VLAN_UNTAG_MASK;
+	vlanmc->member = data[1] & RTL8366S_VLAN_MEMBER_MASK;
+	vlanmc->fid = (data[1] >> RTL8366S_VLAN_FID_SHIFT) &
+		      RTL8366S_VLAN_FID_MASK;
+
+	return 0;
+}
+
+static int rtl8366s_set_vlan_mc(struct rtl8366_smi *smi, u32 index,
+				const struct rtl8366_vlan_mc *vlanmc)
+{
+	u32 data[2];
+	int err;
+	int i;
+
+	if (index >= RTL8366S_NUM_VLANS ||
+	    vlanmc->vid >= RTL8366S_NUM_VIDS ||
+	    vlanmc->priority > RTL8366S_PRIORITYMAX ||
+	    vlanmc->member > RTL8366S_VLAN_MEMBER_MASK ||
+	    vlanmc->untag > RTL8366S_VLAN_UNTAG_MASK ||
+	    vlanmc->fid > RTL8366S_FIDMAX)
+		return -EINVAL;
+
+	data[0] = (vlanmc->vid & RTL8366S_VLAN_VID_MASK) |
+		  ((vlanmc->priority & RTL8366S_VLAN_PRIORITY_MASK) <<
+			RTL8366S_VLAN_PRIORITY_SHIFT);
+	data[1] = (vlanmc->member & RTL8366S_VLAN_MEMBER_MASK) |
+		  ((vlanmc->untag & RTL8366S_VLAN_UNTAG_MASK) <<
+			RTL8366S_VLAN_UNTAG_SHIFT) |
+		  ((vlanmc->fid & RTL8366S_VLAN_FID_MASK) <<
+			RTL8366S_VLAN_FID_SHIFT);
+
+	for (i = 0; i < 2; i++) {
+		err = rtl8366_smi_write_reg(smi,
+					    RTL8366S_VLAN_MC_BASE(index) + i,
+					    data[i]);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int rtl8366s_get_mc_index(struct rtl8366_smi *smi, int port, int *val)
+{
+	u32 data;
+	int err;
+
+	if (port >= RTL8366S_NUM_PORTS)
+		return -EINVAL;
+
+	err = rtl8366_smi_read_reg(smi, RTL8366S_PORT_VLAN_CTRL_REG(port),
+				   &data);
+	if (err)
+		return err;
+
+	*val = (data >> RTL8366S_PORT_VLAN_CTRL_SHIFT(port)) &
+	       RTL8366S_PORT_VLAN_CTRL_MASK;
+
+	return 0;
+}
+
+static int rtl8366s_set_mc_index(struct rtl8366_smi *smi, int port, int index)
+{
+	if (port >= RTL8366S_NUM_PORTS || index >= RTL8366S_NUM_VLANS)
+		return -EINVAL;
+
+	return rtl8366_smi_rmwr(smi, RTL8366S_PORT_VLAN_CTRL_REG(port),
+				RTL8366S_PORT_VLAN_CTRL_MASK <<
+					RTL8366S_PORT_VLAN_CTRL_SHIFT(port),
+				(index & RTL8366S_PORT_VLAN_CTRL_MASK) <<
+					RTL8366S_PORT_VLAN_CTRL_SHIFT(port));
+}
+
+static int rtl8366s_enable_vlan(struct rtl8366_smi *smi, int enable)
+{
+	return rtl8366_smi_rmwr(smi, RTL8366S_SGCR, RTL8366S_SGCR_EN_VLAN,
+				(enable) ? RTL8366S_SGCR_EN_VLAN : 0);
+}
+
+static int rtl8366s_enable_vlan4k(struct rtl8366_smi *smi, int enable)
+{
+	return rtl8366_smi_rmwr(smi, RTL8366S_VLAN_TB_CTRL_REG,
+				1, (enable) ? 1 : 0);
+}
+
+static int rtl8366s_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan)
+{
+	unsigned max = RTL8366S_NUM_VLANS;
+
+	if (smi->vlan4k_enabled)
+		max = RTL8366S_NUM_VIDS - 1;
+
+	if (vlan == 0 || vlan >= max)
+		return 0;
+
+	return 1;
+}
+
+static int rtl8366s_enable_port(struct rtl8366_smi *smi, int port, int enable)
+{
+	return rtl8366_smi_rmwr(smi, RTL8366S_PECR, (1 << port),
+				(enable) ? 0 : (1 << port));
+}
+
+static int rtl8366s_sw_reset_mibs(struct switch_dev *dev,
+				  const struct switch_attr *attr,
+				  struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	return rtl8366_smi_rmwr(smi, RTL8366S_MIB_CTRL_REG, 0, (1 << 2));
+}
+
+static int rtl8366s_sw_get_blinkrate(struct switch_dev *dev,
+				     const struct switch_attr *attr,
+				     struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366S_LED_BLINKRATE_REG, &data);
+
+	val->value.i = (data & (RTL8366S_LED_BLINKRATE_MASK));
+
+	return 0;
+}
+
+static int rtl8366s_sw_set_blinkrate(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	if (val->value.i >= 6)
+		return -EINVAL;
+
+	return rtl8366_smi_rmwr(smi, RTL8366S_LED_BLINKRATE_REG,
+				RTL8366S_LED_BLINKRATE_MASK,
+				val->value.i);
+}
+
+static int rtl8366s_sw_get_max_length(struct switch_dev *dev,
+					const struct switch_attr *attr,
+					struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8366S_SGCR, &data);
+
+	val->value.i = ((data & (RTL8366S_SGCR_MAX_LENGTH_MASK)) >> 4);
+
+	return 0;
+}
+
+static int rtl8366s_sw_set_max_length(struct switch_dev *dev,
+					const struct switch_attr *attr,
+					struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	char length_code;
+
+	switch (val->value.i) {
+		case 0:
+			length_code = RTL8366S_SGCR_MAX_LENGTH_1522;
+			break;
+		case 1:
+			length_code = RTL8366S_SGCR_MAX_LENGTH_1536;
+			break;
+		case 2:
+			length_code = RTL8366S_SGCR_MAX_LENGTH_1552;
+			break;
+		case 3:
+			length_code = RTL8366S_SGCR_MAX_LENGTH_16000;
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	return rtl8366_smi_rmwr(smi, RTL8366S_SGCR,
+			RTL8366S_SGCR_MAX_LENGTH_MASK,
+			length_code);
+}
+
+static int rtl8366s_sw_get_learning_enable(struct switch_dev *dev,
+					   const struct switch_attr *attr,
+					   struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi,RTL8366S_SSCR0, &data);
+	val->value.i = !data;
+
+	return 0;
+}
+
+
+static int rtl8366s_sw_set_learning_enable(struct switch_dev *dev,
+					   const struct switch_attr *attr,
+					   struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 portmask = 0;
+	int err = 0;
+
+	if (!val->value.i)
+		portmask = RTL8366S_PORT_ALL;
+
+	/* set learning for all ports */
+	REG_WR(smi, RTL8366S_SSCR0, portmask);
+
+	/* set auto ageing for all ports */
+	REG_WR(smi, RTL8366S_SSCR1, portmask);
+
+	return 0;
+}
+
+static int rtl8366s_sw_get_green(struct switch_dev *dev,
+			      const struct switch_attr *attr,
+			      struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+	int err;
+
+	err = rtl8366_smi_read_reg(smi, RTL8366S_GREEN_ETHERNET_CTRL_REG, &data);
+	if (err)
+		return err;
+
+	val->value.i = ((data & (RTL8366S_GREEN_ETHERNET_TX_BIT | RTL8366S_GREEN_ETHERNET_RX_BIT)) != 0) ? 1 : 0;
+
+	return 0;
+}
+
+static int rtl8366s_sw_set_green(struct switch_dev *dev,
+				 const struct switch_attr *attr,
+				 struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	return rtl8366s_set_green(smi, val->value.i);
+}
+
+static int rtl8366s_sw_get_port_link(struct switch_dev *dev,
+				     int port,
+				     struct switch_port_link *link)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data = 0;
+	u32 speed;
+
+	if (port >= RTL8366S_NUM_PORTS)
+		return -EINVAL;
+
+	rtl8366_smi_read_reg(smi, RTL8366S_PORT_LINK_STATUS_BASE + (port / 2),
+			     &data);
+
+	if (port % 2)
+		data = data >> 8;
+
+	link->link = !!(data & RTL8366S_PORT_STATUS_LINK_MASK);
+	if (!link->link)
+		return 0;
+
+	link->duplex = !!(data & RTL8366S_PORT_STATUS_DUPLEX_MASK);
+	link->rx_flow = !!(data & RTL8366S_PORT_STATUS_RXPAUSE_MASK);
+	link->tx_flow = !!(data & RTL8366S_PORT_STATUS_TXPAUSE_MASK);
+	link->aneg = !!(data & RTL8366S_PORT_STATUS_AN_MASK);
+
+	speed = (data & RTL8366S_PORT_STATUS_SPEED_MASK);
+	switch (speed) {
+	case 0:
+		link->speed = SWITCH_PORT_SPEED_10;
+		break;
+	case 1:
+		link->speed = SWITCH_PORT_SPEED_100;
+		break;
+	case 2:
+		link->speed = SWITCH_PORT_SPEED_1000;
+		break;
+	default:
+		link->speed = SWITCH_PORT_SPEED_UNKNOWN;
+		break;
+	}
+
+	return 0;
+}
+
+static int rtl8366s_sw_set_port_led(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+	u32 mask;
+	u32 reg;
+
+	if (val->port_vlan >= RTL8366S_NUM_PORTS ||
+	    (1 << val->port_vlan) == RTL8366S_PORT_UNKNOWN)
+		return -EINVAL;
+
+	if (val->port_vlan == RTL8366S_PORT_NUM_CPU) {
+		reg = RTL8366S_LED_BLINKRATE_REG;
+		mask = 0xF << 4;
+		data = val->value.i << 4;
+	} else {
+		reg = RTL8366S_LED_CTRL_REG;
+		mask = 0xF << (val->port_vlan * 4),
+		data = val->value.i << (val->port_vlan * 4);
+	}
+
+	return rtl8366_smi_rmwr(smi, reg, mask, data);
+}
+
+static int rtl8366s_sw_get_port_led(struct switch_dev *dev,
+				    const struct switch_attr *attr,
+				    struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data = 0;
+
+	if (val->port_vlan >= RTL8366S_NUM_LEDGROUPS)
+		return -EINVAL;
+
+	rtl8366_smi_read_reg(smi, RTL8366S_LED_CTRL_REG, &data);
+	val->value.i = (data >> (val->port_vlan * 4)) & 0x000F;
+
+	return 0;
+}
+
+static int rtl8366s_sw_get_green_port(struct switch_dev *dev,
+				      const struct switch_attr *attr,
+				      struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	int err;
+	u32 phyData;
+
+	if (val->port_vlan >= RTL8366S_NUM_PORTS)
+		return -EINVAL;
+
+	err = rtl8366s_read_phy_reg(smi, val->port_vlan, 0, RTL8366S_PHY_POWER_SAVING_CTRL_REG, &phyData);
+	if (err)
+		return err;
+
+	val->value.i = ((phyData & RTL8366S_PHY_POWER_SAVING_MASK) != 0) ? 1 : 0;
+
+	return 0;
+}
+
+static int rtl8366s_sw_set_green_port(struct switch_dev *dev,
+				      const struct switch_attr *attr,
+				      struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	return rtl8366s_set_green_port(smi, val->port_vlan, val->value.i);
+}
+
+static int rtl8366s_sw_reset_port_mibs(struct switch_dev *dev,
+				       const struct switch_attr *attr,
+				       struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	if (val->port_vlan >= RTL8366S_NUM_PORTS)
+		return -EINVAL;
+
+
+	return rtl8366_smi_rmwr(smi, RTL8366S_MIB_CTRL_REG,
+				0, (1 << (val->port_vlan + 3)));
+}
+
+static int rtl8366s_sw_get_port_stats(struct switch_dev *dev, int port,
+                                        struct switch_port_stats *stats)
+{
+	return (rtl8366_sw_get_port_stats(dev, port, stats,
+				RTL8366S_MIB_TXB_ID, RTL8366S_MIB_RXB_ID));
+}
+
+static struct switch_attr rtl8366s_globals[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_learning",
+		.description = "Enable learning, enable aging",
+		.set = rtl8366s_sw_set_learning_enable,
+		.get = rtl8366s_sw_get_learning_enable,
+		.max = 1,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.set = rtl8366_sw_set_vlan_enable,
+		.get = rtl8366_sw_get_vlan_enable,
+		.max = 1,
+		.ofs = 1
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan4k",
+		.description = "Enable VLAN 4K mode",
+		.set = rtl8366_sw_set_vlan_enable,
+		.get = rtl8366_sw_get_vlan_enable,
+		.max = 1,
+		.ofs = 2
+	}, {
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mibs",
+		.description = "Reset all MIB counters",
+		.set = rtl8366s_sw_reset_mibs,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "blinkrate",
+		.description = "Get/Set LED blinking rate (0 = 43ms, 1 = 84ms,"
+		" 2 = 120ms, 3 = 170ms, 4 = 340ms, 5 = 670ms)",
+		.set = rtl8366s_sw_set_blinkrate,
+		.get = rtl8366s_sw_get_blinkrate,
+		.max = 5
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "max_length",
+		.description = "Get/Set the maximum length of valid packets"
+		" (0 = 1522, 1 = 1536, 2 = 1552, 3 = 16000 (9216?))",
+		.set = rtl8366s_sw_set_max_length,
+		.get = rtl8366s_sw_get_max_length,
+		.max = 3,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "green_mode",
+		.description = "Get/Set the router green feature",
+		.set = rtl8366s_sw_set_green,
+		.get = rtl8366s_sw_get_green,
+		.max = 1,
+	},
+};
+
+static struct switch_attr rtl8366s_port[] = {
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mib",
+		.description = "Reset single port MIB counters",
+		.set = rtl8366s_sw_reset_port_mibs,
+	}, {
+		.type = SWITCH_TYPE_STRING,
+		.name = "mib",
+		.description = "Get MIB counters for port",
+		.max = 33,
+		.set = NULL,
+		.get = rtl8366_sw_get_port_mib,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "led",
+		.description = "Get/Set port group (0 - 3) led mode (0 - 15)",
+		.max = 15,
+		.set = rtl8366s_sw_set_port_led,
+		.get = rtl8366s_sw_get_port_led,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "green_port",
+		.description = "Get/Set port green feature (0 - 1)",
+		.max = 1,
+		.set = rtl8366s_sw_set_green_port,
+		.get = rtl8366s_sw_get_green_port,
+	},
+};
+
+static struct switch_attr rtl8366s_vlan[] = {
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "info",
+		.description = "Get vlan information",
+		.max = 1,
+		.set = NULL,
+		.get = rtl8366_sw_get_vlan_info,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "fid",
+		.description = "Get/Set vlan FID",
+		.max = RTL8366S_FIDMAX,
+		.set = rtl8366_sw_set_vlan_fid,
+		.get = rtl8366_sw_get_vlan_fid,
+	},
+};
+
+static const struct switch_dev_ops rtl8366_ops = {
+	.attr_global = {
+		.attr = rtl8366s_globals,
+		.n_attr = ARRAY_SIZE(rtl8366s_globals),
+	},
+	.attr_port = {
+		.attr = rtl8366s_port,
+		.n_attr = ARRAY_SIZE(rtl8366s_port),
+	},
+	.attr_vlan = {
+		.attr = rtl8366s_vlan,
+		.n_attr = ARRAY_SIZE(rtl8366s_vlan),
+	},
+
+	.get_vlan_ports = rtl8366_sw_get_vlan_ports,
+	.set_vlan_ports = rtl8366_sw_set_vlan_ports,
+	.get_port_pvid = rtl8366_sw_get_port_pvid,
+	.set_port_pvid = rtl8366_sw_set_port_pvid,
+	.reset_switch = rtl8366_sw_reset_switch,
+	.get_port_link = rtl8366s_sw_get_port_link,
+	.get_port_stats = rtl8366s_sw_get_port_stats,
+};
+
+static int rtl8366s_switch_init(struct rtl8366_smi *smi)
+{
+	struct switch_dev *dev = &smi->sw_dev;
+	int err;
+
+	dev->name = "RTL8366S";
+	dev->cpu_port = RTL8366S_PORT_NUM_CPU;
+	dev->ports = RTL8366S_NUM_PORTS;
+	dev->vlans = RTL8366S_NUM_VIDS;
+	dev->ops = &rtl8366_ops;
+	dev->alias = dev_name(smi->parent);
+
+	err = register_switch(dev, NULL);
+	if (err)
+		dev_err(smi->parent, "switch registration failed\n");
+
+	return err;
+}
+
+static void rtl8366s_switch_cleanup(struct rtl8366_smi *smi)
+{
+	unregister_switch(&smi->sw_dev);
+}
+
+static int rtl8366s_mii_read(struct mii_bus *bus, int addr, int reg)
+{
+	struct rtl8366_smi *smi = bus->priv;
+	u32 val = 0;
+	int err;
+
+	err = rtl8366s_read_phy_reg(smi, addr, 0, reg, &val);
+	if (err)
+		return 0xffff;
+
+	return val;
+}
+
+static int rtl8366s_mii_write(struct mii_bus *bus, int addr, int reg, u16 val)
+{
+	struct rtl8366_smi *smi = bus->priv;
+	u32 t;
+	int err;
+
+	err = rtl8366s_write_phy_reg(smi, addr, 0, reg, val);
+	/* flush write */
+	(void) rtl8366s_read_phy_reg(smi, addr, 0, reg, &t);
+
+	return err;
+}
+
+static int rtl8366s_detect(struct rtl8366_smi *smi)
+{
+	u32 chip_id = 0;
+	u32 chip_ver = 0;
+	int ret;
+
+	ret = rtl8366_smi_read_reg(smi, RTL8366S_CHIP_ID_REG, &chip_id);
+	if (ret) {
+		dev_err(smi->parent, "unable to read chip id\n");
+		return ret;
+	}
+
+	switch (chip_id) {
+	case RTL8366S_CHIP_ID_8366:
+		break;
+	default:
+		dev_err(smi->parent, "unknown chip id (%04x)\n", chip_id);
+		return -ENODEV;
+	}
+
+	ret = rtl8366_smi_read_reg(smi, RTL8366S_CHIP_VERSION_CTRL_REG,
+				   &chip_ver);
+	if (ret) {
+		dev_err(smi->parent, "unable to read chip version\n");
+		return ret;
+	}
+
+	dev_info(smi->parent, "RTL%04x ver. %u chip found\n",
+		 chip_id, chip_ver & RTL8366S_CHIP_VERSION_MASK);
+
+	return 0;
+}
+
+static struct rtl8366_smi_ops rtl8366s_smi_ops = {
+	.detect		= rtl8366s_detect,
+	.reset_chip	= rtl8366s_reset_chip,
+	.setup		= rtl8366s_setup,
+
+	.mii_read	= rtl8366s_mii_read,
+	.mii_write	= rtl8366s_mii_write,
+
+	.get_vlan_mc	= rtl8366s_get_vlan_mc,
+	.set_vlan_mc	= rtl8366s_set_vlan_mc,
+	.get_vlan_4k	= rtl8366s_get_vlan_4k,
+	.set_vlan_4k	= rtl8366s_set_vlan_4k,
+	.get_mc_index	= rtl8366s_get_mc_index,
+	.set_mc_index	= rtl8366s_set_mc_index,
+	.get_mib_counter = rtl8366_get_mib_counter,
+	.is_vlan_valid	= rtl8366s_is_vlan_valid,
+	.enable_vlan	= rtl8366s_enable_vlan,
+	.enable_vlan4k	= rtl8366s_enable_vlan4k,
+	.enable_port	= rtl8366s_enable_port,
+};
+
+static int rtl8366s_probe(struct platform_device *pdev)
+{
+	static int rtl8366_smi_version_printed;
+	struct rtl8366_smi *smi;
+	int err;
+
+	if (!rtl8366_smi_version_printed++)
+		printk(KERN_NOTICE RTL8366S_DRIVER_DESC
+		       " version " RTL8366S_DRIVER_VER"\n");
+
+	smi = rtl8366_smi_probe(pdev);
+	if (IS_ERR(smi))
+		return PTR_ERR(smi);
+
+	smi->clk_delay = 10;
+	smi->cmd_read = 0xa9;
+	smi->cmd_write = 0xa8;
+	smi->ops = &rtl8366s_smi_ops;
+	smi->cpu_port = RTL8366S_PORT_NUM_CPU;
+	smi->num_ports = RTL8366S_NUM_PORTS;
+	smi->num_vlan_mc = RTL8366S_NUM_VLANS;
+	smi->mib_counters = rtl8366s_mib_counters;
+	smi->num_mib_counters = ARRAY_SIZE(rtl8366s_mib_counters);
+
+	err = rtl8366_smi_init(smi);
+	if (err)
+		goto err_free_smi;
+
+	platform_set_drvdata(pdev, smi);
+
+	err = rtl8366s_switch_init(smi);
+	if (err)
+		goto err_clear_drvdata;
+
+	return 0;
+
+ err_clear_drvdata:
+	platform_set_drvdata(pdev, NULL);
+	rtl8366_smi_cleanup(smi);
+ err_free_smi:
+	kfree(smi);
+	return err;
+}
+
+static int rtl8366s_remove(struct platform_device *pdev)
+{
+	struct rtl8366_smi *smi = platform_get_drvdata(pdev);
+
+	if (smi) {
+		rtl8366s_switch_cleanup(smi);
+		platform_set_drvdata(pdev, NULL);
+		rtl8366_smi_cleanup(smi);
+		kfree(smi);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id rtl8366s_match[] = {
+	{ .compatible = "realtek,rtl8366s" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rtl8366s_match);
+#endif
+
+static struct platform_driver rtl8366s_driver = {
+	.driver = {
+		.name		= RTL8366S_DRIVER_NAME,
+		.owner		= THIS_MODULE,
+#ifdef CONFIG_OF
+		.of_match_table = of_match_ptr(rtl8366s_match),
+#endif
+	},
+	.probe		= rtl8366s_probe,
+	.remove		= rtl8366s_remove,
+};
+
+static int __init rtl8366s_module_init(void)
+{
+	return platform_driver_register(&rtl8366s_driver);
+}
+module_init(rtl8366s_module_init);
+
+static void __exit rtl8366s_module_exit(void)
+{
+	platform_driver_unregister(&rtl8366s_driver);
+}
+module_exit(rtl8366s_module_exit);
+
+MODULE_DESCRIPTION(RTL8366S_DRIVER_DESC);
+MODULE_VERSION(RTL8366S_DRIVER_VER);
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_AUTHOR("Antti Seppälä <a.seppala@gmail.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" RTL8366S_DRIVER_NAME);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/rtl8367.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/rtl8367.c
new file mode 100644
index 0000000..7f0569d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/rtl8367.c
@@ -0,0 +1,1846 @@
+/*
+ * Platform driver for the Realtek RTL8367R/M ethernet switches
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/rtl8367.h>
+
+#include "rtl8366_smi.h"
+
+#define RTL8367_RESET_DELAY	1000	/* msecs*/
+
+#define RTL8367_PHY_ADDR_MAX	8
+#define RTL8367_PHY_REG_MAX	31
+
+#define RTL8367_VID_MASK	0xffff
+#define RTL8367_FID_MASK	0xfff
+#define RTL8367_UNTAG_MASK	0xffff
+#define RTL8367_MEMBER_MASK	0xffff
+
+#define RTL8367_PORT_CFG_REG(_p)		(0x000e + 0x20 * (_p))
+#define   RTL8367_PORT_CFG_EGRESS_MODE_SHIFT	4
+#define   RTL8367_PORT_CFG_EGRESS_MODE_MASK	0x3
+#define   RTL8367_PORT_CFG_EGRESS_MODE_ORIGINAL	0
+#define   RTL8367_PORT_CFG_EGRESS_MODE_KEEP	1
+#define   RTL8367_PORT_CFG_EGRESS_MODE_PRI	2
+#define   RTL8367_PORT_CFG_EGRESS_MODE_REAL	3
+
+#define RTL8367_BYPASS_LINE_RATE_REG		0x03f7
+
+#define RTL8367_TA_CTRL_REG			0x0500
+#define   RTL8367_TA_CTRL_STATUS		BIT(12)
+#define   RTL8367_TA_CTRL_METHOD		BIT(5)
+#define   RTL8367_TA_CTRL_CMD_SHIFT		4
+#define   RTL8367_TA_CTRL_CMD_READ		0
+#define   RTL8367_TA_CTRL_CMD_WRITE		1
+#define   RTL8367_TA_CTRL_TABLE_SHIFT		0
+#define   RTL8367_TA_CTRL_TABLE_ACLRULE		1
+#define   RTL8367_TA_CTRL_TABLE_ACLACT		2
+#define   RTL8367_TA_CTRL_TABLE_CVLAN		3
+#define   RTL8367_TA_CTRL_TABLE_L2		4
+#define   RTL8367_TA_CTRL_CVLAN_READ \
+		((RTL8367_TA_CTRL_CMD_READ << RTL8367_TA_CTRL_CMD_SHIFT) | \
+		 RTL8367_TA_CTRL_TABLE_CVLAN)
+#define   RTL8367_TA_CTRL_CVLAN_WRITE \
+		((RTL8367_TA_CTRL_CMD_WRITE << RTL8367_TA_CTRL_CMD_SHIFT) | \
+		 RTL8367_TA_CTRL_TABLE_CVLAN)
+
+#define RTL8367_TA_ADDR_REG			0x0501
+#define   RTL8367_TA_ADDR_MASK			0x3fff
+
+#define RTL8367_TA_DATA_REG(_x)			(0x0503 + (_x))
+#define   RTL8367_TA_VLAN_DATA_SIZE		4
+#define   RTL8367_TA_VLAN_VID_MASK		RTL8367_VID_MASK
+#define   RTL8367_TA_VLAN_MEMBER_SHIFT		0
+#define   RTL8367_TA_VLAN_MEMBER_MASK		RTL8367_MEMBER_MASK
+#define   RTL8367_TA_VLAN_FID_SHIFT		0
+#define   RTL8367_TA_VLAN_FID_MASK		RTL8367_FID_MASK
+#define   RTL8367_TA_VLAN_UNTAG1_SHIFT		14
+#define   RTL8367_TA_VLAN_UNTAG1_MASK		0x3
+#define   RTL8367_TA_VLAN_UNTAG2_SHIFT		0
+#define   RTL8367_TA_VLAN_UNTAG2_MASK		0x3fff
+
+#define RTL8367_VLAN_PVID_CTRL_REG(_p)		(0x0700 + (_p) / 2)
+#define RTL8367_VLAN_PVID_CTRL_MASK		0x1f
+#define RTL8367_VLAN_PVID_CTRL_SHIFT(_p)	(8 * ((_p) % 2))
+
+#define RTL8367_VLAN_MC_BASE(_x)		(0x0728 + (_x) * 4)
+#define   RTL8367_VLAN_MC_DATA_SIZE		4
+#define   RTL8367_VLAN_MC_MEMBER_SHIFT		0
+#define   RTL8367_VLAN_MC_MEMBER_MASK		RTL8367_MEMBER_MASK
+#define   RTL8367_VLAN_MC_FID_SHIFT		0
+#define   RTL8367_VLAN_MC_FID_MASK		RTL8367_FID_MASK
+#define   RTL8367_VLAN_MC_EVID_SHIFT		0
+#define   RTL8367_VLAN_MC_EVID_MASK		RTL8367_VID_MASK
+
+#define RTL8367_VLAN_CTRL_REG			0x07a8
+#define   RTL8367_VLAN_CTRL_ENABLE		BIT(0)
+
+#define RTL8367_VLAN_INGRESS_REG		0x07a9
+
+#define RTL8367_PORT_ISOLATION_REG(_p)		(0x08a2 + (_p))
+
+#define RTL8367_MIB_COUNTER_REG(_x)		(0x1000 + (_x))
+
+#define RTL8367_MIB_ADDRESS_REG			0x1004
+
+#define RTL8367_MIB_CTRL_REG(_x)		(0x1005 + (_x))
+#define   RTL8367_MIB_CTRL_GLOBAL_RESET_MASK	BIT(11)
+#define   RTL8367_MIB_CTRL_QM_RESET_MASK	BIT(10)
+#define   RTL8367_MIB_CTRL_PORT_RESET_MASK(_p)	BIT(2 + (_p))
+#define   RTL8367_MIB_CTRL_RESET_MASK		BIT(1)
+#define   RTL8367_MIB_CTRL_BUSY_MASK		BIT(0)
+
+#define RTL8367_MIB_COUNT			36
+#define RTL8367_MIB_COUNTER_PORT_OFFSET		0x0050
+
+#define RTL8367_SWC0_REG			0x1200
+#define   RTL8367_SWC0_MAX_LENGTH_SHIFT		13
+#define   RTL8367_SWC0_MAX_LENGTH(_x)		((_x) << 13)
+#define   RTL8367_SWC0_MAX_LENGTH_MASK		RTL8367_SWC0_MAX_LENGTH(0x3)
+#define   RTL8367_SWC0_MAX_LENGTH_1522		RTL8367_SWC0_MAX_LENGTH(0)
+#define   RTL8367_SWC0_MAX_LENGTH_1536		RTL8367_SWC0_MAX_LENGTH(1)
+#define   RTL8367_SWC0_MAX_LENGTH_1552		RTL8367_SWC0_MAX_LENGTH(2)
+#define   RTL8367_SWC0_MAX_LENGTH_16000		RTL8367_SWC0_MAX_LENGTH(3)
+
+#define RTL8367_CHIP_NUMBER_REG			0x1300
+
+#define RTL8367_CHIP_VER_REG			0x1301
+#define   RTL8367_CHIP_VER_RLVID_SHIFT		12
+#define   RTL8367_CHIP_VER_RLVID_MASK		0xf
+#define   RTL8367_CHIP_VER_MCID_SHIFT		8
+#define   RTL8367_CHIP_VER_MCID_MASK		0xf
+#define   RTL8367_CHIP_VER_BOID_SHIFT		4
+#define   RTL8367_CHIP_VER_BOID_MASK		0xf
+
+#define RTL8367_CHIP_MODE_REG			0x1302
+#define   RTL8367_CHIP_MODE_MASK		0x7
+
+#define RTL8367_CHIP_DEBUG0_REG			0x1303
+#define   RTL8367_CHIP_DEBUG0_DUMMY0(_x)	BIT(8 + (_x))
+
+#define RTL8367_CHIP_DEBUG1_REG			0x1304
+
+#define RTL8367_DIS_REG				0x1305
+#define   RTL8367_DIS_SKIP_MII_RXER(_x)		BIT(12 + (_x))
+#define   RTL8367_DIS_RGMII_SHIFT(_x)		(4 * (_x))
+#define   RTL8367_DIS_RGMII_MASK		0x7
+
+#define RTL8367_EXT_RGMXF_REG(_x)		(0x1306 + (_x))
+#define   RTL8367_EXT_RGMXF_DUMMY0_SHIFT	5
+#define   RTL8367_EXT_RGMXF_DUMMY0_MASK	0x7ff
+#define   RTL8367_EXT_RGMXF_TXDELAY_SHIFT	3
+#define   RTL8367_EXT_RGMXF_TXDELAY_MASK	1
+#define   RTL8367_EXT_RGMXF_RXDELAY_MASK	0x7
+
+#define RTL8367_DI_FORCE_REG(_x)		(0x1310 + (_x))
+#define   RTL8367_DI_FORCE_MODE			BIT(12)
+#define   RTL8367_DI_FORCE_NWAY			BIT(7)
+#define   RTL8367_DI_FORCE_TXPAUSE		BIT(6)
+#define   RTL8367_DI_FORCE_RXPAUSE		BIT(5)
+#define   RTL8367_DI_FORCE_LINK			BIT(4)
+#define   RTL8367_DI_FORCE_DUPLEX		BIT(2)
+#define   RTL8367_DI_FORCE_SPEED_MASK		3
+#define   RTL8367_DI_FORCE_SPEED_10		0
+#define   RTL8367_DI_FORCE_SPEED_100		1
+#define   RTL8367_DI_FORCE_SPEED_1000		2
+
+#define RTL8367_MAC_FORCE_REG(_x)		(0x1312 + (_x))
+
+#define RTL8367_CHIP_RESET_REG			0x1322
+#define   RTL8367_CHIP_RESET_SW			BIT(1)
+#define   RTL8367_CHIP_RESET_HW			BIT(0)
+
+#define RTL8367_PORT_STATUS_REG(_p)		(0x1352 + (_p))
+#define   RTL8367_PORT_STATUS_NWAY		BIT(7)
+#define   RTL8367_PORT_STATUS_TXPAUSE		BIT(6)
+#define   RTL8367_PORT_STATUS_RXPAUSE		BIT(5)
+#define   RTL8367_PORT_STATUS_LINK		BIT(4)
+#define   RTL8367_PORT_STATUS_DUPLEX		BIT(2)
+#define   RTL8367_PORT_STATUS_SPEED_MASK	0x0003
+#define   RTL8367_PORT_STATUS_SPEED_10		0
+#define   RTL8367_PORT_STATUS_SPEED_100		1
+#define   RTL8367_PORT_STATUS_SPEED_1000	2
+
+#define RTL8367_RTL_NO_REG			0x13c0
+#define   RTL8367_RTL_NO_8367R			0x3670
+#define   RTL8367_RTL_NO_8367M			0x3671
+
+#define RTL8367_RTL_VER_REG			0x13c1
+#define   RTL8367_RTL_VER_MASK			0xf
+
+#define RTL8367_RTL_MAGIC_ID_REG		0x13c2
+#define   RTL8367_RTL_MAGIC_ID_VAL		0x0249
+
+#define RTL8367_LED_SYS_CONFIG_REG		0x1b00
+#define RTL8367_LED_MODE_REG			0x1b02
+#define   RTL8367_LED_MODE_RATE_M		0x7
+#define   RTL8367_LED_MODE_RATE_S		1
+
+#define RTL8367_LED_CONFIG_REG			0x1b03
+#define   RTL8367_LED_CONFIG_DATA_S		12
+#define   RTL8367_LED_CONFIG_DATA_M		0x3
+#define   RTL8367_LED_CONFIG_SEL		BIT(14)
+#define   RTL8367_LED_CONFIG_LED_CFG_M		0xf
+
+#define RTL8367_PARA_LED_IO_EN1_REG		0x1b24
+#define RTL8367_PARA_LED_IO_EN2_REG		0x1b25
+#define   RTL8367_PARA_LED_IO_EN_PMASK		0xff
+
+#define RTL8367_IA_CTRL_REG			0x1f00
+#define   RTL8367_IA_CTRL_RW(_x)		((_x) << 1)
+#define   RTL8367_IA_CTRL_RW_READ		RTL8367_IA_CTRL_RW(0)
+#define   RTL8367_IA_CTRL_RW_WRITE		RTL8367_IA_CTRL_RW(1)
+#define   RTL8367_IA_CTRL_CMD_MASK		BIT(0)
+
+#define RTL8367_IA_STATUS_REG			0x1f01
+#define   RTL8367_IA_STATUS_PHY_BUSY		BIT(2)
+#define   RTL8367_IA_STATUS_SDS_BUSY		BIT(1)
+#define   RTL8367_IA_STATUS_MDX_BUSY		BIT(0)
+
+#define RTL8367_IA_ADDRESS_REG			0x1f02
+
+#define RTL8367_IA_WRITE_DATA_REG		0x1f03
+#define RTL8367_IA_READ_DATA_REG		0x1f04
+
+#define RTL8367_INTERNAL_PHY_REG(_a, _r)	(0x2000 + 32 * (_a) + (_r))
+
+#define RTL8367_CPU_PORT_NUM		9
+#define RTL8367_NUM_PORTS		10
+#define RTL8367_NUM_VLANS		32
+#define RTL8367_NUM_LEDGROUPS		4
+#define RTL8367_NUM_VIDS		4096
+#define RTL8367_PRIORITYMAX		7
+#define RTL8367_FIDMAX			7
+
+#define RTL8367_PORT_0			BIT(0)
+#define RTL8367_PORT_1			BIT(1)
+#define RTL8367_PORT_2			BIT(2)
+#define RTL8367_PORT_3			BIT(3)
+#define RTL8367_PORT_4			BIT(4)
+#define RTL8367_PORT_5			BIT(5)
+#define RTL8367_PORT_6			BIT(6)
+#define RTL8367_PORT_7			BIT(7)
+#define RTL8367_PORT_E1			BIT(8)	/* external port 1 */
+#define RTL8367_PORT_E0			BIT(9)	/* external port 0 */
+
+#define RTL8367_PORTS_ALL					\
+	(RTL8367_PORT_0 | RTL8367_PORT_1 | RTL8367_PORT_2 |	\
+	 RTL8367_PORT_3 | RTL8367_PORT_4 | RTL8367_PORT_5 |	\
+	 RTL8367_PORT_6 | RTL8367_PORT_7 | RTL8367_PORT_E1 |	\
+	 RTL8367_PORT_E0)
+
+#define RTL8367_PORTS_ALL_BUT_CPU				\
+	(RTL8367_PORT_0 | RTL8367_PORT_1 | RTL8367_PORT_2 |	\
+	 RTL8367_PORT_3 | RTL8367_PORT_4 | RTL8367_PORT_5 |	\
+	 RTL8367_PORT_6 | RTL8367_PORT_7 | RTL8367_PORT_E1)
+
+struct rtl8367_initval {
+	u16 reg;
+	u16 val;
+};
+
+#define RTL8367_MIB_RXB_ID		0	/* IfInOctets */
+#define RTL8367_MIB_TXB_ID		20	/* IfOutOctets */
+
+static struct rtl8366_mib_counter rtl8367_mib_counters[] = {
+	{ 0,  0, 4, "IfInOctets"				},
+	{ 0,  4, 2, "Dot3StatsFCSErrors"			},
+	{ 0,  6, 2, "Dot3StatsSymbolErrors"			},
+	{ 0,  8, 2, "Dot3InPauseFrames"				},
+	{ 0, 10, 2, "Dot3ControlInUnknownOpcodes"		},
+	{ 0, 12, 2, "EtherStatsFragments"			},
+	{ 0, 14, 2, "EtherStatsJabbers"				},
+	{ 0, 16, 2, "IfInUcastPkts"				},
+	{ 0, 18, 2, "EtherStatsDropEvents"			},
+	{ 0, 20, 4, "EtherStatsOctets"				},
+
+	{ 0, 24, 2, "EtherStatsUnderSizePkts"			},
+	{ 0, 26, 2, "EtherOversizeStats"			},
+	{ 0, 28, 2, "EtherStatsPkts64Octets"			},
+	{ 0, 30, 2, "EtherStatsPkts65to127Octets"		},
+	{ 0, 32, 2, "EtherStatsPkts128to255Octets"		},
+	{ 0, 34, 2, "EtherStatsPkts256to511Octets"		},
+	{ 0, 36, 2, "EtherStatsPkts512to1023Octets"		},
+	{ 0, 38, 2, "EtherStatsPkts1024to1518Octets"		},
+	{ 0, 40, 2, "EtherStatsMulticastPkts"			},
+	{ 0, 42, 2, "EtherStatsBroadcastPkts"			},
+
+	{ 0, 44, 4, "IfOutOctets"				},
+
+	{ 0, 48, 2, "Dot3StatsSingleCollisionFrames"		},
+	{ 0, 50, 2, "Dot3StatMultipleCollisionFrames"		},
+	{ 0, 52, 2, "Dot3sDeferredTransmissions"		},
+	{ 0, 54, 2, "Dot3StatsLateCollisions"			},
+	{ 0, 56, 2, "EtherStatsCollisions"			},
+	{ 0, 58, 2, "Dot3StatsExcessiveCollisions"		},
+	{ 0, 60, 2, "Dot3OutPauseFrames"			},
+	{ 0, 62, 2, "Dot1dBasePortDelayExceededDiscards"	},
+	{ 0, 64, 2, "Dot1dTpPortInDiscards"			},
+	{ 0, 66, 2, "IfOutUcastPkts"				},
+	{ 0, 68, 2, "IfOutMulticastPkts"			},
+	{ 0, 70, 2, "IfOutBroadcastPkts"			},
+	{ 0, 72, 2, "OutOampduPkts"				},
+	{ 0, 74, 2, "InOampduPkts"				},
+	{ 0, 76, 2, "PktgenPkts"				},
+};
+
+#define REG_RD(_smi, _reg, _val)					\
+	do {								\
+		err = rtl8366_smi_read_reg(_smi, _reg, _val);		\
+		if (err)						\
+			return err;					\
+	} while (0)
+
+#define REG_WR(_smi, _reg, _val)					\
+	do {								\
+		err = rtl8366_smi_write_reg(_smi, _reg, _val);		\
+		if (err)						\
+			return err;					\
+	} while (0)
+
+#define REG_RMW(_smi, _reg, _mask, _val)				\
+	do {								\
+		err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val);	\
+		if (err)						\
+			return err;					\
+	} while (0)
+
+static const struct rtl8367_initval rtl8367_initvals_0_0[] = {
+	{0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0000}, {0x2215, 0x1006},
+	{0x221f, 0x0005}, {0x2200, 0x00c6}, {0x221f, 0x0007}, {0x221e, 0x0048},
+	{0x2215, 0x6412}, {0x2216, 0x6412}, {0x2217, 0x6412}, {0x2218, 0x6412},
+	{0x2219, 0x6412}, {0x221A, 0x6412}, {0x221f, 0x0001}, {0x220c, 0xdbf0},
+	{0x2209, 0x2576}, {0x2207, 0x287E}, {0x220A, 0x68E5}, {0x221D, 0x3DA4},
+	{0x221C, 0xE7F7}, {0x2214, 0x7F52}, {0x2218, 0x7FCE}, {0x2208, 0x04B7},
+	{0x2206, 0x4072}, {0x2210, 0xF05E}, {0x221B, 0xB414}, {0x221F, 0x0003},
+	{0x221A, 0x06A6}, {0x2210, 0xF05E}, {0x2213, 0x06EB}, {0x2212, 0xF4D2},
+	{0x220E, 0xE120}, {0x2200, 0x7C00}, {0x2202, 0x5FD0}, {0x220D, 0x0207},
+	{0x221f, 0x0002}, {0x2205, 0x0978}, {0x2202, 0x8C01}, {0x2207, 0x3620},
+	{0x221C, 0x0001}, {0x2203, 0x0420}, {0x2204, 0x80C8}, {0x133e, 0x0ede},
+	{0x221f, 0x0002}, {0x220c, 0x0073}, {0x220d, 0xEB65}, {0x220e, 0x51d1},
+	{0x220f, 0x5dcb}, {0x2210, 0x3044}, {0x2211, 0x1800}, {0x2212, 0x7E00},
+	{0x2213, 0x0000}, {0x133f, 0x0010}, {0x133e, 0x0ffe}, {0x207f, 0x0002},
+	{0x2074, 0x3D22}, {0x2075, 0x2000}, {0x2076, 0x6040}, {0x2077, 0x0000},
+	{0x2078, 0x0f0a}, {0x2079, 0x50AB}, {0x207a, 0x0000}, {0x207b, 0x0f0f},
+	{0x205f, 0x0002}, {0x2054, 0xFF00}, {0x2055, 0x000A}, {0x2056, 0x000A},
+	{0x2057, 0x0005}, {0x2058, 0x0005}, {0x2059, 0x0000}, {0x205A, 0x0005},
+	{0x205B, 0x0005}, {0x205C, 0x0005}, {0x209f, 0x0002}, {0x2094, 0x00AA},
+	{0x2095, 0x00AA}, {0x2096, 0x00AA}, {0x2097, 0x00AA}, {0x2098, 0x0055},
+	{0x2099, 0x00AA}, {0x209A, 0x00AA}, {0x209B, 0x00AA}, {0x1363, 0x8354},
+	{0x1270, 0x3333}, {0x1271, 0x3333}, {0x1272, 0x3333}, {0x1330, 0x00DB},
+	{0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x121d, 0x1006}, {0x121e, 0x03e8},
+	{0x121f, 0x02b3}, {0x1220, 0x028f}, {0x1221, 0x029b}, {0x1222, 0x0277},
+	{0x1223, 0x02b3}, {0x1224, 0x028f}, {0x1225, 0x029b}, {0x1226, 0x0277},
+	{0x1227, 0x00c0}, {0x1228, 0x00b4}, {0x122f, 0x00c0}, {0x1230, 0x00b4},
+	{0x1229, 0x0020}, {0x122a, 0x000c}, {0x1231, 0x0030}, {0x1232, 0x0024},
+	{0x0219, 0x0032}, {0x0200, 0x03e8}, {0x0201, 0x03e8}, {0x0202, 0x03e8},
+	{0x0203, 0x03e8}, {0x0204, 0x03e8}, {0x0205, 0x03e8}, {0x0206, 0x03e8},
+	{0x0207, 0x03e8}, {0x0218, 0x0032}, {0x0208, 0x029b}, {0x0209, 0x029b},
+	{0x020a, 0x029b}, {0x020b, 0x029b}, {0x020c, 0x029b}, {0x020d, 0x029b},
+	{0x020e, 0x029b}, {0x020f, 0x029b}, {0x0210, 0x029b}, {0x0211, 0x029b},
+	{0x0212, 0x029b}, {0x0213, 0x029b}, {0x0214, 0x029b}, {0x0215, 0x029b},
+	{0x0216, 0x029b}, {0x0217, 0x029b}, {0x0900, 0x0000}, {0x0901, 0x0000},
+	{0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087b, 0x0000},
+	{0x087c, 0xff00}, {0x087d, 0x0000}, {0x087e, 0x0000}, {0x0801, 0x0100},
+	{0x0802, 0x0100}, {0x1700, 0x014C}, {0x0301, 0x00FF}, {0x12AA, 0x0096},
+	{0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0005}, {0x2200, 0x00C4},
+	{0x221f, 0x0000}, {0x2210, 0x05EF}, {0x2204, 0x05E1}, {0x2200, 0x1340},
+	{0x133f, 0x0010}, {0x20A0, 0x1940}, {0x20C0, 0x1940}, {0x20E0, 0x1940},
+};
+
+static const struct rtl8367_initval rtl8367_initvals_0_1[] = {
+	{0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0000}, {0x2215, 0x1006},
+	{0x221f, 0x0005}, {0x2200, 0x00c6}, {0x221f, 0x0007}, {0x221e, 0x0048},
+	{0x2215, 0x6412}, {0x2216, 0x6412}, {0x2217, 0x6412}, {0x2218, 0x6412},
+	{0x2219, 0x6412}, {0x221A, 0x6412}, {0x221f, 0x0001}, {0x220c, 0xdbf0},
+	{0x2209, 0x2576}, {0x2207, 0x287E}, {0x220A, 0x68E5}, {0x221D, 0x3DA4},
+	{0x221C, 0xE7F7}, {0x2214, 0x7F52}, {0x2218, 0x7FCE}, {0x2208, 0x04B7},
+	{0x2206, 0x4072}, {0x2210, 0xF05E}, {0x221B, 0xB414}, {0x221F, 0x0003},
+	{0x221A, 0x06A6}, {0x2210, 0xF05E}, {0x2213, 0x06EB}, {0x2212, 0xF4D2},
+	{0x220E, 0xE120}, {0x2200, 0x7C00}, {0x2202, 0x5FD0}, {0x220D, 0x0207},
+	{0x221f, 0x0002}, {0x2205, 0x0978}, {0x2202, 0x8C01}, {0x2207, 0x3620},
+	{0x221C, 0x0001}, {0x2203, 0x0420}, {0x2204, 0x80C8}, {0x133e, 0x0ede},
+	{0x221f, 0x0002}, {0x220c, 0x0073}, {0x220d, 0xEB65}, {0x220e, 0x51d1},
+	{0x220f, 0x5dcb}, {0x2210, 0x3044}, {0x2211, 0x1800}, {0x2212, 0x7E00},
+	{0x2213, 0x0000}, {0x133f, 0x0010}, {0x133e, 0x0ffe}, {0x207f, 0x0002},
+	{0x2074, 0x3D22}, {0x2075, 0x2000}, {0x2076, 0x6040}, {0x2077, 0x0000},
+	{0x2078, 0x0f0a}, {0x2079, 0x50AB}, {0x207a, 0x0000}, {0x207b, 0x0f0f},
+	{0x205f, 0x0002}, {0x2054, 0xFF00}, {0x2055, 0x000A}, {0x2056, 0x000A},
+	{0x2057, 0x0005}, {0x2058, 0x0005}, {0x2059, 0x0000}, {0x205A, 0x0005},
+	{0x205B, 0x0005}, {0x205C, 0x0005}, {0x209f, 0x0002}, {0x2094, 0x00AA},
+	{0x2095, 0x00AA}, {0x2096, 0x00AA}, {0x2097, 0x00AA}, {0x2098, 0x0055},
+	{0x2099, 0x00AA}, {0x209A, 0x00AA}, {0x209B, 0x00AA}, {0x1363, 0x8354},
+	{0x1270, 0x3333}, {0x1271, 0x3333}, {0x1272, 0x3333}, {0x1330, 0x00DB},
+	{0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x121d, 0x1b06}, {0x121e, 0x07f0},
+	{0x121f, 0x0438}, {0x1220, 0x040f}, {0x1221, 0x040f}, {0x1222, 0x03eb},
+	{0x1223, 0x0438}, {0x1224, 0x040f}, {0x1225, 0x040f}, {0x1226, 0x03eb},
+	{0x1227, 0x0144}, {0x1228, 0x0138}, {0x122f, 0x0144}, {0x1230, 0x0138},
+	{0x1229, 0x0020}, {0x122a, 0x000c}, {0x1231, 0x0030}, {0x1232, 0x0024},
+	{0x0219, 0x0032}, {0x0200, 0x07d0}, {0x0201, 0x07d0}, {0x0202, 0x07d0},
+	{0x0203, 0x07d0}, {0x0204, 0x07d0}, {0x0205, 0x07d0}, {0x0206, 0x07d0},
+	{0x0207, 0x07d0}, {0x0218, 0x0032}, {0x0208, 0x0190}, {0x0209, 0x0190},
+	{0x020a, 0x0190}, {0x020b, 0x0190}, {0x020c, 0x0190}, {0x020d, 0x0190},
+	{0x020e, 0x0190}, {0x020f, 0x0190}, {0x0210, 0x0190}, {0x0211, 0x0190},
+	{0x0212, 0x0190}, {0x0213, 0x0190}, {0x0214, 0x0190}, {0x0215, 0x0190},
+	{0x0216, 0x0190}, {0x0217, 0x0190}, {0x0900, 0x0000}, {0x0901, 0x0000},
+	{0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087b, 0x0000},
+	{0x087c, 0xff00}, {0x087d, 0x0000}, {0x087e, 0x0000}, {0x0801, 0x0100},
+	{0x0802, 0x0100}, {0x1700, 0x0125}, {0x0301, 0x00FF}, {0x12AA, 0x0096},
+	{0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0005}, {0x2200, 0x00C4},
+	{0x221f, 0x0000}, {0x2210, 0x05EF}, {0x2204, 0x05E1}, {0x2200, 0x1340},
+	{0x133f, 0x0010},
+};
+
+static const struct rtl8367_initval rtl8367_initvals_1_0[] = {
+	{0x1B24, 0x0000}, {0x1B25, 0x0000}, {0x1B26, 0x0000}, {0x1B27, 0x0000},
+	{0x207F, 0x0002}, {0x2079, 0x0200}, {0x207F, 0x0000}, {0x133F, 0x0030},
+	{0x133E, 0x000E}, {0x221F, 0x0005}, {0x2201, 0x0700}, {0x2205, 0x8B82},
+	{0x2206, 0x05CB}, {0x221F, 0x0002}, {0x2204, 0x80C2}, {0x2205, 0x0938},
+	{0x221F, 0x0003}, {0x2212, 0xC4D2}, {0x220D, 0x0207}, {0x221F, 0x0001},
+	{0x2207, 0x267E}, {0x221C, 0xE5F7}, {0x221B, 0x0424}, {0x221F, 0x0007},
+	{0x221E, 0x0040}, {0x2218, 0x0000}, {0x221F, 0x0007}, {0x221E, 0x002C},
+	{0x2218, 0x008B}, {0x221F, 0x0005}, {0x2205, 0xFFF6}, {0x2206, 0x0080},
+	{0x2205, 0x8000}, {0x2206, 0xF8E0}, {0x2206, 0xE000}, {0x2206, 0xE1E0},
+	{0x2206, 0x01AC}, {0x2206, 0x2408}, {0x2206, 0xE08B}, {0x2206, 0x84F7},
+	{0x2206, 0x20E4}, {0x2206, 0x8B84}, {0x2206, 0xFC05}, {0x2206, 0xF8FA},
+	{0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AC}, {0x2206, 0x201A},
+	{0x2206, 0xBF80}, {0x2206, 0x59D0}, {0x2206, 0x2402}, {0x2206, 0x803D},
+	{0x2206, 0xE0E0}, {0x2206, 0xE4E1}, {0x2206, 0xE0E5}, {0x2206, 0x5806},
+	{0x2206, 0x68C0}, {0x2206, 0xD1D2}, {0x2206, 0xE4E0}, {0x2206, 0xE4E5},
+	{0x2206, 0xE0E5}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x05FB},
+	{0x2206, 0x0BFB}, {0x2206, 0x58FF}, {0x2206, 0x9E11}, {0x2206, 0x06F0},
+	{0x2206, 0x0C81}, {0x2206, 0x8AE0}, {0x2206, 0x0019}, {0x2206, 0x1B89},
+	{0x2206, 0xCFEB}, {0x2206, 0x19EB}, {0x2206, 0x19B0}, {0x2206, 0xEFFF},
+	{0x2206, 0x0BFF}, {0x2206, 0x0425}, {0x2206, 0x0807}, {0x2206, 0x2640},
+	{0x2206, 0x7227}, {0x2206, 0x267E}, {0x2206, 0x2804}, {0x2206, 0xB729},
+	{0x2206, 0x2576}, {0x2206, 0x2A68}, {0x2206, 0xE52B}, {0x2206, 0xAD00},
+	{0x2206, 0x2CDB}, {0x2206, 0xF02D}, {0x2206, 0x67BB}, {0x2206, 0x2E7B},
+	{0x2206, 0x0F2F}, {0x2206, 0x7365}, {0x2206, 0x31AC}, {0x2206, 0xCC32},
+	{0x2206, 0x2300}, {0x2206, 0x332D}, {0x2206, 0x1734}, {0x2206, 0x7F52},
+	{0x2206, 0x3510}, {0x2206, 0x0036}, {0x2206, 0x0600}, {0x2206, 0x370C},
+	{0x2206, 0xC038}, {0x2206, 0x7FCE}, {0x2206, 0x3CE5}, {0x2206, 0xF73D},
+	{0x2206, 0x3DA4}, {0x2206, 0x6530}, {0x2206, 0x3E67}, {0x2206, 0x0053},
+	{0x2206, 0x69D2}, {0x2206, 0x0F6A}, {0x2206, 0x012C}, {0x2206, 0x6C2B},
+	{0x2206, 0x136E}, {0x2206, 0xE100}, {0x2206, 0x6F12}, {0x2206, 0xF771},
+	{0x2206, 0x006B}, {0x2206, 0x7306}, {0x2206, 0xEB74}, {0x2206, 0x94C7},
+	{0x2206, 0x7698}, {0x2206, 0x0A77}, {0x2206, 0x5000}, {0x2206, 0x788A},
+	{0x2206, 0x1579}, {0x2206, 0x7F6F}, {0x2206, 0x7A06}, {0x2206, 0xA600},
+	{0x2205, 0x8B90}, {0x2206, 0x8000}, {0x2205, 0x8B92}, {0x2206, 0x8000},
+	{0x2205, 0x8B94}, {0x2206, 0x8014}, {0x2208, 0xFFFA}, {0x2202, 0x3C65},
+	{0x2205, 0xFFF6}, {0x2206, 0x00F7}, {0x221F, 0x0000}, {0x221F, 0x0007},
+	{0x221E, 0x0042}, {0x2218, 0x0000}, {0x221E, 0x002D}, {0x2218, 0xF010},
+	{0x221E, 0x0020}, {0x2215, 0x0000}, {0x221E, 0x0023}, {0x2216, 0x8000},
+	{0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, {0x1362, 0x0115},
+	{0x1363, 0x0002}, {0x1363, 0x0000}, {0x1306, 0x000C}, {0x1307, 0x000C},
+	{0x1303, 0x0067}, {0x1304, 0x4444}, {0x1203, 0xFF00}, {0x1200, 0x7FC4},
+	{0x121D, 0x7D16}, {0x121E, 0x03E8}, {0x121F, 0x024E}, {0x1220, 0x0230},
+	{0x1221, 0x0244}, {0x1222, 0x0226}, {0x1223, 0x024E}, {0x1224, 0x0230},
+	{0x1225, 0x0244}, {0x1226, 0x0226}, {0x1227, 0x00C0}, {0x1228, 0x00B4},
+	{0x122F, 0x00C0}, {0x1230, 0x00B4}, {0x0208, 0x03E8}, {0x0209, 0x03E8},
+	{0x020A, 0x03E8}, {0x020B, 0x03E8}, {0x020C, 0x03E8}, {0x020D, 0x03E8},
+	{0x020E, 0x03E8}, {0x020F, 0x03E8}, {0x0210, 0x03E8}, {0x0211, 0x03E8},
+	{0x0212, 0x03E8}, {0x0213, 0x03E8}, {0x0214, 0x03E8}, {0x0215, 0x03E8},
+	{0x0216, 0x03E8}, {0x0217, 0x03E8}, {0x0900, 0x0000}, {0x0901, 0x0000},
+	{0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087B, 0x0000},
+	{0x087C, 0xFF00}, {0x087D, 0x0000}, {0x087E, 0x0000}, {0x0801, 0x0100},
+	{0x0802, 0x0100}, {0x0A20, 0x2040}, {0x0A21, 0x2040}, {0x0A22, 0x2040},
+	{0x0A23, 0x2040}, {0x0A24, 0x2040}, {0x0A28, 0x2040}, {0x0A29, 0x2040},
+	{0x133F, 0x0030}, {0x133E, 0x000E}, {0x221F, 0x0000}, {0x2200, 0x1340},
+	{0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, {0x20A0, 0x1940},
+	{0x20C0, 0x1940}, {0x20E0, 0x1940}, {0x130c, 0x0050},
+};
+
+static const struct rtl8367_initval rtl8367_initvals_1_1[] = {
+	{0x1B24, 0x0000}, {0x1B25, 0x0000}, {0x1B26, 0x0000}, {0x1B27, 0x0000},
+	{0x207F, 0x0002}, {0x2079, 0x0200}, {0x207F, 0x0000}, {0x133F, 0x0030},
+	{0x133E, 0x000E}, {0x221F, 0x0005}, {0x2201, 0x0700}, {0x2205, 0x8B82},
+	{0x2206, 0x05CB}, {0x221F, 0x0002}, {0x2204, 0x80C2}, {0x2205, 0x0938},
+	{0x221F, 0x0003}, {0x2212, 0xC4D2}, {0x220D, 0x0207}, {0x221F, 0x0001},
+	{0x2207, 0x267E}, {0x221C, 0xE5F7}, {0x221B, 0x0424}, {0x221F, 0x0007},
+	{0x221E, 0x0040}, {0x2218, 0x0000}, {0x221F, 0x0007}, {0x221E, 0x002C},
+	{0x2218, 0x008B}, {0x221F, 0x0005}, {0x2205, 0xFFF6}, {0x2206, 0x0080},
+	{0x2205, 0x8000}, {0x2206, 0xF8E0}, {0x2206, 0xE000}, {0x2206, 0xE1E0},
+	{0x2206, 0x01AC}, {0x2206, 0x2408}, {0x2206, 0xE08B}, {0x2206, 0x84F7},
+	{0x2206, 0x20E4}, {0x2206, 0x8B84}, {0x2206, 0xFC05}, {0x2206, 0xF8FA},
+	{0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AC}, {0x2206, 0x201A},
+	{0x2206, 0xBF80}, {0x2206, 0x59D0}, {0x2206, 0x2402}, {0x2206, 0x803D},
+	{0x2206, 0xE0E0}, {0x2206, 0xE4E1}, {0x2206, 0xE0E5}, {0x2206, 0x5806},
+	{0x2206, 0x68C0}, {0x2206, 0xD1D2}, {0x2206, 0xE4E0}, {0x2206, 0xE4E5},
+	{0x2206, 0xE0E5}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x05FB},
+	{0x2206, 0x0BFB}, {0x2206, 0x58FF}, {0x2206, 0x9E11}, {0x2206, 0x06F0},
+	{0x2206, 0x0C81}, {0x2206, 0x8AE0}, {0x2206, 0x0019}, {0x2206, 0x1B89},
+	{0x2206, 0xCFEB}, {0x2206, 0x19EB}, {0x2206, 0x19B0}, {0x2206, 0xEFFF},
+	{0x2206, 0x0BFF}, {0x2206, 0x0425}, {0x2206, 0x0807}, {0x2206, 0x2640},
+	{0x2206, 0x7227}, {0x2206, 0x267E}, {0x2206, 0x2804}, {0x2206, 0xB729},
+	{0x2206, 0x2576}, {0x2206, 0x2A68}, {0x2206, 0xE52B}, {0x2206, 0xAD00},
+	{0x2206, 0x2CDB}, {0x2206, 0xF02D}, {0x2206, 0x67BB}, {0x2206, 0x2E7B},
+	{0x2206, 0x0F2F}, {0x2206, 0x7365}, {0x2206, 0x31AC}, {0x2206, 0xCC32},
+	{0x2206, 0x2300}, {0x2206, 0x332D}, {0x2206, 0x1734}, {0x2206, 0x7F52},
+	{0x2206, 0x3510}, {0x2206, 0x0036}, {0x2206, 0x0600}, {0x2206, 0x370C},
+	{0x2206, 0xC038}, {0x2206, 0x7FCE}, {0x2206, 0x3CE5}, {0x2206, 0xF73D},
+	{0x2206, 0x3DA4}, {0x2206, 0x6530}, {0x2206, 0x3E67}, {0x2206, 0x0053},
+	{0x2206, 0x69D2}, {0x2206, 0x0F6A}, {0x2206, 0x012C}, {0x2206, 0x6C2B},
+	{0x2206, 0x136E}, {0x2206, 0xE100}, {0x2206, 0x6F12}, {0x2206, 0xF771},
+	{0x2206, 0x006B}, {0x2206, 0x7306}, {0x2206, 0xEB74}, {0x2206, 0x94C7},
+	{0x2206, 0x7698}, {0x2206, 0x0A77}, {0x2206, 0x5000}, {0x2206, 0x788A},
+	{0x2206, 0x1579}, {0x2206, 0x7F6F}, {0x2206, 0x7A06}, {0x2206, 0xA600},
+	{0x2205, 0x8B90}, {0x2206, 0x8000}, {0x2205, 0x8B92}, {0x2206, 0x8000},
+	{0x2205, 0x8B94}, {0x2206, 0x8014}, {0x2208, 0xFFFA}, {0x2202, 0x3C65},
+	{0x2205, 0xFFF6}, {0x2206, 0x00F7}, {0x221F, 0x0000}, {0x221F, 0x0007},
+	{0x221E, 0x0042}, {0x2218, 0x0000}, {0x221E, 0x002D}, {0x2218, 0xF010},
+	{0x221E, 0x0020}, {0x2215, 0x0000}, {0x221E, 0x0023}, {0x2216, 0x8000},
+	{0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, {0x1362, 0x0115},
+	{0x1363, 0x0002}, {0x1363, 0x0000}, {0x1306, 0x000C}, {0x1307, 0x000C},
+	{0x1303, 0x0067}, {0x1304, 0x4444}, {0x1203, 0xFF00}, {0x1200, 0x7FC4},
+	{0x0900, 0x0000}, {0x0901, 0x0000}, {0x0902, 0x0000}, {0x0903, 0x0000},
+	{0x0865, 0x3210}, {0x087B, 0x0000}, {0x087C, 0xFF00}, {0x087D, 0x0000},
+	{0x087E, 0x0000}, {0x0801, 0x0100}, {0x0802, 0x0100}, {0x0A20, 0x2040},
+	{0x0A21, 0x2040}, {0x0A22, 0x2040}, {0x0A23, 0x2040}, {0x0A24, 0x2040},
+	{0x0A25, 0x2040}, {0x0A26, 0x2040}, {0x0A27, 0x2040}, {0x0A28, 0x2040},
+	{0x0A29, 0x2040}, {0x133F, 0x0030}, {0x133E, 0x000E}, {0x221F, 0x0000},
+	{0x2200, 0x1340}, {0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE},
+	{0x1B03, 0x0876},
+};
+
+static const struct rtl8367_initval rtl8367_initvals_2_0[] = {
+	{0x1b24, 0x0000}, {0x1b25, 0x0000}, {0x1b26, 0x0000}, {0x1b27, 0x0000},
+	{0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0007}, {0x221e, 0x0048},
+	{0x2219, 0x4012}, {0x221f, 0x0003}, {0x2201, 0x3554}, {0x2202, 0x63e8},
+	{0x2203, 0x99c2}, {0x2204, 0x0113}, {0x2205, 0x303e}, {0x220d, 0x0207},
+	{0x220e, 0xe100}, {0x221f, 0x0007}, {0x221e, 0x0040}, {0x2218, 0x0000},
+	{0x221f, 0x0007}, {0x221e, 0x002c}, {0x2218, 0x008b}, {0x221f, 0x0005},
+	{0x2205, 0xfff6}, {0x2206, 0x0080}, {0x221f, 0x0005}, {0x2205, 0x8000},
+	{0x2206, 0x0280}, {0x2206, 0x2bf7}, {0x2206, 0x00e0}, {0x2206, 0xfff7},
+	{0x2206, 0xa080}, {0x2206, 0x02ae}, {0x2206, 0xf602}, {0x2206, 0x804e},
+	{0x2206, 0x0201}, {0x2206, 0x5002}, {0x2206, 0x0163}, {0x2206, 0x0201},
+	{0x2206, 0x79e0}, {0x2206, 0x8b8c}, {0x2206, 0xe18b}, {0x2206, 0x8d1e},
+	{0x2206, 0x01e1}, {0x2206, 0x8b8e}, {0x2206, 0x1e01}, {0x2206, 0xa000},
+	{0x2206, 0xe4ae}, {0x2206, 0xd8bf}, {0x2206, 0x8b88}, {0x2206, 0xec00},
+	{0x2206, 0x19a9}, {0x2206, 0x8b90}, {0x2206, 0xf9ee}, {0x2206, 0xfff6},
+	{0x2206, 0x00ee}, {0x2206, 0xfff7}, {0x2206, 0xfce0}, {0x2206, 0xe140},
+	{0x2206, 0xe1e1}, {0x2206, 0x41f7}, {0x2206, 0x2ff6}, {0x2206, 0x28e4},
+	{0x2206, 0xe140}, {0x2206, 0xe5e1}, {0x2206, 0x4104}, {0x2206, 0xf8fa},
+	{0x2206, 0xef69}, {0x2206, 0xe08b}, {0x2206, 0x86ac}, {0x2206, 0x201a},
+	{0x2206, 0xbf80}, {0x2206, 0x77d0}, {0x2206, 0x6c02}, {0x2206, 0x2978},
+	{0x2206, 0xe0e0}, {0x2206, 0xe4e1}, {0x2206, 0xe0e5}, {0x2206, 0x5806},
+	{0x2206, 0x68c0}, {0x2206, 0xd1d2}, {0x2206, 0xe4e0}, {0x2206, 0xe4e5},
+	{0x2206, 0xe0e5}, {0x2206, 0xef96}, {0x2206, 0xfefc}, {0x2206, 0x0425},
+	{0x2206, 0x0807}, {0x2206, 0x2640}, {0x2206, 0x7227}, {0x2206, 0x267e},
+	{0x2206, 0x2804}, {0x2206, 0xb729}, {0x2206, 0x2576}, {0x2206, 0x2a68},
+	{0x2206, 0xe52b}, {0x2206, 0xad00}, {0x2206, 0x2cdb}, {0x2206, 0xf02d},
+	{0x2206, 0x67bb}, {0x2206, 0x2e7b}, {0x2206, 0x0f2f}, {0x2206, 0x7365},
+	{0x2206, 0x31ac}, {0x2206, 0xcc32}, {0x2206, 0x2300}, {0x2206, 0x332d},
+	{0x2206, 0x1734}, {0x2206, 0x7f52}, {0x2206, 0x3510}, {0x2206, 0x0036},
+	{0x2206, 0x0600}, {0x2206, 0x370c}, {0x2206, 0xc038}, {0x2206, 0x7fce},
+	{0x2206, 0x3ce5}, {0x2206, 0xf73d}, {0x2206, 0x3da4}, {0x2206, 0x6530},
+	{0x2206, 0x3e67}, {0x2206, 0x0053}, {0x2206, 0x69d2}, {0x2206, 0x0f6a},
+	{0x2206, 0x012c}, {0x2206, 0x6c2b}, {0x2206, 0x136e}, {0x2206, 0xe100},
+	{0x2206, 0x6f12}, {0x2206, 0xf771}, {0x2206, 0x006b}, {0x2206, 0x7306},
+	{0x2206, 0xeb74}, {0x2206, 0x94c7}, {0x2206, 0x7698}, {0x2206, 0x0a77},
+	{0x2206, 0x5000}, {0x2206, 0x788a}, {0x2206, 0x1579}, {0x2206, 0x7f6f},
+	{0x2206, 0x7a06}, {0x2206, 0xa600}, {0x2201, 0x0701}, {0x2200, 0x0405},
+	{0x221f, 0x0000}, {0x2200, 0x1340}, {0x221f, 0x0000}, {0x133f, 0x0010},
+	{0x133e, 0x0ffe}, {0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x121d, 0x7D16},
+	{0x121e, 0x03e8}, {0x121f, 0x024e}, {0x1220, 0x0230}, {0x1221, 0x0244},
+	{0x1222, 0x0226}, {0x1223, 0x024e}, {0x1224, 0x0230}, {0x1225, 0x0244},
+	{0x1226, 0x0226}, {0x1227, 0x00c0}, {0x1228, 0x00b4}, {0x122f, 0x00c0},
+	{0x1230, 0x00b4}, {0x0208, 0x03e8}, {0x0209, 0x03e8}, {0x020a, 0x03e8},
+	{0x020b, 0x03e8}, {0x020c, 0x03e8}, {0x020d, 0x03e8}, {0x020e, 0x03e8},
+	{0x020f, 0x03e8}, {0x0210, 0x03e8}, {0x0211, 0x03e8}, {0x0212, 0x03e8},
+	{0x0213, 0x03e8}, {0x0214, 0x03e8}, {0x0215, 0x03e8}, {0x0216, 0x03e8},
+	{0x0217, 0x03e8}, {0x0900, 0x0000}, {0x0901, 0x0000}, {0x0902, 0x0000},
+	{0x0903, 0x0000}, {0x0865, 0x3210}, {0x087b, 0x0000}, {0x087c, 0xff00},
+	{0x087d, 0x0000}, {0x087e, 0x0000}, {0x0801, 0x0100}, {0x0802, 0x0100},
+	{0x0A20, 0x2040}, {0x0A21, 0x2040}, {0x0A22, 0x2040}, {0x0A23, 0x2040},
+	{0x0A24, 0x2040}, {0x0A28, 0x2040}, {0x0A29, 0x2040}, {0x20A0, 0x1940},
+	{0x20C0, 0x1940}, {0x20E0, 0x1940}, {0x130c, 0x0050},
+};
+
+static const struct rtl8367_initval rtl8367_initvals_2_1[] = {
+	{0x1b24, 0x0000}, {0x1b25, 0x0000}, {0x1b26, 0x0000}, {0x1b27, 0x0000},
+	{0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0007}, {0x221e, 0x0048},
+	{0x2219, 0x4012}, {0x221f, 0x0003}, {0x2201, 0x3554}, {0x2202, 0x63e8},
+	{0x2203, 0x99c2}, {0x2204, 0x0113}, {0x2205, 0x303e}, {0x220d, 0x0207},
+	{0x220e, 0xe100}, {0x221f, 0x0007}, {0x221e, 0x0040}, {0x2218, 0x0000},
+	{0x221f, 0x0007}, {0x221e, 0x002c}, {0x2218, 0x008b}, {0x221f, 0x0005},
+	{0x2205, 0xfff6}, {0x2206, 0x0080}, {0x221f, 0x0005}, {0x2205, 0x8000},
+	{0x2206, 0x0280}, {0x2206, 0x2bf7}, {0x2206, 0x00e0}, {0x2206, 0xfff7},
+	{0x2206, 0xa080}, {0x2206, 0x02ae}, {0x2206, 0xf602}, {0x2206, 0x804e},
+	{0x2206, 0x0201}, {0x2206, 0x5002}, {0x2206, 0x0163}, {0x2206, 0x0201},
+	{0x2206, 0x79e0}, {0x2206, 0x8b8c}, {0x2206, 0xe18b}, {0x2206, 0x8d1e},
+	{0x2206, 0x01e1}, {0x2206, 0x8b8e}, {0x2206, 0x1e01}, {0x2206, 0xa000},
+	{0x2206, 0xe4ae}, {0x2206, 0xd8bf}, {0x2206, 0x8b88}, {0x2206, 0xec00},
+	{0x2206, 0x19a9}, {0x2206, 0x8b90}, {0x2206, 0xf9ee}, {0x2206, 0xfff6},
+	{0x2206, 0x00ee}, {0x2206, 0xfff7}, {0x2206, 0xfce0}, {0x2206, 0xe140},
+	{0x2206, 0xe1e1}, {0x2206, 0x41f7}, {0x2206, 0x2ff6}, {0x2206, 0x28e4},
+	{0x2206, 0xe140}, {0x2206, 0xe5e1}, {0x2206, 0x4104}, {0x2206, 0xf8fa},
+	{0x2206, 0xef69}, {0x2206, 0xe08b}, {0x2206, 0x86ac}, {0x2206, 0x201a},
+	{0x2206, 0xbf80}, {0x2206, 0x77d0}, {0x2206, 0x6c02}, {0x2206, 0x2978},
+	{0x2206, 0xe0e0}, {0x2206, 0xe4e1}, {0x2206, 0xe0e5}, {0x2206, 0x5806},
+	{0x2206, 0x68c0}, {0x2206, 0xd1d2}, {0x2206, 0xe4e0}, {0x2206, 0xe4e5},
+	{0x2206, 0xe0e5}, {0x2206, 0xef96}, {0x2206, 0xfefc}, {0x2206, 0x0425},
+	{0x2206, 0x0807}, {0x2206, 0x2640}, {0x2206, 0x7227}, {0x2206, 0x267e},
+	{0x2206, 0x2804}, {0x2206, 0xb729}, {0x2206, 0x2576}, {0x2206, 0x2a68},
+	{0x2206, 0xe52b}, {0x2206, 0xad00}, {0x2206, 0x2cdb}, {0x2206, 0xf02d},
+	{0x2206, 0x67bb}, {0x2206, 0x2e7b}, {0x2206, 0x0f2f}, {0x2206, 0x7365},
+	{0x2206, 0x31ac}, {0x2206, 0xcc32}, {0x2206, 0x2300}, {0x2206, 0x332d},
+	{0x2206, 0x1734}, {0x2206, 0x7f52}, {0x2206, 0x3510}, {0x2206, 0x0036},
+	{0x2206, 0x0600}, {0x2206, 0x370c}, {0x2206, 0xc038}, {0x2206, 0x7fce},
+	{0x2206, 0x3ce5}, {0x2206, 0xf73d}, {0x2206, 0x3da4}, {0x2206, 0x6530},
+	{0x2206, 0x3e67}, {0x2206, 0x0053}, {0x2206, 0x69d2}, {0x2206, 0x0f6a},
+	{0x2206, 0x012c}, {0x2206, 0x6c2b}, {0x2206, 0x136e}, {0x2206, 0xe100},
+	{0x2206, 0x6f12}, {0x2206, 0xf771}, {0x2206, 0x006b}, {0x2206, 0x7306},
+	{0x2206, 0xeb74}, {0x2206, 0x94c7}, {0x2206, 0x7698}, {0x2206, 0x0a77},
+	{0x2206, 0x5000}, {0x2206, 0x788a}, {0x2206, 0x1579}, {0x2206, 0x7f6f},
+	{0x2206, 0x7a06}, {0x2206, 0xa600}, {0x2201, 0x0701}, {0x2200, 0x0405},
+	{0x221f, 0x0000}, {0x2200, 0x1340}, {0x221f, 0x0000}, {0x133f, 0x0010},
+	{0x133e, 0x0ffe}, {0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x0900, 0x0000},
+	{0x0901, 0x0000}, {0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210},
+	{0x087b, 0x0000}, {0x087c, 0xff00}, {0x087d, 0x0000}, {0x087e, 0x0000},
+	{0x0801, 0x0100}, {0x0802, 0x0100}, {0x0A20, 0x2040}, {0x0A21, 0x2040},
+	{0x0A22, 0x2040}, {0x0A23, 0x2040}, {0x0A24, 0x2040}, {0x0A25, 0x2040},
+	{0x0A26, 0x2040}, {0x0A27, 0x2040}, {0x0A28, 0x2040}, {0x0A29, 0x2040},
+	{0x130c, 0x0050},
+};
+
+static int rtl8367_write_initvals(struct rtl8366_smi *smi,
+				  const struct rtl8367_initval *initvals,
+				  int count)
+{
+	int err;
+	int i;
+
+	for (i = 0; i < count; i++)
+		REG_WR(smi, initvals[i].reg, initvals[i].val);
+
+	return 0;
+}
+
+static int rtl8367_read_phy_reg(struct rtl8366_smi *smi,
+				u32 phy_addr, u32 phy_reg, u32 *val)
+{
+	int timeout;
+	u32 data;
+	int err;
+
+	if (phy_addr > RTL8367_PHY_ADDR_MAX)
+		return -EINVAL;
+
+	if (phy_reg > RTL8367_PHY_REG_MAX)
+		return -EINVAL;
+
+	REG_RD(smi, RTL8367_IA_STATUS_REG, &data);
+	if (data & RTL8367_IA_STATUS_PHY_BUSY)
+		return -ETIMEDOUT;
+
+	/* prepare address */
+	REG_WR(smi, RTL8367_IA_ADDRESS_REG,
+	       RTL8367_INTERNAL_PHY_REG(phy_addr, phy_reg));
+
+	/* send read command */
+	REG_WR(smi, RTL8367_IA_CTRL_REG,
+	       RTL8367_IA_CTRL_CMD_MASK | RTL8367_IA_CTRL_RW_READ);
+
+	timeout = 5;
+	do {
+		REG_RD(smi, RTL8367_IA_STATUS_REG, &data);
+		if ((data & RTL8367_IA_STATUS_PHY_BUSY) == 0)
+			break;
+
+		if (timeout--) {
+			dev_err(smi->parent, "phy read timed out\n");
+			return -ETIMEDOUT;
+		}
+
+		udelay(1);
+	} while (1);
+
+	/* read data */
+	REG_RD(smi, RTL8367_IA_READ_DATA_REG, val);
+
+	dev_dbg(smi->parent, "phy_read: addr:%02x, reg:%02x, val:%04x\n",
+		phy_addr, phy_reg, *val);
+	return 0;
+}
+
+static int rtl8367_write_phy_reg(struct rtl8366_smi *smi,
+				 u32 phy_addr, u32 phy_reg, u32 val)
+{
+	int timeout;
+	u32 data;
+	int err;
+
+	dev_dbg(smi->parent, "phy_write: addr:%02x, reg:%02x, val:%04x\n",
+		phy_addr, phy_reg, val);
+
+	if (phy_addr > RTL8367_PHY_ADDR_MAX)
+		return -EINVAL;
+
+	if (phy_reg > RTL8367_PHY_REG_MAX)
+		return -EINVAL;
+
+	REG_RD(smi, RTL8367_IA_STATUS_REG, &data);
+	if (data & RTL8367_IA_STATUS_PHY_BUSY)
+		return -ETIMEDOUT;
+
+	/* preapre data */
+	REG_WR(smi, RTL8367_IA_WRITE_DATA_REG, val);
+
+	/* prepare address */
+	REG_WR(smi, RTL8367_IA_ADDRESS_REG,
+	       RTL8367_INTERNAL_PHY_REG(phy_addr, phy_reg));
+
+	/* send write command */
+	REG_WR(smi, RTL8367_IA_CTRL_REG,
+	       RTL8367_IA_CTRL_CMD_MASK | RTL8367_IA_CTRL_RW_WRITE);
+
+	timeout = 5;
+	do {
+		REG_RD(smi, RTL8367_IA_STATUS_REG, &data);
+		if ((data & RTL8367_IA_STATUS_PHY_BUSY) == 0)
+			break;
+
+		if (timeout--) {
+			dev_err(smi->parent, "phy write timed out\n");
+			return -ETIMEDOUT;
+		}
+
+		udelay(1);
+	} while (1);
+
+	return 0;
+}
+
+static int rtl8367_init_regs0(struct rtl8366_smi *smi, unsigned mode)
+{
+	const struct rtl8367_initval *initvals;
+	int count;
+	int err;
+
+	switch (mode) {
+	case 0:
+		initvals = rtl8367_initvals_0_0;
+		count = ARRAY_SIZE(rtl8367_initvals_0_0);
+		break;
+
+	case 1:
+	case 2:
+		initvals = rtl8367_initvals_0_1;
+		count = ARRAY_SIZE(rtl8367_initvals_0_1);
+		break;
+
+	default:
+		dev_err(smi->parent, "%s: unknow mode %u\n", __func__, mode);
+		return -ENODEV;
+	}
+
+	err = rtl8367_write_initvals(smi, initvals, count);
+	if (err)
+		return err;
+
+	/* TODO: complete this */
+
+	return 0;
+}
+
+static int rtl8367_init_regs1(struct rtl8366_smi *smi, unsigned mode)
+{
+	const struct rtl8367_initval *initvals;
+	int count;
+
+	switch (mode) {
+	case 0:
+		initvals = rtl8367_initvals_1_0;
+		count = ARRAY_SIZE(rtl8367_initvals_1_0);
+		break;
+
+	case 1:
+	case 2:
+		initvals = rtl8367_initvals_1_1;
+		count = ARRAY_SIZE(rtl8367_initvals_1_1);
+		break;
+
+	default:
+		dev_err(smi->parent, "%s: unknow mode %u\n", __func__, mode);
+		return -ENODEV;
+	}
+
+	return rtl8367_write_initvals(smi, initvals, count);
+}
+
+static int rtl8367_init_regs2(struct rtl8366_smi *smi, unsigned mode)
+{
+	const struct rtl8367_initval *initvals;
+	int count;
+
+	switch (mode) {
+	case 0:
+		initvals = rtl8367_initvals_2_0;
+		count = ARRAY_SIZE(rtl8367_initvals_2_0);
+		break;
+
+	case 1:
+	case 2:
+		initvals = rtl8367_initvals_2_1;
+		count = ARRAY_SIZE(rtl8367_initvals_2_1);
+		break;
+
+	default:
+		dev_err(smi->parent, "%s: unknow mode %u\n", __func__, mode);
+		return -ENODEV;
+	}
+
+	return rtl8367_write_initvals(smi, initvals, count);
+}
+
+static int rtl8367_init_regs(struct rtl8366_smi *smi)
+{
+	u32 data;
+	u32 rlvid;
+	u32 mode;
+	int err;
+
+	REG_WR(smi, RTL8367_RTL_MAGIC_ID_REG, RTL8367_RTL_MAGIC_ID_VAL);
+
+	REG_RD(smi, RTL8367_CHIP_VER_REG, &data);
+	rlvid = (data >> RTL8367_CHIP_VER_RLVID_SHIFT) &
+		RTL8367_CHIP_VER_RLVID_MASK;
+
+	REG_RD(smi, RTL8367_CHIP_MODE_REG, &data);
+	mode = data & RTL8367_CHIP_MODE_MASK;
+
+	switch (rlvid) {
+	case 0:
+		err = rtl8367_init_regs0(smi, mode);
+		break;
+
+	case 1:
+		err = rtl8367_write_phy_reg(smi, 0, 31, 5);
+		if (err)
+			break;
+
+		err = rtl8367_write_phy_reg(smi, 0, 5, 0x3ffe);
+		if (err)
+			break;
+
+		err = rtl8367_read_phy_reg(smi, 0, 6, &data);
+		if (err)
+			break;
+
+		if (data == 0x94eb) {
+			err = rtl8367_init_regs1(smi, mode);
+		} else if (data == 0x2104) {
+			err = rtl8367_init_regs2(smi, mode);
+		} else {
+			dev_err(smi->parent, "unknow phy data %04x\n", data);
+			return -ENODEV;
+		}
+
+		break;
+
+	default:
+		dev_err(smi->parent, "unknow rlvid %u\n", rlvid);
+		err = -ENODEV;
+		break;
+	}
+
+	return err;
+}
+
+static int rtl8367_reset_chip(struct rtl8366_smi *smi)
+{
+	int timeout = 10;
+	int err;
+	u32 data;
+
+	REG_WR(smi, RTL8367_CHIP_RESET_REG, RTL8367_CHIP_RESET_HW);
+	msleep(RTL8367_RESET_DELAY);
+
+	do {
+		REG_RD(smi, RTL8367_CHIP_RESET_REG, &data);
+		if (!(data & RTL8367_CHIP_RESET_HW))
+			break;
+
+		msleep(1);
+	} while (--timeout);
+
+	if (!timeout) {
+		dev_err(smi->parent, "chip reset timed out\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int rtl8367_extif_set_mode(struct rtl8366_smi *smi, int id,
+				  enum rtl8367_extif_mode mode)
+{
+	int err;
+
+	/* set port mode */
+	switch (mode) {
+	case RTL8367_EXTIF_MODE_RGMII:
+	case RTL8367_EXTIF_MODE_RGMII_33V:
+		REG_WR(smi, RTL8367_CHIP_DEBUG0_REG, 0x0367);
+		REG_WR(smi, RTL8367_CHIP_DEBUG1_REG, 0x7777);
+		break;
+
+	case RTL8367_EXTIF_MODE_TMII_MAC:
+	case RTL8367_EXTIF_MODE_TMII_PHY:
+		REG_RMW(smi, RTL8367_BYPASS_LINE_RATE_REG,
+			BIT((id + 1) % 2), BIT((id + 1) % 2));
+		break;
+
+	case RTL8367_EXTIF_MODE_GMII:
+		REG_RMW(smi, RTL8367_CHIP_DEBUG0_REG,
+		        RTL8367_CHIP_DEBUG0_DUMMY0(id),
+			RTL8367_CHIP_DEBUG0_DUMMY0(id));
+		REG_RMW(smi, RTL8367_EXT_RGMXF_REG(id), BIT(6), BIT(6));
+		break;
+
+	case RTL8367_EXTIF_MODE_MII_MAC:
+	case RTL8367_EXTIF_MODE_MII_PHY:
+	case RTL8367_EXTIF_MODE_DISABLED:
+		REG_RMW(smi, RTL8367_BYPASS_LINE_RATE_REG,
+			BIT((id + 1) % 2), 0);
+		REG_RMW(smi, RTL8367_EXT_RGMXF_REG(id), BIT(6), 0);
+		break;
+
+	default:
+		dev_err(smi->parent,
+			"invalid mode for external interface %d\n", id);
+		return -EINVAL;
+	}
+
+	REG_RMW(smi, RTL8367_DIS_REG,
+		RTL8367_DIS_RGMII_MASK << RTL8367_DIS_RGMII_SHIFT(id),
+		mode << RTL8367_DIS_RGMII_SHIFT(id));
+
+	return 0;
+}
+
+static int rtl8367_extif_set_force(struct rtl8366_smi *smi, int id,
+				   struct rtl8367_port_ability *pa)
+{
+	u32 mask;
+	u32 val;
+	int err;
+
+	mask = (RTL8367_DI_FORCE_MODE |
+		RTL8367_DI_FORCE_NWAY |
+		RTL8367_DI_FORCE_TXPAUSE |
+		RTL8367_DI_FORCE_RXPAUSE |
+		RTL8367_DI_FORCE_LINK |
+		RTL8367_DI_FORCE_DUPLEX |
+		RTL8367_DI_FORCE_SPEED_MASK);
+
+	val = pa->speed;
+	val |= pa->force_mode ? RTL8367_DI_FORCE_MODE : 0;
+	val |= pa->nway ? RTL8367_DI_FORCE_NWAY : 0;
+	val |= pa->txpause ? RTL8367_DI_FORCE_TXPAUSE : 0;
+	val |= pa->rxpause ? RTL8367_DI_FORCE_RXPAUSE : 0;
+	val |= pa->link ? RTL8367_DI_FORCE_LINK : 0;
+	val |= pa->duplex ? RTL8367_DI_FORCE_DUPLEX : 0;
+
+	REG_RMW(smi, RTL8367_DI_FORCE_REG(id), mask, val);
+
+	return 0;
+}
+
+static int rtl8367_extif_set_rgmii_delay(struct rtl8366_smi *smi, int id,
+					 unsigned txdelay, unsigned rxdelay)
+{
+	u32 mask;
+	u32 val;
+	int err;
+
+	mask = (RTL8367_EXT_RGMXF_RXDELAY_MASK |
+		(RTL8367_EXT_RGMXF_TXDELAY_MASK <<
+			RTL8367_EXT_RGMXF_TXDELAY_SHIFT));
+
+	val = rxdelay;
+	val |= txdelay << RTL8367_EXT_RGMXF_TXDELAY_SHIFT;
+
+	REG_RMW(smi, RTL8367_EXT_RGMXF_REG(id), mask, val);
+
+	return 0;
+}
+
+static int rtl8367_extif_init(struct rtl8366_smi *smi, int id,
+			      struct rtl8367_extif_config *cfg)
+{
+	enum rtl8367_extif_mode mode;
+	int err;
+
+	mode = (cfg) ? cfg->mode : RTL8367_EXTIF_MODE_DISABLED;
+
+	err = rtl8367_extif_set_mode(smi, id, mode);
+	if (err)
+		return err;
+
+	if (mode != RTL8367_EXTIF_MODE_DISABLED) {
+		err = rtl8367_extif_set_force(smi, id, &cfg->ability);
+		if (err)
+			return err;
+
+		err = rtl8367_extif_set_rgmii_delay(smi, id, cfg->txdelay,
+						     cfg->rxdelay);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int rtl8367_led_group_set_ports(struct rtl8366_smi *smi,
+				       unsigned int group, u16 port_mask)
+{
+	u32 reg;
+	u32 s;
+	int err;
+
+	port_mask &= RTL8367_PARA_LED_IO_EN_PMASK;
+	s = (group % 2) * 8;
+	reg = RTL8367_PARA_LED_IO_EN1_REG + (group / 2);
+
+	REG_RMW(smi, reg, (RTL8367_PARA_LED_IO_EN_PMASK << s), port_mask << s);
+
+	return 0;
+}
+
+static int rtl8367_led_group_set_mode(struct rtl8366_smi *smi,
+				      unsigned int mode)
+{
+	u16 mask;
+	u16 set;
+	int err;
+
+	mode &= RTL8367_LED_CONFIG_DATA_M;
+
+	mask = (RTL8367_LED_CONFIG_DATA_M << RTL8367_LED_CONFIG_DATA_S) |
+		RTL8367_LED_CONFIG_SEL;
+	set = (mode << RTL8367_LED_CONFIG_DATA_S) | RTL8367_LED_CONFIG_SEL;
+
+	REG_RMW(smi, RTL8367_LED_CONFIG_REG, mask, set);
+
+	return 0;
+}
+
+static int rtl8367_led_group_set_config(struct rtl8366_smi *smi,
+				        unsigned int led, unsigned int cfg)
+{
+	u16 mask;
+	u16 set;
+	int err;
+
+	mask = (RTL8367_LED_CONFIG_LED_CFG_M << (led * 4)) |
+		RTL8367_LED_CONFIG_SEL;
+	set = (cfg & RTL8367_LED_CONFIG_LED_CFG_M) << (led * 4);
+
+	REG_RMW(smi, RTL8367_LED_CONFIG_REG, mask, set);
+	return 0;
+}
+
+static int rtl8367_led_op_select_parallel(struct rtl8366_smi *smi)
+{
+	int err;
+
+	REG_WR(smi, RTL8367_LED_SYS_CONFIG_REG, 0x1472);
+	return 0;
+}
+
+static int rtl8367_led_blinkrate_set(struct rtl8366_smi *smi, unsigned int rate)
+{
+	u16 mask;
+	u16 set;
+	int err;
+
+	mask = RTL8367_LED_MODE_RATE_M << RTL8367_LED_MODE_RATE_S;
+	set = (rate & RTL8367_LED_MODE_RATE_M) << RTL8367_LED_MODE_RATE_S;
+	REG_RMW(smi, RTL8367_LED_MODE_REG, mask, set);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static int rtl8367_extif_init_of(struct rtl8366_smi *smi, int id,
+				 const char *name)
+{
+	struct rtl8367_extif_config *cfg;
+	const __be32 *prop;
+	int size;
+	int err;
+
+	prop = of_get_property(smi->parent->of_node, name, &size);
+	if (!prop)
+		return rtl8367_extif_init(smi, id, NULL);
+
+	if (size != (9 * sizeof(*prop))) {
+		dev_err(smi->parent, "%s property is invalid\n", name);
+		return -EINVAL;
+	}
+
+	cfg = kzalloc(sizeof(struct rtl8367_extif_config), GFP_KERNEL);
+	if (!cfg)
+		return -ENOMEM;
+
+	cfg->txdelay = be32_to_cpup(prop++);
+	cfg->rxdelay = be32_to_cpup(prop++);
+	cfg->mode = be32_to_cpup(prop++);
+	cfg->ability.force_mode = be32_to_cpup(prop++);
+	cfg->ability.txpause = be32_to_cpup(prop++);
+	cfg->ability.rxpause = be32_to_cpup(prop++);
+	cfg->ability.link = be32_to_cpup(prop++);
+	cfg->ability.duplex = be32_to_cpup(prop++);
+	cfg->ability.speed = be32_to_cpup(prop++);
+
+	err = rtl8367_extif_init(smi, id, cfg);
+	kfree(cfg);
+
+	return err;
+}
+#else
+static int rtl8367_extif_init_of(struct rtl8366_smi *smi, int id,
+				 const char *name)
+{
+	return -EINVAL;
+}
+#endif
+
+static int rtl8367_setup(struct rtl8366_smi *smi)
+{
+	struct rtl8367_platform_data *pdata;
+	int err;
+	int i;
+
+	pdata = smi->parent->platform_data;
+
+	err = rtl8367_init_regs(smi);
+	if (err)
+		return err;
+
+	/* initialize external interfaces */
+	if (smi->parent->of_node) {
+		err = rtl8367_extif_init_of(smi, 0, "realtek,extif0");
+		if (err)
+			return err;
+
+		err = rtl8367_extif_init_of(smi, 1, "realtek,extif1");
+		if (err)
+			return err;
+	} else {
+		err = rtl8367_extif_init(smi, 0, pdata->extif0_cfg);
+		if (err)
+			return err;
+
+		err = rtl8367_extif_init(smi, 1, pdata->extif1_cfg);
+		if (err)
+			return err;
+	}
+
+	/* set maximum packet length to 1536 bytes */
+	REG_RMW(smi, RTL8367_SWC0_REG, RTL8367_SWC0_MAX_LENGTH_MASK,
+		RTL8367_SWC0_MAX_LENGTH_1536);
+
+	/*
+	 * discard VLAN tagged packets if the port is not a member of
+	 * the VLAN with which the packets is associated.
+	 */
+	REG_WR(smi, RTL8367_VLAN_INGRESS_REG, RTL8367_PORTS_ALL);
+
+	/*
+	 * Setup egress tag mode for each port.
+	 */
+	for (i = 0; i < RTL8367_NUM_PORTS; i++)
+		REG_RMW(smi,
+			RTL8367_PORT_CFG_REG(i),
+			RTL8367_PORT_CFG_EGRESS_MODE_MASK <<
+				RTL8367_PORT_CFG_EGRESS_MODE_SHIFT,
+			RTL8367_PORT_CFG_EGRESS_MODE_ORIGINAL <<
+				RTL8367_PORT_CFG_EGRESS_MODE_SHIFT);
+
+	/* setup LEDs */
+	err = rtl8367_led_group_set_ports(smi, 0, RTL8367_PORTS_ALL);
+	if (err)
+		return err;
+
+	err = rtl8367_led_group_set_mode(smi, 0);
+	if (err)
+		return err;
+
+	err = rtl8367_led_op_select_parallel(smi);
+	if (err)
+		return err;
+
+	err = rtl8367_led_blinkrate_set(smi, 1);
+	if (err)
+		return err;
+
+	err = rtl8367_led_group_set_config(smi, 0, 2);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int rtl8367_get_mib_counter(struct rtl8366_smi *smi, int counter,
+				   int port, unsigned long long *val)
+{
+	struct rtl8366_mib_counter *mib;
+	int offset;
+	int i;
+	int err;
+	u32 addr, data;
+	u64 mibvalue;
+
+	if (port > RTL8367_NUM_PORTS || counter >= RTL8367_MIB_COUNT)
+		return -EINVAL;
+
+	mib = &rtl8367_mib_counters[counter];
+	addr = RTL8367_MIB_COUNTER_PORT_OFFSET * port + mib->offset;
+
+	/*
+	 * Writing access counter address first
+	 * then ASIC will prepare 64bits counter wait for being retrived
+	 */
+	REG_WR(smi, RTL8367_MIB_ADDRESS_REG, addr >> 2);
+
+	/* read MIB control register */
+	REG_RD(smi, RTL8367_MIB_CTRL_REG(0), &data);
+
+	if (data & RTL8367_MIB_CTRL_BUSY_MASK)
+		return -EBUSY;
+
+	if (data & RTL8367_MIB_CTRL_RESET_MASK)
+		return -EIO;
+
+	if (mib->length == 4)
+		offset = 3;
+	else
+		offset = (mib->offset + 1) % 4;
+
+	mibvalue = 0;
+	for (i = 0; i < mib->length; i++) {
+		REG_RD(smi, RTL8367_MIB_COUNTER_REG(offset - i), &data);
+		mibvalue = (mibvalue << 16) | (data & 0xFFFF);
+	}
+
+	*val = mibvalue;
+	return 0;
+}
+
+static int rtl8367_get_vlan_4k(struct rtl8366_smi *smi, u32 vid,
+				struct rtl8366_vlan_4k *vlan4k)
+{
+	u32 data[RTL8367_TA_VLAN_DATA_SIZE];
+	int err;
+	int i;
+
+	memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k));
+
+	if (vid >= RTL8367_NUM_VIDS)
+		return -EINVAL;
+
+	/* write VID */
+	REG_WR(smi, RTL8367_TA_ADDR_REG, vid);
+
+	/* write table access control word */
+	REG_WR(smi, RTL8367_TA_CTRL_REG, RTL8367_TA_CTRL_CVLAN_READ);
+
+	for (i = 0; i < ARRAY_SIZE(data); i++)
+		REG_RD(smi, RTL8367_TA_DATA_REG(i), &data[i]);
+
+	vlan4k->vid = vid;
+	vlan4k->member = (data[0] >> RTL8367_TA_VLAN_MEMBER_SHIFT) &
+			 RTL8367_TA_VLAN_MEMBER_MASK;
+	vlan4k->fid = (data[1] >> RTL8367_TA_VLAN_FID_SHIFT) &
+		      RTL8367_TA_VLAN_FID_MASK;
+	vlan4k->untag = (data[2] >> RTL8367_TA_VLAN_UNTAG1_SHIFT) &
+			RTL8367_TA_VLAN_UNTAG1_MASK;
+	vlan4k->untag |= ((data[3] >> RTL8367_TA_VLAN_UNTAG2_SHIFT) &
+			  RTL8367_TA_VLAN_UNTAG2_MASK) << 2;
+
+	return 0;
+}
+
+static int rtl8367_set_vlan_4k(struct rtl8366_smi *smi,
+				const struct rtl8366_vlan_4k *vlan4k)
+{
+	u32 data[RTL8367_TA_VLAN_DATA_SIZE];
+	int err;
+	int i;
+
+	if (vlan4k->vid >= RTL8367_NUM_VIDS ||
+	    vlan4k->member > RTL8367_TA_VLAN_MEMBER_MASK ||
+	    vlan4k->untag > RTL8367_UNTAG_MASK ||
+	    vlan4k->fid > RTL8367_FIDMAX)
+		return -EINVAL;
+
+	data[0] = (vlan4k->member & RTL8367_TA_VLAN_MEMBER_MASK) <<
+		  RTL8367_TA_VLAN_MEMBER_SHIFT;
+	data[1] = (vlan4k->fid & RTL8367_TA_VLAN_FID_MASK) <<
+		  RTL8367_TA_VLAN_FID_SHIFT;
+	data[2] = (vlan4k->untag & RTL8367_TA_VLAN_UNTAG1_MASK) <<
+		  RTL8367_TA_VLAN_UNTAG1_SHIFT;
+	data[3] = ((vlan4k->untag >> 2) & RTL8367_TA_VLAN_UNTAG2_MASK) <<
+		  RTL8367_TA_VLAN_UNTAG2_SHIFT;
+
+	for (i = 0; i < ARRAY_SIZE(data); i++)
+		REG_WR(smi, RTL8367_TA_DATA_REG(i), data[i]);
+
+	/* write VID */
+	REG_WR(smi, RTL8367_TA_ADDR_REG,
+	       vlan4k->vid & RTL8367_TA_VLAN_VID_MASK);
+
+	/* write table access control word */
+	REG_WR(smi, RTL8367_TA_CTRL_REG, RTL8367_TA_CTRL_CVLAN_WRITE);
+
+	return 0;
+}
+
+static int rtl8367_get_vlan_mc(struct rtl8366_smi *smi, u32 index,
+				struct rtl8366_vlan_mc *vlanmc)
+{
+	u32 data[RTL8367_VLAN_MC_DATA_SIZE];
+	int err;
+	int i;
+
+	memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc));
+
+	if (index >= RTL8367_NUM_VLANS)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(data); i++)
+		REG_RD(smi, RTL8367_VLAN_MC_BASE(index) + i, &data[i]);
+
+	vlanmc->member = (data[0] >> RTL8367_VLAN_MC_MEMBER_SHIFT) &
+			 RTL8367_VLAN_MC_MEMBER_MASK;
+	vlanmc->fid = (data[1] >> RTL8367_VLAN_MC_FID_SHIFT) &
+		      RTL8367_VLAN_MC_FID_MASK;
+	vlanmc->vid = (data[3] >> RTL8367_VLAN_MC_EVID_SHIFT) &
+		      RTL8367_VLAN_MC_EVID_MASK;
+
+	return 0;
+}
+
+static int rtl8367_set_vlan_mc(struct rtl8366_smi *smi, u32 index,
+				const struct rtl8366_vlan_mc *vlanmc)
+{
+	u32 data[RTL8367_VLAN_MC_DATA_SIZE];
+	int err;
+	int i;
+
+	if (index >= RTL8367_NUM_VLANS ||
+	    vlanmc->vid >= RTL8367_NUM_VIDS ||
+	    vlanmc->priority > RTL8367_PRIORITYMAX ||
+	    vlanmc->member > RTL8367_VLAN_MC_MEMBER_MASK ||
+	    vlanmc->untag > RTL8367_UNTAG_MASK ||
+	    vlanmc->fid > RTL8367_FIDMAX)
+		return -EINVAL;
+
+	data[0] = (vlanmc->member & RTL8367_VLAN_MC_MEMBER_MASK) <<
+		  RTL8367_VLAN_MC_MEMBER_SHIFT;
+	data[1] = (vlanmc->fid & RTL8367_VLAN_MC_FID_MASK) <<
+		  RTL8367_VLAN_MC_FID_SHIFT;
+	data[2] = 0;
+	data[3] = (vlanmc->vid & RTL8367_VLAN_MC_EVID_MASK) <<
+		   RTL8367_VLAN_MC_EVID_SHIFT;
+
+	for (i = 0; i < ARRAY_SIZE(data); i++)
+		REG_WR(smi, RTL8367_VLAN_MC_BASE(index) + i, data[i]);
+
+	return 0;
+}
+
+static int rtl8367_get_mc_index(struct rtl8366_smi *smi, int port, int *val)
+{
+	u32 data;
+	int err;
+
+	if (port >= RTL8367_NUM_PORTS)
+		return -EINVAL;
+
+	REG_RD(smi, RTL8367_VLAN_PVID_CTRL_REG(port), &data);
+
+	*val = (data >> RTL8367_VLAN_PVID_CTRL_SHIFT(port)) &
+	       RTL8367_VLAN_PVID_CTRL_MASK;
+
+	return 0;
+}
+
+static int rtl8367_set_mc_index(struct rtl8366_smi *smi, int port, int index)
+{
+	if (port >= RTL8367_NUM_PORTS || index >= RTL8367_NUM_VLANS)
+		return -EINVAL;
+
+	return rtl8366_smi_rmwr(smi, RTL8367_VLAN_PVID_CTRL_REG(port),
+				RTL8367_VLAN_PVID_CTRL_MASK <<
+					RTL8367_VLAN_PVID_CTRL_SHIFT(port),
+				(index & RTL8367_VLAN_PVID_CTRL_MASK) <<
+					RTL8367_VLAN_PVID_CTRL_SHIFT(port));
+}
+
+static int rtl8367_enable_vlan(struct rtl8366_smi *smi, int enable)
+{
+	return rtl8366_smi_rmwr(smi, RTL8367_VLAN_CTRL_REG,
+				RTL8367_VLAN_CTRL_ENABLE,
+				(enable) ? RTL8367_VLAN_CTRL_ENABLE : 0);
+}
+
+static int rtl8367_enable_vlan4k(struct rtl8366_smi *smi, int enable)
+{
+	return 0;
+}
+
+static int rtl8367_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan)
+{
+	unsigned max = RTL8367_NUM_VLANS;
+
+	if (smi->vlan4k_enabled)
+		max = RTL8367_NUM_VIDS - 1;
+
+	if (vlan == 0 || vlan >= max)
+		return 0;
+
+	return 1;
+}
+
+static int rtl8367_enable_port(struct rtl8366_smi *smi, int port, int enable)
+{
+	int err;
+
+	REG_WR(smi, RTL8367_PORT_ISOLATION_REG(port),
+	       (enable) ? RTL8367_PORTS_ALL : 0);
+
+	return 0;
+}
+
+static int rtl8367_sw_reset_mibs(struct switch_dev *dev,
+				  const struct switch_attr *attr,
+				  struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	return rtl8366_smi_rmwr(smi, RTL8367_MIB_CTRL_REG(0), 0,
+				RTL8367_MIB_CTRL_GLOBAL_RESET_MASK);
+}
+
+static int rtl8367_sw_get_port_link(struct switch_dev *dev,
+				    int port,
+				    struct switch_port_link *link)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data = 0;
+	u32 speed;
+
+	if (port >= RTL8367_NUM_PORTS)
+		return -EINVAL;
+
+	rtl8366_smi_read_reg(smi, RTL8367_PORT_STATUS_REG(port), &data);
+
+	link->link = !!(data & RTL8367_PORT_STATUS_LINK);
+	if (!link->link)
+		return 0;
+
+	link->duplex = !!(data & RTL8367_PORT_STATUS_DUPLEX);
+	link->rx_flow = !!(data & RTL8367_PORT_STATUS_RXPAUSE);
+	link->tx_flow = !!(data & RTL8367_PORT_STATUS_TXPAUSE);
+	link->aneg = !!(data & RTL8367_PORT_STATUS_NWAY);
+
+	speed = (data & RTL8367_PORT_STATUS_SPEED_MASK);
+	switch (speed) {
+	case 0:
+		link->speed = SWITCH_PORT_SPEED_10;
+		break;
+	case 1:
+		link->speed = SWITCH_PORT_SPEED_100;
+		break;
+	case 2:
+		link->speed = SWITCH_PORT_SPEED_1000;
+		break;
+	default:
+		link->speed = SWITCH_PORT_SPEED_UNKNOWN;
+		break;
+	}
+
+	return 0;
+}
+
+static int rtl8367_sw_get_max_length(struct switch_dev *dev,
+				     const struct switch_attr *attr,
+				     struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8367_SWC0_REG, &data);
+	val->value.i = (data & RTL8367_SWC0_MAX_LENGTH_MASK) >>
+			RTL8367_SWC0_MAX_LENGTH_SHIFT;
+
+	return 0;
+}
+
+static int rtl8367_sw_set_max_length(struct switch_dev *dev,
+				     const struct switch_attr *attr,
+				     struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 max_len;
+
+	switch (val->value.i) {
+	case 0:
+		max_len = RTL8367_SWC0_MAX_LENGTH_1522;
+		break;
+	case 1:
+		max_len = RTL8367_SWC0_MAX_LENGTH_1536;
+		break;
+	case 2:
+		max_len = RTL8367_SWC0_MAX_LENGTH_1552;
+		break;
+	case 3:
+		max_len = RTL8367_SWC0_MAX_LENGTH_16000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return rtl8366_smi_rmwr(smi, RTL8367_SWC0_REG,
+			        RTL8367_SWC0_MAX_LENGTH_MASK, max_len);
+}
+
+
+static int rtl8367_sw_reset_port_mibs(struct switch_dev *dev,
+				       const struct switch_attr *attr,
+				       struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	int port;
+
+	port = val->port_vlan;
+	if (port >= RTL8367_NUM_PORTS)
+		return -EINVAL;
+
+	return rtl8366_smi_rmwr(smi, RTL8367_MIB_CTRL_REG(port / 8), 0,
+				RTL8367_MIB_CTRL_PORT_RESET_MASK(port % 8));
+}
+
+static int rtl8367_sw_get_port_stats(struct switch_dev *dev, int port,
+                                        struct switch_port_stats *stats)
+{
+	return (rtl8366_sw_get_port_stats(dev, port, stats,
+				RTL8367_MIB_TXB_ID, RTL8367_MIB_RXB_ID));
+}
+
+static struct switch_attr rtl8367_globals[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.set = rtl8366_sw_set_vlan_enable,
+		.get = rtl8366_sw_get_vlan_enable,
+		.max = 1,
+		.ofs = 1
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan4k",
+		.description = "Enable VLAN 4K mode",
+		.set = rtl8366_sw_set_vlan_enable,
+		.get = rtl8366_sw_get_vlan_enable,
+		.max = 1,
+		.ofs = 2
+	}, {
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mibs",
+		.description = "Reset all MIB counters",
+		.set = rtl8367_sw_reset_mibs,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "max_length",
+		.description = "Get/Set the maximum length of valid packets"
+			       "(0:1522, 1:1536, 2:1552, 3:16000)",
+		.set = rtl8367_sw_set_max_length,
+		.get = rtl8367_sw_get_max_length,
+		.max = 3,
+	}
+};
+
+static struct switch_attr rtl8367_port[] = {
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mib",
+		.description = "Reset single port MIB counters",
+		.set = rtl8367_sw_reset_port_mibs,
+	}, {
+		.type = SWITCH_TYPE_STRING,
+		.name = "mib",
+		.description = "Get MIB counters for port",
+		.max = 33,
+		.set = NULL,
+		.get = rtl8366_sw_get_port_mib,
+	},
+};
+
+static struct switch_attr rtl8367_vlan[] = {
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "info",
+		.description = "Get vlan information",
+		.max = 1,
+		.set = NULL,
+		.get = rtl8366_sw_get_vlan_info,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "fid",
+		.description = "Get/Set vlan FID",
+		.max = RTL8367_FIDMAX,
+		.set = rtl8366_sw_set_vlan_fid,
+		.get = rtl8366_sw_get_vlan_fid,
+	},
+};
+
+static const struct switch_dev_ops rtl8367_sw_ops = {
+	.attr_global = {
+		.attr = rtl8367_globals,
+		.n_attr = ARRAY_SIZE(rtl8367_globals),
+	},
+	.attr_port = {
+		.attr = rtl8367_port,
+		.n_attr = ARRAY_SIZE(rtl8367_port),
+	},
+	.attr_vlan = {
+		.attr = rtl8367_vlan,
+		.n_attr = ARRAY_SIZE(rtl8367_vlan),
+	},
+
+	.get_vlan_ports = rtl8366_sw_get_vlan_ports,
+	.set_vlan_ports = rtl8366_sw_set_vlan_ports,
+	.get_port_pvid = rtl8366_sw_get_port_pvid,
+	.set_port_pvid = rtl8366_sw_set_port_pvid,
+	.reset_switch = rtl8366_sw_reset_switch,
+	.get_port_link = rtl8367_sw_get_port_link,
+	.get_port_stats = rtl8367_sw_get_port_stats,
+};
+
+static int rtl8367_switch_init(struct rtl8366_smi *smi)
+{
+	struct switch_dev *dev = &smi->sw_dev;
+	int err;
+
+	dev->name = "RTL8367";
+	dev->cpu_port = RTL8367_CPU_PORT_NUM;
+	dev->ports = RTL8367_NUM_PORTS;
+	dev->vlans = RTL8367_NUM_VIDS;
+	dev->ops = &rtl8367_sw_ops;
+	dev->alias = dev_name(smi->parent);
+
+	err = register_switch(dev, NULL);
+	if (err)
+		dev_err(smi->parent, "switch registration failed\n");
+
+	return err;
+}
+
+static void rtl8367_switch_cleanup(struct rtl8366_smi *smi)
+{
+	unregister_switch(&smi->sw_dev);
+}
+
+static int rtl8367_mii_read(struct mii_bus *bus, int addr, int reg)
+{
+	struct rtl8366_smi *smi = bus->priv;
+	u32 val = 0;
+	int err;
+
+	err = rtl8367_read_phy_reg(smi, addr, reg, &val);
+	if (err)
+		return 0xffff;
+
+	return val;
+}
+
+static int rtl8367_mii_write(struct mii_bus *bus, int addr, int reg, u16 val)
+{
+	struct rtl8366_smi *smi = bus->priv;
+	u32 t;
+	int err;
+
+	err = rtl8367_write_phy_reg(smi, addr, reg, val);
+	if (err)
+		return err;
+
+	/* flush write */
+	(void) rtl8367_read_phy_reg(smi, addr, reg, &t);
+
+	return err;
+}
+
+static int rtl8367_detect(struct rtl8366_smi *smi)
+{
+	u32 rtl_no = 0;
+	u32 rtl_ver = 0;
+	char *chip_name;
+	int ret;
+
+	ret = rtl8366_smi_read_reg(smi, RTL8367_RTL_NO_REG, &rtl_no);
+	if (ret) {
+		dev_err(smi->parent, "unable to read chip number\n");
+		return ret;
+	}
+
+	switch (rtl_no) {
+	case RTL8367_RTL_NO_8367R:
+		chip_name = "8367R";
+		break;
+	case RTL8367_RTL_NO_8367M:
+		chip_name = "8367M";
+		break;
+	default:
+		dev_err(smi->parent, "unknown chip number (%04x)\n", rtl_no);
+		return -ENODEV;
+	}
+
+	ret = rtl8366_smi_read_reg(smi, RTL8367_RTL_VER_REG, &rtl_ver);
+	if (ret) {
+		dev_err(smi->parent, "unable to read chip version\n");
+		return ret;
+	}
+
+	dev_info(smi->parent, "RTL%s ver. %u chip found\n",
+		 chip_name, rtl_ver & RTL8367_RTL_VER_MASK);
+
+	return 0;
+}
+
+static struct rtl8366_smi_ops rtl8367_smi_ops = {
+	.detect		= rtl8367_detect,
+	.reset_chip	= rtl8367_reset_chip,
+	.setup		= rtl8367_setup,
+
+	.mii_read	= rtl8367_mii_read,
+	.mii_write	= rtl8367_mii_write,
+
+	.get_vlan_mc	= rtl8367_get_vlan_mc,
+	.set_vlan_mc	= rtl8367_set_vlan_mc,
+	.get_vlan_4k	= rtl8367_get_vlan_4k,
+	.set_vlan_4k	= rtl8367_set_vlan_4k,
+	.get_mc_index	= rtl8367_get_mc_index,
+	.set_mc_index	= rtl8367_set_mc_index,
+	.get_mib_counter = rtl8367_get_mib_counter,
+	.is_vlan_valid	= rtl8367_is_vlan_valid,
+	.enable_vlan	= rtl8367_enable_vlan,
+	.enable_vlan4k	= rtl8367_enable_vlan4k,
+	.enable_port	= rtl8367_enable_port,
+};
+
+static int rtl8367_probe(struct platform_device *pdev)
+{
+	struct rtl8366_smi *smi;
+	int err;
+
+	smi = rtl8366_smi_probe(pdev);
+	if (IS_ERR(smi))
+		return PTR_ERR(smi);
+
+	smi->clk_delay = 1500;
+	smi->cmd_read = 0xb9;
+	smi->cmd_write = 0xb8;
+	smi->ops = &rtl8367_smi_ops;
+	smi->cpu_port = RTL8367_CPU_PORT_NUM;
+	smi->num_ports = RTL8367_NUM_PORTS;
+	smi->num_vlan_mc = RTL8367_NUM_VLANS;
+	smi->mib_counters = rtl8367_mib_counters;
+	smi->num_mib_counters = ARRAY_SIZE(rtl8367_mib_counters);
+
+	err = rtl8366_smi_init(smi);
+	if (err)
+		goto err_free_smi;
+
+	platform_set_drvdata(pdev, smi);
+
+	err = rtl8367_switch_init(smi);
+	if (err)
+		goto err_clear_drvdata;
+
+	return 0;
+
+ err_clear_drvdata:
+	platform_set_drvdata(pdev, NULL);
+	rtl8366_smi_cleanup(smi);
+ err_free_smi:
+	kfree(smi);
+	return err;
+}
+
+static int rtl8367_remove(struct platform_device *pdev)
+{
+	struct rtl8366_smi *smi = platform_get_drvdata(pdev);
+
+	if (smi) {
+		rtl8367_switch_cleanup(smi);
+		platform_set_drvdata(pdev, NULL);
+		rtl8366_smi_cleanup(smi);
+		kfree(smi);
+	}
+
+	return 0;
+}
+
+static void rtl8367_shutdown(struct platform_device *pdev)
+{
+	struct rtl8366_smi *smi = platform_get_drvdata(pdev);
+
+	if (smi)
+		rtl8367_reset_chip(smi);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id rtl8367_match[] = {
+       { .compatible = "realtek,rtl8367" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, rtl8367_match);
+#endif
+
+static struct platform_driver rtl8367_driver = {
+	.driver = {
+		.name		= RTL8367_DRIVER_NAME,
+		.owner		= THIS_MODULE,
+#ifdef CONFIG_OF
+		.of_match_table = of_match_ptr(rtl8367_match),
+#endif
+	},
+	.probe		= rtl8367_probe,
+	.remove		= rtl8367_remove,
+	.shutdown	= rtl8367_shutdown,
+};
+
+static int __init rtl8367_module_init(void)
+{
+	return platform_driver_register(&rtl8367_driver);
+}
+module_init(rtl8367_module_init);
+
+static void __exit rtl8367_module_exit(void)
+{
+	platform_driver_unregister(&rtl8367_driver);
+}
+module_exit(rtl8367_module_exit);
+
+MODULE_DESCRIPTION("Realtek RTL8367 ethernet switch driver");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" RTL8367_DRIVER_NAME);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/rtl8367b.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/rtl8367b.c
new file mode 100644
index 0000000..3599791
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/rtl8367b.c
@@ -0,0 +1,1673 @@
+/*
+ * Platform driver for the Realtek RTL8367R-VB ethernet switches
+ *
+ * Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/rtl8367.h>
+
+#include "rtl8366_smi.h"
+
+#define RTL8367B_RESET_DELAY	1000	/* msecs*/
+
+#define RTL8367B_PHY_ADDR_MAX	8
+#define RTL8367B_PHY_REG_MAX	31
+
+#define RTL8367B_VID_MASK	0x3fff
+#define RTL8367B_FID_MASK	0xf
+#define RTL8367B_UNTAG_MASK	0xff
+#define RTL8367B_MEMBER_MASK	0xff
+
+#define RTL8367B_PORT_MISC_CFG_REG(_p)		(0x000e + 0x20 * (_p))
+#define   RTL8367B_PORT_MISC_CFG_EGRESS_MODE_SHIFT	4
+#define   RTL8367B_PORT_MISC_CFG_EGRESS_MODE_MASK	0x3
+#define   RTL8367B_PORT_MISC_CFG_EGRESS_MODE_ORIGINAL	0
+#define   RTL8367B_PORT_MISC_CFG_EGRESS_MODE_KEEP	1
+#define   RTL8367B_PORT_MISC_CFG_EGRESS_MODE_PRI	2
+#define   RTL8367B_PORT_MISC_CFG_EGRESS_MODE_REAL	3
+
+#define RTL8367B_BYPASS_LINE_RATE_REG		0x03f7
+
+#define RTL8367B_TA_CTRL_REG			0x0500 /*GOOD*/
+#define   RTL8367B_TA_CTRL_SPA_SHIFT		8
+#define   RTL8367B_TA_CTRL_SPA_MASK		0x7
+#define   RTL8367B_TA_CTRL_METHOD		BIT(4)/*GOOD*/
+#define   RTL8367B_TA_CTRL_CMD_SHIFT		3
+#define   RTL8367B_TA_CTRL_CMD_READ		0
+#define   RTL8367B_TA_CTRL_CMD_WRITE		1
+#define   RTL8367B_TA_CTRL_TABLE_SHIFT		0 /*GOOD*/
+#define   RTL8367B_TA_CTRL_TABLE_ACLRULE	1
+#define   RTL8367B_TA_CTRL_TABLE_ACLACT		2
+#define   RTL8367B_TA_CTRL_TABLE_CVLAN		3
+#define   RTL8367B_TA_CTRL_TABLE_L2		4
+#define   RTL8367B_TA_CTRL_CVLAN_READ \
+		((RTL8367B_TA_CTRL_CMD_READ << RTL8367B_TA_CTRL_CMD_SHIFT) | \
+		 RTL8367B_TA_CTRL_TABLE_CVLAN)
+#define   RTL8367B_TA_CTRL_CVLAN_WRITE \
+		((RTL8367B_TA_CTRL_CMD_WRITE << RTL8367B_TA_CTRL_CMD_SHIFT) | \
+		 RTL8367B_TA_CTRL_TABLE_CVLAN)
+
+#define RTL8367B_TA_ADDR_REG			0x0501/*GOOD*/
+#define   RTL8367B_TA_ADDR_MASK			0x3fff/*GOOD*/
+
+#define RTL8367B_TA_LUT_REG			0x0502/*GOOD*/
+
+#define RTL8367B_TA_WRDATA_REG(_x)		(0x0510 + (_x))/*GOOD*/
+#define   RTL8367B_TA_VLAN_NUM_WORDS		2
+#define   RTL8367B_TA_VLAN_VID_MASK		RTL8367B_VID_MASK
+#define   RTL8367B_TA_VLAN0_MEMBER_SHIFT	0
+#define   RTL8367B_TA_VLAN0_MEMBER_MASK		RTL8367B_MEMBER_MASK
+#define   RTL8367B_TA_VLAN0_UNTAG_SHIFT		8
+#define   RTL8367B_TA_VLAN0_UNTAG_MASK		RTL8367B_MEMBER_MASK
+#define   RTL8367B_TA_VLAN1_FID_SHIFT		0
+#define   RTL8367B_TA_VLAN1_FID_MASK		RTL8367B_FID_MASK
+
+#define RTL8367B_TA_RDDATA_REG(_x)		(0x0520 + (_x))/*GOOD*/
+
+#define RTL8367B_VLAN_PVID_CTRL_REG(_p)		(0x0700 + (_p) / 2) /*GOOD*/
+#define RTL8367B_VLAN_PVID_CTRL_MASK		0x1f /*GOOD*/
+#define RTL8367B_VLAN_PVID_CTRL_SHIFT(_p)	(8 * ((_p) % 2)) /*GOOD*/
+
+#define RTL8367B_VLAN_MC_BASE(_x)		(0x0728 + (_x) * 4) /*GOOD*/
+#define   RTL8367B_VLAN_MC_NUM_WORDS		4 /*GOOD*/
+#define   RTL8367B_VLAN_MC0_MEMBER_SHIFT	0/*GOOD*/
+#define   RTL8367B_VLAN_MC0_MEMBER_MASK		RTL8367B_MEMBER_MASK/*GOOD*/
+#define   RTL8367B_VLAN_MC1_FID_SHIFT		0/*GOOD*/
+#define   RTL8367B_VLAN_MC1_FID_MASK		RTL8367B_FID_MASK/*GOOD*/
+#define   RTL8367B_VLAN_MC3_EVID_SHIFT		0/*GOOD*/
+#define   RTL8367B_VLAN_MC3_EVID_MASK		RTL8367B_VID_MASK/*GOOD*/
+
+#define RTL8367B_VLAN_CTRL_REG			0x07a8 /*GOOD*/
+#define   RTL8367B_VLAN_CTRL_ENABLE		BIT(0)
+
+#define RTL8367B_VLAN_INGRESS_REG		0x07a9 /*GOOD*/
+
+#define RTL8367B_PORT_ISOLATION_REG(_p)		(0x08a2 + (_p)) /*GOOD*/
+
+#define RTL8367B_MIB_COUNTER_REG(_x)		(0x1000 + (_x))	/*GOOD*/
+#define RTL8367B_MIB_COUNTER_PORT_OFFSET	0x007c /*GOOD*/
+
+#define RTL8367B_MIB_ADDRESS_REG		0x1004 /*GOOD*/
+
+#define RTL8367B_MIB_CTRL0_REG(_x)		(0x1005 + (_x)) /*GOOD*/
+#define   RTL8367B_MIB_CTRL0_GLOBAL_RESET_MASK	BIT(11)	/*GOOD*/
+#define   RTL8367B_MIB_CTRL0_QM_RESET_MASK	BIT(10) /*GOOD*/
+#define   RTL8367B_MIB_CTRL0_PORT_RESET_MASK(_p) BIT(2 + (_p)) /*GOOD*/
+#define   RTL8367B_MIB_CTRL0_RESET_MASK		BIT(1) /*GOOD*/
+#define   RTL8367B_MIB_CTRL0_BUSY_MASK		BIT(0) /*GOOD*/
+
+#define RTL8367B_SWC0_REG			0x1200/*GOOD*/
+#define   RTL8367B_SWC0_MAX_LENGTH_SHIFT	13/*GOOD*/
+#define   RTL8367B_SWC0_MAX_LENGTH(_x)		((_x) << 13) /*GOOD*/
+#define   RTL8367B_SWC0_MAX_LENGTH_MASK		RTL8367B_SWC0_MAX_LENGTH(0x3)
+#define   RTL8367B_SWC0_MAX_LENGTH_1522		RTL8367B_SWC0_MAX_LENGTH(0)
+#define   RTL8367B_SWC0_MAX_LENGTH_1536		RTL8367B_SWC0_MAX_LENGTH(1)
+#define   RTL8367B_SWC0_MAX_LENGTH_1552		RTL8367B_SWC0_MAX_LENGTH(2)
+#define   RTL8367B_SWC0_MAX_LENGTH_16000	RTL8367B_SWC0_MAX_LENGTH(3)
+
+#define RTL8367B_CHIP_NUMBER_REG		0x1300/*GOOD*/
+
+#define RTL8367B_CHIP_VER_REG			0x1301/*GOOD*/
+#define   RTL8367B_CHIP_VER_RLVID_SHIFT		12/*GOOD*/
+#define   RTL8367B_CHIP_VER_RLVID_MASK		0xf/*GOOD*/
+#define   RTL8367B_CHIP_VER_MCID_SHIFT		8/*GOOD*/
+#define   RTL8367B_CHIP_VER_MCID_MASK		0xf/*GOOD*/
+#define   RTL8367B_CHIP_VER_BOID_SHIFT		4/*GOOD*/
+#define   RTL8367B_CHIP_VER_BOID_MASK		0xf/*GOOD*/
+#define   RTL8367B_CHIP_VER_AFE_SHIFT		0/*GOOD*/
+#define   RTL8367B_CHIP_VER_AFE_MASK		0x1/*GOOD*/
+
+#define RTL8367B_CHIP_MODE_REG			0x1302
+#define   RTL8367B_CHIP_MODE_MASK		0x7
+
+#define RTL8367B_CHIP_DEBUG0_REG		0x1303
+#define   RTL8367B_DEBUG0_SEL33(_x)		BIT(8 + (_x))
+#define   RTL8367B_DEBUG0_DRI_OTHER		BIT(7)
+#define   RTL8367B_DEBUG0_DRI_RG(_x)		BIT(5 + (_x))
+#define   RTL8367B_DEBUG0_DRI(_x)		BIT(3 + (_x))
+#define   RTL8367B_DEBUG0_SLR_OTHER		BIT(2)
+#define   RTL8367B_DEBUG0_SLR(_x)		BIT(_x)
+
+#define RTL8367B_CHIP_DEBUG1_REG		0x1304
+#define   RTL8367B_DEBUG1_DN_MASK(_x)		\
+	    GENMASK(6 + (_x)*8, 4 + (_x)*8)
+#define   RTL8367B_DEBUG1_DN_SHIFT(_x)		(4 + (_x) * 8)
+#define   RTL8367B_DEBUG1_DP_MASK(_x)		\
+	    GENMASK(2 + (_x) * 8, (_x) * 8)
+#define   RTL8367B_DEBUG1_DP_SHIFT(_x)		((_x) * 8)
+
+#define RTL8367B_CHIP_DEBUG2_REG		0x13e2
+#define   RTL8367B_DEBUG2_RG2_DN_MASK		GENMASK(8, 6)
+#define   RTL8367B_DEBUG2_RG2_DN_SHIFT		6
+#define   RTL8367B_DEBUG2_RG2_DP_MASK		GENMASK(5, 3)
+#define   RTL8367B_DEBUG2_RG2_DP_SHIFT		3
+#define   RTL8367B_DEBUG2_DRI_EXT2_RG		BIT(2)
+#define   RTL8367B_DEBUG2_DRI_EXT2		BIT(1)
+#define   RTL8367B_DEBUG2_SLR_EXT2		BIT(0)
+
+#define RTL8367B_DIS_REG			0x1305
+#define   RTL8367B_DIS_SKIP_MII_RXER(_x)	BIT(12 + (_x))
+#define   RTL8367B_DIS_RGMII_SHIFT(_x)		(4 * (_x))
+#define   RTL8367B_DIS_RGMII_MASK		0x7
+
+#define RTL8367B_DIS2_REG			0x13c3
+#define   RTL8367B_DIS2_SKIP_MII_RXER_SHIFT	4
+#define   RTL8367B_DIS2_SKIP_MII_RXER		0x10
+#define   RTL8367B_DIS2_RGMII_SHIFT		0
+#define   RTL8367B_DIS2_RGMII_MASK		0xf
+
+#define RTL8367B_EXT_RGMXF_REG(_x)		\
+	  ((_x) == 2 ? 0x13c5 : 0x1306 + (_x))
+#define   RTL8367B_EXT_RGMXF_DUMMY0_SHIFT	5
+#define   RTL8367B_EXT_RGMXF_DUMMY0_MASK	0x7ff
+#define   RTL8367B_EXT_RGMXF_TXDELAY_SHIFT	3
+#define   RTL8367B_EXT_RGMXF_TXDELAY_MASK	1
+#define   RTL8367B_EXT_RGMXF_RXDELAY_MASK	0x7
+
+#define RTL8367B_DI_FORCE_REG(_x)		\
+	  ((_x) == 2 ? 0x13c4 : 0x1310 + (_x))
+#define   RTL8367B_DI_FORCE_MODE		BIT(12)
+#define   RTL8367B_DI_FORCE_NWAY		BIT(7)
+#define   RTL8367B_DI_FORCE_TXPAUSE		BIT(6)
+#define   RTL8367B_DI_FORCE_RXPAUSE		BIT(5)
+#define   RTL8367B_DI_FORCE_LINK		BIT(4)
+#define   RTL8367B_DI_FORCE_DUPLEX		BIT(2)
+#define   RTL8367B_DI_FORCE_SPEED_MASK		3
+#define   RTL8367B_DI_FORCE_SPEED_10		0
+#define   RTL8367B_DI_FORCE_SPEED_100		1
+#define   RTL8367B_DI_FORCE_SPEED_1000		2
+
+#define RTL8367B_MAC_FORCE_REG(_x)		(0x1312 + (_x))
+
+#define RTL8367B_CHIP_RESET_REG			0x1322 /*GOOD*/
+#define   RTL8367B_CHIP_RESET_SW		BIT(1) /*GOOD*/
+#define   RTL8367B_CHIP_RESET_HW		BIT(0) /*GOOD*/
+
+#define RTL8367B_PORT_STATUS_REG(_p)		(0x1352 + (_p)) /*GOOD*/
+#define   RTL8367B_PORT_STATUS_EN_1000_SPI	BIT(11) /*GOOD*/
+#define   RTL8367B_PORT_STATUS_EN_100_SPI	BIT(10)/*GOOD*/
+#define   RTL8367B_PORT_STATUS_NWAY_FAULT	BIT(9)/*GOOD*/
+#define   RTL8367B_PORT_STATUS_LINK_MASTER	BIT(8)/*GOOD*/
+#define   RTL8367B_PORT_STATUS_NWAY		BIT(7)/*GOOD*/
+#define   RTL8367B_PORT_STATUS_TXPAUSE		BIT(6)/*GOOD*/
+#define   RTL8367B_PORT_STATUS_RXPAUSE		BIT(5)/*GOOD*/
+#define   RTL8367B_PORT_STATUS_LINK		BIT(4)/*GOOD*/
+#define   RTL8367B_PORT_STATUS_DUPLEX		BIT(2)/*GOOD*/
+#define   RTL8367B_PORT_STATUS_SPEED_MASK	0x0003/*GOOD*/
+#define   RTL8367B_PORT_STATUS_SPEED_10		0/*GOOD*/
+#define   RTL8367B_PORT_STATUS_SPEED_100	1/*GOOD*/
+#define   RTL8367B_PORT_STATUS_SPEED_1000	2/*GOOD*/
+
+#define RTL8367B_RTL_MAGIC_ID_REG		0x13c2
+#define   RTL8367B_RTL_MAGIC_ID_VAL		0x0249
+
+#define RTL8367B_IA_CTRL_REG			0x1f00
+#define   RTL8367B_IA_CTRL_RW(_x)		((_x) << 1)
+#define   RTL8367B_IA_CTRL_RW_READ		RTL8367B_IA_CTRL_RW(0)
+#define   RTL8367B_IA_CTRL_RW_WRITE		RTL8367B_IA_CTRL_RW(1)
+#define   RTL8367B_IA_CTRL_CMD_MASK		BIT(0)
+
+#define RTL8367B_IA_STATUS_REG			0x1f01
+#define   RTL8367B_IA_STATUS_PHY_BUSY		BIT(2)
+#define   RTL8367B_IA_STATUS_SDS_BUSY		BIT(1)
+#define   RTL8367B_IA_STATUS_MDX_BUSY		BIT(0)
+
+#define RTL8367B_IA_ADDRESS_REG			0x1f02
+#define RTL8367B_IA_WRITE_DATA_REG		0x1f03
+#define RTL8367B_IA_READ_DATA_REG		0x1f04
+
+#define RTL8367B_INTERNAL_PHY_REG(_a, _r)	(0x2000 + 32 * (_a) + (_r))
+
+#define RTL8367B_NUM_MIB_COUNTERS	58
+
+#define RTL8367B_CPU_PORT_NUM		5
+#define RTL8367B_NUM_PORTS		8
+#define RTL8367B_NUM_VLANS		32
+#define RTL8367B_NUM_VIDS		4096
+#define RTL8367B_PRIORITYMAX		7
+#define RTL8367B_FIDMAX			7
+
+#define RTL8367B_PORT_0			BIT(0)
+#define RTL8367B_PORT_1			BIT(1)
+#define RTL8367B_PORT_2			BIT(2)
+#define RTL8367B_PORT_3			BIT(3)
+#define RTL8367B_PORT_4			BIT(4)
+#define RTL8367B_PORT_E0		BIT(5)	/* External port 0 */
+#define RTL8367B_PORT_E1		BIT(6)	/* External port 1 */
+#define RTL8367B_PORT_E2		BIT(7)	/* External port 2 */
+
+#define RTL8367B_PORTS_ALL					\
+	(RTL8367B_PORT_0 | RTL8367B_PORT_1 | RTL8367B_PORT_2 |	\
+	 RTL8367B_PORT_3 | RTL8367B_PORT_4 | RTL8367B_PORT_E0 | \
+	 RTL8367B_PORT_E1 | RTL8367B_PORT_E2)
+
+#define RTL8367B_PORTS_ALL_BUT_CPU				\
+	(RTL8367B_PORT_0 | RTL8367B_PORT_1 | RTL8367B_PORT_2 |	\
+	 RTL8367B_PORT_3 | RTL8367B_PORT_4 | RTL8367B_PORT_E1 |	\
+	 RTL8367B_PORT_E2)
+
+struct rtl8367b_initval {
+	u16 reg;
+	u16 val;
+};
+
+#define RTL8367B_MIB_RXB_ID		0	/* IfInOctets */
+#define RTL8367B_MIB_TXB_ID		28	/* IfOutOctets */
+
+static struct rtl8366_mib_counter
+rtl8367b_mib_counters[RTL8367B_NUM_MIB_COUNTERS] = {
+	{0,   0, 4, "ifInOctets"			},
+	{0,   4, 2, "dot3StatsFCSErrors"		},
+	{0,   6, 2, "dot3StatsSymbolErrors"		},
+	{0,   8, 2, "dot3InPauseFrames"			},
+	{0,  10, 2, "dot3ControlInUnknownOpcodes"	},
+	{0,  12, 2, "etherStatsFragments"		},
+	{0,  14, 2, "etherStatsJabbers"			},
+	{0,  16, 2, "ifInUcastPkts"			},
+	{0,  18, 2, "etherStatsDropEvents"		},
+	{0,  20, 2, "ifInMulticastPkts"			},
+	{0,  22, 2, "ifInBroadcastPkts"			},
+	{0,  24, 2, "inMldChecksumError"		},
+	{0,  26, 2, "inIgmpChecksumError"		},
+	{0,  28, 2, "inMldSpecificQuery"		},
+	{0,  30, 2, "inMldGeneralQuery"			},
+	{0,  32, 2, "inIgmpSpecificQuery"		},
+	{0,  34, 2, "inIgmpGeneralQuery"		},
+	{0,  36, 2, "inMldLeaves"			},
+	{0,  38, 2, "inIgmpLeaves"			},
+
+	{0,  40, 4, "etherStatsOctets"			},
+	{0,  44, 2, "etherStatsUnderSizePkts"		},
+	{0,  46, 2, "etherOversizeStats"		},
+	{0,  48, 2, "etherStatsPkts64Octets"		},
+	{0,  50, 2, "etherStatsPkts65to127Octets"	},
+	{0,  52, 2, "etherStatsPkts128to255Octets"	},
+	{0,  54, 2, "etherStatsPkts256to511Octets"	},
+	{0,  56, 2, "etherStatsPkts512to1023Octets"	},
+	{0,  58, 2, "etherStatsPkts1024to1518Octets"	},
+
+	{0,  60, 4, "ifOutOctets"			},
+	{0,  64, 2, "dot3StatsSingleCollisionFrames"	},
+	{0,  66, 2, "dot3StatMultipleCollisionFrames"	},
+	{0,  68, 2, "dot3sDeferredTransmissions"	},
+	{0,  70, 2, "dot3StatsLateCollisions"		},
+	{0,  72, 2, "etherStatsCollisions"		},
+	{0,  74, 2, "dot3StatsExcessiveCollisions"	},
+	{0,  76, 2, "dot3OutPauseFrames"		},
+	{0,  78, 2, "ifOutDiscards"			},
+	{0,  80, 2, "dot1dTpPortInDiscards"		},
+	{0,  82, 2, "ifOutUcastPkts"			},
+	{0,  84, 2, "ifOutMulticastPkts"		},
+	{0,  86, 2, "ifOutBroadcastPkts"		},
+	{0,  88, 2, "outOampduPkts"			},
+	{0,  90, 2, "inOampduPkts"			},
+	{0,  92, 2, "inIgmpJoinsSuccess"		},
+	{0,  94, 2, "inIgmpJoinsFail"			},
+	{0,  96, 2, "inMldJoinsSuccess"			},
+	{0,  98, 2, "inMldJoinsFail"			},
+	{0, 100, 2, "inReportSuppressionDrop"		},
+	{0, 102, 2, "inLeaveSuppressionDrop"		},
+	{0, 104, 2, "outIgmpReports"			},
+	{0, 106, 2, "outIgmpLeaves"			},
+	{0, 108, 2, "outIgmpGeneralQuery"		},
+	{0, 110, 2, "outIgmpSpecificQuery"		},
+	{0, 112, 2, "outMldReports"			},
+	{0, 114, 2, "outMldLeaves"			},
+	{0, 116, 2, "outMldGeneralQuery"		},
+	{0, 118, 2, "outMldSpecificQuery"		},
+	{0, 120, 2, "inKnownMulticastPkts"		},
+};
+
+#define REG_RD(_smi, _reg, _val)					\
+	do {								\
+		err = rtl8366_smi_read_reg(_smi, _reg, _val);		\
+		if (err)						\
+			return err;					\
+	} while (0)
+
+#define REG_WR(_smi, _reg, _val)					\
+	do {								\
+		err = rtl8366_smi_write_reg(_smi, _reg, _val);		\
+		if (err)						\
+			return err;					\
+	} while (0)
+
+#define REG_RMW(_smi, _reg, _mask, _val)				\
+	do {								\
+		err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val);	\
+		if (err)						\
+			return err;					\
+	} while (0)
+
+static const struct rtl8367b_initval rtl8367r_vb_initvals_0[] = {
+	{0x1B03, 0x0876}, {0x1200, 0x7FC4}, {0x0301, 0x0026}, {0x1722, 0x0E14},
+	{0x205F, 0x0002}, {0x2059, 0x1A00}, {0x205F, 0x0000}, {0x207F, 0x0002},
+	{0x2077, 0x0000}, {0x2078, 0x0000}, {0x2079, 0x0000}, {0x207A, 0x0000},
+	{0x207B, 0x0000}, {0x207F, 0x0000}, {0x205F, 0x0002}, {0x2053, 0x0000},
+	{0x2054, 0x0000}, {0x2055, 0x0000}, {0x2056, 0x0000}, {0x2057, 0x0000},
+	{0x205F, 0x0000}, {0x12A4, 0x110A}, {0x12A6, 0x150A}, {0x13F1, 0x0013},
+	{0x13F4, 0x0010}, {0x13F5, 0x0000}, {0x0018, 0x0F00}, {0x0038, 0x0F00},
+	{0x0058, 0x0F00}, {0x0078, 0x0F00}, {0x0098, 0x0F00}, {0x12B6, 0x0C02},
+	{0x12B7, 0x030F}, {0x12B8, 0x11FF}, {0x12BC, 0x0004}, {0x1362, 0x0115},
+	{0x1363, 0x0002}, {0x1363, 0x0000}, {0x133F, 0x0030}, {0x133E, 0x000E},
+	{0x221F, 0x0007}, {0x221E, 0x002D}, {0x2218, 0xF030}, {0x221F, 0x0007},
+	{0x221E, 0x0023}, {0x2216, 0x0005}, {0x2215, 0x00B9}, {0x2219, 0x0044},
+	{0x2215, 0x00BA}, {0x2219, 0x0020}, {0x2215, 0x00BB}, {0x2219, 0x00C1},
+	{0x2215, 0x0148}, {0x2219, 0x0096}, {0x2215, 0x016E}, {0x2219, 0x0026},
+	{0x2216, 0x0000}, {0x2216, 0x0000}, {0x221E, 0x002D}, {0x2218, 0xF010},
+	{0x221F, 0x0007}, {0x221E, 0x0020}, {0x2215, 0x0D00}, {0x221F, 0x0000},
+	{0x221F, 0x0000}, {0x2217, 0x2160}, {0x221F, 0x0001}, {0x2210, 0xF25E},
+	{0x221F, 0x0007}, {0x221E, 0x0042}, {0x2215, 0x0F00}, {0x2215, 0x0F00},
+	{0x2216, 0x7408}, {0x2215, 0x0E00}, {0x2215, 0x0F00}, {0x2215, 0x0F01},
+	{0x2216, 0x4000}, {0x2215, 0x0E01}, {0x2215, 0x0F01}, {0x2215, 0x0F02},
+	{0x2216, 0x9400}, {0x2215, 0x0E02}, {0x2215, 0x0F02}, {0x2215, 0x0F03},
+	{0x2216, 0x7408}, {0x2215, 0x0E03}, {0x2215, 0x0F03}, {0x2215, 0x0F04},
+	{0x2216, 0x4008}, {0x2215, 0x0E04}, {0x2215, 0x0F04}, {0x2215, 0x0F05},
+	{0x2216, 0x9400}, {0x2215, 0x0E05}, {0x2215, 0x0F05}, {0x2215, 0x0F06},
+	{0x2216, 0x0803}, {0x2215, 0x0E06}, {0x2215, 0x0F06}, {0x2215, 0x0D00},
+	{0x2215, 0x0100}, {0x221F, 0x0001}, {0x2210, 0xF05E}, {0x221F, 0x0000},
+	{0x2217, 0x2100}, {0x221F, 0x0000}, {0x220D, 0x0003}, {0x220E, 0x0015},
+	{0x220D, 0x4003}, {0x220E, 0x0006}, {0x221F, 0x0000}, {0x2200, 0x1340},
+	{0x133F, 0x0010}, {0x12A0, 0x0058}, {0x12A1, 0x0058}, {0x133E, 0x000E},
+	{0x133F, 0x0030}, {0x221F, 0x0000}, {0x2210, 0x0166}, {0x221F, 0x0000},
+	{0x133E, 0x000E}, {0x133F, 0x0010}, {0x133F, 0x0030}, {0x133E, 0x000E},
+	{0x221F, 0x0005}, {0x2205, 0xFFF6}, {0x2206, 0x0080}, {0x2205, 0x8B6E},
+	{0x2206, 0x0000}, {0x220F, 0x0100}, {0x2205, 0x8000}, {0x2206, 0x0280},
+	{0x2206, 0x28F7}, {0x2206, 0x00E0}, {0x2206, 0xFFF7}, {0x2206, 0xA080},
+	{0x2206, 0x02AE}, {0x2206, 0xF602}, {0x2206, 0x0153}, {0x2206, 0x0201},
+	{0x2206, 0x6602}, {0x2206, 0x80B9}, {0x2206, 0xE08B}, {0x2206, 0x8CE1},
+	{0x2206, 0x8B8D}, {0x2206, 0x1E01}, {0x2206, 0xE18B}, {0x2206, 0x8E1E},
+	{0x2206, 0x01A0}, {0x2206, 0x00E7}, {0x2206, 0xAEDB}, {0x2206, 0xEEE0},
+	{0x2206, 0x120E}, {0x2206, 0xEEE0}, {0x2206, 0x1300}, {0x2206, 0xEEE0},
+	{0x2206, 0x2001}, {0x2206, 0xEEE0}, {0x2206, 0x2166}, {0x2206, 0xEEE0},
+	{0x2206, 0xC463}, {0x2206, 0xEEE0}, {0x2206, 0xC5E8}, {0x2206, 0xEEE0},
+	{0x2206, 0xC699}, {0x2206, 0xEEE0}, {0x2206, 0xC7C2}, {0x2206, 0xEEE0},
+	{0x2206, 0xC801}, {0x2206, 0xEEE0}, {0x2206, 0xC913}, {0x2206, 0xEEE0},
+	{0x2206, 0xCA30}, {0x2206, 0xEEE0}, {0x2206, 0xCB3E}, {0x2206, 0xEEE0},
+	{0x2206, 0xDCE1}, {0x2206, 0xEEE0}, {0x2206, 0xDD00}, {0x2206, 0xEEE2},
+	{0x2206, 0x0001}, {0x2206, 0xEEE2}, {0x2206, 0x0100}, {0x2206, 0xEEE4},
+	{0x2206, 0x8860}, {0x2206, 0xEEE4}, {0x2206, 0x8902}, {0x2206, 0xEEE4},
+	{0x2206, 0x8C00}, {0x2206, 0xEEE4}, {0x2206, 0x8D30}, {0x2206, 0xEEEA},
+	{0x2206, 0x1480}, {0x2206, 0xEEEA}, {0x2206, 0x1503}, {0x2206, 0xEEEA},
+	{0x2206, 0xC600}, {0x2206, 0xEEEA}, {0x2206, 0xC706}, {0x2206, 0xEE85},
+	{0x2206, 0xEE00}, {0x2206, 0xEE85}, {0x2206, 0xEF00}, {0x2206, 0xEE8B},
+	{0x2206, 0x6750}, {0x2206, 0xEE8B}, {0x2206, 0x6632}, {0x2206, 0xEE8A},
+	{0x2206, 0xD448}, {0x2206, 0xEE8A}, {0x2206, 0xD548}, {0x2206, 0xEE8A},
+	{0x2206, 0xD649}, {0x2206, 0xEE8A}, {0x2206, 0xD7F8}, {0x2206, 0xEE8B},
+	{0x2206, 0x85E2}, {0x2206, 0xEE8B}, {0x2206, 0x8700}, {0x2206, 0xEEFF},
+	{0x2206, 0xF600}, {0x2206, 0xEEFF}, {0x2206, 0xF7FC}, {0x2206, 0x04F8},
+	{0x2206, 0xE08B}, {0x2206, 0x8EAD}, {0x2206, 0x2023}, {0x2206, 0xF620},
+	{0x2206, 0xE48B}, {0x2206, 0x8E02}, {0x2206, 0x2877}, {0x2206, 0x0225},
+	{0x2206, 0xC702}, {0x2206, 0x26A1}, {0x2206, 0x0281}, {0x2206, 0xB302},
+	{0x2206, 0x8496}, {0x2206, 0x0202}, {0x2206, 0xA102}, {0x2206, 0x27F1},
+	{0x2206, 0x0228}, {0x2206, 0xF902}, {0x2206, 0x2AA0}, {0x2206, 0x0282},
+	{0x2206, 0xB8E0}, {0x2206, 0x8B8E}, {0x2206, 0xAD21}, {0x2206, 0x08F6},
+	{0x2206, 0x21E4}, {0x2206, 0x8B8E}, {0x2206, 0x0202}, {0x2206, 0x80E0},
+	{0x2206, 0x8B8E}, {0x2206, 0xAD22}, {0x2206, 0x05F6}, {0x2206, 0x22E4},
+	{0x2206, 0x8B8E}, {0x2206, 0xE08B}, {0x2206, 0x8EAD}, {0x2206, 0x2305},
+	{0x2206, 0xF623}, {0x2206, 0xE48B}, {0x2206, 0x8EE0}, {0x2206, 0x8B8E},
+	{0x2206, 0xAD24}, {0x2206, 0x08F6}, {0x2206, 0x24E4}, {0x2206, 0x8B8E},
+	{0x2206, 0x0227}, {0x2206, 0x6AE0}, {0x2206, 0x8B8E}, {0x2206, 0xAD25},
+	{0x2206, 0x05F6}, {0x2206, 0x25E4}, {0x2206, 0x8B8E}, {0x2206, 0xE08B},
+	{0x2206, 0x8EAD}, {0x2206, 0x260B}, {0x2206, 0xF626}, {0x2206, 0xE48B},
+	{0x2206, 0x8E02}, {0x2206, 0x830D}, {0x2206, 0x021D}, {0x2206, 0x6BE0},
+	{0x2206, 0x8B8E}, {0x2206, 0xAD27}, {0x2206, 0x05F6}, {0x2206, 0x27E4},
+	{0x2206, 0x8B8E}, {0x2206, 0x0281}, {0x2206, 0x4402}, {0x2206, 0x045C},
+	{0x2206, 0xFC04}, {0x2206, 0xF8E0}, {0x2206, 0x8B83}, {0x2206, 0xAD23},
+	{0x2206, 0x30E0}, {0x2206, 0xE022}, {0x2206, 0xE1E0}, {0x2206, 0x2359},
+	{0x2206, 0x02E0}, {0x2206, 0x85EF}, {0x2206, 0xE585}, {0x2206, 0xEFAC},
+	{0x2206, 0x2907}, {0x2206, 0x1F01}, {0x2206, 0x9E51}, {0x2206, 0xAD29},
+	{0x2206, 0x20E0}, {0x2206, 0x8B83}, {0x2206, 0xAD21}, {0x2206, 0x06E1},
+	{0x2206, 0x8B84}, {0x2206, 0xAD28}, {0x2206, 0x42E0}, {0x2206, 0x8B85},
+	{0x2206, 0xAD21}, {0x2206, 0x06E1}, {0x2206, 0x8B84}, {0x2206, 0xAD29},
+	{0x2206, 0x36BF}, {0x2206, 0x34BF}, {0x2206, 0x022C}, {0x2206, 0x31AE},
+	{0x2206, 0x2EE0}, {0x2206, 0x8B83}, {0x2206, 0xAD21}, {0x2206, 0x10E0},
+	{0x2206, 0x8B84}, {0x2206, 0xF620}, {0x2206, 0xE48B}, {0x2206, 0x84EE},
+	{0x2206, 0x8ADA}, {0x2206, 0x00EE}, {0x2206, 0x8ADB}, {0x2206, 0x00E0},
+	{0x2206, 0x8B85}, {0x2206, 0xAD21}, {0x2206, 0x0CE0}, {0x2206, 0x8B84},
+	{0x2206, 0xF621}, {0x2206, 0xE48B}, {0x2206, 0x84EE}, {0x2206, 0x8B72},
+	{0x2206, 0xFFBF}, {0x2206, 0x34C2}, {0x2206, 0x022C}, {0x2206, 0x31FC},
+	{0x2206, 0x04F8}, {0x2206, 0xFAEF}, {0x2206, 0x69E0}, {0x2206, 0x8B85},
+	{0x2206, 0xAD21}, {0x2206, 0x42E0}, {0x2206, 0xE022}, {0x2206, 0xE1E0},
+	{0x2206, 0x2358}, {0x2206, 0xC059}, {0x2206, 0x021E}, {0x2206, 0x01E1},
+	{0x2206, 0x8B72}, {0x2206, 0x1F10}, {0x2206, 0x9E2F}, {0x2206, 0xE48B},
+	{0x2206, 0x72AD}, {0x2206, 0x2123}, {0x2206, 0xE18B}, {0x2206, 0x84F7},
+	{0x2206, 0x29E5}, {0x2206, 0x8B84}, {0x2206, 0xAC27}, {0x2206, 0x10AC},
+	{0x2206, 0x2605}, {0x2206, 0x0205}, {0x2206, 0x23AE}, {0x2206, 0x1602},
+	{0x2206, 0x0535}, {0x2206, 0x0282}, {0x2206, 0x30AE}, {0x2206, 0x0E02},
+	{0x2206, 0x056A}, {0x2206, 0x0282}, {0x2206, 0x75AE}, {0x2206, 0x0602},
+	{0x2206, 0x04DC}, {0x2206, 0x0282}, {0x2206, 0x04EF}, {0x2206, 0x96FE},
+	{0x2206, 0xFC04}, {0x2206, 0xF8F9}, {0x2206, 0xE08B}, {0x2206, 0x87AD},
+	{0x2206, 0x2321}, {0x2206, 0xE0EA}, {0x2206, 0x14E1}, {0x2206, 0xEA15},
+	{0x2206, 0xAD26}, {0x2206, 0x18F6}, {0x2206, 0x27E4}, {0x2206, 0xEA14},
+	{0x2206, 0xE5EA}, {0x2206, 0x15F6}, {0x2206, 0x26E4}, {0x2206, 0xEA14},
+	{0x2206, 0xE5EA}, {0x2206, 0x15F7}, {0x2206, 0x27E4}, {0x2206, 0xEA14},
+	{0x2206, 0xE5EA}, {0x2206, 0x15FD}, {0x2206, 0xFC04}, {0x2206, 0xF8F9},
+	{0x2206, 0xE08B}, {0x2206, 0x87AD}, {0x2206, 0x233A}, {0x2206, 0xAD22},
+	{0x2206, 0x37E0}, {0x2206, 0xE020}, {0x2206, 0xE1E0}, {0x2206, 0x21AC},
+	{0x2206, 0x212E}, {0x2206, 0xE0EA}, {0x2206, 0x14E1}, {0x2206, 0xEA15},
+	{0x2206, 0xF627}, {0x2206, 0xE4EA}, {0x2206, 0x14E5}, {0x2206, 0xEA15},
+	{0x2206, 0xE2EA}, {0x2206, 0x12E3}, {0x2206, 0xEA13}, {0x2206, 0x5A8F},
+	{0x2206, 0x6A20}, {0x2206, 0xE6EA}, {0x2206, 0x12E7}, {0x2206, 0xEA13},
+	{0x2206, 0xF726}, {0x2206, 0xE4EA}, {0x2206, 0x14E5}, {0x2206, 0xEA15},
+	{0x2206, 0xF727}, {0x2206, 0xE4EA}, {0x2206, 0x14E5}, {0x2206, 0xEA15},
+	{0x2206, 0xFDFC}, {0x2206, 0x04F8}, {0x2206, 0xF9E0}, {0x2206, 0x8B87},
+	{0x2206, 0xAD23}, {0x2206, 0x38AD}, {0x2206, 0x2135}, {0x2206, 0xE0E0},
+	{0x2206, 0x20E1}, {0x2206, 0xE021}, {0x2206, 0xAC21}, {0x2206, 0x2CE0},
+	{0x2206, 0xEA14}, {0x2206, 0xE1EA}, {0x2206, 0x15F6}, {0x2206, 0x27E4},
+	{0x2206, 0xEA14}, {0x2206, 0xE5EA}, {0x2206, 0x15E2}, {0x2206, 0xEA12},
+	{0x2206, 0xE3EA}, {0x2206, 0x135A}, {0x2206, 0x8FE6}, {0x2206, 0xEA12},
+	{0x2206, 0xE7EA}, {0x2206, 0x13F7}, {0x2206, 0x26E4}, {0x2206, 0xEA14},
+	{0x2206, 0xE5EA}, {0x2206, 0x15F7}, {0x2206, 0x27E4}, {0x2206, 0xEA14},
+	{0x2206, 0xE5EA}, {0x2206, 0x15FD}, {0x2206, 0xFC04}, {0x2206, 0xF8FA},
+	{0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AD}, {0x2206, 0x2146},
+	{0x2206, 0xE0E0}, {0x2206, 0x22E1}, {0x2206, 0xE023}, {0x2206, 0x58C0},
+	{0x2206, 0x5902}, {0x2206, 0x1E01}, {0x2206, 0xE18B}, {0x2206, 0x651F},
+	{0x2206, 0x109E}, {0x2206, 0x33E4}, {0x2206, 0x8B65}, {0x2206, 0xAD21},
+	{0x2206, 0x22AD}, {0x2206, 0x272A}, {0x2206, 0xD400}, {0x2206, 0x01BF},
+	{0x2206, 0x34F2}, {0x2206, 0x022C}, {0x2206, 0xA2BF}, {0x2206, 0x34F5},
+	{0x2206, 0x022C}, {0x2206, 0xE0E0}, {0x2206, 0x8B67}, {0x2206, 0x1B10},
+	{0x2206, 0xAA14}, {0x2206, 0xE18B}, {0x2206, 0x660D}, {0x2206, 0x1459},
+	{0x2206, 0x0FAE}, {0x2206, 0x05E1}, {0x2206, 0x8B66}, {0x2206, 0x590F},
+	{0x2206, 0xBF85}, {0x2206, 0x6102}, {0x2206, 0x2CA2}, {0x2206, 0xEF96},
+	{0x2206, 0xFEFC}, {0x2206, 0x04F8}, {0x2206, 0xF9FA}, {0x2206, 0xFBEF},
+	{0x2206, 0x79E2}, {0x2206, 0x8AD2}, {0x2206, 0xAC19}, {0x2206, 0x2DE0},
+	{0x2206, 0xE036}, {0x2206, 0xE1E0}, {0x2206, 0x37EF}, {0x2206, 0x311F},
+	{0x2206, 0x325B}, {0x2206, 0x019E}, {0x2206, 0x1F7A}, {0x2206, 0x0159},
+	{0x2206, 0x019F}, {0x2206, 0x0ABF}, {0x2206, 0x348E}, {0x2206, 0x022C},
+	{0x2206, 0x31F6}, {0x2206, 0x06AE}, {0x2206, 0x0FF6}, {0x2206, 0x0302},
+	{0x2206, 0x0470}, {0x2206, 0xF703}, {0x2206, 0xF706}, {0x2206, 0xBF34},
+	{0x2206, 0x9302}, {0x2206, 0x2C31}, {0x2206, 0xAC1A}, {0x2206, 0x25E0},
+	{0x2206, 0xE022}, {0x2206, 0xE1E0}, {0x2206, 0x23EF}, {0x2206, 0x300D},
+	{0x2206, 0x311F}, {0x2206, 0x325B}, {0x2206, 0x029E}, {0x2206, 0x157A},
+	{0x2206, 0x0258}, {0x2206, 0xC4A0}, {0x2206, 0x0408}, {0x2206, 0xBF34},
+	{0x2206, 0x9E02}, {0x2206, 0x2C31}, {0x2206, 0xAE06}, {0x2206, 0xBF34},
+	{0x2206, 0x9C02}, {0x2206, 0x2C31}, {0x2206, 0xAC1B}, {0x2206, 0x4AE0},
+	{0x2206, 0xE012}, {0x2206, 0xE1E0}, {0x2206, 0x13EF}, {0x2206, 0x300D},
+	{0x2206, 0x331F}, {0x2206, 0x325B}, {0x2206, 0x1C9E}, {0x2206, 0x3AEF},
+	{0x2206, 0x325B}, {0x2206, 0x1C9F}, {0x2206, 0x09BF}, {0x2206, 0x3498},
+	{0x2206, 0x022C}, {0x2206, 0x3102}, {0x2206, 0x83C5}, {0x2206, 0x5A03},
+	{0x2206, 0x0D03}, {0x2206, 0x581C}, {0x2206, 0x1E20}, {0x2206, 0x0207},
+	{0x2206, 0xA0A0}, {0x2206, 0x000E}, {0x2206, 0x0284}, {0x2206, 0x17AD},
+	{0x2206, 0x1817}, {0x2206, 0xBF34}, {0x2206, 0x9A02}, {0x2206, 0x2C31},
+	{0x2206, 0xAE0F}, {0x2206, 0xBF34}, {0x2206, 0xC802}, {0x2206, 0x2C31},
+	{0x2206, 0xBF34}, {0x2206, 0xC502}, {0x2206, 0x2C31}, {0x2206, 0x0284},
+	{0x2206, 0x52E6}, {0x2206, 0x8AD2}, {0x2206, 0xEF97}, {0x2206, 0xFFFE},
+	{0x2206, 0xFDFC}, {0x2206, 0x04F8}, {0x2206, 0xBF34}, {0x2206, 0xDA02},
+	{0x2206, 0x2CE0}, {0x2206, 0xE58A}, {0x2206, 0xD3BF}, {0x2206, 0x34D4},
+	{0x2206, 0x022C}, {0x2206, 0xE00C}, {0x2206, 0x1159}, {0x2206, 0x02E0},
+	{0x2206, 0x8AD3}, {0x2206, 0x1E01}, {0x2206, 0xE48A}, {0x2206, 0xD3D1},
+	{0x2206, 0x00BF}, {0x2206, 0x34DA}, {0x2206, 0x022C}, {0x2206, 0xA2D1},
+	{0x2206, 0x01BF}, {0x2206, 0x34D4}, {0x2206, 0x022C}, {0x2206, 0xA2BF},
+	{0x2206, 0x34CB}, {0x2206, 0x022C}, {0x2206, 0xE0E5}, {0x2206, 0x8ACE},
+	{0x2206, 0xBF85}, {0x2206, 0x6702}, {0x2206, 0x2CE0}, {0x2206, 0xE58A},
+	{0x2206, 0xCFBF}, {0x2206, 0x8564}, {0x2206, 0x022C}, {0x2206, 0xE0E5},
+	{0x2206, 0x8AD0}, {0x2206, 0xBF85}, {0x2206, 0x6A02}, {0x2206, 0x2CE0},
+	{0x2206, 0xE58A}, {0x2206, 0xD1FC}, {0x2206, 0x04F8}, {0x2206, 0xE18A},
+	{0x2206, 0xD1BF}, {0x2206, 0x856A}, {0x2206, 0x022C}, {0x2206, 0xA2E1},
+	{0x2206, 0x8AD0}, {0x2206, 0xBF85}, {0x2206, 0x6402}, {0x2206, 0x2CA2},
+	{0x2206, 0xE18A}, {0x2206, 0xCFBF}, {0x2206, 0x8567}, {0x2206, 0x022C},
+	{0x2206, 0xA2E1}, {0x2206, 0x8ACE}, {0x2206, 0xBF34}, {0x2206, 0xCB02},
+	{0x2206, 0x2CA2}, {0x2206, 0xE18A}, {0x2206, 0xD3BF}, {0x2206, 0x34DA},
+	{0x2206, 0x022C}, {0x2206, 0xA2E1}, {0x2206, 0x8AD3}, {0x2206, 0x0D11},
+	{0x2206, 0xBF34}, {0x2206, 0xD402}, {0x2206, 0x2CA2}, {0x2206, 0xFC04},
+	{0x2206, 0xF9A0}, {0x2206, 0x0405}, {0x2206, 0xE38A}, {0x2206, 0xD4AE},
+	{0x2206, 0x13A0}, {0x2206, 0x0805}, {0x2206, 0xE38A}, {0x2206, 0xD5AE},
+	{0x2206, 0x0BA0}, {0x2206, 0x0C05}, {0x2206, 0xE38A}, {0x2206, 0xD6AE},
+	{0x2206, 0x03E3}, {0x2206, 0x8AD7}, {0x2206, 0xEF13}, {0x2206, 0xBF34},
+	{0x2206, 0xCB02}, {0x2206, 0x2CA2}, {0x2206, 0xEF13}, {0x2206, 0x0D11},
+	{0x2206, 0xBF85}, {0x2206, 0x6702}, {0x2206, 0x2CA2}, {0x2206, 0xEF13},
+	{0x2206, 0x0D14}, {0x2206, 0xBF85}, {0x2206, 0x6402}, {0x2206, 0x2CA2},
+	{0x2206, 0xEF13}, {0x2206, 0x0D17}, {0x2206, 0xBF85}, {0x2206, 0x6A02},
+	{0x2206, 0x2CA2}, {0x2206, 0xFD04}, {0x2206, 0xF8E0}, {0x2206, 0x8B85},
+	{0x2206, 0xAD27}, {0x2206, 0x2DE0}, {0x2206, 0xE036}, {0x2206, 0xE1E0},
+	{0x2206, 0x37E1}, {0x2206, 0x8B73}, {0x2206, 0x1F10}, {0x2206, 0x9E20},
+	{0x2206, 0xE48B}, {0x2206, 0x73AC}, {0x2206, 0x200B}, {0x2206, 0xAC21},
+	{0x2206, 0x0DAC}, {0x2206, 0x250F}, {0x2206, 0xAC27}, {0x2206, 0x0EAE},
+	{0x2206, 0x0F02}, {0x2206, 0x84CC}, {0x2206, 0xAE0A}, {0x2206, 0x0284},
+	{0x2206, 0xD1AE}, {0x2206, 0x05AE}, {0x2206, 0x0302}, {0x2206, 0x84D8},
+	{0x2206, 0xFC04}, {0x2206, 0xEE8B}, {0x2206, 0x6800}, {0x2206, 0x0402},
+	{0x2206, 0x84E5}, {0x2206, 0x0285}, {0x2206, 0x2804}, {0x2206, 0x0285},
+	{0x2206, 0x4904}, {0x2206, 0xEE8B}, {0x2206, 0x6800}, {0x2206, 0xEE8B},
+	{0x2206, 0x6902}, {0x2206, 0x04F8}, {0x2206, 0xF9E0}, {0x2206, 0x8B85},
+	{0x2206, 0xAD26}, {0x2206, 0x38D0}, {0x2206, 0x0B02}, {0x2206, 0x2B4D},
+	{0x2206, 0x5882}, {0x2206, 0x7882}, {0x2206, 0x9F2D}, {0x2206, 0xE08B},
+	{0x2206, 0x68E1}, {0x2206, 0x8B69}, {0x2206, 0x1F10}, {0x2206, 0x9EC8},
+	{0x2206, 0x10E4}, {0x2206, 0x8B68}, {0x2206, 0xE0E0}, {0x2206, 0x00E1},
+	{0x2206, 0xE001}, {0x2206, 0xF727}, {0x2206, 0xE4E0}, {0x2206, 0x00E5},
+	{0x2206, 0xE001}, {0x2206, 0xE2E0}, {0x2206, 0x20E3}, {0x2206, 0xE021},
+	{0x2206, 0xAD30}, {0x2206, 0xF7F6}, {0x2206, 0x27E4}, {0x2206, 0xE000},
+	{0x2206, 0xE5E0}, {0x2206, 0x01FD}, {0x2206, 0xFC04}, {0x2206, 0xF8FA},
+	{0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AD}, {0x2206, 0x2212},
+	{0x2206, 0xE0E0}, {0x2206, 0x14E1}, {0x2206, 0xE015}, {0x2206, 0xAD26},
+	{0x2206, 0x9CE1}, {0x2206, 0x85E0}, {0x2206, 0xBF85}, {0x2206, 0x6D02},
+	{0x2206, 0x2CA2}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x04F8},
+	{0x2206, 0xFAEF}, {0x2206, 0x69E0}, {0x2206, 0x8B86}, {0x2206, 0xAD22},
+	{0x2206, 0x09E1}, {0x2206, 0x85E1}, {0x2206, 0xBF85}, {0x2206, 0x6D02},
+	{0x2206, 0x2CA2}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x0464},
+	{0x2206, 0xE48C}, {0x2206, 0xFDE4}, {0x2206, 0x80CA}, {0x2206, 0xE480},
+	{0x2206, 0x66E0}, {0x2206, 0x8E70}, {0x2206, 0xE076}, {0x2205, 0xE142},
+	{0x2206, 0x0701}, {0x2205, 0xE140}, {0x2206, 0x0405}, {0x220F, 0x0000},
+	{0x221F, 0x0000}, {0x2200, 0x1340}, {0x133E, 0x000E}, {0x133F, 0x0010},
+	{0x13EB, 0x11BB}
+};
+
+static const struct rtl8367b_initval rtl8367r_vb_initvals_1[] = {
+	{0x1B03, 0x0876}, {0x1200, 0x7FC4}, {0x1305, 0xC000}, {0x121E, 0x03CA},
+	{0x1233, 0x0352}, {0x1234, 0x0064}, {0x1237, 0x0096}, {0x1238, 0x0078},
+	{0x1239, 0x0084}, {0x123A, 0x0030}, {0x205F, 0x0002}, {0x2059, 0x1A00},
+	{0x205F, 0x0000}, {0x207F, 0x0002}, {0x2077, 0x0000}, {0x2078, 0x0000},
+	{0x2079, 0x0000}, {0x207A, 0x0000}, {0x207B, 0x0000}, {0x207F, 0x0000},
+	{0x205F, 0x0002}, {0x2053, 0x0000}, {0x2054, 0x0000}, {0x2055, 0x0000},
+	{0x2056, 0x0000}, {0x2057, 0x0000}, {0x205F, 0x0000}, {0x133F, 0x0030},
+	{0x133E, 0x000E}, {0x221F, 0x0005}, {0x2205, 0x8B86}, {0x2206, 0x800E},
+	{0x221F, 0x0000}, {0x133F, 0x0010}, {0x12A3, 0x2200}, {0x6107, 0xE58B},
+	{0x6103, 0xA970}, {0x0018, 0x0F00}, {0x0038, 0x0F00}, {0x0058, 0x0F00},
+	{0x0078, 0x0F00}, {0x0098, 0x0F00}, {0x133F, 0x0030}, {0x133E, 0x000E},
+	{0x221F, 0x0005}, {0x2205, 0x8B6E}, {0x2206, 0x0000}, {0x220F, 0x0100},
+	{0x2205, 0xFFF6}, {0x2206, 0x0080}, {0x2205, 0x8000}, {0x2206, 0x0280},
+	{0x2206, 0x2BF7}, {0x2206, 0x00E0}, {0x2206, 0xFFF7}, {0x2206, 0xA080},
+	{0x2206, 0x02AE}, {0x2206, 0xF602}, {0x2206, 0x0153}, {0x2206, 0x0201},
+	{0x2206, 0x6602}, {0x2206, 0x8044}, {0x2206, 0x0201}, {0x2206, 0x7CE0},
+	{0x2206, 0x8B8C}, {0x2206, 0xE18B}, {0x2206, 0x8D1E}, {0x2206, 0x01E1},
+	{0x2206, 0x8B8E}, {0x2206, 0x1E01}, {0x2206, 0xA000}, {0x2206, 0xE4AE},
+	{0x2206, 0xD8EE}, {0x2206, 0x85C0}, {0x2206, 0x00EE}, {0x2206, 0x85C1},
+	{0x2206, 0x00EE}, {0x2206, 0x8AFC}, {0x2206, 0x07EE}, {0x2206, 0x8AFD},
+	{0x2206, 0x73EE}, {0x2206, 0xFFF6}, {0x2206, 0x00EE}, {0x2206, 0xFFF7},
+	{0x2206, 0xFC04}, {0x2206, 0xF8E0}, {0x2206, 0x8B8E}, {0x2206, 0xAD20},
+	{0x2206, 0x0302}, {0x2206, 0x8050}, {0x2206, 0xFC04}, {0x2206, 0xF8F9},
+	{0x2206, 0xE08B}, {0x2206, 0x85AD}, {0x2206, 0x2548}, {0x2206, 0xE08A},
+	{0x2206, 0xE4E1}, {0x2206, 0x8AE5}, {0x2206, 0x7C00}, {0x2206, 0x009E},
+	{0x2206, 0x35EE}, {0x2206, 0x8AE4}, {0x2206, 0x00EE}, {0x2206, 0x8AE5},
+	{0x2206, 0x00E0}, {0x2206, 0x8AFC}, {0x2206, 0xE18A}, {0x2206, 0xFDE2},
+	{0x2206, 0x85C0}, {0x2206, 0xE385}, {0x2206, 0xC102}, {0x2206, 0x2DAC},
+	{0x2206, 0xAD20}, {0x2206, 0x12EE}, {0x2206, 0x8AE4}, {0x2206, 0x03EE},
+	{0x2206, 0x8AE5}, {0x2206, 0xB7EE}, {0x2206, 0x85C0}, {0x2206, 0x00EE},
+	{0x2206, 0x85C1}, {0x2206, 0x00AE}, {0x2206, 0x1115}, {0x2206, 0xE685},
+	{0x2206, 0xC0E7}, {0x2206, 0x85C1}, {0x2206, 0xAE08}, {0x2206, 0xEE85},
+	{0x2206, 0xC000}, {0x2206, 0xEE85}, {0x2206, 0xC100}, {0x2206, 0xFDFC},
+	{0x2206, 0x0400}, {0x2205, 0xE142}, {0x2206, 0x0701}, {0x2205, 0xE140},
+	{0x2206, 0x0405}, {0x220F, 0x0000}, {0x221F, 0x0000}, {0x133E, 0x000E},
+	{0x133F, 0x0010}, {0x13EB, 0x11BB}, {0x207F, 0x0002}, {0x2073, 0x1D22},
+	{0x207F, 0x0000}, {0x133F, 0x0030}, {0x133E, 0x000E}, {0x2200, 0x1340},
+	{0x133E, 0x000E}, {0x133F, 0x0010},
+};
+
+static int rtl8367b_write_initvals(struct rtl8366_smi *smi,
+				  const struct rtl8367b_initval *initvals,
+				  int count)
+{
+	int err;
+	int i;
+
+	for (i = 0; i < count; i++)
+		REG_WR(smi, initvals[i].reg, initvals[i].val);
+
+	return 0;
+}
+
+static int rtl8367b_read_phy_reg(struct rtl8366_smi *smi,
+				u32 phy_addr, u32 phy_reg, u32 *val)
+{
+	int timeout;
+	u32 data;
+	int err;
+
+	if (phy_addr > RTL8367B_PHY_ADDR_MAX)
+		return -EINVAL;
+
+	if (phy_reg > RTL8367B_PHY_REG_MAX)
+		return -EINVAL;
+
+	REG_RD(smi, RTL8367B_IA_STATUS_REG, &data);
+	if (data & RTL8367B_IA_STATUS_PHY_BUSY)
+		return -ETIMEDOUT;
+
+	/* prepare address */
+	REG_WR(smi, RTL8367B_IA_ADDRESS_REG,
+	       RTL8367B_INTERNAL_PHY_REG(phy_addr, phy_reg));
+
+	/* send read command */
+	REG_WR(smi, RTL8367B_IA_CTRL_REG,
+	       RTL8367B_IA_CTRL_CMD_MASK | RTL8367B_IA_CTRL_RW_READ);
+
+	timeout = 5;
+	do {
+		REG_RD(smi, RTL8367B_IA_STATUS_REG, &data);
+		if ((data & RTL8367B_IA_STATUS_PHY_BUSY) == 0)
+			break;
+
+		if (timeout--) {
+			dev_err(smi->parent, "phy read timed out\n");
+			return -ETIMEDOUT;
+		}
+
+		udelay(1);
+	} while (1);
+
+	/* read data */
+	REG_RD(smi, RTL8367B_IA_READ_DATA_REG, val);
+
+	dev_dbg(smi->parent, "phy_read: addr:%02x, reg:%02x, val:%04x\n",
+		phy_addr, phy_reg, *val);
+	return 0;
+}
+
+static int rtl8367b_write_phy_reg(struct rtl8366_smi *smi,
+				 u32 phy_addr, u32 phy_reg, u32 val)
+{
+	int timeout;
+	u32 data;
+	int err;
+
+	dev_dbg(smi->parent, "phy_write: addr:%02x, reg:%02x, val:%04x\n",
+		phy_addr, phy_reg, val);
+
+	if (phy_addr > RTL8367B_PHY_ADDR_MAX)
+		return -EINVAL;
+
+	if (phy_reg > RTL8367B_PHY_REG_MAX)
+		return -EINVAL;
+
+	REG_RD(smi, RTL8367B_IA_STATUS_REG, &data);
+	if (data & RTL8367B_IA_STATUS_PHY_BUSY)
+		return -ETIMEDOUT;
+
+	/* preapre data */
+	REG_WR(smi, RTL8367B_IA_WRITE_DATA_REG, val);
+
+	/* prepare address */
+	REG_WR(smi, RTL8367B_IA_ADDRESS_REG,
+	       RTL8367B_INTERNAL_PHY_REG(phy_addr, phy_reg));
+
+	/* send write command */
+	REG_WR(smi, RTL8367B_IA_CTRL_REG,
+	       RTL8367B_IA_CTRL_CMD_MASK | RTL8367B_IA_CTRL_RW_WRITE);
+
+	timeout = 5;
+	do {
+		REG_RD(smi, RTL8367B_IA_STATUS_REG, &data);
+		if ((data & RTL8367B_IA_STATUS_PHY_BUSY) == 0)
+			break;
+
+		if (timeout--) {
+			dev_err(smi->parent, "phy write timed out\n");
+			return -ETIMEDOUT;
+		}
+
+		udelay(1);
+	} while (1);
+
+	return 0;
+}
+
+static int rtl8367b_init_regs(struct rtl8366_smi *smi)
+{
+	const struct rtl8367b_initval *initvals;
+	u32 chip_ver;
+	u32 rlvid;
+	int count;
+	int err;
+
+	REG_WR(smi, RTL8367B_RTL_MAGIC_ID_REG, RTL8367B_RTL_MAGIC_ID_VAL);
+	REG_RD(smi, RTL8367B_CHIP_VER_REG, &chip_ver);
+
+	rlvid = (chip_ver >> RTL8367B_CHIP_VER_RLVID_SHIFT) &
+		RTL8367B_CHIP_VER_RLVID_MASK;
+
+	switch (rlvid) {
+	case 0:
+		initvals = rtl8367r_vb_initvals_0;
+		count = ARRAY_SIZE(rtl8367r_vb_initvals_0);
+		break;
+
+	case 1:
+		initvals = rtl8367r_vb_initvals_1;
+		count = ARRAY_SIZE(rtl8367r_vb_initvals_1);
+		break;
+
+	default:
+		dev_err(smi->parent, "unknow rlvid %u\n", rlvid);
+		return -ENODEV;
+	}
+
+	/* TODO: disable RLTP */
+
+	return rtl8367b_write_initvals(smi, initvals, count);
+}
+
+static int rtl8367b_reset_chip(struct rtl8366_smi *smi)
+{
+	int timeout = 10;
+	int err;
+	u32 data;
+
+	REG_WR(smi, RTL8367B_CHIP_RESET_REG, RTL8367B_CHIP_RESET_HW);
+	msleep(RTL8367B_RESET_DELAY);
+
+	do {
+		REG_RD(smi, RTL8367B_CHIP_RESET_REG, &data);
+		if (!(data & RTL8367B_CHIP_RESET_HW))
+			break;
+
+		msleep(1);
+	} while (--timeout);
+
+	if (!timeout) {
+		dev_err(smi->parent, "chip reset timed out\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int rtl8367b_extif_set_mode(struct rtl8366_smi *smi, int id,
+				   enum rtl8367_extif_mode mode)
+{
+	int err;
+
+	/* set port mode */
+	switch (mode) {
+	case RTL8367_EXTIF_MODE_RGMII:
+		REG_RMW(smi, RTL8367B_CHIP_DEBUG0_REG,
+			RTL8367B_DEBUG0_SEL33(id),
+			RTL8367B_DEBUG0_SEL33(id));
+		if (id <= 1) {
+			REG_RMW(smi, RTL8367B_CHIP_DEBUG0_REG,
+				RTL8367B_DEBUG0_DRI(id) |
+					RTL8367B_DEBUG0_DRI_RG(id) |
+					RTL8367B_DEBUG0_SLR(id),
+				RTL8367B_DEBUG0_DRI_RG(id) |
+					RTL8367B_DEBUG0_SLR(id));
+			REG_RMW(smi, RTL8367B_CHIP_DEBUG1_REG,
+				RTL8367B_DEBUG1_DN_MASK(id) |
+					RTL8367B_DEBUG1_DP_MASK(id),
+				(7 << RTL8367B_DEBUG1_DN_SHIFT(id)) |
+					(7 << RTL8367B_DEBUG1_DP_SHIFT(id)));
+		} else {
+			REG_RMW(smi, RTL8367B_CHIP_DEBUG2_REG,
+				RTL8367B_DEBUG2_DRI_EXT2 |
+					RTL8367B_DEBUG2_DRI_EXT2_RG |
+					RTL8367B_DEBUG2_SLR_EXT2 |
+					RTL8367B_DEBUG2_RG2_DN_MASK |
+					RTL8367B_DEBUG2_RG2_DP_MASK,
+				RTL8367B_DEBUG2_DRI_EXT2_RG |
+					RTL8367B_DEBUG2_SLR_EXT2 |
+					(7 << RTL8367B_DEBUG2_RG2_DN_SHIFT) |
+					(7 << RTL8367B_DEBUG2_RG2_DP_SHIFT));
+		}
+		break;
+
+	case RTL8367_EXTIF_MODE_TMII_MAC:
+	case RTL8367_EXTIF_MODE_TMII_PHY:
+		REG_RMW(smi, RTL8367B_BYPASS_LINE_RATE_REG, BIT(id), BIT(id));
+		break;
+
+	case RTL8367_EXTIF_MODE_GMII:
+		REG_RMW(smi, RTL8367B_CHIP_DEBUG0_REG,
+			RTL8367B_DEBUG0_SEL33(id),
+			RTL8367B_DEBUG0_SEL33(id));
+		REG_RMW(smi, RTL8367B_EXT_RGMXF_REG(id), BIT(6), BIT(6));
+		break;
+
+	case RTL8367_EXTIF_MODE_MII_MAC:
+	case RTL8367_EXTIF_MODE_MII_PHY:
+	case RTL8367_EXTIF_MODE_DISABLED:
+		REG_RMW(smi, RTL8367B_BYPASS_LINE_RATE_REG, BIT(id), 0);
+		REG_RMW(smi, RTL8367B_EXT_RGMXF_REG(id), BIT(6), 0);
+		break;
+
+	default:
+		dev_err(smi->parent,
+			"invalid mode for external interface %d\n", id);
+		return -EINVAL;
+	}
+
+	if (id <= 1)
+		REG_RMW(smi, RTL8367B_DIS_REG,
+			RTL8367B_DIS_RGMII_MASK << RTL8367B_DIS_RGMII_SHIFT(id),
+			mode << RTL8367B_DIS_RGMII_SHIFT(id));
+	else
+		REG_RMW(smi, RTL8367B_DIS2_REG,
+			RTL8367B_DIS2_RGMII_MASK << RTL8367B_DIS2_RGMII_SHIFT,
+			mode << RTL8367B_DIS2_RGMII_SHIFT);
+
+	return 0;
+}
+
+static int rtl8367b_extif_set_force(struct rtl8366_smi *smi, int id,
+				    struct rtl8367_port_ability *pa)
+{
+	u32 mask;
+	u32 val;
+	int err;
+
+	mask = (RTL8367B_DI_FORCE_MODE |
+		RTL8367B_DI_FORCE_NWAY |
+		RTL8367B_DI_FORCE_TXPAUSE |
+		RTL8367B_DI_FORCE_RXPAUSE |
+		RTL8367B_DI_FORCE_LINK |
+		RTL8367B_DI_FORCE_DUPLEX |
+		RTL8367B_DI_FORCE_SPEED_MASK);
+
+	val = pa->speed;
+	val |= pa->force_mode ? RTL8367B_DI_FORCE_MODE : 0;
+	val |= pa->nway ? RTL8367B_DI_FORCE_NWAY : 0;
+	val |= pa->txpause ? RTL8367B_DI_FORCE_TXPAUSE : 0;
+	val |= pa->rxpause ? RTL8367B_DI_FORCE_RXPAUSE : 0;
+	val |= pa->link ? RTL8367B_DI_FORCE_LINK : 0;
+	val |= pa->duplex ? RTL8367B_DI_FORCE_DUPLEX : 0;
+
+	REG_RMW(smi, RTL8367B_DI_FORCE_REG(id), mask, val);
+
+	return 0;
+}
+
+static int rtl8367b_extif_set_rgmii_delay(struct rtl8366_smi *smi, int id,
+					 unsigned txdelay, unsigned rxdelay)
+{
+	u32 mask;
+	u32 val;
+	int err;
+
+	mask = (RTL8367B_EXT_RGMXF_RXDELAY_MASK |
+		(RTL8367B_EXT_RGMXF_TXDELAY_MASK <<
+			RTL8367B_EXT_RGMXF_TXDELAY_SHIFT));
+
+	val = rxdelay;
+	val |= txdelay << RTL8367B_EXT_RGMXF_TXDELAY_SHIFT;
+
+	REG_RMW(smi, RTL8367B_EXT_RGMXF_REG(id), mask, val);
+
+	return 0;
+}
+
+static int rtl8367b_extif_init(struct rtl8366_smi *smi, int id,
+			       struct rtl8367_extif_config *cfg)
+{
+	enum rtl8367_extif_mode mode;
+	int err;
+
+	mode = (cfg) ? cfg->mode : RTL8367_EXTIF_MODE_DISABLED;
+
+	err = rtl8367b_extif_set_mode(smi, id, mode);
+	if (err)
+		return err;
+
+	if (mode != RTL8367_EXTIF_MODE_DISABLED) {
+		err = rtl8367b_extif_set_force(smi, id, &cfg->ability);
+		if (err)
+			return err;
+
+		err = rtl8367b_extif_set_rgmii_delay(smi, id, cfg->txdelay,
+						     cfg->rxdelay);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static int rtl8367b_extif_init_of(struct rtl8366_smi *smi, int id,
+				  const char *name)
+{
+	struct rtl8367_extif_config *cfg;
+	const __be32 *prop;
+	int size;
+	int err;
+
+	prop = of_get_property(smi->parent->of_node, name, &size);
+	if (!prop)
+		return rtl8367b_extif_init(smi, id, NULL);
+
+	if (size != (9 * sizeof(*prop))) {
+		dev_err(smi->parent, "%s property is invalid\n", name);
+		return -EINVAL;
+	}
+
+	cfg = kzalloc(sizeof(struct rtl8367_extif_config), GFP_KERNEL);
+	if (!cfg)
+		return -ENOMEM;
+
+	cfg->txdelay = be32_to_cpup(prop++);
+	cfg->rxdelay = be32_to_cpup(prop++);
+	cfg->mode = be32_to_cpup(prop++);
+	cfg->ability.force_mode = be32_to_cpup(prop++);
+	cfg->ability.txpause = be32_to_cpup(prop++);
+	cfg->ability.rxpause = be32_to_cpup(prop++);
+	cfg->ability.link = be32_to_cpup(prop++);
+	cfg->ability.duplex = be32_to_cpup(prop++);
+	cfg->ability.speed = be32_to_cpup(prop++);
+
+	err = rtl8367b_extif_init(smi, id, cfg);
+	kfree(cfg);
+
+	return err;
+}
+#else
+static int rtl8367b_extif_init_of(struct rtl8366_smi *smi, int id,
+				  const char *name)
+{
+	return -EINVAL;
+}
+#endif
+
+static int rtl8367b_setup(struct rtl8366_smi *smi)
+{
+	struct rtl8367_platform_data *pdata;
+	int err;
+	int i;
+
+	pdata = smi->parent->platform_data;
+
+	err = rtl8367b_init_regs(smi);
+	if (err)
+		return err;
+
+	/* initialize external interfaces */
+	if (smi->parent->of_node) {
+		err = rtl8367b_extif_init_of(smi, 0, "realtek,extif0");
+		if (err)
+			return err;
+
+		err = rtl8367b_extif_init_of(smi, 1, "realtek,extif1");
+		if (err)
+			return err;
+
+		err = rtl8367b_extif_init_of(smi, 2, "realtek,extif2");
+		if (err)
+			return err;
+	} else {
+		err = rtl8367b_extif_init(smi, 0, pdata->extif0_cfg);
+		if (err)
+			return err;
+
+		err = rtl8367b_extif_init(smi, 1, pdata->extif1_cfg);
+		if (err)
+			return err;
+	}
+
+	/* set maximum packet length to 1536 bytes */
+	REG_RMW(smi, RTL8367B_SWC0_REG, RTL8367B_SWC0_MAX_LENGTH_MASK,
+		RTL8367B_SWC0_MAX_LENGTH_1536);
+
+	/*
+	 * discard VLAN tagged packets if the port is not a member of
+	 * the VLAN with which the packets is associated.
+	 */
+	REG_WR(smi, RTL8367B_VLAN_INGRESS_REG, RTL8367B_PORTS_ALL);
+
+	/*
+	 * Setup egress tag mode for each port.
+	 */
+	for (i = 0; i < RTL8367B_NUM_PORTS; i++)
+		REG_RMW(smi,
+			RTL8367B_PORT_MISC_CFG_REG(i),
+			RTL8367B_PORT_MISC_CFG_EGRESS_MODE_MASK <<
+				RTL8367B_PORT_MISC_CFG_EGRESS_MODE_SHIFT,
+			RTL8367B_PORT_MISC_CFG_EGRESS_MODE_ORIGINAL <<
+				RTL8367B_PORT_MISC_CFG_EGRESS_MODE_SHIFT);
+
+	return 0;
+}
+
+static int rtl8367b_get_mib_counter(struct rtl8366_smi *smi, int counter,
+				    int port, unsigned long long *val)
+{
+	struct rtl8366_mib_counter *mib;
+	int offset;
+	int i;
+	int err;
+	u32 addr, data;
+	u64 mibvalue;
+
+	if (port > RTL8367B_NUM_PORTS ||
+	    counter >= RTL8367B_NUM_MIB_COUNTERS)
+		return -EINVAL;
+
+	mib = &rtl8367b_mib_counters[counter];
+	addr = RTL8367B_MIB_COUNTER_PORT_OFFSET * port + mib->offset;
+
+	/*
+	 * Writing access counter address first
+	 * then ASIC will prepare 64bits counter wait for being retrived
+	 */
+	REG_WR(smi, RTL8367B_MIB_ADDRESS_REG, addr >> 2);
+
+	/* read MIB control register */
+	REG_RD(smi, RTL8367B_MIB_CTRL0_REG(0), &data);
+
+	if (data & RTL8367B_MIB_CTRL0_BUSY_MASK)
+		return -EBUSY;
+
+	if (data & RTL8367B_MIB_CTRL0_RESET_MASK)
+		return -EIO;
+
+	if (mib->length == 4)
+		offset = 3;
+	else
+		offset = (mib->offset + 1) % 4;
+
+	mibvalue = 0;
+	for (i = 0; i < mib->length; i++) {
+		REG_RD(smi, RTL8367B_MIB_COUNTER_REG(offset - i), &data);
+		mibvalue = (mibvalue << 16) | (data & 0xFFFF);
+	}
+
+	*val = mibvalue;
+	return 0;
+}
+
+static int rtl8367b_get_vlan_4k(struct rtl8366_smi *smi, u32 vid,
+				struct rtl8366_vlan_4k *vlan4k)
+{
+	u32 data[RTL8367B_TA_VLAN_NUM_WORDS];
+	int err;
+	int i;
+
+	memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k));
+
+	if (vid >= RTL8367B_NUM_VIDS)
+		return -EINVAL;
+
+	/* write VID */
+	REG_WR(smi, RTL8367B_TA_ADDR_REG, vid);
+
+	/* write table access control word */
+	REG_WR(smi, RTL8367B_TA_CTRL_REG, RTL8367B_TA_CTRL_CVLAN_READ);
+
+	for (i = 0; i < ARRAY_SIZE(data); i++)
+		REG_RD(smi, RTL8367B_TA_RDDATA_REG(i), &data[i]);
+
+	vlan4k->vid = vid;
+	vlan4k->member = (data[0] >> RTL8367B_TA_VLAN0_MEMBER_SHIFT) &
+			 RTL8367B_TA_VLAN0_MEMBER_MASK;
+	vlan4k->untag = (data[0] >> RTL8367B_TA_VLAN0_UNTAG_SHIFT) &
+			RTL8367B_TA_VLAN0_UNTAG_MASK;
+	vlan4k->fid = (data[1] >> RTL8367B_TA_VLAN1_FID_SHIFT) &
+		      RTL8367B_TA_VLAN1_FID_MASK;
+
+	return 0;
+}
+
+static int rtl8367b_set_vlan_4k(struct rtl8366_smi *smi,
+				const struct rtl8366_vlan_4k *vlan4k)
+{
+	u32 data[RTL8367B_TA_VLAN_NUM_WORDS];
+	int err;
+	int i;
+
+	if (vlan4k->vid >= RTL8367B_NUM_VIDS ||
+	    vlan4k->member > RTL8367B_TA_VLAN0_MEMBER_MASK ||
+	    vlan4k->untag > RTL8367B_UNTAG_MASK ||
+	    vlan4k->fid > RTL8367B_FIDMAX)
+		return -EINVAL;
+
+	memset(data, 0, sizeof(data));
+
+	data[0] = (vlan4k->member & RTL8367B_TA_VLAN0_MEMBER_MASK) <<
+		  RTL8367B_TA_VLAN0_MEMBER_SHIFT;
+	data[0] |= (vlan4k->untag & RTL8367B_TA_VLAN0_UNTAG_MASK) <<
+		   RTL8367B_TA_VLAN0_UNTAG_SHIFT;
+	data[1] = (vlan4k->fid & RTL8367B_TA_VLAN1_FID_MASK) <<
+		  RTL8367B_TA_VLAN1_FID_SHIFT;
+
+	for (i = 0; i < ARRAY_SIZE(data); i++)
+		REG_WR(smi, RTL8367B_TA_WRDATA_REG(i), data[i]);
+
+	/* write VID */
+	REG_WR(smi, RTL8367B_TA_ADDR_REG,
+	       vlan4k->vid & RTL8367B_TA_VLAN_VID_MASK);
+
+	/* write table access control word */
+	REG_WR(smi, RTL8367B_TA_CTRL_REG, RTL8367B_TA_CTRL_CVLAN_WRITE);
+
+	return 0;
+}
+
+static int rtl8367b_get_vlan_mc(struct rtl8366_smi *smi, u32 index,
+				struct rtl8366_vlan_mc *vlanmc)
+{
+	u32 data[RTL8367B_VLAN_MC_NUM_WORDS];
+	int err;
+	int i;
+
+	memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc));
+
+	if (index >= RTL8367B_NUM_VLANS)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(data); i++)
+		REG_RD(smi, RTL8367B_VLAN_MC_BASE(index) + i, &data[i]);
+
+	vlanmc->member = (data[0] >> RTL8367B_VLAN_MC0_MEMBER_SHIFT) &
+			 RTL8367B_VLAN_MC0_MEMBER_MASK;
+	vlanmc->fid = (data[1] >> RTL8367B_VLAN_MC1_FID_SHIFT) &
+		      RTL8367B_VLAN_MC1_FID_MASK;
+	vlanmc->vid = (data[3] >> RTL8367B_VLAN_MC3_EVID_SHIFT) &
+		      RTL8367B_VLAN_MC3_EVID_MASK;
+
+	return 0;
+}
+
+static int rtl8367b_set_vlan_mc(struct rtl8366_smi *smi, u32 index,
+				const struct rtl8366_vlan_mc *vlanmc)
+{
+	u32 data[RTL8367B_VLAN_MC_NUM_WORDS];
+	int err;
+	int i;
+
+	if (index >= RTL8367B_NUM_VLANS ||
+	    vlanmc->vid >= RTL8367B_NUM_VIDS ||
+	    vlanmc->priority > RTL8367B_PRIORITYMAX ||
+	    vlanmc->member > RTL8367B_VLAN_MC0_MEMBER_MASK ||
+	    vlanmc->untag > RTL8367B_UNTAG_MASK ||
+	    vlanmc->fid > RTL8367B_FIDMAX)
+		return -EINVAL;
+
+	data[0] = (vlanmc->member & RTL8367B_VLAN_MC0_MEMBER_MASK) <<
+		  RTL8367B_VLAN_MC0_MEMBER_SHIFT;
+	data[1] = (vlanmc->fid & RTL8367B_VLAN_MC1_FID_MASK) <<
+		  RTL8367B_VLAN_MC1_FID_SHIFT;
+	data[2] = 0;
+	data[3] = (vlanmc->vid & RTL8367B_VLAN_MC3_EVID_MASK) <<
+		   RTL8367B_VLAN_MC3_EVID_SHIFT;
+
+	for (i = 0; i < ARRAY_SIZE(data); i++)
+		REG_WR(smi, RTL8367B_VLAN_MC_BASE(index) + i, data[i]);
+
+	return 0;
+}
+
+static int rtl8367b_get_mc_index(struct rtl8366_smi *smi, int port, int *val)
+{
+	u32 data;
+	int err;
+
+	if (port >= RTL8367B_NUM_PORTS)
+		return -EINVAL;
+
+	REG_RD(smi, RTL8367B_VLAN_PVID_CTRL_REG(port), &data);
+
+	*val = (data >> RTL8367B_VLAN_PVID_CTRL_SHIFT(port)) &
+	       RTL8367B_VLAN_PVID_CTRL_MASK;
+
+	return 0;
+}
+
+static int rtl8367b_set_mc_index(struct rtl8366_smi *smi, int port, int index)
+{
+	if (port >= RTL8367B_NUM_PORTS || index >= RTL8367B_NUM_VLANS)
+		return -EINVAL;
+
+	return rtl8366_smi_rmwr(smi, RTL8367B_VLAN_PVID_CTRL_REG(port),
+				RTL8367B_VLAN_PVID_CTRL_MASK <<
+					RTL8367B_VLAN_PVID_CTRL_SHIFT(port),
+				(index & RTL8367B_VLAN_PVID_CTRL_MASK) <<
+					RTL8367B_VLAN_PVID_CTRL_SHIFT(port));
+}
+
+static int rtl8367b_enable_vlan(struct rtl8366_smi *smi, int enable)
+{
+	return rtl8366_smi_rmwr(smi, RTL8367B_VLAN_CTRL_REG,
+				RTL8367B_VLAN_CTRL_ENABLE,
+				(enable) ? RTL8367B_VLAN_CTRL_ENABLE : 0);
+}
+
+static int rtl8367b_enable_vlan4k(struct rtl8366_smi *smi, int enable)
+{
+	return 0;
+}
+
+static int rtl8367b_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan)
+{
+	unsigned max = RTL8367B_NUM_VLANS;
+
+	if (smi->vlan4k_enabled)
+		max = RTL8367B_NUM_VIDS - 1;
+
+	if (vlan == 0 || vlan >= max)
+		return 0;
+
+	return 1;
+}
+
+static int rtl8367b_enable_port(struct rtl8366_smi *smi, int port, int enable)
+{
+	int err;
+
+	REG_WR(smi, RTL8367B_PORT_ISOLATION_REG(port),
+	       (enable) ? RTL8367B_PORTS_ALL : 0);
+
+	return 0;
+}
+
+static int rtl8367b_sw_reset_mibs(struct switch_dev *dev,
+				  const struct switch_attr *attr,
+				  struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+
+	return rtl8366_smi_rmwr(smi, RTL8367B_MIB_CTRL0_REG(0), 0,
+				RTL8367B_MIB_CTRL0_GLOBAL_RESET_MASK);
+}
+
+static int rtl8367b_sw_get_port_link(struct switch_dev *dev,
+				    int port,
+				    struct switch_port_link *link)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data = 0;
+	u32 speed;
+
+	if (port >= RTL8367B_NUM_PORTS)
+		return -EINVAL;
+
+	rtl8366_smi_read_reg(smi, RTL8367B_PORT_STATUS_REG(port), &data);
+
+	link->link = !!(data & RTL8367B_PORT_STATUS_LINK);
+	if (!link->link)
+		return 0;
+
+	link->duplex = !!(data & RTL8367B_PORT_STATUS_DUPLEX);
+	link->rx_flow = !!(data & RTL8367B_PORT_STATUS_RXPAUSE);
+	link->tx_flow = !!(data & RTL8367B_PORT_STATUS_TXPAUSE);
+	link->aneg = !!(data & RTL8367B_PORT_STATUS_NWAY);
+
+	speed = (data & RTL8367B_PORT_STATUS_SPEED_MASK);
+	switch (speed) {
+	case 0:
+		link->speed = SWITCH_PORT_SPEED_10;
+		break;
+	case 1:
+		link->speed = SWITCH_PORT_SPEED_100;
+		break;
+	case 2:
+		link->speed = SWITCH_PORT_SPEED_1000;
+		break;
+	default:
+		link->speed = SWITCH_PORT_SPEED_UNKNOWN;
+		break;
+	}
+
+	return 0;
+}
+
+static int rtl8367b_sw_get_max_length(struct switch_dev *dev,
+				     const struct switch_attr *attr,
+				     struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 data;
+
+	rtl8366_smi_read_reg(smi, RTL8367B_SWC0_REG, &data);
+	val->value.i = (data & RTL8367B_SWC0_MAX_LENGTH_MASK) >>
+			RTL8367B_SWC0_MAX_LENGTH_SHIFT;
+
+	return 0;
+}
+
+static int rtl8367b_sw_set_max_length(struct switch_dev *dev,
+				     const struct switch_attr *attr,
+				     struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	u32 max_len;
+
+	switch (val->value.i) {
+	case 0:
+		max_len = RTL8367B_SWC0_MAX_LENGTH_1522;
+		break;
+	case 1:
+		max_len = RTL8367B_SWC0_MAX_LENGTH_1536;
+		break;
+	case 2:
+		max_len = RTL8367B_SWC0_MAX_LENGTH_1552;
+		break;
+	case 3:
+		max_len = RTL8367B_SWC0_MAX_LENGTH_16000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return rtl8366_smi_rmwr(smi, RTL8367B_SWC0_REG,
+			        RTL8367B_SWC0_MAX_LENGTH_MASK, max_len);
+}
+
+
+static int rtl8367b_sw_reset_port_mibs(struct switch_dev *dev,
+				       const struct switch_attr *attr,
+				       struct switch_val *val)
+{
+	struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev);
+	int port;
+
+	port = val->port_vlan;
+	if (port >= RTL8367B_NUM_PORTS)
+		return -EINVAL;
+
+	return rtl8366_smi_rmwr(smi, RTL8367B_MIB_CTRL0_REG(port / 8), 0,
+				RTL8367B_MIB_CTRL0_PORT_RESET_MASK(port % 8));
+}
+
+static int rtl8367b_sw_get_port_stats(struct switch_dev *dev, int port,
+                                        struct switch_port_stats *stats)
+{
+	return (rtl8366_sw_get_port_stats(dev, port, stats,
+				RTL8367B_MIB_TXB_ID, RTL8367B_MIB_RXB_ID));
+}
+
+static struct switch_attr rtl8367b_globals[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.set = rtl8366_sw_set_vlan_enable,
+		.get = rtl8366_sw_get_vlan_enable,
+		.max = 1,
+		.ofs = 1
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan4k",
+		.description = "Enable VLAN 4K mode",
+		.set = rtl8366_sw_set_vlan_enable,
+		.get = rtl8366_sw_get_vlan_enable,
+		.max = 1,
+		.ofs = 2
+	}, {
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mibs",
+		.description = "Reset all MIB counters",
+		.set = rtl8367b_sw_reset_mibs,
+	}, {
+		.type = SWITCH_TYPE_INT,
+		.name = "max_length",
+		.description = "Get/Set the maximum length of valid packets"
+			       "(0:1522, 1:1536, 2:1552, 3:16000)",
+		.set = rtl8367b_sw_set_max_length,
+		.get = rtl8367b_sw_get_max_length,
+		.max = 3,
+	}
+};
+
+static struct switch_attr rtl8367b_port[] = {
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mib",
+		.description = "Reset single port MIB counters",
+		.set = rtl8367b_sw_reset_port_mibs,
+	}, {
+		.type = SWITCH_TYPE_STRING,
+		.name = "mib",
+		.description = "Get MIB counters for port",
+		.max = 33,
+		.set = NULL,
+		.get = rtl8366_sw_get_port_mib,
+	},
+};
+
+static struct switch_attr rtl8367b_vlan[] = {
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "info",
+		.description = "Get vlan information",
+		.max = 1,
+		.set = NULL,
+		.get = rtl8366_sw_get_vlan_info,
+	},
+};
+
+static const struct switch_dev_ops rtl8367b_sw_ops = {
+	.attr_global = {
+		.attr = rtl8367b_globals,
+		.n_attr = ARRAY_SIZE(rtl8367b_globals),
+	},
+	.attr_port = {
+		.attr = rtl8367b_port,
+		.n_attr = ARRAY_SIZE(rtl8367b_port),
+	},
+	.attr_vlan = {
+		.attr = rtl8367b_vlan,
+		.n_attr = ARRAY_SIZE(rtl8367b_vlan),
+	},
+
+	.get_vlan_ports = rtl8366_sw_get_vlan_ports,
+	.set_vlan_ports = rtl8366_sw_set_vlan_ports,
+	.get_port_pvid = rtl8366_sw_get_port_pvid,
+	.set_port_pvid = rtl8366_sw_set_port_pvid,
+	.reset_switch = rtl8366_sw_reset_switch,
+	.get_port_link = rtl8367b_sw_get_port_link,
+	.get_port_stats = rtl8367b_sw_get_port_stats,
+};
+
+static int rtl8367b_switch_init(struct rtl8366_smi *smi)
+{
+	struct switch_dev *dev = &smi->sw_dev;
+	int err;
+
+	dev->name = "RTL8367B";
+	dev->cpu_port = smi->cpu_port;
+	dev->ports = RTL8367B_NUM_PORTS;
+	dev->vlans = RTL8367B_NUM_VIDS;
+	dev->ops = &rtl8367b_sw_ops;
+	dev->alias = dev_name(smi->parent);
+
+	err = register_switch(dev, NULL);
+	if (err)
+		dev_err(smi->parent, "switch registration failed\n");
+
+	return err;
+}
+
+static void rtl8367b_switch_cleanup(struct rtl8366_smi *smi)
+{
+	unregister_switch(&smi->sw_dev);
+}
+
+static int rtl8367b_mii_read(struct mii_bus *bus, int addr, int reg)
+{
+	struct rtl8366_smi *smi = bus->priv;
+	u32 val = 0;
+	int err;
+
+	err = rtl8367b_read_phy_reg(smi, addr, reg, &val);
+	if (err)
+		return 0xffff;
+
+	return val;
+}
+
+static int rtl8367b_mii_write(struct mii_bus *bus, int addr, int reg, u16 val)
+{
+	struct rtl8366_smi *smi = bus->priv;
+	u32 t;
+	int err;
+
+	err = rtl8367b_write_phy_reg(smi, addr, reg, val);
+	if (err)
+		return err;
+
+	/* flush write */
+	(void) rtl8367b_read_phy_reg(smi, addr, reg, &t);
+
+	return err;
+}
+
+static int rtl8367b_detect(struct rtl8366_smi *smi)
+{
+	const char *chip_name;
+	u32 chip_num;
+	u32 chip_ver;
+	u32 chip_mode;
+	int ret;
+
+	/* TODO: improve chip detection */
+	rtl8366_smi_write_reg(smi, RTL8367B_RTL_MAGIC_ID_REG,
+			      RTL8367B_RTL_MAGIC_ID_VAL);
+
+	ret = rtl8366_smi_read_reg(smi, RTL8367B_CHIP_NUMBER_REG, &chip_num);
+	if (ret) {
+		dev_err(smi->parent, "unable to read %s register\n",
+			"chip number");
+		return ret;
+	}
+
+	ret = rtl8366_smi_read_reg(smi, RTL8367B_CHIP_VER_REG, &chip_ver);
+	if (ret) {
+		dev_err(smi->parent, "unable to read %s register\n",
+			"chip version");
+		return ret;
+	}
+
+	ret = rtl8366_smi_read_reg(smi, RTL8367B_CHIP_MODE_REG, &chip_mode);
+	if (ret) {
+		dev_err(smi->parent, "unable to read %s register\n",
+			"chip mode");
+		return ret;
+	}
+
+	switch (chip_ver) {
+	case 0x1000:
+		chip_name = "8367RB";
+		break;
+	case 0x1010:
+		chip_name = "8367R-VB";
+		break;
+	default:
+		dev_err(smi->parent,
+			"unknown chip num:%04x ver:%04x, mode:%04x\n",
+			chip_num, chip_ver, chip_mode);
+		return -ENODEV;
+	}
+
+	dev_info(smi->parent, "RTL%s chip found\n", chip_name);
+
+	return 0;
+}
+
+static struct rtl8366_smi_ops rtl8367b_smi_ops = {
+	.detect		= rtl8367b_detect,
+	.reset_chip	= rtl8367b_reset_chip,
+	.setup		= rtl8367b_setup,
+
+	.mii_read	= rtl8367b_mii_read,
+	.mii_write	= rtl8367b_mii_write,
+
+	.get_vlan_mc	= rtl8367b_get_vlan_mc,
+	.set_vlan_mc	= rtl8367b_set_vlan_mc,
+	.get_vlan_4k	= rtl8367b_get_vlan_4k,
+	.set_vlan_4k	= rtl8367b_set_vlan_4k,
+	.get_mc_index	= rtl8367b_get_mc_index,
+	.set_mc_index	= rtl8367b_set_mc_index,
+	.get_mib_counter = rtl8367b_get_mib_counter,
+	.is_vlan_valid	= rtl8367b_is_vlan_valid,
+	.enable_vlan	= rtl8367b_enable_vlan,
+	.enable_vlan4k	= rtl8367b_enable_vlan4k,
+	.enable_port	= rtl8367b_enable_port,
+};
+
+static int  rtl8367b_probe(struct platform_device *pdev)
+{
+	struct rtl8366_smi *smi;
+	int err;
+
+	smi = rtl8366_smi_probe(pdev);
+	if (IS_ERR(smi))
+		return PTR_ERR(smi);
+
+	smi->clk_delay = 1500;
+	smi->cmd_read = 0xb9;
+	smi->cmd_write = 0xb8;
+	smi->ops = &rtl8367b_smi_ops;
+	smi->num_ports = RTL8367B_NUM_PORTS;
+	if (of_property_read_u32(pdev->dev.of_node, "cpu_port", &smi->cpu_port)
+	    || smi->cpu_port >= smi->num_ports)
+		smi->cpu_port = RTL8367B_CPU_PORT_NUM;
+	smi->num_vlan_mc = RTL8367B_NUM_VLANS;
+	smi->mib_counters = rtl8367b_mib_counters;
+	smi->num_mib_counters = ARRAY_SIZE(rtl8367b_mib_counters);
+
+	err = rtl8366_smi_init(smi);
+	if (err)
+		goto err_free_smi;
+
+	platform_set_drvdata(pdev, smi);
+
+	err = rtl8367b_switch_init(smi);
+	if (err)
+		goto err_clear_drvdata;
+
+	return 0;
+
+ err_clear_drvdata:
+	platform_set_drvdata(pdev, NULL);
+	rtl8366_smi_cleanup(smi);
+ err_free_smi:
+	kfree(smi);
+	return err;
+}
+
+static int rtl8367b_remove(struct platform_device *pdev)
+{
+	struct rtl8366_smi *smi = platform_get_drvdata(pdev);
+
+	if (smi) {
+		rtl8367b_switch_cleanup(smi);
+		platform_set_drvdata(pdev, NULL);
+		rtl8366_smi_cleanup(smi);
+		kfree(smi);
+	}
+
+	return 0;
+}
+
+static void rtl8367b_shutdown(struct platform_device *pdev)
+{
+	struct rtl8366_smi *smi = platform_get_drvdata(pdev);
+
+	if (smi)
+		rtl8367b_reset_chip(smi);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id rtl8367b_match[] = {
+	{ .compatible = "realtek,rtl8367b" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, rtl8367b_match);
+#endif
+
+static struct platform_driver rtl8367b_driver = {
+	.driver = {
+		.name		= RTL8367B_DRIVER_NAME,
+		.owner		= THIS_MODULE,
+#ifdef CONFIG_OF
+		.of_match_table = of_match_ptr(rtl8367b_match),
+#endif
+	},
+	.probe		= rtl8367b_probe,
+	.remove		= rtl8367b_remove,
+	.shutdown	= rtl8367b_shutdown,
+};
+
+module_platform_driver(rtl8367b_driver);
+
+MODULE_DESCRIPTION("Realtek RTL8367B ethernet switch driver");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" RTL8367B_DRIVER_NAME);
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/swconfig.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/swconfig.c
new file mode 100644
index 0000000..a734e57
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/swconfig.c
@@ -0,0 +1,1242 @@
+/*
+ * swconfig.c: Switch configuration API
+ *
+ * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/if.h>
+#include <linux/if_ether.h>
+#include <linux/capability.h>
+#include <linux/skbuff.h>
+#include <linux/switch.h>
+#include <linux/of.h>
+#include <linux/version.h>
+#include <uapi/linux/mii.h>
+
+#define SWCONFIG_DEVNAME	"switch%d"
+
+#include "swconfig_leds.c"
+
+MODULE_AUTHOR("Felix Fietkau <nbd@nbd.name>");
+MODULE_LICENSE("GPL");
+
+static int swdev_id;
+static struct list_head swdevs;
+static DEFINE_MUTEX(swdevs_lock);
+struct swconfig_callback;
+
+struct swconfig_callback {
+	struct sk_buff *msg;
+	struct genlmsghdr *hdr;
+	struct genl_info *info;
+	int cmd;
+
+	/* callback for filling in the message data */
+	int (*fill)(struct swconfig_callback *cb, void *arg);
+
+	/* callback for closing the message before sending it */
+	int (*close)(struct swconfig_callback *cb, void *arg);
+
+	struct nlattr *nest[4];
+	int args[4];
+};
+
+/* defaults */
+
+static int
+swconfig_get_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	int ret;
+	if (val->port_vlan >= dev->vlans)
+		return -EINVAL;
+
+	if (!dev->ops->get_vlan_ports)
+		return -EOPNOTSUPP;
+
+	ret = dev->ops->get_vlan_ports(dev, val);
+	return ret;
+}
+
+static int
+swconfig_set_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	struct switch_port *ports = val->value.ports;
+	const struct switch_dev_ops *ops = dev->ops;
+	int i;
+
+	if (val->port_vlan >= dev->vlans)
+		return -EINVAL;
+
+	/* validate ports */
+	if (val->len > dev->ports)
+		return -EINVAL;
+
+	if (!ops->set_vlan_ports)
+		return -EOPNOTSUPP;
+
+	for (i = 0; i < val->len; i++) {
+		if (ports[i].id >= dev->ports)
+			return -EINVAL;
+
+		if (ops->set_port_pvid &&
+		    !(ports[i].flags & (1 << SWITCH_PORT_FLAG_TAGGED)))
+			ops->set_port_pvid(dev, ports[i].id, val->port_vlan);
+	}
+
+	return ops->set_vlan_ports(dev, val);
+}
+
+static int
+swconfig_set_pvid(struct switch_dev *dev, const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	if (val->port_vlan >= dev->ports)
+		return -EINVAL;
+
+	if (!dev->ops->set_port_pvid)
+		return -EOPNOTSUPP;
+
+	return dev->ops->set_port_pvid(dev, val->port_vlan, val->value.i);
+}
+
+static int
+swconfig_get_pvid(struct switch_dev *dev, const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	if (val->port_vlan >= dev->ports)
+		return -EINVAL;
+
+	if (!dev->ops->get_port_pvid)
+		return -EOPNOTSUPP;
+
+	return dev->ops->get_port_pvid(dev, val->port_vlan, &val->value.i);
+}
+
+static int
+swconfig_set_link(struct switch_dev *dev, const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	if (!dev->ops->set_port_link)
+		return -EOPNOTSUPP;
+
+	return dev->ops->set_port_link(dev, val->port_vlan, val->value.link);
+}
+
+static int
+swconfig_get_link(struct switch_dev *dev, const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	struct switch_port_link *link = val->value.link;
+
+	if (val->port_vlan >= dev->ports)
+		return -EINVAL;
+
+	if (!dev->ops->get_port_link)
+		return -EOPNOTSUPP;
+
+	memset(link, 0, sizeof(*link));
+	return dev->ops->get_port_link(dev, val->port_vlan, link);
+}
+
+static int
+swconfig_apply_config(struct switch_dev *dev, const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	/* don't complain if not supported by the switch driver */
+	if (!dev->ops->apply_config)
+		return 0;
+
+	return dev->ops->apply_config(dev);
+}
+
+static int
+swconfig_reset_switch(struct switch_dev *dev, const struct switch_attr *attr,
+			struct switch_val *val)
+{
+	/* don't complain if not supported by the switch driver */
+	if (!dev->ops->reset_switch)
+		return 0;
+
+	return dev->ops->reset_switch(dev);
+}
+
+enum global_defaults {
+	GLOBAL_APPLY,
+	GLOBAL_RESET,
+};
+
+enum vlan_defaults {
+	VLAN_PORTS,
+};
+
+enum port_defaults {
+	PORT_PVID,
+	PORT_LINK,
+};
+
+static struct switch_attr default_global[] = {
+	[GLOBAL_APPLY] = {
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "apply",
+		.description = "Activate changes in the hardware",
+		.set = swconfig_apply_config,
+	},
+	[GLOBAL_RESET] = {
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset",
+		.description = "Reset the switch",
+		.set = swconfig_reset_switch,
+	}
+};
+
+static struct switch_attr default_port[] = {
+	[PORT_PVID] = {
+		.type = SWITCH_TYPE_INT,
+		.name = "pvid",
+		.description = "Primary VLAN ID",
+		.set = swconfig_set_pvid,
+		.get = swconfig_get_pvid,
+	},
+	[PORT_LINK] = {
+		.type = SWITCH_TYPE_LINK,
+		.name = "link",
+		.description = "Get port link information",
+		.set = swconfig_set_link,
+		.get = swconfig_get_link,
+	}
+};
+
+static struct switch_attr default_vlan[] = {
+	[VLAN_PORTS] = {
+		.type = SWITCH_TYPE_PORTS,
+		.name = "ports",
+		.description = "VLAN port mapping",
+		.set = swconfig_set_vlan_ports,
+		.get = swconfig_get_vlan_ports,
+	},
+};
+
+static const struct switch_attr *
+swconfig_find_attr_by_name(const struct switch_attrlist *alist,
+				const char *name)
+{
+	int i;
+
+	for (i = 0; i < alist->n_attr; i++)
+		if (strcmp(name, alist->attr[i].name) == 0)
+			return &alist->attr[i];
+
+	return NULL;
+}
+
+static void swconfig_defaults_init(struct switch_dev *dev)
+{
+	const struct switch_dev_ops *ops = dev->ops;
+
+	dev->def_global = 0;
+	dev->def_vlan = 0;
+	dev->def_port = 0;
+
+	if (ops->get_vlan_ports || ops->set_vlan_ports)
+		set_bit(VLAN_PORTS, &dev->def_vlan);
+
+	if (ops->get_port_pvid || ops->set_port_pvid)
+		set_bit(PORT_PVID, &dev->def_port);
+
+	if (ops->get_port_link &&
+	    !swconfig_find_attr_by_name(&ops->attr_port, "link"))
+		set_bit(PORT_LINK, &dev->def_port);
+
+	/* always present, can be no-op */
+	set_bit(GLOBAL_APPLY, &dev->def_global);
+	set_bit(GLOBAL_RESET, &dev->def_global);
+}
+
+
+static struct genl_family switch_fam;
+
+static const struct nla_policy switch_policy[SWITCH_ATTR_MAX+1] = {
+	[SWITCH_ATTR_ID] = { .type = NLA_U32 },
+	[SWITCH_ATTR_OP_ID] = { .type = NLA_U32 },
+	[SWITCH_ATTR_OP_PORT] = { .type = NLA_U32 },
+	[SWITCH_ATTR_OP_VLAN] = { .type = NLA_U32 },
+	[SWITCH_ATTR_OP_VALUE_INT] = { .type = NLA_U32 },
+	[SWITCH_ATTR_OP_VALUE_STR] = { .type = NLA_NUL_STRING },
+	[SWITCH_ATTR_OP_VALUE_PORTS] = { .type = NLA_NESTED },
+	[SWITCH_ATTR_TYPE] = { .type = NLA_U32 },
+};
+
+static const struct nla_policy port_policy[SWITCH_PORT_ATTR_MAX+1] = {
+	[SWITCH_PORT_ID] = { .type = NLA_U32 },
+	[SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG },
+};
+
+static struct nla_policy link_policy[SWITCH_LINK_ATTR_MAX] = {
+	[SWITCH_LINK_FLAG_DUPLEX] = { .type = NLA_FLAG },
+	[SWITCH_LINK_FLAG_ANEG] = { .type = NLA_FLAG },
+	[SWITCH_LINK_SPEED] = { .type = NLA_U32 },
+};
+
+static inline void
+swconfig_lock(void)
+{
+	mutex_lock(&swdevs_lock);
+}
+
+static inline void
+swconfig_unlock(void)
+{
+	mutex_unlock(&swdevs_lock);
+}
+
+static struct switch_dev *
+swconfig_get_dev(struct genl_info *info)
+{
+	struct switch_dev *dev = NULL;
+	struct switch_dev *p;
+	int id;
+
+	if (!info->attrs[SWITCH_ATTR_ID])
+		goto done;
+
+	id = nla_get_u32(info->attrs[SWITCH_ATTR_ID]);
+	swconfig_lock();
+	list_for_each_entry(p, &swdevs, dev_list) {
+		if (id != p->id)
+			continue;
+
+		dev = p;
+		break;
+	}
+	if (dev)
+		mutex_lock(&dev->sw_mutex);
+	else
+		pr_debug("device %d not found\n", id);
+	swconfig_unlock();
+done:
+	return dev;
+}
+
+static inline void
+swconfig_put_dev(struct switch_dev *dev)
+{
+	mutex_unlock(&dev->sw_mutex);
+}
+
+static int
+swconfig_dump_attr(struct swconfig_callback *cb, void *arg)
+{
+	struct switch_attr *op = arg;
+	struct genl_info *info = cb->info;
+	struct sk_buff *msg = cb->msg;
+	int id = cb->args[0];
+	void *hdr;
+
+	hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &switch_fam,
+			NLM_F_MULTI, SWITCH_CMD_NEW_ATTR);
+	if (IS_ERR(hdr))
+		return -1;
+
+	if (nla_put_u32(msg, SWITCH_ATTR_OP_ID, id))
+		goto nla_put_failure;
+	if (nla_put_u32(msg, SWITCH_ATTR_OP_TYPE, op->type))
+		goto nla_put_failure;
+	if (nla_put_string(msg, SWITCH_ATTR_OP_NAME, op->name))
+		goto nla_put_failure;
+	if (op->description)
+		if (nla_put_string(msg, SWITCH_ATTR_OP_DESCRIPTION,
+			op->description))
+			goto nla_put_failure;
+
+	genlmsg_end(msg, hdr);
+	return msg->len;
+nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	return -EMSGSIZE;
+}
+
+/* spread multipart messages across multiple message buffers */
+static int
+swconfig_send_multipart(struct swconfig_callback *cb, void *arg)
+{
+	struct genl_info *info = cb->info;
+	int restart = 0;
+	int err;
+
+	do {
+		if (!cb->msg) {
+			cb->msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+			if (cb->msg == NULL)
+				goto error;
+		}
+
+		if (!(cb->fill(cb, arg) < 0))
+			break;
+
+		/* fill failed, check if this was already the second attempt */
+		if (restart)
+			goto error;
+
+		/* try again in a new message, send the current one */
+		restart = 1;
+		if (cb->close) {
+			if (cb->close(cb, arg) < 0)
+				goto error;
+		}
+		err = genlmsg_reply(cb->msg, info);
+		cb->msg = NULL;
+		if (err < 0)
+			goto error;
+
+	} while (restart);
+
+	return 0;
+
+error:
+	if (cb->msg)
+		nlmsg_free(cb->msg);
+	return -1;
+}
+
+static int
+swconfig_list_attrs(struct sk_buff *skb, struct genl_info *info)
+{
+	struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
+	const struct switch_attrlist *alist;
+	struct switch_dev *dev;
+	struct swconfig_callback cb;
+	int err = -EINVAL;
+	int i;
+
+	/* defaults */
+	struct switch_attr *def_list;
+	unsigned long *def_active;
+	int n_def;
+
+	dev = swconfig_get_dev(info);
+	if (!dev)
+		return -EINVAL;
+
+	switch (hdr->cmd) {
+	case SWITCH_CMD_LIST_GLOBAL:
+		alist = &dev->ops->attr_global;
+		def_list = default_global;
+		def_active = &dev->def_global;
+		n_def = ARRAY_SIZE(default_global);
+		break;
+	case SWITCH_CMD_LIST_VLAN:
+		alist = &dev->ops->attr_vlan;
+		def_list = default_vlan;
+		def_active = &dev->def_vlan;
+		n_def = ARRAY_SIZE(default_vlan);
+		break;
+	case SWITCH_CMD_LIST_PORT:
+		alist = &dev->ops->attr_port;
+		def_list = default_port;
+		def_active = &dev->def_port;
+		n_def = ARRAY_SIZE(default_port);
+		break;
+	default:
+		WARN_ON(1);
+		goto out;
+	}
+
+	memset(&cb, 0, sizeof(cb));
+	cb.info = info;
+	cb.fill = swconfig_dump_attr;
+	for (i = 0; i < alist->n_attr; i++) {
+		if (alist->attr[i].disabled)
+			continue;
+		cb.args[0] = i;
+		err = swconfig_send_multipart(&cb, (void *) &alist->attr[i]);
+		if (err < 0)
+			goto error;
+	}
+
+	/* defaults */
+	for (i = 0; i < n_def; i++) {
+		if (!test_bit(i, def_active))
+			continue;
+		cb.args[0] = SWITCH_ATTR_DEFAULTS_OFFSET + i;
+		err = swconfig_send_multipart(&cb, (void *) &def_list[i]);
+		if (err < 0)
+			goto error;
+	}
+	swconfig_put_dev(dev);
+
+	if (!cb.msg)
+		return 0;
+
+	return genlmsg_reply(cb.msg, info);
+
+error:
+	if (cb.msg)
+		nlmsg_free(cb.msg);
+out:
+	swconfig_put_dev(dev);
+	return err;
+}
+
+static const struct switch_attr *
+swconfig_lookup_attr(struct switch_dev *dev, struct genl_info *info,
+		struct switch_val *val)
+{
+	struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
+	const struct switch_attrlist *alist;
+	const struct switch_attr *attr = NULL;
+	unsigned int attr_id;
+
+	/* defaults */
+	struct switch_attr *def_list;
+	unsigned long *def_active;
+	int n_def;
+
+	if (!info->attrs[SWITCH_ATTR_OP_ID])
+		goto done;
+
+	switch (hdr->cmd) {
+	case SWITCH_CMD_SET_GLOBAL:
+	case SWITCH_CMD_GET_GLOBAL:
+		alist = &dev->ops->attr_global;
+		def_list = default_global;
+		def_active = &dev->def_global;
+		n_def = ARRAY_SIZE(default_global);
+		break;
+	case SWITCH_CMD_SET_VLAN:
+	case SWITCH_CMD_GET_VLAN:
+		alist = &dev->ops->attr_vlan;
+		def_list = default_vlan;
+		def_active = &dev->def_vlan;
+		n_def = ARRAY_SIZE(default_vlan);
+		if (!info->attrs[SWITCH_ATTR_OP_VLAN])
+			goto done;
+		val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_VLAN]);
+		if (val->port_vlan >= dev->vlans)
+			goto done;
+		break;
+	case SWITCH_CMD_SET_PORT:
+	case SWITCH_CMD_GET_PORT:
+		alist = &dev->ops->attr_port;
+		def_list = default_port;
+		def_active = &dev->def_port;
+		n_def = ARRAY_SIZE(default_port);
+		if (!info->attrs[SWITCH_ATTR_OP_PORT])
+			goto done;
+		val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_PORT]);
+		if (val->port_vlan >= dev->ports)
+			goto done;
+		break;
+	default:
+		WARN_ON(1);
+		goto done;
+	}
+
+	if (!alist)
+		goto done;
+
+	attr_id = nla_get_u32(info->attrs[SWITCH_ATTR_OP_ID]);
+	if (attr_id >= SWITCH_ATTR_DEFAULTS_OFFSET) {
+		attr_id -= SWITCH_ATTR_DEFAULTS_OFFSET;
+		if (attr_id >= n_def)
+			goto done;
+		if (!test_bit(attr_id, def_active))
+			goto done;
+		attr = &def_list[attr_id];
+	} else {
+		if (attr_id >= alist->n_attr)
+			goto done;
+		attr = &alist->attr[attr_id];
+	}
+
+	if (attr->disabled)
+		attr = NULL;
+
+done:
+	if (!attr)
+		pr_debug("attribute lookup failed\n");
+	val->attr = attr;
+	return attr;
+}
+
+static int
+swconfig_parse_ports(struct sk_buff *msg, struct nlattr *head,
+		struct switch_val *val, int max)
+{
+	struct nlattr *nla;
+	int rem;
+
+	val->len = 0;
+	nla_for_each_nested(nla, head, rem) {
+		struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1];
+		struct switch_port *port;
+
+		if (val->len >= max)
+			return -EINVAL;
+
+		port = &val->value.ports[val->len];
+
+		if (nla_parse_nested_deprecated(tb, SWITCH_PORT_ATTR_MAX, nla,
+				port_policy, NULL))
+			return -EINVAL;
+
+		if (!tb[SWITCH_PORT_ID])
+			return -EINVAL;
+
+		port->id = nla_get_u32(tb[SWITCH_PORT_ID]);
+		if (tb[SWITCH_PORT_FLAG_TAGGED])
+			port->flags |= (1 << SWITCH_PORT_FLAG_TAGGED);
+		val->len++;
+	}
+
+	return 0;
+}
+
+static int
+swconfig_parse_link(struct sk_buff *msg, struct nlattr *nla,
+		    struct switch_port_link *link)
+{
+	struct nlattr *tb[SWITCH_LINK_ATTR_MAX + 1];
+
+	if (nla_parse_nested_deprecated(tb, SWITCH_LINK_ATTR_MAX, nla, link_policy, NULL))
+		return -EINVAL;
+
+	link->duplex = !!tb[SWITCH_LINK_FLAG_DUPLEX];
+	link->aneg = !!tb[SWITCH_LINK_FLAG_ANEG];
+	link->speed = nla_get_u32(tb[SWITCH_LINK_SPEED]);
+
+	return 0;
+}
+
+static int
+swconfig_set_attr(struct sk_buff *skb, struct genl_info *info)
+{
+	const struct switch_attr *attr;
+	struct switch_dev *dev;
+	struct switch_val val;
+	int err = -EINVAL;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	dev = swconfig_get_dev(info);
+	if (!dev)
+		return -EINVAL;
+
+	memset(&val, 0, sizeof(val));
+	attr = swconfig_lookup_attr(dev, info, &val);
+	if (!attr || !attr->set)
+		goto error;
+
+	val.attr = attr;
+	switch (attr->type) {
+	case SWITCH_TYPE_NOVAL:
+		break;
+	case SWITCH_TYPE_INT:
+		if (!info->attrs[SWITCH_ATTR_OP_VALUE_INT])
+			goto error;
+		val.value.i =
+			nla_get_u32(info->attrs[SWITCH_ATTR_OP_VALUE_INT]);
+		break;
+	case SWITCH_TYPE_STRING:
+		if (!info->attrs[SWITCH_ATTR_OP_VALUE_STR])
+			goto error;
+		val.value.s =
+			nla_data(info->attrs[SWITCH_ATTR_OP_VALUE_STR]);
+		break;
+	case SWITCH_TYPE_PORTS:
+		val.value.ports = dev->portbuf;
+		memset(dev->portbuf, 0,
+			sizeof(struct switch_port) * dev->ports);
+
+		/* TODO: implement multipart? */
+		if (info->attrs[SWITCH_ATTR_OP_VALUE_PORTS]) {
+			err = swconfig_parse_ports(skb,
+				info->attrs[SWITCH_ATTR_OP_VALUE_PORTS],
+				&val, dev->ports);
+			if (err < 0)
+				goto error;
+		} else {
+			val.len = 0;
+			err = 0;
+		}
+		break;
+	case SWITCH_TYPE_LINK:
+		val.value.link = &dev->linkbuf;
+		memset(&dev->linkbuf, 0, sizeof(struct switch_port_link));
+
+		if (info->attrs[SWITCH_ATTR_OP_VALUE_LINK]) {
+			err = swconfig_parse_link(skb,
+						  info->attrs[SWITCH_ATTR_OP_VALUE_LINK],
+						  val.value.link);
+			if (err < 0)
+				goto error;
+		} else {
+			val.len = 0;
+			err = 0;
+		}
+		break;
+	default:
+		goto error;
+	}
+
+	err = attr->set(dev, attr, &val);
+error:
+	swconfig_put_dev(dev);
+	return err;
+}
+
+static int
+swconfig_close_portlist(struct swconfig_callback *cb, void *arg)
+{
+	if (cb->nest[0])
+		nla_nest_end(cb->msg, cb->nest[0]);
+	return 0;
+}
+
+static int
+swconfig_send_port(struct swconfig_callback *cb, void *arg)
+{
+	const struct switch_port *port = arg;
+	struct nlattr *p = NULL;
+
+	if (!cb->nest[0]) {
+		cb->nest[0] = nla_nest_start(cb->msg, cb->cmd);
+		if (!cb->nest[0])
+			return -1;
+	}
+
+	p = nla_nest_start(cb->msg, SWITCH_ATTR_PORT);
+	if (!p)
+		goto error;
+
+	if (nla_put_u32(cb->msg, SWITCH_PORT_ID, port->id))
+		goto nla_put_failure;
+	if (port->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) {
+		if (nla_put_flag(cb->msg, SWITCH_PORT_FLAG_TAGGED))
+			goto nla_put_failure;
+	}
+
+	nla_nest_end(cb->msg, p);
+	return 0;
+
+nla_put_failure:
+		nla_nest_cancel(cb->msg, p);
+error:
+	nla_nest_cancel(cb->msg, cb->nest[0]);
+	return -1;
+}
+
+static int
+swconfig_send_ports(struct sk_buff **msg, struct genl_info *info, int attr,
+		const struct switch_val *val)
+{
+	struct swconfig_callback cb;
+	int err = 0;
+	int i;
+
+	if (!val->value.ports)
+		return -EINVAL;
+
+	memset(&cb, 0, sizeof(cb));
+	cb.cmd = attr;
+	cb.msg = *msg;
+	cb.info = info;
+	cb.fill = swconfig_send_port;
+	cb.close = swconfig_close_portlist;
+
+	cb.nest[0] = nla_nest_start(cb.msg, cb.cmd);
+	for (i = 0; i < val->len; i++) {
+		err = swconfig_send_multipart(&cb, &val->value.ports[i]);
+		if (err)
+			goto done;
+	}
+	err = val->len;
+	swconfig_close_portlist(&cb, NULL);
+	*msg = cb.msg;
+
+done:
+	return err;
+}
+
+static int
+swconfig_send_link(struct sk_buff *msg, struct genl_info *info, int attr,
+		   const struct switch_port_link *link)
+{
+	struct nlattr *p = NULL;
+	int err = 0;
+
+	p = nla_nest_start(msg, attr);
+	if (link->link) {
+		if (nla_put_flag(msg, SWITCH_LINK_FLAG_LINK))
+			goto nla_put_failure;
+	}
+	if (link->duplex) {
+		if (nla_put_flag(msg, SWITCH_LINK_FLAG_DUPLEX))
+			goto nla_put_failure;
+	}
+	if (link->aneg) {
+		if (nla_put_flag(msg, SWITCH_LINK_FLAG_ANEG))
+			goto nla_put_failure;
+	}
+	if (link->tx_flow) {
+		if (nla_put_flag(msg, SWITCH_LINK_FLAG_TX_FLOW))
+			goto nla_put_failure;
+	}
+	if (link->rx_flow) {
+		if (nla_put_flag(msg, SWITCH_LINK_FLAG_RX_FLOW))
+			goto nla_put_failure;
+	}
+	if (nla_put_u32(msg, SWITCH_LINK_SPEED, link->speed))
+		goto nla_put_failure;
+	if (link->eee & ADVERTISED_100baseT_Full) {
+		if (nla_put_flag(msg, SWITCH_LINK_FLAG_EEE_100BASET))
+			goto nla_put_failure;
+	}
+	if (link->eee & ADVERTISED_1000baseT_Full) {
+		if (nla_put_flag(msg, SWITCH_LINK_FLAG_EEE_1000BASET))
+			goto nla_put_failure;
+	}
+	nla_nest_end(msg, p);
+
+	return err;
+
+nla_put_failure:
+	nla_nest_cancel(msg, p);
+	return -1;
+}
+
+static int
+swconfig_get_attr(struct sk_buff *skb, struct genl_info *info)
+{
+	struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
+	const struct switch_attr *attr;
+	struct switch_dev *dev;
+	struct sk_buff *msg = NULL;
+	struct switch_val val;
+	int err = -EINVAL;
+	int cmd = hdr->cmd;
+
+	dev = swconfig_get_dev(info);
+	if (!dev)
+		return -EINVAL;
+
+	memset(&val, 0, sizeof(val));
+	attr = swconfig_lookup_attr(dev, info, &val);
+	if (!attr || !attr->get)
+		goto error;
+
+	if (attr->type == SWITCH_TYPE_PORTS) {
+		val.value.ports = dev->portbuf;
+		memset(dev->portbuf, 0,
+			sizeof(struct switch_port) * dev->ports);
+	} else if (attr->type == SWITCH_TYPE_LINK) {
+		val.value.link = &dev->linkbuf;
+		memset(&dev->linkbuf, 0, sizeof(struct switch_port_link));
+	}
+
+	err = attr->get(dev, attr, &val);
+	if (err)
+		goto error;
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg)
+		goto error;
+
+	hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &switch_fam,
+			0, cmd);
+	if (IS_ERR(hdr))
+		goto nla_put_failure;
+
+	switch (attr->type) {
+	case SWITCH_TYPE_INT:
+		if (nla_put_u32(msg, SWITCH_ATTR_OP_VALUE_INT, val.value.i))
+			goto nla_put_failure;
+		break;
+	case SWITCH_TYPE_STRING:
+		if (nla_put_string(msg, SWITCH_ATTR_OP_VALUE_STR, val.value.s))
+			goto nla_put_failure;
+		break;
+	case SWITCH_TYPE_PORTS:
+		err = swconfig_send_ports(&msg, info,
+				SWITCH_ATTR_OP_VALUE_PORTS, &val);
+		if (err < 0)
+			goto nla_put_failure;
+		break;
+	case SWITCH_TYPE_LINK:
+		err = swconfig_send_link(msg, info,
+					 SWITCH_ATTR_OP_VALUE_LINK, val.value.link);
+		if (err < 0)
+			goto nla_put_failure;
+		break;
+	default:
+		pr_debug("invalid type in attribute\n");
+		err = -EINVAL;
+		goto nla_put_failure;
+	}
+	genlmsg_end(msg, hdr);
+	err = msg->len;
+	if (err < 0)
+		goto nla_put_failure;
+
+	swconfig_put_dev(dev);
+	return genlmsg_reply(msg, info);
+
+nla_put_failure:
+	if (msg)
+		nlmsg_free(msg);
+error:
+	swconfig_put_dev(dev);
+	if (!err)
+		err = -ENOMEM;
+	return err;
+}
+
+static int
+swconfig_send_switch(struct sk_buff *msg, u32 pid, u32 seq, int flags,
+		const struct switch_dev *dev)
+{
+	struct nlattr *p = NULL, *m = NULL;
+	void *hdr;
+	int i;
+
+	hdr = genlmsg_put(msg, pid, seq, &switch_fam, flags,
+			SWITCH_CMD_NEW_ATTR);
+	if (IS_ERR(hdr))
+		return -1;
+
+	if (nla_put_u32(msg, SWITCH_ATTR_ID, dev->id))
+		goto nla_put_failure;
+	if (nla_put_string(msg, SWITCH_ATTR_DEV_NAME, dev->devname))
+		goto nla_put_failure;
+	if (nla_put_string(msg, SWITCH_ATTR_ALIAS, dev->alias))
+		goto nla_put_failure;
+	if (nla_put_string(msg, SWITCH_ATTR_NAME, dev->name))
+		goto nla_put_failure;
+	if (nla_put_u32(msg, SWITCH_ATTR_VLANS, dev->vlans))
+		goto nla_put_failure;
+	if (nla_put_u32(msg, SWITCH_ATTR_PORTS, dev->ports))
+		goto nla_put_failure;
+	if (nla_put_u32(msg, SWITCH_ATTR_CPU_PORT, dev->cpu_port))
+		goto nla_put_failure;
+
+	m = nla_nest_start(msg, SWITCH_ATTR_PORTMAP);
+	if (!m)
+		goto nla_put_failure;
+	for (i = 0; i < dev->ports; i++) {
+		p = nla_nest_start(msg, SWITCH_ATTR_PORTS);
+		if (!p)
+			continue;
+		if (dev->portmap[i].s) {
+			if (nla_put_string(msg, SWITCH_PORTMAP_SEGMENT,
+						dev->portmap[i].s))
+				goto nla_put_failure;
+			if (nla_put_u32(msg, SWITCH_PORTMAP_VIRT,
+						dev->portmap[i].virt))
+				goto nla_put_failure;
+		}
+		nla_nest_end(msg, p);
+	}
+	nla_nest_end(msg, m);
+	genlmsg_end(msg, hdr);
+	return msg->len;
+nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	return -EMSGSIZE;
+}
+
+static int swconfig_dump_switches(struct sk_buff *skb,
+		struct netlink_callback *cb)
+{
+	struct switch_dev *dev;
+	int start = cb->args[0];
+	int idx = 0;
+
+	swconfig_lock();
+	list_for_each_entry(dev, &swdevs, dev_list) {
+		if (++idx <= start)
+			continue;
+		if (swconfig_send_switch(skb, NETLINK_CB(cb->skb).portid,
+				cb->nlh->nlmsg_seq, NLM_F_MULTI,
+				dev) < 0)
+			break;
+	}
+	swconfig_unlock();
+	cb->args[0] = idx;
+
+	return skb->len;
+}
+
+static int
+swconfig_done(struct netlink_callback *cb)
+{
+	return 0;
+}
+
+static struct genl_ops swconfig_ops[] = {
+	{
+		.cmd = SWITCH_CMD_LIST_GLOBAL,
+		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.doit = swconfig_list_attrs,
+	},
+	{
+		.cmd = SWITCH_CMD_LIST_VLAN,
+		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.doit = swconfig_list_attrs,
+	},
+	{
+		.cmd = SWITCH_CMD_LIST_PORT,
+		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.doit = swconfig_list_attrs,
+	},
+	{
+		.cmd = SWITCH_CMD_GET_GLOBAL,
+		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.doit = swconfig_get_attr,
+	},
+	{
+		.cmd = SWITCH_CMD_GET_VLAN,
+		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.doit = swconfig_get_attr,
+	},
+	{
+		.cmd = SWITCH_CMD_GET_PORT,
+		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.doit = swconfig_get_attr,
+	},
+	{
+		.cmd = SWITCH_CMD_SET_GLOBAL,
+		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags = GENL_ADMIN_PERM,
+		.doit = swconfig_set_attr,
+	},
+	{
+		.cmd = SWITCH_CMD_SET_VLAN,
+		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags = GENL_ADMIN_PERM,
+		.doit = swconfig_set_attr,
+	},
+	{
+		.cmd = SWITCH_CMD_SET_PORT,
+		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags = GENL_ADMIN_PERM,
+		.doit = swconfig_set_attr,
+	},
+	{
+		.cmd = SWITCH_CMD_GET_SWITCH,
+		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.dumpit = swconfig_dump_switches,
+		.done = swconfig_done,
+	}
+};
+
+static struct genl_family switch_fam = {
+	.name = "switch",
+	.hdrsize = 0,
+	.version = 1,
+	.maxattr = SWITCH_ATTR_MAX,
+	.policy = switch_policy,
+	.module = THIS_MODULE,
+	.ops = swconfig_ops,
+	.n_ops = ARRAY_SIZE(swconfig_ops),
+};
+
+#ifdef CONFIG_OF
+void
+of_switch_load_portmap(struct switch_dev *dev)
+{
+	struct device_node *port;
+
+	if (!dev->of_node)
+		return;
+
+	for_each_child_of_node(dev->of_node, port) {
+		const __be32 *prop;
+		const char *segment;
+		int size, phys;
+
+		if (!of_device_is_compatible(port, "swconfig,port"))
+			continue;
+
+		if (of_property_read_string(port, "swconfig,segment", &segment))
+			continue;
+
+		prop = of_get_property(port, "swconfig,portmap", &size);
+		if (!prop)
+			continue;
+
+		if (size != (2 * sizeof(*prop))) {
+			pr_err("%s: failed to parse port mapping\n",
+					port->name);
+			continue;
+		}
+
+		phys = be32_to_cpup(prop++);
+		if ((phys < 0) | (phys >= dev->ports)) {
+			pr_err("%s: physical port index out of range\n",
+					port->name);
+			continue;
+		}
+
+		dev->portmap[phys].s = kstrdup(segment, GFP_KERNEL);
+		dev->portmap[phys].virt = be32_to_cpup(prop);
+		pr_debug("Found port: %s, physical: %d, virtual: %d\n",
+			segment, phys, dev->portmap[phys].virt);
+	}
+}
+#endif
+
+int
+register_switch(struct switch_dev *dev, struct net_device *netdev)
+{
+	struct switch_dev *sdev;
+	const int max_switches = 8 * sizeof(unsigned long);
+	unsigned long in_use = 0;
+	int err;
+	int i;
+
+	INIT_LIST_HEAD(&dev->dev_list);
+	if (netdev) {
+		dev->netdev = netdev;
+		if (!dev->alias)
+			dev->alias = netdev->name;
+	}
+	BUG_ON(!dev->alias);
+
+	/* Make sure swdev_id doesn't overflow */
+	if (swdev_id == INT_MAX) {
+		return -ENOMEM;
+	}
+
+	if (dev->ports > 0) {
+		dev->portbuf = kzalloc(sizeof(struct switch_port) *
+				dev->ports, GFP_KERNEL);
+		if (!dev->portbuf)
+			return -ENOMEM;
+		dev->portmap = kzalloc(sizeof(struct switch_portmap) *
+				dev->ports, GFP_KERNEL);
+		if (!dev->portmap) {
+			kfree(dev->portbuf);
+			return -ENOMEM;
+		}
+	}
+	swconfig_defaults_init(dev);
+	mutex_init(&dev->sw_mutex);
+	swconfig_lock();
+	dev->id = ++swdev_id;
+
+	list_for_each_entry(sdev, &swdevs, dev_list) {
+		if (!sscanf(sdev->devname, SWCONFIG_DEVNAME, &i))
+			continue;
+		if (i < 0 || i > max_switches)
+			continue;
+
+		set_bit(i, &in_use);
+	}
+	i = find_first_zero_bit(&in_use, max_switches);
+
+	if (i == max_switches) {
+		swconfig_unlock();
+		return -ENFILE;
+	}
+
+#ifdef CONFIG_OF
+	if (dev->ports)
+		of_switch_load_portmap(dev);
+#endif
+
+	/* fill device name */
+	snprintf(dev->devname, IFNAMSIZ, SWCONFIG_DEVNAME, i);
+
+	list_add_tail(&dev->dev_list, &swdevs);
+	swconfig_unlock();
+
+	err = swconfig_create_led_trigger(dev);
+	if (err)
+		return err;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(register_switch);
+
+void
+unregister_switch(struct switch_dev *dev)
+{
+	swconfig_destroy_led_trigger(dev);
+	kfree(dev->portbuf);
+	mutex_lock(&dev->sw_mutex);
+	swconfig_lock();
+	list_del(&dev->dev_list);
+	swconfig_unlock();
+	mutex_unlock(&dev->sw_mutex);
+}
+EXPORT_SYMBOL_GPL(unregister_switch);
+
+int
+switch_generic_set_link(struct switch_dev *dev, int port,
+			struct switch_port_link *link)
+{
+	if (WARN_ON(!dev->ops->phy_write16))
+		return -ENOTSUPP;
+
+	/* Generic implementation */
+	if (link->aneg) {
+		dev->ops->phy_write16(dev, port, MII_BMCR, 0x0000);
+		dev->ops->phy_write16(dev, port, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
+	} else {
+		u16 bmcr = 0;
+
+		if (link->duplex)
+			bmcr |= BMCR_FULLDPLX;
+
+		switch (link->speed) {
+		case SWITCH_PORT_SPEED_10:
+			break;
+		case SWITCH_PORT_SPEED_100:
+			bmcr |= BMCR_SPEED100;
+			break;
+		case SWITCH_PORT_SPEED_1000:
+			bmcr |= BMCR_SPEED1000;
+			break;
+		default:
+			return -ENOTSUPP;
+		}
+
+		dev->ops->phy_write16(dev, port, MII_BMCR, bmcr);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(switch_generic_set_link);
+
+static int __init
+swconfig_init(void)
+{
+	INIT_LIST_HEAD(&swdevs);
+
+	return genl_register_family(&switch_fam);
+}
+
+static void __exit
+swconfig_exit(void)
+{
+	genl_unregister_family(&switch_fam);
+}
+
+module_init(swconfig_init);
+module_exit(swconfig_exit);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/swconfig_leds.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/swconfig_leds.c
new file mode 100644
index 0000000..df53e5c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/net/phy/swconfig_leds.c
@@ -0,0 +1,555 @@
+/*
+ * swconfig_led.c: LED trigger support for the switch configuration API
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ */
+
+#ifdef CONFIG_SWCONFIG_LEDS
+
+#include <linux/leds.h>
+#include <linux/ctype.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+
+#define SWCONFIG_LED_TIMER_INTERVAL	(HZ / 10)
+#define SWCONFIG_LED_NUM_PORTS		32
+
+#define SWCONFIG_LED_PORT_SPEED_NA	0x01	/* unknown speed */
+#define SWCONFIG_LED_PORT_SPEED_10	0x02	/* 10 Mbps */
+#define SWCONFIG_LED_PORT_SPEED_100	0x04	/* 100 Mbps */
+#define SWCONFIG_LED_PORT_SPEED_1000	0x08	/* 1000 Mbps */
+#define SWCONFIG_LED_PORT_SPEED_ALL	(SWCONFIG_LED_PORT_SPEED_NA | \
+					 SWCONFIG_LED_PORT_SPEED_10 | \
+					 SWCONFIG_LED_PORT_SPEED_100 | \
+					 SWCONFIG_LED_PORT_SPEED_1000)
+
+#define SWCONFIG_LED_MODE_LINK		0x01
+#define SWCONFIG_LED_MODE_TX		0x02
+#define SWCONFIG_LED_MODE_RX		0x04
+#define SWCONFIG_LED_MODE_TXRX		(SWCONFIG_LED_MODE_TX   | \
+					 SWCONFIG_LED_MODE_RX)
+#define SWCONFIG_LED_MODE_ALL		(SWCONFIG_LED_MODE_LINK | \
+					 SWCONFIG_LED_MODE_TX   | \
+					 SWCONFIG_LED_MODE_RX)
+
+struct switch_led_trigger {
+	struct led_trigger trig;
+	struct switch_dev *swdev;
+
+	struct delayed_work sw_led_work;
+	u32 port_mask;
+	u32 port_link;
+	unsigned long long port_tx_traffic[SWCONFIG_LED_NUM_PORTS];
+	unsigned long long port_rx_traffic[SWCONFIG_LED_NUM_PORTS];
+	u8 link_speed[SWCONFIG_LED_NUM_PORTS];
+};
+
+struct swconfig_trig_data {
+	struct led_classdev *led_cdev;
+	struct switch_dev *swdev;
+
+	rwlock_t lock;
+	u32 port_mask;
+
+	bool prev_link;
+	unsigned long prev_traffic;
+	enum led_brightness prev_brightness;
+	u8 mode;
+	u8 speed_mask;
+};
+
+static void
+swconfig_trig_set_brightness(struct swconfig_trig_data *trig_data,
+			     enum led_brightness brightness)
+{
+	led_set_brightness(trig_data->led_cdev, brightness);
+	trig_data->prev_brightness = brightness;
+}
+
+static void
+swconfig_trig_update_port_mask(struct led_trigger *trigger)
+{
+	struct list_head *entry;
+	struct switch_led_trigger *sw_trig;
+	u32 port_mask;
+
+	if (!trigger)
+		return;
+
+	sw_trig = (void *) trigger;
+
+	port_mask = 0;
+	read_lock(&trigger->leddev_list_lock);
+	list_for_each(entry, &trigger->led_cdevs) {
+		struct led_classdev *led_cdev;
+		struct swconfig_trig_data *trig_data;
+
+		led_cdev = list_entry(entry, struct led_classdev, trig_list);
+		trig_data = led_cdev->trigger_data;
+		if (trig_data) {
+			read_lock(&trig_data->lock);
+			port_mask |= trig_data->port_mask;
+			read_unlock(&trig_data->lock);
+		}
+	}
+	read_unlock(&trigger->leddev_list_lock);
+
+	sw_trig->port_mask = port_mask;
+
+	if (port_mask)
+		schedule_delayed_work(&sw_trig->sw_led_work,
+				      SWCONFIG_LED_TIMER_INTERVAL);
+	else
+		cancel_delayed_work_sync(&sw_trig->sw_led_work);
+}
+
+static ssize_t
+swconfig_trig_port_mask_store(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t size)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
+	unsigned long port_mask;
+	int ret;
+	bool changed;
+
+	ret = kstrtoul(buf, 0, &port_mask);
+	if (ret)
+		return ret;
+
+	write_lock(&trig_data->lock);
+	changed = (trig_data->port_mask != port_mask);
+	trig_data->port_mask = port_mask;
+	write_unlock(&trig_data->lock);
+
+	if (changed) {
+		if (port_mask == 0)
+			swconfig_trig_set_brightness(trig_data, LED_OFF);
+
+		swconfig_trig_update_port_mask(led_cdev->trigger);
+	}
+
+	return size;
+}
+
+static ssize_t
+swconfig_trig_port_mask_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
+	u32 port_mask;
+
+	read_lock(&trig_data->lock);
+	port_mask = trig_data->port_mask;
+	read_unlock(&trig_data->lock);
+
+	sprintf(buf, "%#x\n", port_mask);
+
+	return strlen(buf) + 1;
+}
+
+static DEVICE_ATTR(port_mask, 0644, swconfig_trig_port_mask_show,
+		   swconfig_trig_port_mask_store);
+
+/* speed_mask file handler - display value */
+static ssize_t swconfig_trig_speed_mask_show(struct device *dev,
+					     struct device_attribute *attr,
+					     char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
+	u8 speed_mask;
+
+	read_lock(&trig_data->lock);
+	speed_mask = trig_data->speed_mask;
+	read_unlock(&trig_data->lock);
+
+	sprintf(buf, "%#x\n", speed_mask);
+
+	return strlen(buf) + 1;
+}
+
+/* speed_mask file handler - store value */
+static ssize_t swconfig_trig_speed_mask_store(struct device *dev,
+					      struct device_attribute *attr,
+					      const char *buf, size_t size)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
+	u8 speed_mask;
+	int ret;
+
+	ret = kstrtou8(buf, 0, &speed_mask);
+	if (ret)
+		return ret;
+
+	write_lock(&trig_data->lock);
+	trig_data->speed_mask = speed_mask & SWCONFIG_LED_PORT_SPEED_ALL;
+	write_unlock(&trig_data->lock);
+
+	return size;
+}
+
+/* speed_mask special file */
+static DEVICE_ATTR(speed_mask, 0644, swconfig_trig_speed_mask_show,
+		   swconfig_trig_speed_mask_store);
+
+static ssize_t swconfig_trig_mode_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
+	u8 mode;
+
+	read_lock(&trig_data->lock);
+	mode = trig_data->mode;
+	read_unlock(&trig_data->lock);
+
+	if (mode == 0) {
+		strcpy(buf, "none\n");
+	} else {
+		if (mode & SWCONFIG_LED_MODE_LINK)
+			strcat(buf, "link ");
+		if (mode & SWCONFIG_LED_MODE_TX)
+			strcat(buf, "tx ");
+		if (mode & SWCONFIG_LED_MODE_RX)
+			strcat(buf, "rx ");
+		strcat(buf, "\n");
+	}
+
+	return strlen(buf)+1;
+}
+
+static ssize_t swconfig_trig_mode_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
+	char copybuf[128];
+	int new_mode = -1;
+	char *p, *token;
+
+	/* take a copy since we don't want to trash the inbound buffer when using strsep */
+	strncpy(copybuf, buf, sizeof(copybuf));
+	copybuf[sizeof(copybuf) - 1] = 0;
+	p = copybuf;
+
+	while ((token = strsep(&p, " \t\n")) != NULL) {
+		if (!*token)
+			continue;
+
+		if (new_mode < 0)
+			new_mode = 0;
+
+		if (!strcmp(token, "none"))
+			new_mode = 0;
+		else if (!strcmp(token, "tx"))
+			new_mode |= SWCONFIG_LED_MODE_TX;
+		else if (!strcmp(token, "rx"))
+			new_mode |= SWCONFIG_LED_MODE_RX;
+		else if (!strcmp(token, "link"))
+			new_mode |= SWCONFIG_LED_MODE_LINK;
+		else
+			return -EINVAL;
+	}
+
+	if (new_mode < 0)
+		return -EINVAL;
+
+	write_lock(&trig_data->lock);
+	trig_data->mode = (u8)new_mode;
+	write_unlock(&trig_data->lock);
+
+	return size;
+}
+
+/* mode special file */
+static DEVICE_ATTR(mode, 0644, swconfig_trig_mode_show,
+		   swconfig_trig_mode_store);
+
+static int
+swconfig_trig_activate(struct led_classdev *led_cdev)
+{
+	struct switch_led_trigger *sw_trig;
+	struct swconfig_trig_data *trig_data;
+	int err;
+
+	trig_data = kzalloc(sizeof(struct swconfig_trig_data), GFP_KERNEL);
+	if (!trig_data)
+		return -ENOMEM;
+
+	sw_trig = (void *) led_cdev->trigger;
+
+	rwlock_init(&trig_data->lock);
+	trig_data->led_cdev = led_cdev;
+	trig_data->swdev = sw_trig->swdev;
+	trig_data->speed_mask = SWCONFIG_LED_PORT_SPEED_ALL;
+	trig_data->mode = SWCONFIG_LED_MODE_ALL;
+	led_cdev->trigger_data = trig_data;
+
+	err = device_create_file(led_cdev->dev, &dev_attr_port_mask);
+	if (err)
+		goto err_free;
+
+	err = device_create_file(led_cdev->dev, &dev_attr_speed_mask);
+	if (err)
+		goto err_dev_free;
+
+	err = device_create_file(led_cdev->dev, &dev_attr_mode);
+	if (err)
+		goto err_mode_free;
+
+	return 0;
+
+err_mode_free:
+	device_remove_file(led_cdev->dev, &dev_attr_speed_mask);
+
+err_dev_free:
+	device_remove_file(led_cdev->dev, &dev_attr_port_mask);
+
+err_free:
+	led_cdev->trigger_data = NULL;
+	kfree(trig_data);
+
+	return err;
+}
+
+static void
+swconfig_trig_deactivate(struct led_classdev *led_cdev)
+{
+	struct swconfig_trig_data *trig_data;
+
+	swconfig_trig_update_port_mask(led_cdev->trigger);
+
+	trig_data = (void *) led_cdev->trigger_data;
+	if (trig_data) {
+		device_remove_file(led_cdev->dev, &dev_attr_port_mask);
+		device_remove_file(led_cdev->dev, &dev_attr_speed_mask);
+		device_remove_file(led_cdev->dev, &dev_attr_mode);
+		kfree(trig_data);
+	}
+}
+
+/*
+ * link off -> led off (can't be any other reason to turn it on)
+ * link on:
+ *	mode link: led on by default only if speed matches, else off
+ *	mode txrx: blink only if speed matches, else off
+ */
+static void
+swconfig_trig_led_event(struct switch_led_trigger *sw_trig,
+			struct led_classdev *led_cdev)
+{
+	struct swconfig_trig_data *trig_data;
+	u32 port_mask;
+	bool link;
+	u8 speed_mask, mode;
+	enum led_brightness led_base, led_blink;
+
+	trig_data = led_cdev->trigger_data;
+	if (!trig_data)
+		return;
+
+	read_lock(&trig_data->lock);
+	port_mask = trig_data->port_mask;
+	speed_mask = trig_data->speed_mask;
+	mode = trig_data->mode;
+	read_unlock(&trig_data->lock);
+
+	link = !!(sw_trig->port_link & port_mask);
+	if (!link) {
+		if (trig_data->prev_brightness != LED_OFF)
+			swconfig_trig_set_brightness(trig_data, LED_OFF); /* and stop */
+	}
+	else {
+		unsigned long traffic;
+		int speedok;	/* link speed flag */
+		int i;
+
+		led_base = LED_FULL;
+		led_blink = LED_OFF;
+		traffic = 0;
+		speedok = 0;
+		for (i = 0; i < SWCONFIG_LED_NUM_PORTS; i++) {
+			if (port_mask & (1 << i)) {
+				if (sw_trig->link_speed[i] & speed_mask) {
+					traffic += ((mode & SWCONFIG_LED_MODE_TX) ?
+						    sw_trig->port_tx_traffic[i] : 0) +
+						((mode & SWCONFIG_LED_MODE_RX) ?
+						 sw_trig->port_rx_traffic[i] : 0);
+					speedok = 1;
+				}
+			}
+		}
+
+		if (speedok) {
+			/* At least one port speed matches speed_mask */
+			if (!(mode & SWCONFIG_LED_MODE_LINK)) {
+				led_base = LED_OFF;
+				led_blink = LED_FULL;
+			}
+
+			if (trig_data->prev_brightness != led_base)
+				swconfig_trig_set_brightness(trig_data,
+							     led_base);
+			else if (traffic != trig_data->prev_traffic)
+				swconfig_trig_set_brightness(trig_data,
+							     led_blink);
+		} else if (trig_data->prev_brightness != LED_OFF)
+			swconfig_trig_set_brightness(trig_data, LED_OFF);
+
+		trig_data->prev_traffic = traffic;
+	}
+
+	trig_data->prev_link = link;
+}
+
+static void
+swconfig_trig_update_leds(struct switch_led_trigger *sw_trig)
+{
+	struct list_head *entry;
+	struct led_trigger *trigger;
+
+	trigger = &sw_trig->trig;
+	read_lock(&trigger->leddev_list_lock);
+	list_for_each(entry, &trigger->led_cdevs) {
+		struct led_classdev *led_cdev;
+
+		led_cdev = list_entry(entry, struct led_classdev, trig_list);
+		swconfig_trig_led_event(sw_trig, led_cdev);
+	}
+	read_unlock(&trigger->leddev_list_lock);
+}
+
+static void
+swconfig_led_work_func(struct work_struct *work)
+{
+	struct switch_led_trigger *sw_trig;
+	struct switch_dev *swdev;
+	u32 port_mask;
+	u32 link;
+	int i;
+
+	sw_trig = container_of(work, struct switch_led_trigger,
+			       sw_led_work.work);
+
+	port_mask = sw_trig->port_mask;
+	swdev = sw_trig->swdev;
+
+	link = 0;
+	for (i = 0; i < SWCONFIG_LED_NUM_PORTS; i++) {
+		u32 port_bit;
+
+		sw_trig->link_speed[i] = 0;
+
+		port_bit = BIT(i);
+		if ((port_mask & port_bit) == 0)
+			continue;
+
+		if (swdev->ops->get_port_link) {
+			struct switch_port_link port_link;
+
+			memset(&port_link, '\0', sizeof(port_link));
+			swdev->ops->get_port_link(swdev, i, &port_link);
+
+			if (port_link.link) {
+				link |= port_bit;
+				switch (port_link.speed) {
+				case SWITCH_PORT_SPEED_UNKNOWN:
+					sw_trig->link_speed[i] =
+						SWCONFIG_LED_PORT_SPEED_NA;
+					break;
+				case SWITCH_PORT_SPEED_10:
+					sw_trig->link_speed[i] =
+						SWCONFIG_LED_PORT_SPEED_10;
+					break;
+				case SWITCH_PORT_SPEED_100:
+					sw_trig->link_speed[i] =
+						SWCONFIG_LED_PORT_SPEED_100;
+					break;
+				case SWITCH_PORT_SPEED_1000:
+					sw_trig->link_speed[i] =
+						SWCONFIG_LED_PORT_SPEED_1000;
+					break;
+				}
+			}
+		}
+
+		if (swdev->ops->get_port_stats) {
+			struct switch_port_stats port_stats;
+
+			memset(&port_stats, '\0', sizeof(port_stats));
+			swdev->ops->get_port_stats(swdev, i, &port_stats);
+			sw_trig->port_tx_traffic[i] = port_stats.tx_bytes;
+			sw_trig->port_rx_traffic[i] = port_stats.rx_bytes;
+		}
+	}
+
+	sw_trig->port_link = link;
+
+	swconfig_trig_update_leds(sw_trig);
+
+	schedule_delayed_work(&sw_trig->sw_led_work,
+			      SWCONFIG_LED_TIMER_INTERVAL);
+}
+
+static int
+swconfig_create_led_trigger(struct switch_dev *swdev)
+{
+	struct switch_led_trigger *sw_trig;
+	int err;
+
+	if (!swdev->ops->get_port_link)
+		return 0;
+
+	sw_trig = kzalloc(sizeof(struct switch_led_trigger), GFP_KERNEL);
+	if (!sw_trig)
+		return -ENOMEM;
+
+	sw_trig->swdev = swdev;
+	sw_trig->trig.name = swdev->devname;
+	sw_trig->trig.activate = swconfig_trig_activate;
+	sw_trig->trig.deactivate = swconfig_trig_deactivate;
+
+	INIT_DELAYED_WORK(&sw_trig->sw_led_work, swconfig_led_work_func);
+
+	err = led_trigger_register(&sw_trig->trig);
+	if (err)
+		goto err_free;
+
+	swdev->led_trigger = sw_trig;
+
+	return 0;
+
+err_free:
+	kfree(sw_trig);
+	return err;
+}
+
+static void
+swconfig_destroy_led_trigger(struct switch_dev *swdev)
+{
+	struct switch_led_trigger *sw_trig;
+
+	sw_trig = swdev->led_trigger;
+	if (sw_trig) {
+		cancel_delayed_work_sync(&sw_trig->sw_led_work);
+		led_trigger_unregister(&sw_trig->trig);
+		kfree(sw_trig);
+	}
+}
+
+#else /* SWCONFIG_LEDS */
+static inline int
+swconfig_create_led_trigger(struct switch_dev *swdev) { return 0; }
+
+static inline void
+swconfig_destroy_led_trigger(struct switch_dev *swdev) { }
+#endif /* CONFIG_SWCONFIG_LEDS */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/platform/mikrotik/Kconfig b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/platform/mikrotik/Kconfig
new file mode 100644
index 0000000..7499ba1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/platform/mikrotik/Kconfig
@@ -0,0 +1,19 @@
+menuconfig MIKROTIK
+	bool "Platform support for MikroTik RouterBoard virtual devices"
+	default n
+	help
+	  Say Y here to get to see options for the MikroTik RouterBoard platform.
+	  This option alone does not add any kernel code.
+
+
+if MIKROTIK
+
+config MIKROTIK_RB_SYSFS
+	tristate "RouterBoot sysfs support"
+	depends on MTD
+	select LZO_DECOMPRESS
+	select CRC32
+	help
+	  This driver exposes RouterBoot configuration in sysfs.
+
+endif # MIKROTIK
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/platform/mikrotik/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/platform/mikrotik/Makefile
new file mode 100644
index 0000000..a232e1a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/platform/mikrotik/Makefile
@@ -0,0 +1,4 @@
+#
+# Makefile for MikroTik RouterBoard platform specific drivers
+#
+obj-$(CONFIG_MIKROTIK_RB_SYSFS)     += routerboot.o rb_hardconfig.o rb_softconfig.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/platform/mikrotik/rb_hardconfig.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/platform/mikrotik/rb_hardconfig.c
new file mode 100644
index 0000000..e6a6928
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/platform/mikrotik/rb_hardconfig.c
@@ -0,0 +1,825 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for MikroTik RouterBoot hard config.
+ *
+ * Copyright (C) 2020 Thibaut VARÈNE <hacks+kernel@slashdirt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This driver exposes the data encoded in the "hard_config" flash segment of
+ * MikroTik RouterBOARDs devices. It presents the data in a sysfs folder
+ * named "hard_config". The WLAN calibration data is available on demand via
+ * the 'wlan_data' sysfs file in that folder.
+ *
+ * This driver permanently allocates a chunk of RAM as large as the hard_config
+ * MTD partition, although it is technically possible to operate entirely from
+ * the MTD device without using a local buffer (except when requesting WLAN
+ * calibration data), at the cost of a performance penalty.
+ *
+ * Note: PAGE_SIZE is assumed to be >= 4K, hence the device attribute show
+ * routines need not check for output overflow.
+ *
+ * Some constant defines extracted from routerboot.{c,h} by Gabor Juhos
+ * <juhosg@openwrt.org>
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/kobject.h>
+#include <linux/bitops.h>
+#include <linux/string.h>
+#include <linux/mtd/mtd.h>
+#include <linux/sysfs.h>
+#include <linux/lzo.h>
+
+#include "routerboot.h"
+
+#define RB_HARDCONFIG_VER		"0.06"
+#define RB_HC_PR_PFX			"[rb_hardconfig] "
+
+/* ID values for hardware settings */
+#define RB_ID_FLASH_INFO		0x03
+#define RB_ID_MAC_ADDRESS_PACK		0x04
+#define RB_ID_BOARD_PRODUCT_CODE	0x05
+#define RB_ID_BIOS_VERSION		0x06
+#define RB_ID_SDRAM_TIMINGS		0x08
+#define RB_ID_DEVICE_TIMINGS		0x09
+#define RB_ID_SOFTWARE_ID		0x0A
+#define RB_ID_SERIAL_NUMBER		0x0B
+#define RB_ID_MEMORY_SIZE		0x0D
+#define RB_ID_MAC_ADDRESS_COUNT		0x0E
+#define RB_ID_HW_OPTIONS		0x15
+#define RB_ID_WLAN_DATA			0x16
+#define RB_ID_BOARD_IDENTIFIER		0x17
+#define RB_ID_PRODUCT_NAME		0x21
+#define RB_ID_DEFCONF			0x26
+#define RB_ID_BOARD_REVISION		0x27
+
+/* Bit definitions for hardware options */
+#define RB_HW_OPT_NO_UART		BIT(0)
+#define RB_HW_OPT_HAS_VOLTAGE		BIT(1)
+#define RB_HW_OPT_HAS_USB		BIT(2)
+#define RB_HW_OPT_HAS_ATTINY		BIT(3)
+#define RB_HW_OPT_PULSE_DUTY_CYCLE	BIT(9)
+#define RB_HW_OPT_NO_NAND		BIT(14)
+#define RB_HW_OPT_HAS_LCD		BIT(15)
+#define RB_HW_OPT_HAS_POE_OUT		BIT(16)
+#define RB_HW_OPT_HAS_uSD		BIT(17)
+#define RB_HW_OPT_HAS_SIM		BIT(18)
+#define RB_HW_OPT_HAS_SFP		BIT(20)
+#define RB_HW_OPT_HAS_WIFI		BIT(21)
+#define RB_HW_OPT_HAS_TS_FOR_ADC	BIT(22)
+#define RB_HW_OPT_HAS_PLC		BIT(29)
+
+/*
+ * Tag ID values for ERD data.
+ * Mikrotik used to pack all calibration data under a single tag id 0x1, but
+ * recently switched to a new scheme where each radio calibration gets a
+ * separate tag. The new scheme has tag id bit 15 always set and seems to be
+ * mutually exclusive with the old scheme.
+ */
+#define RB_WLAN_ERD_ID_SOLO		0x0001
+#define RB_WLAN_ERD_ID_MULTI_8001	0x8001
+#define RB_WLAN_ERD_ID_MULTI_8201	0x8201
+
+static struct kobject *hc_kobj;
+static u8 *hc_buf;		// ro buffer after init(): no locking required
+static size_t hc_buflen;
+
+/*
+ * For LZOR style WLAN data unpacking.
+ * This binary blob is prepended to the data encoded on some devices as
+ * RB_ID_WLAN_DATA, the result is then first decompressed with LZO, and then
+ * finally RLE-decoded.
+ * This binary blob has been extracted from RouterOS by
+ * https://forum.openwrt.org/u/ius
+ */
+static const u8 hc_lzor_prefix[] = {
+	0x00, 0x05, 0x4c, 0x4c, 0x44, 0x00, 0x34, 0xfe,
+	0xfe, 0x34, 0x11, 0x3c, 0x1e, 0x3c, 0x2e, 0x3c,
+	0x4c, 0x34, 0x00, 0x52, 0x62, 0x92, 0xa2, 0xb2,
+	0xc3, 0x2a, 0x14, 0x00, 0x00, 0x05, 0xfe, 0x6a,
+	0x3c, 0x16, 0x32, 0x16, 0x11, 0x1e, 0x12, 0x46,
+	0x32, 0x46, 0x11, 0x4e, 0x12, 0x36, 0x32, 0x36,
+	0x11, 0x3e, 0x12, 0x5a, 0x9a, 0x64, 0x00, 0x04,
+	0xfe, 0x10, 0x3c, 0x00, 0x01, 0x00, 0x00, 0x28,
+	0x0c, 0x00, 0x0f, 0xfe, 0x14, 0x00, 0x24, 0x24,
+	0x23, 0x24, 0x24, 0x23, 0x25, 0x22, 0x21, 0x21,
+	0x23, 0x22, 0x21, 0x22, 0x21, 0x2d, 0x38, 0x00,
+	0x0c, 0x25, 0x25, 0x24, 0x25, 0x25, 0x24, 0x23,
+	0x22, 0x21, 0x20, 0x23, 0x21, 0x21, 0x22, 0x21,
+	0x2d, 0x38, 0x00, 0x28, 0xb0, 0x00, 0x00, 0x22,
+	0x00, 0x00, 0xc0, 0xfe, 0x03, 0x00, 0xc0, 0x00,
+	0x62, 0xff, 0x62, 0xff, 0xfe, 0x06, 0x00, 0xbb,
+	0xff, 0xba, 0xff, 0xfe, 0x08, 0x00, 0x9e, 0xff,
+	0xfe, 0x0a, 0x00, 0x53, 0xff, 0xfe, 0x02, 0x00,
+	0x20, 0xff, 0xb1, 0xfe, 0xfe, 0xb2, 0xfe, 0xfe,
+	0xed, 0xfe, 0xfe, 0xfe, 0x04, 0x00, 0x3a, 0xff,
+	0x3a, 0xff, 0xde, 0xfd, 0x5f, 0x04, 0x33, 0xff,
+	0x4c, 0x74, 0x03, 0x05, 0x05, 0xff, 0x6d, 0xfe,
+	0xfe, 0x6d, 0xfe, 0xfe, 0xaf, 0x08, 0x63, 0xff,
+	0x64, 0x6f, 0x08, 0xac, 0xff, 0xbf, 0x6d, 0x08,
+	0x7a, 0x6d, 0x08, 0x96, 0x74, 0x04, 0x00, 0x08,
+	0x79, 0xff, 0xda, 0xfe, 0xfe, 0xdb, 0xfe, 0xfe,
+	0x56, 0xff, 0xfe, 0x04, 0x00, 0x5e, 0xff, 0x5e,
+	0xff, 0x6c, 0xfe, 0xfe, 0xfe, 0x06, 0x00, 0x41,
+	0xff, 0x7f, 0x74, 0x03, 0x00, 0x11, 0x44, 0xff,
+	0xa9, 0xfe, 0xfe, 0xa9, 0xfe, 0xfe, 0xa5, 0x8f,
+	0x01, 0x00, 0x08, 0x01, 0x01, 0x02, 0x04, 0x08,
+	0x02, 0x04, 0x08, 0x08, 0x01, 0x01, 0xfe, 0x22,
+	0x00, 0x4c, 0x60, 0x64, 0x8c, 0x90, 0xd0, 0xd4,
+	0xd8, 0x5c, 0x10, 0x09, 0xd8, 0xff, 0xb0, 0xff,
+	0x00, 0x00, 0xba, 0xff, 0x14, 0x00, 0xba, 0xff,
+	0x64, 0x00, 0x00, 0x08, 0xfe, 0x06, 0x00, 0x74,
+	0xff, 0x42, 0xff, 0xce, 0xff, 0x60, 0xff, 0x0a,
+	0x00, 0xb4, 0x00, 0xa0, 0x00, 0xa0, 0xfe, 0x07,
+	0x00, 0x0a, 0x00, 0xb0, 0xff, 0x96, 0x4d, 0x00,
+	0x56, 0x57, 0x18, 0xa6, 0xff, 0x92, 0x70, 0x11,
+	0x00, 0x12, 0x90, 0x90, 0x76, 0x5a, 0x54, 0x54,
+	0x4c, 0x46, 0x38, 0x00, 0x10, 0x10, 0x08, 0xfe,
+	0x05, 0x00, 0x38, 0x29, 0x25, 0x23, 0x22, 0x22,
+	0x1f, 0x00, 0x00, 0x00, 0xf6, 0xe1, 0xdd, 0xf8,
+	0xfe, 0x00, 0xfe, 0x15, 0x00, 0x00, 0xd0, 0x02,
+	0x74, 0x02, 0x08, 0xf8, 0xe5, 0xde, 0x02, 0x04,
+	0x04, 0xfd, 0x00, 0x00, 0x00, 0x07, 0x50, 0x2d,
+	0x01, 0x90, 0x90, 0x76, 0x60, 0xb0, 0x07, 0x07,
+	0x0c, 0x0c, 0x04, 0xfe, 0x05, 0x00, 0x66, 0x66,
+	0x5a, 0x56, 0xbc, 0x01, 0x06, 0xfc, 0xfc, 0xf1,
+	0xfe, 0x07, 0x00, 0x24, 0x95, 0x70, 0x64, 0x18,
+	0x06, 0x2c, 0xff, 0xb5, 0xfe, 0xfe, 0xb5, 0xfe,
+	0xfe, 0xe2, 0x8c, 0x24, 0x02, 0x2f, 0xff, 0x2f,
+	0xff, 0xb4, 0x78, 0x02, 0x05, 0x73, 0xff, 0xed,
+	0xfe, 0xfe, 0x4f, 0xff, 0x36, 0x74, 0x1e, 0x09,
+	0x4f, 0xff, 0x50, 0xff, 0xfe, 0x16, 0x00, 0x70,
+	0xac, 0x70, 0x8e, 0xac, 0x40, 0x0e, 0x01, 0x70,
+	0x7f, 0x8e, 0xac, 0x6c, 0x00, 0x0b, 0xfe, 0x02,
+	0x00, 0xfe, 0x0a, 0x2c, 0x2a, 0x2a, 0x28, 0x26,
+	0x1e, 0x1e, 0xfe, 0x02, 0x20, 0x65, 0x20, 0x00,
+	0x00, 0x05, 0x12, 0x00, 0x11, 0x1e, 0x11, 0x11,
+	0x41, 0x1e, 0x41, 0x11, 0x31, 0x1e, 0x31, 0x11,
+	0x70, 0x75, 0x7a, 0x7f, 0x84, 0x89, 0x8e, 0x93,
+	0x98, 0x30, 0x20, 0x00, 0x02, 0x00, 0xfe, 0x06,
+	0x3c, 0xbc, 0x32, 0x0c, 0x00, 0x00, 0x2a, 0x12,
+	0x1e, 0x12, 0x2e, 0x12, 0xcc, 0x12, 0x11, 0x1a,
+	0x1e, 0x1a, 0x2e, 0x1a, 0x4c, 0x10, 0x1e, 0x10,
+	0x11, 0x18, 0x1e, 0x42, 0x1e, 0x42, 0x2e, 0x42,
+	0xcc, 0x42, 0x11, 0x4a, 0x1e, 0x4a, 0x2e, 0x4a,
+	0x4c, 0x40, 0x1e, 0x40, 0x11, 0x48, 0x1e, 0x32,
+	0x1e, 0x32, 0x2e, 0x32, 0xcc, 0x32, 0x11, 0x3a,
+	0x1e, 0x3a, 0x2e, 0x3a, 0x4c, 0x30, 0x1e, 0x30,
+	0x11, 0x38, 0x1e, 0x27, 0x9a, 0x01, 0x9d, 0xa2,
+	0x2f, 0x28, 0x00, 0x00, 0x46, 0xde, 0xc4, 0xbf,
+	0xa6, 0x9d, 0x81, 0x7b, 0x5c, 0x61, 0x40, 0xc7,
+	0xc0, 0xae, 0xa9, 0x8c, 0x83, 0x6a, 0x62, 0x50,
+	0x3e, 0xce, 0xc2, 0xae, 0xa3, 0x8c, 0x7b, 0x6a,
+	0x5a, 0x50, 0x35, 0xd7, 0xc2, 0xb7, 0xa4, 0x95,
+	0x7e, 0x72, 0x5a, 0x59, 0x37, 0xfe, 0x02, 0xf8,
+	0x8c, 0x95, 0x90, 0x8f, 0x00, 0xd7, 0xc0, 0xb7,
+	0xa2, 0x95, 0x7b, 0x72, 0x56, 0x59, 0x32, 0xc7,
+	0xc3, 0xae, 0xad, 0x8c, 0x85, 0x6a, 0x63, 0x50,
+	0x3e, 0xce, 0xc3, 0xae, 0xa4, 0x8c, 0x7c, 0x6a,
+	0x59, 0x50, 0x34, 0xd7, 0xc2, 0xb7, 0xa5, 0x95,
+	0x7e, 0x72, 0x59, 0x59, 0x36, 0xfc, 0x05, 0x00,
+	0x02, 0xce, 0xc5, 0xae, 0xa5, 0x95, 0x83, 0x72,
+	0x5c, 0x59, 0x36, 0xbf, 0xc6, 0xa5, 0xab, 0x8c,
+	0x8c, 0x6a, 0x67, 0x50, 0x41, 0x64, 0x07, 0x00,
+	0x02, 0x95, 0x8c, 0x72, 0x65, 0x59, 0x3f, 0xce,
+	0xc7, 0xae, 0xa8, 0x95, 0x86, 0x72, 0x5f, 0x59,
+	0x39, 0xfe, 0x02, 0xf8, 0x8b, 0x7c, 0x0b, 0x09,
+	0xb7, 0xc2, 0x9d, 0xa4, 0x83, 0x85, 0x6a, 0x6b,
+	0x50, 0x44, 0xb7, 0xc1, 0x64, 0x01, 0x00, 0x06,
+	0x61, 0x5d, 0x48, 0x3d, 0xae, 0xc4, 0x9d, 0xad,
+	0x7b, 0x85, 0x61, 0x66, 0x48, 0x46, 0xae, 0xc3,
+	0x95, 0xa3, 0x72, 0x7c, 0x59, 0x56, 0x38, 0x31,
+	0x7c, 0x0b, 0x00, 0x0c, 0x96, 0x91, 0x8f, 0x00,
+	0xb7, 0xc0, 0xa5, 0xab, 0x8c, 0x8a, 0x6a, 0x64,
+	0x50, 0x3c, 0xb7, 0xc0, 0x9d, 0xa0, 0x83, 0x80,
+	0x6a, 0x64, 0x50, 0x3d, 0xb7, 0xc5, 0x9d, 0xa5,
+	0x83, 0x87, 0x6c, 0x08, 0x07, 0xae, 0xc0, 0x9d,
+	0xa8, 0x83, 0x88, 0x6a, 0x6d, 0x50, 0x46, 0xfc,
+	0x05, 0x00, 0x16, 0xbf, 0xc0, 0xa5, 0xa2, 0x8c,
+	0x7f, 0x6a, 0x57, 0x50, 0x2f, 0xb7, 0xc7, 0xa5,
+	0xb1, 0x8c, 0x8e, 0x72, 0x6d, 0x59, 0x45, 0xbf,
+	0xc6, 0xa5, 0xa8, 0x8c, 0x87, 0x6a, 0x5f, 0x50,
+	0x37, 0xbf, 0xc2, 0xa5, 0xa4, 0x8c, 0x83, 0x6a,
+	0x5c, 0x50, 0x34, 0xbc, 0x05, 0x00, 0x0e, 0x90,
+	0x00, 0xc7, 0xc2, 0xae, 0xaa, 0x95, 0x82, 0x7b,
+	0x60, 0x61, 0x3f, 0xb7, 0xc6, 0xa5, 0xb1, 0x8c,
+	0x8d, 0x72, 0x6b, 0x61, 0x51, 0xbf, 0xc4, 0xa5,
+	0xa5, 0x8c, 0x82, 0x72, 0x61, 0x59, 0x39, 0x6c,
+	0x26, 0x03, 0x95, 0x82, 0x7b, 0x61, 0x61, 0x40,
+	0xfc, 0x05, 0x00, 0x00, 0x7e, 0xd7, 0xc3, 0xb7,
+	0xa8, 0x9d, 0x80, 0x83, 0x5d, 0x6a, 0x3f, 0xbf,
+	0xc7, 0xa5, 0xa8, 0x8c, 0x84, 0x72, 0x60, 0x61,
+	0x46, 0xbf, 0xc2, 0xae, 0xb0, 0x9d, 0x92, 0x83,
+	0x6f, 0x6a, 0x50, 0xd7, 0xc3, 0xb7, 0xa7, 0x9d,
+	0x80, 0x83, 0x5e, 0x6a, 0x40, 0xfe, 0x02, 0xf8,
+	0x8d, 0x96, 0x90, 0x90, 0xfe, 0x05, 0x00, 0x8a,
+	0xc4, 0x63, 0xb8, 0x3c, 0xa6, 0x29, 0x97, 0x16,
+	0x81, 0x84, 0xb7, 0x5b, 0xa9, 0x33, 0x94, 0x1e,
+	0x83, 0x11, 0x70, 0xb8, 0xc2, 0x70, 0xb1, 0x4d,
+	0xa3, 0x2a, 0x8d, 0x1b, 0x7b, 0xa8, 0xbc, 0x68,
+	0xab, 0x47, 0x9d, 0x27, 0x87, 0x18, 0x75, 0xae,
+	0xc6, 0x7d, 0xbb, 0x4d, 0xaa, 0x1c, 0x84, 0x11,
+	0x72, 0xa3, 0xbb, 0x6e, 0xad, 0x3c, 0x97, 0x24,
+	0x85, 0x16, 0x71, 0x80, 0xb2, 0x57, 0xa4, 0x30,
+	0x8e, 0x1c, 0x7c, 0x10, 0x68, 0xbb, 0xbd, 0x75,
+	0xac, 0x4f, 0x9e, 0x2b, 0x87, 0x1a, 0x76, 0x96,
+	0xc5, 0x5e, 0xb5, 0x3e, 0xa5, 0x1f, 0x8c, 0x12,
+	0x7a, 0xc1, 0xc6, 0x42, 0x9f, 0x27, 0x8c, 0x16,
+	0x77, 0x0f, 0x67, 0x9d, 0xbc, 0x68, 0xad, 0x36,
+	0x95, 0x20, 0x83, 0x11, 0x6d, 0x9b, 0xb8, 0x67,
+	0xa8, 0x34, 0x90, 0x1f, 0x7c, 0x10, 0x67, 0x9e,
+	0xc9, 0x6a, 0xbb, 0x37, 0xa4, 0x20, 0x90, 0x11,
+	0x7b, 0xc6, 0xc8, 0x47, 0xa4, 0x2a, 0x90, 0x18,
+	0x7b, 0x10, 0x6c, 0xae, 0xc4, 0x5d, 0xad, 0x37,
+	0x9a, 0x1f, 0x85, 0x13, 0x75, 0x70, 0xad, 0x42,
+	0x99, 0x25, 0x84, 0x17, 0x74, 0x0b, 0x56, 0x87,
+	0xc8, 0x57, 0xb8, 0x2b, 0x9e, 0x19, 0x8a, 0x0d,
+	0x74, 0xa7, 0xc8, 0x6e, 0xb9, 0x36, 0xa0, 0x1f,
+	0x8b, 0x11, 0x75, 0x94, 0xbe, 0x4b, 0xa5, 0x2a,
+	0x92, 0x18, 0x7c, 0x0f, 0x6b, 0xaf, 0xc0, 0x58,
+	0xa8, 0x34, 0x94, 0x1d, 0x7d, 0x12, 0x6d, 0x82,
+	0xc0, 0x52, 0xb0, 0x25, 0x94, 0x14, 0x7f, 0x0c,
+	0x68, 0x84, 0xbf, 0x3e, 0xa4, 0x22, 0x8e, 0x10,
+	0x76, 0x0b, 0x65, 0x88, 0xb6, 0x42, 0x9b, 0x26,
+	0x87, 0x14, 0x70, 0x0c, 0x5f, 0xc5, 0xc2, 0x3e,
+	0x97, 0x23, 0x83, 0x13, 0x6c, 0x0c, 0x5c, 0xb1,
+	0xc9, 0x76, 0xbc, 0x4a, 0xaa, 0x20, 0x8d, 0x12,
+	0x78, 0x93, 0xbf, 0x46, 0xa3, 0x26, 0x8d, 0x14,
+	0x74, 0x0c, 0x62, 0xc8, 0xc4, 0x3b, 0x97, 0x21,
+	0x82, 0x11, 0x6a, 0x0a, 0x59, 0xa3, 0xb9, 0x68,
+	0xa9, 0x30, 0x8d, 0x1a, 0x78, 0x0f, 0x61, 0xa0,
+	0xc9, 0x73, 0xbe, 0x50, 0xb1, 0x30, 0x9f, 0x14,
+	0x80, 0x83, 0xb7, 0x3c, 0x9a, 0x20, 0x84, 0x0e,
+	0x6a, 0x0a, 0x57, 0xac, 0xc2, 0x68, 0xb0, 0x2e,
+	0x92, 0x19, 0x7c, 0x0d, 0x63, 0x93, 0xbe, 0x62,
+	0xb0, 0x3c, 0x9e, 0x1a, 0x80, 0x0e, 0x6b, 0xbb,
+	0x02, 0xa0, 0x02, 0xa0, 0x02, 0x6f, 0x00, 0x75,
+	0x00, 0x75, 0x00, 0x00, 0x00, 0xad, 0x02, 0xb3,
+	0x02, 0x6f, 0x00, 0x87, 0x00, 0x85, 0xfe, 0x03,
+	0x00, 0xc2, 0x02, 0x82, 0x4d, 0x92, 0x6e, 0x4d,
+	0xb1, 0xa8, 0x84, 0x01, 0x00, 0x07, 0x7e, 0x00,
+	0xa8, 0x02, 0xa4, 0x02, 0xa4, 0x02, 0xa2, 0x00,
+	0xa6, 0x00, 0xa6, 0x00, 0x00, 0x00, 0xb4, 0x02,
+	0xb4, 0x02, 0x92, 0x00, 0x96, 0x00, 0x96, 0x46,
+	0x04, 0xb0, 0x02, 0x64, 0x02, 0x0a, 0x8c, 0x00,
+	0x90, 0x02, 0x98, 0x02, 0x98, 0x02, 0x0e, 0x01,
+	0x11, 0x01, 0x11, 0x50, 0xc3, 0x08, 0x88, 0x02,
+	0x88, 0x02, 0x19, 0x01, 0x02, 0x01, 0x02, 0x01,
+	0xf3, 0x2d, 0x00, 0x00
+};
+
+/* Array of known hw_options bits with human-friendly parsing */
+static struct hc_hwopt {
+	const u32 bit;
+	const char *str;
+} const hc_hwopts[] = {
+	{
+		.bit = RB_HW_OPT_NO_UART,
+		.str = "no UART\t\t",
+	}, {
+		.bit = RB_HW_OPT_HAS_VOLTAGE,
+		.str = "has Vreg\t",
+	}, {
+		.bit = RB_HW_OPT_HAS_USB,
+		.str = "has usb\t\t",
+	}, {
+		.bit = RB_HW_OPT_HAS_ATTINY,
+		.str = "has ATtiny\t",
+	}, {
+		.bit = RB_HW_OPT_NO_NAND,
+		.str = "no NAND\t\t",
+	}, {
+		.bit = RB_HW_OPT_HAS_LCD,
+		.str = "has LCD\t\t",
+	}, {
+		.bit = RB_HW_OPT_HAS_POE_OUT,
+		.str = "has POE out\t",
+	}, {
+		.bit = RB_HW_OPT_HAS_uSD,
+		.str = "has MicroSD\t",
+	}, {
+		.bit = RB_HW_OPT_HAS_SIM,
+		.str = "has SIM\t\t",
+	}, {
+		.bit = RB_HW_OPT_HAS_SFP,
+		.str = "has SFP\t\t",
+	}, {
+		.bit = RB_HW_OPT_HAS_WIFI,
+		.str = "has WiFi\t",
+	}, {
+		.bit = RB_HW_OPT_HAS_TS_FOR_ADC,
+		.str = "has TS ADC\t",
+	}, {
+		.bit = RB_HW_OPT_HAS_PLC,
+		.str = "has PLC\t\t",
+	},
+};
+
+/*
+ * The MAC is stored network-endian on all devices, in 2 32-bit segments:
+ * <XX:XX:XX:XX> <XX:XX:00:00>. Kernel print has us covered.
+ */
+static ssize_t hc_tag_show_mac(const u8 *pld, u16 pld_len, char *buf)
+{
+	if (8 != pld_len)
+		return -EINVAL;
+
+	return sprintf(buf, "%pM\n", pld);
+}
+
+/*
+ * Print HW options in a human readable way:
+ * The raw number and in decoded form
+ */
+static ssize_t hc_tag_show_hwoptions(const u8 *pld, u16 pld_len, char *buf)
+{
+	char *out = buf;
+	u32 data;	// cpu-endian
+	int i;
+
+	if (sizeof(data) != pld_len)
+		return -EINVAL;
+
+	data = *(u32 *)pld;
+	out += sprintf(out, "raw\t\t: 0x%08x\n\n", data);
+
+	for (i = 0; i < ARRAY_SIZE(hc_hwopts); i++)
+		out += sprintf(out, "%s: %s\n", hc_hwopts[i].str,
+			       (data & hc_hwopts[i].bit) ? "true" : "false");
+
+	return out - buf;
+}
+
+static ssize_t hc_wlan_data_bin_read(struct file *filp, struct kobject *kobj,
+				     struct bin_attribute *attr, char *buf,
+				     loff_t off, size_t count);
+
+static struct hc_wlan_attr {
+	const u16 erd_tag_id;
+	struct bin_attribute battr;
+	u16 pld_ofs;
+	u16 pld_len;
+} hc_wd_multi_battrs[] = {
+	{
+		.erd_tag_id = RB_WLAN_ERD_ID_MULTI_8001,
+		.battr = __BIN_ATTR(data_0, S_IRUSR, hc_wlan_data_bin_read, NULL, 0),
+	}, {
+		.erd_tag_id = RB_WLAN_ERD_ID_MULTI_8201,
+		.battr = __BIN_ATTR(data_2, S_IRUSR, hc_wlan_data_bin_read, NULL, 0),
+	}
+};
+
+static struct hc_wlan_attr hc_wd_solo_battr = {
+	.erd_tag_id = RB_WLAN_ERD_ID_SOLO,
+	.battr = __BIN_ATTR(wlan_data, S_IRUSR, hc_wlan_data_bin_read, NULL, 0),
+};
+
+static ssize_t hc_attr_show(struct kobject *kobj, struct kobj_attribute *attr,
+			    char *buf);
+
+/* Array of known tags to publish in sysfs */
+static struct hc_attr {
+	const u16 tag_id;
+	ssize_t (* const tshow)(const u8 *pld, u16 pld_len, char *buf);
+	struct kobj_attribute kattr;
+	u16 pld_ofs;
+	u16 pld_len;
+} hc_attrs[] = {
+	{
+		.tag_id = RB_ID_FLASH_INFO,
+		.tshow = routerboot_tag_show_u32s,
+		.kattr = __ATTR(flash_info, S_IRUSR, hc_attr_show, NULL),
+	}, {
+		.tag_id = RB_ID_MAC_ADDRESS_PACK,
+		.tshow = hc_tag_show_mac,
+		.kattr = __ATTR(mac_base, S_IRUSR, hc_attr_show, NULL),
+	}, {
+		.tag_id = RB_ID_BOARD_PRODUCT_CODE,
+		.tshow = routerboot_tag_show_string,
+		.kattr = __ATTR(board_product_code, S_IRUSR, hc_attr_show, NULL),
+	}, {
+		.tag_id = RB_ID_BIOS_VERSION,
+		.tshow = routerboot_tag_show_string,
+		.kattr = __ATTR(booter_version, S_IRUSR, hc_attr_show, NULL),
+	}, {
+		.tag_id = RB_ID_SERIAL_NUMBER,
+		.tshow = routerboot_tag_show_string,
+		.kattr = __ATTR(board_serial, S_IRUSR, hc_attr_show, NULL),
+	}, {
+		.tag_id = RB_ID_MEMORY_SIZE,
+		.tshow = routerboot_tag_show_u32s,
+		.kattr = __ATTR(mem_size, S_IRUSR, hc_attr_show, NULL),
+	}, {
+		.tag_id = RB_ID_MAC_ADDRESS_COUNT,
+		.tshow = routerboot_tag_show_u32s,
+		.kattr = __ATTR(mac_count, S_IRUSR, hc_attr_show, NULL),
+	}, {
+		.tag_id = RB_ID_HW_OPTIONS,
+		.tshow = hc_tag_show_hwoptions,
+		.kattr = __ATTR(hw_options, S_IRUSR, hc_attr_show, NULL),
+	}, {
+		.tag_id = RB_ID_WLAN_DATA,
+		.tshow = NULL,
+	}, {
+		.tag_id = RB_ID_BOARD_IDENTIFIER,
+		.tshow = routerboot_tag_show_string,
+		.kattr = __ATTR(board_identifier, S_IRUSR, hc_attr_show, NULL),
+	}, {
+		.tag_id = RB_ID_PRODUCT_NAME,
+		.tshow = routerboot_tag_show_string,
+		.kattr = __ATTR(product_name, S_IRUSR, hc_attr_show, NULL),
+	}, {
+		.tag_id = RB_ID_DEFCONF,
+		.tshow = routerboot_tag_show_string,
+		.kattr = __ATTR(defconf, S_IRUSR, hc_attr_show, NULL),
+	}, {
+		.tag_id = RB_ID_BOARD_REVISION,
+		.tshow = routerboot_tag_show_string,
+		.kattr = __ATTR(board_revision, S_IRUSR, hc_attr_show, NULL),
+	}
+};
+
+/*
+ * If the RB_ID_WLAN_DATA payload starts with RB_MAGIC_ERD, then past
+ * that magic number the payload itself contains a routerboot tag node
+ * locating the LZO-compressed calibration data. So far this scheme is only
+ * known to use a single tag at id 0x1.
+ */
+static int hc_wlan_data_unpack_erd(const u16 tag_id, const u8 *inbuf, size_t inlen,
+				   void *outbuf, size_t *outlen)
+{
+	u16 lzo_ofs, lzo_len;
+	int ret;
+
+	/* Find embedded tag */
+	ret = routerboot_tag_find(inbuf, inlen, tag_id, &lzo_ofs, &lzo_len);
+	if (ret) {
+		pr_debug(RB_HC_PR_PFX "no ERD data for id 0x%04x\n", tag_id);
+		goto fail;
+	}
+
+	if (lzo_len > inlen) {
+		pr_debug(RB_HC_PR_PFX "Invalid ERD data length\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	ret = lzo1x_decompress_safe(inbuf+lzo_ofs, lzo_len, outbuf, outlen);
+	if (ret)
+		pr_debug(RB_HC_PR_PFX "LZO decompression error (%d)\n", ret);
+
+fail:
+	return ret;
+}
+
+/*
+ * If the RB_ID_WLAN_DATA payload starts with RB_MAGIC_LZOR, then past
+ * that magic number is a payload that must be appended to the hc_lzor_prefix,
+ * the resulting blob is LZO-compressed. In the LZO decompression result,
+ * the RB_MAGIC_ERD magic number (aligned) must be located. Following that
+ * magic, there is one or more routerboot tag node(s) locating the RLE-encoded
+ * calibration data payload.
+ */
+static int hc_wlan_data_unpack_lzor(const u16 tag_id, const u8 *inbuf, size_t inlen,
+				    void *outbuf, size_t *outlen)
+{
+	u16 rle_ofs, rle_len;
+	const u32 *needle;
+	u8 *tempbuf;
+	size_t templen, lzo_len;
+	int ret;
+
+	lzo_len = inlen + sizeof(hc_lzor_prefix);
+	if (lzo_len > *outlen)
+		return -EFBIG;
+
+	/* Temporary buffer same size as the outbuf */
+	templen = *outlen;
+	tempbuf = kmalloc(templen, GFP_KERNEL);
+	if (!tempbuf)
+		return -ENOMEM;
+
+	/* Concatenate into the outbuf */
+	memcpy(outbuf, hc_lzor_prefix, sizeof(hc_lzor_prefix));
+	memcpy(outbuf + sizeof(hc_lzor_prefix), inbuf, inlen);
+
+	/* LZO-decompress lzo_len bytes of outbuf into the tempbuf */
+	ret = lzo1x_decompress_safe(outbuf, lzo_len, tempbuf, &templen);
+	if (ret) {
+		if (LZO_E_INPUT_NOT_CONSUMED == ret) {
+			/*
+			 * The tag length is always aligned thus the LZO payload may be padded,
+			 * which can trigger a spurious error which we ignore here.
+			 */
+			pr_debug(RB_HC_PR_PFX "LZOR: LZO EOF before buffer end - this may be harmless\n");
+		} else {
+			pr_debug(RB_HC_PR_PFX "LZOR: LZO decompression error (%d)\n", ret);
+			goto fail;
+		}
+	}
+
+	/*
+	 * Post decompression we have a blob (possibly byproduct of the lzo
+	 * dictionary). We need to find RB_MAGIC_ERD. The magic number seems to
+	 * be 32bit-aligned in the decompression output.
+	 */
+	needle = (const u32 *)tempbuf;
+	while (RB_MAGIC_ERD != *needle++) {
+		if ((u8 *)needle >= tempbuf+templen) {
+			pr_debug(RB_HC_PR_PFX "LZOR: ERD magic not found\n");
+			ret = -ENODATA;
+			goto fail;
+		}
+	};
+	templen -= (u8 *)needle - tempbuf;
+
+	/* Past magic. Look for tag node */
+	ret = routerboot_tag_find((u8 *)needle, templen, tag_id, &rle_ofs, &rle_len);
+	if (ret) {
+		pr_debug(RB_HC_PR_PFX "LZOR: no RLE data for id 0x%04x\n", tag_id);
+		goto fail;
+	}
+
+	if (rle_len > templen) {
+		pr_debug(RB_HC_PR_PFX "LZOR: Invalid RLE data length\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	/* RLE-decode tempbuf from needle back into the outbuf */
+	ret = routerboot_rle_decode((u8 *)needle+rle_ofs, rle_len, outbuf, outlen);
+	if (ret)
+		pr_debug(RB_HC_PR_PFX "LZOR: RLE decoding error (%d)\n", ret);
+
+fail:
+	kfree(tempbuf);
+	return ret;
+}
+
+static int hc_wlan_data_unpack(const u16 tag_id, const size_t tofs, size_t tlen,
+			       void *outbuf, size_t *outlen)
+{
+	const u8 *lbuf;
+	u32 magic;
+	int ret;
+
+	/* Caller ensure tlen > 0. tofs is aligned */
+	if ((tofs + tlen) > hc_buflen)
+		return -EIO;
+
+	lbuf = hc_buf + tofs;
+	magic = *(u32 *)lbuf;
+
+	ret = -ENODATA;
+	switch (magic) {
+	case RB_MAGIC_LZOR:
+		/* Skip magic */
+		lbuf += sizeof(magic);
+		tlen -= sizeof(magic);
+		ret = hc_wlan_data_unpack_lzor(tag_id, lbuf, tlen, outbuf, outlen);
+		break;
+	case RB_MAGIC_ERD:
+		/* Skip magic */
+		lbuf += sizeof(magic);
+		tlen -= sizeof(magic);
+		ret = hc_wlan_data_unpack_erd(tag_id, lbuf, tlen, outbuf, outlen);
+		break;
+	default:
+		/*
+		 * If the RB_ID_WLAN_DATA payload doesn't start with a
+		 * magic number, the payload itself is the raw RLE-encoded
+		 * calibration data. Only RB_WLAN_ERD_ID_SOLO makes sense here.
+		 */
+		if (RB_WLAN_ERD_ID_SOLO == tag_id) {
+			ret = routerboot_rle_decode(lbuf, tlen, outbuf, outlen);
+			if (ret)
+				pr_debug(RB_HC_PR_PFX "RLE decoding error (%d)\n", ret);
+		}
+		break;
+	}
+
+	return ret;
+}
+
+static ssize_t hc_attr_show(struct kobject *kobj, struct kobj_attribute *attr,
+			    char *buf)
+{
+	const struct hc_attr *hc_attr;
+	const u8 *pld;
+	u16 pld_len;
+
+	hc_attr = container_of(attr, typeof(*hc_attr), kattr);
+
+	if (!hc_attr->pld_len)
+		return -ENOENT;
+
+	pld = hc_buf + hc_attr->pld_ofs;
+	pld_len = hc_attr->pld_len;
+
+	return hc_attr->tshow(pld, pld_len, buf);
+}
+
+/*
+ * This function will allocate and free memory every time it is called. This
+ * is not the fastest way to do this, but since the data is rarely read (mainly
+ * at boot time to load wlan caldata), this makes it possible to save memory for
+ * the system.
+ */
+static ssize_t hc_wlan_data_bin_read(struct file *filp, struct kobject *kobj,
+				     struct bin_attribute *attr, char *buf,
+				     loff_t off, size_t count)
+{
+	struct hc_wlan_attr *hc_wattr;
+	size_t outlen;
+	void *outbuf;
+	int ret;
+
+	hc_wattr = container_of(attr, typeof(*hc_wattr), battr);
+
+	if (!hc_wattr->pld_len)
+		return -ENOENT;
+
+	outlen = RB_ART_SIZE;
+
+	/* Don't bother unpacking if the source is already too large */
+	if (hc_wattr->pld_len > outlen)
+		return -EFBIG;
+
+	outbuf = kmalloc(outlen, GFP_KERNEL);
+	if (!outbuf)
+		return -ENOMEM;
+
+	ret = hc_wlan_data_unpack(hc_wattr->erd_tag_id, hc_wattr->pld_ofs, hc_wattr->pld_len, outbuf, &outlen);
+	if (ret) {
+		kfree(outbuf);
+		return ret;
+	}
+
+	if (off >= outlen) {
+		kfree(outbuf);
+		return 0;
+	}
+
+	if (off + count > outlen)
+		count = outlen - off;
+
+	memcpy(buf, outbuf + off, count);
+
+	kfree(outbuf);
+	return count;
+}
+
+int __init rb_hardconfig_init(struct kobject *rb_kobj)
+{
+	struct kobject *hc_wlan_kobj;
+	struct mtd_info *mtd;
+	size_t bytes_read, buflen, outlen;
+	const u8 *buf;
+	void *outbuf;
+	int i, j, ret;
+	u32 magic;
+
+	hc_buf = NULL;
+	hc_kobj = NULL;
+	hc_wlan_kobj = NULL;
+
+	// TODO allow override
+	mtd = get_mtd_device_nm(RB_MTD_HARD_CONFIG);
+	if (IS_ERR(mtd))
+		return -ENODEV;
+
+	hc_buflen = mtd->size;
+	hc_buf = kmalloc(hc_buflen, GFP_KERNEL);
+	if (!hc_buf) {
+		put_mtd_device(mtd);
+		return -ENOMEM;
+	}
+
+	ret = mtd_read(mtd, 0, hc_buflen, &bytes_read, hc_buf);
+	put_mtd_device(mtd);
+
+	if (ret)
+		goto fail;
+
+	if (bytes_read != hc_buflen) {
+		ret = -EIO;
+		goto fail;
+	}
+
+	/* Check we have what we expect */
+	magic = *(const u32 *)hc_buf;
+	if (RB_MAGIC_HARD != magic) {
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	/* Skip magic */
+	buf = hc_buf + sizeof(magic);
+	buflen = hc_buflen - sizeof(magic);
+
+	/* Populate sysfs */
+	ret = -ENOMEM;
+	hc_kobj = kobject_create_and_add(RB_MTD_HARD_CONFIG, rb_kobj);
+	if (!hc_kobj)
+		goto fail;
+
+	/* Locate and publish all known tags */
+	for (i = 0; i < ARRAY_SIZE(hc_attrs); i++) {
+		ret = routerboot_tag_find(buf, buflen, hc_attrs[i].tag_id,
+					  &hc_attrs[i].pld_ofs, &hc_attrs[i].pld_len);
+		if (ret) {
+			hc_attrs[i].pld_ofs = hc_attrs[i].pld_len = 0;
+			continue;
+		}
+
+		/* Account for skipped magic */
+		hc_attrs[i].pld_ofs += sizeof(magic);
+
+		/*
+		 * Special case RB_ID_WLAN_DATA to prep and create the binary attribute.
+		 * We first check if the data is "old style" within a single tag (or no tag at all):
+		 * If it is we publish this single blob as a binary attribute child of hc_kobj to
+		 * preserve backward compatibility.
+		 * If it isn't and instead uses multiple ERD tags, we create a subfolder and
+		 * publish the known ones there.
+		 */
+		if ((RB_ID_WLAN_DATA == hc_attrs[i].tag_id) && hc_attrs[i].pld_len) {
+			outlen = RB_ART_SIZE;
+			outbuf = kmalloc(outlen, GFP_KERNEL);
+			if (!outbuf) {
+				pr_warn(RB_HC_PR_PFX "Out of memory parsing WLAN tag\n");
+				continue;
+			}
+
+			/* Test ID_SOLO first, if found: done */
+			ret = hc_wlan_data_unpack(RB_WLAN_ERD_ID_SOLO, hc_attrs[i].pld_ofs, hc_attrs[i].pld_len, outbuf, &outlen);
+			if (!ret) {
+				hc_wd_solo_battr.pld_ofs = hc_attrs[i].pld_ofs;
+				hc_wd_solo_battr.pld_len = hc_attrs[i].pld_len;
+
+				ret = sysfs_create_bin_file(hc_kobj, &hc_wd_solo_battr.battr);
+				if (ret)
+					pr_warn(RB_HC_PR_PFX "Could not create %s sysfs entry (%d)\n",
+						hc_wd_solo_battr.battr.attr.name, ret);
+			}
+			/* Otherwise, create "wlan_data" subtree and publish known data */
+			else {
+				hc_wlan_kobj = kobject_create_and_add("wlan_data", hc_kobj);
+				if (!hc_wlan_kobj) {
+					kfree(outbuf);
+					pr_warn(RB_HC_PR_PFX "Could not create wlan_data sysfs folder\n");
+					continue;
+				}
+
+				for (j = 0; j < ARRAY_SIZE(hc_wd_multi_battrs); j++) {
+					outlen = RB_ART_SIZE;
+					ret = hc_wlan_data_unpack(hc_wd_multi_battrs[j].erd_tag_id,
+								  hc_attrs[i].pld_ofs, hc_attrs[i].pld_len, outbuf, &outlen);
+					if (ret) {
+						hc_wd_multi_battrs[j].pld_ofs = hc_wd_multi_battrs[j].pld_len = 0;
+						continue;
+					}
+
+					hc_wd_multi_battrs[j].pld_ofs = hc_attrs[i].pld_ofs;
+					hc_wd_multi_battrs[j].pld_len = hc_attrs[i].pld_len;
+
+					ret = sysfs_create_bin_file(hc_wlan_kobj, &hc_wd_multi_battrs[j].battr);
+					if (ret)
+						pr_warn(RB_HC_PR_PFX "Could not create wlan_data/%s sysfs entry (%d)\n",
+							hc_wd_multi_battrs[j].battr.attr.name, ret);
+				}
+			}
+
+			kfree(outbuf);
+		}
+		/* All other tags are published via standard attributes */
+		else {
+			ret = sysfs_create_file(hc_kobj, &hc_attrs[i].kattr.attr);
+			if (ret)
+				pr_warn(RB_HC_PR_PFX "Could not create %s sysfs entry (%d)\n",
+				       hc_attrs[i].kattr.attr.name, ret);
+		}
+	}
+
+	pr_info("MikroTik RouterBOARD hardware configuration sysfs driver v" RB_HARDCONFIG_VER "\n");
+
+	return 0;
+
+fail:
+	kfree(hc_buf);
+	hc_buf = NULL;
+	return ret;
+}
+
+void __exit rb_hardconfig_exit(void)
+{
+	kobject_put(hc_kobj);
+	kfree(hc_buf);
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/platform/mikrotik/rb_softconfig.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/platform/mikrotik/rb_softconfig.c
new file mode 100644
index 0000000..070bd32
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/platform/mikrotik/rb_softconfig.c
@@ -0,0 +1,806 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for MikroTik RouterBoot soft config.
+ *
+ * Copyright (C) 2020 Thibaut VARÈNE <hacks+kernel@slashdirt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This driver exposes the data encoded in the "soft_config" flash segment of
+ * MikroTik RouterBOARDs devices. It presents the data in a sysfs folder
+ * named "soft_config". The data is presented in a user/machine-friendly way
+ * with just as much parsing as can be generalized across mikrotik platforms
+ * (as inferred from reverse-engineering).
+ *
+ * The known soft_config tags are presented in the "soft_config" sysfs folder,
+ * with the addition of one specific file named "commit", which is only
+ * available if the driver supports writes to the mtd device: no modifications
+ * made to any of the other attributes are actually written back to flash media
+ * until a true value is input into this file (e.g. [Yy1]). This is to avoid
+ * unnecessary flash wear, and to permit to revert all changes by issuing a
+ * false value ([Nn0]). Reading the content of this file shows the current
+ * status of the driver: if the data in sysfs matches the content of the
+ * soft_config partition, the file will read "clean". Otherwise, it will read
+ * "dirty".
+ *
+ * The writeable sysfs files presented by this driver will accept only inputs
+ * which are in a valid range for the given tag. As a design choice, the driver
+ * will not assess whether the inputs are identical to the existing data.
+ *
+ * Note: PAGE_SIZE is assumed to be >= 4K, hence the device attribute show
+ * routines need not check for output overflow.
+ *
+ * Some constant defines extracted from rbcfg.h by Gabor Juhos
+ * <juhosg@openwrt.org>
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/mtd/mtd.h>
+#include <linux/sysfs.h>
+#include <linux/version.h>
+#include <linux/capability.h>
+#include <linux/spinlock.h>
+#include <linux/crc32.h>
+
+#ifdef CONFIG_ATH79
+ #include <asm/mach-ath79/ath79.h>
+#endif
+
+#include "routerboot.h"
+
+#define RB_SOFTCONFIG_VER		"0.03"
+#define RB_SC_PR_PFX			"[rb_softconfig] "
+
+/*
+ * mtd operations before 4.17 are asynchronous, not handled by this code
+ * Also make the driver act read-only if 4K_SECTORS are not enabled, since they
+ * are require to handle partial erasing of the small soft_config partition.
+ */
+#if defined(CONFIG_MTD_SPI_NOR_USE_4K_SECTORS)
+ #define RB_SC_HAS_WRITE_SUPPORT	true
+ #define RB_SC_WMODE			S_IWUSR
+ #define RB_SC_RMODE			S_IRUSR
+#else
+ #define RB_SC_HAS_WRITE_SUPPORT	false
+ #define RB_SC_WMODE			0
+ #define RB_SC_RMODE			S_IRUSR
+#endif
+
+/* ID values for software settings */
+#define RB_SCID_UART_SPEED		0x01	// u32*1
+#define RB_SCID_BOOT_DELAY		0x02	// u32*1
+#define RB_SCID_BOOT_DEVICE		0x03	// u32*1
+#define RB_SCID_BOOT_KEY		0x04	// u32*1
+#define RB_SCID_CPU_MODE		0x05	// u32*1
+#define RB_SCID_BIOS_VERSION		0x06	// str
+#define RB_SCID_BOOT_PROTOCOL		0x09	// u32*1
+#define RB_SCID_CPU_FREQ_IDX		0x0C	// u32*1
+#define RB_SCID_BOOTER			0x0D	// u32*1
+#define RB_SCID_SILENT_BOOT		0x0F	// u32*1
+/*
+ * protected_routerboot seems to use tag 0x1F. It only works in combination with
+ * RouterOS, resulting in a wiped board otherwise, so it's not implemented here.
+ * The tag values are as follows:
+ * - off: 0x0
+ * - on: the lower halfword encodes the max value in s for the reset feature,
+ *	 the higher halfword encodes the min value in s for the reset feature.
+ * Default value when on: 0x00140258: 0x14 = 20s / 0x258= 600s
+ * See details here: https://wiki.mikrotik.com/wiki/Manual:RouterBOARD_settings#Protected_bootloader
+ */
+
+/* Tag values */
+
+#define RB_UART_SPEED_115200		0
+#define RB_UART_SPEED_57600		1
+#define RB_UART_SPEED_38400		2
+#define RB_UART_SPEED_19200		3
+#define RB_UART_SPEED_9600		4
+#define RB_UART_SPEED_4800		5
+#define RB_UART_SPEED_2400		6
+#define RB_UART_SPEED_1200		7
+#define RB_UART_SPEED_OFF		8
+
+/* valid boot delay: 1 - 9s in 1s increment */
+#define RB_BOOT_DELAY_MIN		1
+#define RB_BOOT_DELAY_MAX		9
+
+#define RB_BOOT_DEVICE_ETHER		0	// "boot over Ethernet"
+#define RB_BOOT_DEVICE_NANDETH		1	// "boot from NAND, if fail then Ethernet"
+#define RB_BOOT_DEVICE_CFCARD		2	// (not available in rbcfg)
+#define RB_BOOT_DEVICE_ETHONCE		3	// "boot Ethernet once, then NAND"
+#define RB_BOOT_DEVICE_NANDONLY		5	// "boot from NAND only"
+#define RB_BOOT_DEVICE_FLASHCFG		7	// "boot in flash configuration mode"
+#define RB_BOOT_DEVICE_FLSHONCE		8	// "boot in flash configuration mode once, then NAND"
+
+/*
+ * ATH79 9xxx CPU frequency indices.
+ * It is unknown if they apply to all ATH79 RBs, and some do not seem to feature
+ * the upper levels (QCA955x), while F is presumably AR9344-only.
+ */
+#define RB_CPU_FREQ_IDX_ATH79_9X_A	(0 << 3)
+#define RB_CPU_FREQ_IDX_ATH79_9X_B	(1 << 3)	// 0x8
+#define RB_CPU_FREQ_IDX_ATH79_9X_C	(2 << 3)	// 0x10 - factory freq for many devices
+#define RB_CPU_FREQ_IDX_ATH79_9X_D	(3 << 3)	// 0x18
+#define RB_CPU_FREQ_IDX_ATH79_9X_E	(4 << 3)	// 0x20
+#define RB_CPU_FREQ_IDX_ATH79_9X_F	(5 << 3)	// 0x28
+
+#define RB_CPU_FREQ_IDX_ATH79_9X_MIN		0	// all devices support lowest setting
+#define RB_CPU_FREQ_IDX_ATH79_9X_AR9334_MAX	5	// stops at F
+#define RB_CPU_FREQ_IDX_ATH79_9X_QCA953X_MAX	4	// stops at E
+#define RB_CPU_FREQ_IDX_ATH79_9X_QCA9556_MAX	2	// stops at C
+#define RB_CPU_FREQ_IDX_ATH79_9X_QCA9558_MAX	3	// stops at D
+
+/* ATH79 7xxx CPU frequency indices. */
+#define RB_CPU_FREQ_IDX_ATH79_7X_A	((0 * 9) << 4)
+#define RB_CPU_FREQ_IDX_ATH79_7X_B	((1 * 9) << 4)
+#define RB_CPU_FREQ_IDX_ATH79_7X_C	((2 * 9) << 4)
+#define RB_CPU_FREQ_IDX_ATH79_7X_D	((3 * 9) << 4)
+#define RB_CPU_FREQ_IDX_ATH79_7X_E	((4 * 9) << 4)
+#define RB_CPU_FREQ_IDX_ATH79_7X_F	((5 * 9) << 4)
+#define RB_CPU_FREQ_IDX_ATH79_7X_G	((6 * 9) << 4)
+#define RB_CPU_FREQ_IDX_ATH79_7X_H	((7 * 9) << 4)
+
+#define RB_CPU_FREQ_IDX_ATH79_7X_MIN		0	// all devices support lowest setting
+#define RB_CPU_FREQ_IDX_ATH79_7X_AR724X_MAX	3	// stops at D
+#define RB_CPU_FREQ_IDX_ATH79_7X_AR7161_MAX	7	// stops at H - check if applies to all AR71xx devices
+
+#define RB_SC_CRC32_OFFSET		4	// located right after magic
+
+static struct kobject *sc_kobj;
+static u8 *sc_buf;
+static size_t sc_buflen;
+static rwlock_t sc_bufrwl;		// rw lock to sc_buf
+
+/* MUST be used with lock held */
+#define RB_SC_CLRCRC()		*(u32 *)(sc_buf + RB_SC_CRC32_OFFSET) = 0
+#define RB_SC_GETCRC()		*(u32 *)(sc_buf + RB_SC_CRC32_OFFSET)
+#define RB_SC_SETCRC(_crc)	*(u32 *)(sc_buf + RB_SC_CRC32_OFFSET) = (_crc)
+
+struct sc_u32tvs {
+	const u32 val;
+	const char *str;
+};
+
+#define RB_SC_TVS(_val, _str) {		\
+	.val = (_val),			\
+	.str = (_str),			\
+}
+
+static ssize_t sc_tag_show_u32tvs(const u8 *pld, u16 pld_len, char *buf,
+				  const struct sc_u32tvs tvs[], const int tvselmts)
+{
+	const char *fmt;
+	char *out = buf;
+	u32 data;	// cpu-endian
+	int i;
+
+	// fallback to raw hex output if we can't handle the input
+	if (tvselmts < 0)
+		return routerboot_tag_show_u32s(pld, pld_len, buf);
+
+	if (sizeof(data) != pld_len)
+		return -EINVAL;
+
+	read_lock(&sc_bufrwl);
+	data = *(u32 *)pld;		// pld aliases sc_buf
+	read_unlock(&sc_bufrwl);
+
+	for (i = 0; i < tvselmts; i++) {
+		fmt = (tvs[i].val == data) ? "[%s] " : "%s ";
+		out += sprintf(out, fmt, tvs[i].str);
+	}
+
+	out += sprintf(out, "\n");
+	return out - buf;
+}
+
+static ssize_t sc_tag_store_u32tvs(const u8 *pld, u16 pld_len, const char *buf, size_t count,
+				   const struct sc_u32tvs tvs[], const int tvselmts)
+{
+	int i;
+
+	if (tvselmts < 0)
+		return tvselmts;
+
+	if (sizeof(u32) != pld_len)
+		return -EINVAL;
+
+	for (i = 0; i < tvselmts; i++) {
+		if (sysfs_streq(buf, tvs[i].str)) {
+			write_lock(&sc_bufrwl);
+			*(u32 *)pld = tvs[i].val;	// pld aliases sc_buf
+			RB_SC_CLRCRC();
+			write_unlock(&sc_bufrwl);
+			return count;
+		}
+	}
+
+	return -EINVAL;
+}
+
+struct sc_boolts {
+	const char *strfalse;
+	const char *strtrue;
+};
+
+static ssize_t sc_tag_show_boolts(const u8 *pld, u16 pld_len, char *buf,
+				  const struct sc_boolts *bts)
+{
+	const char *fmt;
+	char *out = buf;
+	u32 data;	// cpu-endian
+
+	if (sizeof(data) != pld_len)
+		return -EINVAL;
+
+	read_lock(&sc_bufrwl);
+	data = *(u32 *)pld;		// pld aliases sc_buf
+	read_unlock(&sc_bufrwl);
+
+	fmt = (data) ? "%s [%s]\n" : "[%s] %s\n";
+	out += sprintf(out, fmt, bts->strfalse, bts->strtrue);
+
+	return out - buf;
+}
+
+static ssize_t sc_tag_store_boolts(const u8 *pld, u16 pld_len, const char *buf, size_t count,
+				   const struct sc_boolts *bts)
+{
+	u32 data;	// cpu-endian
+
+	if (sizeof(data) != pld_len)
+		return -EINVAL;
+
+	if (sysfs_streq(buf, bts->strfalse))
+		data = 0;
+	else if (sysfs_streq(buf, bts->strtrue))
+		data = 1;
+	else
+		return -EINVAL;
+
+	write_lock(&sc_bufrwl);
+	*(u32 *)pld = data;		// pld aliases sc_buf
+	RB_SC_CLRCRC();
+	write_unlock(&sc_bufrwl);
+
+	return count;
+}
+static struct sc_u32tvs const sc_uartspeeds[] = {
+	RB_SC_TVS(RB_UART_SPEED_OFF,	"off"),
+	RB_SC_TVS(RB_UART_SPEED_1200,	"1200"),
+	RB_SC_TVS(RB_UART_SPEED_2400,	"2400"),
+	RB_SC_TVS(RB_UART_SPEED_4800,	"4800"),
+	RB_SC_TVS(RB_UART_SPEED_9600,	"9600"),
+	RB_SC_TVS(RB_UART_SPEED_19200,	"19200"),
+	RB_SC_TVS(RB_UART_SPEED_38400,	"38400"),
+	RB_SC_TVS(RB_UART_SPEED_57600,	"57600"),
+	RB_SC_TVS(RB_UART_SPEED_115200,	"115200"),
+};
+
+/*
+ * While the defines are carried over from rbcfg, use strings that more clearly
+ * show the actual setting purpose (especially since the NAND* settings apply
+ * to both nand- and nor-based devices). "cfcard" was disabled in rbcfg: disable
+ * it here too.
+ */
+static struct sc_u32tvs const sc_bootdevices[] = {
+	RB_SC_TVS(RB_BOOT_DEVICE_ETHER,		"eth"),
+	RB_SC_TVS(RB_BOOT_DEVICE_NANDETH,	"flasheth"),
+	//RB_SC_TVS(RB_BOOT_DEVICE_CFCARD,	"cfcard"),
+	RB_SC_TVS(RB_BOOT_DEVICE_ETHONCE,	"ethonce"),
+	RB_SC_TVS(RB_BOOT_DEVICE_NANDONLY,	"flash"),
+	RB_SC_TVS(RB_BOOT_DEVICE_FLASHCFG,	"cfg"),
+	RB_SC_TVS(RB_BOOT_DEVICE_FLSHONCE,	"cfgonce"),
+};
+
+static struct sc_boolts const sc_bootkey = {
+	.strfalse = "any",
+	.strtrue = "del",
+};
+
+static struct sc_boolts const sc_cpumode = {
+	.strfalse = "powersave",
+	.strtrue = "regular",
+};
+
+static struct sc_boolts const sc_bootproto = {
+	.strfalse = "bootp",
+	.strtrue = "dhcp",
+};
+
+static struct sc_boolts const sc_booter = {
+	.strfalse = "regular",
+	.strtrue = "backup",
+};
+
+static struct sc_boolts const sc_silent_boot = {
+	.strfalse = "off",
+	.strtrue = "on",
+};
+
+#define SC_TAG_SHOW_STORE_U32TVS_FUNCS(_name)		\
+static ssize_t sc_tag_show_##_name(const u8 *pld, u16 pld_len, char *buf)	\
+{										\
+	return sc_tag_show_u32tvs(pld, pld_len, buf, sc_##_name, ARRAY_SIZE(sc_##_name));	\
+}										\
+static ssize_t sc_tag_store_##_name(const u8 *pld, u16 pld_len, const char *buf, size_t count)	\
+{										\
+	return sc_tag_store_u32tvs(pld, pld_len, buf, count, sc_##_name, ARRAY_SIZE(sc_##_name));	\
+}
+
+#define SC_TAG_SHOW_STORE_BOOLTS_FUNCS(_name)		\
+static ssize_t sc_tag_show_##_name(const u8 *pld, u16 pld_len, char *buf)	\
+{										\
+	return sc_tag_show_boolts(pld, pld_len, buf, &sc_##_name);	\
+}										\
+static ssize_t sc_tag_store_##_name(const u8 *pld, u16 pld_len, const char *buf, size_t count)	\
+{										\
+	return sc_tag_store_boolts(pld, pld_len, buf, count, &sc_##_name);	\
+}
+
+SC_TAG_SHOW_STORE_U32TVS_FUNCS(uartspeeds)
+SC_TAG_SHOW_STORE_U32TVS_FUNCS(bootdevices)
+SC_TAG_SHOW_STORE_BOOLTS_FUNCS(bootkey)
+SC_TAG_SHOW_STORE_BOOLTS_FUNCS(cpumode)
+SC_TAG_SHOW_STORE_BOOLTS_FUNCS(bootproto)
+SC_TAG_SHOW_STORE_BOOLTS_FUNCS(booter)
+SC_TAG_SHOW_STORE_BOOLTS_FUNCS(silent_boot)
+
+static ssize_t sc_tag_show_bootdelays(const u8 *pld, u16 pld_len, char *buf)
+{
+	const char *fmt;
+	char *out = buf;
+	u32 data;	// cpu-endian
+	int i;
+
+	if (sizeof(data) != pld_len)
+		return -EINVAL;
+
+	read_lock(&sc_bufrwl);
+	data = *(u32 *)pld;		// pld aliases sc_buf
+	read_unlock(&sc_bufrwl);
+
+	for (i = RB_BOOT_DELAY_MIN; i <= RB_BOOT_DELAY_MAX; i++) {
+		fmt = (i == data) ? "[%d] " : "%d ";
+		out += sprintf(out, fmt, i);
+	}
+
+	out += sprintf(out, "\n");
+	return out - buf;
+}
+
+static ssize_t sc_tag_store_bootdelays(const u8 *pld, u16 pld_len, const char *buf, size_t count)
+{
+	u32 data;	// cpu-endian
+	int ret;
+
+	if (sizeof(data) != pld_len)
+		return -EINVAL;
+
+	ret = kstrtou32(buf, 10, &data);
+	if (ret)
+		return ret;
+
+	if ((data < RB_BOOT_DELAY_MIN) || (RB_BOOT_DELAY_MAX < data))
+		return -EINVAL;
+
+	write_lock(&sc_bufrwl);
+	*(u32 *)pld = data;		// pld aliases sc_buf
+	RB_SC_CLRCRC();
+	write_unlock(&sc_bufrwl);
+
+	return count;
+}
+
+/* Support CPU frequency accessors only when the tag format has been asserted */
+#if defined(CONFIG_ATH79)
+/* Use the same letter-based nomenclature as RouterBOOT */
+static struct sc_u32tvs const sc_cpufreq_indexes_ath79_9x[] = {
+	RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_A,	"a"),
+	RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_B,	"b"),
+	RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_C,	"c"),
+	RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_D,	"d"),
+	RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_E,	"e"),
+	RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_F,	"f"),
+};
+
+static struct sc_u32tvs const sc_cpufreq_indexes_ath79_7x[] = {
+	RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_A,	"a"),
+	RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_B,	"b"),
+	RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_C,	"c"),
+	RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_D,	"d"),
+	RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_E,	"e"),
+	RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_F,	"f"),
+	RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_G,	"g"),
+	RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_H,	"h"),
+};
+
+static int sc_tag_cpufreq_ath79_arraysize(void)
+{
+	int idx_max;
+
+	if (ATH79_SOC_AR7161 == ath79_soc)
+		idx_max = RB_CPU_FREQ_IDX_ATH79_7X_AR7161_MAX+1;
+	else if (soc_is_ar724x())
+		idx_max = RB_CPU_FREQ_IDX_ATH79_7X_AR724X_MAX+1;
+	else if (soc_is_ar9344())
+		idx_max = RB_CPU_FREQ_IDX_ATH79_9X_AR9334_MAX+1;
+	else if (soc_is_qca953x())
+		idx_max = RB_CPU_FREQ_IDX_ATH79_9X_QCA953X_MAX+1;
+	else if (soc_is_qca9556())
+		idx_max = RB_CPU_FREQ_IDX_ATH79_9X_QCA9556_MAX+1;
+	else if (soc_is_qca9558())
+		idx_max = RB_CPU_FREQ_IDX_ATH79_9X_QCA9558_MAX+1;
+	else
+		idx_max = -EOPNOTSUPP;
+
+	return idx_max;
+}
+
+static ssize_t sc_tag_show_cpufreq_indexes(const u8 *pld, u16 pld_len, char *buf)
+{
+	const struct sc_u32tvs *tvs;
+
+	if (soc_is_ar71xx() || soc_is_ar724x())
+		tvs = sc_cpufreq_indexes_ath79_7x;
+	else
+		tvs = sc_cpufreq_indexes_ath79_9x;
+
+	return sc_tag_show_u32tvs(pld, pld_len, buf, tvs, sc_tag_cpufreq_ath79_arraysize());
+}
+
+static ssize_t sc_tag_store_cpufreq_indexes(const u8 *pld, u16 pld_len, const char *buf, size_t count)
+{
+	const struct sc_u32tvs *tvs;
+
+	if (soc_is_ar71xx() || soc_is_ar724x())
+		tvs = sc_cpufreq_indexes_ath79_7x;
+	else
+		tvs = sc_cpufreq_indexes_ath79_9x;
+
+	return sc_tag_store_u32tvs(pld, pld_len, buf, count, tvs, sc_tag_cpufreq_ath79_arraysize());
+}
+#else
+ /* By default we only show the raw value to help with reverse-engineering */
+ #define sc_tag_show_cpufreq_indexes	routerboot_tag_show_u32s
+ #define sc_tag_store_cpufreq_indexes	NULL
+#endif
+
+static ssize_t sc_attr_show(struct kobject *kobj, struct kobj_attribute *attr,
+			    char *buf);
+static ssize_t sc_attr_store(struct kobject *kobj, struct kobj_attribute *attr,
+			     const char *buf, size_t count);
+
+/* Array of known tags to publish in sysfs */
+static struct sc_attr {
+	const u16 tag_id;
+	/* sysfs tag show attribute. Must lock sc_buf when dereferencing pld */
+	ssize_t (* const tshow)(const u8 *pld, u16 pld_len, char *buf);
+	/* sysfs tag store attribute. Must lock sc_buf when dereferencing pld */
+	ssize_t (* const tstore)(const u8 *pld, u16 pld_len, const char *buf, size_t count);
+	struct kobj_attribute kattr;
+	u16 pld_ofs;
+	u16 pld_len;
+} sc_attrs[] = {
+	{
+		.tag_id = RB_SCID_UART_SPEED,
+		.tshow = sc_tag_show_uartspeeds,
+		.tstore = sc_tag_store_uartspeeds,
+		.kattr = __ATTR(uart_speed, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store),
+	}, {
+		.tag_id = RB_SCID_BOOT_DELAY,
+		.tshow = sc_tag_show_bootdelays,
+		.tstore = sc_tag_store_bootdelays,
+		.kattr = __ATTR(boot_delay, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store),
+	}, {
+		.tag_id = RB_SCID_BOOT_DEVICE,
+		.tshow = sc_tag_show_bootdevices,
+		.tstore = sc_tag_store_bootdevices,
+		.kattr = __ATTR(boot_device, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store),
+	}, {
+		.tag_id = RB_SCID_BOOT_KEY,
+		.tshow = sc_tag_show_bootkey,
+		.tstore = sc_tag_store_bootkey,
+		.kattr = __ATTR(boot_key, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store),
+	}, {
+		.tag_id = RB_SCID_CPU_MODE,
+		.tshow = sc_tag_show_cpumode,
+		.tstore = sc_tag_store_cpumode,
+		.kattr = __ATTR(cpu_mode, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store),
+	}, {
+		.tag_id = RB_SCID_BIOS_VERSION,
+		.tshow = routerboot_tag_show_string,
+		.tstore = NULL,
+		.kattr = __ATTR(bios_version, RB_SC_RMODE, sc_attr_show, NULL),
+	}, {
+		.tag_id = RB_SCID_BOOT_PROTOCOL,
+		.tshow = sc_tag_show_bootproto,
+		.tstore = sc_tag_store_bootproto,
+		.kattr = __ATTR(boot_proto, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store),
+	}, {
+		.tag_id = RB_SCID_CPU_FREQ_IDX,
+		.tshow = sc_tag_show_cpufreq_indexes,
+		.tstore = sc_tag_store_cpufreq_indexes,
+		.kattr = __ATTR(cpufreq_index, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store),
+	}, {
+		.tag_id = RB_SCID_BOOTER,
+		.tshow = sc_tag_show_booter,
+		.tstore = sc_tag_store_booter,
+		.kattr = __ATTR(booter, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store),
+	}, {
+		.tag_id = RB_SCID_SILENT_BOOT,
+		.tshow = sc_tag_show_silent_boot,
+		.tstore = sc_tag_store_silent_boot,
+		.kattr = __ATTR(silent_boot, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store),
+	},
+};
+
+static ssize_t sc_attr_show(struct kobject *kobj, struct kobj_attribute *attr,
+			    char *buf)
+{
+	const struct sc_attr *sc_attr;
+	const u8 *pld;
+	u16 pld_len;
+
+	sc_attr = container_of(attr, typeof(*sc_attr), kattr);
+
+	if (!sc_attr->pld_len)
+		return -ENOENT;
+
+	pld = sc_buf + sc_attr->pld_ofs;	// pld aliases sc_buf -> lock!
+	pld_len = sc_attr->pld_len;
+
+	return sc_attr->tshow(pld, pld_len, buf);
+}
+
+static ssize_t sc_attr_store(struct kobject *kobj, struct kobj_attribute *attr,
+			     const char *buf, size_t count)
+{
+	const struct sc_attr *sc_attr;
+	const u8 *pld;
+	u16 pld_len;
+
+	if (!RB_SC_HAS_WRITE_SUPPORT)
+		return -EOPNOTSUPP;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	sc_attr = container_of(attr, typeof(*sc_attr), kattr);
+
+	if (!sc_attr->tstore)
+		return -EOPNOTSUPP;
+
+	if (!sc_attr->pld_len)
+		return -ENOENT;
+
+	pld = sc_buf + sc_attr->pld_ofs;	// pld aliases sc_buf -> lock!
+	pld_len = sc_attr->pld_len;
+
+	return sc_attr->tstore(pld, pld_len, buf, count);
+}
+
+/*
+ * Shows the current buffer status:
+ * "clean": the buffer is in sync with the mtd data
+ * "dirty": the buffer is out of sync with the mtd data
+ */
+static ssize_t sc_commit_show(struct kobject *kobj, struct kobj_attribute *attr,
+			      char *buf)
+{
+	const char *str;
+	char *out = buf;
+	u32 crc;
+
+	read_lock(&sc_bufrwl);
+	crc = RB_SC_GETCRC();
+	read_unlock(&sc_bufrwl);
+
+	str = (crc) ? "clean" : "dirty";
+	out += sprintf(out, "%s\n", str);
+
+	return out - buf;
+}
+
+/*
+ * Performs buffer flushing:
+ * This routine expects an input compatible with kstrtobool().
+ * - a "false" input discards the current changes and reads data back from mtd.
+ * - a "true" input commits the current changes to mtd.
+ * If there is no pending changes, this routine is a no-op.
+ * Handling failures is left as an exercise to userspace.
+ */
+static ssize_t sc_commit_store(struct kobject *kobj, struct kobj_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct mtd_info *mtd;
+	struct erase_info ei;
+	size_t bytes_rw, ret = count;
+	bool flush;
+	u32 crc;
+
+	if (!RB_SC_HAS_WRITE_SUPPORT)
+		return -EOPNOTSUPP;
+
+	read_lock(&sc_bufrwl);
+	crc = RB_SC_GETCRC();
+	read_unlock(&sc_bufrwl);
+
+	if (crc)
+		return count;	// NO-OP
+
+	ret = kstrtobool(buf, &flush);
+	if (ret)
+		return ret;
+
+	mtd = get_mtd_device_nm(RB_MTD_SOFT_CONFIG);	// TODO allow override
+	if (IS_ERR(mtd))
+		return -ENODEV;
+
+	write_lock(&sc_bufrwl);
+	if (!flush)	// reread
+		ret = mtd_read(mtd, 0, mtd->size, &bytes_rw, sc_buf);
+	else {	// crc32 + commit
+		/*
+		 * CRC32 is computed on the entire buffer, excluding the CRC
+		 * value itself. CRC is already null when we reach this point,
+		 * so we can compute the CRC32 on the buffer as is.
+		 * The expected CRC32 is Ethernet FCS style, meaning the seed is
+		 * ~0 and the final result is also bitflipped.
+		 */
+
+		crc = ~crc32(~0, sc_buf, sc_buflen);
+		RB_SC_SETCRC(crc);
+
+		/*
+		 * The soft_config partition is assumed to be entirely contained
+		 * in a single eraseblock.
+		 */
+
+		ei.addr = 0;
+		ei.len = mtd->size;
+		ret = mtd_erase(mtd, &ei);
+		if (!ret)
+			ret = mtd_write(mtd, 0, mtd->size, &bytes_rw, sc_buf);
+
+		/*
+		 * Handling mtd_write() failure here is a tricky situation. The
+		 * proposed approach is to let userspace deal with retrying,
+		 * with the caveat that it must try to flush the buffer again as
+		 * rereading the mtd contents could potentially read garbage.
+		 * The rationale is: even if we keep a shadow buffer of the
+		 * original content, there is no guarantee that we will ever be
+		 * able to write it anyway.
+		 * Regardless, it appears that RouterBOOT will ignore an invalid
+		 * soft_config (including a completely wiped segment) and will
+		 * write back factory defaults when it happens.
+		 */
+	}
+	write_unlock(&sc_bufrwl);
+
+	put_mtd_device(mtd);
+
+	if (ret)
+		goto mtdfail;
+
+	if (bytes_rw != sc_buflen) {
+		ret = -EIO;
+		goto mtdfail;
+	}
+
+	return count;
+
+mtdfail:
+	RB_SC_CLRCRC();	// mark buffer content as dirty/invalid
+	return ret;
+}
+
+static struct kobj_attribute sc_kattrcommit = __ATTR(commit, RB_SC_RMODE|RB_SC_WMODE, sc_commit_show, sc_commit_store);
+
+int __init rb_softconfig_init(struct kobject *rb_kobj)
+{
+	struct mtd_info *mtd;
+	size_t bytes_read, buflen;
+	const u8 *buf;
+	int i, ret;
+	u32 magic;
+
+	sc_buf = NULL;
+	sc_kobj = NULL;
+
+	// TODO allow override
+	mtd = get_mtd_device_nm(RB_MTD_SOFT_CONFIG);
+	if (IS_ERR(mtd))
+		return -ENODEV;
+
+	sc_buflen = mtd->size;
+	sc_buf = kmalloc(sc_buflen, GFP_KERNEL);
+	if (!sc_buf) {
+		put_mtd_device(mtd);
+		return -ENOMEM;
+	}
+
+	ret = mtd_read(mtd, 0, sc_buflen, &bytes_read, sc_buf);
+	put_mtd_device(mtd);
+
+	if (ret)
+		goto fail;
+
+	if (bytes_read != sc_buflen) {
+		ret = -EIO;
+		goto fail;
+	}
+
+	/* Check we have what we expect */
+	magic = *(const u32 *)sc_buf;
+	if (RB_MAGIC_SOFT != magic) {
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	/* Skip magic and 32bit CRC located immediately after */
+	buf = sc_buf + (sizeof(magic) + sizeof(u32));
+	buflen = sc_buflen - (sizeof(magic) + sizeof(u32));
+
+	/* Populate sysfs */
+	ret = -ENOMEM;
+	sc_kobj = kobject_create_and_add(RB_MTD_SOFT_CONFIG, rb_kobj);
+	if (!sc_kobj)
+		goto fail;
+
+	rwlock_init(&sc_bufrwl);
+
+	/* Locate and publish all known tags */
+	for (i = 0; i < ARRAY_SIZE(sc_attrs); i++) {
+		ret = routerboot_tag_find(buf, buflen, sc_attrs[i].tag_id,
+					  &sc_attrs[i].pld_ofs, &sc_attrs[i].pld_len);
+		if (ret) {
+			sc_attrs[i].pld_ofs = sc_attrs[i].pld_len = 0;
+			continue;
+		}
+
+		/* Account for skipped magic and crc32 */
+		sc_attrs[i].pld_ofs += sizeof(magic) + sizeof(u32);
+
+		ret = sysfs_create_file(sc_kobj, &sc_attrs[i].kattr.attr);
+		if (ret)
+			pr_warn(RB_SC_PR_PFX "Could not create %s sysfs entry (%d)\n",
+			       sc_attrs[i].kattr.attr.name, ret);
+	}
+
+	/* Finally add the 'commit' attribute */
+	if (RB_SC_HAS_WRITE_SUPPORT) {
+		ret = sysfs_create_file(sc_kobj, &sc_kattrcommit.attr);
+		if (ret) {
+			pr_err(RB_SC_PR_PFX "Could not create %s sysfs entry (%d), aborting!\n",
+			       sc_kattrcommit.attr.name, ret);
+			goto sysfsfail;	// required attribute
+		}
+	}
+
+	pr_info("MikroTik RouterBOARD software configuration sysfs driver v" RB_SOFTCONFIG_VER "\n");
+
+	return 0;
+
+sysfsfail:
+	kobject_put(sc_kobj);
+	sc_kobj = NULL;
+fail:
+	kfree(sc_buf);
+	sc_buf = NULL;
+	return ret;
+}
+
+void __exit rb_softconfig_exit(void)
+{
+	kobject_put(sc_kobj);
+	kfree(sc_buf);
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/platform/mikrotik/routerboot.c b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/platform/mikrotik/routerboot.c
new file mode 100644
index 0000000..4c8c0bf
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/platform/mikrotik/routerboot.c
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for MikroTik RouterBoot flash data. Common routines.
+ *
+ * Copyright (C) 2020 Thibaut VARÈNE <hacks+kernel@slashdirt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sysfs.h>
+
+#include "routerboot.h"
+
+static struct kobject *rb_kobj;
+
+/**
+ * routerboot_tag_find() - Locate a given tag in routerboot config data.
+ * @bufhead: the buffer to look into. Must start with a tag node.
+ * @buflen: size of bufhead
+ * @tag_id: the tag identifier to look for
+ * @pld_ofs: will be updated with tag payload offset in bufhead, if tag found
+ * @pld_len: will be updated with tag payload size, if tag found
+ *
+ * This incarnation of tag_find() does only that: it finds a specific routerboot
+ * tag node in the input buffer. Routerboot tag nodes are u32 values:
+ * - The low nibble is the tag identification number,
+ * - The high nibble is the tag payload length (node excluded) in bytes.
+ * The payload immediately follows the tag node. Tag nodes are 32bit-aligned.
+ * The returned pld_ofs will always be aligned. pld_len may not end on 32bit
+ * boundary (the only known case is when parsing ERD data).
+ * The nodes are cpu-endian on the flash media. The payload is cpu-endian when
+ * applicable. Tag nodes are not ordered (by ID) on flash.
+ *
+ * Return: 0 on success (tag found) or errno
+ */
+int routerboot_tag_find(const u8 *bufhead, const size_t buflen, const u16 tag_id,
+			u16 *pld_ofs, u16 *pld_len)
+{
+	const u32 *datum, *bufend;
+	u32 node;
+	u16 id, len;
+	int ret;
+
+	if (!bufhead || !tag_id)
+		return -EINVAL;
+
+	ret = -ENOENT;
+	datum = (const u32 *)bufhead;
+	bufend = (const u32 *)(bufhead + buflen);
+
+	while (datum < bufend) {
+		node = *datum++;
+
+		/* Tag list ends with null node */
+		if (!node)
+			break;
+
+		id = node & 0xFFFF;
+		len = node >> 16;
+
+		if (tag_id == id) {
+			if (datum >= bufend)
+				break;
+
+			if (pld_ofs)
+				*pld_ofs = (u16)((u8 *)datum - bufhead);
+			if (pld_len)
+				*pld_len = len;
+
+			ret = 0;
+			break;
+		}
+
+		/*
+		 * The only known situation where len may not end on 32bit
+		 * boundary is within ERD data. Since we're only extracting
+		 * one tag (the first and only one) from that data, we should
+		 * never need to forcefully ALIGN(). Do it anyway, this is not a
+		 * performance path.
+		 */
+		len = ALIGN(len, sizeof(*datum));
+		datum += len / sizeof(*datum);
+	}
+
+	return ret;
+}
+
+/**
+ * routerboot_rle_decode() - Simple RLE (MikroTik variant) decoding routine.
+ * @in: input buffer to decode
+ * @inlen: size of in
+ * @out: output buffer to write decoded data to
+ * @outlen: pointer to out size when function is called, will be updated with
+ * size of decoded output on return
+ *
+ * MikroTik's variant of RLE operates as follows, considering a signed run byte:
+ * - positive run => classic RLE
+ * - negative run => the next -<run> bytes must be copied verbatim
+ * The API is matched to the lzo1x routines for convenience.
+ *
+ * NB: The output buffer cannot overlap with the input buffer.
+ *
+ * Return: 0 on success or errno
+ */
+int routerboot_rle_decode(const u8 *in, size_t inlen, u8 *out, size_t *outlen)
+{
+	int ret, run, nbytes;	// use native types for speed
+	u8 byte;
+
+	if (!in || (inlen < 2) || !out)
+		return -EINVAL;
+
+	ret = -ENOSPC;
+	nbytes = 0;
+	while (inlen >= 2) {
+		run = *in++;
+		inlen--;
+
+		/* Verbatim copies */
+		if (run & 0x80) {
+			/* Invert run byte sign */
+			run = ~run & 0xFF;
+			run++;
+
+			if (run > inlen)
+				goto fail;
+
+			inlen -= run;
+
+			nbytes += run;
+			if (nbytes > *outlen)
+				goto fail;
+
+			/* Basic memcpy */
+			while (run-- > 0)
+				*out++ = *in++;
+		}
+		/* Stream of half-words RLE: <run><byte>. run == 0 is ignored */
+		else {
+			byte = *in++;
+			inlen--;
+
+			nbytes += run;
+			if (nbytes > *outlen)
+				goto fail;
+
+			while (run-- > 0)
+				*out++ = byte;
+		}
+	}
+
+	ret = 0;
+fail:
+	*outlen = nbytes;
+	return ret;
+}
+
+static int __init routerboot_init(void)
+{
+	rb_kobj = kobject_create_and_add("mikrotik", firmware_kobj);
+	if (!rb_kobj)
+		return -ENOMEM;
+
+	/*
+	 * We ignore the following return values and always register.
+	 * These init() routines are designed so that their failed state is
+	 * always manageable by the corresponding exit() calls.
+	 */
+	rb_hardconfig_init(rb_kobj);
+	rb_softconfig_init(rb_kobj);
+
+	return 0;
+}
+
+static void __exit routerboot_exit(void)
+{
+	rb_softconfig_exit();
+	rb_hardconfig_exit();
+	kobject_put(rb_kobj);	// recursive afaict
+}
+
+/* Common routines */
+
+ssize_t routerboot_tag_show_string(const u8 *pld, u16 pld_len, char *buf)
+{
+	return scnprintf(buf, pld_len+1, "%s\n", pld);
+}
+
+ssize_t routerboot_tag_show_u32s(const u8 *pld, u16 pld_len, char *buf)
+{
+	char *out = buf;
+	u32 *data;	// cpu-endian
+
+	/* Caller ensures pld_len > 0 */
+	if (pld_len % sizeof(*data))
+		return -EINVAL;
+
+	data = (u32 *)pld;
+
+	do {
+		out += sprintf(out, "0x%08x\n", *data);
+		data++;
+	} while ((pld_len -= sizeof(*data)));
+
+	return out - buf;
+}
+
+module_init(routerboot_init);
+module_exit(routerboot_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MikroTik RouterBoot sysfs support");
+MODULE_AUTHOR("Thibaut VARENE");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/platform/mikrotik/routerboot.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/platform/mikrotik/routerboot.h
new file mode 100644
index 0000000..67d8980
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/drivers/platform/mikrotik/routerboot.h
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Common definitions for MikroTik RouterBoot data.
+ *
+ * Copyright (C) 2020 Thibaut VARÈNE <hacks+kernel@slashdirt.org>
+ */
+
+
+#ifndef _ROUTERBOOT_H_
+#define _ROUTERBOOT_H_
+
+#include <linux/types.h>
+
+// these magic values are stored in cpu-endianness on flash
+#define RB_MAGIC_HARD	(('H') | ('a' << 8) | ('r' << 16) | ('d' << 24))
+#define RB_MAGIC_SOFT	(('S') | ('o' << 8) | ('f' << 16) | ('t' << 24))
+#define RB_MAGIC_LZOR	(('L') | ('Z' << 8) | ('O' << 16) | ('R' << 24))
+#define RB_MAGIC_ERD	(('E' << 16) | ('R' << 8) | ('D'))
+
+#define RB_ART_SIZE	0x10000
+
+#define RB_MTD_HARD_CONFIG	"hard_config"
+#define RB_MTD_SOFT_CONFIG	"soft_config"
+
+int routerboot_tag_find(const u8 *bufhead, const size_t buflen, const u16 tag_id, u16 *pld_ofs, u16 *pld_len);
+int routerboot_rle_decode(const u8 *in, size_t inlen, u8 *out, size_t *outlen);
+
+int __init rb_hardconfig_init(struct kobject *rb_kobj);
+void __exit rb_hardconfig_exit(void);
+
+int __init rb_softconfig_init(struct kobject *rb_kobj);
+void __exit rb_softconfig_exit(void);
+
+ssize_t routerboot_tag_show_string(const u8 *pld, u16 pld_len, char *buf);
+ssize_t routerboot_tag_show_u32s(const u8 *pld, u16 pld_len, char *buf);
+
+#endif /* _ROUTERBOOT_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/dt-bindings/mtd/partitions/uimage.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/dt-bindings/mtd/partitions/uimage.h
new file mode 100644
index 0000000..43d5f7b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/dt-bindings/mtd/partitions/uimage.h
@@ -0,0 +1,198 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ *    *** IMPORTANT ***
+ * This file is not only included from C-code but also from devicetree source
+ * files. As such this file MUST only contain comments and defines.
+ *
+ * Based on image.h from U-Boot which is
+ * (C) Copyright 2008 Semihalf
+ * (C) Copyright 2000-2005 Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
+#ifndef __UIMAGE_H__
+#define __UIMAGE_H__
+
+/*
+ * Operating System Codes
+ *
+ * The following are exposed to uImage header.
+ * New IDs *MUST* be appended at the end of the list and *NEVER*
+ * inserted for backward compatibility.
+ */
+#define	IH_OS_INVALID		0	/* Invalid OS	*/
+#define	IH_OS_OPENBSD		1	/* OpenBSD	*/
+#define	IH_OS_NETBSD		2	/* NetBSD	*/
+#define	IH_OS_FREEBSD		3	/* FreeBSD	*/
+#define	IH_OS_4_4BSD		4	/* 4.4BSD	*/
+#define	IH_OS_LINUX		5	/* Linux	*/
+#define	IH_OS_SVR4		6	/* SVR4		*/
+#define	IH_OS_ESIX		7	/* Esix		*/
+#define	IH_OS_SOLARIS		8	/* Solaris	*/
+#define	IH_OS_IRIX		9	/* Irix		*/
+#define	IH_OS_SCO	       10	/* SCO		*/
+#define	IH_OS_DELL	       11	/* Dell		*/
+#define	IH_OS_NCR	       12	/* NCR		*/
+#define	IH_OS_LYNXOS	       13	/* LynxOS	*/
+#define	IH_OS_VXWORKS	       14	/* VxWorks	*/
+#define	IH_OS_PSOS	       15	/* pSOS		*/
+#define	IH_OS_QNX	       16	/* QNX		*/
+#define	IH_OS_U_BOOT	       17	/* Firmware	*/
+#define	IH_OS_RTEMS	       18	/* RTEMS	*/
+#define	IH_OS_ARTOS	       19	/* ARTOS	*/
+#define	IH_OS_UNITY	       20	/* Unity OS	*/
+#define	IH_OS_INTEGRITY	       21	/* INTEGRITY	*/
+#define	IH_OS_OSE	       22	/* OSE		*/
+#define	IH_OS_PLAN9	       23	/* Plan 9	*/
+#define	IH_OS_OPENRTOS	       24	/* OpenRTOS	*/
+#define	IH_OS_ARM_TRUSTED_FIRMWARE 25    /* ARM Trusted Firmware */
+#define	IH_OS_TEE	       26	/* Trusted Execution Environment */
+#define	IH_OS_OPENSBI	       27	/* RISC-V OpenSBI */
+#define	IH_OS_EFI	       28	/* EFI Firmware (e.g. GRUB2) */
+
+/*
+ * CPU Architecture Codes (supported by Linux)
+ *
+ * The following are exposed to uImage header.
+ * New IDs *MUST* be appended at the end of the list and *NEVER*
+ * inserted for backward compatibility.
+ */
+#define	IH_ARCH_INVALID		0	/* Invalid CPU	*/
+#define	IH_ARCH_ALPHA		1	/* Alpha	*/
+#define	IH_ARCH_ARM		2	/* ARM		*/
+#define	IH_ARCH_I386		3	/* Intel x86	*/
+#define	IH_ARCH_IA64		4	/* IA64		*/
+#define	IH_ARCH_MIPS		5	/* MIPS		*/
+#define	IH_ARCH_MIPS64		6	/* MIPS	 64 Bit */
+#define	IH_ARCH_PPC		7	/* PowerPC	*/
+#define	IH_ARCH_S390		8	/* IBM S390	*/
+#define	IH_ARCH_SH		9	/* SuperH	*/
+#define	IH_ARCH_SPARC	       10	/* Sparc	*/
+#define	IH_ARCH_SPARC64	       11	/* Sparc 64 Bit */
+#define	IH_ARCH_M68K	       12	/* M68K		*/
+#define	IH_ARCH_NIOS	       13	/* Nios-32	*/
+#define	IH_ARCH_MICROBLAZE     14	/* MicroBlaze   */
+#define	IH_ARCH_NIOS2	       15	/* Nios-II	*/
+#define	IH_ARCH_BLACKFIN       16	/* Blackfin	*/
+#define	IH_ARCH_AVR32	       17	/* AVR32	*/
+#define	IH_ARCH_ST200	       18	/* STMicroelectronics ST200  */
+#define	IH_ARCH_SANDBOX	       19	/* Sandbox architecture (test only) */
+#define	IH_ARCH_NDS32	       20	/* ANDES Technology - NDS32  */
+#define	IH_ARCH_OPENRISC       21	/* OpenRISC 1000  */
+#define	IH_ARCH_ARM64	       22	/* ARM64	*/
+#define	IH_ARCH_ARC	       23	/* Synopsys DesignWare ARC */
+#define	IH_ARCH_X86_64	       24	/* AMD x86_64, Intel and Via */
+#define	IH_ARCH_XTENSA	       25	/* Xtensa	*/
+#define	IH_ARCH_RISCV	       26	/* RISC-V */
+
+/*
+ * Image Types
+ *
+ * "Standalone Programs" are directly runnable in the environment
+ *	provided by U-Boot; it is expected that (if they behave
+ *	well) you can continue to work in U-Boot after return from
+ *	the Standalone Program.
+ * "OS Kernel Images" are usually images of some Embedded OS which
+ *	will take over control completely. Usually these programs
+ *	will install their own set of exception handlers, device
+ *	drivers, set up the MMU, etc. - this means, that you cannot
+ *	expect to re-enter U-Boot except by resetting the CPU.
+ * "RAMDisk Images" are more or less just data blocks, and their
+ *	parameters (address, size) are passed to an OS kernel that is
+ *	being started.
+ * "Multi-File Images" contain several images, typically an OS
+ *	(Linux) kernel image and one or more data images like
+ *	RAMDisks. This construct is useful for instance when you want
+ *	to boot over the network using BOOTP etc., where the boot
+ *	server provides just a single image file, but you want to get
+ *	for instance an OS kernel and a RAMDisk image.
+ *
+ *	"Multi-File Images" start with a list of image sizes, each
+ *	image size (in bytes) specified by an "uint32_t" in network
+ *	byte order. This list is terminated by an "(uint32_t)0".
+ *	Immediately after the terminating 0 follow the images, one by
+ *	one, all aligned on "uint32_t" boundaries (size rounded up to
+ *	a multiple of 4 bytes - except for the last file).
+ *
+ * "Firmware Images" are binary images containing firmware (like
+ *	U-Boot or FPGA images) which usually will be programmed to
+ *	flash memory.
+ *
+ * "Script files" are command sequences that will be executed by
+ *	U-Boot's command interpreter; this feature is especially
+ *	useful when you configure U-Boot to use a real shell (hush)
+ *	as command interpreter (=> Shell Scripts).
+ *
+ * The following are exposed to uImage header.
+ * New IDs *MUST* be appended at the end of the list and *NEVER*
+ * inserted for backward compatibility.
+ */
+#define	IH_TYPE_INVALID		0	/* Invalid Image		*/
+#define	IH_TYPE_STANDALONE	1	/* Standalone Program		*/
+#define	IH_TYPE_KERNEL		2	/* OS Kernel Image		*/
+#define	IH_TYPE_RAMDISK		3	/* RAMDisk Image		*/
+#define	IH_TYPE_MULTI		4	/* Multi-File Image		*/
+#define	IH_TYPE_FIRMWARE	5	/* Firmware Image		*/
+#define	IH_TYPE_SCRIPT		6	/* Script file			*/
+#define	IH_TYPE_FILESYSTEM	7	/* Filesystem Image (any type)	*/
+#define	IH_TYPE_FLATDT		8	/* Binary Flat Device Tree Blob	*/
+#define	IH_TYPE_KWBIMAGE	9	/* Kirkwood Boot Image		*/
+#define	IH_TYPE_IMXIMAGE       10	/* Freescale IMXBoot Image	*/
+#define	IH_TYPE_UBLIMAGE       11	/* Davinci UBL Image		*/
+#define	IH_TYPE_OMAPIMAGE      12	/* TI OMAP Config Header Image	*/
+#define	IH_TYPE_AISIMAGE       13	/* TI Davinci AIS Image		*/
+	/* OS Kernel Image, can run from any load address */
+#define	IH_TYPE_KERNEL_NOLOAD  14
+#define	IH_TYPE_PBLIMAGE       15	/* Freescale PBL Boot Image	*/
+#define	IH_TYPE_MXSIMAGE       16	/* Freescale MXSBoot Image	*/
+#define	IH_TYPE_GPIMAGE	       17	/* TI Keystone GPHeader Image	*/
+#define	IH_TYPE_ATMELIMAGE     18	/* ATMEL ROM bootable Image	*/
+#define	IH_TYPE_SOCFPGAIMAGE   19	/* Altera SOCFPGA CV/AV Preloader */
+#define	IH_TYPE_X86_SETUP      20	/* x86 setup.bin Image		*/
+#define	IH_TYPE_LPC32XXIMAGE   21	/* x86 setup.bin Image		*/
+#define	IH_TYPE_LOADABLE       22	/* A list of typeless images	*/
+#define	IH_TYPE_RKIMAGE	       23	/* Rockchip Boot Image		*/
+#define	IH_TYPE_RKSD	       24	/* Rockchip SD card		*/
+#define	IH_TYPE_RKSPI	       25	/* Rockchip SPI image		*/
+#define	IH_TYPE_ZYNQIMAGE      26	/* Xilinx Zynq Boot Image */
+#define	IH_TYPE_ZYNQMPIMAGE    27	/* Xilinx ZynqMP Boot Image */
+#define	IH_TYPE_ZYNQMPBIF      28	/* Xilinx ZynqMP Boot Image (bif) */
+#define	IH_TYPE_FPGA	       29	/* FPGA Image */
+#define	IH_TYPE_VYBRIDIMAGE    30	/* VYBRID .vyb Image */
+#define	IH_TYPE_TEE            31	/* Trusted Execution Environment OS Image */
+#define	IH_TYPE_FIRMWARE_IVT   32	/* Firmware Image with HABv4 IVT */
+#define	IH_TYPE_PMMC           33	/* TI Power Management Micro-Controller Firmware */
+#define	IH_TYPE_STM32IMAGE     34	/* STMicroelectronics STM32 Image */
+#define	IH_TYPE_SOCFPGAIMAGE_V1 35	/* Altera SOCFPGA A10 Preloader	*/
+#define	IH_TYPE_MTKIMAGE       36	/* MediaTek BootROM loadable Image */
+#define	IH_TYPE_IMX8MIMAGE     37	/* Freescale IMX8MBoot Image	*/
+#define	IH_TYPE_IMX8IMAGE      38	/* Freescale IMX8Boot Image	*/
+#define	IH_TYPE_COPRO	       39	/* Coprocessor Image for remoteproc*/
+
+
+/*
+ * Compression Types
+ *
+ * The following are exposed to uImage header.
+ * New IDs *MUST* be appended at the end of the list and *NEVER*
+ * inserted for backward compatibility.
+ */
+#define	IH_COMP_NONE		0	/*  No	 Compression Used	*/
+#define	IH_COMP_GZIP		1	/* gzip	 Compression Used	*/
+#define	IH_COMP_BZIP2		2	/* bzip2 Compression Used	*/
+#define	IH_COMP_LZMA		3	/* lzma  Compression Used	*/
+#define	IH_COMP_LZO		4	/* lzo   Compression Used	*/
+#define	IH_COMP_LZ4		5	/* lz4   Compression Used	*/
+
+
+#define LZ4F_MAGIC	0x184D2204	/* LZ4 Magic Number		*/
+#define IH_MAGIC	0x27051956	/* Image Magic Number		*/
+#define IH_NMLEN		32	/* Image Name Length		*/
+
+/*
+ * Magic values specific to "openwrt,uimage" partitions
+ */
+#define IH_MAGIC_OKLI	0x4f4b4c49	/* 'OKLI'			*/
+#define FW_EDIMAX_OFFSET	20	/* Edimax Firmware Offset	*/
+#define FW_MAGIC_EDIMAX	0x43535953	/* Edimax Firmware Magic Number */
+
+#endif	/* __UIMAGE_H__ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/ar8216_platform.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/ar8216_platform.h
new file mode 100644
index 0000000..24bc442
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/ar8216_platform.h
@@ -0,0 +1,133 @@
+/*
+ * AR8216 switch driver platform data
+ *
+ * Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef AR8216_PLATFORM_H
+#define AR8216_PLATFORM_H
+
+enum ar8327_pad_mode {
+	AR8327_PAD_NC = 0,
+	AR8327_PAD_MAC2MAC_MII,
+	AR8327_PAD_MAC2MAC_GMII,
+	AR8327_PAD_MAC_SGMII,
+	AR8327_PAD_MAC2PHY_MII,
+	AR8327_PAD_MAC2PHY_GMII,
+	AR8327_PAD_MAC_RGMII,
+	AR8327_PAD_PHY_GMII,
+	AR8327_PAD_PHY_RGMII,
+	AR8327_PAD_PHY_MII,
+};
+
+enum ar8327_clk_delay_sel {
+	AR8327_CLK_DELAY_SEL0 = 0,
+	AR8327_CLK_DELAY_SEL1,
+	AR8327_CLK_DELAY_SEL2,
+	AR8327_CLK_DELAY_SEL3,
+};
+
+struct ar8327_pad_cfg {
+	enum ar8327_pad_mode mode;
+	bool rxclk_sel;
+	bool txclk_sel;
+	bool pipe_rxclk_sel;
+	bool txclk_delay_en;
+	bool rxclk_delay_en;
+	bool sgmii_delay_en;
+	enum ar8327_clk_delay_sel txclk_delay_sel;
+	enum ar8327_clk_delay_sel rxclk_delay_sel;
+	bool mac06_exchange_dis;
+};
+
+enum ar8327_port_speed {
+	AR8327_PORT_SPEED_10 = 0,
+	AR8327_PORT_SPEED_100,
+	AR8327_PORT_SPEED_1000,
+};
+
+struct ar8327_port_cfg {
+	int force_link:1;
+	enum ar8327_port_speed speed;
+	int txpause:1;
+	int rxpause:1;
+	int duplex:1;
+};
+
+struct ar8327_sgmii_cfg {
+	u32 sgmii_ctrl;
+	bool serdes_aen;
+};
+
+struct ar8327_led_cfg {
+	u32 led_ctrl0;
+	u32 led_ctrl1;
+	u32 led_ctrl2;
+	u32 led_ctrl3;
+	bool open_drain;
+};
+
+enum ar8327_led_num {
+	AR8327_LED_PHY0_0 = 0,
+	AR8327_LED_PHY0_1,
+	AR8327_LED_PHY0_2,
+	AR8327_LED_PHY1_0,
+	AR8327_LED_PHY1_1,
+	AR8327_LED_PHY1_2,
+	AR8327_LED_PHY2_0,
+	AR8327_LED_PHY2_1,
+	AR8327_LED_PHY2_2,
+	AR8327_LED_PHY3_0,
+	AR8327_LED_PHY3_1,
+	AR8327_LED_PHY3_2,
+	AR8327_LED_PHY4_0,
+	AR8327_LED_PHY4_1,
+	AR8327_LED_PHY4_2,
+};
+
+enum ar8327_led_mode {
+	AR8327_LED_MODE_HW = 0,
+	AR8327_LED_MODE_SW,
+};
+
+struct ar8327_led_info {
+	const char *name;
+	const char *default_trigger;
+	bool active_low;
+	enum ar8327_led_num led_num;
+	enum ar8327_led_mode mode;
+};
+
+#define AR8327_LED_INFO(_led, _mode, _name) {	\
+	.name = (_name), 	   		\
+	.led_num = AR8327_LED_ ## _led,		\
+	.mode = AR8327_LED_MODE_ ## _mode 	\
+}
+
+struct ar8327_platform_data {
+	struct ar8327_pad_cfg *pad0_cfg;
+	struct ar8327_pad_cfg *pad5_cfg;
+	struct ar8327_pad_cfg *pad6_cfg;
+	struct ar8327_sgmii_cfg *sgmii_cfg;
+	struct ar8327_port_cfg port0_cfg;
+	struct ar8327_port_cfg port6_cfg;
+	struct ar8327_led_cfg *led_cfg;
+
+	int (*get_port_link)(unsigned port);
+
+	unsigned num_leds;
+	const struct ar8327_led_info *leds;
+};
+
+#endif /* AR8216_PLATFORM_H */
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/ath5k_platform.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/ath5k_platform.h
new file mode 100644
index 0000000..ec85224
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/ath5k_platform.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (c) 2010 Daniel Golle <daniel.golle@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _LINUX_ATH5K_PLATFORM_H
+#define _LINUX_ATH5K_PLATFORM_H
+
+#define ATH5K_PLAT_EEP_MAX_WORDS	2048
+
+struct ath5k_platform_data {
+	u16 *eeprom_data;
+	u8 *macaddr;
+};
+
+#endif /* _LINUX_ATH5K_PLATFORM_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/ath9k_platform.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/ath9k_platform.h
new file mode 100644
index 0000000..e210108
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/ath9k_platform.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _LINUX_ATH9K_PLATFORM_H
+#define _LINUX_ATH9K_PLATFORM_H
+
+#define ATH9K_PLAT_EEP_MAX_WORDS	2048
+
+struct ath9k_platform_data {
+	const char *eeprom_name;
+
+	u16 eeprom_data[ATH9K_PLAT_EEP_MAX_WORDS];
+	u8 *macaddr;
+
+	int led_pin;
+	u32 gpio_mask;
+	u32 gpio_val;
+
+	u32 bt_active_pin;
+	u32 bt_priority_pin;
+	u32 wlan_active_pin;
+
+	bool endian_check;
+	bool is_clk_25mhz;
+	bool tx_gain_buffalo;
+	bool disable_2ghz;
+	bool disable_5ghz;
+	bool led_active_high;
+
+	int (*get_mac_revision)(void);
+	int (*external_reset)(void);
+
+	bool use_eeprom;
+
+	int num_leds;
+	const struct gpio_led *leds;
+
+	unsigned num_btns;
+	const struct gpio_keys_button *btns;
+	unsigned btn_poll_interval;
+};
+
+#endif /* _LINUX_ATH9K_PLATFORM_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/myloader.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/myloader.h
new file mode 100644
index 0000000..d89e415
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/myloader.h
@@ -0,0 +1,121 @@
+/*
+ *  Compex's MyLoader specific definitions
+ *
+ *  Copyright (C) 2006-2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#ifndef _MYLOADER_H_
+#define _MYLOADER_H_
+
+/* Myloader specific magic numbers */
+#define MYLO_MAGIC_SYS_PARAMS	0x20021107
+#define MYLO_MAGIC_PARTITIONS	0x20021103
+#define MYLO_MAGIC_BOARD_PARAMS	0x20021103
+
+/* Vendor ID's (seems to be same as the PCI vendor ID's) */
+#define VENID_COMPEX		0x11F6
+
+/* Devices based on the ADM5120 */
+#define DEVID_COMPEX_NP27G	0x0078
+#define DEVID_COMPEX_NP28G	0x044C
+#define DEVID_COMPEX_NP28GHS	0x044E
+#define DEVID_COMPEX_WP54Gv1C	0x0514
+#define DEVID_COMPEX_WP54G	0x0515
+#define DEVID_COMPEX_WP54AG	0x0546
+#define DEVID_COMPEX_WPP54AG	0x0550
+#define DEVID_COMPEX_WPP54G	0x0555
+
+/* Devices based on the Atheros AR2317 */
+#define DEVID_COMPEX_NP25G	0x05E6
+#define DEVID_COMPEX_WPE53G	0x05DC
+
+/* Devices based on the Atheros AR71xx */
+#define DEVID_COMPEX_WP543	0x0640
+#define DEVID_COMPEX_WPE72	0x0672
+
+/* Devices based on the IXP422 */
+#define DEVID_COMPEX_WP18	0x047E
+#define DEVID_COMPEX_NP18A	0x0489
+
+/* Other devices */
+#define DEVID_COMPEX_NP26G8M	0x03E8
+#define DEVID_COMPEX_NP26G16M	0x03E9
+
+struct mylo_partition {
+	uint16_t	flags;	/* partition flags */
+	uint16_t	type;	/* type of the partition */
+	uint32_t	addr;	/* relative address of the partition from the
+				   flash start */
+	uint32_t	size;	/* size of the partition in bytes */
+	uint32_t	param;	/* if this is the active partition, the
+				   MyLoader load code to this address */
+};
+
+#define PARTITION_FLAG_ACTIVE	0x8000 /* this is the active partition,
+					* MyLoader loads firmware from here */
+#define PARTITION_FLAG_ISRAM	0x2000 /* FIXME: this is a RAM partition? */
+#define PARTIIION_FLAG_RAMLOAD	0x1000 /* FIXME: load this partition into the RAM? */
+#define PARTITION_FLAG_PRELOAD	0x0800 /* the partition data preloaded to RAM
+					* before decompression */
+#define PARTITION_FLAG_LZMA	0x0100 /* partition data compressed by LZMA */
+#define PARTITION_FLAG_HAVEHDR  0x0002 /* the partition data have a header */
+
+#define PARTITION_TYPE_FREE	0
+#define PARTITION_TYPE_USED	1
+
+#define MYLO_MAX_PARTITIONS	8	/* maximum number of partitions in the
+					   partition table */
+
+struct mylo_partition_table {
+	uint32_t	magic;		/* must be MYLO_MAGIC_PARTITIONS */
+	uint32_t	res0;		/* unknown/unused */
+	uint32_t	res1;		/* unknown/unused */
+	uint32_t 	res2;		/* unknown/unused */
+	struct mylo_partition partitions[MYLO_MAX_PARTITIONS];
+};
+
+struct mylo_partition_header {
+	uint32_t	len;		/* length of the partition data */
+	uint32_t	crc;		/* CRC value of the partition data */
+};
+
+struct mylo_system_params {
+	uint32_t	magic;		/* must be MYLO_MAGIC_SYS_PARAMS */
+	uint32_t	res0;
+	uint32_t	res1;
+	uint32_t	mylo_ver;
+	uint16_t	vid;		/* Vendor ID */
+	uint16_t	did;		/* Device ID */
+	uint16_t	svid;		/* Sub Vendor ID */
+	uint16_t	sdid;		/* Sub Device ID */
+	uint32_t	rev;		/* device revision */
+	uint32_t	fwhi;
+	uint32_t	fwlo;
+	uint32_t	tftp_addr;
+	uint32_t	prog_start;
+	uint32_t	flash_size;	/* size of boot FLASH in bytes */
+	uint32_t	dram_size;	/* size of onboard RAM in bytes */
+};
+
+struct mylo_eth_addr {
+	uint8_t	mac[6];
+	uint8_t	csum[2];
+};
+
+#define MYLO_ETHADDR_COUNT	8	/* maximum number of ethernet address
+					   in the board parameters */
+
+struct mylo_board_params {
+	uint32_t	magic;	/* must be MYLO_MAGIC_BOARD_PARAMS */
+	uint32_t	res0;
+	uint32_t	res1;
+	uint32_t	res2;
+	struct mylo_eth_addr addr[MYLO_ETHADDR_COUNT];
+};
+
+#endif /* _MYLOADER_H_*/
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/platform_data/adm6996-gpio.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/platform_data/adm6996-gpio.h
new file mode 100644
index 0000000..d5af9bb
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/platform_data/adm6996-gpio.h
@@ -0,0 +1,29 @@
+/*
+ * ADM6996 GPIO platform data
+ *
+ * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation
+ */
+
+#ifndef __PLATFORM_ADM6996_GPIO_H
+#define __PLATFORM_ADM6996_GPIO_H
+
+#include <linux/kernel.h>
+
+enum adm6996_model {
+	ADM6996FC = 1,
+	ADM6996M = 2,
+	ADM6996L = 3,
+};
+
+struct adm6996_gpio_platform_data {
+	u8 eecs;
+	u8 eesk;
+	u8 eedi;
+	enum adm6996_model model;
+};
+
+#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/routerboot.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/routerboot.h
new file mode 100644
index 0000000..3cda858
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/routerboot.h
@@ -0,0 +1,106 @@
+/*
+ *  Mikrotik's RouterBOOT definitions
+ *
+ *  Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#ifndef _ROUTERBOOT_H
+#define _ROUTERBOOT_H
+
+#define RB_MAC_SIZE		6
+
+/*
+ * Magic numbers
+ */
+#define RB_MAGIC_HARD	0x64726148 /* "Hard" */
+#define RB_MAGIC_SOFT	0x74666F53 /* "Soft" */
+#define RB_MAGIC_DAWN	0x6E776144 /* "Dawn" */
+
+#define RB_ID_TERMINATOR	0
+
+/*
+ * ID values for Hardware settings
+ */
+#define RB_ID_HARD_01		1
+#define RB_ID_HARD_02		2
+#define RB_ID_FLASH_INFO	3
+#define RB_ID_MAC_ADDRESS_PACK	4
+#define RB_ID_BOARD_NAME	5
+#define RB_ID_BIOS_VERSION	6
+#define RB_ID_HARD_07		7
+#define RB_ID_SDRAM_TIMINGS	8
+#define RB_ID_DEVICE_TIMINGS	9
+#define RB_ID_SOFTWARE_ID	10
+#define RB_ID_SERIAL_NUMBER	11
+#define RB_ID_HARD_12		12
+#define RB_ID_MEMORY_SIZE	13
+#define RB_ID_MAC_ADDRESS_COUNT	14
+#define RB_ID_HW_OPTIONS	21
+#define RB_ID_WLAN_DATA		22
+
+/*
+ * ID values for Software settings
+ */
+#define RB_ID_UART_SPEED	1
+#define RB_ID_BOOT_DELAY	2
+#define RB_ID_BOOT_DEVICE	3
+#define RB_ID_BOOT_KEY		4
+#define RB_ID_CPU_MODE		5
+#define RB_ID_FW_VERSION	6
+#define RB_ID_SOFT_07		7
+#define RB_ID_SOFT_08		8
+#define RB_ID_BOOT_PROTOCOL	9
+#define RB_ID_SOFT_10		10
+#define RB_ID_SOFT_11		11
+
+/*
+ * UART_SPEED values
+ */
+#define RB_UART_SPEED_115200	0
+#define RB_UART_SPEED_57600	1
+#define RB_UART_SPEED_38400	2
+#define RB_UART_SPEED_19200	3
+#define RB_UART_SPEED_9600	4
+#define RB_UART_SPEED_4800	5
+#define RB_UART_SPEED_2400	6
+#define RB_UART_SPEED_1200	7
+
+/*
+ * BOOT_DELAY values
+ */
+#define RB_BOOT_DELAY_0SEC	0
+#define RB_BOOT_DELAY_1SEC	1
+#define RB_BOOT_DELAY_2SEC	2
+
+/*
+ * BOOT_DEVICE values
+ */
+#define RB_BOOT_DEVICE_ETHER	0
+#define RB_BOOT_DEVICE_NANDETH	1
+#define RB_BOOT_DEVICE_ETHONCE	2
+#define RB_BOOT_DEVICE_NANDONLY	3
+
+/*
+ * BOOT_KEY values
+ */
+#define RB_BOOT_KEY_ANY		0
+#define RB_BOOT_KEY_DEL		1
+
+/*
+ * CPU_MODE values
+ */
+#define RB_CPU_MODE_POWERSAVE	0
+#define RB_CPU_MODE_REGULAR	1
+
+/*
+ * BOOT_PROTOCOL values
+ */
+#define RB_BOOT_PROTOCOL_BOOTP	0
+#define RB_BOOT_PROTOCOL_DHCP	1
+
+#endif /* _ROUTERBOOT_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/rt2x00_platform.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/rt2x00_platform.h
new file mode 100644
index 0000000..e10377e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/rt2x00_platform.h
@@ -0,0 +1,23 @@
+/*
+ * Platform data definition for the rt2x00 driver
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#ifndef _RT2X00_PLATFORM_H
+#define _RT2X00_PLATFORM_H
+
+struct rt2x00_platform_data {
+	char *eeprom_file_name;
+	const u8 *mac_address;
+
+	int disable_2ghz;
+	int disable_5ghz;
+};
+
+#endif /* _RT2X00_PLATFORM_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/rtl8366.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/rtl8366.h
new file mode 100644
index 0000000..e3ce8f5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/rtl8366.h
@@ -0,0 +1,42 @@
+/*
+ * Platform data definition for the Realtek RTL8366RB/S ethernet switch driver
+ *
+ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef _RTL8366_H
+#define _RTL8366_H
+
+#define RTL8366_DRIVER_NAME	"rtl8366"
+#define RTL8366S_DRIVER_NAME	"rtl8366s"
+#define RTL8366RB_DRIVER_NAME	"rtl8366rb"
+
+struct rtl8366_smi;
+
+enum rtl8366_type {
+	RTL8366_TYPE_UNKNOWN,
+	RTL8366_TYPE_S,
+	RTL8366_TYPE_RB,
+};
+
+struct rtl8366_initval {
+	unsigned	reg;
+	u16		val;
+};
+
+struct rtl8366_platform_data {
+	unsigned	gpio_sda;
+	unsigned	gpio_sck;
+	void		(*hw_reset)(struct rtl8366_smi *smi, bool active);
+
+	unsigned	num_initvals;
+	struct rtl8366_initval *initvals;
+};
+
+enum rtl8366_type rtl8366_smi_detect(struct rtl8366_platform_data *pdata);
+
+#endif /*  _RTL8366_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/rtl8367.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/rtl8367.h
new file mode 100644
index 0000000..1415039
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/rtl8367.h
@@ -0,0 +1,63 @@
+/*
+ * Platform data definition for the Realtek RTL8367 ethernet switch driver
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef _RTL8367_H
+#define _RTL8367_H
+
+#define RTL8367_DRIVER_NAME	"rtl8367"
+#define RTL8367B_DRIVER_NAME	"rtl8367b"
+
+enum rtl8367_port_speed {
+	RTL8367_PORT_SPEED_10 = 0,
+	RTL8367_PORT_SPEED_100,
+	RTL8367_PORT_SPEED_1000,
+};
+
+struct rtl8367_port_ability {
+	int force_mode;
+	int nway;
+	int txpause;
+	int rxpause;
+	int link;
+	int duplex;
+	enum rtl8367_port_speed speed;
+};
+
+enum rtl8367_extif_mode {
+	RTL8367_EXTIF_MODE_DISABLED = 0,
+	RTL8367_EXTIF_MODE_RGMII,
+	RTL8367_EXTIF_MODE_MII_MAC,
+	RTL8367_EXTIF_MODE_MII_PHY,
+	RTL8367_EXTIF_MODE_TMII_MAC,
+	RTL8367_EXTIF_MODE_TMII_PHY,
+	RTL8367_EXTIF_MODE_GMII,
+	RTL8367_EXTIF_MODE_RGMII_33V,
+	RTL8367B_EXTIF_MODE_RMII_MAC = 7,
+	RTL8367B_EXTIF_MODE_RMII_PHY,
+	RTL8367B_EXTIF_MODE_RGMII_33V,
+};
+
+struct rtl8367_extif_config {
+	unsigned int txdelay;
+	unsigned int rxdelay;
+	enum rtl8367_extif_mode mode;
+	struct rtl8367_port_ability ability;
+};
+
+struct rtl8367_platform_data {
+	unsigned gpio_sda;
+	unsigned gpio_sck;
+	void (*hw_reset)(bool active);
+
+	struct rtl8367_extif_config *extif0_cfg;
+	struct rtl8367_extif_config *extif1_cfg;
+};
+
+#endif /*  _RTL8367_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/switch.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/switch.h
new file mode 100644
index 0000000..4e62384
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/linux/switch.h
@@ -0,0 +1,179 @@
+/*
+ * switch.h: Switch configuration API
+ *
+ * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _LINUX_SWITCH_H
+#define _LINUX_SWITCH_H
+
+#include <net/genetlink.h>
+#include <uapi/linux/switch.h>
+
+struct switch_dev;
+struct switch_op;
+struct switch_val;
+struct switch_attr;
+struct switch_attrlist;
+struct switch_led_trigger;
+
+int register_switch(struct switch_dev *dev, struct net_device *netdev);
+void unregister_switch(struct switch_dev *dev);
+
+/**
+ * struct switch_attrlist - attribute list
+ *
+ * @n_attr: number of attributes
+ * @attr: pointer to the attributes array
+ */
+struct switch_attrlist {
+	int n_attr;
+	const struct switch_attr *attr;
+};
+
+enum switch_port_speed {
+	SWITCH_PORT_SPEED_UNKNOWN = 0,
+	SWITCH_PORT_SPEED_10 = 10,
+	SWITCH_PORT_SPEED_100 = 100,
+	SWITCH_PORT_SPEED_1000 = 1000,
+};
+
+struct switch_port_link {
+	bool link;
+	bool duplex;
+	bool aneg;
+	bool tx_flow;
+	bool rx_flow;
+	enum switch_port_speed speed;
+	/* in ethtool adv_t format */
+	u32 eee;
+};
+
+struct switch_port_stats {
+	unsigned long long tx_bytes;
+	unsigned long long rx_bytes;
+};
+
+/**
+ * struct switch_dev_ops - switch driver operations
+ *
+ * @attr_global: global switch attribute list
+ * @attr_port: port attribute list
+ * @attr_vlan: vlan attribute list
+ *
+ * Callbacks:
+ *
+ * @get_vlan_ports: read the port list of a VLAN
+ * @set_vlan_ports: set the port list of a VLAN
+ *
+ * @get_port_pvid: get the primary VLAN ID of a port
+ * @set_port_pvid: set the primary VLAN ID of a port
+ *
+ * @apply_config: apply all changed settings to the switch
+ * @reset_switch: resetting the switch
+ */
+struct switch_dev_ops {
+	struct switch_attrlist attr_global, attr_port, attr_vlan;
+
+	int (*get_vlan_ports)(struct switch_dev *dev, struct switch_val *val);
+	int (*set_vlan_ports)(struct switch_dev *dev, struct switch_val *val);
+
+	int (*get_port_pvid)(struct switch_dev *dev, int port, int *val);
+	int (*set_port_pvid)(struct switch_dev *dev, int port, int val);
+
+	int (*apply_config)(struct switch_dev *dev);
+	int (*reset_switch)(struct switch_dev *dev);
+
+	int (*get_port_link)(struct switch_dev *dev, int port,
+			     struct switch_port_link *link);
+	int (*set_port_link)(struct switch_dev *dev, int port,
+			     struct switch_port_link *link);
+	int (*get_port_stats)(struct switch_dev *dev, int port,
+			      struct switch_port_stats *stats);
+
+	int (*phy_read16)(struct switch_dev *dev, int addr, u8 reg, u16 *value);
+	int (*phy_write16)(struct switch_dev *dev, int addr, u8 reg, u16 value);
+};
+
+struct switch_dev {
+	struct device_node *of_node;
+	const struct switch_dev_ops *ops;
+	/* will be automatically filled */
+	char devname[IFNAMSIZ];
+
+	const char *name;
+	/* NB: either alias or netdev must be set */
+	const char *alias;
+	struct net_device *netdev;
+
+	unsigned int ports;
+	unsigned int vlans;
+	unsigned int cpu_port;
+
+	/* the following fields are internal for swconfig */
+	unsigned int id;
+	struct list_head dev_list;
+	unsigned long def_global, def_port, def_vlan;
+
+	struct mutex sw_mutex;
+	struct switch_port *portbuf;
+	struct switch_portmap *portmap;
+	struct switch_port_link linkbuf;
+
+	char buf[128];
+
+#ifdef CONFIG_SWCONFIG_LEDS
+	struct switch_led_trigger *led_trigger;
+#endif
+};
+
+struct switch_port {
+	u32 id;
+	u32 flags;
+};
+
+struct switch_portmap {
+	u32 virt;
+	const char *s;
+};
+
+struct switch_val {
+	const struct switch_attr *attr;
+	unsigned int port_vlan;
+	unsigned int len;
+	union {
+		const char *s;
+		u32 i;
+		struct switch_port *ports;
+		struct switch_port_link *link;
+	} value;
+};
+
+struct switch_attr {
+	int disabled;
+	int type;
+	const char *name;
+	const char *description;
+
+	int (*set)(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val);
+	int (*get)(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val);
+
+	/* for driver internal use */
+	int id;
+	int ofs;
+	int max;
+};
+
+int switch_generic_set_link(struct switch_dev *dev, int port,
+			    struct switch_port_link *link);
+
+#endif /* _LINUX_SWITCH_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/uapi/linux/switch.h b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/uapi/linux/switch.h
new file mode 100644
index 0000000..ea44965
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/files/include/uapi/linux/switch.h
@@ -0,0 +1,119 @@
+/*
+ * switch.h: Switch configuration API
+ *
+ * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _UAPI_LINUX_SWITCH_H
+#define _UAPI_LINUX_SWITCH_H
+
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/netlink.h>
+#include <linux/genetlink.h>
+#ifndef __KERNEL__
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/ctrl.h>
+#endif
+
+/* main attributes */
+enum {
+	SWITCH_ATTR_UNSPEC,
+	/* global */
+	SWITCH_ATTR_TYPE,
+	/* device */
+	SWITCH_ATTR_ID,
+	SWITCH_ATTR_DEV_NAME,
+	SWITCH_ATTR_ALIAS,
+	SWITCH_ATTR_NAME,
+	SWITCH_ATTR_VLANS,
+	SWITCH_ATTR_PORTS,
+	SWITCH_ATTR_PORTMAP,
+	SWITCH_ATTR_CPU_PORT,
+	/* attributes */
+	SWITCH_ATTR_OP_ID,
+	SWITCH_ATTR_OP_TYPE,
+	SWITCH_ATTR_OP_NAME,
+	SWITCH_ATTR_OP_PORT,
+	SWITCH_ATTR_OP_VLAN,
+	SWITCH_ATTR_OP_VALUE_INT,
+	SWITCH_ATTR_OP_VALUE_STR,
+	SWITCH_ATTR_OP_VALUE_PORTS,
+	SWITCH_ATTR_OP_VALUE_LINK,
+	SWITCH_ATTR_OP_DESCRIPTION,
+	/* port lists */
+	SWITCH_ATTR_PORT,
+	SWITCH_ATTR_MAX
+};
+
+enum {
+	/* port map */
+	SWITCH_PORTMAP_PORTS,
+	SWITCH_PORTMAP_SEGMENT,
+	SWITCH_PORTMAP_VIRT,
+	SWITCH_PORTMAP_MAX
+};
+
+/* commands */
+enum {
+	SWITCH_CMD_UNSPEC,
+	SWITCH_CMD_GET_SWITCH,
+	SWITCH_CMD_NEW_ATTR,
+	SWITCH_CMD_LIST_GLOBAL,
+	SWITCH_CMD_GET_GLOBAL,
+	SWITCH_CMD_SET_GLOBAL,
+	SWITCH_CMD_LIST_PORT,
+	SWITCH_CMD_GET_PORT,
+	SWITCH_CMD_SET_PORT,
+	SWITCH_CMD_LIST_VLAN,
+	SWITCH_CMD_GET_VLAN,
+	SWITCH_CMD_SET_VLAN
+};
+
+/* data types */
+enum switch_val_type {
+	SWITCH_TYPE_UNSPEC,
+	SWITCH_TYPE_INT,
+	SWITCH_TYPE_STRING,
+	SWITCH_TYPE_PORTS,
+	SWITCH_TYPE_LINK,
+	SWITCH_TYPE_NOVAL,
+};
+
+/* port nested attributes */
+enum {
+	SWITCH_PORT_UNSPEC,
+	SWITCH_PORT_ID,
+	SWITCH_PORT_FLAG_TAGGED,
+	SWITCH_PORT_ATTR_MAX
+};
+
+/* link nested attributes */
+enum {
+	SWITCH_LINK_UNSPEC,
+	SWITCH_LINK_FLAG_LINK,
+	SWITCH_LINK_FLAG_DUPLEX,
+	SWITCH_LINK_FLAG_ANEG,
+	SWITCH_LINK_FLAG_TX_FLOW,
+	SWITCH_LINK_FLAG_RX_FLOW,
+	SWITCH_LINK_SPEED,
+	SWITCH_LINK_FLAG_EEE_100BASET,
+	SWITCH_LINK_FLAG_EEE_1000BASET,
+	SWITCH_LINK_ATTR_MAX,
+};
+
+#define SWITCH_ATTR_DEFAULTS_OFFSET	0x1000
+
+
+#endif /* _UAPI_LINUX_SWITCH_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/204-module_strip.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/204-module_strip.patch
new file mode 100644
index 0000000..ef7beae
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/204-module_strip.patch
@@ -0,0 +1,204 @@
+From a779a482fb9b9f8fcdf8b2519c789b4b9bb5dd05 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 7 Jul 2017 16:56:48 +0200
+Subject: build: add a hack for removing non-essential module info
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ include/linux/module.h      | 13 ++++++++-----
+ include/linux/moduleparam.h | 15 ++++++++++++---
+ init/Kconfig                |  7 +++++++
+ kernel/module.c             |  5 ++++-
+ scripts/mod/modpost.c       | 12 ++++++++++++
+ 5 files changed, 43 insertions(+), 9 deletions(-)
+
+--- a/include/linux/module.h
++++ b/include/linux/module.h
+@@ -157,6 +157,7 @@ extern void cleanup_module(void);
+ 
+ /* Generic info of form tag = "info" */
+ #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
++#define MODULE_INFO_STRIP(tag, info) __MODULE_INFO_STRIP(tag, tag, info)
+ 
+ /* For userspace: you can also call me... */
+ #define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias)
+@@ -216,12 +217,12 @@ extern void cleanup_module(void);
+  * Author(s), use "Name <email>" or just "Name", for multiple
+  * authors use multiple MODULE_AUTHOR() statements/lines.
+  */
+-#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
++#define MODULE_AUTHOR(_author) MODULE_INFO_STRIP(author, _author)
+ 
+ /* What your module does. */
+-#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)
++#define MODULE_DESCRIPTION(_description) MODULE_INFO_STRIP(description, _description)
+ 
+-#ifdef MODULE
++#if defined(MODULE) && !defined(CONFIG_MODULE_STRIPPED)
+ /* Creates an alias so file2alias.c can find device table. */
+ #define MODULE_DEVICE_TABLE(type, name)					\
+ extern typeof(name) __mod_##type##__##name##_device_table		\
+@@ -248,7 +249,9 @@ extern typeof(name) __mod_##type##__##na
+  */
+ 
+ #if defined(MODULE) || !defined(CONFIG_SYSFS)
+-#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
++#define MODULE_VERSION(_version) MODULE_INFO_STRIP(version, _version)
++#elif defined(CONFIG_MODULE_STRIPPED)
++#define MODULE_VERSION(_version) __MODULE_INFO_DISABLED(version)
+ #else
+ #define MODULE_VERSION(_version)					\
+ 	MODULE_INFO(version, _version);					\
+@@ -271,7 +274,7 @@ extern typeof(name) __mod_##type##__##na
+ /* Optional firmware file (or files) needed by the module
+  * format is simply firmware file name.  Multiple firmware
+  * files require multiple MODULE_FIRMWARE() specifiers */
+-#define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware)
++#define MODULE_FIRMWARE(_firmware) MODULE_INFO_STRIP(firmware, _firmware)
+ 
+ #define MODULE_IMPORT_NS(ns) MODULE_INFO(import_ns, #ns)
+ 
+--- a/include/linux/moduleparam.h
++++ b/include/linux/moduleparam.h
+@@ -20,10 +20,24 @@
+ /* Chosen so that structs with an unsigned long line up. */
+ #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long))
+ 
++/* This struct is here for syntactic coherency, it is not used */
++#define __MODULE_INFO_DISABLED(name)					  \
++  struct __UNIQUE_ID(name) {}
++
++#ifdef CONFIG_MODULE_STRIPPED
++#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO_DISABLED(name)
++#else
++#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO(tag, name, info)
++#endif
++
++#ifdef MODULE
+ #define __MODULE_INFO(tag, name, info)					  \
+ static const char __UNIQUE_ID(name)[]					  \
+   __used __attribute__((section(".modinfo"), unused, aligned(1)))	  \
+   = __MODULE_INFO_PREFIX __stringify(tag) "=" info
++#else
++#define __MODULE_INFO(tag, name, info) __MODULE_INFO_DISABLED(name)
++#endif
+ 
+ #define __MODULE_PARM_TYPE(name, _type)					  \
+   __MODULE_INFO(parmtype, name##type, #name ":" _type)
+@@ -31,7 +45,7 @@ static const char __UNIQUE_ID(name)[]
+ /* One for each parameter, describing how to use it.  Some files do
+    multiple of these per line, so can't just use MODULE_INFO. */
+ #define MODULE_PARM_DESC(_parm, desc) \
+-	__MODULE_INFO(parm, _parm, #_parm ":" desc)
++	__MODULE_INFO_STRIP(parm, _parm, #_parm ":" desc)
+ 
+ struct kernel_param;
+ 
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -2208,6 +2208,13 @@ config TRIM_UNUSED_KSYMS
+ 
+ 	  If unsure, or if you need to build out-of-tree modules, say N.
+ 
++config MODULE_STRIPPED
++	bool "Reduce module size"
++	depends on MODULES
++	help
++	  Remove module parameter descriptions, author info, version, aliases,
++	  device tables, etc.
++
+ endif # MODULES
+ 
+ config MODULES_TREE_LOOKUP
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -3256,9 +3256,11 @@ static int setup_load_info(struct load_i
+ 
+ static int check_modinfo(struct module *mod, struct load_info *info, int flags)
+ {
+-	const char *modmagic = get_modinfo(info, "vermagic");
+ 	int err;
+ 
++#ifndef CONFIG_MODULE_STRIPPED
++	const char *modmagic = get_modinfo(info, "vermagic");
++
+ 	if (flags & MODULE_INIT_IGNORE_VERMAGIC)
+ 		modmagic = NULL;
+ 
+@@ -3279,6 +3281,7 @@ static int check_modinfo(struct module *
+ 				mod->name);
+ 		add_taint_module(mod, TAINT_OOT_MODULE, LOCKDEP_STILL_OK);
+ 	}
++#endif
+ 
+ 	check_modinfo_retpoline(mod, info);
+ 
+--- a/scripts/mod/modpost.c
++++ b/scripts/mod/modpost.c
+@@ -2056,7 +2056,9 @@ static void read_symbols(const char *mod
+ 		symname = remove_dot(info.strtab + sym->st_name);
+ 
+ 		handle_modversions(mod, &info, sym, symname);
++#ifndef CONFIG_MODULE_STRIPPED
+ 		handle_moddevtable(mod, &info, sym, symname);
++#endif
+ 	}
+ 
+ 	/* Apply symbol namespaces from __kstrtabns_<symbol> entries. */
+@@ -2270,8 +2272,10 @@ static void add_header(struct buffer *b,
+ 	buf_printf(b, "\n");
+ 	buf_printf(b, "BUILD_SALT;\n");
+ 	buf_printf(b, "\n");
++#ifndef CONFIG_MODULE_STRIPPED
+ 	buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
+ 	buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
++#endif
+ 	buf_printf(b, "\n");
+ 	buf_printf(b, "__visible struct module __this_module\n");
+ 	buf_printf(b, "__section(.gnu.linkonce.this_module) = {\n");
+@@ -2288,8 +2292,10 @@ static void add_header(struct buffer *b,
+ 
+ static void add_intree_flag(struct buffer *b, int is_intree)
+ {
++#ifndef CONFIG_MODULE_STRIPPED
+ 	if (is_intree)
+ 		buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
++#endif
+ }
+ 
+ /* Cannot check for assembler */
+@@ -2302,8 +2308,10 @@ static void add_retpoline(struct buffer
+ 
+ static void add_staging_flag(struct buffer *b, const char *name)
+ {
++#ifndef CONFIG_MODULE_STRIPPED
+ 	if (strstarts(name, "drivers/staging"))
+ 		buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
++#endif
+ }
+ 
+ /**
+@@ -2387,11 +2395,13 @@ static void add_depends(struct buffer *b
+ 
+ static void add_srcversion(struct buffer *b, struct module *mod)
+ {
++#ifndef CONFIG_MODULE_STRIPPED
+ 	if (mod->srcversion[0]) {
+ 		buf_printf(b, "\n");
+ 		buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
+ 			   mod->srcversion);
+ 	}
++#endif
+ }
+ 
+ static void write_if_changed(struct buffer *b, const char *fname)
+@@ -2661,7 +2671,9 @@ int main(int argc, char **argv)
+ 		add_staging_flag(&buf, mod->name);
+ 		err |= add_versions(&buf, mod);
+ 		add_depends(&buf, mod);
++#ifndef CONFIG_MODULE_STRIPPED
+ 		add_moddevtable(&buf, mod);
++#endif
+ 		add_srcversion(&buf, mod);
+ 
+ 		sprintf(fname, "%s.mod.c", mod->name);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/210-darwin_scripts_include.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/210-darwin_scripts_include.patch
new file mode 100644
index 0000000..be6adc0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/210-darwin_scripts_include.patch
@@ -0,0 +1,3053 @@
+From db7c30dcd9a0391bf13b62c9f91e144d762ef43a Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <f.fainelli@gmail.com>
+Date: Fri, 7 Jul 2017 17:00:49 +0200
+Subject: Add an OSX specific patch to make the kernel be compiled
+
+lede-commit: 3fc2a24f0422b2f55f9ed43f116db3111f700526
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+---
+ scripts/kconfig/Makefile   |    3 +
+ scripts/mod/elf.h          | 3007 ++++++++++++++++++++++++++++++++++++++++++++
+ scripts/mod/mk_elfconfig.c |    4 +
+ scripts/mod/modpost.h      |    4 +
+ 4 files changed, 3018 insertions(+)
+ create mode 100644 scripts/mod/elf.h
+
+--- /dev/null
++++ b/scripts/mod/elf.h
+@@ -0,0 +1,3007 @@
++/* This file defines standard ELF types, structures, and macros.
++   Copyright (C) 1995-2012 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#ifndef _ELF_H
++#define	_ELF_H 1
++
++/* Standard ELF types.  */
++
++#include <stdint.h>
++
++/* Type for a 16-bit quantity.  */
++typedef uint16_t Elf32_Half;
++typedef uint16_t Elf64_Half;
++
++/* Types for signed and unsigned 32-bit quantities.  */
++typedef uint32_t Elf32_Word;
++typedef	int32_t  Elf32_Sword;
++typedef uint32_t Elf64_Word;
++typedef	int32_t  Elf64_Sword;
++
++/* Types for signed and unsigned 64-bit quantities.  */
++typedef uint64_t Elf32_Xword;
++typedef	int64_t  Elf32_Sxword;
++typedef uint64_t Elf64_Xword;
++typedef	int64_t  Elf64_Sxword;
++
++/* Type of addresses.  */
++typedef uint32_t Elf32_Addr;
++typedef uint64_t Elf64_Addr;
++
++/* Type of file offsets.  */
++typedef uint32_t Elf32_Off;
++typedef uint64_t Elf64_Off;
++
++/* Type for section indices, which are 16-bit quantities.  */
++typedef uint16_t Elf32_Section;
++typedef uint16_t Elf64_Section;
++
++/* Type for version symbol information.  */
++typedef Elf32_Half Elf32_Versym;
++typedef Elf64_Half Elf64_Versym;
++
++
++/* The ELF file header.  This appears at the start of every ELF file.  */
++
++#define EI_NIDENT (16)
++
++typedef struct
++{
++  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
++  Elf32_Half	e_type;			/* Object file type */
++  Elf32_Half	e_machine;		/* Architecture */
++  Elf32_Word	e_version;		/* Object file version */
++  Elf32_Addr	e_entry;		/* Entry point virtual address */
++  Elf32_Off	e_phoff;		/* Program header table file offset */
++  Elf32_Off	e_shoff;		/* Section header table file offset */
++  Elf32_Word	e_flags;		/* Processor-specific flags */
++  Elf32_Half	e_ehsize;		/* ELF header size in bytes */
++  Elf32_Half	e_phentsize;		/* Program header table entry size */
++  Elf32_Half	e_phnum;		/* Program header table entry count */
++  Elf32_Half	e_shentsize;		/* Section header table entry size */
++  Elf32_Half	e_shnum;		/* Section header table entry count */
++  Elf32_Half	e_shstrndx;		/* Section header string table index */
++} Elf32_Ehdr;
++
++typedef struct
++{
++  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
++  Elf64_Half	e_type;			/* Object file type */
++  Elf64_Half	e_machine;		/* Architecture */
++  Elf64_Word	e_version;		/* Object file version */
++  Elf64_Addr	e_entry;		/* Entry point virtual address */
++  Elf64_Off	e_phoff;		/* Program header table file offset */
++  Elf64_Off	e_shoff;		/* Section header table file offset */
++  Elf64_Word	e_flags;		/* Processor-specific flags */
++  Elf64_Half	e_ehsize;		/* ELF header size in bytes */
++  Elf64_Half	e_phentsize;		/* Program header table entry size */
++  Elf64_Half	e_phnum;		/* Program header table entry count */
++  Elf64_Half	e_shentsize;		/* Section header table entry size */
++  Elf64_Half	e_shnum;		/* Section header table entry count */
++  Elf64_Half	e_shstrndx;		/* Section header string table index */
++} Elf64_Ehdr;
++
++/* Fields in the e_ident array.  The EI_* macros are indices into the
++   array.  The macros under each EI_* macro are the values the byte
++   may have.  */
++
++#define EI_MAG0		0		/* File identification byte 0 index */
++#define ELFMAG0		0x7f		/* Magic number byte 0 */
++
++#define EI_MAG1		1		/* File identification byte 1 index */
++#define ELFMAG1		'E'		/* Magic number byte 1 */
++
++#define EI_MAG2		2		/* File identification byte 2 index */
++#define ELFMAG2		'L'		/* Magic number byte 2 */
++
++#define EI_MAG3		3		/* File identification byte 3 index */
++#define ELFMAG3		'F'		/* Magic number byte 3 */
++
++/* Conglomeration of the identification bytes, for easy testing as a word.  */
++#define	ELFMAG		"\177ELF"
++#define	SELFMAG		4
++
++#define EI_CLASS	4		/* File class byte index */
++#define ELFCLASSNONE	0		/* Invalid class */
++#define ELFCLASS32	1		/* 32-bit objects */
++#define ELFCLASS64	2		/* 64-bit objects */
++#define ELFCLASSNUM	3
++
++#define EI_DATA		5		/* Data encoding byte index */
++#define ELFDATANONE	0		/* Invalid data encoding */
++#define ELFDATA2LSB	1		/* 2's complement, little endian */
++#define ELFDATA2MSB	2		/* 2's complement, big endian */
++#define ELFDATANUM	3
++
++#define EI_VERSION	6		/* File version byte index */
++					/* Value must be EV_CURRENT */
++
++#define EI_OSABI	7		/* OS ABI identification */
++#define ELFOSABI_NONE		0	/* UNIX System V ABI */
++#define ELFOSABI_SYSV		0	/* Alias.  */
++#define ELFOSABI_HPUX		1	/* HP-UX */
++#define ELFOSABI_NETBSD		2	/* NetBSD.  */
++#define ELFOSABI_GNU		3	/* Object uses GNU ELF extensions.  */
++#define ELFOSABI_LINUX		ELFOSABI_GNU /* Compatibility alias.  */
++#define ELFOSABI_SOLARIS	6	/* Sun Solaris.  */
++#define ELFOSABI_AIX		7	/* IBM AIX.  */
++#define ELFOSABI_IRIX		8	/* SGI Irix.  */
++#define ELFOSABI_FREEBSD	9	/* FreeBSD.  */
++#define ELFOSABI_TRU64		10	/* Compaq TRU64 UNIX.  */
++#define ELFOSABI_MODESTO	11	/* Novell Modesto.  */
++#define ELFOSABI_OPENBSD	12	/* OpenBSD.  */
++#define ELFOSABI_ARM_AEABI	64	/* ARM EABI */
++#define ELFOSABI_ARM		97	/* ARM */
++#define ELFOSABI_STANDALONE	255	/* Standalone (embedded) application */
++
++#define EI_ABIVERSION	8		/* ABI version */
++
++#define EI_PAD		9		/* Byte index of padding bytes */
++
++/* Legal values for e_type (object file type).  */
++
++#define ET_NONE		0		/* No file type */
++#define ET_REL		1		/* Relocatable file */
++#define ET_EXEC		2		/* Executable file */
++#define ET_DYN		3		/* Shared object file */
++#define ET_CORE		4		/* Core file */
++#define	ET_NUM		5		/* Number of defined types */
++#define ET_LOOS		0xfe00		/* OS-specific range start */
++#define ET_HIOS		0xfeff		/* OS-specific range end */
++#define ET_LOPROC	0xff00		/* Processor-specific range start */
++#define ET_HIPROC	0xffff		/* Processor-specific range end */
++
++/* Legal values for e_machine (architecture).  */
++
++#define EM_NONE		 0		/* No machine */
++#define EM_M32		 1		/* AT&T WE 32100 */
++#define EM_SPARC	 2		/* SUN SPARC */
++#define EM_386		 3		/* Intel 80386 */
++#define EM_68K		 4		/* Motorola m68k family */
++#define EM_88K		 5		/* Motorola m88k family */
++#define EM_860		 7		/* Intel 80860 */
++#define EM_MIPS		 8		/* MIPS R3000 big-endian */
++#define EM_S370		 9		/* IBM System/370 */
++#define EM_MIPS_RS3_LE	10		/* MIPS R3000 little-endian */
++
++#define EM_PARISC	15		/* HPPA */
++#define EM_VPP500	17		/* Fujitsu VPP500 */
++#define EM_SPARC32PLUS	18		/* Sun's "v8plus" */
++#define EM_960		19		/* Intel 80960 */
++#define EM_PPC		20		/* PowerPC */
++#define EM_PPC64	21		/* PowerPC 64-bit */
++#define EM_S390		22		/* IBM S390 */
++
++#define EM_V800		36		/* NEC V800 series */
++#define EM_FR20		37		/* Fujitsu FR20 */
++#define EM_RH32		38		/* TRW RH-32 */
++#define EM_RCE		39		/* Motorola RCE */
++#define EM_ARM		40		/* ARM */
++#define EM_FAKE_ALPHA	41		/* Digital Alpha */
++#define EM_SH		42		/* Hitachi SH */
++#define EM_SPARCV9	43		/* SPARC v9 64-bit */
++#define EM_TRICORE	44		/* Siemens Tricore */
++#define EM_ARC		45		/* Argonaut RISC Core */
++#define EM_H8_300	46		/* Hitachi H8/300 */
++#define EM_H8_300H	47		/* Hitachi H8/300H */
++#define EM_H8S		48		/* Hitachi H8S */
++#define EM_H8_500	49		/* Hitachi H8/500 */
++#define EM_IA_64	50		/* Intel Merced */
++#define EM_MIPS_X	51		/* Stanford MIPS-X */
++#define EM_COLDFIRE	52		/* Motorola Coldfire */
++#define EM_68HC12	53		/* Motorola M68HC12 */
++#define EM_MMA		54		/* Fujitsu MMA Multimedia Accelerator*/
++#define EM_PCP		55		/* Siemens PCP */
++#define EM_NCPU		56		/* Sony nCPU embeeded RISC */
++#define EM_NDR1		57		/* Denso NDR1 microprocessor */
++#define EM_STARCORE	58		/* Motorola Start*Core processor */
++#define EM_ME16		59		/* Toyota ME16 processor */
++#define EM_ST100	60		/* STMicroelectronic ST100 processor */
++#define EM_TINYJ	61		/* Advanced Logic Corp. Tinyj emb.fam*/
++#define EM_X86_64	62		/* AMD x86-64 architecture */
++#define EM_PDSP		63		/* Sony DSP Processor */
++
++#define EM_FX66		66		/* Siemens FX66 microcontroller */
++#define EM_ST9PLUS	67		/* STMicroelectronics ST9+ 8/16 mc */
++#define EM_ST7		68		/* STmicroelectronics ST7 8 bit mc */
++#define EM_68HC16	69		/* Motorola MC68HC16 microcontroller */
++#define EM_68HC11	70		/* Motorola MC68HC11 microcontroller */
++#define EM_68HC08	71		/* Motorola MC68HC08 microcontroller */
++#define EM_68HC05	72		/* Motorola MC68HC05 microcontroller */
++#define EM_SVX		73		/* Silicon Graphics SVx */
++#define EM_ST19		74		/* STMicroelectronics ST19 8 bit mc */
++#define EM_VAX		75		/* Digital VAX */
++#define EM_CRIS		76		/* Axis Communications 32-bit embedded processor */
++#define EM_JAVELIN	77		/* Infineon Technologies 32-bit embedded processor */
++#define EM_FIREPATH	78		/* Element 14 64-bit DSP Processor */
++#define EM_ZSP		79		/* LSI Logic 16-bit DSP Processor */
++#define EM_MMIX		80		/* Donald Knuth's educational 64-bit processor */
++#define EM_HUANY	81		/* Harvard University machine-independent object files */
++#define EM_PRISM	82		/* SiTera Prism */
++#define EM_AVR		83		/* Atmel AVR 8-bit microcontroller */
++#define EM_FR30		84		/* Fujitsu FR30 */
++#define EM_D10V		85		/* Mitsubishi D10V */
++#define EM_D30V		86		/* Mitsubishi D30V */
++#define EM_V850		87		/* NEC v850 */
++#define EM_M32R		88		/* Mitsubishi M32R */
++#define EM_MN10300	89		/* Matsushita MN10300 */
++#define EM_MN10200	90		/* Matsushita MN10200 */
++#define EM_PJ		91		/* picoJava */
++#define EM_OPENRISC	92		/* OpenRISC 32-bit embedded processor */
++#define EM_ARC_A5	93		/* ARC Cores Tangent-A5 */
++#define EM_XTENSA	94		/* Tensilica Xtensa Architecture */
++#define EM_TILEPRO	188		/* Tilera TILEPro */
++#define EM_TILEGX	191		/* Tilera TILE-Gx */
++#define EM_NUM		192
++
++/* If it is necessary to assign new unofficial EM_* values, please
++   pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
++   chances of collision with official or non-GNU unofficial values.  */
++
++#define EM_ALPHA	0x9026
++
++/* Legal values for e_version (version).  */
++
++#define EV_NONE		0		/* Invalid ELF version */
++#define EV_CURRENT	1		/* Current version */
++#define EV_NUM		2
++
++/* Section header.  */
++
++typedef struct
++{
++  Elf32_Word	sh_name;		/* Section name (string tbl index) */
++  Elf32_Word	sh_type;		/* Section type */
++  Elf32_Word	sh_flags;		/* Section flags */
++  Elf32_Addr	sh_addr;		/* Section virtual addr at execution */
++  Elf32_Off	sh_offset;		/* Section file offset */
++  Elf32_Word	sh_size;		/* Section size in bytes */
++  Elf32_Word	sh_link;		/* Link to another section */
++  Elf32_Word	sh_info;		/* Additional section information */
++  Elf32_Word	sh_addralign;		/* Section alignment */
++  Elf32_Word	sh_entsize;		/* Entry size if section holds table */
++} Elf32_Shdr;
++
++typedef struct
++{
++  Elf64_Word	sh_name;		/* Section name (string tbl index) */
++  Elf64_Word	sh_type;		/* Section type */
++  Elf64_Xword	sh_flags;		/* Section flags */
++  Elf64_Addr	sh_addr;		/* Section virtual addr at execution */
++  Elf64_Off	sh_offset;		/* Section file offset */
++  Elf64_Xword	sh_size;		/* Section size in bytes */
++  Elf64_Word	sh_link;		/* Link to another section */
++  Elf64_Word	sh_info;		/* Additional section information */
++  Elf64_Xword	sh_addralign;		/* Section alignment */
++  Elf64_Xword	sh_entsize;		/* Entry size if section holds table */
++} Elf64_Shdr;
++
++/* Special section indices.  */
++
++#define SHN_UNDEF	0		/* Undefined section */
++#define SHN_LORESERVE	0xff00		/* Start of reserved indices */
++#define SHN_LOPROC	0xff00		/* Start of processor-specific */
++#define SHN_BEFORE	0xff00		/* Order section before all others
++					   (Solaris).  */
++#define SHN_AFTER	0xff01		/* Order section after all others
++					   (Solaris).  */
++#define SHN_HIPROC	0xff1f		/* End of processor-specific */
++#define SHN_LOOS	0xff20		/* Start of OS-specific */
++#define SHN_HIOS	0xff3f		/* End of OS-specific */
++#define SHN_ABS		0xfff1		/* Associated symbol is absolute */
++#define SHN_COMMON	0xfff2		/* Associated symbol is common */
++#define SHN_XINDEX	0xffff		/* Index is in extra table.  */
++#define SHN_HIRESERVE	0xffff		/* End of reserved indices */
++
++/* Legal values for sh_type (section type).  */
++
++#define SHT_NULL	  0		/* Section header table entry unused */
++#define SHT_PROGBITS	  1		/* Program data */
++#define SHT_SYMTAB	  2		/* Symbol table */
++#define SHT_STRTAB	  3		/* String table */
++#define SHT_RELA	  4		/* Relocation entries with addends */
++#define SHT_HASH	  5		/* Symbol hash table */
++#define SHT_DYNAMIC	  6		/* Dynamic linking information */
++#define SHT_NOTE	  7		/* Notes */
++#define SHT_NOBITS	  8		/* Program space with no data (bss) */
++#define SHT_REL		  9		/* Relocation entries, no addends */
++#define SHT_SHLIB	  10		/* Reserved */
++#define SHT_DYNSYM	  11		/* Dynamic linker symbol table */
++#define SHT_INIT_ARRAY	  14		/* Array of constructors */
++#define SHT_FINI_ARRAY	  15		/* Array of destructors */
++#define SHT_PREINIT_ARRAY 16		/* Array of pre-constructors */
++#define SHT_GROUP	  17		/* Section group */
++#define SHT_SYMTAB_SHNDX  18		/* Extended section indeces */
++#define	SHT_NUM		  19		/* Number of defined types.  */
++#define SHT_LOOS	  0x60000000	/* Start OS-specific.  */
++#define SHT_GNU_ATTRIBUTES 0x6ffffff5	/* Object attributes.  */
++#define SHT_GNU_HASH	  0x6ffffff6	/* GNU-style hash table.  */
++#define SHT_GNU_LIBLIST	  0x6ffffff7	/* Prelink library list */
++#define SHT_CHECKSUM	  0x6ffffff8	/* Checksum for DSO content.  */
++#define SHT_LOSUNW	  0x6ffffffa	/* Sun-specific low bound.  */
++#define SHT_SUNW_move	  0x6ffffffa
++#define SHT_SUNW_COMDAT   0x6ffffffb
++#define SHT_SUNW_syminfo  0x6ffffffc
++#define SHT_GNU_verdef	  0x6ffffffd	/* Version definition section.  */
++#define SHT_GNU_verneed	  0x6ffffffe	/* Version needs section.  */
++#define SHT_GNU_versym	  0x6fffffff	/* Version symbol table.  */
++#define SHT_HISUNW	  0x6fffffff	/* Sun-specific high bound.  */
++#define SHT_HIOS	  0x6fffffff	/* End OS-specific type */
++#define SHT_LOPROC	  0x70000000	/* Start of processor-specific */
++#define SHT_HIPROC	  0x7fffffff	/* End of processor-specific */
++#define SHT_LOUSER	  0x80000000	/* Start of application-specific */
++#define SHT_HIUSER	  0x8fffffff	/* End of application-specific */
++
++/* Legal values for sh_flags (section flags).  */
++
++#define SHF_WRITE	     (1 << 0)	/* Writable */
++#define SHF_ALLOC	     (1 << 1)	/* Occupies memory during execution */
++#define SHF_EXECINSTR	     (1 << 2)	/* Executable */
++#define SHF_MERGE	     (1 << 4)	/* Might be merged */
++#define SHF_STRINGS	     (1 << 5)	/* Contains nul-terminated strings */
++#define SHF_INFO_LINK	     (1 << 6)	/* `sh_info' contains SHT index */
++#define SHF_LINK_ORDER	     (1 << 7)	/* Preserve order after combining */
++#define SHF_OS_NONCONFORMING (1 << 8)	/* Non-standard OS specific handling
++					   required */
++#define SHF_GROUP	     (1 << 9)	/* Section is member of a group.  */
++#define SHF_TLS		     (1 << 10)	/* Section hold thread-local data.  */
++#define SHF_MASKOS	     0x0ff00000	/* OS-specific.  */
++#define SHF_MASKPROC	     0xf0000000	/* Processor-specific */
++#define SHF_ORDERED	     (1 << 30)	/* Special ordering requirement
++					   (Solaris).  */
++#define SHF_EXCLUDE	     (1 << 31)	/* Section is excluded unless
++					   referenced or allocated (Solaris).*/
++
++/* Section group handling.  */
++#define GRP_COMDAT	0x1		/* Mark group as COMDAT.  */
++
++/* Symbol table entry.  */
++
++typedef struct
++{
++  Elf32_Word	st_name;		/* Symbol name (string tbl index) */
++  Elf32_Addr	st_value;		/* Symbol value */
++  Elf32_Word	st_size;		/* Symbol size */
++  unsigned char	st_info;		/* Symbol type and binding */
++  unsigned char	st_other;		/* Symbol visibility */
++  Elf32_Section	st_shndx;		/* Section index */
++} Elf32_Sym;
++
++typedef struct
++{
++  Elf64_Word	st_name;		/* Symbol name (string tbl index) */
++  unsigned char	st_info;		/* Symbol type and binding */
++  unsigned char st_other;		/* Symbol visibility */
++  Elf64_Section	st_shndx;		/* Section index */
++  Elf64_Addr	st_value;		/* Symbol value */
++  Elf64_Xword	st_size;		/* Symbol size */
++} Elf64_Sym;
++
++/* The syminfo section if available contains additional information about
++   every dynamic symbol.  */
++
++typedef struct
++{
++  Elf32_Half si_boundto;		/* Direct bindings, symbol bound to */
++  Elf32_Half si_flags;			/* Per symbol flags */
++} Elf32_Syminfo;
++
++typedef struct
++{
++  Elf64_Half si_boundto;		/* Direct bindings, symbol bound to */
++  Elf64_Half si_flags;			/* Per symbol flags */
++} Elf64_Syminfo;
++
++/* Possible values for si_boundto.  */
++#define SYMINFO_BT_SELF		0xffff	/* Symbol bound to self */
++#define SYMINFO_BT_PARENT	0xfffe	/* Symbol bound to parent */
++#define SYMINFO_BT_LOWRESERVE	0xff00	/* Beginning of reserved entries */
++
++/* Possible bitmasks for si_flags.  */
++#define SYMINFO_FLG_DIRECT	0x0001	/* Direct bound symbol */
++#define SYMINFO_FLG_PASSTHRU	0x0002	/* Pass-thru symbol for translator */
++#define SYMINFO_FLG_COPY	0x0004	/* Symbol is a copy-reloc */
++#define SYMINFO_FLG_LAZYLOAD	0x0008	/* Symbol bound to object to be lazy
++					   loaded */
++/* Syminfo version values.  */
++#define SYMINFO_NONE		0
++#define SYMINFO_CURRENT		1
++#define SYMINFO_NUM		2
++
++
++/* How to extract and insert information held in the st_info field.  */
++
++#define ELF32_ST_BIND(val)		(((unsigned char) (val)) >> 4)
++#define ELF32_ST_TYPE(val)		((val) & 0xf)
++#define ELF32_ST_INFO(bind, type)	(((bind) << 4) + ((type) & 0xf))
++
++/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field.  */
++#define ELF64_ST_BIND(val)		ELF32_ST_BIND (val)
++#define ELF64_ST_TYPE(val)		ELF32_ST_TYPE (val)
++#define ELF64_ST_INFO(bind, type)	ELF32_ST_INFO ((bind), (type))
++
++/* Legal values for ST_BIND subfield of st_info (symbol binding).  */
++
++#define STB_LOCAL	0		/* Local symbol */
++#define STB_GLOBAL	1		/* Global symbol */
++#define STB_WEAK	2		/* Weak symbol */
++#define	STB_NUM		3		/* Number of defined types.  */
++#define STB_LOOS	10		/* Start of OS-specific */
++#define STB_GNU_UNIQUE	10		/* Unique symbol.  */
++#define STB_HIOS	12		/* End of OS-specific */
++#define STB_LOPROC	13		/* Start of processor-specific */
++#define STB_HIPROC	15		/* End of processor-specific */
++
++/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
++
++#define STT_NOTYPE	0		/* Symbol type is unspecified */
++#define STT_OBJECT	1		/* Symbol is a data object */
++#define STT_FUNC	2		/* Symbol is a code object */
++#define STT_SECTION	3		/* Symbol associated with a section */
++#define STT_FILE	4		/* Symbol's name is file name */
++#define STT_COMMON	5		/* Symbol is a common data object */
++#define STT_TLS		6		/* Symbol is thread-local data object*/
++#define	STT_NUM		7		/* Number of defined types.  */
++#define STT_LOOS	10		/* Start of OS-specific */
++#define STT_GNU_IFUNC	10		/* Symbol is indirect code object */
++#define STT_HIOS	12		/* End of OS-specific */
++#define STT_LOPROC	13		/* Start of processor-specific */
++#define STT_HIPROC	15		/* End of processor-specific */
++
++
++/* Symbol table indices are found in the hash buckets and chain table
++   of a symbol hash table section.  This special index value indicates
++   the end of a chain, meaning no further symbols are found in that bucket.  */
++
++#define STN_UNDEF	0		/* End of a chain.  */
++
++
++/* How to extract and insert information held in the st_other field.  */
++
++#define ELF32_ST_VISIBILITY(o)	((o) & 0x03)
++
++/* For ELF64 the definitions are the same.  */
++#define ELF64_ST_VISIBILITY(o)	ELF32_ST_VISIBILITY (o)
++
++/* Symbol visibility specification encoded in the st_other field.  */
++#define STV_DEFAULT	0		/* Default symbol visibility rules */
++#define STV_INTERNAL	1		/* Processor specific hidden class */
++#define STV_HIDDEN	2		/* Sym unavailable in other modules */
++#define STV_PROTECTED	3		/* Not preemptible, not exported */
++
++
++/* Relocation table entry without addend (in section of type SHT_REL).  */
++
++typedef struct
++{
++  Elf32_Addr	r_offset;		/* Address */
++  Elf32_Word	r_info;			/* Relocation type and symbol index */
++} Elf32_Rel;
++
++/* I have seen two different definitions of the Elf64_Rel and
++   Elf64_Rela structures, so we'll leave them out until Novell (or
++   whoever) gets their act together.  */
++/* The following, at least, is used on Sparc v9, MIPS, and Alpha.  */
++
++typedef struct
++{
++  Elf64_Addr	r_offset;		/* Address */
++  Elf64_Xword	r_info;			/* Relocation type and symbol index */
++} Elf64_Rel;
++
++/* Relocation table entry with addend (in section of type SHT_RELA).  */
++
++typedef struct
++{
++  Elf32_Addr	r_offset;		/* Address */
++  Elf32_Word	r_info;			/* Relocation type and symbol index */
++  Elf32_Sword	r_addend;		/* Addend */
++} Elf32_Rela;
++
++typedef struct
++{
++  Elf64_Addr	r_offset;		/* Address */
++  Elf64_Xword	r_info;			/* Relocation type and symbol index */
++  Elf64_Sxword	r_addend;		/* Addend */
++} Elf64_Rela;
++
++/* How to extract and insert information held in the r_info field.  */
++
++#define ELF32_R_SYM(val)		((val) >> 8)
++#define ELF32_R_TYPE(val)		((val) & 0xff)
++#define ELF32_R_INFO(sym, type)		(((sym) << 8) + ((type) & 0xff))
++
++#define ELF64_R_SYM(i)			((i) >> 32)
++#define ELF64_R_TYPE(i)			((i) & 0xffffffff)
++#define ELF64_R_INFO(sym,type)		((((Elf64_Xword) (sym)) << 32) + (type))
++
++/* Program segment header.  */
++
++typedef struct
++{
++  Elf32_Word	p_type;			/* Segment type */
++  Elf32_Off	p_offset;		/* Segment file offset */
++  Elf32_Addr	p_vaddr;		/* Segment virtual address */
++  Elf32_Addr	p_paddr;		/* Segment physical address */
++  Elf32_Word	p_filesz;		/* Segment size in file */
++  Elf32_Word	p_memsz;		/* Segment size in memory */
++  Elf32_Word	p_flags;		/* Segment flags */
++  Elf32_Word	p_align;		/* Segment alignment */
++} Elf32_Phdr;
++
++typedef struct
++{
++  Elf64_Word	p_type;			/* Segment type */
++  Elf64_Word	p_flags;		/* Segment flags */
++  Elf64_Off	p_offset;		/* Segment file offset */
++  Elf64_Addr	p_vaddr;		/* Segment virtual address */
++  Elf64_Addr	p_paddr;		/* Segment physical address */
++  Elf64_Xword	p_filesz;		/* Segment size in file */
++  Elf64_Xword	p_memsz;		/* Segment size in memory */
++  Elf64_Xword	p_align;		/* Segment alignment */
++} Elf64_Phdr;
++
++/* Special value for e_phnum.  This indicates that the real number of
++   program headers is too large to fit into e_phnum.  Instead the real
++   value is in the field sh_info of section 0.  */
++
++#define PN_XNUM		0xffff
++
++/* Legal values for p_type (segment type).  */
++
++#define	PT_NULL		0		/* Program header table entry unused */
++#define PT_LOAD		1		/* Loadable program segment */
++#define PT_DYNAMIC	2		/* Dynamic linking information */
++#define PT_INTERP	3		/* Program interpreter */
++#define PT_NOTE		4		/* Auxiliary information */
++#define PT_SHLIB	5		/* Reserved */
++#define PT_PHDR		6		/* Entry for header table itself */
++#define PT_TLS		7		/* Thread-local storage segment */
++#define	PT_NUM		8		/* Number of defined types */
++#define PT_LOOS		0x60000000	/* Start of OS-specific */
++#define PT_GNU_EH_FRAME	0x6474e550	/* GCC .eh_frame_hdr segment */
++#define PT_GNU_STACK	0x6474e551	/* Indicates stack executability */
++#define PT_GNU_RELRO	0x6474e552	/* Read-only after relocation */
++#define PT_LOSUNW	0x6ffffffa
++#define PT_SUNWBSS	0x6ffffffa	/* Sun Specific segment */
++#define PT_SUNWSTACK	0x6ffffffb	/* Stack segment */
++#define PT_HISUNW	0x6fffffff
++#define PT_HIOS		0x6fffffff	/* End of OS-specific */
++#define PT_LOPROC	0x70000000	/* Start of processor-specific */
++#define PT_HIPROC	0x7fffffff	/* End of processor-specific */
++
++/* Legal values for p_flags (segment flags).  */
++
++#define PF_X		(1 << 0)	/* Segment is executable */
++#define PF_W		(1 << 1)	/* Segment is writable */
++#define PF_R		(1 << 2)	/* Segment is readable */
++#define PF_MASKOS	0x0ff00000	/* OS-specific */
++#define PF_MASKPROC	0xf0000000	/* Processor-specific */
++
++/* Legal values for note segment descriptor types for core files. */
++
++#define NT_PRSTATUS	1		/* Contains copy of prstatus struct */
++#define NT_FPREGSET	2		/* Contains copy of fpregset struct */
++#define NT_PRPSINFO	3		/* Contains copy of prpsinfo struct */
++#define NT_PRXREG	4		/* Contains copy of prxregset struct */
++#define NT_TASKSTRUCT	4		/* Contains copy of task structure */
++#define NT_PLATFORM	5		/* String from sysinfo(SI_PLATFORM) */
++#define NT_AUXV		6		/* Contains copy of auxv array */
++#define NT_GWINDOWS	7		/* Contains copy of gwindows struct */
++#define NT_ASRS		8		/* Contains copy of asrset struct */
++#define NT_PSTATUS	10		/* Contains copy of pstatus struct */
++#define NT_PSINFO	13		/* Contains copy of psinfo struct */
++#define NT_PRCRED	14		/* Contains copy of prcred struct */
++#define NT_UTSNAME	15		/* Contains copy of utsname struct */
++#define NT_LWPSTATUS	16		/* Contains copy of lwpstatus struct */
++#define NT_LWPSINFO	17		/* Contains copy of lwpinfo struct */
++#define NT_PRFPXREG	20		/* Contains copy of fprxregset struct */
++#define NT_PRXFPREG	0x46e62b7f	/* Contains copy of user_fxsr_struct */
++#define NT_PPC_VMX	0x100		/* PowerPC Altivec/VMX registers */
++#define NT_PPC_SPE	0x101		/* PowerPC SPE/EVR registers */
++#define NT_PPC_VSX	0x102		/* PowerPC VSX registers */
++#define NT_386_TLS	0x200		/* i386 TLS slots (struct user_desc) */
++#define NT_386_IOPERM	0x201		/* x86 io permission bitmap (1=deny) */
++#define NT_X86_XSTATE	0x202		/* x86 extended state using xsave */
++
++/* Legal values for the note segment descriptor types for object files.  */
++
++#define NT_VERSION	1		/* Contains a version string.  */
++
++
++/* Dynamic section entry.  */
++
++typedef struct
++{
++  Elf32_Sword	d_tag;			/* Dynamic entry type */
++  union
++    {
++      Elf32_Word d_val;			/* Integer value */
++      Elf32_Addr d_ptr;			/* Address value */
++    } d_un;
++} Elf32_Dyn;
++
++typedef struct
++{
++  Elf64_Sxword	d_tag;			/* Dynamic entry type */
++  union
++    {
++      Elf64_Xword d_val;		/* Integer value */
++      Elf64_Addr d_ptr;			/* Address value */
++    } d_un;
++} Elf64_Dyn;
++
++/* Legal values for d_tag (dynamic entry type).  */
++
++#define DT_NULL		0		/* Marks end of dynamic section */
++#define DT_NEEDED	1		/* Name of needed library */
++#define DT_PLTRELSZ	2		/* Size in bytes of PLT relocs */
++#define DT_PLTGOT	3		/* Processor defined value */
++#define DT_HASH		4		/* Address of symbol hash table */
++#define DT_STRTAB	5		/* Address of string table */
++#define DT_SYMTAB	6		/* Address of symbol table */
++#define DT_RELA		7		/* Address of Rela relocs */
++#define DT_RELASZ	8		/* Total size of Rela relocs */
++#define DT_RELAENT	9		/* Size of one Rela reloc */
++#define DT_STRSZ	10		/* Size of string table */
++#define DT_SYMENT	11		/* Size of one symbol table entry */
++#define DT_INIT		12		/* Address of init function */
++#define DT_FINI		13		/* Address of termination function */
++#define DT_SONAME	14		/* Name of shared object */
++#define DT_RPATH	15		/* Library search path (deprecated) */
++#define DT_SYMBOLIC	16		/* Start symbol search here */
++#define DT_REL		17		/* Address of Rel relocs */
++#define DT_RELSZ	18		/* Total size of Rel relocs */
++#define DT_RELENT	19		/* Size of one Rel reloc */
++#define DT_PLTREL	20		/* Type of reloc in PLT */
++#define DT_DEBUG	21		/* For debugging; unspecified */
++#define DT_TEXTREL	22		/* Reloc might modify .text */
++#define DT_JMPREL	23		/* Address of PLT relocs */
++#define	DT_BIND_NOW	24		/* Process relocations of object */
++#define	DT_INIT_ARRAY	25		/* Array with addresses of init fct */
++#define	DT_FINI_ARRAY	26		/* Array with addresses of fini fct */
++#define	DT_INIT_ARRAYSZ	27		/* Size in bytes of DT_INIT_ARRAY */
++#define	DT_FINI_ARRAYSZ	28		/* Size in bytes of DT_FINI_ARRAY */
++#define DT_RUNPATH	29		/* Library search path */
++#define DT_FLAGS	30		/* Flags for the object being loaded */
++#define DT_ENCODING	32		/* Start of encoded range */
++#define DT_PREINIT_ARRAY 32		/* Array with addresses of preinit fct*/
++#define DT_PREINIT_ARRAYSZ 33		/* size in bytes of DT_PREINIT_ARRAY */
++#define	DT_NUM		34		/* Number used */
++#define DT_LOOS		0x6000000d	/* Start of OS-specific */
++#define DT_HIOS		0x6ffff000	/* End of OS-specific */
++#define DT_LOPROC	0x70000000	/* Start of processor-specific */
++#define DT_HIPROC	0x7fffffff	/* End of processor-specific */
++#define	DT_PROCNUM	DT_MIPS_NUM	/* Most used by any processor */
++
++/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
++   Dyn.d_un.d_val field of the Elf*_Dyn structure.  This follows Sun's
++   approach.  */
++#define DT_VALRNGLO	0x6ffffd00
++#define DT_GNU_PRELINKED 0x6ffffdf5	/* Prelinking timestamp */
++#define DT_GNU_CONFLICTSZ 0x6ffffdf6	/* Size of conflict section */
++#define DT_GNU_LIBLISTSZ 0x6ffffdf7	/* Size of library list */
++#define DT_CHECKSUM	0x6ffffdf8
++#define DT_PLTPADSZ	0x6ffffdf9
++#define DT_MOVEENT	0x6ffffdfa
++#define DT_MOVESZ	0x6ffffdfb
++#define DT_FEATURE_1	0x6ffffdfc	/* Feature selection (DTF_*).  */
++#define DT_POSFLAG_1	0x6ffffdfd	/* Flags for DT_* entries, effecting
++					   the following DT_* entry.  */
++#define DT_SYMINSZ	0x6ffffdfe	/* Size of syminfo table (in bytes) */
++#define DT_SYMINENT	0x6ffffdff	/* Entry size of syminfo */
++#define DT_VALRNGHI	0x6ffffdff
++#define DT_VALTAGIDX(tag)	(DT_VALRNGHI - (tag))	/* Reverse order! */
++#define DT_VALNUM 12
++
++/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
++   Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
++
++   If any adjustment is made to the ELF object after it has been
++   built these entries will need to be adjusted.  */
++#define DT_ADDRRNGLO	0x6ffffe00
++#define DT_GNU_HASH	0x6ffffef5	/* GNU-style hash table.  */
++#define DT_TLSDESC_PLT	0x6ffffef6
++#define DT_TLSDESC_GOT	0x6ffffef7
++#define DT_GNU_CONFLICT	0x6ffffef8	/* Start of conflict section */
++#define DT_GNU_LIBLIST	0x6ffffef9	/* Library list */
++#define DT_CONFIG	0x6ffffefa	/* Configuration information.  */
++#define DT_DEPAUDIT	0x6ffffefb	/* Dependency auditing.  */
++#define DT_AUDIT	0x6ffffefc	/* Object auditing.  */
++#define	DT_PLTPAD	0x6ffffefd	/* PLT padding.  */
++#define	DT_MOVETAB	0x6ffffefe	/* Move table.  */
++#define DT_SYMINFO	0x6ffffeff	/* Syminfo table.  */
++#define DT_ADDRRNGHI	0x6ffffeff
++#define DT_ADDRTAGIDX(tag)	(DT_ADDRRNGHI - (tag))	/* Reverse order! */
++#define DT_ADDRNUM 11
++
++/* The versioning entry types.  The next are defined as part of the
++   GNU extension.  */
++#define DT_VERSYM	0x6ffffff0
++
++#define DT_RELACOUNT	0x6ffffff9
++#define DT_RELCOUNT	0x6ffffffa
++
++/* These were chosen by Sun.  */
++#define DT_FLAGS_1	0x6ffffffb	/* State flags, see DF_1_* below.  */
++#define	DT_VERDEF	0x6ffffffc	/* Address of version definition
++					   table */
++#define	DT_VERDEFNUM	0x6ffffffd	/* Number of version definitions */
++#define	DT_VERNEED	0x6ffffffe	/* Address of table with needed
++					   versions */
++#define	DT_VERNEEDNUM	0x6fffffff	/* Number of needed versions */
++#define DT_VERSIONTAGIDX(tag)	(DT_VERNEEDNUM - (tag))	/* Reverse order! */
++#define DT_VERSIONTAGNUM 16
++
++/* Sun added these machine-independent extensions in the "processor-specific"
++   range.  Be compatible.  */
++#define DT_AUXILIARY    0x7ffffffd      /* Shared object to load before self */
++#define DT_FILTER       0x7fffffff      /* Shared object to get values from */
++#define DT_EXTRATAGIDX(tag)	((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1)
++#define DT_EXTRANUM	3
++
++/* Values of `d_un.d_val' in the DT_FLAGS entry.  */
++#define DF_ORIGIN	0x00000001	/* Object may use DF_ORIGIN */
++#define DF_SYMBOLIC	0x00000002	/* Symbol resolutions starts here */
++#define DF_TEXTREL	0x00000004	/* Object contains text relocations */
++#define DF_BIND_NOW	0x00000008	/* No lazy binding for this object */
++#define DF_STATIC_TLS	0x00000010	/* Module uses the static TLS model */
++
++/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1
++   entry in the dynamic section.  */
++#define DF_1_NOW	0x00000001	/* Set RTLD_NOW for this object.  */
++#define DF_1_GLOBAL	0x00000002	/* Set RTLD_GLOBAL for this object.  */
++#define DF_1_GROUP	0x00000004	/* Set RTLD_GROUP for this object.  */
++#define DF_1_NODELETE	0x00000008	/* Set RTLD_NODELETE for this object.*/
++#define DF_1_LOADFLTR	0x00000010	/* Trigger filtee loading at runtime.*/
++#define DF_1_INITFIRST	0x00000020	/* Set RTLD_INITFIRST for this object*/
++#define DF_1_NOOPEN	0x00000040	/* Set RTLD_NOOPEN for this object.  */
++#define DF_1_ORIGIN	0x00000080	/* $ORIGIN must be handled.  */
++#define DF_1_DIRECT	0x00000100	/* Direct binding enabled.  */
++#define DF_1_TRANS	0x00000200
++#define DF_1_INTERPOSE	0x00000400	/* Object is used to interpose.  */
++#define DF_1_NODEFLIB	0x00000800	/* Ignore default lib search path.  */
++#define DF_1_NODUMP	0x00001000	/* Object can't be dldump'ed.  */
++#define DF_1_CONFALT	0x00002000	/* Configuration alternative created.*/
++#define DF_1_ENDFILTEE	0x00004000	/* Filtee terminates filters search. */
++#define	DF_1_DISPRELDNE	0x00008000	/* Disp reloc applied at build time. */
++#define	DF_1_DISPRELPND	0x00010000	/* Disp reloc applied at run-time.  */
++
++/* Flags for the feature selection in DT_FEATURE_1.  */
++#define DTF_1_PARINIT	0x00000001
++#define DTF_1_CONFEXP	0x00000002
++
++/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry.  */
++#define DF_P1_LAZYLOAD	0x00000001	/* Lazyload following object.  */
++#define DF_P1_GROUPPERM	0x00000002	/* Symbols from next object are not
++					   generally available.  */
++
++/* Version definition sections.  */
++
++typedef struct
++{
++  Elf32_Half	vd_version;		/* Version revision */
++  Elf32_Half	vd_flags;		/* Version information */
++  Elf32_Half	vd_ndx;			/* Version Index */
++  Elf32_Half	vd_cnt;			/* Number of associated aux entries */
++  Elf32_Word	vd_hash;		/* Version name hash value */
++  Elf32_Word	vd_aux;			/* Offset in bytes to verdaux array */
++  Elf32_Word	vd_next;		/* Offset in bytes to next verdef
++					   entry */
++} Elf32_Verdef;
++
++typedef struct
++{
++  Elf64_Half	vd_version;		/* Version revision */
++  Elf64_Half	vd_flags;		/* Version information */
++  Elf64_Half	vd_ndx;			/* Version Index */
++  Elf64_Half	vd_cnt;			/* Number of associated aux entries */
++  Elf64_Word	vd_hash;		/* Version name hash value */
++  Elf64_Word	vd_aux;			/* Offset in bytes to verdaux array */
++  Elf64_Word	vd_next;		/* Offset in bytes to next verdef
++					   entry */
++} Elf64_Verdef;
++
++
++/* Legal values for vd_version (version revision).  */
++#define VER_DEF_NONE	0		/* No version */
++#define VER_DEF_CURRENT	1		/* Current version */
++#define VER_DEF_NUM	2		/* Given version number */
++
++/* Legal values for vd_flags (version information flags).  */
++#define VER_FLG_BASE	0x1		/* Version definition of file itself */
++#define VER_FLG_WEAK	0x2		/* Weak version identifier */
++
++/* Versym symbol index values.  */
++#define	VER_NDX_LOCAL		0	/* Symbol is local.  */
++#define	VER_NDX_GLOBAL		1	/* Symbol is global.  */
++#define	VER_NDX_LORESERVE	0xff00	/* Beginning of reserved entries.  */
++#define	VER_NDX_ELIMINATE	0xff01	/* Symbol is to be eliminated.  */
++
++/* Auxialiary version information.  */
++
++typedef struct
++{
++  Elf32_Word	vda_name;		/* Version or dependency names */
++  Elf32_Word	vda_next;		/* Offset in bytes to next verdaux
++					   entry */
++} Elf32_Verdaux;
++
++typedef struct
++{
++  Elf64_Word	vda_name;		/* Version or dependency names */
++  Elf64_Word	vda_next;		/* Offset in bytes to next verdaux
++					   entry */
++} Elf64_Verdaux;
++
++
++/* Version dependency section.  */
++
++typedef struct
++{
++  Elf32_Half	vn_version;		/* Version of structure */
++  Elf32_Half	vn_cnt;			/* Number of associated aux entries */
++  Elf32_Word	vn_file;		/* Offset of filename for this
++					   dependency */
++  Elf32_Word	vn_aux;			/* Offset in bytes to vernaux array */
++  Elf32_Word	vn_next;		/* Offset in bytes to next verneed
++					   entry */
++} Elf32_Verneed;
++
++typedef struct
++{
++  Elf64_Half	vn_version;		/* Version of structure */
++  Elf64_Half	vn_cnt;			/* Number of associated aux entries */
++  Elf64_Word	vn_file;		/* Offset of filename for this
++					   dependency */
++  Elf64_Word	vn_aux;			/* Offset in bytes to vernaux array */
++  Elf64_Word	vn_next;		/* Offset in bytes to next verneed
++					   entry */
++} Elf64_Verneed;
++
++
++/* Legal values for vn_version (version revision).  */
++#define VER_NEED_NONE	 0		/* No version */
++#define VER_NEED_CURRENT 1		/* Current version */
++#define VER_NEED_NUM	 2		/* Given version number */
++
++/* Auxiliary needed version information.  */
++
++typedef struct
++{
++  Elf32_Word	vna_hash;		/* Hash value of dependency name */
++  Elf32_Half	vna_flags;		/* Dependency specific information */
++  Elf32_Half	vna_other;		/* Unused */
++  Elf32_Word	vna_name;		/* Dependency name string offset */
++  Elf32_Word	vna_next;		/* Offset in bytes to next vernaux
++					   entry */
++} Elf32_Vernaux;
++
++typedef struct
++{
++  Elf64_Word	vna_hash;		/* Hash value of dependency name */
++  Elf64_Half	vna_flags;		/* Dependency specific information */
++  Elf64_Half	vna_other;		/* Unused */
++  Elf64_Word	vna_name;		/* Dependency name string offset */
++  Elf64_Word	vna_next;		/* Offset in bytes to next vernaux
++					   entry */
++} Elf64_Vernaux;
++
++
++/* Legal values for vna_flags.  */
++#define VER_FLG_WEAK	0x2		/* Weak version identifier */
++
++
++/* Auxiliary vector.  */
++
++/* This vector is normally only used by the program interpreter.  The
++   usual definition in an ABI supplement uses the name auxv_t.  The
++   vector is not usually defined in a standard <elf.h> file, but it
++   can't hurt.  We rename it to avoid conflicts.  The sizes of these
++   types are an arrangement between the exec server and the program
++   interpreter, so we don't fully specify them here.  */
++
++typedef struct
++{
++  uint32_t a_type;		/* Entry type */
++  union
++    {
++      uint32_t a_val;		/* Integer value */
++      /* We use to have pointer elements added here.  We cannot do that,
++	 though, since it does not work when using 32-bit definitions
++	 on 64-bit platforms and vice versa.  */
++    } a_un;
++} Elf32_auxv_t;
++
++typedef struct
++{
++  uint64_t a_type;		/* Entry type */
++  union
++    {
++      uint64_t a_val;		/* Integer value */
++      /* We use to have pointer elements added here.  We cannot do that,
++	 though, since it does not work when using 32-bit definitions
++	 on 64-bit platforms and vice versa.  */
++    } a_un;
++} Elf64_auxv_t;
++
++/* Legal values for a_type (entry type).  */
++
++#define AT_NULL		0		/* End of vector */
++#define AT_IGNORE	1		/* Entry should be ignored */
++#define AT_EXECFD	2		/* File descriptor of program */
++#define AT_PHDR		3		/* Program headers for program */
++#define AT_PHENT	4		/* Size of program header entry */
++#define AT_PHNUM	5		/* Number of program headers */
++#define AT_PAGESZ	6		/* System page size */
++#define AT_BASE		7		/* Base address of interpreter */
++#define AT_FLAGS	8		/* Flags */
++#define AT_ENTRY	9		/* Entry point of program */
++#define AT_NOTELF	10		/* Program is not ELF */
++#define AT_UID		11		/* Real uid */
++#define AT_EUID		12		/* Effective uid */
++#define AT_GID		13		/* Real gid */
++#define AT_EGID		14		/* Effective gid */
++#define AT_CLKTCK	17		/* Frequency of times() */
++
++/* Some more special a_type values describing the hardware.  */
++#define AT_PLATFORM	15		/* String identifying platform.  */
++#define AT_HWCAP	16		/* Machine dependent hints about
++					   processor capabilities.  */
++
++/* This entry gives some information about the FPU initialization
++   performed by the kernel.  */
++#define AT_FPUCW	18		/* Used FPU control word.  */
++
++/* Cache block sizes.  */
++#define AT_DCACHEBSIZE	19		/* Data cache block size.  */
++#define AT_ICACHEBSIZE	20		/* Instruction cache block size.  */
++#define AT_UCACHEBSIZE	21		/* Unified cache block size.  */
++
++/* A special ignored value for PPC, used by the kernel to control the
++   interpretation of the AUXV. Must be > 16.  */
++#define AT_IGNOREPPC	22		/* Entry should be ignored.  */
++
++#define	AT_SECURE	23		/* Boolean, was exec setuid-like?  */
++
++#define AT_BASE_PLATFORM 24		/* String identifying real platforms.*/
++
++#define AT_RANDOM	25		/* Address of 16 random bytes.  */
++
++#define AT_EXECFN	31		/* Filename of executable.  */
++
++/* Pointer to the global system page used for system calls and other
++   nice things.  */
++#define AT_SYSINFO	32
++#define AT_SYSINFO_EHDR	33
++
++/* Shapes of the caches.  Bits 0-3 contains associativity; bits 4-7 contains
++   log2 of line size; mask those to get cache size.  */
++#define AT_L1I_CACHESHAPE	34
++#define AT_L1D_CACHESHAPE	35
++#define AT_L2_CACHESHAPE	36
++#define AT_L3_CACHESHAPE	37
++
++/* Note section contents.  Each entry in the note section begins with
++   a header of a fixed form.  */
++
++typedef struct
++{
++  Elf32_Word n_namesz;			/* Length of the note's name.  */
++  Elf32_Word n_descsz;			/* Length of the note's descriptor.  */
++  Elf32_Word n_type;			/* Type of the note.  */
++} Elf32_Nhdr;
++
++typedef struct
++{
++  Elf64_Word n_namesz;			/* Length of the note's name.  */
++  Elf64_Word n_descsz;			/* Length of the note's descriptor.  */
++  Elf64_Word n_type;			/* Type of the note.  */
++} Elf64_Nhdr;
++
++/* Known names of notes.  */
++
++/* Solaris entries in the note section have this name.  */
++#define ELF_NOTE_SOLARIS	"SUNW Solaris"
++
++/* Note entries for GNU systems have this name.  */
++#define ELF_NOTE_GNU		"GNU"
++
++
++/* Defined types of notes for Solaris.  */
++
++/* Value of descriptor (one word) is desired pagesize for the binary.  */
++#define ELF_NOTE_PAGESIZE_HINT	1
++
++
++/* Defined note types for GNU systems.  */
++
++/* ABI information.  The descriptor consists of words:
++   word 0: OS descriptor
++   word 1: major version of the ABI
++   word 2: minor version of the ABI
++   word 3: subminor version of the ABI
++*/
++#define NT_GNU_ABI_TAG	1
++#define ELF_NOTE_ABI	NT_GNU_ABI_TAG /* Old name.  */
++
++/* Known OSes.  These values can appear in word 0 of an
++   NT_GNU_ABI_TAG note section entry.  */
++#define ELF_NOTE_OS_LINUX	0
++#define ELF_NOTE_OS_GNU		1
++#define ELF_NOTE_OS_SOLARIS2	2
++#define ELF_NOTE_OS_FREEBSD	3
++
++/* Synthetic hwcap information.  The descriptor begins with two words:
++   word 0: number of entries
++   word 1: bitmask of enabled entries
++   Then follow variable-length entries, one byte followed by a
++   '\0'-terminated hwcap name string.  The byte gives the bit
++   number to test if enabled, (1U << bit) & bitmask.  */
++#define NT_GNU_HWCAP	2
++
++/* Build ID bits as generated by ld --build-id.
++   The descriptor consists of any nonzero number of bytes.  */
++#define NT_GNU_BUILD_ID	3
++
++/* Version note generated by GNU gold containing a version string.  */
++#define NT_GNU_GOLD_VERSION	4
++
++
++/* Move records.  */
++typedef struct
++{
++  Elf32_Xword m_value;		/* Symbol value.  */
++  Elf32_Word m_info;		/* Size and index.  */
++  Elf32_Word m_poffset;		/* Symbol offset.  */
++  Elf32_Half m_repeat;		/* Repeat count.  */
++  Elf32_Half m_stride;		/* Stride info.  */
++} Elf32_Move;
++
++typedef struct
++{
++  Elf64_Xword m_value;		/* Symbol value.  */
++  Elf64_Xword m_info;		/* Size and index.  */
++  Elf64_Xword m_poffset;	/* Symbol offset.  */
++  Elf64_Half m_repeat;		/* Repeat count.  */
++  Elf64_Half m_stride;		/* Stride info.  */
++} Elf64_Move;
++
++/* Macro to construct move records.  */
++#define ELF32_M_SYM(info)	((info) >> 8)
++#define ELF32_M_SIZE(info)	((unsigned char) (info))
++#define ELF32_M_INFO(sym, size)	(((sym) << 8) + (unsigned char) (size))
++
++#define ELF64_M_SYM(info)	ELF32_M_SYM (info)
++#define ELF64_M_SIZE(info)	ELF32_M_SIZE (info)
++#define ELF64_M_INFO(sym, size)	ELF32_M_INFO (sym, size)
++
++
++/* Motorola 68k specific definitions.  */
++
++/* Values for Elf32_Ehdr.e_flags.  */
++#define EF_CPU32	0x00810000
++
++/* m68k relocs.  */
++
++#define R_68K_NONE	0		/* No reloc */
++#define R_68K_32	1		/* Direct 32 bit  */
++#define R_68K_16	2		/* Direct 16 bit  */
++#define R_68K_8		3		/* Direct 8 bit  */
++#define R_68K_PC32	4		/* PC relative 32 bit */
++#define R_68K_PC16	5		/* PC relative 16 bit */
++#define R_68K_PC8	6		/* PC relative 8 bit */
++#define R_68K_GOT32	7		/* 32 bit PC relative GOT entry */
++#define R_68K_GOT16	8		/* 16 bit PC relative GOT entry */
++#define R_68K_GOT8	9		/* 8 bit PC relative GOT entry */
++#define R_68K_GOT32O	10		/* 32 bit GOT offset */
++#define R_68K_GOT16O	11		/* 16 bit GOT offset */
++#define R_68K_GOT8O	12		/* 8 bit GOT offset */
++#define R_68K_PLT32	13		/* 32 bit PC relative PLT address */
++#define R_68K_PLT16	14		/* 16 bit PC relative PLT address */
++#define R_68K_PLT8	15		/* 8 bit PC relative PLT address */
++#define R_68K_PLT32O	16		/* 32 bit PLT offset */
++#define R_68K_PLT16O	17		/* 16 bit PLT offset */
++#define R_68K_PLT8O	18		/* 8 bit PLT offset */
++#define R_68K_COPY	19		/* Copy symbol at runtime */
++#define R_68K_GLOB_DAT	20		/* Create GOT entry */
++#define R_68K_JMP_SLOT	21		/* Create PLT entry */
++#define R_68K_RELATIVE	22		/* Adjust by program base */
++#define R_68K_TLS_GD32      25          /* 32 bit GOT offset for GD */
++#define R_68K_TLS_GD16      26          /* 16 bit GOT offset for GD */
++#define R_68K_TLS_GD8       27          /* 8 bit GOT offset for GD */
++#define R_68K_TLS_LDM32     28          /* 32 bit GOT offset for LDM */
++#define R_68K_TLS_LDM16     29          /* 16 bit GOT offset for LDM */
++#define R_68K_TLS_LDM8      30          /* 8 bit GOT offset for LDM */
++#define R_68K_TLS_LDO32     31          /* 32 bit module-relative offset */
++#define R_68K_TLS_LDO16     32          /* 16 bit module-relative offset */
++#define R_68K_TLS_LDO8      33          /* 8 bit module-relative offset */
++#define R_68K_TLS_IE32      34          /* 32 bit GOT offset for IE */
++#define R_68K_TLS_IE16      35          /* 16 bit GOT offset for IE */
++#define R_68K_TLS_IE8       36          /* 8 bit GOT offset for IE */
++#define R_68K_TLS_LE32      37          /* 32 bit offset relative to
++					   static TLS block */
++#define R_68K_TLS_LE16      38          /* 16 bit offset relative to
++					   static TLS block */
++#define R_68K_TLS_LE8       39          /* 8 bit offset relative to
++					   static TLS block */
++#define R_68K_TLS_DTPMOD32  40          /* 32 bit module number */
++#define R_68K_TLS_DTPREL32  41          /* 32 bit module-relative offset */
++#define R_68K_TLS_TPREL32   42          /* 32 bit TP-relative offset */
++/* Keep this the last entry.  */
++#define R_68K_NUM	43
++
++/* Intel 80386 specific definitions.  */
++
++/* i386 relocs.  */
++
++#define R_386_NONE	   0		/* No reloc */
++#define R_386_32	   1		/* Direct 32 bit  */
++#define R_386_PC32	   2		/* PC relative 32 bit */
++#define R_386_GOT32	   3		/* 32 bit GOT entry */
++#define R_386_PLT32	   4		/* 32 bit PLT address */
++#define R_386_COPY	   5		/* Copy symbol at runtime */
++#define R_386_GLOB_DAT	   6		/* Create GOT entry */
++#define R_386_JMP_SLOT	   7		/* Create PLT entry */
++#define R_386_RELATIVE	   8		/* Adjust by program base */
++#define R_386_GOTOFF	   9		/* 32 bit offset to GOT */
++#define R_386_GOTPC	   10		/* 32 bit PC relative offset to GOT */
++#define R_386_32PLT	   11
++#define R_386_TLS_TPOFF	   14		/* Offset in static TLS block */
++#define R_386_TLS_IE	   15		/* Address of GOT entry for static TLS
++					   block offset */
++#define R_386_TLS_GOTIE	   16		/* GOT entry for static TLS block
++					   offset */
++#define R_386_TLS_LE	   17		/* Offset relative to static TLS
++					   block */
++#define R_386_TLS_GD	   18		/* Direct 32 bit for GNU version of
++					   general dynamic thread local data */
++#define R_386_TLS_LDM	   19		/* Direct 32 bit for GNU version of
++					   local dynamic thread local data
++					   in LE code */
++#define R_386_16	   20
++#define R_386_PC16	   21
++#define R_386_8		   22
++#define R_386_PC8	   23
++#define R_386_TLS_GD_32	   24		/* Direct 32 bit for general dynamic
++					   thread local data */
++#define R_386_TLS_GD_PUSH  25		/* Tag for pushl in GD TLS code */
++#define R_386_TLS_GD_CALL  26		/* Relocation for call to
++					   __tls_get_addr() */
++#define R_386_TLS_GD_POP   27		/* Tag for popl in GD TLS code */
++#define R_386_TLS_LDM_32   28		/* Direct 32 bit for local dynamic
++					   thread local data in LE code */
++#define R_386_TLS_LDM_PUSH 29		/* Tag for pushl in LDM TLS code */
++#define R_386_TLS_LDM_CALL 30		/* Relocation for call to
++					   __tls_get_addr() in LDM code */
++#define R_386_TLS_LDM_POP  31		/* Tag for popl in LDM TLS code */
++#define R_386_TLS_LDO_32   32		/* Offset relative to TLS block */
++#define R_386_TLS_IE_32	   33		/* GOT entry for negated static TLS
++					   block offset */
++#define R_386_TLS_LE_32	   34		/* Negated offset relative to static
++					   TLS block */
++#define R_386_TLS_DTPMOD32 35		/* ID of module containing symbol */
++#define R_386_TLS_DTPOFF32 36		/* Offset in TLS block */
++#define R_386_TLS_TPOFF32  37		/* Negated offset in static TLS block */
++/* 38? */
++#define R_386_TLS_GOTDESC  39		/* GOT offset for TLS descriptor.  */
++#define R_386_TLS_DESC_CALL 40		/* Marker of call through TLS
++					   descriptor for
++					   relaxation.  */
++#define R_386_TLS_DESC     41		/* TLS descriptor containing
++					   pointer to code and to
++					   argument, returning the TLS
++					   offset for the symbol.  */
++#define R_386_IRELATIVE	   42		/* Adjust indirectly by program base */
++/* Keep this the last entry.  */
++#define R_386_NUM	   43
++
++/* SUN SPARC specific definitions.  */
++
++/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
++
++#define STT_SPARC_REGISTER	13	/* Global register reserved to app. */
++
++/* Values for Elf64_Ehdr.e_flags.  */
++
++#define EF_SPARCV9_MM		3
++#define EF_SPARCV9_TSO		0
++#define EF_SPARCV9_PSO		1
++#define EF_SPARCV9_RMO		2
++#define EF_SPARC_LEDATA		0x800000 /* little endian data */
++#define EF_SPARC_EXT_MASK	0xFFFF00
++#define EF_SPARC_32PLUS		0x000100 /* generic V8+ features */
++#define EF_SPARC_SUN_US1	0x000200 /* Sun UltraSPARC1 extensions */
++#define EF_SPARC_HAL_R1		0x000400 /* HAL R1 extensions */
++#define EF_SPARC_SUN_US3	0x000800 /* Sun UltraSPARCIII extensions */
++
++/* SPARC relocs.  */
++
++#define R_SPARC_NONE		0	/* No reloc */
++#define R_SPARC_8		1	/* Direct 8 bit */
++#define R_SPARC_16		2	/* Direct 16 bit */
++#define R_SPARC_32		3	/* Direct 32 bit */
++#define R_SPARC_DISP8		4	/* PC relative 8 bit */
++#define R_SPARC_DISP16		5	/* PC relative 16 bit */
++#define R_SPARC_DISP32		6	/* PC relative 32 bit */
++#define R_SPARC_WDISP30		7	/* PC relative 30 bit shifted */
++#define R_SPARC_WDISP22		8	/* PC relative 22 bit shifted */
++#define R_SPARC_HI22		9	/* High 22 bit */
++#define R_SPARC_22		10	/* Direct 22 bit */
++#define R_SPARC_13		11	/* Direct 13 bit */
++#define R_SPARC_LO10		12	/* Truncated 10 bit */
++#define R_SPARC_GOT10		13	/* Truncated 10 bit GOT entry */
++#define R_SPARC_GOT13		14	/* 13 bit GOT entry */
++#define R_SPARC_GOT22		15	/* 22 bit GOT entry shifted */
++#define R_SPARC_PC10		16	/* PC relative 10 bit truncated */
++#define R_SPARC_PC22		17	/* PC relative 22 bit shifted */
++#define R_SPARC_WPLT30		18	/* 30 bit PC relative PLT address */
++#define R_SPARC_COPY		19	/* Copy symbol at runtime */
++#define R_SPARC_GLOB_DAT	20	/* Create GOT entry */
++#define R_SPARC_JMP_SLOT	21	/* Create PLT entry */
++#define R_SPARC_RELATIVE	22	/* Adjust by program base */
++#define R_SPARC_UA32		23	/* Direct 32 bit unaligned */
++
++/* Additional Sparc64 relocs.  */
++
++#define R_SPARC_PLT32		24	/* Direct 32 bit ref to PLT entry */
++#define R_SPARC_HIPLT22		25	/* High 22 bit PLT entry */
++#define R_SPARC_LOPLT10		26	/* Truncated 10 bit PLT entry */
++#define R_SPARC_PCPLT32		27	/* PC rel 32 bit ref to PLT entry */
++#define R_SPARC_PCPLT22		28	/* PC rel high 22 bit PLT entry */
++#define R_SPARC_PCPLT10		29	/* PC rel trunc 10 bit PLT entry */
++#define R_SPARC_10		30	/* Direct 10 bit */
++#define R_SPARC_11		31	/* Direct 11 bit */
++#define R_SPARC_64		32	/* Direct 64 bit */
++#define R_SPARC_OLO10		33	/* 10bit with secondary 13bit addend */
++#define R_SPARC_HH22		34	/* Top 22 bits of direct 64 bit */
++#define R_SPARC_HM10		35	/* High middle 10 bits of ... */
++#define R_SPARC_LM22		36	/* Low middle 22 bits of ... */
++#define R_SPARC_PC_HH22		37	/* Top 22 bits of pc rel 64 bit */
++#define R_SPARC_PC_HM10		38	/* High middle 10 bit of ... */
++#define R_SPARC_PC_LM22		39	/* Low miggle 22 bits of ... */
++#define R_SPARC_WDISP16		40	/* PC relative 16 bit shifted */
++#define R_SPARC_WDISP19		41	/* PC relative 19 bit shifted */
++#define R_SPARC_GLOB_JMP	42	/* was part of v9 ABI but was removed */
++#define R_SPARC_7		43	/* Direct 7 bit */
++#define R_SPARC_5		44	/* Direct 5 bit */
++#define R_SPARC_6		45	/* Direct 6 bit */
++#define R_SPARC_DISP64		46	/* PC relative 64 bit */
++#define R_SPARC_PLT64		47	/* Direct 64 bit ref to PLT entry */
++#define R_SPARC_HIX22		48	/* High 22 bit complemented */
++#define R_SPARC_LOX10		49	/* Truncated 11 bit complemented */
++#define R_SPARC_H44		50	/* Direct high 12 of 44 bit */
++#define R_SPARC_M44		51	/* Direct mid 22 of 44 bit */
++#define R_SPARC_L44		52	/* Direct low 10 of 44 bit */
++#define R_SPARC_REGISTER	53	/* Global register usage */
++#define R_SPARC_UA64		54	/* Direct 64 bit unaligned */
++#define R_SPARC_UA16		55	/* Direct 16 bit unaligned */
++#define R_SPARC_TLS_GD_HI22	56
++#define R_SPARC_TLS_GD_LO10	57
++#define R_SPARC_TLS_GD_ADD	58
++#define R_SPARC_TLS_GD_CALL	59
++#define R_SPARC_TLS_LDM_HI22	60
++#define R_SPARC_TLS_LDM_LO10	61
++#define R_SPARC_TLS_LDM_ADD	62
++#define R_SPARC_TLS_LDM_CALL	63
++#define R_SPARC_TLS_LDO_HIX22	64
++#define R_SPARC_TLS_LDO_LOX10	65
++#define R_SPARC_TLS_LDO_ADD	66
++#define R_SPARC_TLS_IE_HI22	67
++#define R_SPARC_TLS_IE_LO10	68
++#define R_SPARC_TLS_IE_LD	69
++#define R_SPARC_TLS_IE_LDX	70
++#define R_SPARC_TLS_IE_ADD	71
++#define R_SPARC_TLS_LE_HIX22	72
++#define R_SPARC_TLS_LE_LOX10	73
++#define R_SPARC_TLS_DTPMOD32	74
++#define R_SPARC_TLS_DTPMOD64	75
++#define R_SPARC_TLS_DTPOFF32	76
++#define R_SPARC_TLS_DTPOFF64	77
++#define R_SPARC_TLS_TPOFF32	78
++#define R_SPARC_TLS_TPOFF64	79
++#define R_SPARC_GOTDATA_HIX22	80
++#define R_SPARC_GOTDATA_LOX10	81
++#define R_SPARC_GOTDATA_OP_HIX22	82
++#define R_SPARC_GOTDATA_OP_LOX10	83
++#define R_SPARC_GOTDATA_OP	84
++#define R_SPARC_H34		85
++#define R_SPARC_SIZE32		86
++#define R_SPARC_SIZE64		87
++#define R_SPARC_WDISP10		88
++#define R_SPARC_JMP_IREL	248
++#define R_SPARC_IRELATIVE	249
++#define R_SPARC_GNU_VTINHERIT	250
++#define R_SPARC_GNU_VTENTRY	251
++#define R_SPARC_REV32		252
++/* Keep this the last entry.  */
++#define R_SPARC_NUM		253
++
++/* For Sparc64, legal values for d_tag of Elf64_Dyn.  */
++
++#define DT_SPARC_REGISTER 0x70000001
++#define DT_SPARC_NUM	2
++
++/* MIPS R3000 specific definitions.  */
++
++/* Legal values for e_flags field of Elf32_Ehdr.  */
++
++#define EF_MIPS_NOREORDER   1		/* A .noreorder directive was used */
++#define EF_MIPS_PIC	    2		/* Contains PIC code */
++#define EF_MIPS_CPIC	    4		/* Uses PIC calling sequence */
++#define EF_MIPS_XGOT	    8
++#define EF_MIPS_64BIT_WHIRL 16
++#define EF_MIPS_ABI2	    32
++#define EF_MIPS_ABI_ON32    64
++#define EF_MIPS_ARCH	    0xf0000000	/* MIPS architecture level */
++
++/* Legal values for MIPS architecture level.  */
++
++#define EF_MIPS_ARCH_1	    0x00000000	/* -mips1 code.  */
++#define EF_MIPS_ARCH_2	    0x10000000	/* -mips2 code.  */
++#define EF_MIPS_ARCH_3	    0x20000000	/* -mips3 code.  */
++#define EF_MIPS_ARCH_4	    0x30000000	/* -mips4 code.  */
++#define EF_MIPS_ARCH_5	    0x40000000	/* -mips5 code.  */
++#define EF_MIPS_ARCH_32	    0x60000000	/* MIPS32 code.  */
++#define EF_MIPS_ARCH_64	    0x70000000	/* MIPS64 code.  */
++
++/* The following are non-official names and should not be used.  */
++
++#define E_MIPS_ARCH_1	  0x00000000	/* -mips1 code.  */
++#define E_MIPS_ARCH_2	  0x10000000	/* -mips2 code.  */
++#define E_MIPS_ARCH_3	  0x20000000	/* -mips3 code.  */
++#define E_MIPS_ARCH_4	  0x30000000	/* -mips4 code.  */
++#define E_MIPS_ARCH_5	  0x40000000	/* -mips5 code.  */
++#define E_MIPS_ARCH_32	  0x60000000	/* MIPS32 code.  */
++#define E_MIPS_ARCH_64	  0x70000000	/* MIPS64 code.  */
++
++/* Special section indices.  */
++
++#define SHN_MIPS_ACOMMON    0xff00	/* Allocated common symbols */
++#define SHN_MIPS_TEXT	    0xff01	/* Allocated test symbols.  */
++#define SHN_MIPS_DATA	    0xff02	/* Allocated data symbols.  */
++#define SHN_MIPS_SCOMMON    0xff03	/* Small common symbols */
++#define SHN_MIPS_SUNDEFINED 0xff04	/* Small undefined symbols */
++
++/* Legal values for sh_type field of Elf32_Shdr.  */
++
++#define SHT_MIPS_LIBLIST       0x70000000 /* Shared objects used in link */
++#define SHT_MIPS_MSYM	       0x70000001
++#define SHT_MIPS_CONFLICT      0x70000002 /* Conflicting symbols */
++#define SHT_MIPS_GPTAB	       0x70000003 /* Global data area sizes */
++#define SHT_MIPS_UCODE	       0x70000004 /* Reserved for SGI/MIPS compilers */
++#define SHT_MIPS_DEBUG	       0x70000005 /* MIPS ECOFF debugging information*/
++#define SHT_MIPS_REGINFO       0x70000006 /* Register usage information */
++#define SHT_MIPS_PACKAGE       0x70000007
++#define SHT_MIPS_PACKSYM       0x70000008
++#define SHT_MIPS_RELD	       0x70000009
++#define SHT_MIPS_IFACE         0x7000000b
++#define SHT_MIPS_CONTENT       0x7000000c
++#define SHT_MIPS_OPTIONS       0x7000000d /* Miscellaneous options.  */
++#define SHT_MIPS_SHDR	       0x70000010
++#define SHT_MIPS_FDESC	       0x70000011
++#define SHT_MIPS_EXTSYM	       0x70000012
++#define SHT_MIPS_DENSE	       0x70000013
++#define SHT_MIPS_PDESC	       0x70000014
++#define SHT_MIPS_LOCSYM	       0x70000015
++#define SHT_MIPS_AUXSYM	       0x70000016
++#define SHT_MIPS_OPTSYM	       0x70000017
++#define SHT_MIPS_LOCSTR	       0x70000018
++#define SHT_MIPS_LINE	       0x70000019
++#define SHT_MIPS_RFDESC	       0x7000001a
++#define SHT_MIPS_DELTASYM      0x7000001b
++#define SHT_MIPS_DELTAINST     0x7000001c
++#define SHT_MIPS_DELTACLASS    0x7000001d
++#define SHT_MIPS_DWARF         0x7000001e /* DWARF debugging information.  */
++#define SHT_MIPS_DELTADECL     0x7000001f
++#define SHT_MIPS_SYMBOL_LIB    0x70000020
++#define SHT_MIPS_EVENTS	       0x70000021 /* Event section.  */
++#define SHT_MIPS_TRANSLATE     0x70000022
++#define SHT_MIPS_PIXIE	       0x70000023
++#define SHT_MIPS_XLATE	       0x70000024
++#define SHT_MIPS_XLATE_DEBUG   0x70000025
++#define SHT_MIPS_WHIRL	       0x70000026
++#define SHT_MIPS_EH_REGION     0x70000027
++#define SHT_MIPS_XLATE_OLD     0x70000028
++#define SHT_MIPS_PDR_EXCEPTION 0x70000029
++
++/* Legal values for sh_flags field of Elf32_Shdr.  */
++
++#define SHF_MIPS_GPREL	 0x10000000	/* Must be part of global data area */
++#define SHF_MIPS_MERGE	 0x20000000
++#define SHF_MIPS_ADDR	 0x40000000
++#define SHF_MIPS_STRINGS 0x80000000
++#define SHF_MIPS_NOSTRIP 0x08000000
++#define SHF_MIPS_LOCAL	 0x04000000
++#define SHF_MIPS_NAMES	 0x02000000
++#define SHF_MIPS_NODUPE	 0x01000000
++
++
++/* Symbol tables.  */
++
++/* MIPS specific values for `st_other'.  */
++#define STO_MIPS_DEFAULT		0x0
++#define STO_MIPS_INTERNAL		0x1
++#define STO_MIPS_HIDDEN			0x2
++#define STO_MIPS_PROTECTED		0x3
++#define STO_MIPS_PLT			0x8
++#define STO_MIPS_SC_ALIGN_UNUSED	0xff
++
++/* MIPS specific values for `st_info'.  */
++#define STB_MIPS_SPLIT_COMMON		13
++
++/* Entries found in sections of type SHT_MIPS_GPTAB.  */
++
++typedef union
++{
++  struct
++    {
++      Elf32_Word gt_current_g_value;	/* -G value used for compilation */
++      Elf32_Word gt_unused;		/* Not used */
++    } gt_header;			/* First entry in section */
++  struct
++    {
++      Elf32_Word gt_g_value;		/* If this value were used for -G */
++      Elf32_Word gt_bytes;		/* This many bytes would be used */
++    } gt_entry;				/* Subsequent entries in section */
++} Elf32_gptab;
++
++/* Entry found in sections of type SHT_MIPS_REGINFO.  */
++
++typedef struct
++{
++  Elf32_Word	ri_gprmask;		/* General registers used */
++  Elf32_Word	ri_cprmask[4];		/* Coprocessor registers used */
++  Elf32_Sword	ri_gp_value;		/* $gp register value */
++} Elf32_RegInfo;
++
++/* Entries found in sections of type SHT_MIPS_OPTIONS.  */
++
++typedef struct
++{
++  unsigned char kind;		/* Determines interpretation of the
++				   variable part of descriptor.  */
++  unsigned char size;		/* Size of descriptor, including header.  */
++  Elf32_Section section;	/* Section header index of section affected,
++				   0 for global options.  */
++  Elf32_Word info;		/* Kind-specific information.  */
++} Elf_Options;
++
++/* Values for `kind' field in Elf_Options.  */
++
++#define ODK_NULL	0	/* Undefined.  */
++#define ODK_REGINFO	1	/* Register usage information.  */
++#define ODK_EXCEPTIONS	2	/* Exception processing options.  */
++#define ODK_PAD		3	/* Section padding options.  */
++#define ODK_HWPATCH	4	/* Hardware workarounds performed */
++#define ODK_FILL	5	/* record the fill value used by the linker. */
++#define ODK_TAGS	6	/* reserve space for desktop tools to write. */
++#define ODK_HWAND	7	/* HW workarounds.  'AND' bits when merging. */
++#define ODK_HWOR	8	/* HW workarounds.  'OR' bits when merging.  */
++
++/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries.  */
++
++#define OEX_FPU_MIN	0x1f	/* FPE's which MUST be enabled.  */
++#define OEX_FPU_MAX	0x1f00	/* FPE's which MAY be enabled.  */
++#define OEX_PAGE0	0x10000	/* page zero must be mapped.  */
++#define OEX_SMM		0x20000	/* Force sequential memory mode?  */
++#define OEX_FPDBUG	0x40000	/* Force floating point debug mode?  */
++#define OEX_PRECISEFP	OEX_FPDBUG
++#define OEX_DISMISS	0x80000	/* Dismiss invalid address faults?  */
++
++#define OEX_FPU_INVAL	0x10
++#define OEX_FPU_DIV0	0x08
++#define OEX_FPU_OFLO	0x04
++#define OEX_FPU_UFLO	0x02
++#define OEX_FPU_INEX	0x01
++
++/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry.  */
++
++#define OHW_R4KEOP	0x1	/* R4000 end-of-page patch.  */
++#define OHW_R8KPFETCH	0x2	/* may need R8000 prefetch patch.  */
++#define OHW_R5KEOP	0x4	/* R5000 end-of-page patch.  */
++#define OHW_R5KCVTL	0x8	/* R5000 cvt.[ds].l bug.  clean=1.  */
++
++#define OPAD_PREFIX	0x1
++#define OPAD_POSTFIX	0x2
++#define OPAD_SYMBOL	0x4
++
++/* Entry found in `.options' section.  */
++
++typedef struct
++{
++  Elf32_Word hwp_flags1;	/* Extra flags.  */
++  Elf32_Word hwp_flags2;	/* Extra flags.  */
++} Elf_Options_Hw;
++
++/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries.  */
++
++#define OHWA0_R4KEOP_CHECKED	0x00000001
++#define OHWA1_R4KEOP_CLEAN	0x00000002
++
++/* MIPS relocs.  */
++
++#define R_MIPS_NONE		0	/* No reloc */
++#define R_MIPS_16		1	/* Direct 16 bit */
++#define R_MIPS_32		2	/* Direct 32 bit */
++#define R_MIPS_REL32		3	/* PC relative 32 bit */
++#define R_MIPS_26		4	/* Direct 26 bit shifted */
++#define R_MIPS_HI16		5	/* High 16 bit */
++#define R_MIPS_LO16		6	/* Low 16 bit */
++#define R_MIPS_GPREL16		7	/* GP relative 16 bit */
++#define R_MIPS_LITERAL		8	/* 16 bit literal entry */
++#define R_MIPS_GOT16		9	/* 16 bit GOT entry */
++#define R_MIPS_PC16		10	/* PC relative 16 bit */
++#define R_MIPS_CALL16		11	/* 16 bit GOT entry for function */
++#define R_MIPS_GPREL32		12	/* GP relative 32 bit */
++
++#define R_MIPS_SHIFT5		16
++#define R_MIPS_SHIFT6		17
++#define R_MIPS_64		18
++#define R_MIPS_GOT_DISP		19
++#define R_MIPS_GOT_PAGE		20
++#define R_MIPS_GOT_OFST		21
++#define R_MIPS_GOT_HI16		22
++#define R_MIPS_GOT_LO16		23
++#define R_MIPS_SUB		24
++#define R_MIPS_INSERT_A		25
++#define R_MIPS_INSERT_B		26
++#define R_MIPS_DELETE		27
++#define R_MIPS_HIGHER		28
++#define R_MIPS_HIGHEST		29
++#define R_MIPS_CALL_HI16	30
++#define R_MIPS_CALL_LO16	31
++#define R_MIPS_SCN_DISP		32
++#define R_MIPS_REL16		33
++#define R_MIPS_ADD_IMMEDIATE	34
++#define R_MIPS_PJUMP		35
++#define R_MIPS_RELGOT		36
++#define R_MIPS_JALR		37
++#define R_MIPS_TLS_DTPMOD32	38	/* Module number 32 bit */
++#define R_MIPS_TLS_DTPREL32	39	/* Module-relative offset 32 bit */
++#define R_MIPS_TLS_DTPMOD64	40	/* Module number 64 bit */
++#define R_MIPS_TLS_DTPREL64	41	/* Module-relative offset 64 bit */
++#define R_MIPS_TLS_GD		42	/* 16 bit GOT offset for GD */
++#define R_MIPS_TLS_LDM		43	/* 16 bit GOT offset for LDM */
++#define R_MIPS_TLS_DTPREL_HI16	44	/* Module-relative offset, high 16 bits */
++#define R_MIPS_TLS_DTPREL_LO16	45	/* Module-relative offset, low 16 bits */
++#define R_MIPS_TLS_GOTTPREL	46	/* 16 bit GOT offset for IE */
++#define R_MIPS_TLS_TPREL32	47	/* TP-relative offset, 32 bit */
++#define R_MIPS_TLS_TPREL64	48	/* TP-relative offset, 64 bit */
++#define R_MIPS_TLS_TPREL_HI16	49	/* TP-relative offset, high 16 bits */
++#define R_MIPS_TLS_TPREL_LO16	50	/* TP-relative offset, low 16 bits */
++#define R_MIPS_GLOB_DAT		51
++#define R_MIPS_COPY		126
++#define R_MIPS_JUMP_SLOT        127
++/* Keep this the last entry.  */
++#define R_MIPS_NUM		128
++
++/* Legal values for p_type field of Elf32_Phdr.  */
++
++#define PT_MIPS_REGINFO	0x70000000	/* Register usage information */
++#define PT_MIPS_RTPROC  0x70000001	/* Runtime procedure table. */
++#define PT_MIPS_OPTIONS 0x70000002
++
++/* Special program header types.  */
++
++#define PF_MIPS_LOCAL	0x10000000
++
++/* Legal values for d_tag field of Elf32_Dyn.  */
++
++#define DT_MIPS_RLD_VERSION  0x70000001	/* Runtime linker interface version */
++#define DT_MIPS_TIME_STAMP   0x70000002	/* Timestamp */
++#define DT_MIPS_ICHECKSUM    0x70000003	/* Checksum */
++#define DT_MIPS_IVERSION     0x70000004	/* Version string (string tbl index) */
++#define DT_MIPS_FLAGS	     0x70000005	/* Flags */
++#define DT_MIPS_BASE_ADDRESS 0x70000006	/* Base address */
++#define DT_MIPS_MSYM	     0x70000007
++#define DT_MIPS_CONFLICT     0x70000008	/* Address of CONFLICT section */
++#define DT_MIPS_LIBLIST	     0x70000009	/* Address of LIBLIST section */
++#define DT_MIPS_LOCAL_GOTNO  0x7000000a	/* Number of local GOT entries */
++#define DT_MIPS_CONFLICTNO   0x7000000b	/* Number of CONFLICT entries */
++#define DT_MIPS_LIBLISTNO    0x70000010	/* Number of LIBLIST entries */
++#define DT_MIPS_SYMTABNO     0x70000011	/* Number of DYNSYM entries */
++#define DT_MIPS_UNREFEXTNO   0x70000012	/* First external DYNSYM */
++#define DT_MIPS_GOTSYM	     0x70000013	/* First GOT entry in DYNSYM */
++#define DT_MIPS_HIPAGENO     0x70000014	/* Number of GOT page table entries */
++#define DT_MIPS_RLD_MAP	     0x70000016	/* Address of run time loader map.  */
++#define DT_MIPS_DELTA_CLASS  0x70000017	/* Delta C++ class definition.  */
++#define DT_MIPS_DELTA_CLASS_NO    0x70000018 /* Number of entries in
++						DT_MIPS_DELTA_CLASS.  */
++#define DT_MIPS_DELTA_INSTANCE    0x70000019 /* Delta C++ class instances.  */
++#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in
++						DT_MIPS_DELTA_INSTANCE.  */
++#define DT_MIPS_DELTA_RELOC  0x7000001b /* Delta relocations.  */
++#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in
++					     DT_MIPS_DELTA_RELOC.  */
++#define DT_MIPS_DELTA_SYM    0x7000001d /* Delta symbols that Delta
++					   relocations refer to.  */
++#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in
++					   DT_MIPS_DELTA_SYM.  */
++#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the
++					     class declaration.  */
++#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in
++						DT_MIPS_DELTA_CLASSSYM.  */
++#define DT_MIPS_CXX_FLAGS    0x70000022 /* Flags indicating for C++ flavor.  */
++#define DT_MIPS_PIXIE_INIT   0x70000023
++#define DT_MIPS_SYMBOL_LIB   0x70000024
++#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025
++#define DT_MIPS_LOCAL_GOTIDX 0x70000026
++#define DT_MIPS_HIDDEN_GOTIDX 0x70000027
++#define DT_MIPS_PROTECTED_GOTIDX 0x70000028
++#define DT_MIPS_OPTIONS	     0x70000029 /* Address of .options.  */
++#define DT_MIPS_INTERFACE    0x7000002a /* Address of .interface.  */
++#define DT_MIPS_DYNSTR_ALIGN 0x7000002b
++#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */
++#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve
++						    function stored in GOT.  */
++#define DT_MIPS_PERF_SUFFIX  0x7000002e /* Default suffix of dso to be added
++					   by rld on dlopen() calls.  */
++#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */
++#define DT_MIPS_GP_VALUE     0x70000030 /* GP value for aux GOTs.  */
++#define DT_MIPS_AUX_DYNAMIC  0x70000031 /* Address of aux .dynamic.  */
++/* The address of .got.plt in an executable using the new non-PIC ABI.  */
++#define DT_MIPS_PLTGOT	     0x70000032
++/* The base of the PLT in an executable using the new non-PIC ABI if that
++   PLT is writable.  For a non-writable PLT, this is omitted or has a zero
++   value.  */
++#define DT_MIPS_RWPLT        0x70000034
++#define DT_MIPS_NUM	     0x35
++
++/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry.  */
++
++#define RHF_NONE		   0		/* No flags */
++#define RHF_QUICKSTART		   (1 << 0)	/* Use quickstart */
++#define RHF_NOTPOT		   (1 << 1)	/* Hash size not power of 2 */
++#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2)	/* Ignore LD_LIBRARY_PATH */
++#define RHF_NO_MOVE		   (1 << 3)
++#define RHF_SGI_ONLY		   (1 << 4)
++#define RHF_GUARANTEE_INIT	   (1 << 5)
++#define RHF_DELTA_C_PLUS_PLUS	   (1 << 6)
++#define RHF_GUARANTEE_START_INIT   (1 << 7)
++#define RHF_PIXIE		   (1 << 8)
++#define RHF_DEFAULT_DELAY_LOAD	   (1 << 9)
++#define RHF_REQUICKSTART	   (1 << 10)
++#define RHF_REQUICKSTARTED	   (1 << 11)
++#define RHF_CORD		   (1 << 12)
++#define RHF_NO_UNRES_UNDEF	   (1 << 13)
++#define RHF_RLD_ORDER_SAFE	   (1 << 14)
++
++/* Entries found in sections of type SHT_MIPS_LIBLIST.  */
++
++typedef struct
++{
++  Elf32_Word l_name;		/* Name (string table index) */
++  Elf32_Word l_time_stamp;	/* Timestamp */
++  Elf32_Word l_checksum;	/* Checksum */
++  Elf32_Word l_version;		/* Interface version */
++  Elf32_Word l_flags;		/* Flags */
++} Elf32_Lib;
++
++typedef struct
++{
++  Elf64_Word l_name;		/* Name (string table index) */
++  Elf64_Word l_time_stamp;	/* Timestamp */
++  Elf64_Word l_checksum;	/* Checksum */
++  Elf64_Word l_version;		/* Interface version */
++  Elf64_Word l_flags;		/* Flags */
++} Elf64_Lib;
++
++
++/* Legal values for l_flags.  */
++
++#define LL_NONE		  0
++#define LL_EXACT_MATCH	  (1 << 0)	/* Require exact match */
++#define LL_IGNORE_INT_VER (1 << 1)	/* Ignore interface version */
++#define LL_REQUIRE_MINOR  (1 << 2)
++#define LL_EXPORTS	  (1 << 3)
++#define LL_DELAY_LOAD	  (1 << 4)
++#define LL_DELTA	  (1 << 5)
++
++/* Entries found in sections of type SHT_MIPS_CONFLICT.  */
++
++typedef Elf32_Addr Elf32_Conflict;
++
++
++/* HPPA specific definitions.  */
++
++/* Legal values for e_flags field of Elf32_Ehdr.  */
++
++#define EF_PARISC_TRAPNIL	0x00010000 /* Trap nil pointer dereference.  */
++#define EF_PARISC_EXT		0x00020000 /* Program uses arch. extensions. */
++#define EF_PARISC_LSB		0x00040000 /* Program expects little endian. */
++#define EF_PARISC_WIDE		0x00080000 /* Program expects wide mode.  */
++#define EF_PARISC_NO_KABP	0x00100000 /* No kernel assisted branch
++					      prediction.  */
++#define EF_PARISC_LAZYSWAP	0x00400000 /* Allow lazy swapping.  */
++#define EF_PARISC_ARCH		0x0000ffff /* Architecture version.  */
++
++/* Defined values for `e_flags & EF_PARISC_ARCH' are:  */
++
++#define EFA_PARISC_1_0		    0x020b /* PA-RISC 1.0 big-endian.  */
++#define EFA_PARISC_1_1		    0x0210 /* PA-RISC 1.1 big-endian.  */
++#define EFA_PARISC_2_0		    0x0214 /* PA-RISC 2.0 big-endian.  */
++
++/* Additional section indeces.  */
++
++#define SHN_PARISC_ANSI_COMMON	0xff00	   /* Section for tenatively declared
++					      symbols in ANSI C.  */
++#define SHN_PARISC_HUGE_COMMON	0xff01	   /* Common blocks in huge model.  */
++
++/* Legal values for sh_type field of Elf32_Shdr.  */
++
++#define SHT_PARISC_EXT		0x70000000 /* Contains product specific ext. */
++#define SHT_PARISC_UNWIND	0x70000001 /* Unwind information.  */
++#define SHT_PARISC_DOC		0x70000002 /* Debug info for optimized code. */
++
++/* Legal values for sh_flags field of Elf32_Shdr.  */
++
++#define SHF_PARISC_SHORT	0x20000000 /* Section with short addressing. */
++#define SHF_PARISC_HUGE		0x40000000 /* Section far from gp.  */
++#define SHF_PARISC_SBP		0x80000000 /* Static branch prediction code. */
++
++/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
++
++#define STT_PARISC_MILLICODE	13	/* Millicode function entry point.  */
++
++#define STT_HP_OPAQUE		(STT_LOOS + 0x1)
++#define STT_HP_STUB		(STT_LOOS + 0x2)
++
++/* HPPA relocs.  */
++
++#define R_PARISC_NONE		0	/* No reloc.  */
++#define R_PARISC_DIR32		1	/* Direct 32-bit reference.  */
++#define R_PARISC_DIR21L		2	/* Left 21 bits of eff. address.  */
++#define R_PARISC_DIR17R		3	/* Right 17 bits of eff. address.  */
++#define R_PARISC_DIR17F		4	/* 17 bits of eff. address.  */
++#define R_PARISC_DIR14R		6	/* Right 14 bits of eff. address.  */
++#define R_PARISC_PCREL32	9	/* 32-bit rel. address.  */
++#define R_PARISC_PCREL21L	10	/* Left 21 bits of rel. address.  */
++#define R_PARISC_PCREL17R	11	/* Right 17 bits of rel. address.  */
++#define R_PARISC_PCREL17F	12	/* 17 bits of rel. address.  */
++#define R_PARISC_PCREL14R	14	/* Right 14 bits of rel. address.  */
++#define R_PARISC_DPREL21L	18	/* Left 21 bits of rel. address.  */
++#define R_PARISC_DPREL14R	22	/* Right 14 bits of rel. address.  */
++#define R_PARISC_GPREL21L	26	/* GP-relative, left 21 bits.  */
++#define R_PARISC_GPREL14R	30	/* GP-relative, right 14 bits.  */
++#define R_PARISC_LTOFF21L	34	/* LT-relative, left 21 bits.  */
++#define R_PARISC_LTOFF14R	38	/* LT-relative, right 14 bits.  */
++#define R_PARISC_SECREL32	41	/* 32 bits section rel. address.  */
++#define R_PARISC_SEGBASE	48	/* No relocation, set segment base.  */
++#define R_PARISC_SEGREL32	49	/* 32 bits segment rel. address.  */
++#define R_PARISC_PLTOFF21L	50	/* PLT rel. address, left 21 bits.  */
++#define R_PARISC_PLTOFF14R	54	/* PLT rel. address, right 14 bits.  */
++#define R_PARISC_LTOFF_FPTR32	57	/* 32 bits LT-rel. function pointer. */
++#define R_PARISC_LTOFF_FPTR21L	58	/* LT-rel. fct ptr, left 21 bits. */
++#define R_PARISC_LTOFF_FPTR14R	62	/* LT-rel. fct ptr, right 14 bits. */
++#define R_PARISC_FPTR64		64	/* 64 bits function address.  */
++#define R_PARISC_PLABEL32	65	/* 32 bits function address.  */
++#define R_PARISC_PLABEL21L	66	/* Left 21 bits of fdesc address.  */
++#define R_PARISC_PLABEL14R	70	/* Right 14 bits of fdesc address.  */
++#define R_PARISC_PCREL64	72	/* 64 bits PC-rel. address.  */
++#define R_PARISC_PCREL22F	74	/* 22 bits PC-rel. address.  */
++#define R_PARISC_PCREL14WR	75	/* PC-rel. address, right 14 bits.  */
++#define R_PARISC_PCREL14DR	76	/* PC rel. address, right 14 bits.  */
++#define R_PARISC_PCREL16F	77	/* 16 bits PC-rel. address.  */
++#define R_PARISC_PCREL16WF	78	/* 16 bits PC-rel. address.  */
++#define R_PARISC_PCREL16DF	79	/* 16 bits PC-rel. address.  */
++#define R_PARISC_DIR64		80	/* 64 bits of eff. address.  */
++#define R_PARISC_DIR14WR	83	/* 14 bits of eff. address.  */
++#define R_PARISC_DIR14DR	84	/* 14 bits of eff. address.  */
++#define R_PARISC_DIR16F		85	/* 16 bits of eff. address.  */
++#define R_PARISC_DIR16WF	86	/* 16 bits of eff. address.  */
++#define R_PARISC_DIR16DF	87	/* 16 bits of eff. address.  */
++#define R_PARISC_GPREL64	88	/* 64 bits of GP-rel. address.  */
++#define R_PARISC_GPREL14WR	91	/* GP-rel. address, right 14 bits.  */
++#define R_PARISC_GPREL14DR	92	/* GP-rel. address, right 14 bits.  */
++#define R_PARISC_GPREL16F	93	/* 16 bits GP-rel. address.  */
++#define R_PARISC_GPREL16WF	94	/* 16 bits GP-rel. address.  */
++#define R_PARISC_GPREL16DF	95	/* 16 bits GP-rel. address.  */
++#define R_PARISC_LTOFF64	96	/* 64 bits LT-rel. address.  */
++#define R_PARISC_LTOFF14WR	99	/* LT-rel. address, right 14 bits.  */
++#define R_PARISC_LTOFF14DR	100	/* LT-rel. address, right 14 bits.  */
++#define R_PARISC_LTOFF16F	101	/* 16 bits LT-rel. address.  */
++#define R_PARISC_LTOFF16WF	102	/* 16 bits LT-rel. address.  */
++#define R_PARISC_LTOFF16DF	103	/* 16 bits LT-rel. address.  */
++#define R_PARISC_SECREL64	104	/* 64 bits section rel. address.  */
++#define R_PARISC_SEGREL64	112	/* 64 bits segment rel. address.  */
++#define R_PARISC_PLTOFF14WR	115	/* PLT-rel. address, right 14 bits.  */
++#define R_PARISC_PLTOFF14DR	116	/* PLT-rel. address, right 14 bits.  */
++#define R_PARISC_PLTOFF16F	117	/* 16 bits LT-rel. address.  */
++#define R_PARISC_PLTOFF16WF	118	/* 16 bits PLT-rel. address.  */
++#define R_PARISC_PLTOFF16DF	119	/* 16 bits PLT-rel. address.  */
++#define R_PARISC_LTOFF_FPTR64	120	/* 64 bits LT-rel. function ptr.  */
++#define R_PARISC_LTOFF_FPTR14WR	123	/* LT-rel. fct. ptr., right 14 bits. */
++#define R_PARISC_LTOFF_FPTR14DR	124	/* LT-rel. fct. ptr., right 14 bits. */
++#define R_PARISC_LTOFF_FPTR16F	125	/* 16 bits LT-rel. function ptr.  */
++#define R_PARISC_LTOFF_FPTR16WF	126	/* 16 bits LT-rel. function ptr.  */
++#define R_PARISC_LTOFF_FPTR16DF	127	/* 16 bits LT-rel. function ptr.  */
++#define R_PARISC_LORESERVE	128
++#define R_PARISC_COPY		128	/* Copy relocation.  */
++#define R_PARISC_IPLT		129	/* Dynamic reloc, imported PLT */
++#define R_PARISC_EPLT		130	/* Dynamic reloc, exported PLT */
++#define R_PARISC_TPREL32	153	/* 32 bits TP-rel. address.  */
++#define R_PARISC_TPREL21L	154	/* TP-rel. address, left 21 bits.  */
++#define R_PARISC_TPREL14R	158	/* TP-rel. address, right 14 bits.  */
++#define R_PARISC_LTOFF_TP21L	162	/* LT-TP-rel. address, left 21 bits. */
++#define R_PARISC_LTOFF_TP14R	166	/* LT-TP-rel. address, right 14 bits.*/
++#define R_PARISC_LTOFF_TP14F	167	/* 14 bits LT-TP-rel. address.  */
++#define R_PARISC_TPREL64	216	/* 64 bits TP-rel. address.  */
++#define R_PARISC_TPREL14WR	219	/* TP-rel. address, right 14 bits.  */
++#define R_PARISC_TPREL14DR	220	/* TP-rel. address, right 14 bits.  */
++#define R_PARISC_TPREL16F	221	/* 16 bits TP-rel. address.  */
++#define R_PARISC_TPREL16WF	222	/* 16 bits TP-rel. address.  */
++#define R_PARISC_TPREL16DF	223	/* 16 bits TP-rel. address.  */
++#define R_PARISC_LTOFF_TP64	224	/* 64 bits LT-TP-rel. address.  */
++#define R_PARISC_LTOFF_TP14WR	227	/* LT-TP-rel. address, right 14 bits.*/
++#define R_PARISC_LTOFF_TP14DR	228	/* LT-TP-rel. address, right 14 bits.*/
++#define R_PARISC_LTOFF_TP16F	229	/* 16 bits LT-TP-rel. address.  */
++#define R_PARISC_LTOFF_TP16WF	230	/* 16 bits LT-TP-rel. address.  */
++#define R_PARISC_LTOFF_TP16DF	231	/* 16 bits LT-TP-rel. address.  */
++#define R_PARISC_GNU_VTENTRY	232
++#define R_PARISC_GNU_VTINHERIT	233
++#define R_PARISC_TLS_GD21L	234	/* GD 21-bit left.  */
++#define R_PARISC_TLS_GD14R	235	/* GD 14-bit right.  */
++#define R_PARISC_TLS_GDCALL	236	/* GD call to __t_g_a.  */
++#define R_PARISC_TLS_LDM21L	237	/* LD module 21-bit left.  */
++#define R_PARISC_TLS_LDM14R	238	/* LD module 14-bit right.  */
++#define R_PARISC_TLS_LDMCALL	239	/* LD module call to __t_g_a.  */
++#define R_PARISC_TLS_LDO21L	240	/* LD offset 21-bit left.  */
++#define R_PARISC_TLS_LDO14R	241	/* LD offset 14-bit right.  */
++#define R_PARISC_TLS_DTPMOD32	242	/* DTP module 32-bit.  */
++#define R_PARISC_TLS_DTPMOD64	243	/* DTP module 64-bit.  */
++#define R_PARISC_TLS_DTPOFF32	244	/* DTP offset 32-bit.  */
++#define R_PARISC_TLS_DTPOFF64	245	/* DTP offset 32-bit.  */
++#define R_PARISC_TLS_LE21L	R_PARISC_TPREL21L
++#define R_PARISC_TLS_LE14R	R_PARISC_TPREL14R
++#define R_PARISC_TLS_IE21L	R_PARISC_LTOFF_TP21L
++#define R_PARISC_TLS_IE14R	R_PARISC_LTOFF_TP14R
++#define R_PARISC_TLS_TPREL32	R_PARISC_TPREL32
++#define R_PARISC_TLS_TPREL64	R_PARISC_TPREL64
++#define R_PARISC_HIRESERVE	255
++
++/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr.  */
++
++#define PT_HP_TLS		(PT_LOOS + 0x0)
++#define PT_HP_CORE_NONE		(PT_LOOS + 0x1)
++#define PT_HP_CORE_VERSION	(PT_LOOS + 0x2)
++#define PT_HP_CORE_KERNEL	(PT_LOOS + 0x3)
++#define PT_HP_CORE_COMM		(PT_LOOS + 0x4)
++#define PT_HP_CORE_PROC		(PT_LOOS + 0x5)
++#define PT_HP_CORE_LOADABLE	(PT_LOOS + 0x6)
++#define PT_HP_CORE_STACK	(PT_LOOS + 0x7)
++#define PT_HP_CORE_SHM		(PT_LOOS + 0x8)
++#define PT_HP_CORE_MMF		(PT_LOOS + 0x9)
++#define PT_HP_PARALLEL		(PT_LOOS + 0x10)
++#define PT_HP_FASTBIND		(PT_LOOS + 0x11)
++#define PT_HP_OPT_ANNOT		(PT_LOOS + 0x12)
++#define PT_HP_HSL_ANNOT		(PT_LOOS + 0x13)
++#define PT_HP_STACK		(PT_LOOS + 0x14)
++
++#define PT_PARISC_ARCHEXT	0x70000000
++#define PT_PARISC_UNWIND	0x70000001
++
++/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr.  */
++
++#define PF_PARISC_SBP		0x08000000
++
++#define PF_HP_PAGE_SIZE		0x00100000
++#define PF_HP_FAR_SHARED	0x00200000
++#define PF_HP_NEAR_SHARED	0x00400000
++#define PF_HP_CODE		0x01000000
++#define PF_HP_MODIFY		0x02000000
++#define PF_HP_LAZYSWAP		0x04000000
++#define PF_HP_SBP		0x08000000
++
++
++/* Alpha specific definitions.  */
++
++/* Legal values for e_flags field of Elf64_Ehdr.  */
++
++#define EF_ALPHA_32BIT		1	/* All addresses must be < 2GB.  */
++#define EF_ALPHA_CANRELAX	2	/* Relocations for relaxing exist.  */
++
++/* Legal values for sh_type field of Elf64_Shdr.  */
++
++/* These two are primerily concerned with ECOFF debugging info.  */
++#define SHT_ALPHA_DEBUG		0x70000001
++#define SHT_ALPHA_REGINFO	0x70000002
++
++/* Legal values for sh_flags field of Elf64_Shdr.  */
++
++#define SHF_ALPHA_GPREL		0x10000000
++
++/* Legal values for st_other field of Elf64_Sym.  */
++#define STO_ALPHA_NOPV		0x80	/* No PV required.  */
++#define STO_ALPHA_STD_GPLOAD	0x88	/* PV only used for initial ldgp.  */
++
++/* Alpha relocs.  */
++
++#define R_ALPHA_NONE		0	/* No reloc */
++#define R_ALPHA_REFLONG		1	/* Direct 32 bit */
++#define R_ALPHA_REFQUAD		2	/* Direct 64 bit */
++#define R_ALPHA_GPREL32		3	/* GP relative 32 bit */
++#define R_ALPHA_LITERAL		4	/* GP relative 16 bit w/optimization */
++#define R_ALPHA_LITUSE		5	/* Optimization hint for LITERAL */
++#define R_ALPHA_GPDISP		6	/* Add displacement to GP */
++#define R_ALPHA_BRADDR		7	/* PC+4 relative 23 bit shifted */
++#define R_ALPHA_HINT		8	/* PC+4 relative 16 bit shifted */
++#define R_ALPHA_SREL16		9	/* PC relative 16 bit */
++#define R_ALPHA_SREL32		10	/* PC relative 32 bit */
++#define R_ALPHA_SREL64		11	/* PC relative 64 bit */
++#define R_ALPHA_GPRELHIGH	17	/* GP relative 32 bit, high 16 bits */
++#define R_ALPHA_GPRELLOW	18	/* GP relative 32 bit, low 16 bits */
++#define R_ALPHA_GPREL16		19	/* GP relative 16 bit */
++#define R_ALPHA_COPY		24	/* Copy symbol at runtime */
++#define R_ALPHA_GLOB_DAT	25	/* Create GOT entry */
++#define R_ALPHA_JMP_SLOT	26	/* Create PLT entry */
++#define R_ALPHA_RELATIVE	27	/* Adjust by program base */
++#define R_ALPHA_TLS_GD_HI	28
++#define R_ALPHA_TLSGD		29
++#define R_ALPHA_TLS_LDM		30
++#define R_ALPHA_DTPMOD64	31
++#define R_ALPHA_GOTDTPREL	32
++#define R_ALPHA_DTPREL64	33
++#define R_ALPHA_DTPRELHI	34
++#define R_ALPHA_DTPRELLO	35
++#define R_ALPHA_DTPREL16	36
++#define R_ALPHA_GOTTPREL	37
++#define R_ALPHA_TPREL64		38
++#define R_ALPHA_TPRELHI		39
++#define R_ALPHA_TPRELLO		40
++#define R_ALPHA_TPREL16		41
++/* Keep this the last entry.  */
++#define R_ALPHA_NUM		46
++
++/* Magic values of the LITUSE relocation addend.  */
++#define LITUSE_ALPHA_ADDR	0
++#define LITUSE_ALPHA_BASE	1
++#define LITUSE_ALPHA_BYTOFF	2
++#define LITUSE_ALPHA_JSR	3
++#define LITUSE_ALPHA_TLS_GD	4
++#define LITUSE_ALPHA_TLS_LDM	5
++
++/* Legal values for d_tag of Elf64_Dyn.  */
++#define DT_ALPHA_PLTRO		(DT_LOPROC + 0)
++#define DT_ALPHA_NUM		1
++
++/* PowerPC specific declarations */
++
++/* Values for Elf32/64_Ehdr.e_flags.  */
++#define EF_PPC_EMB		0x80000000	/* PowerPC embedded flag */
++
++/* Cygnus local bits below */
++#define EF_PPC_RELOCATABLE	0x00010000	/* PowerPC -mrelocatable flag*/
++#define EF_PPC_RELOCATABLE_LIB	0x00008000	/* PowerPC -mrelocatable-lib
++						   flag */
++
++/* PowerPC relocations defined by the ABIs */
++#define R_PPC_NONE		0
++#define R_PPC_ADDR32		1	/* 32bit absolute address */
++#define R_PPC_ADDR24		2	/* 26bit address, 2 bits ignored.  */
++#define R_PPC_ADDR16		3	/* 16bit absolute address */
++#define R_PPC_ADDR16_LO		4	/* lower 16bit of absolute address */
++#define R_PPC_ADDR16_HI		5	/* high 16bit of absolute address */
++#define R_PPC_ADDR16_HA		6	/* adjusted high 16bit */
++#define R_PPC_ADDR14		7	/* 16bit address, 2 bits ignored */
++#define R_PPC_ADDR14_BRTAKEN	8
++#define R_PPC_ADDR14_BRNTAKEN	9
++#define R_PPC_REL24		10	/* PC relative 26 bit */
++#define R_PPC_REL14		11	/* PC relative 16 bit */
++#define R_PPC_REL14_BRTAKEN	12
++#define R_PPC_REL14_BRNTAKEN	13
++#define R_PPC_GOT16		14
++#define R_PPC_GOT16_LO		15
++#define R_PPC_GOT16_HI		16
++#define R_PPC_GOT16_HA		17
++#define R_PPC_PLTREL24		18
++#define R_PPC_COPY		19
++#define R_PPC_GLOB_DAT		20
++#define R_PPC_JMP_SLOT		21
++#define R_PPC_RELATIVE		22
++#define R_PPC_LOCAL24PC		23
++#define R_PPC_UADDR32		24
++#define R_PPC_UADDR16		25
++#define R_PPC_REL32		26
++#define R_PPC_PLT32		27
++#define R_PPC_PLTREL32		28
++#define R_PPC_PLT16_LO		29
++#define R_PPC_PLT16_HI		30
++#define R_PPC_PLT16_HA		31
++#define R_PPC_SDAREL16		32
++#define R_PPC_SECTOFF		33
++#define R_PPC_SECTOFF_LO	34
++#define R_PPC_SECTOFF_HI	35
++#define R_PPC_SECTOFF_HA	36
++
++/* PowerPC relocations defined for the TLS access ABI.  */
++#define R_PPC_TLS		67 /* none	(sym+add)@tls */
++#define R_PPC_DTPMOD32		68 /* word32	(sym+add)@dtpmod */
++#define R_PPC_TPREL16		69 /* half16*	(sym+add)@tprel */
++#define R_PPC_TPREL16_LO	70 /* half16	(sym+add)@tprel@l */
++#define R_PPC_TPREL16_HI	71 /* half16	(sym+add)@tprel@h */
++#define R_PPC_TPREL16_HA	72 /* half16	(sym+add)@tprel@ha */
++#define R_PPC_TPREL32		73 /* word32	(sym+add)@tprel */
++#define R_PPC_DTPREL16		74 /* half16*	(sym+add)@dtprel */
++#define R_PPC_DTPREL16_LO	75 /* half16	(sym+add)@dtprel@l */
++#define R_PPC_DTPREL16_HI	76 /* half16	(sym+add)@dtprel@h */
++#define R_PPC_DTPREL16_HA	77 /* half16	(sym+add)@dtprel@ha */
++#define R_PPC_DTPREL32		78 /* word32	(sym+add)@dtprel */
++#define R_PPC_GOT_TLSGD16	79 /* half16*	(sym+add)@got@tlsgd */
++#define R_PPC_GOT_TLSGD16_LO	80 /* half16	(sym+add)@got@tlsgd@l */
++#define R_PPC_GOT_TLSGD16_HI	81 /* half16	(sym+add)@got@tlsgd@h */
++#define R_PPC_GOT_TLSGD16_HA	82 /* half16	(sym+add)@got@tlsgd@ha */
++#define R_PPC_GOT_TLSLD16	83 /* half16*	(sym+add)@got@tlsld */
++#define R_PPC_GOT_TLSLD16_LO	84 /* half16	(sym+add)@got@tlsld@l */
++#define R_PPC_GOT_TLSLD16_HI	85 /* half16	(sym+add)@got@tlsld@h */
++#define R_PPC_GOT_TLSLD16_HA	86 /* half16	(sym+add)@got@tlsld@ha */
++#define R_PPC_GOT_TPREL16	87 /* half16*	(sym+add)@got@tprel */
++#define R_PPC_GOT_TPREL16_LO	88 /* half16	(sym+add)@got@tprel@l */
++#define R_PPC_GOT_TPREL16_HI	89 /* half16	(sym+add)@got@tprel@h */
++#define R_PPC_GOT_TPREL16_HA	90 /* half16	(sym+add)@got@tprel@ha */
++#define R_PPC_GOT_DTPREL16	91 /* half16*	(sym+add)@got@dtprel */
++#define R_PPC_GOT_DTPREL16_LO	92 /* half16*	(sym+add)@got@dtprel@l */
++#define R_PPC_GOT_DTPREL16_HI	93 /* half16*	(sym+add)@got@dtprel@h */
++#define R_PPC_GOT_DTPREL16_HA	94 /* half16*	(sym+add)@got@dtprel@ha */
++
++/* The remaining relocs are from the Embedded ELF ABI, and are not
++   in the SVR4 ELF ABI.  */
++#define R_PPC_EMB_NADDR32	101
++#define R_PPC_EMB_NADDR16	102
++#define R_PPC_EMB_NADDR16_LO	103
++#define R_PPC_EMB_NADDR16_HI	104
++#define R_PPC_EMB_NADDR16_HA	105
++#define R_PPC_EMB_SDAI16	106
++#define R_PPC_EMB_SDA2I16	107
++#define R_PPC_EMB_SDA2REL	108
++#define R_PPC_EMB_SDA21		109	/* 16 bit offset in SDA */
++#define R_PPC_EMB_MRKREF	110
++#define R_PPC_EMB_RELSEC16	111
++#define R_PPC_EMB_RELST_LO	112
++#define R_PPC_EMB_RELST_HI	113
++#define R_PPC_EMB_RELST_HA	114
++#define R_PPC_EMB_BIT_FLD	115
++#define R_PPC_EMB_RELSDA	116	/* 16 bit relative offset in SDA */
++
++/* Diab tool relocations.  */
++#define R_PPC_DIAB_SDA21_LO	180	/* like EMB_SDA21, but lower 16 bit */
++#define R_PPC_DIAB_SDA21_HI	181	/* like EMB_SDA21, but high 16 bit */
++#define R_PPC_DIAB_SDA21_HA	182	/* like EMB_SDA21, adjusted high 16 */
++#define R_PPC_DIAB_RELSDA_LO	183	/* like EMB_RELSDA, but lower 16 bit */
++#define R_PPC_DIAB_RELSDA_HI	184	/* like EMB_RELSDA, but high 16 bit */
++#define R_PPC_DIAB_RELSDA_HA	185	/* like EMB_RELSDA, adjusted high 16 */
++
++/* GNU extension to support local ifunc.  */
++#define R_PPC_IRELATIVE		248
++
++/* GNU relocs used in PIC code sequences.  */
++#define R_PPC_REL16		249	/* half16   (sym+add-.) */
++#define R_PPC_REL16_LO		250	/* half16   (sym+add-.)@l */
++#define R_PPC_REL16_HI		251	/* half16   (sym+add-.)@h */
++#define R_PPC_REL16_HA		252	/* half16   (sym+add-.)@ha */
++
++/* This is a phony reloc to handle any old fashioned TOC16 references
++   that may still be in object files.  */
++#define R_PPC_TOC16		255
++
++/* PowerPC specific values for the Dyn d_tag field.  */
++#define DT_PPC_GOT		(DT_LOPROC + 0)
++#define DT_PPC_NUM		1
++
++/* PowerPC64 relocations defined by the ABIs */
++#define R_PPC64_NONE		R_PPC_NONE
++#define R_PPC64_ADDR32		R_PPC_ADDR32 /* 32bit absolute address */
++#define R_PPC64_ADDR24		R_PPC_ADDR24 /* 26bit address, word aligned */
++#define R_PPC64_ADDR16		R_PPC_ADDR16 /* 16bit absolute address */
++#define R_PPC64_ADDR16_LO	R_PPC_ADDR16_LO	/* lower 16bits of address */
++#define R_PPC64_ADDR16_HI	R_PPC_ADDR16_HI	/* high 16bits of address. */
++#define R_PPC64_ADDR16_HA	R_PPC_ADDR16_HA /* adjusted high 16bits.  */
++#define R_PPC64_ADDR14		R_PPC_ADDR14 /* 16bit address, word aligned */
++#define R_PPC64_ADDR14_BRTAKEN	R_PPC_ADDR14_BRTAKEN
++#define R_PPC64_ADDR14_BRNTAKEN	R_PPC_ADDR14_BRNTAKEN
++#define R_PPC64_REL24		R_PPC_REL24 /* PC-rel. 26 bit, word aligned */
++#define R_PPC64_REL14		R_PPC_REL14 /* PC relative 16 bit */
++#define R_PPC64_REL14_BRTAKEN	R_PPC_REL14_BRTAKEN
++#define R_PPC64_REL14_BRNTAKEN	R_PPC_REL14_BRNTAKEN
++#define R_PPC64_GOT16		R_PPC_GOT16
++#define R_PPC64_GOT16_LO	R_PPC_GOT16_LO
++#define R_PPC64_GOT16_HI	R_PPC_GOT16_HI
++#define R_PPC64_GOT16_HA	R_PPC_GOT16_HA
++
++#define R_PPC64_COPY		R_PPC_COPY
++#define R_PPC64_GLOB_DAT	R_PPC_GLOB_DAT
++#define R_PPC64_JMP_SLOT	R_PPC_JMP_SLOT
++#define R_PPC64_RELATIVE	R_PPC_RELATIVE
++
++#define R_PPC64_UADDR32		R_PPC_UADDR32
++#define R_PPC64_UADDR16		R_PPC_UADDR16
++#define R_PPC64_REL32		R_PPC_REL32
++#define R_PPC64_PLT32		R_PPC_PLT32
++#define R_PPC64_PLTREL32	R_PPC_PLTREL32
++#define R_PPC64_PLT16_LO	R_PPC_PLT16_LO
++#define R_PPC64_PLT16_HI	R_PPC_PLT16_HI
++#define R_PPC64_PLT16_HA	R_PPC_PLT16_HA
++
++#define R_PPC64_SECTOFF		R_PPC_SECTOFF
++#define R_PPC64_SECTOFF_LO	R_PPC_SECTOFF_LO
++#define R_PPC64_SECTOFF_HI	R_PPC_SECTOFF_HI
++#define R_PPC64_SECTOFF_HA	R_PPC_SECTOFF_HA
++#define R_PPC64_ADDR30		37 /* word30 (S + A - P) >> 2 */
++#define R_PPC64_ADDR64		38 /* doubleword64 S + A */
++#define R_PPC64_ADDR16_HIGHER	39 /* half16 #higher(S + A) */
++#define R_PPC64_ADDR16_HIGHERA	40 /* half16 #highera(S + A) */
++#define R_PPC64_ADDR16_HIGHEST	41 /* half16 #highest(S + A) */
++#define R_PPC64_ADDR16_HIGHESTA	42 /* half16 #highesta(S + A) */
++#define R_PPC64_UADDR64		43 /* doubleword64 S + A */
++#define R_PPC64_REL64		44 /* doubleword64 S + A - P */
++#define R_PPC64_PLT64		45 /* doubleword64 L + A */
++#define R_PPC64_PLTREL64	46 /* doubleword64 L + A - P */
++#define R_PPC64_TOC16		47 /* half16* S + A - .TOC */
++#define R_PPC64_TOC16_LO	48 /* half16 #lo(S + A - .TOC.) */
++#define R_PPC64_TOC16_HI	49 /* half16 #hi(S + A - .TOC.) */
++#define R_PPC64_TOC16_HA	50 /* half16 #ha(S + A - .TOC.) */
++#define R_PPC64_TOC		51 /* doubleword64 .TOC */
++#define R_PPC64_PLTGOT16	52 /* half16* M + A */
++#define R_PPC64_PLTGOT16_LO	53 /* half16 #lo(M + A) */
++#define R_PPC64_PLTGOT16_HI	54 /* half16 #hi(M + A) */
++#define R_PPC64_PLTGOT16_HA	55 /* half16 #ha(M + A) */
++
++#define R_PPC64_ADDR16_DS	56 /* half16ds* (S + A) >> 2 */
++#define R_PPC64_ADDR16_LO_DS	57 /* half16ds  #lo(S + A) >> 2 */
++#define R_PPC64_GOT16_DS	58 /* half16ds* (G + A) >> 2 */
++#define R_PPC64_GOT16_LO_DS	59 /* half16ds  #lo(G + A) >> 2 */
++#define R_PPC64_PLT16_LO_DS	60 /* half16ds  #lo(L + A) >> 2 */
++#define R_PPC64_SECTOFF_DS	61 /* half16ds* (R + A) >> 2 */
++#define R_PPC64_SECTOFF_LO_DS	62 /* half16ds  #lo(R + A) >> 2 */
++#define R_PPC64_TOC16_DS	63 /* half16ds* (S + A - .TOC.) >> 2 */
++#define R_PPC64_TOC16_LO_DS	64 /* half16ds  #lo(S + A - .TOC.) >> 2 */
++#define R_PPC64_PLTGOT16_DS	65 /* half16ds* (M + A) >> 2 */
++#define R_PPC64_PLTGOT16_LO_DS	66 /* half16ds  #lo(M + A) >> 2 */
++
++/* PowerPC64 relocations defined for the TLS access ABI.  */
++#define R_PPC64_TLS		67 /* none	(sym+add)@tls */
++#define R_PPC64_DTPMOD64	68 /* doubleword64 (sym+add)@dtpmod */
++#define R_PPC64_TPREL16		69 /* half16*	(sym+add)@tprel */
++#define R_PPC64_TPREL16_LO	70 /* half16	(sym+add)@tprel@l */
++#define R_PPC64_TPREL16_HI	71 /* half16	(sym+add)@tprel@h */
++#define R_PPC64_TPREL16_HA	72 /* half16	(sym+add)@tprel@ha */
++#define R_PPC64_TPREL64		73 /* doubleword64 (sym+add)@tprel */
++#define R_PPC64_DTPREL16	74 /* half16*	(sym+add)@dtprel */
++#define R_PPC64_DTPREL16_LO	75 /* half16	(sym+add)@dtprel@l */
++#define R_PPC64_DTPREL16_HI	76 /* half16	(sym+add)@dtprel@h */
++#define R_PPC64_DTPREL16_HA	77 /* half16	(sym+add)@dtprel@ha */
++#define R_PPC64_DTPREL64	78 /* doubleword64 (sym+add)@dtprel */
++#define R_PPC64_GOT_TLSGD16	79 /* half16*	(sym+add)@got@tlsgd */
++#define R_PPC64_GOT_TLSGD16_LO	80 /* half16	(sym+add)@got@tlsgd@l */
++#define R_PPC64_GOT_TLSGD16_HI	81 /* half16	(sym+add)@got@tlsgd@h */
++#define R_PPC64_GOT_TLSGD16_HA	82 /* half16	(sym+add)@got@tlsgd@ha */
++#define R_PPC64_GOT_TLSLD16	83 /* half16*	(sym+add)@got@tlsld */
++#define R_PPC64_GOT_TLSLD16_LO	84 /* half16	(sym+add)@got@tlsld@l */
++#define R_PPC64_GOT_TLSLD16_HI	85 /* half16	(sym+add)@got@tlsld@h */
++#define R_PPC64_GOT_TLSLD16_HA	86 /* half16	(sym+add)@got@tlsld@ha */
++#define R_PPC64_GOT_TPREL16_DS	87 /* half16ds*	(sym+add)@got@tprel */
++#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */
++#define R_PPC64_GOT_TPREL16_HI	89 /* half16	(sym+add)@got@tprel@h */
++#define R_PPC64_GOT_TPREL16_HA	90 /* half16	(sym+add)@got@tprel@ha */
++#define R_PPC64_GOT_DTPREL16_DS	91 /* half16ds*	(sym+add)@got@dtprel */
++#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */
++#define R_PPC64_GOT_DTPREL16_HI	93 /* half16	(sym+add)@got@dtprel@h */
++#define R_PPC64_GOT_DTPREL16_HA	94 /* half16	(sym+add)@got@dtprel@ha */
++#define R_PPC64_TPREL16_DS	95 /* half16ds*	(sym+add)@tprel */
++#define R_PPC64_TPREL16_LO_DS	96 /* half16ds	(sym+add)@tprel@l */
++#define R_PPC64_TPREL16_HIGHER	97 /* half16	(sym+add)@tprel@higher */
++#define R_PPC64_TPREL16_HIGHERA	98 /* half16	(sym+add)@tprel@highera */
++#define R_PPC64_TPREL16_HIGHEST	99 /* half16	(sym+add)@tprel@highest */
++#define R_PPC64_TPREL16_HIGHESTA 100 /* half16	(sym+add)@tprel@highesta */
++#define R_PPC64_DTPREL16_DS	101 /* half16ds* (sym+add)@dtprel */
++#define R_PPC64_DTPREL16_LO_DS	102 /* half16ds	(sym+add)@dtprel@l */
++#define R_PPC64_DTPREL16_HIGHER	103 /* half16	(sym+add)@dtprel@higher */
++#define R_PPC64_DTPREL16_HIGHERA 104 /* half16	(sym+add)@dtprel@highera */
++#define R_PPC64_DTPREL16_HIGHEST 105 /* half16	(sym+add)@dtprel@highest */
++#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16	(sym+add)@dtprel@highesta */
++
++/* GNU extension to support local ifunc.  */
++#define R_PPC64_JMP_IREL	247
++#define R_PPC64_IRELATIVE	248
++#define R_PPC64_REL16		249	/* half16   (sym+add-.) */
++#define R_PPC64_REL16_LO	250	/* half16   (sym+add-.)@l */
++#define R_PPC64_REL16_HI	251	/* half16   (sym+add-.)@h */
++#define R_PPC64_REL16_HA	252	/* half16   (sym+add-.)@ha */
++
++/* PowerPC64 specific values for the Dyn d_tag field.  */
++#define DT_PPC64_GLINK  (DT_LOPROC + 0)
++#define DT_PPC64_OPD	(DT_LOPROC + 1)
++#define DT_PPC64_OPDSZ	(DT_LOPROC + 2)
++#define DT_PPC64_NUM    3
++
++
++/* ARM specific declarations */
++
++/* Processor specific flags for the ELF header e_flags field.  */
++#define EF_ARM_RELEXEC		0x01
++#define EF_ARM_HASENTRY		0x02
++#define EF_ARM_INTERWORK	0x04
++#define EF_ARM_APCS_26		0x08
++#define EF_ARM_APCS_FLOAT	0x10
++#define EF_ARM_PIC		0x20
++#define EF_ARM_ALIGN8		0x40 /* 8-bit structure alignment is in use */
++#define EF_ARM_NEW_ABI		0x80
++#define EF_ARM_OLD_ABI		0x100
++#define EF_ARM_SOFT_FLOAT	0x200
++#define EF_ARM_VFP_FLOAT	0x400
++#define EF_ARM_MAVERICK_FLOAT	0x800
++
++
++/* Other constants defined in the ARM ELF spec. version B-01.  */
++/* NB. These conflict with values defined above.  */
++#define EF_ARM_SYMSARESORTED	0x04
++#define EF_ARM_DYNSYMSUSESEGIDX	0x08
++#define EF_ARM_MAPSYMSFIRST	0x10
++#define EF_ARM_EABIMASK		0XFF000000
++
++/* Constants defined in AAELF.  */
++#define EF_ARM_BE8	    0x00800000
++#define EF_ARM_LE8	    0x00400000
++
++#define EF_ARM_EABI_VERSION(flags)	((flags) & EF_ARM_EABIMASK)
++#define EF_ARM_EABI_UNKNOWN	0x00000000
++#define EF_ARM_EABI_VER1	0x01000000
++#define EF_ARM_EABI_VER2	0x02000000
++#define EF_ARM_EABI_VER3	0x03000000
++#define EF_ARM_EABI_VER4	0x04000000
++#define EF_ARM_EABI_VER5	0x05000000
++
++/* Additional symbol types for Thumb.  */
++#define STT_ARM_TFUNC		STT_LOPROC /* A Thumb function.  */
++#define STT_ARM_16BIT		STT_HIPROC /* A Thumb label.  */
++
++/* ARM-specific values for sh_flags */
++#define SHF_ARM_ENTRYSECT	0x10000000 /* Section contains an entry point */
++#define SHF_ARM_COMDEF		0x80000000 /* Section may be multiply defined
++					      in the input to a link step.  */
++
++/* ARM-specific program header flags */
++#define PF_ARM_SB		0x10000000 /* Segment contains the location
++					      addressed by the static base. */
++#define PF_ARM_PI		0x20000000 /* Position-independent segment.  */
++#define PF_ARM_ABS		0x40000000 /* Absolute segment.  */
++
++/* Processor specific values for the Phdr p_type field.  */
++#define PT_ARM_EXIDX		(PT_LOPROC + 1)	/* ARM unwind segment.  */
++
++/* Processor specific values for the Shdr sh_type field.  */
++#define SHT_ARM_EXIDX		(SHT_LOPROC + 1) /* ARM unwind section.  */
++#define SHT_ARM_PREEMPTMAP	(SHT_LOPROC + 2) /* Preemption details.  */
++#define SHT_ARM_ATTRIBUTES	(SHT_LOPROC + 3) /* ARM attributes section.  */
++
++
++/* ARM relocs.  */
++
++#define R_ARM_NONE		0	/* No reloc */
++#define R_ARM_PC24		1	/* PC relative 26 bit branch */
++#define R_ARM_ABS32		2	/* Direct 32 bit  */
++#define R_ARM_REL32		3	/* PC relative 32 bit */
++#define R_ARM_PC13		4
++#define R_ARM_ABS16		5	/* Direct 16 bit */
++#define R_ARM_ABS12		6	/* Direct 12 bit */
++#define R_ARM_THM_ABS5		7
++#define R_ARM_ABS8		8	/* Direct 8 bit */
++#define R_ARM_SBREL32		9
++#define R_ARM_THM_PC22		10
++#define R_ARM_THM_PC8		11
++#define R_ARM_AMP_VCALL9	12
++#define R_ARM_SWI24		13	/* Obsolete static relocation.  */
++#define R_ARM_TLS_DESC		13      /* Dynamic relocation.  */
++#define R_ARM_THM_SWI8		14
++#define R_ARM_XPC25		15
++#define R_ARM_THM_XPC22		16
++#define R_ARM_TLS_DTPMOD32	17	/* ID of module containing symbol */
++#define R_ARM_TLS_DTPOFF32	18	/* Offset in TLS block */
++#define R_ARM_TLS_TPOFF32	19	/* Offset in static TLS block */
++#define R_ARM_COPY		20	/* Copy symbol at runtime */
++#define R_ARM_GLOB_DAT		21	/* Create GOT entry */
++#define R_ARM_JUMP_SLOT		22	/* Create PLT entry */
++#define R_ARM_RELATIVE		23	/* Adjust by program base */
++#define R_ARM_GOTOFF		24	/* 32 bit offset to GOT */
++#define R_ARM_GOTPC		25	/* 32 bit PC relative offset to GOT */
++#define R_ARM_GOT32		26	/* 32 bit GOT entry */
++#define R_ARM_PLT32		27	/* 32 bit PLT address */
++#define R_ARM_ALU_PCREL_7_0	32
++#define R_ARM_ALU_PCREL_15_8	33
++#define R_ARM_ALU_PCREL_23_15	34
++#define R_ARM_LDR_SBREL_11_0	35
++#define R_ARM_ALU_SBREL_19_12	36
++#define R_ARM_ALU_SBREL_27_20	37
++#define R_ARM_TLS_GOTDESC	90
++#define R_ARM_TLS_CALL		91
++#define R_ARM_TLS_DESCSEQ	92
++#define R_ARM_THM_TLS_CALL	93
++#define R_ARM_GNU_VTENTRY	100
++#define R_ARM_GNU_VTINHERIT	101
++#define R_ARM_THM_PC11		102	/* thumb unconditional branch */
++#define R_ARM_THM_PC9		103	/* thumb conditional branch */
++#define R_ARM_TLS_GD32		104	/* PC-rel 32 bit for global dynamic
++					   thread local data */
++#define R_ARM_TLS_LDM32		105	/* PC-rel 32 bit for local dynamic
++					   thread local data */
++#define R_ARM_TLS_LDO32		106	/* 32 bit offset relative to TLS
++					   block */
++#define R_ARM_TLS_IE32		107	/* PC-rel 32 bit for GOT entry of
++					   static TLS block offset */
++#define R_ARM_TLS_LE32		108	/* 32 bit offset relative to static
++					   TLS block */
++#define	R_ARM_THM_TLS_DESCSEQ	129
++#define R_ARM_IRELATIVE		160
++#define R_ARM_RXPC25		249
++#define R_ARM_RSBREL32		250
++#define R_ARM_THM_RPC22		251
++#define R_ARM_RREL32		252
++#define R_ARM_RABS22		253
++#define R_ARM_RPC24		254
++#define R_ARM_RBASE		255
++/* Keep this the last entry.  */
++#define R_ARM_NUM		256
++
++/* IA-64 specific declarations.  */
++
++/* Processor specific flags for the Ehdr e_flags field.  */
++#define EF_IA_64_MASKOS		0x0000000f	/* os-specific flags */
++#define EF_IA_64_ABI64		0x00000010	/* 64-bit ABI */
++#define EF_IA_64_ARCH		0xff000000	/* arch. version mask */
++
++/* Processor specific values for the Phdr p_type field.  */
++#define PT_IA_64_ARCHEXT	(PT_LOPROC + 0)	/* arch extension bits */
++#define PT_IA_64_UNWIND		(PT_LOPROC + 1)	/* ia64 unwind bits */
++#define PT_IA_64_HP_OPT_ANOT	(PT_LOOS + 0x12)
++#define PT_IA_64_HP_HSL_ANOT	(PT_LOOS + 0x13)
++#define PT_IA_64_HP_STACK	(PT_LOOS + 0x14)
++
++/* Processor specific flags for the Phdr p_flags field.  */
++#define PF_IA_64_NORECOV	0x80000000	/* spec insns w/o recovery */
++
++/* Processor specific values for the Shdr sh_type field.  */
++#define SHT_IA_64_EXT		(SHT_LOPROC + 0) /* extension bits */
++#define SHT_IA_64_UNWIND	(SHT_LOPROC + 1) /* unwind bits */
++
++/* Processor specific flags for the Shdr sh_flags field.  */
++#define SHF_IA_64_SHORT		0x10000000	/* section near gp */
++#define SHF_IA_64_NORECOV	0x20000000	/* spec insns w/o recovery */
++
++/* Processor specific values for the Dyn d_tag field.  */
++#define DT_IA_64_PLT_RESERVE	(DT_LOPROC + 0)
++#define DT_IA_64_NUM		1
++
++/* IA-64 relocations.  */
++#define R_IA64_NONE		0x00	/* none */
++#define R_IA64_IMM14		0x21	/* symbol + addend, add imm14 */
++#define R_IA64_IMM22		0x22	/* symbol + addend, add imm22 */
++#define R_IA64_IMM64		0x23	/* symbol + addend, mov imm64 */
++#define R_IA64_DIR32MSB		0x24	/* symbol + addend, data4 MSB */
++#define R_IA64_DIR32LSB		0x25	/* symbol + addend, data4 LSB */
++#define R_IA64_DIR64MSB		0x26	/* symbol + addend, data8 MSB */
++#define R_IA64_DIR64LSB		0x27	/* symbol + addend, data8 LSB */
++#define R_IA64_GPREL22		0x2a	/* @gprel(sym + add), add imm22 */
++#define R_IA64_GPREL64I		0x2b	/* @gprel(sym + add), mov imm64 */
++#define R_IA64_GPREL32MSB	0x2c	/* @gprel(sym + add), data4 MSB */
++#define R_IA64_GPREL32LSB	0x2d	/* @gprel(sym + add), data4 LSB */
++#define R_IA64_GPREL64MSB	0x2e	/* @gprel(sym + add), data8 MSB */
++#define R_IA64_GPREL64LSB	0x2f	/* @gprel(sym + add), data8 LSB */
++#define R_IA64_LTOFF22		0x32	/* @ltoff(sym + add), add imm22 */
++#define R_IA64_LTOFF64I		0x33	/* @ltoff(sym + add), mov imm64 */
++#define R_IA64_PLTOFF22		0x3a	/* @pltoff(sym + add), add imm22 */
++#define R_IA64_PLTOFF64I	0x3b	/* @pltoff(sym + add), mov imm64 */
++#define R_IA64_PLTOFF64MSB	0x3e	/* @pltoff(sym + add), data8 MSB */
++#define R_IA64_PLTOFF64LSB	0x3f	/* @pltoff(sym + add), data8 LSB */
++#define R_IA64_FPTR64I		0x43	/* @fptr(sym + add), mov imm64 */
++#define R_IA64_FPTR32MSB	0x44	/* @fptr(sym + add), data4 MSB */
++#define R_IA64_FPTR32LSB	0x45	/* @fptr(sym + add), data4 LSB */
++#define R_IA64_FPTR64MSB	0x46	/* @fptr(sym + add), data8 MSB */
++#define R_IA64_FPTR64LSB	0x47	/* @fptr(sym + add), data8 LSB */
++#define R_IA64_PCREL60B		0x48	/* @pcrel(sym + add), brl */
++#define R_IA64_PCREL21B		0x49	/* @pcrel(sym + add), ptb, call */
++#define R_IA64_PCREL21M		0x4a	/* @pcrel(sym + add), chk.s */
++#define R_IA64_PCREL21F		0x4b	/* @pcrel(sym + add), fchkf */
++#define R_IA64_PCREL32MSB	0x4c	/* @pcrel(sym + add), data4 MSB */
++#define R_IA64_PCREL32LSB	0x4d	/* @pcrel(sym + add), data4 LSB */
++#define R_IA64_PCREL64MSB	0x4e	/* @pcrel(sym + add), data8 MSB */
++#define R_IA64_PCREL64LSB	0x4f	/* @pcrel(sym + add), data8 LSB */
++#define R_IA64_LTOFF_FPTR22	0x52	/* @ltoff(@fptr(s+a)), imm22 */
++#define R_IA64_LTOFF_FPTR64I	0x53	/* @ltoff(@fptr(s+a)), imm64 */
++#define R_IA64_LTOFF_FPTR32MSB	0x54	/* @ltoff(@fptr(s+a)), data4 MSB */
++#define R_IA64_LTOFF_FPTR32LSB	0x55	/* @ltoff(@fptr(s+a)), data4 LSB */
++#define R_IA64_LTOFF_FPTR64MSB	0x56	/* @ltoff(@fptr(s+a)), data8 MSB */
++#define R_IA64_LTOFF_FPTR64LSB	0x57	/* @ltoff(@fptr(s+a)), data8 LSB */
++#define R_IA64_SEGREL32MSB	0x5c	/* @segrel(sym + add), data4 MSB */
++#define R_IA64_SEGREL32LSB	0x5d	/* @segrel(sym + add), data4 LSB */
++#define R_IA64_SEGREL64MSB	0x5e	/* @segrel(sym + add), data8 MSB */
++#define R_IA64_SEGREL64LSB	0x5f	/* @segrel(sym + add), data8 LSB */
++#define R_IA64_SECREL32MSB	0x64	/* @secrel(sym + add), data4 MSB */
++#define R_IA64_SECREL32LSB	0x65	/* @secrel(sym + add), data4 LSB */
++#define R_IA64_SECREL64MSB	0x66	/* @secrel(sym + add), data8 MSB */
++#define R_IA64_SECREL64LSB	0x67	/* @secrel(sym + add), data8 LSB */
++#define R_IA64_REL32MSB		0x6c	/* data 4 + REL */
++#define R_IA64_REL32LSB		0x6d	/* data 4 + REL */
++#define R_IA64_REL64MSB		0x6e	/* data 8 + REL */
++#define R_IA64_REL64LSB		0x6f	/* data 8 + REL */
++#define R_IA64_LTV32MSB		0x74	/* symbol + addend, data4 MSB */
++#define R_IA64_LTV32LSB		0x75	/* symbol + addend, data4 LSB */
++#define R_IA64_LTV64MSB		0x76	/* symbol + addend, data8 MSB */
++#define R_IA64_LTV64LSB		0x77	/* symbol + addend, data8 LSB */
++#define R_IA64_PCREL21BI	0x79	/* @pcrel(sym + add), 21bit inst */
++#define R_IA64_PCREL22		0x7a	/* @pcrel(sym + add), 22bit inst */
++#define R_IA64_PCREL64I		0x7b	/* @pcrel(sym + add), 64bit inst */
++#define R_IA64_IPLTMSB		0x80	/* dynamic reloc, imported PLT, MSB */
++#define R_IA64_IPLTLSB		0x81	/* dynamic reloc, imported PLT, LSB */
++#define R_IA64_COPY		0x84	/* copy relocation */
++#define R_IA64_SUB		0x85	/* Addend and symbol difference */
++#define R_IA64_LTOFF22X		0x86	/* LTOFF22, relaxable.  */
++#define R_IA64_LDXMOV		0x87	/* Use of LTOFF22X.  */
++#define R_IA64_TPREL14		0x91	/* @tprel(sym + add), imm14 */
++#define R_IA64_TPREL22		0x92	/* @tprel(sym + add), imm22 */
++#define R_IA64_TPREL64I		0x93	/* @tprel(sym + add), imm64 */
++#define R_IA64_TPREL64MSB	0x96	/* @tprel(sym + add), data8 MSB */
++#define R_IA64_TPREL64LSB	0x97	/* @tprel(sym + add), data8 LSB */
++#define R_IA64_LTOFF_TPREL22	0x9a	/* @ltoff(@tprel(s+a)), imm2 */
++#define R_IA64_DTPMOD64MSB	0xa6	/* @dtpmod(sym + add), data8 MSB */
++#define R_IA64_DTPMOD64LSB	0xa7	/* @dtpmod(sym + add), data8 LSB */
++#define R_IA64_LTOFF_DTPMOD22	0xaa	/* @ltoff(@dtpmod(sym + add)), imm22 */
++#define R_IA64_DTPREL14		0xb1	/* @dtprel(sym + add), imm14 */
++#define R_IA64_DTPREL22		0xb2	/* @dtprel(sym + add), imm22 */
++#define R_IA64_DTPREL64I	0xb3	/* @dtprel(sym + add), imm64 */
++#define R_IA64_DTPREL32MSB	0xb4	/* @dtprel(sym + add), data4 MSB */
++#define R_IA64_DTPREL32LSB	0xb5	/* @dtprel(sym + add), data4 LSB */
++#define R_IA64_DTPREL64MSB	0xb6	/* @dtprel(sym + add), data8 MSB */
++#define R_IA64_DTPREL64LSB	0xb7	/* @dtprel(sym + add), data8 LSB */
++#define R_IA64_LTOFF_DTPREL22	0xba	/* @ltoff(@dtprel(s+a)), imm22 */
++
++/* SH specific declarations */
++
++/* Processor specific flags for the ELF header e_flags field.  */
++#define EF_SH_MACH_MASK		0x1f
++#define EF_SH_UNKNOWN		0x0
++#define EF_SH1			0x1
++#define EF_SH2			0x2
++#define EF_SH3			0x3
++#define EF_SH_DSP		0x4
++#define EF_SH3_DSP		0x5
++#define EF_SH4AL_DSP		0x6
++#define EF_SH3E			0x8
++#define EF_SH4			0x9
++#define EF_SH2E			0xb
++#define EF_SH4A			0xc
++#define EF_SH2A			0xd
++#define EF_SH4_NOFPU		0x10
++#define EF_SH4A_NOFPU		0x11
++#define EF_SH4_NOMMU_NOFPU	0x12
++#define EF_SH2A_NOFPU		0x13
++#define EF_SH3_NOMMU		0x14
++#define EF_SH2A_SH4_NOFPU	0x15
++#define EF_SH2A_SH3_NOFPU	0x16
++#define EF_SH2A_SH4		0x17
++#define EF_SH2A_SH3E		0x18
++
++/* SH relocs.  */
++#define	R_SH_NONE		0
++#define	R_SH_DIR32		1
++#define	R_SH_REL32		2
++#define	R_SH_DIR8WPN		3
++#define	R_SH_IND12W		4
++#define	R_SH_DIR8WPL		5
++#define	R_SH_DIR8WPZ		6
++#define	R_SH_DIR8BP		7
++#define	R_SH_DIR8W		8
++#define	R_SH_DIR8L		9
++#define	R_SH_SWITCH16		25
++#define	R_SH_SWITCH32		26
++#define	R_SH_USES		27
++#define	R_SH_COUNT		28
++#define	R_SH_ALIGN		29
++#define	R_SH_CODE		30
++#define	R_SH_DATA		31
++#define	R_SH_LABEL		32
++#define	R_SH_SWITCH8		33
++#define	R_SH_GNU_VTINHERIT	34
++#define	R_SH_GNU_VTENTRY	35
++#define	R_SH_TLS_GD_32		144
++#define	R_SH_TLS_LD_32		145
++#define	R_SH_TLS_LDO_32		146
++#define	R_SH_TLS_IE_32		147
++#define	R_SH_TLS_LE_32		148
++#define	R_SH_TLS_DTPMOD32	149
++#define	R_SH_TLS_DTPOFF32	150
++#define	R_SH_TLS_TPOFF32	151
++#define	R_SH_GOT32		160
++#define	R_SH_PLT32		161
++#define	R_SH_COPY		162
++#define	R_SH_GLOB_DAT		163
++#define	R_SH_JMP_SLOT		164
++#define	R_SH_RELATIVE		165
++#define	R_SH_GOTOFF		166
++#define	R_SH_GOTPC		167
++/* Keep this the last entry.  */
++#define	R_SH_NUM		256
++
++/* S/390 specific definitions.  */
++
++/* Valid values for the e_flags field.  */
++
++#define EF_S390_HIGH_GPRS    0x00000001  /* High GPRs kernel facility needed.  */
++
++/* Additional s390 relocs */
++
++#define R_390_NONE		0	/* No reloc.  */
++#define R_390_8			1	/* Direct 8 bit.  */
++#define R_390_12		2	/* Direct 12 bit.  */
++#define R_390_16		3	/* Direct 16 bit.  */
++#define R_390_32		4	/* Direct 32 bit.  */
++#define R_390_PC32		5	/* PC relative 32 bit.	*/
++#define R_390_GOT12		6	/* 12 bit GOT offset.  */
++#define R_390_GOT32		7	/* 32 bit GOT offset.  */
++#define R_390_PLT32		8	/* 32 bit PC relative PLT address.  */
++#define R_390_COPY		9	/* Copy symbol at runtime.  */
++#define R_390_GLOB_DAT		10	/* Create GOT entry.  */
++#define R_390_JMP_SLOT		11	/* Create PLT entry.  */
++#define R_390_RELATIVE		12	/* Adjust by program base.  */
++#define R_390_GOTOFF32		13	/* 32 bit offset to GOT.	 */
++#define R_390_GOTPC		14	/* 32 bit PC relative offset to GOT.  */
++#define R_390_GOT16		15	/* 16 bit GOT offset.  */
++#define R_390_PC16		16	/* PC relative 16 bit.	*/
++#define R_390_PC16DBL		17	/* PC relative 16 bit shifted by 1.  */
++#define R_390_PLT16DBL		18	/* 16 bit PC rel. PLT shifted by 1.  */
++#define R_390_PC32DBL		19	/* PC relative 32 bit shifted by 1.  */
++#define R_390_PLT32DBL		20	/* 32 bit PC rel. PLT shifted by 1.  */
++#define R_390_GOTPCDBL		21	/* 32 bit PC rel. GOT shifted by 1.  */
++#define R_390_64		22	/* Direct 64 bit.  */
++#define R_390_PC64		23	/* PC relative 64 bit.	*/
++#define R_390_GOT64		24	/* 64 bit GOT offset.  */
++#define R_390_PLT64		25	/* 64 bit PC relative PLT address.  */
++#define R_390_GOTENT		26	/* 32 bit PC rel. to GOT entry >> 1. */
++#define R_390_GOTOFF16		27	/* 16 bit offset to GOT. */
++#define R_390_GOTOFF64		28	/* 64 bit offset to GOT. */
++#define R_390_GOTPLT12		29	/* 12 bit offset to jump slot.	*/
++#define R_390_GOTPLT16		30	/* 16 bit offset to jump slot.	*/
++#define R_390_GOTPLT32		31	/* 32 bit offset to jump slot.	*/
++#define R_390_GOTPLT64		32	/* 64 bit offset to jump slot.	*/
++#define R_390_GOTPLTENT		33	/* 32 bit rel. offset to jump slot.  */
++#define R_390_PLTOFF16		34	/* 16 bit offset from GOT to PLT. */
++#define R_390_PLTOFF32		35	/* 32 bit offset from GOT to PLT. */
++#define R_390_PLTOFF64		36	/* 16 bit offset from GOT to PLT. */
++#define R_390_TLS_LOAD		37	/* Tag for load insn in TLS code.  */
++#define R_390_TLS_GDCALL	38	/* Tag for function call in general
++					   dynamic TLS code. */
++#define R_390_TLS_LDCALL	39	/* Tag for function call in local
++					   dynamic TLS code. */
++#define R_390_TLS_GD32		40	/* Direct 32 bit for general dynamic
++					   thread local data.  */
++#define R_390_TLS_GD64		41	/* Direct 64 bit for general dynamic
++					  thread local data.  */
++#define R_390_TLS_GOTIE12	42	/* 12 bit GOT offset for static TLS
++					   block offset.  */
++#define R_390_TLS_GOTIE32	43	/* 32 bit GOT offset for static TLS
++					   block offset.  */
++#define R_390_TLS_GOTIE64	44	/* 64 bit GOT offset for static TLS
++					   block offset. */
++#define R_390_TLS_LDM32		45	/* Direct 32 bit for local dynamic
++					   thread local data in LE code.  */
++#define R_390_TLS_LDM64		46	/* Direct 64 bit for local dynamic
++					   thread local data in LE code.  */
++#define R_390_TLS_IE32		47	/* 32 bit address of GOT entry for
++					   negated static TLS block offset.  */
++#define R_390_TLS_IE64		48	/* 64 bit address of GOT entry for
++					   negated static TLS block offset.  */
++#define R_390_TLS_IEENT		49	/* 32 bit rel. offset to GOT entry for
++					   negated static TLS block offset.  */
++#define R_390_TLS_LE32		50	/* 32 bit negated offset relative to
++					   static TLS block.  */
++#define R_390_TLS_LE64		51	/* 64 bit negated offset relative to
++					   static TLS block.  */
++#define R_390_TLS_LDO32		52	/* 32 bit offset relative to TLS
++					   block.  */
++#define R_390_TLS_LDO64		53	/* 64 bit offset relative to TLS
++					   block.  */
++#define R_390_TLS_DTPMOD	54	/* ID of module containing symbol.  */
++#define R_390_TLS_DTPOFF	55	/* Offset in TLS block.	 */
++#define R_390_TLS_TPOFF		56	/* Negated offset in static TLS
++					   block.  */
++#define R_390_20		57	/* Direct 20 bit.  */
++#define R_390_GOT20		58	/* 20 bit GOT offset.  */
++#define R_390_GOTPLT20		59	/* 20 bit offset to jump slot.  */
++#define R_390_TLS_GOTIE20	60	/* 20 bit GOT offset for static TLS
++					   block offset.  */
++#define R_390_IRELATIVE         61      /* STT_GNU_IFUNC relocation.  */
++/* Keep this the last entry.  */
++#define R_390_NUM		62
++
++
++/* CRIS relocations.  */
++#define R_CRIS_NONE		0
++#define R_CRIS_8		1
++#define R_CRIS_16		2
++#define R_CRIS_32		3
++#define R_CRIS_8_PCREL		4
++#define R_CRIS_16_PCREL		5
++#define R_CRIS_32_PCREL		6
++#define R_CRIS_GNU_VTINHERIT	7
++#define R_CRIS_GNU_VTENTRY	8
++#define R_CRIS_COPY		9
++#define R_CRIS_GLOB_DAT		10
++#define R_CRIS_JUMP_SLOT	11
++#define R_CRIS_RELATIVE		12
++#define R_CRIS_16_GOT		13
++#define R_CRIS_32_GOT		14
++#define R_CRIS_16_GOTPLT	15
++#define R_CRIS_32_GOTPLT	16
++#define R_CRIS_32_GOTREL	17
++#define R_CRIS_32_PLT_GOTREL	18
++#define R_CRIS_32_PLT_PCREL	19
++
++#define R_CRIS_NUM		20
++
++
++/* AMD x86-64 relocations.  */
++#define R_X86_64_NONE		0	/* No reloc */
++#define R_X86_64_64		1	/* Direct 64 bit  */
++#define R_X86_64_PC32		2	/* PC relative 32 bit signed */
++#define R_X86_64_GOT32		3	/* 32 bit GOT entry */
++#define R_X86_64_PLT32		4	/* 32 bit PLT address */
++#define R_X86_64_COPY		5	/* Copy symbol at runtime */
++#define R_X86_64_GLOB_DAT	6	/* Create GOT entry */
++#define R_X86_64_JUMP_SLOT	7	/* Create PLT entry */
++#define R_X86_64_RELATIVE	8	/* Adjust by program base */
++#define R_X86_64_GOTPCREL	9	/* 32 bit signed PC relative
++					   offset to GOT */
++#define R_X86_64_32		10	/* Direct 32 bit zero extended */
++#define R_X86_64_32S		11	/* Direct 32 bit sign extended */
++#define R_X86_64_16		12	/* Direct 16 bit zero extended */
++#define R_X86_64_PC16		13	/* 16 bit sign extended pc relative */
++#define R_X86_64_8		14	/* Direct 8 bit sign extended  */
++#define R_X86_64_PC8		15	/* 8 bit sign extended pc relative */
++#define R_X86_64_DTPMOD64	16	/* ID of module containing symbol */
++#define R_X86_64_DTPOFF64	17	/* Offset in module's TLS block */
++#define R_X86_64_TPOFF64	18	/* Offset in initial TLS block */
++#define R_X86_64_TLSGD		19	/* 32 bit signed PC relative offset
++					   to two GOT entries for GD symbol */
++#define R_X86_64_TLSLD		20	/* 32 bit signed PC relative offset
++					   to two GOT entries for LD symbol */
++#define R_X86_64_DTPOFF32	21	/* Offset in TLS block */
++#define R_X86_64_GOTTPOFF	22	/* 32 bit signed PC relative offset
++					   to GOT entry for IE symbol */
++#define R_X86_64_TPOFF32	23	/* Offset in initial TLS block */
++#define R_X86_64_PC64		24	/* PC relative 64 bit */
++#define R_X86_64_GOTOFF64	25	/* 64 bit offset to GOT */
++#define R_X86_64_GOTPC32	26	/* 32 bit signed pc relative
++					   offset to GOT */
++#define R_X86_64_GOT64		27	/* 64-bit GOT entry offset */
++#define R_X86_64_GOTPCREL64	28	/* 64-bit PC relative offset
++					   to GOT entry */
++#define R_X86_64_GOTPC64	29	/* 64-bit PC relative offset to GOT */
++#define R_X86_64_GOTPLT64	30 	/* like GOT64, says PLT entry needed */
++#define R_X86_64_PLTOFF64	31	/* 64-bit GOT relative offset
++					   to PLT entry */
++#define R_X86_64_SIZE32		32	/* Size of symbol plus 32-bit addend */
++#define R_X86_64_SIZE64		33	/* Size of symbol plus 64-bit addend */
++#define R_X86_64_GOTPC32_TLSDESC 34	/* GOT offset for TLS descriptor.  */
++#define R_X86_64_TLSDESC_CALL   35	/* Marker for call through TLS
++					   descriptor.  */
++#define R_X86_64_TLSDESC        36	/* TLS descriptor.  */
++#define R_X86_64_IRELATIVE	37	/* Adjust indirectly by program base */
++#define R_X86_64_RELATIVE64	38	/* 64-bit adjust by program base */
++
++#define R_X86_64_NUM		39
++
++
++/* AM33 relocations.  */
++#define R_MN10300_NONE		0	/* No reloc.  */
++#define R_MN10300_32		1	/* Direct 32 bit.  */
++#define R_MN10300_16		2	/* Direct 16 bit.  */
++#define R_MN10300_8		3	/* Direct 8 bit.  */
++#define R_MN10300_PCREL32	4	/* PC-relative 32-bit.  */
++#define R_MN10300_PCREL16	5	/* PC-relative 16-bit signed.  */
++#define R_MN10300_PCREL8	6	/* PC-relative 8-bit signed.  */
++#define R_MN10300_GNU_VTINHERIT	7	/* Ancient C++ vtable garbage... */
++#define R_MN10300_GNU_VTENTRY	8	/* ... collection annotation.  */
++#define R_MN10300_24		9	/* Direct 24 bit.  */
++#define R_MN10300_GOTPC32	10	/* 32-bit PCrel offset to GOT.  */
++#define R_MN10300_GOTPC16	11	/* 16-bit PCrel offset to GOT.  */
++#define R_MN10300_GOTOFF32	12	/* 32-bit offset from GOT.  */
++#define R_MN10300_GOTOFF24	13	/* 24-bit offset from GOT.  */
++#define R_MN10300_GOTOFF16	14	/* 16-bit offset from GOT.  */
++#define R_MN10300_PLT32		15	/* 32-bit PCrel to PLT entry.  */
++#define R_MN10300_PLT16		16	/* 16-bit PCrel to PLT entry.  */
++#define R_MN10300_GOT32		17	/* 32-bit offset to GOT entry.  */
++#define R_MN10300_GOT24		18	/* 24-bit offset to GOT entry.  */
++#define R_MN10300_GOT16		19	/* 16-bit offset to GOT entry.  */
++#define R_MN10300_COPY		20	/* Copy symbol at runtime.  */
++#define R_MN10300_GLOB_DAT	21	/* Create GOT entry.  */
++#define R_MN10300_JMP_SLOT	22	/* Create PLT entry.  */
++#define R_MN10300_RELATIVE	23	/* Adjust by program base.  */
++
++#define R_MN10300_NUM		24
++
++
++/* M32R relocs.  */
++#define R_M32R_NONE		0	/* No reloc. */
++#define R_M32R_16		1	/* Direct 16 bit. */
++#define R_M32R_32		2	/* Direct 32 bit. */
++#define R_M32R_24		3	/* Direct 24 bit. */
++#define R_M32R_10_PCREL		4	/* PC relative 10 bit shifted. */
++#define R_M32R_18_PCREL		5	/* PC relative 18 bit shifted. */
++#define R_M32R_26_PCREL		6	/* PC relative 26 bit shifted. */
++#define R_M32R_HI16_ULO		7	/* High 16 bit with unsigned low. */
++#define R_M32R_HI16_SLO		8	/* High 16 bit with signed low. */
++#define R_M32R_LO16		9	/* Low 16 bit. */
++#define R_M32R_SDA16		10	/* 16 bit offset in SDA. */
++#define R_M32R_GNU_VTINHERIT	11
++#define R_M32R_GNU_VTENTRY	12
++/* M32R relocs use SHT_RELA.  */
++#define R_M32R_16_RELA		33	/* Direct 16 bit. */
++#define R_M32R_32_RELA		34	/* Direct 32 bit. */
++#define R_M32R_24_RELA		35	/* Direct 24 bit. */
++#define R_M32R_10_PCREL_RELA	36	/* PC relative 10 bit shifted. */
++#define R_M32R_18_PCREL_RELA	37	/* PC relative 18 bit shifted. */
++#define R_M32R_26_PCREL_RELA	38	/* PC relative 26 bit shifted. */
++#define R_M32R_HI16_ULO_RELA	39	/* High 16 bit with unsigned low */
++#define R_M32R_HI16_SLO_RELA	40	/* High 16 bit with signed low */
++#define R_M32R_LO16_RELA	41	/* Low 16 bit */
++#define R_M32R_SDA16_RELA	42	/* 16 bit offset in SDA */
++#define R_M32R_RELA_GNU_VTINHERIT	43
++#define R_M32R_RELA_GNU_VTENTRY	44
++#define R_M32R_REL32		45	/* PC relative 32 bit.  */
++
++#define R_M32R_GOT24		48	/* 24 bit GOT entry */
++#define R_M32R_26_PLTREL	49	/* 26 bit PC relative to PLT shifted */
++#define R_M32R_COPY		50	/* Copy symbol at runtime */
++#define R_M32R_GLOB_DAT		51	/* Create GOT entry */
++#define R_M32R_JMP_SLOT		52	/* Create PLT entry */
++#define R_M32R_RELATIVE		53	/* Adjust by program base */
++#define R_M32R_GOTOFF		54	/* 24 bit offset to GOT */
++#define R_M32R_GOTPC24		55	/* 24 bit PC relative offset to GOT */
++#define R_M32R_GOT16_HI_ULO	56	/* High 16 bit GOT entry with unsigned
++					   low */
++#define R_M32R_GOT16_HI_SLO	57	/* High 16 bit GOT entry with signed
++					   low */
++#define R_M32R_GOT16_LO		58	/* Low 16 bit GOT entry */
++#define R_M32R_GOTPC_HI_ULO	59	/* High 16 bit PC relative offset to
++					   GOT with unsigned low */
++#define R_M32R_GOTPC_HI_SLO	60	/* High 16 bit PC relative offset to
++					   GOT with signed low */
++#define R_M32R_GOTPC_LO		61	/* Low 16 bit PC relative offset to
++					   GOT */
++#define R_M32R_GOTOFF_HI_ULO	62	/* High 16 bit offset to GOT
++					   with unsigned low */
++#define R_M32R_GOTOFF_HI_SLO	63	/* High 16 bit offset to GOT
++					   with signed low */
++#define R_M32R_GOTOFF_LO	64	/* Low 16 bit offset to GOT */
++#define R_M32R_NUM		256	/* Keep this the last entry. */
++
++
++/* TILEPro relocations.  */
++#define R_TILEPRO_NONE		0	/* No reloc */
++#define R_TILEPRO_32		1	/* Direct 32 bit */
++#define R_TILEPRO_16		2	/* Direct 16 bit */
++#define R_TILEPRO_8		3	/* Direct 8 bit */
++#define R_TILEPRO_32_PCREL	4	/* PC relative 32 bit */
++#define R_TILEPRO_16_PCREL	5	/* PC relative 16 bit */
++#define R_TILEPRO_8_PCREL	6	/* PC relative 8 bit */
++#define R_TILEPRO_LO16		7	/* Low 16 bit */
++#define R_TILEPRO_HI16		8	/* High 16 bit */
++#define R_TILEPRO_HA16		9	/* High 16 bit, adjusted */
++#define R_TILEPRO_COPY		10	/* Copy relocation */
++#define R_TILEPRO_GLOB_DAT	11	/* Create GOT entry */
++#define R_TILEPRO_JMP_SLOT	12	/* Create PLT entry */
++#define R_TILEPRO_RELATIVE	13	/* Adjust by program base */
++#define R_TILEPRO_BROFF_X1	14	/* X1 pipe branch offset */
++#define R_TILEPRO_JOFFLONG_X1	15	/* X1 pipe jump offset */
++#define R_TILEPRO_JOFFLONG_X1_PLT 16	/* X1 pipe jump offset to PLT */
++#define R_TILEPRO_IMM8_X0	17	/* X0 pipe 8-bit */
++#define R_TILEPRO_IMM8_Y0	18	/* Y0 pipe 8-bit */
++#define R_TILEPRO_IMM8_X1	19	/* X1 pipe 8-bit */
++#define R_TILEPRO_IMM8_Y1	20	/* Y1 pipe 8-bit */
++#define R_TILEPRO_MT_IMM15_X1	21	/* X1 pipe mtspr */
++#define R_TILEPRO_MF_IMM15_X1	22	/* X1 pipe mfspr */
++#define R_TILEPRO_IMM16_X0	23	/* X0 pipe 16-bit */
++#define R_TILEPRO_IMM16_X1	24	/* X1 pipe 16-bit */
++#define R_TILEPRO_IMM16_X0_LO	25	/* X0 pipe low 16-bit */
++#define R_TILEPRO_IMM16_X1_LO	26	/* X1 pipe low 16-bit */
++#define R_TILEPRO_IMM16_X0_HI	27	/* X0 pipe high 16-bit */
++#define R_TILEPRO_IMM16_X1_HI	28	/* X1 pipe high 16-bit */
++#define R_TILEPRO_IMM16_X0_HA	29	/* X0 pipe high 16-bit, adjusted */
++#define R_TILEPRO_IMM16_X1_HA	30	/* X1 pipe high 16-bit, adjusted */
++#define R_TILEPRO_IMM16_X0_PCREL 31	/* X0 pipe PC relative 16 bit */
++#define R_TILEPRO_IMM16_X1_PCREL 32	/* X1 pipe PC relative 16 bit */
++#define R_TILEPRO_IMM16_X0_LO_PCREL 33	/* X0 pipe PC relative low 16 bit */
++#define R_TILEPRO_IMM16_X1_LO_PCREL 34	/* X1 pipe PC relative low 16 bit */
++#define R_TILEPRO_IMM16_X0_HI_PCREL 35	/* X0 pipe PC relative high 16 bit */
++#define R_TILEPRO_IMM16_X1_HI_PCREL 36	/* X1 pipe PC relative high 16 bit */
++#define R_TILEPRO_IMM16_X0_HA_PCREL 37	/* X0 pipe PC relative ha() 16 bit */
++#define R_TILEPRO_IMM16_X1_HA_PCREL 38	/* X1 pipe PC relative ha() 16 bit */
++#define R_TILEPRO_IMM16_X0_GOT	39	/* X0 pipe 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X1_GOT	40	/* X1 pipe 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X0_GOT_LO 41	/* X0 pipe low 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X1_GOT_LO 42	/* X1 pipe low 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X0_GOT_HI 43	/* X0 pipe high 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X1_GOT_HI 44	/* X1 pipe high 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X0_GOT_HA 45	/* X0 pipe ha() 16-bit GOT offset */
++#define R_TILEPRO_IMM16_X1_GOT_HA 46	/* X1 pipe ha() 16-bit GOT offset */
++#define R_TILEPRO_MMSTART_X0	47	/* X0 pipe mm "start" */
++#define R_TILEPRO_MMEND_X0	48	/* X0 pipe mm "end" */
++#define R_TILEPRO_MMSTART_X1	49	/* X1 pipe mm "start" */
++#define R_TILEPRO_MMEND_X1	50	/* X1 pipe mm "end" */
++#define R_TILEPRO_SHAMT_X0	51	/* X0 pipe shift amount */
++#define R_TILEPRO_SHAMT_X1	52	/* X1 pipe shift amount */
++#define R_TILEPRO_SHAMT_Y0	53	/* Y0 pipe shift amount */
++#define R_TILEPRO_SHAMT_Y1	54	/* Y1 pipe shift amount */
++#define R_TILEPRO_DEST_IMM8_X1	55	/* X1 pipe destination 8-bit */
++/* Relocs 56-59 are currently not defined.  */
++#define R_TILEPRO_TLS_GD_CALL	60	/* "jal" for TLS GD */
++#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61	/* X0 pipe "addi" for TLS GD */
++#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62	/* X1 pipe "addi" for TLS GD */
++#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63	/* Y0 pipe "addi" for TLS GD */
++#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64	/* Y1 pipe "addi" for TLS GD */
++#define R_TILEPRO_TLS_IE_LOAD	65	/* "lw_tls" for TLS IE */
++#define R_TILEPRO_IMM16_X0_TLS_GD 66	/* X0 pipe 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X1_TLS_GD 67	/* X1 pipe 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68	/* X0 pipe low 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69	/* X1 pipe low 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70	/* X0 pipe high 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71	/* X1 pipe high 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72	/* X0 pipe ha() 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73	/* X1 pipe ha() 16-bit TLS GD offset */
++#define R_TILEPRO_IMM16_X0_TLS_IE 74	/* X0 pipe 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X1_TLS_IE 75	/* X1 pipe 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76	/* X0 pipe low 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77	/* X1 pipe low 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78	/* X0 pipe high 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79	/* X1 pipe high 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80	/* X0 pipe ha() 16-bit TLS IE offset */
++#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81	/* X1 pipe ha() 16-bit TLS IE offset */
++#define R_TILEPRO_TLS_DTPMOD32	82	/* ID of module containing symbol */
++#define R_TILEPRO_TLS_DTPOFF32	83	/* Offset in TLS block */
++#define R_TILEPRO_TLS_TPOFF32	84	/* Offset in static TLS block */
++#define R_TILEPRO_IMM16_X0_TLS_LE 85	/* X0 pipe 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X1_TLS_LE 86	/* X1 pipe 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87	/* X0 pipe low 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88	/* X1 pipe low 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89	/* X0 pipe high 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90	/* X1 pipe high 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91	/* X0 pipe ha() 16-bit TLS LE offset */
++#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92	/* X1 pipe ha() 16-bit TLS LE offset */
++
++#define R_TILEPRO_GNU_VTINHERIT	128	/* GNU C++ vtable hierarchy */
++#define R_TILEPRO_GNU_VTENTRY	129	/* GNU C++ vtable member usage */
++
++#define R_TILEPRO_NUM		130
++
++
++/* TILE-Gx relocations.  */
++#define R_TILEGX_NONE		0	/* No reloc */
++#define R_TILEGX_64		1	/* Direct 64 bit */
++#define R_TILEGX_32		2	/* Direct 32 bit */
++#define R_TILEGX_16		3	/* Direct 16 bit */
++#define R_TILEGX_8		4	/* Direct 8 bit */
++#define R_TILEGX_64_PCREL	5	/* PC relative 64 bit */
++#define R_TILEGX_32_PCREL	6	/* PC relative 32 bit */
++#define R_TILEGX_16_PCREL	7	/* PC relative 16 bit */
++#define R_TILEGX_8_PCREL	8	/* PC relative 8 bit */
++#define R_TILEGX_HW0		9	/* hword 0 16-bit */
++#define R_TILEGX_HW1		10	/* hword 1 16-bit */
++#define R_TILEGX_HW2		11	/* hword 2 16-bit */
++#define R_TILEGX_HW3		12	/* hword 3 16-bit */
++#define R_TILEGX_HW0_LAST	13	/* last hword 0 16-bit */
++#define R_TILEGX_HW1_LAST	14	/* last hword 1 16-bit */
++#define R_TILEGX_HW2_LAST	15	/* last hword 2 16-bit */
++#define R_TILEGX_COPY		16	/* Copy relocation */
++#define R_TILEGX_GLOB_DAT	17	/* Create GOT entry */
++#define R_TILEGX_JMP_SLOT	18	/* Create PLT entry */
++#define R_TILEGX_RELATIVE	19	/* Adjust by program base */
++#define R_TILEGX_BROFF_X1	20	/* X1 pipe branch offset */
++#define R_TILEGX_JUMPOFF_X1	21	/* X1 pipe jump offset */
++#define R_TILEGX_JUMPOFF_X1_PLT	22	/* X1 pipe jump offset to PLT */
++#define R_TILEGX_IMM8_X0	23	/* X0 pipe 8-bit */
++#define R_TILEGX_IMM8_Y0	24	/* Y0 pipe 8-bit */
++#define R_TILEGX_IMM8_X1	25	/* X1 pipe 8-bit */
++#define R_TILEGX_IMM8_Y1	26	/* Y1 pipe 8-bit */
++#define R_TILEGX_DEST_IMM8_X1	27	/* X1 pipe destination 8-bit */
++#define R_TILEGX_MT_IMM14_X1	28	/* X1 pipe mtspr */
++#define R_TILEGX_MF_IMM14_X1	29	/* X1 pipe mfspr */
++#define R_TILEGX_MMSTART_X0	30	/* X0 pipe mm "start" */
++#define R_TILEGX_MMEND_X0	31	/* X0 pipe mm "end" */
++#define R_TILEGX_SHAMT_X0	32	/* X0 pipe shift amount */
++#define R_TILEGX_SHAMT_X1	33	/* X1 pipe shift amount */
++#define R_TILEGX_SHAMT_Y0	34	/* Y0 pipe shift amount */
++#define R_TILEGX_SHAMT_Y1	35	/* Y1 pipe shift amount */
++#define R_TILEGX_IMM16_X0_HW0	36	/* X0 pipe hword 0 */
++#define R_TILEGX_IMM16_X1_HW0	37	/* X1 pipe hword 0 */
++#define R_TILEGX_IMM16_X0_HW1	38	/* X0 pipe hword 1 */
++#define R_TILEGX_IMM16_X1_HW1	39	/* X1 pipe hword 1 */
++#define R_TILEGX_IMM16_X0_HW2	40	/* X0 pipe hword 2 */
++#define R_TILEGX_IMM16_X1_HW2	41	/* X1 pipe hword 2 */
++#define R_TILEGX_IMM16_X0_HW3	42	/* X0 pipe hword 3 */
++#define R_TILEGX_IMM16_X1_HW3	43	/* X1 pipe hword 3 */
++#define R_TILEGX_IMM16_X0_HW0_LAST 44	/* X0 pipe last hword 0 */
++#define R_TILEGX_IMM16_X1_HW0_LAST 45	/* X1 pipe last hword 0 */
++#define R_TILEGX_IMM16_X0_HW1_LAST 46	/* X0 pipe last hword 1 */
++#define R_TILEGX_IMM16_X1_HW1_LAST 47	/* X1 pipe last hword 1 */
++#define R_TILEGX_IMM16_X0_HW2_LAST 48	/* X0 pipe last hword 2 */
++#define R_TILEGX_IMM16_X1_HW2_LAST 49	/* X1 pipe last hword 2 */
++#define R_TILEGX_IMM16_X0_HW0_PCREL 50	/* X0 pipe PC relative hword 0 */
++#define R_TILEGX_IMM16_X1_HW0_PCREL 51	/* X1 pipe PC relative hword 0 */
++#define R_TILEGX_IMM16_X0_HW1_PCREL 52	/* X0 pipe PC relative hword 1 */
++#define R_TILEGX_IMM16_X1_HW1_PCREL 53	/* X1 pipe PC relative hword 1 */
++#define R_TILEGX_IMM16_X0_HW2_PCREL 54	/* X0 pipe PC relative hword 2 */
++#define R_TILEGX_IMM16_X1_HW2_PCREL 55	/* X1 pipe PC relative hword 2 */
++#define R_TILEGX_IMM16_X0_HW3_PCREL 56	/* X0 pipe PC relative hword 3 */
++#define R_TILEGX_IMM16_X1_HW3_PCREL 57	/* X1 pipe PC relative hword 3 */
++#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */
++#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */
++#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */
++#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */
++#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */
++#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */
++#define R_TILEGX_IMM16_X0_HW0_GOT 64	/* X0 pipe hword 0 GOT offset */
++#define R_TILEGX_IMM16_X1_HW0_GOT 65	/* X1 pipe hword 0 GOT offset */
++/* Relocs 66-71 are currently not defined.  */
++#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */
++#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */
++#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */
++#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */
++/* Relocs 76-77 are currently not defined.  */
++#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78	/* X0 pipe hword 0 TLS GD offset */
++#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79	/* X1 pipe hword 0 TLS GD offset */
++#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80	/* X0 pipe hword 0 TLS LE offset */
++#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81	/* X1 pipe hword 0 TLS LE offset */
++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */
++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */
++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */
++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */
++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */
++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */
++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */
++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */
++/* Relocs 90-91 are currently not defined.  */
++#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92	/* X0 pipe hword 0 TLS IE offset */
++#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93	/* X1 pipe hword 0 TLS IE offset */
++/* Relocs 94-99 are currently not defined.  */
++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */
++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */
++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */
++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */
++/* Relocs 104-105 are currently not defined.  */
++#define R_TILEGX_TLS_DTPMOD64	106	/* 64-bit ID of symbol's module */
++#define R_TILEGX_TLS_DTPOFF64	107	/* 64-bit offset in TLS block */
++#define R_TILEGX_TLS_TPOFF64	108	/* 64-bit offset in static TLS block */
++#define R_TILEGX_TLS_DTPMOD32	109	/* 32-bit ID of symbol's module */
++#define R_TILEGX_TLS_DTPOFF32	110	/* 32-bit offset in TLS block */
++#define R_TILEGX_TLS_TPOFF32	111	/* 32-bit offset in static TLS block */
++#define R_TILEGX_TLS_GD_CALL	112	/* "jal" for TLS GD */
++#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113	/* X0 pipe "addi" for TLS GD */
++#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114	/* X1 pipe "addi" for TLS GD */
++#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115	/* Y0 pipe "addi" for TLS GD */
++#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116	/* Y1 pipe "addi" for TLS GD */
++#define R_TILEGX_TLS_IE_LOAD	117	/* "ld_tls" for TLS IE */
++#define R_TILEGX_IMM8_X0_TLS_ADD 118	/* X0 pipe "addi" for TLS GD/IE */
++#define R_TILEGX_IMM8_X1_TLS_ADD 119	/* X1 pipe "addi" for TLS GD/IE */
++#define R_TILEGX_IMM8_Y0_TLS_ADD 120	/* Y0 pipe "addi" for TLS GD/IE */
++#define R_TILEGX_IMM8_Y1_TLS_ADD 121	/* Y1 pipe "addi" for TLS GD/IE */
++
++#define R_TILEGX_GNU_VTINHERIT	128	/* GNU C++ vtable hierarchy */
++#define R_TILEGX_GNU_VTENTRY	129	/* GNU C++ vtable member usage */
++
++#define R_TILEGX_NUM		130
++
++#endif	/* elf.h */
+--- a/scripts/mod/mk_elfconfig.c
++++ b/scripts/mod/mk_elfconfig.c
+@@ -2,7 +2,11 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
++#ifndef __APPLE__
+ #include <elf.h>
++#else
++#include "elf.h"
++#endif
+ 
+ int
+ main(int argc, char **argv)
+--- a/scripts/mod/modpost.h
++++ b/scripts/mod/modpost.h
+@@ -8,7 +8,11 @@
+ #include <sys/mman.h>
+ #include <fcntl.h>
+ #include <unistd.h>
++#if !(defined(__APPLE__) || defined(__CYGWIN__))
+ #include <elf.h>
++#else
++#include "elf.h"
++#endif
+ 
+ #include "elfconfig.h"
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/211-darwin-uuid-typedef-clash.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/211-darwin-uuid-typedef-clash.patch
new file mode 100644
index 0000000..50a6227
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/211-darwin-uuid-typedef-clash.patch
@@ -0,0 +1,22 @@
+From e44fc2af1ddc452b6659d08c16973d65c73b7d0a Mon Sep 17 00:00:00 2001
+From: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
+Date: Wed, 5 Feb 2020 18:36:43 +0000
+Subject: [PATCH] file2alias: build on macos
+
+Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
+---
+ scripts/mod/file2alias.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/scripts/mod/file2alias.c
++++ b/scripts/mod/file2alias.c
+@@ -38,6 +38,9 @@ typedef struct {
+ 	__u8 b[16];
+ } guid_t;
+ 
++#ifdef __APPLE__
++#define uuid_t compat_uuid_t
++#endif
+ /* backwards compatibility, don't use in new code */
+ typedef struct {
+ 	__u8 b[16];
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/212-tools_portability.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/212-tools_portability.patch
new file mode 100644
index 0000000..0d8eb6f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/212-tools_portability.patch
@@ -0,0 +1,110 @@
+From 48232d3d931c95953ce2ddfe7da7bb164aef6a73 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 7 Jul 2017 17:03:16 +0200
+Subject: fix portability of some includes files in tools/ used on the host
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ tools/include/tools/be_byteshift.h |  4 ++++
+ tools/include/tools/le_byteshift.h |  4 ++++
+ tools/include/tools/linux_types.h  | 22 ++++++++++++++++++++++
+ 3 files changed, 30 insertions(+)
+ create mode 100644 tools/include/tools/linux_types.h
+
+--- a/tools/include/tools/be_byteshift.h
++++ b/tools/include/tools/be_byteshift.h
+@@ -2,6 +2,10 @@
+ #ifndef _TOOLS_BE_BYTESHIFT_H
+ #define _TOOLS_BE_BYTESHIFT_H
+ 
++#ifndef __linux__
++#include "linux_types.h"
++#endif
++
+ #include <stdint.h>
+ 
+ static inline uint16_t __get_unaligned_be16(const uint8_t *p)
+--- a/tools/include/tools/le_byteshift.h
++++ b/tools/include/tools/le_byteshift.h
+@@ -2,6 +2,10 @@
+ #ifndef _TOOLS_LE_BYTESHIFT_H
+ #define _TOOLS_LE_BYTESHIFT_H
+ 
++#ifndef __linux__
++#include "linux_types.h"
++#endif
++
+ #include <stdint.h>
+ 
+ static inline uint16_t __get_unaligned_le16(const uint8_t *p)
+--- /dev/null
++++ b/tools/include/tools/linux_types.h
+@@ -0,0 +1,26 @@
++#ifndef __LINUX_TYPES_H
++#define __LINUX_TYPES_H
++
++#include <stdint.h>
++
++typedef int8_t __s8;
++typedef uint8_t __u8;
++typedef uint8_t __be8;
++typedef uint8_t __le8;
++
++typedef int16_t __s16;
++typedef uint16_t __u16;
++typedef uint16_t __be16;
++typedef uint16_t __le16;
++
++typedef int32_t __s32;
++typedef uint32_t __u32;
++typedef uint32_t __be32;
++typedef uint32_t __le32;
++
++typedef int64_t __s64;
++typedef uint64_t __u64;
++typedef uint64_t __be64;
++typedef uint64_t __le64;
++
++#endif
+--- a/tools/include/linux/types.h
++++ b/tools/include/linux/types.h
+@@ -7,8 +7,12 @@
+ #include <stdint.h>
+ 
+ #define __SANE_USERSPACE_TYPES__	/* For PPC64, to get LL64 types */
++#ifndef __linux__
++#include <tools/linux_types.h>
++#else
+ #include <asm/types.h>
+ #include <asm/posix_types.h>
++#endif
+ 
+ struct page;
+ struct kmem_cache;
+--- a/tools/perf/pmu-events/jevents.c
++++ b/tools/perf/pmu-events/jevents.c
+@@ -1,4 +1,6 @@
++#ifdef __linux__
+ #define  _XOPEN_SOURCE 500	/* needed for nftw() */
++#endif
+ #define  _GNU_SOURCE		/* needed for asprintf() */
+ 
+ /* Parse event JSON files */
+@@ -35,6 +37,7 @@
+ #include <stdlib.h>
+ #include <errno.h>
+ #include <string.h>
++#include <strings.h>
+ #include <ctype.h>
+ #include <unistd.h>
+ #include <stdarg.h>
+--- a/tools/perf/pmu-events/json.c
++++ b/tools/perf/pmu-events/json.c
+@@ -38,7 +38,6 @@
+ #include <unistd.h>
+ #include "jsmn.h"
+ #include "json.h"
+-#include <linux/kernel.h>
+ 
+ 
+ static char *mapfile(const char *fn, size_t *size)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/214-spidev_h_portability.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/214-spidev_h_portability.patch
new file mode 100644
index 0000000..415e9a4
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/214-spidev_h_portability.patch
@@ -0,0 +1,24 @@
+From be9be95ff10e16a5b4ad36f903978d0cc5747024 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 7 Jul 2017 17:04:08 +0200
+Subject: kernel: fix linux/spi/spidev.h portability issues with musl
+
+Felix will try to get this define included into musl
+
+lede-commit: 795e7cf60de19e7a076a46874fab7bb88b43bbff
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ include/uapi/linux/spi/spidev.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/include/uapi/linux/spi/spidev.h
++++ b/include/uapi/linux/spi/spidev.h
+@@ -117,7 +117,7 @@ struct spi_ioc_transfer {
+ 
+ /* not all platforms use <asm-generic/ioctl.h> or _IOC_TYPECHECK() ... */
+ #define SPI_MSGSIZE(N) \
+-	((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \
++	((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << 13)) \
+ 		? ((N)*(sizeof (struct spi_ioc_transfer))) : 0)
+ #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/220-gc_sections.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/220-gc_sections.patch
new file mode 100644
index 0000000..fdfaf51
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/220-gc_sections.patch
@@ -0,0 +1,136 @@
+From e3d8676f5722b7622685581e06e8f53e6138e3ab Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 15 Jul 2017 23:42:36 +0200
+Subject: use -ffunction-sections, -fdata-sections and --gc-sections
+
+In combination with kernel symbol export stripping this significantly reduces
+the kernel image size. Used on both ARM and MIPS architectures.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ Makefile                          | 10 +++----
+ arch/arm/Kconfig                  |  1 +
+ arch/arm/boot/compressed/Makefile |  1 +
+ arch/arm/kernel/vmlinux.lds.S     | 26 ++++++++--------
+ arch/mips/Kconfig                 |  1 +
+ arch/mips/kernel/vmlinux.lds.S    |  4 +--
+ include/asm-generic/vmlinux.lds.h | 63 ++++++++++++++++++++-------------------
+ 7 files changed, 55 insertions(+), 51 deletions(-)
+
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -112,6 +112,7 @@ config ARM
+ 	select HAVE_UID16
+ 	select HAVE_VIRT_CPU_ACCOUNTING_GEN
+ 	select IRQ_FORCED_THREADING
++	select HAVE_LD_DEAD_CODE_DATA_ELIMINATION
+ 	select MODULES_USE_ELF_REL
+ 	select NEED_DMA_MAP_STATE
+ 	select OF_EARLY_FLATTREE if OF
+--- a/arch/arm/boot/compressed/Makefile
++++ b/arch/arm/boot/compressed/Makefile
+@@ -108,6 +108,7 @@ ifeq ($(CONFIG_FUNCTION_TRACER),y)
+ ORIG_CFLAGS := $(KBUILD_CFLAGS)
+ KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
+ endif
++KBUILD_CFLAGS_KERNEL := $(patsubst -f%-sections,,$(KBUILD_CFLAGS_KERNEL))
+ 
+ # -fstack-protector-strong triggers protection checks in this code,
+ # but it is being used too early to link to meaningful stack_chk logic.
+--- a/arch/arm/kernel/vmlinux.lds.S
++++ b/arch/arm/kernel/vmlinux.lds.S
+@@ -100,24 +100,24 @@ SECTIONS
+ 	}
+ 	.init.arch.info : {
+ 		__arch_info_begin = .;
+-		*(.arch.info.init)
++		KEEP(*(.arch.info.init))
+ 		__arch_info_end = .;
+ 	}
+ 	.init.tagtable : {
+ 		__tagtable_begin = .;
+-		*(.taglist.init)
++		KEEP(*(.taglist.init))
+ 		__tagtable_end = .;
+ 	}
+ #ifdef CONFIG_SMP_ON_UP
+ 	.init.smpalt : {
+ 		__smpalt_begin = .;
+-		*(.alt.smp.init)
++		KEEP(*(.alt.smp.init))
+ 		__smpalt_end = .;
+ 	}
+ #endif
+ 	.init.pv_table : {
+ 		__pv_table_begin = .;
+-		*(.pv_table)
++		KEEP(*(.pv_table))
+ 		__pv_table_end = .;
+ 	}
+ 
+--- a/arch/arm/kernel/vmlinux.lds.h
++++ b/arch/arm/kernel/vmlinux.lds.h
+@@ -22,13 +22,13 @@
+ #define ARM_MMU_DISCARD(x)
+ #else
+ #define ARM_MMU_KEEP(x)
+-#define ARM_MMU_DISCARD(x)	x
++#define ARM_MMU_DISCARD(x)	KEEP(x)
+ #endif
+ 
+ #define PROC_INFO							\
+ 		. = ALIGN(4);						\
+ 		__proc_info_begin = .;					\
+-		*(.proc.info.init)					\
++		KEEP(*(.proc.info.init))				\
+ 		__proc_info_end = .;
+ 
+ #define HYPERVISOR_TEXT							\
+@@ -39,11 +39,11 @@
+ #define IDMAP_TEXT							\
+ 		ALIGN_FUNCTION();					\
+ 		__idmap_text_start = .;					\
+-		*(.idmap.text)						\
++		KEEP(*(.idmap.text))					\
+ 		__idmap_text_end = .;					\
+ 		. = ALIGN(PAGE_SIZE);					\
+ 		__hyp_idmap_text_start = .;				\
+-		*(.hyp.idmap.text)					\
++		KEEP(*(.hyp.idmap.text))				\
+ 		__hyp_idmap_text_end = .;
+ 
+ #define ARM_DISCARD							\
+@@ -86,12 +86,12 @@
+ 	. = ALIGN(8);							\
+ 	.ARM.unwind_idx : {						\
+ 		__start_unwind_idx = .;					\
+-		*(.ARM.exidx*)						\
++		KEEP(*(.ARM.exidx*))					\
+ 		__stop_unwind_idx = .;					\
+ 	}								\
+ 	.ARM.unwind_tab : {						\
+ 		__start_unwind_tab = .;					\
+-		*(.ARM.extab*)						\
++		KEEP(*(.ARM.extab*))					\
+ 		__stop_unwind_tab = .;					\
+ 	}
+ 
+@@ -102,14 +102,14 @@
+ #define ARM_VECTORS							\
+ 	__vectors_start = .;						\
+ 	.vectors 0xffff0000 : AT(__vectors_start) {			\
+-		*(.vectors)						\
++		KEEP(*(.vectors))					\
+ 	}								\
+ 	. = __vectors_start + SIZEOF(.vectors);				\
+ 	__vectors_end = .;						\
+ 									\
+ 	__stubs_start = .;						\
+ 	.stubs ADDR(.vectors) + 0x1000 : AT(__stubs_start) {		\
+-		*(.stubs)						\
++		KEEP(*(.stubs))						\
+ 	}								\
+ 	. = __stubs_start + SIZEOF(.stubs);				\
+ 	__stubs_end = .;						\
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/221-module_exports.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/221-module_exports.patch
new file mode 100644
index 0000000..47f40ac
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/221-module_exports.patch
@@ -0,0 +1,109 @@
+From b14784e7883390c20ed3ff904892255404a5914b Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 7 Jul 2017 17:05:53 +0200
+Subject: add an optional config option for stripping all unnecessary symbol exports from the kernel image
+
+lede-commit: bb5a40c64b7c4f4848509fa0a6625055fc9e66cc
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ include/asm-generic/vmlinux.lds.h | 18 +++++++++++++++---
+ include/linux/export.h            |  9 ++++++++-
+ scripts/Makefile.build            |  2 +-
+ 3 files changed, 24 insertions(+), 5 deletions(-)
+
+--- a/include/asm-generic/vmlinux.lds.h
++++ b/include/asm-generic/vmlinux.lds.h
+@@ -54,6 +54,16 @@
+ #define LOAD_OFFSET 0
+ #endif
+ 
++#ifndef SYMTAB_KEEP
++#define SYMTAB_KEEP KEEP(*(SORT(___ksymtab+*)))
++#define SYMTAB_KEEP_GPL KEEP(*(SORT(___ksymtab_gpl+*)))
++#endif
++
++#ifndef SYMTAB_DISCARD
++#define SYMTAB_DISCARD
++#define SYMTAB_DISCARD_GPL
++#endif
++
+ /* Align . to a 8 byte boundary equals to maximum function alignment. */
+ #define ALIGN_FUNCTION()  . = ALIGN(8)
+ 
+@@ -407,14 +417,14 @@
+ 	/* Kernel symbol table: Normal symbols */			\
+ 	__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\
+ 		__start___ksymtab = .;					\
+-		KEEP(*(SORT(___ksymtab+*)))				\
++		SYMTAB_KEEP						\
+ 		__stop___ksymtab = .;					\
+ 	}								\
+ 									\
+ 	/* Kernel symbol table: GPL-only symbols */			\
+ 	__ksymtab_gpl     : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) {	\
+ 		__start___ksymtab_gpl = .;				\
+-		KEEP(*(SORT(___ksymtab_gpl+*)))				\
++		SYMTAB_KEEP_GPL						\
+ 		__stop___ksymtab_gpl = .;				\
+ 	}								\
+ 									\
+@@ -476,7 +486,7 @@
+ 									\
+ 	/* Kernel symbol table: strings */				\
+         __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {	\
+-		*(__ksymtab_strings)					\
++		*(__ksymtab_strings+*)					\
+ 	}								\
+ 									\
+ 	/* __*init sections */						\
+@@ -905,6 +915,8 @@
+ 	EXIT_TEXT							\
+ 	EXIT_DATA							\
+ 	EXIT_CALL							\
++	SYMTAB_DISCARD							\
++	SYMTAB_DISCARD_GPL						\
+ 	*(.discard)							\
+ 	*(.discard.*)							\
+ 	*(.modinfo)							\
+--- a/include/linux/export.h
++++ b/include/linux/export.h
+@@ -98,18 +98,26 @@ struct kernel_symbol {
+ 
+ #else
+ 
++#ifdef MODULE
++#define __EXPORT_SUFFIX(sym)
++#else
++#define __EXPORT_SUFFIX(sym) "+" #sym
++#endif
++
+ #define ___export_symbol_common(sym, sec)				\
+ 	extern typeof(sym) sym;						\
+ 	__CRC_SYMBOL(sym, sec);						\
+ 	static const char __kstrtab_##sym[]				\
+-	__attribute__((section("__ksymtab_strings"), used, aligned(1)))	\
++	__attribute__((section("__ksymtab_strings"			\
++	  __EXPORT_SUFFIX(sym)), used, aligned(1)))			\
+ 	= #sym								\
+ 
+ /* For every exported symbol, place a struct in the __ksymtab section */
+ #define ___EXPORT_SYMBOL_NS(sym, sec, ns)				\
+ 	___export_symbol_common(sym, sec);				\
+ 	static const char __kstrtabns_##sym[]				\
+-	__attribute__((section("__ksymtab_strings"), used, aligned(1)))	\
++	__attribute__((section("__ksymtab_strings"			\
++	  __EXPORT_SUFFIX(sym)), used, aligned(1)))			\
+ 	= #ns;								\
+ 	__KSYMTAB_ENTRY_NS(sym, sec)
+ 
+--- a/scripts/Makefile.build
++++ b/scripts/Makefile.build
+@@ -350,7 +350,7 @@ targets += $(extra-y) $(MAKECMDGOALS) $(
+ # Linker scripts preprocessor (.lds.S -> .lds)
+ # ---------------------------------------------------------------------------
+ quiet_cmd_cpp_lds_S = LDS     $@
+-      cmd_cpp_lds_S = $(CPP) $(cpp_flags) -P -U$(ARCH) \
++      cmd_cpp_lds_S = $(CPP) $(EXTRA_LDSFLAGS) $(cpp_flags) -P -U$(ARCH) \
+ 	                     -D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $<
+ 
+ $(obj)/%.lds: $(src)/%.lds.S FORCE
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/230-openwrt_lzma_options.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/230-openwrt_lzma_options.patch
new file mode 100644
index 0000000..809ccbc
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/230-openwrt_lzma_options.patch
@@ -0,0 +1,71 @@
+From b3d00b452467f621317953d9e4c6f9ae8dcfd271 Mon Sep 17 00:00:00 2001
+From: Imre Kaloz <kaloz@openwrt.org>
+Date: Fri, 7 Jul 2017 17:06:55 +0200
+Subject: use the openwrt lzma options for now
+
+lede-commit: 548de949f392049420a6a1feeef118b30ab8ea8c
+Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
+---
+ lib/decompress.c              |  1 +
+ scripts/Makefile.lib          |  2 +-
+ usr/gen_initramfs_list.sh | 10 +++++-----
+ 3 files changed, 7 insertions(+), 6 deletions(-)
+
+--- a/lib/decompress.c
++++ b/lib/decompress.c
+@@ -49,6 +49,7 @@ static const struct compress_format comp
+ 	{ {0x1f, 0x9e}, "gzip", gunzip },
+ 	{ {0x42, 0x5a}, "bzip2", bunzip2 },
+ 	{ {0x5d, 0x00}, "lzma", unlzma },
++	{ {0x6d, 0x00}, "lzma-openwrt", unlzma },
+ 	{ {0xfd, 0x37}, "xz", unxz },
+ 	{ {0x89, 0x4c}, "lzo", unlzo },
+ 	{ {0x02, 0x21}, "lz4", unlz4 },
+--- a/scripts/Makefile.lib
++++ b/scripts/Makefile.lib
+@@ -328,7 +328,7 @@ quiet_cmd_bzip2 = BZIP2   $@
+ # ---------------------------------------------------------------------------
+ 
+ quiet_cmd_lzma = LZMA    $@
+-      cmd_lzma = { cat $(real-prereqs) | $(LZMA) -9; $(size_append); } > $@
++      cmd_lzma = { cat $(real-prereqs) | $(LZMA) e -d20 -lc1 -lp2 -pb2 -eos -si -so; $(size_append); } > $@
+ 
+ quiet_cmd_lzo = LZO     $@
+       cmd_lzo = { cat $(real-prereqs) | $(KLZOP) -9; $(size_append); } > $@
+--- a/usr/gen_initramfs_list.sh
++++ b/usr/gen_initramfs_list.sh
+@@ -229,7 +229,7 @@ cpio_list=
+ output="/dev/stdout"
+ output_file=""
+ is_cpio_compressed=
+-compr="gzip -n -9 -f"
++compr="gzip -n -9 -f -"
+ 
+ arg="$1"
+ case "$arg" in
+@@ -245,13 +245,13 @@ case "$arg" in
+ 		output=${cpio_list}
+ 		echo "$output_file" | grep -q "\.gz$" \
+                 && [ -x "`which gzip 2> /dev/null`" ] \
+-                && compr="gzip -n -9 -f"
++                && compr="gzip -n -9 -f -"
+ 		echo "$output_file" | grep -q "\.bz2$" \
+                 && [ -x "`which bzip2 2> /dev/null`" ] \
+-                && compr="bzip2 -9 -f"
++                && compr="bzip2 -9 -f -"
+ 		echo "$output_file" | grep -q "\.lzma$" \
+                 && [ -x "`which lzma 2> /dev/null`" ] \
+-                && compr="lzma -9 -f"
++                && compr="lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so"
+ 		echo "$output_file" | grep -q "\.xz$" \
+                 && [ -x "`which xz 2> /dev/null`" ] \
+                 && compr="xz --check=crc32 --lzma2=dict=1MiB"
+@@ -320,7 +320,7 @@ if [ ! -z ${output_file} ]; then
+ 	if [ "${is_cpio_compressed}" = "compressed" ]; then
+ 		cat ${cpio_tfile} > ${output_file}
+ 	else
+-		(cat ${cpio_tfile} | ${compr}  - > ${output_file}) \
++		(cat ${cpio_tfile} | ${compr} > ${output_file}) \
+ 		|| (rm -f ${output_file} ; false)
+ 	fi
+ 	[ -z ${cpio_file} ] && rm ${cpio_tfile}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/249-udp-tunnel-selection.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/249-udp-tunnel-selection.patch
new file mode 100644
index 0000000..2c74298
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/249-udp-tunnel-selection.patch
@@ -0,0 +1,11 @@
+--- a/net/ipv4/Kconfig
++++ b/net/ipv4/Kconfig
+@@ -315,7 +315,7 @@ config NET_IPVTI
+ 	  on top.
+ 
+ config NET_UDP_TUNNEL
+-	tristate
++	tristate "IP: UDP tunneling support"
+ 	select NET_IP_TUNNEL
+ 	default n
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/250-netfilter_depends.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/250-netfilter_depends.patch
new file mode 100644
index 0000000..d03cb53
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/250-netfilter_depends.patch
@@ -0,0 +1,27 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: hack: net: remove bogus netfilter dependencies
+
+lede-commit: 589d2a377dee27d206fc3725325309cf649e4df6
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ net/netfilter/Kconfig | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -228,7 +228,6 @@ config NF_CONNTRACK_FTP
+ 
+ config NF_CONNTRACK_H323
+ 	tristate "H.323 protocol support"
+-	depends on IPV6 || IPV6=n
+ 	depends on NETFILTER_ADVANCED
+ 	help
+ 	  H.323 is a VoIP signalling protocol from ITU-T. As one of the most
+@@ -1088,7 +1087,6 @@ config NETFILTER_XT_TARGET_SECMARK
+ 
+ config NETFILTER_XT_TARGET_TCPMSS
+ 	tristate '"TCPMSS" target support'
+-	depends on IPV6 || IPV6=n
+ 	default m if NETFILTER_ADVANCED=n
+ 	---help---
+ 	  This option adds a `TCPMSS' target, which allows you to alter the
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/251-sound_kconfig.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/251-sound_kconfig.patch
new file mode 100644
index 0000000..f593417
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/251-sound_kconfig.patch
@@ -0,0 +1,199 @@
+From da3c50704f14132f4adf80d48e9a4cd5d46e54c9 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Fri, 7 Jul 2017 17:09:21 +0200
+Subject: kconfig: owrt specifc dependencies
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ crypto/Kconfig        | 10 +++++-----
+ drivers/bcma/Kconfig  |  1 +
+ drivers/ssb/Kconfig   |  3 ++-
+ lib/Kconfig           |  8 ++++----
+ net/netfilter/Kconfig |  2 +-
+ net/wireless/Kconfig  | 17 ++++++++++-------
+ sound/core/Kconfig    |  4 ++--
+ 7 files changed, 25 insertions(+), 20 deletions(-)
+
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -33,7 +33,7 @@ config CRYPTO_FIPS
+ 	  this is.
+ 
+ config CRYPTO_ALGAPI
+-	tristate
++	tristate "ALGAPI"
+ 	select CRYPTO_ALGAPI2
+ 	help
+ 	  This option provides the API for cryptographic algorithms.
+@@ -42,7 +42,7 @@ config CRYPTO_ALGAPI2
+ 	tristate
+ 
+ config CRYPTO_AEAD
+-	tristate
++	tristate "AEAD"
+ 	select CRYPTO_AEAD2
+ 	select CRYPTO_ALGAPI
+ 
+@@ -53,7 +53,7 @@ config CRYPTO_AEAD2
+ 	select CRYPTO_RNG2
+ 
+ config CRYPTO_BLKCIPHER
+-	tristate
++	tristate "BLKCIPHER"
+ 	select CRYPTO_BLKCIPHER2
+ 	select CRYPTO_ALGAPI
+ 
+@@ -63,7 +63,7 @@ config CRYPTO_BLKCIPHER2
+ 	select CRYPTO_RNG2
+ 
+ config CRYPTO_HASH
+-	tristate
++	tristate "HASH"
+ 	select CRYPTO_HASH2
+ 	select CRYPTO_ALGAPI
+ 
+@@ -72,7 +72,7 @@ config CRYPTO_HASH2
+ 	select CRYPTO_ALGAPI2
+ 
+ config CRYPTO_RNG
+-	tristate
++	tristate "RNG"
+ 	select CRYPTO_RNG2
+ 	select CRYPTO_ALGAPI
+ 
+--- a/drivers/bcma/Kconfig
++++ b/drivers/bcma/Kconfig
+@@ -16,6 +16,7 @@ if BCMA
+ # Support for Block-I/O. SELECT this from the driver that needs it.
+ config BCMA_BLOCKIO
+ 	bool
++	default y
+ 
+ config BCMA_HOST_PCI_POSSIBLE
+ 	bool
+--- a/drivers/ssb/Kconfig
++++ b/drivers/ssb/Kconfig
+@@ -29,6 +29,7 @@ config SSB_SPROM
+ config SSB_BLOCKIO
+ 	bool
+ 	depends on SSB
++	default y
+ 
+ config SSB_PCIHOST_POSSIBLE
+ 	bool
+@@ -49,7 +50,7 @@ config SSB_PCIHOST
+ config SSB_B43_PCI_BRIDGE
+ 	bool
+ 	depends on SSB_PCIHOST
+-	default n
++	default y
+ 
+ config SSB_PCMCIAHOST_POSSIBLE
+ 	bool
+--- a/lib/Kconfig
++++ b/lib/Kconfig
+@@ -402,16 +402,16 @@ config BCH_CONST_T
+ # Textsearch support is select'ed if needed
+ #
+ config TEXTSEARCH
+-	bool
++	bool "Textsearch support"
+ 
+ config TEXTSEARCH_KMP
+-	tristate
++	tristate "Textsearch KMP"
+ 
+ config TEXTSEARCH_BM
+-	tristate
++	tristate "Textsearch BM"
+ 
+ config TEXTSEARCH_FSM
+-	tristate
++	tristate "Textsearch FSM"
+ 
+ config BTREE
+ 	bool
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -11,7 +11,7 @@ config NETFILTER_INGRESS
+ 	  infrastructure.
+ 
+ config NETFILTER_NETLINK
+-	tristate
++	tristate "Netfilter NFNETLINK interface"
+ 
+ config NETFILTER_FAMILY_BRIDGE
+ 	bool
+--- a/net/wireless/Kconfig
++++ b/net/wireless/Kconfig
+@@ -1,6 +1,6 @@
+ # SPDX-License-Identifier: GPL-2.0-only
+ config WIRELESS_EXT
+-	bool
++	bool "Wireless extensions"
+ 
+ config WEXT_CORE
+ 	def_bool y
+@@ -12,10 +12,10 @@ config WEXT_PROC
+ 	depends on WEXT_CORE
+ 
+ config WEXT_SPY
+-	bool
++	bool "WEXT_SPY"
+ 
+ config WEXT_PRIV
+-	bool
++	bool "WEXT_PRIV"
+ 
+ config CFG80211
+ 	tristate "cfg80211 - wireless configuration API"
+@@ -203,7 +203,7 @@ config CFG80211_WEXT_EXPORT
+ endif # CFG80211
+ 
+ config LIB80211
+-	tristate
++	tristate "LIB80211"
+ 	default n
+ 	help
+ 	  This options enables a library of common routines used
+@@ -212,17 +212,17 @@ config LIB80211
+ 	  Drivers should select this themselves if needed.
+ 
+ config LIB80211_CRYPT_WEP
+-	tristate
++	tristate "LIB80211_CRYPT_WEP"
+ 	select CRYPTO_LIB_ARC4
+ 
+ config LIB80211_CRYPT_CCMP
+-	tristate
++	tristate "LIB80211_CRYPT_CCMP"
+ 	select CRYPTO
+ 	select CRYPTO_AES
+ 	select CRYPTO_CCM
+ 
+ config LIB80211_CRYPT_TKIP
+-	tristate
++	tristate "LIB80211_CRYPT_TKIP"
+ 	select CRYPTO_LIB_ARC4
+ 
+ config LIB80211_DEBUG
+--- a/sound/core/Kconfig
++++ b/sound/core/Kconfig
+@@ -17,7 +17,7 @@ config SND_DMAENGINE_PCM
+ 	tristate
+ 
+ config SND_HWDEP
+-	tristate
++	tristate "Sound hardware support"
+ 
+ config SND_SEQ_DEVICE
+ 	tristate
+@@ -27,7 +27,7 @@ config SND_RAWMIDI
+ 	select SND_SEQ_DEVICE if SND_SEQUENCER != n
+ 
+ config SND_COMPRESS_OFFLOAD
+-	tristate
++	tristate "Compression offloading support"
+ 
+ config SND_JACK
+ 	bool
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/259-regmap_dynamic.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/259-regmap_dynamic.patch
new file mode 100644
index 0000000..812e182
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/259-regmap_dynamic.patch
@@ -0,0 +1,125 @@
+From 811d9e2268a62b830cfe93cd8bc929afcb8b198b Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 15 Jul 2017 21:12:38 +0200
+Subject: kernel: move regmap bloat out of the kernel image if it is only being used in modules
+
+lede-commit: 96f39119815028073583e4fca3a9c5fe9141e998
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ drivers/base/regmap/Kconfig  | 15 ++++++++++-----
+ drivers/base/regmap/Makefile | 12 ++++++++----
+ drivers/base/regmap/regmap.c |  3 +++
+ include/linux/regmap.h       |  2 +-
+ 4 files changed, 22 insertions(+), 10 deletions(-)
+
+--- a/drivers/base/regmap/Kconfig
++++ b/drivers/base/regmap/Kconfig
+@@ -4,9 +4,8 @@
+ # subsystems should select the appropriate symbols.
+ 
+ config REGMAP
+-	default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SCCB || REGMAP_I3C)
+ 	select IRQ_DOMAIN if REGMAP_IRQ
+-	bool
++	tristate
+ 
+ config REGCACHE_COMPRESSED
+ 	select LZO_COMPRESS
+@@ -18,38 +17,49 @@ config REGMAP_AC97
+ 
+ config REGMAP_I2C
+ 	tristate
++	select REGMAP
+ 	depends on I2C
+ 
+ config REGMAP_SLIMBUS
+ 	tristate
++	select REGMAP
+ 	depends on SLIMBUS
+ 
+ config REGMAP_SPI
+ 	tristate
++	select REGMAP
++	depends on SPI_MASTER
+ 	depends on SPI
+ 
+ config REGMAP_SPMI
+ 	tristate
++	select REGMAP
+ 	depends on SPMI
+ 
+ config REGMAP_W1
+ 	tristate
++	select REGMAP
+ 	depends on W1
+ 
+ config REGMAP_MMIO
+ 	tristate
++	select REGMAP
+ 
+ config REGMAP_IRQ
+ 	bool
++	select REGMAP
+ 
+ config REGMAP_SOUNDWIRE
+ 	tristate
++	select REGMAP
+ 	depends on SOUNDWIRE
+ 
+ config REGMAP_SCCB
+ 	tristate
++	select REGMAP
+ 	depends on I2C
+ 
+ config REGMAP_I3C
+ 	tristate
++	select REGMAP
+ 	depends on I3C
+--- a/drivers/base/regmap/Makefile
++++ b/drivers/base/regmap/Makefile
+@@ -2,10 +2,14 @@
+ # For include/trace/define_trace.h to include trace.h
+ CFLAGS_regmap.o := -I$(src)
+ 
+-obj-$(CONFIG_REGMAP) += regmap.o regcache.o
+-obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-flat.o
+-obj-$(CONFIG_REGCACHE_COMPRESSED) += regcache-lzo.o
+-obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
++regmap-core-objs = regmap.o regcache.o regcache-rbtree.o regcache-flat.o
++ifdef CONFIG_DEBUG_FS
++regmap-core-objs += regmap-debugfs.o
++endif
++ifdef CONFIG_REGCACHE_COMPRESSED
++regmap-core-objs += regcache-lzo.o
++endif
++obj-$(CONFIG_REGMAP) += regmap-core.o
+ obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o
+ obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
+ obj-$(CONFIG_REGMAP_SLIMBUS) += regmap-slimbus.o
+--- a/drivers/base/regmap/regmap.c
++++ b/drivers/base/regmap/regmap.c
+@@ -9,6 +9,7 @@
+ #include <linux/device.h>
+ #include <linux/slab.h>
+ #include <linux/export.h>
++#include <linux/module.h>
+ #include <linux/mutex.h>
+ #include <linux/err.h>
+ #include <linux/of.h>
+@@ -3118,3 +3119,5 @@ static int __init regmap_initcall(void)
+ 	return 0;
+ }
+ postcore_initcall(regmap_initcall);
++
++MODULE_LICENSE("GPL");
+--- a/include/linux/regmap.h
++++ b/include/linux/regmap.h
+@@ -185,7 +185,7 @@ struct reg_sequence {
+ 	pollret ?: ((cond) ? 0 : -ETIMEDOUT); \
+ })
+ 
+-#ifdef CONFIG_REGMAP
++#if IS_REACHABLE(CONFIG_REGMAP)
+ 
+ enum regmap_endian {
+ 	/* Unspecified -> 0 -> Backwards compatible default */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/260-crypto_test_dependencies.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/260-crypto_test_dependencies.patch
new file mode 100644
index 0000000..c1b0b85
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/260-crypto_test_dependencies.patch
@@ -0,0 +1,52 @@
+From fd1799b0bf5efa46dd3e6dfbbf3955564807e508 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 7 Jul 2017 17:12:51 +0200
+Subject: kernel: prevent cryptomgr from pulling in useless extra dependencies for tests that are not run
+
+Reduces kernel size after LZMA by about 5k on MIPS
+
+lede-commit: 044c316167e076479a344c59905e5b435b84a77f
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ crypto/Kconfig   | 13 ++++++-------
+ crypto/algboss.c |  4 ++++
+ 2 files changed, 10 insertions(+), 7 deletions(-)
+
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -120,13 +120,13 @@ config CRYPTO_MANAGER
+ 	  cbc(aes).
+ 
+ config CRYPTO_MANAGER2
+-	def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y)
+-	select CRYPTO_AEAD2
+-	select CRYPTO_HASH2
+-	select CRYPTO_BLKCIPHER2
+-	select CRYPTO_AKCIPHER2
+-	select CRYPTO_KPP2
+-	select CRYPTO_ACOMP2
++	def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y && !CRYPTO_MANAGER_DISABLE_TESTS)
++	select CRYPTO_AEAD2 if !CRYPTO_MANAGER_DISABLE_TESTS
++	select CRYPTO_HASH2 if !CRYPTO_MANAGER_DISABLE_TESTS
++	select CRYPTO_BLKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS
++	select CRYPTO_AKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS
++	select CRYPTO_KPP2 if !CRYPTO_MANAGER_DISABLE_TESTS
++	select CRYPTO_ACOMP2 if !CRYPTO_MANAGER_DISABLE_TESTS
+ 
+ config CRYPTO_USER
+ 	tristate "Userspace cryptographic algorithm configuration"
+--- a/crypto/algboss.c
++++ b/crypto/algboss.c
+@@ -240,8 +240,12 @@ static int cryptomgr_schedule_test(struc
+ 	type = alg->cra_flags;
+ 
+ 	/* Do not test internal algorithms. */
++#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
++	type |= CRYPTO_ALG_TESTED;
++#else
+ 	if (type & CRYPTO_ALG_INTERNAL)
+ 		type |= CRYPTO_ALG_TESTED;
++#endif
+ 
+ 	param->type = type;
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/260-lib-arc4-unhide.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/260-lib-arc4-unhide.patch
new file mode 100644
index 0000000..a7668ac
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/260-lib-arc4-unhide.patch
@@ -0,0 +1,15 @@
+This makes it possible to select CONFIG_CRYPTO_LIB_ARC4 directly. We 
+need this to be able to compile this into the kernel and make use of it 
+from backports.
+
+--- a/lib/crypto/Kconfig
++++ b/lib/crypto/Kconfig
+@@ -6,7 +6,7 @@ config CRYPTO_LIB_AES
+ 	tristate
+ 
+ config CRYPTO_LIB_ARC4
+-	tristate
++	tristate "ARC4 cipher library"
+ 
+ config CRYPTO_ARCH_HAVE_LIB_BLAKE2S
+ 	tristate
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/280-rfkill-stubs.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/280-rfkill-stubs.patch
new file mode 100644
index 0000000..2e48aea
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/280-rfkill-stubs.patch
@@ -0,0 +1,84 @@
+From 236c1acdfef5958010ac9814a9872e0a46fd78ee Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Fri, 7 Jul 2017 17:13:44 +0200
+Subject: rfkill: add fake rfkill support
+
+allow building of modules depending on RFKILL even if RFKILL is not enabled.
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ include/linux/rfkill.h |  2 +-
+ net/Makefile           |  2 +-
+ net/rfkill/Kconfig     | 14 +++++++++-----
+ net/rfkill/Makefile    |  2 +-
+ 4 files changed, 12 insertions(+), 8 deletions(-)
+
+--- a/include/linux/rfkill.h
++++ b/include/linux/rfkill.h
+@@ -64,7 +64,7 @@ struct rfkill_ops {
+ 	int	(*set_block)(void *data, bool blocked);
+ };
+ 
+-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
++#if defined(CONFIG_RFKILL_FULL) || defined(CONFIG_RFKILL_FULL_MODULE)
+ /**
+  * rfkill_alloc - Allocate rfkill structure
+  * @name: name of the struct -- the string is not copied internally
+--- a/net/Makefile
++++ b/net/Makefile
+@@ -53,7 +53,7 @@ obj-$(CONFIG_TIPC)		+= tipc/
+ obj-$(CONFIG_NETLABEL)		+= netlabel/
+ obj-$(CONFIG_IUCV)		+= iucv/
+ obj-$(CONFIG_SMC)		+= smc/
+-obj-$(CONFIG_RFKILL)		+= rfkill/
++obj-$(CONFIG_RFKILL_FULL)	+= rfkill/
+ obj-$(CONFIG_NET_9P)		+= 9p/
+ obj-$(CONFIG_CAIF)		+= caif/
+ ifneq ($(CONFIG_DCB),)
+--- a/net/rfkill/Kconfig
++++ b/net/rfkill/Kconfig
+@@ -2,7 +2,11 @@
+ #
+ # RF switch subsystem configuration
+ #
+-menuconfig RFKILL
++config RFKILL
++	bool
++	default y
++
++menuconfig RFKILL_FULL
+ 	tristate "RF switch subsystem support"
+ 	help
+ 	  Say Y here if you want to have control over RF switches
+@@ -14,19 +18,19 @@ menuconfig RFKILL
+ # LED trigger support
+ config RFKILL_LEDS
+ 	bool
+-	depends on RFKILL
++	depends on RFKILL_FULL
+ 	depends on LEDS_TRIGGERS = y || RFKILL = LEDS_TRIGGERS
+ 	default y
+ 
+ config RFKILL_INPUT
+ 	bool "RF switch input support" if EXPERT
+-	depends on RFKILL
++	depends on RFKILL_FULL
+ 	depends on INPUT = y || RFKILL = INPUT
+ 	default y if !EXPERT
+ 
+ config RFKILL_GPIO
+ 	tristate "GPIO RFKILL driver"
+-	depends on RFKILL
++	depends on RFKILL_FULL
+ 	depends on GPIOLIB || COMPILE_TEST
+ 	default n
+ 	help
+--- a/net/rfkill/Makefile
++++ b/net/rfkill/Makefile
+@@ -5,5 +5,5 @@
+ 
+ rfkill-y			+= core.o
+ rfkill-$(CONFIG_RFKILL_INPUT)	+= input.o
+-obj-$(CONFIG_RFKILL)		+= rfkill.o
++obj-$(CONFIG_RFKILL_FULL)	+= rfkill.o
+ obj-$(CONFIG_RFKILL_GPIO)	+= rfkill-gpio.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/300-MIPS-r4k_cache-use-more-efficient-cache-blast.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/300-MIPS-r4k_cache-use-more-efficient-cache-blast.patch
new file mode 100644
index 0000000..aed08a5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/300-MIPS-r4k_cache-use-more-efficient-cache-blast.patch
@@ -0,0 +1,64 @@
+From: Ben Menchaca <ben.menchaca@qca.qualcomm.com>
+Date: Fri, 7 Jun 2013 18:35:22 -0500
+Subject: MIPS: r4k_cache: use more efficient cache blast
+
+Optimize the compiler output for larger cache blast cases that are
+common for DMA-based networking.
+
+Signed-off-by: Ben Menchaca <ben.menchaca@qca.qualcomm.com>
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+--- a/arch/mips/include/asm/r4kcache.h
++++ b/arch/mips/include/asm/r4kcache.h
+@@ -617,14 +617,46 @@ static inline void prot##extra##blast_##
+ 						    unsigned long end)	\
+ {									\
+ 	unsigned long lsize = cpu_##desc##_line_size();			\
++	unsigned long lsize_2 = lsize * 2;				\
++	unsigned long lsize_3 = lsize * 3;				\
++	unsigned long lsize_4 = lsize * 4;				\
++	unsigned long lsize_5 = lsize * 5;				\
++	unsigned long lsize_6 = lsize * 6;				\
++	unsigned long lsize_7 = lsize * 7;				\
++	unsigned long lsize_8 = lsize * 8;				\
+ 	unsigned long addr = start & ~(lsize - 1);			\
+-	unsigned long aend = (end - 1) & ~(lsize - 1);			\
++	unsigned long aend = (end + lsize - 1) & ~(lsize - 1);		\
++	int lines = (aend - addr) / lsize;				\
+ 									\
+-	while (1) {							\
++	while (lines >= 8) {						\
++		prot##cache_op(hitop, addr);				\
++		prot##cache_op(hitop, addr + lsize);			\
++		prot##cache_op(hitop, addr + lsize_2);			\
++		prot##cache_op(hitop, addr + lsize_3);			\
++		prot##cache_op(hitop, addr + lsize_4);			\
++		prot##cache_op(hitop, addr + lsize_5);			\
++		prot##cache_op(hitop, addr + lsize_6);			\
++		prot##cache_op(hitop, addr + lsize_7);			\
++		addr += lsize_8;					\
++		lines -= 8;						\
++	}								\
++									\
++	if (lines & 0x4) {						\
++		prot##cache_op(hitop, addr);				\
++		prot##cache_op(hitop, addr + lsize);			\
++		prot##cache_op(hitop, addr + lsize_2);			\
++		prot##cache_op(hitop, addr + lsize_3);			\
++		addr += lsize_4;					\
++	}								\
++									\
++	if (lines & 0x2) {						\
++		prot##cache_op(hitop, addr);				\
++		prot##cache_op(hitop, addr + lsize);			\
++		addr += lsize_2;					\
++	}								\
++									\
++	if (lines & 0x1) {						\
+ 		prot##cache_op(hitop, addr);				\
+-		if (addr == aend)					\
+-			break;						\
+-		addr += lsize;						\
+ 	}								\
+ }
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/301-mips_image_cmdline_hack.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/301-mips_image_cmdline_hack.patch
new file mode 100644
index 0000000..eab6349
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/301-mips_image_cmdline_hack.patch
@@ -0,0 +1,38 @@
+From: John Crispin <john@phrozen.org>
+Subject: hack: kernel: add generic image_cmdline hack to MIPS targets
+
+lede-commit: d59f5b3a987a48508257a0ddbaeadc7909f9f976
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ arch/mips/Kconfig       | 4 ++++
+ arch/mips/kernel/head.S | 6 ++++++
+ 2 files changed, 10 insertions(+)
+
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -1162,6 +1162,10 @@ config SYNC_R4K
+ config MIPS_MACHINE
+ 	def_bool n
+ 
++config IMAGE_CMDLINE_HACK
++	bool "OpenWrt specific image command line hack"
++	default n
++
+ config NO_IOPORT_MAP
+ 	def_bool n
+ 
+--- a/arch/mips/kernel/head.S
++++ b/arch/mips/kernel/head.S
+@@ -79,6 +79,12 @@ FEXPORT(__kernel_entry)
+ 	j	kernel_entry
+ #endif /* CONFIG_BOOT_RAW */
+ 
++#ifdef CONFIG_IMAGE_CMDLINE_HACK
++	.ascii	"CMDLINE:"
++EXPORT(__image_cmdline)
++	.fill	0x400
++#endif /* CONFIG_IMAGE_CMDLINE_HACK */
++
+ 	__REF
+ 
+ NESTED(kernel_entry, 16, sp)			# kernel entry point
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/321-powerpc_crtsavres_prereq.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/321-powerpc_crtsavres_prereq.patch
new file mode 100644
index 0000000..8591705
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/321-powerpc_crtsavres_prereq.patch
@@ -0,0 +1,39 @@
+From 107c0964cb8db7ca28ac5199426414fdab3c274d Mon Sep 17 00:00:00 2001
+From: "Alexandros C. Couloumbis" <alex@ozo.com>
+Date: Fri, 7 Jul 2017 17:14:51 +0200
+Subject: hack: arch: powerpc: drop register save/restore library from modules
+
+Upstream GCC uses a libgcc function for saving/restoring registers. This
+makes the code bigger, and upstream kernels need to carry that function
+for every single kernel module. Our GCC is patched to avoid those
+references, so we can drop the extra bloat for modules.
+
+lede-commit: e8e1084654f50904e6bf77b70b2de3f137d7b3ec
+Signed-off-by: Alexandros C. Couloumbis <alex@ozo.com>
+---
+ arch/powerpc/Makefile | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/arch/powerpc/Makefile
++++ b/arch/powerpc/Makefile
+@@ -61,20 +61,6 @@ machine-$(CONFIG_PPC64) += 64
+ machine-$(CONFIG_CPU_LITTLE_ENDIAN) += le
+ UTS_MACHINE := $(subst $(space),,$(machine-y))
+ 
+-# XXX This needs to be before we override LD below
+-ifdef CONFIG_PPC32
+-KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
+-else
+-KBUILD_LDS_MODULE += $(srctree)/arch/powerpc/kernel/module.lds
+-ifeq ($(call ld-ifversion, -ge, 225000000, y),y)
+-# Have the linker provide sfpr if possible.
+-# There is a corresponding test in arch/powerpc/lib/Makefile
+-KBUILD_LDFLAGS_MODULE += --save-restore-funcs
+-else
+-KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
+-endif
+-endif
+-
+ ifdef CONFIG_CPU_LITTLE_ENDIAN
+ KBUILD_CFLAGS	+= -mlittle-endian
+ KBUILD_LDFLAGS	+= -EL
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/400-unlock_mx25l6406e_with_4bit_block_protect.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/400-unlock_mx25l6406e_with_4bit_block_protect.patch
new file mode 100644
index 0000000..af0a149
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/400-unlock_mx25l6406e_with_4bit_block_protect.patch
@@ -0,0 +1,69 @@
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -196,7 +196,7 @@ struct flash_info {
+ 	u16		page_size;
+ 	u16		addr_width;
+ 
+-	u16		flags;
++	u32		flags;
+ #define SECT_4K			BIT(0)	/* SPINOR_OP_BE_4K works uniformly */
+ #define SPI_NOR_NO_ERASE	BIT(1)	/* No erase command needed */
+ #define SST_WRITE		BIT(2)	/* use SST byte programming */
+@@ -233,6 +233,10 @@ struct flash_info {
+ #define SPI_NOR_SKIP_SFDP	BIT(13)	/* Skip parsing of SFDP tables */
+ #define USE_CLSR		BIT(14)	/* use CLSR command */
+ #define SPI_NOR_OCTAL_READ	BIT(15)	/* Flash supports Octal Read */
++#define SPI_NOR_4BIT_BP		BIT(17) /*
++					 * Flash SR has 4 bit fields (BP0-3)
++					 * for block protection.
++					 */
+ 
+ 	/* Part specific fixup hooks. */
+ 	const struct spi_nor_fixups *fixups;
+@@ -1985,6 +1989,9 @@ static int spi_nor_clear_sr_bp(struct sp
+ 	int ret;
+ 	u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+ 
++	if (nor->flags & SNOR_F_HAS_4BIT_BP)
++		mask |= SR_BP3;
++
+ 	ret = read_sr(nor);
+ 	if (ret < 0) {
+ 		dev_err(nor->dev, "error while reading status register\n");
+@@ -2337,7 +2344,7 @@ static const struct flash_info spi_nor_i
+ 	{ "mx25l1606e",  INFO(0xc22015, 0, 64 * 1024,  32, SECT_4K) },
+ 	{ "mx25l3205d",  INFO(0xc22016, 0, 64 * 1024,  64, SECT_4K) },
+ 	{ "mx25l3255e",  INFO(0xc29e16, 0, 64 * 1024,  64, SECT_4K) },
+-	{ "mx25l6405d",  INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) },
++	{ "mx25l6405d",  INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_4BIT_BP) },
+ 	{ "mx25u2033e",  INFO(0xc22532, 0, 64 * 1024,   4, SECT_4K) },
+ 	{ "mx25u3235f",	 INFO(0xc22536, 0, 64 * 1024,  64,
+ 			 SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+@@ -5025,6 +5032,9 @@ int spi_nor_scan(struct spi_nor *nor, co
+ 	if (info->flags & USE_CLSR)
+ 		nor->flags |= SNOR_F_USE_CLSR;
+ 
++	if (info->flags & SPI_NOR_4BIT_BP)
++		nor->flags |= SNOR_F_HAS_4BIT_BP;
++
+ 	if (info->flags & SPI_NOR_NO_ERASE)
+ 		mtd->flags |= MTD_NO_ERASE;
+ 
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -127,6 +127,7 @@
+ #define SR_BP0			BIT(2)	/* Block protect 0 */
+ #define SR_BP1			BIT(3)	/* Block protect 1 */
+ #define SR_BP2			BIT(4)	/* Block protect 2 */
++#define SR_BP3			BIT(5)	/* Block protect 3 */
+ #define SR_TB			BIT(5)	/* Top/Bottom protect */
+ #define SR_SRWD			BIT(7)	/* SR write protect */
+ /* Spansion/Cypress specific status bits */
+@@ -243,6 +244,7 @@ enum spi_nor_option_flags {
+ 	SNOR_F_4B_OPCODES	= BIT(6),
+ 	SNOR_F_HAS_4BAIT	= BIT(7),
+ 	SNOR_F_HAS_LOCK		= BIT(8),
++	SNOR_F_HAS_4BIT_BP      = BIT(12),
+ };
+ 
+ /**
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/531-debloat_lzma.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/531-debloat_lzma.patch
new file mode 100644
index 0000000..2f70eee
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/531-debloat_lzma.patch
@@ -0,0 +1,1040 @@
+From 3fd297761ac246c54d7723c57fca95c112b99465 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 15 Jul 2017 21:15:44 +0200
+Subject: lzma: de-bloat the lzma library used by jffs2
+
+lede-commit: 3fd1dd08fbcbb78b34efefd32c3032e5c99108d6
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ include/linux/lzma/LzFind.h  |  17 ---
+ include/linux/lzma/LzmaDec.h | 101 ---------------
+ include/linux/lzma/LzmaEnc.h |  20 ---
+ lib/lzma/LzFind.c            | 287 ++++---------------------------------------
+ lib/lzma/LzmaDec.c           |  86 +------------
+ lib/lzma/LzmaEnc.c           | 172 ++------------------------
+ 6 files changed, 42 insertions(+), 641 deletions(-)
+
+--- a/include/linux/lzma/LzFind.h
++++ b/include/linux/lzma/LzFind.h
+@@ -55,11 +55,6 @@ typedef struct _CMatchFinder
+ 
+ #define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
+ 
+-int MatchFinder_NeedMove(CMatchFinder *p);
+-Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
+-void MatchFinder_MoveBlock(CMatchFinder *p);
+-void MatchFinder_ReadIfRequired(CMatchFinder *p);
+-
+ void MatchFinder_Construct(CMatchFinder *p);
+ 
+ /* Conditions:
+@@ -70,12 +65,6 @@ int MatchFinder_Create(CMatchFinder *p,
+     UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+     ISzAlloc *alloc);
+ void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
+-void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
+-void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
+-
+-UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
+-    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
+-    UInt32 *distances, UInt32 maxLen);
+ 
+ /*
+ Conditions:
+@@ -102,12 +91,6 @@ typedef struct _IMatchFinder
+ 
+ void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
+ 
+-void MatchFinder_Init(CMatchFinder *p);
+-UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+-UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+-void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+-void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+-
+ #ifdef __cplusplus
+ }
+ #endif
+--- a/include/linux/lzma/LzmaDec.h
++++ b/include/linux/lzma/LzmaDec.h
+@@ -31,14 +31,6 @@ typedef struct _CLzmaProps
+   UInt32 dicSize;
+ } CLzmaProps;
+ 
+-/* LzmaProps_Decode - decodes properties
+-Returns:
+-  SZ_OK
+-  SZ_ERROR_UNSUPPORTED - Unsupported properties
+-*/
+-
+-SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
+-
+ 
+ /* ---------- LZMA Decoder state ---------- */
+ 
+@@ -70,8 +62,6 @@ typedef struct
+ 
+ #define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
+ 
+-void LzmaDec_Init(CLzmaDec *p);
+-
+ /* There are two types of LZMA streams:
+      0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
+      1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
+@@ -108,97 +98,6 @@ typedef enum
+ 
+ /* ELzmaStatus is used only as output value for function call */
+ 
+-
+-/* ---------- Interfaces ---------- */
+-
+-/* There are 3 levels of interfaces:
+-     1) Dictionary Interface
+-     2) Buffer Interface
+-     3) One Call Interface
+-   You can select any of these interfaces, but don't mix functions from different
+-   groups for same object. */
+-
+-
+-/* There are two variants to allocate state for Dictionary Interface:
+-     1) LzmaDec_Allocate / LzmaDec_Free
+-     2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
+-   You can use variant 2, if you set dictionary buffer manually.
+-   For Buffer Interface you must always use variant 1.
+-
+-LzmaDec_Allocate* can return:
+-  SZ_OK
+-  SZ_ERROR_MEM         - Memory allocation error
+-  SZ_ERROR_UNSUPPORTED - Unsupported properties
+-*/
+-
+-SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
+-void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
+-
+-SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
+-void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
+-
+-/* ---------- Dictionary Interface ---------- */
+-
+-/* You can use it, if you want to eliminate the overhead for data copying from
+-   dictionary to some other external buffer.
+-   You must work with CLzmaDec variables directly in this interface.
+-
+-   STEPS:
+-     LzmaDec_Constr()
+-     LzmaDec_Allocate()
+-     for (each new stream)
+-     {
+-       LzmaDec_Init()
+-       while (it needs more decompression)
+-       {
+-         LzmaDec_DecodeToDic()
+-         use data from CLzmaDec::dic and update CLzmaDec::dicPos
+-       }
+-     }
+-     LzmaDec_Free()
+-*/
+-
+-/* LzmaDec_DecodeToDic
+-
+-   The decoding to internal dictionary buffer (CLzmaDec::dic).
+-   You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
+-
+-finishMode:
+-  It has meaning only if the decoding reaches output limit (dicLimit).
+-  LZMA_FINISH_ANY - Decode just dicLimit bytes.
+-  LZMA_FINISH_END - Stream must be finished after dicLimit.
+-
+-Returns:
+-  SZ_OK
+-    status:
+-      LZMA_STATUS_FINISHED_WITH_MARK
+-      LZMA_STATUS_NOT_FINISHED
+-      LZMA_STATUS_NEEDS_MORE_INPUT
+-      LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+-  SZ_ERROR_DATA - Data error
+-*/
+-
+-SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
+-    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+-
+-
+-/* ---------- Buffer Interface ---------- */
+-
+-/* It's zlib-like interface.
+-   See LzmaDec_DecodeToDic description for information about STEPS and return results,
+-   but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
+-   to work with CLzmaDec variables manually.
+-
+-finishMode:
+-  It has meaning only if the decoding reaches output limit (*destLen).
+-  LZMA_FINISH_ANY - Decode just destLen bytes.
+-  LZMA_FINISH_END - Stream must be finished after (*destLen).
+-*/
+-
+-SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
+-    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+-
+-
+ /* ---------- One Call Interface ---------- */
+ 
+ /* LzmaDecode
+--- a/include/linux/lzma/LzmaEnc.h
++++ b/include/linux/lzma/LzmaEnc.h
+@@ -31,9 +31,6 @@ typedef struct _CLzmaEncProps
+ } CLzmaEncProps;
+ 
+ void LzmaEncProps_Init(CLzmaEncProps *p);
+-void LzmaEncProps_Normalize(CLzmaEncProps *p);
+-UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
+-
+ 
+ /* ---------- CLzmaEncHandle Interface ---------- */
+ 
+@@ -53,26 +50,9 @@ CLzmaEncHandle LzmaEnc_Create(ISzAlloc *
+ void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig);
+ SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
+ SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
+-SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
+-    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+ SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+     int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+ 
+-/* ---------- One Call Interface ---------- */
+-
+-/* LzmaEncode
+-Return code:
+-  SZ_OK               - OK
+-  SZ_ERROR_MEM        - Memory allocation error
+-  SZ_ERROR_PARAM      - Incorrect paramater
+-  SZ_ERROR_OUTPUT_EOF - output buffer overflow
+-  SZ_ERROR_THREAD     - errors in multithreading functions (only for Mt version)
+-*/
+-
+-SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+-    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+-    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+-
+ #ifdef __cplusplus
+ }
+ #endif
+--- a/lib/lzma/LzFind.c
++++ b/lib/lzma/LzFind.c
+@@ -14,9 +14,15 @@
+ 
+ #define kStartMaxLen 3
+ 
++#if 0
++#define DIRECT_INPUT	p->directInput
++#else
++#define DIRECT_INPUT	1
++#endif
++
+ static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
+ {
+-  if (!p->directInput)
++  if (!DIRECT_INPUT)
+   {
+     alloc->Free(alloc, p->bufferBase);
+     p->bufferBase = 0;
+@@ -28,7 +34,7 @@ static void LzInWindow_Free(CMatchFinder
+ static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
+ {
+   UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
+-  if (p->directInput)
++  if (DIRECT_INPUT)
+   {
+     p->blockSize = blockSize;
+     return 1;
+@@ -42,12 +48,12 @@ static int LzInWindow_Create(CMatchFinde
+   return (p->bufferBase != 0);
+ }
+ 
+-Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
+-Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
++static Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
++static Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
+ 
+-UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
++static UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
+ 
+-void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
++static void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
+ {
+   p->posLimit -= subValue;
+   p->pos -= subValue;
+@@ -58,7 +64,7 @@ static void MatchFinder_ReadBlock(CMatch
+ {
+   if (p->streamEndWasReached || p->result != SZ_OK)
+     return;
+-  if (p->directInput)
++  if (DIRECT_INPUT)
+   {
+     UInt32 curSize = 0xFFFFFFFF - p->streamPos;
+     if (curSize > p->directInputRem)
+@@ -89,7 +95,7 @@ static void MatchFinder_ReadBlock(CMatch
+   }
+ }
+ 
+-void MatchFinder_MoveBlock(CMatchFinder *p)
++static void MatchFinder_MoveBlock(CMatchFinder *p)
+ {
+   memmove(p->bufferBase,
+     p->buffer - p->keepSizeBefore,
+@@ -97,22 +103,14 @@ void MatchFinder_MoveBlock(CMatchFinder
+   p->buffer = p->bufferBase + p->keepSizeBefore;
+ }
+ 
+-int MatchFinder_NeedMove(CMatchFinder *p)
++static int MatchFinder_NeedMove(CMatchFinder *p)
+ {
+-  if (p->directInput)
++  if (DIRECT_INPUT)
+     return 0;
+   /* if (p->streamEndWasReached) return 0; */
+   return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
+ }
+ 
+-void MatchFinder_ReadIfRequired(CMatchFinder *p)
+-{
+-  if (p->streamEndWasReached)
+-    return;
+-  if (p->keepSizeAfter >= p->streamPos - p->pos)
+-    MatchFinder_ReadBlock(p);
+-}
+-
+ static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
+ {
+   if (MatchFinder_NeedMove(p))
+@@ -268,7 +266,7 @@ static void MatchFinder_SetLimits(CMatch
+   p->posLimit = p->pos + limit;
+ }
+ 
+-void MatchFinder_Init(CMatchFinder *p)
++static void MatchFinder_Init(CMatchFinder *p)
+ {
+   UInt32 i;
+   for (i = 0; i < p->hashSizeSum; i++)
+@@ -287,7 +285,7 @@ static UInt32 MatchFinder_GetSubValue(CM
+   return (p->pos - p->historySize - 1) & kNormalizeMask;
+ }
+ 
+-void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
++static void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
+ {
+   UInt32 i;
+   for (i = 0; i < numItems; i++)
+@@ -319,38 +317,7 @@ static void MatchFinder_CheckLimits(CMat
+   MatchFinder_SetLimits(p);
+ }
+ 
+-static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+-    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+-    UInt32 *distances, UInt32 maxLen)
+-{
+-  son[_cyclicBufferPos] = curMatch;
+-  for (;;)
+-  {
+-    UInt32 delta = pos - curMatch;
+-    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+-      return distances;
+-    {
+-      const Byte *pb = cur - delta;
+-      curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
+-      if (pb[maxLen] == cur[maxLen] && *pb == *cur)
+-      {
+-        UInt32 len = 0;
+-        while (++len != lenLimit)
+-          if (pb[len] != cur[len])
+-            break;
+-        if (maxLen < len)
+-        {
+-          *distances++ = maxLen = len;
+-          *distances++ = delta - 1;
+-          if (len == lenLimit)
+-            return distances;
+-        }
+-      }
+-    }
+-  }
+-}
+-
+-UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
++static UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+     UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+     UInt32 *distances, UInt32 maxLen)
+ {
+@@ -460,10 +427,10 @@ static void SkipMatchesSpec(UInt32 lenLi
+   p->buffer++; \
+   if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
+ 
+-#define MOVE_POS_RET MOVE_POS return offset;
+-
+ static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
+ 
++#define MOVE_POS_RET MatchFinder_MovePos(p); return offset;
++
+ #define GET_MATCHES_HEADER2(minLen, ret_op) \
+   UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
+   lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
+@@ -479,62 +446,7 @@ static void MatchFinder_MovePos(CMatchFi
+   distances + offset, maxLen) - distances); MOVE_POS_RET;
+ 
+ #define SKIP_FOOTER \
+-  SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
+-
+-static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+-{
+-  UInt32 offset;
+-  GET_MATCHES_HEADER(2)
+-  HASH2_CALC;
+-  curMatch = p->hash[hashValue];
+-  p->hash[hashValue] = p->pos;
+-  offset = 0;
+-  GET_MATCHES_FOOTER(offset, 1)
+-}
+-
+-UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+-{
+-  UInt32 offset;
+-  GET_MATCHES_HEADER(3)
+-  HASH_ZIP_CALC;
+-  curMatch = p->hash[hashValue];
+-  p->hash[hashValue] = p->pos;
+-  offset = 0;
+-  GET_MATCHES_FOOTER(offset, 2)
+-}
+-
+-static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+-{
+-  UInt32 hash2Value, delta2, maxLen, offset;
+-  GET_MATCHES_HEADER(3)
+-
+-  HASH3_CALC;
+-
+-  delta2 = p->pos - p->hash[hash2Value];
+-  curMatch = p->hash[kFix3HashSize + hashValue];
+-
+-  p->hash[hash2Value] =
+-  p->hash[kFix3HashSize + hashValue] = p->pos;
+-
+-
+-  maxLen = 2;
+-  offset = 0;
+-  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+-  {
+-    for (; maxLen != lenLimit; maxLen++)
+-      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+-        break;
+-    distances[0] = maxLen;
+-    distances[1] = delta2 - 1;
+-    offset = 2;
+-    if (maxLen == lenLimit)
+-    {
+-      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+-      MOVE_POS_RET;
+-    }
+-  }
+-  GET_MATCHES_FOOTER(offset, maxLen)
+-}
++  SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MatchFinder_MovePos(p);
+ 
+ static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+ {
+@@ -583,108 +495,6 @@ static UInt32 Bt4_MatchFinder_GetMatches
+   GET_MATCHES_FOOTER(offset, maxLen)
+ }
+ 
+-static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+-{
+-  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+-  GET_MATCHES_HEADER(4)
+-
+-  HASH4_CALC;
+-
+-  delta2 = p->pos - p->hash[                hash2Value];
+-  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
+-  curMatch = p->hash[kFix4HashSize + hashValue];
+-
+-  p->hash[                hash2Value] =
+-  p->hash[kFix3HashSize + hash3Value] =
+-  p->hash[kFix4HashSize + hashValue] = p->pos;
+-
+-  maxLen = 1;
+-  offset = 0;
+-  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+-  {
+-    distances[0] = maxLen = 2;
+-    distances[1] = delta2 - 1;
+-    offset = 2;
+-  }
+-  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+-  {
+-    maxLen = 3;
+-    distances[offset + 1] = delta3 - 1;
+-    offset += 2;
+-    delta2 = delta3;
+-  }
+-  if (offset != 0)
+-  {
+-    for (; maxLen != lenLimit; maxLen++)
+-      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+-        break;
+-    distances[offset - 2] = maxLen;
+-    if (maxLen == lenLimit)
+-    {
+-      p->son[p->cyclicBufferPos] = curMatch;
+-      MOVE_POS_RET;
+-    }
+-  }
+-  if (maxLen < 3)
+-    maxLen = 3;
+-  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+-    distances + offset, maxLen) - (distances));
+-  MOVE_POS_RET
+-}
+-
+-UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+-{
+-  UInt32 offset;
+-  GET_MATCHES_HEADER(3)
+-  HASH_ZIP_CALC;
+-  curMatch = p->hash[hashValue];
+-  p->hash[hashValue] = p->pos;
+-  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+-    distances, 2) - (distances));
+-  MOVE_POS_RET
+-}
+-
+-static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+-{
+-  do
+-  {
+-    SKIP_HEADER(2)
+-    HASH2_CALC;
+-    curMatch = p->hash[hashValue];
+-    p->hash[hashValue] = p->pos;
+-    SKIP_FOOTER
+-  }
+-  while (--num != 0);
+-}
+-
+-void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+-{
+-  do
+-  {
+-    SKIP_HEADER(3)
+-    HASH_ZIP_CALC;
+-    curMatch = p->hash[hashValue];
+-    p->hash[hashValue] = p->pos;
+-    SKIP_FOOTER
+-  }
+-  while (--num != 0);
+-}
+-
+-static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+-{
+-  do
+-  {
+-    UInt32 hash2Value;
+-    SKIP_HEADER(3)
+-    HASH3_CALC;
+-    curMatch = p->hash[kFix3HashSize + hashValue];
+-    p->hash[hash2Value] =
+-    p->hash[kFix3HashSize + hashValue] = p->pos;
+-    SKIP_FOOTER
+-  }
+-  while (--num != 0);
+-}
+-
+ static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+ {
+   do
+@@ -701,61 +511,12 @@ static void Bt4_MatchFinder_Skip(CMatchF
+   while (--num != 0);
+ }
+ 
+-static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+-{
+-  do
+-  {
+-    UInt32 hash2Value, hash3Value;
+-    SKIP_HEADER(4)
+-    HASH4_CALC;
+-    curMatch = p->hash[kFix4HashSize + hashValue];
+-    p->hash[                hash2Value] =
+-    p->hash[kFix3HashSize + hash3Value] =
+-    p->hash[kFix4HashSize + hashValue] = p->pos;
+-    p->son[p->cyclicBufferPos] = curMatch;
+-    MOVE_POS
+-  }
+-  while (--num != 0);
+-}
+-
+-void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+-{
+-  do
+-  {
+-    SKIP_HEADER(3)
+-    HASH_ZIP_CALC;
+-    curMatch = p->hash[hashValue];
+-    p->hash[hashValue] = p->pos;
+-    p->son[p->cyclicBufferPos] = curMatch;
+-    MOVE_POS
+-  }
+-  while (--num != 0);
+-}
+-
+ void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
+ {
+   vTable->Init = (Mf_Init_Func)MatchFinder_Init;
+   vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
+   vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
+   vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
+-  if (!p->btMode)
+-  {
+-    vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
+-    vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
+-  }
+-  else if (p->numHashBytes == 2)
+-  {
+-    vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
+-    vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
+-  }
+-  else if (p->numHashBytes == 3)
+-  {
+-    vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
+-    vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
+-  }
+-  else
+-  {
+-    vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
+-    vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
+-  }
++  vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
++  vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
+ }
+--- a/lib/lzma/LzmaDec.c
++++ b/lib/lzma/LzmaDec.c
+@@ -682,7 +682,7 @@ static void LzmaDec_InitRc(CLzmaDec *p,
+   p->needFlush = 0;
+ }
+ 
+-void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
++static void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
+ {
+   p->needFlush = 1;
+   p->remainLen = 0;
+@@ -698,7 +698,7 @@ void LzmaDec_InitDicAndState(CLzmaDec *p
+     p->needInitState = 1;
+ }
+ 
+-void LzmaDec_Init(CLzmaDec *p)
++static void LzmaDec_Init(CLzmaDec *p)
+ {
+   p->dicPos = 0;
+   LzmaDec_InitDicAndState(p, True, True);
+@@ -716,7 +716,7 @@ static void LzmaDec_InitStateReal(CLzmaD
+   p->needInitState = 0;
+ }
+ 
+-SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
++static SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
+     ELzmaFinishMode finishMode, ELzmaStatus *status)
+ {
+   SizeT inSize = *srcLen;
+@@ -837,65 +837,13 @@ SRes LzmaDec_DecodeToDic(CLzmaDec *p, Si
+   return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA;
+ }
+ 
+-SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+-{
+-  SizeT outSize = *destLen;
+-  SizeT inSize = *srcLen;
+-  *srcLen = *destLen = 0;
+-  for (;;)
+-  {
+-    SizeT inSizeCur = inSize, outSizeCur, dicPos;
+-    ELzmaFinishMode curFinishMode;
+-    SRes res;
+-    if (p->dicPos == p->dicBufSize)
+-      p->dicPos = 0;
+-    dicPos = p->dicPos;
+-    if (outSize > p->dicBufSize - dicPos)
+-    {
+-      outSizeCur = p->dicBufSize;
+-      curFinishMode = LZMA_FINISH_ANY;
+-    }
+-    else
+-    {
+-      outSizeCur = dicPos + outSize;
+-      curFinishMode = finishMode;
+-    }
+-
+-    res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
+-    src += inSizeCur;
+-    inSize -= inSizeCur;
+-    *srcLen += inSizeCur;
+-    outSizeCur = p->dicPos - dicPos;
+-    memcpy(dest, p->dic + dicPos, outSizeCur);
+-    dest += outSizeCur;
+-    outSize -= outSizeCur;
+-    *destLen += outSizeCur;
+-    if (res != 0)
+-      return res;
+-    if (outSizeCur == 0 || outSize == 0)
+-      return SZ_OK;
+-  }
+-}
+-
+-void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
++static void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
+ {
+   alloc->Free(alloc, p->probs);
+   p->probs = 0;
+ }
+ 
+-static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc)
+-{
+-  alloc->Free(alloc, p->dic);
+-  p->dic = 0;
+-}
+-
+-void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)
+-{
+-  LzmaDec_FreeProbs(p, alloc);
+-  LzmaDec_FreeDict(p, alloc);
+-}
+-
+-SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
++static SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
+ {
+   UInt32 dicSize;
+   Byte d;
+@@ -935,7 +883,7 @@ static SRes LzmaDec_AllocateProbs2(CLzma
+   return SZ_OK;
+ }
+ 
+-SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
++static SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+ {
+   CLzmaProps propNew;
+   RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+@@ -943,28 +891,6 @@ SRes LzmaDec_AllocateProbs(CLzmaDec *p,
+   p->prop = propNew;
+   return SZ_OK;
+ }
+-
+-SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+-{
+-  CLzmaProps propNew;
+-  SizeT dicBufSize;
+-  RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+-  RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+-  dicBufSize = propNew.dicSize;
+-  if (p->dic == 0 || dicBufSize != p->dicBufSize)
+-  {
+-    LzmaDec_FreeDict(p, alloc);
+-    p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
+-    if (p->dic == 0)
+-    {
+-      LzmaDec_FreeProbs(p, alloc);
+-      return SZ_ERROR_MEM;
+-    }
+-  }
+-  p->dicBufSize = dicBufSize;
+-  p->prop = propNew;
+-  return SZ_OK;
+-}
+ 
+ SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+     const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+--- a/lib/lzma/LzmaEnc.c
++++ b/lib/lzma/LzmaEnc.c
+@@ -53,7 +53,7 @@ void LzmaEncProps_Init(CLzmaEncProps *p)
+   p->writeEndMark = 0;
+ }
+ 
+-void LzmaEncProps_Normalize(CLzmaEncProps *p)
++static void LzmaEncProps_Normalize(CLzmaEncProps *p)
+ {
+   int level = p->level;
+   if (level < 0) level = 5;
+@@ -76,7 +76,7 @@ void LzmaEncProps_Normalize(CLzmaEncProp
+       #endif
+ }
+ 
+-UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
++static UInt32 __maybe_unused LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
+ {
+   CLzmaEncProps props = *props2;
+   LzmaEncProps_Normalize(&props);
+@@ -93,7 +93,7 @@ UInt32 LzmaEncProps_GetDictSize(const CL
+ 
+ #define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); }
+ 
+-UInt32 GetPosSlot1(UInt32 pos)
++static UInt32 GetPosSlot1(UInt32 pos)
+ {
+   UInt32 res;
+   BSR2_RET(pos, res);
+@@ -107,7 +107,7 @@ UInt32 GetPosSlot1(UInt32 pos)
+ #define kNumLogBits (9 + (int)sizeof(size_t) / 2)
+ #define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7)
+ 
+-void LzmaEnc_FastPosInit(Byte *g_FastPos)
++static void LzmaEnc_FastPosInit(Byte *g_FastPos)
+ {
+   int c = 2, slotFast;
+   g_FastPos[0] = 0;
+@@ -339,58 +339,6 @@ typedef struct
+   CSaveState saveState;
+ } CLzmaEnc;
+ 
+-void LzmaEnc_SaveState(CLzmaEncHandle pp)
+-{
+-  CLzmaEnc *p = (CLzmaEnc *)pp;
+-  CSaveState *dest = &p->saveState;
+-  int i;
+-  dest->lenEnc = p->lenEnc;
+-  dest->repLenEnc = p->repLenEnc;
+-  dest->state = p->state;
+-
+-  for (i = 0; i < kNumStates; i++)
+-  {
+-    memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
+-    memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
+-  }
+-  for (i = 0; i < kNumLenToPosStates; i++)
+-    memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
+-  memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
+-  memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
+-  memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
+-  memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
+-  memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
+-  memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
+-  memcpy(dest->reps, p->reps, sizeof(p->reps));
+-  memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb));
+-}
+-
+-void LzmaEnc_RestoreState(CLzmaEncHandle pp)
+-{
+-  CLzmaEnc *dest = (CLzmaEnc *)pp;
+-  const CSaveState *p = &dest->saveState;
+-  int i;
+-  dest->lenEnc = p->lenEnc;
+-  dest->repLenEnc = p->repLenEnc;
+-  dest->state = p->state;
+-
+-  for (i = 0; i < kNumStates; i++)
+-  {
+-    memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
+-    memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
+-  }
+-  for (i = 0; i < kNumLenToPosStates; i++)
+-    memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
+-  memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
+-  memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
+-  memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
+-  memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
+-  memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
+-  memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
+-  memcpy(dest->reps, p->reps, sizeof(p->reps));
+-  memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb));
+-}
+-
+ SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
+ {
+   CLzmaEnc *p = (CLzmaEnc *)pp;
+@@ -600,7 +548,7 @@ static void LitEnc_EncodeMatched(CRangeE
+   while (symbol < 0x10000);
+ }
+ 
+-void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
++static void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
+ {
+   UInt32 i;
+   for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits))
+@@ -1676,7 +1624,7 @@ static void FillDistancesPrices(CLzmaEnc
+   p->matchPriceCount = 0;
+ }
+ 
+-void LzmaEnc_Construct(CLzmaEnc *p)
++static void LzmaEnc_Construct(CLzmaEnc *p)
+ {
+   RangeEnc_Construct(&p->rc);
+   MatchFinder_Construct(&p->matchFinderBase);
+@@ -1709,7 +1657,7 @@ CLzmaEncHandle LzmaEnc_Create(ISzAlloc *
+   return p;
+ }
+ 
+-void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
++static void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
+ {
+   alloc->Free(alloc, p->litProbs);
+   alloc->Free(alloc, p->saveState.litProbs);
+@@ -1717,7 +1665,7 @@ void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAl
+   p->saveState.litProbs = 0;
+ }
+ 
+-void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)
++static void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)
+ {
+   #ifndef _7ZIP_ST
+   MatchFinderMt_Destruct(&p->matchFinderMt, allocBig);
+@@ -1947,7 +1895,7 @@ static SRes LzmaEnc_Alloc(CLzmaEnc *p, U
+   return SZ_OK;
+ }
+ 
+-void LzmaEnc_Init(CLzmaEnc *p)
++static void LzmaEnc_Init(CLzmaEnc *p)
+ {
+   UInt32 i;
+   p->state = 0;
+@@ -2005,7 +1953,7 @@ void LzmaEnc_Init(CLzmaEnc *p)
+   p->lpMask = (1 << p->lp) - 1;
+ }
+ 
+-void LzmaEnc_InitPrices(CLzmaEnc *p)
++static void LzmaEnc_InitPrices(CLzmaEnc *p)
+ {
+   if (!p->fastMode)
+   {
+@@ -2037,26 +1985,6 @@ static SRes LzmaEnc_AllocAndInit(CLzmaEn
+   return SZ_OK;
+ }
+ 
+-static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream,
+-    ISzAlloc *alloc, ISzAlloc *allocBig)
+-{
+-  CLzmaEnc *p = (CLzmaEnc *)pp;
+-  p->matchFinderBase.stream = inStream;
+-  p->needInit = 1;
+-  p->rc.outStream = outStream;
+-  return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig);
+-}
+-
+-SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp,
+-    ISeqInStream *inStream, UInt32 keepWindowSize,
+-    ISzAlloc *alloc, ISzAlloc *allocBig)
+-{
+-  CLzmaEnc *p = (CLzmaEnc *)pp;
+-  p->matchFinderBase.stream = inStream;
+-  p->needInit = 1;
+-  return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
+-}
+-
+ static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen)
+ {
+   p->matchFinderBase.directInput = 1;
+@@ -2064,7 +1992,7 @@ static void LzmaEnc_SetInputBuf(CLzmaEnc
+   p->matchFinderBase.directInputRem = srcLen;
+ }
+ 
+-SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
++static SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
+     UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
+ {
+   CLzmaEnc *p = (CLzmaEnc *)pp;
+@@ -2074,7 +2002,7 @@ SRes LzmaEnc_MemPrepare(CLzmaEncHandle p
+   return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
+ }
+ 
+-void LzmaEnc_Finish(CLzmaEncHandle pp)
++static void LzmaEnc_Finish(CLzmaEncHandle pp)
+ {
+   #ifndef _7ZIP_ST
+   CLzmaEnc *p = (CLzmaEnc *)pp;
+@@ -2107,53 +2035,6 @@ static size_t MyWrite(void *pp, const vo
+   return size;
+ }
+ 
+-
+-UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)
+-{
+-  const CLzmaEnc *p = (CLzmaEnc *)pp;
+-  return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
+-}
+-
+-const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
+-{
+-  const CLzmaEnc *p = (CLzmaEnc *)pp;
+-  return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
+-}
+-
+-SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit,
+-    Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
+-{
+-  CLzmaEnc *p = (CLzmaEnc *)pp;
+-  UInt64 nowPos64;
+-  SRes res;
+-  CSeqOutStreamBuf outStream;
+-
+-  outStream.funcTable.Write = MyWrite;
+-  outStream.data = dest;
+-  outStream.rem = *destLen;
+-  outStream.overflow = False;
+-
+-  p->writeEndMark = False;
+-  p->finished = False;
+-  p->result = SZ_OK;
+-
+-  if (reInit)
+-    LzmaEnc_Init(p);
+-  LzmaEnc_InitPrices(p);
+-  nowPos64 = p->nowPos64;
+-  RangeEnc_Init(&p->rc);
+-  p->rc.outStream = &outStream.funcTable;
+-
+-  res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize);
+-
+-  *unpackSize = (UInt32)(p->nowPos64 - nowPos64);
+-  *destLen -= outStream.rem;
+-  if (outStream.overflow)
+-    return SZ_ERROR_OUTPUT_EOF;
+-
+-  return res;
+-}
+-
+ static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress)
+ {
+   SRes res = SZ_OK;
+@@ -2184,13 +2065,6 @@ static SRes LzmaEnc_Encode2(CLzmaEnc *p,
+   return res;
+ }
+ 
+-SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress,
+-    ISzAlloc *alloc, ISzAlloc *allocBig)
+-{
+-  RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig));
+-  return LzmaEnc_Encode2((CLzmaEnc *)pp, progress);
+-}
+-
+ SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size)
+ {
+   CLzmaEnc *p = (CLzmaEnc *)pp;
+@@ -2247,25 +2121,3 @@ SRes LzmaEnc_MemEncode(CLzmaEncHandle pp
+     return SZ_ERROR_OUTPUT_EOF;
+   return res;
+ }
+-
+-SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+-    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+-    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
+-{
+-  CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc);
+-  SRes res;
+-  if (p == 0)
+-    return SZ_ERROR_MEM;
+-
+-  res = LzmaEnc_SetProps(p, props);
+-  if (res == SZ_OK)
+-  {
+-    res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize);
+-    if (res == SZ_OK)
+-      res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen,
+-          writeEndMark, progress, alloc, allocBig);
+-  }
+-
+-  LzmaEnc_Destroy(p, alloc, allocBig);
+-  return res;
+-}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/550-loop-Report-EOPNOTSUPP-properly.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/550-loop-Report-EOPNOTSUPP-properly.patch
new file mode 100644
index 0000000..0e5447d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/550-loop-Report-EOPNOTSUPP-properly.patch
@@ -0,0 +1,41 @@
+From 2e864386e62e702a343be2507062ee08d5dfc810 Mon Sep 17 00:00:00 2001
+From: Evan Green <evgreen@chromium.org>
+Date: Thu, 14 Nov 2019 15:50:07 -0800
+Subject: loop: Report EOPNOTSUPP properly
+
+Properly plumb out EOPNOTSUPP from loop driver operations, which may
+get returned when for instance a discard operation is attempted but not
+supported by the underlying block device. Before this change, everything
+was reported in the log as an I/O error, which is scary and not
+helpful in debugging.
+
+Signed-off-by: Evan Green <evgreen@chromium.org>
+Reviewed-by: Gwendal Grignou <gwendal@chromium.org>
+Reviewed-by: Bart Van Assche <bvanassche@acm.org>
+---
+ drivers/block/loop.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/block/loop.c
++++ b/drivers/block/loop.c
+@@ -462,7 +462,7 @@ static void lo_complete_rq(struct reques
+ 	if (!cmd->use_aio || cmd->ret < 0 || cmd->ret == blk_rq_bytes(rq) ||
+ 	    req_op(rq) != REQ_OP_READ) {
+ 		if (cmd->ret < 0)
+-			ret = BLK_STS_IOERR;
++			ret = errno_to_blk_status(cmd->ret);
+ 		goto end_io;
+ 	}
+ 
+@@ -1973,7 +1973,10 @@ static void loop_handle_cmd(struct loop_
+  failed:
+ 	/* complete non-aio request */
+ 	if (!cmd->use_aio || ret) {
+-		cmd->ret = ret ? -EIO : 0;
++		if (ret == -EOPNOTSUPP)
++			cmd->ret = ret;
++		else
++			cmd->ret = ret ? -EIO : 0;
+ 		blk_mq_complete_request(rq);
+ 	}
+ }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/640-bridge-only-accept-EAP-locally.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/640-bridge-only-accept-EAP-locally.patch
new file mode 100644
index 0000000..a713aa3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/640-bridge-only-accept-EAP-locally.patch
@@ -0,0 +1,82 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 7 Jul 2017 17:18:54 +0200
+Subject: bridge: only accept EAP locally
+
+When bridging, do not forward EAP frames to other ports, only deliver
+them locally, regardless of the state.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+[add disable_eap_hack sysfs attribute]
+Signed-off-by: Etienne Champetier <champetier.etienne@gmail.com>
+---
+
+--- a/net/bridge/br_input.c
++++ b/net/bridge/br_input.c
+@@ -103,10 +103,14 @@ int br_handle_frame_finish(struct net *n
+ 		}
+ 	}
+ 
++	BR_INPUT_SKB_CB(skb)->brdev = br->dev;
++
++	if (skb->protocol == htons(ETH_P_PAE) && !br->disable_eap_hack)
++		return br_pass_frame_up(skb);
++
+ 	if (p->state == BR_STATE_LEARNING)
+ 		goto drop;
+ 
+-	BR_INPUT_SKB_CB(skb)->brdev = br->dev;
+ 	BR_INPUT_SKB_CB(skb)->src_port_isolated = !!(p->flags & BR_ISOLATED);
+ 
+ 	if (IS_ENABLED(CONFIG_INET) &&
+--- a/net/bridge/br_private.h
++++ b/net/bridge/br_private.h
+@@ -345,6 +345,8 @@ struct net_bridge {
+ 	u16				group_fwd_mask;
+ 	u16				group_fwd_mask_required;
+ 
++	bool				disable_eap_hack;
++
+ 	/* STP */
+ 	bridge_id			designated_root;
+ 	bridge_id			bridge_id;
+--- a/net/bridge/br_sysfs_br.c
++++ b/net/bridge/br_sysfs_br.c
+@@ -166,6 +166,30 @@ static ssize_t group_fwd_mask_store(stru
+ }
+ static DEVICE_ATTR_RW(group_fwd_mask);
+ 
++static ssize_t disable_eap_hack_show(struct device *d,
++				   struct device_attribute *attr,
++				   char *buf)
++{
++	struct net_bridge *br = to_bridge(d);
++	return sprintf(buf, "%u\n", br->disable_eap_hack);
++}
++
++static int set_disable_eap_hack(struct net_bridge *br, unsigned long val)
++{
++	br->disable_eap_hack = !!val;
++
++	return 0;
++}
++
++static ssize_t disable_eap_hack_store(struct device *d,
++				    struct device_attribute *attr,
++				    const char *buf,
++				    size_t len)
++{
++	return store_bridge_parm(d, buf, len, set_disable_eap_hack);
++}
++static DEVICE_ATTR_RW(disable_eap_hack);
++
+ static ssize_t priority_show(struct device *d, struct device_attribute *attr,
+ 			     char *buf)
+ {
+@@ -851,6 +875,7 @@ static struct attribute *bridge_attrs[]
+ 	&dev_attr_ageing_time.attr,
+ 	&dev_attr_stp_state.attr,
+ 	&dev_attr_group_fwd_mask.attr,
++	&dev_attr_disable_eap_hack.attr,
+ 	&dev_attr_priority.attr,
+ 	&dev_attr_bridge_id.attr,
+ 	&dev_attr_root_id.attr,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/645-netfilter-connmark-introduce-set-dscpmark.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/645-netfilter-connmark-introduce-set-dscpmark.patch
new file mode 100644
index 0000000..2d3fe01
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/645-netfilter-connmark-introduce-set-dscpmark.patch
@@ -0,0 +1,212 @@
+From eda40b8c8c82e0f2789d6bc8bf63846dce2e8f32 Mon Sep 17 00:00:00 2001
+From: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
+Date: Sat, 23 Mar 2019 09:29:49 +0000
+Subject: [PATCH] netfilter: connmark: introduce set-dscpmark
+
+set-dscpmark is a method of storing the DSCP of an ip packet into
+conntrack mark.  In combination with a suitable tc filter action
+(act_ctinfo) DSCP values are able to be stored in the mark on egress and
+restored on ingress across links that otherwise alter or bleach DSCP.
+
+This is useful for qdiscs such as CAKE which are able to shape according
+to policies based on DSCP.
+
+Ingress classification is traditionally a challenging task since
+iptables rules haven't yet run and tc filter/eBPF programs are pre-NAT
+lookups, hence are unable to see internal IPv4 addresses as used on the
+typical home masquerading gateway.
+
+x_tables CONNMARK set-dscpmark target solves the problem of storing the
+DSCP to the conntrack mark in a way suitable for the new act_ctinfo tc
+action to restore.
+
+The set-dscpmark option accepts 2 parameters, a 32bit 'dscpmask' and a
+32bit 'statemask'.  The dscp mask must be 6 contiguous bits and
+represents the area where the DSCP will be stored in the connmark.  The
+state mask is a minimum 1 bit length mask that must not overlap with the
+dscpmask.  It represents a flag which is set when the DSCP has been
+stored in the conntrack mark. This is useful to implement a 'one shot'
+iptables based classification where the 'complicated' iptables rules are
+only run once to classify the connection on initial (egress) packet and
+subsequent packets are all marked/restored with the same DSCP.  A state
+mask of zero disables the setting of a status bit/s.
+
+example syntax with a suitably modified iptables user space application:
+
+iptables -A QOS_MARK_eth0 -t mangle -j CONNMARK --set-dscpmark 0xfc000000/0x01000000
+
+Would store the DSCP in the top 6 bits of the 32bit mark field, and use
+the LSB of the top byte as the 'DSCP has been stored' marker.
+
+|----0xFC----conntrack mark----000000---|
+| Bits 31-26 | bit 25 | bit24 |~~~ Bit 0|
+| DSCP       | unused | flag  |unused   |
+|-----------------------0x01---000000---|
+      ^                   ^
+      |                   |
+      ---|             Conditional flag
+         |             set this when dscp
+|-ip diffserv-|        stored in mark
+| 6 bits      |
+|-------------|
+
+an identically configured tc action to restore looks like:
+
+tc filter show dev eth0 ingress
+filter parent ffff: protocol all pref 10 u32 chain 0
+filter parent ffff: protocol all pref 10 u32 chain 0 fh 800: ht divisor 1
+filter parent ffff: protocol all pref 10 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1: not_in_hw
+  match 00000000/00000000 at 0
+	action order 1: ctinfo zone 0 pipe
+	 index 2 ref 1 bind 1 dscp 0xfc000000/0x1000000
+
+	action order 2: mirred (Egress Redirect to device ifb4eth0) stolen
+	index 1 ref 1 bind 1
+
+|----0xFC----conntrack mark----000000---|
+| Bits 31-26 | bit 25 | bit24 |~~~ Bit 0|
+| DSCP       | unused | flag  |unused   |
+|-----------------------0x01---000000---|
+      |                   |
+      |                   |
+      ---|             Conditional flag
+         v             only restore if set
+|-ip diffserv-|
+| 6 bits      |
+|-------------|
+
+Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
+---
+ include/uapi/linux/netfilter/xt_connmark.h | 10 ++++
+ net/netfilter/xt_connmark.c                | 55 ++++++++++++++++++----
+ 2 files changed, 57 insertions(+), 8 deletions(-)
+
+--- a/include/uapi/linux/netfilter/xt_connmark.h
++++ b/include/uapi/linux/netfilter/xt_connmark.h
+@@ -20,6 +20,11 @@ enum {
+ };
+ 
+ enum {
++	XT_CONNMARK_VALUE =	(1 << 0),
++	XT_CONNMARK_DSCP = 	(1 << 1)
++};
++
++enum {
+ 	D_SHIFT_LEFT = 0,
+ 	D_SHIFT_RIGHT,
+ };
+@@ -34,6 +39,11 @@ struct xt_connmark_tginfo2 {
+ 	__u8 shift_dir, shift_bits, mode;
+ };
+ 
++struct xt_connmark_tginfo3 {
++	__u32 ctmark, ctmask, nfmask;
++	__u8 shift_dir, shift_bits, mode, func;
++};
++
+ struct xt_connmark_mtinfo1 {
+ 	__u32 mark, mask;
+ 	__u8 invert;
+--- a/net/netfilter/xt_connmark.c
++++ b/net/netfilter/xt_connmark.c
+@@ -24,12 +24,13 @@ MODULE_ALIAS("ipt_connmark");
+ MODULE_ALIAS("ip6t_connmark");
+ 
+ static unsigned int
+-connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info)
++connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo3 *info)
+ {
+ 	enum ip_conntrack_info ctinfo;
+ 	u_int32_t new_targetmark;
+ 	struct nf_conn *ct;
+ 	u_int32_t newmark;
++	u_int8_t dscp;
+ 
+ 	ct = nf_ct_get(skb, &ctinfo);
+ 	if (ct == NULL)
+@@ -37,12 +38,24 @@ connmark_tg_shift(struct sk_buff *skb, c
+ 
+ 	switch (info->mode) {
+ 	case XT_CONNMARK_SET:
+-		newmark = (ct->mark & ~info->ctmask) ^ info->ctmark;
+-		if (info->shift_dir == D_SHIFT_RIGHT)
+-			newmark >>= info->shift_bits;
+-		else
+-			newmark <<= info->shift_bits;
++		newmark = ct->mark;
++		if (info->func & XT_CONNMARK_VALUE) {
++			newmark = (newmark & ~info->ctmask) ^ info->ctmark;
++			if (info->shift_dir == D_SHIFT_RIGHT)
++				newmark >>= info->shift_bits;
++			else
++				newmark <<= info->shift_bits;
++		} else if (info->func & XT_CONNMARK_DSCP) {
++			if (skb->protocol == htons(ETH_P_IP))
++				dscp = ipv4_get_dsfield(ip_hdr(skb)) >> 2;
++			else if (skb->protocol == htons(ETH_P_IPV6))
++				dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> 2;
++			else	/* protocol doesn't have diffserv */
++				break;
+ 
++			newmark = (newmark & ~info->ctmark) |
++				  (info->ctmask | (dscp << info->shift_bits));
++		}
+ 		if (ct->mark != newmark) {
+ 			ct->mark = newmark;
+ 			nf_conntrack_event_cache(IPCT_MARK, ct);
+@@ -81,20 +94,36 @@ static unsigned int
+ connmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
+ {
+ 	const struct xt_connmark_tginfo1 *info = par->targinfo;
+-	const struct xt_connmark_tginfo2 info2 = {
++	const struct xt_connmark_tginfo3 info3 = {
+ 		.ctmark	= info->ctmark,
+ 		.ctmask	= info->ctmask,
+ 		.nfmask	= info->nfmask,
+ 		.mode	= info->mode,
++		.func	= XT_CONNMARK_VALUE
+ 	};
+ 
+-	return connmark_tg_shift(skb, &info2);
++	return connmark_tg_shift(skb, &info3);
+ }
+ 
+ static unsigned int
+ connmark_tg_v2(struct sk_buff *skb, const struct xt_action_param *par)
+ {
+ 	const struct xt_connmark_tginfo2 *info = par->targinfo;
++	const struct xt_connmark_tginfo3 info3 = {
++		.ctmark	= info->ctmark,
++		.ctmask	= info->ctmask,
++		.nfmask	= info->nfmask,
++		.mode	= info->mode,
++		.func	= XT_CONNMARK_VALUE
++	};
++
++	return connmark_tg_shift(skb, &info3);
++}
++
++static unsigned int
++connmark_tg_v3(struct sk_buff *skb, const struct xt_action_param *par)
++{
++	const struct xt_connmark_tginfo3 *info = par->targinfo;
+ 
+ 	return connmark_tg_shift(skb, info);
+ }
+@@ -165,6 +194,16 @@ static struct xt_target connmark_tg_reg[
+ 		.targetsize     = sizeof(struct xt_connmark_tginfo2),
+ 		.destroy        = connmark_tg_destroy,
+ 		.me             = THIS_MODULE,
++	},
++	{
++		.name           = "CONNMARK",
++		.revision       = 3,
++		.family         = NFPROTO_UNSPEC,
++		.checkentry     = connmark_tg_check,
++		.target         = connmark_tg_v3,
++		.targetsize     = sizeof(struct xt_connmark_tginfo3),
++		.destroy        = connmark_tg_destroy,
++		.me             = THIS_MODULE,
+ 	}
+ };
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/647-netfilter-flow-acct.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/647-netfilter-flow-acct.patch
new file mode 100644
index 0000000..f9480d5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/647-netfilter-flow-acct.patch
@@ -0,0 +1,70 @@
+--- a/include/net/netfilter/nf_flow_table.h
++++ b/include/net/netfilter/nf_flow_table.h
+@@ -160,6 +160,8 @@ struct nf_flow_table_hw {
+ int nf_flow_table_hw_register(const struct nf_flow_table_hw *offload);
+ void nf_flow_table_hw_unregister(const struct nf_flow_table_hw *offload);
+ 
++void nf_flow_table_acct(struct flow_offload *flow, struct sk_buff *skb, int dir);
++
+ extern struct work_struct nf_flow_offload_hw_work;
+ 
+ #define MODULE_ALIAS_NF_FLOWTABLE(family)	\
+--- a/net/netfilter/nf_flow_table_core.c
++++ b/net/netfilter/nf_flow_table_core.c
+@@ -13,6 +13,7 @@
+ #include <net/netfilter/nf_conntrack_core.h>
+ #include <net/netfilter/nf_conntrack_l4proto.h>
+ #include <net/netfilter/nf_conntrack_tuple.h>
++#include <net/netfilter/nf_conntrack_acct.h>
+ 
+ struct flow_offload_entry {
+ 	struct flow_offload	flow;
+@@ -164,6 +165,22 @@ void flow_offload_free(struct flow_offlo
+ }
+ EXPORT_SYMBOL_GPL(flow_offload_free);
+ 
++void nf_flow_table_acct(struct flow_offload *flow, struct sk_buff *skb, int dir)
++{
++	struct flow_offload_entry *entry;
++	struct nf_conn_acct *acct;
++
++	entry = container_of(flow, struct flow_offload_entry, flow);
++	acct = nf_conn_acct_find(entry->ct);
++	if (acct) {
++		struct nf_conn_counter *counter = acct->counter;
++
++		atomic64_inc(&counter[dir].packets);
++		atomic64_add(skb->len, &counter[dir].bytes);
++	}
++}
++EXPORT_SYMBOL_GPL(nf_flow_table_acct);
++
+ static u32 flow_offload_hash(const void *data, u32 len, u32 seed)
+ {
+ 	const struct flow_offload_tuple *tuple = data;
+--- a/net/netfilter/nf_flow_table_ip.c
++++ b/net/netfilter/nf_flow_table_ip.c
+@@ -12,6 +12,7 @@
+ #include <net/ip6_route.h>
+ #include <net/neighbour.h>
+ #include <net/netfilter/nf_flow_table.h>
++
+ /* For layer 4 checksum field offset. */
+ #include <linux/tcp.h>
+ #include <linux/udp.h>
+@@ -296,6 +297,7 @@ nf_flow_offload_ip_hook(void *priv, stru
+ 	skb->dev = outdev;
+ 	nexthop = rt_nexthop(rt, flow->tuplehash[!dir].tuple.src_v4.s_addr);
+ 	skb_dst_set_noref(skb, &rt->dst);
++	nf_flow_table_acct(flow, skb, dir);
+ 	neigh_xmit(NEIGH_ARP_TABLE, outdev, &nexthop, skb);
+ 
+ 	return NF_STOLEN;
+@@ -526,6 +528,7 @@ nf_flow_offload_ipv6_hook(void *priv, st
+ 	skb->dev = outdev;
+ 	nexthop = rt6_nexthop(rt, &flow->tuplehash[!dir].tuple.src_v6);
+ 	skb_dst_set_noref(skb, &rt->dst);
++	nf_flow_table_acct(flow, skb, dir);
+ 	neigh_xmit(NEIGH_ND_TABLE, outdev, nexthop, skb);
+ 
+ 	return NF_STOLEN;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/650-netfilter-add-xt_OFFLOAD-target.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/650-netfilter-add-xt_OFFLOAD-target.patch
new file mode 100644
index 0000000..d584cb5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/650-netfilter-add-xt_OFFLOAD-target.patch
@@ -0,0 +1,589 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Tue, 20 Feb 2018 15:56:02 +0100
+Subject: [PATCH] netfilter: add xt_OFFLOAD target
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ create mode 100644 net/netfilter/xt_OFFLOAD.c
+
+--- a/net/ipv4/netfilter/Kconfig
++++ b/net/ipv4/netfilter/Kconfig
+@@ -56,8 +56,6 @@ config NF_TABLES_ARP
+ 	help
+ 	  This option enables the ARP support for nf_tables.
+ 
+-endif # NF_TABLES
+-
+ config NF_FLOW_TABLE_IPV4
+ 	tristate "Netfilter flow table IPv4 module"
+ 	depends on NF_FLOW_TABLE
+@@ -66,6 +64,8 @@ config NF_FLOW_TABLE_IPV4
+ 
+ 	  To compile it as a module, choose M here.
+ 
++endif # NF_TABLES
++
+ config NF_DUP_IPV4
+ 	tristate "Netfilter IPv4 packet duplication to alternate destination"
+ 	depends on !NF_CONNTRACK || NF_CONNTRACK
+--- a/net/ipv6/netfilter/Kconfig
++++ b/net/ipv6/netfilter/Kconfig
+@@ -45,7 +45,6 @@ config NFT_FIB_IPV6
+ 	  multicast or blackhole.
+ 
+ endif # NF_TABLES_IPV6
+-endif # NF_TABLES
+ 
+ config NF_FLOW_TABLE_IPV6
+ 	tristate "Netfilter flow table IPv6 module"
+@@ -55,6 +54,8 @@ config NF_FLOW_TABLE_IPV6
+ 
+ 	  To compile it as a module, choose M here.
+ 
++endif # NF_TABLES
++
+ config NF_DUP_IPV6
+ 	tristate "Netfilter IPv6 packet duplication to alternate destination"
+ 	depends on !NF_CONNTRACK || NF_CONNTRACK
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -690,8 +690,6 @@ config NFT_FIB_NETDEV
+ 
+ endif # NF_TABLES_NETDEV
+ 
+-endif # NF_TABLES
+-
+ config NF_FLOW_TABLE_INET
+ 	tristate "Netfilter flow table mixed IPv4/IPv6 module"
+ 	depends on NF_FLOW_TABLE
+@@ -700,11 +698,12 @@ config NF_FLOW_TABLE_INET
+ 
+ 	  To compile it as a module, choose M here.
+ 
++endif # NF_TABLES
++
+ config NF_FLOW_TABLE
+ 	tristate "Netfilter flow table module"
+ 	depends on NETFILTER_INGRESS
+ 	depends on NF_CONNTRACK
+-	depends on NF_TABLES
+ 	help
+ 	  This option adds the flow table core infrastructure.
+ 
+@@ -993,6 +992,15 @@ config NETFILTER_XT_TARGET_NOTRACK
+ 	depends on NETFILTER_ADVANCED
+ 	select NETFILTER_XT_TARGET_CT
+ 
++config NETFILTER_XT_TARGET_FLOWOFFLOAD
++	tristate '"FLOWOFFLOAD" target support'
++	depends on NF_FLOW_TABLE
++	depends on NETFILTER_INGRESS
++	help
++	  This option adds a `FLOWOFFLOAD' target, which uses the nf_flow_offload
++	  module to speed up processing of packets by bypassing the usual
++	  netfilter chains
++
+ config NETFILTER_XT_TARGET_RATEEST
+ 	tristate '"RATEEST" target support'
+ 	depends on NETFILTER_ADVANCED
+--- a/net/netfilter/Makefile
++++ b/net/netfilter/Makefile
+@@ -141,6 +141,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIF
+ obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
+ obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o
+ obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o
++obj-$(CONFIG_NETFILTER_XT_TARGET_FLOWOFFLOAD) += xt_FLOWOFFLOAD.o
+ obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o
+ obj-$(CONFIG_NETFILTER_XT_TARGET_HMARK) += xt_HMARK.o
+ obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
+--- /dev/null
++++ b/net/netfilter/xt_FLOWOFFLOAD.c
+@@ -0,0 +1,427 @@
++/*
++ * Copyright (C) 2018 Felix Fietkau <nbd@nbd.name>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/netfilter.h>
++#include <linux/netfilter/xt_FLOWOFFLOAD.h>
++#include <net/ip.h>
++#include <net/netfilter/nf_conntrack.h>
++#include <net/netfilter/nf_conntrack_extend.h>
++#include <net/netfilter/nf_conntrack_helper.h>
++#include <net/netfilter/nf_flow_table.h>
++
++static struct nf_flowtable nf_flowtable;
++static HLIST_HEAD(hooks);
++static DEFINE_SPINLOCK(hooks_lock);
++static struct delayed_work hook_work;
++
++struct xt_flowoffload_hook {
++	struct hlist_node list;
++	struct nf_hook_ops ops;
++	struct net *net;
++	bool registered;
++	bool used;
++};
++
++static unsigned int
++xt_flowoffload_net_hook(void *priv, struct sk_buff *skb,
++			  const struct nf_hook_state *state)
++{
++	switch (skb->protocol) {
++	case htons(ETH_P_IP):
++		return nf_flow_offload_ip_hook(priv, skb, state);
++	case htons(ETH_P_IPV6):
++		return nf_flow_offload_ipv6_hook(priv, skb, state);
++	}
++
++	return NF_ACCEPT;
++}
++
++int nf_flow_table_iterate(struct nf_flowtable *flow_table,
++			   void (*iter)(struct flow_offload *flow, void *data),
++			   void *data);
++
++static int
++xt_flowoffload_create_hook(struct net_device *dev)
++{
++	struct xt_flowoffload_hook *hook;
++	struct nf_hook_ops *ops;
++
++	hook = kzalloc(sizeof(*hook), GFP_ATOMIC);
++	if (!hook)
++		return -ENOMEM;
++
++	ops = &hook->ops;
++	ops->pf = NFPROTO_NETDEV;
++	ops->hooknum = NF_NETDEV_INGRESS;
++	ops->priority = 10;
++	ops->priv = &nf_flowtable;
++	ops->hook = xt_flowoffload_net_hook;
++	ops->dev = dev;
++
++	hlist_add_head(&hook->list, &hooks);
++	mod_delayed_work(system_power_efficient_wq, &hook_work, 0);
++
++	return 0;
++}
++
++static struct xt_flowoffload_hook *
++flow_offload_lookup_hook(struct net_device *dev)
++{
++	struct xt_flowoffload_hook *hook;
++
++	hlist_for_each_entry(hook, &hooks, list) {
++		if (hook->ops.dev == dev)
++			return hook;
++	}
++
++	return NULL;
++}
++
++static void
++xt_flowoffload_check_device(struct net_device *dev)
++{
++	struct xt_flowoffload_hook *hook;
++
++	spin_lock_bh(&hooks_lock);
++	hook = flow_offload_lookup_hook(dev);
++	if (hook)
++		hook->used = true;
++	else
++		xt_flowoffload_create_hook(dev);
++	spin_unlock_bh(&hooks_lock);
++}
++
++static void
++xt_flowoffload_register_hooks(void)
++{
++	struct xt_flowoffload_hook *hook;
++
++restart:
++	hlist_for_each_entry(hook, &hooks, list) {
++		if (hook->registered)
++			continue;
++
++		hook->registered = true;
++		hook->net = dev_net(hook->ops.dev);
++		spin_unlock_bh(&hooks_lock);
++		nf_register_net_hook(hook->net, &hook->ops);
++		spin_lock_bh(&hooks_lock);
++		goto restart;
++	}
++
++}
++
++static void
++xt_flowoffload_cleanup_hooks(void)
++{
++	struct xt_flowoffload_hook *hook;
++
++restart:
++	hlist_for_each_entry(hook, &hooks, list) {
++		if (hook->used || !hook->registered)
++			continue;
++
++		hlist_del(&hook->list);
++		spin_unlock_bh(&hooks_lock);
++		nf_unregister_net_hook(hook->net, &hook->ops);
++		kfree(hook);
++		spin_lock_bh(&hooks_lock);
++		goto restart;
++	}
++
++}
++
++static void
++xt_flowoffload_check_hook(struct flow_offload *flow, void *data)
++{
++	struct flow_offload_tuple *tuple = &flow->tuplehash[0].tuple;
++	struct xt_flowoffload_hook *hook;
++	bool *found = data;
++	struct rtable *rt = (struct rtable *)tuple->dst_cache;
++
++	spin_lock_bh(&hooks_lock);
++	hlist_for_each_entry(hook, &hooks, list) {
++		if (hook->ops.dev->ifindex != tuple->iifidx &&
++		    hook->ops.dev->ifindex != rt->dst.dev->ifindex)
++			continue;
++
++		hook->used = true;
++		*found = true;
++	}
++	spin_unlock_bh(&hooks_lock);
++}
++
++static void
++xt_flowoffload_hook_work(struct work_struct *work)
++{
++	struct xt_flowoffload_hook *hook;
++	bool found = false;
++	int err;
++
++	spin_lock_bh(&hooks_lock);
++	xt_flowoffload_register_hooks();
++	hlist_for_each_entry(hook, &hooks, list)
++		hook->used = false;
++	spin_unlock_bh(&hooks_lock);
++
++	err = nf_flow_table_iterate(&nf_flowtable, xt_flowoffload_check_hook,
++				    &found);
++	if (err && err != -EAGAIN)
++	    goto out;
++
++	spin_lock_bh(&hooks_lock);
++	xt_flowoffload_cleanup_hooks();
++	spin_unlock_bh(&hooks_lock);
++
++out:
++	if (found)
++		queue_delayed_work(system_power_efficient_wq, &hook_work, HZ);
++}
++
++static bool
++xt_flowoffload_skip(struct sk_buff *skb, int family)
++{
++	if (skb_sec_path(skb))
++		return true;
++
++	if (family == NFPROTO_IPV4) {
++		const struct ip_options *opt = &(IPCB(skb)->opt);
++
++		if (unlikely(opt->optlen))
++			return true;
++	}
++
++	return false;
++}
++
++static struct dst_entry *
++xt_flowoffload_dst(const struct nf_conn *ct, enum ip_conntrack_dir dir,
++		   const struct xt_action_param *par, int ifindex)
++{
++	struct dst_entry *dst = NULL;
++	struct flowi fl;
++
++	memset(&fl, 0, sizeof(fl));
++	switch (xt_family(par)) {
++	case NFPROTO_IPV4:
++		fl.u.ip4.daddr = ct->tuplehash[dir].tuple.src.u3.ip;
++		fl.u.ip4.flowi4_oif = ifindex;
++		break;
++	case NFPROTO_IPV6:
++		fl.u.ip6.saddr = ct->tuplehash[dir].tuple.dst.u3.in6;
++		fl.u.ip6.daddr = ct->tuplehash[dir].tuple.src.u3.in6;
++		fl.u.ip6.flowi6_oif = ifindex;
++		break;
++	}
++
++	nf_route(xt_net(par), &dst, &fl, false, xt_family(par));
++
++	return dst;
++}
++
++static int
++xt_flowoffload_route(struct sk_buff *skb, const struct nf_conn *ct,
++		   const struct xt_action_param *par,
++		   struct nf_flow_route *route, enum ip_conntrack_dir dir)
++{
++	struct dst_entry *this_dst, *other_dst;
++
++	this_dst = xt_flowoffload_dst(ct, !dir, par, xt_out(par)->ifindex);
++	other_dst = xt_flowoffload_dst(ct, dir, par, xt_in(par)->ifindex);
++
++	route->tuple[dir].dst		= this_dst;
++	route->tuple[!dir].dst		= other_dst;
++
++	if (!this_dst || !other_dst)
++		return -ENOENT;
++
++	if (dst_xfrm(this_dst) || dst_xfrm(other_dst))
++		return -EINVAL;
++
++	return 0;
++}
++
++static unsigned int
++flowoffload_tg(struct sk_buff *skb, const struct xt_action_param *par)
++{
++	const struct xt_flowoffload_target_info *info = par->targinfo;
++	struct tcphdr _tcph, *tcph = NULL;
++	enum ip_conntrack_info ctinfo;
++	enum ip_conntrack_dir dir;
++	struct nf_flow_route route;
++	struct flow_offload *flow = NULL;
++	struct nf_conn *ct;
++	struct net *net;
++
++	if (xt_flowoffload_skip(skb, xt_family(par)))
++		return XT_CONTINUE;
++
++	ct = nf_ct_get(skb, &ctinfo);
++	if (ct == NULL)
++		return XT_CONTINUE;
++
++	switch (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum) {
++	case IPPROTO_TCP:
++		if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED)
++			return XT_CONTINUE;
++
++		tcph = skb_header_pointer(skb, par->thoff,
++					  sizeof(_tcph), &_tcph);
++		if (unlikely(!tcph || tcph->fin || tcph->rst))
++			return XT_CONTINUE;
++		break;
++	case IPPROTO_UDP:
++		break;
++	default:
++		return XT_CONTINUE;
++	}
++
++	if (nf_ct_ext_exist(ct, NF_CT_EXT_HELPER) ||
++	    ct->status & IPS_SEQ_ADJUST)
++		return XT_CONTINUE;
++
++	if (!nf_ct_is_confirmed(ct))
++		return XT_CONTINUE;
++
++	if (!xt_in(par) || !xt_out(par))
++		return XT_CONTINUE;
++
++	if (test_and_set_bit(IPS_OFFLOAD_BIT, &ct->status))
++		return XT_CONTINUE;
++
++	dir = CTINFO2DIR(ctinfo);
++
++	if (xt_flowoffload_route(skb, ct, par, &route, dir) == 0)
++		flow = flow_offload_alloc(ct, &route);
++
++	dst_release(route.tuple[dir].dst);
++	dst_release(route.tuple[!dir].dst);
++
++	if (!flow)
++		goto err_flow_route;
++
++	if (tcph) {
++		ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
++		ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
++	}
++
++	if (flow_offload_add(&nf_flowtable, flow) < 0)
++		goto err_flow_add;
++
++	xt_flowoffload_check_device(xt_in(par));
++	xt_flowoffload_check_device(xt_out(par));
++
++	net = read_pnet(&nf_flowtable.ft_net);
++	if (!net)
++		write_pnet(&nf_flowtable.ft_net, xt_net(par));
++
++	if (info->flags & XT_FLOWOFFLOAD_HW)
++		nf_flow_offload_hw_add(xt_net(par), flow, ct);
++
++	return XT_CONTINUE;
++
++err_flow_add:
++	flow_offload_free(flow);
++err_flow_route:
++	clear_bit(IPS_OFFLOAD_BIT, &ct->status);
++	return XT_CONTINUE;
++}
++
++
++static int flowoffload_chk(const struct xt_tgchk_param *par)
++{
++	struct xt_flowoffload_target_info *info = par->targinfo;
++
++	if (info->flags & ~XT_FLOWOFFLOAD_MASK)
++		return -EINVAL;
++
++	return 0;
++}
++
++static struct xt_target offload_tg_reg __read_mostly = {
++	.family		= NFPROTO_UNSPEC,
++	.name		= "FLOWOFFLOAD",
++	.revision	= 0,
++	.targetsize	= sizeof(struct xt_flowoffload_target_info),
++	.usersize	= sizeof(struct xt_flowoffload_target_info),
++	.checkentry	= flowoffload_chk,
++	.target		= flowoffload_tg,
++	.me		= THIS_MODULE,
++};
++
++static int xt_flowoffload_table_init(struct nf_flowtable *table)
++{
++	table->flags = NF_FLOWTABLE_F_HW;
++	nf_flow_table_init(table);
++	return 0;
++}
++
++static void xt_flowoffload_table_cleanup(struct nf_flowtable *table)
++{
++	nf_flow_table_free(table);
++}
++
++static int flow_offload_netdev_event(struct notifier_block *this,
++				     unsigned long event, void *ptr)
++{
++	struct xt_flowoffload_hook *hook = NULL;
++	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
++
++	if (event != NETDEV_UNREGISTER)
++		return NOTIFY_DONE;
++
++	spin_lock_bh(&hooks_lock);
++	hook = flow_offload_lookup_hook(dev);
++	if (hook) {
++		hlist_del(&hook->list);
++	}
++	spin_unlock_bh(&hooks_lock);
++	if (hook) {
++		nf_unregister_net_hook(hook->net, &hook->ops);
++		kfree(hook);
++	}
++
++	nf_flow_table_cleanup(dev);
++
++	return NOTIFY_DONE;
++}
++
++static struct notifier_block flow_offload_netdev_notifier = {
++	.notifier_call	= flow_offload_netdev_event,
++};
++
++static int __init xt_flowoffload_tg_init(void)
++{
++	int ret;
++
++	register_netdevice_notifier(&flow_offload_netdev_notifier);
++
++	INIT_DELAYED_WORK(&hook_work, xt_flowoffload_hook_work);
++
++	ret = xt_flowoffload_table_init(&nf_flowtable);
++	if (ret)
++		return ret;
++
++	ret = xt_register_target(&offload_tg_reg);
++	if (ret)
++		xt_flowoffload_table_cleanup(&nf_flowtable);
++
++	return ret;
++}
++
++static void __exit xt_flowoffload_tg_exit(void)
++{
++	xt_unregister_target(&offload_tg_reg);
++	xt_flowoffload_table_cleanup(&nf_flowtable);
++	unregister_netdevice_notifier(&flow_offload_netdev_notifier);
++}
++
++MODULE_LICENSE("GPL");
++module_init(xt_flowoffload_tg_init);
++module_exit(xt_flowoffload_tg_exit);
+--- a/net/netfilter/nf_flow_table_core.c
++++ b/net/netfilter/nf_flow_table_core.c
+@@ -7,7 +7,6 @@
+ #include <linux/netdevice.h>
+ #include <net/ip.h>
+ #include <net/ip6_route.h>
+-#include <net/netfilter/nf_tables.h>
+ #include <net/netfilter/nf_flow_table.h>
+ #include <net/netfilter/nf_conntrack.h>
+ #include <net/netfilter/nf_conntrack_core.h>
+@@ -338,8 +337,7 @@ flow_offload_lookup(struct nf_flowtable
+ }
+ EXPORT_SYMBOL_GPL(flow_offload_lookup);
+ 
+-static int
+-nf_flow_table_iterate(struct nf_flowtable *flow_table,
++int nf_flow_table_iterate(struct nf_flowtable *flow_table,
+ 		      void (*iter)(struct flow_offload *flow, void *data),
+ 		      void *data)
+ {
+@@ -372,6 +370,7 @@ nf_flow_table_iterate(struct nf_flowtabl
+ 
+ 	return err;
+ }
++EXPORT_SYMBOL_GPL(nf_flow_table_iterate);
+ 
+ static void nf_flow_offload_gc_step(struct flow_offload *flow, void *data)
+ {
+--- /dev/null
++++ b/include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h
+@@ -0,0 +1,17 @@
++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
++#ifndef _XT_FLOWOFFLOAD_H
++#define _XT_FLOWOFFLOAD_H
++
++#include <linux/types.h>
++
++enum {
++	XT_FLOWOFFLOAD_HW	= 1 << 0,
++
++	XT_FLOWOFFLOAD_MASK	= XT_FLOWOFFLOAD_HW
++};
++
++struct xt_flowoffload_target_info {
++	__u32 flags;
++};
++
++#endif /* _XT_FLOWOFFLOAD_H */
+--- a/include/net/netfilter/nf_flow_table.h
++++ b/include/net/netfilter/nf_flow_table.h
+@@ -130,6 +130,10 @@ static inline void flow_offload_dead(str
+ 	flow->flags |= FLOW_OFFLOAD_DYING;
+ }
+ 
++int nf_flow_table_iterate(struct nf_flowtable *flow_table,
++                      void (*iter)(struct flow_offload *flow, void *data),
++                      void *data);
++
+ int nf_flow_snat_port(const struct flow_offload *flow,
+ 		      struct sk_buff *skb, unsigned int thoff,
+ 		      u8 protocol, enum flow_offload_tuple_dir dir);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/651-wireless_mesh_header.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/651-wireless_mesh_header.patch
new file mode 100644
index 0000000..f545d8e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/651-wireless_mesh_header.patch
@@ -0,0 +1,24 @@
+From 6d3bc769657b0ee7c7506dad9911111c4226a7ea Mon Sep 17 00:00:00 2001
+From: Imre Kaloz <kaloz@openwrt.org>
+Date: Fri, 7 Jul 2017 17:21:05 +0200
+Subject: mac80211: increase wireless mesh header size
+
+lede-commit 3d4466cfd8f75f717efdb1f96fdde3c70d865fc1
+Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
+---
+ include/linux/netdevice.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -138,8 +138,8 @@ static inline bool dev_xmit_complete(int
+ 
+ #if defined(CONFIG_HYPERV_NET)
+ # define LL_MAX_HEADER 128
+-#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25)
+-# if defined(CONFIG_MAC80211_MESH)
++#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25) || 1
++# if defined(CONFIG_MAC80211_MESH) || 1
+ #  define LL_MAX_HEADER 128
+ # else
+ #  define LL_MAX_HEADER 96
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/660-fq_codel_defaults.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/660-fq_codel_defaults.patch
new file mode 100644
index 0000000..46bf0e3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/660-fq_codel_defaults.patch
@@ -0,0 +1,27 @@
+From a6ccb238939b25851474a279b20367fd24a0e816 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 7 Jul 2017 17:21:53 +0200
+Subject:  hack: net: fq_codel: tune defaults for small devices
+
+Assume that x86_64 devices always have a big memory and do not need this 
+optimization compared to devices with only 32 MB or 64 MB RAM.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ net/sched/sch_fq_codel.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/net/sched/sch_fq_codel.c
++++ b/net/sched/sch_fq_codel.c
+@@ -470,7 +470,11 @@ static int fq_codel_init(struct Qdisc *s
+ 
+ 	sch->limit = 10*1024;
+ 	q->flows_cnt = 1024;
++#ifdef CONFIG_X86_64
+ 	q->memory_limit = 32 << 20; /* 32 MBytes */
++#else
++	q->memory_limit = 4 << 20; /* 4 MBytes */
++#endif
+ 	q->drop_batch_size = 64;
+ 	q->quantum = psched_mtu(qdisc_dev(sch));
+ 	INIT_LIST_HEAD(&q->new_flows);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/661-use_fq_codel_by_default.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/661-use_fq_codel_by_default.patch
new file mode 100644
index 0000000..11f1a25
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/661-use_fq_codel_by_default.patch
@@ -0,0 +1,100 @@
+From 1d418f7e88035ed7a94073f6354246c66e9193e9 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 7 Jul 2017 17:22:58 +0200
+Subject: fq_codel: switch default qdisc from pfifo_fast to fq_codel and remove pfifo_fast
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ include/net/sch_generic.h | 3 ++-
+ net/sched/Kconfig         | 3 ++-
+ net/sched/sch_api.c       | 2 +-
+ net/sched/sch_fq_codel.c  | 3 ++-
+ net/sched/sch_generic.c   | 4 ++--
+ 5 files changed, 9 insertions(+), 6 deletions(-)
+
+--- a/include/net/sch_generic.h
++++ b/include/net/sch_generic.h
+@@ -617,12 +617,13 @@ extern struct Qdisc_ops noop_qdisc_ops;
+ extern struct Qdisc_ops pfifo_fast_ops;
+ extern struct Qdisc_ops mq_qdisc_ops;
+ extern struct Qdisc_ops noqueue_qdisc_ops;
++extern struct Qdisc_ops fq_codel_qdisc_ops;
+ extern const struct Qdisc_ops *default_qdisc_ops;
+ static inline const struct Qdisc_ops *
+ get_default_qdisc_ops(const struct net_device *dev, int ntx)
+ {
+ 	return ntx < dev->real_num_tx_queues ?
+-			default_qdisc_ops : &pfifo_fast_ops;
++			default_qdisc_ops : &fq_codel_qdisc_ops;
+ }
+ 
+ struct Qdisc_class_common {
+--- a/net/sched/Kconfig
++++ b/net/sched/Kconfig
+@@ -4,8 +4,9 @@
+ #
+ 
+ menuconfig NET_SCHED
+-	bool "QoS and/or fair queueing"
++	def_bool y
+ 	select NET_SCH_FIFO
++	select NET_SCH_FQ_CODEL
+ 	---help---
+ 	  When the kernel has several packets to send out over a network
+ 	  device, it has to decide which ones to send first, which ones to
+--- a/net/sched/sch_api.c
++++ b/net/sched/sch_api.c
+@@ -2278,7 +2278,7 @@ static int __init pktsched_init(void)
+ 		return err;
+ 	}
+ 
+-	register_qdisc(&pfifo_fast_ops);
++	register_qdisc(&fq_codel_qdisc_ops);
+ 	register_qdisc(&pfifo_qdisc_ops);
+ 	register_qdisc(&bfifo_qdisc_ops);
+ 	register_qdisc(&pfifo_head_drop_qdisc_ops);
+--- a/net/sched/sch_fq_codel.c
++++ b/net/sched/sch_fq_codel.c
+@@ -710,7 +710,7 @@ static const struct Qdisc_class_ops fq_c
+ 	.walk		=	fq_codel_walk,
+ };
+ 
+-static struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = {
++struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = {
+ 	.cl_ops		=	&fq_codel_class_ops,
+ 	.id		=	"fq_codel",
+ 	.priv_size	=	sizeof(struct fq_codel_sched_data),
+@@ -725,6 +725,7 @@ static struct Qdisc_ops fq_codel_qdisc_o
+ 	.dump_stats =	fq_codel_dump_stats,
+ 	.owner		=	THIS_MODULE,
+ };
++EXPORT_SYMBOL(fq_codel_qdisc_ops);
+ 
+ static int __init fq_codel_module_init(void)
+ {
+--- a/net/sched/sch_generic.c
++++ b/net/sched/sch_generic.c
+@@ -32,7 +32,7 @@
+ #include <net/xfrm.h>
+ 
+ /* Qdisc to use by default */
+-const struct Qdisc_ops *default_qdisc_ops = &pfifo_fast_ops;
++const struct Qdisc_ops *default_qdisc_ops = &fq_codel_qdisc_ops;
+ EXPORT_SYMBOL(default_qdisc_ops);
+ 
+ static void qdisc_maybe_clear_missed(struct Qdisc *q,
+@@ -1079,12 +1079,12 @@ static void attach_one_default_qdisc(str
+ 				     void *_unused)
+ {
+ 	struct Qdisc *qdisc;
+-	const struct Qdisc_ops *ops = default_qdisc_ops;
++	const struct Qdisc_ops *ops = &fq_codel_qdisc_ops;
+ 
+ 	if (dev->priv_flags & IFF_NO_QUEUE)
+ 		ops = &noqueue_qdisc_ops;
+ 	else if(dev->type == ARPHRD_CAN)
+-		ops = &pfifo_fast_ops;
++		ops = &fq_codel_qdisc_ops;
+ 
+ 	qdisc = qdisc_create_dflt(dev_queue, ops, TC_H_ROOT, NULL);
+ 	if (!qdisc) {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/662-remove_pfifo_fast.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/662-remove_pfifo_fast.patch
new file mode 100644
index 0000000..9df3a82
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/662-remove_pfifo_fast.patch
@@ -0,0 +1,243 @@
+From b531d492d5ef1cf9dba0f4888eb5fd8624a6d762 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 7 Jul 2017 17:23:42 +0200
+Subject: net: sched: switch default qdisc from pfifo_fast to fq_codel and remove pfifo_fast
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ net/sched/sch_generic.c | 140 ------------------------------------------------
+ 1 file changed, 140 deletions(-)
+
+--- a/net/sched/sch_generic.c
++++ b/net/sched/sch_generic.c
+@@ -620,230 +620,6 @@ struct Qdisc_ops noqueue_qdisc_ops __rea
+ 	.owner		=	THIS_MODULE,
+ };
+ 
+-static const u8 prio2band[TC_PRIO_MAX + 1] = {
+-	1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1
+-};
+-
+-/* 3-band FIFO queue: old style, but should be a bit faster than
+-   generic prio+fifo combination.
+- */
+-
+-#define PFIFO_FAST_BANDS 3
+-
+-/*
+- * Private data for a pfifo_fast scheduler containing:
+- *	- rings for priority bands
+- */
+-struct pfifo_fast_priv {
+-	struct skb_array q[PFIFO_FAST_BANDS];
+-};
+-
+-static inline struct skb_array *band2list(struct pfifo_fast_priv *priv,
+-					  int band)
+-{
+-	return &priv->q[band];
+-}
+-
+-static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc *qdisc,
+-			      struct sk_buff **to_free)
+-{
+-	int band = prio2band[skb->priority & TC_PRIO_MAX];
+-	struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
+-	struct skb_array *q = band2list(priv, band);
+-	unsigned int pkt_len = qdisc_pkt_len(skb);
+-	int err;
+-
+-	err = skb_array_produce(q, skb);
+-
+-	if (unlikely(err)) {
+-		if (qdisc_is_percpu_stats(qdisc))
+-			return qdisc_drop_cpu(skb, qdisc, to_free);
+-		else
+-			return qdisc_drop(skb, qdisc, to_free);
+-	}
+-
+-	qdisc_update_stats_at_enqueue(qdisc, pkt_len);
+-	return NET_XMIT_SUCCESS;
+-}
+-
+-static struct sk_buff *pfifo_fast_dequeue(struct Qdisc *qdisc)
+-{
+-	struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
+-	struct sk_buff *skb = NULL;
+-	bool need_retry = true;
+-	int band;
+-
+-retry:
+-	for (band = 0; band < PFIFO_FAST_BANDS && !skb; band++) {
+-		struct skb_array *q = band2list(priv, band);
+-
+-		if (__skb_array_empty(q))
+-			continue;
+-
+-		skb = __skb_array_consume(q);
+-	}
+-	if (likely(skb)) {
+-		qdisc_update_stats_at_dequeue(qdisc, skb);
+-	} else if (need_retry &&
+-		   test_bit(__QDISC_STATE_MISSED, &qdisc->state)) {
+-		/* Delay clearing the STATE_MISSED here to reduce
+-		 * the overhead of the second spin_trylock() in
+-		 * qdisc_run_begin() and __netif_schedule() calling
+-		 * in qdisc_run_end().
+-		 */
+-		clear_bit(__QDISC_STATE_MISSED, &qdisc->state);
+-
+-		/* Make sure dequeuing happens after clearing
+-		 * STATE_MISSED.
+-		 */
+-		smp_mb__after_atomic();
+-
+-		need_retry = false;
+-
+-		goto retry;
+-	} else {
+-		WRITE_ONCE(qdisc->empty, true);
+-	}
+-
+-	return skb;
+-}
+-
+-static struct sk_buff *pfifo_fast_peek(struct Qdisc *qdisc)
+-{
+-	struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
+-	struct sk_buff *skb = NULL;
+-	int band;
+-
+-	for (band = 0; band < PFIFO_FAST_BANDS && !skb; band++) {
+-		struct skb_array *q = band2list(priv, band);
+-
+-		skb = __skb_array_peek(q);
+-	}
+-
+-	return skb;
+-}
+-
+-static void pfifo_fast_reset(struct Qdisc *qdisc)
+-{
+-	int i, band;
+-	struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
+-
+-	for (band = 0; band < PFIFO_FAST_BANDS; band++) {
+-		struct skb_array *q = band2list(priv, band);
+-		struct sk_buff *skb;
+-
+-		/* NULL ring is possible if destroy path is due to a failed
+-		 * skb_array_init() in pfifo_fast_init() case.
+-		 */
+-		if (!q->ring.queue)
+-			continue;
+-
+-		while ((skb = __skb_array_consume(q)) != NULL)
+-			kfree_skb(skb);
+-	}
+-
+-	if (qdisc_is_percpu_stats(qdisc)) {
+-		for_each_possible_cpu(i) {
+-			struct gnet_stats_queue *q;
+-
+-			q = per_cpu_ptr(qdisc->cpu_qstats, i);
+-			q->backlog = 0;
+-			q->qlen = 0;
+-		}
+-	}
+-}
+-
+-static int pfifo_fast_dump(struct Qdisc *qdisc, struct sk_buff *skb)
+-{
+-	struct tc_prio_qopt opt = { .bands = PFIFO_FAST_BANDS };
+-
+-	memcpy(&opt.priomap, prio2band, TC_PRIO_MAX + 1);
+-	if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt))
+-		goto nla_put_failure;
+-	return skb->len;
+-
+-nla_put_failure:
+-	return -1;
+-}
+-
+-static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt,
+-			   struct netlink_ext_ack *extack)
+-{
+-	unsigned int qlen = qdisc_dev(qdisc)->tx_queue_len;
+-	struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
+-	int prio;
+-
+-	/* guard against zero length rings */
+-	if (!qlen)
+-		return -EINVAL;
+-
+-	for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) {
+-		struct skb_array *q = band2list(priv, prio);
+-		int err;
+-
+-		err = skb_array_init(q, qlen, GFP_KERNEL);
+-		if (err)
+-			return -ENOMEM;
+-	}
+-
+-	/* Can by-pass the queue discipline */
+-	qdisc->flags |= TCQ_F_CAN_BYPASS;
+-	return 0;
+-}
+-
+-static void pfifo_fast_destroy(struct Qdisc *sch)
+-{
+-	struct pfifo_fast_priv *priv = qdisc_priv(sch);
+-	int prio;
+-
+-	for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) {
+-		struct skb_array *q = band2list(priv, prio);
+-
+-		/* NULL ring is possible if destroy path is due to a failed
+-		 * skb_array_init() in pfifo_fast_init() case.
+-		 */
+-		if (!q->ring.queue)
+-			continue;
+-		/* Destroy ring but no need to kfree_skb because a call to
+-		 * pfifo_fast_reset() has already done that work.
+-		 */
+-		ptr_ring_cleanup(&q->ring, NULL);
+-	}
+-}
+-
+-static int pfifo_fast_change_tx_queue_len(struct Qdisc *sch,
+-					  unsigned int new_len)
+-{
+-	struct pfifo_fast_priv *priv = qdisc_priv(sch);
+-	struct skb_array *bands[PFIFO_FAST_BANDS];
+-	int prio;
+-
+-	for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) {
+-		struct skb_array *q = band2list(priv, prio);
+-
+-		bands[prio] = q;
+-	}
+-
+-	return skb_array_resize_multiple(bands, PFIFO_FAST_BANDS, new_len,
+-					 GFP_KERNEL);
+-}
+-
+-struct Qdisc_ops pfifo_fast_ops __read_mostly = {
+-	.id		=	"pfifo_fast",
+-	.priv_size	=	sizeof(struct pfifo_fast_priv),
+-	.enqueue	=	pfifo_fast_enqueue,
+-	.dequeue	=	pfifo_fast_dequeue,
+-	.peek		=	pfifo_fast_peek,
+-	.init		=	pfifo_fast_init,
+-	.destroy	=	pfifo_fast_destroy,
+-	.reset		=	pfifo_fast_reset,
+-	.dump		=	pfifo_fast_dump,
+-	.change_tx_queue_len =  pfifo_fast_change_tx_queue_len,
+-	.owner		=	THIS_MODULE,
+-	.static_flags	=	TCQ_F_NOLOCK | TCQ_F_CPUSTATS,
+-};
+-EXPORT_SYMBOL(pfifo_fast_ops);
+-
+ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
+ 			  const struct Qdisc_ops *ops,
+ 			  struct netlink_ext_ack *extack)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/700-swconfig_switch_drivers.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/700-swconfig_switch_drivers.patch
new file mode 100644
index 0000000..f30ad81
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/700-swconfig_switch_drivers.patch
@@ -0,0 +1,135 @@
+From 36e516290611e613aa92996cb4339561452695b4 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 7 Jul 2017 17:24:23 +0200
+Subject: net: swconfig: adds openwrt switch layer
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ drivers/net/phy/Kconfig   | 83 +++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/net/phy/Makefile  | 15 +++++++++
+ include/uapi/linux/Kbuild |  1 +
+ 3 files changed, 99 insertions(+)
+
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -250,6 +250,85 @@ config LED_TRIGGER_PHY
+ 		for any speed known to the PHY.
+ 
+ 
++comment "Switch configuration API + drivers"
++
++config SWCONFIG
++	tristate "Switch configuration API"
++	---help---
++	  Switch configuration API using netlink. This allows
++	  you to configure the VLAN features of certain switches.
++
++config SWCONFIG_LEDS
++	bool "Switch LED trigger support"
++	depends on (SWCONFIG && LEDS_TRIGGERS)
++
++config ADM6996_PHY
++	tristate "Driver for ADM6996 switches"
++	select SWCONFIG
++	---help---
++	  Currently supports the ADM6996FC and ADM6996M switches.
++	  Support for FC is very limited.
++
++config AR8216_PHY
++	tristate "Driver for Atheros AR8216 switches"
++	select ETHERNET_PACKET_MANGLE
++	select SWCONFIG
++
++config AR8216_PHY_LEDS
++	bool "Atheros AR8216 switch LED support"
++	depends on (AR8216_PHY && LEDS_CLASS)
++
++source "drivers/net/phy/b53/Kconfig"
++
++config IP17XX_PHY
++	tristate "Driver for IC+ IP17xx switches"
++	select SWCONFIG
++
++config MVSWITCH_PHY
++	tristate "Driver for Marvell 88E6060 switches"
++	select ETHERNET_PACKET_MANGLE
++
++config PSB6970_PHY
++	tristate "Lantiq XWAY Tantos (PSB6970) Ethernet switch"
++	select SWCONFIG
++	select ETHERNET_PACKET_MANGLE
++
++config RTL8306_PHY
++	tristate "Driver for Realtek RTL8306S switches"
++	select SWCONFIG
++
++config RTL8366_SMI
++	tristate "Driver for the RTL8366 SMI interface"
++	depends on GPIOLIB
++	---help---
++	  This module implements the SMI interface protocol which is used
++	  by some RTL8366 ethernet switch devices via the generic GPIO API.
++
++if RTL8366_SMI
++
++config RTL8366_SMI_DEBUG_FS
++	bool "RTL8366 SMI interface debugfs support"
++        depends on DEBUG_FS
++        default n
++
++config RTL8366S_PHY
++	tristate "Driver for the Realtek RTL8366S switch"
++	select SWCONFIG
++
++config RTL8366RB_PHY
++	tristate "Driver for the Realtek RTL8366RB switch"
++	select SWCONFIG
++
++config RTL8367_PHY
++	tristate "Driver for the Realtek RTL8367R/M switches"
++	select SWCONFIG
++
++config RTL8367B_PHY
++	tristate "Driver fot the Realtek RTL8367R-VB switch"
++	select SWCONFIG
++
++endif # RTL8366_SMI
++
+ comment "MII PHY device drivers"
+ 
+ config SFP
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -22,6 +22,20 @@ libphy-$(CONFIG_LED_TRIGGER_PHY)	+= phy_
+ obj-$(CONFIG_PHYLINK)		+= phylink.o
+ obj-$(CONFIG_PHYLIB)		+= libphy.o
+ 
++obj-$(CONFIG_SWCONFIG)		+= swconfig.o
++obj-$(CONFIG_ADM6996_PHY)	+= adm6996.o
++obj-$(CONFIG_AR8216_PHY)	+= ar8216.o ar8327.o
++obj-$(CONFIG_SWCONFIG_B53)	+= b53/
++obj-$(CONFIG_IP17XX_PHY)	+= ip17xx.o
++obj-$(CONFIG_MVSWITCH_PHY)	+= mvswitch.o
++obj-$(CONFIG_PSB6970_PHY)	+= psb6970.o
++obj-$(CONFIG_RTL8306_PHY)	+= rtl8306.o
++obj-$(CONFIG_RTL8366_SMI)	+= rtl8366_smi.o
++obj-$(CONFIG_RTL8366S_PHY)	+= rtl8366s.o
++obj-$(CONFIG_RTL8366RB_PHY)	+= rtl8366rb.o
++obj-$(CONFIG_RTL8367_PHY)	+= rtl8367.o
++obj-$(CONFIG_RTL8367B_PHY)	+= rtl8367b.o
++
+ obj-$(CONFIG_MDIO_ASPEED)	+= mdio-aspeed.o
+ obj-$(CONFIG_MDIO_BCM_IPROC)	+= mdio-bcm-iproc.o
+ obj-$(CONFIG_MDIO_BCM_UNIMAC)	+= mdio-bcm-unimac.o
+--- a/include/linux/platform_data/b53.h
++++ b/include/linux/platform_data/b53.h
+@@ -29,6 +29,9 @@ struct b53_platform_data {
+ 	u32 chip_id;
+ 	u16 enabled_ports;
+ 
++	/* allow to specify an ethX alias */
++	const char *alias;
++
+ 	/* only used by MMAP'd driver */
+ 	unsigned big_endian:1;
+ 	void __iomem *regs;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/703-add_vsc8504_support.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/703-add_vsc8504_support.patch
new file mode 100644
index 0000000..afb6ca6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/703-add_vsc8504_support.patch
@@ -0,0 +1,57 @@
+From: Roman Kuzmitskii <damex.pp@icloud.com>
+Date: Thu, 05 Nov 2020 02:00:00 +0000
+Subject: [PATCH] net: phy: vitesse: add vsc8504 support
+
+This patch adds support for vsc8504 phy.
+That phy is changed owner:
+ vitesse -> microsemi -> microchip
+So is its driver in kernel was changed and rewritten.
+
+there is no need to upstream this patch.
+this vsc8504 is supported by newer kernels out of box.
+support could be enabled by CONFIG_MICROSEMI_PHY.
+
+Tested-by: Johannes Kimmel <fff@bareminimum.eu>
+Signed-off-by: Roman Kuzmitskii <damex.pp@icloud.com>
+--- a/drivers/net/phy/vitesse.c
++++ b/drivers/net/phy/vitesse.c
+@@ -61,6 +61,7 @@
+ 
+ #define PHY_ID_VSC8234			0x000fc620
+ #define PHY_ID_VSC8244			0x000fc6c0
++#define PHY_ID_VSC8504			0x000704c2
+ #define PHY_ID_VSC8572			0x000704d0
+ #define PHY_ID_VSC8601			0x00070420
+ #define PHY_ID_VSC7385			0x00070450
+@@ -292,6 +293,7 @@ static int vsc82xx_config_intr(struct ph
+ 		err = phy_write(phydev, MII_VSC8244_IMASK,
+ 			(phydev->drv->phy_id == PHY_ID_VSC8234 ||
+ 			 phydev->drv->phy_id == PHY_ID_VSC8244 ||
++			 phydev->drv->phy_id == PHY_ID_VSC8504 ||
+ 			 phydev->drv->phy_id == PHY_ID_VSC8572 ||
+ 			 phydev->drv->phy_id == PHY_ID_VSC8601) ?
+ 				MII_VSC8244_IMASK_MASK :
+@@ -402,6 +404,15 @@ static struct phy_driver vsc82xx_driver[
+ 	.ack_interrupt	= &vsc824x_ack_interrupt,
+ 	.config_intr	= &vsc82xx_config_intr,
+ }, {
++	.phy_id         = PHY_ID_VSC8504,
++	.name           = "Vitesse VSC8504",
++	.phy_id_mask    = 0x000ffff0,
++	/* PHY_GBIT_FEATURES */
++	.config_init    = &vsc824x_config_init,
++	.config_aneg    = &vsc82x4_config_aneg,
++	.ack_interrupt  = &vsc824x_ack_interrupt,
++	.config_intr    = &vsc82xx_config_intr,
++}, {
+ 	.phy_id         = PHY_ID_VSC8572,
+ 	.name           = "Vitesse VSC8572",
+ 	.phy_id_mask    = 0x000ffff0,
+@@ -488,6 +499,7 @@ module_phy_driver(vsc82xx_driver);
+ static struct mdio_device_id __maybe_unused vitesse_tbl[] = {
+ 	{ PHY_ID_VSC8234, 0x000ffff0 },
+ 	{ PHY_ID_VSC8244, 0x000fffc0 },
++	{ PHY_ID_VSC8504, 0x000ffff0 },
+ 	{ PHY_ID_VSC8572, 0x000ffff0 },
+ 	{ PHY_ID_VSC7385, 0x000ffff0 },
+ 	{ PHY_ID_VSC7388, 0x000ffff0 },
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/710-net-dsa-mv88e6xxx-default-VID-1.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/710-net-dsa-mv88e6xxx-default-VID-1.patch
new file mode 100644
index 0000000..5dc5ac6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/710-net-dsa-mv88e6xxx-default-VID-1.patch
@@ -0,0 +1,18 @@
+--- a/drivers/net/dsa/mv88e6xxx/chip.c
++++ b/drivers/net/dsa/mv88e6xxx/chip.c
+@@ -1930,6 +1930,7 @@ static int mv88e6xxx_port_fdb_add(struct
+ 	struct mv88e6xxx_chip *chip = ds->priv;
+ 	int err;
+ 
++	vid = vid ? : 1;
+ 	mv88e6xxx_reg_lock(chip);
+ 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
+ 					   MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
+@@ -1944,6 +1945,7 @@ static int mv88e6xxx_port_fdb_del(struct
+ 	struct mv88e6xxx_chip *chip = ds->priv;
+ 	int err;
+ 
++	vid = vid ? : 1;
+ 	mv88e6xxx_reg_lock(chip);
+ 	err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0);
+ 	mv88e6xxx_reg_unlock(chip);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/711-net-dsa-mv88e6xxx-disable-ATU-violation.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/711-net-dsa-mv88e6xxx-disable-ATU-violation.patch
new file mode 100644
index 0000000..1da388c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/711-net-dsa-mv88e6xxx-disable-ATU-violation.patch
@@ -0,0 +1,12 @@
+--- a/drivers/net/dsa/mv88e6xxx/chip.c
++++ b/drivers/net/dsa/mv88e6xxx/chip.c
+@@ -2492,6 +2492,9 @@ static int mv88e6xxx_setup_port(struct m
+ 	if (dsa_is_cpu_port(ds, port))
+ 		reg = 0;
+ 
++	/* Disable ATU member violation interrupt */
++	reg |= MV88E6XXX_PORT_ASSOC_VECTOR_IGNORE_WRONG;
++
+ 	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
+ 				   reg);
+ 	if (err)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/721-phy_packets.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/721-phy_packets.patch
new file mode 100644
index 0000000..89ff8ea
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/721-phy_packets.patch
@@ -0,0 +1,176 @@
+From ffe387740bbe88dd88bbe04d6375902708003d6e Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 7 Jul 2017 17:25:00 +0200
+Subject: net: add packet mangeling patch
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ include/linux/netdevice.h | 11 +++++++++++
+ include/linux/skbuff.h    | 14 ++++----------
+ net/Kconfig               |  6 ++++++
+ net/core/dev.c            | 18 ++++++++++++++----
+ net/core/skbuff.c         | 17 +++++++++++++++++
+ net/ethernet/eth.c        |  6 ++++++
+ 6 files changed, 58 insertions(+), 14 deletions(-)
+
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -1540,6 +1540,7 @@ enum netdev_priv_flags {
+ 	IFF_FAILOVER_SLAVE		= 1<<28,
+ 	IFF_L3MDEV_RX_HANDLER		= 1<<29,
+ 	IFF_LIVE_RENAME_OK		= 1<<30,
++	IFF_NO_IP_ALIGN			= 1<<31,
+ };
+ 
+ #define IFF_802_1Q_VLAN			IFF_802_1Q_VLAN
+@@ -1572,6 +1573,7 @@ enum netdev_priv_flags {
+ #define IFF_FAILOVER_SLAVE		IFF_FAILOVER_SLAVE
+ #define IFF_L3MDEV_RX_HANDLER		IFF_L3MDEV_RX_HANDLER
+ #define IFF_LIVE_RENAME_OK		IFF_LIVE_RENAME_OK
++#define IFF_NO_IP_ALIGN			IFF_NO_IP_ALIGN
+ 
+ /* Specifies the type of the struct net_device::ml_priv pointer */
+ enum netdev_ml_priv_type {
+@@ -1882,6 +1884,11 @@ struct net_device {
+ 	const struct tlsdev_ops *tlsdev_ops;
+ #endif
+ 
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++	void (*eth_mangle_rx)(struct net_device *dev, struct sk_buff *skb);
++	struct sk_buff *(*eth_mangle_tx)(struct net_device *dev, struct sk_buff *skb);
++#endif
++
+ 	const struct header_ops *header_ops;
+ 
+ 	unsigned int		flags;
+@@ -1964,6 +1971,10 @@ struct net_device {
+ 	struct mpls_dev __rcu	*mpls_ptr;
+ #endif
+ 
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++	void			*phy_ptr; /* PHY device specific data */
++#endif
++
+ /*
+  * Cache lines mostly used on receive path (including eth_type_trans())
+  */
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -2684,6 +2684,10 @@ static inline int pskb_trim(struct sk_bu
+ 	return (len < skb->len) ? __pskb_trim(skb, len) : 0;
+ }
+ 
++extern struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
++		unsigned int length, gfp_t gfp);
++
++
+ /**
+  *	pskb_trim_unique - remove end from a paged unique (not cloned) buffer
+  *	@skb: buffer to alter
+@@ -2815,16 +2819,6 @@ static inline struct sk_buff *dev_alloc_
+ }
+ 
+ 
+-static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
+-		unsigned int length, gfp_t gfp)
+-{
+-	struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
+-
+-	if (NET_IP_ALIGN && skb)
+-		skb_reserve(skb, NET_IP_ALIGN);
+-	return skb;
+-}
+-
+ static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev,
+ 		unsigned int length)
+ {
+--- a/net/Kconfig
++++ b/net/Kconfig
+@@ -26,6 +26,12 @@ menuconfig NET
+ 
+ if NET
+ 
++config ETHERNET_PACKET_MANGLE
++	bool
++	help
++	  This option can be selected by phy drivers that need to mangle
++	  packets going in or out of an ethernet device.
++
+ config WANT_COMPAT_NETLINK_MESSAGES
+ 	bool
+ 	help
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -3221,10 +3221,20 @@ static int xmit_one(struct sk_buff *skb,
+ 	if (dev_nit_active(dev))
+ 		dev_queue_xmit_nit(skb, dev);
+ 
+-	len = skb->len;
+-	trace_net_dev_start_xmit(skb, dev);
+-	rc = netdev_start_xmit(skb, dev, txq, more);
+-	trace_net_dev_xmit(skb, rc, dev, len);
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++	if (!dev->eth_mangle_tx ||
++	    (skb = dev->eth_mangle_tx(dev, skb)) != NULL)
++#else
++	if (1)
++#endif
++	{
++		len = skb->len;
++		trace_net_dev_start_xmit(skb, dev);
++		rc = netdev_start_xmit(skb, dev, txq, more);
++		trace_net_dev_xmit(skb, rc, dev, len);
++	} else {
++		rc = NETDEV_TX_OK;
++	}
+ 
+ 	return rc;
+ }
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -60,6 +60,7 @@
+ #include <linux/prefetch.h>
+ #include <linux/if_vlan.h>
+ #include <linux/mpls.h>
++#include <linux/if.h>
+ 
+ #include <net/protocol.h>
+ #include <net/dst.h>
+@@ -549,6 +550,22 @@ skb_fail:
+ }
+ EXPORT_SYMBOL(__napi_alloc_skb);
+ 
++struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
++		unsigned int length, gfp_t gfp)
++{
++	struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
++
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++	if (dev && (dev->priv_flags & IFF_NO_IP_ALIGN))
++		return skb;
++#endif
++
++	if (NET_IP_ALIGN && skb)
++		skb_reserve(skb, NET_IP_ALIGN);
++	return skb;
++}
++EXPORT_SYMBOL(__netdev_alloc_skb_ip_align);
++
+ void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
+ 		     int size, unsigned int truesize)
+ {
+--- a/net/ethernet/eth.c
++++ b/net/ethernet/eth.c
+@@ -171,6 +171,12 @@ __be16 eth_type_trans(struct sk_buff *sk
+ 	const struct ethhdr *eth;
+ 
+ 	skb->dev = dev;
++
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++	if (dev->eth_mangle_rx)
++		dev->eth_mangle_rx(dev, skb);
++#endif
++
+ 	skb_reset_mac_header(skb);
+ 
+ 	eth = (struct ethhdr *)skb->data;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/773-bgmac-add-srab-switch.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/773-bgmac-add-srab-switch.patch
new file mode 100644
index 0000000..89e0df4
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/773-bgmac-add-srab-switch.patch
@@ -0,0 +1,98 @@
+From 3cb240533ab787899dc7f17aa7d6c5b4810e2e58 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Fri, 7 Jul 2017 17:26:01 +0200
+Subject: bcm53xx: bgmac: use srab switch driver
+
+use the srab switch driver on these SoCs.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/net/ethernet/broadcom/bgmac-bcma.c |  1 +
+ drivers/net/ethernet/broadcom/bgmac.c      | 24 ++++++++++++++++++++++++
+ drivers/net/ethernet/broadcom/bgmac.h      |  4 ++++
+ 3 files changed, 29 insertions(+)
+
+--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c
++++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c
+@@ -268,6 +268,7 @@ static int bgmac_probe(struct bcma_devic
+ 		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
+ 		bgmac->feature_flags |= BGMAC_FEAT_NO_RESET;
+ 		bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
++		bgmac->feature_flags |= BGMAC_FEAT_SRAB;
+ 		break;
+ 	default:
+ 		bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -12,6 +12,7 @@
+ #include <linux/bcma/bcma.h>
+ #include <linux/etherdevice.h>
+ #include <linux/interrupt.h>
++#include <linux/platform_data/b53.h>
+ #include <linux/bcm47xx_nvram.h>
+ #include <linux/phy.h>
+ #include <linux/phy_fixed.h>
+@@ -1407,6 +1408,17 @@ static const struct ethtool_ops bgmac_et
+ 	.set_link_ksettings     = phy_ethtool_set_link_ksettings,
+ };
+ 
++static struct b53_platform_data bgmac_b53_pdata = {
++};
++
++static struct platform_device bgmac_b53_dev = {
++	.name		= "b53-srab-switch",
++	.id		= -1,
++	.dev		= {
++		.platform_data = &bgmac_b53_pdata,
++	},
++};
++
+ /**************************************************
+  * MII
+  **************************************************/
+@@ -1538,6 +1550,14 @@ int bgmac_enet_probe(struct bgmac *bgmac
+ 	net_dev->hw_features = net_dev->features;
+ 	net_dev->vlan_features = net_dev->features;
+ 
++	if ((bgmac->feature_flags & BGMAC_FEAT_SRAB) && !bgmac_b53_pdata.regs) {
++		bgmac_b53_pdata.regs = ioremap_nocache(0x18007000, 0x1000);
++
++		err = platform_device_register(&bgmac_b53_dev);
++		if (!err)
++			bgmac->b53_device = &bgmac_b53_dev;
++	}
++
+ 	err = register_netdev(bgmac->net_dev);
+ 	if (err) {
+ 		dev_err(bgmac->dev, "Cannot register net device\n");
+@@ -1560,6 +1580,10 @@ EXPORT_SYMBOL_GPL(bgmac_enet_probe);
+ 
+ void bgmac_enet_remove(struct bgmac *bgmac)
+ {
++	if (bgmac->b53_device)
++		platform_device_unregister(&bgmac_b53_dev);
++	bgmac->b53_device = NULL;
++
+ 	unregister_netdev(bgmac->net_dev);
+ 	phy_disconnect(bgmac->net_dev->phydev);
+ 	netif_napi_del(&bgmac->napi);
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -427,6 +427,7 @@
+ #define BGMAC_FEAT_CC4_IF_SW_TYPE_RGMII	BIT(18)
+ #define BGMAC_FEAT_CC7_IF_TYPE_RGMII	BIT(19)
+ #define BGMAC_FEAT_IDM_MASK		BIT(20)
++#define BGMAC_FEAT_SRAB			BIT(21)
+ 
+ struct bgmac_slot_info {
+ 	union {
+@@ -532,6 +533,9 @@ struct bgmac {
+ 	void (*cmn_maskset32)(struct bgmac *bgmac, u16 offset, u32 mask,
+ 			      u32 set);
+ 	int (*phy_connect)(struct bgmac *bgmac);
++
++	/* platform device for associated switch */
++	struct platform_device *b53_device;
+ };
+ 
+ struct bgmac *bgmac_alloc(struct device *dev);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/901-debloat_sock_diag.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/901-debloat_sock_diag.patch
new file mode 100644
index 0000000..0abb672
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/901-debloat_sock_diag.patch
@@ -0,0 +1,145 @@
+From 3b6115d6b57a263bdc8c9b1df273bd4a7955eead Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 8 Jul 2017 08:16:31 +0200
+Subject: debloat: add some debloat patches, strip down procfs and make O_DIRECT support optional, saves ~15K after lzma on MIPS
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ net/Kconfig         | 3 +++
+ net/core/Makefile   | 3 ++-
+ net/core/sock.c     | 2 ++
+ net/ipv4/Kconfig    | 1 +
+ net/netlink/Kconfig | 1 +
+ net/packet/Kconfig  | 1 +
+ net/unix/Kconfig    | 1 +
+ 7 files changed, 11 insertions(+), 1 deletion(-)
+
+--- a/net/Kconfig
++++ b/net/Kconfig
+@@ -103,6 +103,9 @@ source "net/netlabel/Kconfig"
+ 
+ endif # if INET
+ 
++config SOCK_DIAG
++	bool
++
+ config NETWORK_SECMARK
+ 	bool "Security Marking"
+ 	help
+--- a/net/core/Makefile
++++ b/net/core/Makefile
+@@ -10,9 +10,10 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core.
+ 
+ obj-y		     += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \
+ 			neighbour.o rtnetlink.o utils.o link_watch.o filter.o \
+-			sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \
++ 			dev_ioctl.o tso.o sock_reuseport.o \
+ 			fib_notifier.o xdp.o flow_offload.o
+ 
++obj-$(CONFIG_SOCK_DIAG) += sock_diag.o
+ obj-y += net-sysfs.o
+ obj-$(CONFIG_PAGE_POOL) += page_pool.o
+ obj-$(CONFIG_PROC_FS) += net-procfs.o
+--- a/net/core/sock.c
++++ b/net/core/sock.c
+@@ -140,6 +140,7 @@
+ 
+ static DEFINE_MUTEX(proto_list_mutex);
+ static LIST_HEAD(proto_list);
++static atomic64_t cookie_gen;
+ 
+ static void sock_inuse_add(struct net *net, int val);
+ 
+@@ -539,6 +540,18 @@ discard_and_relse:
+ }
+ EXPORT_SYMBOL(__sk_receive_skb);
+ 
++u64 sock_gen_cookie(struct sock *sk)
++{
++	while (1) {
++		u64 res = atomic64_read(&sk->sk_cookie);
++
++		if (res)
++			return res;
++		res = atomic64_inc_return(&cookie_gen);
++		atomic64_cmpxchg(&sk->sk_cookie, 0, res);
++	}
++}
++
+ struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie)
+ {
+ 	struct dst_entry *dst = __sk_dst_get(sk);
+@@ -1760,9 +1773,11 @@ static void __sk_free(struct sock *sk)
+ 	if (likely(sk->sk_net_refcnt))
+ 		sock_inuse_add(sock_net(sk), -1);
+ 
++#ifdef CONFIG_SOCK_DIAG
+ 	if (unlikely(sk->sk_net_refcnt && sock_diag_has_destroy_listeners(sk)))
+ 		sock_diag_broadcast_destroy(sk);
+ 	else
++#endif
+ 		sk_destruct(sk);
+ }
+ 
+--- a/net/core/sock_diag.c
++++ b/net/core/sock_diag.c
+@@ -19,19 +19,6 @@ static const struct sock_diag_handler *s
+ static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh);
+ static DEFINE_MUTEX(sock_diag_table_mutex);
+ static struct workqueue_struct *broadcast_wq;
+-static atomic64_t cookie_gen;
+-
+-u64 sock_gen_cookie(struct sock *sk)
+-{
+-	while (1) {
+-		u64 res = atomic64_read(&sk->sk_cookie);
+-
+-		if (res)
+-			return res;
+-		res = atomic64_inc_return(&cookie_gen);
+-		atomic64_cmpxchg(&sk->sk_cookie, 0, res);
+-	}
+-}
+ 
+ int sock_diag_check_cookie(struct sock *sk, const __u32 *cookie)
+ {
+--- a/net/ipv4/Kconfig
++++ b/net/ipv4/Kconfig
+@@ -400,6 +400,7 @@ config INET_TUNNEL
+ 
+ config INET_DIAG
+ 	tristate "INET: socket monitoring interface"
++	select SOCK_DIAG
+ 	default y
+ 	---help---
+ 	  Support for INET (TCP, DCCP, etc) socket monitoring interface used by
+--- a/net/netlink/Kconfig
++++ b/net/netlink/Kconfig
+@@ -5,6 +5,7 @@
+ 
+ config NETLINK_DIAG
+ 	tristate "NETLINK: socket monitoring interface"
++	select SOCK_DIAG
+ 	default n
+ 	---help---
+ 	  Support for NETLINK socket monitoring interface used by the ss tool.
+--- a/net/packet/Kconfig
++++ b/net/packet/Kconfig
+@@ -19,6 +19,7 @@ config PACKET
+ config PACKET_DIAG
+ 	tristate "Packet: sockets monitoring interface"
+ 	depends on PACKET
++	select SOCK_DIAG
+ 	default n
+ 	---help---
+ 	  Support for PF_PACKET sockets monitoring interface used by the ss tool.
+--- a/net/unix/Kconfig
++++ b/net/unix/Kconfig
+@@ -28,6 +28,7 @@ config UNIX_SCM
+ config UNIX_DIAG
+ 	tristate "UNIX: socket monitoring interface"
+ 	depends on UNIX
++	select SOCK_DIAG
+ 	default n
+ 	---help---
+ 	  Support for UNIX socket monitoring interface used by the ss tool.
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/902-debloat_proc.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/902-debloat_proc.patch
new file mode 100644
index 0000000..c680e7b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/902-debloat_proc.patch
@@ -0,0 +1,408 @@
+From 9e3f1d0805b2d919904dd9a4ff0d956314cc3cba Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 8 Jul 2017 08:20:09 +0200
+Subject: debloat: procfs
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ fs/locks.c               |  2 ++
+ fs/proc/Kconfig          |  5 +++++
+ fs/proc/consoles.c       |  3 +++
+ fs/proc/proc_tty.c       | 11 ++++++++++-
+ include/net/snmp.h       | 18 +++++++++++++++++-
+ ipc/msg.c                |  3 +++
+ ipc/sem.c                |  2 ++
+ ipc/shm.c                |  2 ++
+ ipc/util.c               |  3 +++
+ kernel/exec_domain.c     |  2 ++
+ kernel/irq/proc.c        |  9 +++++++++
+ kernel/time/timer_list.c |  2 ++
+ mm/vmalloc.c             |  2 ++
+ mm/vmstat.c              |  8 +++++---
+ net/8021q/vlanproc.c     |  6 ++++++
+ net/core/net-procfs.c    | 18 ++++++++++++------
+ net/core/sock.c          |  2 ++
+ net/ipv4/fib_trie.c      | 18 ++++++++++++------
+ net/ipv4/proc.c          |  3 +++
+ net/ipv4/route.c         |  3 +++
+ 20 files changed, 105 insertions(+), 17 deletions(-)
+
+--- a/fs/locks.c
++++ b/fs/locks.c
+@@ -2989,6 +2989,8 @@ static const struct seq_operations locks
+ 
+ static int __init proc_locks_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
+ 	proc_create_seq_private("locks", 0, NULL, &locks_seq_operations,
+ 			sizeof(struct locks_iterator), NULL);
+ 	return 0;
+--- a/fs/proc/Kconfig
++++ b/fs/proc/Kconfig
+@@ -100,6 +100,11 @@ config PROC_CHILDREN
+ 	  Say Y if you are running any user-space software which takes benefit from
+ 	  this interface. For example, rkt is such a piece of software.
+ 
++config PROC_STRIPPED
++	default n
++	depends on EXPERT
++	bool "Strip non-essential /proc functionality to reduce code size"
++
+ config PROC_PID_ARCH_STATUS
+ 	def_bool n
+ 	depends on PROC_FS
+--- a/fs/proc/consoles.c
++++ b/fs/proc/consoles.c
+@@ -92,6 +92,9 @@ static const struct seq_operations conso
+ 
+ static int __init proc_consoles_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
++
+ 	proc_create_seq("consoles", 0, NULL, &consoles_op);
+ 	return 0;
+ }
+--- a/fs/proc/proc_tty.c
++++ b/fs/proc/proc_tty.c
+@@ -133,7 +133,10 @@ static const struct seq_operations tty_d
+ void proc_tty_register_driver(struct tty_driver *driver)
+ {
+ 	struct proc_dir_entry *ent;
+-		
++
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	if (!driver->driver_name || driver->proc_entry ||
+ 	    !driver->ops->proc_show)
+ 		return;
+@@ -150,6 +153,9 @@ void proc_tty_unregister_driver(struct t
+ {
+ 	struct proc_dir_entry *ent;
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	ent = driver->proc_entry;
+ 	if (!ent)
+ 		return;
+@@ -164,6 +170,9 @@ void proc_tty_unregister_driver(struct t
+  */
+ void __init proc_tty_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	if (!proc_mkdir("tty", NULL))
+ 		return;
+ 	proc_mkdir("tty/ldisc", NULL);	/* Preserved: it's userspace visible */
+--- a/include/net/snmp.h
++++ b/include/net/snmp.h
+@@ -118,6 +118,21 @@ struct linux_xfrm_mib {
+ #define DECLARE_SNMP_STAT(type, name)	\
+ 	extern __typeof__(type) __percpu *name
+ 
++#ifdef CONFIG_PROC_STRIPPED
++#define __SNMP_STATS_DUMMY(mib)	\
++	do { (void) mib->mibs[0]; } while(0)
++
++#define __SNMP_INC_STATS(mib, field) __SNMP_STATS_DUMMY(mib)
++#define SNMP_INC_STATS_ATOMIC_LONG(mib, field) __SNMP_STATS_DUMMY(mib)
++#define SNMP_INC_STATS(mib, field) __SNMP_STATS_DUMMY(mib)
++#define SNMP_DEC_STATS(mib, field) __SNMP_STATS_DUMMY(mib)
++#define __SNMP_ADD_STATS(mib, field, addend) __SNMP_STATS_DUMMY(mib)
++#define SNMP_ADD_STATS(mib, field, addend) __SNMP_STATS_DUMMY(mib)
++#define SNMP_UPD_PO_STATS(mib, basefield, addend) __SNMP_STATS_DUMMY(mib)
++#define __SNMP_UPD_PO_STATS(mib, basefield, addend) __SNMP_STATS_DUMMY(mib)
++
++#else
++
+ #define __SNMP_INC_STATS(mib, field)	\
+ 			__this_cpu_inc(mib->mibs[field])
+ 
+@@ -148,8 +163,9 @@ struct linux_xfrm_mib {
+ 		__this_cpu_add(ptr[basefield##OCTETS], addend);	\
+ 	} while (0)
+ 
++#endif
+ 
+-#if BITS_PER_LONG==32
++#if (BITS_PER_LONG==32) && !defined(CONFIG_PROC_STRIPPED)
+ 
+ #define __SNMP_ADD_STATS64(mib, field, addend) 				\
+ 	do {								\
+--- a/ipc/msg.c
++++ b/ipc/msg.c
+@@ -1317,6 +1317,9 @@ void __init msg_init(void)
+ {
+ 	msg_init_ns(&init_ipc_ns);
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	ipc_init_proc_interface("sysvipc/msg",
+ 				"       key      msqid perms      cbytes       qnum lspid lrpid   uid   gid  cuid  cgid      stime      rtime      ctime\n",
+ 				IPC_MSG_IDS, sysvipc_msg_proc_show);
+--- a/ipc/sem.c
++++ b/ipc/sem.c
+@@ -243,6 +243,8 @@ void sem_exit_ns(struct ipc_namespace *n
+ void __init sem_init(void)
+ {
+ 	sem_init_ns(&init_ipc_ns);
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
+ 	ipc_init_proc_interface("sysvipc/sem",
+ 				"       key      semid perms      nsems   uid   gid  cuid  cgid      otime      ctime\n",
+ 				IPC_SEM_IDS, sysvipc_sem_proc_show);
+--- a/ipc/shm.c
++++ b/ipc/shm.c
+@@ -154,6 +154,8 @@ pure_initcall(ipc_ns_init);
+ 
+ void __init shm_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
+ 	ipc_init_proc_interface("sysvipc/shm",
+ #if BITS_PER_LONG <= 32
+ 				"       key      shmid perms       size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime        rss       swap\n",
+--- a/ipc/util.c
++++ b/ipc/util.c
+@@ -140,6 +140,9 @@ void __init ipc_init_proc_interface(cons
+ 	struct proc_dir_entry *pde;
+ 	struct ipc_proc_iface *iface;
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	iface = kmalloc(sizeof(*iface), GFP_KERNEL);
+ 	if (!iface)
+ 		return;
+--- a/kernel/exec_domain.c
++++ b/kernel/exec_domain.c
+@@ -29,6 +29,8 @@ static int execdomains_proc_show(struct
+ 
+ static int __init proc_execdomains_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
+ 	proc_create_single("execdomains", 0, NULL, execdomains_proc_show);
+ 	return 0;
+ }
+--- a/kernel/irq/proc.c
++++ b/kernel/irq/proc.c
+@@ -341,6 +341,9 @@ void register_irq_proc(unsigned int irq,
+ 	void __maybe_unused *irqp = (void *)(unsigned long) irq;
+ 	char name [MAX_NAMELEN];
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
++		return;
++
+ 	if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip))
+ 		return;
+ 
+@@ -394,6 +397,9 @@ void unregister_irq_proc(unsigned int ir
+ {
+ 	char name [MAX_NAMELEN];
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
++		return;
++
+ 	if (!root_irq_dir || !desc->dir)
+ 		return;
+ #ifdef CONFIG_SMP
+@@ -432,6 +438,9 @@ void init_irq_proc(void)
+ 	unsigned int irq;
+ 	struct irq_desc *desc;
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
++		return;
++
+ 	/* create /proc/irq */
+ 	root_irq_dir = proc_mkdir("irq", NULL);
+ 	if (!root_irq_dir)
+--- a/kernel/time/timer_list.c
++++ b/kernel/time/timer_list.c
+@@ -370,6 +370,8 @@ static int __init init_timer_list_procfs
+ {
+ 	struct proc_dir_entry *pe;
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
+ 	pe = proc_create_seq_private("timer_list", 0400, NULL, &timer_list_sops,
+ 			sizeof(struct timer_list_iter), NULL);
+ 	if (!pe)
+--- a/mm/vmalloc.c
++++ b/mm/vmalloc.c
+@@ -3564,6 +3564,8 @@ static const struct seq_operations vmall
+ 
+ static int __init proc_vmalloc_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
+ 	if (IS_ENABLED(CONFIG_NUMA))
+ 		proc_create_seq_private("vmallocinfo", 0400, NULL,
+ 				&vmalloc_op,
+--- a/mm/vmstat.c
++++ b/mm/vmstat.c
+@@ -1988,10 +1988,12 @@ void __init init_mm_internals(void)
+ 	start_shepherd_timer();
+ #endif
+ #ifdef CONFIG_PROC_FS
+-	proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op);
+-	proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
++		proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op);
++		proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op);
++		proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op);
++	}
+ 	proc_create_seq("vmstat", 0444, NULL, &vmstat_op);
+-	proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op);
+ #endif
+ }
+ 
+--- a/net/8021q/vlanproc.c
++++ b/net/8021q/vlanproc.c
+@@ -93,6 +93,9 @@ void vlan_proc_cleanup(struct net *net)
+ {
+ 	struct vlan_net *vn = net_generic(net, vlan_net_id);
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return;
++
+ 	if (vn->proc_vlan_conf)
+ 		remove_proc_entry(name_conf, vn->proc_vlan_dir);
+ 
+@@ -112,6 +115,9 @@ int __net_init vlan_proc_init(struct net
+ {
+ 	struct vlan_net *vn = net_generic(net, vlan_net_id);
+ 
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
++
+ 	vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net);
+ 	if (!vn->proc_vlan_dir)
+ 		goto err;
+--- a/net/core/net-procfs.c
++++ b/net/core/net-procfs.c
+@@ -309,10 +309,12 @@ static int __net_init dev_proc_net_init(
+ 	if (!proc_create_net("dev", 0444, net->proc_net, &dev_seq_ops,
+ 			sizeof(struct seq_net_private)))
+ 		goto out;
+-	if (!proc_create_seq("softnet_stat", 0444, net->proc_net,
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
++			!proc_create_seq("softnet_stat", 0444, net->proc_net,
+ 			 &softnet_seq_ops))
+ 		goto out_dev;
+-	if (!proc_create_net("ptype", 0444, net->proc_net, &ptype_seq_ops,
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
++			!proc_create_net("ptype", 0444, net->proc_net, &ptype_seq_ops,
+ 			sizeof(struct seq_net_private)))
+ 		goto out_softnet;
+ 
+@@ -322,9 +324,11 @@ static int __net_init dev_proc_net_init(
+ out:
+ 	return rc;
+ out_ptype:
+-	remove_proc_entry("ptype", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
++		remove_proc_entry("ptype", net->proc_net);
+ out_softnet:
+-	remove_proc_entry("softnet_stat", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
++		remove_proc_entry("softnet_stat", net->proc_net);
+ out_dev:
+ 	remove_proc_entry("dev", net->proc_net);
+ 	goto out;
+@@ -334,8 +338,10 @@ static void __net_exit dev_proc_net_exit
+ {
+ 	wext_proc_exit(net);
+ 
+-	remove_proc_entry("ptype", net->proc_net);
+-	remove_proc_entry("softnet_stat", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
++		remove_proc_entry("ptype", net->proc_net);
++		remove_proc_entry("softnet_stat", net->proc_net);
++	}
+ 	remove_proc_entry("dev", net->proc_net);
+ }
+ 
+--- a/net/core/sock.c
++++ b/net/core/sock.c
+@@ -3643,6 +3643,8 @@ static __net_initdata struct pernet_oper
+ 
+ static int __init proto_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
+ 	return register_pernet_subsys(&proto_net_ops);
+ }
+ 
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -2848,11 +2848,13 @@ static const struct seq_operations fib_r
+ 
+ int __net_init fib_proc_init(struct net *net)
+ {
+-	if (!proc_create_net("fib_trie", 0444, net->proc_net, &fib_trie_seq_ops,
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
++			!proc_create_net("fib_trie", 0444, net->proc_net, &fib_trie_seq_ops,
+ 			sizeof(struct fib_trie_iter)))
+ 		goto out1;
+ 
+-	if (!proc_create_net_single("fib_triestat", 0444, net->proc_net,
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
++			!proc_create_net_single("fib_triestat", 0444, net->proc_net,
+ 			fib_triestat_seq_show, NULL))
+ 		goto out2;
+ 
+@@ -2863,17 +2865,21 @@ int __net_init fib_proc_init(struct net
+ 	return 0;
+ 
+ out3:
+-	remove_proc_entry("fib_triestat", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
++		remove_proc_entry("fib_triestat", net->proc_net);
+ out2:
+-	remove_proc_entry("fib_trie", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
++		remove_proc_entry("fib_trie", net->proc_net);
+ out1:
+ 	return -ENOMEM;
+ }
+ 
+ void __net_exit fib_proc_exit(struct net *net)
+ {
+-	remove_proc_entry("fib_trie", net->proc_net);
+-	remove_proc_entry("fib_triestat", net->proc_net);
++	if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
++		remove_proc_entry("fib_trie", net->proc_net);
++		remove_proc_entry("fib_triestat", net->proc_net);
++	}
+ 	remove_proc_entry("route", net->proc_net);
+ }
+ 
+--- a/net/ipv4/proc.c
++++ b/net/ipv4/proc.c
+@@ -522,5 +522,8 @@ static __net_initdata struct pernet_oper
+ 
+ int __init ip_misc_proc_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
++
+ 	return register_pernet_subsys(&ip_proc_ops);
+ }
+--- a/net/ipv4/route.c
++++ b/net/ipv4/route.c
+@@ -410,6 +410,9 @@ static struct pernet_operations ip_rt_pr
+ 
+ static int __init ip_rt_proc_init(void)
+ {
++	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
++		return 0;
++
+ 	return register_pernet_subsys(&ip_rt_proc_ops);
+ }
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/904-debloat_dma_buf.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/904-debloat_dma_buf.patch
new file mode 100644
index 0000000..76032d9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/904-debloat_dma_buf.patch
@@ -0,0 +1,74 @@
+From e3692cb2fcd5ba1244512a0f43b8118f65f1c375 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 8 Jul 2017 08:20:43 +0200
+Subject: debloat: dmabuf
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ drivers/base/Kconfig      |  2 +-
+ drivers/dma-buf/Makefile  | 10 +++++++---
+ drivers/dma-buf/dma-buf.c |  4 +++-
+ kernel/sched/core.c       |  1 +
+ 4 files changed, 12 insertions(+), 5 deletions(-)
+
+--- a/drivers/base/Kconfig
++++ b/drivers/base/Kconfig
+@@ -179,7 +179,7 @@ config SOC_BUS
+ source "drivers/base/regmap/Kconfig"
+ 
+ config DMA_SHARED_BUFFER
+-	bool
++	tristate
+ 	default n
+ 	select IRQ_WORK
+ 	help
+--- a/drivers/dma-buf/Makefile
++++ b/drivers/dma-buf/Makefile
+@@ -1,9 +1,13 @@
+ # SPDX-License-Identifier: GPL-2.0-only
+-obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \
+-	 dma-resv.o seqno-fence.o
+-obj-$(CONFIG_SYNC_FILE)		+= sync_file.o
+-obj-$(CONFIG_SW_SYNC)		+= sw_sync.o sync_debug.o
+-obj-$(CONFIG_UDMABUF)		+= udmabuf.o
++obj-$(CONFIG_DMA_SHARED_BUFFER) := dma-shared-buffer.o
++
++dma-buf-objs-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \
++		  dma-resv.o seqno-fence.o
++dma-buf-objs-$(CONFIG_SYNC_FILE)	+= sync_file.o
++dma-buf-objs-$(CONFIG_SW_SYNC)		+= sw_sync.o sync_debug.o
++dma-buf-objs-$(CONFIG_UDMABUF)		+= udmabuf.o
++
++dma-shared-buffer-objs :=  $(dma-buf-objs-y)
+ 
+ dmabuf_selftests-y := \
+ 	selftest.o \
+--- a/drivers/dma-buf/dma-buf.c
++++ b/drivers/dma-buf/dma-buf.c
+@@ -1314,4 +1314,5 @@ static void __exit dma_buf_deinit(void)
+ 	dma_buf_uninit_debugfs();
+ 	kern_unmount(dma_buf_mnt);
+ }
+-__exitcall(dma_buf_deinit);
++module_exit(dma_buf_deinit);
++MODULE_LICENSE("GPL");
+--- a/kernel/sched/core.c
++++ b/kernel/sched/core.c
+@@ -2770,6 +2770,7 @@ int wake_up_state(struct task_struct *p,
+ {
+ 	return try_to_wake_up(p, state, 0);
+ }
++EXPORT_SYMBOL_GPL(wake_up_state);
+ 
+ /*
+  * Perform scheduler related setup for a newly forked process p.
+--- a/fs/d_path.c
++++ b/fs/d_path.c
+@@ -311,6 +311,7 @@ char *dynamic_dname(struct dentry *dentr
+ 	buffer += buflen - sz;
+ 	return memcpy(buffer, temp, sz);
+ }
++EXPORT_SYMBOL_GPL(dynamic_dname);
+ 
+ char *simple_dname(struct dentry *dentry, char *buffer, int buflen)
+ {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/910-kobject_uevent.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/910-kobject_uevent.patch
new file mode 100644
index 0000000..c4c41ca
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/910-kobject_uevent.patch
@@ -0,0 +1,32 @@
+From 0d37e6edc09c99e683dd91ca0e83bbc0df8477b3 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 16 Jul 2017 16:56:10 +0200
+Subject: lib: add uevent_next_seqnum()
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ include/linux/kobject.h |  5 +++++
+ lib/kobject_uevent.c    | 37 +++++++++++++++++++++++++++++++++++++
+ 2 files changed, 42 insertions(+)
+
+--- a/lib/kobject_uevent.c
++++ b/lib/kobject_uevent.c
+@@ -179,6 +179,18 @@ out:
+ 	return r;
+ }
+ 
++u64 uevent_next_seqnum(void)
++{
++	u64 seq;
++
++	mutex_lock(&uevent_sock_mutex);
++	seq = ++uevent_seqnum;
++	mutex_unlock(&uevent_sock_mutex);
++
++	return seq;
++}
++EXPORT_SYMBOL_GPL(uevent_next_seqnum);
++
+ /**
+  * kobject_synth_uevent - send synthetic uevent with arguments
+  *
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/911-kobject_add_broadcast_uevent.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/911-kobject_add_broadcast_uevent.patch
new file mode 100644
index 0000000..6f5e50d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/911-kobject_add_broadcast_uevent.patch
@@ -0,0 +1,76 @@
+From 0d37e6edc09c99e683dd91ca0e83bbc0df8477b3 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 16 Jul 2017 16:56:10 +0200
+Subject: lib: add uevent_next_seqnum()
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ include/linux/kobject.h |  5 +++++
+ lib/kobject_uevent.c    | 37 +++++++++++++++++++++++++++++++++++++
+ 2 files changed, 42 insertions(+)
+
+--- a/include/linux/kobject.h
++++ b/include/linux/kobject.h
+@@ -32,6 +32,8 @@
+ #define UEVENT_NUM_ENVP			32	/* number of env pointers */
+ #define UEVENT_BUFFER_SIZE		2048	/* buffer for the variables */
+ 
++struct sk_buff;
++
+ #ifdef CONFIG_UEVENT_HELPER
+ /* path to the userspace helper executed on an event */
+ extern char uevent_helper[];
+@@ -245,4 +247,7 @@ int kobject_synth_uevent(struct kobject
+ __printf(2, 3)
+ int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...);
+ 
++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
++		     gfp_t allocation);
++
+ #endif /* _KOBJECT_H_ */
+--- a/lib/kobject_uevent.c
++++ b/lib/kobject_uevent.c
+@@ -691,6 +691,43 @@ int add_uevent_var(struct kobj_uevent_en
+ EXPORT_SYMBOL_GPL(add_uevent_var);
+ 
+ #if defined(CONFIG_NET)
++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
++		     gfp_t allocation)
++{
++	struct uevent_sock *ue_sk;
++	int err = 0;
++
++	/* send netlink message */
++	mutex_lock(&uevent_sock_mutex);
++	list_for_each_entry(ue_sk, &uevent_sock_list, list) {
++		struct sock *uevent_sock = ue_sk->sk;
++		struct sk_buff *skb2;
++
++		skb2 = skb_clone(skb, allocation);
++		if (!skb2)
++			break;
++
++		err = netlink_broadcast(uevent_sock, skb2, pid, group,
++					allocation);
++		if (err)
++			break;
++	}
++	mutex_unlock(&uevent_sock_mutex);
++
++	kfree_skb(skb);
++	return err;
++}
++#else
++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
++		     gfp_t allocation)
++{
++	kfree_skb(skb);
++	return 0;
++}
++#endif
++EXPORT_SYMBOL_GPL(broadcast_uevent);
++
++#if defined(CONFIG_NET)
+ static int uevent_net_broadcast(struct sock *usk, struct sk_buff *skb,
+ 				struct netlink_ext_ack *extack)
+ {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/921-always-create-console-node-in-initramfs.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/921-always-create-console-node-in-initramfs.patch
new file mode 100644
index 0000000..e437579
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/921-always-create-console-node-in-initramfs.patch
@@ -0,0 +1,40 @@
+From 5d301596fdc72f6cb672f72eb3c66e7cddefb103 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 8 Jul 2017 08:26:02 +0200
+Subject: initramfs: always create console node
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ usr/gen_initramfs_list.sh | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- a/usr/gen_initramfs_list.sh
++++ b/usr/gen_initramfs_list.sh
+@@ -59,6 +59,18 @@ default_initramfs() {
+ 	EOF
+ }
+ 
++list_openwrt_initramfs() {
++	:
++}
++
++openwrt_initramfs() {
++	# make sure that /dev/console exists
++	cat <<-EOF >> ${output}
++		dir /dev 0755 0 0
++		nod /dev/console 0600 0 0 c 5 1
++	EOF
++}
++
+ filetype() {
+ 	local argv1="$1"
+ 
+@@ -180,6 +192,8 @@ dir_filelist() {
+ 	if [  "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then
+ 		${dep_list}print_mtime "$1"
+ 
++		${dep_list}openwrt_initramfs
++
+ 		echo "${dirlist}" | \
+ 		while read x; do
+ 			${dep_list}parse ${x}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/hack-5.4.inc b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/hack-5.4.inc
new file mode 100644
index 0000000..5376315
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/hack-5.4/hack-5.4.inc
@@ -0,0 +1,44 @@
+#patch hack-5.4 (come from openwrt/lede/target/linux/mediatek)
+SRC_URI_append = " \
+    file://204-module_strip.patch \
+    file://210-darwin_scripts_include.patch \
+    file://211-darwin-uuid-typedef-clash.patch \
+    file://212-tools_portability.patch \
+    file://214-spidev_h_portability.patch \
+    file://220-gc_sections.patch \
+    file://221-module_exports.patch \
+    file://230-openwrt_lzma_options.patch \
+    file://249-udp-tunnel-selection.patch \
+    file://250-netfilter_depends.patch \
+    file://251-sound_kconfig.patch \
+    file://259-regmap_dynamic.patch \
+    file://260-crypto_test_dependencies.patch \
+    file://260-lib-arc4-unhide.patch \
+    file://280-rfkill-stubs.patch \
+    file://300-MIPS-r4k_cache-use-more-efficient-cache-blast.patch \
+    file://301-mips_image_cmdline_hack.patch \
+    file://321-powerpc_crtsavres_prereq.patch \
+    file://400-unlock_mx25l6406e_with_4bit_block_protect.patch \
+    file://531-debloat_lzma.patch \
+    file://550-loop-Report-EOPNOTSUPP-properly.patch \
+    file://640-bridge-only-accept-EAP-locally.patch \
+    file://645-netfilter-connmark-introduce-set-dscpmark.patch \
+    file://647-netfilter-flow-acct.patch \
+    file://650-netfilter-add-xt_OFFLOAD-target.patch \
+    file://651-wireless_mesh_header.patch \
+    file://660-fq_codel_defaults.patch \
+    file://661-use_fq_codel_by_default.patch \
+    file://662-remove_pfifo_fast.patch \
+    file://700-swconfig_switch_drivers.patch \
+    file://703-add_vsc8504_support.patch \
+    file://710-net-dsa-mv88e6xxx-default-VID-1.patch \
+    file://711-net-dsa-mv88e6xxx-disable-ATU-violation.patch \
+    file://721-phy_packets.patch \
+    file://773-bgmac-add-srab-switch.patch \
+    file://901-debloat_sock_diag.patch \
+    file://902-debloat_proc.patch \
+    file://904-debloat_dma_buf.patch \
+    file://910-kobject_uevent.patch \
+    file://911-kobject_add_broadcast_uevent.patch \
+    file://921-always-create-console-node-in-initramfs.patch \
+    "
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/0931-w1-gpio-fix-problem-with-platfom-data-in-w1-gpio.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/0931-w1-gpio-fix-problem-with-platfom-data-in-w1-gpio.patch
new file mode 100644
index 0000000..33eb34c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/0931-w1-gpio-fix-problem-with-platfom-data-in-w1-gpio.patch
@@ -0,0 +1,26 @@
+From d9c8bc8c1408f3e8529db6e4e04017b4c579c342 Mon Sep 17 00:00:00 2001
+From: Pawel Dembicki <paweldembicki@gmail.com>
+Date: Sun, 18 Feb 2018 17:08:04 +0100
+Subject: [PATCH] w1: gpio: fix problem with platfom data in w1-gpio
+
+In devices, where fdt is used, is impossible to apply platform data
+without proper fdt node.
+
+This patch allow to use platform data in devices with fdt.
+
+Signed-off-by: Pawel Dembicki <paweldembicki@gmail.com>
+---
+ drivers/w1/masters/w1-gpio.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+--- a/drivers/w1/masters/w1-gpio.c
++++ b/drivers/w1/masters/w1-gpio.c
+@@ -76,7 +76,7 @@ static int w1_gpio_probe(struct platform
+ 	enum gpiod_flags gflags = GPIOD_OUT_LOW_OPEN_DRAIN;
+ 	int err;
+ 
+-	if (of_have_populated_dt()) {
++	if (of_have_populated_dt() && !dev_get_platdata(&pdev->dev)) {
+ 		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ 		if (!pdata)
+ 			return -ENOMEM;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/102-MIPS-only-process-negative-stack-offsets-on-stack-tr.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/102-MIPS-only-process-negative-stack-offsets-on-stack-tr.patch
new file mode 100644
index 0000000..4531941
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/102-MIPS-only-process-negative-stack-offsets-on-stack-tr.patch
@@ -0,0 +1,57 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 18 Apr 2018 10:50:05 +0200
+Subject: [PATCH] MIPS: only process negative stack offsets on stack traces
+
+Fixes endless back traces in cases where the compiler emits a stack
+pointer increase in a branch delay slot (probably for some form of
+function return).
+
+[    3.475442] BUG: MAX_STACK_TRACE_ENTRIES too low!
+[    3.480070] turning off the locking correctness validator.
+[    3.485521] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.14.34 #0
+[    3.491475] Stack : 00000000 00000000 00000000 00000000 80e0fce2 00000034 00000000 00000000
+[    3.499764]         87c3838c 80696377 8061047c 00000000 00000001 00000001 87c2d850 6534689f
+[    3.508059]         00000000 00000000 80e10000 00000000 00000000 000000cf 0000000f 00000000
+[    3.516353]         00000000 806a0000 00076891 00000000 00000000 00000000 ffffffff 00000000
+[    3.524648]         806c0000 00000004 80e10000 806a0000 00000003 80690000 00000000 80700000
+[    3.532942]         ...
+[    3.535362] Call Trace:
+[    3.537818] [<80010a48>] show_stack+0x58/0x100
+[    3.542207] [<804c2f78>] dump_stack+0xe8/0x170
+[    3.546613] [<80079f90>] save_trace+0xf0/0x110
+[    3.551010] [<8007b1ec>] mark_lock+0x33c/0x78c
+[    3.555413] [<8007bf48>] __lock_acquire+0x2ac/0x1a08
+[    3.560337] [<8007de60>] lock_acquire+0x64/0x8c
+[    3.564846] [<804e1570>] _raw_spin_lock_irqsave+0x54/0x78
+[    3.570186] [<801b618c>] kernfs_notify+0x94/0xac
+[    3.574770] [<801b7b10>] sysfs_notify+0x74/0xa0
+[    3.579257] [<801b618c>] kernfs_notify+0x94/0xac
+[    3.583839] [<801b7b10>] sysfs_notify+0x74/0xa0
+[    3.588329] [<801b618c>] kernfs_notify+0x94/0xac
+[    3.592911] [<801b7b10>] sysfs_notify+0x74/0xa0
+[    3.597401] [<801b618c>] kernfs_notify+0x94/0xac
+[    3.601983] [<801b7b10>] sysfs_notify+0x74/0xa0
+[    3.606473] [<801b618c>] kernfs_notify+0x94/0xac
+[    3.611055] [<801b7b10>] sysfs_notify+0x74/0xa0
+[    3.615545] [<801b618c>] kernfs_notify+0x94/0xac
+[    3.620125] [<801b7b10>] sysfs_notify+0x74/0xa0
+[    3.624619] [<801b618c>] kernfs_notify+0x94/0xac
+[    3.629197] [<801b7b10>] sysfs_notify+0x74/0xa0
+[    3.633691] [<801b618c>] kernfs_notify+0x94/0xac
+[    3.638269] [<801b7b10>] sysfs_notify+0x74/0xa0
+[    3.642763] [<801b618c>] kernfs_notify+0x94/0xac
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/arch/mips/kernel/process.c
++++ b/arch/mips/kernel/process.c
+@@ -365,6 +365,8 @@ static inline int is_sp_move_ins(union m
+ 
+ 	if (ip->i_format.opcode == addiu_op ||
+ 	    ip->i_format.opcode == daddiu_op) {
++		if (ip->i_format.simmediate > 0)
++			return 0;
+ 		*frame_size = -ip->i_format.simmediate;
+ 		return 1;
+ 	}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/103-MIPS-select-CPU_MIPS64-for-remaining-MIPS64-CPUs.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/103-MIPS-select-CPU_MIPS64-for-remaining-MIPS64-CPUs.patch
new file mode 100644
index 0000000..2960c24
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/103-MIPS-select-CPU_MIPS64-for-remaining-MIPS64-CPUs.patch
@@ -0,0 +1,37 @@
+From 31ca877744d95713e4925de542e1c686ab08a542 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Sat, 27 Feb 2021 13:20:24 +0100
+Subject: [PATCH] MIPS: select CPU_MIPS64 for remaining MIPS64 CPUs
+
+The CPU_MIPS64 and CPU_MIPS32 variables are supposed to be able to
+distinguish broadly between 64-bit and 32-bit MIPS CPUs. However, they
+weren't selected by the specialty CPUs, Octeon and Loongson, which meant
+it was possible to hit a weird state of:
+
+    MIPS=y, CONFIG_64BIT=y, CPU_MIPS64=n
+
+This commit rectifies the issue by having CPU_MIPS64 be selected when
+the missing Octeon or Loongson models are selected.
+
+Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+Cc: Ralf Baechle <ralf@linux-mips.org>
+Cc: George Cherian <gcherian@marvell.com>
+Cc: Huacai Chen <chenhuacai@kernel.org>
+Cc: Jiaxun Yang <jiaxun.yang@flygoat.com>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ arch/mips/Kconfig | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -2041,7 +2041,8 @@ config CPU_MIPS32
+ 
+ config CPU_MIPS64
+ 	bool
+-	default y if CPU_MIPS64_R1 || CPU_MIPS64_R2 || CPU_MIPS64_R6
++	default y if CPU_MIPS64_R1 || CPU_MIPS64_R2 || CPU_MIPS64_R6 || \
++		     CPU_LOONGSON64 || CPU_CAVIUM_OCTEON
+ 
+ #
+ # These indicate the revision of the architecture
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/110-ehci_hcd_ignore_oc.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/110-ehci_hcd_ignore_oc.patch
new file mode 100644
index 0000000..1d1e9dd
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/110-ehci_hcd_ignore_oc.patch
@@ -0,0 +1,79 @@
+From: Florian Fainelli <florian@openwrt.org>
+Subject: USB: EHCI: add ignore_oc flag to disable overcurrent checking
+
+This patch adds an ignore_oc flag which can be set by EHCI controller
+not supporting or wanting to disable overcurrent checking. The EHCI
+platform data in include/linux/usb/ehci_pdriver.h is also augmented to
+take advantage of this new flag.
+
+Signed-off-by: Florian Fainelli <florian@openwrt.org>
+---
+ drivers/usb/host/ehci-hcd.c      |    2 +-
+ drivers/usb/host/ehci-hub.c      |    4 ++--
+ drivers/usb/host/ehci-platform.c |    1 +
+ drivers/usb/host/ehci.h          |    1 +
+ include/linux/usb/ehci_pdriver.h |    1 +
+ 5 files changed, 6 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -660,7 +660,7 @@ static int ehci_run (struct usb_hcd *hcd
+ 		"USB %x.%x started, EHCI %x.%02x%s\n",
+ 		((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
+ 		temp >> 8, temp & 0xff,
+-		ignore_oc ? ", overcurrent ignored" : "");
++		(ignore_oc || ehci->ignore_oc) ? ", overcurrent ignored" : "");
+ 
+ 	ehci_writel(ehci, INTR_MASK,
+ 		    &ehci->regs->intr_enable); /* Turn On Interrupts */
+--- a/drivers/usb/host/ehci-hub.c
++++ b/drivers/usb/host/ehci-hub.c
+@@ -643,7 +643,7 @@ ehci_hub_status_data (struct usb_hcd *hc
+ 	 * always set, seem to clear PORT_OCC and PORT_CSC when writing to
+ 	 * PORT_POWER; that's surprising, but maybe within-spec.
+ 	 */
+-	if (!ignore_oc)
++	if (!ignore_oc && !ehci->ignore_oc)
+ 		mask = PORT_CSC | PORT_PEC | PORT_OCC;
+ 	else
+ 		mask = PORT_CSC | PORT_PEC;
+@@ -1013,7 +1013,7 @@ int ehci_hub_control(
+ 		if (temp & PORT_PEC)
+ 			status |= USB_PORT_STAT_C_ENABLE << 16;
+ 
+-		if ((temp & PORT_OCC) && !ignore_oc){
++		if ((temp & PORT_OCC) && (!ignore_oc && !ehci->ignore_oc)){
+ 			status |= USB_PORT_STAT_C_OVERCURRENT << 16;
+ 
+ 			/*
+--- a/drivers/usb/host/ehci-platform.c
++++ b/drivers/usb/host/ehci-platform.c
+@@ -325,6 +325,8 @@ static int ehci_platform_probe(struct pl
+ 		hcd->has_tt = 1;
+ 	if (pdata->reset_on_resume)
+ 		priv->reset_on_resume = true;
++	if (pdata->ignore_oc)
++		ehci->ignore_oc = 1;
+ 
+ #ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+ 	if (ehci->big_endian_mmio) {
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -219,6 +219,7 @@ struct ehci_hcd {			/* one per controlle
+ 	unsigned		need_oc_pp_cycle:1; /* MPC834X port power */
+ 	unsigned		imx28_write_fix:1; /* For Freescale i.MX28 */
+ 	unsigned		is_aspeed:1;
++	unsigned		ignore_oc:1;
+ 
+ 	/* required for usb32 quirk */
+ 	#define OHCI_CTRL_HCFS          (3 << 6)
+--- a/include/linux/usb/ehci_pdriver.h
++++ b/include/linux/usb/ehci_pdriver.h
+@@ -50,6 +50,7 @@ struct usb_ehci_pdata {
+ 	unsigned	no_io_watchdog:1;
+ 	unsigned	reset_on_resume:1;
+ 	unsigned	dma_mask_64:1;
++	unsigned	ignore_oc:1;
+ 
+ 	/* Turn on all power and clocks */
+ 	int (*power_on)(struct platform_device *pdev);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch
new file mode 100644
index 0000000..09e8267
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch
@@ -0,0 +1,82 @@
+From: Tobias Wolf <dev-NTEO@vplace.de>
+Subject: mm: Fix alloc_node_mem_map with ARCH_PFN_OFFSET calculation
+
+An rt288x (ralink) based router (Belkin F5D8235 v1) does not boot with any
+kernel beyond version 4.3 resulting in:
+
+BUG: Bad page state in process swapper  pfn:086ac
+
+bisect resulted in:
+
+a1c34a3bf00af2cede839879502e12dc68491ad5 is the first bad commit
+commit a1c34a3bf00af2cede839879502e12dc68491ad5
+Author: Laura Abbott <laura@labbott.name>
+Date:   Thu Nov 5 18:48:46 2015 -0800
+
+    mm: Don't offset memmap for flatmem
+
+    Srinivas Kandagatla reported bad page messages when trying to remove the
+    bottom 2MB on an ARM based IFC6410 board
+
+      BUG: Bad page state in process swapper  pfn:fffa8
+      page:ef7fb500 count:0 mapcount:0 mapping:  (null) index:0x0
+      flags: 0x96640253(locked|error|dirty|active|arch_1|reclaim|mlocked)
+      page dumped because: PAGE_FLAGS_CHECK_AT_FREE flag(s) set
+      bad because of flags:
+      flags: 0x200041(locked|active|mlocked)
+      Modules linked in:
+      CPU: 0 PID: 0 Comm: swapper Not tainted 3.19.0-rc3-00007-g412f9ba-dirty
+#816
+      Hardware name: Qualcomm (Flattened Device Tree)
+        unwind_backtrace
+        show_stack
+        dump_stack
+        bad_page
+        free_pages_prepare
+        free_hot_cold_page
+        __free_pages
+        free_highmem_page
+        mem_init
+        start_kernel
+      Disabling lock debugging due to kernel taint
+    [...]
+:040000 040000 2de013c372345fd471cd58f0553c9b38b0ef1cc4
+0a8156f848733dfa21e16c196dfb6c0a76290709 M      mm
+
+This fix for ARM does not account ARCH_PFN_OFFSET for mem_map as later used by
+page_to_pfn anymore.
+
+The following output was generated with two hacked in printk statements:
+
+printk("before %p vs. %p or %p\n", mem_map, mem_map - offset, mem_map -
+(pgdat->node_start_pfn - ARCH_PFN_OFFSET));
+		if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
+			mem_map -= offset + (pgdat->node_start_pfn - ARCH_PFN_OFFSET);
+printk("after %p\n", mem_map);
+
+Output:
+
+[    0.000000] before 8861b280 vs. 8861b280 or 8851b280
+[    0.000000] after 8851b280
+
+As seen in the first line mem_map with subtraction of offset does not equal the
+mem_map after subtraction of ARCH_PFN_OFFSET.
+
+After adding the offset of ARCH_PFN_OFFSET as well to mem_map as the
+previously calculated offset is zero for the named platform it is able to boot
+4.4 and 4.9-rc7 again.
+
+Signed-off-by: Tobias Wolf <dev-NTEO@vplace.de>
+---
+
+--- a/mm/page_alloc.c
++++ b/mm/page_alloc.c
+@@ -6886,7 +6886,7 @@ static void __ref alloc_node_mem_map(str
+ 		mem_map = NODE_DATA(0)->node_mem_map;
+ #if defined(CONFIG_HAVE_MEMBLOCK_NODE_MAP) || defined(CONFIG_FLATMEM)
+ 		if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
+-			mem_map -= offset;
++			mem_map -= offset + (pgdat->node_start_pfn - ARCH_PFN_OFFSET);
+ #endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
+ 	}
+ #endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/130-add-linux-spidev-compatible-si3210.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/130-add-linux-spidev-compatible-si3210.patch
new file mode 100644
index 0000000..eedb2bb
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/130-add-linux-spidev-compatible-si3210.patch
@@ -0,0 +1,18 @@
+From: Giuseppe Lippolis <giu.lippolis@gmail.com>
+Subject: Add the linux,spidev compatible in spidev Several device in ramips have this binding in the dts
+
+Signed-off-by: Giuseppe Lippolis <giu.lippolis@gmail.com>
+---
+ drivers/spi/spidev.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/spi/spidev.c
++++ b/drivers/spi/spidev.c
+@@ -678,6 +678,7 @@ static const struct of_device_id spidev_
+ 	{ .compatible = "lwn,bk4" },
+ 	{ .compatible = "dh,dhcom-board" },
+ 	{ .compatible = "menlo,m53cpld" },
++	{ .compatible = "siliconlabs,si3210" },
+ 	{},
+ };
+ MODULE_DEVICE_TABLE(of, spidev_dt_ids);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/140-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/140-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch
new file mode 100644
index 0000000..b9bb3f7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/140-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch
@@ -0,0 +1,62 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: jffs2: use .rename2 and add RENAME_WHITEOUT support
+
+It is required for renames on overlayfs
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/fs/jffs2/dir.c
++++ b/fs/jffs2/dir.c
+@@ -756,6 +756,24 @@ static int jffs2_mknod (struct inode *di
+ 	return ret;
+ }
+ 
++static int jffs2_whiteout (struct inode *old_dir, struct dentry *old_dentry)
++{
++	struct dentry *wh;
++	int err;
++
++	wh = d_alloc(old_dentry->d_parent, &old_dentry->d_name);
++	if (!wh)
++		return -ENOMEM;
++
++	err = jffs2_mknod(old_dir, wh, S_IFCHR | WHITEOUT_MODE,
++			  WHITEOUT_DEV);
++	if (err)
++		return err;
++
++	d_rehash(wh);
++	return 0;
++}
++
+ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
+ 			 struct inode *new_dir_i, struct dentry *new_dentry,
+ 			 unsigned int flags)
+@@ -766,7 +784,7 @@ static int jffs2_rename (struct inode *o
+ 	uint8_t type;
+ 	uint32_t now;
+ 
+-	if (flags & ~RENAME_NOREPLACE)
++	if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT))
+ 		return -EINVAL;
+ 
+ 	/* The VFS will check for us and prevent trying to rename a
+@@ -832,9 +850,14 @@ static int jffs2_rename (struct inode *o
+ 	if (d_is_dir(old_dentry) && !victim_f)
+ 		inc_nlink(new_dir_i);
+ 
+-	/* Unlink the original */
+-	ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
+-			      old_dentry->d_name.name, old_dentry->d_name.len, NULL, now);
++	if (flags & RENAME_WHITEOUT)
++		/* Replace with whiteout */
++		ret = jffs2_whiteout(old_dir_i, old_dentry);
++	else
++		/* Unlink the original */
++		ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
++				      old_dentry->d_name.name,
++				      old_dentry->d_name.len, NULL, now);
+ 
+ 	/* We don't touch inode->i_nlink */
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/141-jffs2-add-RENAME_EXCHANGE-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/141-jffs2-add-RENAME_EXCHANGE-support.patch
new file mode 100644
index 0000000..4b30bc7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/141-jffs2-add-RENAME_EXCHANGE-support.patch
@@ -0,0 +1,73 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: jffs2: add RENAME_EXCHANGE support
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/fs/jffs2/dir.c
++++ b/fs/jffs2/dir.c
+@@ -781,18 +781,31 @@ static int jffs2_rename (struct inode *o
+ 	int ret;
+ 	struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
+ 	struct jffs2_inode_info *victim_f = NULL;
++	struct inode *fst_inode = d_inode(old_dentry);
++	struct inode *snd_inode = d_inode(new_dentry);
+ 	uint8_t type;
+ 	uint32_t now;
+ 
+-	if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT))
++	if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT|RENAME_EXCHANGE))
+ 		return -EINVAL;
+ 
++	if ((flags & RENAME_EXCHANGE) && (old_dir_i != new_dir_i)) {
++		if (S_ISDIR(fst_inode->i_mode) && !S_ISDIR(snd_inode->i_mode)) {
++			inc_nlink(new_dir_i);
++			drop_nlink(old_dir_i);
++		}
++		else if (!S_ISDIR(fst_inode->i_mode) && S_ISDIR(snd_inode->i_mode)) {
++			drop_nlink(new_dir_i);
++			inc_nlink(old_dir_i);
++		}
++	}
++
+ 	/* The VFS will check for us and prevent trying to rename a
+ 	 * file over a directory and vice versa, but if it's a directory,
+ 	 * the VFS can't check whether the victim is empty. The filesystem
+ 	 * needs to do that for itself.
+ 	 */
+-	if (d_really_is_positive(new_dentry)) {
++	if (d_really_is_positive(new_dentry) && !(flags & RENAME_EXCHANGE)) {
+ 		victim_f = JFFS2_INODE_INFO(d_inode(new_dentry));
+ 		if (d_is_dir(new_dentry)) {
+ 			struct jffs2_full_dirent *fd;
+@@ -827,7 +840,7 @@ static int jffs2_rename (struct inode *o
+ 	if (ret)
+ 		return ret;
+ 
+-	if (victim_f) {
++	if (victim_f && !(flags & RENAME_EXCHANGE)) {
+ 		/* There was a victim. Kill it off nicely */
+ 		if (d_is_dir(new_dentry))
+ 			clear_nlink(d_inode(new_dentry));
+@@ -853,6 +866,12 @@ static int jffs2_rename (struct inode *o
+ 	if (flags & RENAME_WHITEOUT)
+ 		/* Replace with whiteout */
+ 		ret = jffs2_whiteout(old_dir_i, old_dentry);
++	else if (flags & RENAME_EXCHANGE)
++		/* Replace the original */
++		ret = jffs2_do_link(c, JFFS2_INODE_INFO(old_dir_i),
++				    d_inode(new_dentry)->i_ino, type,
++				    old_dentry->d_name.name, old_dentry->d_name.len,
++				    now);
+ 	else
+ 		/* Unlink the original */
+ 		ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
+@@ -884,7 +903,7 @@ static int jffs2_rename (struct inode *o
+ 		return ret;
+ 	}
+ 
+-	if (d_is_dir(old_dentry))
++	if (d_is_dir(old_dentry) && !(flags & RENAME_EXCHANGE))
+ 		drop_nlink(old_dir_i);
+ 
+ 	new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/150-bridge_allow_receiption_on_disabled_port.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/150-bridge_allow_receiption_on_disabled_port.patch
new file mode 100644
index 0000000..c63268e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/150-bridge_allow_receiption_on_disabled_port.patch
@@ -0,0 +1,45 @@
+From: Stephen Hemminger <stephen@networkplumber.org>
+Subject: bridge: allow receiption on disabled port
+
+When an ethernet device is enslaved to a bridge, and the bridge STP
+detects loss of carrier (or operational state down), then normally
+packet receiption is blocked.
+
+This breaks control applications like WPA which maybe expecting to
+receive packets to negotiate to bring link up. The bridge needs to
+block forwarding packets from these disabled ports, but there is no
+hard requirement to not allow local packet delivery.
+
+Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+
+--- a/net/bridge/br_input.c
++++ b/net/bridge/br_input.c
+@@ -190,6 +190,9 @@ static void __br_handle_local_finish(str
+ /* note: already called with rcu_read_lock */
+ static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
+ {
++	struct net_bridge_port *p = br_port_get_rcu(skb->dev);
++
++	if (p->state != BR_STATE_DISABLED)
+ 	__br_handle_local_finish(skb);
+ 
+ 	/* return 1 to signal the okfn() was called so it's ok to use the skb */
+@@ -340,6 +343,17 @@ rx_handler_result_t br_handle_frame(stru
+ 
+ forward:
+ 	switch (p->state) {
++	case BR_STATE_DISABLED:
++		if (ether_addr_equal(p->br->dev->dev_addr, dest))
++			skb->pkt_type = PACKET_HOST;
++
++		if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,
++			dev_net(skb->dev), NULL, skb, skb->dev, NULL,
++			br_handle_local_finish) == 1) {
++			return RX_HANDLER_PASS;
++		}
++		break;
++
+ 	case BR_STATE_FORWARDING:
+ 	case BR_STATE_LEARNING:
+ 		if (ether_addr_equal(p->br->dev->dev_addr, dest))
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/180-net-phy-at803x-add-support-for-AT8032.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/180-net-phy-at803x-add-support-for-AT8032.patch
new file mode 100644
index 0000000..9b88282
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/180-net-phy-at803x-add-support-for-AT8032.patch
@@ -0,0 +1,63 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: net: phy: at803x: add support for AT8032
+
+Like AT8030, this PHY needs the GPIO reset workaround
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/phy/at803x.c
++++ b/drivers/net/phy/at803x.c
+@@ -64,8 +64,10 @@
+ 
+ #define ATH8030_PHY_ID 0x004dd076
+ #define ATH8031_PHY_ID 0x004dd074
++#define ATH8032_PHY_ID 0x004dd023
+ #define ATH8035_PHY_ID 0x004dd072
+ #define AT803X_PHY_ID_MASK			0xffffffef
++#define AT8032_PHY_ID_MASK			0xffffffff
+ 
+ MODULE_DESCRIPTION("Atheros 803x PHY driver");
+ MODULE_AUTHOR("Matus Ujhelyi");
+@@ -314,7 +316,7 @@ static int at803x_config_intr(struct phy
+ static void at803x_link_change_notify(struct phy_device *phydev)
+ {
+ 	/*
+-	 * Conduct a hardware reset for AT8030 every time a link loss is
++	 * Conduct a hardware reset for AT8030/2 every time a link loss is
+ 	 * signalled. This is necessary to circumvent a hardware bug that
+ 	 * occurs when the cable is unplugged while TX packets are pending
+ 	 * in the FIFO. In such cases, the FIFO enters an error mode it
+@@ -471,6 +473,24 @@ static struct phy_driver at803x_driver[]
+ 	.aneg_done		= at803x_aneg_done,
+ 	.ack_interrupt		= &at803x_ack_interrupt,
+ 	.config_intr		= &at803x_config_intr,
++}, {
++	/* ATHEROS 8032 */
++	.phy_id			= ATH8032_PHY_ID,
++	.name			= "Atheros 8032 ethernet",
++	.phy_id_mask		= AT8032_PHY_ID_MASK,
++	.probe			= at803x_probe,
++	.config_init		= at803x_config_init,
++	.link_change_notify	= at803x_link_change_notify,
++	.set_wol		= at803x_set_wol,
++	.get_wol		= at803x_get_wol,
++	.suspend		= at803x_suspend,
++	.resume			= at803x_resume,
++	/* PHY_BASIC_FEATURES */
++	.read_status		= at803x_read_status,
++	.config_aneg		= genphy_config_aneg,
++	.read_status		= genphy_read_status,
++	.ack_interrupt		= at803x_ack_interrupt,
++	.config_intr		= at803x_config_intr,
+ } };
+ 
+ module_phy_driver(at803x_driver);
+@@ -478,6 +498,7 @@ module_phy_driver(at803x_driver);
+ static struct mdio_device_id __maybe_unused atheros_tbl[] = {
+ 	{ ATH8030_PHY_ID, AT803X_PHY_ID_MASK },
+ 	{ ATH8031_PHY_ID, AT803X_PHY_ID_MASK },
++	{ ATH8032_PHY_ID, AT8032_PHY_ID_MASK },
+ 	{ ATH8035_PHY_ID, AT803X_PHY_ID_MASK },
+ 	{ }
+ };
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/190-rtc-rs5c372-support_alarms_up_to_1_week.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/190-rtc-rs5c372-support_alarms_up_to_1_week.patch
new file mode 100644
index 0000000..13b79b5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/190-rtc-rs5c372-support_alarms_up_to_1_week.patch
@@ -0,0 +1,94 @@
+From: Daniel González Cabanelas <dgcbueu@gmail.com>
+Subject: [PATCH 1/2] rtc: rs5c372: support alarms up to 1 week
+
+The Ricoh R2221x, R2223x, RS5C372, RV5C387A chips can handle 1 week
+alarms.
+
+Read the "wday" alarm register and convert it to a date to support up 1
+week in our driver.
+
+Signed-off-by: Daniel González Cabanelas <dgcbueu@gmail.com>
+---
+ drivers/rtc/rtc-rs5c372.c | 48 ++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 42 insertions(+), 6 deletions(-)
+
+--- a/drivers/rtc/rtc-rs5c372.c
++++ b/drivers/rtc/rtc-rs5c372.c
+@@ -393,7 +393,9 @@ static int rs5c_read_alarm(struct device
+ {
+ 	struct i2c_client	*client = to_i2c_client(dev);
+ 	struct rs5c372		*rs5c = i2c_get_clientdata(client);
+-	int			status;
++	int			status, wday_offs;
++	struct rtc_time 	rtc;
++	unsigned long 		alarm_secs;
+ 
+ 	status = rs5c_get_regs(rs5c);
+ 	if (status < 0)
+@@ -403,6 +405,30 @@ static int rs5c_read_alarm(struct device
+ 	t->time.tm_sec = 0;
+ 	t->time.tm_min = bcd2bin(rs5c->regs[RS5C_REG_ALARM_A_MIN] & 0x7f);
+ 	t->time.tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C_REG_ALARM_A_HOURS]);
++	t->time.tm_wday = ffs(rs5c->regs[RS5C_REG_ALARM_A_WDAY] & 0x7f) - 1;
++
++	/* determine the day, month and year based on alarm wday, taking as a
++	 * reference the current time from the rtc
++	 */
++	status = rs5c372_rtc_read_time(dev, &rtc);
++	if (status < 0)
++		return status;
++
++	wday_offs = t->time.tm_wday - rtc.tm_wday;
++	alarm_secs = mktime64(rtc.tm_year + 1900,
++			      rtc.tm_mon + 1,
++			      rtc.tm_mday + wday_offs,
++			      t->time.tm_hour,
++			      t->time.tm_min,
++			      t->time.tm_sec);
++
++	if (wday_offs < 0 || (wday_offs == 0 &&
++			      (t->time.tm_hour < rtc.tm_hour ||
++			       (t->time.tm_hour == rtc.tm_hour &&
++				t->time.tm_min <= rtc.tm_min))))
++		alarm_secs += 7 * 86400;
++
++	rtc_time64_to_tm(alarm_secs, &t->time);
+ 
+ 	/* ... and status */
+ 	t->enabled = !!(rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE);
+@@ -417,12 +443,20 @@ static int rs5c_set_alarm(struct device
+ 	struct rs5c372		*rs5c = i2c_get_clientdata(client);
+ 	int			status, addr, i;
+ 	unsigned char		buf[3];
++	struct rtc_time 	rtc_tm;
++	unsigned long 		rtc_secs, alarm_secs;
+ 
+-	/* only handle up to 24 hours in the future, like RTC_ALM_SET */
+-	if (t->time.tm_mday != -1
+-			|| t->time.tm_mon != -1
+-			|| t->time.tm_year != -1)
++	/* chip only can handle alarms up to one week in the future*/
++	status = rs5c372_rtc_read_time(dev, &rtc_tm);
++	if (status)
++		return status;
++	rtc_secs = rtc_tm_to_time64(&rtc_tm);
++	alarm_secs = rtc_tm_to_time64(&t->time);
++	if (alarm_secs >= rtc_secs + 7 * 86400) {
++		dev_err(dev, "%s: alarm maximum is one week in the future (%d)\n",
++			__func__, status);
+ 		return -EINVAL;
++	}
+ 
+ 	/* REVISIT: round up tm_sec */
+ 
+@@ -443,7 +477,9 @@ static int rs5c_set_alarm(struct device
+ 	/* set alarm */
+ 	buf[0] = bin2bcd(t->time.tm_min);
+ 	buf[1] = rs5c_hr2reg(rs5c, t->time.tm_hour);
+-	buf[2] = 0x7f;	/* any/all days */
++	/* each bit is the day of the week, 0x7f means all days */
++	buf[2] = (t->time.tm_wday >= 0 && t->time.tm_wday < 7) ?
++		  BIT(t->time.tm_wday) : 0x7f;
+ 
+ 	for (i = 0; i < sizeof(buf); i++) {
+ 		addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch
new file mode 100644
index 0000000..7e9d0e6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch
@@ -0,0 +1,70 @@
+From: Daniel González Cabanelas <dgcbueu@gmail.com>
+Subject: [PATCH 2/2] rtc: rs5c372: let the alarm to be used as wakeup source
+
+Currently there is no use for the interrupts on the rs5c372 RTC and the
+wakealarm isn't enabled. There are some devices like NASes which use this
+RTC to wake up from the power off state when the INTR pin is activated by
+the alarm clock.
+
+Enable the alarm and let to be used as a wakeup source.
+
+Tested on a Buffalo LS421DE NAS.
+
+Signed-off-by: Daniel González Cabanelas <dgcbueu@gmail.com>
+---
+ drivers/rtc/rtc-rs5c372.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+--- a/drivers/rtc/rtc-rs5c372.c
++++ b/drivers/rtc/rtc-rs5c372.c
+@@ -654,6 +654,7 @@ static int rs5c372_probe(struct i2c_clie
+ 	int err = 0;
+ 	int smbus_mode = 0;
+ 	struct rs5c372 *rs5c372;
++	bool rs5c372_can_wakeup_device = false;
+ 
+ 	dev_dbg(&client->dev, "%s\n", __func__);
+ 
+@@ -689,6 +690,12 @@ static int rs5c372_probe(struct i2c_clie
+ 	else
+ 		rs5c372->type = id->driver_data;
+ 
++#ifdef CONFIG_OF
++	if(of_property_read_bool(client->dev.of_node,
++					      "wakeup-source"))
++		rs5c372_can_wakeup_device = true;
++#endif
++
+ 	/* we read registers 0x0f then 0x00-0x0f; skip the first one */
+ 	rs5c372->regs = &rs5c372->buf[1];
+ 	rs5c372->smbus = smbus_mode;
+@@ -722,6 +729,8 @@ static int rs5c372_probe(struct i2c_clie
+ 		goto exit;
+ 	}
+ 
++	rs5c372->has_irq = 1;
++
+ 	/* if the oscillator lost power and no other software (like
+ 	 * the bootloader) set it up, do it here.
+ 	 *
+@@ -748,6 +757,10 @@ static int rs5c372_probe(struct i2c_clie
+ 			);
+ 
+ 	/* REVISIT use client->irq to register alarm irq ... */
++	if (rs5c372_can_wakeup_device) {
++		device_init_wakeup(&client->dev, true);
++	}
++
+ 	rs5c372->rtc = devm_rtc_device_register(&client->dev,
+ 					rs5c372_driver.driver.name,
+ 					&rs5c372_rtc_ops, THIS_MODULE);
+@@ -761,6 +774,9 @@ static int rs5c372_probe(struct i2c_clie
+ 	if (err)
+ 		goto exit;
+ 
++	/* the rs5c372 alarm only supports a minute accuracy */
++	rs5c372->rtc->uie_unsupported = 1;
++
+ 	return 0;
+ 
+ exit:
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/201-extra_optimization.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/201-extra_optimization.patch
new file mode 100644
index 0000000..c606487
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/201-extra_optimization.patch
@@ -0,0 +1,31 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: Upgrade to Linux 2.6.19
+
+- Includes large parts of the patch from #1021 by dpalffy
+- Includes RB532 NAND driver changes by n0-1
+
+[john@phrozen.org: feix will add this to his upstream queue]
+
+lede-commit: bff468813f78f81e36ebb2a3f4354de7365e640f
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ Makefile | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/Makefile
++++ b/Makefile
+@@ -719,11 +719,11 @@ KBUILD_CFLAGS	+= $(call cc-disable-warni
+ KBUILD_CFLAGS	+= $(call cc-disable-warning, address-of-packed-member)
+ 
+ ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE
+-KBUILD_CFLAGS += -O2
++KBUILD_CFLAGS += -O2 $(EXTRA_OPTIMIZATION)
+ else ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3
+-KBUILD_CFLAGS += -O3
++KBUILD_CFLAGS += -O3 $(EXTRA_OPTIMIZATION)
+ else ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
+-KBUILD_CFLAGS += -Os
++KBUILD_CFLAGS += -Os -fno-reorder-blocks -fno-tree-ch $(EXTRA_OPTIMIZATION)
+ endif
+ 
+ # Tell gcc to never replace conditional load with a non-conditional one
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/203-kallsyms_uncompressed.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/203-kallsyms_uncompressed.patch
new file mode 100644
index 0000000..68a2d4d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/203-kallsyms_uncompressed.patch
@@ -0,0 +1,119 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: kernel: add a config option for keeping the kallsyms table uncompressed, saving ~9kb kernel size after lzma on ar71xx
+
+[john@phrozen.org: added to my upstream queue 30.12.2016]
+lede-commit: e0e3509b5ce2ccf93d4d67ea907613f5f7ec2eed
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ init/Kconfig            | 11 +++++++++++
+ kernel/kallsyms.c       |  8 ++++++++
+ scripts/kallsyms.c      | 12 ++++++++++++
+ scripts/link-vmlinux.sh |  4 ++++
+ 4 files changed, 35 insertions(+)
+
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1280,6 +1280,17 @@ config SYSCTL_ARCH_UNALIGN_ALLOW
+ 	  the unaligned access emulation.
+ 	  see arch/parisc/kernel/unaligned.c for reference
+ 
++config KALLSYMS_UNCOMPRESSED
++	bool "Keep kallsyms uncompressed"
++	depends on KALLSYMS
++	help
++		Normally kallsyms contains compressed symbols (using a token table),
++		reducing the uncompressed kernel image size. Keeping the symbol table
++		uncompressed significantly improves the size of this part in compressed
++		kernel images.
++
++		Say N unless you need compressed kernel images to be small.
++
+ config HAVE_PCSPKR_PLATFORM
+ 	bool
+ 
+--- a/kernel/kallsyms.c
++++ b/kernel/kallsyms.c
+@@ -75,6 +75,11 @@ static unsigned int kallsyms_expand_symb
+ 	 * For every byte on the compressed symbol data, copy the table
+ 	 * entry for that byte.
+ 	 */
++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
++	memcpy(result, data + 1, len - 1);
++	result += len - 1;
++	len = 0;
++#endif
+ 	while (len) {
+ 		tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
+ 		data++;
+@@ -107,6 +112,9 @@ tail:
+  */
+ static char kallsyms_get_symbol_type(unsigned int off)
+ {
++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
++	return kallsyms_names[off + 1];
++#endif
+ 	/*
+ 	 * Get just the first code, look it up in the token table,
+ 	 * and return the first char from this token.
+--- a/scripts/kallsyms.c
++++ b/scripts/kallsyms.c
+@@ -59,6 +59,7 @@ static struct addr_range percpu_range =
+ static struct sym_entry *table;
+ static unsigned int table_size, table_cnt;
+ static int all_symbols = 0;
++static int uncompressed = 0;
+ static int absolute_percpu = 0;
+ static int base_relative = 0;
+ 
+@@ -440,6 +441,9 @@ static void write_src(void)
+ 
+ 	free(markers);
+ 
++	if (uncompressed)
++		return;
++
+ 	output_label("kallsyms_token_table");
+ 	off = 0;
+ 	for (i = 0; i < 256; i++) {
+@@ -500,6 +504,9 @@ static void *find_token(unsigned char *s
+ {
+ 	int i;
+ 
++	if (uncompressed)
++		return NULL;
++
+ 	for (i = 0; i < len - 1; i++) {
+ 		if (str[i] == token[0] && str[i+1] == token[1])
+ 			return &str[i];
+@@ -572,6 +579,9 @@ static void optimize_result(void)
+ {
+ 	int i, best;
+ 
++	if (uncompressed)
++		return;
++
+ 	/* using the '\0' symbol last allows compress_symbols to use standard
+ 	 * fast string functions */
+ 	for (i = 255; i >= 0; i--) {
+@@ -751,6 +761,8 @@ int main(int argc, char **argv)
+ 				absolute_percpu = 1;
+ 			else if (strcmp(argv[i], "--base-relative") == 0)
+ 				base_relative = 1;
++			else if (strcmp(argv[i], "--uncompressed") == 0)
++				uncompressed = 1;
+ 			else
+ 				usage();
+ 		}
+--- a/scripts/link-vmlinux.sh
++++ b/scripts/link-vmlinux.sh
+@@ -160,6 +160,10 @@ kallsyms()
+ 		kallsymopt="${kallsymopt} --base-relative"
+ 	fi
+ 
++	if [ -n "${CONFIG_KALLSYMS_UNCOMPRESSED}" ]; then
++		kallsymopt="${kallsymopt} --uncompressed"
++	fi
++
+ 	local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL}               \
+ 		      ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}"
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/205-backtrace_module_info.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/205-backtrace_module_info.patch
new file mode 100644
index 0000000..6048c25
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/205-backtrace_module_info.patch
@@ -0,0 +1,41 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: kernel: when KALLSYMS is disabled, print module address + size for matching backtrace entries
+
+[john@phrozen.org: felix will add this to his upstream queue]
+
+lede-commit 53827cdc824556cda910b23ce5030c363b8f1461
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ lib/vsprintf.c | 15 +++++++++++----
+ 1 file changed, 11 insertions(+), 4 deletions(-)
+
+--- a/lib/vsprintf.c
++++ b/lib/vsprintf.c
+@@ -940,8 +940,10 @@ char *symbol_string(char *buf, char *end
+ 		    struct printf_spec spec, const char *fmt)
+ {
+ 	unsigned long value;
+-#ifdef CONFIG_KALLSYMS
+ 	char sym[KSYM_SYMBOL_LEN];
++#ifndef CONFIG_KALLSYMS
++	struct module *mod;
++	int len;
+ #endif
+ 
+ 	if (fmt[1] == 'R')
+@@ -958,8 +960,14 @@ char *symbol_string(char *buf, char *end
+ 
+ 	return string_nocheck(buf, end, sym, spec);
+ #else
+-	return special_hex_number(buf, end, value, sizeof(void *));
++	len = snprintf(sym, sizeof(sym), "0x%lx", value);
++	mod = __module_address(value);
++	if (mod)
++		snprintf(sym + len, sizeof(sym) - len, " [%s@%p+0x%x]",
++			 mod->name, mod->core_layout.base,
++			 mod->core_layout.size);
+ #endif
++	return string(buf, end, sym, spec);
+ }
+ 
+ static const struct printf_spec default_str_spec = {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/240-remove-unsane-filenames-from-deps_initramfs-list.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/240-remove-unsane-filenames-from-deps_initramfs-list.patch
new file mode 100644
index 0000000..7d890d3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/240-remove-unsane-filenames-from-deps_initramfs-list.patch
@@ -0,0 +1,47 @@
+From: Gabor Juhos <juhosg@openwrt.org>
+Subject: usr: sanitize deps_initramfs list
+
+If any filename in the intramfs dependency
+list contains a colon, that causes a kernel
+build error like this:
+
+/devel/openwrt/build_dir/linux-ar71xx_generic/linux-3.6.6/usr/Makefile:58: *** multiple target patterns.  Stop.
+make[5]: *** [usr] Error 2
+
+Fix it by removing such filenames from the
+deps_initramfs list.
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ usr/Makefile | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/usr/Makefile
++++ b/usr/Makefile
+@@ -42,21 +42,23 @@ ifneq ($(wildcard $(obj)/$(datafile_d_y)
+ 	include $(obj)/$(datafile_d_y)
+ endif
+ 
++deps_initramfs_sane := $(foreach v,$(deps_initramfs),$(if $(findstring :,$(v)),,$(v)))
++
+ quiet_cmd_initfs = GEN     $@
+       cmd_initfs = $(initramfs) -o $@ $(ramfs-args) $(ramfs-input)
+ 
+ targets := $(datafile_y)
+ 
+ # do not try to update files included in initramfs
+-$(deps_initramfs): ;
++$(deps_initramfs_sane): ;
+ 
+-$(deps_initramfs): klibcdirs
++$(deps_initramfs_sane): klibcdirs
+ # We rebuild initramfs_data.cpio if:
+ # 1) Any included file is newer than initramfs_data.cpio
+ # 2) There are changes in which files are included (added or deleted)
+ # 3) If gen_init_cpio are newer than initramfs_data.cpio
+ # 4) Arguments to gen_initramfs.sh changes
+-$(obj)/$(datafile_y): $(obj)/gen_init_cpio $(deps_initramfs) klibcdirs
++$(obj)/$(datafile_y): $(obj)/gen_init_cpio $(deps_initramfs_sane) klibcdirs
+ 	$(Q)$(initramfs) -l $(ramfs-input) > $(obj)/$(datafile_d_y)
+ 	$(call if_changed,initfs)
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/261-enable_wilink_platform_without_drivers.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/261-enable_wilink_platform_without_drivers.patch
new file mode 100644
index 0000000..c4cf2cc
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/261-enable_wilink_platform_without_drivers.patch
@@ -0,0 +1,20 @@
+From: Imre Kaloz <kaloz@openwrt.org>
+Subject: [PATCH] hack: net: wireless: make the wl12xx glue code available with
+ compat-wireless, too
+
+Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
+---
+ drivers/net/wireless/ti/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/ti/Kconfig
++++ b/drivers/net/wireless/ti/Kconfig
+@@ -20,7 +20,7 @@ source "drivers/net/wireless/ti/wlcore/K
+ 
+ config WILINK_PLATFORM_DATA
+ 	bool "TI WiLink platform data"
+-	depends on WLCORE_SDIO || WL1251_SDIO
++	depends on WLCORE_SDIO || WL1251_SDIO || ARCH_OMAP2PLUS
+ 	default y
+ 	---help---
+ 	Small platform data bit needed to pass data to the sdio modules.
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/270-platform-mikrotik-build-bits.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/270-platform-mikrotik-build-bits.patch
new file mode 100644
index 0000000..df738ef
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/270-platform-mikrotik-build-bits.patch
@@ -0,0 +1,31 @@
+From c2deb5ef01a0ef09088832744cbace9e239a6ee0 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Thibaut=20VAR=C3=88NE?= <hacks@slashdirt.org>
+Date: Sat, 28 Mar 2020 12:11:50 +0100
+Subject: [PATCH] generic: platform/mikrotik build bits (5.4)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch adds platform/mikrotik kernel build bits
+
+Signed-off-by: Thibaut VARÈNE <hacks@slashdirt.org>
+---
+ drivers/platform/Kconfig  | 2 ++
+ drivers/platform/Makefile | 1 +
+ 2 files changed, 3 insertions(+)
+
+--- a/drivers/platform/Kconfig
++++ b/drivers/platform/Kconfig
+@@ -13,3 +13,5 @@ source "drivers/platform/chrome/Kconfig"
+ source "drivers/platform/mellanox/Kconfig"
+ 
+ source "drivers/platform/olpc/Kconfig"
++
++source "drivers/platform/mikrotik/Kconfig"
+--- a/drivers/platform/Makefile
++++ b/drivers/platform/Makefile
+@@ -9,3 +9,4 @@ obj-$(CONFIG_MIPS)		+= mips/
+ obj-$(CONFIG_OLPC_EC)		+= olpc/
+ obj-$(CONFIG_GOLDFISH)		+= goldfish/
+ obj-$(CONFIG_CHROME_PLATFORMS)	+= chrome/
++obj-$(CONFIG_MIKROTIK)		+= mikrotik/
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/300-mips_expose_boot_raw.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/300-mips_expose_boot_raw.patch
new file mode 100644
index 0000000..b8a9018
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/300-mips_expose_boot_raw.patch
@@ -0,0 +1,40 @@
+From: Mark Miller <mark@mirell.org>
+Subject: mips: expose CONFIG_BOOT_RAW
+
+This exposes the CONFIG_BOOT_RAW symbol in Kconfig. This is needed on
+certain Broadcom chipsets running CFE in order to load the kernel.
+
+Signed-off-by: Mark Miller <mark@mirell.org>
+Acked-by: Rob Landley <rob@landley.net>
+---
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -1072,9 +1072,6 @@ config FW_ARC
+ config ARCH_MAY_HAVE_PC_FDC
+ 	bool
+ 
+-config BOOT_RAW
+-	bool
+-
+ config CEVT_BCM1480
+ 	bool
+ 
+@@ -3048,6 +3045,18 @@ choice
+ 		bool "Extend builtin kernel arguments with bootloader arguments"
+ endchoice
+ 
++config BOOT_RAW
++	bool "Enable the kernel to be executed from the load address"
++	default n
++	help
++	 Allow the kernel to be executed from the load address for
++	 bootloaders which cannot read the ELF format. This places
++	 a jump to start_kernel at the load address.
++
++	 If unsure, say N.
++
++
++
+ endmenu
+ 
+ config LOCKDEP_SUPPORT
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/302-mips_no_branch_likely.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/302-mips_no_branch_likely.patch
new file mode 100644
index 0000000..bf1b489
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/302-mips_no_branch_likely.patch
@@ -0,0 +1,22 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: mips: use -mno-branch-likely for kernel and userspace
+
+saves ~11k kernel size after lzma and ~12k squashfs size in the
+
+lede-commit: 41a039f46450ffae9483d6216422098669da2900
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ arch/mips/Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -92,7 +92,7 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
+ # machines may also.  Since BFD is incredibly buggy with respect to
+ # crossformat linking we rely on the elf2ecoff tool for format conversion.
+ #
+-cflags-y			+= -G 0 -mno-abicalls -fno-pic -pipe
++cflags-y			+= -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
+ cflags-y			+= -msoft-float
+ LDFLAGS_vmlinux			+= -G 0 -static -n -nostdlib
+ KBUILD_AFLAGS_MODULE		+= -mlong-calls
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/305-mips_module_reloc.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/305-mips_module_reloc.patch
new file mode 100644
index 0000000..40a219f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/305-mips_module_reloc.patch
@@ -0,0 +1,371 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: mips: replace -mlong-calls with -mno-long-calls to make function calls faster in kernel modules to achieve this, try to
+
+lede-commit: 3b3d64743ba2a874df9d70cd19e242205b0a788c
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ arch/mips/Makefile             |   5 +
+ arch/mips/include/asm/module.h |   5 +
+ arch/mips/kernel/module.c      | 279 ++++++++++++++++++++++++++++++++++++++++-
+ 3 files changed, 284 insertions(+), 5 deletions(-)
+
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -95,8 +95,18 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
+ cflags-y			+= -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
+ cflags-y			+= -msoft-float
+ LDFLAGS_vmlinux			+= -G 0 -static -n -nostdlib
++ifdef CONFIG_64BIT
+ KBUILD_AFLAGS_MODULE		+= -mlong-calls
+ KBUILD_CFLAGS_MODULE		+= -mlong-calls
++else
++  ifdef CONFIG_DYNAMIC_FTRACE
++    KBUILD_AFLAGS_MODULE	+= -mlong-calls
++    KBUILD_CFLAGS_MODULE	+= -mlong-calls
++  else
++    KBUILD_AFLAGS_MODULE	+= -mno-long-calls
++    KBUILD_CFLAGS_MODULE	+= -mno-long-calls
++  endif
++endif
+ 
+ ifeq ($(CONFIG_RELOCATABLE),y)
+ LDFLAGS_vmlinux			+= --emit-relocs
+--- a/arch/mips/include/asm/module.h
++++ b/arch/mips/include/asm/module.h
+@@ -12,6 +12,11 @@ struct mod_arch_specific {
+ 	const struct exception_table_entry *dbe_start;
+ 	const struct exception_table_entry *dbe_end;
+ 	struct mips_hi16 *r_mips_hi16_list;
++
++	void *phys_plt_tbl;
++	void *virt_plt_tbl;
++	unsigned int phys_plt_offset;
++	unsigned int virt_plt_offset;
+ };
+ 
+ typedef uint8_t Elf64_Byte;		/* Type for a 8-bit quantity.  */
+--- a/arch/mips/kernel/module.c
++++ b/arch/mips/kernel/module.c
+@@ -32,14 +32,221 @@ struct mips_hi16 {
+ static LIST_HEAD(dbe_list);
+ static DEFINE_SPINLOCK(dbe_lock);
+ 
+-#ifdef MODULE_START
++/*
++ * Get the potential max trampolines size required of the init and
++ * non-init sections. Only used if we cannot find enough contiguous
++ * physically mapped memory to put the module into.
++ */
++static unsigned int
++get_plt_size(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
++             const char *secstrings, unsigned int symindex, bool is_init)
++{
++	unsigned long ret = 0;
++	unsigned int i, j;
++	Elf_Sym *syms;
++
++	/* Everything marked ALLOC (this includes the exported symbols) */
++	for (i = 1; i < hdr->e_shnum; ++i) {
++		unsigned int info = sechdrs[i].sh_info;
++
++		if (sechdrs[i].sh_type != SHT_REL
++		    && sechdrs[i].sh_type != SHT_RELA)
++			continue;
++
++		/* Not a valid relocation section? */
++		if (info >= hdr->e_shnum)
++			continue;
++
++		/* Don't bother with non-allocated sections */
++		if (!(sechdrs[info].sh_flags & SHF_ALLOC))
++			continue;
++
++		/* If it's called *.init*, and we're not init, we're
++                   not interested */
++		if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0)
++		    != is_init)
++			continue;
++
++		syms = (Elf_Sym *) sechdrs[symindex].sh_addr;
++		if (sechdrs[i].sh_type == SHT_REL) {
++			Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr;
++			unsigned int size = sechdrs[i].sh_size / sizeof(*rel);
++
++			for (j = 0; j < size; ++j) {
++				Elf_Sym *sym;
++
++				if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26)
++					continue;
++
++				sym = syms + ELF_MIPS_R_SYM(rel[j]);
++				if (!is_init && sym->st_shndx != SHN_UNDEF)
++					continue;
++
++				ret += 4 * sizeof(int);
++			}
++		} else {
++			Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr;
++			unsigned int size = sechdrs[i].sh_size / sizeof(*rela);
++
++			for (j = 0; j < size; ++j) {
++				Elf_Sym *sym;
++
++				if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26)
++					continue;
++
++				sym = syms + ELF_MIPS_R_SYM(rela[j]);
++				if (!is_init && sym->st_shndx != SHN_UNDEF)
++					continue;
++
++				ret += 4 * sizeof(int);
++			}
++		}
++	}
++
++	return ret;
++}
++
++#ifndef MODULE_START
++static void *alloc_phys(unsigned long size)
++{
++	unsigned order;
++	struct page *page;
++	struct page *p;
++
++	size = PAGE_ALIGN(size);
++	order = get_order(size);
++
++	page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN |
++			__GFP_THISNODE, order);
++	if (!page)
++		return NULL;
++
++	split_page(page, order);
++
++	/* mark all pages except for the last one */
++	for (p = page; p + 1 < page + (size >> PAGE_SHIFT); ++p)
++		set_bit(PG_owner_priv_1, &p->flags);
++
++	for (p = page + (size >> PAGE_SHIFT); p < page + (1 << order); ++p)
++		__free_page(p);
++
++	return page_address(page);
++}
++#endif
++
++static void free_phys(void *ptr)
++{
++	struct page *page;
++	bool free;
++
++	page = virt_to_page(ptr);
++	do {
++		free = test_and_clear_bit(PG_owner_priv_1, &page->flags);
++		__free_page(page);
++		page++;
++	} while (free);
++}
++
++
+ void *module_alloc(unsigned long size)
+ {
++#ifdef MODULE_START
+ 	return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END,
+ 				GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE,
+ 				__builtin_return_address(0));
++#else
++	void *ptr;
++
++	if (size == 0)
++		return NULL;
++
++	ptr = alloc_phys(size);
++
++	/* If we failed to allocate physically contiguous memory,
++	 * fall back to regular vmalloc. The module loader code will
++	 * create jump tables to handle long jumps */
++	if (!ptr)
++		return vmalloc(size);
++
++	return ptr;
++#endif
+ }
++
++static inline bool is_phys_addr(void *ptr)
++{
++#ifdef CONFIG_64BIT
++	return (KSEGX((unsigned long)ptr) == CKSEG0);
++#else
++	return (KSEGX(ptr) == KSEG0);
+ #endif
++}
++
++/* Free memory returned from module_alloc */
++void module_memfree(void *module_region)
++{
++	if (is_phys_addr(module_region))
++		free_phys(module_region);
++	else
++		vfree(module_region);
++}
++
++static void *__module_alloc(int size, bool phys)
++{
++	void *ptr;
++
++	if (phys)
++		ptr = kmalloc(size, GFP_KERNEL);
++	else
++		ptr = vmalloc(size);
++	return ptr;
++}
++
++static void __module_free(void *ptr)
++{
++	if (is_phys_addr(ptr))
++		kfree(ptr);
++	else
++		vfree(ptr);
++}
++
++int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
++			      char *secstrings, struct module *mod)
++{
++	unsigned int symindex = 0;
++	unsigned int core_size, init_size;
++	int i;
++
++	mod->arch.phys_plt_offset = 0;
++	mod->arch.virt_plt_offset = 0;
++	mod->arch.phys_plt_tbl = NULL;
++	mod->arch.virt_plt_tbl = NULL;
++
++	if (IS_ENABLED(CONFIG_64BIT))
++		return 0;
++
++	for (i = 1; i < hdr->e_shnum; i++)
++		if (sechdrs[i].sh_type == SHT_SYMTAB)
++			symindex = i;
++
++	core_size = get_plt_size(hdr, sechdrs, secstrings, symindex, false);
++	init_size = get_plt_size(hdr, sechdrs, secstrings, symindex, true);
++
++	if ((core_size + init_size) == 0)
++		return 0;
++
++	mod->arch.phys_plt_tbl = __module_alloc(core_size + init_size, 1);
++	if (!mod->arch.phys_plt_tbl)
++		return -ENOMEM;
++
++	mod->arch.virt_plt_tbl = __module_alloc(core_size + init_size, 0);
++	if (!mod->arch.virt_plt_tbl) {
++		__module_free(mod->arch.phys_plt_tbl);
++		mod->arch.phys_plt_tbl = NULL;
++		return -ENOMEM;
++	}
++
++	return 0;
++}
+ 
+ static int apply_r_mips_none(struct module *me, u32 *location,
+ 			     u32 base, Elf_Addr v, bool rela)
+@@ -55,9 +262,40 @@ static int apply_r_mips_32(struct module
+ 	return 0;
+ }
+ 
++static Elf_Addr add_plt_entry_to(unsigned *plt_offset,
++				 void *start, Elf_Addr v)
++{
++	unsigned *tramp = start + *plt_offset;
++	*plt_offset += 4 * sizeof(int);
++
++	/* adjust carry for addiu */
++	if (v & 0x00008000)
++		v += 0x10000;
++
++	tramp[0] = 0x3c190000 | (v >> 16);      /* lui t9, hi16 */
++	tramp[1] = 0x27390000 | (v & 0xffff);   /* addiu t9, t9, lo16 */
++	tramp[2] = 0x03200008;                  /* jr t9 */
++	tramp[3] = 0x00000000;                  /* nop */
++
++	return (Elf_Addr) tramp;
++}
++
++static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v)
++{
++	if (is_phys_addr(location))
++		return add_plt_entry_to(&me->arch.phys_plt_offset,
++				me->arch.phys_plt_tbl, v);
++	else
++		return add_plt_entry_to(&me->arch.virt_plt_offset,
++				me->arch.virt_plt_tbl, v);
++
++}
++
+ static int apply_r_mips_26(struct module *me, u32 *location,
+ 			   u32 base, Elf_Addr v, bool rela)
+ {
++	u32 ofs = base & 0x03ffffff;
++
+ 	if (v % 4) {
+ 		pr_err("module %s: dangerous R_MIPS_26 relocation\n",
+ 		       me->name);
+@@ -65,13 +303,17 @@ static int apply_r_mips_26(struct module
+ 	}
+ 
+ 	if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
+-		pr_err("module %s: relocation overflow\n",
+-		       me->name);
+-		return -ENOEXEC;
++		v = add_plt_entry(me, location, v + (ofs << 2));
++		if (!v) {
++			pr_err("module %s: relocation overflow\n",
++			       me->name);
++			return -ENOEXEC;
++		}
++		ofs = 0;
+ 	}
+ 
+ 	*location = (*location & ~0x03ffffff) |
+-		    ((base + (v >> 2)) & 0x03ffffff);
++		    ((ofs + (v >> 2)) & 0x03ffffff);
+ 
+ 	return 0;
+ }
+@@ -447,9 +689,36 @@ int module_finalize(const Elf_Ehdr *hdr,
+ 		list_add(&me->arch.dbe_list, &dbe_list);
+ 		spin_unlock_irq(&dbe_lock);
+ 	}
++
++	/* Get rid of the fixup trampoline if we're running the module
++	 * from physically mapped address space */
++	if (me->arch.phys_plt_offset == 0) {
++		__module_free(me->arch.phys_plt_tbl);
++		me->arch.phys_plt_tbl = NULL;
++	}
++	if (me->arch.virt_plt_offset == 0) {
++		__module_free(me->arch.virt_plt_tbl);
++		me->arch.virt_plt_tbl = NULL;
++	}
++
+ 	return 0;
+ }
+ 
++void module_arch_freeing_init(struct module *mod)
++{
++	if (mod->state == MODULE_STATE_LIVE)
++		return;
++
++	if (mod->arch.phys_plt_tbl) {
++		__module_free(mod->arch.phys_plt_tbl);
++		mod->arch.phys_plt_tbl = NULL;
++	}
++	if (mod->arch.virt_plt_tbl) {
++		__module_free(mod->arch.virt_plt_tbl);
++		mod->arch.virt_plt_tbl = NULL;
++	}
++}
++
+ void module_arch_cleanup(struct module *mod)
+ {
+ 	spin_lock_irq(&dbe_lock);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/307-mips_highmem_offset.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/307-mips_highmem_offset.patch
new file mode 100644
index 0000000..9dd2fa9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/307-mips_highmem_offset.patch
@@ -0,0 +1,19 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: kernel: adjust mips highmem offset to avoid the need for -mlong-calls on systems with >256M RAM
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ arch/mips/include/asm/mach-generic/spaces.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/mips/include/asm/mach-generic/spaces.h
++++ b/arch/mips/include/asm/mach-generic/spaces.h
+@@ -50,7 +50,7 @@
+  * Memory above this physical address will be considered highmem.
+  */
+ #ifndef HIGHMEM_START
+-#define HIGHMEM_START		_AC(0x20000000, UL)
++#define HIGHMEM_START		_AC(0x10000000, UL)
+ #endif
+ 
+ #endif /* CONFIG_32BIT */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/308-mips32r2_tune.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/308-mips32r2_tune.patch
new file mode 100644
index 0000000..8636511
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/308-mips32r2_tune.patch
@@ -0,0 +1,22 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: kernel: add -mtune=34kc to MIPS CFLAGS when building for mips32r2
+
+This provides a good tradeoff across at least 24Kc-74Kc, while also
+producing smaller code.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ arch/mips/Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -177,7 +177,7 @@ cflags-$(CONFIG_CPU_VR41XX)	+= -march=r4
+ cflags-$(CONFIG_CPU_R4X00)	+= -march=r4600 -Wa,--trap
+ cflags-$(CONFIG_CPU_TX49XX)	+= -march=r4600 -Wa,--trap
+ cflags-$(CONFIG_CPU_MIPS32_R1)	+= -march=mips32 -Wa,--trap
+-cflags-$(CONFIG_CPU_MIPS32_R2)	+= -march=mips32r2 -Wa,--trap
++cflags-$(CONFIG_CPU_MIPS32_R2)	+= -march=mips32r2 -mtune=34kc -Wa,--trap
+ cflags-$(CONFIG_CPU_MIPS32_R6)	+= -march=mips32r6 -Wa,--trap -modd-spreg
+ cflags-$(CONFIG_CPU_MIPS64_R1)	+= -march=mips64 -Wa,--trap
+ cflags-$(CONFIG_CPU_MIPS64_R2)	+= -march=mips64r2 -Wa,--trap
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/309-MIPS-Add-CPU-option-reporting-to-proc-cpuinfo.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/309-MIPS-Add-CPU-option-reporting-to-proc-cpuinfo.patch
new file mode 100644
index 0000000..e4075a2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/309-MIPS-Add-CPU-option-reporting-to-proc-cpuinfo.patch
@@ -0,0 +1,142 @@
+From 87ec87c2ad615c1a177cd08ef5fa29fc739f6e50 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 23 Dec 2018 18:06:53 +0100
+Subject: [PATCH] MIPS: Add CPU option reporting to /proc/cpuinfo
+
+Many MIPS CPUs have optional CPU features which are not activates for
+all CPU cores. Print the CPU options which are implemented in the core
+in /proc/cpuinfo. This makes it possible to see what features are
+supported and which are not supported. This should cover all standard
+MIPS extensions, before it only printed information about the main MIPS
+ASEs.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/mips/kernel/proc.c | 116 ++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 116 insertions(+)
+
+--- a/arch/mips/kernel/proc.c
++++ b/arch/mips/kernel/proc.c
+@@ -134,6 +134,122 @@ static int show_cpuinfo(struct seq_file
+ 		seq_printf(m, "micromips kernel\t: %s\n",
+ 		      (read_c0_config3() & MIPS_CONF3_ISA_OE) ?  "yes" : "no");
+ 	}
++
++	seq_printf(m, "Options implemented\t:");
++	if (cpu_has_tlb)
++		seq_printf(m, "%s", " tlb");
++	if (cpu_has_ftlb)
++		seq_printf(m, "%s", " ftlb");
++	if (cpu_has_tlbinv)
++		seq_printf(m, "%s", " tlbinv");
++	if (cpu_has_segments)
++		seq_printf(m, "%s", " segments");
++	if (cpu_has_rixiex)
++		seq_printf(m, "%s", " rixiex");
++	if (cpu_has_ldpte)
++		seq_printf(m, "%s", " ldpte");
++	if (cpu_has_maar)
++		seq_printf(m, "%s", " maar");
++	if (cpu_has_rw_llb)
++		seq_printf(m, "%s", " rw_llb");
++	if (cpu_has_4kex)
++		seq_printf(m, "%s", " 4kex");
++	if (cpu_has_3k_cache)
++		seq_printf(m, "%s", " 3k_cache");
++	if (cpu_has_4k_cache)
++		seq_printf(m, "%s", " 4k_cache");
++	if (cpu_has_6k_cache)
++		seq_printf(m, "%s", " 6k_cache");
++	if (cpu_has_8k_cache)
++		seq_printf(m, "%s", " 8k_cache");
++	if (cpu_has_tx39_cache)
++		seq_printf(m, "%s", " tx39_cache");
++	if (cpu_has_octeon_cache)
++		seq_printf(m, "%s", " octeon_cache");
++	if (cpu_has_fpu)
++		seq_printf(m, "%s", " fpu");
++	if (cpu_has_32fpr)
++		seq_printf(m, "%s", " 32fpr");
++	if (cpu_has_cache_cdex_p)
++		seq_printf(m, "%s", " cache_cdex_p");
++	if (cpu_has_cache_cdex_s)
++		seq_printf(m, "%s", " cache_cdex_s");
++	if (cpu_has_prefetch)
++		seq_printf(m, "%s", " prefetch");
++	if (cpu_has_mcheck)
++		seq_printf(m, "%s", " mcheck");
++	if (cpu_has_ejtag)
++		seq_printf(m, "%s", " ejtag");
++	if (cpu_has_llsc)
++		seq_printf(m, "%s", " llsc");
++	if (cpu_has_bp_ghist)
++		seq_printf(m, "%s", " bp_ghist");
++	if (cpu_has_guestctl0ext)
++		seq_printf(m, "%s", " guestctl0ext");
++	if (cpu_has_guestctl1)
++		seq_printf(m, "%s", " guestctl1");
++	if (cpu_has_guestctl2)
++		seq_printf(m, "%s", " guestctl2");
++	if (cpu_has_guestid)
++		seq_printf(m, "%s", " guestid");
++	if (cpu_has_drg)
++		seq_printf(m, "%s", " drg");
++	if (cpu_has_rixi)
++		seq_printf(m, "%s", " rixi");
++	if (cpu_has_lpa)
++		seq_printf(m, "%s", " lpa");
++	if (cpu_has_mvh)
++		seq_printf(m, "%s", " mvh");
++	if (cpu_has_vtag_icache)
++		seq_printf(m, "%s", " vtag_icache");
++	if (cpu_has_dc_aliases)
++		seq_printf(m, "%s", " dc_aliases");
++	if (cpu_has_ic_fills_f_dc)
++		seq_printf(m, "%s", " ic_fills_f_dc");
++	if (cpu_has_pindexed_dcache)
++		seq_printf(m, "%s", " pindexed_dcache");
++	if (cpu_has_userlocal)
++		seq_printf(m, "%s", " userlocal");
++	if (cpu_has_nofpuex)
++		seq_printf(m, "%s", " nofpuex");
++	if (cpu_has_vint)
++		seq_printf(m, "%s", " vint");
++	if (cpu_has_veic)
++		seq_printf(m, "%s", " veic");
++	if (cpu_has_inclusive_pcaches)
++		seq_printf(m, "%s", " inclusive_pcaches");
++	if (cpu_has_perf_cntr_intr_bit)
++		seq_printf(m, "%s", " perf_cntr_intr_bit");
++	if (cpu_has_ufr)
++		seq_printf(m, "%s", " ufr");
++	if (cpu_has_fre)
++		seq_printf(m, "%s", " fre");
++	if (cpu_has_cdmm)
++		seq_printf(m, "%s", " cdmm");
++	if (cpu_has_small_pages)
++		seq_printf(m, "%s", " small_pages");
++	if (cpu_has_nan_legacy)
++		seq_printf(m, "%s", " nan_legacy");
++	if (cpu_has_nan_2008)
++		seq_printf(m, "%s", " nan_2008");
++	if (cpu_has_ebase_wg)
++		seq_printf(m, "%s", " ebase_wg");
++	if (cpu_has_badinstr)
++		seq_printf(m, "%s", " badinstr");
++	if (cpu_has_badinstrp)
++		seq_printf(m, "%s", " badinstrp");
++	if (cpu_has_contextconfig)
++		seq_printf(m, "%s", " contextconfig");
++	if (cpu_has_perf)
++		seq_printf(m, "%s", " perf");
++	if (cpu_has_shared_ftlb_ram)
++		seq_printf(m, "%s", " shared_ftlb_ram");
++	if (cpu_has_shared_ftlb_entries)
++		seq_printf(m, "%s", " shared_ftlb_entries");
++	if (cpu_has_mipsmt_pertccounters)
++		seq_printf(m, "%s", " mipsmt_pertccounters");
++	seq_printf(m, "\n");
++
+ 	seq_printf(m, "shadow register sets\t: %d\n",
+ 		      cpu_data[n].srsets);
+ 	seq_printf(m, "kscratch registers\t: %d\n",
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/310-arm_module_unresolved_weak_sym.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/310-arm_module_unresolved_weak_sym.patch
new file mode 100644
index 0000000..24807f7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/310-arm_module_unresolved_weak_sym.patch
@@ -0,0 +1,22 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: fix errors in unresolved weak symbols on arm
+
+lede-commit: 570699d4838a907c3ef9f2819bf19eb72997b32f
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ arch/arm/kernel/module.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/arch/arm/kernel/module.c
++++ b/arch/arm/kernel/module.c
+@@ -99,6 +99,10 @@ apply_relocate(Elf32_Shdr *sechdrs, cons
+ 			return -ENOEXEC;
+ 		}
+ 
++		if ((IS_ERR_VALUE(sym->st_value) || !sym->st_value) &&
++		    ELF_ST_BIND(sym->st_info) == STB_WEAK)
++			continue;
++
+ 		loc = dstsec->sh_addr + rel->r_offset;
+ 
+ 		switch (ELF32_R_TYPE(rel->r_info)) {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/311-MIPS-zboot-put-appended-dtb-into-a-section.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/311-MIPS-zboot-put-appended-dtb-into-a-section.patch
new file mode 100644
index 0000000..3f8808f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/311-MIPS-zboot-put-appended-dtb-into-a-section.patch
@@ -0,0 +1,36 @@
+From 7d1531c81c0fb4c93bea8dc316043ad0e4d0c270 Mon Sep 17 00:00:00 2001
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Sun, 25 Oct 2020 23:19:40 +0800
+Subject: [PATCH] MIPS: zboot: put appended dtb into a section
+
+This will make a separated section for dtb appear in ELF, and we can
+then use objcopy to patch a dtb into vmlinuz when RAW_APPENDED_DTB
+is set in kernel config.
+
+command to patch a dtb:
+objcopy --set-section-flags=.appended_dtb=alloc,contents \
+        --update-section=.appended_dtb=<target>.dtb vmlinuz vmlinuz-dtb
+
+Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
+---
+ arch/mips/boot/compressed/ld.script | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+--- a/arch/mips/boot/compressed/ld.script
++++ b/arch/mips/boot/compressed/ld.script
+@@ -31,9 +31,12 @@ SECTIONS
+ 		CONSTRUCTORS
+ 		. = ALIGN(16);
+ 	}
+-	__appended_dtb = .;
+-	/* leave space for appended DTB */
+-	. += 0x100000;
++
++	.appended_dtb : {
++		__appended_dtb = .;
++		/* leave space for appended DTB */
++		. += 0x100000;
++	}
+ 
+ 	_edata = .;
+ 	/* End of data section */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch
new file mode 100644
index 0000000..2808c95
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch
@@ -0,0 +1,281 @@
+From: Yousong Zhou <yszhou4tech@gmail.com>
+Subject: MIPS: kexec: Accept command line parameters from userspace.
+
+Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
+---
+ arch/mips/kernel/machine_kexec.c   |  153 +++++++++++++++++++++++++++++++-----
+ arch/mips/kernel/machine_kexec.h   |   20 +++++
+ arch/mips/kernel/relocate_kernel.S |   21 +++--
+ 3 files changed, 167 insertions(+), 27 deletions(-)
+ create mode 100644 arch/mips/kernel/machine_kexec.h
+
+--- a/arch/mips/kernel/machine_kexec.c
++++ b/arch/mips/kernel/machine_kexec.c
+@@ -9,14 +9,11 @@
+ #include <linux/delay.h>
+ #include <linux/libfdt.h>
+ 
++#include <asm/bootinfo.h>
+ #include <asm/cacheflush.h>
+ #include <asm/page.h>
+-
+-extern const unsigned char relocate_new_kernel[];
+-extern const size_t relocate_new_kernel_size;
+-
+-extern unsigned long kexec_start_address;
+-extern unsigned long kexec_indirection_page;
++#include <linux/uaccess.h>
++#include "machine_kexec.h"
+ 
+ static unsigned long reboot_code_buffer;
+ 
+@@ -30,6 +27,101 @@ void (*_crash_smp_send_stop)(void) = NUL
+ void (*_machine_kexec_shutdown)(void) = NULL;
+ void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL;
+ 
++static void machine_kexec_print_args(void)
++{
++	unsigned long argc = (int)kexec_args[0];
++	int i;
++
++	pr_info("kexec_args[0] (argc): %lu\n", argc);
++	pr_info("kexec_args[1] (argv): %p\n", (void *)kexec_args[1]);
++	pr_info("kexec_args[2] (env ): %p\n", (void *)kexec_args[2]);
++	pr_info("kexec_args[3] (desc): %p\n", (void *)kexec_args[3]);
++
++	for (i = 0; i < argc; i++) {
++		pr_info("kexec_argv[%d] = %p, %s\n",
++				i, kexec_argv[i], kexec_argv[i]);
++	}
++}
++
++static void machine_kexec_init_argv(struct kimage *image)
++{
++	void __user *buf = NULL;
++	size_t bufsz;
++	size_t size;
++	int i;
++
++	bufsz = 0;
++	for (i = 0; i < image->nr_segments; i++) {
++		struct kexec_segment *seg;
++
++		seg = &image->segment[i];
++		if (seg->bufsz < 6)
++			continue;
++
++		if (strncmp((char *) seg->buf, "kexec ", 6))
++			continue;
++
++		buf = seg->buf;
++		bufsz = seg->bufsz;
++		break;
++	}
++
++	if (!buf)
++		return;
++
++	size = KEXEC_COMMAND_LINE_SIZE;
++	size = min(size, bufsz);
++	if (size < bufsz)
++		pr_warn("kexec command line truncated to %zd bytes\n", size);
++
++	/* Copy to kernel space */
++	if (copy_from_user(kexec_argv_buf, buf, size))
++		pr_warn("kexec command line copy to kernel space failed\n");
++
++	kexec_argv_buf[size - 1] = 0;
++}
++
++static void machine_kexec_parse_argv(struct kimage *image)
++{
++	char *reboot_code_buffer;
++	int reloc_delta;
++	char *ptr;
++	int argc;
++	int i;
++
++	ptr = kexec_argv_buf;
++	argc = 0;
++
++	/*
++	 * convert command line string to array of parameters
++	 * (as bootloader does).
++	 */
++	while (ptr && *ptr && (KEXEC_MAX_ARGC > argc)) {
++		if (*ptr == ' ') {
++			*ptr++ = '\0';
++			continue;
++		}
++
++		kexec_argv[argc++] = ptr;
++		ptr = strchr(ptr, ' ');
++	}
++
++	if (!argc)
++		return;
++
++	kexec_args[0] = argc;
++	kexec_args[1] = (unsigned long)kexec_argv;
++	kexec_args[2] = 0;
++	kexec_args[3] = 0;
++
++	reboot_code_buffer = page_address(image->control_code_page);
++	reloc_delta = reboot_code_buffer - (char *)kexec_relocate_new_kernel;
++
++	kexec_args[1] += reloc_delta;
++	for (i = 0; i < argc; i++)
++		kexec_argv[i] += reloc_delta;
++}
++
+ static void kexec_image_info(const struct kimage *kimage)
+ {
+ 	unsigned long i;
+@@ -99,6 +191,18 @@ machine_kexec_prepare(struct kimage *kim
+ #endif
+ 
+ 	kexec_image_info(kimage);
++	/*
++	 * Whenever arguments passed from kexec-tools, Init the arguments as
++	 * the original ones to try avoiding booting failure.
++	 */
++
++	kexec_args[0] = fw_arg0;
++	kexec_args[1] = fw_arg1;
++	kexec_args[2] = fw_arg2;
++	kexec_args[3] = fw_arg3;
++
++	machine_kexec_init_argv(kimage);
++	machine_kexec_parse_argv(kimage);
+ 
+ 	if (_machine_kexec_prepare)
+ 		return _machine_kexec_prepare(kimage);
+@@ -161,7 +265,7 @@ machine_crash_shutdown(struct pt_regs *r
+ void kexec_nonboot_cpu_jump(void)
+ {
+ 	local_flush_icache_range((unsigned long)relocated_kexec_smp_wait,
+-				 reboot_code_buffer + relocate_new_kernel_size);
++				 reboot_code_buffer + KEXEC_RELOCATE_NEW_KERNEL_SIZE);
+ 
+ 	relocated_kexec_smp_wait(NULL);
+ }
+@@ -199,7 +303,7 @@ void kexec_reboot(void)
+ 	 * machine_kexec() CPU.
+ 	 */
+ 	local_flush_icache_range(reboot_code_buffer,
+-				 reboot_code_buffer + relocate_new_kernel_size);
++				 reboot_code_buffer + KEXEC_RELOCATE_NEW_KERNEL_SIZE);
+ 
+ 	do_kexec = (void *)reboot_code_buffer;
+ 	do_kexec();
+@@ -212,10 +316,12 @@ machine_kexec(struct kimage *image)
+ 	unsigned long *ptr;
+ 
+ 	reboot_code_buffer =
+-	  (unsigned long)page_address(image->control_code_page);
++		(unsigned long)page_address(image->control_code_page);
++	pr_info("reboot_code_buffer = %p\n", (void *)reboot_code_buffer);
+ 
+ 	kexec_start_address =
+ 		(unsigned long) phys_to_virt(image->start);
++	pr_info("kexec_start_address = %p\n", (void *)kexec_start_address);
+ 
+ 	if (image->type == KEXEC_TYPE_DEFAULT) {
+ 		kexec_indirection_page =
+@@ -223,9 +329,19 @@ machine_kexec(struct kimage *image)
+ 	} else {
+ 		kexec_indirection_page = (unsigned long)&image->head;
+ 	}
++	pr_info("kexec_indirection_page = %p\n", (void *)kexec_indirection_page);
+ 
+-	memcpy((void*)reboot_code_buffer, relocate_new_kernel,
+-	       relocate_new_kernel_size);
++	pr_info("Where is memcpy: %p\n", memcpy);
++	pr_info("kexec_relocate_new_kernel = %p, kexec_relocate_new_kernel_end = %p\n",
++		(void *)kexec_relocate_new_kernel, &kexec_relocate_new_kernel_end);
++	pr_info("Copy %lu bytes from %p to %p\n", KEXEC_RELOCATE_NEW_KERNEL_SIZE,
++		(void *)kexec_relocate_new_kernel, (void *)reboot_code_buffer);
++	memcpy((void*)reboot_code_buffer, kexec_relocate_new_kernel,
++	       KEXEC_RELOCATE_NEW_KERNEL_SIZE);
++
++	pr_info("Before _print_args().\n");
++	machine_kexec_print_args();
++	pr_info("Before eval loop.\n");
+ 
+ 	/*
+ 	 * The generic kexec code builds a page list with physical
+@@ -256,7 +372,7 @@ machine_kexec(struct kimage *image)
+ #ifdef CONFIG_SMP
+ 	/* All secondary cpus now may jump to kexec_wait cycle */
+ 	relocated_kexec_smp_wait = reboot_code_buffer +
+-		(void *)(kexec_smp_wait - relocate_new_kernel);
++		(void *)(kexec_smp_wait - kexec_relocate_new_kernel);
+ 	smp_wmb();
+ 	atomic_set(&kexec_ready_to_reboot, 1);
+ #endif
+--- /dev/null
++++ b/arch/mips/kernel/machine_kexec.h
+@@ -0,0 +1,20 @@
++#ifndef _MACHINE_KEXEC_H
++#define _MACHINE_KEXEC_H
++
++#ifndef __ASSEMBLY__
++extern const unsigned char kexec_relocate_new_kernel[];
++extern unsigned long kexec_relocate_new_kernel_end;
++extern unsigned long kexec_start_address;
++extern unsigned long kexec_indirection_page;
++
++extern char kexec_argv_buf[];
++extern char *kexec_argv[];
++
++#define KEXEC_RELOCATE_NEW_KERNEL_SIZE	((unsigned long)&kexec_relocate_new_kernel_end - (unsigned long)kexec_relocate_new_kernel)
++#endif /* !__ASSEMBLY__ */
++
++#define KEXEC_COMMAND_LINE_SIZE		256
++#define KEXEC_ARGV_SIZE			(KEXEC_COMMAND_LINE_SIZE / 16)
++#define KEXEC_MAX_ARGC			(KEXEC_ARGV_SIZE / sizeof(long))
++
++#endif
+--- a/arch/mips/kernel/relocate_kernel.S
++++ b/arch/mips/kernel/relocate_kernel.S
+@@ -10,8 +10,9 @@
+ #include <asm/mipsregs.h>
+ #include <asm/stackframe.h>
+ #include <asm/addrspace.h>
++#include "machine_kexec.h"
+ 
+-LEAF(relocate_new_kernel)
++LEAF(kexec_relocate_new_kernel)
+ 	PTR_L a0,	arg0
+ 	PTR_L a1,	arg1
+ 	PTR_L a2,	arg2
+@@ -96,7 +97,7 @@ done:
+ #endif
+ 	/* jump to kexec_start_address */
+ 	j		s1
+-	END(relocate_new_kernel)
++	END(kexec_relocate_new_kernel)
+ 
+ #ifdef CONFIG_SMP
+ /*
+@@ -182,9 +183,15 @@ kexec_indirection_page:
+ 	PTR		0
+ 	.size		kexec_indirection_page, PTRSIZE
+ 
+-relocate_new_kernel_end:
++kexec_argv_buf:
++	EXPORT(kexec_argv_buf)
++	.skip		KEXEC_COMMAND_LINE_SIZE
++	.size		kexec_argv_buf, KEXEC_COMMAND_LINE_SIZE
++
++kexec_argv:
++	EXPORT(kexec_argv)
++	.skip		KEXEC_ARGV_SIZE
++	.size		kexec_argv, KEXEC_ARGV_SIZE
+ 
+-relocate_new_kernel_size:
+-	EXPORT(relocate_new_kernel_size)
+-	PTR		relocate_new_kernel_end - relocate_new_kernel
+-	.size		relocate_new_kernel_size, PTRSIZE
++kexec_relocate_new_kernel_end:
++	EXPORT(kexec_relocate_new_kernel_end)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/332-arc-add-OWRTDTB-section.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/332-arc-add-OWRTDTB-section.patch
new file mode 100644
index 0000000..4b0534e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/332-arc-add-OWRTDTB-section.patch
@@ -0,0 +1,84 @@
+From bb0c3b0175240bf152fd7c644821a0cf9f77c37c Mon Sep 17 00:00:00 2001
+From: Evgeniy Didin <Evgeniy.Didin@synopsys.com>
+Date: Fri, 15 Mar 2019 18:53:38 +0300
+Subject: [PATCH] arc add OWRTDTB section
+
+This change allows OpenWRT to patch resulting kernel binary with
+external .dtb.
+
+That allows us to re-use exactky the same vmlinux on different boards
+given its ARC core configurations match (at least cache line sizes etc).
+
+""patch-dtb" searches for ASCII "OWRTDTB:" strign and copies external
+.dtb right after it, keeping the string in place.
+
+Signed-off-by: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
+Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
+Signed-off-by: Evgeniy Didin <Evgeniy.Didin@synopsys.com>
+---
+ arch/arc/kernel/head.S        | 10 ++++++++++
+ arch/arc/kernel/setup.c       |  4 +++-
+ arch/arc/kernel/vmlinux.lds.S | 13 +++++++++++++
+ 3 files changed, 26 insertions(+), 1 deletion(-)
+
+--- a/arch/arc/kernel/head.S
++++ b/arch/arc/kernel/head.S
+@@ -61,6 +61,16 @@
+ #endif
+ .endm
+ 
++	; Here "patch-dtb" will embed external .dtb
++	; Note "patch-dtb" searches for ASCII "OWRTDTB:" string
++	; and pastes .dtb right after it, hense the string precedes
++	; __image_dtb symbol.
++	.section .owrt, "aw",@progbits
++	.ascii  "OWRTDTB:"
++ENTRY(__image_dtb)
++	.fill   0x4000
++END(__image_dtb)
++
+ 	.section .init.text, "ax",@progbits
+ 
+ ;----------------------------------------------------------------
+--- a/arch/arc/kernel/setup.c
++++ b/arch/arc/kernel/setup.c
+@@ -492,6 +492,8 @@ static inline bool uboot_arg_invalid(uns
+ /* We always pass 0 as magic from U-boot */
+ #define UBOOT_MAGIC_VALUE	0
+ 
++extern struct boot_param_header __image_dtb;
++
+ void __init handle_uboot_args(void)
+ {
+ 	bool use_embedded_dtb = true;
+@@ -530,7 +532,7 @@ void __init handle_uboot_args(void)
+ ignore_uboot_args:
+ 
+ 	if (use_embedded_dtb) {
+-		machine_desc = setup_machine_fdt(__dtb_start);
++		machine_desc = setup_machine_fdt(&__image_dtb);
+ 		if (!machine_desc)
+ 			panic("Embedded DT invalid\n");
+ 	}
+--- a/arch/arc/kernel/vmlinux.lds.S
++++ b/arch/arc/kernel/vmlinux.lds.S
+@@ -27,6 +27,19 @@ SECTIONS
+ 
+ 	. = CONFIG_LINUX_LINK_BASE;
+ 
++	/*
++	* In OpenWRT we want to patch built binary embedding .dtb of choice.
++	* This is implemented with "patch-dtb" utility which searches for
++	* "OWRTDTB:" string in first 16k of image and if it is found
++	* copies .dtb right after mentioned string.
++	*
++	* Note: "OWRTDTB:" won't be overwritten with .dtb, .dtb will follow it.
++	*/
++ 	.owrt : {
++		*(.owrt)
++	. = ALIGN(PAGE_SIZE);
++	}
++
+ 	_int_vec_base_lds = .;
+ 	.vector : {
+ 		*(.vector)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/333-arc-enable-unaligned-access-in-kernel-mode.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/333-arc-enable-unaligned-access-in-kernel-mode.patch
new file mode 100644
index 0000000..1848a84
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/333-arc-enable-unaligned-access-in-kernel-mode.patch
@@ -0,0 +1,24 @@
+From: Alexey Brodkin <abrodkin@synopsys.com>
+Subject: arc: enable unaligned access in kernel mode
+
+This enables misaligned access handling even in kernel mode.
+Some wireless drivers (ath9k-htc and mt7601u) use misaligned accesses
+here and there and to cope with that without fixing stuff in the drivers
+we're just gracefully handling it on ARC.
+
+Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
+---
+ arch/arc/kernel/unaligned.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arc/kernel/unaligned.c
++++ b/arch/arc/kernel/unaligned.c
+@@ -202,7 +202,7 @@ int misaligned_fixup(unsigned long addre
+ 	char buf[TASK_COMM_LEN];
+ 
+ 	/* handle user mode only and only if enabled by sysadmin */
+-	if (!user_mode(regs) || !unaligned_enabled)
++	if (!unaligned_enabled)
+ 		return 1;
+ 
+ 	if (no_unaligned_warning) {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/342-powerpc-Enable-kernel-XZ-compression-option-on-PPC_8.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/342-powerpc-Enable-kernel-XZ-compression-option-on-PPC_8.patch
new file mode 100644
index 0000000..8d4c742
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/342-powerpc-Enable-kernel-XZ-compression-option-on-PPC_8.patch
@@ -0,0 +1,25 @@
+From 66770a004afe10df11d3902e16eaa0c2c39436bb Mon Sep 17 00:00:00 2001
+From: Pawel Dembicki <paweldembicki@gmail.com>
+Date: Fri, 24 May 2019 17:56:19 +0200
+Subject: [PATCH] powerpc: Enable kernel XZ compression option on PPC_85xx
+
+Enable kernel XZ compression option on PPC_85xx. Tested with
+simpleImage on TP-Link TL-WDR4900 (Freescale P1014 processor).
+
+Suggested-by: Christian Lamparter <chunkeey@gmail.com>
+Signed-off-by: Pawel Dembicki <paweldembicki@gmail.com>
+---
+ arch/powerpc/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/powerpc/Kconfig
++++ b/arch/powerpc/Kconfig
+@@ -205,7 +205,7 @@ config PPC
+ 	select HAVE_KERNEL_GZIP
+ 	select HAVE_KERNEL_LZMA			if DEFAULT_UIMAGE
+ 	select HAVE_KERNEL_LZO			if DEFAULT_UIMAGE
+-	select HAVE_KERNEL_XZ			if PPC_BOOK3S || 44x
++	select HAVE_KERNEL_XZ			if PPC_BOOK3S || 44x || PPC_85xx
+ 	select HAVE_KPROBES
+ 	select HAVE_KPROBES_ON_FTRACE
+ 	select HAVE_KRETPROBES
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/400-mtd-add-rootfs-split-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/400-mtd-add-rootfs-split-support.patch
new file mode 100644
index 0000000..83a4ed3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/400-mtd-add-rootfs-split-support.patch
@@ -0,0 +1,107 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: make rootfs split/detection more generic - patch can be moved to generic-2.6 after testing on other platforms
+
+lede-commit: 328e660b31f0937d52c5ae3d6e7029409918a9df
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ drivers/mtd/Kconfig            | 17 +++++++++++++++++
+ drivers/mtd/mtdpart.c          | 35 +++++++++++++++++++++++++++++++++++
+ include/linux/mtd/partitions.h |  2 ++
+ 3 files changed, 54 insertions(+)
+
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -12,6 +12,23 @@ menuconfig MTD
+ 
+ if MTD
+ 
++menu "OpenWrt specific MTD options"
++
++config MTD_ROOTFS_ROOT_DEV
++	bool "Automatically set 'rootfs' partition to be root filesystem"
++	default y
++
++config MTD_SPLIT_FIRMWARE
++	bool "Automatically split firmware partition for kernel+rootfs"
++	default y
++
++config MTD_SPLIT_FIRMWARE_NAME
++	string "Firmware partition name"
++	depends on MTD_SPLIT_FIRMWARE
++	default "firmware"
++
++endmenu
++
+ config MTD_TESTS
+ 	tristate "MTD tests support (DANGEROUS)"
+ 	depends on m
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -15,10 +15,12 @@
+ #include <linux/kmod.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
++#include <linux/magic.h>
+ #include <linux/err.h>
+ #include <linux/of.h>
+ 
+ #include "mtdcore.h"
++#include "mtdsplit/mtdsplit.h"
+ 
+ /* Our partition linked list */
+ static LIST_HEAD(mtd_partitions);
+@@ -38,6 +40,8 @@ struct mtd_part {
+ 	struct list_head list;
+ };
+ 
++static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part);
++
+ /*
+  * Given a pointer to the MTD object in the mtd_part structure, we can retrieve
+  * the pointer to that structure.
+@@ -612,6 +616,7 @@ int mtd_add_partition(struct mtd_info *p
+ 	if (ret)
+ 		goto err_remove_part;
+ 
++	mtd_partition_split(parent, new);
+ 	mtd_add_partition_attrs(new);
+ 
+ 	return 0;
+@@ -698,6 +703,29 @@ int mtd_del_partition(struct mtd_info *m
+ }
+ EXPORT_SYMBOL_GPL(mtd_del_partition);
+ 
++#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
++#define SPLIT_FIRMWARE_NAME	CONFIG_MTD_SPLIT_FIRMWARE_NAME
++#else
++#define SPLIT_FIRMWARE_NAME	"unused"
++#endif
++
++static void split_firmware(struct mtd_info *master, struct mtd_part *part)
++{
++}
++
++static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part)
++{
++	static int rootfs_found = 0;
++
++	if (rootfs_found)
++		return;
++
++	if (IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE) &&
++	    !strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) &&
++	    !of_find_property(mtd_get_of_node(&part->mtd), "compatible", NULL))
++		split_firmware(master, part);
++}
++
+ /*
+  * This function, given a master MTD object and a partition table, creates
+  * and registers slave MTD objects which are bound to the master according to
+@@ -738,6 +766,7 @@ int add_mtd_partitions(struct mtd_info *
+ 			goto err_del_partitions;
+ 		}
+ 
++		mtd_partition_split(master, slave);
+ 		mtd_add_partition_attrs(slave);
+ 		/* Look for subpartitions */
+ 		parse_mtd_partitions(&slave->mtd, parts[i].types, NULL);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/401-mtd-add-support-for-different-partition-parser-types.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/401-mtd-add-support-for-different-partition-parser-types.patch
new file mode 100644
index 0000000..f471c62
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/401-mtd-add-support-for-different-partition-parser-types.patch
@@ -0,0 +1,142 @@
+From: Gabor Juhos <juhosg@openwrt.org>
+Subject: mtd: add support for different partition parser types
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ drivers/mtd/mtdpart.c          |   56 ++++++++++++++++++++++++++++++++++++++++
+ include/linux/mtd/partitions.h |   11 ++++++++
+ 2 files changed, 67 insertions(+)
+
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -41,6 +41,10 @@ struct mtd_part {
+ };
+ 
+ static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part);
++static int parse_mtd_partitions_by_type(struct mtd_info *master,
++					enum mtd_parser_type type,
++					const struct mtd_partition **pparts,
++					struct mtd_part_parser_data *data);
+ 
+ /*
+  * Given a pointer to the MTD object in the mtd_part structure, we can retrieve
+@@ -703,6 +707,36 @@ int mtd_del_partition(struct mtd_info *m
+ }
+ EXPORT_SYMBOL_GPL(mtd_del_partition);
+ 
++static int
++run_parsers_by_type(struct mtd_part *slave, enum mtd_parser_type type)
++{
++	struct mtd_partition *parts;
++	int nr_parts;
++	int i;
++
++	nr_parts = parse_mtd_partitions_by_type(&slave->mtd, type, (const struct mtd_partition **)&parts,
++						NULL);
++	if (nr_parts <= 0)
++		return nr_parts;
++
++	if (WARN_ON(!parts))
++		return 0;
++
++	for (i = 0; i < nr_parts; i++) {
++		/* adjust partition offsets */
++		parts[i].offset += slave->offset;
++
++		mtd_add_partition(slave->parent,
++				  parts[i].name,
++				  parts[i].offset,
++				  parts[i].size);
++	}
++
++	kfree(parts);
++
++	return nr_parts;
++}
++
+ #ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
+ #define SPLIT_FIRMWARE_NAME	CONFIG_MTD_SPLIT_FIRMWARE_NAME
+ #else
+@@ -1052,6 +1086,61 @@ void mtd_part_parser_cleanup(struct mtd_
+ 	}
+ }
+ 
++static struct mtd_part_parser *
++get_partition_parser_by_type(enum mtd_parser_type type,
++			     struct mtd_part_parser *start)
++{
++	struct mtd_part_parser *p, *ret = NULL;
++
++	spin_lock(&part_parser_lock);
++
++	p = list_prepare_entry(start, &part_parsers, list);
++	if (start)
++		mtd_part_parser_put(start);
++
++	list_for_each_entry_continue(p, &part_parsers, list) {
++		if (p->type == type && try_module_get(p->owner)) {
++			ret = p;
++			break;
++		}
++	}
++
++	spin_unlock(&part_parser_lock);
++
++	return ret;
++}
++
++static int parse_mtd_partitions_by_type(struct mtd_info *master,
++					enum mtd_parser_type type,
++					const struct mtd_partition **pparts,
++					struct mtd_part_parser_data *data)
++{
++	struct mtd_part_parser *prev = NULL;
++	int ret = 0;
++
++	while (1) {
++		struct mtd_part_parser *parser;
++
++		parser = get_partition_parser_by_type(type, prev);
++		if (!parser)
++			break;
++
++		ret = (*parser->parse_fn)(master, pparts, data);
++
++		if (ret > 0) {
++			mtd_part_parser_put(parser);
++			printk(KERN_NOTICE
++			       "%d %s partitions found on MTD device %s\n",
++			       ret, parser->name, master->name);
++			break;
++		}
++
++		prev = parser;
++	}
++
++	return ret;
++}
++
+ int mtd_is_partition(const struct mtd_info *mtd)
+ {
+ 	struct mtd_part *part;
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -73,6 +73,10 @@ struct mtd_part_parser_data {
+  * Functions dealing with the various ways of partitioning the space
+  */
+ 
++enum mtd_parser_type {
++	MTD_PARSER_TYPE_DEVICE = 0,
++};
++
+ struct mtd_part_parser {
+ 	struct list_head list;
+ 	struct module *owner;
+@@ -81,6 +85,7 @@ struct mtd_part_parser {
+ 	int (*parse_fn)(struct mtd_info *, const struct mtd_partition **,
+ 			struct mtd_part_parser_data *);
+ 	void (*cleanup)(const struct mtd_partition *pparts, int nr_parts);
++	enum mtd_parser_type type;
+ };
+ 
+ /* Container for passing around a set of parsed partitions */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch
new file mode 100644
index 0000000..afe3ec7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch
@@ -0,0 +1,44 @@
+From: Gabor Juhos <juhosg@openwrt.org>
+Subject: kernel/3.10: allow to use partition parsers for rootfs and firmware split
+
+lede-commit: 3b71cd94bc9517bc25267dccb393b07d4b54564e
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ drivers/mtd/mtdpart.c          | 37 +++++++++++++++++++++++++++++++++++++
+ include/linux/mtd/partitions.h |  2 ++
+ 2 files changed, 39 insertions(+)
+
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -745,6 +745,7 @@ run_parsers_by_type(struct mtd_part *sla
+ 
+ static void split_firmware(struct mtd_info *master, struct mtd_part *part)
+ {
++	run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
+ }
+ 
+ static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part)
+@@ -754,6 +755,12 @@ static void mtd_partition_split(struct m
+ 	if (rootfs_found)
+ 		return;
+ 
++	if (!strcmp(part->mtd.name, "rootfs")) {
++		run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS);
++
++		rootfs_found = 1;
++	}
++
+ 	if (IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE) &&
+ 	    !strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) &&
+ 	    !of_find_property(mtd_get_of_node(&part->mtd), "compatible", NULL))
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -75,6 +75,8 @@ struct mtd_part_parser_data {
+ 
+ enum mtd_parser_type {
+ 	MTD_PARSER_TYPE_DEVICE = 0,
++	MTD_PARSER_TYPE_ROOTFS,
++	MTD_PARSER_TYPE_FIRMWARE,
+ };
+ 
+ struct mtd_part_parser {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/403-mtd-hook-mtdsplit-to-Kbuild.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/403-mtd-hook-mtdsplit-to-Kbuild.patch
new file mode 100644
index 0000000..5d868ff
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/403-mtd-hook-mtdsplit-to-Kbuild.patch
@@ -0,0 +1,32 @@
+From: Gabor Juhos <juhosg@openwrt.org>
+Subject: [PATCH] kernel/3.10: move squashfs check from rootfs split code into a separate file
+
+lede-commit: d89bea92b31b4e157a0fa438e75370f089f73427
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ drivers/mtd/Kconfig  | 2 ++
+ drivers/mtd/Makefile | 2 ++
+ 2 files changed, 4 insertions(+)
+
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -27,6 +27,8 @@ config MTD_SPLIT_FIRMWARE_NAME
+ 	depends on MTD_SPLIT_FIRMWARE
+ 	default "firmware"
+ 
++source "drivers/mtd/mtdsplit/Kconfig"
++
+ endmenu
+ 
+ config MTD_TESTS
+--- a/drivers/mtd/Makefile
++++ b/drivers/mtd/Makefile
+@@ -9,6 +9,8 @@ mtd-y				:= mtdcore.o mtdsuper.o mtdconc
+ 
+ obj-y				+= parsers/
+ 
++obj-$(CONFIG_MTD_SPLIT)		+= mtdsplit/
++
+ # 'Users' - code which presents functionality to userspace.
+ obj-$(CONFIG_MTD_BLKDEVS)	+= mtd_blkdevs.o
+ obj-$(CONFIG_MTD_BLOCK)		+= mtdblock.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/404-mtd-add-more-helper-functions.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/404-mtd-add-more-helper-functions.patch
new file mode 100644
index 0000000..059a440
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/404-mtd-add-more-helper-functions.patch
@@ -0,0 +1,76 @@
+From: Gabor Juhos <juhosg@openwrt.org>
+Subject: kernel/3.10: add separate rootfs partition parser
+
+lede-commit: daec7ad7688415156e2730e401503d09bd3acf91
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ drivers/mtd/mtdpart.c          | 29 +++++++++++++++++++++++++++++
+ include/linux/mtd/mtd.h        | 18 ++++++++++++++++++
+ include/linux/mtd/partitions.h |  2 ++
+ 3 files changed, 49 insertions(+)
+
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -1165,6 +1165,24 @@ int mtd_is_partition(const struct mtd_in
+ }
+ EXPORT_SYMBOL_GPL(mtd_is_partition);
+ 
++struct mtd_info *mtd_get_master(const struct mtd_info *mtd)
++{
++	if (!mtd_is_partition(mtd))
++		return (struct mtd_info *)mtd;
++
++	return mtd_to_part(mtd)->parent;
++}
++EXPORT_SYMBOL_GPL(mtd_get_master);
++
++uint64_t mtdpart_get_offset(const struct mtd_info *mtd)
++{
++	if (!mtd_is_partition(mtd))
++		return 0;
++
++	return mtd_to_part(mtd)->offset;
++}
++EXPORT_SYMBOL_GPL(mtdpart_get_offset);
++
+ /* Returns the size of the entire flash chip */
+ uint64_t mtd_get_device_size(const struct mtd_info *mtd)
+ {
+--- a/include/linux/mtd/mtd.h
++++ b/include/linux/mtd/mtd.h
+@@ -504,6 +504,24 @@ static inline void mtd_align_erase_req(s
+ 		req->len += mtd->erasesize - mod;
+ }
+ 
++static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd)
++{
++	if (mtd_mod_by_eb(sz, mtd) == 0)
++		return sz;
++
++	/* Round up to next erase block */
++	return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize;
++}
++
++static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd)
++{
++	if (mtd_mod_by_eb(sz, mtd) == 0)
++		return sz;
++
++	/* Round down to the start of the current erase block */
++	return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize;
++}
++
+ static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd)
+ {
+ 	if (mtd->writesize_shift)
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -116,6 +116,8 @@ int mtd_is_partition(const struct mtd_in
+ int mtd_add_partition(struct mtd_info *master, const char *name,
+ 		      long long offset, long long length);
+ int mtd_del_partition(struct mtd_info *master, int partno);
++struct mtd_info *mtd_get_master(const struct mtd_info *mtd);
++uint64_t mtdpart_get_offset(const struct mtd_info *mtd);
+ uint64_t mtd_get_device_size(const struct mtd_info *mtd);
+ 
+ #endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/410-mtd-parsers-ofpart-fix-parsing-subpartitions.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/410-mtd-parsers-ofpart-fix-parsing-subpartitions.patch
new file mode 100644
index 0000000..d0fc1d5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/410-mtd-parsers-ofpart-fix-parsing-subpartitions.patch
@@ -0,0 +1,76 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Thu, 6 May 2021 12:33:58 +0200
+Subject: [PATCH] mtd: parsers: ofpart: fix parsing subpartitions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+ofpart was recently patched to not scan random partition nodes as
+subpartitions. That change unfortunately broke scanning valid
+subpartitions like:
+
+partitions {
+	compatible = "fixed-partitions";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	partition@0 {
+		compatible = "fixed-partitions";
+		label = "bootloader";
+		reg = <0x0 0x100000>;
+
+		partition@0 {
+			label = "config";
+			reg = <0x80000 0x80000>;
+		};
+	};
+};
+
+Fix that regression by adding 1 more code path. We actually need 3
+conditional blocks to support 3 possible cases. This change also makes
+code easier to understand & follow.
+
+Reported-by: David Bauer <mail@david-bauer.net>
+Fixes: 2d751203aacf ("mtd: parsers: ofpart: limit parsing of deprecated DT syntax
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+---
+ drivers/mtd/parsers/ofpart_core.c | 26 ++++++++++++++------------
+ 1 file changed, 14 insertions(+), 12 deletions(-)
+
+--- a/drivers/mtd/parsers/ofpart_core.c
++++ b/drivers/mtd/parsers/ofpart_core.c
+@@ -57,20 +57,22 @@ static int parse_fixed_partitions(struct
+ 	if (!mtd_node)
+ 		return 0;
+ 
+-	ofpart_node = of_get_child_by_name(mtd_node, "partitions");
+-	if (!ofpart_node && !mtd_is_partition(master)) {
+-		/*
+-		 * We might get here even when ofpart isn't used at all (e.g.,
+-		 * when using another parser), so don't be louder than
+-		 * KERN_DEBUG
+-		 */
+-		pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n",
+-			 master->name, mtd_node);
++	if (!mtd_is_partition(master)) { /* Master */
++		ofpart_node = of_get_child_by_name(mtd_node, "partitions");
++		if (!ofpart_node) {
++			/*
++			 * We might get here even when ofpart isn't used at all (e.g.,
++			 * when using another parser), so don't be louder than
++			 * KERN_DEBUG
++			 */
++			pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n",
++				master->name, mtd_node);
++			ofpart_node = mtd_node;
++			dedicated = false;
++		}
++	} else { /* Partition */
+ 		ofpart_node = mtd_node;
+-		dedicated = false;
+ 	}
+-	if (!ofpart_node)
+-		return 0;
+ 
+ 	of_id = of_match_node(parse_ofpart_match_table, ofpart_node);
+ 	if (dedicated && !of_id) {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/411-mtd-partial_eraseblock_write.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/411-mtd-partial_eraseblock_write.patch
new file mode 100644
index 0000000..c48a144
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/411-mtd-partial_eraseblock_write.patch
@@ -0,0 +1,130 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: mtd: implement write support for partitions covering only a part of an eraseblock (buffer data that would otherwise be erased)
+
+lede-commit: 87a8e8ac1067f58ba831c4aae443f3655c31cd80
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ drivers/mtd/mtdpart.c   | 90 ++++++++++++++++++++++++++++++++++++++++++++-----
+ include/linux/mtd/mtd.h |  4 +++
+ 2 files changed, 85 insertions(+), 9 deletions(-)
+
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -22,6 +22,8 @@
+ #include "mtdcore.h"
+ #include "mtdsplit/mtdsplit.h"
+ 
++#define MTD_ERASE_PARTIAL	0x8000 /* partition only covers parts of an erase block */
++
+ /* Our partition linked list */
+ static LIST_HEAD(mtd_partitions);
+ static DEFINE_MUTEX(mtd_partitions_mutex);
+@@ -206,11 +208,77 @@ static int part_erase(struct mtd_info *m
+ {
+ 	struct mtd_part *part = mtd_to_part(mtd);
+ 	int ret;
++	size_t wrlen = 0;
++	u8 *erase_buf = NULL;
++	u32 erase_buf_ofs = 0;
++	bool partial_start = false;
++
++	if (mtd->flags & MTD_ERASE_PARTIAL) {
++		size_t readlen = 0;
++		u64 mtd_ofs;
++
++		erase_buf = kmalloc(part->parent->erasesize, GFP_ATOMIC);
++		if (!erase_buf)
++			return -ENOMEM;
++
++		mtd_ofs = part->offset + instr->addr;
++		erase_buf_ofs = do_div(mtd_ofs, part->parent->erasesize);
++
++		if (erase_buf_ofs > 0) {
++			instr->addr -= erase_buf_ofs;
++			ret = mtd_read(part->parent,
++				instr->addr + part->offset,
++				part->parent->erasesize,
++				&readlen, erase_buf);
++
++			instr->len += erase_buf_ofs;
++			partial_start = true;
++		} else {
++			mtd_ofs = part->offset + part->mtd.size;
++			erase_buf_ofs = part->parent->erasesize -
++				do_div(mtd_ofs, part->parent->erasesize);
++
++			if (erase_buf_ofs > 0) {
++				instr->len += erase_buf_ofs;
++				ret = mtd_read(part->parent,
++					part->offset + instr->addr +
++					instr->len - part->parent->erasesize,
++					part->parent->erasesize, &readlen,
++					erase_buf);
++			} else {
++				ret = 0;
++			}
++		}
++		if (ret < 0) {
++			kfree(erase_buf);
++			return ret;
++		}
++
++	}
+ 
+ 	instr->addr += part->offset;
+ 	ret = part->parent->_erase(part->parent, instr);
+ 	if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
+ 		instr->fail_addr -= part->offset;
++
++	if (mtd->flags & MTD_ERASE_PARTIAL) {
++		if (partial_start) {
++			part->parent->_write(part->parent,
++				instr->addr, erase_buf_ofs,
++				&wrlen, erase_buf);
++			instr->addr += erase_buf_ofs;
++		} else {
++			instr->len -= erase_buf_ofs;
++			part->parent->_write(part->parent,
++				instr->addr + instr->len,
++				erase_buf_ofs, &wrlen,
++				erase_buf +
++				part->parent->erasesize -
++				erase_buf_ofs);
++		}
++		kfree(erase_buf);
++	}
++
+ 	instr->addr -= part->offset;
+ 
+ 	return ret;
+@@ -525,19 +593,22 @@ static struct mtd_part *allocate_partiti
+ 	remainder = do_div(tmp, wr_alignment);
+ 	if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {
+ 		/* Doesn't start on a boundary of major erase size */
+-		/* FIXME: Let it be writable if it is on a boundary of
+-		 * _minor_ erase size though */
+-		slave->mtd.flags &= ~MTD_WRITEABLE;
+-		printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n",
+-			part->name);
++		slave->mtd.flags |= MTD_ERASE_PARTIAL;
++		if (((u32)slave->mtd.size) > parent->erasesize)
++			slave->mtd.flags &= ~MTD_WRITEABLE;
++		else
++			slave->mtd.erasesize = slave->mtd.size;
+ 	}
+ 
+ 	tmp = part_absolute_offset(parent) + slave->offset + slave->mtd.size;
+ 	remainder = do_div(tmp, wr_alignment);
+ 	if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {
+-		slave->mtd.flags &= ~MTD_WRITEABLE;
+-		printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n",
+-			part->name);
++		slave->mtd.flags |= MTD_ERASE_PARTIAL;
++
++		if ((u32)slave->mtd.size > parent->erasesize)
++			slave->mtd.flags &= ~MTD_WRITEABLE;
++		else
++			slave->mtd.erasesize = slave->mtd.size;
+ 	}
+ 
+ 	mtd_set_ooblayout(&slave->mtd, &part_ooblayout_ops);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/412-mtd-partial_eraseblock_unlock.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/412-mtd-partial_eraseblock_unlock.patch
new file mode 100644
index 0000000..b23bc1b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/412-mtd-partial_eraseblock_unlock.patch
@@ -0,0 +1,40 @@
+From: Tim Harvey <tharvey@gateworks.com>
+Subject: mtd: allow partial block unlock
+
+This allows sysupgrade for devices such as the Gateworks Avila/Cambria
+product families based on the ixp4xx using the redboot bootloader with
+combined FIS directory and RedBoot config partitions on larger FLASH
+devices with larger eraseblocks.
+
+This second iteration of this patch addresses previous issues:
+- whitespace breakage fixed
+- unlock in all scenarios
+- simplification and fix logic bug
+
+[john@phrozen.org: this should be moved to the ixp4xx folder]
+
+Signed-off-by: Tim Harvey <tharvey@gateworks.com>
+---
+ drivers/mtd/mtdpart.c | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -293,7 +293,16 @@ static int part_lock(struct mtd_info *mt
+ static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+ {
+ 	struct mtd_part *part = mtd_to_part(mtd);
+-	return part->parent->_unlock(part->parent, ofs + part->offset, len);
++
++	ofs += part->offset;
++
++	if (mtd->flags & MTD_ERASE_PARTIAL) {
++		/* round up len to next erasesize and round down offset to prev block */
++		len = (mtd_div_by_eb(len, part->parent) + 1) * part->parent->erasesize;
++		ofs &= ~(part->parent->erasesize - 1);
++	}
++
++	return part->parent->_unlock(part->parent, ofs, len);
+ }
+ 
+ static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/419-mtd-redboot-add-of_match_table-with-DT-binding.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/419-mtd-redboot-add-of_match_table-with-DT-binding.patch
new file mode 100644
index 0000000..7692f48
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/419-mtd-redboot-add-of_match_table-with-DT-binding.patch
@@ -0,0 +1,22 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Subject: [PATCH] mtd: redboot: add of_match_table with DT binding
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This allows parsing RedBoot compatible partitions for properly described
+flash device in DT.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+---
+
+--- a/drivers/mtd/parsers/redboot.c
++++ b/drivers/mtd/parsers/redboot.c
+@@ -305,6 +305,7 @@ static int parse_redboot_partitions(stru
+ 
+ static const struct of_device_id mtd_parser_redboot_of_match_table[] = {
+ 	{ .compatible = "redboot-fis" },
++	{ .compatible = "ecoscentric,redboot-fis-partitions" },
+ 	{},
+ };
+ MODULE_DEVICE_TABLE(of, mtd_parser_redboot_of_match_table);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/420-mtd-redboot_space.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/420-mtd-redboot_space.patch
new file mode 100644
index 0000000..a3cd4ec
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/420-mtd-redboot_space.patch
@@ -0,0 +1,41 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: add patch for including unpartitioned space in the rootfs partition for redboot devices (if applicable)
+
+[john@phrozen.org: used by ixp and others]
+
+lede-commit: 394918851f84e4d00fa16eb900e7700e95091f00
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ drivers/mtd/redboot.c | 19 +++++++++++++------
+ 1 file changed, 13 insertions(+), 6 deletions(-)
+
+--- a/drivers/mtd/parsers/redboot.c
++++ b/drivers/mtd/parsers/redboot.c
+@@ -279,14 +279,21 @@ static int parse_redboot_partitions(stru
+ #endif
+ 		names += strlen(names)+1;
+ 
+-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+ 		if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
+-			i++;
+-			parts[i].offset = parts[i-1].size + parts[i-1].offset;
+-			parts[i].size = fl->next->img->flash_base - parts[i].offset;
+-			parts[i].name = nullname;
+-		}
++			if (!strcmp(parts[i].name, "rootfs")) {
++				parts[i].size = fl->next->img->flash_base;
++				parts[i].size &= ~(master->erasesize - 1);
++				parts[i].size -= parts[i].offset;
++#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
++				nrparts--;
++			} else {
++				i++;
++				parts[i].offset = parts[i-1].size + parts[i-1].offset;
++				parts[i].size = fl->next->img->flash_base - parts[i].offset;
++				parts[i].name = nullname;
+ #endif
++			}
++		}
+ 		tmp_fl = fl;
+ 		fl = fl->next;
+ 		kfree(tmp_fl);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/430-mtd-add-myloader-partition-parser.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/430-mtd-add-myloader-partition-parser.patch
new file mode 100644
index 0000000..3319ed9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/430-mtd-add-myloader-partition-parser.patch
@@ -0,0 +1,229 @@
+From: Florian Fainelli <f.fainelli@gmail.com>
+Subject: Add myloader partition table parser
+
+[john@phozen.org: shoud be upstreamable]
+
+lede-commit: d8bf22859b51faa09d22c056fe221a45d2f7a3b8
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+[adjust for kernel 5.4, add myloader.c to patch]
+Signed-off-by: Adrian Schmutzler <freifunk@adrianschmutzler.de>
+
+--- a/drivers/mtd/parsers/Kconfig
++++ b/drivers/mtd/parsers/Kconfig
+@@ -57,6 +57,22 @@ config MTD_CMDLINE_PARTS
+ 
+ 	  If unsure, say 'N'.
+ 
++config MTD_MYLOADER_PARTS
++	tristate "MyLoader partition parsing"
++	depends on ADM5120 || ATH25 || ATH79
++	---help---
++	  MyLoader is a bootloader which allows the user to define partitions
++	  in flash devices, by putting a table in the second erase block
++	  on the device, similar to a partition table. This table gives the 
++	  offsets and lengths of the user defined partitions.
++
++	  If you need code which can detect and parse these tables, and
++	  register MTD 'partitions' corresponding to each image detected,
++	  enable this option.
++
++	  You will still need the parsing functions to be called by the driver
++	  for your particular device. It won't happen automatically.
++
+ config MTD_OF_PARTS
+ 	tristate "OpenFirmware (device tree) partitioning parser"
+ 	default y
+--- a/drivers/mtd/parsers/Makefile
++++ b/drivers/mtd/parsers/Makefile
+@@ -3,6 +3,7 @@ obj-$(CONFIG_MTD_AR7_PARTS)		+= ar7part.
+ obj-$(CONFIG_MTD_BCM47XX_PARTS)		+= bcm47xxpart.o
+ obj-$(CONFIG_MTD_BCM63XX_PARTS)		+= bcm63xxpart.o
+ obj-$(CONFIG_MTD_CMDLINE_PARTS)		+= cmdlinepart.o
++obj-$(CONFIG_MTD_MYLOADER_PARTS)		+= myloader.o
+ obj-$(CONFIG_MTD_OF_PARTS)		+= ofpart.o
+ ofpart-y				+= ofpart_core.o
+ ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908)	+= ofpart_bcm4908.o
+--- /dev/null
++++ b/drivers/mtd/parsers/myloader.c
+@@ -0,0 +1,181 @@
++/*
++ *  Parse MyLoader-style flash partition tables and produce a Linux partition
++ *  array to match.
++ *
++ *  Copyright (C) 2007-2009 Gabor Juhos <juhosg@openwrt.org>
++ *
++ *  This file was based on drivers/mtd/redboot.c
++ *  Author: Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/vmalloc.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/byteorder/generic.h>
++#include <linux/myloader.h>
++
++#define BLOCK_LEN_MIN		0x10000
++#define PART_NAME_LEN		32
++
++struct part_data {
++	struct mylo_partition_table	tab;
++	char names[MYLO_MAX_PARTITIONS][PART_NAME_LEN];
++};
++
++static int myloader_parse_partitions(struct mtd_info *master,
++				     const struct mtd_partition **pparts,
++				     struct mtd_part_parser_data *data)
++{
++	struct part_data *buf;
++	struct mylo_partition_table *tab;
++	struct mylo_partition *part;
++	struct mtd_partition *mtd_parts;
++	struct mtd_partition *mtd_part;
++	int num_parts;
++	int ret, i;
++	size_t retlen;
++	char *names;
++	unsigned long offset;
++	unsigned long blocklen;
++
++	buf = vmalloc(sizeof(*buf));
++	if (!buf) {
++		return -ENOMEM;
++		goto out;
++	}
++	tab = &buf->tab;
++
++	blocklen = master->erasesize;
++	if (blocklen < BLOCK_LEN_MIN)
++		blocklen = BLOCK_LEN_MIN;
++
++	offset = blocklen;
++
++	/* Find the partition table */
++	for (i = 0; i < 4; i++, offset += blocklen) {
++		printk(KERN_DEBUG "%s: searching for MyLoader partition table"
++				" at offset 0x%lx\n", master->name, offset);
++
++		ret = mtd_read(master, offset, sizeof(*buf), &retlen,
++			       (void *)buf);
++		if (ret)
++			goto out_free_buf;
++
++		if (retlen != sizeof(*buf)) {
++			ret = -EIO;
++			goto out_free_buf;
++		}
++
++		/* Check for Partition Table magic number */
++		if (tab->magic == le32_to_cpu(MYLO_MAGIC_PARTITIONS))
++			break;
++
++	}
++
++	if (tab->magic != le32_to_cpu(MYLO_MAGIC_PARTITIONS)) {
++		printk(KERN_DEBUG "%s: no MyLoader partition table found\n",
++			master->name);
++		ret = 0;
++		goto out_free_buf;
++	}
++
++	/* The MyLoader and the Partition Table is always present */
++	num_parts = 2;
++
++	/* Detect number of used partitions */
++	for (i = 0; i < MYLO_MAX_PARTITIONS; i++) {
++		part = &tab->partitions[i];
++
++		if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE)
++			continue;
++
++		num_parts++;
++	}
++
++	mtd_parts = kzalloc((num_parts * sizeof(*mtd_part) +
++				num_parts * PART_NAME_LEN), GFP_KERNEL);
++
++	if (!mtd_parts) {
++		ret = -ENOMEM;
++		goto out_free_buf;
++	}
++
++	mtd_part = mtd_parts;
++	names = (char *)&mtd_parts[num_parts];
++
++	strncpy(names, "myloader", PART_NAME_LEN);
++	mtd_part->name = names;
++	mtd_part->offset = 0;
++	mtd_part->size = offset;
++	mtd_part->mask_flags = MTD_WRITEABLE;
++	mtd_part++;
++	names += PART_NAME_LEN;
++
++	strncpy(names, "partition_table", PART_NAME_LEN);
++	mtd_part->name = names;
++	mtd_part->offset = offset;
++	mtd_part->size = blocklen;
++	mtd_part->mask_flags = MTD_WRITEABLE;
++	mtd_part++;
++	names += PART_NAME_LEN;
++
++	for (i = 0; i < MYLO_MAX_PARTITIONS; i++) {
++		part = &tab->partitions[i];
++
++		if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE)
++			continue;
++
++		if ((buf->names[i][0]) && (buf->names[i][0] != '\xff'))
++			strncpy(names, buf->names[i], PART_NAME_LEN);
++		else
++			snprintf(names, PART_NAME_LEN, "partition%d", i);
++
++		mtd_part->offset = le32_to_cpu(part->addr);
++		mtd_part->size = le32_to_cpu(part->size);
++		mtd_part->name = names;
++		mtd_part++;
++		names += PART_NAME_LEN;
++	}
++
++	*pparts = mtd_parts;
++	ret = num_parts;
++
++ out_free_buf:
++	vfree(buf);
++ out:
++	return ret;
++}
++
++static struct mtd_part_parser myloader_mtd_parser = {
++	.owner		= THIS_MODULE,
++	.parse_fn	= myloader_parse_partitions,
++	.name		= "MyLoader",
++};
++
++static int __init myloader_mtd_parser_init(void)
++{
++	register_mtd_parser(&myloader_mtd_parser);
++
++	return 0;
++}
++
++static void __exit myloader_mtd_parser_exit(void)
++{
++	deregister_mtd_parser(&myloader_mtd_parser);
++}
++
++module_init(myloader_mtd_parser_init);
++module_exit(myloader_mtd_parser_exit);
++
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_DESCRIPTION("Parsing code for MyLoader partition tables");
++MODULE_LICENSE("GPL v2");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch
new file mode 100644
index 0000000..2ea59cd
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch
@@ -0,0 +1,68 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Subject: [PATCH] mtd: bcm47xxpart: check for bad blocks when calculating offsets
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+
+--- a/drivers/mtd/parsers/parser_trx.c
++++ b/drivers/mtd/parsers/parser_trx.c
+@@ -25,6 +25,33 @@ struct trx_header {
+ 	uint32_t offset[3];
+ } __packed;
+ 
++/*
++ * Calculate real end offset (address) for a given amount of data. It checks
++ * all blocks skipping bad ones.
++ */
++static size_t parser_trx_real_offset(struct mtd_info *mtd, size_t bytes)
++{
++	size_t real_offset = 0;
++
++	if (mtd_block_isbad(mtd, real_offset))
++		pr_warn("Base offset shouldn't be at bad block");
++
++	while (bytes >= mtd->erasesize) {
++		bytes -= mtd->erasesize;
++		real_offset += mtd->erasesize;
++		while (mtd_block_isbad(mtd, real_offset)) {
++			real_offset += mtd->erasesize;
++
++			if (real_offset >= mtd->size)
++				return real_offset - mtd->erasesize;
++		}
++	}
++
++	real_offset += bytes;
++
++	return real_offset;
++}
++
+ static const char *parser_trx_data_part_name(struct mtd_info *master,
+ 					     size_t offset)
+ {
+@@ -79,21 +106,21 @@ static int parser_trx_parse(struct mtd_i
+ 	if (trx.offset[2]) {
+ 		part = &parts[curr_part++];
+ 		part->name = "loader";
+-		part->offset = trx.offset[i];
++		part->offset = parser_trx_real_offset(mtd, trx.offset[i]);
+ 		i++;
+ 	}
+ 
+ 	if (trx.offset[i]) {
+ 		part = &parts[curr_part++];
+ 		part->name = "linux";
+-		part->offset = trx.offset[i];
++		part->offset = parser_trx_real_offset(mtd, trx.offset[i]);
+ 		i++;
+ 	}
+ 
+ 	if (trx.offset[i]) {
+ 		part = &parts[curr_part++];
+-		part->name = parser_trx_data_part_name(mtd, trx.offset[i]);
+-		part->offset = trx.offset[i];
++		part->offset = parser_trx_real_offset(mtd, trx.offset[i]);
++		part->name = parser_trx_data_part_name(mtd, part->offset);
+ 		i++;
+ 	}
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch
new file mode 100644
index 0000000..852654d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch
@@ -0,0 +1,37 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Subject: mtd: bcm47xxpart: detect T_Meter partition
+
+It can be found on many Netgear devices. It consists of many 0x30 blocks
+starting with 4D 54.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/mtd/bcm47xxpart.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/mtd/parsers/bcm47xxpart.c
++++ b/drivers/mtd/parsers/bcm47xxpart.c
+@@ -35,6 +35,7 @@
+ #define NVRAM_HEADER			0x48534C46	/* FLSH */
+ #define POT_MAGIC1			0x54544f50	/* POTT */
+ #define POT_MAGIC2			0x504f		/* OP */
++#define T_METER_MAGIC			0x4D540000	/* MT */
+ #define ML_MAGIC1			0x39685a42
+ #define ML_MAGIC2			0x26594131
+ #define TRX_MAGIC			0x30524448
+@@ -178,6 +179,15 @@ static int bcm47xxpart_parse(struct mtd_
+ 					     MTD_WRITEABLE);
+ 			continue;
+ 		}
++
++		/* T_Meter */
++		if ((le32_to_cpu(buf[0x000 / 4]) & 0xFFFF0000) == T_METER_MAGIC &&
++		    (le32_to_cpu(buf[0x030 / 4]) & 0xFFFF0000) == T_METER_MAGIC &&
++		    (le32_to_cpu(buf[0x060 / 4]) & 0xFFFF0000) == T_METER_MAGIC) {
++			bcm47xxpart_add_part(&parts[curr_part++], "T_Meter", offset,
++					     MTD_WRITEABLE);
++			continue;
++		}
+ 
+ 		/* TRX */
+ 		if (buf[0x000 / 4] == TRX_MAGIC) {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/435-mtd-add-routerbootpart-parser-config.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/435-mtd-add-routerbootpart-parser-config.patch
new file mode 100644
index 0000000..ab1e09a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/435-mtd-add-routerbootpart-parser-config.patch
@@ -0,0 +1,38 @@
+From 4437e01fb6bca63fccdba5d6c44888b0935885c2 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Thibaut=20VAR=C3=88NE?= <hacks@slashdirt.org>
+Date: Tue, 24 Mar 2020 11:45:07 +0100
+Subject: [PATCH] generic: routerboot partition build bits (5.4)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch adds routerbootpart kernel build bits
+
+Signed-off-by: Thibaut VARÈNE <hacks@slashdirt.org>
+---
+ drivers/mtd/parsers/Kconfig  | 9 +++++++++
+ drivers/mtd/parsers/Makefile | 1 +
+ 2 files changed, 10 insertions(+)
+
+--- a/drivers/mtd/parsers/Kconfig
++++ b/drivers/mtd/parsers/Kconfig
+@@ -195,3 +195,12 @@ config MTD_REDBOOT_PARTS_READONLY
+ 	  'FIS directory' images, enable this option.
+ 
+ endif # MTD_REDBOOT_PARTS
++
++config MTD_ROUTERBOOT_PARTS
++	tristate "RouterBoot flash partition parser"
++	depends on MTD && OF
++	help
++	 MikroTik RouterBoot is implemented as a multi segment system on the
++	 flash, some of which are fixed and some of which are located at
++	 variable offsets. This parser handles both cases via properly
++	 formatted DTS.
+--- a/drivers/mtd/parsers/Makefile
++++ b/drivers/mtd/parsers/Makefile
+@@ -13,3 +13,4 @@ obj-$(CONFIG_MTD_AFS_PARTS)		+= afs.o
+ obj-$(CONFIG_MTD_PARSER_TRX)		+= parser_trx.o
+ obj-$(CONFIG_MTD_SHARPSL_PARTS)		+= sharpslpart.o
+ obj-$(CONFIG_MTD_REDBOOT_PARTS)		+= redboot.o
++obj-$(CONFIG_MTD_ROUTERBOOT_PARTS)		+= routerbootpart.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/447-mtd-spinand-gigadevice-Add-support-for-GD5F4GQ4xC.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/447-mtd-spinand-gigadevice-Add-support-for-GD5F4GQ4xC.patch
new file mode 100644
index 0000000..e1fcb15
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/447-mtd-spinand-gigadevice-Add-support-for-GD5F4GQ4xC.patch
@@ -0,0 +1,87 @@
+From 30521ccfb4597f91b9e5c7967acef9c7c85e58a8 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Wed, 12 Aug 2020 22:50:26 +0200
+Subject: [PATCH v2 447/447] mtd: spinand: gigadevice: Add support for
+ GD5F4GQ4xC
+
+This adds support for the following 4GiB chips:
+GD5F4GQ4RCYIG 1.8V
+GD5F4GQ4UCYIG 3.3V
+
+The datasheet can be found here:
+https://www.novitronic.ch/sixcms/media.php/2/DS-00173-GD5F4GQ4xCxIG-Rev1.574695.pdf
+
+The GD5F4GQ4UCYIGT (3.3V) version is used on the Imagination
+Technologies Creator Ci40 (Marduk), the 1.8V version was not tested.
+
+This device only works in single SPI mode and not in dual or quad mode
+for me on this board.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/mtd/nand/spi/gigadevice.c | 49 +++++++++++++++++++++++++++++++
+ 1 file changed, 49 insertions(+)
+
+--- a/drivers/mtd/nand/spi/gigadevice.c
++++ b/drivers/mtd/nand/spi/gigadevice.c
+@@ -132,6 +132,35 @@ static const struct mtd_ooblayout_ops gd
+ 	.free = gd5fxgq4_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)
+ {
+@@ -222,6 +251,24 @@ static const struct spinand_info gigadev
+ 		     SPINAND_HAS_QE_BIT,
+ 		     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
+ 				     gd5fxgq4xa_ecc_get_status)),
++	SPINAND_INFO("GD5F4GQ4RC", 0xa468,
++		     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", 0xb468,
++		     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", 0xd1,
+ 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+ 		     NAND_ECCREQ(8, 512),
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/450-mtd-spi-nor-allow-NOR-driver-to-write-fewer-bytes-th.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/450-mtd-spi-nor-allow-NOR-driver-to-write-fewer-bytes-th.patch
new file mode 100644
index 0000000..fe2d7a6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/450-mtd-spi-nor-allow-NOR-driver-to-write-fewer-bytes-th.patch
@@ -0,0 +1,22 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 22 Feb 2018 11:11:57 +0100
+Subject: [PATCH] mtd: spi-nor: allow NOR driver to write fewer bytes than
+ requested
+
+The write size can be constrained by the maximum message/transfer size
+of the SPI controller. Only check for ret = 0 to avoid an infinite loop.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -2706,7 +2706,7 @@ static int spi_nor_write(struct mtd_info
+ 
+ 		write_enable(nor);
+ 		ret = spi_nor_write_data(nor, addr, page_remain, buf + i);
+-		if (ret < 0)
++		if (ret <= 0)
+ 			goto write_err;
+ 		written = ret;
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch
new file mode 100644
index 0000000..659a638
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch
@@ -0,0 +1,25 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: kernel: disable cfi cmdset 0002 erase suspend
+
+on some platforms, erase suspend leads to data corruption and lockups when write
+ops collide with erase ops. this has been observed on the buffalo wzr-hp-g300nh.
+rather than play whack-a-mole with a hard to reproduce issue on a variety of devices,
+simply disable erase suspend, as it will usually not produce any useful gain on
+the small filesystems used on embedded hardware.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ drivers/mtd/chips/cfi_cmdset_0002.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/mtd/chips/cfi_cmdset_0002.c
++++ b/drivers/mtd/chips/cfi_cmdset_0002.c
+@@ -909,7 +909,7 @@ static int get_chip(struct map_info *map
+ 		return 0;
+ 
+ 	case FL_ERASING:
+-		if (!cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
++		if (1 /* no suspend */ || !cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
+ 		    !(mode == FL_READY || mode == FL_POINT ||
+ 		    (mode == FL_WRITING && (cfip->EraseSuspend & 0x2))))
+ 			goto sleep;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch
new file mode 100644
index 0000000..8d2195e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch
@@ -0,0 +1,17 @@
+From: George Kashperko <george@znau.edu.ua>
+Subject: Issue map read after Write Buffer Load command to ensure chip is ready to receive data.
+
+Signed-off-by: George Kashperko <george@znau.edu.ua>
+---
+ drivers/mtd/chips/cfi_cmdset_0002.c |    1 +
+ 1 file changed, 1 insertion(+)
+--- a/drivers/mtd/chips/cfi_cmdset_0002.c
++++ b/drivers/mtd/chips/cfi_cmdset_0002.c
+@@ -2054,6 +2054,7 @@ static int __xipram do_write_buffer(stru
+ 
+ 	/* Write Buffer Load */
+ 	map_write(map, CMD(0x25), cmd_adr);
++	(void) map_read(map, cmd_adr);
+ 
+ 	chip->state = FL_WRITING_TO_BUFFER;
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/465-m25p80-mx-disable-software-protection.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/465-m25p80-mx-disable-software-protection.patch
new file mode 100644
index 0000000..24d2d45
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/465-m25p80-mx-disable-software-protection.patch
@@ -0,0 +1,18 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: Disable software protection bits for Macronix flashes.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -4884,6 +4884,7 @@ int spi_nor_scan(struct spi_nor *nor, co
+ 	 */
+ 	if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL ||
+ 	    JEDEC_MFR(nor->info) == SNOR_MFR_INTEL ||
++	    JEDEC_MFR(nor->info) == SNOR_MFR_MACRONIX ||
+ 	    JEDEC_MFR(nor->info) == SNOR_MFR_SST ||
+ 	    nor->info->flags & SPI_NOR_HAS_LOCK)
+ 		nor->clear_sr_bp = spi_nor_clear_sr_bp;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/466-Revert-mtd-spi-nor-fix-Spansion-regressions-aliased-.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/466-Revert-mtd-spi-nor-fix-Spansion-regressions-aliased-.patch
new file mode 100644
index 0000000..70f1e9f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/466-Revert-mtd-spi-nor-fix-Spansion-regressions-aliased-.patch
@@ -0,0 +1,35 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Tue, 9 Jan 2018 20:41:48 +0100
+Subject: [PATCH] Revert "mtd: spi-nor: fix Spansion regressions (aliased with
+ Winbond)"
+
+This reverts commit 67b9bcd36906e12a15ffec19463afbbd6a41660e.
+
+The underlying issue breaking Spansion flash has been fixed with "mtd: spi-nor:
+wait until lock/unlock operations are ready" and "mtd: spi-nor: wait for SR_WIP
+to clear on initial unlock", so we can support unlocking for Winbond flash
+again.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -4398,6 +4398,7 @@ static void st_micron_set_default_init(s
+ 
+ static void winbond_set_default_init(struct spi_nor *nor)
+ {
++	nor->flags |= SNOR_F_HAS_LOCK;
+ 	nor->params.set_4byte = winbond_set_4byte;
+ }
+ 
+@@ -4886,6 +4887,7 @@ int spi_nor_scan(struct spi_nor *nor, co
+ 	    JEDEC_MFR(nor->info) == SNOR_MFR_INTEL ||
+ 	    JEDEC_MFR(nor->info) == SNOR_MFR_MACRONIX ||
+ 	    JEDEC_MFR(nor->info) == SNOR_MFR_SST ||
++	    JEDEC_MFR(nor->info) == SNOR_MFR_WINBOND ||
+ 	    nor->info->flags & SPI_NOR_HAS_LOCK)
+ 		nor->clear_sr_bp = spi_nor_clear_sr_bp;
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/470-mtd-spi-nor-support-limiting-4K-sectors-support-base.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/470-mtd-spi-nor-support-limiting-4K-sectors-support-base.patch
new file mode 100644
index 0000000..d3e587f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/470-mtd-spi-nor-support-limiting-4K-sectors-support-base.patch
@@ -0,0 +1,79 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 4 Nov 2017 07:40:23 +0100
+Subject: [PATCH] mtd: spi-nor: support limiting 4K sectors support based on
+ flash size
+
+Some devices need 4K sectors to be able to deal with small flash chips.
+For instance, w25x05 is 64 KiB in size, and without 4K sectors, the
+entire chip is just one erase block.
+On bigger flash chip sizes, using 4K sectors can significantly slow down
+many operations, including using a writable filesystem. There are several
+platforms where it makes sense to use a single kernel on both kinds of
+devices.
+
+To support this properly, allow configuring an upper flash chip size
+limit for 4K sectors support.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/mtd/spi-nor/Kconfig
++++ b/drivers/mtd/spi-nor/Kconfig
+@@ -34,6 +34,17 @@ config SPI_ASPEED_SMC
+ 	  and support for the SPI flash memory controller (SPI) for
+ 	  the host firmware. The implementation only supports SPI NOR.
+ 
++config MTD_SPI_NOR_USE_4K_SECTORS_LIMIT
++	int "Maximum flash chip size to use 4K sectors on (in KiB)"
++	depends on MTD_SPI_NOR_USE_4K_SECTORS
++	default "4096"
++	help
++	  There are many flash chips that support 4K sectors, but are so large
++	  that using them significantly slows down writing large amounts of
++	  data or using a writable filesystem.
++	  Any flash chip larger than the size specified in this option will
++	  not use 4K sectors.
++
+ config SPI_CADENCE_QUADSPI
+ 	tristate "Cadence Quad SPI controller"
+ 	depends on OF && (ARM || ARM64 || COMPILE_TEST)
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -4464,6 +4464,7 @@ static void spi_nor_info_init_params(str
+ 	struct spi_nor_erase_map *map = &params->erase_map;
+ 	const struct flash_info *info = nor->info;
+ 	struct device_node *np = spi_nor_get_flash_node(nor);
++	struct mtd_info *mtd = &nor->mtd;
+ 	u8 i, erase_mask;
+ 
+ 	/* Initialize legacy flash parameters and settings. */
+@@ -4527,6 +4528,21 @@ static void spi_nor_info_init_params(str
+ 	 */
+ 	erase_mask = 0;
+ 	i = 0;
++#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
++	if ((info->flags & SECT_4K_PMC) && (mtd->size <=
++		   CONFIG_MTD_SPI_NOR_USE_4K_SECTORS_LIMIT * 1024)) {
++		erase_mask |= BIT(i);
++		spi_nor_set_erase_type(&map->erase_type[i], 4096u,
++				       SPINOR_OP_BE_4K_PMC);
++		i++;
++	} else if ((info->flags & SECT_4K) && (mtd->size <=
++	    CONFIG_MTD_SPI_NOR_USE_4K_SECTORS_LIMIT * 1024)) {
++		erase_mask |= BIT(i);
++		spi_nor_set_erase_type(&map->erase_type[i], 4096u,
++				       SPINOR_OP_BE_4K);
++		i++;
++	}
++#else
+ 	if (info->flags & SECT_4K_PMC) {
+ 		erase_mask |= BIT(i);
+ 		spi_nor_set_erase_type(&map->erase_type[i], 4096u,
+@@ -4538,6 +4554,7 @@ static void spi_nor_info_init_params(str
+ 				       SPINOR_OP_BE_4K);
+ 		i++;
+ 	}
++#endif
+ 	erase_mask |= BIT(i);
+ 	spi_nor_set_erase_type(&map->erase_type[i], info->sector_size,
+ 			       SPINOR_OP_SE);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/476-mtd-spi-nor-add-eon-en25q128.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/476-mtd-spi-nor-add-eon-en25q128.patch
new file mode 100644
index 0000000..b62dae5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/476-mtd-spi-nor-add-eon-en25q128.patch
@@ -0,0 +1,18 @@
+From: Piotr Dymacz <pepe2k@gmail.com>
+Subject: kernel/mtd: add support for EON EN25Q128
+
+Signed-off-by: Piotr Dymacz <pepe2k@gmail.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -2179,6 +2179,7 @@ static const struct flash_info spi_nor_i
+ 	{ "en25q32b",   INFO(0x1c3016, 0, 64 * 1024,   64, 0) },
+ 	{ "en25p64",    INFO(0x1c2017, 0, 64 * 1024,  128, 0) },
+ 	{ "en25q64",    INFO(0x1c3017, 0, 64 * 1024,  128, SECT_4K) },
++	{ "en25q128",   INFO(0x1c3018, 0, 64 * 1024,  256, SECT_4K) },
+ 	{ "en25q80a",   INFO(0x1c3014, 0, 64 * 1024,   16,
+ 			SECT_4K | SPI_NOR_DUAL_READ) },
+ 	{ "en25qh32",   INFO(0x1c7016, 0, 64 * 1024,   64, 0) },
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/479-mtd-spi-nor-add-xtx-xt25f128b.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/479-mtd-spi-nor-add-xtx-xt25f128b.patch
new file mode 100644
index 0000000..39e0260
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/479-mtd-spi-nor-add-xtx-xt25f128b.patch
@@ -0,0 +1,42 @@
+From patchwork Thu Feb  6 17:19:41 2020
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
+X-Patchwork-Id: 1234465
+Date: Thu, 6 Feb 2020 19:19:41 +0200
+From: Daniel Golle <daniel@makrotopia.org>
+To: linux-mtd@lists.infradead.org
+Subject: [PATCH v2] mtd: spi-nor: Add support for xt25f128b chip
+Message-ID: <20200206171941.GA2398@makrotopia.org>
+MIME-Version: 1.0
+Content-Disposition: inline
+List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-mtd>,
+ <mailto:linux-mtd-request@lists.infradead.org?subject=subscribe>
+Cc: Eitan Cohen <eitan@neot-semadar.com>, Piotr Dymacz <pepe2k@gmail.com>,
+ Tudor Ambarus <tudor.ambarus@microchip.com>
+Sender: "linux-mtd" <linux-mtd-bounces@lists.infradead.org>
+Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org
+
+Add XT25F128B made by XTX Technology (Shenzhen) Limited.
+This chip supports dual and quad read and uniform 4K-byte erase.
+Verified on Teltonika RUT955 which comes with XT25F128B in recent
+versions of the device.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -2506,6 +2506,9 @@ static const struct flash_info spi_nor_i
+ 	/* XMC (Wuhan Xinxin Semiconductor Manufacturing Corp.) */
+ 	{ "XM25QH64A", INFO(0x207017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ 	{ "XM25QH128A", INFO(0x207018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++
++	/* XTX Technology (Shenzhen) Limited */
++	{ "xt25f128b", INFO(0x0B4018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ 	{ },
+ };
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/480-mtd-set-rootfs-to-be-root-dev.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/480-mtd-set-rootfs-to-be-root-dev.patch
new file mode 100644
index 0000000..95863d6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/480-mtd-set-rootfs-to-be-root-dev.patch
@@ -0,0 +1,38 @@
+From: Gabor Juhos <juhosg@openwrt.org>
+Subject: kernel/3.1[02]: move MTD root device setup code to mtdcore
+
+The current code only allows to automatically set
+root device on MTD partitions. Move the code to MTD
+core to allow to use it with all MTD devices.
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ drivers/mtd/mtdcore.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/mtd/mtdcore.c
++++ b/drivers/mtd/mtdcore.c
+@@ -27,6 +27,7 @@
+ #include <linux/reboot.h>
+ #include <linux/leds.h>
+ #include <linux/debugfs.h>
++#include <linux/root_dev.h>
+ #include <linux/nvmem-provider.h>
+ 
+ #include <linux/mtd/mtd.h>
+@@ -699,6 +700,15 @@ int add_mtd_device(struct mtd_info *mtd)
+ 	   of this try_ nonsense, and no bitching about it
+ 	   either. :) */
+ 	__module_get(THIS_MODULE);
++
++	if (!strcmp(mtd->name, "rootfs") &&
++	    IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
++	    ROOT_DEV == 0) {
++		pr_notice("mtd: device %d (%s) set to be root filesystem\n",
++			  mtd->index, mtd->name);
++		ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index);
++	}
++
+ 	return 0;
+ 
+ fail_nvmem_add:
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/481-mtd-spi-nor-rework-broken-flash-reset-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/481-mtd-spi-nor-rework-broken-flash-reset-support.patch
new file mode 100644
index 0000000..81b4f19
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/481-mtd-spi-nor-rework-broken-flash-reset-support.patch
@@ -0,0 +1,167 @@
+From ea92cbb50a78404e29de2cc3999a240615ffb1c8 Mon Sep 17 00:00:00 2001
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Mon, 6 Apr 2020 17:58:48 +0800
+Subject: [PATCH] mtd: spi-nor: rework broken-flash-reset support
+
+Instead of resetting flash to 3B address on remove hook, this
+implementation only enters 4B mode when needed, which prevents
+more unexpected reboot stuck. This implementation makes it only
+break when a kernel panic happens during flash operation on 16M+
+areas.
+*OpenWrt only*: silent broken-flash-reset warning. We are not dealing
+with vendors and it's unpleasant for users to se that unnecessary
+and long WARN_ON print.
+
+Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 52 +++++++++++++++++++++++++++++++++--
+ 1 file changed, 49 insertions(+), 3 deletions(-)
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -616,6 +616,22 @@ static void spi_nor_set_4byte_opcodes(st
+ 	}
+ }
+ 
++static int spi_nor_check_set_addr_width(struct spi_nor *nor, loff_t addr)
++{
++	u8 addr_width;
++
++	if ((nor->flags & (SNOR_F_4B_OPCODES | SNOR_F_BROKEN_RESET)) !=
++	    SNOR_F_BROKEN_RESET)
++		return 0;
++
++	addr_width = addr & 0xff000000 ? 4 : 3;
++	if (nor->addr_width == addr_width)
++		return 0;
++
++	nor->addr_width = addr_width;
++	return nor->params.set_4byte(nor, addr_width == 4);
++}
++
+ static int macronix_set_4byte(struct spi_nor *nor, bool enable)
+ {
+ 	if (nor->spimem) {
+@@ -1261,6 +1277,10 @@ static int spi_nor_erase(struct mtd_info
+ 	if (ret)
+ 		return ret;
+ 
++	ret = spi_nor_check_set_addr_width(nor, instr->addr + instr->len);
++	if (ret < 0)
++		return ret;
++
+ 	/* whole-chip erase? */
+ 	if (len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) {
+ 		unsigned long timeout;
+@@ -1317,6 +1337,7 @@ static int spi_nor_erase(struct mtd_info
+ 	write_disable(nor);
+ 
+ erase_err:
++	spi_nor_check_set_addr_width(nor, 0);
+ 	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
+ 
+ 	return ret;
+@@ -1623,7 +1644,9 @@ static int spi_nor_lock(struct mtd_info
+ 	if (ret)
+ 		return ret;
+ 
++	spi_nor_check_set_addr_width(nor, ofs + len);
+ 	ret = nor->params.locking_ops->lock(nor, ofs, len);
++	spi_nor_check_set_addr_width(nor, 0);
+ 
+ 	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK);
+ 	return ret;
+@@ -1638,7 +1661,9 @@ static int spi_nor_unlock(struct mtd_inf
+ 	if (ret)
+ 		return ret;
+ 
++	spi_nor_check_set_addr_width(nor, ofs + len);
+ 	ret = nor->params.locking_ops->unlock(nor, ofs, len);
++	spi_nor_check_set_addr_width(nor, 0);
+ 
+ 	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK);
+ 	return ret;
+@@ -1653,7 +1678,9 @@ static int spi_nor_is_locked(struct mtd_
+ 	if (ret)
+ 		return ret;
+ 
++	spi_nor_check_set_addr_width(nor, ofs + len);
+ 	ret = nor->params.locking_ops->is_locked(nor, ofs, len);
++	spi_nor_check_set_addr_width(nor, 0);
+ 
+ 	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK);
+ 	return ret;
+@@ -2559,6 +2586,10 @@ static int spi_nor_read(struct mtd_info
+ 	if (ret)
+ 		return ret;
+ 
++	ret = spi_nor_check_set_addr_width(nor, from + len);
++	if (ret < 0)
++		return ret;
++
+ 	while (len) {
+ 		loff_t addr = from;
+ 
+@@ -2582,6 +2613,7 @@ static int spi_nor_read(struct mtd_info
+ 	ret = 0;
+ 
+ read_err:
++	spi_nor_check_set_addr_width(nor, 0);
+ 	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ);
+ 	return ret;
+ }
+@@ -2599,6 +2631,10 @@ static int sst_write(struct mtd_info *mt
+ 	if (ret)
+ 		return ret;
+ 
++	ret = spi_nor_check_set_addr_width(nor, to + len);
++	if (ret < 0)
++		return ret;
++
+ 	write_enable(nor);
+ 
+ 	nor->sst_write_second = false;
+@@ -2661,6 +2697,7 @@ static int sst_write(struct mtd_info *mt
+ 	}
+ sst_write_err:
+ 	*retlen += actual;
++	spi_nor_check_set_addr_width(nor, 0);
+ 	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
+ 	return ret;
+ }
+@@ -2683,6 +2720,10 @@ static int spi_nor_write(struct mtd_info
+ 	if (ret)
+ 		return ret;
+ 
++	ret = spi_nor_check_set_addr_width(nor, to + len);
++	if (ret < 0)
++		return ret;
++
+ 	for (i = 0; i < len; ) {
+ 		ssize_t written;
+ 		loff_t addr = to + i;
+@@ -2722,6 +2763,7 @@ static int spi_nor_write(struct mtd_info
+ 	}
+ 
+ write_err:
++	spi_nor_check_set_addr_width(nor, 0);
+ 	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
+ 	return ret;
+ }
+@@ -4726,9 +4768,13 @@ static int spi_nor_init(struct spi_nor *
+ 		 * reboots (e.g., crashes). Warn the user (or hopefully, system
+ 		 * designer) that this is bad.
+ 		 */
+-		WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET,
+-			  "enabling reset hack; may not recover from unexpected reboots\n");
+-		nor->params.set_4byte(nor, true);
++		if (nor->flags & SNOR_F_BROKEN_RESET) {
++			dev_warn(nor->dev,
++				"enabling reset hack; may not recover from unexpected reboots\n");
++			nor->addr_width = 3;
++		} else {
++			nor->params.set_4byte(nor, true);
++		}
+ 	}
+ 
+ 	return 0;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/482-mtd-spi-nor-add-support-for-Gigadevice-GD25D05.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/482-mtd-spi-nor-add-support-for-Gigadevice-GD25D05.patch
new file mode 100644
index 0000000..3a22133
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/482-mtd-spi-nor-add-support-for-Gigadevice-GD25D05.patch
@@ -0,0 +1,24 @@
+From d68b4aa22e8c625685bfad642dd7337948dc0ad1 Mon Sep 17 00:00:00 2001
+From: Koen Vandeputte <koen.vandeputte@ncentric.com>
+Date: Mon, 6 Jan 2020 13:07:56 +0100
+Subject: [PATCH] mtd: spi-nor: add support for Gigadevice GD25D05
+
+Signed-off-by: Koen Vandeputte <koen.vandeputte@ncentric.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -2232,6 +2232,11 @@ static const struct flash_info spi_nor_i
+ 
+ 	/* GigaDevice */
+ 	{
++		"gd25d05", INFO(0xc84010, 0, 64 * 1024,  1,
++			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
++			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
++	},
++	{
+ 		"gd25q16", INFO(0xc84015, 0, 64 * 1024,  32,
+ 			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+ 			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/482-mtd-spi-nor-fix-4-byte-opcode-support-for-w25q256.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/482-mtd-spi-nor-fix-4-byte-opcode-support-for-w25q256.patch
new file mode 100644
index 0000000..63366e6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/482-mtd-spi-nor-fix-4-byte-opcode-support-for-w25q256.patch
@@ -0,0 +1,60 @@
+From: Mantas Pucka <mantas@8devices.com>
+To: linux-mtd@lists.infradead.org
+Subject: [PATCH] mtd: spi-nor: fix 4-byte opcode support for w25q256
+Date: Wed, 15 Apr 2020 16:48:30 +0300
+Message-ID: <1586958510-24012-1-git-send-email-mantas@8devices.com>
+
+There are 2 different chips (w25q256fv and w25q256jv) that share
+the same JEDEC ID. Only w25q256jv fully supports 4-byte opcodes.
+Use SFDP header version to differentiate between them.
+
+for OpenWRT only: rebased to linux-v5.4
+
+Signed-off-by: Mantas Pucka <mantas@8devices.com>
+---
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -2172,6 +2172,32 @@ static struct spi_nor_fixups gd25q256_fi
+ 	.default_init = gd25q256_default_init,
+ };
+ 
++static int
++w25q256_post_bfpt_fixups(struct spi_nor *nor,
++			 const struct sfdp_parameter_header *bfpt_header,
++			 const struct sfdp_bfpt *bfpt,
++			 struct spi_nor_flash_parameter *params)
++{
++	/*
++	 * W25Q256JV supports 4B opcodes but W25Q256FV does not.
++	 * Unfortunately, Winbond has re-used the same JEDEC ID for both
++	 * variants which prevents us from defining a new entry in the parts
++	 * table.
++	 * To differentiate between W25Q256JV and W25Q256FV check SFDP header
++	 * version: only JV has JESD216A compliant structure (version 5)
++	 */
++
++	if (bfpt_header->major == SFDP_JESD216_MAJOR &&
++	    bfpt_header->minor == SFDP_JESD216A_MINOR)
++		nor->flags |= SNOR_F_4B_OPCODES;
++
++	return 0;
++}
++
++static struct spi_nor_fixups w25q256_fixups = {
++	.post_bfpt = w25q256_post_bfpt_fixups,
++};
++
+ /* NOTE: double check command sets and memory organization when you add
+  * more nor chips.  This current list focusses on newer chips, which
+  * have been converging on command sets which including JEDEC ID.
+@@ -2515,7 +2541,8 @@ static const struct flash_info spi_nor_i
+ 	{ "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) },
+ 	{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, SECT_4K) },
+ 	{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
+-	{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++	{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
++			  .fixups = &w25q256_fixups },
+ 	{ "w25q256jvm", INFO(0xef7019, 0, 64 * 1024, 512,
+ 			     SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ 	{ "w25m512jv", INFO(0xef7119, 0, 64 * 1024, 1024,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch
new file mode 100644
index 0000000..b21daea
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch
@@ -0,0 +1,97 @@
+From: Daniel Golle <daniel@makrotopia.org>
+Subject: ubi: auto-attach mtd device named "ubi" or "data" on boot
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mtd/ubi/build.c | 36 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+
+--- a/drivers/mtd/ubi/build.c
++++ b/drivers/mtd/ubi/build.c
+@@ -1168,6 +1168,73 @@ static struct mtd_info * __init open_mtd
+ 	return mtd;
+ }
+ 
++/*
++ * This function tries attaching mtd partitions named either "ubi" or "data"
++ * during boot.
++ */
++static void __init ubi_auto_attach(void)
++{
++	int err;
++	struct mtd_info *mtd;
++	loff_t offset = 0;
++	size_t len;
++	char magic[4];
++
++	/* try attaching mtd device named "ubi" or "data" */
++	mtd = open_mtd_device("ubi");
++	if (IS_ERR(mtd))
++		mtd = open_mtd_device("data");
++
++	if (IS_ERR(mtd))
++		return;
++
++	/* get the first not bad block */
++	if (mtd_can_have_bb(mtd))
++		while (mtd_block_isbad(mtd, offset)) {
++			offset += mtd->erasesize;
++
++			if (offset > mtd->size) {
++				pr_err("UBI error: Failed to find a non-bad "
++				       "block on mtd%d\n", mtd->index);
++				goto cleanup;
++			}
++		}
++
++	/* check if the read from flash was successful */
++	err = mtd_read(mtd, offset, 4, &len, (void *) magic);
++	if ((err && !mtd_is_bitflip(err)) || len != 4) {
++		pr_err("UBI error: unable to read from mtd%d\n", mtd->index);
++		goto cleanup;
++	}
++
++	/* check for a valid ubi magic */
++	if (strncmp(magic, "UBI#", 4)) {
++		pr_err("UBI error: no valid UBI magic found inside mtd%d\n", mtd->index);
++		goto cleanup;
++	}
++
++	/* don't auto-add media types where UBI doesn't makes sense */
++	if (mtd->type != MTD_NANDFLASH &&
++	    mtd->type != MTD_NORFLASH &&
++	    mtd->type != MTD_DATAFLASH &&
++	    mtd->type != MTD_MLCNANDFLASH)
++		goto cleanup;
++
++	mutex_lock(&ubi_devices_mutex);
++	pr_notice("UBI: auto-attach mtd%d\n", mtd->index);
++	err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0);
++	mutex_unlock(&ubi_devices_mutex);
++	if (err < 0) {
++		pr_err("UBI error: cannot attach mtd%d\n", mtd->index);
++		goto cleanup;
++	}
++
++	return;
++
++cleanup:
++	put_mtd_device(mtd);
++}
++
+ static int __init ubi_init(void)
+ {
+ 	int err, i, k;
+@@ -1251,6 +1318,12 @@ static int __init ubi_init(void)
+ 		}
+ 	}
+ 
++	/* auto-attach mtd devices only if built-in to the kernel and no ubi.mtd
++	 * parameter was given */
++	if (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
++	    !ubi_is_module() && !mtd_devs)
++		ubi_auto_attach();
++
+ 	err = ubiblock_init();
+ 	if (err) {
+ 		pr_err("UBI error: block: cannot initialize, error %d\n", err);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/491-ubi-auto-create-ubiblock-device-for-rootfs.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/491-ubi-auto-create-ubiblock-device-for-rootfs.patch
new file mode 100644
index 0000000..61fcbac
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/491-ubi-auto-create-ubiblock-device-for-rootfs.patch
@@ -0,0 +1,66 @@
+From: Daniel Golle <daniel@makrotopia.org>
+Subject: ubi: auto-create ubiblock device for rootfs
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mtd/ubi/block.c | 42 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 42 insertions(+)
+
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -652,6 +652,44 @@ static void __init ubiblock_create_from_
+ 	}
+ }
+ 
++#define UBIFS_NODE_MAGIC  0x06101831
++static inline int ubi_vol_is_ubifs(struct ubi_volume_desc *desc)
++{
++	int ret;
++	uint32_t magic_of, magic;
++	ret = ubi_read(desc, 0, (char *)&magic_of, 0, 4);
++	if (ret)
++		return 0;
++	magic = le32_to_cpu(magic_of);
++	return magic == UBIFS_NODE_MAGIC;
++}
++
++static void __init ubiblock_create_auto_rootfs(void)
++{
++	int ubi_num, ret, is_ubifs;
++	struct ubi_volume_desc *desc;
++	struct ubi_volume_info vi;
++
++	for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) {
++		desc = ubi_open_volume_nm(ubi_num, "rootfs", UBI_READONLY);
++		if (IS_ERR(desc))
++			continue;
++
++		ubi_get_volume_info(desc, &vi);
++		is_ubifs = ubi_vol_is_ubifs(desc);
++		ubi_close_volume(desc);
++		if (is_ubifs)
++			break;
++
++		ret = ubiblock_create(&vi);
++		if (ret)
++			pr_err("UBI error: block: can't add '%s' volume, err=%d\n",
++				vi.name, ret);
++		/* always break if we get here */
++		break;
++	}
++}
++
+ static void ubiblock_remove_all(void)
+ {
+ 	struct ubiblock *next;
+@@ -684,6 +722,10 @@ int __init ubiblock_init(void)
+ 	 */
+ 	ubiblock_create_from_param();
+ 
++	/* auto-attach "rootfs" volume if existing and non-ubifs */
++	if (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV))
++		ubiblock_create_auto_rootfs();
++
+ 	/*
+ 	 * Block devices are only created upon user requests, so we ignore
+ 	 * existing volumes.
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch
new file mode 100644
index 0000000..aa61f4a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch
@@ -0,0 +1,51 @@
+From: Daniel Golle <daniel@makrotopia.org>
+Subject: try auto-mounting ubi0:rootfs in init/do_mounts.c
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ init/do_mounts.c | 26 +++++++++++++++++++++++++-
+ 1 file changed, 25 insertions(+), 1 deletion(-)
+
+--- a/init/do_mounts.c
++++ b/init/do_mounts.c
+@@ -460,7 +460,28 @@ retry:
+ out:
+ 	put_page(page);
+ }
+- 
++
++static int __init mount_ubi_rootfs(void)
++{
++	int flags = MS_SILENT;
++	int err, tried = 0;
++
++	while (tried < 2) {
++		err = do_mount_root("ubi0:rootfs", "ubifs", flags, \
++					root_mount_data);
++		switch (err) {
++			case -EACCES:
++				flags |= MS_RDONLY;
++				tried++;
++				break;
++			default:
++				return err;
++		}
++	}
++
++	return -EINVAL;
++}
++
+ #ifdef CONFIG_ROOT_NFS
+ 
+ #define NFSROOT_TIMEOUT_MIN	5
+@@ -554,6 +575,10 @@ void __init mount_root(void)
+ 			change_floppy("root floppy");
+ 	}
+ #endif
++#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
++	if (!mount_ubi_rootfs())
++		return;
++#endif
+ #ifdef CONFIG_BLOCK
+ 	{
+ 		int err = create_dev("/dev/root", ROOT_DEV);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch
new file mode 100644
index 0000000..2dff468
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch
@@ -0,0 +1,34 @@
+From: Daniel Golle <daniel@makrotopia.org>
+Subject: ubi: set ROOT_DEV to ubiblock "rootfs" if unset
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/mtd/ubi/block.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -42,6 +42,7 @@
+ #include <linux/scatterlist.h>
+ #include <linux/idr.h>
+ #include <asm/div64.h>
++#include <linux/root_dev.h>
+ 
+ #include "ubi-media.h"
+ #include "ubi.h"
+@@ -458,6 +459,15 @@ int ubiblock_create(struct ubi_volume_in
+ 	dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)",
+ 		 dev->ubi_num, dev->vol_id, vi->name);
+ 	mutex_unlock(&devices_mutex);
++
++	if (!strcmp(vi->name, "rootfs") &&
++	    IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
++	    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);
++		ROOT_DEV = MKDEV(gd->major, gd->first_minor);
++	}
++
+ 	return 0;
+ 
+ out_free_queue:
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/494-mtd-ubi-add-EOF-marker-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/494-mtd-ubi-add-EOF-marker-support.patch
new file mode 100644
index 0000000..fc48146
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/494-mtd-ubi-add-EOF-marker-support.patch
@@ -0,0 +1,60 @@
+From: Gabor Juhos <juhosg@openwrt.org>
+Subject: mtd: add EOF marker support to the UBI layer
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ drivers/mtd/ubi/attach.c | 25 ++++++++++++++++++++++---
+ drivers/mtd/ubi/ubi.h    |  1 +
+ 2 files changed, 23 insertions(+), 3 deletions(-)
+
+--- a/drivers/mtd/ubi/attach.c
++++ b/drivers/mtd/ubi/attach.c
+@@ -926,6 +926,13 @@ static bool vol_ignored(int vol_id)
+ #endif
+ }
+ 
++static bool ec_hdr_has_eof(struct ubi_ec_hdr *ech)
++{
++	return ech->padding1[0] == 'E' &&
++	       ech->padding1[1] == 'O' &&
++	       ech->padding1[2] == 'F';
++}
++
+ /**
+  * scan_peb - scan and process UBI headers of a PEB.
+  * @ubi: UBI device description object
+@@ -958,9 +965,21 @@ static int scan_peb(struct ubi_device *u
+ 		return 0;
+ 	}
+ 
+-	err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
+-	if (err < 0)
+-		return err;
++	if (!ai->eof_found) {
++		err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
++		if (err < 0)
++			return err;
++
++		if (ec_hdr_has_eof(ech)) {
++			pr_notice("UBI: EOF marker found, PEBs from %d will be erased\n",
++				pnum);
++			ai->eof_found = true;
++		}
++	}
++
++	if (ai->eof_found)
++		err = UBI_IO_FF_BITFLIPS;
++
+ 	switch (err) {
+ 	case 0:
+ 		break;
+--- a/drivers/mtd/ubi/ubi.h
++++ b/drivers/mtd/ubi/ubi.h
+@@ -780,6 +780,7 @@ struct ubi_attach_info {
+ 	int mean_ec;
+ 	uint64_t ec_sum;
+ 	int ec_count;
++	bool eof_found;
+ 	struct kmem_cache *aeb_slab_cache;
+ 	struct ubi_ec_hdr *ech;
+ 	struct ubi_vid_io_buf *vidb;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/495-mtd-core-add-get_mtd_device_by_node.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/495-mtd-core-add-get_mtd_device_by_node.patch
new file mode 100644
index 0000000..a173381
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/495-mtd-core-add-get_mtd_device_by_node.patch
@@ -0,0 +1,75 @@
+From 1bd1b740f208d1cf4071932cc51860d37266c402 Mon Sep 17 00:00:00 2001
+From: Bernhard Frauendienst <kernel@nospam.obeliks.de>
+Date: Sat, 1 Sep 2018 00:30:11 +0200
+Subject: [PATCH 495/497] mtd: core: add get_mtd_device_by_node
+
+Add function to retrieve a mtd device by its OF node. Since drivers can
+assign arbitrary names to mtd devices in the absence of a label
+property, there is no other reliable way to retrieve a mtd device for a
+given OF node.
+
+Signed-off-by: Bernhard Frauendienst <kernel@nospam.obeliks.de>
+Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
+---
+ drivers/mtd/mtdcore.c   | 38 ++++++++++++++++++++++++++++++++++++++
+ include/linux/mtd/mtd.h |  2 ++
+ 2 files changed, 40 insertions(+)
+
+--- a/drivers/mtd/mtdcore.c
++++ b/drivers/mtd/mtdcore.c
+@@ -1053,6 +1053,44 @@ out_unlock:
+ }
+ EXPORT_SYMBOL_GPL(get_mtd_device_nm);
+ 
++/**
++ *	get_mtd_device_by_node - obtain a validated handle for an MTD device
++ *	by of_node
++ *	@of_node: OF node of MTD device to open
++ *
++ *	This function returns MTD device description structure in case of
++ *	success and an error code in case of failure.
++ */
++struct mtd_info *get_mtd_device_by_node(const struct device_node *of_node)
++{
++	int err = -ENODEV;
++	struct mtd_info *mtd = NULL, *other;
++
++	mutex_lock(&mtd_table_mutex);
++
++	mtd_for_each_device(other) {
++		if (of_node == other->dev.of_node) {
++			mtd = other;
++			break;
++		}
++	}
++
++	if (!mtd)
++		goto out_unlock;
++
++	err = __get_mtd_device(mtd);
++	if (err)
++		goto out_unlock;
++
++	mutex_unlock(&mtd_table_mutex);
++	return mtd;
++
++out_unlock:
++	mutex_unlock(&mtd_table_mutex);
++	return ERR_PTR(err);
++}
++EXPORT_SYMBOL_GPL(get_mtd_device_by_node);
++
+ void put_mtd_device(struct mtd_info *mtd)
+ {
+ 	mutex_lock(&mtd_table_mutex);
+--- a/include/linux/mtd/mtd.h
++++ b/include/linux/mtd/mtd.h
+@@ -586,6 +586,8 @@ extern struct mtd_info *get_mtd_device(s
+ extern int __get_mtd_device(struct mtd_info *mtd);
+ extern void __put_mtd_device(struct mtd_info *mtd);
+ extern struct mtd_info *get_mtd_device_nm(const char *name);
++extern struct mtd_info *get_mtd_device_by_node(
++		const struct device_node *of_node);
+ extern void put_mtd_device(struct mtd_info *mtd);
+ 
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/496-dt-bindings-add-bindings-for-mtd-concat-devices.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/496-dt-bindings-add-bindings-for-mtd-concat-devices.patch
new file mode 100644
index 0000000..01f3b9e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/496-dt-bindings-add-bindings-for-mtd-concat-devices.patch
@@ -0,0 +1,52 @@
+From 5734c6669fba7ddb5ef491ccff7159d15dba0b59 Mon Sep 17 00:00:00 2001
+From: Bernhard Frauendienst <kernel@nospam.obeliks.de>
+Date: Wed, 5 Sep 2018 01:32:51 +0200
+Subject: [PATCH 496/497] dt-bindings: add bindings for mtd-concat devices
+
+Document virtual mtd-concat device bindings.
+
+Signed-off-by: Bernhard Frauendienst <kernel@nospam.obeliks.de>
+---
+ .../devicetree/bindings/mtd/mtd-concat.txt    | 36 +++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/mtd/mtd-concat.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mtd/mtd-concat.txt
+@@ -0,0 +1,36 @@
++Virtual MTD concat device
++
++Requires properties:
++- devices: list of phandles to mtd nodes that should be concatenated
++
++Example:
++
++&spi {
++	flash0: flash@0 {
++		...
++	};
++	flash1: flash@1 {
++		...
++	};
++};
++
++flash {
++	compatible = "mtd-concat";
++
++	devices = <&flash0 &flash1>;
++
++	partitions {
++		compatible = "fixed-partitions";
++
++		partition@0 {
++			label = "boot";
++			reg = <0x0000000 0x0040000>;
++			read-only;
++		};
++
++		partition@40000 {
++			label = "firmware";
++			reg = <0x0040000 0x1fc0000>;
++		};
++	}
++}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/497-mtd-mtdconcat-add-dt-driver-for-concat-devices.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/497-mtd-mtdconcat-add-dt-driver-for-concat-devices.patch
new file mode 100644
index 0000000..1c42ed7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/497-mtd-mtdconcat-add-dt-driver-for-concat-devices.patch
@@ -0,0 +1,216 @@
+From e53f712d8eac71f54399b61038ccf87d2cee99d7 Mon Sep 17 00:00:00 2001
+From: Bernhard Frauendienst <kernel@nospam.obeliks.de>
+Date: Sat, 25 Aug 2018 12:35:22 +0200
+Subject: [PATCH 497/497] mtd: mtdconcat: add dt driver for concat devices
+
+Some mtd drivers like physmap variants have support for concatenating
+multiple mtd devices, but there is no generic way to define such a
+concat device from within the device tree.
+
+This is useful for some SoC boards that use multiple flash chips as
+memory banks of a single mtd device, with partitions spanning chip
+borders.
+
+This commit adds a driver for creating virtual mtd-concat devices. They
+must have a compatible = "mtd-concat" line, and define a list of devices
+to concat in the 'devices' property, for example:
+
+flash {
+  compatible = "mtd-concat";
+
+  devices = <&flash0 &flash1>;
+
+  partitions {
+    ...
+  };
+};
+
+The driver is added to the very end of the mtd Makefile to increase the
+likelyhood of all child devices already being loaded at the time of
+probing, preventing unnecessary deferred probes.
+
+Signed-off-by: Bernhard Frauendienst <kernel@nospam.obeliks.de>
+---
+ drivers/mtd/Kconfig                 |   2 +
+ drivers/mtd/Makefile                |   3 +
+ drivers/mtd/composite/Kconfig       |  12 +++
+ drivers/mtd/composite/Makefile      |   6 ++
+ drivers/mtd/composite/virt_concat.c | 128 ++++++++++++++++++++++++++++
+ 5 files changed, 151 insertions(+)
+ create mode 100644 drivers/mtd/composite/Kconfig
+ create mode 100644 drivers/mtd/composite/Makefile
+ create mode 100644 drivers/mtd/composite/virt_concat.c
+
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -228,4 +228,6 @@ source "drivers/mtd/ubi/Kconfig"
+ 
+ source "drivers/mtd/hyperbus/Kconfig"
+ 
++source "drivers/mtd/composite/Kconfig"
++
+ endif # MTD
+--- a/drivers/mtd/Makefile
++++ b/drivers/mtd/Makefile
+@@ -32,3 +32,6 @@ obj-y		+= chips/ lpddr/ maps/ devices/ n
+ obj-$(CONFIG_MTD_SPI_NOR)	+= spi-nor/
+ obj-$(CONFIG_MTD_UBI)		+= ubi/
+ obj-$(CONFIG_MTD_HYPERBUS)	+= hyperbus/
++
++# Composite drivers must be loaded last
++obj-y				+= composite/
+--- /dev/null
++++ b/drivers/mtd/composite/Kconfig
+@@ -0,0 +1,12 @@
++menu "Composite MTD device drivers"
++	depends on MTD!=n
++
++config MTD_VIRT_CONCAT
++	tristate "Virtual concat MTD device"
++	help
++	  This driver allows creation of a virtual MTD concat device, which
++	  concatenates multiple underlying MTD devices to a single device.
++	  This is required by some SoC boards where multiple memory banks are
++	  used as one device with partitions spanning across device boundaries.
++
++endmenu
+--- /dev/null
++++ b/drivers/mtd/composite/Makefile
+@@ -0,0 +1,6 @@
++# SPDX-License-Identifier: GPL-2.0
++#
++# linux/drivers/mtd/composite/Makefile
++#
++
++obj-$(CONFIG_MTD_VIRT_CONCAT)   += virt_concat.o
+--- /dev/null
++++ b/drivers/mtd/composite/virt_concat.c
+@@ -0,0 +1,128 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Virtual concat MTD device driver
++ *
++ * Copyright (C) 2018 Bernhard Frauendienst
++ * Author: Bernhard Frauendienst, kernel@nospam.obeliks.de
++ */
++
++#include <linux/module.h>
++#include <linux/device.h>
++#include <linux/mtd/concat.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/of.h>
++#include <linux/of_platform.h>
++#include <linux/slab.h>
++
++/*
++ * struct of_virt_concat - platform device driver data.
++ * @cmtd the final mtd_concat device
++ * @num_devices the number of devices in @devices
++ * @devices points to an array of devices already loaded
++ */
++struct of_virt_concat {
++	struct mtd_info	*cmtd;
++	int num_devices;
++	struct mtd_info	**devices;
++};
++
++static int virt_concat_remove(struct platform_device *pdev)
++{
++	struct of_virt_concat *info;
++	int i;
++
++	info = platform_get_drvdata(pdev);
++	if (!info)
++		return 0;
++
++	// unset data for when this is called after a probe error
++	platform_set_drvdata(pdev, NULL);
++
++	if (info->cmtd) {
++		mtd_device_unregister(info->cmtd);
++		mtd_concat_destroy(info->cmtd);
++	}
++
++	if (info->devices) {
++		for (i = 0; i < info->num_devices; i++)
++			put_mtd_device(info->devices[i]);
++	}
++
++	return 0;
++}
++
++static int virt_concat_probe(struct platform_device *pdev)
++{
++	struct device_node *node = pdev->dev.of_node;
++	struct of_phandle_iterator it;
++	struct of_virt_concat *info;
++	struct mtd_info *mtd;
++	int err = 0, count;
++
++	count = of_count_phandle_with_args(node, "devices", NULL);
++	if (count <= 0)
++		return -EINVAL;
++
++	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
++	if (!info)
++		return -ENOMEM;
++	info->devices = devm_kcalloc(&pdev->dev, count,
++				     sizeof(*(info->devices)), GFP_KERNEL);
++	if (!info->devices) {
++		err = -ENOMEM;
++		goto err_remove;
++	}
++
++	platform_set_drvdata(pdev, info);
++
++	of_for_each_phandle(&it, err, node, "devices", NULL, 0) {
++		mtd = get_mtd_device_by_node(it.node);
++		if (IS_ERR(mtd)) {
++			of_node_put(it.node);
++			err = -EPROBE_DEFER;
++			goto err_remove;
++		}
++
++		info->devices[info->num_devices++] = mtd;
++	}
++
++	info->cmtd = mtd_concat_create(info->devices, info->num_devices,
++				       dev_name(&pdev->dev));
++	if (!info->cmtd) {
++		err = -ENXIO;
++		goto err_remove;
++	}
++
++	info->cmtd->dev.parent = &pdev->dev;
++	mtd_set_of_node(info->cmtd, node);
++	mtd_device_register(info->cmtd, NULL, 0);
++
++	return 0;
++
++err_remove:
++	virt_concat_remove(pdev);
++
++	return err;
++}
++
++static const struct of_device_id virt_concat_of_match[] = {
++	{ .compatible = "mtd-concat", },
++	{ /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, virt_concat_of_match);
++
++static struct platform_driver virt_concat_driver = {
++	.probe = virt_concat_probe,
++	.remove = virt_concat_remove,
++	.driver	 = {
++		.name   = "virt-mtdconcat",
++		.of_match_table = virt_concat_of_match,
++	},
++};
++
++module_platform_driver(virt_concat_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Bernhard Frauendienst <kernel@nospam.obeliks.de>");
++MODULE_DESCRIPTION("Virtual concat MTD device driver");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/498-mtd-mtdconcat-select-readwrite-function.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/498-mtd-mtdconcat-select-readwrite-function.patch
new file mode 100644
index 0000000..129bbff
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/498-mtd-mtdconcat-select-readwrite-function.patch
@@ -0,0 +1,24 @@
+--- a/drivers/mtd/mtdconcat.c
++++ b/drivers/mtd/mtdconcat.c
+@@ -642,8 +642,12 @@ struct mtd_info *mtd_concat_create(struc
+ 		concat->mtd._writev = concat_writev;
+ 	if (subdev[0]->_read_oob)
+ 		concat->mtd._read_oob = concat_read_oob;
++	else
++		concat->mtd._read = concat_read;
+ 	if (subdev[0]->_write_oob)
+ 		concat->mtd._write_oob = concat_write_oob;
++	else
++		concat->mtd._write = concat_write;
+ 	if (subdev[0]->_block_isbad)
+ 		concat->mtd._block_isbad = concat_block_isbad;
+ 	if (subdev[0]->_block_markbad)
+@@ -701,8 +705,6 @@ struct mtd_info *mtd_concat_create(struc
+ 	concat->mtd.name = name;
+ 
+ 	concat->mtd._erase = concat_erase;
+-	concat->mtd._read = concat_read;
+-	concat->mtd._write = concat_write;
+ 	concat->mtd._sync = concat_sync;
+ 	concat->mtd._lock = concat_lock;
+ 	concat->mtd._unlock = concat_unlock;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/499-mtd-add-nmbm-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/499-mtd-add-nmbm-support.patch
new file mode 100644
index 0000000..5cbaae2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/499-mtd-add-nmbm-support.patch
@@ -0,0 +1,21 @@
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -228,6 +228,8 @@ source "drivers/mtd/ubi/Kconfig"
+ 
+ source "drivers/mtd/hyperbus/Kconfig"
+ 
++source "drivers/mtd/nmbm/Kconfig"
++
+ source "drivers/mtd/composite/Kconfig"
+ 
+ endif # MTD
+--- a/drivers/mtd/Makefile
++++ b/drivers/mtd/Makefile
+@@ -33,5 +33,7 @@ obj-$(CONFIG_MTD_SPI_NOR)	+= spi-nor/
+ obj-$(CONFIG_MTD_UBI)		+= ubi/
+ obj-$(CONFIG_MTD_HYPERBUS)	+= hyperbus/
+ 
++obj-y				+= nmbm/
++
+ # Composite drivers must be loaded last
+ obj-y				+= composite/
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/530-jffs2_make_lzma_available.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/530-jffs2_make_lzma_available.patch
new file mode 100644
index 0000000..052db7e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/530-jffs2_make_lzma_available.patch
@@ -0,0 +1,5180 @@
+From: Alexandros C. Couloumbis <alex@ozo.com>
+Subject: fs: add jffs2/lzma support (not activated by default yet)
+
+lede-commit: c2c88d315fa0e881f8b19da07b62859b915b11b2
+Signed-off-by: Alexandros C. Couloumbis <alex@ozo.com>
+---
+ fs/jffs2/Kconfig             |    9 +
+ fs/jffs2/Makefile            |    3 +
+ fs/jffs2/compr.c             |    6 +
+ fs/jffs2/compr.h             |   10 +-
+ fs/jffs2/compr_lzma.c        |  128 +++
+ fs/jffs2/super.c             |   33 +-
+ include/linux/lzma.h         |   62 ++
+ include/linux/lzma/LzFind.h  |  115 +++
+ include/linux/lzma/LzHash.h  |   54 +
+ include/linux/lzma/LzmaDec.h |  231 +++++
+ include/linux/lzma/LzmaEnc.h |   80 ++
+ include/linux/lzma/Types.h   |  226 +++++
+ include/uapi/linux/jffs2.h   |    1 +
+ lib/Kconfig                  |    6 +
+ lib/Makefile                 |   12 +
+ lib/lzma/LzFind.c            |  761 ++++++++++++++
+ lib/lzma/LzmaDec.c           |  999 +++++++++++++++++++
+ lib/lzma/LzmaEnc.c           | 2271 ++++++++++++++++++++++++++++++++++++++++++
+ lib/lzma/Makefile            |    7 +
+ 19 files changed, 5008 insertions(+), 6 deletions(-)
+ create mode 100644 fs/jffs2/compr_lzma.c
+ create mode 100644 include/linux/lzma.h
+ create mode 100644 include/linux/lzma/LzFind.h
+ create mode 100644 include/linux/lzma/LzHash.h
+ create mode 100644 include/linux/lzma/LzmaDec.h
+ create mode 100644 include/linux/lzma/LzmaEnc.h
+ create mode 100644 include/linux/lzma/Types.h
+ create mode 100644 lib/lzma/LzFind.c
+ create mode 100644 lib/lzma/LzmaDec.c
+ create mode 100644 lib/lzma/LzmaEnc.c
+ create mode 100644 lib/lzma/Makefile
+
+--- a/fs/jffs2/Kconfig
++++ b/fs/jffs2/Kconfig
+@@ -136,6 +136,15 @@ config JFFS2_LZO
+ 	  This feature was added in July, 2007. Say 'N' if you need
+ 	  compatibility with older bootloaders or kernels.
+ 
++config JFFS2_LZMA
++	bool "JFFS2 LZMA compression support" if JFFS2_COMPRESSION_OPTIONS
++	select LZMA_COMPRESS
++	select LZMA_DECOMPRESS
++	depends on JFFS2_FS
++	default n
++	help
++	  JFFS2 wrapper to the LZMA C SDK
++
+ config JFFS2_RTIME
+ 	bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS
+ 	depends on JFFS2_FS
+--- a/fs/jffs2/Makefile
++++ b/fs/jffs2/Makefile
+@@ -19,4 +19,7 @@ jffs2-$(CONFIG_JFFS2_RUBIN)	+= compr_rub
+ jffs2-$(CONFIG_JFFS2_RTIME)	+= compr_rtime.o
+ jffs2-$(CONFIG_JFFS2_ZLIB)	+= compr_zlib.o
+ jffs2-$(CONFIG_JFFS2_LZO)	+= compr_lzo.o
++jffs2-$(CONFIG_JFFS2_LZMA)	+= compr_lzma.o
+ jffs2-$(CONFIG_JFFS2_SUMMARY)   += summary.o
++
++CFLAGS_compr_lzma.o += -Iinclude/linux -Ilib/lzma
+--- a/fs/jffs2/compr.c
++++ b/fs/jffs2/compr.c
+@@ -378,6 +378,9 @@ int __init jffs2_compressors_init(void)
+ #ifdef CONFIG_JFFS2_LZO
+ 	jffs2_lzo_init();
+ #endif
++#ifdef CONFIG_JFFS2_LZMA
++	jffs2_lzma_init();
++#endif
+ /* Setting default compression mode */
+ #ifdef CONFIG_JFFS2_CMODE_NONE
+ 	jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
+@@ -401,6 +404,9 @@ int __init jffs2_compressors_init(void)
+ int jffs2_compressors_exit(void)
+ {
+ /* Unregistering compressors */
++#ifdef CONFIG_JFFS2_LZMA
++	jffs2_lzma_exit();
++#endif
+ #ifdef CONFIG_JFFS2_LZO
+ 	jffs2_lzo_exit();
+ #endif
+--- a/fs/jffs2/compr.h
++++ b/fs/jffs2/compr.h
+@@ -29,9 +29,9 @@
+ #define JFFS2_DYNRUBIN_PRIORITY  20
+ #define JFFS2_LZARI_PRIORITY     30
+ #define JFFS2_RTIME_PRIORITY     50
+-#define JFFS2_ZLIB_PRIORITY      60
+-#define JFFS2_LZO_PRIORITY       80
+-
++#define JFFS2_LZMA_PRIORITY      70
++#define JFFS2_ZLIB_PRIORITY      80
++#define JFFS2_LZO_PRIORITY       90
+ 
+ #define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */
+ #define JFFS2_DYNRUBIN_DISABLED  /*	   for decompression */
+@@ -101,5 +101,9 @@ void jffs2_zlib_exit(void);
+ int jffs2_lzo_init(void);
+ void jffs2_lzo_exit(void);
+ #endif
++#ifdef CONFIG_JFFS2_LZMA
++int jffs2_lzma_init(void);
++void jffs2_lzma_exit(void);
++#endif
+ 
+ #endif /* __JFFS2_COMPR_H__ */
+--- /dev/null
++++ b/fs/jffs2/compr_lzma.c
+@@ -0,0 +1,128 @@
++/*
++ * JFFS2 -- Journalling Flash File System, Version 2.
++ *
++ * For licensing information, see the file 'LICENCE' in this directory.
++ *
++ * JFFS2 wrapper to the LZMA C SDK
++ *
++ */
++
++#include <linux/lzma.h>
++#include "compr.h"
++
++#ifdef __KERNEL__
++	static DEFINE_MUTEX(deflate_mutex);
++#endif
++
++CLzmaEncHandle *p;
++Byte propsEncoded[LZMA_PROPS_SIZE];
++SizeT propsSize = sizeof(propsEncoded);
++
++STATIC void lzma_free_workspace(void)
++{
++	LzmaEnc_Destroy(p, &lzma_alloc, &lzma_alloc);
++}
++
++STATIC int INIT lzma_alloc_workspace(CLzmaEncProps *props)
++{
++	if ((p = (CLzmaEncHandle *)LzmaEnc_Create(&lzma_alloc)) == NULL)
++	{
++		PRINT_ERROR("Failed to allocate lzma deflate workspace\n");
++		return -ENOMEM;
++	}
++
++	if (LzmaEnc_SetProps(p, props) != SZ_OK)
++	{
++		lzma_free_workspace();
++		return -1;
++	}
++
++	if (LzmaEnc_WriteProperties(p, propsEncoded, &propsSize) != SZ_OK)
++	{
++		lzma_free_workspace();
++		return -1;
++	}
++
++	return 0;
++}
++
++STATIC int jffs2_lzma_compress(unsigned char *data_in, unsigned char *cpage_out,
++			      uint32_t *sourcelen, uint32_t *dstlen)
++{
++	SizeT compress_size = (SizeT)(*dstlen);
++	int ret;
++
++	#ifdef __KERNEL__
++		mutex_lock(&deflate_mutex);
++	#endif
++
++	ret = LzmaEnc_MemEncode(p, cpage_out, &compress_size, data_in, *sourcelen,
++		0, NULL, &lzma_alloc, &lzma_alloc);
++
++	#ifdef __KERNEL__
++		mutex_unlock(&deflate_mutex);
++	#endif
++
++	if (ret != SZ_OK)
++		return -1;
++
++	*dstlen = (uint32_t)compress_size;
++
++	return 0;
++}
++
++STATIC int jffs2_lzma_decompress(unsigned char *data_in, unsigned char *cpage_out,
++				 uint32_t srclen, uint32_t destlen)
++{
++	int ret;
++	SizeT dl = (SizeT)destlen;
++	SizeT sl = (SizeT)srclen;
++	ELzmaStatus status;
++
++	ret = LzmaDecode(cpage_out, &dl, data_in, &sl, propsEncoded,
++		propsSize, LZMA_FINISH_ANY, &status, &lzma_alloc);
++
++	if (ret != SZ_OK || status == LZMA_STATUS_NOT_FINISHED || dl != (SizeT)destlen)
++		return -1;
++
++	return 0;
++}
++
++static struct jffs2_compressor jffs2_lzma_comp = {
++	.priority = JFFS2_LZMA_PRIORITY,
++	.name = "lzma",
++	.compr = JFFS2_COMPR_LZMA,
++	.compress = &jffs2_lzma_compress,
++	.decompress = &jffs2_lzma_decompress,
++	.disabled = 0,
++};
++
++int INIT jffs2_lzma_init(void)
++{
++	int ret;
++	CLzmaEncProps props;
++	LzmaEncProps_Init(&props);
++
++	props.dictSize = LZMA_BEST_DICT(0x2000);
++	props.level = LZMA_BEST_LEVEL;
++	props.lc = LZMA_BEST_LC;
++	props.lp = LZMA_BEST_LP;
++	props.pb = LZMA_BEST_PB;
++	props.fb = LZMA_BEST_FB;
++
++	ret = lzma_alloc_workspace(&props);
++	if (ret < 0)
++		return ret;
++
++	ret = jffs2_register_compressor(&jffs2_lzma_comp);
++	if (ret)
++		lzma_free_workspace();
++
++	return ret;
++}
++
++void jffs2_lzma_exit(void)
++{
++	jffs2_unregister_compressor(&jffs2_lzma_comp);
++	lzma_free_workspace();
++}
+--- a/fs/jffs2/super.c
++++ b/fs/jffs2/super.c
+@@ -380,14 +380,41 @@ static int __init init_jffs2_fs(void)
+ 	BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
+ 	BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
+ 
+-	pr_info("version 2.2."
++	pr_info("version 2.2"
+ #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+ 	       " (NAND)"
+ #endif
+ #ifdef CONFIG_JFFS2_SUMMARY
+-	       " (SUMMARY) "
++	       " (SUMMARY)"
+ #endif
+-	       " © 2001-2006 Red Hat, Inc.\n");
++#ifdef CONFIG_JFFS2_ZLIB
++	       " (ZLIB)"
++#endif
++#ifdef CONFIG_JFFS2_LZO
++	       " (LZO)"
++#endif
++#ifdef CONFIG_JFFS2_LZMA
++	       " (LZMA)"
++#endif
++#ifdef CONFIG_JFFS2_RTIME
++	       " (RTIME)"
++#endif
++#ifdef CONFIG_JFFS2_RUBIN
++	       " (RUBIN)"
++#endif
++#ifdef  CONFIG_JFFS2_CMODE_NONE
++	       " (CMODE_NONE)"
++#endif
++#ifdef CONFIG_JFFS2_CMODE_PRIORITY
++	       " (CMODE_PRIORITY)"
++#endif
++#ifdef CONFIG_JFFS2_CMODE_SIZE
++	       " (CMODE_SIZE)"
++#endif
++#ifdef CONFIG_JFFS2_CMODE_FAVOURLZO
++	       " (CMODE_FAVOURLZO)"
++#endif
++	       " (c) 2001-2006 Red Hat, Inc.\n");
+ 
+ 	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
+ 					     sizeof(struct jffs2_inode_info),
+--- /dev/null
++++ b/include/linux/lzma.h
+@@ -0,0 +1,62 @@
++#ifndef __LZMA_H__
++#define __LZMA_H__
++
++#ifdef __KERNEL__
++	#include <linux/kernel.h>
++	#include <linux/sched.h>
++	#include <linux/slab.h>
++	#include <linux/vmalloc.h>
++	#include <linux/init.h>
++	#define LZMA_MALLOC vmalloc
++	#define LZMA_FREE vfree
++	#define PRINT_ERROR(msg) printk(KERN_WARNING #msg)
++	#define INIT __init
++	#define STATIC static
++#else
++	#include <stdint.h>
++	#include <stdlib.h>
++	#include <stdio.h>
++	#include <unistd.h>
++	#include <string.h>
++	#include <asm/types.h>
++	#include <errno.h>
++	#include <linux/jffs2.h>
++	#ifndef PAGE_SIZE
++		extern int page_size;
++		#define PAGE_SIZE page_size
++	#endif
++	#define LZMA_MALLOC malloc
++	#define LZMA_FREE free
++	#define PRINT_ERROR(msg) fprintf(stderr, msg)
++	#define INIT
++	#define STATIC
++#endif
++
++#include "lzma/LzmaDec.h"
++#include "lzma/LzmaEnc.h"
++
++#define LZMA_BEST_LEVEL (9)
++#define LZMA_BEST_LC    (0)
++#define LZMA_BEST_LP    (0)
++#define LZMA_BEST_PB    (0)
++#define LZMA_BEST_FB  (273)
++
++#define LZMA_BEST_DICT(n) (((int)((n) / 2)) * 2)
++
++static void *p_lzma_malloc(void *p, size_t size)
++{
++	if (size == 0)
++		return NULL;
++
++	return LZMA_MALLOC(size);
++}
++
++static void p_lzma_free(void *p, void *address)
++{
++	if (address != NULL)
++		LZMA_FREE(address);
++}
++
++static ISzAlloc lzma_alloc = {p_lzma_malloc, p_lzma_free};
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzFind.h
+@@ -0,0 +1,115 @@
++/* LzFind.h -- Match finder for LZ algorithms
++2009-04-22 : Igor Pavlov : Public domain */
++
++#ifndef __LZ_FIND_H
++#define __LZ_FIND_H
++
++#include "Types.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++typedef UInt32 CLzRef;
++
++typedef struct _CMatchFinder
++{
++  Byte *buffer;
++  UInt32 pos;
++  UInt32 posLimit;
++  UInt32 streamPos;
++  UInt32 lenLimit;
++
++  UInt32 cyclicBufferPos;
++  UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
++
++  UInt32 matchMaxLen;
++  CLzRef *hash;
++  CLzRef *son;
++  UInt32 hashMask;
++  UInt32 cutValue;
++
++  Byte *bufferBase;
++  ISeqInStream *stream;
++  int streamEndWasReached;
++
++  UInt32 blockSize;
++  UInt32 keepSizeBefore;
++  UInt32 keepSizeAfter;
++
++  UInt32 numHashBytes;
++  int directInput;
++  size_t directInputRem;
++  int btMode;
++  int bigHash;
++  UInt32 historySize;
++  UInt32 fixedHashSize;
++  UInt32 hashSizeSum;
++  UInt32 numSons;
++  SRes result;
++  UInt32 crc[256];
++} CMatchFinder;
++
++#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
++#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)])
++
++#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
++
++int MatchFinder_NeedMove(CMatchFinder *p);
++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
++void MatchFinder_MoveBlock(CMatchFinder *p);
++void MatchFinder_ReadIfRequired(CMatchFinder *p);
++
++void MatchFinder_Construct(CMatchFinder *p);
++
++/* Conditions:
++     historySize <= 3 GB
++     keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
++*/
++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
++    UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
++    ISzAlloc *alloc);
++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
++
++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
++    UInt32 *distances, UInt32 maxLen);
++
++/*
++Conditions:
++  Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
++  Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
++*/
++
++typedef void (*Mf_Init_Func)(void *object);
++typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index);
++typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
++typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
++typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
++typedef void (*Mf_Skip_Func)(void *object, UInt32);
++
++typedef struct _IMatchFinder
++{
++  Mf_Init_Func Init;
++  Mf_GetIndexByte_Func GetIndexByte;
++  Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
++  Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
++  Mf_GetMatches_Func GetMatches;
++  Mf_Skip_Func Skip;
++} IMatchFinder;
++
++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
++
++void MatchFinder_Init(CMatchFinder *p);
++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzHash.h
+@@ -0,0 +1,54 @@
++/* LzHash.h -- HASH functions for LZ algorithms
++2009-02-07 : Igor Pavlov : Public domain */
++
++#ifndef __LZ_HASH_H
++#define __LZ_HASH_H
++
++#define kHash2Size (1 << 10)
++#define kHash3Size (1 << 16)
++#define kHash4Size (1 << 20)
++
++#define kFix3HashSize (kHash2Size)
++#define kFix4HashSize (kHash2Size + kHash3Size)
++#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
++
++#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8);
++
++#define HASH3_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
++
++#define HASH4_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
++  hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; }
++
++#define HASH5_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
++  hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \
++  hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \
++  hash4Value &= (kHash4Size - 1); }
++
++/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */
++#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
++
++
++#define MT_HASH2_CALC \
++  hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
++
++#define MT_HASH3_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
++
++#define MT_HASH4_CALC { \
++  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
++  hash2Value = temp & (kHash2Size - 1); \
++  hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
++  hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); }
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzmaDec.h
+@@ -0,0 +1,231 @@
++/* LzmaDec.h -- LZMA Decoder
++2009-02-07 : Igor Pavlov : Public domain */
++
++#ifndef __LZMA_DEC_H
++#define __LZMA_DEC_H
++
++#include "Types.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* #define _LZMA_PROB32 */
++/* _LZMA_PROB32 can increase the speed on some CPUs,
++   but memory usage for CLzmaDec::probs will be doubled in that case */
++
++#ifdef _LZMA_PROB32
++#define CLzmaProb UInt32
++#else
++#define CLzmaProb UInt16
++#endif
++
++
++/* ---------- LZMA Properties ---------- */
++
++#define LZMA_PROPS_SIZE 5
++
++typedef struct _CLzmaProps
++{
++  unsigned lc, lp, pb;
++  UInt32 dicSize;
++} CLzmaProps;
++
++/* LzmaProps_Decode - decodes properties
++Returns:
++  SZ_OK
++  SZ_ERROR_UNSUPPORTED - Unsupported properties
++*/
++
++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
++
++
++/* ---------- LZMA Decoder state ---------- */
++
++/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
++   Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
++
++#define LZMA_REQUIRED_INPUT_MAX 20
++
++typedef struct
++{
++  CLzmaProps prop;
++  CLzmaProb *probs;
++  Byte *dic;
++  const Byte *buf;
++  UInt32 range, code;
++  SizeT dicPos;
++  SizeT dicBufSize;
++  UInt32 processedPos;
++  UInt32 checkDicSize;
++  unsigned state;
++  UInt32 reps[4];
++  unsigned remainLen;
++  int needFlush;
++  int needInitState;
++  UInt32 numProbs;
++  unsigned tempBufSize;
++  Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
++} CLzmaDec;
++
++#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
++
++void LzmaDec_Init(CLzmaDec *p);
++
++/* There are two types of LZMA streams:
++     0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
++     1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
++
++typedef enum
++{
++  LZMA_FINISH_ANY,   /* finish at any point */
++  LZMA_FINISH_END    /* block must be finished at the end */
++} ELzmaFinishMode;
++
++/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
++
++   You must use LZMA_FINISH_END, when you know that current output buffer
++   covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
++
++   If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
++   and output value of destLen will be less than output buffer size limit.
++   You can check status result also.
++
++   You can use multiple checks to test data integrity after full decompression:
++     1) Check Result and "status" variable.
++     2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
++     3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
++        You must use correct finish mode in that case. */
++
++typedef enum
++{
++  LZMA_STATUS_NOT_SPECIFIED,               /* use main error code instead */
++  LZMA_STATUS_FINISHED_WITH_MARK,          /* stream was finished with end mark. */
++  LZMA_STATUS_NOT_FINISHED,                /* stream was not finished */
++  LZMA_STATUS_NEEDS_MORE_INPUT,            /* you must provide more input bytes */
++  LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK  /* there is probability that stream was finished without end mark */
++} ELzmaStatus;
++
++/* ELzmaStatus is used only as output value for function call */
++
++
++/* ---------- Interfaces ---------- */
++
++/* There are 3 levels of interfaces:
++     1) Dictionary Interface
++     2) Buffer Interface
++     3) One Call Interface
++   You can select any of these interfaces, but don't mix functions from different
++   groups for same object. */
++
++
++/* There are two variants to allocate state for Dictionary Interface:
++     1) LzmaDec_Allocate / LzmaDec_Free
++     2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
++   You can use variant 2, if you set dictionary buffer manually.
++   For Buffer Interface you must always use variant 1.
++
++LzmaDec_Allocate* can return:
++  SZ_OK
++  SZ_ERROR_MEM         - Memory allocation error
++  SZ_ERROR_UNSUPPORTED - Unsupported properties
++*/
++
++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
++
++SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
++void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
++
++/* ---------- Dictionary Interface ---------- */
++
++/* You can use it, if you want to eliminate the overhead for data copying from
++   dictionary to some other external buffer.
++   You must work with CLzmaDec variables directly in this interface.
++
++   STEPS:
++     LzmaDec_Constr()
++     LzmaDec_Allocate()
++     for (each new stream)
++     {
++       LzmaDec_Init()
++       while (it needs more decompression)
++       {
++         LzmaDec_DecodeToDic()
++         use data from CLzmaDec::dic and update CLzmaDec::dicPos
++       }
++     }
++     LzmaDec_Free()
++*/
++
++/* LzmaDec_DecodeToDic
++
++   The decoding to internal dictionary buffer (CLzmaDec::dic).
++   You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
++
++finishMode:
++  It has meaning only if the decoding reaches output limit (dicLimit).
++  LZMA_FINISH_ANY - Decode just dicLimit bytes.
++  LZMA_FINISH_END - Stream must be finished after dicLimit.
++
++Returns:
++  SZ_OK
++    status:
++      LZMA_STATUS_FINISHED_WITH_MARK
++      LZMA_STATUS_NOT_FINISHED
++      LZMA_STATUS_NEEDS_MORE_INPUT
++      LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
++  SZ_ERROR_DATA - Data error
++*/
++
++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
++    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
++
++
++/* ---------- Buffer Interface ---------- */
++
++/* It's zlib-like interface.
++   See LzmaDec_DecodeToDic description for information about STEPS and return results,
++   but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
++   to work with CLzmaDec variables manually.
++
++finishMode:
++  It has meaning only if the decoding reaches output limit (*destLen).
++  LZMA_FINISH_ANY - Decode just destLen bytes.
++  LZMA_FINISH_END - Stream must be finished after (*destLen).
++*/
++
++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
++    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
++
++
++/* ---------- One Call Interface ---------- */
++
++/* LzmaDecode
++
++finishMode:
++  It has meaning only if the decoding reaches output limit (*destLen).
++  LZMA_FINISH_ANY - Decode just destLen bytes.
++  LZMA_FINISH_END - Stream must be finished after (*destLen).
++
++Returns:
++  SZ_OK
++    status:
++      LZMA_STATUS_FINISHED_WITH_MARK
++      LZMA_STATUS_NOT_FINISHED
++      LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
++  SZ_ERROR_DATA - Data error
++  SZ_ERROR_MEM  - Memory allocation error
++  SZ_ERROR_UNSUPPORTED - Unsupported properties
++  SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
++*/
++
++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
++    const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
++    ELzmaStatus *status, ISzAlloc *alloc);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/LzmaEnc.h
+@@ -0,0 +1,80 @@
++/*  LzmaEnc.h -- LZMA Encoder
++2009-02-07 : Igor Pavlov : Public domain */
++
++#ifndef __LZMA_ENC_H
++#define __LZMA_ENC_H
++
++#include "Types.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#define LZMA_PROPS_SIZE 5
++
++typedef struct _CLzmaEncProps
++{
++  int level;       /*  0 <= level <= 9 */
++  UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version
++                      (1 << 12) <= dictSize <= (1 << 30) for 64-bit version
++                       default = (1 << 24) */
++  int lc;          /* 0 <= lc <= 8, default = 3 */
++  int lp;          /* 0 <= lp <= 4, default = 0 */
++  int pb;          /* 0 <= pb <= 4, default = 2 */
++  int algo;        /* 0 - fast, 1 - normal, default = 1 */
++  int fb;          /* 5 <= fb <= 273, default = 32 */
++  int btMode;      /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */
++  int numHashBytes; /* 2, 3 or 4, default = 4 */
++  UInt32 mc;        /* 1 <= mc <= (1 << 30), default = 32 */
++  unsigned writeEndMark;  /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */
++  int numThreads;  /* 1 or 2, default = 2 */
++} CLzmaEncProps;
++
++void LzmaEncProps_Init(CLzmaEncProps *p);
++void LzmaEncProps_Normalize(CLzmaEncProps *p);
++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
++
++
++/* ---------- CLzmaEncHandle Interface ---------- */
++
++/* LzmaEnc_* functions can return the following exit codes:
++Returns:
++  SZ_OK           - OK
++  SZ_ERROR_MEM    - Memory allocation error
++  SZ_ERROR_PARAM  - Incorrect paramater in props
++  SZ_ERROR_WRITE  - Write callback error.
++  SZ_ERROR_PROGRESS - some break from progress callback
++  SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
++*/
++
++typedef void * CLzmaEncHandle;
++
++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc);
++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig);
++SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
++SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
++SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
++    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
++SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
++
++/* ---------- One Call Interface ---------- */
++
++/* LzmaEncode
++Return code:
++  SZ_OK               - OK
++  SZ_ERROR_MEM        - Memory allocation error
++  SZ_ERROR_PARAM      - Incorrect paramater
++  SZ_ERROR_OUTPUT_EOF - output buffer overflow
++  SZ_ERROR_THREAD     - errors in multithreading functions (only for Mt version)
++*/
++
++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
++    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
+--- /dev/null
++++ b/include/linux/lzma/Types.h
+@@ -0,0 +1,226 @@
++/* Types.h -- Basic types
++2009-11-23 : Igor Pavlov : Public domain */
++
++#ifndef __7Z_TYPES_H
++#define __7Z_TYPES_H
++
++#include <stddef.h>
++
++#ifdef _WIN32
++#include <windows.h>
++#endif
++
++#ifndef EXTERN_C_BEGIN
++#ifdef __cplusplus
++#define EXTERN_C_BEGIN extern "C" {
++#define EXTERN_C_END }
++#else
++#define EXTERN_C_BEGIN
++#define EXTERN_C_END
++#endif
++#endif
++
++EXTERN_C_BEGIN
++
++#define SZ_OK 0
++
++#define SZ_ERROR_DATA 1
++#define SZ_ERROR_MEM 2
++#define SZ_ERROR_CRC 3
++#define SZ_ERROR_UNSUPPORTED 4
++#define SZ_ERROR_PARAM 5
++#define SZ_ERROR_INPUT_EOF 6
++#define SZ_ERROR_OUTPUT_EOF 7
++#define SZ_ERROR_READ 8
++#define SZ_ERROR_WRITE 9
++#define SZ_ERROR_PROGRESS 10
++#define SZ_ERROR_FAIL 11
++#define SZ_ERROR_THREAD 12
++
++#define SZ_ERROR_ARCHIVE 16
++#define SZ_ERROR_NO_ARCHIVE 17
++
++typedef int SRes;
++
++#ifdef _WIN32
++typedef DWORD WRes;
++#else
++typedef int WRes;
++#endif
++
++#ifndef RINOK
++#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
++#endif
++
++typedef unsigned char Byte;
++typedef short Int16;
++typedef unsigned short UInt16;
++
++#ifdef _LZMA_UINT32_IS_ULONG
++typedef long Int32;
++typedef unsigned long UInt32;
++#else
++typedef int Int32;
++typedef unsigned int UInt32;
++#endif
++
++#ifdef _SZ_NO_INT_64
++
++/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
++   NOTES: Some code will work incorrectly in that case! */
++
++typedef long Int64;
++typedef unsigned long UInt64;
++
++#else
++
++#if defined(_MSC_VER) || defined(__BORLANDC__)
++typedef __int64 Int64;
++typedef unsigned __int64 UInt64;
++#else
++typedef long long int Int64;
++typedef unsigned long long int UInt64;
++#endif
++
++#endif
++
++#ifdef _LZMA_NO_SYSTEM_SIZE_T
++typedef UInt32 SizeT;
++#else
++typedef size_t SizeT;
++#endif
++
++typedef int Bool;
++#define True 1
++#define False 0
++
++
++#ifdef _WIN32
++#define MY_STD_CALL __stdcall
++#else
++#define MY_STD_CALL
++#endif
++
++#ifdef _MSC_VER
++
++#if _MSC_VER >= 1300
++#define MY_NO_INLINE __declspec(noinline)
++#else
++#define MY_NO_INLINE
++#endif
++
++#define MY_CDECL __cdecl
++#define MY_FAST_CALL __fastcall
++
++#else
++
++#define MY_CDECL
++#define MY_FAST_CALL
++
++#endif
++
++
++/* The following interfaces use first parameter as pointer to structure */
++
++typedef struct
++{
++  SRes (*Read)(void *p, void *buf, size_t *size);
++    /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
++       (output(*size) < input(*size)) is allowed */
++} ISeqInStream;
++
++/* it can return SZ_ERROR_INPUT_EOF */
++SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size);
++SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType);
++SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf);
++
++typedef struct
++{
++  size_t (*Write)(void *p, const void *buf, size_t size);
++    /* Returns: result - the number of actually written bytes.
++       (result < size) means error */
++} ISeqOutStream;
++
++typedef enum
++{
++  SZ_SEEK_SET = 0,
++  SZ_SEEK_CUR = 1,
++  SZ_SEEK_END = 2
++} ESzSeek;
++
++typedef struct
++{
++  SRes (*Read)(void *p, void *buf, size_t *size);  /* same as ISeqInStream::Read */
++  SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
++} ISeekInStream;
++
++typedef struct
++{
++  SRes (*Look)(void *p, void **buf, size_t *size);
++    /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
++       (output(*size) > input(*size)) is not allowed
++       (output(*size) < input(*size)) is allowed */
++  SRes (*Skip)(void *p, size_t offset);
++    /* offset must be <= output(*size) of Look */
++
++  SRes (*Read)(void *p, void *buf, size_t *size);
++    /* reads directly (without buffer). It's same as ISeqInStream::Read */
++  SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
++} ILookInStream;
++
++SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size);
++SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset);
++
++/* reads via ILookInStream::Read */
++SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType);
++SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size);
++
++#define LookToRead_BUF_SIZE (1 << 14)
++
++typedef struct
++{
++  ILookInStream s;
++  ISeekInStream *realStream;
++  size_t pos;
++  size_t size;
++  Byte buf[LookToRead_BUF_SIZE];
++} CLookToRead;
++
++void LookToRead_CreateVTable(CLookToRead *p, int lookahead);
++void LookToRead_Init(CLookToRead *p);
++
++typedef struct
++{
++  ISeqInStream s;
++  ILookInStream *realStream;
++} CSecToLook;
++
++void SecToLook_CreateVTable(CSecToLook *p);
++
++typedef struct
++{
++  ISeqInStream s;
++  ILookInStream *realStream;
++} CSecToRead;
++
++void SecToRead_CreateVTable(CSecToRead *p);
++
++typedef struct
++{
++  SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
++    /* Returns: result. (result != SZ_OK) means break.
++       Value (UInt64)(Int64)-1 for size means unknown value. */
++} ICompressProgress;
++
++typedef struct
++{
++  void *(*Alloc)(void *p, size_t size);
++  void (*Free)(void *p, void *address); /* address can be 0 */
++} ISzAlloc;
++
++#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
++#define IAlloc_Free(p, a) (p)->Free((p), a)
++
++EXTERN_C_END
++
++#endif
+--- a/include/uapi/linux/jffs2.h
++++ b/include/uapi/linux/jffs2.h
+@@ -46,6 +46,7 @@
+ #define JFFS2_COMPR_DYNRUBIN	0x05
+ #define JFFS2_COMPR_ZLIB	0x06
+ #define JFFS2_COMPR_LZO		0x07
++#define JFFS2_COMPR_LZMA	0x08
+ /* Compatibility flags. */
+ #define JFFS2_COMPAT_MASK 0xc000      /* What do to if an unknown nodetype is found */
+ #define JFFS2_NODE_ACCURATE 0x2000
+--- a/lib/Kconfig
++++ b/lib/Kconfig
+@@ -303,6 +303,12 @@ config ZSTD_DECOMPRESS
+ 
+ source "lib/xz/Kconfig"
+ 
++config LZMA_COMPRESS
++    tristate
++
++config LZMA_DECOMPRESS
++    tristate
++
+ #
+ # These all provide a common interface (hence the apparent duplication with
+ # ZLIB_INFLATE; DECOMPRESS_GZIP is just a wrapper.)
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -3,6 +3,16 @@
+ # Makefile for some libs needed in the kernel.
+ #
+ 
++ifdef CONFIG_JFFS2_ZLIB
++	CONFIG_ZLIB_INFLATE:=y
++	CONFIG_ZLIB_DEFLATE:=y
++endif
++
++ifdef CONFIG_JFFS2_LZMA
++	CONFIG_LZMA_DECOMPRESS:=y
++	CONFIG_LZMA_COMPRESS:=y
++endif
++
+ ifdef CONFIG_FUNCTION_TRACER
+ ORIG_CFLAGS := $(KBUILD_CFLAGS)
+ KBUILD_CFLAGS = $(subst $(CC_FLAGS_FTRACE),,$(ORIG_CFLAGS))
+@@ -149,6 +159,8 @@ obj-$(CONFIG_ZSTD_COMPRESS) += zstd/
+ obj-$(CONFIG_ZSTD_DECOMPRESS) += zstd/
+ obj-$(CONFIG_XZ_DEC) += xz/
+ obj-$(CONFIG_RAID6_PQ) += raid6/
++obj-$(CONFIG_LZMA_COMPRESS) += lzma/
++obj-$(CONFIG_LZMA_DECOMPRESS) += lzma/
+ 
+ lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o
+ lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o
+--- /dev/null
++++ b/lib/lzma/LzFind.c
+@@ -0,0 +1,761 @@
++/* LzFind.c -- Match finder for LZ algorithms
++2009-04-22 : Igor Pavlov : Public domain */
++
++#include <string.h>
++
++#include "LzFind.h"
++#include "LzHash.h"
++
++#define kEmptyHashValue 0
++#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
++#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
++#define kNormalizeMask (~(kNormalizeStepMin - 1))
++#define kMaxHistorySize ((UInt32)3 << 30)
++
++#define kStartMaxLen 3
++
++static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
++{
++  if (!p->directInput)
++  {
++    alloc->Free(alloc, p->bufferBase);
++    p->bufferBase = 0;
++  }
++}
++
++/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
++
++static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
++{
++  UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
++  if (p->directInput)
++  {
++    p->blockSize = blockSize;
++    return 1;
++  }
++  if (p->bufferBase == 0 || p->blockSize != blockSize)
++  {
++    LzInWindow_Free(p, alloc);
++    p->blockSize = blockSize;
++    p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize);
++  }
++  return (p->bufferBase != 0);
++}
++
++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
++Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
++
++UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
++
++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
++{
++  p->posLimit -= subValue;
++  p->pos -= subValue;
++  p->streamPos -= subValue;
++}
++
++static void MatchFinder_ReadBlock(CMatchFinder *p)
++{
++  if (p->streamEndWasReached || p->result != SZ_OK)
++    return;
++  if (p->directInput)
++  {
++    UInt32 curSize = 0xFFFFFFFF - p->streamPos;
++    if (curSize > p->directInputRem)
++      curSize = (UInt32)p->directInputRem;
++    p->directInputRem -= curSize;
++    p->streamPos += curSize;
++    if (p->directInputRem == 0)
++      p->streamEndWasReached = 1;
++    return;
++  }
++  for (;;)
++  {
++    Byte *dest = p->buffer + (p->streamPos - p->pos);
++    size_t size = (p->bufferBase + p->blockSize - dest);
++    if (size == 0)
++      return;
++    p->result = p->stream->Read(p->stream, dest, &size);
++    if (p->result != SZ_OK)
++      return;
++    if (size == 0)
++    {
++      p->streamEndWasReached = 1;
++      return;
++    }
++    p->streamPos += (UInt32)size;
++    if (p->streamPos - p->pos > p->keepSizeAfter)
++      return;
++  }
++}
++
++void MatchFinder_MoveBlock(CMatchFinder *p)
++{
++  memmove(p->bufferBase,
++    p->buffer - p->keepSizeBefore,
++    (size_t)(p->streamPos - p->pos + p->keepSizeBefore));
++  p->buffer = p->bufferBase + p->keepSizeBefore;
++}
++
++int MatchFinder_NeedMove(CMatchFinder *p)
++{
++  if (p->directInput)
++    return 0;
++  /* if (p->streamEndWasReached) return 0; */
++  return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
++}
++
++void MatchFinder_ReadIfRequired(CMatchFinder *p)
++{
++  if (p->streamEndWasReached)
++    return;
++  if (p->keepSizeAfter >= p->streamPos - p->pos)
++    MatchFinder_ReadBlock(p);
++}
++
++static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
++{
++  if (MatchFinder_NeedMove(p))
++    MatchFinder_MoveBlock(p);
++  MatchFinder_ReadBlock(p);
++}
++
++static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
++{
++  p->cutValue = 32;
++  p->btMode = 1;
++  p->numHashBytes = 4;
++  p->bigHash = 0;
++}
++
++#define kCrcPoly 0xEDB88320
++
++void MatchFinder_Construct(CMatchFinder *p)
++{
++  UInt32 i;
++  p->bufferBase = 0;
++  p->directInput = 0;
++  p->hash = 0;
++  MatchFinder_SetDefaultSettings(p);
++
++  for (i = 0; i < 256; i++)
++  {
++    UInt32 r = i;
++    int j;
++    for (j = 0; j < 8; j++)
++      r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
++    p->crc[i] = r;
++  }
++}
++
++static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->hash);
++  p->hash = 0;
++}
++
++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
++{
++  MatchFinder_FreeThisClassMemory(p, alloc);
++  LzInWindow_Free(p, alloc);
++}
++
++static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc)
++{
++  size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
++  if (sizeInBytes / sizeof(CLzRef) != num)
++    return 0;
++  return (CLzRef *)alloc->Alloc(alloc, sizeInBytes);
++}
++
++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
++    UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
++    ISzAlloc *alloc)
++{
++  UInt32 sizeReserv;
++  if (historySize > kMaxHistorySize)
++  {
++    MatchFinder_Free(p, alloc);
++    return 0;
++  }
++  sizeReserv = historySize >> 1;
++  if (historySize > ((UInt32)2 << 30))
++    sizeReserv = historySize >> 2;
++  sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
++
++  p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
++  p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
++  /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
++  if (LzInWindow_Create(p, sizeReserv, alloc))
++  {
++    UInt32 newCyclicBufferSize = historySize + 1;
++    UInt32 hs;
++    p->matchMaxLen = matchMaxLen;
++    {
++      p->fixedHashSize = 0;
++      if (p->numHashBytes == 2)
++        hs = (1 << 16) - 1;
++      else
++      {
++        hs = historySize - 1;
++        hs |= (hs >> 1);
++        hs |= (hs >> 2);
++        hs |= (hs >> 4);
++        hs |= (hs >> 8);
++        hs >>= 1;
++        hs |= 0xFFFF; /* don't change it! It's required for Deflate */
++        if (hs > (1 << 24))
++        {
++          if (p->numHashBytes == 3)
++            hs = (1 << 24) - 1;
++          else
++            hs >>= 1;
++        }
++      }
++      p->hashMask = hs;
++      hs++;
++      if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
++      if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
++      if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
++      hs += p->fixedHashSize;
++    }
++
++    {
++      UInt32 prevSize = p->hashSizeSum + p->numSons;
++      UInt32 newSize;
++      p->historySize = historySize;
++      p->hashSizeSum = hs;
++      p->cyclicBufferSize = newCyclicBufferSize;
++      p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
++      newSize = p->hashSizeSum + p->numSons;
++      if (p->hash != 0 && prevSize == newSize)
++        return 1;
++      MatchFinder_FreeThisClassMemory(p, alloc);
++      p->hash = AllocRefs(newSize, alloc);
++      if (p->hash != 0)
++      {
++        p->son = p->hash + p->hashSizeSum;
++        return 1;
++      }
++    }
++  }
++  MatchFinder_Free(p, alloc);
++  return 0;
++}
++
++static void MatchFinder_SetLimits(CMatchFinder *p)
++{
++  UInt32 limit = kMaxValForNormalize - p->pos;
++  UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
++  if (limit2 < limit)
++    limit = limit2;
++  limit2 = p->streamPos - p->pos;
++  if (limit2 <= p->keepSizeAfter)
++  {
++    if (limit2 > 0)
++      limit2 = 1;
++  }
++  else
++    limit2 -= p->keepSizeAfter;
++  if (limit2 < limit)
++    limit = limit2;
++  {
++    UInt32 lenLimit = p->streamPos - p->pos;
++    if (lenLimit > p->matchMaxLen)
++      lenLimit = p->matchMaxLen;
++    p->lenLimit = lenLimit;
++  }
++  p->posLimit = p->pos + limit;
++}
++
++void MatchFinder_Init(CMatchFinder *p)
++{
++  UInt32 i;
++  for (i = 0; i < p->hashSizeSum; i++)
++    p->hash[i] = kEmptyHashValue;
++  p->cyclicBufferPos = 0;
++  p->buffer = p->bufferBase;
++  p->pos = p->streamPos = p->cyclicBufferSize;
++  p->result = SZ_OK;
++  p->streamEndWasReached = 0;
++  MatchFinder_ReadBlock(p);
++  MatchFinder_SetLimits(p);
++}
++
++static UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
++{
++  return (p->pos - p->historySize - 1) & kNormalizeMask;
++}
++
++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
++{
++  UInt32 i;
++  for (i = 0; i < numItems; i++)
++  {
++    UInt32 value = items[i];
++    if (value <= subValue)
++      value = kEmptyHashValue;
++    else
++      value -= subValue;
++    items[i] = value;
++  }
++}
++
++static void MatchFinder_Normalize(CMatchFinder *p)
++{
++  UInt32 subValue = MatchFinder_GetSubValue(p);
++  MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons);
++  MatchFinder_ReduceOffsets(p, subValue);
++}
++
++static void MatchFinder_CheckLimits(CMatchFinder *p)
++{
++  if (p->pos == kMaxValForNormalize)
++    MatchFinder_Normalize(p);
++  if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
++    MatchFinder_CheckAndMoveAndRead(p);
++  if (p->cyclicBufferPos == p->cyclicBufferSize)
++    p->cyclicBufferPos = 0;
++  MatchFinder_SetLimits(p);
++}
++
++static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
++    UInt32 *distances, UInt32 maxLen)
++{
++  son[_cyclicBufferPos] = curMatch;
++  for (;;)
++  {
++    UInt32 delta = pos - curMatch;
++    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
++      return distances;
++    {
++      const Byte *pb = cur - delta;
++      curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
++      if (pb[maxLen] == cur[maxLen] && *pb == *cur)
++      {
++        UInt32 len = 0;
++        while (++len != lenLimit)
++          if (pb[len] != cur[len])
++            break;
++        if (maxLen < len)
++        {
++          *distances++ = maxLen = len;
++          *distances++ = delta - 1;
++          if (len == lenLimit)
++            return distances;
++        }
++      }
++    }
++  }
++}
++
++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
++    UInt32 *distances, UInt32 maxLen)
++{
++  CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
++  CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
++  UInt32 len0 = 0, len1 = 0;
++  for (;;)
++  {
++    UInt32 delta = pos - curMatch;
++    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
++    {
++      *ptr0 = *ptr1 = kEmptyHashValue;
++      return distances;
++    }
++    {
++      CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
++      const Byte *pb = cur - delta;
++      UInt32 len = (len0 < len1 ? len0 : len1);
++      if (pb[len] == cur[len])
++      {
++        if (++len != lenLimit && pb[len] == cur[len])
++          while (++len != lenLimit)
++            if (pb[len] != cur[len])
++              break;
++        if (maxLen < len)
++        {
++          *distances++ = maxLen = len;
++          *distances++ = delta - 1;
++          if (len == lenLimit)
++          {
++            *ptr1 = pair[0];
++            *ptr0 = pair[1];
++            return distances;
++          }
++        }
++      }
++      if (pb[len] < cur[len])
++      {
++        *ptr1 = curMatch;
++        ptr1 = pair + 1;
++        curMatch = *ptr1;
++        len1 = len;
++      }
++      else
++      {
++        *ptr0 = curMatch;
++        ptr0 = pair;
++        curMatch = *ptr0;
++        len0 = len;
++      }
++    }
++  }
++}
++
++static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
++    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
++{
++  CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
++  CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
++  UInt32 len0 = 0, len1 = 0;
++  for (;;)
++  {
++    UInt32 delta = pos - curMatch;
++    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
++    {
++      *ptr0 = *ptr1 = kEmptyHashValue;
++      return;
++    }
++    {
++      CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
++      const Byte *pb = cur - delta;
++      UInt32 len = (len0 < len1 ? len0 : len1);
++      if (pb[len] == cur[len])
++      {
++        while (++len != lenLimit)
++          if (pb[len] != cur[len])
++            break;
++        {
++          if (len == lenLimit)
++          {
++            *ptr1 = pair[0];
++            *ptr0 = pair[1];
++            return;
++          }
++        }
++      }
++      if (pb[len] < cur[len])
++      {
++        *ptr1 = curMatch;
++        ptr1 = pair + 1;
++        curMatch = *ptr1;
++        len1 = len;
++      }
++      else
++      {
++        *ptr0 = curMatch;
++        ptr0 = pair;
++        curMatch = *ptr0;
++        len0 = len;
++      }
++    }
++  }
++}
++
++#define MOVE_POS \
++  ++p->cyclicBufferPos; \
++  p->buffer++; \
++  if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
++
++#define MOVE_POS_RET MOVE_POS return offset;
++
++static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
++
++#define GET_MATCHES_HEADER2(minLen, ret_op) \
++  UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
++  lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
++  cur = p->buffer;
++
++#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
++#define SKIP_HEADER(minLen)        GET_MATCHES_HEADER2(minLen, continue)
++
++#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
++
++#define GET_MATCHES_FOOTER(offset, maxLen) \
++  offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \
++  distances + offset, maxLen) - distances); MOVE_POS_RET;
++
++#define SKIP_FOOTER \
++  SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
++
++static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 offset;
++  GET_MATCHES_HEADER(2)
++  HASH2_CALC;
++  curMatch = p->hash[hashValue];
++  p->hash[hashValue] = p->pos;
++  offset = 0;
++  GET_MATCHES_FOOTER(offset, 1)
++}
++
++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 offset;
++  GET_MATCHES_HEADER(3)
++  HASH_ZIP_CALC;
++  curMatch = p->hash[hashValue];
++  p->hash[hashValue] = p->pos;
++  offset = 0;
++  GET_MATCHES_FOOTER(offset, 2)
++}
++
++static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 hash2Value, delta2, maxLen, offset;
++  GET_MATCHES_HEADER(3)
++
++  HASH3_CALC;
++
++  delta2 = p->pos - p->hash[hash2Value];
++  curMatch = p->hash[kFix3HashSize + hashValue];
++
++  p->hash[hash2Value] =
++  p->hash[kFix3HashSize + hashValue] = p->pos;
++
++
++  maxLen = 2;
++  offset = 0;
++  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
++  {
++    for (; maxLen != lenLimit; maxLen++)
++      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
++        break;
++    distances[0] = maxLen;
++    distances[1] = delta2 - 1;
++    offset = 2;
++    if (maxLen == lenLimit)
++    {
++      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
++      MOVE_POS_RET;
++    }
++  }
++  GET_MATCHES_FOOTER(offset, maxLen)
++}
++
++static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
++  GET_MATCHES_HEADER(4)
++
++  HASH4_CALC;
++
++  delta2 = p->pos - p->hash[                hash2Value];
++  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
++  curMatch = p->hash[kFix4HashSize + hashValue];
++
++  p->hash[                hash2Value] =
++  p->hash[kFix3HashSize + hash3Value] =
++  p->hash[kFix4HashSize + hashValue] = p->pos;
++
++  maxLen = 1;
++  offset = 0;
++  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
++  {
++    distances[0] = maxLen = 2;
++    distances[1] = delta2 - 1;
++    offset = 2;
++  }
++  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
++  {
++    maxLen = 3;
++    distances[offset + 1] = delta3 - 1;
++    offset += 2;
++    delta2 = delta3;
++  }
++  if (offset != 0)
++  {
++    for (; maxLen != lenLimit; maxLen++)
++      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
++        break;
++    distances[offset - 2] = maxLen;
++    if (maxLen == lenLimit)
++    {
++      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
++      MOVE_POS_RET;
++    }
++  }
++  if (maxLen < 3)
++    maxLen = 3;
++  GET_MATCHES_FOOTER(offset, maxLen)
++}
++
++static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
++  GET_MATCHES_HEADER(4)
++
++  HASH4_CALC;
++
++  delta2 = p->pos - p->hash[                hash2Value];
++  delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
++  curMatch = p->hash[kFix4HashSize + hashValue];
++
++  p->hash[                hash2Value] =
++  p->hash[kFix3HashSize + hash3Value] =
++  p->hash[kFix4HashSize + hashValue] = p->pos;
++
++  maxLen = 1;
++  offset = 0;
++  if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
++  {
++    distances[0] = maxLen = 2;
++    distances[1] = delta2 - 1;
++    offset = 2;
++  }
++  if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
++  {
++    maxLen = 3;
++    distances[offset + 1] = delta3 - 1;
++    offset += 2;
++    delta2 = delta3;
++  }
++  if (offset != 0)
++  {
++    for (; maxLen != lenLimit; maxLen++)
++      if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
++        break;
++    distances[offset - 2] = maxLen;
++    if (maxLen == lenLimit)
++    {
++      p->son[p->cyclicBufferPos] = curMatch;
++      MOVE_POS_RET;
++    }
++  }
++  if (maxLen < 3)
++    maxLen = 3;
++  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
++    distances + offset, maxLen) - (distances));
++  MOVE_POS_RET
++}
++
++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
++{
++  UInt32 offset;
++  GET_MATCHES_HEADER(3)
++  HASH_ZIP_CALC;
++  curMatch = p->hash[hashValue];
++  p->hash[hashValue] = p->pos;
++  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
++    distances, 2) - (distances));
++  MOVE_POS_RET
++}
++
++static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    SKIP_HEADER(2)
++    HASH2_CALC;
++    curMatch = p->hash[hashValue];
++    p->hash[hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    SKIP_HEADER(3)
++    HASH_ZIP_CALC;
++    curMatch = p->hash[hashValue];
++    p->hash[hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    UInt32 hash2Value;
++    SKIP_HEADER(3)
++    HASH3_CALC;
++    curMatch = p->hash[kFix3HashSize + hashValue];
++    p->hash[hash2Value] =
++    p->hash[kFix3HashSize + hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    UInt32 hash2Value, hash3Value;
++    SKIP_HEADER(4)
++    HASH4_CALC;
++    curMatch = p->hash[kFix4HashSize + hashValue];
++    p->hash[                hash2Value] =
++    p->hash[kFix3HashSize + hash3Value] = p->pos;
++    p->hash[kFix4HashSize + hashValue] = p->pos;
++    SKIP_FOOTER
++  }
++  while (--num != 0);
++}
++
++static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    UInt32 hash2Value, hash3Value;
++    SKIP_HEADER(4)
++    HASH4_CALC;
++    curMatch = p->hash[kFix4HashSize + hashValue];
++    p->hash[                hash2Value] =
++    p->hash[kFix3HashSize + hash3Value] =
++    p->hash[kFix4HashSize + hashValue] = p->pos;
++    p->son[p->cyclicBufferPos] = curMatch;
++    MOVE_POS
++  }
++  while (--num != 0);
++}
++
++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
++{
++  do
++  {
++    SKIP_HEADER(3)
++    HASH_ZIP_CALC;
++    curMatch = p->hash[hashValue];
++    p->hash[hashValue] = p->pos;
++    p->son[p->cyclicBufferPos] = curMatch;
++    MOVE_POS
++  }
++  while (--num != 0);
++}
++
++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
++{
++  vTable->Init = (Mf_Init_Func)MatchFinder_Init;
++  vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
++  vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
++  vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
++  if (!p->btMode)
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
++  }
++  else if (p->numHashBytes == 2)
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
++  }
++  else if (p->numHashBytes == 3)
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
++  }
++  else
++  {
++    vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
++    vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
++  }
++}
+--- /dev/null
++++ b/lib/lzma/LzmaDec.c
+@@ -0,0 +1,999 @@
++/* LzmaDec.c -- LZMA Decoder
++2009-09-20 : Igor Pavlov : Public domain */
++
++#include "LzmaDec.h"
++
++#include <string.h>
++
++#define kNumTopBits 24
++#define kTopValue ((UInt32)1 << kNumTopBits)
++
++#define kNumBitModelTotalBits 11
++#define kBitModelTotal (1 << kNumBitModelTotalBits)
++#define kNumMoveBits 5
++
++#define RC_INIT_SIZE 5
++
++#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); }
++
++#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
++#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
++#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits));
++#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \
++  { UPDATE_0(p); i = (i + i); A0; } else \
++  { UPDATE_1(p); i = (i + i) + 1; A1; }
++#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;)
++
++#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); }
++#define TREE_DECODE(probs, limit, i) \
++  { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; }
++
++/* #define _LZMA_SIZE_OPT */
++
++#ifdef _LZMA_SIZE_OPT
++#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i)
++#else
++#define TREE_6_DECODE(probs, i) \
++  { i = 1; \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  TREE_GET_BIT(probs, i); \
++  i -= 0x40; }
++#endif
++
++#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); }
++
++#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
++#define UPDATE_0_CHECK range = bound;
++#define UPDATE_1_CHECK range -= bound; code -= bound;
++#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \
++  { UPDATE_0_CHECK; i = (i + i); A0; } else \
++  { UPDATE_1_CHECK; i = (i + i) + 1; A1; }
++#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;)
++#define TREE_DECODE_CHECK(probs, limit, i) \
++  { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; }
++
++
++#define kNumPosBitsMax 4
++#define kNumPosStatesMax (1 << kNumPosBitsMax)
++
++#define kLenNumLowBits 3
++#define kLenNumLowSymbols (1 << kLenNumLowBits)
++#define kLenNumMidBits 3
++#define kLenNumMidSymbols (1 << kLenNumMidBits)
++#define kLenNumHighBits 8
++#define kLenNumHighSymbols (1 << kLenNumHighBits)
++
++#define LenChoice 0
++#define LenChoice2 (LenChoice + 1)
++#define LenLow (LenChoice2 + 1)
++#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
++#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
++#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
++
++
++#define kNumStates 12
++#define kNumLitStates 7
++
++#define kStartPosModelIndex 4
++#define kEndPosModelIndex 14
++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
++
++#define kNumPosSlotBits 6
++#define kNumLenToPosStates 4
++
++#define kNumAlignBits 4
++#define kAlignTableSize (1 << kNumAlignBits)
++
++#define kMatchMinLen 2
++#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
++
++#define IsMatch 0
++#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
++#define IsRepG0 (IsRep + kNumStates)
++#define IsRepG1 (IsRepG0 + kNumStates)
++#define IsRepG2 (IsRepG1 + kNumStates)
++#define IsRep0Long (IsRepG2 + kNumStates)
++#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
++#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
++#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
++#define LenCoder (Align + kAlignTableSize)
++#define RepLenCoder (LenCoder + kNumLenProbs)
++#define Literal (RepLenCoder + kNumLenProbs)
++
++#define LZMA_BASE_SIZE 1846
++#define LZMA_LIT_SIZE 768
++
++#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
++
++#if Literal != LZMA_BASE_SIZE
++StopCompilingDueBUG
++#endif
++
++#define LZMA_DIC_MIN (1 << 12)
++
++/* First LZMA-symbol is always decoded.
++And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization
++Out:
++  Result:
++    SZ_OK - OK
++    SZ_ERROR_DATA - Error
++  p->remainLen:
++    < kMatchSpecLenStart : normal remain
++    = kMatchSpecLenStart : finished
++    = kMatchSpecLenStart + 1 : Flush marker
++    = kMatchSpecLenStart + 2 : State Init Marker
++*/
++
++static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
++{
++  CLzmaProb *probs = p->probs;
++
++  unsigned state = p->state;
++  UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3];
++  unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
++  unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1;
++  unsigned lc = p->prop.lc;
++
++  Byte *dic = p->dic;
++  SizeT dicBufSize = p->dicBufSize;
++  SizeT dicPos = p->dicPos;
++
++  UInt32 processedPos = p->processedPos;
++  UInt32 checkDicSize = p->checkDicSize;
++  unsigned len = 0;
++
++  const Byte *buf = p->buf;
++  UInt32 range = p->range;
++  UInt32 code = p->code;
++
++  do
++  {
++    CLzmaProb *prob;
++    UInt32 bound;
++    unsigned ttt;
++    unsigned posState = processedPos & pbMask;
++
++    prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
++    IF_BIT_0(prob)
++    {
++      unsigned symbol;
++      UPDATE_0(prob);
++      prob = probs + Literal;
++      if (checkDicSize != 0 || processedPos != 0)
++        prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) +
++        (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc))));
++
++      if (state < kNumLitStates)
++      {
++        state -= (state < 4) ? state : 3;
++        symbol = 1;
++        do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100);
++      }
++      else
++      {
++        unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
++        unsigned offs = 0x100;
++        state -= (state < 10) ? 3 : 6;
++        symbol = 1;
++        do
++        {
++          unsigned bit;
++          CLzmaProb *probLit;
++          matchByte <<= 1;
++          bit = (matchByte & offs);
++          probLit = prob + offs + bit + symbol;
++          GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit)
++        }
++        while (symbol < 0x100);
++      }
++      dic[dicPos++] = (Byte)symbol;
++      processedPos++;
++      continue;
++    }
++    else
++    {
++      UPDATE_1(prob);
++      prob = probs + IsRep + state;
++      IF_BIT_0(prob)
++      {
++        UPDATE_0(prob);
++        state += kNumStates;
++        prob = probs + LenCoder;
++      }
++      else
++      {
++        UPDATE_1(prob);
++        if (checkDicSize == 0 && processedPos == 0)
++          return SZ_ERROR_DATA;
++        prob = probs + IsRepG0 + state;
++        IF_BIT_0(prob)
++        {
++          UPDATE_0(prob);
++          prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
++          IF_BIT_0(prob)
++          {
++            UPDATE_0(prob);
++            dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
++            dicPos++;
++            processedPos++;
++            state = state < kNumLitStates ? 9 : 11;
++            continue;
++          }
++          UPDATE_1(prob);
++        }
++        else
++        {
++          UInt32 distance;
++          UPDATE_1(prob);
++          prob = probs + IsRepG1 + state;
++          IF_BIT_0(prob)
++          {
++            UPDATE_0(prob);
++            distance = rep1;
++          }
++          else
++          {
++            UPDATE_1(prob);
++            prob = probs + IsRepG2 + state;
++            IF_BIT_0(prob)
++            {
++              UPDATE_0(prob);
++              distance = rep2;
++            }
++            else
++            {
++              UPDATE_1(prob);
++              distance = rep3;
++              rep3 = rep2;
++            }
++            rep2 = rep1;
++          }
++          rep1 = rep0;
++          rep0 = distance;
++        }
++        state = state < kNumLitStates ? 8 : 11;
++        prob = probs + RepLenCoder;
++      }
++      {
++        unsigned limit, offset;
++        CLzmaProb *probLen = prob + LenChoice;
++        IF_BIT_0(probLen)
++        {
++          UPDATE_0(probLen);
++          probLen = prob + LenLow + (posState << kLenNumLowBits);
++          offset = 0;
++          limit = (1 << kLenNumLowBits);
++        }
++        else
++        {
++          UPDATE_1(probLen);
++          probLen = prob + LenChoice2;
++          IF_BIT_0(probLen)
++          {
++            UPDATE_0(probLen);
++            probLen = prob + LenMid + (posState << kLenNumMidBits);
++            offset = kLenNumLowSymbols;
++            limit = (1 << kLenNumMidBits);
++          }
++          else
++          {
++            UPDATE_1(probLen);
++            probLen = prob + LenHigh;
++            offset = kLenNumLowSymbols + kLenNumMidSymbols;
++            limit = (1 << kLenNumHighBits);
++          }
++        }
++        TREE_DECODE(probLen, limit, len);
++        len += offset;
++      }
++
++      if (state >= kNumStates)
++      {
++        UInt32 distance;
++        prob = probs + PosSlot +
++            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
++        TREE_6_DECODE(prob, distance);
++        if (distance >= kStartPosModelIndex)
++        {
++          unsigned posSlot = (unsigned)distance;
++          int numDirectBits = (int)(((distance >> 1) - 1));
++          distance = (2 | (distance & 1));
++          if (posSlot < kEndPosModelIndex)
++          {
++            distance <<= numDirectBits;
++            prob = probs + SpecPos + distance - posSlot - 1;
++            {
++              UInt32 mask = 1;
++              unsigned i = 1;
++              do
++              {
++                GET_BIT2(prob + i, i, ; , distance |= mask);
++                mask <<= 1;
++              }
++              while (--numDirectBits != 0);
++            }
++          }
++          else
++          {
++            numDirectBits -= kNumAlignBits;
++            do
++            {
++              NORMALIZE
++              range >>= 1;
++
++              {
++                UInt32 t;
++                code -= range;
++                t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */
++                distance = (distance << 1) + (t + 1);
++                code += range & t;
++              }
++              /*
++              distance <<= 1;
++              if (code >= range)
++              {
++                code -= range;
++                distance |= 1;
++              }
++              */
++            }
++            while (--numDirectBits != 0);
++            prob = probs + Align;
++            distance <<= kNumAlignBits;
++            {
++              unsigned i = 1;
++              GET_BIT2(prob + i, i, ; , distance |= 1);
++              GET_BIT2(prob + i, i, ; , distance |= 2);
++              GET_BIT2(prob + i, i, ; , distance |= 4);
++              GET_BIT2(prob + i, i, ; , distance |= 8);
++            }
++            if (distance == (UInt32)0xFFFFFFFF)
++            {
++              len += kMatchSpecLenStart;
++              state -= kNumStates;
++              break;
++            }
++          }
++        }
++        rep3 = rep2;
++        rep2 = rep1;
++        rep1 = rep0;
++        rep0 = distance + 1;
++        if (checkDicSize == 0)
++        {
++          if (distance >= processedPos)
++            return SZ_ERROR_DATA;
++        }
++        else if (distance >= checkDicSize)
++          return SZ_ERROR_DATA;
++        state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
++      }
++
++      len += kMatchMinLen;
++
++      if (limit == dicPos)
++        return SZ_ERROR_DATA;
++      {
++        SizeT rem = limit - dicPos;
++        unsigned curLen = ((rem < len) ? (unsigned)rem : len);
++        SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0);
++
++        processedPos += curLen;
++
++        len -= curLen;
++        if (pos + curLen <= dicBufSize)
++        {
++          Byte *dest = dic + dicPos;
++          ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
++          const Byte *lim = dest + curLen;
++          dicPos += curLen;
++          do
++            *(dest) = (Byte)*(dest + src);
++          while (++dest != lim);
++        }
++        else
++        {
++          do
++          {
++            dic[dicPos++] = dic[pos];
++            if (++pos == dicBufSize)
++              pos = 0;
++          }
++          while (--curLen != 0);
++        }
++      }
++    }
++  }
++  while (dicPos < limit && buf < bufLimit);
++  NORMALIZE;
++  p->buf = buf;
++  p->range = range;
++  p->code = code;
++  p->remainLen = len;
++  p->dicPos = dicPos;
++  p->processedPos = processedPos;
++  p->reps[0] = rep0;
++  p->reps[1] = rep1;
++  p->reps[2] = rep2;
++  p->reps[3] = rep3;
++  p->state = state;
++
++  return SZ_OK;
++}
++
++static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
++{
++  if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart)
++  {
++    Byte *dic = p->dic;
++    SizeT dicPos = p->dicPos;
++    SizeT dicBufSize = p->dicBufSize;
++    unsigned len = p->remainLen;
++    UInt32 rep0 = p->reps[0];
++    if (limit - dicPos < len)
++      len = (unsigned)(limit - dicPos);
++
++    if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
++      p->checkDicSize = p->prop.dicSize;
++
++    p->processedPos += len;
++    p->remainLen -= len;
++    while (len-- != 0)
++    {
++      dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
++      dicPos++;
++    }
++    p->dicPos = dicPos;
++  }
++}
++
++static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
++{
++  do
++  {
++    SizeT limit2 = limit;
++    if (p->checkDicSize == 0)
++    {
++      UInt32 rem = p->prop.dicSize - p->processedPos;
++      if (limit - p->dicPos > rem)
++        limit2 = p->dicPos + rem;
++    }
++    RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit));
++    if (p->processedPos >= p->prop.dicSize)
++      p->checkDicSize = p->prop.dicSize;
++    LzmaDec_WriteRem(p, limit);
++  }
++  while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart);
++
++  if (p->remainLen > kMatchSpecLenStart)
++  {
++    p->remainLen = kMatchSpecLenStart;
++  }
++  return 0;
++}
++
++typedef enum
++{
++  DUMMY_ERROR, /* unexpected end of input stream */
++  DUMMY_LIT,
++  DUMMY_MATCH,
++  DUMMY_REP
++} ELzmaDummy;
++
++static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize)
++{
++  UInt32 range = p->range;
++  UInt32 code = p->code;
++  const Byte *bufLimit = buf + inSize;
++  CLzmaProb *probs = p->probs;
++  unsigned state = p->state;
++  ELzmaDummy res;
++
++  {
++    CLzmaProb *prob;
++    UInt32 bound;
++    unsigned ttt;
++    unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1);
++
++    prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
++    IF_BIT_0_CHECK(prob)
++    {
++      UPDATE_0_CHECK
++
++      /* if (bufLimit - buf >= 7) return DUMMY_LIT; */
++
++      prob = probs + Literal;
++      if (p->checkDicSize != 0 || p->processedPos != 0)
++        prob += (LZMA_LIT_SIZE *
++          ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) +
++          (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
++
++      if (state < kNumLitStates)
++      {
++        unsigned symbol = 1;
++        do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100);
++      }
++      else
++      {
++        unsigned matchByte = p->dic[p->dicPos - p->reps[0] +
++            ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)];
++        unsigned offs = 0x100;
++        unsigned symbol = 1;
++        do
++        {
++          unsigned bit;
++          CLzmaProb *probLit;
++          matchByte <<= 1;
++          bit = (matchByte & offs);
++          probLit = prob + offs + bit + symbol;
++          GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit)
++        }
++        while (symbol < 0x100);
++      }
++      res = DUMMY_LIT;
++    }
++    else
++    {
++      unsigned len;
++      UPDATE_1_CHECK;
++
++      prob = probs + IsRep + state;
++      IF_BIT_0_CHECK(prob)
++      {
++        UPDATE_0_CHECK;
++        state = 0;
++        prob = probs + LenCoder;
++        res = DUMMY_MATCH;
++      }
++      else
++      {
++        UPDATE_1_CHECK;
++        res = DUMMY_REP;
++        prob = probs + IsRepG0 + state;
++        IF_BIT_0_CHECK(prob)
++        {
++          UPDATE_0_CHECK;
++          prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
++          IF_BIT_0_CHECK(prob)
++          {
++            UPDATE_0_CHECK;
++            NORMALIZE_CHECK;
++            return DUMMY_REP;
++          }
++          else
++          {
++            UPDATE_1_CHECK;
++          }
++        }
++        else
++        {
++          UPDATE_1_CHECK;
++          prob = probs + IsRepG1 + state;
++          IF_BIT_0_CHECK(prob)
++          {
++            UPDATE_0_CHECK;
++          }
++          else
++          {
++            UPDATE_1_CHECK;
++            prob = probs + IsRepG2 + state;
++            IF_BIT_0_CHECK(prob)
++            {
++              UPDATE_0_CHECK;
++            }
++            else
++            {
++              UPDATE_1_CHECK;
++            }
++          }
++        }
++        state = kNumStates;
++        prob = probs + RepLenCoder;
++      }
++      {
++        unsigned limit, offset;
++        CLzmaProb *probLen = prob + LenChoice;
++        IF_BIT_0_CHECK(probLen)
++        {
++          UPDATE_0_CHECK;
++          probLen = prob + LenLow + (posState << kLenNumLowBits);
++          offset = 0;
++          limit = 1 << kLenNumLowBits;
++        }
++        else
++        {
++          UPDATE_1_CHECK;
++          probLen = prob + LenChoice2;
++          IF_BIT_0_CHECK(probLen)
++          {
++            UPDATE_0_CHECK;
++            probLen = prob + LenMid + (posState << kLenNumMidBits);
++            offset = kLenNumLowSymbols;
++            limit = 1 << kLenNumMidBits;
++          }
++          else
++          {
++            UPDATE_1_CHECK;
++            probLen = prob + LenHigh;
++            offset = kLenNumLowSymbols + kLenNumMidSymbols;
++            limit = 1 << kLenNumHighBits;
++          }
++        }
++        TREE_DECODE_CHECK(probLen, limit, len);
++        len += offset;
++      }
++
++      if (state < 4)
++      {
++        unsigned posSlot;
++        prob = probs + PosSlot +
++            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
++            kNumPosSlotBits);
++        TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
++        if (posSlot >= kStartPosModelIndex)
++        {
++          int numDirectBits = ((posSlot >> 1) - 1);
++
++          /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */
++
++          if (posSlot < kEndPosModelIndex)
++          {
++            prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1;
++          }
++          else
++          {
++            numDirectBits -= kNumAlignBits;
++            do
++            {
++              NORMALIZE_CHECK
++              range >>= 1;
++              code -= range & (((code - range) >> 31) - 1);
++              /* if (code >= range) code -= range; */
++            }
++            while (--numDirectBits != 0);
++            prob = probs + Align;
++            numDirectBits = kNumAlignBits;
++          }
++          {
++            unsigned i = 1;
++            do
++            {
++              GET_BIT_CHECK(prob + i, i);
++            }
++            while (--numDirectBits != 0);
++          }
++        }
++      }
++    }
++  }
++  NORMALIZE_CHECK;
++  return res;
++}
++
++
++static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data)
++{
++  p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]);
++  p->range = 0xFFFFFFFF;
++  p->needFlush = 0;
++}
++
++void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
++{
++  p->needFlush = 1;
++  p->remainLen = 0;
++  p->tempBufSize = 0;
++
++  if (initDic)
++  {
++    p->processedPos = 0;
++    p->checkDicSize = 0;
++    p->needInitState = 1;
++  }
++  if (initState)
++    p->needInitState = 1;
++}
++
++void LzmaDec_Init(CLzmaDec *p)
++{
++  p->dicPos = 0;
++  LzmaDec_InitDicAndState(p, True, True);
++}
++
++static void LzmaDec_InitStateReal(CLzmaDec *p)
++{
++  UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp));
++  UInt32 i;
++  CLzmaProb *probs = p->probs;
++  for (i = 0; i < numProbs; i++)
++    probs[i] = kBitModelTotal >> 1;
++  p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1;
++  p->state = 0;
++  p->needInitState = 0;
++}
++
++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
++    ELzmaFinishMode finishMode, ELzmaStatus *status)
++{
++  SizeT inSize = *srcLen;
++  (*srcLen) = 0;
++  LzmaDec_WriteRem(p, dicLimit);
++
++  *status = LZMA_STATUS_NOT_SPECIFIED;
++
++  while (p->remainLen != kMatchSpecLenStart)
++  {
++      int checkEndMarkNow;
++
++      if (p->needFlush != 0)
++      {
++        for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
++          p->tempBuf[p->tempBufSize++] = *src++;
++        if (p->tempBufSize < RC_INIT_SIZE)
++        {
++          *status = LZMA_STATUS_NEEDS_MORE_INPUT;
++          return SZ_OK;
++        }
++        if (p->tempBuf[0] != 0)
++          return SZ_ERROR_DATA;
++
++        LzmaDec_InitRc(p, p->tempBuf);
++        p->tempBufSize = 0;
++      }
++
++      checkEndMarkNow = 0;
++      if (p->dicPos >= dicLimit)
++      {
++        if (p->remainLen == 0 && p->code == 0)
++        {
++          *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK;
++          return SZ_OK;
++        }
++        if (finishMode == LZMA_FINISH_ANY)
++        {
++          *status = LZMA_STATUS_NOT_FINISHED;
++          return SZ_OK;
++        }
++        if (p->remainLen != 0)
++        {
++          *status = LZMA_STATUS_NOT_FINISHED;
++          return SZ_ERROR_DATA;
++        }
++        checkEndMarkNow = 1;
++      }
++
++      if (p->needInitState)
++        LzmaDec_InitStateReal(p);
++
++      if (p->tempBufSize == 0)
++      {
++        SizeT processed;
++        const Byte *bufLimit;
++        if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
++        {
++          int dummyRes = LzmaDec_TryDummy(p, src, inSize);
++          if (dummyRes == DUMMY_ERROR)
++          {
++            memcpy(p->tempBuf, src, inSize);
++            p->tempBufSize = (unsigned)inSize;
++            (*srcLen) += inSize;
++            *status = LZMA_STATUS_NEEDS_MORE_INPUT;
++            return SZ_OK;
++          }
++          if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
++          {
++            *status = LZMA_STATUS_NOT_FINISHED;
++            return SZ_ERROR_DATA;
++          }
++          bufLimit = src;
++        }
++        else
++          bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX;
++        p->buf = src;
++        if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0)
++          return SZ_ERROR_DATA;
++        processed = (SizeT)(p->buf - src);
++        (*srcLen) += processed;
++        src += processed;
++        inSize -= processed;
++      }
++      else
++      {
++        unsigned rem = p->tempBufSize, lookAhead = 0;
++        while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize)
++          p->tempBuf[rem++] = src[lookAhead++];
++        p->tempBufSize = rem;
++        if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
++        {
++          int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem);
++          if (dummyRes == DUMMY_ERROR)
++          {
++            (*srcLen) += lookAhead;
++            *status = LZMA_STATUS_NEEDS_MORE_INPUT;
++            return SZ_OK;
++          }
++          if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
++          {
++            *status = LZMA_STATUS_NOT_FINISHED;
++            return SZ_ERROR_DATA;
++          }
++        }
++        p->buf = p->tempBuf;
++        if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0)
++          return SZ_ERROR_DATA;
++        lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf));
++        (*srcLen) += lookAhead;
++        src += lookAhead;
++        inSize -= lookAhead;
++        p->tempBufSize = 0;
++      }
++  }
++  if (p->code == 0)
++    *status = LZMA_STATUS_FINISHED_WITH_MARK;
++  return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA;
++}
++
++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
++{
++  SizeT outSize = *destLen;
++  SizeT inSize = *srcLen;
++  *srcLen = *destLen = 0;
++  for (;;)
++  {
++    SizeT inSizeCur = inSize, outSizeCur, dicPos;
++    ELzmaFinishMode curFinishMode;
++    SRes res;
++    if (p->dicPos == p->dicBufSize)
++      p->dicPos = 0;
++    dicPos = p->dicPos;
++    if (outSize > p->dicBufSize - dicPos)
++    {
++      outSizeCur = p->dicBufSize;
++      curFinishMode = LZMA_FINISH_ANY;
++    }
++    else
++    {
++      outSizeCur = dicPos + outSize;
++      curFinishMode = finishMode;
++    }
++
++    res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
++    src += inSizeCur;
++    inSize -= inSizeCur;
++    *srcLen += inSizeCur;
++    outSizeCur = p->dicPos - dicPos;
++    memcpy(dest, p->dic + dicPos, outSizeCur);
++    dest += outSizeCur;
++    outSize -= outSizeCur;
++    *destLen += outSizeCur;
++    if (res != 0)
++      return res;
++    if (outSizeCur == 0 || outSize == 0)
++      return SZ_OK;
++  }
++}
++
++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->probs);
++  p->probs = 0;
++}
++
++static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->dic);
++  p->dic = 0;
++}
++
++void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)
++{
++  LzmaDec_FreeProbs(p, alloc);
++  LzmaDec_FreeDict(p, alloc);
++}
++
++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
++{
++  UInt32 dicSize;
++  Byte d;
++
++  if (size < LZMA_PROPS_SIZE)
++    return SZ_ERROR_UNSUPPORTED;
++  else
++    dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24);
++
++  if (dicSize < LZMA_DIC_MIN)
++    dicSize = LZMA_DIC_MIN;
++  p->dicSize = dicSize;
++
++  d = data[0];
++  if (d >= (9 * 5 * 5))
++    return SZ_ERROR_UNSUPPORTED;
++
++  p->lc = d % 9;
++  d /= 9;
++  p->pb = d / 5;
++  p->lp = d % 5;
++
++  return SZ_OK;
++}
++
++static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc)
++{
++  UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
++  if (p->probs == 0 || numProbs != p->numProbs)
++  {
++    LzmaDec_FreeProbs(p, alloc);
++    p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb));
++    p->numProbs = numProbs;
++    if (p->probs == 0)
++      return SZ_ERROR_MEM;
++  }
++  return SZ_OK;
++}
++
++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
++{
++  CLzmaProps propNew;
++  RINOK(LzmaProps_Decode(&propNew, props, propsSize));
++  RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
++  p->prop = propNew;
++  return SZ_OK;
++}
++
++SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
++{
++  CLzmaProps propNew;
++  SizeT dicBufSize;
++  RINOK(LzmaProps_Decode(&propNew, props, propsSize));
++  RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
++  dicBufSize = propNew.dicSize;
++  if (p->dic == 0 || dicBufSize != p->dicBufSize)
++  {
++    LzmaDec_FreeDict(p, alloc);
++    p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
++    if (p->dic == 0)
++    {
++      LzmaDec_FreeProbs(p, alloc);
++      return SZ_ERROR_MEM;
++    }
++  }
++  p->dicBufSize = dicBufSize;
++  p->prop = propNew;
++  return SZ_OK;
++}
++
++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
++    const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
++    ELzmaStatus *status, ISzAlloc *alloc)
++{
++  CLzmaDec p;
++  SRes res;
++  SizeT inSize = *srcLen;
++  SizeT outSize = *destLen;
++  *srcLen = *destLen = 0;
++  if (inSize < RC_INIT_SIZE)
++    return SZ_ERROR_INPUT_EOF;
++
++  LzmaDec_Construct(&p);
++  res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc);
++  if (res != 0)
++    return res;
++  p.dic = dest;
++  p.dicBufSize = outSize;
++
++  LzmaDec_Init(&p);
++
++  *srcLen = inSize;
++  res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
++
++  if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
++    res = SZ_ERROR_INPUT_EOF;
++
++  (*destLen) = p.dicPos;
++  LzmaDec_FreeProbs(&p, alloc);
++  return res;
++}
+--- /dev/null
++++ b/lib/lzma/LzmaEnc.c
+@@ -0,0 +1,2271 @@
++/* LzmaEnc.c -- LZMA Encoder
++2009-11-24 : Igor Pavlov : Public domain */
++
++#include <string.h>
++
++/* #define SHOW_STAT */
++/* #define SHOW_STAT2 */
++
++#if defined(SHOW_STAT) || defined(SHOW_STAT2)
++#include <stdio.h>
++#endif
++
++#include "LzmaEnc.h"
++
++/* disable MT */
++#define _7ZIP_ST
++
++#include "LzFind.h"
++#ifndef _7ZIP_ST
++#include "LzFindMt.h"
++#endif
++
++#ifdef SHOW_STAT
++static int ttt = 0;
++#endif
++
++#define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1)
++
++#define kBlockSize (9 << 10)
++#define kUnpackBlockSize (1 << 18)
++#define kMatchArraySize (1 << 21)
++#define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX)
++
++#define kNumMaxDirectBits (31)
++
++#define kNumTopBits 24
++#define kTopValue ((UInt32)1 << kNumTopBits)
++
++#define kNumBitModelTotalBits 11
++#define kBitModelTotal (1 << kNumBitModelTotalBits)
++#define kNumMoveBits 5
++#define kProbInitValue (kBitModelTotal >> 1)
++
++#define kNumMoveReducingBits 4
++#define kNumBitPriceShiftBits 4
++#define kBitPrice (1 << kNumBitPriceShiftBits)
++
++void LzmaEncProps_Init(CLzmaEncProps *p)
++{
++  p->level = 5;
++  p->dictSize = p->mc = 0;
++  p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1;
++  p->writeEndMark = 0;
++}
++
++void LzmaEncProps_Normalize(CLzmaEncProps *p)
++{
++  int level = p->level;
++  if (level < 0) level = 5;
++  p->level = level;
++  if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26)));
++  if (p->lc < 0) p->lc = 3;
++  if (p->lp < 0) p->lp = 0;
++  if (p->pb < 0) p->pb = 2;
++  if (p->algo < 0) p->algo = (level < 5 ? 0 : 1);
++  if (p->fb < 0) p->fb = (level < 7 ? 32 : 64);
++  if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1);
++  if (p->numHashBytes < 0) p->numHashBytes = 4;
++  if (p->mc == 0)  p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1);
++  if (p->numThreads < 0)
++    p->numThreads =
++      #ifndef _7ZIP_ST
++      ((p->btMode && p->algo) ? 2 : 1);
++      #else
++      1;
++      #endif
++}
++
++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
++{
++  CLzmaEncProps props = *props2;
++  LzmaEncProps_Normalize(&props);
++  return props.dictSize;
++}
++
++/* #define LZMA_LOG_BSR */
++/* Define it for Intel's CPU */
++
++
++#ifdef LZMA_LOG_BSR
++
++#define kDicLogSizeMaxCompress 30
++
++#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); }
++
++UInt32 GetPosSlot1(UInt32 pos)
++{
++  UInt32 res;
++  BSR2_RET(pos, res);
++  return res;
++}
++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
++#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); }
++
++#else
++
++#define kNumLogBits (9 + (int)sizeof(size_t) / 2)
++#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7)
++
++void LzmaEnc_FastPosInit(Byte *g_FastPos)
++{
++  int c = 2, slotFast;
++  g_FastPos[0] = 0;
++  g_FastPos[1] = 1;
++
++  for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++)
++  {
++    UInt32 k = (1 << ((slotFast >> 1) - 1));
++    UInt32 j;
++    for (j = 0; j < k; j++, c++)
++      g_FastPos[c] = (Byte)slotFast;
++  }
++}
++
++#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \
++  (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \
++  res = p->g_FastPos[pos >> i] + (i * 2); }
++/*
++#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \
++  p->g_FastPos[pos >> 6] + 12 : \
++  p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; }
++*/
++
++#define GetPosSlot1(pos) p->g_FastPos[pos]
++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
++#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); }
++
++#endif
++
++
++#define LZMA_NUM_REPS 4
++
++typedef unsigned CState;
++
++typedef struct
++{
++  UInt32 price;
++
++  CState state;
++  int prev1IsChar;
++  int prev2;
++
++  UInt32 posPrev2;
++  UInt32 backPrev2;
++
++  UInt32 posPrev;
++  UInt32 backPrev;
++  UInt32 backs[LZMA_NUM_REPS];
++} COptimal;
++
++#define kNumOpts (1 << 12)
++
++#define kNumLenToPosStates 4
++#define kNumPosSlotBits 6
++#define kDicLogSizeMin 0
++#define kDicLogSizeMax 32
++#define kDistTableSizeMax (kDicLogSizeMax * 2)
++
++
++#define kNumAlignBits 4
++#define kAlignTableSize (1 << kNumAlignBits)
++#define kAlignMask (kAlignTableSize - 1)
++
++#define kStartPosModelIndex 4
++#define kEndPosModelIndex 14
++#define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex)
++
++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
++
++#ifdef _LZMA_PROB32
++#define CLzmaProb UInt32
++#else
++#define CLzmaProb UInt16
++#endif
++
++#define LZMA_PB_MAX 4
++#define LZMA_LC_MAX 8
++#define LZMA_LP_MAX 4
++
++#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX)
++
++
++#define kLenNumLowBits 3
++#define kLenNumLowSymbols (1 << kLenNumLowBits)
++#define kLenNumMidBits 3
++#define kLenNumMidSymbols (1 << kLenNumMidBits)
++#define kLenNumHighBits 8
++#define kLenNumHighSymbols (1 << kLenNumHighBits)
++
++#define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
++
++#define LZMA_MATCH_LEN_MIN 2
++#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1)
++
++#define kNumStates 12
++
++typedef struct
++{
++  CLzmaProb choice;
++  CLzmaProb choice2;
++  CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits];
++  CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits];
++  CLzmaProb high[kLenNumHighSymbols];
++} CLenEnc;
++
++typedef struct
++{
++  CLenEnc p;
++  UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal];
++  UInt32 tableSize;
++  UInt32 counters[LZMA_NUM_PB_STATES_MAX];
++} CLenPriceEnc;
++
++typedef struct
++{
++  UInt32 range;
++  Byte cache;
++  UInt64 low;
++  UInt64 cacheSize;
++  Byte *buf;
++  Byte *bufLim;
++  Byte *bufBase;
++  ISeqOutStream *outStream;
++  UInt64 processed;
++  SRes res;
++} CRangeEnc;
++
++typedef struct
++{
++  CLzmaProb *litProbs;
++
++  CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
++  CLzmaProb isRep[kNumStates];
++  CLzmaProb isRepG0[kNumStates];
++  CLzmaProb isRepG1[kNumStates];
++  CLzmaProb isRepG2[kNumStates];
++  CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
++
++  CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
++  CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
++  CLzmaProb posAlignEncoder[1 << kNumAlignBits];
++
++  CLenPriceEnc lenEnc;
++  CLenPriceEnc repLenEnc;
++
++  UInt32 reps[LZMA_NUM_REPS];
++  UInt32 state;
++} CSaveState;
++
++typedef struct
++{
++  IMatchFinder matchFinder;
++  void *matchFinderObj;
++
++  #ifndef _7ZIP_ST
++  Bool mtMode;
++  CMatchFinderMt matchFinderMt;
++  #endif
++
++  CMatchFinder matchFinderBase;
++
++  #ifndef _7ZIP_ST
++  Byte pad[128];
++  #endif
++
++  UInt32 optimumEndIndex;
++  UInt32 optimumCurrentIndex;
++
++  UInt32 longestMatchLength;
++  UInt32 numPairs;
++  UInt32 numAvail;
++  COptimal opt[kNumOpts];
++
++  #ifndef LZMA_LOG_BSR
++  Byte g_FastPos[1 << kNumLogBits];
++  #endif
++
++  UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
++  UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1];
++  UInt32 numFastBytes;
++  UInt32 additionalOffset;
++  UInt32 reps[LZMA_NUM_REPS];
++  UInt32 state;
++
++  UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
++  UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances];
++  UInt32 alignPrices[kAlignTableSize];
++  UInt32 alignPriceCount;
++
++  UInt32 distTableSize;
++
++  unsigned lc, lp, pb;
++  unsigned lpMask, pbMask;
++
++  CLzmaProb *litProbs;
++
++  CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
++  CLzmaProb isRep[kNumStates];
++  CLzmaProb isRepG0[kNumStates];
++  CLzmaProb isRepG1[kNumStates];
++  CLzmaProb isRepG2[kNumStates];
++  CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
++
++  CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
++  CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
++  CLzmaProb posAlignEncoder[1 << kNumAlignBits];
++
++  CLenPriceEnc lenEnc;
++  CLenPriceEnc repLenEnc;
++
++  unsigned lclp;
++
++  Bool fastMode;
++
++  CRangeEnc rc;
++
++  Bool writeEndMark;
++  UInt64 nowPos64;
++  UInt32 matchPriceCount;
++  Bool finished;
++  Bool multiThread;
++
++  SRes result;
++  UInt32 dictSize;
++  UInt32 matchFinderCycles;
++
++  int needInit;
++
++  CSaveState saveState;
++} CLzmaEnc;
++
++void LzmaEnc_SaveState(CLzmaEncHandle pp)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  CSaveState *dest = &p->saveState;
++  int i;
++  dest->lenEnc = p->lenEnc;
++  dest->repLenEnc = p->repLenEnc;
++  dest->state = p->state;
++
++  for (i = 0; i < kNumStates; i++)
++  {
++    memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
++    memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
++  }
++  for (i = 0; i < kNumLenToPosStates; i++)
++    memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
++  memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
++  memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
++  memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
++  memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
++  memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
++  memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
++  memcpy(dest->reps, p->reps, sizeof(p->reps));
++  memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb));
++}
++
++void LzmaEnc_RestoreState(CLzmaEncHandle pp)
++{
++  CLzmaEnc *dest = (CLzmaEnc *)pp;
++  const CSaveState *p = &dest->saveState;
++  int i;
++  dest->lenEnc = p->lenEnc;
++  dest->repLenEnc = p->repLenEnc;
++  dest->state = p->state;
++
++  for (i = 0; i < kNumStates; i++)
++  {
++    memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
++    memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
++  }
++  for (i = 0; i < kNumLenToPosStates; i++)
++    memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
++  memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
++  memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
++  memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
++  memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
++  memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
++  memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
++  memcpy(dest->reps, p->reps, sizeof(p->reps));
++  memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb));
++}
++
++SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  CLzmaEncProps props = *props2;
++  LzmaEncProps_Normalize(&props);
++
++  if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX ||
++      props.dictSize > (1 << kDicLogSizeMaxCompress) || props.dictSize > (1 << 30))
++    return SZ_ERROR_PARAM;
++  p->dictSize = props.dictSize;
++  p->matchFinderCycles = props.mc;
++  {
++    unsigned fb = props.fb;
++    if (fb < 5)
++      fb = 5;
++    if (fb > LZMA_MATCH_LEN_MAX)
++      fb = LZMA_MATCH_LEN_MAX;
++    p->numFastBytes = fb;
++  }
++  p->lc = props.lc;
++  p->lp = props.lp;
++  p->pb = props.pb;
++  p->fastMode = (props.algo == 0);
++  p->matchFinderBase.btMode = props.btMode;
++  {
++    UInt32 numHashBytes = 4;
++    if (props.btMode)
++    {
++      if (props.numHashBytes < 2)
++        numHashBytes = 2;
++      else if (props.numHashBytes < 4)
++        numHashBytes = props.numHashBytes;
++    }
++    p->matchFinderBase.numHashBytes = numHashBytes;
++  }
++
++  p->matchFinderBase.cutValue = props.mc;
++
++  p->writeEndMark = props.writeEndMark;
++
++  #ifndef _7ZIP_ST
++  /*
++  if (newMultiThread != _multiThread)
++  {
++    ReleaseMatchFinder();
++    _multiThread = newMultiThread;
++  }
++  */
++  p->multiThread = (props.numThreads > 1);
++  #endif
++
++  return SZ_OK;
++}
++
++static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4,  5,  6,   4, 5};
++static const int kMatchNextStates[kNumStates]   = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
++static const int kRepNextStates[kNumStates]     = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
++static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
++
++#define IsCharState(s) ((s) < 7)
++
++#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1)
++
++#define kInfinityPrice (1 << 30)
++
++static void RangeEnc_Construct(CRangeEnc *p)
++{
++  p->outStream = 0;
++  p->bufBase = 0;
++}
++
++#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize)
++
++#define RC_BUF_SIZE (1 << 16)
++static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc)
++{
++  if (p->bufBase == 0)
++  {
++    p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE);
++    if (p->bufBase == 0)
++      return 0;
++    p->bufLim = p->bufBase + RC_BUF_SIZE;
++  }
++  return 1;
++}
++
++static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->bufBase);
++  p->bufBase = 0;
++}
++
++static void RangeEnc_Init(CRangeEnc *p)
++{
++  /* Stream.Init(); */
++  p->low = 0;
++  p->range = 0xFFFFFFFF;
++  p->cacheSize = 1;
++  p->cache = 0;
++
++  p->buf = p->bufBase;
++
++  p->processed = 0;
++  p->res = SZ_OK;
++}
++
++static void RangeEnc_FlushStream(CRangeEnc *p)
++{
++  size_t num;
++  if (p->res != SZ_OK)
++    return;
++  num = p->buf - p->bufBase;
++  if (num != p->outStream->Write(p->outStream, p->bufBase, num))
++    p->res = SZ_ERROR_WRITE;
++  p->processed += num;
++  p->buf = p->bufBase;
++}
++
++static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p)
++{
++  if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0)
++  {
++    Byte temp = p->cache;
++    do
++    {
++      Byte *buf = p->buf;
++      *buf++ = (Byte)(temp + (Byte)(p->low >> 32));
++      p->buf = buf;
++      if (buf == p->bufLim)
++        RangeEnc_FlushStream(p);
++      temp = 0xFF;
++    }
++    while (--p->cacheSize != 0);
++    p->cache = (Byte)((UInt32)p->low >> 24);
++  }
++  p->cacheSize++;
++  p->low = (UInt32)p->low << 8;
++}
++
++static void RangeEnc_FlushData(CRangeEnc *p)
++{
++  int i;
++  for (i = 0; i < 5; i++)
++    RangeEnc_ShiftLow(p);
++}
++
++static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits)
++{
++  do
++  {
++    p->range >>= 1;
++    p->low += p->range & (0 - ((value >> --numBits) & 1));
++    if (p->range < kTopValue)
++    {
++      p->range <<= 8;
++      RangeEnc_ShiftLow(p);
++    }
++  }
++  while (numBits != 0);
++}
++
++static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol)
++{
++  UInt32 ttt = *prob;
++  UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt;
++  if (symbol == 0)
++  {
++    p->range = newBound;
++    ttt += (kBitModelTotal - ttt) >> kNumMoveBits;
++  }
++  else
++  {
++    p->low += newBound;
++    p->range -= newBound;
++    ttt -= ttt >> kNumMoveBits;
++  }
++  *prob = (CLzmaProb)ttt;
++  if (p->range < kTopValue)
++  {
++    p->range <<= 8;
++    RangeEnc_ShiftLow(p);
++  }
++}
++
++static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol)
++{
++  symbol |= 0x100;
++  do
++  {
++    RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1);
++    symbol <<= 1;
++  }
++  while (symbol < 0x10000);
++}
++
++static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte)
++{
++  UInt32 offs = 0x100;
++  symbol |= 0x100;
++  do
++  {
++    matchByte <<= 1;
++    RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1);
++    symbol <<= 1;
++    offs &= ~(matchByte ^ symbol);
++  }
++  while (symbol < 0x10000);
++}
++
++void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
++{
++  UInt32 i;
++  for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits))
++  {
++    const int kCyclesBits = kNumBitPriceShiftBits;
++    UInt32 w = i;
++    UInt32 bitCount = 0;
++    int j;
++    for (j = 0; j < kCyclesBits; j++)
++    {
++      w = w * w;
++      bitCount <<= 1;
++      while (w >= ((UInt32)1 << 16))
++      {
++        w >>= 1;
++        bitCount++;
++      }
++    }
++    ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount);
++  }
++}
++
++
++#define GET_PRICE(prob, symbol) \
++  p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
++
++#define GET_PRICEa(prob, symbol) \
++  ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
++
++#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits]
++#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
++
++#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits]
++#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
++
++static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  symbol |= 0x100;
++  do
++  {
++    price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1);
++    symbol <<= 1;
++  }
++  while (symbol < 0x10000);
++  return price;
++}
++
++static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  UInt32 offs = 0x100;
++  symbol |= 0x100;
++  do
++  {
++    matchByte <<= 1;
++    price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1);
++    symbol <<= 1;
++    offs &= ~(matchByte ^ symbol);
++  }
++  while (symbol < 0x10000);
++  return price;
++}
++
++
++static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
++{
++  UInt32 m = 1;
++  int i;
++  for (i = numBitLevels; i != 0;)
++  {
++    UInt32 bit;
++    i--;
++    bit = (symbol >> i) & 1;
++    RangeEnc_EncodeBit(rc, probs + m, bit);
++    m = (m << 1) | bit;
++  }
++}
++
++static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
++{
++  UInt32 m = 1;
++  int i;
++  for (i = 0; i < numBitLevels; i++)
++  {
++    UInt32 bit = symbol & 1;
++    RangeEnc_EncodeBit(rc, probs + m, bit);
++    m = (m << 1) | bit;
++    symbol >>= 1;
++  }
++}
++
++static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  symbol |= (1 << numBitLevels);
++  while (symbol != 1)
++  {
++    price += GET_PRICEa(probs[symbol >> 1], symbol & 1);
++    symbol >>= 1;
++  }
++  return price;
++}
++
++static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
++{
++  UInt32 price = 0;
++  UInt32 m = 1;
++  int i;
++  for (i = numBitLevels; i != 0; i--)
++  {
++    UInt32 bit = symbol & 1;
++    symbol >>= 1;
++    price += GET_PRICEa(probs[m], bit);
++    m = (m << 1) | bit;
++  }
++  return price;
++}
++
++
++static void LenEnc_Init(CLenEnc *p)
++{
++  unsigned i;
++  p->choice = p->choice2 = kProbInitValue;
++  for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++)
++    p->low[i] = kProbInitValue;
++  for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++)
++    p->mid[i] = kProbInitValue;
++  for (i = 0; i < kLenNumHighSymbols; i++)
++    p->high[i] = kProbInitValue;
++}
++
++static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState)
++{
++  if (symbol < kLenNumLowSymbols)
++  {
++    RangeEnc_EncodeBit(rc, &p->choice, 0);
++    RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol);
++  }
++  else
++  {
++    RangeEnc_EncodeBit(rc, &p->choice, 1);
++    if (symbol < kLenNumLowSymbols + kLenNumMidSymbols)
++    {
++      RangeEnc_EncodeBit(rc, &p->choice2, 0);
++      RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols);
++    }
++    else
++    {
++      RangeEnc_EncodeBit(rc, &p->choice2, 1);
++      RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols);
++    }
++  }
++}
++
++static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices)
++{
++  UInt32 a0 = GET_PRICE_0a(p->choice);
++  UInt32 a1 = GET_PRICE_1a(p->choice);
++  UInt32 b0 = a1 + GET_PRICE_0a(p->choice2);
++  UInt32 b1 = a1 + GET_PRICE_1a(p->choice2);
++  UInt32 i = 0;
++  for (i = 0; i < kLenNumLowSymbols; i++)
++  {
++    if (i >= numSymbols)
++      return;
++    prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices);
++  }
++  for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++)
++  {
++    if (i >= numSymbols)
++      return;
++    prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices);
++  }
++  for (; i < numSymbols; i++)
++    prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices);
++}
++
++static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices)
++{
++  LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices);
++  p->counters[posState] = p->tableSize;
++}
++
++static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices)
++{
++  UInt32 posState;
++  for (posState = 0; posState < numPosStates; posState++)
++    LenPriceEnc_UpdateTable(p, posState, ProbPrices);
++}
++
++static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices)
++{
++  LenEnc_Encode(&p->p, rc, symbol, posState);
++  if (updatePrice)
++    if (--p->counters[posState] == 0)
++      LenPriceEnc_UpdateTable(p, posState, ProbPrices);
++}
++
++
++
++
++static void MovePos(CLzmaEnc *p, UInt32 num)
++{
++  #ifdef SHOW_STAT
++  ttt += num;
++  printf("\n MovePos %d", num);
++  #endif
++  if (num != 0)
++  {
++    p->additionalOffset += num;
++    p->matchFinder.Skip(p->matchFinderObj, num);
++  }
++}
++
++static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes)
++{
++  UInt32 lenRes = 0, numPairs;
++  p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
++  numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches);
++  #ifdef SHOW_STAT
++  printf("\n i = %d numPairs = %d    ", ttt, numPairs / 2);
++  ttt++;
++  {
++    UInt32 i;
++    for (i = 0; i < numPairs; i += 2)
++      printf("%2d %6d   | ", p->matches[i], p->matches[i + 1]);
++  }
++  #endif
++  if (numPairs > 0)
++  {
++    lenRes = p->matches[numPairs - 2];
++    if (lenRes == p->numFastBytes)
++    {
++      const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++      UInt32 distance = p->matches[numPairs - 1] + 1;
++      UInt32 numAvail = p->numAvail;
++      if (numAvail > LZMA_MATCH_LEN_MAX)
++        numAvail = LZMA_MATCH_LEN_MAX;
++      {
++        const Byte *pby2 = pby - distance;
++        for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++);
++      }
++    }
++  }
++  p->additionalOffset++;
++  *numDistancePairsRes = numPairs;
++  return lenRes;
++}
++
++
++#define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False;
++#define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False;
++#define IsShortRep(p) ((p)->backPrev == 0)
++
++static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState)
++{
++  return
++    GET_PRICE_0(p->isRepG0[state]) +
++    GET_PRICE_0(p->isRep0Long[state][posState]);
++}
++
++static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState)
++{
++  UInt32 price;
++  if (repIndex == 0)
++  {
++    price = GET_PRICE_0(p->isRepG0[state]);
++    price += GET_PRICE_1(p->isRep0Long[state][posState]);
++  }
++  else
++  {
++    price = GET_PRICE_1(p->isRepG0[state]);
++    if (repIndex == 1)
++      price += GET_PRICE_0(p->isRepG1[state]);
++    else
++    {
++      price += GET_PRICE_1(p->isRepG1[state]);
++      price += GET_PRICE(p->isRepG2[state], repIndex - 2);
++    }
++  }
++  return price;
++}
++
++static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState)
++{
++  return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] +
++    GetPureRepPrice(p, repIndex, state, posState);
++}
++
++static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur)
++{
++  UInt32 posMem = p->opt[cur].posPrev;
++  UInt32 backMem = p->opt[cur].backPrev;
++  p->optimumEndIndex = cur;
++  do
++  {
++    if (p->opt[cur].prev1IsChar)
++    {
++      MakeAsChar(&p->opt[posMem])
++      p->opt[posMem].posPrev = posMem - 1;
++      if (p->opt[cur].prev2)
++      {
++        p->opt[posMem - 1].prev1IsChar = False;
++        p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2;
++        p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2;
++      }
++    }
++    {
++      UInt32 posPrev = posMem;
++      UInt32 backCur = backMem;
++
++      backMem = p->opt[posPrev].backPrev;
++      posMem = p->opt[posPrev].posPrev;
++
++      p->opt[posPrev].backPrev = backCur;
++      p->opt[posPrev].posPrev = cur;
++      cur = posPrev;
++    }
++  }
++  while (cur != 0);
++  *backRes = p->opt[0].backPrev;
++  p->optimumCurrentIndex  = p->opt[0].posPrev;
++  return p->optimumCurrentIndex;
++}
++
++#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300)
++
++static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes)
++{
++  UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur;
++  UInt32 matchPrice, repMatchPrice, normalMatchPrice;
++  UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS];
++  UInt32 *matches;
++  const Byte *data;
++  Byte curByte, matchByte;
++  if (p->optimumEndIndex != p->optimumCurrentIndex)
++  {
++    const COptimal *opt = &p->opt[p->optimumCurrentIndex];
++    UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex;
++    *backRes = opt->backPrev;
++    p->optimumCurrentIndex = opt->posPrev;
++    return lenRes;
++  }
++  p->optimumCurrentIndex = p->optimumEndIndex = 0;
++
++  if (p->additionalOffset == 0)
++    mainLen = ReadMatchDistances(p, &numPairs);
++  else
++  {
++    mainLen = p->longestMatchLength;
++    numPairs = p->numPairs;
++  }
++
++  numAvail = p->numAvail;
++  if (numAvail < 2)
++  {
++    *backRes = (UInt32)(-1);
++    return 1;
++  }
++  if (numAvail > LZMA_MATCH_LEN_MAX)
++    numAvail = LZMA_MATCH_LEN_MAX;
++
++  data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++  repMaxIndex = 0;
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    UInt32 lenTest;
++    const Byte *data2;
++    reps[i] = p->reps[i];
++    data2 = data - (reps[i] + 1);
++    if (data[0] != data2[0] || data[1] != data2[1])
++    {
++      repLens[i] = 0;
++      continue;
++    }
++    for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);
++    repLens[i] = lenTest;
++    if (lenTest > repLens[repMaxIndex])
++      repMaxIndex = i;
++  }
++  if (repLens[repMaxIndex] >= p->numFastBytes)
++  {
++    UInt32 lenRes;
++    *backRes = repMaxIndex;
++    lenRes = repLens[repMaxIndex];
++    MovePos(p, lenRes - 1);
++    return lenRes;
++  }
++
++  matches = p->matches;
++  if (mainLen >= p->numFastBytes)
++  {
++    *backRes = matches[numPairs - 1] + LZMA_NUM_REPS;
++    MovePos(p, mainLen - 1);
++    return mainLen;
++  }
++  curByte = *data;
++  matchByte = *(data - (reps[0] + 1));
++
++  if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2)
++  {
++    *backRes = (UInt32)-1;
++    return 1;
++  }
++
++  p->opt[0].state = (CState)p->state;
++
++  posState = (position & p->pbMask);
++
++  {
++    const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
++    p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) +
++        (!IsCharState(p->state) ?
++          LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) :
++          LitEnc_GetPrice(probs, curByte, p->ProbPrices));
++  }
++
++  MakeAsChar(&p->opt[1]);
++
++  matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]);
++  repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]);
++
++  if (matchByte == curByte)
++  {
++    UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState);
++    if (shortRepPrice < p->opt[1].price)
++    {
++      p->opt[1].price = shortRepPrice;
++      MakeAsShortRep(&p->opt[1]);
++    }
++  }
++  lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]);
++
++  if (lenEnd < 2)
++  {
++    *backRes = p->opt[1].backPrev;
++    return 1;
++  }
++
++  p->opt[1].posPrev = 0;
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++    p->opt[0].backs[i] = reps[i];
++
++  len = lenEnd;
++  do
++    p->opt[len--].price = kInfinityPrice;
++  while (len >= 2);
++
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    UInt32 repLen = repLens[i];
++    UInt32 price;
++    if (repLen < 2)
++      continue;
++    price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState);
++    do
++    {
++      UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2];
++      COptimal *opt = &p->opt[repLen];
++      if (curAndLenPrice < opt->price)
++      {
++        opt->price = curAndLenPrice;
++        opt->posPrev = 0;
++        opt->backPrev = i;
++        opt->prev1IsChar = False;
++      }
++    }
++    while (--repLen >= 2);
++  }
++
++  normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]);
++
++  len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
++  if (len <= mainLen)
++  {
++    UInt32 offs = 0;
++    while (len > matches[offs])
++      offs += 2;
++    for (; ; len++)
++    {
++      COptimal *opt;
++      UInt32 distance = matches[offs + 1];
++
++      UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN];
++      UInt32 lenToPosState = GetLenToPosState(len);
++      if (distance < kNumFullDistances)
++        curAndLenPrice += p->distancesPrices[lenToPosState][distance];
++      else
++      {
++        UInt32 slot;
++        GetPosSlot2(distance, slot);
++        curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot];
++      }
++      opt = &p->opt[len];
++      if (curAndLenPrice < opt->price)
++      {
++        opt->price = curAndLenPrice;
++        opt->posPrev = 0;
++        opt->backPrev = distance + LZMA_NUM_REPS;
++        opt->prev1IsChar = False;
++      }
++      if (len == matches[offs])
++      {
++        offs += 2;
++        if (offs == numPairs)
++          break;
++      }
++    }
++  }
++
++  cur = 0;
++
++    #ifdef SHOW_STAT2
++    if (position >= 0)
++    {
++      unsigned i;
++      printf("\n pos = %4X", position);
++      for (i = cur; i <= lenEnd; i++)
++      printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price);
++    }
++    #endif
++
++  for (;;)
++  {
++    UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen;
++    UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice;
++    Bool nextIsChar;
++    Byte curByte, matchByte;
++    const Byte *data;
++    COptimal *curOpt;
++    COptimal *nextOpt;
++
++    cur++;
++    if (cur == lenEnd)
++      return Backward(p, backRes, cur);
++
++    newLen = ReadMatchDistances(p, &numPairs);
++    if (newLen >= p->numFastBytes)
++    {
++      p->numPairs = numPairs;
++      p->longestMatchLength = newLen;
++      return Backward(p, backRes, cur);
++    }
++    position++;
++    curOpt = &p->opt[cur];
++    posPrev = curOpt->posPrev;
++    if (curOpt->prev1IsChar)
++    {
++      posPrev--;
++      if (curOpt->prev2)
++      {
++        state = p->opt[curOpt->posPrev2].state;
++        if (curOpt->backPrev2 < LZMA_NUM_REPS)
++          state = kRepNextStates[state];
++        else
++          state = kMatchNextStates[state];
++      }
++      else
++        state = p->opt[posPrev].state;
++      state = kLiteralNextStates[state];
++    }
++    else
++      state = p->opt[posPrev].state;
++    if (posPrev == cur - 1)
++    {
++      if (IsShortRep(curOpt))
++        state = kShortRepNextStates[state];
++      else
++        state = kLiteralNextStates[state];
++    }
++    else
++    {
++      UInt32 pos;
++      const COptimal *prevOpt;
++      if (curOpt->prev1IsChar && curOpt->prev2)
++      {
++        posPrev = curOpt->posPrev2;
++        pos = curOpt->backPrev2;
++        state = kRepNextStates[state];
++      }
++      else
++      {
++        pos = curOpt->backPrev;
++        if (pos < LZMA_NUM_REPS)
++          state = kRepNextStates[state];
++        else
++          state = kMatchNextStates[state];
++      }
++      prevOpt = &p->opt[posPrev];
++      if (pos < LZMA_NUM_REPS)
++      {
++        UInt32 i;
++        reps[0] = prevOpt->backs[pos];
++        for (i = 1; i <= pos; i++)
++          reps[i] = prevOpt->backs[i - 1];
++        for (; i < LZMA_NUM_REPS; i++)
++          reps[i] = prevOpt->backs[i];
++      }
++      else
++      {
++        UInt32 i;
++        reps[0] = (pos - LZMA_NUM_REPS);
++        for (i = 1; i < LZMA_NUM_REPS; i++)
++          reps[i] = prevOpt->backs[i - 1];
++      }
++    }
++    curOpt->state = (CState)state;
++
++    curOpt->backs[0] = reps[0];
++    curOpt->backs[1] = reps[1];
++    curOpt->backs[2] = reps[2];
++    curOpt->backs[3] = reps[3];
++
++    curPrice = curOpt->price;
++    nextIsChar = False;
++    data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++    curByte = *data;
++    matchByte = *(data - (reps[0] + 1));
++
++    posState = (position & p->pbMask);
++
++    curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]);
++    {
++      const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
++      curAnd1Price +=
++        (!IsCharState(state) ?
++          LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) :
++          LitEnc_GetPrice(probs, curByte, p->ProbPrices));
++    }
++
++    nextOpt = &p->opt[cur + 1];
++
++    if (curAnd1Price < nextOpt->price)
++    {
++      nextOpt->price = curAnd1Price;
++      nextOpt->posPrev = cur;
++      MakeAsChar(nextOpt);
++      nextIsChar = True;
++    }
++
++    matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]);
++    repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]);
++
++    if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0))
++    {
++      UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState);
++      if (shortRepPrice <= nextOpt->price)
++      {
++        nextOpt->price = shortRepPrice;
++        nextOpt->posPrev = cur;
++        MakeAsShortRep(nextOpt);
++        nextIsChar = True;
++      }
++    }
++    numAvailFull = p->numAvail;
++    {
++      UInt32 temp = kNumOpts - 1 - cur;
++      if (temp < numAvailFull)
++        numAvailFull = temp;
++    }
++
++    if (numAvailFull < 2)
++      continue;
++    numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes);
++
++    if (!nextIsChar && matchByte != curByte) /* speed optimization */
++    {
++      /* try Literal + rep0 */
++      UInt32 temp;
++      UInt32 lenTest2;
++      const Byte *data2 = data - (reps[0] + 1);
++      UInt32 limit = p->numFastBytes + 1;
++      if (limit > numAvailFull)
++        limit = numAvailFull;
++
++      for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++);
++      lenTest2 = temp - 1;
++      if (lenTest2 >= 2)
++      {
++        UInt32 state2 = kLiteralNextStates[state];
++        UInt32 posStateNext = (position + 1) & p->pbMask;
++        UInt32 nextRepMatchPrice = curAnd1Price +
++            GET_PRICE_1(p->isMatch[state2][posStateNext]) +
++            GET_PRICE_1(p->isRep[state2]);
++        /* for (; lenTest2 >= 2; lenTest2--) */
++        {
++          UInt32 curAndLenPrice;
++          COptimal *opt;
++          UInt32 offset = cur + 1 + lenTest2;
++          while (lenEnd < offset)
++            p->opt[++lenEnd].price = kInfinityPrice;
++          curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
++          opt = &p->opt[offset];
++          if (curAndLenPrice < opt->price)
++          {
++            opt->price = curAndLenPrice;
++            opt->posPrev = cur + 1;
++            opt->backPrev = 0;
++            opt->prev1IsChar = True;
++            opt->prev2 = False;
++          }
++        }
++      }
++    }
++
++    startLen = 2; /* speed optimization */
++    {
++    UInt32 repIndex;
++    for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++)
++    {
++      UInt32 lenTest;
++      UInt32 lenTestTemp;
++      UInt32 price;
++      const Byte *data2 = data - (reps[repIndex] + 1);
++      if (data[0] != data2[0] || data[1] != data2[1])
++        continue;
++      for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);
++      while (lenEnd < cur + lenTest)
++        p->opt[++lenEnd].price = kInfinityPrice;
++      lenTestTemp = lenTest;
++      price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState);
++      do
++      {
++        UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2];
++        COptimal *opt = &p->opt[cur + lenTest];
++        if (curAndLenPrice < opt->price)
++        {
++          opt->price = curAndLenPrice;
++          opt->posPrev = cur;
++          opt->backPrev = repIndex;
++          opt->prev1IsChar = False;
++        }
++      }
++      while (--lenTest >= 2);
++      lenTest = lenTestTemp;
++
++      if (repIndex == 0)
++        startLen = lenTest + 1;
++
++      /* if (_maxMode) */
++        {
++          UInt32 lenTest2 = lenTest + 1;
++          UInt32 limit = lenTest2 + p->numFastBytes;
++          UInt32 nextRepMatchPrice;
++          if (limit > numAvailFull)
++            limit = numAvailFull;
++          for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
++          lenTest2 -= lenTest + 1;
++          if (lenTest2 >= 2)
++          {
++            UInt32 state2 = kRepNextStates[state];
++            UInt32 posStateNext = (position + lenTest) & p->pbMask;
++            UInt32 curAndLenCharPrice =
++                price + p->repLenEnc.prices[posState][lenTest - 2] +
++                GET_PRICE_0(p->isMatch[state2][posStateNext]) +
++                LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
++                    data[lenTest], data2[lenTest], p->ProbPrices);
++            state2 = kLiteralNextStates[state2];
++            posStateNext = (position + lenTest + 1) & p->pbMask;
++            nextRepMatchPrice = curAndLenCharPrice +
++                GET_PRICE_1(p->isMatch[state2][posStateNext]) +
++                GET_PRICE_1(p->isRep[state2]);
++
++            /* for (; lenTest2 >= 2; lenTest2--) */
++            {
++              UInt32 curAndLenPrice;
++              COptimal *opt;
++              UInt32 offset = cur + lenTest + 1 + lenTest2;
++              while (lenEnd < offset)
++                p->opt[++lenEnd].price = kInfinityPrice;
++              curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
++              opt = &p->opt[offset];
++              if (curAndLenPrice < opt->price)
++              {
++                opt->price = curAndLenPrice;
++                opt->posPrev = cur + lenTest + 1;
++                opt->backPrev = 0;
++                opt->prev1IsChar = True;
++                opt->prev2 = True;
++                opt->posPrev2 = cur;
++                opt->backPrev2 = repIndex;
++              }
++            }
++          }
++        }
++    }
++    }
++    /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */
++    if (newLen > numAvail)
++    {
++      newLen = numAvail;
++      for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2);
++      matches[numPairs] = newLen;
++      numPairs += 2;
++    }
++    if (newLen >= startLen)
++    {
++      UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]);
++      UInt32 offs, curBack, posSlot;
++      UInt32 lenTest;
++      while (lenEnd < cur + newLen)
++        p->opt[++lenEnd].price = kInfinityPrice;
++
++      offs = 0;
++      while (startLen > matches[offs])
++        offs += 2;
++      curBack = matches[offs + 1];
++      GetPosSlot2(curBack, posSlot);
++      for (lenTest = /*2*/ startLen; ; lenTest++)
++      {
++        UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN];
++        UInt32 lenToPosState = GetLenToPosState(lenTest);
++        COptimal *opt;
++        if (curBack < kNumFullDistances)
++          curAndLenPrice += p->distancesPrices[lenToPosState][curBack];
++        else
++          curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask];
++
++        opt = &p->opt[cur + lenTest];
++        if (curAndLenPrice < opt->price)
++        {
++          opt->price = curAndLenPrice;
++          opt->posPrev = cur;
++          opt->backPrev = curBack + LZMA_NUM_REPS;
++          opt->prev1IsChar = False;
++        }
++
++        if (/*_maxMode && */lenTest == matches[offs])
++        {
++          /* Try Match + Literal + Rep0 */
++          const Byte *data2 = data - (curBack + 1);
++          UInt32 lenTest2 = lenTest + 1;
++          UInt32 limit = lenTest2 + p->numFastBytes;
++          UInt32 nextRepMatchPrice;
++          if (limit > numAvailFull)
++            limit = numAvailFull;
++          for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
++          lenTest2 -= lenTest + 1;
++          if (lenTest2 >= 2)
++          {
++            UInt32 state2 = kMatchNextStates[state];
++            UInt32 posStateNext = (position + lenTest) & p->pbMask;
++            UInt32 curAndLenCharPrice = curAndLenPrice +
++                GET_PRICE_0(p->isMatch[state2][posStateNext]) +
++                LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
++                    data[lenTest], data2[lenTest], p->ProbPrices);
++            state2 = kLiteralNextStates[state2];
++            posStateNext = (posStateNext + 1) & p->pbMask;
++            nextRepMatchPrice = curAndLenCharPrice +
++                GET_PRICE_1(p->isMatch[state2][posStateNext]) +
++                GET_PRICE_1(p->isRep[state2]);
++
++            /* for (; lenTest2 >= 2; lenTest2--) */
++            {
++              UInt32 offset = cur + lenTest + 1 + lenTest2;
++              UInt32 curAndLenPrice;
++              COptimal *opt;
++              while (lenEnd < offset)
++                p->opt[++lenEnd].price = kInfinityPrice;
++              curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
++              opt = &p->opt[offset];
++              if (curAndLenPrice < opt->price)
++              {
++                opt->price = curAndLenPrice;
++                opt->posPrev = cur + lenTest + 1;
++                opt->backPrev = 0;
++                opt->prev1IsChar = True;
++                opt->prev2 = True;
++                opt->posPrev2 = cur;
++                opt->backPrev2 = curBack + LZMA_NUM_REPS;
++              }
++            }
++          }
++          offs += 2;
++          if (offs == numPairs)
++            break;
++          curBack = matches[offs + 1];
++          if (curBack >= kNumFullDistances)
++            GetPosSlot2(curBack, posSlot);
++        }
++      }
++    }
++  }
++}
++
++#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist))
++
++static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes)
++{
++  UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i;
++  const Byte *data;
++  const UInt32 *matches;
++
++  if (p->additionalOffset == 0)
++    mainLen = ReadMatchDistances(p, &numPairs);
++  else
++  {
++    mainLen = p->longestMatchLength;
++    numPairs = p->numPairs;
++  }
++
++  numAvail = p->numAvail;
++  *backRes = (UInt32)-1;
++  if (numAvail < 2)
++    return 1;
++  if (numAvail > LZMA_MATCH_LEN_MAX)
++    numAvail = LZMA_MATCH_LEN_MAX;
++  data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++
++  repLen = repIndex = 0;
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    UInt32 len;
++    const Byte *data2 = data - (p->reps[i] + 1);
++    if (data[0] != data2[0] || data[1] != data2[1])
++      continue;
++    for (len = 2; len < numAvail && data[len] == data2[len]; len++);
++    if (len >= p->numFastBytes)
++    {
++      *backRes = i;
++      MovePos(p, len - 1);
++      return len;
++    }
++    if (len > repLen)
++    {
++      repIndex = i;
++      repLen = len;
++    }
++  }
++
++  matches = p->matches;
++  if (mainLen >= p->numFastBytes)
++  {
++    *backRes = matches[numPairs - 1] + LZMA_NUM_REPS;
++    MovePos(p, mainLen - 1);
++    return mainLen;
++  }
++
++  mainDist = 0; /* for GCC */
++  if (mainLen >= 2)
++  {
++    mainDist = matches[numPairs - 1];
++    while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1)
++    {
++      if (!ChangePair(matches[numPairs - 3], mainDist))
++        break;
++      numPairs -= 2;
++      mainLen = matches[numPairs - 2];
++      mainDist = matches[numPairs - 1];
++    }
++    if (mainLen == 2 && mainDist >= 0x80)
++      mainLen = 1;
++  }
++
++  if (repLen >= 2 && (
++        (repLen + 1 >= mainLen) ||
++        (repLen + 2 >= mainLen && mainDist >= (1 << 9)) ||
++        (repLen + 3 >= mainLen && mainDist >= (1 << 15))))
++  {
++    *backRes = repIndex;
++    MovePos(p, repLen - 1);
++    return repLen;
++  }
++
++  if (mainLen < 2 || numAvail <= 2)
++    return 1;
++
++  p->longestMatchLength = ReadMatchDistances(p, &p->numPairs);
++  if (p->longestMatchLength >= 2)
++  {
++    UInt32 newDistance = matches[p->numPairs - 1];
++    if ((p->longestMatchLength >= mainLen && newDistance < mainDist) ||
++        (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) ||
++        (p->longestMatchLength > mainLen + 1) ||
++        (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist)))
++      return 1;
++  }
++
++  data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
++  for (i = 0; i < LZMA_NUM_REPS; i++)
++  {
++    UInt32 len, limit;
++    const Byte *data2 = data - (p->reps[i] + 1);
++    if (data[0] != data2[0] || data[1] != data2[1])
++      continue;
++    limit = mainLen - 1;
++    for (len = 2; len < limit && data[len] == data2[len]; len++);
++    if (len >= limit)
++      return 1;
++  }
++  *backRes = mainDist + LZMA_NUM_REPS;
++  MovePos(p, mainLen - 2);
++  return mainLen;
++}
++
++static void WriteEndMarker(CLzmaEnc *p, UInt32 posState)
++{
++  UInt32 len;
++  RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
++  RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
++  p->state = kMatchNextStates[p->state];
++  len = LZMA_MATCH_LEN_MIN;
++  LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
++  RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1);
++  RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits);
++  RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask);
++}
++
++static SRes CheckErrors(CLzmaEnc *p)
++{
++  if (p->result != SZ_OK)
++    return p->result;
++  if (p->rc.res != SZ_OK)
++    p->result = SZ_ERROR_WRITE;
++  if (p->matchFinderBase.result != SZ_OK)
++    p->result = SZ_ERROR_READ;
++  if (p->result != SZ_OK)
++    p->finished = True;
++  return p->result;
++}
++
++static SRes Flush(CLzmaEnc *p, UInt32 nowPos)
++{
++  /* ReleaseMFStream(); */
++  p->finished = True;
++  if (p->writeEndMark)
++    WriteEndMarker(p, nowPos & p->pbMask);
++  RangeEnc_FlushData(&p->rc);
++  RangeEnc_FlushStream(&p->rc);
++  return CheckErrors(p);
++}
++
++static void FillAlignPrices(CLzmaEnc *p)
++{
++  UInt32 i;
++  for (i = 0; i < kAlignTableSize; i++)
++    p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices);
++  p->alignPriceCount = 0;
++}
++
++static void FillDistancesPrices(CLzmaEnc *p)
++{
++  UInt32 tempPrices[kNumFullDistances];
++  UInt32 i, lenToPosState;
++  for (i = kStartPosModelIndex; i < kNumFullDistances; i++)
++  {
++    UInt32 posSlot = GetPosSlot1(i);
++    UInt32 footerBits = ((posSlot >> 1) - 1);
++    UInt32 base = ((2 | (posSlot & 1)) << footerBits);
++    tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices);
++  }
++
++  for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
++  {
++    UInt32 posSlot;
++    const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState];
++    UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState];
++    for (posSlot = 0; posSlot < p->distTableSize; posSlot++)
++      posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices);
++    for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++)
++      posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits);
++
++    {
++      UInt32 *distancesPrices = p->distancesPrices[lenToPosState];
++      UInt32 i;
++      for (i = 0; i < kStartPosModelIndex; i++)
++        distancesPrices[i] = posSlotPrices[i];
++      for (; i < kNumFullDistances; i++)
++        distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i];
++    }
++  }
++  p->matchPriceCount = 0;
++}
++
++void LzmaEnc_Construct(CLzmaEnc *p)
++{
++  RangeEnc_Construct(&p->rc);
++  MatchFinder_Construct(&p->matchFinderBase);
++  #ifndef _7ZIP_ST
++  MatchFinderMt_Construct(&p->matchFinderMt);
++  p->matchFinderMt.MatchFinder = &p->matchFinderBase;
++  #endif
++
++  {
++    CLzmaEncProps props;
++    LzmaEncProps_Init(&props);
++    LzmaEnc_SetProps(p, &props);
++  }
++
++  #ifndef LZMA_LOG_BSR
++  LzmaEnc_FastPosInit(p->g_FastPos);
++  #endif
++
++  LzmaEnc_InitPriceTables(p->ProbPrices);
++  p->litProbs = 0;
++  p->saveState.litProbs = 0;
++}
++
++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc)
++{
++  void *p;
++  p = alloc->Alloc(alloc, sizeof(CLzmaEnc));
++  if (p != 0)
++    LzmaEnc_Construct((CLzmaEnc *)p);
++  return p;
++}
++
++void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
++{
++  alloc->Free(alloc, p->litProbs);
++  alloc->Free(alloc, p->saveState.litProbs);
++  p->litProbs = 0;
++  p->saveState.litProbs = 0;
++}
++
++void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  #ifndef _7ZIP_ST
++  MatchFinderMt_Destruct(&p->matchFinderMt, allocBig);
++  #endif
++  MatchFinder_Free(&p->matchFinderBase, allocBig);
++  LzmaEnc_FreeLits(p, alloc);
++  RangeEnc_Free(&p->rc, alloc);
++}
++
++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig);
++  alloc->Free(alloc, p);
++}
++
++static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize)
++{
++  UInt32 nowPos32, startPos32;
++  if (p->needInit)
++  {
++    p->matchFinder.Init(p->matchFinderObj);
++    p->needInit = 0;
++  }
++
++  if (p->finished)
++    return p->result;
++  RINOK(CheckErrors(p));
++
++  nowPos32 = (UInt32)p->nowPos64;
++  startPos32 = nowPos32;
++
++  if (p->nowPos64 == 0)
++  {
++    UInt32 numPairs;
++    Byte curByte;
++    if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
++      return Flush(p, nowPos32);
++    ReadMatchDistances(p, &numPairs);
++    RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0);
++    p->state = kLiteralNextStates[p->state];
++    curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset);
++    LitEnc_Encode(&p->rc, p->litProbs, curByte);
++    p->additionalOffset--;
++    nowPos32++;
++  }
++
++  if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0)
++  for (;;)
++  {
++    UInt32 pos, len, posState;
++
++    if (p->fastMode)
++      len = GetOptimumFast(p, &pos);
++    else
++      len = GetOptimum(p, nowPos32, &pos);
++
++    #ifdef SHOW_STAT2
++    printf("\n pos = %4X,   len = %d   pos = %d", nowPos32, len, pos);
++    #endif
++
++    posState = nowPos32 & p->pbMask;
++    if (len == 1 && pos == (UInt32)-1)
++    {
++      Byte curByte;
++      CLzmaProb *probs;
++      const Byte *data;
++
++      RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0);
++      data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
++      curByte = *data;
++      probs = LIT_PROBS(nowPos32, *(data - 1));
++      if (IsCharState(p->state))
++        LitEnc_Encode(&p->rc, probs, curByte);
++      else
++        LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1));
++      p->state = kLiteralNextStates[p->state];
++    }
++    else
++    {
++      RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
++      if (pos < LZMA_NUM_REPS)
++      {
++        RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1);
++        if (pos == 0)
++        {
++          RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0);
++          RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1));
++        }
++        else
++        {
++          UInt32 distance = p->reps[pos];
++          RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1);
++          if (pos == 1)
++            RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0);
++          else
++          {
++            RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1);
++            RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2);
++            if (pos == 3)
++              p->reps[3] = p->reps[2];
++            p->reps[2] = p->reps[1];
++          }
++          p->reps[1] = p->reps[0];
++          p->reps[0] = distance;
++        }
++        if (len == 1)
++          p->state = kShortRepNextStates[p->state];
++        else
++        {
++          LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
++          p->state = kRepNextStates[p->state];
++        }
++      }
++      else
++      {
++        UInt32 posSlot;
++        RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
++        p->state = kMatchNextStates[p->state];
++        LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
++        pos -= LZMA_NUM_REPS;
++        GetPosSlot(pos, posSlot);
++        RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot);
++
++        if (posSlot >= kStartPosModelIndex)
++        {
++          UInt32 footerBits = ((posSlot >> 1) - 1);
++          UInt32 base = ((2 | (posSlot & 1)) << footerBits);
++          UInt32 posReduced = pos - base;
++
++          if (posSlot < kEndPosModelIndex)
++            RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced);
++          else
++          {
++            RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
++            RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask);
++            p->alignPriceCount++;
++          }
++        }
++        p->reps[3] = p->reps[2];
++        p->reps[2] = p->reps[1];
++        p->reps[1] = p->reps[0];
++        p->reps[0] = pos;
++        p->matchPriceCount++;
++      }
++    }
++    p->additionalOffset -= len;
++    nowPos32 += len;
++    if (p->additionalOffset == 0)
++    {
++      UInt32 processed;
++      if (!p->fastMode)
++      {
++        if (p->matchPriceCount >= (1 << 7))
++          FillDistancesPrices(p);
++        if (p->alignPriceCount >= kAlignTableSize)
++          FillAlignPrices(p);
++      }
++      if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
++        break;
++      processed = nowPos32 - startPos32;
++      if (useLimits)
++      {
++        if (processed + kNumOpts + 300 >= maxUnpackSize ||
++            RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize)
++          break;
++      }
++      else if (processed >= (1 << 15))
++      {
++        p->nowPos64 += nowPos32 - startPos32;
++        return CheckErrors(p);
++      }
++    }
++  }
++  p->nowPos64 += nowPos32 - startPos32;
++  return Flush(p, nowPos32);
++}
++
++#define kBigHashDicLimit ((UInt32)1 << 24)
++
++static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  UInt32 beforeSize = kNumOpts;
++  Bool btMode;
++  if (!RangeEnc_Alloc(&p->rc, alloc))
++    return SZ_ERROR_MEM;
++  btMode = (p->matchFinderBase.btMode != 0);
++  #ifndef _7ZIP_ST
++  p->mtMode = (p->multiThread && !p->fastMode && btMode);
++  #endif
++
++  {
++    unsigned lclp = p->lc + p->lp;
++    if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp)
++    {
++      LzmaEnc_FreeLits(p, alloc);
++      p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
++      p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
++      if (p->litProbs == 0 || p->saveState.litProbs == 0)
++      {
++        LzmaEnc_FreeLits(p, alloc);
++        return SZ_ERROR_MEM;
++      }
++      p->lclp = lclp;
++    }
++  }
++
++  p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit);
++
++  if (beforeSize + p->dictSize < keepWindowSize)
++    beforeSize = keepWindowSize - p->dictSize;
++
++  #ifndef _7ZIP_ST
++  if (p->mtMode)
++  {
++    RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig));
++    p->matchFinderObj = &p->matchFinderMt;
++    MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder);
++  }
++  else
++  #endif
++  {
++    if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig))
++      return SZ_ERROR_MEM;
++    p->matchFinderObj = &p->matchFinderBase;
++    MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder);
++  }
++  return SZ_OK;
++}
++
++void LzmaEnc_Init(CLzmaEnc *p)
++{
++  UInt32 i;
++  p->state = 0;
++  for (i = 0 ; i < LZMA_NUM_REPS; i++)
++    p->reps[i] = 0;
++
++  RangeEnc_Init(&p->rc);
++
++
++  for (i = 0; i < kNumStates; i++)
++  {
++    UInt32 j;
++    for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++)
++    {
++      p->isMatch[i][j] = kProbInitValue;
++      p->isRep0Long[i][j] = kProbInitValue;
++    }
++    p->isRep[i] = kProbInitValue;
++    p->isRepG0[i] = kProbInitValue;
++    p->isRepG1[i] = kProbInitValue;
++    p->isRepG2[i] = kProbInitValue;
++  }
++
++  {
++    UInt32 num = 0x300 << (p->lp + p->lc);
++    for (i = 0; i < num; i++)
++      p->litProbs[i] = kProbInitValue;
++  }
++
++  {
++    for (i = 0; i < kNumLenToPosStates; i++)
++    {
++      CLzmaProb *probs = p->posSlotEncoder[i];
++      UInt32 j;
++      for (j = 0; j < (1 << kNumPosSlotBits); j++)
++        probs[j] = kProbInitValue;
++    }
++  }
++  {
++    for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
++      p->posEncoders[i] = kProbInitValue;
++  }
++
++  LenEnc_Init(&p->lenEnc.p);
++  LenEnc_Init(&p->repLenEnc.p);
++
++  for (i = 0; i < (1 << kNumAlignBits); i++)
++    p->posAlignEncoder[i] = kProbInitValue;
++
++  p->optimumEndIndex = 0;
++  p->optimumCurrentIndex = 0;
++  p->additionalOffset = 0;
++
++  p->pbMask = (1 << p->pb) - 1;
++  p->lpMask = (1 << p->lp) - 1;
++}
++
++void LzmaEnc_InitPrices(CLzmaEnc *p)
++{
++  if (!p->fastMode)
++  {
++    FillDistancesPrices(p);
++    FillAlignPrices(p);
++  }
++
++  p->lenEnc.tableSize =
++  p->repLenEnc.tableSize =
++      p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN;
++  LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices);
++  LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices);
++}
++
++static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  UInt32 i;
++  for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++)
++    if (p->dictSize <= ((UInt32)1 << i))
++      break;
++  p->distTableSize = i * 2;
++
++  p->finished = False;
++  p->result = SZ_OK;
++  RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig));
++  LzmaEnc_Init(p);
++  LzmaEnc_InitPrices(p);
++  p->nowPos64 = 0;
++  return SZ_OK;
++}
++
++static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream,
++    ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  p->matchFinderBase.stream = inStream;
++  p->needInit = 1;
++  p->rc.outStream = outStream;
++  return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig);
++}
++
++SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp,
++    ISeqInStream *inStream, UInt32 keepWindowSize,
++    ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  p->matchFinderBase.stream = inStream;
++  p->needInit = 1;
++  return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
++}
++
++static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen)
++{
++  p->matchFinderBase.directInput = 1;
++  p->matchFinderBase.bufferBase = (Byte *)src;
++  p->matchFinderBase.directInputRem = srcLen;
++}
++
++SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
++    UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  LzmaEnc_SetInputBuf(p, src, srcLen);
++  p->needInit = 1;
++
++  return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
++}
++
++void LzmaEnc_Finish(CLzmaEncHandle pp)
++{
++  #ifndef _7ZIP_ST
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  if (p->mtMode)
++    MatchFinderMt_ReleaseStream(&p->matchFinderMt);
++  #else
++  pp = pp;
++  #endif
++}
++
++typedef struct
++{
++  ISeqOutStream funcTable;
++  Byte *data;
++  SizeT rem;
++  Bool overflow;
++} CSeqOutStreamBuf;
++
++static size_t MyWrite(void *pp, const void *data, size_t size)
++{
++  CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp;
++  if (p->rem < size)
++  {
++    size = p->rem;
++    p->overflow = True;
++  }
++  memcpy(p->data, data, size);
++  p->rem -= size;
++  p->data += size;
++  return size;
++}
++
++
++UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)
++{
++  const CLzmaEnc *p = (CLzmaEnc *)pp;
++  return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
++}
++
++const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
++{
++  const CLzmaEnc *p = (CLzmaEnc *)pp;
++  return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
++}
++
++SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit,
++    Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  UInt64 nowPos64;
++  SRes res;
++  CSeqOutStreamBuf outStream;
++
++  outStream.funcTable.Write = MyWrite;
++  outStream.data = dest;
++  outStream.rem = *destLen;
++  outStream.overflow = False;
++
++  p->writeEndMark = False;
++  p->finished = False;
++  p->result = SZ_OK;
++
++  if (reInit)
++    LzmaEnc_Init(p);
++  LzmaEnc_InitPrices(p);
++  nowPos64 = p->nowPos64;
++  RangeEnc_Init(&p->rc);
++  p->rc.outStream = &outStream.funcTable;
++
++  res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize);
++
++  *unpackSize = (UInt32)(p->nowPos64 - nowPos64);
++  *destLen -= outStream.rem;
++  if (outStream.overflow)
++    return SZ_ERROR_OUTPUT_EOF;
++
++  return res;
++}
++
++static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress)
++{
++  SRes res = SZ_OK;
++
++  #ifndef _7ZIP_ST
++  Byte allocaDummy[0x300];
++  int i = 0;
++  for (i = 0; i < 16; i++)
++    allocaDummy[i] = (Byte)i;
++  #endif
++
++  for (;;)
++  {
++    res = LzmaEnc_CodeOneBlock(p, False, 0, 0);
++    if (res != SZ_OK || p->finished != 0)
++      break;
++    if (progress != 0)
++    {
++      res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc));
++      if (res != SZ_OK)
++      {
++        res = SZ_ERROR_PROGRESS;
++        break;
++      }
++    }
++  }
++  LzmaEnc_Finish(p);
++  return res;
++}
++
++SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress,
++    ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig));
++  return LzmaEnc_Encode2((CLzmaEnc *)pp, progress);
++}
++
++SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size)
++{
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++  int i;
++  UInt32 dictSize = p->dictSize;
++  if (*size < LZMA_PROPS_SIZE)
++    return SZ_ERROR_PARAM;
++  *size = LZMA_PROPS_SIZE;
++  props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc);
++
++  for (i = 11; i <= 30; i++)
++  {
++    if (dictSize <= ((UInt32)2 << i))
++    {
++      dictSize = (2 << i);
++      break;
++    }
++    if (dictSize <= ((UInt32)3 << i))
++    {
++      dictSize = (3 << i);
++      break;
++    }
++  }
++
++  for (i = 0; i < 4; i++)
++    props[1 + i] = (Byte)(dictSize >> (8 * i));
++  return SZ_OK;
++}
++
++SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  SRes res;
++  CLzmaEnc *p = (CLzmaEnc *)pp;
++
++  CSeqOutStreamBuf outStream;
++
++  LzmaEnc_SetInputBuf(p, src, srcLen);
++
++  outStream.funcTable.Write = MyWrite;
++  outStream.data = dest;
++  outStream.rem = *destLen;
++  outStream.overflow = False;
++
++  p->writeEndMark = writeEndMark;
++
++  p->rc.outStream = &outStream.funcTable;
++  res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig);
++  if (res == SZ_OK)
++    res = LzmaEnc_Encode2(p, progress);
++
++  *destLen -= outStream.rem;
++  if (outStream.overflow)
++    return SZ_ERROR_OUTPUT_EOF;
++  return res;
++}
++
++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
++    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
++    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
++{
++  CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc);
++  SRes res;
++  if (p == 0)
++    return SZ_ERROR_MEM;
++
++  res = LzmaEnc_SetProps(p, props);
++  if (res == SZ_OK)
++  {
++    res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize);
++    if (res == SZ_OK)
++      res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen,
++          writeEndMark, progress, alloc, allocBig);
++  }
++
++  LzmaEnc_Destroy(p, alloc, allocBig);
++  return res;
++}
+--- /dev/null
++++ b/lib/lzma/Makefile
+@@ -0,0 +1,7 @@
++lzma_compress-objs := LzFind.o LzmaEnc.o
++lzma_decompress-objs := LzmaDec.o
++
++obj-$(CONFIG_LZMA_COMPRESS) += lzma_compress.o
++obj-$(CONFIG_LZMA_DECOMPRESS) += lzma_decompress.o
++
++EXTRA_CFLAGS += -Iinclude/linux -Iinclude/linux/lzma -include types.h
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/532-jffs2_eofdetect.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/532-jffs2_eofdetect.patch
new file mode 100644
index 0000000..df4ab9b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/532-jffs2_eofdetect.patch
@@ -0,0 +1,65 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: fs: jffs2: EOF marker
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ fs/jffs2/build.c | 10 ++++++++++
+ fs/jffs2/scan.c  | 21 +++++++++++++++++++--
+ 2 files changed, 29 insertions(+), 2 deletions(-)
+
+--- a/fs/jffs2/build.c
++++ b/fs/jffs2/build.c
+@@ -117,6 +117,16 @@ static int jffs2_build_filesystem(struct
+ 	dbg_fsbuild("scanned flash completely\n");
+ 	jffs2_dbg_dump_block_lists_nolock(c);
+ 
++	if (c->flags & (1 << 7)) {
++		printk("%s(): unlocking the mtd device... ", __func__);
++		mtd_unlock(c->mtd, 0, c->mtd->size);
++		printk("done.\n");
++
++		printk("%s(): erasing all blocks after the end marker... ", __func__);
++		jffs2_erase_pending_blocks(c, -1);
++		printk("done.\n");
++	}
++
+ 	dbg_fsbuild("pass 1 starting\n");
+ 	c->flags |= JFFS2_SB_FLAG_BUILDING;
+ 	/* Now scan the directory tree, increasing nlink according to every dirent found. */
+--- a/fs/jffs2/scan.c
++++ b/fs/jffs2/scan.c
+@@ -148,8 +148,14 @@ int jffs2_scan_medium(struct jffs2_sb_in
+ 		/* reset summary info for next eraseblock scan */
+ 		jffs2_sum_reset_collected(s);
+ 
+-		ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
+-						buf_size, s);
++		if (c->flags & (1 << 7)) {
++			if (mtd_block_isbad(c->mtd, jeb->offset))
++				ret = BLK_STATE_BADBLOCK;
++			else
++				ret = BLK_STATE_ALLFF;
++		} else
++			ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
++							buf_size, s);
+ 
+ 		if (ret < 0)
+ 			goto out;
+@@ -564,6 +570,17 @@ full_scan:
+ 			return err;
+ 	}
+ 
++	if ((buf[0] == 0xde) &&
++		(buf[1] == 0xad) &&
++		(buf[2] == 0xc0) &&
++		(buf[3] == 0xde)) {
++		/* end of filesystem. erase everything after this point */
++		printk("%s(): End of filesystem marker found at 0x%x\n", __func__, jeb->offset);
++		c->flags |= (1 << 7);
++
++		return BLK_STATE_ALLFF;
++	}
++
+ 	/* We temporarily use 'ofs' as a pointer into the buffer/jeb */
+ 	ofs = 0;
+ 	max_ofs = EMPTY_SCAN_SIZE(c->sector_size);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/600-netfilter_conntrack_flush.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/600-netfilter_conntrack_flush.patch
new file mode 100644
index 0000000..eaf8c78
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/600-netfilter_conntrack_flush.patch
@@ -0,0 +1,88 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: netfilter: add support for flushing conntrack via /proc
+
+lede-commit 8193bbe59a74d34d6a26d4a8cb857b1952905314
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ net/netfilter/nf_conntrack_standalone.c | 59 ++++++++++++++++++++++++++++++++-
+ 1 file changed, 58 insertions(+), 1 deletion(-)
+
+--- a/net/netfilter/nf_conntrack_standalone.c
++++ b/net/netfilter/nf_conntrack_standalone.c
+@@ -9,6 +9,7 @@
+ #include <linux/percpu.h>
+ #include <linux/netdevice.h>
+ #include <linux/security.h>
++#include <linux/inet.h>
+ #include <net/net_namespace.h>
+ #ifdef CONFIG_SYSCTL
+ #include <linux/sysctl.h>
+@@ -455,6 +456,56 @@ static int ct_cpu_seq_show(struct seq_fi
+ 	return 0;
+ }
+ 
++struct kill_request {
++	u16 family;
++	union nf_inet_addr addr;
++};
++
++static int kill_matching(struct nf_conn *i, void *data)
++{
++	struct kill_request *kr = data;
++	struct nf_conntrack_tuple *t1 = &i->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
++	struct nf_conntrack_tuple *t2 = &i->tuplehash[IP_CT_DIR_REPLY].tuple;
++
++	if (!kr->family)
++		return 1;
++
++	if (t1->src.l3num != kr->family)
++		return 0;
++
++	return (nf_inet_addr_cmp(&kr->addr, &t1->src.u3) ||
++	        nf_inet_addr_cmp(&kr->addr, &t1->dst.u3) ||
++	        nf_inet_addr_cmp(&kr->addr, &t2->src.u3) ||
++	        nf_inet_addr_cmp(&kr->addr, &t2->dst.u3));
++}
++
++static int ct_file_write(struct file *file, char *buf, size_t count)
++{
++	struct seq_file *seq = file->private_data;
++	struct net *net = seq_file_net(seq);
++	struct kill_request kr = { };
++
++	if (count == 0)
++		return 0;
++
++	if (count >= INET6_ADDRSTRLEN)
++		count = INET6_ADDRSTRLEN - 1;
++
++	if (strnchr(buf, count, ':')) {
++		kr.family = AF_INET6;
++		if (!in6_pton(buf, count, (void *)&kr.addr, '\n', NULL))
++			return -EINVAL;
++	} else if (strnchr(buf, count, '.')) {
++		kr.family = AF_INET;
++		if (!in4_pton(buf, count, (void *)&kr.addr, '\n', NULL))
++			return -EINVAL;
++	}
++
++	nf_ct_iterate_cleanup_net(net, kill_matching, &kr, 0, 0);
++
++	return 0;
++}
++
+ static const struct seq_operations ct_cpu_seq_ops = {
+ 	.start	= ct_cpu_seq_start,
+ 	.next	= ct_cpu_seq_next,
+@@ -468,8 +519,9 @@ static int nf_conntrack_standalone_init_
+ 	kuid_t root_uid;
+ 	kgid_t root_gid;
+ 
+-	pde = proc_create_net("nf_conntrack", 0440, net->proc_net, &ct_seq_ops,
+-			sizeof(struct ct_iter_state));
++	pde = proc_create_net_data_write("nf_conntrack", 0440, net->proc_net,
++					 &ct_seq_ops, &ct_file_write,
++					 sizeof(struct ct_iter_state), NULL);
+ 	if (!pde)
+ 		goto out_nf_conntrack;
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/610-netfilter_match_bypass_default_checks.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/610-netfilter_match_bypass_default_checks.patch
new file mode 100644
index 0000000..703ac82
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/610-netfilter_match_bypass_default_checks.patch
@@ -0,0 +1,110 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: kernel: add a new version of my netfilter speedup patches for linux 2.6.39 and 3.0
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ include/uapi/linux/netfilter_ipv4/ip_tables.h |  1 +
+ net/ipv4/netfilter/ip_tables.c                | 37 +++++++++++++++++++++++++++
+ 2 files changed, 38 insertions(+)
+
+--- a/include/uapi/linux/netfilter_ipv4/ip_tables.h
++++ b/include/uapi/linux/netfilter_ipv4/ip_tables.h
+@@ -89,6 +89,7 @@ struct ipt_ip {
+ #define IPT_F_FRAG		0x01	/* Set if rule is a fragment rule */
+ #define IPT_F_GOTO		0x02	/* Set if jump is a goto */
+ #define IPT_F_MASK		0x03	/* All possible flag bits mask. */
++#define IPT_F_NO_DEF_MATCH	0x80	/* Internal: no default match rules present */
+ 
+ /* Values for "inv" field in struct ipt_ip. */
+ #define IPT_INV_VIA_IN		0x01	/* Invert the sense of IN IFACE. */
+--- a/net/ipv4/netfilter/ip_tables.c
++++ b/net/ipv4/netfilter/ip_tables.c
+@@ -50,6 +50,9 @@ ip_packet_match(const struct iphdr *ip,
+ {
+ 	unsigned long ret;
+ 
++	if (ipinfo->flags & IPT_F_NO_DEF_MATCH)
++		return true;
++
+ 	if (NF_INVF(ipinfo, IPT_INV_SRCIP,
+ 		    (ip->saddr & ipinfo->smsk.s_addr) != ipinfo->src.s_addr) ||
+ 	    NF_INVF(ipinfo, IPT_INV_DSTIP,
+@@ -80,6 +83,29 @@ ip_packet_match(const struct iphdr *ip,
+ 	return true;
+ }
+ 
++static void
++ip_checkdefault(struct ipt_ip *ip)
++{
++	static const char iface_mask[IFNAMSIZ] = {};
++
++	if (ip->invflags || ip->flags & IPT_F_FRAG)
++		return;
++
++	if (memcmp(ip->iniface_mask, iface_mask, IFNAMSIZ) != 0)
++		return;
++
++	if (memcmp(ip->outiface_mask, iface_mask, IFNAMSIZ) != 0)
++		return;
++
++	if (ip->smsk.s_addr || ip->dmsk.s_addr)
++		return;
++
++	if (ip->proto)
++		return;
++
++	ip->flags |= IPT_F_NO_DEF_MATCH;
++}
++
+ static bool
+ ip_checkentry(const struct ipt_ip *ip)
+ {
+@@ -524,6 +550,8 @@ find_check_entry(struct ipt_entry *e, st
+ 	struct xt_mtchk_param mtpar;
+ 	struct xt_entry_match *ematch;
+ 
++	ip_checkdefault(&e->ip);
++
+ 	if (!xt_percpu_counter_alloc(alloc_state, &e->counters))
+ 		return -ENOMEM;
+ 
+@@ -818,6 +846,7 @@ copy_entries_to_user(unsigned int total_
+ 	const struct xt_table_info *private = table->private;
+ 	int ret = 0;
+ 	const void *loc_cpu_entry;
++	u8 flags;
+ 
+ 	counters = alloc_counters(table);
+ 	if (IS_ERR(counters))
+@@ -845,6 +874,14 @@ copy_entries_to_user(unsigned int total_
+ 			goto free_counters;
+ 		}
+ 
++		flags = e->ip.flags & IPT_F_MASK;
++		if (copy_to_user(userptr + off
++				 + offsetof(struct ipt_entry, ip.flags),
++				 &flags, sizeof(flags)) != 0) {
++			ret = -EFAULT;
++			goto free_counters;
++		}
++
+ 		for (i = sizeof(struct ipt_entry);
+ 		     i < e->target_offset;
+ 		     i += m->u.match_size) {
+@@ -1225,12 +1262,15 @@ compat_copy_entry_to_user(struct ipt_ent
+ 	compat_uint_t origsize;
+ 	const struct xt_entry_match *ematch;
+ 	int ret = 0;
++	u8 flags = e->ip.flags & IPT_F_MASK;
+ 
+ 	origsize = *size;
+ 	ce = *dstptr;
+ 	if (copy_to_user(ce, e, sizeof(struct ipt_entry)) != 0 ||
+ 	    copy_to_user(&ce->counters, &counters[i],
+-	    sizeof(counters[i])) != 0)
++	    sizeof(counters[i])) != 0 ||
++	    copy_to_user(&ce->ip.flags, &flags,
++	    sizeof(flags)) != 0)
+ 		return -EFAULT;
+ 
+ 	*dstptr += sizeof(struct compat_ipt_entry);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/611-netfilter_match_bypass_default_table.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/611-netfilter_match_bypass_default_table.patch
new file mode 100644
index 0000000..baf738a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/611-netfilter_match_bypass_default_table.patch
@@ -0,0 +1,106 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: netfilter: match bypass default table
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ net/ipv4/netfilter/ip_tables.c | 79 +++++++++++++++++++++++++++++++-----------
+ 1 file changed, 58 insertions(+), 21 deletions(-)
+
+--- a/net/ipv4/netfilter/ip_tables.c
++++ b/net/ipv4/netfilter/ip_tables.c
+@@ -246,6 +246,33 @@ struct ipt_entry *ipt_next_entry(const s
+ 	return (void *)entry + entry->next_offset;
+ }
+ 
++static bool
++ipt_handle_default_rule(struct ipt_entry *e, unsigned int *verdict)
++{
++	struct xt_entry_target *t;
++	struct xt_standard_target *st;
++
++	if (e->target_offset != sizeof(struct ipt_entry))
++		return false;
++
++	if (!(e->ip.flags & IPT_F_NO_DEF_MATCH))
++		return false;
++
++	t = ipt_get_target(e);
++	if (t->u.kernel.target->target)
++		return false;
++
++	st = (struct xt_standard_target *) t;
++	if (st->verdict == XT_RETURN)
++		return false;
++
++	if (st->verdict >= 0)
++		return false;
++
++	*verdict = (unsigned)(-st->verdict) - 1;
++	return true;
++}
++
+ /* Returns one of the generic firewall policies, like NF_ACCEPT. */
+ unsigned int
+ ipt_do_table(struct sk_buff *skb,
+@@ -266,27 +293,28 @@ ipt_do_table(struct sk_buff *skb,
+ 	unsigned int addend;
+ 
+ 	/* Initialization */
++	WARN_ON(!(table->valid_hooks & (1 << hook)));
++	local_bh_disable();
++	private = READ_ONCE(table->private); /* Address dependency. */
++	cpu        = smp_processor_id();
++	table_base = private->entries;
++
++	e = get_entry(table_base, private->hook_entry[hook]);
++	if (ipt_handle_default_rule(e, &verdict)) {
++		struct xt_counters *counter;
++
++		counter = xt_get_this_cpu_counter(&e->counters);
++		ADD_COUNTER(*counter, skb->len, 1);
++		local_bh_enable();
++		return verdict;
++	}
++
+ 	stackidx = 0;
+ 	ip = ip_hdr(skb);
+ 	indev = state->in ? state->in->name : nulldevname;
+ 	outdev = state->out ? state->out->name : nulldevname;
+-	/* We handle fragments by dealing with the first fragment as
+-	 * if it was a normal packet.  All other fragments are treated
+-	 * normally, except that they will NEVER match rules that ask
+-	 * things we don't know, ie. tcp syn flag or ports).  If the
+-	 * rule is also a fragment-specific rule, non-fragments won't
+-	 * match it. */
+-	acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
+-	acpar.thoff   = ip_hdrlen(skb);
+-	acpar.hotdrop = false;
+-	acpar.state   = state;
+ 
+-	WARN_ON(!(table->valid_hooks & (1 << hook)));
+-	local_bh_disable();
+ 	addend = xt_write_recseq_begin();
+-	private = READ_ONCE(table->private); /* Address dependency. */
+-	cpu        = smp_processor_id();
+-	table_base = private->entries;
+ 	jumpstack  = (struct ipt_entry **)private->jumpstack[cpu];
+ 
+ 	/* Switch to alternate jumpstack if we're being invoked via TEE.
+@@ -299,7 +327,16 @@ ipt_do_table(struct sk_buff *skb,
+ 	if (static_key_false(&xt_tee_enabled))
+ 		jumpstack += private->stacksize * __this_cpu_read(nf_skb_duplicated);
+ 
+-	e = get_entry(table_base, private->hook_entry[hook]);
++	/* We handle fragments by dealing with the first fragment as
++	 * if it was a normal packet.  All other fragments are treated
++	 * normally, except that they will NEVER match rules that ask
++	 * things we don't know, ie. tcp syn flag or ports).  If the
++	 * rule is also a fragment-specific rule, non-fragments won't
++	 * match it. */
++	acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
++	acpar.thoff   = ip_hdrlen(skb);
++	acpar.hotdrop = false;
++	acpar.state   = state;
+ 
+ 	do {
+ 		const struct xt_entry_target *t;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/612-netfilter_match_reduce_memory_access.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/612-netfilter_match_reduce_memory_access.patch
new file mode 100644
index 0000000..79da677
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/612-netfilter_match_reduce_memory_access.patch
@@ -0,0 +1,22 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: netfilter: reduce match memory access
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ net/ipv4/netfilter/ip_tables.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/net/ipv4/netfilter/ip_tables.c
++++ b/net/ipv4/netfilter/ip_tables.c
+@@ -53,9 +53,9 @@ ip_packet_match(const struct iphdr *ip,
+ 	if (ipinfo->flags & IPT_F_NO_DEF_MATCH)
+ 		return true;
+ 
+-	if (NF_INVF(ipinfo, IPT_INV_SRCIP,
++	if (NF_INVF(ipinfo, IPT_INV_SRCIP, ipinfo->smsk.s_addr &&
+ 		    (ip->saddr & ipinfo->smsk.s_addr) != ipinfo->src.s_addr) ||
+-	    NF_INVF(ipinfo, IPT_INV_DSTIP,
++	    NF_INVF(ipinfo, IPT_INV_DSTIP, ipinfo->dmsk.s_addr &&
+ 		    (ip->daddr & ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr))
+ 		return false;
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/613-netfilter_optional_tcp_window_check.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/613-netfilter_optional_tcp_window_check.patch
new file mode 100644
index 0000000..0735f8d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/613-netfilter_optional_tcp_window_check.patch
@@ -0,0 +1,73 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: netfilter: optional tcp window check
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ net/netfilter/nf_conntrack_proto_tcp.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/net/netfilter/nf_conntrack_proto_tcp.c
++++ b/net/netfilter/nf_conntrack_proto_tcp.c
+@@ -31,6 +31,9 @@
+ #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
+ #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
+ 
++/* Do not check the TCP window for incoming packets  */
++static int nf_ct_tcp_no_window_check __read_mostly = 1;
++
+ /* "Be conservative in what you do,
+     be liberal in what you accept from others."
+     If it's non-zero, we mark only out of window RST segments as INVALID. */
+@@ -476,6 +479,9 @@ static bool tcp_in_window(const struct n
+ 	s32 receiver_offset;
+ 	bool res, in_recv_win;
+ 
++	if (nf_ct_tcp_no_window_check)
++		return true;
++
+ 	/*
+ 	 * Get the required data from the packet.
+ 	 */
+@@ -1130,7 +1136,7 @@ int nf_conntrack_tcp_packet(struct nf_co
+ 		 IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED &&
+ 		 timeouts[new_state] > timeouts[TCP_CONNTRACK_UNACK])
+ 		timeout = timeouts[TCP_CONNTRACK_UNACK];
+-	else if (ct->proto.tcp.last_win == 0 &&
++	else if (!nf_ct_tcp_no_window_check && ct->proto.tcp.last_win == 0 &&
+ 		 timeouts[new_state] > timeouts[TCP_CONNTRACK_RETRANS])
+ 		timeout = timeouts[TCP_CONNTRACK_RETRANS];
+ 	else
+--- a/net/netfilter/nf_conntrack_standalone.c
++++ b/net/netfilter/nf_conntrack_standalone.c
+@@ -25,6 +25,9 @@
+ #include <net/netfilter/nf_conntrack_timestamp.h>
+ #include <linux/rculist_nulls.h>
+ 
++/* Do not check the TCP window for incoming packets  */
++static int nf_ct_tcp_no_window_check __read_mostly = 1;
++
+ static bool enable_hooks __read_mostly;
+ MODULE_PARM_DESC(enable_hooks, "Always enable conntrack hooks");
+ module_param(enable_hooks, bool, 0000);
+@@ -650,6 +653,7 @@ enum nf_ct_sysctl_index {
+ 	NF_SYSCTL_CT_PROTO_TIMEOUT_GRE_STREAM,
+ #endif
+ 
++	NF_SYSCTL_CT_PROTO_TCP_NO_WINDOW_CHECK,
+ 	__NF_SYSCTL_CT_LAST_SYSCTL,
+ };
+ 
+@@ -976,6 +980,13 @@ static struct ctl_table nf_ct_sysctl_tab
+ 		.proc_handler   = proc_dointvec_jiffies,
+ 	},
+ #endif
++	[NF_SYSCTL_CT_PROTO_TCP_NO_WINDOW_CHECK] = {
++		.procname       = "nf_conntrack_tcp_no_window_check",
++		.data           = &nf_ct_tcp_no_window_check,
++		.maxlen         = sizeof(unsigned int),
++		.mode           = 0644,
++		.proc_handler   = proc_dointvec,
++	},
+ 	{}
+ };
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/620-net_sched-codel-do-not-defer-queue-length-update.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/620-net_sched-codel-do-not-defer-queue-length-update.patch
new file mode 100644
index 0000000..ca85b8a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/620-net_sched-codel-do-not-defer-queue-length-update.patch
@@ -0,0 +1,86 @@
+From: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
+Date: Mon, 21 Aug 2017 11:14:14 +0300
+Subject: [PATCH] net_sched/codel: do not defer queue length update
+
+When codel wants to drop last packet in ->dequeue() it cannot call
+qdisc_tree_reduce_backlog() right away - it will notify parent qdisc
+about zero qlen and HTB/HFSC will deactivate class. The same class will
+be deactivated second time by caller of ->dequeue(). Currently codel and
+fq_codel defer update. This triggers warning in HFSC when it's qlen != 0
+but there is no active classes.
+
+This patch update parent queue length immediately: just temporary increase
+qlen around qdisc_tree_reduce_backlog() to prevent first class deactivation
+if we have skb to return.
+
+This might open another problem in HFSC - now operation peek could fail and
+deactivate parent class.
+
+Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=109581
+---
+
+--- a/net/sched/sch_codel.c
++++ b/net/sched/sch_codel.c
+@@ -95,11 +95,17 @@ static struct sk_buff *codel_qdisc_deque
+ 			    &q->stats, qdisc_pkt_len, codel_get_enqueue_time,
+ 			    drop_func, dequeue_func);
+ 
+-	/* We cant call qdisc_tree_reduce_backlog() if our qlen is 0,
+-	 * or HTB crashes. Defer it for next round.
++	/* If our qlen is 0 qdisc_tree_reduce_backlog() will deactivate
++	 * parent class, dequeue in parent qdisc will do the same if we
++	 * return skb. Temporary increment qlen if we have skb.
+ 	 */
+-	if (q->stats.drop_count && sch->q.qlen) {
+-		qdisc_tree_reduce_backlog(sch, q->stats.drop_count, q->stats.drop_len);
++	if (q->stats.drop_count) {
++		if (skb)
++			sch->q.qlen++;
++		qdisc_tree_reduce_backlog(sch, q->stats.drop_count,
++					  q->stats.drop_len);
++		if (skb)
++			sch->q.qlen--;
+ 		q->stats.drop_count = 0;
+ 		q->stats.drop_len = 0;
+ 	}
+--- a/net/sched/sch_fq_codel.c
++++ b/net/sched/sch_fq_codel.c
+@@ -305,6 +305,21 @@ begin:
+ 			    &flow->cvars, &q->cstats, qdisc_pkt_len,
+ 			    codel_get_enqueue_time, drop_func, dequeue_func);
+ 
++	/* If our qlen is 0 qdisc_tree_reduce_backlog() will deactivate
++	 * parent class, dequeue in parent qdisc will do the same if we
++	 * return skb. Temporary increment qlen if we have skb.
++	 */
++	if (q->cstats.drop_count) {
++		if (skb)
++			sch->q.qlen++;
++		qdisc_tree_reduce_backlog(sch, q->cstats.drop_count,
++					  q->cstats.drop_len);
++		if (skb)
++			sch->q.qlen--;
++		q->cstats.drop_count = 0;
++		q->cstats.drop_len = 0;
++	}
++
+ 	if (!skb) {
+ 		/* force a pass through old_flows to prevent starvation */
+ 		if ((head == &q->new_flows) && !list_empty(&q->old_flows))
+@@ -315,15 +330,6 @@ begin:
+ 	}
+ 	qdisc_bstats_update(sch, skb);
+ 	flow->deficit -= qdisc_pkt_len(skb);
+-	/* We cant call qdisc_tree_reduce_backlog() if our qlen is 0,
+-	 * or HTB crashes. Defer it for next round.
+-	 */
+-	if (q->cstats.drop_count && sch->q.qlen) {
+-		qdisc_tree_reduce_backlog(sch, q->cstats.drop_count,
+-					  q->cstats.drop_len);
+-		q->cstats.drop_count = 0;
+-		q->cstats.drop_len = 0;
+-	}
+ 	return skb;
+ }
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/630-packet_socket_type.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/630-packet_socket_type.patch
new file mode 100644
index 0000000..df1de5a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/630-packet_socket_type.patch
@@ -0,0 +1,138 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: net: add an optimization for dealing with raw sockets
+
+lede-commit: 4898039703d7315f0f3431c860123338ec3be0f6
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ include/uapi/linux/if_packet.h |  3 +++
+ net/packet/af_packet.c         | 34 +++++++++++++++++++++++++++-------
+ net/packet/internal.h          |  1 +
+ 3 files changed, 31 insertions(+), 7 deletions(-)
+
+--- a/include/uapi/linux/if_packet.h
++++ b/include/uapi/linux/if_packet.h
+@@ -32,6 +32,8 @@ struct sockaddr_ll {
+ #define PACKET_KERNEL		7		/* To kernel space	*/
+ /* Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space */
+ #define PACKET_FASTROUTE	6		/* Fastrouted frame	*/
++#define PACKET_MASK_ANY		0xffffffff	/* mask for packet type bits */
++
+ 
+ /* Packet socket options */
+ 
+@@ -58,6 +60,7 @@ struct sockaddr_ll {
+ #define PACKET_ROLLOVER_STATS		21
+ #define PACKET_FANOUT_DATA		22
+ #define PACKET_IGNORE_OUTGOING		23
++#define PACKET_RECV_TYPE		24
+ 
+ #define PACKET_FANOUT_HASH		0
+ #define PACKET_FANOUT_LB		1
+--- a/net/packet/af_packet.c
++++ b/net/packet/af_packet.c
+@@ -1801,6 +1801,7 @@ static int packet_rcv_spkt(struct sk_buf
+ {
+ 	struct sock *sk;
+ 	struct sockaddr_pkt *spkt;
++	struct packet_sock *po;
+ 
+ 	/*
+ 	 *	When we registered the protocol we saved the socket in the data
+@@ -1808,6 +1809,7 @@ static int packet_rcv_spkt(struct sk_buf
+ 	 */
+ 
+ 	sk = pt->af_packet_priv;
++	po = pkt_sk(sk);
+ 
+ 	/*
+ 	 *	Yank back the headers [hope the device set this
+@@ -1820,7 +1822,7 @@ static int packet_rcv_spkt(struct sk_buf
+ 	 *	so that this procedure is noop.
+ 	 */
+ 
+-	if (skb->pkt_type == PACKET_LOOPBACK)
++	if (!(po->pkt_type & (1 << skb->pkt_type)))
+ 		goto out;
+ 
+ 	if (!net_eq(dev_net(dev), sock_net(sk)))
+@@ -2058,12 +2060,12 @@ static int packet_rcv(struct sk_buff *sk
+ 	unsigned int snaplen, res;
+ 	bool is_drop_n_account = false;
+ 
+-	if (skb->pkt_type == PACKET_LOOPBACK)
+-		goto drop;
+-
+ 	sk = pt->af_packet_priv;
+ 	po = pkt_sk(sk);
+ 
++	if (!(po->pkt_type & (1 << skb->pkt_type)))
++		goto drop;
++
+ 	if (!net_eq(dev_net(dev), sock_net(sk)))
+ 		goto drop;
+ 
+@@ -2189,12 +2191,12 @@ static int tpacket_rcv(struct sk_buff *s
+ 	BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32);
+ 	BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48);
+ 
+-	if (skb->pkt_type == PACKET_LOOPBACK)
+-		goto drop;
+-
+ 	sk = pt->af_packet_priv;
+ 	po = pkt_sk(sk);
+ 
++	if (!(po->pkt_type & (1 << skb->pkt_type)))
++		goto drop;
++
+ 	if (!net_eq(dev_net(dev), sock_net(sk)))
+ 		goto drop;
+ 
+@@ -3293,6 +3295,7 @@ static int packet_create(struct net *net
+ 	mutex_init(&po->pg_vec_lock);
+ 	po->rollover = NULL;
+ 	po->prot_hook.func = packet_rcv;
++	po->pkt_type = PACKET_MASK_ANY & ~(1 << PACKET_LOOPBACK);
+ 
+ 	if (sock->type == SOCK_PACKET)
+ 		po->prot_hook.func = packet_rcv_spkt;
+@@ -3930,6 +3933,16 @@ packet_setsockopt(struct socket *sock, i
+ 		po->xmit = val ? packet_direct_xmit : dev_queue_xmit;
+ 		return 0;
+ 	}
++        case PACKET_RECV_TYPE:
++        {
++                unsigned int val;
++                if (optlen != sizeof(val))
++                        return -EINVAL;
++                if (copy_from_user(&val, optval, sizeof(val)))
++                        return -EFAULT;
++                po->pkt_type = val & ~BIT(PACKET_LOOPBACK);
++                return 0;
++        }
+ 	default:
+ 		return -ENOPROTOOPT;
+ 	}
+@@ -3986,6 +3999,13 @@ static int packet_getsockopt(struct sock
+ 	case PACKET_VNET_HDR:
+ 		val = po->has_vnet_hdr;
+ 		break;
++	case PACKET_RECV_TYPE:
++		if (len > sizeof(unsigned int))
++			len = sizeof(unsigned int);
++		val = po->pkt_type;
++
++		data = &val;
++		break;
+ 	case PACKET_VERSION:
+ 		val = po->tp_version;
+ 		break;
+--- a/net/packet/internal.h
++++ b/net/packet/internal.h
+@@ -136,6 +136,7 @@ struct packet_sock {
+ 	int			(*xmit)(struct sk_buff *skb);
+ 	struct packet_type	prot_hook ____cacheline_aligned_in_smp;
+ 	atomic_t		tp_drops ____cacheline_aligned_in_smp;
++	unsigned int		pkt_type;
+ };
+ 
+ static struct packet_sock *pkt_sk(struct sock *sk)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/640-netfilter-nf_flow_table-add-hardware-offload-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/640-netfilter-nf_flow_table-add-hardware-offload-support.patch
new file mode 100644
index 0000000..bd4808c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/640-netfilter-nf_flow_table-add-hardware-offload-support.patch
@@ -0,0 +1,564 @@
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Thu, 11 Jan 2018 16:32:00 +0100
+Subject: [PATCH] netfilter: nf_flow_table: add hardware offload support
+
+This patch adds the infrastructure to offload flows to hardware, in case
+the nic/switch comes with built-in flow tables capabilities.
+
+If the hardware comes with no hardware flow tables or they have
+limitations in terms of features, the existing infrastructure falls back
+to the software flow table implementation.
+
+The software flow table garbage collector skips entries that resides in
+the hardware, so the hardware will be responsible for releasing this
+flow table entry too via flow_offload_dead().
+
+Hardware configuration, either to add or to delete entries, is done from
+the hardware offload workqueue, to ensure this is done from user context
+given that we may sleep when grabbing the mdio mutex.
+
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+---
+ create mode 100644 net/netfilter/nf_flow_table_hw.c
+
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -922,6 +922,13 @@ struct devlink;
+ struct tlsdev_ops;
+ 
+ 
++struct flow_offload;
++
++enum flow_offload_type {
++	FLOW_OFFLOAD_ADD	= 0,
++	FLOW_OFFLOAD_DEL,
++};
++
+ /*
+  * This structure defines the management hooks for network devices.
+  * The following hooks can be defined; unless noted otherwise, they are
+@@ -1154,6 +1161,10 @@ struct tlsdev_ops;
+  * int (*ndo_bridge_dellink)(struct net_device *dev, struct nlmsghdr *nlh,
+  *			     u16 flags);
+  *
++ * int (*ndo_flow_offload)(enum flow_offload_type type,
++ *			   struct flow_offload *flow);
++ *	Adds/deletes flow entry to/from net device flowtable.
++ *
+  * int (*ndo_change_carrier)(struct net_device *dev, bool new_carrier);
+  *	Called to change device carrier. Soft-devices (like dummy, team, etc)
+  *	which do not represent real hardware may define this to allow their
+@@ -1401,6 +1412,8 @@ struct net_device_ops {
+ 	int			(*ndo_bridge_dellink)(struct net_device *dev,
+ 						      struct nlmsghdr *nlh,
+ 						      u16 flags);
++	int			(*ndo_flow_offload)(enum flow_offload_type type,
++						    struct flow_offload *flow);
+ 	int			(*ndo_change_carrier)(struct net_device *dev,
+ 						      bool new_carrier);
+ 	int			(*ndo_get_phys_port_id)(struct net_device *dev,
+--- a/include/net/netfilter/nf_flow_table.h
++++ b/include/net/netfilter/nf_flow_table.h
+@@ -21,11 +21,17 @@ struct nf_flowtable_type {
+ 	struct module			*owner;
+ };
+ 
++enum nf_flowtable_flags {
++	NF_FLOWTABLE_F_HW		= 0x1,
++};
++
+ struct nf_flowtable {
+ 	struct list_head		list;
+ 	struct rhashtable		rhashtable;
+ 	const struct nf_flowtable_type	*type;
++	u32				flags;
+ 	struct delayed_work		gc_work;
++	possible_net_t			ft_net;
+ };
+ 
+ enum flow_offload_tuple_dir {
+@@ -68,6 +74,7 @@ struct flow_offload_tuple_rhash {
+ #define FLOW_OFFLOAD_DNAT	0x2
+ #define FLOW_OFFLOAD_DYING	0x4
+ #define FLOW_OFFLOAD_TEARDOWN	0x8
++#define FLOW_OFFLOAD_HW		0x10
+ 
+ struct flow_offload {
+ 	struct flow_offload_tuple_rhash		tuplehash[FLOW_OFFLOAD_DIR_MAX];
+@@ -120,6 +127,22 @@ unsigned int nf_flow_offload_ip_hook(voi
+ unsigned int nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
+ 				       const struct nf_hook_state *state);
+ 
++void nf_flow_offload_hw_add(struct net *net, struct flow_offload *flow,
++			    struct nf_conn *ct);
++void nf_flow_offload_hw_del(struct net *net, struct flow_offload *flow);
++
++struct nf_flow_table_hw {
++	struct module	*owner;
++	void		(*add)(struct net *net, struct flow_offload *flow,
++			       struct nf_conn *ct);
++	void		(*del)(struct net *net, struct flow_offload *flow);
++};
++
++int nf_flow_table_hw_register(const struct nf_flow_table_hw *offload);
++void nf_flow_table_hw_unregister(const struct nf_flow_table_hw *offload);
++
++extern struct work_struct nf_flow_offload_hw_work;
++
+ #define MODULE_ALIAS_NF_FLOWTABLE(family)	\
+ 	MODULE_ALIAS("nf-flowtable-" __stringify(family))
+ 
+--- a/include/uapi/linux/netfilter/nf_tables.h
++++ b/include/uapi/linux/netfilter/nf_tables.h
+@@ -1516,6 +1516,7 @@ enum nft_object_attributes {
+  * @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32)
+  * @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32)
+  * @NFTA_FLOWTABLE_HANDLE: object handle (NLA_U64)
++ * @NFTA_FLOWTABLE_FLAGS: flags (NLA_U32)
+  */
+ enum nft_flowtable_attributes {
+ 	NFTA_FLOWTABLE_UNSPEC,
+@@ -1525,6 +1526,7 @@ enum nft_flowtable_attributes {
+ 	NFTA_FLOWTABLE_USE,
+ 	NFTA_FLOWTABLE_HANDLE,
+ 	NFTA_FLOWTABLE_PAD,
++	NFTA_FLOWTABLE_FLAGS,
+ 	__NFTA_FLOWTABLE_MAX
+ };
+ #define NFTA_FLOWTABLE_MAX	(__NFTA_FLOWTABLE_MAX - 1)
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -711,6 +711,15 @@ config NF_FLOW_TABLE
+ 
+ 	  To compile it as a module, choose M here.
+ 
++config NF_FLOW_TABLE_HW
++	tristate "Netfilter flow table hardware offload module"
++	depends on NF_FLOW_TABLE
++	help
++	  This option adds hardware offload support for the flow table core
++	  infrastructure.
++
++	  To compile it as a module, choose M here.
++
+ config NETFILTER_XTABLES
+ 	tristate "Netfilter Xtables support (required for ip_tables)"
+ 	default m if NETFILTER_ADVANCED=n
+--- a/net/netfilter/Makefile
++++ b/net/netfilter/Makefile
+@@ -123,6 +123,7 @@ obj-$(CONFIG_NF_FLOW_TABLE)	+= nf_flow_t
+ nf_flow_table-objs := nf_flow_table_core.o nf_flow_table_ip.o
+ 
+ obj-$(CONFIG_NF_FLOW_TABLE_INET) += nf_flow_table_inet.o
++obj-$(CONFIG_NF_FLOW_TABLE_HW)	+= nf_flow_table_hw.o
+ 
+ # generic X tables
+ obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
+--- a/net/netfilter/nf_flow_table_core.c
++++ b/net/netfilter/nf_flow_table_core.c
+@@ -248,10 +248,16 @@ static inline bool nf_flow_has_expired(c
+ 	return nf_flow_timeout_delta(flow->timeout) <= 0;
+ }
+ 
++static inline bool nf_flow_in_hw(const struct flow_offload *flow)
++{
++	return flow->flags & FLOW_OFFLOAD_HW;
++}
++
+ static void flow_offload_del(struct nf_flowtable *flow_table,
+ 			     struct flow_offload *flow)
+ {
+ 	struct flow_offload_entry *e;
++	struct net *net = read_pnet(&flow_table->ft_net);
+ 
+ 	rhashtable_remove_fast(&flow_table->rhashtable,
+ 			       &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].node,
+@@ -271,6 +277,9 @@ static void flow_offload_del(struct nf_f
+ 	if (!(flow->flags & FLOW_OFFLOAD_TEARDOWN))
+ 		flow_offload_fixup_ct_state(e->ct);
+ 
++	if (nf_flow_in_hw(flow))
++		nf_flow_offload_hw_del(net, flow);
++
+ 	flow_offload_free(flow);
+ }
+ 
+@@ -361,6 +370,9 @@ static void nf_flow_offload_gc_step(stru
+ 	if (!teardown)
+ 		nf_ct_offload_timeout(flow);
+ 
++	if (nf_flow_in_hw(flow) && !teardown)
++		return;
++
+ 	if (nf_flow_has_expired(flow) || teardown)
+ 		flow_offload_del(flow_table, flow);
+ }
+@@ -490,10 +502,43 @@ int nf_flow_dnat_port(const struct flow_
+ }
+ EXPORT_SYMBOL_GPL(nf_flow_dnat_port);
+ 
++static const struct nf_flow_table_hw __rcu *nf_flow_table_hw_hook __read_mostly;
++
++static int nf_flow_offload_hw_init(struct nf_flowtable *flow_table)
++{
++	const struct nf_flow_table_hw *offload;
++
++	if (!rcu_access_pointer(nf_flow_table_hw_hook))
++		request_module("nf-flow-table-hw");
++
++	rcu_read_lock();
++	offload = rcu_dereference(nf_flow_table_hw_hook);
++	if (!offload)
++		goto err_no_hw_offload;
++
++	if (!try_module_get(offload->owner))
++		goto err_no_hw_offload;
++
++	rcu_read_unlock();
++
++	return 0;
++
++err_no_hw_offload:
++	rcu_read_unlock();
++
++	return -EOPNOTSUPP;
++}
++
+ int nf_flow_table_init(struct nf_flowtable *flowtable)
+ {
+ 	int err;
+ 
++	if (flowtable->flags & NF_FLOWTABLE_F_HW) {
++		err = nf_flow_offload_hw_init(flowtable);
++		if (err)
++			return err;
++	}
++
+ 	INIT_DEFERRABLE_WORK(&flowtable->gc_work, nf_flow_offload_work_gc);
+ 
+ 	err = rhashtable_init(&flowtable->rhashtable,
+@@ -534,6 +579,8 @@ static void nf_flow_table_iterate_cleanu
+ {
+ 	nf_flow_table_iterate(flowtable, nf_flow_table_do_cleanup, dev);
+ 	flush_delayed_work(&flowtable->gc_work);
++	if (flowtable->flags & NF_FLOWTABLE_F_HW)
++		flush_work(&nf_flow_offload_hw_work);
+ }
+ 
+ void nf_flow_table_cleanup(struct net_device *dev)
+@@ -547,6 +594,26 @@ void nf_flow_table_cleanup(struct net_de
+ }
+ EXPORT_SYMBOL_GPL(nf_flow_table_cleanup);
+ 
++struct work_struct nf_flow_offload_hw_work;
++EXPORT_SYMBOL_GPL(nf_flow_offload_hw_work);
++
++/* Give the hardware workqueue the chance to remove entries from hardware.*/
++static void nf_flow_offload_hw_free(struct nf_flowtable *flowtable)
++{
++	const struct nf_flow_table_hw *offload;
++
++	flush_work(&nf_flow_offload_hw_work);
++
++	rcu_read_lock();
++	offload = rcu_dereference(nf_flow_table_hw_hook);
++	if (!offload) {
++		rcu_read_unlock();
++		return;
++	}
++	module_put(offload->owner);
++	rcu_read_unlock();
++}
++
+ void nf_flow_table_free(struct nf_flowtable *flow_table)
+ {
+ 	mutex_lock(&flowtable_lock);
+@@ -556,9 +623,58 @@ void nf_flow_table_free(struct nf_flowta
+ 	nf_flow_table_iterate(flow_table, nf_flow_table_do_cleanup, NULL);
+ 	nf_flow_table_iterate(flow_table, nf_flow_offload_gc_step, flow_table);
+ 	rhashtable_destroy(&flow_table->rhashtable);
++	if (flow_table->flags & NF_FLOWTABLE_F_HW)
++		nf_flow_offload_hw_free(flow_table);
+ }
+ EXPORT_SYMBOL_GPL(nf_flow_table_free);
+ 
++/* Must be called from user context. */
++void nf_flow_offload_hw_add(struct net *net, struct flow_offload *flow,
++			    struct nf_conn *ct)
++{
++	const struct nf_flow_table_hw *offload;
++
++	rcu_read_lock();
++	offload = rcu_dereference(nf_flow_table_hw_hook);
++	if (offload)
++		offload->add(net, flow, ct);
++	rcu_read_unlock();
++}
++EXPORT_SYMBOL_GPL(nf_flow_offload_hw_add);
++
++/* Must be called from user context. */
++void nf_flow_offload_hw_del(struct net *net, struct flow_offload *flow)
++{
++	const struct nf_flow_table_hw *offload;
++
++	rcu_read_lock();
++	offload = rcu_dereference(nf_flow_table_hw_hook);
++	if (offload)
++		offload->del(net, flow);
++	rcu_read_unlock();
++}
++EXPORT_SYMBOL_GPL(nf_flow_offload_hw_del);
++
++int nf_flow_table_hw_register(const struct nf_flow_table_hw *offload)
++{
++	if (rcu_access_pointer(nf_flow_table_hw_hook))
++		return -EBUSY;
++
++	rcu_assign_pointer(nf_flow_table_hw_hook, offload);
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(nf_flow_table_hw_register);
++
++void nf_flow_table_hw_unregister(const struct nf_flow_table_hw *offload)
++{
++	WARN_ON(rcu_access_pointer(nf_flow_table_hw_hook) != offload);
++	rcu_assign_pointer(nf_flow_table_hw_hook, NULL);
++
++	synchronize_rcu();
++}
++EXPORT_SYMBOL_GPL(nf_flow_table_hw_unregister);
++
+ static int nf_flow_table_netdev_event(struct notifier_block *this,
+ 				      unsigned long event, void *ptr)
+ {
+--- /dev/null
++++ b/net/netfilter/nf_flow_table_hw.c
+@@ -0,0 +1,169 @@
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/rhashtable.h>
++#include <linux/netdevice.h>
++#include <net/netfilter/nf_flow_table.h>
++#include <net/netfilter/nf_conntrack.h>
++#include <net/netfilter/nf_conntrack_core.h>
++#include <net/netfilter/nf_conntrack_tuple.h>
++
++static DEFINE_SPINLOCK(flow_offload_hw_pending_list_lock);
++static LIST_HEAD(flow_offload_hw_pending_list);
++
++static DEFINE_MUTEX(nf_flow_offload_hw_mutex);
++
++struct flow_offload_hw {
++	struct list_head	list;
++	enum flow_offload_type	type;
++	struct flow_offload	*flow;
++	struct nf_conn		*ct;
++	possible_net_t		flow_hw_net;
++};
++
++static int do_flow_offload_hw(struct net *net, struct flow_offload *flow,
++			      int type)
++{
++	struct net_device *indev;
++	int ret, ifindex;
++
++	ifindex = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.iifidx;
++	indev = dev_get_by_index(net, ifindex);
++	if (WARN_ON(!indev))
++		return 0;
++
++	mutex_lock(&nf_flow_offload_hw_mutex);
++	ret = indev->netdev_ops->ndo_flow_offload(type, flow);
++	mutex_unlock(&nf_flow_offload_hw_mutex);
++
++	dev_put(indev);
++
++	return ret;
++}
++
++static void flow_offload_hw_work_add(struct flow_offload_hw *offload)
++{
++	struct net *net;
++	int ret;
++
++	if (nf_ct_is_dying(offload->ct))
++		return;
++
++	net = read_pnet(&offload->flow_hw_net);
++	ret = do_flow_offload_hw(net, offload->flow, FLOW_OFFLOAD_ADD);
++	if (ret >= 0)
++		offload->flow->flags |= FLOW_OFFLOAD_HW;
++}
++
++static void flow_offload_hw_work_del(struct flow_offload_hw *offload)
++{
++	struct net *net = read_pnet(&offload->flow_hw_net);
++
++	do_flow_offload_hw(net, offload->flow, FLOW_OFFLOAD_DEL);
++}
++
++static void flow_offload_hw_work(struct work_struct *work)
++{
++	struct flow_offload_hw *offload, *next;
++	LIST_HEAD(hw_offload_pending);
++
++	spin_lock_bh(&flow_offload_hw_pending_list_lock);
++	list_replace_init(&flow_offload_hw_pending_list, &hw_offload_pending);
++	spin_unlock_bh(&flow_offload_hw_pending_list_lock);
++
++	list_for_each_entry_safe(offload, next, &hw_offload_pending, list) {
++		switch (offload->type) {
++		case FLOW_OFFLOAD_ADD:
++			flow_offload_hw_work_add(offload);
++			break;
++		case FLOW_OFFLOAD_DEL:
++			flow_offload_hw_work_del(offload);
++			break;
++		}
++		if (offload->ct)
++			nf_conntrack_put(&offload->ct->ct_general);
++		list_del(&offload->list);
++		kfree(offload);
++	}
++}
++
++static void flow_offload_queue_work(struct flow_offload_hw *offload)
++{
++	spin_lock_bh(&flow_offload_hw_pending_list_lock);
++	list_add_tail(&offload->list, &flow_offload_hw_pending_list);
++	spin_unlock_bh(&flow_offload_hw_pending_list_lock);
++
++	schedule_work(&nf_flow_offload_hw_work);
++}
++
++static void flow_offload_hw_add(struct net *net, struct flow_offload *flow,
++				struct nf_conn *ct)
++{
++	struct flow_offload_hw *offload;
++
++	offload = kmalloc(sizeof(struct flow_offload_hw), GFP_ATOMIC);
++	if (!offload)
++		return;
++
++	nf_conntrack_get(&ct->ct_general);
++	offload->type = FLOW_OFFLOAD_ADD;
++	offload->ct = ct;
++	offload->flow = flow;
++	write_pnet(&offload->flow_hw_net, net);
++
++	flow_offload_queue_work(offload);
++}
++
++static void flow_offload_hw_del(struct net *net, struct flow_offload *flow)
++{
++	struct flow_offload_hw *offload;
++
++	offload = kmalloc(sizeof(struct flow_offload_hw), GFP_ATOMIC);
++	if (!offload)
++		return;
++
++	offload->type = FLOW_OFFLOAD_DEL;
++	offload->ct = NULL;
++	offload->flow = flow;
++	write_pnet(&offload->flow_hw_net, net);
++
++	flow_offload_queue_work(offload);
++}
++
++static const struct nf_flow_table_hw flow_offload_hw = {
++	.add	= flow_offload_hw_add,
++	.del	= flow_offload_hw_del,
++	.owner	= THIS_MODULE,
++};
++
++static int __init nf_flow_table_hw_module_init(void)
++{
++	INIT_WORK(&nf_flow_offload_hw_work, flow_offload_hw_work);
++	nf_flow_table_hw_register(&flow_offload_hw);
++
++	return 0;
++}
++
++static void __exit nf_flow_table_hw_module_exit(void)
++{
++	struct flow_offload_hw *offload, *next;
++	LIST_HEAD(hw_offload_pending);
++
++	nf_flow_table_hw_unregister(&flow_offload_hw);
++	cancel_work_sync(&nf_flow_offload_hw_work);
++
++	list_for_each_entry_safe(offload, next, &hw_offload_pending, list) {
++		if (offload->ct)
++			nf_conntrack_put(&offload->ct->ct_general);
++		list_del(&offload->list);
++		kfree(offload);
++	}
++}
++
++module_init(nf_flow_table_hw_module_init);
++module_exit(nf_flow_table_hw_module_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
++MODULE_ALIAS("nf-flow-table-hw");
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -5748,6 +5748,13 @@ static int nf_tables_flowtable_parse_hoo
+ 	if (err < 0)
+ 		return err;
+ 
++	for (i = 0; i < n; i++) {
++		if (flowtable->data.flags & NF_FLOWTABLE_F_HW &&
++		    !dev_array[i]->netdev_ops->ndo_flow_offload) {
++			return -EOPNOTSUPP;
++		}
++	}
++
+ 	ops = kcalloc(n, sizeof(struct nf_hook_ops), GFP_KERNEL);
+ 	if (!ops)
+ 		return -ENOMEM;
+@@ -5878,10 +5885,19 @@ static int nf_tables_newflowtable(struct
+ 	}
+ 
+ 	flowtable->data.type = type;
++	write_pnet(&flowtable->data.ft_net, net);
++
+ 	err = type->init(&flowtable->data);
+ 	if (err < 0)
+ 		goto err3;
+ 
++	if (nla[NFTA_FLOWTABLE_FLAGS]) {
++		flowtable->data.flags =
++			ntohl(nla_get_be32(nla[NFTA_FLOWTABLE_FLAGS]));
++		if (flowtable->data.flags & ~NF_FLOWTABLE_F_HW)
++			goto err4;
++	}
++
+ 	err = nf_tables_flowtable_parse_hook(&ctx, nla[NFTA_FLOWTABLE_HOOK],
+ 					     flowtable);
+ 	if (err < 0)
+@@ -6007,7 +6023,8 @@ static int nf_tables_fill_flowtable_info
+ 	    nla_put_string(skb, NFTA_FLOWTABLE_NAME, flowtable->name) ||
+ 	    nla_put_be32(skb, NFTA_FLOWTABLE_USE, htonl(flowtable->use)) ||
+ 	    nla_put_be64(skb, NFTA_FLOWTABLE_HANDLE, cpu_to_be64(flowtable->handle),
+-			 NFTA_FLOWTABLE_PAD))
++			 NFTA_FLOWTABLE_PAD) ||
++	    nla_put_be32(skb, NFTA_FLOWTABLE_FLAGS, htonl(flowtable->data.flags)))
+ 		goto nla_put_failure;
+ 
+ 	nest = nla_nest_start_noflag(skb, NFTA_FLOWTABLE_HOOK);
+--- a/net/netfilter/nft_flow_offload.c
++++ b/net/netfilter/nft_flow_offload.c
+@@ -128,6 +128,9 @@ static void nft_flow_offload_eval(const
+ 	if (ret < 0)
+ 		goto err_flow_add;
+ 
++	if (flowtable->flags & NF_FLOWTABLE_F_HW)
++		nf_flow_offload_hw_add(nft_net(pkt), flow, ct);
++
+ 	dst_release(route.tuple[!dir].dst);
+ 	return;
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/641-netfilter-nf_flow_table-support-hw-offload-through-v.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/641-netfilter-nf_flow_table-support-hw-offload-through-v.patch
new file mode 100644
index 0000000..b808c02
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/641-netfilter-nf_flow_table-support-hw-offload-through-v.patch
@@ -0,0 +1,306 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 15 Mar 2018 20:46:31 +0100
+Subject: [PATCH] netfilter: nf_flow_table: support hw offload through
+ virtual interfaces
+
+There are hardware offload devices that support offloading VLANs and
+PPPoE devices. Additionally, it is useful to be able to offload packets
+routed through bridge interfaces as well.
+Add support for finding the path to the offload device through these
+virtual interfaces, while collecting useful parameters for the offload
+device, like VLAN ID/protocol, PPPoE session and Ethernet MAC address.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -923,6 +923,7 @@ struct tlsdev_ops;
+ 
+ 
+ struct flow_offload;
++struct flow_offload_hw_path;
+ 
+ enum flow_offload_type {
+ 	FLOW_OFFLOAD_ADD	= 0,
+@@ -1161,8 +1162,15 @@ enum flow_offload_type {
+  * int (*ndo_bridge_dellink)(struct net_device *dev, struct nlmsghdr *nlh,
+  *			     u16 flags);
+  *
++ * int (*ndo_flow_offload_check)(struct flow_offload_hw_path *path);
++ *	For virtual devices like bridges, vlan, and pppoe, fill in the
++ *	underlying network device that can be used for offloading connections.
++ *	Return an error if offloading is not supported.
++ *
+  * int (*ndo_flow_offload)(enum flow_offload_type type,
+- *			   struct flow_offload *flow);
++ *			   struct flow_offload *flow,
++ *			   struct flow_offload_hw_path *src,
++ *			   struct flow_offload_hw_path *dest);
+  *	Adds/deletes flow entry to/from net device flowtable.
+  *
+  * int (*ndo_change_carrier)(struct net_device *dev, bool new_carrier);
+@@ -1412,8 +1420,11 @@ struct net_device_ops {
+ 	int			(*ndo_bridge_dellink)(struct net_device *dev,
+ 						      struct nlmsghdr *nlh,
+ 						      u16 flags);
++	int			(*ndo_flow_offload_check)(struct flow_offload_hw_path *path);
+ 	int			(*ndo_flow_offload)(enum flow_offload_type type,
+-						    struct flow_offload *flow);
++						    struct flow_offload *flow,
++						    struct flow_offload_hw_path *src,
++						    struct flow_offload_hw_path *dest);
+ 	int			(*ndo_change_carrier)(struct net_device *dev,
+ 						      bool new_carrier);
+ 	int			(*ndo_get_phys_port_id)(struct net_device *dev,
+--- a/include/net/netfilter/nf_flow_table.h
++++ b/include/net/netfilter/nf_flow_table.h
+@@ -85,6 +85,21 @@ struct flow_offload {
+ 	};
+ };
+ 
++#define FLOW_OFFLOAD_PATH_ETHERNET	BIT(0)
++#define FLOW_OFFLOAD_PATH_VLAN		BIT(1)
++#define FLOW_OFFLOAD_PATH_PPPOE		BIT(2)
++
++struct flow_offload_hw_path {
++	struct net_device *dev;
++	u32 flags;
++
++	u8 eth_src[ETH_ALEN];
++	u8 eth_dest[ETH_ALEN];
++	u16 vlan_proto;
++	u16 vlan_id;
++	u16 pppoe_sid;
++};
++
+ #define NF_FLOW_TIMEOUT (30 * HZ)
+ 
+ struct nf_flow_route {
+--- a/net/netfilter/nf_flow_table_hw.c
++++ b/net/netfilter/nf_flow_table_hw.c
+@@ -19,48 +19,77 @@ struct flow_offload_hw {
+ 	enum flow_offload_type	type;
+ 	struct flow_offload	*flow;
+ 	struct nf_conn		*ct;
+-	possible_net_t		flow_hw_net;
++
++	struct flow_offload_hw_path src;
++	struct flow_offload_hw_path dest;
+ };
+ 
+-static int do_flow_offload_hw(struct net *net, struct flow_offload *flow,
+-			      int type)
++static void flow_offload_check_ethernet(struct flow_offload_tuple *tuple,
++					struct dst_entry *dst,
++					struct flow_offload_hw_path *path)
+ {
+-	struct net_device *indev;
+-	int ret, ifindex;
++	struct net_device *dev = path->dev;
++	struct neighbour *n;
+ 
+-	ifindex = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.iifidx;
+-	indev = dev_get_by_index(net, ifindex);
+-	if (WARN_ON(!indev))
+-		return 0;
+-
+-	mutex_lock(&nf_flow_offload_hw_mutex);
+-	ret = indev->netdev_ops->ndo_flow_offload(type, flow);
+-	mutex_unlock(&nf_flow_offload_hw_mutex);
++	if (dev->type != ARPHRD_ETHER)
++		return;
+ 
+-	dev_put(indev);
++	memcpy(path->eth_src, path->dev->dev_addr, ETH_ALEN);
++	n = dst_neigh_lookup(dst, &tuple->src_v4);
++	if (!n)
++		return;
+ 
+-	return ret;
++	memcpy(path->eth_dest, n->ha, ETH_ALEN);
++	path->flags |= FLOW_OFFLOAD_PATH_ETHERNET;
++	neigh_release(n);
+ }
+ 
+-static void flow_offload_hw_work_add(struct flow_offload_hw *offload)
++static int flow_offload_check_path(struct net *net,
++				   struct flow_offload_tuple *tuple,
++				   struct dst_entry *dst,
++				   struct flow_offload_hw_path *path)
+ {
+-	struct net *net;
+-	int ret;
++	struct net_device *dev;
+ 
+-	if (nf_ct_is_dying(offload->ct))
+-		return;
++	dev = dev_get_by_index_rcu(net, tuple->iifidx);
++	if (!dev)
++		return -ENOENT;
++
++	path->dev = dev;
++	flow_offload_check_ethernet(tuple, dst, path);
+ 
+-	net = read_pnet(&offload->flow_hw_net);
+-	ret = do_flow_offload_hw(net, offload->flow, FLOW_OFFLOAD_ADD);
+-	if (ret >= 0)
+-		offload->flow->flags |= FLOW_OFFLOAD_HW;
++	if (dev->netdev_ops->ndo_flow_offload_check)
++		return dev->netdev_ops->ndo_flow_offload_check(path);
++
++	return 0;
+ }
+ 
+-static void flow_offload_hw_work_del(struct flow_offload_hw *offload)
++static int do_flow_offload_hw(struct flow_offload_hw *offload)
+ {
+-	struct net *net = read_pnet(&offload->flow_hw_net);
++	struct net_device *src_dev = offload->src.dev;
++	struct net_device *dest_dev = offload->dest.dev;
++	int ret;
++
++	ret = src_dev->netdev_ops->ndo_flow_offload(offload->type,
++						    offload->flow,
++						    &offload->src,
++						    &offload->dest);
++
++	/* restore devices in case the driver mangled them */
++	offload->src.dev = src_dev;
++	offload->dest.dev = dest_dev;
+ 
+-	do_flow_offload_hw(net, offload->flow, FLOW_OFFLOAD_DEL);
++	return ret;
++}
++
++static void flow_offload_hw_free(struct flow_offload_hw *offload)
++{
++	dev_put(offload->src.dev);
++	dev_put(offload->dest.dev);
++	if (offload->ct)
++		nf_conntrack_put(&offload->ct->ct_general);
++	list_del(&offload->list);
++	kfree(offload);
+ }
+ 
+ static void flow_offload_hw_work(struct work_struct *work)
+@@ -73,18 +102,22 @@ static void flow_offload_hw_work(struct
+ 	spin_unlock_bh(&flow_offload_hw_pending_list_lock);
+ 
+ 	list_for_each_entry_safe(offload, next, &hw_offload_pending, list) {
++		mutex_lock(&nf_flow_offload_hw_mutex);
+ 		switch (offload->type) {
+ 		case FLOW_OFFLOAD_ADD:
+-			flow_offload_hw_work_add(offload);
++			if (nf_ct_is_dying(offload->ct))
++				break;
++
++			if (do_flow_offload_hw(offload) >= 0)
++				offload->flow->flags |= FLOW_OFFLOAD_HW;
+ 			break;
+ 		case FLOW_OFFLOAD_DEL:
+-			flow_offload_hw_work_del(offload);
++			do_flow_offload_hw(offload);
+ 			break;
+ 		}
+-		if (offload->ct)
+-			nf_conntrack_put(&offload->ct->ct_general);
+-		list_del(&offload->list);
+-		kfree(offload);
++		mutex_unlock(&nf_flow_offload_hw_mutex);
++
++		flow_offload_hw_free(offload);
+ 	}
+ }
+ 
+@@ -97,20 +130,56 @@ static void flow_offload_queue_work(stru
+ 	schedule_work(&nf_flow_offload_hw_work);
+ }
+ 
++static struct flow_offload_hw *
++flow_offload_hw_prepare(struct net *net, struct flow_offload *flow)
++{
++	struct flow_offload_hw_path src = {};
++	struct flow_offload_hw_path dest = {};
++	struct flow_offload_tuple *tuple_s, *tuple_d;
++	struct flow_offload_hw *offload = NULL;
++
++	rcu_read_lock_bh();
++
++	tuple_s = &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple;
++	tuple_d = &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple;
++
++	if (flow_offload_check_path(net, tuple_s, tuple_d->dst_cache, &src))
++		goto out;
++
++	if (flow_offload_check_path(net, tuple_d, tuple_s->dst_cache, &dest))
++		goto out;
++
++	if (!src.dev->netdev_ops->ndo_flow_offload)
++		goto out;
++
++	offload = kzalloc(sizeof(struct flow_offload_hw), GFP_ATOMIC);
++	if (!offload)
++		goto out;
++
++	dev_hold(src.dev);
++	dev_hold(dest.dev);
++	offload->src = src;
++	offload->dest = dest;
++	offload->flow = flow;
++
++out:
++	rcu_read_unlock_bh();
++
++	return offload;
++}
++
+ static void flow_offload_hw_add(struct net *net, struct flow_offload *flow,
+ 				struct nf_conn *ct)
+ {
+ 	struct flow_offload_hw *offload;
+ 
+-	offload = kmalloc(sizeof(struct flow_offload_hw), GFP_ATOMIC);
++	offload = flow_offload_hw_prepare(net, flow);
+ 	if (!offload)
+ 		return;
+ 
+ 	nf_conntrack_get(&ct->ct_general);
+ 	offload->type = FLOW_OFFLOAD_ADD;
+ 	offload->ct = ct;
+-	offload->flow = flow;
+-	write_pnet(&offload->flow_hw_net, net);
+ 
+ 	flow_offload_queue_work(offload);
+ }
+@@ -119,14 +188,11 @@ static void flow_offload_hw_del(struct n
+ {
+ 	struct flow_offload_hw *offload;
+ 
+-	offload = kmalloc(sizeof(struct flow_offload_hw), GFP_ATOMIC);
++	offload = flow_offload_hw_prepare(net, flow);
+ 	if (!offload)
+ 		return;
+ 
+ 	offload->type = FLOW_OFFLOAD_DEL;
+-	offload->ct = NULL;
+-	offload->flow = flow;
+-	write_pnet(&offload->flow_hw_net, net);
+ 
+ 	flow_offload_queue_work(offload);
+ }
+@@ -153,12 +219,8 @@ static void __exit nf_flow_table_hw_modu
+ 	nf_flow_table_hw_unregister(&flow_offload_hw);
+ 	cancel_work_sync(&nf_flow_offload_hw_work);
+ 
+-	list_for_each_entry_safe(offload, next, &hw_offload_pending, list) {
+-		if (offload->ct)
+-			nf_conntrack_put(&offload->ct->ct_general);
+-		list_del(&offload->list);
+-		kfree(offload);
+-	}
++	list_for_each_entry_safe(offload, next, &hw_offload_pending, list)
++		flow_offload_hw_free(offload);
+ }
+ 
+ module_init(nf_flow_table_hw_module_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/642-net-8021q-support-hardware-flow-table-offload.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/642-net-8021q-support-hardware-flow-table-offload.patch
new file mode 100644
index 0000000..cfcc28a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/642-net-8021q-support-hardware-flow-table-offload.patch
@@ -0,0 +1,61 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 15 Mar 2018 20:49:58 +0100
+Subject: [PATCH] net: 8021q: support hardware flow table offload
+
+Add the VLAN ID and protocol information
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/8021q/vlan_dev.c
++++ b/net/8021q/vlan_dev.c
+@@ -27,6 +27,11 @@
+ #include <linux/phy.h>
+ #include <net/arp.h>
+ 
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++#include <linux/netfilter.h>
++#include <net/netfilter/nf_flow_table.h>
++#endif
++
+ #include "vlan.h"
+ #include "vlanproc.h"
+ #include <linux/if_vlan.h>
+@@ -747,6 +752,27 @@ static int vlan_dev_get_iflink(const str
+ 	return real_dev->ifindex;
+ }
+ 
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++static int vlan_dev_flow_offload_check(struct flow_offload_hw_path *path)
++{
++	struct net_device *dev = path->dev;
++	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
++
++	if (path->flags & FLOW_OFFLOAD_PATH_VLAN)
++		return -EEXIST;
++
++	path->flags |= FLOW_OFFLOAD_PATH_VLAN;
++	path->vlan_proto = vlan->vlan_proto;
++	path->vlan_id = vlan->vlan_id;
++	path->dev = vlan->real_dev;
++
++	if (vlan->real_dev->netdev_ops->ndo_flow_offload_check)
++		return vlan->real_dev->netdev_ops->ndo_flow_offload_check(path);
++
++	return 0;
++}
++#endif /* CONFIG_NF_FLOW_TABLE */
++
+ static const struct ethtool_ops vlan_ethtool_ops = {
+ 	.get_link_ksettings	= vlan_ethtool_get_link_ksettings,
+ 	.get_drvinfo	        = vlan_ethtool_get_drvinfo,
+@@ -785,6 +811,9 @@ static const struct net_device_ops vlan_
+ #endif
+ 	.ndo_fix_features	= vlan_dev_fix_features,
+ 	.ndo_get_iflink		= vlan_dev_get_iflink,
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++	.ndo_flow_offload_check = vlan_dev_flow_offload_check,
++#endif
+ };
+ 
+ static void vlan_dev_free(struct net_device *dev)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/643-net-bridge-support-hardware-flow-table-offload.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/643-net-bridge-support-hardware-flow-table-offload.patch
new file mode 100644
index 0000000..d47482d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/643-net-bridge-support-hardware-flow-table-offload.patch
@@ -0,0 +1,61 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 15 Mar 2018 20:50:37 +0100
+Subject: [PATCH] net: bridge: support hardware flow table offload
+
+Look up the real device and pass it on
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/bridge/br_device.c
++++ b/net/bridge/br_device.c
+@@ -14,6 +14,10 @@
+ #include <linux/ethtool.h>
+ #include <linux/list.h>
+ #include <linux/netfilter_bridge.h>
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++#include <linux/netfilter.h>
++#include <net/netfilter/nf_flow_table.h>
++#endif
+ 
+ #include <linux/uaccess.h>
+ #include "br_private.h"
+@@ -382,6 +386,28 @@ static const struct ethtool_ops br_ethto
+ 	.get_link	= ethtool_op_get_link,
+ };
+ 
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++static int br_flow_offload_check(struct flow_offload_hw_path *path)
++{
++	struct net_device *dev = path->dev;
++	struct net_bridge *br = netdev_priv(dev);
++	struct net_bridge_fdb_entry *dst;
++
++	if (!(path->flags & FLOW_OFFLOAD_PATH_ETHERNET))
++		return -EINVAL;
++
++	dst = br_fdb_find_rcu(br, path->eth_dest, path->vlan_id);
++	if (!dst || !dst->dst)
++		return -ENOENT;
++
++	path->dev = dst->dst->dev;
++	if (path->dev->netdev_ops->ndo_flow_offload_check)
++		return path->dev->netdev_ops->ndo_flow_offload_check(path);
++
++	return 0;
++}
++#endif /* CONFIG_NF_FLOW_TABLE */
++
+ static const struct net_device_ops br_netdev_ops = {
+ 	.ndo_open		 = br_dev_open,
+ 	.ndo_stop		 = br_dev_stop,
+@@ -410,6 +436,9 @@ static const struct net_device_ops br_ne
+ 	.ndo_bridge_setlink	 = br_setlink,
+ 	.ndo_bridge_dellink	 = br_dellink,
+ 	.ndo_features_check	 = passthru_features_check,
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++	.ndo_flow_offload_check	 = br_flow_offload_check,
++#endif
+ };
+ 
+ static struct device_type br_type = {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/644-net-pppoe-support-hardware-flow-table-offload.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/644-net-pppoe-support-hardware-flow-table-offload.patch
new file mode 100644
index 0000000..b09b3bc
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/644-net-pppoe-support-hardware-flow-table-offload.patch
@@ -0,0 +1,125 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 15 Mar 2018 21:15:00 +0100
+Subject: [PATCH] net: pppoe: support hardware flow table offload
+
+Pass on the PPPoE session ID and the remote MAC address
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/ppp/ppp_generic.c
++++ b/drivers/net/ppp/ppp_generic.c
+@@ -53,6 +53,11 @@
+ #include <net/net_namespace.h>
+ #include <net/netns/generic.h>
+ 
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++#include <linux/netfilter.h>
++#include <net/netfilter/nf_flow_table.h>
++#endif
++
+ #define PPP_VERSION	"2.4.2"
+ 
+ /*
+@@ -1378,12 +1383,37 @@ static void ppp_dev_priv_destructor(stru
+ 		ppp_destroy_interface(ppp);
+ }
+ 
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++static int ppp_flow_offload_check(struct flow_offload_hw_path *path)
++{
++	struct ppp *ppp = netdev_priv(path->dev);
++	struct ppp_channel *chan;
++	struct channel *pch;
++
++	if (ppp->flags & SC_MULTILINK)
++		return -EOPNOTSUPP;
++
++	if (list_empty(&ppp->channels))
++		return -ENODEV;
++
++	pch = list_first_entry(&ppp->channels, struct channel, clist);
++	chan = pch->chan;
++	if (!chan->ops->flow_offload_check)
++		return -EOPNOTSUPP;
++
++	return chan->ops->flow_offload_check(chan, path);
++}
++#endif /* CONFIG_NF_FLOW_TABLE */
++
+ static const struct net_device_ops ppp_netdev_ops = {
+ 	.ndo_init	 = ppp_dev_init,
+ 	.ndo_uninit      = ppp_dev_uninit,
+ 	.ndo_start_xmit  = ppp_start_xmit,
+ 	.ndo_do_ioctl    = ppp_net_ioctl,
+ 	.ndo_get_stats64 = ppp_get_stats64,
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++	.ndo_flow_offload_check = ppp_flow_offload_check,
++#endif
+ };
+ 
+ static struct device_type ppp_type = {
+--- a/drivers/net/ppp/pppoe.c
++++ b/drivers/net/ppp/pppoe.c
+@@ -73,6 +73,11 @@
+ #include <linux/proc_fs.h>
+ #include <linux/seq_file.h>
+ 
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++#include <linux/netfilter.h>
++#include <net/netfilter/nf_flow_table.h>
++#endif
++
+ #include <linux/nsproxy.h>
+ #include <net/net_namespace.h>
+ #include <net/netns/generic.h>
+@@ -974,8 +979,36 @@ static int pppoe_xmit(struct ppp_channel
+ 	return __pppoe_xmit(sk, skb);
+ }
+ 
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++static int pppoe_flow_offload_check(struct ppp_channel *chan,
++				    struct flow_offload_hw_path *path)
++{
++	struct sock *sk = (struct sock *)chan->private;
++	struct pppox_sock *po = pppox_sk(sk);
++	struct net_device *dev = po->pppoe_dev;
++
++	if (sock_flag(sk, SOCK_DEAD) ||
++	    !(sk->sk_state & PPPOX_CONNECTED) || !dev)
++		return -ENODEV;
++
++	path->dev = po->pppoe_dev;
++	path->flags |= FLOW_OFFLOAD_PATH_PPPOE;
++	memcpy(path->eth_src, po->pppoe_dev->dev_addr, ETH_ALEN);
++	memcpy(path->eth_dest, po->pppoe_pa.remote, ETH_ALEN);
++	path->pppoe_sid = be16_to_cpu(po->num);
++
++	if (path->dev->netdev_ops->ndo_flow_offload_check)
++		return path->dev->netdev_ops->ndo_flow_offload_check(path);
++
++	return 0;
++}
++#endif /* CONFIG_NF_FLOW_TABLE */
++
+ static const struct ppp_channel_ops pppoe_chan_ops = {
+ 	.start_xmit = pppoe_xmit,
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++	.flow_offload_check = pppoe_flow_offload_check,
++#endif
+ };
+ 
+ static int pppoe_recvmsg(struct socket *sock, struct msghdr *m,
+--- a/include/linux/ppp_channel.h
++++ b/include/linux/ppp_channel.h
+@@ -28,6 +28,10 @@ struct ppp_channel_ops {
+ 	int	(*start_xmit)(struct ppp_channel *, struct sk_buff *);
+ 	/* Handle an ioctl call that has come in via /dev/ppp. */
+ 	int	(*ioctl)(struct ppp_channel *, unsigned int, unsigned long);
++
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++	int	(*flow_offload_check)(struct ppp_channel *, struct flow_offload_hw_path *);
++#endif
+ };
+ 
+ struct ppp_channel {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/645-netfilter-nf_flow_table-rework-hardware-offload-time.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/645-netfilter-nf_flow_table-rework-hardware-offload-time.patch
new file mode 100644
index 0000000..3c44c29
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/645-netfilter-nf_flow_table-rework-hardware-offload-time.patch
@@ -0,0 +1,37 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 25 Mar 2018 21:10:55 +0200
+Subject: [PATCH] netfilter: nf_flow_table: rework hardware offload timeout
+ handling
+
+Some offload implementations send keepalive packets + explicit
+notifications of TCP FIN/RST packets. In this case it is more convenient
+to simply let the driver update flow->timeout handling and use the
+regular flow offload gc step.
+
+For drivers that manage their own lifetime, a separate flag can be set
+to avoid gc timeouts.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/include/net/netfilter/nf_flow_table.h
++++ b/include/net/netfilter/nf_flow_table.h
+@@ -75,6 +75,7 @@ struct flow_offload_tuple_rhash {
+ #define FLOW_OFFLOAD_DYING	0x4
+ #define FLOW_OFFLOAD_TEARDOWN	0x8
+ #define FLOW_OFFLOAD_HW		0x10
++#define FLOW_OFFLOAD_KEEP	0x20
+ 
+ struct flow_offload {
+ 	struct flow_offload_tuple_rhash		tuplehash[FLOW_OFFLOAD_DIR_MAX];
+--- a/net/netfilter/nf_flow_table_core.c
++++ b/net/netfilter/nf_flow_table_core.c
+@@ -370,7 +370,7 @@ static void nf_flow_offload_gc_step(stru
+ 	if (!teardown)
+ 		nf_ct_offload_timeout(flow);
+ 
+-	if (nf_flow_in_hw(flow) && !teardown)
++	if ((flow->flags & FLOW_OFFLOAD_KEEP) && !teardown)
+ 		return;
+ 
+ 	if (nf_flow_has_expired(flow) || teardown)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/646-netfilter-nf_flow_table-rework-private-driver-data.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/646-netfilter-nf_flow_table-rework-private-driver-data.patch
new file mode 100644
index 0000000..159ad8a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/646-netfilter-nf_flow_table-rework-private-driver-data.patch
@@ -0,0 +1,25 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 27 Apr 2018 14:42:14 +0200
+Subject: [PATCH] netfilter: nf_flow_table: rework private driver data
+
+Move the timeout out of the union, since it can be shared between the
+driver and the stack. Add a private pointer that the driver can use to
+point to its own data structures
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/include/net/netfilter/nf_flow_table.h
++++ b/include/net/netfilter/nf_flow_table.h
+@@ -80,9 +80,10 @@ struct flow_offload_tuple_rhash {
+ struct flow_offload {
+ 	struct flow_offload_tuple_rhash		tuplehash[FLOW_OFFLOAD_DIR_MAX];
+ 	u32					flags;
++	u32					timeout;
+ 	union {
+ 		/* Your private driver data here. */
+-		u32		timeout;
++		void *priv;
+ 	};
+ };
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/647-net-dsa-support-hardware-flow-table-offload.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/647-net-dsa-support-hardware-flow-table-offload.patch
new file mode 100644
index 0000000..91aae5b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/647-net-dsa-support-hardware-flow-table-offload.patch
@@ -0,0 +1,78 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 17 Sep 2020 18:41:23 +0200
+Subject: [PATCH] net: dsa: support hardware flow table offload
+
+Look up the master device and the port id
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/include/net/netfilter/nf_flow_table.h
++++ b/include/net/netfilter/nf_flow_table.h
+@@ -90,6 +90,7 @@ struct flow_offload {
+ #define FLOW_OFFLOAD_PATH_ETHERNET	BIT(0)
+ #define FLOW_OFFLOAD_PATH_VLAN		BIT(1)
+ #define FLOW_OFFLOAD_PATH_PPPOE		BIT(2)
++#define FLOW_OFFLOAD_PATH_DSA		BIT(3)
+ 
+ struct flow_offload_hw_path {
+ 	struct net_device *dev;
+@@ -100,6 +101,7 @@ struct flow_offload_hw_path {
+ 	u16 vlan_proto;
+ 	u16 vlan_id;
+ 	u16 pppoe_sid;
++	u16 dsa_port;
+ };
+ 
+ #define NF_FLOW_TIMEOUT (30 * HZ)
+--- a/net/dsa/slave.c
++++ b/net/dsa/slave.c
+@@ -19,6 +19,10 @@
+ #include <linux/if_bridge.h>
+ #include <linux/netpoll.h>
+ #include <linux/ptp_classify.h>
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++#include <linux/netfilter.h>
++#include <net/netfilter/nf_flow_table.h>
++#endif
+ 
+ #include "dsa_priv.h"
+ 
+@@ -1226,6 +1230,27 @@ static struct devlink_port *dsa_slave_ge
+ 	return dp->ds->devlink ? &dp->devlink_port : NULL;
+ }
+ 
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++static int dsa_flow_offload_check(struct flow_offload_hw_path *path)
++{
++	struct net_device *dev = path->dev;
++	struct dsa_port *dp;
++
++	if (!(path->flags & FLOW_OFFLOAD_PATH_ETHERNET))
++		return -EINVAL;
++
++	dp = dsa_slave_to_port(dev);
++	path->dsa_port = dp->index;
++	path->dev = dsa_slave_to_master(dev);
++	path->flags |= FLOW_OFFLOAD_PATH_DSA;
++
++	if (path->dev->netdev_ops->ndo_flow_offload_check)
++		return path->dev->netdev_ops->ndo_flow_offload_check(path);
++
++	return 0;
++}
++#endif /* CONFIG_NF_FLOW_TABLE */
++
+ static const struct net_device_ops dsa_slave_netdev_ops = {
+ 	.ndo_open	 	= dsa_slave_open,
+ 	.ndo_stop		= dsa_slave_close,
+@@ -1250,6 +1275,9 @@ static const struct net_device_ops dsa_s
+ 	.ndo_vlan_rx_add_vid	= dsa_slave_vlan_rx_add_vid,
+ 	.ndo_vlan_rx_kill_vid	= dsa_slave_vlan_rx_kill_vid,
+ 	.ndo_get_devlink_port	= dsa_slave_get_devlink_port,
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++	.ndo_flow_offload_check	 = dsa_flow_offload_check,
++#endif
+ };
+ 
+ static struct device_type dsa_type = {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/655-increase_skb_pad.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/655-increase_skb_pad.patch
new file mode 100644
index 0000000..e325301
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/655-increase_skb_pad.patch
@@ -0,0 +1,20 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: kernel: add a few patches for avoiding unnecessary skb reallocations - significantly improves ethernet<->wireless performance
+
+lede-commit: 6f89cffc9add6939d44a6b54cf9a5e77849aa7fd
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ include/linux/skbuff.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -2650,7 +2650,7 @@ static inline int pskb_network_may_pull(
+  * NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8)
+  */
+ #ifndef NET_SKB_PAD
+-#define NET_SKB_PAD	max(32, L1_CACHE_BYTES)
++#define NET_SKB_PAD	max(64, L1_CACHE_BYTES)
+ #endif
+ 
+ int ___pskb_trim(struct sk_buff *skb, unsigned int len);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch
new file mode 100644
index 0000000..39f7af2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch
@@ -0,0 +1,501 @@
+From: Steven Barth <steven@midlink.org>
+Subject: Add support for MAP-E FMRs (mesh mode)
+
+MAP-E FMRs (draft-ietf-softwire-map-10) are rules for IPv4-communication
+between MAP CEs (mesh mode) without the need to forward such data to a
+border relay. This is similar to how 6rd works but for IPv4 over IPv6.
+
+Signed-off-by: Steven Barth <cyrus@openwrt.org>
+---
+ include/net/ip6_tunnel.h       |  13 ++
+ include/uapi/linux/if_tunnel.h |  13 ++
+ net/ipv6/ip6_tunnel.c          | 276 +++++++++++++++++++++++++++++++++++++++--
+ 3 files changed, 291 insertions(+), 11 deletions(-)
+
+--- a/include/net/ip6_tunnel.h
++++ b/include/net/ip6_tunnel.h
+@@ -18,6 +18,18 @@
+ /* determine capability on a per-packet basis */
+ #define IP6_TNL_F_CAP_PER_PACKET 0x40000
+ 
++/* IPv6 tunnel FMR */
++struct __ip6_tnl_fmr {
++	struct __ip6_tnl_fmr *next; /* next fmr in list */
++	struct in6_addr ip6_prefix;
++	struct in_addr ip4_prefix;
++
++	__u8 ip6_prefix_len;
++	__u8 ip4_prefix_len;
++	__u8 ea_len;
++	__u8 offset;
++};
++
+ struct __ip6_tnl_parm {
+ 	char name[IFNAMSIZ];	/* name of tunnel device */
+ 	int link;		/* ifindex of underlying L2 interface */
+@@ -29,6 +41,7 @@ struct __ip6_tnl_parm {
+ 	__u32 flags;		/* tunnel flags */
+ 	struct in6_addr laddr;	/* local tunnel end-point address */
+ 	struct in6_addr raddr;	/* remote tunnel end-point address */
++	struct __ip6_tnl_fmr *fmrs;	/* FMRs */
+ 
+ 	__be16			i_flags;
+ 	__be16			o_flags;
+--- a/include/uapi/linux/if_tunnel.h
++++ b/include/uapi/linux/if_tunnel.h
+@@ -77,10 +77,23 @@ enum {
+ 	IFLA_IPTUN_ENCAP_DPORT,
+ 	IFLA_IPTUN_COLLECT_METADATA,
+ 	IFLA_IPTUN_FWMARK,
++	IFLA_IPTUN_FMRS,
+ 	__IFLA_IPTUN_MAX,
+ };
+ #define IFLA_IPTUN_MAX	(__IFLA_IPTUN_MAX - 1)
+ 
++enum {
++	IFLA_IPTUN_FMR_UNSPEC,
++	IFLA_IPTUN_FMR_IP6_PREFIX,
++	IFLA_IPTUN_FMR_IP4_PREFIX,
++	IFLA_IPTUN_FMR_IP6_PREFIX_LEN,
++	IFLA_IPTUN_FMR_IP4_PREFIX_LEN,
++	IFLA_IPTUN_FMR_EA_LEN,
++	IFLA_IPTUN_FMR_OFFSET,
++	__IFLA_IPTUN_FMR_MAX,
++};
++#define IFLA_IPTUN_FMR_MAX (__IFLA_IPTUN_FMR_MAX - 1)
++
+ enum tunnel_encap_types {
+ 	TUNNEL_ENCAP_NONE,
+ 	TUNNEL_ENCAP_FOU,
+--- a/net/ipv6/ip6_tunnel.c
++++ b/net/ipv6/ip6_tunnel.c
+@@ -11,6 +11,9 @@
+  *      linux/net/ipv6/sit.c and linux/net/ipv4/ipip.c
+  *
+  *      RFC 2473
++ *
++ *      Changes:
++ *      Steven Barth <cyrus@openwrt.org>:           MAP-E FMR support
+  */
+ 
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+@@ -67,9 +70,9 @@ static bool log_ecn_error = true;
+ module_param(log_ecn_error, bool, 0644);
+ MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
+ 
+-static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2)
++static u32 HASH(const struct in6_addr *addr)
+ {
+-	u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2);
++	u32 hash = ipv6_addr_hash(addr);
+ 
+ 	return hash_32(hash, IP6_TUNNEL_HASH_SIZE_SHIFT);
+ }
+@@ -136,20 +139,29 @@ static struct net_device_stats *ip6_get_
+ static struct ip6_tnl *
+ ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_addr *local)
+ {
+-	unsigned int hash = HASH(remote, local);
++	unsigned int hash = HASH(local);
+ 	struct ip6_tnl *t;
+ 	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
+ 	struct in6_addr any;
++	struct __ip6_tnl_fmr *fmr;
+ 
+ 	for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+-		if (ipv6_addr_equal(local, &t->parms.laddr) &&
+-		    ipv6_addr_equal(remote, &t->parms.raddr) &&
+-		    (t->dev->flags & IFF_UP))
++		if (!ipv6_addr_equal(local, &t->parms.laddr) ||
++				!(t->dev->flags & IFF_UP))
++			continue;
++
++		if (ipv6_addr_equal(remote, &t->parms.raddr))
+ 			return t;
++
++		for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) {
++			if (ipv6_prefix_equal(remote, &fmr->ip6_prefix,
++					fmr->ip6_prefix_len))
++				return t;
++		}
+ 	}
+ 
+ 	memset(&any, 0, sizeof(any));
+-	hash = HASH(&any, local);
++	hash = HASH(local);
+ 	for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+ 		if (ipv6_addr_equal(local, &t->parms.laddr) &&
+ 		    ipv6_addr_any(&t->parms.raddr) &&
+@@ -157,7 +169,7 @@ ip6_tnl_lookup(struct net *net, const st
+ 			return t;
+ 	}
+ 
+-	hash = HASH(remote, &any);
++	hash = HASH(&any);
+ 	for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+ 		if (ipv6_addr_equal(remote, &t->parms.raddr) &&
+ 		    ipv6_addr_any(&t->parms.laddr) &&
+@@ -197,7 +209,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n,
+ 
+ 	if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
+ 		prio = 1;
+-		h = HASH(remote, local);
++		h = HASH(local);
+ 	}
+ 	return &ip6n->tnls[prio][h];
+ }
+@@ -377,6 +389,12 @@ ip6_tnl_dev_uninit(struct net_device *de
+ 	struct net *net = t->net;
+ 	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
+ 
++	while (t->parms.fmrs) {
++		struct __ip6_tnl_fmr *next = t->parms.fmrs->next;
++		kfree(t->parms.fmrs);
++		t->parms.fmrs = next;
++	}
++
+ 	if (dev == ip6n->fb_tnl_dev)
+ 		RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL);
+ 	else
+@@ -766,6 +784,107 @@ int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
+ }
+ EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl);
+ 
++/**
++ * ip4ip6_fmr_calc - calculate target / source IPv6-address based on FMR
++ *   @dest: destination IPv6 address buffer
++ *   @skb: received socket buffer
++ *   @fmr: MAP FMR
++ *   @xmit: Calculate for xmit or rcv
++ **/
++static void ip4ip6_fmr_calc(struct in6_addr *dest,
++		const struct iphdr *iph, const uint8_t *end,
++		const struct __ip6_tnl_fmr *fmr, bool xmit)
++{
++	int psidlen = fmr->ea_len - (32 - fmr->ip4_prefix_len);
++	u8 *portp = NULL;
++	bool use_dest_addr;
++	const struct iphdr *dsth = iph;
++
++	if ((u8*)dsth >= end)
++		return;
++
++	/* find significant IP header */
++	if (iph->protocol == IPPROTO_ICMP) {
++		struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4);
++		if (ih && ((u8*)&ih[1]) <= end && (
++			ih->type == ICMP_DEST_UNREACH ||
++			ih->type == ICMP_SOURCE_QUENCH ||
++			ih->type == ICMP_TIME_EXCEEDED ||
++			ih->type == ICMP_PARAMETERPROB ||
++			ih->type == ICMP_REDIRECT))
++				dsth = (const struct iphdr*)&ih[1];
++	}
++
++	/* in xmit-path use dest port by default and source port only if
++		this is an ICMP reply to something else; vice versa in rcv-path */
++	use_dest_addr = (xmit && dsth == iph) || (!xmit && dsth != iph);
++
++	/* get dst port */
++	if (((u8*)&dsth[1]) <= end && (
++		dsth->protocol == IPPROTO_UDP ||
++		dsth->protocol == IPPROTO_TCP ||
++		dsth->protocol == IPPROTO_SCTP ||
++		dsth->protocol == IPPROTO_DCCP)) {
++			/* for UDP, TCP, SCTP and DCCP source and dest port
++			follow IPv4 header directly */
++			portp = ((u8*)dsth) + dsth->ihl * 4;
++
++			if (use_dest_addr)
++				portp += sizeof(u16);
++	} else if (iph->protocol == IPPROTO_ICMP) {
++		struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4);
++
++		/* use icmp identifier as port */
++		if (((u8*)&ih) <= end && (
++		    (use_dest_addr && (
++		    ih->type == ICMP_ECHOREPLY ||
++			ih->type == ICMP_TIMESTAMPREPLY ||
++			ih->type == ICMP_INFO_REPLY ||
++			ih->type == ICMP_ADDRESSREPLY)) ||
++			(!use_dest_addr && (
++			ih->type == ICMP_ECHO ||
++			ih->type == ICMP_TIMESTAMP ||
++			ih->type == ICMP_INFO_REQUEST ||
++			ih->type == ICMP_ADDRESS)
++			)))
++				portp = (u8*)&ih->un.echo.id;
++	}
++
++	if ((portp && &portp[2] <= end) || psidlen == 0) {
++		int frombyte = fmr->ip6_prefix_len / 8;
++		int fromrem = fmr->ip6_prefix_len % 8;
++		int bytes = sizeof(struct in6_addr) - frombyte;
++		const u32 *addr = (use_dest_addr) ? &iph->daddr : &iph->saddr;
++		u64 eabits = ((u64)ntohl(*addr)) << (32 + fmr->ip4_prefix_len);
++		u64 t = 0;
++
++		/* extract PSID from port and add it to eabits */
++		u16 psidbits = 0;
++		if (psidlen > 0) {
++			psidbits = ((u16)portp[0]) << 8 | ((u16)portp[1]);
++			psidbits >>= 16 - psidlen - fmr->offset;
++			psidbits = (u16)(psidbits << (16 - psidlen));
++			eabits |= ((u64)psidbits) << (48 - (fmr->ea_len - psidlen));
++		}
++
++		/* rewrite destination address */
++		*dest = fmr->ip6_prefix;
++		memcpy(&dest->s6_addr[10], addr, sizeof(*addr));
++		dest->s6_addr16[7] = htons(psidbits >> (16 - psidlen));
++
++		if (bytes > sizeof(u64))
++			bytes = sizeof(u64);
++
++		/* insert eabits */
++		memcpy(&t, &dest->s6_addr[frombyte], bytes);
++		t = be64_to_cpu(t) & ~(((((u64)1) << fmr->ea_len) - 1)
++			<< (64 - fmr->ea_len - fromrem));
++		t = cpu_to_be64(t | (eabits >> fromrem));
++		memcpy(&dest->s6_addr[frombyte], &t, bytes);
++	}
++}
++
++
+ static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
+ 			 const struct tnl_ptk_info *tpi,
+ 			 struct metadata_dst *tun_dst,
+@@ -818,6 +937,27 @@ static int __ip6_tnl_rcv(struct ip6_tnl
+ 	skb_reset_network_header(skb);
+ 	memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
+ 
++	if (tpi->proto == htons(ETH_P_IP) && tunnel->parms.fmrs &&
++		!ipv6_addr_equal(&ipv6h->saddr, &tunnel->parms.raddr)) {
++			/* Packet didn't come from BR, so lookup FMR */
++			struct __ip6_tnl_fmr *fmr;
++			struct in6_addr expected = tunnel->parms.raddr;
++			for (fmr = tunnel->parms.fmrs; fmr; fmr = fmr->next)
++				if (ipv6_prefix_equal(&ipv6h->saddr,
++					&fmr->ip6_prefix, fmr->ip6_prefix_len))
++						break;
++
++			/* Check that IPv6 matches IPv4 source to prevent spoofing */
++			if (fmr)
++				ip4ip6_fmr_calc(&expected, ip_hdr(skb),
++						skb_tail_pointer(skb), fmr, false);
++
++			if (!ipv6_addr_equal(&ipv6h->saddr, &expected)) {
++				rcu_read_unlock();
++				goto drop;
++			}
++	}
++
+ 	__skb_tunnel_rx(skb, tunnel->dev, tunnel->net);
+ 
+ 	err = dscp_ecn_decapsulate(tunnel, ipv6h, skb);
+@@ -958,6 +1098,7 @@ static void init_tel_txopt(struct ipv6_t
+ 	opt->ops.opt_nflen = 8;
+ }
+ 
++
+ /**
+  * ip6_tnl_addr_conflict - compare packet addresses to tunnel's own
+  *   @t: the outgoing tunnel device
+@@ -1310,6 +1451,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str
+ {
+ 	struct ip6_tnl *t = netdev_priv(dev);
+ 	struct ipv6hdr *ipv6h;
++	struct __ip6_tnl_fmr *fmr;
+ 	int encap_limit = -1;
+ 	__u16 offset;
+ 	struct flowi6 fl6;
+@@ -1375,6 +1517,18 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str
+ 	fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
+ 	dsfield = INET_ECN_encapsulate(dsfield, ipv6_get_dsfield(ipv6h));
+ 
++	/* try to find matching FMR */
++	for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) {
++		unsigned mshift = 32 - fmr->ip4_prefix_len;
++		if (ntohl(fmr->ip4_prefix.s_addr) >> mshift ==
++				ntohl(ip_hdr(skb)->daddr) >> mshift)
++			break;
++	}
++
++	/* change dstaddr according to FMR */
++	if (fmr)
++		ip4ip6_fmr_calc(&fl6.daddr, ip_hdr(skb), skb_tail_pointer(skb), fmr, true);
++
+ 	if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6))
+ 		return -1;
+ 
+@@ -1504,6 +1658,14 @@ ip6_tnl_change(struct ip6_tnl *t, const
+ 	t->parms.link = p->link;
+ 	t->parms.proto = p->proto;
+ 	t->parms.fwmark = p->fwmark;
++
++	while (t->parms.fmrs) {
++		struct __ip6_tnl_fmr *next = t->parms.fmrs->next;
++		kfree(t->parms.fmrs);
++		t->parms.fmrs = next;
++	}
++	t->parms.fmrs = p->fmrs;
++
+ 	dst_cache_reset(&t->dst_cache);
+ 	ip6_tnl_link_config(t);
+ 	return 0;
+@@ -1542,6 +1704,7 @@ ip6_tnl_parm_from_user(struct __ip6_tnl_
+ 	p->flowinfo = u->flowinfo;
+ 	p->link = u->link;
+ 	p->proto = u->proto;
++	p->fmrs = NULL;
+ 	memcpy(p->name, u->name, sizeof(u->name));
+ }
+ 
+@@ -1926,6 +2089,15 @@ static int ip6_tnl_validate(struct nlatt
+ 	return 0;
+ }
+ 
++static const struct nla_policy ip6_tnl_fmr_policy[IFLA_IPTUN_FMR_MAX + 1] = {
++	[IFLA_IPTUN_FMR_IP6_PREFIX] = { .len = sizeof(struct in6_addr) },
++	[IFLA_IPTUN_FMR_IP4_PREFIX] = { .len = sizeof(struct in_addr) },
++	[IFLA_IPTUN_FMR_IP6_PREFIX_LEN] = { .type = NLA_U8 },
++	[IFLA_IPTUN_FMR_IP4_PREFIX_LEN] = { .type = NLA_U8 },
++	[IFLA_IPTUN_FMR_EA_LEN] = { .type = NLA_U8 },
++	[IFLA_IPTUN_FMR_OFFSET] = { .type = NLA_U8 }
++};
++
+ static void ip6_tnl_netlink_parms(struct nlattr *data[],
+ 				  struct __ip6_tnl_parm *parms)
+ {
+@@ -1963,6 +2135,46 @@ static void ip6_tnl_netlink_parms(struct
+ 
+ 	if (data[IFLA_IPTUN_FWMARK])
+ 		parms->fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]);
++
++	if (data[IFLA_IPTUN_FMRS]) {
++		unsigned rem;
++		struct nlattr *fmr;
++		nla_for_each_nested(fmr, data[IFLA_IPTUN_FMRS], rem) {
++			struct nlattr *fmrd[IFLA_IPTUN_FMR_MAX + 1], *c;
++			struct __ip6_tnl_fmr *nfmr;
++
++			nla_parse_nested(fmrd, IFLA_IPTUN_FMR_MAX,
++				fmr, ip6_tnl_fmr_policy, NULL);
++
++			if (!(nfmr = kzalloc(sizeof(*nfmr), GFP_KERNEL)))
++				continue;
++
++			nfmr->offset = 6;
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX]))
++				nla_memcpy(&nfmr->ip6_prefix, fmrd[IFLA_IPTUN_FMR_IP6_PREFIX],
++					sizeof(nfmr->ip6_prefix));
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX]))
++				nla_memcpy(&nfmr->ip4_prefix, fmrd[IFLA_IPTUN_FMR_IP4_PREFIX],
++					sizeof(nfmr->ip4_prefix));
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX_LEN]))
++				nfmr->ip6_prefix_len = nla_get_u8(c);
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX_LEN]))
++				nfmr->ip4_prefix_len = nla_get_u8(c);
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_EA_LEN]))
++				nfmr->ea_len = nla_get_u8(c);
++
++			if ((c = fmrd[IFLA_IPTUN_FMR_OFFSET]))
++				nfmr->offset = nla_get_u8(c);
++
++			nfmr->next = parms->fmrs;
++			parms->fmrs = nfmr;
++		}
++	}
+ }
+ 
+ static bool ip6_tnl_netlink_encap_parms(struct nlattr *data[],
+@@ -2078,6 +2290,12 @@ static void ip6_tnl_dellink(struct net_d
+ 
+ static size_t ip6_tnl_get_size(const struct net_device *dev)
+ {
++	const struct ip6_tnl *t = netdev_priv(dev);
++	struct __ip6_tnl_fmr *c;
++	int fmrs = 0;
++	for (c = t->parms.fmrs; c; c = c->next)
++		++fmrs;
++
+ 	return
+ 		/* IFLA_IPTUN_LINK */
+ 		nla_total_size(4) +
+@@ -2107,6 +2325,24 @@ static size_t ip6_tnl_get_size(const str
+ 		nla_total_size(0) +
+ 		/* IFLA_IPTUN_FWMARK */
+ 		nla_total_size(4) +
++		/* IFLA_IPTUN_FMRS */
++		nla_total_size(0) +
++		(
++			/* nest */
++			nla_total_size(0) +
++			/* IFLA_IPTUN_FMR_IP6_PREFIX */
++			nla_total_size(sizeof(struct in6_addr)) +
++			/* IFLA_IPTUN_FMR_IP4_PREFIX */
++			nla_total_size(sizeof(struct in_addr)) +
++			/* IFLA_IPTUN_FMR_EA_LEN */
++			nla_total_size(1) +
++			/* IFLA_IPTUN_FMR_IP6_PREFIX_LEN */
++			nla_total_size(1) +
++			/* IFLA_IPTUN_FMR_IP4_PREFIX_LEN */
++			nla_total_size(1) +
++			/* IFLA_IPTUN_FMR_OFFSET */
++			nla_total_size(1)
++		) * fmrs +
+ 		0;
+ }
+ 
+@@ -2114,6 +2350,9 @@ static int ip6_tnl_fill_info(struct sk_b
+ {
+ 	struct ip6_tnl *tunnel = netdev_priv(dev);
+ 	struct __ip6_tnl_parm *parm = &tunnel->parms;
++	struct __ip6_tnl_fmr *c;
++	int fmrcnt = 0;
++	struct nlattr *fmrs;
+ 
+ 	if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) ||
+ 	    nla_put_in6_addr(skb, IFLA_IPTUN_LOCAL, &parm->laddr) ||
+@@ -2123,9 +2362,27 @@ static int ip6_tnl_fill_info(struct sk_b
+ 	    nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) ||
+ 	    nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) ||
+ 	    nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto) ||
+-	    nla_put_u32(skb, IFLA_IPTUN_FWMARK, parm->fwmark))
++	    nla_put_u32(skb, IFLA_IPTUN_FWMARK, parm->fwmark) ||
++	    !(fmrs = nla_nest_start(skb, IFLA_IPTUN_FMRS)))
+ 		goto nla_put_failure;
+ 
++	for (c = parm->fmrs; c; c = c->next) {
++		struct nlattr *fmr = nla_nest_start(skb, ++fmrcnt);
++		if (!fmr ||
++			nla_put(skb, IFLA_IPTUN_FMR_IP6_PREFIX,
++				sizeof(c->ip6_prefix), &c->ip6_prefix) ||
++			nla_put(skb, IFLA_IPTUN_FMR_IP4_PREFIX,
++				sizeof(c->ip4_prefix), &c->ip4_prefix) ||
++			nla_put_u8(skb, IFLA_IPTUN_FMR_IP6_PREFIX_LEN, c->ip6_prefix_len) ||
++			nla_put_u8(skb, IFLA_IPTUN_FMR_IP4_PREFIX_LEN, c->ip4_prefix_len) ||
++			nla_put_u8(skb, IFLA_IPTUN_FMR_EA_LEN, c->ea_len) ||
++			nla_put_u8(skb, IFLA_IPTUN_FMR_OFFSET, c->offset))
++				goto nla_put_failure;
++
++		nla_nest_end(skb, fmr);
++	}
++	nla_nest_end(skb, fmrs);
++
+ 	if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, tunnel->encap.type) ||
+ 	    nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT, tunnel->encap.sport) ||
+ 	    nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT, tunnel->encap.dport) ||
+@@ -2165,6 +2422,7 @@ static const struct nla_policy ip6_tnl_p
+ 	[IFLA_IPTUN_ENCAP_DPORT]	= { .type = NLA_U16 },
+ 	[IFLA_IPTUN_COLLECT_METADATA]	= { .type = NLA_FLAG },
+ 	[IFLA_IPTUN_FWMARK]		= { .type = NLA_U32 },
++	[IFLA_IPTUN_FMRS]		= { .type = NLA_NESTED },
+ };
+ 
+ static struct rtnl_link_ops ip6_link_ops __read_mostly = {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch
new file mode 100644
index 0000000..82c1e26
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch
@@ -0,0 +1,263 @@
+From: Jonas Gorski <jogo@openwrt.org>
+Subject: ipv6: allow rejecting with "source address failed policy"
+
+RFC6204 L-14 requires rejecting traffic from invalid addresses with
+ICMPv6 Destination Unreachable, Code 5 (Source address failed ingress/
+egress policy) on the LAN side, so add an appropriate rule for that.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ include/net/netns/ipv6.h       |  1 +
+ include/uapi/linux/fib_rules.h |  4 +++
+ include/uapi/linux/rtnetlink.h |  1 +
+ net/ipv4/fib_semantics.c       |  4 +++
+ net/ipv4/fib_trie.c            |  1 +
+ net/ipv4/ipmr.c                |  1 +
+ net/ipv6/fib6_rules.c          |  4 +++
+ net/ipv6/ip6mr.c               |  2 ++
+ net/ipv6/route.c               | 58 +++++++++++++++++++++++++++++++++++++++++-
+ 9 files changed, 75 insertions(+), 1 deletion(-)
+
+--- a/include/net/netns/ipv6.h
++++ b/include/net/netns/ipv6.h
+@@ -84,6 +84,7 @@ struct netns_ipv6 {
+ 	unsigned int		fib6_rules_require_fldissect;
+ 	bool			fib6_has_custom_rules;
+ 	struct rt6_info         *ip6_prohibit_entry;
++	struct rt6_info		*ip6_policy_failed_entry;
+ 	struct rt6_info         *ip6_blk_hole_entry;
+ 	struct fib6_table       *fib6_local_tbl;
+ 	struct fib_rules_ops    *fib6_rules_ops;
+--- a/include/uapi/linux/fib_rules.h
++++ b/include/uapi/linux/fib_rules.h
+@@ -82,6 +82,10 @@ enum {
+ 	FR_ACT_BLACKHOLE,	/* Drop without notification */
+ 	FR_ACT_UNREACHABLE,	/* Drop with ENETUNREACH */
+ 	FR_ACT_PROHIBIT,	/* Drop with EACCES */
++	FR_ACT_RES9,
++	FR_ACT_RES10,
++	FR_ACT_RES11,
++	FR_ACT_POLICY_FAILED,	/* Drop with EACCES */
+ 	__FR_ACT_MAX,
+ };
+ 
+--- a/include/uapi/linux/rtnetlink.h
++++ b/include/uapi/linux/rtnetlink.h
+@@ -235,6 +235,7 @@ enum {
+ 	RTN_THROW,		/* Not in this table		*/
+ 	RTN_NAT,		/* Translate this address	*/
+ 	RTN_XRESOLVE,		/* Use external resolver	*/
++	RTN_POLICY_FAILED,	/* Failed ingress/egress policy */
+ 	__RTN_MAX
+ };
+ 
+--- a/net/ipv4/fib_semantics.c
++++ b/net/ipv4/fib_semantics.c
+@@ -142,6 +142,10 @@ const struct fib_prop fib_props[RTN_MAX
+ 		.error	= -EINVAL,
+ 		.scope	= RT_SCOPE_NOWHERE,
+ 	},
++	[RTN_POLICY_FAILED] = {
++		.error	= -EACCES,
++		.scope	= RT_SCOPE_UNIVERSE,
++	},
+ };
+ 
+ static void rt_fibinfo_free(struct rtable __rcu **rtp)
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -2596,6 +2596,7 @@ static const char *const rtn_type_names[
+ 	[RTN_THROW] = "THROW",
+ 	[RTN_NAT] = "NAT",
+ 	[RTN_XRESOLVE] = "XRESOLVE",
++	[RTN_POLICY_FAILED] = "POLICY_FAILED",
+ };
+ 
+ static inline const char *rtn_type(char *buf, size_t len, unsigned int t)
+--- a/net/ipv4/ipmr.c
++++ b/net/ipv4/ipmr.c
+@@ -173,6 +173,7 @@ static int ipmr_rule_action(struct fib_r
+ 	case FR_ACT_UNREACHABLE:
+ 		return -ENETUNREACH;
+ 	case FR_ACT_PROHIBIT:
++	case FR_ACT_POLICY_FAILED:
+ 		return -EACCES;
+ 	case FR_ACT_BLACKHOLE:
+ 	default:
+--- a/net/ipv6/fib6_rules.c
++++ b/net/ipv6/fib6_rules.c
+@@ -216,6 +216,10 @@ static int __fib6_rule_action(struct fib
+ 		err = -EACCES;
+ 		rt = net->ipv6.ip6_prohibit_entry;
+ 		goto discard_pkt;
++	case FR_ACT_POLICY_FAILED:
++		err = -EACCES;
++		rt = net->ipv6.ip6_policy_failed_entry;
++		goto discard_pkt;
+ 	}
+ 
+ 	tb_id = fib_rule_get_table(rule, arg);
+--- a/net/ipv6/ip6mr.c
++++ b/net/ipv6/ip6mr.c
+@@ -161,6 +161,8 @@ static int ip6mr_rule_action(struct fib_
+ 		return -ENETUNREACH;
+ 	case FR_ACT_PROHIBIT:
+ 		return -EACCES;
++	case FR_ACT_POLICY_FAILED:
++		return -EACCES;
+ 	case FR_ACT_BLACKHOLE:
+ 	default:
+ 		return -EINVAL;
+--- a/net/ipv6/route.c
++++ b/net/ipv6/route.c
+@@ -94,6 +94,8 @@ static int		ip6_pkt_discard(struct sk_bu
+ static int		ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb);
+ static int		ip6_pkt_prohibit(struct sk_buff *skb);
+ static int		ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb);
++static int		ip6_pkt_policy_failed(struct sk_buff *skb);
++static int		ip6_pkt_policy_failed_out(struct net *net, struct sock *sk, struct sk_buff *skb);
+ static void		ip6_link_failure(struct sk_buff *skb);
+ static void		ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
+ 					   struct sk_buff *skb, u32 mtu,
+@@ -327,6 +329,18 @@ static const struct rt6_info ip6_prohibi
+ 	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
+ };
+ 
++static const struct rt6_info ip6_policy_failed_entry_template = {
++	.dst = {
++		.__refcnt	= ATOMIC_INIT(1),
++		.__use		= 1,
++		.obsolete	= DST_OBSOLETE_FORCE_CHK,
++		.error		= -EACCES,
++		.input		= ip6_pkt_policy_failed,
++		.output		= ip6_pkt_policy_failed_out,
++	},
++	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
++};
++
+ static const struct rt6_info ip6_blk_hole_entry_template = {
+ 	.dst = {
+ 		.__refcnt	= ATOMIC_INIT(1),
+@@ -1048,6 +1062,7 @@ static const int fib6_prop[RTN_MAX + 1]
+ 	[RTN_BLACKHOLE]	= -EINVAL,
+ 	[RTN_UNREACHABLE] = -EHOSTUNREACH,
+ 	[RTN_PROHIBIT]	= -EACCES,
++	[RTN_POLICY_FAILED] = -EACCES,
+ 	[RTN_THROW]	= -EAGAIN,
+ 	[RTN_NAT]	= -EINVAL,
+ 	[RTN_XRESOLVE]	= -EINVAL,
+@@ -1085,6 +1100,10 @@ static void ip6_rt_init_dst_reject(struc
+ 		rt->dst.output = ip6_pkt_prohibit_out;
+ 		rt->dst.input = ip6_pkt_prohibit;
+ 		break;
++	case RTN_POLICY_FAILED:
++		rt->dst.output = ip6_pkt_policy_failed_out;
++		rt->dst.input = ip6_pkt_policy_failed;
++		break;
+ 	case RTN_THROW:
+ 	case RTN_UNREACHABLE:
+ 	default:
+@@ -4453,6 +4472,17 @@ static int ip6_pkt_prohibit_out(struct n
+ 	return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
+ }
+ 
++static int ip6_pkt_policy_failed(struct sk_buff *skb)
++{
++	return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_INNOROUTES);
++}
++
++static int ip6_pkt_policy_failed_out(struct net *net, struct sock *sk, struct sk_buff *skb)
++{
++	skb->dev = skb_dst(skb)->dev;
++	return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_OUTNOROUTES);
++}
++
+ /*
+  *	Allocate a dst for local (unicast / anycast) address.
+  */
+@@ -4933,7 +4963,8 @@ static int rtm_to_fib6_config(struct sk_
+ 	if (rtm->rtm_type == RTN_UNREACHABLE ||
+ 	    rtm->rtm_type == RTN_BLACKHOLE ||
+ 	    rtm->rtm_type == RTN_PROHIBIT ||
+-	    rtm->rtm_type == RTN_THROW)
++	    rtm->rtm_type == RTN_THROW ||
++	    rtm->rtm_type == RTN_POLICY_FAILED)
+ 		cfg->fc_flags |= RTF_REJECT;
+ 
+ 	if (rtm->rtm_type == RTN_LOCAL)
+@@ -6084,6 +6115,8 @@ static int ip6_route_dev_notify(struct n
+ #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ 		net->ipv6.ip6_prohibit_entry->dst.dev = dev;
+ 		net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
++		net->ipv6.ip6_policy_failed_entry->dst.dev = dev;
++		net->ipv6.ip6_policy_failed_entry->rt6i_idev = in6_dev_get(dev);
+ 		net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
+ 		net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
+ #endif
+@@ -6095,6 +6128,7 @@ static int ip6_route_dev_notify(struct n
+ 		in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev);
+ #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ 		in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev);
++		in6_dev_put_clear(&net->ipv6.ip6_policy_failed_entry->rt6i_idev);
+ 		in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev);
+ #endif
+ 	}
+@@ -6287,6 +6321,8 @@ static int __net_init ip6_route_net_init
+ 
+ #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ 	net->ipv6.fib6_has_custom_rules = false;
++
++
+ 	net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
+ 					       sizeof(*net->ipv6.ip6_prohibit_entry),
+ 					       GFP_KERNEL);
+@@ -6297,11 +6333,21 @@ static int __net_init ip6_route_net_init
+ 			 ip6_template_metrics, true);
+ 	INIT_LIST_HEAD(&net->ipv6.ip6_prohibit_entry->rt6i_uncached);
+ 
++	net->ipv6.ip6_policy_failed_entry =
++				kmemdup(&ip6_policy_failed_entry_template,
++				sizeof(*net->ipv6.ip6_policy_failed_entry), GFP_KERNEL);
++	if (!net->ipv6.ip6_policy_failed_entry)
++		goto out_ip6_prohibit_entry;
++	net->ipv6.ip6_policy_failed_entry->dst.ops = &net->ipv6.ip6_dst_ops;
++	dst_init_metrics(&net->ipv6.ip6_policy_failed_entry->dst,
++			 ip6_template_metrics, true);
++	INIT_LIST_HEAD(&net->ipv6.ip6_policy_failed_entry->rt6i_uncached);
++
+ 	net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
+ 					       sizeof(*net->ipv6.ip6_blk_hole_entry),
+ 					       GFP_KERNEL);
+ 	if (!net->ipv6.ip6_blk_hole_entry)
+-		goto out_ip6_prohibit_entry;
++		goto out_ip6_policy_failed_entry;
+ 	net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
+ 	dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
+ 			 ip6_template_metrics, true);
+@@ -6325,6 +6371,8 @@ out:
+ 	return ret;
+ 
+ #ifdef CONFIG_IPV6_MULTIPLE_TABLES
++out_ip6_policy_failed_entry:
++	kfree(net->ipv6.ip6_policy_failed_entry);
+ out_ip6_prohibit_entry:
+ 	kfree(net->ipv6.ip6_prohibit_entry);
+ out_ip6_null_entry:
+@@ -6344,6 +6392,7 @@ static void __net_exit ip6_route_net_exi
+ 	kfree(net->ipv6.ip6_null_entry);
+ #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ 	kfree(net->ipv6.ip6_prohibit_entry);
++	kfree(net->ipv6.ip6_policy_failed_entry);
+ 	kfree(net->ipv6.ip6_blk_hole_entry);
+ #endif
+ 	dst_entries_destroy(&net->ipv6.ip6_dst_ops);
+@@ -6421,6 +6470,9 @@ void __init ip6_route_init_special_entri
+ 	init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
+ 	init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
+ 	init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
++	init_net.ipv6.ip6_policy_failed_entry->dst.dev = init_net.loopback_dev;
++	init_net.ipv6.ip6_policy_failed_entry->rt6i_idev =
++		in6_dev_get(init_net.loopback_dev);
+   #endif
+ }
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch
new file mode 100644
index 0000000..a92d8ec
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch
@@ -0,0 +1,50 @@
+From: Jonas Gorski <jogo@openwrt.org>
+Subject: net: provide defines for _POLICY_FAILED until all code is updated
+
+Upstream introduced ICMPV6_POLICY_FAIL for code 5 of destination
+unreachable, conflicting with our name.
+
+Add appropriate defines to allow our code to build with the new
+name until we have updated our local patches for older kernels
+and userspace packages.
+
+Signed-off-by: Jonas Gorski <jogo@openwrt.org>
+---
+ include/uapi/linux/fib_rules.h | 2 ++
+ include/uapi/linux/icmpv6.h    | 2 ++
+ include/uapi/linux/rtnetlink.h | 2 ++
+ 3 files changed, 6 insertions(+)
+
+--- a/include/uapi/linux/fib_rules.h
++++ b/include/uapi/linux/fib_rules.h
+@@ -89,6 +89,8 @@ enum {
+ 	__FR_ACT_MAX,
+ };
+ 
++#define FR_ACT_FAILED_POLICY FR_ACT_POLICY_FAILED
++
+ #define FR_ACT_MAX (__FR_ACT_MAX - 1)
+ 
+ #endif
+--- a/include/uapi/linux/icmpv6.h
++++ b/include/uapi/linux/icmpv6.h
+@@ -125,6 +125,8 @@ struct icmp6hdr {
+ #define ICMPV6_POLICY_FAIL		5
+ #define ICMPV6_REJECT_ROUTE		6
+ 
++#define ICMPV6_FAILED_POLICY		ICMPV6_POLICY_FAIL
++
+ /*
+  *	Codes for Time Exceeded
+  */
+--- a/include/uapi/linux/rtnetlink.h
++++ b/include/uapi/linux/rtnetlink.h
+@@ -239,6 +239,8 @@ enum {
+ 	__RTN_MAX
+ };
+ 
++#define RTN_FAILED_POLICY RTN_POLICY_FAILED
++
+ #define RTN_MAX (__RTN_MAX - 1)
+ 
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/680-NET-skip-GRO-for-foreign-MAC-addresses.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/680-NET-skip-GRO-for-foreign-MAC-addresses.patch
new file mode 100644
index 0000000..9795a99
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/680-NET-skip-GRO-for-foreign-MAC-addresses.patch
@@ -0,0 +1,149 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: net: replace GRO optimization patch with a new one that supports VLANs/bridges with different MAC addresses
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ include/linux/netdevice.h |  2 ++
+ include/linux/skbuff.h    |  3 ++-
+ net/core/dev.c            | 48 +++++++++++++++++++++++++++++++++++++++++++++++
+ net/ethernet/eth.c        | 18 +++++++++++++++++-
+ 4 files changed, 69 insertions(+), 2 deletions(-)
+
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -1927,6 +1927,8 @@ struct net_device {
+ 	struct netdev_hw_addr_list	mc;
+ 	struct netdev_hw_addr_list	dev_addrs;
+ 
++	unsigned char		local_addr_mask[MAX_ADDR_LEN];
++
+ #ifdef CONFIG_SYSFS
+ 	struct kset		*queues_kset;
+ #endif
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -824,6 +824,7 @@ struct sk_buff {
+ #ifdef CONFIG_TLS_DEVICE
+ 	__u8			decrypted:1;
+ #endif
++	__u8			gro_skip:1;
+ 
+ #ifdef CONFIG_NET_SCHED
+ 	__u16			tc_index;	/* traffic control index */
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -5541,6 +5541,9 @@ static enum gro_result dev_gro_receive(s
+ 	int same_flow;
+ 	int grow;
+ 
++	if (skb->gro_skip)
++		goto normal;
++
+ 	if (netif_elide_gro(skb->dev))
+ 		goto normal;
+ 
+@@ -7484,6 +7487,48 @@ static void __netdev_adjacent_dev_unlink
+ 					   &upper_dev->adj_list.lower);
+ }
+ 
++static void __netdev_addr_mask(unsigned char *mask, const unsigned char *addr,
++			       struct net_device *dev)
++{
++	int i;
++
++	for (i = 0; i < dev->addr_len; i++)
++		mask[i] |= addr[i] ^ dev->dev_addr[i];
++}
++
++static void __netdev_upper_mask(unsigned char *mask, struct net_device *dev,
++				struct net_device *lower)
++{
++	struct net_device *cur;
++	struct list_head *iter;
++
++	netdev_for_each_upper_dev_rcu(dev, cur, iter) {
++		__netdev_addr_mask(mask, cur->dev_addr, lower);
++		__netdev_upper_mask(mask, cur, lower);
++	}
++}
++
++static void __netdev_update_addr_mask(struct net_device *dev)
++{
++	unsigned char mask[MAX_ADDR_LEN];
++	struct net_device *cur;
++	struct list_head *iter;
++
++	memset(mask, 0, sizeof(mask));
++	__netdev_upper_mask(mask, dev, dev);
++	memcpy(dev->local_addr_mask, mask, dev->addr_len);
++
++	netdev_for_each_lower_dev(dev, cur, iter)
++		__netdev_update_addr_mask(cur);
++}
++
++static void netdev_update_addr_mask(struct net_device *dev)
++{
++	rcu_read_lock();
++	__netdev_update_addr_mask(dev);
++	rcu_read_unlock();
++}
++
+ static int __netdev_upper_dev_link(struct net_device *dev,
+ 				   struct net_device *upper_dev, bool master,
+ 				   void *upper_priv, void *upper_info,
+@@ -7534,6 +7579,7 @@ static int __netdev_upper_dev_link(struc
+ 	if (ret)
+ 		return ret;
+ 
++	netdev_update_addr_mask(dev);
+ 	ret = call_netdevice_notifiers_info(NETDEV_CHANGEUPPER,
+ 					    &changeupper_info.info);
+ 	ret = notifier_to_errno(ret);
+@@ -7627,6 +7673,7 @@ void netdev_upper_dev_unlink(struct net_
+ 
+ 	__netdev_adjacent_dev_unlink_neighbour(dev, upper_dev);
+ 
++	netdev_update_addr_mask(dev);
+ 	call_netdevice_notifiers_info(NETDEV_CHANGEUPPER,
+ 				      &changeupper_info.info);
+ 
+@@ -8357,6 +8404,7 @@ int dev_set_mac_address(struct net_devic
+ 	if (err)
+ 		return err;
+ 	dev->addr_assign_type = NET_ADDR_SET;
++	netdev_update_addr_mask(dev);
+ 	call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
+ 	add_device_randomness(dev->dev_addr, dev->addr_len);
+ 	return 0;
+--- a/net/ethernet/eth.c
++++ b/net/ethernet/eth.c
+@@ -143,6 +143,18 @@ u32 eth_get_headlen(const struct net_dev
+ }
+ EXPORT_SYMBOL(eth_get_headlen);
+ 
++static inline bool
++eth_check_local_mask(const void *addr1, const void *addr2, const void *mask)
++{
++	const u16 *a1 = addr1;
++	const u16 *a2 = addr2;
++	const u16 *m = mask;
++
++	return (((a1[0] ^ a2[0]) & ~m[0]) |
++		((a1[1] ^ a2[1]) & ~m[1]) |
++		((a1[2] ^ a2[2]) & ~m[2]));
++}
++
+ /**
+  * eth_type_trans - determine the packet's protocol ID.
+  * @skb: received socket data
+@@ -174,6 +186,10 @@ __be16 eth_type_trans(struct sk_buff *sk
+ 		} else {
+ 			skb->pkt_type = PACKET_OTHERHOST;
+ 		}
++
++		if (eth_check_local_mask(eth->h_dest, dev->dev_addr,
++					 dev->local_addr_mask))
++			skb->gro_skip = 1;
+ 	}
+ 
+ 	/*
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/681-NET-add-of_get_mac_address_mtd.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/681-NET-add-of_get_mac_address_mtd.patch
new file mode 100644
index 0000000..b02febe
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/681-NET-add-of_get_mac_address_mtd.patch
@@ -0,0 +1,135 @@
+From: John Crispin <blogic@openwrt.org>
+Subject: NET: add mtd-mac-address support to of_get_mac_address()
+
+Many embedded devices have information such as mac addresses stored inside mtd
+devices. This patch allows us to add a property inside a node describing a
+network interface. The new property points at a mtd partition with an offset
+where the mac address can be found.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ drivers/of/of_net.c    |   37 +++++++++++++++++++++++++++++++++++++
+ include/linux/of_net.h |    1 +
+ 2 files changed, 38 insertions(+)
+
+--- a/drivers/of/of_net.c
++++ b/drivers/of/of_net.c
+@@ -11,6 +11,7 @@
+ #include <linux/phy.h>
+ #include <linux/export.h>
+ #include <linux/device.h>
++#include <linux/mtd/mtd.h>
+ 
+ /**
+  * of_get_phy_mode - Get phy mode for given device_node
+@@ -39,7 +40,7 @@ int of_get_phy_mode(struct device_node *
+ }
+ EXPORT_SYMBOL_GPL(of_get_phy_mode);
+ 
+-static const void *of_get_mac_addr(struct device_node *np, const char *name)
++static void *of_get_mac_addr(struct device_node *np, const char *name)
+ {
+ 	struct property *pp = of_find_property(np, name, NULL);
+ 
+@@ -72,6 +73,79 @@ static const void *of_get_mac_addr_nvmem
+ 	return mac;
+ }
+ 
++static const void *of_get_mac_address_mtd(struct device_node *np)
++{
++#ifdef CONFIG_MTD
++	struct device_node *mtd_np = NULL;
++	struct property *prop;
++	size_t retlen;
++	int size, ret;
++	struct mtd_info *mtd;
++	const char *part;
++	const __be32 *list;
++	phandle phandle;
++	u32 mac_inc = 0;
++	u8 mac[ETH_ALEN];
++	void *addr;
++	u32 inc_idx;
++
++	list = of_get_property(np, "mtd-mac-address", &size);
++	if (!list || (size != (2 * sizeof(*list))))
++		return NULL;
++
++	phandle = be32_to_cpup(list++);
++	if (phandle)
++		mtd_np = of_find_node_by_phandle(phandle);
++
++	if (!mtd_np)
++		return NULL;
++
++	part = of_get_property(mtd_np, "label", NULL);
++	if (!part)
++		part = mtd_np->name;
++
++	mtd = get_mtd_device_nm(part);
++	if (IS_ERR(mtd))
++		return NULL;
++
++	ret = mtd_read(mtd, be32_to_cpup(list), 6, &retlen, mac);
++	put_mtd_device(mtd);
++
++	if (of_property_read_u32(np, "mtd-mac-address-increment-byte", &inc_idx))
++		inc_idx = 5;
++	if (inc_idx > 5)
++		return NULL;
++
++	if (!of_property_read_u32(np, "mtd-mac-address-increment", &mac_inc))
++		mac[inc_idx] += mac_inc;
++
++	if (!is_valid_ether_addr(mac))
++		return NULL;
++
++	addr = of_get_mac_addr(np, "mac-address");
++	if (addr) {
++		memcpy(addr, mac, ETH_ALEN);
++		return addr;
++	}
++
++	prop = kzalloc(sizeof(*prop), GFP_KERNEL);
++	if (!prop)
++		return NULL;
++
++	prop->name = "mac-address";
++	prop->length = ETH_ALEN;
++	prop->value = kmemdup(mac, ETH_ALEN, GFP_KERNEL);
++	if (!prop->value || of_add_property(np, prop))
++		goto free;
++
++	return prop->value;
++free:
++	kfree(prop->value);
++	kfree(prop);
++#endif
++	return NULL;
++}
++
+ /**
+  * Search the device tree for the best MAC address to use.  'mac-address' is
+  * checked first, because that is supposed to contain to "most recent" MAC
+@@ -92,12 +166,20 @@ static const void *of_get_mac_addr_nvmem
+  * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
+  * but is all zeros.
+  *
++ *
++ * If a mtd-mac-address property exists, try to fetch the MAC address from the
++ * specified mtd device, and store it as a 'mac-address' property
++ *
+  * Return: Will be a valid pointer on success and ERR_PTR in case of error.
+ */
+ const void *of_get_mac_address(struct device_node *np)
+ {
+ 	const void *addr;
+ 
++	addr = of_get_mac_address_mtd(np);
++	if (addr)
++		return addr;
++
+ 	addr = of_get_mac_addr(np, "mac-address");
+ 	if (addr)
+ 		return addr;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/703-phy-add-detach-callback-to-struct-phy_driver.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/703-phy-add-detach-callback-to-struct-phy_driver.patch
new file mode 100644
index 0000000..b74b04c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/703-phy-add-detach-callback-to-struct-phy_driver.patch
@@ -0,0 +1,38 @@
+From: Gabor Juhos <juhosg@openwrt.org>
+Subject: generic: add detach callback to struct phy_driver
+
+lede-commit: fe61fc2d7d0b3fb348b502f68f98243b3ddf5867
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ drivers/net/phy/phy_device.c | 3 +++
+ include/linux/phy.h          | 6 ++++++
+ 2 files changed, 9 insertions(+)
+
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -1465,6 +1465,9 @@ void phy_detach(struct phy_device *phyde
+ 	struct module *ndev_owner = NULL;
+ 	struct mii_bus *bus;
+ 
++	if (phydev->drv && phydev->drv->detach)
++		phydev->drv->detach(phydev);
++
+ 	if (phydev->sysfs_links) {
+ 		if (dev)
+ 			sysfs_remove_link(&dev->dev.kobj, "phydev");
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -540,6 +540,12 @@ struct phy_driver {
+ 	/* Override default interrupt handling */
+ 	int (*handle_interrupt)(struct phy_device *phydev);
+ 
++	/*
++	 * Called before an ethernet device is detached
++	 * from the PHY.
++	 */
++	void (*detach)(struct phy_device *phydev);
++
+ 	/* Clears up any memory if needed */
+ 	void (*remove)(struct phy_device *phydev);
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/735-net-phy-at803x-fix-at8033-sgmii-mode.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/735-net-phy-at803x-fix-at8033-sgmii-mode.patch
new file mode 100644
index 0000000..7957430
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/735-net-phy-at803x-fix-at8033-sgmii-mode.patch
@@ -0,0 +1,51 @@
+From: Roman Yeryomin <roman@advem.lv>
+Subject: kernel: add at803x fix for sgmii mode
+
+Some (possibly broken) bootloaders incorreclty initialize at8033
+phy. This patch enables sgmii autonegotiation mode.
+
+[john@phrozen.org: felix added this to his upstream queue]
+
+Signed-off-by: Roman Yeryomin <roman@advem.lv>
+---
+ drivers/net/phy/at803x.c | 25 +++++++++++++++++++++++++
+ 1 file changed, 25 insertions(+)
+
+--- a/drivers/net/phy/at803x.c
++++ b/drivers/net/phy/at803x.c
+@@ -46,6 +46,7 @@
+ #define AT803X_LOC_MAC_ADDR_32_47_OFFSET	0x804A
+ #define AT803X_REG_CHIP_CONFIG			0x1f
+ #define AT803X_BT_BX_REG_SEL			0x8000
++#define AT803X_SGMII_ANEG_EN			0x1000
+ 
+ #define AT803X_DEBUG_ADDR			0x1D
+ #define AT803X_DEBUG_DATA			0x1E
+@@ -259,6 +260,27 @@ static int at803x_probe(struct phy_devic
+ static int at803x_config_init(struct phy_device *phydev)
+ {
+ 	int ret;
++	u32 v;
++
++	if (phydev->drv->phy_id == ATH8031_PHY_ID &&
++		phydev->interface == PHY_INTERFACE_MODE_SGMII)
++	{
++		v = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
++		/* select SGMII/fiber page */
++		ret = phy_write(phydev, AT803X_REG_CHIP_CONFIG,
++						v & ~AT803X_BT_BX_REG_SEL);
++		if (ret)
++			return ret;
++		/* enable SGMII autonegotiation */
++		ret = phy_write(phydev, MII_BMCR, AT803X_SGMII_ANEG_EN);
++		if (ret)
++			return ret;
++		/* select copper page */
++		ret = phy_write(phydev, AT803X_REG_CHIP_CONFIG,
++						v | AT803X_BT_BX_REG_SEL);
++		if (ret)
++			return ret;
++	}
+ 
+ 	/* The RX and TX delay default is:
+ 	 *   after HW reset: RX delay enabled and TX delay disabled
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/739-net-avoid-tx-fault-with-Nokia-GPON-module.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/739-net-avoid-tx-fault-with-Nokia-GPON-module.patch
new file mode 100644
index 0000000..6648d10
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/739-net-avoid-tx-fault-with-Nokia-GPON-module.patch
@@ -0,0 +1,108 @@
+From 283b211aa01bdae94dffb3121655dbb20bf237f4 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2019 15:22:05 +0000
+Subject: net: sfp: avoid tx-fault with Nokia GPON module
+
+The Nokia GPON module can hold tx-fault active while it is initialising
+which can take up to 60s. Avoid this causing the module to be declared
+faulty after the SFP MSA defined non-cooled module timeout.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 42 ++++++++++++++++++++++++++++++------------
+ 1 file changed, 30 insertions(+), 12 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -155,10 +155,20 @@ static const enum gpiod_flags gpio_flags
+ 	GPIOD_ASIS,
+ };
+ 
+-#define T_WAIT		msecs_to_jiffies(50)
+-#define T_INIT_JIFFIES	msecs_to_jiffies(300)
+-#define T_RESET_US	10
+-#define T_FAULT_RECOVER	msecs_to_jiffies(1000)
++/* t_start_up (SFF-8431) or t_init (SFF-8472) is the time required for a
++ * non-cooled module to initialise its laser safety circuitry. We wait
++ * an initial T_WAIT period before we check the tx fault to give any PHY
++ * on board (for a copper SFP) time to initialise.
++ */
++#define T_WAIT			msecs_to_jiffies(50)
++#define T_START_UP		msecs_to_jiffies(300)
++#define T_START_UP_BAD_GPON	msecs_to_jiffies(60000)
++
++/* t_reset is the time required to assert the TX_DISABLE signal to reset
++ * an indicated TX_FAULT.
++ */
++#define T_RESET_US		10
++#define T_FAULT_RECOVER		msecs_to_jiffies(1000)
+ 
+ /* SFP module presence detection is poor: the three MOD DEF signals are
+  * the same length on the PCB, which means it's possible for MOD DEF 0 to
+@@ -219,6 +229,7 @@ struct sfp {
+ 
+ 	struct sfp_eeprom_id id;
+ 	unsigned int module_power_mW;
++	unsigned int module_t_start_up;
+ 
+ #if IS_ENABLED(CONFIG_HWMON)
+ 	struct sfp_diag diag;
+@@ -1742,6 +1753,12 @@ static int sfp_sm_mod_probe(struct sfp *
+ 	if (ret < 0)
+ 		return ret;
+ 
++	if (!memcmp(id.base.vendor_name, "ALCATELLUCENT   ", 16) &&
++	    !memcmp(id.base.vendor_pn, "3FE46541AA      ", 16))
++		sfp->module_t_start_up = T_START_UP_BAD_GPON;
++	else
++		sfp->module_t_start_up = T_START_UP;
++
+ 	return 0;
+ }
+ 
+@@ -1947,11 +1964,12 @@ static void sfp_sm_main(struct sfp *sfp,
+ 			break;
+ 
+ 		if (sfp->state & SFP_F_TX_FAULT) {
+-			/* Wait t_init before indicating that the link is up,
+-			 * provided the current state indicates no TX_FAULT. If
+-			 * TX_FAULT clears before this time, that's fine too.
++			/* Wait up to t_init (SFF-8472) or t_start_up (SFF-8431)
++			 * from the TX_DISABLE deassertion for the module to
++			 * initialise, which is indicated by TX_FAULT
++			 * deasserting.
+ 			 */
+-			timeout = T_INIT_JIFFIES;
++			timeout = sfp->module_t_start_up;
+ 			if (timeout > T_WAIT)
+ 				timeout -= T_WAIT;
+ 			else
+@@ -1968,8 +1986,8 @@ static void sfp_sm_main(struct sfp *sfp,
+ 
+ 	case SFP_S_INIT:
+ 		if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT) {
+-			/* TX_FAULT is still asserted after t_init, so assume
+-			 * there is a fault.
++			/* TX_FAULT is still asserted after t_init or
++			 * or t_start_up, so assume there is a fault.
+ 			 */
+ 			sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT,
+ 				     sfp->sm_retries == 5);
+@@ -1988,7 +2006,7 @@ static void sfp_sm_main(struct sfp *sfp,
+ 	case SFP_S_INIT_TX_FAULT:
+ 		if (event == SFP_E_TIMEOUT) {
+ 			sfp_module_tx_fault_reset(sfp);
+-			sfp_sm_next(sfp, SFP_S_INIT, T_INIT_JIFFIES);
++			sfp_sm_next(sfp, SFP_S_INIT, sfp->module_t_start_up);
+ 		}
+ 		break;
+ 
+@@ -2012,7 +2030,7 @@ static void sfp_sm_main(struct sfp *sfp,
+ 	case SFP_S_TX_FAULT:
+ 		if (event == SFP_E_TIMEOUT) {
+ 			sfp_module_tx_fault_reset(sfp);
+-			sfp_sm_next(sfp, SFP_S_REINIT, T_INIT_JIFFIES);
++			sfp_sm_next(sfp, SFP_S_REINIT, sfp->module_t_start_up);
+ 		}
+ 		break;
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/740-net-sfp-remove-incomplete-100BASE-FX-and-100BASE-LX-.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/740-net-sfp-remove-incomplete-100BASE-FX-and-100BASE-LX-.patch
new file mode 100644
index 0000000..1abc34e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/740-net-sfp-remove-incomplete-100BASE-FX-and-100BASE-LX-.patch
@@ -0,0 +1,52 @@
+From 29cd215aaf6c2050c43e4de03aee436c16f90b96 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Thu, 21 Nov 2019 17:27:14 +0000
+Subject: [PATCH 643/660] net: sfp: remove incomplete 100BASE-FX and 100BASE-LX
+ support
+
+The 100BASE-FX and 100BASE-LX support assumes a PHY is present; this
+is probably an incorrect assumption. In any case, sfp_parse_support()
+will fail such a module. Let's stop pretending we support these
+modules.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp-bus.c |  4 +---
+ drivers/net/phy/sfp.c     | 13 +------------
+ 2 files changed, 2 insertions(+), 15 deletions(-)
+
+--- a/drivers/net/phy/sfp-bus.c
++++ b/drivers/net/phy/sfp-bus.c
+@@ -342,9 +342,7 @@ phy_interface_t sfp_select_interface(str
+ 	if (phylink_test(link_modes, 2500baseX_Full))
+ 		return PHY_INTERFACE_MODE_2500BASEX;
+ 
+-	if (id->base.e1000_base_t ||
+-	    id->base.e100_base_lx ||
+-	    id->base.e100_base_fx)
++	if (id->base.e1000_base_t)
+ 		return PHY_INTERFACE_MODE_SGMII;
+ 
+ 	if (phylink_test(link_modes, 1000baseX_Full))
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -1505,18 +1505,7 @@ static void sfp_sm_fault(struct sfp *sfp
+ 
+ static void sfp_sm_probe_for_phy(struct sfp *sfp)
+ {
+-	/* Setting the serdes link mode is guesswork: there's no
+-	 * field in the EEPROM which indicates what mode should
+-	 * be used.
+-	 *
+-	 * If it's a gigabit-only fiber module, it probably does
+-	 * not have a PHY, so switch to 802.3z negotiation mode.
+-	 * Otherwise, switch to SGMII mode (which is required to
+-	 * support non-gigabit speeds) and probe for a PHY.
+-	 */
+-	if (sfp->id.base.e1000_base_t ||
+-	    sfp->id.base.e100_base_lx ||
+-	    sfp->id.base.e100_base_fx)
++	if (sfp->id.base.e1000_base_t)
+ 		sfp_sm_probe_phy(sfp);
+ }
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/741-net-sfp-derive-interface-mode-from-ethtool-link-mode.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/741-net-sfp-derive-interface-mode-from-ethtool-link-mode.patch
new file mode 100644
index 0000000..8158c78
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/741-net-sfp-derive-interface-mode-from-ethtool-link-mode.patch
@@ -0,0 +1,89 @@
+From dc45d9e04572b5cd6d32f51cdf9f62b18022e6dd Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Thu, 21 Nov 2019 17:32:59 +0000
+Subject: [PATCH 644/660] net: sfp: derive interface mode from ethtool link
+ modes
+
+We don't need the EEPROM ID to derive the phy interface mode as we can
+derive it merely from the ethtool link modes.  Remove the EEPROM ID
+argument to sfp_select_interface().
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/marvell10g.c |  2 +-
+ drivers/net/phy/phylink.c    |  2 +-
+ drivers/net/phy/sfp-bus.c    | 11 ++++-------
+ include/linux/sfp.h          |  2 --
+ 4 files changed, 6 insertions(+), 11 deletions(-)
+
+--- a/drivers/net/phy/marvell10g.c
++++ b/drivers/net/phy/marvell10g.c
+@@ -214,7 +214,7 @@ static int mv3310_sfp_insert(void *upstr
+ 	phy_interface_t iface;
+ 
+ 	sfp_parse_support(phydev->sfp_bus, id, support);
+-	iface = sfp_select_interface(phydev->sfp_bus, id, support);
++	iface = sfp_select_interface(phydev->sfp_bus, support);
+ 
+ 	if (iface != PHY_INTERFACE_MODE_10GKR) {
+ 		dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n");
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1718,7 +1718,7 @@ static int phylink_sfp_module_insert(voi
+ 
+ 	linkmode_copy(support1, support);
+ 
+-	iface = sfp_select_interface(pl->sfp_bus, id, config.advertising);
++	iface = sfp_select_interface(pl->sfp_bus, config.advertising);
+ 	if (iface == PHY_INTERFACE_MODE_NA) {
+ 		phylink_err(pl,
+ 			    "selection of interface failed, advertisement %*pb\n",
+--- a/drivers/net/phy/sfp-bus.c
++++ b/drivers/net/phy/sfp-bus.c
+@@ -320,16 +320,12 @@ EXPORT_SYMBOL_GPL(sfp_parse_support);
+ /**
+  * sfp_select_interface() - Select appropriate phy_interface_t mode
+  * @bus: a pointer to the &struct sfp_bus structure for the sfp module
+- * @id: a pointer to the module's &struct sfp_eeprom_id
+  * @link_modes: ethtool link modes mask
+  *
+- * Derive the phy_interface_t mode for the information found in the
+- * module's identifying EEPROM and the link modes mask. There is no
+- * standard or defined way to derive this information, so we decide
+- * based upon the link mode mask.
++ * Derive the phy_interface_t mode for the SFP module from the link
++ * modes mask.
+  */
+ phy_interface_t sfp_select_interface(struct sfp_bus *bus,
+-				     const struct sfp_eeprom_id *id,
+ 				     unsigned long *link_modes)
+ {
+ 	if (phylink_test(link_modes, 10000baseCR_Full) ||
+@@ -342,7 +338,8 @@ phy_interface_t sfp_select_interface(str
+ 	if (phylink_test(link_modes, 2500baseX_Full))
+ 		return PHY_INTERFACE_MODE_2500BASEX;
+ 
+-	if (id->base.e1000_base_t)
++	if (phylink_test(link_modes, 1000baseT_Half) ||
++	    phylink_test(link_modes, 1000baseT_Full))
+ 		return PHY_INTERFACE_MODE_SGMII;
+ 
+ 	if (phylink_test(link_modes, 1000baseX_Full))
+--- a/include/linux/sfp.h
++++ b/include/linux/sfp.h
+@@ -504,7 +504,6 @@ int sfp_parse_port(struct sfp_bus *bus,
+ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
+ 		       unsigned long *support);
+ phy_interface_t sfp_select_interface(struct sfp_bus *bus,
+-				     const struct sfp_eeprom_id *id,
+ 				     unsigned long *link_modes);
+ 
+ int sfp_get_module_info(struct sfp_bus *bus, struct ethtool_modinfo *modinfo);
+@@ -532,7 +531,6 @@ static inline void sfp_parse_support(str
+ }
+ 
+ static inline phy_interface_t sfp_select_interface(struct sfp_bus *bus,
+-						   const struct sfp_eeprom_id *id,
+ 						   unsigned long *link_modes)
+ {
+ 	return PHY_INTERFACE_MODE_NA;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/742-net-sfp-add-more-extended-compliance-codes.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/742-net-sfp-add-more-extended-compliance-codes.patch
new file mode 100644
index 0000000..868e145
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/742-net-sfp-add-more-extended-compliance-codes.patch
@@ -0,0 +1,251 @@
+From c66a4e76c8554c84e64b9315314576ac403c6641 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Thu, 26 Sep 2019 15:14:18 +0100
+Subject: [PATCH 645/660] net: sfp: add more extended compliance codes
+
+SFF-8024 is used to define various constants re-used in several SFF
+SFP-related specifications.  Split these constants from the enum, and
+rename them to indicate that they're defined by SFF-8024.
+
+Add and use updated SFF-8024 extended compliance code definitions for
+10GBASE-T, 5GBASE-T and 2.5GBASE-T modules.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp-bus.c | 60 ++++++++++++++++------------
+ drivers/net/phy/sfp.c     |  4 +-
+ include/linux/sfp.h       | 82 ++++++++++++++++++++++++++-------------
+ 3 files changed, 93 insertions(+), 53 deletions(-)
+
+--- a/drivers/net/phy/sfp-bus.c
++++ b/drivers/net/phy/sfp-bus.c
+@@ -124,35 +124,35 @@ int sfp_parse_port(struct sfp_bus *bus,
+ 
+ 	/* port is the physical connector, set this from the connector field. */
+ 	switch (id->base.connector) {
+-	case SFP_CONNECTOR_SC:
+-	case SFP_CONNECTOR_FIBERJACK:
+-	case SFP_CONNECTOR_LC:
+-	case SFP_CONNECTOR_MT_RJ:
+-	case SFP_CONNECTOR_MU:
+-	case SFP_CONNECTOR_OPTICAL_PIGTAIL:
++	case SFF8024_CONNECTOR_SC:
++	case SFF8024_CONNECTOR_FIBERJACK:
++	case SFF8024_CONNECTOR_LC:
++	case SFF8024_CONNECTOR_MT_RJ:
++	case SFF8024_CONNECTOR_MU:
++	case SFF8024_CONNECTOR_OPTICAL_PIGTAIL:
++	case SFF8024_CONNECTOR_MPO_1X12:
++	case SFF8024_CONNECTOR_MPO_2X16:
+ 		port = PORT_FIBRE;
+ 		break;
+ 
+-	case SFP_CONNECTOR_RJ45:
++	case SFF8024_CONNECTOR_RJ45:
+ 		port = PORT_TP;
+ 		break;
+ 
+-	case SFP_CONNECTOR_COPPER_PIGTAIL:
++	case SFF8024_CONNECTOR_COPPER_PIGTAIL:
+ 		port = PORT_DA;
+ 		break;
+ 
+-	case SFP_CONNECTOR_UNSPEC:
++	case SFF8024_CONNECTOR_UNSPEC:
+ 		if (id->base.e1000_base_t) {
+ 			port = PORT_TP;
+ 			break;
+ 		}
+ 		/* fallthrough */
+-	case SFP_CONNECTOR_SG: /* guess */
+-	case SFP_CONNECTOR_MPO_1X12:
+-	case SFP_CONNECTOR_MPO_2X16:
+-	case SFP_CONNECTOR_HSSDC_II:
+-	case SFP_CONNECTOR_NOSEPARATE:
+-	case SFP_CONNECTOR_MXC_2X16:
++	case SFF8024_CONNECTOR_SG: /* guess */
++	case SFF8024_CONNECTOR_HSSDC_II:
++	case SFF8024_CONNECTOR_NOSEPARATE:
++	case SFF8024_CONNECTOR_MXC_2X16:
+ 		port = PORT_OTHER;
+ 		break;
+ 	default:
+@@ -261,22 +261,33 @@ void sfp_parse_support(struct sfp_bus *b
+ 	}
+ 
+ 	switch (id->base.extended_cc) {
+-	case 0x00: /* Unspecified */
++	case SFF8024_ECC_UNSPEC:
+ 		break;
+-	case 0x02: /* 100Gbase-SR4 or 25Gbase-SR */
++	case SFF8024_ECC_100GBASE_SR4_25GBASE_SR:
+ 		phylink_set(modes, 100000baseSR4_Full);
+ 		phylink_set(modes, 25000baseSR_Full);
+ 		break;
+-	case 0x03: /* 100Gbase-LR4 or 25Gbase-LR */
+-	case 0x04: /* 100Gbase-ER4 or 25Gbase-ER */
++	case SFF8024_ECC_100GBASE_LR4_25GBASE_LR:
++	case SFF8024_ECC_100GBASE_ER4_25GBASE_ER:
+ 		phylink_set(modes, 100000baseLR4_ER4_Full);
+ 		break;
+-	case 0x0b: /* 100Gbase-CR4 or 25Gbase-CR CA-L */
+-	case 0x0c: /* 25Gbase-CR CA-S */
+-	case 0x0d: /* 25Gbase-CR CA-N */
++	case SFF8024_ECC_100GBASE_CR4:
+ 		phylink_set(modes, 100000baseCR4_Full);
++		/* fallthrough */
++	case SFF8024_ECC_25GBASE_CR_S:
++	case SFF8024_ECC_25GBASE_CR_N:
+ 		phylink_set(modes, 25000baseCR_Full);
+ 		break;
++	case SFF8024_ECC_10GBASE_T_SFI:
++	case SFF8024_ECC_10GBASE_T_SR:
++		phylink_set(modes, 10000baseT_Full);
++		break;
++	case SFF8024_ECC_5GBASE_T:
++		phylink_set(modes, 5000baseT_Full);
++		break;
++	case SFF8024_ECC_2_5GBASE_T:
++		phylink_set(modes, 2500baseT_Full);
++		break;
+ 	default:
+ 		dev_warn(bus->sfp_dev,
+ 			 "Unknown/unsupported extended compliance code: 0x%02x\n",
+@@ -301,7 +312,7 @@ void sfp_parse_support(struct sfp_bus *b
+ 	 */
+ 	if (bitmap_empty(modes, __ETHTOOL_LINK_MODE_MASK_NBITS)) {
+ 		/* If the encoding and bit rate allows 1000baseX */
+-		if (id->base.encoding == SFP_ENCODING_8B10B && br_nom &&
++		if (id->base.encoding == SFF8024_ENCODING_8B10B && br_nom &&
+ 		    br_min <= 1300 && br_max >= 1200)
+ 			phylink_set(modes, 1000baseX_Full);
+ 	}
+@@ -332,7 +343,8 @@ phy_interface_t sfp_select_interface(str
+ 	    phylink_test(link_modes, 10000baseSR_Full) ||
+ 	    phylink_test(link_modes, 10000baseLR_Full) ||
+ 	    phylink_test(link_modes, 10000baseLRM_Full) ||
+-	    phylink_test(link_modes, 10000baseER_Full))
++	    phylink_test(link_modes, 10000baseER_Full) ||
++	    phylink_test(link_modes, 10000baseT_Full))
+ 		return PHY_INTERFACE_MODE_10GKR;
+ 
+ 	if (phylink_test(link_modes, 2500baseX_Full))
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -243,7 +243,7 @@ struct sfp {
+ 
+ static bool sff_module_supported(const struct sfp_eeprom_id *id)
+ {
+-	return id->base.phys_id == SFP_PHYS_ID_SFF &&
++	return id->base.phys_id == SFF8024_ID_SFF_8472 &&
+ 	       id->base.phys_ext_id == SFP_PHYS_EXT_ID_SFP;
+ }
+ 
+@@ -254,7 +254,7 @@ static const struct sff_data sff_data =
+ 
+ static bool sfp_module_supported(const struct sfp_eeprom_id *id)
+ {
+-	return id->base.phys_id == SFP_PHYS_ID_SFP &&
++	return id->base.phys_id == SFF8024_ID_SFP &&
+ 	       id->base.phys_ext_id == SFP_PHYS_EXT_ID_SFP;
+ }
+ 
+--- a/include/linux/sfp.h
++++ b/include/linux/sfp.h
+@@ -275,6 +275,61 @@ struct sfp_diag {
+ 	__be16 cal_v_offset;
+ } __packed;
+ 
++/* SFF8024 defined constants */
++enum {
++	SFF8024_ID_UNK			= 0x00,
++	SFF8024_ID_SFF_8472		= 0x02,
++	SFF8024_ID_SFP			= 0x03,
++	SFF8024_ID_DWDM_SFP		= 0x0b,
++	SFF8024_ID_QSFP_8438		= 0x0c,
++	SFF8024_ID_QSFP_8436_8636	= 0x0d,
++	SFF8024_ID_QSFP28_8636		= 0x11,
++
++	SFF8024_ENCODING_UNSPEC		= 0x00,
++	SFF8024_ENCODING_8B10B		= 0x01,
++	SFF8024_ENCODING_4B5B		= 0x02,
++	SFF8024_ENCODING_NRZ		= 0x03,
++	SFF8024_ENCODING_8472_MANCHESTER= 0x04,
++	SFF8024_ENCODING_8472_SONET	= 0x05,
++	SFF8024_ENCODING_8472_64B66B	= 0x06,
++	SFF8024_ENCODING_8436_MANCHESTER= 0x06,
++	SFF8024_ENCODING_8436_SONET	= 0x04,
++	SFF8024_ENCODING_8436_64B66B	= 0x05,
++	SFF8024_ENCODING_256B257B	= 0x07,
++	SFF8024_ENCODING_PAM4		= 0x08,
++
++	SFF8024_CONNECTOR_UNSPEC	= 0x00,
++	/* codes 01-05 not supportable on SFP, but some modules have single SC */
++	SFF8024_CONNECTOR_SC		= 0x01,
++	SFF8024_CONNECTOR_FIBERJACK	= 0x06,
++	SFF8024_CONNECTOR_LC		= 0x07,
++	SFF8024_CONNECTOR_MT_RJ		= 0x08,
++	SFF8024_CONNECTOR_MU		= 0x09,
++	SFF8024_CONNECTOR_SG		= 0x0a,
++	SFF8024_CONNECTOR_OPTICAL_PIGTAIL= 0x0b,
++	SFF8024_CONNECTOR_MPO_1X12	= 0x0c,
++	SFF8024_CONNECTOR_MPO_2X16	= 0x0d,
++	SFF8024_CONNECTOR_HSSDC_II	= 0x20,
++	SFF8024_CONNECTOR_COPPER_PIGTAIL= 0x21,
++	SFF8024_CONNECTOR_RJ45		= 0x22,
++	SFF8024_CONNECTOR_NOSEPARATE	= 0x23,
++	SFF8024_CONNECTOR_MXC_2X16	= 0x24,
++
++	SFF8024_ECC_UNSPEC		= 0x00,
++	SFF8024_ECC_100G_25GAUI_C2M_AOC	= 0x01,
++	SFF8024_ECC_100GBASE_SR4_25GBASE_SR = 0x02,
++	SFF8024_ECC_100GBASE_LR4_25GBASE_LR = 0x03,
++	SFF8024_ECC_100GBASE_ER4_25GBASE_ER = 0x04,
++	SFF8024_ECC_100GBASE_SR10	= 0x05,
++	SFF8024_ECC_100GBASE_CR4	= 0x0b,
++	SFF8024_ECC_25GBASE_CR_S	= 0x0c,
++	SFF8024_ECC_25GBASE_CR_N	= 0x0d,
++	SFF8024_ECC_10GBASE_T_SFI	= 0x16,
++	SFF8024_ECC_10GBASE_T_SR	= 0x1c,
++	SFF8024_ECC_5GBASE_T		= 0x1d,
++	SFF8024_ECC_2_5GBASE_T		= 0x1e,
++};
++
+ /* SFP EEPROM registers */
+ enum {
+ 	SFP_PHYS_ID			= 0x00,
+@@ -309,34 +364,7 @@ enum {
+ 	SFP_SFF8472_COMPLIANCE		= 0x5e,
+ 	SFP_CC_EXT			= 0x5f,
+ 
+-	SFP_PHYS_ID_SFF			= 0x02,
+-	SFP_PHYS_ID_SFP			= 0x03,
+ 	SFP_PHYS_EXT_ID_SFP		= 0x04,
+-	SFP_CONNECTOR_UNSPEC		= 0x00,
+-	/* codes 01-05 not supportable on SFP, but some modules have single SC */
+-	SFP_CONNECTOR_SC		= 0x01,
+-	SFP_CONNECTOR_FIBERJACK		= 0x06,
+-	SFP_CONNECTOR_LC		= 0x07,
+-	SFP_CONNECTOR_MT_RJ		= 0x08,
+-	SFP_CONNECTOR_MU		= 0x09,
+-	SFP_CONNECTOR_SG		= 0x0a,
+-	SFP_CONNECTOR_OPTICAL_PIGTAIL	= 0x0b,
+-	SFP_CONNECTOR_MPO_1X12		= 0x0c,
+-	SFP_CONNECTOR_MPO_2X16		= 0x0d,
+-	SFP_CONNECTOR_HSSDC_II		= 0x20,
+-	SFP_CONNECTOR_COPPER_PIGTAIL	= 0x21,
+-	SFP_CONNECTOR_RJ45		= 0x22,
+-	SFP_CONNECTOR_NOSEPARATE	= 0x23,
+-	SFP_CONNECTOR_MXC_2X16		= 0x24,
+-	SFP_ENCODING_UNSPEC		= 0x00,
+-	SFP_ENCODING_8B10B		= 0x01,
+-	SFP_ENCODING_4B5B		= 0x02,
+-	SFP_ENCODING_NRZ		= 0x03,
+-	SFP_ENCODING_8472_MANCHESTER	= 0x04,
+-	SFP_ENCODING_8472_SONET		= 0x05,
+-	SFP_ENCODING_8472_64B66B	= 0x06,
+-	SFP_ENCODING_256B257B		= 0x07,
+-	SFP_ENCODING_PAM4		= 0x08,
+ 	SFP_OPTIONS_HIGH_POWER_LEVEL	= BIT(13),
+ 	SFP_OPTIONS_PAGING_A2		= BIT(12),
+ 	SFP_OPTIONS_RETIMER		= BIT(11),
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/743-net-sfp-add-module-start-stop-upstream-notifications.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/743-net-sfp-add-module-start-stop-upstream-notifications.patch
new file mode 100644
index 0000000..ba1b5b5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/743-net-sfp-add-module-start-stop-upstream-notifications.patch
@@ -0,0 +1,131 @@
+From f9a5a54b59cb904b37bf7409a43635ab195d0214 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 19 Nov 2019 10:13:25 +0000
+Subject: [PATCH 646/660] net: sfp: add module start/stop upstream
+ notifications
+
+When dealing with some copper modules, we can't positively know the
+module capabilities are until we have probed the PHY. Without the full
+capabilities, we may end up failing a module that we could otherwise
+drive with a restricted set of capabilities.
+
+An example of this would be a module with a NBASE-T PHY plugged into
+a host that supports phy interface modes 2500BASE-X and SGMII. The
+PHY supports 10GBASE-R, 5000BASE-X, 2500BASE-X, SGMII interface modes,
+which means a subset of the capabilities are compatible with the host.
+
+However, reading the module EEPROM leads us to believe that the module
+only supports ethtool link mode 10GBASE-T, which is incompatible with
+the host - and thus results in the module being rejected.
+
+This patch adds an extra notification which are triggered after the
+SFP module's PHY probe, and a corresponding notification just before
+the PHY is removed.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp-bus.c | 21 +++++++++++++++++++++
+ drivers/net/phy/sfp.c     |  8 ++++++++
+ drivers/net/phy/sfp.h     |  2 ++
+ include/linux/sfp.h       |  4 ++++
+ 4 files changed, 35 insertions(+)
+
+--- a/drivers/net/phy/sfp-bus.c
++++ b/drivers/net/phy/sfp-bus.c
+@@ -717,6 +717,27 @@ void sfp_module_remove(struct sfp_bus *b
+ }
+ EXPORT_SYMBOL_GPL(sfp_module_remove);
+ 
++int sfp_module_start(struct sfp_bus *bus)
++{
++	const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
++	int ret = 0;
++
++	if (ops && ops->module_start)
++		ret = ops->module_start(bus->upstream);
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(sfp_module_start);
++
++void sfp_module_stop(struct sfp_bus *bus)
++{
++	const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
++
++	if (ops && ops->module_stop)
++		ops->module_stop(bus->upstream);
++}
++EXPORT_SYMBOL_GPL(sfp_module_stop);
++
+ static void sfp_socket_clear(struct sfp_bus *bus)
+ {
+ 	bus->sfp_dev = NULL;
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -59,6 +59,7 @@ enum {
+ 	SFP_DEV_UP,
+ 
+ 	SFP_S_DOWN = 0,
++	SFP_S_FAIL,
+ 	SFP_S_WAIT,
+ 	SFP_S_INIT,
+ 	SFP_S_INIT_TX_FAULT,
+@@ -122,6 +123,7 @@ static const char *event_to_str(unsigned
+ 
+ static const char * const sm_state_strings[] = {
+ 	[SFP_S_DOWN] = "down",
++	[SFP_S_FAIL] = "fail",
+ 	[SFP_S_WAIT] = "wait",
+ 	[SFP_S_INIT] = "init",
+ 	[SFP_S_INIT_TX_FAULT] = "init_tx_fault",
+@@ -1918,6 +1920,8 @@ static void sfp_sm_main(struct sfp *sfp,
+ 		if (sfp->sm_state == SFP_S_LINK_UP &&
+ 		    sfp->sm_dev_state == SFP_DEV_UP)
+ 			sfp_sm_link_down(sfp);
++		if (sfp->sm_state > SFP_S_INIT)
++			sfp_module_stop(sfp->sfp_bus);
+ 		if (sfp->mod_phy)
+ 			sfp_sm_phy_detach(sfp);
+ 		sfp_module_tx_disable(sfp);
+@@ -1985,6 +1989,10 @@ static void sfp_sm_main(struct sfp *sfp,
+ 			 * clear.  Probe for the PHY and check the LOS state.
+ 			 */
+ 			sfp_sm_probe_for_phy(sfp);
++			if (sfp_module_start(sfp->sfp_bus)) {
++				sfp_sm_next(sfp, SFP_S_FAIL, 0);
++				break;
++			}
+ 			sfp_sm_link_check_los(sfp);
+ 
+ 			/* Reset the fault retry count */
+--- a/drivers/net/phy/sfp.h
++++ b/drivers/net/phy/sfp.h
+@@ -22,6 +22,8 @@ void sfp_link_up(struct sfp_bus *bus);
+ void sfp_link_down(struct sfp_bus *bus);
+ int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id);
+ void sfp_module_remove(struct sfp_bus *bus);
++int sfp_module_start(struct sfp_bus *bus);
++void sfp_module_stop(struct sfp_bus *bus);
+ int sfp_link_configure(struct sfp_bus *bus, const struct sfp_eeprom_id *id);
+ struct sfp_bus *sfp_register_socket(struct device *dev, struct sfp *sfp,
+ 				    const struct sfp_socket_ops *ops);
+--- a/include/linux/sfp.h
++++ b/include/linux/sfp.h
+@@ -507,6 +507,8 @@ struct sfp_bus;
+  * @module_insert: called after a module has been detected to determine
+  *   whether the module is supported for the upstream device.
+  * @module_remove: called after the module has been removed.
++ * @module_start: called after the PHY probe step
++ * @module_stop: called before the PHY is removed
+  * @link_down: called when the link is non-operational for whatever
+  *   reason.
+  * @link_up: called when the link is operational.
+@@ -520,6 +522,8 @@ struct sfp_upstream_ops {
+ 	void (*detach)(void *priv, struct sfp_bus *bus);
+ 	int (*module_insert)(void *priv, const struct sfp_eeprom_id *id);
+ 	void (*module_remove)(void *priv);
++	int (*module_start)(void *priv);
++	void (*module_stop)(void *priv);
+ 	void (*link_down)(void *priv);
+ 	void (*link_up)(void *priv);
+ 	int (*connect_phy)(void *priv, struct phy_device *);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/744-net-sfp-move-phy_start-phy_stop-to-phylink.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/744-net-sfp-move-phy_start-phy_stop-to-phylink.patch
new file mode 100644
index 0000000..98987d5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/744-net-sfp-move-phy_start-phy_stop-to-phylink.patch
@@ -0,0 +1,72 @@
+From e2dc261b872a92a055eb2e86ac136baf9b20f2f2 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Thu, 21 Nov 2019 17:21:33 +0000
+Subject: [PATCH 647/660] net: sfp: move phy_start()/phy_stop() to phylink
+
+Move phy_start() and phy_stop() into the module_start and module_stop
+notifications in phylink, rather than having them in the SFP code.
+This gives phylink responsibility for controlling the PHY, rather
+than having SFP start and stop the PHY state machine.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phylink.c | 22 ++++++++++++++++++++++
+ drivers/net/phy/sfp.c     |  2 --
+ 2 files changed, 22 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1772,6 +1772,26 @@ static int phylink_sfp_module_insert(voi
+ 	return ret;
+ }
+ 
++static int phylink_sfp_module_start(void *upstream)
++{
++	struct phylink *pl = upstream;
++
++	/* If this SFP module has a PHY, start the PHY now. */
++	if (pl->phydev)
++		phy_start(pl->phydev);
++		
++	return 0;
++}
++
++static void phylink_sfp_module_stop(void *upstream)
++{
++	struct phylink *pl = upstream;
++
++	/* If this SFP module has a PHY, stop it. */
++	if (pl->phydev)
++		phy_stop(pl->phydev);
++}
++
+ static void phylink_sfp_link_down(void *upstream)
+ {
+ 	struct phylink *pl = upstream;
+@@ -1807,6 +1827,8 @@ static const struct sfp_upstream_ops sfp
+ 	.attach = phylink_sfp_attach,
+ 	.detach = phylink_sfp_detach,
+ 	.module_insert = phylink_sfp_module_insert,
++	.module_start = phylink_sfp_module_start,
++	.module_stop = phylink_sfp_module_stop,
+ 	.link_up = phylink_sfp_link_up,
+ 	.link_down = phylink_sfp_link_down,
+ 	.connect_phy = phylink_sfp_connect_phy,
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -1412,7 +1412,6 @@ static void sfp_sm_mod_next(struct sfp *
+ 
+ static void sfp_sm_phy_detach(struct sfp *sfp)
+ {
+-	phy_stop(sfp->mod_phy);
+ 	sfp_remove_phy(sfp->sfp_bus);
+ 	phy_device_remove(sfp->mod_phy);
+ 	phy_device_free(sfp->mod_phy);
+@@ -1443,7 +1442,6 @@ static void sfp_sm_probe_phy(struct sfp
+ 	}
+ 
+ 	sfp->mod_phy = phy;
+-	phy_start(phy);
+ }
+ 
+ static void sfp_sm_link_up(struct sfp *sfp)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/745-net-mdio-i2c-add-support-for-Clause-45-accesses.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/745-net-mdio-i2c-add-support-for-Clause-45-accesses.patch
new file mode 100644
index 0000000..761a94b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/745-net-mdio-i2c-add-support-for-Clause-45-accesses.patch
@@ -0,0 +1,74 @@
+From c9de73988a35c6c85810a992954ac568cca503e5 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Wed, 2 Oct 2019 10:31:10 +0100
+Subject: [PATCH 648/660] net: mdio-i2c: add support for Clause 45 accesses
+
+Some SFP+ modules have PHYs on them just like SFP modules do, except
+they are Clause 45 PHYs.  The I2C protocol used to access them is
+modified slightly in order to send the device address and 16-bit
+register index.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/mdio-i2c.c | 28 ++++++++++++++++++++--------
+ 1 file changed, 20 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/phy/mdio-i2c.c
++++ b/drivers/net/phy/mdio-i2c.c
+@@ -33,17 +33,24 @@ static int i2c_mii_read(struct mii_bus *
+ {
+ 	struct i2c_adapter *i2c = bus->priv;
+ 	struct i2c_msg msgs[2];
+-	u8 data[2], dev_addr = reg;
++	u8 addr[3], data[2], *p;
+ 	int bus_addr, ret;
+ 
+ 	if (!i2c_mii_valid_phy_id(phy_id))
+ 		return 0xffff;
+ 
++	p = addr;
++	if (reg & MII_ADDR_C45) {
++		*p++ = 0x20 | ((reg >> 16) & 31);
++		*p++ = reg >> 8;
++	}
++	*p++ = reg;
++
+ 	bus_addr = i2c_mii_phy_addr(phy_id);
+ 	msgs[0].addr = bus_addr;
+ 	msgs[0].flags = 0;
+-	msgs[0].len = 1;
+-	msgs[0].buf = &dev_addr;
++	msgs[0].len = p - addr;
++	msgs[0].buf = addr;
+ 	msgs[1].addr = bus_addr;
+ 	msgs[1].flags = I2C_M_RD;
+ 	msgs[1].len = sizeof(data);
+@@ -61,18 +68,23 @@ static int i2c_mii_write(struct mii_bus
+ 	struct i2c_adapter *i2c = bus->priv;
+ 	struct i2c_msg msg;
+ 	int ret;
+-	u8 data[3];
++	u8 data[5], *p;
+ 
+ 	if (!i2c_mii_valid_phy_id(phy_id))
+ 		return 0;
+ 
+-	data[0] = reg;
+-	data[1] = val >> 8;
+-	data[2] = val;
++	p = data;
++	if (reg & MII_ADDR_C45) {
++		*p++ = (reg >> 16) & 31;
++		*p++ = reg >> 8;
++	}
++	*p++ = reg;
++	*p++ = val >> 8;
++	*p++ = val;
+ 
+ 	msg.addr = i2c_mii_phy_addr(phy_id);
+ 	msg.flags = 0;
+-	msg.len = 3;
++	msg.len = p - data;
+ 	msg.buf = data;
+ 
+ 	ret = i2c_transfer(i2c, &msg, 1);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/746-net-phylink-re-split-__phylink_connect_phy.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/746-net-phylink-re-split-__phylink_connect_phy.patch
new file mode 100644
index 0000000..d547a18
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/746-net-phylink-re-split-__phylink_connect_phy.patch
@@ -0,0 +1,93 @@
+From 0db7fba746b5608c30d4e2ba1c99a2a309e2d288 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 8 Nov 2019 15:22:48 +0000
+Subject: [PATCH 649/660] net: phylink: re-split __phylink_connect_phy()
+
+In order to support Clause 45 PHYs on SFP+ modules, which have an
+indeterminant phy interface mode, we need to be able to call
+phylink_bringup_phy() with a different interface mode to that used when
+binding the PHY. Reduce __phylink_connect_phy() to an attach operation,
+and move the call to phylink_bringup_phy() to its call sites.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phylink.c | 39 ++++++++++++++++++++++++---------------
+ 1 file changed, 24 insertions(+), 15 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -765,11 +765,9 @@ static int phylink_bringup_phy(struct ph
+ 	return 0;
+ }
+ 
+-static int __phylink_connect_phy(struct phylink *pl, struct phy_device *phy,
+-		phy_interface_t interface)
++static int phylink_attach_phy(struct phylink *pl, struct phy_device *phy,
++			      phy_interface_t interface)
+ {
+-	int ret;
+-
+ 	if (WARN_ON(pl->link_an_mode == MLO_AN_FIXED ||
+ 		    (pl->link_an_mode == MLO_AN_INBAND &&
+ 		     phy_interface_mode_is_8023z(interface))))
+@@ -778,15 +776,7 @@ static int __phylink_connect_phy(struct
+ 	if (pl->phydev)
+ 		return -EBUSY;
+ 
+-	ret = phy_attach_direct(pl->netdev, phy, 0, interface);
+-	if (ret)
+-		return ret;
+-
+-	ret = phylink_bringup_phy(pl, phy);
+-	if (ret)
+-		phy_detach(phy);
+-
+-	return ret;
++	return phy_attach_direct(pl->netdev, phy, 0, interface);
+ }
+ 
+ /**
+@@ -806,13 +796,23 @@ static int __phylink_connect_phy(struct
+  */
+ int phylink_connect_phy(struct phylink *pl, struct phy_device *phy)
+ {
++	int ret;
++
+ 	/* Use PHY device/driver interface */
+ 	if (pl->link_interface == PHY_INTERFACE_MODE_NA) {
+ 		pl->link_interface = phy->interface;
+ 		pl->link_config.interface = pl->link_interface;
+ 	}
+ 
+-	return __phylink_connect_phy(pl, phy, pl->link_interface);
++	ret = phylink_attach_phy(pl, phy, pl->link_interface);
++	if (ret < 0)
++		return ret;
++
++	ret = phylink_bringup_phy(pl, phy);
++	if (ret)
++		phy_detach(phy);
++
++	return ret;
+ }
+ EXPORT_SYMBOL_GPL(phylink_connect_phy);
+ 
+@@ -1814,8 +1814,17 @@ static void phylink_sfp_link_up(void *up
+ static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
+ {
+ 	struct phylink *pl = upstream;
++	int ret;
+ 
+-	return __phylink_connect_phy(upstream, phy, pl->link_config.interface);
++	ret = phylink_attach_phy(pl, phy, pl->link_config.interface);
++	if (ret < 0)
++		return ret;
++
++	ret = phylink_bringup_phy(pl, phy);
++	if (ret)
++		phy_detach(phy);
++
++	return ret;
+ }
+ 
+ static void phylink_sfp_disconnect_phy(void *upstream)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/747-net-phylink-support-Clause-45-PHYs-on-SFP-modules.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/747-net-phylink-support-Clause-45-PHYs-on-SFP-modules.patch
new file mode 100644
index 0000000..673de10
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/747-net-phylink-support-Clause-45-PHYs-on-SFP-modules.patch
@@ -0,0 +1,89 @@
+From caf32f96f13df7d3ae6cb8bf8001c88ae22025ca Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 8 Nov 2019 15:28:22 +0000
+Subject: [PATCH 650/660] net: phylink: support Clause 45 PHYs on SFP+ modules
+
+Some SFP+ modules have Clause 45 PHYs embedded on them, which need a
+little more handling in order to ensure that they are correctly setup,
+as they switch the PHY link mode according to the negotiated speed.
+
+With Clause 22 PHYs, we assumed that they would operate in SGMII mode,
+but this assumption is now false.  Adapt phylink to support Clause 45
+PHYs on SFP+ modules.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phylink.c | 21 ++++++++++++++++-----
+ 1 file changed, 16 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -712,7 +712,8 @@ static void phylink_phy_change(struct ph
+ 		    phy_duplex_to_str(phydev->duplex));
+ }
+ 
+-static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy)
++static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
++			       phy_interface_t interface)
+ {
+ 	struct phylink_link_state config;
+ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
+@@ -730,7 +731,7 @@ static int phylink_bringup_phy(struct ph
+ 	memset(&config, 0, sizeof(config));
+ 	linkmode_copy(supported, phy->supported);
+ 	linkmode_copy(config.advertising, phy->advertising);
+-	config.interface = pl->link_config.interface;
++	config.interface = interface;
+ 
+ 	ret = phylink_validate(pl, supported, &config);
+ 	if (ret)
+@@ -746,6 +747,7 @@ static int phylink_bringup_phy(struct ph
+ 	mutex_lock(&phy->lock);
+ 	mutex_lock(&pl->state_mutex);
+ 	pl->phydev = phy;
++	pl->phy_state.interface = interface;
+ 	linkmode_copy(pl->supported, supported);
+ 	linkmode_copy(pl->link_config.advertising, config.advertising);
+ 
+@@ -808,7 +810,7 @@ int phylink_connect_phy(struct phylink *
+ 	if (ret < 0)
+ 		return ret;
+ 
+-	ret = phylink_bringup_phy(pl, phy);
++	ret = phylink_bringup_phy(pl, phy, pl->link_config.interface);
+ 	if (ret)
+ 		phy_detach(phy);
+ 
+@@ -861,7 +863,7 @@ int phylink_of_phy_connect(struct phylin
+ 	if (!phy_dev)
+ 		return -ENODEV;
+ 
+-	ret = phylink_bringup_phy(pl, phy_dev);
++	ret = phylink_bringup_phy(pl, phy_dev, pl->link_config.interface);
+ 	if (ret)
+ 		phy_detach(phy_dev);
+ 
+@@ -1814,13 +1816,22 @@ static void phylink_sfp_link_up(void *up
+ static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
+ {
+ 	struct phylink *pl = upstream;
++	phy_interface_t interface = pl->link_config.interface;
+ 	int ret;
+ 
+ 	ret = phylink_attach_phy(pl, phy, pl->link_config.interface);
+ 	if (ret < 0)
+ 		return ret;
+ 
+-	ret = phylink_bringup_phy(pl, phy);
++	/* Clause 45 PHYs switch their Serdes lane between several different
++	 * modes, normally 10GBASE-R, SGMII. Some use 2500BASE-X for 2.5G
++	 * speeds.  We really need to know which interface modes the PHY and
++	 * MAC supports to properly work out which linkmodes can be supported.
++	 */
++	if (phy->is_c45)
++		interface = PHY_INTERFACE_MODE_NA;
++
++	ret = phylink_bringup_phy(pl, phy, interface);
+ 	if (ret)
+ 		phy_detach(phy);
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/748-net-phylink-split-link_an_mode-configured-and-curren.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/748-net-phylink-split-link_an_mode-configured-and-curren.patch
new file mode 100644
index 0000000..eaf21db
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/748-net-phylink-split-link_an_mode-configured-and-curren.patch
@@ -0,0 +1,257 @@
+From d1339d6956f0255b6ce2412328a98945be8cc3ca Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Sat, 16 Nov 2019 11:30:18 +0000
+Subject: [PATCH 651/660] net: phylink: split link_an_mode configured and
+ current settings
+
+Split link_an_mode between the configured setting and the current
+operating setting.  This is an important distinction to make when we
+need to configure PHY mode for a plugged SFP+ module that does not
+use in-band signalling.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phylink.c | 59 ++++++++++++++++++++-------------------
+ 1 file changed, 31 insertions(+), 28 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -48,7 +48,8 @@ struct phylink {
+ 	unsigned long phylink_disable_state; /* bitmask of disables */
+ 	struct phy_device *phydev;
+ 	phy_interface_t link_interface;	/* PHY_INTERFACE_xxx */
+-	u8 link_an_mode;		/* MLO_AN_xxx */
++	u8 cfg_link_an_mode;		/* MLO_AN_xxx */
++	u8 cur_link_an_mode;
+ 	u8 link_port;			/* The current non-phy ethtool port */
+ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
+ 
+@@ -258,12 +259,12 @@ static int phylink_parse_mode(struct phy
+ 
+ 	dn = fwnode_get_named_child_node(fwnode, "fixed-link");
+ 	if (dn || fwnode_property_present(fwnode, "fixed-link"))
+-		pl->link_an_mode = MLO_AN_FIXED;
++		pl->cfg_link_an_mode = MLO_AN_FIXED;
+ 	fwnode_handle_put(dn);
+ 
+ 	if (fwnode_property_read_string(fwnode, "managed", &managed) == 0 &&
+ 	    strcmp(managed, "in-band-status") == 0) {
+-		if (pl->link_an_mode == MLO_AN_FIXED) {
++		if (pl->cfg_link_an_mode == MLO_AN_FIXED) {
+ 			phylink_err(pl,
+ 				    "can't use both fixed-link and in-band-status\n");
+ 			return -EINVAL;
+@@ -275,7 +276,7 @@ static int phylink_parse_mode(struct phy
+ 		phylink_set(pl->supported, Asym_Pause);
+ 		phylink_set(pl->supported, Pause);
+ 		pl->link_config.an_enabled = true;
+-		pl->link_an_mode = MLO_AN_INBAND;
++		pl->cfg_link_an_mode = MLO_AN_INBAND;
+ 
+ 		switch (pl->link_config.interface) {
+ 		case PHY_INTERFACE_MODE_SGMII:
+@@ -335,14 +336,14 @@ static void phylink_mac_config(struct ph
+ {
+ 	phylink_dbg(pl,
+ 		    "%s: mode=%s/%s/%s/%s adv=%*pb pause=%02x link=%u an=%u\n",
+-		    __func__, phylink_an_mode_str(pl->link_an_mode),
++		    __func__, phylink_an_mode_str(pl->cur_link_an_mode),
+ 		    phy_modes(state->interface),
+ 		    phy_speed_to_str(state->speed),
+ 		    phy_duplex_to_str(state->duplex),
+ 		    __ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising,
+ 		    state->pause, state->link, state->an_enabled);
+ 
+-	pl->ops->mac_config(pl->config, pl->link_an_mode, state);
++	pl->ops->mac_config(pl->config, pl->cur_link_an_mode, state);
+ }
+ 
+ static void phylink_mac_config_up(struct phylink *pl,
+@@ -443,7 +444,7 @@ static void phylink_mac_link_up(struct p
+ 	struct net_device *ndev = pl->netdev;
+ 
+ 	pl->cur_interface = link_state.interface;
+-	pl->ops->mac_link_up(pl->config, pl->link_an_mode,
++	pl->ops->mac_link_up(pl->config, pl->cur_link_an_mode,
+ 			     pl->cur_interface, pl->phydev);
+ 
+ 	if (ndev)
+@@ -462,7 +463,7 @@ static void phylink_mac_link_down(struct
+ 
+ 	if (ndev)
+ 		netif_carrier_off(ndev);
+-	pl->ops->mac_link_down(pl->config, pl->link_an_mode,
++	pl->ops->mac_link_down(pl->config, pl->cur_link_an_mode,
+ 			       pl->cur_interface);
+ 	phylink_info(pl, "Link is Down\n");
+ }
+@@ -481,7 +482,7 @@ static void phylink_resolve(struct work_
+ 	} else if (pl->mac_link_dropped) {
+ 		link_state.link = false;
+ 	} else {
+-		switch (pl->link_an_mode) {
++		switch (pl->cur_link_an_mode) {
+ 		case MLO_AN_PHY:
+ 			link_state = pl->phy_state;
+ 			phylink_resolve_flow(pl, &link_state);
+@@ -649,7 +650,7 @@ struct phylink *phylink_create(struct ph
+ 		return ERR_PTR(ret);
+ 	}
+ 
+-	if (pl->link_an_mode == MLO_AN_FIXED) {
++	if (pl->cfg_link_an_mode == MLO_AN_FIXED) {
+ 		ret = phylink_parse_fixedlink(pl, fwnode);
+ 		if (ret < 0) {
+ 			kfree(pl);
+@@ -657,6 +658,8 @@ struct phylink *phylink_create(struct ph
+ 		}
+ 	}
+ 
++	pl->cur_link_an_mode = pl->cfg_link_an_mode;
++
+ 	ret = phylink_register_sfp(pl, fwnode);
+ 	if (ret < 0) {
+ 		kfree(pl);
+@@ -770,8 +773,8 @@ static int phylink_bringup_phy(struct ph
+ static int phylink_attach_phy(struct phylink *pl, struct phy_device *phy,
+ 			      phy_interface_t interface)
+ {
+-	if (WARN_ON(pl->link_an_mode == MLO_AN_FIXED ||
+-		    (pl->link_an_mode == MLO_AN_INBAND &&
++	if (WARN_ON(pl->cfg_link_an_mode == MLO_AN_FIXED ||
++		    (pl->cfg_link_an_mode == MLO_AN_INBAND &&
+ 		     phy_interface_mode_is_8023z(interface))))
+ 		return -EINVAL;
+ 
+@@ -838,8 +841,8 @@ int phylink_of_phy_connect(struct phylin
+ 	int ret;
+ 
+ 	/* Fixed links and 802.3z are handled without needing a PHY */
+-	if (pl->link_an_mode == MLO_AN_FIXED ||
+-	    (pl->link_an_mode == MLO_AN_INBAND &&
++	if (pl->cfg_link_an_mode == MLO_AN_FIXED ||
++	    (pl->cfg_link_an_mode == MLO_AN_INBAND &&
+ 	     phy_interface_mode_is_8023z(pl->link_interface)))
+ 		return 0;
+ 
+@@ -850,7 +853,7 @@ int phylink_of_phy_connect(struct phylin
+ 		phy_node = of_parse_phandle(dn, "phy-device", 0);
+ 
+ 	if (!phy_node) {
+-		if (pl->link_an_mode == MLO_AN_PHY)
++		if (pl->cfg_link_an_mode == MLO_AN_PHY)
+ 			return -ENODEV;
+ 		return 0;
+ 	}
+@@ -913,7 +916,7 @@ int phylink_fixed_state_cb(struct phylin
+ 	/* It does not make sense to let the link be overriden unless we use
+ 	 * MLO_AN_FIXED
+ 	 */
+-	if (pl->link_an_mode != MLO_AN_FIXED)
++	if (pl->cfg_link_an_mode != MLO_AN_FIXED)
+ 		return -EINVAL;
+ 
+ 	mutex_lock(&pl->state_mutex);
+@@ -963,7 +966,7 @@ void phylink_start(struct phylink *pl)
+ 	ASSERT_RTNL();
+ 
+ 	phylink_info(pl, "configuring for %s/%s link mode\n",
+-		     phylink_an_mode_str(pl->link_an_mode),
++		     phylink_an_mode_str(pl->cur_link_an_mode),
+ 		     phy_modes(pl->link_config.interface));
+ 
+ 	/* Always set the carrier off */
+@@ -986,7 +989,7 @@ void phylink_start(struct phylink *pl)
+ 	clear_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
+ 	phylink_run_resolve(pl);
+ 
+-	if (pl->link_an_mode == MLO_AN_FIXED && pl->link_gpio) {
++	if (pl->cfg_link_an_mode == MLO_AN_FIXED && pl->link_gpio) {
+ 		int irq = gpiod_to_irq(pl->link_gpio);
+ 
+ 		if (irq > 0) {
+@@ -1001,7 +1004,7 @@ void phylink_start(struct phylink *pl)
+ 		if (irq <= 0)
+ 			mod_timer(&pl->link_poll, jiffies + HZ);
+ 	}
+-	if (pl->link_an_mode == MLO_AN_FIXED && pl->get_fixed_state)
++	if (pl->cfg_link_an_mode == MLO_AN_FIXED && pl->get_fixed_state)
+ 		mod_timer(&pl->link_poll, jiffies + HZ);
+ 	if (pl->phydev)
+ 		phy_start(pl->phydev);
+@@ -1128,7 +1131,7 @@ int phylink_ethtool_ksettings_get(struct
+ 
+ 	linkmode_copy(kset->link_modes.supported, pl->supported);
+ 
+-	switch (pl->link_an_mode) {
++	switch (pl->cur_link_an_mode) {
+ 	case MLO_AN_FIXED:
+ 		/* We are using fixed settings. Report these as the
+ 		 * current link settings - and note that these also
+@@ -1200,7 +1203,7 @@ int phylink_ethtool_ksettings_set(struct
+ 		/* If we have a fixed link (as specified by firmware), refuse
+ 		 * to change link parameters.
+ 		 */
+-		if (pl->link_an_mode == MLO_AN_FIXED &&
++		if (pl->cur_link_an_mode == MLO_AN_FIXED &&
+ 		    (s->speed != pl->link_config.speed ||
+ 		     s->duplex != pl->link_config.duplex))
+ 			return -EINVAL;
+@@ -1212,7 +1215,7 @@ int phylink_ethtool_ksettings_set(struct
+ 		__clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, config.advertising);
+ 	} else {
+ 		/* If we have a fixed link, refuse to enable autonegotiation */
+-		if (pl->link_an_mode == MLO_AN_FIXED)
++		if (pl->cur_link_an_mode == MLO_AN_FIXED)
+ 			return -EINVAL;
+ 
+ 		config.speed = SPEED_UNKNOWN;
+@@ -1254,7 +1257,7 @@ int phylink_ethtool_ksettings_set(struct
+ 	 * configuration. For a fixed link, this isn't able to change any
+ 	 * parameters, which just leaves inband mode.
+ 	 */
+-	if (pl->link_an_mode == MLO_AN_INBAND &&
++	if (pl->cur_link_an_mode == MLO_AN_INBAND &&
+ 	    !test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state)) {
+ 		phylink_mac_config(pl, &pl->link_config);
+ 		phylink_mac_an_restart(pl);
+@@ -1344,7 +1347,7 @@ int phylink_ethtool_set_pauseparam(struc
+ 				   pause->tx_pause);
+ 	} else if (!test_bit(PHYLINK_DISABLE_STOPPED,
+ 			     &pl->phylink_disable_state)) {
+-		switch (pl->link_an_mode) {
++		switch (pl->cur_link_an_mode) {
+ 		case MLO_AN_FIXED:
+ 			/* Should we allow fixed links to change against the config? */
+ 			phylink_resolve_flow(pl, config);
+@@ -1551,7 +1554,7 @@ static int phylink_mii_read(struct phyli
+ 	struct phylink_link_state state;
+ 	int val = 0xffff;
+ 
+-	switch (pl->link_an_mode) {
++	switch (pl->cur_link_an_mode) {
+ 	case MLO_AN_FIXED:
+ 		if (phy_id == 0) {
+ 			phylink_get_fixed_state(pl, &state);
+@@ -1579,7 +1582,7 @@ static int phylink_mii_read(struct phyli
+ static int phylink_mii_write(struct phylink *pl, unsigned int phy_id,
+ 			     unsigned int reg, unsigned int val)
+ {
+-	switch (pl->link_an_mode) {
++	switch (pl->cur_link_an_mode) {
+ 	case MLO_AN_FIXED:
+ 		break;
+ 
+@@ -1753,10 +1756,10 @@ static int phylink_sfp_module_insert(voi
+ 		linkmode_copy(pl->link_config.advertising, config.advertising);
+ 	}
+ 
+-	if (pl->link_an_mode != MLO_AN_INBAND ||
++	if (pl->cur_link_an_mode != MLO_AN_INBAND ||
+ 	    pl->link_config.interface != config.interface) {
+ 		pl->link_config.interface = config.interface;
+-		pl->link_an_mode = MLO_AN_INBAND;
++		pl->cur_link_an_mode = MLO_AN_INBAND;
+ 
+ 		changed = true;
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/749-net-phylink-split-phylink_sfp_module_insert.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/749-net-phylink-split-phylink_sfp_module_insert.patch
new file mode 100644
index 0000000..b840d71
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/749-net-phylink-split-phylink_sfp_module_insert.patch
@@ -0,0 +1,120 @@
+From 36569971241ae6b81376da4937d2c8760122d10b Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Thu, 21 Nov 2019 17:58:58 +0000
+Subject: [PATCH 652/660] net: phylink: split phylink_sfp_module_insert()
+
+Split out the configuration step from phylink_sfp_module_insert() so
+we can re-use this later.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phylink.c | 47 +++++++++++++++++++++++----------------
+ 1 file changed, 28 insertions(+), 19 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1688,25 +1688,21 @@ static void phylink_sfp_detach(void *ups
+ 	pl->netdev->sfp_bus = NULL;
+ }
+ 
+-static int phylink_sfp_module_insert(void *upstream,
+-				     const struct sfp_eeprom_id *id)
++static int phylink_sfp_config(struct phylink *pl, u8 mode, u8 port,
++			      const unsigned long *supported,
++			      const unsigned long *advertising)
+ {
+-	struct phylink *pl = upstream;
+-	__ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
+ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(support1);
++	__ETHTOOL_DECLARE_LINK_MODE_MASK(support);
+ 	struct phylink_link_state config;
+ 	phy_interface_t iface;
+-	int ret = 0;
+ 	bool changed;
+-	u8 port;
++	int ret;
+ 
+-	ASSERT_RTNL();
+-
+-	sfp_parse_support(pl->sfp_bus, id, support);
+-	port = sfp_parse_port(pl->sfp_bus, id, support);
++	linkmode_copy(support, supported);
+ 
+ 	memset(&config, 0, sizeof(config));
+-	linkmode_copy(config.advertising, support);
++	linkmode_copy(config.advertising, advertising);
+ 	config.interface = PHY_INTERFACE_MODE_NA;
+ 	config.speed = SPEED_UNKNOWN;
+ 	config.duplex = DUPLEX_UNKNOWN;
+@@ -1721,8 +1717,6 @@ static int phylink_sfp_module_insert(voi
+ 		return ret;
+ 	}
+ 
+-	linkmode_copy(support1, support);
+-
+ 	iface = sfp_select_interface(pl->sfp_bus, config.advertising);
+ 	if (iface == PHY_INTERFACE_MODE_NA) {
+ 		phylink_err(pl,
+@@ -1732,18 +1726,18 @@ static int phylink_sfp_module_insert(voi
+ 	}
+ 
+ 	config.interface = iface;
++	linkmode_copy(support1, support);
+ 	ret = phylink_validate(pl, support1, &config);
+ 	if (ret) {
+ 		phylink_err(pl, "validation of %s/%s with support %*pb failed: %d\n",
+-			    phylink_an_mode_str(MLO_AN_INBAND),
++			    phylink_an_mode_str(mode),
+ 			    phy_modes(config.interface),
+ 			    __ETHTOOL_LINK_MODE_MASK_NBITS, support, ret);
+ 		return ret;
+ 	}
+ 
+ 	phylink_dbg(pl, "requesting link mode %s/%s with support %*pb\n",
+-		    phylink_an_mode_str(MLO_AN_INBAND),
+-		    phy_modes(config.interface),
++		    phylink_an_mode_str(mode), phy_modes(config.interface),
+ 		    __ETHTOOL_LINK_MODE_MASK_NBITS, support);
+ 
+ 	if (phy_interface_mode_is_8023z(iface) && pl->phydev)
+@@ -1756,15 +1750,15 @@ static int phylink_sfp_module_insert(voi
+ 		linkmode_copy(pl->link_config.advertising, config.advertising);
+ 	}
+ 
+-	if (pl->cur_link_an_mode != MLO_AN_INBAND ||
++	if (pl->cur_link_an_mode != mode ||
+ 	    pl->link_config.interface != config.interface) {
+ 		pl->link_config.interface = config.interface;
+-		pl->cur_link_an_mode = MLO_AN_INBAND;
++		pl->cur_link_an_mode = mode;
+ 
+ 		changed = true;
+ 
+ 		phylink_info(pl, "switched to %s/%s link mode\n",
+-			     phylink_an_mode_str(MLO_AN_INBAND),
++			     phylink_an_mode_str(mode),
+ 			     phy_modes(config.interface));
+ 	}
+ 
+@@ -1777,6 +1771,21 @@ static int phylink_sfp_module_insert(voi
+ 	return ret;
+ }
+ 
++static int phylink_sfp_module_insert(void *upstream,
++				     const struct sfp_eeprom_id *id)
++{
++	struct phylink *pl = upstream;
++	__ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
++	u8 port;
++
++	ASSERT_RTNL();
++
++	sfp_parse_support(pl->sfp_bus, id, support);
++	port = sfp_parse_port(pl->sfp_bus, id, support);
++
++	return phylink_sfp_config(pl, MLO_AN_INBAND, port, support, support);
++}
++
+ static int phylink_sfp_module_start(void *upstream)
+ {
+ 	struct phylink *pl = upstream;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/750-net-phylink-delay-MAC-configuration-for-copper-SFP-m.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/750-net-phylink-delay-MAC-configuration-for-copper-SFP-m.patch
new file mode 100644
index 0000000..667170a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/750-net-phylink-delay-MAC-configuration-for-copper-SFP-m.patch
@@ -0,0 +1,201 @@
+From 52c956003a9d5bcae1f445f9dfd42b624adb6e87 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Wed, 11 Dec 2019 10:56:45 +0000
+Subject: [PATCH] net: phylink: delay MAC configuration for copper SFP modules
+
+Knowing whether we need to delay the MAC configuration because a module
+may have a PHY is useful to phylink to allow NBASE-T modules to work on
+systems supporting no more than 2.5G speeds.
+
+This commit allows us to delay such configuration until after the PHY
+has been probed by recording the parsed capabilities, and if the module
+may have a PHY, doing no more until the module_start() notification is
+called.  At that point, we either have a PHY, or we don't.
+
+We move the PHY-based setup a little later, and use the PHYs support
+capabilities rather than the EEPROM parsed capabilities to determine
+whether we can support the PHY.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/phylink.c | 53 +++++++++++++++++++++++++++++++--------
+ drivers/net/phy/sfp-bus.c | 28 +++++++++++++++++++++
+ include/linux/sfp.h       |  7 ++++++
+ 3 files changed, 78 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -72,6 +72,9 @@ struct phylink {
+ 	bool mac_link_dropped;
+ 
+ 	struct sfp_bus *sfp_bus;
++	bool sfp_may_have_phy;
++	__ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support);
++	u8 sfp_port;
+ };
+ 
+ #define phylink_printk(level, pl, fmt, ...) \
+@@ -1688,7 +1691,7 @@ static void phylink_sfp_detach(void *ups
+ 	pl->netdev->sfp_bus = NULL;
+ }
+ 
+-static int phylink_sfp_config(struct phylink *pl, u8 mode, u8 port,
++static int phylink_sfp_config(struct phylink *pl, u8 mode,
+ 			      const unsigned long *supported,
+ 			      const unsigned long *advertising)
+ {
+@@ -1762,7 +1765,7 @@ static int phylink_sfp_config(struct phy
+ 			     phy_modes(config.interface));
+ 	}
+ 
+-	pl->link_port = port;
++	pl->link_port = pl->sfp_port;
+ 
+ 	if (changed && !test_bit(PHYLINK_DISABLE_STOPPED,
+ 				 &pl->phylink_disable_state))
+@@ -1775,15 +1778,20 @@ static int phylink_sfp_module_insert(voi
+ 				     const struct sfp_eeprom_id *id)
+ {
+ 	struct phylink *pl = upstream;
+-	__ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
+-	u8 port;
++	unsigned long *support = pl->sfp_support;
+ 
+ 	ASSERT_RTNL();
+ 
++	linkmode_zero(support);
+ 	sfp_parse_support(pl->sfp_bus, id, support);
+-	port = sfp_parse_port(pl->sfp_bus, id, support);
++	pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, support);
+ 
+-	return phylink_sfp_config(pl, MLO_AN_INBAND, port, support, support);
++	/* If this module may have a PHY connecting later, defer until later */
++	pl->sfp_may_have_phy = sfp_may_have_phy(pl->sfp_bus, id);
++	if (pl->sfp_may_have_phy)
++		return 0;
++
++	return phylink_sfp_config(pl, MLO_AN_INBAND, support, support);
+ }
+ 
+ static int phylink_sfp_module_start(void *upstream)
+@@ -1791,10 +1799,19 @@ static int phylink_sfp_module_start(void
+ 	struct phylink *pl = upstream;
+ 
+ 	/* If this SFP module has a PHY, start the PHY now. */
+-	if (pl->phydev)
++	if (pl->phydev) {
+ 		phy_start(pl->phydev);
+-		
+-	return 0;
++		return 0;
++	}
++
++	/* If the module may have a PHY but we didn't detect one we
++	 * need to configure the MAC here.
++	 */
++	if (!pl->sfp_may_have_phy)
++		return 0;
++
++	return phylink_sfp_config(pl, MLO_AN_INBAND,
++				  pl->sfp_support, pl->sfp_support);
+ }
+ 
+ static void phylink_sfp_module_stop(void *upstream)
+@@ -1828,10 +1845,26 @@ static void phylink_sfp_link_up(void *up
+ static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
+ {
+ 	struct phylink *pl = upstream;
+-	phy_interface_t interface = pl->link_config.interface;
++	phy_interface_t interface;
+ 	int ret;
+ 
+-	ret = phylink_attach_phy(pl, phy, pl->link_config.interface);
++	/*
++	 * This is the new way of dealing with flow control for PHYs,
++	 * as described by Timur Tabi in commit 529ed1275263 ("net: phy:
++	 * phy drivers should not set SUPPORTED_[Asym_]Pause") except
++	 * using our validate call to the MAC, we rely upon the MAC
++	 * clearing the bits from both supported and advertising fields.
++	 */
++	phy_support_asym_pause(phy);
++
++	/* Do the initial configuration */
++	ret = phylink_sfp_config(pl, MLO_AN_INBAND, phy->supported,
++				 phy->advertising);
++	if (ret < 0)
++		return ret;
++
++	interface = pl->link_config.interface;
++	ret = phylink_attach_phy(pl, phy, interface);
+ 	if (ret < 0)
+ 		return ret;
+ 
+--- a/drivers/net/phy/sfp-bus.c
++++ b/drivers/net/phy/sfp-bus.c
+@@ -103,6 +103,7 @@ static const struct sfp_quirk *sfp_looku
+ 
+ 	return NULL;
+ }
++
+ /**
+  * sfp_parse_port() - Parse the EEPROM base ID, setting the port type
+  * @bus: a pointer to the &struct sfp_bus structure for the sfp module
+@@ -179,6 +180,33 @@ int sfp_parse_port(struct sfp_bus *bus,
+ EXPORT_SYMBOL_GPL(sfp_parse_port);
+ 
+ /**
++ * sfp_may_have_phy() - indicate whether the module may have a PHY
++ * @bus: a pointer to the &struct sfp_bus structure for the sfp module
++ * @id: a pointer to the module's &struct sfp_eeprom_id
++ *
++ * Parse the EEPROM identification given in @id, and return whether
++ * this module may have a PHY.
++ */
++bool sfp_may_have_phy(struct sfp_bus *bus, const struct sfp_eeprom_id *id)
++{
++	if (id->base.e1000_base_t)
++		return true;
++
++	if (id->base.phys_id != SFF8024_ID_DWDM_SFP) {
++		switch (id->base.extended_cc) {
++		case SFF8024_ECC_10GBASE_T_SFI:
++		case SFF8024_ECC_10GBASE_T_SR:
++		case SFF8024_ECC_5GBASE_T:
++		case SFF8024_ECC_2_5GBASE_T:
++			return true;
++		}
++	}
++
++	return false;
++}
++EXPORT_SYMBOL_GPL(sfp_may_have_phy);
++
++/**
+  * sfp_parse_support() - Parse the eeprom id for supported link modes
+  * @bus: a pointer to the &struct sfp_bus structure for the sfp module
+  * @id: a pointer to the module's &struct sfp_eeprom_id
+--- a/include/linux/sfp.h
++++ b/include/linux/sfp.h
+@@ -533,6 +533,7 @@ struct sfp_upstream_ops {
+ #if IS_ENABLED(CONFIG_SFP)
+ int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
+ 		   unsigned long *support);
++bool sfp_may_have_phy(struct sfp_bus *bus, const struct sfp_eeprom_id *id);
+ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
+ 		       unsigned long *support);
+ phy_interface_t sfp_select_interface(struct sfp_bus *bus,
+@@ -556,6 +557,12 @@ static inline int sfp_parse_port(struct
+ 	return PORT_OTHER;
+ }
+ 
++static inline bool sfp_may_have_phy(struct sfp_bus *bus,
++				    const struct sfp_eeprom_id *id)
++{
++	return false;
++}
++
+ static inline void sfp_parse_support(struct sfp_bus *bus,
+ 				     const struct sfp_eeprom_id *id,
+ 				     unsigned long *support)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/751-net-phylink-make-Broadcom-BCM84881-based-SFPs-work.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/751-net-phylink-make-Broadcom-BCM84881-based-SFPs-work.patch
new file mode 100644
index 0000000..d583044
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/751-net-phylink-make-Broadcom-BCM84881-based-SFPs-work.patch
@@ -0,0 +1,59 @@
+From 7adb5b2126bc013f0964ddaefad6ad1b132e86c3 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Wed, 11 Dec 2019 10:56:50 +0000
+Subject: [PATCH] net: phylink: make Broadcom BCM84881 based SFPs work
+
+The Broadcom BCM84881 does not appear to send the SGMII control word
+when operating in SGMII mode, which causes network adapters to fail
+to link with the PHY, or decide to operate at fixed 1G speed, even if
+the PHY negotiated 100M.
+
+Work around this by detecting the Broadcom BCM84881 and switch to phy
+mode rather than inband mode.
+
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/phylink.c | 18 ++++++++++++++++--
+ 1 file changed, 16 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1842,10 +1842,20 @@ static void phylink_sfp_link_up(void *up
+ 	phylink_run_resolve(pl);
+ }
+ 
++/* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII
++ * or 802.3z control word, so inband will not work.
++ */
++static bool phylink_phy_no_inband(struct phy_device *phy)
++{
++	return phy->is_c45 &&
++		(phy->c45_ids.device_ids[1] & 0xfffffff0) == 0xae025150;
++}
++
+ static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
+ {
+ 	struct phylink *pl = upstream;
+ 	phy_interface_t interface;
++	u8 mode;
+ 	int ret;
+ 
+ 	/*
+@@ -1857,9 +1867,13 @@ static int phylink_sfp_connect_phy(void
+ 	 */
+ 	phy_support_asym_pause(phy);
+ 
++	if (phylink_phy_no_inband(phy))
++		mode = MLO_AN_PHY;
++	else
++		mode = MLO_AN_INBAND;
++
+ 	/* Do the initial configuration */
+-	ret = phylink_sfp_config(pl, MLO_AN_INBAND, phy->supported,
+-				 phy->advertising);
++	ret = phylink_sfp_config(pl, mode, phy->supported, phy->advertising);
+ 	if (ret < 0)
+ 		return ret;
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/752-net-phy-add-Broadcom-BCM84881-PHY-driver.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/752-net-phy-add-Broadcom-BCM84881-PHY-driver.patch
new file mode 100644
index 0000000..783dec0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/752-net-phy-add-Broadcom-BCM84881-PHY-driver.patch
@@ -0,0 +1,315 @@
+From 75f4d8d10e016f7428c268424483a927ee7a78bb Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Wed, 11 Dec 2019 10:56:56 +0000
+Subject: [PATCH] net: phy: add Broadcom BCM84881 PHY driver
+
+Add a rudimentary Clause 45 driver for the BCM84881 PHY, found on
+Methode DM7052 SFPs.
+
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/Kconfig    |   6 +
+ drivers/net/phy/Makefile   |   1 +
+ drivers/net/phy/bcm84881.c | 269 +++++++++++++++++++++++++++++++++++++
+ 3 files changed, 276 insertions(+)
+ create mode 100644 drivers/net/phy/bcm84881.c
+
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -330,6 +330,12 @@ config BROADCOM_PHY
+ 	  Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S, BCM5464,
+ 	  BCM5481, BCM54810 and BCM5482 PHYs.
+ 
++config BCM84881_PHY
++	tristate "Broadcom BCM84881 PHY"
++	depends on PHYLIB
++	---help---
++	  Support the Broadcom BCM84881 PHY.
++
+ config CICADA_PHY
+ 	tristate "Cicada PHYs"
+ 	---help---
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -62,6 +62,7 @@ obj-$(CONFIG_BCM87XX_PHY)	+= bcm87xx.o
+ obj-$(CONFIG_BCM_CYGNUS_PHY)	+= bcm-cygnus.o
+ obj-$(CONFIG_BCM_NET_PHYLIB)	+= bcm-phy-lib.o
+ obj-$(CONFIG_BROADCOM_PHY)	+= broadcom.o
++obj-$(CONFIG_BCM84881_PHY)	+= bcm84881.o
+ obj-$(CONFIG_CICADA_PHY)	+= cicada.o
+ obj-$(CONFIG_CORTINA_PHY)	+= cortina.o
+ obj-$(CONFIG_DAVICOM_PHY)	+= davicom.o
+--- /dev/null
++++ b/drivers/net/phy/bcm84881.c
+@@ -0,0 +1,269 @@
++// SPDX-License-Identifier: GPL-2.0
++// Broadcom BCM84881 NBASE-T PHY driver, as found on a SFP+ module.
++// Copyright (C) 2019 Russell King, Deep Blue Solutions Ltd.
++//
++// Like the Marvell 88x3310, the Broadcom 84881 changes its host-side
++// interface according to the operating speed between 10GBASE-R,
++// 2500BASE-X and SGMII (but unlike the 88x3310, without the control
++// word).
++//
++// This driver only supports those aspects of the PHY that I'm able to
++// observe and test with the SFP+ module, which is an incomplete subset
++// of what this PHY is able to support. For example, I only assume it
++// supports a single lane Serdes connection, but it may be that the PHY
++// is able to support more than that.
++#include <linux/delay.h>
++#include <linux/module.h>
++#include <linux/phy.h>
++
++enum {
++	MDIO_AN_C22 = 0xffe0,
++};
++
++static int bcm84881_wait_init(struct phy_device *phydev)
++{
++	unsigned int tries = 20;
++	int ret, val;
++
++	do {
++		val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1);
++		if (val < 0) {
++			ret = val;
++			break;
++		}
++		if (!(val & MDIO_CTRL1_RESET)) {
++			ret = 0;
++			break;
++		}
++		if (!--tries) {
++			ret = -ETIMEDOUT;
++			break;
++		}
++		msleep(100);
++	} while (1);
++
++	if (ret)
++		phydev_err(phydev, "%s failed: %d\n", __func__, ret);
++
++	return ret;
++}
++
++static int bcm84881_config_init(struct phy_device *phydev)
++{
++	switch (phydev->interface) {
++	case PHY_INTERFACE_MODE_SGMII:
++	case PHY_INTERFACE_MODE_2500BASEX:
++	case PHY_INTERFACE_MODE_10GKR:
++		break;
++	default:
++		return -ENODEV;
++	}
++	return 0;
++}
++
++static int bcm84881_probe(struct phy_device *phydev)
++{
++	/* This driver requires PMAPMD and AN blocks */
++	const u32 mmd_mask = MDIO_DEVS_PMAPMD | MDIO_DEVS_AN;
++
++	if (!phydev->is_c45 ||
++	    (phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask)
++		return -ENODEV;
++
++	return 0;
++}
++
++static int bcm84881_get_features(struct phy_device *phydev)
++{
++	int ret;
++
++	ret = genphy_c45_pma_read_abilities(phydev);
++	if (ret)
++		return ret;
++
++	/* Although the PHY sets bit 1.11.8, it does not support 10M modes */
++	linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
++			   phydev->supported);
++	linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
++			   phydev->supported);
++
++	return 0;
++}
++
++static int bcm84881_config_aneg(struct phy_device *phydev)
++{
++	bool changed = false;
++	u32 adv;
++	int ret;
++
++	/* Wait for the PHY to finish initialising, otherwise our
++	 * advertisement may be overwritten.
++	 */
++	ret = bcm84881_wait_init(phydev);
++	if (ret)
++		return ret;
++
++	/* We don't support manual MDI control */
++	phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
++
++	/* disabled autoneg doesn't seem to work with this PHY */
++	if (phydev->autoneg == AUTONEG_DISABLE)
++		return -EINVAL;
++
++	ret = genphy_c45_an_config_aneg(phydev);
++	if (ret < 0)
++		return ret;
++	if (ret > 0)
++		changed = true;
++
++	adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
++	ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN,
++				     MDIO_AN_C22 + MII_CTRL1000,
++				     ADVERTISE_1000FULL | ADVERTISE_1000HALF,
++				     adv);
++	if (ret < 0)
++		return ret;
++	if (ret > 0)
++		changed = true;
++
++	return genphy_c45_check_and_restart_aneg(phydev, changed);
++}
++
++static int bcm84881_aneg_done(struct phy_device *phydev)
++{
++	int bmsr, val;
++
++	val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
++	if (val < 0)
++		return val;
++
++	bmsr = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_C22 + MII_BMSR);
++	if (bmsr < 0)
++		return val;
++
++	return !!(val & MDIO_AN_STAT1_COMPLETE) &&
++	       !!(bmsr & BMSR_ANEGCOMPLETE);
++}
++
++static int bcm84881_read_status(struct phy_device *phydev)
++{
++	unsigned int mode;
++	int bmsr, val;
++
++	val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
++	if (val < 0)
++		return val;
++
++	if (val & MDIO_AN_CTRL1_RESTART) {
++		phydev->link = 0;
++		return 0;
++	}
++
++	val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
++	if (val < 0)
++		return val;
++
++	bmsr = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_C22 + MII_BMSR);
++	if (bmsr < 0)
++		return val;
++
++	phydev->autoneg_complete = !!(val & MDIO_AN_STAT1_COMPLETE) &&
++				   !!(bmsr & BMSR_ANEGCOMPLETE);
++	phydev->link = !!(val & MDIO_STAT1_LSTATUS) &&
++		       !!(bmsr & BMSR_LSTATUS);
++	if (phydev->autoneg == AUTONEG_ENABLE && !phydev->autoneg_complete)
++		phydev->link = false;
++
++	if (!phydev->link)
++		return 0;
++
++	linkmode_zero(phydev->lp_advertising);
++	phydev->speed = SPEED_UNKNOWN;
++	phydev->duplex = DUPLEX_UNKNOWN;
++	phydev->pause = 0;
++	phydev->asym_pause = 0;
++	phydev->mdix = 0;
++
++	if (phydev->autoneg_complete) {
++		val = genphy_c45_read_lpa(phydev);
++		if (val < 0)
++			return val;
++
++		val = phy_read_mmd(phydev, MDIO_MMD_AN,
++				   MDIO_AN_C22 + MII_STAT1000);
++		if (val < 0)
++			return val;
++
++		mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val);
++
++		if (phydev->autoneg == AUTONEG_ENABLE)
++			phy_resolve_aneg_linkmode(phydev);
++	}
++
++	if (phydev->autoneg == AUTONEG_DISABLE) {
++		/* disabled autoneg doesn't seem to work, so force the link
++		 * down.
++		 */
++		phydev->link = 0;
++		return 0;
++	}
++
++	/* Set the host link mode - we set the phy interface mode and
++	 * the speed according to this register so that downshift works.
++	 * We leave the duplex setting as per the resolution from the
++	 * above.
++	 */
++	val = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x4011);
++	mode = (val & 0x1e) >> 1;
++	if (mode == 1 || mode == 2)
++		phydev->interface = PHY_INTERFACE_MODE_SGMII;
++	else if (mode == 3)
++		phydev->interface = PHY_INTERFACE_MODE_10GKR;
++	else if (mode == 4)
++		phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
++	switch (mode & 7) {
++	case 1:
++		phydev->speed = SPEED_100;
++		break;
++	case 2:
++		phydev->speed = SPEED_1000;
++		break;
++	case 3:
++		phydev->speed = SPEED_10000;
++		break;
++	case 4:
++		phydev->speed = SPEED_2500;
++		break;
++	case 5:
++		phydev->speed = SPEED_5000;
++		break;
++	}
++
++	return genphy_c45_read_mdix(phydev);
++}
++
++static struct phy_driver bcm84881_drivers[] = {
++	{
++		.phy_id		= 0xae025150,
++		.phy_id_mask	= 0xfffffff0,
++		.name		= "Broadcom BCM84881",
++		.config_init	= bcm84881_config_init,
++		.probe		= bcm84881_probe,
++		.get_features	= bcm84881_get_features,
++		.config_aneg	= bcm84881_config_aneg,
++		.aneg_done	= bcm84881_aneg_done,
++		.read_status	= bcm84881_read_status,
++	},
++};
++
++module_phy_driver(bcm84881_drivers);
++
++/* FIXME: module auto-loading for Clause 45 PHYs seems non-functional */
++static struct mdio_device_id __maybe_unused bcm84881_tbl[] = {
++	{ 0xae025150, 0xfffffff0 },
++	{ },
++};
++MODULE_AUTHOR("Russell King");
++MODULE_DESCRIPTION("Broadcom BCM84881 PHY driver");
++MODULE_DEVICE_TABLE(mdio, bcm84881_tbl);
++MODULE_LICENSE("GPL");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/753-net-sfp-add-support-for-Clause-45-PHYs.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/753-net-sfp-add-support-for-Clause-45-PHYs.patch
new file mode 100644
index 0000000..dcd1ba7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/753-net-sfp-add-support-for-Clause-45-PHYs.patch
@@ -0,0 +1,94 @@
+From 6df6709dc3d00e0bc948d45dfa8d8f18ba379c48 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 5 Nov 2019 11:56:18 +0000
+Subject: [PATCH 656/660] net: sfp: add support for Clause 45 PHYs
+
+Some SFP+ modules have a Clause 45 PHY onboard, which is accessible via
+the normal I2C address.  Detect 10G BASE-T PHYs which may have an
+accessible PHY and probe for it.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 44 +++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 40 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -1418,12 +1418,12 @@ static void sfp_sm_phy_detach(struct sfp
+ 	sfp->mod_phy = NULL;
+ }
+ 
+-static void sfp_sm_probe_phy(struct sfp *sfp)
++static void sfp_sm_probe_phy(struct sfp *sfp, bool is_c45)
+ {
+ 	struct phy_device *phy;
+ 	int err;
+ 
+-	phy = mdiobus_scan(sfp->i2c_mii, SFP_PHY_ADDR);
++	phy = get_phy_device(sfp->i2c_mii, SFP_PHY_ADDR, is_c45);
+ 	if (phy == ERR_PTR(-ENODEV)) {
+ 		dev_info(sfp->dev, "no PHY detected\n");
+ 		return;
+@@ -1433,6 +1433,13 @@ static void sfp_sm_probe_phy(struct sfp
+ 		return;
+ 	}
+ 
++	err = phy_device_register(phy);
++	if (err) {
++		phy_device_free(phy);
++		dev_err(sfp->dev, "phy_device_register failed: %d\n", err);
++		return;
++	}
++
+ 	err = sfp_add_phy(sfp->sfp_bus, phy);
+ 	if (err) {
+ 		phy_device_remove(phy);
+@@ -1503,10 +1510,32 @@ static void sfp_sm_fault(struct sfp *sfp
+ 	}
+ }
+ 
++/* Probe a SFP for a PHY device if the module supports copper - the PHY
++ * normally sits at I2C bus address 0x56, and may either be a clause 22
++ * or clause 45 PHY.
++ *
++ * Clause 22 copper SFP modules normally operate in Cisco SGMII mode with
++ * negotiation enabled, but some may be in 1000base-X - which is for the
++ * PHY driver to determine.
++ *
++ * Clause 45 copper SFP+ modules (10G) appear to switch their interface
++ * mode according to the negotiated line speed.
++ */
+ static void sfp_sm_probe_for_phy(struct sfp *sfp)
+ {
+-	if (sfp->id.base.e1000_base_t)
+-		sfp_sm_probe_phy(sfp);
++	switch (sfp->id.base.extended_cc) {
++	case SFF8024_ECC_10GBASE_T_SFI:
++	case SFF8024_ECC_10GBASE_T_SR:
++	case SFF8024_ECC_5GBASE_T:
++	case SFF8024_ECC_2_5GBASE_T:
++		sfp_sm_probe_phy(sfp, true);
++		break;
++
++	default:
++		if (sfp->id.base.e1000_base_t)
++			sfp_sm_probe_phy(sfp, false);
++		break;
++	}
+ }
+ 
+ static int sfp_module_parse_power(struct sfp *sfp)
+@@ -1566,6 +1595,13 @@ static int sfp_sm_mod_hpower(struct sfp
+ 		return -EAGAIN;
+ 	}
+ 
++	/* DM7052 reports as a high power module, responds to reads (with
++	 * all bytes 0xff) at 0x51 but does not accept writes.  In any case,
++	 * if the bit is already set, we're already in high power mode.
++	 */
++	if (!!(val & BIT(0)) == enable)
++		return 0;
++
+ 	if (enable)
+ 		val |= BIT(0);
+ 	else
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/754-net-sfp-fix-unbind.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/754-net-sfp-fix-unbind.patch
new file mode 100644
index 0000000..c31922e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/754-net-sfp-fix-unbind.patch
@@ -0,0 +1,28 @@
+From 729fd05aac22cdf1e502fbf1bf80e5ebba0d9fbc Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2019 17:48:28 +0000
+Subject: [PATCH] net: sfp: fix unbind
+
+When unbinding, we don't correctly tear down the module state, leaving
+(for example) the hwmon registration behind. Ensure everything is
+properly removed by sending a remove event at unbind.
+
+Fixes: 6b0da5c9c1a3 ("net: sfp: track upstream's attachment state in state machine")
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -2431,6 +2431,10 @@ static int sfp_remove(struct platform_de
+ 
+ 	sfp_unregister_socket(sfp->sfp_bus);
+ 
++	rtnl_lock();
++	sfp_sm_event(sfp, SFP_E_REMOVE);
++	rtnl_unlock();
++
+ 	return 0;
+ }
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/755-net-sfp-fix-hwmon.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/755-net-sfp-fix-hwmon.patch
new file mode 100644
index 0000000..a18e480
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/755-net-sfp-fix-hwmon.patch
@@ -0,0 +1,44 @@
+From 5eb0df5023c6ae8a71a7848fd5e1f788d86e51ae Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 3 Dec 2019 18:46:04 +0000
+Subject: [PATCH] net: sfp: fix hwmon
+
+The referenced commit below allowed more than one hwmon device to be
+created per SFP, which is definitely not what we want. Avoid this by
+only creating the hwmon device just as we transition to WAITDEV state.
+
+Fixes: 139d3a212a1f ("net: sfp: allow modules with slow diagnostics to probe")
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 13 ++++---------
+ 1 file changed, 4 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -1883,6 +1883,10 @@ static void sfp_sm_module(struct sfp *sf
+ 			break;
+ 		}
+ 
++		err = sfp_hwmon_insert(sfp);
++		if (err)
++			dev_warn(sfp->dev, "hwmon probe failed: %d\n", err);
++
+ 		sfp_sm_mod_next(sfp, SFP_MOD_WAITDEV, 0);
+ 		/* fall through */
+ 	case SFP_MOD_WAITDEV:
+@@ -1932,15 +1936,6 @@ static void sfp_sm_module(struct sfp *sf
+ 	case SFP_MOD_ERROR:
+ 		break;
+ 	}
+-
+-#if IS_ENABLED(CONFIG_HWMON)
+-	if (sfp->sm_mod_state >= SFP_MOD_WAITDEV &&
+-	    IS_ERR_OR_NULL(sfp->hwmon_dev)) {
+-		err = sfp_hwmon_insert(sfp);
+-		if (err)
+-			dev_warn(sfp->dev, "hwmon probe failed: %d\n", err);
+-	}
+-#endif
+ }
+ 
+ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/756-net-sfp-use-a-definition-for-the-fault-recovery-atte.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/756-net-sfp-use-a-definition-for-the-fault-recovery-atte.patch
new file mode 100644
index 0000000..ba4f8c4
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/756-net-sfp-use-a-definition-for-the-fault-recovery-atte.patch
@@ -0,0 +1,55 @@
+From 4d6bfb6fbb00af38402db4d1ce464e22def9fd9e Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Thu, 28 Nov 2019 14:24:40 +0000
+Subject: [PATCH 1/4] net: sfp: use a definition for the fault recovery
+ attempts
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -172,6 +172,14 @@ static const enum gpiod_flags gpio_flags
+ #define T_RESET_US		10
+ #define T_FAULT_RECOVER		msecs_to_jiffies(1000)
+ 
++/* N_FAULT_INIT is the number of recovery attempts at module initialisation
++ * time. If the TX_FAULT signal is not deasserted after this number of
++ * attempts at clearing it, we decide that the module is faulty.
++ * N_FAULT is the same but after the module has initialised.
++ */
++#define N_FAULT_INIT		5
++#define N_FAULT			5
++
+ /* SFP module presence detection is poor: the three MOD DEF signals are
+  * the same length on the PCB, which means it's possible for MOD DEF 0 to
+  * connect before the I2C bus on MOD DEF 1/2.
+@@ -1972,7 +1980,7 @@ static void sfp_sm_main(struct sfp *sfp,
+ 		sfp_module_tx_enable(sfp);
+ 
+ 		/* Initialise the fault clearance retries */
+-		sfp->sm_retries = 5;
++		sfp->sm_retries = N_FAULT_INIT;
+ 
+ 		/* We need to check the TX_FAULT state, which is not defined
+ 		 * while TX_DISABLE is asserted. The earliest we want to do
+@@ -2012,7 +2020,7 @@ static void sfp_sm_main(struct sfp *sfp,
+ 			 * or t_start_up, so assume there is a fault.
+ 			 */
+ 			sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT,
+-				     sfp->sm_retries == 5);
++				     sfp->sm_retries == N_FAULT_INIT);
+ 		} else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) {
+ 	init_done:	/* TX_FAULT deasserted or we timed out with TX_FAULT
+ 			 * clear.  Probe for the PHY and check the LOS state.
+@@ -2025,7 +2033,7 @@ static void sfp_sm_main(struct sfp *sfp,
+ 			sfp_sm_link_check_los(sfp);
+ 
+ 			/* Reset the fault retry count */
+-			sfp->sm_retries = 5;
++			sfp->sm_retries = N_FAULT;
+ 		}
+ 		break;
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/757-net-sfp-rename-sm_retries.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/757-net-sfp-rename-sm_retries.patch
new file mode 100644
index 0000000..13f3b6c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/757-net-sfp-rename-sm_retries.patch
@@ -0,0 +1,60 @@
+From bfa3cbb01c7ea34d7369c9bd2ec1b2dc67082b04 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Mon, 2 Dec 2019 18:06:44 +0000
+Subject: [PATCH 2/4] net: sfp: rename sm_retries
+
+Rename sm_retries as sm_fault_retries, as this is what this member is
+tracking.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -235,7 +235,7 @@ struct sfp {
+ 	unsigned char sm_mod_tries;
+ 	unsigned char sm_dev_state;
+ 	unsigned short sm_state;
+-	unsigned int sm_retries;
++	unsigned char sm_fault_retries;
+ 
+ 	struct sfp_eeprom_id id;
+ 	unsigned int module_power_mW;
+@@ -1506,7 +1506,7 @@ static bool sfp_los_event_inactive(struc
+ 
+ static void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn)
+ {
+-	if (sfp->sm_retries && !--sfp->sm_retries) {
++	if (sfp->sm_fault_retries && !--sfp->sm_fault_retries) {
+ 		dev_err(sfp->dev,
+ 			"module persistently indicates fault, disabling\n");
+ 		sfp_sm_next(sfp, SFP_S_TX_DISABLE, 0);
+@@ -1980,7 +1980,7 @@ static void sfp_sm_main(struct sfp *sfp,
+ 		sfp_module_tx_enable(sfp);
+ 
+ 		/* Initialise the fault clearance retries */
+-		sfp->sm_retries = N_FAULT_INIT;
++		sfp->sm_fault_retries = N_FAULT_INIT;
+ 
+ 		/* We need to check the TX_FAULT state, which is not defined
+ 		 * while TX_DISABLE is asserted. The earliest we want to do
+@@ -2020,7 +2020,7 @@ static void sfp_sm_main(struct sfp *sfp,
+ 			 * or t_start_up, so assume there is a fault.
+ 			 */
+ 			sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT,
+-				     sfp->sm_retries == N_FAULT_INIT);
++				     sfp->sm_fault_retries == N_FAULT_INIT);
+ 		} else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) {
+ 	init_done:	/* TX_FAULT deasserted or we timed out with TX_FAULT
+ 			 * clear.  Probe for the PHY and check the LOS state.
+@@ -2033,7 +2033,7 @@ static void sfp_sm_main(struct sfp *sfp,
+ 			sfp_sm_link_check_los(sfp);
+ 
+ 			/* Reset the fault retry count */
+-			sfp->sm_retries = N_FAULT;
++			sfp->sm_fault_retries = N_FAULT;
+ 		}
+ 		break;
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/758-net-sfp-error-handling-for-phy-probe.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/758-net-sfp-error-handling-for-phy-probe.patch
new file mode 100644
index 0000000..dfa772d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/758-net-sfp-error-handling-for-phy-probe.patch
@@ -0,0 +1,97 @@
+From 1fba543dc8edf4a43bff3276306648bb27c1e207 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 29 Nov 2019 00:30:08 +0000
+Subject: [PATCH 3/4] net: sfp: error handling for phy probe
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 26 +++++++++++++++++---------
+ 1 file changed, 17 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -1426,7 +1426,7 @@ static void sfp_sm_phy_detach(struct sfp
+ 	sfp->mod_phy = NULL;
+ }
+ 
+-static void sfp_sm_probe_phy(struct sfp *sfp, bool is_c45)
++static int sfp_sm_probe_phy(struct sfp *sfp, bool is_c45)
+ {
+ 	struct phy_device *phy;
+ 	int err;
+@@ -1434,18 +1434,18 @@ static void sfp_sm_probe_phy(struct sfp
+ 	phy = get_phy_device(sfp->i2c_mii, SFP_PHY_ADDR, is_c45);
+ 	if (phy == ERR_PTR(-ENODEV)) {
+ 		dev_info(sfp->dev, "no PHY detected\n");
+-		return;
++		return 0;
+ 	}
+ 	if (IS_ERR(phy)) {
+ 		dev_err(sfp->dev, "mdiobus scan returned %ld\n", PTR_ERR(phy));
+-		return;
++		return PTR_ERR(phy);
+ 	}
+ 
+ 	err = phy_device_register(phy);
+ 	if (err) {
+ 		phy_device_free(phy);
+ 		dev_err(sfp->dev, "phy_device_register failed: %d\n", err);
+-		return;
++		return err;
+ 	}
+ 
+ 	err = sfp_add_phy(sfp->sfp_bus, phy);
+@@ -1453,10 +1453,12 @@ static void sfp_sm_probe_phy(struct sfp
+ 		phy_device_remove(phy);
+ 		phy_device_free(phy);
+ 		dev_err(sfp->dev, "sfp_add_phy failed: %d\n", err);
+-		return;
++		return err;
+ 	}
+ 
+ 	sfp->mod_phy = phy;
++
++	return 0;
+ }
+ 
+ static void sfp_sm_link_up(struct sfp *sfp)
+@@ -1529,21 +1531,24 @@ static void sfp_sm_fault(struct sfp *sfp
+  * Clause 45 copper SFP+ modules (10G) appear to switch their interface
+  * mode according to the negotiated line speed.
+  */
+-static void sfp_sm_probe_for_phy(struct sfp *sfp)
++static int sfp_sm_probe_for_phy(struct sfp *sfp)
+ {
++	int err = 0;
++
+ 	switch (sfp->id.base.extended_cc) {
+ 	case SFF8024_ECC_10GBASE_T_SFI:
+ 	case SFF8024_ECC_10GBASE_T_SR:
+ 	case SFF8024_ECC_5GBASE_T:
+ 	case SFF8024_ECC_2_5GBASE_T:
+-		sfp_sm_probe_phy(sfp, true);
++		err = sfp_sm_probe_phy(sfp, true);
+ 		break;
+ 
+ 	default:
+ 		if (sfp->id.base.e1000_base_t)
+-			sfp_sm_probe_phy(sfp, false);
++			err = sfp_sm_probe_phy(sfp, false);
+ 		break;
+ 	}
++	return err;
+ }
+ 
+ static int sfp_module_parse_power(struct sfp *sfp)
+@@ -2025,7 +2030,10 @@ static void sfp_sm_main(struct sfp *sfp,
+ 	init_done:	/* TX_FAULT deasserted or we timed out with TX_FAULT
+ 			 * clear.  Probe for the PHY and check the LOS state.
+ 			 */
+-			sfp_sm_probe_for_phy(sfp);
++			if (sfp_sm_probe_for_phy(sfp)) {
++				sfp_sm_next(sfp, SFP_S_FAIL, 0);
++				break;
++			}
+ 			if (sfp_module_start(sfp->sfp_bus)) {
+ 				sfp_sm_next(sfp, SFP_S_FAIL, 0);
+ 				break;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/759-net-sfp-re-attempt-probing-for-phy.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/759-net-sfp-re-attempt-probing-for-phy.patch
new file mode 100644
index 0000000..aebb6b0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/759-net-sfp-re-attempt-probing-for-phy.patch
@@ -0,0 +1,132 @@
+From 6c4efe83a0acf6f06c89ae17b885fa5739eb5be7 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Mon, 2 Dec 2019 18:20:22 +0000
+Subject: [PATCH 4/4] net: sfp: re-attempt probing for phy
+
+Some 1000BASE-T PHY modules take a while for the PHY to wake up.
+Retry the probe a number of times before deciding that the module has
+no PHY.
+
+Tested with:
+ Sourcephotonics SPGBTXCNFC - PHY takes less than 50ms to respond.
+ Champion One 1000SFPT - PHY takes about 200ms to respond.
+ Mikrotik S-RJ01 - no PHY
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 59 ++++++++++++++++++++++++++++++++++++---------------
+ 1 file changed, 42 insertions(+), 17 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -62,6 +62,7 @@ enum {
+ 	SFP_S_FAIL,
+ 	SFP_S_WAIT,
+ 	SFP_S_INIT,
++	SFP_S_INIT_PHY,
+ 	SFP_S_INIT_TX_FAULT,
+ 	SFP_S_WAIT_LOS,
+ 	SFP_S_LINK_UP,
+@@ -126,6 +127,7 @@ static const char * const sm_state_strin
+ 	[SFP_S_FAIL] = "fail",
+ 	[SFP_S_WAIT] = "wait",
+ 	[SFP_S_INIT] = "init",
++	[SFP_S_INIT_PHY] = "init_phy",
+ 	[SFP_S_INIT_TX_FAULT] = "init_tx_fault",
+ 	[SFP_S_WAIT_LOS] = "wait_los",
+ 	[SFP_S_LINK_UP] = "link_up",
+@@ -180,6 +182,12 @@ static const enum gpiod_flags gpio_flags
+ #define N_FAULT_INIT		5
+ #define N_FAULT			5
+ 
++/* T_PHY_RETRY is the time interval between attempts to probe the PHY.
++ * R_PHY_RETRY is the number of attempts.
++ */
++#define T_PHY_RETRY		msecs_to_jiffies(50)
++#define R_PHY_RETRY		12
++
+ /* SFP module presence detection is poor: the three MOD DEF signals are
+  * the same length on the PCB, which means it's possible for MOD DEF 0 to
+  * connect before the I2C bus on MOD DEF 1/2.
+@@ -236,6 +244,7 @@ struct sfp {
+ 	unsigned char sm_dev_state;
+ 	unsigned short sm_state;
+ 	unsigned char sm_fault_retries;
++	unsigned char sm_phy_retries;
+ 
+ 	struct sfp_eeprom_id id;
+ 	unsigned int module_power_mW;
+@@ -1432,10 +1441,8 @@ static int sfp_sm_probe_phy(struct sfp *
+ 	int err;
+ 
+ 	phy = get_phy_device(sfp->i2c_mii, SFP_PHY_ADDR, is_c45);
+-	if (phy == ERR_PTR(-ENODEV)) {
+-		dev_info(sfp->dev, "no PHY detected\n");
+-		return 0;
+-	}
++	if (phy == ERR_PTR(-ENODEV))
++		return PTR_ERR(phy);
+ 	if (IS_ERR(phy)) {
+ 		dev_err(sfp->dev, "mdiobus scan returned %ld\n", PTR_ERR(phy));
+ 		return PTR_ERR(phy);
+@@ -1954,6 +1961,7 @@ static void sfp_sm_module(struct sfp *sf
+ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
+ {
+ 	unsigned long timeout;
++	int ret;
+ 
+ 	/* Some events are global */
+ 	if (sfp->sm_state != SFP_S_DOWN &&
+@@ -2027,22 +2035,39 @@ static void sfp_sm_main(struct sfp *sfp,
+ 			sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT,
+ 				     sfp->sm_fault_retries == N_FAULT_INIT);
+ 		} else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) {
+-	init_done:	/* TX_FAULT deasserted or we timed out with TX_FAULT
+-			 * clear.  Probe for the PHY and check the LOS state.
+-			 */
+-			if (sfp_sm_probe_for_phy(sfp)) {
+-				sfp_sm_next(sfp, SFP_S_FAIL, 0);
+-				break;
+-			}
+-			if (sfp_module_start(sfp->sfp_bus)) {
+-				sfp_sm_next(sfp, SFP_S_FAIL, 0);
++	init_done:
++			sfp->sm_phy_retries = R_PHY_RETRY;
++			goto phy_probe;
++		}
++		break;
++
++	case SFP_S_INIT_PHY:
++		if (event != SFP_E_TIMEOUT)
++			break;
++	phy_probe:
++		/* TX_FAULT deasserted or we timed out with TX_FAULT
++		 * clear.  Probe for the PHY and check the LOS state.
++		 */
++		ret = sfp_sm_probe_for_phy(sfp);
++		if (ret == -ENODEV) {
++			if (--sfp->sm_phy_retries) {
++				sfp_sm_next(sfp, SFP_S_INIT_PHY, T_PHY_RETRY);
+ 				break;
++			} else {
++				dev_info(sfp->dev, "no PHY detected\n");
+ 			}
+-			sfp_sm_link_check_los(sfp);
+-
+-			/* Reset the fault retry count */
+-			sfp->sm_fault_retries = N_FAULT;
++		} else if (ret) {
++			sfp_sm_next(sfp, SFP_S_FAIL, 0);
++			break;
+ 		}
++		if (sfp_module_start(sfp->sfp_bus)) {
++			sfp_sm_next(sfp, SFP_S_FAIL, 0);
++			break;
++		}
++		sfp_sm_link_check_los(sfp);
++
++		/* Reset the fault retry count */
++		sfp->sm_fault_retries = N_FAULT;
+ 		break;
+ 
+ 	case SFP_S_INIT_TX_FAULT:
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/760-net-dsa-mv88e6xxx-fix-vlan-setup.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/760-net-dsa-mv88e6xxx-fix-vlan-setup.patch
new file mode 100644
index 0000000..a49b48f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/760-net-dsa-mv88e6xxx-fix-vlan-setup.patch
@@ -0,0 +1,27 @@
+From a1b291f3f6c80a6c5ccad7283fc472d77a2a4763 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Sun, 22 Dec 2019 12:40:11 +0000
+Subject: [PATCH] net: dsa: mv88e6xxx: fix vlan setup
+
+Provide an option that drivers can set to indicate they want to receive
+vlan configuration even when vlan filtering is disabled. This is safe
+for Marvell DSA bridges, which do not look up ingress traffic in the
+VTU if the port is in 8021Q disabled state. Whether this change is
+suitable for all DSA bridges is not known.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+Signed-off-by: DENG Qingfang <dqfext@gmail.com>
+---
+ drivers/net/dsa/mv88e6xxx/chip.c |  1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/dsa/mv88e6xxx/chip.c
++++ b/drivers/net/dsa/mv88e6xxx/chip.c
+@@ -2663,6 +2663,7 @@ static int mv88e6xxx_setup(struct dsa_sw
+ 
+ 	chip->ds = ds;
+ 	ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip);
++	ds->configure_vlan_while_not_filtering = true;
+ 
+ 	mv88e6xxx_reg_lock(chip);
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/761-net-dsa-mt7530-Support-EEE-features.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/761-net-dsa-mt7530-Support-EEE-features.patch
new file mode 100644
index 0000000..c2dc35d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/761-net-dsa-mt7530-Support-EEE-features.patch
@@ -0,0 +1,121 @@
+From 9cfb2d426c38272f245e9e6f62b3552d1ed5852b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= <opensource@vdorst.com>
+Date: Tue, 21 Apr 2020 00:18:08 +0200
+Subject: [PATCH] net: dsa: mt7530: Support EEE features
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: René van Dorst <opensource@vdorst.com>
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -1407,9 +1407,13 @@ static void mt7530_phylink_mac_config(st
+ 	switch (state->speed) {
+ 	case SPEED_1000:
+ 		mcr_new |= PMCR_FORCE_SPEED_1000;
++		if (priv->eee_enable & BIT(port))
++			mcr_new |= PMCR_FORCE_EEE1G;
+ 		break;
+ 	case SPEED_100:
+ 		mcr_new |= PMCR_FORCE_SPEED_100;
++		if (priv->eee_enable & BIT(port))
++			mcr_new |= PMCR_FORCE_EEE100;
+ 		break;
+ 	}
+ 	if (state->duplex == DUPLEX_FULL) {
+@@ -1545,6 +1549,54 @@ mt7530_phylink_mac_link_state(struct dsa
+ 	return 1;
+ }
+ 
++static int mt7530_get_mac_eee(struct dsa_switch *ds, int port,
++			      struct ethtool_eee *e)
++{
++	struct mt7530_priv *priv = ds->priv;
++	u32 eeecr, pmsr;
++
++	e->eee_enabled = !!(priv->eee_enable & BIT(port));
++
++	if (e->eee_enabled) {
++		eeecr = mt7530_read(priv, MT7530_PMEEECR_P(port));
++		e->tx_lpi_enabled = !(eeecr & LPI_MODE_EN);
++		e->tx_lpi_timer   = (eeecr >> 4) & 0xFFF;
++		pmsr = mt7530_read(priv, MT7530_PMSR_P(port));
++		e->eee_active  = e->eee_enabled && !!(pmsr & PMSR_EEE1G);
++	} else {
++		e->tx_lpi_enabled = 0;
++		e->tx_lpi_timer = 0;
++		e->eee_active = 0;
++	}
++
++	return 0;
++}
++
++static int mt7530_set_mac_eee(struct dsa_switch *ds, int port,
++			      struct ethtool_eee *e)
++{
++	struct mt7530_priv *priv = ds->priv;
++	u32 eeecr;
++
++	if (e->tx_lpi_enabled && e->tx_lpi_timer > 0xFFF)
++		return -EINVAL;
++
++	if (e->eee_enabled) {
++		priv->eee_enable |= BIT(port);
++		//MT7530_PMEEECR_P
++		eeecr = mt7530_read(priv, MT7530_PMEEECR_P(port));
++		eeecr &= 0xFFFF0000;
++		if (!e->tx_lpi_enabled)
++			eeecr |= LPI_MODE_EN;
++		eeecr |= LPI_THRESH(e->tx_lpi_timer);
++		mt7530_write(priv, MT7530_PMEEECR_P(port), eeecr);
++	} else {
++		priv->eee_enable &= ~(BIT(port));
++	}
++
++	return 0;
++}
++
+ static const struct dsa_switch_ops mt7530_switch_ops = {
+ 	.get_tag_protocol	= mtk_get_tag_protocol,
+ 	.setup			= mt7530_setup,
+@@ -1572,6 +1624,8 @@ static const struct dsa_switch_ops mt753
+ 	.phylink_mac_config	= mt7530_phylink_mac_config,
+ 	.phylink_mac_link_down	= mt7530_phylink_mac_link_down,
+ 	.phylink_mac_link_up	= mt7530_phylink_mac_link_up,
++	.get_mac_eee		= mt7530_get_mac_eee,
++	.set_mac_eee		= mt7530_set_mac_eee,
+ };
+ 
+ static const struct of_device_id mt7530_of_match[] = {
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -212,6 +212,8 @@ enum mt7530_vlan_port_attr {
+ #define  PMCR_RX_EN			BIT(13)
+ #define  PMCR_BACKOFF_EN		BIT(9)
+ #define  PMCR_BACKPR_EN			BIT(8)
++#define  PMCR_FORCE_EEE1G		BIT(7)
++#define  PMCR_FORCE_EEE100		BIT(6)
+ #define  PMCR_TX_FC_EN			BIT(5)
+ #define  PMCR_RX_FC_EN			BIT(4)
+ #define  PMCR_FORCE_SPEED_1000		BIT(3)
+@@ -233,6 +235,12 @@ enum mt7530_vlan_port_attr {
+ #define  PMSR_DPX			BIT(1)
+ #define  PMSR_LINK			BIT(0)
+ 
++#define MT7530_PMEEECR_P(x)		(0x3004 + (x) * 0x100)
++#define  WAKEUP_TIME_1000(x)		((x & 0xFF) << 24)
++#define  WAKEUP_TIME_100(x)		((x & 0xFF) << 16)
++#define  LPI_THRESH(x)			((x & 0xFFF) << 4)
++#define  LPI_MODE_EN			BIT(0)
++
+ /* Register for MIB */
+ #define MT7530_PORT_MIB_COUNTER(x)	(0x4000 + (x) * 0x100)
+ #define MT7530_MIB_CCR			0x4fe0
+@@ -471,6 +479,7 @@ struct mt7530_priv {
+ 	unsigned int		p5_intf_sel;
+ 	u8			mirror_rx;
+ 	u8			mirror_tx;
++	u8			eee_enable;
+ 
+ 	struct mt7530_port	ports[MT7530_NUM_PORTS];
+ 	/* protect among processes for registers access*/
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/762-net-bridge-switchdev-Refactor-br_switchdev_fdb_notif.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/762-net-bridge-switchdev-Refactor-br_switchdev_fdb_notif.patch
new file mode 100644
index 0000000..bfa2d37
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/762-net-bridge-switchdev-Refactor-br_switchdev_fdb_notif.patch
@@ -0,0 +1,71 @@
+From 46fe6cecb296d850c1ee2b333e57093ac4b733f3 Mon Sep 17 00:00:00 2001
+From: Tobias Waldekranz <tobias@waldekranz.com>
+Date: Sat, 16 Jan 2021 02:25:09 +0100
+Subject: [PATCH] net: bridge: switchdev: Refactor br_switchdev_fdb_notify
+
+Instead of having to add more and more arguments to
+br_switchdev_fdb_call_notifiers, get rid of it and build the info
+struct directly in br_switchdev_fdb_notify.
+
+Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+---
+ net/bridge/br_switchdev.c | 37 +++++++++++--------------------------
+ 1 file changed, 11 insertions(+), 26 deletions(-)
+
+--- a/net/bridge/br_switchdev.c
++++ b/net/bridge/br_switchdev.c
+@@ -102,42 +102,27 @@ int br_switchdev_set_port_flag(struct ne
+ 	return 0;
+ }
+ 
+-static void
+-br_switchdev_fdb_call_notifiers(bool adding, const unsigned char *mac,
+-				u16 vid, struct net_device *dev,
+-				bool added_by_user, bool offloaded)
+-{
+-	struct switchdev_notifier_fdb_info info;
+-	unsigned long notifier_type;
+-
+-	info.addr = mac;
+-	info.vid = vid;
+-	info.added_by_user = added_by_user;
+-	info.offloaded = offloaded;
+-	notifier_type = adding ? SWITCHDEV_FDB_ADD_TO_DEVICE : SWITCHDEV_FDB_DEL_TO_DEVICE;
+-	call_switchdev_notifiers(notifier_type, dev, &info.info, NULL);
+-}
+-
+ void
+ br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type)
+ {
++	struct switchdev_notifier_fdb_info info = {
++		.addr = fdb->key.addr.addr,
++		.vid = fdb->key.vlan_id,
++		.added_by_user = fdb->added_by_user,
++		.offloaded = fdb->offloaded,
++	};
++
+ 	if (!fdb->dst)
+ 		return;
+ 
+ 	switch (type) {
+ 	case RTM_DELNEIGH:
+-		br_switchdev_fdb_call_notifiers(false, fdb->key.addr.addr,
+-						fdb->key.vlan_id,
+-						fdb->dst->dev,
+-						fdb->added_by_user,
+-						fdb->offloaded);
++		call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_DEVICE,
++					 fdb->dst->dev, &info.info, NULL);
+ 		break;
+ 	case RTM_NEWNEIGH:
+-		br_switchdev_fdb_call_notifiers(true, fdb->key.addr.addr,
+-						fdb->key.vlan_id,
+-						fdb->dst->dev,
+-						fdb->added_by_user,
+-						fdb->offloaded);
++		call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_DEVICE,
++					 fdb->dst->dev, &info.info, NULL);
+ 		break;
+ 	}
+ }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/763-net-bridge-switchdev-Include-local-flag-in-FDB-notif.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/763-net-bridge-switchdev-Include-local-flag-in-FDB-notif.patch
new file mode 100644
index 0000000..49d6f07
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/763-net-bridge-switchdev-Include-local-flag-in-FDB-notif.patch
@@ -0,0 +1,42 @@
+From ec5be4f79026282925ae383caa431a8d41e3456a Mon Sep 17 00:00:00 2001
+From: Tobias Waldekranz <tobias@waldekranz.com>
+Date: Sat, 16 Jan 2021 02:25:10 +0100
+Subject: [PATCH] net: bridge: switchdev: Include local flag in FDB
+ notifications
+
+Some switchdev drivers, notably DSA, ignore all dynamically learned
+address notifications (!added_by_user) as these are autonomously added
+by the switch. Previously, such a notification was indistinguishable
+from a local address notification. Include a local bit in the
+notification so that the two classes can be discriminated.
+
+This allows DSA-like devices to add local addresses to the hardware
+FDB (with the CPU as the destination), thereby avoiding flows towards
+the CPU being flooded by the switch as unknown unicast.
+
+Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
+---
+ include/net/switchdev.h   | 1 +
+ net/bridge/br_switchdev.c | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/include/net/switchdev.h
++++ b/include/net/switchdev.h
+@@ -124,6 +124,7 @@ struct switchdev_notifier_fdb_info {
+ 	const unsigned char *addr;
+ 	u16 vid;
+ 	u8 added_by_user:1,
++	   local:1,
+ 	   offloaded:1;
+ };
+ 
+--- a/net/bridge/br_switchdev.c
++++ b/net/bridge/br_switchdev.c
+@@ -109,6 +109,7 @@ br_switchdev_fdb_notify(const struct net
+ 		.addr = fdb->key.addr.addr,
+ 		.vid = fdb->key.vlan_id,
+ 		.added_by_user = fdb->added_by_user,
++		.local = fdb->is_local,
+ 		.offloaded = fdb->offloaded,
+ 	};
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/764-net-bridge-switchdev-Send-FDB-notifications-for-host.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/764-net-bridge-switchdev-Send-FDB-notifications-for-host.patch
new file mode 100644
index 0000000..8b869dd
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/764-net-bridge-switchdev-Send-FDB-notifications-for-host.patch
@@ -0,0 +1,94 @@
+From 2e50fd9322047253c327550b4485cf8761035a8c Mon Sep 17 00:00:00 2001
+From: Tobias Waldekranz <tobias@waldekranz.com>
+Date: Sat, 16 Jan 2021 02:25:11 +0100
+Subject: [PATCH] net: bridge: switchdev: Send FDB notifications for host
+ addresses
+
+Treat addresses added to the bridge itself in the same way as regular
+ports and send out a notification so that drivers may sync it down to
+the hardware FDB.
+
+Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
+---
+ net/bridge/br_fdb.c       |  4 ++--
+ net/bridge/br_private.h   |  7 ++++---
+ net/bridge/br_switchdev.c | 11 +++++------
+ 3 files changed, 11 insertions(+), 11 deletions(-)
+
+--- a/net/bridge/br_fdb.c
++++ b/net/bridge/br_fdb.c
+@@ -581,7 +581,7 @@ void br_fdb_update(struct net_bridge *br
+ 
+ 			/* fastpath: update of existing entry */
+ 			if (unlikely(source != fdb->dst && !fdb->is_sticky)) {
+-				br_switchdev_fdb_notify(fdb, RTM_DELNEIGH);
++				br_switchdev_fdb_notify(br, fdb, RTM_DELNEIGH);
+ 				fdb->dst = source;
+ 				fdb_modified = true;
+ 				/* Take over HW learned entry */
+@@ -697,7 +697,7 @@ static void fdb_notify(struct net_bridge
+ 	int err = -ENOBUFS;
+ 
+ 	if (swdev_notify)
+-		br_switchdev_fdb_notify(fdb, type);
++		br_switchdev_fdb_notify(br, fdb, type);
+ 
+ 	skb = nlmsg_new(fdb_nlmsg_size(), GFP_ATOMIC);
+ 	if (skb == NULL)
+--- a/net/bridge/br_private.h
++++ b/net/bridge/br_private.h
+@@ -1203,8 +1203,8 @@ bool nbp_switchdev_allowed_egress(const
+ int br_switchdev_set_port_flag(struct net_bridge_port *p,
+ 			       unsigned long flags,
+ 			       unsigned long mask);
+-void br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb,
+-			     int type);
++void br_switchdev_fdb_notify(struct net_bridge *br,
++			     const struct net_bridge_fdb_entry *fdb, int type);
+ int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, u16 flags,
+ 			       struct netlink_ext_ack *extack);
+ int br_switchdev_port_vlan_del(struct net_device *dev, u16 vid);
+@@ -1250,7 +1250,8 @@ static inline int br_switchdev_port_vlan
+ }
+ 
+ static inline void
+-br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type)
++br_switchdev_fdb_notify(struct net_bridge *br,
++			const struct net_bridge_fdb_entry *fdb, int type)
+ {
+ }
+ 
+--- a/net/bridge/br_switchdev.c
++++ b/net/bridge/br_switchdev.c
+@@ -103,7 +103,8 @@ int br_switchdev_set_port_flag(struct ne
+ }
+ 
+ void
+-br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type)
++br_switchdev_fdb_notify(struct net_bridge *br,
++			const struct net_bridge_fdb_entry *fdb, int type)
+ {
+ 	struct switchdev_notifier_fdb_info info = {
+ 		.addr = fdb->key.addr.addr,
+@@ -112,18 +113,16 @@ br_switchdev_fdb_notify(const struct net
+ 		.local = fdb->is_local,
+ 		.offloaded = fdb->offloaded,
+ 	};
+-
+-	if (!fdb->dst)
+-		return;
++	struct net_device *dev = fdb->dst ? fdb->dst->dev : br->dev;
+ 
+ 	switch (type) {
+ 	case RTM_DELNEIGH:
+ 		call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_DEVICE,
+-					 fdb->dst->dev, &info.info, NULL);
++					 dev, &info.info, NULL);
+ 		break;
+ 	case RTM_NEWNEIGH:
+ 		call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_DEVICE,
+-					 fdb->dst->dev, &info.info, NULL);
++					 dev, &info.info, NULL);
+ 		break;
+ 	}
+ }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/765-net-dsa-Include-local-addresses-in-assisted-CPU-port.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/765-net-dsa-Include-local-addresses-in-assisted-CPU-port.patch
new file mode 100644
index 0000000..d951246
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/765-net-dsa-Include-local-addresses-in-assisted-CPU-port.patch
@@ -0,0 +1,36 @@
+From dd082716b43a3684b2f473ae5d1e76d1c076d86d Mon Sep 17 00:00:00 2001
+From: Tobias Waldekranz <tobias@waldekranz.com>
+Date: Sat, 16 Jan 2021 02:25:12 +0100
+Subject: [PATCH] net: dsa: Include local addresses in assisted CPU port
+ learning
+
+Add local addresses (i.e. the ports' MAC addresses) to the hardware
+FDB when assisted CPU port learning is enabled.
+
+NOTE: The bridge's own MAC address is also "local". If that address is
+not shared with any port, the bridge's MAC is not be added by this
+functionality - but the following commit takes care of that case.
+
+Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
+---
+ net/dsa/slave.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/net/dsa/slave.c
++++ b/net/dsa/slave.c
+@@ -1698,10 +1698,12 @@ static int dsa_slave_switchdev_event(str
+ 		fdb_info = ptr;
+ 
+ 		if (dsa_slave_dev_check(dev)) {
+-			if (!fdb_info->added_by_user)
+-				return NOTIFY_OK;
+-
+ 			dp = dsa_slave_to_port(dev);
++
++			if (fdb_info->local && dp->ds->assisted_learning_on_cpu_port)
++				dp = dp->cpu_dp;
++			else if (!fdb_info->added_by_user)
++				return NOTIFY_OK;
+ 		} else {
+ 			/* Snoop addresses learnt on foreign interfaces
+ 			 * bridged with us, for switches that don't
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/766-net-dsa-Include-bridge-addresses-in-assisted-CPU-por.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/766-net-dsa-Include-bridge-addresses-in-assisted-CPU-por.patch
new file mode 100644
index 0000000..46504ae
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/766-net-dsa-Include-bridge-addresses-in-assisted-CPU-por.patch
@@ -0,0 +1,30 @@
+From 0663ebde114a6fb2c28c622ba5212b302d4d2581 Mon Sep 17 00:00:00 2001
+From: Tobias Waldekranz <tobias@waldekranz.com>
+Date: Sat, 16 Jan 2021 02:25:13 +0100
+Subject: [PATCH] net: dsa: Include bridge addresses in assisted CPU port
+ learning
+
+Now that notifications are sent out for addresses added to the bridge
+itself, extend DSA to include those addresses in the hardware FDB when
+assisted CPU port learning is enabled.
+
+Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
+---
+ net/dsa/slave.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/net/dsa/slave.c
++++ b/net/dsa/slave.c
+@@ -1712,7 +1712,11 @@ static int dsa_slave_switchdev_event(str
+ 			struct net_device *br_dev;
+ 			struct dsa_slave_priv *p;
+ 
+-			br_dev = netdev_master_upper_dev_get_rcu(dev);
++			if (netif_is_bridge_master(dev))
++				br_dev = dev;
++			else
++				br_dev = netdev_master_upper_dev_get_rcu(dev);
++
+ 			if (!br_dev)
+ 				return NOTIFY_DONE;
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/767-net-dsa-Sync-static-FDB-entries-on-foreign-interface.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/767-net-dsa-Sync-static-FDB-entries-on-foreign-interface.patch
new file mode 100644
index 0000000..e626086
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/767-net-dsa-Sync-static-FDB-entries-on-foreign-interface.patch
@@ -0,0 +1,56 @@
+From 81e39fd78db82fb51b05fff309b9c521f1a0bc5a Mon Sep 17 00:00:00 2001
+From: Tobias Waldekranz <tobias@waldekranz.com>
+Date: Sat, 16 Jan 2021 02:25:14 +0100
+Subject: [PATCH] net: dsa: Sync static FDB entries on foreign interfaces to
+ hardware
+
+Reuse the "assisted_learning_on_cpu_port" functionality to always add
+entries for user-configured entries on foreign interfaces, even if
+assisted_learning_on_cpu_port is not enabled. E.g. in this situation:
+
+   br0
+   / \
+swp0 dummy0
+
+$ bridge fdb add 02:00:de:ad:00:01 dev dummy0 vlan 1 master
+
+Results in DSA adding an entry in the hardware FDB, pointing this
+address towards the CPU port.
+
+The same is true for entries added to the bridge itself, e.g:
+
+$ bridge fdb add 02:00:de:ad:00:01 dev br0 vlan 1 self
+
+Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
+---
+ net/dsa/slave.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+--- a/net/dsa/slave.c
++++ b/net/dsa/slave.c
+@@ -1705,9 +1705,12 @@ static int dsa_slave_switchdev_event(str
+ 			else if (!fdb_info->added_by_user)
+ 				return NOTIFY_OK;
+ 		} else {
+-			/* Snoop addresses learnt on foreign interfaces
+-			 * bridged with us, for switches that don't
+-			 * automatically learn SA from CPU-injected traffic
++			/* Snoop addresses added to foreign interfaces
++			 * bridged with us, or the bridge
++			 * itself. Dynamically learned addresses can
++			 * also be added for switches that don't
++			 * automatically learn SA from CPU-injected
++			 * traffic.
+ 			 */
+ 			struct net_device *br_dev;
+ 			struct dsa_slave_priv *p;
+@@ -1729,7 +1732,8 @@ static int dsa_slave_switchdev_event(str
+ 
+ 			dp = p->dp->cpu_dp;
+ 
+-			if (!dp->ds->assisted_learning_on_cpu_port)
++			if (!fdb_info->added_by_user &&
++			    !dp->ds->assisted_learning_on_cpu_port)
+ 				return NOTIFY_DONE;
+ 		}
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch
new file mode 100644
index 0000000..cb421f1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch
@@ -0,0 +1,27 @@
+From:   Tobias Waldekranz <tobias@waldekranz.com>
+Subject: [RFC net-next 7/7] net: dsa: mv88e6xxx: Request assisted learning on CPU port
+Date:   Sat, 16 Jan 2021 02:25:15 +0100
+Archived-At: <https://lore.kernel.org/netdev/20210116012515.3152-8-tobias@waldekranz.com/>
+
+While the hardware is capable of performing learning on the CPU port,
+it requires alot of additions to the bridge's forwarding path in order
+to handle multi-destination traffic correctly.
+
+Until that is in place, opt for the next best thing and let DSA sync
+the relevant addresses down to the hardware FDB.
+
+Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
+---
+ drivers/net/dsa/mv88e6xxx/chip.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/dsa/mv88e6xxx/chip.c
++++ b/drivers/net/dsa/mv88e6xxx/chip.c
+@@ -5080,6 +5080,7 @@ static int mv88e6xxx_register_switch(str
+ 	ds->ops = &mv88e6xxx_switch_ops;
+ 	ds->ageing_time_min = chip->info->age_time_coeff;
+ 	ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX;
++	ds->assisted_learning_on_cpu_port = true;
+ 
+ 	dev_set_drvdata(dev, ds);
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/800-bcma-get-SoC-device-struct-copy-its-DMA-params-to-th.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/800-bcma-get-SoC-device-struct-copy-its-DMA-params-to-th.patch
new file mode 100644
index 0000000..511a9f7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/800-bcma-get-SoC-device-struct-copy-its-DMA-params-to-th.patch
@@ -0,0 +1,64 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Subject: [PATCH] bcma: get SoC device struct & copy its DMA params to the
+ subdevices
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+For bus devices to be fully usable it's required to set their DMA
+parameters.
+
+For years it has been missing and remained unnoticed because of
+mips_dma_alloc_coherent() silently handling the empty coherent_dma_mask.
+Kernel 4.19 came with a lot of DMA changes and caused a regression on
+the bcm47xx. Starting with the commit f8c55dc6e828 ("MIPS: use generic
+dma noncoherent ops for simple noncoherent platforms") DMA coherent
+allocations just fail. Example:
+[    1.114914] bgmac_bcma bcma0:2: Allocation of TX ring 0x200 failed
+[    1.121215] bgmac_bcma bcma0:2: Unable to alloc memory for DMA
+[    1.127626] bgmac_bcma: probe of bcma0:2 failed with error -12
+[    1.133838] bgmac_bcma: Broadcom 47xx GBit MAC driver loaded
+
+This change fixes above regression in addition to the MIPS bcm47xx
+commit 321c46b91550 ("MIPS: BCM47XX: Setup struct device for the SoC").
+
+It also fixes another *old* GPIO regression caused by a parent pointing
+to the NULL:
+[    0.157054] missing gpiochip .dev parent pointer
+[    0.157287] bcma: bus0: Error registering GPIO driver: -22
+introduced by the commit 74f4e0cc6108 ("bcma: switch GPIO portions to
+use GPIOLIB_IRQCHIP").
+
+Fixes: f8c55dc6e828 ("MIPS: use generic dma noncoherent ops for simple noncoherent platforms")
+Fixes: 74f4e0cc6108 ("bcma: switch GPIO portions to use GPIOLIB_IRQCHIP")
+Cc: linux-mips@linux-mips.org
+Cc: Christoph Hellwig <hch@lst.de>
+Cc: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+---
+
+--- a/drivers/bcma/host_soc.c
++++ b/drivers/bcma/host_soc.c
+@@ -191,6 +191,8 @@ int __init bcma_host_soc_init(struct bcm
+ 	struct bcma_bus *bus = &soc->bus;
+ 	int err;
+ 
++	bus->dev = soc->dev;
++
+ 	/* Scan bus and initialize it */
+ 	err = bcma_bus_early_register(bus);
+ 	if (err)
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -241,8 +241,10 @@ void bcma_prepare_core(struct bcma_bus *
+ 	core->dev.bus = &bcma_bus_type;
+ 	dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index);
+ 	core->dev.parent = bus->dev;
+-	if (bus->dev)
++	if (bus->dev) {
+ 		bcma_of_fill_device(bus->dev, core);
++		dma_coerce_mask_and_coherent(&core->dev, bus->dev->coherent_dma_mask);
++	}
+ 
+ 	switch (bus->hosttype) {
+ 	case BCMA_HOSTTYPE_PCI:
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/810-pci_disable_common_quirks.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/810-pci_disable_common_quirks.patch
new file mode 100644
index 0000000..5aea055
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/810-pci_disable_common_quirks.patch
@@ -0,0 +1,62 @@
+From: Gabor Juhos <juhosg@openwrt.org>
+Subject: debloat: add kernel config option to disabling common PCI quirks
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ drivers/pci/Kconfig  | 6 ++++++
+ drivers/pci/quirks.c | 6 ++++++
+ 2 files changed, 12 insertions(+)
+
+--- a/drivers/pci/Kconfig
++++ b/drivers/pci/Kconfig
+@@ -115,6 +115,13 @@ config XEN_PCIDEV_FRONTEND
+           The PCI device frontend driver allows the kernel to import arbitrary
+           PCI devices from a PCI backend to support PCI driver domains.
+ 
++config PCI_DISABLE_COMMON_QUIRKS
++	bool "PCI disable common quirks"
++	depends on PCI
++	help
++	  If you don't know what to do here, say N.
++
++
+ config PCI_ATS
+ 	bool
+ 
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -206,6 +206,7 @@ static void quirk_mmio_always_on(struct
+ DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID,
+ 				PCI_CLASS_BRIDGE_HOST, 8, quirk_mmio_always_on);
+ 
++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
+ /*
+  * The Mellanox Tavor device gives false positive parity errors.  Mark this
+  * device with a broken_parity_status to allow PCI scanning code to "skip"
+@@ -3323,6 +3324,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f9, quirk_intel_mc_errata);
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65fa, quirk_intel_mc_errata);
+ 
++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */
++
+ /*
+  * Ivytown NTB BAR sizes are misreported by the hardware due to an erratum.
+  * To work around this, query the size it should be configured to by the
+@@ -3348,6 +3351,8 @@ static void quirk_intel_ntb(struct pci_d
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e08, quirk_intel_ntb);
+ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e0d, quirk_intel_ntb);
+ 
++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
++
+ /*
+  * Some BIOS implementations leave the Intel GPU interrupts enabled, even
+  * though no one is handling them (e.g., if the i915 driver is never
+@@ -3386,6 +3391,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq);
+ 
++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */
++
+ /*
+  * PCI devices which are on Intel chips can skip the 10ms delay
+  * before entering D3 mode.
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/811-pci_disable_usb_common_quirks.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/811-pci_disable_usb_common_quirks.patch
new file mode 100644
index 0000000..6e4584c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/811-pci_disable_usb_common_quirks.patch
@@ -0,0 +1,115 @@
+From: Felix Fietkau <nbd@nbd.name>
+Subject: debloat: disable common USB quirks
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ drivers/usb/host/pci-quirks.c | 16 ++++++++++++++++
+ drivers/usb/host/pci-quirks.h | 18 +++++++++++++++++-
+ include/linux/usb/hcd.h       |  7 +++++++
+ 3 files changed, 40 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/host/pci-quirks.c
++++ b/drivers/usb/host/pci-quirks.c
+@@ -125,6 +125,8 @@ struct amd_chipset_type {
+ 	u8 rev;
+ };
+ 
++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
++
+ static struct amd_chipset_info {
+ 	struct pci_dev	*nb_dev;
+ 	struct pci_dev	*smbus_dev;
+@@ -630,6 +632,10 @@ bool usb_amd_pt_check_port(struct device
+ }
+ EXPORT_SYMBOL_GPL(usb_amd_pt_check_port);
+ 
++#endif /* CONFIG_PCI_DISABLE_COMMON_QUIRKS */
++
++#if IS_ENABLED(CONFIG_USB_UHCI_HCD)
++
+ /*
+  * Make sure the controller is completely inactive, unable to
+  * generate interrupts or do DMA.
+@@ -709,8 +715,17 @@ reset_needed:
+ 	uhci_reset_hc(pdev, base);
+ 	return 1;
+ }
++#else
++int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base)
++{
++	return 0;
++}
++
++#endif
+ EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc);
+ 
++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
++
+ static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask)
+ {
+ 	u16 cmd;
+@@ -1271,3 +1286,4 @@ static void quirk_usb_early_handoff(stru
+ }
+ DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
+ 			PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff);
++#endif
+--- a/drivers/usb/host/pci-quirks.h
++++ b/drivers/usb/host/pci-quirks.h
+@@ -5,6 +5,9 @@
+ #ifdef CONFIG_USB_PCI
+ void uhci_reset_hc(struct pci_dev *pdev, unsigned long base);
+ int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base);
++#endif  /* CONFIG_USB_PCI */
++
++#if defined(CONFIG_USB_PCI) && !defined(CONFIG_PCI_DISABLE_COMMON_QUIRKS)
+ int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev);
+ bool usb_amd_hang_symptom_quirk(void);
+ bool usb_amd_prefetch_quirk(void);
+@@ -19,6 +22,18 @@ void sb800_prefetch(struct device *dev,
+ bool usb_amd_pt_check_port(struct device *device, int port);
+ #else
+ struct pci_dev;
++static inline int usb_amd_quirk_pll_check(void)
++{
++	return 0;
++}
++static inline bool usb_amd_hang_symptom_quirk(void)
++{
++	return false;
++}
++static inline bool usb_amd_prefetch_quirk(void)
++{
++	return false;
++}
+ static inline void usb_amd_quirk_pll_disable(void) {}
+ static inline void usb_amd_quirk_pll_enable(void) {}
+ static inline void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev) {}
+@@ -29,6 +44,11 @@ static inline bool usb_amd_pt_check_port
+ {
+ 	return false;
+ }
++static inline void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev) {}
++static inline bool usb_xhci_needs_pci_reset(struct pci_dev *pdev)
++{
++	return false;
++}
+ #endif  /* CONFIG_USB_PCI */
+ 
+ #endif  /*  __LINUX_USB_PCI_QUIRKS_H  */
+--- a/include/linux/usb/hcd.h
++++ b/include/linux/usb/hcd.h
+@@ -483,7 +483,14 @@ extern int usb_hcd_pci_probe(struct pci_
+ extern void usb_hcd_pci_remove(struct pci_dev *dev);
+ extern void usb_hcd_pci_shutdown(struct pci_dev *dev);
+ 
++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
+ extern int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev);
++#else
++static inline int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev)
++{
++	return 0;
++}
++#endif
+ 
+ #ifdef CONFIG_PM
+ extern const struct dev_pm_ops usb_hcd_pci_pm_ops;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/820-libata-Assign-OF-node-to-the-SCSI-device.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/820-libata-Assign-OF-node-to-the-SCSI-device.patch
new file mode 100644
index 0000000..c4cbaaa
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/820-libata-Assign-OF-node-to-the-SCSI-device.patch
@@ -0,0 +1,86 @@
+From 43a93893eb33e996836b99fb3e1f7300c0132a51 Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Tue, 31 Dec 2019 18:15:33 +0100
+Subject: [PATCH 5/7] libata: Assign OF node to the SCSI device
+
+When we spawn a SCSI device from an ATA device in libata-scsi
+the SCSI device had no relation to the device tree.
+
+The DT binding allows us to define port nodes under a
+PATA (IDE) or SATA host controller, so we can have proper device
+nodes for these devices.
+
+If OF is enabled, walk the children of the host controller node
+to see if there is a valid device tree node to assign. The reg
+is used to match to ID 0 for the master device and ID 1 for the
+slave device.
+
+The corresponding device tree bindings have been accepted by
+the device tree maintainers.
+
+Cc: Chris Healy <cphealy@gmail.com>
+Cc: Martin K. Petersen <martin.petersen@oracle.com>
+Cc: Bart Van Assche <bvanassche@acm.org>
+Cc: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ChangeLog v1->v2:
+- Use dev_dbg() for the debug print
+- return immediately after finding a matching OF node
+---
+ drivers/ata/libata-scsi.c | 30 ++++++++++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+
+--- a/drivers/ata/libata-scsi.c
++++ b/drivers/ata/libata-scsi.c
+@@ -35,6 +35,7 @@
+ #include <linux/suspend.h>
+ #include <asm/unaligned.h>
+ #include <linux/ioprio.h>
++#include <linux/of.h>
+ 
+ #include "libata.h"
+ #include "libata-transport.h"
+@@ -4590,6 +4591,34 @@ int ata_scsi_add_hosts(struct ata_host *
+ 	return rc;
+ }
+ 
++#ifdef CONFIG_OF
++static void ata_scsi_assign_ofnode(struct ata_device *dev, struct ata_port *ap)
++{
++	struct scsi_device *sdev = dev->sdev;
++	struct device *d = ap->host->dev;
++	struct device_node *np = d->of_node;
++	struct device_node *child;
++
++	for_each_available_child_of_node(np, child) {
++		int ret;
++		u32 val;
++
++		ret = of_property_read_u32(child, "reg", &val);
++		if (ret)
++			continue;
++		if (val == dev->devno) {
++			dev_dbg(d, "found matching device node\n");
++			sdev->sdev_gendev.of_node = child;
++			return;
++		}
++	}
++}
++#else
++static void ata_scsi_assign_ofnode(struct ata_device *dev, struct ata_port *ap)
++{
++}
++#endif
++
+ void ata_scsi_scan_host(struct ata_port *ap, int sync)
+ {
+ 	int tries = 5;
+@@ -4615,6 +4644,7 @@ void ata_scsi_scan_host(struct ata_port
+ 						 NULL);
+ 			if (!IS_ERR(sdev)) {
+ 				dev->sdev = sdev;
++				ata_scsi_assign_ofnode(dev, ap);
+ 				scsi_device_put(sdev);
+ 			} else {
+ 				dev->sdev = NULL;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/834-ledtrig-libata.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/834-ledtrig-libata.patch
new file mode 100644
index 0000000..2fbbb54
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/834-ledtrig-libata.patch
@@ -0,0 +1,149 @@
+From: Daniel Golle <daniel@makrotopia.org>
+Subject: libata: add ledtrig support
+
+This adds a LED trigger for each ATA port indicating disk activity.
+
+As this is needed only on specific platforms (NAS SoCs and such),
+these platforms should define ARCH_WANTS_LIBATA_LEDS if there
+are boards with LED(s) intended to indicate ATA disk activity and
+need the OS to take care of that.
+In that way, if not selected, LED trigger support not will be
+included in libata-core and both, codepaths and structures remain
+untouched.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/ata/Kconfig       | 16 ++++++++++++++++
+ drivers/ata/libata-core.c | 41 +++++++++++++++++++++++++++++++++++++++++
+ include/linux/libata.h    |  9 +++++++++
+ 3 files changed, 66 insertions(+)
+
+--- a/drivers/ata/Kconfig
++++ b/drivers/ata/Kconfig
+@@ -45,6 +45,22 @@ config ATA_VERBOSE_ERROR
+ 
+ 	  If unsure, say Y.
+ 
++config ARCH_WANT_LIBATA_LEDS
++	bool
++
++config ATA_LEDS
++	bool "support ATA port LED triggers"
++	depends on ARCH_WANT_LIBATA_LEDS
++	select NEW_LEDS
++	select LEDS_CLASS
++	select LEDS_TRIGGERS
++	default y
++	help
++	  This option adds a LED trigger for each registered ATA port.
++	  It is used to drive disk activity leds connected via GPIO.
++
++	  If unsure, say N.
++
+ config ATA_ACPI
+ 	bool "ATA ACPI Support"
+ 	depends on ACPI
+--- a/drivers/ata/libata-core.c
++++ b/drivers/ata/libata-core.c
+@@ -714,6 +714,19 @@ u64 ata_tf_read_block(const struct ata_t
+ 	return block;
+ }
+ 
++#ifdef CONFIG_ATA_LEDS
++#define LIBATA_BLINK_DELAY 20 /* ms */
++static inline void ata_led_act(struct ata_port *ap)
++{
++	unsigned long led_delay = LIBATA_BLINK_DELAY;
++
++	if (unlikely(!ap->ledtrig))
++		return;
++
++	led_trigger_blink_oneshot(ap->ledtrig, &led_delay, &led_delay, 0);
++}
++#endif
++
+ /**
+  *	ata_build_rw_tf - Build ATA taskfile for given read/write request
+  *	@tf: Target ATA taskfile
+@@ -5152,6 +5165,9 @@ struct ata_queued_cmd *ata_qc_new_init(s
+ 		if (tag < 0)
+ 			return NULL;
+ 	}
++#ifdef CONFIG_ATA_LEDS
++	ata_led_act(ap);
++#endif
+ 
+ 	qc = __ata_qc_from_tag(ap, tag);
+ 	qc->tag = qc->hw_tag = tag;
+@@ -6088,6 +6104,9 @@ struct ata_port *ata_port_alloc(struct a
+ 	ap->stats.unhandled_irq = 1;
+ 	ap->stats.idle_irq = 1;
+ #endif
++#ifdef CONFIG_ATA_LEDS
++	ap->ledtrig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
++#endif
+ 	ata_sff_port_init(ap);
+ 
+ 	return ap;
+@@ -6123,6 +6142,12 @@ static void ata_host_release(struct kref
+ 
+ 		kfree(ap->pmp_link);
+ 		kfree(ap->slave_link);
++#ifdef CONFIG_ATA_LEDS
++		if (ap->ledtrig) {
++			led_trigger_unregister(ap->ledtrig);
++			kfree(ap->ledtrig);
++		};
++#endif
+ 		kfree(ap);
+ 		host->ports[i] = NULL;
+ 	}
+@@ -6586,7 +6611,23 @@ int ata_host_register(struct ata_host *h
+ 		host->ports[i]->print_id = atomic_inc_return(&ata_print_id);
+ 		host->ports[i]->local_port_no = i + 1;
+ 	}
++#ifdef CONFIG_ATA_LEDS
++	for (i = 0; i < host->n_ports; i++) {
++		if (unlikely(!host->ports[i]->ledtrig))
++			continue;
+ 
++		snprintf(host->ports[i]->ledtrig_name,
++			sizeof(host->ports[i]->ledtrig_name), "ata%u",
++			host->ports[i]->print_id);
++
++		host->ports[i]->ledtrig->name = host->ports[i]->ledtrig_name;
++
++		if (led_trigger_register(host->ports[i]->ledtrig)) {
++			kfree(host->ports[i]->ledtrig);
++			host->ports[i]->ledtrig = NULL;
++		}
++	}
++#endif
+ 	/* Create associated sysfs transport objects  */
+ 	for (i = 0; i < host->n_ports; i++) {
+ 		rc = ata_tport_add(host->dev,host->ports[i]);
+--- a/include/linux/libata.h
++++ b/include/linux/libata.h
+@@ -23,6 +23,9 @@
+ #include <linux/cdrom.h>
+ #include <linux/sched.h>
+ #include <linux/async.h>
++#ifdef CONFIG_ATA_LEDS
++#include <linux/leds.h>
++#endif
+ 
+ /*
+  * Define if arch has non-standard setup.  This is a _PCI_ standard
+@@ -882,6 +885,12 @@ struct ata_port {
+ #ifdef CONFIG_ATA_ACPI
+ 	struct ata_acpi_gtm	__acpi_init_gtm; /* use ata_acpi_init_gtm() */
+ #endif
++
++#ifdef CONFIG_ATA_LEDS
++	struct led_trigger	*ledtrig;
++	char			ledtrig_name[8];
++#endif
++
+ 	/* owned by EH */
+ 	u8			sector_buf[ATA_SECT_SIZE] ____cacheline_aligned;
+ };
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/840-hwrng-bcm2835-set-quality-to-1000.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/840-hwrng-bcm2835-set-quality-to-1000.patch
new file mode 100644
index 0000000..247c6d8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/840-hwrng-bcm2835-set-quality-to-1000.patch
@@ -0,0 +1,26 @@
+From d6988cf1d16faac56899918bb2b1be8d85155e3f Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
+Date: Sat, 20 Feb 2021 18:36:38 +0100
+Subject: [PATCH] hwrng: bcm2835: set quality to 1000
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This allows devices without a high precission timer to reduce boot from >100s
+to <30s.
+
+Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
+---
+ drivers/char/hw_random/bcm2835-rng.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/char/hw_random/bcm2835-rng.c
++++ b/drivers/char/hw_random/bcm2835-rng.c
+@@ -167,6 +167,7 @@ static int bcm2835_rng_probe(struct plat
+ 	priv->rng.init = bcm2835_rng_init;
+ 	priv->rng.read = bcm2835_rng_read;
+ 	priv->rng.cleanup = bcm2835_rng_cleanup;
++	priv->rng.quality = 1000;
+ 
+ 	if (dev_of_node(dev)) {
+ 		rng_id = of_match_node(bcm2835_rng_of_match, np);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/920-mangle_bootargs.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/920-mangle_bootargs.patch
new file mode 100644
index 0000000..09782e9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/920-mangle_bootargs.patch
@@ -0,0 +1,71 @@
+From: Imre Kaloz <kaloz@openwrt.org>
+Subject: init: add CONFIG_MANGLE_BOOTARGS and disable it by default
+
+Enabling this option renames the bootloader supplied root=
+and rootfstype= variables, which might have to be know but
+would break the automatisms OpenWrt uses.
+
+Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
+---
+ init/Kconfig |  9 +++++++++
+ init/main.c  | 24 ++++++++++++++++++++++++
+ 2 files changed, 33 insertions(+)
+
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1675,6 +1675,15 @@ config EMBEDDED
+ 	  an embedded system so certain expert options are available
+ 	  for configuration.
+ 
++config MANGLE_BOOTARGS
++	bool "Rename offending bootargs"
++	depends on EXPERT
++	help
++	  Sometimes the bootloader passed bogus root= and rootfstype=
++	  parameters to the kernel, and while you want to ignore them,
++	  you need to know the values f.e. to support dual firmware
++	  layouts on the flash.
++
+ config HAVE_PERF_EVENTS
+ 	bool
+ 	help
+--- a/init/main.c
++++ b/init/main.c
+@@ -367,6 +367,29 @@ static inline void setup_nr_cpu_ids(void
+ static inline void smp_prepare_cpus(unsigned int maxcpus) { }
+ #endif
+ 
++#ifdef CONFIG_MANGLE_BOOTARGS
++static void __init mangle_bootargs(char *command_line)
++{
++	char *rootdev;
++	char *rootfs;
++
++	rootdev = strstr(command_line, "root=/dev/mtdblock");
++
++	if (rootdev)
++		strncpy(rootdev, "mangled_rootblock=", 18);
++
++	rootfs = strstr(command_line, "rootfstype");
++
++	if (rootfs)
++		strncpy(rootfs, "mangled_fs", 10);
++
++}
++#else
++static void __init mangle_bootargs(char *command_line)
++{
++}
++#endif
++
+ /*
+  * We need to store the untouched command line for future reference.
+  * We also need to store the touched command line since the parameter
+@@ -597,6 +620,7 @@ asmlinkage __visible void __init start_k
+ 	pr_notice("%s", linux_banner);
+ 	early_security_init();
+ 	setup_arch(&command_line);
++	mangle_bootargs(command_line);
+ 	setup_command_line(command_line);
+ 	setup_nr_cpu_ids();
+ 	setup_per_cpu_areas();
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/pending-5.4.inc b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/pending-5.4.inc
new file mode 100644
index 0000000..620dca6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/pending-5.4.inc
@@ -0,0 +1,132 @@
+#patch pending-5.4 (come from openwrt/lede/target/linux/mediatek)
+SRC_URI_append = " \
+    file://0931-w1-gpio-fix-problem-with-platfom-data-in-w1-gpio.patch \
+    file://102-MIPS-only-process-negative-stack-offsets-on-stack-tr.patch \
+    file://103-MIPS-select-CPU_MIPS64-for-remaining-MIPS64-CPUs.patch \
+    file://110-ehci_hcd_ignore_oc.patch \
+    file://120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch \
+    file://130-add-linux-spidev-compatible-si3210.patch \
+    file://140-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch \
+    file://141-jffs2-add-RENAME_EXCHANGE-support.patch \
+    file://150-bridge_allow_receiption_on_disabled_port.patch \
+    file://180-net-phy-at803x-add-support-for-AT8032.patch \
+    file://190-rtc-rs5c372-support_alarms_up_to_1_week.patch \
+    file://191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch \
+    file://201-extra_optimization.patch \
+    file://203-kallsyms_uncompressed.patch \
+    file://205-backtrace_module_info.patch \
+    file://240-remove-unsane-filenames-from-deps_initramfs-list.patch \
+    file://261-enable_wilink_platform_without_drivers.patch \
+    file://270-platform-mikrotik-build-bits.patch \
+    file://300-mips_expose_boot_raw.patch \
+    file://302-mips_no_branch_likely.patch \
+    file://305-mips_module_reloc.patch \
+    file://307-mips_highmem_offset.patch \
+    file://308-mips32r2_tune.patch \
+    file://309-MIPS-Add-CPU-option-reporting-to-proc-cpuinfo.patch \
+    file://310-arm_module_unresolved_weak_sym.patch \
+    file://311-MIPS-zboot-put-appended-dtb-into-a-section.patch \
+    file://330-MIPS-kexec-Accept-command-line-parameters-from-users.patch \
+    file://332-arc-add-OWRTDTB-section.patch \
+    file://333-arc-enable-unaligned-access-in-kernel-mode.patch \
+    file://342-powerpc-Enable-kernel-XZ-compression-option-on-PPC_8.patch \
+    file://400-mtd-add-rootfs-split-support.patch \
+    file://401-mtd-add-support-for-different-partition-parser-types.patch \
+    file://402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch \
+    file://403-mtd-hook-mtdsplit-to-Kbuild.patch \
+    file://404-mtd-add-more-helper-functions.patch \
+    file://410-mtd-parsers-ofpart-fix-parsing-subpartitions.patch \
+    file://411-mtd-partial_eraseblock_write.patch \
+    file://412-mtd-partial_eraseblock_unlock.patch \
+    file://419-mtd-redboot-add-of_match_table-with-DT-binding.patch \
+    file://420-mtd-redboot_space.patch \
+    file://430-mtd-add-myloader-partition-parser.patch \
+    file://431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch \
+    file://432-mtd-bcm47xxpart-detect-T_Meter-partition.patch \
+    file://435-mtd-add-routerbootpart-parser-config.patch \
+    file://447-mtd-spinand-gigadevice-Add-support-for-GD5F4GQ4xC.patch \
+    file://450-mtd-spi-nor-allow-NOR-driver-to-write-fewer-bytes-th.patch \
+    file://460-mtd-cfi_cmdset_0002-no-erase_suspend.patch \
+    file://461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch \
+    file://465-m25p80-mx-disable-software-protection.patch \
+    file://466-Revert-mtd-spi-nor-fix-Spansion-regressions-aliased-.patch \
+    file://470-mtd-spi-nor-support-limiting-4K-sectors-support-base.patch \
+    file://476-mtd-spi-nor-add-eon-en25q128.patch \
+    file://479-mtd-spi-nor-add-xtx-xt25f128b.patch \
+    file://480-mtd-set-rootfs-to-be-root-dev.patch \
+    file://481-mtd-spi-nor-rework-broken-flash-reset-support.patch \
+    file://482-mtd-spi-nor-add-support-for-Gigadevice-GD25D05.patch \
+    file://482-mtd-spi-nor-fix-4-byte-opcode-support-for-w25q256.patch \
+    file://490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch \
+    file://491-ubi-auto-create-ubiblock-device-for-rootfs.patch \
+    file://492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch \
+    file://493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch \
+    file://494-mtd-ubi-add-EOF-marker-support.patch \
+    file://495-mtd-core-add-get_mtd_device_by_node.patch \
+    file://496-dt-bindings-add-bindings-for-mtd-concat-devices.patch \
+    file://497-mtd-mtdconcat-add-dt-driver-for-concat-devices.patch \
+    file://498-mtd-mtdconcat-select-readwrite-function.patch \
+    file://499-mtd-add-nmbm-support.patch \
+    file://530-jffs2_make_lzma_available.patch \
+    file://532-jffs2_eofdetect.patch \
+    file://600-netfilter_conntrack_flush.patch \
+    file://610-netfilter_match_bypass_default_checks.patch \
+    file://611-netfilter_match_bypass_default_table.patch \
+    file://612-netfilter_match_reduce_memory_access.patch \
+    file://613-netfilter_optional_tcp_window_check.patch \
+    file://620-net_sched-codel-do-not-defer-queue-length-update.patch \
+    file://630-packet_socket_type.patch \
+    file://640-netfilter-nf_flow_table-add-hardware-offload-support.patch \
+    file://641-netfilter-nf_flow_table-support-hw-offload-through-v.patch \
+    file://642-net-8021q-support-hardware-flow-table-offload.patch \
+    file://643-net-bridge-support-hardware-flow-table-offload.patch \
+    file://644-net-pppoe-support-hardware-flow-table-offload.patch \
+    file://645-netfilter-nf_flow_table-rework-hardware-offload-time.patch \
+    file://646-netfilter-nf_flow_table-rework-private-driver-data.patch \
+    file://647-net-dsa-support-hardware-flow-table-offload.patch \
+    file://655-increase_skb_pad.patch \
+    file://666-Add-support-for-MAP-E-FMRs-mesh-mode.patch \
+    file://670-ipv6-allow-rejecting-with-source-address-failed-policy.patch \
+    file://671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch \
+    file://680-NET-skip-GRO-for-foreign-MAC-addresses.patch \
+    file://681-NET-add-of_get_mac_address_mtd.patch \
+    file://703-phy-add-detach-callback-to-struct-phy_driver.patch \
+    file://735-net-phy-at803x-fix-at8033-sgmii-mode.patch \
+    file://739-net-avoid-tx-fault-with-Nokia-GPON-module.patch \
+    file://740-net-sfp-remove-incomplete-100BASE-FX-and-100BASE-LX-.patch \
+    file://741-net-sfp-derive-interface-mode-from-ethtool-link-mode.patch \
+    file://742-net-sfp-add-more-extended-compliance-codes.patch \
+    file://743-net-sfp-add-module-start-stop-upstream-notifications.patch \
+    file://744-net-sfp-move-phy_start-phy_stop-to-phylink.patch \
+    file://745-net-mdio-i2c-add-support-for-Clause-45-accesses.patch \
+    file://746-net-phylink-re-split-__phylink_connect_phy.patch \
+    file://747-net-phylink-support-Clause-45-PHYs-on-SFP-modules.patch \
+    file://748-net-phylink-split-link_an_mode-configured-and-curren.patch \
+    file://749-net-phylink-split-phylink_sfp_module_insert.patch \
+    file://750-net-phylink-delay-MAC-configuration-for-copper-SFP-m.patch \
+    file://751-net-phylink-make-Broadcom-BCM84881-based-SFPs-work.patch \
+    file://752-net-phy-add-Broadcom-BCM84881-PHY-driver.patch \
+    file://753-net-sfp-add-support-for-Clause-45-PHYs.patch \
+    file://754-net-sfp-fix-unbind.patch \
+    file://755-net-sfp-fix-hwmon.patch \
+    file://756-net-sfp-use-a-definition-for-the-fault-recovery-atte.patch \
+    file://757-net-sfp-rename-sm_retries.patch \
+    file://758-net-sfp-error-handling-for-phy-probe.patch \
+    file://759-net-sfp-re-attempt-probing-for-phy.patch \
+    file://760-net-dsa-mv88e6xxx-fix-vlan-setup.patch \
+    file://761-net-dsa-mt7530-Support-EEE-features.patch \
+    file://762-net-bridge-switchdev-Refactor-br_switchdev_fdb_notif.patch \
+    file://763-net-bridge-switchdev-Include-local-flag-in-FDB-notif.patch \
+    file://764-net-bridge-switchdev-Send-FDB-notifications-for-host.patch \
+    file://765-net-dsa-Include-local-addresses-in-assisted-CPU-port.patch \
+    file://766-net-dsa-Include-bridge-addresses-in-assisted-CPU-por.patch \
+    file://767-net-dsa-Sync-static-FDB-entries-on-foreign-interface.patch \
+    file://768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch \
+    file://800-bcma-get-SoC-device-struct-copy-its-DMA-params-to-th.patch \
+    file://810-pci_disable_common_quirks.patch \
+    file://811-pci_disable_usb_common_quirks.patch \
+    file://820-libata-Assign-OF-node-to-the-SCSI-device.patch \
+    file://834-ledtrig-libata.patch \
+    file://840-hwrng-bcm2835-set-quality-to-1000.patch \
+    file://920-mangle_bootargs.patch \
+    "
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986-clkitg.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986-clkitg.dtsi
new file mode 100644
index 0000000..70b56f2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986-clkitg.dtsi
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Wenzhen.Yu <Wenzhen.Yu@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&clkitg {
+	bring-up {
+		compatible = "mediatek,clk-bring-up";
+		clocks =
+			<&apmixedsys CK_APMIXED_ARMPLL>,
+			<&apmixedsys  CK_APMIXED_NET2PLL>,
+			<&apmixedsys  CK_APMIXED_MMPLL>,
+			<&apmixedsys  CK_APMIXED_SGMPLL>,
+			<&apmixedsys  CK_APMIXED_WEDMCUPLL>,
+			<&apmixedsys  CK_APMIXED_NET1PLL>,
+			<&apmixedsys  CK_APMIXED_MPLL>,
+			<&apmixedsys  CK_APMIXED_APLL2>,
+			<&infracfg CK_INFRA_CK_F26M>,
+			<&infracfg CK_INFRA_UART>,
+			<&clk40m>,
+			<&infracfg CK_INFRA_I2C>,
+			<&clk40m>,
+			<&infracfg CK_INFRA_PWM>,
+			<&infracfg CK_INFRA_66M_MCK>,
+			<&infracfg CK_INFRA_CK_F32K>,
+			<&clk40m>,
+			<&infracfg CK_INFRA_PWM_BCK>,
+			<&infracfg CK_INFRA_PWM_CK1>,
+			<&infracfg CK_INFRA_PWM_CK2>,
+			<&infracfg CK_INFRA_133M_HCK>,
+			<&infracfg CK_INFRA_EIP_CK>,
+			<&infracfg CK_INFRA_66M_PHCK>,
+			<&infracfg CK_INFRA_FAUD_L_CK	>,
+			<&infracfg CK_INFRA_FAUD_AUD_CK>,
+			<&infracfg CK_INFRA_FAUD_EG2_CK>,
+			<&infracfg CK_INFRA_I2CS_CK>,
+			<&infracfg CK_INFRA_MUX_UART0>,
+			<&infracfg CK_INFRA_MUX_UART1>,
+			<&infracfg CK_INFRA_MUX_UART2>,
+			<&infracfg CK_INFRA_NFI_CK>,
+			<&infracfg CK_INFRA_SPINFI_CK>,
+			<&clk40m>,
+			<&clk40m>,
+			<&infracfg CK_INFRA_RTC_32K>,
+			<&infracfg CK_INFRA_FMSDC_CK>,
+			<&infracfg CK_INFRA_FMSDC_HCK_CK>,
+			<&infracfg CK_INFRA_PERI_133M>,
+			<&infracfg CK_INFRA_133M_PHCK>,
+			<&infracfg CK_INFRA_USB_SYS_CK>,
+			<&infracfg CK_INFRA_USB_CK>,
+			<&infracfg CK_INFRA_USB_XHCI_CK>,
+			<&clk40m>,
+			<&infracfg CK_INFRA_F26M_CK0>,
+			<&infracfg_ao CK_INFRA_UART0_SEL>,
+			<&infracfg_ao CK_INFRA_UART1_SEL>,	
+			<&infracfg_ao CK_INFRA_UART2_SEL>,
+			<&clk40m>,
+			<&clk40m>,
+			<&infracfg_ao CK_INFRA_PWM1_SEL>,
+			<&infracfg_ao CK_INFRA_PWM2_SEL>,
+			<&infracfg_ao CK_INFRA_PWM_BSEL>,
+			<&clk40m>,
+			<&clk40m>,
+			<&infracfg_ao CK_INFRA_PWM_HCK>,
+			<&infracfg_ao CK_INFRA_PWM_STA>,
+			<&infracfg_ao CK_INFRA_PWM1_CK>,
+			<&infracfg_ao CK_INFRA_PWM2_CK>,
+			<&infracfg_ao CK_INFRA_CQ_DMA_CK>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&infracfg_ao CK_INFRA_DRAMC_26M_CK>,
+			<&clk40m>,
+			<&infracfg_ao CK_INFRA_AP_DMA_CK>,
+			<&infracfg_ao CK_INFRA_SEJ_CK>,
+			<&infracfg_ao CK_INFRA_SEJ_13M_CK>,
+			<&clk40m>,
+			<&infracfg_ao CK_INFRA_I2CO_CK>,
+			<&infracfg_ao CK_INFRA_UART0_CK>,
+			<&infracfg_ao CK_INFRA_UART1_CK>,
+			<&infracfg_ao CK_INFRA_UART2_CK>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&infracfg_ao CK_INFRA_FRTC_CK>,
+			<&infracfg_ao CK_INFRA_MSDC_CK>,
+			<&infracfg_ao CK_INFRA_MSDC_HCK_CK>,
+			<&infracfg_ao CK_INFRA_MSDC_133M_CK>,
+			<&infracfg_ao CK_INFRA_MSDC_66M_CK>,
+			<&clk40m>,
+			<&clk40m>,
+			<&infracfg_ao CK_INFRA_FBIST2FPC_CK>,
+			<&infracfg_ao CK_INFRA_IUSB_133_CK>,
+			<&infracfg_ao CK_INFRA_IUSB_66M_CK>,
+			<&infracfg_ao CK_INFRA_IUSB_SYS_CK>,
+			<&infracfg_ao CK_INFRA_IUSB_CK>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&topckgen CK_TOP_CB_M_416M>,
+			<&clk40m>,
+			<&topckgen CK_TOP_CB_M_D4>,
+			<&topckgen CK_TOP_CB_M_D8>,
+			<&topckgen CK_TOP_M_D8_D2>,
+			<&topckgen CK_TOP_M_D3_D2>,
+			<&topckgen CK_TOP_CB_MM_D2>,
+			<&topckgen CK_TOP_CB_MM_D4>,
+			<&topckgen CK_TOP_CB_MM_D8>,
+			<&topckgen CK_TOP_MM_D8_D2>,
+			<&topckgen CK_TOP_MM_D3_D8>,
+			<&topckgen CK_TOP_CB_U2_PHYD_CK>,
+			<&topckgen CK_TOP_CB_APLL2_196M>,
+			<&topckgen CK_TOP_APLL2_D4>,
+			<&topckgen CK_TOP_CB_NET1_D4>,
+			<&topckgen CK_TOP_CB_NET1_D5>,
+			<&topckgen CK_TOP_NET1_D5_D2>,
+			<&topckgen CK_TOP_NET1_D5_D4>,
+			<&topckgen CK_TOP_NET1_D8_D2>,
+			<&topckgen CK_TOP_NET1_D8_D4>,
+			<&topckgen CK_TOP_CB_NET2_800M>,
+			<&topckgen CK_TOP_CB_NET2_D4>,
+			<&topckgen CK_TOP_NET2_D4_D2>,
+			<&topckgen CK_TOP_NET2_D3_D2>,
+			<&topckgen CK_TOP_CB_WEDMCU_760M>,
+			<&topckgen CK_TOP_WEDMCU_D5_D2	>,
+			<&topckgen CK_TOP_CB_SGM_325M>,
+			<&topckgen CK_TOP_CB_CKSQ_40M_D2>,
+			<&topckgen CK_TOP_CB_RTC_32K>,
+			<&topckgen CK_TOP_CB_RTC_32P7K>,
+			<&topckgen CK_TOP_NFI1X>,
+			<&topckgen CK_TOP_USB_EQ_RX250M>,
+			<&topckgen CK_TOP_USB_TX250M>,
+			<&topckgen CK_TOP_USB_LN0_CK>,
+			<&topckgen CK_TOP_USB_CDR_CK>,
+			<&topckgen CK_TOP_SPINFI_BCK>,
+			<&topckgen CK_TOP_I2C_BCK>,
+			<&topckgen CK_TOP_PEXTP_TL>,
+			<&topckgen CK_TOP_EMMC_250M>,
+			<&topckgen CK_TOP_EMMC_416M>,
+			<&topckgen CK_TOP_F_26M_ADC_CK>,
+			<&topckgen CK_TOP_SYSAXI>,
+			<&topckgen CK_TOP_NETSYS_WED_MCU>,
+			<&topckgen CK_TOP_NETSYS_2X>,
+			<&topckgen CK_TOP_SGM_325M>,
+			<&topckgen CK_TOP_A1SYS>,
+			<&topckgen CK_TOP_EIP_B>,
+			<&topckgen CK_TOP_F26M>,
+			<&topckgen CK_TOP_AUD_L>,
+			<&topckgen CK_TOP_A_TUNER>,
+			<&topckgen CK_TOP_U2U3_REF>,
+			<&topckgen CK_TOP_U2U3_SYS>,
+			<&topckgen CK_TOP_U2U3_XHCI>,
+			<&topckgen CK_TOP_AP2CNN_HOST>,
+			<&topckgen CK_TOP_NFI1X_SEL>,
+			<&topckgen CK_TOP_SPINFI_SEL>,
+			<&clk40m>,
+			<&clk40m>,
+			<&topckgen CK_TOP_UART_SEL>,
+			<&topckgen CK_TOP_PWM_SEL>,
+			<&topckgen CK_TOP_I2C_SEL>,
+			<&topckgen CK_TOP_PEXTP_TL_SEL>,
+			<&topckgen CK_TOP_EMMC_250M_SEL	>,
+			<&topckgen CK_TOP_EMMC_416M_SEL	>,
+			<&topckgen CK_TOP_F_26M_ADC_SEL>,
+			<&topckgen CK_TOP_DRAMC_SEL>,
+			<&topckgen CK_TOP_DRAMC_MD32_SEL>,
+			<&topckgen CK_TOP_SYSAXI_SEL>,
+			<&topckgen CK_TOP_SYSAPB_SEL>,
+			<&topckgen CK_TOP_ARM_DB_MAIN_SEL>,
+			<&clk40m>,
+			<&topckgen CK_TOP_NETSYS_SEL>,
+			<&topckgen CK_TOP_NETSYS_500M_SEL>,
+			<&topckgen CK_TOP_NETSYS_MCU_SEL>,
+			<&topckgen CK_TOP_NETSYS_2X_SEL>,
+			<&topckgen CK_TOP_SGM_325M_SEL>,
+			<&topckgen CK_TOP_SGM_REG_SEL>,
+			<&clk40m>,
+			<&topckgen CK_TOP_CONN_MCUSYS_SEL>,
+			<&clk40m>,
+			<&topckgen CK_TOP_PCIE_PHY_SEL>,
+			<&topckgen CK_TOP_USB3_PHY_SEL>,
+			<&topckgen CK_TOP_F26M_SEL>,
+			<&clk40m>,
+			<&clk40m>,
+			<&topckgen CK_TOP_U2U3_SEL>,
+			<&topckgen CK_TOP_U2U3_SYS_SEL>,
+			<&topckgen CK_TOP_U2U3_XHCI_SEL>,
+			<&topckgen CK_TOP_DA_U2_REFSEL>,
+			<&topckgen CK_TOP_DA_U2_CK_1P_SEL>,
+			<&topckgen CK_TOP_AP2CNN_HOST_SEL>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>;
+
+
+		clock-names = "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11",
+		"12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23",
+		"24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35",
+		"36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47",
+		"48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
+		"60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71",
+		"72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83",
+		"84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95",
+		"96", "97", "98", "99", "100", "101", "102", "103", "104", "105", "106", "107",
+		"108", "109", "110", "111", "112", "113", "114", "115", "116", "117",
+		"118", "119", "120", "121", "122", "123",
+		"124", "125", "126", "127", "128", "129", "130", "131", "132", "133", "134", "135",
+		"136", "137", "138", "139", "140", "141", "142", "143", "144", "145", "146", "147",
+		"148", "149", "150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
+		"160", "161", "162", "163", "164", "165", "166", "167", "168", "169", "170", "171",
+		"172", "173", "174", "175", "176", "177", "178", "179", "180", "181", "182", "183",
+		"184", "185", "186", "187", "188", "189", "190", "191", "192", "193", "194", "195",
+		"196", "197", "198", "199", "200", "201", "202", "203", "204", "205", "206", "207",
+		"208", "209", "210", "211", "212", "213", "214", "215", "216", "217", "218", "219", "220", "221";
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986-fpga-ubi.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986-fpga-ubi.dts
new file mode 100644
index 0000000..8604918
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986-fpga-ubi.dts
@@ -0,0 +1,163 @@
+/dts-v1/;
+#include "mt7986-fpga.dtsi"
+/ {
+	model = "MediaTek MT7986 FPGA (UBI)";
+	compatible = "mediatek,mt7986-fpga,ubi";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		// fpga ddr2: 128MB*2
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	status = "okay";
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <500000>;
+
+		partition@00000 {
+			label = "BL2";
+			reg = <0x00000 0x0060000>;
+		};
+		partition@60000 {
+			label = "u-boot-env";
+			reg = <0x60000 0x0010000>;
+		};
+		partition@70000 {
+			label = "Factory";
+			reg = <0x70000 0x00B0000>;
+		};
+		partition@120000 {
+			label = "BL31";
+			reg = <0x120000 0x0010000>;
+		};
+		partition@130000 {
+			label = "u-boot";
+			reg = <0x130000 0x00D0000>;
+		};
+		partition@200000 {
+			label = "firmware";
+			reg = <0x200000 0xE00000>;
+		};
+	};
+	spi_nand@1 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-max-frequency = <500000>;
+
+		partition@00000 {
+			label = "BL2";
+			reg = <0x00000 0x0100000>;
+		};
+		partition@100000 {
+			label = "u-boot-env";
+			reg = <0x100000 0x0080000>;
+		};
+		partition@180000 {
+			label = "Factory";
+			reg = <0x180000 0x00200000>;
+		};
+		partition@380000 {
+			label = "BL31";
+			reg = <0x380000 0x0080000>;
+		};
+		partition@400000 {
+			label = "u-boot";
+			reg = <0x400000 0x0180000>;
+		};
+		partition@580000 {
+			label = "firmware";
+			reg = <0x580000 0x7a80000>;
+		};
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	/* pin shared with snfi */
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&pio {
+	spi_flash_pins: spi0-pins {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+	};
+
+	snfi_pins: snfi-pins {
+		mux {
+			function = "flash";
+			groups = "snfi";
+		};
+	};
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&snand {
+	pinctrl-names = "default";
+	/* pin shared with spic */
+	pinctrl-0 = <&snfi_pins>;
+	status = "okay";
+	mediatek,quad-spi;
+
+	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 0x0200000>;
+		};
+
+		partition@380000 {
+			label = "FIP";
+			reg = <0x380000 0x0200000>;
+		};
+
+		partition@580000 {
+			label = "ubi";
+			reg = <0x580000 0x4000000>;
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986-fpga.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986-fpga.dts
new file mode 100644
index 0000000..37f93c0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986-fpga.dts
@@ -0,0 +1,163 @@
+/dts-v1/;
+#include "mt7986-fpga.dtsi"
+/ {
+	model = "MediaTek MT7986 FPGA";
+	compatible = "mediatek,mt7986-fpga";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		// fpga ddr2: 128MB*2
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	status = "okay";
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <500000>;
+
+		partition@00000 {
+			label = "BL2";
+			reg = <0x00000 0x0060000>;
+		};
+		partition@60000 {
+			label = "u-boot-env";
+			reg = <0x60000 0x0010000>;
+		};
+		partition@70000 {
+			label = "Factory";
+			reg = <0x70000 0x00B0000>;
+		};
+		partition@120000 {
+			label = "BL31";
+			reg = <0x120000 0x0010000>;
+		};
+		partition@130000 {
+			label = "u-boot";
+			reg = <0x130000 0x00D0000>;
+		};
+		partition@200000 {
+			label = "firmware";
+			reg = <0x200000 0xE00000>;
+		};
+	};
+	spi_nand@1 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-max-frequency = <500000>;
+
+		partition@00000 {
+			label = "BL2";
+			reg = <0x00000 0x0100000>;
+		};
+		partition@100000 {
+			label = "u-boot-env";
+			reg = <0x100000 0x0080000>;
+		};
+		partition@180000 {
+			label = "Factory";
+			reg = <0x180000 0x00200000>;
+		};
+		partition@380000 {
+			label = "BL31";
+			reg = <0x380000 0x0080000>;
+		};
+		partition@400000 {
+			label = "u-boot";
+			reg = <0x400000 0x0180000>;
+		};
+		partition@580000 {
+			label = "firmware";
+			reg = <0x580000 0x7a80000>;
+		};
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	/* pin shared with snfi */
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&pio {
+	spi_flash_pins: spi0-pins {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+	};
+
+	snfi_pins: snfi-pins {
+		mux {
+			function = "flash";
+			groups = "snfi";
+		};
+	};
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&snand {
+	pinctrl-names = "default";
+	/* pin shared with spic */
+	pinctrl-0 = <&snfi_pins>;
+	status = "okay";
+	mediatek,quad-spi;
+
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		partition@0 {
+			label = "BL2";
+			reg = <0x00000 0x0080000>;
+			read-only;
+		};
+
+		partition@80000 {
+			label = "FIP";
+			reg = <0x80000 0x0200000>;
+		};
+
+		partition@280000 {
+			label = "u-boot-env";
+			reg = <0x280000 0x0080000>;
+		};
+
+		partition@300000 {
+			label = "Factory";
+			reg = <0x300000 0x0080000>;
+		};
+
+		partition@380000 {
+			label = "firmware";
+			reg = <0x380000 0x7c00000>;
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986-fpga.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986-fpga.dtsi
new file mode 100644
index 0000000..12a0234
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986-fpga.dtsi
@@ -0,0 +1,427 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Sam.Shih <sam.shih@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/phy/phy.h>
+#include <dt-bindings/reset/ti-syscon.h>
+/ {
+	compatible = "mediatek,mt7986-fpga";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			enable-method = "psci";
+			reg = <0x0>;
+		};
+
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			enable-method = "psci";
+			reg = <0x1>;
+		};
+	};
+
+	wed: wed@15010000 {
+		compatible = "mediatek,wed";
+		wed_num = <2>;
+		/* add this property for wed get the pci slot number. */
+		pci_slot_map = <0>, <1>;
+		reg = <0 0x15010000 0 0x1000>,
+		      <0 0x15011000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	wed2: wed2@15011000 {
+		compatible = "mediatek,wed2";
+		wed_num = <2>;
+		reg = <0 0x15010000 0 0x1000>,
+		      <0 0x15011000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	wdma: wdma@15104800 {
+		compatible = "mediatek,wed-wdma";
+		reg = <0 0x15104800 0 0x400>,
+		      <0 0x15104c00 0 0x400>;
+	};
+
+	ap2woccif: ap2woccif@151A5000 {
+		compatible = "mediatek,ap2woccif";
+		reg = <0 0x151A5000 0 0x1000>,
+		      <0 0x151AD000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>;
+        };
+
+	wocpu0_ilm: wocpu0_ilm@151E0000 {
+		compatible = "mediatek,wocpu0_ilm";
+		reg = <0 0x151E0000 0 0x8000>;
+	};
+
+        wocpu1_ilm: wocpu1_ilm@151F0000 {
+                compatible = "mediatek,wocpu1_ilm";
+                reg = <0 0x151F0000 0 0x8000>;
+        };
+
+	wocpu_dlm: wocpu_dlm@151E8000 {
+		compatible = "mediatek,wocpu_dlm";
+		reg = <0 0x151E8000 0 0x2000>,
+		      <0 0x151F8000 0 0x2000>;
+
+		resets = <&ethsysrst 0>;
+		reset-names = "wocpu_rst";
+	};
+
+	cpu_boot: wocpu_boot@15194000 {
+		compatible = "mediatek,wocpu_boot";
+		reg = <0 0x15194000 0 0x1000>;
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		/* 192 KiB reserved for ARM Trusted Firmware (BL31) */
+		secmon_reserved: secmon@43000000 {
+			reg = <0 0x43000000 0 0x30000>;
+			no-map;
+		};
+
+		wmcpu_emi: wmcpu-reserved@4FC00000 {
+			compatible = "mediatek,wmcpu-reserved";
+			no-map;
+			reg = <0 0x4FC00000 0 0x00100000>;
+		};
+
+		wocpu0_emi: wocpu0_emi@4FD00000 {
+			compatible = "mediatek,wocpu0_emi";
+			no-map;
+			reg = <0 0x4FD00000 0 0x40000>;
+			shared = <0>;
+		};
+
+		wocpu1_emi: wocpu1_emi@4FD80000 {
+			compatible = "mediatek,wocpu1_emi";
+			no-map;
+			reg = <0 0x4FD40000 0 0x40000>;
+			shared = <0>;
+		};
+
+		wocpu_data: wocpu_data@4FE00000 {
+			compatible = "mediatek,wocpu_data";
+			no-map;
+			reg = <0 0x4FD80000 0 0x200000>;
+			shared = <1>;
+		};
+	};
+
+	psci {
+		compatible  = "arm,psci-0.2";
+		method      = "smc";
+	};
+
+	system_clk: dummy13m {
+		compatible = "fixed-clock";
+		clock-frequency = <13000000>;
+		#clock-cells = <0>;
+	};
+
+	rtc_clk: dummy32k {
+		compatible = "fixed-clock";
+		clock-frequency = <32000>;
+		#clock-cells = <0>;
+	};
+
+	uart_clk: dummy12m {
+		compatible = "fixed-clock";
+		clock-frequency = <12000000>;
+		#clock-cells = <0>;
+	};
+
+	gpt_clk: dummy6m {
+		compatible = "fixed-clock";
+		clock-frequency = <6000000>;
+		#clock-cells = <0>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupt-parent = <&gic>;
+		clock-frequency = <12000000>;
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+
+	};
+
+	watchdog: watchdog@1001c000 {
+		compatible = "mediatek,mt7622-wdt",
+			     "mediatek,mt6589-wdt";
+		reg = <0 0x1001c000 0 0x1000>;
+		interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+		#reset-cells = <1>;
+	};
+
+	gic: interrupt-controller@c000000 {
+		compatible = "arm,gic-v3";
+		#interrupt-cells = <3>;
+		interrupt-parent = <&gic>;
+		interrupt-controller;
+		reg = <0 0x0c000000 0 0x40000>,  /* GICD */
+		      <0 0x0c080000 0 0x200000>; /* GICR */
+
+		interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	uart0: serial@11002000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11002000 0 0x400>;
+		interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&uart_clk>;
+		status = "disabled";
+	};
+
+	uart1: serial@11003000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11003000 0 0x400>;
+		interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&uart_clk>;
+		status = "disabled";
+	};
+
+	uart2: serial@11004000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11004000 0 0x400>;
+		interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&uart_clk>;
+		status = "disabled";
+	};
+
+	pcie: pcie@11280000 {
+		compatible = "mediatek,mt7986-pcie";
+		device_type = "pci";
+		reg = <0 0x11280000 0 0x5000>;
+		reg-names = "port0";
+		#address-cells = <3>;
+		#size-cells = <2>;
+		interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+		bus-range = <0x00 0xff>;
+		ranges = <0x82000000 0 0x20000000
+			  0x0 0x20000000 0 0x10000000>;
+
+		pcie0: pcie@0,0 {
+			device_type = "pci";
+			reg = <0x0000 0 0 0 0>;
+			#address-cells = <3>;
+			#size-cells = <2>;
+			ranges;
+			#interrupt-cells = <1>;
+			interrupt-map-mask = <0 0 0 7>;
+			interrupt-map = <0 0 0 1 &pcie_intc0 0>,
+					<0 0 0 2 &pcie_intc0 1>,
+					<0 0 0 3 &pcie_intc0 2>,
+					<0 0 0 4 &pcie_intc0 3>;
+			pcie_intc0: interrupt-controller {
+				interrupt-controller;
+				#address-cells = <0>;
+				#interrupt-cells = <1>;
+			};
+		};
+	};
+
+	pio: pinctrl@1001f000 {
+		compatible = "mediatek,mt7986-pinctrl";
+		reg = <0 0x1001f000 0 0x1000>,
+		      <0 0x11c30000 0 0x1000>,
+                      <0 0x11c40000 0 0x1000>,
+                      <0 0x11e20000 0 0x1000>,
+                      <0 0x11e30000 0 0x1000>,
+                      <0 0x11f00000 0 0x1000>,
+                      <0 0x11f10000 0 0x1000>,
+		      <0 0x1000b000 0 0x1000>;
+		reg-names = "gpio_base", "iocfg_rt_base", "iocfg_rb_base",
+                            "iocfg_lt_base", "iocfg_lb_base", "iocfg_tr_base",
+                            "iocfg_tl_base", "eint";
+		gpio-controller;
+		#gpio-cells = <2>;
+		gpio-ranges = <&pio 0 0 100>;
+		interrupt-controller;
+		interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-parent = <&gic>;
+		#interrupt-cells = <2>;
+	};
+
+        ethsys: syscon@15000000 {
+                #address-cells = <1>;
+                #size-cells = <1>;
+                compatible = "mediatek,mt7986-ethsys",
+                             "syscon";
+                reg = <0 0x15000000 0 0x1000>;
+                #clock-cells = <1>;
+                #reset-cells = <1>;
+
+		ethsysrst: reset-controller {
+			compatible = "ti,syscon-reset";
+			#reset-cells = <1>;
+			ti,reset-bits = <0x34 4 0x34 4 0x34 4 (ASSERT_SET | DEASSERT_CLEAR | STATUS_SET)>;
+		};
+        };
+
+        eth: ethernet@15100000 {
+                compatible = "mediatek,mt7986-eth";
+                reg = <0 0x15100000 0 0x80000>;
+                interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
+                mediatek,ethsys = <&ethsys>;
+                #reset-cells = <1>;
+                #address-cells = <1>;
+                #size-cells = <0>;
+                status = "disabled";
+        };
+
+	snand: snfi@11005000 {
+		compatible = "mediatek,mt7986-snand";
+		reg = <0 0x11005000 0 0x1000>, <0 0x11006000 0 0x1000>;
+		reg-names = "nfi", "ecc";
+		interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>;
+		clock-names = "nfi_clk", "pad_clk", "ecc_clk";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	wed_pcie: wed_pcie@10003000 {
+		compatible = "mediatek,wed_pcie";
+		reg = <0 0x10003000 0 0x10>;
+	};
+
+	wbsys: wbsys@18000000 {
+		compatible = "mediatek,wbsys";
+		reg = <0 0x18000000 0  0x1000000>;
+		interrupts = <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 215 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>;
+		chip_id = <0x7986>;
+	};
+
+	spi0: spi@1100a000 {
+		compatible = "mediatek,ipm-spi";
+		reg = <0 0x1100a000 0 0x100>;
+		interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+		status = "disabled";
+	};
+
+	spi1: spi@1100b000 {
+		compatible = "mediatek,ipm-spi";
+		reg = <0 0x1100b000 0 0x100>;
+		interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+		status = "disabled";
+	};
+
+	auxadc: adc@1100d000 {
+		compatible = "mediatek,mt7986-auxadc",
+			     "mediatek,mt7622-auxadc";
+		reg = <0 0x1100d000 0 0x1000>;
+		clocks = <&system_clk>;
+		clock-names = "main";
+		#io-channel-cells = <1>;
+        };
+
+	consys: consys@10000000 {
+		compatible = "mediatek,mt7986-consys";
+		reg = <0 0x10000000 0 0x8600000>;
+		memory-region = <&wmcpu_emi>;
+	};
+
+	xhci: xhci@11200000 {
+		compatible = "mediatek,mt7986-xhci",
+			     "mediatek,mtk-xhci";
+		reg = <0 0x11200000 0 0x2e00>,
+		      <0 0x11203e00 0 0x0100>;
+		reg-names = "mac", "ippc";
+		interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&u2port0 PHY_TYPE_USB2>;
+		clocks = <&system_clk>,
+		         <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>;
+		clock-names = "sys_ck",
+			      "xhci_ck",
+			      "ref_ck",
+			      "mcu_ck",
+			      "dma_ck";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		mediatek,u3p-dis-msk=<0x01>;
+		status = "okay";
+	};
+
+	usbtphy: usb-phy@11203e00 {
+		compatible = "mediatek,a60810-u2phy",
+			     "mediatek,a60931-u3phy",
+			     "mediatek,a60xxx-usbphy";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+		status = "okay";
+
+		u2port0: usb-phy@11203ed0 {
+			reg = <0 0x11203ed0 0 0x008>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			status = "okay";
+		};
+
+		u3port0: usb-phy@11203ed8 {
+			reg = <0 0x11203ed8 0 0x008>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			status = "disabled";
+		};
+
+		u2port1: usb-phy@11203ee0 {
+			reg = <0 0x11203ee0 0 0x008>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			status = "disabled";
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986-snfi-nand-partition.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986-snfi-nand-partition.dtsi
new file mode 100644
index 0000000..b88e1c1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986-snfi-nand-partition.dtsi
@@ -0,0 +1,44 @@
+/ {
+	nmbm_snfi {
+		compatible = "generic,nmbm";
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		lower-mtd-device = <&snand>;
+		forced-create;
+		empty-page-ecc-protected;
+
+		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>;
+			};
+
+			factory: partition@180000 {
+				label = "Factory";
+				reg = <0x180000 0x0200000>;
+			};
+
+			partition@380000 {
+				label = "FIP";
+				reg = <0x380000 0x0200000>;
+			};
+
+			partition@580000 {
+				label = "ubi";
+				reg = <0x580000 0x4000000>;
+			};
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986-spim-nand-partition.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986-spim-nand-partition.dtsi
new file mode 100644
index 0000000..4cc7961
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986-spim-nand-partition.dtsi
@@ -0,0 +1,43 @@
+/ {
+	nmbm_spim_nand {
+		compatible = "generic,nmbm";
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		lower-mtd-device = <&spi_nand>;
+		forced-create;
+
+		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>;
+			};
+
+			factory: partition@180000 {
+				label = "Factory";
+				reg = <0x180000 0x0200000>;
+			};
+
+			partition@380000 {
+				label = "FIP";
+				reg = <0x380000 0x0200000>;
+			};
+
+			partition@580000 {
+				label = "ubi";
+				reg = <0x580000 0x4000000>;
+			};
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986-spim-nor-partition.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986-spim-nor-partition.dtsi
new file mode 100644
index 0000000..dcdde5a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986-spim-nor-partition.dtsi
@@ -0,0 +1,30 @@
+&spi0 {
+	spi_nor@0 {
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@00000 {
+				label = "BL2";
+				reg = <0x00000 0x0040000>;
+			};
+			partition@40000 {
+				label = "u-boot-env";
+				reg = <0x40000 0x0010000>;
+			};
+			factory: partition@50000 {
+				label = "Factory";
+				reg = <0x50000 0x00B0000>;
+			};
+			partition@100000 {
+				label = "FIP";
+				reg = <0x100000 0x0080000>;
+			};
+			partition@180000 {
+				label = "firmware";
+				reg = <0x180000 0xE00000>;
+			};
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-emmc-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-emmc-rfb.dts
new file mode 100644
index 0000000..c094abe
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-emmc-rfb.dts
@@ -0,0 +1,296 @@
+/dts-v1/;
+#include "mt7986a.dtsi"
+#include "mt7986a-pinctrl.dtsi"
+/ {
+	model = "MediaTek MT7986a RFB";
+	compatible = "mediatek,mt7986a-emmc-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000 \
+				root=PARTLABEL=rootfs rootwait rootfstype=squashfs,f2fs";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	reg_1p8v: regulator-1p8v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-1.8V";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	sound {
+		compatible = "mediatek,mt7986-wm8960-machine";
+		mediatek,platform = <&afe>;
+		audio-routing = "Headphone", "HP_L",
+				"Headphone", "HP_R",
+				"LINPUT1", "AMIC",
+				"RINPUT1", "AMIC";
+		mediatek,audio-codec = <&wm8960>;
+		status = "okay";
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin &pwm1_pin_g1>;
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+
+	wm8960: wm8960@1a {
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+	};
+};
+
+&auxadc {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@4 {
+					reg = <4>;
+					label = "lan4";
+				};
+
+				port@5 {
+					reg = <5>;
+					label = "lan5";
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins_g2>;
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_pins_default>;
+	pinctrl-1 = <&mmc0_pins_uhs>;
+	bus-width = <8>;
+	max-frequency = <200000000>;
+	cap-mmc-highspeed;
+	mmc-hs200-1_8v;
+	mmc-hs400-1_8v;
+	hs400-ds-delay = <0x14014>;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_1p8v>;
+	non-removable;
+	no-sd;
+	no-sdio;
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
+
+&pio {
+	mmc0_pins_default: mmc0-pins-50-to-61-default {
+		mux {
+			function = "flash";
+			groups = "emmc_51";
+		};
+		conf-cmd-dat {
+			pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2",
+			       "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5",
+			       "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+		conf-clk {
+			pins = "EMMC_CK";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-ds {
+			pins = "EMMC_DSL";
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-rst {
+			pins = "EMMC_RSTB";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+
+	mmc0_pins_uhs: mmc0-pins-50-to-61-uhs {
+		mux {
+			function = "flash";
+			groups = "emmc_51";
+		};
+		conf-cmd-dat {
+			pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2",
+			       "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5",
+			       "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+		conf-clk {
+			pins = "EMMC_CK";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-ds {
+			pins = "EMMC_DSL";
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-rst {
+			pins = "EMMC_RSTB";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-gsw-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-gsw-spim-nand-rfb.dts
new file mode 100644
index 0000000..cb80e99
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-gsw-spim-nand-rfb.dts
@@ -0,0 +1,264 @@
+/dts-v1/;
+#include "mt7986a.dtsi"
+#include "mt7986a-pinctrl.dtsi"
+#include "mt7986-spim-nand-partition.dtsi"
+/ {
+	model = "MediaTek MT7986b gsw RFB";
+	compatible = "mediatek,mt7986a-2500wan-gsw-spim-snand-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	gsw: gsw@0 {
+		compatible = "mediatek,mt753x";
+		mediatek,ethsys = <&ethsys>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	sound {
+		compatible = "mediatek,mt7986-wm8960-machine";
+		mediatek,platform = <&afe>;
+		audio-routing = "Headphone", "HP_L",
+				"Headphone", "HP_R",
+				"LINPUT1", "AMIC",
+				"RINPUT1", "AMIC";
+		mediatek,audio-codec = <&wm8960>;
+		status = "okay";
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin &pwm1_pin_g1>;
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+
+	wm8960: wm8960@1a {
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+	};
+};
+
+&auxadc {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+	};
+};
+
+&gsw {
+	mediatek,mdio = <&mdio>;
+	mediatek,portmap = "lllll";
+	mediatek,mdio_master_pinmux = <1>;
+	reset-gpios = <&pio 5 0>;
+	interrupt-parent = <&pio>;
+	interrupts = <66 IRQ_TYPE_LEVEL_HIGH>;
+	status = "okay";
+
+	port5: port@5 {
+		compatible = "mediatek,mt753x-port";
+		reg = <5>;
+		phy-mode = "sgmii";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+		};
+
+	};
+
+	port6: port@6 {
+		compatible = "mediatek,mt753x-port";
+		mediatek,ssc-on;
+		reg = <6>;
+		phy-mode = "sgmii";
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	cs-gpios = <0>, <0>;
+	status = "okay";
+
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <20000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+
+	spi_nand: spi_nand@1 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-max-frequency = <20000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins_g2>;
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+        pinctrl-names = "default", "dbdc";
+        pinctrl-0 = <&wf_2g_5g_pins>;
+        pinctrl-1 = <&wf_dbdc_pins>;
+};
+
+&pio {
+	spi_flash_pins: spi-flash-pins-33-to-38 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+	};
+
+        wf_2g_5g_pins: wf_2g_5g-pins {
+                mux {
+                        function = "wifi";
+                        groups = "wf_2g", "wf_5g";
+                };
+                conf {
+                        pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+                               "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+                               "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+                               "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+                               "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+                               "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+                               "WF1_TOP_CLK", "WF1_TOP_DATA";
+                        drive-strength = <MTK_DRIVE_4mA>;
+                };
+        };
+
+        wf_dbdc_pins: wf_dbdc-pins {
+                mux {
+                        function = "wifi";
+                        groups = "wf_dbdc";
+                };
+                conf {
+                        pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+                               "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+                               "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+                               "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+                               "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+                               "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+                               "WF1_TOP_CLK", "WF1_TOP_DATA";
+                        drive-strength = <MTK_DRIVE_4mA>;
+                };
+        };
+
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-sd-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-sd-rfb.dts
new file mode 100644
index 0000000..2a1d0dc
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-sd-rfb.dts
@@ -0,0 +1,304 @@
+/dts-v1/;
+#include "mt7986a.dtsi"
+#include "mt7986a-pinctrl.dtsi"
+/ {
+	model = "MediaTek MT7986a RFB";
+	compatible = "mediatek,mt7986a-2500wan-sd-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+			earlycon=uart8250,mmio32,0x11002000 \
+			root=PARTLABEL=rootfs rootwait rootfstype=squashfs,f2fs";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	sound {
+		compatible = "mediatek,mt7986-wm8960-machine";
+		mediatek,platform = <&afe>;
+		audio-routing = "Headphone", "HP_L",
+				"Headphone", "HP_R",
+				"LINPUT1", "AMIC",
+				"RINPUT1", "AMIC";
+		mediatek,audio-codec = <&wm8960>;
+		status = "okay";
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin &pwm1_pin_g1>;
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+
+	wm8960: wm8960@1a {
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+	};
+};
+
+&auxadc {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@4 {
+					reg = <4>;
+					label = "lan4";
+				};
+
+				port@5 {
+					reg = <5>;
+					label = "lan5";
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_pins_default>;
+	pinctrl-1 = <&mmc0_pins_uhs>;
+	bus-width = <4>;
+	max-frequency = <52000000>;
+	cap-sd-highspeed;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_3p3v>;
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&pio {
+	mmc0_pins_default: mmc0-pins-50-to-61-default {
+		mux {
+			function = "flash";
+			groups = "emmc_51";
+		};
+		conf-cmd-dat {
+			pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2",
+			       "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5",
+			       "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+		conf-clk {
+			pins = "EMMC_CK";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-ds {
+			pins = "EMMC_DSL";
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-rst {
+			pins = "EMMC_RSTB";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+
+	mmc0_pins_uhs: mmc0-pins-50-to-61-uhs {
+		mux {
+			function = "flash";
+			groups = "emmc_51";
+		};
+		conf-cmd-dat {
+			pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2",
+			       "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5",
+			       "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+		conf-clk {
+			pins = "EMMC_CK";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-ds {
+			pins = "EMMC_DSL";
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-rst {
+			pins = "EMMC_RSTB";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+
+	wf_2g_5g_pins: wf_2g_5g-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_2g", "wf_5g";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+
+	wf_dbdc_pins: wf_dbdc-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_dbdc";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nand-rfb.dts
new file mode 100644
index 0000000..5504369
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nand-rfb.dts
@@ -0,0 +1,283 @@
+/dts-v1/;
+#include "mt7986a.dtsi"
+#include "mt7986a-pinctrl.dtsi"
+#include "mt7986-spim-nand-partition.dtsi"
+/ {
+	model = "MediaTek MT7986a RFB";
+	compatible = "mediatek,mt7986a-2500wan-spim-snand-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	sound {
+		compatible = "mediatek,mt7986-wm8960-machine";
+		mediatek,platform = <&afe>;
+		audio-routing = "Headphone", "HP_L",
+				"Headphone", "HP_R",
+				"LINPUT1", "AMIC",
+				"RINPUT1", "AMIC";
+		mediatek,audio-codec = <&wm8960>;
+		status = "okay";
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin &pwm1_pin_g1>;
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+
+	wm8960: wm8960@1a {
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+	};
+};
+
+&auxadc {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@4 {
+					reg = <4>;
+					label = "lan4";
+				};
+
+				port@5 {
+					reg = <5>;
+					label = "lan5";
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	cs-gpios = <0>, <0>;
+	status = "okay";
+
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <20000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+
+	spi_nand: spi_nand@1 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-max-frequency = <20000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins_g2>;
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+	pinctrl-names = "default", "dbdc";
+	pinctrl-0 = <&wf_2g_5g_pins>;
+	pinctrl-1 = <&wf_dbdc_pins>;
+};
+
+&pio {
+	spi_flash_pins: spi-flash-pins-33-to-38 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+	};
+
+	wf_2g_5g_pins: wf_2g_5g-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_2g", "wf_5g";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+
+	wf_dbdc_pins: wf_dbdc-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_dbdc";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nor-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nor-rfb.dts
new file mode 100644
index 0000000..c1f22d1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nor-rfb.dts
@@ -0,0 +1,235 @@
+/dts-v1/;
+#include "mt7986a.dtsi"
+#include "mt7986a-pinctrl.dtsi"
+#include "mt7986-spim-nor-partition.dtsi"
+/ {
+	model = "MediaTek MT7986a RFB";
+	compatible = "mediatek,mt7986a-2500wan-nor-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	sound {
+		compatible = "mediatek,mt7986-wm8960-machine";
+		mediatek,platform = <&afe>;
+		audio-routing = "Headphone", "HP_L",
+				"Headphone", "HP_R",
+				"LINPUT1", "AMIC",
+				"RINPUT1", "AMIC";
+		mediatek,audio-codec = <&wm8960>;
+		status = "okay";
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin &pwm1_pin_g1>;
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+
+	wm8960: wm8960@1a {
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+	};
+};
+
+&auxadc {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@4 {
+					reg = <4>;
+					label = "lan4";
+				};
+
+				port@5 {
+					reg = <5>;
+					label = "lan5";
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	cs-gpios = <0>, <0>;
+	status = "okay";
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins_g2>;
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
+
+&pio {
+	spi_flash_pins: spi-flash-pins-33-to-38 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-emmc-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-emmc-rfb.dts
new file mode 100644
index 0000000..b4ae0b0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-emmc-rfb.dts
@@ -0,0 +1,297 @@
+/dts-v1/;
+#include "mt7986a.dtsi"
+#include "mt7986a-pinctrl.dtsi"
+/ {
+	model = "MediaTek MT7986a RFB";
+	compatible = "mediatek,mt7986a-emmc-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000 \
+				root=PARTLABEL=rootfs rootwait rootfstype=squashfs,f2fs";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	reg_1p8v: regulator-1p8v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-1.8V";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	sound_wm8960 {
+		compatible = "mediatek,mt79xx-wm8960-machine";
+		mediatek,platform = <&afe>;
+		audio-routing = "Headphone", "HP_L",
+				"Headphone", "HP_R",
+				"LINPUT1", "AMIC",
+				"RINPUT1", "AMIC";
+		mediatek,audio-codec = <&wm8960>;
+		status = "okay";
+	};
+
+	sound_si3218x {
+		compatible = "mediatek,mt79xx-si3218x-machine";
+		mediatek,platform = <&afe>;
+		mediatek,ext-codec = <&proslic_spi>;
+		status = "okay";
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin &pwm1_pin_g1>;
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+
+	wm8960: wm8960@1a {
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+	};
+};
+
+&auxadc {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins_g2>;
+	status = "okay";
+
+	proslic_spi: proslic_spi@0 {
+		compatible = "silabs,proslic_spi";
+		reg = <0>;
+		spi-max-frequency = <10000000>;
+		spi-cpha = <1>;
+		spi-cpol = <1>;
+		channel_count = <1>;
+		debug_level = <4>;       /* 1 = TRC, 2 = DBG, 4 = ERR */
+		reset_gpio = <&pio 7 0>;
+		ig,enable-spi = <1>;     /* 1: Enable, 0: Disable */
+	};
+};
+
+&mmc0 {
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_pins_default>;
+	pinctrl-1 = <&mmc0_pins_uhs>;
+	bus-width = <8>;
+	max-frequency = <200000000>;
+	cap-mmc-highspeed;
+	mmc-hs200-1_8v;
+	mmc-hs400-1_8v;
+	hs400-ds-delay = <0x14014>;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_1p8v>;
+	non-removable;
+	no-sd;
+	no-sdio;
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	status = "okay";
+};
+
+&pio {
+	mmc0_pins_default: mmc0-pins-50-to-61-default {
+		mux {
+			function = "flash";
+			groups = "emmc_51";
+		};
+		conf-cmd-dat {
+			pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2",
+			       "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5",
+			       "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+		conf-clk {
+			pins = "EMMC_CK";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-ds {
+			pins = "EMMC_DSL";
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-rst {
+			pins = "EMMC_RSTB";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+
+	mmc0_pins_uhs: mmc0-pins-50-to-61-uhs {
+		mux {
+			function = "flash";
+			groups = "emmc_51";
+		};
+		conf-cmd-dat {
+			pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2",
+			       "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5",
+			       "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+		conf-clk {
+			pins = "EMMC_CK";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-ds {
+			pins = "EMMC_DSL";
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-rst {
+			pins = "EMMC_RSTB";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-pinctrl.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-pinctrl.dtsi
new file mode 100644
index 0000000..42619a1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-pinctrl.dtsi
@@ -0,0 +1,141 @@
+&pio {
+	wifi_led_pins: wifi_led-pins-1-2 {
+		mux {
+			function = "led";
+			groups = "wifi_led";
+		};
+	};
+
+	i2c_pins: i2c-pins-3-4 {
+		mux {
+			function = "i2c";
+			groups = "i2c";
+		};
+	};
+
+	uart1_pins_g0: uart1-pins-7-to-10 {
+		mux {
+			function = "uart";
+			groups = "uart1_0";
+		};
+	};
+
+	pcie0_pins: pcie0-pins-9-10-41 {
+		mux {
+			function = "pcie";
+			groups = "pcie_clk", "pcie_wake", "pcie_pereset";
+		};
+	};
+
+	jtag_pins: jtag-pins-11-to-14 {
+		mux {
+			function = "jtag";
+			groups = "jtag";
+		};
+	};
+
+	spic_pins_g0: spic-pins-11-to-14 {
+		mux {
+			function = "spi";
+			groups = "spi1_0";
+		};
+	};
+
+	pwm1_pin_g0: pwm1-pin-20 {
+		mux {
+			function = "pwm";
+			groups = "pwm1_1";
+		};
+	};
+
+	pwm0_pin: pwm0-pin-21 {
+		mux {
+			function = "pwm";
+			groups = "pwm0";
+		};
+	};
+
+	pwm1_pin_g1: pwm1-pin-22 {
+		mux {
+			function = "pwm";
+			groups = "pwm1_0";
+		};
+	};
+
+	spic_pins_g1: spic-pins-23-to-26 {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+
+	uart1_pins_g1: uart1-pins-23-to-26 {
+		mux {
+			function = "uart";
+			groups = "uart1_1";
+		};
+	};
+
+	spic_pins_g2: spic-pins-29-to-32 {
+		mux {
+			function = "spi";
+			groups = "spi1_2";
+		};
+	};
+
+	uart1_pins_g2: uart1-pins-29-to-32 {
+		mux {
+			function = "uart";
+			groups = "uart1_2";
+		};
+	};
+
+	uart2_pins_g0: uart1-pins-29-to-32 {
+		mux {
+			function = "uart";
+			groups = "uart1_2";
+		};
+	};
+
+	uart2_pins_g1: uart1-pins-23-to-36 {
+		mux {
+			function = "uart";
+			groups = "uart2_1";
+		};
+	};
+
+	spic_pins_g3: spic-pins-33-to-36 {
+		mux {
+			function = "spi";
+			groups = "spi1_3";
+		};
+	};
+
+	uart1_pins_g3: uart1-pins-35-to-38 {
+		mux {
+			function = "uart";
+			groups = "uart1_3_rx_tx", "uart1_3_cts_rts";
+		};
+	};
+
+	uart1_pins: uart1-pins-42-to-45 {
+		mux {
+			function = "uart";
+			groups = "uart1";
+		};
+	};
+
+	uart2_pins: uart1-pins-46-to-49 {
+		mux {
+			function = "uart";
+			groups = "uart2";
+		};
+	};
+
+	pcm_pins: pcm-pins-62-to-65 {
+		mux {
+			function = "pcm";
+			groups = "pcm";
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-snfi-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-snfi-nand-rfb.dts
new file mode 100644
index 0000000..3164038
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-snfi-nand-rfb.dts
@@ -0,0 +1,239 @@
+/dts-v1/;
+#include "mt7986a.dtsi"
+#include "mt7986a-pinctrl.dtsi"
+#include "mt7986-snfi-nand-partition.dtsi"
+/ {
+	model = "MediaTek MT7986a RFB";
+	compatible = "mediatek,mt7986a-snfi-snand-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	sound_wm8960 {
+		compatible = "mediatek,mt79xx-wm8960-machine";
+		mediatek,platform = <&afe>;
+		audio-routing = "Headphone", "HP_L",
+				"Headphone", "HP_R",
+				"LINPUT1", "AMIC",
+				"RINPUT1", "AMIC";
+		mediatek,audio-codec = <&wm8960>;
+		status = "okay";
+	};
+
+	sound_si3218x {
+		compatible = "mediatek,mt79xx-si3218x-machine";
+		mediatek,platform = <&afe>;
+		mediatek,ext-codec = <&proslic_spi>;
+		status = "okay";
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin &pwm1_pin_g1>;
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+
+	wm8960: wm8960@1a {
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+	};
+};
+
+&auxadc {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&snand {
+	pinctrl-names = "default";
+	pinctrl-0 = <&snfi_pins>;
+	mediatek,quad-spi;
+	status = "okay";
+
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins_g2>;
+	status = "okay";
+
+	proslic_spi: proslic_spi@0 {
+		compatible = "silabs,proslic_spi";
+		reg = <0>;
+		spi-max-frequency = <10000000>;
+		spi-cpha = <1>;
+		spi-cpol = <1>;
+		channel_count = <1>;
+		debug_level = <4>;       /* 1 = TRC, 2 = DBG, 4 = ERR */
+		reset_gpio = <&pio 7 0>;
+		ig,enable-spi = <1>;     /* 1: Enable, 0: Disable */
+	};
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
+
+&pio {
+	snfi_pins: snfi-pins-23-to-28 {
+		mux {
+			function = "flash";
+			groups = "snfi";
+		};
+		conf-clk {
+			pins = "SPI0_CLK";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+		conf-pu {
+			pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI0_MOSI", "SPI0_MISO";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nand-rfb.dts
new file mode 100644
index 0000000..203bc4a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nand-rfb.dts
@@ -0,0 +1,285 @@
+/dts-v1/;
+#include "mt7986a.dtsi"
+#include "mt7986a-pinctrl.dtsi"
+#include "mt7986-spim-nand-partition.dtsi"
+/ {
+	model = "MediaTek MT7986a RFB";
+	compatible = "mediatek,mt7986a-spim-snand-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	sound_wm8960 {
+		compatible = "mediatek,mt79xx-wm8960-machine";
+		mediatek,platform = <&afe>;
+		audio-routing = "Headphone", "HP_L",
+				"Headphone", "HP_R",
+				"LINPUT1", "AMIC",
+				"RINPUT1", "AMIC";
+		mediatek,audio-codec = <&wm8960>;
+		status = "okay";
+	};
+
+	sound_si3218x {
+		compatible = "mediatek,mt79xx-si3218x-machine";
+		mediatek,platform = <&afe>;
+		mediatek,ext-codec = <&proslic_spi>;
+		status = "okay";
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin &pwm1_pin_g1>;
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+
+	wm8960: wm8960@1a {
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+	};
+};
+
+&auxadc {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	cs-gpios = <0>, <0>;
+	status = "okay";
+
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+
+	spi_nand: spi_nand@1 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-max-frequency = <52000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins_g2>;
+	status = "okay";
+
+	proslic_spi: proslic_spi@0 {
+		compatible = "silabs,proslic_spi";
+		reg = <0>;
+		spi-max-frequency = <10000000>;
+		spi-cpha = <1>;
+		spi-cpol = <1>;
+		channel_count = <1>;
+		debug_level = <4>;       /* 1 = TRC, 2 = DBG, 4 = ERR */
+		reset_gpio = <&pio 7 0>;
+		ig,enable-spi = <1>;     /* 1: Enable, 0: Disable */
+	};
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+	pinctrl-names = "default", "dbdc";
+	pinctrl-0 = <&wf_2g_5g_pins>;
+	pinctrl-1 = <&wf_dbdc_pins>;
+};
+
+&pio {
+	spi_flash_pins: spi-flash-pins-33-to-38 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+	};
+
+	wf_2g_5g_pins: wf_2g_5g-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_2g", "wf_5g";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+
+	wf_dbdc_pins: wf_dbdc-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_dbdc";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nor-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nor-rfb.dts
new file mode 100644
index 0000000..275d48d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nor-rfb.dts
@@ -0,0 +1,238 @@
+/dts-v1/;
+#include "mt7986a.dtsi"
+#include "mt7986a-pinctrl.dtsi"
+#include "mt7986-spim-nor-partition.dtsi"
+/ {
+	model = "MediaTek MT7986a RFB";
+	compatible = "mediatek,mt7986a-nor-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	sound_wm8960 {
+		compatible = "mediatek,mt79xx-wm8960-machine";
+		mediatek,platform = <&afe>;
+		audio-routing = "Headphone", "HP_L",
+				"Headphone", "HP_R",
+				"LINPUT1", "AMIC",
+				"RINPUT1", "AMIC";
+		mediatek,audio-codec = <&wm8960>;
+		status = "okay";
+	};
+
+	sound_si3218x {
+		compatible = "mediatek,mt79xx-si3218x-machine";
+		mediatek,platform = <&afe>;
+		mediatek,ext-codec = <&proslic_spi>;
+		status = "okay";
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin &pwm1_pin_g1>;
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+
+	wm8960: wm8960@1a {
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+	};
+};
+
+&auxadc {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	cs-gpios = <0>, <0>;
+	status = "okay";
+
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins_g2>;
+	status = "okay";
+
+	proslic_spi: proslic_spi@0 {
+		compatible = "silabs,proslic_spi";
+		reg = <0>;
+		spi-max-frequency = <10000000>;
+		spi-cpha = <1>;
+		spi-cpol = <1>;
+		channel_count = <1>;
+		debug_level = <4>;       /* 1 = TRC, 2 = DBG, 4 = ERR */
+		reset_gpio = <&pio 7 0>;
+		ig,enable-spi = <1>;     /* 1: Enable, 0: Disable */
+	};
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
+
+&pio {
+	spi_flash_pins: spi-flash-pins-33-to-38 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a.dtsi
new file mode 100644
index 0000000..2b72991
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a.dtsi
@@ -0,0 +1,808 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Sam.Shih <sam.shih@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/phy/phy.h>
+#include <dt-bindings/reset/ti-syscon.h>
+#include <dt-bindings/clock/mt7986-clk.h>
+#include <dt-bindings/thermal/thermal.h>
+#include <dt-bindings/pinctrl/mt65xx.h>
+#include <dt-bindings/reset/mt7986-resets.h>
+
+/ {
+	compatible = "mediatek,mt7986a-rfb";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu0: cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			enable-method = "psci";
+			reg = <0x0>;
+		};
+
+		cpu1: cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			enable-method = "psci";
+			reg = <0x1>;
+		};
+
+		cpu2: cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			enable-method = "psci";
+			reg = <0x2>;
+		};
+
+		cpu3: cpu@3 {
+			device_type = "cpu";
+			enable-method = "psci";
+			compatible = "arm,cortex-a53";
+			reg = <0x3>;
+		};
+	};
+
+	wed: wed@15010000 {
+		compatible = "mediatek,wed";
+		wed_num = <2>;
+		/* add this property for wed get the pci slot number. */
+		pci_slot_map = <0>, <1>;
+		reg = <0 0x15010000 0 0x1000>,
+		      <0 0x15011000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	wed2: wed2@15011000 {
+		compatible = "mediatek,wed2";
+		wed_num = <2>;
+		reg = <0 0x15010000 0 0x1000>,
+		      <0 0x15011000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	wdma: wdma@15104800 {
+		compatible = "mediatek,wed-wdma";
+		reg = <0 0x15104800 0 0x400>,
+		      <0 0x15104c00 0 0x400>;
+	};
+
+	ap2woccif: ap2woccif@151A5000 {
+		compatible = "mediatek,ap2woccif";
+		reg = <0 0x151A5000 0 0x1000>,
+		      <0 0x151AD000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>;
+        };
+
+	wocpu0_ilm: wocpu0_ilm@151E0000 {
+		compatible = "mediatek,wocpu0_ilm";
+		reg = <0 0x151E0000 0 0x8000>;
+	};
+
+        wocpu1_ilm: wocpu1_ilm@151F0000 {
+                compatible = "mediatek,wocpu1_ilm";
+                reg = <0 0x151F0000 0 0x8000>;
+        };
+
+	wocpu_dlm: wocpu_dlm@151E8000 {
+		compatible = "mediatek,wocpu_dlm";
+		reg = <0 0x151E8000 0 0x2000>,
+		      <0 0x151F8000 0 0x2000>;
+
+		resets = <&ethsysrst 0>;
+		reset-names = "wocpu_rst";
+	};
+
+	cpu_boot: wocpu_boot@15194000 {
+		compatible = "mediatek,wocpu_boot";
+		reg = <0 0x15194000 0 0x1000>;
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		/* 192 KiB reserved for ARM Trusted Firmware (BL31) */
+		secmon_reserved: secmon@43000000 {
+			reg = <0 0x43000000 0 0x30000>;
+			no-map;
+		};
+
+		wmcpu_emi: wmcpu-reserved@4FC00000 {
+			compatible = "mediatek,wmcpu-reserved";
+			no-map;
+			reg = <0 0x4FC00000 0 0x00100000>;
+		};
+
+		wocpu0_emi: wocpu0_emi@4FD00000 {
+			compatible = "mediatek,wocpu0_emi";
+			no-map;
+			reg = <0 0x4FD00000 0 0x40000>;
+			shared = <0>;
+		};
+
+		wocpu1_emi: wocpu1_emi@4FD40000 {
+			compatible = "mediatek,wocpu1_emi";
+			no-map;
+			reg = <0 0x4FD40000 0 0x40000>;
+			shared = <0>;
+		};
+
+		wocpu_data: wocpu_data@4FD80000 {
+			compatible = "mediatek,wocpu_data";
+			no-map;
+			reg = <0 0x4FD80000 0 0x240000>;
+			shared = <1>;
+		};
+	};
+
+	psci {
+		compatible  = "arm,psci-0.2";
+		method      = "smc";
+	};
+
+	clk40m: oscillator@0 {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <40000000>;
+		clock-output-names = "clkxtal";
+	};
+
+	system_clk: dummy_system_clk {
+		compatible = "fixed-clock";
+		clock-frequency = <40000000>;
+		#clock-cells = <0>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupt-parent = <&gic>;
+		clock-frequency = <13000000>;
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	infracfg_ao: infracfg_ao@10001000 {
+		compatible = "mediatek,mt7986-infracfg_ao", "syscon";
+		reg = <0 0x10001000 0 0x68>;
+		#clock-cells = <1>;
+	};
+
+	infracfg: infracfg@10001040 {
+		compatible = "mediatek,mt7986-infracfg", "syscon";
+		reg = <0 0x1000106c 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	topckgen: topckgen@1001B000 {
+		compatible = "mediatek,mt7986-topckgen", "syscon";
+		reg = <0 0x1001B000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	apmixedsys: apmixedsys@1001E000 {
+		compatible = "mediatek,mt7986-apmixedsys", "syscon";
+		reg = <0 0x1001E000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	watchdog: watchdog@1001c000 {
+		compatible = "mediatek,mt7986-wdt";
+		reg = <0 0x1001c000 0 0x1000>;
+		interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+		#reset-cells = <1>;
+	};
+
+	gic: interrupt-controller@c000000 {
+		compatible = "arm,gic-v3";
+		#interrupt-cells = <3>;
+		interrupt-parent = <&gic>;
+		interrupt-controller;
+		reg = <0 0x0c000000 0 0x40000>,  /* GICD */
+		      <0 0x0c080000 0 0x200000>; /* GICR */
+
+		interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	pwm: pwm@10048000 {
+		compatible = "mediatek,mt7986-pwm";
+		reg = <0 0x10048000 0 0x1000>;
+		#clock-cells = <1>;
+		#pwm-cells = <2>;
+		interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg CK_INFRA_PWM>,
+			 <&infracfg_ao CK_INFRA_PWM_BSEL>,
+			 <&infracfg_ao CK_INFRA_PWM1_CK>,
+			 <&infracfg_ao CK_INFRA_PWM2_CK>;
+		assigned-clocks = <&topckgen CK_TOP_PWM_SEL>,
+				  <&infracfg_ao CK_INFRA_PWM_BSEL>,
+				  <&infracfg_ao CK_INFRA_PWM1_SEL>,
+				  <&infracfg_ao CK_INFRA_PWM2_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_M_D4>,
+					 <&infracfg CK_INFRA_PWM>,
+					 <&infracfg CK_INFRA_PWM>,
+					 <&infracfg CK_INFRA_PWM>;
+		clock-names = "top", "main", "pwm1", "pwm2";
+		status = "disabled";
+	};
+
+	uart0: serial@11002000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11002000 0 0x400>;
+		interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_UART0_CK>;
+		assigned-clocks = <&topckgen CK_TOP_UART_SEL>,
+				  <&infracfg_ao CK_INFRA_UART0_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_CKSQ_40M>,
+					 <&infracfg CK_INFRA_UART>;
+		status = "disabled";
+	};
+
+	uart1: serial@11003000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11003000 0 0x400>;
+		interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_UART1_CK>;
+		assigned-clocks = <&infracfg_ao CK_INFRA_UART1_SEL>;
+		assigned-clock-parents = <&infracfg CK_INFRA_CK_F26M>;
+		status = "disabled";
+	};
+
+	uart2: serial@11004000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11004000 0 0x400>;
+		interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_UART2_CK>;
+		assigned-clocks = <&infracfg_ao CK_INFRA_UART2_SEL>;
+		assigned-clock-parents = <&infracfg CK_INFRA_CK_F26M>;
+		status = "disabled";
+	};
+
+        i2c0: i2c@11008000 {
+                compatible = "mediatek,mt7986-i2c";
+                reg = <0 0x11008000 0 0x90>,
+                      <0 0x10217080 0 0x80>;
+                interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+                clock-div = <5>;
+                clocks = <&infracfg_ao CK_INFRA_I2CO_CK>,
+                         <&infracfg_ao CK_INFRA_AP_DMA_CK>;
+                clock-names = "main", "dma";
+                #address-cells = <1>;
+                #size-cells = <0>;
+                status = "disabled";
+        };
+
+	thermal-zones {
+		cpu_thermal: cpu-thermal {
+			polling-delay-passive = <1000>;
+			polling-delay = <1000>;
+			thermal-sensors = <&thermal 0>;
+		};
+	};
+
+	thermal: thermal@1100c800 {
+		#thermal-sensor-cells = <1>;
+		compatible = "mediatek,mt7986-thermal";
+		reg = <0 0x1100c800 0 0x800>;
+		interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_THERM_CK>,
+			 <&infracfg_ao CK_INFRA_ADC_26M_CK>,
+			 <&infracfg_ao CK_INFRA_ADC_FRC_CK>;
+		clock-names = "therm", "auxadc", "adc_32k";
+		mediatek,auxadc = <&auxadc>;
+		mediatek,apmixedsys = <&apmixedsys>;
+		nvmem-cells = <&thermal_calibration>;
+		nvmem-cell-names = "calibration-data";
+	};
+
+	pcie0: pcie@11280000 {
+		compatible = "mediatek,mt7986-pcie";
+		reg = <0 0x11280000 0 0x5000>;
+		reg-names = "pcie-mac";
+		#address-cells = <3>;
+		#size-cells = <2>;
+		interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+		bus-range = <0x00 0xff>;
+		ranges = <0x82000000 0 0x20000000
+			  0x0 0x20000000 0 0x10000000>;
+		status = "disabled";
+
+		clocks = <&infracfg_ao CK_INFRA_PCIE_SEL>,
+			 <&infracfg_ao CK_INFRA_IPCIE_CK>,
+			 <&infracfg_ao CK_INFRA_IPCIE_PIPE_CK>,
+			 <&infracfg_ao CK_INFRA_IPCIER_CK>,
+			 <&infracfg_ao CK_INFRA_IPCIEB_CK>;
+
+		phys = <&pcieport PHY_TYPE_PCIE>;
+		phy-names = "pcie-phy";
+
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 7>;
+		interrupt-map = <0 0 0 1 &pcie_intc0 0>,
+				<0 0 0 2 &pcie_intc0 1>,
+				<0 0 0 3 &pcie_intc0 2>,
+				<0 0 0 4 &pcie_intc0 3>;
+		pcie_intc0: interrupt-controller {
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <1>;
+		};
+	};
+
+	crypto: crypto@10320000 {
+		compatible = "inside-secure,safexcel-eip97";
+		reg = <0 0x10320000 0 0x40000>;
+		interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "ring0", "ring1", "ring2", "ring3";
+		clocks = <&infracfg_ao CK_INFRA_EIP97_CK>;
+		clock-names = "infra_eip97_ck";
+		assigned-clocks = <&topckgen CK_TOP_EIP_B_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_NET2_800M>;
+	};
+
+	pio: pinctrl@1001f000 {
+		compatible = "mediatek,mt7986-pinctrl";
+		reg = <0 0x1001f000 0 0x1000>,
+		      <0 0x11c30000 0 0x1000>,
+		      <0 0x11c40000 0 0x1000>,
+		      <0 0x11e20000 0 0x1000>,
+		      <0 0x11e30000 0 0x1000>,
+		      <0 0x11f00000 0 0x1000>,
+		      <0 0x11f10000 0 0x1000>,
+		      <0 0x1000b000 0 0x1000>;
+		reg-names = "gpio_base", "iocfg_rt_base", "iocfg_rb_base",
+			    "iocfg_lt_base", "iocfg_lb_base", "iocfg_tr_base",
+			    "iocfg_tl_base", "eint";
+		gpio-controller;
+		#gpio-cells = <2>;
+		gpio-ranges = <&pio 0 0 100>;
+		interrupt-controller;
+		interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-parent = <&gic>;
+		#interrupt-cells = <2>;
+	};
+
+	ethsys: syscon@15000000 {
+                #address-cells = <1>;
+                #size-cells = <1>;
+                compatible = "mediatek,mt7986-ethsys_ck",
+                             "syscon";
+                reg = <0 0x15000000 0 0x1000>;
+                #clock-cells = <1>;
+                #reset-cells = <1>;
+
+		ethsysrst: reset-controller {
+			compatible = "ti,syscon-reset";
+			#reset-cells = <1>;
+			ti,reset-bits = <0x34 4 0x34 4 0x34 4 (ASSERT_SET | DEASSERT_CLEAR | STATUS_SET)>;
+		};
+        };
+
+        eth: ethernet@15100000 {
+                compatible = "mediatek,mt7986-eth";
+                reg = <0 0x15100000 0 0x80000>;
+                interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
+                clocks = <&ethsys CK_ETH_FE_EN>,
+                         <&ethsys CK_ETH_GP2_EN>,
+                         <&ethsys CK_ETH_GP1_EN>,
+                         <&ethsys CK_ETH_WOCPU1_EN>,
+                         <&ethsys CK_ETH_WOCPU0_EN>,
+                         <&sgmiisys0 CK_SGM0_TX_EN>,
+                         <&sgmiisys0 CK_SGM0_RX_EN>,
+                         <&sgmiisys0 CK_SGM0_CK0_EN>,
+                         <&sgmiisys0 CK_SGM0_CDR_CK0_EN>,
+                         <&sgmiisys1 CK_SGM1_TX_EN>,
+                         <&sgmiisys1 CK_SGM1_RX_EN>,
+                         <&sgmiisys1 CK_SGM1_CK1_EN>,
+                         <&sgmiisys1 CK_SGM1_CDR_CK1_EN>;
+                clock-names = "fe", "gp2", "gp1", "wocpu1", "wocpu0",
+                         "sgmii_tx250m", "sgmii_rx250m",
+                         "sgmii_cdr_ref", "sgmii_cdr_fb",
+                         "sgmii2_tx250m", "sgmii2_rx250m",
+                         "sgmii2_cdr_ref", "sgmii2_cdr_fb";
+		assigned-clocks = <&topckgen CK_TOP_NETSYS_2X_SEL>,
+				  <&topckgen CK_TOP_SGM_325M_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_NET2_800M>,
+					 <&topckgen CK_TOP_CB_SGM_325M>;
+                mediatek,ethsys = <&ethsys>;
+		mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
+                #reset-cells = <1>;
+                #address-cells = <1>;
+                #size-cells = <0>;
+                status = "disabled";
+        };
+
+	hnat: hnat@15000000 {
+		compatible = "mediatek,mtk-hnat_v4";
+		reg = <0 0x15100000 0 0x80000>;
+		resets = <&ethsys 0>;
+		reset-names = "mtketh";
+		status = "disabled";
+	};
+
+	sgmiisys0: syscon@10060000 {
+		compatible = "mediatek,mt7986-sgmiisys",
+				"mediatek,mt7986-sgmiisys_0",
+				"syscon";
+		reg = <0 0x10060000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	sgmiisys1: syscon@10070000 {
+		compatible = "mediatek,mt7986-sgmiisys",
+				 "mediatek,mt7986-sgmiisys_1",
+				 "syscon";
+		reg = <0 0x10070000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	snand: snfi@11005000 {
+		compatible = "mediatek,mt7986-snand";
+		reg = <0 0x11005000 0 0x1000>, <0 0x11006000 0 0x1000>;
+		reg-names = "nfi", "ecc";
+		interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_SPINFI1_CK>,
+			 <&infracfg_ao CK_INFRA_NFI1_CK>,
+			 <&infracfg_ao CK_INFRA_NFI_HCK_CK>;
+		clock-names = "pad_clk", "nfi_clk", "nfi_hclk";
+		assigned-clocks = <&topckgen CK_TOP_SPINFI_SEL>,
+			 	  <&topckgen CK_TOP_NFI1X_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_M_D8>,
+					 <&topckgen CK_TOP_CB_M_D8>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	wbsys: wbsys@18000000 {
+		compatible = "mediatek,wbsys",
+			     "mediatek,mt7986-wmac";
+		resets = <&watchdog MT7986_TOPRGU_CONSYS_RST>;
+		reset-names = "consys";
+		reg = <0 0x18000000 0 0x1000000>,
+		      <0 0x10003000 0 0x1000>,
+		      <0 0x11d10000 0 0x1000>;
+		interrupts = <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 215 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>;
+		chip_id = <0x7986>;
+		memory-region = <&wmcpu_emi>;
+	};
+
+	wed_pcie: wed_pcie@10003000 {
+		compatible = "mediatek,wed_pcie";
+		reg = <0 0x10003000 0 0x10>;
+	};
+
+	spi0: spi@1100a000 {
+		compatible = "mediatek,ipm-spi-quad";
+		reg = <0 0x1100a000 0 0x100>;
+		interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&topckgen CK_TOP_CB_M_D2>,
+			 <&topckgen CK_TOP_SPI_SEL>,
+			 <&infracfg_ao CK_INFRA_SPI0_CK>,
+			 <&infracfg_ao CK_INFRA_SPI0_HCK_CK>;
+		clock-names = "parent-clk", "sel-clk", "spi-clk", "spi-hclk";
+		status = "disabled";
+	};
+
+	spi1: spi@1100b000 {
+		compatible = "mediatek,ipm-spi-single";
+		reg = <0 0x1100b000 0 0x100>;
+		interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&topckgen CK_TOP_CB_M_D2>,
+			 <&topckgen CK_TOP_SPIM_MST_SEL>,
+			 <&infracfg_ao CK_INFRA_SPI1_CK>,
+			 <&infracfg_ao CK_INFRA_SPI1_HCK_CK>;
+		clock-names = "parent-clk", "sel-clk", "spi-clk", "spi-hclk";
+		status = "disabled";
+	};
+
+	mmc0: mmc@11230000 {
+		compatible = "mediatek,mt7986-mmc";
+		reg = <0 0x11230000 0 0x1000>,
+			<0 0x11c20000 0 0x1000>;
+		interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&topckgen CK_TOP_EMMC_416M>,
+			<&topckgen CK_TOP_EMMC_250M>,
+			<&infracfg_ao CK_INFRA_MSDC_CK>;
+		clock-names = "source", "hclk", "source_cg";
+		assigned-clocks = <&topckgen CK_TOP_EMMC_416M_SEL>,
+				  <&topckgen CK_TOP_EMMC_250M_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_M_416M>,
+					 <&topckgen CK_TOP_NET1_D5_D2>;
+		status = "disabled";
+	};
+
+	auxadc: adc@1100d000 {
+		compatible = "mediatek,mt7986-auxadc",
+			     "mediatek,mt7622-auxadc";
+		reg = <0 0x1100d000 0 0x1000>;
+		clocks = <&infracfg_ao CK_INFRA_ADC_26M_CK>,
+			 <&infracfg_ao CK_INFRA_ADC_FRC_CK>;
+		clock-names = "main", "32k";
+		#io-channel-cells = <1>;
+		status = "disabled";
+	};
+
+	consys: consys@10000000 {
+		compatible = "mediatek,mt7986-consys";
+		reg = <0 0x10000000 0 0x8600000>;
+		memory-region = <&wmcpu_emi>;
+	};
+
+	xhci: xhci@11200000 {
+		compatible = "mediatek,mt7986-xhci",
+			     "mediatek,mtk-xhci";
+		reg = <0 0x11200000 0 0x2e00>,
+		      <0 0x11203e00 0 0x0100>;
+		reg-names = "mac", "ippc";
+		interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&u2port0 PHY_TYPE_USB2>,
+		       <&u3port0 PHY_TYPE_USB3>,
+		       <&u2port1 PHY_TYPE_USB2>;
+		clocks = <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>;
+		clock-names = "sys_ck",
+			      "xhci_ck",
+			      "ref_ck",
+			      "mcu_ck",
+			      "dma_ck";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		status = "okay";
+	};
+
+	pcietphy: pcie-phy@11c00000 {
+		compatible = "mediatek,mt7986",
+			     "mediatek,generic-tphy-v4";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+		status = "okay";
+
+		pcieport: pcie-phy@11c00000 {
+			reg = <0 0x11c00000 0 0x20000>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			auto_load_valid;
+			auto_load_valid_ln1;
+			nvmem-cells = <&pcie_intr_ln0>,
+				      <&pcie_rx_imp_ln0>,
+				      <&pcie_tx_imp_ln0>,
+				      <&pcie_auto_load_valid_ln0>,
+				      <&pcie_intr_ln1>,
+				      <&pcie_rx_imp_ln1>,
+				      <&pcie_tx_imp_ln1>,
+				      <&pcie_auto_load_valid_ln1>;
+			nvmem-cell-names = "intr",
+					   "rx_imp",
+					   "tx_imp",
+					   "auto_load_valid",
+					   "intr_ln1",
+					   "rx_imp_ln1",
+					   "tx_imp_ln1",
+					   "auto_load_valid_ln1";
+			status = "okay";
+		};
+	};
+
+	usbtphy: usb-phy@11e10000 {
+		compatible = "mediatek,mt7986",
+			     "mediatek,generic-tphy-v2";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+		status = "okay";
+
+		u2port0: usb-phy@11e10000 {
+			reg = <0 0x11e10000 0 0x700>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			auto_load_valid;
+			nvmem-cells = <&u2_intr_p0>, <&u2_auto_load_valid_p0>;
+			nvmem-cell-names = "intr", "auto_load_valid";
+			status = "okay";
+		};
+
+		u3port0: usb-phy@11e10700 {
+			reg = <0 0x11e10700 0 0x900>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			auto_load_valid;
+			nvmem-cells = <&comb_intr_p0>,
+			      <&comb_rx_imp_p0>,
+			      <&comb_tx_imp_p0>,
+			      <&comb_auto_load_valid>;
+			nvmem-cell-names = "intr", "rx_imp", "tx_imp", "auto_load_valid";
+			status = "okay";
+		};
+
+		u2port1: usb-phy@11e11000 {
+			reg = <0 0x11e11000 0 0x700>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			auto_load_valid;
+			nvmem-cells = <&u2_intr_p1>, <&u2_auto_load_valid_p1>;
+			nvmem-cell-names = "intr", "auto_load_valid";
+			status = "okay";
+		};
+	};
+
+	clkitg: clkitg {
+		compatible = "simple-bus";
+	};
+
+	afe: audio-controller@11210000 {
+		compatible = "mediatek,mt79xx-audio";
+		reg = <0 0x11210000 0 0x9000>;
+		interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_AUD_BUS_CK>,
+			 <&infracfg_ao CK_INFRA_AUD_26M_CK>,
+			 <&infracfg_ao CK_INFRA_AUD_L_CK>,
+			 <&infracfg_ao CK_INFRA_AUD_AUD_CK>,
+			 <&infracfg_ao CK_INFRA_AUD_EG2_CK>;
+		clock-names = "aud_bus_ck",
+			      "aud_26m_ck",
+			      "aud_l_ck",
+			      "aud_aud_ck",
+			      "aud_eg2_ck";
+		assigned-clocks = <&topckgen CK_TOP_A1SYS_SEL>,
+				  <&topckgen CK_TOP_AUD_L_SEL>,
+				  <&topckgen CK_TOP_A_TUNER_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_APLL2_D4>,
+					 <&topckgen CK_TOP_CB_APLL2_196M>,
+					 <&topckgen CK_TOP_APLL2_D4>;
+	};
+
+	trng: trng@1020f000 {
+		compatible = "mediatek,mt7986-rng",
+			     "mediatek,mt7623-rng";
+		reg = <0 0x1020f000 0 0x100>;
+		clocks = <&infracfg_ao CK_INFRA_TRNG_CK>;
+		clock-names = "rng";
+	};
+
+	ice: ice_debug {
+		compatible = "mediatek,mt7986-ice_debug",
+			"mediatek,mt2701-ice_debug";
+		clocks = <&infracfg_ao CK_INFRA_DBG_CK>,
+			 <&topckgen CK_TOP_ARM_DB_JTSEL>;
+		clock-names = "ice_dbg", "dbg_jtsel";
+	};
+
+	efuse: efuse@11d00000 {
+		compatible = "mediatek,mt7986-efuse",
+			     "mediatek,efuse";
+		reg = <0 0x11d00000 0 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		thermal_calibration: calib@274 {
+			reg = <0x274 0xc>;
+		};
+
+		comb_auto_load_valid: usb3-alv-imp@8da {
+			reg = <0x8da 1>;
+			bits = <0 1>;
+		};
+
+		comb_rx_imp_p0: usb3-rx-imp@8d8 {
+			reg = <0x8d8 1>;
+			bits = <0 5>;
+		};
+
+		comb_tx_imp_p0: usb3-tx-imp@8d8 {
+			reg = <0x8d8 2>;
+			bits = <5 5>;
+		};
+
+		comb_intr_p0: usb3-intr@8d9 {
+			reg = <0x8d9 1>;
+			bits = <2 6>;
+		};
+
+		u2_auto_load_valid_p0: usb2-alv-p0@8e0 {
+			reg  = <0x8e0 1>;
+			bits = <0 1>;
+		};
+
+		u2_intr_p0: usb2-intr-p0@8e0 {
+			reg  = <0x8e0 1>;
+			bits = <1 5>;
+		};
+
+		u2_auto_load_valid_p1: usb2-alv-p1@8e0 {
+			reg  = <0x8e0 2>;
+			bits = <6 1>;
+		};
+
+		u2_intr_p1: usb2-intr-p1@8e0 {
+			reg  = <0x8e0 2>;
+			bits = <7 5>;
+		};
+
+		pcie_rx_imp_ln0: pcie-rx-imp@8d0 {
+			reg = <0x8d0 1>;
+			bits = <0 5>;
+		};
+
+		pcie_tx_imp_ln0: pcie-tx-imp@8d0 {
+			reg = <0x8d0 2>;
+			bits = <5 5>;
+		};
+
+		pcie_intr_ln0: pcie-intr@8d1 {
+			reg = <0x8d1 1>;
+			bits = <2 6>;
+		};
+
+		pcie_auto_load_valid_ln0: pcie-ln0-alv@8d4 {
+			reg = <0x8d4 1>;
+			bits = <0 1>;
+		};
+
+		pcie_rx_imp_ln1: pcie-rx-imp@8d2 {
+			reg = <0x8d2 1>;
+			bits = <0 5>;
+		};
+
+		pcie_tx_imp_ln1: pcie-tx-imp@8d2 {
+			reg = <0x8d2 2>;
+			bits = <5 5>;
+		};
+
+		pcie_intr_ln1: pcie-intr@8d3 {
+			reg = <0x8d3 1>;
+			bits = <2 6>;
+		};
+
+		pcie_auto_load_valid_ln1: pcie-ln1-alv@8d4 {
+			reg = <0x8d4 1>;
+			bits = <1 1>;
+		};
+	};
+};
+
+#include "mt7986-clkitg.dtsi"
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-emmc-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-emmc-rfb.dts
new file mode 100644
index 0000000..d768e45
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-emmc-rfb.dts
@@ -0,0 +1,245 @@
+/dts-v1/;
+#include "mt7986b.dtsi"
+#include "mt7986b-pinctrl.dtsi"
+/ {
+	model = "MediaTek MT7986b RFB";
+	compatible = "mediatek,mt7986b-emmc-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000 \
+				root=PARTLABEL=rootfs rootwait rootfstype=squashfs,f2fs";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+/* Warning: pins shared with &snand */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+/* Warning: pins shared with &spi1 */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "disabled";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@4 {
+					reg = <4>;
+					label = "lan4";
+				};
+
+				port@5 {
+					reg = <5>;
+					label = "lan5";
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+/* Warning: pins shared with &uart2 */
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_pins_default>;
+	pinctrl-1 = <&mmc0_pins_uhs>;
+	bus-width = <8>;
+	max-frequency = <50000000>;
+	cap-mmc-highspeed;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_3p3v>;
+	non-removable;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
+
+&pio {
+	mmc0_pins_default: mmc0-pins-22-to-32-default {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+		conf-cmd-dat {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO",
+			       "SPI0_CS", "SPI0_HOLD", "SPI0_WP",
+			       "SPI1_CLK", "SPI1_MOSI", "SPI1_MISO";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+		conf-clk {
+			pins = "SPI1_CS";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-rst {
+			pins = "PWM1";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+
+	mmc0_pins_uhs: mmc0-pins-22-to-32-uhs {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+		conf-cmd-dat {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO",
+			       "SPI0_CS", "SPI0_HOLD", "SPI0_WP",
+			       "SPI1_CLK", "SPI1_MOSI", "SPI1_MISO";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+		conf-clk {
+			pins = "SPI1_CS";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-rst {
+			pins = "PWM1";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-gsw-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-gsw-spim-nand-rfb.dts
new file mode 100644
index 0000000..840b52f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-gsw-spim-nand-rfb.dts
@@ -0,0 +1,198 @@
+/dts-v1/;
+#include "mt7986b.dtsi"
+#include "mt7986b-pinctrl.dtsi"
+#include "mt7986-spim-nand-partition.dtsi"
+/ {
+	model = "MediaTek MT7986b gsw RFB";
+	compatible = "mediatek,mt7986b-gsw-spim-snand-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	gsw: gsw@0 {
+		compatible = "mediatek,mt753x";
+		mediatek,ethsys = <&ethsys>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+/* Warning: pins shared with &snand */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+/* Warning: pins shared with &spi1 */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "disabled";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+	};
+};
+
+&gsw {
+	mediatek,mdio = <&mdio>;
+	mediatek,portmap = "lllll";
+	mediatek,mdio_master_pinmux = <1>;
+	reset-gpios = <&pio 5 0>;
+	interrupt-parent = <&pio>;
+	interrupts = <66 IRQ_TYPE_LEVEL_HIGH>;
+	status = "okay";
+
+	port5: port@5 {
+		compatible = "mediatek,mt753x-port";
+		reg = <5>;
+		phy-mode = "sgmii";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+		};
+
+	};
+
+	port6: port@6 {
+		compatible = "mediatek,mt753x-port";
+		mediatek,ssc-on;
+		reg = <6>;
+		phy-mode = "sgmii";
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	cs-gpios = <0>, <0>;
+	status = "okay";
+
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <20000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+
+	spi_nand: spi_nand@1 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-max-frequency = <20000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+/* Warning: pins shared with &uart2 */
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
+
+&pio {
+	spi_flash_pins: spi-flash-pins-33-to-38 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-sd-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-sd-rfb.dts
new file mode 100644
index 0000000..953cca1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-sd-rfb.dts
@@ -0,0 +1,272 @@
+/dts-v1/;
+#include "mt7986b.dtsi"
+#include "mt7986b-pinctrl.dtsi"
+/ {
+	model = "MediaTek MT7986b RFB";
+	compatible = "mediatek,mt7986b-2500wan-sd-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+			earlycon=uart8250,mmio32,0x11002000 \
+			root=PARTLABEL=rootfs rootwait rootfstype=squashfs,f2fs";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+/* Warning: pins shared with &snand */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+/* Warning: pins shared with &spi1 */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "disabled";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@4 {
+					reg = <4>;
+					label = "lan4";
+				};
+
+				port@5 {
+					reg = <5>;
+					label = "lan5";
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_pins_default>;
+	pinctrl-1 = <&mmc0_pins_uhs>;
+	bus-width = <4>;
+	max-frequency = <52000000>;
+	cap-sd-highspeed;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_3p3v>;
+	status = "okay";
+};
+
+&pio {
+	mmc0_pins_default: mmc0-pins-22-to-32-default {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+
+		conf-cmd-dat {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO",
+			       "SPI0_CS", "SPI0_HOLD", "SPI0_WP",
+			       "SPI1_CLK", "SPI1_MOSI", "SPI1_MISO";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+
+		conf-clk {
+			pins = "SPI1_CS";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+
+		conf-rst {
+			pins = "PWM1";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+
+	mmc0_pins_uhs: mmc0-pins-22-to-32-uhs {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+
+		conf-cmd-dat {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO",
+			       "SPI0_CS", "SPI0_HOLD", "SPI0_WP",
+			       "SPI1_CLK", "SPI1_MOSI", "SPI1_MISO";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+
+		conf-clk {
+			pins = "SPI1_CS";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+
+		conf-rst {
+			pins = "PWM1";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+
+	wf_2g_5g_pins: wf_2g_5g-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_2g", "wf_5g";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+
+	wf_dbdc_pins: wf_dbdc-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_dbdc";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-snfi-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-snfi-nand-rfb.dts
new file mode 100644
index 0000000..ab72f6c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-snfi-nand-rfb.dts
@@ -0,0 +1,209 @@
+/dts-v1/;
+#include "mt7986b.dtsi"
+#include "mt7986b-pinctrl.dtsi"
+#include "mt7986-snfi-nand-partition.dtsi"
+/ {
+	model = "MediaTek MT7986b RFB";
+	compatible = "mediatek,mt7986b-snfi-snand-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+/* Warning: pins shared with &snand */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+/* Warning: pins shared with &spi1 */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "disabled";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@4 {
+					reg = <4>;
+					label = "lan4";
+				};
+
+				port@5 {
+					reg = <5>;
+					label = "lan5";
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+/* Warning: pins shared with &uart1 */
+&snand {
+	pinctrl-names = "default";
+	pinctrl-0 = <&snfi_pins>;
+	mediatek,quad-spi;
+	status = "okay";
+
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+	};
+};
+
+/* Warning: pins shared with &uart2 */
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
+
+&pio {
+	snfi_pins: snfi-pins-23-to-28 {
+		mux {
+			function = "flash";
+			groups = "snfi";
+		};
+		conf-clk {
+			pins = "SPI0_CLK";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+		conf-pu {
+			pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI0_MOSI", "SPI0_MISO";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-spim-nand-rfb.dts
new file mode 100644
index 0000000..d2b3ba3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-spim-nand-rfb.dts
@@ -0,0 +1,255 @@
+/dts-v1/;
+#include "mt7986b.dtsi"
+#include "mt7986b-pinctrl.dtsi"
+#include "mt7986-spim-nand-partition.dtsi"
+/ {
+	model = "MediaTek MT7986b RFB";
+	compatible = "mediatek,mt7986b-2500wan-spim-snand-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+/* Warning: pins shared with &snand */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+/* Warning: pins shared with &spi1 */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "disabled";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@4 {
+					reg = <4>;
+					label = "lan4";
+				};
+
+				port@5 {
+					reg = <5>;
+					label = "lan5";
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	cs-gpios = <0>, <0>;
+	status = "okay";
+
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <20000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+
+	spi_nand: spi_nand@1 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-max-frequency = <20000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+/* Warning: pins shared with &uart2 */
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+	pinctrl-names = "default", "dbdc";
+	pinctrl-0 = <&wf_2g_5g_pins>;
+	pinctrl-1 = <&wf_dbdc_pins>;
+};
+
+&pio {
+	spi_flash_pins: spi-flash-pins-33-to-38 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+
+	};
+
+	wf_2g_5g_pins: wf_2g_5g-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_2g", "wf_5g";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+
+	wf_dbdc_pins: wf_dbdc-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_dbdc";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-spim-nor-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-spim-nor-rfb.dts
new file mode 100644
index 0000000..277eec2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-spim-nor-rfb.dts
@@ -0,0 +1,208 @@
+/dts-v1/;
+#include "mt7986b.dtsi"
+#include "mt7986b-pinctrl.dtsi"
+#include "mt7986-spim-nor-partition.dtsi"
+/ {
+	model = "MediaTek MT7986b RFB";
+	compatible = "mediatek,mt7986b-nor-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+/* Warning: pins shared with &snand */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+/* Warning: pins shared with &spi1 */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "disabled";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@4 {
+					reg = <4>;
+					label = "lan4";
+				};
+
+				port@5 {
+					reg = <5>;
+					label = "lan5";
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	cs-gpios = <0>, <0>;
+	status = "okay";
+
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+/* Warning: pins shared with &uart2 */
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
+
+&pio {
+	spi_flash_pins: spi-flash-pins-33-to-38 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-emmc-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-emmc-rfb.dts
new file mode 100644
index 0000000..483c098
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-emmc-rfb.dts
@@ -0,0 +1,229 @@
+/dts-v1/;
+#include "mt7986b.dtsi"
+#include "mt7986b-pinctrl.dtsi"
+/ {
+	model = "MediaTek MT7986b RFB";
+	compatible = "mediatek,mt7986b-emmc-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000 \
+				root=PARTLABEL=rootfs rootwait rootfstype=squashfs,f2fs";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+/* Warning: pins shared with &snand */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+/* Warning: pins shared with &spi1 */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "disabled";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+/* Warning: pins shared with &uart2 */
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_pins_default>;
+	pinctrl-1 = <&mmc0_pins_uhs>;
+	bus-width = <8>;
+	max-frequency = <52000000>;
+	cap-mmc-highspeed;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_3p3v>;
+	non-removable;
+	no-sd;
+	no-sdio;
+	status = "okay";
+};
+
+&wbsys {
+	status = "okay";
+};
+
+&pio {
+	mmc0_pins_default: mmc0-pins-22-to-32-default {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+		conf-cmd-dat {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO",
+			       "SPI0_CS", "SPI0_HOLD", "SPI0_WP",
+			       "SPI1_CLK", "SPI1_MOSI", "SPI1_MISO";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+		conf-clk {
+			pins = "SPI1_CS";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-rst {
+			pins = "PWM1";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+
+	mmc0_pins_uhs: mmc0-pins-22-to-32-uhs {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+		conf-cmd-dat {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO",
+			       "SPI0_CS", "SPI0_HOLD", "SPI0_WP",
+			       "SPI1_CLK", "SPI1_MOSI", "SPI1_MISO";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+		conf-clk {
+			pins = "SPI1_CS";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-rst {
+			pins = "PWM1";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-pinctrl.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-pinctrl.dtsi
new file mode 100644
index 0000000..de8e325
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-pinctrl.dtsi
@@ -0,0 +1,29 @@
+&pio {
+	i2c_pins: i2c-pins-3-4 {
+		mux {
+			function = "i2c";
+			groups = "i2c";
+		};
+	};
+
+	uart1_pins: uart1-pins-23-to-26 {
+		mux {
+			function = "uart";
+			groups = "uart1_1";
+		};
+	};
+
+	uart2_pins: uart1-pins-29-to-32 {
+		mux {
+			function = "uart";
+			groups = "uart2_0";
+		};
+	};
+
+	spic_pins: spi1-pins-29-to-32 {
+		mux {
+			function = "spi";
+			groups = "spi1_2";
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-snfi-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-snfi-nand-rfb.dts
new file mode 100644
index 0000000..b260808
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-snfi-nand-rfb.dts
@@ -0,0 +1,192 @@
+/dts-v1/;
+#include "mt7986b.dtsi"
+#include "mt7986b-pinctrl.dtsi"
+#include "mt7986-snfi-nand-partition.dtsi"
+/ {
+	model = "MediaTek MT7986b RFB";
+	compatible = "mediatek,mt7986b-snfi-snand-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+/* Warning: pins shared with &snand */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+/* Warning: pins shared with &spi1 */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "disabled";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+/* Warning: pins shared with &uart1 */
+&snand {
+	pinctrl-names = "default";
+	pinctrl-0 = <&snfi_pins>;
+	mediatek,quad-spi;
+	status = "okay";
+
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+	};
+};
+
+/* Warning: pins shared with &uart2 */
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
+
+&pio {
+	snfi_pins: snfi-pins-23-to-28 {
+		mux {
+			function = "flash";
+			groups = "snfi";
+		};
+		conf-clk {
+			pins = "SPI0_CLK";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+		conf-pu {
+			pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI0_MOSI", "SPI0_MISO";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-spim-nand-rfb.dts
new file mode 100644
index 0000000..6cecec9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-spim-nand-rfb.dts
@@ -0,0 +1,238 @@
+/dts-v1/;
+#include "mt7986b.dtsi"
+#include "mt7986b-pinctrl.dtsi"
+#include "mt7986-spim-nand-partition.dtsi"
+/ {
+	model = "MediaTek MT7986b RFB";
+	compatible = "mediatek,mt7986b-spim-snand-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+/* Warning: pins shared with &snand */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+/* Warning: pins shared with &spi1 */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "disabled";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	cs-gpios = <0>, <0>;
+	status = "okay";
+
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+
+	spi_nand: spi_nand@1 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-max-frequency = <52000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+/* Warning: pins shared with &uart2 */
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+	pinctrl-names = "default", "dbdc";
+	pinctrl-0 = <&wf_2g_5g_pins>;
+	pinctrl-1 = <&wf_dbdc_pins>;
+};
+
+&pio {
+	spi_flash_pins: spi-flash-pins-33-to-38 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+
+	};
+
+	wf_2g_5g_pins: wf_2g_5g-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_2g", "wf_5g";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+
+	wf_dbdc_pins: wf_dbdc-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_dbdc";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-spim-nor-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-spim-nor-rfb.dts
new file mode 100644
index 0000000..443dbb5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-spim-nor-rfb.dts
@@ -0,0 +1,191 @@
+/dts-v1/;
+#include "mt7986b.dtsi"
+#include "mt7986b-pinctrl.dtsi"
+#include "mt7986-spim-nor-partition.dtsi"
+/ {
+	model = "MediaTek MT7986b RFB";
+	compatible = "mediatek,mt7986b-nor-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+/* Warning: pins shared with &snand */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+/* Warning: pins shared with &spi1 */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "disabled";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	cs-gpios = <0>, <0>;
+	status = "okay";
+
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+/* Warning: pins shared with &uart2 */
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
+
+&pio {
+	spi_flash_pins: spi-flash-pins-33-to-38 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b.dtsi
new file mode 100644
index 0000000..14e3640
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b.dtsi
@@ -0,0 +1,676 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Sam.Shih <sam.shih@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/phy/phy.h>
+#include <dt-bindings/reset/ti-syscon.h>
+#include <dt-bindings/clock/mt7986-clk.h>
+#include <dt-bindings/thermal/thermal.h>
+#include <dt-bindings/pinctrl/mt65xx.h>
+#include <dt-bindings/reset/mt7986-resets.h>
+
+/ {
+	compatible = "mediatek,mt7986b-rfb";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu0: cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			enable-method = "psci";
+			reg = <0x0>;
+		};
+
+		cpu1: cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			enable-method = "psci";
+			reg = <0x1>;
+		};
+
+		cpu2: cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			enable-method = "psci";
+			reg = <0x2>;
+		};
+
+		cpu3: cpu@3 {
+			device_type = "cpu";
+			enable-method = "psci";
+			compatible = "arm,cortex-a53";
+			reg = <0x3>;
+		};
+	};
+
+	wed: wed@15010000 {
+		compatible = "mediatek,wed";
+		wed_num = <2>;
+		/* add this property for wed get the pci slot number. */
+		pci_slot_map = <0>, <1>;
+		reg = <0 0x15010000 0 0x1000>,
+		      <0 0x15011000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	wed2: wed2@15011000 {
+		compatible = "mediatek,wed2";
+		wed_num = <2>;
+		reg = <0 0x15010000 0 0x1000>,
+		      <0 0x15011000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	wdma: wdma@15104800 {
+		compatible = "mediatek,wed-wdma";
+		reg = <0 0x15104800 0 0x400>,
+		      <0 0x15104c00 0 0x400>;
+	};
+
+	ap2woccif: ap2woccif@151A5000 {
+		compatible = "mediatek,ap2woccif";
+		reg = <0 0x151A5000 0 0x1000>,
+		      <0 0x151AD000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>;
+        };
+
+	wocpu0_ilm: wocpu0_ilm@151E0000 {
+		compatible = "mediatek,wocpu0_ilm";
+		reg = <0 0x151E0000 0 0x8000>;
+	};
+
+        wocpu1_ilm: wocpu1_ilm@151F0000 {
+                compatible = "mediatek,wocpu1_ilm";
+                reg = <0 0x151F0000 0 0x8000>;
+        };
+
+	wocpu_dlm: wocpu_dlm@151E8000 {
+		compatible = "mediatek,wocpu_dlm";
+		reg = <0 0x151E8000 0 0x2000>,
+		      <0 0x151F8000 0 0x2000>;
+
+		resets = <&ethsysrst 0>;
+		reset-names = "wocpu_rst";
+	};
+
+	cpu_boot: wocpu_boot@15194000 {
+		compatible = "mediatek,wocpu_boot";
+		reg = <0 0x15194000 0 0x1000>;
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		/* 192 KiB reserved for ARM Trusted Firmware (BL31) */
+		secmon_reserved: secmon@43000000 {
+			reg = <0 0x43000000 0 0x30000>;
+			no-map;
+		};
+
+		wmcpu_emi: wmcpu-reserved@4FC00000 {
+			compatible = "mediatek,wmcpu-reserved";
+			no-map;
+			reg = <0 0x4FC00000 0 0x00100000>;
+		};
+
+		wocpu0_emi: wocpu0_emi@4FD00000 {
+			compatible = "mediatek,wocpu0_emi";
+			no-map;
+			reg = <0 0x4FD00000 0 0x40000>;
+			shared = <0>;
+		};
+
+		wocpu1_emi: wocpu1_emi@4FD40000 {
+			compatible = "mediatek,wocpu1_emi";
+			no-map;
+			reg = <0 0x4FD40000 0 0x40000>;
+			shared = <0>;
+		};
+
+		wocpu_data: wocpu_data@4FD80000 {
+			compatible = "mediatek,wocpu_data";
+			no-map;
+			reg = <0 0x4FD80000 0 0x240000>;
+			shared = <1>;
+		};
+	};
+
+	psci {
+		compatible  = "arm,psci-0.2";
+		method      = "smc";
+	};
+
+	clk40m: oscillator@0 {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <40000000>;
+		clock-output-names = "clkxtal";
+	};
+
+	system_clk: dummy_system_clk {
+		compatible = "fixed-clock";
+		clock-frequency = <40000000>;
+		#clock-cells = <0>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupt-parent = <&gic>;
+		clock-frequency = <13000000>;
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	infracfg_ao: infracfg_ao@10001000 {
+		compatible = "mediatek,mt7986-infracfg_ao", "syscon";
+		reg = <0 0x10001000 0 0x68>;
+		#clock-cells = <1>;
+	};
+
+	infracfg: infracfg@10001040 {
+		compatible = "mediatek,mt7986-infracfg", "syscon";
+		reg = <0 0x1000106c 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	topckgen: topckgen@1001B000 {
+		compatible = "mediatek,mt7986-topckgen", "syscon";
+		reg = <0 0x1001B000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	apmixedsys: apmixedsys@1001E000 {
+		compatible = "mediatek,mt7986-apmixedsys", "syscon";
+		reg = <0 0x1001E000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	watchdog: watchdog@1001c000 {
+		compatible = "mediatek,mt7986-wdt";
+		reg = <0 0x1001c000 0 0x1000>;
+		interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+		#reset-cells = <1>;
+	};
+
+	gic: interrupt-controller@c000000 {
+		compatible = "arm,gic-v3";
+		#interrupt-cells = <3>;
+		interrupt-parent = <&gic>;
+		interrupt-controller;
+		reg = <0 0x0c000000 0 0x40000>,  /* GICD */
+		      <0 0x0c080000 0 0x200000>; /* GICR */
+
+		interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	pwm: pwm@10048000 {
+		compatible = "mediatek,mt7986-pwm";
+		reg = <0 0x10048000 0 0x1000>;
+		#clock-cells = <1>;
+		#pwm-cells = <2>;
+		interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg CK_INFRA_PWM>,
+			 <&infracfg_ao CK_INFRA_PWM_BSEL>,
+			 <&infracfg_ao CK_INFRA_PWM1_CK>,
+			 <&infracfg_ao CK_INFRA_PWM2_CK>;
+		assigned-clocks = <&topckgen CK_TOP_PWM_SEL>,
+				  <&infracfg_ao CK_INFRA_PWM_BSEL>,
+				  <&infracfg_ao CK_INFRA_PWM1_SEL>,
+				  <&infracfg_ao CK_INFRA_PWM2_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_M_D4>,
+					 <&infracfg CK_INFRA_PWM>,
+					 <&infracfg CK_INFRA_PWM>,
+					 <&infracfg CK_INFRA_PWM>;
+		clock-names = "top", "main", "pwm1", "pwm2";
+		status = "disabled";
+	};
+
+	uart0: serial@11002000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11002000 0 0x400>;
+		interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_UART0_CK>;
+		assigned-clocks = <&topckgen CK_TOP_UART_SEL>,
+				  <&infracfg_ao CK_INFRA_UART0_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_CKSQ_40M>,
+					 <&infracfg CK_INFRA_UART>;
+		status = "disabled";
+	};
+
+	uart1: serial@11003000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11003000 0 0x400>;
+		interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_UART1_CK>;
+		assigned-clocks = <&infracfg_ao CK_INFRA_UART1_SEL>;
+		assigned-clock-parents = <&infracfg CK_INFRA_CK_F26M>;
+		status = "disabled";
+	};
+
+	uart2: serial@11004000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11004000 0 0x400>;
+		interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_UART2_CK>;
+		assigned-clocks = <&infracfg_ao CK_INFRA_UART2_SEL>;
+		assigned-clock-parents = <&infracfg CK_INFRA_CK_F26M>;
+		status = "disabled";
+	};
+
+        i2c0: i2c@11008000 {
+                compatible = "mediatek,mt7986-i2c";
+                reg = <0 0x11008000 0 0x90>,
+                      <0 0x10217080 0 0x80>;
+                interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+                clock-div = <5>;
+                clocks = <&infracfg_ao CK_INFRA_I2CO_CK>,
+                         <&infracfg_ao CK_INFRA_AP_DMA_CK>;
+                clock-names = "main", "dma";
+                #address-cells = <1>;
+                #size-cells = <0>;
+                status = "disabled";
+        };
+
+	thermal-zones {
+		cpu_thermal: cpu-thermal {
+			polling-delay-passive = <1000>;
+			polling-delay = <1000>;
+			thermal-sensors = <&thermal 0>;
+		};
+	};
+
+	thermal: thermal@1100c800 {
+		#thermal-sensor-cells = <1>;
+		compatible = "mediatek,mt7986-thermal";
+		reg = <0 0x1100c800 0 0x800>;
+		interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_THERM_CK>,
+			 <&infracfg_ao CK_INFRA_ADC_26M_CK>,
+			 <&infracfg_ao CK_INFRA_ADC_FRC_CK>;
+		clock-names = "therm", "auxadc", "adc_32k";
+		mediatek,auxadc = <&auxadc>;
+		mediatek,apmixedsys = <&apmixedsys>;
+		nvmem-cells = <&thermal_calibration>;
+		nvmem-cell-names = "calibration-data";
+	};
+
+	crypto: crypto@10320000 {
+		compatible = "inside-secure,safexcel-eip97";
+		reg = <0 0x10320000 0 0x40000>;
+		interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "ring0", "ring1", "ring2", "ring3";
+		clocks = <&infracfg_ao CK_INFRA_EIP97_CK>;
+		clock-names = "infra_eip97_ck";
+		assigned-clocks = <&topckgen CK_TOP_EIP_B_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_NET2_800M>;
+	};
+
+	pio: pinctrl@1001f000 {
+		compatible = "mediatek,mt7986-pinctrl";
+		reg = <0 0x1001f000 0 0x1000>,
+		      <0 0x11c30000 0 0x1000>,
+		      <0 0x11c40000 0 0x1000>,
+		      <0 0x11e20000 0 0x1000>,
+		      <0 0x11e30000 0 0x1000>,
+		      <0 0x11f00000 0 0x1000>,
+		      <0 0x11f10000 0 0x1000>,
+		      <0 0x1000b000 0 0x1000>;
+		reg-names = "gpio_base", "iocfg_rt_base", "iocfg_rb_base",
+			    "iocfg_lt_base", "iocfg_lb_base", "iocfg_tr_base",
+			    "iocfg_tl_base", "eint";
+		gpio-controller;
+		#gpio-cells = <2>;
+		gpio-ranges = <&pio 0 0 100>;
+		interrupt-controller;
+		interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-parent = <&gic>;
+		#interrupt-cells = <2>;
+	};
+
+	ethsys: syscon@15000000 {
+                #address-cells = <1>;
+                #size-cells = <1>;
+                compatible = "mediatek,mt7986-ethsys_ck",
+                             "syscon";
+                reg = <0 0x15000000 0 0x1000>;
+                #clock-cells = <1>;
+                #reset-cells = <1>;
+
+		ethsysrst: reset-controller {
+			compatible = "ti,syscon-reset";
+			#reset-cells = <1>;
+			ti,reset-bits = <0x34 4 0x34 4 0x34 4 (ASSERT_SET | DEASSERT_CLEAR | STATUS_SET)>;
+		};
+        };
+
+        eth: ethernet@15100000 {
+                compatible = "mediatek,mt7986-eth";
+                reg = <0 0x15100000 0 0x80000>;
+                interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
+                clocks = <&ethsys CK_ETH_FE_EN>,
+                         <&ethsys CK_ETH_GP2_EN>,
+                         <&ethsys CK_ETH_GP1_EN>,
+                         <&ethsys CK_ETH_WOCPU1_EN>,
+                         <&ethsys CK_ETH_WOCPU0_EN>,
+                         <&sgmiisys0 CK_SGM0_TX_EN>,
+                         <&sgmiisys0 CK_SGM0_RX_EN>,
+                         <&sgmiisys0 CK_SGM0_CK0_EN>,
+                         <&sgmiisys0 CK_SGM0_CDR_CK0_EN>,
+                         <&sgmiisys1 CK_SGM1_TX_EN>,
+                         <&sgmiisys1 CK_SGM1_RX_EN>,
+                         <&sgmiisys1 CK_SGM1_CK1_EN>,
+                         <&sgmiisys1 CK_SGM1_CDR_CK1_EN>;
+                clock-names = "fe", "gp2", "gp1", "wocpu1", "wocpu0",
+                         "sgmii_tx250m", "sgmii_rx250m",
+                         "sgmii_cdr_ref", "sgmii_cdr_fb",
+                         "sgmii2_tx250m", "sgmii2_rx250m",
+                         "sgmii2_cdr_ref", "sgmii2_cdr_fb";
+		assigned-clocks = <&topckgen CK_TOP_NETSYS_2X_SEL>,
+				  <&topckgen CK_TOP_SGM_325M_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_NET2_800M>,
+					 <&topckgen CK_TOP_CB_SGM_325M>;
+                mediatek,ethsys = <&ethsys>;
+		mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
+                #reset-cells = <1>;
+                #address-cells = <1>;
+                #size-cells = <0>;
+                status = "disabled";
+        };
+
+	hnat: hnat@15000000 {
+		compatible = "mediatek,mtk-hnat_v4";
+		reg = <0 0x15100000 0 0x80000>;
+		resets = <&ethsys 0>;
+		reset-names = "mtketh";
+		status = "disabled";
+	};
+
+	sgmiisys0: syscon@10060000 {
+		compatible = "mediatek,mt7986-sgmiisys",
+				"mediatek,mt7986-sgmiisys_0",
+				"syscon";
+		reg = <0 0x10060000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	sgmiisys1: syscon@10070000 {
+		compatible = "mediatek,mt7986-sgmiisys",
+				 "mediatek,mt7986-sgmiisys_1",
+				 "syscon";
+		reg = <0 0x10070000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	snand: snfi@11005000 {
+		compatible = "mediatek,mt7986-snand";
+		reg = <0 0x11005000 0 0x1000>, <0 0x11006000 0 0x1000>;
+		reg-names = "nfi", "ecc";
+		interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_SPINFI1_CK>,
+			 <&infracfg_ao CK_INFRA_NFI1_CK>,
+			 <&infracfg_ao CK_INFRA_NFI_HCK_CK>;
+		clock-names = "pad_clk", "nfi_clk", "nfi_hclk";
+		assigned-clocks = <&topckgen CK_TOP_SPINFI_SEL>,
+			 	  <&topckgen CK_TOP_NFI1X_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_M_D8>,
+					 <&topckgen CK_TOP_CB_M_D8>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	wbsys: wbsys@18000000 {
+		compatible = "mediatek,wbsys",
+			     "mediatek,mt7986-wmac";
+		resets = <&watchdog MT7986_TOPRGU_CONSYS_RST>;
+		reset-names = "consys";
+		reg = <0 0x18000000 0 0x1000000>,
+		      <0 0x10003000 0 0x1000>,
+		      <0 0x11d10000 0 0x1000>;
+		interrupts = <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 215 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>;
+		chip_id = <0x7986>;
+		memory-region = <&wmcpu_emi>;
+	};
+
+	wed_pcie: wed_pcie@10003000 {
+		compatible = "mediatek,wed_pcie";
+		reg = <0 0x10003000 0 0x10>;
+	};
+
+	spi0: spi@1100a000 {
+		compatible = "mediatek,ipm-spi-quad";
+		reg = <0 0x1100a000 0 0x100>;
+		interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&topckgen CK_TOP_CB_M_D2>,
+			 <&topckgen CK_TOP_SPI_SEL>,
+			 <&infracfg_ao CK_INFRA_SPI0_CK>,
+			 <&infracfg_ao CK_INFRA_SPI0_HCK_CK>;
+		clock-names = "parent-clk", "sel-clk", "spi-clk", "spi-hclk";
+		status = "disabled";
+	};
+
+	spi1: spi@1100b000 {
+		compatible = "mediatek,ipm-spi-single";
+		reg = <0 0x1100b000 0 0x100>;
+		interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&topckgen CK_TOP_CB_M_D2>,
+			 <&topckgen CK_TOP_SPIM_MST_SEL>,
+			 <&infracfg_ao CK_INFRA_SPI1_CK>,
+			 <&infracfg_ao CK_INFRA_SPI1_HCK_CK>;
+		clock-names = "parent-clk", "sel-clk", "spi-clk", "spi-hclk";
+		status = "disabled";
+	};
+
+	mmc0: mmc@11230000 {
+		compatible = "mediatek,mt7986-mmc";
+		reg = <0 0x11230000 0 0x1000>,
+			<0 0x11c20000 0 0x1000>;
+		interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&topckgen CK_TOP_EMMC_416M>,
+			<&topckgen CK_TOP_EMMC_250M>,
+			<&infracfg_ao CK_INFRA_MSDC_CK>;
+		clock-names = "source", "hclk", "source_cg";
+		assigned-clocks = <&topckgen CK_TOP_EMMC_416M_SEL>,
+				  <&topckgen CK_TOP_EMMC_250M_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_M_416M>,
+					 <&topckgen CK_TOP_NET1_D5_D2>;
+		status = "disabled";
+	};
+
+	auxadc: adc@1100d000 {
+		compatible = "mediatek,mt7986-auxadc",
+			     "mediatek,mt7622-auxadc";
+		reg = <0 0x1100d000 0 0x1000>;
+		clocks = <&infracfg_ao CK_INFRA_ADC_26M_CK>,
+			 <&infracfg_ao CK_INFRA_ADC_FRC_CK>;
+		clock-names = "main", "32k";
+		#io-channel-cells = <1>;
+		status = "disabled";
+	};
+
+	consys: consys@10000000 {
+		compatible = "mediatek,mt7986-consys";
+		reg = <0 0x10000000 0 0x8600000>;
+		memory-region = <&wmcpu_emi>;
+	};
+
+	xhci: xhci@11200000 {
+		compatible = "mediatek,mt7986-xhci",
+			     "mediatek,mtk-xhci";
+		reg = <0 0x11200000 0 0x2e00>,
+		      <0 0x11203e00 0 0x0100>;
+		reg-names = "mac", "ippc";
+		interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&u3port0 PHY_TYPE_USB3>,
+		       <&u2port1 PHY_TYPE_USB2>;
+		clocks = <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>;
+		clock-names = "sys_ck",
+			      "xhci_ck",
+			      "ref_ck",
+			      "mcu_ck",
+			      "dma_ck";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		status = "okay";
+	};
+
+	usbtphy: usb-phy@11e10000 {
+		compatible = "mediatek,mt7986",
+			     "mediatek,generic-tphy-v2";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+		status = "okay";
+
+		u2port0: usb-phy@11e10000 {
+			reg = <0 0x11e10000 0 0x700>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			auto_load_valid;
+			nvmem-cells = <&u2_intr_p0>, <&u2_auto_load_valid_p0>;
+			nvmem-cell-names = "intr", "auto_load_valid";
+			status = "disabled";
+		};
+
+		u3port0: usb-phy@11e10700 {
+			reg = <0 0x11e10700 0 0x900>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			auto_load_valid;
+			nvmem-cells = <&comb_intr_p0>,
+			      <&comb_rx_imp_p0>,
+			      <&comb_tx_imp_p0>,
+			      <&comb_auto_load_valid>;
+			nvmem-cell-names = "intr", "rx_imp", "tx_imp", "auto_load_valid";
+			status = "okay";
+		};
+
+		u2port1: usb-phy@11e11000 {
+			reg = <0 0x11e11000 0 0x700>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			auto_load_valid;
+			nvmem-cells = <&u2_intr_p1>, <&u2_auto_load_valid_p1>;
+			nvmem-cell-names = "intr", "auto_load_valid";
+			status = "okay";
+		};
+	};
+
+	clkitg: clkitg {
+		compatible = "simple-bus";
+	};
+
+	trng: trng@1020f000 {
+		compatible = "mediatek,mt7986-rng",
+			     "mediatek,mt7623-rng";
+		reg = <0 0x1020f000 0 0x100>;
+		clocks = <&infracfg_ao CK_INFRA_TRNG_CK>;
+		clock-names = "rng";
+	};
+
+	ice: ice_debug {
+		compatible = "mediatek,mt7986-ice_debug",
+			"mediatek,mt2701-ice_debug";
+		clocks = <&infracfg_ao CK_INFRA_DBG_CK>,
+			 <&topckgen CK_TOP_ARM_DB_JTSEL>;
+		clock-names = "ice_dbg", "dbg_jtsel";
+	};
+
+	efuse: efuse@11d00000 {
+		compatible = "mediatek,mt7986-efuse",
+			     "mediatek,efuse";
+		reg = <0 0x11d00000 0 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		thermal_calibration: calib@274 {
+			reg = <0x274 0xc>;
+		};
+
+		comb_auto_load_valid: usb3-alv-imp@8da {
+			reg = <0x8da 1>;
+			bits = <0 1>;
+		};
+
+		comb_rx_imp_p0: usb3-rx-imp@8d8 {
+			reg = <0x8d8 1>;
+			bits = <0 5>;
+		};
+
+		comb_tx_imp_p0: usb3-tx-imp@8d8 {
+			reg = <0x8d8 2>;
+			bits = <5 5>;
+		};
+
+		comb_intr_p0: usb3-intr@8d9 {
+			reg = <0x8d9 1>;
+			bits = <2 6>;
+		};
+
+		u2_auto_load_valid_p0: usb2-alv-p0@8e0 {
+			reg  = <0x8e0 1>;
+			bits = <0 1>;
+		};
+
+		u2_intr_p0: usb2-intr-p0@8e0 {
+			reg  = <0x8e0 1>;
+			bits = <1 5>;
+		};
+
+		u2_auto_load_valid_p1: usb2-alv-p1@8e0 {
+			reg  = <0x8e0 2>;
+			bits = <6 1>;
+		};
+
+		u2_intr_p1: usb2-intr-p1@8e0 {
+			reg  = <0x8e0 2>;
+			bits = <7 5>;
+		};
+	};	
+};
+
+#include "mt7986-clkitg.dtsi"
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64-rootdisk.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64-rootdisk.dts
new file mode 100644
index 0000000..36d9086
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64-rootdisk.dts
@@ -0,0 +1,591 @@
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ *
+ * SPDX-License-Identifier: (GPL-2.0-only OR MIT)
+ */
+
+/dts-v1/;
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
+
+#include "mt7622.dtsi"
+#include "mt6380.dtsi"
+
+/ {
+	model = "Bananapi BPI-R64";
+	compatible = "bananapi,bpi-r64-rootdisk", "mediatek,mt7622";
+
+	aliases {
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+		bootargs = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n1 swiotlb=512 root=/dev/mmcblk0p7 rootfstype=squashfs,f2fs";
+	};
+
+	cpus {
+		cpu@0 {
+			proc-supply = <&mt6380_vcpu_reg>;
+			sram-supply = <&mt6380_vm_reg>;
+		};
+
+		cpu@1 {
+			proc-supply = <&mt6380_vcpu_reg>;
+			sram-supply = <&mt6380_vm_reg>;
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		factory {
+			label = "factory";
+			linux,code = <BTN_0>;
+			gpios = <&pio 0 GPIO_ACTIVE_HIGH>;
+		};
+
+		wps {
+			label = "wps";
+			linux,code = <KEY_WPS_BUTTON>;
+			gpios = <&pio 102 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		green {
+			label = "bpi-r64:pio:green";
+			gpios = <&pio 89 GPIO_ACTIVE_HIGH>;
+		};
+
+		red {
+			label = "bpi-r64:pio:red";
+			gpios = <&pio 88 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x40000000>;
+	};
+
+	reg_1p8v: regulator-1p8v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-1.8V";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-always-on;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	reg_5v: regulator-5v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-5V";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&bch {
+	status = "disabled";
+};
+
+&btif {
+	status = "okay";
+};
+
+&cir {
+	pinctrl-names = "default";
+	pinctrl-0 = <&irrx_pins>;
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "rgmii";
+
+		fixed-link {
+			speed = <1000>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		switch@1f {
+			compatible = "mediatek,mt7531";
+			reg = <0x1f>;
+			reset-gpios = <&pio 54 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				wan: port@0 {
+					reg = <0>;
+					label = "wan";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan0";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan1";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan2";
+				};
+
+				port@4 {
+					reg = <4>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	status = "okay";
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins>;
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&emmc_pins_default>;
+	pinctrl-1 = <&emmc_pins_uhs>;
+	status = "okay";
+	bus-width = <8>;
+	max-frequency = <50000000>;
+	cap-mmc-highspeed;
+	mmc-hs200-1_8v;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_1p8v>;
+	assigned-clocks = <&topckgen CLK_TOP_MSDC30_0_SEL>;
+	assigned-clock-parents = <&topckgen CLK_TOP_UNIV48M>;
+	non-removable;
+};
+
+&mmc1 {
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&sd0_pins_default>;
+	pinctrl-1 = <&sd0_pins_uhs>;
+	status = "okay";
+	bus-width = <4>;
+	max-frequency = <50000000>;
+	cap-sd-highspeed;
+	r_smpl = <1>;
+	cd-gpios = <&pio 81 GPIO_ACTIVE_LOW>;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_3p3v>;
+	assigned-clocks = <&topckgen CLK_TOP_MSDC30_1_SEL>;
+	assigned-clock-parents = <&topckgen CLK_TOP_UNIV48M>;
+};
+
+&nandc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&parallel_nand_pins>;
+	status = "disabled";
+};
+
+&nor_flash {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_nor_pins>;
+	status = "disabled";
+
+	flash@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+	};
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&pcie1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie1_pins>;
+	status = "okay";
+};
+
+&pio {
+	/* Attention: GPIO 90 is used to switch between PCIe@1,0 and
+	 * SATA functions. i.e. output-high: PCIe, output-low: SATA
+	 */
+	asm_sel {
+		gpio-hog;
+		gpios = <90 GPIO_ACTIVE_HIGH>;
+		output-high;
+	};
+
+	/* eMMC is shared pin with parallel NAND */
+	emmc_pins_default: emmc-pins-default {
+		mux {
+			function = "emmc", "emmc_rst";
+			groups = "emmc";
+		};
+
+		/* "NDL0","NDL1","NDL2","NDL3","NDL4","NDL5","NDL6","NDL7",
+		 * "NRB","NCLE" pins are used as DAT0,DAT1,DAT2,DAT3,DAT4,
+		 * DAT5,DAT6,DAT7,CMD,CLK for eMMC respectively
+		 */
+		conf-cmd-dat {
+			pins = "NDL0", "NDL1", "NDL2",
+			       "NDL3", "NDL4", "NDL5",
+			       "NDL6", "NDL7", "NRB";
+			input-enable;
+			bias-pull-up;
+		};
+
+		conf-clk {
+			pins = "NCLE";
+			bias-pull-down;
+		};
+	};
+
+	emmc_pins_uhs: emmc-pins-uhs {
+		mux {
+			function = "emmc";
+			groups = "emmc";
+		};
+
+		conf-cmd-dat {
+			pins = "NDL0", "NDL1", "NDL2",
+			       "NDL3", "NDL4", "NDL5",
+			       "NDL6", "NDL7", "NRB";
+			input-enable;
+			drive-strength = <4>;
+			bias-pull-up;
+		};
+
+		conf-clk {
+			pins = "NCLE";
+			drive-strength = <4>;
+			bias-pull-down;
+		};
+	};
+
+	eth_pins: eth-pins {
+		mux {
+			function = "eth";
+			groups = "mdc_mdio", "rgmii_via_gmac2";
+		};
+	};
+
+	i2c1_pins: i2c1-pins {
+		mux {
+			function = "i2c";
+			groups =  "i2c1_0";
+		};
+	};
+
+	i2c2_pins: i2c2-pins {
+		mux {
+			function = "i2c";
+			groups =  "i2c2_0";
+		};
+	};
+
+	i2s1_pins: i2s1-pins {
+		mux {
+			function = "i2s";
+			groups =  "i2s_out_mclk_bclk_ws",
+				  "i2s1_in_data",
+				  "i2s1_out_data";
+		};
+
+		conf {
+			pins = "I2S1_IN", "I2S1_OUT", "I2S_BCLK",
+			       "I2S_WS", "I2S_MCLK";
+			drive-strength = <12>;
+			bias-pull-down;
+		};
+	};
+
+	irrx_pins: irrx-pins {
+		mux {
+			function = "ir";
+			groups =  "ir_1_rx";
+		};
+	};
+
+	irtx_pins: irtx-pins {
+		mux {
+			function = "ir";
+			groups =  "ir_1_tx";
+		};
+	};
+
+	/* Parallel nand is shared pin with eMMC */
+	parallel_nand_pins: parallel-nand-pins {
+		mux {
+			function = "flash";
+			groups = "par_nand";
+		};
+	};
+
+	pcie0_pins: pcie0-pins {
+		mux {
+			function = "pcie";
+			groups = "pcie0_pad_perst",
+				 "pcie0_1_waken",
+				 "pcie0_1_clkreq";
+		};
+	};
+
+	pcie1_pins: pcie1-pins {
+		mux {
+			function = "pcie";
+			groups = "pcie1_pad_perst",
+				 "pcie1_0_waken",
+				 "pcie1_0_clkreq";
+		};
+	};
+
+	pmic_bus_pins: pmic-bus-pins {
+		mux {
+			function = "pmic";
+			groups = "pmic_bus";
+		};
+	};
+
+	pwm7_pins: pwm1-2-pins {
+		mux {
+			function = "pwm";
+			groups = "pwm_ch7_2";
+		};
+	};
+
+	wled_pins: wled-pins {
+		mux {
+			function = "led";
+			groups = "wled";
+		};
+	};
+
+	sd0_pins_default: sd0-pins-default {
+		mux {
+			function = "sd";
+			groups = "sd_0";
+		};
+
+		/* "I2S2_OUT, "I2S4_IN"", "I2S3_IN", "I2S2_IN",
+		 *  "I2S4_OUT", "I2S3_OUT" are used as DAT0, DAT1,
+		 *  DAT2, DAT3, CMD, CLK for SD respectively.
+		 */
+		conf-cmd-data {
+			pins = "I2S2_OUT", "I2S4_IN", "I2S3_IN",
+			       "I2S2_IN","I2S4_OUT";
+			input-enable;
+			drive-strength = <8>;
+			bias-pull-up;
+		};
+		conf-clk {
+			pins = "I2S3_OUT";
+			drive-strength = <12>;
+			bias-pull-down;
+		};
+		conf-cd {
+			pins = "TXD3";
+			bias-pull-up;
+		};
+	};
+
+	sd0_pins_uhs: sd0-pins-uhs {
+		mux {
+			function = "sd";
+			groups = "sd_0";
+		};
+
+		conf-cmd-data {
+			pins = "I2S2_OUT", "I2S4_IN", "I2S3_IN",
+			       "I2S2_IN","I2S4_OUT";
+			input-enable;
+			bias-pull-up;
+		};
+
+		conf-clk {
+			pins = "I2S3_OUT";
+			bias-pull-down;
+		};
+	};
+
+	/* Serial NAND is shared pin with SPI-NOR */
+	serial_nand_pins: serial-nand-pins {
+		mux {
+			function = "flash";
+			groups = "snfi";
+		};
+	};
+
+	spic0_pins: spic0-pins {
+		mux {
+			function = "spi";
+			groups = "spic0_0";
+		};
+	};
+
+	spic1_pins: spic1-pins {
+		mux {
+			function = "spi";
+			groups = "spic1_0";
+		};
+	};
+
+	/* SPI-NOR is shared pin with serial NAND */
+	spi_nor_pins: spi-nor-pins {
+		mux {
+			function = "flash";
+			groups = "spi_nor";
+		};
+	};
+
+	/* serial NAND is shared pin with SPI-NOR */
+	serial_nand_pins: serial-nand-pins {
+		mux {
+			function = "flash";
+			groups = "snfi";
+		};
+	};
+
+	uart0_pins: uart0-pins {
+		mux {
+			function = "uart";
+			groups = "uart0_0_tx_rx" ;
+		};
+	};
+
+	uart2_pins: uart2-pins {
+		mux {
+			function = "uart";
+			groups = "uart2_1_tx_rx" ;
+		};
+	};
+
+	watchdog_pins: watchdog-pins {
+		mux {
+			function = "watchdog";
+			groups = "watchdog";
+		};
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm7_pins>;
+	status = "okay";
+};
+
+&pwrap {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pmic_bus_pins>;
+
+	status = "okay";
+};
+
+&sata {
+	status = "disable";
+};
+
+&sata_phy {
+	status = "disable";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic0_pins>;
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic1_pins>;
+	status = "okay";
+};
+
+&ssusb {
+	vusb33-supply = <&reg_3p3v>;
+	vbus-supply = <&reg_5v>;
+	status = "okay";
+};
+
+&u3phy {
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	pinctrl-names = "default";
+	pinctrl-0 = <&watchdog_pins>;
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7622-elecom-wrc-2533gent.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7622-elecom-wrc-2533gent.dts
new file mode 100644
index 0000000..2ac1c6a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7622-elecom-wrc-2533gent.dts
@@ -0,0 +1,608 @@
+/*
+ * Copyright (c) 2017 MediaTek Inc.
+ * Author: Ming Huang <ming.huang@mediatek.com>
+ *	   Sean Wang <sean.wang@mediatek.com>
+ *
+ * SPDX-License-Identifier: (GPL-2.0-only OR MIT)
+ */
+
+/dts-v1/;
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
+
+#include "mt7622.dtsi"
+#include "mt6380.dtsi"
+
+/ {
+	model = "Elecom WRC-2533";
+	compatible = "elecom,wrc-2533gent", "mediatek,mt7622";
+
+	aliases {
+		led-boot = &led_power;
+		led-failsafe = &led_power;
+		led-running = &led_power;
+		led-upgrade = &led_power;
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+		bootargs = "earlycon=uart8250,mmio32,0x11002000 swiotlb=512 console=ttyS0,115200n8";
+	};
+
+	cpus {
+		cpu@0 {
+			proc-supply = <&mt6380_vcpu_reg>;
+			sram-supply = <&mt6380_vm_reg>;
+		};
+
+		cpu@1 {
+			proc-supply = <&mt6380_vcpu_reg>;
+			sram-supply = <&mt6380_vm_reg>;
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		poll-interval = <100>;
+
+		wps {
+			label = "wps";
+			linux,code = <KEY_WPS_BUTTON>;
+			gpios = <&pio 0 GPIO_ACTIVE_HIGH>;
+		};
+
+		factory {
+			label = "factory";
+			linux,code = <KEY_WPS_BUTTON>;
+			gpios = <&pio 102 GPIO_ACTIVE_LOW>;
+		};
+
+		switch0 {
+			label = "switch0";
+			gpios = <&pio 1 GPIO_ACTIVE_LOW>;
+			linux,code = <BTN_0>;
+			linux,input-type = <EV_SW>;
+		};
+
+		switch1 {
+			label = "switch1";
+			gpios = <&pio 16 GPIO_ACTIVE_LOW>;
+			linux,code = <BTN_1>;
+			linux,input-type = <EV_SW>;
+		};
+
+		switch2 {
+			label = "switch2";
+			gpios = <&pio 17 GPIO_ACTIVE_LOW>;
+			linux,code = <BTN_2>;
+			linux,input-type = <EV_SW>;
+		};
+
+		switch3 {
+			label = "switch3";
+			gpios = <&pio 18 GPIO_ACTIVE_LOW>;
+			linux,code = <BTN_3>;
+			linux,input-type = <EV_SW>;
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led_power: power_g {
+			label = "wrc-2533:green:power";
+			gpios = <&pio 2 GPIO_ACTIVE_HIGH>;
+		};
+
+		power_b {
+			label = "wrc-2533:blue:power";
+			gpios = <&pio 19 GPIO_ACTIVE_HIGH>;
+		};
+
+		power_r {
+			label = "wrc-2533:red:power";
+			gpios = <&pio 73 GPIO_ACTIVE_HIGH>;
+		};
+
+		usb {
+			label = "wrc-2533:blue:usb";
+			gpios = <&pio 74 GPIO_ACTIVE_HIGH>;
+		};
+
+		wps {
+			label = "wrc-2533:red:wps";
+			gpios = <&pio 76 GPIO_ACTIVE_LOW>;
+		};
+
+		wifi2 {
+			label = "wrc-2533:blue:wifi2g";
+			gpios = <&pio 85 GPIO_ACTIVE_LOW>;
+		};
+
+		wifi5 {
+			label = "wrc-2533:blue:wifi5g";
+			gpios = <&pio 91 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	reg_usb_vbus: regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "usb_vbus";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&pio 22 GPIO_ACTIVE_LOW>;
+		enable-active-high;
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x3F000000>;
+	};
+
+	reg_1p8v: regulator-1p8v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-1.8V";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-always-on;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	rtkgsw: rtkgsw@0 {
+		compatible = "mediatek,rtk-gsw";
+		mediatek,ethsys = <&ethsys>;
+		mediatek,mdio = <&mdio>;
+		mediatek,reset-pin = <&pio 54 0>;
+		status = "okay";
+	};
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&slot0 {
+	mt7615@0,0 {
+		reg = <0x0000 0 0 0 0>;
+		mediatek,mtd-eeprom = <&factory 0x05000>;
+	};
+};
+
+&pio {
+	/* eMMC is shared pin with parallel NAND */
+	emmc_pins_default: emmc-pins-default {
+		mux {
+			function = "emmc", "emmc_rst";
+			groups = "emmc";
+		};
+
+		/* "NDL0","NDL1","NDL2","NDL3","NDL4","NDL5","NDL6","NDL7",
+		 * "NRB","NCLE" pins are used as DAT0,DAT1,DAT2,DAT3,DAT4,
+		 * DAT5,DAT6,DAT7,CMD,CLK for eMMC respectively
+		 */
+		conf-cmd-dat {
+			pins = "NDL0", "NDL1", "NDL2",
+			       "NDL3", "NDL4", "NDL5",
+			       "NDL6", "NDL7", "NRB";
+			input-enable;
+			bias-pull-up;
+		};
+
+		conf-clk {
+			pins = "NCLE";
+			bias-pull-down;
+		};
+	};
+
+	emmc_pins_uhs: emmc-pins-uhs {
+		mux {
+			function = "emmc";
+			groups = "emmc";
+		};
+
+		conf-cmd-dat {
+			pins = "NDL0", "NDL1", "NDL2",
+			       "NDL3", "NDL4", "NDL5",
+			       "NDL6", "NDL7", "NRB";
+			input-enable;
+			drive-strength = <4>;
+			bias-pull-up;
+		};
+
+		conf-clk {
+			pins = "NCLE";
+			drive-strength = <4>;
+			bias-pull-down;
+		};
+	};
+
+	eth_pins: eth-pins {
+		mux {
+			function = "eth";
+			groups = "mdc_mdio", "rgmii_via_gmac2";
+		};
+	};
+
+	i2c1_pins: i2c1-pins {
+		mux {
+			function = "i2c";
+			groups =  "i2c1_0";
+		};
+	};
+
+	i2c2_pins: i2c2-pins {
+		mux {
+			function = "i2c";
+			groups =  "i2c2_0";
+		};
+	};
+
+	i2s1_pins: i2s1-pins {
+		mux {
+			function = "i2s";
+			groups =  "i2s_out_mclk_bclk_ws",
+				  "i2s1_in_data",
+				  "i2s1_out_data";
+		};
+
+		conf {
+			pins = "I2S1_IN", "I2S1_OUT", "I2S_BCLK",
+			       "I2S_WS", "I2S_MCLK";
+			drive-strength = <12>;
+			bias-pull-down;
+		};
+	};
+
+	irrx_pins: irrx-pins {
+		mux {
+			function = "ir";
+			groups =  "ir_1_rx";
+		};
+	};
+
+	irtx_pins: irtx-pins {
+		mux {
+			function = "ir";
+			groups =  "ir_1_tx";
+		};
+	};
+
+	/* Parallel nand is shared pin with eMMC */
+	parallel_nand_pins: parallel-nand-pins {
+		mux {
+			function = "flash";
+			groups = "par_nand";
+		};
+	};
+
+	pcie0_pins: pcie0-pins {
+		mux {
+			function = "pcie";
+			groups = "pcie0_pad_perst",
+				 "pcie0_1_waken",
+				 "pcie0_1_clkreq";
+		};
+	};
+
+	pcie1_pins: pcie1-pins {
+		mux {
+			function = "pcie";
+			groups = "pcie1_pad_perst",
+				 "pcie1_0_waken",
+				 "pcie1_0_clkreq";
+		};
+	};
+
+	pmic_bus_pins: pmic-bus-pins {
+		mux {
+			function = "pmic";
+			groups = "pmic_bus";
+		};
+	};
+
+	pwm7_pins: pwm1-2-pins {
+		mux {
+			function = "pwm";
+			groups = "pwm_ch7_2";
+		};
+	};
+
+	wled_pins: wled-pins {
+		mux {
+			function = "led";
+			groups = "wled";
+		};
+	};
+
+	sd0_pins_default: sd0-pins-default {
+		mux {
+			function = "sd";
+			groups = "sd_0";
+		};
+
+		/* "I2S2_OUT, "I2S4_IN"", "I2S3_IN", "I2S2_IN",
+		 *  "I2S4_OUT", "I2S3_OUT" are used as DAT0, DAT1,
+		 *  DAT2, DAT3, CMD, CLK for SD respectively.
+		 */
+		conf-cmd-data {
+			pins = "I2S2_OUT", "I2S4_IN", "I2S3_IN",
+			       "I2S2_IN","I2S4_OUT";
+			input-enable;
+			drive-strength = <8>;
+			bias-pull-up;
+		};
+		conf-clk {
+			pins = "I2S3_OUT";
+			drive-strength = <12>;
+			bias-pull-down;
+		};
+		conf-cd {
+			pins = "TXD3";
+			bias-pull-up;
+		};
+	};
+
+	sd0_pins_uhs: sd0-pins-uhs {
+		mux {
+			function = "sd";
+			groups = "sd_0";
+		};
+
+		conf-cmd-data {
+			pins = "I2S2_OUT", "I2S4_IN", "I2S3_IN",
+			       "I2S2_IN","I2S4_OUT";
+			input-enable;
+			bias-pull-up;
+		};
+
+		conf-clk {
+			pins = "I2S3_OUT";
+			bias-pull-down;
+		};
+	};
+
+	/* Serial NAND is shared pin with SPI-NOR */
+	serial_nand_pins: serial-nand-pins {
+		mux {
+			function = "flash";
+			groups = "snfi";
+		};
+	};
+
+	spic0_pins: spic0-pins {
+		mux {
+			function = "spi";
+			groups = "spic0_0";
+		};
+	};
+
+	spic1_pins: spic1-pins {
+		mux {
+			function = "spi";
+			groups = "spic1_0";
+		};
+	};
+
+	/* SPI-NOR is shared pin with serial NAND */
+	spi_nor_pins: spi-nor-pins {
+		mux {
+			function = "flash";
+			groups = "spi_nor";
+		};
+	};
+
+	/* serial NAND is shared pin with SPI-NOR */
+	serial_nand_pins: serial-nand-pins {
+		mux {
+			function = "flash";
+			groups = "snfi";
+		};
+	};
+
+	uart0_pins: uart0-pins {
+		mux {
+			function = "uart";
+			groups = "uart0_0_tx_rx" ;
+		};
+	};
+
+	uart2_pins: uart2-pins {
+		mux {
+			function = "uart";
+			groups = "uart2_1_tx_rx" ;
+		};
+	};
+
+	watchdog_pins: watchdog-pins {
+		mux {
+			function = "watchdog";
+			groups = "watchdog";
+		};
+	};
+};
+
+&bch {
+	status = "okay";
+};
+
+&btif {
+	status = "disabled";
+};
+
+&cir {
+	pinctrl-names = "default";
+	pinctrl-0 = <&irrx_pins>;
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&eth_pins>;
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "sgmii";
+		fixed-link {
+			speed = <1000>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "rgmii";
+		fixed-link {
+			speed = <1000>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	status = "okay";
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins>;
+	status = "okay";
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm7_pins>;
+	status = "okay";
+};
+
+&pwrap {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pmic_bus_pins>;
+
+	status = "okay";
+};
+
+&snfi {
+	pinctrl-names = "default";
+	pinctrl-0 = <&serial_nand_pins>;
+	status = "okay";
+
+	spi_nand@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		spi-max-frequency = <104000000>;
+		reg = <0>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "Preloader";
+				reg = <0x00000 0x0080000>;
+				read-only;
+			};
+
+			partition@80000 {
+				label = "ATF";
+				reg = <0x80000 0x0040000>;
+				read-only;
+			};
+
+			partition@c0000 {
+				label = "uboot";
+				reg = <0xc0000 0x0080000>;
+				read-only;
+			};
+
+			partition@140000 {
+				label = "uboot-env";
+				reg = <0x140000 0x0080000>;
+				read-only;
+			};
+
+			factory: partition@1c0000 {
+				label = "factory";
+				reg = <0x1c0000 0x0040000>;
+				read-only;
+			};
+
+			partition@200000 {
+				label = "firmware";
+				reg = <0x200000 0x2000000>;
+			};
+
+			partition@2200000 {
+				label = "reserved";
+				reg = <0x2200000 0x4000000>;
+			};
+		};
+	};
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic0_pins>;
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic1_pins>;
+	status = "okay";
+};
+
+&ssusb {
+	vusb33-supply = <&reg_3p3v>;
+	vbus-supply = <&reg_usb_vbus>;
+	status = "okay";
+};
+
+&u3phy {
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	pinctrl-names = "default";
+	pinctrl-0 = <&watchdog_pins>;
+	status = "okay";
+};
+
+&wmac {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7622-rfb1-ubi.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7622-rfb1-ubi.dts
new file mode 100644
index 0000000..bf59b83
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7622-rfb1-ubi.dts
@@ -0,0 +1,618 @@
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ *
+ * SPDX-License-Identifier: (GPL-2.0-only OR MIT)
+ */
+
+/dts-v1/;
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
+
+#include "mt7622.dtsi"
+#include "mt6380.dtsi"
+
+/ {
+	model = "MT7622_MT7531 RFB";
+	compatible = "mediatek,mt7622,ubi";
+
+	aliases {
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+		bootargs = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n1 swiotlb=512";
+	};
+
+	cpus {
+		cpu@0 {
+			proc-supply = <&mt6380_vcpu_reg>;
+			sram-supply = <&mt6380_vm_reg>;
+		};
+
+		cpu@1 {
+			proc-supply = <&mt6380_vcpu_reg>;
+			sram-supply = <&mt6380_vm_reg>;
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		factory {
+			label = "factory";
+			linux,code = <BTN_0>;
+			gpios = <&pio 0 GPIO_ACTIVE_HIGH>;
+		};
+
+		wps {
+			label = "wps";
+			linux,code = <KEY_WPS_BUTTON>;
+			gpios = <&pio 102 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	gsw: gsw@0 {
+		compatible = "mediatek,mt753x";
+		mediatek,ethsys = <&ethsys>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		green {
+			label = "bpi-r64:pio:green";
+			gpios = <&pio 89 GPIO_ACTIVE_HIGH>;
+		};
+
+		red {
+			label = "bpi-r64:pio:red";
+			gpios = <&pio 88 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x40000000>;
+	};
+
+	reg_1p8v: regulator-1p8v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-1.8V";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-always-on;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	reg_5v: regulator-5v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-5V";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&btif {
+	status = "okay";
+};
+
+&cir {
+	pinctrl-names = "default";
+	pinctrl-0 = <&irrx_pins>;
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "rgmii";
+
+		fixed-link {
+			speed = <1000>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+};
+
+&gsw {
+	mediatek,mdio = <&mdio>;
+	mediatek,portmap = "llllw";
+	mediatek,mdio_master_pinmux = <0>;
+	reset-gpios = <&pio 54 0>;
+	interrupt-parent = <&pio>;
+	interrupts = <53 IRQ_TYPE_LEVEL_HIGH>;
+	status = "okay";
+
+	port5: port@5 {
+		compatible = "mediatek,mt753x-port";
+		reg = <5>;
+		phy-mode = "rgmii";
+		fixed-link {
+			speed = <1000>;
+			full-duplex;
+		};
+	};
+
+	port6: port@6 {
+		compatible = "mediatek,mt753x-port";
+		reg = <6>;
+		phy-mode = "sgmii";
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+		};
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	status = "okay";
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins>;
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&emmc_pins_default>;
+	pinctrl-1 = <&emmc_pins_uhs>;
+	status = "okay";
+	bus-width = <8>;
+	max-frequency = <50000000>;
+	cap-mmc-highspeed;
+	mmc-hs200-1_8v;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_1p8v>;
+	assigned-clocks = <&topckgen CLK_TOP_MSDC30_0_SEL>;
+	assigned-clock-parents = <&topckgen CLK_TOP_UNIV48M>;
+	non-removable;
+};
+
+&mmc1 {
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&sd0_pins_default>;
+	pinctrl-1 = <&sd0_pins_uhs>;
+	status = "okay";
+	bus-width = <4>;
+	max-frequency = <50000000>;
+	cap-sd-highspeed;
+	r_smpl = <1>;
+	cd-gpios = <&pio 81 GPIO_ACTIVE_LOW>;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_3p3v>;
+	assigned-clocks = <&topckgen CLK_TOP_MSDC30_1_SEL>;
+	assigned-clock-parents = <&topckgen CLK_TOP_UNIV48M>;
+};
+
+&nandc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&parallel_nand_pins>;
+	status = "disabled";
+};
+
+&nor_flash {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_nor_pins>;
+	status = "disabled";
+
+	flash@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+	};
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&pcie1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie1_pins>;
+	status = "okay";
+};
+
+&pio {
+	/* Attention: GPIO 90 is used to switch between PCIe@1,0 and
+	 * SATA functions. i.e. output-high: PCIe, output-low: SATA
+	 */
+	asm_sel {
+		gpio-hog;
+		gpios = <90 GPIO_ACTIVE_HIGH>;
+		output-high;
+	};
+
+	/* eMMC is shared pin with parallel NAND */
+	emmc_pins_default: emmc-pins-default {
+		mux {
+			function = "emmc", "emmc_rst";
+			groups = "emmc";
+		};
+
+		/* "NDL0","NDL1","NDL2","NDL3","NDL4","NDL5","NDL6","NDL7",
+		 * "NRB","NCLE" pins are used as DAT0,DAT1,DAT2,DAT3,DAT4,
+		 * DAT5,DAT6,DAT7,CMD,CLK for eMMC respectively
+		 */
+		conf-cmd-dat {
+			pins = "NDL0", "NDL1", "NDL2",
+			       "NDL3", "NDL4", "NDL5",
+			       "NDL6", "NDL7", "NRB";
+			input-enable;
+			bias-pull-up;
+		};
+
+		conf-clk {
+			pins = "NCLE";
+			bias-pull-down;
+		};
+	};
+
+	emmc_pins_uhs: emmc-pins-uhs {
+		mux {
+			function = "emmc";
+			groups = "emmc";
+		};
+
+		conf-cmd-dat {
+			pins = "NDL0", "NDL1", "NDL2",
+			       "NDL3", "NDL4", "NDL5",
+			       "NDL6", "NDL7", "NRB";
+			input-enable;
+			drive-strength = <4>;
+			bias-pull-up;
+		};
+
+		conf-clk {
+			pins = "NCLE";
+			drive-strength = <4>;
+			bias-pull-down;
+		};
+	};
+
+	eth_pins: eth-pins {
+		mux {
+			function = "eth";
+			groups = "mdc_mdio", "rgmii_via_gmac2";
+		};
+	};
+
+	i2c1_pins: i2c1-pins {
+		mux {
+			function = "i2c";
+			groups =  "i2c1_0";
+		};
+	};
+
+	i2c2_pins: i2c2-pins {
+		mux {
+			function = "i2c";
+			groups =  "i2c2_0";
+		};
+	};
+
+	i2s1_pins: i2s1-pins {
+		mux {
+			function = "i2s";
+			groups =  "i2s_out_mclk_bclk_ws",
+				  "i2s1_in_data",
+				  "i2s1_out_data";
+		};
+
+		conf {
+			pins = "I2S1_IN", "I2S1_OUT", "I2S_BCLK",
+			       "I2S_WS", "I2S_MCLK";
+			drive-strength = <12>;
+			bias-pull-down;
+		};
+	};
+
+	irrx_pins: irrx-pins {
+		mux {
+			function = "ir";
+			groups =  "ir_1_rx";
+		};
+	};
+
+	irtx_pins: irtx-pins {
+		mux {
+			function = "ir";
+			groups =  "ir_1_tx";
+		};
+	};
+
+	/* Parallel nand is shared pin with eMMC */
+	parallel_nand_pins: parallel-nand-pins {
+		mux {
+			function = "flash";
+			groups = "par_nand";
+		};
+	};
+
+	pcie0_pins: pcie0-pins {
+		mux {
+			function = "pcie";
+			groups = "pcie0_pad_perst",
+				 "pcie0_1_waken",
+				 "pcie0_1_clkreq";
+		};
+	};
+
+	pcie1_pins: pcie1-pins {
+		mux {
+			function = "pcie";
+			groups = "pcie1_pad_perst",
+				 "pcie1_0_waken",
+				 "pcie1_0_clkreq";
+		};
+	};
+
+	pmic_bus_pins: pmic-bus-pins {
+		mux {
+			function = "pmic";
+			groups = "pmic_bus";
+		};
+	};
+
+	pwm7_pins: pwm1-2-pins {
+		mux {
+			function = "pwm";
+			groups = "pwm_ch7_2";
+		};
+	};
+
+	wled_pins: wled-pins {
+		mux {
+			function = "led";
+			groups = "wled";
+		};
+	};
+
+	sd0_pins_default: sd0-pins-default {
+		mux {
+			function = "sd";
+			groups = "sd_0";
+		};
+
+		/* "I2S2_OUT, "I2S4_IN"", "I2S3_IN", "I2S2_IN",
+		 *  "I2S4_OUT", "I2S3_OUT" are used as DAT0, DAT1,
+		 *  DAT2, DAT3, CMD, CLK for SD respectively.
+		 */
+		conf-cmd-data {
+			pins = "I2S2_OUT", "I2S4_IN", "I2S3_IN",
+			       "I2S2_IN","I2S4_OUT";
+			input-enable;
+			drive-strength = <8>;
+			bias-pull-up;
+		};
+		conf-clk {
+			pins = "I2S3_OUT";
+			drive-strength = <12>;
+			bias-pull-down;
+		};
+		conf-cd {
+			pins = "TXD3";
+			bias-pull-up;
+		};
+	};
+
+	sd0_pins_uhs: sd0-pins-uhs {
+		mux {
+			function = "sd";
+			groups = "sd_0";
+		};
+
+		conf-cmd-data {
+			pins = "I2S2_OUT", "I2S4_IN", "I2S3_IN",
+			       "I2S2_IN","I2S4_OUT";
+			input-enable;
+			bias-pull-up;
+		};
+
+		conf-clk {
+			pins = "I2S3_OUT";
+			bias-pull-down;
+		};
+	};
+
+	/* Serial NAND is shared pin with SPI-NOR */
+	serial_nand_pins: serial-nand-pins {
+		mux {
+			function = "flash";
+			groups = "snfi";
+		};
+	};
+
+	spic0_pins: spic0-pins {
+		mux {
+			function = "spi";
+			groups = "spic0_0";
+		};
+	};
+
+	spic1_pins: spic1-pins {
+		mux {
+			function = "spi";
+			groups = "spic1_0";
+		};
+	};
+
+	/* SPI-NOR is shared pin with serial NAND */
+	spi_nor_pins: spi-nor-pins {
+		mux {
+			function = "flash";
+			groups = "spi_nor";
+		};
+	};
+
+	/* serial NAND is shared pin with SPI-NOR */
+	serial_nand_pins: serial-nand-pins {
+		mux {
+			function = "flash";
+			groups = "snfi";
+		};
+	};
+
+	uart0_pins: uart0-pins {
+		mux {
+			function = "uart";
+			groups = "uart0_0_tx_rx" ;
+		};
+	};
+
+	uart2_pins: uart2-pins {
+		mux {
+			function = "uart";
+			groups = "uart2_1_tx_rx" ;
+		};
+	};
+
+	watchdog_pins: watchdog-pins {
+		mux {
+			function = "watchdog";
+			groups = "watchdog";
+		};
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm7_pins>;
+	status = "okay";
+};
+
+&pwrap {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pmic_bus_pins>;
+
+	status = "okay";
+};
+
+&sata {
+	status = "disable";
+};
+
+&sata_phy {
+	status = "disable";
+};
+
+&snand {
+	pinctrl-names = "default";
+	pinctrl-0 = <&serial_nand_pins>;
+	status = "okay";
+	mediatek,quad-spi;
+
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		partition@0 {
+			label = "BL2";
+			reg = <0x00000 0x0080000>;
+			read-only;
+		};
+
+		partition@80000 {
+			label = "FIP";
+			reg = <0x80000 0x0200000>;
+		};
+
+		partition@280000 {
+			label = "Config";
+			reg = <0x280000 0x0080000>;
+		};
+
+		factory: partition@300000 {
+			label = "Factory";
+			reg = <0x300000 0x0100000>;
+		};
+
+		partition@400000 {
+			label = "ubi";
+			reg = <0x400000 0x2400000>;
+		};
+	};
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic0_pins>;
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic1_pins>;
+	status = "okay";
+};
+
+&ssusb {
+	vusb33-supply = <&reg_3p3v>;
+	vbus-supply = <&reg_5v>;
+	status = "okay";
+};
+
+&u3phy {
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	pinctrl-names = "default";
+	pinctrl-0 = <&watchdog_pins>;
+	status = "okay";
+};
+
+&wmac {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7622-ubnt-unifi-6-lr.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7622-ubnt-unifi-6-lr.dts
new file mode 100644
index 0000000..1f410b1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7622-ubnt-unifi-6-lr.dts
@@ -0,0 +1,327 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+
+/dts-v1/;
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
+
+#include "mt7622.dtsi"
+#include "mt6380.dtsi"
+
+/ {
+	model = "Ubiquiti UniFi 6 LR";
+	compatible = "ubnt,unifi-6-lr", "mediatek,mt7622";
+
+	aliases {
+		led-boot = &led_blue;
+		led-failsafe = &led_blue;
+		led-running = &led_blue;
+		led-upgrade = &led_blue;
+		label-mac-device = &gmac0;
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+		bootargs = "earlycon=uart8250,mmio32,0x11002000 swiotlb=512 console=ttyS0,115200n8";
+	};
+
+	cpus {
+		cpu@0 {
+			proc-supply = <&mt6380_vcpu_reg>;
+			sram-supply = <&mt6380_vm_reg>;
+		};
+
+		cpu@1 {
+			proc-supply = <&mt6380_vcpu_reg>;
+			sram-supply = <&mt6380_vm_reg>;
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		reset {
+			label = "reset";
+			linux,code = <KEY_RESTART>;
+			gpios = <&pio 62 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x3f000000>;
+	};
+
+	reg_1p8v: regulator-1p8v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-1.8V";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-always-on;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&slot0 {
+	wifi@0,0 {
+		reg = <0x0 0 0 0 0>;
+		mediatek,mtd-eeprom = <&factory 0x20000>;
+		mtd-mac-address = <&eeprom 0x6>;
+		ieee80211-freq-limit = <5000000 6000000>;
+	};
+};
+
+&pio {
+	eth_pins: eth-pins {
+		mux {
+			function = "eth";
+			groups = "mdc_mdio", "rgmii_via_gmac2";
+		};
+	};
+
+	pcie0_pins: pcie0-pins {
+		mux {
+			function = "pcie";
+			groups = "pcie0_pad_perst",
+				 "pcie0_1_waken",
+				 "pcie0_1_clkreq";
+		};
+	};
+
+	pcie1_pins: pcie1-pins {
+		mux {
+			function = "pcie";
+			groups = "pcie1_pad_perst",
+				 "pcie1_0_waken",
+				 "pcie1_0_clkreq";
+		};
+	};
+
+	pmic_bus_pins: pmic-bus-pins {
+		mux {
+			function = "pmic";
+			groups = "pmic_bus";
+		};
+	};
+
+	spi_nor_pins: spi-nor-pins {
+		mux {
+			function = "flash";
+			groups = "spi_nor";
+		};
+	};
+
+	uart0_pins: uart0-pins {
+		mux {
+			function = "uart";
+			groups = "uart0_0_tx_rx" ;
+		};
+	};
+
+	uart3_pins: uart3-pins {
+		mux {
+			function = "uart";
+			groups = "uart3_1_tx_rx" ;
+		};
+	};
+
+	i2c0_pins: i2c0-pins {
+		mux {
+			function = "i2c";
+			groups =  "i2c0";
+		};
+	};
+
+	watchdog_pins: watchdog-pins {
+		mux {
+			function = "watchdog";
+			groups = "watchdog";
+		};
+	};
+};
+
+&bch {
+	status = "okay";
+};
+
+&btif {
+	status = "disabled";
+};
+
+&eth {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&eth_pins>;
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+
+		phy-mode = "2500base-x";
+		mtd-mac-address = <&eeprom 0x0>;
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethernet-phy@8 {
+			/* Marvell AQRate AQR112W - no driver */
+			compatible = "ethernet-phy-ieee802.3-c45";
+			reg = <0x8>;
+		};
+	};
+};
+
+&pwrap {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pmic_bus_pins>;
+
+	status = "okay";
+};
+
+&nor_flash {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_nor_pins>;
+
+	status = "okay";
+
+	flash@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <50000000>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "preloader";
+				reg = <0x0 0x40000>;
+				read-only;
+			};
+
+			partition@40000 {
+				label = "atf";
+				reg = <0x40000 0x20000>;
+				read-only;
+			};
+
+			partition@60000 {
+				label = "u-boot";
+				reg = <0x60000 0x60000>;
+				read-only;
+			};
+
+			partition@c0000 {
+				label = "u-boot-env";
+				reg = <0xc0000 0x10000>;
+			};
+
+			factory: partition@d0000 {
+				label = "factory";
+				reg = <0xd0000 0x40000>;
+				read-only;
+			};
+
+			eeprom: partition@110000 {
+				label = "eeprom";
+				reg = <0x110000 0x10000>;
+				read-only;
+			};
+
+			partition@120000 {
+				label = "bs";
+				reg = <0x120000 0x10000>;
+			};
+
+			partition@130000 {
+				label = "cfg";
+				reg = <0x130000 0x100000>;
+				read-only;
+			};
+
+			partition@230000 {
+				compatible = "denx,fit";
+				label = "firmware";
+				reg = <0x230000 0x1ee0000>;
+			};
+
+			partition@2110000 {
+				label = "kernel1";
+				reg = <0x2110000 0x1ee0000>;
+			};
+		};
+	};
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins>;
+	status = "okay";
+};
+
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart3_pins>;
+	status = "okay";
+
+	/* MT7915 Bluetooth */
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins>;
+	status = "okay";
+
+	led-controller@30 {
+		compatible = "ubnt,ledbar";
+		reg = <0x30>;
+
+		enable-gpio = <&pio 59 0>;
+
+		red {
+			label = "red";
+		};
+
+		green {
+			label = "green";
+		};
+
+		led_blue: blue {
+			label = "blue";
+		};
+	};
+};
+
+&watchdog {
+	pinctrl-names = "default";
+	pinctrl-0 = <&watchdog_pins>;
+	status = "okay";
+};
+
+&wmac {
+	mediatek,mtd-eeprom = <&factory 0x0>;
+	mtd-mac-address = <&eeprom 0x0>;
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-clkitg.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-clkitg.dtsi
new file mode 100644
index 0000000..0d6d91d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-clkitg.dtsi
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Wenzhen.Yu <Wenzhen.Yu@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&clkitg {
+	bring-up {
+		compatible = "mediatek,clk-bring-up";
+		clocks =
+			<&apmixedsys CK_APMIXED_ARMPLL>,
+			<&apmixedsys  CK_APMIXED_NET2PLL>,
+			<&apmixedsys  CK_APMIXED_MMPLL>,
+			<&apmixedsys  CK_APMIXED_SGMPLL>,
+			<&apmixedsys  CK_APMIXED_WEDMCUPLL>,
+			<&apmixedsys  CK_APMIXED_NET1PLL>,
+			<&apmixedsys  CK_APMIXED_MPLL>,
+			<&apmixedsys  CK_APMIXED_APLL2>,
+			<&infracfg CK_INFRA_CK_F26M>,
+			<&clk40m>,
+			<&infracfg CK_INFRA_ISPI0>,
+			<&infracfg CK_INFRA_I2C>,
+			<&infracfg CK_INFRA_ISPI1>,
+			<&clk40m>,
+			<&infracfg CK_INFRA_66M_MCK>,
+			<&infracfg CK_INFRA_CK_F32K>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&infracfg CK_INFRA_133M_HCK>,
+			<&infracfg CK_INFRA_66M_PHCK>,
+			<&infracfg CK_INFRA_FAUD_L_CK	>,
+			<&infracfg CK_INFRA_FAUD_AUD_CK>,
+			<&infracfg CK_INFRA_FAUD_EG2_CK>,
+			<&infracfg CK_INFRA_I2CS_CK>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&infracfg CK_INFRA_MUX_SPI0>,
+			<&infracfg CK_INFRA_MUX_SPI1>,
+			<&infracfg CK_INFRA_RTC_32K>,
+			<&infracfg CK_INFRA_FMSDC_CK>,
+			<&infracfg CK_INFRA_FMSDC_HCK_CK>,
+			<&infracfg CK_INFRA_PERI_133M>,
+			<&infracfg CK_INFRA_133M_PHCK>,
+			<&infracfg CK_INFRA_USB_SYS_CK>,
+			<&infracfg CK_INFRA_USB_CK>,
+			<&infracfg CK_INFRA_USB_XHCI_CK>,
+			<&clk40m>,
+			<&infracfg CK_INFRA_F26M_CK0>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&infracfg_ao CK_INFRA_GPT_STA>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&infracfg_ao CK_INFRA_CQ_DMA_CK>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&infracfg_ao CK_INFRA_DRAMC_26M_CK>,
+			<&clk40m>,
+			<&infracfg_ao CK_INFRA_AP_DMA_CK>,
+			<&infracfg_ao CK_INFRA_SEJ_CK>,
+			<&infracfg_ao CK_INFRA_SEJ_13M_CK>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&infracfg_ao CK_INFRA_FRTC_CK>,
+			<&infracfg_ao CK_INFRA_MSDC_CK>,
+			<&infracfg_ao CK_INFRA_MSDC_HCK_CK>,
+			<&infracfg_ao CK_INFRA_MSDC_133M_CK>,
+			<&infracfg_ao CK_INFRA_MSDC_66M_CK>,
+			<&clk40m>,
+			<&clk40m>,
+			<&infracfg_ao CK_INFRA_FBIST2FPC_CK>,
+			<&infracfg_ao CK_INFRA_I2C_MCK_CK>,
+			<&infracfg_ao CK_INFRA_I2C_PCK_CK>,
+			<&infracfg_ao CK_INFRA_IUSB_133_CK>,
+			<&infracfg_ao CK_INFRA_IUSB_66M_CK>,
+			<&infracfg_ao CK_INFRA_IUSB_SYS_CK>,
+			<&infracfg_ao CK_INFRA_IUSB_CK>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&topckgen CK_TOP_CB_M_416M>,
+			<&clk40m>,
+			<&topckgen CK_TOP_CB_M_D4>,
+			<&topckgen CK_TOP_CB_M_D8>,
+			<&topckgen CK_TOP_M_D8_D2>,
+			<&topckgen CK_TOP_M_D3_D2>,
+			<&topckgen CK_TOP_CB_MM_D2>,
+			<&topckgen CK_TOP_CB_MM_D4>,
+			<&topckgen CK_TOP_CB_MM_D8>,
+			<&topckgen CK_TOP_CB_APLL2_196M>,
+			<&topckgen CK_TOP_APLL2_D4>,
+			<&topckgen CK_TOP_CB_NET1_D4>,
+			<&topckgen CK_TOP_CB_NET1_D5>,
+			<&topckgen CK_TOP_NET1_D5_D2>,
+			<&topckgen CK_TOP_NET1_D5_D4>,
+			<&topckgen CK_TOP_NET1_D8_D2>,
+			<&topckgen CK_TOP_NET1_D8_D4>,
+			<&clk40m>,
+			<&topckgen CK_TOP_CB_NET2_D4>,
+			<&topckgen CK_TOP_NET2_D4_D2>,
+			<&topckgen CK_TOP_CB_WEDMCU_208M>,
+			<&clk40m>,
+			<&topckgen CK_TOP_CB_RTC_32K>,
+			<&topckgen CK_TOP_CB_RTC_32P7K>,
+			<&clk40m>,
+			<&topckgen CK_TOP_USB_EQ_RX250M>,
+			<&topckgen CK_TOP_USB_TX250M>,
+			<&topckgen CK_TOP_USB_LN0_CK>,
+			<&topckgen CK_TOP_USB_CDR_CK>,
+			<&clk40m>,
+			<&topckgen CK_TOP_I2C_BCK>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&topckgen CK_TOP_F26M_SEL>,
+			<&topckgen CK_TOP_SYSAXI>,
+			<&topckgen CK_TOP_NETSYS_WED_MCU>,
+			<&topckgen CK_TOP_NETSYS_2X>,
+			<&topckgen CK_TOP_SGM_325M>,
+			<&topckgen CK_TOP_A1SYS>,
+			<&topckgen CK_TOP_F26M>,
+			<&topckgen CK_TOP_AUD_L>,
+			<&topckgen CK_TOP_A_TUNER>,
+			<&topckgen CK_TOP_U2U3_REF>,
+			<&topckgen CK_TOP_U2U3_SYS>,
+			<&topckgen CK_TOP_U2U3_XHCI>,
+			<&topckgen CK_TOP_AP2CNN_HOST>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&topckgen CK_TOP_I2C_SEL>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&topckgen CK_TOP_F26M_SEL>,
+			<&topckgen CK_TOP_DRAMC_SEL>,
+			<&topckgen CK_TOP_DRAMC_MD32_SEL>,
+			<&topckgen CK_TOP_SYSAXI_SEL>,
+			<&topckgen CK_TOP_SYSAPB_SEL>,
+			<&topckgen CK_TOP_ARM_DB_MAIN_SEL>,
+			<&topckgen CK_TOP_AP2CNN_HOST_SEL>,
+			<&topckgen CK_TOP_NETSYS_SEL>,
+			<&topckgen CK_TOP_NETSYS_500M_SEL>,
+			<&topckgen CK_TOP_NETSYS_MCU_SEL>,
+			<&clk40m>,
+			<&clk40m>,
+			<&topckgen CK_TOP_SGM_REG_SEL>,
+			<&topckgen CK_TOP_NETSYS_500M_SEL>,
+			<&clk40m>,
+			<&topckgen CK_TOP_USB3_PHY_SEL>,
+			<&topckgen CK_TOP_F26M_SEL>,
+			<&topckgen CK_TOP_U2U3_SEL>,
+			<&topckgen CK_TOP_U2U3_SYS_SEL>,
+			<&topckgen CK_TOP_U2U3_XHCI_SEL>,
+			<&topckgen CK_TOP_USB_FRMCNT_SEL>;
+
+
+		clock-names = "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11",
+		"12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23",
+		"24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35",
+		"36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47",
+		"48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
+		"60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71",
+		"72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83",
+		"84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95",
+		"96", "97", "98", "99", "100", "101", "102", "103", "104", "105", "106", "107",
+		"108", "109", "110", "111", "112", "113", "114", "115", "116", "117",
+		"118", "119", "120", "121", "122", "123",
+		"124", "125", "126", "127", "128", "129", "130", "131", "132", "133", "134", "135",
+		"136", "137", "138", "139", "140", "141", "142", "143", "144", "145", "146", "147",
+		"148", "149", "150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
+		"160", "161", "162", "163", "164", "165", "166", "167", "168", "169", "170", "171",
+		"172", "173", "174", "175", "176", "177", "178", "179", "180", "181", "182", "183";
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-emmc-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-emmc-rfb.dts
new file mode 100644
index 0000000..bf2628e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-emmc-rfb.dts
@@ -0,0 +1,169 @@
+/dts-v1/;
+#include "mt7981.dtsi"
+/ {
+	model = "MediaTek MT7981 RFB";
+	compatible = "mediatek,mt7981-emmc-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000 \
+				root=PARTLABEL=rootfs rootfstype=squashfs,f2fs";
+	};
+
+	memory {
+		// fpga ddr2: 128MB*2
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&mmc0 {
+         pinctrl-names = "default", "state_uhs";
+         pinctrl-0 = <&mmc0_pins_default>;
+         pinctrl-1 = <&mmc0_pins_uhs>;
+         bus-width = <8>;
+         max-frequency = <52000000>;
+         cap-mmc-highspeed;
+         vmmc-supply = <&reg_3p3v>;
+         non-removable;
+         status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "gmii";
+		phy-handle = <&phy0>;
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy0: ethernet-phy@0 {
+			compatible = "ethernet-phy-id03a2.9461";
+			reg = <0>;
+			phy-mode = "gmii";
+			nvmem-cells = <&phy_calibration>;
+			nvmem-cell-names = "phy-cal-data";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 39 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan1";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan2";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan3";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan4";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&pio {
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+
+	mmc0_pins_default: mmc0-pins-default {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+	};
+
+	mmc0_pins_uhs: mmc0-pins-uhs {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+	};
+};
+
+&xhci {
+	mediatek,u3p-dis-msk = <0x0>;
+	phys = <&u2port0 PHY_TYPE_USB2>,
+	       <&u3port0 PHY_TYPE_USB3>;
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-fpga-emmc.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-fpga-emmc.dts
new file mode 100644
index 0000000..6c3a197
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-fpga-emmc.dts
@@ -0,0 +1,135 @@
+/dts-v1/;
+#include "mt7981-fpga.dtsi"
+/ {
+	model = "MediaTek MT7981 FPGA";
+	compatible = "mediatek,mt7981-fpga-emmc";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000 \
+				root=PARTLABEL=rootfs rootfstype=squashfs,f2fs";
+	};
+
+	memory {
+		// fpga ddr2: 128MB*2
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	wsys_adie: wsys_adie@0 {
+	// fpga cases need to manual change adie_id / sku_type for dvt only
+		compatible = "mediatek,rebb-mt7981-adie";
+		adie_id = <7976>;
+		sku_type = <3000>;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	/* pin shared with snfi */
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&pcie {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie_pins>;
+	status = "okay";
+};
+
+&pio {
+	pcie_pins: pcie-pins {
+		mux {
+			function = "pcie";
+			groups = "pcie_pereset", "pcie_clk", "pcie_wake";
+		};
+	};
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+
+	mmc0_pins_default: mmc0-pins-default {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+	};
+
+	mmc0_pins_uhs: mmc0-pins-uhs {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+	};
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&mmc0 {
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_pins_default>;
+	pinctrl-1 = <&mmc0_pins_uhs>;
+	bus-width = <8>;
+	max-frequency = <3000000>;
+	cap-mmc-highspeed;
+	vmmc-supply = <&reg_3p3v>;
+	non-removable;
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "rgmii";
+
+		fixed-link {
+			speed = <100>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "rgmii";
+
+		fixed-link {
+			speed = <100>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "eth0";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-fpga-sd.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-fpga-sd.dts
new file mode 100644
index 0000000..deca60b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-fpga-sd.dts
@@ -0,0 +1,135 @@
+/dts-v1/;
+#include "mt7981-fpga.dtsi"
+/ {
+	model = "MediaTek MT7981 FPGA";
+	compatible = "mediatek,mt7981-fpga-sd";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000 \
+				root=PARTLABEL=rootfs rootfstype=squashfs,f2fs";
+	};
+
+	memory {
+		// fpga ddr2: 128MB*2
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	wsys_adie: wsys_adie@0 {
+	// fpga cases need to manual change adie_id / sku_type for dvt only
+		compatible = "mediatek,rebb-mt7981-adie";
+		adie_id = <7976>;
+		sku_type = <3000>;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	/* pin shared with snfi */
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&pcie {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie_pins>;
+	status = "okay";
+};
+
+&pio {
+	pcie_pins: pcie-pins {
+		mux {
+			function = "pcie";
+			groups = "pcie_pereset", "pcie_clk", "pcie_wake";
+		};
+	};
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+
+	mmc0_pins_default: mmc0-pins-default {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+	};
+
+	mmc0_pins_uhs: mmc0-pins-uhs {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+	};
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&mmc0 {
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_pins_default>;
+	pinctrl-1 = <&mmc0_pins_uhs>;
+	bus-width = <4>;
+	max-frequency = <3000000>;
+	cap-sd-highspeed;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_3p3v>;
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "rgmii";
+
+		fixed-link {
+			speed = <100>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "rgmii";
+
+		fixed-link {
+			speed = <100>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "eth0";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-fpga-snfi-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-fpga-snfi-nand.dts
new file mode 100644
index 0000000..ef49a12
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-fpga-snfi-nand.dts
@@ -0,0 +1,157 @@
+/dts-v1/;
+#include "mt7981-fpga.dtsi"
+/ {
+	model = "MediaTek MT7981 FPGA";
+	compatible = "mediatek,mt7981-fpga-snfi-nand";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		// fpga ddr2: 128MB*2
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	nmbm_snfi {
+		compatible = "generic,nmbm";
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		lower-mtd-device = <&snand>;
+		forced-create;
+		empty-page-ecc-protected;
+
+		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>;
+			};
+
+			factory: partition@180000 {
+				label = "Factory";
+				reg = <0x180000 0x0200000>;
+			};
+
+			partition@380000 {
+				label = "FIP";
+				reg = <0x380000 0x0200000>;
+			};
+
+			partition@580000 {
+				label = "ubi";
+				reg = <0x580000 0x4000000>;
+			};
+		};
+	};
+
+	wsys_adie: wsys_adie@0 {
+	// fpga cases need to manual change adie_id / sku_type for dvt only
+		compatible = "mediatek,rebb-mt7981-adie";
+		adie_id = <7976>;
+		sku_type = <3000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	/* pin shared with snfi */
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&pcie {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie_pins>;
+	status = "okay";
+};
+
+&pio {
+	pcie_pins: pcie-pins {
+		mux {
+			function = "pcie";
+			groups = "pcie_pereset", "pcie_clk", "pcie_wake";
+		};
+	};
+
+	snfi_pins: snfi-pins {
+		mux {
+			function = "flash";
+			groups = "snfi";
+		};
+	};
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&snand {
+	pinctrl-names = "default";
+	/* pin shared with spic */
+	pinctrl-0 = <&snfi_pins>;
+	status = "okay";
+	mediatek,quad-spi;
+};
+
+&eth {
+        status = "okay";
+
+        gmac0: mac@0 {
+                compatible = "mediatek,eth-mac";
+                reg = <0>;
+                phy-mode = "rgmii";
+
+                fixed-link {
+                        speed = <100>;
+                        full-duplex;
+                        pause;
+                };
+        };
+	gmac1: mac@1 {
+                compatible = "mediatek,eth-mac";
+                reg = <1>;
+                phy-mode = "rgmii";
+
+                fixed-link {
+                        speed = <100>;
+                        full-duplex;
+                        pause;
+                };
+        };
+
+        mdio: mdio-bus {
+                #address-cells = <1>;
+                #size-cells = <0>;
+        };
+
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "eth0";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-fpga-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-fpga-spim-nand.dts
new file mode 100644
index 0000000..f56e778
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-fpga-spim-nand.dts
@@ -0,0 +1,161 @@
+/dts-v1/;
+#include "mt7981-fpga.dtsi"
+/ {
+	model = "MediaTek MT7981 FPGA";
+	compatible = "mediatek,mt7981-fpga-spim-nand";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		// fpga ddr2: 128MB*2
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	nmbm_spim_nand {
+		compatible = "generic,nmbm";
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		lower-mtd-device = <&spi_nand>;
+		forced-create;
+
+		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 0x0200000>;
+			};
+
+			partition@380000 {
+				label = "FIP";
+				reg = <0x380000 0x0200000>;
+			};
+
+			partition@580000 {
+				label = "ubi";
+				reg = <0x580000 0x4000000>;
+			};
+		};
+	};
+
+	wsys_adie: wsys_adie@0 {
+	// fpga cases need to manual change adie_id / sku_type for dvt only
+		compatible = "mediatek,rebb-mt7981-adie";
+		adie_id = <7976>;
+		sku_type = <3000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi0_flash_pins>;
+	status = "okay";
+	spi_nand: spi_nand@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		reg = <0>;
+		spi-max-frequency = <3000000>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	/* pin shared with snfi */
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&pcie {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie_pins>;
+	status = "okay";
+};
+
+&pio {
+	pcie_pins: pcie-pins {
+		mux {
+			function = "pcie";
+			groups = "pcie_pereset", "pcie_clk", "pcie_wake";
+		};
+	};
+
+	spi0_flash_pins: spi0-pins {
+		mux {
+			function = "spi";
+			groups = "spi0", "spi0_wp_hold";
+		};
+	};
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&eth {
+        status = "okay";
+
+        gmac0: mac@0 {
+                compatible = "mediatek,eth-mac";
+                reg = <0>;
+                phy-mode = "rgmii";
+
+                fixed-link {
+                        speed = <100>;
+                        full-duplex;
+                        pause;
+                };
+        };
+	gmac1: mac@1 {
+                compatible = "mediatek,eth-mac";
+                reg = <1>;
+                phy-mode = "rgmii";
+
+                fixed-link {
+                        speed = <100>;
+                        full-duplex;
+                        pause;
+                };
+        };
+
+        mdio: mdio-bus {
+                #address-cells = <1>;
+                #size-cells = <0>;
+        };
+
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "eth0";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-fpga-spim-nor.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-fpga-spim-nor.dts
new file mode 100644
index 0000000..ec0b4c9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-fpga-spim-nor.dts
@@ -0,0 +1,148 @@
+/dts-v1/;
+#include "mt7981-fpga.dtsi"
+/ {
+	model = "MediaTek MT7981 FPGA";
+	compatible = "mediatek,mt7981-fpga-nor";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		// fpga ddr2: 128MB*2
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+        wsys_adie: wsys_adie@0 {
+		// fpga cases need to manual change adie_id / sku_type for dvt only
+                compatible = "mediatek,rebb-mt7981-adie";
+                adie_id = <7976>;
+                sku_type = <3000>;
+        };
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	/* pin shared with snfi */
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&spi2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi2_flash_pins>;
+	status = "okay";
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <500000>;
+
+		partition@00000 {
+			label = "BL2";
+			reg = <0x00000 0x0040000>;
+		};
+		partition@40000 {
+			label = "u-boot-env";
+			reg = <0x40000 0x0010000>;
+		};
+		factory: partition@50000 {
+			label = "Factory";
+			reg = <0x50000 0x00B0000>;
+		};
+		partition@100000 {
+			label = "FIP";
+			reg = <0x100000 0x0080000>;
+		};
+		partition@180000 {
+			label = "firmware";
+			reg = <0x180000 0xE00000>;
+		};
+	};
+};
+
+&pcie {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie_pins>;
+	status = "okay";
+};
+
+&pio {
+	pcie_pins: pcie-pins {
+		mux {
+			function = "pcie";
+			groups = "pcie_pereset", "pcie_clk", "pcie_wake";
+		};
+	};
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+
+	spi2_flash_pins: spi2-pins {
+		mux {
+			function = "spi";
+			groups = "spi2", "spi2_wp_hold";
+		};
+	};
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&eth {
+        status = "okay";
+
+        gmac0: mac@0 {
+                compatible = "mediatek,eth-mac";
+                reg = <0>;
+                phy-mode = "rgmii";
+
+                fixed-link {
+                        speed = <100>;
+                        full-duplex;
+                        pause;
+                };
+        }; 
+	gmac1: mac@1 {
+                compatible = "mediatek,eth-mac";
+                reg = <1>;
+                phy-mode = "rgmii";
+
+                fixed-link {
+                        speed = <100>;
+                        full-duplex;
+                        pause;
+                };
+        };
+
+        mdio: mdio-bus {
+                #address-cells = <1>;
+                #size-cells = <0>;
+        };
+
+}; 
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "eth0";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&wed {
+	dy_txbm_enable = "true";
+	dy_txbm_budge = <8>;
+	txbm_init_sz = <10>;
+	status = "okay";
+};
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-fpga.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-fpga.dtsi
new file mode 100644
index 0000000..a803992
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-fpga.dtsi
@@ -0,0 +1,443 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Sam.Shih <sam.shih@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/phy/phy.h>
+#include <dt-bindings/reset/ti-syscon.h>
+/ {
+	compatible = "mediatek,mt7981-fpga";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			enable-method = "psci";
+			reg = <0x0>;
+		};
+
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			enable-method = "psci";
+			reg = <0x1>;
+		};
+	};
+
+	auxadc: adc@1100d000 {
+		compatible = "mediatek,mt7981-auxadc",
+			     "mediatek,mt7622-auxadc";
+		reg = <0 0x1100d000 0 0x1000>;
+		clocks = <&system_clk>;
+		clock-names = "main";
+		#io-channel-cells = <1>;
+	};
+
+	wed: wed@15010000 {
+		compatible = "mediatek,wed";
+		wed_num = <2>;
+		/* add this property for wed get the pci slot number. */
+		pci_slot_map = <0>, <1>;
+		reg = <0 0x15010000 0 0x1000>,
+		      <0 0x15011000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	wdma: wdma@15104800 {
+		compatible = "mediatek,wed-wdma";
+		reg = <0 0x15104800 0 0x400>,
+		      <0 0x15104c00 0 0x400>;
+	};
+
+	ap2woccif: ap2woccif@151A5000 {
+		compatible = "mediatek,ap2woccif";
+		reg = <0 0x151A5000 0 0x1000>,
+		      <0 0x151AD000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>;
+        };
+
+	wocpu0_ilm: wocpu0_ilm@151E0000 {
+		compatible = "mediatek,wocpu0_ilm";
+		reg = <0 0x151E0000 0 0x8000>;
+	};
+
+	wocpu_dlm: wocpu_dlm@151E8000 {
+		compatible = "mediatek,wocpu_dlm";
+		reg = <0 0x151E8000 0 0x2000>,
+		      <0 0x151F8000 0 0x2000>;
+
+		resets = <&ethsysrst 0>;
+		reset-names = "wocpu_rst";
+	};
+
+	cpu_boot: wocpu_boot@15194000 {
+		compatible = "mediatek,wocpu_boot";
+		reg = <0 0x15194000 0 0x1000>;
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		/* 192 KiB reserved for ARM Trusted Firmware (BL31) */
+		secmon_reserved: secmon@43000000 {
+			reg = <0 0x43000000 0 0x30000>;
+			no-map;
+		};
+
+		wmcpu_emi: wmcpu-reserved@47C80000 {
+			compatible = "mediatek,wmcpu-reserved";
+			no-map;
+			reg = <0 0x47C80000 0 0x00100000>;
+		};
+
+		wocpu0_emi: wocpu0_emi@47D80000 {
+			compatible = "mediatek,wocpu0_emi";
+			no-map;
+			reg = <0 0x47D80000 0 0x40000>;
+			shared = <0>;
+		};
+
+		wocpu_data: wocpu_data@47DC0000 {
+			compatible = "mediatek,wocpu_data";
+			no-map;
+			reg = <0 0x47DC0000 0 0x240000>;
+			shared = <1>;
+		};
+	};
+
+	psci {
+		compatible  = "arm,psci-0.2";
+		method      = "smc";
+	};
+
+	system_clk: dummy13m {
+		compatible = "fixed-clock";
+		clock-frequency = <13000000>;
+		#clock-cells = <0>;
+	};
+
+	rtc_clk: dummy32k {
+		compatible = "fixed-clock";
+		clock-frequency = <32000>;
+		#clock-cells = <0>;
+	};
+
+	uart_clk: dummy12m {
+		compatible = "fixed-clock";
+		clock-frequency = <12000000>;
+		#clock-cells = <0>;
+	};
+
+	gpt_clk: dummy6m {
+		compatible = "fixed-clock";
+		clock-frequency = <6000000>;
+		#clock-cells = <0>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupt-parent = <&gic>;
+		clock-frequency = <12000000>;
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+
+	};
+
+	watchdog: watchdog@1001c000 {
+		compatible = "mediatek,mt7622-wdt",
+			     "mediatek,mt6589-wdt";
+		reg = <0 0x1001c000 0 0x1000>;
+		interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+		#reset-cells = <1>;
+	};
+
+	gic: interrupt-controller@c000000 {
+		compatible = "arm,gic-v3";
+		#interrupt-cells = <3>;
+		interrupt-parent = <&gic>;
+		interrupt-controller;
+		reg = <0 0x0c000000 0 0x40000>,  /* GICD */
+		      <0 0x0c080000 0 0x200000>; /* GICR */
+
+		interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	uart0: serial@11002000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11002000 0 0x400>;
+		interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&uart_clk>;
+		status = "disabled";
+	};
+
+	uart1: serial@11003000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11003000 0 0x400>;
+		interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&uart_clk>;
+		status = "disabled";
+	};
+
+	uart2: serial@11004000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11004000 0 0x400>;
+		interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&uart_clk>;
+		status = "disabled";
+	};
+
+	pcie: pcie@11280000 {
+		compatible = "mediatek,mt7981-pcie",
+			     "mediatek,mt7986-pcie";
+		device_type = "pci";
+		reg = <0 0x11280000 0 0x4000>;
+		reg-names = "pcie-mac";
+		#address-cells = <3>;
+		#size-cells = <2>;
+		interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+		bus-range = <0x00 0xff>;
+		ranges = <0x82000000 0 0x20000000
+			  0x0 0x20000000 0 0x10000000>;
+		status = "disabled";
+
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 7>;
+		interrupt-map = <0 0 0 1 &pcie_intc 0>,
+				<0 0 0 2 &pcie_intc 1>,
+				<0 0 0 3 &pcie_intc 2>,
+				<0 0 0 4 &pcie_intc 3>;
+		pcie_intc: interrupt-controller {
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <1>;
+		};
+	};
+
+	pio: pinctrl@11d00000 {
+		compatible = "mediatek,mt7981-pinctrl";
+		reg = <0 0x11d00000 0 0x1000>,
+		      <0 0x11c00000 0 0x1000>,
+		      <0 0x11c10000 0 0x1000>,
+		      <0 0x11d20000 0 0x1000>,
+		      <0 0x11e00000 0 0x1000>,
+		      <0 0x11e20000 0 0x1000>,
+		      <0 0x11f00000 0 0x1000>,
+		      <0 0x11f10000 0 0x1000>,
+		      <0 0x1000b000 0 0x1000>;
+		reg-names = "gpio_base", "iocfg_rt_base", "iocfg_rm_base",
+			    "iocfg_rb_base", "iocfg_lb_base", "iocfg_bl_base",
+			    "iocfg_tm_base", "iocfg_tl_base", "eint";
+		gpio-controller;
+		#gpio-cells = <2>;
+		gpio-ranges = <&pio 0 0 56>;
+		interrupt-controller;
+		interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-parent = <&gic>;
+		#interrupt-cells = <2>;
+	};
+
+        ethsys: syscon@15000000 {
+                #address-cells = <1>;
+                #size-cells = <1>;
+                compatible = "mediatek,mt7986-ethsys",
+                             "syscon";
+                reg = <0 0x15000000 0 0x1000>;
+                #clock-cells = <1>;
+                #reset-cells = <1>;
+
+		ethsysrst: reset-controller {
+			compatible = "ti,syscon-reset";
+			#reset-cells = <1>;
+			ti,reset-bits = <0x34 4 0x34 4 0x34 4 (ASSERT_SET | DEASSERT_CLEAR | STATUS_SET)>;
+		};
+        };
+
+        eth: ethernet@15100000 {
+                compatible = "mediatek,mt7981-eth";
+                reg = <0 0x15100000 0 0x80000>;
+                interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
+                mediatek,ethsys = <&ethsys>;
+		mediatek,infracfg = <&ethsys>;
+                #reset-cells = <1>;
+                #address-cells = <1>;
+                #size-cells = <0>;
+                status = "disabled";
+        };
+
+	hnat: hnat@15000000 {
+		compatible = "mediatek,mtk-hnat_v4";
+		reg = <0 0x15100000 0 0x80000>;
+		resets = <&ethsys 0>;
+		reset-names = "mtketh";
+		status = "disabled";
+	};
+
+	snand: snfi@11005000 {
+		compatible = "mediatek,mt7986-snand";
+		reg = <0 0x11005000 0 0x1000>, <0 0x11006000 0 0x1000>;
+		reg-names = "nfi", "ecc";
+		interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>;
+		clock-names = "pad_clk", "nfi_clk", "nfi_hclk";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	mmc0: mmc@11230000 {
+                  compatible = "mediatek,mt7986-mmc";
+                  reg = <0 0x11230000 0 0x1000>, <0 0x11c20000 0 0x1000>;
+                  interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+                  clocks = <&system_clk>,
+                           <&system_clk>,
+                           <&system_clk>;
+                  clock-names = "source", "hclk", "source_cg";
+                  status = "disabled";
+        };
+
+	wed_pcie: wed_pcie@10003000 {
+		compatible = "mediatek,wed_pcie";
+		reg = <0 0x10003000 0 0x10>;
+	};
+
+	wbsys: wbsys@18000000 {
+		compatible = "mediatek,wbsys";
+		reg = <0 0x18000000 0  0x1000000>;
+		interrupts = <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 215 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>;
+		chip_id = <0x7981>;
+	};
+
+	spi0: spi@1100a000 {
+		compatible = "mediatek,ipm-spi-quad";
+		reg = <0 0x1100a000 0 0x100>;
+		interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&uart_clk>,
+			 <&uart_clk>,
+			 <&uart_clk>,
+			 <&uart_clk>;
+		clock-names = "parent-clk", "sel-clk", "spi-clk", "spi-hclk";
+		status = "disabled";
+	};
+
+	spi1: spi@1100b000 {
+		compatible = "mediatek,ipm-spi-single";
+		reg = <0 0x1100b000 0 0x100>;
+		interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&uart_clk>,
+			 <&uart_clk>,
+			 <&uart_clk>,
+			 <&uart_clk>;
+		clock-names = "parent-clk", "sel-clk", "spi-clk", "spi-hclk";
+		status = "disabled";
+	};
+
+	spi2: spi@11009000 {
+		compatible = "mediatek,ipm-spi-quad";
+		reg = <0 0x11009000 0 0x100>;
+		interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&uart_clk>,
+			 <&uart_clk>,
+			 <&uart_clk>,
+			 <&uart_clk>;
+		clock-names = "parent-clk", "sel-clk", "spi-clk", "spi-hclk";
+		status = "disabled";
+	};
+
+	consys: consys@10000000 {
+		compatible = "mediatek,mt7981-consys";
+		reg = <0 0x10000000 0 0x8600000>;
+		memory-region = <&wmcpu_emi>;
+	};
+
+	xhci: xhci@11200000 {
+		compatible = "mediatek,mt7981-xhci",
+			     "mediatek,mtk-xhci";
+		reg = <0 0x11200000 0 0x2e00>,
+		      <0 0x11203e00 0 0x0100>;
+		reg-names = "mac", "ippc";
+		interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&u2port0 PHY_TYPE_USB2>;
+		clocks = <&system_clk>,
+		         <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>;
+		clock-names = "sys_ck",
+			      "xhci_ck",
+			      "ref_ck",
+			      "mcu_ck",
+			      "dma_ck";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		mediatek,u3p-dis-msk=<0x01>;
+		status = "okay";
+	};
+
+	usbtphy: usb-phy@11203e00 {
+		compatible = "mediatek,a60810-u2phy",
+			     "mediatek,a60931-u3phy",
+			     "mediatek,a60xxx-usbphy";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+		status = "okay";
+
+		u2port0: usb-phy@11203ed0 {
+			reg = <0 0x11203ed0 0 0x008>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			status = "okay";
+		};
+
+		u3port0: usb-phy@11203ed8 {
+			reg = <0 0x11203ed8 0 0x008>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			status = "disabled";
+		};
+
+		u2port1: usb-phy@11203ee0 {
+			reg = <0 0x11203ee0 0 0x008>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			status = "disabled";
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-sd-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-sd-rfb.dts
new file mode 100644
index 0000000..7d0c097
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-sd-rfb.dts
@@ -0,0 +1,169 @@
+/dts-v1/;
+#include "mt7981.dtsi"
+/ {
+	model = "MediaTek MT7981 RFB";
+	compatible = "mediatek,mt7981-sd-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000 \
+				root=PARTLABEL=rootfs rootfstype=squashfs,f2fs";
+	};
+
+	memory {
+		// fpga ddr2: 128MB*2
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&mmc0 {
+         pinctrl-names = "default", "state_uhs";
+         pinctrl-0 = <&mmc0_pins_default>;
+         pinctrl-1 = <&mmc0_pins_uhs>;
+         bus-width = <4>;
+         max-frequency = <52000000>;
+         cap-sd-highspeed;
+         vmmc-supply = <&reg_3p3v>;
+         vqmmc-supply = <&reg_3p3v>;
+         status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "gmii";
+		phy-handle = <&phy0>;
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy0: ethernet-phy@0 {
+			compatible = "ethernet-phy-id03a2.9461";
+			reg = <0>;
+			phy-mode = "gmii";
+			nvmem-cells = <&phy_calibration>;
+			nvmem-cell-names = "phy-cal-data";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 39 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan1";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan2";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan3";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan4";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&pio {
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+
+	mmc0_pins_default: mmc0-pins-default {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+	};
+
+	mmc0_pins_uhs: mmc0-pins-uhs {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+	};
+};
+
+&xhci {
+	mediatek,u3p-dis-msk = <0x0>;
+	phys = <&u2port0 PHY_TYPE_USB2>,
+	       <&u3port0 PHY_TYPE_USB3>;
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-snfi-nand-2500wan-p5.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-snfi-nand-2500wan-p5.dts
new file mode 100644
index 0000000..ad1dbfa
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-snfi-nand-2500wan-p5.dts
@@ -0,0 +1,205 @@
+/dts-v1/;
+#include "mt7981.dtsi"
+/ {
+	model = "MediaTek MT7981 RFB";
+	compatible = "mediatek,mt7981-snand-pcie-2500wan-p5-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		// fpga ddr2: 128MB*2
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	nmbm_snfi {
+		compatible = "generic,nmbm";
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		lower-mtd-device = <&snand>;
+		forced-create;
+		empty-page-ecc-protected;
+
+		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>;
+			};
+
+			factory: partition@180000 {
+				label = "Factory";
+				reg = <0x180000 0x0200000>;
+			};
+
+			partition@380000 {
+				label = "FIP";
+				reg = <0x380000 0x0200000>;
+			};
+
+			partition@580000 {
+				label = "ubi";
+				reg = <0x580000 0x4000000>;
+			};
+		};
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+        status = "okay";
+
+        gmac0: mac@0 {
+                compatible = "mediatek,eth-mac";
+                reg = <0>;
+                phy-mode = "2500base-x";
+
+                fixed-link {
+                        speed = <2500>;
+                        full-duplex;
+                        pause;
+                };
+        };
+
+        mdio: mdio-bus {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 14 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+                switch@0 {
+                        compatible = "mediatek,mt7531";
+                        reg = <31>;
+                        reset-gpios = <&pio 39 0>;
+
+                        ports {
+                                #address-cells = <1>;
+                                #size-cells = <0>;
+
+                                port@0 {
+                                        reg = <0>;
+                                        label = "lan1";
+                                };
+
+                                port@1 {
+                                        reg = <1>;
+                                        label = "lan2";
+                                };
+
+                                port@2 {
+                                        reg = <2>;
+                                        label = "lan3";
+                                };
+
+                                port@3 {
+                                        reg = <3>;
+                                        label = "lan4";
+                                };
+
+                        	port@5 {
+                                	reg = <5>;
+	                                label = "wan";
+        	                        phy-mode = "2500base-x";
+
+                	                fixed-link {
+                        	                speed = <2500>;
+                                	        full-duplex;
+                                        	pause;
+	                                };
+        	                };
+
+                                port@6 {
+                                        reg = <6>;
+                                        label = "cpu";
+                                        ethernet = <&gmac0>;
+                                        phy-mode = "2500base-x";
+
+                                        fixed-link {
+                                                speed = <2500>;
+                                                full-duplex;
+                                                pause;
+                                        };
+                                };
+                        };
+                };
+        };
+};
+
+&hnat {
+	mtketh-wan = "wan";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <1>;
+	status = "okay";
+};
+
+&snand {
+	pinctrl-names = "default";
+	pinctrl-0 = <&snfi_pins>;
+	status = "okay";
+	mediatek,quad-spi;
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&pcie {
+        pinctrl-names = "default";
+        pinctrl-0 = <&pcie_pins>;
+        status = "okay";
+};
+
+&pio {
+
+        pcie_pins: pcie-pins {
+                mux {
+                        function = "pcie";
+                        groups = "pcie_pereset", "pcie_clk", "pcie_wake";
+                };
+        };
+
+	snfi_pins: snfi-pins {
+		mux {
+			function = "flash";
+			groups = "snfi";
+		};
+	};
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+};
+
+&xhci {
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-2500wan-gmac2.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-2500wan-gmac2.dts
new file mode 100644
index 0000000..904d529
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-2500wan-gmac2.dts
@@ -0,0 +1,259 @@
+/dts-v1/;
+#include "mt7981.dtsi"
+/ {
+	model = "MediaTek MT7981 RFB";
+	compatible = "mediatek,mt7981-spim-snand-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		// fpga ddr2: 128MB*2
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	nmbm_spim_nand {
+		compatible = "generic,nmbm";
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		lower-mtd-device = <&spi_nand>;
+		forced-create;
+
+		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 0x0200000>;
+			};
+
+			partition@380000 {
+				label = "FIP";
+				reg = <0x380000 0x0200000>;
+			};
+
+			partition@580000 {
+				label = "ubi";
+				reg = <0x580000 0x4000000>;
+			};
+		};
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+        status = "okay";
+
+        gmac0: mac@0 {
+                compatible = "mediatek,eth-mac";
+                reg = <0>;
+                phy-mode = "2500base-x";
+
+                fixed-link {
+                        speed = <2500>;
+                        full-duplex;
+                        pause;
+                };
+        };
+
+        gmac1: mac@1 {
+                compatible = "mediatek,eth-mac";
+                reg = <1>;
+                phy-mode = "2500base-x";
+
+                fixed-link {
+                        speed = <2500>;
+                        full-duplex;
+                        pause;
+                };
+        };
+
+        mdio: mdio-bus {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 14 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+                switch@0 {
+                        compatible = "mediatek,mt7531";
+                        reg = <31>;
+                        reset-gpios = <&pio 39 0>;
+                        ports {
+                                #address-cells = <1>;
+                                #size-cells = <0>;
+
+                                port@0 {
+                                        reg = <0>;
+                                        label = "lan1";
+                                };
+
+                                port@1 {
+                                        reg = <1>;
+                                        label = "lan2";
+                                };
+
+                                port@2 {
+                                        reg = <2>;
+                                        label = "lan3";
+                                };
+
+                                port@3 {
+                                        reg = <3>;
+                                        label = "lan4";
+                                };
+
+                                port@6 {
+                                        reg = <6>;
+                                        label = "cpu";
+                                        ethernet = <&gmac0>;
+                                        phy-mode = "2500base-x";
+
+                                        fixed-link {
+                                                speed = <2500>;
+                                                full-duplex;
+                                                pause;
+                                        };
+                                };
+                        };
+                };
+        };
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi0_flash_pins>;
+	status = "okay";
+	spi_nand: spi_nand@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&pio {
+
+	i2c_pins: i2c-pins-g0 {
+                mux {
+                        function = "i2c";
+                        groups = "i2c0_0";
+                };
+        };
+
+        pcm_pins: pcm-pins-g0 {
+                mux {
+                        function = "pcm";
+                        groups = "pcm";
+                };
+        };
+
+        pwm0_pin: pwm0-pin-g0 {
+                mux {
+                        function = "pwm";
+                        groups = "pwm0_0";
+                };
+        };
+
+        pwm1_pin: pwm1-pin-g0 {
+                mux {
+                        function = "pwm";
+                        groups = "pwm1_0";
+                };
+        };
+
+        pwm2_pin: pwm2-pin {
+                mux {
+                        function = "pwm";
+                        groups = "pwm2";
+                };
+        };
+
+	spi0_flash_pins: spi0-pins {
+		mux {
+			function = "spi";
+			groups = "spi0", "spi0_wp_hold";
+		};
+
+		conf-pu {
+			pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_00>;
+		};
+
+		conf-pd {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_00>;
+		};
+	};
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+
+	uart1_pins: uart1-pins-g1 {
+                mux {
+                        function = "uart";
+                        groups = "uart1_1";
+                };
+        };
+
+	uart2_pins: uart2-pins-g1 {
+		mux {
+                        function = "uart";
+                        groups = "uart2_1";
+                };
+        };
+};
+
+&xhci {
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-gsw.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-gsw.dts
new file mode 100644
index 0000000..cd59f6d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-gsw.dts
@@ -0,0 +1,289 @@
+/dts-v1/;
+#include "mt7981.dtsi"
+/ {
+	model = "MediaTek MT7981 RFB";
+	compatible = "mediatek,mt7981-spim-snand-gsw-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		// fpga ddr2: 128MB*2
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	nmbm_spim_nand {
+		compatible = "generic,nmbm";
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		lower-mtd-device = <&spi_nand>;
+		forced-create;
+
+		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 0x0200000>;
+			};
+
+			partition@380000 {
+				label = "FIP";
+				reg = <0x380000 0x0200000>;
+			};
+
+			partition@580000 {
+				label = "ubi";
+				reg = <0x580000 0x4000000>;
+			};
+		};
+	};
+
+	sound_wm8960 {
+		compatible = "mediatek,mt79xx-wm8960-machine";
+		mediatek,platform = <&afe>;
+		audio-routing = "Headphone", "HP_L",
+				"Headphone", "HP_R",
+				"LINPUT1", "AMIC",
+				"RINPUT1", "AMIC";
+		mediatek,audio-codec = <&wm8960>;
+		status = "disabled";
+	};
+
+	sound_si3218x {
+		compatible = "mediatek,mt79xx-si3218x-machine";
+		mediatek,platform = <&afe>;
+		mediatek,ext-codec = <&proslic_spi>;
+		status = "disabled";
+	};
+
+        gsw: gsw@0 {
+                compatible = "mediatek,mt753x";
+                mediatek,ethsys = <&ethsys>;
+                #address-cells = <1>;
+                #size-cells = <0>;
+        };
+};
+
+&afe {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcm_pins>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "disabled";
+
+	wm8960: wm8960@1a {
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+        status = "okay";
+
+        gmac0: mac@0 {
+                compatible = "mediatek,eth-mac";
+                reg = <0>;
+                phy-mode = "2500base-x";
+
+                fixed-link {
+                        speed = <2500>;
+                        full-duplex;
+                        pause;
+                };
+        };
+
+        gmac1: mac@1 {
+                compatible = "mediatek,eth-mac";
+                reg = <1>;
+                phy-mode = "gmii";
+                phy-handle = <&phy0>;
+        };
+
+        mdio: mdio-bus {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                phy0: ethernet-phy@0 {
+                        compatible = "ethernet-phy-id03a2.9461";
+                        reg = <0>;
+                        phy-mode = "gmii";
+                        nvmem-cells = <&phy_calibration>;
+                        nvmem-cell-names = "phy-cal-data";
+                };
+
+        };
+};
+
+&gsw {
+        mediatek,mdio = <&mdio>;
+        mediatek,portmap = "llllw";
+        mediatek,mdio_master_pinmux = <1>;
+        reset-gpios = <&pio 39 0>;
+        interrupt-parent = <&pio>;
+        interrupts = <38 IRQ_TYPE_LEVEL_HIGH>;
+        status = "okay";
+
+        port6: port@6 {
+                compatible = "mediatek,mt753x-port";
+                reg = <6>;
+                phy-mode = "sgmii";
+                fixed-link {
+                        speed = <2500>;
+                        full-duplex;
+                };
+        };
+};
+
+&hnat {
+        mtketh-wan = "eth1";
+        mtketh-lan = "eth0";
+        mtketh-max-gmac = <2>;
+        status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi0_flash_pins>;
+	status = "okay";
+	spi_nand: spi_nand@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "okay";
+
+	proslic_spi: proslic_spi@0 {
+		compatible = "silabs,proslic_spi";
+		reg = <0>;
+		spi-max-frequency = <10000000>;
+		spi-cpha = <1>;
+		spi-cpol = <1>;
+		channel_count = <1>;
+		debug_level = <4>;       /* 1 = TRC, 2 = DBG, 4 = ERR */
+		reset_gpio = <&pio 15 0>;
+		ig,enable-spi = <1>;     /* 1: Enable, 0: Disable */
+	};
+};
+
+&pio {
+
+	i2c_pins: i2c-pins-g0 {
+                mux {
+                        function = "i2c";
+                        groups = "i2c0_0";
+                };
+        };
+
+        pcm_pins: pcm-pins-g0 {
+                mux {
+                        function = "pcm";
+                        groups = "pcm";
+                };
+        };
+
+        pwm0_pin: pwm0-pin-g0 {
+                mux {
+                        function = "pwm";
+                        groups = "pwm0_0";
+                };
+        };
+
+        pwm1_pin: pwm1-pin-g0 {
+                mux {
+                        function = "pwm";
+                        groups = "pwm1_0";
+                };
+        };
+
+        pwm2_pin: pwm2-pin {
+                mux {
+                        function = "pwm";
+                        groups = "pwm2";
+                };
+        };
+
+	spi0_flash_pins: spi0-pins {
+		mux {
+			function = "spi";
+			groups = "spi0", "spi0_wp_hold";
+		};
+
+		conf-pu {
+			pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_00>;
+		};
+
+		conf-pd {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_00>;
+		};
+	};
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+
+	uart1_pins: uart1-pins-g1 {
+                mux {
+                        function = "uart";
+                        groups = "uart1_1";
+                };
+        };
+
+	uart2_pins: uart2-pins-g1 {
+		mux {
+                        function = "uart";
+                        groups = "uart2_1";
+                };
+        };
+};
+
+&xhci {
+	mediatek,u3p-dis-msk = <0x0>;
+	phys = <&u2port0 PHY_TYPE_USB2>,
+	       <&u3port0 PHY_TYPE_USB3>;
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-rfb.dts
new file mode 100755
index 0000000..e8a3d2f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-rfb.dts
@@ -0,0 +1,305 @@
+/dts-v1/;
+#include "mt7981.dtsi"
+/ {
+	model = "MediaTek MT7981 RFB";
+	compatible = "mediatek,mt7981-spim-snand-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		// fpga ddr2: 128MB*2
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	nmbm_spim_nand {
+		compatible = "generic,nmbm";
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		lower-mtd-device = <&spi_nand>;
+		forced-create;
+
+		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 0x0200000>;
+			};
+
+			partition@380000 {
+				label = "FIP";
+				reg = <0x380000 0x0200000>;
+			};
+
+			partition@580000 {
+				label = "ubi";
+				reg = <0x580000 0x4000000>;
+			};
+		};
+	};
+
+	sound_wm8960 {
+		compatible = "mediatek,mt79xx-wm8960-machine";
+		mediatek,platform = <&afe>;
+		audio-routing = "Headphone", "HP_L",
+				"Headphone", "HP_R",
+				"LINPUT1", "AMIC",
+				"RINPUT1", "AMIC";
+		mediatek,audio-codec = <&wm8960>;
+		status = "disabled";
+	};
+
+	sound_si3218x {
+		compatible = "mediatek,mt79xx-si3218x-machine";
+		mediatek,platform = <&afe>;
+		mediatek,ext-codec = <&proslic_spi>;
+		status = "disabled";
+	};
+};
+
+&afe {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcm_pins>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "disabled";
+
+	wm8960: wm8960@1a {
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+        status = "okay";
+
+        gmac0: mac@0 {
+                compatible = "mediatek,eth-mac";
+                reg = <0>;
+                phy-mode = "2500base-x";
+
+                fixed-link {
+                        speed = <2500>;
+                        full-duplex;
+                        pause;
+                };
+        };
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "gmii";
+		phy-handle = <&phy0>;
+	};
+
+        mdio: mdio-bus {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+		phy0: ethernet-phy@0 {
+			compatible = "ethernet-phy-id03a2.9461";
+			reg = <0>;
+			phy-mode = "gmii";
+			nvmem-cells = <&phy_calibration>;
+			nvmem-cell-names = "phy-cal-data";
+		};
+
+		switch@0 {
+                        compatible = "mediatek,mt7531";
+                        reg = <31>;
+                        reset-gpios = <&pio 39 0>;
+
+                        ports {
+                                #address-cells = <1>;
+                                #size-cells = <0>;
+
+                                port@0 {
+                                        reg = <0>;
+                                        label = "lan1";
+                                };
+
+                                port@1 {
+                                        reg = <1>;
+                                        label = "lan2";
+                                };
+
+                                port@2 {
+                                        reg = <2>;
+                                        label = "lan3";
+                                };
+
+                                port@3 {
+                                        reg = <3>;
+                                        label = "lan4";
+                                };
+
+                                port@6 {
+                                        reg = <6>;
+                                        label = "cpu";
+                                        ethernet = <&gmac0>;
+                                        phy-mode = "2500base-x";
+
+                                        fixed-link {
+                                                speed = <2500>;
+                                                full-duplex;
+                                                pause;
+                                        };
+                                };
+                        };
+                };
+        };
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi0_flash_pins>;
+	status = "okay";
+	spi_nand: spi_nand@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "okay";
+
+	proslic_spi: proslic_spi@0 {
+		compatible = "silabs,proslic_spi";
+		reg = <0>;
+		spi-max-frequency = <10000000>;
+		spi-cpha = <1>;
+		spi-cpol = <1>;
+		channel_count = <1>;
+		debug_level = <4>;       /* 1 = TRC, 2 = DBG, 4 = ERR */
+		reset_gpio = <&pio 15 0>;
+		ig,enable-spi = <1>;     /* 1: Enable, 0: Disable */
+	};
+};
+
+&pio {
+
+	i2c_pins: i2c-pins-g0 {
+                mux {
+                        function = "i2c";
+                        groups = "i2c0_0";
+                };
+        };
+
+        pcm_pins: pcm-pins-g0 {
+                mux {
+                        function = "pcm";
+                        groups = "pcm";
+                };
+        };
+
+        pwm0_pin: pwm0-pin-g0 {
+                mux {
+                        function = "pwm";
+                        groups = "pwm0_0";
+                };
+        };
+
+        pwm1_pin: pwm1-pin-g0 {
+                mux {
+                        function = "pwm";
+                        groups = "pwm1_0";
+                };
+        };
+
+        pwm2_pin: pwm2-pin {
+                mux {
+                        function = "pwm";
+                        groups = "pwm2";
+                };
+        };
+
+	spi0_flash_pins: spi0-pins {
+		mux {
+			function = "spi";
+			groups = "spi0", "spi0_wp_hold";
+		};
+
+		conf-pu {
+			pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_00>;
+		};
+
+		conf-pd {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_00>;
+		};
+	};
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+
+	uart1_pins: uart1-pins-g1 {
+                mux {
+                        function = "uart";
+                        groups = "uart1_1";
+                };
+        };
+
+	uart2_pins: uart2-pins-g1 {
+		mux {
+                        function = "uart";
+                        groups = "uart2_1";
+                };
+        };
+};
+
+&xhci {
+	mediatek,u3p-dis-msk = <0x0>;
+	phys = <&u2port0 PHY_TYPE_USB2>,
+	       <&u3port0 PHY_TYPE_USB3>;
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nor-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nor-rfb.dts
new file mode 100755
index 0000000..ee0382d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nor-rfb.dts
@@ -0,0 +1,192 @@
+/dts-v1/;
+#include "mt7981.dtsi"
+/ {
+	model = "MediaTek MT7981 RFB";
+	compatible = "mediatek,mt7981-spim-nor-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		// fpga ddr2: 128MB*2
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+        status = "okay";
+
+        gmac0: mac@0 {
+                compatible = "mediatek,eth-mac";
+                reg = <0>;
+                phy-mode = "2500base-x";
+
+                fixed-link {
+                        speed = <2500>;
+                        full-duplex;
+                        pause;
+                };
+        };
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "gmii";
+		phy-handle = <&phy0>;
+	};
+
+        mdio: mdio-bus {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+		phy0: ethernet-phy@0 {
+			compatible = "ethernet-phy-id03a2.9461";
+			reg = <0>;
+			phy-mode = "gmii";
+			nvmem-cells = <&phy_calibration>;
+			nvmem-cell-names = "phy-cal-data";
+		};
+
+		switch@0 {
+                        compatible = "mediatek,mt7531";
+                        reg = <31>;
+                        reset-gpios = <&pio 39 0>;
+
+                        ports {
+                                #address-cells = <1>;
+                                #size-cells = <0>;
+
+                                port@0 {
+                                        reg = <0>;
+                                        label = "lan1";
+                                };
+
+                                port@1 {
+                                        reg = <1>;
+                                        label = "lan2";
+                                };
+
+                                port@2 {
+                                        reg = <2>;
+                                        label = "lan3";
+                                };
+
+                                port@3 {
+                                        reg = <3>;
+                                        label = "lan4";
+                                };
+
+                                port@6 {
+                                        reg = <6>;
+                                        label = "cpu";
+                                        ethernet = <&gmac0>;
+                                        phy-mode = "2500base-x";
+
+                                        fixed-link {
+                                                speed = <2500>;
+                                                full-duplex;
+                                                pause;
+                                        };
+                                };
+                        };
+                };
+        };
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&spi2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi2_flash_pins>;
+	status = "okay";
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <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>;
+		};
+		partition@180000 {
+			label = "firmware";
+			reg = <0x180000 0xE00000>;
+		};
+	};
+};
+
+&pio {
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+
+	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-down = <MTK_PUPD_SET_R1R0_00>;
+		};
+
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_00>;
+		};
+	};
+};
+
+&xhci {  
+        status = "okay";
+};
+
+&wed {
+	dy_txbm_enable = "true";
+	dy_txbm_budget = <8>;
+	txbm_init_sz = <8>;
+	txbm_max_sz = <32>;
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981.dtsi
new file mode 100644
index 0000000..1374f2e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981.dtsi
@@ -0,0 +1,674 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Sam.Shih <sam.shih@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/phy/phy.h>
+#include <dt-bindings/reset/ti-syscon.h>
+#include <dt-bindings/clock/mt7981-clk.h>
+#include <dt-bindings/pinctrl/mt65xx.h>
+/ {
+	compatible = "mediatek,mt7981-rfb";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			enable-method = "psci";
+			reg = <0x0>;
+		};
+
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			enable-method = "psci";
+			reg = <0x1>;
+		};
+	};
+
+	pwm: pwm@10048000 {
+		compatible = "mediatek,mt7981-pwm";
+		reg = <0 0x10048000 0 0x1000>;
+		#pwm-cells = <2>;
+		clocks = <&infracfg_ao CK_INFRA_PWM_STA>,
+			 <&infracfg_ao CK_INFRA_PWM_HCK>,
+			 <&infracfg_ao CK_INFRA_PWM1_CK>,
+			 <&infracfg_ao CK_INFRA_PWM2_CK>,
+			 <&infracfg_ao CK_INFRA_PWM3_CK>;
+		clock-names = "top", "main", "pwm1", "pwm2", "pwm3";
+	};
+
+	thermal-zones {
+		cpu_thermal: cpu-thermal {
+			polling-delay-passive = <1000>;
+			polling-delay = <1000>;
+			thermal-sensors = <&thermal 0>;
+		};
+	};
+
+	thermal: thermal@1100c800 {
+		#thermal-sensor-cells = <1>;
+		compatible = "mediatek,mt7981-thermal";
+		reg = <0 0x1100c800 0 0x800>;
+		interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_THERM_CK>,
+			 <&infracfg_ao CK_INFRA_ADC_26M_CK>,
+			 <&infracfg_ao CK_INFRA_ADC_FRC_CK>;
+		clock-names = "therm", "auxadc", "adc_32k";
+		mediatek,auxadc = <&auxadc>;
+		mediatek,apmixedsys = <&apmixedsys>;
+		nvmem-cells = <&thermal_calibration>;
+		nvmem-cell-names = "calibration-data";
+	};
+
+	auxadc: adc@1100d000 {
+		compatible = "mediatek,mt7981-auxadc",
+			     "mediatek,mt7622-auxadc";
+		reg = <0 0x1100d000 0 0x1000>;
+		clocks = <&infracfg_ao CK_INFRA_ADC_26M_CK>,
+			 <&infracfg_ao CK_INFRA_ADC_FRC_CK>;
+		clock-names = "main", "32k";
+		#io-channel-cells = <1>;
+	};
+
+	wed: wed@15010000 {
+		compatible = "mediatek,wed";
+		wed_num = <2>;
+		/* add this property for wed get the pci slot number. */
+		pci_slot_map = <0>, <1>;
+		reg = <0 0x15010000 0 0x1000>,
+		      <0 0x15011000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	wdma: wdma@15104800 {
+		compatible = "mediatek,wed-wdma";
+		reg = <0 0x15104800 0 0x400>,
+		      <0 0x15104c00 0 0x400>;
+	};
+
+	ap2woccif: ap2woccif@151A5000 {
+		compatible = "mediatek,ap2woccif";
+		reg = <0 0x151A5000 0 0x1000>,
+		      <0 0x151AD000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>;
+        };
+
+	wocpu0_ilm: wocpu0_ilm@151E0000 {
+		compatible = "mediatek,wocpu0_ilm";
+		reg = <0 0x151E0000 0 0x8000>;
+	};
+
+	wocpu_dlm: wocpu_dlm@151E8000 {
+		compatible = "mediatek,wocpu_dlm";
+		reg = <0 0x151E8000 0 0x2000>,
+		      <0 0x151F8000 0 0x2000>;
+
+		resets = <&ethsysrst 0>;
+		reset-names = "wocpu_rst";
+	};
+
+	cpu_boot: wocpu_boot@15194000 {
+		compatible = "mediatek,wocpu_boot";
+		reg = <0 0x15194000 0 0x1000>;
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		/* 192 KiB reserved for ARM Trusted Firmware (BL31) */
+		secmon_reserved: secmon@43000000 {
+			reg = <0 0x43000000 0 0x30000>;
+			no-map;
+		};
+
+		wmcpu_emi: wmcpu-reserved@47C80000 {
+			compatible = "mediatek,wmcpu-reserved";
+			no-map;
+			reg = <0 0x47C80000 0 0x00100000>;
+		};
+
+		wocpu0_emi: wocpu0_emi@47D80000 {
+			compatible = "mediatek,wocpu0_emi";
+			no-map;
+			reg = <0 0x47D80000 0 0x40000>;
+			shared = <0>;
+		};
+
+		wocpu_data: wocpu_data@47DC0000 {
+			compatible = "mediatek,wocpu_data";
+			no-map;
+			reg = <0 0x47DC0000 0 0x240000>;
+			shared = <1>;
+		};
+	};
+
+	psci {
+		compatible  = "arm,psci-0.2";
+		method      = "smc";
+	};
+
+	clk40m: oscillator@0 {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <40000000>;
+		clock-output-names = "clkxtal";
+	};
+
+	infracfg_ao: infracfg_ao@10001000 {
+		compatible = "mediatek,mt7981-infracfg_ao", "syscon";
+		reg = <0 0x10001000 0 0x68>;
+		#clock-cells = <1>;
+	};
+
+	infracfg: infracfg@10001040 {
+		compatible = "mediatek,mt7981-infracfg", "syscon";
+		reg = <0 0x10001068 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	topckgen: topckgen@1001B000 {
+		compatible = "mediatek,mt7981-topckgen", "syscon";
+		reg = <0 0x1001B000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	apmixedsys: apmixedsys@1001E000 {
+		compatible = "mediatek,mt7981-apmixedsys", "syscon";
+		reg = <0 0x1001E000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	system_clk: dummy_system_clk {
+		compatible = "fixed-clock";
+		clock-frequency = <40000000>;
+		#clock-cells = <0>;
+	};
+
+	gpt_clk: dummy_gpt_clk {
+		compatible = "fixed-clock";
+		clock-frequency = <20000000>;
+		#clock-cells = <0>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupt-parent = <&gic>;
+		clock-frequency = <13000000>;
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+
+	};
+
+	watchdog: watchdog@1001c000 {
+		compatible = "mediatek,mt7622-wdt",
+			     "mediatek,mt6589-wdt";
+		reg = <0 0x1001c000 0 0x1000>;
+		interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+		#reset-cells = <1>;
+	};
+
+	gic: interrupt-controller@c000000 {
+		compatible = "arm,gic-v3";
+		#interrupt-cells = <3>;
+		interrupt-parent = <&gic>;
+		interrupt-controller;
+		reg = <0 0x0c000000 0 0x40000>,  /* GICD */
+		      <0 0x0c080000 0 0x200000>; /* GICR */
+
+		interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	trng: trng@1020f000 {
+		compatible = "mediatek,mt7981-rng";
+	};
+
+	uart0: serial@11002000 {
+		compatible = "mediatek,mt6577-uart";
+		reg = <0 0x11002000 0 0x400>;
+		interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_UART0_CK>;
+		assigned-clocks = <&topckgen CK_TOP_UART_SEL>,
+				  <&infracfg_ao CK_INFRA_UART0_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_CKSQ_40M>,
+					 <&infracfg CK_INFRA_UART>;
+		status = "disabled";
+	};
+
+	uart1: serial@11003000 {
+		compatible = "mediatek,mt6577-uart";
+		reg = <0 0x11003000 0 0x400>;
+		interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_UART1_CK>;
+		assigned-clocks = <&topckgen CK_TOP_UART_SEL>,
+				  <&infracfg_ao CK_INFRA_UART1_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_CKSQ_40M>,
+					 <&infracfg CK_INFRA_UART>;
+		status = "disabled";
+	};
+
+	uart2: serial@11004000 {
+		compatible = "mediatek,mt6577-uart";
+		reg = <0 0x11004000 0 0x400>;
+		interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_UART2_CK>;
+		assigned-clocks = <&topckgen CK_TOP_UART_SEL>,
+				  <&infracfg_ao CK_INFRA_UART2_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_CKSQ_40M>,
+					 <&infracfg CK_INFRA_UART>;
+		status = "disabled";
+	};
+
+	i2c0: i2c@11007000 {
+		compatible = "mediatek,mt7981-i2c";
+		reg = <0 0x11007000 0 0x1000>,
+		      <0 0x10217080 0 0x80>;
+		interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+		clock-div = <1>;
+		clocks = <&infracfg_ao CK_INFRA_I2CO_CK>,
+			 <&infracfg_ao CK_INFRA_AP_DMA_CK>;
+		clock-names = "main", "dma";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	pcie: pcie@11280000 {
+		compatible = "mediatek,mt7981-pcie",
+			     "mediatek,mt7986-pcie";
+		device_type = "pci";
+		reg = <0 0x11280000 0 0x4000>;
+		reg-names = "pcie-mac";
+		#address-cells = <3>;
+		#size-cells = <2>;
+		interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+		bus-range = <0x00 0xff>;
+		ranges = <0x82000000 0 0x20000000
+			  0x0 0x20000000 0 0x10000000>;
+		status = "disabled";
+
+		clocks = <&infracfg_ao CK_INFRA_IPCIE_CK>,
+			 <&infracfg_ao CK_INFRA_IPCIE_PIPE_CK>,
+			 <&infracfg_ao CK_INFRA_IPCIER_CK>,
+			 <&infracfg_ao CK_INFRA_IPCIEB_CK>;
+
+		phys = <&u3port0 PHY_TYPE_PCIE>;
+		phy-names = "pcie-phy";
+
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 7>;
+		interrupt-map = <0 0 0 1 &pcie_intc 0>,
+				<0 0 0 2 &pcie_intc 1>,
+				<0 0 0 3 &pcie_intc 2>,
+				<0 0 0 4 &pcie_intc 3>;
+		pcie_intc: interrupt-controller {
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <1>;
+		};
+	};
+
+	crypto: crypto@10320000 {
+		compatible = "inside-secure,safexcel-eip97";
+		reg = <0 0x10320000 0 0x40000>;
+		interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "ring0", "ring1", "ring2", "ring3";
+		clocks = <&topckgen CK_TOP_EIP97B>;
+		clock-names = "top_eip97_ck";
+		assigned-clocks = <&topckgen CK_TOP_EIP97B_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_NET1_D5>;
+	};
+
+	pio: pinctrl@11d00000 {
+		compatible = "mediatek,mt7981-pinctrl";
+		reg = <0 0x11d00000 0 0x1000>,
+		      <0 0x11c00000 0 0x1000>,
+		      <0 0x11c10000 0 0x1000>,
+		      <0 0x11d20000 0 0x1000>,
+		      <0 0x11e00000 0 0x1000>,
+		      <0 0x11e20000 0 0x1000>,
+		      <0 0x11f00000 0 0x1000>,
+		      <0 0x11f10000 0 0x1000>,
+		      <0 0x1000b000 0 0x1000>;
+		reg-names = "gpio_base", "iocfg_rt_base", "iocfg_rm_base",
+			    "iocfg_rb_base", "iocfg_lb_base", "iocfg_bl_base",
+			    "iocfg_tm_base", "iocfg_tl_base", "eint";
+		gpio-controller;
+		#gpio-cells = <2>;
+		gpio-ranges = <&pio 0 0 56>;
+		interrupt-controller;
+		interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-parent = <&gic>;
+		#interrupt-cells = <2>;
+	};
+
+	ethsys: syscon@15000000 {
+                #address-cells = <1>;
+                #size-cells = <1>;
+                compatible = "mediatek,mt7981-ethsys",
+                             "syscon";
+                reg = <0 0x15000000 0 0x1000>;
+                #clock-cells = <1>;
+                #reset-cells = <1>;
+
+		ethsysrst: reset-controller {
+			compatible = "ti,syscon-reset";
+			#reset-cells = <1>;
+			ti,reset-bits = <0x34 4 0x34 4 0x34 4 (ASSERT_SET | DEASSERT_CLEAR | STATUS_SET)>;
+		};
+        };
+
+        eth: ethernet@15100000 {
+                compatible = "mediatek,mt7981-eth";
+                reg = <0 0x15100000 0 0x80000>;
+                interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
+                clocks = <&ethsys CK_ETH_FE_EN>,
+                         <&ethsys CK_ETH_GP2_EN>,
+                         <&ethsys CK_ETH_GP1_EN>,
+                         <&ethsys CK_ETH_WOCPU0_EN>,
+                         <&sgmiisys0 CK_SGM0_TX_EN>,
+                         <&sgmiisys0 CK_SGM0_RX_EN>,
+                         <&sgmiisys0 CK_SGM0_CK0_EN>,
+                         <&sgmiisys0 CK_SGM0_CDR_CK0_EN>,
+                         <&sgmiisys1 CK_SGM1_TX_EN>,
+                         <&sgmiisys1 CK_SGM1_RX_EN>,
+                         <&sgmiisys1 CK_SGM1_CK1_EN>,
+                         <&sgmiisys1 CK_SGM1_CDR_CK1_EN>;
+		clock-names = "fe", "gp2", "gp1", "wocpu0",
+                         "sgmii_tx250m", "sgmii_rx250m",
+                         "sgmii_cdr_ref", "sgmii_cdr_fb",
+                         "sgmii2_tx250m", "sgmii2_rx250m",
+                         "sgmii2_cdr_ref", "sgmii2_cdr_fb";
+                assigned-clocks = <&topckgen CK_TOP_NETSYS_2X_SEL>,
+                                  <&topckgen CK_TOP_SGM_325M_SEL>;
+                assigned-clock-parents = <&topckgen CK_TOP_CB_NET2_800M>,
+                                         <&topckgen CK_TOP_CB_SGM_325M>;
+                mediatek,ethsys = <&ethsys>;
+		mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
+		mediatek,infracfg = <&topmisc>;
+                #reset-cells = <1>;
+                #address-cells = <1>;
+                #size-cells = <0>;
+                status = "disabled";
+        };
+
+	hnat: hnat@15000000 {
+		compatible = "mediatek,mtk-hnat_v4";
+		reg = <0 0x15100000 0 0x80000>;
+		resets = <&ethsys 0>;
+		reset-names = "mtketh";
+		status = "disabled";
+	};
+
+	sgmiisys0: syscon@10060000 {
+		compatible = "mediatek,mt7981-sgmiisys_0", "syscon";
+		reg = <0 0x10060000 0 0x1000>;
+		pn_swap;
+		#clock-cells = <1>;
+	};
+
+	sgmiisys1: syscon@10070000 {
+		compatible = "mediatek,mt7981-sgmiisys_1", "syscon";
+		reg = <0 0x10070000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	topmisc: topmisc@11d10000 {
+		compatible = "mediatek,mt7981-topmisc", "syscon";
+		reg = <0 0x11d10000 0 0x10000>;
+		#clock-cells = <1>;
+	};
+
+	snand: snfi@11005000 {
+		compatible = "mediatek,mt7986-snand";
+		reg = <0 0x11005000 0 0x1000>, <0 0x11006000 0 0x1000>;
+		reg-names = "nfi", "ecc";
+		interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_SPINFI1_CK>,
+			 <&infracfg_ao CK_INFRA_NFI1_CK>,
+			 <&infracfg_ao CK_INFRA_NFI_HCK_CK>;
+		clock-names = "pad_clk", "nfi_clk", "nfi_hclk";
+		assigned-clocks = <&topckgen CK_TOP_SPINFI_SEL>,
+				  <&topckgen CK_TOP_NFI1X_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_M_D8>,
+					 <&topckgen CK_TOP_CB_M_D8>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	mmc0: mmc@11230000 {
+                   compatible = "mediatek,mt7986-mmc",
+                                "mediatek,mt7981-mmc";
+                   reg = <0 0x11230000 0 0x1000>, <0 0x11c20000 0 0x1000>;
+                   interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+                   clocks = <&topckgen CK_TOP_EMMC_208M>,
+                             <&topckgen CK_TOP_EMMC_400M>,
+                             <&infracfg_ao CK_INFRA_MSDC_CK>;
+                   assigned-clocks = <&topckgen CK_TOP_EMMC_208M_SEL>,
+                                      <&topckgen CK_TOP_EMMC_400M_SEL>;
+                   assigned-clock-parents = <&topckgen CK_TOP_CB_M_D2>,
+                                             <&topckgen CK_TOP_CB_NET2_D2>;
+                   clock-names = "source", "hclk", "source_cg";
+                   status = "disabled";
+        };
+
+	wbsys: wbsys@18000000 {
+		compatible = "mediatek,wbsys";
+		reg = <0 0x18000000 0  0x1000000>;
+		interrupts = <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 215 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>;
+		chip_id = <0x7981>;
+	};
+
+	wed_pcie: wed_pcie@10003000 {
+		compatible = "mediatek,wed_pcie";
+		reg = <0 0x10003000 0 0x10>;
+	};
+
+	spi0: spi@1100a000 {
+		compatible = "mediatek,ipm-spi-quad";
+		reg = <0 0x1100a000 0 0x100>;
+		interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&topckgen CK_TOP_CB_M_D2>,
+			 <&topckgen CK_TOP_SPI_SEL>,
+			 <&infracfg_ao CK_INFRA_SPI0_CK>,
+			 <&infracfg_ao CK_INFRA_SPI0_HCK_CK>;
+		clock-names = "parent-clk", "sel-clk", "spi-clk", "spi-hclk";
+		status = "disabled";
+	};
+
+	spi1: spi@1100b000 {
+		compatible = "mediatek,ipm-spi-single";
+		reg = <0 0x1100b000 0 0x100>;
+		interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&topckgen CK_TOP_CB_M_D2>,
+			 <&topckgen CK_TOP_SPIM_MST_SEL>,
+			 <&infracfg_ao CK_INFRA_SPI1_CK>,
+			 <&infracfg_ao CK_INFRA_SPI1_HCK_CK>;
+		clock-names = "parent-clk", "sel-clk", "spi-clk", "spi-hclk";
+		status = "disabled";
+	};
+
+	spi2: spi@11009000 {
+		compatible = "mediatek,ipm-spi-quad";
+		reg = <0 0x11009000 0 0x100>;
+		interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&topckgen CK_TOP_CB_M_D2>,
+			 <&topckgen CK_TOP_SPI_SEL>,
+			 <&infracfg_ao CK_INFRA_SPI2_CK>,
+			 <&infracfg_ao CK_INFRA_SPI2_HCK_CK>;
+		clock-names = "parent-clk", "sel-clk", "spi-clk", "spi-hclk";
+		status = "disabled";
+	};
+
+
+	consys: consys@10000000 {
+		compatible = "mediatek,mt7981-consys";
+		reg = <0 0x10000000 0 0x8600000>;
+		memory-region = <&wmcpu_emi>;
+	};
+
+	xhci: xhci@11200000 {
+		compatible = "mediatek,mt7986-xhci",
+			     "mediatek,mtk-xhci";
+		reg = <0 0x11200000 0 0x2e00>,
+		      <0 0x11203e00 0 0x0100>;
+		reg-names = "mac", "ippc";
+		interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&u2port0 PHY_TYPE_USB2>;
+		clocks = <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>;
+		clock-names = "sys_ck",
+			      "xhci_ck",
+			      "ref_ck",
+			      "mcu_ck",
+			      "dma_ck";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		mediatek,u3p-dis-msk = <0x01>;
+		status = "disabled";
+	};
+
+	usbtphy: usb-phy@11e10000 {
+		compatible = "mediatek,mt7986",
+			     "mediatek,generic-tphy-v2";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+		status = "okay";
+
+		u2port0: usb-phy@11e10000 {
+			reg = <0 0x11e10000 0 0x700>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			status = "okay";
+		};
+
+		u3port0: usb-phy@11e10700 {
+			reg = <0 0x11e10700 0 0x900>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			mediatek,syscon-type = <&topmisc 0x218 0>;
+			nvmem-cells = <&comb_intr_p0>,
+			      <&comb_rx_imp_p0>,
+			      <&comb_tx_imp_p0>;
+			nvmem-cell-names = "intr", "rx_imp", "tx_imp";
+			status = "okay";
+		};
+	};
+
+        reg_3p3v: regulator-3p3v {
+                  compatible = "regulator-fixed";
+                  regulator-name = "fixed-3.3V";
+                  regulator-min-microvolt = <3300000>;
+                  regulator-max-microvolt = <3300000>;
+                  regulator-boot-on;
+                  regulator-always-on;
+        };
+
+        clkitg: clkitg {
+		compatible = "simple-bus";
+	};
+
+	efuse: efuse@11f20000 {
+		compatible = "mediatek,efuse";
+		reg = <0 0x11f20000 0 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		thermal_calibration: calib@274 {
+			reg = <0x274 0xc>;
+		};
+
+		phy_calibration: calib@8dc {
+			reg = <0x8dc 0x10>;
+		};
+
+		comb_rx_imp_p0: usb3-rx-imp@8c8 {
+			reg = <0x8c8 1>;
+			bits = <0 5>;
+		};
+
+		comb_tx_imp_p0: usb3-tx-imp@8c8 {
+			reg = <0x8c8 2>;
+			bits = <5 5>;
+		};
+
+		comb_intr_p0: usb3-intr@8c9 {
+			reg = <0x8c9 1>;
+			bits = <2 6>;
+		};
+	};
+
+	afe: audio-controller@11210000 {
+		compatible = "mediatek,mt79xx-audio";
+		reg = <0 0x11210000 0 0x9000>;
+		interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_AUD_BUS_CK>,
+			 <&infracfg_ao CK_INFRA_AUD_26M_CK>,
+			 <&infracfg_ao CK_INFRA_AUD_L_CK>,
+			 <&infracfg_ao CK_INFRA_AUD_AUD_CK>,
+			 <&infracfg_ao CK_INFRA_AUD_EG2_CK>,
+			 <&topckgen CK_TOP_AUD_SEL>;
+		clock-names = "aud_bus_ck",
+			      "aud_26m_ck",
+			      "aud_l_ck",
+			      "aud_aud_ck",
+			      "aud_eg2_ck",
+			      "aud_sel";
+		assigned-clocks = <&topckgen CK_TOP_AUD_SEL>,
+				  <&topckgen CK_TOP_A1SYS_SEL>,
+				  <&topckgen CK_TOP_AUD_L_SEL>,
+				  <&topckgen CK_TOP_A_TUNER_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_APLL2_196M>,
+					 <&topckgen CK_TOP_APLL2_D4>,
+					 <&topckgen CK_TOP_CB_APLL2_196M>,
+					 <&topckgen CK_TOP_APLL2_D4>;
+		status = "disabled";
+	};
+
+	ice: ice_debug {
+		compatible = "mediatek,mt7981-ice_debug",
+			   "mediatek,mt2701-ice_debug";
+		clocks = <&infracfg_ao CK_INFRA_DBG_CK>;
+		clock-names = "ice_dbg";
+	};
+};
+#include "mt7981-clkitg.dtsi"
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-clkitg.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-clkitg.dtsi
new file mode 100644
index 0000000..70b56f2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-clkitg.dtsi
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Wenzhen.Yu <Wenzhen.Yu@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&clkitg {
+	bring-up {
+		compatible = "mediatek,clk-bring-up";
+		clocks =
+			<&apmixedsys CK_APMIXED_ARMPLL>,
+			<&apmixedsys  CK_APMIXED_NET2PLL>,
+			<&apmixedsys  CK_APMIXED_MMPLL>,
+			<&apmixedsys  CK_APMIXED_SGMPLL>,
+			<&apmixedsys  CK_APMIXED_WEDMCUPLL>,
+			<&apmixedsys  CK_APMIXED_NET1PLL>,
+			<&apmixedsys  CK_APMIXED_MPLL>,
+			<&apmixedsys  CK_APMIXED_APLL2>,
+			<&infracfg CK_INFRA_CK_F26M>,
+			<&infracfg CK_INFRA_UART>,
+			<&clk40m>,
+			<&infracfg CK_INFRA_I2C>,
+			<&clk40m>,
+			<&infracfg CK_INFRA_PWM>,
+			<&infracfg CK_INFRA_66M_MCK>,
+			<&infracfg CK_INFRA_CK_F32K>,
+			<&clk40m>,
+			<&infracfg CK_INFRA_PWM_BCK>,
+			<&infracfg CK_INFRA_PWM_CK1>,
+			<&infracfg CK_INFRA_PWM_CK2>,
+			<&infracfg CK_INFRA_133M_HCK>,
+			<&infracfg CK_INFRA_EIP_CK>,
+			<&infracfg CK_INFRA_66M_PHCK>,
+			<&infracfg CK_INFRA_FAUD_L_CK	>,
+			<&infracfg CK_INFRA_FAUD_AUD_CK>,
+			<&infracfg CK_INFRA_FAUD_EG2_CK>,
+			<&infracfg CK_INFRA_I2CS_CK>,
+			<&infracfg CK_INFRA_MUX_UART0>,
+			<&infracfg CK_INFRA_MUX_UART1>,
+			<&infracfg CK_INFRA_MUX_UART2>,
+			<&infracfg CK_INFRA_NFI_CK>,
+			<&infracfg CK_INFRA_SPINFI_CK>,
+			<&clk40m>,
+			<&clk40m>,
+			<&infracfg CK_INFRA_RTC_32K>,
+			<&infracfg CK_INFRA_FMSDC_CK>,
+			<&infracfg CK_INFRA_FMSDC_HCK_CK>,
+			<&infracfg CK_INFRA_PERI_133M>,
+			<&infracfg CK_INFRA_133M_PHCK>,
+			<&infracfg CK_INFRA_USB_SYS_CK>,
+			<&infracfg CK_INFRA_USB_CK>,
+			<&infracfg CK_INFRA_USB_XHCI_CK>,
+			<&clk40m>,
+			<&infracfg CK_INFRA_F26M_CK0>,
+			<&infracfg_ao CK_INFRA_UART0_SEL>,
+			<&infracfg_ao CK_INFRA_UART1_SEL>,	
+			<&infracfg_ao CK_INFRA_UART2_SEL>,
+			<&clk40m>,
+			<&clk40m>,
+			<&infracfg_ao CK_INFRA_PWM1_SEL>,
+			<&infracfg_ao CK_INFRA_PWM2_SEL>,
+			<&infracfg_ao CK_INFRA_PWM_BSEL>,
+			<&clk40m>,
+			<&clk40m>,
+			<&infracfg_ao CK_INFRA_PWM_HCK>,
+			<&infracfg_ao CK_INFRA_PWM_STA>,
+			<&infracfg_ao CK_INFRA_PWM1_CK>,
+			<&infracfg_ao CK_INFRA_PWM2_CK>,
+			<&infracfg_ao CK_INFRA_CQ_DMA_CK>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&infracfg_ao CK_INFRA_DRAMC_26M_CK>,
+			<&clk40m>,
+			<&infracfg_ao CK_INFRA_AP_DMA_CK>,
+			<&infracfg_ao CK_INFRA_SEJ_CK>,
+			<&infracfg_ao CK_INFRA_SEJ_13M_CK>,
+			<&clk40m>,
+			<&infracfg_ao CK_INFRA_I2CO_CK>,
+			<&infracfg_ao CK_INFRA_UART0_CK>,
+			<&infracfg_ao CK_INFRA_UART1_CK>,
+			<&infracfg_ao CK_INFRA_UART2_CK>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&infracfg_ao CK_INFRA_FRTC_CK>,
+			<&infracfg_ao CK_INFRA_MSDC_CK>,
+			<&infracfg_ao CK_INFRA_MSDC_HCK_CK>,
+			<&infracfg_ao CK_INFRA_MSDC_133M_CK>,
+			<&infracfg_ao CK_INFRA_MSDC_66M_CK>,
+			<&clk40m>,
+			<&clk40m>,
+			<&infracfg_ao CK_INFRA_FBIST2FPC_CK>,
+			<&infracfg_ao CK_INFRA_IUSB_133_CK>,
+			<&infracfg_ao CK_INFRA_IUSB_66M_CK>,
+			<&infracfg_ao CK_INFRA_IUSB_SYS_CK>,
+			<&infracfg_ao CK_INFRA_IUSB_CK>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&topckgen CK_TOP_CB_M_416M>,
+			<&clk40m>,
+			<&topckgen CK_TOP_CB_M_D4>,
+			<&topckgen CK_TOP_CB_M_D8>,
+			<&topckgen CK_TOP_M_D8_D2>,
+			<&topckgen CK_TOP_M_D3_D2>,
+			<&topckgen CK_TOP_CB_MM_D2>,
+			<&topckgen CK_TOP_CB_MM_D4>,
+			<&topckgen CK_TOP_CB_MM_D8>,
+			<&topckgen CK_TOP_MM_D8_D2>,
+			<&topckgen CK_TOP_MM_D3_D8>,
+			<&topckgen CK_TOP_CB_U2_PHYD_CK>,
+			<&topckgen CK_TOP_CB_APLL2_196M>,
+			<&topckgen CK_TOP_APLL2_D4>,
+			<&topckgen CK_TOP_CB_NET1_D4>,
+			<&topckgen CK_TOP_CB_NET1_D5>,
+			<&topckgen CK_TOP_NET1_D5_D2>,
+			<&topckgen CK_TOP_NET1_D5_D4>,
+			<&topckgen CK_TOP_NET1_D8_D2>,
+			<&topckgen CK_TOP_NET1_D8_D4>,
+			<&topckgen CK_TOP_CB_NET2_800M>,
+			<&topckgen CK_TOP_CB_NET2_D4>,
+			<&topckgen CK_TOP_NET2_D4_D2>,
+			<&topckgen CK_TOP_NET2_D3_D2>,
+			<&topckgen CK_TOP_CB_WEDMCU_760M>,
+			<&topckgen CK_TOP_WEDMCU_D5_D2	>,
+			<&topckgen CK_TOP_CB_SGM_325M>,
+			<&topckgen CK_TOP_CB_CKSQ_40M_D2>,
+			<&topckgen CK_TOP_CB_RTC_32K>,
+			<&topckgen CK_TOP_CB_RTC_32P7K>,
+			<&topckgen CK_TOP_NFI1X>,
+			<&topckgen CK_TOP_USB_EQ_RX250M>,
+			<&topckgen CK_TOP_USB_TX250M>,
+			<&topckgen CK_TOP_USB_LN0_CK>,
+			<&topckgen CK_TOP_USB_CDR_CK>,
+			<&topckgen CK_TOP_SPINFI_BCK>,
+			<&topckgen CK_TOP_I2C_BCK>,
+			<&topckgen CK_TOP_PEXTP_TL>,
+			<&topckgen CK_TOP_EMMC_250M>,
+			<&topckgen CK_TOP_EMMC_416M>,
+			<&topckgen CK_TOP_F_26M_ADC_CK>,
+			<&topckgen CK_TOP_SYSAXI>,
+			<&topckgen CK_TOP_NETSYS_WED_MCU>,
+			<&topckgen CK_TOP_NETSYS_2X>,
+			<&topckgen CK_TOP_SGM_325M>,
+			<&topckgen CK_TOP_A1SYS>,
+			<&topckgen CK_TOP_EIP_B>,
+			<&topckgen CK_TOP_F26M>,
+			<&topckgen CK_TOP_AUD_L>,
+			<&topckgen CK_TOP_A_TUNER>,
+			<&topckgen CK_TOP_U2U3_REF>,
+			<&topckgen CK_TOP_U2U3_SYS>,
+			<&topckgen CK_TOP_U2U3_XHCI>,
+			<&topckgen CK_TOP_AP2CNN_HOST>,
+			<&topckgen CK_TOP_NFI1X_SEL>,
+			<&topckgen CK_TOP_SPINFI_SEL>,
+			<&clk40m>,
+			<&clk40m>,
+			<&topckgen CK_TOP_UART_SEL>,
+			<&topckgen CK_TOP_PWM_SEL>,
+			<&topckgen CK_TOP_I2C_SEL>,
+			<&topckgen CK_TOP_PEXTP_TL_SEL>,
+			<&topckgen CK_TOP_EMMC_250M_SEL	>,
+			<&topckgen CK_TOP_EMMC_416M_SEL	>,
+			<&topckgen CK_TOP_F_26M_ADC_SEL>,
+			<&topckgen CK_TOP_DRAMC_SEL>,
+			<&topckgen CK_TOP_DRAMC_MD32_SEL>,
+			<&topckgen CK_TOP_SYSAXI_SEL>,
+			<&topckgen CK_TOP_SYSAPB_SEL>,
+			<&topckgen CK_TOP_ARM_DB_MAIN_SEL>,
+			<&clk40m>,
+			<&topckgen CK_TOP_NETSYS_SEL>,
+			<&topckgen CK_TOP_NETSYS_500M_SEL>,
+			<&topckgen CK_TOP_NETSYS_MCU_SEL>,
+			<&topckgen CK_TOP_NETSYS_2X_SEL>,
+			<&topckgen CK_TOP_SGM_325M_SEL>,
+			<&topckgen CK_TOP_SGM_REG_SEL>,
+			<&clk40m>,
+			<&topckgen CK_TOP_CONN_MCUSYS_SEL>,
+			<&clk40m>,
+			<&topckgen CK_TOP_PCIE_PHY_SEL>,
+			<&topckgen CK_TOP_USB3_PHY_SEL>,
+			<&topckgen CK_TOP_F26M_SEL>,
+			<&clk40m>,
+			<&clk40m>,
+			<&topckgen CK_TOP_U2U3_SEL>,
+			<&topckgen CK_TOP_U2U3_SYS_SEL>,
+			<&topckgen CK_TOP_U2U3_XHCI_SEL>,
+			<&topckgen CK_TOP_DA_U2_REFSEL>,
+			<&topckgen CK_TOP_DA_U2_CK_1P_SEL>,
+			<&topckgen CK_TOP_AP2CNN_HOST_SEL>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>,
+			<&clk40m>;
+
+
+		clock-names = "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11",
+		"12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23",
+		"24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35",
+		"36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47",
+		"48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
+		"60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71",
+		"72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83",
+		"84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95",
+		"96", "97", "98", "99", "100", "101", "102", "103", "104", "105", "106", "107",
+		"108", "109", "110", "111", "112", "113", "114", "115", "116", "117",
+		"118", "119", "120", "121", "122", "123",
+		"124", "125", "126", "127", "128", "129", "130", "131", "132", "133", "134", "135",
+		"136", "137", "138", "139", "140", "141", "142", "143", "144", "145", "146", "147",
+		"148", "149", "150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
+		"160", "161", "162", "163", "164", "165", "166", "167", "168", "169", "170", "171",
+		"172", "173", "174", "175", "176", "177", "178", "179", "180", "181", "182", "183",
+		"184", "185", "186", "187", "188", "189", "190", "191", "192", "193", "194", "195",
+		"196", "197", "198", "199", "200", "201", "202", "203", "204", "205", "206", "207",
+		"208", "209", "210", "211", "212", "213", "214", "215", "216", "217", "218", "219", "220", "221";
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-fpga-ubi.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-fpga-ubi.dts
new file mode 100644
index 0000000..8604918
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-fpga-ubi.dts
@@ -0,0 +1,163 @@
+/dts-v1/;
+#include "mt7986-fpga.dtsi"
+/ {
+	model = "MediaTek MT7986 FPGA (UBI)";
+	compatible = "mediatek,mt7986-fpga,ubi";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		// fpga ddr2: 128MB*2
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	status = "okay";
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <500000>;
+
+		partition@00000 {
+			label = "BL2";
+			reg = <0x00000 0x0060000>;
+		};
+		partition@60000 {
+			label = "u-boot-env";
+			reg = <0x60000 0x0010000>;
+		};
+		partition@70000 {
+			label = "Factory";
+			reg = <0x70000 0x00B0000>;
+		};
+		partition@120000 {
+			label = "BL31";
+			reg = <0x120000 0x0010000>;
+		};
+		partition@130000 {
+			label = "u-boot";
+			reg = <0x130000 0x00D0000>;
+		};
+		partition@200000 {
+			label = "firmware";
+			reg = <0x200000 0xE00000>;
+		};
+	};
+	spi_nand@1 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-max-frequency = <500000>;
+
+		partition@00000 {
+			label = "BL2";
+			reg = <0x00000 0x0100000>;
+		};
+		partition@100000 {
+			label = "u-boot-env";
+			reg = <0x100000 0x0080000>;
+		};
+		partition@180000 {
+			label = "Factory";
+			reg = <0x180000 0x00200000>;
+		};
+		partition@380000 {
+			label = "BL31";
+			reg = <0x380000 0x0080000>;
+		};
+		partition@400000 {
+			label = "u-boot";
+			reg = <0x400000 0x0180000>;
+		};
+		partition@580000 {
+			label = "firmware";
+			reg = <0x580000 0x7a80000>;
+		};
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	/* pin shared with snfi */
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&pio {
+	spi_flash_pins: spi0-pins {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+	};
+
+	snfi_pins: snfi-pins {
+		mux {
+			function = "flash";
+			groups = "snfi";
+		};
+	};
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&snand {
+	pinctrl-names = "default";
+	/* pin shared with spic */
+	pinctrl-0 = <&snfi_pins>;
+	status = "okay";
+	mediatek,quad-spi;
+
+	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 0x0200000>;
+		};
+
+		partition@380000 {
+			label = "FIP";
+			reg = <0x380000 0x0200000>;
+		};
+
+		partition@580000 {
+			label = "ubi";
+			reg = <0x580000 0x4000000>;
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-fpga.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-fpga.dts
new file mode 100644
index 0000000..37f93c0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-fpga.dts
@@ -0,0 +1,163 @@
+/dts-v1/;
+#include "mt7986-fpga.dtsi"
+/ {
+	model = "MediaTek MT7986 FPGA";
+	compatible = "mediatek,mt7986-fpga";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		// fpga ddr2: 128MB*2
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	status = "okay";
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <500000>;
+
+		partition@00000 {
+			label = "BL2";
+			reg = <0x00000 0x0060000>;
+		};
+		partition@60000 {
+			label = "u-boot-env";
+			reg = <0x60000 0x0010000>;
+		};
+		partition@70000 {
+			label = "Factory";
+			reg = <0x70000 0x00B0000>;
+		};
+		partition@120000 {
+			label = "BL31";
+			reg = <0x120000 0x0010000>;
+		};
+		partition@130000 {
+			label = "u-boot";
+			reg = <0x130000 0x00D0000>;
+		};
+		partition@200000 {
+			label = "firmware";
+			reg = <0x200000 0xE00000>;
+		};
+	};
+	spi_nand@1 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-max-frequency = <500000>;
+
+		partition@00000 {
+			label = "BL2";
+			reg = <0x00000 0x0100000>;
+		};
+		partition@100000 {
+			label = "u-boot-env";
+			reg = <0x100000 0x0080000>;
+		};
+		partition@180000 {
+			label = "Factory";
+			reg = <0x180000 0x00200000>;
+		};
+		partition@380000 {
+			label = "BL31";
+			reg = <0x380000 0x0080000>;
+		};
+		partition@400000 {
+			label = "u-boot";
+			reg = <0x400000 0x0180000>;
+		};
+		partition@580000 {
+			label = "firmware";
+			reg = <0x580000 0x7a80000>;
+		};
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	/* pin shared with snfi */
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&pio {
+	spi_flash_pins: spi0-pins {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+	};
+
+	snfi_pins: snfi-pins {
+		mux {
+			function = "flash";
+			groups = "snfi";
+		};
+	};
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&snand {
+	pinctrl-names = "default";
+	/* pin shared with spic */
+	pinctrl-0 = <&snfi_pins>;
+	status = "okay";
+	mediatek,quad-spi;
+
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		partition@0 {
+			label = "BL2";
+			reg = <0x00000 0x0080000>;
+			read-only;
+		};
+
+		partition@80000 {
+			label = "FIP";
+			reg = <0x80000 0x0200000>;
+		};
+
+		partition@280000 {
+			label = "u-boot-env";
+			reg = <0x280000 0x0080000>;
+		};
+
+		partition@300000 {
+			label = "Factory";
+			reg = <0x300000 0x0080000>;
+		};
+
+		partition@380000 {
+			label = "firmware";
+			reg = <0x380000 0x7c00000>;
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-fpga.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-fpga.dtsi
new file mode 100644
index 0000000..12a0234
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-fpga.dtsi
@@ -0,0 +1,427 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Sam.Shih <sam.shih@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/phy/phy.h>
+#include <dt-bindings/reset/ti-syscon.h>
+/ {
+	compatible = "mediatek,mt7986-fpga";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			enable-method = "psci";
+			reg = <0x0>;
+		};
+
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			enable-method = "psci";
+			reg = <0x1>;
+		};
+	};
+
+	wed: wed@15010000 {
+		compatible = "mediatek,wed";
+		wed_num = <2>;
+		/* add this property for wed get the pci slot number. */
+		pci_slot_map = <0>, <1>;
+		reg = <0 0x15010000 0 0x1000>,
+		      <0 0x15011000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	wed2: wed2@15011000 {
+		compatible = "mediatek,wed2";
+		wed_num = <2>;
+		reg = <0 0x15010000 0 0x1000>,
+		      <0 0x15011000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	wdma: wdma@15104800 {
+		compatible = "mediatek,wed-wdma";
+		reg = <0 0x15104800 0 0x400>,
+		      <0 0x15104c00 0 0x400>;
+	};
+
+	ap2woccif: ap2woccif@151A5000 {
+		compatible = "mediatek,ap2woccif";
+		reg = <0 0x151A5000 0 0x1000>,
+		      <0 0x151AD000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>;
+        };
+
+	wocpu0_ilm: wocpu0_ilm@151E0000 {
+		compatible = "mediatek,wocpu0_ilm";
+		reg = <0 0x151E0000 0 0x8000>;
+	};
+
+        wocpu1_ilm: wocpu1_ilm@151F0000 {
+                compatible = "mediatek,wocpu1_ilm";
+                reg = <0 0x151F0000 0 0x8000>;
+        };
+
+	wocpu_dlm: wocpu_dlm@151E8000 {
+		compatible = "mediatek,wocpu_dlm";
+		reg = <0 0x151E8000 0 0x2000>,
+		      <0 0x151F8000 0 0x2000>;
+
+		resets = <&ethsysrst 0>;
+		reset-names = "wocpu_rst";
+	};
+
+	cpu_boot: wocpu_boot@15194000 {
+		compatible = "mediatek,wocpu_boot";
+		reg = <0 0x15194000 0 0x1000>;
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		/* 192 KiB reserved for ARM Trusted Firmware (BL31) */
+		secmon_reserved: secmon@43000000 {
+			reg = <0 0x43000000 0 0x30000>;
+			no-map;
+		};
+
+		wmcpu_emi: wmcpu-reserved@4FC00000 {
+			compatible = "mediatek,wmcpu-reserved";
+			no-map;
+			reg = <0 0x4FC00000 0 0x00100000>;
+		};
+
+		wocpu0_emi: wocpu0_emi@4FD00000 {
+			compatible = "mediatek,wocpu0_emi";
+			no-map;
+			reg = <0 0x4FD00000 0 0x40000>;
+			shared = <0>;
+		};
+
+		wocpu1_emi: wocpu1_emi@4FD80000 {
+			compatible = "mediatek,wocpu1_emi";
+			no-map;
+			reg = <0 0x4FD40000 0 0x40000>;
+			shared = <0>;
+		};
+
+		wocpu_data: wocpu_data@4FE00000 {
+			compatible = "mediatek,wocpu_data";
+			no-map;
+			reg = <0 0x4FD80000 0 0x200000>;
+			shared = <1>;
+		};
+	};
+
+	psci {
+		compatible  = "arm,psci-0.2";
+		method      = "smc";
+	};
+
+	system_clk: dummy13m {
+		compatible = "fixed-clock";
+		clock-frequency = <13000000>;
+		#clock-cells = <0>;
+	};
+
+	rtc_clk: dummy32k {
+		compatible = "fixed-clock";
+		clock-frequency = <32000>;
+		#clock-cells = <0>;
+	};
+
+	uart_clk: dummy12m {
+		compatible = "fixed-clock";
+		clock-frequency = <12000000>;
+		#clock-cells = <0>;
+	};
+
+	gpt_clk: dummy6m {
+		compatible = "fixed-clock";
+		clock-frequency = <6000000>;
+		#clock-cells = <0>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupt-parent = <&gic>;
+		clock-frequency = <12000000>;
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+
+	};
+
+	watchdog: watchdog@1001c000 {
+		compatible = "mediatek,mt7622-wdt",
+			     "mediatek,mt6589-wdt";
+		reg = <0 0x1001c000 0 0x1000>;
+		interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+		#reset-cells = <1>;
+	};
+
+	gic: interrupt-controller@c000000 {
+		compatible = "arm,gic-v3";
+		#interrupt-cells = <3>;
+		interrupt-parent = <&gic>;
+		interrupt-controller;
+		reg = <0 0x0c000000 0 0x40000>,  /* GICD */
+		      <0 0x0c080000 0 0x200000>; /* GICR */
+
+		interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	uart0: serial@11002000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11002000 0 0x400>;
+		interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&uart_clk>;
+		status = "disabled";
+	};
+
+	uart1: serial@11003000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11003000 0 0x400>;
+		interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&uart_clk>;
+		status = "disabled";
+	};
+
+	uart2: serial@11004000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11004000 0 0x400>;
+		interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&uart_clk>;
+		status = "disabled";
+	};
+
+	pcie: pcie@11280000 {
+		compatible = "mediatek,mt7986-pcie";
+		device_type = "pci";
+		reg = <0 0x11280000 0 0x5000>;
+		reg-names = "port0";
+		#address-cells = <3>;
+		#size-cells = <2>;
+		interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+		bus-range = <0x00 0xff>;
+		ranges = <0x82000000 0 0x20000000
+			  0x0 0x20000000 0 0x10000000>;
+
+		pcie0: pcie@0,0 {
+			device_type = "pci";
+			reg = <0x0000 0 0 0 0>;
+			#address-cells = <3>;
+			#size-cells = <2>;
+			ranges;
+			#interrupt-cells = <1>;
+			interrupt-map-mask = <0 0 0 7>;
+			interrupt-map = <0 0 0 1 &pcie_intc0 0>,
+					<0 0 0 2 &pcie_intc0 1>,
+					<0 0 0 3 &pcie_intc0 2>,
+					<0 0 0 4 &pcie_intc0 3>;
+			pcie_intc0: interrupt-controller {
+				interrupt-controller;
+				#address-cells = <0>;
+				#interrupt-cells = <1>;
+			};
+		};
+	};
+
+	pio: pinctrl@1001f000 {
+		compatible = "mediatek,mt7986-pinctrl";
+		reg = <0 0x1001f000 0 0x1000>,
+		      <0 0x11c30000 0 0x1000>,
+                      <0 0x11c40000 0 0x1000>,
+                      <0 0x11e20000 0 0x1000>,
+                      <0 0x11e30000 0 0x1000>,
+                      <0 0x11f00000 0 0x1000>,
+                      <0 0x11f10000 0 0x1000>,
+		      <0 0x1000b000 0 0x1000>;
+		reg-names = "gpio_base", "iocfg_rt_base", "iocfg_rb_base",
+                            "iocfg_lt_base", "iocfg_lb_base", "iocfg_tr_base",
+                            "iocfg_tl_base", "eint";
+		gpio-controller;
+		#gpio-cells = <2>;
+		gpio-ranges = <&pio 0 0 100>;
+		interrupt-controller;
+		interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-parent = <&gic>;
+		#interrupt-cells = <2>;
+	};
+
+        ethsys: syscon@15000000 {
+                #address-cells = <1>;
+                #size-cells = <1>;
+                compatible = "mediatek,mt7986-ethsys",
+                             "syscon";
+                reg = <0 0x15000000 0 0x1000>;
+                #clock-cells = <1>;
+                #reset-cells = <1>;
+
+		ethsysrst: reset-controller {
+			compatible = "ti,syscon-reset";
+			#reset-cells = <1>;
+			ti,reset-bits = <0x34 4 0x34 4 0x34 4 (ASSERT_SET | DEASSERT_CLEAR | STATUS_SET)>;
+		};
+        };
+
+        eth: ethernet@15100000 {
+                compatible = "mediatek,mt7986-eth";
+                reg = <0 0x15100000 0 0x80000>;
+                interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
+                mediatek,ethsys = <&ethsys>;
+                #reset-cells = <1>;
+                #address-cells = <1>;
+                #size-cells = <0>;
+                status = "disabled";
+        };
+
+	snand: snfi@11005000 {
+		compatible = "mediatek,mt7986-snand";
+		reg = <0 0x11005000 0 0x1000>, <0 0x11006000 0 0x1000>;
+		reg-names = "nfi", "ecc";
+		interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>;
+		clock-names = "nfi_clk", "pad_clk", "ecc_clk";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	wed_pcie: wed_pcie@10003000 {
+		compatible = "mediatek,wed_pcie";
+		reg = <0 0x10003000 0 0x10>;
+	};
+
+	wbsys: wbsys@18000000 {
+		compatible = "mediatek,wbsys";
+		reg = <0 0x18000000 0  0x1000000>;
+		interrupts = <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 215 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>;
+		chip_id = <0x7986>;
+	};
+
+	spi0: spi@1100a000 {
+		compatible = "mediatek,ipm-spi";
+		reg = <0 0x1100a000 0 0x100>;
+		interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+		status = "disabled";
+	};
+
+	spi1: spi@1100b000 {
+		compatible = "mediatek,ipm-spi";
+		reg = <0 0x1100b000 0 0x100>;
+		interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+		status = "disabled";
+	};
+
+	auxadc: adc@1100d000 {
+		compatible = "mediatek,mt7986-auxadc",
+			     "mediatek,mt7622-auxadc";
+		reg = <0 0x1100d000 0 0x1000>;
+		clocks = <&system_clk>;
+		clock-names = "main";
+		#io-channel-cells = <1>;
+        };
+
+	consys: consys@10000000 {
+		compatible = "mediatek,mt7986-consys";
+		reg = <0 0x10000000 0 0x8600000>;
+		memory-region = <&wmcpu_emi>;
+	};
+
+	xhci: xhci@11200000 {
+		compatible = "mediatek,mt7986-xhci",
+			     "mediatek,mtk-xhci";
+		reg = <0 0x11200000 0 0x2e00>,
+		      <0 0x11203e00 0 0x0100>;
+		reg-names = "mac", "ippc";
+		interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&u2port0 PHY_TYPE_USB2>;
+		clocks = <&system_clk>,
+		         <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>;
+		clock-names = "sys_ck",
+			      "xhci_ck",
+			      "ref_ck",
+			      "mcu_ck",
+			      "dma_ck";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		mediatek,u3p-dis-msk=<0x01>;
+		status = "okay";
+	};
+
+	usbtphy: usb-phy@11203e00 {
+		compatible = "mediatek,a60810-u2phy",
+			     "mediatek,a60931-u3phy",
+			     "mediatek,a60xxx-usbphy";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+		status = "okay";
+
+		u2port0: usb-phy@11203ed0 {
+			reg = <0 0x11203ed0 0 0x008>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			status = "okay";
+		};
+
+		u3port0: usb-phy@11203ed8 {
+			reg = <0 0x11203ed8 0 0x008>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			status = "disabled";
+		};
+
+		u2port1: usb-phy@11203ee0 {
+			reg = <0 0x11203ee0 0 0x008>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			status = "disabled";
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-snfi-nand-partition.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-snfi-nand-partition.dtsi
new file mode 100644
index 0000000..b88e1c1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-snfi-nand-partition.dtsi
@@ -0,0 +1,44 @@
+/ {
+	nmbm_snfi {
+		compatible = "generic,nmbm";
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		lower-mtd-device = <&snand>;
+		forced-create;
+		empty-page-ecc-protected;
+
+		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>;
+			};
+
+			factory: partition@180000 {
+				label = "Factory";
+				reg = <0x180000 0x0200000>;
+			};
+
+			partition@380000 {
+				label = "FIP";
+				reg = <0x380000 0x0200000>;
+			};
+
+			partition@580000 {
+				label = "ubi";
+				reg = <0x580000 0x4000000>;
+			};
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-spim-nand-partition.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-spim-nand-partition.dtsi
new file mode 100644
index 0000000..4cc7961
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-spim-nand-partition.dtsi
@@ -0,0 +1,43 @@
+/ {
+	nmbm_spim_nand {
+		compatible = "generic,nmbm";
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		lower-mtd-device = <&spi_nand>;
+		forced-create;
+
+		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>;
+			};
+
+			factory: partition@180000 {
+				label = "Factory";
+				reg = <0x180000 0x0200000>;
+			};
+
+			partition@380000 {
+				label = "FIP";
+				reg = <0x380000 0x0200000>;
+			};
+
+			partition@580000 {
+				label = "ubi";
+				reg = <0x580000 0x4000000>;
+			};
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-spim-nor-partition.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-spim-nor-partition.dtsi
new file mode 100644
index 0000000..dcdde5a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986-spim-nor-partition.dtsi
@@ -0,0 +1,30 @@
+&spi0 {
+	spi_nor@0 {
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@00000 {
+				label = "BL2";
+				reg = <0x00000 0x0040000>;
+			};
+			partition@40000 {
+				label = "u-boot-env";
+				reg = <0x40000 0x0010000>;
+			};
+			factory: partition@50000 {
+				label = "Factory";
+				reg = <0x50000 0x00B0000>;
+			};
+			partition@100000 {
+				label = "FIP";
+				reg = <0x100000 0x0080000>;
+			};
+			partition@180000 {
+				label = "firmware";
+				reg = <0x180000 0xE00000>;
+			};
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-emmc-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-emmc-rfb.dts
new file mode 100644
index 0000000..c094abe
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-emmc-rfb.dts
@@ -0,0 +1,296 @@
+/dts-v1/;
+#include "mt7986a.dtsi"
+#include "mt7986a-pinctrl.dtsi"
+/ {
+	model = "MediaTek MT7986a RFB";
+	compatible = "mediatek,mt7986a-emmc-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000 \
+				root=PARTLABEL=rootfs rootwait rootfstype=squashfs,f2fs";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	reg_1p8v: regulator-1p8v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-1.8V";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	sound {
+		compatible = "mediatek,mt7986-wm8960-machine";
+		mediatek,platform = <&afe>;
+		audio-routing = "Headphone", "HP_L",
+				"Headphone", "HP_R",
+				"LINPUT1", "AMIC",
+				"RINPUT1", "AMIC";
+		mediatek,audio-codec = <&wm8960>;
+		status = "okay";
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin &pwm1_pin_g1>;
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+
+	wm8960: wm8960@1a {
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+	};
+};
+
+&auxadc {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@4 {
+					reg = <4>;
+					label = "lan4";
+				};
+
+				port@5 {
+					reg = <5>;
+					label = "lan5";
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins_g2>;
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_pins_default>;
+	pinctrl-1 = <&mmc0_pins_uhs>;
+	bus-width = <8>;
+	max-frequency = <200000000>;
+	cap-mmc-highspeed;
+	mmc-hs200-1_8v;
+	mmc-hs400-1_8v;
+	hs400-ds-delay = <0x14014>;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_1p8v>;
+	non-removable;
+	no-sd;
+	no-sdio;
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
+
+&pio {
+	mmc0_pins_default: mmc0-pins-50-to-61-default {
+		mux {
+			function = "flash";
+			groups = "emmc_51";
+		};
+		conf-cmd-dat {
+			pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2",
+			       "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5",
+			       "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+		conf-clk {
+			pins = "EMMC_CK";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-ds {
+			pins = "EMMC_DSL";
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-rst {
+			pins = "EMMC_RSTB";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+
+	mmc0_pins_uhs: mmc0-pins-50-to-61-uhs {
+		mux {
+			function = "flash";
+			groups = "emmc_51";
+		};
+		conf-cmd-dat {
+			pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2",
+			       "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5",
+			       "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+		conf-clk {
+			pins = "EMMC_CK";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-ds {
+			pins = "EMMC_DSL";
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-rst {
+			pins = "EMMC_RSTB";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-gsw-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-gsw-spim-nand-rfb.dts
new file mode 100644
index 0000000..21d5dc8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-gsw-spim-nand-rfb.dts
@@ -0,0 +1,226 @@
+/dts-v1/;
+#include "mt7986a.dtsi"
+#include "mt7986a-pinctrl.dtsi"
+#include "mt7986-spim-nand-partition.dtsi"
+/ {
+	model = "MediaTek MT7986b gsw RFB";
+	compatible = "mediatek,mt7986a-2500wan-gsw-spim-snand-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	gsw: gsw@0 {
+		compatible = "mediatek,mt753x";
+		mediatek,ethsys = <&ethsys>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	sound {
+		compatible = "mediatek,mt7986-wm8960-machine";
+		mediatek,platform = <&afe>;
+		audio-routing = "Headphone", "HP_L",
+				"Headphone", "HP_R",
+				"LINPUT1", "AMIC",
+				"RINPUT1", "AMIC";
+		mediatek,audio-codec = <&wm8960>;
+		status = "okay";
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin &pwm1_pin_g1>;
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+
+	wm8960: wm8960@1a {
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+	};
+};
+
+&auxadc {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+	};
+};
+
+&gsw {
+	mediatek,mdio = <&mdio>;
+	mediatek,portmap = "lllll";
+	mediatek,mdio_master_pinmux = <1>;
+	reset-gpios = <&pio 5 0>;
+	interrupt-parent = <&pio>;
+	interrupts = <66 IRQ_TYPE_LEVEL_HIGH>;
+	status = "okay";
+
+	port5: port@5 {
+		compatible = "mediatek,mt753x-port";
+		reg = <5>;
+		phy-mode = "sgmii";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+		};
+
+	};
+
+	port6: port@6 {
+		compatible = "mediatek,mt753x-port";
+		mediatek,ssc-on;
+		reg = <6>;
+		phy-mode = "sgmii";
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	cs-gpios = <0>, <0>;
+	status = "okay";
+
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <20000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+
+	spi_nand: spi_nand@1 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-max-frequency = <20000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins_g2>;
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
+
+&pio {
+	spi_flash_pins: spi-flash-pins-33-to-38 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-sd-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-sd-rfb.dts
new file mode 100644
index 0000000..2a1d0dc
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-sd-rfb.dts
@@ -0,0 +1,304 @@
+/dts-v1/;
+#include "mt7986a.dtsi"
+#include "mt7986a-pinctrl.dtsi"
+/ {
+	model = "MediaTek MT7986a RFB";
+	compatible = "mediatek,mt7986a-2500wan-sd-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+			earlycon=uart8250,mmio32,0x11002000 \
+			root=PARTLABEL=rootfs rootwait rootfstype=squashfs,f2fs";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	sound {
+		compatible = "mediatek,mt7986-wm8960-machine";
+		mediatek,platform = <&afe>;
+		audio-routing = "Headphone", "HP_L",
+				"Headphone", "HP_R",
+				"LINPUT1", "AMIC",
+				"RINPUT1", "AMIC";
+		mediatek,audio-codec = <&wm8960>;
+		status = "okay";
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin &pwm1_pin_g1>;
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+
+	wm8960: wm8960@1a {
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+	};
+};
+
+&auxadc {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@4 {
+					reg = <4>;
+					label = "lan4";
+				};
+
+				port@5 {
+					reg = <5>;
+					label = "lan5";
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_pins_default>;
+	pinctrl-1 = <&mmc0_pins_uhs>;
+	bus-width = <4>;
+	max-frequency = <52000000>;
+	cap-sd-highspeed;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_3p3v>;
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&pio {
+	mmc0_pins_default: mmc0-pins-50-to-61-default {
+		mux {
+			function = "flash";
+			groups = "emmc_51";
+		};
+		conf-cmd-dat {
+			pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2",
+			       "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5",
+			       "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+		conf-clk {
+			pins = "EMMC_CK";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-ds {
+			pins = "EMMC_DSL";
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-rst {
+			pins = "EMMC_RSTB";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+
+	mmc0_pins_uhs: mmc0-pins-50-to-61-uhs {
+		mux {
+			function = "flash";
+			groups = "emmc_51";
+		};
+		conf-cmd-dat {
+			pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2",
+			       "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5",
+			       "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+		conf-clk {
+			pins = "EMMC_CK";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-ds {
+			pins = "EMMC_DSL";
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-rst {
+			pins = "EMMC_RSTB";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+
+	wf_2g_5g_pins: wf_2g_5g-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_2g", "wf_5g";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+
+	wf_dbdc_pins: wf_dbdc-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_dbdc";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nand-rfb.dts
new file mode 100644
index 0000000..5504369
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nand-rfb.dts
@@ -0,0 +1,283 @@
+/dts-v1/;
+#include "mt7986a.dtsi"
+#include "mt7986a-pinctrl.dtsi"
+#include "mt7986-spim-nand-partition.dtsi"
+/ {
+	model = "MediaTek MT7986a RFB";
+	compatible = "mediatek,mt7986a-2500wan-spim-snand-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	sound {
+		compatible = "mediatek,mt7986-wm8960-machine";
+		mediatek,platform = <&afe>;
+		audio-routing = "Headphone", "HP_L",
+				"Headphone", "HP_R",
+				"LINPUT1", "AMIC",
+				"RINPUT1", "AMIC";
+		mediatek,audio-codec = <&wm8960>;
+		status = "okay";
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin &pwm1_pin_g1>;
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+
+	wm8960: wm8960@1a {
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+	};
+};
+
+&auxadc {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@4 {
+					reg = <4>;
+					label = "lan4";
+				};
+
+				port@5 {
+					reg = <5>;
+					label = "lan5";
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	cs-gpios = <0>, <0>;
+	status = "okay";
+
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <20000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+
+	spi_nand: spi_nand@1 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-max-frequency = <20000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins_g2>;
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+	pinctrl-names = "default", "dbdc";
+	pinctrl-0 = <&wf_2g_5g_pins>;
+	pinctrl-1 = <&wf_dbdc_pins>;
+};
+
+&pio {
+	spi_flash_pins: spi-flash-pins-33-to-38 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+	};
+
+	wf_2g_5g_pins: wf_2g_5g-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_2g", "wf_5g";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+
+	wf_dbdc_pins: wf_dbdc-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_dbdc";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nor-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nor-rfb.dts
new file mode 100644
index 0000000..c1f22d1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nor-rfb.dts
@@ -0,0 +1,235 @@
+/dts-v1/;
+#include "mt7986a.dtsi"
+#include "mt7986a-pinctrl.dtsi"
+#include "mt7986-spim-nor-partition.dtsi"
+/ {
+	model = "MediaTek MT7986a RFB";
+	compatible = "mediatek,mt7986a-2500wan-nor-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	sound {
+		compatible = "mediatek,mt7986-wm8960-machine";
+		mediatek,platform = <&afe>;
+		audio-routing = "Headphone", "HP_L",
+				"Headphone", "HP_R",
+				"LINPUT1", "AMIC",
+				"RINPUT1", "AMIC";
+		mediatek,audio-codec = <&wm8960>;
+		status = "okay";
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin &pwm1_pin_g1>;
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+
+	wm8960: wm8960@1a {
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+	};
+};
+
+&auxadc {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@4 {
+					reg = <4>;
+					label = "lan4";
+				};
+
+				port@5 {
+					reg = <5>;
+					label = "lan5";
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	cs-gpios = <0>, <0>;
+	status = "okay";
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins_g2>;
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
+
+&pio {
+	spi_flash_pins: spi-flash-pins-33-to-38 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-emmc-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-emmc-rfb.dts
new file mode 100644
index 0000000..b4ae0b0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-emmc-rfb.dts
@@ -0,0 +1,297 @@
+/dts-v1/;
+#include "mt7986a.dtsi"
+#include "mt7986a-pinctrl.dtsi"
+/ {
+	model = "MediaTek MT7986a RFB";
+	compatible = "mediatek,mt7986a-emmc-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000 \
+				root=PARTLABEL=rootfs rootwait rootfstype=squashfs,f2fs";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	reg_1p8v: regulator-1p8v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-1.8V";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	sound_wm8960 {
+		compatible = "mediatek,mt79xx-wm8960-machine";
+		mediatek,platform = <&afe>;
+		audio-routing = "Headphone", "HP_L",
+				"Headphone", "HP_R",
+				"LINPUT1", "AMIC",
+				"RINPUT1", "AMIC";
+		mediatek,audio-codec = <&wm8960>;
+		status = "okay";
+	};
+
+	sound_si3218x {
+		compatible = "mediatek,mt79xx-si3218x-machine";
+		mediatek,platform = <&afe>;
+		mediatek,ext-codec = <&proslic_spi>;
+		status = "okay";
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin &pwm1_pin_g1>;
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+
+	wm8960: wm8960@1a {
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+	};
+};
+
+&auxadc {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins_g2>;
+	status = "okay";
+
+	proslic_spi: proslic_spi@0 {
+		compatible = "silabs,proslic_spi";
+		reg = <0>;
+		spi-max-frequency = <10000000>;
+		spi-cpha = <1>;
+		spi-cpol = <1>;
+		channel_count = <1>;
+		debug_level = <4>;       /* 1 = TRC, 2 = DBG, 4 = ERR */
+		reset_gpio = <&pio 7 0>;
+		ig,enable-spi = <1>;     /* 1: Enable, 0: Disable */
+	};
+};
+
+&mmc0 {
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_pins_default>;
+	pinctrl-1 = <&mmc0_pins_uhs>;
+	bus-width = <8>;
+	max-frequency = <200000000>;
+	cap-mmc-highspeed;
+	mmc-hs200-1_8v;
+	mmc-hs400-1_8v;
+	hs400-ds-delay = <0x14014>;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_1p8v>;
+	non-removable;
+	no-sd;
+	no-sdio;
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	status = "okay";
+};
+
+&pio {
+	mmc0_pins_default: mmc0-pins-50-to-61-default {
+		mux {
+			function = "flash";
+			groups = "emmc_51";
+		};
+		conf-cmd-dat {
+			pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2",
+			       "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5",
+			       "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+		conf-clk {
+			pins = "EMMC_CK";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-ds {
+			pins = "EMMC_DSL";
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-rst {
+			pins = "EMMC_RSTB";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+
+	mmc0_pins_uhs: mmc0-pins-50-to-61-uhs {
+		mux {
+			function = "flash";
+			groups = "emmc_51";
+		};
+		conf-cmd-dat {
+			pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2",
+			       "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5",
+			       "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+		conf-clk {
+			pins = "EMMC_CK";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-ds {
+			pins = "EMMC_DSL";
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-rst {
+			pins = "EMMC_RSTB";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-pinctrl.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-pinctrl.dtsi
new file mode 100644
index 0000000..42619a1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-pinctrl.dtsi
@@ -0,0 +1,141 @@
+&pio {
+	wifi_led_pins: wifi_led-pins-1-2 {
+		mux {
+			function = "led";
+			groups = "wifi_led";
+		};
+	};
+
+	i2c_pins: i2c-pins-3-4 {
+		mux {
+			function = "i2c";
+			groups = "i2c";
+		};
+	};
+
+	uart1_pins_g0: uart1-pins-7-to-10 {
+		mux {
+			function = "uart";
+			groups = "uart1_0";
+		};
+	};
+
+	pcie0_pins: pcie0-pins-9-10-41 {
+		mux {
+			function = "pcie";
+			groups = "pcie_clk", "pcie_wake", "pcie_pereset";
+		};
+	};
+
+	jtag_pins: jtag-pins-11-to-14 {
+		mux {
+			function = "jtag";
+			groups = "jtag";
+		};
+	};
+
+	spic_pins_g0: spic-pins-11-to-14 {
+		mux {
+			function = "spi";
+			groups = "spi1_0";
+		};
+	};
+
+	pwm1_pin_g0: pwm1-pin-20 {
+		mux {
+			function = "pwm";
+			groups = "pwm1_1";
+		};
+	};
+
+	pwm0_pin: pwm0-pin-21 {
+		mux {
+			function = "pwm";
+			groups = "pwm0";
+		};
+	};
+
+	pwm1_pin_g1: pwm1-pin-22 {
+		mux {
+			function = "pwm";
+			groups = "pwm1_0";
+		};
+	};
+
+	spic_pins_g1: spic-pins-23-to-26 {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+
+	uart1_pins_g1: uart1-pins-23-to-26 {
+		mux {
+			function = "uart";
+			groups = "uart1_1";
+		};
+	};
+
+	spic_pins_g2: spic-pins-29-to-32 {
+		mux {
+			function = "spi";
+			groups = "spi1_2";
+		};
+	};
+
+	uart1_pins_g2: uart1-pins-29-to-32 {
+		mux {
+			function = "uart";
+			groups = "uart1_2";
+		};
+	};
+
+	uart2_pins_g0: uart1-pins-29-to-32 {
+		mux {
+			function = "uart";
+			groups = "uart1_2";
+		};
+	};
+
+	uart2_pins_g1: uart1-pins-23-to-36 {
+		mux {
+			function = "uart";
+			groups = "uart2_1";
+		};
+	};
+
+	spic_pins_g3: spic-pins-33-to-36 {
+		mux {
+			function = "spi";
+			groups = "spi1_3";
+		};
+	};
+
+	uart1_pins_g3: uart1-pins-35-to-38 {
+		mux {
+			function = "uart";
+			groups = "uart1_3_rx_tx", "uart1_3_cts_rts";
+		};
+	};
+
+	uart1_pins: uart1-pins-42-to-45 {
+		mux {
+			function = "uart";
+			groups = "uart1";
+		};
+	};
+
+	uart2_pins: uart1-pins-46-to-49 {
+		mux {
+			function = "uart";
+			groups = "uart2";
+		};
+	};
+
+	pcm_pins: pcm-pins-62-to-65 {
+		mux {
+			function = "pcm";
+			groups = "pcm";
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-snfi-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-snfi-nand-rfb.dts
new file mode 100644
index 0000000..3164038
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-snfi-nand-rfb.dts
@@ -0,0 +1,239 @@
+/dts-v1/;
+#include "mt7986a.dtsi"
+#include "mt7986a-pinctrl.dtsi"
+#include "mt7986-snfi-nand-partition.dtsi"
+/ {
+	model = "MediaTek MT7986a RFB";
+	compatible = "mediatek,mt7986a-snfi-snand-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	sound_wm8960 {
+		compatible = "mediatek,mt79xx-wm8960-machine";
+		mediatek,platform = <&afe>;
+		audio-routing = "Headphone", "HP_L",
+				"Headphone", "HP_R",
+				"LINPUT1", "AMIC",
+				"RINPUT1", "AMIC";
+		mediatek,audio-codec = <&wm8960>;
+		status = "okay";
+	};
+
+	sound_si3218x {
+		compatible = "mediatek,mt79xx-si3218x-machine";
+		mediatek,platform = <&afe>;
+		mediatek,ext-codec = <&proslic_spi>;
+		status = "okay";
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin &pwm1_pin_g1>;
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+
+	wm8960: wm8960@1a {
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+	};
+};
+
+&auxadc {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&snand {
+	pinctrl-names = "default";
+	pinctrl-0 = <&snfi_pins>;
+	mediatek,quad-spi;
+	status = "okay";
+
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins_g2>;
+	status = "okay";
+
+	proslic_spi: proslic_spi@0 {
+		compatible = "silabs,proslic_spi";
+		reg = <0>;
+		spi-max-frequency = <10000000>;
+		spi-cpha = <1>;
+		spi-cpol = <1>;
+		channel_count = <1>;
+		debug_level = <4>;       /* 1 = TRC, 2 = DBG, 4 = ERR */
+		reset_gpio = <&pio 7 0>;
+		ig,enable-spi = <1>;     /* 1: Enable, 0: Disable */
+	};
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
+
+&pio {
+	snfi_pins: snfi-pins-23-to-28 {
+		mux {
+			function = "flash";
+			groups = "snfi";
+		};
+		conf-clk {
+			pins = "SPI0_CLK";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+		conf-pu {
+			pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI0_MOSI", "SPI0_MISO";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nand-rfb.dts
new file mode 100644
index 0000000..203bc4a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nand-rfb.dts
@@ -0,0 +1,285 @@
+/dts-v1/;
+#include "mt7986a.dtsi"
+#include "mt7986a-pinctrl.dtsi"
+#include "mt7986-spim-nand-partition.dtsi"
+/ {
+	model = "MediaTek MT7986a RFB";
+	compatible = "mediatek,mt7986a-spim-snand-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	sound_wm8960 {
+		compatible = "mediatek,mt79xx-wm8960-machine";
+		mediatek,platform = <&afe>;
+		audio-routing = "Headphone", "HP_L",
+				"Headphone", "HP_R",
+				"LINPUT1", "AMIC",
+				"RINPUT1", "AMIC";
+		mediatek,audio-codec = <&wm8960>;
+		status = "okay";
+	};
+
+	sound_si3218x {
+		compatible = "mediatek,mt79xx-si3218x-machine";
+		mediatek,platform = <&afe>;
+		mediatek,ext-codec = <&proslic_spi>;
+		status = "okay";
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin &pwm1_pin_g1>;
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+
+	wm8960: wm8960@1a {
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+	};
+};
+
+&auxadc {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	cs-gpios = <0>, <0>;
+	status = "okay";
+
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+
+	spi_nand: spi_nand@1 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-max-frequency = <52000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins_g2>;
+	status = "okay";
+
+	proslic_spi: proslic_spi@0 {
+		compatible = "silabs,proslic_spi";
+		reg = <0>;
+		spi-max-frequency = <10000000>;
+		spi-cpha = <1>;
+		spi-cpol = <1>;
+		channel_count = <1>;
+		debug_level = <4>;       /* 1 = TRC, 2 = DBG, 4 = ERR */
+		reset_gpio = <&pio 7 0>;
+		ig,enable-spi = <1>;     /* 1: Enable, 0: Disable */
+	};
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+	pinctrl-names = "default", "dbdc";
+	pinctrl-0 = <&wf_2g_5g_pins>;
+	pinctrl-1 = <&wf_dbdc_pins>;
+};
+
+&pio {
+	spi_flash_pins: spi-flash-pins-33-to-38 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+	};
+
+	wf_2g_5g_pins: wf_2g_5g-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_2g", "wf_5g";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+
+	wf_dbdc_pins: wf_dbdc-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_dbdc";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nor-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nor-rfb.dts
new file mode 100644
index 0000000..275d48d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nor-rfb.dts
@@ -0,0 +1,238 @@
+/dts-v1/;
+#include "mt7986a.dtsi"
+#include "mt7986a-pinctrl.dtsi"
+#include "mt7986-spim-nor-partition.dtsi"
+/ {
+	model = "MediaTek MT7986a RFB";
+	compatible = "mediatek,mt7986a-nor-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	sound_wm8960 {
+		compatible = "mediatek,mt79xx-wm8960-machine";
+		mediatek,platform = <&afe>;
+		audio-routing = "Headphone", "HP_L",
+				"Headphone", "HP_R",
+				"LINPUT1", "AMIC",
+				"RINPUT1", "AMIC";
+		mediatek,audio-codec = <&wm8960>;
+		status = "okay";
+	};
+
+	sound_si3218x {
+		compatible = "mediatek,mt79xx-si3218x-machine";
+		mediatek,platform = <&afe>;
+		mediatek,ext-codec = <&proslic_spi>;
+		status = "okay";
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pin &pwm1_pin_g1>;
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+
+	wm8960: wm8960@1a {
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+	};
+};
+
+&auxadc {
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	cs-gpios = <0>, <0>;
+	status = "okay";
+
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins_g2>;
+	status = "okay";
+
+	proslic_spi: proslic_spi@0 {
+		compatible = "silabs,proslic_spi";
+		reg = <0>;
+		spi-max-frequency = <10000000>;
+		spi-cpha = <1>;
+		spi-cpol = <1>;
+		channel_count = <1>;
+		debug_level = <4>;       /* 1 = TRC, 2 = DBG, 4 = ERR */
+		reset_gpio = <&pio 7 0>;
+		ig,enable-spi = <1>;     /* 1: Enable, 0: Disable */
+	};
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
+
+&pio {
+	spi_flash_pins: spi-flash-pins-33-to-38 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
new file mode 100644
index 0000000..2b72991
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
@@ -0,0 +1,808 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Sam.Shih <sam.shih@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/phy/phy.h>
+#include <dt-bindings/reset/ti-syscon.h>
+#include <dt-bindings/clock/mt7986-clk.h>
+#include <dt-bindings/thermal/thermal.h>
+#include <dt-bindings/pinctrl/mt65xx.h>
+#include <dt-bindings/reset/mt7986-resets.h>
+
+/ {
+	compatible = "mediatek,mt7986a-rfb";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu0: cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			enable-method = "psci";
+			reg = <0x0>;
+		};
+
+		cpu1: cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			enable-method = "psci";
+			reg = <0x1>;
+		};
+
+		cpu2: cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			enable-method = "psci";
+			reg = <0x2>;
+		};
+
+		cpu3: cpu@3 {
+			device_type = "cpu";
+			enable-method = "psci";
+			compatible = "arm,cortex-a53";
+			reg = <0x3>;
+		};
+	};
+
+	wed: wed@15010000 {
+		compatible = "mediatek,wed";
+		wed_num = <2>;
+		/* add this property for wed get the pci slot number. */
+		pci_slot_map = <0>, <1>;
+		reg = <0 0x15010000 0 0x1000>,
+		      <0 0x15011000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	wed2: wed2@15011000 {
+		compatible = "mediatek,wed2";
+		wed_num = <2>;
+		reg = <0 0x15010000 0 0x1000>,
+		      <0 0x15011000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	wdma: wdma@15104800 {
+		compatible = "mediatek,wed-wdma";
+		reg = <0 0x15104800 0 0x400>,
+		      <0 0x15104c00 0 0x400>;
+	};
+
+	ap2woccif: ap2woccif@151A5000 {
+		compatible = "mediatek,ap2woccif";
+		reg = <0 0x151A5000 0 0x1000>,
+		      <0 0x151AD000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>;
+        };
+
+	wocpu0_ilm: wocpu0_ilm@151E0000 {
+		compatible = "mediatek,wocpu0_ilm";
+		reg = <0 0x151E0000 0 0x8000>;
+	};
+
+        wocpu1_ilm: wocpu1_ilm@151F0000 {
+                compatible = "mediatek,wocpu1_ilm";
+                reg = <0 0x151F0000 0 0x8000>;
+        };
+
+	wocpu_dlm: wocpu_dlm@151E8000 {
+		compatible = "mediatek,wocpu_dlm";
+		reg = <0 0x151E8000 0 0x2000>,
+		      <0 0x151F8000 0 0x2000>;
+
+		resets = <&ethsysrst 0>;
+		reset-names = "wocpu_rst";
+	};
+
+	cpu_boot: wocpu_boot@15194000 {
+		compatible = "mediatek,wocpu_boot";
+		reg = <0 0x15194000 0 0x1000>;
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		/* 192 KiB reserved for ARM Trusted Firmware (BL31) */
+		secmon_reserved: secmon@43000000 {
+			reg = <0 0x43000000 0 0x30000>;
+			no-map;
+		};
+
+		wmcpu_emi: wmcpu-reserved@4FC00000 {
+			compatible = "mediatek,wmcpu-reserved";
+			no-map;
+			reg = <0 0x4FC00000 0 0x00100000>;
+		};
+
+		wocpu0_emi: wocpu0_emi@4FD00000 {
+			compatible = "mediatek,wocpu0_emi";
+			no-map;
+			reg = <0 0x4FD00000 0 0x40000>;
+			shared = <0>;
+		};
+
+		wocpu1_emi: wocpu1_emi@4FD40000 {
+			compatible = "mediatek,wocpu1_emi";
+			no-map;
+			reg = <0 0x4FD40000 0 0x40000>;
+			shared = <0>;
+		};
+
+		wocpu_data: wocpu_data@4FD80000 {
+			compatible = "mediatek,wocpu_data";
+			no-map;
+			reg = <0 0x4FD80000 0 0x240000>;
+			shared = <1>;
+		};
+	};
+
+	psci {
+		compatible  = "arm,psci-0.2";
+		method      = "smc";
+	};
+
+	clk40m: oscillator@0 {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <40000000>;
+		clock-output-names = "clkxtal";
+	};
+
+	system_clk: dummy_system_clk {
+		compatible = "fixed-clock";
+		clock-frequency = <40000000>;
+		#clock-cells = <0>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupt-parent = <&gic>;
+		clock-frequency = <13000000>;
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	infracfg_ao: infracfg_ao@10001000 {
+		compatible = "mediatek,mt7986-infracfg_ao", "syscon";
+		reg = <0 0x10001000 0 0x68>;
+		#clock-cells = <1>;
+	};
+
+	infracfg: infracfg@10001040 {
+		compatible = "mediatek,mt7986-infracfg", "syscon";
+		reg = <0 0x1000106c 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	topckgen: topckgen@1001B000 {
+		compatible = "mediatek,mt7986-topckgen", "syscon";
+		reg = <0 0x1001B000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	apmixedsys: apmixedsys@1001E000 {
+		compatible = "mediatek,mt7986-apmixedsys", "syscon";
+		reg = <0 0x1001E000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	watchdog: watchdog@1001c000 {
+		compatible = "mediatek,mt7986-wdt";
+		reg = <0 0x1001c000 0 0x1000>;
+		interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+		#reset-cells = <1>;
+	};
+
+	gic: interrupt-controller@c000000 {
+		compatible = "arm,gic-v3";
+		#interrupt-cells = <3>;
+		interrupt-parent = <&gic>;
+		interrupt-controller;
+		reg = <0 0x0c000000 0 0x40000>,  /* GICD */
+		      <0 0x0c080000 0 0x200000>; /* GICR */
+
+		interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	pwm: pwm@10048000 {
+		compatible = "mediatek,mt7986-pwm";
+		reg = <0 0x10048000 0 0x1000>;
+		#clock-cells = <1>;
+		#pwm-cells = <2>;
+		interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg CK_INFRA_PWM>,
+			 <&infracfg_ao CK_INFRA_PWM_BSEL>,
+			 <&infracfg_ao CK_INFRA_PWM1_CK>,
+			 <&infracfg_ao CK_INFRA_PWM2_CK>;
+		assigned-clocks = <&topckgen CK_TOP_PWM_SEL>,
+				  <&infracfg_ao CK_INFRA_PWM_BSEL>,
+				  <&infracfg_ao CK_INFRA_PWM1_SEL>,
+				  <&infracfg_ao CK_INFRA_PWM2_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_M_D4>,
+					 <&infracfg CK_INFRA_PWM>,
+					 <&infracfg CK_INFRA_PWM>,
+					 <&infracfg CK_INFRA_PWM>;
+		clock-names = "top", "main", "pwm1", "pwm2";
+		status = "disabled";
+	};
+
+	uart0: serial@11002000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11002000 0 0x400>;
+		interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_UART0_CK>;
+		assigned-clocks = <&topckgen CK_TOP_UART_SEL>,
+				  <&infracfg_ao CK_INFRA_UART0_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_CKSQ_40M>,
+					 <&infracfg CK_INFRA_UART>;
+		status = "disabled";
+	};
+
+	uart1: serial@11003000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11003000 0 0x400>;
+		interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_UART1_CK>;
+		assigned-clocks = <&infracfg_ao CK_INFRA_UART1_SEL>;
+		assigned-clock-parents = <&infracfg CK_INFRA_CK_F26M>;
+		status = "disabled";
+	};
+
+	uart2: serial@11004000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11004000 0 0x400>;
+		interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_UART2_CK>;
+		assigned-clocks = <&infracfg_ao CK_INFRA_UART2_SEL>;
+		assigned-clock-parents = <&infracfg CK_INFRA_CK_F26M>;
+		status = "disabled";
+	};
+
+        i2c0: i2c@11008000 {
+                compatible = "mediatek,mt7986-i2c";
+                reg = <0 0x11008000 0 0x90>,
+                      <0 0x10217080 0 0x80>;
+                interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+                clock-div = <5>;
+                clocks = <&infracfg_ao CK_INFRA_I2CO_CK>,
+                         <&infracfg_ao CK_INFRA_AP_DMA_CK>;
+                clock-names = "main", "dma";
+                #address-cells = <1>;
+                #size-cells = <0>;
+                status = "disabled";
+        };
+
+	thermal-zones {
+		cpu_thermal: cpu-thermal {
+			polling-delay-passive = <1000>;
+			polling-delay = <1000>;
+			thermal-sensors = <&thermal 0>;
+		};
+	};
+
+	thermal: thermal@1100c800 {
+		#thermal-sensor-cells = <1>;
+		compatible = "mediatek,mt7986-thermal";
+		reg = <0 0x1100c800 0 0x800>;
+		interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_THERM_CK>,
+			 <&infracfg_ao CK_INFRA_ADC_26M_CK>,
+			 <&infracfg_ao CK_INFRA_ADC_FRC_CK>;
+		clock-names = "therm", "auxadc", "adc_32k";
+		mediatek,auxadc = <&auxadc>;
+		mediatek,apmixedsys = <&apmixedsys>;
+		nvmem-cells = <&thermal_calibration>;
+		nvmem-cell-names = "calibration-data";
+	};
+
+	pcie0: pcie@11280000 {
+		compatible = "mediatek,mt7986-pcie";
+		reg = <0 0x11280000 0 0x5000>;
+		reg-names = "pcie-mac";
+		#address-cells = <3>;
+		#size-cells = <2>;
+		interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+		bus-range = <0x00 0xff>;
+		ranges = <0x82000000 0 0x20000000
+			  0x0 0x20000000 0 0x10000000>;
+		status = "disabled";
+
+		clocks = <&infracfg_ao CK_INFRA_PCIE_SEL>,
+			 <&infracfg_ao CK_INFRA_IPCIE_CK>,
+			 <&infracfg_ao CK_INFRA_IPCIE_PIPE_CK>,
+			 <&infracfg_ao CK_INFRA_IPCIER_CK>,
+			 <&infracfg_ao CK_INFRA_IPCIEB_CK>;
+
+		phys = <&pcieport PHY_TYPE_PCIE>;
+		phy-names = "pcie-phy";
+
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 7>;
+		interrupt-map = <0 0 0 1 &pcie_intc0 0>,
+				<0 0 0 2 &pcie_intc0 1>,
+				<0 0 0 3 &pcie_intc0 2>,
+				<0 0 0 4 &pcie_intc0 3>;
+		pcie_intc0: interrupt-controller {
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <1>;
+		};
+	};
+
+	crypto: crypto@10320000 {
+		compatible = "inside-secure,safexcel-eip97";
+		reg = <0 0x10320000 0 0x40000>;
+		interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "ring0", "ring1", "ring2", "ring3";
+		clocks = <&infracfg_ao CK_INFRA_EIP97_CK>;
+		clock-names = "infra_eip97_ck";
+		assigned-clocks = <&topckgen CK_TOP_EIP_B_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_NET2_800M>;
+	};
+
+	pio: pinctrl@1001f000 {
+		compatible = "mediatek,mt7986-pinctrl";
+		reg = <0 0x1001f000 0 0x1000>,
+		      <0 0x11c30000 0 0x1000>,
+		      <0 0x11c40000 0 0x1000>,
+		      <0 0x11e20000 0 0x1000>,
+		      <0 0x11e30000 0 0x1000>,
+		      <0 0x11f00000 0 0x1000>,
+		      <0 0x11f10000 0 0x1000>,
+		      <0 0x1000b000 0 0x1000>;
+		reg-names = "gpio_base", "iocfg_rt_base", "iocfg_rb_base",
+			    "iocfg_lt_base", "iocfg_lb_base", "iocfg_tr_base",
+			    "iocfg_tl_base", "eint";
+		gpio-controller;
+		#gpio-cells = <2>;
+		gpio-ranges = <&pio 0 0 100>;
+		interrupt-controller;
+		interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-parent = <&gic>;
+		#interrupt-cells = <2>;
+	};
+
+	ethsys: syscon@15000000 {
+                #address-cells = <1>;
+                #size-cells = <1>;
+                compatible = "mediatek,mt7986-ethsys_ck",
+                             "syscon";
+                reg = <0 0x15000000 0 0x1000>;
+                #clock-cells = <1>;
+                #reset-cells = <1>;
+
+		ethsysrst: reset-controller {
+			compatible = "ti,syscon-reset";
+			#reset-cells = <1>;
+			ti,reset-bits = <0x34 4 0x34 4 0x34 4 (ASSERT_SET | DEASSERT_CLEAR | STATUS_SET)>;
+		};
+        };
+
+        eth: ethernet@15100000 {
+                compatible = "mediatek,mt7986-eth";
+                reg = <0 0x15100000 0 0x80000>;
+                interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
+                clocks = <&ethsys CK_ETH_FE_EN>,
+                         <&ethsys CK_ETH_GP2_EN>,
+                         <&ethsys CK_ETH_GP1_EN>,
+                         <&ethsys CK_ETH_WOCPU1_EN>,
+                         <&ethsys CK_ETH_WOCPU0_EN>,
+                         <&sgmiisys0 CK_SGM0_TX_EN>,
+                         <&sgmiisys0 CK_SGM0_RX_EN>,
+                         <&sgmiisys0 CK_SGM0_CK0_EN>,
+                         <&sgmiisys0 CK_SGM0_CDR_CK0_EN>,
+                         <&sgmiisys1 CK_SGM1_TX_EN>,
+                         <&sgmiisys1 CK_SGM1_RX_EN>,
+                         <&sgmiisys1 CK_SGM1_CK1_EN>,
+                         <&sgmiisys1 CK_SGM1_CDR_CK1_EN>;
+                clock-names = "fe", "gp2", "gp1", "wocpu1", "wocpu0",
+                         "sgmii_tx250m", "sgmii_rx250m",
+                         "sgmii_cdr_ref", "sgmii_cdr_fb",
+                         "sgmii2_tx250m", "sgmii2_rx250m",
+                         "sgmii2_cdr_ref", "sgmii2_cdr_fb";
+		assigned-clocks = <&topckgen CK_TOP_NETSYS_2X_SEL>,
+				  <&topckgen CK_TOP_SGM_325M_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_NET2_800M>,
+					 <&topckgen CK_TOP_CB_SGM_325M>;
+                mediatek,ethsys = <&ethsys>;
+		mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
+                #reset-cells = <1>;
+                #address-cells = <1>;
+                #size-cells = <0>;
+                status = "disabled";
+        };
+
+	hnat: hnat@15000000 {
+		compatible = "mediatek,mtk-hnat_v4";
+		reg = <0 0x15100000 0 0x80000>;
+		resets = <&ethsys 0>;
+		reset-names = "mtketh";
+		status = "disabled";
+	};
+
+	sgmiisys0: syscon@10060000 {
+		compatible = "mediatek,mt7986-sgmiisys",
+				"mediatek,mt7986-sgmiisys_0",
+				"syscon";
+		reg = <0 0x10060000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	sgmiisys1: syscon@10070000 {
+		compatible = "mediatek,mt7986-sgmiisys",
+				 "mediatek,mt7986-sgmiisys_1",
+				 "syscon";
+		reg = <0 0x10070000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	snand: snfi@11005000 {
+		compatible = "mediatek,mt7986-snand";
+		reg = <0 0x11005000 0 0x1000>, <0 0x11006000 0 0x1000>;
+		reg-names = "nfi", "ecc";
+		interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_SPINFI1_CK>,
+			 <&infracfg_ao CK_INFRA_NFI1_CK>,
+			 <&infracfg_ao CK_INFRA_NFI_HCK_CK>;
+		clock-names = "pad_clk", "nfi_clk", "nfi_hclk";
+		assigned-clocks = <&topckgen CK_TOP_SPINFI_SEL>,
+			 	  <&topckgen CK_TOP_NFI1X_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_M_D8>,
+					 <&topckgen CK_TOP_CB_M_D8>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	wbsys: wbsys@18000000 {
+		compatible = "mediatek,wbsys",
+			     "mediatek,mt7986-wmac";
+		resets = <&watchdog MT7986_TOPRGU_CONSYS_RST>;
+		reset-names = "consys";
+		reg = <0 0x18000000 0 0x1000000>,
+		      <0 0x10003000 0 0x1000>,
+		      <0 0x11d10000 0 0x1000>;
+		interrupts = <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 215 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>;
+		chip_id = <0x7986>;
+		memory-region = <&wmcpu_emi>;
+	};
+
+	wed_pcie: wed_pcie@10003000 {
+		compatible = "mediatek,wed_pcie";
+		reg = <0 0x10003000 0 0x10>;
+	};
+
+	spi0: spi@1100a000 {
+		compatible = "mediatek,ipm-spi-quad";
+		reg = <0 0x1100a000 0 0x100>;
+		interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&topckgen CK_TOP_CB_M_D2>,
+			 <&topckgen CK_TOP_SPI_SEL>,
+			 <&infracfg_ao CK_INFRA_SPI0_CK>,
+			 <&infracfg_ao CK_INFRA_SPI0_HCK_CK>;
+		clock-names = "parent-clk", "sel-clk", "spi-clk", "spi-hclk";
+		status = "disabled";
+	};
+
+	spi1: spi@1100b000 {
+		compatible = "mediatek,ipm-spi-single";
+		reg = <0 0x1100b000 0 0x100>;
+		interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&topckgen CK_TOP_CB_M_D2>,
+			 <&topckgen CK_TOP_SPIM_MST_SEL>,
+			 <&infracfg_ao CK_INFRA_SPI1_CK>,
+			 <&infracfg_ao CK_INFRA_SPI1_HCK_CK>;
+		clock-names = "parent-clk", "sel-clk", "spi-clk", "spi-hclk";
+		status = "disabled";
+	};
+
+	mmc0: mmc@11230000 {
+		compatible = "mediatek,mt7986-mmc";
+		reg = <0 0x11230000 0 0x1000>,
+			<0 0x11c20000 0 0x1000>;
+		interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&topckgen CK_TOP_EMMC_416M>,
+			<&topckgen CK_TOP_EMMC_250M>,
+			<&infracfg_ao CK_INFRA_MSDC_CK>;
+		clock-names = "source", "hclk", "source_cg";
+		assigned-clocks = <&topckgen CK_TOP_EMMC_416M_SEL>,
+				  <&topckgen CK_TOP_EMMC_250M_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_M_416M>,
+					 <&topckgen CK_TOP_NET1_D5_D2>;
+		status = "disabled";
+	};
+
+	auxadc: adc@1100d000 {
+		compatible = "mediatek,mt7986-auxadc",
+			     "mediatek,mt7622-auxadc";
+		reg = <0 0x1100d000 0 0x1000>;
+		clocks = <&infracfg_ao CK_INFRA_ADC_26M_CK>,
+			 <&infracfg_ao CK_INFRA_ADC_FRC_CK>;
+		clock-names = "main", "32k";
+		#io-channel-cells = <1>;
+		status = "disabled";
+	};
+
+	consys: consys@10000000 {
+		compatible = "mediatek,mt7986-consys";
+		reg = <0 0x10000000 0 0x8600000>;
+		memory-region = <&wmcpu_emi>;
+	};
+
+	xhci: xhci@11200000 {
+		compatible = "mediatek,mt7986-xhci",
+			     "mediatek,mtk-xhci";
+		reg = <0 0x11200000 0 0x2e00>,
+		      <0 0x11203e00 0 0x0100>;
+		reg-names = "mac", "ippc";
+		interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&u2port0 PHY_TYPE_USB2>,
+		       <&u3port0 PHY_TYPE_USB3>,
+		       <&u2port1 PHY_TYPE_USB2>;
+		clocks = <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>;
+		clock-names = "sys_ck",
+			      "xhci_ck",
+			      "ref_ck",
+			      "mcu_ck",
+			      "dma_ck";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		status = "okay";
+	};
+
+	pcietphy: pcie-phy@11c00000 {
+		compatible = "mediatek,mt7986",
+			     "mediatek,generic-tphy-v4";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+		status = "okay";
+
+		pcieport: pcie-phy@11c00000 {
+			reg = <0 0x11c00000 0 0x20000>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			auto_load_valid;
+			auto_load_valid_ln1;
+			nvmem-cells = <&pcie_intr_ln0>,
+				      <&pcie_rx_imp_ln0>,
+				      <&pcie_tx_imp_ln0>,
+				      <&pcie_auto_load_valid_ln0>,
+				      <&pcie_intr_ln1>,
+				      <&pcie_rx_imp_ln1>,
+				      <&pcie_tx_imp_ln1>,
+				      <&pcie_auto_load_valid_ln1>;
+			nvmem-cell-names = "intr",
+					   "rx_imp",
+					   "tx_imp",
+					   "auto_load_valid",
+					   "intr_ln1",
+					   "rx_imp_ln1",
+					   "tx_imp_ln1",
+					   "auto_load_valid_ln1";
+			status = "okay";
+		};
+	};
+
+	usbtphy: usb-phy@11e10000 {
+		compatible = "mediatek,mt7986",
+			     "mediatek,generic-tphy-v2";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+		status = "okay";
+
+		u2port0: usb-phy@11e10000 {
+			reg = <0 0x11e10000 0 0x700>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			auto_load_valid;
+			nvmem-cells = <&u2_intr_p0>, <&u2_auto_load_valid_p0>;
+			nvmem-cell-names = "intr", "auto_load_valid";
+			status = "okay";
+		};
+
+		u3port0: usb-phy@11e10700 {
+			reg = <0 0x11e10700 0 0x900>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			auto_load_valid;
+			nvmem-cells = <&comb_intr_p0>,
+			      <&comb_rx_imp_p0>,
+			      <&comb_tx_imp_p0>,
+			      <&comb_auto_load_valid>;
+			nvmem-cell-names = "intr", "rx_imp", "tx_imp", "auto_load_valid";
+			status = "okay";
+		};
+
+		u2port1: usb-phy@11e11000 {
+			reg = <0 0x11e11000 0 0x700>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			auto_load_valid;
+			nvmem-cells = <&u2_intr_p1>, <&u2_auto_load_valid_p1>;
+			nvmem-cell-names = "intr", "auto_load_valid";
+			status = "okay";
+		};
+	};
+
+	clkitg: clkitg {
+		compatible = "simple-bus";
+	};
+
+	afe: audio-controller@11210000 {
+		compatible = "mediatek,mt79xx-audio";
+		reg = <0 0x11210000 0 0x9000>;
+		interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_AUD_BUS_CK>,
+			 <&infracfg_ao CK_INFRA_AUD_26M_CK>,
+			 <&infracfg_ao CK_INFRA_AUD_L_CK>,
+			 <&infracfg_ao CK_INFRA_AUD_AUD_CK>,
+			 <&infracfg_ao CK_INFRA_AUD_EG2_CK>;
+		clock-names = "aud_bus_ck",
+			      "aud_26m_ck",
+			      "aud_l_ck",
+			      "aud_aud_ck",
+			      "aud_eg2_ck";
+		assigned-clocks = <&topckgen CK_TOP_A1SYS_SEL>,
+				  <&topckgen CK_TOP_AUD_L_SEL>,
+				  <&topckgen CK_TOP_A_TUNER_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_APLL2_D4>,
+					 <&topckgen CK_TOP_CB_APLL2_196M>,
+					 <&topckgen CK_TOP_APLL2_D4>;
+	};
+
+	trng: trng@1020f000 {
+		compatible = "mediatek,mt7986-rng",
+			     "mediatek,mt7623-rng";
+		reg = <0 0x1020f000 0 0x100>;
+		clocks = <&infracfg_ao CK_INFRA_TRNG_CK>;
+		clock-names = "rng";
+	};
+
+	ice: ice_debug {
+		compatible = "mediatek,mt7986-ice_debug",
+			"mediatek,mt2701-ice_debug";
+		clocks = <&infracfg_ao CK_INFRA_DBG_CK>,
+			 <&topckgen CK_TOP_ARM_DB_JTSEL>;
+		clock-names = "ice_dbg", "dbg_jtsel";
+	};
+
+	efuse: efuse@11d00000 {
+		compatible = "mediatek,mt7986-efuse",
+			     "mediatek,efuse";
+		reg = <0 0x11d00000 0 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		thermal_calibration: calib@274 {
+			reg = <0x274 0xc>;
+		};
+
+		comb_auto_load_valid: usb3-alv-imp@8da {
+			reg = <0x8da 1>;
+			bits = <0 1>;
+		};
+
+		comb_rx_imp_p0: usb3-rx-imp@8d8 {
+			reg = <0x8d8 1>;
+			bits = <0 5>;
+		};
+
+		comb_tx_imp_p0: usb3-tx-imp@8d8 {
+			reg = <0x8d8 2>;
+			bits = <5 5>;
+		};
+
+		comb_intr_p0: usb3-intr@8d9 {
+			reg = <0x8d9 1>;
+			bits = <2 6>;
+		};
+
+		u2_auto_load_valid_p0: usb2-alv-p0@8e0 {
+			reg  = <0x8e0 1>;
+			bits = <0 1>;
+		};
+
+		u2_intr_p0: usb2-intr-p0@8e0 {
+			reg  = <0x8e0 1>;
+			bits = <1 5>;
+		};
+
+		u2_auto_load_valid_p1: usb2-alv-p1@8e0 {
+			reg  = <0x8e0 2>;
+			bits = <6 1>;
+		};
+
+		u2_intr_p1: usb2-intr-p1@8e0 {
+			reg  = <0x8e0 2>;
+			bits = <7 5>;
+		};
+
+		pcie_rx_imp_ln0: pcie-rx-imp@8d0 {
+			reg = <0x8d0 1>;
+			bits = <0 5>;
+		};
+
+		pcie_tx_imp_ln0: pcie-tx-imp@8d0 {
+			reg = <0x8d0 2>;
+			bits = <5 5>;
+		};
+
+		pcie_intr_ln0: pcie-intr@8d1 {
+			reg = <0x8d1 1>;
+			bits = <2 6>;
+		};
+
+		pcie_auto_load_valid_ln0: pcie-ln0-alv@8d4 {
+			reg = <0x8d4 1>;
+			bits = <0 1>;
+		};
+
+		pcie_rx_imp_ln1: pcie-rx-imp@8d2 {
+			reg = <0x8d2 1>;
+			bits = <0 5>;
+		};
+
+		pcie_tx_imp_ln1: pcie-tx-imp@8d2 {
+			reg = <0x8d2 2>;
+			bits = <5 5>;
+		};
+
+		pcie_intr_ln1: pcie-intr@8d3 {
+			reg = <0x8d3 1>;
+			bits = <2 6>;
+		};
+
+		pcie_auto_load_valid_ln1: pcie-ln1-alv@8d4 {
+			reg = <0x8d4 1>;
+			bits = <1 1>;
+		};
+	};
+};
+
+#include "mt7986-clkitg.dtsi"
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-emmc-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-emmc-rfb.dts
new file mode 100644
index 0000000..d768e45
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-emmc-rfb.dts
@@ -0,0 +1,245 @@
+/dts-v1/;
+#include "mt7986b.dtsi"
+#include "mt7986b-pinctrl.dtsi"
+/ {
+	model = "MediaTek MT7986b RFB";
+	compatible = "mediatek,mt7986b-emmc-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000 \
+				root=PARTLABEL=rootfs rootwait rootfstype=squashfs,f2fs";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+/* Warning: pins shared with &snand */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+/* Warning: pins shared with &spi1 */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "disabled";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@4 {
+					reg = <4>;
+					label = "lan4";
+				};
+
+				port@5 {
+					reg = <5>;
+					label = "lan5";
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+/* Warning: pins shared with &uart2 */
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_pins_default>;
+	pinctrl-1 = <&mmc0_pins_uhs>;
+	bus-width = <8>;
+	max-frequency = <50000000>;
+	cap-mmc-highspeed;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_3p3v>;
+	non-removable;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
+
+&pio {
+	mmc0_pins_default: mmc0-pins-22-to-32-default {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+		conf-cmd-dat {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO",
+			       "SPI0_CS", "SPI0_HOLD", "SPI0_WP",
+			       "SPI1_CLK", "SPI1_MOSI", "SPI1_MISO";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+		conf-clk {
+			pins = "SPI1_CS";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-rst {
+			pins = "PWM1";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+
+	mmc0_pins_uhs: mmc0-pins-22-to-32-uhs {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+		conf-cmd-dat {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO",
+			       "SPI0_CS", "SPI0_HOLD", "SPI0_WP",
+			       "SPI1_CLK", "SPI1_MOSI", "SPI1_MISO";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+		conf-clk {
+			pins = "SPI1_CS";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-rst {
+			pins = "PWM1";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-gsw-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-gsw-spim-nand-rfb.dts
new file mode 100644
index 0000000..840b52f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-gsw-spim-nand-rfb.dts
@@ -0,0 +1,198 @@
+/dts-v1/;
+#include "mt7986b.dtsi"
+#include "mt7986b-pinctrl.dtsi"
+#include "mt7986-spim-nand-partition.dtsi"
+/ {
+	model = "MediaTek MT7986b gsw RFB";
+	compatible = "mediatek,mt7986b-gsw-spim-snand-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	gsw: gsw@0 {
+		compatible = "mediatek,mt753x";
+		mediatek,ethsys = <&ethsys>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+/* Warning: pins shared with &snand */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+/* Warning: pins shared with &spi1 */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "disabled";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+	};
+};
+
+&gsw {
+	mediatek,mdio = <&mdio>;
+	mediatek,portmap = "lllll";
+	mediatek,mdio_master_pinmux = <1>;
+	reset-gpios = <&pio 5 0>;
+	interrupt-parent = <&pio>;
+	interrupts = <66 IRQ_TYPE_LEVEL_HIGH>;
+	status = "okay";
+
+	port5: port@5 {
+		compatible = "mediatek,mt753x-port";
+		reg = <5>;
+		phy-mode = "sgmii";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+		};
+
+	};
+
+	port6: port@6 {
+		compatible = "mediatek,mt753x-port";
+		mediatek,ssc-on;
+		reg = <6>;
+		phy-mode = "sgmii";
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	cs-gpios = <0>, <0>;
+	status = "okay";
+
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <20000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+
+	spi_nand: spi_nand@1 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-max-frequency = <20000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+/* Warning: pins shared with &uart2 */
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
+
+&pio {
+	spi_flash_pins: spi-flash-pins-33-to-38 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-sd-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-sd-rfb.dts
new file mode 100644
index 0000000..953cca1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-sd-rfb.dts
@@ -0,0 +1,272 @@
+/dts-v1/;
+#include "mt7986b.dtsi"
+#include "mt7986b-pinctrl.dtsi"
+/ {
+	model = "MediaTek MT7986b RFB";
+	compatible = "mediatek,mt7986b-2500wan-sd-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+			earlycon=uart8250,mmio32,0x11002000 \
+			root=PARTLABEL=rootfs rootwait rootfstype=squashfs,f2fs";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+/* Warning: pins shared with &snand */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+/* Warning: pins shared with &spi1 */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "disabled";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@4 {
+					reg = <4>;
+					label = "lan4";
+				};
+
+				port@5 {
+					reg = <5>;
+					label = "lan5";
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_pins_default>;
+	pinctrl-1 = <&mmc0_pins_uhs>;
+	bus-width = <4>;
+	max-frequency = <52000000>;
+	cap-sd-highspeed;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_3p3v>;
+	status = "okay";
+};
+
+&pio {
+	mmc0_pins_default: mmc0-pins-22-to-32-default {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+
+		conf-cmd-dat {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO",
+			       "SPI0_CS", "SPI0_HOLD", "SPI0_WP",
+			       "SPI1_CLK", "SPI1_MOSI", "SPI1_MISO";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+
+		conf-clk {
+			pins = "SPI1_CS";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+
+		conf-rst {
+			pins = "PWM1";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+
+	mmc0_pins_uhs: mmc0-pins-22-to-32-uhs {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+
+		conf-cmd-dat {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO",
+			       "SPI0_CS", "SPI0_HOLD", "SPI0_WP",
+			       "SPI1_CLK", "SPI1_MOSI", "SPI1_MISO";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+
+		conf-clk {
+			pins = "SPI1_CS";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+
+		conf-rst {
+			pins = "PWM1";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+
+	wf_2g_5g_pins: wf_2g_5g-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_2g", "wf_5g";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+
+	wf_dbdc_pins: wf_dbdc-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_dbdc";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-snfi-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-snfi-nand-rfb.dts
new file mode 100644
index 0000000..ab72f6c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-snfi-nand-rfb.dts
@@ -0,0 +1,209 @@
+/dts-v1/;
+#include "mt7986b.dtsi"
+#include "mt7986b-pinctrl.dtsi"
+#include "mt7986-snfi-nand-partition.dtsi"
+/ {
+	model = "MediaTek MT7986b RFB";
+	compatible = "mediatek,mt7986b-snfi-snand-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+/* Warning: pins shared with &snand */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+/* Warning: pins shared with &spi1 */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "disabled";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@4 {
+					reg = <4>;
+					label = "lan4";
+				};
+
+				port@5 {
+					reg = <5>;
+					label = "lan5";
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+/* Warning: pins shared with &uart1 */
+&snand {
+	pinctrl-names = "default";
+	pinctrl-0 = <&snfi_pins>;
+	mediatek,quad-spi;
+	status = "okay";
+
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+	};
+};
+
+/* Warning: pins shared with &uart2 */
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
+
+&pio {
+	snfi_pins: snfi-pins-23-to-28 {
+		mux {
+			function = "flash";
+			groups = "snfi";
+		};
+		conf-clk {
+			pins = "SPI0_CLK";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+		conf-pu {
+			pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI0_MOSI", "SPI0_MISO";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-spim-nand-rfb.dts
new file mode 100644
index 0000000..d2b3ba3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-spim-nand-rfb.dts
@@ -0,0 +1,255 @@
+/dts-v1/;
+#include "mt7986b.dtsi"
+#include "mt7986b-pinctrl.dtsi"
+#include "mt7986-spim-nand-partition.dtsi"
+/ {
+	model = "MediaTek MT7986b RFB";
+	compatible = "mediatek,mt7986b-2500wan-spim-snand-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+/* Warning: pins shared with &snand */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+/* Warning: pins shared with &spi1 */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "disabled";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@4 {
+					reg = <4>;
+					label = "lan4";
+				};
+
+				port@5 {
+					reg = <5>;
+					label = "lan5";
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	cs-gpios = <0>, <0>;
+	status = "okay";
+
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <20000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+
+	spi_nand: spi_nand@1 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-max-frequency = <20000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+/* Warning: pins shared with &uart2 */
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+	pinctrl-names = "default", "dbdc";
+	pinctrl-0 = <&wf_2g_5g_pins>;
+	pinctrl-1 = <&wf_dbdc_pins>;
+};
+
+&pio {
+	spi_flash_pins: spi-flash-pins-33-to-38 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+
+	};
+
+	wf_2g_5g_pins: wf_2g_5g-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_2g", "wf_5g";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+
+	wf_dbdc_pins: wf_dbdc-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_dbdc";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-spim-nor-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-spim-nor-rfb.dts
new file mode 100644
index 0000000..277eec2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-spim-nor-rfb.dts
@@ -0,0 +1,208 @@
+/dts-v1/;
+#include "mt7986b.dtsi"
+#include "mt7986b-pinctrl.dtsi"
+#include "mt7986-spim-nor-partition.dtsi"
+/ {
+	model = "MediaTek MT7986b RFB";
+	compatible = "mediatek,mt7986b-nor-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+/* Warning: pins shared with &snand */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+/* Warning: pins shared with &spi1 */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "disabled";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@4 {
+					reg = <4>;
+					label = "lan4";
+				};
+
+				port@5 {
+					reg = <5>;
+					label = "lan5";
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	cs-gpios = <0>, <0>;
+	status = "okay";
+
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+/* Warning: pins shared with &uart2 */
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
+
+&pio {
+	spi_flash_pins: spi-flash-pins-33-to-38 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-emmc-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-emmc-rfb.dts
new file mode 100644
index 0000000..483c098
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-emmc-rfb.dts
@@ -0,0 +1,229 @@
+/dts-v1/;
+#include "mt7986b.dtsi"
+#include "mt7986b-pinctrl.dtsi"
+/ {
+	model = "MediaTek MT7986b RFB";
+	compatible = "mediatek,mt7986b-emmc-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000 \
+				root=PARTLABEL=rootfs rootwait rootfstype=squashfs,f2fs";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+/* Warning: pins shared with &snand */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+/* Warning: pins shared with &spi1 */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "disabled";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+/* Warning: pins shared with &uart2 */
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_pins_default>;
+	pinctrl-1 = <&mmc0_pins_uhs>;
+	bus-width = <8>;
+	max-frequency = <52000000>;
+	cap-mmc-highspeed;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_3p3v>;
+	non-removable;
+	no-sd;
+	no-sdio;
+	status = "okay";
+};
+
+&wbsys {
+	status = "okay";
+};
+
+&pio {
+	mmc0_pins_default: mmc0-pins-22-to-32-default {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+		conf-cmd-dat {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO",
+			       "SPI0_CS", "SPI0_HOLD", "SPI0_WP",
+			       "SPI1_CLK", "SPI1_MOSI", "SPI1_MISO";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+		conf-clk {
+			pins = "SPI1_CS";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-rst {
+			pins = "PWM1";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+
+	mmc0_pins_uhs: mmc0-pins-22-to-32-uhs {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+		conf-cmd-dat {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO",
+			       "SPI0_CS", "SPI0_HOLD", "SPI0_WP",
+			       "SPI1_CLK", "SPI1_MOSI", "SPI1_MISO";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+		conf-clk {
+			pins = "SPI1_CS";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <2>;	/* pull-down 50K */
+		};
+		conf-rst {
+			pins = "PWM1";
+			drive-strength = <MTK_DRIVE_4mA>;
+			mediatek,pull-up-adv = <1>;	/* pull-up 10K */
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-pinctrl.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-pinctrl.dtsi
new file mode 100644
index 0000000..de8e325
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-pinctrl.dtsi
@@ -0,0 +1,29 @@
+&pio {
+	i2c_pins: i2c-pins-3-4 {
+		mux {
+			function = "i2c";
+			groups = "i2c";
+		};
+	};
+
+	uart1_pins: uart1-pins-23-to-26 {
+		mux {
+			function = "uart";
+			groups = "uart1_1";
+		};
+	};
+
+	uart2_pins: uart1-pins-29-to-32 {
+		mux {
+			function = "uart";
+			groups = "uart2_0";
+		};
+	};
+
+	spic_pins: spi1-pins-29-to-32 {
+		mux {
+			function = "spi";
+			groups = "spi1_2";
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-snfi-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-snfi-nand-rfb.dts
new file mode 100644
index 0000000..b260808
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-snfi-nand-rfb.dts
@@ -0,0 +1,192 @@
+/dts-v1/;
+#include "mt7986b.dtsi"
+#include "mt7986b-pinctrl.dtsi"
+#include "mt7986-snfi-nand-partition.dtsi"
+/ {
+	model = "MediaTek MT7986b RFB";
+	compatible = "mediatek,mt7986b-snfi-snand-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+/* Warning: pins shared with &snand */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+/* Warning: pins shared with &spi1 */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "disabled";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+/* Warning: pins shared with &uart1 */
+&snand {
+	pinctrl-names = "default";
+	pinctrl-0 = <&snfi_pins>;
+	mediatek,quad-spi;
+	status = "okay";
+
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+	};
+};
+
+/* Warning: pins shared with &uart2 */
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
+
+&pio {
+	snfi_pins: snfi-pins-23-to-28 {
+		mux {
+			function = "flash";
+			groups = "snfi";
+		};
+		conf-clk {
+			pins = "SPI0_CLK";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+		conf-pu {
+			pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI0_MOSI", "SPI0_MISO";
+			drive-strength = <MTK_DRIVE_6mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-spim-nand-rfb.dts
new file mode 100644
index 0000000..6cecec9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-spim-nand-rfb.dts
@@ -0,0 +1,238 @@
+/dts-v1/;
+#include "mt7986b.dtsi"
+#include "mt7986b-pinctrl.dtsi"
+#include "mt7986-spim-nand-partition.dtsi"
+/ {
+	model = "MediaTek MT7986b RFB";
+	compatible = "mediatek,mt7986b-spim-snand-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+/* Warning: pins shared with &snand */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+/* Warning: pins shared with &spi1 */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "disabled";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	cs-gpios = <0>, <0>;
+	status = "okay";
+
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+
+	spi_nand: spi_nand@1 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-max-frequency = <52000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+/* Warning: pins shared with &uart2 */
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+	pinctrl-names = "default", "dbdc";
+	pinctrl-0 = <&wf_2g_5g_pins>;
+	pinctrl-1 = <&wf_dbdc_pins>;
+};
+
+&pio {
+	spi_flash_pins: spi-flash-pins-33-to-38 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+
+	};
+
+	wf_2g_5g_pins: wf_2g_5g-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_2g", "wf_5g";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+
+	wf_dbdc_pins: wf_dbdc-pins {
+		mux {
+			function = "wifi";
+			groups = "wf_dbdc";
+		};
+		conf {
+			pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4",
+			       "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6",
+			       "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10",
+			       "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1",
+			       "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0",
+			       "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8",
+			       "WF1_TOP_CLK", "WF1_TOP_DATA";
+			drive-strength = <MTK_DRIVE_4mA>;
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-spim-nor-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-spim-nor-rfb.dts
new file mode 100644
index 0000000..443dbb5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-spim-nor-rfb.dts
@@ -0,0 +1,191 @@
+/dts-v1/;
+#include "mt7986b.dtsi"
+#include "mt7986b-pinctrl.dtsi"
+#include "mt7986-spim-nor-partition.dtsi"
+/ {
+	model = "MediaTek MT7986b RFB";
+	compatible = "mediatek,mt7986b-nor-rfb";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+				earlycon=uart8250,mmio32,0x11002000";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+/* Warning: pins shared with &snand */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+/* Warning: pins shared with &spi1 */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+	status = "disabled";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "okay";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <5>;
+			reset-gpios = <&pio 6 1>;
+			reset-deassert-us = <20000>;
+			phy-mode = "2500base-x";
+		};
+
+		phy6: phy@6 {
+			compatible = "ethernet-phy-id67c9.de0a";
+			reg = <6>;
+			phy-mode = "2500base-x";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7531";
+			reg = <31>;
+			reset-gpios = <&pio 5 0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "2500base-x";
+
+					fixed-link {
+						speed = <2500>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-max-gmac = <2>;
+	status = "okay";
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	cs-gpios = <0>, <0>;
+	status = "okay";
+
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+		spi-tx-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+/* Warning: pins shared with &uart2 */
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spic_pins>;
+	status = "okay";
+};
+
+&wbsys {
+	mediatek,mtd-eeprom = <&factory 0x0000>;
+	status = "okay";
+};
+
+&pio {
+	spi_flash_pins: spi-flash-pins-33-to-38 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-up-adv = <0>;	/* bias-disable */
+		};
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			mediatek,pull-down-adv = <0>;	/* bias-disable */
+		};
+
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
new file mode 100644
index 0000000..14e3640
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
@@ -0,0 +1,676 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Sam.Shih <sam.shih@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/phy/phy.h>
+#include <dt-bindings/reset/ti-syscon.h>
+#include <dt-bindings/clock/mt7986-clk.h>
+#include <dt-bindings/thermal/thermal.h>
+#include <dt-bindings/pinctrl/mt65xx.h>
+#include <dt-bindings/reset/mt7986-resets.h>
+
+/ {
+	compatible = "mediatek,mt7986b-rfb";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu0: cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			enable-method = "psci";
+			reg = <0x0>;
+		};
+
+		cpu1: cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			enable-method = "psci";
+			reg = <0x1>;
+		};
+
+		cpu2: cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			enable-method = "psci";
+			reg = <0x2>;
+		};
+
+		cpu3: cpu@3 {
+			device_type = "cpu";
+			enable-method = "psci";
+			compatible = "arm,cortex-a53";
+			reg = <0x3>;
+		};
+	};
+
+	wed: wed@15010000 {
+		compatible = "mediatek,wed";
+		wed_num = <2>;
+		/* add this property for wed get the pci slot number. */
+		pci_slot_map = <0>, <1>;
+		reg = <0 0x15010000 0 0x1000>,
+		      <0 0x15011000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	wed2: wed2@15011000 {
+		compatible = "mediatek,wed2";
+		wed_num = <2>;
+		reg = <0 0x15010000 0 0x1000>,
+		      <0 0x15011000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	wdma: wdma@15104800 {
+		compatible = "mediatek,wed-wdma";
+		reg = <0 0x15104800 0 0x400>,
+		      <0 0x15104c00 0 0x400>;
+	};
+
+	ap2woccif: ap2woccif@151A5000 {
+		compatible = "mediatek,ap2woccif";
+		reg = <0 0x151A5000 0 0x1000>,
+		      <0 0x151AD000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>;
+        };
+
+	wocpu0_ilm: wocpu0_ilm@151E0000 {
+		compatible = "mediatek,wocpu0_ilm";
+		reg = <0 0x151E0000 0 0x8000>;
+	};
+
+        wocpu1_ilm: wocpu1_ilm@151F0000 {
+                compatible = "mediatek,wocpu1_ilm";
+                reg = <0 0x151F0000 0 0x8000>;
+        };
+
+	wocpu_dlm: wocpu_dlm@151E8000 {
+		compatible = "mediatek,wocpu_dlm";
+		reg = <0 0x151E8000 0 0x2000>,
+		      <0 0x151F8000 0 0x2000>;
+
+		resets = <&ethsysrst 0>;
+		reset-names = "wocpu_rst";
+	};
+
+	cpu_boot: wocpu_boot@15194000 {
+		compatible = "mediatek,wocpu_boot";
+		reg = <0 0x15194000 0 0x1000>;
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		/* 192 KiB reserved for ARM Trusted Firmware (BL31) */
+		secmon_reserved: secmon@43000000 {
+			reg = <0 0x43000000 0 0x30000>;
+			no-map;
+		};
+
+		wmcpu_emi: wmcpu-reserved@4FC00000 {
+			compatible = "mediatek,wmcpu-reserved";
+			no-map;
+			reg = <0 0x4FC00000 0 0x00100000>;
+		};
+
+		wocpu0_emi: wocpu0_emi@4FD00000 {
+			compatible = "mediatek,wocpu0_emi";
+			no-map;
+			reg = <0 0x4FD00000 0 0x40000>;
+			shared = <0>;
+		};
+
+		wocpu1_emi: wocpu1_emi@4FD40000 {
+			compatible = "mediatek,wocpu1_emi";
+			no-map;
+			reg = <0 0x4FD40000 0 0x40000>;
+			shared = <0>;
+		};
+
+		wocpu_data: wocpu_data@4FD80000 {
+			compatible = "mediatek,wocpu_data";
+			no-map;
+			reg = <0 0x4FD80000 0 0x240000>;
+			shared = <1>;
+		};
+	};
+
+	psci {
+		compatible  = "arm,psci-0.2";
+		method      = "smc";
+	};
+
+	clk40m: oscillator@0 {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <40000000>;
+		clock-output-names = "clkxtal";
+	};
+
+	system_clk: dummy_system_clk {
+		compatible = "fixed-clock";
+		clock-frequency = <40000000>;
+		#clock-cells = <0>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupt-parent = <&gic>;
+		clock-frequency = <13000000>;
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	infracfg_ao: infracfg_ao@10001000 {
+		compatible = "mediatek,mt7986-infracfg_ao", "syscon";
+		reg = <0 0x10001000 0 0x68>;
+		#clock-cells = <1>;
+	};
+
+	infracfg: infracfg@10001040 {
+		compatible = "mediatek,mt7986-infracfg", "syscon";
+		reg = <0 0x1000106c 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	topckgen: topckgen@1001B000 {
+		compatible = "mediatek,mt7986-topckgen", "syscon";
+		reg = <0 0x1001B000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	apmixedsys: apmixedsys@1001E000 {
+		compatible = "mediatek,mt7986-apmixedsys", "syscon";
+		reg = <0 0x1001E000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	watchdog: watchdog@1001c000 {
+		compatible = "mediatek,mt7986-wdt";
+		reg = <0 0x1001c000 0 0x1000>;
+		interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+		#reset-cells = <1>;
+	};
+
+	gic: interrupt-controller@c000000 {
+		compatible = "arm,gic-v3";
+		#interrupt-cells = <3>;
+		interrupt-parent = <&gic>;
+		interrupt-controller;
+		reg = <0 0x0c000000 0 0x40000>,  /* GICD */
+		      <0 0x0c080000 0 0x200000>; /* GICR */
+
+		interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	pwm: pwm@10048000 {
+		compatible = "mediatek,mt7986-pwm";
+		reg = <0 0x10048000 0 0x1000>;
+		#clock-cells = <1>;
+		#pwm-cells = <2>;
+		interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg CK_INFRA_PWM>,
+			 <&infracfg_ao CK_INFRA_PWM_BSEL>,
+			 <&infracfg_ao CK_INFRA_PWM1_CK>,
+			 <&infracfg_ao CK_INFRA_PWM2_CK>;
+		assigned-clocks = <&topckgen CK_TOP_PWM_SEL>,
+				  <&infracfg_ao CK_INFRA_PWM_BSEL>,
+				  <&infracfg_ao CK_INFRA_PWM1_SEL>,
+				  <&infracfg_ao CK_INFRA_PWM2_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_M_D4>,
+					 <&infracfg CK_INFRA_PWM>,
+					 <&infracfg CK_INFRA_PWM>,
+					 <&infracfg CK_INFRA_PWM>;
+		clock-names = "top", "main", "pwm1", "pwm2";
+		status = "disabled";
+	};
+
+	uart0: serial@11002000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11002000 0 0x400>;
+		interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_UART0_CK>;
+		assigned-clocks = <&topckgen CK_TOP_UART_SEL>,
+				  <&infracfg_ao CK_INFRA_UART0_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_CKSQ_40M>,
+					 <&infracfg CK_INFRA_UART>;
+		status = "disabled";
+	};
+
+	uart1: serial@11003000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11003000 0 0x400>;
+		interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_UART1_CK>;
+		assigned-clocks = <&infracfg_ao CK_INFRA_UART1_SEL>;
+		assigned-clock-parents = <&infracfg CK_INFRA_CK_F26M>;
+		status = "disabled";
+	};
+
+	uart2: serial@11004000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11004000 0 0x400>;
+		interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_UART2_CK>;
+		assigned-clocks = <&infracfg_ao CK_INFRA_UART2_SEL>;
+		assigned-clock-parents = <&infracfg CK_INFRA_CK_F26M>;
+		status = "disabled";
+	};
+
+        i2c0: i2c@11008000 {
+                compatible = "mediatek,mt7986-i2c";
+                reg = <0 0x11008000 0 0x90>,
+                      <0 0x10217080 0 0x80>;
+                interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+                clock-div = <5>;
+                clocks = <&infracfg_ao CK_INFRA_I2CO_CK>,
+                         <&infracfg_ao CK_INFRA_AP_DMA_CK>;
+                clock-names = "main", "dma";
+                #address-cells = <1>;
+                #size-cells = <0>;
+                status = "disabled";
+        };
+
+	thermal-zones {
+		cpu_thermal: cpu-thermal {
+			polling-delay-passive = <1000>;
+			polling-delay = <1000>;
+			thermal-sensors = <&thermal 0>;
+		};
+	};
+
+	thermal: thermal@1100c800 {
+		#thermal-sensor-cells = <1>;
+		compatible = "mediatek,mt7986-thermal";
+		reg = <0 0x1100c800 0 0x800>;
+		interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_THERM_CK>,
+			 <&infracfg_ao CK_INFRA_ADC_26M_CK>,
+			 <&infracfg_ao CK_INFRA_ADC_FRC_CK>;
+		clock-names = "therm", "auxadc", "adc_32k";
+		mediatek,auxadc = <&auxadc>;
+		mediatek,apmixedsys = <&apmixedsys>;
+		nvmem-cells = <&thermal_calibration>;
+		nvmem-cell-names = "calibration-data";
+	};
+
+	crypto: crypto@10320000 {
+		compatible = "inside-secure,safexcel-eip97";
+		reg = <0 0x10320000 0 0x40000>;
+		interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "ring0", "ring1", "ring2", "ring3";
+		clocks = <&infracfg_ao CK_INFRA_EIP97_CK>;
+		clock-names = "infra_eip97_ck";
+		assigned-clocks = <&topckgen CK_TOP_EIP_B_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_NET2_800M>;
+	};
+
+	pio: pinctrl@1001f000 {
+		compatible = "mediatek,mt7986-pinctrl";
+		reg = <0 0x1001f000 0 0x1000>,
+		      <0 0x11c30000 0 0x1000>,
+		      <0 0x11c40000 0 0x1000>,
+		      <0 0x11e20000 0 0x1000>,
+		      <0 0x11e30000 0 0x1000>,
+		      <0 0x11f00000 0 0x1000>,
+		      <0 0x11f10000 0 0x1000>,
+		      <0 0x1000b000 0 0x1000>;
+		reg-names = "gpio_base", "iocfg_rt_base", "iocfg_rb_base",
+			    "iocfg_lt_base", "iocfg_lb_base", "iocfg_tr_base",
+			    "iocfg_tl_base", "eint";
+		gpio-controller;
+		#gpio-cells = <2>;
+		gpio-ranges = <&pio 0 0 100>;
+		interrupt-controller;
+		interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-parent = <&gic>;
+		#interrupt-cells = <2>;
+	};
+
+	ethsys: syscon@15000000 {
+                #address-cells = <1>;
+                #size-cells = <1>;
+                compatible = "mediatek,mt7986-ethsys_ck",
+                             "syscon";
+                reg = <0 0x15000000 0 0x1000>;
+                #clock-cells = <1>;
+                #reset-cells = <1>;
+
+		ethsysrst: reset-controller {
+			compatible = "ti,syscon-reset";
+			#reset-cells = <1>;
+			ti,reset-bits = <0x34 4 0x34 4 0x34 4 (ASSERT_SET | DEASSERT_CLEAR | STATUS_SET)>;
+		};
+        };
+
+        eth: ethernet@15100000 {
+                compatible = "mediatek,mt7986-eth";
+                reg = <0 0x15100000 0 0x80000>;
+                interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
+                clocks = <&ethsys CK_ETH_FE_EN>,
+                         <&ethsys CK_ETH_GP2_EN>,
+                         <&ethsys CK_ETH_GP1_EN>,
+                         <&ethsys CK_ETH_WOCPU1_EN>,
+                         <&ethsys CK_ETH_WOCPU0_EN>,
+                         <&sgmiisys0 CK_SGM0_TX_EN>,
+                         <&sgmiisys0 CK_SGM0_RX_EN>,
+                         <&sgmiisys0 CK_SGM0_CK0_EN>,
+                         <&sgmiisys0 CK_SGM0_CDR_CK0_EN>,
+                         <&sgmiisys1 CK_SGM1_TX_EN>,
+                         <&sgmiisys1 CK_SGM1_RX_EN>,
+                         <&sgmiisys1 CK_SGM1_CK1_EN>,
+                         <&sgmiisys1 CK_SGM1_CDR_CK1_EN>;
+                clock-names = "fe", "gp2", "gp1", "wocpu1", "wocpu0",
+                         "sgmii_tx250m", "sgmii_rx250m",
+                         "sgmii_cdr_ref", "sgmii_cdr_fb",
+                         "sgmii2_tx250m", "sgmii2_rx250m",
+                         "sgmii2_cdr_ref", "sgmii2_cdr_fb";
+		assigned-clocks = <&topckgen CK_TOP_NETSYS_2X_SEL>,
+				  <&topckgen CK_TOP_SGM_325M_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_NET2_800M>,
+					 <&topckgen CK_TOP_CB_SGM_325M>;
+                mediatek,ethsys = <&ethsys>;
+		mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
+                #reset-cells = <1>;
+                #address-cells = <1>;
+                #size-cells = <0>;
+                status = "disabled";
+        };
+
+	hnat: hnat@15000000 {
+		compatible = "mediatek,mtk-hnat_v4";
+		reg = <0 0x15100000 0 0x80000>;
+		resets = <&ethsys 0>;
+		reset-names = "mtketh";
+		status = "disabled";
+	};
+
+	sgmiisys0: syscon@10060000 {
+		compatible = "mediatek,mt7986-sgmiisys",
+				"mediatek,mt7986-sgmiisys_0",
+				"syscon";
+		reg = <0 0x10060000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	sgmiisys1: syscon@10070000 {
+		compatible = "mediatek,mt7986-sgmiisys",
+				 "mediatek,mt7986-sgmiisys_1",
+				 "syscon";
+		reg = <0 0x10070000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	snand: snfi@11005000 {
+		compatible = "mediatek,mt7986-snand";
+		reg = <0 0x11005000 0 0x1000>, <0 0x11006000 0 0x1000>;
+		reg-names = "nfi", "ecc";
+		interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_SPINFI1_CK>,
+			 <&infracfg_ao CK_INFRA_NFI1_CK>,
+			 <&infracfg_ao CK_INFRA_NFI_HCK_CK>;
+		clock-names = "pad_clk", "nfi_clk", "nfi_hclk";
+		assigned-clocks = <&topckgen CK_TOP_SPINFI_SEL>,
+			 	  <&topckgen CK_TOP_NFI1X_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_M_D8>,
+					 <&topckgen CK_TOP_CB_M_D8>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	wbsys: wbsys@18000000 {
+		compatible = "mediatek,wbsys",
+			     "mediatek,mt7986-wmac";
+		resets = <&watchdog MT7986_TOPRGU_CONSYS_RST>;
+		reset-names = "consys";
+		reg = <0 0x18000000 0 0x1000000>,
+		      <0 0x10003000 0 0x1000>,
+		      <0 0x11d10000 0 0x1000>;
+		interrupts = <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 215 IRQ_TYPE_LEVEL_HIGH>,
+					 <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>;
+		chip_id = <0x7986>;
+		memory-region = <&wmcpu_emi>;
+	};
+
+	wed_pcie: wed_pcie@10003000 {
+		compatible = "mediatek,wed_pcie";
+		reg = <0 0x10003000 0 0x10>;
+	};
+
+	spi0: spi@1100a000 {
+		compatible = "mediatek,ipm-spi-quad";
+		reg = <0 0x1100a000 0 0x100>;
+		interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&topckgen CK_TOP_CB_M_D2>,
+			 <&topckgen CK_TOP_SPI_SEL>,
+			 <&infracfg_ao CK_INFRA_SPI0_CK>,
+			 <&infracfg_ao CK_INFRA_SPI0_HCK_CK>;
+		clock-names = "parent-clk", "sel-clk", "spi-clk", "spi-hclk";
+		status = "disabled";
+	};
+
+	spi1: spi@1100b000 {
+		compatible = "mediatek,ipm-spi-single";
+		reg = <0 0x1100b000 0 0x100>;
+		interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&topckgen CK_TOP_CB_M_D2>,
+			 <&topckgen CK_TOP_SPIM_MST_SEL>,
+			 <&infracfg_ao CK_INFRA_SPI1_CK>,
+			 <&infracfg_ao CK_INFRA_SPI1_HCK_CK>;
+		clock-names = "parent-clk", "sel-clk", "spi-clk", "spi-hclk";
+		status = "disabled";
+	};
+
+	mmc0: mmc@11230000 {
+		compatible = "mediatek,mt7986-mmc";
+		reg = <0 0x11230000 0 0x1000>,
+			<0 0x11c20000 0 0x1000>;
+		interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&topckgen CK_TOP_EMMC_416M>,
+			<&topckgen CK_TOP_EMMC_250M>,
+			<&infracfg_ao CK_INFRA_MSDC_CK>;
+		clock-names = "source", "hclk", "source_cg";
+		assigned-clocks = <&topckgen CK_TOP_EMMC_416M_SEL>,
+				  <&topckgen CK_TOP_EMMC_250M_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_M_416M>,
+					 <&topckgen CK_TOP_NET1_D5_D2>;
+		status = "disabled";
+	};
+
+	auxadc: adc@1100d000 {
+		compatible = "mediatek,mt7986-auxadc",
+			     "mediatek,mt7622-auxadc";
+		reg = <0 0x1100d000 0 0x1000>;
+		clocks = <&infracfg_ao CK_INFRA_ADC_26M_CK>,
+			 <&infracfg_ao CK_INFRA_ADC_FRC_CK>;
+		clock-names = "main", "32k";
+		#io-channel-cells = <1>;
+		status = "disabled";
+	};
+
+	consys: consys@10000000 {
+		compatible = "mediatek,mt7986-consys";
+		reg = <0 0x10000000 0 0x8600000>;
+		memory-region = <&wmcpu_emi>;
+	};
+
+	xhci: xhci@11200000 {
+		compatible = "mediatek,mt7986-xhci",
+			     "mediatek,mtk-xhci";
+		reg = <0 0x11200000 0 0x2e00>,
+		      <0 0x11203e00 0 0x0100>;
+		reg-names = "mac", "ippc";
+		interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&u3port0 PHY_TYPE_USB3>,
+		       <&u2port1 PHY_TYPE_USB2>;
+		clocks = <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>;
+		clock-names = "sys_ck",
+			      "xhci_ck",
+			      "ref_ck",
+			      "mcu_ck",
+			      "dma_ck";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		status = "okay";
+	};
+
+	usbtphy: usb-phy@11e10000 {
+		compatible = "mediatek,mt7986",
+			     "mediatek,generic-tphy-v2";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+		status = "okay";
+
+		u2port0: usb-phy@11e10000 {
+			reg = <0 0x11e10000 0 0x700>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			auto_load_valid;
+			nvmem-cells = <&u2_intr_p0>, <&u2_auto_load_valid_p0>;
+			nvmem-cell-names = "intr", "auto_load_valid";
+			status = "disabled";
+		};
+
+		u3port0: usb-phy@11e10700 {
+			reg = <0 0x11e10700 0 0x900>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			auto_load_valid;
+			nvmem-cells = <&comb_intr_p0>,
+			      <&comb_rx_imp_p0>,
+			      <&comb_tx_imp_p0>,
+			      <&comb_auto_load_valid>;
+			nvmem-cell-names = "intr", "rx_imp", "tx_imp", "auto_load_valid";
+			status = "okay";
+		};
+
+		u2port1: usb-phy@11e11000 {
+			reg = <0 0x11e11000 0 0x700>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			auto_load_valid;
+			nvmem-cells = <&u2_intr_p1>, <&u2_auto_load_valid_p1>;
+			nvmem-cell-names = "intr", "auto_load_valid";
+			status = "okay";
+		};
+	};
+
+	clkitg: clkitg {
+		compatible = "simple-bus";
+	};
+
+	trng: trng@1020f000 {
+		compatible = "mediatek,mt7986-rng",
+			     "mediatek,mt7623-rng";
+		reg = <0 0x1020f000 0 0x100>;
+		clocks = <&infracfg_ao CK_INFRA_TRNG_CK>;
+		clock-names = "rng";
+	};
+
+	ice: ice_debug {
+		compatible = "mediatek,mt7986-ice_debug",
+			"mediatek,mt2701-ice_debug";
+		clocks = <&infracfg_ao CK_INFRA_DBG_CK>,
+			 <&topckgen CK_TOP_ARM_DB_JTSEL>;
+		clock-names = "ice_dbg", "dbg_jtsel";
+	};
+
+	efuse: efuse@11d00000 {
+		compatible = "mediatek,mt7986-efuse",
+			     "mediatek,efuse";
+		reg = <0 0x11d00000 0 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		thermal_calibration: calib@274 {
+			reg = <0x274 0xc>;
+		};
+
+		comb_auto_load_valid: usb3-alv-imp@8da {
+			reg = <0x8da 1>;
+			bits = <0 1>;
+		};
+
+		comb_rx_imp_p0: usb3-rx-imp@8d8 {
+			reg = <0x8d8 1>;
+			bits = <0 5>;
+		};
+
+		comb_tx_imp_p0: usb3-tx-imp@8d8 {
+			reg = <0x8d8 2>;
+			bits = <5 5>;
+		};
+
+		comb_intr_p0: usb3-intr@8d9 {
+			reg = <0x8d9 1>;
+			bits = <2 6>;
+		};
+
+		u2_auto_load_valid_p0: usb2-alv-p0@8e0 {
+			reg  = <0x8e0 1>;
+			bits = <0 1>;
+		};
+
+		u2_intr_p0: usb2-intr-p0@8e0 {
+			reg  = <0x8e0 1>;
+			bits = <1 5>;
+		};
+
+		u2_auto_load_valid_p1: usb2-alv-p1@8e0 {
+			reg  = <0x8e0 2>;
+			bits = <6 1>;
+		};
+
+		u2_intr_p1: usb2-intr-p1@8e0 {
+			reg  = <0x8e0 2>;
+			bits = <7 5>;
+		};
+	};	
+};
+
+#include "mt7986-clkitg.dtsi"
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/clk/mediatek/clk-bringup.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/clk/mediatek/clk-bringup.c
new file mode 100644
index 0000000..ad1f092
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/clk/mediatek/clk-bringup.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: James Liao <jamesjj.liao@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "[clk-bringup] " fmt
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+
+static const struct of_device_id bring_up_id_table[] = {
+	{ .compatible = "mediatek,clk-bring-up",},
+	{ .compatible = "mediatek,mt8163-bring-up",},
+	{ .compatible = "mediatek,mt8173-bring-up",},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, bring_up_id_table);
+
+static int bring_up_probe(struct platform_device *pdev)
+{
+	const int NR_CLKS = 300;
+	char clk_name_buf[16];
+	struct clk *clk;
+	int i, r;
+
+	for (i = 0; i < NR_CLKS; i++) {
+		sprintf(clk_name_buf, "%d", i);
+
+		clk = devm_clk_get(&pdev->dev, clk_name_buf);
+		if (!IS_ERR(clk)) {
+			r = clk_prepare_enable(clk);
+			if (r)
+				pr_debug("clk_prepare_enable(%s): %d\n",
+					__clk_get_name(clk), r);
+		}
+	}
+
+	return 0;
+}
+
+static int bring_up_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver bring_up = {
+	.probe		= bring_up_probe,
+	.remove		= bring_up_remove,
+	.driver		= {
+		.name	= "bring_up",
+		.owner	= THIS_MODULE,
+		.of_match_table = bring_up_id_table,
+	},
+};
+
+module_platform_driver(bring_up);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/clk/mediatek/clk-mt7981.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/clk/mediatek/clk-mt7981.c
new file mode 100644
index 0000000..471fef3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/clk/mediatek/clk-mt7981.c
@@ -0,0 +1,854 @@
+/*

+ * Copyright (c) 2021 MediaTek Inc.

+ * Author: Wenzhen Yu<Yenzhen.Yu@mediatek.com>

+ *

+ * This program is free software; you can redistribute it and/or modify

+ * it under the terms of the GNU General Public License version 2 as

+ * published by the Free Software Foundation.

+ *

+ * This program is distributed in the hope that it will be useful,

+ * but WITHOUT ANY WARRANTY; without even the implied warranty of

+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+ * GNU General Public License for more details.

+ */

+

+#include <linux/clk.h>

+#include <linux/delay.h>

+#include <linux/of.h>

+#include <linux/of_address.h>

+#include <linux/slab.h>

+#include <linux/mfd/syscon.h>

+

+#include "clk-mtk.h"

+#include "clk-gate.h"

+#include "clk-mux.h"

+

+#include <dt-bindings/clock/mt7981-clk.h>

+

+static DEFINE_SPINLOCK(mt7981_clk_lock);

+

+static const struct mtk_fixed_factor infra_divs[] __initconst = {

+	FACTOR(CK_INFRA_CK_F26M, "infra_ck_f26m", "csw_f26m_sel", 1, 1),

+	FACTOR(CK_INFRA_UART, "infra_uart", "uart_sel", 1, 1),

+	FACTOR(CK_INFRA_ISPI0, "infra_ispi0", "spi_sel", 1, 1),

+	FACTOR(CK_INFRA_I2C, "infra_i2c", "i2c_sel", 1, 1),

+	FACTOR(CK_INFRA_ISPI1, "infra_ispi1", "spim_mst_sel", 1, 1),

+	FACTOR(CK_INFRA_PWM, "infra_pwm", "pwm_sel", 1, 1),

+	FACTOR(CK_INFRA_66M_MCK, "infra_66m_mck", "sysaxi_sel", 1, 2),

+	FACTOR(CK_INFRA_CK_F32K, "infra_ck_f32k", "cb_rtc_32p7k", 1, 1),

+	FACTOR(CK_INFRA_PCIE_CK, "infra_pcie", "pextp_tl_ck_sel", 1, 1),

+	FACTOR(CK_INFRA_PWM_BCK, "infra_pwm_bck", "infra_pwm_bsel", 1, 1),

+	FACTOR(CK_INFRA_PWM_CK1, "infra_pwm_ck1", "infra_pwm1_sel", 1, 1),

+	FACTOR(CK_INFRA_PWM_CK2, "infra_pwm_ck2", "infra_pwm2_sel", 1, 1),

+	FACTOR(CK_INFRA_133M_HCK, "infra_133m_hck", "sysaxi", 1, 1),

+	FACTOR(CK_INFRA_66M_PHCK, "infra_66m_phck", "infra_133m_hck", 1, 1),

+	FACTOR(CK_INFRA_FAUD_L_CK, "infra_faud_l", "aud_l", 1, 1),

+	FACTOR(CK_INFRA_FAUD_AUD_CK, "infra_faud_aud", "a1sys", 1, 1),

+	FACTOR(CK_INFRA_FAUD_EG2_CK, "infra_faud_eg2", "a_tuner", 1, 1),

+	FACTOR(CK_INFRA_I2CS_CK, "infra_i2cs", "i2c_bck", 1, 1),

+	FACTOR(CK_INFRA_MUX_UART0, "infra_mux_uart0", "infra_uart0_sel", 1, 1),

+	FACTOR(CK_INFRA_MUX_UART1, "infra_mux_uart1", "infra_uart1_sel", 1, 1),

+	FACTOR(CK_INFRA_MUX_UART2, "infra_mux_uart2", "infra_uart2_sel", 1, 1),

+	FACTOR(CK_INFRA_NFI_CK, "infra_nfi", "nfi1x", 1, 1),

+	FACTOR(CK_INFRA_SPINFI_CK, "infra_spinfi", "spinfi_bck", 1, 1),

+	FACTOR(CK_INFRA_MUX_SPI0, "infra_mux_spi0", "infra_spi0_sel", 1, 1),

+	FACTOR(CK_INFRA_MUX_SPI1, "infra_mux_spi1", "infra_spi1_sel", 1, 1),

+	FACTOR(CK_INFRA_MUX_SPI2, "infra_mux_spi2", "infra_spi2_sel", 1, 1),

+	FACTOR(CK_INFRA_RTC_32K, "infra_rtc_32k", "cb_rtc_32k", 1, 1),

+	FACTOR(CK_INFRA_FMSDC_CK, "infra_fmsdc", "emmc_400m", 1, 1),

+	FACTOR(CK_INFRA_FMSDC_HCK_CK, "infra_fmsdc_hck", "emmc_208m", 1, 1),

+	FACTOR(CK_INFRA_PERI_133M, "infra_peri_133m", "sysaxi", 1, 1),

+	FACTOR(CK_INFRA_133M_PHCK, "infra_133m_phck", "sysaxi", 1, 1),

+	FACTOR(CK_INFRA_USB_SYS_CK, "infra_usb_sys", "u2u3_sys", 1, 1),

+	FACTOR(CK_INFRA_USB_CK, "infra_usb", "u2u3_ref", 1, 1),

+	FACTOR(CK_INFRA_USB_XHCI_CK, "infra_usb_xhci", "u2u3_xhci", 1, 1),

+	FACTOR(CK_INFRA_PCIE_GFMUX_TL_O_PRE, "infra_pcie_mux", "pextp_tl", 1, 1),

+	FACTOR(CK_INFRA_F26M_CK0, "infra_f26m_ck0", "csw_f26m", 1, 1),

+	FACTOR(CK_INFRA_133M_MCK, "infra_133m_mck", "sysaxi", 1, 1),

+};

+

+static const struct mtk_fixed_factor top_divs[] __initconst = {

+	FACTOR(CK_TOP_CB_CKSQ_40M, "cb_cksq_40m", "clkxtal", 1, 1),

+	FACTOR(CK_TOP_CB_M_416M, "cb_m_416m", "mpll", 1, 1),

+	FACTOR(CK_TOP_CB_M_D2, "cb_m_d2", "mpll", 1, 2),

+	FACTOR(CK_TOP_CB_M_D3, "cb_m_d3", "mpll", 1, 3),

+	FACTOR(CK_TOP_M_D3_D2, "m_d3_d2", "mpll", 1, 2),

+	FACTOR(CK_TOP_CB_M_D4, "cb_m_d4", "mpll", 1, 4),

+	FACTOR(CK_TOP_CB_M_D8, "cb_m_d8", "mpll", 1, 8),

+	FACTOR(CK_TOP_M_D8_D2, "m_d8_d2", "mpll", 1, 16),

+	FACTOR(CK_TOP_CB_MM_720M, "cb_mm_720m", "mmpll", 1, 1),

+	FACTOR(CK_TOP_CB_MM_D2, "cb_mm_d2", "mmpll", 1, 2),

+	FACTOR(CK_TOP_CB_MM_D3, "cb_mm_d3", "mmpll", 1, 3),

+	FACTOR(CK_TOP_CB_MM_D3_D5, "cb_mm_d3_d5", "mmpll", 1, 15),

+	FACTOR(CK_TOP_CB_MM_D4, "cb_mm_d4", "mmpll", 1, 4),

+	FACTOR(CK_TOP_CB_MM_D6, "cb_mm_d6", "mmpll", 1, 6),

+	FACTOR(CK_TOP_MM_D6_D2, "mm_d6_d2", "mmpll", 1, 12),

+	FACTOR(CK_TOP_CB_MM_D8, "cb_mm_d8", "mmpll", 1, 8),

+	FACTOR(CK_TOP_CB_APLL2_196M, "cb_apll2_196m", "apll2", 1, 1),

+	FACTOR(CK_TOP_APLL2_D2, "apll2_d2", "apll2", 1, 2),

+	FACTOR(CK_TOP_APLL2_D4, "apll2_d4", "apll2", 1, 4),

+	FACTOR(CK_TOP_NET1_2500M, "net1_2500m", "net1pll", 1, 1),

+	FACTOR(CK_TOP_CB_NET1_D4, "cb_net1_d4", "net1pll", 1, 4),

+	FACTOR(CK_TOP_CB_NET1_D5, "cb_net1_d5", "net1pll", 1, 5),

+	FACTOR(CK_TOP_NET1_D5_D2, "net1_d5_d2", "net1pll", 1, 10),

+	FACTOR(CK_TOP_NET1_D5_D4, "net1_d5_d4", "net1pll", 1, 20),

+	FACTOR(CK_TOP_CB_NET1_D8, "cb_net1_d8", "net1pll", 1, 8),

+	FACTOR(CK_TOP_NET1_D8_D2, "net1_d8_d2", "net1pll", 1, 16),

+	FACTOR(CK_TOP_NET1_D8_D4, "net1_d8_d4", "net1pll", 1, 32),

+	FACTOR(CK_TOP_CB_NET2_800M, "cb_net2_800m", "net2pll", 1, 1),

+	FACTOR(CK_TOP_CB_NET2_D2, "cb_net2_d2", "net2pll", 1, 2),

+	FACTOR(CK_TOP_CB_NET2_D4, "cb_net2_d4", "net2pll", 1, 4),

+	FACTOR(CK_TOP_NET2_D4_D2, "net2_d4_d2", "net2pll", 1, 8),

+	FACTOR(CK_TOP_NET2_D4_D4, "net2_d4_d4", "net2pll", 1, 16),

+	FACTOR(CK_TOP_CB_NET2_D6, "cb_net2_d6", "net2pll", 1, 6),

+	FACTOR(CK_TOP_CB_WEDMCU_208M, "cb_wedmcu_208m", "wedmcupll", 1, 1),

+	FACTOR(CK_TOP_CB_SGM_325M, "cb_sgm_325m", "sgmpll", 1, 1),

+	FACTOR(CK_TOP_CKSQ_40M_D2, "cksq_40m_d2", "cb_cksq_40m", 1, 2),

+	FACTOR(CK_TOP_CB_RTC_32K, "cb_rtc_32k", "cb_cksq_40m", 1, 1250),

+	FACTOR(CK_TOP_CB_RTC_32P7K, "cb_rtc_32p7k", "cb_cksq_40m", 1, 1220),

+	FACTOR(CK_TOP_USB_TX250M, "usb_tx250m", "cb_cksq_40m", 1, 1),

+	FACTOR(CK_TOP_FAUD, "faud", "aud_sel", 1, 1),

+	FACTOR(CK_TOP_NFI1X, "nfi1x", "nfi1x_sel", 1, 1),

+	FACTOR(CK_TOP_USB_EQ_RX250M, "usb_eq_rx250m", "cb_cksq_40m", 1, 1),

+	FACTOR(CK_TOP_USB_CDR_CK, "usb_cdr", "cb_cksq_40m", 1, 1),

+	FACTOR(CK_TOP_USB_LN0_CK, "usb_ln0", "cb_cksq_40m", 1, 1),

+	FACTOR(CK_TOP_SPINFI_BCK, "spinfi_bck", "spinfi_sel", 1, 1),

+	FACTOR(CK_TOP_SPI, "spi", "spi_sel", 1, 1),

+	FACTOR(CK_TOP_SPIM_MST, "spim_mst", "spim_mst_sel", 1, 1),

+	FACTOR(CK_TOP_UART_BCK, "uart_bck", "uart_sel", 1, 1),

+	FACTOR(CK_TOP_PWM_BCK, "pwm_bck", "pwm_sel", 1, 1),

+	FACTOR(CK_TOP_I2C_BCK, "i2c_bck", "i2c_sel", 1, 1),

+	FACTOR(CK_TOP_PEXTP_TL, "pextp_tl", "pextp_tl_ck_sel", 1, 1),

+	FACTOR(CK_TOP_EMMC_208M, "emmc_208m", "emmc_208m_sel", 1, 1),

+	FACTOR(CK_TOP_EMMC_400M, "emmc_400m", "emmc_400m_sel", 1, 1),

+	FACTOR(CK_TOP_DRAMC_REF, "dramc_ref", "dramc_sel", 1, 1),

+	FACTOR(CK_TOP_DRAMC_MD32, "dramc_md32", "dramc_md32_sel", 1, 1),

+	FACTOR(CK_TOP_SYSAXI, "sysaxi", "sysaxi_sel", 1, 1),

+	FACTOR(CK_TOP_SYSAPB, "sysapb", "sysapb_sel", 1, 1),

+	FACTOR(CK_TOP_ARM_DB_MAIN, "arm_db_main", "arm_db_main_sel", 1, 1),

+	FACTOR(CK_TOP_AP2CNN_HOST, "ap2cnn_host", "ap2cnn_host_sel", 1, 1),

+	FACTOR(CK_TOP_NETSYS, "netsys", "netsys_sel", 1, 1),

+	FACTOR(CK_TOP_NETSYS_500M, "netsys_500m", "netsys_500m_sel", 1, 1),

+	FACTOR(CK_TOP_NETSYS_WED_MCU, "netsys_wed_mcu", "netsys_mcu_sel", 1, 1),

+	FACTOR(CK_TOP_NETSYS_2X, "netsys_2x", "netsys_2x_sel", 1, 1),

+	FACTOR(CK_TOP_SGM_325M, "sgm_325m", "sgm_325m_sel", 1, 1),

+	FACTOR(CK_TOP_SGM_REG, "sgm_reg", "sgm_reg_sel", 1, 1),

+	FACTOR(CK_TOP_F26M, "csw_f26m", "csw_f26m_sel", 1, 1),

+	FACTOR(CK_TOP_EIP97B, "eip97b", "eip97b_sel", 1, 1),

+	FACTOR(CK_TOP_USB3_PHY, "usb3_phy", "usb3_phy_sel", 1, 1),

+	FACTOR(CK_TOP_AUD, "aud", "faud", 1, 1),

+	FACTOR(CK_TOP_A1SYS, "a1sys", "a1sys_sel", 1, 1),

+	FACTOR(CK_TOP_AUD_L, "aud_l", "aud_l_sel", 1, 1),

+	FACTOR(CK_TOP_A_TUNER, "a_tuner", "a_tuner_sel", 1, 1),

+	FACTOR(CK_TOP_U2U3_REF, "u2u3_ref", "u2u3_sel", 1, 1),

+	FACTOR(CK_TOP_U2U3_SYS, "u2u3_sys", "u2u3_sys_sel", 1, 1),

+	FACTOR(CK_TOP_U2U3_XHCI, "u2u3_xhci", "u2u3_xhci_sel", 1, 1),

+	FACTOR(CK_TOP_USB_FRMCNT, "usb_frmcnt", "usb_frmcnt_sel", 1, 1),

+};

+

+static const char * const nfi1x_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_mm_d4",

+	"net1_d8_d2",

+	"cb_net2_d6",

+	"cb_m_d4",

+	"cb_mm_d8",

+	"net1_d8_d4",

+	"cb_m_d8"

+};

+

+static const char * const spinfi_parents[] __initconst = {

+	"cksq_40m_d2",

+	"cb_cksq_40m",

+	"net1_d5_d4",

+	"cb_m_d4",

+	"cb_mm_d8",

+	"net1_d8_d4",

+	"mm_d6_d2",

+	"cb_m_d8"

+};

+

+static const char * const spi_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_m_d2",

+	"cb_mm_d4",

+	"net1_d8_d2",

+	"cb_net2_d6",

+	"net1_d5_d4",

+	"cb_m_d4",

+	"net1_d8_d4"

+};

+

+static const char * const uart_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_m_d8",

+	"m_d8_d2"

+};

+

+static const char * const pwm_parents[] __initconst = {

+	"cb_cksq_40m",

+	"net1_d8_d2",

+	"net1_d5_d4",

+	"cb_m_d4",

+	"m_d8_d2",

+	"cb_rtc_32k"

+};

+

+static const char * const i2c_parents[] __initconst = {

+	"cb_cksq_40m",

+	"net1_d5_d4",

+	"cb_m_d4",

+	"net1_d8_d4"

+};

+

+static const char * const pextp_tl_ck_parents[] __initconst = {

+	"cb_cksq_40m",

+	"net1_d5_d4",

+	"cb_m_d4",

+	"cb_rtc_32k"

+};

+

+static const char * const emmc_208m_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_m_d2",

+	"cb_net2_d4",

+	"cb_apll2_196m",

+	"cb_mm_d4",

+	"net1_d8_d2",

+	"cb_mm_d6"

+};

+

+static const char * const emmc_400m_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_net2_d2",

+	"cb_mm_d2",

+	"cb_net2_d2"

+};

+

+static const char * const csw_f26m_parents[] __initconst = {

+	"cksq_40m_d2",

+	"m_d8_d2"

+};

+

+static const char * const dramc_md32_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_m_d2",

+	"cb_wedmcu_208m"

+};

+

+static const char * const sysaxi_parents[] __initconst = {

+	"cb_cksq_40m",

+	"net1_d8_d2"

+};

+

+static const char * const sysapb_parents[] __initconst = {

+	"cb_cksq_40m",

+	"m_d3_d2"

+};

+

+static const char * const arm_db_main_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_net2_d6"

+};

+

+static const char * const ap2cnn_host_parents[] __initconst = {

+	"cb_cksq_40m",

+	"net1_d8_d4"

+};

+

+static const char * const netsys_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_mm_d2"

+};

+

+static const char * const netsys_500m_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_net1_d5"

+};

+

+static const char * const netsys_mcu_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_mm_720m",

+	"cb_net1_d4",

+	"cb_net1_d5",

+	"cb_m_416m"

+};

+

+static const char * const netsys_2x_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_net2_800m",

+	"cb_mm_720m"

+};

+

+static const char * const sgm_325m_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_sgm_325m"

+};

+

+static const char * const sgm_reg_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_net2_d4"

+};

+

+static const char * const eip97b_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_net1_d5",

+	"cb_m_416m",

+	"cb_mm_d2",

+	"net1_d5_d2"

+};

+

+static const char * const aud_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_apll2_196m"

+};

+

+static const char * const a1sys_parents[] __initconst = {

+	"cb_cksq_40m",

+	"apll2_d4"

+};

+

+static const char * const aud_l_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_apll2_196m",

+	"m_d8_d2"

+};

+

+static const char * const a_tuner_parents[] __initconst = {

+	"cb_cksq_40m",

+	"apll2_d4",

+	"m_d8_d2"

+};

+

+static const char * const u2u3_parents[] __initconst = {

+	"cb_cksq_40m",

+	"m_d8_d2"

+};

+

+static const char * const u2u3_sys_parents[] __initconst = {

+	"cb_cksq_40m",

+	"net1_d5_d4"

+};

+

+static const char * const usb_frmcnt_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_mm_d3_d5"

+};

+

+static const struct mtk_mux top_muxes[] = {

+	/* CLK_CFG_0 */

+	MUX_GATE_CLR_SET_UPD(CK_TOP_NFI1X_SEL, "nfi1x_sel",

+	    nfi1x_parents, 0x000, 0x004, 0x008, 0, 3, 7, 0x1C0, 0),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_SPINFI_SEL, "spinfi_sel",

+	    spinfi_parents, 0x000, 0x004, 0x008, 8, 3, 15, 0x1C0, 1),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_SPI_SEL, "spi_sel",

+	    spi_parents, 0x000, 0x004, 0x008, 16, 3, 23, 0x1C0, 2),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_SPIM_MST_SEL, "spim_mst_sel",

+	    spi_parents, 0x000, 0x004, 0x008, 24, 3, 31, 0x1C0, 3),

+	/* CLK_CFG_1 */

+	MUX_GATE_CLR_SET_UPD(CK_TOP_UART_SEL, "uart_sel",

+	    uart_parents, 0x010, 0x014, 0x018, 0, 2, 7, 0x1C0, 4),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_PWM_SEL, "pwm_sel",

+	    pwm_parents, 0x010, 0x014, 0x018, 8, 3, 15, 0x1C0, 5),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_I2C_SEL, "i2c_sel",

+	    i2c_parents, 0x010, 0x014, 0x018, 16, 2, 23, 0x1C0, 6),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_TL_SEL, "pextp_tl_ck_sel",

+	    pextp_tl_ck_parents, 0x010, 0x014, 0x018, 24, 2, 31, 0x1C0, 7),

+	/* CLK_CFG_2 */

+	MUX_GATE_CLR_SET_UPD(CK_TOP_EMMC_208M_SEL, "emmc_208m_sel",

+	    emmc_208m_parents, 0x020, 0x024, 0x028, 0, 3, 7, 0x1C0, 8),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_EMMC_400M_SEL, "emmc_400m_sel",

+	    emmc_400m_parents, 0x020, 0x024, 0x028, 8, 2, 15, 0x1C0, 9),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_F26M_SEL, "csw_f26m_sel",

+	    csw_f26m_parents, 0x020, 0x024, 0x028, 16, 1, 23, 0x1C0, 10),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_DRAMC_SEL, "dramc_sel",

+	    csw_f26m_parents, 0x020, 0x024, 0x028, 24, 1, 31, 0x1C0, 11),

+	/* CLK_CFG_3 */

+	MUX_GATE_CLR_SET_UPD(CK_TOP_DRAMC_MD32_SEL, "dramc_md32_sel",

+	    dramc_md32_parents, 0x030, 0x034, 0x038, 0, 2, 7, 0x1C0, 12),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_SYSAXI_SEL, "sysaxi_sel",

+	    sysaxi_parents, 0x030, 0x034, 0x038, 8, 1, 15, 0x1C0, 13),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_SYSAPB_SEL, "sysapb_sel",

+	    sysapb_parents, 0x030, 0x034, 0x038, 16, 1, 23, 0x1C0, 14),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_ARM_DB_MAIN_SEL, "arm_db_main_sel",

+	    arm_db_main_parents, 0x030, 0x034, 0x038, 24, 1, 31, 0x1C0, 15),

+	/* CLK_CFG_4 */

+	MUX_GATE_CLR_SET_UPD(CK_TOP_AP2CNN_HOST_SEL, "ap2cnn_host_sel",

+	    ap2cnn_host_parents, 0x040, 0x044, 0x048, 0, 1, 7, 0x1C0, 16),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_SEL, "netsys_sel",

+	    netsys_parents, 0x040, 0x044, 0x048, 8, 1, 15, 0x1C0, 17),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_500M_SEL, "netsys_500m_sel",

+	    netsys_500m_parents, 0x040, 0x044, 0x048, 16, 1, 23, 0x1C0, 18),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_MCU_SEL, "netsys_mcu_sel",

+	    netsys_mcu_parents, 0x040, 0x044, 0x048, 24, 3, 31, 0x1C0, 19),

+	/* CLK_CFG_5 */

+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_2X_SEL, "netsys_2x_sel",

+	    netsys_2x_parents, 0x050, 0x054, 0x058, 0, 2, 7, 0x1C0, 20),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_SGM_325M_SEL, "sgm_325m_sel",

+	    sgm_325m_parents, 0x050, 0x054, 0x058, 8, 1, 15, 0x1C0, 21),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_SGM_REG_SEL, "sgm_reg_sel",

+	    sgm_reg_parents, 0x050, 0x054, 0x058, 16, 1, 23, 0x1C0, 22),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_EIP97B_SEL, "eip97b_sel",

+	    eip97b_parents, 0x050, 0x054, 0x058, 24, 3, 31, 0x1C0, 23),

+	/* CLK_CFG_6 */

+	MUX_GATE_CLR_SET_UPD(CK_TOP_USB3_PHY_SEL, "usb3_phy_sel",

+	    csw_f26m_parents, 0x060, 0x064, 0x068, 0, 1, 7, 0x1C0, 24),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_AUD_SEL, "aud_sel",

+	    aud_parents, 0x060, 0x064, 0x068, 8, 1, 15, 0x1C0, 25),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_A1SYS_SEL, "a1sys_sel",

+	    a1sys_parents, 0x060, 0x064, 0x068, 16, 1, 23, 0x1C0, 26),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_AUD_L_SEL, "aud_l_sel",

+	    aud_l_parents, 0x060, 0x064, 0x068, 24, 2, 31, 0x1C0, 27),

+	/* CLK_CFG_7 */

+	MUX_GATE_CLR_SET_UPD(CK_TOP_A_TUNER_SEL, "a_tuner_sel",

+	    a_tuner_parents, 0x070, 0x074, 0x078, 0, 2, 7, 0x1C0, 28),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_U2U3_SEL, "u2u3_sel",

+	    u2u3_parents, 0x070, 0x074, 0x078, 8, 1, 15, 0x1C0, 29),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_U2U3_SYS_SEL, "u2u3_sys_sel",

+	    u2u3_sys_parents, 0x070, 0x074, 0x078, 16, 1, 23, 0x1C0, 30),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_U2U3_XHCI_SEL, "u2u3_xhci_sel",

+	    u2u3_sys_parents, 0x070, 0x074, 0x078, 24, 1, 31, 0x1C4, 0),

+	/* CLK_CFG_8 */

+	MUX_GATE_CLR_SET_UPD(CK_TOP_USB_FRMCNT_SEL, "usb_frmcnt_sel",

+	    usb_frmcnt_parents, 0x080, 0x084, 0x088, 0, 1, 7, 0x1C4, 1),

+};

+

+static const char * const infra_uart0_parents[] __initconst = {

+	"infra_ck_f26m",

+	"infra_uart"

+};

+

+static const char * const infra_spi0_parents[] __initconst = {

+	"infra_i2c",

+	"infra_ispi0"

+};

+

+static const char * const infra_spi1_parents[] __initconst = {

+	"infra_i2c",

+	"infra_ispi1"

+};

+

+static const char * const infra_pwm1_parents[] __initconst = {

+	"infra_pwm"

+};

+

+static const char * const infra_pwm_bsel_parents[] __initconst = {

+	"infra_ck_f32k",

+	"infra_ck_f26m",

+	"infra_66m_mck",

+	"infra_pwm"

+};

+

+static const char * const infra_pcie_parents[] __initconst = {

+	"infra_ck_f32k",

+	"infra_ck_f26m",

+	"cb_cksq_40m",

+	"infra_pcie"

+};

+

+static const struct mtk_mux infra_muxes[] = {

+	/* MODULE_CLK_SEL_0 */

+	MUX_GATE_CLR_SET_UPD(CK_INFRA_UART0_SEL, "infra_uart0_sel",

+	    infra_uart0_parents, 0x0018, 0x0010, 0x0014, 0, 1, -1, -1, -1),

+	MUX_GATE_CLR_SET_UPD(CK_INFRA_UART1_SEL, "infra_uart1_sel",

+	    infra_uart0_parents, 0x0018, 0x0010, 0x0014, 1, 1, -1, -1, -1),

+	MUX_GATE_CLR_SET_UPD(CK_INFRA_UART2_SEL, "infra_uart2_sel",

+	    infra_uart0_parents, 0x0018, 0x0010, 0x0014, 2, 1, -1, -1, -1),

+	MUX_GATE_CLR_SET_UPD(CK_INFRA_SPI0_SEL, "infra_spi0_sel",

+	    infra_spi0_parents, 0x0018, 0x0010, 0x0014, 4, 1, -1, -1, -1),

+	MUX_GATE_CLR_SET_UPD(CK_INFRA_SPI1_SEL, "infra_spi1_sel",

+	    infra_spi1_parents, 0x0018, 0x0010, 0x0014, 5, 1, -1, -1, -1),

+	MUX_GATE_CLR_SET_UPD(CK_INFRA_SPI2_SEL, "infra_spi2_sel",

+	    infra_spi0_parents, 0x0018, 0x0010, 0x0014, 6, 1, -1, -1, -1),

+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM1_SEL, "infra_pwm1_sel",

+	    infra_pwm1_parents, 0x0018, 0x0010, 0x0014, 9, 1, -1, -1, -1),

+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM2_SEL, "infra_pwm2_sel",

+	    infra_pwm1_parents, 0x0018, 0x0010, 0x0014, 11, 1, -1, -1, -1),

+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM3_SEL, "infra_pwm3_sel",

+	    infra_pwm1_parents, 0x0018, 0x0010, 0x0014, 15, 1, -1, -1, -1),

+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM_BSEL, "infra_pwm_bsel",

+	    infra_pwm_bsel_parents, 0x0018, 0x0010, 0x0014, 13, 2, -1, -1, -1),

+	/* MODULE_CLK_SEL_1 */

+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PCIE_SEL, "infra_pcie_sel",

+	    infra_pcie_parents, 0x0028, 0x0020, 0x0024, 0, 2, -1, -1, -1),

+};

+

+static struct mtk_composite top_aud_divs[] = {

+	DIV_GATE(CK_TOP_AUD_I2S_M, "aud_i2s_m", "aud",

+		0x0420, 0, 0x0420, 8, 8),

+};

+

+static const struct mtk_gate_regs infra0_cg_regs = {

+	.set_ofs = 0x40,

+	.clr_ofs = 0x44,

+	.sta_ofs = 0x48,

+};

+

+static const struct mtk_gate_regs infra1_cg_regs = {

+	.set_ofs = 0x50,

+	.clr_ofs = 0x54,

+	.sta_ofs = 0x58,

+};

+

+static const struct mtk_gate_regs infra2_cg_regs = {

+	.set_ofs = 0x60,

+	.clr_ofs = 0x64,

+	.sta_ofs = 0x68,

+};

+

+#define GATE_INFRA0(_id, _name, _parent, _shift) {	\

+		.id = _id,				\

+		.name = _name,				\

+		.parent_name = _parent,			\

+		.regs = &infra0_cg_regs,			\

+		.shift = _shift,			\

+		.ops = &mtk_clk_gate_ops_setclr,	\

+	}

+

+#define GATE_INFRA1(_id, _name, _parent, _shift) {	\

+		.id = _id,				\

+		.name = _name,				\

+		.parent_name = _parent,			\

+		.regs = &infra1_cg_regs,			\

+		.shift = _shift,			\

+		.ops = &mtk_clk_gate_ops_setclr,	\

+	}

+

+#define GATE_INFRA2(_id, _name, _parent, _shift) {	\

+		.id = _id,				\

+		.name = _name,				\

+		.parent_name = _parent,			\

+		.regs = &infra2_cg_regs,			\

+		.shift = _shift,			\

+		.ops = &mtk_clk_gate_ops_setclr,	\

+	}

+

+static const struct mtk_gate infra_clks[] __initconst = {

+	/* INFRA0 */

+	GATE_INFRA0(CK_INFRA_GPT_STA, "infra_gpt_sta", "infra_66m_mck", 0),

+	GATE_INFRA0(CK_INFRA_PWM_HCK, "infra_pwm_hck", "infra_66m_mck", 1),

+	GATE_INFRA0(CK_INFRA_PWM_STA, "infra_pwm_sta", "infra_pwm_bck", 2),

+	GATE_INFRA0(CK_INFRA_PWM1_CK, "infra_pwm1", "infra_pwm_ck1", 3),

+	GATE_INFRA0(CK_INFRA_PWM2_CK, "infra_pwm2", "infra_pwm_ck2", 4),

+	GATE_INFRA0(CK_INFRA_CQ_DMA_CK, "infra_cq_dma", "infra_133m_hck", 6),

+	GATE_INFRA0(CK_INFRA_AUD_BUS_CK, "infra_aud_bus", "infra_66m_phck", 8),

+	GATE_INFRA0(CK_INFRA_AUD_26M_CK, "infra_aud_26m", "infra_ck_f26m", 9),

+	GATE_INFRA0(CK_INFRA_AUD_L_CK, "infra_aud_l", "infra_faud_l", 10),

+	GATE_INFRA0(CK_INFRA_AUD_AUD_CK, "infra_aud_aud", "infra_faud_aud", 11),

+	GATE_INFRA0(CK_INFRA_AUD_EG2_CK, "infra_aud_eg2", "infra_faud_eg2", 13),

+	GATE_INFRA0(CK_INFRA_DRAMC_26M_CK, "infra_dramc_26m", "infra_ck_f26m", 14),

+	GATE_INFRA0(CK_INFRA_DBG_CK, "infra_dbg", "infra_66m_mck", 15),

+	GATE_INFRA0(CK_INFRA_AP_DMA_CK, "infra_ap_dma", "infra_66m_mck", 16),

+	GATE_INFRA0(CK_INFRA_SEJ_CK, "infra_sej", "infra_66m_mck", 24),

+	GATE_INFRA0(CK_INFRA_SEJ_13M_CK, "infra_sej_13m", "infra_ck_f26m", 25),

+	GATE_INFRA0(CK_INFRA_PWM3_CK, "infra_pwm3", "infra_pwm3_sel", 27),

+	/* INFRA1 */

+	GATE_INFRA1(CK_INFRA_THERM_CK, "infra_therm", "infra_ck_f26m", 0),

+	GATE_INFRA1(CK_INFRA_I2CO_CK, "infra_i2co", "infra_i2cs", 1),

+	GATE_INFRA1(CK_INFRA_UART0_CK, "infra_uart0", "infra_mux_uart0", 2),

+	GATE_INFRA1(CK_INFRA_UART1_CK, "infra_uart1", "infra_mux_uart1", 3),

+	GATE_INFRA1(CK_INFRA_UART2_CK, "infra_uart2", "infra_mux_uart2", 4),

+	GATE_INFRA1(CK_INFRA_SPI2_CK, "infra_spi2", "infra_mux_spi2", 6),

+	GATE_INFRA1(CK_INFRA_SPI2_HCK_CK, "infra_spi2_hck", "infra_66m_mck", 7),

+	GATE_INFRA1(CK_INFRA_NFI1_CK, "infra_nfi1", "infra_nfi", 8),

+	GATE_INFRA1(CK_INFRA_SPINFI1_CK, "infra_spinfi1", "infra_spinfi", 9),

+	GATE_INFRA1(CK_INFRA_NFI_HCK_CK, "infra_nfi_hck", "infra_66m_mck", 10),

+	GATE_INFRA1(CK_INFRA_SPI0_CK, "infra_spi0", "infra_mux_spi0", 11),

+	GATE_INFRA1(CK_INFRA_SPI1_CK, "infra_spi1", "infra_mux_spi1", 12),

+	GATE_INFRA1(CK_INFRA_SPI0_HCK_CK, "infra_spi0_hck", "infra_66m_mck", 13),

+	GATE_INFRA1(CK_INFRA_SPI1_HCK_CK, "infra_spi1_hck", "infra_66m_mck", 14),

+	GATE_INFRA1(CK_INFRA_FRTC_CK, "infra_frtc", "infra_rtc_32k", 15),

+	GATE_INFRA1(CK_INFRA_MSDC_CK, "infra_msdc", "infra_fmsdc", 16),

+	GATE_INFRA1(CK_INFRA_MSDC_HCK_CK, "infra_msdc_hck", "infra_fmsdc_hck", 17),

+	GATE_INFRA1(CK_INFRA_MSDC_133M_CK, "infra_msdc_133m", "infra_peri_133m", 18),

+	GATE_INFRA1(CK_INFRA_MSDC_66M_CK, "infra_msdc_66m", "infra_66m_phck", 19),

+	GATE_INFRA1(CK_INFRA_ADC_26M_CK, "infra_adc_26m", "csw_f26m", 20),

+	GATE_INFRA1(CK_INFRA_ADC_FRC_CK, "infra_adc_frc", "csw_f26m", 21),

+	GATE_INFRA1(CK_INFRA_FBIST2FPC_CK, "infra_fbist2fpc", "infra_nfi", 23),

+	GATE_INFRA1(CK_INFRA_I2C_MCK_CK, "infra_i2c_mck", "infra_133m_mck", 25),

+	GATE_INFRA1(CK_INFRA_I2C_PCK_CK, "infra_i2c_pck", "infra_66m_mck", 26),

+	/* INFRA2 */

+	GATE_INFRA2(CK_INFRA_IUSB_133_CK, "infra_iusb_133", "infra_133m_phck", 0),

+	GATE_INFRA2(CK_INFRA_IUSB_66M_CK, "infra_iusb_66m", "infra_66m_phck", 1),

+	GATE_INFRA2(CK_INFRA_IUSB_SYS_CK, "infra_iusb_sys", "infra_usb_sys", 2),

+	GATE_INFRA2(CK_INFRA_IUSB_CK, "infra_iusb", "infra_usb", 3),

+	GATE_INFRA2(CK_INFRA_IPCIE_CK, "infra_ipcie", "infra_pcie_mux", 12),

+	GATE_INFRA2(CK_INFRA_IPCIE_PIPE_CK, "infra_ipcie_pipe", "cb_cksq_40m", 13),

+	GATE_INFRA2(CK_INFRA_IPCIER_CK, "infra_ipcier", "infra_f26m_ck0", 14),

+	GATE_INFRA2(CK_INFRA_IPCIEB_CK, "infra_ipcieb", "infra_133m_phck", 15),

+};

+

+static const struct mtk_gate_regs sgmii0_cg_regs = {

+	.set_ofs = 0xE4,

+	.clr_ofs = 0xE4,

+	.sta_ofs = 0xE4,

+};

+

+#define GATE_SGMII0(_id, _name, _parent, _shift) {	\

+		.id = _id,				\

+		.name = _name,				\

+		.parent_name = _parent,			\

+		.regs = &sgmii0_cg_regs,			\

+		.shift = _shift,			\

+		.ops = &mtk_clk_gate_ops_no_setclr_inv,	\

+	}

+

+static const struct mtk_gate sgmii0_clks[] __initconst = {

+	GATE_SGMII0(CK_SGM0_TX_EN, "sgm0_tx_en", "usb_tx250m", 2),

+	GATE_SGMII0(CK_SGM0_RX_EN, "sgm0_rx_en", "usb_eq_rx250m", 3),

+	GATE_SGMII0(CK_SGM0_CK0_EN, "sgm0_ck0_en", "usb_ln0", 4),

+	GATE_SGMII0(CK_SGM0_CDR_CK0_EN, "sgm0_cdr_ck0_en", "usb_cdr", 5),

+};

+

+static const struct mtk_gate_regs sgmii1_cg_regs = {

+	.set_ofs = 0xE4,

+	.clr_ofs = 0xE4,

+	.sta_ofs = 0xE4,

+};

+

+#define GATE_SGMII1(_id, _name, _parent, _shift) {	\

+		.id = _id,				\

+		.name = _name,				\

+		.parent_name = _parent,			\

+		.regs = &sgmii1_cg_regs,			\

+		.shift = _shift,			\

+		.ops = &mtk_clk_gate_ops_no_setclr_inv,	\

+	}

+

+static const struct mtk_gate sgmii1_clks[] __initconst = {

+	GATE_SGMII1(CK_SGM1_TX_EN, "sgm1_tx_en", "usb_tx250m", 2),

+	GATE_SGMII1(CK_SGM1_RX_EN, "sgm1_rx_en", "usb_eq_rx250m", 3),

+	GATE_SGMII1(CK_SGM1_CK1_EN, "sgm1_ck1_en", "usb_ln0", 4),

+	GATE_SGMII1(CK_SGM1_CDR_CK1_EN, "sgm1_cdr_ck1_en", "usb_cdr", 5),

+};

+

+static const struct mtk_gate_regs eth_cg_regs = {

+	.set_ofs = 0x30,

+	.clr_ofs = 0x30,

+	.sta_ofs = 0x30,

+};

+

+#define GATE_ETH(_id, _name, _parent, _shift) {	\

+		.id = _id,				\

+		.name = _name,				\

+		.parent_name = _parent,			\

+		.regs = &eth_cg_regs,			\

+		.shift = _shift,			\

+		.ops = &mtk_clk_gate_ops_no_setclr_inv,	\

+	}

+

+static const struct mtk_gate eth_clks[] __initconst = {

+	GATE_ETH(CK_ETH_FE_EN, "eth_fe_en", "netsys_2x", 6),

+	GATE_ETH(CK_ETH_GP2_EN, "eth_gp2_en", "sgm_325m", 7),

+	GATE_ETH(CK_ETH_GP1_EN, "eth_gp1_en", "sgm_325m", 8),

+	GATE_ETH(CK_ETH_WOCPU0_EN, "eth_wocpu0_en", "netsys_wed_mcu", 15),

+};

+

+#define MT7981_PLL_FMAX		(2500UL * MHZ)

+

+#define CON0_MT7981_RST_BAR	BIT(27)

+

+#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits,	\

+			_pd_reg, _pd_shift, _tuner_reg, _pcw_reg,	\

+			_pcw_shift, _div_table, _parent_name) {		\

+		.id = _id,						\

+		.name = _name,						\

+		.reg = _reg,						\

+		.pwr_reg = _pwr_reg,					\

+		.en_mask = _en_mask,					\

+		.flags = _flags,					\

+		.rst_bar_mask = CON0_MT7981_RST_BAR,			\

+		.fmax = MT7981_PLL_FMAX,				\

+		.pcwbits = _pcwbits,					\

+		.pd_reg = _pd_reg,					\

+		.pd_shift = _pd_shift,					\

+		.tuner_reg = _tuner_reg,				\

+		.pcw_reg = _pcw_reg,					\

+		.pcw_shift = _pcw_shift,				\

+		.div_table = _div_table,				\

+		.parent_name = _parent_name,				\

+	}

+

+#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits,	\

+			_pd_reg, _pd_shift, _tuner_reg, _pcw_reg,	\

+			_pcw_shift, _parent_name)				\

+		PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \

+			_pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \

+			NULL, _parent_name)

+

+static const struct mtk_pll_data plls[] = {

+	PLL(CK_APMIXED_ARMPLL, "armpll", 0x0200, 0x020C, 0x00000001,

+	    0, 32, 0x0200, 4, 0, 0x0204, 0, "clkxtal"),

+	PLL(CK_APMIXED_NET2PLL, "net2pll", 0x0210, 0x021C, 0x00000001,

+	    0, 32, 0x0210, 4, 0, 0x0214, 0, "clkxtal"),

+	PLL(CK_APMIXED_MMPLL, "mmpll", 0x0220, 0x022C, 0x00000001,

+	    0, 32, 0x0220, 4, 0, 0x0224, 0, "clkxtal"),

+	PLL(CK_APMIXED_SGMPLL, "sgmpll", 0x0230, 0x023C, 0x00000001,

+	    0, 32, 0x0230, 4, 0, 0x0234, 0, "clkxtal"),

+	PLL(CK_APMIXED_WEDMCUPLL, "wedmcupll", 0x0240, 0x024C, 0x00000001,

+	    0, 32, 0x0240, 4, 0, 0x0244, 0, "clkxtal"),

+	PLL(CK_APMIXED_NET1PLL, "net1pll", 0x0250, 0x025C, 0x00000001,

+	    0, 32, 0x0250, 4, 0, 0x0254, 0, "clkxtal"),

+	PLL(CK_APMIXED_MPLL, "mpll", 0x0260, 0x0270, 0x00000001,

+	    0, 32, 0x0260, 4, 0, 0x0264, 0, "clkxtal"),

+	PLL(CK_APMIXED_APLL2, "apll2", 0x0278, 0x0288, 0x00000001,

+	    0, 32, 0x0278, 4, 0, 0x027C, 0, "clkxtal"),

+};

+

+static struct clk_onecell_data *mt7981_top_clk_data __initdata;

+static struct clk_onecell_data *mt7981_pll_clk_data __initdata;

+

+static void __init mtk_clk_enable_critical(void)

+{

+	if (!mt7981_top_clk_data || !mt7981_pll_clk_data)

+		return;

+

+	clk_prepare_enable(mt7981_pll_clk_data->clks[CK_APMIXED_ARMPLL]);

+	clk_prepare_enable(mt7981_top_clk_data->clks[CK_TOP_SYSAXI_SEL]);

+	clk_prepare_enable(mt7981_top_clk_data->clks[CK_TOP_SYSAPB_SEL]);

+	clk_prepare_enable(mt7981_top_clk_data->clks[CK_TOP_DRAMC_SEL]);

+	clk_prepare_enable(mt7981_top_clk_data->clks[CK_TOP_DRAMC_MD32_SEL]);

+	clk_prepare_enable(mt7981_top_clk_data->clks[CK_TOP_F26M_SEL]);

+}

+

+static void __init mtk_infracfg_init(struct device_node *node)

+{

+	int r;

+

+

+	mt7981_top_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);

+

+	mtk_clk_register_factors(infra_divs, ARRAY_SIZE(infra_divs), mt7981_top_clk_data);

+

+	r = of_clk_add_provider(node, of_clk_src_onecell_get, mt7981_top_clk_data);

+

+	if (r)

+		pr_err("%s(): could not register clock provider: %d\n",

+			__func__, r);

+

+	mtk_clk_enable_critical();

+}

+CLK_OF_DECLARE(mtk_infracfg, "mediatek,mt7981-infracfg", mtk_infracfg_init);

+

+static void __init mtk_topckgen_init(struct device_node *node)

+{

+	int r;

+	void __iomem *base;

+

+	base = of_iomap(node, 0);

+	if (!base) {

+		pr_err("%s(): ioremap failed\n", __func__);

+		return;

+	}

+

+	mt7981_top_clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);

+

+	mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), mt7981_top_clk_data);

+	mtk_clk_register_muxes(top_muxes, ARRAY_SIZE(top_muxes), node, &mt7981_clk_lock, mt7981_top_clk_data);

+	mtk_clk_register_composites(top_aud_divs, ARRAY_SIZE(top_aud_divs),

+		base, &mt7981_clk_lock, mt7981_top_clk_data);

+

+	r = of_clk_add_provider(node, of_clk_src_onecell_get, mt7981_top_clk_data);

+

+	if (r)

+		pr_err("%s(): could not register clock provider: %d\n",

+			__func__, r);

+

+	mtk_clk_enable_critical();

+}

+CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt7981-topckgen", mtk_topckgen_init);

+

+static void __init mtk_infracfg_ao_init(struct device_node *node)

+{

+	struct clk_onecell_data *clk_data;

+	int r;

+	void __iomem *base;

+

+	base = of_iomap(node, 0);

+	if (!base) {

+		pr_err("%s(): ioremap failed\n", __func__);

+		return;

+	}

+

+	clk_data = mtk_alloc_clk_data(CLK_INFRA_AO_NR_CLK);

+

+	mtk_clk_register_muxes(infra_muxes, ARRAY_SIZE(infra_muxes), node, &mt7981_clk_lock, clk_data);

+	mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks), clk_data);

+

+	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);

+

+	if (r)

+		pr_err("%s(): could not register clock provider: %d\n",

+			__func__, r);

+}

+CLK_OF_DECLARE(mtk_infracfg_ao, "mediatek,mt7981-infracfg_ao", mtk_infracfg_ao_init);

+

+static void __init mtk_apmixedsys_init(struct device_node *node)

+{

+	int r;

+

+	mt7981_pll_clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK);

+

+	mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), mt7981_pll_clk_data);

+

+	r = of_clk_add_provider(node, of_clk_src_onecell_get, mt7981_pll_clk_data);

+

+	if (r)

+		pr_err("%s(): could not register clock provider: %d\n",

+			__func__, r);

+

+	mtk_clk_enable_critical();

+}

+CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt7981-apmixedsys", mtk_apmixedsys_init);

+

+static void __init mtk_sgmiisys_0_init(struct device_node *node)

+{

+	struct clk_onecell_data *clk_data;

+	int r;

+

+	clk_data = mtk_alloc_clk_data(CLK_SGMII0_NR_CLK);

+

+	mtk_clk_register_gates(node, sgmii0_clks, ARRAY_SIZE(sgmii0_clks), clk_data);

+

+	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);

+

+	if (r)

+		pr_err("%s(): could not register clock provider: %d\n",

+			__func__, r);

+}

+CLK_OF_DECLARE(mtk_sgmiisys_0, "mediatek,mt7981-sgmiisys_0", mtk_sgmiisys_0_init);

+

+static void __init mtk_sgmiisys_1_init(struct device_node *node)

+{

+	struct clk_onecell_data *clk_data;

+	int r;

+

+	clk_data = mtk_alloc_clk_data(CLK_SGMII1_NR_CLK);

+

+	mtk_clk_register_gates(node, sgmii1_clks, ARRAY_SIZE(sgmii1_clks), clk_data);

+

+	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);

+

+	if (r)

+		pr_err("%s(): could not register clock provider: %d\n",

+			__func__, r);

+}

+CLK_OF_DECLARE(mtk_sgmiisys_1, "mediatek,mt7981-sgmiisys_1", mtk_sgmiisys_1_init);

+

+static void __init mtk_ethsys_init(struct device_node *node)

+{

+	struct clk_onecell_data *clk_data;

+	int r;

+

+	clk_data = mtk_alloc_clk_data(CLK_ETH_NR_CLK);

+

+	mtk_clk_register_gates(node, eth_clks, ARRAY_SIZE(eth_clks), clk_data);

+

+	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);

+

+	if (r)

+		pr_err("%s(): could not register clock provider: %d\n",

+			__func__, r);

+}

+CLK_OF_DECLARE(mtk_ethsys, "mediatek,mt7981-ethsys", mtk_ethsys_init);

+

diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/clk/mediatek/clk-mt7986.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/clk/mediatek/clk-mt7986.c
new file mode 100644
index 0000000..2238414
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/clk/mediatek/clk-mt7986.c
@@ -0,0 +1,814 @@
+/*

+ * Copyright (c) 2021 MediaTek Inc.

+ * Author: Wenzhen Yu<Yenzhen.Yu@mediatek.com>

+ *

+ * This program is free software; you can redistribute it and/or modify

+ * it under the terms of the GNU General Public License version 2 as

+ * published by the Free Software Foundation.

+ *

+ * This program is distributed in the hope that it will be useful,

+ * but WITHOUT ANY WARRANTY; without even the implied warranty of

+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+ * GNU General Public License for more details.

+ */

+

+#include <linux/clk.h>

+#include <linux/delay.h>

+#include <linux/of.h>

+#include <linux/of_address.h>

+#include <linux/slab.h>

+#include <linux/mfd/syscon.h>

+

+#include "clk-mtk.h"

+#include "clk-gate.h"

+#include "clk-mux.h"

+

+

+#include <dt-bindings/clock/mt7986-clk.h>

+

+static DEFINE_SPINLOCK(mt7986_clk_lock);

+

+

+

+static const struct mtk_fixed_factor infra_divs[] __initconst = {

+	FACTOR(CK_INFRA_CK_F26M, "infra_ck_f26m", "csw_f26m_sel", 1, 1),

+	FACTOR(CK_INFRA_UART, "infra_uart", "uart_sel", 1, 1),

+	FACTOR(CK_INFRA_ISPI0, "infra_ispi0", "spi_sel", 1, 1),

+	FACTOR(CK_INFRA_I2C, "infra_i2c", "i2c_sel", 1, 1),

+	FACTOR(CK_INFRA_ISPI1, "infra_ispi1", "spim_mst_sel", 1, 1),

+	FACTOR(CK_INFRA_PWM, "infra_pwm", "pwm_sel", 1, 1),

+	FACTOR(CK_INFRA_66M_MCK, "infra_66m_mck", "sysaxi_sel", 1, 2),

+	FACTOR(CK_INFRA_CK_F32K, "infra_ck_f32k", "cb_rtc_32p7k", 1, 1),

+	FACTOR(CK_INFRA_PCIE_CK, "infra_pcie", "pextp_tl_ck_sel", 1, 1),

+	FACTOR(CK_INFRA_PWM_BCK, "infra_pwm_bck", "infra_pwm_bsel", 1, 1),

+	FACTOR(CK_INFRA_PWM_CK1, "infra_pwm_ck1", "infra_pwm1_sel", 1, 1),

+	FACTOR(CK_INFRA_PWM_CK2, "infra_pwm_ck2", "infra_pwm2_sel", 1, 1),

+	FACTOR(CK_INFRA_133M_HCK, "infra_133m_hck", "sysaxi", 1, 1),

+	FACTOR(CK_INFRA_EIP_CK, "infra_eip", "eip_b", 1, 1),

+	FACTOR(CK_INFRA_66M_PHCK, "infra_66m_phck", "infra_133m_hck", 1, 2),

+	FACTOR(CK_INFRA_FAUD_L_CK, "infra_faud_l", "aud_l", 1, 1),

+	FACTOR(CK_INFRA_FAUD_AUD_CK, "infra_faud_aud", "a1sys", 1, 1),

+	FACTOR(CK_INFRA_FAUD_EG2_CK, "infra_faud_eg2", "a_tuner", 1, 1),

+	FACTOR(CK_INFRA_I2CS_CK, "infra_i2cs", "i2c_bck", 1, 1),

+	FACTOR(CK_INFRA_MUX_UART0, "infra_mux_uart0", "infra_uart0_sel", 1, 1),

+	FACTOR(CK_INFRA_MUX_UART1, "infra_mux_uart1", "infra_uart1_sel", 1, 1),

+	FACTOR(CK_INFRA_MUX_UART2, "infra_mux_uart2", "infra_uart2_sel", 1, 1),

+	FACTOR(CK_INFRA_NFI_CK, "infra_nfi", "nfi1x", 1, 1),

+	FACTOR(CK_INFRA_SPINFI_CK, "infra_spinfi", "spinfi_bck", 1, 1),

+	FACTOR(CK_INFRA_MUX_SPI0, "infra_mux_spi0", "infra_spi0_sel", 1, 1),

+	FACTOR(CK_INFRA_MUX_SPI1, "infra_mux_spi1", "infra_spi1_sel", 1, 1),

+	FACTOR(CK_INFRA_RTC_32K, "infra_rtc_32k", "cb_rtc_32k", 1, 1),

+	FACTOR(CK_INFRA_FMSDC_CK, "infra_fmsdc", "emmc_416m", 1, 1),

+	FACTOR(CK_INFRA_FMSDC_HCK_CK, "infra_fmsdc_hck", "emmc_250m", 1, 1),

+	FACTOR(CK_INFRA_PERI_133M, "infra_peri_133m", "sysaxi", 1, 1),

+	FACTOR(CK_INFRA_133M_PHCK, "infra_133m_phck", "sysaxi", 1, 1),

+	FACTOR(CK_INFRA_USB_SYS_CK, "infra_usb_sys", "u2u3_sys", 1, 1),

+	FACTOR(CK_INFRA_USB_CK, "infra_usb", "u2u3_ref", 1, 1),

+	FACTOR(CK_INFRA_USB_XHCI_CK, "infra_usb_xhci", "u2u3_xhci", 1, 1),

+	FACTOR(CK_INFRA_PCIE_GFMUX_TL_O_PRE, "infra_pcie_mux", "pextp_tl", 1, 1),

+	FACTOR(CK_INFRA_F26M_CK0, "infra_f26m_ck0", "csw_f26m", 1, 1),

+	FACTOR(CK_INFRA_HD_133M, "infra_hd_133m", "sysaxi", 1, 1),

+};

+

+static const struct mtk_fixed_factor top_divs[] __initconst = {

+	FACTOR(CK_TOP_CB_CKSQ_40M, "cb_cksq_40m", "clkxtal", 1, 1),

+	FACTOR(CK_TOP_CB_M_416M, "cb_m_416m", "mpll", 1, 1),

+	FACTOR(CK_TOP_CB_M_D2, "cb_m_d2", "mpll", 1, 2),

+	FACTOR(CK_TOP_CB_M_D4, "cb_m_d4", "mpll", 1, 4),

+	FACTOR(CK_TOP_CB_M_D8, "cb_m_d8", "mpll", 1, 8),

+	FACTOR(CK_TOP_M_D8_D2, "m_d8_d2", "mpll", 1, 16),

+	FACTOR(CK_TOP_M_D3_D2, "m_d3_d2", "mpll", 1, 6),

+	FACTOR(CK_TOP_CB_MM_D2, "cb_mm_d2", "mmpll", 1, 2),

+	FACTOR(CK_TOP_CB_MM_D4, "cb_mm_d4", "mmpll", 1, 4),

+	FACTOR(CK_TOP_CB_MM_D8, "cb_mm_d8", "mmpll", 1, 8),

+	FACTOR(CK_TOP_MM_D8_D2, "mm_d8_d2", "mmpll", 1, 16),

+	FACTOR(CK_TOP_MM_D3_D8, "mm_d3_d8", "mmpll", 1, 24),

+	FACTOR(CK_TOP_CB_U2_PHYD_CK, "cb_u2_phyd", "mmpll", 1, 30),

+	FACTOR(CK_TOP_CB_APLL2_196M, "cb_apll2_196m", "apll2", 1, 1),

+	FACTOR(CK_TOP_APLL2_D4, "apll2_d4", "apll2", 1, 4),

+	FACTOR(CK_TOP_CB_NET1_D4, "cb_net1_d4", "net1pll", 1, 4),

+	FACTOR(CK_TOP_CB_NET1_D5, "cb_net1_d5", "net1pll", 1, 5),

+	FACTOR(CK_TOP_NET1_D5_D2, "net1_d5_d2", "net1pll", 1, 10),

+	FACTOR(CK_TOP_NET1_D5_D4, "net1_d5_d4", "net1pll", 1, 20),

+	FACTOR(CK_TOP_NET1_D8_D2, "net1_d8_d2", "net1pll", 1, 16),

+	FACTOR(CK_TOP_NET1_D8_D4, "net1_d8_d4", "net1pll", 1, 32),

+	FACTOR(CK_TOP_CB_NET2_800M, "cb_net2_800m", "net2pll", 1, 1),

+	FACTOR(CK_TOP_CB_NET2_D4, "cb_net2_d4", "net2pll", 1, 4),

+	FACTOR(CK_TOP_NET2_D4_D2, "net2_d4_d2", "net2pll", 1, 8),

+	FACTOR(CK_TOP_NET2_D3_D2, "net2_d3_d2", "net2pll", 1, 6),

+	FACTOR(CK_TOP_CB_WEDMCU_760M, "cb_wedmcu_760m", "wedmcupll", 1, 1),

+	FACTOR(CK_TOP_WEDMCU_D5_D2, "wedmcu_d5_d2", "wedmcupll", 1, 10),

+	FACTOR(CK_TOP_CB_SGM_325M, "cb_sgm_325m", "sgmpll", 1, 1),

+	FACTOR(CK_TOP_CB_CKSQ_40M_D2, "cb_cksq_40m_d2", "cb_cksq_40m", 1, 2),

+	FACTOR(CK_TOP_CB_RTC_32K, "cb_rtc_32k", "cb_cksq_40m", 1, 1250),

+	FACTOR(CK_TOP_CB_RTC_32P7K, "cb_rtc_32p7k", "cb_cksq_40m", 1, 1220),

+	FACTOR(CK_TOP_NFI1X, "nfi1x", "nfi1x_sel", 1, 1),

+	FACTOR(CK_TOP_USB_EQ_RX250M, "usb_eq_rx250m", "cb_cksq_40m", 1, 1),

+	FACTOR(CK_TOP_USB_TX250M, "usb_tx250m", "cb_cksq_40m", 1, 1),

+	FACTOR(CK_TOP_USB_LN0_CK, "usb_ln0", "cb_cksq_40m", 1, 1),

+	FACTOR(CK_TOP_USB_CDR_CK, "usb_cdr", "cb_cksq_40m", 1, 1),

+	FACTOR(CK_TOP_SPINFI_BCK, "spinfi_bck", "spinfi_sel", 1, 1),

+	FACTOR(CK_TOP_I2C_BCK, "i2c_bck", "i2c_sel", 1, 1),

+	FACTOR(CK_TOP_PEXTP_TL, "pextp_tl", "pextp_tl_ck_sel", 1, 1),

+	FACTOR(CK_TOP_EMMC_250M, "emmc_250m", "emmc_250m_sel", 1, 1),

+	FACTOR(CK_TOP_EMMC_416M, "emmc_416m", "emmc_416m_sel", 1, 1),

+	FACTOR(CK_TOP_F_26M_ADC_CK, "f_26m_adc", "f_26m_adc_sel", 1, 1),

+	FACTOR(CK_TOP_SYSAXI, "sysaxi", "sysaxi_sel", 1, 1),

+	FACTOR(CK_TOP_NETSYS_WED_MCU, "netsys_wed_mcu", "netsys_mcu_sel", 1, 1),

+	FACTOR(CK_TOP_NETSYS_2X, "netsys_2x", "netsys_2x_sel", 1, 1),

+	FACTOR(CK_TOP_SGM_325M, "sgm_325m", "sgm_325m_sel", 1, 1),

+	FACTOR(CK_TOP_A1SYS, "a1sys", "a1sys_sel", 1, 1),

+	FACTOR(CK_TOP_EIP_B, "eip_b", "eip_b_sel", 1, 1),

+	FACTOR(CK_TOP_F26M, "csw_f26m", "csw_f26m_sel", 1, 1),

+	FACTOR(CK_TOP_AUD_L, "aud_l", "aud_l_sel", 1, 1),

+	FACTOR(CK_TOP_A_TUNER, "a_tuner", "a_tuner_sel", 1, 1),

+	FACTOR(CK_TOP_U2U3_REF, "u2u3_ref", "u2u3_sel", 1, 1),

+	FACTOR(CK_TOP_U2U3_SYS, "u2u3_sys", "u2u3_sys_sel", 1, 1),

+	FACTOR(CK_TOP_U2U3_XHCI, "u2u3_xhci", "u2u3_xhci_sel", 1, 1),

+	FACTOR(CK_TOP_AP2CNN_HOST, "ap2cnn_host", "ap2cnn_host_sel", 1, 1),

+};

+

+static const char * const nfi1x_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_mm_d8",

+	"net1_d8_d2",

+	"net2_d3_d2",

+	"cb_m_d4",

+	"mm_d8_d2",

+	"wedmcu_d5_d2",

+	"cb_m_d8"

+};

+

+static const char * const spinfi_parents[] __initconst = {

+	"cb_cksq_40m_d2",

+	"cb_cksq_40m",

+	"net1_d5_d4",

+	"cb_m_d4",

+	"mm_d8_d2",

+	"wedmcu_d5_d2",

+	"mm_d3_d8",

+	"cb_m_d8"

+};

+

+static const char * const spi_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_m_d2",

+	"cb_mm_d8",

+	"net1_d8_d2",

+	"net2_d3_d2",

+	"net1_d5_d4",

+	"cb_m_d4",

+	"wedmcu_d5_d2"

+};

+

+static const char * const uart_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_m_d8",

+	"m_d8_d2"

+};

+

+static const char * const pwm_parents[] __initconst = {

+	"cb_cksq_40m",

+	"net1_d8_d2",

+	"net1_d5_d4",

+	"cb_m_d4"

+};

+

+static const char * const i2c_parents[] __initconst = {

+	"cb_cksq_40m",

+	"net1_d5_d4",

+	"cb_m_d4",

+	"net1_d8_d4"

+};

+

+static const char * const pextp_tl_ck_parents[] __initconst = {

+	"cb_cksq_40m",

+	"net1_d5_d4",

+	"net2_d4_d2",

+	"cb_rtc_32k"

+};

+

+static const char * const emmc_250m_parents[] __initconst = {

+	"cb_cksq_40m",

+	"net1_d5_d2"

+};

+

+static const char * const emmc_416m_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_m_416m"

+};

+

+static const char * const f_26m_adc_parents[] __initconst = {

+	"cb_cksq_40m",

+	"m_d8_d2"

+};

+

+static const char * const dramc_md32_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_m_d2"

+};

+

+static const char * const sysaxi_parents[] __initconst = {

+	"cb_cksq_40m",

+	"net1_d8_d2",

+	"cb_net2_d4"

+};

+

+static const char * const sysapb_parents[] __initconst = {

+	"cb_cksq_40m",

+	"m_d3_d2",

+	"net2_d4_d2"

+};

+

+static const char * const arm_db_main_parents[] __initconst = {

+	"cb_cksq_40m",

+	"net2_d3_d2"

+};

+

+static const char * const arm_db_jtsel_parents[] __initconst = {

+	"cb_jtck_50m",

+	"cb_cksq_40m"

+};

+

+static const char * const netsys_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_mm_d4"

+};

+

+static const char * const netsys_500m_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_net1_d5"

+};

+

+static const char * const netsys_mcu_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_wedmcu_760m",

+	"cb_mm_d2",

+	"cb_net1_d4",

+	"cb_net1_d5"

+};

+

+static const char * const netsys_2x_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_net2_800m",

+	"cb_wedmcu_760m",

+	"cb_mm_d2"

+};

+

+static const char * const sgm_325m_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_sgm_325m"

+};

+

+static const char * const sgm_reg_parents[] __initconst = {

+	"cb_cksq_40m",

+	"net1_d8_d4"

+};

+

+static const char * const a1sys_parents[] __initconst = {

+	"cb_cksq_40m",

+	"apll2_d4"

+};

+

+static const char * const conn_mcusys_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_mm_d2"

+};

+

+static const char * const eip_b_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_net2_800m"

+};

+

+static const char * const aud_l_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_apll2_196m",

+	"m_d8_d2"

+};

+

+static const char * const a_tuner_parents[] __initconst = {

+	"cb_cksq_40m",

+	"apll2_d4",

+	"m_d8_d2"

+};

+

+static const char * const u2u3_sys_parents[] __initconst = {

+	"cb_cksq_40m",

+	"net1_d5_d4"

+};

+

+static const char * const da_u2_refsel_parents[] __initconst = {

+	"cb_cksq_40m",

+	"cb_u2_phyd"

+};

+

+static const struct mtk_mux top_muxes[] = {

+	/* CLK_CFG_0 */

+	MUX_GATE_CLR_SET_UPD(CK_TOP_NFI1X_SEL, "nfi1x_sel",

+	    nfi1x_parents, 0x000, 0x004, 0x008, 0, 3, 7, 0x1C0, 0),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_SPINFI_SEL, "spinfi_sel",

+	    spinfi_parents, 0x000, 0x004, 0x008, 8, 3, 15, 0x1C0, 1),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_SPI_SEL, "spi_sel",

+	    spi_parents, 0x000, 0x004, 0x008, 16, 3, 23, 0x1C0, 2),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_SPIM_MST_SEL, "spim_mst_sel",

+	    spi_parents, 0x000, 0x004, 0x008, 24, 3, 31, 0x1C0, 3),

+	/* CLK_CFG_1 */

+	MUX_GATE_CLR_SET_UPD(CK_TOP_UART_SEL, "uart_sel",

+	    uart_parents, 0x010, 0x014, 0x018, 0, 2, 7, 0x1C0, 4),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_PWM_SEL, "pwm_sel",

+	    pwm_parents, 0x010, 0x014, 0x018, 8, 2, 15, 0x1C0, 5),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_I2C_SEL, "i2c_sel",

+	    i2c_parents, 0x010, 0x014, 0x018, 16, 2, 23, 0x1C0, 6),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_TL_SEL, "pextp_tl_ck_sel",

+	    pextp_tl_ck_parents, 0x010, 0x014, 0x018, 24, 2, 31, 0x1C0, 7),

+	/* CLK_CFG_2 */

+	MUX_GATE_CLR_SET_UPD(CK_TOP_EMMC_250M_SEL, "emmc_250m_sel",

+	    emmc_250m_parents, 0x020, 0x024, 0x028, 0, 1, 7, 0x1C0, 8),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_EMMC_416M_SEL, "emmc_416m_sel",

+	    emmc_416m_parents, 0x020, 0x024, 0x028, 8, 1, 15, 0x1C0, 9),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_F_26M_ADC_SEL, "f_26m_adc_sel",

+	    f_26m_adc_parents, 0x020, 0x024, 0x028, 16, 1, 23, 0x1C0, 10),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_DRAMC_SEL, "dramc_sel",

+	    f_26m_adc_parents, 0x020, 0x024, 0x028, 24, 1, 31, 0x1C0, 11),

+	/* CLK_CFG_3 */

+	MUX_GATE_CLR_SET_UPD(CK_TOP_DRAMC_MD32_SEL, "dramc_md32_sel",

+	    dramc_md32_parents, 0x030, 0x034, 0x038, 0, 1, 7, 0x1C0, 12),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_SYSAXI_SEL, "sysaxi_sel",

+	    sysaxi_parents, 0x030, 0x034, 0x038, 8, 2, 15, 0x1C0, 13),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_SYSAPB_SEL, "sysapb_sel",

+	    sysapb_parents, 0x030, 0x034, 0x038, 16, 2, 23, 0x1C0, 14),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_ARM_DB_MAIN_SEL, "arm_db_main_sel",

+	    arm_db_main_parents, 0x030, 0x034, 0x038, 24, 1, 31, 0x1C0, 15),

+	/* CLK_CFG_4 */

+	MUX_GATE_CLR_SET_UPD(CK_TOP_ARM_DB_JTSEL, "arm_db_jtsel",

+	    arm_db_jtsel_parents, 0x040, 0x044, 0x048, 0, 1, 7, 0x1C0, 16),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_SEL, "netsys_sel",

+	    netsys_parents, 0x040, 0x044, 0x048, 8, 1, 15, 0x1C0, 17),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_500M_SEL, "netsys_500m_sel",

+	    netsys_500m_parents, 0x040, 0x044, 0x048, 16, 1, 23, 0x1C0, 18),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_MCU_SEL, "netsys_mcu_sel",

+	    netsys_mcu_parents, 0x040, 0x044, 0x048, 24, 3, 31, 0x1C0, 19),

+	/* CLK_CFG_5 */

+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_2X_SEL, "netsys_2x_sel",

+	    netsys_2x_parents, 0x050, 0x054, 0x058, 0, 2, 7, 0x1C0, 20),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_SGM_325M_SEL, "sgm_325m_sel",

+	    sgm_325m_parents, 0x050, 0x054, 0x058, 8, 1, 15, 0x1C0, 21),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_SGM_REG_SEL, "sgm_reg_sel",

+	    sgm_reg_parents, 0x050, 0x054, 0x058, 16, 1, 23, 0x1C0, 22),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_A1SYS_SEL, "a1sys_sel",

+	    a1sys_parents, 0x050, 0x054, 0x058, 24, 1, 31, 0x1C0, 23),

+	/* CLK_CFG_6 */

+	MUX_GATE_CLR_SET_UPD(CK_TOP_CONN_MCUSYS_SEL, "conn_mcusys_sel",

+	    conn_mcusys_parents, 0x060, 0x064, 0x068, 0, 1, 7, 0x1C0, 24),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_EIP_B_SEL, "eip_b_sel",

+	    eip_b_parents, 0x060, 0x064, 0x068, 8, 1, 15, 0x1C0, 25),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_PCIE_PHY_SEL, "pcie_phy_sel",

+	    f_26m_adc_parents, 0x060, 0x064, 0x068, 16, 1, 23, 0x1C0, 26),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_USB3_PHY_SEL, "usb3_phy_sel",

+	    f_26m_adc_parents, 0x060, 0x064, 0x068, 24, 1, 31, 0x1C0, 27),

+	/* CLK_CFG_7 */

+	MUX_GATE_CLR_SET_UPD(CK_TOP_F26M_SEL, "csw_f26m_sel",

+	    f_26m_adc_parents, 0x070, 0x074, 0x078, 0, 1, 7, 0x1C0, 28),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_AUD_L_SEL, "aud_l_sel",

+	    aud_l_parents, 0x070, 0x074, 0x078, 8, 2, 15, 0x1C0, 29),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_A_TUNER_SEL, "a_tuner_sel",

+	    a_tuner_parents, 0x070, 0x074, 0x078, 16, 2, 23, 0x1C0, 30),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_U2U3_SEL, "u2u3_sel",

+	    f_26m_adc_parents, 0x070, 0x074, 0x078, 24, 1, 31, 0x1C4, 0),

+	/* CLK_CFG_8 */

+	MUX_GATE_CLR_SET_UPD(CK_TOP_U2U3_SYS_SEL, "u2u3_sys_sel",

+	    u2u3_sys_parents, 0x080, 0x084, 0x088, 0, 1, 7, 0x1C4, 1),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_U2U3_XHCI_SEL, "u2u3_xhci_sel",

+	    u2u3_sys_parents, 0x080, 0x084, 0x088, 8, 1, 15, 0x1C4, 2),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_DA_U2_REFSEL, "da_u2_refsel",

+	    da_u2_refsel_parents, 0x080, 0x084, 0x088, 16, 1, 23, 0x1C4, 3),

+	MUX_GATE_CLR_SET_UPD(CK_TOP_DA_U2_CK_1P_SEL, "da_u2_ck_1p_sel",

+	    da_u2_refsel_parents, 0x080, 0x084, 0x088, 24, 1, 31, 0x1C4, 4),

+	/* CLK_CFG_9 */

+	MUX_GATE_CLR_SET_UPD(CK_TOP_AP2CNN_HOST_SEL, "ap2cnn_host_sel",

+	    sgm_reg_parents, 0x090, 0x094, 0x098, 0, 1, 7, 0x1C4, 5),

+};

+

+static const char * const infra_uart0_parents[] __initconst = {

+	"infra_ck_f26m",

+	"infra_uart"

+};

+

+static const char * const infra_spi0_parents[] __initconst = {

+	"infra_i2c",

+	"infra_ispi0"

+};

+

+static const char * const infra_spi1_parents[] __initconst = {

+	"infra_i2c",

+	"infra_ispi1"

+};

+

+static const char * const infra_pwm_bsel_parents[] __initconst = {

+	"infra_ck_f32k",

+	"infra_ck_f26m",

+	"infra_66m_mck",

+	"infra_pwm"

+};

+

+static const char * const infra_pcie_parents[] __initconst = {

+	"infra_ck_f32k",

+	"infra_ck_f26m",

+	"cb_cksq_40m",

+	"infra_pcie"

+};

+

+static const struct mtk_mux infra_muxes[] = {

+	/* MODULE_CLK_SEL_0 */

+	MUX_GATE_CLR_SET_UPD(CK_INFRA_UART0_SEL, "infra_uart0_sel",

+	    infra_uart0_parents, 0x0018, 0x0010, 0x0014, 0, 1, -1, -1, -1),

+	MUX_GATE_CLR_SET_UPD(CK_INFRA_UART1_SEL, "infra_uart1_sel",

+	    infra_uart0_parents, 0x0018, 0x0010, 0x0014, 1, 1, -1, -1, -1),

+	MUX_GATE_CLR_SET_UPD(CK_INFRA_UART2_SEL, "infra_uart2_sel",

+	    infra_uart0_parents, 0x0018, 0x0010, 0x0014, 2, 1, -1, -1, -1),

+	MUX_GATE_CLR_SET_UPD(CK_INFRA_SPI0_SEL, "infra_spi0_sel",

+	    infra_spi0_parents, 0x0018, 0x0010, 0x0014, 4, 1, -1, -1, -1),

+	MUX_GATE_CLR_SET_UPD(CK_INFRA_SPI1_SEL, "infra_spi1_sel",

+	    infra_spi1_parents, 0x0018, 0x0010, 0x0014, 5, 1, -1, -1, -1),

+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM1_SEL, "infra_pwm1_sel",

+	    infra_pwm_bsel_parents, 0x0018, 0x0010, 0x0014, 9, 2, -1, -1, -1),

+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM2_SEL, "infra_pwm2_sel",

+	    infra_pwm_bsel_parents, 0x0018, 0x0010, 0x0014, 11, 2, -1, -1, -1),

+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM_BSEL, "infra_pwm_bsel",

+	    infra_pwm_bsel_parents, 0x0018, 0x0010, 0x0014, 13, 2, -1, -1, -1),

+	/* MODULE_CLK_SEL_1 */

+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PCIE_SEL, "infra_pcie_sel",

+	    infra_pcie_parents, 0x0028, 0x0020, 0x0024, 0, 2, -1, -1, -1),

+};

+

+

+

+static const struct mtk_gate_regs infra0_cg_regs = {

+	.set_ofs = 0x40,

+	.clr_ofs = 0x44,

+	.sta_ofs = 0x48,

+};

+

+static const struct mtk_gate_regs infra1_cg_regs = {

+	.set_ofs = 0x50,

+	.clr_ofs = 0x54,

+	.sta_ofs = 0x58,

+};

+

+static const struct mtk_gate_regs infra2_cg_regs = {

+	.set_ofs = 0x60,

+	.clr_ofs = 0x64,

+	.sta_ofs = 0x68,

+};

+

+#define GATE_INFRA0(_id, _name, _parent, _shift) {	\

+		.id = _id,				\

+		.name = _name,				\

+		.parent_name = _parent,			\

+		.regs = &infra0_cg_regs,			\

+		.shift = _shift,			\

+		.ops = &mtk_clk_gate_ops_setclr,	\

+	}

+

+#define GATE_INFRA1(_id, _name, _parent, _shift) {	\

+		.id = _id,				\

+		.name = _name,				\

+		.parent_name = _parent,			\

+		.regs = &infra1_cg_regs,			\

+		.shift = _shift,			\

+		.ops = &mtk_clk_gate_ops_setclr,	\

+	}

+

+#define GATE_INFRA2(_id, _name, _parent, _shift) {	\

+		.id = _id,				\

+		.name = _name,				\

+		.parent_name = _parent,			\

+		.regs = &infra2_cg_regs,			\

+		.shift = _shift,			\

+		.ops = &mtk_clk_gate_ops_setclr,	\

+	}

+

+static const struct mtk_gate infra_clks[] __initconst = {

+	/* INFRA0 */

+	GATE_INFRA0(CK_INFRA_PWM_HCK, "infra_pwm_hck", "infra_66m_mck", 1),

+	GATE_INFRA0(CK_INFRA_PWM_STA, "infra_pwm_sta", "infra_pwm_bck", 2),

+	GATE_INFRA0(CK_INFRA_PWM1_CK, "infra_pwm1", "infra_pwm_ck1", 3),

+	GATE_INFRA0(CK_INFRA_PWM2_CK, "infra_pwm2", "infra_pwm_ck2", 4),

+	GATE_INFRA0(CK_INFRA_CQ_DMA_CK, "infra_cq_dma", "infra_133m_hck", 6),

+	GATE_INFRA0(CK_INFRA_EIP97_CK, "infra_eip97", "infra_eip", 7),

+	GATE_INFRA0(CK_INFRA_AUD_BUS_CK, "infra_aud_bus", "infra_66m_phck", 8),

+	GATE_INFRA0(CK_INFRA_AUD_26M_CK, "infra_aud_26m", "infra_ck_f26m", 9),

+	GATE_INFRA0(CK_INFRA_AUD_L_CK, "infra_aud_l", "infra_faud_l", 10),

+	GATE_INFRA0(CK_INFRA_AUD_AUD_CK, "infra_aud_aud", "infra_faud_aud", 11),

+	GATE_INFRA0(CK_INFRA_AUD_EG2_CK, "infra_aud_eg2", "infra_faud_eg2", 13),

+	GATE_INFRA0(CK_INFRA_DRAMC_26M_CK, "infra_dramc_26m", "infra_ck_f26m", 14),

+	GATE_INFRA0(CK_INFRA_DBG_CK, "infra_dbg", "infra_66m_mck", 15),

+	GATE_INFRA0(CK_INFRA_AP_DMA_CK, "infra_ap_dma", "infra_66m_mck", 16),

+	GATE_INFRA0(CK_INFRA_SEJ_CK, "infra_sej", "infra_66m_mck", 24),

+	GATE_INFRA0(CK_INFRA_SEJ_13M_CK, "infra_sej_13m", "infra_ck_f26m", 25),

+	GATE_INFRA0(CK_INFRA_TRNG_CK, "infra_trng", "infra_hd_133m", 26),

+	/* INFRA1 */

+	GATE_INFRA1(CK_INFRA_THERM_CK, "infra_therm", "infra_ck_f26m", 0),

+	GATE_INFRA1(CK_INFRA_I2CO_CK, "infra_i2co", "infra_i2cs", 1),

+	GATE_INFRA1(CK_INFRA_UART0_CK, "infra_uart0", "infra_mux_uart0", 2),

+	GATE_INFRA1(CK_INFRA_UART1_CK, "infra_uart1", "infra_mux_uart1", 3),

+	GATE_INFRA1(CK_INFRA_UART2_CK, "infra_uart2", "infra_mux_uart2", 4),

+	GATE_INFRA1(CK_INFRA_NFI1_CK, "infra_nfi1", "infra_nfi", 8),

+	GATE_INFRA1(CK_INFRA_SPINFI1_CK, "infra_spinfi1", "infra_spinfi", 9),

+	GATE_INFRA1(CK_INFRA_NFI_HCK_CK, "infra_nfi_hck", "infra_66m_mck", 10),

+	GATE_INFRA1(CK_INFRA_SPI0_CK, "infra_spi0", "infra_mux_spi0", 11),

+	GATE_INFRA1(CK_INFRA_SPI1_CK, "infra_spi1", "infra_mux_spi1", 12),

+	GATE_INFRA1(CK_INFRA_SPI0_HCK_CK, "infra_spi0_hck", "infra_66m_mck", 13),

+	GATE_INFRA1(CK_INFRA_SPI1_HCK_CK, "infra_spi1_hck", "infra_66m_mck", 14),

+	GATE_INFRA1(CK_INFRA_FRTC_CK, "infra_frtc", "infra_rtc_32k", 15),

+	GATE_INFRA1(CK_INFRA_MSDC_CK, "infra_msdc", "infra_fmsdc", 16),

+	GATE_INFRA1(CK_INFRA_MSDC_HCK_CK, "infra_msdc_hck", "infra_fmsdc_hck", 17),

+	GATE_INFRA1(CK_INFRA_MSDC_133M_CK, "infra_msdc_133m", "infra_peri_133m", 18),

+	GATE_INFRA1(CK_INFRA_MSDC_66M_CK, "infra_msdc_66m", "infra_66m_phck", 19),

+	GATE_INFRA1(CK_INFRA_ADC_26M_CK, "infra_adc_26m", "csw_f26m", 20),

+	GATE_INFRA1(CK_INFRA_ADC_FRC_CK, "infra_adc_frc", "csw_f26m", 21),

+	GATE_INFRA1(CK_INFRA_FBIST2FPC_CK, "infra_fbist2fpc", "infra_nfi", 23),

+	/* INFRA2 */

+	GATE_INFRA2(CK_INFRA_IUSB_133_CK, "infra_iusb_133", "infra_133m_phck", 0),

+	GATE_INFRA2(CK_INFRA_IUSB_66M_CK, "infra_iusb_66m", "infra_66m_phck", 1),

+	GATE_INFRA2(CK_INFRA_IUSB_SYS_CK, "infra_iusb_sys", "infra_usb_sys", 2),

+	GATE_INFRA2(CK_INFRA_IUSB_CK, "infra_iusb", "infra_usb", 3),

+	GATE_INFRA2(CK_INFRA_IPCIE_CK, "infra_ipcie", "infra_pcie_mux", 12),

+	GATE_INFRA2(CK_INFRA_IPCIE_PIPE_CK, "infra_ipcie_pipe", "cb_cksq_40m", 13),

+	GATE_INFRA2(CK_INFRA_IPCIER_CK, "infra_ipcier", "infra_f26m_ck0", 14),

+	GATE_INFRA2(CK_INFRA_IPCIEB_CK, "infra_ipcieb", "infra_133m_phck", 15),

+};

+

+static const struct mtk_gate_regs sgmii0_cg_regs = {

+	.set_ofs = 0xE4,

+	.clr_ofs = 0xE4,

+	.sta_ofs = 0xE4,

+};

+

+#define GATE_SGMII0(_id, _name, _parent, _shift) {	\

+		.id = _id,				\

+		.name = _name,				\

+		.parent_name = _parent,			\

+		.regs = &sgmii0_cg_regs,			\

+		.shift = _shift,			\

+		.ops = &mtk_clk_gate_ops_no_setclr_inv,	\

+	}

+

+static const struct mtk_gate sgmii0_clks[] __initconst = {

+	GATE_SGMII0(CK_SGM0_TX_EN, "sgm0_tx_en", "usb_tx250m", 2),

+	GATE_SGMII0(CK_SGM0_RX_EN, "sgm0_rx_en", "usb_eq_rx250m", 3),

+	GATE_SGMII0(CK_SGM0_CK0_EN, "sgm0_ck0_en", "usb_ln0", 4),

+	GATE_SGMII0(CK_SGM0_CDR_CK0_EN, "sgm0_cdr_ck0_en", "usb_cdr", 5),

+};

+

+static const struct mtk_gate_regs sgmii1_cg_regs = {

+	.set_ofs = 0xE4,

+	.clr_ofs = 0xE4,

+	.sta_ofs = 0xE4,

+};

+

+#define GATE_SGMII1(_id, _name, _parent, _shift) {	\

+		.id = _id,				\

+		.name = _name,				\

+		.parent_name = _parent,			\

+		.regs = &sgmii1_cg_regs,			\

+		.shift = _shift,			\

+		.ops = &mtk_clk_gate_ops_no_setclr_inv,	\

+	}

+

+static const struct mtk_gate sgmii1_clks[] __initconst = {

+	GATE_SGMII1(CK_SGM1_TX_EN, "sgm1_tx_en", "usb_tx250m", 2),

+	GATE_SGMII1(CK_SGM1_RX_EN, "sgm1_rx_en", "usb_eq_rx250m", 3),

+	GATE_SGMII1(CK_SGM1_CK1_EN, "sgm1_ck1_en", "usb_ln0", 4),

+	GATE_SGMII1(CK_SGM1_CDR_CK1_EN, "sgm1_cdr_ck1_en", "usb_cdr", 5),

+};

+

+static const struct mtk_gate_regs eth_cg_regs = {

+	.set_ofs = 0x30,

+	.clr_ofs = 0x30,

+	.sta_ofs = 0x30,

+};

+

+#define GATE_ETH(_id, _name, _parent, _shift) {	\

+		.id = _id,				\

+		.name = _name,				\

+		.parent_name = _parent,			\

+		.regs = &eth_cg_regs,			\

+		.shift = _shift,			\

+		.ops = &mtk_clk_gate_ops_no_setclr_inv,	\

+	}

+

+static const struct mtk_gate eth_clks[] __initconst = {

+	GATE_ETH(CK_ETH_FE_EN, "eth_fe_en", "netsys_2x", 6),

+	GATE_ETH(CK_ETH_GP2_EN, "eth_gp2_en", "sgm_325m", 7),

+	GATE_ETH(CK_ETH_GP1_EN, "eth_gp1_en", "sgm_325m", 8),

+	GATE_ETH(CK_ETH_WOCPU1_EN, "eth_wocpu1_en", "netsys_wed_mcu", 14),

+	GATE_ETH(CK_ETH_WOCPU0_EN, "eth_wocpu0_en", "netsys_wed_mcu", 15),

+};

+

+#define MT7986_PLL_FMAX		(2500UL * MHZ)

+

+#define CON0_MT7986_RST_BAR	BIT(27)

+

+#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits,	\

+			_pd_reg, _pd_shift, _tuner_reg, _pcw_reg,	\

+			_pcw_shift, _div_table, _parent_name) {		\

+		.id = _id,						\

+		.name = _name,						\

+		.reg = _reg,						\

+		.pwr_reg = _pwr_reg,					\

+		.en_mask = _en_mask,					\

+		.flags = _flags,					\

+		.rst_bar_mask = CON0_MT7986_RST_BAR,			\

+		.fmax = MT7986_PLL_FMAX,				\

+		.pcwbits = _pcwbits,					\

+		.pd_reg = _pd_reg,					\

+		.pd_shift = _pd_shift,					\

+		.tuner_reg = _tuner_reg,				\

+		.pcw_reg = _pcw_reg,					\

+		.pcw_shift = _pcw_shift,				\

+		.div_table = _div_table,				\

+		.parent_name = _parent_name,				\

+	}

+

+#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits,	\

+			_pd_reg, _pd_shift, _tuner_reg, _pcw_reg,	\

+			_pcw_shift, _parent_name)				\

+		PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \

+			_pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \

+			NULL, _parent_name)

+

+static const struct mtk_pll_data plls[] = {

+	PLL(CK_APMIXED_ARMPLL, "armpll", 0x0200, 0x020C, 0x00000001,

+	    0, 32, 0x0200, 4, 0, 0x0204, 0, "clkxtal"),

+	PLL(CK_APMIXED_NET2PLL, "net2pll", 0x0210, 0x021C, 0x00000001,

+	    0, 32, 0x0210, 4, 0, 0x0214, 0, "clkxtal"),

+	PLL(CK_APMIXED_MMPLL, "mmpll", 0x0220, 0x022C, 0x00000001,

+	    0, 32, 0x0220, 4, 0, 0x0224, 0, "clkxtal"),

+	PLL(CK_APMIXED_SGMPLL, "sgmpll", 0x0230, 0x023c, 0x00000001,

+	    0, 32, 0x0230, 4, 0, 0x0234, 0, "clkxtal"),

+	PLL(CK_APMIXED_WEDMCUPLL, "wedmcupll", 0x0240, 0x024c, 0x00000001,

+	    0, 32, 0x0240, 4, 0, 0x0244, 0, "clkxtal"),

+	PLL(CK_APMIXED_NET1PLL, "net1pll", 0x0250, 0x025c, 0x00000001,

+	    0, 32, 0x0250, 4, 0, 0x0254, 0, "clkxtal"),

+	PLL(CK_APMIXED_MPLL, "mpll", 0x0260, 0x0270, 0x00000001,

+	    0, 32, 0x0260, 4, 0, 0x0264, 0, "clkxtal"),

+	PLL(CK_APMIXED_APLL2, "apll2", 0x0278, 0x0288, 0x00000001,

+	    0, 32, 0x0278, 4, 0, 0x027c, 0, "clkxtal"),

+};

+

+static struct clk_onecell_data *mt7986_top_clk_data __initdata;

+static struct clk_onecell_data *mt7986_pll_clk_data __initdata;

+

+static void __init mtk_clk_enable_critical(void)

+{

+	if (!mt7986_top_clk_data || !mt7986_pll_clk_data)

+		return;

+

+	clk_prepare_enable(mt7986_pll_clk_data->clks[CK_APMIXED_ARMPLL]);

+	clk_prepare_enable(mt7986_top_clk_data->clks[CK_TOP_SYSAXI_SEL]);

+	clk_prepare_enable(mt7986_top_clk_data->clks[CK_TOP_SYSAPB_SEL]);

+	clk_prepare_enable(mt7986_top_clk_data->clks[CK_TOP_DRAMC_SEL]);

+	clk_prepare_enable(mt7986_top_clk_data->clks[CK_TOP_DRAMC_MD32_SEL]);

+	clk_prepare_enable(mt7986_top_clk_data->clks[CK_TOP_F26M_SEL]);

+}

+

+static void __init mtk_infracfg_init(struct device_node *node)

+{

+	int r;

+

+

+	mt7986_top_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);

+

+	mtk_clk_register_factors(infra_divs, ARRAY_SIZE(infra_divs), mt7986_top_clk_data);

+

+	r = of_clk_add_provider(node, of_clk_src_onecell_get, mt7986_top_clk_data);

+

+	if (r)

+		pr_err("%s(): could not register clock provider: %d\n",

+			__func__, r);

+

+	mtk_clk_enable_critical();

+}

+CLK_OF_DECLARE(mtk_infracfg, "mediatek,mt7986-infracfg", mtk_infracfg_init);

+

+static void __init mtk_topckgen_init(struct device_node *node)

+{

+	int r;

+	void __iomem *base;

+

+	base = of_iomap(node, 0);

+	if (!base) {

+		pr_err("%s(): ioremap failed\n", __func__);

+		return;

+	}

+

+	mt7986_top_clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);

+

+	mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), mt7986_top_clk_data);

+	mtk_clk_register_muxes(top_muxes, ARRAY_SIZE(top_muxes), node, &mt7986_clk_lock, mt7986_top_clk_data);

+

+	r = of_clk_add_provider(node, of_clk_src_onecell_get, mt7986_top_clk_data);

+

+	if (r)

+		pr_err("%s(): could not register clock provider: %d\n",

+			__func__, r);

+

+	mtk_clk_enable_critical();

+}

+CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt7986-topckgen", mtk_topckgen_init);

+

+static void __init mtk_infracfg_ao_init(struct device_node *node)

+{

+	struct clk_onecell_data *clk_data;

+	int r;

+	void __iomem *base;

+

+	base = of_iomap(node, 0);

+	if (!base) {

+		pr_err("%s(): ioremap failed\n", __func__);

+		return;

+	}

+

+	clk_data = mtk_alloc_clk_data(CLK_INFRA_AO_NR_CLK);

+

+	mtk_clk_register_muxes(infra_muxes, ARRAY_SIZE(infra_muxes), node, &mt7986_clk_lock, clk_data);

+	mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks), clk_data);

+

+	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);

+

+	if (r)

+		pr_err("%s(): could not register clock provider: %d\n",

+			__func__, r);

+}

+CLK_OF_DECLARE(mtk_infracfg_ao, "mediatek,mt7986-infracfg_ao", mtk_infracfg_ao_init);

+

+static void __init mtk_apmixedsys_init(struct device_node *node)

+{

+	int r;

+

+	mt7986_pll_clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK);

+

+	mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), mt7986_pll_clk_data);

+

+	r = of_clk_add_provider(node, of_clk_src_onecell_get, mt7986_pll_clk_data);

+

+	if (r)

+		pr_err("%s(): could not register clock provider: %d\n",

+			__func__, r);

+

+	mtk_clk_enable_critical();

+}

+CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt7986-apmixedsys", mtk_apmixedsys_init);

+

+static void __init mtk_sgmiisys_0_init(struct device_node *node)

+{

+	struct clk_onecell_data *clk_data;

+	int r;

+

+	clk_data = mtk_alloc_clk_data(CLK_SGMII0_NR_CLK);

+

+	mtk_clk_register_gates(node, sgmii0_clks, ARRAY_SIZE(sgmii0_clks), clk_data);

+

+	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);

+

+	if (r)

+		pr_err("%s(): could not register clock provider: %d\n",

+			__func__, r);

+}

+CLK_OF_DECLARE(mtk_sgmiisys_0, "mediatek,mt7986-sgmiisys_0", mtk_sgmiisys_0_init);

+

+static void __init mtk_sgmiisys_1_init(struct device_node *node)

+{

+	struct clk_onecell_data *clk_data;

+	int r;

+

+	clk_data = mtk_alloc_clk_data(CLK_SGMII1_NR_CLK);

+

+	mtk_clk_register_gates(node, sgmii1_clks, ARRAY_SIZE(sgmii1_clks), clk_data);

+

+	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);

+

+	if (r)

+		pr_err("%s(): could not register clock provider: %d\n",

+			__func__, r);

+}

+CLK_OF_DECLARE(mtk_sgmiisys_1, "mediatek,mt7986-sgmiisys_1", mtk_sgmiisys_1_init);

+

+static void __init mtk_ethsys_init(struct device_node *node)

+{

+	struct clk_onecell_data *clk_data;

+	int r;

+

+	clk_data = mtk_alloc_clk_data(CLK_ETH_NR_CLK);

+

+	mtk_clk_register_gates(node, eth_clks, ARRAY_SIZE(eth_clks), clk_data);

+

+	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);

+

+	if (r)

+		pr_err("%s(): could not register clock provider: %d\n",

+			__func__, r);

+}

+CLK_OF_DECLARE(mtk_ethsys, "mediatek,mt7986-ethsys_ck", mtk_ethsys_init);

+

diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/leds/leds-ubnt-ledbar.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/leds/leds-ubnt-ledbar.c
new file mode 100644
index 0000000..1f50038
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/leds/leds-ubnt-ledbar.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
+
+/**
+ * Driver for the Ubiquiti RGB LED controller (LEDBAR).
+ * This Controller is based on a Holtek HT32F52241 and connected
+ * via I2C.
+ *
+ *  - The Controller needs an enable signal set to high when
+ *    performing a transaction. On the U6-LR, this is located
+ *    at Pin 18 (R6902)
+ *
+ *  - The Pin is also printed when calling the "usetled" function
+ *    contained in the ubntapp bootloader application.
+ */
+
+#define UBNT_LEDBAR_MAX_BRIGHTNESS		0xff
+
+#define UBNT_LEDBAR_TRANSACTION_LENGTH	8
+#define UBNT_LEDBAR_TRANSACTION_SUCCESS	0xaa
+
+#define UBNT_LEDBAR_TRANSACTION_BLUE_IDX	2
+#define UBNT_LEDBAR_TRANSACTION_GREEN_IDX	3
+#define UBNT_LEDBAR_TRANSACTION_RED_IDX		4
+
+struct ubnt_ledbar {
+	struct mutex lock;
+	struct i2c_client *client;
+	struct led_classdev led_red;
+	struct led_classdev led_green;
+	struct led_classdev led_blue;
+	struct gpio_desc *enable_gpio;
+};
+
+static int ubnt_ledbar_perform_transaction(struct ubnt_ledbar *ledbar,
+					   char *transaction)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < UBNT_LEDBAR_TRANSACTION_LENGTH; i++)
+		i2c_smbus_write_byte(ledbar->client, transaction[i]);
+
+	return i2c_smbus_read_byte(ledbar->client);
+}
+
+static int ubnt_ledbar_apply_state(struct ubnt_ledbar *ledbar)
+{
+	char setup_msg[UBNT_LEDBAR_TRANSACTION_LENGTH] = {0x40, 0x10, 0x00, 0x00,
+							  0x00, 0x00, 0x00, 0x11};
+	char led_msg[UBNT_LEDBAR_TRANSACTION_LENGTH] = {0x40, 0x00, 0x00, 0x00,
+							0x00, 0x00, 0x01, 0x00};
+	char i2c_response;
+	int ret = 0;
+
+	mutex_lock(&ledbar->lock);
+
+	led_msg[UBNT_LEDBAR_TRANSACTION_BLUE_IDX] = ledbar->led_blue.brightness;
+	led_msg[UBNT_LEDBAR_TRANSACTION_GREEN_IDX] = ledbar->led_green.brightness;
+	led_msg[UBNT_LEDBAR_TRANSACTION_RED_IDX] = ledbar->led_red.brightness;
+
+	gpiod_set_raw_value(ledbar->enable_gpio, 1);
+
+	msleep(10);
+
+	i2c_response = ubnt_ledbar_perform_transaction(ledbar, setup_msg);
+	if (i2c_response != UBNT_LEDBAR_TRANSACTION_SUCCESS) {
+		dev_err(&ledbar->client->dev, "Error initializing LED transaction: %02x\n", ret);
+		ret = -EINVAL;
+		goto out_gpio;
+	}
+
+	i2c_response = ubnt_ledbar_perform_transaction(ledbar, led_msg);
+	if (i2c_response != UBNT_LEDBAR_TRANSACTION_SUCCESS) {
+		dev_err(&ledbar->client->dev, "Failed LED transaction: %02x\n", ret);
+		ret = -EINVAL;
+		goto out_gpio;
+	}
+
+	msleep(10);
+out_gpio:
+	gpiod_set_raw_value(ledbar->enable_gpio, 0);
+
+	mutex_unlock(&ledbar->lock);
+
+	return ret;
+}
+
+#define UBNT_LEDBAR_CONTROL_RGBS(name)				\
+static int ubnt_ledbar_set_##name##_brightness(struct led_classdev *led_cdev,\
+					enum led_brightness value)	\
+{									\
+	struct ubnt_ledbar *ledbar = \
+			container_of(led_cdev, struct ubnt_ledbar, led_##name); \
+	int ret; \
+	led_cdev->brightness = value; \
+	ret = ubnt_ledbar_apply_state(ledbar); \
+	return ret; \
+}
+
+UBNT_LEDBAR_CONTROL_RGBS(red);
+UBNT_LEDBAR_CONTROL_RGBS(green);
+UBNT_LEDBAR_CONTROL_RGBS(blue);
+
+
+static int ubnt_ledbar_init_led(struct device_node *np, struct ubnt_ledbar *ledbar,
+				struct led_classdev *led_cdev)
+{
+	struct led_init_data init_data = {};
+	int ret;
+
+	if (!np)
+		return 0;
+
+	init_data.fwnode = of_fwnode_handle(np);
+
+	led_cdev->max_brightness = UBNT_LEDBAR_MAX_BRIGHTNESS;
+
+	ret = devm_led_classdev_register_ext(&ledbar->client->dev, led_cdev,
+					     &init_data);
+	if (ret)
+		dev_err(&ledbar->client->dev, "led register err: %d\n", ret);
+
+	return ret;
+}
+
+
+static int ubnt_ledbar_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	struct device_node *np = client->dev.of_node;
+	struct ubnt_ledbar *ledbar;
+	int ret;
+
+	ledbar = devm_kzalloc(&client->dev, sizeof(*ledbar), GFP_KERNEL);
+	if (!ledbar)
+		return -ENOMEM;
+
+	ledbar->enable_gpio = devm_gpiod_get(&client->dev, "enable", GPIOD_OUT_LOW);
+
+	if (IS_ERR(ledbar->enable_gpio)) {
+		ret = PTR_ERR(ledbar->enable_gpio);
+		dev_err(&client->dev, "Failed to get enable gpio: %d\n", ret);
+		return ret;
+	}
+
+	gpiod_direction_output(ledbar->enable_gpio, 0);
+
+	ledbar->client = client;
+
+	mutex_init(&ledbar->lock);
+
+	i2c_set_clientdata(client, ledbar);
+
+	ledbar->led_red.brightness_set_blocking = ubnt_ledbar_set_red_brightness;
+	ubnt_ledbar_init_led(of_get_child_by_name(np, "red"), ledbar, &ledbar->led_red);
+
+	ledbar->led_green.brightness_set_blocking = ubnt_ledbar_set_green_brightness;
+	ubnt_ledbar_init_led(of_get_child_by_name(np, "green"), ledbar, &ledbar->led_green);
+
+	ledbar->led_blue.brightness_set_blocking = ubnt_ledbar_set_blue_brightness;
+	ubnt_ledbar_init_led(of_get_child_by_name(np, "blue"), ledbar, &ledbar->led_blue);
+
+	return ubnt_ledbar_apply_state(ledbar);
+}
+
+static int ubnt_ledbar_remove(struct i2c_client *client)
+{
+	struct ubnt_ledbar *ledbar = i2c_get_clientdata(client);
+
+	mutex_destroy(&ledbar->lock);
+
+	return 0;
+}
+
+static const struct i2c_device_id ubnt_ledbar_id[] = {
+	{ "ubnt-ledbar", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ubnt_ledbar_id);
+
+static const struct of_device_id of_ubnt_ledbar_match[] = {
+	{ .compatible = "ubnt,ledbar", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, of_ubnt_ledbar_match);
+
+static struct i2c_driver ubnt_ledbar_driver = {
+	.driver = {
+		.name	= "ubnt-ledbar",
+		.of_match_table = of_ubnt_ledbar_match,
+	},
+	.probe		= ubnt_ledbar_probe,
+	.remove		= ubnt_ledbar_remove,
+	.id_table	= ubnt_ledbar_id,
+};
+module_i2c_driver(ubnt_ledbar_driver);
+
+MODULE_DESCRIPTION("Ubiquiti LEDBAR driver");
+MODULE_AUTHOR("David Bauer <mail@david-bauer.net>");
+MODULE_LICENSE("GPL v2");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/Kconfig b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/Kconfig
new file mode 100644
index 0000000..e15d2b0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/Kconfig
@@ -0,0 +1,3 @@
+menu "Mediatek Misc"
+source "drivers/misc/mediatek/ice_debug/Kconfig"
+endmenu
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/Makefile
new file mode 100644
index 0000000..55e7465
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MTK_ICE_DEBUG) +=ice_debug/
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/ice_debug/Kconfig b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/ice_debug/Kconfig
new file mode 100644
index 0000000..338f3d3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/ice_debug/Kconfig
@@ -0,0 +1,3 @@
+config MTK_ICE_DEBUG
+	bool "ICE_DEBUG"
+	default y if ARCH_MEDIATEK
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/ice_debug/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/ice_debug/Makefile
new file mode 100644
index 0000000..4d54159
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/ice_debug/Makefile
@@ -0,0 +1,14 @@
+#
+# Copyright (C) 2015 MediaTek Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+obj-$(CONFIG_MTK_ICE_DEBUG) += ice_debug.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/ice_debug/ice_debug.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/ice_debug/ice_debug.c
new file mode 100644
index 0000000..b677a45
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/misc/mediatek/ice_debug/ice_debug.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/clk.h>
+#include <linux/of_address.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+static const struct of_device_id mt2701_icedbg_match[] = {
+	{.compatible = "mediatek,mt2701-ice_debug", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mt2701_icedbg_match);
+
+static int mtk_ice_debug_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct clk *clk_icedbg;
+
+	clk_icedbg = devm_clk_get(&pdev->dev, "ice_dbg");
+	if (IS_ERR(clk_icedbg)) {
+		dev_err(&pdev->dev, "get ice_dbg clock fail: %ld\n",
+				PTR_ERR(clk_icedbg));
+		return PTR_ERR(clk_icedbg);
+	}
+
+	ret = clk_prepare_enable(clk_icedbg);
+	if (ret)
+		return ret;
+
+	/*enable CK_TOP_ARM_DB_JTSEL clk*/
+	clk_icedbg = devm_clk_get(&pdev->dev, "dbg_jtsel");
+	if (IS_ERR(clk_icedbg)) {
+		dev_err(&pdev->dev, "get dbg_sel clock fail: %ld\n",
+				PTR_ERR(clk_icedbg));
+		return PTR_ERR(clk_icedbg);
+	}
+
+	ret = clk_prepare_enable(clk_icedbg);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static struct platform_driver mtk_icedbg_driver = {
+	.probe = mtk_ice_debug_probe,
+	.driver = {
+		.name = "mediatek,mt2701-ice_debug",
+		.owner = THIS_MODULE,
+		.of_match_table = mt2701_icedbg_match,
+	},
+};
+
+static int __init mtk_ice_debug_init(void)
+{
+	return platform_driver_register(&mtk_icedbg_driver);
+}
+module_init(mtk_ice_debug_init);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MediaTek MT2701 ICE_DEBUG Driver");
+MODULE_AUTHOR("Maoguang Meng <maoguang.meng@mediatek.com>");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/Kconfig b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/Kconfig
new file mode 100644
index 0000000..138b939
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/Kconfig
@@ -0,0 +1,14 @@
+#
+# Copyright (C) 2020 MediaTek Inc. All rights reserved.
+# Author: Weijie Gao <weijie.gao@mediatek.com>
+#
+# SPDX-License-Identifier: GPL-2.0
+#
+
+config MTK_SPI_NAND
+	tristate "MediaTek SPI NAND flash controller driver"
+	depends on MTD
+	default n
+	help
+	  This option enables access to SPI-NAND flashes through the
+	  MTD interface of MediaTek SPI NAND Flash Controller
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/Makefile
new file mode 100644
index 0000000..a39f1ca
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright (C) 2020 MediaTek Inc. All rights reserved.
+# Author: Weijie Gao <weijie.gao@mediatek.com>
+#
+# SPDX-License-Identifier: GPL-2.0
+#
+
+obj-y += mtk-snand.o mtk-snand-ecc.o mtk-snand-ids.o mtk-snand-os.o \
+	 mtk-snand-mtd.o
+
+ccflags-y += -DPRIVATE_MTK_SNAND_HEADER
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-def.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-def.h
new file mode 100644
index 0000000..8058f7b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-def.h
@@ -0,0 +1,271 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#ifndef _MTK_SNAND_DEF_H_
+#define _MTK_SNAND_DEF_H_
+
+#include "mtk-snand-os.h"
+
+#ifdef PRIVATE_MTK_SNAND_HEADER
+#include "mtk-snand.h"
+#else
+#include <mtk-snand.h>
+#endif
+
+struct mtk_snand_plat_dev;
+
+enum snand_flash_io {
+	SNAND_IO_1_1_1,
+	SNAND_IO_1_1_2,
+	SNAND_IO_1_2_2,
+	SNAND_IO_1_1_4,
+	SNAND_IO_1_4_4,
+
+	__SNAND_IO_MAX
+};
+
+#define SPI_IO_1_1_1			BIT(SNAND_IO_1_1_1)
+#define SPI_IO_1_1_2			BIT(SNAND_IO_1_1_2)
+#define SPI_IO_1_2_2			BIT(SNAND_IO_1_2_2)
+#define SPI_IO_1_1_4			BIT(SNAND_IO_1_1_4)
+#define SPI_IO_1_4_4			BIT(SNAND_IO_1_4_4)
+
+struct snand_opcode {
+	uint8_t opcode;
+	uint8_t dummy;
+};
+
+struct snand_io_cap {
+	uint8_t caps;
+	struct snand_opcode opcodes[__SNAND_IO_MAX];
+};
+
+#define SNAND_OP(_io, _opcode, _dummy) [_io] = { .opcode = (_opcode), \
+						 .dummy = (_dummy) }
+
+#define SNAND_IO_CAP(_name, _caps, ...) \
+	struct snand_io_cap _name = { .caps = (_caps), \
+				      .opcodes = { __VA_ARGS__ } }
+
+#define SNAND_MAX_ID_LEN		4
+
+enum snand_id_type {
+	SNAND_ID_DYMMY,
+	SNAND_ID_ADDR = SNAND_ID_DYMMY,
+	SNAND_ID_DIRECT,
+
+	__SNAND_ID_TYPE_MAX
+};
+
+struct snand_id {
+	uint8_t type;	/* enum snand_id_type */
+	uint8_t len;
+	uint8_t id[SNAND_MAX_ID_LEN];
+};
+
+#define SNAND_ID(_type, ...) \
+	{ .type = (_type), .id = { __VA_ARGS__ }, \
+	  .len = sizeof((uint8_t[]) { __VA_ARGS__ }) }
+
+struct snand_mem_org {
+	uint16_t pagesize;
+	uint16_t sparesize;
+	uint16_t pages_per_block;
+	uint16_t blocks_per_die;
+	uint16_t planes_per_die;
+	uint16_t ndies;
+};
+
+#define SNAND_MEMORG(_ps, _ss, _ppb, _bpd, _ppd, _nd) \
+	{ .pagesize = (_ps), .sparesize = (_ss), .pages_per_block = (_ppb), \
+	  .blocks_per_die = (_bpd), .planes_per_die = (_ppd), .ndies = (_nd) }
+
+typedef int (*snand_select_die_t)(struct mtk_snand *snf, uint32_t dieidx);
+
+struct snand_flash_info {
+	const char *model;
+	struct snand_id id;
+	const struct snand_mem_org memorg;
+	const struct snand_io_cap *cap_rd;
+	const struct snand_io_cap *cap_pl;
+	snand_select_die_t select_die;
+};
+
+#define SNAND_INFO(_model, _id, _memorg, _cap_rd, _cap_pl, ...) \
+	{ .model = (_model), .id = _id, .memorg = _memorg, \
+	  .cap_rd = (_cap_rd), .cap_pl = (_cap_pl), __VA_ARGS__ }
+
+const struct snand_flash_info *snand_flash_id_lookup(enum snand_id_type type,
+						     const uint8_t *id);
+
+struct mtk_snand_soc_data {
+	uint16_t sector_size;
+	uint16_t max_sectors;
+	uint16_t fdm_size;
+	uint16_t fdm_ecc_size;
+	uint16_t fifo_size;
+
+	bool bbm_swap;
+	bool empty_page_check;
+	uint32_t mastersta_mask;
+
+	const uint8_t *spare_sizes;
+	uint32_t num_spare_size;
+
+	uint16_t latch_lat;
+	uint16_t sample_delay;
+};
+
+enum mtk_ecc_regs {
+	ECC_DECDONE,
+};
+
+struct mtk_ecc_soc_data {
+	const uint8_t *ecc_caps;
+	uint32_t num_ecc_cap;
+	const uint32_t *regs;
+	uint16_t mode_shift;
+	uint8_t errnum_bits;
+	uint8_t errnum_shift;
+};
+
+struct mtk_snand {
+	struct mtk_snand_plat_dev *pdev;
+
+	void __iomem *nfi_base;
+	void __iomem *ecc_base;
+
+	enum mtk_snand_soc soc;
+	const struct mtk_snand_soc_data *nfi_soc;
+	const struct mtk_ecc_soc_data *ecc_soc;
+	bool snfi_quad_spi;
+	bool quad_spi_op;
+
+	const char *model;
+	uint64_t size;
+	uint64_t die_size;
+	uint32_t erasesize;
+	uint32_t writesize;
+	uint32_t oobsize;
+
+	uint32_t num_dies;
+	snand_select_die_t select_die;
+
+	uint8_t opcode_rfc;
+	uint8_t opcode_pl;
+	uint8_t dummy_rfc;
+	uint8_t mode_rfc;
+	uint8_t mode_pl;
+
+	uint32_t writesize_mask;
+	uint32_t writesize_shift;
+	uint32_t erasesize_mask;
+	uint32_t erasesize_shift;
+	uint64_t die_mask;
+	uint32_t die_shift;
+
+	uint32_t spare_per_sector;
+	uint32_t raw_sector_size;
+	uint32_t ecc_strength;
+	uint32_t ecc_steps;
+	uint32_t ecc_bytes;
+	uint32_t ecc_parity_bits;
+
+	uint8_t *page_cache;	/* Used by read/write page */
+	uint8_t *buf_cache;	/* Used by block bad/markbad & auto_oob */
+	int *sect_bf;		/* Used by ECC correction */
+};
+
+enum mtk_snand_log_category {
+	SNAND_LOG_NFI,
+	SNAND_LOG_SNFI,
+	SNAND_LOG_ECC,
+	SNAND_LOG_CHIP,
+
+	__SNAND_LOG_CAT_MAX
+};
+
+int mtk_ecc_setup(struct mtk_snand *snf, void *fmdaddr, uint32_t max_ecc_bytes,
+		  uint32_t msg_size);
+int mtk_snand_ecc_encoder_start(struct mtk_snand *snf);
+void mtk_snand_ecc_encoder_stop(struct mtk_snand *snf);
+int mtk_snand_ecc_decoder_start(struct mtk_snand *snf);
+void mtk_snand_ecc_decoder_stop(struct mtk_snand *snf);
+int mtk_ecc_wait_decoder_done(struct mtk_snand *snf);
+int mtk_ecc_check_decode_error(struct mtk_snand *snf);
+int mtk_ecc_fixup_empty_sector(struct mtk_snand *snf, uint32_t sect);
+
+int mtk_snand_mac_io(struct mtk_snand *snf, const uint8_t *out, uint32_t outlen,
+		     uint8_t *in, uint32_t inlen);
+int mtk_snand_set_feature(struct mtk_snand *snf, uint32_t addr, uint32_t val);
+
+int mtk_snand_log(struct mtk_snand_plat_dev *pdev,
+		  enum mtk_snand_log_category cat, const char *fmt, ...);
+
+#define snand_log_nfi(pdev, fmt, ...) \
+	mtk_snand_log(pdev, SNAND_LOG_NFI, fmt, ##__VA_ARGS__)
+
+#define snand_log_snfi(pdev, fmt, ...) \
+	mtk_snand_log(pdev, SNAND_LOG_SNFI, fmt, ##__VA_ARGS__)
+
+#define snand_log_ecc(pdev, fmt, ...) \
+	mtk_snand_log(pdev, SNAND_LOG_ECC, fmt, ##__VA_ARGS__)
+
+#define snand_log_chip(pdev, fmt, ...) \
+	mtk_snand_log(pdev, SNAND_LOG_CHIP, fmt, ##__VA_ARGS__)
+
+/* ffs64 */
+static inline int mtk_snand_ffs64(uint64_t x)
+{
+	if (!x)
+		return 0;
+
+	if (!(x & 0xffffffff))
+		return ffs((uint32_t)(x >> 32)) + 32;
+
+	return ffs((uint32_t)(x & 0xffffffff));
+}
+
+/* NFI dummy commands */
+#define NFI_CMD_DUMMY_READ		0x00
+#define NFI_CMD_DUMMY_WRITE		0x80
+
+/* SPI-NAND opcodes */
+#define SNAND_CMD_RESET			0xff
+#define SNAND_CMD_BLOCK_ERASE		0xd8
+#define SNAND_CMD_READ_FROM_CACHE_QUAD	0xeb
+#define SNAND_CMD_WINBOND_SELECT_DIE	0xc2
+#define SNAND_CMD_READ_FROM_CACHE_DUAL	0xbb
+#define SNAND_CMD_READID		0x9f
+#define SNAND_CMD_READ_FROM_CACHE_X4	0x6b
+#define SNAND_CMD_READ_FROM_CACHE_X2	0x3b
+#define SNAND_CMD_PROGRAM_LOAD_X4	0x32
+#define SNAND_CMD_SET_FEATURE		0x1f
+#define SNAND_CMD_READ_TO_CACHE		0x13
+#define SNAND_CMD_PROGRAM_EXECUTE	0x10
+#define SNAND_CMD_GET_FEATURE		0x0f
+#define SNAND_CMD_READ_FROM_CACHE	0x0b
+#define SNAND_CMD_WRITE_ENABLE		0x06
+#define SNAND_CMD_PROGRAM_LOAD		0x02
+
+/* SPI-NAND feature addresses */
+#define SNAND_FEATURE_MICRON_DIE_ADDR	0xd0
+#define SNAND_MICRON_DIE_SEL_1		BIT(6)
+
+#define SNAND_FEATURE_STATUS_ADDR	0xc0
+#define SNAND_STATUS_OIP		BIT(0)
+#define SNAND_STATUS_WEL		BIT(1)
+#define SNAND_STATUS_ERASE_FAIL		BIT(2)
+#define SNAND_STATUS_PROGRAM_FAIL	BIT(3)
+
+#define SNAND_FEATURE_CONFIG_ADDR	0xb0
+#define SNAND_FEATURE_QUAD_ENABLE	BIT(0)
+#define SNAND_FEATURE_ECC_EN		BIT(4)
+
+#define SNAND_FEATURE_PROTECT_ADDR	0xa0
+
+#endif /* _MTK_SNAND_DEF_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-ecc.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-ecc.c
new file mode 100644
index 0000000..4094339
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-ecc.c
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include "mtk-snand-def.h"
+
+/* ECC registers */
+#define ECC_ENCCON			0x000
+#define ENC_EN				BIT(0)
+
+#define ECC_ENCCNFG			0x004
+#define ENC_MS_S			16
+#define ENC_BURST_EN			BIT(8)
+#define ENC_TNUM_S			0
+
+#define ECC_ENCIDLE			0x00c
+#define ENC_IDLE			BIT(0)
+
+#define ECC_DECCON			0x100
+#define DEC_EN				BIT(0)
+
+#define ECC_DECCNFG			0x104
+#define DEC_EMPTY_EN			BIT(31)
+#define DEC_CS_S			16
+#define DEC_CON_S			12
+#define   DEC_CON_CORRECT		3
+#define DEC_BURST_EN			BIT(8)
+#define DEC_TNUM_S			0
+
+#define ECC_DECIDLE			0x10c
+#define DEC_IDLE			BIT(0)
+
+#define ECC_DECENUM0			0x114
+#define ECC_DECENUM(n)			(ECC_DECENUM0 + (n) * 4)
+
+/* ECC_ENCIDLE & ECC_DECIDLE */
+#define ECC_IDLE			BIT(0)
+
+/* ENC_MODE & DEC_MODE */
+#define ECC_MODE_NFI			1
+
+#define ECC_TIMEOUT			500000
+
+static const uint8_t mt7622_ecc_caps[] = { 4, 6, 8, 10, 12 };
+
+static const uint8_t mt7986_ecc_caps[] = {
+	4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24
+};
+
+static const uint32_t mt7622_ecc_regs[] = {
+	[ECC_DECDONE] = 0x11c,
+};
+
+static const uint32_t mt7986_ecc_regs[] = {
+	[ECC_DECDONE] = 0x124,
+};
+
+static const struct mtk_ecc_soc_data mtk_ecc_socs[__SNAND_SOC_MAX] = {
+	[SNAND_SOC_MT7622] = {
+		.ecc_caps = mt7622_ecc_caps,
+		.num_ecc_cap = ARRAY_SIZE(mt7622_ecc_caps),
+		.regs = mt7622_ecc_regs,
+		.mode_shift = 4,
+		.errnum_bits = 5,
+		.errnum_shift = 5,
+	},
+	[SNAND_SOC_MT7629] = {
+		.ecc_caps = mt7622_ecc_caps,
+		.num_ecc_cap = ARRAY_SIZE(mt7622_ecc_caps),
+		.regs = mt7622_ecc_regs,
+		.mode_shift = 4,
+		.errnum_bits = 5,
+		.errnum_shift = 5,
+	},
+	[SNAND_SOC_MT7986] = {
+		.ecc_caps = mt7986_ecc_caps,
+		.num_ecc_cap = ARRAY_SIZE(mt7986_ecc_caps),
+		.regs = mt7986_ecc_regs,
+		.mode_shift = 5,
+		.errnum_bits = 5,
+		.errnum_shift = 8,
+	},
+};
+
+static inline uint32_t ecc_read32(struct mtk_snand *snf, uint32_t reg)
+{
+	return readl(snf->ecc_base + reg);
+}
+
+static inline void ecc_write32(struct mtk_snand *snf, uint32_t reg,
+			       uint32_t val)
+{
+	writel(val, snf->ecc_base + reg);
+}
+
+static inline void ecc_write16(struct mtk_snand *snf, uint32_t reg,
+			       uint16_t val)
+{
+	writew(val, snf->ecc_base + reg);
+}
+
+static int mtk_ecc_poll(struct mtk_snand *snf, uint32_t reg, uint32_t bits)
+{
+	uint32_t val;
+
+	return read16_poll_timeout(snf->ecc_base + reg, val, (val & bits), 0,
+				   ECC_TIMEOUT);
+}
+
+static int mtk_ecc_wait_idle(struct mtk_snand *snf, uint32_t reg)
+{
+	int ret;
+
+	ret = mtk_ecc_poll(snf, reg, ECC_IDLE);
+	if (ret) {
+		snand_log_ecc(snf->pdev, "ECC engine is busy\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+int mtk_ecc_setup(struct mtk_snand *snf, void *fmdaddr, uint32_t max_ecc_bytes,
+		  uint32_t msg_size)
+{
+	uint32_t i, val, ecc_msg_bits, ecc_strength;
+	int ret;
+
+	snf->ecc_soc = &mtk_ecc_socs[snf->soc];
+
+	snf->ecc_parity_bits = fls(1 + 8 * msg_size);
+	ecc_strength = max_ecc_bytes * 8 / snf->ecc_parity_bits;
+
+	for (i = snf->ecc_soc->num_ecc_cap - 1; i >= 0; i--) {
+		if (snf->ecc_soc->ecc_caps[i] <= ecc_strength)
+			break;
+	}
+
+	if (unlikely(i < 0)) {
+		snand_log_ecc(snf->pdev, "Page size %u+%u is not supported\n",
+			      snf->writesize, snf->oobsize);
+		return -ENOTSUPP;
+	}
+
+	snf->ecc_strength = snf->ecc_soc->ecc_caps[i];
+	snf->ecc_bytes = DIV_ROUND_UP(snf->ecc_strength * snf->ecc_parity_bits,
+				      8);
+
+	/* Encoder config */
+	ecc_write16(snf, ECC_ENCCON, 0);
+	ret = mtk_ecc_wait_idle(snf, ECC_ENCIDLE);
+	if (ret)
+		return ret;
+
+	ecc_msg_bits = msg_size * 8;
+	val = (ecc_msg_bits << ENC_MS_S) |
+	      (ECC_MODE_NFI << snf->ecc_soc->mode_shift) | i;
+	ecc_write32(snf, ECC_ENCCNFG, val);
+
+	/* Decoder config */
+	ecc_write16(snf, ECC_DECCON, 0);
+	ret = mtk_ecc_wait_idle(snf, ECC_DECIDLE);
+	if (ret)
+		return ret;
+
+	ecc_msg_bits += snf->ecc_strength * snf->ecc_parity_bits;
+	val = DEC_EMPTY_EN | (ecc_msg_bits << DEC_CS_S) |
+	      (DEC_CON_CORRECT << DEC_CON_S) |
+	      (ECC_MODE_NFI << snf->ecc_soc->mode_shift) | i;
+	ecc_write32(snf, ECC_DECCNFG, val);
+
+	return 0;
+}
+
+int mtk_snand_ecc_encoder_start(struct mtk_snand *snf)
+{
+	int ret;
+
+	ret = mtk_ecc_wait_idle(snf, ECC_ENCIDLE);
+	if (ret) {
+		ecc_write16(snf, ECC_ENCCON, 0);
+		mtk_ecc_wait_idle(snf, ECC_ENCIDLE);
+	}
+
+	ecc_write16(snf, ECC_ENCCON, ENC_EN);
+
+	return 0;
+}
+
+void mtk_snand_ecc_encoder_stop(struct mtk_snand *snf)
+{
+	mtk_ecc_wait_idle(snf, ECC_ENCIDLE);
+	ecc_write16(snf, ECC_ENCCON, 0);
+}
+
+int mtk_snand_ecc_decoder_start(struct mtk_snand *snf)
+{
+	int ret;
+
+	ret = mtk_ecc_wait_idle(snf, ECC_DECIDLE);
+	if (ret) {
+		ecc_write16(snf, ECC_DECCON, 0);
+		mtk_ecc_wait_idle(snf, ECC_DECIDLE);
+	}
+
+	ecc_write16(snf, ECC_DECCON, DEC_EN);
+
+	return 0;
+}
+
+void mtk_snand_ecc_decoder_stop(struct mtk_snand *snf)
+{
+	mtk_ecc_wait_idle(snf, ECC_DECIDLE);
+	ecc_write16(snf, ECC_DECCON, 0);
+}
+
+int mtk_ecc_wait_decoder_done(struct mtk_snand *snf)
+{
+	uint16_t val, step_mask = (1 << snf->ecc_steps) - 1;
+	uint32_t reg = snf->ecc_soc->regs[ECC_DECDONE];
+	int ret;
+
+	ret = read16_poll_timeout(snf->ecc_base + reg, val,
+				  (val & step_mask) == step_mask, 0,
+				  ECC_TIMEOUT);
+	if (ret)
+		snand_log_ecc(snf->pdev, "ECC decoder is busy\n");
+
+	return ret;
+}
+
+int mtk_ecc_check_decode_error(struct mtk_snand *snf)
+{
+	uint32_t i, regi, fi, errnum;
+	uint32_t errnum_shift = snf->ecc_soc->errnum_shift;
+	uint32_t errnum_mask = (1 << snf->ecc_soc->errnum_bits) - 1;
+	int ret = 0;
+
+	for (i = 0; i < snf->ecc_steps; i++) {
+		regi = i / 4;
+		fi = i % 4;
+
+		errnum = ecc_read32(snf, ECC_DECENUM(regi));
+		errnum = (errnum >> (fi * errnum_shift)) & errnum_mask;
+
+		if (errnum <= snf->ecc_strength) {
+			snf->sect_bf[i] = errnum;
+		} else {
+			snf->sect_bf[i] = -1;
+			ret = -EBADMSG;
+		}
+	}
+
+	return ret;
+}
+
+static int mtk_ecc_check_buf_bitflips(struct mtk_snand *snf, const void *buf,
+				      size_t len, uint32_t bitflips)
+{
+	const uint8_t *buf8 = buf;
+	const uint32_t *buf32;
+	uint32_t d, weight;
+
+	while (len && ((uintptr_t)buf8) % sizeof(uint32_t)) {
+		weight = hweight8(*buf8);
+		bitflips += BITS_PER_BYTE - weight;
+		buf8++;
+		len--;
+
+		if (bitflips > snf->ecc_strength)
+			return -EBADMSG;
+	}
+
+	buf32 = (const uint32_t *)buf8;
+	while (len >= sizeof(uint32_t)) {
+		d = *buf32;
+
+		if (d != ~0) {
+			weight = hweight32(d);
+			bitflips += sizeof(uint32_t) * BITS_PER_BYTE - weight;
+		}
+
+		buf32++;
+		len -= sizeof(uint32_t);
+
+		if (bitflips > snf->ecc_strength)
+			return -EBADMSG;
+	}
+
+	buf8 = (const uint8_t *)buf32;
+	while (len) {
+		weight = hweight8(*buf8);
+		bitflips += BITS_PER_BYTE - weight;
+		buf8++;
+		len--;
+
+		if (bitflips > snf->ecc_strength)
+			return -EBADMSG;
+	}
+
+	return bitflips;
+}
+
+static int mtk_ecc_check_parity_bitflips(struct mtk_snand *snf, const void *buf,
+					 uint32_t bits, uint32_t bitflips)
+{
+	uint32_t len, i;
+	uint8_t b;
+	int rc;
+
+	len = bits >> 3;
+	bits &= 7;
+
+	rc = mtk_ecc_check_buf_bitflips(snf, buf, len, bitflips);
+	if (!bits || rc < 0)
+		return rc;
+
+	bitflips = rc;
+
+	/* We want a precise count of bits */
+	b = ((const uint8_t *)buf)[len];
+	for (i = 0; i < bits; i++) {
+		if (!(b & BIT(i)))
+			bitflips++;
+	}
+
+	if (bitflips > snf->ecc_strength)
+		return -EBADMSG;
+
+	return bitflips;
+}
+
+static void mtk_ecc_reset_parity(void *buf, uint32_t bits)
+{
+	uint32_t len;
+
+	len = bits >> 3;
+	bits &= 7;
+
+	memset(buf, 0xff, len);
+
+	/* Only reset bits protected by ECC to 1 */
+	if (bits)
+		((uint8_t *)buf)[len] |= GENMASK(bits - 1, 0);
+}
+
+int mtk_ecc_fixup_empty_sector(struct mtk_snand *snf, uint32_t sect)
+{
+	uint32_t ecc_bytes = snf->spare_per_sector - snf->nfi_soc->fdm_size;
+	uint8_t *oob = snf->page_cache + snf->writesize;
+	uint8_t *data_ptr, *fdm_ptr, *ecc_ptr;
+	int bitflips = 0, ecc_bits, parity_bits;
+
+	parity_bits = fls(snf->nfi_soc->sector_size * 8);
+	ecc_bits = snf->ecc_strength * parity_bits;
+
+	data_ptr = snf->page_cache + sect * snf->nfi_soc->sector_size;
+	fdm_ptr = oob + sect * snf->nfi_soc->fdm_size;
+	ecc_ptr = oob + snf->ecc_steps * snf->nfi_soc->fdm_size +
+		  sect * ecc_bytes;
+
+	/*
+	 * Check whether DATA + FDM + ECC of a sector contains correctable
+	 * bitflips
+	 */
+	bitflips = mtk_ecc_check_buf_bitflips(snf, data_ptr,
+					      snf->nfi_soc->sector_size,
+					      bitflips);
+	if (bitflips < 0)
+		return -EBADMSG;
+
+	bitflips = mtk_ecc_check_buf_bitflips(snf, fdm_ptr,
+					      snf->nfi_soc->fdm_ecc_size,
+					      bitflips);
+	if (bitflips < 0)
+		return -EBADMSG;
+
+	bitflips = mtk_ecc_check_parity_bitflips(snf, ecc_ptr, ecc_bits,
+						 bitflips);
+	if (bitflips < 0)
+		return -EBADMSG;
+
+	if (!bitflips)
+		return 0;
+
+	/* Reset the data of this sector to 0xff */
+	memset(data_ptr, 0xff, snf->nfi_soc->sector_size);
+	memset(fdm_ptr, 0xff, snf->nfi_soc->fdm_ecc_size);
+	mtk_ecc_reset_parity(ecc_ptr, ecc_bits);
+
+	return bitflips;
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-ids.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-ids.c
new file mode 100644
index 0000000..1756ff7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-ids.c
@@ -0,0 +1,511 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include "mtk-snand-def.h"
+
+static int mtk_snand_winbond_select_die(struct mtk_snand *snf, uint32_t dieidx);
+static int mtk_snand_micron_select_die(struct mtk_snand *snf, uint32_t dieidx);
+
+#define SNAND_MEMORG_512M_2K_64		SNAND_MEMORG(2048, 64, 64, 512, 1, 1)
+#define SNAND_MEMORG_1G_2K_64		SNAND_MEMORG(2048, 64, 64, 1024, 1, 1)
+#define SNAND_MEMORG_2G_2K_64		SNAND_MEMORG(2048, 64, 64, 2048, 1, 1)
+#define SNAND_MEMORG_2G_2K_120		SNAND_MEMORG(2048, 120, 64, 2048, 1, 1)
+#define SNAND_MEMORG_4G_2K_64		SNAND_MEMORG(2048, 64, 64, 4096, 1, 1)
+#define SNAND_MEMORG_1G_2K_120		SNAND_MEMORG(2048, 120, 64, 1024, 1, 1)
+#define SNAND_MEMORG_1G_2K_128		SNAND_MEMORG(2048, 128, 64, 1024, 1, 1)
+#define SNAND_MEMORG_2G_2K_128		SNAND_MEMORG(2048, 128, 64, 2048, 1, 1)
+#define SNAND_MEMORG_4G_2K_128		SNAND_MEMORG(2048, 128, 64, 4096, 1, 1)
+#define SNAND_MEMORG_4G_4K_240		SNAND_MEMORG(4096, 240, 64, 2048, 1, 1)
+#define SNAND_MEMORG_4G_4K_256		SNAND_MEMORG(4096, 256, 64, 2048, 1, 1)
+#define SNAND_MEMORG_8G_4K_256		SNAND_MEMORG(4096, 256, 64, 4096, 1, 1)
+#define SNAND_MEMORG_2G_2K_64_2P	SNAND_MEMORG(2048, 64, 64, 2048, 2, 1)
+#define SNAND_MEMORG_2G_2K_64_2D	SNAND_MEMORG(2048, 64, 64, 1024, 1, 2)
+#define SNAND_MEMORG_2G_2K_128_2P	SNAND_MEMORG(2048, 128, 64, 2048, 2, 1)
+#define SNAND_MEMORG_4G_2K_64_2P	SNAND_MEMORG(2048, 64, 64, 4096, 2, 1)
+#define SNAND_MEMORG_4G_2K_128_2P_2D	SNAND_MEMORG(2048, 128, 64, 2048, 2, 2)
+#define SNAND_MEMORG_8G_4K_256_2D	SNAND_MEMORG(4096, 256, 64, 2048, 1, 2)
+
+static const SNAND_IO_CAP(snand_cap_read_from_cache_quad,
+	SPI_IO_1_1_1 | SPI_IO_1_1_2 | SPI_IO_1_2_2 | SPI_IO_1_1_4 |
+	SPI_IO_1_4_4,
+	SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_READ_FROM_CACHE, 8),
+	SNAND_OP(SNAND_IO_1_1_2, SNAND_CMD_READ_FROM_CACHE_X2, 8),
+	SNAND_OP(SNAND_IO_1_2_2, SNAND_CMD_READ_FROM_CACHE_DUAL, 4),
+	SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_READ_FROM_CACHE_X4, 8),
+	SNAND_OP(SNAND_IO_1_4_4, SNAND_CMD_READ_FROM_CACHE_QUAD, 4));
+
+static const SNAND_IO_CAP(snand_cap_read_from_cache_quad_q2d,
+	SPI_IO_1_1_1 | SPI_IO_1_1_2 | SPI_IO_1_2_2 | SPI_IO_1_1_4 |
+	SPI_IO_1_4_4,
+	SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_READ_FROM_CACHE, 8),
+	SNAND_OP(SNAND_IO_1_1_2, SNAND_CMD_READ_FROM_CACHE_X2, 8),
+	SNAND_OP(SNAND_IO_1_2_2, SNAND_CMD_READ_FROM_CACHE_DUAL, 4),
+	SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_READ_FROM_CACHE_X4, 8),
+	SNAND_OP(SNAND_IO_1_4_4, SNAND_CMD_READ_FROM_CACHE_QUAD, 2));
+
+static const SNAND_IO_CAP(snand_cap_read_from_cache_quad_a8d,
+	SPI_IO_1_1_1 | SPI_IO_1_1_2 | SPI_IO_1_2_2 | SPI_IO_1_1_4 |
+	SPI_IO_1_4_4,
+	SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_READ_FROM_CACHE, 8),
+	SNAND_OP(SNAND_IO_1_1_2, SNAND_CMD_READ_FROM_CACHE_X2, 8),
+	SNAND_OP(SNAND_IO_1_2_2, SNAND_CMD_READ_FROM_CACHE_DUAL, 8),
+	SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_READ_FROM_CACHE_X4, 8),
+	SNAND_OP(SNAND_IO_1_4_4, SNAND_CMD_READ_FROM_CACHE_QUAD, 8));
+
+static const SNAND_IO_CAP(snand_cap_read_from_cache_x4,
+	SPI_IO_1_1_1 | SPI_IO_1_1_2 | SPI_IO_1_1_4,
+	SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_READ_FROM_CACHE, 8),
+	SNAND_OP(SNAND_IO_1_1_2, SNAND_CMD_READ_FROM_CACHE_X2, 8),
+	SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_READ_FROM_CACHE_X4, 8));
+
+static const SNAND_IO_CAP(snand_cap_read_from_cache_x4_only,
+	SPI_IO_1_1_1 | SPI_IO_1_1_4,
+	SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_READ_FROM_CACHE, 8),
+	SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_READ_FROM_CACHE_X4, 8));
+
+static const SNAND_IO_CAP(snand_cap_program_load_x1,
+	SPI_IO_1_1_1,
+	SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_PROGRAM_LOAD, 0));
+
+static const SNAND_IO_CAP(snand_cap_program_load_x4,
+	SPI_IO_1_1_1 | SPI_IO_1_1_4,
+	SNAND_OP(SNAND_IO_1_1_1, SNAND_CMD_PROGRAM_LOAD, 0),
+	SNAND_OP(SNAND_IO_1_1_4, SNAND_CMD_PROGRAM_LOAD_X4, 0));
+
+static const struct snand_flash_info snand_flash_ids[] = {
+	SNAND_INFO("W25N512GV", SNAND_ID(SNAND_ID_DYMMY, 0xef, 0xaa, 0x20),
+		   SNAND_MEMORG_512M_2K_64,
+		   &snand_cap_read_from_cache_quad,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("W25N01GV", SNAND_ID(SNAND_ID_DYMMY, 0xef, 0xaa, 0x21),
+		   SNAND_MEMORG_1G_2K_64,
+		   &snand_cap_read_from_cache_quad,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("W25M02GV", SNAND_ID(SNAND_ID_DYMMY, 0xef, 0xab, 0x21),
+		   SNAND_MEMORG_2G_2K_64_2D,
+		   &snand_cap_read_from_cache_quad,
+		   &snand_cap_program_load_x4,
+		   mtk_snand_winbond_select_die),
+	SNAND_INFO("W25N02KV", SNAND_ID(SNAND_ID_DYMMY, 0xef, 0xaa, 0x22),
+		   SNAND_MEMORG_2G_2K_128,
+		   &snand_cap_read_from_cache_quad,
+		   &snand_cap_program_load_x4),
+
+	SNAND_INFO("GD5F1GQ4UAWxx", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0x10),
+		   SNAND_MEMORG_1G_2K_64,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("GD5F1GQ4UExIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xd1),
+		   SNAND_MEMORG_1G_2K_128,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("GD5F1GQ4UExxH", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xd9),
+		   SNAND_MEMORG_1G_2K_64,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("GD5F1GQ4xAYIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xf1),
+		   SNAND_MEMORG_1G_2K_64,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("GD5F2GQ4UExIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xd2),
+		   SNAND_MEMORG_2G_2K_128,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("GD5F2GQ5UExxH", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0x32),
+		   SNAND_MEMORG_2G_2K_64,
+		   &snand_cap_read_from_cache_quad_a8d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("GD5F2GQ4xAYIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xf2),
+		   SNAND_MEMORG_2G_2K_64,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("GD5F4GQ4UBxIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xd4),
+		   SNAND_MEMORG_4G_4K_256,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("GD5F4GQ4xAYIG", SNAND_ID(SNAND_ID_ADDR, 0xc8, 0xf4),
+		   SNAND_MEMORG_4G_2K_64,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("GD5F2GQ5UExxG", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x52),
+		   SNAND_MEMORG_2G_2K_128,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("GD5F4GQ4UCxIG", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0xb4),
+		   SNAND_MEMORG_4G_4K_256,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+
+	SNAND_INFO("MX35LF1GE4AB", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x12),
+		   SNAND_MEMORG_1G_2K_64,
+		   &snand_cap_read_from_cache_x4,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("MX35LF1G24AD", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x14),
+		   SNAND_MEMORG_1G_2K_128,
+		   &snand_cap_read_from_cache_quad,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("MX31LF1GE4BC", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x1e),
+		   SNAND_MEMORG_1G_2K_64,
+		   &snand_cap_read_from_cache_x4,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("MX35LF2GE4AB", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x22),
+		   SNAND_MEMORG_2G_2K_64,
+		   &snand_cap_read_from_cache_x4,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("MX35LF2G24AD", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x24),
+		   SNAND_MEMORG_2G_2K_128,
+		   &snand_cap_read_from_cache_quad,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("MX35LF2GE4AD", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x26),
+		   SNAND_MEMORG_2G_2K_128,
+		   &snand_cap_read_from_cache_x4,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("MX35LF2G14AC", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x20),
+		   SNAND_MEMORG_2G_2K_64,
+		   &snand_cap_read_from_cache_x4,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("MX35LF4G24AD", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x35),
+		   SNAND_MEMORG_4G_4K_256,
+		   &snand_cap_read_from_cache_quad,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("MX35LF4GE4AD", SNAND_ID(SNAND_ID_DYMMY, 0xc2, 0x37),
+		   SNAND_MEMORG_4G_4K_256,
+		   &snand_cap_read_from_cache_x4,
+		   &snand_cap_program_load_x4),
+
+	SNAND_INFO("MT29F1G01AAADD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x12),
+		   SNAND_MEMORG_1G_2K_64,
+		   &snand_cap_read_from_cache_x4,
+		   &snand_cap_program_load_x1),
+	SNAND_INFO("MT29F1G01ABAFD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x14),
+		   SNAND_MEMORG_1G_2K_128,
+		   &snand_cap_read_from_cache_quad,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("MT29F2G01AAAED", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x9f),
+		   SNAND_MEMORG_2G_2K_64_2P,
+		   &snand_cap_read_from_cache_x4,
+		   &snand_cap_program_load_x1),
+	SNAND_INFO("MT29F2G01ABAGD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x24),
+		   SNAND_MEMORG_2G_2K_128_2P,
+		   &snand_cap_read_from_cache_quad,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("MT29F4G01AAADD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x32),
+		   SNAND_MEMORG_4G_2K_64_2P,
+		   &snand_cap_read_from_cache_x4,
+		   &snand_cap_program_load_x1),
+	SNAND_INFO("MT29F4G01ABAFD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x34),
+		   SNAND_MEMORG_4G_4K_256,
+		   &snand_cap_read_from_cache_quad,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("MT29F4G01ADAGD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x36),
+		   SNAND_MEMORG_4G_2K_128_2P_2D,
+		   &snand_cap_read_from_cache_quad,
+		   &snand_cap_program_load_x4,
+		   mtk_snand_micron_select_die),
+	SNAND_INFO("MT29F8G01ADAFD", SNAND_ID(SNAND_ID_DYMMY, 0x2c, 0x46),
+		   SNAND_MEMORG_8G_4K_256_2D,
+		   &snand_cap_read_from_cache_quad,
+		   &snand_cap_program_load_x4,
+		   mtk_snand_micron_select_die),
+
+	SNAND_INFO("TC58CVG0S3HRAIG", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xc2),
+		   SNAND_MEMORG_1G_2K_128,
+		   &snand_cap_read_from_cache_x4,
+		   &snand_cap_program_load_x1),
+	SNAND_INFO("TC58CVG1S3HRAIG", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xcb),
+		   SNAND_MEMORG_2G_2K_128,
+		   &snand_cap_read_from_cache_x4,
+		   &snand_cap_program_load_x1),
+	SNAND_INFO("TC58CVG2S0HRAIG", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xcd),
+		   SNAND_MEMORG_4G_4K_256,
+		   &snand_cap_read_from_cache_x4,
+		   &snand_cap_program_load_x1),
+	SNAND_INFO("TC58CVG0S3HRAIJ", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xe2),
+		   SNAND_MEMORG_1G_2K_128,
+		   &snand_cap_read_from_cache_x4,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("TC58CVG1S3HRAIJ", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xeb),
+		   SNAND_MEMORG_2G_2K_128,
+		   &snand_cap_read_from_cache_x4,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("TC58CVG2S0HRAIJ", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xed),
+		   SNAND_MEMORG_4G_4K_256,
+		   &snand_cap_read_from_cache_x4,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("TH58CVG3S0HRAIJ", SNAND_ID(SNAND_ID_DYMMY, 0x98, 0xe4),
+		   SNAND_MEMORG_8G_4K_256,
+		   &snand_cap_read_from_cache_x4,
+		   &snand_cap_program_load_x4),
+
+	SNAND_INFO("F50L512M41A", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x20),
+		   SNAND_MEMORG_512M_2K_64,
+		   &snand_cap_read_from_cache_x4,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("F50L1G41A", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x21),
+		   SNAND_MEMORG_1G_2K_64,
+		   &snand_cap_read_from_cache_x4,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("F50L1G41LB", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x01),
+		   SNAND_MEMORG_1G_2K_64,
+		   &snand_cap_read_from_cache_quad,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("F50L2G41LB", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x0a),
+		   SNAND_MEMORG_2G_2K_64_2D,
+		   &snand_cap_read_from_cache_quad,
+		   &snand_cap_program_load_x4,
+		   mtk_snand_winbond_select_die),
+
+	SNAND_INFO("CS11G0T0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x00),
+		   SNAND_MEMORG_1G_2K_128,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("CS11G0G0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x10),
+		   SNAND_MEMORG_1G_2K_128,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("CS11G0S0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x20),
+		   SNAND_MEMORG_1G_2K_64,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("CS11G1T0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x01),
+		   SNAND_MEMORG_2G_2K_128,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("CS11G1S0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x21),
+		   SNAND_MEMORG_2G_2K_64,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("CS11G2T0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x02),
+		   SNAND_MEMORG_4G_2K_128,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("CS11G2S0A0AA", SNAND_ID(SNAND_ID_DYMMY, 0x6b, 0x22),
+		   SNAND_MEMORG_4G_2K_64,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+
+	SNAND_INFO("EM73B044VCA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x01),
+		   SNAND_MEMORG_512M_2K_64,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73C044SNB", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x11),
+		   SNAND_MEMORG_1G_2K_120,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73C044SNF", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x09),
+		   SNAND_MEMORG_1G_2K_128,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73C044VCA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x18),
+		   SNAND_MEMORG_1G_2K_64,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73C044SNA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x19),
+		   SNAND_MEMORG(2048, 64, 128, 512, 1, 1),
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73C044VCD", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1c),
+		   SNAND_MEMORG_1G_2K_64,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73C044SND", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1d),
+		   SNAND_MEMORG_1G_2K_64,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73D044SND", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1e),
+		   SNAND_MEMORG_2G_2K_64,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73C044VCC", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x22),
+		   SNAND_MEMORG_1G_2K_64,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73C044VCF", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x25),
+		   SNAND_MEMORG_1G_2K_64,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73C044SNC", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x31),
+		   SNAND_MEMORG_1G_2K_128,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73D044SNC", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x0a),
+		   SNAND_MEMORG_2G_2K_120,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73D044SNA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x12),
+		   SNAND_MEMORG_2G_2K_128,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73D044SNF", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x10),
+		   SNAND_MEMORG_2G_2K_128,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73D044VCA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x13),
+		   SNAND_MEMORG_2G_2K_128,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73D044VCB", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x14),
+		   SNAND_MEMORG_2G_2K_64,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73D044VCD", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x17),
+		   SNAND_MEMORG_2G_2K_128,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73D044VCH", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1b),
+		   SNAND_MEMORG_2G_2K_64,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73D044SND", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1d),
+		   SNAND_MEMORG_2G_2K_64,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73D044VCG", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x1f),
+		   SNAND_MEMORG_2G_2K_64,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73D044VCE", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x20),
+		   SNAND_MEMORG_2G_2K_64,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73D044VCL", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x2e),
+		   SNAND_MEMORG_2G_2K_128,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73D044SNB", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x32),
+		   SNAND_MEMORG_2G_2K_128,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73E044SNA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x03),
+		   SNAND_MEMORG_4G_4K_256,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73E044SND", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x0b),
+		   SNAND_MEMORG_4G_4K_240,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73E044SNB", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x23),
+		   SNAND_MEMORG_4G_4K_256,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73E044VCA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x2c),
+		   SNAND_MEMORG_4G_4K_256,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73E044VCB", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x2f),
+		   SNAND_MEMORG_4G_2K_128,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73F044SNA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x24),
+		   SNAND_MEMORG_8G_4K_256,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73F044VCA", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x2d),
+		   SNAND_MEMORG_8G_4K_256,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73E044SNE", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x0e),
+		   SNAND_MEMORG_8G_4K_256,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73C044SNG", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x0c),
+		   SNAND_MEMORG_1G_2K_120,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("EM73D044VCN", SNAND_ID(SNAND_ID_DYMMY, 0xd5, 0x0f),
+		   SNAND_MEMORG_2G_2K_64,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+
+	SNAND_INFO("FM35Q1GA", SNAND_ID(SNAND_ID_DYMMY, 0xe5, 0x71),
+		   SNAND_MEMORG_1G_2K_64,
+		   &snand_cap_read_from_cache_x4,
+		   &snand_cap_program_load_x4),
+
+	SNAND_INFO("PN26G01A", SNAND_ID(SNAND_ID_DYMMY, 0xa1, 0xe1),
+		   SNAND_MEMORG_1G_2K_128,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("PN26G02A", SNAND_ID(SNAND_ID_DYMMY, 0xa1, 0xe2),
+		   SNAND_MEMORG_2G_2K_128,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+
+	SNAND_INFO("IS37SML01G1", SNAND_ID(SNAND_ID_DYMMY, 0xc8, 0x21),
+		   SNAND_MEMORG_1G_2K_64,
+		   &snand_cap_read_from_cache_x4,
+		   &snand_cap_program_load_x4),
+
+	SNAND_INFO("ATO25D1GA", SNAND_ID(SNAND_ID_DYMMY, 0x9b, 0x12),
+		   SNAND_MEMORG_1G_2K_64,
+		   &snand_cap_read_from_cache_x4_only,
+		   &snand_cap_program_load_x4),
+
+	SNAND_INFO("HYF1GQ4U", SNAND_ID(SNAND_ID_DYMMY, 0xc9, 0x51),
+		   SNAND_MEMORG_1G_2K_128,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+	SNAND_INFO("HYF2GQ4U", SNAND_ID(SNAND_ID_DYMMY, 0xc9, 0x52),
+		   SNAND_MEMORG_2G_2K_128,
+		   &snand_cap_read_from_cache_quad_q2d,
+		   &snand_cap_program_load_x4),
+};
+
+static int mtk_snand_winbond_select_die(struct mtk_snand *snf, uint32_t dieidx)
+{
+	uint8_t op[2];
+
+	if (dieidx > 1) {
+		snand_log_chip(snf->pdev, "Invalid die index %u\n", dieidx);
+		return -EINVAL;
+	}
+
+	op[0] = SNAND_CMD_WINBOND_SELECT_DIE;
+	op[1] = (uint8_t)dieidx;
+
+	return mtk_snand_mac_io(snf, op, sizeof(op), NULL, 0);
+}
+
+static int mtk_snand_micron_select_die(struct mtk_snand *snf, uint32_t dieidx)
+{
+	int ret;
+
+	if (dieidx > 1) {
+		snand_log_chip(snf->pdev, "Invalid die index %u\n", dieidx);
+		return -EINVAL;
+	}
+
+	ret = mtk_snand_set_feature(snf, SNAND_FEATURE_MICRON_DIE_ADDR,
+				    SNAND_MICRON_DIE_SEL_1);
+	if (ret) {
+		snand_log_chip(snf->pdev,
+			       "Failed to set die selection feature\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+const struct snand_flash_info *snand_flash_id_lookup(enum snand_id_type type,
+						     const uint8_t *id)
+{
+	const struct snand_id *fid;
+	uint32_t i;
+
+	for (i = 0; i < ARRAY_SIZE(snand_flash_ids); i++) {
+		if (snand_flash_ids[i].id.type != type)
+			continue;
+
+		fid = &snand_flash_ids[i].id;
+		if (memcmp(fid->id, id, fid->len))
+			continue;
+
+		return &snand_flash_ids[i];
+	}
+
+	return NULL;
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-mtd.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-mtd.c
new file mode 100644
index 0000000..e1e0317
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-mtd.c
@@ -0,0 +1,728 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/wait.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of_platform.h>
+
+#include "mtk-snand.h"
+#include "mtk-snand-os.h"
+
+struct mtk_snand_of_id {
+	enum mtk_snand_soc soc;
+	bool en_ecc_clk;
+	bool en_nfi_hclk;
+};
+
+struct mtk_snand_mtd {
+	struct mtk_snand_plat_dev pdev;
+	struct mtk_snand_of_id *soc_id;
+
+	struct clk *nfi_clk;
+	struct clk *pad_clk;
+	struct clk *ecc_clk;
+	struct clk *nfi_hclk;
+
+	void __iomem *nfi_regs;
+	void __iomem *ecc_regs;
+
+	int irq;
+
+	bool quad_spi;
+	enum mtk_snand_soc soc;
+
+	struct mtd_info mtd;
+	struct mtk_snand *snf;
+	struct mtk_snand_chip_info cinfo;
+	uint8_t *page_cache;
+	struct mutex lock;
+};
+
+#define mtd_to_msm(mtd) container_of(mtd, struct mtk_snand_mtd, mtd)
+
+static int mtk_snand_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct mtk_snand_mtd *msm = mtd_to_msm(mtd);
+	u64 start_addr, end_addr;
+	int ret;
+
+	/* Do not allow write past end of device */
+	if ((instr->addr + instr->len) > mtd->size) {
+		dev_err(msm->pdev.dev,
+			"attempt to erase beyond end of device\n");
+		return -EINVAL;
+	}
+
+	start_addr = instr->addr & (~mtd->erasesize_mask);
+	end_addr = instr->addr + instr->len;
+	if (end_addr & mtd->erasesize_mask) {
+		end_addr = (end_addr + mtd->erasesize_mask) &
+			   (~mtd->erasesize_mask);
+	}
+
+	mutex_lock(&msm->lock);
+
+	while (start_addr < end_addr) {
+		if (mtk_snand_block_isbad(msm->snf, start_addr)) {
+			instr->fail_addr = start_addr;
+			ret = -EIO;
+			break;
+		}
+
+		ret = mtk_snand_erase_block(msm->snf, start_addr);
+		if (ret) {
+			instr->fail_addr = start_addr;
+			break;
+		}
+
+		start_addr += mtd->erasesize;
+	}
+
+	mutex_unlock(&msm->lock);
+
+	return ret;
+}
+
+static int mtk_snand_mtd_read_data(struct mtk_snand_mtd *msm, uint64_t addr,
+				   struct mtd_oob_ops *ops)
+{
+	struct mtd_info *mtd = &msm->mtd;
+	size_t len, ooblen, maxooblen, chklen;
+	uint32_t col, ooboffs;
+	uint8_t *datcache, *oobcache;
+	bool ecc_failed = false, raw = ops->mode == MTD_OPS_RAW ? true : false;
+	int ret, max_bitflips = 0;
+
+	col = addr & mtd->writesize_mask;
+	addr &= ~mtd->writesize_mask;
+	maxooblen = mtd_oobavail(mtd, ops);
+	ooboffs = ops->ooboffs;
+	ooblen = ops->ooblen;
+	len = ops->len;
+
+	datcache = len ? msm->page_cache : NULL;
+	oobcache = ooblen ? msm->page_cache + mtd->writesize : NULL;
+
+	ops->oobretlen = 0;
+	ops->retlen = 0;
+
+	while (len || ooblen) {
+		if (ops->mode == MTD_OPS_AUTO_OOB)
+			ret = mtk_snand_read_page_auto_oob(msm->snf, addr,
+				datcache, oobcache, maxooblen, NULL, raw);
+		else
+			ret = mtk_snand_read_page(msm->snf, addr, datcache,
+				oobcache, raw);
+
+		if (ret < 0 && ret != -EBADMSG)
+			return ret;
+
+		if (ret == -EBADMSG) {
+			mtd->ecc_stats.failed++;
+			ecc_failed = true;
+		} else {
+			mtd->ecc_stats.corrected += ret;
+			max_bitflips = max_t(int, ret, max_bitflips);
+		}
+
+		if (len) {
+			/* Move data */
+			chklen = mtd->writesize - col;
+			if (chklen > len)
+				chklen = len;
+
+			memcpy(ops->datbuf + ops->retlen, datcache + col,
+			       chklen);
+			len -= chklen;
+			col = 0; /* (col + chklen) %  */
+			ops->retlen += chklen;
+		}
+
+		if (ooblen) {
+			/* Move oob */
+			chklen = maxooblen - ooboffs;
+			if (chklen > ooblen)
+				chklen = ooblen;
+
+			memcpy(ops->oobbuf + ops->oobretlen, oobcache + ooboffs,
+			       chklen);
+			ooblen -= chklen;
+			ooboffs = 0; /* (ooboffs + chklen) % maxooblen; */
+			ops->oobretlen += chklen;
+		}
+
+		addr += mtd->writesize;
+	}
+
+	return ecc_failed ? -EBADMSG : max_bitflips;
+}
+
+static int mtk_snand_mtd_read_oob(struct mtd_info *mtd, loff_t from,
+				  struct mtd_oob_ops *ops)
+{
+	struct mtk_snand_mtd *msm = mtd_to_msm(mtd);
+	uint32_t maxooblen;
+	int ret;
+
+	if (!ops->oobbuf && !ops->datbuf) {
+		if (ops->ooblen || ops->len)
+			return -EINVAL;
+
+		return 0;
+	}
+
+	switch (ops->mode) {
+	case MTD_OPS_PLACE_OOB:
+	case MTD_OPS_AUTO_OOB:
+	case MTD_OPS_RAW:
+		break;
+	default:
+		dev_err(msm->pdev.dev, "unsupported oob mode: %u\n", ops->mode);
+		return -EINVAL;
+	}
+
+	maxooblen = mtd_oobavail(mtd, ops);
+
+	/* Do not allow read past end of device */
+	if (ops->datbuf && (from + ops->len) > mtd->size) {
+		dev_err(msm->pdev.dev,
+			"attempt to read beyond end of device\n");
+		return -EINVAL;
+	}
+
+	if (unlikely(ops->ooboffs >= maxooblen)) {
+		dev_err(msm->pdev.dev, "attempt to start read outside oob\n");
+		return -EINVAL;
+	}
+
+	if (unlikely(from >= mtd->size ||
+	    ops->ooboffs + ops->ooblen > ((mtd->size >> mtd->writesize_shift) -
+	    (from >> mtd->writesize_shift)) * maxooblen)) {
+		dev_err(msm->pdev.dev,
+			"attempt to read beyond end of device\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&msm->lock);
+	ret = mtk_snand_mtd_read_data(msm, from, ops);
+	mutex_unlock(&msm->lock);
+
+	return ret;
+}
+
+static int mtk_snand_mtd_write_data(struct mtk_snand_mtd *msm, uint64_t addr,
+				    struct mtd_oob_ops *ops)
+{
+	struct mtd_info *mtd = &msm->mtd;
+	size_t len, ooblen, maxooblen, chklen, oobwrlen;
+	uint32_t col, ooboffs;
+	uint8_t *datcache, *oobcache;
+	bool raw = ops->mode == MTD_OPS_RAW ? true : false;
+	int ret;
+
+	col = addr & mtd->writesize_mask;
+	addr &= ~mtd->writesize_mask;
+	maxooblen = mtd_oobavail(mtd, ops);
+	ooboffs = ops->ooboffs;
+	ooblen = ops->ooblen;
+	len = ops->len;
+
+	datcache = len ? msm->page_cache : NULL;
+	oobcache = ooblen ? msm->page_cache + mtd->writesize : NULL;
+
+	ops->oobretlen = 0;
+	ops->retlen = 0;
+
+	while (len || ooblen) {
+		if (len) {
+			/* Move data */
+			chklen = mtd->writesize - col;
+			if (chklen > len)
+				chklen = len;
+
+			memset(datcache, 0xff, col);
+			memcpy(datcache + col, ops->datbuf + ops->retlen,
+			       chklen);
+			memset(datcache + col + chklen, 0xff,
+			       mtd->writesize - col - chklen);
+			len -= chklen;
+			col = 0; /* (col + chklen) %  */
+			ops->retlen += chklen;
+		}
+
+		oobwrlen = 0;
+		if (ooblen) {
+			/* Move oob */
+			chklen = maxooblen - ooboffs;
+			if (chklen > ooblen)
+				chklen = ooblen;
+
+			memset(oobcache, 0xff, ooboffs);
+			memcpy(oobcache + ooboffs,
+			       ops->oobbuf + ops->oobretlen, chklen);
+			memset(oobcache + ooboffs + chklen, 0xff,
+			       mtd->oobsize - ooboffs - chklen);
+			oobwrlen = chklen + ooboffs;
+			ooblen -= chklen;
+			ooboffs = 0; /* (ooboffs + chklen) % maxooblen; */
+			ops->oobretlen += chklen;
+		}
+
+		if (ops->mode == MTD_OPS_AUTO_OOB)
+			ret = mtk_snand_write_page_auto_oob(msm->snf, addr,
+				datcache, oobcache, oobwrlen, NULL, raw);
+		else
+			ret = mtk_snand_write_page(msm->snf, addr, datcache,
+				oobcache, raw);
+
+		if (ret)
+			return ret;
+
+		addr += mtd->writesize;
+	}
+
+	return 0;
+}
+
+static int mtk_snand_mtd_write_oob(struct mtd_info *mtd, loff_t to,
+				   struct mtd_oob_ops *ops)
+{
+	struct mtk_snand_mtd *msm = mtd_to_msm(mtd);
+	uint32_t maxooblen;
+	int ret;
+
+	if (!ops->oobbuf && !ops->datbuf) {
+		if (ops->ooblen || ops->len)
+			return -EINVAL;
+
+		return 0;
+	}
+
+	switch (ops->mode) {
+	case MTD_OPS_PLACE_OOB:
+	case MTD_OPS_AUTO_OOB:
+	case MTD_OPS_RAW:
+		break;
+	default:
+		dev_err(msm->pdev.dev, "unsupported oob mode: %u\n", ops->mode);
+		return -EINVAL;
+	}
+
+	maxooblen = mtd_oobavail(mtd, ops);
+
+	/* Do not allow write past end of device */
+	if (ops->datbuf && (to + ops->len) > mtd->size) {
+		dev_err(msm->pdev.dev,
+			"attempt to write beyond end of device\n");
+		return -EINVAL;
+	}
+
+	if (unlikely(ops->ooboffs >= maxooblen)) {
+		dev_err(msm->pdev.dev,
+			"attempt to start write outside oob\n");
+		return -EINVAL;
+	}
+
+	if (unlikely(to >= mtd->size ||
+	    ops->ooboffs + ops->ooblen > ((mtd->size >> mtd->writesize_shift) -
+	    (to >> mtd->writesize_shift)) * maxooblen)) {
+		dev_err(msm->pdev.dev,
+			"attempt to write beyond end of device\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&msm->lock);
+	ret = mtk_snand_mtd_write_data(msm, to, ops);
+	mutex_unlock(&msm->lock);
+
+	return ret;
+}
+
+static int mtk_snand_mtd_block_isbad(struct mtd_info *mtd, loff_t offs)
+{
+	struct mtk_snand_mtd *msm = mtd_to_msm(mtd);
+	int ret;
+
+	mutex_lock(&msm->lock);
+	ret = mtk_snand_block_isbad(msm->snf, offs);
+	mutex_unlock(&msm->lock);
+
+	return ret;
+}
+
+static int mtk_snand_mtd_block_markbad(struct mtd_info *mtd, loff_t offs)
+{
+	struct mtk_snand_mtd *msm = mtd_to_msm(mtd);
+	int ret;
+
+	mutex_lock(&msm->lock);
+	ret = mtk_snand_block_markbad(msm->snf, offs);
+	mutex_unlock(&msm->lock);
+
+	return ret;
+}
+
+static int mtk_snand_ooblayout_ecc(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *oobecc)
+{
+	struct mtk_snand_mtd *msm = mtd_to_msm(mtd);
+
+	if (section)
+		return -ERANGE;
+
+	oobecc->offset = msm->cinfo.fdm_size * msm->cinfo.num_sectors;
+	oobecc->length = mtd->oobsize - oobecc->offset;
+
+	return 0;
+}
+
+static int mtk_snand_ooblayout_free(struct mtd_info *mtd, int section,
+				    struct mtd_oob_region *oobfree)
+{
+	struct mtk_snand_mtd *msm = mtd_to_msm(mtd);
+
+	if (section >= msm->cinfo.num_sectors)
+		return -ERANGE;
+
+	oobfree->length = msm->cinfo.fdm_size - 1;
+	oobfree->offset = section * msm->cinfo.fdm_size + 1;
+
+	return 0;
+}
+
+static irqreturn_t mtk_snand_irq(int irq, void *id)
+{
+	struct mtk_snand_mtd *msm = id;
+	int ret;
+
+	ret = mtk_snand_irq_process(msm->snf);
+	if (ret > 0)
+		return IRQ_HANDLED;
+
+	return IRQ_NONE;
+}
+
+static int mtk_snand_enable_clk(struct mtk_snand_mtd *msm)
+{
+	struct mtk_snand_of_id *soc_id = msm->soc_id;
+	int ret;
+
+	ret = clk_prepare_enable(msm->nfi_clk);
+	if (ret) {
+		dev_err(msm->pdev.dev, "unable to enable nfi clk\n");
+		return ret;
+	}
+
+	ret = clk_prepare_enable(msm->pad_clk);
+	if (ret) {
+		dev_err(msm->pdev.dev, "unable to enable pad clk\n");
+		clk_disable_unprepare(msm->nfi_clk);
+		return ret;
+	}
+
+	if (soc_id->en_ecc_clk) {
+		ret = clk_prepare_enable(msm->ecc_clk);
+		if (ret) {
+			dev_err(msm->pdev.dev, "unable to enable ecc clk\n");
+			clk_disable_unprepare(msm->nfi_clk);
+			clk_disable_unprepare(msm->pad_clk);
+			return ret;
+		}
+	}
+
+	if (soc_id->en_nfi_hclk) {
+		ret = clk_prepare_enable(msm->nfi_hclk);
+		if (ret) {
+			dev_err(msm->pdev.dev, "unable to enable nfi hclk\n");
+			clk_disable_unprepare(msm->nfi_clk);
+			clk_disable_unprepare(msm->pad_clk);
+			if (soc_id->en_ecc_clk)
+				clk_disable_unprepare(msm->ecc_clk);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void mtk_snand_disable_clk(struct mtk_snand_mtd *msm)
+{
+	struct mtk_snand_of_id *soc_id = msm->soc_id;
+
+	clk_disable_unprepare(msm->nfi_clk);
+	clk_disable_unprepare(msm->pad_clk);
+	if (soc_id->en_ecc_clk)
+		clk_disable_unprepare(msm->ecc_clk);
+	if (soc_id->en_nfi_hclk)
+		clk_disable_unprepare(msm->nfi_hclk);
+}
+
+static const struct mtd_ooblayout_ops mtk_snand_ooblayout = {
+	.ecc = mtk_snand_ooblayout_ecc,
+	.free = mtk_snand_ooblayout_free,
+};
+
+static struct mtk_snand_of_id mt7622_soc_id = {
+	.soc = SNAND_SOC_MT7622,
+	.en_ecc_clk = true,
+	.en_nfi_hclk = false
+};
+
+static struct mtk_snand_of_id mt7629_soc_id = {
+	.soc = SNAND_SOC_MT7629,
+	.en_ecc_clk = true,
+	.en_nfi_hclk = false
+};
+
+static struct mtk_snand_of_id mt7986_soc_id = {
+	.soc = SNAND_SOC_MT7986,
+	.en_ecc_clk = false,
+	.en_nfi_hclk = true
+};
+
+static const struct of_device_id mtk_snand_ids[] = {
+	{ .compatible = "mediatek,mt7622-snand", .data = &mt7622_soc_id },
+	{ .compatible = "mediatek,mt7629-snand", .data = &mt7629_soc_id },
+	{ .compatible = "mediatek,mt7986-snand", .data = &mt7986_soc_id },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(of, mtk_snand_ids);
+
+static int mtk_snand_probe(struct platform_device *pdev)
+{
+	struct mtk_snand_platdata mtk_snand_pdata = {};
+	struct device_node *np = pdev->dev.of_node;
+	const struct of_device_id *of_soc_id;
+	struct mtk_snand_mtd *msm;
+	struct mtd_info *mtd;
+	struct resource *r;
+	uint32_t size;
+	int ret;
+
+	of_soc_id = of_match_node(mtk_snand_ids, np);
+	if (!of_soc_id)
+		return -EINVAL;
+
+	msm = devm_kzalloc(&pdev->dev, sizeof(*msm), GFP_KERNEL);
+	if (!msm)
+		return -ENOMEM;
+
+	msm->soc_id = of_soc_id->data;
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nfi");
+	msm->nfi_regs = devm_ioremap_resource(&pdev->dev, r);
+	if (IS_ERR(msm->nfi_regs)) {
+		ret = PTR_ERR(msm->nfi_regs);
+		goto errout1;
+	}
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ecc");
+	msm->ecc_regs = devm_ioremap_resource(&pdev->dev, r);
+	if (IS_ERR(msm->ecc_regs)) {
+		ret = PTR_ERR(msm->ecc_regs);
+		goto errout1;
+	}
+
+	msm->pdev.dev = &pdev->dev;
+	msm->quad_spi = of_property_read_bool(np, "mediatek,quad-spi");
+	msm->soc = msm->soc_id->soc;
+
+	msm->nfi_clk = devm_clk_get(msm->pdev.dev, "nfi_clk");
+	if (IS_ERR(msm->nfi_clk)) {
+		ret = PTR_ERR(msm->nfi_clk);
+		dev_err(msm->pdev.dev,
+			"unable to get nfi_clk, err = %d\n", ret);
+		goto errout1;
+	}
+
+	if (msm->soc_id->en_ecc_clk) {
+		msm->ecc_clk = devm_clk_get(msm->pdev.dev, "ecc_clk");
+		if (IS_ERR(msm->ecc_clk)) {
+			ret = PTR_ERR(msm->ecc_clk);
+			dev_err(msm->pdev.dev,
+				"unable to get ecc_clk, err = %d\n", ret);
+			goto errout1;
+		}
+	}
+
+	msm->pad_clk = devm_clk_get(msm->pdev.dev, "pad_clk");
+	if (IS_ERR(msm->pad_clk)) {
+		ret = PTR_ERR(msm->pad_clk);
+		dev_err(msm->pdev.dev,
+			"unable to get pad_clk, err = %d\n", ret);
+		goto errout1;
+	}
+
+	if (msm->soc_id->en_nfi_hclk) {
+		msm->nfi_hclk = devm_clk_get(msm->pdev.dev, "nfi_hclk");
+		if (IS_ERR(msm->nfi_hclk)) {
+			ret = PTR_ERR(msm->nfi_hclk);
+			dev_err(msm->pdev.dev,
+				"unable to get nfi_hclk, err = %d\n", ret);
+			goto errout1;
+		}
+	}
+
+	ret = mtk_snand_enable_clk(msm);
+	if (ret)
+		goto errout1;
+
+	/* Probe SPI-NAND Flash */
+	mtk_snand_pdata.soc = msm->soc;
+	mtk_snand_pdata.quad_spi = msm->quad_spi;
+	mtk_snand_pdata.nfi_base = msm->nfi_regs;
+	mtk_snand_pdata.ecc_base = msm->ecc_regs;
+
+	ret = mtk_snand_init(&msm->pdev, &mtk_snand_pdata, &msm->snf);
+	if (ret)
+		goto errout1;
+
+	msm->irq = platform_get_irq(pdev, 0);
+	if (msm->irq >= 0) {
+		ret = devm_request_irq(msm->pdev.dev, msm->irq, mtk_snand_irq,
+				       0x0, "mtk-snand", msm);
+		if (ret) {
+			dev_err(msm->pdev.dev, "failed to request snfi irq\n");
+			goto errout2;
+		}
+
+		ret = dma_set_mask(msm->pdev.dev, DMA_BIT_MASK(32));
+		if (ret) {
+			dev_err(msm->pdev.dev, "failed to set dma mask\n");
+			goto errout3;
+		}
+	}
+
+	mtk_snand_get_chip_info(msm->snf, &msm->cinfo);
+
+	size = msm->cinfo.pagesize + msm->cinfo.sparesize;
+	msm->page_cache = devm_kmalloc(msm->pdev.dev, size, GFP_KERNEL);
+	if (!msm->page_cache) {
+		dev_err(msm->pdev.dev, "failed to allocate page cache\n");
+		ret = -ENOMEM;
+		goto errout3;
+	}
+
+	mutex_init(&msm->lock);
+
+	dev_info(msm->pdev.dev,
+		 "chip is %s, size %lluMB, page size %u, oob size %u\n",
+		 msm->cinfo.model, msm->cinfo.chipsize >> 20,
+		 msm->cinfo.pagesize, msm->cinfo.sparesize);
+
+	/* Initialize mtd for SPI-NAND */
+	mtd = &msm->mtd;
+
+	mtd->owner = THIS_MODULE;
+	mtd->dev.parent = &pdev->dev;
+	mtd->type = MTD_NANDFLASH;
+	mtd->flags = MTD_CAP_NANDFLASH;
+
+	mtd_set_of_node(mtd, np);
+
+	mtd->size = msm->cinfo.chipsize;
+	mtd->erasesize = msm->cinfo.blocksize;
+	mtd->writesize = msm->cinfo.pagesize;
+	mtd->writebufsize = mtd->writesize;
+	mtd->oobsize = msm->cinfo.sparesize;
+	mtd->oobavail = msm->cinfo.num_sectors * (msm->cinfo.fdm_size - 1);
+
+	mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
+	mtd->writesize_shift = ffs(mtd->writesize) - 1;
+	mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1;
+	mtd->writesize_mask = (1 << mtd->writesize_shift) - 1;
+
+	mtd->ooblayout = &mtk_snand_ooblayout;
+
+	mtd->ecc_strength = msm->cinfo.ecc_strength;
+	mtd->bitflip_threshold = (mtd->ecc_strength * 3) / 4;
+	mtd->ecc_step_size = msm->cinfo.sector_size;
+
+	mtd->_erase = mtk_snand_mtd_erase;
+	mtd->_read_oob = mtk_snand_mtd_read_oob;
+	mtd->_write_oob = mtk_snand_mtd_write_oob;
+	mtd->_block_isbad = mtk_snand_mtd_block_isbad;
+	mtd->_block_markbad = mtk_snand_mtd_block_markbad;
+
+	ret = mtd_device_register(mtd, NULL, 0);
+	if (ret) {
+		dev_err(msm->pdev.dev, "failed to register mtd partition\n");
+		goto errout4;
+	}
+
+	platform_set_drvdata(pdev, msm);
+
+	return 0;
+
+errout4:
+	devm_kfree(msm->pdev.dev, msm->page_cache);
+
+errout3:
+	if (msm->irq >= 0)
+		devm_free_irq(msm->pdev.dev, msm->irq, msm);
+
+errout2:
+	mtk_snand_cleanup(msm->snf);
+
+errout1:
+	devm_kfree(msm->pdev.dev, msm);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return ret;
+}
+
+static int mtk_snand_remove(struct platform_device *pdev)
+{
+	struct mtk_snand_mtd *msm = platform_get_drvdata(pdev);
+	struct mtd_info *mtd = &msm->mtd;
+	int ret;
+
+	ret = mtd_device_unregister(mtd);
+	if (ret)
+		return ret;
+
+	mtk_snand_cleanup(msm->snf);
+
+	if (msm->irq >= 0)
+		devm_free_irq(msm->pdev.dev, msm->irq, msm);
+
+	mtk_snand_disable_clk(msm);
+
+	devm_kfree(msm->pdev.dev, msm->page_cache);
+	devm_kfree(msm->pdev.dev, msm);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver mtk_snand_driver = {
+	.probe = mtk_snand_probe,
+	.remove = mtk_snand_remove,
+	.driver = {
+		.name = "mtk-snand",
+		.of_match_table = mtk_snand_ids,
+	},
+};
+
+module_platform_driver(mtk_snand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Weijie Gao <weijie.gao@mediatek.com>");
+MODULE_DESCRIPTION("MeidaTek SPI-NAND Flash Controller Driver");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-os.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-os.c
new file mode 100644
index 0000000..0c3ffec
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-os.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include "mtk-snand-def.h"
+
+int mtk_snand_log(struct mtk_snand_plat_dev *pdev,
+		  enum mtk_snand_log_category cat, const char *fmt, ...)
+{
+	const char *catname = "";
+	va_list ap;
+	char *msg;
+
+	switch (cat) {
+	case SNAND_LOG_NFI:
+		catname = "NFI";
+		break;
+	case SNAND_LOG_SNFI:
+		catname = "SNFI";
+		break;
+	case SNAND_LOG_ECC:
+		catname = "ECC";
+		break;
+	default:
+		break;
+	}
+
+	va_start(ap, fmt);
+	msg = kvasprintf(GFP_KERNEL, fmt, ap);
+	va_end(ap);
+
+	if (!msg) {
+		dev_warn(pdev->dev, "unable to print log\n");
+		return -1;
+	}
+
+	if (*catname)
+		dev_warn(pdev->dev, "%s: %s", catname, msg);
+	else
+		dev_warn(pdev->dev, "%s", msg);
+
+	kfree(msg);
+
+	return 0;
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-os.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-os.h
new file mode 100644
index 0000000..223f73f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand-os.h
@@ -0,0 +1,133 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#ifndef _MTK_SNAND_OS_H_
+#define _MTK_SNAND_OS_H_
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/limits.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/sizes.h>
+#include <linux/iopoll.h>
+#include <linux/hrtimer.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <asm/div64.h>
+
+struct mtk_snand_plat_dev {
+	struct device *dev;
+	struct completion done;
+};
+
+/* Polling helpers */
+#define read16_poll_timeout(addr, val, cond, sleep_us, timeout_us) \
+	readw_poll_timeout((addr), (val), (cond), (sleep_us), (timeout_us))
+
+#define read32_poll_timeout(addr, val, cond, sleep_us, timeout_us) \
+	readl_poll_timeout((addr), (val), (cond), (sleep_us), (timeout_us))
+
+/* Timer helpers */
+#define mtk_snand_time_t ktime_t
+
+static inline mtk_snand_time_t timer_get_ticks(void)
+{
+	return ktime_get();
+}
+
+static inline mtk_snand_time_t timer_time_to_tick(uint32_t timeout_us)
+{
+	return ktime_add_us(ktime_set(0, 0), timeout_us);
+}
+
+static inline bool timer_is_timeout(mtk_snand_time_t start_tick,
+				    mtk_snand_time_t timeout_tick)
+{
+	ktime_t tmo = ktime_add(start_tick, timeout_tick);
+
+	return ktime_compare(ktime_get(), tmo) > 0;
+}
+
+/* Memory helpers */
+static inline void *generic_mem_alloc(struct mtk_snand_plat_dev *pdev,
+				      size_t size)
+{
+	return devm_kzalloc(pdev->dev, size, GFP_KERNEL);
+}
+static inline void generic_mem_free(struct mtk_snand_plat_dev *pdev, void *ptr)
+{
+	devm_kfree(pdev->dev, ptr);
+}
+
+static inline void *dma_mem_alloc(struct mtk_snand_plat_dev *pdev, size_t size)
+{
+	return kzalloc(size, GFP_KERNEL);
+}
+static inline void dma_mem_free(struct mtk_snand_plat_dev *pdev, void *ptr)
+{
+	kfree(ptr);
+}
+
+static inline int dma_mem_map(struct mtk_snand_plat_dev *pdev, void *vaddr,
+			      uintptr_t *dma_addr, size_t size, bool to_device)
+{
+	dma_addr_t addr;
+	int ret;
+
+	addr = dma_map_single(pdev->dev, vaddr, size,
+			      to_device ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+	ret = dma_mapping_error(pdev->dev, addr);
+	if (ret)
+		return ret;
+
+	*dma_addr = (uintptr_t)addr;
+
+	return 0;
+}
+
+static inline void dma_mem_unmap(struct mtk_snand_plat_dev *pdev,
+				 uintptr_t dma_addr, size_t size,
+				 bool to_device)
+{
+	dma_unmap_single(pdev->dev, dma_addr, size,
+			 to_device ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+}
+
+/* Interrupt helpers */
+static inline void irq_completion_done(struct mtk_snand_plat_dev *pdev)
+{
+	complete(&pdev->done);
+}
+
+static inline void irq_completion_init(struct mtk_snand_plat_dev *pdev)
+{
+	init_completion(&pdev->done);
+}
+
+static inline int irq_completion_wait(struct mtk_snand_plat_dev *pdev,
+				       void __iomem *reg, uint32_t bit,
+				       uint32_t timeout_us)
+{
+#if 0
+	uint32_t val;
+
+	return read32_poll_timeout(reg, val, val & bit, 0, timeout_us);
+#else
+	int ret;
+
+	ret = wait_for_completion_timeout(&pdev->done,
+					  usecs_to_jiffies(timeout_us));
+	if (!ret)
+		return -ETIMEDOUT;
+
+	return 0;
+#endif
+}
+
+#endif /* _MTK_SNAND_OS_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand.c
new file mode 100644
index 0000000..884bcfc
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand.c
@@ -0,0 +1,1913 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include "mtk-snand-def.h"
+
+/* NFI registers */
+#define NFI_CNFG			0x000
+#define CNFG_OP_MODE_S			12
+#define   CNFG_OP_MODE_CUST		6
+#define   CNFG_OP_MODE_PROGRAM		3
+#define CNFG_AUTO_FMT_EN		BIT(9)
+#define CNFG_HW_ECC_EN			BIT(8)
+#define CNFG_DMA_BURST_EN		BIT(2)
+#define CNFG_READ_MODE			BIT(1)
+#define CNFG_DMA_MODE			BIT(0)
+
+#define NFI_PAGEFMT			0x0004
+#define NFI_SPARE_SIZE_LS_S		16
+#define NFI_FDM_ECC_NUM_S		12
+#define NFI_FDM_NUM_S			8
+#define NFI_SPARE_SIZE_S		4
+#define NFI_SEC_SEL_512			BIT(2)
+#define NFI_PAGE_SIZE_S			0
+#define   NFI_PAGE_SIZE_512_2K		0
+#define   NFI_PAGE_SIZE_2K_4K		1
+#define   NFI_PAGE_SIZE_4K_8K		2
+#define   NFI_PAGE_SIZE_8K_16K		3
+
+#define NFI_CON				0x008
+#define CON_SEC_NUM_S			12
+#define CON_BWR				BIT(9)
+#define CON_BRD				BIT(8)
+#define CON_NFI_RST			BIT(1)
+#define CON_FIFO_FLUSH			BIT(0)
+
+#define NFI_INTR_EN			0x010
+#define NFI_INTR_STA			0x014
+#define NFI_IRQ_INTR_EN			BIT(31)
+#define NFI_IRQ_CUS_READ		BIT(8)
+#define NFI_IRQ_CUS_PG			BIT(7)
+
+#define NFI_CMD				0x020
+
+#define NFI_STRDATA			0x040
+#define STR_DATA			BIT(0)
+
+#define NFI_STA				0x060
+#define NFI_NAND_FSM			GENMASK(28, 24)
+#define NFI_FSM				GENMASK(19, 16)
+#define READ_EMPTY			BIT(12)
+
+#define NFI_FIFOSTA			0x064
+#define FIFO_WR_REMAIN_S		8
+#define FIFO_RD_REMAIN_S		0
+
+#define NFI_ADDRCNTR			0x070
+#define SEC_CNTR			GENMASK(16, 12)
+#define SEC_CNTR_S			12
+#define NFI_SEC_CNTR(val)               (((val) & SEC_CNTR) >> SEC_CNTR_S)
+
+#define NFI_STRADDR			0x080
+
+#define NFI_BYTELEN			0x084
+#define BUS_SEC_CNTR(val)		(((val) & SEC_CNTR) >> SEC_CNTR_S)
+
+#define NFI_FDM0L			0x0a0
+#define NFI_FDM0M			0x0a4
+#define NFI_FDML(n)			(NFI_FDM0L + (n) * 8)
+#define NFI_FDMM(n)			(NFI_FDM0M + (n) * 8)
+
+#define NFI_DEBUG_CON1			0x220
+#define WBUF_EN				BIT(2)
+
+#define NFI_MASTERSTA			0x224
+#define MAS_ADDR			GENMASK(11, 9)
+#define MAS_RD				GENMASK(8, 6)
+#define MAS_WR				GENMASK(5, 3)
+#define MAS_RDDLY			GENMASK(2, 0)
+#define NFI_MASTERSTA_MASK_7622		(MAS_ADDR | MAS_RD | MAS_WR | MAS_RDDLY)
+#define AHB_BUS_BUSY			BIT(1)
+#define BUS_BUSY			BIT(0)
+#define NFI_MASTERSTA_MASK_7986		(AHB_BUS_BUSY | BUS_BUSY)
+
+/* SNFI registers */
+#define SNF_MAC_CTL			0x500
+#define MAC_XIO_SEL			BIT(4)
+#define SF_MAC_EN			BIT(3)
+#define SF_TRIG				BIT(2)
+#define WIP_READY			BIT(1)
+#define WIP				BIT(0)
+
+#define SNF_MAC_OUTL			0x504
+#define SNF_MAC_INL			0x508
+
+#define SNF_RD_CTL2			0x510
+#define DATA_READ_DUMMY_S		8
+#define DATA_READ_CMD_S			0
+
+#define SNF_RD_CTL3			0x514
+
+#define SNF_PG_CTL1			0x524
+#define PG_LOAD_CMD_S			8
+
+#define SNF_PG_CTL2			0x528
+
+#define SNF_MISC_CTL			0x538
+#define SW_RST				BIT(28)
+#define FIFO_RD_LTC_S			25
+#define PG_LOAD_X4_EN			BIT(20)
+#define DATA_READ_MODE_S		16
+#define DATA_READ_MODE			GENMASK(18, 16)
+#define   DATA_READ_MODE_X1		0
+#define   DATA_READ_MODE_X2		1
+#define   DATA_READ_MODE_X4		2
+#define   DATA_READ_MODE_DUAL		5
+#define   DATA_READ_MODE_QUAD		6
+#define LATCH_LAT_S			8
+#define LATCH_LAT			GENMASK(9, 8)
+#define PG_LOAD_CUSTOM_EN		BIT(7)
+#define DATARD_CUSTOM_EN		BIT(6)
+#define CS_DESELECT_CYC_S		0
+
+#define SNF_MISC_CTL2			0x53c
+#define PROGRAM_LOAD_BYTE_NUM_S		16
+#define READ_DATA_BYTE_NUM_S		11
+
+#define SNF_DLY_CTL3			0x548
+#define SFCK_SAM_DLY_S			0
+
+#define SNF_STA_CTL1			0x550
+#define CUS_PG_DONE			BIT(28)
+#define CUS_READ_DONE			BIT(27)
+#define SPI_STATE_S			0
+#define SPI_STATE			GENMASK(3, 0)
+
+#define SNF_CFG				0x55c
+#define SPI_MODE			BIT(0)
+
+#define SNF_GPRAM			0x800
+#define SNF_GPRAM_SIZE			0xa0
+
+#define SNFI_POLL_INTERVAL		1000000
+
+static const uint8_t mt7622_spare_sizes[] = { 16, 26, 27, 28 };
+
+static const uint8_t mt7986_spare_sizes[] = {
+	16, 26, 27, 28, 32, 36, 40, 44, 48, 49, 50, 51, 52, 62, 61, 63, 64,
+	67, 74
+};
+
+static const struct mtk_snand_soc_data mtk_snand_socs[__SNAND_SOC_MAX] = {
+	[SNAND_SOC_MT7622] = {
+		.sector_size = 512,
+		.max_sectors = 8,
+		.fdm_size = 8,
+		.fdm_ecc_size = 1,
+		.fifo_size = 32,
+		.bbm_swap = false,
+		.empty_page_check = false,
+		.mastersta_mask = NFI_MASTERSTA_MASK_7622,
+		.spare_sizes = mt7622_spare_sizes,
+		.num_spare_size = ARRAY_SIZE(mt7622_spare_sizes),
+		.latch_lat = 0,
+		.sample_delay = 40
+	},
+	[SNAND_SOC_MT7629] = {
+		.sector_size = 512,
+		.max_sectors = 8,
+		.fdm_size = 8,
+		.fdm_ecc_size = 1,
+		.fifo_size = 32,
+		.bbm_swap = true,
+		.empty_page_check = false,
+		.mastersta_mask = NFI_MASTERSTA_MASK_7622,
+		.spare_sizes = mt7622_spare_sizes,
+		.num_spare_size = ARRAY_SIZE(mt7622_spare_sizes),
+		.latch_lat = 0,
+		.sample_delay = 40
+	},
+	[SNAND_SOC_MT7986] = {
+		.sector_size = 1024,
+		.max_sectors = 16,
+		.fdm_size = 8,
+		.fdm_ecc_size = 1,
+		.fifo_size = 64,
+		.bbm_swap = true,
+		.empty_page_check = true,
+		.mastersta_mask = NFI_MASTERSTA_MASK_7986,
+		.spare_sizes = mt7986_spare_sizes,
+		.num_spare_size = ARRAY_SIZE(mt7986_spare_sizes),
+		.latch_lat = 0,
+		.sample_delay = 40
+	},
+};
+
+static inline uint32_t nfi_read32(struct mtk_snand *snf, uint32_t reg)
+{
+	return readl(snf->nfi_base + reg);
+}
+
+static inline void nfi_write32(struct mtk_snand *snf, uint32_t reg,
+			       uint32_t val)
+{
+	writel(val, snf->nfi_base + reg);
+}
+
+static inline void nfi_write16(struct mtk_snand *snf, uint32_t reg,
+			       uint16_t val)
+{
+	writew(val, snf->nfi_base + reg);
+}
+
+static inline void nfi_rmw32(struct mtk_snand *snf, uint32_t reg, uint32_t clr,
+			     uint32_t set)
+{
+	uint32_t val;
+
+	val = readl(snf->nfi_base + reg);
+	val &= ~clr;
+	val |= set;
+	writel(val, snf->nfi_base + reg);
+}
+
+static void nfi_write_data(struct mtk_snand *snf, uint32_t reg,
+			   const uint8_t *data, uint32_t len)
+{
+	uint32_t i, val = 0, es = sizeof(uint32_t);
+
+	for (i = reg; i < reg + len; i++) {
+		val |= ((uint32_t)*data++) << (8 * (i % es));
+
+		if (i % es == es - 1 || i == reg + len - 1) {
+			nfi_write32(snf, i & ~(es - 1), val);
+			val = 0;
+		}
+	}
+}
+
+static void nfi_read_data(struct mtk_snand *snf, uint32_t reg, uint8_t *data,
+			  uint32_t len)
+{
+	uint32_t i, val = 0, es = sizeof(uint32_t);
+
+	for (i = reg; i < reg + len; i++) {
+		if (i == reg || i % es == 0)
+			val = nfi_read32(snf, i & ~(es - 1));
+
+		*data++ = (uint8_t)(val >> (8 * (i % es)));
+	}
+}
+
+static inline void do_bm_swap(uint8_t *bm1, uint8_t *bm2)
+{
+	uint8_t tmp = *bm1;
+	*bm1 = *bm2;
+	*bm2 = tmp;
+}
+
+static void mtk_snand_bm_swap_raw(struct mtk_snand *snf)
+{
+	uint32_t fdm_bbm_pos;
+
+	if (!snf->nfi_soc->bbm_swap || snf->ecc_steps == 1)
+		return;
+
+	fdm_bbm_pos = (snf->ecc_steps - 1) * snf->raw_sector_size +
+		      snf->nfi_soc->sector_size;
+	do_bm_swap(&snf->page_cache[fdm_bbm_pos],
+		   &snf->page_cache[snf->writesize]);
+}
+
+static void mtk_snand_bm_swap(struct mtk_snand *snf)
+{
+	uint32_t buf_bbm_pos, fdm_bbm_pos;
+
+	if (!snf->nfi_soc->bbm_swap || snf->ecc_steps == 1)
+		return;
+
+	buf_bbm_pos = snf->writesize -
+		      (snf->ecc_steps - 1) * snf->spare_per_sector;
+	fdm_bbm_pos = snf->writesize +
+		      (snf->ecc_steps - 1) * snf->nfi_soc->fdm_size;
+	do_bm_swap(&snf->page_cache[fdm_bbm_pos],
+		   &snf->page_cache[buf_bbm_pos]);
+}
+
+static void mtk_snand_fdm_bm_swap_raw(struct mtk_snand *snf)
+{
+	uint32_t fdm_bbm_pos1, fdm_bbm_pos2;
+
+	if (!snf->nfi_soc->bbm_swap || snf->ecc_steps == 1)
+		return;
+
+	fdm_bbm_pos1 = snf->nfi_soc->sector_size;
+	fdm_bbm_pos2 = (snf->ecc_steps - 1) * snf->raw_sector_size +
+		       snf->nfi_soc->sector_size;
+	do_bm_swap(&snf->page_cache[fdm_bbm_pos1],
+		   &snf->page_cache[fdm_bbm_pos2]);
+}
+
+static void mtk_snand_fdm_bm_swap(struct mtk_snand *snf)
+{
+	uint32_t fdm_bbm_pos1, fdm_bbm_pos2;
+
+	if (!snf->nfi_soc->bbm_swap || snf->ecc_steps == 1)
+		return;
+
+	fdm_bbm_pos1 = snf->writesize;
+	fdm_bbm_pos2 = snf->writesize +
+		       (snf->ecc_steps - 1) * snf->nfi_soc->fdm_size;
+	do_bm_swap(&snf->page_cache[fdm_bbm_pos1],
+		   &snf->page_cache[fdm_bbm_pos2]);
+}
+
+static int mtk_nfi_reset(struct mtk_snand *snf)
+{
+	uint32_t val, fifo_mask;
+	int ret;
+
+	nfi_write32(snf, NFI_CON, CON_FIFO_FLUSH | CON_NFI_RST);
+
+	ret = read16_poll_timeout(snf->nfi_base + NFI_MASTERSTA, val,
+				  !(val & snf->nfi_soc->mastersta_mask), 0,
+				  SNFI_POLL_INTERVAL);
+	if (ret) {
+		snand_log_nfi(snf->pdev,
+			      "NFI master is still busy after reset\n");
+		return ret;
+	}
+
+	ret = read32_poll_timeout(snf->nfi_base + NFI_STA, val,
+				  !(val & (NFI_FSM | NFI_NAND_FSM)), 0,
+				  SNFI_POLL_INTERVAL);
+	if (ret) {
+		snand_log_nfi(snf->pdev, "Failed to reset NFI\n");
+		return ret;
+	}
+
+	fifo_mask = ((snf->nfi_soc->fifo_size - 1) << FIFO_RD_REMAIN_S) |
+		    ((snf->nfi_soc->fifo_size - 1) << FIFO_WR_REMAIN_S);
+	ret = read16_poll_timeout(snf->nfi_base + NFI_FIFOSTA, val,
+				  !(val & fifo_mask), 0, SNFI_POLL_INTERVAL);
+	if (ret) {
+		snand_log_nfi(snf->pdev, "NFI FIFOs are not empty\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int mtk_snand_mac_reset(struct mtk_snand *snf)
+{
+	int ret;
+	uint32_t val;
+
+	nfi_rmw32(snf, SNF_MISC_CTL, 0, SW_RST);
+
+	ret = read32_poll_timeout(snf->nfi_base + SNF_STA_CTL1, val,
+				  !(val & SPI_STATE), 0, SNFI_POLL_INTERVAL);
+	if (ret)
+		snand_log_snfi(snf->pdev, "Failed to reset SNFI MAC\n");
+
+	nfi_write32(snf, SNF_MISC_CTL, (2 << FIFO_RD_LTC_S) |
+		    (10 << CS_DESELECT_CYC_S) | (snf->nfi_soc->latch_lat << LATCH_LAT_S));
+
+	return ret;
+}
+
+static int mtk_snand_mac_trigger(struct mtk_snand *snf, uint32_t outlen,
+				 uint32_t inlen)
+{
+	int ret;
+	uint32_t val;
+
+	nfi_write32(snf, SNF_MAC_CTL, SF_MAC_EN);
+	nfi_write32(snf, SNF_MAC_OUTL, outlen);
+	nfi_write32(snf, SNF_MAC_INL, inlen);
+
+	nfi_write32(snf, SNF_MAC_CTL, SF_MAC_EN | SF_TRIG);
+
+	ret = read32_poll_timeout(snf->nfi_base + SNF_MAC_CTL, val,
+				  val & WIP_READY, 0, SNFI_POLL_INTERVAL);
+	if (ret) {
+		snand_log_snfi(snf->pdev, "Timed out waiting for WIP_READY\n");
+		goto cleanup;
+	}
+
+	ret = read32_poll_timeout(snf->nfi_base + SNF_MAC_CTL, val,
+				  !(val & WIP), 0, SNFI_POLL_INTERVAL);
+	if (ret) {
+		snand_log_snfi(snf->pdev,
+			       "Timed out waiting for WIP cleared\n");
+	}
+
+cleanup:
+	nfi_write32(snf, SNF_MAC_CTL, 0);
+
+	return ret;
+}
+
+int mtk_snand_mac_io(struct mtk_snand *snf, const uint8_t *out, uint32_t outlen,
+		     uint8_t *in, uint32_t inlen)
+{
+	int ret;
+
+	if (outlen + inlen > SNF_GPRAM_SIZE)
+		return -EINVAL;
+
+	mtk_snand_mac_reset(snf);
+
+	nfi_write_data(snf, SNF_GPRAM, out, outlen);
+
+	ret = mtk_snand_mac_trigger(snf, outlen, inlen);
+	if (ret)
+		return ret;
+
+	if (!inlen)
+		return 0;
+
+	nfi_read_data(snf, SNF_GPRAM + outlen, in, inlen);
+
+	return 0;
+}
+
+static int mtk_snand_get_feature(struct mtk_snand *snf, uint32_t addr)
+{
+	uint8_t op[2], val;
+	int ret;
+
+	op[0] = SNAND_CMD_GET_FEATURE;
+	op[1] = (uint8_t)addr;
+
+	ret = mtk_snand_mac_io(snf, op, sizeof(op), &val, 1);
+	if (ret)
+		return ret;
+
+	return val;
+}
+
+int mtk_snand_set_feature(struct mtk_snand *snf, uint32_t addr, uint32_t val)
+{
+	uint8_t op[3];
+
+	op[0] = SNAND_CMD_SET_FEATURE;
+	op[1] = (uint8_t)addr;
+	op[2] = (uint8_t)val;
+
+	return mtk_snand_mac_io(snf, op, sizeof(op), NULL, 0);
+}
+
+static int mtk_snand_poll_status(struct mtk_snand *snf, uint32_t wait_us)
+{
+	int val;
+	mtk_snand_time_t time_start, tmo;
+
+	time_start = timer_get_ticks();
+	tmo = timer_time_to_tick(wait_us);
+
+	do {
+		val = mtk_snand_get_feature(snf, SNAND_FEATURE_STATUS_ADDR);
+		if (!(val & SNAND_STATUS_OIP))
+			return val & (SNAND_STATUS_ERASE_FAIL |
+				      SNAND_STATUS_PROGRAM_FAIL);
+	} while (!timer_is_timeout(time_start, tmo));
+
+	return -ETIMEDOUT;
+}
+
+int mtk_snand_chip_reset(struct mtk_snand *snf)
+{
+	uint8_t op = SNAND_CMD_RESET;
+	int ret;
+
+	ret = mtk_snand_mac_io(snf, &op, 1, NULL, 0);
+	if (ret)
+		return ret;
+
+	ret = mtk_snand_poll_status(snf, SNFI_POLL_INTERVAL);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int mtk_snand_config_feature(struct mtk_snand *snf, uint8_t clr,
+				    uint8_t set)
+{
+	int val, newval;
+	int ret;
+
+	val = mtk_snand_get_feature(snf, SNAND_FEATURE_CONFIG_ADDR);
+	if (val < 0) {
+		snand_log_chip(snf->pdev,
+			       "Failed to get configuration feature\n");
+		return val;
+	}
+
+	newval = (val & (~clr)) | set;
+
+	if (newval == val)
+		return 0;
+
+	ret = mtk_snand_set_feature(snf, SNAND_FEATURE_CONFIG_ADDR,
+				    (uint8_t)newval);
+	if (val < 0) {
+		snand_log_chip(snf->pdev,
+			       "Failed to set configuration feature\n");
+		return ret;
+	}
+
+	val = mtk_snand_get_feature(snf, SNAND_FEATURE_CONFIG_ADDR);
+	if (val < 0) {
+		snand_log_chip(snf->pdev,
+			       "Failed to get configuration feature\n");
+		return val;
+	}
+
+	if (newval != val)
+		return -ENOTSUPP;
+
+	return 0;
+}
+
+static int mtk_snand_ondie_ecc_control(struct mtk_snand *snf, bool enable)
+{
+	int ret;
+
+	if (enable)
+		ret = mtk_snand_config_feature(snf, 0, SNAND_FEATURE_ECC_EN);
+	else
+		ret = mtk_snand_config_feature(snf, SNAND_FEATURE_ECC_EN, 0);
+
+	if (ret) {
+		snand_log_chip(snf->pdev, "Failed to %s On-Die ECC engine\n",
+			       enable ? "enable" : "disable");
+	}
+
+	return ret;
+}
+
+static int mtk_snand_qspi_control(struct mtk_snand *snf, bool enable)
+{
+	int ret;
+
+	if (enable) {
+		ret = mtk_snand_config_feature(snf, 0,
+					       SNAND_FEATURE_QUAD_ENABLE);
+	} else {
+		ret = mtk_snand_config_feature(snf,
+					       SNAND_FEATURE_QUAD_ENABLE, 0);
+	}
+
+	if (ret) {
+		snand_log_chip(snf->pdev, "Failed to %s quad spi\n",
+			       enable ? "enable" : "disable");
+	}
+
+	return ret;
+}
+
+static int mtk_snand_unlock(struct mtk_snand *snf)
+{
+	int ret;
+
+	ret = mtk_snand_set_feature(snf, SNAND_FEATURE_PROTECT_ADDR, 0);
+	if (ret) {
+		snand_log_chip(snf->pdev, "Failed to set protection feature\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int mtk_snand_write_enable(struct mtk_snand *snf)
+{
+	uint8_t op = SNAND_CMD_WRITE_ENABLE;
+	int ret, val;
+
+	ret = mtk_snand_mac_io(snf, &op, 1, NULL, 0);
+	if (ret)
+		return ret;
+
+	val = mtk_snand_get_feature(snf, SNAND_FEATURE_STATUS_ADDR);
+	if (val < 0)
+		return ret;
+
+	if (val & SNAND_STATUS_WEL)
+		return 0;
+
+	snand_log_chip(snf->pdev, "Failed to send write-enable command\n");
+
+	return -ENOTSUPP;
+}
+
+static int mtk_snand_select_die(struct mtk_snand *snf, uint32_t dieidx)
+{
+	if (!snf->select_die)
+		return 0;
+
+	return snf->select_die(snf, dieidx);
+}
+
+static uint64_t mtk_snand_select_die_address(struct mtk_snand *snf,
+					     uint64_t addr)
+{
+	uint32_t dieidx;
+
+	if (!snf->select_die)
+		return addr;
+
+	dieidx = addr >> snf->die_shift;
+
+	mtk_snand_select_die(snf, dieidx);
+
+	return addr & snf->die_mask;
+}
+
+static uint32_t mtk_snand_get_plane_address(struct mtk_snand *snf,
+					    uint32_t page)
+{
+	uint32_t pages_per_block;
+
+	pages_per_block = 1 << (snf->erasesize_shift - snf->writesize_shift);
+
+	if (page & pages_per_block)
+		return 1 << (snf->writesize_shift + 1);
+
+	return 0;
+}
+
+static int mtk_snand_page_op(struct mtk_snand *snf, uint32_t page, uint8_t cmd)
+{
+	uint8_t op[4];
+
+	op[0] = cmd;
+	op[1] = (page >> 16) & 0xff;
+	op[2] = (page >> 8) & 0xff;
+	op[3] = page & 0xff;
+
+	return mtk_snand_mac_io(snf, op, sizeof(op), NULL, 0);
+}
+
+static void mtk_snand_read_fdm(struct mtk_snand *snf, uint8_t *buf)
+{
+	uint32_t vall, valm;
+	uint8_t *oobptr = buf;
+	int i, j;
+
+	for (i = 0; i < snf->ecc_steps; i++) {
+		vall = nfi_read32(snf, NFI_FDML(i));
+		valm = nfi_read32(snf, NFI_FDMM(i));
+
+		for (j = 0; j < snf->nfi_soc->fdm_size; j++)
+			oobptr[j] = (j >= 4 ? valm : vall) >> ((j % 4) * 8);
+
+		oobptr += snf->nfi_soc->fdm_size;
+	}
+}
+
+static int mtk_snand_read_ecc_parity(struct mtk_snand *snf, uint32_t page,
+				     uint32_t sect, uint8_t *oob)
+{
+	uint32_t ecc_bytes = snf->spare_per_sector - snf->nfi_soc->fdm_size;
+	uint32_t coladdr, raw_offs, offs;
+	uint8_t op[4];
+
+	if (sizeof(op) + ecc_bytes > SNF_GPRAM_SIZE) {
+		snand_log_snfi(snf->pdev,
+			       "ECC parity size does not fit the GPRAM\n");
+		return -ENOTSUPP;
+	}
+
+	raw_offs = sect * snf->raw_sector_size + snf->nfi_soc->sector_size +
+		   snf->nfi_soc->fdm_size;
+	offs = snf->ecc_steps * snf->nfi_soc->fdm_size + sect * ecc_bytes;
+
+	/* Column address with plane bit */
+	coladdr = raw_offs | mtk_snand_get_plane_address(snf, page);
+
+	op[0] = SNAND_CMD_READ_FROM_CACHE;
+	op[1] = (coladdr >> 8) & 0xff;
+	op[2] = coladdr & 0xff;
+	op[3] = 0;
+
+	return mtk_snand_mac_io(snf, op, sizeof(op), oob + offs, ecc_bytes);
+}
+
+static int mtk_snand_check_ecc_result(struct mtk_snand *snf, uint32_t page)
+{
+	uint8_t *oob = snf->page_cache + snf->writesize;
+	int i, rc, ret = 0, max_bitflips = 0;
+
+	for (i = 0; i < snf->ecc_steps; i++) {
+		if (snf->sect_bf[i] >= 0) {
+			if (snf->sect_bf[i] > max_bitflips)
+				max_bitflips = snf->sect_bf[i];
+			continue;
+		}
+
+		rc = mtk_snand_read_ecc_parity(snf, page, i, oob);
+		if (rc)
+			return rc;
+
+		rc = mtk_ecc_fixup_empty_sector(snf, i);
+		if (rc < 0) {
+			ret = -EBADMSG;
+
+			snand_log_ecc(snf->pdev,
+			      "Uncorrectable bitflips in page %u sect %u\n",
+			      page, i);
+		} else if (rc) {
+			snf->sect_bf[i] = rc;
+
+			if (snf->sect_bf[i] > max_bitflips)
+				max_bitflips = snf->sect_bf[i];
+
+			snand_log_ecc(snf->pdev,
+			      "%u bitflip%s corrected in page %u sect %u\n",
+			      rc, rc > 1 ? "s" : "", page, i);
+		} else {
+			snf->sect_bf[i] = 0;
+		}
+	}
+
+	return ret ? ret : max_bitflips;
+}
+
+static int mtk_snand_read_cache(struct mtk_snand *snf, uint32_t page, bool raw)
+{
+	uint32_t coladdr, rwbytes, mode, len, val;
+	uintptr_t dma_addr;
+	int ret;
+
+	/* Column address with plane bit */
+	coladdr = mtk_snand_get_plane_address(snf, page);
+
+	mtk_snand_mac_reset(snf);
+	mtk_nfi_reset(snf);
+
+	/* Command and dummy cycles */
+	nfi_write32(snf, SNF_RD_CTL2,
+		    ((uint32_t)snf->dummy_rfc << DATA_READ_DUMMY_S) |
+		    (snf->opcode_rfc << DATA_READ_CMD_S));
+
+	/* Column address */
+	nfi_write32(snf, SNF_RD_CTL3, coladdr);
+
+	/* Set read mode */
+	mode = (uint32_t)snf->mode_rfc << DATA_READ_MODE_S;
+	nfi_rmw32(snf, SNF_MISC_CTL, DATA_READ_MODE,
+			mode | DATARD_CUSTOM_EN | (snf->nfi_soc->latch_lat << LATCH_LAT_S));
+
+	/* Set bytes to read */
+	rwbytes = snf->ecc_steps * snf->raw_sector_size;
+	nfi_write32(snf, SNF_MISC_CTL2, (rwbytes << PROGRAM_LOAD_BYTE_NUM_S) |
+		    rwbytes);
+
+	/* NFI read prepare */
+	mode = raw ? 0 : CNFG_HW_ECC_EN | CNFG_AUTO_FMT_EN;
+	nfi_write16(snf, NFI_CNFG, (CNFG_OP_MODE_CUST << CNFG_OP_MODE_S) |
+		    CNFG_DMA_BURST_EN | CNFG_READ_MODE | CNFG_DMA_MODE | mode);
+
+	nfi_write32(snf, NFI_CON, (snf->ecc_steps << CON_SEC_NUM_S));
+
+	/* Prepare for DMA read */
+	len = snf->writesize + snf->oobsize;
+	ret = dma_mem_map(snf->pdev, snf->page_cache, &dma_addr, len, false);
+	if (ret) {
+		snand_log_nfi(snf->pdev,
+			      "DMA map from device failed with %d\n", ret);
+		return ret;
+	}
+
+	nfi_write32(snf, NFI_STRADDR, (uint32_t)dma_addr);
+
+	if (!raw)
+		mtk_snand_ecc_decoder_start(snf);
+
+	/* Prepare for custom read interrupt */
+	nfi_write32(snf, NFI_INTR_EN, NFI_IRQ_INTR_EN | NFI_IRQ_CUS_READ);
+	irq_completion_init(snf->pdev);
+
+	/* Trigger NFI into custom mode */
+	nfi_write16(snf, NFI_CMD, NFI_CMD_DUMMY_READ);
+
+	/* Start DMA read */
+	nfi_rmw32(snf, NFI_CON, 0, CON_BRD);
+	nfi_write16(snf, NFI_STRDATA, STR_DATA);
+
+	/* Wait for operation finished */
+	ret = irq_completion_wait(snf->pdev, snf->nfi_base + SNF_STA_CTL1,
+				  CUS_READ_DONE, SNFI_POLL_INTERVAL);
+	if (ret) {
+		snand_log_nfi(snf->pdev,
+			      "DMA timed out for reading from cache\n");
+		goto cleanup;
+	}
+
+	/* Wait for BUS_SEC_CNTR returning expected value */
+	ret = read32_poll_timeout(snf->nfi_base + NFI_BYTELEN, val,
+				  BUS_SEC_CNTR(val) >= snf->ecc_steps,
+				  0, SNFI_POLL_INTERVAL);
+	if (ret) {
+		snand_log_nfi(snf->pdev,
+			      "Timed out waiting for BUS_SEC_CNTR\n");
+		goto cleanup;
+	}
+
+	/* Wait for bus becoming idle */
+	ret = read32_poll_timeout(snf->nfi_base + NFI_MASTERSTA, val,
+				  !(val & snf->nfi_soc->mastersta_mask),
+				  0, SNFI_POLL_INTERVAL);
+	if (ret) {
+		snand_log_nfi(snf->pdev,
+			      "Timed out waiting for bus becoming idle\n");
+		goto cleanup;
+	}
+
+	if (!raw) {
+		ret = mtk_ecc_wait_decoder_done(snf);
+		if (ret)
+			goto cleanup;
+
+		mtk_snand_read_fdm(snf, snf->page_cache + snf->writesize);
+
+		mtk_ecc_check_decode_error(snf);
+		mtk_snand_ecc_decoder_stop(snf);
+
+		ret = mtk_snand_check_ecc_result(snf, page);
+	}
+
+cleanup:
+	/* DMA cleanup */
+	dma_mem_unmap(snf->pdev, dma_addr, len, false);
+
+	/* Stop read */
+	nfi_write32(snf, NFI_CON, 0);
+	nfi_write16(snf, NFI_CNFG, 0);
+
+	/* Clear SNF done flag */
+	nfi_rmw32(snf, SNF_STA_CTL1, 0, CUS_READ_DONE);
+	nfi_write32(snf, SNF_STA_CTL1, 0);
+
+	/* Disable interrupt */
+	nfi_read32(snf, NFI_INTR_STA);
+	nfi_write32(snf, NFI_INTR_EN, 0);
+
+	nfi_rmw32(snf, SNF_MISC_CTL, DATARD_CUSTOM_EN | LATCH_LAT, 0);
+
+	return ret;
+}
+
+static void mtk_snand_from_raw_page(struct mtk_snand *snf, void *buf, void *oob)
+{
+	uint32_t i, ecc_bytes = snf->spare_per_sector - snf->nfi_soc->fdm_size;
+	uint8_t *eccptr = oob + snf->ecc_steps * snf->nfi_soc->fdm_size;
+	uint8_t *bufptr = buf, *oobptr = oob, *raw_sector;
+
+	for (i = 0; i < snf->ecc_steps; i++) {
+		raw_sector = snf->page_cache + i * snf->raw_sector_size;
+
+		if (buf) {
+			memcpy(bufptr, raw_sector, snf->nfi_soc->sector_size);
+			bufptr += snf->nfi_soc->sector_size;
+		}
+
+		raw_sector += snf->nfi_soc->sector_size;
+
+		if (oob) {
+			memcpy(oobptr, raw_sector, snf->nfi_soc->fdm_size);
+			oobptr += snf->nfi_soc->fdm_size;
+			raw_sector += snf->nfi_soc->fdm_size;
+
+			memcpy(eccptr, raw_sector, ecc_bytes);
+			eccptr += ecc_bytes;
+		}
+	}
+}
+
+static int mtk_snand_do_read_page(struct mtk_snand *snf, uint64_t addr,
+				  void *buf, void *oob, bool raw, bool format)
+{
+	uint64_t die_addr;
+	uint32_t page, dly_ctrl3;
+	int ret, retry_cnt = 0;
+
+	die_addr = mtk_snand_select_die_address(snf, addr);
+	page = die_addr >> snf->writesize_shift;
+
+	dly_ctrl3 = nfi_read32(snf, SNF_DLY_CTL3);
+
+	ret = mtk_snand_page_op(snf, page, SNAND_CMD_READ_TO_CACHE);
+	if (ret)
+		return ret;
+
+	ret = mtk_snand_poll_status(snf, SNFI_POLL_INTERVAL);
+	if (ret < 0) {
+		snand_log_chip(snf->pdev, "Read to cache command timed out\n");
+		return ret;
+	}
+
+retry:
+	ret = mtk_snand_read_cache(snf, page, raw);
+	if (ret < 0 && ret != -EBADMSG)
+		return ret;
+
+	if (ret == -EBADMSG && retry_cnt < 16) {
+		nfi_write32(snf, SNF_DLY_CTL3, retry_cnt * 2);
+		retry_cnt++;
+		goto retry;
+	}
+
+	if (retry_cnt) {
+		if(ret == -EBADMSG) {
+			nfi_write32(snf, SNF_DLY_CTL3, dly_ctrl3);
+			snand_log_chip(snf->pdev,
+				       "NFI calibration failed. Original sample delay: 0x%x\n",
+				       dly_ctrl3);
+		} else {
+			snand_log_chip(snf->pdev,
+				       "NFI calibration passed. New sample delay: 0x%x\n",
+				       nfi_read32(snf, SNF_DLY_CTL3));
+		}
+	}
+
+	if (raw) {
+		if (format) {
+			mtk_snand_bm_swap_raw(snf);
+			mtk_snand_fdm_bm_swap_raw(snf);
+			mtk_snand_from_raw_page(snf, buf, oob);
+		} else {
+			if (buf)
+				memcpy(buf, snf->page_cache, snf->writesize);
+
+			if (oob) {
+				memset(oob, 0xff, snf->oobsize);
+				memcpy(oob, snf->page_cache + snf->writesize,
+				       snf->ecc_steps * snf->spare_per_sector);
+			}
+		}
+	} else {
+		mtk_snand_bm_swap(snf);
+		mtk_snand_fdm_bm_swap(snf);
+
+		if (buf)
+			memcpy(buf, snf->page_cache, snf->writesize);
+
+		if (oob) {
+			memset(oob, 0xff, snf->oobsize);
+			memcpy(oob, snf->page_cache + snf->writesize,
+			       snf->ecc_steps * snf->nfi_soc->fdm_size);
+		}
+	}
+
+	return ret;
+}
+
+int mtk_snand_read_page(struct mtk_snand *snf, uint64_t addr, void *buf,
+			void *oob, bool raw)
+{
+	if (!snf || (!buf && !oob))
+		return -EINVAL;
+
+	if (addr >= snf->size)
+		return -EINVAL;
+
+	return mtk_snand_do_read_page(snf, addr, buf, oob, raw, true);
+}
+
+static void mtk_snand_write_fdm(struct mtk_snand *snf, const uint8_t *buf)
+{
+	uint32_t vall, valm, fdm_size = snf->nfi_soc->fdm_size;
+	const uint8_t *oobptr = buf;
+	int i, j;
+
+	for (i = 0; i < snf->ecc_steps; i++) {
+		vall = 0;
+		valm = 0;
+
+		for (j = 0; j < 8; j++) {
+			if (j < 4)
+				vall |= (j < fdm_size ? oobptr[j] : 0xff)
+						<< (j * 8);
+			else
+				valm |= (j < fdm_size ? oobptr[j] : 0xff)
+						<< ((j - 4) * 8);
+		}
+
+		nfi_write32(snf, NFI_FDML(i), vall);
+		nfi_write32(snf, NFI_FDMM(i), valm);
+
+		oobptr += fdm_size;
+	}
+}
+
+static int mtk_snand_program_load(struct mtk_snand *snf, uint32_t page,
+				  bool raw)
+{
+	uint32_t coladdr, rwbytes, mode, len, val;
+	uintptr_t dma_addr;
+	int ret;
+
+	/* Column address with plane bit */
+	coladdr = mtk_snand_get_plane_address(snf, page);
+
+	mtk_snand_mac_reset(snf);
+	mtk_nfi_reset(snf);
+
+	/* Write FDM registers if necessary */
+	if (!raw)
+		mtk_snand_write_fdm(snf, snf->page_cache + snf->writesize);
+
+	/* Command */
+	nfi_write32(snf, SNF_PG_CTL1, (snf->opcode_pl << PG_LOAD_CMD_S));
+
+	/* Column address */
+	nfi_write32(snf, SNF_PG_CTL2, coladdr);
+
+	/* Set write mode */
+	mode = snf->mode_pl ? PG_LOAD_X4_EN : 0;
+	nfi_rmw32(snf, SNF_MISC_CTL, PG_LOAD_X4_EN, mode | PG_LOAD_CUSTOM_EN);
+
+	/* Set bytes to write */
+	rwbytes = snf->ecc_steps * snf->raw_sector_size;
+	nfi_write32(snf, SNF_MISC_CTL2, (rwbytes << PROGRAM_LOAD_BYTE_NUM_S) |
+		    rwbytes);
+
+	/* NFI write prepare */
+	mode = raw ? 0 : CNFG_HW_ECC_EN | CNFG_AUTO_FMT_EN;
+	nfi_write16(snf, NFI_CNFG, (CNFG_OP_MODE_PROGRAM << CNFG_OP_MODE_S) |
+		    CNFG_DMA_BURST_EN | CNFG_DMA_MODE | mode);
+
+	nfi_write32(snf, NFI_CON, (snf->ecc_steps << CON_SEC_NUM_S));
+
+	/* Prepare for DMA write */
+	len = snf->writesize + snf->oobsize;
+	ret = dma_mem_map(snf->pdev, snf->page_cache, &dma_addr, len, true);
+	if (ret) {
+		snand_log_nfi(snf->pdev,
+			      "DMA map to device failed with %d\n", ret);
+		return ret;
+	}
+
+	nfi_write32(snf, NFI_STRADDR, (uint32_t)dma_addr);
+
+	if (!raw)
+		mtk_snand_ecc_encoder_start(snf);
+
+	/* Prepare for custom write interrupt */
+	nfi_write32(snf, NFI_INTR_EN, NFI_IRQ_INTR_EN | NFI_IRQ_CUS_PG);
+	irq_completion_init(snf->pdev);
+
+	/* Trigger NFI into custom mode */
+	nfi_write16(snf, NFI_CMD, NFI_CMD_DUMMY_WRITE);
+
+	/* Start DMA write */
+	nfi_rmw32(snf, NFI_CON, 0, CON_BWR);
+	nfi_write16(snf, NFI_STRDATA, STR_DATA);
+
+	/* Wait for operation finished */
+	ret = irq_completion_wait(snf->pdev, snf->nfi_base + SNF_STA_CTL1,
+				  CUS_PG_DONE, SNFI_POLL_INTERVAL);
+	if (ret) {
+		snand_log_nfi(snf->pdev,
+			      "DMA timed out for program load\n");
+		goto cleanup;
+	}
+
+	/* Wait for NFI_SEC_CNTR returning expected value */
+	ret = read32_poll_timeout(snf->nfi_base + NFI_ADDRCNTR, val,
+				  NFI_SEC_CNTR(val) >= snf->ecc_steps,
+				  0, SNFI_POLL_INTERVAL);
+	if (ret) {
+		snand_log_nfi(snf->pdev,
+			      "Timed out waiting for BUS_SEC_CNTR\n");
+		goto cleanup;
+	}
+
+	if (!raw)
+		mtk_snand_ecc_encoder_stop(snf);
+
+cleanup:
+	/* DMA cleanup */
+	dma_mem_unmap(snf->pdev, dma_addr, len, true);
+
+	/* Stop write */
+	nfi_write32(snf, NFI_CON, 0);
+	nfi_write16(snf, NFI_CNFG, 0);
+
+	/* Clear SNF done flag */
+	nfi_rmw32(snf, SNF_STA_CTL1, 0, CUS_PG_DONE);
+	nfi_write32(snf, SNF_STA_CTL1, 0);
+
+	/* Disable interrupt */
+	nfi_read32(snf, NFI_INTR_STA);
+	nfi_write32(snf, NFI_INTR_EN, 0);
+
+	nfi_rmw32(snf, SNF_MISC_CTL, PG_LOAD_CUSTOM_EN, 0);
+
+	return ret;
+}
+
+static void mtk_snand_to_raw_page(struct mtk_snand *snf,
+				  const void *buf, const void *oob,
+				  bool empty_ecc)
+{
+	uint32_t i, ecc_bytes = snf->spare_per_sector - snf->nfi_soc->fdm_size;
+	const uint8_t *eccptr = oob + snf->ecc_steps * snf->nfi_soc->fdm_size;
+	const uint8_t *bufptr = buf, *oobptr = oob;
+	uint8_t *raw_sector;
+
+	memset(snf->page_cache, 0xff, snf->writesize + snf->oobsize);
+	for (i = 0; i < snf->ecc_steps; i++) {
+		raw_sector = snf->page_cache + i * snf->raw_sector_size;
+
+		if (buf) {
+			memcpy(raw_sector, bufptr, snf->nfi_soc->sector_size);
+			bufptr += snf->nfi_soc->sector_size;
+		}
+
+		raw_sector += snf->nfi_soc->sector_size;
+
+		if (oob) {
+			memcpy(raw_sector, oobptr, snf->nfi_soc->fdm_size);
+			oobptr += snf->nfi_soc->fdm_size;
+			raw_sector += snf->nfi_soc->fdm_size;
+
+			if (empty_ecc)
+				memset(raw_sector, 0xff, ecc_bytes);
+			else
+				memcpy(raw_sector, eccptr, ecc_bytes);
+			eccptr += ecc_bytes;
+		}
+	}
+}
+
+static bool mtk_snand_is_empty_page(struct mtk_snand *snf, const void *buf,
+				    const void *oob)
+{
+	const uint8_t *p = buf;
+	uint32_t i, j;
+
+	if (buf) {
+		for (i = 0; i < snf->writesize; i++) {
+			if (p[i] != 0xff)
+				return false;
+		}
+	}
+
+	if (oob) {
+		for (j = 0; j < snf->ecc_steps; j++) {
+			p = oob + j * snf->nfi_soc->fdm_size;
+
+			for (i = 0; i < snf->nfi_soc->fdm_ecc_size; i++) {
+				if (p[i] != 0xff)
+					return false;
+			}
+		}
+	}
+
+	return true;
+}
+
+static int mtk_snand_do_write_page(struct mtk_snand *snf, uint64_t addr,
+				   const void *buf, const void *oob,
+				   bool raw, bool format)
+{
+	uint64_t die_addr;
+	bool empty_ecc = false;
+	uint32_t page;
+	int ret;
+
+	die_addr = mtk_snand_select_die_address(snf, addr);
+	page = die_addr >> snf->writesize_shift;
+
+	if (!raw && mtk_snand_is_empty_page(snf, buf, oob)) {
+		/*
+		 * If the data in the page to be ecc-ed is full 0xff,
+		 * change to raw write mode
+		 */
+		raw = true;
+		format = true;
+
+		/* fill ecc parity code region with 0xff */
+		empty_ecc = true;
+	}
+
+	if (raw) {
+		if (format) {
+			mtk_snand_to_raw_page(snf, buf, oob, empty_ecc);
+			mtk_snand_fdm_bm_swap_raw(snf);
+			mtk_snand_bm_swap_raw(snf);
+		} else {
+			memset(snf->page_cache, 0xff,
+			       snf->writesize + snf->oobsize);
+
+			if (buf)
+				memcpy(snf->page_cache, buf, snf->writesize);
+
+			if (oob) {
+				memcpy(snf->page_cache + snf->writesize, oob,
+				       snf->ecc_steps * snf->spare_per_sector);
+			}
+		}
+	} else {
+		memset(snf->page_cache, 0xff, snf->writesize + snf->oobsize);
+		if (buf)
+			memcpy(snf->page_cache, buf, snf->writesize);
+
+		if (oob) {
+			memcpy(snf->page_cache + snf->writesize, oob,
+			       snf->ecc_steps * snf->nfi_soc->fdm_size);
+		}
+
+		mtk_snand_fdm_bm_swap(snf);
+		mtk_snand_bm_swap(snf);
+	}
+
+	ret = mtk_snand_write_enable(snf);
+	if (ret)
+		return ret;
+
+	ret = mtk_snand_program_load(snf, page, raw);
+	if (ret)
+		return ret;
+
+	ret = mtk_snand_page_op(snf, page, SNAND_CMD_PROGRAM_EXECUTE);
+	if (ret)
+		return ret;
+
+	ret = mtk_snand_poll_status(snf, SNFI_POLL_INTERVAL);
+	if (ret < 0) {
+		snand_log_chip(snf->pdev,
+			       "Page program command timed out on page %u\n",
+			       page);
+		return ret;
+	}
+
+	if (ret & SNAND_STATUS_PROGRAM_FAIL) {
+		snand_log_chip(snf->pdev,
+			       "Page program failed on page %u\n", page);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int mtk_snand_write_page(struct mtk_snand *snf, uint64_t addr, const void *buf,
+			 const void *oob, bool raw)
+{
+	if (!snf || (!buf && !oob))
+		return -EINVAL;
+
+	if (addr >= snf->size)
+		return -EINVAL;
+
+	return mtk_snand_do_write_page(snf, addr, buf, oob, raw, true);
+}
+
+int mtk_snand_erase_block(struct mtk_snand *snf, uint64_t addr)
+{
+	uint64_t die_addr;
+	uint32_t page, block;
+	int ret;
+
+	if (!snf)
+		return -EINVAL;
+
+	if (addr >= snf->size)
+		return -EINVAL;
+
+	die_addr = mtk_snand_select_die_address(snf, addr);
+	block = die_addr >> snf->erasesize_shift;
+	page = block << (snf->erasesize_shift - snf->writesize_shift);
+
+	ret = mtk_snand_write_enable(snf);
+	if (ret)
+		return ret;
+
+	ret = mtk_snand_page_op(snf, page, SNAND_CMD_BLOCK_ERASE);
+	if (ret)
+		return ret;
+
+	ret = mtk_snand_poll_status(snf, SNFI_POLL_INTERVAL);
+	if (ret < 0) {
+		snand_log_chip(snf->pdev,
+			       "Block erase command timed out on block %u\n",
+			       block);
+		return ret;
+	}
+
+	if (ret & SNAND_STATUS_ERASE_FAIL) {
+		snand_log_chip(snf->pdev,
+			       "Block erase failed on block %u\n", block);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int mtk_snand_block_isbad_std(struct mtk_snand *snf, uint64_t addr)
+{
+	int ret;
+
+	ret = mtk_snand_do_read_page(snf, addr, NULL, snf->buf_cache, true,
+				     false);
+	if (ret && ret != -EBADMSG)
+		return ret;
+
+	return snf->buf_cache[0] != 0xff;
+}
+
+static int mtk_snand_block_isbad_mtk(struct mtk_snand *snf, uint64_t addr)
+{
+	int ret;
+
+	ret = mtk_snand_do_read_page(snf, addr, NULL, snf->buf_cache, true,
+				     true);
+	if (ret && ret != -EBADMSG)
+		return ret;
+
+	return snf->buf_cache[0] != 0xff;
+}
+
+int mtk_snand_block_isbad(struct mtk_snand *snf, uint64_t addr)
+{
+	if (!snf)
+		return -EINVAL;
+
+	if (addr >= snf->size)
+		return -EINVAL;
+
+	addr &= ~snf->erasesize_mask;
+
+	if (snf->nfi_soc->bbm_swap)
+		return mtk_snand_block_isbad_std(snf, addr);
+
+	return mtk_snand_block_isbad_mtk(snf, addr);
+}
+
+static int mtk_snand_block_markbad_std(struct mtk_snand *snf, uint64_t addr)
+{
+	/* Standard BBM position */
+	memset(snf->buf_cache, 0xff, snf->oobsize);
+	snf->buf_cache[0] = 0;
+
+	return mtk_snand_do_write_page(snf, addr, NULL, snf->buf_cache, true,
+				       false);
+}
+
+static int mtk_snand_block_markbad_mtk(struct mtk_snand *snf, uint64_t addr)
+{
+	/* Write the whole page with zeros */
+	memset(snf->buf_cache, 0, snf->writesize + snf->oobsize);
+
+	return mtk_snand_do_write_page(snf, addr, snf->buf_cache,
+				       snf->buf_cache + snf->writesize, true,
+				       true);
+}
+
+int mtk_snand_block_markbad(struct mtk_snand *snf, uint64_t addr)
+{
+	if (!snf)
+		return -EINVAL;
+
+	if (addr >= snf->size)
+		return -EINVAL;
+
+	addr &= ~snf->erasesize_mask;
+
+	if (snf->nfi_soc->bbm_swap)
+		return mtk_snand_block_markbad_std(snf, addr);
+
+	return mtk_snand_block_markbad_mtk(snf, addr);
+}
+
+int mtk_snand_fill_oob(struct mtk_snand *snf, uint8_t *oobraw,
+		       const uint8_t *oobbuf, size_t ooblen)
+{
+	size_t len = ooblen, sect_fdm_len;
+	const uint8_t *oob = oobbuf;
+	uint32_t step = 0;
+
+	if (!snf || !oobraw || !oob)
+		return -EINVAL;
+
+	while (len && step < snf->ecc_steps) {
+		sect_fdm_len = snf->nfi_soc->fdm_size - 1;
+		if (sect_fdm_len > len)
+			sect_fdm_len = len;
+
+		memcpy(oobraw + step * snf->nfi_soc->fdm_size + 1, oob,
+		       sect_fdm_len);
+
+		len -= sect_fdm_len;
+		oob += sect_fdm_len;
+		step++;
+	}
+
+	return len;
+}
+
+int mtk_snand_transfer_oob(struct mtk_snand *snf, uint8_t *oobbuf,
+			   size_t ooblen, const uint8_t *oobraw)
+{
+	size_t len = ooblen, sect_fdm_len;
+	uint8_t *oob = oobbuf;
+	uint32_t step = 0;
+
+	if (!snf || !oobraw || !oob)
+		return -EINVAL;
+
+	while (len && step < snf->ecc_steps) {
+		sect_fdm_len = snf->nfi_soc->fdm_size - 1;
+		if (sect_fdm_len > len)
+			sect_fdm_len = len;
+
+		memcpy(oob, oobraw + step * snf->nfi_soc->fdm_size + 1,
+		       sect_fdm_len);
+
+		len -= sect_fdm_len;
+		oob += sect_fdm_len;
+		step++;
+	}
+
+	return len;
+}
+
+int mtk_snand_read_page_auto_oob(struct mtk_snand *snf, uint64_t addr,
+				 void *buf, void *oob, size_t ooblen,
+				 size_t *actualooblen, bool raw)
+{
+	int ret, oobremain;
+
+	if (!snf)
+		return -EINVAL;
+
+	if (!oob)
+		return mtk_snand_read_page(snf, addr, buf, NULL, raw);
+
+	ret = mtk_snand_read_page(snf, addr, buf, snf->buf_cache, raw);
+	if (ret && ret != -EBADMSG) {
+		if (actualooblen)
+			*actualooblen = 0;
+		return ret;
+	}
+
+	oobremain = mtk_snand_transfer_oob(snf, oob, ooblen, snf->buf_cache);
+	if (actualooblen)
+		*actualooblen = ooblen - oobremain;
+
+	return ret;
+}
+
+int mtk_snand_write_page_auto_oob(struct mtk_snand *snf, uint64_t addr,
+				  const void *buf, const void *oob,
+				  size_t ooblen, size_t *actualooblen, bool raw)
+{
+	int oobremain;
+
+	if (!snf)
+		return -EINVAL;
+
+	if (!oob)
+		return mtk_snand_write_page(snf, addr, buf, NULL, raw);
+
+	memset(snf->buf_cache, 0xff, snf->oobsize);
+	oobremain = mtk_snand_fill_oob(snf, snf->buf_cache, oob, ooblen);
+	if (actualooblen)
+		*actualooblen = ooblen - oobremain;
+
+	return mtk_snand_write_page(snf, addr, buf, snf->buf_cache, raw);
+}
+
+int mtk_snand_get_chip_info(struct mtk_snand *snf,
+			    struct mtk_snand_chip_info *info)
+{
+	if (!snf || !info)
+		return -EINVAL;
+
+	info->model = snf->model;
+	info->chipsize = snf->size;
+	info->blocksize = snf->erasesize;
+	info->pagesize = snf->writesize;
+	info->sparesize = snf->oobsize;
+	info->spare_per_sector = snf->spare_per_sector;
+	info->fdm_size = snf->nfi_soc->fdm_size;
+	info->fdm_ecc_size = snf->nfi_soc->fdm_ecc_size;
+	info->num_sectors = snf->ecc_steps;
+	info->sector_size = snf->nfi_soc->sector_size;
+	info->ecc_strength = snf->ecc_strength;
+	info->ecc_bytes = snf->ecc_bytes;
+
+	return 0;
+}
+
+int mtk_snand_irq_process(struct mtk_snand *snf)
+{
+	uint32_t sta, ien;
+
+	if (!snf)
+		return -EINVAL;
+
+	sta = nfi_read32(snf, NFI_INTR_STA);
+	ien = nfi_read32(snf, NFI_INTR_EN);
+
+	if (!(sta & ien))
+		return 0;
+
+	nfi_write32(snf, NFI_INTR_EN, 0);
+	irq_completion_done(snf->pdev);
+
+	return 1;
+}
+
+static int mtk_snand_select_spare_per_sector(struct mtk_snand *snf)
+{
+	uint32_t spare_per_step = snf->oobsize / snf->ecc_steps;
+	int i, mul = 1;
+
+	/*
+	 * If we're using the 1KB sector size, HW will automatically
+	 * double the spare size. So we should only use half of the value.
+	 */
+	if (snf->nfi_soc->sector_size == 1024)
+		mul = 2;
+
+	spare_per_step /= mul;
+
+	for (i = snf->nfi_soc->num_spare_size - 1; i >= 0; i--) {
+		if (snf->nfi_soc->spare_sizes[i] <= spare_per_step) {
+			snf->spare_per_sector = snf->nfi_soc->spare_sizes[i];
+			snf->spare_per_sector *= mul;
+			return i;
+		}
+	}
+
+	snand_log_nfi(snf->pdev,
+		      "Page size %u+%u is not supported\n", snf->writesize,
+		      snf->oobsize);
+
+	return -1;
+}
+
+static int mtk_snand_pagefmt_setup(struct mtk_snand *snf)
+{
+	uint32_t spare_size_idx, spare_size_shift, pagesize_idx;
+	uint32_t sector_size_512;
+
+	if (snf->nfi_soc->sector_size == 512) {
+		sector_size_512 = NFI_SEC_SEL_512;
+		spare_size_shift = NFI_SPARE_SIZE_S;
+	} else {
+		sector_size_512 = 0;
+		spare_size_shift = NFI_SPARE_SIZE_LS_S;
+	}
+
+	switch (snf->writesize) {
+	case SZ_512:
+		pagesize_idx = NFI_PAGE_SIZE_512_2K;
+		break;
+	case SZ_2K:
+		if (snf->nfi_soc->sector_size == 512)
+			pagesize_idx = NFI_PAGE_SIZE_2K_4K;
+		else
+			pagesize_idx = NFI_PAGE_SIZE_512_2K;
+		break;
+	case SZ_4K:
+		if (snf->nfi_soc->sector_size == 512)
+			pagesize_idx = NFI_PAGE_SIZE_4K_8K;
+		else
+			pagesize_idx = NFI_PAGE_SIZE_2K_4K;
+		break;
+	case SZ_8K:
+		if (snf->nfi_soc->sector_size == 512)
+			pagesize_idx = NFI_PAGE_SIZE_8K_16K;
+		else
+			pagesize_idx = NFI_PAGE_SIZE_4K_8K;
+		break;
+	case SZ_16K:
+		pagesize_idx = NFI_PAGE_SIZE_8K_16K;
+		break;
+	default:
+		snand_log_nfi(snf->pdev, "Page size %u is not supported\n",
+			      snf->writesize);
+		return -ENOTSUPP;
+	}
+
+	spare_size_idx = mtk_snand_select_spare_per_sector(snf);
+	if (unlikely(spare_size_idx < 0))
+		return -ENOTSUPP;
+
+	snf->raw_sector_size = snf->nfi_soc->sector_size +
+			       snf->spare_per_sector;
+
+	/* Setup page format */
+	nfi_write32(snf, NFI_PAGEFMT,
+		    (snf->nfi_soc->fdm_ecc_size << NFI_FDM_ECC_NUM_S) |
+		    (snf->nfi_soc->fdm_size << NFI_FDM_NUM_S) |
+		    (spare_size_idx << spare_size_shift) |
+		    (pagesize_idx << NFI_PAGE_SIZE_S) |
+		    sector_size_512);
+
+	return 0;
+}
+
+static enum snand_flash_io mtk_snand_select_opcode(struct mtk_snand *snf,
+				   uint32_t snfi_caps, uint8_t *opcode,
+				   uint8_t *dummy,
+				   const struct snand_io_cap *op_cap)
+{
+	uint32_t i, caps;
+
+	caps = snfi_caps & op_cap->caps;
+
+	i = fls(caps);
+	if (i > 0) {
+		*opcode = op_cap->opcodes[i - 1].opcode;
+		if (dummy)
+			*dummy = op_cap->opcodes[i - 1].dummy;
+		return i - 1;
+	}
+
+	return __SNAND_IO_MAX;
+}
+
+static int mtk_snand_select_opcode_rfc(struct mtk_snand *snf,
+				       uint32_t snfi_caps,
+				       const struct snand_io_cap *op_cap)
+{
+	enum snand_flash_io idx;
+
+	static const uint8_t rfc_modes[__SNAND_IO_MAX] = {
+		[SNAND_IO_1_1_1] = DATA_READ_MODE_X1,
+		[SNAND_IO_1_1_2] = DATA_READ_MODE_X2,
+		[SNAND_IO_1_2_2] = DATA_READ_MODE_DUAL,
+		[SNAND_IO_1_1_4] = DATA_READ_MODE_X4,
+		[SNAND_IO_1_4_4] = DATA_READ_MODE_QUAD,
+	};
+
+	idx = mtk_snand_select_opcode(snf, snfi_caps, &snf->opcode_rfc,
+				      &snf->dummy_rfc, op_cap);
+	if (idx >= __SNAND_IO_MAX) {
+		snand_log_snfi(snf->pdev,
+			       "No capable opcode for read from cache\n");
+		return -ENOTSUPP;
+	}
+
+	snf->mode_rfc = rfc_modes[idx];
+
+	if (idx == SNAND_IO_1_1_4 || idx == SNAND_IO_1_4_4)
+		snf->quad_spi_op = true;
+
+	return 0;
+}
+
+static int mtk_snand_select_opcode_pl(struct mtk_snand *snf, uint32_t snfi_caps,
+				      const struct snand_io_cap *op_cap)
+{
+	enum snand_flash_io idx;
+
+	static const uint8_t pl_modes[__SNAND_IO_MAX] = {
+		[SNAND_IO_1_1_1] = 0,
+		[SNAND_IO_1_1_4] = 1,
+	};
+
+	idx = mtk_snand_select_opcode(snf, snfi_caps, &snf->opcode_pl,
+				      NULL, op_cap);
+	if (idx >= __SNAND_IO_MAX) {
+		snand_log_snfi(snf->pdev,
+			       "No capable opcode for program load\n");
+		return -ENOTSUPP;
+	}
+
+	snf->mode_pl = pl_modes[idx];
+
+	if (idx == SNAND_IO_1_1_4)
+		snf->quad_spi_op = true;
+
+	return 0;
+}
+
+static int mtk_snand_setup(struct mtk_snand *snf,
+			   const struct snand_flash_info *snand_info)
+{
+	const struct snand_mem_org *memorg = &snand_info->memorg;
+	uint32_t i, msg_size, snfi_caps;
+	int ret;
+
+	/* Calculate flash memory organization */
+	snf->model = snand_info->model;
+	snf->writesize = memorg->pagesize;
+	snf->oobsize = memorg->sparesize;
+	snf->erasesize = snf->writesize * memorg->pages_per_block;
+	snf->die_size = (uint64_t)snf->erasesize * memorg->blocks_per_die;
+	snf->size = snf->die_size * memorg->ndies;
+	snf->num_dies = memorg->ndies;
+
+	snf->writesize_mask = snf->writesize - 1;
+	snf->erasesize_mask = snf->erasesize - 1;
+	snf->die_mask = snf->die_size - 1;
+
+	snf->writesize_shift = ffs(snf->writesize) - 1;
+	snf->erasesize_shift = ffs(snf->erasesize) - 1;
+	snf->die_shift = mtk_snand_ffs64(snf->die_size) - 1;
+
+	snf->select_die = snand_info->select_die;
+
+	/* Determine opcodes for read from cache/program load */
+	snfi_caps = SPI_IO_1_1_1 | SPI_IO_1_1_2 | SPI_IO_1_2_2;
+	if (snf->snfi_quad_spi)
+		snfi_caps |= SPI_IO_1_1_4 | SPI_IO_1_4_4;
+
+	ret = mtk_snand_select_opcode_rfc(snf, snfi_caps, snand_info->cap_rd);
+	if (ret)
+		return ret;
+
+	ret = mtk_snand_select_opcode_pl(snf, snfi_caps, snand_info->cap_pl);
+	if (ret)
+		return ret;
+
+	/* ECC and page format */
+	snf->ecc_steps = snf->writesize / snf->nfi_soc->sector_size;
+	if (snf->ecc_steps > snf->nfi_soc->max_sectors) {
+		snand_log_nfi(snf->pdev, "Page size %u is not supported\n",
+			      snf->writesize);
+		return -ENOTSUPP;
+	}
+
+	ret = mtk_snand_pagefmt_setup(snf);
+	if (ret)
+		return ret;
+
+	msg_size = snf->nfi_soc->sector_size + snf->nfi_soc->fdm_ecc_size;
+	ret = mtk_ecc_setup(snf, snf->nfi_base + NFI_FDM0L,
+			    snf->spare_per_sector - snf->nfi_soc->fdm_size,
+			    msg_size);
+	if (ret)
+		return ret;
+
+	nfi_write16(snf, NFI_CNFG, 0);
+
+	/* Tuning options */
+	nfi_write16(snf, NFI_DEBUG_CON1, WBUF_EN);
+	nfi_write32(snf, SNF_DLY_CTL3, (snf->nfi_soc->sample_delay << SFCK_SAM_DLY_S));
+
+	/* Interrupts */
+	nfi_read32(snf, NFI_INTR_STA);
+	nfi_write32(snf, NFI_INTR_EN, 0);
+
+	/* Clear SNF done flag */
+	nfi_rmw32(snf, SNF_STA_CTL1, 0, CUS_READ_DONE | CUS_PG_DONE);
+	nfi_write32(snf, SNF_STA_CTL1, 0);
+
+	/* Initialization on all dies */
+	for (i = 0; i < snf->num_dies; i++) {
+		mtk_snand_select_die(snf, i);
+
+		/* Disable On-Die ECC engine */
+		ret = mtk_snand_ondie_ecc_control(snf, false);
+		if (ret)
+			return ret;
+
+		/* Disable block protection */
+		mtk_snand_unlock(snf);
+
+		/* Enable/disable quad-spi */
+		mtk_snand_qspi_control(snf, snf->quad_spi_op);
+	}
+
+	mtk_snand_select_die(snf, 0);
+
+	return 0;
+}
+
+static int mtk_snand_id_probe(struct mtk_snand *snf,
+			      const struct snand_flash_info **snand_info)
+{
+	uint8_t id[4], op[2];
+	int ret;
+
+	/* Read SPI-NAND JEDEC ID, OP + dummy/addr + ID */
+	op[0] = SNAND_CMD_READID;
+	op[1] = 0;
+	ret = mtk_snand_mac_io(snf, op, 2, id, sizeof(id));
+	if (ret)
+		return ret;
+
+	*snand_info = snand_flash_id_lookup(SNAND_ID_DYMMY, id);
+	if (*snand_info)
+		return 0;
+
+	/* Read SPI-NAND JEDEC ID, OP + ID */
+	op[0] = SNAND_CMD_READID;
+	ret = mtk_snand_mac_io(snf, op, 1, id, sizeof(id));
+	if (ret)
+		return ret;
+
+	*snand_info = snand_flash_id_lookup(SNAND_ID_DYMMY, id);
+	if (*snand_info)
+		return 0;
+
+	snand_log_chip(snf->pdev,
+		       "Unrecognized SPI-NAND ID: %02x %02x %02x %02x\n",
+		       id[0], id[1], id[2], id[3]);
+
+	return -EINVAL;
+}
+
+int mtk_snand_init(void *dev, const struct mtk_snand_platdata *pdata,
+		   struct mtk_snand **psnf)
+{
+	const struct snand_flash_info *snand_info;
+	uint32_t rawpage_size, sect_bf_size;
+	struct mtk_snand tmpsnf, *snf;
+	int ret;
+
+	if (!pdata || !psnf)
+		return -EINVAL;
+
+	if (pdata->soc >= __SNAND_SOC_MAX) {
+		snand_log_chip(dev, "Invalid SOC %u for MTK-SNAND\n",
+			       pdata->soc);
+		return -EINVAL;
+	}
+
+	/* Dummy instance only for initial reset and id probe */
+	tmpsnf.nfi_base = pdata->nfi_base;
+	tmpsnf.ecc_base = pdata->ecc_base;
+	tmpsnf.soc = pdata->soc;
+	tmpsnf.nfi_soc = &mtk_snand_socs[pdata->soc];
+	tmpsnf.pdev = dev;
+
+	/* Switch to SNFI mode */
+	writel(SPI_MODE, tmpsnf.nfi_base + SNF_CFG);
+
+	/* Reset SNFI & NFI */
+	mtk_snand_mac_reset(&tmpsnf);
+	mtk_nfi_reset(&tmpsnf);
+
+	/* Reset SPI-NAND chip */
+	ret = mtk_snand_chip_reset(&tmpsnf);
+	if (ret) {
+		snand_log_chip(dev, "Failed to reset SPI-NAND chip\n");
+		return ret;
+	}
+
+	/* Probe SPI-NAND flash by JEDEC ID */
+	ret = mtk_snand_id_probe(&tmpsnf, &snand_info);
+	if (ret)
+		return ret;
+
+	rawpage_size = snand_info->memorg.pagesize +
+		       snand_info->memorg.sparesize;
+
+	sect_bf_size = mtk_snand_socs[pdata->soc].max_sectors *
+		       sizeof(*snf->sect_bf);
+
+	/* Allocate memory for instance and cache */
+	snf = generic_mem_alloc(dev,
+				sizeof(*snf) + rawpage_size + sect_bf_size);
+	if (!snf) {
+		snand_log_chip(dev, "Failed to allocate memory for instance\n");
+		return -ENOMEM;
+	}
+
+	snf->sect_bf = (int *)((uintptr_t)snf + sizeof(*snf));
+	snf->buf_cache = (uint8_t *)((uintptr_t)snf->sect_bf + sect_bf_size);
+
+	/* Allocate memory for DMA buffer */
+	snf->page_cache = dma_mem_alloc(dev, rawpage_size);
+	if (!snf->page_cache) {
+		generic_mem_free(dev, snf);
+		snand_log_chip(dev,
+			       "Failed to allocate memory for DMA buffer\n");
+		return -ENOMEM;
+	}
+
+	/* Fill up instance */
+	snf->pdev = dev;
+	snf->nfi_base = pdata->nfi_base;
+	snf->ecc_base = pdata->ecc_base;
+	snf->soc = pdata->soc;
+	snf->nfi_soc = &mtk_snand_socs[pdata->soc];
+	snf->snfi_quad_spi = pdata->quad_spi;
+
+	/* Initialize SNFI & ECC engine */
+	ret = mtk_snand_setup(snf, snand_info);
+	if (ret) {
+		dma_mem_free(dev, snf->page_cache);
+		generic_mem_free(dev, snf);
+		return ret;
+	}
+
+	*psnf = snf;
+
+	return 0;
+}
+
+int mtk_snand_cleanup(struct mtk_snand *snf)
+{
+	if (!snf)
+		return 0;
+
+	dma_mem_free(snf->pdev, snf->page_cache);
+	generic_mem_free(snf->pdev, snf);
+
+	return 0;
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand.h
new file mode 100644
index 0000000..382f80c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/mtd/mtk-snand/mtk-snand.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#ifndef _MTK_SNAND_H_
+#define _MTK_SNAND_H_
+
+#ifndef PRIVATE_MTK_SNAND_HEADER
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+#endif
+
+enum mtk_snand_soc {
+	SNAND_SOC_MT7622,
+	SNAND_SOC_MT7629,
+	SNAND_SOC_MT7986,
+
+	__SNAND_SOC_MAX
+};
+
+struct mtk_snand_platdata {
+	void *nfi_base;
+	void *ecc_base;
+	enum mtk_snand_soc soc;
+	bool quad_spi;
+};
+
+struct mtk_snand_chip_info {
+	const char *model;
+	uint64_t chipsize;
+	uint32_t blocksize;
+	uint32_t pagesize;
+	uint32_t sparesize;
+	uint32_t spare_per_sector;
+	uint32_t fdm_size;
+	uint32_t fdm_ecc_size;
+	uint32_t num_sectors;
+	uint32_t sector_size;
+	uint32_t ecc_strength;
+	uint32_t ecc_bytes;
+};
+
+struct mtk_snand;
+struct snand_flash_info;
+
+int mtk_snand_init(void *dev, const struct mtk_snand_platdata *pdata,
+		   struct mtk_snand **psnf);
+int mtk_snand_cleanup(struct mtk_snand *snf);
+
+int mtk_snand_chip_reset(struct mtk_snand *snf);
+int mtk_snand_read_page(struct mtk_snand *snf, uint64_t addr, void *buf,
+			void *oob, bool raw);
+int mtk_snand_write_page(struct mtk_snand *snf, uint64_t addr, const void *buf,
+			 const void *oob, bool raw);
+int mtk_snand_erase_block(struct mtk_snand *snf, uint64_t addr);
+int mtk_snand_block_isbad(struct mtk_snand *snf, uint64_t addr);
+int mtk_snand_block_markbad(struct mtk_snand *snf, uint64_t addr);
+int mtk_snand_fill_oob(struct mtk_snand *snf, uint8_t *oobraw,
+		       const uint8_t *oobbuf, size_t ooblen);
+int mtk_snand_transfer_oob(struct mtk_snand *snf, uint8_t *oobbuf,
+			   size_t ooblen, const uint8_t *oobraw);
+int mtk_snand_read_page_auto_oob(struct mtk_snand *snf, uint64_t addr,
+				 void *buf, void *oob, size_t ooblen,
+				 size_t *actualooblen, bool raw);
+int mtk_snand_write_page_auto_oob(struct mtk_snand *snf, uint64_t addr,
+				  const void *buf, const void *oob,
+				  size_t ooblen, size_t *actualooblen,
+				  bool raw);
+int mtk_snand_get_chip_info(struct mtk_snand *snf,
+			    struct mtk_snand_chip_info *info);
+int mtk_snand_irq_process(struct mtk_snand *snf);
+
+#endif /* _MTK_SNAND_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/Kconfig b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/Kconfig
new file mode 100755
index 0000000..42e6b38
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/Kconfig
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config NET_VENDOR_MEDIATEK
+	bool "MediaTek ethernet driver"
+	depends on ARCH_MEDIATEK || SOC_MT7621 || SOC_MT7620
+	---help---
+	  If you have a Mediatek SoC with ethernet, say Y.
+
+if NET_VENDOR_MEDIATEK
+
+config NET_MEDIATEK_SOC
+	tristate "MediaTek SoC Gigabit Ethernet support"
+	select PHYLINK
+	---help---
+	  This driver supports the gigabit ethernet MACs in the
+	  MediaTek SoC family.
+
+config MEDIATEK_NETSYS_V2
+	tristate "MediaTek Ethernet NETSYS V2 support"
+	 depends on ARCH_MEDIATEK && NET_MEDIATEK_SOC
+	---help---
+	  This options enable MTK Ethernet NETSYS V2 support
+
+config NET_MEDIATEK_HNAT
+	tristate "MediaTek HW NAT support"
+	depends on NET_MEDIATEK_SOC && NF_CONNTRACK && IP_NF_NAT
+	---help---
+	  This driver supports the hardward Network Address Translation
+	  in the MediaTek MT7986/MT2701/MT7622/MT7629/MT7621 chipset
+	  family.
+
+endif #NET_VENDOR_MEDIATEK
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/Makefile
new file mode 100755
index 0000000..f046e73
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for the Mediatek SoCs built-in ethernet macs
+#
+
+obj-$(CONFIG_NET_MEDIATEK_SOC)			+= mtk_eth.o
+mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o mtk_eth_dbg.o
+obj-$(CONFIG_NET_MEDIATEK_HNAT)			+= mtk_hnat/
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
new file mode 100755
index 0000000..574440d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
@@ -0,0 +1,1529 @@
+/*
+ *   Copyright (C) 2018 MediaTek Inc.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; version 2 of the License
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
+ *   Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
+ *   Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
+ */
+
+#include <linux/trace_seq.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <linux/u64_stats_sync.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/ctype.h>
+#include <linux/debugfs.h>
+#include <linux/of_mdio.h>
+
+#include "mtk_eth_soc.h"
+#include "mtk_eth_dbg.h"
+
+u32 hw_lro_agg_num_cnt[MTK_HW_LRO_RING_NUM][MTK_HW_LRO_MAX_AGG_CNT + 1];
+u32 hw_lro_agg_size_cnt[MTK_HW_LRO_RING_NUM][16];
+u32 hw_lro_tot_agg_cnt[MTK_HW_LRO_RING_NUM];
+u32 hw_lro_tot_flush_cnt[MTK_HW_LRO_RING_NUM];
+u32 hw_lro_agg_flush_cnt[MTK_HW_LRO_RING_NUM];
+u32 hw_lro_age_flush_cnt[MTK_HW_LRO_RING_NUM];
+u32 hw_lro_seq_flush_cnt[MTK_HW_LRO_RING_NUM];
+u32 hw_lro_timestamp_flush_cnt[MTK_HW_LRO_RING_NUM];
+u32 hw_lro_norule_flush_cnt[MTK_HW_LRO_RING_NUM];
+u32 mtk_hwlro_stats_ebl;
+static struct proc_dir_entry *proc_hw_lro_stats, *proc_hw_lro_auto_tlb;
+typedef int (*mtk_lro_dbg_func) (int par);
+
+struct mtk_eth_debug {
+        struct dentry *root;
+};
+
+struct mtk_eth *g_eth;
+
+struct mtk_eth_debug eth_debug;
+
+void mt7530_mdio_w32(struct mtk_eth *eth, u16 reg, u32 val)
+{
+	mutex_lock(&eth->mii_bus->mdio_lock);
+
+	_mtk_mdio_write(eth, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
+	_mtk_mdio_write(eth, 0x1f, (reg >> 2) & 0xf,  val & 0xffff);
+	_mtk_mdio_write(eth, 0x1f, 0x10, val >> 16);
+
+	mutex_unlock(&eth->mii_bus->mdio_lock);
+}
+
+u32 mt7530_mdio_r32(struct mtk_eth *eth, u32 reg)
+{
+	u16 high, low;
+
+	mutex_lock(&eth->mii_bus->mdio_lock);
+
+	_mtk_mdio_write(eth, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
+	low = _mtk_mdio_read(eth, 0x1f, (reg >> 2) & 0xf);
+	high = _mtk_mdio_read(eth, 0x1f, 0x10);
+
+	mutex_unlock(&eth->mii_bus->mdio_lock);
+
+	return (high << 16) | (low & 0xffff);
+}
+
+void mtk_switch_w32(struct mtk_eth *eth, u32 val, unsigned reg)
+{
+	mtk_w32(eth, val, reg + 0x10000);
+}
+EXPORT_SYMBOL(mtk_switch_w32);
+
+u32 mtk_switch_r32(struct mtk_eth *eth, unsigned reg)
+{
+	return mtk_r32(eth, reg + 0x10000);
+}
+EXPORT_SYMBOL(mtk_switch_r32);
+
+static int mtketh_debug_show(struct seq_file *m, void *private)
+{
+	struct mtk_eth *eth = m->private;
+	struct mtk_mac *mac = 0;
+	int  i = 0;
+
+	for (i = 0 ; i < MTK_MAX_DEVS ; i++) {
+		if (!eth->mac[i] ||
+		    of_phy_is_fixed_link(eth->mac[i]->of_node))
+			continue;
+		mac = eth->mac[i];
+#if 0 //FIXME
+		while (j < 30) {
+			d =  _mtk_mdio_read(eth, mac->phy_dev->addr, j);
+
+			seq_printf(m, "phy=%d, reg=0x%08x, data=0x%08x\n",
+				   mac->phy_dev->addr, j, d);
+			j++;
+		}
+#endif		
+	}
+	return 0;
+}
+
+static int mtketh_debug_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, mtketh_debug_show, inode->i_private);
+}
+
+static const struct file_operations mtketh_debug_fops = {
+	.open = mtketh_debug_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int mtketh_mt7530sw_debug_show(struct seq_file *m, void *private)
+{
+	struct mtk_eth *eth = m->private;
+	u32  offset, data;
+	int i;
+	struct mt7530_ranges {
+		u32 start;
+		u32 end;
+	} ranges[] = {
+		{0x0, 0xac},
+		{0x1000, 0x10e0},
+		{0x1100, 0x1140},
+		{0x1200, 0x1240},
+		{0x1300, 0x1340},
+		{0x1400, 0x1440},
+		{0x1500, 0x1540},
+		{0x1600, 0x1640},
+		{0x1800, 0x1848},
+		{0x1900, 0x1948},
+		{0x1a00, 0x1a48},
+		{0x1b00, 0x1b48},
+		{0x1c00, 0x1c48},
+		{0x1d00, 0x1d48},
+		{0x1e00, 0x1e48},
+		{0x1f60, 0x1ffc},
+		{0x2000, 0x212c},
+		{0x2200, 0x222c},
+		{0x2300, 0x232c},
+		{0x2400, 0x242c},
+		{0x2500, 0x252c},
+		{0x2600, 0x262c},
+		{0x3000, 0x3014},
+		{0x30c0, 0x30f8},
+		{0x3100, 0x3114},
+		{0x3200, 0x3214},
+		{0x3300, 0x3314},
+		{0x3400, 0x3414},
+		{0x3500, 0x3514},
+		{0x3600, 0x3614},
+		{0x4000, 0x40d4},
+		{0x4100, 0x41d4},
+		{0x4200, 0x42d4},
+		{0x4300, 0x43d4},
+		{0x4400, 0x44d4},
+		{0x4500, 0x45d4},
+		{0x4600, 0x46d4},
+		{0x4f00, 0x461c},
+		{0x7000, 0x7038},
+		{0x7120, 0x7124},
+		{0x7800, 0x7804},
+		{0x7810, 0x7810},
+		{0x7830, 0x7830},
+		{0x7a00, 0x7a7c},
+		{0x7b00, 0x7b04},
+		{0x7e00, 0x7e04},
+		{0x7ffc, 0x7ffc},
+	};
+
+	if (!mt7530_exist(eth))
+		return -EOPNOTSUPP;
+
+	if ((!eth->mac[0] || !of_phy_is_fixed_link(eth->mac[0]->of_node)) &&
+	    (!eth->mac[1] || !of_phy_is_fixed_link(eth->mac[1]->of_node))) {
+		seq_puts(m, "no switch found\n");
+		return 0;
+	}
+
+	for (i = 0 ; i < ARRAY_SIZE(ranges) ; i++) {
+		for (offset = ranges[i].start;
+		     offset <= ranges[i].end; offset += 4) {
+			data =  mt7530_mdio_r32(eth, offset);
+			seq_printf(m, "mt7530 switch reg=0x%08x, data=0x%08x\n",
+				   offset, data);
+		}
+	}
+
+	return 0;
+}
+
+static int mtketh_debug_mt7530sw_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, mtketh_mt7530sw_debug_show, inode->i_private);
+}
+
+static const struct file_operations mtketh_debug_mt7530sw_fops = {
+	.open = mtketh_debug_mt7530sw_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static ssize_t mtketh_mt7530sw_debugfs_write(struct file *file,
+					     const char __user *ptr,
+					     size_t len, loff_t *off)
+{
+	struct mtk_eth *eth = file->private_data;
+	char buf[32], *token, *p = buf;
+	u32 reg, value, phy;
+	int ret;
+
+	if (!mt7530_exist(eth))
+		return -EOPNOTSUPP;
+
+	if (*off != 0)
+		return 0;
+
+	if (len > sizeof(buf) - 1)
+		len = sizeof(buf) - 1;
+
+	ret = strncpy_from_user(buf, ptr, len);
+	if (ret < 0)
+		return ret;
+	buf[len] = '\0';
+
+	token = strsep(&p, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtoul(token, 16, (unsigned long *)&phy))
+		return -EINVAL;
+
+	token = strsep(&p, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtoul(token, 16, (unsigned long *)&reg))
+		return -EINVAL;
+
+	token = strsep(&p, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtoul(token, 16, (unsigned long *)&value))
+		return -EINVAL;
+
+	pr_info("%s:phy=%d, reg=0x%x, val=0x%x\n", __func__,
+		0x1f, reg, value);
+	mt7530_mdio_w32(eth, reg, value);
+	pr_info("%s:phy=%d, reg=0x%x, val=0x%x confirm..\n", __func__,
+		0x1f, reg, mt7530_mdio_r32(eth, reg));
+
+	return len;
+}
+
+static ssize_t mtketh_debugfs_write(struct file *file, const char __user *ptr,
+				    size_t len, loff_t *off)
+{
+	struct mtk_eth *eth = file->private_data;
+	char buf[32], *token, *p = buf;
+	u32 reg, value, phy;
+	int ret;
+
+	if (*off != 0)
+		return 0;
+
+	if (len > sizeof(buf) - 1)
+		len = sizeof(buf) - 1;
+
+	ret = strncpy_from_user(buf, ptr, len);
+	if (ret < 0)
+		return ret;
+	buf[len] = '\0';
+
+	token = strsep(&p, " ");
+	if (!token)
+		return -EINVAL;
+	if (kstrtoul(token, 16, (unsigned long *)&phy))
+		return -EINVAL;
+
+	token = strsep(&p, " ");
+
+	if (!token)
+		return -EINVAL;
+	if (kstrtoul(token, 16, (unsigned long *)&reg))
+		return -EINVAL;
+
+	token = strsep(&p, " ");
+
+	if (!token)
+		return -EINVAL;
+	if (kstrtoul(token, 16, (unsigned long *)&value))
+		return -EINVAL;
+
+	pr_info("%s:phy=%d, reg=0x%x, val=0x%x\n", __func__,
+		phy, reg, value);
+
+	_mtk_mdio_write(eth, phy,  reg, value);
+
+	pr_info("%s:phy=%d, reg=0x%x, val=0x%x confirm..\n", __func__,
+		phy, reg, _mtk_mdio_read(eth, phy, reg));
+
+	return len;
+}
+
+static ssize_t mtketh_debugfs_reset(struct file *file, const char __user *ptr,
+				    size_t len, loff_t *off)
+{
+	struct mtk_eth *eth = file->private_data;
+
+	schedule_work(&eth->pending_work);
+	return len;
+}
+
+static const struct file_operations fops_reg_w = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.write = mtketh_debugfs_write,
+	.llseek = noop_llseek,
+};
+
+static const struct file_operations fops_eth_reset = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.write = mtketh_debugfs_reset,
+	.llseek = noop_llseek,
+};
+
+static const struct file_operations fops_mt7530sw_reg_w = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.write = mtketh_mt7530sw_debugfs_write,
+	.llseek = noop_llseek,
+};
+
+void mtketh_debugfs_exit(struct mtk_eth *eth)
+{
+	debugfs_remove_recursive(eth_debug.root);
+}
+
+int mtketh_debugfs_init(struct mtk_eth *eth)
+{
+	int ret = 0;
+
+	eth_debug.root = debugfs_create_dir("mtketh", NULL);
+	if (!eth_debug.root) {
+		dev_notice(eth->dev, "%s:err at %d\n", __func__, __LINE__);
+		ret = -ENOMEM;
+	}
+
+	debugfs_create_file("phy_regs", S_IRUGO,
+			    eth_debug.root, eth, &mtketh_debug_fops);
+	debugfs_create_file("phy_reg_w", S_IFREG | S_IWUSR,
+			    eth_debug.root, eth,  &fops_reg_w);
+	debugfs_create_file("reset", S_IFREG | S_IWUSR,
+			    eth_debug.root, eth,  &fops_eth_reset);
+	if (mt7530_exist(eth)) {
+		debugfs_create_file("mt7530sw_regs", S_IRUGO,
+				    eth_debug.root, eth,
+				    &mtketh_debug_mt7530sw_fops);
+		debugfs_create_file("mt7530sw_reg_w", S_IFREG | S_IWUSR,
+				    eth_debug.root, eth,
+				    &fops_mt7530sw_reg_w);
+	}
+	return ret;
+}
+
+void mii_mgr_read_combine(struct mtk_eth *eth, u32 phy_addr, u32 phy_register,
+			  u32 *read_data)
+{
+	if (mt7530_exist(eth) && phy_addr == 31)
+		*read_data = mt7530_mdio_r32(eth, phy_register);
+
+	else
+		*read_data = _mtk_mdio_read(eth, phy_addr, phy_register);
+}
+
+void mii_mgr_write_combine(struct mtk_eth *eth, u16 phy_addr, u16 phy_register,
+			   u32 write_data)
+{
+	if (mt7530_exist(eth) && phy_addr == 31)
+		mt7530_mdio_w32(eth, phy_register, write_data);
+
+	else
+		_mtk_mdio_write(eth, phy_addr, phy_register, write_data);
+}
+
+static void mii_mgr_read_cl45(struct mtk_eth *eth, u16 port, u16 devad, u16 reg, u16 *data)
+{
+	mtk_cl45_ind_read(eth, port, devad, reg, data);
+}
+
+static void mii_mgr_write_cl45(struct mtk_eth *eth, u16 port, u16 devad, u16 reg, u16 data)
+{
+	mtk_cl45_ind_write(eth, port, devad, reg, data);
+}
+
+int mtk_do_priv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	struct mtk_mii_ioctl_data mii;
+	struct mtk_esw_reg reg;
+	u16 val;
+
+	switch (cmd) {
+	case MTKETH_MII_READ:
+		if (copy_from_user(&mii, ifr->ifr_data, sizeof(mii)))
+			goto err_copy;
+		mii_mgr_read_combine(eth, mii.phy_id, mii.reg_num,
+				     &mii.val_out);
+		if (copy_to_user(ifr->ifr_data, &mii, sizeof(mii)))
+			goto err_copy;
+
+		return 0;
+	case MTKETH_MII_WRITE:
+		if (copy_from_user(&mii, ifr->ifr_data, sizeof(mii)))
+			goto err_copy;
+		mii_mgr_write_combine(eth, mii.phy_id, mii.reg_num,
+				      mii.val_in);
+		return 0;
+	case MTKETH_MII_READ_CL45:
+		if (copy_from_user(&mii, ifr->ifr_data, sizeof(mii)))
+			goto err_copy;
+		mii_mgr_read_cl45(eth,
+				  mdio_phy_id_prtad(mii.phy_id),
+				  mdio_phy_id_devad(mii.phy_id),
+				  mii.reg_num,
+				  &val);
+		mii.val_out = val;
+		if (copy_to_user(ifr->ifr_data, &mii, sizeof(mii)))
+			goto err_copy;
+
+		return 0;
+	case MTKETH_MII_WRITE_CL45:
+		if (copy_from_user(&mii, ifr->ifr_data, sizeof(mii)))
+			goto err_copy;
+		val = mii.val_in;
+		mii_mgr_write_cl45(eth,
+				  mdio_phy_id_prtad(mii.phy_id),
+				  mdio_phy_id_devad(mii.phy_id),
+				  mii.reg_num,
+				  val);
+		return 0;
+	case MTKETH_ESW_REG_READ:
+		if (!mt7530_exist(eth))
+			return -EOPNOTSUPP;
+		if (copy_from_user(&reg, ifr->ifr_data, sizeof(reg)))
+			goto err_copy;
+		if (reg.off > REG_ESW_MAX)
+			return -EINVAL;
+		reg.val = mtk_switch_r32(eth, reg.off);
+
+		if (copy_to_user(ifr->ifr_data, &reg, sizeof(reg)))
+			goto err_copy;
+
+		return 0;
+	case MTKETH_ESW_REG_WRITE:
+		if (!mt7530_exist(eth))
+			return -EOPNOTSUPP;
+		if (copy_from_user(&reg, ifr->ifr_data, sizeof(reg)))
+			goto err_copy;
+		if (reg.off > REG_ESW_MAX)
+			return -EINVAL;
+		mtk_switch_w32(eth, reg.val, reg.off);
+
+		return 0;
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+err_copy:
+	return -EFAULT;
+}
+
+int esw_cnt_read(struct seq_file *seq, void *v)
+{
+	unsigned int pkt_cnt = 0;
+	int i = 0;
+	struct mtk_eth *eth = g_eth;
+	unsigned int mib_base = MTK_GDM1_TX_GBCNT;
+
+	seq_puts(seq, "\n		  <<CPU>>\n");
+	seq_puts(seq, "		    |\n");
+	seq_puts(seq, "+-----------------------------------------------+\n");
+	seq_puts(seq, "|		  <<PSE>>		        |\n");
+	seq_puts(seq, "+-----------------------------------------------+\n");
+	seq_puts(seq, "		   |\n");
+	seq_puts(seq, "+-----------------------------------------------+\n");
+	seq_puts(seq, "|		  <<GDMA>>		        |\n");
+	seq_printf(seq, "| GDMA1_RX_GBCNT  : %010u (Rx Good Bytes)	|\n",
+		   mtk_r32(eth, mib_base));
+	seq_printf(seq, "| GDMA1_RX_GPCNT  : %010u (Rx Good Pkts)	|\n",
+		   mtk_r32(eth, mib_base+0x08));
+	seq_printf(seq, "| GDMA1_RX_OERCNT : %010u (overflow error)	|\n",
+		   mtk_r32(eth, mib_base+0x10));
+	seq_printf(seq, "| GDMA1_RX_FERCNT : %010u (FCS error)	|\n",
+		   mtk_r32(eth, mib_base+0x14));
+	seq_printf(seq, "| GDMA1_RX_SERCNT : %010u (too short)	|\n",
+		   mtk_r32(eth, mib_base+0x18));
+	seq_printf(seq, "| GDMA1_RX_LERCNT : %010u (too long)	|\n",
+		   mtk_r32(eth, mib_base+0x1C));
+	seq_printf(seq, "| GDMA1_RX_CERCNT : %010u (checksum error)	|\n",
+		   mtk_r32(eth, mib_base+0x20));
+	seq_printf(seq, "| GDMA1_RX_FCCNT  : %010u (flow control)	|\n",
+		   mtk_r32(eth, mib_base+0x24));
+	seq_printf(seq, "| GDMA1_TX_SKIPCNT: %010u (about count)	|\n",
+		   mtk_r32(eth, mib_base+0x28));
+	seq_printf(seq, "| GDMA1_TX_COLCNT : %010u (collision count)	|\n",
+		   mtk_r32(eth, mib_base+0x2C));
+	seq_printf(seq, "| GDMA1_TX_GBCNT  : %010u (Tx Good Bytes)	|\n",
+		   mtk_r32(eth, mib_base+0x30));
+	seq_printf(seq, "| GDMA1_TX_GPCNT  : %010u (Tx Good Pkts)	|\n",
+		   mtk_r32(eth, mib_base+0x38));
+	seq_puts(seq, "|						|\n");
+	seq_printf(seq, "| GDMA2_RX_GBCNT  : %010u (Rx Good Bytes)	|\n",
+		   mtk_r32(eth, mib_base+0x40));
+	seq_printf(seq, "| GDMA2_RX_GPCNT  : %010u (Rx Good Pkts)	|\n",
+		   mtk_r32(eth, mib_base+0x48));
+	seq_printf(seq, "| GDMA2_RX_OERCNT : %010u (overflow error)	|\n",
+		   mtk_r32(eth, mib_base+0x50));
+	seq_printf(seq, "| GDMA2_RX_FERCNT : %010u (FCS error)	|\n",
+		   mtk_r32(eth, mib_base+0x54));
+	seq_printf(seq, "| GDMA2_RX_SERCNT : %010u (too short)	|\n",
+		   mtk_r32(eth, mib_base+0x58));
+	seq_printf(seq, "| GDMA2_RX_LERCNT : %010u (too long)	|\n",
+		   mtk_r32(eth, mib_base+0x5C));
+	seq_printf(seq, "| GDMA2_RX_CERCNT : %010u (checksum error)	|\n",
+		   mtk_r32(eth, mib_base+0x60));
+	seq_printf(seq, "| GDMA2_RX_FCCNT  : %010u (flow control)	|\n",
+		   mtk_r32(eth, mib_base+0x64));
+	seq_printf(seq, "| GDMA2_TX_SKIPCNT: %010u (skip)		|\n",
+		   mtk_r32(eth, mib_base+0x68));
+	seq_printf(seq, "| GDMA2_TX_COLCNT : %010u (collision)	|\n",
+		   mtk_r32(eth, mib_base+0x6C));
+	seq_printf(seq, "| GDMA2_TX_GBCNT  : %010u (Tx Good Bytes)	|\n",
+		   mtk_r32(eth, mib_base+0x70));
+	seq_printf(seq, "| GDMA2_TX_GPCNT  : %010u (Tx Good Pkts)	|\n",
+		   mtk_r32(eth, mib_base+0x78));
+	seq_puts(seq, "+-----------------------------------------------+\n");
+
+	if (!mt7530_exist(eth))
+		return 0;
+
+#define DUMP_EACH_PORT(base)					\
+	do { \
+		for (i = 0; i < 7; i++) {				\
+			pkt_cnt = mt7530_mdio_r32(eth, (base) + (i * 0x100));\
+			seq_printf(seq, "%8u ", pkt_cnt);		\
+		}							\
+		seq_puts(seq, "\n"); \
+	} while (0)
+
+	seq_printf(seq, "===================== %8s %8s %8s %8s %8s %8s %8s\n",
+		   "Port0", "Port1", "Port2", "Port3", "Port4", "Port5",
+		   "Port6");
+	seq_puts(seq, "Tx Drop Packet      :");
+	DUMP_EACH_PORT(0x4000);
+	seq_puts(seq, "Tx CRC Error        :");
+	DUMP_EACH_PORT(0x4004);
+	seq_puts(seq, "Tx Unicast Packet   :");
+	DUMP_EACH_PORT(0x4008);
+	seq_puts(seq, "Tx Multicast Packet :");
+	DUMP_EACH_PORT(0x400C);
+	seq_puts(seq, "Tx Broadcast Packet :");
+	DUMP_EACH_PORT(0x4010);
+	seq_puts(seq, "Tx Collision Event  :");
+	DUMP_EACH_PORT(0x4014);
+	seq_puts(seq, "Tx Pause Packet     :");
+	DUMP_EACH_PORT(0x402C);
+	seq_puts(seq, "Rx Drop Packet      :");
+	DUMP_EACH_PORT(0x4060);
+	seq_puts(seq, "Rx Filtering Packet :");
+	DUMP_EACH_PORT(0x4064);
+	seq_puts(seq, "Rx Unicast Packet   :");
+	DUMP_EACH_PORT(0x4068);
+	seq_puts(seq, "Rx Multicast Packet :");
+	DUMP_EACH_PORT(0x406C);
+	seq_puts(seq, "Rx Broadcast Packet :");
+	DUMP_EACH_PORT(0x4070);
+	seq_puts(seq, "Rx Alignment Error  :");
+	DUMP_EACH_PORT(0x4074);
+	seq_puts(seq, "Rx CRC Error	    :");
+	DUMP_EACH_PORT(0x4078);
+	seq_puts(seq, "Rx Undersize Error  :");
+	DUMP_EACH_PORT(0x407C);
+	seq_puts(seq, "Rx Fragment Error   :");
+	DUMP_EACH_PORT(0x4080);
+	seq_puts(seq, "Rx Oversize Error   :");
+	DUMP_EACH_PORT(0x4084);
+	seq_puts(seq, "Rx Jabber Error     :");
+	DUMP_EACH_PORT(0x4088);
+	seq_puts(seq, "Rx Pause Packet     :");
+	DUMP_EACH_PORT(0x408C);
+	mt7530_mdio_w32(eth, 0x4fe0, 0xf0);
+	mt7530_mdio_w32(eth, 0x4fe0, 0x800000f0);
+
+	seq_puts(seq, "\n");
+
+	return 0;
+}
+
+static int switch_count_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, esw_cnt_read, 0);
+}
+
+static const struct file_operations switch_count_fops = {
+	.owner = THIS_MODULE,
+	.open = switch_count_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release
+};
+
+static struct proc_dir_entry *proc_tx_ring, *proc_rx_ring;
+
+int tx_ring_read(struct seq_file *seq, void *v)
+{
+	struct mtk_tx_ring *ring = &g_eth->tx_ring;
+	struct mtk_tx_dma *tx_ring;
+	int i = 0;
+
+	tx_ring =
+	    kmalloc(sizeof(struct mtk_tx_dma) * MTK_DMA_SIZE, GFP_KERNEL);
+	if (!tx_ring) {
+		seq_puts(seq, " allocate temp tx_ring fail.\n");
+		return 0;
+	}
+
+	for (i = 0; i < MTK_DMA_SIZE; i++)
+		tx_ring[i] = ring->dma[i];
+
+	seq_printf(seq, "free count = %d\n", (int)atomic_read(&ring->free_count));
+	seq_printf(seq, "cpu next free: %d\n", (int)(ring->next_free - ring->dma));
+	seq_printf(seq, "cpu last free: %d\n", (int)(ring->last_free - ring->dma));
+	for (i = 0; i < MTK_DMA_SIZE; i++) {
+		dma_addr_t tmp = ring->phys + i * sizeof(*tx_ring);
+
+		seq_printf(seq, "%d (%pad): %08x %08x %08x %08x", i, &tmp,
+			   *(int *)&tx_ring[i].txd1, *(int *)&tx_ring[i].txd2,
+			   *(int *)&tx_ring[i].txd3, *(int *)&tx_ring[i].txd4);
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+		seq_printf(seq, " %08x %08x %08x %08x",
+			   *(int *)&tx_ring[i].txd5, *(int *)&tx_ring[i].txd6,
+			   *(int *)&tx_ring[i].txd7, *(int *)&tx_ring[i].txd8);
+#endif
+		seq_printf(seq, "\n");
+	}
+
+	kfree(tx_ring);
+	return 0;
+}
+
+static int tx_ring_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, tx_ring_read, NULL);
+}
+
+static const struct file_operations tx_ring_fops = {
+	.owner = THIS_MODULE,
+	.open = tx_ring_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release
+};
+
+int rx_ring_read(struct seq_file *seq, void *v)
+{
+	struct mtk_rx_ring *ring = &g_eth->rx_ring[0];
+	struct mtk_rx_dma *rx_ring;
+
+	int i = 0;
+
+	rx_ring =
+	    kmalloc(sizeof(struct mtk_rx_dma) * MTK_DMA_SIZE, GFP_KERNEL);
+	if (!rx_ring) {
+		seq_puts(seq, " allocate temp rx_ring fail.\n");
+		return 0;
+	}
+
+	for (i = 0; i < MTK_DMA_SIZE; i++)
+		rx_ring[i] = ring->dma[i];
+
+	seq_printf(seq, "next to read: %d\n",
+		   NEXT_DESP_IDX(ring->calc_idx, MTK_DMA_SIZE));
+	for (i = 0; i < MTK_DMA_SIZE; i++) {
+		seq_printf(seq, "%d: %08x %08x %08x %08x", i,
+			   *(int *)&rx_ring[i].rxd1, *(int *)&rx_ring[i].rxd2,
+			   *(int *)&rx_ring[i].rxd3, *(int *)&rx_ring[i].rxd4);
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+		seq_printf(seq, " %08x %08x %08x %08x",
+			   *(int *)&rx_ring[i].rxd5, *(int *)&rx_ring[i].rxd6,
+			   *(int *)&rx_ring[i].rxd7, *(int *)&rx_ring[i].rxd8);
+#endif
+		seq_printf(seq, "\n");
+	}
+
+	kfree(rx_ring);
+	return 0;
+}
+
+static int rx_ring_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, rx_ring_read, NULL);
+}
+
+static const struct file_operations rx_ring_fops = {
+	.owner = THIS_MODULE,
+	.open = rx_ring_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release
+};
+
+static inline u32 mtk_dbg_r32(u32 reg)
+{
+	void __iomem *virt_reg;
+	u32 val;
+
+	virt_reg = ioremap(reg, 32);
+	val = __raw_readl(virt_reg);
+	iounmap(virt_reg);
+
+	return val;
+}
+
+int dbg_regs_read(struct seq_file *seq, void *v)
+{
+	struct mtk_eth *eth = g_eth;
+
+	seq_puts(seq, "   <<DEBUG REG DUMP>>\n");
+
+	seq_printf(seq, "| FE_INT_STA	: %08x |\n",
+		   mtk_r32(eth, MTK_INT_STATUS));
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+		seq_printf(seq, "| FE_INT_STA2	: %08x |\n",
+			   mtk_r32(eth, MTK_INT_STATUS2));
+
+	seq_printf(seq, "| PSE_FQFC_CFG	: %08x |\n",
+		   mtk_r32(eth, MTK_PSE_FQFC_CFG));
+	seq_printf(seq, "| PSE_IQ_STA1	: %08x |\n",
+		   mtk_r32(eth, MTK_PSE_IQ_STA(0)));
+	seq_printf(seq, "| PSE_IQ_STA2	: %08x |\n",
+		   mtk_r32(eth, MTK_PSE_IQ_STA(1)));
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+		seq_printf(seq, "| PSE_IQ_STA3	: %08x |\n",
+			   mtk_r32(eth, MTK_PSE_IQ_STA(2)));
+		seq_printf(seq, "| PSE_IQ_STA4	: %08x |\n",
+			   mtk_r32(eth, MTK_PSE_IQ_STA(3)));
+		seq_printf(seq, "| PSE_IQ_STA5	: %08x |\n",
+			   mtk_r32(eth, MTK_PSE_IQ_STA(4)));
+	}
+
+	seq_printf(seq, "| PSE_OQ_STA1	: %08x |\n",
+		   mtk_r32(eth, MTK_PSE_OQ_STA(0)));
+	seq_printf(seq, "| PSE_OQ_STA2	: %08x |\n",
+		   mtk_r32(eth, MTK_PSE_OQ_STA(1)));
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+		seq_printf(seq, "| PSE_OQ_STA3	: %08x |\n",
+			   mtk_r32(eth, MTK_PSE_OQ_STA(2)));
+		seq_printf(seq, "| PSE_OQ_STA4	: %08x |\n",
+			   mtk_r32(eth, MTK_PSE_OQ_STA(3)));
+		seq_printf(seq, "| PSE_OQ_STA5	: %08x |\n",
+			   mtk_r32(eth, MTK_PSE_OQ_STA(4)));
+	}
+
+	seq_printf(seq, "| PDMA_CRX_IDX	: %08x |\n",
+		   mtk_r32(eth, MTK_PRX_CRX_IDX0));
+	seq_printf(seq, "| PDMA_DRX_IDX	: %08x |\n",
+		   mtk_r32(eth, MTK_PRX_DRX_IDX0));
+	seq_printf(seq, "| QDMA_CTX_IDX	: %08x |\n",
+		   mtk_r32(eth, MTK_QTX_CTX_PTR));
+	seq_printf(seq, "| QDMA_DTX_IDX	: %08x |\n",
+		   mtk_r32(eth, MTK_QTX_DTX_PTR));
+	seq_printf(seq, "| QDMA_FQ_CNT	: %08x |\n",
+		   mtk_r32(eth, MTK_QDMA_FQ_CNT));
+	seq_printf(seq, "| FE_PSE_FREE	: %08x |\n",
+		   mtk_r32(eth, MTK_FE_PSE_FREE));
+	seq_printf(seq, "| FE_DROP_FQ	: %08x |\n",
+		   mtk_r32(eth, MTK_FE_DROP_FQ));
+	seq_printf(seq, "| FE_DROP_FC	: %08x |\n",
+		   mtk_r32(eth, MTK_FE_DROP_FC));
+	seq_printf(seq, "| FE_DROP_PPE	: %08x |\n",
+		   mtk_r32(eth, MTK_FE_DROP_PPE));
+	seq_printf(seq, "| GDM1_IG_CTRL	: %08x |\n",
+		   mtk_r32(eth, MTK_GDMA_FWD_CFG(0)));
+	seq_printf(seq, "| GDM2_IG_CTRL	: %08x |\n",
+		   mtk_r32(eth, MTK_GDMA_FWD_CFG(1)));
+	seq_printf(seq, "| MAC_P1_MCR	: %08x |\n",
+		   mtk_r32(eth, MTK_MAC_MCR(0)));
+	seq_printf(seq, "| MAC_P2_MCR	: %08x |\n",
+		   mtk_r32(eth, MTK_MAC_MCR(1)));
+	seq_printf(seq, "| MAC_P1_FSM	: %08x |\n",
+		   mtk_r32(eth, MTK_MAC_FSM(0)));
+	seq_printf(seq, "| MAC_P2_FSM	: %08x |\n",
+		   mtk_r32(eth, MTK_MAC_FSM(1)));
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+		seq_printf(seq, "| FE_CDM1_FSM	: %08x |\n",
+			   mtk_r32(eth, MTK_FE_CDM1_FSM));
+		seq_printf(seq, "| FE_CDM2_FSM	: %08x |\n",
+			   mtk_r32(eth, MTK_FE_CDM2_FSM));
+		seq_printf(seq, "| FE_CDM3_FSM	: %08x |\n",
+			   mtk_r32(eth, MTK_FE_CDM3_FSM));
+		seq_printf(seq, "| FE_CDM4_FSM	: %08x |\n",
+			   mtk_r32(eth, MTK_FE_CDM4_FSM));
+		seq_printf(seq, "| FE_GDM1_FSM	: %08x |\n",
+			   mtk_r32(eth, MTK_FE_GDM1_FSM));
+		seq_printf(seq, "| FE_GDM2_FSM	: %08x |\n",
+			   mtk_r32(eth, MTK_FE_GDM2_FSM));
+		seq_printf(seq, "| SGMII_EFUSE	: %08x |\n",
+			   mtk_dbg_r32(MTK_SGMII_EFUSE));
+		seq_printf(seq, "| SGMII0_RX_CNT : %08x |\n",
+			   mtk_dbg_r32(MTK_SGMII_FALSE_CARRIER_CNT(0)));
+		seq_printf(seq, "| SGMII1_RX_CNT : %08x |\n",
+			   mtk_dbg_r32(MTK_SGMII_FALSE_CARRIER_CNT(1)));
+		seq_printf(seq, "| WED_RTQM_GLO	: %08x |\n",
+			   mtk_dbg_r32(MTK_WED_RTQM_GLO_CFG));
+	}
+
+	mtk_w32(eth, 0xffffffff, MTK_INT_STATUS);
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+		mtk_w32(eth, 0xffffffff, MTK_INT_STATUS2);
+
+	return 0;
+}
+
+static int dbg_regs_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dbg_regs_read, 0);
+}
+
+static const struct file_operations dbg_regs_fops = {
+	.owner = THIS_MODULE,
+	.open = dbg_regs_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release
+};
+
+void hw_lro_stats_update(u32 ring_no, struct mtk_rx_dma *rxd)
+{
+	u32 idx, agg_cnt, agg_size;
+
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+	idx = ring_no - 4;
+	agg_cnt = RX_DMA_GET_AGG_CNT_V2(rxd->rxd6);
+#else
+	idx = ring_no - 1;
+	agg_cnt = RX_DMA_GET_AGG_CNT(rxd->rxd2);
+#endif
+
+	agg_size = RX_DMA_GET_PLEN0(rxd->rxd2);
+
+	hw_lro_agg_size_cnt[idx][agg_size / 5000]++;
+	hw_lro_agg_num_cnt[idx][agg_cnt]++;
+	hw_lro_tot_flush_cnt[idx]++;
+	hw_lro_tot_agg_cnt[idx] += agg_cnt;
+}
+
+void hw_lro_flush_stats_update(u32 ring_no, struct mtk_rx_dma *rxd)
+{
+	u32 idx, flush_reason;
+
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+	idx = ring_no - 4;
+	flush_reason = RX_DMA_GET_FLUSH_RSN_V2(rxd->rxd6);
+#else
+	idx = ring_no - 1;
+	flush_reason = RX_DMA_GET_REV(rxd->rxd2);
+#endif
+
+	if ((flush_reason & 0x7) == MTK_HW_LRO_AGG_FLUSH)
+		hw_lro_agg_flush_cnt[idx]++;
+	else if ((flush_reason & 0x7) == MTK_HW_LRO_AGE_FLUSH)
+		hw_lro_age_flush_cnt[idx]++;
+	else if ((flush_reason & 0x7) == MTK_HW_LRO_NOT_IN_SEQ_FLUSH)
+		hw_lro_seq_flush_cnt[idx]++;
+	else if ((flush_reason & 0x7) == MTK_HW_LRO_TIMESTAMP_FLUSH)
+		hw_lro_timestamp_flush_cnt[idx]++;
+	else if ((flush_reason & 0x7) == MTK_HW_LRO_NON_RULE_FLUSH)
+		hw_lro_norule_flush_cnt[idx]++;
+}
+
+ssize_t hw_lro_stats_write(struct file *file, const char __user *buffer,
+			   size_t count, loff_t *data)
+{
+	memset(hw_lro_agg_num_cnt, 0, sizeof(hw_lro_agg_num_cnt));
+	memset(hw_lro_agg_size_cnt, 0, sizeof(hw_lro_agg_size_cnt));
+	memset(hw_lro_tot_agg_cnt, 0, sizeof(hw_lro_tot_agg_cnt));
+	memset(hw_lro_tot_flush_cnt, 0, sizeof(hw_lro_tot_flush_cnt));
+	memset(hw_lro_agg_flush_cnt, 0, sizeof(hw_lro_agg_flush_cnt));
+	memset(hw_lro_age_flush_cnt, 0, sizeof(hw_lro_age_flush_cnt));
+	memset(hw_lro_seq_flush_cnt, 0, sizeof(hw_lro_seq_flush_cnt));
+	memset(hw_lro_timestamp_flush_cnt, 0,
+	       sizeof(hw_lro_timestamp_flush_cnt));
+	memset(hw_lro_norule_flush_cnt, 0, sizeof(hw_lro_norule_flush_cnt));
+
+	pr_info("clear hw lro cnt table\n");
+
+	return count;
+}
+
+int hw_lro_stats_read_v1(struct seq_file *seq, void *v)
+{
+	int i;
+
+	seq_puts(seq, "HW LRO statistic dump:\n");
+
+	/* Agg number count */
+	seq_puts(seq, "Cnt:   RING1 | RING2 | RING3 | Total\n");
+	for (i = 0; i <= MTK_HW_LRO_MAX_AGG_CNT; i++) {
+		seq_printf(seq, " %d :      %d        %d        %d        %d\n",
+			   i, hw_lro_agg_num_cnt[0][i],
+			   hw_lro_agg_num_cnt[1][i], hw_lro_agg_num_cnt[2][i],
+			   hw_lro_agg_num_cnt[0][i] + hw_lro_agg_num_cnt[1][i] +
+			   hw_lro_agg_num_cnt[2][i]);
+	}
+
+	/* Total agg count */
+	seq_puts(seq, "Total agg:   RING1 | RING2 | RING3 | Total\n");
+	seq_printf(seq, "                %d      %d      %d      %d\n",
+		   hw_lro_tot_agg_cnt[0], hw_lro_tot_agg_cnt[1],
+		   hw_lro_tot_agg_cnt[2],
+		   hw_lro_tot_agg_cnt[0] + hw_lro_tot_agg_cnt[1] +
+		   hw_lro_tot_agg_cnt[2]);
+
+	/* Total flush count */
+	seq_puts(seq, "Total flush:   RING1 | RING2 | RING3 | Total\n");
+	seq_printf(seq, "                %d      %d      %d      %d\n",
+		   hw_lro_tot_flush_cnt[0], hw_lro_tot_flush_cnt[1],
+		   hw_lro_tot_flush_cnt[2],
+		   hw_lro_tot_flush_cnt[0] + hw_lro_tot_flush_cnt[1] +
+		   hw_lro_tot_flush_cnt[2]);
+
+	/* Avg agg count */
+	seq_puts(seq, "Avg agg:   RING1 | RING2 | RING3 | Total\n");
+	seq_printf(seq, "                %d      %d      %d      %d\n",
+		   (hw_lro_tot_flush_cnt[0]) ?
+		    hw_lro_tot_agg_cnt[0] / hw_lro_tot_flush_cnt[0] : 0,
+		   (hw_lro_tot_flush_cnt[1]) ?
+		    hw_lro_tot_agg_cnt[1] / hw_lro_tot_flush_cnt[1] : 0,
+		   (hw_lro_tot_flush_cnt[2]) ?
+		    hw_lro_tot_agg_cnt[2] / hw_lro_tot_flush_cnt[2] : 0,
+		   (hw_lro_tot_flush_cnt[0] + hw_lro_tot_flush_cnt[1] +
+		    hw_lro_tot_flush_cnt[2]) ?
+		    ((hw_lro_tot_agg_cnt[0] + hw_lro_tot_agg_cnt[1] +
+		      hw_lro_tot_agg_cnt[2]) / (hw_lro_tot_flush_cnt[0] +
+		      hw_lro_tot_flush_cnt[1] + hw_lro_tot_flush_cnt[2])) : 0);
+
+	/*  Statistics of aggregation size counts */
+	seq_puts(seq, "HW LRO flush pkt len:\n");
+	seq_puts(seq, " Length  | RING1  | RING2  | RING3  | Total\n");
+	for (i = 0; i < 15; i++) {
+		seq_printf(seq, "%d~%d: %d      %d      %d      %d\n", i * 5000,
+			   (i + 1) * 5000, hw_lro_agg_size_cnt[0][i],
+			   hw_lro_agg_size_cnt[1][i], hw_lro_agg_size_cnt[2][i],
+			   hw_lro_agg_size_cnt[0][i] +
+			   hw_lro_agg_size_cnt[1][i] +
+			   hw_lro_agg_size_cnt[2][i]);
+	}
+
+	seq_puts(seq, "Flush reason:   RING1 | RING2 | RING3 | Total\n");
+	seq_printf(seq, "AGG timeout:      %d      %d      %d      %d\n",
+		   hw_lro_agg_flush_cnt[0], hw_lro_agg_flush_cnt[1],
+		   hw_lro_agg_flush_cnt[2],
+		   (hw_lro_agg_flush_cnt[0] + hw_lro_agg_flush_cnt[1] +
+		    hw_lro_agg_flush_cnt[2]));
+
+	seq_printf(seq, "AGE timeout:      %d      %d      %d      %d\n",
+		   hw_lro_age_flush_cnt[0], hw_lro_age_flush_cnt[1],
+		   hw_lro_age_flush_cnt[2],
+		   (hw_lro_age_flush_cnt[0] + hw_lro_age_flush_cnt[1] +
+		    hw_lro_age_flush_cnt[2]));
+
+	seq_printf(seq, "Not in-sequence:  %d      %d      %d      %d\n",
+		   hw_lro_seq_flush_cnt[0], hw_lro_seq_flush_cnt[1],
+		   hw_lro_seq_flush_cnt[2],
+		   (hw_lro_seq_flush_cnt[0] + hw_lro_seq_flush_cnt[1] +
+		    hw_lro_seq_flush_cnt[2]));
+
+	seq_printf(seq, "Timestamp:        %d      %d      %d      %d\n",
+		   hw_lro_timestamp_flush_cnt[0],
+		   hw_lro_timestamp_flush_cnt[1],
+		   hw_lro_timestamp_flush_cnt[2],
+		   (hw_lro_timestamp_flush_cnt[0] +
+		    hw_lro_timestamp_flush_cnt[1] +
+		    hw_lro_timestamp_flush_cnt[2]));
+
+	seq_printf(seq, "No LRO rule:      %d      %d      %d      %d\n",
+		   hw_lro_norule_flush_cnt[0],
+		   hw_lro_norule_flush_cnt[1],
+		   hw_lro_norule_flush_cnt[2],
+		   (hw_lro_norule_flush_cnt[0] +
+		    hw_lro_norule_flush_cnt[1] +
+		    hw_lro_norule_flush_cnt[2]));
+
+	return 0;
+}
+
+int hw_lro_stats_read_v2(struct seq_file *seq, void *v)
+{
+	int i;
+
+	seq_puts(seq, "HW LRO statistic dump:\n");
+
+	/* Agg number count */
+	seq_puts(seq, "Cnt:   RING4 | RING5 | RING6 | RING7 Total\n");
+	for (i = 0; i <= MTK_HW_LRO_MAX_AGG_CNT; i++) {
+		seq_printf(seq,
+			   " %d :      %d        %d        %d        %d        %d\n",
+			   i, hw_lro_agg_num_cnt[0][i], hw_lro_agg_num_cnt[1][i],
+			   hw_lro_agg_num_cnt[2][i], hw_lro_agg_num_cnt[3][i],
+			   hw_lro_agg_num_cnt[0][i] + hw_lro_agg_num_cnt[1][i] +
+			   hw_lro_agg_num_cnt[2][i] + hw_lro_agg_num_cnt[3][i]);
+	}
+
+	/* Total agg count */
+	seq_puts(seq, "Total agg:   RING4 | RING5 | RING6 | RING7 Total\n");
+	seq_printf(seq, "                %d      %d      %d      %d      %d\n",
+		   hw_lro_tot_agg_cnt[0], hw_lro_tot_agg_cnt[1],
+		   hw_lro_tot_agg_cnt[2], hw_lro_tot_agg_cnt[3],
+		   hw_lro_tot_agg_cnt[0] + hw_lro_tot_agg_cnt[1] +
+		   hw_lro_tot_agg_cnt[2] + hw_lro_tot_agg_cnt[3]);
+
+	/* Total flush count */
+	seq_puts(seq, "Total flush:   RING4 | RING5 | RING6 | RING7 Total\n");
+	seq_printf(seq, "                %d      %d      %d      %d      %d\n",
+		   hw_lro_tot_flush_cnt[0], hw_lro_tot_flush_cnt[1],
+		   hw_lro_tot_flush_cnt[2], hw_lro_tot_flush_cnt[3],
+		   hw_lro_tot_flush_cnt[0] + hw_lro_tot_flush_cnt[1] +
+		   hw_lro_tot_flush_cnt[2] + hw_lro_tot_flush_cnt[3]);
+
+	/* Avg agg count */
+	seq_puts(seq, "Avg agg:   RING4 | RING5 | RING6 | RING7 Total\n");
+	seq_printf(seq, "                %d      %d      %d      %d      %d\n",
+		   (hw_lro_tot_flush_cnt[0]) ?
+		    hw_lro_tot_agg_cnt[0] / hw_lro_tot_flush_cnt[0] : 0,
+		   (hw_lro_tot_flush_cnt[1]) ?
+		    hw_lro_tot_agg_cnt[1] / hw_lro_tot_flush_cnt[1] : 0,
+		   (hw_lro_tot_flush_cnt[2]) ?
+		    hw_lro_tot_agg_cnt[2] / hw_lro_tot_flush_cnt[2] : 0,
+		   (hw_lro_tot_flush_cnt[3]) ?
+                    hw_lro_tot_agg_cnt[3] / hw_lro_tot_flush_cnt[3] : 0,
+		   (hw_lro_tot_flush_cnt[0] + hw_lro_tot_flush_cnt[1] +
+		    hw_lro_tot_flush_cnt[2] + hw_lro_tot_flush_cnt[3]) ?
+		    ((hw_lro_tot_agg_cnt[0] + hw_lro_tot_agg_cnt[1] +
+		      hw_lro_tot_agg_cnt[2] + hw_lro_tot_agg_cnt[3]) /
+		     (hw_lro_tot_flush_cnt[0] + hw_lro_tot_flush_cnt[1] +
+		      hw_lro_tot_flush_cnt[2] + hw_lro_tot_flush_cnt[3])) : 0);
+
+	/*  Statistics of aggregation size counts */
+	seq_puts(seq, "HW LRO flush pkt len:\n");
+	seq_puts(seq, " Length  | RING4  | RING5  | RING6  | RING7 Total\n");
+	for (i = 0; i < 15; i++) {
+		seq_printf(seq, "%d~%d: %d      %d      %d      %d      %d\n",
+			   i * 5000, (i + 1) * 5000,
+			   hw_lro_agg_size_cnt[0][i], hw_lro_agg_size_cnt[1][i],
+			   hw_lro_agg_size_cnt[2][i], hw_lro_agg_size_cnt[3][i],
+			   hw_lro_agg_size_cnt[0][i] +
+			   hw_lro_agg_size_cnt[1][i] +
+			   hw_lro_agg_size_cnt[2][i] +
+			   hw_lro_agg_size_cnt[3][i]);
+	}
+
+	seq_puts(seq, "Flush reason:   RING4 | RING5 | RING6 | RING7 Total\n");
+	seq_printf(seq, "AGG timeout:      %d      %d      %d      %d      %d\n",
+		   hw_lro_agg_flush_cnt[0], hw_lro_agg_flush_cnt[1],
+		   hw_lro_agg_flush_cnt[2], hw_lro_agg_flush_cnt[3],
+		   (hw_lro_agg_flush_cnt[0] + hw_lro_agg_flush_cnt[1] +
+		    hw_lro_agg_flush_cnt[2] + hw_lro_agg_flush_cnt[3]));
+
+	seq_printf(seq, "AGE timeout:      %d      %d      %d      %d      %d\n",
+		   hw_lro_age_flush_cnt[0], hw_lro_age_flush_cnt[1],
+		   hw_lro_age_flush_cnt[2], hw_lro_age_flush_cnt[3],
+		   (hw_lro_age_flush_cnt[0] + hw_lro_age_flush_cnt[1] +
+		    hw_lro_age_flush_cnt[2] + hw_lro_age_flush_cnt[3]));
+
+	seq_printf(seq, "Not in-sequence:  %d      %d      %d      %d      %d\n",
+		   hw_lro_seq_flush_cnt[0], hw_lro_seq_flush_cnt[1],
+		   hw_lro_seq_flush_cnt[2], hw_lro_seq_flush_cnt[3],
+		   (hw_lro_seq_flush_cnt[0] + hw_lro_seq_flush_cnt[1] +
+		    hw_lro_seq_flush_cnt[2] + hw_lro_seq_flush_cnt[3]));
+
+	seq_printf(seq, "Timestamp:        %d      %d      %d      %d      %d\n",
+		   hw_lro_timestamp_flush_cnt[0],
+		   hw_lro_timestamp_flush_cnt[1],
+		   hw_lro_timestamp_flush_cnt[2],
+		   hw_lro_timestamp_flush_cnt[3],
+		   (hw_lro_timestamp_flush_cnt[0] +
+		    hw_lro_timestamp_flush_cnt[1] +
+		    hw_lro_timestamp_flush_cnt[2] +
+		    hw_lro_timestamp_flush_cnt[3]));
+
+	seq_printf(seq, "No LRO rule:      %d      %d      %d      %d      %d\n",
+		   hw_lro_norule_flush_cnt[0],
+		   hw_lro_norule_flush_cnt[1],
+		   hw_lro_norule_flush_cnt[2],
+		   hw_lro_norule_flush_cnt[3],
+		   (hw_lro_norule_flush_cnt[0] +
+		    hw_lro_norule_flush_cnt[1] +
+		    hw_lro_norule_flush_cnt[2] +
+		    hw_lro_norule_flush_cnt[3]));
+
+	return 0;
+}
+
+int hw_lro_stats_read_wrapper(struct seq_file *seq, void *v)
+{
+	struct mtk_eth *eth = g_eth;
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+		hw_lro_stats_read_v2(seq, v);
+	else
+		hw_lro_stats_read_v1(seq, v);
+
+	return 0;
+}
+
+static int hw_lro_stats_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, hw_lro_stats_read_wrapper, NULL);
+}
+
+static const struct file_operations hw_lro_stats_fops = {
+	.owner = THIS_MODULE,
+	.open = hw_lro_stats_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.write = hw_lro_stats_write,
+	.release = single_release
+};
+
+int hwlro_agg_cnt_ctrl(int cnt)
+{
+	int i;
+
+	for (i = 1; i <= MTK_HW_LRO_RING_NUM; i++)
+		SET_PDMA_RXRING_MAX_AGG_CNT(g_eth, i, cnt);
+
+	return 0;
+}
+
+int hwlro_agg_time_ctrl(int time)
+{
+	int i;
+
+	for (i = 1; i <= MTK_HW_LRO_RING_NUM; i++)
+		SET_PDMA_RXRING_AGG_TIME(g_eth, i, time);
+
+	return 0;
+}
+
+int hwlro_age_time_ctrl(int time)
+{
+	int i;
+
+	for (i = 1; i <= MTK_HW_LRO_RING_NUM; i++)
+		SET_PDMA_RXRING_AGE_TIME(g_eth, i, time);
+
+	return 0;
+}
+
+int hwlro_threshold_ctrl(int bandwidth)
+{
+	SET_PDMA_LRO_BW_THRESHOLD(g_eth, bandwidth);
+
+	return 0;
+}
+
+int hwlro_ring_enable_ctrl(int enable)
+{
+	int i;
+
+	pr_info("[%s] %s HW LRO rings\n", __func__, (enable) ? "Enable" : "Disable");
+
+	for (i = 1; i <= MTK_HW_LRO_RING_NUM; i++)
+		SET_PDMA_RXRING_VALID(g_eth, i, enable);
+
+	return 0;
+}
+
+int hwlro_stats_enable_ctrl(int enable)
+{
+	pr_info("[%s] %s HW LRO statistics\n", __func__, (enable) ? "Enable" : "Disable");
+	mtk_hwlro_stats_ebl = enable;
+
+	return 0;
+}
+
+static const mtk_lro_dbg_func lro_dbg_func[] = {
+	[0] = hwlro_agg_cnt_ctrl,
+	[1] = hwlro_agg_time_ctrl,
+	[2] = hwlro_age_time_ctrl,
+	[3] = hwlro_threshold_ctrl,
+	[4] = hwlro_ring_enable_ctrl,
+	[5] = hwlro_stats_enable_ctrl,
+};
+
+ssize_t hw_lro_auto_tlb_write(struct file *file, const char __user *buffer,
+			      size_t count, loff_t *data)
+{
+	char buf[32];
+	char *p_buf;
+	char *p_token = NULL;
+	char *p_delimiter = " \t";
+	long x = 0, y = 0;
+	u32 len = count;
+	int ret;
+
+	if (len >= sizeof(buf)) {
+		pr_info("Input handling fail!\n");
+		return -1;
+	}
+
+	if (copy_from_user(buf, buffer, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+
+	p_buf = buf;
+	p_token = strsep(&p_buf, p_delimiter);
+	if (!p_token)
+		x = 0;
+	else
+		ret = kstrtol(p_token, 10, &x);
+
+	p_token = strsep(&p_buf, "\t\n ");
+	if (p_token)
+		ret = kstrtol(p_token, 10, &y);
+
+	if (lro_dbg_func[x] && (ARRAY_SIZE(lro_dbg_func) > x))
+		(*lro_dbg_func[x]) (y);
+
+	return count;
+}
+
+void hw_lro_auto_tlb_dump_v1(struct seq_file *seq, u32 index)
+{
+	int i;
+	struct mtk_lro_alt_v1 alt;
+	__be32 addr;
+	u32 tlb_info[9];
+	u32 dw_len, cnt, priority;
+	u32 entry;
+
+	if (index > 4)
+		index = index - 1;
+	entry = (index * 9) + 1;
+
+	/* read valid entries of the auto-learn table */
+	mtk_w32(g_eth, entry, MTK_FE_ALT_CF8);
+
+	for (i = 0; i < 9; i++)
+		tlb_info[i] = mtk_r32(g_eth, MTK_FE_ALT_SEQ_CFC);
+
+	memcpy(&alt, tlb_info, sizeof(struct mtk_lro_alt_v1));
+
+	dw_len = alt.alt_info7.dw_len;
+	cnt = alt.alt_info6.cnt;
+
+	if (mtk_r32(g_eth, MTK_PDMA_LRO_CTRL_DW0) & MTK_LRO_ALT_PKT_CNT_MODE)
+		priority = cnt;		/* packet count */
+	else
+		priority = dw_len;	/* byte count */
+
+	/* dump valid entries of the auto-learn table */
+	if (index >= 4)
+		seq_printf(seq, "\n===== TABLE Entry: %d (Act) =====\n", index);
+	else
+		seq_printf(seq, "\n===== TABLE Entry: %d (LRU) =====\n", index);
+
+	if (alt.alt_info8.ipv4) {
+		addr = htonl(alt.alt_info1.sip0);
+		seq_printf(seq, "SIP = %pI4 (IPv4)\n", &addr);
+	} else {
+		seq_printf(seq, "SIP = %08X:%08X:%08X:%08X (IPv6)\n",
+			   alt.alt_info4.sip3, alt.alt_info3.sip2,
+			   alt.alt_info2.sip1, alt.alt_info1.sip0);
+	}
+
+	seq_printf(seq, "DIP_ID = %d\n", alt.alt_info8.dip_id);
+	seq_printf(seq, "TCP SPORT = %d | TCP DPORT = %d\n",
+		   alt.alt_info0.stp, alt.alt_info0.dtp);
+	seq_printf(seq, "VLAN_VID_VLD = %d\n", alt.alt_info6.vlan_vid_vld);
+	seq_printf(seq, "VLAN1 = %d | VLAN2 = %d | VLAN3 = %d | VLAN4 =%d\n",
+		   (alt.alt_info5.vlan_vid0 & 0xfff),
+		   ((alt.alt_info5.vlan_vid0 >> 12) & 0xfff),
+		   ((alt.alt_info6.vlan_vid1 << 8) |
+		   ((alt.alt_info5.vlan_vid0 >> 24) & 0xfff)),
+		   ((alt.alt_info6.vlan_vid1 >> 4) & 0xfff));
+	seq_printf(seq, "TPUT = %d | FREQ = %d\n", dw_len, cnt);
+	seq_printf(seq, "PRIORITY = %d\n", priority);
+}
+
+void hw_lro_auto_tlb_dump_v2(struct seq_file *seq, u32 index)
+{
+	int i;
+	struct mtk_lro_alt_v2 alt;
+	u32 score = 0, ipv4 = 0;
+	u32 ipv6[4] = { 0 };
+	u32 tlb_info[12];
+
+	/* read valid entries of the auto-learn table */
+	mtk_w32(g_eth, index << MTK_LRO_ALT_INDEX_OFFSET, MTK_LRO_ALT_DBG);
+
+	for (i = 0; i < 11; i++)
+		tlb_info[i] = mtk_r32(g_eth, MTK_LRO_ALT_DBG_DATA);
+
+	memcpy(&alt, tlb_info, sizeof(struct mtk_lro_alt_v2));
+
+	if (mtk_r32(g_eth, MTK_PDMA_LRO_CTRL_DW0) & MTK_LRO_ALT_PKT_CNT_MODE)
+		score = 1;	/* packet count */
+	else
+		score = 0;	/* byte count */
+
+	/* dump valid entries of the auto-learn table */
+	if (alt.alt_info0.valid) {
+		if (index < 5)
+			seq_printf(seq,
+				   "\n===== TABLE Entry: %d (onging) =====\n",
+				   index);
+		else
+			seq_printf(seq,
+				   "\n===== TABLE Entry: %d (candidate) =====\n",
+				   index);
+
+		if (alt.alt_info1.v4_valid) {
+			ipv4 = (alt.alt_info4.sip0_h << 23) |
+				alt.alt_info5.sip0_l;
+			seq_printf(seq, "SIP = 0x%x: (IPv4)\n", ipv4);
+
+			ipv4 = (alt.alt_info8.dip0_h << 23) |
+				alt.alt_info9.dip0_l;
+			seq_printf(seq, "DIP = 0x%x: (IPv4)\n", ipv4);
+		} else if (alt.alt_info1.v6_valid) {
+			ipv6[3] = (alt.alt_info1.sip3_h << 23) |
+				   (alt.alt_info2.sip3_l << 9);
+			ipv6[2] = (alt.alt_info2.sip2_h << 23) |
+				   (alt.alt_info3.sip2_l << 9);
+			ipv6[1] = (alt.alt_info3.sip1_h << 23) |
+				   (alt.alt_info4.sip1_l << 9);
+			ipv6[0] = (alt.alt_info4.sip0_h << 23) |
+				   (alt.alt_info5.sip0_l << 9);
+			seq_printf(seq, "SIP = 0x%x:0x%x:0x%x:0x%x (IPv6)\n",
+				   ipv6[3], ipv6[2], ipv6[1], ipv6[0]);
+
+			ipv6[3] = (alt.alt_info5.dip3_h << 23) |
+				   (alt.alt_info6.dip3_l << 9);
+			ipv6[2] = (alt.alt_info6.dip2_h << 23) |
+				   (alt.alt_info7.dip2_l << 9);
+			ipv6[1] = (alt.alt_info7.dip1_h << 23) |
+				   (alt.alt_info8.dip1_l << 9);
+			ipv6[0] = (alt.alt_info8.dip0_h << 23) |
+				   (alt.alt_info9.dip0_l << 9);
+			seq_printf(seq, "DIP = 0x%x:0x%x:0x%x:0x%x (IPv6)\n",
+				   ipv6[3], ipv6[2], ipv6[1], ipv6[0]);
+		}
+
+		seq_printf(seq, "TCP SPORT = %d | TCP DPORT = %d\n",
+			   (alt.alt_info9.sp_h << 7) | (alt.alt_info10.sp_l),
+			   alt.alt_info10.dp);
+	}
+}
+
+int hw_lro_auto_tlb_read(struct seq_file *seq, void *v)
+{
+	int i;
+	u32 reg_val;
+	u32 reg_op1, reg_op2, reg_op3, reg_op4;
+	u32 agg_cnt, agg_time, age_time;
+
+	seq_puts(seq, "Usage of /proc/mtketh/hw_lro_auto_tlb:\n");
+	seq_puts(seq, "echo [function] [setting] > /proc/mtketh/hw_lro_auto_tlb\n");
+	seq_puts(seq, "Functions:\n");
+	seq_puts(seq, "[0] = hwlro_agg_cnt_ctrl\n");
+	seq_puts(seq, "[1] = hwlro_agg_time_ctrl\n");
+	seq_puts(seq, "[2] = hwlro_age_time_ctrl\n");
+	seq_puts(seq, "[3] = hwlro_threshold_ctrl\n");
+	seq_puts(seq, "[4] = hwlro_ring_enable_ctrl\n");
+	seq_puts(seq, "[5] = hwlro_stats_enable_ctrl\n\n");
+
+	if (MTK_HAS_CAPS(g_eth->soc->caps, MTK_NETSYS_V2)) {
+		for (i = 1; i <= 8; i++)
+			hw_lro_auto_tlb_dump_v2(seq, i);
+	} else {
+		/* Read valid entries of the auto-learn table */
+		mtk_w32(g_eth, 0, MTK_FE_ALT_CF8);
+		reg_val = mtk_r32(g_eth, MTK_FE_ALT_SEQ_CFC);
+
+		seq_printf(seq,
+			   "HW LRO Auto-learn Table: (MTK_FE_ALT_SEQ_CFC=0x%x)\n",
+			   reg_val);
+
+		for (i = 7; i >= 0; i--) {
+			if (reg_val & (1 << i))
+				hw_lro_auto_tlb_dump_v1(seq, i);
+		}
+	}
+
+	/* Read the agg_time/age_time/agg_cnt of LRO rings */
+	seq_puts(seq, "\nHW LRO Ring Settings\n");
+
+	for (i = 1; i <= MTK_HW_LRO_RING_NUM; i++) {
+		reg_op1 = mtk_r32(g_eth, MTK_LRO_CTRL_DW1_CFG(i));
+		reg_op2 = mtk_r32(g_eth, MTK_LRO_CTRL_DW2_CFG(i));
+		reg_op3 = mtk_r32(g_eth, MTK_LRO_CTRL_DW3_CFG(i));
+		reg_op4 = mtk_r32(g_eth, MTK_PDMA_LRO_CTRL_DW2);
+
+		agg_cnt =
+		    ((reg_op3 & 0x3) << 6) |
+		    ((reg_op2 >> MTK_LRO_RING_AGG_CNT_L_OFFSET) & 0x3f);
+		agg_time = (reg_op2 >> MTK_LRO_RING_AGG_TIME_OFFSET) & 0xffff;
+		age_time =
+		    ((reg_op2 & 0x3f) << 10) |
+		    ((reg_op1 >> MTK_LRO_RING_AGE_TIME_L_OFFSET) & 0x3ff);
+		seq_printf(seq,
+			   "Ring[%d]: MAX_AGG_CNT=%d, AGG_TIME=%d, AGE_TIME=%d, Threshold=%d\n",
+			   (MTK_HAS_CAPS(g_eth->soc->caps, MTK_NETSYS_V2))? i+3 : i,
+			   agg_cnt, agg_time, age_time, reg_op4);
+	}
+
+	seq_puts(seq, "\n");
+
+	return 0;
+}
+
+static int hw_lro_auto_tlb_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, hw_lro_auto_tlb_read, NULL);
+}
+
+static const struct file_operations hw_lro_auto_tlb_fops = {
+	.owner = THIS_MODULE,
+	.open = hw_lro_auto_tlb_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.write = hw_lro_auto_tlb_write,
+	.release = single_release
+};
+
+struct proc_dir_entry *proc_reg_dir;
+static struct proc_dir_entry *proc_esw_cnt, *proc_dbg_regs;
+
+int debug_proc_init(struct mtk_eth *eth)
+{
+	g_eth = eth;
+
+	if (!proc_reg_dir)
+		proc_reg_dir = proc_mkdir(PROCREG_DIR, NULL);
+
+	proc_tx_ring =
+	    proc_create(PROCREG_TXRING, 0, proc_reg_dir, &tx_ring_fops);
+	if (!proc_tx_ring)
+		pr_notice("!! FAIL to create %s PROC !!\n", PROCREG_TXRING);
+
+	proc_rx_ring =
+	    proc_create(PROCREG_RXRING, 0, proc_reg_dir, &rx_ring_fops);
+	if (!proc_rx_ring)
+		pr_notice("!! FAIL to create %s PROC !!\n", PROCREG_RXRING);
+
+	proc_esw_cnt =
+	    proc_create(PROCREG_ESW_CNT, 0, proc_reg_dir, &switch_count_fops);
+	if (!proc_esw_cnt)
+		pr_notice("!! FAIL to create %s PROC !!\n", PROCREG_ESW_CNT);
+
+	proc_dbg_regs =
+	    proc_create(PROCREG_DBG_REGS, 0, proc_reg_dir, &dbg_regs_fops);
+	if (!proc_dbg_regs)
+		pr_notice("!! FAIL to create %s PROC !!\n", PROCREG_DBG_REGS);
+
+	if (g_eth->hwlro) {
+		proc_hw_lro_stats =
+			proc_create(PROCREG_HW_LRO_STATS, 0, proc_reg_dir,
+				    &hw_lro_stats_fops);
+		if (!proc_hw_lro_stats)
+			pr_info("!! FAIL to create %s PROC !!\n", PROCREG_HW_LRO_STATS);
+
+		proc_hw_lro_auto_tlb =
+			proc_create(PROCREG_HW_LRO_AUTO_TLB, 0, proc_reg_dir,
+				    &hw_lro_auto_tlb_fops);
+		if (!proc_hw_lro_auto_tlb)
+			pr_info("!! FAIL to create %s PROC !!\n",
+				PROCREG_HW_LRO_AUTO_TLB);
+	}
+
+	return 0;
+}
+
+void debug_proc_exit(void)
+{
+	if (proc_tx_ring)
+		remove_proc_entry(PROCREG_TXRING, proc_reg_dir);
+	if (proc_rx_ring)
+		remove_proc_entry(PROCREG_RXRING, proc_reg_dir);
+
+	if (proc_esw_cnt)
+		remove_proc_entry(PROCREG_ESW_CNT, proc_reg_dir);
+
+	if (proc_reg_dir)
+		remove_proc_entry(PROCREG_DIR, 0);
+
+	if (proc_dbg_regs)
+		remove_proc_entry(PROCREG_DBG_REGS, proc_reg_dir);
+
+	if (g_eth->hwlro) {
+		if (proc_hw_lro_stats)
+			remove_proc_entry(PROCREG_HW_LRO_STATS, proc_reg_dir);
+
+		if (proc_hw_lro_auto_tlb)
+			remove_proc_entry(PROCREG_HW_LRO_AUTO_TLB, proc_reg_dir);
+	}
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.h
new file mode 100755
index 0000000..ea147b7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_dbg.h
@@ -0,0 +1,284 @@
+/*
+ *   Copyright (C) 2018 MediaTek Inc.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; version 2 of the License
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
+ *   Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
+ *   Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
+ */
+
+#ifndef MTK_ETH_DBG_H
+#define MTK_ETH_DBG_H
+
+/* Debug Purpose Register */
+#define MTK_PSE_FQFC_CFG		0x100
+#define MTK_FE_CDM1_FSM			0x220
+#define MTK_FE_CDM2_FSM			0x224
+#define MTK_FE_CDM3_FSM			0x238
+#define MTK_FE_CDM4_FSM			0x298
+#define MTK_FE_GDM1_FSM			0x228
+#define MTK_FE_GDM2_FSM			0x22C
+#define MTK_FE_PSE_FREE			0x240
+#define MTK_FE_DROP_FQ			0x244
+#define MTK_FE_DROP_FC			0x248
+#define MTK_FE_DROP_PPE			0x24C
+#define MTK_MAC_FSM(x)			(0x1010C + ((x) * 0x100))
+#define MTK_SGMII_FALSE_CARRIER_CNT(x)	(0x10060028 + ((x) * 0x10000))
+#define MTK_SGMII_EFUSE			0x11D008C8
+#define MTK_WED_RTQM_GLO_CFG		0x15010B00
+
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#define MTK_PSE_IQ_STA(x)		(0x180 + (x) * 0x4)
+#define MTK_PSE_OQ_STA(x)		(0x1A0 + (x) * 0x4)
+#else
+#define MTK_PSE_IQ_STA(x)		(0x110 + (x) * 0x4)
+#define MTK_PSE_OQ_STA(x)		(0x118 + (x) * 0x4)
+#endif
+
+#define MTKETH_MII_READ                  0x89F3
+#define MTKETH_MII_WRITE                 0x89F4
+#define MTKETH_ESW_REG_READ              0x89F1
+#define MTKETH_ESW_REG_WRITE             0x89F2
+#define MTKETH_MII_READ_CL45             0x89FC
+#define MTKETH_MII_WRITE_CL45            0x89FD
+#define REG_ESW_MAX                     0xFC
+
+#define PROCREG_ESW_CNT			"esw_cnt"
+#define PROCREG_TXRING			"tx_ring"
+#define PROCREG_RXRING			"rx_ring"
+#define PROCREG_DIR			"mtketh"
+#define PROCREG_DBG_REGS		"dbg_regs"
+#define PROCREG_HW_LRO_STATS		"hw_lro_stats"
+#define PROCREG_HW_LRO_AUTO_TLB		"hw_lro_auto_tlb"
+
+/* HW LRO flush reason */
+#define MTK_HW_LRO_AGG_FLUSH		(1)
+#define MTK_HW_LRO_AGE_FLUSH		(2)
+#define MTK_HW_LRO_NOT_IN_SEQ_FLUSH	(3)
+#define MTK_HW_LRO_TIMESTAMP_FLUSH	(4)
+#define MTK_HW_LRO_NON_RULE_FLUSH	(5)
+
+#define SET_PDMA_RXRING_MAX_AGG_CNT(eth, x, y)				\
+{									\
+	u32 reg_val1 = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(x));		\
+	u32 reg_val2 = mtk_r32(eth, MTK_LRO_CTRL_DW3_CFG(x));		\
+	reg_val1 &= ~MTK_LRO_RING_AGG_CNT_L_MASK;			\
+	reg_val2 &= ~MTK_LRO_RING_AGG_CNT_H_MASK;			\
+	reg_val1 |= ((y) & 0x3f) << MTK_LRO_RING_AGG_CNT_L_OFFSET;	\
+	reg_val2 |= (((y) >> 6) & 0x03) <<				\
+		     MTK_LRO_RING_AGG_CNT_H_OFFSET;			\
+	mtk_w32(eth, reg_val1, MTK_LRO_CTRL_DW2_CFG(x));		\
+	mtk_w32(eth, reg_val2, MTK_LRO_CTRL_DW3_CFG(x));		\
+}
+
+#define SET_PDMA_RXRING_AGG_TIME(eth, x, y)				\
+{									\
+	u32 reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(x));		\
+	reg_val &= ~MTK_LRO_RING_AGG_TIME_MASK;				\
+	reg_val |= ((y) & 0xffff) << MTK_LRO_RING_AGG_TIME_OFFSET;	\
+	mtk_w32(eth, reg_val, MTK_LRO_CTRL_DW2_CFG(x));			\
+}
+
+#define SET_PDMA_RXRING_AGE_TIME(eth, x, y)				\
+{									\
+	u32 reg_val1 = mtk_r32(eth, MTK_LRO_CTRL_DW1_CFG(x));		\
+	u32 reg_val2 = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(x));		\
+	reg_val1 &= ~MTK_LRO_RING_AGE_TIME_L_MASK;			\
+	reg_val2 &= ~MTK_LRO_RING_AGE_TIME_H_MASK;			\
+	reg_val1 |= ((y) & 0x3ff) << MTK_LRO_RING_AGE_TIME_L_OFFSET;	\
+	reg_val2 |= (((y) >> 10) & 0x03f) <<				\
+		     MTK_LRO_RING_AGE_TIME_H_OFFSET;			\
+	mtk_w32(eth, reg_val1, MTK_LRO_CTRL_DW1_CFG(x));		\
+	mtk_w32(eth, reg_val2, MTK_LRO_CTRL_DW2_CFG(x));		\
+}
+
+#define SET_PDMA_LRO_BW_THRESHOLD(eth, x)				\
+{									\
+	u32 reg_val = mtk_r32(eth, MTK_PDMA_LRO_CTRL_DW2);		\
+	reg_val = (x);							\
+	mtk_w32(eth, reg_val, MTK_PDMA_LRO_CTRL_DW2);			\
+}
+
+#define SET_PDMA_RXRING_VALID(eth, x, y)				\
+{									\
+	u32 reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(x));		\
+	reg_val &= ~(0x1 << MTK_RX_PORT_VALID_OFFSET);			\
+	reg_val |= ((y) & 0x1) << MTK_RX_PORT_VALID_OFFSET;		\
+	mtk_w32(eth, reg_val, MTK_LRO_CTRL_DW2_CFG(x));			\
+}
+
+struct mtk_lro_alt_v1_info0 {
+	u32 dtp : 16;
+	u32 stp : 16;
+};
+
+struct mtk_lro_alt_v1_info1 {
+	u32 sip0 : 32;
+};
+
+struct mtk_lro_alt_v1_info2 {
+	u32 sip1 : 32;
+};
+
+struct mtk_lro_alt_v1_info3 {
+	u32 sip2 : 32;
+};
+
+struct mtk_lro_alt_v1_info4 {
+	u32 sip3 : 32;
+};
+
+struct mtk_lro_alt_v1_info5 {
+	u32 vlan_vid0 : 32;
+};
+
+struct mtk_lro_alt_v1_info6 {
+	u32 vlan_vid1 : 16;
+	u32 vlan_vid_vld : 4;
+	u32 cnt : 12;
+};
+
+struct mtk_lro_alt_v1_info7 {
+	u32 dw_len : 32;
+};
+
+struct mtk_lro_alt_v1_info8 {
+	u32 dip_id : 2;
+	u32 ipv6 : 1;
+	u32 ipv4 : 1;
+	u32 resv : 27;
+	u32 valid : 1;
+};
+
+struct mtk_lro_alt_v1 {
+	struct mtk_lro_alt_v1_info0 alt_info0;
+	struct mtk_lro_alt_v1_info1 alt_info1;
+	struct mtk_lro_alt_v1_info2 alt_info2;
+	struct mtk_lro_alt_v1_info3 alt_info3;
+	struct mtk_lro_alt_v1_info4 alt_info4;
+	struct mtk_lro_alt_v1_info5 alt_info5;
+	struct mtk_lro_alt_v1_info6 alt_info6;
+	struct mtk_lro_alt_v1_info7 alt_info7;
+	struct mtk_lro_alt_v1_info8 alt_info8;
+};
+
+struct mtk_lro_alt_v2_info0 {
+	u32 v2_id_h:3;
+	u32 v1_id:12;
+	u32 v0_id:12;
+	u32 v3_valid:1;
+	u32 v2_valid:1;
+	u32 v1_valid:1;
+	u32 v0_valid:1;
+	u32 valid:1;
+};
+
+struct mtk_lro_alt_v2_info1 {
+	u32 sip3_h:9;
+	u32 v6_valid:1;
+	u32 v4_valid:1;
+	u32 v3_id:12;
+	u32 v2_id_l:9;
+};
+
+struct mtk_lro_alt_v2_info2 {
+	u32 sip2_h:9;
+	u32 sip3_l:23;
+};
+struct mtk_lro_alt_v2_info3 {
+	u32 sip1_h:9;
+	u32 sip2_l:23;
+};
+struct mtk_lro_alt_v2_info4 {
+	u32 sip0_h:9;
+	u32 sip1_l:23;
+};
+struct mtk_lro_alt_v2_info5 {
+	u32 dip3_h:9;
+	u32 sip0_l:23;
+};
+struct mtk_lro_alt_v2_info6 {
+	u32 dip2_h:9;
+	u32 dip3_l:23;
+};
+struct mtk_lro_alt_v2_info7 {
+	u32 dip1_h:9;
+	u32 dip2_l:23;
+};
+struct mtk_lro_alt_v2_info8 {
+	u32 dip0_h:9;
+	u32 dip1_l:23;
+};
+struct mtk_lro_alt_v2_info9 {
+	u32 sp_h:9;
+	u32 dip0_l:23;
+};
+struct mtk_lro_alt_v2_info10 {
+	u32 resv:9;
+	u32 dp:16;
+	u32 sp_l:7;
+};
+
+struct mtk_lro_alt_v2 {
+	struct mtk_lro_alt_v2_info0 alt_info0;
+	struct mtk_lro_alt_v2_info1 alt_info1;
+	struct mtk_lro_alt_v2_info2 alt_info2;
+	struct mtk_lro_alt_v2_info3 alt_info3;
+	struct mtk_lro_alt_v2_info4 alt_info4;
+	struct mtk_lro_alt_v2_info5 alt_info5;
+	struct mtk_lro_alt_v2_info6 alt_info6;
+	struct mtk_lro_alt_v2_info7 alt_info7;
+	struct mtk_lro_alt_v2_info8 alt_info8;
+	struct mtk_lro_alt_v2_info9 alt_info9;
+	struct mtk_lro_alt_v2_info10 alt_info10;
+};
+
+struct mtk_esw_reg {
+	unsigned int off;
+	unsigned int val;
+};
+
+struct mtk_mii_ioctl_data {
+	u16 phy_id;
+	u16 reg_num;
+	unsigned int val_in;
+	unsigned int val_out;
+};
+
+#if defined(CONFIG_NET_DSA_MT7530) || defined(CONFIG_MT753X_GSW)
+static inline bool mt7530_exist(struct mtk_eth *eth)
+{
+	return true;
+}
+#else
+static inline bool mt7530_exist(struct mtk_eth *eth)
+{
+	return false;
+}
+#endif
+
+extern u32 _mtk_mdio_read(struct mtk_eth *eth, u16 phy_addr, u16 phy_reg);
+extern u32 _mtk_mdio_write(struct mtk_eth *eth, u16 phy_addr,
+		    u16 phy_register, u16 write_data);
+
+extern u32 mtk_cl45_ind_read(struct mtk_eth *eth, u16 port, u16 devad, u16 reg, u16 *data);
+extern u32 mtk_cl45_ind_write(struct mtk_eth *eth, u16 port, u16 devad, u16 reg, u16 data);
+
+int debug_proc_init(struct mtk_eth *eth);
+void debug_proc_exit(void);
+
+int mtketh_debugfs_init(struct mtk_eth *eth);
+void mtketh_debugfs_exit(struct mtk_eth *eth);
+int mtk_do_priv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+void hw_lro_stats_update(u32 ring_no, struct mtk_rx_dma *rxd);
+void hw_lro_flush_stats_update(u32 ring_no, struct mtk_rx_dma *rxd);
+
+#endif /* MTK_ETH_DBG_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_path.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_path.c
new file mode 100755
index 0000000..dcb3c8a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_path.c
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018-2019 MediaTek Inc.
+
+/* A library for configuring path from GMAC/GDM to target PHY
+ *
+ * Author: Sean Wang <sean.wang@mediatek.com>
+ *
+ */
+
+#include <linux/phy.h>
+#include <linux/regmap.h>
+
+#include "mtk_eth_soc.h"
+
+struct mtk_eth_muxc {
+	const char	*name;
+	int		cap_bit;
+	int		(*set_path)(struct mtk_eth *eth, int path);
+};
+
+static const char *mtk_eth_path_name(int path)
+{
+	switch (path) {
+	case MTK_ETH_PATH_GMAC1_RGMII:
+		return "gmac1_rgmii";
+	case MTK_ETH_PATH_GMAC1_TRGMII:
+		return "gmac1_trgmii";
+	case MTK_ETH_PATH_GMAC1_SGMII:
+		return "gmac1_sgmii";
+	case MTK_ETH_PATH_GMAC2_RGMII:
+		return "gmac2_rgmii";
+	case MTK_ETH_PATH_GMAC2_SGMII:
+		return "gmac2_sgmii";
+	case MTK_ETH_PATH_GMAC2_GEPHY:
+		return "gmac2_gephy";
+	case MTK_ETH_PATH_GDM1_ESW:
+		return "gdm1_esw";
+	default:
+		return "unknown path";
+	}
+}
+
+static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, int path)
+{
+	bool updated = true;
+	u32 val, mask, set;
+
+	switch (path) {
+	case MTK_ETH_PATH_GMAC1_SGMII:
+		mask = ~(u32)MTK_MUX_TO_ESW;
+		set = 0;
+		break;
+	case MTK_ETH_PATH_GDM1_ESW:
+		mask = ~(u32)MTK_MUX_TO_ESW;
+		set = MTK_MUX_TO_ESW;
+		break;
+	default:
+		updated = false;
+		break;
+	};
+
+	if (updated) {
+		val = mtk_r32(eth, MTK_MAC_MISC);
+		val = (val & mask) | set;
+		mtk_w32(eth, val, MTK_MAC_MISC);
+	}
+
+	dev_dbg(eth->dev, "path %s in %s updated = %d\n",
+		mtk_eth_path_name(path), __func__, updated);
+
+	return 0;
+}
+
+static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, int path)
+{
+	unsigned int val = 0;
+	bool updated = true;
+
+	switch (path) {
+	case MTK_ETH_PATH_GMAC2_GEPHY:
+		val = ~(u32)GEPHY_MAC_SEL;
+		break;
+	default:
+		updated = false;
+		break;
+	}
+
+	if (updated)
+		regmap_update_bits(eth->infra, INFRA_MISC2, GEPHY_MAC_SEL, val);
+
+	dev_dbg(eth->dev, "path %s in %s updated = %d\n",
+		mtk_eth_path_name(path), __func__, updated);
+
+	return 0;
+}
+
+static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, int path)
+{
+	unsigned int val = 0,mask=0,reg=0;
+	bool updated = true;
+
+	switch (path) {
+	case MTK_ETH_PATH_GMAC2_SGMII:
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_U3_COPHY_V2)) {
+			reg = USB_PHY_SWITCH_REG;
+			val = SGMII_QPHY_SEL;
+			mask = QPHY_SEL_MASK;
+		} else {
+			reg = INFRA_MISC2;
+			val = CO_QPHY_SEL;
+			mask = val;
+		}
+		break;
+	default:
+		updated = false;
+		break;
+	}
+
+	if (updated)
+		regmap_update_bits(eth->infra, reg, mask, val);
+
+	dev_dbg(eth->dev, "path %s in %s updated = %d\n",
+		mtk_eth_path_name(path), __func__, updated);
+
+	return 0;
+}
+
+static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, int path)
+{
+	unsigned int val = 0;
+	bool updated = true;
+
+	spin_lock(&eth->syscfg0_lock);
+
+	switch (path) {
+	case MTK_ETH_PATH_GMAC1_SGMII:
+		val = SYSCFG0_SGMII_GMAC1;
+		break;
+	case MTK_ETH_PATH_GMAC2_SGMII:
+		val = SYSCFG0_SGMII_GMAC2;
+		break;
+	case MTK_ETH_PATH_GMAC1_RGMII:
+	case MTK_ETH_PATH_GMAC2_RGMII:
+		regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
+		val &= SYSCFG0_SGMII_MASK;
+
+		if ((path == MTK_GMAC1_RGMII && val == SYSCFG0_SGMII_GMAC1) ||
+		    (path == MTK_GMAC2_RGMII && val == SYSCFG0_SGMII_GMAC2))
+			val = 0;
+		else
+			updated = false;
+		break;
+	default:
+		updated = false;
+		break;
+	};
+
+	if (updated)
+		regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
+				   SYSCFG0_SGMII_MASK, val);
+
+	spin_unlock(&eth->syscfg0_lock);
+
+	dev_dbg(eth->dev, "path %s in %s updated = %d\n",
+		mtk_eth_path_name(path), __func__, updated);
+
+	return 0;
+}
+
+static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, int path)
+{
+	unsigned int val = 0;
+	bool updated = true;
+
+	spin_lock(&eth->syscfg0_lock);
+
+	regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
+
+	switch (path) {
+	case MTK_ETH_PATH_GMAC1_SGMII:
+		val |= SYSCFG0_SGMII_GMAC1_V2;
+		break;
+	case MTK_ETH_PATH_GMAC2_GEPHY:
+		val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2;
+		break;
+	case MTK_ETH_PATH_GMAC2_SGMII:
+		val |= SYSCFG0_SGMII_GMAC2_V2;
+		break;
+	default:
+		updated = false;
+	};
+
+	if (updated)
+		regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
+				   SYSCFG0_SGMII_MASK, val);
+
+	spin_unlock(&eth->syscfg0_lock);
+
+	dev_dbg(eth->dev, "path %s in %s updated = %d\n",
+		mtk_eth_path_name(path), __func__, updated);
+
+	return 0;
+}
+
+static const struct mtk_eth_muxc mtk_eth_muxc[] = {
+	{
+		.name = "mux_gdm1_to_gmac1_esw",
+		.cap_bit = MTK_ETH_MUX_GDM1_TO_GMAC1_ESW,
+		.set_path = set_mux_gdm1_to_gmac1_esw,
+	}, {
+		.name = "mux_gmac2_gmac0_to_gephy",
+		.cap_bit = MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY,
+		.set_path = set_mux_gmac2_gmac0_to_gephy,
+	}, {
+		.name = "mux_u3_gmac2_to_qphy",
+		.cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY,
+		.set_path = set_mux_u3_gmac2_to_qphy,
+	}, {
+		.name = "mux_gmac1_gmac2_to_sgmii_rgmii",
+		.cap_bit = MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII,
+		.set_path = set_mux_gmac1_gmac2_to_sgmii_rgmii,
+	}, {
+		.name = "mux_gmac12_to_gephy_sgmii",
+		.cap_bit = MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII,
+		.set_path = set_mux_gmac12_to_gephy_sgmii,
+	},
+};
+
+static int mtk_eth_mux_setup(struct mtk_eth *eth, int path)
+{
+	int i, err = 0;
+
+	if (!MTK_HAS_CAPS(eth->soc->caps, path)) {
+		dev_err(eth->dev, "path %s isn't support on the SoC\n",
+			mtk_eth_path_name(path));
+		return -EINVAL;
+	}
+
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_MUX))
+		return 0;
+
+	/* Setup MUX in path fabric */
+	for (i = 0; i < ARRAY_SIZE(mtk_eth_muxc); i++) {
+		if (MTK_HAS_CAPS(eth->soc->caps, mtk_eth_muxc[i].cap_bit)) {
+			err = mtk_eth_muxc[i].set_path(eth, path);
+			if (err)
+				goto out;
+		} else {
+			dev_dbg(eth->dev, "mux %s isn't present on the SoC\n",
+				mtk_eth_muxc[i].name);
+		}
+	}
+
+out:
+	return err;
+}
+
+int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id)
+{
+	int err, path;
+
+	path = (mac_id == 0) ?  MTK_ETH_PATH_GMAC1_SGMII :
+				MTK_ETH_PATH_GMAC2_SGMII;
+
+	/* Setup proper MUXes along the path */
+	err = mtk_eth_mux_setup(eth, path);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id)
+{
+	int err, path = 0;
+
+	if (mac_id == 1)
+		path = MTK_ETH_PATH_GMAC2_GEPHY;
+
+	if (!path)
+		return -EINVAL;
+
+	/* Setup proper MUXes along the path */
+	err = mtk_eth_mux_setup(eth, path);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id)
+{
+	int err, path;
+
+	path = (mac_id == 0) ?  MTK_ETH_PATH_GMAC1_RGMII :
+				MTK_ETH_PATH_GMAC2_RGMII;
+
+	/* Setup proper MUXes along the path */
+	err = mtk_eth_mux_setup(eth, path);
+	if (err)
+		return err;
+
+	return 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
new file mode 100755
index 0000000..1bf43b3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -0,0 +1,3758 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ *
+ *   Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
+ *   Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
+ *   Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
+ */
+
+#include <linux/of_device.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/if_vlan.h>
+#include <linux/reset.h>
+#include <linux/tcp.h>
+#include <linux/interrupt.h>
+#include <linux/pinctrl/devinfo.h>
+#include <linux/phylink.h>
+#include <net/dsa.h>
+
+#include "mtk_eth_soc.h"
+#include "mtk_eth_dbg.h"
+
+#if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE)
+#include "mtk_hnat/nf_hnat_mtk.h"
+#endif
+
+static int mtk_msg_level = -1;
+module_param_named(msg_level, mtk_msg_level, int, 0);
+MODULE_PARM_DESC(msg_level, "Message level (-1=defaults,0=none,...,16=all)");
+
+#define MTK_ETHTOOL_STAT(x) { #x, \
+			      offsetof(struct mtk_hw_stats, x) / sizeof(u64) }
+
+/* strings used by ethtool */
+static const struct mtk_ethtool_stats {
+	char str[ETH_GSTRING_LEN];
+	u32 offset;
+} mtk_ethtool_stats[] = {
+	MTK_ETHTOOL_STAT(tx_bytes),
+	MTK_ETHTOOL_STAT(tx_packets),
+	MTK_ETHTOOL_STAT(tx_skip),
+	MTK_ETHTOOL_STAT(tx_collisions),
+	MTK_ETHTOOL_STAT(rx_bytes),
+	MTK_ETHTOOL_STAT(rx_packets),
+	MTK_ETHTOOL_STAT(rx_overflow),
+	MTK_ETHTOOL_STAT(rx_fcs_errors),
+	MTK_ETHTOOL_STAT(rx_short_errors),
+	MTK_ETHTOOL_STAT(rx_long_errors),
+	MTK_ETHTOOL_STAT(rx_checksum_errors),
+	MTK_ETHTOOL_STAT(rx_flow_control_packets),
+};
+
+static const char * const mtk_clks_source_name[] = {
+	"ethif", "sgmiitop", "esw", "gp0", "gp1", "gp2", "fe", "trgpll",
+	"sgmii_tx250m", "sgmii_rx250m", "sgmii_cdr_ref", "sgmii_cdr_fb",
+	"sgmii2_tx250m", "sgmii2_rx250m", "sgmii2_cdr_ref", "sgmii2_cdr_fb",
+	"sgmii_ck", "eth2pll", "wocpu0","wocpu1",
+};
+
+void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg)
+{
+	__raw_writel(val, eth->base + reg);
+}
+
+u32 mtk_r32(struct mtk_eth *eth, unsigned reg)
+{
+	return __raw_readl(eth->base + reg);
+}
+
+u32 mtk_m32(struct mtk_eth *eth, u32 mask, u32 set, unsigned reg)
+{
+	u32 val;
+
+	val = mtk_r32(eth, reg);
+	val &= ~mask;
+	val |= set;
+	mtk_w32(eth, val, reg);
+	return reg;
+}
+
+static int mtk_mdio_busy_wait(struct mtk_eth *eth)
+{
+	unsigned long t_start = jiffies;
+
+	while (1) {
+		if (!(mtk_r32(eth, MTK_PHY_IAC) & PHY_IAC_ACCESS))
+			return 0;
+		if (time_after(jiffies, t_start + PHY_IAC_TIMEOUT))
+			break;
+		cond_resched();
+	}
+
+	dev_err(eth->dev, "mdio: MDIO timeout\n");
+	return -1;
+}
+
+u32 _mtk_mdio_write(struct mtk_eth *eth, u16 phy_addr,
+			   u16 phy_register, u16 write_data)
+{
+	if (mtk_mdio_busy_wait(eth))
+		return -1;
+
+	write_data &= 0xffff;
+
+	mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START | PHY_IAC_WRITE |
+		((phy_register & 0x1f) << PHY_IAC_REG_SHIFT) |
+		((phy_addr & 0x1f) << PHY_IAC_ADDR_SHIFT) | write_data,
+		MTK_PHY_IAC);
+
+	if (mtk_mdio_busy_wait(eth))
+		return -1;
+
+	return 0;
+}
+
+u32 _mtk_mdio_read(struct mtk_eth *eth, u16 phy_addr, u16 phy_reg)
+{
+	u32 d;
+
+	if (mtk_mdio_busy_wait(eth))
+		return 0xffff;
+
+	mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START | PHY_IAC_READ |
+		((phy_reg & 0x1f) << PHY_IAC_REG_SHIFT) |
+		((phy_addr & 0x1f) << PHY_IAC_ADDR_SHIFT),
+		MTK_PHY_IAC);
+
+	if (mtk_mdio_busy_wait(eth))
+		return 0xffff;
+
+	d = mtk_r32(eth, MTK_PHY_IAC) & 0xffff;
+
+	return d;
+}
+
+static int mtk_mdio_write(struct mii_bus *bus, int phy_addr,
+			  int phy_reg, u16 val)
+{
+	struct mtk_eth *eth = bus->priv;
+
+	return _mtk_mdio_write(eth, phy_addr, phy_reg, val);
+}
+
+static int mtk_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg)
+{
+	struct mtk_eth *eth = bus->priv;
+
+	return _mtk_mdio_read(eth, phy_addr, phy_reg);
+}
+
+u32 mtk_cl45_ind_read(struct mtk_eth *eth, u16 port, u16 devad, u16 reg, u16 *data)
+{
+        mutex_lock(&eth->mii_bus->mdio_lock);
+
+        _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, devad);
+        _mtk_mdio_write(eth, port, MII_MMD_ADDR_DATA_REG, reg);
+        _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
+        *data = _mtk_mdio_read(eth, port, MII_MMD_ADDR_DATA_REG);
+
+        mutex_unlock(&eth->mii_bus->mdio_lock);
+
+        return 0;
+}
+
+u32 mtk_cl45_ind_write(struct mtk_eth *eth, u16 port, u16 devad, u16 reg, u16 data)
+{
+        mutex_lock(&eth->mii_bus->mdio_lock);
+
+        _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, devad);
+        _mtk_mdio_write(eth, port, MII_MMD_ADDR_DATA_REG, reg);
+        _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
+        _mtk_mdio_write(eth, port, MII_MMD_ADDR_DATA_REG, data);
+
+        mutex_unlock(&eth->mii_bus->mdio_lock);
+
+        return 0;
+}
+
+static int mt7621_gmac0_rgmii_adjust(struct mtk_eth *eth,
+				     phy_interface_t interface)
+{
+	u32 val;
+
+	/* Check DDR memory type.
+	 * Currently TRGMII mode with DDR2 memory is not supported.
+	 */
+	regmap_read(eth->ethsys, ETHSYS_SYSCFG, &val);
+	if (interface == PHY_INTERFACE_MODE_TRGMII &&
+	    val & SYSCFG_DRAM_TYPE_DDR2) {
+		dev_err(eth->dev,
+			"TRGMII mode with DDR2 memory is not supported!\n");
+		return -EOPNOTSUPP;
+	}
+
+	val = (interface == PHY_INTERFACE_MODE_TRGMII) ?
+		ETHSYS_TRGMII_MT7621_DDR_PLL : 0;
+
+	regmap_update_bits(eth->ethsys, ETHSYS_CLKCFG0,
+			   ETHSYS_TRGMII_MT7621_MASK, val);
+
+	return 0;
+}
+
+static void mtk_gmac0_rgmii_adjust(struct mtk_eth *eth,
+				   phy_interface_t interface, int speed)
+{
+	u32 val;
+	int ret;
+
+	if (interface == PHY_INTERFACE_MODE_TRGMII) {
+		mtk_w32(eth, TRGMII_MODE, INTF_MODE);
+		val = 500000000;
+		ret = clk_set_rate(eth->clks[MTK_CLK_TRGPLL], val);
+		if (ret)
+			dev_err(eth->dev, "Failed to set trgmii pll: %d\n", ret);
+		return;
+	}
+
+	val = (speed == SPEED_1000) ?
+		INTF_MODE_RGMII_1000 : INTF_MODE_RGMII_10_100;
+	mtk_w32(eth, val, INTF_MODE);
+
+	regmap_update_bits(eth->ethsys, ETHSYS_CLKCFG0,
+			   ETHSYS_TRGMII_CLK_SEL362_5,
+			   ETHSYS_TRGMII_CLK_SEL362_5);
+
+	val = (speed == SPEED_1000) ? 250000000 : 500000000;
+	ret = clk_set_rate(eth->clks[MTK_CLK_TRGPLL], val);
+	if (ret)
+		dev_err(eth->dev, "Failed to set trgmii pll: %d\n", ret);
+
+	val = (speed == SPEED_1000) ?
+		RCK_CTRL_RGMII_1000 : RCK_CTRL_RGMII_10_100;
+	mtk_w32(eth, val, TRGMII_RCK_CTRL);
+
+	val = (speed == SPEED_1000) ?
+		TCK_CTRL_RGMII_1000 : TCK_CTRL_RGMII_10_100;
+	mtk_w32(eth, val, TRGMII_TCK_CTRL);
+}
+
+static void mtk_mac_config(struct phylink_config *config, unsigned int mode,
+			   const struct phylink_link_state *state)
+{
+	struct mtk_mac *mac = container_of(config, struct mtk_mac,
+					   phylink_config);
+	struct mtk_eth *eth = mac->hw;
+	u32 mcr_cur, mcr_new, sid, i;
+	int val, ge_mode, err=0;
+
+	/* MT76x8 has no hardware settings between for the MAC */
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) &&
+	    mac->interface != state->interface) {
+		/* Setup soc pin functions */
+		switch (state->interface) {
+		case PHY_INTERFACE_MODE_TRGMII:
+			if (mac->id)
+				goto err_phy;
+			if (!MTK_HAS_CAPS(mac->hw->soc->caps,
+					  MTK_GMAC1_TRGMII))
+				goto err_phy;
+			/* fall through */
+		case PHY_INTERFACE_MODE_RGMII_TXID:
+		case PHY_INTERFACE_MODE_RGMII_RXID:
+		case PHY_INTERFACE_MODE_RGMII_ID:
+		case PHY_INTERFACE_MODE_RGMII:
+		case PHY_INTERFACE_MODE_MII:
+		case PHY_INTERFACE_MODE_REVMII:
+		case PHY_INTERFACE_MODE_RMII:
+			if (MTK_HAS_CAPS(eth->soc->caps, MTK_RGMII)) {
+				err = mtk_gmac_rgmii_path_setup(eth, mac->id);
+				if (err)
+					goto init_err;
+			}
+			break;
+		case PHY_INTERFACE_MODE_1000BASEX:
+		case PHY_INTERFACE_MODE_2500BASEX:
+		case PHY_INTERFACE_MODE_SGMII:
+			if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
+				err = mtk_gmac_sgmii_path_setup(eth, mac->id);
+				if (err)
+					goto init_err;
+			}
+			break;
+		case PHY_INTERFACE_MODE_GMII:
+			if (MTK_HAS_CAPS(eth->soc->caps, MTK_GEPHY)) {
+				err = mtk_gmac_gephy_path_setup(eth, mac->id);
+				if (err)
+					goto init_err;
+			}
+			break;
+		default:
+			goto err_phy;
+		}
+
+		/* Setup clock for 1st gmac */
+		if (!mac->id && state->interface != PHY_INTERFACE_MODE_SGMII &&
+		    !phy_interface_mode_is_8023z(state->interface) &&
+		    MTK_HAS_CAPS(mac->hw->soc->caps, MTK_GMAC1_TRGMII)) {
+			if (MTK_HAS_CAPS(mac->hw->soc->caps,
+					 MTK_TRGMII_MT7621_CLK)) {
+				if (mt7621_gmac0_rgmii_adjust(mac->hw,
+							      state->interface))
+					goto err_phy;
+			} else {
+				mtk_gmac0_rgmii_adjust(mac->hw,
+						       state->interface,
+						       state->speed);
+
+				/* mt7623_pad_clk_setup */
+				for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
+					mtk_w32(mac->hw,
+						TD_DM_DRVP(8) | TD_DM_DRVN(8),
+						TRGMII_TD_ODT(i));
+
+				/* Assert/release MT7623 RXC reset */
+				mtk_m32(mac->hw, 0, RXC_RST | RXC_DQSISEL,
+					TRGMII_RCK_CTRL);
+				mtk_m32(mac->hw, RXC_RST, 0, TRGMII_RCK_CTRL);
+			}
+		}
+
+		ge_mode = 0;
+		switch (state->interface) {
+		case PHY_INTERFACE_MODE_MII:
+		case PHY_INTERFACE_MODE_GMII:
+			ge_mode = 1;
+			break;
+		case PHY_INTERFACE_MODE_REVMII:
+			ge_mode = 2;
+			break;
+		case PHY_INTERFACE_MODE_RMII:
+			if (mac->id)
+				goto err_phy;
+			ge_mode = 3;
+			break;
+		default:
+			break;
+		}
+
+		/* put the gmac into the right mode */
+		spin_lock(&eth->syscfg0_lock);
+		regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
+		val &= ~SYSCFG0_GE_MODE(SYSCFG0_GE_MASK, mac->id);
+		val |= SYSCFG0_GE_MODE(ge_mode, mac->id);
+		regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val);
+		spin_unlock(&eth->syscfg0_lock);
+
+		mac->interface = state->interface;
+	}
+
+	/* SGMII */
+	if (state->interface == PHY_INTERFACE_MODE_SGMII ||
+	    phy_interface_mode_is_8023z(state->interface)) {
+		/* The path GMAC to SGMII will be enabled once the SGMIISYS is
+		 * being setup done.
+		 */
+		spin_lock(&eth->syscfg0_lock);
+		regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
+
+		regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
+				   SYSCFG0_SGMII_MASK,
+				   ~(u32)SYSCFG0_SGMII_MASK);
+
+		/* Decide how GMAC and SGMIISYS be mapped */
+		sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ?
+		       0 : mac->id;
+
+		/* Setup SGMIISYS with the determined property */
+		if (state->interface != PHY_INTERFACE_MODE_SGMII)
+			err = mtk_sgmii_setup_mode_force(eth->sgmii, sid,
+							 state);
+		else if (phylink_autoneg_inband(mode))
+			err = mtk_sgmii_setup_mode_an(eth->sgmii, sid);
+
+		if (err) {
+			spin_unlock(&eth->syscfg0_lock);
+			goto init_err;
+		}
+
+		regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
+				   SYSCFG0_SGMII_MASK, val);
+		spin_unlock(&eth->syscfg0_lock);
+	} else if (phylink_autoneg_inband(mode)) {
+		dev_err(eth->dev,
+			"In-band mode not supported in non SGMII mode!\n");
+		return;
+	}
+
+	/* Setup gmac */
+	mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id));
+	mcr_new = mcr_cur;
+	mcr_new &= ~(MAC_MCR_SPEED_100 | MAC_MCR_SPEED_1000 |
+		     MAC_MCR_FORCE_DPX | MAC_MCR_FORCE_TX_FC |
+		     MAC_MCR_FORCE_RX_FC);
+	mcr_new |= MAC_MCR_MAX_RX_1536 | MAC_MCR_IPG_CFG | MAC_MCR_FORCE_MODE |
+		   MAC_MCR_BACKOFF_EN | MAC_MCR_BACKPR_EN | MAC_MCR_FORCE_LINK;
+
+	switch (state->speed) {
+	case SPEED_2500:
+	case SPEED_1000:
+		mcr_new |= MAC_MCR_SPEED_1000;
+		break;
+	case SPEED_100:
+		mcr_new |= MAC_MCR_SPEED_100;
+		break;
+	}
+	if (state->duplex == DUPLEX_FULL) {
+		mcr_new |= MAC_MCR_FORCE_DPX;
+		if (state->pause & MLO_PAUSE_TX)
+			mcr_new |= MAC_MCR_FORCE_TX_FC;
+		if (state->pause & MLO_PAUSE_RX)
+			mcr_new |= MAC_MCR_FORCE_RX_FC;
+	}
+
+	/* Only update control register when needed! */
+	if (mcr_new != mcr_cur)
+		mtk_w32(mac->hw, mcr_new, MTK_MAC_MCR(mac->id));
+
+	return;
+
+err_phy:
+	dev_err(eth->dev, "%s: GMAC%d mode %s not supported!\n", __func__,
+		mac->id, phy_modes(state->interface));
+	return;
+
+init_err:
+	dev_err(eth->dev, "%s: GMAC%d mode %s err: %d!\n", __func__,
+		mac->id, phy_modes(state->interface), err);
+}
+
+static int mtk_mac_link_state(struct phylink_config *config,
+			      struct phylink_link_state *state)
+{
+	struct mtk_mac *mac = container_of(config, struct mtk_mac,
+					   phylink_config);
+	u32 pmsr = mtk_r32(mac->hw, MTK_MAC_MSR(mac->id));
+
+	state->link = (pmsr & MAC_MSR_LINK);
+	state->duplex = (pmsr & MAC_MSR_DPX) >> 1;
+
+	switch (pmsr & (MAC_MSR_SPEED_1000 | MAC_MSR_SPEED_100)) {
+	case 0:
+		state->speed = SPEED_10;
+		break;
+	case MAC_MSR_SPEED_100:
+		state->speed = SPEED_100;
+		break;
+	case MAC_MSR_SPEED_1000:
+		state->speed = SPEED_1000;
+		break;
+	default:
+		state->speed = SPEED_UNKNOWN;
+		break;
+	}
+
+	state->pause &= (MLO_PAUSE_RX | MLO_PAUSE_TX);
+	if (pmsr & MAC_MSR_RX_FC)
+		state->pause |= MLO_PAUSE_RX;
+	if (pmsr & MAC_MSR_TX_FC)
+		state->pause |= MLO_PAUSE_TX;
+
+	return 1;
+}
+
+static void mtk_mac_an_restart(struct phylink_config *config)
+{
+	struct mtk_mac *mac = container_of(config, struct mtk_mac,
+					   phylink_config);
+
+	mtk_sgmii_restart_an(mac->hw, mac->id);
+}
+
+static void mtk_mac_link_down(struct phylink_config *config, unsigned int mode,
+			      phy_interface_t interface)
+{
+	struct mtk_mac *mac = container_of(config, struct mtk_mac,
+					   phylink_config);
+	u32 mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id));
+
+	mcr &= ~(MAC_MCR_TX_EN | MAC_MCR_RX_EN);
+	mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
+}
+
+static void mtk_mac_link_up(struct phylink_config *config,
+                            struct phy_device *phy,
+                            unsigned int mode, phy_interface_t interface,
+                            int speed, int duplex, bool tx_pause, bool rx_pause)
+{
+	struct mtk_mac *mac = container_of(config, struct mtk_mac,
+					   phylink_config);
+	u32 mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id));
+
+	mcr |= MAC_MCR_TX_EN | MAC_MCR_RX_EN;
+	mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
+}
+
+static void mtk_validate(struct phylink_config *config,
+			 unsigned long *supported,
+			 struct phylink_link_state *state)
+{
+	struct mtk_mac *mac = container_of(config, struct mtk_mac,
+					   phylink_config);
+	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+
+	if (state->interface != PHY_INTERFACE_MODE_NA &&
+	    state->interface != PHY_INTERFACE_MODE_MII &&
+	    state->interface != PHY_INTERFACE_MODE_GMII &&
+	    !(MTK_HAS_CAPS(mac->hw->soc->caps, MTK_RGMII) &&
+	      phy_interface_mode_is_rgmii(state->interface)) &&
+	    !(MTK_HAS_CAPS(mac->hw->soc->caps, MTK_TRGMII) &&
+	      !mac->id && state->interface == PHY_INTERFACE_MODE_TRGMII) &&
+	    !(MTK_HAS_CAPS(mac->hw->soc->caps, MTK_SGMII) &&
+	      (state->interface == PHY_INTERFACE_MODE_SGMII ||
+	       phy_interface_mode_is_8023z(state->interface)))) {
+		linkmode_zero(supported);
+		return;
+	}
+
+	phylink_set_port_modes(mask);
+	phylink_set(mask, Autoneg);
+
+	switch (state->interface) {
+	case PHY_INTERFACE_MODE_TRGMII:
+		phylink_set(mask, 1000baseT_Full);
+		break;
+	case PHY_INTERFACE_MODE_1000BASEX:
+	case PHY_INTERFACE_MODE_2500BASEX:
+		phylink_set(mask, 1000baseX_Full);
+		phylink_set(mask, 2500baseX_Full);
+		break;
+	case PHY_INTERFACE_MODE_GMII:
+	case PHY_INTERFACE_MODE_RGMII:
+	case PHY_INTERFACE_MODE_RGMII_ID:
+	case PHY_INTERFACE_MODE_RGMII_RXID:
+	case PHY_INTERFACE_MODE_RGMII_TXID:
+		phylink_set(mask, 1000baseT_Half);
+		/* fall through */
+	case PHY_INTERFACE_MODE_SGMII:
+		phylink_set(mask, 1000baseT_Full);
+		phylink_set(mask, 1000baseX_Full);
+		/* fall through */
+	case PHY_INTERFACE_MODE_MII:
+	case PHY_INTERFACE_MODE_RMII:
+	case PHY_INTERFACE_MODE_REVMII:
+	case PHY_INTERFACE_MODE_NA:
+	default:
+		phylink_set(mask, 10baseT_Half);
+		phylink_set(mask, 10baseT_Full);
+		phylink_set(mask, 100baseT_Half);
+		phylink_set(mask, 100baseT_Full);
+		break;
+	}
+
+	if (state->interface == PHY_INTERFACE_MODE_NA) {
+		if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_SGMII)) {
+			phylink_set(mask, 1000baseT_Full);
+			phylink_set(mask, 1000baseX_Full);
+			phylink_set(mask, 2500baseX_Full);
+		}
+		if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_RGMII)) {
+			phylink_set(mask, 1000baseT_Full);
+			phylink_set(mask, 1000baseT_Half);
+			phylink_set(mask, 1000baseX_Full);
+		}
+		if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_GEPHY)) {
+			phylink_set(mask, 1000baseT_Full);
+			phylink_set(mask, 1000baseT_Half);
+		}
+	}
+
+	phylink_set(mask, Pause);
+	phylink_set(mask, Asym_Pause);
+
+	linkmode_and(supported, supported, mask);
+	linkmode_and(state->advertising, state->advertising, mask);
+
+	/* We can only operate at 2500BaseX or 1000BaseX. If requested
+	 * to advertise both, only report advertising at 2500BaseX.
+	 */
+	phylink_helper_basex_speed(state);
+}
+
+static const struct phylink_mac_ops mtk_phylink_ops = {
+	.validate = mtk_validate,
+	.mac_link_state = mtk_mac_link_state,
+	.mac_an_restart = mtk_mac_an_restart,
+	.mac_config = mtk_mac_config,
+	.mac_link_down = mtk_mac_link_down,
+	.mac_link_up = mtk_mac_link_up,
+};
+
+static int mtk_mdio_init(struct mtk_eth *eth)
+{
+	struct device_node *mii_np;
+	int ret;
+
+	mii_np = of_get_child_by_name(eth->dev->of_node, "mdio-bus");
+	if (!mii_np) {
+		dev_err(eth->dev, "no %s child node found", "mdio-bus");
+		return -ENODEV;
+	}
+
+	if (!of_device_is_available(mii_np)) {
+		ret = -ENODEV;
+		goto err_put_node;
+	}
+
+	eth->mii_bus = devm_mdiobus_alloc(eth->dev);
+	if (!eth->mii_bus) {
+		ret = -ENOMEM;
+		goto err_put_node;
+	}
+
+	eth->mii_bus->name = "mdio";
+	eth->mii_bus->read = mtk_mdio_read;
+	eth->mii_bus->write = mtk_mdio_write;
+	eth->mii_bus->priv = eth;
+	eth->mii_bus->parent = eth->dev;
+
+	if(snprintf(eth->mii_bus->id, MII_BUS_ID_SIZE, "%pOFn", mii_np) < 0) {
+		ret = -ENOMEM;
+		goto err_put_node;
+	}
+	ret = of_mdiobus_register(eth->mii_bus, mii_np);
+
+err_put_node:
+	of_node_put(mii_np);
+	return ret;
+}
+
+static void mtk_mdio_cleanup(struct mtk_eth *eth)
+{
+	if (!eth->mii_bus)
+		return;
+
+	mdiobus_unregister(eth->mii_bus);
+}
+
+static inline void mtk_tx_irq_disable(struct mtk_eth *eth, u32 mask)
+{
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&eth->tx_irq_lock, flags);
+	val = mtk_r32(eth, eth->tx_int_mask_reg);
+	mtk_w32(eth, val & ~mask, eth->tx_int_mask_reg);
+	spin_unlock_irqrestore(&eth->tx_irq_lock, flags);
+}
+
+static inline void mtk_tx_irq_enable(struct mtk_eth *eth, u32 mask)
+{
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&eth->tx_irq_lock, flags);
+	val = mtk_r32(eth, eth->tx_int_mask_reg);
+	mtk_w32(eth, val | mask, eth->tx_int_mask_reg);
+	spin_unlock_irqrestore(&eth->tx_irq_lock, flags);
+}
+
+static inline void mtk_rx_irq_disable(struct mtk_eth *eth, u32 mask)
+{
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&eth->rx_irq_lock, flags);
+	val = mtk_r32(eth, MTK_PDMA_INT_MASK);
+	mtk_w32(eth, val & ~mask, MTK_PDMA_INT_MASK);
+	spin_unlock_irqrestore(&eth->rx_irq_lock, flags);
+}
+
+static inline void mtk_rx_irq_enable(struct mtk_eth *eth, u32 mask)
+{
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&eth->rx_irq_lock, flags);
+	val = mtk_r32(eth, MTK_PDMA_INT_MASK);
+	mtk_w32(eth, val | mask, MTK_PDMA_INT_MASK);
+	spin_unlock_irqrestore(&eth->rx_irq_lock, flags);
+}
+
+static int mtk_set_mac_address(struct net_device *dev, void *p)
+{
+	int ret = eth_mac_addr(dev, p);
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	const char *macaddr = dev->dev_addr;
+
+	if (ret)
+		return ret;
+
+	if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state)))
+		return -EBUSY;
+
+	spin_lock_bh(&mac->hw->page_lock);
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) {
+		mtk_w32(mac->hw, (macaddr[0] << 8) | macaddr[1],
+			MT7628_SDM_MAC_ADRH);
+		mtk_w32(mac->hw, (macaddr[2] << 24) | (macaddr[3] << 16) |
+			(macaddr[4] << 8) | macaddr[5],
+			MT7628_SDM_MAC_ADRL);
+	} else {
+		mtk_w32(mac->hw, (macaddr[0] << 8) | macaddr[1],
+			MTK_GDMA_MAC_ADRH(mac->id));
+		mtk_w32(mac->hw, (macaddr[2] << 24) | (macaddr[3] << 16) |
+			(macaddr[4] << 8) | macaddr[5],
+			MTK_GDMA_MAC_ADRL(mac->id));
+	}
+	spin_unlock_bh(&mac->hw->page_lock);
+
+	return 0;
+}
+
+void mtk_stats_update_mac(struct mtk_mac *mac)
+{
+	struct mtk_hw_stats *hw_stats = mac->hw_stats;
+	unsigned int base = MTK_GDM1_TX_GBCNT;
+	u64 stats;
+
+	base += hw_stats->reg_offset;
+
+	u64_stats_update_begin(&hw_stats->syncp);
+
+	hw_stats->rx_bytes += mtk_r32(mac->hw, base);
+	stats =  mtk_r32(mac->hw, base + 0x04);
+	if (stats)
+		hw_stats->rx_bytes += (stats << 32);
+	hw_stats->rx_packets += mtk_r32(mac->hw, base + 0x08);
+	hw_stats->rx_overflow += mtk_r32(mac->hw, base + 0x10);
+	hw_stats->rx_fcs_errors += mtk_r32(mac->hw, base + 0x14);
+	hw_stats->rx_short_errors += mtk_r32(mac->hw, base + 0x18);
+	hw_stats->rx_long_errors += mtk_r32(mac->hw, base + 0x1c);
+	hw_stats->rx_checksum_errors += mtk_r32(mac->hw, base + 0x20);
+	hw_stats->rx_flow_control_packets +=
+					mtk_r32(mac->hw, base + 0x24);
+	hw_stats->tx_skip += mtk_r32(mac->hw, base + 0x28);
+	hw_stats->tx_collisions += mtk_r32(mac->hw, base + 0x2c);
+	hw_stats->tx_bytes += mtk_r32(mac->hw, base + 0x30);
+	stats =  mtk_r32(mac->hw, base + 0x34);
+	if (stats)
+		hw_stats->tx_bytes += (stats << 32);
+	hw_stats->tx_packets += mtk_r32(mac->hw, base + 0x38);
+	u64_stats_update_end(&hw_stats->syncp);
+}
+
+static void mtk_stats_update(struct mtk_eth *eth)
+{
+	int i;
+
+	for (i = 0; i < MTK_MAC_COUNT; i++) {
+		if (!eth->mac[i] || !eth->mac[i]->hw_stats)
+			continue;
+		if (spin_trylock(&eth->mac[i]->hw_stats->stats_lock)) {
+			mtk_stats_update_mac(eth->mac[i]);
+			spin_unlock(&eth->mac[i]->hw_stats->stats_lock);
+		}
+	}
+}
+
+static void mtk_get_stats64(struct net_device *dev,
+			    struct rtnl_link_stats64 *storage)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_hw_stats *hw_stats = mac->hw_stats;
+	unsigned int start;
+
+	if (netif_running(dev) && netif_device_present(dev)) {
+		if (spin_trylock_bh(&hw_stats->stats_lock)) {
+			mtk_stats_update_mac(mac);
+			spin_unlock_bh(&hw_stats->stats_lock);
+		}
+	}
+
+	do {
+		start = u64_stats_fetch_begin_irq(&hw_stats->syncp);
+		storage->rx_packets = hw_stats->rx_packets;
+		storage->tx_packets = hw_stats->tx_packets;
+		storage->rx_bytes = hw_stats->rx_bytes;
+		storage->tx_bytes = hw_stats->tx_bytes;
+		storage->collisions = hw_stats->tx_collisions;
+		storage->rx_length_errors = hw_stats->rx_short_errors +
+			hw_stats->rx_long_errors;
+		storage->rx_over_errors = hw_stats->rx_overflow;
+		storage->rx_crc_errors = hw_stats->rx_fcs_errors;
+		storage->rx_errors = hw_stats->rx_checksum_errors;
+		storage->tx_aborted_errors = hw_stats->tx_skip;
+	} while (u64_stats_fetch_retry_irq(&hw_stats->syncp, start));
+
+	storage->tx_errors = dev->stats.tx_errors;
+	storage->rx_dropped = dev->stats.rx_dropped;
+	storage->tx_dropped = dev->stats.tx_dropped;
+}
+
+static inline int mtk_max_frag_size(int mtu)
+{
+	/* make sure buf_size will be at least MTK_MAX_RX_LENGTH */
+	if (mtu + MTK_RX_ETH_HLEN < MTK_MAX_RX_LENGTH)
+		mtu = MTK_MAX_RX_LENGTH - MTK_RX_ETH_HLEN;
+
+	return SKB_DATA_ALIGN(MTK_RX_HLEN + mtu) +
+		SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+}
+
+static inline int mtk_max_buf_size(int frag_size)
+{
+	int buf_size = frag_size - NET_SKB_PAD - NET_IP_ALIGN -
+		       SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+	WARN_ON(buf_size < MTK_MAX_RX_LENGTH);
+
+	return buf_size;
+}
+
+static inline bool mtk_rx_get_desc(struct mtk_rx_dma *rxd,
+				   struct mtk_rx_dma *dma_rxd)
+{
+	rxd->rxd2 = READ_ONCE(dma_rxd->rxd2);
+	if (!(rxd->rxd2 & RX_DMA_DONE))
+		return false;
+
+	rxd->rxd1 = READ_ONCE(dma_rxd->rxd1);
+	rxd->rxd3 = READ_ONCE(dma_rxd->rxd3);
+	rxd->rxd4 = READ_ONCE(dma_rxd->rxd4);
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+	rxd->rxd5 = READ_ONCE(dma_rxd->rxd5);
+	rxd->rxd6 = READ_ONCE(dma_rxd->rxd6);
+#endif
+	return true;
+}
+
+/* the qdma core needs scratch memory to be setup */
+static int mtk_init_fq_dma(struct mtk_eth *eth)
+{
+	dma_addr_t phy_ring_tail;
+	int cnt = MTK_DMA_SIZE;
+	dma_addr_t dma_addr;
+	int i;
+
+	if (!eth->soc->has_sram) {
+		eth->scratch_ring = dma_alloc_coherent(eth->dev,
+					       cnt * sizeof(struct mtk_tx_dma),
+					       &eth->phy_scratch_ring,
+					       GFP_ATOMIC);
+	} else {
+		eth->scratch_ring = eth->base + MTK_ETH_SRAM_OFFSET;
+	}
+
+	if (unlikely(!eth->scratch_ring))
+                        return -ENOMEM;
+
+	eth->scratch_head = kcalloc(cnt, MTK_QDMA_PAGE_SIZE,
+				    GFP_KERNEL);
+	if (unlikely(!eth->scratch_head))
+		return -ENOMEM;
+
+	dma_addr = dma_map_single(eth->dev,
+				  eth->scratch_head, cnt * MTK_QDMA_PAGE_SIZE,
+				  DMA_FROM_DEVICE);
+	if (unlikely(dma_mapping_error(eth->dev, dma_addr)))
+		return -ENOMEM;
+
+	phy_ring_tail = eth->phy_scratch_ring +
+			(sizeof(struct mtk_tx_dma) * (cnt - 1));
+
+	for (i = 0; i < cnt; i++) {
+		eth->scratch_ring[i].txd1 =
+				(dma_addr + (i * MTK_QDMA_PAGE_SIZE));
+		if (i < cnt - 1)
+			eth->scratch_ring[i].txd2 = (eth->phy_scratch_ring +
+				((i + 1) * sizeof(struct mtk_tx_dma)));
+		eth->scratch_ring[i].txd3 = TX_DMA_SDL(MTK_QDMA_PAGE_SIZE);
+
+		eth->scratch_ring[i].txd4 = 0;
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+		if (eth->soc->has_sram && ((sizeof(struct mtk_tx_dma)) > 16)) {
+			eth->scratch_ring[i].txd5 = 0;
+			eth->scratch_ring[i].txd6 = 0;
+			eth->scratch_ring[i].txd7 = 0;
+			eth->scratch_ring[i].txd8 = 0;
+		}
+#endif
+	}
+
+	mtk_w32(eth, eth->phy_scratch_ring, MTK_QDMA_FQ_HEAD);
+	mtk_w32(eth, phy_ring_tail, MTK_QDMA_FQ_TAIL);
+	mtk_w32(eth, (cnt << 16) | cnt, MTK_QDMA_FQ_CNT);
+	mtk_w32(eth, MTK_QDMA_PAGE_SIZE << 16, MTK_QDMA_FQ_BLEN);
+
+	return 0;
+}
+
+static inline void *mtk_qdma_phys_to_virt(struct mtk_tx_ring *ring, u32 desc)
+{
+	void *ret = ring->dma;
+
+	return ret + (desc - ring->phys);
+}
+
+static inline struct mtk_tx_buf *mtk_desc_to_tx_buf(struct mtk_tx_ring *ring,
+						    struct mtk_tx_dma *txd)
+{
+	int idx = txd - ring->dma;
+
+	return &ring->buf[idx];
+}
+
+static struct mtk_tx_dma *qdma_to_pdma(struct mtk_tx_ring *ring,
+				       struct mtk_tx_dma *dma)
+{
+	return ring->dma_pdma - ring->dma + dma;
+}
+
+static int txd_to_idx(struct mtk_tx_ring *ring, struct mtk_tx_dma *dma)
+{
+	return ((void *)dma - (void *)ring->dma) / sizeof(*dma);
+}
+
+static void mtk_tx_unmap(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf,
+			 bool napi)
+{
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
+		if (tx_buf->flags & MTK_TX_FLAGS_SINGLE0) {
+			dma_unmap_single(eth->dev,
+					 dma_unmap_addr(tx_buf, dma_addr0),
+					 dma_unmap_len(tx_buf, dma_len0),
+					 DMA_TO_DEVICE);
+		} else if (tx_buf->flags & MTK_TX_FLAGS_PAGE0) {
+			dma_unmap_page(eth->dev,
+				       dma_unmap_addr(tx_buf, dma_addr0),
+				       dma_unmap_len(tx_buf, dma_len0),
+				       DMA_TO_DEVICE);
+		}
+	} else {
+		if (dma_unmap_len(tx_buf, dma_len0)) {
+			dma_unmap_page(eth->dev,
+				       dma_unmap_addr(tx_buf, dma_addr0),
+				       dma_unmap_len(tx_buf, dma_len0),
+				       DMA_TO_DEVICE);
+		}
+
+		if (dma_unmap_len(tx_buf, dma_len1)) {
+			dma_unmap_page(eth->dev,
+				       dma_unmap_addr(tx_buf, dma_addr1),
+				       dma_unmap_len(tx_buf, dma_len1),
+				       DMA_TO_DEVICE);
+		}
+	}
+
+	tx_buf->flags = 0;
+	if (tx_buf->skb &&
+	    (tx_buf->skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC)) {
+		if (napi)
+			napi_consume_skb(tx_buf->skb, napi);
+		else
+			dev_kfree_skb_any(tx_buf->skb);
+	}
+	tx_buf->skb = NULL;
+}
+
+static void setup_tx_buf(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf,
+			 struct mtk_tx_dma *txd, dma_addr_t mapped_addr,
+			 size_t size, int idx)
+{
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
+		dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr);
+		dma_unmap_len_set(tx_buf, dma_len0, size);
+	} else {
+		if (idx & 1) {
+			txd->txd3 = mapped_addr;
+			txd->txd2 |= TX_DMA_PLEN1(size);
+			dma_unmap_addr_set(tx_buf, dma_addr1, mapped_addr);
+			dma_unmap_len_set(tx_buf, dma_len1, size);
+		} else {
+			tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC;
+			txd->txd1 = mapped_addr;
+			txd->txd2 = TX_DMA_PLEN0(size);
+			dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr);
+			dma_unmap_len_set(tx_buf, dma_len0, size);
+		}
+	}
+}
+
+static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,
+		      int tx_num, struct mtk_tx_ring *ring, bool gso)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	struct mtk_tx_dma *itxd, *txd;
+	struct mtk_tx_dma *itxd_pdma, *txd_pdma;
+	struct mtk_tx_buf *itx_buf, *tx_buf;
+	dma_addr_t mapped_addr;
+	unsigned int nr_frags;
+	int i, n_desc = 1;
+	u32 txd4 = 0, txd5 = 0, txd6 = 0;
+	u32 fport;
+	u32 qid = 0;
+	int k = 0;
+
+	itxd = ring->next_free;
+	itxd_pdma = qdma_to_pdma(ring, itxd);
+	if (itxd == ring->last_free)
+		return -ENOMEM;
+
+	itx_buf = mtk_desc_to_tx_buf(ring, itxd);
+	memset(itx_buf, 0, sizeof(*itx_buf));
+
+	mapped_addr = dma_map_single(eth->dev, skb->data,
+				     skb_headlen(skb), DMA_TO_DEVICE);
+	if (unlikely(dma_mapping_error(eth->dev, mapped_addr)))
+		return -ENOMEM;
+
+	WRITE_ONCE(itxd->txd1, mapped_addr);
+	itx_buf->flags |= MTK_TX_FLAGS_SINGLE0;
+	itx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 :
+			  MTK_TX_FLAGS_FPORT1;
+	setup_tx_buf(eth, itx_buf, itxd_pdma, mapped_addr, skb_headlen(skb),
+		     k++);
+
+	nr_frags = skb_shinfo(skb)->nr_frags;
+
+        qid = skb->mark & (MTK_QDMA_TX_MASK);
+
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+	if(!qid && mac->id)
+		qid = MTK_QDMA_GMAC2_QID;
+#endif
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+		/* set the forward port */
+		fport = (mac->id + 1) << TX_DMA_FPORT_SHIFT_V2;
+		txd4 |= fport;
+
+		if (gso)
+			txd5 |= TX_DMA_TSO_V2;
+
+		/* TX Checksum offload */
+		if (skb->ip_summed == CHECKSUM_PARTIAL)
+			txd5 |= TX_DMA_CHKSUM_V2;
+
+		/* VLAN header offload */
+		if (skb_vlan_tag_present(skb))
+			txd6 |= TX_DMA_INS_VLAN_V2 | skb_vlan_tag_get(skb);
+
+		txd4 = txd4 | TX_DMA_SWC_V2;
+	} else {
+		/* set the forward port */
+		fport = (mac->id + 1) << TX_DMA_FPORT_SHIFT;
+		txd4 |= fport;
+
+                if (gso)
+                        txd4 |= TX_DMA_TSO;
+
+                /* TX Checksum offload */
+                if (skb->ip_summed == CHECKSUM_PARTIAL)
+                        txd4 |= TX_DMA_CHKSUM;
+
+		/* VLAN header offload */
+		if (skb_vlan_tag_present(skb))
+			txd4 |= TX_DMA_INS_VLAN | skb_vlan_tag_get(skb);
+	}
+	/* TX SG offload */
+	txd = itxd;
+	txd_pdma = qdma_to_pdma(ring, txd);
+
+#if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE)
+	if (HNAT_SKB_CB2(skb)->magic == 0x78681415) {
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+			txd4 &= ~(0xf << TX_DMA_FPORT_SHIFT_V2);
+			txd4 |= 0x4 << TX_DMA_FPORT_SHIFT_V2;
+		} else {
+			txd4 &= ~(0x7 << TX_DMA_FPORT_SHIFT);
+			txd4 |= 0x4 << TX_DMA_FPORT_SHIFT;
+		}
+	}
+
+	trace_printk("[%s] nr_frags=%x HNAT_SKB_CB2(skb)->magic=%x txd4=%x<-----\n",
+		     __func__, nr_frags, HNAT_SKB_CB2(skb)->magic, txd4);
+#endif
+
+	for (i = 0; i < nr_frags; i++) {
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+		unsigned int offset = 0;
+		int frag_size = skb_frag_size(frag);
+
+		while (frag_size) {
+			bool last_frag = false;
+			unsigned int frag_map_size;
+			bool new_desc = true;
+
+			if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA) ||
+			    (i & 0x1)) {
+				txd = mtk_qdma_phys_to_virt(ring, txd->txd2);
+				txd_pdma = qdma_to_pdma(ring, txd);
+				if (txd == ring->last_free)
+					goto err_dma;
+
+				n_desc++;
+			} else {
+				new_desc = false;
+			}
+
+
+			frag_map_size = min(frag_size, MTK_TX_DMA_BUF_LEN);
+			mapped_addr = skb_frag_dma_map(eth->dev, frag, offset,
+						       frag_map_size,
+						       DMA_TO_DEVICE);
+			if (unlikely(dma_mapping_error(eth->dev, mapped_addr)))
+				goto err_dma;
+
+			if (i == nr_frags - 1 &&
+			    (frag_size - frag_map_size) == 0)
+				last_frag = true;
+
+			WRITE_ONCE(txd->txd1, mapped_addr);
+
+			if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+				WRITE_ONCE(txd->txd3, (TX_DMA_PLEN0(frag_map_size) |
+					   last_frag * TX_DMA_LS0));
+				WRITE_ONCE(txd->txd4, fport | TX_DMA_SWC_V2 |
+						      QID_BITS_V2(qid));
+			} else {
+				WRITE_ONCE(txd->txd3,
+					   (TX_DMA_SWC | QID_LOW_BITS(qid) |
+					    TX_DMA_PLEN0(frag_map_size) |
+					    last_frag * TX_DMA_LS0));
+				WRITE_ONCE(txd->txd4,
+					   fport | QID_HIGH_BITS(qid));
+			}
+
+			tx_buf = mtk_desc_to_tx_buf(ring, txd);
+			if (new_desc)
+				memset(tx_buf, 0, sizeof(*tx_buf));
+			tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC;
+			tx_buf->flags |= MTK_TX_FLAGS_PAGE0;
+			tx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 :
+					 MTK_TX_FLAGS_FPORT1;
+
+			setup_tx_buf(eth, tx_buf, txd_pdma, mapped_addr,
+				     frag_map_size, k++);
+
+			frag_size -= frag_map_size;
+			offset += frag_map_size;
+		}
+	}
+
+	/* store skb to cleanup */
+	itx_buf->skb = skb;
+
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+	WRITE_ONCE(itxd->txd5, txd5);
+	WRITE_ONCE(itxd->txd6, txd6);
+	WRITE_ONCE(itxd->txd7, 0);
+	WRITE_ONCE(itxd->txd8, 0);
+#endif
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+		WRITE_ONCE(itxd->txd4, txd4 | QID_BITS_V2(qid));
+		WRITE_ONCE(itxd->txd3, (TX_DMA_PLEN0(skb_headlen(skb)) |
+				(!nr_frags * TX_DMA_LS0)));
+	} else {
+		WRITE_ONCE(itxd->txd4, txd4 | QID_HIGH_BITS(qid));
+		WRITE_ONCE(itxd->txd3,
+			   TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) |
+			   (!nr_frags * TX_DMA_LS0) | QID_LOW_BITS(qid));
+	}
+
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
+		if (k & 0x1)
+			txd_pdma->txd2 |= TX_DMA_LS0;
+		else
+			txd_pdma->txd2 |= TX_DMA_LS1;
+	}
+
+	netdev_sent_queue(dev, skb->len);
+	skb_tx_timestamp(skb);
+
+	ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2);
+	atomic_sub(n_desc, &ring->free_count);
+
+	/* make sure that all changes to the dma ring are flushed before we
+	 * continue
+	 */
+	wmb();
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
+		if (netif_xmit_stopped(netdev_get_tx_queue(dev, 0)) ||
+		    !netdev_xmit_more())
+			mtk_w32(eth, txd->txd2, MTK_QTX_CTX_PTR);
+	} else {
+		int next_idx = NEXT_DESP_IDX(txd_to_idx(ring, txd),
+					     ring->dma_size);
+		mtk_w32(eth, next_idx, MT7628_TX_CTX_IDX0);
+	}
+
+	return 0;
+
+err_dma:
+	do {
+		tx_buf = mtk_desc_to_tx_buf(ring, itxd);
+
+		/* unmap dma */
+		mtk_tx_unmap(eth, tx_buf, false);
+
+		itxd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU;
+		if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
+			itxd_pdma->txd2 = TX_DMA_DESP2_DEF;
+
+		itxd = mtk_qdma_phys_to_virt(ring, itxd->txd2);
+		itxd_pdma = qdma_to_pdma(ring, itxd);
+	} while (itxd != txd);
+
+	return -ENOMEM;
+}
+
+static inline int mtk_cal_txd_req(struct sk_buff *skb)
+{
+	int i, nfrags;
+	skb_frag_t *frag;
+
+	nfrags = 1;
+	if (skb_is_gso(skb)) {
+		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+			frag = &skb_shinfo(skb)->frags[i];
+			nfrags += DIV_ROUND_UP(skb_frag_size(frag),
+						MTK_TX_DMA_BUF_LEN);
+		}
+	} else {
+		nfrags += skb_shinfo(skb)->nr_frags;
+	}
+
+	return nfrags;
+}
+
+static int mtk_queue_stopped(struct mtk_eth *eth)
+{
+	int i;
+
+	for (i = 0; i < MTK_MAC_COUNT; i++) {
+		if (!eth->netdev[i])
+			continue;
+		if (netif_queue_stopped(eth->netdev[i]))
+			return 1;
+	}
+
+	return 0;
+}
+
+static void mtk_wake_queue(struct mtk_eth *eth)
+{
+	int i;
+
+	for (i = 0; i < MTK_MAC_COUNT; i++) {
+		if (!eth->netdev[i])
+			continue;
+		netif_wake_queue(eth->netdev[i]);
+	}
+}
+
+static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	struct mtk_tx_ring *ring = &eth->tx_ring;
+	struct net_device_stats *stats = &dev->stats;
+	bool gso = false;
+	int tx_num;
+
+	/* normally we can rely on the stack not calling this more than once,
+	 * however we have 2 queues running on the same ring so we need to lock
+	 * the ring access
+	 */
+	spin_lock(&eth->page_lock);
+
+	if (unlikely(test_bit(MTK_RESETTING, &eth->state)))
+		goto drop;
+
+	tx_num = mtk_cal_txd_req(skb);
+	if (unlikely(atomic_read(&ring->free_count) <= tx_num)) {
+		netif_stop_queue(dev);
+		netif_err(eth, tx_queued, dev,
+			  "Tx Ring full when queue awake!\n");
+		spin_unlock(&eth->page_lock);
+		return NETDEV_TX_BUSY;
+	}
+
+	/* TSO: fill MSS info in tcp checksum field */
+	if (skb_is_gso(skb)) {
+		if (skb_cow_head(skb, 0)) {
+			netif_warn(eth, tx_err, dev,
+				   "GSO expand head fail.\n");
+			goto drop;
+		}
+
+		if (skb_shinfo(skb)->gso_type &
+				(SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
+			gso = true;
+			tcp_hdr(skb)->check = htons(skb_shinfo(skb)->gso_size);
+		}
+	}
+
+	if (mtk_tx_map(skb, dev, tx_num, ring, gso) < 0)
+		goto drop;
+
+	if (unlikely(atomic_read(&ring->free_count) <= ring->thresh))
+		netif_stop_queue(dev);
+
+	spin_unlock(&eth->page_lock);
+
+	return NETDEV_TX_OK;
+
+drop:
+	spin_unlock(&eth->page_lock);
+	stats->tx_dropped++;
+	dev_kfree_skb_any(skb);
+	return NETDEV_TX_OK;
+}
+
+static struct mtk_rx_ring *mtk_get_rx_ring(struct mtk_eth *eth)
+{
+	int i;
+	struct mtk_rx_ring *ring;
+	int idx;
+
+	for (i = 0; i < MTK_MAX_RX_RING_NUM; i++) {
+		if (!IS_NORMAL_RING(i) && !IS_HW_LRO_RING(i))
+			continue;
+
+		ring = &eth->rx_ring[i];
+		idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
+		if (ring->dma[idx].rxd2 & RX_DMA_DONE) {
+			ring->calc_idx_update = true;
+			return ring;
+		}
+	}
+
+	return NULL;
+}
+
+static void mtk_update_rx_cpu_idx(struct mtk_eth *eth, struct mtk_rx_ring *ring)
+{
+	int i;
+
+	if (!eth->hwlro)
+		mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
+	else {
+		for (i = 0; i < MTK_MAX_RX_RING_NUM; i++) {
+			ring = &eth->rx_ring[i];
+			if (ring->calc_idx_update) {
+				ring->calc_idx_update = false;
+				mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
+			}
+		}
+	}
+}
+
+static int mtk_poll_rx(struct napi_struct *napi, int budget,
+		       struct mtk_eth *eth)
+{
+	struct mtk_napi *rx_napi = container_of(napi, struct mtk_napi, napi);
+	struct mtk_rx_ring *ring = rx_napi->rx_ring;
+	int idx;
+	struct sk_buff *skb;
+	u8 *data, *new_data;
+	struct mtk_rx_dma *rxd, trxd;
+	int done = 0;
+
+	if (unlikely(!ring))
+		goto rx_done;
+
+	while (done < budget) {
+		struct net_device *netdev;
+		unsigned int pktlen;
+		dma_addr_t dma_addr;
+		int mac;
+
+		if (eth->hwlro)
+			ring = mtk_get_rx_ring(eth);
+
+		if (unlikely(!ring))
+			goto rx_done;
+
+		idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
+		rxd = &ring->dma[idx];
+		data = ring->data[idx];
+
+		if (!mtk_rx_get_desc(&trxd, rxd))
+			break;
+
+		/* find out which mac the packet come from. values start at 1 */
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) {
+			mac = 0;
+		} else {
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+			if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+				mac = RX_DMA_GET_SPORT(trxd.rxd5) - 1;
+			else
+#endif
+				mac = (trxd.rxd4 & RX_DMA_SPECIAL_TAG) ?
+				      0 : RX_DMA_GET_SPORT(trxd.rxd4) - 1;
+		}
+
+		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;
+
+		/* alloc new buffer */
+		new_data = napi_alloc_frag(ring->frag_size);
+		if (unlikely(!new_data)) {
+			netdev->stats.rx_dropped++;
+			goto release_desc;
+		}
+		dma_addr = dma_map_single(eth->dev,
+					  new_data + NET_SKB_PAD +
+					  eth->ip_align,
+					  ring->buf_size,
+					  DMA_FROM_DEVICE);
+		if (unlikely(dma_mapping_error(eth->dev, dma_addr))) {
+			skb_free_frag(new_data);
+			netdev->stats.rx_dropped++;
+			goto release_desc;
+		}
+
+		dma_unmap_single(eth->dev, trxd.rxd1,
+				 ring->buf_size, DMA_FROM_DEVICE);
+
+		/* receive data */
+		skb = build_skb(data, ring->frag_size);
+		if (unlikely(!skb)) {
+			skb_free_frag(data);
+			netdev->stats.rx_dropped++;
+			goto skip_rx;
+		}
+		skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
+
+		pktlen = RX_DMA_GET_PLEN0(trxd.rxd2);
+		skb->dev = netdev;
+		skb_put(skb, pktlen);
+
+		if ((!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) &&
+				  (trxd.rxd4 & eth->rx_dma_l4_valid)) ||
+		    (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) &&
+				  (trxd.rxd3 & eth->rx_dma_l4_valid)))
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+		else
+			skb_checksum_none_assert(skb);
+		skb->protocol = eth_type_trans(skb, netdev);
+
+		if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
+			if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+				if (trxd.rxd3 & RX_DMA_VTAG_V2)
+					__vlan_hwaccel_put_tag(skb,
+					htons(RX_DMA_VPID_V2(trxd.rxd4)),
+					RX_DMA_VID_V2(trxd.rxd4));
+			} else {
+				if (trxd.rxd2 & RX_DMA_VTAG)
+					__vlan_hwaccel_put_tag(skb,
+					htons(RX_DMA_VPID(trxd.rxd3)),
+					RX_DMA_VID(trxd.rxd3));
+			}
+
+			/* If netdev is attached to dsa switch, the special
+			 * tag inserted in VLAN field by switch hardware can
+			 * be offload by RX HW VLAN offload. Clears the VLAN
+			 * information from @skb to avoid unexpected 8021d
+			 * handler before packet enter dsa framework.
+			 */
+			if (netdev_uses_dsa(netdev))
+				__vlan_hwaccel_clear_tag(skb);
+		}
+
+#if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE)
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+			*(u32 *)(skb->head) = trxd.rxd5;
+		else
+#endif
+			*(u32 *)(skb->head) = trxd.rxd4;
+
+		skb_hnat_alg(skb) = 0;
+		skb_hnat_filled(skb) = 0;
+		skb_hnat_magic_tag(skb) = HNAT_MAGIC_TAG;
+
+		if (skb_hnat_reason(skb) == HIT_BIND_FORCE_TO_CPU) {
+			trace_printk("[%s] reason=0x%x(force to CPU) from WAN to Ext\n",
+				     __func__, skb_hnat_reason(skb));
+			skb->pkt_type = PACKET_HOST;
+		}
+
+		trace_printk("[%s] rxd:(entry=%x,sport=%x,reason=%x,alg=%x\n",
+			     __func__, skb_hnat_entry(skb), skb_hnat_sport(skb),
+			     skb_hnat_reason(skb), skb_hnat_alg(skb));
+#endif
+		if (mtk_hwlro_stats_ebl &&
+		    IS_HW_LRO_RING(ring->ring_no) && eth->hwlro) {
+			hw_lro_stats_update(ring->ring_no, &trxd);
+			hw_lro_flush_stats_update(ring->ring_no, &trxd);
+		}
+
+		skb_record_rx_queue(skb, 0);
+		napi_gro_receive(napi, skb);
+
+skip_rx:
+		ring->data[idx] = new_data;
+		rxd->rxd1 = (unsigned int)dma_addr;
+
+release_desc:
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628))
+			rxd->rxd2 = RX_DMA_LSO;
+		else
+			rxd->rxd2 = RX_DMA_PLEN0(ring->buf_size);
+
+		ring->calc_idx = idx;
+
+		done++;
+	}
+
+rx_done:
+	if (done) {
+		/* make sure that all changes to the dma ring are flushed before
+		 * we continue
+		 */
+		wmb();
+		mtk_update_rx_cpu_idx(eth, ring);
+	}
+
+	return done;
+}
+
+static void mtk_poll_tx_qdma(struct mtk_eth *eth, int budget,
+			    unsigned int *done, unsigned int *bytes)
+{
+	struct mtk_tx_ring *ring = &eth->tx_ring;
+	struct mtk_tx_dma *desc;
+	struct sk_buff *skb;
+	struct mtk_tx_buf *tx_buf;
+	u32 cpu, dma;
+
+	cpu = ring->last_free_ptr;
+	dma = mtk_r32(eth, MTK_QTX_DRX_PTR);
+
+	desc = mtk_qdma_phys_to_virt(ring, cpu);
+
+	while ((cpu != dma) && budget) {
+		u32 next_cpu = desc->txd2;
+		int mac = 0;
+
+		if ((desc->txd3 & TX_DMA_OWNER_CPU) == 0)
+			break;
+
+		desc = mtk_qdma_phys_to_virt(ring, desc->txd2);
+
+		tx_buf = mtk_desc_to_tx_buf(ring, desc);
+		if (tx_buf->flags & MTK_TX_FLAGS_FPORT1)
+			mac = 1;
+
+		skb = tx_buf->skb;
+		if (!skb)
+			break;
+
+		if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) {
+			bytes[mac] += skb->len;
+			done[mac]++;
+			budget--;
+		}
+		mtk_tx_unmap(eth, tx_buf, true);
+
+		ring->last_free = desc;
+		atomic_inc(&ring->free_count);
+
+		cpu = next_cpu;
+	}
+
+	ring->last_free_ptr = cpu;
+	mtk_w32(eth, cpu, MTK_QTX_CRX_PTR);
+}
+
+static void mtk_poll_tx_pdma(struct mtk_eth *eth, int budget,
+			    unsigned int *done, unsigned int *bytes)
+{
+	struct mtk_tx_ring *ring = &eth->tx_ring;
+	struct mtk_tx_dma *desc;
+	struct sk_buff *skb;
+	struct mtk_tx_buf *tx_buf;
+	u32 cpu, dma;
+
+	cpu = ring->cpu_idx;
+	dma = mtk_r32(eth, MT7628_TX_DTX_IDX0);
+
+	while ((cpu != dma) && budget) {
+		tx_buf = &ring->buf[cpu];
+		skb = tx_buf->skb;
+		if (!skb)
+			break;
+
+		if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) {
+			bytes[0] += skb->len;
+			done[0]++;
+			budget--;
+		}
+
+		mtk_tx_unmap(eth, tx_buf, true);
+
+		desc = &ring->dma[cpu];
+		ring->last_free = desc;
+		atomic_inc(&ring->free_count);
+
+		cpu = NEXT_DESP_IDX(cpu, ring->dma_size);
+	}
+
+	ring->cpu_idx = cpu;
+}
+
+static int mtk_poll_tx(struct mtk_eth *eth, int budget)
+{
+	struct mtk_tx_ring *ring = &eth->tx_ring;
+	unsigned int done[MTK_MAX_DEVS];
+	unsigned int bytes[MTK_MAX_DEVS];
+	int total = 0, i;
+
+	memset(done, 0, sizeof(done));
+	memset(bytes, 0, sizeof(bytes));
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
+		mtk_poll_tx_qdma(eth, budget, done, bytes);
+	else
+		mtk_poll_tx_pdma(eth, budget, done, bytes);
+
+	for (i = 0; i < MTK_MAC_COUNT; i++) {
+		if (!eth->netdev[i] || !done[i])
+			continue;
+		netdev_completed_queue(eth->netdev[i], done[i], bytes[i]);
+		total += done[i];
+	}
+
+	if (mtk_queue_stopped(eth) &&
+	    (atomic_read(&ring->free_count) > ring->thresh))
+		mtk_wake_queue(eth);
+
+	return total;
+}
+
+static void mtk_handle_status_irq(struct mtk_eth *eth)
+{
+	u32 status2 = mtk_r32(eth, MTK_INT_STATUS);
+
+	if (unlikely(status2 & (MTK_GDM1_AF | MTK_GDM2_AF))) {
+		mtk_stats_update(eth);
+		mtk_w32(eth, (MTK_GDM1_AF | MTK_GDM2_AF),
+			MTK_INT_STATUS);
+	}
+}
+
+static int mtk_napi_tx(struct napi_struct *napi, int budget)
+{
+	struct mtk_eth *eth = container_of(napi, struct mtk_eth, tx_napi);
+	u32 status, mask;
+	int tx_done = 0;
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
+		mtk_handle_status_irq(eth);
+	mtk_w32(eth, MTK_TX_DONE_INT, eth->tx_int_status_reg);
+	tx_done = mtk_poll_tx(eth, budget);
+
+	if (unlikely(netif_msg_intr(eth))) {
+		status = mtk_r32(eth, eth->tx_int_status_reg);
+		mask = mtk_r32(eth, eth->tx_int_mask_reg);
+		dev_info(eth->dev,
+			 "done tx %d, intr 0x%08x/0x%x\n",
+			 tx_done, status, mask);
+	}
+
+	if (tx_done == budget)
+		return budget;
+
+	status = mtk_r32(eth, eth->tx_int_status_reg);
+	if (status & MTK_TX_DONE_INT)
+		return budget;
+
+	if (napi_complete(napi))
+		mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
+
+	return tx_done;
+}
+
+static int mtk_napi_rx(struct napi_struct *napi, int budget)
+{
+	struct mtk_napi *rx_napi = container_of(napi, struct mtk_napi, napi);
+	struct mtk_eth *eth = rx_napi->eth;
+	struct mtk_rx_ring *ring = rx_napi->rx_ring;
+	u32 status, mask;
+	int rx_done = 0;
+	int remain_budget = budget;
+
+	mtk_handle_status_irq(eth);
+
+poll_again:
+	mtk_w32(eth, MTK_RX_DONE_INT(ring->ring_no), MTK_PDMA_INT_STATUS);
+	rx_done = mtk_poll_rx(napi, remain_budget, eth);
+
+	if (unlikely(netif_msg_intr(eth))) {
+		status = mtk_r32(eth, MTK_PDMA_INT_STATUS);
+		mask = mtk_r32(eth, MTK_PDMA_INT_MASK);
+		dev_info(eth->dev,
+			 "done rx %d, intr 0x%08x/0x%x\n",
+			 rx_done, status, mask);
+	}
+	if (rx_done == remain_budget)
+		return budget;
+
+	status = mtk_r32(eth, MTK_PDMA_INT_STATUS);
+	if (status & MTK_RX_DONE_INT(ring->ring_no)) {
+		remain_budget -= rx_done;
+		goto poll_again;
+	}
+
+	if (napi_complete(napi))
+		mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(ring->ring_no));
+
+	return rx_done + budget - remain_budget;
+}
+
+static int mtk_tx_alloc(struct mtk_eth *eth)
+{
+	struct mtk_tx_ring *ring = &eth->tx_ring;
+	int i, sz = sizeof(*ring->dma);
+
+	ring->buf = kcalloc(MTK_DMA_SIZE, sizeof(*ring->buf),
+			       GFP_KERNEL);
+	if (!ring->buf)
+		goto no_tx_mem;
+
+	if (!eth->soc->has_sram)
+		ring->dma = dma_alloc_coherent(eth->dev, MTK_DMA_SIZE * sz,
+					       &ring->phys, GFP_ATOMIC);
+	else {
+		ring->dma =  eth->scratch_ring + MTK_DMA_SIZE;
+		ring->phys = eth->phy_scratch_ring + MTK_DMA_SIZE * sz;
+	}
+
+	if (!ring->dma)
+		goto no_tx_mem;
+
+	for (i = 0; i < MTK_DMA_SIZE; i++) {
+		int next = (i + 1) % MTK_DMA_SIZE;
+		u32 next_ptr = ring->phys + next * sz;
+
+		ring->dma[i].txd2 = next_ptr;
+		ring->dma[i].txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU;
+		ring->dma[i].txd4 = 0;
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+                if (eth->soc->has_sram && ( sz > 16)) {
+                        ring->dma[i].txd5 = 0;
+                        ring->dma[i].txd6 = 0;
+                        ring->dma[i].txd7 = 0;
+                        ring->dma[i].txd8 = 0;
+                }
+#endif
+	}
+
+	/* On MT7688 (PDMA only) this driver uses the ring->dma structs
+	 * only as the framework. The real HW descriptors are the PDMA
+	 * descriptors in ring->dma_pdma.
+	 */
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
+		ring->dma_pdma = dma_alloc_coherent(eth->dev, MTK_DMA_SIZE * sz,
+						    &ring->phys_pdma,
+						    GFP_ATOMIC);
+		if (!ring->dma_pdma)
+			goto no_tx_mem;
+
+		for (i = 0; i < MTK_DMA_SIZE; i++) {
+			ring->dma_pdma[i].txd2 = TX_DMA_DESP2_DEF;
+			ring->dma_pdma[i].txd4 = 0;
+		}
+	}
+
+	ring->dma_size = MTK_DMA_SIZE;
+	atomic_set(&ring->free_count, MTK_DMA_SIZE - 2);
+	ring->next_free = &ring->dma[0];
+	ring->last_free = &ring->dma[MTK_DMA_SIZE - 1];
+	ring->last_free_ptr = (u32)(ring->phys + ((MTK_DMA_SIZE - 1) * sz));
+	ring->thresh = MAX_SKB_FRAGS;
+
+	/* make sure that all changes to the dma ring are flushed before we
+	 * continue
+	 */
+	wmb();
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
+		mtk_w32(eth, ring->phys, MTK_QTX_CTX_PTR);
+		mtk_w32(eth, ring->phys, MTK_QTX_DTX_PTR);
+		mtk_w32(eth,
+			ring->phys + ((MTK_DMA_SIZE - 1) * sz),
+			MTK_QTX_CRX_PTR);
+		mtk_w32(eth, ring->last_free_ptr, MTK_QTX_DRX_PTR);
+		mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES,
+			MTK_QTX_CFG(0));
+	} else {
+		mtk_w32(eth, ring->phys_pdma, MT7628_TX_BASE_PTR0);
+		mtk_w32(eth, MTK_DMA_SIZE, MT7628_TX_MAX_CNT0);
+		mtk_w32(eth, 0, MT7628_TX_CTX_IDX0);
+		mtk_w32(eth, MT7628_PST_DTX_IDX0, MTK_PDMA_RST_IDX);
+	}
+
+	return 0;
+
+no_tx_mem:
+	return -ENOMEM;
+}
+
+static void mtk_tx_clean(struct mtk_eth *eth)
+{
+	struct mtk_tx_ring *ring = &eth->tx_ring;
+	int i;
+
+	if (ring->buf) {
+		for (i = 0; i < MTK_DMA_SIZE; i++)
+			mtk_tx_unmap(eth, &ring->buf[i], false);
+		kfree(ring->buf);
+		ring->buf = NULL;
+	}
+
+	if (!eth->soc->has_sram && ring->dma) {
+		dma_free_coherent(eth->dev,
+				  MTK_DMA_SIZE * sizeof(*ring->dma),
+				  ring->dma,
+				  ring->phys);
+		ring->dma = NULL;
+	}
+
+	if (ring->dma_pdma) {
+		dma_free_coherent(eth->dev,
+				  MTK_DMA_SIZE * sizeof(*ring->dma_pdma),
+				  ring->dma_pdma,
+				  ring->phys_pdma);
+		ring->dma_pdma = NULL;
+	}
+}
+
+static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
+{
+	struct mtk_rx_ring *ring;
+	int rx_data_len, rx_dma_size;
+	int i;
+
+	if (rx_flag == MTK_RX_FLAGS_QDMA) {
+		if (ring_no)
+			return -EINVAL;
+		ring = &eth->rx_ring_qdma;
+	} else {
+		ring = &eth->rx_ring[ring_no];
+	}
+
+	if (rx_flag == MTK_RX_FLAGS_HWLRO) {
+		rx_data_len = MTK_MAX_LRO_RX_LENGTH;
+		rx_dma_size = MTK_HW_LRO_DMA_SIZE;
+	} else {
+		rx_data_len = ETH_DATA_LEN;
+		rx_dma_size = MTK_DMA_SIZE;
+	}
+
+	ring->frag_size = mtk_max_frag_size(rx_data_len);
+	ring->buf_size = mtk_max_buf_size(ring->frag_size);
+	ring->data = kcalloc(rx_dma_size, sizeof(*ring->data),
+			     GFP_KERNEL);
+	if (!ring->data)
+		return -ENOMEM;
+
+	for (i = 0; i < rx_dma_size; i++) {
+		ring->data[i] = netdev_alloc_frag(ring->frag_size);
+		if (!ring->data[i])
+			return -ENOMEM;
+	}
+
+	if ((!eth->soc->has_sram) || (eth->soc->has_sram
+				&& (rx_flag != MTK_RX_FLAGS_NORMAL)))
+		ring->dma = dma_alloc_coherent(eth->dev,
+					       rx_dma_size * sizeof(*ring->dma),
+					       &ring->phys, GFP_ATOMIC);
+	else {
+		struct mtk_tx_ring *tx_ring = &eth->tx_ring;
+		ring->dma = (struct mtk_rx_dma *)(tx_ring->dma +
+			     MTK_DMA_SIZE * (ring_no + 1));
+		ring->phys = tx_ring->phys + MTK_DMA_SIZE *
+			     sizeof(*tx_ring->dma) * (ring_no + 1);
+	}
+
+	if (!ring->dma)
+		return -ENOMEM;
+
+	for (i = 0; i < rx_dma_size; i++) {
+		dma_addr_t dma_addr = dma_map_single(eth->dev,
+				ring->data[i] + NET_SKB_PAD + eth->ip_align,
+				ring->buf_size,
+				DMA_FROM_DEVICE);
+		if (unlikely(dma_mapping_error(eth->dev, dma_addr)))
+			return -ENOMEM;
+		ring->dma[i].rxd1 = (unsigned int)dma_addr;
+
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628))
+			ring->dma[i].rxd2 = RX_DMA_LSO;
+		else
+			ring->dma[i].rxd2 = RX_DMA_PLEN0(ring->buf_size);
+
+		ring->dma[i].rxd3 = 0;
+		ring->dma[i].rxd4 = 0;
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+		if (eth->soc->has_sram && ((sizeof(struct mtk_rx_dma)) > 16)) {
+			ring->dma[i].rxd5 = 0;
+			ring->dma[i].rxd6 = 0;
+			ring->dma[i].rxd7 = 0;
+			ring->dma[i].rxd8 = 0;
+		}
+#endif
+	}
+	ring->dma_size = rx_dma_size;
+	ring->calc_idx_update = false;
+	ring->calc_idx = rx_dma_size - 1;
+	ring->crx_idx_reg = (rx_flag == MTK_RX_FLAGS_QDMA) ?
+			     MTK_QRX_CRX_IDX_CFG(ring_no) :
+			     MTK_PRX_CRX_IDX_CFG(ring_no);
+	ring->ring_no = ring_no;
+	/* make sure that all changes to the dma ring are flushed before we
+	 * continue
+	 */
+	wmb();
+
+	if (rx_flag == MTK_RX_FLAGS_QDMA) {
+		mtk_w32(eth, ring->phys, MTK_QRX_BASE_PTR_CFG(ring_no));
+		mtk_w32(eth, rx_dma_size, MTK_QRX_MAX_CNT_CFG(ring_no));
+		mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
+		mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), MTK_QDMA_RST_IDX);
+	} else {
+		mtk_w32(eth, ring->phys, MTK_PRX_BASE_PTR_CFG(ring_no));
+		mtk_w32(eth, rx_dma_size, MTK_PRX_MAX_CNT_CFG(ring_no));
+		mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg);
+		mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), MTK_PDMA_RST_IDX);
+	}
+
+	return 0;
+}
+
+static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring, int in_sram)
+{
+	int i;
+
+	if (ring->data && ring->dma) {
+		for (i = 0; i < ring->dma_size; i++) {
+			if (!ring->data[i])
+				continue;
+			if (!ring->dma[i].rxd1)
+				continue;
+			dma_unmap_single(eth->dev,
+					 ring->dma[i].rxd1,
+					 ring->buf_size,
+					 DMA_FROM_DEVICE);
+			skb_free_frag(ring->data[i]);
+		}
+		kfree(ring->data);
+		ring->data = NULL;
+	}
+
+	if(in_sram)
+		return;
+
+	if (ring->dma) {
+		dma_free_coherent(eth->dev,
+				  ring->dma_size * sizeof(*ring->dma),
+				  ring->dma,
+				  ring->phys);
+		ring->dma = NULL;
+	}
+}
+
+static int mtk_hwlro_rx_init(struct mtk_eth *eth)
+{
+	int i;
+	u32 val;
+	u32 ring_ctrl_dw1 = 0, ring_ctrl_dw2 = 0, ring_ctrl_dw3 = 0;
+	u32 lro_ctrl_dw0 = 0, lro_ctrl_dw3 = 0;
+
+	/* set LRO rings to auto-learn modes */
+	ring_ctrl_dw2 |= MTK_RING_AUTO_LERAN_MODE;
+
+	/* validate LRO ring */
+	ring_ctrl_dw2 |= MTK_RING_VLD;
+
+	/* set AGE timer (unit: 20us) */
+	ring_ctrl_dw2 |= MTK_RING_AGE_TIME_H;
+	ring_ctrl_dw1 |= MTK_RING_AGE_TIME_L;
+
+	/* set max AGG timer (unit: 20us) */
+	ring_ctrl_dw2 |= MTK_RING_MAX_AGG_TIME;
+
+	/* set max LRO AGG count */
+	ring_ctrl_dw2 |= MTK_RING_MAX_AGG_CNT_L;
+	ring_ctrl_dw3 |= MTK_RING_MAX_AGG_CNT_H;
+
+	for (i = 1; i <= MTK_HW_LRO_RING_NUM; i++) {
+		mtk_w32(eth, ring_ctrl_dw1, MTK_LRO_CTRL_DW1_CFG(i));
+		mtk_w32(eth, ring_ctrl_dw2, MTK_LRO_CTRL_DW2_CFG(i));
+		mtk_w32(eth, ring_ctrl_dw3, MTK_LRO_CTRL_DW3_CFG(i));
+	}
+
+	/* IPv4 checksum update enable */
+	lro_ctrl_dw0 |= MTK_L3_CKS_UPD_EN;
+
+	/* switch priority comparison to packet count mode */
+	lro_ctrl_dw0 |= MTK_LRO_ALT_PKT_CNT_MODE;
+
+	/* bandwidth threshold setting */
+	mtk_w32(eth, MTK_HW_LRO_BW_THRE, MTK_PDMA_LRO_CTRL_DW2);
+
+	/* auto-learn score delta setting */
+	mtk_w32(eth, MTK_HW_LRO_REPLACE_DELTA, MTK_LRO_ALT_SCORE_DELTA);
+
+	/* set refresh timer for altering flows to 1 sec. (unit: 20us) */
+	mtk_w32(eth, (MTK_HW_LRO_TIMER_UNIT << 16) | MTK_HW_LRO_REFRESH_TIME,
+		MTK_PDMA_LRO_ALT_REFRESH_TIMER);
+
+	/* the minimal remaining room of SDL0 in RXD for lro aggregation */
+	lro_ctrl_dw3 |= MTK_LRO_MIN_RXD_SDL;
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+		val = mtk_r32(eth, MTK_PDMA_RX_CFG);
+		mtk_w32(eth, val | (MTK_PDMA_LRO_SDL << MTK_RX_CFG_SDL_OFFSET),
+			MTK_PDMA_RX_CFG);
+
+		lro_ctrl_dw0 |= MTK_PDMA_LRO_SDL << MTK_CTRL_DW0_SDL_OFFSET;
+	} else {
+		/* set HW LRO mode & the max aggregation count for rx packets */
+		lro_ctrl_dw3 |= MTK_ADMA_MODE | (MTK_HW_LRO_MAX_AGG_CNT & 0xff);
+	}
+
+	/* enable HW LRO */
+	lro_ctrl_dw0 |= MTK_LRO_EN;
+
+	/* enable cpu reason black list */
+	lro_ctrl_dw0 |= MTK_LRO_CRSN_BNW;
+
+	mtk_w32(eth, lro_ctrl_dw3, MTK_PDMA_LRO_CTRL_DW3);
+	mtk_w32(eth, lro_ctrl_dw0, MTK_PDMA_LRO_CTRL_DW0);
+
+	/* no use PPE cpu reason */
+	mtk_w32(eth, 0xffffffff, MTK_PDMA_LRO_CTRL_DW1);
+
+	return 0;
+}
+
+static void mtk_hwlro_rx_uninit(struct mtk_eth *eth)
+{
+	int i;
+	u32 val;
+
+	/* relinquish lro rings, flush aggregated packets */
+	mtk_w32(eth, MTK_LRO_RING_RELINGUISH_REQ, MTK_PDMA_LRO_CTRL_DW0);
+
+	/* wait for relinquishments done */
+	for (i = 0; i < 10; i++) {
+		val = mtk_r32(eth, MTK_PDMA_LRO_CTRL_DW0);
+		if (val & MTK_LRO_RING_RELINGUISH_DONE) {
+			msleep(20);
+			continue;
+		}
+		break;
+	}
+
+	/* invalidate lro rings */
+	for (i = 1; i <= MTK_HW_LRO_RING_NUM; i++)
+		mtk_w32(eth, 0, MTK_LRO_CTRL_DW2_CFG(i));
+
+	/* disable HW LRO */
+	mtk_w32(eth, 0, MTK_PDMA_LRO_CTRL_DW0);
+}
+
+static void mtk_hwlro_val_ipaddr(struct mtk_eth *eth, int idx, __be32 ip)
+{
+	u32 reg_val;
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+		idx += 1;
+
+	reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(idx));
+
+	/* invalidate the IP setting */
+	mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(idx));
+
+	mtk_w32(eth, ip, MTK_LRO_DIP_DW0_CFG(idx));
+
+	/* validate the IP setting */
+	mtk_w32(eth, (reg_val | MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(idx));
+}
+
+static void mtk_hwlro_inval_ipaddr(struct mtk_eth *eth, int idx)
+{
+	u32 reg_val;
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+		idx += 1;
+
+	reg_val = mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(idx));
+
+	/* invalidate the IP setting */
+	mtk_w32(eth, (reg_val & ~MTK_RING_MYIP_VLD), MTK_LRO_CTRL_DW2_CFG(idx));
+
+	mtk_w32(eth, 0, MTK_LRO_DIP_DW0_CFG(idx));
+}
+
+static int mtk_hwlro_get_ip_cnt(struct mtk_mac *mac)
+{
+	int cnt = 0;
+	int i;
+
+	for (i = 0; i < MTK_MAX_LRO_IP_CNT; i++) {
+		if (mac->hwlro_ip[i])
+			cnt++;
+	}
+
+	return cnt;
+}
+
+static int mtk_hwlro_add_ipaddr(struct net_device *dev,
+				struct ethtool_rxnfc *cmd)
+{
+	struct ethtool_rx_flow_spec *fsp =
+		(struct ethtool_rx_flow_spec *)&cmd->fs;
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	int hwlro_idx;
+
+	if ((fsp->flow_type != TCP_V4_FLOW) ||
+	    (!fsp->h_u.tcp_ip4_spec.ip4dst) ||
+	    (fsp->location > 1))
+		return -EINVAL;
+
+	mac->hwlro_ip[fsp->location] = htonl(fsp->h_u.tcp_ip4_spec.ip4dst);
+	hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + fsp->location;
+
+	mac->hwlro_ip_cnt = mtk_hwlro_get_ip_cnt(mac);
+
+	mtk_hwlro_val_ipaddr(eth, hwlro_idx, mac->hwlro_ip[fsp->location]);
+
+	return 0;
+}
+
+static int mtk_hwlro_del_ipaddr(struct net_device *dev,
+				struct ethtool_rxnfc *cmd)
+{
+	struct ethtool_rx_flow_spec *fsp =
+		(struct ethtool_rx_flow_spec *)&cmd->fs;
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	int hwlro_idx;
+
+	if (fsp->location > 1)
+		return -EINVAL;
+
+	mac->hwlro_ip[fsp->location] = 0;
+	hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + fsp->location;
+
+	mac->hwlro_ip_cnt = mtk_hwlro_get_ip_cnt(mac);
+
+	mtk_hwlro_inval_ipaddr(eth, hwlro_idx);
+
+	return 0;
+}
+
+static void mtk_hwlro_netdev_disable(struct net_device *dev)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	int i, hwlro_idx;
+
+	for (i = 0; i < MTK_MAX_LRO_IP_CNT; i++) {
+		mac->hwlro_ip[i] = 0;
+		hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + i;
+
+		mtk_hwlro_inval_ipaddr(eth, hwlro_idx);
+	}
+
+	mac->hwlro_ip_cnt = 0;
+}
+
+static int mtk_hwlro_get_fdir_entry(struct net_device *dev,
+				    struct ethtool_rxnfc *cmd)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct ethtool_rx_flow_spec *fsp =
+		(struct ethtool_rx_flow_spec *)&cmd->fs;
+
+	/* only tcp dst ipv4 is meaningful, others are meaningless */
+	fsp->flow_type = TCP_V4_FLOW;
+	fsp->h_u.tcp_ip4_spec.ip4dst = ntohl(mac->hwlro_ip[fsp->location]);
+	fsp->m_u.tcp_ip4_spec.ip4dst = 0;
+
+	fsp->h_u.tcp_ip4_spec.ip4src = 0;
+	fsp->m_u.tcp_ip4_spec.ip4src = 0xffffffff;
+	fsp->h_u.tcp_ip4_spec.psrc = 0;
+	fsp->m_u.tcp_ip4_spec.psrc = 0xffff;
+	fsp->h_u.tcp_ip4_spec.pdst = 0;
+	fsp->m_u.tcp_ip4_spec.pdst = 0xffff;
+	fsp->h_u.tcp_ip4_spec.tos = 0;
+	fsp->m_u.tcp_ip4_spec.tos = 0xff;
+
+	return 0;
+}
+
+static int mtk_hwlro_get_fdir_all(struct net_device *dev,
+				  struct ethtool_rxnfc *cmd,
+				  u32 *rule_locs)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	int cnt = 0;
+	int i;
+
+	for (i = 0; i < MTK_MAX_LRO_IP_CNT; i++) {
+		if (mac->hwlro_ip[i]) {
+			rule_locs[cnt] = i;
+			cnt++;
+		}
+	}
+
+	cmd->rule_cnt = cnt;
+
+	return 0;
+}
+
+static int mtk_rss_init(struct mtk_eth *eth)
+{
+	u32 val;
+
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+		/* Set RSS rings to PSE modes */
+		val =  mtk_r32(eth, MTK_LRO_CTRL_DW2_CFG(1));
+		val |= MTK_RING_PSE_MODE;
+		mtk_w32(eth, val, MTK_LRO_CTRL_DW2_CFG(1));
+
+		/* Enable non-lro multiple rx */
+		val = mtk_r32(eth, MTK_PDMA_LRO_CTRL_DW0);
+		val |= MTK_NON_LRO_MULTI_EN;
+		mtk_w32(eth, val, MTK_PDMA_LRO_CTRL_DW0);
+
+		/* Enable RSS dly int supoort */
+		val |= MTK_LRO_DLY_INT_EN;
+		mtk_w32(eth, val, MTK_PDMA_LRO_CTRL_DW0);
+
+		/* Set RSS delay config int ring1 */
+		mtk_w32(eth, MTK_MAX_DELAY_INT, MTK_LRO_RX1_DLY_INT);
+	}
+
+	/* Hash Type */
+	val = mtk_r32(eth, MTK_PDMA_RSS_GLO_CFG);
+	val |= MTK_RSS_IPV4_STATIC_HASH;
+	val |= MTK_RSS_IPV6_STATIC_HASH;
+	mtk_w32(eth, val, MTK_PDMA_RSS_GLO_CFG);
+
+	/* Select the size of indirection table */
+	mtk_w32(eth, MTK_RSS_INDR_TABLE_SIZE4, MTK_RSS_INDR_TABLE_DW0);
+	mtk_w32(eth, MTK_RSS_INDR_TABLE_SIZE4, MTK_RSS_INDR_TABLE_DW1);
+	mtk_w32(eth, MTK_RSS_INDR_TABLE_SIZE4, MTK_RSS_INDR_TABLE_DW2);
+	mtk_w32(eth, MTK_RSS_INDR_TABLE_SIZE4, MTK_RSS_INDR_TABLE_DW3);
+	mtk_w32(eth, MTK_RSS_INDR_TABLE_SIZE4, MTK_RSS_INDR_TABLE_DW4);
+	mtk_w32(eth, MTK_RSS_INDR_TABLE_SIZE4, MTK_RSS_INDR_TABLE_DW5);
+	mtk_w32(eth, MTK_RSS_INDR_TABLE_SIZE4, MTK_RSS_INDR_TABLE_DW6);
+	mtk_w32(eth, MTK_RSS_INDR_TABLE_SIZE4, MTK_RSS_INDR_TABLE_DW7);
+
+	/* Pause */
+	val |= MTK_RSS_CFG_REQ;
+	mtk_w32(eth, val, MTK_PDMA_RSS_GLO_CFG);
+
+	/* Enable RSS*/
+	val |= MTK_RSS_EN;
+	mtk_w32(eth, val, MTK_PDMA_RSS_GLO_CFG);
+
+	/* Release pause */
+	val &= ~(MTK_RSS_CFG_REQ);
+	mtk_w32(eth, val, MTK_PDMA_RSS_GLO_CFG);
+
+	/* Set perRSS GRP INT */
+	mtk_w32(eth, MTK_RX_DONE_INT(MTK_RSS_RING1), MTK_PDMA_INT_GRP3);
+
+	/* Set GRP INT */
+	mtk_w32(eth, 0x21021030, MTK_FE_INT_GRP);
+
+	return 0;
+}
+
+static void mtk_rss_uninit(struct mtk_eth *eth)
+{
+	u32 val;
+
+	/* Pause */
+	val = mtk_r32(eth, MTK_PDMA_RSS_GLO_CFG);
+	val |= MTK_RSS_CFG_REQ;
+	mtk_w32(eth, val, MTK_PDMA_RSS_GLO_CFG);
+
+	/* Disable RSS*/
+	val &= ~(MTK_RSS_EN);
+	mtk_w32(eth, val, MTK_PDMA_RSS_GLO_CFG);
+
+	/* Release pause */
+	val &= ~(MTK_RSS_CFG_REQ);
+	mtk_w32(eth, val, MTK_PDMA_RSS_GLO_CFG);
+}
+
+static netdev_features_t mtk_fix_features(struct net_device *dev,
+					  netdev_features_t features)
+{
+	if (!(features & NETIF_F_LRO)) {
+		struct mtk_mac *mac = netdev_priv(dev);
+		int ip_cnt = mtk_hwlro_get_ip_cnt(mac);
+
+		if (ip_cnt) {
+			netdev_info(dev, "RX flow is programmed, LRO should keep on\n");
+
+			features |= NETIF_F_LRO;
+		}
+	}
+
+	if ((features & NETIF_F_HW_VLAN_CTAG_TX) && netdev_uses_dsa(dev)) {
+		netdev_info(dev, "TX vlan offload cannot be enabled when dsa is attached.\n");
+
+		features &= ~NETIF_F_HW_VLAN_CTAG_TX;
+	}
+
+	return features;
+}
+
+static int mtk_set_features(struct net_device *dev, netdev_features_t features)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	int err = 0;
+
+	if (!((dev->features ^ features) & MTK_SET_FEATURES))
+		return 0;
+
+	if (!(features & NETIF_F_LRO))
+		mtk_hwlro_netdev_disable(dev);
+
+	if (!(features & NETIF_F_HW_VLAN_CTAG_RX))
+		mtk_w32(eth, 0, MTK_CDMP_EG_CTRL);
+	else
+		mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
+
+	return err;
+}
+
+/* wait for DMA to finish whatever it is doing before we start using it again */
+static int mtk_dma_busy_wait(struct mtk_eth *eth)
+{
+	unsigned long t_start = jiffies;
+
+	while (1) {
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
+			if (!(mtk_r32(eth, MTK_QDMA_GLO_CFG) &
+			      (MTK_RX_DMA_BUSY | MTK_TX_DMA_BUSY)))
+				return 0;
+		} else {
+			if (!(mtk_r32(eth, MTK_PDMA_GLO_CFG) &
+			      (MTK_RX_DMA_BUSY | MTK_TX_DMA_BUSY)))
+				return 0;
+		}
+
+		if (time_after(jiffies, t_start + MTK_DMA_BUSY_TIMEOUT))
+			break;
+	}
+
+	dev_err(eth->dev, "DMA init timeout\n");
+	return -1;
+}
+
+static int mtk_dma_init(struct mtk_eth *eth)
+{
+	int err;
+	u32 i;
+
+	if (mtk_dma_busy_wait(eth))
+		return -EBUSY;
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
+		/* QDMA needs scratch memory for internal reordering of the
+		 * descriptors
+		 */
+		err = mtk_init_fq_dma(eth);
+		if (err)
+			return err;
+	}
+
+	err = mtk_tx_alloc(eth);
+	if (err)
+		return err;
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
+		err = mtk_rx_alloc(eth, 0, MTK_RX_FLAGS_QDMA);
+		if (err)
+			return err;
+	}
+
+	err = mtk_rx_alloc(eth, 0, MTK_RX_FLAGS_NORMAL);
+	if (err)
+		return err;
+
+	if (eth->hwlro) {
+		i = (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ? 4 : 1;
+		for (; i < MTK_MAX_RX_RING_NUM; i++) {
+			err = mtk_rx_alloc(eth, i, MTK_RX_FLAGS_HWLRO);
+			if (err)
+				return err;
+		}
+		err = mtk_hwlro_rx_init(eth);
+		if (err)
+			return err;
+	}
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_NAPI_NUM; i++) {
+			err = mtk_rx_alloc(eth, i, MTK_RX_FLAGS_NORMAL);
+			if (err)
+				return err;
+		}
+		err = mtk_rss_init(eth);
+		if (err)
+                        return err;
+	}
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
+		/* Enable random early drop and set drop threshold
+		 * automatically
+		 */
+		mtk_w32(eth, FC_THRES_DROP_MODE | FC_THRES_DROP_EN |
+			FC_THRES_MIN, MTK_QDMA_FC_THRES);
+		mtk_w32(eth, 0x0, MTK_QDMA_HRED2);
+	}
+
+	return 0;
+}
+
+static void mtk_dma_free(struct mtk_eth *eth)
+{
+	int i;
+
+	for (i = 0; i < MTK_MAC_COUNT; i++)
+		if (eth->netdev[i])
+			netdev_reset_queue(eth->netdev[i]);
+	if ( !eth->soc->has_sram && eth->scratch_ring) {
+		dma_free_coherent(eth->dev,
+				  MTK_DMA_SIZE * sizeof(struct mtk_tx_dma),
+				  eth->scratch_ring,
+				  eth->phy_scratch_ring);
+		eth->scratch_ring = NULL;
+		eth->phy_scratch_ring = 0;
+	}
+	mtk_tx_clean(eth);
+	mtk_rx_clean(eth, &eth->rx_ring[0],1);
+	mtk_rx_clean(eth, &eth->rx_ring_qdma,0);
+
+	if (eth->hwlro) {
+		mtk_hwlro_rx_uninit(eth);
+
+		i = (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ? 4 : 1;
+		for (; i < MTK_MAX_RX_RING_NUM; i++)
+			mtk_rx_clean(eth, &eth->rx_ring[i], 0);
+	}
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		mtk_rss_uninit(eth);
+
+		for (i = 1; i < MTK_RX_NAPI_NUM; i++)
+			mtk_rx_clean(eth, &eth->rx_ring[i], 1);
+	}
+
+	if (eth->scratch_head) {
+		kfree(eth->scratch_head);
+		eth->scratch_head = NULL;
+	}
+}
+
+static void mtk_tx_timeout(struct net_device *dev)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+
+	eth->netdev[mac->id]->stats.tx_errors++;
+	netif_err(eth, tx_err, dev,
+		  "transmit timed out\n");
+	schedule_work(&eth->pending_work);
+}
+
+static irqreturn_t mtk_handle_irq_rx(int irq, void *priv)
+{
+	struct mtk_napi *rx_napi = priv;
+	struct mtk_eth *eth = rx_napi->eth;
+	struct mtk_rx_ring *ring = rx_napi->rx_ring;
+
+	if (likely(napi_schedule_prep(&rx_napi->napi))) {
+		mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(ring->ring_no));
+		__napi_schedule(&rx_napi->napi);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mtk_handle_irq_tx(int irq, void *_eth)
+{
+	struct mtk_eth *eth = _eth;
+
+	if (likely(napi_schedule_prep(&eth->tx_napi))) {
+		mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
+		__napi_schedule(&eth->tx_napi);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mtk_handle_irq(int irq, void *_eth)
+{
+	struct mtk_eth *eth = _eth;
+
+	if (mtk_r32(eth, MTK_PDMA_INT_MASK) & MTK_RX_DONE_INT(0)) {
+		if (mtk_r32(eth, MTK_PDMA_INT_STATUS) & MTK_RX_DONE_INT(0))
+			mtk_handle_irq_rx(irq, &eth->rx_napi[0]);
+	}
+	if (mtk_r32(eth, eth->tx_int_mask_reg) & MTK_TX_DONE_INT) {
+		if (mtk_r32(eth, eth->tx_int_status_reg) & MTK_TX_DONE_INT)
+			mtk_handle_irq_tx(irq, _eth);
+	}
+
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void mtk_poll_controller(struct net_device *dev)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+
+	mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
+	mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(0));
+	mtk_handle_irq_rx(eth->irq[2], &eth->rx_napi[0]);
+	mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
+	mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(0));
+}
+#endif
+
+static int mtk_start_dma(struct mtk_eth *eth)
+{
+	u32 rx_2b_offset = (NET_IP_ALIGN == 2) ? MTK_RX_2B_OFFSET : 0;
+	int val, err;
+
+	err = mtk_dma_init(eth);
+	if (err) {
+		mtk_dma_free(eth);
+		return err;
+	}
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
+		val = mtk_r32(eth, MTK_QDMA_GLO_CFG);
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+			mtk_w32(eth,
+				val | MTK_TX_DMA_EN | MTK_RX_DMA_EN |
+				MTK_DMA_SIZE_32DWORDS | MTK_TX_WB_DDONE |
+				MTK_NDP_CO_PRO | MTK_MUTLI_CNT |
+				MTK_RESV_BUF | MTK_WCOMP_EN |
+				MTK_DMAD_WR_WDONE | MTK_CHK_DDONE_EN |
+				MTK_RX_2B_OFFSET, MTK_QDMA_GLO_CFG);
+		else
+			mtk_w32(eth,
+				val | MTK_TX_DMA_EN |
+				MTK_DMA_SIZE_32DWORDS | MTK_NDP_CO_PRO |
+				MTK_RX_DMA_EN | MTK_RX_2B_OFFSET |
+				MTK_RX_BT_32DWORDS,
+				MTK_QDMA_GLO_CFG);
+
+		val = mtk_r32(eth, MTK_PDMA_GLO_CFG);
+		mtk_w32(eth,
+			val | MTK_RX_DMA_EN | rx_2b_offset |
+			MTK_RX_BT_32DWORDS | MTK_MULTI_EN,
+			MTK_PDMA_GLO_CFG);
+	} else {
+		mtk_w32(eth, MTK_TX_WB_DDONE | MTK_TX_DMA_EN | MTK_RX_DMA_EN |
+			MTK_MULTI_EN | MTK_PDMA_SIZE_8DWORDS,
+			MTK_PDMA_GLO_CFG);
+	}
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) && eth->hwlro) {
+		val = mtk_r32(eth, MTK_PDMA_GLO_CFG);
+		mtk_w32(eth, val | MTK_RX_DMA_LRO_EN, MTK_PDMA_GLO_CFG);
+	}
+
+	return 0;
+}
+
+static void mtk_gdm_config(struct mtk_eth *eth, u32 config)
+{
+	int i;
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628))
+		return;
+
+	for (i = 0; i < MTK_MAC_COUNT; i++) {
+		u32 val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i));
+
+		/* default setup the forward port to send frame to PDMA */
+		val &= ~0xffff;
+
+		/* Enable RX checksum */
+		val |= MTK_GDMA_ICS_EN | MTK_GDMA_TCS_EN | MTK_GDMA_UCS_EN;
+
+		val |= config;
+
+		if (eth->netdev[i] && netdev_uses_dsa(eth->netdev[i]))
+			val |= MTK_GDMA_SPECIAL_TAG;
+
+		mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i));
+	}
+}
+
+static int mtk_open(struct net_device *dev)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	int err, i;
+	struct device_node *phy_node;
+
+	err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0);
+	if (err) {
+		netdev_err(dev, "%s: could not attach PHY: %d\n", __func__,
+			   err);
+		return err;
+	}
+
+	/* we run 2 netdevs on the same dma ring so we only bring it up once */
+	if (!refcount_read(&eth->dma_refcnt)) {
+		int err = mtk_start_dma(eth);
+
+		if (err)
+			return err;
+
+		mtk_gdm_config(eth, MTK_GDMA_TO_PDMA);
+
+		/* Indicates CDM to parse the MTK special tag from CPU */
+		if (netdev_uses_dsa(dev)) {
+			u32 val;
+			val = mtk_r32(eth, MTK_CDMQ_IG_CTRL);
+			mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL);
+			val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
+			mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL);
+		}
+
+		napi_enable(&eth->tx_napi);
+		napi_enable(&eth->rx_napi[0].napi);
+		mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
+		mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(0));
+
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+			for (i = 1; i < MTK_RX_NAPI_NUM; i++) {
+				napi_enable(&eth->rx_napi[i].napi);
+				mtk_rx_irq_enable(eth, MTK_RX_DONE_INT(i));
+			}
+		}
+
+		refcount_set(&eth->dma_refcnt, 1);
+	}
+	else
+		refcount_inc(&eth->dma_refcnt);
+
+	phylink_start(mac->phylink);
+	netif_start_queue(dev);
+	phy_node = of_parse_phandle(mac->of_node, "phy-handle", 0);
+	if (!phy_node) {
+		regmap_write(eth->sgmii->regmap[0], SGMSYS_QPHY_PWR_STATE_CTRL, 0);
+	}
+	return 0;
+}
+
+static void mtk_stop_dma(struct mtk_eth *eth, u32 glo_cfg)
+{
+	u32 val;
+	int i;
+
+	/* stop the dma engine */
+	spin_lock_bh(&eth->page_lock);
+	val = mtk_r32(eth, glo_cfg);
+	mtk_w32(eth, val & ~(MTK_TX_WB_DDONE | MTK_RX_DMA_EN | MTK_TX_DMA_EN),
+		glo_cfg);
+	spin_unlock_bh(&eth->page_lock);
+
+	/* wait for dma stop */
+	for (i = 0; i < 10; i++) {
+		val = mtk_r32(eth, glo_cfg);
+		if (val & (MTK_TX_DMA_BUSY | MTK_RX_DMA_BUSY)) {
+			msleep(20);
+			continue;
+		}
+		break;
+	}
+}
+
+static int mtk_stop(struct net_device *dev)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	int i;
+	u32 val = 0;
+	struct device_node *phy_node;
+
+	netif_tx_disable(dev);
+
+	phy_node = of_parse_phandle(mac->of_node, "phy-handle", 0);
+	if (phy_node) {
+		val = _mtk_mdio_read(eth, 0, 0);
+		val |= BMCR_PDOWN;
+		_mtk_mdio_write(eth, 0, 0, val);
+	}else {
+		regmap_read(eth->sgmii->regmap[0], SGMSYS_QPHY_PWR_STATE_CTRL, &val);
+		val |= SGMII_PHYA_PWD;
+		regmap_write(eth->sgmii->regmap[0], SGMSYS_QPHY_PWR_STATE_CTRL, val);
+	}
+
+	//GMAC RX disable
+	val = mtk_r32(eth, MTK_MAC_MCR(mac->id));
+	mtk_w32(eth, val & ~(MAC_MCR_RX_EN), MTK_MAC_MCR(mac->id));
+
+	phylink_stop(mac->phylink);
+
+	phylink_disconnect_phy(mac->phylink);
+
+	/* only shutdown DMA if this is the last user */
+	if (!refcount_dec_and_test(&eth->dma_refcnt))
+		return 0;
+
+	mtk_gdm_config(eth, MTK_GDMA_DROP_ALL);
+
+	mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
+	mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(0));
+	napi_disable(&eth->tx_napi);
+	napi_disable(&eth->rx_napi[0].napi);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_NAPI_NUM; i++) {
+			mtk_rx_irq_disable(eth, MTK_RX_DONE_INT(i));
+			napi_disable(&eth->rx_napi[i].napi);
+		}
+	}
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
+		mtk_stop_dma(eth, MTK_QDMA_GLO_CFG);
+	mtk_stop_dma(eth, MTK_PDMA_GLO_CFG);
+
+	mtk_dma_free(eth);
+
+	return 0;
+}
+
+static void ethsys_reset(struct mtk_eth *eth, u32 reset_bits)
+{
+	regmap_update_bits(eth->ethsys, ETHSYS_RSTCTRL,
+			   reset_bits,
+			   reset_bits);
+
+	usleep_range(1000, 1100);
+	regmap_update_bits(eth->ethsys, ETHSYS_RSTCTRL,
+			   reset_bits,
+			   ~reset_bits);
+	mdelay(10);
+}
+
+static void mtk_clk_disable(struct mtk_eth *eth)
+{
+	int clk;
+
+	for (clk = MTK_CLK_MAX - 1; clk >= 0; clk--)
+		clk_disable_unprepare(eth->clks[clk]);
+}
+
+static int mtk_clk_enable(struct mtk_eth *eth)
+{
+	int clk, ret;
+
+	for (clk = 0; clk < MTK_CLK_MAX ; clk++) {
+		ret = clk_prepare_enable(eth->clks[clk]);
+		if (ret)
+			goto err_disable_clks;
+	}
+
+	return 0;
+
+err_disable_clks:
+	while (--clk >= 0)
+		clk_disable_unprepare(eth->clks[clk]);
+
+	return ret;
+}
+
+static int mtk_napi_init(struct mtk_eth *eth)
+{
+	struct mtk_napi *rx_napi = &eth->rx_napi[0];
+	int i;
+
+	rx_napi->eth = eth;
+	rx_napi->rx_ring = &eth->rx_ring[0];
+	rx_napi->irq_grp_no = 2;
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_NAPI_NUM; i++) {
+			rx_napi = &eth->rx_napi[i];
+			rx_napi->eth = eth;
+			rx_napi->rx_ring = &eth->rx_ring[i];
+			rx_napi->irq_grp_no = 2 + i;
+		}
+	}
+
+	return 0;
+}
+
+static int mtk_hw_init(struct mtk_eth *eth)
+{
+	int i, ret;
+
+	if (test_and_set_bit(MTK_HW_INIT, &eth->state))
+		return 0;
+
+	pm_runtime_enable(eth->dev);
+	pm_runtime_get_sync(eth->dev);
+
+	ret = mtk_clk_enable(eth);
+	if (ret)
+		goto err_disable_pm;
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) {
+		ret = device_reset(eth->dev);
+		if (ret) {
+			dev_err(eth->dev, "MAC reset failed!\n");
+			goto err_disable_pm;
+		}
+
+		/* enable interrupt delay for RX */
+		mtk_w32(eth, MTK_PDMA_DELAY_RX_DELAY, MTK_PDMA_DELAY_INT);
+
+		/* disable delay and normal interrupt */
+		mtk_tx_irq_disable(eth, ~0);
+		mtk_rx_irq_disable(eth, ~0);
+
+		return 0;
+	}
+
+	/* Non-MT7628 handling... */
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+		regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN, 0);
+
+	if(MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1))
+		ethsys_reset(eth,  RSTCTRL_ETH | RSTCTRL_FE | RSTCTRL_PPE | RSTCTRL_PPE1);
+	else
+		ethsys_reset(eth,  RSTCTRL_ETH | RSTCTRL_FE | RSTCTRL_PPE);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+		regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN, 0x3ffffff);
+
+		/* Set FE to PDMAv2 if necessary */
+		mtk_w32(eth, mtk_r32(eth, MTK_FE_GLO_MISC) | MTK_PDMA_V2, MTK_FE_GLO_MISC);
+	}
+
+	if (eth->pctl) {
+		/* Set GE2 driving and slew rate */
+		regmap_write(eth->pctl, GPIO_DRV_SEL10, 0xa00);
+
+		/* set GE2 TDSEL */
+		regmap_write(eth->pctl, GPIO_OD33_CTRL8, 0x5);
+
+		/* set GE2 TUNE */
+		regmap_write(eth->pctl, GPIO_BIAS_CTRL, 0x0);
+	}
+
+	/* Set linkdown as the default for each GMAC. Its own MCR would be set
+	 * up with the more appropriate value when mtk_mac_config call is being
+	 * invoked.
+	 */
+	for (i = 0; i < MTK_MAC_COUNT; i++)
+		mtk_w32(eth, MAC_MCR_FORCE_LINK_DOWN, MTK_MAC_MCR(i));
+
+	/* Enable RX VLan Offloading */
+	if (eth->soc->hw_features & NETIF_F_HW_VLAN_CTAG_RX)
+		mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
+	else
+		mtk_w32(eth, 0, MTK_CDMP_EG_CTRL);
+
+	/* enable interrupt delay for RX/TX */
+	mtk_w32(eth, 0x8f0f8f0f, MTK_PDMA_DELAY_INT);
+	mtk_w32(eth, 0x8f0f8f0f, MTK_QDMA_DELAY_INT);
+
+	mtk_tx_irq_disable(eth, ~0);
+	mtk_rx_irq_disable(eth, ~0);
+
+	/* FE int grouping */
+	mtk_w32(eth, MTK_TX_DONE_INT, MTK_PDMA_INT_GRP1);
+	mtk_w32(eth, MTK_RX_DONE_INT(0), MTK_PDMA_INT_GRP2);
+	mtk_w32(eth, MTK_TX_DONE_INT, MTK_QDMA_INT_GRP1);
+	mtk_w32(eth, MTK_RX_DONE_INT(0), MTK_QDMA_INT_GRP2);
+	mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
+		/* PSE Free Queue Flow Control  */
+		mtk_w32(eth, 0x01fa01f4, PSE_FQFC_CFG2);
+
+		/* PSE should not drop port8 and port9 packets */
+		mtk_w32(eth, 0x00000300, PSE_DROP_CFG);
+
+		/* PSE config input queue threshold */
+		mtk_w32(eth, 0x001a000e, PSE_IQ_REV(1));
+		mtk_w32(eth, 0x01ff001a, PSE_IQ_REV(2));
+		mtk_w32(eth, 0x000e01ff, PSE_IQ_REV(3));
+		mtk_w32(eth, 0x000e000e, PSE_IQ_REV(4));
+		mtk_w32(eth, 0x000e000e, PSE_IQ_REV(5));
+		mtk_w32(eth, 0x000e000e, PSE_IQ_REV(6));
+		mtk_w32(eth, 0x000e000e, PSE_IQ_REV(7));
+		mtk_w32(eth, 0x002a000e, PSE_IQ_REV(8));
+
+		/* PSE config output queue threshold */
+		mtk_w32(eth, 0x000f000a, PSE_OQ_TH(1));
+		mtk_w32(eth, 0x001a000f, PSE_OQ_TH(2));
+		mtk_w32(eth, 0x000f001a, PSE_OQ_TH(3));
+		mtk_w32(eth, 0x01ff000f, PSE_OQ_TH(4));
+		mtk_w32(eth, 0x000f000f, PSE_OQ_TH(5));
+		mtk_w32(eth, 0x0006000f, PSE_OQ_TH(6));
+		mtk_w32(eth, 0x00060006, PSE_OQ_TH(7));
+		mtk_w32(eth, 0x00060006, PSE_OQ_TH(8));
+
+		/* GDM and CDM Threshold */
+		mtk_w32(eth, 0x00000004, MTK_GDM2_THRES);
+                mtk_w32(eth, 0x00000004, MTK_CDMW0_THRES);
+                mtk_w32(eth, 0x00000004, MTK_CDMW1_THRES);
+                mtk_w32(eth, 0x00000004, MTK_CDME0_THRES);
+                mtk_w32(eth, 0x00000004, MTK_CDME1_THRES);
+                mtk_w32(eth, 0x00000004, MTK_CDMM_THRES);
+	}
+
+	return 0;
+
+err_disable_pm:
+	pm_runtime_put_sync(eth->dev);
+	pm_runtime_disable(eth->dev);
+
+	return ret;
+}
+
+static int mtk_hw_deinit(struct mtk_eth *eth)
+{
+	if (!test_and_clear_bit(MTK_HW_INIT, &eth->state))
+		return 0;
+
+	mtk_clk_disable(eth);
+
+	pm_runtime_put_sync(eth->dev);
+	pm_runtime_disable(eth->dev);
+
+	return 0;
+}
+
+static int __init mtk_init(struct net_device *dev)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	const char *mac_addr;
+
+	mac_addr = of_get_mac_address(mac->of_node);
+	if (!IS_ERR(mac_addr))
+		ether_addr_copy(dev->dev_addr, mac_addr);
+
+	/* If the mac address is invalid, use random mac address  */
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		eth_hw_addr_random(dev);
+		dev_err(eth->dev, "generated random MAC address %pM\n",
+			dev->dev_addr);
+	}
+
+	return 0;
+}
+
+static void mtk_uninit(struct net_device *dev)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+
+	phylink_disconnect_phy(mac->phylink);
+	mtk_tx_irq_disable(eth, ~0);
+	mtk_rx_irq_disable(eth, ~0);
+}
+
+static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+
+	switch (cmd) {
+	case SIOCGMIIPHY:
+	case SIOCGMIIREG:
+	case SIOCSMIIREG:
+		return phylink_mii_ioctl(mac->phylink, ifr, cmd);
+	default:
+		/* default invoke the mtk_eth_dbg handler */
+		return mtk_do_priv_ioctl(dev, ifr, cmd);
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static void mtk_pending_work(struct work_struct *work)
+{
+	struct mtk_eth *eth = container_of(work, struct mtk_eth, pending_work);
+	int err, i;
+	unsigned long restart = 0;
+
+	rtnl_lock();
+
+	dev_dbg(eth->dev, "[%s][%d] reset\n", __func__, __LINE__);
+
+	while (test_and_set_bit_lock(MTK_RESETTING, &eth->state))
+		cpu_relax();
+
+	dev_dbg(eth->dev, "[%s][%d] mtk_stop starts\n", __func__, __LINE__);
+	/* stop all devices to make sure that dma is properly shut down */
+	for (i = 0; i < MTK_MAC_COUNT; i++) {
+		if (!eth->netdev[i])
+			continue;
+		mtk_stop(eth->netdev[i]);
+		__set_bit(i, &restart);
+	}
+	dev_dbg(eth->dev, "[%s][%d] mtk_stop ends\n", __func__, __LINE__);
+
+	/* restart underlying hardware such as power, clock, pin mux
+	 * and the connected phy
+	 */
+	mtk_hw_deinit(eth);
+
+	if (eth->dev->pins)
+		pinctrl_select_state(eth->dev->pins->p,
+				     eth->dev->pins->default_state);
+	mtk_hw_init(eth);
+
+	/* restart DMA and enable IRQs */
+	for (i = 0; i < MTK_MAC_COUNT; i++) {
+		if (!test_bit(i, &restart))
+			continue;
+		err = mtk_open(eth->netdev[i]);
+		if (err) {
+			netif_alert(eth, ifup, eth->netdev[i],
+			      "Driver up/down cycle failed, closing device.\n");
+			dev_close(eth->netdev[i]);
+		}
+	}
+
+	dev_dbg(eth->dev, "[%s][%d] reset done\n", __func__, __LINE__);
+
+	clear_bit_unlock(MTK_RESETTING, &eth->state);
+
+	rtnl_unlock();
+}
+
+static int mtk_free_dev(struct mtk_eth *eth)
+{
+	int i;
+
+	for (i = 0; i < MTK_MAC_COUNT; i++) {
+		if (!eth->netdev[i])
+			continue;
+		free_netdev(eth->netdev[i]);
+	}
+
+	return 0;
+}
+
+static int mtk_unreg_dev(struct mtk_eth *eth)
+{
+	int i;
+
+	for (i = 0; i < MTK_MAC_COUNT; i++) {
+		if (!eth->netdev[i])
+			continue;
+		unregister_netdev(eth->netdev[i]);
+	}
+
+	return 0;
+}
+
+static int mtk_cleanup(struct mtk_eth *eth)
+{
+	mtk_unreg_dev(eth);
+	mtk_free_dev(eth);
+	cancel_work_sync(&eth->pending_work);
+
+	return 0;
+}
+
+static int mtk_get_link_ksettings(struct net_device *ndev,
+				  struct ethtool_link_ksettings *cmd)
+{
+	struct mtk_mac *mac = netdev_priv(ndev);
+
+	if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state)))
+		return -EBUSY;
+
+	return phylink_ethtool_ksettings_get(mac->phylink, cmd);
+}
+
+static int mtk_set_link_ksettings(struct net_device *ndev,
+				  const struct ethtool_link_ksettings *cmd)
+{
+	struct mtk_mac *mac = netdev_priv(ndev);
+
+	if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state)))
+		return -EBUSY;
+
+	return phylink_ethtool_ksettings_set(mac->phylink, cmd);
+}
+
+static void mtk_get_drvinfo(struct net_device *dev,
+			    struct ethtool_drvinfo *info)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+
+	strlcpy(info->driver, mac->hw->dev->driver->name, sizeof(info->driver));
+	strlcpy(info->bus_info, dev_name(mac->hw->dev), sizeof(info->bus_info));
+	info->n_stats = ARRAY_SIZE(mtk_ethtool_stats);
+}
+
+static u32 mtk_get_msglevel(struct net_device *dev)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+
+	return mac->hw->msg_enable;
+}
+
+static void mtk_set_msglevel(struct net_device *dev, u32 value)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+
+	mac->hw->msg_enable = value;
+}
+
+static int mtk_nway_reset(struct net_device *dev)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+
+	if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state)))
+		return -EBUSY;
+
+	if (!mac->phylink)
+		return -ENOTSUPP;
+
+	return phylink_ethtool_nway_reset(mac->phylink);
+}
+
+static void mtk_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+	int i;
+
+	switch (stringset) {
+	case ETH_SS_STATS:
+		for (i = 0; i < ARRAY_SIZE(mtk_ethtool_stats); i++) {
+			memcpy(data, mtk_ethtool_stats[i].str, ETH_GSTRING_LEN);
+			data += ETH_GSTRING_LEN;
+		}
+		break;
+	}
+}
+
+static int mtk_get_sset_count(struct net_device *dev, int sset)
+{
+	switch (sset) {
+	case ETH_SS_STATS:
+		return ARRAY_SIZE(mtk_ethtool_stats);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static void mtk_get_ethtool_stats(struct net_device *dev,
+				  struct ethtool_stats *stats, u64 *data)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_hw_stats *hwstats = mac->hw_stats;
+	u64 *data_src, *data_dst;
+	unsigned int start;
+	int i;
+
+	if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state)))
+		return;
+
+	if (netif_running(dev) && netif_device_present(dev)) {
+		if (spin_trylock_bh(&hwstats->stats_lock)) {
+			mtk_stats_update_mac(mac);
+			spin_unlock_bh(&hwstats->stats_lock);
+		}
+	}
+
+	data_src = (u64 *)hwstats;
+
+	do {
+		data_dst = data;
+		start = u64_stats_fetch_begin_irq(&hwstats->syncp);
+
+		for (i = 0; i < ARRAY_SIZE(mtk_ethtool_stats); i++)
+			*data_dst++ = *(data_src + mtk_ethtool_stats[i].offset);
+	} while (u64_stats_fetch_retry_irq(&hwstats->syncp, start));
+}
+
+static int mtk_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
+			 u32 *rule_locs)
+{
+	int ret = -EOPNOTSUPP;
+
+	switch (cmd->cmd) {
+	case ETHTOOL_GRXRINGS:
+		if (dev->hw_features & NETIF_F_LRO) {
+			cmd->data = MTK_MAX_RX_RING_NUM;
+			ret = 0;
+		}
+		break;
+	case ETHTOOL_GRXCLSRLCNT:
+		if (dev->hw_features & NETIF_F_LRO) {
+			struct mtk_mac *mac = netdev_priv(dev);
+
+			cmd->rule_cnt = mac->hwlro_ip_cnt;
+			ret = 0;
+		}
+		break;
+	case ETHTOOL_GRXCLSRULE:
+		if (dev->hw_features & NETIF_F_LRO)
+			ret = mtk_hwlro_get_fdir_entry(dev, cmd);
+		break;
+	case ETHTOOL_GRXCLSRLALL:
+		if (dev->hw_features & NETIF_F_LRO)
+			ret = mtk_hwlro_get_fdir_all(dev, cmd,
+						     rule_locs);
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static int mtk_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
+{
+	int ret = -EOPNOTSUPP;
+
+	switch (cmd->cmd) {
+	case ETHTOOL_SRXCLSRLINS:
+		if (dev->hw_features & NETIF_F_LRO)
+			ret = mtk_hwlro_add_ipaddr(dev, cmd);
+		break;
+	case ETHTOOL_SRXCLSRLDEL:
+		if (dev->hw_features & NETIF_F_LRO)
+			ret = mtk_hwlro_del_ipaddr(dev, cmd);
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static const struct ethtool_ops mtk_ethtool_ops = {
+	.get_link_ksettings	= mtk_get_link_ksettings,
+	.set_link_ksettings	= mtk_set_link_ksettings,
+	.get_drvinfo		= mtk_get_drvinfo,
+	.get_msglevel		= mtk_get_msglevel,
+	.set_msglevel		= mtk_set_msglevel,
+	.nway_reset		= mtk_nway_reset,
+	.get_link		= ethtool_op_get_link,
+	.get_strings		= mtk_get_strings,
+	.get_sset_count		= mtk_get_sset_count,
+	.get_ethtool_stats	= mtk_get_ethtool_stats,
+	.get_rxnfc		= mtk_get_rxnfc,
+	.set_rxnfc              = mtk_set_rxnfc,
+};
+
+static const struct net_device_ops mtk_netdev_ops = {
+	.ndo_init		= mtk_init,
+	.ndo_uninit		= mtk_uninit,
+	.ndo_open		= mtk_open,
+	.ndo_stop		= mtk_stop,
+	.ndo_start_xmit		= mtk_start_xmit,
+	.ndo_set_mac_address	= mtk_set_mac_address,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_do_ioctl		= mtk_do_ioctl,
+	.ndo_tx_timeout		= mtk_tx_timeout,
+	.ndo_get_stats64        = mtk_get_stats64,
+	.ndo_fix_features	= mtk_fix_features,
+	.ndo_set_features	= mtk_set_features,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller	= mtk_poll_controller,
+#endif
+};
+
+static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
+{
+	const __be32 *_id = of_get_property(np, "reg", NULL);
+	struct phylink *phylink;
+	int phy_mode, id, err;
+	struct mtk_mac *mac;
+
+	if (!_id) {
+		dev_err(eth->dev, "missing mac id\n");
+		return -EINVAL;
+	}
+
+	id = be32_to_cpup(_id);
+	if (id < 0 || id >= MTK_MAC_COUNT) {
+		dev_err(eth->dev, "%d is not a valid mac id\n", id);
+		return -EINVAL;
+	}
+
+	if (eth->netdev[id]) {
+		dev_err(eth->dev, "duplicate mac id found: %d\n", id);
+		return -EINVAL;
+	}
+
+	eth->netdev[id] = alloc_etherdev(sizeof(*mac));
+	if (!eth->netdev[id]) {
+		dev_err(eth->dev, "alloc_etherdev failed\n");
+		return -ENOMEM;
+	}
+	mac = netdev_priv(eth->netdev[id]);
+	eth->mac[id] = mac;
+	mac->id = id;
+	mac->hw = eth;
+	mac->of_node = np;
+
+	memset(mac->hwlro_ip, 0, sizeof(mac->hwlro_ip));
+	mac->hwlro_ip_cnt = 0;
+
+	mac->hw_stats = devm_kzalloc(eth->dev,
+				     sizeof(*mac->hw_stats),
+				     GFP_KERNEL);
+	if (!mac->hw_stats) {
+		dev_err(eth->dev, "failed to allocate counter memory\n");
+		err = -ENOMEM;
+		goto free_netdev;
+	}
+	spin_lock_init(&mac->hw_stats->stats_lock);
+	u64_stats_init(&mac->hw_stats->syncp);
+	mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET;
+
+	/* phylink create */
+	phy_mode = of_get_phy_mode(np);
+	if (phy_mode < 0) {
+		dev_err(eth->dev, "incorrect phy-mode\n");
+		err = -EINVAL;
+		goto free_netdev;
+	}
+
+	/* mac config is not set */
+	mac->interface = PHY_INTERFACE_MODE_NA;
+	mac->mode = MLO_AN_PHY;
+	mac->speed = SPEED_UNKNOWN;
+
+	mac->phylink_config.dev = &eth->netdev[id]->dev;
+	mac->phylink_config.type = PHYLINK_NETDEV;
+
+	phylink = phylink_create(&mac->phylink_config,
+				 of_fwnode_handle(mac->of_node),
+				 phy_mode, &mtk_phylink_ops);
+	if (IS_ERR(phylink)) {
+		err = PTR_ERR(phylink);
+		goto free_netdev;
+	}
+
+	mac->phylink = phylink;
+
+	SET_NETDEV_DEV(eth->netdev[id], eth->dev);
+	eth->netdev[id]->watchdog_timeo = 5 * HZ;
+	eth->netdev[id]->netdev_ops = &mtk_netdev_ops;
+	eth->netdev[id]->base_addr = (unsigned long)eth->base;
+
+	eth->netdev[id]->hw_features = eth->soc->hw_features;
+	if (eth->hwlro)
+		eth->netdev[id]->hw_features |= NETIF_F_LRO;
+
+	eth->netdev[id]->vlan_features = eth->soc->hw_features &
+		~(NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX);
+	eth->netdev[id]->features |= eth->soc->hw_features;
+	eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops;
+
+	eth->netdev[id]->irq = eth->irq[0];
+	eth->netdev[id]->dev.of_node = np;
+
+	return 0;
+
+free_netdev:
+	free_netdev(eth->netdev[id]);
+	return err;
+}
+
+static int mtk_probe(struct platform_device *pdev)
+{
+	struct device_node *mac_np;
+	struct mtk_eth *eth;
+	int err, i;
+
+	eth = devm_kzalloc(&pdev->dev, sizeof(*eth), GFP_KERNEL);
+	if (!eth)
+		return -ENOMEM;
+
+	eth->soc = of_device_get_match_data(&pdev->dev);
+
+	eth->dev = &pdev->dev;
+	eth->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(eth->base))
+		return PTR_ERR(eth->base);
+
+	if(eth->soc->has_sram) {
+		struct resource *res;
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		if (unlikely(!res))
+			return -EINVAL;
+		eth->phy_scratch_ring = res->start + MTK_ETH_SRAM_OFFSET;
+	}
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
+		eth->tx_int_mask_reg = MTK_QDMA_INT_MASK;
+		eth->tx_int_status_reg = MTK_QDMA_INT_STATUS;
+	} else {
+		eth->tx_int_mask_reg = MTK_PDMA_INT_MASK;
+		eth->tx_int_status_reg = MTK_PDMA_INT_STATUS;
+	}
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) {
+		eth->rx_dma_l4_valid = RX_DMA_L4_VALID_PDMA;
+		eth->ip_align = NET_IP_ALIGN;
+	} else {
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+			eth->rx_dma_l4_valid = RX_DMA_L4_VALID_V2;
+		else
+			eth->rx_dma_l4_valid = RX_DMA_L4_VALID;
+	}
+
+	spin_lock_init(&eth->page_lock);
+	spin_lock_init(&eth->tx_irq_lock);
+	spin_lock_init(&eth->rx_irq_lock);
+	spin_lock_init(&eth->syscfg0_lock);
+
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) {
+		eth->ethsys = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+							      "mediatek,ethsys");
+		if (IS_ERR(eth->ethsys)) {
+			dev_err(&pdev->dev, "no ethsys regmap found\n");
+			return PTR_ERR(eth->ethsys);
+		}
+	}
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_INFRA)) {
+		eth->infra = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+							     "mediatek,infracfg");
+		if (IS_ERR(eth->infra)) {
+			dev_err(&pdev->dev, "no infracfg regmap found\n");
+			return PTR_ERR(eth->infra);
+		}
+	}
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
+		eth->sgmii = devm_kzalloc(eth->dev, sizeof(*eth->sgmii),
+					  GFP_KERNEL);
+		if (!eth->sgmii)
+			return -ENOMEM;
+
+		err = mtk_sgmii_init(eth->sgmii, pdev->dev.of_node,
+				     eth->soc->ana_rgc3);
+
+		if (err)
+			return err;
+	}
+
+	if (eth->soc->required_pctl) {
+		eth->pctl = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+							    "mediatek,pctl");
+		if (IS_ERR(eth->pctl)) {
+			dev_err(&pdev->dev, "no pctl regmap found\n");
+			return PTR_ERR(eth->pctl);
+		}
+	}
+
+	for (i = 0; i < MTK_MAX_IRQ_NUM; i++) {
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT) && i > 0)
+			eth->irq[i] = eth->irq[0];
+		else
+			eth->irq[i] = platform_get_irq(pdev, i);
+		if (eth->irq[i] < 0) {
+			dev_err(&pdev->dev, "no IRQ%d resource found\n", i);
+			return -ENXIO;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(eth->clks); i++) {
+		eth->clks[i] = devm_clk_get(eth->dev,
+					    mtk_clks_source_name[i]);
+		if (IS_ERR(eth->clks[i])) {
+			if (PTR_ERR(eth->clks[i]) == -EPROBE_DEFER)
+				return -EPROBE_DEFER;
+			if (eth->soc->required_clks & BIT(i)) {
+				dev_err(&pdev->dev, "clock %s not found\n",
+					mtk_clks_source_name[i]);
+				return -EINVAL;
+			}
+			eth->clks[i] = NULL;
+		}
+	}
+
+	eth->msg_enable = netif_msg_init(mtk_msg_level, MTK_DEFAULT_MSG_ENABLE);
+	INIT_WORK(&eth->pending_work, mtk_pending_work);
+
+	err = mtk_hw_init(eth);
+	if (err)
+		return err;
+
+	eth->hwlro = MTK_HAS_CAPS(eth->soc->caps, MTK_HWLRO);
+
+	for_each_child_of_node(pdev->dev.of_node, mac_np) {
+		if (!of_device_is_compatible(mac_np,
+					     "mediatek,eth-mac"))
+			continue;
+
+		if (!of_device_is_available(mac_np))
+			continue;
+
+		err = mtk_add_mac(eth, mac_np);
+		if (err) {
+			of_node_put(mac_np);
+			goto err_deinit_hw;
+		}
+	}
+
+	err = mtk_napi_init(eth);
+	if (err)
+		goto err_free_dev;
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) {
+		err = devm_request_irq(eth->dev, eth->irq[0],
+				       mtk_handle_irq, 0,
+				       dev_name(eth->dev), eth);
+	} else {
+		err = devm_request_irq(eth->dev, eth->irq[1],
+				       mtk_handle_irq_tx, 0,
+				       dev_name(eth->dev), eth);
+		if (err)
+			goto err_free_dev;
+
+		err = devm_request_irq(eth->dev, eth->irq[2],
+				       mtk_handle_irq_rx, 0,
+				       dev_name(eth->dev), &eth->rx_napi[0]);
+		if (err)
+			goto err_free_dev;
+
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+			for (i = 1; i < MTK_RX_NAPI_NUM; i++) {
+				err = devm_request_irq(eth->dev,
+						eth->irq[2 + i],
+						mtk_handle_irq_rx, 0,
+						dev_name(eth->dev),
+						&eth->rx_napi[i]);
+				if (err)
+					goto err_free_dev;
+			}
+		}
+	}
+	if (err)
+		goto err_free_dev;
+
+	/* No MT7628/88 support yet */
+	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) {
+		err = mtk_mdio_init(eth);
+		if (err)
+			goto err_free_dev;
+	}
+
+	for (i = 0; i < MTK_MAX_DEVS; i++) {
+		if (!eth->netdev[i])
+			continue;
+
+		err = register_netdev(eth->netdev[i]);
+		if (err) {
+			dev_err(eth->dev, "error bringing up device\n");
+			goto err_deinit_mdio;
+		} else
+			netif_info(eth, probe, eth->netdev[i],
+				   "mediatek frame engine at 0x%08lx, irq %d\n",
+				   eth->netdev[i]->base_addr, eth->irq[0]);
+	}
+
+	/* we run 2 devices on the same DMA ring so we need a dummy device
+	 * for NAPI to work
+	 */
+	init_dummy_netdev(&eth->dummy_dev);
+	netif_napi_add(&eth->dummy_dev, &eth->tx_napi, mtk_napi_tx,
+		       MTK_NAPI_WEIGHT);
+	netif_napi_add(&eth->dummy_dev, &eth->rx_napi[0].napi, mtk_napi_rx,
+		       MTK_NAPI_WEIGHT);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_NAPI_NUM; i++)
+			netif_napi_add(&eth->dummy_dev, &eth->rx_napi[i].napi,
+				       mtk_napi_rx, MTK_NAPI_WEIGHT);
+	}
+
+	mtketh_debugfs_init(eth);
+	debug_proc_init(eth);
+
+	platform_set_drvdata(pdev, eth);
+
+	return 0;
+
+err_deinit_mdio:
+	mtk_mdio_cleanup(eth);
+err_free_dev:
+	mtk_free_dev(eth);
+err_deinit_hw:
+	mtk_hw_deinit(eth);
+
+	return err;
+}
+
+static int mtk_remove(struct platform_device *pdev)
+{
+	struct mtk_eth *eth = platform_get_drvdata(pdev);
+	struct mtk_mac *mac;
+	int i;
+
+	/* stop all devices to make sure that dma is properly shut down */
+	for (i = 0; i < MTK_MAC_COUNT; i++) {
+		if (!eth->netdev[i])
+			continue;
+		mtk_stop(eth->netdev[i]);
+		mac = netdev_priv(eth->netdev[i]);
+		phylink_disconnect_phy(mac->phylink);
+	}
+
+	mtk_hw_deinit(eth);
+
+	netif_napi_del(&eth->tx_napi);
+	netif_napi_del(&eth->rx_napi[0].napi);
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSS)) {
+		for (i = 1; i < MTK_RX_NAPI_NUM; i++)
+			netif_napi_del(&eth->rx_napi[i].napi);
+	}
+
+	mtk_cleanup(eth);
+	mtk_mdio_cleanup(eth);
+
+	return 0;
+}
+
+static const struct mtk_soc_data mt2701_data = {
+	.caps = MT7623_CAPS | MTK_HWLRO,
+	.hw_features = MTK_HW_FEATURES,
+	.required_clks = MT7623_CLKS_BITMAP,
+	.required_pctl = true,
+	.has_sram = false,
+};
+
+static const struct mtk_soc_data mt7621_data = {
+	.caps = MT7621_CAPS,
+	.hw_features = MTK_HW_FEATURES,
+	.required_clks = MT7621_CLKS_BITMAP,
+	.required_pctl = false,
+	.has_sram = false,
+};
+
+static const struct mtk_soc_data mt7622_data = {
+	.ana_rgc3 = 0x2028,
+	.caps = MT7622_CAPS | MTK_HWLRO,
+	.hw_features = MTK_HW_FEATURES,
+	.required_clks = MT7622_CLKS_BITMAP,
+	.required_pctl = false,
+	.has_sram = false,
+};
+
+static const struct mtk_soc_data mt7623_data = {
+	.caps = MT7623_CAPS | MTK_HWLRO,
+	.hw_features = MTK_HW_FEATURES,
+	.required_clks = MT7623_CLKS_BITMAP,
+	.required_pctl = true,
+	.has_sram = false,
+};
+
+static const struct mtk_soc_data mt7629_data = {
+	.ana_rgc3 = 0x128,
+	.caps = MT7629_CAPS | MTK_HWLRO,
+	.hw_features = MTK_HW_FEATURES,
+	.required_clks = MT7629_CLKS_BITMAP,
+	.required_pctl = false,
+	.has_sram = false,
+};
+
+static const struct mtk_soc_data mt7986_data = {
+	.ana_rgc3 = 0x128,
+	.caps = MT7986_CAPS,
+	.hw_features = MTK_HW_FEATURES,
+	.required_clks = MT7986_CLKS_BITMAP,
+	.required_pctl = false,
+	.has_sram = true,
+};
+
+static const struct mtk_soc_data mt7981_data = {
+	.ana_rgc3 = 0x128,
+	.caps = MT7981_CAPS,
+	.hw_features = MTK_HW_FEATURES,
+	.required_clks = MT7981_CLKS_BITMAP,
+	.required_pctl = false,
+	.has_sram = true,
+};
+
+static const struct mtk_soc_data rt5350_data = {
+	.caps = MT7628_CAPS,
+	.hw_features = MTK_HW_FEATURES_MT7628,
+	.required_clks = MT7628_CLKS_BITMAP,
+	.required_pctl = false,
+	.has_sram = false,
+};
+
+const struct of_device_id of_mtk_match[] = {
+	{ .compatible = "mediatek,mt2701-eth", .data = &mt2701_data},
+	{ .compatible = "mediatek,mt7621-eth", .data = &mt7621_data},
+	{ .compatible = "mediatek,mt7622-eth", .data = &mt7622_data},
+	{ .compatible = "mediatek,mt7623-eth", .data = &mt7623_data},
+	{ .compatible = "mediatek,mt7629-eth", .data = &mt7629_data},
+	{ .compatible = "mediatek,mt7986-eth", .data = &mt7986_data},
+	{ .compatible = "mediatek,mt7981-eth", .data = &mt7981_data},
+	{ .compatible = "ralink,rt5350-eth", .data = &rt5350_data},
+	{},
+};
+MODULE_DEVICE_TABLE(of, of_mtk_match);
+
+static struct platform_driver mtk_driver = {
+	.probe = mtk_probe,
+	.remove = mtk_remove,
+	.driver = {
+		.name = "mtk_soc_eth",
+		.of_match_table = of_mtk_match,
+	},
+};
+
+module_platform_driver(mtk_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("Ethernet driver for MediaTek SoC");
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
new file mode 100755
index 0000000..a31c4f6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -0,0 +1,1270 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ *
+ *   Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
+ *   Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
+ *   Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
+ */
+
+#ifndef MTK_ETH_H
+#define MTK_ETH_H
+
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/of_net.h>
+#include <linux/u64_stats_sync.h>
+#include <linux/refcount.h>
+#include <linux/phylink.h>
+
+#define MTK_QDMA_PAGE_SIZE	2048
+#define	MTK_MAX_RX_LENGTH	1536
+#define MTK_DMA_SIZE		2048
+#define MTK_NAPI_WEIGHT		256
+#define MTK_MAC_COUNT		2
+#define MTK_RX_ETH_HLEN		(VLAN_ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN)
+#define MTK_RX_HLEN		(NET_SKB_PAD + MTK_RX_ETH_HLEN + NET_IP_ALIGN)
+#define MTK_DMA_DUMMY_DESC	0xffffffff
+#define MTK_DEFAULT_MSG_ENABLE	(NETIF_MSG_DRV | \
+				 NETIF_MSG_PROBE | \
+				 NETIF_MSG_LINK | \
+				 NETIF_MSG_TIMER | \
+				 NETIF_MSG_IFDOWN | \
+				 NETIF_MSG_IFUP | \
+				 NETIF_MSG_RX_ERR | \
+				 NETIF_MSG_TX_ERR)
+#define MTK_HW_FEATURES		(NETIF_F_IP_CSUM | \
+				 NETIF_F_RXCSUM | \
+				 NETIF_F_HW_VLAN_CTAG_TX | \
+				 NETIF_F_SG | NETIF_F_TSO | \
+				 NETIF_F_TSO6 | \
+				 NETIF_F_IPV6_CSUM)
+#define MTK_SET_FEATURES	(NETIF_F_LRO | \
+				 NETIF_F_HW_VLAN_CTAG_RX)
+#define MTK_HW_FEATURES_MT7628	(NETIF_F_SG | NETIF_F_RXCSUM)
+#define NEXT_DESP_IDX(X, Y)	(((X) + 1) & ((Y) - 1))
+
+#define MTK_HW_LRO_DMA_SIZE	8
+
+#define	MTK_MAX_LRO_RX_LENGTH		(4096 * 3)
+#define	MTK_MAX_LRO_IP_CNT		2
+#define	MTK_HW_LRO_TIMER_UNIT		1	/* 20 us */
+#define	MTK_HW_LRO_REFRESH_TIME		50000	/* 1 sec. */
+#define	MTK_HW_LRO_AGG_TIME		10	/* 200us */
+#define	MTK_HW_LRO_AGE_TIME		50	/* 1ms */
+#define	MTK_HW_LRO_MAX_AGG_CNT		64
+#define	MTK_HW_LRO_BW_THRE		3000
+#define	MTK_HW_LRO_REPLACE_DELTA	1000
+#define	MTK_HW_LRO_SDL_REMAIN_ROOM	1522
+
+/* Frame Engine Global Reset Register */
+#define MTK_RST_GL		0x04
+#define RST_GL_PSE		BIT(0)
+
+/* Frame Engine Interrupt Status Register */
+#define MTK_INT_STATUS		0x08
+#define MTK_INT_STATUS2		0x28
+#define MTK_GDM1_AF		BIT(28)
+#define MTK_GDM2_AF		BIT(29)
+
+/* PDMA HW LRO Alter Flow Timer Register */
+#define MTK_PDMA_LRO_ALT_REFRESH_TIMER	0x1c
+
+/* Frame Engine Interrupt Grouping Register */
+#define MTK_FE_INT_GRP		0x20
+
+/* Frame Engine LRO auto-learn table info */
+#define MTK_FE_ALT_CF8		0x300
+#define MTK_FE_ALT_SGL_CFC	0x304
+#define MTK_FE_ALT_SEQ_CFC	0x308
+
+/* CDMP Ingress Control Register */
+#define MTK_CDMQ_IG_CTRL	0x1400
+#define MTK_CDMQ_STAG_EN	BIT(0)
+
+/* CDMP Ingress Control Register */
+#define MTK_CDMP_IG_CTRL	0x400
+#define MTK_CDMP_STAG_EN	BIT(0)
+
+/* CDMP Exgress Control Register */
+#define MTK_CDMP_EG_CTRL	0x404
+
+/* GDM Exgress Control Register */
+#define MTK_GDMA_FWD_CFG(x)	(0x500 + (x * 0x1000))
+#define MTK_GDMA_SPECIAL_TAG	BIT(24)
+#define MTK_GDMA_ICS_EN		BIT(22)
+#define MTK_GDMA_TCS_EN		BIT(21)
+#define MTK_GDMA_UCS_EN		BIT(20)
+#define MTK_GDMA_TO_PDMA	0x0
+#define MTK_GDMA_DROP_ALL	0x7777
+
+/* Unicast Filter MAC Address Register - Low */
+#define MTK_GDMA_MAC_ADRL(x)	(0x508 + (x * 0x1000))
+
+/* Unicast Filter MAC Address Register - High */
+#define MTK_GDMA_MAC_ADRH(x)	(0x50C + (x * 0x1000))
+
+/* Internal SRAM offset */
+#define MTK_ETH_SRAM_OFFSET	0x40000
+
+/* FE global misc reg*/
+#define MTK_FE_GLO_MISC         0x124
+
+/* PSE Free Queue Flow Control  */
+#define PSE_FQFC_CFG1		0x100
+#define PSE_FQFC_CFG2		0x104
+#define PSE_DROP_CFG		0x108
+
+/* PSE Input Queue Reservation Register*/
+#define PSE_IQ_REV(x)		(0x140 + ((x - 1) * 0x4))
+
+/* PSE Output Queue Threshold Register*/
+#define PSE_OQ_TH(x)		(0x160 + ((x - 1) * 0x4))
+
+/* GDM and CDM Threshold */
+#define MTK_GDM2_THRES		0x1530
+#define MTK_CDMW0_THRES		0x164c
+#define MTK_CDMW1_THRES		0x1650
+#define MTK_CDME0_THRES		0x1654
+#define MTK_CDME1_THRES		0x1658
+#define MTK_CDMM_THRES		0x165c
+
+#define MTK_PDMA_V2		BIT(4)
+
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#define PDMA_BASE               0x6000
+#define QDMA_BASE               0x4400
+#else
+#define PDMA_BASE               0x0800
+#define QDMA_BASE               0x1800
+#endif
+/* PDMA RX Base Pointer Register */
+#define MTK_PRX_BASE_PTR0	(PDMA_BASE + 0x100)
+#define MTK_PRX_BASE_PTR_CFG(x)	(MTK_PRX_BASE_PTR0 + (x * 0x10))
+
+/* PDMA RX Maximum Count Register */
+#define MTK_PRX_MAX_CNT0	(MTK_PRX_BASE_PTR0 + 0x04)
+#define MTK_PRX_MAX_CNT_CFG(x)	(MTK_PRX_MAX_CNT0 + (x * 0x10))
+
+/* PDMA RX CPU Pointer Register */
+#define MTK_PRX_CRX_IDX0	(MTK_PRX_BASE_PTR0 + 0x08)
+#define MTK_PRX_CRX_IDX_CFG(x)	(MTK_PRX_CRX_IDX0 + (x * 0x10))
+
+/* PDMA RX DMA Pointer Register */
+#define MTK_PRX_DRX_IDX0	(MTK_PRX_BASE_PTR0 + 0x0c)
+#define MTK_PRX_DRX_IDX_CFG(x)	(MTK_PRX_DRX_IDX0 + (x * 0x10))
+
+/* PDMA HW LRO Control Registers */
+#define BITS(m, n)			(~(BIT(m) - 1) & ((BIT(n) - 1) | BIT(n)))
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#define MTK_MAX_RX_RING_NUM		(8)
+#define MTK_HW_LRO_RING_NUM		(4)
+#define IS_HW_LRO_RING(ring_no)		(((ring_no) > 3) && ((ring_no) < 8))
+#define MTK_PDMA_LRO_CTRL_DW0		(PDMA_BASE + 0x408)
+#define MTK_LRO_ALT_SCORE_DELTA		(PDMA_BASE + 0x41c)
+#define MTK_LRO_RX_RING0_CTRL_DW1	(PDMA_BASE + 0x438)
+#define MTK_LRO_RX_RING0_CTRL_DW2	(PDMA_BASE + 0x43c)
+#define MTK_LRO_RX_RING0_CTRL_DW3	(PDMA_BASE + 0x440)
+#define MTK_L3_CKS_UPD_EN		BIT(19)
+#define MTK_LRO_CRSN_BNW		BIT(22)
+#define MTK_LRO_RING_RELINGUISH_REQ	(0xf << 24)
+#define MTK_LRO_RING_RELINGUISH_DONE	(0xf << 28)
+#else
+#define MTK_MAX_RX_RING_NUM		(4)
+#define MTK_HW_LRO_RING_NUM		(3)
+#define IS_HW_LRO_RING(ring_no)		(((ring_no) > 0) && ((ring_no) < 4))
+#define MTK_PDMA_LRO_CTRL_DW0		(PDMA_BASE + 0x180)
+#define MTK_LRO_ALT_SCORE_DELTA		(PDMA_BASE + 0x24c)
+#define MTK_LRO_RX_RING0_CTRL_DW1	(PDMA_BASE + 0x328)
+#define MTK_LRO_RX_RING0_CTRL_DW2	(PDMA_BASE + 0x32c)
+#define MTK_LRO_RX_RING0_CTRL_DW3	(PDMA_BASE + 0x330)
+#define MTK_LRO_CRSN_BNW		BIT(6)
+#define MTK_L3_CKS_UPD_EN		BIT(7)
+#define MTK_LRO_RING_RELINGUISH_REQ	(0x7 << 26)
+#define MTK_LRO_RING_RELINGUISH_DONE	(0x7 << 29)
+#endif
+
+#define IS_NORMAL_RING(ring_no)		((ring_no) == 0)
+#define MTK_LRO_EN			BIT(0)
+#define MTK_NON_LRO_MULTI_EN   		BIT(2)
+#define MTK_LRO_DLY_INT_EN		BIT(5)
+#define MTK_LRO_ALT_PKT_CNT_MODE	BIT(21)
+#define MTK_LRO_L4_CTRL_PSH_EN		BIT(23)
+#define MTK_CTRL_DW0_SDL_OFFSET		(3)
+#define MTK_CTRL_DW0_SDL_MASK		BITS(3, 18)
+
+#define MTK_PDMA_LRO_CTRL_DW1	(MTK_PDMA_LRO_CTRL_DW0 + 0x04)
+#define MTK_PDMA_LRO_CTRL_DW2	(MTK_PDMA_LRO_CTRL_DW0 + 0x08)
+#define MTK_PDMA_LRO_CTRL_DW3	(MTK_PDMA_LRO_CTRL_DW0 + 0x0c)
+#define MTK_ADMA_MODE		BIT(15)
+#define MTK_LRO_MIN_RXD_SDL	(MTK_HW_LRO_SDL_REMAIN_ROOM << 16)
+
+/* PDMA RSS Control Registers */
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#define MTK_PDMA_RSS_GLO_CFG		(PDMA_BASE + 0x800)
+#define MTK_RX_NAPI_NUM			(2)
+#define MTK_MAX_IRQ_NUM			(4)
+#else
+#define MTK_PDMA_RSS_GLO_CFG		0x3000
+#define MTK_RX_NAPI_NUM			(1)
+#define MTK_MAX_IRQ_NUM			(3)
+#endif
+#define MTK_RSS_RING1			(1)
+#define MTK_RSS_EN			BIT(0)
+#define MTK_RSS_CFG_REQ			BIT(2)
+#define MTK_RSS_IPV6_STATIC_HASH	(0x7 << 8)
+#define MTK_RSS_IPV4_STATIC_HASH	(0x7 << 12)
+#define MTK_RSS_INDR_TABLE_DW0		(MTK_PDMA_RSS_GLO_CFG + 0x50)
+#define MTK_RSS_INDR_TABLE_DW1		(MTK_PDMA_RSS_GLO_CFG + 0x54)
+#define MTK_RSS_INDR_TABLE_DW2		(MTK_PDMA_RSS_GLO_CFG + 0x58)
+#define MTK_RSS_INDR_TABLE_DW3		(MTK_PDMA_RSS_GLO_CFG + 0x5C)
+#define MTK_RSS_INDR_TABLE_DW4		(MTK_PDMA_RSS_GLO_CFG + 0x60)
+#define MTK_RSS_INDR_TABLE_DW5		(MTK_PDMA_RSS_GLO_CFG + 0x64)
+#define MTK_RSS_INDR_TABLE_DW6		(MTK_PDMA_RSS_GLO_CFG + 0x68)
+#define MTK_RSS_INDR_TABLE_DW7		(MTK_PDMA_RSS_GLO_CFG + 0x6C)
+#define MTK_RSS_INDR_TABLE_SIZE4	0x44444444
+
+/* PDMA Global Configuration Register */
+#define MTK_PDMA_GLO_CFG	(PDMA_BASE + 0x204)
+#define MTK_RX_DMA_LRO_EN	BIT(8)
+#define MTK_MULTI_EN		BIT(10)
+#define MTK_PDMA_SIZE_8DWORDS	(1 << 4)
+
+/* PDMA Global Configuration Register */
+#define MTK_PDMA_RX_CFG		(PDMA_BASE + 0x210)
+#define MTK_PDMA_LRO_SDL	(0x3000)
+#define MTK_RX_CFG_SDL_OFFSET	(16)
+
+/* PDMA Reset Index Register */
+#define MTK_PDMA_RST_IDX	(PDMA_BASE + 0x208)
+#define MTK_PST_DRX_IDX0	BIT(16)
+#define MTK_PST_DRX_IDX_CFG(x)	(MTK_PST_DRX_IDX0 << (x))
+
+/* PDMA Delay Interrupt Register */
+#define MTK_PDMA_DELAY_INT		(PDMA_BASE + 0x20c)
+#define MTK_PDMA_DELAY_RX_EN		BIT(15)
+#define MTK_PDMA_DELAY_RX_PINT		4
+#define MTK_PDMA_DELAY_RX_PINT_SHIFT	8
+#define MTK_PDMA_DELAY_RX_PTIME		4
+#define MTK_PDMA_DELAY_RX_DELAY		\
+	(MTK_PDMA_DELAY_RX_EN | MTK_PDMA_DELAY_RX_PTIME | \
+	(MTK_PDMA_DELAY_RX_PINT << MTK_PDMA_DELAY_RX_PINT_SHIFT))
+
+/* PDMA Interrupt Status Register */
+#define MTK_PDMA_INT_STATUS	(PDMA_BASE + 0x220)
+
+/* PDMA Interrupt Mask Register */
+#define MTK_PDMA_INT_MASK	(PDMA_BASE + 0x228)
+
+/* PDMA Interrupt grouping registers */
+#define MTK_PDMA_INT_GRP1	(PDMA_BASE + 0x250)
+#define MTK_PDMA_INT_GRP2	(PDMA_BASE + 0x254)
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#define MTK_PDMA_INT_GRP3	(PDMA_BASE + 0x258)
+#else
+#define MTK_PDMA_INT_GRP3	(PDMA_BASE + 0x22c)
+#endif
+#define MTK_LRO_RX1_DLY_INT	0xa70
+#define MTK_MAX_DELAY_INT	0x8f0f8f0f
+
+/* PDMA HW LRO IP Setting Registers */
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#define MTK_LRO_RX_RING0_DIP_DW0	(PDMA_BASE + 0x414)
+#else
+#define MTK_LRO_RX_RING0_DIP_DW0	(PDMA_BASE + 0x304)
+#endif
+#define MTK_LRO_DIP_DW0_CFG(x)		(MTK_LRO_RX_RING0_DIP_DW0 + (x * 0x40))
+#define MTK_RING_MYIP_VLD		BIT(9)
+
+/* PDMA HW LRO ALT Debug Registers */
+#define MTK_LRO_ALT_DBG			(PDMA_BASE + 0x440)
+#define MTK_LRO_ALT_INDEX_OFFSET	(8)
+
+/* PDMA HW LRO ALT Data Registers */
+#define MTK_LRO_ALT_DBG_DATA		(PDMA_BASE + 0x444)
+
+/* PDMA HW LRO Ring Control Registers */
+#define MTK_LRO_CTRL_DW1_CFG(x)		(MTK_LRO_RX_RING0_CTRL_DW1 + (x * 0x40))
+#define MTK_LRO_CTRL_DW2_CFG(x)		(MTK_LRO_RX_RING0_CTRL_DW2 + (x * 0x40))
+#define MTK_LRO_CTRL_DW3_CFG(x)		(MTK_LRO_RX_RING0_CTRL_DW3 + (x * 0x40))
+#define MTK_RING_AGE_TIME_L		((MTK_HW_LRO_AGE_TIME & 0x3ff) << 22)
+#define MTK_RING_AGE_TIME_H		((MTK_HW_LRO_AGE_TIME >> 10) & 0x3f)
+#define MTK_RING_PSE_MODE        	(1 << 6)
+#define MTK_RING_AUTO_LERAN_MODE	(3 << 6)
+#define MTK_RING_VLD			BIT(8)
+#define MTK_RING_MAX_AGG_TIME		((MTK_HW_LRO_AGG_TIME & 0xffff) << 10)
+#define MTK_RING_MAX_AGG_CNT_L		((MTK_HW_LRO_MAX_AGG_CNT & 0x3f) << 26)
+#define MTK_RING_MAX_AGG_CNT_H		((MTK_HW_LRO_MAX_AGG_CNT >> 6) & 0x3)
+
+/* LRO_RX_RING_CTRL_DW masks */
+#define MTK_LRO_RING_AGG_TIME_MASK	BITS(10, 25)
+#define MTK_LRO_RING_AGG_CNT_L_MASK	BITS(26, 31)
+#define MTK_LRO_RING_AGG_CNT_H_MASK	BITS(0, 1)
+#define MTK_LRO_RING_AGE_TIME_L_MASK	BITS(22, 31)
+#define MTK_LRO_RING_AGE_TIME_H_MASK	BITS(0, 5)
+
+/* LRO_RX_RING_CTRL_DW0 offsets */
+#define MTK_RX_IPV6_FORCE_OFFSET	(0)
+#define MTK_RX_IPV4_FORCE_OFFSET	(1)
+
+/* LRO_RX_RING_CTRL_DW1 offsets  */
+#define MTK_LRO_RING_AGE_TIME_L_OFFSET	(22)
+
+/* LRO_RX_RING_CTRL_DW2 offsets  */
+#define MTK_LRO_RING_AGE_TIME_H_OFFSET	(0)
+#define MTK_RX_MODE_OFFSET		(6)
+#define MTK_RX_PORT_VALID_OFFSET	(8)
+#define MTK_RX_MYIP_VALID_OFFSET	(9)
+#define MTK_LRO_RING_AGG_TIME_OFFSET	(10)
+#define MTK_LRO_RING_AGG_CNT_L_OFFSET	(26)
+
+/* LRO_RX_RING_CTRL_DW3 offsets  */
+#define MTK_LRO_RING_AGG_CNT_H_OFFSET	(0)
+
+/* LRO_RX_RING_STP_DTP_DW offsets */
+#define MTK_RX_TCP_DEST_PORT_OFFSET	(0)
+#define MTK_RX_TCP_SRC_PORT_OFFSET	(16)
+
+/* QDMA TX Queue Configuration Registers */
+#define MTK_QTX_CFG(x)		(QDMA_BASE + (x * 0x10))
+#define QDMA_RES_THRES		4
+
+/* QDMA TX Queue Scheduler Registers */
+#define MTK_QTX_SCH(x)		(QDMA_BASE + 4 + (x * 0x10))
+
+/* QDMA RX Base Pointer Register */
+#define MTK_QRX_BASE_PTR0	(QDMA_BASE + 0x100)
+#define MTK_QRX_BASE_PTR_CFG(x)	(MTK_QRX_BASE_PTR0 + ((x) * 0x10))
+
+/* QDMA RX Maximum Count Register */
+#define MTK_QRX_MAX_CNT0	(QDMA_BASE + 0x104)
+#define MTK_QRX_MAX_CNT_CFG(x)	(MTK_QRX_MAX_CNT0 + ((x) * 0x10))
+
+/* QDMA RX CPU Pointer Register */
+#define MTK_QRX_CRX_IDX0	(QDMA_BASE + 0x108)
+#define MTK_QRX_CRX_IDX_CFG(x)	(MTK_QRX_CRX_IDX0 + ((x) * 0x10))
+
+/* QDMA RX DMA Pointer Register */
+#define MTK_QRX_DRX_IDX0	(QDMA_BASE + 0x10c)
+
+/* QDMA Global Configuration Register */
+#define MTK_QDMA_GLO_CFG	(QDMA_BASE + 0x204)
+#define MTK_RX_2B_OFFSET	BIT(31)
+#define MTK_RX_BT_32DWORDS	(3 << 11)
+#define MTK_NDP_CO_PRO		BIT(10)
+#define MTK_TX_WB_DDONE		BIT(6)
+#define MTK_DMA_SIZE_16DWORDS	(2 << 4)
+#define MTK_DMA_SIZE_32DWORDS	(3 << 4)
+#define MTK_RX_DMA_BUSY		BIT(3)
+#define MTK_TX_DMA_BUSY		BIT(1)
+#define MTK_RX_DMA_EN		BIT(2)
+#define MTK_TX_DMA_EN		BIT(0)
+#define MTK_DMA_BUSY_TIMEOUT	HZ
+
+/* QDMA V2 Global Configuration Register */
+#define MTK_CHK_DDONE_EN	BIT(28)
+#define MTK_DMAD_WR_WDONE	BIT(26)
+#define MTK_WCOMP_EN		BIT(24)
+#define MTK_RESV_BUF		(0x40 << 16)
+#define MTK_MUTLI_CNT		(0x4 << 12)
+
+/* QDMA Reset Index Register */
+#define MTK_QDMA_RST_IDX	(QDMA_BASE + 0x208)
+
+/* QDMA Delay Interrupt Register */
+#define MTK_QDMA_DELAY_INT	(QDMA_BASE + 0x20c)
+
+/* QDMA Flow Control Register */
+#define MTK_QDMA_FC_THRES	(QDMA_BASE + 0x210)
+#define FC_THRES_DROP_MODE	BIT(20)
+#define FC_THRES_DROP_EN	(7 << 16)
+#define FC_THRES_MIN		0x4444
+
+/* QDMA Interrupt Status Register */
+#define MTK_QDMA_INT_STATUS	(QDMA_BASE + 0x218)
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#define MTK_RX_DONE_INT(ring_no)		\
+	((ring_no)? BIT(16 + (ring_no)) : BIT(14))
+#else
+#define MTK_RX_DONE_INT(ring_no)		\
+	((ring_no)? BIT(24 + (ring_no)) : BIT(30))
+#endif
+#define MTK_RX_DONE_INT3	BIT(19)
+#define MTK_RX_DONE_INT2	BIT(18)
+#define MTK_RX_DONE_INT1	BIT(17)
+#define MTK_RX_DONE_INT0	BIT(16)
+#define MTK_TX_DONE_INT3	BIT(3)
+#define MTK_TX_DONE_INT2	BIT(2)
+#define MTK_TX_DONE_INT1	BIT(1)
+#define MTK_TX_DONE_INT0	BIT(0)
+#define MTK_TX_DONE_DLY         BIT(28)
+#define MTK_TX_DONE_INT         MTK_TX_DONE_DLY
+
+/* QDMA Interrupt grouping registers */
+#define MTK_QDMA_INT_GRP1	(QDMA_BASE + 0x220)
+#define MTK_QDMA_INT_GRP2	(QDMA_BASE + 0x224)
+#define MTK_RLS_DONE_INT	BIT(0)
+
+/* QDMA Interrupt Status Register */
+#define MTK_QDMA_INT_MASK	(QDMA_BASE + 0x21c)
+
+/* QDMA Interrupt Mask Register */
+#define MTK_QDMA_HRED2		(QDMA_BASE + 0x244)
+
+/* QDMA TX Forward CPU Pointer Register */
+#define MTK_QTX_CTX_PTR		(QDMA_BASE +0x300)
+
+/* QDMA TX Forward DMA Pointer Register */
+#define MTK_QTX_DTX_PTR		(QDMA_BASE +0x304)
+
+/* QDMA TX Release CPU Pointer Register */
+#define MTK_QTX_CRX_PTR		(QDMA_BASE +0x310)
+
+/* QDMA TX Release DMA Pointer Register */
+#define MTK_QTX_DRX_PTR		(QDMA_BASE +0x314)
+
+/* QDMA FQ Head Pointer Register */
+#define MTK_QDMA_FQ_HEAD	(QDMA_BASE +0x320)
+
+/* QDMA FQ Head Pointer Register */
+#define MTK_QDMA_FQ_TAIL	(QDMA_BASE +0x324)
+
+/* QDMA FQ Free Page Counter Register */
+#define MTK_QDMA_FQ_CNT		(QDMA_BASE +0x328)
+
+/* QDMA FQ Free Page Buffer Length Register */
+#define MTK_QDMA_FQ_BLEN	(QDMA_BASE +0x32c)
+
+/* GMA1 Received Good Byte Count Register */
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#define MTK_GDM1_TX_GBCNT       0x1C00
+#else
+#define MTK_GDM1_TX_GBCNT	0x2400
+#endif
+#define MTK_STAT_OFFSET		0x40
+
+/* QDMA TX NUM */
+#define MTK_QDMA_TX_NUM		16
+#define MTK_QDMA_TX_MASK	((MTK_QDMA_TX_NUM) - 1)
+#define QID_LOW_BITS(x)         ((x) & 0xf)
+#define QID_HIGH_BITS(x)        ((((x) >> 4) & 0x3) << 20)
+#define QID_BITS_V2(x)		(((x) & 0x3f) << 16)
+
+#define MTK_QDMA_GMAC2_QID	8
+
+/* QDMA V2 descriptor txd6 */
+#define TX_DMA_INS_VLAN_V2         BIT(16)
+
+/* QDMA V2 descriptor txd5 */
+#define TX_DMA_CHKSUM_V2           (0x7 << 28)
+#define TX_DMA_TSO_V2              BIT(31)
+
+/* QDMA V2 descriptor txd4 */
+#define TX_DMA_FPORT_SHIFT_V2      8
+#define TX_DMA_FPORT_MASK_V2       0xf
+#define TX_DMA_SWC_V2              BIT(30)
+
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#define MTK_TX_DMA_BUF_LEN      0xffff
+#define MTK_TX_DMA_BUF_SHIFT    8
+#else
+#define MTK_TX_DMA_BUF_LEN      0x3fff
+#define MTK_TX_DMA_BUF_SHIFT    16
+#endif
+
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#define MTK_RX_DMA_BUF_LEN      0xffff
+#define MTK_RX_DMA_BUF_SHIFT    8
+#define RX_DMA_SPORT_SHIFT      26
+#define RX_DMA_SPORT_MASK       0xf
+#else
+#define MTK_RX_DMA_BUF_LEN      0x3fff
+#define MTK_RX_DMA_BUF_SHIFT    16
+#define RX_DMA_SPORT_SHIFT      19
+#define RX_DMA_SPORT_MASK       0x7
+#endif
+
+/* QDMA descriptor txd4 */
+#define TX_DMA_CHKSUM		(0x7 << 29)
+#define TX_DMA_TSO		BIT(28)
+#define TX_DMA_FPORT_SHIFT	25
+#define TX_DMA_FPORT_MASK	0x7
+#define TX_DMA_INS_VLAN		BIT(16)
+
+/* QDMA descriptor txd3 */
+#define TX_DMA_OWNER_CPU	BIT(31)
+#define TX_DMA_LS0		BIT(30)
+#define TX_DMA_PLEN0(_x)	(((_x) & MTK_TX_DMA_BUF_LEN) << MTK_TX_DMA_BUF_SHIFT)
+#define TX_DMA_PLEN1(_x)	((_x) & MTK_TX_DMA_BUF_LEN)
+#define TX_DMA_SWC		BIT(14)
+#define TX_DMA_SDL(_x)		(TX_DMA_PLEN0(_x))
+
+/* PDMA on MT7628 */
+#define TX_DMA_DONE		BIT(31)
+#define TX_DMA_LS1		BIT(14)
+#define TX_DMA_DESP2_DEF	(TX_DMA_LS0 | TX_DMA_DONE)
+
+/* QDMA descriptor rxd2 */
+#define RX_DMA_DONE		BIT(31)
+#define RX_DMA_LSO		BIT(30)
+#define RX_DMA_PLEN0(_x)	(((_x) & MTK_RX_DMA_BUF_LEN) << MTK_RX_DMA_BUF_SHIFT)
+#define RX_DMA_GET_PLEN0(_x)	(((_x) >> MTK_RX_DMA_BUF_SHIFT) & MTK_RX_DMA_BUF_LEN)
+#define RX_DMA_GET_AGG_CNT(_x)	(((_x) >> 2) & 0xff)
+#define RX_DMA_GET_REV(_x)	(((_x) >> 10) & 0x1f)
+#define RX_DMA_VTAG		BIT(15)
+
+/* QDMA descriptor rxd3 */
+#define RX_DMA_VID(_x)		((_x) & VLAN_VID_MASK)
+#define RX_DMA_TCI(_x)		((_x) & (VLAN_PRIO_MASK | VLAN_VID_MASK))
+#define RX_DMA_VPID(_x)		(((_x) >> 16) & 0xffff)
+
+/* QDMA descriptor rxd4 */
+#define RX_DMA_L4_VALID		BIT(24)
+#define RX_DMA_L4_VALID_PDMA	BIT(30)		/* when PDMA is used */
+#define RX_DMA_SPECIAL_TAG	BIT(22)		/* switch header in packet */
+
+#define RX_DMA_GET_SPORT(_x) 	(((_x) >> RX_DMA_SPORT_SHIFT) & RX_DMA_SPORT_MASK)
+
+/* PDMA V2 descriptor rxd3 */
+#define RX_DMA_VTAG_V2          BIT(0)
+#define RX_DMA_L4_VALID_V2      BIT(2)
+
+/* PDMA V2 descriptor rxd4 */
+#define RX_DMA_VID_V2(_x)       RX_DMA_VID(_x)
+#define RX_DMA_TCI_V2(_x)	RX_DMA_TCI(_x)
+#define RX_DMA_VPID_V2(_x)	RX_DMA_VPID(_x)
+
+/* PDMA V2 descriptor rxd6 */
+#define RX_DMA_GET_FLUSH_RSN_V2(_x)	((_x) & 0x7)
+#define RX_DMA_GET_AGG_CNT_V2(_x)	(((_x) >> 16) & 0xff)
+
+/* PHY Indirect Access Control registers */
+#define MTK_PHY_IAC		0x10004
+#define PHY_IAC_ACCESS		BIT(31)
+#define PHY_IAC_READ		BIT(19)
+#define PHY_IAC_WRITE		BIT(18)
+#define PHY_IAC_START		BIT(16)
+#define PHY_IAC_ADDR_SHIFT	20
+#define PHY_IAC_REG_SHIFT	25
+#define PHY_IAC_TIMEOUT		HZ
+
+#define MTK_MAC_MISC		0x1000c
+#define MTK_MUX_TO_ESW		BIT(0)
+
+/* Mac control registers */
+#define MTK_MAC_MCR(x)		(0x10100 + (x * 0x100))
+#define MAC_MCR_MAX_RX_1536	BIT(24)
+#define MAC_MCR_IPG_CFG		(BIT(18) | BIT(16))
+#define MAC_MCR_FORCE_MODE	BIT(15)
+#define MAC_MCR_TX_EN		BIT(14)
+#define MAC_MCR_RX_EN		BIT(13)
+#define MAC_MCR_BACKOFF_EN	BIT(9)
+#define MAC_MCR_BACKPR_EN	BIT(8)
+#define MAC_MCR_FORCE_RX_FC	BIT(5)
+#define MAC_MCR_FORCE_TX_FC	BIT(4)
+#define MAC_MCR_SPEED_1000	BIT(3)
+#define MAC_MCR_SPEED_100	BIT(2)
+#define MAC_MCR_FORCE_DPX	BIT(1)
+#define MAC_MCR_FORCE_LINK	BIT(0)
+#define MAC_MCR_FORCE_LINK_DOWN	(MAC_MCR_FORCE_MODE)
+
+/* Mac status registers */
+#define MTK_MAC_MSR(x)		(0x10108 + (x * 0x100))
+#define MAC_MSR_EEE1G		BIT(7)
+#define MAC_MSR_EEE100M		BIT(6)
+#define MAC_MSR_RX_FC		BIT(5)
+#define MAC_MSR_TX_FC		BIT(4)
+#define MAC_MSR_SPEED_1000	BIT(3)
+#define MAC_MSR_SPEED_100	BIT(2)
+#define MAC_MSR_SPEED_MASK	(MAC_MSR_SPEED_1000 | MAC_MSR_SPEED_100)
+#define MAC_MSR_DPX		BIT(1)
+#define MAC_MSR_LINK		BIT(0)
+
+/* TRGMII RXC control register */
+#define TRGMII_RCK_CTRL		0x10300
+#define DQSI0(x)		((x << 0) & GENMASK(6, 0))
+#define DQSI1(x)		((x << 8) & GENMASK(14, 8))
+#define RXCTL_DMWTLAT(x)	((x << 16) & GENMASK(18, 16))
+#define RXC_RST			BIT(31)
+#define RXC_DQSISEL		BIT(30)
+#define RCK_CTRL_RGMII_1000	(RXC_DQSISEL | RXCTL_DMWTLAT(2) | DQSI1(16))
+#define RCK_CTRL_RGMII_10_100	RXCTL_DMWTLAT(2)
+
+#define NUM_TRGMII_CTRL		5
+
+/* TRGMII RXC control register */
+#define TRGMII_TCK_CTRL		0x10340
+#define TXCTL_DMWTLAT(x)	((x << 16) & GENMASK(18, 16))
+#define TXC_INV			BIT(30)
+#define TCK_CTRL_RGMII_1000	TXCTL_DMWTLAT(2)
+#define TCK_CTRL_RGMII_10_100	(TXC_INV | TXCTL_DMWTLAT(2))
+
+/* TRGMII TX Drive Strength */
+#define TRGMII_TD_ODT(i)	(0x10354 + 8 * (i))
+#define  TD_DM_DRVP(x)		((x) & 0xf)
+#define  TD_DM_DRVN(x)		(((x) & 0xf) << 4)
+
+/* TRGMII Interface mode register */
+#define INTF_MODE		0x10390
+#define TRGMII_INTF_DIS		BIT(0)
+#define TRGMII_MODE		BIT(1)
+#define TRGMII_CENTRAL_ALIGNED	BIT(2)
+#define INTF_MODE_RGMII_1000    (TRGMII_MODE | TRGMII_CENTRAL_ALIGNED)
+#define INTF_MODE_RGMII_10_100  0
+
+/* GPIO port control registers for GMAC 2*/
+#define GPIO_OD33_CTRL8		0x4c0
+#define GPIO_BIAS_CTRL		0xed0
+#define GPIO_DRV_SEL10		0xf00
+
+/* ethernet subsystem chip id register */
+#define ETHSYS_CHIPID0_3	0x0
+#define ETHSYS_CHIPID4_7	0x4
+#define MT7623_ETH		7623
+#define MT7622_ETH		7622
+#define MT7621_ETH		7621
+
+/* ethernet system control register */
+#define ETHSYS_SYSCFG		0x10
+#define SYSCFG_DRAM_TYPE_DDR2	BIT(4)
+
+/* ethernet subsystem config register */
+#define ETHSYS_SYSCFG0		0x14
+#define SYSCFG0_GE_MASK		0x3
+#define SYSCFG0_GE_MODE(x, y)	(x << (12 + (y * 2)))
+#define SYSCFG0_SGMII_MASK     GENMASK(9, 8)
+#define SYSCFG0_SGMII_GMAC1    ((2 << 8) & SYSCFG0_SGMII_MASK)
+#define SYSCFG0_SGMII_GMAC2    ((3 << 8) & SYSCFG0_SGMII_MASK)
+#define SYSCFG0_SGMII_GMAC1_V2 BIT(9)
+#define SYSCFG0_SGMII_GMAC2_V2 BIT(8)
+
+
+/* ethernet subsystem clock register */
+#define ETHSYS_CLKCFG0		0x2c
+#define ETHSYS_TRGMII_CLK_SEL362_5	BIT(11)
+#define ETHSYS_TRGMII_MT7621_MASK	(BIT(5) | BIT(6))
+#define ETHSYS_TRGMII_MT7621_APLL	BIT(6)
+#define ETHSYS_TRGMII_MT7621_DDR_PLL	BIT(5)
+
+/* ethernet reset control register */
+#define ETHSYS_RSTCTRL	0x34
+#define RSTCTRL_FE	BIT(6)
+#define RSTCTRL_PPE	BIT(31)
+#define RSTCTRL_PPE1 	BIT(30)
+#define RSTCTRL_ETH 	BIT(23)
+
+/* ethernet reset check idle register */
+#define ETHSYS_FE_RST_CHK_IDLE_EN 	0x28
+
+
+/* SGMII subsystem config registers */
+/* Register to auto-negotiation restart */
+#define SGMSYS_PCS_CONTROL_1	0x0
+#define SGMII_AN_RESTART	BIT(9)
+#define SGMII_ISOLATE		BIT(10)
+#define SGMII_AN_ENABLE		BIT(12)
+#define SGMII_LINK_STATYS	BIT(18)
+#define SGMII_AN_ABILITY	BIT(19)
+#define SGMII_AN_COMPLETE	BIT(21)
+#define SGMII_PCS_FAULT		BIT(23)
+#define SGMII_AN_EXPANSION_CLR	BIT(30)
+
+/* Register to programmable link timer, the unit in 2 * 8ns */
+#define SGMSYS_PCS_LINK_TIMER	0x18
+#define SGMII_LINK_TIMER_DEFAULT	(0x186a0 & GENMASK(19, 0))
+
+/* Register to control remote fault */
+#define SGMSYS_SGMII_MODE		0x20
+#define SGMII_IF_MODE_BIT0		BIT(0)
+#define SGMII_SPEED_DUPLEX_AN		BIT(1)
+#define SGMII_SPEED_10			0x0
+#define SGMII_SPEED_100			BIT(2)
+#define SGMII_SPEED_1000		BIT(3)
+#define SGMII_DUPLEX_FULL		BIT(4)
+#define SGMII_IF_MODE_BIT5		BIT(5)
+#define SGMII_REMOTE_FAULT_DIS		BIT(8)
+#define SGMII_CODE_SYNC_SET_VAL		BIT(9)
+#define SGMII_CODE_SYNC_SET_EN		BIT(10)
+#define SGMII_SEND_AN_ERROR_EN		BIT(11)
+#define SGMII_IF_MODE_MASK		GENMASK(5, 1)
+
+/* Register to set SGMII speed, ANA RG_ Control Signals III*/
+#define SGMSYS_ANA_RG_CS3	0x2028
+#define RG_PHY_SPEED_MASK	(BIT(2) | BIT(3))
+#define RG_PHY_SPEED_1_25G	0x0
+#define RG_PHY_SPEED_3_125G	BIT(2)
+
+/* Register to power up QPHY */
+#define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8
+#define	SGMII_PHYA_PWD		BIT(4)
+
+/* Register to QPHY wrapper control */
+#define SGMSYS_QPHY_WRAP_CTRL	0xec
+#define SGMII_PN_SWAP_MASK	GENMASK(1, 0)
+#define SGMII_PN_SWAP_TX_RX	(BIT(0) | BIT(1))
+
+/* Infrasys subsystem config registers */
+#define INFRA_MISC2            0x70c
+#define CO_QPHY_SEL            BIT(0)
+#define GEPHY_MAC_SEL          BIT(1)
+
+/* Top misc registers */
+#define USB_PHY_SWITCH_REG     0x218
+#define QPHY_SEL_MASK          GENMASK(1, 0)
+#define SGMII_QPHY_SEL	       0x2
+
+/*MDIO control*/
+#define MII_MMD_ACC_CTL_REG             0x0d
+#define MII_MMD_ADDR_DATA_REG           0x0e
+#define MMD_OP_MODE_DATA BIT(14)
+
+/* MT7628/88 specific stuff */
+#define MT7628_PDMA_OFFSET	0x0800
+#define MT7628_SDM_OFFSET	0x0c00
+
+#define MT7628_TX_BASE_PTR0	(MT7628_PDMA_OFFSET + 0x00)
+#define MT7628_TX_MAX_CNT0	(MT7628_PDMA_OFFSET + 0x04)
+#define MT7628_TX_CTX_IDX0	(MT7628_PDMA_OFFSET + 0x08)
+#define MT7628_TX_DTX_IDX0	(MT7628_PDMA_OFFSET + 0x0c)
+#define MT7628_PST_DTX_IDX0	BIT(0)
+
+#define MT7628_SDM_MAC_ADRL	(MT7628_SDM_OFFSET + 0x0c)
+#define MT7628_SDM_MAC_ADRH	(MT7628_SDM_OFFSET + 0x10)
+
+struct mtk_rx_dma {
+	unsigned int rxd1;
+	unsigned int rxd2;
+	unsigned int rxd3;
+	unsigned int rxd4;
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+	unsigned int rxd5;
+	unsigned int rxd6;
+	unsigned int rxd7;
+	unsigned int rxd8;
+#endif
+} __packed __aligned(4);
+
+struct mtk_tx_dma {
+	unsigned int txd1;
+	unsigned int txd2;
+	unsigned int txd3;
+	unsigned int txd4;
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+	unsigned int txd5;
+	unsigned int txd6;
+	unsigned int txd7;
+	unsigned int txd8;
+#endif
+} __packed __aligned(4);
+
+struct mtk_eth;
+struct mtk_mac;
+
+/* struct mtk_hw_stats - the structure that holds the traffic statistics.
+ * @stats_lock:		make sure that stats operations are atomic
+ * @reg_offset:		the status register offset of the SoC
+ * @syncp:		the refcount
+ *
+ * All of the supported SoCs have hardware counters for traffic statistics.
+ * Whenever the status IRQ triggers we can read the latest stats from these
+ * counters and store them in this struct.
+ */
+struct mtk_hw_stats {
+	u64 tx_bytes;
+	u64 tx_packets;
+	u64 tx_skip;
+	u64 tx_collisions;
+	u64 rx_bytes;
+	u64 rx_packets;
+	u64 rx_overflow;
+	u64 rx_fcs_errors;
+	u64 rx_short_errors;
+	u64 rx_long_errors;
+	u64 rx_checksum_errors;
+	u64 rx_flow_control_packets;
+
+	spinlock_t		stats_lock;
+	u32			reg_offset;
+	struct u64_stats_sync	syncp;
+};
+
+enum mtk_tx_flags {
+	/* PDMA descriptor can point at 1-2 segments. This enum allows us to
+	 * track how memory was allocated so that it can be freed properly.
+	 */
+	MTK_TX_FLAGS_SINGLE0	= 0x01,
+	MTK_TX_FLAGS_PAGE0	= 0x02,
+
+	/* MTK_TX_FLAGS_FPORTx allows tracking which port the transmitted
+	 * SKB out instead of looking up through hardware TX descriptor.
+	 */
+	MTK_TX_FLAGS_FPORT0	= 0x04,
+	MTK_TX_FLAGS_FPORT1	= 0x08,
+};
+
+/* This enum allows us to identify how the clock is defined on the array of the
+ * clock in the order
+ */
+enum mtk_clks_map {
+	MTK_CLK_ETHIF,
+	MTK_CLK_SGMIITOP,
+	MTK_CLK_ESW,
+	MTK_CLK_GP0,
+	MTK_CLK_GP1,
+	MTK_CLK_GP2,
+	MTK_CLK_FE,
+	MTK_CLK_TRGPLL,
+	MTK_CLK_SGMII_TX_250M,
+	MTK_CLK_SGMII_RX_250M,
+	MTK_CLK_SGMII_CDR_REF,
+	MTK_CLK_SGMII_CDR_FB,
+	MTK_CLK_SGMII2_TX_250M,
+	MTK_CLK_SGMII2_RX_250M,
+	MTK_CLK_SGMII2_CDR_REF,
+	MTK_CLK_SGMII2_CDR_FB,
+	MTK_CLK_SGMII_CK,
+	MTK_CLK_ETH2PLL,
+	MTK_CLK_WOCPU0,
+	MTK_CLK_WOCPU1,
+	MTK_CLK_MAX
+};
+
+#define MT7623_CLKS_BITMAP	(BIT(MTK_CLK_ETHIF) | BIT(MTK_CLK_ESW) |  \
+				 BIT(MTK_CLK_GP1) | BIT(MTK_CLK_GP2) | \
+				 BIT(MTK_CLK_TRGPLL))
+#define MT7622_CLKS_BITMAP	(BIT(MTK_CLK_ETHIF) | BIT(MTK_CLK_ESW) |  \
+				 BIT(MTK_CLK_GP0) | BIT(MTK_CLK_GP1) | \
+				 BIT(MTK_CLK_GP2) | \
+				 BIT(MTK_CLK_SGMII_TX_250M) | \
+				 BIT(MTK_CLK_SGMII_RX_250M) | \
+				 BIT(MTK_CLK_SGMII_CDR_REF) | \
+				 BIT(MTK_CLK_SGMII_CDR_FB) | \
+				 BIT(MTK_CLK_SGMII_CK) | \
+				 BIT(MTK_CLK_ETH2PLL))
+#define MT7621_CLKS_BITMAP	(0)
+#define MT7628_CLKS_BITMAP	(0)
+#define MT7629_CLKS_BITMAP	(BIT(MTK_CLK_ETHIF) | BIT(MTK_CLK_ESW) |  \
+				 BIT(MTK_CLK_GP0) | BIT(MTK_CLK_GP1) | \
+				 BIT(MTK_CLK_GP2) | BIT(MTK_CLK_FE) | \
+				 BIT(MTK_CLK_SGMII_TX_250M) | \
+				 BIT(MTK_CLK_SGMII_RX_250M) | \
+				 BIT(MTK_CLK_SGMII_CDR_REF) | \
+				 BIT(MTK_CLK_SGMII_CDR_FB) | \
+				 BIT(MTK_CLK_SGMII2_TX_250M) | \
+				 BIT(MTK_CLK_SGMII2_RX_250M) | \
+				 BIT(MTK_CLK_SGMII2_CDR_REF) | \
+				 BIT(MTK_CLK_SGMII2_CDR_FB) | \
+				 BIT(MTK_CLK_SGMII_CK) | \
+				 BIT(MTK_CLK_ETH2PLL) | BIT(MTK_CLK_SGMIITOP))
+
+#define MT7986_CLKS_BITMAP	(BIT(MTK_CLK_FE) | BIT(MTK_CLK_GP2) | BIT(MTK_CLK_GP1) | \
+                                 BIT(MTK_CLK_WOCPU1) | BIT(MTK_CLK_WOCPU0) | \
+                                 BIT(MTK_CLK_SGMII_TX_250M) | \
+                                 BIT(MTK_CLK_SGMII_RX_250M) | \
+                                 BIT(MTK_CLK_SGMII_CDR_REF) | \
+                                 BIT(MTK_CLK_SGMII_CDR_FB) | \
+                                 BIT(MTK_CLK_SGMII2_TX_250M) | \
+                                 BIT(MTK_CLK_SGMII2_RX_250M) | \
+                                 BIT(MTK_CLK_SGMII2_CDR_REF) | \
+                                 BIT(MTK_CLK_SGMII2_CDR_FB))
+
+
+#define MT7981_CLKS_BITMAP	(BIT(MTK_CLK_FE) | BIT(MTK_CLK_GP2) | BIT(MTK_CLK_GP1) | \
+                                 BIT(MTK_CLK_WOCPU0) | \
+                                 BIT(MTK_CLK_SGMII_TX_250M) | \
+                                 BIT(MTK_CLK_SGMII_RX_250M) | \
+                                 BIT(MTK_CLK_SGMII_CDR_REF) | \
+                                 BIT(MTK_CLK_SGMII_CDR_FB) | \
+                                 BIT(MTK_CLK_SGMII2_TX_250M) | \
+                                 BIT(MTK_CLK_SGMII2_RX_250M) | \
+                                 BIT(MTK_CLK_SGMII2_CDR_REF) | \
+                                 BIT(MTK_CLK_SGMII2_CDR_FB))
+enum mtk_dev_state {
+	MTK_HW_INIT,
+	MTK_RESETTING
+};
+
+/* struct mtk_tx_buf -	This struct holds the pointers to the memory pointed at
+ *			by the TX descriptor	s
+ * @skb:		The SKB pointer of the packet being sent
+ * @dma_addr0:		The base addr of the first segment
+ * @dma_len0:		The length of the first segment
+ * @dma_addr1:		The base addr of the second segment
+ * @dma_len1:		The length of the second segment
+ */
+struct mtk_tx_buf {
+	struct sk_buff *skb;
+	u32 flags;
+	DEFINE_DMA_UNMAP_ADDR(dma_addr0);
+	DEFINE_DMA_UNMAP_LEN(dma_len0);
+	DEFINE_DMA_UNMAP_ADDR(dma_addr1);
+	DEFINE_DMA_UNMAP_LEN(dma_len1);
+};
+
+/* struct mtk_tx_ring -	This struct holds info describing a TX ring
+ * @dma:		The descriptor ring
+ * @buf:		The memory pointed at by the ring
+ * @phys:		The physical addr of tx_buf
+ * @next_free:		Pointer to the next free descriptor
+ * @last_free:		Pointer to the last free descriptor
+ * @last_free_ptr:	Hardware pointer value of the last free descriptor
+ * @thresh:		The threshold of minimum amount of free descriptors
+ * @free_count:		QDMA uses a linked list. Track how many free descriptors
+ *			are present
+ */
+struct mtk_tx_ring {
+	struct mtk_tx_dma *dma;
+	struct mtk_tx_buf *buf;
+	dma_addr_t phys;
+	struct mtk_tx_dma *next_free;
+	struct mtk_tx_dma *last_free;
+	u32 last_free_ptr;
+	u16 thresh;
+	atomic_t free_count;
+	int dma_size;
+	struct mtk_tx_dma *dma_pdma;	/* For MT7628/88 PDMA handling */
+	dma_addr_t phys_pdma;
+	int cpu_idx;
+};
+
+/* PDMA rx ring mode */
+enum mtk_rx_flags {
+	MTK_RX_FLAGS_NORMAL = 0,
+	MTK_RX_FLAGS_HWLRO,
+	MTK_RX_FLAGS_QDMA,
+};
+
+/* struct mtk_rx_ring -	This struct holds info describing a RX ring
+ * @dma:		The descriptor ring
+ * @data:		The memory pointed at by the ring
+ * @phys:		The physical addr of rx_buf
+ * @frag_size:		How big can each fragment be
+ * @buf_size:		The size of each packet buffer
+ * @calc_idx:		The current head of ring
+ * @ring_no:		The index of ring
+ */
+struct mtk_rx_ring {
+	struct mtk_rx_dma *dma;
+	u8 **data;
+	dma_addr_t phys;
+	u16 frag_size;
+	u16 buf_size;
+	u16 dma_size;
+	bool calc_idx_update;
+	u16 calc_idx;
+	u32 crx_idx_reg;
+	u32 ring_no;
+};
+
+/* struct mtk_napi -	This is the structure holding NAPI-related information,
+ *			and a mtk_napi struct is binding to one interrupt group
+ * @napi:		The NAPI struct
+ * @rx_ring:		Pointer to the memory holding info about the RX ring
+ * @irq_grp_idx:	The index indicates which interrupt group that this
+ *			mtk_napi is binding to
+ */
+struct mtk_napi {
+	struct napi_struct	napi;
+	struct mtk_eth		*eth;
+	struct mtk_rx_ring	*rx_ring;
+	u32			irq_grp_no;
+};
+
+enum mkt_eth_capabilities {
+	MTK_RGMII_BIT = 0,
+	MTK_TRGMII_BIT,
+	MTK_SGMII_BIT,
+	MTK_ESW_BIT,
+	MTK_GEPHY_BIT,
+	MTK_MUX_BIT,
+	MTK_INFRA_BIT,
+	MTK_SHARED_SGMII_BIT,
+	MTK_HWLRO_BIT,
+	MTK_RSS_BIT,
+	MTK_SHARED_INT_BIT,
+	MTK_TRGMII_MT7621_CLK_BIT,
+	MTK_QDMA_BIT,
+	MTK_NETSYS_V2_BIT,
+	MTK_SOC_MT7628_BIT,
+	MTK_RSTCTRL_PPE1_BIT,
+	MTK_U3_COPHY_V2_BIT,
+
+	/* MUX BITS*/
+	MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT,
+	MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT,
+	MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT,
+	MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT,
+	MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT,
+
+	/* PATH BITS */
+	MTK_ETH_PATH_GMAC1_RGMII_BIT,
+	MTK_ETH_PATH_GMAC1_TRGMII_BIT,
+	MTK_ETH_PATH_GMAC1_SGMII_BIT,
+	MTK_ETH_PATH_GMAC2_RGMII_BIT,
+	MTK_ETH_PATH_GMAC2_SGMII_BIT,
+	MTK_ETH_PATH_GMAC2_GEPHY_BIT,
+	MTK_ETH_PATH_GDM1_ESW_BIT,
+};
+
+/* Supported hardware group on SoCs */
+#define MTK_RGMII		BIT(MTK_RGMII_BIT)
+#define MTK_TRGMII		BIT(MTK_TRGMII_BIT)
+#define MTK_SGMII		BIT(MTK_SGMII_BIT)
+#define MTK_ESW			BIT(MTK_ESW_BIT)
+#define MTK_GEPHY		BIT(MTK_GEPHY_BIT)
+#define MTK_MUX			BIT(MTK_MUX_BIT)
+#define MTK_INFRA		BIT(MTK_INFRA_BIT)
+#define MTK_SHARED_SGMII	BIT(MTK_SHARED_SGMII_BIT)
+#define MTK_HWLRO		BIT(MTK_HWLRO_BIT)
+#define MTK_RSS			BIT(MTK_RSS_BIT)
+#define MTK_SHARED_INT		BIT(MTK_SHARED_INT_BIT)
+#define MTK_TRGMII_MT7621_CLK	BIT(MTK_TRGMII_MT7621_CLK_BIT)
+#define MTK_QDMA		BIT(MTK_QDMA_BIT)
+#define MTK_NETSYS_V2		BIT(MTK_NETSYS_V2_BIT)
+#define MTK_SOC_MT7628		BIT(MTK_SOC_MT7628_BIT)
+#define MTK_RSTCTRL_PPE1	BIT(MTK_RSTCTRL_PPE1_BIT)
+#define MTK_U3_COPHY_V2		BIT(MTK_U3_COPHY_V2_BIT)
+
+#define MTK_ETH_MUX_GDM1_TO_GMAC1_ESW		\
+	BIT(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT)
+#define MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY	\
+	BIT(MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT)
+#define MTK_ETH_MUX_U3_GMAC2_TO_QPHY		\
+	BIT(MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT)
+#define MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII	\
+	BIT(MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT)
+#define MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII	\
+	BIT(MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT)
+
+/* Supported path present on SoCs */
+#define MTK_ETH_PATH_GMAC1_RGMII	BIT(MTK_ETH_PATH_GMAC1_RGMII_BIT)
+#define MTK_ETH_PATH_GMAC1_TRGMII	BIT(MTK_ETH_PATH_GMAC1_TRGMII_BIT)
+#define MTK_ETH_PATH_GMAC1_SGMII	BIT(MTK_ETH_PATH_GMAC1_SGMII_BIT)
+#define MTK_ETH_PATH_GMAC2_RGMII	BIT(MTK_ETH_PATH_GMAC2_RGMII_BIT)
+#define MTK_ETH_PATH_GMAC2_SGMII	BIT(MTK_ETH_PATH_GMAC2_SGMII_BIT)
+#define MTK_ETH_PATH_GMAC2_GEPHY	BIT(MTK_ETH_PATH_GMAC2_GEPHY_BIT)
+#define MTK_ETH_PATH_GDM1_ESW		BIT(MTK_ETH_PATH_GDM1_ESW_BIT)
+
+#define MTK_GMAC1_RGMII		(MTK_ETH_PATH_GMAC1_RGMII | MTK_RGMII)
+#define MTK_GMAC1_TRGMII	(MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII)
+#define MTK_GMAC1_SGMII		(MTK_ETH_PATH_GMAC1_SGMII | MTK_SGMII)
+#define MTK_GMAC2_RGMII		(MTK_ETH_PATH_GMAC2_RGMII | MTK_RGMII)
+#define MTK_GMAC2_SGMII		(MTK_ETH_PATH_GMAC2_SGMII | MTK_SGMII)
+#define MTK_GMAC2_GEPHY		(MTK_ETH_PATH_GMAC2_GEPHY | MTK_GEPHY)
+#define MTK_GDM1_ESW		(MTK_ETH_PATH_GDM1_ESW | MTK_ESW)
+
+/* MUXes present on SoCs */
+/* 0: GDM1 -> GMAC1, 1: GDM1 -> ESW */
+#define MTK_MUX_GDM1_TO_GMAC1_ESW (MTK_ETH_MUX_GDM1_TO_GMAC1_ESW | MTK_MUX)
+
+/* 0: GMAC2 -> GEPHY, 1: GMAC0 -> GePHY */
+#define MTK_MUX_GMAC2_GMAC0_TO_GEPHY    \
+	(MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY | MTK_MUX | MTK_INFRA)
+
+/* 0: U3 -> QPHY, 1: GMAC2 -> QPHY */
+#define MTK_MUX_U3_GMAC2_TO_QPHY        \
+	(MTK_ETH_MUX_U3_GMAC2_TO_QPHY | MTK_MUX | MTK_INFRA)
+
+/* 2: GMAC1 -> SGMII, 3: GMAC2 -> SGMII */
+#define MTK_MUX_GMAC1_GMAC2_TO_SGMII_RGMII      \
+	(MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII | MTK_MUX | \
+	MTK_SHARED_SGMII)
+
+/* 0: GMACx -> GEPHY, 1: GMACx -> SGMII where x is 1 or 2 */
+#define MTK_MUX_GMAC12_TO_GEPHY_SGMII   \
+	(MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII | MTK_MUX)
+
+#define MTK_HAS_CAPS(caps, _x)		(((caps) & (_x)) == (_x))
+
+#define MT7621_CAPS  (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | \
+		      MTK_GMAC2_RGMII | MTK_SHARED_INT | \
+		      MTK_TRGMII_MT7621_CLK | MTK_QDMA)
+
+#define MT7622_CAPS  (MTK_GMAC1_RGMII | MTK_GMAC1_SGMII | MTK_GMAC2_RGMII | \
+		      MTK_GMAC2_SGMII | MTK_GDM1_ESW | \
+		      MTK_MUX_GDM1_TO_GMAC1_ESW | \
+		      MTK_MUX_GMAC1_GMAC2_TO_SGMII_RGMII | MTK_QDMA)
+
+#define MT7623_CAPS  (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | MTK_GMAC2_RGMII | \
+		      MTK_QDMA)
+
+#define MT7628_CAPS  (MTK_SHARED_INT | MTK_SOC_MT7628)
+
+#define MT7629_CAPS  (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \
+		      MTK_GDM1_ESW | MTK_MUX_GDM1_TO_GMAC1_ESW | \
+		      MTK_MUX_GMAC2_GMAC0_TO_GEPHY | \
+		      MTK_MUX_U3_GMAC2_TO_QPHY | \
+		      MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA)
+
+#define MT7986_CAPS   (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \
+                       MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
+                       MTK_NETSYS_V2 | MTK_RSTCTRL_PPE1)
+
+#define MT7981_CAPS   (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \
+			MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
+			MTK_MUX_U3_GMAC2_TO_QPHY | MTK_U3_COPHY_V2 | \
+			MTK_NETSYS_V2)
+
+/* struct mtk_eth_data -	This is the structure holding all differences
+ *				among various plaforms
+ * @ana_rgc3:                   The offset for register ANA_RGC3 related to
+ *				sgmiisys syscon
+ * @caps			Flags shown the extra capability for the SoC
+ * @hw_features			Flags shown HW features
+ * @required_clks		Flags shown the bitmap for required clocks on
+ *				the target SoC
+ * @required_pctl		A bool value to show whether the SoC requires
+ *				the extra setup for those pins used by GMAC.
+ */
+struct mtk_soc_data {
+	u32             ana_rgc3;
+	u32		caps;
+	u32		required_clks;
+	bool		required_pctl;
+	netdev_features_t hw_features;
+	bool		has_sram;
+};
+
+/* currently no SoC has more than 2 macs */
+#define MTK_MAX_DEVS			2
+
+#define MTK_SGMII_PHYSPEED_AN          BIT(31)
+#define MTK_SGMII_PHYSPEED_MASK        GENMASK(2, 0)
+#define MTK_SGMII_PHYSPEED_1000        BIT(0)
+#define MTK_SGMII_PHYSPEED_2500        BIT(1)
+#define MTK_SGMII_PN_SWAP	       BIT(16)
+#define MTK_HAS_FLAGS(flags, _x)       (((flags) & (_x)) == (_x))
+
+/* struct mtk_sgmii -  This is the structure holding sgmii regmap and its
+ *                     characteristics
+ * @regmap:            The register map pointing at the range used to setup
+ *                     SGMII modes
+ * @flags:             The enum refers to which mode the sgmii wants to run on
+ * @ana_rgc3:          The offset refers to register ANA_RGC3 related to regmap
+ */
+
+struct mtk_sgmii {
+	struct regmap   *regmap[MTK_MAX_DEVS];
+	u32             flags[MTK_MAX_DEVS];
+	u32             ana_rgc3;
+};
+
+/* struct mtk_eth -	This is the main datasructure for holding the state
+ *			of the driver
+ * @dev:		The device pointer
+ * @base:		The mapped register i/o base
+ * @page_lock:		Make sure that register operations are atomic
+ * @tx_irq__lock:	Make sure that IRQ register operations are atomic
+ * @rx_irq__lock:	Make sure that IRQ register operations are atomic
+ * @dummy_dev:		we run 2 netdevs on 1 physical DMA ring and need a
+ *			dummy for NAPI to work
+ * @netdev:		The netdev instances
+ * @mac:		Each netdev is linked to a physical MAC
+ * @irq:		The IRQ that we are using
+ * @msg_enable:		Ethtool msg level
+ * @ethsys:		The register map pointing at the range used to setup
+ *			MII modes
+ * @infra:              The register map pointing at the range used to setup
+ *                      SGMII and GePHY path
+ * @pctl:		The register map pointing at the range used to setup
+ *			GMAC port drive/slew values
+ * @dma_refcnt:		track how many netdevs are using the DMA engine
+ * @tx_ring:		Pointer to the memory holding info about the TX ring
+ * @rx_ring:		Pointer to the memory holding info about the RX ring
+ * @rx_ring_qdma:	Pointer to the memory holding info about the QDMA RX ring
+ * @tx_napi:		The TX NAPI struct
+ * @rx_napi:		The RX NAPI struct
+ * @scratch_ring:	Newer SoCs need memory for a second HW managed TX ring
+ * @phy_scratch_ring:	physical address of scratch_ring
+ * @scratch_head:	The scratch memory that scratch_ring points to.
+ * @clks:		clock array for all clocks required
+ * @mii_bus:		If there is a bus we need to create an instance for it
+ * @pending_work:	The workqueue used to reset the dma ring
+ * @state:		Initialization and runtime state of the device
+ * @soc:		Holding specific data among vaious SoCs
+ */
+
+struct mtk_eth {
+	struct device			*dev;
+	void __iomem			*base;
+	spinlock_t			page_lock;
+	spinlock_t			tx_irq_lock;
+	spinlock_t			rx_irq_lock;
+	struct net_device		dummy_dev;
+	struct net_device		*netdev[MTK_MAX_DEVS];
+	struct mtk_mac			*mac[MTK_MAX_DEVS];
+	int				irq[MTK_MAX_IRQ_NUM];
+	u32				msg_enable;
+	unsigned long			sysclk;
+	struct regmap			*ethsys;
+	struct regmap                   *infra;
+	struct mtk_sgmii                *sgmii;
+	struct regmap			*pctl;
+	bool				hwlro;
+	refcount_t			dma_refcnt;
+	struct mtk_tx_ring		tx_ring;
+	struct mtk_rx_ring		rx_ring[MTK_MAX_RX_RING_NUM];
+	struct mtk_rx_ring		rx_ring_qdma;
+	struct napi_struct		tx_napi;
+	struct mtk_napi			rx_napi[MTK_RX_NAPI_NUM];
+	struct mtk_tx_dma		*scratch_ring;
+	dma_addr_t			phy_scratch_ring;
+	void				*scratch_head;
+	struct clk			*clks[MTK_CLK_MAX];
+
+	struct mii_bus			*mii_bus;
+	struct work_struct		pending_work;
+	unsigned long			state;
+
+	const struct mtk_soc_data	*soc;
+
+	u32				tx_int_mask_reg;
+	u32				tx_int_status_reg;
+	u32				rx_dma_l4_valid;
+	int				ip_align;
+	spinlock_t			syscfg0_lock;
+};
+
+/* struct mtk_mac -	the structure that holds the info about the MACs of the
+ *			SoC
+ * @id:			The number of the MAC
+ * @interface:		Interface mode kept for detecting change in hw settings
+ * @of_node:		Our devicetree node
+ * @hw:			Backpointer to our main datastruture
+ * @hw_stats:		Packet statistics counter
+ */
+struct mtk_mac {
+	unsigned int			id;
+	phy_interface_t			interface;
+	unsigned int			mode;
+	int				speed;
+	struct device_node		*of_node;
+	struct phylink			*phylink;
+	struct phylink_config		phylink_config;
+	struct mtk_eth			*hw;
+	struct mtk_hw_stats		*hw_stats;
+	__be32				hwlro_ip[MTK_MAX_LRO_IP_CNT];
+	int				hwlro_ip_cnt;
+};
+
+/* the struct describing the SoC. these are declared in the soc_xyz.c files */
+extern const struct of_device_id of_mtk_match[];
+extern u32 mtk_hwlro_stats_ebl;
+
+/* read the hardware status register */
+void mtk_stats_update_mac(struct mtk_mac *mac);
+
+void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg);
+u32 mtk_r32(struct mtk_eth *eth, unsigned reg);
+
+int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *np,
+		   u32 ana_rgc3);
+int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, unsigned int id);
+int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, unsigned int id,
+			       const struct phylink_link_state *state);
+void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id);
+
+int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id);
+int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id);
+int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id);
+
+#endif /* MTK_ETH_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/Makefile
new file mode 100644
index 0000000..bf1bbcb
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/Makefile
@@ -0,0 +1,5 @@
+ccflags-y=-Werror
+
+obj-$(CONFIG_NET_MEDIATEK_HNAT)         += mtkhnat.o
+mtkhnat-objs := hnat.o hnat_nf_hook.o hnat_debugfs.o hnat_mcast.o
+mtkhnat-$(CONFIG_NET_DSA_MT7530)	+= hnat_stag.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
new file mode 100644
index 0000000..58a83b8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
@@ -0,0 +1,866 @@
+/*   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; version 2 of the License
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   Copyright (C) 2014-2016 Sean Wang <sean.wang@mediatek.com>
+ *   Copyright (C) 2016-2017 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/if.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/rtnetlink.h>
+#include <net/netlink.h>
+
+#include "nf_hnat_mtk.h"
+#include "hnat.h"
+
+struct mtk_hnat *hnat_priv;
+static struct socket *_hnat_roam_sock;
+static struct work_struct _hnat_roam_work;
+
+int (*ra_sw_nat_hook_rx)(struct sk_buff *skb) = NULL;
+EXPORT_SYMBOL(ra_sw_nat_hook_rx);
+int (*ra_sw_nat_hook_tx)(struct sk_buff *skb, int gmac_no) = NULL;
+EXPORT_SYMBOL(ra_sw_nat_hook_tx);
+
+int (*ppe_del_entry_by_mac)(unsigned char *mac) = NULL;
+EXPORT_SYMBOL(ppe_del_entry_by_mac);
+
+void (*ppe_dev_register_hook)(struct net_device *dev) = NULL;
+EXPORT_SYMBOL(ppe_dev_register_hook);
+void (*ppe_dev_unregister_hook)(struct net_device *dev) = NULL;
+EXPORT_SYMBOL(ppe_dev_unregister_hook);
+
+static void hnat_sma_build_entry(struct timer_list *t)
+{
+	int i;
+
+	for (i = 0; i < CFG_PPE_NUM; i++)
+		cr_set_field(hnat_priv->ppe_base[i] + PPE_TB_CFG,
+			     SMA, SMA_FWD_CPU_BUILD_ENTRY);
+}
+
+void hnat_cache_ebl(int enable)
+{
+	int i;
+
+	for (i = 0; i < CFG_PPE_NUM; i++) {
+		cr_set_field(hnat_priv->ppe_base[i] + PPE_CAH_CTRL, CAH_X_MODE, 1);
+		cr_set_field(hnat_priv->ppe_base[i] + PPE_CAH_CTRL, CAH_X_MODE, 0);
+		cr_set_field(hnat_priv->ppe_base[i] + PPE_CAH_CTRL, CAH_EN, enable);
+	}
+}
+
+static void hnat_reset_timestamp(struct timer_list *t)
+{
+	struct foe_entry *entry;
+	int hash_index;
+
+	hnat_cache_ebl(0);
+	cr_set_field(hnat_priv->ppe_base[0] + PPE_TB_CFG, TCP_AGE, 0);
+	cr_set_field(hnat_priv->ppe_base[0] + PPE_TB_CFG, UDP_AGE, 0);
+	writel(0, hnat_priv->fe_base + 0x0010);
+
+	for (hash_index = 0; hash_index < hnat_priv->foe_etry_num; hash_index++) {
+		entry = hnat_priv->foe_table_cpu[0] + hash_index;
+		if (entry->bfib1.state == BIND)
+			entry->bfib1.time_stamp =
+				readl(hnat_priv->fe_base + 0x0010) & (0xFFFF);
+	}
+
+	cr_set_field(hnat_priv->ppe_base[0] + PPE_TB_CFG, TCP_AGE, 1);
+	cr_set_field(hnat_priv->ppe_base[0] + PPE_TB_CFG, UDP_AGE, 1);
+	hnat_cache_ebl(1);
+
+	mod_timer(&hnat_priv->hnat_reset_timestamp_timer, jiffies + 14400 * HZ);
+}
+
+static void cr_set_bits(void __iomem *reg, u32 bs)
+{
+	u32 val = readl(reg);
+
+	val |= bs;
+	writel(val, reg);
+}
+
+static void cr_clr_bits(void __iomem *reg, u32 bs)
+{
+	u32 val = readl(reg);
+
+	val &= ~bs;
+	writel(val, reg);
+}
+
+void cr_set_field(void __iomem *reg, u32 field, u32 val)
+{
+	unsigned int tv = readl(reg);
+
+	tv &= ~field;
+	tv |= ((val) << (ffs((unsigned int)field) - 1));
+	writel(tv, reg);
+}
+
+/*boundary entry can't be used to accelerate data flow*/
+static void exclude_boundary_entry(struct foe_entry *foe_table_cpu)
+{
+	int entry_base = 0;
+	int bad_entry, i, j;
+	struct foe_entry *foe_entry;
+	/*these entries are boundary every 128 entries*/
+	int boundary_entry_offset[8] = { 12, 25, 38, 51, 76, 89, 102, 115};
+
+	if (!foe_table_cpu)
+		return;
+
+	for (i = 0; entry_base < hnat_priv->foe_etry_num; i++) {
+		/* set boundary entries as static*/
+		for (j = 0; j < 8; j++) {
+			bad_entry = entry_base + boundary_entry_offset[j];
+			foe_entry = &foe_table_cpu[bad_entry];
+			foe_entry->udib1.sta = 1;
+		}
+		entry_base = (i + 1) * 128;
+	}
+}
+
+void set_gmac_ppe_fwd(int id, int enable)
+{
+	void __iomem *reg;
+	u32 val;
+
+	reg = hnat_priv->fe_base + (id ? GDMA2_FWD_CFG : GDMA1_FWD_CFG);
+
+	if (enable) {
+		cr_set_bits(reg, BITS_GDM_ALL_FRC_P_PPE);
+
+		return;
+	}
+
+	/*disabled */
+	val = readl(reg);
+	if ((val & GDM_ALL_FRC_MASK) == BITS_GDM_ALL_FRC_P_PPE)
+		cr_set_field(reg, GDM_ALL_FRC_MASK,
+			     BITS_GDM_ALL_FRC_P_CPU_PDMA);
+}
+
+static int entry_mac_cmp(struct foe_entry *entry, u8 *mac)
+{
+	int ret = 0;
+
+	if(IS_IPV4_GRP(entry)) {
+		if(((swab32(entry->ipv4_hnapt.dmac_hi) == *(u32 *)mac) &&
+			(swab16(entry->ipv4_hnapt.dmac_lo) == *(u16 *)&mac[4])) ||
+			((swab32(entry->ipv4_hnapt.smac_hi) == *(u32 *)mac) &&
+			(swab16(entry->ipv4_hnapt.smac_lo) == *(u16 *)&mac[4])))
+			ret = 1;
+	} else {
+		if(((swab32(entry->ipv6_5t_route.dmac_hi) == *(u32 *)mac) &&
+			(swab16(entry->ipv6_5t_route.dmac_lo) == *(u16 *)&mac[4])) ||
+			((swab32(entry->ipv6_5t_route.smac_hi) == *(u32 *)mac) &&
+			(swab16(entry->ipv6_5t_route.smac_lo) == *(u16 *)&mac[4])))
+			ret = 1;
+	}
+
+	if (ret && debug_level >= 2)
+		pr_info("mac=%pM\n", mac);
+
+	return ret;
+}
+
+int entry_delete_by_mac(u8 *mac)
+{
+	struct foe_entry *entry = NULL;
+	int index, i, ret = 0;
+
+	for (i = 0; i < CFG_PPE_NUM; i++) {
+		entry = hnat_priv->foe_table_cpu[i];
+		for (index = 0; index < DEF_ETRY_NUM; entry++, index++) {
+			if(entry->bfib1.state == BIND && entry_mac_cmp(entry, mac)) {
+				memset(entry, 0, sizeof(*entry));
+				hnat_cache_ebl(1);
+				if (debug_level >= 2)
+					pr_info("delete entry idx = %d\n", index);
+				ret++;
+			}
+		}
+	}
+
+	if(!ret && debug_level >= 2)
+		pr_info("entry not found\n");
+
+	return ret;
+}
+
+static void hnat_roam_handler(struct work_struct *work)
+{
+	struct kvec iov;
+	struct msghdr msg;
+	struct nlmsghdr *nlh;
+	struct ndmsg *ndm;
+	struct nlattr *nla;
+	u8 rcv_buf[512];
+	int len;
+
+	if (!_hnat_roam_sock)
+		return;
+
+	iov.iov_base = rcv_buf;
+	iov.iov_len = sizeof(rcv_buf);
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_namelen = sizeof(struct sockaddr_nl);
+
+	len = kernel_recvmsg(_hnat_roam_sock, &msg, &iov, 1, iov.iov_len, 0);
+	if (len <= 0)
+		goto out;
+
+	nlh = (struct nlmsghdr*)rcv_buf;
+	if (!NLMSG_OK(nlh, len) || nlh->nlmsg_type != RTM_NEWNEIGH)
+		goto out;
+
+	len = nlh->nlmsg_len - NLMSG_HDRLEN;
+	ndm = (struct ndmsg *)NLMSG_DATA(nlh);
+	if (ndm->ndm_family != PF_BRIDGE)
+		goto out;
+
+	nla = (struct nlattr *)((u8 *)ndm + sizeof(struct ndmsg));
+	len -= NLMSG_LENGTH(sizeof(struct ndmsg));
+	while (nla_ok(nla, len)) {
+		if (nla_type(nla) == NDA_LLADDR) {
+			entry_delete_by_mac(nla_data(nla));
+		}
+		nla = nla_next(nla, &len);
+	}
+
+out:
+	schedule_work(&_hnat_roam_work);
+}
+
+static int hnat_roaming_enable(void)
+{
+	struct socket *sock = NULL;
+	struct sockaddr_nl addr;
+	int ret;
+
+	INIT_WORK(&_hnat_roam_work, hnat_roam_handler);
+
+	ret = sock_create_kern(&init_net, AF_NETLINK, SOCK_RAW, NETLINK_ROUTE, &sock);
+	if (ret < 0)
+		goto out;
+
+	_hnat_roam_sock = sock;
+
+	addr.nl_family = AF_NETLINK;
+	addr.nl_pad = 0;
+	addr.nl_pid = 65534;
+	addr.nl_groups = 1 << (RTNLGRP_NEIGH - 1);
+	ret = kernel_bind(sock, (struct sockaddr *)&addr, sizeof(addr));
+	if (ret < 0)
+		goto out;
+
+	schedule_work(&_hnat_roam_work);
+	pr_info("hnat roaming work enable\n");
+
+	return 0;
+out:
+	if (sock)
+		sock_release(sock);
+
+	return ret;
+}
+
+static void hnat_roaming_disable(void)
+{
+	if (_hnat_roam_sock)
+		sock_release(_hnat_roam_sock);
+	_hnat_roam_sock = NULL;
+	pr_info("hnat roaming work disable\n");
+}
+
+static int hnat_start(u32 ppe_id)
+{
+	u32 foe_table_sz;
+	u32 foe_mib_tb_sz;
+	int etry_num_cfg;
+
+	if (ppe_id >= CFG_PPE_NUM)
+		return -EINVAL;
+
+	/* mapp the FOE table */
+	for (etry_num_cfg = DEF_ETRY_NUM_CFG ; etry_num_cfg >= 0 ; etry_num_cfg--, hnat_priv->foe_etry_num /= 2) {
+		foe_table_sz = hnat_priv->foe_etry_num * sizeof(struct foe_entry);
+		hnat_priv->foe_table_cpu[ppe_id] = dma_alloc_coherent(
+				hnat_priv->dev, foe_table_sz,
+				&hnat_priv->foe_table_dev[ppe_id], GFP_KERNEL);
+
+		if (hnat_priv->foe_table_cpu[ppe_id])
+			break;
+	}
+
+	if (!hnat_priv->foe_table_cpu[ppe_id])
+		return -1;
+	dev_info(hnat_priv->dev, "PPE%d entry number = %d\n",
+		 ppe_id, hnat_priv->foe_etry_num);
+
+	writel(hnat_priv->foe_table_dev[ppe_id], hnat_priv->ppe_base[ppe_id] + PPE_TB_BASE);
+	memset(hnat_priv->foe_table_cpu[ppe_id], 0, foe_table_sz);
+
+	if (hnat_priv->data->version == MTK_HNAT_V1)
+		exclude_boundary_entry(hnat_priv->foe_table_cpu[ppe_id]);
+
+	if (hnat_priv->data->per_flow_accounting) {
+		foe_mib_tb_sz = hnat_priv->foe_etry_num * sizeof(struct mib_entry);
+		hnat_priv->foe_mib_cpu[ppe_id] =
+			dma_alloc_coherent(hnat_priv->dev, foe_mib_tb_sz,
+					   &hnat_priv->foe_mib_dev[ppe_id], GFP_KERNEL);
+		if (!hnat_priv->foe_mib_cpu[ppe_id])
+			return -1;
+		writel(hnat_priv->foe_mib_dev[ppe_id],
+		       hnat_priv->ppe_base[ppe_id] + PPE_MIB_TB_BASE);
+		memset(hnat_priv->foe_mib_cpu[ppe_id], 0, foe_mib_tb_sz);
+
+		hnat_priv->acct[ppe_id] =
+			kzalloc(hnat_priv->foe_etry_num * sizeof(struct hnat_accounting),
+				GFP_KERNEL);
+		if (!hnat_priv->acct[ppe_id])
+			return -1;
+	}
+	/* setup hashing */
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, TB_ETRY_NUM, etry_num_cfg);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, HASH_MODE, HASH_MODE_1);
+	writel(HASH_SEED_KEY, hnat_priv->ppe_base[ppe_id] + PPE_HASH_SEED);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, XMODE, 0);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, TB_ENTRY_SIZE, ENTRY_80B);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, SMA, SMA_FWD_CPU_BUILD_ENTRY);
+
+	/* set ip proto */
+	writel(0xFFFFFFFF, hnat_priv->ppe_base[ppe_id] + PPE_IP_PROT_CHK);
+
+	/* setup caching */
+	hnat_cache_ebl(1);
+
+	/* enable FOE */
+	cr_set_bits(hnat_priv->ppe_base[ppe_id] + PPE_FLOW_CFG,
+		    BIT_UDP_IP4F_NAT_EN | BIT_IPV4_NAT_EN | BIT_IPV4_NAPT_EN |
+		    BIT_IPV4_NAT_FRAG_EN | BIT_IPV4_HASH_GREK |
+		    BIT_IPV4_DSL_EN | BIT_IPV6_6RD_EN |
+		    BIT_IPV6_3T_ROUTE_EN | BIT_IPV6_5T_ROUTE_EN);
+
+	if (hnat_priv->data->version == MTK_HNAT_V4)
+		cr_set_bits(hnat_priv->ppe_base[ppe_id] + PPE_FLOW_CFG,
+			    BIT_IPV4_MAPE_EN | BIT_IPV4_MAPT_EN);
+
+	/* setup FOE aging */
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, NTU_AGE, 1);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, UNBD_AGE, 1);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_UNB_AGE, UNB_MNP, 1000);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_UNB_AGE, UNB_DLTA, 3);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, TCP_AGE, 1);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, UDP_AGE, 1);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, FIN_AGE, 1);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_BND_AGE_0, UDP_DLTA, 12);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_BND_AGE_0, NTU_DLTA, 1);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_BND_AGE_1, FIN_DLTA, 1);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_BND_AGE_1, TCP_DLTA, 7);
+
+	/* setup FOE ka */
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, SCAN_MODE, 2);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, KA_CFG, 3);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_KA, KA_T, 1);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_KA, TCP_KA, 1);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_KA, UDP_KA, 1);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_BIND_LMT_1, NTU_KA, 1);
+
+	/* setup FOE rate limit */
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_BIND_LMT_0, QURT_LMT, 16383);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_BIND_LMT_0, HALF_LMT, 16383);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_BIND_LMT_1, FULL_LMT, 16383);
+	/* setup binding threshold as 30 packets per second */
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_BNDR, BIND_RATE, 0x1E);
+
+	/* setup FOE cf gen */
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_GLO_CFG, PPE_EN, 1);
+	writel(0, hnat_priv->ppe_base[ppe_id] + PPE_DFT_CPORT); /* pdma */
+	/* writel(0x55555555, hnat_priv->ppe_base[ppe_id] + PPE_DFT_CPORT); */ /* qdma */
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_GLO_CFG, TTL0_DRP, 0);
+
+	if (hnat_priv->data->version == MTK_HNAT_V4) {
+		writel(0xcb777, hnat_priv->ppe_base[ppe_id] + PPE_DFT_CPORT1);
+		writel(0x7f, hnat_priv->ppe_base[ppe_id] + PPE_SBW_CTRL);
+	}
+
+	/*enable ppe mib counter*/
+	if (hnat_priv->data->per_flow_accounting) {
+		cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_MIB_CFG, MIB_EN, 1);
+		cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_MIB_CFG, MIB_READ_CLEAR, 1);
+		cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_MIB_CAH_CTRL, MIB_CAH_EN, 1);
+	}
+
+	hnat_priv->g_ppdev = dev_get_by_name(&init_net, hnat_priv->ppd);
+	hnat_priv->g_wandev = dev_get_by_name(&init_net, hnat_priv->wan);
+
+	dev_info(hnat_priv->dev, "PPE%d hwnat start\n", ppe_id);
+
+	return 0;
+}
+
+static int ppe_busy_wait(u32 ppe_id)
+{
+	unsigned long t_start = jiffies;
+	u32 r = 0;
+
+	if (ppe_id >= CFG_PPE_NUM)
+		return -EINVAL;
+
+	while (1) {
+		r = readl((hnat_priv->ppe_base[ppe_id] + 0x0));
+		if (!(r & BIT(31)))
+			return 0;
+		if (time_after(jiffies, t_start + HZ))
+			break;
+		usleep_range(10, 20);
+	}
+
+	dev_notice(hnat_priv->dev, "ppe:%s timeout\n", __func__);
+
+	return -1;
+}
+
+static void hnat_stop(u32 ppe_id)
+{
+	u32 foe_table_sz;
+	u32 foe_mib_tb_sz;
+	struct foe_entry *entry, *end;
+	u32 r1 = 0, r2 = 0;
+
+	if (ppe_id >= CFG_PPE_NUM)
+		return;
+
+	/* send all traffic back to the DMA engine */
+	set_gmac_ppe_fwd(0, 0);
+	set_gmac_ppe_fwd(1, 0);
+
+	dev_info(hnat_priv->dev, "hwnat stop\n");
+
+	if (hnat_priv->foe_table_cpu[ppe_id]) {
+		entry = hnat_priv->foe_table_cpu[ppe_id];
+		end = hnat_priv->foe_table_cpu[ppe_id] + hnat_priv->foe_etry_num;
+		while (entry < end) {
+			entry->bfib1.state = INVALID;
+			entry++;
+		}
+	}
+	/* disable caching */
+	hnat_cache_ebl(0);
+
+	/* flush cache has to be ahead of hnat disable --*/
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_GLO_CFG, PPE_EN, 0);
+
+	/* disable scan mode and keep-alive */
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, SCAN_MODE, 0);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, KA_CFG, 0);
+
+	ppe_busy_wait(ppe_id);
+
+	/* disable FOE */
+	cr_clr_bits(hnat_priv->ppe_base[ppe_id] + PPE_FLOW_CFG,
+		    BIT_IPV4_NAPT_EN | BIT_IPV4_NAT_EN | BIT_IPV4_NAT_FRAG_EN |
+		    BIT_IPV6_HASH_GREK | BIT_IPV4_DSL_EN |
+		    BIT_IPV6_6RD_EN | BIT_IPV6_3T_ROUTE_EN |
+		    BIT_IPV6_5T_ROUTE_EN | BIT_FUC_FOE | BIT_FMC_FOE);
+
+	if (hnat_priv->data->version == MTK_HNAT_V4)
+		cr_clr_bits(hnat_priv->ppe_base[ppe_id] + PPE_FLOW_CFG,
+			    BIT_IPV4_MAPE_EN | BIT_IPV4_MAPT_EN);
+
+	/* disable FOE aging */
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, NTU_AGE, 0);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, UNBD_AGE, 0);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, TCP_AGE, 0);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, UDP_AGE, 0);
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_TB_CFG, FIN_AGE, 0);
+
+	r1 = readl(hnat_priv->fe_base + 0x100);
+	r2 = readl(hnat_priv->fe_base + 0x10c);
+
+	dev_info(hnat_priv->dev, "0x100 = 0x%x, 0x10c = 0x%x\n", r1, r2);
+
+	if (((r1 & 0xff00) >> 0x8) >= (r1 & 0xff) ||
+	    ((r1 & 0xff00) >> 0x8) >= (r2 & 0xff)) {
+		dev_info(hnat_priv->dev, "reset pse\n");
+		writel(0x1, hnat_priv->fe_base + 0x4);
+	}
+
+	/* free the FOE table */
+	foe_table_sz = hnat_priv->foe_etry_num * sizeof(struct foe_entry);
+	if (hnat_priv->foe_table_cpu[ppe_id])
+		dma_free_coherent(hnat_priv->dev, foe_table_sz,
+				  hnat_priv->foe_table_cpu[ppe_id],
+				  hnat_priv->foe_table_dev[ppe_id]);
+	writel(0, hnat_priv->ppe_base[ppe_id] + PPE_TB_BASE);
+
+	if (hnat_priv->data->per_flow_accounting) {
+		foe_mib_tb_sz = hnat_priv->foe_etry_num * sizeof(struct mib_entry);
+		if (hnat_priv->foe_mib_cpu[ppe_id])
+			dma_free_coherent(hnat_priv->dev, foe_mib_tb_sz,
+					  hnat_priv->foe_mib_cpu[ppe_id],
+					  hnat_priv->foe_mib_dev[ppe_id]);
+		writel(0, hnat_priv->ppe_base[ppe_id] + PPE_MIB_TB_BASE);
+		kfree(hnat_priv->acct[ppe_id]);
+	}
+}
+
+static void hnat_release_netdev(void)
+{
+	int i;
+	struct extdev_entry *ext_entry;
+
+	for (i = 0; i < MAX_EXT_DEVS && hnat_priv->ext_if[i]; i++) {
+		ext_entry = hnat_priv->ext_if[i];
+		if (ext_entry->dev)
+			dev_put(ext_entry->dev);
+		ext_if_del(ext_entry);
+		kfree(ext_entry);
+	}
+
+	if (hnat_priv->g_ppdev)
+		dev_put(hnat_priv->g_ppdev);
+
+	if (hnat_priv->g_wandev)
+		dev_put(hnat_priv->g_wandev);
+}
+
+static struct notifier_block nf_hnat_netdevice_nb __read_mostly = {
+	.notifier_call = nf_hnat_netdevice_event,
+};
+
+static struct notifier_block nf_hnat_netevent_nb __read_mostly = {
+	.notifier_call = nf_hnat_netevent_handler,
+};
+
+int hnat_enable_hook(void)
+{
+	/* register hook functions used by WHNAT module.
+	 */
+	if (hnat_priv->data->whnat) {
+		ra_sw_nat_hook_rx =
+			(hnat_priv->data->version == MTK_HNAT_V4) ?
+			 mtk_sw_nat_hook_rx : NULL;
+		ra_sw_nat_hook_tx = mtk_sw_nat_hook_tx;
+		ppe_dev_register_hook = mtk_ppe_dev_register_hook;
+		ppe_dev_unregister_hook = mtk_ppe_dev_unregister_hook;
+	}
+
+	if (hnat_register_nf_hooks())
+		return -1;
+
+	ppe_del_entry_by_mac = entry_delete_by_mac;
+	hook_toggle = 1;
+
+	return 0;
+}
+
+int hnat_disable_hook(void)
+{
+	int i, hash_index;
+	struct foe_entry *entry;
+
+	ra_sw_nat_hook_tx = NULL;
+	ra_sw_nat_hook_rx = NULL;
+	hnat_unregister_nf_hooks();
+
+	for (i = 0; i < CFG_PPE_NUM; i++) {
+		cr_set_field(hnat_priv->ppe_base[i] + PPE_TB_CFG,
+			     SMA, SMA_ONLY_FWD_CPU);
+
+		for (hash_index = 0; hash_index < hnat_priv->foe_etry_num; hash_index++) {
+			entry = hnat_priv->foe_table_cpu[i] + hash_index;
+			if (entry->bfib1.state == BIND) {
+				entry->ipv4_hnapt.udib1.state = INVALID;
+				entry->ipv4_hnapt.udib1.time_stamp =
+					readl((hnat_priv->fe_base + 0x0010)) & 0xFF;
+			}
+		}
+	}
+
+	/* clear HWNAT cache */
+	hnat_cache_ebl(1);
+
+	mod_timer(&hnat_priv->hnat_sma_build_entry_timer, jiffies + 3 * HZ);
+	ppe_del_entry_by_mac = NULL;
+	hook_toggle = 0;
+
+	return 0;
+}
+
+static struct packet_type mtk_pack_type __read_mostly = {
+	.type   = HQOS_MAGIC_TAG,
+	.func   = mtk_hqos_ptype_cb,
+};
+
+static int hnat_probe(struct platform_device *pdev)
+{
+	int i;
+	int err = 0;
+	int index = 0;
+	struct resource *res;
+	const char *name;
+	struct device_node *np;
+	unsigned int val;
+	struct property *prop;
+	struct extdev_entry *ext_entry;
+	const struct of_device_id *match;
+
+	hnat_priv = devm_kzalloc(&pdev->dev, sizeof(struct mtk_hnat), GFP_KERNEL);
+	if (!hnat_priv)
+		return -ENOMEM;
+
+	hnat_priv->foe_etry_num = DEF_ETRY_NUM;
+
+	match = of_match_device(of_hnat_match, &pdev->dev);
+	if (unlikely(!match))
+		return -EINVAL;
+
+	hnat_priv->data = (struct mtk_hnat_data *)match->data;
+
+	hnat_priv->dev = &pdev->dev;
+	np = hnat_priv->dev->of_node;
+
+	err = of_property_read_string(np, "mtketh-wan", &name);
+	if (err < 0)
+		return -EINVAL;
+
+	strncpy(hnat_priv->wan, (char *)name, IFNAMSIZ - 1);
+	dev_info(&pdev->dev, "wan = %s\n", hnat_priv->wan);
+
+	err = of_property_read_string(np, "mtketh-lan", &name);
+	if (err < 0)
+		strncpy(hnat_priv->lan, "eth0", IFNAMSIZ);
+	else
+		strncpy(hnat_priv->lan, (char *)name, IFNAMSIZ - 1);
+	dev_info(&pdev->dev, "lan = %s\n", hnat_priv->lan);
+
+	err = of_property_read_string(np, "mtketh-ppd", &name);
+	if (err < 0)
+		strncpy(hnat_priv->ppd, "eth0", IFNAMSIZ);
+	else
+		strncpy(hnat_priv->ppd, (char *)name, IFNAMSIZ - 1);
+	dev_info(&pdev->dev, "ppd = %s\n", hnat_priv->ppd);
+
+	/*get total gmac num in hnat*/
+	err = of_property_read_u32_index(np, "mtketh-max-gmac", 0, &val);
+
+	if (err < 0)
+		return -EINVAL;
+
+	hnat_priv->gmac_num = val;
+
+	dev_info(&pdev->dev, "gmac num = %d\n", hnat_priv->gmac_num);
+
+	err = of_property_read_u32_index(np, "mtkdsa-wan-port", 0, &val);
+
+	if (err < 0) {
+		hnat_priv->wan_dsa_port = NONE_DSA_PORT;
+	} else {
+		hnat_priv->wan_dsa_port = val;
+		dev_info(&pdev->dev, "wan dsa port = %d\n", hnat_priv->wan_dsa_port);
+	}
+
+	err = of_property_read_u32_index(np, "mtketh-ppe-num", 0, &val);
+
+	if (err < 0)
+		hnat_priv->ppe_num = 1;
+	else
+		hnat_priv->ppe_num = val;
+
+	dev_info(&pdev->dev, "ppe num = %d\n", hnat_priv->ppe_num);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENOENT;
+
+	hnat_priv->fe_base = devm_ioremap_nocache(&pdev->dev, res->start,
+					     res->end - res->start + 1);
+	if (!hnat_priv->fe_base)
+		return -EADDRNOTAVAIL;
+
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+	hnat_priv->ppe_base[0] = hnat_priv->fe_base + 0x2200;
+
+	if (CFG_PPE_NUM > 1)
+		hnat_priv->ppe_base[1] = hnat_priv->fe_base + 0x2600;
+#else
+	hnat_priv->ppe_base[0] = hnat_priv->fe_base + 0xe00;
+#endif
+
+	err = hnat_init_debugfs(hnat_priv);
+	if (err)
+		return err;
+
+	prop = of_find_property(np, "ext-devices", NULL);
+	for (name = of_prop_next_string(prop, NULL); name;
+	     name = of_prop_next_string(prop, name), index++) {
+		ext_entry = kzalloc(sizeof(*ext_entry), GFP_KERNEL);
+		if (!ext_entry) {
+			err = -ENOMEM;
+			goto err_out1;
+		}
+		strncpy(ext_entry->name, (char *)name, IFNAMSIZ - 1);
+		ext_if_add(ext_entry);
+	}
+
+	for (i = 0; i < MAX_EXT_DEVS && hnat_priv->ext_if[i]; i++) {
+		ext_entry = hnat_priv->ext_if[i];
+		dev_info(&pdev->dev, "ext devices = %s\n", ext_entry->name);
+	}
+
+	hnat_priv->lvid = 1;
+	hnat_priv->wvid = 2;
+
+	for (i = 0; i < CFG_PPE_NUM; i++) {
+		err = hnat_start(i);
+		if (err)
+			goto err_out;
+	}
+
+	if (hnat_priv->data->whnat) {
+		err = whnat_adjust_nf_hooks();
+		if (err)
+			goto err_out;
+	}
+
+	err = hnat_enable_hook();
+	if (err)
+		goto err_out;
+
+	register_netdevice_notifier(&nf_hnat_netdevice_nb);
+	register_netevent_notifier(&nf_hnat_netevent_nb);
+
+	if (hnat_priv->data->mcast) {
+		for (i = 0; i < CFG_PPE_NUM; i++)
+			hnat_mcast_enable(i);
+	}
+
+	timer_setup(&hnat_priv->hnat_sma_build_entry_timer, hnat_sma_build_entry, 0);
+	if (hnat_priv->data->version == MTK_HNAT_V3) {
+		timer_setup(&hnat_priv->hnat_reset_timestamp_timer, hnat_reset_timestamp, 0);
+		hnat_priv->hnat_reset_timestamp_timer.expires = jiffies;
+		add_timer(&hnat_priv->hnat_reset_timestamp_timer);
+	}
+
+	if (IS_HQOS_MODE && IS_GMAC1_MODE)
+		dev_add_pack(&mtk_pack_type);
+
+	err = hnat_roaming_enable();
+	if (err)
+		pr_info("hnat roaming work fail\n");
+
+	return 0;
+
+err_out:
+	for (i = 0; i < CFG_PPE_NUM; i++)
+		hnat_stop(i);
+err_out1:
+	hnat_deinit_debugfs(hnat_priv);
+	for (i = 0; i < MAX_EXT_DEVS && hnat_priv->ext_if[i]; i++) {
+		ext_entry = hnat_priv->ext_if[i];
+		ext_if_del(ext_entry);
+		kfree(ext_entry);
+	}
+	return err;
+}
+
+static int hnat_remove(struct platform_device *pdev)
+{
+	int i;
+
+	hnat_roaming_disable();
+	unregister_netdevice_notifier(&nf_hnat_netdevice_nb);
+	unregister_netevent_notifier(&nf_hnat_netevent_nb);
+	hnat_disable_hook();
+
+	if (hnat_priv->data->mcast)
+		hnat_mcast_disable();
+
+	for (i = 0; i < CFG_PPE_NUM; i++)
+		hnat_stop(i);
+
+	hnat_deinit_debugfs(hnat_priv);
+	hnat_release_netdev();
+	del_timer_sync(&hnat_priv->hnat_sma_build_entry_timer);
+	if (hnat_priv->data->version == MTK_HNAT_V3)
+		del_timer_sync(&hnat_priv->hnat_reset_timestamp_timer);
+
+	if (IS_HQOS_MODE && IS_GMAC1_MODE)
+		dev_remove_pack(&mtk_pack_type);
+
+	return 0;
+}
+
+static const struct mtk_hnat_data hnat_data_v1 = {
+	.num_of_sch = 2,
+	.whnat = false,
+	.per_flow_accounting = false,
+	.mcast = false,
+	.version = MTK_HNAT_V1,
+};
+
+static const struct mtk_hnat_data hnat_data_v2 = {
+	.num_of_sch = 2,
+	.whnat = true,
+	.per_flow_accounting = true,
+	.mcast = false,
+	.version = MTK_HNAT_V2,
+};
+
+static const struct mtk_hnat_data hnat_data_v3 = {
+	.num_of_sch = 4,
+	.whnat = false,
+	.per_flow_accounting = false,
+	.mcast = false,
+	.version = MTK_HNAT_V3,
+};
+
+static const struct mtk_hnat_data hnat_data_v4 = {
+	.num_of_sch = 4,
+	.whnat = true,
+	.per_flow_accounting = true,
+	.mcast = false,
+	.version = MTK_HNAT_V4,
+};
+
+const struct of_device_id of_hnat_match[] = {
+	{ .compatible = "mediatek,mtk-hnat", .data = &hnat_data_v3 },
+	{ .compatible = "mediatek,mtk-hnat_v1", .data = &hnat_data_v1 },
+	{ .compatible = "mediatek,mtk-hnat_v2", .data = &hnat_data_v2 },
+	{ .compatible = "mediatek,mtk-hnat_v3", .data = &hnat_data_v3 },
+	{ .compatible = "mediatek,mtk-hnat_v4", .data = &hnat_data_v4 },
+	{},
+};
+MODULE_DEVICE_TABLE(of, of_hnat_match);
+
+static struct platform_driver hnat_driver = {
+	.probe = hnat_probe,
+	.remove = hnat_remove,
+	.driver = {
+		.name = "mediatek_soc_hnat",
+		.of_match_table = of_hnat_match,
+	},
+};
+
+module_platform_driver(hnat_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
+MODULE_AUTHOR("John Crispin <john@phrozen.org>");
+MODULE_DESCRIPTION("Mediatek Hardware NAT");
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
new file mode 100644
index 0000000..31a060f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
@@ -0,0 +1,969 @@
+/*   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; version 2 of the License
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   Copyright (C) 2014-2016 Sean Wang <sean.wang@mediatek.com>
+ *   Copyright (C) 2016-2017 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/debugfs.h>
+#include <linux/string.h>
+#include <linux/if.h>
+#include <linux/if_ether.h>
+#include <net/netevent.h>
+#include <linux/mod_devicetable.h>
+#include "hnat_mcast.h"
+
+/*--------------------------------------------------------------------------*/
+/* Register Offset*/
+/*--------------------------------------------------------------------------*/
+#define PPE_GLO_CFG 0x00
+#define PPE_FLOW_CFG 0x04
+#define PPE_IP_PROT_CHK 0x08
+#define PPE_IP_PROT_0 0x0C
+#define PPE_IP_PROT_1 0x10
+#define PPE_IP_PROT_2 0x14
+#define PPE_IP_PROT_3 0x18
+#define PPE_TB_CFG 0x1C
+#define PPE_TB_BASE 0x20
+#define PPE_TB_USED 0x24
+#define PPE_BNDR 0x28
+#define PPE_BIND_LMT_0 0x2C
+#define PPE_BIND_LMT_1 0x30
+#define PPE_KA 0x34
+#define PPE_UNB_AGE 0x38
+#define PPE_BND_AGE_0 0x3C
+#define PPE_BND_AGE_1 0x40
+#define PPE_HASH_SEED 0x44
+#define PPE_DFT_CPORT 0x48
+#define PPE_DFT_CPORT1 0x4C
+#define PPE_MCAST_PPSE 0x84
+#define PPE_MCAST_L_0 0x88
+#define PPE_MCAST_H_0 0x8C
+#define PPE_MCAST_L_1 0x90
+#define PPE_MCAST_H_1 0x94
+#define PPE_MCAST_L_2 0x98
+#define PPE_MCAST_H_2 0x9C
+#define PPE_MCAST_L_3 0xA0
+#define PPE_MCAST_H_3 0xA4
+#define PPE_MCAST_L_4 0xA8
+#define PPE_MCAST_H_4 0xAC
+#define PPE_MCAST_L_5 0xB0
+#define PPE_MCAST_H_5 0xB4
+#define PPE_MCAST_L_6 0xBC
+#define PPE_MCAST_H_6 0xC0
+#define PPE_MCAST_L_7 0xC4
+#define PPE_MCAST_H_7 0xC8
+#define PPE_MCAST_L_8 0xCC
+#define PPE_MCAST_H_8 0xD0
+#define PPE_MCAST_L_9 0xD4
+#define PPE_MCAST_H_9 0xD8
+#define PPE_MCAST_L_A 0xDC
+#define PPE_MCAST_H_A 0xE0
+#define PPE_MCAST_L_B 0xE4
+#define PPE_MCAST_H_B 0xE8
+#define PPE_MCAST_L_C 0xEC
+#define PPE_MCAST_H_C 0xF0
+#define PPE_MCAST_L_D 0xF4
+#define PPE_MCAST_H_D 0xF8
+#define PPE_MCAST_L_E 0xFC
+#define PPE_MCAST_H_E 0xE0
+#define PPE_MCAST_L_F 0x100
+#define PPE_MCAST_H_F 0x104
+#define PPE_MCAST_L_10 0xC00
+#define PPE_MCAST_H_10 0xC04
+#define PPE_MTU_DRP 0x108
+#define PPE_MTU_VLYR_0 0x10C
+#define PPE_MTU_VLYR_1 0x110
+#define PPE_MTU_VLYR_2 0x114
+#define PPE_VPM_TPID 0x118
+#define PPE_CAH_CTRL 0x120
+#define PPE_CAH_TAG_SRH 0x124
+#define PPE_CAH_LINE_RW 0x128
+#define PPE_CAH_WDATA 0x12C
+#define PPE_CAH_RDATA 0x130
+
+#define PPE_MIB_CFG 0X134
+#define PPE_MIB_TB_BASE 0X138
+#define PPE_MIB_SER_CR 0X13C
+#define PPE_MIB_SER_R0 0X140
+#define PPE_MIB_SER_R1 0X144
+#define PPE_MIB_SER_R2 0X148
+#define PPE_MIB_CAH_CTRL 0X150
+#define PPE_MIB_CAH_TAG_SRH 0X154
+#define PPE_MIB_CAH_LINE_RW 0X158
+#define PPE_MIB_CAH_WDATA 0X15C
+#define PPE_MIB_CAH_RDATA 0X160
+#define PPE_SBW_CTRL 0x174
+
+#define GDMA1_FWD_CFG 0x500
+#define GDMA2_FWD_CFG 0x1500
+
+/* QDMA Tx queue configuration */
+#define QTX_CFG(x)			(QDMA_BASE + ((x) * 0x10))
+#define QTX_CFG_HW_RESV_CNT_OFFSET	(8)
+#define QTX_CFG_SW_RESV_CNT_OFFSET	(0)
+
+#define QTX_SCH(x)			(QDMA_BASE + 0x4 + ((x) * 0x10))
+#define QTX_SCH_MIN_RATE_EN		BIT(27)
+#define QTX_SCH_MAX_RATE_EN		BIT(11)
+#define QTX_SCH_MIN_RATE_MAN_OFFSET	(20)
+#define QTX_SCH_MIN_RATE_EXP_OFFSET	(16)
+#define QTX_SCH_MAX_RATE_WGHT_OFFSET	(12)
+#define QTX_SCH_MAX_RATE_MAN_OFFSET	(4)
+#define QTX_SCH_MAX_RATE_EXP_OFFSET	(0)
+
+/* QDMA Tx scheduler configuration */
+#define QDMA_PAGE			(QDMA_BASE + 0x1f0)
+#define QDMA_TX_2SCH_BASE		(QDMA_BASE + 0x214)
+#define QTX_MIB_IF			(QDMA_BASE + 0x2bc)
+#define QDMA_TX_4SCH_BASE(x)		(QDMA_BASE + 0x398 + (((x) >> 1) * 0x4))
+#define QDMA_TX_SCH_WFQ_EN		BIT(15)
+
+/*--------------------------------------------------------------------------*/
+/* Register Mask*/
+/*--------------------------------------------------------------------------*/
+/* PPE_TB_CFG mask */
+#define TB_ETRY_NUM (0x7 << 0) /* RW */
+#define TB_ENTRY_SIZE (0x1 << 3) /* RW */
+#define SMA (0x3 << 4) /* RW */
+#define NTU_AGE (0x1 << 7) /* RW */
+#define UNBD_AGE (0x1 << 8) /* RW */
+#define TCP_AGE (0x1 << 9) /* RW */
+#define UDP_AGE (0x1 << 10) /* RW */
+#define FIN_AGE (0x1 << 11) /* RW */
+#define KA_CFG (0x3 << 12)
+#define HASH_MODE (0x3 << 14) /* RW */
+#define SCAN_MODE (0x3 << 16) /* RW */
+#define XMODE (0x3 << 18) /* RW */
+
+/*PPE_CAH_CTRL mask*/
+#define CAH_EN (0x1 << 0) /* RW */
+#define CAH_X_MODE (0x1 << 9) /* RW */
+
+/*PPE_UNB_AGE mask*/
+#define UNB_DLTA (0xff << 0) /* RW */
+#define UNB_MNP (0xffff << 16) /* RW */
+
+/*PPE_BND_AGE_0 mask*/
+#define UDP_DLTA (0xffff << 0) /* RW */
+#define NTU_DLTA (0xffff << 16) /* RW */
+
+/*PPE_BND_AGE_1 mask*/
+#define TCP_DLTA (0xffff << 0) /* RW */
+#define FIN_DLTA (0xffff << 16) /* RW */
+
+/*PPE_KA mask*/
+#define KA_T (0xffff << 0) /* RW */
+#define TCP_KA (0xff << 16) /* RW */
+#define UDP_KA (0xff << 24) /* RW */
+
+/*PPE_BIND_LMT_0 mask*/
+#define QURT_LMT (0x3ff << 0) /* RW */
+#define HALF_LMT (0x3ff << 16) /* RW */
+
+/*PPE_BIND_LMT_1 mask*/
+#define FULL_LMT (0x3fff << 0) /* RW */
+#define NTU_KA (0xff << 16) /* RW */
+
+/*PPE_BNDR mask*/
+#define BIND_RATE (0xffff << 0) /* RW */
+#define PBND_RD_PRD (0xffff << 16) /* RW */
+
+/*PPE_GLO_CFG mask*/
+#define PPE_EN (0x1 << 0) /* RW */
+#define TTL0_DRP (0x1 << 4) /* RW */
+#define MCAST_TB_EN (0x1 << 7) /* RW */
+#define MCAST_HASH (0x3 << 12) /* RW */
+
+#define MC_P3_PPSE (0xf << 12) /* RW */
+#define MC_P2_PPSE (0xf << 8) /* RW */
+#define MC_P1_PPSE (0xf << 4) /* RW */
+#define MC_P0_PPSE (0xf << 0) /* RW */
+
+#define MIB_EN (0x1 << 0) /* RW */
+#define MIB_READ_CLEAR (0X1 << 1) /* RW */
+#define MIB_CAH_EN (0X1 << 0) /* RW */
+
+/*GDMA_FWD_CFG mask */
+#define GDM_UFRC_MASK (0x7 << 12) /* RW */
+#define GDM_BFRC_MASK (0x7 << 8) /*RW*/
+#define GDM_MFRC_MASK (0x7 << 4) /*RW*/
+#define GDM_OFRC_MASK (0x7 << 0) /*RW*/
+#define GDM_ALL_FRC_MASK                                                      \
+	(GDM_UFRC_MASK | GDM_BFRC_MASK | GDM_MFRC_MASK | GDM_OFRC_MASK)
+
+/*QDMA_PAGE mask*/
+#define QTX_CFG_PAGE (0xf << 0) /* RW */
+
+/*QTX_MIB_IF mask*/
+#define MIB_ON_QTX_CFG (0x1 << 31) /* RW */
+#define VQTX_MIB_EN (0x1 << 28) /* RW */
+
+/*--------------------------------------------------------------------------*/
+/* Descriptor Structure */
+/*--------------------------------------------------------------------------*/
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+struct hnat_unbind_info_blk {
+	u32 time_stamp : 8;
+	u32 sp : 4;
+	u32 pcnt : 8;
+	u32 ilgf : 1;
+	u32 mc : 1;
+	u32 preb : 1;
+	u32 pkt_type : 5;
+	u32 state : 2;
+	u32 udp : 1;
+	u32 sta : 1;		/* static entry */
+} __packed;
+
+struct hnat_bind_info_blk {
+	u32 time_stamp : 8;
+	u32 sp : 4;
+	u32 mc : 1;
+	u32 ka : 1;		/* keep alive */
+	u32 vlan_layer : 3;
+	u32 psn : 1;		/* egress packet has PPPoE session */
+	u32 vpm : 1;		/* 0:ethertype remark, 1:0x8100(CR default) */
+	u32 ps : 1;		/* packet sampling */
+	u32 cah : 1;		/* cacheable flag */
+	u32 rmt : 1;		/* remove tunnel ip header (6rd/dslite only) */
+	u32 ttl : 1;
+	u32 pkt_type : 5;
+	u32 state : 2;
+	u32 udp : 1;
+	u32 sta : 1;		/* static entry */
+} __packed;
+
+struct hnat_info_blk2 {
+	u32 qid : 7;		/* QID in Qos Port */
+	u32 port_mg : 1;
+	u32 fqos : 1;		/* force to PSE QoS port */
+	u32 dp : 4;		/* force to PSE port x */
+	u32 mcast : 1;		/* multicast this packet to CPU */
+	u32 pcpl : 1;		/* OSBN */
+	u32 mibf : 1;
+	u32 alen : 1;
+	u32 rxid : 2;
+	u32 winfoi : 1;
+	u32 port_ag : 4;
+	u32 dscp : 8;		/* DSCP value */
+} __packed;
+
+struct hnat_winfo {
+	u32 bssid : 6;		/* WiFi Bssidx */
+	u32 wcid : 10;		/* WiFi wtable Idx */
+} __packed;
+
+#else
+struct hnat_unbind_info_blk {
+	u32 time_stamp : 8;
+	u32 pcnt : 16; /* packet count */
+	u32 preb : 1;
+	u32 pkt_type : 3;
+	u32 state : 2;
+	u32 udp : 1;
+	u32 sta : 1; /* static entry */
+} __packed;
+
+struct hnat_bind_info_blk {
+	u32 time_stamp : 15;
+	u32 ka : 1; /* keep alive */
+	u32 vlan_layer : 3;
+	u32 psn : 1; /* egress packet has PPPoE session */
+	u32 vpm : 1; /* 0:ethertype remark, 1:0x8100(CR default) */
+	u32 ps : 1; /* packet sampling */
+	u32 cah : 1; /* cacheable flag */
+	u32 rmt : 1; /* remove tunnel ip header (6rd/dslite only) */
+	u32 ttl : 1;
+	u32 pkt_type : 3;
+	u32 state : 2;
+	u32 udp : 1;
+	u32 sta : 1; /* static entry */
+} __packed;
+
+struct hnat_info_blk2 {
+	u32 qid : 4; /* QID in Qos Port */
+	u32 fqos : 1; /* force to PSE QoS port */
+	u32 dp : 3; /* force to PSE port x
+		     * 0:PSE,1:GSW, 2:GMAC,4:PPE,5:QDMA,7=DROP
+		     */
+	u32 mcast : 1; /* multicast this packet to CPU */
+	u32 pcpl : 1; /* OSBN */
+	u32 mibf : 1; /* 0:off 1:on PPE MIB counter */
+	u32 alen : 1; /* 0:post 1:pre packet length in accounting */
+	u32 port_mg : 6; /* port meter group */
+	u32 port_ag : 6; /* port account group */
+	u32 dscp : 8; /* DSCP value */
+} __packed;
+
+struct hnat_winfo {
+	u32 bssid : 6;		/* WiFi Bssidx */
+	u32 wcid : 8;		/* WiFi wtable Idx */
+	u32 rxid : 2;		/* WiFi Ring idx */
+} __packed;
+#endif
+
+/* info blk2 for WHNAT */
+struct hnat_info_blk2_whnat {
+	u32 qid : 4; /* QID[3:0] in Qos Port */
+	u32 fqos : 1; /* force to PSE QoS port */
+	u32 dp : 3; /* force to PSE port x
+		     * 0:PSE,1:GSW, 2:GMAC,4:PPE,5:QDMA,7=DROP
+		     */
+	u32 mcast : 1; /* multicast this packet to CPU */
+	u32 pcpl : 1; /* OSBN */
+	u32 mibf : 1; /* 0:off 1:on PPE MIB counter */
+	u32 alen : 1; /* 0:post 1:pre packet length in accounting */
+	u32 qid2 : 2; /* QID[5:4] in Qos Port */
+	u32 resv : 2;
+	u32 wdmaid : 1; /* 0:to pcie0 dev 1:to pcie1 dev */
+	u32 winfoi : 1; /* 0:off 1:on Wi-Fi hwnat support */
+	u32 port_ag : 6; /* port account group */
+	u32 dscp : 8; /* DSCP value */
+} __packed;
+
+struct hnat_ipv4_hnapt {
+	union {
+		struct hnat_bind_info_blk bfib1;
+		struct hnat_unbind_info_blk udib1;
+		u32 info_blk1;
+	};
+	u32 sip;
+	u32 dip;
+	u16 dport;
+	u16 sport;
+	union {
+		struct hnat_info_blk2 iblk2;
+		struct hnat_info_blk2_whnat iblk2w;
+		u32 info_blk2;
+	};
+	u32 new_sip;
+	u32 new_dip;
+	u16 new_dport;
+	u16 new_sport;
+	u16 m_timestamp; /* For mcast*/
+	u16 resv1;
+	u32 resv2;
+	u32 resv3 : 26;
+	u32 act_dp : 6; /* UDF */
+	u16 vlan1;
+	u16 etype;
+	u32 dmac_hi;
+	union {
+#if !defined(CONFIG_MEDIATEK_NETSYS_V2)
+		struct hnat_winfo winfo;
+#endif
+		u16 vlan2;
+	};
+	u16 dmac_lo;
+	u32 smac_hi;
+	u16 pppoe_id;
+	u16 smac_lo;
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+	u16 minfo;
+	struct hnat_winfo winfo;
+#endif
+} __packed;
+
+struct hnat_ipv4_dslite {
+	union {
+		struct hnat_bind_info_blk bfib1;
+		struct hnat_unbind_info_blk udib1;
+		u32 info_blk1;
+	};
+	u32 sip;
+	u32 dip;
+	u16 dport;
+	u16 sport;
+
+	u32 tunnel_sipv6_0;
+	u32 tunnel_sipv6_1;
+	u32 tunnel_sipv6_2;
+	u32 tunnel_sipv6_3;
+
+	u32 tunnel_dipv6_0;
+	u32 tunnel_dipv6_1;
+	u32 tunnel_dipv6_2;
+	u32 tunnel_dipv6_3;
+
+	u8 flow_lbl[3]; /* in order to consist with Linux kernel (should be 20bits) */
+	u8 priority;    /* in order to consist with Linux kernel (should be 8bits) */
+	u32 hop_limit : 8;
+	u32 resv2 : 18;
+	u32 act_dp : 6; /* UDF */
+
+	union {
+		struct hnat_info_blk2 iblk2;
+		struct hnat_info_blk2_whnat iblk2w;
+		u32 info_blk2;
+	};
+
+	u16 vlan1;
+	u16 etype;
+	u32 dmac_hi;
+	union {
+#if !defined(CONFIG_MEDIATEK_NETSYS_V2)
+		struct hnat_winfo winfo;
+#endif
+		u16 vlan2;
+	};
+	u16 dmac_lo;
+	u32 smac_hi;
+	u16 pppoe_id;
+	u16 smac_lo;
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+	u16 minfo;
+	struct hnat_winfo winfo;
+	u32 new_sip;
+        u32 new_dip;
+        u16 new_dport;
+        u16 new_sport;
+#endif
+} __packed;
+
+struct hnat_ipv6_3t_route {
+	union {
+		struct hnat_bind_info_blk bfib1;
+		struct hnat_unbind_info_blk udib1;
+		u32 info_blk1;
+	};
+	u32 ipv6_sip0;
+	u32 ipv6_sip1;
+	u32 ipv6_sip2;
+	u32 ipv6_sip3;
+	u32 ipv6_dip0;
+	u32 ipv6_dip1;
+	u32 ipv6_dip2;
+	u32 ipv6_dip3;
+	u32 prot : 8;
+	u32 hph : 24; /* hash placeholder */
+
+	u32 resv1;
+	u32 resv2;
+	u32 resv3;
+	u32 resv4 : 26;
+	u32 act_dp : 6; /* UDF */
+
+	union {
+		struct hnat_info_blk2 iblk2;
+		struct hnat_info_blk2_whnat iblk2w;
+		u32 info_blk2;
+	};
+	u16 vlan1;
+	u16 etype;
+	u32 dmac_hi;
+	union {
+#if !defined(CONFIG_MEDIATEK_NETSYS_V2)
+		struct hnat_winfo winfo;
+#endif
+		u16 vlan2;
+	};
+	u16 dmac_lo;
+	u32 smac_hi;
+	u16 pppoe_id;
+	u16 smac_lo;
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+	u16 minfo;
+	struct hnat_winfo winfo;
+#endif
+} __packed;
+
+struct hnat_ipv6_5t_route {
+	union {
+		struct hnat_bind_info_blk bfib1;
+		struct hnat_unbind_info_blk udib1;
+		u32 info_blk1;
+	};
+	u32 ipv6_sip0;
+	u32 ipv6_sip1;
+	u32 ipv6_sip2;
+	u32 ipv6_sip3;
+	u32 ipv6_dip0;
+	u32 ipv6_dip1;
+	u32 ipv6_dip2;
+	u32 ipv6_dip3;
+	u16 dport;
+	u16 sport;
+
+	u32 resv1;
+	u32 resv2;
+	u32 resv3;
+	u32 resv4 : 26;
+	u32 act_dp : 6; /* UDF */
+
+	union {
+		struct hnat_info_blk2 iblk2;
+		struct hnat_info_blk2_whnat iblk2w;
+		u32 info_blk2;
+	};
+
+	u16 vlan1;
+	u16 etype;
+	u32 dmac_hi;
+	union {
+#if !defined(CONFIG_MEDIATEK_NETSYS_V2)
+		struct hnat_winfo winfo;
+#endif
+		u16 vlan2;
+	};
+	u16 dmac_lo;
+	u32 smac_hi;
+	u16 pppoe_id;
+	u16 smac_lo;
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+	u16 minfo;
+	struct hnat_winfo winfo;
+#endif
+} __packed;
+
+struct hnat_ipv6_6rd {
+	union {
+		struct hnat_bind_info_blk bfib1;
+		struct hnat_unbind_info_blk udib1;
+		u32 info_blk1;
+	};
+	u32 ipv6_sip0;
+	u32 ipv6_sip1;
+	u32 ipv6_sip2;
+	u32 ipv6_sip3;
+	u32 ipv6_dip0;
+	u32 ipv6_dip1;
+	u32 ipv6_dip2;
+	u32 ipv6_dip3;
+	u16 dport;
+	u16 sport;
+
+	u32 tunnel_sipv4;
+	u32 tunnel_dipv4;
+	u32 hdr_chksum : 16;
+	u32 dscp : 8;
+	u32 ttl : 8;
+	u32 flag : 3;
+	u32 resv1 : 13;
+	u32 per_flow_6rd_id : 1;
+	u32 resv2 : 9;
+	u32 act_dp : 6; /* UDF */
+
+	union {
+		struct hnat_info_blk2 iblk2;
+		struct hnat_info_blk2_whnat iblk2w;
+		u32 info_blk2;
+	};
+
+	u16 vlan1;
+	u16 etype;
+	u32 dmac_hi;
+	union {
+#if !defined(CONFIG_MEDIATEK_NETSYS_V2)
+		struct hnat_winfo winfo;
+#endif
+		u16 vlan2;
+	};
+	u16 dmac_lo;
+	u32 smac_hi;
+	u16 pppoe_id;
+	u16 smac_lo;
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+	u16 minfo;
+	struct hnat_winfo winfo;
+	u32 resv3;
+        u32 resv4;
+        u16 new_dport;
+        u16 new_sport;
+#endif
+} __packed;
+
+struct foe_entry {
+	union {
+		struct hnat_unbind_info_blk udib1;
+		struct hnat_bind_info_blk bfib1;
+		struct hnat_ipv4_hnapt ipv4_hnapt;
+		struct hnat_ipv4_dslite ipv4_dslite;
+		struct hnat_ipv6_3t_route ipv6_3t_route;
+		struct hnat_ipv6_5t_route ipv6_5t_route;
+		struct hnat_ipv6_6rd ipv6_6rd;
+	};
+};
+
+/* If user wants to change default FOE entry number, both DEF_ETRY_NUM and
+ * DEF_ETRY_NUM_CFG need to be modified.
+ */
+#define DEF_ETRY_NUM		8192
+/* feasible values : 32768, 16384, 8192, 4096, 2048, 1024 */
+#define DEF_ETRY_NUM_CFG	TABLE_8K
+/* corresponding values : TABLE_32K, TABLE_16K, TABLE_8K, TABLE_4K, TABLE_2K,
+ * TABLE_1K
+ */
+#define MAX_EXT_DEVS		(0x3fU)
+#define MAX_IF_NUM		64
+
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#define MAX_PPE_NUM		2
+#else
+#define MAX_PPE_NUM		1
+#endif
+#define CFG_PPE_NUM		(hnat_priv->ppe_num)
+
+struct mib_entry {
+	u32 byt_cnt_l;
+	u16 byt_cnt_h;
+	u32 pkt_cnt_l;
+	u8 pkt_cnt_h;
+	u8 resv0;
+	u32 resv1;
+} __packed;
+
+struct hnat_accounting {
+	u64 bytes;
+	u64 packets;
+};
+
+enum mtk_hnat_version {
+	MTK_HNAT_V1 = 1, /* version 1: mt7621, mt7623 */
+	MTK_HNAT_V2, /* version 2: mt7622 */
+	MTK_HNAT_V3, /* version 3: mt7629 */
+	MTK_HNAT_V4, /* version 4: mt7986 */
+};
+
+struct mtk_hnat_data {
+	u8 num_of_sch;
+	bool whnat;
+	bool per_flow_accounting;
+	bool mcast;
+	enum mtk_hnat_version version;
+};
+
+struct mtk_hnat {
+	struct device *dev;
+	void __iomem *fe_base;
+	void __iomem *ppe_base[MAX_PPE_NUM];
+	struct foe_entry *foe_table_cpu[MAX_PPE_NUM];
+	dma_addr_t foe_table_dev[MAX_PPE_NUM];
+	u8 enable;
+	u8 enable1;
+	struct dentry *root;
+	struct debugfs_regset32 *regset[MAX_PPE_NUM];
+
+	struct mib_entry *foe_mib_cpu[MAX_PPE_NUM];
+	dma_addr_t foe_mib_dev[MAX_PPE_NUM];
+	struct hnat_accounting *acct[MAX_PPE_NUM];
+	const struct mtk_hnat_data *data;
+
+	/*devices we plays for*/
+	char wan[IFNAMSIZ];
+	char lan[IFNAMSIZ];
+	char ppd[IFNAMSIZ];
+	u16 lvid;
+	u16 wvid;
+
+	struct reset_control *rstc;
+
+	u8 ppe_num;
+	u8 gmac_num;
+	u8 wan_dsa_port;
+	struct ppe_mcast_table *pmcast;
+
+	u32 foe_etry_num;
+	struct net_device *g_ppdev;
+	struct net_device *g_wandev;
+	struct net_device *wifi_hook_if[MAX_IF_NUM];
+	struct extdev_entry *ext_if[MAX_EXT_DEVS];
+	struct timer_list hnat_sma_build_entry_timer;
+	struct timer_list hnat_reset_timestamp_timer;
+	struct timer_list hnat_mcast_check_timer;
+	bool nf_stat_en;
+};
+
+struct extdev_entry {
+	char name[IFNAMSIZ];
+	struct net_device *dev;
+};
+
+struct tcpudphdr {
+	__be16 src;
+	__be16 dst;
+};
+
+enum FoeEntryState { INVALID = 0, UNBIND = 1, BIND = 2, FIN = 3 };
+
+enum FoeIpAct {
+	IPV4_HNAPT = 0,
+	IPV4_HNAT = 1,
+	IPV4_DSLITE = 3,
+	IPV6_3T_ROUTE = 4,
+	IPV6_5T_ROUTE = 5,
+	IPV6_6RD = 7,
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+	IPV4_MAP_T = 8,
+	IPV4_MAP_E = 9,
+#else
+	IPV4_MAP_T = 6,
+	IPV4_MAP_E = 6,
+#endif
+};
+
+/*--------------------------------------------------------------------------*/
+/* Common Definition*/
+/*--------------------------------------------------------------------------*/
+
+#define HNAT_SW_VER   "1.1.0"
+#define HASH_SEED_KEY 0x12345678
+
+/*PPE_TB_CFG value*/
+#define ENTRY_80B 1
+#define ENTRY_64B 0
+#define TABLE_1K 0
+#define TABLE_2K 1
+#define TABLE_4K 2
+#define TABLE_8K 3
+#define TABLE_16K 4
+#define TABLE_32K 5
+#define SMA_DROP 0 /* Drop the packet */
+#define SMA_DROP2 1 /* Drop the packet */
+#define SMA_ONLY_FWD_CPU 2 /* Only Forward to CPU */
+#define SMA_FWD_CPU_BUILD_ENTRY 3 /* Forward to CPU and build new FOE entry */
+#define HASH_MODE_0 0
+#define HASH_MODE_1 1
+#define HASH_MODE_2 2
+#define HASH_MODE_3 3
+
+/*PPE_FLOW_CFG*/
+#define BIT_FUC_FOE BIT(2)
+#define BIT_FMC_FOE BIT(1)
+#define BIT_FBC_FOE BIT(0)
+#define BIT_UDP_IP4F_NAT_EN BIT(7) /*Enable IPv4 fragment + UDP packet NAT*/
+#define BIT_IPV6_3T_ROUTE_EN BIT(8)
+#define BIT_IPV6_5T_ROUTE_EN BIT(9)
+#define BIT_IPV6_6RD_EN BIT(10)
+#define BIT_IPV4_NAT_EN BIT(12)
+#define BIT_IPV4_NAPT_EN BIT(13)
+#define BIT_IPV4_DSL_EN BIT(14)
+#define BIT_MIB_BUSY BIT(16)
+#define BIT_IPV4_NAT_FRAG_EN BIT(17)
+#define BIT_IPV4_HASH_GREK BIT(19)
+#define BIT_IPV6_HASH_GREK BIT(20)
+#define BIT_IPV4_MAPE_EN BIT(21)
+#define BIT_IPV4_MAPT_EN BIT(22)
+
+/*GDMA_FWD_CFG value*/
+#define BITS_GDM_UFRC_P_PPE (NR_PPE0_PORT << 12)
+#define BITS_GDM_BFRC_P_PPE (NR_PPE0_PORT << 8)
+#define BITS_GDM_MFRC_P_PPE (NR_PPE0_PORT << 4)
+#define BITS_GDM_OFRC_P_PPE (NR_PPE0_PORT << 0)
+#define BITS_GDM_ALL_FRC_P_PPE                                              \
+	(BITS_GDM_UFRC_P_PPE | BITS_GDM_BFRC_P_PPE | BITS_GDM_MFRC_P_PPE |  \
+	 BITS_GDM_OFRC_P_PPE)
+
+#define BITS_GDM_UFRC_P_CPU_PDMA (NR_PDMA_PORT << 12)
+#define BITS_GDM_BFRC_P_CPU_PDMA (NR_PDMA_PORT << 8)
+#define BITS_GDM_MFRC_P_CPU_PDMA (NR_PDMA_PORT << 4)
+#define BITS_GDM_OFRC_P_CPU_PDMA (NR_PDMA_PORT << 0)
+#define BITS_GDM_ALL_FRC_P_CPU_PDMA                                           \
+	(BITS_GDM_UFRC_P_CPU_PDMA | BITS_GDM_BFRC_P_CPU_PDMA |               \
+	 BITS_GDM_MFRC_P_CPU_PDMA | BITS_GDM_OFRC_P_CPU_PDMA)
+
+#define BITS_GDM_UFRC_P_CPU_QDMA (NR_QDMA_PORT << 12)
+#define BITS_GDM_BFRC_P_CPU_QDMA (NR_QDMA_PORT << 8)
+#define BITS_GDM_MFRC_P_CPU_QDMA (NR_QDMA_PORT << 4)
+#define BITS_GDM_OFRC_P_CPU_QDMA (NR_QDMA_PORT << 0)
+#define BITS_GDM_ALL_FRC_P_CPU_QDMA                                           \
+	(BITS_GDM_UFRC_P_CPU_QDMA | BITS_GDM_BFRC_P_CPU_QDMA |               \
+	 BITS_GDM_MFRC_P_CPU_QDMA | BITS_GDM_OFRC_P_CPU_QDMA)
+
+#define BITS_GDM_UFRC_P_DISCARD (NR_DISCARD << 12)
+#define BITS_GDM_BFRC_P_DISCARD (NR_DISCARD << 8)
+#define BITS_GDM_MFRC_P_DISCARD (NR_DISCARD << 4)
+#define BITS_GDM_OFRC_P_DISCARD (NR_DISCARD << 0)
+#define BITS_GDM_ALL_FRC_P_DISCARD                                            \
+	(BITS_GDM_UFRC_P_DISCARD | BITS_GDM_BFRC_P_DISCARD |                 \
+	 BITS_GDM_MFRC_P_DISCARD | BITS_GDM_OFRC_P_DISCARD)
+
+#define hnat_is_enabled(hnat_priv) (hnat_priv->enable)
+#define hnat_enabled(hnat_priv) (hnat_priv->enable = 1)
+#define hnat_disabled(hnat_priv) (hnat_priv->enable = 0)
+#define hnat_is_enabled1(hnat_priv) (hnat_priv->enable1)
+#define hnat_enabled1(hnat_priv) (hnat_priv->enable1 = 1)
+#define hnat_disabled1(hnat_priv) (hnat_priv->enable1 = 0)
+
+#define entry_hnat_is_bound(e) (e->bfib1.state == BIND)
+#define entry_hnat_state(e) (e->bfib1.state)
+
+#define skb_hnat_is_hashed(skb)                                                \
+	(skb_hnat_entry(skb) != 0x3fff && skb_hnat_entry(skb) < hnat_priv->foe_etry_num)
+#define FROM_GE_LAN(skb) (skb_hnat_iface(skb) == FOE_MAGIC_GE_LAN)
+#define FROM_GE_WAN(skb) (skb_hnat_iface(skb) == FOE_MAGIC_GE_WAN)
+#define FROM_GE_PPD(skb) (skb_hnat_iface(skb) == FOE_MAGIC_GE_PPD)
+#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))
+#define FOE_MAGIC_GE_LAN 0x1
+#define FOE_MAGIC_GE_WAN 0x2
+#define FOE_MAGIC_EXT 0x3
+#define FOE_MAGIC_GE_VIRTUAL 0x4
+#define FOE_MAGIC_GE_PPD 0x5
+#define FOE_MAGIC_WED0 0x78
+#define FOE_MAGIC_WED1 0x79
+#define FOE_INVALID 0xf
+#define index6b(i) (0x3fU - i)
+
+#define IPV4_HNAPT 0
+#define IPV4_HNAT 1
+#define IP_FORMAT(addr)                                                        \
+	(((unsigned char *)&addr)[3], ((unsigned char *)&addr)[2],              \
+	((unsigned char *)&addr)[1], ((unsigned char *)&addr)[0])
+
+/*PSE Ports*/
+#define NR_PDMA_PORT 0
+#define NR_GMAC1_PORT 1
+#define NR_GMAC2_PORT 2
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#define NR_WHNAT_WDMA_PORT EINVAL
+#define NR_PPE0_PORT 3
+#define NR_PPE1_PORT 4
+#else
+#define NR_WHNAT_WDMA_PORT 3
+#define NR_PPE0_PORT 4
+#endif
+#define NR_QDMA_PORT 5
+#define NR_DISCARD 7
+#define NR_WDMA0_PORT 8
+#define NR_WDMA1_PORT 9
+#define LAN_DEV_NAME hnat_priv->lan
+#define IS_WAN(dev)                                                            \
+	(!strncmp((dev)->name, hnat_priv->wan, strlen(hnat_priv->wan)))
+#define IS_LAN(dev) (!strncmp(dev->name, LAN_DEV_NAME, strlen(LAN_DEV_NAME)))
+#define IS_BR(dev) (!strncmp(dev->name, "br", 2))
+#define IS_WHNAT(dev)								\
+	((hnat_priv->data->whnat &&						\
+	 (get_wifi_hook_if_index_from_dev(dev) != 0)) ? 1 : 0)
+#define IS_EXT(dev) ((get_index_from_dev(dev) != 0) ? 1 : 0)
+#define IS_PPD(dev) (!strcmp(dev->name, hnat_priv->ppd))
+#define IS_IPV4_HNAPT(x) (((x)->bfib1.pkt_type == IPV4_HNAPT) ? 1 : 0)
+#define IS_IPV4_HNAT(x) (((x)->bfib1.pkt_type == IPV4_HNAT) ? 1 : 0)
+#define IS_IPV4_GRP(x) (IS_IPV4_HNAPT(x) | IS_IPV4_HNAT(x))
+#define IS_IPV4_DSLITE(x) (((x)->bfib1.pkt_type == IPV4_DSLITE) ? 1 : 0)
+#define IS_IPV4_MAPE(x) (((x)->bfib1.pkt_type == IPV4_MAP_E) ? 1 : 0)
+#define IS_IPV4_MAPT(x) (((x)->bfib1.pkt_type == IPV4_MAP_T) ? 1 : 0)
+#define IS_IPV6_3T_ROUTE(x) (((x)->bfib1.pkt_type == IPV6_3T_ROUTE) ? 1 : 0)
+#define IS_IPV6_5T_ROUTE(x) (((x)->bfib1.pkt_type == IPV6_5T_ROUTE) ? 1 : 0)
+#define IS_IPV6_6RD(x) (((x)->bfib1.pkt_type == IPV6_6RD) ? 1 : 0)
+#define IS_IPV6_GRP(x)                                                         \
+	(IS_IPV6_3T_ROUTE(x) | IS_IPV6_5T_ROUTE(x) | IS_IPV6_6RD(x) |          \
+	 IS_IPV4_DSLITE(x) | IS_IPV4_MAPE(x) | IS_IPV4_MAPT(x))
+#define IS_BOND_MODE (!strncmp(LAN_DEV_NAME, "bond", 4))
+#define IS_GMAC1_MODE ((hnat_priv->gmac_num == 1) ? 1 : 0)
+#define IS_HQOS_MODE (qos_toggle == 1)
+#define IS_PPPQ_MODE (qos_toggle == 2)		/* Per Port Per Queue */
+#define MAX_PPPQ_PORT_NUM	6
+
+#define es(entry) (entry_state[entry->bfib1.state])
+#define ei(entry, end) (hnat_priv->foe_etry_num - (int)(end - entry))
+#define pt(entry) (packet_type[entry->ipv4_hnapt.bfib1.pkt_type])
+#define ipv4_smac(mac, e)                                                      \
+	({                                                                     \
+		mac[0] = e->ipv4_hnapt.smac_hi[3];                             \
+		mac[1] = e->ipv4_hnapt.smac_hi[2];                             \
+		mac[2] = e->ipv4_hnapt.smac_hi[1];                             \
+		mac[3] = e->ipv4_hnapt.smac_hi[0];                             \
+		mac[4] = e->ipv4_hnapt.smac_lo[1];                             \
+		mac[5] = e->ipv4_hnapt.smac_lo[0];                             \
+	})
+#define ipv4_dmac(mac, e)                                                      \
+	({                                                                     \
+		mac[0] = e->ipv4_hnapt.dmac_hi[3];                             \
+		mac[1] = e->ipv4_hnapt.dmac_hi[2];                             \
+		mac[2] = e->ipv4_hnapt.dmac_hi[1];                             \
+		mac[3] = e->ipv4_hnapt.dmac_hi[0];                             \
+		mac[4] = e->ipv4_hnapt.dmac_lo[1];                             \
+		mac[5] = e->ipv4_hnapt.dmac_lo[0];                             \
+	})
+
+#define IS_DSA_LAN(dev) (!strncmp(dev->name, "lan", 3))
+#define IS_DSA_WAN(dev) (!strncmp(dev->name, "wan", 3))
+#define NONE_DSA_PORT 0xff
+#define MAX_CRSN_NUM 32
+#define IPV6_HDR_LEN 40
+
+/*QDMA_PAGE value*/
+#define NUM_OF_Q_PER_PAGE 16
+
+/*IPv6 Header*/
+#ifndef NEXTHDR_IPIP
+#define NEXTHDR_IPIP 4
+#endif
+
+extern const struct of_device_id of_hnat_match[];
+extern struct mtk_hnat *hnat_priv;
+
+#if defined(CONFIG_NET_DSA_MT7530)
+u32 hnat_dsa_fill_stag(const struct net_device *netdev,
+		       struct foe_entry *entry,
+		       struct flow_offload_hw_path *hw_path,
+		       u16 eth_proto, int mape);
+
+static inline bool hnat_dsa_is_enable(struct mtk_hnat *priv)
+{
+	return (priv->wan_dsa_port != NONE_DSA_PORT);
+}
+#else
+static inline u32 hnat_dsa_fill_stag(const struct net_device *netdev,
+				     struct foe_entry *entry,
+				     struct flow_offload_hw_path *hw_path,
+				     u16 eth_proto, int mape)
+{
+}
+
+static inline bool hnat_dsa_is_enable(struct mtk_hnat *priv)
+{
+	return false;
+}
+#endif
+
+void hnat_deinit_debugfs(struct mtk_hnat *h);
+int hnat_init_debugfs(struct mtk_hnat *h);
+int hnat_register_nf_hooks(void);
+void hnat_unregister_nf_hooks(void);
+int whnat_adjust_nf_hooks(void);
+int mtk_hqos_ptype_cb(struct sk_buff *skb, struct net_device *dev,
+		      struct packet_type *pt, struct net_device *unused);
+extern int dbg_cpu_reason;
+extern int debug_level;
+extern int hook_toggle;
+extern int mape_toggle;
+extern int qos_toggle;
+
+int ext_if_add(struct extdev_entry *ext_entry);
+int ext_if_del(struct extdev_entry *ext_entry);
+void cr_set_field(void __iomem *reg, u32 field, u32 val);
+int mtk_sw_nat_hook_tx(struct sk_buff *skb, int gmac_no);
+int mtk_sw_nat_hook_rx(struct sk_buff *skb);
+void mtk_ppe_dev_register_hook(struct net_device *dev);
+void mtk_ppe_dev_unregister_hook(struct net_device *dev);
+int nf_hnat_netdevice_event(struct notifier_block *unused, unsigned long event,
+			    void *ptr);
+int nf_hnat_netevent_handler(struct notifier_block *unused, unsigned long event,
+			     void *ptr);
+uint32_t foe_dump_pkt(struct sk_buff *skb);
+uint32_t hnat_cpu_reason_cnt(struct sk_buff *skb);
+int hnat_enable_hook(void);
+int hnat_disable_hook(void);
+void hnat_cache_ebl(int enable);
+void hnat_qos_shaper_ebl(u32 id, u32 enable);
+void set_gmac_ppe_fwd(int gmac_no, int enable);
+int entry_detail(u32 ppe_id, int index);
+int entry_delete_by_mac(u8 *mac);
+int entry_delete(u32 ppe_id, int index);
+struct hnat_accounting *hnat_get_count(struct mtk_hnat *h, u32 ppe_id,
+				       u32 index, struct hnat_accounting *diff);
+
+static inline u16 foe_timestamp(struct mtk_hnat *h)
+{
+	return (readl(hnat_priv->fe_base + 0x0010)) & 0xffff;
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
new file mode 100644
index 0000000..a5403a8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
@@ -0,0 +1,2294 @@
+/*   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; version 2 of the License
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   Copyright (C) 2014-2016 Sean Wang <sean.wang@mediatek.com>
+ *   Copyright (C) 2016-2017 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/iopoll.h>
+
+#include "hnat.h"
+#include "nf_hnat_mtk.h"
+#include "../mtk_eth_soc.h"
+
+int dbg_entry_state = BIND;
+typedef int (*debugfs_write_func)(int par1);
+int debug_level;
+int dbg_cpu_reason;
+int hook_toggle;
+int mape_toggle;
+int qos_toggle;
+unsigned int dbg_cpu_reason_cnt[MAX_CRSN_NUM];
+
+static const char * const entry_state[] = { "INVALID", "UNBIND", "BIND", "FIN" };
+
+static const char * const packet_type[] = {
+	"IPV4_HNAPT",    "IPV4_HNAT",     "IPV6_1T_ROUTE", "IPV4_DSLITE",
+	"IPV6_3T_ROUTE", "IPV6_5T_ROUTE", "REV",	   "IPV6_6RD",
+	"IPV4_MAP_T",    "IPV4_MAP_E",
+};
+
+static uint8_t *show_cpu_reason(struct sk_buff *skb)
+{
+	static u8 buf[32];
+
+	switch (skb_hnat_reason(skb)) {
+	case TTL_0:
+		return "IPv4(IPv6) TTL(hop limit)\n";
+	case HAS_OPTION_HEADER:
+		return "Ipv4(IPv6) has option(extension) header\n";
+	case NO_FLOW_IS_ASSIGNED:
+		return "No flow is assigned\n";
+	case IPV4_WITH_FRAGMENT:
+		return "IPv4 HNAT doesn't support IPv4 /w fragment\n";
+	case IPV4_HNAPT_DSLITE_WITH_FRAGMENT:
+		return "IPv4 HNAPT/DS-Lite doesn't support IPv4 /w fragment\n";
+	case IPV4_HNAPT_DSLITE_WITHOUT_TCP_UDP:
+		return "IPv4 HNAPT/DS-Lite can't find TCP/UDP sport/dport\n";
+	case IPV6_5T_6RD_WITHOUT_TCP_UDP:
+		return "IPv6 5T-route/6RD can't find TCP/UDP sport/dport\n";
+	case TCP_FIN_SYN_RST:
+		return "Ingress packet is TCP fin/syn/rst\n";
+	case UN_HIT:
+		return "FOE Un-hit\n";
+	case HIT_UNBIND:
+		return "FOE Hit unbind\n";
+	case HIT_UNBIND_RATE_REACH:
+		return "FOE Hit unbind & rate reach\n";
+	case HIT_BIND_TCP_FIN:
+		return "Hit bind PPE TCP FIN entry\n";
+	case HIT_BIND_TTL_1:
+		return "Hit bind PPE entry and TTL(hop limit) = 1 and TTL(hot limit) - 1\n";
+	case HIT_BIND_WITH_VLAN_VIOLATION:
+		return "Hit bind and VLAN replacement violation\n";
+	case HIT_BIND_KEEPALIVE_UC_OLD_HDR:
+		return "Hit bind and keep alive with unicast old-header packet\n";
+	case HIT_BIND_KEEPALIVE_MC_NEW_HDR:
+		return "Hit bind and keep alive with multicast new-header packet\n";
+	case HIT_BIND_KEEPALIVE_DUP_OLD_HDR:
+		return "Hit bind and keep alive with duplicate old-header packet\n";
+	case HIT_BIND_FORCE_TO_CPU:
+		return "FOE Hit bind & force to CPU\n";
+	case HIT_BIND_EXCEED_MTU:
+		return "Hit bind and exceed MTU\n";
+	case HIT_BIND_MULTICAST_TO_CPU:
+		return "Hit bind multicast packet to CPU\n";
+	case HIT_BIND_MULTICAST_TO_GMAC_CPU:
+		return "Hit bind multicast packet to GMAC & CPU\n";
+	case HIT_PRE_BIND:
+		return "Pre bind\n";
+	}
+
+	sprintf(buf, "CPU Reason Error - %X\n", skb_hnat_entry(skb));
+	return buf;
+}
+
+uint32_t foe_dump_pkt(struct sk_buff *skb)
+{
+	struct foe_entry *entry;
+
+	if (skb_hnat_entry(skb) >= hnat_priv->foe_etry_num ||
+	    skb_hnat_ppe(skb) >= CFG_PPE_NUM)
+		return 1;
+
+	entry = &hnat_priv->foe_table_cpu[skb_hnat_ppe(skb)][skb_hnat_entry(skb)];
+	pr_info("\nRx===<FOE_Entry=%d>=====\n", skb_hnat_entry(skb));
+	pr_info("RcvIF=%s\n", skb->dev->name);
+	pr_info("PPE_ID=%d\n", skb_hnat_ppe(skb));
+	pr_info("FOE_Entry=%d\n", skb_hnat_entry(skb));
+	pr_info("CPU Reason=%s", show_cpu_reason(skb));
+	pr_info("ALG=%d\n", skb_hnat_alg(skb));
+	pr_info("SP=%d\n", skb_hnat_sport(skb));
+
+	/* some special alert occurred, so entry_num is useless (just skip it) */
+	if (skb_hnat_entry(skb) == 0x3fff)
+		return 1;
+
+	/* PPE: IPv4 packet=IPV4_HNAT IPv6 packet=IPV6_ROUTE */
+	if (IS_IPV4_GRP(entry)) {
+		__be32 saddr = htonl(entry->ipv4_hnapt.sip);
+		__be32 daddr = htonl(entry->ipv4_hnapt.dip);
+
+		pr_info("Information Block 1=%x\n",
+			entry->ipv4_hnapt.info_blk1);
+		pr_info("SIP=%pI4\n", &saddr);
+		pr_info("DIP=%pI4\n", &daddr);
+		pr_info("SPORT=%d\n", entry->ipv4_hnapt.sport);
+		pr_info("DPORT=%d\n", entry->ipv4_hnapt.dport);
+		pr_info("Information Block 2=%x\n",
+			entry->ipv4_hnapt.info_blk2);
+		pr_info("State = %s, proto = %s\n", entry->bfib1.state == 0 ?
+			"Invalid" : entry->bfib1.state == 1 ?
+			"Unbind" : entry->bfib1.state == 2 ?
+			"BIND" : entry->bfib1.state == 3 ?
+			"FIN" : "Unknown",
+			entry->ipv4_hnapt.bfib1.udp == 0 ?
+			"TCP" : entry->ipv4_hnapt.bfib1.udp == 1 ?
+			"UDP" : "Unknown");
+	} else if (IS_IPV6_GRP(entry)) {
+		pr_info("Information Block 1=%x\n",
+			entry->ipv6_5t_route.info_blk1);
+		pr_info("IPv6_SIP=%08X:%08X:%08X:%08X\n",
+			entry->ipv6_5t_route.ipv6_sip0,
+			entry->ipv6_5t_route.ipv6_sip1,
+			entry->ipv6_5t_route.ipv6_sip2,
+			entry->ipv6_5t_route.ipv6_sip3);
+		pr_info("IPv6_DIP=%08X:%08X:%08X:%08X\n",
+			entry->ipv6_5t_route.ipv6_dip0,
+			entry->ipv6_5t_route.ipv6_dip1,
+			entry->ipv6_5t_route.ipv6_dip2,
+			entry->ipv6_5t_route.ipv6_dip3);
+		pr_info("SPORT=%d\n", entry->ipv6_5t_route.sport);
+		pr_info("DPORT=%d\n", entry->ipv6_5t_route.dport);
+		pr_info("Information Block 2=%x\n",
+			entry->ipv6_5t_route.info_blk2);
+		pr_info("State = %s, proto = %s\n", entry->bfib1.state == 0 ?
+			"Invalid" : entry->bfib1.state == 1 ?
+			"Unbind" : entry->bfib1.state == 2 ?
+			"BIND" : entry->bfib1.state == 3 ?
+			"FIN" : "Unknown",
+			entry->ipv6_5t_route.bfib1.udp == 0 ?
+			"TCP" : entry->ipv6_5t_route.bfib1.udp == 1 ?
+			"UDP" :	"Unknown");
+	} else {
+		pr_info("unknown Pkt_type=%d\n", entry->bfib1.pkt_type);
+	}
+
+	pr_info("==================================\n");
+	return 1;
+}
+
+uint32_t hnat_cpu_reason_cnt(struct sk_buff *skb)
+{
+	switch (skb_hnat_reason(skb)) {
+	case TTL_0:
+		dbg_cpu_reason_cnt[0]++;
+		return 0;
+	case HAS_OPTION_HEADER:
+		dbg_cpu_reason_cnt[1]++;
+		return 0;
+	case NO_FLOW_IS_ASSIGNED:
+		dbg_cpu_reason_cnt[2]++;
+		return 0;
+	case IPV4_WITH_FRAGMENT:
+		dbg_cpu_reason_cnt[3]++;
+		return 0;
+	case IPV4_HNAPT_DSLITE_WITH_FRAGMENT:
+		dbg_cpu_reason_cnt[4]++;
+		return 0;
+	case IPV4_HNAPT_DSLITE_WITHOUT_TCP_UDP:
+		dbg_cpu_reason_cnt[5]++;
+		return 0;
+	case IPV6_5T_6RD_WITHOUT_TCP_UDP:
+		dbg_cpu_reason_cnt[6]++;
+		return 0;
+	case TCP_FIN_SYN_RST:
+		dbg_cpu_reason_cnt[7]++;
+		return 0;
+	case UN_HIT:
+		dbg_cpu_reason_cnt[8]++;
+		return 0;
+	case HIT_UNBIND:
+		dbg_cpu_reason_cnt[9]++;
+		return 0;
+	case HIT_UNBIND_RATE_REACH:
+		dbg_cpu_reason_cnt[10]++;
+		return 0;
+	case HIT_BIND_TCP_FIN:
+		dbg_cpu_reason_cnt[11]++;
+		return 0;
+	case HIT_BIND_TTL_1:
+		dbg_cpu_reason_cnt[12]++;
+		return 0;
+	case HIT_BIND_WITH_VLAN_VIOLATION:
+		dbg_cpu_reason_cnt[13]++;
+		return 0;
+	case HIT_BIND_KEEPALIVE_UC_OLD_HDR:
+		dbg_cpu_reason_cnt[14]++;
+		return 0;
+	case HIT_BIND_KEEPALIVE_MC_NEW_HDR:
+		dbg_cpu_reason_cnt[15]++;
+		return 0;
+	case HIT_BIND_KEEPALIVE_DUP_OLD_HDR:
+		dbg_cpu_reason_cnt[16]++;
+		return 0;
+	case HIT_BIND_FORCE_TO_CPU:
+		dbg_cpu_reason_cnt[17]++;
+		return 0;
+	case HIT_BIND_EXCEED_MTU:
+		dbg_cpu_reason_cnt[18]++;
+		return 0;
+	case HIT_BIND_MULTICAST_TO_CPU:
+		dbg_cpu_reason_cnt[19]++;
+		return 0;
+	case HIT_BIND_MULTICAST_TO_GMAC_CPU:
+		dbg_cpu_reason_cnt[20]++;
+		return 0;
+	case HIT_PRE_BIND:
+		dbg_cpu_reason_cnt[21]++;
+		return 0;
+	}
+
+	return 0;
+}
+
+int hnat_set_usage(int level)
+{
+	debug_level = level;
+	pr_info("Read cpu_reason count: cat /sys/kernel/debug/hnat/cpu_reason\n\n");
+	pr_info("====================Advanced Settings====================\n");
+	pr_info("Usage: echo [type] [option] > /sys/kernel/debug/hnat/cpu_reason\n\n");
+	pr_info("Commands:   [type] [option]\n");
+	pr_info("              0       0~7      Set debug_level(0~7), current debug_level=%d\n",
+		debug_level);
+	pr_info("              1    cpu_reason  Track entries of the set cpu_reason\n");
+	pr_info("                               Set type=1 will change debug_level=7\n");
+	pr_info("cpu_reason list:\n");
+	pr_info("                       2       IPv4(IPv6) TTL(hop limit) = 0\n");
+	pr_info("                       3       IPv4(IPv6) has option(extension) header\n");
+	pr_info("                       7       No flow is assigned\n");
+	pr_info("                       8       IPv4 HNAT doesn't support IPv4 /w fragment\n");
+	pr_info("                       9       IPv4 HNAPT/DS-Lite doesn't support IPv4 /w fragment\n");
+	pr_info("                      10       IPv4 HNAPT/DS-Lite can't find TCP/UDP sport/dport\n");
+	pr_info("                      11       IPv6 5T-route/6RD can't find TCP/UDP sport/dport\n");
+	pr_info("                      12       Ingress packet is TCP fin/syn/rst\n");
+	pr_info("                      13       FOE Un-hit\n");
+	pr_info("                      14       FOE Hit unbind\n");
+	pr_info("                      15       FOE Hit unbind & rate reach\n");
+	pr_info("                      16       Hit bind PPE TCP FIN entry\n");
+	pr_info("                      17       Hit bind PPE entry and TTL(hop limit) = 1\n");
+	pr_info("                      18       Hit bind and VLAN replacement violation\n");
+	pr_info("                      19       Hit bind and keep alive with unicast old-header packet\n");
+	pr_info("                      20       Hit bind and keep alive with multicast new-header packet\n");
+	pr_info("                      21       Hit bind and keep alive with duplicate old-header packet\n");
+	pr_info("                      22       FOE Hit bind & force to CPU\n");
+	pr_info("                      23       HIT_BIND_WITH_OPTION_HEADER\n");
+	pr_info("                      24       Switch clone multicast packet to CPU\n");
+	pr_info("                      25       Switch clone multicast packet to GMAC1 & CPU\n");
+	pr_info("                      26       HIT_PRE_BIND\n");
+	pr_info("                      27       HIT_BIND_PACKET_SAMPLING\n");
+	pr_info("                      28       Hit bind and exceed MTU\n");
+
+	return 0;
+}
+
+int hnat_cpu_reason(int cpu_reason)
+{
+	dbg_cpu_reason = cpu_reason;
+	debug_level = 7;
+	pr_info("show cpu reason = %d\n", cpu_reason);
+
+	return 0;
+}
+
+int entry_set_usage(int level)
+{
+	debug_level = level;
+	pr_info("Show all entries(default state=bind): cat /sys/kernel/debug/hnat/hnat_entry\n\n");
+	pr_info("====================Advanced Settings====================\n");
+	pr_info("Usage: echo [type] [option] > /sys/kernel/debug/hnat/hnat_entry\n\n");
+	pr_info("Commands:   [type] [option]\n");
+	pr_info("              0       0~7      Set debug_level(0~7), current debug_level=%d\n",
+		debug_level);
+	pr_info("              1       0~3      Change tracking state\n");
+	pr_info("                               (0:invalid; 1:unbind; 2:bind; 3:fin)\n");
+	pr_info("              2   <entry_idx>  Show PPE0 specific foe entry info. of assigned <entry_idx>\n");
+	pr_info("              3   <entry_idx>  Delete PPE0 specific foe entry of assigned <entry_idx>\n");
+	pr_info("              4   <entry_idx>  Show PPE1 specific foe entry info. of assigned <entry_idx>\n");
+	pr_info("              5   <entry_idx>  Delete PPE1 specific foe entry of assigned <entry_idx>\n");
+	pr_info("                               When entry_idx is -1, clear all entries\n");
+
+	return 0;
+}
+
+int entry_set_state(int state)
+{
+	dbg_entry_state = state;
+	pr_info("ENTRY STATE = %s\n", dbg_entry_state == 0 ?
+		"Invalid" : dbg_entry_state == 1 ?
+		"Unbind" : dbg_entry_state == 2 ?
+		"BIND" : dbg_entry_state == 3 ?
+		"FIN" : "Unknown");
+	return 0;
+}
+
+int wrapped_ppe0_entry_detail(int index) {
+	entry_detail(0, index);
+	return 0;
+}
+
+int wrapped_ppe1_entry_detail(int index) {
+	entry_detail(1, index);
+	return 0;
+}
+
+int entry_detail(u32 ppe_id, int index)
+{
+	struct foe_entry *entry;
+	struct mtk_hnat *h = hnat_priv;
+	u32 *p;
+	u32 i = 0;
+	u32 print_cnt;
+	unsigned char h_dest[ETH_ALEN];
+	unsigned char h_source[ETH_ALEN];
+	__be32 saddr, daddr, nsaddr, ndaddr;
+
+	if (ppe_id >= CFG_PPE_NUM)
+		return -EINVAL;
+
+	if (index < 0 || index >= h->foe_etry_num) {
+		pr_info("Invalid entry index\n");
+		return -EINVAL;
+	}
+
+	entry = h->foe_table_cpu[ppe_id] + index;
+	saddr = htonl(entry->ipv4_hnapt.sip);
+	daddr = htonl(entry->ipv4_hnapt.dip);
+	nsaddr = htonl(entry->ipv4_hnapt.new_sip);
+	ndaddr = htonl(entry->ipv4_hnapt.new_dip);
+	p = (uint32_t *)entry;
+	pr_info("==========<PPE_ID=%d, Flow Table Entry=%d (%p)>===============\n",
+		ppe_id, index, entry);
+	if (debug_level >= 2) {
+		print_cnt = 20;
+		for (i = 0; i < print_cnt; i++)
+			pr_info("%02d: %08X\n", i, *(p + i));
+	}
+	pr_info("-----------------<Flow Info>------------------\n");
+	pr_info("Information Block 1: %08X\n", entry->ipv4_hnapt.info_blk1);
+
+	if (IS_IPV4_HNAPT(entry)) {
+		pr_info("Information Block 2: %08X (FP=%d FQOS=%d QID=%d)",
+			entry->ipv4_hnapt.info_blk2,
+			entry->ipv4_hnapt.iblk2.dp,
+			entry->ipv4_hnapt.iblk2.fqos,
+			entry->ipv4_hnapt.iblk2.qid);
+		pr_info("Create IPv4 HNAPT entry\n");
+		pr_info("IPv4 Org IP/Port: %pI4:%d->%pI4:%d\n", &saddr,
+			entry->ipv4_hnapt.sport, &daddr,
+			entry->ipv4_hnapt.dport);
+		pr_info("IPv4 New IP/Port: %pI4:%d->%pI4:%d\n", &nsaddr,
+			entry->ipv4_hnapt.new_sport, &ndaddr,
+			entry->ipv4_hnapt.new_dport);
+	} else if (IS_IPV4_HNAT(entry)) {
+		pr_info("Information Block 2: %08X\n",
+			entry->ipv4_hnapt.info_blk2);
+		pr_info("Create IPv4 HNAT entry\n");
+		pr_info("IPv4 Org IP: %pI4->%pI4\n", &saddr, &daddr);
+		pr_info("IPv4 New IP: %pI4->%pI4\n", &nsaddr, &ndaddr);
+	} else if (IS_IPV4_DSLITE(entry)) {
+		pr_info("Information Block 2: %08X\n",
+			entry->ipv4_dslite.info_blk2);
+		pr_info("Create IPv4 Ds-Lite entry\n");
+		pr_info("IPv4 Ds-Lite: %pI4:%d->%pI4:%d\n", &saddr,
+			entry->ipv4_dslite.sport, &daddr,
+			entry->ipv4_dslite.dport);
+		pr_info("EG DIPv6: %08X:%08X:%08X:%08X->%08X:%08X:%08X:%08X\n",
+			entry->ipv4_dslite.tunnel_sipv6_0,
+			entry->ipv4_dslite.tunnel_sipv6_1,
+			entry->ipv4_dslite.tunnel_sipv6_2,
+			entry->ipv4_dslite.tunnel_sipv6_3,
+			entry->ipv4_dslite.tunnel_dipv6_0,
+			entry->ipv4_dslite.tunnel_dipv6_1,
+			entry->ipv4_dslite.tunnel_dipv6_2,
+			entry->ipv4_dslite.tunnel_dipv6_3);
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+	} else if (IS_IPV4_MAPE(entry)) {
+		nsaddr = htonl(entry->ipv4_dslite.new_sip);
+		ndaddr = htonl(entry->ipv4_dslite.new_dip);
+
+		pr_info("Information Block 2: %08X\n",
+			entry->ipv4_dslite.info_blk2);
+		pr_info("Create IPv4 MAP-E entry\n");
+		pr_info("IPv4 MAP-E Org IP/Port: %pI4:%d->%pI4:%d\n",
+			&saddr,	entry->ipv4_dslite.sport,
+			&daddr,	entry->ipv4_dslite.dport);
+		pr_info("IPv4 MAP-E New IP/Port: %pI4:%d->%pI4:%d\n",
+			&nsaddr, entry->ipv4_dslite.new_sport,
+			&ndaddr, entry->ipv4_dslite.new_dport);
+		pr_info("EG DIPv6: %08X:%08X:%08X:%08X->%08X:%08X:%08X:%08X\n",
+			entry->ipv4_dslite.tunnel_sipv6_0,
+			entry->ipv4_dslite.tunnel_sipv6_1,
+			entry->ipv4_dslite.tunnel_sipv6_2,
+			entry->ipv4_dslite.tunnel_sipv6_3,
+			entry->ipv4_dslite.tunnel_dipv6_0,
+			entry->ipv4_dslite.tunnel_dipv6_1,
+			entry->ipv4_dslite.tunnel_dipv6_2,
+			entry->ipv4_dslite.tunnel_dipv6_3);
+#endif
+	} else if (IS_IPV6_3T_ROUTE(entry)) {
+		pr_info("Information Block 2: %08X\n",
+			entry->ipv6_3t_route.info_blk2);
+		pr_info("Create IPv6 3-Tuple entry\n");
+		pr_info("ING SIPv6->DIPv6: %08X:%08X:%08X:%08X-> %08X:%08X:%08X:%08X (Prot=%d)\n",
+			entry->ipv6_3t_route.ipv6_sip0,
+			entry->ipv6_3t_route.ipv6_sip1,
+			entry->ipv6_3t_route.ipv6_sip2,
+			entry->ipv6_3t_route.ipv6_sip3,
+			entry->ipv6_3t_route.ipv6_dip0,
+			entry->ipv6_3t_route.ipv6_dip1,
+			entry->ipv6_3t_route.ipv6_dip2,
+			entry->ipv6_3t_route.ipv6_dip3,
+			entry->ipv6_3t_route.prot);
+	} else if (IS_IPV6_5T_ROUTE(entry)) {
+		pr_info("Information Block 2: %08X\n",
+			entry->ipv6_5t_route.info_blk2);
+		pr_info("Create IPv6 5-Tuple entry\n");
+		pr_info("ING SIPv6->DIPv6: %08X:%08X:%08X:%08X:%d-> %08X:%08X:%08X:%08X:%d\n",
+			entry->ipv6_5t_route.ipv6_sip0,
+			entry->ipv6_5t_route.ipv6_sip1,
+			entry->ipv6_5t_route.ipv6_sip2,
+			entry->ipv6_5t_route.ipv6_sip3,
+			entry->ipv6_5t_route.sport,
+			entry->ipv6_5t_route.ipv6_dip0,
+			entry->ipv6_5t_route.ipv6_dip1,
+			entry->ipv6_5t_route.ipv6_dip2,
+			entry->ipv6_5t_route.ipv6_dip3,
+			entry->ipv6_5t_route.dport);
+	} else if (IS_IPV6_6RD(entry)) {
+		pr_info("Information Block 2: %08X\n",
+			entry->ipv6_6rd.info_blk2);
+		pr_info("Create IPv6 6RD entry\n");
+		pr_info("ING SIPv6->DIPv6: %08X:%08X:%08X:%08X:%d-> %08X:%08X:%08X:%08X:%d\n",
+			entry->ipv6_6rd.ipv6_sip0, entry->ipv6_6rd.ipv6_sip1,
+			entry->ipv6_6rd.ipv6_sip2, entry->ipv6_6rd.ipv6_sip3,
+			entry->ipv6_6rd.sport, entry->ipv6_6rd.ipv6_dip0,
+			entry->ipv6_6rd.ipv6_dip1, entry->ipv6_6rd.ipv6_dip2,
+			entry->ipv6_6rd.ipv6_dip3, entry->ipv6_6rd.dport);
+	}
+	if (IS_IPV4_HNAPT(entry) || IS_IPV4_HNAT(entry)) {
+		*((u32 *)h_source) = swab32(entry->ipv4_hnapt.smac_hi);
+		*((u16 *)&h_source[4]) = swab16(entry->ipv4_hnapt.smac_lo);
+		*((u32 *)h_dest) = swab32(entry->ipv4_hnapt.dmac_hi);
+		*((u16 *)&h_dest[4]) = swab16(entry->ipv4_hnapt.dmac_lo);
+		pr_info("SMAC=%pM => DMAC=%pM\n", h_source, h_dest);
+		pr_info("State = %s, ",	entry->bfib1.state == 0 ?
+			"Invalid" : entry->bfib1.state == 1 ?
+			"Unbind" : entry->bfib1.state == 2 ?
+			"BIND" : entry->bfib1.state == 3 ?
+			"FIN" : "Unknown");
+		pr_info("Vlan_Layer = %u, ", entry->bfib1.vlan_layer);
+		pr_info("Eth_type = 0x%x, Vid1 = 0x%x, Vid2 = 0x%x\n",
+			entry->ipv4_hnapt.etype, entry->ipv4_hnapt.vlan1,
+			entry->ipv4_hnapt.vlan2);
+		pr_info("multicast = %d, pppoe = %d, proto = %s\n",
+			entry->ipv4_hnapt.iblk2.mcast,
+			entry->ipv4_hnapt.bfib1.psn,
+			entry->ipv4_hnapt.bfib1.udp == 0 ?
+			"TCP" :	entry->ipv4_hnapt.bfib1.udp == 1 ?
+			"UDP" : "Unknown");
+		pr_info("=========================================\n\n");
+	} else {
+		*((u32 *)h_source) = swab32(entry->ipv6_5t_route.smac_hi);
+		*((u16 *)&h_source[4]) = swab16(entry->ipv6_5t_route.smac_lo);
+		*((u32 *)h_dest) = swab32(entry->ipv6_5t_route.dmac_hi);
+		*((u16 *)&h_dest[4]) = swab16(entry->ipv6_5t_route.dmac_lo);
+		pr_info("SMAC=%pM => DMAC=%pM\n", h_source, h_dest);
+		pr_info("State = %s, ",	entry->bfib1.state == 0 ?
+			"Invalid" : entry->bfib1.state == 1 ?
+			"Unbind" : entry->bfib1.state == 2 ?
+			"BIND" : entry->bfib1.state == 3 ?
+			"FIN" : "Unknown");
+
+		pr_info("Vlan_Layer = %u, ", entry->bfib1.vlan_layer);
+		pr_info("Eth_type = 0x%x, Vid1 = 0x%x, Vid2 = 0x%x\n",
+			entry->ipv6_5t_route.etype, entry->ipv6_5t_route.vlan1,
+			entry->ipv6_5t_route.vlan2);
+		pr_info("multicast = %d, pppoe = %d, proto = %s\n",
+			entry->ipv6_5t_route.iblk2.mcast,
+			entry->ipv6_5t_route.bfib1.psn,
+			entry->ipv6_5t_route.bfib1.udp == 0 ?
+			"TCP" :	entry->ipv6_5t_route.bfib1.udp == 1 ?
+			"UDP" :	"Unknown");
+		pr_info("=========================================\n\n");
+	}
+	return 0;
+}
+
+int wrapped_ppe0_entry_delete(int index) {
+	entry_delete(0, index);
+	return 0;
+}
+
+int wrapped_ppe1_entry_delete(int index) {
+	entry_delete(1, index);
+	return 0;
+}
+
+int entry_delete(u32 ppe_id, int index)
+{
+	struct foe_entry *entry;
+	struct mtk_hnat *h = hnat_priv;
+
+	if (ppe_id >= CFG_PPE_NUM)
+		return -EINVAL;
+
+	if (index < -1 || index >= (int)h->foe_etry_num) {
+		pr_info("Invalid entry index\n");
+		return -EINVAL;
+	}
+
+	if (index == -1) {
+		memset(h->foe_table_cpu[ppe_id], 0, h->foe_etry_num * sizeof(struct foe_entry));
+		pr_info("clear all foe entry\n");
+	} else {
+
+		entry = h->foe_table_cpu[ppe_id] + index;
+		memset(entry, 0, sizeof(struct foe_entry));
+		pr_info("delete ppe id = %d, entry idx = %d\n", ppe_id, index);
+	}
+
+	/* clear HWNAT cache */
+	hnat_cache_ebl(1);
+
+	return 0;
+}
+EXPORT_SYMBOL(entry_delete);
+
+int cr_set_usage(int level)
+{
+	debug_level = level;
+	pr_info("Dump hnat CR: cat /sys/kernel/debug/hnat/hnat_setting\n\n");
+	pr_info("====================Advanced Settings====================\n");
+	pr_info("Usage: echo [type] [option] > /sys/kernel/debug/hnat/hnat_setting\n\n");
+	pr_info("Commands:   [type] [option]\n");
+	pr_info("              0     0~7        Set debug_level(0~7), current debug_level=%d\n",
+		debug_level);
+	pr_info("              1     0~65535    Set binding threshold\n");
+	pr_info("              2     0~65535    Set TCP bind lifetime\n");
+	pr_info("              3     0~65535    Set FIN bind lifetime\n");
+	pr_info("              4     0~65535    Set UDP bind lifetime\n");
+	pr_info("              5     0~255      Set TCP keep alive interval\n");
+	pr_info("              6     0~255      Set UDP keep alive interval\n");
+	pr_info("              7     0~1        Set hnat counter update to nf_conntrack\n");
+
+	return 0;
+}
+
+int binding_threshold(int threshold)
+{
+	int i;
+
+	pr_info("Binding Threshold =%d\n", threshold);
+
+	for (i = 0; i < CFG_PPE_NUM; i++)
+		writel(threshold, hnat_priv->ppe_base[i] + PPE_BNDR);
+
+	return 0;
+}
+
+int tcp_bind_lifetime(int tcp_life)
+{
+	int i;
+
+	pr_info("tcp_life = %d\n", tcp_life);
+
+	/* set Delta time for aging out an bind TCP FOE entry */
+	for (i = 0; i < CFG_PPE_NUM; i++)
+		cr_set_field(hnat_priv->ppe_base[i] + PPE_BND_AGE_1,
+			     TCP_DLTA, tcp_life);
+
+	return 0;
+}
+
+int fin_bind_lifetime(int fin_life)
+{
+	int i;
+
+	pr_info("fin_life = %d\n", fin_life);
+
+	/* set Delta time for aging out an bind TCP FIN FOE entry */
+	for (i = 0; i < CFG_PPE_NUM; i++)
+		cr_set_field(hnat_priv->ppe_base[i] + PPE_BND_AGE_1,
+			     FIN_DLTA, fin_life);
+
+	return 0;
+}
+
+int udp_bind_lifetime(int udp_life)
+{
+	int i;
+
+	pr_info("udp_life = %d\n", udp_life);
+
+	/* set Delta time for aging out an bind UDP FOE entry */
+	for (i = 0; i < CFG_PPE_NUM; i++)
+		cr_set_field(hnat_priv->ppe_base[i] + PPE_BND_AGE_0,
+			     UDP_DLTA, udp_life);
+
+	return 0;
+}
+
+int tcp_keep_alive(int tcp_interval)
+{
+	int i;
+
+	if (tcp_interval > 255) {
+		tcp_interval = 255;
+		pr_info("TCP keep alive max interval = 255\n");
+	} else {
+		pr_info("tcp_interval = %d\n", tcp_interval);
+	}
+
+	/* Keep alive time for bind FOE TCP entry */
+	for (i = 0; i < CFG_PPE_NUM; i++)
+		cr_set_field(hnat_priv->ppe_base[i] + PPE_KA,
+			     TCP_KA, tcp_interval);
+
+	return 0;
+}
+
+int udp_keep_alive(int udp_interval)
+{
+	int i;
+
+	if (udp_interval > 255) {
+		udp_interval = 255;
+		pr_info("TCP/UDP keep alive max interval = 255\n");
+	} else {
+		pr_info("udp_interval = %d\n", udp_interval);
+	}
+
+	/* Keep alive timer for bind FOE UDP entry */
+	for (i = 0; i < CFG_PPE_NUM; i++)
+		cr_set_field(hnat_priv->ppe_base[i] + PPE_KA,
+			     UDP_KA, udp_interval);
+
+	return 0;
+}
+
+int set_nf_update_toggle(int toggle)
+{
+	struct mtk_hnat *h = hnat_priv;
+
+	if (toggle == 1)
+		pr_info("Enable hnat counter update to nf_conntrack\n");
+	else if (toggle == 0)
+		pr_info("Disable hnat counter update to nf_conntrack\n");
+	else
+		pr_info("input error\n");
+	h->nf_stat_en = toggle;
+
+	return 0;
+}
+
+static const debugfs_write_func hnat_set_func[] = {
+	[0] = hnat_set_usage,
+	[1] = hnat_cpu_reason,
+};
+
+static const debugfs_write_func entry_set_func[] = {
+	[0] = entry_set_usage,
+	[1] = entry_set_state,
+	[2] = wrapped_ppe0_entry_detail,
+	[3] = wrapped_ppe0_entry_delete,
+	[4] = wrapped_ppe1_entry_detail,
+	[5] = wrapped_ppe1_entry_delete,
+};
+
+static const debugfs_write_func cr_set_func[] = {
+	[0] = cr_set_usage,      [1] = binding_threshold,
+	[2] = tcp_bind_lifetime, [3] = fin_bind_lifetime,
+	[4] = udp_bind_lifetime, [5] = tcp_keep_alive,
+	[6] = udp_keep_alive,    [7] = set_nf_update_toggle,
+};
+
+int read_mib(struct mtk_hnat *h, u32 ppe_id,
+	     u32 index, u64 *bytes, u64 *packets)
+{
+	int ret;
+	u32 val, cnt_r0, cnt_r1, cnt_r2;
+
+	if (ppe_id >= CFG_PPE_NUM)
+		return -EINVAL;
+
+	writel(index | (1 << 16), h->ppe_base[ppe_id] + PPE_MIB_SER_CR);
+	ret = readx_poll_timeout_atomic(readl, h->ppe_base[ppe_id] + PPE_MIB_SER_CR, val,
+					!(val & BIT_MIB_BUSY), 20, 10000);
+
+	if (ret < 0) {
+		pr_notice("mib busy, please check later\n");
+		return ret;
+	}
+	cnt_r0 = readl(h->ppe_base[ppe_id] + PPE_MIB_SER_R0);
+	cnt_r1 = readl(h->ppe_base[ppe_id] + PPE_MIB_SER_R1);
+	cnt_r2 = readl(h->ppe_base[ppe_id] + PPE_MIB_SER_R2);
+	*bytes = cnt_r0 + ((u64)(cnt_r1 & 0xffff) << 32);
+	*packets = ((cnt_r1 & 0xffff0000) >> 16) + ((cnt_r2 & 0xffffff) << 16);
+
+	return 0;
+
+}
+
+struct hnat_accounting *hnat_get_count(struct mtk_hnat *h, u32 ppe_id,
+				       u32 index, struct hnat_accounting *diff)
+
+{
+	u64 bytes, packets;
+
+	if (ppe_id >= CFG_PPE_NUM)
+		return NULL;
+
+	if (!hnat_priv->data->per_flow_accounting)
+		return NULL;
+
+	if (read_mib(h, ppe_id, index, &bytes, &packets))
+		return NULL;
+
+	h->acct[ppe_id][index].bytes += bytes;
+	h->acct[ppe_id][index].packets += packets;
+	
+	if (diff) {
+		diff->bytes = bytes;
+		diff->packets = packets;
+	}
+
+	return &h->acct[ppe_id][index];
+}
+EXPORT_SYMBOL(hnat_get_count);
+
+#define PRINT_COUNT(m, acct) {if (acct) \
+		seq_printf(m, "bytes=%llu|packets=%llu|", \
+			   acct->bytes, acct->packets); }
+static int __hnat_debug_show(struct seq_file *m, void *private, u32 ppe_id)
+{
+	struct mtk_hnat *h = hnat_priv;
+	struct foe_entry *entry, *end;
+	unsigned char h_dest[ETH_ALEN];
+	unsigned char h_source[ETH_ALEN];
+	struct hnat_accounting *acct;
+	u32 entry_index = 0;
+
+	if (ppe_id >= CFG_PPE_NUM)
+		return -EINVAL;
+
+	entry = h->foe_table_cpu[ppe_id];
+	end = h->foe_table_cpu[ppe_id] + hnat_priv->foe_etry_num;
+	while (entry < end) {
+		if (!entry->bfib1.state) {
+			entry++;
+			entry_index++;
+			continue;
+		}
+		acct = hnat_get_count(h, ppe_id, entry_index, NULL);
+		if (IS_IPV4_HNAPT(entry)) {
+			__be32 saddr = htonl(entry->ipv4_hnapt.sip);
+			__be32 daddr = htonl(entry->ipv4_hnapt.dip);
+			__be32 nsaddr = htonl(entry->ipv4_hnapt.new_sip);
+			__be32 ndaddr = htonl(entry->ipv4_hnapt.new_dip);
+
+			*((u32 *)h_source) = swab32(entry->ipv4_hnapt.smac_hi);
+			*((u16 *)&h_source[4]) =
+				swab16(entry->ipv4_hnapt.smac_lo);
+			*((u32 *)h_dest) = swab32(entry->ipv4_hnapt.dmac_hi);
+			*((u16 *)&h_dest[4]) =
+				swab16(entry->ipv4_hnapt.dmac_lo);
+			PRINT_COUNT(m, acct);
+			seq_printf(m,
+				   "addr=0x%p|ppe=%d|index=%d|state=%s|type=%s|%pI4:%d->%pI4:%d=>%pI4:%d->%pI4:%d|%pM=>%pM|etype=0x%04x|info1=0x%x|info2=0x%x|vlan1=%d|vlan2=%d\n",
+				   entry, ppe_id, ei(entry, end),
+				   es(entry), pt(entry), &saddr,
+				   entry->ipv4_hnapt.sport, &daddr,
+				   entry->ipv4_hnapt.dport, &nsaddr,
+				   entry->ipv4_hnapt.new_sport, &ndaddr,
+				   entry->ipv4_hnapt.new_dport, h_source, h_dest,
+				   ntohs(entry->ipv4_hnapt.etype),
+				   entry->ipv4_hnapt.info_blk1,
+				   entry->ipv4_hnapt.info_blk2,
+				   entry->ipv4_hnapt.vlan1,
+				   entry->ipv4_hnapt.vlan2);
+		} else if (IS_IPV4_HNAT(entry)) {
+			__be32 saddr = htonl(entry->ipv4_hnapt.sip);
+			__be32 daddr = htonl(entry->ipv4_hnapt.dip);
+			__be32 nsaddr = htonl(entry->ipv4_hnapt.new_sip);
+			__be32 ndaddr = htonl(entry->ipv4_hnapt.new_dip);
+
+			*((u32 *)h_source) = swab32(entry->ipv4_hnapt.smac_hi);
+			*((u16 *)&h_source[4]) =
+				swab16(entry->ipv4_hnapt.smac_lo);
+			*((u32 *)h_dest) = swab32(entry->ipv4_hnapt.dmac_hi);
+			*((u16 *)&h_dest[4]) =
+				swab16(entry->ipv4_hnapt.dmac_lo);
+			PRINT_COUNT(m, acct);
+			seq_printf(m,
+				   "addr=0x%p|ppe=%d|index=%d|state=%s|type=%s|%pI4->%pI4=>%pI4->%pI4|%pM=>%pM|etype=0x%04x|info1=0x%x|info2=0x%x|vlan1=%d|vlan2=%d\n",
+				   entry, ppe_id, ei(entry, end),
+				   es(entry), pt(entry), &saddr,
+				   &daddr, &nsaddr, &ndaddr, h_source, h_dest,
+				   ntohs(entry->ipv4_hnapt.etype),
+				   entry->ipv4_hnapt.info_blk1,
+				   entry->ipv4_hnapt.info_blk2,
+				   entry->ipv4_hnapt.vlan1,
+				   entry->ipv4_hnapt.vlan2);
+		} else if (IS_IPV6_5T_ROUTE(entry)) {
+			u32 ipv6_sip0 = entry->ipv6_3t_route.ipv6_sip0;
+			u32 ipv6_sip1 = entry->ipv6_3t_route.ipv6_sip1;
+			u32 ipv6_sip2 = entry->ipv6_3t_route.ipv6_sip2;
+			u32 ipv6_sip3 = entry->ipv6_3t_route.ipv6_sip3;
+			u32 ipv6_dip0 = entry->ipv6_3t_route.ipv6_dip0;
+			u32 ipv6_dip1 = entry->ipv6_3t_route.ipv6_dip1;
+			u32 ipv6_dip2 = entry->ipv6_3t_route.ipv6_dip2;
+			u32 ipv6_dip3 = entry->ipv6_3t_route.ipv6_dip3;
+
+			*((u32 *)h_source) =
+				swab32(entry->ipv6_5t_route.smac_hi);
+			*((u16 *)&h_source[4]) =
+				swab16(entry->ipv6_5t_route.smac_lo);
+			*((u32 *)h_dest) = swab32(entry->ipv6_5t_route.dmac_hi);
+			*((u16 *)&h_dest[4]) =
+				swab16(entry->ipv6_5t_route.dmac_lo);
+			PRINT_COUNT(m, acct);
+			seq_printf(m,
+				   "addr=0x%p|ppe=%d|index=%d|state=%s|type=%s|SIP=%08x:%08x:%08x:%08x(sp=%d)->DIP=%08x:%08x:%08x:%08x(dp=%d)|%pM=>%pM|etype=0x%04x|info1=0x%x|info2=0x%x\n",
+				   entry, ppe_id, ei(entry, end), es(entry), pt(entry), ipv6_sip0,
+				   ipv6_sip1, ipv6_sip2, ipv6_sip3,
+				   entry->ipv6_5t_route.sport, ipv6_dip0,
+				   ipv6_dip1, ipv6_dip2, ipv6_dip3,
+				   entry->ipv6_5t_route.dport, h_source, h_dest,
+				   ntohs(entry->ipv6_5t_route.etype),
+				   entry->ipv6_5t_route.info_blk1,
+				   entry->ipv6_5t_route.info_blk2);
+		} else if (IS_IPV6_3T_ROUTE(entry)) {
+			u32 ipv6_sip0 = entry->ipv6_3t_route.ipv6_sip0;
+			u32 ipv6_sip1 = entry->ipv6_3t_route.ipv6_sip1;
+			u32 ipv6_sip2 = entry->ipv6_3t_route.ipv6_sip2;
+			u32 ipv6_sip3 = entry->ipv6_3t_route.ipv6_sip3;
+			u32 ipv6_dip0 = entry->ipv6_3t_route.ipv6_dip0;
+			u32 ipv6_dip1 = entry->ipv6_3t_route.ipv6_dip1;
+			u32 ipv6_dip2 = entry->ipv6_3t_route.ipv6_dip2;
+			u32 ipv6_dip3 = entry->ipv6_3t_route.ipv6_dip3;
+
+			*((u32 *)h_source) =
+				swab32(entry->ipv6_5t_route.smac_hi);
+			*((u16 *)&h_source[4]) =
+				swab16(entry->ipv6_5t_route.smac_lo);
+			*((u32 *)h_dest) = swab32(entry->ipv6_5t_route.dmac_hi);
+			*((u16 *)&h_dest[4]) =
+				swab16(entry->ipv6_5t_route.dmac_lo);
+			PRINT_COUNT(m, acct);
+			seq_printf(m,
+				   "addr=0x%p|ppe=%d|index=%d|state=%s|type=%s|SIP=%08x:%08x:%08x:%08x->DIP=%08x:%08x:%08x:%08x|%pM=>%pM|etype=0x%04x|info1=0x%x|info2=0x%x\n",
+				   entry, ppe_id, ei(entry, end),
+				   es(entry), pt(entry), ipv6_sip0,
+				   ipv6_sip1, ipv6_sip2, ipv6_sip3, ipv6_dip0,
+				   ipv6_dip1, ipv6_dip2, ipv6_dip3, h_source,
+				   h_dest, ntohs(entry->ipv6_5t_route.etype),
+				   entry->ipv6_5t_route.info_blk1,
+				   entry->ipv6_5t_route.info_blk2);
+		} else if (IS_IPV6_6RD(entry)) {
+			u32 ipv6_sip0 = entry->ipv6_3t_route.ipv6_sip0;
+			u32 ipv6_sip1 = entry->ipv6_3t_route.ipv6_sip1;
+			u32 ipv6_sip2 = entry->ipv6_3t_route.ipv6_sip2;
+			u32 ipv6_sip3 = entry->ipv6_3t_route.ipv6_sip3;
+			u32 ipv6_dip0 = entry->ipv6_3t_route.ipv6_dip0;
+			u32 ipv6_dip1 = entry->ipv6_3t_route.ipv6_dip1;
+			u32 ipv6_dip2 = entry->ipv6_3t_route.ipv6_dip2;
+			u32 ipv6_dip3 = entry->ipv6_3t_route.ipv6_dip3;
+			__be32 tsaddr = htonl(entry->ipv6_6rd.tunnel_sipv4);
+			__be32 tdaddr = htonl(entry->ipv6_6rd.tunnel_dipv4);
+
+			*((u32 *)h_source) =
+				swab32(entry->ipv6_5t_route.smac_hi);
+			*((u16 *)&h_source[4]) =
+				swab16(entry->ipv6_5t_route.smac_lo);
+			*((u32 *)h_dest) = swab32(entry->ipv6_5t_route.dmac_hi);
+			*((u16 *)&h_dest[4]) =
+				swab16(entry->ipv6_5t_route.dmac_lo);
+			PRINT_COUNT(m, acct);
+			seq_printf(m,
+				   "addr=0x%p|ppe=%d|index=%d|state=%s|type=%s|SIP=%08x:%08x:%08x:%08x(sp=%d)->DIP=%08x:%08x:%08x:%08x(dp=%d)|TSIP=%pI4->TDIP=%pI4|%pM=>%pM|etype=0x%04x|info1=0x%x|info2=0x%x\n",
+				   entry, ppe_id, ei(entry, end),
+				   es(entry), pt(entry), ipv6_sip0,
+				   ipv6_sip1, ipv6_sip2, ipv6_sip3,
+				   entry->ipv6_5t_route.sport, ipv6_dip0,
+				   ipv6_dip1, ipv6_dip2, ipv6_dip3,
+				   entry->ipv6_5t_route.dport, &tsaddr, &tdaddr,
+				   h_source, h_dest,
+				   ntohs(entry->ipv6_5t_route.etype),
+				   entry->ipv6_5t_route.info_blk1,
+				   entry->ipv6_5t_route.info_blk2);
+		} else if (IS_IPV4_DSLITE(entry)) {
+			__be32 saddr = htonl(entry->ipv4_hnapt.sip);
+			__be32 daddr = htonl(entry->ipv4_hnapt.dip);
+			u32 ipv6_tsip0 = entry->ipv4_dslite.tunnel_sipv6_0;
+			u32 ipv6_tsip1 = entry->ipv4_dslite.tunnel_sipv6_1;
+			u32 ipv6_tsip2 = entry->ipv4_dslite.tunnel_sipv6_2;
+			u32 ipv6_tsip3 = entry->ipv4_dslite.tunnel_sipv6_3;
+			u32 ipv6_tdip0 = entry->ipv4_dslite.tunnel_dipv6_0;
+			u32 ipv6_tdip1 = entry->ipv4_dslite.tunnel_dipv6_1;
+			u32 ipv6_tdip2 = entry->ipv4_dslite.tunnel_dipv6_2;
+			u32 ipv6_tdip3 = entry->ipv4_dslite.tunnel_dipv6_3;
+
+			*((u32 *)h_source) = swab32(entry->ipv4_dslite.smac_hi);
+			*((u16 *)&h_source[4]) =
+				swab16(entry->ipv4_dslite.smac_lo);
+			*((u32 *)h_dest) = swab32(entry->ipv4_dslite.dmac_hi);
+			*((u16 *)&h_dest[4]) =
+				swab16(entry->ipv4_dslite.dmac_lo);
+			PRINT_COUNT(m, acct);
+			seq_printf(m,
+				   "addr=0x%p|ppe=%d|index=%d|state=%s|type=%s|SIP=%pI4->DIP=%pI4|TSIP=%08x:%08x:%08x:%08x->TDIP=%08x:%08x:%08x:%08x|%pM=>%pM|etype=0x%04x|info1=0x%x|info2=0x%x\n",
+				   entry, ppe_id, ei(entry, end),
+				   es(entry), pt(entry), &saddr,
+				   &daddr, ipv6_tsip0, ipv6_tsip1, ipv6_tsip2,
+				   ipv6_tsip3, ipv6_tdip0, ipv6_tdip1, ipv6_tdip2,
+				   ipv6_tdip3, h_source, h_dest,
+				   ntohs(entry->ipv6_5t_route.etype),
+				   entry->ipv6_5t_route.info_blk1,
+				   entry->ipv6_5t_route.info_blk2);
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+		} else if (IS_IPV4_MAPE(entry)) {
+			__be32 saddr = htonl(entry->ipv4_dslite.sip);
+			__be32 daddr = htonl(entry->ipv4_dslite.dip);
+			__be32 nsaddr = htonl(entry->ipv4_dslite.new_sip);
+			__be32 ndaddr = htonl(entry->ipv4_dslite.new_dip);
+			u32 ipv6_tsip0 = entry->ipv4_dslite.tunnel_sipv6_0;
+			u32 ipv6_tsip1 = entry->ipv4_dslite.tunnel_sipv6_1;
+			u32 ipv6_tsip2 = entry->ipv4_dslite.tunnel_sipv6_2;
+			u32 ipv6_tsip3 = entry->ipv4_dslite.tunnel_sipv6_3;
+			u32 ipv6_tdip0 = entry->ipv4_dslite.tunnel_dipv6_0;
+			u32 ipv6_tdip1 = entry->ipv4_dslite.tunnel_dipv6_1;
+			u32 ipv6_tdip2 = entry->ipv4_dslite.tunnel_dipv6_2;
+			u32 ipv6_tdip3 = entry->ipv4_dslite.tunnel_dipv6_3;
+
+			*((u32 *)h_source) = swab32(entry->ipv4_dslite.smac_hi);
+			*((u16 *)&h_source[4]) =
+				swab16(entry->ipv4_dslite.smac_lo);
+			*((u32 *)h_dest) = swab32(entry->ipv4_dslite.dmac_hi);
+			*((u16 *)&h_dest[4]) =
+				swab16(entry->ipv4_dslite.dmac_lo);
+			PRINT_COUNT(m, acct);
+			seq_printf(m,
+				   "addr=0x%p|ppe=%d|index=%d|state=%s|type=%s|SIP=%pI4:%d->DIP=%pI4:%d|NSIP=%pI4:%d->NDIP=%pI4:%d|TSIP=%08x:%08x:%08x:%08x->TDIP=%08x:%08x:%08x:%08x|%pM=>%pM|etype=0x%04x|info1=0x%x|info2=0x%x\n",
+				   entry, ppe_id, ei(entry, end),
+				   es(entry), pt(entry),
+				   &saddr, entry->ipv4_dslite.sport,
+				   &daddr, entry->ipv4_dslite.dport,
+				   &nsaddr, entry->ipv4_dslite.new_sport,
+				   &ndaddr, entry->ipv4_dslite.new_dport,
+				   ipv6_tsip0, ipv6_tsip1, ipv6_tsip2,
+				   ipv6_tsip3, ipv6_tdip0, ipv6_tdip1,
+				   ipv6_tdip2, ipv6_tdip3, h_source, h_dest,
+				   ntohs(entry->ipv6_5t_route.etype),
+				   entry->ipv6_5t_route.info_blk1,
+				   entry->ipv6_5t_route.info_blk2);
+#endif
+		} else
+			seq_printf(m, "addr=0x%p|ppe=%d|index=%d state=%s\n", entry, ppe_id, ei(entry, end),
+				   es(entry));
+		entry++;
+		entry_index++;
+	}
+
+	return 0;
+}
+
+static int hnat_debug_show(struct seq_file *m, void *private)
+{
+	int i;
+
+	for (i = 0; i < CFG_PPE_NUM; i++)
+		__hnat_debug_show(m, private, i);
+
+	return 0;
+}
+
+static int hnat_debug_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, hnat_debug_show, file->private_data);
+}
+
+static const struct file_operations hnat_debug_fops = {
+	.open = hnat_debug_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int hnat_whnat_show(struct seq_file *m, void *private)
+{
+	int i;
+	struct net_device *dev;
+
+	for (i = 0; i < MAX_IF_NUM; i++) {
+		dev = hnat_priv->wifi_hook_if[i];
+		if (dev)
+			seq_printf(m, "%d:%s\n", i, dev->name);
+		else
+			continue;
+	}
+
+	return 0;
+}
+
+static int hnat_whnat_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, hnat_whnat_show, file->private_data);
+}
+
+static const struct file_operations hnat_whnat_fops = {
+	.open = hnat_whnat_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+int cpu_reason_read(struct seq_file *m, void *private)
+{
+	int i;
+
+	pr_info("============ CPU REASON =========\n");
+	pr_info("(2)IPv4(IPv6) TTL(hop limit) = %u\n", dbg_cpu_reason_cnt[0]);
+	pr_info("(3)Ipv4(IPv6) has option(extension) header = %u\n",
+		dbg_cpu_reason_cnt[1]);
+	pr_info("(7)No flow is assigned = %u\n", dbg_cpu_reason_cnt[2]);
+	pr_info("(8)IPv4 HNAT doesn't support IPv4 /w fragment = %u\n",
+		dbg_cpu_reason_cnt[3]);
+	pr_info("(9)IPv4 HNAPT/DS-Lite doesn't support IPv4 /w fragment = %u\n",
+		dbg_cpu_reason_cnt[4]);
+	pr_info("(10)IPv4 HNAPT/DS-Lite can't find TCP/UDP sport/dport = %u\n",
+		dbg_cpu_reason_cnt[5]);
+	pr_info("(11)IPv6 5T-route/6RD can't find TCP/UDP sport/dport = %u\n",
+		dbg_cpu_reason_cnt[6]);
+	pr_info("(12)Ingress packet is TCP fin/syn/rst = %u\n",
+		dbg_cpu_reason_cnt[7]);
+	pr_info("(13)FOE Un-hit = %u\n", dbg_cpu_reason_cnt[8]);
+	pr_info("(14)FOE Hit unbind = %u\n", dbg_cpu_reason_cnt[9]);
+	pr_info("(15)FOE Hit unbind & rate reach = %u\n",
+		dbg_cpu_reason_cnt[10]);
+	pr_info("(16)Hit bind PPE TCP FIN entry = %u\n",
+		dbg_cpu_reason_cnt[11]);
+	pr_info("(17)Hit bind PPE entry and TTL(hop limit) = 1 and TTL(hot limit) - 1 = %u\n",
+		dbg_cpu_reason_cnt[12]);
+	pr_info("(18)Hit bind and VLAN replacement violation = %u\n",
+		dbg_cpu_reason_cnt[13]);
+	pr_info("(19)Hit bind and keep alive with unicast old-header packet = %u\n",
+		dbg_cpu_reason_cnt[14]);
+	pr_info("(20)Hit bind and keep alive with multicast new-header packet = %u\n",
+		dbg_cpu_reason_cnt[15]);
+	pr_info("(21)Hit bind and keep alive with duplicate old-header packet = %u\n",
+		dbg_cpu_reason_cnt[16]);
+	pr_info("(22)FOE Hit bind & force to CPU = %u\n",
+		dbg_cpu_reason_cnt[17]);
+	pr_info("(28)Hit bind and exceed MTU =%u\n", dbg_cpu_reason_cnt[18]);
+	pr_info("(24)Hit bind multicast packet to CPU = %u\n",
+		dbg_cpu_reason_cnt[19]);
+	pr_info("(25)Hit bind multicast packet to GMAC & CPU = %u\n",
+		dbg_cpu_reason_cnt[20]);
+	pr_info("(26)Pre bind = %u\n", dbg_cpu_reason_cnt[21]);
+
+	for (i = 0; i < 22; i++)
+		dbg_cpu_reason_cnt[i] = 0;
+	return 0;
+}
+
+static int cpu_reason_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, cpu_reason_read, file->private_data);
+}
+
+ssize_t cpu_reason_write(struct file *file, const char __user *buffer,
+			 size_t count, loff_t *data)
+{
+	char buf[32];
+	char *p_buf;
+	u32 len = count;
+	long arg0 = 0, arg1 = 0;
+	char *p_token = NULL;
+	char *p_delimiter = " \t";
+	int ret;
+
+	if (len >= sizeof(buf)) {
+		pr_info("input handling fail!\n");
+		return -1;
+	}
+
+	if (copy_from_user(buf, buffer, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+
+	p_buf = buf;
+	p_token = strsep(&p_buf, p_delimiter);
+	if (!p_token)
+		arg0 = 0;
+	else
+		ret = kstrtol(p_token, 10, &arg0);
+
+	switch (arg0) {
+	case 0:
+	case 1:
+		p_token = strsep(&p_buf, p_delimiter);
+		if (!p_token)
+			arg1 = 0;
+		else
+			ret = kstrtol(p_token, 10, &arg1);
+		break;
+	default:
+		pr_info("no handler defined for command id(0x%08lx)\n\r", arg0);
+		arg0 = 0;
+		arg1 = 0;
+		break;
+	}
+
+	(*hnat_set_func[arg0])(arg1);
+
+	return len;
+}
+
+static const struct file_operations cpu_reason_fops = {
+	.open = cpu_reason_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.write = cpu_reason_write,
+	.release = single_release,
+};
+
+void dbg_dump_entry(struct seq_file *m, struct foe_entry *entry,
+		    uint32_t index)
+{
+	__be32 saddr, daddr, nsaddr, ndaddr;
+
+	saddr = htonl(entry->ipv4_hnapt.sip);
+	daddr = htonl(entry->ipv4_hnapt.dip);
+	nsaddr = htonl(entry->ipv4_hnapt.new_sip);
+	ndaddr = htonl(entry->ipv4_hnapt.new_dip);
+
+	if (IS_IPV4_HNAPT(entry)) {
+		seq_printf(m,
+			   "NAPT(%d): %pI4:%d->%pI4:%d => %pI4:%d->%pI4:%d\n",
+			   index, &saddr, entry->ipv4_hnapt.sport, &daddr,
+			   entry->ipv4_hnapt.dport, &nsaddr,
+			   entry->ipv4_hnapt.new_sport, &ndaddr,
+			   entry->ipv4_hnapt.new_dport);
+	} else if (IS_IPV4_HNAT(entry)) {
+		seq_printf(m, "NAT(%d): %pI4->%pI4 => %pI4->%pI4\n",
+			   index, &saddr, &daddr, &nsaddr, &ndaddr);
+	}
+
+	if (IS_IPV4_DSLITE(entry)) {
+		seq_printf(m,
+			   "IPv4 Ds-Lite(%d): %pI4:%d->%pI4:%d => %08X:%08X:%08X:%08X->%08X:%08X:%08X:%08X\n",
+			   index, &saddr, entry->ipv4_dslite.sport, &daddr,
+			   entry->ipv4_dslite.dport,
+			   entry->ipv4_dslite.tunnel_sipv6_0,
+			   entry->ipv4_dslite.tunnel_sipv6_1,
+			   entry->ipv4_dslite.tunnel_sipv6_2,
+			   entry->ipv4_dslite.tunnel_sipv6_3,
+			   entry->ipv4_dslite.tunnel_dipv6_0,
+			   entry->ipv4_dslite.tunnel_dipv6_1,
+			   entry->ipv4_dslite.tunnel_dipv6_2,
+			   entry->ipv4_dslite.tunnel_dipv6_3);
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+	} else if (IS_IPV4_MAPE(entry)) {
+		nsaddr = htonl(entry->ipv4_dslite.new_sip);
+		ndaddr = htonl(entry->ipv4_dslite.new_dip);
+
+		seq_printf(m,
+			   "IPv4 MAP-E(%d): %pI4:%d->%pI4:%d => %pI4:%d->%pI4:%d | Tunnel=%08X:%08X:%08X:%08X->%08X:%08X:%08X:%08X\n",
+			   index, &saddr, entry->ipv4_dslite.sport,
+			   &daddr, entry->ipv4_dslite.dport,
+			   &nsaddr, entry->ipv4_dslite.new_sport,
+			   &ndaddr, entry->ipv4_dslite.new_dport,
+			   entry->ipv4_dslite.tunnel_sipv6_0,
+			   entry->ipv4_dslite.tunnel_sipv6_1,
+			   entry->ipv4_dslite.tunnel_sipv6_2,
+			   entry->ipv4_dslite.tunnel_sipv6_3,
+			   entry->ipv4_dslite.tunnel_dipv6_0,
+			   entry->ipv4_dslite.tunnel_dipv6_1,
+			   entry->ipv4_dslite.tunnel_dipv6_2,
+			   entry->ipv4_dslite.tunnel_dipv6_3);
+#endif
+	} else if (IS_IPV6_3T_ROUTE(entry)) {
+		seq_printf(m,
+			   "IPv6_3T(%d): %08X:%08X:%08X:%08X => %08X:%08X:%08X:%08X (Prot=%d)\n",
+			   index, entry->ipv6_3t_route.ipv6_sip0,
+			   entry->ipv6_3t_route.ipv6_sip1,
+			   entry->ipv6_3t_route.ipv6_sip2,
+			   entry->ipv6_3t_route.ipv6_sip3,
+			   entry->ipv6_3t_route.ipv6_dip0,
+			   entry->ipv6_3t_route.ipv6_dip1,
+			   entry->ipv6_3t_route.ipv6_dip2,
+			   entry->ipv6_3t_route.ipv6_dip3,
+			   entry->ipv6_3t_route.prot);
+	} else if (IS_IPV6_5T_ROUTE(entry)) {
+		seq_printf(m,
+			   "IPv6_5T(%d): %08X:%08X:%08X:%08X:%d => %08X:%08X:%08X:%08X:%d\n",
+			   index, entry->ipv6_5t_route.ipv6_sip0,
+			   entry->ipv6_5t_route.ipv6_sip1,
+			   entry->ipv6_5t_route.ipv6_sip2,
+			   entry->ipv6_5t_route.ipv6_sip3,
+			   entry->ipv6_5t_route.sport,
+			   entry->ipv6_5t_route.ipv6_dip0,
+			   entry->ipv6_5t_route.ipv6_dip1,
+			   entry->ipv6_5t_route.ipv6_dip2,
+			   entry->ipv6_5t_route.ipv6_dip3,
+			   entry->ipv6_5t_route.dport);
+	} else if (IS_IPV6_6RD(entry)) {
+		seq_printf(m,
+			   "IPv6_6RD(%d): %08X:%08X:%08X:%08X:%d => %08X:%08X:%08X:%08X:%d\n",
+			   index, entry->ipv6_6rd.ipv6_sip0,
+			   entry->ipv6_6rd.ipv6_sip1, entry->ipv6_6rd.ipv6_sip2,
+			   entry->ipv6_6rd.ipv6_sip3, entry->ipv6_6rd.sport,
+			   entry->ipv6_6rd.ipv6_dip0, entry->ipv6_6rd.ipv6_dip1,
+			   entry->ipv6_6rd.ipv6_dip2, entry->ipv6_6rd.ipv6_dip3,
+			   entry->ipv6_6rd.dport);
+	}
+}
+
+int __hnat_entry_read(struct seq_file *m, void *private, u32 ppe_id)
+{
+	struct mtk_hnat *h = hnat_priv;
+	struct foe_entry *entry, *end;
+	int hash_index;
+	int cnt;
+
+	if (ppe_id >= CFG_PPE_NUM)
+		return -EINVAL;
+
+	hash_index = 0;
+	cnt = 0;
+	entry = h->foe_table_cpu[ppe_id];
+	end = h->foe_table_cpu[ppe_id] + hnat_priv->foe_etry_num;
+
+	seq_printf(m, "============================\n");
+	seq_printf(m, "PPE_ID = %d\n", ppe_id);
+
+	while (entry < end) {
+		if (entry->bfib1.state == dbg_entry_state) {
+			cnt++;
+			dbg_dump_entry(m, entry, hash_index);
+		}
+		hash_index++;
+		entry++;
+	}
+
+	seq_printf(m, "Total State = %s cnt = %d\n",
+		   dbg_entry_state == 0 ?
+		   "Invalid" : dbg_entry_state == 1 ?
+		   "Unbind" : dbg_entry_state == 2 ?
+		   "BIND" : dbg_entry_state == 3 ?
+		   "FIN" : "Unknown", cnt);
+
+	return 0;
+}
+
+int hnat_entry_read(struct seq_file *m, void *private)
+{
+	int i;
+
+	for (i = 0; i < CFG_PPE_NUM; i++)
+		__hnat_entry_read(m, private, i);
+
+	return 0;
+}
+
+ssize_t hnat_entry_write(struct file *file, const char __user *buffer,
+			 size_t count, loff_t *data)
+{
+	char buf[32];
+	char *p_buf;
+	u32 len = count;
+	long arg0 = 0, arg1 = 0;
+	char *p_token = NULL;
+	char *p_delimiter = " \t";
+	int ret;
+
+	if (len >= sizeof(buf)) {
+		pr_info("input handling fail!\n");
+		return -1;
+	}
+
+	if (copy_from_user(buf, buffer, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+
+	p_buf = buf;
+	p_token = strsep(&p_buf, p_delimiter);
+	if (!p_token)
+		arg0 = 0;
+	else
+		ret = kstrtol(p_token, 10, &arg0);
+
+	switch (arg0) {
+	case 0:
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+		p_token = strsep(&p_buf, p_delimiter);
+		if (!p_token)
+			arg1 = 0;
+		else
+			ret = kstrtol(p_token, 10, &arg1);
+		break;
+	default:
+		pr_info("no handler defined for command id(0x%08lx)\n\r", arg0);
+		arg0 = 0;
+		arg1 = 0;
+		break;
+	}
+
+	(*entry_set_func[arg0])(arg1);
+
+	return len;
+}
+
+static int hnat_entry_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, hnat_entry_read, file->private_data);
+}
+
+static const struct file_operations hnat_entry_fops = {
+	.open = hnat_entry_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.write = hnat_entry_write,
+	.release = single_release,
+};
+
+int __hnat_setting_read(struct seq_file *m, void *private, u32 ppe_id)
+{
+	struct mtk_hnat *h = hnat_priv;
+	int i;
+	int cr_max;
+
+	if (ppe_id >= CFG_PPE_NUM)
+		return -EINVAL;
+
+	cr_max = 319 * 4;
+	for (i = 0; i < cr_max; i = i + 0x10) {
+		pr_info("0x%p : 0x%08x 0x%08x 0x%08x 0x%08x\n",
+			(void *)h->foe_table_dev[ppe_id] + i,
+			readl(h->ppe_base[ppe_id] + i),
+			readl(h->ppe_base[ppe_id] + i + 4),
+			readl(h->ppe_base[ppe_id] + i + 8),
+			readl(h->ppe_base[ppe_id] + i + 0xc));
+	}
+
+	return 0;
+}
+
+int hnat_setting_read(struct seq_file *m, void *private)
+{
+	int i;
+
+	for (i = 0; i < CFG_PPE_NUM; i++)
+		__hnat_setting_read(m, private, i);
+
+	return 0;
+}
+
+static int hnat_setting_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, hnat_setting_read, file->private_data);
+}
+
+ssize_t hnat_setting_write(struct file *file, const char __user *buffer,
+			   size_t count, loff_t *data)
+{
+	char buf[32];
+	char *p_buf;
+	u32 len = count;
+	long arg0 = 0, arg1 = 0;
+	char *p_token = NULL;
+	char *p_delimiter = " \t";
+	int ret;
+
+	if (len >= sizeof(buf)) {
+		pr_info("input handling fail!\n");
+		return -1;
+	}
+
+	if (copy_from_user(buf, buffer, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+
+	p_buf = buf;
+	p_token = strsep(&p_buf, p_delimiter);
+	if (!p_token)
+		arg0 = 0;
+	else
+		ret = kstrtol(p_token, 10, &arg0);
+
+	switch (arg0) {
+	case 0:
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+		p_token = strsep(&p_buf, p_delimiter);
+		if (!p_token)
+			arg1 = 0;
+		else
+			ret = kstrtol(p_token, 10, &arg1);
+		break;
+	default:
+		pr_info("no handler defined for command id(0x%08lx)\n\r", arg0);
+		arg0 = 0;
+		arg1 = 0;
+		break;
+	}
+
+	(*cr_set_func[arg0])(arg1);
+
+	return len;
+}
+
+static const struct file_operations hnat_setting_fops = {
+	.open = hnat_setting_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.write = hnat_setting_write,
+	.release = single_release,
+};
+
+int __mcast_table_dump(struct seq_file *m, void *private, u32 ppe_id)
+{
+	struct mtk_hnat *h = hnat_priv;
+	struct ppe_mcast_h mcast_h;
+	struct ppe_mcast_l mcast_l;
+	u8 i, max;
+	void __iomem *reg;
+
+	if (ppe_id >= CFG_PPE_NUM)
+		return -EINVAL;
+
+	if (!h->pmcast)
+		return 0;
+
+	max = h->pmcast->max_entry;
+	pr_info("============================\n");
+	pr_info("PPE_ID = %d\n", ppe_id);
+	pr_info("MAC | VID | PortMask | QosPortMask\n");
+	for (i = 0; i < max; i++) {
+		if (i < 0x10) {
+			reg = h->ppe_base[ppe_id] + PPE_MCAST_H_0 + i * 8;
+			mcast_h.u.value = readl(reg);
+			reg = h->ppe_base[ppe_id] + PPE_MCAST_L_0 + i * 8;
+			mcast_l.addr = readl(reg);
+		} else {
+			reg = h->fe_base + PPE_MCAST_H_10 + (i - 0x10) * 8;
+			mcast_h.u.value = readl(reg);
+			reg = h->fe_base + PPE_MCAST_L_10 + (i - 0x10) * 8;
+			mcast_l.addr = readl(reg);
+		}
+		pr_info("%08x %d %c%c%c%c %c%c%c%c (QID=%d, mc_mpre_sel=%d)\n",
+			mcast_l.addr,
+			mcast_h.u.info.mc_vid,
+			(mcast_h.u.info.mc_px_en & 0x08) ? '1' : '-',
+			(mcast_h.u.info.mc_px_en & 0x04) ? '1' : '-',
+			(mcast_h.u.info.mc_px_en & 0x02) ? '1' : '-',
+			(mcast_h.u.info.mc_px_en & 0x01) ? '1' : '-',
+			(mcast_h.u.info.mc_px_qos_en & 0x08) ? '1' : '-',
+			(mcast_h.u.info.mc_px_qos_en & 0x04) ? '1' : '-',
+			(mcast_h.u.info.mc_px_qos_en & 0x02) ? '1' : '-',
+			(mcast_h.u.info.mc_px_qos_en & 0x01) ? '1' : '-',
+			mcast_h.u.info.mc_qos_qid +
+			((mcast_h.u.info.mc_qos_qid54) << 4),
+			mcast_h.u.info.mc_mpre_sel);
+	}
+
+	return 0;
+}
+
+int mcast_table_dump(struct seq_file *m, void *private)
+{
+	int i;
+
+	for (i = 0; i < CFG_PPE_NUM; i++)
+		__mcast_table_dump(m, private, i);
+
+	return 0;
+}
+
+static int mcast_table_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, mcast_table_dump, file->private_data);
+}
+
+static const struct file_operations hnat_mcast_fops = {
+	.open = mcast_table_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int hnat_ext_show(struct seq_file *m, void *private)
+{
+	int i;
+	struct extdev_entry *ext_entry;
+
+	for (i = 0; i < MAX_EXT_DEVS && hnat_priv->ext_if[i]; i++) {
+		ext_entry = hnat_priv->ext_if[i];
+		if (ext_entry->dev)
+			seq_printf(m, "ext devices [%d] = %s  (dev=%p, ifindex=%d)\n",
+				   i, ext_entry->name, ext_entry->dev,
+				   ext_entry->dev->ifindex);
+	}
+
+	return 0;
+}
+
+static int hnat_ext_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, hnat_ext_show, file->private_data);
+}
+
+static const struct file_operations hnat_ext_fops = {
+	.open = hnat_ext_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static ssize_t hnat_sched_show(struct file *file, char __user *user_buf,
+			       size_t count, loff_t *ppos)
+{
+	long id = (long)file->private_data;
+	struct mtk_hnat *h = hnat_priv;
+	u32 qdma_tx_sch;
+	int enable;
+	int scheduling;
+	int max_rate;
+	char *buf;
+	unsigned int len = 0, buf_len = 1500;
+	ssize_t ret_cnt;
+	int scheduler, i;
+	u32 sch_reg;
+
+	buf = kzalloc(buf_len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	if (hnat_priv->data->num_of_sch == 4)
+		qdma_tx_sch = readl(h->fe_base + QDMA_TX_4SCH_BASE(id));
+	else
+		qdma_tx_sch = readl(h->fe_base + QDMA_TX_2SCH_BASE);
+
+	if (id & 0x1)
+		qdma_tx_sch >>= 16;
+	qdma_tx_sch &= 0xffff;
+	enable = !!(qdma_tx_sch & BIT(11));
+	scheduling = !!(qdma_tx_sch & BIT(15));
+	max_rate = ((qdma_tx_sch >> 4) & 0x7f);
+	qdma_tx_sch &= 0xf;
+	while (qdma_tx_sch--)
+		max_rate *= 10;
+
+	len += scnprintf(buf + len, buf_len - len,
+			 "EN\tScheduling\tMAX\tQueue#\n%d\t%s%16d\t", enable,
+			 (scheduling == 1) ? "WRR" : "SP", max_rate);
+
+	for (i = 0; i < MTK_QDMA_TX_NUM; i++) {
+		cr_set_field(h->fe_base + QDMA_PAGE, QTX_CFG_PAGE,
+			     (i / NUM_OF_Q_PER_PAGE));
+		sch_reg = readl(h->fe_base + QTX_SCH(i % NUM_OF_Q_PER_PAGE));
+		if (hnat_priv->data->num_of_sch == 4)
+			scheduler = (sch_reg >> 30) & 0x3;
+		else
+			scheduler = !!(sch_reg & BIT(31));
+		if (id == scheduler)
+			len += scnprintf(buf + len, buf_len - len, "%d  ", i);
+	}
+
+	len += scnprintf(buf + len, buf_len - len, "\n");
+	if (len > buf_len)
+		len = buf_len;
+
+	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+	kfree(buf);
+	return ret_cnt;
+}
+
+static ssize_t hnat_sched_write(struct file *file, const char __user *buf,
+				size_t length, loff_t *offset)
+{
+	long id = (long)file->private_data;
+	struct mtk_hnat *h = hnat_priv;
+	char line[64] = {0};
+	int enable, rate, exp = 0, shift = 0;
+	char scheduling[32];
+	size_t size;
+	u32 qdma_tx_sch;
+	u32 val = 0;
+
+	if (length >= sizeof(line))
+		return -EINVAL;
+
+	if (copy_from_user(line, buf, length))
+		return -EFAULT;
+
+	if (sscanf(line, "%d %s %d", &enable, scheduling, &rate) != 3)
+		return -EFAULT;
+
+	while (rate > 127) {
+		rate /= 10;
+		exp++;
+	}
+
+	line[length] = '\0';
+
+	if (enable)
+		val |= BIT(11);
+	if (strcmp(scheduling, "sp") != 0)
+		val |= BIT(15);
+	val |= (rate & 0x7f) << 4;
+	val |= exp & 0xf;
+	if (id & 0x1)
+		shift = 16;
+
+	if (hnat_priv->data->num_of_sch == 4)
+		qdma_tx_sch = readl(h->fe_base + QDMA_TX_4SCH_BASE(id));
+	else
+		qdma_tx_sch = readl(h->fe_base + QDMA_TX_2SCH_BASE);
+
+	qdma_tx_sch &= ~(0xffff << shift);
+	qdma_tx_sch |= val << shift;
+	if (hnat_priv->data->num_of_sch == 4)
+		writel(qdma_tx_sch, h->fe_base + QDMA_TX_4SCH_BASE(id));
+	else
+		writel(qdma_tx_sch, h->fe_base + QDMA_TX_2SCH_BASE);
+
+	size = strlen(line);
+	*offset += size;
+
+	return length;
+}
+
+static const struct file_operations hnat_sched_fops = {
+	.open = simple_open,
+	.read = hnat_sched_show,
+	.write = hnat_sched_write,
+	.llseek = default_llseek,
+};
+
+static ssize_t hnat_queue_show(struct file *file, char __user *user_buf,
+			       size_t count, loff_t *ppos)
+{
+	struct mtk_hnat *h = hnat_priv;
+	long id = (long)file->private_data;
+	u32 qtx_sch;
+	u32 qtx_cfg;
+	int scheduler;
+	int min_rate_en;
+	int min_rate;
+	int min_rate_exp;
+	int max_rate_en;
+	int max_weight;
+	int max_rate;
+	int max_rate_exp;
+	char *buf;
+	unsigned int len = 0, buf_len = 1500;
+	ssize_t ret_cnt;
+
+	buf = kzalloc(buf_len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	cr_set_field(h->fe_base + QDMA_PAGE, QTX_CFG_PAGE, (id / NUM_OF_Q_PER_PAGE));
+	qtx_cfg = readl(h->fe_base + QTX_CFG(id % NUM_OF_Q_PER_PAGE));
+	qtx_sch = readl(h->fe_base + QTX_SCH(id % NUM_OF_Q_PER_PAGE));
+	if (hnat_priv->data->num_of_sch == 4)
+		scheduler = (qtx_sch >> 30) & 0x3;
+	else
+		scheduler = !!(qtx_sch & BIT(31));
+	min_rate_en = !!(qtx_sch & BIT(27));
+	min_rate = (qtx_sch >> 20) & 0x7f;
+	min_rate_exp = (qtx_sch >> 16) & 0xf;
+	max_rate_en = !!(qtx_sch & BIT(11));
+	max_weight = (qtx_sch >> 12) & 0xf;
+	max_rate = (qtx_sch >> 4) & 0x7f;
+	max_rate_exp = qtx_sch & 0xf;
+	while (min_rate_exp--)
+		min_rate *= 10;
+
+	while (max_rate_exp--)
+		max_rate *= 10;
+
+	len += scnprintf(buf + len, buf_len - len,
+			 "scheduler: %d\nhw resv: %d\nsw resv: %d\n", scheduler,
+			 (qtx_cfg >> 8) & 0xff, qtx_cfg & 0xff);
+
+	if (hnat_priv->data->version != MTK_HNAT_V1) {
+		/* Switch to debug mode */
+		cr_set_field(h->fe_base + QTX_MIB_IF, MIB_ON_QTX_CFG, 1);
+		cr_set_field(h->fe_base + QTX_MIB_IF, VQTX_MIB_EN, 1);
+		qtx_cfg = readl(h->fe_base + QTX_CFG(id % NUM_OF_Q_PER_PAGE));
+		qtx_sch = readl(h->fe_base + QTX_SCH(id % NUM_OF_Q_PER_PAGE));
+		len += scnprintf(buf + len, buf_len - len,
+				 "packet count: %u\n", qtx_cfg);
+		len += scnprintf(buf + len, buf_len - len,
+				 "packet drop: %u\n\n", qtx_sch);
+
+		/* Recover to normal mode */
+		cr_set_field(hnat_priv->fe_base + QTX_MIB_IF,
+			     MIB_ON_QTX_CFG, 0);
+		cr_set_field(hnat_priv->fe_base + QTX_MIB_IF, VQTX_MIB_EN, 0);
+	}
+
+	len += scnprintf(buf + len, buf_len - len,
+			 "      EN     RATE     WEIGHT\n");
+	len += scnprintf(buf + len, buf_len - len,
+			 "----------------------------\n");
+	len += scnprintf(buf + len, buf_len - len,
+			 "max%5d%9d%9d\n", max_rate_en, max_rate, max_weight);
+	len += scnprintf(buf + len, buf_len - len,
+			 "min%5d%9d        -\n", min_rate_en, min_rate);
+
+	if (len > buf_len)
+		len = buf_len;
+
+	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+	kfree(buf);
+	return ret_cnt;
+}
+
+static ssize_t hnat_queue_write(struct file *file, const char __user *buf,
+				size_t length, loff_t *offset)
+{
+	long id = (long)file->private_data;
+	struct mtk_hnat *h = hnat_priv;
+	char line[64] = {0};
+	int max_enable, max_rate, max_exp = 0;
+	int min_enable, min_rate, min_exp = 0;
+	int weight;
+	int resv;
+	int scheduler;
+	size_t size;
+	u32 qtx_sch = 0;
+
+	cr_set_field(h->fe_base + QDMA_PAGE, QTX_CFG_PAGE, (id / NUM_OF_Q_PER_PAGE));
+	if (length >= sizeof(line))
+		return -EINVAL;
+
+	if (copy_from_user(line, buf, length))
+		return -EFAULT;
+
+	if (sscanf(line, "%d %d %d %d %d %d %d", &scheduler, &min_enable, &min_rate,
+		   &max_enable, &max_rate, &weight, &resv) != 7)
+		return -EFAULT;
+
+	line[length] = '\0';
+
+	while (max_rate > 127) {
+		max_rate /= 10;
+		max_exp++;
+	}
+
+	while (min_rate > 127) {
+		min_rate /= 10;
+		min_exp++;
+	}
+
+	if (hnat_priv->data->num_of_sch == 4)
+		qtx_sch |= (scheduler & 0x3) << 30;
+	else
+		qtx_sch |= (scheduler & 0x1) << 31;
+	if (min_enable)
+		qtx_sch |= BIT(27);
+	qtx_sch |= (min_rate & 0x7f) << 20;
+	qtx_sch |= (min_exp & 0xf) << 16;
+	if (max_enable)
+		qtx_sch |= BIT(11);
+	qtx_sch |= (weight & 0xf) << 12;
+	qtx_sch |= (max_rate & 0x7f) << 4;
+	qtx_sch |= max_exp & 0xf;
+	writel(qtx_sch, h->fe_base + QTX_SCH(id % NUM_OF_Q_PER_PAGE));
+
+	resv &= 0xff;
+	qtx_sch = readl(h->fe_base + QTX_CFG(id % NUM_OF_Q_PER_PAGE));
+	qtx_sch &= 0xffff0000;
+	qtx_sch |= (resv << 8) | resv;
+	writel(qtx_sch, h->fe_base + QTX_CFG(id % NUM_OF_Q_PER_PAGE));
+
+	size = strlen(line);
+	*offset += size;
+
+	return length;
+}
+
+static const struct file_operations hnat_queue_fops = {
+	.open = simple_open,
+	.read = hnat_queue_show,
+	.write = hnat_queue_write,
+	.llseek = default_llseek,
+};
+
+static ssize_t hnat_ppd_if_write(struct file *file, const char __user *buffer,
+				 size_t count, loff_t *data)
+{
+	char buf[IFNAMSIZ];
+	struct net_device *dev;
+	char *p, *tmp;
+
+	if (count >= IFNAMSIZ)
+		return -EFAULT;
+
+	memset(buf, 0, IFNAMSIZ);
+	if (copy_from_user(buf, buffer, count))
+		return -EFAULT;
+
+	tmp = buf;
+	p = strsep(&tmp, "\n\r ");
+	dev = dev_get_by_name(&init_net, p);
+
+	if (dev) {
+		if (hnat_priv->g_ppdev)
+			dev_put(hnat_priv->g_ppdev);
+		hnat_priv->g_ppdev = dev;
+
+		strncpy(hnat_priv->ppd, p, IFNAMSIZ - 1);
+		pr_info("hnat_priv ppd = %s\n", hnat_priv->ppd);
+	} else {
+		pr_info("no such device!\n");
+	}
+
+	return count;
+}
+
+static int hnat_ppd_if_read(struct seq_file *m, void *private)
+{
+	pr_info("hnat_priv ppd = %s\n", hnat_priv->ppd);
+
+	if (hnat_priv->g_ppdev) {
+		pr_info("hnat_priv g_ppdev name = %s\n",
+			hnat_priv->g_ppdev->name);
+	} else {
+		pr_info("hnat_priv g_ppdev is null!\n");
+	}
+
+	return 0;
+}
+
+static int hnat_ppd_if_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, hnat_ppd_if_read, file->private_data);
+}
+
+static const struct file_operations hnat_ppd_if_fops = {
+	.open = hnat_ppd_if_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.write = hnat_ppd_if_write,
+	.release = single_release,
+};
+
+static int hnat_mape_toggle_read(struct seq_file *m, void *private)
+{
+	pr_info("value=%d, %s is enabled now!\n", mape_toggle, (mape_toggle) ? "mape" : "ds-lite");
+
+	return 0;
+}
+
+static int hnat_mape_toggle_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, hnat_mape_toggle_read, file->private_data);
+}
+
+static ssize_t hnat_mape_toggle_write(struct file *file, const char __user *buffer,
+				      size_t count, loff_t *data)
+{
+	char buf = 0;
+	int len = count;
+
+	if (copy_from_user(&buf, buffer, len))
+		return -EFAULT;
+
+	if (buf == '1' && !mape_toggle) {
+		pr_info("mape is going to be enabled, ds-lite is going to be disabled !\n");
+		mape_toggle = 1;
+	} else if (buf == '0' && mape_toggle) {
+		pr_info("ds-lite is going to be enabled, mape is going to be disabled !\n");
+		mape_toggle = 0;
+	}
+
+	return len;
+}
+
+static const struct file_operations hnat_mape_toggle_fops = {
+	.open = hnat_mape_toggle_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.write = hnat_mape_toggle_write,
+	.release = single_release,
+};
+
+static int hnat_hook_toggle_read(struct seq_file *m, void *private)
+{
+	pr_info("value=%d, hook is %s now!\n", hook_toggle, (hook_toggle) ? "enabled" : "disabled");
+
+	return 0;
+}
+
+static int hnat_hook_toggle_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, hnat_hook_toggle_read, file->private_data);
+}
+
+static ssize_t hnat_hook_toggle_write(struct file *file, const char __user *buffer,
+				      size_t count, loff_t *data)
+{
+	char buf[8] = {0};
+	int len = count;
+	u32 id;
+
+	if ((len > 8) || copy_from_user(buf, buffer, len))
+		return -EFAULT;
+
+	if (buf[0] == '1' && !hook_toggle) {
+		pr_info("hook is going to be enabled !\n");
+		hnat_enable_hook();
+
+		if (IS_PPPQ_MODE) {
+			for (id = 0; id < MAX_PPPQ_PORT_NUM; id++)
+				hnat_qos_shaper_ebl(id, 1);
+		}
+	} else if (buf[0] == '0' && hook_toggle) {
+		pr_info("hook is going to be disabled !\n");
+		hnat_disable_hook();
+
+		if (IS_PPPQ_MODE) {
+			for (id = 0; id < MAX_PPPQ_PORT_NUM; id++)
+				hnat_qos_shaper_ebl(id, 0);
+		}
+	}
+
+	return len;
+}
+
+static const struct file_operations hnat_hook_toggle_fops = {
+	.open = hnat_hook_toggle_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.write = hnat_hook_toggle_write,
+	.release = single_release,
+};
+
+static int hnat_qos_toggle_read(struct seq_file *m, void *private)
+{
+	pr_info("value=%d, HQoS is %s now!\n", qos_toggle, (qos_toggle) ? "enabled" : "disabled");
+
+	return 0;
+}
+
+static int hnat_qos_toggle_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, hnat_qos_toggle_read, file->private_data);
+}
+
+void hnat_qos_shaper_ebl(u32 id, u32 enable)
+{
+	struct mtk_hnat *h = hnat_priv;
+	u32 cfg;
+
+	if (enable) {
+		cfg = QTX_SCH_MIN_RATE_EN | QTX_SCH_MAX_RATE_EN;
+		cfg |= (1 << QTX_SCH_MIN_RATE_MAN_OFFSET) |
+		       (4 << QTX_SCH_MIN_RATE_EXP_OFFSET) |
+		       (25 << QTX_SCH_MAX_RATE_MAN_OFFSET) |
+		       (5 << QTX_SCH_MAX_RATE_EXP_OFFSET) |
+		       (4 << QTX_SCH_MAX_RATE_WGHT_OFFSET);
+
+		writel(cfg, h->fe_base + QTX_SCH(id % NUM_OF_Q_PER_PAGE));
+	} else {
+		writel(0, h->fe_base + QTX_SCH(id % NUM_OF_Q_PER_PAGE));
+	}
+}
+
+static void hnat_qos_disable(void)
+{
+	struct mtk_hnat *h = hnat_priv;
+	u32 id, cfg;
+
+	for (id = 0; id < MAX_PPPQ_PORT_NUM; id++) {
+		hnat_qos_shaper_ebl(id, 0);
+		writel((4 << QTX_CFG_HW_RESV_CNT_OFFSET) |
+		       (4 << QTX_CFG_SW_RESV_CNT_OFFSET),
+		       h->fe_base + QTX_CFG(id % NUM_OF_Q_PER_PAGE));
+	}
+
+	cfg = (QDMA_TX_SCH_WFQ_EN) | (QDMA_TX_SCH_WFQ_EN << 16);
+	for (id = 0; id < h->data->num_of_sch; id += 2) {
+		if (h->data->num_of_sch == 4)
+			writel(cfg, h->fe_base + QDMA_TX_4SCH_BASE(id));
+		else
+			writel(cfg, h->fe_base + QDMA_TX_2SCH_BASE);
+	}
+}
+
+static void hnat_qos_pppq_enable(void)
+{
+	struct mtk_hnat *h = hnat_priv;
+	u32 id, cfg;
+
+	for (id = 0; id < MAX_PPPQ_PORT_NUM; id++) {
+		if (hook_toggle)
+			hnat_qos_shaper_ebl(id, 1);
+		else
+			hnat_qos_shaper_ebl(id, 0);
+
+		writel((4 << QTX_CFG_HW_RESV_CNT_OFFSET) |
+		       (4 << QTX_CFG_SW_RESV_CNT_OFFSET),
+		       h->fe_base + QTX_CFG(id % NUM_OF_Q_PER_PAGE));
+	}
+
+	cfg = (QDMA_TX_SCH_WFQ_EN) | (QDMA_TX_SCH_WFQ_EN << 16);
+	for (id = 0; id < h->data->num_of_sch; id+= 2) {
+		if (h->data->num_of_sch == 4)
+                        writel(cfg, h->fe_base + QDMA_TX_4SCH_BASE(id));
+                else
+                        writel(cfg, h->fe_base + QDMA_TX_2SCH_BASE);
+	}
+}
+
+static ssize_t hnat_qos_toggle_write(struct file *file, const char __user *buffer,
+				     size_t count, loff_t *data)
+{
+	char buf[8];
+	int len = count;
+
+	if ((len > 8) || copy_from_user(buf, buffer, len))
+		return -EFAULT;
+
+	if (buf[0] == '0') {
+		pr_info("HQoS is going to be disabled !\n");
+		qos_toggle = 0;
+		hnat_qos_disable();
+	} else if (buf[0] == '1') {
+		pr_info("HQoS mode is going to be enabled !\n");
+		qos_toggle = 1;
+	} else if (buf[0] == '2') {
+		pr_info("Per-port-per-queue mode is going to be enabled !\n");
+		qos_toggle = 2;
+		hnat_qos_pppq_enable();
+	}
+
+	return len;
+}
+
+static const struct file_operations hnat_qos_toggle_fops = {
+	.open = hnat_qos_toggle_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.write = hnat_qos_toggle_write,
+	.release = single_release,
+};
+
+static int hnat_version_read(struct seq_file *m, void *private)
+{
+	pr_info("HNAT SW version : %s\nHNAT HW version : %d\n", HNAT_SW_VER, hnat_priv->data->version);
+
+	return 0;
+}
+
+static int hnat_version_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, hnat_version_read, file->private_data);
+}
+
+static const struct file_operations hnat_version_fops = {
+	.open = hnat_version_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+int get_ppe_mib(u32 ppe_id, int index, u64 *pkt_cnt, u64 *byte_cnt)
+{
+	struct mtk_hnat *h = hnat_priv;
+	struct hnat_accounting *acct;
+	struct foe_entry *entry;
+
+	if (ppe_id >= CFG_PPE_NUM)
+		return -EINVAL;
+
+	if (index < 0 || index >= h->foe_etry_num) {
+		pr_info("Invalid entry index\n");
+		return -EINVAL;
+	}
+
+	acct = hnat_get_count(h, ppe_id, index, NULL);
+	entry = hnat_priv->foe_table_cpu[ppe_id] + index;
+
+	if (!acct)
+		return -1;
+
+	if (entry->bfib1.state != BIND)
+		return -1;
+
+	*pkt_cnt = acct->packets;
+	*byte_cnt = acct->bytes;
+
+	return 0;
+}
+EXPORT_SYMBOL(get_ppe_mib);
+
+int is_entry_binding(u32 ppe_id, int index)
+{
+	struct mtk_hnat *h = hnat_priv;
+	struct foe_entry *entry;
+
+	if (ppe_id >= CFG_PPE_NUM)
+		return -EINVAL;
+
+	if (index < 0 || index >= h->foe_etry_num) {
+		pr_info("Invalid entry index\n");
+		return -EINVAL;
+	}
+
+	entry = hnat_priv->foe_table_cpu[ppe_id] + index;
+
+	return entry->bfib1.state == BIND;
+}
+EXPORT_SYMBOL(is_entry_binding);
+
+#define dump_register(nm)                                                      \
+	{                                                                      \
+		.name = __stringify(nm), .offset = PPE_##nm,                   \
+	}
+
+static const struct debugfs_reg32 hnat_regs[] = {
+	dump_register(GLO_CFG),     dump_register(FLOW_CFG),
+	dump_register(IP_PROT_CHK), dump_register(IP_PROT_0),
+	dump_register(IP_PROT_1),   dump_register(IP_PROT_2),
+	dump_register(IP_PROT_3),   dump_register(TB_CFG),
+	dump_register(TB_BASE),     dump_register(TB_USED),
+	dump_register(BNDR),	dump_register(BIND_LMT_0),
+	dump_register(BIND_LMT_1),  dump_register(KA),
+	dump_register(UNB_AGE),     dump_register(BND_AGE_0),
+	dump_register(BND_AGE_1),   dump_register(HASH_SEED),
+	dump_register(DFT_CPORT),   dump_register(MCAST_PPSE),
+	dump_register(MCAST_L_0),   dump_register(MCAST_H_0),
+	dump_register(MCAST_L_1),   dump_register(MCAST_H_1),
+	dump_register(MCAST_L_2),   dump_register(MCAST_H_2),
+	dump_register(MCAST_L_3),   dump_register(MCAST_H_3),
+	dump_register(MCAST_L_4),   dump_register(MCAST_H_4),
+	dump_register(MCAST_L_5),   dump_register(MCAST_H_5),
+	dump_register(MCAST_L_6),   dump_register(MCAST_H_6),
+	dump_register(MCAST_L_7),   dump_register(MCAST_H_7),
+	dump_register(MCAST_L_8),   dump_register(MCAST_H_8),
+	dump_register(MCAST_L_9),   dump_register(MCAST_H_9),
+	dump_register(MCAST_L_A),   dump_register(MCAST_H_A),
+	dump_register(MCAST_L_B),   dump_register(MCAST_H_B),
+	dump_register(MCAST_L_C),   dump_register(MCAST_H_C),
+	dump_register(MCAST_L_D),   dump_register(MCAST_H_D),
+	dump_register(MCAST_L_E),   dump_register(MCAST_H_E),
+	dump_register(MCAST_L_F),   dump_register(MCAST_H_F),
+	dump_register(MTU_DRP),     dump_register(MTU_VLYR_0),
+	dump_register(MTU_VLYR_1),  dump_register(MTU_VLYR_2),
+	dump_register(VPM_TPID),    dump_register(VPM_TPID),
+	dump_register(CAH_CTRL),    dump_register(CAH_TAG_SRH),
+	dump_register(CAH_LINE_RW), dump_register(CAH_WDATA),
+	dump_register(CAH_RDATA),
+};
+
+int hnat_init_debugfs(struct mtk_hnat *h)
+{
+	int ret = 0;
+	struct dentry *root;
+	struct dentry *file;
+	long i;
+	char name[16];
+
+	root = debugfs_create_dir("hnat", NULL);
+	if (!root) {
+		dev_notice(h->dev, "%s:err at %d\n", __func__, __LINE__);
+		ret = -ENOMEM;
+		goto err0;
+	}
+	h->root = root;
+
+	for (i = 0; i < CFG_PPE_NUM; i++) {
+		h->regset[i] = kzalloc(sizeof(*h->regset[i]), GFP_KERNEL);
+		if (!h->regset[i]) {
+			dev_notice(h->dev, "%s:err at %d\n", __func__, __LINE__);
+			ret = -ENOMEM;
+			goto err1;
+		}
+		h->regset[i]->regs = hnat_regs;
+		h->regset[i]->nregs = ARRAY_SIZE(hnat_regs);
+		h->regset[i]->base = h->ppe_base[i];
+
+		snprintf(name, sizeof(name), "regdump%ld", i);
+		file = debugfs_create_regset32(name, S_IRUGO,
+					       root, h->regset[i]);
+		if (!file) {
+			dev_notice(h->dev, "%s:err at %d\n", __func__, __LINE__);
+			ret = -ENOMEM;
+			goto err1;
+		}
+	}
+
+	debugfs_create_file("all_entry", S_IRUGO, root, h, &hnat_debug_fops);
+	debugfs_create_file("external_interface", S_IRUGO, root, h,
+			    &hnat_ext_fops);
+	debugfs_create_file("whnat_interface", S_IRUGO, root, h,
+			    &hnat_whnat_fops);
+	debugfs_create_file("cpu_reason", S_IFREG | S_IRUGO, root, h,
+			    &cpu_reason_fops);
+	debugfs_create_file("hnat_entry", S_IRUGO | S_IRUGO, root, h,
+			    &hnat_entry_fops);
+	debugfs_create_file("hnat_setting", S_IRUGO | S_IRUGO, root, h,
+			    &hnat_setting_fops);
+	debugfs_create_file("mcast_table", S_IRUGO | S_IRUGO, root, h,
+			    &hnat_mcast_fops);
+	debugfs_create_file("hook_toggle", S_IRUGO | S_IRUGO, root, h,
+			    &hnat_hook_toggle_fops);
+	debugfs_create_file("mape_toggle", S_IRUGO | S_IRUGO, root, h,
+			    &hnat_mape_toggle_fops);
+	debugfs_create_file("qos_toggle", S_IRUGO | S_IRUGO, root, h,
+			    &hnat_qos_toggle_fops);
+	debugfs_create_file("hnat_version", S_IRUGO | S_IRUGO, root, h,
+			    &hnat_version_fops);
+	debugfs_create_file("hnat_ppd_if", S_IRUGO | S_IRUGO, root, h,
+			    &hnat_ppd_if_fops);
+
+	for (i = 0; i < hnat_priv->data->num_of_sch; i++) {
+		snprintf(name, sizeof(name), "qdma_sch%ld", i);
+		debugfs_create_file(name, S_IRUGO, root, (void *)i,
+				    &hnat_sched_fops);
+	}
+
+	for (i = 0; i < MTK_QDMA_TX_NUM; i++) {
+		snprintf(name, sizeof(name), "qdma_txq%ld", i);
+		debugfs_create_file(name, S_IRUGO, root, (void *)i,
+				    &hnat_queue_fops);
+	}
+
+	return 0;
+
+err1:
+	debugfs_remove_recursive(root);
+err0:
+	return ret;
+}
+
+void hnat_deinit_debugfs(struct mtk_hnat *h)
+{
+	int i;
+
+	debugfs_remove_recursive(h->root);
+	h->root = NULL;
+
+	for (i = 0; i < CFG_PPE_NUM; i++)
+		kfree(h->regset[i]);
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_mcast.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_mcast.c
new file mode 100644
index 0000000..512c845
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_mcast.c
@@ -0,0 +1,355 @@
+/*   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; version 2 of the License
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   Copyright (C) 2014-2016 Zhiqiang Yang <zhiqiang.yang@mediatek.com>
+ */
+#include <net/sock.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_bridge.h>
+#include "hnat.h"
+
+/* *
+ * mcast_entry_get - Returns the index of an unused entry
+ * or an already existed entry in mtbl
+ */
+static int mcast_entry_get(u16 vlan_id, u32 dst_mac)
+{
+	int index = -1;
+	u8 i;
+	struct ppe_mcast_group *p = hnat_priv->pmcast->mtbl;
+	u8 max = hnat_priv->pmcast->max_entry;
+
+	for (i = 0; i < max; i++) {
+		if ((index == -1) && (!p->valid)) {
+			index = i; /*get the first unused entry index*/
+			continue;
+		}
+		if ((p->vid == vlan_id) && (p->mac_hi == dst_mac)) {
+			index = i;
+			break;
+		}
+		p++;
+	}
+	if (index == -1)
+		pr_info("%s:group table is full\n", __func__);
+
+	return index;
+}
+
+static void get_mac_from_mdb_entry(struct br_mdb_entry *entry,
+				   u32 *mac_hi, u16 *mac_lo)
+{
+	switch (ntohs(entry->addr.proto)) {
+	case ETH_P_IP:
+		*mac_lo = 0x0100;
+		*mac_hi = swab32((entry->addr.u.ip4 & 0xfffffe00) + 0x5e);
+		break;
+	case ETH_P_IPV6:
+		*mac_lo = 0x3333;
+		*mac_hi = swab32(entry->addr.u.ip6.s6_addr32[3]);
+		break;
+	}
+	trace_printk("%s:group mac_h=0x%08x, mac_l=0x%04x\n",
+		     __func__, *mac_hi, *mac_lo);
+}
+
+/*set_hnat_mtbl - set ppe multicast register*/
+static int set_hnat_mtbl(struct ppe_mcast_group *group, u32 ppe_id, int index)
+{
+	struct ppe_mcast_h mcast_h;
+	struct ppe_mcast_l mcast_l;
+	u16 mac_lo = group->mac_lo;
+	u32 mac_hi = group->mac_hi;
+	u8 mc_port = group->mc_port;
+	void __iomem *reg;
+
+	if (ppe_id >= CFG_PPE_NUM)
+		return -EINVAL;
+
+	mcast_h.u.value = 0;
+	mcast_l.addr = 0;
+	if (mac_lo == 0x0100)
+		mcast_h.u.info.mc_mpre_sel = 0;
+	else if (mac_lo == 0x3333)
+		mcast_h.u.info.mc_mpre_sel = 1;
+
+	mcast_h.u.info.mc_px_en = mc_port;
+	mcast_l.addr = mac_hi;
+	mcast_h.u.info.valid = group->valid;
+	trace_printk("%s:index=%d,group info=0x%x,addr=0x%x\n",
+		     __func__, index, mcast_h.u.value, mcast_l.addr);
+	if (index < 0x10) {
+		reg = hnat_priv->ppe_base[ppe_id] + PPE_MCAST_H_0 + ((index) * 8);
+		writel(mcast_h.u.value, reg);
+		reg = hnat_priv->ppe_base[ppe_id] + PPE_MCAST_L_0 + ((index) * 8);
+		writel(mcast_l.addr, reg);
+	} else {
+		index = index - 0x10;
+		reg = hnat_priv->fe_base + PPE_MCAST_H_10 + ((index) * 8);
+		writel(mcast_h.u.value, reg);
+		reg = hnat_priv->fe_base + PPE_MCAST_L_10 + ((index) * 8);
+		writel(mcast_h.u.value, reg);
+	}
+
+	return 0;
+}
+
+/**
+ * hnat_mcast_table_update -
+ *	1.get a valid group entry
+ *	2.update group info
+ *		a.update eif&oif count
+ *		b.eif ==0 & oif == 0,delete it from group table
+ *		c.oif != 0,set mc forward port to cpu,else do not forward to cpu
+ *	3.set the group info to ppe register
+ */
+static int hnat_mcast_table_update(int type, struct br_mdb_entry *entry)
+{
+	struct net_device *dev;
+	u32 mac_hi = 0;
+	u16 mac_lo = 0;
+	int i, index;
+	struct ppe_mcast_group *group;
+
+	rcu_read_lock();
+	dev = dev_get_by_index_rcu(&init_net, entry->ifindex);
+	if (!dev) {
+		rcu_read_unlock();
+		return -ENODEV;
+	}
+	rcu_read_unlock();
+
+	get_mac_from_mdb_entry(entry, &mac_hi, &mac_lo);
+	index = mcast_entry_get(entry->vid, mac_hi);
+	if (index == -1)
+		return -1;
+
+	group = &hnat_priv->pmcast->mtbl[index];
+	group->mac_hi = mac_hi;
+	group->mac_lo = mac_lo;
+	switch (type) {
+	case RTM_NEWMDB:
+		if (IS_LAN(dev) || IS_WAN(dev))
+			group->eif++;
+		else
+			group->oif++;
+		group->vid = entry->vid;
+		group->valid = true;
+		break;
+	case RTM_DELMDB:
+		if (group->valid) {
+			if (IS_LAN(dev) || IS_WAN(dev))
+				group->eif--;
+			else
+				group->oif--;
+			}
+		break;
+	}
+	trace_printk("%s:devname=%s,eif=%d,oif=%d\n", __func__,
+		     dev->name, group->eif, group->oif);
+	if (group->valid) {
+		if (group->oif && group->eif)
+			/*eth&wifi both in group,forward to cpu&GDMA1*/
+			group->mc_port = (MCAST_TO_PDMA || MCAST_TO_GDMA1);
+		else if (group->oif)
+			/*only wifi in group,forward to cpu only*/
+			group->mc_port = MCAST_TO_PDMA;
+		else
+			/*only eth in group,forward to GDMA1 only*/
+			group->mc_port = MCAST_TO_GDMA1;
+		if (!group->oif && !group->eif)
+			/*nobody in this group,clear the entry*/
+			memset(group, 0, sizeof(struct ppe_mcast_group));
+
+		for (i = 0; i < CFG_PPE_NUM; i++)
+			set_hnat_mtbl(group, i, index);
+	}
+
+	return 0;
+}
+
+static void hnat_mcast_nlmsg_handler(struct work_struct *work)
+{
+	struct sk_buff *skb = NULL;
+	struct nlmsghdr *nlh;
+	struct nlattr *nest, *nest2, *info;
+	struct br_port_msg *bpm;
+	struct br_mdb_entry *entry;
+	struct ppe_mcast_table *pmcast;
+	struct sock *sk;
+
+	pmcast = container_of(work, struct ppe_mcast_table, work);
+	sk = pmcast->msock->sk;
+
+	while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
+		nlh = nlmsg_hdr(skb);
+		if (!nlmsg_ok(nlh, skb->len)) {
+			kfree_skb(skb);
+			continue;
+		}
+		bpm = nlmsg_data(nlh);
+		nest = nlmsg_find_attr(nlh, sizeof(bpm), MDBA_MDB);
+		if (!nest) {
+			kfree_skb(skb);
+			continue;
+		}
+		nest2 = nla_find_nested(nest, MDBA_MDB_ENTRY);
+		if (nest2) {
+			info = nla_find_nested(nest2, MDBA_MDB_ENTRY_INFO);
+			if (!info) {
+				kfree_skb(skb);
+				continue;
+			}
+
+			entry = (struct br_mdb_entry *)nla_data(info);
+			trace_printk("%s:cmd=0x%2x,ifindex=0x%x,state=0x%x",
+				     __func__, nlh->nlmsg_type,
+				     entry->ifindex, entry->state);
+			trace_printk("vid=0x%x,ip=0x%x,proto=0x%x\n",
+				     entry->vid, entry->addr.u.ip4,
+				     entry->addr.proto);
+			hnat_mcast_table_update(nlh->nlmsg_type, entry);
+		}
+		kfree_skb(skb);
+	}
+}
+
+static void hnat_mcast_nlmsg_rcv(struct sock *sk)
+{
+	struct ppe_mcast_table *pmcast = hnat_priv->pmcast;
+	struct workqueue_struct *queue = pmcast->queue;
+	struct work_struct *work = &pmcast->work;
+
+	queue_work(queue, work);
+}
+
+static struct socket *hnat_mcast_netlink_open(struct net *net)
+{
+	struct socket *sock = NULL;
+	int ret;
+	struct sockaddr_nl addr;
+
+	ret = sock_create_kern(net, PF_NETLINK, SOCK_RAW, NETLINK_ROUTE, &sock);
+	if (ret < 0)
+		goto out;
+
+	sock->sk->sk_data_ready = hnat_mcast_nlmsg_rcv;
+	addr.nl_family = PF_NETLINK;
+	addr.nl_pid = 65536; /*fix me:how to get an unique id?*/
+	addr.nl_groups = RTMGRP_MDB;
+	ret = sock->ops->bind(sock, (struct sockaddr *)&addr, sizeof(addr));
+	if (ret < 0)
+		goto out;
+
+	return sock;
+out:
+	if (sock)
+		sock_release(sock);
+
+	return NULL;
+}
+
+static void hnat_mcast_check_timestamp(struct timer_list *t)
+{
+	struct foe_entry *entry;
+	int i, hash_index;
+	u16 e_ts, foe_ts;
+
+	for (i = 0; i < CFG_PPE_NUM; i++) {
+		for (hash_index = 0; hash_index < hnat_priv->foe_etry_num; hash_index++) {
+			entry = hnat_priv->foe_table_cpu[i] + hash_index;
+			if (entry->bfib1.sta == 1) {
+				e_ts = (entry->ipv4_hnapt.m_timestamp) & 0xffff;
+				foe_ts = foe_timestamp(hnat_priv);
+				if ((foe_ts - e_ts) > 0x3000)
+					foe_ts = (~(foe_ts)) & 0xffff;
+				if (abs(foe_ts - e_ts) > 20)
+					entry_delete(i, hash_index);
+			}
+		}
+	}
+	mod_timer(&hnat_priv->hnat_mcast_check_timer, jiffies + 10 * HZ);
+}
+
+int hnat_mcast_enable(u32 ppe_id)
+{
+	struct ppe_mcast_table *pmcast;
+
+	if (ppe_id >= CFG_PPE_NUM)
+		return -EINVAL;
+
+	pmcast = kzalloc(sizeof(*pmcast), GFP_KERNEL);
+	if (!pmcast)
+		return -1;
+
+	if (hnat_priv->data->version == MTK_HNAT_V1)
+		pmcast->max_entry = 0x10;
+	else
+		pmcast->max_entry = MAX_MCAST_ENTRY;
+
+	INIT_WORK(&pmcast->work, hnat_mcast_nlmsg_handler);
+	pmcast->queue = create_singlethread_workqueue("ppe_mcast");
+	if (!pmcast->queue)
+		goto err;
+
+	pmcast->msock = hnat_mcast_netlink_open(&init_net);
+	if (!pmcast->msock)
+		goto err;
+
+	hnat_priv->pmcast = pmcast;
+
+	/* mt7629 should checkout mcast entry life time manualy */
+	if (hnat_priv->data->version == MTK_HNAT_V3) {
+		timer_setup(&hnat_priv->hnat_mcast_check_timer,
+			    hnat_mcast_check_timestamp, 0);
+		hnat_priv->hnat_mcast_check_timer.expires = jiffies;
+		add_timer(&hnat_priv->hnat_mcast_check_timer);
+	}
+
+	/* Enable multicast table lookup */
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_GLO_CFG, MCAST_TB_EN, 1);
+	/* multicast port0 map to PDMA */
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_MCAST_PPSE, MC_P0_PPSE, 0);
+	/* multicast port1 map to GMAC1 */
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_MCAST_PPSE, MC_P1_PPSE, 1);
+	/* multicast port2 map to GMAC2 */
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_MCAST_PPSE, MC_P2_PPSE, 2);
+	/* multicast port3 map to QDMA */
+	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_MCAST_PPSE, MC_P3_PPSE, 5);
+
+	return 0;
+err:
+	if (pmcast->queue)
+		destroy_workqueue(pmcast->queue);
+	if (pmcast->msock)
+		sock_release(pmcast->msock);
+	kfree(pmcast);
+
+	return -1;
+}
+
+int hnat_mcast_disable(void)
+{
+	struct ppe_mcast_table *pmcast = hnat_priv->pmcast;
+
+	if (!pmcast)
+		return -EINVAL;
+
+	if (hnat_priv->data->version == MTK_HNAT_V3)
+		del_timer_sync(&hnat_priv->hnat_mcast_check_timer);
+
+	flush_work(&pmcast->work);
+	destroy_workqueue(pmcast->queue);
+	sock_release(pmcast->msock);
+	kfree(pmcast);
+
+	return 0;
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_mcast.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_mcast.h
new file mode 100644
index 0000000..ad5b5d1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_mcast.h
@@ -0,0 +1,69 @@
+/*   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; version 2 of the License
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   Copyright (C) 2014-2016 Zhiqiang Yang <zhiqiang.yang@mediatek.com>
+ */
+
+#ifndef NF_HNAT_MCAST_H
+#define NF_HNAT_MCAST_H
+
+#define RTMGRP_IPV4_MROUTE 0x20
+#define RTMGRP_MDB 0x2000000
+
+#define MAX_MCAST_ENTRY 64
+
+#define MCAST_TO_PDMA (0x1 << 0)
+#define MCAST_TO_GDMA1 (0x1 << 1)
+#define MCAST_TO_GDMA2 (0x1 << 2)
+
+struct ppe_mcast_group {
+	u32 mac_hi; /*multicast mac addr*/
+	u16 mac_lo; /*multicast mac addr*/
+	u16 vid;
+	u8 mc_port; /*1:forward to cpu,2:forward to GDMA1,4:forward to GDMA2*/
+	u8 eif; /*num of eth if added to multi group. */
+	u8 oif; /* num of other if added to multi group ,ex wifi.*/
+	bool valid;
+};
+
+struct ppe_mcast_table {
+	struct workqueue_struct *queue;
+	struct work_struct work;
+	struct socket *msock;
+	struct ppe_mcast_group mtbl[MAX_MCAST_ENTRY];
+	u8 max_entry;
+};
+
+struct ppe_mcast_h {
+	union {
+		u32 value;
+		struct {
+			u32 mc_vid:12;
+			u32 mc_qos_qid54:2; /* mt7622 only */
+			u32 valid:1;
+			u32 rev1:1;
+			/*0:forward to cpu,1:forward to GDMA1*/
+			u32 mc_px_en:4;
+			u32 mc_mpre_sel:2; /* 0=01:00, 2=33:33 */
+			u32 mc_vid_cmp:1;
+			u32 rev2:1;
+			u32 mc_px_qos_en:4;
+			u32 mc_qos_qid:4;
+		} info;
+	} u;
+};
+
+struct ppe_mcast_l {
+	u32 addr;
+};
+
+int hnat_mcast_enable(u32 ppe_id);
+int hnat_mcast_disable(void);
+
+#endif
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
new file mode 100644
index 0000000..24275a0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
@@ -0,0 +1,2288 @@
+/*   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; version 2 of the License
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   Copyright (C) 2014-2016 Sean Wang <sean.wang@mediatek.com>
+ *   Copyright (C) 2016-2017 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/netfilter_bridge.h>
+#include <linux/netfilter_ipv6.h>
+
+#include <net/arp.h>
+#include <net/neighbour.h>
+#include <net/netfilter/nf_conntrack_helper.h>
+#include <net/netfilter/nf_flow_table.h>
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#include <net/ip.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_acct.h>
+
+#include "nf_hnat_mtk.h"
+#include "hnat.h"
+
+#include "../mtk_eth_soc.h"
+
+#define do_ge2ext_fast(dev, skb)                                               \
+	((IS_LAN(dev) || IS_WAN(dev) || IS_PPD(dev)) && \
+	 skb_hnat_is_hashed(skb) && \
+	 skb_hnat_reason(skb) == HIT_BIND_FORCE_TO_CPU)
+#define do_ext2ge_fast_learn(dev, skb)                                         \
+	(IS_PPD(dev) &&                                                        \
+	 (skb_hnat_sport(skb) == NR_PDMA_PORT ||                           \
+	  skb_hnat_sport(skb) == NR_QDMA_PORT) &&                       \
+	  ((get_dev_from_index(skb->vlan_tci & VLAN_VID_MASK)) ||   \
+		 get_wandev_from_index(skb->vlan_tci & VLAN_VID_MASK)))
+#define do_mape_w2l_fast(dev, skb)                                          \
+		(mape_toggle && IS_WAN(dev) && (!is_from_mape(skb)))
+
+static struct ipv6hdr mape_l2w_v6h;
+static struct ipv6hdr mape_w2l_v6h;
+static inline uint8_t get_wifi_hook_if_index_from_dev(const struct net_device *dev)
+{
+	int i;
+
+	for (i = 1; i < MAX_IF_NUM; i++) {
+		if (hnat_priv->wifi_hook_if[i] == dev)
+			return i;
+	}
+
+	return 0;
+}
+
+static inline int get_ext_device_number(void)
+{
+	int i, number = 0;
+
+	for (i = 0; i < MAX_EXT_DEVS && hnat_priv->ext_if[i]; i++)
+		number += 1;
+	return number;
+}
+
+static inline int find_extif_from_devname(const char *name)
+{
+	int i;
+	struct extdev_entry *ext_entry;
+
+	for (i = 0; i < MAX_EXT_DEVS && hnat_priv->ext_if[i]; i++) {
+		ext_entry = hnat_priv->ext_if[i];
+		if (!strcmp(name, ext_entry->name))
+			return 1;
+	}
+	return 0;
+}
+
+static inline int get_index_from_dev(const struct net_device *dev)
+{
+	int i;
+	struct extdev_entry *ext_entry;
+
+	for (i = 0; i < MAX_EXT_DEVS && hnat_priv->ext_if[i]; i++) {
+		ext_entry = hnat_priv->ext_if[i];
+		if (dev == ext_entry->dev)
+			return ext_entry->dev->ifindex;
+	}
+	return 0;
+}
+
+static inline struct net_device *get_dev_from_index(int index)
+{
+	int i;
+	struct extdev_entry *ext_entry;
+	struct net_device *dev = 0;
+
+	for (i = 0; i < MAX_EXT_DEVS && hnat_priv->ext_if[i]; i++) {
+		ext_entry = hnat_priv->ext_if[i];
+		if (ext_entry->dev && index == ext_entry->dev->ifindex) {
+			dev = ext_entry->dev;
+			break;
+		}
+	}
+	return dev;
+}
+
+static inline struct net_device *get_wandev_from_index(int index)
+{
+	if (!hnat_priv->g_wandev)
+		hnat_priv->g_wandev = dev_get_by_name(&init_net, hnat_priv->wan);
+
+	if (hnat_priv->g_wandev && hnat_priv->g_wandev->ifindex == index)
+		return hnat_priv->g_wandev;
+	return NULL;
+}
+
+static inline int extif_set_dev(struct net_device *dev)
+{
+	int i;
+	struct extdev_entry *ext_entry;
+
+	for (i = 0; i < MAX_EXT_DEVS && hnat_priv->ext_if[i]; i++) {
+		ext_entry = hnat_priv->ext_if[i];
+		if (!strcmp(dev->name, ext_entry->name) && !ext_entry->dev) {
+			dev_hold(dev);
+			ext_entry->dev = dev;
+			pr_info("%s(%s)\n", __func__, dev->name);
+
+			return ext_entry->dev->ifindex;
+		}
+	}
+
+	return -1;
+}
+
+static inline int extif_put_dev(struct net_device *dev)
+{
+	int i;
+	struct extdev_entry *ext_entry;
+
+	for (i = 0; i < MAX_EXT_DEVS && hnat_priv->ext_if[i]; i++) {
+		ext_entry = hnat_priv->ext_if[i];
+		if (ext_entry->dev == dev) {
+			ext_entry->dev = NULL;
+			dev_put(dev);
+			pr_info("%s(%s)\n", __func__, dev->name);
+
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+int ext_if_add(struct extdev_entry *ext_entry)
+{
+	int len = get_ext_device_number();
+
+	if (len < MAX_EXT_DEVS)
+		hnat_priv->ext_if[len++] = ext_entry;
+
+	return len;
+}
+
+int ext_if_del(struct extdev_entry *ext_entry)
+{
+	int i, j;
+
+	for (i = 0; i < MAX_EXT_DEVS; i++) {
+		if (hnat_priv->ext_if[i] == ext_entry) {
+			for (j = i; hnat_priv->ext_if[j] && j < MAX_EXT_DEVS - 1; j++)
+				hnat_priv->ext_if[j] = hnat_priv->ext_if[j + 1];
+			hnat_priv->ext_if[j] = NULL;
+			break;
+		}
+	}
+
+	return i;
+}
+
+void foe_clear_all_bind_entries(struct net_device *dev)
+{
+	int i, hash_index;
+	struct foe_entry *entry;
+
+	if (!IS_LAN(dev) && !IS_WAN(dev) &&
+	    !find_extif_from_devname(dev->name) &&
+	    !dev->netdev_ops->ndo_flow_offload_check)
+		return;
+
+	for (i = 0; i < CFG_PPE_NUM; i++) {
+		cr_set_field(hnat_priv->ppe_base[i] + PPE_TB_CFG,
+			     SMA, SMA_ONLY_FWD_CPU);
+
+		for (hash_index = 0; hash_index < hnat_priv->foe_etry_num; hash_index++) {
+			entry = hnat_priv->foe_table_cpu[i] + hash_index;
+			if (entry->bfib1.state == BIND) {
+				entry->ipv4_hnapt.udib1.state = INVALID;
+				entry->ipv4_hnapt.udib1.time_stamp =
+					readl((hnat_priv->fe_base + 0x0010)) & 0xFF;
+			}
+		}
+	}
+
+	/* clear HWNAT cache */
+	hnat_cache_ebl(1);
+
+	mod_timer(&hnat_priv->hnat_sma_build_entry_timer, jiffies + 3 * HZ);
+}
+
+static void gmac_ppe_fwd_enable(struct net_device *dev)
+{
+	if (IS_LAN(dev) || IS_GMAC1_MODE)
+		set_gmac_ppe_fwd(0, 1);
+	else if (IS_WAN(dev))
+		set_gmac_ppe_fwd(1, 1);
+}
+
+int nf_hnat_netdevice_event(struct notifier_block *unused, unsigned long event,
+			    void *ptr)
+{
+	struct net_device *dev;
+
+	dev = netdev_notifier_info_to_dev(ptr);
+
+	switch (event) {
+	case NETDEV_UP:
+		gmac_ppe_fwd_enable(dev);
+
+		extif_set_dev(dev);
+
+		break;
+	case NETDEV_GOING_DOWN:
+		if (!get_wifi_hook_if_index_from_dev(dev))
+			extif_put_dev(dev);
+
+		foe_clear_all_bind_entries(dev);
+
+		break;
+	case NETDEV_UNREGISTER:
+		if (hnat_priv->g_ppdev == dev) {
+			hnat_priv->g_ppdev = NULL;
+			dev_put(dev);
+		}
+		if (hnat_priv->g_wandev == dev) {
+			hnat_priv->g_wandev = NULL;
+			dev_put(dev);
+		}
+
+		break;
+	case NETDEV_REGISTER:
+		if (IS_PPD(dev) && !hnat_priv->g_ppdev)
+			hnat_priv->g_ppdev = dev_get_by_name(&init_net, hnat_priv->ppd);
+		if (IS_WAN(dev) && !hnat_priv->g_wandev)
+			hnat_priv->g_wandev = dev_get_by_name(&init_net, hnat_priv->wan);
+
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+void foe_clear_entry(struct neighbour *neigh)
+{
+	u32 *daddr = (u32 *)neigh->primary_key;
+	unsigned char h_dest[ETH_ALEN];
+	struct foe_entry *entry;
+	int i, hash_index;
+	u32 dip;
+
+	dip = (u32)(*daddr);
+
+	for (i = 0; i < CFG_PPE_NUM; i++) {
+		for (hash_index = 0; hash_index < hnat_priv->foe_etry_num; hash_index++) {
+			entry = hnat_priv->foe_table_cpu[i] + hash_index;
+			if (entry->bfib1.state == BIND &&
+			    entry->ipv4_hnapt.new_dip == ntohl(dip)) {
+				*((u32 *)h_dest) = swab32(entry->ipv4_hnapt.dmac_hi);
+				*((u16 *)&h_dest[4]) =
+					swab16(entry->ipv4_hnapt.dmac_lo);
+				if (strncmp(h_dest, neigh->ha, ETH_ALEN) != 0) {
+					pr_info("%s: state=%d\n", __func__,
+						neigh->nud_state);
+					cr_set_field(hnat_priv->ppe_base[i] + PPE_TB_CFG,
+						     SMA, SMA_ONLY_FWD_CPU);
+
+					entry->ipv4_hnapt.udib1.state = INVALID;
+					entry->ipv4_hnapt.udib1.time_stamp =
+						readl((hnat_priv->fe_base + 0x0010)) & 0xFF;
+
+					/* clear HWNAT cache */
+					hnat_cache_ebl(1);
+
+					mod_timer(&hnat_priv->hnat_sma_build_entry_timer,
+						  jiffies + 3 * HZ);
+
+					pr_info("Delete old entry: dip =%pI4\n", &dip);
+					pr_info("Old mac= %pM\n", h_dest);
+					pr_info("New mac= %pM\n", neigh->ha);
+				}
+			}
+		}
+	}
+}
+
+int nf_hnat_netevent_handler(struct notifier_block *unused, unsigned long event,
+			     void *ptr)
+{
+	struct net_device *dev = NULL;
+	struct neighbour *neigh = NULL;
+
+	switch (event) {
+	case NETEVENT_NEIGH_UPDATE:
+		neigh = ptr;
+		dev = neigh->dev;
+		if (dev)
+			foe_clear_entry(neigh);
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+unsigned int mape_add_ipv6_hdr(struct sk_buff *skb, struct ipv6hdr mape_ip6h)
+{
+	struct ethhdr *eth = NULL;
+	struct ipv6hdr *ip6h = NULL;
+	struct iphdr *iph = NULL;
+
+	if (skb_headroom(skb) < IPV6_HDR_LEN || skb_shared(skb) ||
+	    (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
+		return -1;
+	}
+
+	/* point to L3 */
+	memcpy(skb->data - IPV6_HDR_LEN - ETH_HLEN, skb_push(skb, ETH_HLEN), ETH_HLEN);
+	memcpy(skb_push(skb, IPV6_HDR_LEN - ETH_HLEN), &mape_ip6h, IPV6_HDR_LEN);
+
+	eth = (struct ethhdr *)(skb->data - ETH_HLEN);
+	eth->h_proto = htons(ETH_P_IPV6);
+	skb->protocol = htons(ETH_P_IPV6);
+
+	iph = (struct iphdr *)(skb->data + IPV6_HDR_LEN);
+	ip6h = (struct ipv6hdr *)(skb->data);
+	ip6h->payload_len = iph->tot_len; /* maybe different with ipv4 */
+
+	skb_set_network_header(skb, 0);
+	skb_set_transport_header(skb, iph->ihl * 4 + IPV6_HDR_LEN);
+	return 0;
+}
+
+static void fix_skb_packet_type(struct sk_buff *skb, struct net_device *dev,
+				struct ethhdr *eth)
+{
+	skb->pkt_type = PACKET_HOST;
+	if (unlikely(is_multicast_ether_addr(eth->h_dest))) {
+		if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast))
+			skb->pkt_type = PACKET_BROADCAST;
+		else
+			skb->pkt_type = PACKET_MULTICAST;
+	}
+}
+
+unsigned int do_hnat_ext_to_ge(struct sk_buff *skb, const struct net_device *in,
+			       const char *func)
+{
+	if (hnat_priv->g_ppdev && hnat_priv->g_ppdev->flags & IFF_UP) {
+		u16 vlan_id = 0;
+		skb_set_network_header(skb, 0);
+		skb_push(skb, ETH_HLEN);
+		set_to_ppe(skb);
+
+		vlan_id = skb_vlan_tag_get_id(skb);
+		if (vlan_id) {
+			skb = vlan_insert_tag(skb, skb->vlan_proto, skb->vlan_tci);
+			if (!skb)
+				return -1;
+		}
+
+		/*set where we come from*/
+		skb->vlan_proto = htons(ETH_P_8021Q);
+		skb->vlan_tci =
+			(VLAN_CFI_MASK | (in->ifindex & VLAN_VID_MASK));
+		trace_printk(
+			"%s: vlan_prot=0x%x, vlan_tci=%x, in->name=%s, skb->dev->name=%s\n",
+			__func__, ntohs(skb->vlan_proto), skb->vlan_tci,
+			in->name, hnat_priv->g_ppdev->name);
+		skb->dev = hnat_priv->g_ppdev;
+		dev_queue_xmit(skb);
+		trace_printk("%s: called from %s successfully\n", __func__, func);
+		return 0;
+	}
+
+	trace_printk("%s: called from %s fail\n", __func__, func);
+	return -1;
+}
+
+unsigned int do_hnat_ext_to_ge2(struct sk_buff *skb, const char *func)
+{
+	struct ethhdr *eth = eth_hdr(skb);
+	struct net_device *dev;
+	struct foe_entry *entry;
+
+	trace_printk("%s: vlan_prot=0x%x, vlan_tci=%x\n", __func__,
+		     ntohs(skb->vlan_proto), skb->vlan_tci);
+
+	dev = get_dev_from_index(skb->vlan_tci & VLAN_VID_MASK);
+
+	if (dev) {
+		/*set where we to go*/
+		skb->dev = dev;
+		skb->vlan_proto = 0;
+		skb->vlan_tci = 0;
+
+		if (ntohs(eth->h_proto) == ETH_P_8021Q) {
+			skb = skb_vlan_untag(skb);
+			if (unlikely(!skb))
+				return -1;
+		}
+
+		if (IS_BOND_MODE &&
+		    (((hnat_priv->data->version == MTK_HNAT_V4) &&
+				(skb_hnat_entry(skb) != 0x7fff)) ||
+		     ((hnat_priv->data->version != MTK_HNAT_V4) &&
+				(skb_hnat_entry(skb) != 0x3fff))))
+			skb_set_hash(skb, skb_hnat_entry(skb) >> 1, PKT_HASH_TYPE_L4);
+
+		set_from_extge(skb);
+		fix_skb_packet_type(skb, skb->dev, eth);
+		netif_rx(skb);
+		trace_printk("%s: called from %s successfully\n", __func__,
+			     func);
+		return 0;
+	} else {
+		/* MapE WAN --> LAN/WLAN PingPong. */
+		dev = get_wandev_from_index(skb->vlan_tci & VLAN_VID_MASK);
+		if (mape_toggle && dev) {
+			if (!mape_add_ipv6_hdr(skb, mape_w2l_v6h)) {
+				skb_set_mac_header(skb, -ETH_HLEN);
+				skb->dev = dev;
+				set_from_mape(skb);
+				skb->vlan_proto = 0;
+				skb->vlan_tci = 0;
+				fix_skb_packet_type(skb, skb->dev, eth_hdr(skb));
+				entry = &hnat_priv->foe_table_cpu[skb_hnat_ppe(skb)][skb_hnat_entry(skb)];
+				entry->bfib1.pkt_type = IPV4_HNAPT;
+				netif_rx(skb);
+				return 0;
+			}
+		}
+		trace_printk("%s: called from %s fail\n", __func__, func);
+		return -1;
+	}
+}
+
+unsigned int do_hnat_ge_to_ext(struct sk_buff *skb, const char *func)
+{
+	/*set where we to go*/
+	u8 index;
+	struct foe_entry *entry;
+	struct net_device *dev;
+
+	entry = &hnat_priv->foe_table_cpu[skb_hnat_ppe(skb)][skb_hnat_entry(skb)];
+
+	if (IS_IPV4_GRP(entry))
+		index = entry->ipv4_hnapt.act_dp;
+	else
+		index = entry->ipv6_5t_route.act_dp;
+
+	skb->dev = get_dev_from_index(index);
+
+	if (IS_HQOS_MODE && eth_hdr(skb)->h_proto == HQOS_MAGIC_TAG) {
+		skb = skb_unshare(skb, GFP_ATOMIC);
+		if (!skb)
+			return NF_ACCEPT;
+
+		if (unlikely(!pskb_may_pull(skb, VLAN_HLEN)))
+			return NF_ACCEPT;
+
+		skb_pull_rcsum(skb, VLAN_HLEN);
+
+		memmove(skb->data - ETH_HLEN, skb->data - ETH_HLEN - VLAN_HLEN,
+			2 * ETH_ALEN);
+	}
+
+	if (skb->dev) {
+		skb_set_network_header(skb, 0);
+		skb_push(skb, ETH_HLEN);
+		dev_queue_xmit(skb);
+		trace_printk("%s: called from %s successfully\n", __func__,
+			     func);
+		return 0;
+	} else {
+		if (mape_toggle) {
+			/* Add ipv6 header mape for lan/wlan -->wan */
+			dev = get_wandev_from_index(index);
+			if (dev) {
+				if (!mape_add_ipv6_hdr(skb, mape_l2w_v6h)) {
+					skb_set_network_header(skb, 0);
+					skb_push(skb, ETH_HLEN);
+					skb_set_mac_header(skb, 0);
+					skb->dev = dev;
+					dev_queue_xmit(skb);
+					return 0;
+				}
+				trace_printk("%s: called from %s fail[MapE]\n", __func__,
+					     func);
+				return -1;
+			}
+		}
+	}
+	/*if external devices is down, invalidate related ppe entry*/
+	if (entry_hnat_is_bound(entry)) {
+		entry->bfib1.state = INVALID;
+		if (IS_IPV4_GRP(entry))
+			entry->ipv4_hnapt.act_dp = 0;
+		else
+			entry->ipv6_5t_route.act_dp = 0;
+
+		/* clear HWNAT cache */
+		hnat_cache_ebl(1);
+	}
+	trace_printk("%s: called from %s fail, index=%x\n", __func__,
+		     func, index);
+	return -1;
+}
+
+static void pre_routing_print(struct sk_buff *skb, const struct net_device *in,
+			      const struct net_device *out, const char *func)
+{
+	trace_printk(
+		"[%s]: %s(iif=0x%x CB2=0x%x)-->%s (ppe_hash=0x%x) sport=0x%x reason=0x%x alg=0x%x from %s\n",
+		__func__, in->name, skb_hnat_iface(skb),
+		HNAT_SKB_CB2(skb)->magic, out->name, skb_hnat_entry(skb),
+		skb_hnat_sport(skb), skb_hnat_reason(skb), skb_hnat_alg(skb),
+		func);
+}
+
+static void post_routing_print(struct sk_buff *skb, const struct net_device *in,
+			       const struct net_device *out, const char *func)
+{
+	trace_printk(
+		"[%s]: %s(iif=0x%x, CB2=0x%x)-->%s (ppe_hash=0x%x) sport=0x%x reason=0x%x alg=0x%x from %s\n",
+		__func__, in->name, skb_hnat_iface(skb),
+		HNAT_SKB_CB2(skb)->magic, out->name, skb_hnat_entry(skb),
+		skb_hnat_sport(skb), skb_hnat_reason(skb), skb_hnat_alg(skb),
+		func);
+}
+
+static inline void hnat_set_iif(const struct nf_hook_state *state,
+				struct sk_buff *skb, int val)
+{
+	if (IS_WHNAT(state->in) && FROM_WED(skb)) {
+		return;
+	} else if (IS_LAN(state->in)) {
+		skb_hnat_iface(skb) = FOE_MAGIC_GE_LAN;
+	} else if (IS_PPD(state->in)) {
+		skb_hnat_iface(skb) = FOE_MAGIC_GE_PPD;
+	} else if (IS_EXT(state->in)) {
+		skb_hnat_iface(skb) = FOE_MAGIC_EXT;
+	} else if (IS_WAN(state->in)) {
+		skb_hnat_iface(skb) = FOE_MAGIC_GE_WAN;
+	} else if (!IS_BR(state->in)) {
+		if (state->in->netdev_ops->ndo_flow_offload_check) {
+			skb_hnat_iface(skb) = FOE_MAGIC_GE_VIRTUAL;
+		} else {
+			skb_hnat_iface(skb) = FOE_INVALID;
+
+			if (is_magic_tag_valid(skb) &&
+			    IS_SPACE_AVAILABLE_HEAD(skb))
+				memset(skb_hnat_info(skb), 0, FOE_INFO_LEN);
+		}
+	}
+}
+
+static inline void hnat_set_alg(const struct nf_hook_state *state,
+				struct sk_buff *skb, int val)
+{
+	skb_hnat_alg(skb) = val;
+}
+
+static inline void hnat_set_head_frags(const struct nf_hook_state *state,
+				       struct sk_buff *head_skb, int val,
+				       void (*fn)(const struct nf_hook_state *state,
+						  struct sk_buff *skb, int val))
+{
+	struct sk_buff *segs = skb_shinfo(head_skb)->frag_list;
+
+	fn(state, head_skb, val);
+	while (segs) {
+		fn(state, segs, val);
+		segs = segs->next;
+	}
+}
+
+unsigned int do_hnat_mape_w2l_fast(struct sk_buff *skb, const struct net_device *in,
+				   const char *func)
+{
+	struct ipv6hdr *ip6h = ipv6_hdr(skb);
+	struct iphdr _iphdr;
+	struct iphdr *iph;
+	struct ethhdr *eth;
+
+	/* WAN -> LAN/WLAN MapE. */
+	if (mape_toggle && (ip6h->nexthdr == NEXTHDR_IPIP)) {
+		iph = skb_header_pointer(skb, IPV6_HDR_LEN, sizeof(_iphdr), &_iphdr);
+		if (unlikely(!iph))
+			return -1;
+
+		switch (iph->protocol) {
+		case IPPROTO_UDP:
+		case IPPROTO_TCP:
+			break;
+		default:
+			return -1;
+		}
+		mape_w2l_v6h = *ip6h;
+
+		/* Remove ipv6 header. */
+		memcpy(skb->data + IPV6_HDR_LEN - ETH_HLEN,
+		       skb->data - ETH_HLEN, ETH_HLEN);
+		skb_pull(skb, IPV6_HDR_LEN - ETH_HLEN);
+		skb_set_mac_header(skb, 0);
+		skb_set_network_header(skb, ETH_HLEN);
+		skb_set_transport_header(skb, ETH_HLEN + sizeof(_iphdr));
+
+		eth = eth_hdr(skb);
+		eth->h_proto = htons(ETH_P_IP);
+		set_to_ppe(skb);
+
+		skb->vlan_proto = htons(ETH_P_8021Q);
+		skb->vlan_tci =
+		(VLAN_CFI_MASK | (in->ifindex & VLAN_VID_MASK));
+
+		if (!hnat_priv->g_ppdev)
+			hnat_priv->g_ppdev = dev_get_by_name(&init_net, hnat_priv->ppd);
+
+		skb->dev = hnat_priv->g_ppdev;
+		skb->protocol = htons(ETH_P_IP);
+
+		dev_queue_xmit(skb);
+
+		return 0;
+	}
+	return -1;
+}
+
+static unsigned int is_ppe_support_type(struct sk_buff *skb)
+{
+	struct ethhdr *eth = NULL;
+	struct iphdr *iph = NULL;
+	struct ipv6hdr *ip6h = NULL;
+	struct iphdr _iphdr;
+
+	eth = eth_hdr(skb);
+	if (!is_magic_tag_valid(skb) || !IS_SPACE_AVAILABLE_HEAD(skb) ||
+	    is_broadcast_ether_addr(eth->h_dest))
+		return 0;
+
+	switch (ntohs(skb->protocol)) {
+	case ETH_P_IP:
+		iph = ip_hdr(skb);
+
+		/* do not accelerate non tcp/udp traffic */
+		if ((iph->protocol == IPPROTO_TCP) ||
+		    (iph->protocol == IPPROTO_UDP) ||
+		    (iph->protocol == IPPROTO_IPV6)) {
+			return 1;
+		}
+
+		break;
+	case ETH_P_IPV6:
+		ip6h = ipv6_hdr(skb);
+
+		if ((ip6h->nexthdr == NEXTHDR_TCP) ||
+		    (ip6h->nexthdr == NEXTHDR_UDP)) {
+			return 1;
+		} else if (ip6h->nexthdr == NEXTHDR_IPIP) {
+			iph = skb_header_pointer(skb, IPV6_HDR_LEN,
+						 sizeof(_iphdr), &_iphdr);
+			if (unlikely(!iph))
+				return 0;
+
+			if ((iph->protocol == IPPROTO_TCP) ||
+			    (iph->protocol == IPPROTO_UDP)) {
+				return 1;
+			}
+
+		}
+
+		break;
+	case ETH_P_8021Q:
+		return 1;
+	}
+
+	return 0;
+}
+
+static unsigned int
+mtk_hnat_ipv6_nf_pre_routing(void *priv, struct sk_buff *skb,
+			     const struct nf_hook_state *state)
+{
+	if (!is_ppe_support_type(skb)) {
+		hnat_set_head_frags(state, skb, 1, hnat_set_alg);
+		return NF_ACCEPT;
+	}
+
+	hnat_set_head_frags(state, skb, -1, hnat_set_iif);
+
+	pre_routing_print(skb, state->in, state->out, __func__);
+
+	/* packets from external devices -> xxx ,step 1 , learning stage & bound stage*/
+	if (do_ext2ge_fast_try(state->in, skb)) {
+		if (!do_hnat_ext_to_ge(skb, state->in, __func__))
+			return NF_STOLEN;
+		if (!skb)
+			goto drop;
+		return NF_ACCEPT;
+	}
+
+	/* packets form ge -> external device
+	 * For standalone wan interface
+	 */
+	if (do_ge2ext_fast(state->in, skb)) {
+		if (!do_hnat_ge_to_ext(skb, __func__))
+			return NF_STOLEN;
+		goto drop;
+	}
+
+	/* MapE need remove ipv6 header and pingpong. */
+	if (do_mape_w2l_fast(state->in, skb)) {
+		if (!do_hnat_mape_w2l_fast(skb, state->in, __func__))
+			return NF_STOLEN;
+		else
+			return NF_ACCEPT;
+	}
+
+	if (is_from_mape(skb))
+		clr_from_extge(skb);
+
+	return NF_ACCEPT;
+drop:
+	printk_ratelimited(KERN_WARNING
+				"%s:drop (in_dev=%s, iif=0x%x, CB2=0x%x, ppe_hash=0x%x, sport=0x%x, reason=0x%x, alg=0x%x)\n",
+				__func__, state->in->name, skb_hnat_iface(skb),
+				HNAT_SKB_CB2(skb)->magic, skb_hnat_entry(skb),
+				skb_hnat_sport(skb), skb_hnat_reason(skb),
+				skb_hnat_alg(skb));
+
+	return NF_DROP;
+}
+
+static unsigned int
+mtk_hnat_ipv4_nf_pre_routing(void *priv, struct sk_buff *skb,
+			     const struct nf_hook_state *state)
+{
+	if (!is_ppe_support_type(skb)) {
+		hnat_set_head_frags(state, skb, 1, hnat_set_alg);
+		return NF_ACCEPT;
+	}
+
+	hnat_set_head_frags(state, skb, -1, hnat_set_iif);
+
+	pre_routing_print(skb, state->in, state->out, __func__);
+
+	/* packets from external devices -> xxx ,step 1 , learning stage & bound stage*/
+	if (do_ext2ge_fast_try(state->in, skb)) {
+		if (!do_hnat_ext_to_ge(skb, state->in, __func__))
+			return NF_STOLEN;
+		if (!skb)
+			goto drop;
+		return NF_ACCEPT;
+	}
+
+	/* packets form ge -> external device
+	 * For standalone wan interface
+	 */
+	if (do_ge2ext_fast(state->in, skb)) {
+		if (!do_hnat_ge_to_ext(skb, __func__))
+			return NF_STOLEN;
+		goto drop;
+	}
+
+	return NF_ACCEPT;
+drop:
+	printk_ratelimited(KERN_WARNING
+				"%s:drop (in_dev=%s, iif=0x%x, CB2=0x%x, ppe_hash=0x%x, sport=0x%x, reason=0x%x, alg=0x%x)\n",
+				__func__, state->in->name, skb_hnat_iface(skb),
+				HNAT_SKB_CB2(skb)->magic, skb_hnat_entry(skb),
+				skb_hnat_sport(skb), skb_hnat_reason(skb),
+				skb_hnat_alg(skb));
+
+	return NF_DROP;
+}
+
+static unsigned int
+mtk_hnat_br_nf_local_in(void *priv, struct sk_buff *skb,
+			const struct nf_hook_state *state)
+{
+	struct vlan_ethhdr *veth;
+
+	if (IS_HQOS_MODE && hnat_priv->data->whnat) {
+		veth = (struct vlan_ethhdr *)skb_mac_header(skb);
+
+		if (eth_hdr(skb)->h_proto == HQOS_MAGIC_TAG) {
+			skb_hnat_entry(skb) = ntohs(veth->h_vlan_TCI) & 0x3fff;
+			skb_hnat_reason(skb) = HIT_BIND_FORCE_TO_CPU;
+		}
+	}
+
+	if (!HAS_HQOS_MAGIC_TAG(skb) && !is_ppe_support_type(skb)) {
+		hnat_set_head_frags(state, skb, 1, hnat_set_alg);
+		return NF_ACCEPT;
+	}
+
+	hnat_set_head_frags(state, skb, -1, hnat_set_iif);
+
+	pre_routing_print(skb, state->in, state->out, __func__);
+
+	if (unlikely(debug_level >= 7)) {
+		hnat_cpu_reason_cnt(skb);
+		if (skb_hnat_reason(skb) == dbg_cpu_reason)
+			foe_dump_pkt(skb);
+	}
+
+	/* packets from external devices -> xxx ,step 1 , learning stage & bound stage*/
+	if ((skb_hnat_iface(skb) == FOE_MAGIC_EXT) && !is_from_extge(skb) &&
+	    !is_multicast_ether_addr(eth_hdr(skb)->h_dest)) {
+		if (!hnat_priv->g_ppdev)
+			hnat_priv->g_ppdev = dev_get_by_name(&init_net, hnat_priv->ppd);
+
+		if (!do_hnat_ext_to_ge(skb, state->in, __func__))
+			return NF_STOLEN;
+		if (!skb)
+			goto drop;
+		return NF_ACCEPT;
+	}
+
+	if (hnat_priv->data->whnat) {
+		if (skb_hnat_iface(skb) == FOE_MAGIC_EXT)
+			clr_from_extge(skb);
+
+		/* packets from external devices -> xxx ,step 2, learning stage */
+		if (do_ext2ge_fast_learn(state->in, skb) && (!qos_toggle ||
+		    (qos_toggle && eth_hdr(skb)->h_proto != HQOS_MAGIC_TAG))) {
+			if (!do_hnat_ext_to_ge2(skb, __func__))
+				return NF_STOLEN;
+			goto drop;
+		}
+
+		/* packets form ge -> external device */
+		if (do_ge2ext_fast(state->in, skb)) {
+			if (!do_hnat_ge_to_ext(skb, __func__))
+				return NF_STOLEN;
+			goto drop;
+		}
+	}
+
+	/* MapE need remove ipv6 header and pingpong. (bridge mode) */
+	if (do_mape_w2l_fast(state->in, skb)) {
+		if (!do_hnat_mape_w2l_fast(skb, state->in, __func__))
+			return NF_STOLEN;
+		else
+			return NF_ACCEPT;
+	}
+
+	return NF_ACCEPT;
+drop:
+	printk_ratelimited(KERN_WARNING
+				"%s:drop (in_dev=%s, iif=0x%x, CB2=0x%x, ppe_hash=0x%x, sport=0x%x, reason=0x%x, alg=0x%x)\n",
+				__func__, state->in->name, skb_hnat_iface(skb),
+				HNAT_SKB_CB2(skb)->magic, skb_hnat_entry(skb),
+				skb_hnat_sport(skb), skb_hnat_reason(skb),
+				skb_hnat_alg(skb));
+
+	return NF_DROP;
+}
+
+static unsigned int hnat_ipv6_get_nexthop(struct sk_buff *skb,
+					  const struct net_device *out,
+					  struct flow_offload_hw_path *hw_path)
+{
+	const struct in6_addr *ipv6_nexthop;
+	struct neighbour *neigh = NULL;
+	struct dst_entry *dst = skb_dst(skb);
+	struct ethhdr *eth;
+
+	if (hw_path->flags & FLOW_OFFLOAD_PATH_PPPOE) {
+		memcpy(eth_hdr(skb)->h_source, hw_path->eth_src, ETH_ALEN);
+		memcpy(eth_hdr(skb)->h_dest, hw_path->eth_dest, ETH_ALEN);
+		return 0;
+	}
+
+	rcu_read_lock_bh();
+	ipv6_nexthop =
+		rt6_nexthop((struct rt6_info *)dst, &ipv6_hdr(skb)->daddr);
+	neigh = __ipv6_neigh_lookup_noref(dst->dev, ipv6_nexthop);
+	if (unlikely(!neigh)) {
+		dev_notice(hnat_priv->dev, "%s:No neigh (daddr=%pI6)\n", __func__,
+			   &ipv6_hdr(skb)->daddr);
+		rcu_read_unlock_bh();
+		return -1;
+	}
+
+	/* why do we get all zero ethernet address ? */
+	if (!is_valid_ether_addr(neigh->ha)) {
+		rcu_read_unlock_bh();
+		return -1;
+	}
+
+	if (ipv6_hdr(skb)->nexthdr == NEXTHDR_IPIP) {
+		/*copy ether type for DS-Lite and MapE */
+		eth = (struct ethhdr *)(skb->data - ETH_HLEN);
+		eth->h_proto = skb->protocol;
+	} else {
+		eth = eth_hdr(skb);
+	}
+
+	ether_addr_copy(eth->h_dest, neigh->ha);
+	ether_addr_copy(eth->h_source, out->dev_addr);
+
+	rcu_read_unlock_bh();
+
+	return 0;
+}
+
+static unsigned int hnat_ipv4_get_nexthop(struct sk_buff *skb,
+					  const struct net_device *out,
+					  struct flow_offload_hw_path *hw_path)
+{
+	u32 nexthop;
+	struct neighbour *neigh;
+	struct dst_entry *dst = skb_dst(skb);
+	struct rtable *rt = (struct rtable *)dst;
+	struct net_device *dev = (__force struct net_device *)out;
+
+	if (hw_path->flags & FLOW_OFFLOAD_PATH_PPPOE) {
+		memcpy(eth_hdr(skb)->h_source, hw_path->eth_src, ETH_ALEN);
+		memcpy(eth_hdr(skb)->h_dest, hw_path->eth_dest, ETH_ALEN);
+		return 0;
+	}
+
+	rcu_read_lock_bh();
+	nexthop = (__force u32)rt_nexthop(rt, ip_hdr(skb)->daddr);
+	neigh = __ipv4_neigh_lookup_noref(dev, nexthop);
+	if (unlikely(!neigh)) {
+		dev_notice(hnat_priv->dev, "%s:No neigh (daddr=%pI4)\n", __func__,
+			   &ip_hdr(skb)->daddr);
+		rcu_read_unlock_bh();
+		return -1;
+	}
+
+	/* why do we get all zero ethernet address ? */
+	if (!is_valid_ether_addr(neigh->ha)) {
+		rcu_read_unlock_bh();
+		return -1;
+	}
+
+	memcpy(eth_hdr(skb)->h_dest, neigh->ha, ETH_ALEN);
+	memcpy(eth_hdr(skb)->h_source, out->dev_addr, ETH_ALEN);
+
+	rcu_read_unlock_bh();
+
+	return 0;
+}
+
+static u16 ppe_get_chkbase(struct iphdr *iph)
+{
+	u16 org_chksum = ntohs(iph->check);
+	u16 org_tot_len = ntohs(iph->tot_len);
+	u16 org_id = ntohs(iph->id);
+	u16 chksum_tmp, tot_len_tmp, id_tmp;
+	u32 tmp = 0;
+	u16 chksum_base = 0;
+
+	chksum_tmp = ~(org_chksum);
+	tot_len_tmp = ~(org_tot_len);
+	id_tmp = ~(org_id);
+	tmp = chksum_tmp + tot_len_tmp + id_tmp;
+	tmp = ((tmp >> 16) & 0x7) + (tmp & 0xFFFF);
+	tmp = ((tmp >> 16) & 0x7) + (tmp & 0xFFFF);
+	chksum_base = tmp & 0xFFFF;
+
+	return chksum_base;
+}
+
+struct foe_entry ppe_fill_L2_info(struct ethhdr *eth, struct foe_entry entry,
+				  struct flow_offload_hw_path *hw_path)
+{
+	switch (entry.bfib1.pkt_type) {
+	case IPV4_HNAPT:
+	case IPV4_HNAT:
+		entry.ipv4_hnapt.dmac_hi = swab32(*((u32 *)eth->h_dest));
+		entry.ipv4_hnapt.dmac_lo = swab16(*((u16 *)&eth->h_dest[4]));
+		entry.ipv4_hnapt.smac_hi = swab32(*((u32 *)eth->h_source));
+		entry.ipv4_hnapt.smac_lo = swab16(*((u16 *)&eth->h_source[4]));
+		entry.ipv4_hnapt.pppoe_id = hw_path->pppoe_sid;
+		break;
+	case IPV4_DSLITE:
+	case IPV4_MAP_E:
+	case IPV6_6RD:
+	case IPV6_5T_ROUTE:
+	case IPV6_3T_ROUTE:
+		entry.ipv6_5t_route.dmac_hi = swab32(*((u32 *)eth->h_dest));
+		entry.ipv6_5t_route.dmac_lo = swab16(*((u16 *)&eth->h_dest[4]));
+		entry.ipv6_5t_route.smac_hi = swab32(*((u32 *)eth->h_source));
+		entry.ipv6_5t_route.smac_lo =
+			swab16(*((u16 *)&eth->h_source[4]));
+		entry.ipv6_5t_route.pppoe_id = hw_path->pppoe_sid;
+		break;
+	}
+	return entry;
+}
+
+struct foe_entry ppe_fill_info_blk(struct ethhdr *eth, struct foe_entry entry,
+				   struct flow_offload_hw_path *hw_path)
+{
+	entry.bfib1.psn = (hw_path->flags & FLOW_OFFLOAD_PATH_PPPOE) ? 1 : 0;
+	entry.bfib1.vlan_layer += (hw_path->flags & FLOW_OFFLOAD_PATH_VLAN) ? 1 : 0;
+	entry.bfib1.vpm = (entry.bfib1.vlan_layer) ? 1 : 0;
+	entry.bfib1.ttl = 1;
+	entry.bfib1.cah = 1;
+	entry.bfib1.ka = 1;
+	entry.bfib1.time_stamp = (hnat_priv->data->version == MTK_HNAT_V4) ?
+		readl(hnat_priv->fe_base + 0x0010) & (0xFF) :
+		readl(hnat_priv->fe_base + 0x0010) & (0x7FFF);
+
+	switch (entry.bfib1.pkt_type) {
+	case IPV4_HNAPT:
+	case IPV4_HNAT:
+		if (hnat_priv->data->mcast &&
+		    is_multicast_ether_addr(&eth->h_dest[0])) {
+			entry.ipv4_hnapt.iblk2.mcast = 1;
+			if (hnat_priv->data->version == MTK_HNAT_V3) {
+				entry.bfib1.sta = 1;
+				entry.ipv4_hnapt.m_timestamp = foe_timestamp(hnat_priv);
+			}
+		} else {
+			entry.ipv4_hnapt.iblk2.mcast = 0;
+		}
+
+		entry.ipv4_hnapt.iblk2.port_ag =
+			(hnat_priv->data->version == MTK_HNAT_V4) ? 0xf : 0x3f;
+		break;
+	case IPV4_DSLITE:
+	case IPV4_MAP_E:
+	case IPV6_6RD:
+	case IPV6_5T_ROUTE:
+	case IPV6_3T_ROUTE:
+		if (hnat_priv->data->mcast &&
+		    is_multicast_ether_addr(&eth->h_dest[0])) {
+			entry.ipv6_5t_route.iblk2.mcast = 1;
+			if (hnat_priv->data->version == MTK_HNAT_V3) {
+				entry.bfib1.sta = 1;
+				entry.ipv4_hnapt.m_timestamp = foe_timestamp(hnat_priv);
+			}
+		} else {
+			entry.ipv6_5t_route.iblk2.mcast = 0;
+		}
+
+		entry.ipv6_5t_route.iblk2.port_ag =
+			(hnat_priv->data->version == MTK_HNAT_V4) ? 0xf : 0x3f;
+		break;
+	}
+	return entry;
+}
+
+static void ppe_fill_flow_lbl(struct foe_entry *entry, struct ipv6hdr *ip6h)
+{
+	entry->ipv4_dslite.flow_lbl[0] = ip6h->flow_lbl[2];
+	entry->ipv4_dslite.flow_lbl[1] = ip6h->flow_lbl[1];
+	entry->ipv4_dslite.flow_lbl[2] = ip6h->flow_lbl[0];
+}
+
+static unsigned int skb_to_hnat_info(struct sk_buff *skb,
+				     const struct net_device *dev,
+				     struct foe_entry *foe,
+				     struct flow_offload_hw_path *hw_path)
+{
+	struct foe_entry entry = { 0 };
+	int whnat = IS_WHNAT(dev);
+	struct ethhdr *eth;
+	struct iphdr *iph;
+	struct ipv6hdr *ip6h;
+	struct tcpudphdr _ports;
+	const struct tcpudphdr *pptr;
+	u32 gmac = NR_DISCARD;
+	int udp = 0;
+	u32 qid = 0;
+	u32 port_id = 0;
+	int mape = 0;
+
+	if (ipv6_hdr(skb)->nexthdr == NEXTHDR_IPIP)
+		/* point to ethernet header for DS-Lite and MapE */
+		eth = (struct ethhdr *)(skb->data - ETH_HLEN);
+	else
+		eth = eth_hdr(skb);
+
+	/*do not bind multicast if PPE mcast not enable*/
+	if (!hnat_priv->data->mcast && is_multicast_ether_addr(eth->h_dest))
+		return 0;
+
+	entry.bfib1.pkt_type = foe->udib1.pkt_type; /* Get packte type state*/
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+	entry.bfib1.sp = foe->udib1.sp;
+#endif
+
+	switch (ntohs(eth->h_proto)) {
+	case ETH_P_IP:
+		iph = ip_hdr(skb);
+		switch (iph->protocol) {
+		case IPPROTO_UDP:
+			udp = 1;
+			/* fallthrough */
+		case IPPROTO_TCP:
+			entry.ipv4_hnapt.etype = htons(ETH_P_IP);
+
+			/* DS-Lite WAN->LAN */
+			if (entry.ipv4_hnapt.bfib1.pkt_type == IPV4_DSLITE ||
+			    entry.ipv4_hnapt.bfib1.pkt_type == IPV4_MAP_E) {
+				entry.ipv4_dslite.sip = foe->ipv4_dslite.sip;
+				entry.ipv4_dslite.dip = foe->ipv4_dslite.dip;
+				entry.ipv4_dslite.sport =
+					foe->ipv4_dslite.sport;
+				entry.ipv4_dslite.dport =
+					foe->ipv4_dslite.dport;
+
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+				if (entry.bfib1.pkt_type == IPV4_MAP_E) {
+					pptr = skb_header_pointer(skb,
+								  iph->ihl * 4,
+								  sizeof(_ports),
+								  &_ports);
+					if (unlikely(!pptr))
+						return -1;
+
+					entry.ipv4_dslite.new_sip =
+							ntohl(iph->saddr);
+					entry.ipv4_dslite.new_dip =
+							ntohl(iph->daddr);
+					entry.ipv4_dslite.new_sport =
+							ntohs(pptr->src);
+					entry.ipv4_dslite.new_dport =
+							ntohs(pptr->dst);
+				}
+#endif
+
+				entry.ipv4_dslite.tunnel_sipv6_0 =
+					foe->ipv4_dslite.tunnel_sipv6_0;
+				entry.ipv4_dslite.tunnel_sipv6_1 =
+					foe->ipv4_dslite.tunnel_sipv6_1;
+				entry.ipv4_dslite.tunnel_sipv6_2 =
+					foe->ipv4_dslite.tunnel_sipv6_2;
+				entry.ipv4_dslite.tunnel_sipv6_3 =
+					foe->ipv4_dslite.tunnel_sipv6_3;
+
+				entry.ipv4_dslite.tunnel_dipv6_0 =
+					foe->ipv4_dslite.tunnel_dipv6_0;
+				entry.ipv4_dslite.tunnel_dipv6_1 =
+					foe->ipv4_dslite.tunnel_dipv6_1;
+				entry.ipv4_dslite.tunnel_dipv6_2 =
+					foe->ipv4_dslite.tunnel_dipv6_2;
+				entry.ipv4_dslite.tunnel_dipv6_3 =
+					foe->ipv4_dslite.tunnel_dipv6_3;
+
+				entry.ipv4_dslite.bfib1.rmt = 1;
+				entry.ipv4_dslite.iblk2.dscp = iph->tos;
+				entry.ipv4_dslite.vlan1 = hw_path->vlan_id;
+				if (hnat_priv->data->per_flow_accounting)
+					entry.ipv4_dslite.iblk2.mibf = 1;
+
+			} else {
+				entry.ipv4_hnapt.iblk2.dscp = iph->tos;
+				if (hnat_priv->data->per_flow_accounting)
+					entry.ipv4_hnapt.iblk2.mibf = 1;
+
+				entry.ipv4_hnapt.vlan1 = hw_path->vlan_id;
+
+				if (skb->vlan_tci && FROM_GE_WAN(skb) && IS_LAN(dev)) {
+					entry.bfib1.vlan_layer += 1;
+
+					if (entry.ipv4_hnapt.vlan1)
+						entry.ipv4_hnapt.vlan2 = (skb->vlan_tci & VLAN_VID_MASK);
+					else
+						entry.ipv4_hnapt.vlan1 = (skb->vlan_tci & VLAN_VID_MASK);
+				}
+
+				entry.ipv4_hnapt.sip = foe->ipv4_hnapt.sip;
+				entry.ipv4_hnapt.dip = foe->ipv4_hnapt.dip;
+				entry.ipv4_hnapt.sport = foe->ipv4_hnapt.sport;
+				entry.ipv4_hnapt.dport = foe->ipv4_hnapt.dport;
+
+				entry.ipv4_hnapt.new_sip = ntohl(iph->saddr);
+				entry.ipv4_hnapt.new_dip = ntohl(iph->daddr);
+			}
+
+			entry.ipv4_hnapt.bfib1.udp = udp;
+			if (IS_IPV4_HNAPT(foe)) {
+				pptr = skb_header_pointer(skb, iph->ihl * 4,
+							  sizeof(_ports),
+							  &_ports);
+				if (unlikely(!pptr))
+					return -1;
+
+				entry.ipv4_hnapt.new_sport = ntohs(pptr->src);
+				entry.ipv4_hnapt.new_dport = ntohs(pptr->dst);
+			}
+
+			break;
+
+		default:
+			return -1;
+		}
+		trace_printk(
+			"[%s]skb->head=%p, skb->data=%p,ip_hdr=%p, skb->len=%d, skb->data_len=%d\n",
+			__func__, skb->head, skb->data, iph, skb->len,
+			skb->data_len);
+		break;
+
+	case ETH_P_IPV6:
+		ip6h = ipv6_hdr(skb);
+		switch (ip6h->nexthdr) {
+		case NEXTHDR_UDP:
+			udp = 1;
+			/* fallthrough */
+		case NEXTHDR_TCP: /* IPv6-5T or IPv6-3T */
+			entry.ipv6_5t_route.etype = htons(ETH_P_IPV6);
+
+			entry.ipv6_5t_route.vlan1 = hw_path->vlan_id;
+
+			if (skb->vlan_tci && FROM_GE_WAN(skb) && IS_LAN(dev)) {
+				entry.bfib1.vlan_layer += 1;
+
+				if (entry.ipv6_5t_route.vlan1)
+					entry.ipv6_5t_route.vlan2 = (skb->vlan_tci & VLAN_VID_MASK);
+				else
+					entry.ipv6_5t_route.vlan1 = (skb->vlan_tci & VLAN_VID_MASK);
+			}
+
+			if (hnat_priv->data->per_flow_accounting)
+				entry.ipv6_5t_route.iblk2.mibf = 1;
+			entry.ipv6_5t_route.bfib1.udp = udp;
+
+			if (IS_IPV6_6RD(foe)) {
+				entry.ipv6_5t_route.bfib1.rmt = 1;
+				entry.ipv6_6rd.tunnel_sipv4 =
+					foe->ipv6_6rd.tunnel_sipv4;
+				entry.ipv6_6rd.tunnel_dipv4 =
+					foe->ipv6_6rd.tunnel_dipv4;
+			}
+
+			entry.ipv6_3t_route.ipv6_sip0 =
+				foe->ipv6_3t_route.ipv6_sip0;
+			entry.ipv6_3t_route.ipv6_sip1 =
+				foe->ipv6_3t_route.ipv6_sip1;
+			entry.ipv6_3t_route.ipv6_sip2 =
+				foe->ipv6_3t_route.ipv6_sip2;
+			entry.ipv6_3t_route.ipv6_sip3 =
+				foe->ipv6_3t_route.ipv6_sip3;
+
+			entry.ipv6_3t_route.ipv6_dip0 =
+				foe->ipv6_3t_route.ipv6_dip0;
+			entry.ipv6_3t_route.ipv6_dip1 =
+				foe->ipv6_3t_route.ipv6_dip1;
+			entry.ipv6_3t_route.ipv6_dip2 =
+				foe->ipv6_3t_route.ipv6_dip2;
+			entry.ipv6_3t_route.ipv6_dip3 =
+				foe->ipv6_3t_route.ipv6_dip3;
+
+			if (IS_IPV6_3T_ROUTE(foe)) {
+				entry.ipv6_3t_route.prot =
+					foe->ipv6_3t_route.prot;
+				entry.ipv6_3t_route.hph =
+					foe->ipv6_3t_route.hph;
+			}
+
+			if (IS_IPV6_5T_ROUTE(foe) || IS_IPV6_6RD(foe)) {
+				entry.ipv6_5t_route.sport =
+					foe->ipv6_5t_route.sport;
+				entry.ipv6_5t_route.dport =
+					foe->ipv6_5t_route.dport;
+			}
+			entry.ipv6_5t_route.iblk2.dscp =
+				(ip6h->priority << 4 |
+				 (ip6h->flow_lbl[0] >> 4));
+			break;
+
+		case NEXTHDR_IPIP:
+			if ((!mape_toggle &&
+			     entry.bfib1.pkt_type == IPV4_DSLITE) ||
+			    (mape_toggle &&
+			     entry.bfib1.pkt_type == IPV4_MAP_E)) {
+				/* DS-Lite LAN->WAN */
+				entry.ipv4_dslite.bfib1.udp =
+					foe->ipv4_dslite.bfib1.udp;
+				entry.ipv4_dslite.sip = foe->ipv4_dslite.sip;
+				entry.ipv4_dslite.dip = foe->ipv4_dslite.dip;
+				entry.ipv4_dslite.sport =
+					foe->ipv4_dslite.sport;
+				entry.ipv4_dslite.dport =
+					foe->ipv4_dslite.dport;
+
+				entry.ipv4_dslite.tunnel_sipv6_0 =
+					ntohl(ip6h->saddr.s6_addr32[0]);
+				entry.ipv4_dslite.tunnel_sipv6_1 =
+					ntohl(ip6h->saddr.s6_addr32[1]);
+				entry.ipv4_dslite.tunnel_sipv6_2 =
+					ntohl(ip6h->saddr.s6_addr32[2]);
+				entry.ipv4_dslite.tunnel_sipv6_3 =
+					ntohl(ip6h->saddr.s6_addr32[3]);
+
+				entry.ipv4_dslite.tunnel_dipv6_0 =
+					ntohl(ip6h->daddr.s6_addr32[0]);
+				entry.ipv4_dslite.tunnel_dipv6_1 =
+					ntohl(ip6h->daddr.s6_addr32[1]);
+				entry.ipv4_dslite.tunnel_dipv6_2 =
+					ntohl(ip6h->daddr.s6_addr32[2]);
+				entry.ipv4_dslite.tunnel_dipv6_3 =
+					ntohl(ip6h->daddr.s6_addr32[3]);
+
+				ppe_fill_flow_lbl(&entry, ip6h);
+
+				entry.ipv4_dslite.priority = ip6h->priority;
+				entry.ipv4_dslite.hop_limit = ip6h->hop_limit;
+				entry.ipv4_dslite.vlan1 = hw_path->vlan_id;
+				if (hnat_priv->data->per_flow_accounting)
+					entry.ipv4_dslite.iblk2.mibf = 1;
+			} else if (mape_toggle &&
+				   entry.bfib1.pkt_type == IPV4_HNAPT) {
+				/* MapE LAN -> WAN */
+				mape = 1;
+				entry.ipv4_hnapt.iblk2.dscp =
+					foe->ipv4_hnapt.iblk2.dscp;
+				if (hnat_priv->data->per_flow_accounting)
+					entry.ipv4_hnapt.iblk2.mibf = 1;
+
+				if (IS_GMAC1_MODE)
+					entry.ipv4_hnapt.vlan1 = 1;
+				else
+					entry.ipv4_hnapt.vlan1 = hw_path->vlan_id;
+
+				entry.ipv4_hnapt.sip = foe->ipv4_hnapt.sip;
+				entry.ipv4_hnapt.dip = foe->ipv4_hnapt.dip;
+				entry.ipv4_hnapt.sport = foe->ipv4_hnapt.sport;
+				entry.ipv4_hnapt.dport = foe->ipv4_hnapt.dport;
+
+				entry.ipv4_hnapt.new_sip =
+					foe->ipv4_hnapt.new_sip;
+				entry.ipv4_hnapt.new_dip =
+					foe->ipv4_hnapt.new_dip;
+				entry.ipv4_hnapt.etype = htons(ETH_P_IP);
+
+				if (IS_HQOS_MODE) {
+					entry.ipv4_hnapt.iblk2.qid =
+						(hnat_priv->data->version == MTK_HNAT_V4) ?
+						 skb->mark & 0x7f : skb->mark & 0xf;
+					entry.ipv4_hnapt.iblk2.fqos = 1;
+				}
+
+				entry.ipv4_hnapt.bfib1.udp =
+					foe->ipv4_hnapt.bfib1.udp;
+
+				entry.ipv4_hnapt.new_sport =
+					foe->ipv4_hnapt.new_sport;
+				entry.ipv4_hnapt.new_dport =
+					foe->ipv4_hnapt.new_dport;
+				mape_l2w_v6h = *ip6h;
+			}
+			break;
+
+		default:
+			return -1;
+		}
+
+		trace_printk(
+			"[%s]skb->head=%p, skb->data=%p,ipv6_hdr=%p, skb->len=%d, skb->data_len=%d\n",
+			__func__, skb->head, skb->data, ip6h, skb->len,
+			skb->data_len);
+		break;
+
+	default:
+		iph = ip_hdr(skb);
+		switch (entry.bfib1.pkt_type) {
+		case IPV6_6RD: /* 6RD LAN->WAN */
+			entry.ipv6_6rd.ipv6_sip0 = foe->ipv6_6rd.ipv6_sip0;
+			entry.ipv6_6rd.ipv6_sip1 = foe->ipv6_6rd.ipv6_sip1;
+			entry.ipv6_6rd.ipv6_sip2 = foe->ipv6_6rd.ipv6_sip2;
+			entry.ipv6_6rd.ipv6_sip3 = foe->ipv6_6rd.ipv6_sip3;
+
+			entry.ipv6_6rd.ipv6_dip0 = foe->ipv6_6rd.ipv6_dip0;
+			entry.ipv6_6rd.ipv6_dip1 = foe->ipv6_6rd.ipv6_dip1;
+			entry.ipv6_6rd.ipv6_dip2 = foe->ipv6_6rd.ipv6_dip2;
+			entry.ipv6_6rd.ipv6_dip3 = foe->ipv6_6rd.ipv6_dip3;
+
+			entry.ipv6_6rd.sport = foe->ipv6_6rd.sport;
+			entry.ipv6_6rd.dport = foe->ipv6_6rd.dport;
+			entry.ipv6_6rd.tunnel_sipv4 = ntohl(iph->saddr);
+			entry.ipv6_6rd.tunnel_dipv4 = ntohl(iph->daddr);
+			entry.ipv6_6rd.hdr_chksum = ppe_get_chkbase(iph);
+			entry.ipv6_6rd.flag = (ntohs(iph->frag_off) >> 13);
+			entry.ipv6_6rd.ttl = iph->ttl;
+			entry.ipv6_6rd.dscp = iph->tos;
+			entry.ipv6_6rd.per_flow_6rd_id = 1;
+			entry.ipv6_6rd.vlan1 = hw_path->vlan_id;
+			if (hnat_priv->data->per_flow_accounting)
+				entry.ipv6_6rd.iblk2.mibf = 1;
+			break;
+
+		default:
+			return -1;
+		}
+	}
+
+	/* Fill Layer2 Info.*/
+	entry = ppe_fill_L2_info(eth, entry, hw_path);
+
+	/* Fill Info Blk*/
+	entry = ppe_fill_info_blk(eth, entry, hw_path);
+
+	if (IS_LAN(dev)) {
+		if (IS_DSA_LAN(dev))
+			port_id = hnat_dsa_fill_stag(dev, &entry, hw_path,
+						     ntohs(eth->h_proto),
+						     mape);
+
+		if (IS_BOND_MODE)
+			gmac = ((skb_hnat_entry(skb) >> 1) % hnat_priv->gmac_num) ?
+				 NR_GMAC2_PORT : NR_GMAC1_PORT;
+		else
+			gmac = NR_GMAC1_PORT;
+	} else if (IS_WAN(dev)) {
+		if (IS_DSA_WAN(dev))
+			port_id = hnat_dsa_fill_stag(dev,&entry, hw_path,
+						     ntohs(eth->h_proto),
+						     mape);
+		if (mape_toggle && mape == 1) {
+			gmac = NR_PDMA_PORT;
+			/* Set act_dp = wan_dev */
+			entry.ipv4_hnapt.act_dp = dev->ifindex;
+		} else {
+			gmac = (IS_GMAC1_MODE) ? NR_GMAC1_PORT : NR_GMAC2_PORT;
+		}
+	} else if (IS_EXT(dev) && (FROM_GE_PPD(skb) || FROM_GE_LAN(skb) ||
+		   FROM_GE_WAN(skb) || FROM_GE_VIRTUAL(skb) || FROM_WED(skb))) {
+		if (!hnat_priv->data->whnat && IS_GMAC1_MODE) {
+			entry.bfib1.vpm = 1;
+			entry.bfib1.vlan_layer = 1;
+
+			if (FROM_GE_LAN(skb))
+				entry.ipv4_hnapt.vlan1 = 1;
+			else if (FROM_GE_WAN(skb) || FROM_GE_VIRTUAL(skb))
+				entry.ipv4_hnapt.vlan1 = 2;
+		}
+
+		trace_printk("learn of lan or wan(iif=%x) --> %s(ext)\n",
+			     skb_hnat_iface(skb), dev->name);
+		/* To CPU then stolen by pre-routing hant hook of LAN/WAN
+		 * Current setting is PDMA RX.
+		 */
+		gmac = NR_PDMA_PORT;
+		if (IS_IPV4_GRP(foe))
+			entry.ipv4_hnapt.act_dp = dev->ifindex;
+		else
+			entry.ipv6_5t_route.act_dp = dev->ifindex;
+	} else {
+		printk_ratelimited(KERN_WARNING
+					"Unknown case of dp, iif=%x --> %s\n",
+					skb_hnat_iface(skb), dev->name);
+
+		return 0;
+	}
+
+	if (IS_HQOS_MODE)
+		qid = skb->mark & (MTK_QDMA_TX_MASK);
+	else if (IS_PPPQ_MODE && (IS_DSA_LAN(dev) || IS_DSA_WAN(dev)))
+		qid = port_id & MTK_QDMA_TX_MASK;
+	else
+		qid = 0;
+
+	if (IS_IPV4_GRP(foe)) {
+		entry.ipv4_hnapt.iblk2.dp = gmac;
+		entry.ipv4_hnapt.iblk2.port_mg =
+			(hnat_priv->data->version == MTK_HNAT_V1) ? 0x3f : 0;
+
+		if (qos_toggle) {
+			if (hnat_priv->data->version == MTK_HNAT_V4) {
+				entry.ipv4_hnapt.iblk2.qid = qid & 0x7f;
+			} else {
+				/* qid[5:0]= port_mg[1:0]+ qid[3:0] */
+				entry.ipv4_hnapt.iblk2.qid = qid & 0xf;
+				if (hnat_priv->data->version != MTK_HNAT_V1)
+					entry.ipv4_hnapt.iblk2.port_mg |=
+						((qid >> 4) & 0x3);
+
+				if (((IS_EXT(dev) && (FROM_GE_LAN(skb) ||
+				      FROM_GE_WAN(skb) || FROM_GE_VIRTUAL(skb))) ||
+				      ((mape_toggle && mape == 1) && !FROM_EXT(skb))) &&
+				      (!whnat)) {
+					entry.ipv4_hnapt.etype = htons(HQOS_MAGIC_TAG);
+					entry.ipv4_hnapt.vlan1 = skb_hnat_entry(skb);
+					entry.bfib1.vlan_layer = 1;
+				}
+			}
+
+			if (FROM_EXT(skb) || skb_hnat_sport(skb) == NR_QDMA_PORT ||
+			    (IS_PPPQ_MODE && !IS_DSA_LAN(dev) && !IS_DSA_WAN(dev)))
+				entry.ipv4_hnapt.iblk2.fqos = 0;
+			else
+				entry.ipv4_hnapt.iblk2.fqos = 1;
+		} else {
+			entry.ipv4_hnapt.iblk2.fqos = 0;
+		}
+	} else {
+		entry.ipv6_5t_route.iblk2.dp = gmac;
+		entry.ipv6_5t_route.iblk2.port_mg =
+			(hnat_priv->data->version == MTK_HNAT_V1) ? 0x3f : 0;
+
+		if (qos_toggle) {
+			if (hnat_priv->data->version == MTK_HNAT_V4) {
+				entry.ipv6_5t_route.iblk2.qid = qid & 0x7f;
+			} else {
+				/* qid[5:0]= port_mg[1:0]+ qid[3:0] */
+				entry.ipv6_5t_route.iblk2.qid = qid & 0xf;
+				if (hnat_priv->data->version != MTK_HNAT_V1)
+					entry.ipv6_5t_route.iblk2.port_mg |=
+								((qid >> 4) & 0x3);
+
+				if (IS_EXT(dev) && (FROM_GE_LAN(skb) ||
+				    FROM_GE_WAN(skb) || FROM_GE_VIRTUAL(skb)) &&
+				    (!whnat)) {
+					entry.ipv6_5t_route.etype = htons(HQOS_MAGIC_TAG);
+					entry.ipv6_5t_route.vlan1 = skb_hnat_entry(skb);
+					entry.bfib1.vlan_layer = 1;
+				}
+			}
+
+			if (FROM_EXT(skb) ||
+			    (IS_PPPQ_MODE && !IS_DSA_LAN(dev) && !IS_DSA_WAN(dev)))
+				entry.ipv6_5t_route.iblk2.fqos = 0;
+			else
+				entry.ipv6_5t_route.iblk2.fqos = 1;
+		} else {
+			entry.ipv6_5t_route.iblk2.fqos = 0;
+		}
+	}
+
+	/* The INFO2.port_mg and 2nd VLAN ID fields of PPE entry are redefined
+	 * by Wi-Fi whnat engine. These data and INFO2.dp will be updated and
+	 * the entry is set to BIND state in mtk_sw_nat_hook_tx().
+	 */
+	if (!whnat)
+		entry.bfib1.state = BIND;
+
+	memcpy(foe, &entry, sizeof(entry));
+	/*reset statistic for this entry*/
+	if (hnat_priv->data->per_flow_accounting)
+		memset(&hnat_priv->acct[skb_hnat_ppe(skb)][skb_hnat_entry(skb)],
+		       0, sizeof(struct mib_entry));
+
+	wmb();
+	skb_hnat_filled(skb) = HNAT_INFO_FILLED;
+
+	return 0;
+}
+
+int mtk_sw_nat_hook_tx(struct sk_buff *skb, int gmac_no)
+{
+	struct foe_entry *entry;
+	struct ethhdr *eth;
+
+	if (skb_hnat_alg(skb) || !is_hnat_info_filled(skb) ||
+	    !is_magic_tag_valid(skb) || !IS_SPACE_AVAILABLE_HEAD(skb))
+		return NF_ACCEPT;
+
+	trace_printk(
+		"[%s]entry=%x reason=%x gmac_no=%x wdmaid=%x rxid=%x wcid=%x bssid=%x\n",
+		__func__, skb_hnat_entry(skb), skb_hnat_reason(skb), gmac_no,
+		skb_hnat_wdma_id(skb), skb_hnat_bss_id(skb),
+		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))
+		return NF_ACCEPT;
+
+	if (!skb_hnat_is_hashed(skb))
+		return NF_ACCEPT;
+
+	if (skb_hnat_entry(skb) >= hnat_priv->foe_etry_num ||
+	    skb_hnat_ppe(skb) >= CFG_PPE_NUM)
+		return NF_ACCEPT;
+
+	entry = &hnat_priv->foe_table_cpu[skb_hnat_ppe(skb)][skb_hnat_entry(skb)];
+	if (entry_hnat_is_bound(entry))
+		return NF_ACCEPT;
+
+	if (skb_hnat_reason(skb) != HIT_UNBIND_RATE_REACH)
+		return NF_ACCEPT;
+
+	eth = eth_hdr(skb);
+
+	/*not bind multicast if PPE mcast not enable*/
+	if (!hnat_priv->data->mcast) {
+		if (is_multicast_ether_addr(eth->h_dest))
+			return NF_ACCEPT;
+
+		if (IS_IPV4_GRP(entry))
+			entry->ipv4_hnapt.iblk2.mcast = 0;
+		else
+			entry->ipv6_5t_route.iblk2.mcast = 0;
+	}
+
+	/* Some mt_wifi virtual interfaces, such as apcli,
+	 * will change the smac for specail purpose.
+	 */
+	switch (entry->bfib1.pkt_type) {
+	case IPV4_HNAPT:
+	case IPV4_HNAT:
+		entry->ipv4_hnapt.smac_hi = swab32(*((u32 *)eth->h_source));
+		entry->ipv4_hnapt.smac_lo = swab16(*((u16 *)&eth->h_source[4]));
+		break;
+	case IPV4_DSLITE:
+	case IPV4_MAP_E:
+	case IPV6_6RD:
+	case IPV6_5T_ROUTE:
+	case IPV6_3T_ROUTE:
+		entry->ipv6_5t_route.smac_hi = swab32(*((u32 *)eth->h_source));
+		entry->ipv6_5t_route.smac_lo = swab16(*((u16 *)&eth->h_source[4]));
+		break;
+	}
+
+	if (skb->vlan_tci) {
+		entry->bfib1.vlan_layer += 1;
+		entry->bfib1.vpm = 1;
+		if (IS_IPV4_GRP(entry)) {
+			entry->ipv4_hnapt.etype = htons(ETH_P_8021Q);
+			if(entry->ipv4_hnapt.vlan1)
+				entry->ipv4_hnapt.vlan2 = skb->vlan_tci;
+			else
+				entry->ipv4_hnapt.vlan1 = skb->vlan_tci;
+		} else if (IS_IPV6_GRP(entry)) {
+			entry->ipv6_5t_route.etype = htons(ETH_P_8021Q);
+			if(entry->ipv6_5t_route.vlan1)
+				entry->ipv6_5t_route.vlan2 = skb->vlan_tci;
+			else
+				entry->ipv6_5t_route.vlan1 = skb->vlan_tci;
+		}
+	} else {
+		entry->bfib1.vpm = 0;
+		entry->bfib1.vlan_layer = 0;
+	}
+
+	/* MT7622 wifi hw_nat not support QoS */
+	if (IS_IPV4_GRP(entry)) {
+		entry->ipv4_hnapt.iblk2.fqos = 0;
+		if ((hnat_priv->data->version == MTK_HNAT_V2 &&
+		     gmac_no == NR_WHNAT_WDMA_PORT) ||
+		    (hnat_priv->data->version == MTK_HNAT_V4 &&
+		     (gmac_no == NR_WDMA0_PORT || gmac_no == NR_WDMA1_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_V2)
+			entry->ipv4_hnapt.iblk2.fqos = (IS_HQOS_MODE) ? 1 : 0;
+			entry->ipv4_hnapt.iblk2.rxid = skb_hnat_rx_id(skb);
+			entry->ipv4_hnapt.iblk2.winfoi = 1;
+#else
+			entry->ipv4_hnapt.winfo.rxid = skb_hnat_rx_id(skb);
+			entry->ipv4_hnapt.iblk2w.winfoi = 1;
+			entry->ipv4_hnapt.iblk2w.wdmaid = skb_hnat_wdma_id(skb);
+#endif
+		} else {
+			if (IS_GMAC1_MODE && !hnat_dsa_is_enable(hnat_priv)) {
+				entry->bfib1.vpm = 1;
+				entry->bfib1.vlan_layer = 1;
+
+				if (FROM_GE_LAN(skb))
+					entry->ipv4_hnapt.vlan1 = 1;
+				else if (FROM_GE_WAN(skb) || FROM_GE_VIRTUAL(skb))
+					entry->ipv4_hnapt.vlan1 = 2;
+			}
+
+			if (IS_HQOS_MODE &&
+			    (FROM_GE_LAN(skb) || FROM_GE_WAN(skb) || FROM_GE_VIRTUAL(skb))) {
+				entry->bfib1.vpm = 0;
+				entry->bfib1.vlan_layer = 1;
+				entry->ipv4_hnapt.etype = htons(HQOS_MAGIC_TAG);
+				entry->ipv4_hnapt.vlan1 = skb_hnat_entry(skb);
+				entry->ipv4_hnapt.iblk2.fqos = 1;
+			}
+		}
+		entry->ipv4_hnapt.iblk2.dp = gmac_no;
+	} else {
+		entry->ipv6_5t_route.iblk2.fqos = 0;
+		if ((hnat_priv->data->version == MTK_HNAT_V2 &&
+		     gmac_no == NR_WHNAT_WDMA_PORT) ||
+		    (hnat_priv->data->version == MTK_HNAT_V4 &&
+		     (gmac_no == NR_WDMA0_PORT || gmac_no == NR_WDMA1_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_V2)
+			entry->ipv6_5t_route.iblk2.fqos = (IS_HQOS_MODE) ? 1 : 0;
+			entry->ipv6_5t_route.iblk2.rxid = skb_hnat_rx_id(skb);
+			entry->ipv6_5t_route.iblk2.winfoi = 1;
+#else
+			entry->ipv6_5t_route.winfo.rxid = skb_hnat_rx_id(skb);
+			entry->ipv6_5t_route.iblk2w.winfoi = 1;
+			entry->ipv6_5t_route.iblk2w.wdmaid = skb_hnat_wdma_id(skb);
+#endif
+		} else {
+			if (IS_GMAC1_MODE && !hnat_dsa_is_enable(hnat_priv)) {
+				entry->bfib1.vpm = 1;
+				entry->bfib1.vlan_layer = 1;
+
+				if (FROM_GE_LAN(skb))
+					entry->ipv6_5t_route.vlan1 = 1;
+				else if (FROM_GE_WAN(skb) || FROM_GE_VIRTUAL(skb))
+					entry->ipv6_5t_route.vlan1 = 2;
+			}
+
+			if (IS_HQOS_MODE &&
+			    (FROM_GE_LAN(skb) || FROM_GE_WAN(skb) || FROM_GE_VIRTUAL(skb))) {
+				entry->bfib1.vpm = 0;
+				entry->bfib1.vlan_layer = 1;
+				entry->ipv6_5t_route.etype = htons(HQOS_MAGIC_TAG);
+				entry->ipv6_5t_route.vlan1 = skb_hnat_entry(skb);
+				entry->ipv6_5t_route.iblk2.fqos = 1;
+			}
+		}
+		entry->ipv6_5t_route.iblk2.dp = gmac_no;
+	}
+
+	entry->bfib1.state = BIND;
+
+	return NF_ACCEPT;
+}
+
+int mtk_sw_nat_hook_rx(struct sk_buff *skb)
+{
+	if (!IS_SPACE_AVAILABLE_HEAD(skb) || !FROM_WED(skb)) {
+		skb_hnat_magic_tag(skb) = 0;
+		return NF_ACCEPT;
+	}
+
+	skb_hnat_alg(skb) = 0;
+	skb_hnat_filled(skb) = 0;
+	skb_hnat_magic_tag(skb) = HNAT_MAGIC_TAG;
+
+	if (skb_hnat_iface(skb) == FOE_MAGIC_WED0)
+		skb_hnat_sport(skb) = NR_WDMA0_PORT;
+	else if (skb_hnat_iface(skb) == FOE_MAGIC_WED1)
+		skb_hnat_sport(skb) = NR_WDMA1_PORT;
+
+	return NF_ACCEPT;
+}
+
+void mtk_ppe_dev_register_hook(struct net_device *dev)
+{
+	int i, number = 0;
+	struct extdev_entry *ext_entry;
+
+	for (i = 1; i < MAX_IF_NUM; i++) {
+		if (hnat_priv->wifi_hook_if[i] == dev) {
+			pr_info("%s : %s has been registered in wifi_hook_if table[%d]\n",
+				__func__, dev->name, i);
+			return;
+		}
+		if (!hnat_priv->wifi_hook_if[i]) {
+			if (find_extif_from_devname(dev->name)) {
+				extif_set_dev(dev);
+				goto add_wifi_hook_if;
+			}
+
+			number = get_ext_device_number();
+			if (number >= MAX_EXT_DEVS) {
+				pr_info("%s : extdev array is full. %s is not registered\n",
+					__func__, dev->name);
+				return;
+			}
+
+			ext_entry = kzalloc(sizeof(*ext_entry), GFP_KERNEL);
+			if (!ext_entry)
+				return;
+
+			strncpy(ext_entry->name, dev->name, IFNAMSIZ - 1);
+			dev_hold(dev);
+			ext_entry->dev = dev;
+			ext_if_add(ext_entry);
+
+add_wifi_hook_if:
+			dev_hold(dev);
+			hnat_priv->wifi_hook_if[i] = dev;
+
+			break;
+		}
+	}
+	pr_info("%s : ineterface %s register (%d)\n", __func__, dev->name, i);
+}
+
+void mtk_ppe_dev_unregister_hook(struct net_device *dev)
+{
+	int i;
+
+	for (i = 1; i < MAX_IF_NUM; i++) {
+		if (hnat_priv->wifi_hook_if[i] == dev) {
+			hnat_priv->wifi_hook_if[i] = NULL;
+			dev_put(dev);
+
+			break;
+		}
+	}
+
+	extif_put_dev(dev);
+	pr_info("%s : ineterface %s set null (%d)\n", __func__, dev->name, i);
+}
+
+static unsigned int mtk_hnat_accel_type(struct sk_buff *skb)
+{
+	struct dst_entry *dst;
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
+	const struct nf_conn_help *help;
+
+	/* Do not accelerate 1st round of xfrm flow, and 2nd round of xfrm flow
+	 * is from local_out which is also filtered in sanity check.
+	 */
+	dst = skb_dst(skb);
+	if (dst && dst_xfrm(dst))
+		return 0;
+
+	ct = nf_ct_get(skb, &ctinfo);
+	if (!ct)
+		return 1;
+
+	/* rcu_read_lock()ed by nf_hook_slow */
+	help = nfct_help(ct);
+	if (help && rcu_dereference(help->helper))
+		return 0;
+
+	return 1;
+}
+
+static void mtk_hnat_dscp_update(struct sk_buff *skb, struct foe_entry *entry)
+{
+	struct iphdr *iph;
+	struct ethhdr *eth;
+	struct ipv6hdr *ip6h;
+	bool flag = false;
+
+	eth = eth_hdr(skb);
+	switch (ntohs(eth->h_proto)) {
+	case ETH_P_IP:
+		iph = ip_hdr(skb);
+		if (IS_IPV4_GRP(entry) && entry->ipv4_hnapt.iblk2.dscp != iph->tos)
+			flag = true;
+		break;
+	case ETH_P_IPV6:
+		ip6h = ipv6_hdr(skb);
+		if ((IS_IPV6_3T_ROUTE(entry) || IS_IPV6_5T_ROUTE(entry)) &&
+			(entry->ipv6_5t_route.iblk2.dscp !=
+			(ip6h->priority << 4 | (ip6h->flow_lbl[0] >> 4))))
+			flag = true;
+		break;
+	default:
+		return;
+	}
+
+	if (flag) {
+		if (debug_level >= 2)
+			pr_info("Delete entry idx=%d.\n", skb_hnat_entry(skb));
+		memset(entry, 0, sizeof(struct foe_entry));
+		hnat_cache_ebl(1);
+	}
+}
+
+static void mtk_hnat_nf_update(struct sk_buff *skb)
+{
+	struct nf_conn *ct;
+	struct nf_conn_acct *acct;
+	struct nf_conn_counter *counter;
+	enum ip_conntrack_info ctinfo;
+	struct hnat_accounting diff;
+
+	ct = nf_ct_get(skb, &ctinfo);
+	if (ct) {
+		if (!hnat_get_count(hnat_priv, skb_hnat_ppe(skb), skb_hnat_entry(skb), &diff))
+			return;
+
+		acct = nf_conn_acct_find(ct);
+		if (acct) {
+			counter = acct->counter;
+			atomic64_add(diff.packets, &counter[CTINFO2DIR(ctinfo)].packets);
+			atomic64_add(diff.bytes, &counter[CTINFO2DIR(ctinfo)].bytes);
+		}
+	}
+}
+
+static unsigned int mtk_hnat_nf_post_routing(
+	struct sk_buff *skb, const struct net_device *out,
+	unsigned int (*fn)(struct sk_buff *, const struct net_device *,
+			   struct flow_offload_hw_path *),
+	const char *func)
+{
+	struct foe_entry *entry;
+	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;
+
+	if (skb_hnat_alg(skb) || unlikely(!is_magic_tag_valid(skb) ||
+					  !IS_SPACE_AVAILABLE_HEAD(skb)))
+		return 0;
+
+	if (unlikely(!skb_hnat_is_hashed(skb)))
+		return 0;
+
+	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 (!IS_LAN(out) && !IS_WAN(out) && !IS_EXT(out))
+		return 0;
+
+	trace_printk("[%s] case hit, %x-->%s, reason=%x\n", __func__,
+		     skb_hnat_iface(skb), out->name, skb_hnat_reason(skb));
+
+	entry = &hnat_priv->foe_table_cpu[skb_hnat_ppe(skb)][skb_hnat_entry(skb)];
+
+	switch (skb_hnat_reason(skb)) {
+	case HIT_UNBIND_RATE_REACH:
+		if (entry_hnat_is_bound(entry))
+			break;
+
+		if (fn && !mtk_hnat_accel_type(skb))
+			break;
+
+		if (fn && fn(skb, arp_dev, &hw_path))
+			break;
+
+		skb_to_hnat_info(skb, out, entry, &hw_path);
+		break;
+	case HIT_BIND_KEEPALIVE_DUP_OLD_HDR:
+		/* update hnat count to nf_conntrack by keepalive */
+		if (hnat_priv->data->per_flow_accounting && hnat_priv->nf_stat_en)
+			mtk_hnat_nf_update(skb);
+
+		if (fn && !mtk_hnat_accel_type(skb))
+			break;
+
+		/* update dscp for qos */
+		mtk_hnat_dscp_update(skb, entry);
+
+		/* update mcast timestamp*/
+		if (hnat_priv->data->version == MTK_HNAT_V3 &&
+		    hnat_priv->data->mcast && entry->bfib1.sta == 1)
+			entry->ipv4_hnapt.m_timestamp = foe_timestamp(hnat_priv);
+
+		if (entry_hnat_is_bound(entry)) {
+			memset(skb_hnat_info(skb), 0, FOE_INFO_LEN);
+
+			return -1;
+		}
+		break;
+	case HIT_BIND_MULTICAST_TO_CPU:
+	case HIT_BIND_MULTICAST_TO_GMAC_CPU:
+		/*do not forward to gdma again,if ppe already done it*/
+		if (IS_LAN(out) || IS_WAN(out))
+			return -1;
+		break;
+	}
+
+	return 0;
+}
+
+static unsigned int
+mtk_hnat_ipv6_nf_local_out(void *priv, struct sk_buff *skb,
+			   const struct nf_hook_state *state)
+{
+	struct foe_entry *entry;
+	struct ipv6hdr *ip6h;
+	struct iphdr _iphdr;
+	const struct iphdr *iph;
+	struct tcpudphdr _ports;
+	const struct tcpudphdr *pptr;
+	int udp = 0;
+
+	if (unlikely(!skb_hnat_is_hashed(skb)))
+		return NF_ACCEPT;
+
+	entry = &hnat_priv->foe_table_cpu[skb_hnat_ppe(skb)][skb_hnat_entry(skb)];
+	if (skb_hnat_reason(skb) == HIT_UNBIND_RATE_REACH) {
+		ip6h = ipv6_hdr(skb);
+		if (ip6h->nexthdr == NEXTHDR_IPIP) {
+			/* Map-E LAN->WAN: need to record orig info before fn. */
+			if (mape_toggle) {
+				iph = skb_header_pointer(skb, IPV6_HDR_LEN,
+							 sizeof(_iphdr), &_iphdr);
+				if (unlikely(!iph))
+					return NF_ACCEPT;
+
+				switch (iph->protocol) {
+				case IPPROTO_UDP:
+					udp = 1;
+				case IPPROTO_TCP:
+				break;
+
+				default:
+					return NF_ACCEPT;
+				}
+
+				pptr = skb_header_pointer(skb, IPV6_HDR_LEN + iph->ihl * 4,
+							  sizeof(_ports), &_ports);
+				if (unlikely(!pptr))
+                                        return NF_ACCEPT;
+
+				entry->bfib1.udp = udp;
+
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+				entry->bfib1.pkt_type = IPV4_MAP_E;
+				entry->ipv4_dslite.iblk2.dscp = iph->tos;
+				entry->ipv4_dslite.new_sip = ntohl(iph->saddr);
+				entry->ipv4_dslite.new_dip = ntohl(iph->daddr);
+				entry->ipv4_dslite.new_sport = ntohs(pptr->src);
+				entry->ipv4_dslite.new_dport = ntohs(pptr->dst);
+#else
+				entry->ipv4_hnapt.iblk2.dscp = iph->tos;
+				entry->ipv4_hnapt.new_sip = ntohl(iph->saddr);
+				entry->ipv4_hnapt.new_dip = ntohl(iph->daddr);
+				entry->ipv4_hnapt.new_sport = ntohs(pptr->src);
+				entry->ipv4_hnapt.new_dport = ntohs(pptr->dst);
+#endif
+			} else {
+				entry->bfib1.pkt_type = IPV4_DSLITE;
+			}
+		}
+	}
+	return NF_ACCEPT;
+}
+
+static unsigned int
+mtk_hnat_ipv6_nf_post_routing(void *priv, struct sk_buff *skb,
+			      const struct nf_hook_state *state)
+{
+	post_routing_print(skb, state->in, state->out, __func__);
+
+	if (!mtk_hnat_nf_post_routing(skb, state->out, hnat_ipv6_get_nexthop,
+				      __func__))
+		return NF_ACCEPT;
+
+	trace_printk(
+		"%s:drop (iif=0x%x, out_dev=%s, CB2=0x%x, ppe_hash=0x%x, sport=0x%x, reason=0x%x, alg=0x%x)\n",
+		__func__, skb_hnat_iface(skb), state->out->name, HNAT_SKB_CB2(skb)->magic,
+		skb_hnat_entry(skb), skb_hnat_sport(skb), skb_hnat_reason(skb),
+		skb_hnat_alg(skb));
+
+	return NF_DROP;
+}
+
+static unsigned int
+mtk_hnat_ipv4_nf_post_routing(void *priv, struct sk_buff *skb,
+			      const struct nf_hook_state *state)
+{
+	post_routing_print(skb, state->in, state->out, __func__);
+
+	if (!mtk_hnat_nf_post_routing(skb, state->out, hnat_ipv4_get_nexthop,
+				      __func__))
+		return NF_ACCEPT;
+
+	trace_printk(
+		"%s:drop (iif=0x%x, out_dev=%s, CB2=0x%x, ppe_hash=0x%x, sport=0x%x, reason=0x%x, alg=0x%x)\n",
+		__func__, skb_hnat_iface(skb), state->out->name, HNAT_SKB_CB2(skb)->magic,
+		skb_hnat_entry(skb), skb_hnat_sport(skb), skb_hnat_reason(skb),
+		skb_hnat_alg(skb));
+
+	return NF_DROP;
+}
+
+static unsigned int
+mtk_pong_hqos_handler(void *priv, struct sk_buff *skb,
+		      const struct nf_hook_state *state)
+{
+	struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb);
+
+	if (IS_HQOS_MODE && eth_hdr(skb)->h_proto == HQOS_MAGIC_TAG) {
+		skb_hnat_entry(skb) = ntohs(veth->h_vlan_TCI) & 0x3fff;
+		skb_hnat_reason(skb) = HIT_BIND_FORCE_TO_CPU;
+	}
+
+	if (skb_hnat_iface(skb) == FOE_MAGIC_EXT)
+		clr_from_extge(skb);
+
+	/* packets from external devices -> xxx ,step 2, learning stage */
+	if (do_ext2ge_fast_learn(state->in, skb) && (!qos_toggle ||
+	    (qos_toggle && eth_hdr(skb)->h_proto != HQOS_MAGIC_TAG))) {
+		if (!do_hnat_ext_to_ge2(skb, __func__))
+			return NF_STOLEN;
+		goto drop;
+	}
+
+	/* packets form ge -> external device */
+	if (do_ge2ext_fast(state->in, skb)) {
+		if (!do_hnat_ge_to_ext(skb, __func__))
+			return NF_STOLEN;
+		goto drop;
+	}
+
+	return NF_ACCEPT;
+drop:
+	printk_ratelimited(KERN_WARNING
+				"%s:drop (in_dev=%s, iif=0x%x, CB2=0x%x, ppe_hash=0x%x, sport=0x%x, reason=0x%x, alg=0x%x)\n",
+				__func__, state->in->name, skb_hnat_iface(skb),
+				HNAT_SKB_CB2(skb)->magic, skb_hnat_entry(skb),
+				skb_hnat_sport(skb), skb_hnat_reason(skb),
+				skb_hnat_alg(skb));
+
+	return NF_DROP;
+}
+
+static unsigned int
+mtk_hnat_br_nf_local_out(void *priv, struct sk_buff *skb,
+			 const struct nf_hook_state *state)
+{
+	post_routing_print(skb, state->in, state->out, __func__);
+
+	if (!mtk_hnat_nf_post_routing(skb, state->out, 0, __func__))
+		return NF_ACCEPT;
+
+	trace_printk(
+		"%s:drop (iif=0x%x, out_dev=%s, CB2=0x%x, ppe_hash=0x%x, sport=0x%x, reason=0x%x, alg=0x%x)\n",
+		__func__, skb_hnat_iface(skb), state->out->name, HNAT_SKB_CB2(skb)->magic,
+		skb_hnat_entry(skb), skb_hnat_sport(skb), skb_hnat_reason(skb),
+		skb_hnat_alg(skb));
+
+	return NF_DROP;
+}
+
+static unsigned int
+mtk_hnat_ipv4_nf_local_out(void *priv, struct sk_buff *skb,
+			   const struct nf_hook_state *state)
+{
+	struct sk_buff *new_skb;
+	struct foe_entry *entry;
+	struct iphdr *iph;
+
+	if (!skb_hnat_is_hashed(skb))
+		return NF_ACCEPT;
+
+	entry = &hnat_priv->foe_table_cpu[skb_hnat_ppe(skb)][skb_hnat_entry(skb)];
+
+	if (unlikely(skb_headroom(skb) < FOE_INFO_LEN)) {
+		new_skb = skb_realloc_headroom(skb, FOE_INFO_LEN);
+		if (!new_skb) {
+			dev_info(hnat_priv->dev, "%s:drop\n", __func__);
+			return NF_DROP;
+		}
+		dev_kfree_skb(skb);
+		skb = new_skb;
+	}
+
+	/* Make the flow from local not be bound. */
+	iph = ip_hdr(skb);
+	if (iph->protocol == IPPROTO_IPV6) {
+		entry->udib1.pkt_type = IPV6_6RD;
+		hnat_set_head_frags(state, skb, 0, hnat_set_alg);
+	} else {
+		hnat_set_head_frags(state, skb, 1, hnat_set_alg);
+	}
+
+	return NF_ACCEPT;
+}
+
+static unsigned int mtk_hnat_br_nf_forward(void *priv,
+					   struct sk_buff *skb,
+					   const struct nf_hook_state *state)
+{
+	if ((hnat_priv->data->version == MTK_HNAT_V2) &&
+	    unlikely(IS_EXT(state->in) && IS_EXT(state->out)))
+		hnat_set_head_frags(state, skb, 1, hnat_set_alg);
+
+	return NF_ACCEPT;
+}
+
+static struct nf_hook_ops mtk_hnat_nf_ops[] __read_mostly = {
+	{
+		.hook = mtk_hnat_ipv4_nf_pre_routing,
+		.pf = NFPROTO_IPV4,
+		.hooknum = NF_INET_PRE_ROUTING,
+		.priority = NF_IP_PRI_FIRST + 1,
+	},
+	{
+		.hook = mtk_hnat_ipv6_nf_pre_routing,
+		.pf = NFPROTO_IPV6,
+		.hooknum = NF_INET_PRE_ROUTING,
+		.priority = NF_IP_PRI_FIRST + 1,
+	},
+	{
+		.hook = mtk_hnat_ipv6_nf_post_routing,
+		.pf = NFPROTO_IPV6,
+		.hooknum = NF_INET_POST_ROUTING,
+		.priority = NF_IP_PRI_LAST,
+	},
+	{
+		.hook = mtk_hnat_ipv6_nf_local_out,
+		.pf = NFPROTO_IPV6,
+		.hooknum = NF_INET_LOCAL_OUT,
+		.priority = NF_IP_PRI_LAST,
+	},
+	{
+		.hook = mtk_hnat_ipv4_nf_post_routing,
+		.pf = NFPROTO_IPV4,
+		.hooknum = NF_INET_POST_ROUTING,
+		.priority = NF_IP_PRI_LAST,
+	},
+	{
+		.hook = mtk_hnat_ipv4_nf_local_out,
+		.pf = NFPROTO_IPV4,
+		.hooknum = NF_INET_LOCAL_OUT,
+		.priority = NF_IP_PRI_LAST,
+	},
+	{
+		.hook = mtk_hnat_br_nf_local_in,
+		.pf = NFPROTO_BRIDGE,
+		.hooknum = NF_BR_LOCAL_IN,
+		.priority = NF_BR_PRI_FIRST,
+	},
+	{
+		.hook = mtk_hnat_br_nf_local_out,
+		.pf = NFPROTO_BRIDGE,
+		.hooknum = NF_BR_LOCAL_OUT,
+		.priority = NF_BR_PRI_LAST - 1,
+	},
+	{
+		.hook = mtk_pong_hqos_handler,
+		.pf = NFPROTO_BRIDGE,
+		.hooknum = NF_BR_PRE_ROUTING,
+		.priority = NF_BR_PRI_FIRST + 1,
+	},
+};
+
+int hnat_register_nf_hooks(void)
+{
+	return nf_register_net_hooks(&init_net, mtk_hnat_nf_ops, ARRAY_SIZE(mtk_hnat_nf_ops));
+}
+
+void hnat_unregister_nf_hooks(void)
+{
+	nf_unregister_net_hooks(&init_net, mtk_hnat_nf_ops, ARRAY_SIZE(mtk_hnat_nf_ops));
+}
+
+int whnat_adjust_nf_hooks(void)
+{
+	struct nf_hook_ops *hook = mtk_hnat_nf_ops;
+	unsigned int n = ARRAY_SIZE(mtk_hnat_nf_ops);
+
+	while (n-- > 0) {
+		if (hook[n].hook == mtk_hnat_br_nf_local_in) {
+			hook[n].hooknum = NF_BR_PRE_ROUTING;
+			hook[n].priority = NF_BR_PRI_FIRST + 1;
+		} else if (hook[n].hook == mtk_hnat_br_nf_local_out) {
+			hook[n].hooknum = NF_BR_POST_ROUTING;
+		} else if (hook[n].hook == mtk_pong_hqos_handler) {
+			hook[n].hook = mtk_hnat_br_nf_forward;
+			hook[n].hooknum = NF_BR_FORWARD;
+			hook[n].priority = NF_BR_PRI_LAST - 1;
+		}
+	}
+
+	return 0;
+}
+
+int mtk_hqos_ptype_cb(struct sk_buff *skb, struct net_device *dev,
+		      struct packet_type *pt, struct net_device *unused)
+{
+	struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb);
+
+	skb_hnat_entry(skb) = ntohs(veth->h_vlan_TCI) & 0x3fff;
+	skb_hnat_reason(skb) = HIT_BIND_FORCE_TO_CPU;
+
+	do_hnat_ge_to_ext(skb, __func__);
+
+	return 0;
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_stag.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_stag.c
new file mode 100644
index 0000000..73de3e9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_stag.c
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Landen Chao <landen.chao@mediatek.com>
+ */
+
+#include <linux/of_device.h>
+#include <net/netfilter/nf_flow_table.h>
+#include "hnat.h"
+
+u32 hnat_dsa_fill_stag(const struct net_device *netdev,
+		       struct foe_entry *entry,
+		       struct flow_offload_hw_path *hw_path,
+		       u16 eth_proto,
+		       int mape)
+{
+	const struct net_device *ndev;
+	const unsigned int *port_reg;
+	int port_index;
+	u16 sp_tag;
+
+	if (hw_path->flags & FLOW_OFFLOAD_PATH_VLAN)
+		ndev = hw_path->dev;
+	else
+		ndev = netdev;
+
+	port_reg = of_get_property(ndev->dev.of_node, "reg", NULL);
+	if (unlikely(!port_reg))
+		return -EINVAL;
+
+	port_index = be32_to_cpup(port_reg);
+	sp_tag = BIT(port_index);
+
+	if (!entry->bfib1.vlan_layer)
+		entry->bfib1.vlan_layer = 1;
+	else
+		/* VLAN existence indicator */
+		sp_tag |= BIT(8);
+	entry->bfib1.vpm = 0;
+
+	switch (eth_proto) {
+	case ETH_P_IP:
+		if (entry->ipv4_hnapt.bfib1.pkt_type == IPV4_DSLITE)
+			entry->ipv4_dslite.etype = sp_tag;
+		else
+			entry->ipv4_hnapt.etype = sp_tag;
+		break;
+	case ETH_P_IPV6:
+		/* In the case MAPE LAN --> WAN, binding entry is to CPU.
+		 * Do not add special tag.
+		 */
+		if (!mape)
+			/* etype offset of ipv6 entries are the same. */
+			entry->ipv6_5t_route.etype = sp_tag;
+
+		break;
+	default:
+		pr_info("DSA + HNAT unsupport protocol\n");
+	}
+
+	return port_index;
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h
new file mode 100644
index 0000000..96bbe06
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h
@@ -0,0 +1,129 @@
+/*   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; version 2 of the License
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   Copyright (C) 2014-2016 Sean Wang <sean.wang@mediatek.com>
+ *   Copyright (C) 2016-2017 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef NF_HNAT_MTK_H
+#define NF_HNAT_MTK_H
+
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include "../mtk_eth_soc.h"
+
+#define HNAT_SKB_CB2(__skb) ((struct hnat_skb_cb2 *)&((__skb)->cb[44]))
+struct hnat_skb_cb2 {
+	__u32 magic;
+};
+
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+struct hnat_desc {
+	u32 entry : 15;
+	u32 filled : 3;
+	u32 crsn : 5;
+	u32 resv1 : 3;
+	u32 sport : 4;
+	u32 resv2 : 1;
+	u32 alg : 1;
+	u32 iface : 8;
+	u32 wdmaid : 2;
+	u32 rxid : 2;
+	u32 wcid : 10;
+	u32 bssid : 6;
+	u32 resv5 : 20;
+	u32 magic_tag_protect : 16;
+} __packed;
+#else
+struct hnat_desc {
+	u32 entry : 14;
+	u32 crsn : 5;
+	u32 sport : 4;
+	u32 alg : 1;
+	u32 iface : 4;
+	u32 filled : 3;
+	u32 resv : 1;
+	u32 magic_tag_protect : 16;
+	u32 wdmaid : 8;
+	u32 rxid : 2;
+	u32 wcid : 8;
+	u32 bssid : 6;
+} __packed;
+#endif
+
+#define HQOS_MAGIC_TAG 0x5678
+#define HAS_HQOS_MAGIC_TAG(skb) (qos_toggle && skb->protocol == HQOS_MAGIC_TAG)
+
+#define HNAT_MAGIC_TAG 0x6789
+#define HNAT_INFO_FILLED 0x7
+#define WIFI_INFO_LEN 3
+#define FOE_INFO_LEN (10 + WIFI_INFO_LEN)
+#define IS_SPACE_AVAILABLE_HEAD(skb)                                           \
+	((((skb_headroom(skb) >= FOE_INFO_LEN) ? 1 : 0)))
+
+#define skb_hnat_info(skb) ((struct hnat_desc *)(skb->head))
+#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)
+#define skb_hnat_sport(skb) (((struct hnat_desc *)(skb->head))->sport)
+#define skb_hnat_alg(skb) (((struct hnat_desc *)(skb->head))->alg)
+#define skb_hnat_iface(skb) (((struct hnat_desc *)(skb->head))->iface)
+#define skb_hnat_filled(skb) (((struct hnat_desc *)(skb->head))->filled)
+#define skb_hnat_magic_tag(skb) (((struct hnat_desc *)((skb)->head))->magic_tag_protect)
+#define skb_hnat_wdma_id(skb) (((struct hnat_desc *)((skb)->head))->wdmaid)
+#define skb_hnat_rx_id(skb) (((struct hnat_desc *)((skb)->head))->rxid)
+#define skb_hnat_wc_id(skb) (((struct hnat_desc *)((skb)->head))->wcid)
+#define skb_hnat_bss_id(skb) (((struct hnat_desc *)((skb)->head))->bssid)
+#define skb_hnat_ppe(skb)				\
+	((skb_hnat_iface(skb) == FOE_MAGIC_WED1 && CFG_PPE_NUM > 1) ? 1 : 0)
+#define do_ext2ge_fast_try(dev, skb)						\
+	((skb_hnat_iface(skb) == FOE_MAGIC_EXT) && !is_from_extge(skb))
+#define set_from_extge(skb) (HNAT_SKB_CB2(skb)->magic = 0x78786688)
+#define clr_from_extge(skb) (HNAT_SKB_CB2(skb)->magic = 0x0)
+#define set_to_ppe(skb) (HNAT_SKB_CB2(skb)->magic = 0x78681415)
+#define is_from_extge(skb) (HNAT_SKB_CB2(skb)->magic == 0x78786688)
+#define is_hnat_info_filled(skb) (skb_hnat_filled(skb) == HNAT_INFO_FILLED)
+#define is_magic_tag_valid(skb) (skb_hnat_magic_tag(skb) == HNAT_MAGIC_TAG)
+#define set_from_mape(skb) (HNAT_SKB_CB2(skb)->magic = 0x78787788)
+#define is_from_mape(skb) (HNAT_SKB_CB2(skb)->magic == 0x78787788)
+#define is_unreserved_port(hdr)						       \
+	((ntohs(hdr->source) > 1023) && (ntohs(hdr->dest) > 1023))
+
+#define TTL_0 0x02
+#define HAS_OPTION_HEADER 0x03
+#define NO_FLOW_IS_ASSIGNED 0x07
+#define IPV4_WITH_FRAGMENT 0x08
+#define IPV4_HNAPT_DSLITE_WITH_FRAGMENT 0x09
+#define IPV4_HNAPT_DSLITE_WITHOUT_TCP_UDP 0x0A
+#define IPV6_5T_6RD_WITHOUT_TCP_UDP 0x0B
+#define TCP_FIN_SYN_RST                                                        \
+	0x0C /* Ingress packet is TCP fin/syn/rst (for IPv4 NAPT/DS-Lite or IPv6 5T-route/6RD) */
+#define UN_HIT 0x0D /* FOE Un-hit */
+#define HIT_UNBIND 0x0E /* FOE Hit unbind */
+#define HIT_UNBIND_RATE_REACH 0x0F
+#define HIT_BIND_TCP_FIN 0x10
+#define HIT_BIND_TTL_1 0x11
+#define HIT_BIND_WITH_VLAN_VIOLATION 0x12
+#define HIT_BIND_KEEPALIVE_UC_OLD_HDR 0x13
+#define HIT_BIND_KEEPALIVE_MC_NEW_HDR 0x14
+#define HIT_BIND_KEEPALIVE_DUP_OLD_HDR 0x15
+#define HIT_BIND_FORCE_TO_CPU 0x16
+#define HIT_BIND_WITH_OPTION_HEADER 0x17
+#define HIT_BIND_MULTICAST_TO_CPU 0x18
+#define HIT_BIND_MULTICAST_TO_GMAC_CPU 0x19
+#define HIT_PRE_BIND 0x1A
+#define HIT_BIND_PACKET_SAMPLING 0x1B
+#define HIT_BIND_EXCEED_MTU 0x1C
+
+u32 hnat_tx(struct sk_buff *skb);
+u32 hnat_set_skb_info(struct sk_buff *skb, u32 *rxd);
+u32 hnat_reg(struct net_device *, void __iomem *);
+u32 hnat_unreg(void);
+
+#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c
new file mode 100755
index 0000000..50bdbd8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018-2019 MediaTek Inc.
+
+/* A library for MediaTek SGMII circuit
+ *
+ * Author: Sean Wang <sean.wang@mediatek.com>
+ *
+ */
+
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+#include "mtk_eth_soc.h"
+
+int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3)
+{
+	struct device_node *np;
+	int i;
+
+	ss->ana_rgc3 = ana_rgc3;
+
+	for (i = 0; i < MTK_MAX_DEVS; i++) {
+		np = of_parse_phandle(r, "mediatek,sgmiisys", i);
+		if (!np)
+			break;
+
+		ss->regmap[i] = syscon_node_to_regmap(np);
+		if (IS_ERR(ss->regmap[i]))
+			return PTR_ERR(ss->regmap[i]);
+
+		ss->flags[i] &= ~(MTK_SGMII_PN_SWAP);
+		if (of_property_read_bool(np, "pn_swap"))
+			ss->flags[i] |= MTK_SGMII_PN_SWAP;
+	}
+
+	return 0;
+}
+
+int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, unsigned int id)
+{
+	unsigned int val;
+
+	if (!ss->regmap[id])
+		return -EINVAL;
+
+	/* Setup the link timer and QPHY power up inside SGMIISYS */
+	regmap_write(ss->regmap[id], SGMSYS_PCS_LINK_TIMER,
+		     SGMII_LINK_TIMER_DEFAULT);
+
+	regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val);
+	val |= SGMII_REMOTE_FAULT_DIS;
+	regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val);
+
+	regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val);
+	val |= SGMII_AN_RESTART;
+	regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val);
+
+	if(MTK_HAS_FLAGS(ss->flags[id],MTK_SGMII_PN_SWAP))
+		regmap_update_bits(ss->regmap[id], SGMSYS_QPHY_WRAP_CTRL,
+				   SGMII_PN_SWAP_MASK, SGMII_PN_SWAP_TX_RX);
+
+	regmap_read(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, &val);
+	val &= ~SGMII_PHYA_PWD;
+	regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, val);
+
+	return 0;
+}
+
+int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, unsigned int id,
+			       const struct phylink_link_state *state)
+{
+	unsigned int val;
+
+	if (!ss->regmap[id])
+		return -EINVAL;
+
+	regmap_read(ss->regmap[id], ss->ana_rgc3, &val);
+	val &= ~RG_PHY_SPEED_MASK;
+	if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
+		val |= RG_PHY_SPEED_3_125G;
+	regmap_write(ss->regmap[id], ss->ana_rgc3, val);
+
+	/* Disable SGMII AN */
+	regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val);
+	val &= ~SGMII_AN_ENABLE;
+	regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val);
+
+	/* SGMII force mode setting */
+	regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val);
+	val &= ~SGMII_IF_MODE_MASK;
+
+	switch (state->speed) {
+	case SPEED_10:
+		val |= SGMII_SPEED_10;
+		break;
+	case SPEED_100:
+		val |= SGMII_SPEED_100;
+		break;
+	case SPEED_2500:
+	case SPEED_1000:
+		val |= SGMII_SPEED_1000;
+		break;
+	};
+
+	if (state->duplex == DUPLEX_FULL)
+		val |= SGMII_DUPLEX_FULL;
+
+	regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val);
+
+	if(MTK_HAS_FLAGS(ss->flags[id],MTK_SGMII_PN_SWAP))
+		regmap_update_bits(ss->regmap[id], SGMSYS_QPHY_WRAP_CTRL,
+				   SGMII_PN_SWAP_MASK, SGMII_PN_SWAP_TX_RX);
+	/* Release PHYA power down state */
+	regmap_read(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, &val);
+	val &= ~SGMII_PHYA_PWD;
+	regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, val);
+
+	return 0;
+}
+
+void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id)
+{
+	struct mtk_sgmii *ss = eth->sgmii;
+	unsigned int val, sid;
+
+	/* Decide how GMAC and SGMIISYS be mapped */
+	sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ?
+	       0 : mac_id;
+
+	if (!ss->regmap[sid])
+		return;
+
+	regmap_read(ss->regmap[sid], SGMSYS_PCS_CONTROL_1, &val);
+	val |= SGMII_AN_RESTART;
+	regmap_write(ss->regmap[sid], SGMSYS_PCS_CONTROL_1, val);
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/gpy211.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/gpy211.c
new file mode 100644
index 0000000..4ac83b3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/gpy211.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include <linux/bitfield.h>
+#include <linux/module.h>
+#include <linux/phy.h>
+
+static int gpy211_phy_config_init(struct phy_device *phydev)
+{
+	return 0;
+}
+
+int gpy211_phy_probe(struct phy_device *phydev)
+{
+	int sgmii_reg = phy_read_mmd(phydev, MDIO_MMD_VEND1, 8);
+
+	/* enable 2.5G SGMII rate adaption */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 8, 0x24e2);
+
+	return 0;
+}
+
+static int gpy211_get_features(struct phy_device *phydev)
+{
+	int ret;
+
+	ret = genphy_read_abilities(phydev);
+	if (ret)
+		return ret;
+
+	/* GPY211 with rate adaption supports 100M/1G/2.5G speed. */
+	linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
+			   phydev->supported);
+	linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
+			   phydev->supported);
+	linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
+			 phydev->supported);
+
+	return 0;
+}
+
+static struct phy_driver gpy211_phy_driver[] = {
+	{
+		PHY_ID_MATCH_MODEL(0x67c9de0a),
+		.name		= "Intel GPY211 PHY",
+		.config_init	= gpy211_phy_config_init,
+		.probe		= gpy211_phy_probe,
+		.get_features	= gpy211_get_features,
+	}
+};
+
+module_phy_driver(gpy211_phy_driver);
+
+static struct mdio_device_id __maybe_unused gpy211_phy_tbl[] = {
+	{ PHY_ID_MATCH_VENDOR(0x67c9de00) },
+	{ }
+};
+
+MODULE_DESCRIPTION("Intel GPY211 PHY driver with rate adaption");
+MODULE_AUTHOR("Landen Chao <landen.chao@mediatek.com>");
+MODULE_LICENSE("GPL");
+
+MODULE_DEVICE_TABLE(mdio, gpy211_phy_tbl);
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
new file mode 100644
index 0000000..d8f9d6a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-ge.c
@@ -0,0 +1,932 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include <linux/bitfield.h>
+#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of_platform.h>
+#include <linux/phy.h>
+
+#define ANALOG_INTERNAL_OPERATION_MAX_US	(20)
+#define ZCAL_CTRL_MIN				(0)
+#define ZCAL_CTRL_MAX				(63)
+#define TXRESERVE_MIN				(0)
+#define TXRESERVE_MAX				(7)
+
+
+#define MTK_EXT_PAGE_ACCESS		0x1f
+#define MTK_PHY_PAGE_STANDARD		0x0000
+#define MTK_PHY_PAGE_EXTENDED		0x0001
+#define MTK_PHY_PAGE_EXTENDED_2		0x0002
+#define MTK_PHY_PAGE_EXTENDED_3		0x0003
+#define MTK_PHY_PAGE_EXTENDED_2A30	0x2a30
+#define MTK_PHY_PAGE_EXTENDED_52B5	0x52b5
+
+/* Registers on MDIO_MMD_VEND1 */
+#define MTK_PHY_1st_OVERSHOOT_LEVEL_0TO1	(0x1)
+#define MTK_PHY_2nd_OVERSHOOT_LEVEL_0TO1	(0x2)
+#define MTK_PHY_1st_OVERSHOOT_LEVEL_1TO0	(0x4)
+#define MTK_PHY_2nd_OVERSHOOT_LEVEL_1TO0	(0x5)
+#define MTK_PHY_1st_OVERSHOOT_LEVEL_0TON1	(0x7) /* N means negative */
+#define MTK_PHY_2nd_OVERSHOOT_LEVEL_0TON1	(0x8)
+#define MTK_PHY_1st_OVERSHOOT_LEVEL_N1TO0	(0xa)
+#define MTK_PHY_2nd_OVERSHOOT_LEVEL_N1TO0	(0xb)
+
+#define MTK_PHY_TXVLD_DA_RG				(0x12)
+#define   MTK_PHY_DA_TX_I2MPB_A_GBE_MASK	GENMASK(15, 10)
+#define   MTK_PHY_DA_TX_I2MPB_A_TBT_MASK	GENMASK(5, 0)
+
+#define MTK_PHY_TX_I2MPB_TEST_MODE_A2	(0x16)
+#define   MTK_PHY_DA_TX_I2MPB_A_HBT_MASK	GENMASK(15, 10)
+#define   MTK_PHY_DA_TX_I2MPB_A_TST_MASK	GENMASK(5, 0)
+
+#define MTK_PHY_TX_I2MPB_TEST_MODE_B1	(0x17)
+#define   MTK_PHY_DA_TX_I2MPB_B_GBE_MASK	GENMASK(13, 8)
+#define   MTK_PHY_DA_TX_I2MPB_B_TBT_MASK	GENMASK(5, 0)
+
+#define MTK_PHY_TX_I2MPB_TEST_MODE_B2	(0x18)
+#define   MTK_PHY_DA_TX_I2MPB_B_HBT_MASK	GENMASK(13, 8)
+#define   MTK_PHY_DA_TX_I2MPB_B_TST_MASK	GENMASK(5, 0)
+
+#define MTK_PHY_TX_I2MPB_TEST_MODE_C1	(0x19)
+#define   MTK_PHY_DA_TX_I2MPB_C_GBE_MASK	GENMASK(13, 8)
+#define   MTK_PHY_DA_TX_I2MPB_C_TBT_MASK	GENMASK(5, 0)
+
+#define MTK_PHY_TX_I2MPB_TEST_MODE_C2	(0x20)
+#define   MTK_PHY_DA_TX_I2MPB_C_HBT_MASK	GENMASK(13, 8)
+#define   MTK_PHY_DA_TX_I2MPB_C_TST_MASK	GENMASK(5, 0)
+
+#define MTK_PHY_TX_I2MPB_TEST_MODE_D1	(0x21)
+#define   MTK_PHY_DA_TX_I2MPB_D_GBE_MASK	GENMASK(13, 8)
+#define   MTK_PHY_DA_TX_I2MPB_D_TBT_MASK	GENMASK(5, 0)
+
+#define MTK_PHY_TX_I2MPB_TEST_MODE_D2	(0x22)
+#define   MTK_PHY_DA_TX_I2MPB_D_HBT_MASK	GENMASK(13, 8)
+#define   MTK_PHY_DA_TX_I2MPB_D_TST_MASK	GENMASK(5, 0)
+
+
+#define MTK_PHY_RESERVE_RG_0		(0x27)
+#define MTK_PHY_RESERVE_RG_1		(0x28)
+
+#define MTK_PHY_RG_ANA_TEST_POWERUP_TX	(0x3b)
+#define MTK_PHY_TANA_CAL_MODE		(0xc1)
+#define MTK_PHY_TANA_CAL_MODE_SHIFT	(8)
+
+#define MTK_PHY_RXADC_CTRL_RG9		(0xc8)
+#define   MTK_PHY_DA_RX_PSBN_TBT_MASK	GENMASK(14, 12)
+#define   MTK_PHY_DA_RX_PSBN_HBT_MASK	GENMASK(10, 8)
+#define   MTK_PHY_DA_RX_PSBN_GBE_MASK	GENMASK(6, 4)
+#define   MTK_PHY_DA_RX_PSBN_LP_MASK	GENMASK(2, 0)
+
+#define MTK_PHY_RG_ANA_CAL_RG0		(0xdb)
+#define   MTK_PHY_RG_CAL_CKINV		BIT(12)
+#define   MTK_PHY_RG_ANA_CALEN		BIT(8)
+#define   MTK_PHY_RG_REXT_CALEN		BIT(4)
+#define   MTK_PHY_RG_ZCALEN_A		BIT(0)
+
+#define MTK_PHY_RG_ANA_CAL_RG1		(0xdc)
+#define   MTK_PHY_RG_ZCALEN_B		BIT(12)
+#define   MTK_PHY_RG_ZCALEN_C		BIT(8)
+#define   MTK_PHY_RG_ZCALEN_D		BIT(4)
+#define   MTK_PHY_RG_TXVOS_CALEN	BIT(0)
+
+#define MTK_PHY_RG_ANA_CAL_RG2		(0xdd)
+#define   MTK_PHY_RG_TXG_CALEN_A	BIT(12)
+#define   MTK_PHY_RG_TXG_CALEN_B	BIT(8)
+#define   MTK_PHY_RG_TXG_CALEN_C	BIT(4)
+#define   MTK_PHY_RG_TXG_CALEN_D	BIT(0)
+
+#define MTK_PHY_RG_ANA_CAL_RG5		(0xe0)
+#define   MTK_PHY_RG_REXT_TRIM_MASK	GENMASK(13, 8)
+#define   MTK_PHY_RG_ZCAL_CTRL_MASK	GENMASK(5, 0)
+
+#define MTK_PHY_RG_DEV1E_REG172		(0x172)
+#define   MTK_PHY_CR_TX_AMP_OFFSET_A_MASK	GENMASK(13, 8)
+#define   MTK_PHY_CR_TX_AMP_OFFSET_B_MASK	GENMASK(6, 0)
+
+#define MTK_PHY_RG_DEV1E_REG173		(0x173)
+#define   MTK_PHY_CR_TX_AMP_OFFSET_C_MASK	GENMASK(13, 8)
+#define   MTK_PHY_CR_TX_AMP_OFFSET_D_MASK	GENMASK(6, 0)
+
+#define MTK_PHY_RG_DEV1E_REG174		(0x174)
+#define   MTK_PHY_RSEL_TX_A_MASK	GENMASK(14, 8)
+#define   MTK_PHY_RSEL_TX_B_MASK	GENMASK(6, 0)
+
+#define MTK_PHY_RG_DEV1E_REG175		(0x175)
+#define   MTK_PHY_RSEL_TX_C_MASK	GENMASK(14, 8)
+#define   MTK_PHY_RSEL_TX_D_MASK	GENMASK(6, 0)
+
+#define MTK_PHY_RG_DEV1E_REG17A		(0x17a)
+#define   MTK_PHY_AD_CAL_COMP_OUT_SHIFT	(8)
+
+#define MTK_PHY_RG_DEV1E_REG17B		(0x17b)
+#define   MTK_PHY_DA_CAL_CLK		BIT(0)
+
+#define MTK_PHY_RG_DEV1E_REG17C		(0x17c)
+#define   MTK_PHY_DA_CALIN_FLAG		BIT(0)
+
+#define MTK_PHY_RG_DEV1E_REG17D		(0x17d)
+#define   MTK_PHY_DASN_DAC_IN0_A_MASK	GENMASK(9, 0)
+
+#define MTK_PHY_RG_DEV1E_REG17E		(0x17e)
+#define   MTK_PHY_DASN_DAC_IN0_B_MASK	GENMASK(9, 0)
+
+#define MTK_PHY_RG_DEV1E_REG17F		(0x17f)
+#define   MTK_PHY_DASN_DAC_IN0_C_MASK	GENMASK(9, 0)
+
+#define MTK_PHY_RG_DEV1E_REG180		(0x180)
+#define   MTK_PHY_DASN_DAC_IN0_D_MASK	GENMASK(9, 0)
+
+#define MTK_PHY_RG_DEV1E_REG181		(0x181)
+#define   MTK_PHY_DASN_DAC_IN1_A_MASK	GENMASK(9, 0)
+
+#define MTK_PHY_RG_DEV1E_REG182		(0x182)
+#define   MTK_PHY_DASN_DAC_IN1_B_MASK	GENMASK(9, 0)
+
+#define MTK_PHY_RG_DEV1E_REG183		(0x183)
+#define   MTK_PHY_DASN_DAC_IN1_C_MASK	GENMASK(9, 0)
+
+#define MTK_PHY_RG_DEV1E_REG184		(0x180)
+#define   MTK_PHY_DASN_DAC_IN1_D_MASK	GENMASK(9, 0)
+
+#define MTK_PHY_RG_DEV1E_REG53D		(0x53d)
+#define   MTK_PHY_DA_TX_R50_A_NORMAL_MASK	GENMASK(13, 8)
+#define   MTK_PHY_DA_TX_R50_A_TBT_MASK		GENMASK(5, 0)
+
+#define MTK_PHY_RG_DEV1E_REG53E		(0x53e)
+#define   MTK_PHY_DA_TX_R50_B_NORMAL_MASK	GENMASK(13, 8)
+#define   MTK_PHY_DA_TX_R50_B_TBT_MASK		GENMASK(5, 0)
+
+#define MTK_PHY_RG_DEV1E_REG53F		(0x53f)
+#define   MTK_PHY_DA_TX_R50_C_NORMAL_MASK	GENMASK(13, 8)
+#define   MTK_PHY_DA_TX_R50_C_TBT_MASK		GENMASK(5, 0)
+
+#define MTK_PHY_RG_DEV1E_REG540		(0x540)
+#define   MTK_PHY_DA_TX_R50_D_NORMAL_MASK	GENMASK(13, 8)
+#define   MTK_PHY_DA_TX_R50_D_TBT_MASK		GENMASK(5, 0)
+
+
+/* Registers on MDIO_MMD_VEND2 */
+#define MTK_PHY_ANA_TEST_BUS_CTRL_RG	(0x100)
+#define   MTK_PHY_ANA_TEST_MODE_MASK		GENMASK(15, 8)
+
+#define MTK_PHY_RG_DEV1F_REG110		(0x110)
+#define   MTK_PHY_RG_TST_DMY2_MASK		GENMASK(5, 0)
+#define   MTK_PHY_RG_TANA_RESERVE_MASK	GENMASK(13, 8)
+
+#define MTK_PHY_RG_DEV1F_REG115		(0x115)
+#define   MTK_PHY_RG_BG_RASEL_MASK	GENMASK(2, 0)
+
+/*
+ * These macro privides efuse parsing for internal phy.
+ */
+#define EFS_DA_TX_I2MPB_A(x)		(((x) >> 0) & GENMASK(5, 0))
+#define EFS_DA_TX_I2MPB_B(x)		(((x) >> 6) & GENMASK(5, 0))
+#define EFS_DA_TX_I2MPB_C(x)		(((x) >> 12) & GENMASK(5, 0))
+#define EFS_DA_TX_I2MPB_D(x)		(((x) >> 18) & GENMASK(5, 0))
+#define EFS_DA_TX_AMP_OFFSET_A(x)	(((x) >> 24) & GENMASK(5, 0))
+
+#define EFS_DA_TX_AMP_OFFSET_B(x)	(((x) >> 0) & GENMASK(5, 0))
+#define EFS_DA_TX_AMP_OFFSET_C(x)	(((x) >> 6) & GENMASK(5, 0))
+#define EFS_DA_TX_AMP_OFFSET_D(x)	(((x) >> 12) & GENMASK(5, 0))
+#define EFS_DA_TX_R50_A(x)		(((x) >> 18) & GENMASK(5, 0))
+#define EFS_DA_TX_R50_B(x)		(((x) >> 24) & GENMASK(5, 0))
+
+#define EFS_DA_TX_R50_C(x)		(((x) >> 0) & GENMASK(5, 0))
+#define EFS_DA_TX_R50_D(x)		(((x) >> 6) & GENMASK(5, 0))
+#define EFS_DA_TX_R50_A_10M(x)		(((x) >> 12) & GENMASK(5, 0))
+#define EFS_DA_TX_R50_B_10M(x)		(((x) >> 18) & GENMASK(5, 0))
+
+#define EFS_RG_BG_RASEL(x)		(((x) >> 4) & GENMASK(2, 0))
+#define EFS_RG_REXT_TRIM(x)		(((x) >> 7) & GENMASK(5, 0))
+
+typedef enum {
+	PAIR_A,
+	PAIR_B,
+	PAIR_C,
+	PAIR_D,
+} phy_cal_pair_t;
+
+const u8 mt798x_zcal_to_r50[64] = {
+	7, 8, 9, 9, 10, 10, 11, 11,
+	12, 13, 13, 14, 14, 15, 16, 16,
+	17, 18, 18, 19, 20, 21, 21, 22,
+	23, 24, 24, 25, 26, 27, 28, 29,
+	30, 31, 32, 33, 34, 35, 36, 37,
+	38, 40, 41, 42, 43, 45, 46, 48,
+	49, 51, 52, 54, 55, 57, 59, 61,
+	62, 63, 63, 63, 63, 63, 63, 63
+};
+
+const char pair[4] = {'A', 'B', 'C', 'D'};
+
+#define CAL_NO_PAIR(cal_item, cal_mode, ...) \
+	cal_ret = cal_item##_cal_##cal_mode(phydev, ##__VA_ARGS__);
+
+#define CAL_PAIR_A_TO_A(cal_item, cal_mode, ...)	\
+	for(i=PAIR_A; i<=PAIR_A; i++) {			\
+		cal_ret = cal_item##_cal_##cal_mode(phydev, ##__VA_ARGS__, i);\
+		if(cal_ret) break;			\
+	}
+
+#define CAL_PAIR_A_TO_D(cal_item, cal_mode, ...)	\
+	for(i=PAIR_A; i<=PAIR_D; i++) {			\
+		cal_ret = cal_item##_cal_##cal_mode(phydev, ##__VA_ARGS__, i);\
+		if(cal_ret) break;			\
+	}
+
+#define SW_CAL(cal_item, cal_mode_get, pair_mode)			\
+	if(ret || (!ret && strcmp("sw", cal_mode_get) == 0)) {		\
+		CAL_##pair_mode(cal_item, sw)				\
+	}
+
+#define SW_EFUSE_CAL(cal_item, cal_mode_get, pair_mode,...)	\
+	if ((efs_valid && ret) ||				\
+	    (!ret && strcmp("efuse", cal_mode_get) == 0)) {	\
+		CAL_##pair_mode(cal_item, efuse, ##__VA_ARGS__)	\
+	} else if ((!efs_valid && ret) ||			\
+		   (!ret && strcmp("sw", cal_mode_get) == 0)) {	\
+		CAL_##pair_mode(cal_item, sw)			\
+	}
+
+#define EFUSE_CAL(cal_item, cal_mode_get, pair_mode, ...)	\
+	if ((efs_valid && ret) ||				\
+	    (!ret && strcmp("efuse", cal_mode_get) == 0)) {\
+		CAL_##pair_mode(cal_item, efuse, ##__VA_ARGS__)	\
+	}
+
+#define CAL_FLOW(cal_item, cal_mode, cal_mode_get, pair_mode,...)	\
+	ret = of_property_read_string(phydev->mdio.dev.of_node,		\
+			#cal_item, &cal_mode_get);			\
+	cal_mode##_CAL(cal_item, cal_mode_get, pair_mode, ##__VA_ARGS__)\
+	else {								\
+		dev_info(&phydev->mdio.dev, "%s cal mode %s%s,"		\
+			 " use default value,"				\
+			 " efs-valid: %s",				\
+			 #cal_item,					\
+			 ret? "" : cal_mode_get,			\
+			 ret? "not specified" : " not supported",	\
+			 efs_valid? "yes" : "no");			\
+	}								\
+	if(cal_ret) {							\
+		dev_err(&phydev->mdio.dev, "%s cal failed\n", #cal_item);\
+		ret = -EIO;						\
+		goto out;						\
+	}
+
+static int mtk_gephy_read_page(struct phy_device *phydev)
+{
+	return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+}
+
+static int mtk_gephy_write_page(struct phy_device *phydev, int page)
+{
+	return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
+}
+
+/*
+ * One calibration cycle consists of:
+ * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high
+ *   until AD_CAL_COMP is ready to output calibration result.
+ * 2.Wait until DA_CAL_CLK is available.
+ * 3.Fetch AD_CAL_COMP_OUT.
+ */
+static int cal_cycle(struct phy_device *phydev, int devad,
+		u32 regnum, u16 mask, u16 cal_val)
+{
+	unsigned long timeout;
+	int reg_val;
+	int ret;
+
+	phy_modify_mmd(phydev, devad, regnum,
+			mask, cal_val);
+	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG17C,
+			MTK_PHY_DA_CALIN_FLAG);
+
+	timeout = jiffies + usecs_to_jiffies(ANALOG_INTERNAL_OPERATION_MAX_US);
+	do{
+		reg_val = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG17B);
+	} while(time_before(jiffies, timeout) && !(reg_val & BIT(0)));
+
+	if(!(reg_val & BIT(0))) {
+		dev_err(&phydev->mdio.dev, "Calibration cycle timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG17C,
+			MTK_PHY_DA_CALIN_FLAG);
+	ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG17A) >>
+			MTK_PHY_AD_CAL_COMP_OUT_SHIFT;
+	dev_dbg(&phydev->mdio.dev, "cal_val: 0x%x, ret: %d\n", cal_val, ret);
+
+	return ret;
+}
+
+static int rext_fill_result(struct phy_device *phydev, u16 *buf)
+{
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
+			MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8);
+	phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_DEV1F_REG115,
+			MTK_PHY_RG_BG_RASEL_MASK, buf[1]);
+
+	return 0;
+}
+
+static int rext_cal_efuse(struct phy_device *phydev, u32 *buf)
+{
+	u16 rext_cal_val[2];
+
+	rext_cal_val[0] = EFS_RG_REXT_TRIM(buf[3]);
+	rext_cal_val[1] = EFS_RG_BG_RASEL(buf[3]);
+	rext_fill_result(phydev, rext_cal_val);
+
+	return 0;
+}
+
+static int rext_cal_sw(struct phy_device *phydev)
+{
+	u8 rg_zcal_ctrl_def;
+	u8 zcal_lower, zcal_upper, rg_zcal_ctrl;
+	u8 lower_ret, upper_ret;
+	u16 rext_cal_val[2];
+	int ret;
+
+	phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_ANA_TEST_BUS_CTRL_RG,
+		MTK_PHY_ANA_TEST_MODE_MASK, MTK_PHY_TANA_CAL_MODE << 8);
+	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
+		MTK_PHY_RG_TXVOS_CALEN);
+	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+		MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN | MTK_PHY_RG_REXT_CALEN);
+	phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_DEV1F_REG110,
+		MTK_PHY_RG_TST_DMY2_MASK, 0x1);
+
+	rg_zcal_ctrl_def = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5) &
+					MTK_PHY_RG_ZCAL_CTRL_MASK;
+	zcal_lower = ZCAL_CTRL_MIN;
+	zcal_upper = ZCAL_CTRL_MAX;
+
+	dev_dbg(&phydev->mdio.dev, "Start REXT SW cal.\n");
+	while((zcal_upper-zcal_lower) > 1) {
+		rg_zcal_ctrl = DIV_ROUND_CLOSEST(zcal_lower+zcal_upper, 2);
+		ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
+				MTK_PHY_RG_ZCAL_CTRL_MASK, rg_zcal_ctrl);
+		if(ret == 1) {
+			zcal_upper = rg_zcal_ctrl;
+			upper_ret = ret;
+		} else if(ret == 0) {
+			zcal_lower = rg_zcal_ctrl;
+			lower_ret = ret;
+		} else
+			goto restore;
+	}
+
+	if(zcal_lower == ZCAL_CTRL_MIN) {
+		ret = lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
+				MTK_PHY_RG_ZCAL_CTRL_MASK, zcal_lower);
+	} else if(zcal_upper == ZCAL_CTRL_MAX) {
+		ret = upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
+				MTK_PHY_RG_ZCAL_CTRL_MASK, zcal_upper);
+	}
+	if (ret < 0)
+		goto restore;
+
+	ret = upper_ret-lower_ret;
+	if (ret == 1) {
+		rext_cal_val[0] = zcal_upper;
+		rext_cal_val[1] = zcal_upper >> 3;
+		rext_fill_result(phydev, rext_cal_val);
+		dev_info(&phydev->mdio.dev, "REXT SW cal result: 0x%x\n", zcal_upper);
+		ret = 0;
+	} else
+		ret = -EINVAL;
+
+restore:
+	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_ANA_TEST_BUS_CTRL_RG,
+			   MTK_PHY_ANA_TEST_MODE_MASK);
+	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+			   MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN | MTK_PHY_RG_REXT_CALEN);
+	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_DEV1F_REG110,
+			   MTK_PHY_RG_TST_DMY2_MASK);
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
+		       MTK_PHY_RG_ZCAL_CTRL_MASK, rg_zcal_ctrl_def);
+
+	return ret;
+}
+
+static int tx_offset_fill_result(struct phy_device *phydev, u16 *buf)
+{
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG172,
+		       MTK_PHY_CR_TX_AMP_OFFSET_A_MASK, buf[0] << 8);
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG172,
+		       MTK_PHY_CR_TX_AMP_OFFSET_B_MASK, buf[1]);
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG173,
+		       MTK_PHY_CR_TX_AMP_OFFSET_C_MASK, buf[2] << 8);
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG173,
+		       MTK_PHY_CR_TX_AMP_OFFSET_D_MASK, buf[3]);
+
+	return 0;
+}
+
+static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf)
+{
+	u16 tx_offset_cal_val[4];
+
+	tx_offset_cal_val[0] = EFS_DA_TX_AMP_OFFSET_A(buf[0]);
+	tx_offset_cal_val[1] = EFS_DA_TX_AMP_OFFSET_B(buf[1]);
+	tx_offset_cal_val[2] = EFS_DA_TX_AMP_OFFSET_C(buf[1]);
+	tx_offset_cal_val[3] = EFS_DA_TX_AMP_OFFSET_D(buf[1]);
+
+	tx_offset_fill_result(phydev, tx_offset_cal_val);
+
+	return 0;
+}
+
+static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf)
+{
+	/* We add some calibration to efuse values:
+	 * GBE: +7, TBT: +1, HBT: +4, TST: +7
+	 */
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
+		       MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, (buf[0] + 7) << 10);
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG,
+		       MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, buf[0] + 1);
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
+		       MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, (buf[0] + 4) << 10);
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2,
+		       MTK_PHY_DA_TX_I2MPB_A_TST_MASK, buf[0] + 7);
+
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
+		       MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, (buf[1] + 7) << 8);
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1,
+		       MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, buf[1] + 1);
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
+		       MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, (buf[1] + 4 ) << 8);
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2,
+		       MTK_PHY_DA_TX_I2MPB_B_TST_MASK, buf[1] + 7);
+
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
+		       MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, (buf[2] + 7) << 8);
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1,
+		       MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, buf[2] + 1);
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
+		       MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, (buf[2] + 4) << 8);
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2,
+		       MTK_PHY_DA_TX_I2MPB_C_TST_MASK, buf[2] + 7);
+
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
+		       MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, (buf[3] + 7) << 8);
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1,
+		       MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, buf[3] + 1);
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
+		       MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, (buf[3] + 4) << 8);
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2,
+		       MTK_PHY_DA_TX_I2MPB_D_TST_MASK, buf[3] + 7);
+
+	return 0;
+}
+
+static int tx_amp_cal_efuse(struct phy_device *phydev, u32 *buf)
+{
+	u16 tx_amp_cal_val[4];
+
+	tx_amp_cal_val[0] = EFS_DA_TX_I2MPB_A(buf[0]);
+	tx_amp_cal_val[1] = EFS_DA_TX_I2MPB_B(buf[0]);
+	tx_amp_cal_val[2] = EFS_DA_TX_I2MPB_C(buf[0]);
+	tx_amp_cal_val[3] = EFS_DA_TX_I2MPB_D(buf[0]);
+	tx_amp_fill_result(phydev, tx_amp_cal_val);
+
+	return 0;
+}
+
+static int tx_r50_fill_result(struct phy_device *phydev, u16 *buf,
+			      phy_cal_pair_t txg_calen_x)
+{
+	switch(txg_calen_x) {
+		case PAIR_A:
+			phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG53D,
+				       MTK_PHY_DA_TX_R50_A_NORMAL_MASK, buf[0] << 8);
+			phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG53D,
+				       MTK_PHY_DA_TX_R50_A_TBT_MASK, buf[0]);
+			break;
+		case PAIR_B:
+			phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG53E,
+				       MTK_PHY_DA_TX_R50_B_NORMAL_MASK, buf[0] << 8);
+			phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG53E,
+				       MTK_PHY_DA_TX_R50_B_TBT_MASK, buf[0]);
+			break;
+		case PAIR_C:
+			phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG53F,
+				       MTK_PHY_DA_TX_R50_C_NORMAL_MASK, buf[0] << 8);
+			phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG53F,
+				       MTK_PHY_DA_TX_R50_C_TBT_MASK, buf[0]);
+			break;
+		case PAIR_D:
+			phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG540,
+				       MTK_PHY_DA_TX_R50_D_NORMAL_MASK, buf[0] << 8);
+			phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG540,
+				       MTK_PHY_DA_TX_R50_D_TBT_MASK, buf[0]);
+			break;
+	}
+	return 0;
+}
+
+static int tx_r50_cal_efuse(struct phy_device *phydev, u32 *buf,
+			    phy_cal_pair_t txg_calen_x)
+{
+	u16 tx_r50_cal_val[1];
+
+	switch(txg_calen_x) {
+		case PAIR_A:
+			tx_r50_cal_val[0] = EFS_DA_TX_R50_A(buf[1]);
+			break;
+		case PAIR_B:
+			tx_r50_cal_val[0] = EFS_DA_TX_R50_B(buf[1]);
+			break;
+		case PAIR_C:
+			tx_r50_cal_val[0] = EFS_DA_TX_R50_C(buf[2]);
+			break;
+		case PAIR_D:
+			tx_r50_cal_val[0] = EFS_DA_TX_R50_D(buf[2]);
+			break;
+	}
+	tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x);
+
+	return 0;
+}
+
+static int tx_r50_cal_sw(struct phy_device *phydev, phy_cal_pair_t txg_calen_x)
+{
+	u8 rg_zcal_ctrl_def;
+	u8 zcal_lower, zcal_upper, rg_zcal_ctrl;
+	u8 lower_ret, upper_ret;
+	u16 tx_r50_cal_val[1];
+	int ret;
+
+	phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_ANA_TEST_BUS_CTRL_RG,
+		MTK_PHY_ANA_TEST_MODE_MASK, MTK_PHY_TANA_CAL_MODE << 8);
+	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
+		MTK_PHY_RG_TXVOS_CALEN);
+	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+		MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN);
+	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG2,
+		BIT(txg_calen_x * 4));
+	phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_DEV1F_REG110,
+		MTK_PHY_RG_TST_DMY2_MASK, 0x1);
+
+	rg_zcal_ctrl_def = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5) &
+				MTK_PHY_RG_ZCAL_CTRL_MASK;
+	zcal_lower = ZCAL_CTRL_MIN;
+	zcal_upper = ZCAL_CTRL_MAX;
+
+	dev_dbg(&phydev->mdio.dev, "Start TX-R50 Pair%c SW cal.\n", pair[txg_calen_x]);
+	while((zcal_upper-zcal_lower) > 1) {
+		rg_zcal_ctrl = DIV_ROUND_CLOSEST(zcal_lower+zcal_upper, 2);
+		ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
+				MTK_PHY_RG_ZCAL_CTRL_MASK, rg_zcal_ctrl);
+		if(ret==1) {
+			zcal_upper = rg_zcal_ctrl;
+			upper_ret = ret;
+		} else if(ret==0) {
+			zcal_lower = rg_zcal_ctrl;
+			lower_ret = ret;
+		} else
+			goto restore;
+	}
+
+	if(zcal_lower == ZCAL_CTRL_MIN) {
+		ret = lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
+				MTK_PHY_RG_ZCAL_CTRL_MASK, zcal_lower);
+	} else if(zcal_upper == ZCAL_CTRL_MAX) {
+		ret = upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
+				MTK_PHY_RG_ZCAL_CTRL_MASK, zcal_upper);
+	}
+	if (ret < 0)
+		goto restore;
+
+	ret = upper_ret-lower_ret;
+	if (ret == 1) {
+		tx_r50_cal_val[0] = mt798x_zcal_to_r50[zcal_upper];
+		tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x);
+		dev_info(&phydev->mdio.dev, "TX-R50 Pair%c SW cal result: 0x%x\n",
+			pair[txg_calen_x], zcal_lower);
+		ret = 0;
+	} else
+		ret = -EINVAL;
+
+restore:
+	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_ANA_TEST_BUS_CTRL_RG,
+		MTK_PHY_ANA_TEST_MODE_MASK);
+	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+		MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN);
+	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG2,
+		BIT(txg_calen_x * 4));
+	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_DEV1F_REG110,
+		MTK_PHY_RG_TST_DMY2_MASK);
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5,
+		MTK_PHY_RG_ZCAL_CTRL_MASK, rg_zcal_ctrl_def);
+
+	return ret;
+}
+
+static int tx_vcm_cal_sw(struct phy_device *phydev, phy_cal_pair_t rg_txreserve_x)
+{
+	u8 lower_idx, upper_idx, txreserve_val;
+	u8 lower_ret, upper_ret;
+	int ret;
+
+	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+		MTK_PHY_RG_ANA_CALEN);
+	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+		MTK_PHY_RG_CAL_CKINV);
+	phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
+		MTK_PHY_RG_TXVOS_CALEN);
+
+	switch(rg_txreserve_x) {
+		case PAIR_A:
+			phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG17D,
+				MTK_PHY_DASN_DAC_IN0_A_MASK);
+			phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG181,
+				MTK_PHY_DASN_DAC_IN1_A_MASK);
+			phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+				MTK_PHY_RG_ZCALEN_A);
+			break;
+		case PAIR_B:
+			phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG17E,
+				MTK_PHY_DASN_DAC_IN0_B_MASK);
+			phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG182,
+				MTK_PHY_DASN_DAC_IN1_B_MASK);
+			phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
+				MTK_PHY_RG_ZCALEN_B);
+			break;
+		case PAIR_C:
+			phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG17F,
+				MTK_PHY_DASN_DAC_IN0_C_MASK);
+			phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG183,
+				MTK_PHY_DASN_DAC_IN1_C_MASK);
+			phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
+				MTK_PHY_RG_ZCALEN_C);
+			break;
+		case PAIR_D:
+			phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG180,
+				MTK_PHY_DASN_DAC_IN0_D_MASK);
+			phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG184,
+				MTK_PHY_DASN_DAC_IN1_D_MASK);
+			phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
+				MTK_PHY_RG_ZCALEN_D);
+			break;
+		default:
+			ret = -EINVAL;
+			goto restore;
+	}
+
+	lower_idx = TXRESERVE_MIN;
+	upper_idx = TXRESERVE_MAX;
+
+	dev_dbg(&phydev->mdio.dev, "Start TX-VCM SW cal.\n");
+	while((upper_idx-lower_idx) > 1) {
+		txreserve_val = DIV_ROUND_CLOSEST(lower_idx+upper_idx, 2);
+		ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
+				MTK_PHY_DA_RX_PSBN_TBT_MASK | MTK_PHY_DA_RX_PSBN_HBT_MASK |
+				MTK_PHY_DA_RX_PSBN_GBE_MASK | MTK_PHY_DA_RX_PSBN_LP_MASK,
+				txreserve_val << 12 | txreserve_val << 8 |
+				txreserve_val << 4 | txreserve_val);
+		if(ret==1) {
+			upper_idx = txreserve_val;
+			upper_ret = ret;
+		} else if(ret==0) {
+			lower_idx = txreserve_val;
+			lower_ret = ret;
+		} else
+			goto restore;
+	}
+
+	if(lower_idx == TXRESERVE_MIN) {
+		ret = lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
+				MTK_PHY_DA_RX_PSBN_TBT_MASK | MTK_PHY_DA_RX_PSBN_HBT_MASK |
+				MTK_PHY_DA_RX_PSBN_GBE_MASK | MTK_PHY_DA_RX_PSBN_LP_MASK,
+				lower_idx << 12 | lower_idx << 8 | lower_idx << 4 | lower_idx);
+	} else if(upper_idx == TXRESERVE_MAX) {
+		ret = upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
+				MTK_PHY_DA_RX_PSBN_TBT_MASK | MTK_PHY_DA_RX_PSBN_HBT_MASK |
+				MTK_PHY_DA_RX_PSBN_GBE_MASK | MTK_PHY_DA_RX_PSBN_LP_MASK,
+				upper_idx << 12 | upper_idx << 8 | upper_idx << 4 | upper_idx);
+	}
+	if (ret < 0)
+		goto restore;
+
+	/* We calibrate TX-VCM in different logic. Check upper index and then
+	 * lower index. If this calibration is valid, apply lower index's result.
+	 */
+	ret = upper_ret-lower_ret;
+	if (ret == 1) {
+		ret = 0;
+		dev_info(&phydev->mdio.dev, "TX-VCM SW cal result: 0x%x\n", upper_idx);
+	} else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 && lower_ret == 1) {
+		ret = 0;
+		cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9,
+			MTK_PHY_DA_RX_PSBN_TBT_MASK | MTK_PHY_DA_RX_PSBN_HBT_MASK |
+			MTK_PHY_DA_RX_PSBN_GBE_MASK | MTK_PHY_DA_RX_PSBN_LP_MASK,
+			lower_idx << 12 | lower_idx << 8 | lower_idx << 4 | lower_idx);
+		dev_warn(&phydev->mdio.dev, "TX-VCM SW cal result at low margin 0x%x\n", lower_idx);
+	} else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 && lower_ret == 0) {
+		ret = 0;
+		dev_warn(&phydev->mdio.dev, "TX-VCM SW cal result at high margin 0x%x\n", upper_idx);
+	} else
+		ret = -EINVAL;
+
+restore:
+	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+		MTK_PHY_RG_ANA_CALEN);
+	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
+		MTK_PHY_RG_TXVOS_CALEN);
+	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0,
+		MTK_PHY_RG_ZCALEN_A);
+	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1,
+		MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C | MTK_PHY_RG_ZCALEN_D);
+
+	return ret;
+}
+
+static void mtk_gephy_config_init(struct phy_device *phydev)
+{
+	/* Disable EEE */
+	phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
+
+	/* Enable HW auto downshift */
+	phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4));
+
+	/* Increase SlvDPSready time */
+	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+	__phy_write(phydev, 0x10, 0xafae);
+	__phy_write(phydev, 0x12, 0x2f);
+	__phy_write(phydev, 0x10, 0x8fae);
+	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+	/* Adjust 100_mse_threshold */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff);
+
+	/* Disable mcc */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300);
+}
+
+static int mt7530_phy_config_init(struct phy_device *phydev)
+{
+	mtk_gephy_config_init(phydev);
+
+	/* Increase post_update_timer */
+	phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b);
+
+	return 0;
+}
+
+static int mt7531_phy_config_init(struct phy_device *phydev)
+{
+	if (phydev->interface != PHY_INTERFACE_MODE_INTERNAL)
+		return -EINVAL;
+
+	mtk_gephy_config_init(phydev);
+
+	/* PHY link down power saving enable */
+	phy_set_bits(phydev, 0x17, BIT(4));
+	phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300);
+
+	/* Set TX Pair delay selection */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404);
+
+	return 0;
+}
+
+static inline void mt798x_phy_finetune(struct phy_device *phydev)
+{
+	/* 100M eye finetune:
+	 * Keep middle level of TX MLT3 shapper as default.
+	 * Only change TX MLT3 overshoot level here.
+	 */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_1st_OVERSHOOT_LEVEL_0TO1, 0x1ce);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_2nd_OVERSHOOT_LEVEL_0TO1, 0x1c1);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_1st_OVERSHOOT_LEVEL_1TO0, 0x20f);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_2nd_OVERSHOOT_LEVEL_1TO0, 0x202);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_1st_OVERSHOOT_LEVEL_0TON1, 0x3d0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_2nd_OVERSHOOT_LEVEL_0TON1, 0x3c0);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_1st_OVERSHOOT_LEVEL_N1TO0, 0x13);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_2nd_OVERSHOOT_LEVEL_N1TO0, 0x5);
+#
+	/* TX-AMP finetune:
+	 * 100M +4, 1000M +6 to default value.
+	 * If efuse values aren't valid, TX-AMP uses the below values.
+	 */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, 0x9824);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, 0x9026);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, 0x2624);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, 0x2426);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, 0x2624);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, 0x2426);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, 0x2624);
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, 0x2426);
+}
+
+static int mt798x_phy_config_init(struct phy_device *phydev)
+{
+	const char *cal_mode_from_dts;
+	int i, ret, cal_ret;
+	u32 *buf;
+	bool efs_valid = true;
+	size_t len;
+	struct nvmem_cell *cell;
+
+	if (phydev->interface != PHY_INTERFACE_MODE_GMII)
+		return -EINVAL;
+
+	mt798x_phy_finetune(phydev);
+
+	cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data");
+	if (IS_ERR(cell)) {
+		if (PTR_ERR(cell) == -EPROBE_DEFER)
+			return PTR_ERR(cell);
+		return 0;
+	}
+
+	buf = (u32 *)nvmem_cell_read(cell, &len);
+	if (IS_ERR(buf))
+		return PTR_ERR(buf);
+	nvmem_cell_put(cell);
+
+	if(!buf[0] && !buf[1] && !buf[2] && !buf[3])
+		efs_valid = false;
+
+	if (len < 4 * sizeof(u32)) {
+		dev_err(&phydev->mdio.dev, "invalid calibration data\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	CAL_FLOW(rext, SW_EFUSE, cal_mode_from_dts, NO_PAIR, buf)
+	CAL_FLOW(tx_offset, EFUSE, cal_mode_from_dts, NO_PAIR, buf)
+	CAL_FLOW(tx_amp, EFUSE, cal_mode_from_dts, NO_PAIR, buf)
+	CAL_FLOW(tx_r50, SW_EFUSE, cal_mode_from_dts, PAIR_A_TO_D, buf)
+	CAL_FLOW(tx_vcm, SW, cal_mode_from_dts, PAIR_A_TO_A)
+	ret = 0;
+
+out:
+	kfree(buf);
+	return ret;
+}
+
+static struct phy_driver mtk_gephy_driver[] = {
+#if 0
+	{
+		PHY_ID_MATCH_EXACT(0x03a29412),
+		.name		= "MediaTek MT7530 PHY",
+		.config_init	= mt7530_phy_config_init,
+		/* Interrupts are handled by the switch, not the PHY
+		 * itself.
+		 */
+		.config_intr	= genphy_no_config_intr,
+		.handle_interrupt = genphy_no_ack_interrupt,
+		.suspend	= genphy_suspend,
+		.resume		= genphy_resume,
+		.read_page	= mtk_gephy_read_page,
+		.write_page	= mtk_gephy_write_page,
+	},
+	{
+		PHY_ID_MATCH_EXACT(0x03a29441),
+		.name		= "MediaTek MT7531 PHY",
+		.config_init	= mt7531_phy_config_init,
+		/* Interrupts are handled by the switch, not the PHY
+		 * itself.
+		 */
+		.config_intr	= genphy_no_config_intr,
+		.handle_interrupt = genphy_no_ack_interrupt,
+		.suspend	= genphy_suspend,
+		.resume		= genphy_resume,
+		.read_page	= mtk_gephy_read_page,
+		.write_page	= mtk_gephy_write_page,
+	},
+#endif
+	{
+		PHY_ID_MATCH_EXACT(0x03a29461),
+		.name		= "MediaTek MT798x PHY",
+		.config_init	= mt798x_phy_config_init,
+		/* Interrupts are handled by the switch, not the PHY
+		 * itself.
+		 */
+		.config_intr	= genphy_no_config_intr,
+		.handle_interrupt = genphy_no_ack_interrupt,
+		.suspend	= genphy_suspend,
+		.resume		= genphy_resume,
+		.read_page	= mtk_gephy_read_page,
+		.write_page	= mtk_gephy_write_page,
+	},
+};
+
+module_phy_driver(mtk_gephy_driver);
+
+static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = {
+	{ PHY_ID_MATCH_VENDOR(0x03a29400) },
+	{ }
+};
+
+MODULE_DESCRIPTION("MediaTek Gigabit Ethernet PHY driver");
+MODULE_AUTHOR("DENG, Qingfang <dqfext@gmail.com>");
+MODULE_LICENSE("GPL");
+
+MODULE_DEVICE_TABLE(mdio, mtk_gephy_tbl);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/Kconfig b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/Kconfig
new file mode 100644
index 0000000..d9e0230
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/Kconfig
@@ -0,0 +1,3 @@
+
+config MT753X_GSW
+	tristate "Driver for the MediaTek MT753x switch"
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/Makefile
new file mode 100755
index 0000000..e304fcb
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for MediaTek MT753x gigabit switch
+#
+
+obj-$(CONFIG_MT753X_GSW)	+= mt753x.o
+
+mt753x-$(CONFIG_SWCONFIG)	+= mt753x_swconfig.o
+
+mt753x-y			+= mt753x_mdio.o mt7530.o mt7531.o \
+					mt753x_common.o mt753x_vlan.o mt753x_nl.o
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7530.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7530.c
new file mode 100755
index 0000000..7853e27
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7530.c
@@ -0,0 +1,644 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include "mt753x.h"
+#include "mt753x_regs.h"
+
+/* MT7530 registers */
+
+/* Unique fields of PMCR for MT7530 */
+#define FORCE_MODE			BIT(15)
+
+/* Unique fields of GMACCR for MT7530 */
+#define VLAN_SUPT_NO_S			14
+#define VLAN_SUPT_NO_M			0x1c000
+#define LATE_COL_DROP			BIT(13)
+
+/* Unique fields of (M)HWSTRAP for MT7530 */
+#define BOND_OPTION			BIT(24)
+#define P5_PHY0_SEL			BIT(20)
+#define CHG_TRAP			BIT(16)
+#define LOOPDET_DIS			BIT(14)
+#define P5_INTF_SEL_GMAC5		BIT(13)
+#define SMI_ADDR_S			11
+#define SMI_ADDR_M			0x1800
+#define XTAL_FSEL_S			9
+#define XTAL_FSEL_M			0x600
+#define P6_INTF_DIS			BIT(8)
+#define P5_INTF_MODE_RGMII		BIT(7)
+#define P5_INTF_DIS_S			BIT(6)
+#define C_MDIO_BPS_S			BIT(5)
+#define EEPROM_EN_S			BIT(4)
+
+/* PHY EEE Register bitmap of define */
+#define PHY_DEV07			0x07
+#define PHY_DEV07_REG_03C		0x3c
+
+/* PHY Extend Register 0x14 bitmap of define */
+#define PHY_EXT_REG_14			0x14
+
+/* Fields of PHY_EXT_REG_14 */
+#define PHY_EN_DOWN_SHFIT		BIT(4)
+
+/* PHY Token Ring Register 0x10 bitmap of define */
+#define PHY_TR_REG_10			0x10
+
+/* PHY Token Ring Register 0x12 bitmap of define */
+#define PHY_TR_REG_12			0x12
+
+/* PHY LPI PCS/DSP Control Register bitmap of define */
+#define PHY_LPI_REG_11			0x11
+
+/* PHY DEV 0x1e Register bitmap of define */
+#define PHY_DEV1E			0x1e
+#define PHY_DEV1E_REG_123		0x123
+#define PHY_DEV1E_REG_A6		0xa6
+
+/* Values of XTAL_FSEL */
+#define XTAL_20MHZ			1
+#define XTAL_40MHZ			2
+#define XTAL_25MHZ			3
+
+/* Top single control CR define */
+#define TOP_SIG_CTRL			0x7808
+
+/* TOP_SIG_CTRL Register bitmap of define */
+#define OUTPUT_INTR_S			16
+#define OUTPUT_INTR_M			0x30000
+
+#define P6ECR				0x7830
+#define P6_INTF_MODE_TRGMII		BIT(0)
+
+#define TRGMII_TXCTRL			0x7a40
+#define TRAIN_TXEN			BIT(31)
+#define TXC_INV				BIT(30)
+#define TX_DOEO				BIT(29)
+#define TX_RST				BIT(28)
+
+#define TRGMII_TD0_CTRL			0x7a50
+#define TRGMII_TD1_CTRL			0x7a58
+#define TRGMII_TD2_CTRL			0x7a60
+#define TRGMII_TD3_CTRL			0x7a68
+#define TRGMII_TXCTL_CTRL		0x7a70
+#define TRGMII_TCK_CTRL			0x7a78
+#define TRGMII_TD_CTRL(n)		(0x7a50 + (n) * 8)
+#define NUM_TRGMII_CTRL			6
+#define TX_DMPEDRV			BIT(31)
+#define TX_DM_SR			BIT(15)
+#define TX_DMERODT			BIT(14)
+#define TX_DMOECTL			BIT(13)
+#define TX_TAP_S			8
+#define TX_TAP_M			0xf00
+#define TX_TRAIN_WD_S			0
+#define TX_TRAIN_WD_M			0xff
+
+#define TRGMII_TD0_ODT			0x7a54
+#define TRGMII_TD1_ODT			0x7a5c
+#define TRGMII_TD2_ODT			0x7a64
+#define TRGMII_TD3_ODT			0x7a6c
+#define TRGMII_TXCTL_ODT		0x7574
+#define TRGMII_TCK_ODT			0x757c
+#define TRGMII_TD_ODT(n)		(0x7a54 + (n) * 8)
+#define NUM_TRGMII_ODT			6
+#define TX_DM_DRVN_PRE_S		30
+#define TX_DM_DRVN_PRE_M		0xc0000000
+#define TX_DM_DRVP_PRE_S		28
+#define TX_DM_DRVP_PRE_M		0x30000000
+#define TX_DM_TDSEL_S			24
+#define TX_DM_TDSEL_M			0xf000000
+#define TX_ODTEN			BIT(23)
+#define TX_DME_PRE			BIT(20)
+#define TX_DM_DRVNT0			BIT(19)
+#define TX_DM_DRVPT0			BIT(18)
+#define TX_DM_DRVNTE			BIT(17)
+#define TX_DM_DRVPTE			BIT(16)
+#define TX_DM_ODTN_S			12
+#define TX_DM_ODTN_M			0x7000
+#define TX_DM_ODTP_S			8
+#define TX_DM_ODTP_M			0x700
+#define TX_DM_DRVN_S			4
+#define TX_DM_DRVN_M			0xf0
+#define TX_DM_DRVP_S			0
+#define TX_DM_DRVP_M			0x0f
+
+#define P5RGMIIRXCR			0x7b00
+#define CSR_RGMII_RCTL_CFG_S		24
+#define CSR_RGMII_RCTL_CFG_M		0x7000000
+#define CSR_RGMII_RXD_CFG_S		16
+#define CSR_RGMII_RXD_CFG_M		0x70000
+#define CSR_RGMII_EDGE_ALIGN		BIT(8)
+#define CSR_RGMII_RXC_90DEG_CFG_S	4
+#define CSR_RGMII_RXC_90DEG_CFG_M	0xf0
+#define CSR_RGMII_RXC_0DEG_CFG_S	0
+#define CSR_RGMII_RXC_0DEG_CFG_M	0x0f
+
+#define P5RGMIITXCR			0x7b04
+#define CSR_RGMII_TXEN_CFG_S		16
+#define CSR_RGMII_TXEN_CFG_M		0x70000
+#define CSR_RGMII_TXD_CFG_S		8
+#define CSR_RGMII_TXD_CFG_M		0x700
+#define CSR_RGMII_TXC_CFG_S		0
+#define CSR_RGMII_TXC_CFG_M		0x1f
+
+#define CHIP_REV			0x7ffc
+#define CHIP_NAME_S			16
+#define CHIP_NAME_M			0xffff0000
+#define CHIP_REV_S			0
+#define CHIP_REV_M			0x0f
+
+/* MMD registers */
+#define CORE_PLL_GROUP2			0x401
+#define RG_SYSPLL_EN_NORMAL		BIT(15)
+#define RG_SYSPLL_VODEN			BIT(14)
+#define RG_SYSPLL_POSDIV_S		5
+#define RG_SYSPLL_POSDIV_M		0x60
+
+#define CORE_PLL_GROUP4			0x403
+#define RG_SYSPLL_DDSFBK_EN		BIT(12)
+#define RG_SYSPLL_BIAS_EN		BIT(11)
+#define RG_SYSPLL_BIAS_LPF_EN		BIT(10)
+
+#define CORE_PLL_GROUP5			0x404
+#define RG_LCDDS_PCW_NCPO1_S		0
+#define RG_LCDDS_PCW_NCPO1_M		0xffff
+
+#define CORE_PLL_GROUP6			0x405
+#define RG_LCDDS_PCW_NCPO0_S		0
+#define RG_LCDDS_PCW_NCPO0_M		0xffff
+
+#define CORE_PLL_GROUP7			0x406
+#define RG_LCDDS_PWDB			BIT(15)
+#define RG_LCDDS_ISO_EN			BIT(13)
+#define RG_LCCDS_C_S			4
+#define RG_LCCDS_C_M			0x70
+#define RG_LCDDS_PCW_NCPO_CHG		BIT(3)
+
+#define CORE_PLL_GROUP10		0x409
+#define RG_LCDDS_SSC_DELTA_S		0
+#define RG_LCDDS_SSC_DELTA_M		0xfff
+
+#define CORE_PLL_GROUP11		0x40a
+#define RG_LCDDS_SSC_DELTA1_S		0
+#define RG_LCDDS_SSC_DELTA1_M		0xfff
+
+#define CORE_GSWPLL_GCR_1		0x040d
+#define GSWPLL_PREDIV_S			14
+#define GSWPLL_PREDIV_M			0xc000
+#define GSWPLL_POSTDIV_200M_S		12
+#define GSWPLL_POSTDIV_200M_M		0x3000
+#define GSWPLL_EN_PRE			BIT(11)
+#define GSWPLL_FBKSEL			BIT(10)
+#define GSWPLL_BP			BIT(9)
+#define GSWPLL_BR			BIT(8)
+#define GSWPLL_FBKDIV_200M_S		0
+#define GSWPLL_FBKDIV_200M_M		0xff
+
+#define CORE_GSWPLL_GCR_2		0x040e
+#define GSWPLL_POSTDIV_500M_S		8
+#define GSWPLL_POSTDIV_500M_M		0x300
+#define GSWPLL_FBKDIV_500M_S		0
+#define GSWPLL_FBKDIV_500M_M		0xff
+
+#define TRGMII_GSW_CLK_CG		0x0410
+#define TRGMIICK_EN			BIT(1)
+#define GSWCK_EN			BIT(0)
+
+static int mt7530_mii_read(struct gsw_mt753x *gsw, int phy, int reg)
+{
+	if (phy < MT753X_NUM_PHYS)
+		phy = (gsw->phy_base + phy) & MT753X_SMI_ADDR_MASK;
+
+	return mdiobus_read(gsw->host_bus, phy, reg);
+}
+
+static void mt7530_mii_write(struct gsw_mt753x *gsw, int phy, int reg, u16 val)
+{
+	if (phy < MT753X_NUM_PHYS)
+		phy = (gsw->phy_base + phy) & MT753X_SMI_ADDR_MASK;
+
+	mdiobus_write(gsw->host_bus, phy, reg, val);
+}
+
+static int mt7530_mmd_read(struct gsw_mt753x *gsw, int addr, int devad, u16 reg)
+{
+	u16 val;
+
+	if (addr < MT753X_NUM_PHYS)
+		addr = (gsw->phy_base + addr) & MT753X_SMI_ADDR_MASK;
+
+	mutex_lock(&gsw->host_bus->mdio_lock);
+
+	gsw->host_bus->write(gsw->host_bus, addr, MII_MMD_ACC_CTL_REG,
+			     (MMD_ADDR << MMD_CMD_S) |
+			     ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
+
+	gsw->host_bus->write(gsw->host_bus, addr, MII_MMD_ADDR_DATA_REG, reg);
+
+	gsw->host_bus->write(gsw->host_bus, addr, MII_MMD_ACC_CTL_REG,
+			     (MMD_DATA << MMD_CMD_S) |
+			     ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
+
+	val = gsw->host_bus->read(gsw->host_bus, addr, MII_MMD_ADDR_DATA_REG);
+
+	mutex_unlock(&gsw->host_bus->mdio_lock);
+
+	return val;
+}
+
+static void mt7530_mmd_write(struct gsw_mt753x *gsw, int addr, int devad,
+			     u16 reg, u16 val)
+{
+	if (addr < MT753X_NUM_PHYS)
+		addr = (gsw->phy_base + addr) & MT753X_SMI_ADDR_MASK;
+
+	mutex_lock(&gsw->host_bus->mdio_lock);
+
+	gsw->host_bus->write(gsw->host_bus, addr, MII_MMD_ACC_CTL_REG,
+		      (MMD_ADDR << MMD_CMD_S) |
+		      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
+
+	gsw->host_bus->write(gsw->host_bus, addr, MII_MMD_ADDR_DATA_REG, reg);
+
+	gsw->host_bus->write(gsw->host_bus, addr, MII_MMD_ACC_CTL_REG,
+		      (MMD_DATA << MMD_CMD_S) |
+		      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
+
+	gsw->host_bus->write(gsw->host_bus, addr, MII_MMD_ADDR_DATA_REG, val);
+
+	mutex_unlock(&gsw->host_bus->mdio_lock);
+}
+
+static void mt7530_core_reg_write(struct gsw_mt753x *gsw, u32 reg, u32 val)
+{
+	gsw->mmd_write(gsw, 0, 0x1f, reg, val);
+}
+
+static void mt7530_trgmii_setting(struct gsw_mt753x *gsw)
+{
+	u16 i;
+
+	mt7530_core_reg_write(gsw, CORE_PLL_GROUP5, 0x0780);
+	mdelay(1);
+	mt7530_core_reg_write(gsw, CORE_PLL_GROUP6, 0);
+	mt7530_core_reg_write(gsw, CORE_PLL_GROUP10, 0x87);
+	mdelay(1);
+	mt7530_core_reg_write(gsw, CORE_PLL_GROUP11, 0x87);
+
+	/* PLL BIAS enable */
+	mt7530_core_reg_write(gsw, CORE_PLL_GROUP4,
+			      RG_SYSPLL_DDSFBK_EN | RG_SYSPLL_BIAS_EN);
+	mdelay(1);
+
+	/* PLL LPF enable */
+	mt7530_core_reg_write(gsw, CORE_PLL_GROUP4,
+			      RG_SYSPLL_DDSFBK_EN |
+			      RG_SYSPLL_BIAS_EN | RG_SYSPLL_BIAS_LPF_EN);
+
+	/* sys PLL enable */
+	mt7530_core_reg_write(gsw, CORE_PLL_GROUP2,
+			      RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN |
+			      (1 << RG_SYSPLL_POSDIV_S));
+
+	/* LCDDDS PWDS */
+	mt7530_core_reg_write(gsw, CORE_PLL_GROUP7,
+			      (3 << RG_LCCDS_C_S) |
+			      RG_LCDDS_PWDB | RG_LCDDS_ISO_EN);
+	mdelay(1);
+
+	/* Enable MT7530 TRGMII clock */
+	mt7530_core_reg_write(gsw, TRGMII_GSW_CLK_CG, GSWCK_EN | TRGMIICK_EN);
+
+	/* lower Tx Driving */
+	for (i = 0 ; i < NUM_TRGMII_ODT; i++)
+		mt753x_reg_write(gsw, TRGMII_TD_ODT(i),
+				 (4 << TX_DM_DRVP_S) | (4 << TX_DM_DRVN_S));
+}
+
+static void mt7530_rgmii_setting(struct gsw_mt753x *gsw)
+{
+	u32 val;
+
+	mt7530_core_reg_write(gsw, CORE_PLL_GROUP5, 0x0c80);
+	mdelay(1);
+	mt7530_core_reg_write(gsw, CORE_PLL_GROUP6, 0);
+	mt7530_core_reg_write(gsw, CORE_PLL_GROUP10, 0x87);
+	mdelay(1);
+	mt7530_core_reg_write(gsw, CORE_PLL_GROUP11, 0x87);
+
+	val = mt753x_reg_read(gsw, TRGMII_TXCTRL);
+	val &= ~TXC_INV;
+	mt753x_reg_write(gsw, TRGMII_TXCTRL, val);
+
+	mt753x_reg_write(gsw, TRGMII_TCK_CTRL,
+			 (8 << TX_TAP_S) | (0x55 << TX_TRAIN_WD_S));
+}
+
+static int mt7530_mac_port_setup(struct gsw_mt753x *gsw)
+{
+	u32 hwstrap, p6ecr = 0, p5mcr, p6mcr, phyad;
+
+	hwstrap = mt753x_reg_read(gsw, MHWSTRAP);
+	hwstrap &= ~(P6_INTF_DIS | P5_INTF_MODE_RGMII | P5_INTF_DIS_S);
+	hwstrap |= P5_INTF_SEL_GMAC5;
+	if (!gsw->port5_cfg.enabled) {
+		p5mcr = FORCE_MODE;
+		hwstrap |= P5_INTF_DIS_S;
+	} else {
+		p5mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
+			MAC_MODE | MAC_TX_EN | MAC_RX_EN |
+			BKOFF_EN | BACKPR_EN;
+
+		if (gsw->port5_cfg.force_link) {
+			p5mcr |= FORCE_MODE | FORCE_LINK | FORCE_RX_FC |
+				 FORCE_TX_FC;
+			p5mcr |= gsw->port5_cfg.speed << FORCE_SPD_S;
+
+			if (gsw->port5_cfg.duplex)
+				p5mcr |= FORCE_DPX;
+		}
+
+		switch (gsw->port5_cfg.phy_mode) {
+		case PHY_INTERFACE_MODE_MII:
+		case PHY_INTERFACE_MODE_GMII:
+			break;
+		case PHY_INTERFACE_MODE_RGMII:
+			hwstrap |= P5_INTF_MODE_RGMII;
+			break;
+		default:
+			dev_info(gsw->dev, "%s is not supported by port5\n",
+				 phy_modes(gsw->port5_cfg.phy_mode));
+			p5mcr = FORCE_MODE;
+			hwstrap |= P5_INTF_DIS_S;
+		}
+
+		/* Port5 to PHY direct mode */
+		if (of_property_read_u32(gsw->port5_cfg.np, "phy-address",
+					 &phyad))
+			goto parse_p6;
+
+		if (phyad != 0 && phyad != 4) {
+			dev_info(gsw->dev,
+				 "Only PHY 0/4 can be connected to Port 5\n");
+			goto parse_p6;
+		}
+
+		hwstrap &= ~P5_INTF_SEL_GMAC5;
+		if (phyad == 0)
+			hwstrap |= P5_PHY0_SEL;
+		else
+			hwstrap &= ~P5_PHY0_SEL;
+	}
+
+parse_p6:
+	if (!gsw->port6_cfg.enabled) {
+		p6mcr = FORCE_MODE;
+		hwstrap |= P6_INTF_DIS;
+	} else {
+		p6mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
+			MAC_MODE | MAC_TX_EN | MAC_RX_EN |
+			BKOFF_EN | BACKPR_EN;
+
+		if (gsw->port6_cfg.force_link) {
+			p6mcr |= FORCE_MODE | FORCE_LINK | FORCE_RX_FC |
+				 FORCE_TX_FC;
+			p6mcr |= gsw->port6_cfg.speed << FORCE_SPD_S;
+
+			if (gsw->port6_cfg.duplex)
+				p6mcr |= FORCE_DPX;
+		}
+
+		switch (gsw->port6_cfg.phy_mode) {
+		case PHY_INTERFACE_MODE_RGMII:
+			p6ecr = BIT(1);
+			break;
+		case PHY_INTERFACE_MODE_TRGMII:
+			/* set MT7530 central align */
+			p6ecr = BIT(0);
+			break;
+		default:
+			dev_info(gsw->dev, "%s is not supported by port6\n",
+				 phy_modes(gsw->port6_cfg.phy_mode));
+			p6mcr = FORCE_MODE;
+			hwstrap |= P6_INTF_DIS;
+		}
+	}
+
+	mt753x_reg_write(gsw, MHWSTRAP, hwstrap);
+	mt753x_reg_write(gsw, P6ECR, p6ecr);
+
+	mt753x_reg_write(gsw, PMCR(5), p5mcr);
+	mt753x_reg_write(gsw, PMCR(6), p6mcr);
+
+	return 0;
+}
+
+static void mt7530_core_pll_setup(struct gsw_mt753x *gsw)
+{
+	u32 hwstrap;
+
+	hwstrap = mt753x_reg_read(gsw, HWSTRAP);
+
+	switch ((hwstrap & XTAL_FSEL_M) >> XTAL_FSEL_S) {
+	case XTAL_40MHZ:
+		/* Disable MT7530 core clock */
+		mt7530_core_reg_write(gsw, TRGMII_GSW_CLK_CG, 0);
+
+		/* disable MT7530 PLL */
+		mt7530_core_reg_write(gsw, CORE_GSWPLL_GCR_1,
+				      (2 << GSWPLL_POSTDIV_200M_S) |
+				      (32 << GSWPLL_FBKDIV_200M_S));
+
+		/* For MT7530 core clock = 500Mhz */
+		mt7530_core_reg_write(gsw, CORE_GSWPLL_GCR_2,
+				      (1 << GSWPLL_POSTDIV_500M_S) |
+				      (25 << GSWPLL_FBKDIV_500M_S));
+
+		/* Enable MT7530 PLL */
+		mt7530_core_reg_write(gsw, CORE_GSWPLL_GCR_1,
+				      (2 << GSWPLL_POSTDIV_200M_S) |
+				      (32 << GSWPLL_FBKDIV_200M_S) |
+				      GSWPLL_EN_PRE);
+
+		usleep_range(20, 40);
+
+		/* Enable MT7530 core clock */
+		mt7530_core_reg_write(gsw, TRGMII_GSW_CLK_CG, GSWCK_EN);
+		break;
+	default:
+		/* TODO: PLL settings for 20/25MHz */
+		break;
+	}
+
+	hwstrap = mt753x_reg_read(gsw, HWSTRAP);
+	hwstrap |= CHG_TRAP;
+	if (gsw->direct_phy_access)
+		hwstrap &= ~C_MDIO_BPS_S;
+	else
+		hwstrap |= C_MDIO_BPS_S;
+
+	mt753x_reg_write(gsw, MHWSTRAP, hwstrap);
+
+	if (gsw->port6_cfg.enabled &&
+	    gsw->port6_cfg.phy_mode == PHY_INTERFACE_MODE_TRGMII) {
+		mt7530_trgmii_setting(gsw);
+	} else {
+		/* RGMII */
+		mt7530_rgmii_setting(gsw);
+	}
+
+	/* delay setting for 10/1000M */
+	mt753x_reg_write(gsw, P5RGMIIRXCR,
+			 CSR_RGMII_EDGE_ALIGN |
+			 (2 << CSR_RGMII_RXC_0DEG_CFG_S));
+	mt753x_reg_write(gsw, P5RGMIITXCR, 0x14 << CSR_RGMII_TXC_CFG_S);
+}
+
+static int mt7530_sw_detect(struct gsw_mt753x *gsw, struct chip_rev *crev)
+{
+	u32 rev;
+
+	rev = mt753x_reg_read(gsw, CHIP_REV);
+
+	if (((rev & CHIP_NAME_M) >> CHIP_NAME_S) == MT7530) {
+		if (crev) {
+			crev->rev = rev & CHIP_REV_M;
+			crev->name = "MT7530";
+		}
+
+		return 0;
+	}
+
+	return -ENODEV;
+}
+
+static void mt7530_phy_setting(struct gsw_mt753x *gsw)
+{
+	int i;
+	u32 val;
+
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		/* Disable EEE */
+		gsw->mmd_write(gsw, i, PHY_DEV07, PHY_DEV07_REG_03C, 0);
+
+		/* Enable HW auto downshift */
+		gsw->mii_write(gsw, i, 0x1f, 0x1);
+		val = gsw->mii_read(gsw, i, PHY_EXT_REG_14);
+		val |= PHY_EN_DOWN_SHFIT;
+		gsw->mii_write(gsw, i, PHY_EXT_REG_14, val);
+
+		/* Increase SlvDPSready time */
+		gsw->mii_write(gsw, i, 0x1f, 0x52b5);
+		gsw->mii_write(gsw, i, PHY_TR_REG_10, 0xafae);
+		gsw->mii_write(gsw, i, PHY_TR_REG_12, 0x2f);
+		gsw->mii_write(gsw, i, PHY_TR_REG_10, 0x8fae);
+
+		/* Increase post_update_timer */
+		gsw->mii_write(gsw, i, 0x1f, 0x3);
+		gsw->mii_write(gsw, i, PHY_LPI_REG_11, 0x4b);
+		gsw->mii_write(gsw, i, 0x1f, 0);
+
+		/* Adjust 100_mse_threshold */
+		gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_123, 0xffff);
+
+		/* Disable mcc */
+		gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_A6, 0x300);
+	}
+}
+
+static inline bool get_phy_access_mode(const struct device_node *np)
+{
+	return of_property_read_bool(np, "mt7530,direct-phy-access");
+}
+
+static int mt7530_sw_init(struct gsw_mt753x *gsw)
+{
+	int i;
+	u32 val;
+
+	gsw->direct_phy_access = get_phy_access_mode(gsw->dev->of_node);
+
+	/* Force MT7530 to use (in)direct PHY access */
+	val = mt753x_reg_read(gsw, HWSTRAP);
+	val |= CHG_TRAP;
+	if (gsw->direct_phy_access)
+		val &= ~C_MDIO_BPS_S;
+	else
+		val |= C_MDIO_BPS_S;
+	mt753x_reg_write(gsw, MHWSTRAP, val);
+
+	/* Read PHY address base from HWSTRAP */
+	gsw->phy_base  = (((val & SMI_ADDR_M) >> SMI_ADDR_S) << 3) + 8;
+	gsw->phy_base &= MT753X_SMI_ADDR_MASK;
+
+	if (gsw->direct_phy_access) {
+		gsw->mii_read = mt7530_mii_read;
+		gsw->mii_write = mt7530_mii_write;
+		gsw->mmd_read = mt7530_mmd_read;
+		gsw->mmd_write = mt7530_mmd_write;
+	} else {
+		gsw->mii_read = mt753x_mii_read;
+		gsw->mii_write = mt753x_mii_write;
+		gsw->mmd_read = mt753x_mmd_ind_read;
+		gsw->mmd_write = mt753x_mmd_ind_write;
+	}
+
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		val = gsw->mii_read(gsw, i, MII_BMCR);
+		val |= BMCR_PDOWN;
+		gsw->mii_write(gsw, i, MII_BMCR, val);
+	}
+
+	/* Force MAC link down before reset */
+	mt753x_reg_write(gsw, PMCR(5), FORCE_MODE);
+	mt753x_reg_write(gsw, PMCR(6), FORCE_MODE);
+
+	/* Switch soft reset */
+	/* BUG: sw reset causes gsw int flooding */
+	mt753x_reg_write(gsw, SYS_CTRL, SW_PHY_RST | SW_SYS_RST | SW_REG_RST);
+	usleep_range(10, 20);
+
+	/* global mac control settings configuration */
+	mt753x_reg_write(gsw, GMACCR,
+			 LATE_COL_DROP | (15 << MTCC_LMT_S) |
+			 (2 << MAX_RX_JUMBO_S) | RX_PKT_LEN_MAX_JUMBO);
+
+	/* Output INTR selected */
+	val = mt753x_reg_read(gsw, TOP_SIG_CTRL);
+	val &= ~OUTPUT_INTR_M;
+	val |= (3 << OUTPUT_INTR_S);
+	mt753x_reg_write(gsw, TOP_SIG_CTRL, val);
+
+	mt7530_core_pll_setup(gsw);
+	mt7530_mac_port_setup(gsw);
+
+	return 0;
+}
+
+static int mt7530_sw_post_init(struct gsw_mt753x *gsw)
+{
+	int i;
+	u32 val;
+
+	mt7530_phy_setting(gsw);
+
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		val = gsw->mii_read(gsw, i, MII_BMCR);
+		val &= ~BMCR_PDOWN;
+		gsw->mii_write(gsw, i, MII_BMCR, val);
+	}
+
+	return 0;
+}
+
+struct mt753x_sw_id mt7530_id = {
+	.model = MT7530,
+	.detect = mt7530_sw_detect,
+	.init = mt7530_sw_init,
+	.post_init = mt7530_sw_post_init
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7530.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7530.h
new file mode 100644
index 0000000..40243d4
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7530.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ */
+
+#ifndef _MT7530_H_
+#define _MT7530_H_
+
+#include "mt753x.h"
+
+extern struct mt753x_sw_id mt7530_id;
+
+#endif /* _MT7530_H_ */
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
new file mode 100755
index 0000000..7253042
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.c
@@ -0,0 +1,1058 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Zhanguo Ju <zhanguo.ju@mediatek.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/hrtimer.h>
+
+#include "mt753x.h"
+#include "mt753x_regs.h"
+
+/* MT7531 registers */
+#define SGMII_REG_BASE			0x5000
+#define SGMII_REG_PORT_BASE		0x1000
+#define SGMII_REG(p, r)			(SGMII_REG_BASE + \
+					(p) * SGMII_REG_PORT_BASE + (r))
+#define PCS_CONTROL_1(p)		SGMII_REG(p, 0x00)
+#define SGMII_MODE(p)			SGMII_REG(p, 0x20)
+#define QPHY_PWR_STATE_CTRL(p)		SGMII_REG(p, 0xe8)
+#define ANA_CKBG(p)			SGMII_REG(p, 0x100)
+#define ANA_DA_FORCE_MODE1(p)		SGMII_REG(p, 0x110)
+#define PHYA_CTRL_SIGNAL3(p)		SGMII_REG(p, 0x128)
+#define PHYA_ANA_SYSPLL(p)		SGMII_REG(p, 0x158)
+
+/* Fields of PCS_CONTROL_1 */
+#define SGMII_LINK_STATUS		BIT(18)
+#define SGMII_AN_ENABLE			BIT(12)
+#define SGMII_AN_RESTART		BIT(9)
+
+/* Fields of SGMII_MODE */
+#define SGMII_REMOTE_FAULT_DIS		BIT(8)
+#define SGMII_IF_MODE_FORCE_DUPLEX	BIT(4)
+#define SGMII_IF_MODE_FORCE_SPEED_S	0x2
+#define SGMII_IF_MODE_FORCE_SPEED_M	0x0c
+#define SGMII_IF_MODE_ADVERT_AN		BIT(1)
+
+/* Values of SGMII_IF_MODE_FORCE_SPEED */
+#define SGMII_IF_MODE_FORCE_SPEED_10	0
+#define SGMII_IF_MODE_FORCE_SPEED_100	1
+#define SGMII_IF_MODE_FORCE_SPEED_1000	2
+
+/* Fields of QPHY_PWR_STATE_CTRL */
+#define PHYA_PWD			BIT(4)
+
+/* Fields of ANA_CKBG */
+#define SSUSB_PLL_SSC_EN		BIT(21)
+
+/* Fields of ANA_DA_FORCE_MODE1 */
+#define FORCE_PLL_SSC_EN		BIT(30)
+
+/* Fields of PHYA_CTRL_SIGNAL3 */
+#define RG_TPHY_SPEED_S			2
+#define RG_TPHY_SPEED_M			0x0c
+
+/* Values of RG_TPHY_SPEED */
+#define RG_TPHY_SPEED_1000		0
+#define RG_TPHY_SPEED_2500		1
+
+/* Fields of PHYA_ANA_SYSPLL */
+#define RG_VUSB10_ON			BIT(29)
+
+/* Unique fields of (M)HWSTRAP for MT7531 */
+#define XTAL_FSEL_S			7
+#define XTAL_FSEL_M			BIT(7)
+#define PHY_EN				BIT(6)
+#define CHG_STRAP			BIT(8)
+
+/* Efuse Register Define */
+#define GBE_EFUSE			0x7bc8
+#define GBE_SEL_EFUSE_EN		BIT(0)
+
+/* PHY ENABLE Register bitmap define */
+#define PHY_DEV1F			0x1f
+#define PHY_DEV1F_REG_44		0x44
+#define PHY_DEV1F_REG_104		0x104
+#define PHY_DEV1F_REG_10A		0x10a
+#define PHY_DEV1F_REG_10B		0x10b
+#define PHY_DEV1F_REG_10C		0x10c
+#define PHY_DEV1F_REG_10D		0x10d
+#define PHY_DEV1F_REG_268		0x268
+#define PHY_DEV1F_REG_269		0x269
+#define PHY_DEV1F_REG_26A		0x26A
+#define PHY_DEV1F_REG_403		0x403
+
+/* Fields of PHY_DEV1F_REG_403 */
+#define GBE_EFUSE_SETTING		BIT(3)
+#define PHY_EN_BYPASS_MODE		BIT(4)
+#define POWER_ON_OFF			BIT(5)
+#define PHY_PLL_M			GENMASK(9, 8)
+#define PHY_PLL_SEL(x)			(((x) << 8) & GENMASK(9, 8))
+
+/* PHY EEE Register bitmap of define */
+#define PHY_DEV07			0x07
+#define PHY_DEV07_REG_03C		0x3c
+
+/* PHY Extend Register 0x14 bitmap of define */
+#define PHY_EXT_REG_14			0x14
+
+/* Fields of PHY_EXT_REG_14 */
+#define PHY_EN_DOWN_SHFIT		BIT(4)
+
+/* PHY Extend Register 0x17 bitmap of define */
+#define PHY_EXT_REG_17			0x17
+
+/* Fields of PHY_EXT_REG_17 */
+#define PHY_LINKDOWN_POWER_SAVING_EN	BIT(4)
+
+/* PHY PMA Register 0x17 bitmap of define */
+#define SLV_DSP_READY_TIME_S		15
+#define SLV_DSP_READY_TIME_M		(0xff << SLV_DSP_READY_TIME_S)
+
+/* PHY PMA Register 0x18 bitmap of define */
+#define ENABLE_RANDOM_UPDATE_TRIGGER	BIT(8)
+
+/* PHY DEV 0x1e Register bitmap of define */
+#define PHY_DEV1E			0x1e
+#define PHY_TX_MLT3_BASE		0x0
+#define PHY_DEV1E_REG_13		0x13
+#define PHY_DEV1E_REG_14		0x14
+#define PHY_DEV1E_REG_41		0x41
+#define PHY_DEV1E_REG_A6		0xa6
+#define PHY_DEV1E_REG_0C6		0x0c6
+#define PHY_DEV1E_REG_0FE		0x0fe
+#define PHY_DEV1E_REG_123		0x123
+#define PHY_DEV1E_REG_141		0x141
+#define PHY_DEV1E_REG_189		0x189
+#define PHY_DEV1E_REG_234		0x234
+
+/* Fields of PHY_DEV1E_REG_0C6 */
+#define PHY_POWER_SAVING_S		8
+#define PHY_POWER_SAVING_M		0x300
+#define PHY_POWER_SAVING_TX		0x0
+
+/* Fields of PHY_DEV1E_REG_189 */
+#define DESCRAMBLER_CLEAR_EN		0x1
+
+/* Fields of PHY_DEV1E_REG_234 */
+#define TR_OPEN_LOOP_EN			BIT(0)
+
+/* Port debug count register */
+#define DBG_CNT_BASE			0x3018
+#define DBG_CNT_PORT_BASE		0x100
+#define DBG_CNT(p)			(DBG_CNT_BASE + \
+					(p) * DBG_CNT_PORT_BASE)
+#define DIS_CLR				BIT(31)
+
+/* Values of XTAL_FSEL_S */
+#define XTAL_40MHZ			0
+#define XTAL_25MHZ			1
+
+#define PLLGP_EN			0x7820
+#define EN_COREPLL			BIT(2)
+#define SW_CLKSW			BIT(1)
+#define SW_PLLGP			BIT(0)
+
+#define PLLGP_CR0			0x78a8
+#define RG_COREPLL_EN			BIT(22)
+#define RG_COREPLL_POSDIV_S		23
+#define RG_COREPLL_POSDIV_M		0x3800000
+#define RG_COREPLL_SDM_PCW_S		1
+#define RG_COREPLL_SDM_PCW_M		0x3ffffe
+#define RG_COREPLL_SDM_PCW_CHG		BIT(0)
+
+/* TOP Signals Status Register */
+#define TOP_SIG_SR			0x780c
+#define PAD_MCM_SMI_EN			BIT(0)
+#define PAD_DUAL_SGMII_EN		BIT(1)
+
+/* RGMII and SGMII PLL clock */
+#define ANA_PLLGP_CR2			0x78b0
+#define ANA_PLLGP_CR5			0x78bc
+
+/* GPIO mode define */
+#define GPIO_MODE_REGS(x)		(0x7c0c + (((x) / 8) * 4))
+#define GPIO_MODE_S			4
+
+/* GPIO GROUP IOLB SMT0 Control */
+#define SMT0_IOLB			0x7f04
+#define SMT_IOLB_5_SMI_MDC_EN		BIT(5)
+
+/* Unique fields of PMCR for MT7531 */
+#define FORCE_MODE_EEE1G		BIT(25)
+#define FORCE_MODE_EEE100		BIT(26)
+#define FORCE_MODE_TX_FC		BIT(27)
+#define FORCE_MODE_RX_FC		BIT(28)
+#define FORCE_MODE_DPX			BIT(29)
+#define FORCE_MODE_SPD			BIT(30)
+#define FORCE_MODE_LNK			BIT(31)
+#define FORCE_MODE			BIT(15)
+
+#define CHIP_REV			0x781C
+#define CHIP_NAME_S			16
+#define CHIP_NAME_M			0xffff0000
+#define CHIP_REV_S			0
+#define CHIP_REV_M			0x0f
+#define CHIP_REV_E1			0x0
+
+#define CLKGEN_CTRL			0x7500
+#define CLK_SKEW_OUT_S			8
+#define CLK_SKEW_OUT_M			0x300
+#define CLK_SKEW_IN_S			6
+#define CLK_SKEW_IN_M			0xc0
+#define RXCLK_NO_DELAY			BIT(5)
+#define TXCLK_NO_REVERSE		BIT(4)
+#define GP_MODE_S			1
+#define GP_MODE_M			0x06
+#define GP_CLK_EN			BIT(0)
+
+#define CPGC_CTRL			0xB0
+#define COL_EN				BIT(0)
+#define COL_CLK_EN			BIT(1)
+#define COL_RST_N			BIT(2)
+#define COL_BUSY			BIT(3)
+
+/* Values of GP_MODE */
+#define GP_MODE_RGMII			0
+#define GP_MODE_MII			1
+#define GP_MODE_REV_MII			2
+
+/* Values of CLK_SKEW_IN */
+#define CLK_SKEW_IN_NO_CHANGE		0
+#define CLK_SKEW_IN_DELAY_100PPS	1
+#define CLK_SKEW_IN_DELAY_200PPS	2
+#define CLK_SKEW_IN_REVERSE		3
+
+/* Values of CLK_SKEW_OUT */
+#define CLK_SKEW_OUT_NO_CHANGE		0
+#define CLK_SKEW_OUT_DELAY_100PPS	1
+#define CLK_SKEW_OUT_DELAY_200PPS	2
+#define CLK_SKEW_OUT_REVERSE		3
+
+/* Proprietory Control Register of Internal Phy device 0x1e */
+#define RXADC_CONTROL_3			0xc2
+#define RXADC_LDO_CONTROL_2		0xd3
+
+/* Proprietory Control Register of Internal Phy device 0x1f */
+#define TXVLD_DA_271			0x271
+#define TXVLD_DA_272			0x272
+#define TXVLD_DA_273			0x273
+
+/* gpio pinmux pins and functions define */
+static int gpio_int_pins[] = {0};
+static int gpio_int_funcs[] = {1};
+static int gpio_mdc_pins[] = {11, 20};
+static int gpio_mdc_funcs[] = {2, 2};
+static int gpio_mdio_pins[] = {12, 21};
+static int gpio_mdio_funcs[] = {2, 2};
+
+static int mt7531_set_port_sgmii_force_mode(struct gsw_mt753x *gsw, u32 port,
+					    struct mt753x_port_cfg *port_cfg)
+{
+	u32 speed, port_base, val;
+	ktime_t timeout;
+	u32 timeout_us;
+
+	if (port < 5 || port >= MT753X_NUM_PORTS) {
+		dev_info(gsw->dev, "port %d is not a SGMII port\n", port);
+		return -EINVAL;
+	}
+
+	port_base = port - 5;
+
+	switch (port_cfg->speed) {
+	case MAC_SPD_1000:
+		speed = RG_TPHY_SPEED_1000;
+		break;
+	case MAC_SPD_2500:
+		speed = RG_TPHY_SPEED_2500;
+		break;
+	default:
+		dev_info(gsw->dev, "invalid SGMII speed idx %d for port %d\n",
+			 port_cfg->speed, port);
+
+		speed = RG_TPHY_SPEED_1000;
+	}
+
+	/* Step 1: Speed select register setting */
+	val = mt753x_reg_read(gsw, PHYA_CTRL_SIGNAL3(port_base));
+	val &= ~RG_TPHY_SPEED_M;
+	val |= speed << RG_TPHY_SPEED_S;
+	mt753x_reg_write(gsw, PHYA_CTRL_SIGNAL3(port_base), val);
+
+	/* Step 2 : Disable AN */
+	val = mt753x_reg_read(gsw, PCS_CONTROL_1(port_base));
+	val &= ~SGMII_AN_ENABLE;
+	mt753x_reg_write(gsw, PCS_CONTROL_1(port_base), val);
+
+	/* Step 3: SGMII force mode setting */
+	val = mt753x_reg_read(gsw, SGMII_MODE(port_base));
+	val &= ~SGMII_IF_MODE_ADVERT_AN;
+	val &= ~SGMII_IF_MODE_FORCE_SPEED_M;
+	val |= SGMII_IF_MODE_FORCE_SPEED_1000 << SGMII_IF_MODE_FORCE_SPEED_S;
+	val |= SGMII_IF_MODE_FORCE_DUPLEX;
+	/* For sgmii force mode, 0 is full duplex and 1 is half duplex */
+	if (port_cfg->duplex)
+		val &= ~SGMII_IF_MODE_FORCE_DUPLEX;
+
+	mt753x_reg_write(gsw, SGMII_MODE(port_base), val);
+
+	/* Step 4: XXX: Disable Link partner's AN and set force mode */
+
+	/* Step 5: XXX: Special setting for PHYA ==> reserved for flexible */
+
+	/* Step 6 : Release PHYA power down state */
+	val = mt753x_reg_read(gsw, QPHY_PWR_STATE_CTRL(port_base));
+	val &= ~PHYA_PWD;
+	mt753x_reg_write(gsw, QPHY_PWR_STATE_CTRL(port_base), val);
+
+	/* Step 7 : Polling SGMII_LINK_STATUS */
+	timeout_us = 2000000;
+	timeout = ktime_add_us(ktime_get(), timeout_us);
+	while (1) {
+		val = mt753x_reg_read(gsw, PCS_CONTROL_1(port_base));
+		val &= SGMII_LINK_STATUS;
+
+		if (val)
+			break;
+
+		if (ktime_compare(ktime_get(), timeout) > 0)
+			return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int mt7531_set_port_sgmii_an_mode(struct gsw_mt753x *gsw, u32 port,
+					 struct mt753x_port_cfg *port_cfg)
+{
+	u32 speed, port_base, val;
+	ktime_t timeout;
+	u32 timeout_us;
+
+	if (port < 5 || port >= MT753X_NUM_PORTS) {
+		dev_info(gsw->dev, "port %d is not a SGMII port\n", port);
+		return -EINVAL;
+	}
+
+	port_base = port - 5;
+
+	switch (port_cfg->speed) {
+	case MAC_SPD_1000:
+		speed = RG_TPHY_SPEED_1000;
+		break;
+	case MAC_SPD_2500:
+		speed = RG_TPHY_SPEED_2500;
+		break;
+	default:
+		dev_info(gsw->dev, "invalid SGMII speed idx %d for port %d\n",
+			 port_cfg->speed, port);
+
+		speed = RG_TPHY_SPEED_1000;
+	}
+
+	/* Step 1: Speed select register setting */
+	val = mt753x_reg_read(gsw, PHYA_CTRL_SIGNAL3(port_base));
+	val &= ~RG_TPHY_SPEED_M;
+	val |= speed << RG_TPHY_SPEED_S;
+	mt753x_reg_write(gsw, PHYA_CTRL_SIGNAL3(port_base), val);
+
+	/* Step 2: Remote fault disable */
+	val = mt753x_reg_read(gsw, SGMII_MODE(port));
+	val |= SGMII_REMOTE_FAULT_DIS;
+	mt753x_reg_write(gsw, SGMII_MODE(port), val);
+
+	/* Step 3: Setting Link partner's AN enable = 1 */
+
+	/* Step 4: Setting Link partner's device ability for speed/duplex */
+
+	/* Step 5: AN re-start */
+	val = mt753x_reg_read(gsw, PCS_CONTROL_1(port));
+	val |= SGMII_AN_RESTART;
+	mt753x_reg_write(gsw, PCS_CONTROL_1(port), val);
+
+	/* Step 6: Special setting for PHYA ==> reserved for flexible */
+
+	/* Step 7 : Polling SGMII_LINK_STATUS */
+	timeout_us = 2000000;
+	timeout = ktime_add_us(ktime_get(), timeout_us);
+	while (1) {
+		val = mt753x_reg_read(gsw, PCS_CONTROL_1(port_base));
+		val &= SGMII_LINK_STATUS;
+
+		if (val)
+			break;
+
+		if (ktime_compare(ktime_get(), timeout) > 0)
+			return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static void mt7531_sgmii_ssc(struct gsw_mt753x *gsw, u32 port, int enable)
+{
+	u32 val;
+	u32 port_base = port - 5;
+
+	if (enable) {
+		val = mt753x_reg_read(gsw, ANA_CKBG(port_base));
+		val |= SSUSB_PLL_SSC_EN;
+		mt753x_reg_write(gsw, ANA_CKBG(port_base), val);
+
+		val = mt753x_reg_read(gsw, ANA_DA_FORCE_MODE1(port_base));
+		val |= FORCE_PLL_SSC_EN;
+		mt753x_reg_write(gsw, ANA_DA_FORCE_MODE1(port_base), val);
+	} else {
+		val = mt753x_reg_read(gsw, ANA_CKBG(port_base));
+		val &= ~SSUSB_PLL_SSC_EN;
+		mt753x_reg_write(gsw, ANA_CKBG(port_base), val);
+
+		val = mt753x_reg_read(gsw, ANA_DA_FORCE_MODE1(port_base));
+		val &= ~FORCE_PLL_SSC_EN;
+		mt753x_reg_write(gsw, ANA_DA_FORCE_MODE1(port_base), val);
+	}
+}
+
+static int mt7531_set_port_rgmii(struct gsw_mt753x *gsw, u32 port)
+{
+	u32 val;
+
+	if (port != 5) {
+		dev_info(gsw->dev, "RGMII mode is not available for port %d\n",
+			 port);
+		return -EINVAL;
+	}
+
+	val = mt753x_reg_read(gsw, CLKGEN_CTRL);
+	val |= GP_CLK_EN;
+	val &= ~GP_MODE_M;
+	val |= GP_MODE_RGMII << GP_MODE_S;
+	val |= TXCLK_NO_REVERSE;
+	val |= RXCLK_NO_DELAY;
+	val &= ~CLK_SKEW_IN_M;
+	val |= CLK_SKEW_IN_NO_CHANGE << CLK_SKEW_IN_S;
+	val &= ~CLK_SKEW_OUT_M;
+	val |= CLK_SKEW_OUT_NO_CHANGE << CLK_SKEW_OUT_S;
+	mt753x_reg_write(gsw, CLKGEN_CTRL, val);
+
+	return 0;
+}
+
+static int mt7531_mac_port_setup(struct gsw_mt753x *gsw, u32 port,
+				 struct mt753x_port_cfg *port_cfg)
+{
+	u32 pmcr;
+	u32 speed;
+
+	if (port < 5 || port >= MT753X_NUM_PORTS) {
+		dev_info(gsw->dev, "port %d is not a MAC port\n", port);
+		return -EINVAL;
+	}
+
+	if (port_cfg->enabled) {
+		pmcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
+		       MAC_MODE | MAC_TX_EN | MAC_RX_EN |
+		       BKOFF_EN | BACKPR_EN;
+
+		if (port_cfg->force_link) {
+			/* PMCR's speed field 0x11 is reserved,
+			 * sw should set 0x10
+			 */
+			speed = port_cfg->speed;
+			if (port_cfg->speed == MAC_SPD_2500)
+				speed = MAC_SPD_1000;
+
+			pmcr |= FORCE_MODE_LNK | FORCE_LINK |
+				FORCE_MODE_SPD | FORCE_MODE_DPX |
+				FORCE_MODE_RX_FC | FORCE_MODE_TX_FC |
+				FORCE_RX_FC | FORCE_TX_FC |
+				(speed << FORCE_SPD_S);
+
+			if (port_cfg->duplex)
+				pmcr |= FORCE_DPX;
+		}
+	} else {
+		pmcr = FORCE_MODE_LNK;
+	}
+
+	switch (port_cfg->phy_mode) {
+	case PHY_INTERFACE_MODE_RGMII:
+		mt7531_set_port_rgmii(gsw, port);
+		break;
+	case PHY_INTERFACE_MODE_SGMII:
+		if (port_cfg->force_link)
+			mt7531_set_port_sgmii_force_mode(gsw, port, port_cfg);
+		else
+			mt7531_set_port_sgmii_an_mode(gsw, port, port_cfg);
+
+		mt7531_sgmii_ssc(gsw, port, port_cfg->ssc_on);
+		break;
+	default:
+		if (port_cfg->enabled)
+			dev_info(gsw->dev, "%s is not supported by port %d\n",
+				 phy_modes(port_cfg->phy_mode), port);
+
+		pmcr = FORCE_MODE_LNK;
+	}
+
+	mt753x_reg_write(gsw, PMCR(port), pmcr);
+
+	return 0;
+}
+
+static void mt7531_core_pll_setup(struct gsw_mt753x *gsw)
+{
+	u32 val;
+	u32 top_sig;
+	u32 hwstrap;
+	u32 xtal;
+
+	val = mt753x_reg_read(gsw, CHIP_REV);
+	top_sig = mt753x_reg_read(gsw, TOP_SIG_SR);
+	hwstrap = mt753x_reg_read(gsw, HWSTRAP);
+	if ((val & CHIP_REV_M) > 0)
+		xtal = (top_sig & PAD_MCM_SMI_EN) ? XTAL_40MHZ : XTAL_25MHZ;
+	else
+		xtal = (hwstrap & XTAL_FSEL_M) >> XTAL_FSEL_S;
+
+	/* dump HW strap and XTAL */
+	dev_info(gsw->dev, "HWSTRAP=0x%x XTAL=%dMHz\n", hwstrap,
+		 (xtal == XTAL_25MHZ) ? 25 : 40);
+
+	/* Only BE needs additional setting */
+	if (top_sig & PAD_DUAL_SGMII_EN)
+		return;
+
+	/* Disable Port5 SGMII clearly */
+	val = mt753x_reg_read(gsw, PHYA_ANA_SYSPLL(0));
+	val &= ~RG_VUSB10_ON;
+	mt753x_reg_write(gsw, PHYA_ANA_SYSPLL(0), val);
+
+	switch (xtal) {
+	case XTAL_25MHZ:
+		/* Step 1 : Disable MT7531 COREPLL */
+		val = mt753x_reg_read(gsw, PLLGP_EN);
+		val &= ~EN_COREPLL;
+		mt753x_reg_write(gsw, PLLGP_EN, val);
+
+		/* Step 2: switch to XTAL output */
+		val = mt753x_reg_read(gsw, PLLGP_EN);
+		val |= SW_CLKSW;
+		mt753x_reg_write(gsw, PLLGP_EN, val);
+
+		val = mt753x_reg_read(gsw, PLLGP_CR0);
+		val &= ~RG_COREPLL_EN;
+		mt753x_reg_write(gsw, PLLGP_CR0, val);
+
+		/* Step 3: disable PLLGP and enable program PLLGP */
+		val = mt753x_reg_read(gsw, PLLGP_EN);
+		val |= SW_PLLGP;
+		mt753x_reg_write(gsw, PLLGP_EN, val);
+
+		/* Step 4: program COREPLL output frequency to 500MHz */
+		val = mt753x_reg_read(gsw, PLLGP_CR0);
+		val &= ~RG_COREPLL_POSDIV_M;
+		val |= 2 << RG_COREPLL_POSDIV_S;
+		mt753x_reg_write(gsw, PLLGP_CR0, val);
+		usleep_range(25, 35);
+
+		val = mt753x_reg_read(gsw, PLLGP_CR0);
+		val &= ~RG_COREPLL_SDM_PCW_M;
+		val |= 0x140000 << RG_COREPLL_SDM_PCW_S;
+		mt753x_reg_write(gsw, PLLGP_CR0, val);
+
+		/* Set feedback divide ratio update signal to high */
+		val = mt753x_reg_read(gsw, PLLGP_CR0);
+		val |= RG_COREPLL_SDM_PCW_CHG;
+		mt753x_reg_write(gsw, PLLGP_CR0, val);
+		/* Wait for at least 16 XTAL clocks */
+		usleep_range(10, 20);
+
+		/* Step 5: set feedback divide ratio update signal to low */
+		val = mt753x_reg_read(gsw, PLLGP_CR0);
+		val &= ~RG_COREPLL_SDM_PCW_CHG;
+		mt753x_reg_write(gsw, PLLGP_CR0, val);
+
+		/* Enable 325M clock for SGMII */
+		mt753x_reg_write(gsw, ANA_PLLGP_CR5, 0xad0000);
+
+		/* Enable 250SSC clock for RGMII */
+		mt753x_reg_write(gsw, ANA_PLLGP_CR2, 0x4f40000);
+
+		/* Step 6: Enable MT7531 PLL */
+		val = mt753x_reg_read(gsw, PLLGP_CR0);
+		val |= RG_COREPLL_EN;
+		mt753x_reg_write(gsw, PLLGP_CR0, val);
+
+		val = mt753x_reg_read(gsw, PLLGP_EN);
+		val |= EN_COREPLL;
+		mt753x_reg_write(gsw, PLLGP_EN, val);
+		usleep_range(25, 35);
+
+		break;
+	case XTAL_40MHZ:
+		/* Step 1 : Disable MT7531 COREPLL */
+		val = mt753x_reg_read(gsw, PLLGP_EN);
+		val &= ~EN_COREPLL;
+		mt753x_reg_write(gsw, PLLGP_EN, val);
+
+		/* Step 2: switch to XTAL output */
+		val = mt753x_reg_read(gsw, PLLGP_EN);
+		val |= SW_CLKSW;
+		mt753x_reg_write(gsw, PLLGP_EN, val);
+
+		val = mt753x_reg_read(gsw, PLLGP_CR0);
+		val &= ~RG_COREPLL_EN;
+		mt753x_reg_write(gsw, PLLGP_CR0, val);
+
+		/* Step 3: disable PLLGP and enable program PLLGP */
+		val = mt753x_reg_read(gsw, PLLGP_EN);
+		val |= SW_PLLGP;
+		mt753x_reg_write(gsw, PLLGP_EN, val);
+
+		/* Step 4: program COREPLL output frequency to 500MHz */
+		val = mt753x_reg_read(gsw, PLLGP_CR0);
+		val &= ~RG_COREPLL_POSDIV_M;
+		val |= 2 << RG_COREPLL_POSDIV_S;
+		mt753x_reg_write(gsw, PLLGP_CR0, val);
+		usleep_range(25, 35);
+
+		val = mt753x_reg_read(gsw, PLLGP_CR0);
+		val &= ~RG_COREPLL_SDM_PCW_M;
+		val |= 0x190000 << RG_COREPLL_SDM_PCW_S;
+		mt753x_reg_write(gsw, PLLGP_CR0, val);
+
+		/* Set feedback divide ratio update signal to high */
+		val = mt753x_reg_read(gsw, PLLGP_CR0);
+		val |= RG_COREPLL_SDM_PCW_CHG;
+		mt753x_reg_write(gsw, PLLGP_CR0, val);
+		/* Wait for at least 16 XTAL clocks */
+		usleep_range(10, 20);
+
+		/* Step 5: set feedback divide ratio update signal to low */
+		val = mt753x_reg_read(gsw, PLLGP_CR0);
+		val &= ~RG_COREPLL_SDM_PCW_CHG;
+		mt753x_reg_write(gsw, PLLGP_CR0, val);
+
+		/* Enable 325M clock for SGMII */
+		mt753x_reg_write(gsw, ANA_PLLGP_CR5, 0xad0000);
+
+		/* Enable 250SSC clock for RGMII */
+		mt753x_reg_write(gsw, ANA_PLLGP_CR2, 0x4f40000);
+
+		/* Step 6: Enable MT7531 PLL */
+		val = mt753x_reg_read(gsw, PLLGP_CR0);
+		val |= RG_COREPLL_EN;
+		mt753x_reg_write(gsw, PLLGP_CR0, val);
+
+		val = mt753x_reg_read(gsw, PLLGP_EN);
+		val |= EN_COREPLL;
+		mt753x_reg_write(gsw, PLLGP_EN, val);
+		usleep_range(25, 35);
+		break;
+	}
+}
+
+static int mt7531_internal_phy_calibration(struct gsw_mt753x *gsw)
+{
+	return 0;
+}
+
+static int mt7531_sw_detect(struct gsw_mt753x *gsw, struct chip_rev *crev)
+{
+	u32 rev, topsig;
+
+	rev = mt753x_reg_read(gsw, CHIP_REV);
+
+	if (((rev & CHIP_NAME_M) >> CHIP_NAME_S) == MT7531) {
+		if (crev) {
+			topsig = mt753x_reg_read(gsw, TOP_SIG_SR);
+
+			crev->rev = rev & CHIP_REV_M;
+			crev->name = topsig & PAD_DUAL_SGMII_EN ?
+				     "MT7531AE" : "MT7531BE";
+		}
+
+		return 0;
+	}
+
+	return -ENODEV;
+}
+
+static void pinmux_set_mux_7531(struct gsw_mt753x *gsw, u32 pin, u32 mode)
+{
+	u32 val;
+
+	val = mt753x_reg_read(gsw, GPIO_MODE_REGS(pin));
+	val &= ~(0xf << (pin & 7) * GPIO_MODE_S);
+	val |= mode << (pin & 7) * GPIO_MODE_S;
+	mt753x_reg_write(gsw, GPIO_MODE_REGS(pin), val);
+}
+
+static int mt7531_set_gpio_pinmux(struct gsw_mt753x *gsw)
+{
+	u32 group = 0;
+	struct device_node *np = gsw->dev->of_node;
+
+	/* Set GPIO 0 interrupt mode */
+	pinmux_set_mux_7531(gsw, gpio_int_pins[0], gpio_int_funcs[0]);
+
+	of_property_read_u32(np, "mediatek,mdio_master_pinmux", &group);
+
+	/* group = 0: do nothing, 1: 1st group (AE), 2: 2nd group (BE) */
+	if (group > 0 && group <= 2) {
+		group--;
+		pinmux_set_mux_7531(gsw, gpio_mdc_pins[group],
+				    gpio_mdc_funcs[group]);
+		pinmux_set_mux_7531(gsw, gpio_mdio_pins[group],
+				    gpio_mdio_funcs[group]);
+	}
+
+	return 0;
+}
+
+static void mt7531_phy_pll_setup(struct gsw_mt753x *gsw)
+{
+	u32 hwstrap;
+	u32 val;
+
+	val = mt753x_reg_read(gsw, CHIP_REV);
+	if ((val & CHIP_REV_M) > 0)
+		return;
+
+	hwstrap = mt753x_reg_read(gsw, HWSTRAP);
+
+	switch ((hwstrap & XTAL_FSEL_M) >> XTAL_FSEL_S) {
+	case XTAL_25MHZ:
+		/* disable pll auto calibration */
+		gsw->mmd_write(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_104, 0x608);
+
+		/* change pll sel */
+		val = gsw->mmd_read(gsw, 0, PHY_DEV1F,
+				     PHY_DEV1F_REG_403);
+		val &= ~(PHY_PLL_M);
+		val |= PHY_PLL_SEL(3);
+		gsw->mmd_write(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_403, val);
+
+		/* set divider ratio */
+		gsw->mmd_write(gsw, 0, PHY_DEV1F,
+			       PHY_DEV1F_REG_10A, 0x1009);
+
+		/* set divider ratio */
+		gsw->mmd_write(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_10B, 0x7c6);
+
+		/* capacitance and resistance adjustment */
+		gsw->mmd_write(gsw, 0, PHY_DEV1F,
+			       PHY_DEV1F_REG_10C, 0xa8be);
+
+		break;
+	case XTAL_40MHZ:
+		/* disable pll auto calibration */
+		gsw->mmd_write(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_104, 0x608);
+
+		/* change pll sel */
+		val = gsw->mmd_read(gsw, 0, PHY_DEV1F,
+				     PHY_DEV1F_REG_403);
+		val &= ~(PHY_PLL_M);
+		val |= PHY_PLL_SEL(3);
+		gsw->mmd_write(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_403, val);
+
+		/* set divider ratio */
+		gsw->mmd_write(gsw, 0, PHY_DEV1F,
+			       PHY_DEV1F_REG_10A, 0x1018);
+
+		/* set divider ratio */
+		gsw->mmd_write(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_10B, 0xc676);
+
+		/* capacitance and resistance adjustment */
+		gsw->mmd_write(gsw, 0, PHY_DEV1F,
+			       PHY_DEV1F_REG_10C, 0xd8be);
+		break;
+	}
+
+	/* power down pll. additional delay is not required via mdio access */
+	gsw->mmd_write(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_10D, 0x10);
+
+	/* power up pll */
+	gsw->mmd_write(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_10D, 0x14);
+}
+
+/* 12 registers for TX_MLT3 waveform tuning.
+ *    012 345 678 9ab
+ *  1    __
+ *     _/  \_
+ *  0_/      \
+ *            \_    _/
+ * -1           \__/
+ */
+static void mt7531_phy_100m_eye_diag_setting(struct gsw_mt753x *gsw, u32 port)
+{
+	gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0x0, 0x187);
+	gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0x1, 0x1c9);
+	gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0x2, 0x1c6);
+	gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0x3, 0x182);
+	gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0x4, 0x208);
+	gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0x5, 0x205);
+	gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0x6, 0x384);
+	gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0x7, 0x3cb);
+	gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0x8, 0x3c4);
+	gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0x9, 0x30a);
+	gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0xa, 0x00b);
+	gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0xb, 0x002);
+}
+
+static void mt7531_phy_setting(struct gsw_mt753x *gsw)
+{
+	int i;
+	u32 val;
+
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		mt7531_phy_100m_eye_diag_setting(gsw, i);
+
+		/* Enable HW auto downshift */
+		gsw->mii_write(gsw, i, 0x1f, 0x1);
+		val = gsw->mii_read(gsw, i, PHY_EXT_REG_14);
+		val |= PHY_EN_DOWN_SHFIT;
+		gsw->mii_write(gsw, i, PHY_EXT_REG_14, val);
+
+		/* Decrease SlvDPSready time */
+		val = mt753x_tr_read(gsw, i, PMA_CH, PMA_NOD, PMA_17);
+		val &= ~SLV_DSP_READY_TIME_M;
+		val |= 0xc << SLV_DSP_READY_TIME_S;
+		mt753x_tr_write(gsw, i, PMA_CH, PMA_NOD, PMA_17, val);
+
+		/* Enable Random Update Mechanism */
+		val = mt753x_tr_read(gsw, i, PMA_CH, PMA_NOD, PMA_18);
+		val |= ENABLE_RANDOM_UPDATE_TRIGGER;
+		mt753x_tr_write(gsw, i, PMA_CH, PMA_NOD, PMA_18, val);
+
+		/* PHY link down power saving enable */
+		val = gsw->mii_read(gsw, i, PHY_EXT_REG_17);
+		val |= PHY_LINKDOWN_POWER_SAVING_EN;
+		gsw->mii_write(gsw, i, PHY_EXT_REG_17, val);
+
+		val = gsw->mmd_read(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_0C6);
+		val &= ~PHY_POWER_SAVING_M;
+		val |= PHY_POWER_SAVING_TX << PHY_POWER_SAVING_S;
+		gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_0C6, val);
+
+		/* Timing Recovery for GbE slave mode */
+		mt753x_tr_write(gsw, i, PMA_CH, PMA_NOD, PMA_01, 0x6fb90a);
+		mt753x_tr_write(gsw, i, DSP_CH, DSP_NOD, DSP_06, 0x2ebaef);
+		val = gsw->mmd_read(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_234);
+		val |= TR_OPEN_LOOP_EN;
+		gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_234, val);
+
+		/* Enable Asymmetric Pause Capability */
+		val = gsw->mii_read(gsw, i, MII_ADVERTISE);
+		val |= ADVERTISE_PAUSE_ASYM;
+		gsw->mii_write(gsw, i, MII_ADVERTISE, val);
+	}
+}
+
+static void mt7531_adjust_line_driving(struct gsw_mt753x *gsw, u32 port)
+{
+	/* For ADC timing margin window for LDO calibration */
+	gsw->mmd_write(gsw, port, PHY_DEV1E, RXADC_LDO_CONTROL_2, 0x2222);
+
+	/* Adjust AD sample timing */
+	gsw->mmd_write(gsw, port, PHY_DEV1E, RXADC_CONTROL_3, 0x4444);
+
+	/* Adjust Line driver current for different mode */
+	gsw->mmd_write(gsw, port, PHY_DEV1F, TXVLD_DA_271, 0x2ca5);
+
+	/* Adjust Line driver current for different mode */
+	gsw->mmd_write(gsw, port, PHY_DEV1F, TXVLD_DA_272, 0xc6b);
+
+	/* Adjust Line driver gain for 10BT from 1000BT calibration result */
+	gsw->mmd_write(gsw, port, PHY_DEV1F, TXVLD_DA_273, 0x3000);
+
+	/* Adjust RX Echo path filter */
+	gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_DEV1E_REG_0FE, 0x2);
+
+	/* Adjust RX HVGA bias current */
+	gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_DEV1E_REG_41, 0x3333);
+
+	/* Adjust TX class AB driver 1 */
+	gsw->mmd_write(gsw, port, PHY_DEV1F, PHY_DEV1F_REG_268, 0x384);
+
+	/* Adjust TX class AB driver 2 */
+	gsw->mmd_write(gsw, port, PHY_DEV1F, PHY_DEV1F_REG_269, 0x1114);
+
+	/* Adjust DAC delay for TX Pairs */
+	gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_DEV1E_REG_13, 0x404);
+	gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_DEV1E_REG_14, 0x404);
+
+	/* Adjust DAC digital delay for TX Delay */
+	gsw->mmd_write(gsw, port, PHY_DEV1F, PHY_DEV1F_REG_44, 0xc0);
+
+	/* Adjust Line driver compensation cap for stability concern due to
+	 * increase current.
+	 */
+	gsw->mmd_write(gsw, port, PHY_DEV1F, PHY_DEV1F_REG_26A, 0x3333);
+}
+
+static void mt7531_eee_setting(struct gsw_mt753x *gsw, u32 port)
+{
+	u32 val;
+
+	/* Disable EEE */
+	gsw->mmd_write(gsw, port, PHY_DEV07, PHY_DEV07_REG_03C, 0);
+
+	/* Disable generate signal to clear the scramble_lock when lpi mode */
+	val = gsw->mmd_read(gsw, port, PHY_DEV1E, PHY_DEV1E_REG_189);
+	val &= ~DESCRAMBLER_CLEAR_EN;
+	gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_DEV1E_REG_189, val);
+
+	/* Roll back EEE Slave Mode */
+	gsw->mmd_write(gsw, port, 0x1e, 0x2d1, 0);
+	mt753x_tr_write(gsw, port, DSP_CH, DSP_NOD, DSP_08, 0x1b);
+	mt753x_tr_write(gsw, port, DSP_CH, DSP_NOD, DSP_0f, 0);
+	mt753x_tr_write(gsw, port, DSP_CH, DSP_NOD, DSP_10, 0x5000);
+
+	/* Adjust 100_mse_threshold */
+	gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_DEV1E_REG_123, 0xffff);
+
+	/* Disable mcc */
+	gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_DEV1E_REG_A6, 0x300);
+}
+
+static void mt7531_afifo_reset(struct gsw_mt753x *gsw, int enable)
+{
+	int p;
+	u32 val;
+
+	if (enable) {
+		for (p = 0; p < MT753X_NUM_PORTS; p++) {
+			val = mt753x_reg_read(gsw, DBG_CNT(p));
+			val &= ~DIS_CLR;
+			mt753x_reg_write(gsw, DBG_CNT(p), val);
+		}
+	} else {
+		for (p = 0; p < MT753X_NUM_PORTS; p++) {
+			val = mt753x_reg_read(gsw, DBG_CNT(p));
+			val |= DIS_CLR;
+			mt753x_reg_write(gsw, DBG_CNT(p), val);
+		}
+	}
+}
+
+static int mt7531_sw_init(struct gsw_mt753x *gsw)
+{
+	int i;
+	u32 val;
+
+	gsw->phy_base = (gsw->smi_addr + 1) & MT753X_SMI_ADDR_MASK;
+
+	gsw->mii_read = mt753x_mii_read;
+	gsw->mii_write = mt753x_mii_write;
+	gsw->mmd_read = mt753x_mmd_read;
+	gsw->mmd_write = mt753x_mmd_write;
+
+	gsw->hw_phy_cal = of_property_read_bool(gsw->dev->of_node, "mediatek,hw_phy_cal");
+
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		val = gsw->mii_read(gsw, i, MII_BMCR);
+		val |= BMCR_ISOLATE;
+		gsw->mii_write(gsw, i, MII_BMCR, val);
+	}
+
+	/* Force MAC link down before reset */
+	mt753x_reg_write(gsw, PMCR(5), FORCE_MODE_LNK);
+	mt753x_reg_write(gsw, PMCR(6), FORCE_MODE_LNK);
+
+	/* Switch soft reset */
+	mt753x_reg_write(gsw, SYS_CTRL, SW_SYS_RST | SW_REG_RST);
+	usleep_range(10, 20);
+
+	/* Enable MDC input Schmitt Trigger */
+	val = mt753x_reg_read(gsw, SMT0_IOLB);
+	mt753x_reg_write(gsw, SMT0_IOLB, val | SMT_IOLB_5_SMI_MDC_EN);
+
+	/* Set 7531 gpio pinmux */
+	mt7531_set_gpio_pinmux(gsw);
+
+	mt7531_core_pll_setup(gsw);
+	mt7531_mac_port_setup(gsw, 5, &gsw->port5_cfg);
+	mt7531_mac_port_setup(gsw, 6, &gsw->port6_cfg);
+
+	/* Global mac control settings */
+	mt753x_reg_write(gsw, GMACCR,
+			 (15 << MTCC_LMT_S) | (15 << MAX_RX_JUMBO_S) |
+			 RX_PKT_LEN_MAX_JUMBO);
+
+	/* Enable Collision Poll */
+	val = mt753x_reg_read(gsw, CPGC_CTRL);
+	val |= COL_CLK_EN;
+	mt753x_reg_write(gsw, CPGC_CTRL, val);
+	val |= COL_RST_N;
+	mt753x_reg_write(gsw, CPGC_CTRL, val);
+	val |= COL_EN;
+	mt753x_reg_write(gsw, CPGC_CTRL, val);
+
+	/* Disable AFIFO reset for extra short IPG */
+	mt7531_afifo_reset(gsw, 0);
+
+	return 0;
+}
+
+static int mt7531_sw_post_init(struct gsw_mt753x *gsw)
+{
+	int i;
+	u32 val;
+
+	/* Let internal PHYs only Tx constant data in configure stage. */
+	for (i = 0; i < MT753X_NUM_PHYS; i++)
+		gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_141, 0x200);
+
+	/* Internal PHYs might be enabled by HW Bootstrapping, or bootloader.
+	 * Turn off PHYs before setup PHY PLL.
+	 */
+	val = gsw->mmd_read(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_403);
+	val |= PHY_EN_BYPASS_MODE;
+	val |= POWER_ON_OFF;
+	gsw->mmd_write(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_403, val);
+
+	mt7531_phy_pll_setup(gsw);
+
+	/* Enable Internal PHYs before phy setting */
+	val = gsw->mmd_read(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_403);
+	val |= PHY_EN_BYPASS_MODE;
+	val &= ~POWER_ON_OFF;
+	gsw->mmd_write(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_403, val);
+
+	mt7531_phy_setting(gsw);
+
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		val = gsw->mii_read(gsw, i, MII_BMCR);
+		val &= ~BMCR_ISOLATE;
+		gsw->mii_write(gsw, i, MII_BMCR, val);
+	}
+
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		mt7531_adjust_line_driving(gsw, i);
+		mt7531_eee_setting(gsw, i);
+	}
+
+	/* Restore internal PHYs normal Tx function after configure stage. */
+	for (i = 0; i < MT753X_NUM_PHYS; i++)
+		gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_141, 0x0);
+
+	mt7531_internal_phy_calibration(gsw);
+
+	return 0;
+}
+
+struct mt753x_sw_id mt7531_id = {
+	.model = MT7531,
+	.detect = mt7531_sw_detect,
+	.init = mt7531_sw_init,
+	.post_init = mt7531_sw_post_init
+};
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Zhanguo Ju <zhanguo.ju@mediatek.com>");
+MODULE_DESCRIPTION("Driver for MediaTek MT753x Gigabit Switch");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.h
new file mode 100644
index 0000000..52c8a49
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ */
+
+#ifndef _MT7531_H_
+#define _MT7531_H_
+
+#include "mt753x.h"
+
+extern struct mt753x_sw_id mt7531_id;
+
+#endif /* _MT7531_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x.h
new file mode 100755
index 0000000..732bda1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x.h
@@ -0,0 +1,224 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#ifndef _MT753X_H_
+#define _MT753X_H_
+
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/netdevice.h>
+#include <linux/of_mdio.h>
+#include <linux/workqueue.h>
+#include <linux/gpio/consumer.h>
+
+#ifdef CONFIG_SWCONFIG
+#include <linux/switch.h>
+#endif
+
+#include "mt753x_vlan.h"
+
+#define MT753X_DFL_CPU_PORT	6
+#define MT753X_NUM_PHYS		5
+
+#define MT753X_DFL_SMI_ADDR	0x1f
+#define MT753X_SMI_ADDR_MASK	0x1f
+
+struct gsw_mt753x;
+
+enum mt753x_model {
+	MT7530 = 0x7530,
+	MT7531 = 0x7531
+};
+
+struct mt753x_port_cfg {
+	struct device_node *np;
+	int phy_mode;
+	u32 enabled: 1;
+	u32 force_link: 1;
+	u32 speed: 2;
+	u32 duplex: 1;
+	bool ssc_on;
+	bool stag_on;
+};
+
+struct mt753x_phy {
+	struct gsw_mt753x *gsw;
+	struct net_device netdev;
+	struct phy_device *phydev;
+};
+
+struct gsw_mt753x {
+	u32 id;
+
+	struct device *dev;
+	struct mii_bus *host_bus;
+	struct mii_bus *gphy_bus;
+	struct mutex mii_lock;	/* MII access lock */
+	u32 smi_addr;
+	u32 phy_base;
+	int direct_phy_access;
+
+	enum mt753x_model model;
+	const char *name;
+
+	struct mt753x_port_cfg port5_cfg;
+	struct mt753x_port_cfg port6_cfg;
+
+	bool hw_phy_cal;
+	bool phy_status_poll;
+	struct mt753x_phy phys[MT753X_NUM_PHYS];
+//	int phy_irqs[PHY_MAX_ADDR]; //FIXME 
+
+	int phy_link_sts;
+
+	int irq;
+	int reset_pin;
+	struct work_struct irq_worker;
+
+#ifdef CONFIG_SWCONFIG
+	struct switch_dev swdev;
+	u32 cpu_port;
+#endif
+
+	int global_vlan_enable;
+	struct mt753x_vlan_entry vlan_entries[MT753X_NUM_VLANS];
+	struct mt753x_port_entry port_entries[MT753X_NUM_PORTS];
+
+	int (*mii_read)(struct gsw_mt753x *gsw, int phy, int reg);
+	void (*mii_write)(struct gsw_mt753x *gsw, int phy, int reg, u16 val);
+
+	int (*mmd_read)(struct gsw_mt753x *gsw, int addr, int devad, u16 reg);
+	void (*mmd_write)(struct gsw_mt753x *gsw, int addr, int devad, u16 reg,
+			  u16 val);
+
+	struct list_head list;
+};
+
+struct chip_rev {
+	const char *name;
+	u32 rev;
+};
+
+struct mt753x_sw_id {
+	enum mt753x_model model;
+	int (*detect)(struct gsw_mt753x *gsw, struct chip_rev *crev);
+	int (*init)(struct gsw_mt753x *gsw);
+	int (*post_init)(struct gsw_mt753x *gsw);
+};
+
+extern struct list_head mt753x_devs;
+
+struct gsw_mt753x *mt753x_get_gsw(u32 id);
+struct gsw_mt753x *mt753x_get_first_gsw(void);
+void mt753x_put_gsw(void);
+void mt753x_lock_gsw(void);
+
+u32 mt753x_reg_read(struct gsw_mt753x *gsw, u32 reg);
+void mt753x_reg_write(struct gsw_mt753x *gsw, u32 reg, u32 val);
+
+int mt753x_mii_read(struct gsw_mt753x *gsw, int phy, int reg);
+void mt753x_mii_write(struct gsw_mt753x *gsw, int phy, int reg, u16 val);
+
+int mt753x_mmd_read(struct gsw_mt753x *gsw, int addr, int devad, u16 reg);
+void mt753x_mmd_write(struct gsw_mt753x *gsw, int addr, int devad, u16 reg,
+		      u16 val);
+
+int mt753x_mmd_ind_read(struct gsw_mt753x *gsw, int addr, int devad, u16 reg);
+void mt753x_mmd_ind_write(struct gsw_mt753x *gsw, int addr, int devad, u16 reg,
+			  u16 val);
+
+int mt753x_tr_read(struct gsw_mt753x *gsw, int addr, u8 ch, u8 node, u8 daddr);
+void mt753x_tr_write(struct gsw_mt753x *gsw, int addr, u8 ch, u8 node, u8 daddr,
+		     u32 data);
+
+void mt753x_irq_worker(struct work_struct *work);
+void mt753x_irq_enable(struct gsw_mt753x *gsw);
+
+int mt753x_phy_calibration(struct gsw_mt753x *gsw, u8 phyaddr);
+int extphy_init(struct gsw_mt753x *gsw, int addr);
+
+/* MDIO Indirect Access Registers */
+#define MII_MMD_ACC_CTL_REG		0x0d
+#define MMD_CMD_S			14
+#define MMD_CMD_M			0xc000
+#define MMD_DEVAD_S			0
+#define MMD_DEVAD_M			0x1f
+
+/* MMD_CMD: MMD commands */
+#define MMD_ADDR			0
+#define MMD_DATA			1
+
+#define MII_MMD_ADDR_DATA_REG		0x0e
+
+/* Procedure of MT753x Internal Register Access
+ *
+ * 1. Internal Register Address
+ *
+ *    The MT753x has a 16-bit register address and each register is 32-bit.
+ *    This means the lowest two bits are not used as the register address is
+ *    4-byte aligned.
+ *
+ *    Rest of the valid bits are divided into two parts:
+ *      Bit 15..6 is the Page address
+ *      Bit 5..2 is the low address
+ *
+ *    -------------------------------------------------------------------
+ *    | 15  14  13  12  11  10   9   8   7   6 | 5   4   3   2 | 1   0  |
+ *    |----------------------------------------|---------------|--------|
+ *    |              Page Address              |    Address    | Unused |
+ *    -------------------------------------------------------------------
+ *
+ * 2. MDIO access timing
+ *
+ *    The MT753x uses the following MDIO timing for a single register read
+ *
+ *      Phase 1: Write Page Address
+ *    -------------------------------------------------------------------
+ *    | ST | OP | PHY_ADDR | TYPE | RSVD | TA |  RSVD |    PAGE_ADDR    |
+ *    -------------------------------------------------------------------
+ *    | 01 | 01 |   11111  |   1  | 1111 | xx | 00000 | REG_ADDR[15..6] |
+ *    -------------------------------------------------------------------
+ *
+ *      Phase 2: Write low Address & Read low word
+ *    -------------------------------------------------------------------
+ *    | ST | OP | PHY_ADDR | TYPE |    LOW_ADDR    | TA |      DATA     |
+ *    -------------------------------------------------------------------
+ *    | 01 | 10 |   11111  |   0  | REG_ADDR[5..2] | xx |  DATA[15..0]  |
+ *    -------------------------------------------------------------------
+ *
+ *      Phase 3: Read high word
+ *    -------------------------------------------------------------------
+ *    | ST | OP | PHY_ADDR | TYPE | RSVD | TA |           DATA          |
+ *    -------------------------------------------------------------------
+ *    | 01 | 10 |   11111  |   1  | 0000 | xx |       DATA[31..16]      |
+ *    -------------------------------------------------------------------
+ *
+ *    The MT753x uses the following MDIO timing for a single register write
+ *
+ *      Phase 1: Write Page Address (The same as read)
+ *
+ *      Phase 2: Write low Address and low word
+ *    -------------------------------------------------------------------
+ *    | ST | OP | PHY_ADDR | TYPE |    LOW_ADDR    | TA |      DATA     |
+ *    -------------------------------------------------------------------
+ *    | 01 | 01 |   11111  |   0  | REG_ADDR[5..2] | xx |  DATA[15..0]  |
+ *    -------------------------------------------------------------------
+ *
+ *      Phase 3: write high word
+ *    -------------------------------------------------------------------
+ *    | ST | OP | PHY_ADDR | TYPE | RSVD | TA |           DATA          |
+ *    -------------------------------------------------------------------
+ *    | 01 | 01 |   11111  |   1  | 0000 | xx |       DATA[31..16]      |
+ *    -------------------------------------------------------------------
+ *
+ */
+
+/* Internal Register Address fields */
+#define MT753X_REG_PAGE_ADDR_S		6
+#define MT753X_REG_PAGE_ADDR_M		0xffc0
+#define MT753X_REG_ADDR_S		2
+#define MT753X_REG_ADDR_M		0x3c
+#endif /* _MT753X_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_common.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_common.c
new file mode 100644
index 0000000..4015ddf
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_common.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include "mt753x.h"
+#include "mt753x_regs.h"
+
+void mt753x_irq_enable(struct gsw_mt753x *gsw)
+{
+	u32 val;
+	int i;
+
+	/* Record initial PHY link status */
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		val = gsw->mii_read(gsw, i, MII_BMSR);
+		if (val & BMSR_LSTATUS)
+			gsw->phy_link_sts |= BIT(i);
+	}
+
+	val = BIT(MT753X_NUM_PHYS) - 1;
+
+	mt753x_reg_write(gsw, SYS_INT_EN, val);
+}
+
+static void display_port_link_status(struct gsw_mt753x *gsw, u32 port)
+{
+	u32 pmsr, speed_bits;
+	const char *speed;
+
+	pmsr = mt753x_reg_read(gsw, PMSR(port));
+
+	speed_bits = (pmsr & MAC_SPD_STS_M) >> MAC_SPD_STS_S;
+
+	switch (speed_bits) {
+	case MAC_SPD_10:
+		speed = "10Mbps";
+		break;
+	case MAC_SPD_100:
+		speed = "100Mbps";
+		break;
+	case MAC_SPD_1000:
+		speed = "1Gbps";
+		break;
+	case MAC_SPD_2500:
+		speed = "2.5Gbps";
+		break;
+	}
+
+	if (pmsr & MAC_LNK_STS) {
+		dev_info(gsw->dev, "Port %d Link is Up - %s/%s\n",
+			 port, speed, (pmsr & MAC_DPX_STS) ? "Full" : "Half");
+	} else {
+		dev_info(gsw->dev, "Port %d Link is Down\n", port);
+	}
+}
+
+void mt753x_irq_worker(struct work_struct *work)
+{
+	struct gsw_mt753x *gsw;
+	u32 sts, physts, laststs;
+	int i;
+
+	gsw = container_of(work, struct gsw_mt753x, irq_worker);
+
+	sts = mt753x_reg_read(gsw, SYS_INT_STS);
+
+	/* Check for changed PHY link status */
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		if (!(sts & PHY_LC_INT(i)))
+			continue;
+
+		laststs = gsw->phy_link_sts & BIT(i);
+		physts = !!(gsw->mii_read(gsw, i, MII_BMSR) & BMSR_LSTATUS);
+		physts <<= i;
+
+		if (physts ^ laststs) {
+			gsw->phy_link_sts ^= BIT(i);
+			display_port_link_status(gsw, i);
+		}
+	}
+
+	mt753x_reg_write(gsw, SYS_INT_STS, sts);
+
+	enable_irq(gsw->irq);
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_mdio.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_mdio.c
new file mode 100755
index 0000000..06a1114
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_mdio.c
@@ -0,0 +1,861 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/reset.h>
+#include <linux/hrtimer.h>
+#include <linux/mii.h>
+#include <linux/of_mdio.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/of_net.h>
+#include <linux/of_irq.h>
+#include <linux/phy.h>
+
+#include "mt753x.h"
+#include "mt753x_swconfig.h"
+#include "mt753x_regs.h"
+#include "mt753x_nl.h"
+#include "mt7530.h"
+#include "mt7531.h"
+
+static u32 mt753x_id;
+struct list_head mt753x_devs;
+static DEFINE_MUTEX(mt753x_devs_lock);
+
+static struct mt753x_sw_id *mt753x_sw_ids[] = {
+	&mt7530_id,
+	&mt7531_id,
+};
+
+u32 mt753x_reg_read(struct gsw_mt753x *gsw, u32 reg)
+{
+	u32 high, low;
+
+	mutex_lock(&gsw->host_bus->mdio_lock);
+
+	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x1f,
+		(reg & MT753X_REG_PAGE_ADDR_M) >> MT753X_REG_PAGE_ADDR_S);
+
+	low = gsw->host_bus->read(gsw->host_bus, gsw->smi_addr,
+		(reg & MT753X_REG_ADDR_M) >> MT753X_REG_ADDR_S);
+
+	high = gsw->host_bus->read(gsw->host_bus, gsw->smi_addr, 0x10);
+
+	mutex_unlock(&gsw->host_bus->mdio_lock);
+
+	return (high << 16) | (low & 0xffff);
+}
+
+void mt753x_reg_write(struct gsw_mt753x *gsw, u32 reg, u32 val)
+{
+	mutex_lock(&gsw->host_bus->mdio_lock);
+
+	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x1f,
+		(reg & MT753X_REG_PAGE_ADDR_M) >> MT753X_REG_PAGE_ADDR_S);
+
+	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr,
+		(reg & MT753X_REG_ADDR_M) >> MT753X_REG_ADDR_S, val & 0xffff);
+
+	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x10, val >> 16);
+
+	mutex_unlock(&gsw->host_bus->mdio_lock);
+}
+
+/* Indirect MDIO clause 22/45 access */
+static int mt753x_mii_rw(struct gsw_mt753x *gsw, int phy, int reg, u16 data,
+			 u32 cmd, u32 st)
+{
+	ktime_t timeout;
+	u32 val, timeout_us;
+	int ret = 0;
+
+	timeout_us = 100000;
+	timeout = ktime_add_us(ktime_get(), timeout_us);
+	while (1) {
+		val = mt753x_reg_read(gsw, PHY_IAC);
+
+		if ((val & PHY_ACS_ST) == 0)
+			break;
+
+		if (ktime_compare(ktime_get(), timeout) > 0)
+			return -ETIMEDOUT;
+	}
+
+	val = (st << MDIO_ST_S) |
+	      ((cmd << MDIO_CMD_S) & MDIO_CMD_M) |
+	      ((phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) |
+	      ((reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M);
+
+	if (cmd == MDIO_CMD_WRITE || cmd == MDIO_CMD_ADDR)
+		val |= data & MDIO_RW_DATA_M;
+
+	mt753x_reg_write(gsw, PHY_IAC, val | PHY_ACS_ST);
+
+	timeout_us = 100000;
+	timeout = ktime_add_us(ktime_get(), timeout_us);
+	while (1) {
+		val = mt753x_reg_read(gsw, PHY_IAC);
+
+		if ((val & PHY_ACS_ST) == 0)
+			break;
+
+		if (ktime_compare(ktime_get(), timeout) > 0)
+			return -ETIMEDOUT;
+	}
+
+	if (cmd == MDIO_CMD_READ || cmd == MDIO_CMD_READ_C45) {
+		val = mt753x_reg_read(gsw, PHY_IAC);
+		ret = val & MDIO_RW_DATA_M;
+	}
+
+	return ret;
+}
+
+int mt753x_mii_read(struct gsw_mt753x *gsw, int phy, int reg)
+{
+	int val;
+
+	if (phy < MT753X_NUM_PHYS)
+		phy = (gsw->phy_base + phy) & MT753X_SMI_ADDR_MASK;
+
+	mutex_lock(&gsw->mii_lock);
+	val = mt753x_mii_rw(gsw, phy, reg, 0, MDIO_CMD_READ, MDIO_ST_C22);
+	mutex_unlock(&gsw->mii_lock);
+
+	return val;
+}
+
+void mt753x_mii_write(struct gsw_mt753x *gsw, int phy, int reg, u16 val)
+{
+	if (phy < MT753X_NUM_PHYS)
+		phy = (gsw->phy_base + phy) & MT753X_SMI_ADDR_MASK;
+
+	mutex_lock(&gsw->mii_lock);
+	mt753x_mii_rw(gsw, phy, reg, val, MDIO_CMD_WRITE, MDIO_ST_C22);
+	mutex_unlock(&gsw->mii_lock);
+}
+
+int mt753x_mmd_read(struct gsw_mt753x *gsw, int addr, int devad, u16 reg)
+{
+	int val;
+
+	if (addr < MT753X_NUM_PHYS)
+		addr = (gsw->phy_base + addr) & MT753X_SMI_ADDR_MASK;
+
+	mutex_lock(&gsw->mii_lock);
+	mt753x_mii_rw(gsw, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45);
+	val = mt753x_mii_rw(gsw, addr, devad, 0, MDIO_CMD_READ_C45,
+			    MDIO_ST_C45);
+	mutex_unlock(&gsw->mii_lock);
+
+	return val;
+}
+
+void mt753x_mmd_write(struct gsw_mt753x *gsw, int addr, int devad, u16 reg,
+		      u16 val)
+{
+	if (addr < MT753X_NUM_PHYS)
+		addr = (gsw->phy_base + addr) & MT753X_SMI_ADDR_MASK;
+
+	mutex_lock(&gsw->mii_lock);
+	mt753x_mii_rw(gsw, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45);
+	mt753x_mii_rw(gsw, addr, devad, val, MDIO_CMD_WRITE, MDIO_ST_C45);
+	mutex_unlock(&gsw->mii_lock);
+}
+
+int mt753x_mmd_ind_read(struct gsw_mt753x *gsw, int addr, int devad, u16 reg)
+{
+	u16 val;
+
+	if (addr < MT753X_NUM_PHYS)
+		addr = (gsw->phy_base + addr) & MT753X_SMI_ADDR_MASK;
+
+	mutex_lock(&gsw->mii_lock);
+
+	mt753x_mii_rw(gsw, addr, MII_MMD_ACC_CTL_REG,
+		      (MMD_ADDR << MMD_CMD_S) |
+		      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M),
+		      MDIO_CMD_WRITE, MDIO_ST_C22);
+
+	mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, reg,
+		      MDIO_CMD_WRITE, MDIO_ST_C22);
+
+	mt753x_mii_rw(gsw, addr, MII_MMD_ACC_CTL_REG,
+		      (MMD_DATA << MMD_CMD_S) |
+		      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M),
+		      MDIO_CMD_WRITE, MDIO_ST_C22);
+
+	val = mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, 0,
+			    MDIO_CMD_READ, MDIO_ST_C22);
+
+	mutex_unlock(&gsw->mii_lock);
+
+	return val;
+}
+
+void mt753x_mmd_ind_write(struct gsw_mt753x *gsw, int addr, int devad, u16 reg,
+			  u16 val)
+{
+	if (addr < MT753X_NUM_PHYS)
+		addr = (gsw->phy_base + addr) & MT753X_SMI_ADDR_MASK;
+
+	mutex_lock(&gsw->mii_lock);
+
+	mt753x_mii_rw(gsw, addr, MII_MMD_ACC_CTL_REG,
+		      (MMD_ADDR << MMD_CMD_S) |
+		      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M),
+		      MDIO_CMD_WRITE, MDIO_ST_C22);
+
+	mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, reg,
+		      MDIO_CMD_WRITE, MDIO_ST_C22);
+
+	mt753x_mii_rw(gsw, addr, MII_MMD_ACC_CTL_REG,
+		      (MMD_DATA << MMD_CMD_S) |
+		      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M),
+		      MDIO_CMD_WRITE, MDIO_ST_C22);
+
+	mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, val,
+		      MDIO_CMD_WRITE, MDIO_ST_C22);
+
+	mutex_unlock(&gsw->mii_lock);
+}
+
+static inline int mt753x_get_duplex(const struct device_node *np)
+{
+	return of_property_read_bool(np, "full-duplex");
+}
+
+static void mt753x_load_port_cfg(struct gsw_mt753x *gsw)
+{
+	struct device_node *port_np;
+	struct device_node *fixed_link_node;
+	struct mt753x_port_cfg *port_cfg;
+	u32 port;
+
+	for_each_child_of_node(gsw->dev->of_node, port_np) {
+		if (!of_device_is_compatible(port_np, "mediatek,mt753x-port"))
+			continue;
+
+		if (!of_device_is_available(port_np))
+			continue;
+
+		if (of_property_read_u32(port_np, "reg", &port))
+			continue;
+
+		switch (port) {
+		case 5:
+			port_cfg = &gsw->port5_cfg;
+			break;
+		case 6:
+			port_cfg = &gsw->port6_cfg;
+			break;
+		default:
+			continue;
+		}
+
+		if (port_cfg->enabled) {
+			dev_info(gsw->dev, "duplicated node for port%d\n",
+				 port_cfg->phy_mode);
+			continue;
+		}
+
+		port_cfg->np = port_np;
+
+		port_cfg->phy_mode = of_get_phy_mode(port_np);
+		if (port_cfg->phy_mode < 0) {
+			dev_info(gsw->dev, "incorrect phy-mode %d\n", port);
+			continue;
+		}
+
+		fixed_link_node = of_get_child_by_name(port_np, "fixed-link");
+		if (fixed_link_node) {
+			u32 speed;
+
+			port_cfg->force_link = 1;
+			port_cfg->duplex = mt753x_get_duplex(fixed_link_node);
+
+			if (of_property_read_u32(fixed_link_node, "speed",
+						 &speed)) {
+				speed = 0;
+				continue;
+			}
+
+			of_node_put(fixed_link_node);
+
+			switch (speed) {
+			case 10:
+				port_cfg->speed = MAC_SPD_10;
+				break;
+			case 100:
+				port_cfg->speed = MAC_SPD_100;
+				break;
+			case 1000:
+				port_cfg->speed = MAC_SPD_1000;
+				break;
+			case 2500:
+				port_cfg->speed = MAC_SPD_2500;
+				break;
+			default:
+				dev_info(gsw->dev, "incorrect speed %d\n",
+					 speed);
+				continue;
+			}
+		}
+
+		port_cfg->ssc_on = of_property_read_bool(port_cfg->np,
+							 "mediatek,ssc-on");
+		port_cfg->stag_on = of_property_read_bool(port_cfg->np,
+							  "mediatek,stag-on");
+		port_cfg->enabled = 1;
+	}
+}
+
+void mt753x_tr_write(struct gsw_mt753x *gsw, int addr, u8 ch, u8 node, u8 daddr,
+		     u32 data)
+{
+	ktime_t timeout;
+	u32 timeout_us;
+	u32 val;
+
+	if (addr < MT753X_NUM_PHYS)
+		addr = (gsw->phy_base + addr) & MT753X_SMI_ADDR_MASK;
+
+	gsw->mii_write(gsw, addr, PHY_CL22_PAGE_CTRL, PHY_TR_PAGE);
+
+	val = gsw->mii_read(gsw, addr, PHY_TR_CTRL);
+
+	timeout_us = 100000;
+	timeout = ktime_add_us(ktime_get(), timeout_us);
+	while (1) {
+		val = gsw->mii_read(gsw, addr, PHY_TR_CTRL);
+
+		if (!!(val & PHY_TR_PKT_XMT_STA))
+			break;
+
+		if (ktime_compare(ktime_get(), timeout) > 0)
+			goto out;
+	}
+
+	gsw->mii_write(gsw, addr, PHY_TR_LOW_DATA, PHY_TR_LOW_VAL(data));
+	gsw->mii_write(gsw, addr, PHY_TR_HIGH_DATA, PHY_TR_HIGH_VAL(data));
+	val = PHY_TR_PKT_XMT_STA | (PHY_TR_WRITE << PHY_TR_WR_S) |
+	      (ch << PHY_TR_CH_ADDR_S) | (node << PHY_TR_NODE_ADDR_S) |
+	      (daddr << PHY_TR_DATA_ADDR_S);
+	gsw->mii_write(gsw, addr, PHY_TR_CTRL, val);
+
+	timeout_us = 100000;
+	timeout = ktime_add_us(ktime_get(), timeout_us);
+	while (1) {
+		val = gsw->mii_read(gsw, addr, PHY_TR_CTRL);
+
+		if (!!(val & PHY_TR_PKT_XMT_STA))
+			break;
+
+		if (ktime_compare(ktime_get(), timeout) > 0)
+			goto out;
+	}
+out:
+	gsw->mii_write(gsw, addr, PHY_CL22_PAGE_CTRL, 0);
+}
+
+int mt753x_tr_read(struct gsw_mt753x *gsw, int addr, u8 ch, u8 node, u8 daddr)
+{
+	ktime_t timeout;
+	u32 timeout_us;
+	u32 val;
+	u8 val_h;
+
+	if (addr < MT753X_NUM_PHYS)
+		addr = (gsw->phy_base + addr) & MT753X_SMI_ADDR_MASK;
+
+	gsw->mii_write(gsw, addr, PHY_CL22_PAGE_CTRL, PHY_TR_PAGE);
+
+	val = gsw->mii_read(gsw, addr, PHY_TR_CTRL);
+
+	timeout_us = 100000;
+	timeout = ktime_add_us(ktime_get(), timeout_us);
+	while (1) {
+		val = gsw->mii_read(gsw, addr, PHY_TR_CTRL);
+
+		if (!!(val & PHY_TR_PKT_XMT_STA))
+			break;
+
+		if (ktime_compare(ktime_get(), timeout) > 0) {
+			gsw->mii_write(gsw, addr, PHY_CL22_PAGE_CTRL, 0);
+			return -ETIMEDOUT;
+		}
+	}
+
+	val = PHY_TR_PKT_XMT_STA | (PHY_TR_READ << PHY_TR_WR_S) |
+	      (ch << PHY_TR_CH_ADDR_S) | (node << PHY_TR_NODE_ADDR_S) |
+	      (daddr << PHY_TR_DATA_ADDR_S);
+	gsw->mii_write(gsw, addr, PHY_TR_CTRL, val);
+
+	timeout_us = 100000;
+	timeout = ktime_add_us(ktime_get(), timeout_us);
+	while (1) {
+		val = gsw->mii_read(gsw, addr, PHY_TR_CTRL);
+
+		if (!!(val & PHY_TR_PKT_XMT_STA))
+			break;
+
+		if (ktime_compare(ktime_get(), timeout) > 0) {
+			gsw->mii_write(gsw, addr, PHY_CL22_PAGE_CTRL, 0);
+			return -ETIMEDOUT;
+		}
+	}
+
+	val = gsw->mii_read(gsw, addr, PHY_TR_LOW_DATA);
+	val_h = gsw->mii_read(gsw, addr, PHY_TR_HIGH_DATA);
+	val |= (val_h << 16);
+
+	gsw->mii_write(gsw, addr, PHY_CL22_PAGE_CTRL, 0);
+
+	return val;
+}
+
+static void mt753x_add_gsw(struct gsw_mt753x *gsw)
+{
+	mutex_lock(&mt753x_devs_lock);
+	gsw->id = mt753x_id++;
+	INIT_LIST_HEAD(&gsw->list);
+	list_add_tail(&gsw->list, &mt753x_devs);
+	mutex_unlock(&mt753x_devs_lock);
+}
+
+static void mt753x_remove_gsw(struct gsw_mt753x *gsw)
+{
+	mutex_lock(&mt753x_devs_lock);
+	list_del(&gsw->list);
+	mutex_unlock(&mt753x_devs_lock);
+}
+
+
+struct gsw_mt753x *mt753x_get_gsw(u32 id)
+{
+	struct gsw_mt753x *dev;
+
+	mutex_lock(&mt753x_devs_lock);
+
+	list_for_each_entry(dev, &mt753x_devs, list) {
+		if (dev->id == id)
+			return dev;
+	}
+
+	mutex_unlock(&mt753x_devs_lock);
+
+	return NULL;
+}
+
+struct gsw_mt753x *mt753x_get_first_gsw(void)
+{
+	struct gsw_mt753x *dev;
+
+	mutex_lock(&mt753x_devs_lock);
+
+	list_for_each_entry(dev, &mt753x_devs, list)
+		return dev;
+
+	mutex_unlock(&mt753x_devs_lock);
+
+	return NULL;
+}
+
+void mt753x_put_gsw(void)
+{
+	mutex_unlock(&mt753x_devs_lock);
+}
+
+void mt753x_lock_gsw(void)
+{
+	mutex_lock(&mt753x_devs_lock);
+}
+
+static int mt753x_hw_reset(struct gsw_mt753x *gsw)
+{
+	struct device_node *np = gsw->dev->of_node;
+	struct reset_control *rstc;
+	int mcm;
+	int ret = -EINVAL;
+
+	mcm = of_property_read_bool(np, "mediatek,mcm");
+	if (mcm) {
+		rstc = devm_reset_control_get(gsw->dev, "mcm");
+		ret = IS_ERR(rstc);
+		if (IS_ERR(rstc)) {
+			dev_err(gsw->dev, "Missing reset ctrl of switch\n");
+			return ret;
+		}
+
+		reset_control_assert(rstc);
+		msleep(30);
+		reset_control_deassert(rstc);
+
+		gsw->reset_pin = -1;
+		return 0;
+	}
+
+	gsw->reset_pin = of_get_named_gpio(np, "reset-gpios", 0);
+	if (gsw->reset_pin < 0) {
+		dev_err(gsw->dev, "Missing reset pin of switch\n");
+		return ret;
+	}
+
+	ret = devm_gpio_request(gsw->dev, gsw->reset_pin, "mt753x-reset");
+	if (ret) {
+		dev_info(gsw->dev, "Failed to request gpio %d\n",
+			 gsw->reset_pin);
+		return ret;
+	}
+
+	gpio_direction_output(gsw->reset_pin, 0);
+	msleep(30);
+	gpio_set_value(gsw->reset_pin, 1);
+	msleep(500);
+
+	return 0;
+}
+#if 1 //XDXDXDXD
+static int mt753x_mdio_read(struct mii_bus *bus, int addr, int reg)
+{
+	struct gsw_mt753x *gsw = bus->priv;
+
+	return gsw->mii_read(gsw, addr, reg);
+}
+
+static int mt753x_mdio_write(struct mii_bus *bus, int addr, int reg, u16 val)
+{
+	struct gsw_mt753x *gsw = bus->priv;
+
+	gsw->mii_write(gsw, addr, reg, val);
+
+	return 0;
+}
+
+static const struct net_device_ops mt753x_dummy_netdev_ops = {
+};
+
+static void mt753x_phy_link_handler(struct net_device *dev)
+{
+	struct mt753x_phy *phy = container_of(dev, struct mt753x_phy, netdev);
+	struct phy_device *phydev = phy->phydev;
+	struct gsw_mt753x *gsw = phy->gsw;
+	u32 port = phy - gsw->phys;
+
+	if (phydev->link) {
+		dev_info(gsw->dev,
+			 "Port %d Link is Up - %s/%s - flow control %s\n",
+			 port, phy_speed_to_str(phydev->speed),
+			 (phydev->duplex == DUPLEX_FULL) ? "Full" : "Half",
+			 phydev->pause ? "rx/tx" : "off");
+	} else {
+		dev_info(gsw->dev, "Port %d Link is Down\n", port);
+	}
+}
+
+static void mt753x_connect_internal_phys(struct gsw_mt753x *gsw,
+					 struct device_node *mii_np)
+{
+	struct device_node *phy_np;
+	struct mt753x_phy *phy;
+	int phy_mode;
+	u32 phyad;
+
+	if (!mii_np)
+		return;
+
+	for_each_child_of_node(mii_np, phy_np) {
+		if (of_property_read_u32(phy_np, "reg", &phyad))
+			continue;
+
+		if (phyad >= MT753X_NUM_PHYS)
+			continue;
+
+		phy_mode = of_get_phy_mode(phy_np);
+		if (phy_mode < 0) {
+			dev_info(gsw->dev, "incorrect phy-mode %d for PHY %d\n",
+				 phy_mode, phyad);
+			continue;
+		}
+
+		phy = &gsw->phys[phyad];
+		phy->gsw = gsw;
+
+		init_dummy_netdev(&phy->netdev);
+		phy->netdev.netdev_ops = &mt753x_dummy_netdev_ops;
+
+		phy->phydev = of_phy_connect(&phy->netdev, phy_np,
+					mt753x_phy_link_handler, 0, phy_mode);
+		if (!phy->phydev) {
+			dev_info(gsw->dev, "could not connect to PHY %d\n",
+				 phyad);
+			continue;
+		}
+
+		phy_start(phy->phydev);
+	}
+}
+
+static void mt753x_disconnect_internal_phys(struct gsw_mt753x *gsw)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(gsw->phys); i++) {
+		if (gsw->phys[i].phydev) {
+			phy_stop(gsw->phys[i].phydev);
+			phy_disconnect(gsw->phys[i].phydev);
+			gsw->phys[i].phydev = NULL;
+		}
+	}
+}
+
+static int mt753x_mdio_register(struct gsw_mt753x *gsw)
+{
+	struct device_node *mii_np;
+	int i, ret;
+
+	mii_np = of_get_child_by_name(gsw->dev->of_node, "mdio-bus");
+	if (mii_np && !of_device_is_available(mii_np)) {
+		ret = -ENODEV;
+		goto err_put_node;
+	}
+
+	gsw->gphy_bus = devm_mdiobus_alloc(gsw->dev);
+	if (!gsw->gphy_bus) {
+		ret = -ENOMEM;
+		goto err_put_node;
+	}
+
+	gsw->gphy_bus->name = "mt753x_mdio";
+	gsw->gphy_bus->read = mt753x_mdio_read;
+	gsw->gphy_bus->write = mt753x_mdio_write;
+	gsw->gphy_bus->priv = gsw;
+	gsw->gphy_bus->parent = gsw->dev;
+	gsw->gphy_bus->phy_mask = BIT(MT753X_NUM_PHYS) - 1;
+//	gsw->gphy_bus->irq = gsw->phy_irqs;
+
+	for (i = 0; i < PHY_MAX_ADDR; i++)
+		gsw->gphy_bus->irq[i] = PHY_POLL;
+
+	if (mii_np)
+		snprintf(gsw->gphy_bus->id, MII_BUS_ID_SIZE, "%s@%s",
+			 mii_np->name, gsw->dev->of_node->name);
+	else
+		snprintf(gsw->gphy_bus->id, MII_BUS_ID_SIZE, "mdio@%s",
+			 gsw->dev->of_node->name);
+
+	ret = of_mdiobus_register(gsw->gphy_bus, mii_np);
+
+	if (ret) {
+		devm_mdiobus_free(gsw->dev, gsw->gphy_bus);
+		gsw->gphy_bus = NULL;
+	} else {
+		if (gsw->phy_status_poll)
+			mt753x_connect_internal_phys(gsw, mii_np);
+	}
+
+err_put_node:
+	if (mii_np)
+		of_node_put(mii_np);
+
+	return ret;
+}
+#endif
+
+static irqreturn_t mt753x_irq_handler(int irq, void *dev)
+{
+	struct gsw_mt753x *gsw = dev;
+
+	disable_irq_nosync(gsw->irq);
+
+	schedule_work(&gsw->irq_worker);
+
+	return IRQ_HANDLED;
+}
+
+static int mt753x_probe(struct platform_device *pdev)
+{
+	struct gsw_mt753x *gsw;
+	struct mt753x_sw_id *sw;
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *mdio;
+	struct mii_bus *mdio_bus;
+	int ret = -EINVAL;
+	struct chip_rev rev;
+	struct mt753x_mapping *map;
+	int i;
+
+	mdio = of_parse_phandle(np, "mediatek,mdio", 0);
+	if (!mdio)
+		return -EINVAL;
+
+	mdio_bus = of_mdio_find_bus(mdio);
+	if (!mdio_bus)
+		return -EPROBE_DEFER;
+
+	gsw = devm_kzalloc(&pdev->dev, sizeof(struct gsw_mt753x), GFP_KERNEL);
+	if (!gsw)
+		return -ENOMEM;
+
+	gsw->host_bus = mdio_bus;
+	gsw->dev = &pdev->dev;
+	mutex_init(&gsw->mii_lock);
+
+	/* Switch hard reset */
+	if (mt753x_hw_reset(gsw))
+		goto fail;
+
+	/* Fetch the SMI address dirst */
+	if (of_property_read_u32(np, "mediatek,smi-addr", &gsw->smi_addr))
+		gsw->smi_addr = MT753X_DFL_SMI_ADDR;
+
+	/* Get LAN/WAN port mapping */
+	map = mt753x_find_mapping(np);
+	if (map) {
+		mt753x_apply_mapping(gsw, map);
+		gsw->global_vlan_enable = 1;
+		dev_info(gsw->dev, "LAN/WAN VLAN setting=%s\n", map->name);
+	}
+
+	/* Load MAC port configurations */
+	mt753x_load_port_cfg(gsw);
+
+	/* Check for valid switch and then initialize */
+	for (i = 0; i < ARRAY_SIZE(mt753x_sw_ids); i++) {
+		if (!mt753x_sw_ids[i]->detect(gsw, &rev)) {
+			sw = mt753x_sw_ids[i];
+
+			gsw->name = rev.name;
+			gsw->model = sw->model;
+
+			dev_info(gsw->dev, "Switch is MediaTek %s rev %d",
+				 gsw->name, rev.rev);
+
+			/* Initialize the switch */
+			ret = sw->init(gsw);
+			if (ret)
+				goto fail;
+
+			break;
+		}
+	}
+
+	if (i >= ARRAY_SIZE(mt753x_sw_ids)) {
+		dev_err(gsw->dev, "No mt753x switch found\n");
+		goto fail;
+	}
+
+	gsw->irq = platform_get_irq(pdev, 0);
+	if (gsw->irq >= 0) {
+		ret = devm_request_irq(gsw->dev, gsw->irq, mt753x_irq_handler,
+				       0, dev_name(gsw->dev), gsw);
+		if (ret) {
+			dev_err(gsw->dev, "Failed to request irq %d\n",
+				gsw->irq);
+			goto fail;
+		}
+
+		INIT_WORK(&gsw->irq_worker, mt753x_irq_worker);
+	}
+
+	platform_set_drvdata(pdev, gsw);
+
+	gsw->phy_status_poll = of_property_read_bool(gsw->dev->of_node,
+						     "mediatek,phy-poll");
+
+	mt753x_add_gsw(gsw);
+#if 1 //XDXD
+	mt753x_mdio_register(gsw);
+#endif
+
+	mt753x_swconfig_init(gsw);
+
+	if (sw->post_init)
+		sw->post_init(gsw);
+
+	if (gsw->irq >= 0)
+		mt753x_irq_enable(gsw);
+
+	return 0;
+
+fail:
+	devm_kfree(&pdev->dev, gsw);
+
+	return ret;
+}
+
+static int mt753x_remove(struct platform_device *pdev)
+{
+	struct gsw_mt753x *gsw = platform_get_drvdata(pdev);
+
+	if (gsw->irq >= 0)
+		cancel_work_sync(&gsw->irq_worker);
+
+	if (gsw->reset_pin >= 0)
+		devm_gpio_free(&pdev->dev, gsw->reset_pin);
+
+#ifdef CONFIG_SWCONFIG
+	mt753x_swconfig_destroy(gsw);
+#endif
+
+#if 1 //XDXD
+	mt753x_disconnect_internal_phys(gsw);
+
+	mdiobus_unregister(gsw->gphy_bus);
+#endif
+
+	mt753x_remove_gsw(gsw);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static const struct of_device_id mt753x_ids[] = {
+	{ .compatible = "mediatek,mt753x" },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(of, mt753x_ids);
+
+static struct platform_driver mt753x_driver = {
+	.probe = mt753x_probe,
+	.remove = mt753x_remove,
+	.driver = {
+		.name = "mt753x",
+		.of_match_table = mt753x_ids,
+	},
+};
+
+static int __init mt753x_init(void)
+{
+	int ret;
+
+	INIT_LIST_HEAD(&mt753x_devs);
+	ret = platform_driver_register(&mt753x_driver);
+
+	mt753x_nl_init();
+
+	return ret;
+}
+module_init(mt753x_init);
+
+static void __exit mt753x_exit(void)
+{
+	mt753x_nl_exit();
+
+	platform_driver_unregister(&mt753x_driver);
+}
+module_exit(mt753x_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Weijie Gao <weijie.gao@mediatek.com>");
+MODULE_DESCRIPTION("Driver for MediaTek MT753x Gigabit Switch");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_nl.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_nl.c
new file mode 100755
index 0000000..a04c701
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_nl.c
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Sirui Zhao <Sirui.Zhao@mediatek.com>
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <net/genetlink.h>
+
+#include "mt753x.h"
+#include "mt753x_nl.h"
+
+struct mt753x_nl_cmd_item {
+	enum mt753x_cmd cmd;
+	bool require_dev;
+	int (*process)(struct genl_info *info, struct gsw_mt753x *gsw);
+	u32 nr_required_attrs;
+	const enum mt753x_attr *required_attrs;
+};
+
+static int mt753x_nl_response(struct sk_buff *skb, struct genl_info *info);
+
+static const struct nla_policy mt753x_nl_cmd_policy[] = {
+	[MT753X_ATTR_TYPE_MESG] = { .type = NLA_STRING },
+	[MT753X_ATTR_TYPE_PHY] = { .type = NLA_S32 },
+	[MT753X_ATTR_TYPE_REG] = { .type = NLA_S32 },
+	[MT753X_ATTR_TYPE_VAL] = { .type = NLA_S32 },
+	[MT753X_ATTR_TYPE_DEV_NAME] = { .type = NLA_S32 },
+	[MT753X_ATTR_TYPE_DEV_ID] = { .type = NLA_S32 },
+	[MT753X_ATTR_TYPE_DEVAD] = { .type = NLA_S32 },
+};
+
+static const struct genl_ops mt753x_nl_ops[] = {
+	{
+		.cmd = MT753X_CMD_REQUEST,
+		.doit = mt753x_nl_response,
+//		.policy = mt753x_nl_cmd_policy,
+		.flags = GENL_ADMIN_PERM,
+	}, {
+		.cmd = MT753X_CMD_READ,
+		.doit = mt753x_nl_response,
+//		.policy = mt753x_nl_cmd_policy,
+		.flags = GENL_ADMIN_PERM,
+	}, {
+		.cmd = MT753X_CMD_WRITE,
+		.doit = mt753x_nl_response,
+//		.policy = mt753x_nl_cmd_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+};
+
+static struct genl_family mt753x_nl_family = {
+	.name =		MT753X_GENL_NAME,
+	.version =	MT753X_GENL_VERSION,
+	.maxattr =	MT753X_NR_ATTR_TYPE,
+	.ops =		mt753x_nl_ops,
+	.n_ops =	ARRAY_SIZE(mt753x_nl_ops),
+	.policy =	mt753x_nl_cmd_policy,
+};
+
+static int mt753x_nl_list_devs(char *buff, int size)
+{
+	struct gsw_mt753x *gsw;
+	int len, total = 0;
+	char buf[80];
+
+	memset(buff, 0, size);
+
+	mt753x_lock_gsw();
+
+	list_for_each_entry(gsw, &mt753x_devs, list) {
+		len = snprintf(buf, sizeof(buf),
+			       "id: %d, model: %s, node: %s\n",
+			       gsw->id, gsw->name, gsw->dev->of_node->name);
+		strncat(buff, buf, size - total);
+		total += len;
+	}
+
+	mt753x_put_gsw();
+
+	return total;
+}
+
+static int mt753x_nl_prepare_reply(struct genl_info *info, u8 cmd,
+				   struct sk_buff **skbp)
+{
+	struct sk_buff *msg;
+	void *reply;
+
+	if (!info)
+		return -EINVAL;
+
+	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	/* Construct send-back message header */
+	reply = genlmsg_put(msg, info->snd_portid, info->snd_seq,
+			    &mt753x_nl_family, 0, cmd);
+	if (!reply) {
+		nlmsg_free(msg);
+		return -EINVAL;
+	}
+
+	*skbp = msg;
+	return 0;
+}
+
+static int mt753x_nl_send_reply(struct sk_buff *skb, struct genl_info *info)
+{
+	struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
+	void *reply = genlmsg_data(genlhdr);
+
+	/* Finalize a generic netlink message (update message header) */
+	genlmsg_end(skb, reply);
+
+	/* reply to a request */
+	return genlmsg_reply(skb, info);
+}
+
+static s32 mt753x_nl_get_s32(struct genl_info *info, enum mt753x_attr attr,
+			     s32 defval)
+{
+	struct nlattr *na;
+
+	na = info->attrs[attr];
+	if (na)
+		return nla_get_s32(na);
+
+	return defval;
+}
+
+static int mt753x_nl_get_u32(struct genl_info *info, enum mt753x_attr attr,
+			     u32 *val)
+{
+	struct nlattr *na;
+
+	na = info->attrs[attr];
+	if (na) {
+		*val = nla_get_u32(na);
+		return 0;
+	}
+
+	return -1;
+}
+
+static struct gsw_mt753x *mt753x_nl_parse_find_gsw(struct genl_info *info)
+{
+	struct gsw_mt753x *gsw;
+	struct nlattr *na;
+	int gsw_id;
+
+	na = info->attrs[MT753X_ATTR_TYPE_DEV_ID];
+	if (na) {
+		gsw_id = nla_get_s32(na);
+		if (gsw_id >= 0)
+			gsw = mt753x_get_gsw(gsw_id);
+		else
+			gsw = mt753x_get_first_gsw();
+	} else {
+		gsw = mt753x_get_first_gsw();
+	}
+
+	return gsw;
+}
+
+static int mt753x_nl_get_swdevs(struct genl_info *info, struct gsw_mt753x *gsw)
+{
+	struct sk_buff *rep_skb = NULL;
+	char dev_info[512];
+	int ret;
+
+	ret = mt753x_nl_list_devs(dev_info, sizeof(dev_info));
+	if (!ret) {
+		pr_info("No switch registered\n");
+		return -EINVAL;
+	}
+
+	ret = mt753x_nl_prepare_reply(info, MT753X_CMD_REPLY, &rep_skb);
+	if (ret < 0)
+		goto err;
+
+	ret = nla_put_string(rep_skb, MT753X_ATTR_TYPE_MESG, dev_info);
+	if (ret < 0)
+		goto err;
+
+	return mt753x_nl_send_reply(rep_skb, info);
+
+err:
+	if (rep_skb)
+		nlmsg_free(rep_skb);
+
+	return ret;
+}
+
+static int mt753x_nl_reply_read(struct genl_info *info, struct gsw_mt753x *gsw)
+{
+	struct sk_buff *rep_skb = NULL;
+	s32 phy, devad, reg;
+	int value;
+	int ret = 0;
+
+	phy = mt753x_nl_get_s32(info, MT753X_ATTR_TYPE_PHY, -1);
+	devad = mt753x_nl_get_s32(info, MT753X_ATTR_TYPE_DEVAD, -1);
+	reg = mt753x_nl_get_s32(info, MT753X_ATTR_TYPE_REG, -1);
+
+	if (reg < 0)
+		goto err;
+
+	ret = mt753x_nl_prepare_reply(info, MT753X_CMD_READ, &rep_skb);
+	if (ret < 0)
+		goto err;
+
+	if (phy >= 0) {
+		if (devad < 0)
+			value = gsw->mii_read(gsw, phy, reg);
+		else
+			value = gsw->mmd_read(gsw, phy, devad, reg);
+	} else {
+		value = mt753x_reg_read(gsw, reg);
+	}
+
+	ret = nla_put_s32(rep_skb, MT753X_ATTR_TYPE_REG, reg);
+	if (ret < 0)
+		goto err;
+
+	ret = nla_put_s32(rep_skb, MT753X_ATTR_TYPE_VAL, value);
+	if (ret < 0)
+		goto err;
+
+	return mt753x_nl_send_reply(rep_skb, info);
+
+err:
+	if (rep_skb)
+		nlmsg_free(rep_skb);
+
+	return ret;
+}
+
+static int mt753x_nl_reply_write(struct genl_info *info, struct gsw_mt753x *gsw)
+{
+	struct sk_buff *rep_skb = NULL;
+	s32 phy, devad, reg;
+	u32 value;
+	int ret = 0;
+
+	phy = mt753x_nl_get_s32(info, MT753X_ATTR_TYPE_PHY, -1);
+	devad = mt753x_nl_get_s32(info, MT753X_ATTR_TYPE_DEVAD, -1);
+	reg = mt753x_nl_get_s32(info, MT753X_ATTR_TYPE_REG, -1);
+
+	if (mt753x_nl_get_u32(info, MT753X_ATTR_TYPE_VAL, &value))
+		goto err;
+
+	if (reg < 0)
+		goto err;
+
+	ret = mt753x_nl_prepare_reply(info, MT753X_CMD_WRITE, &rep_skb);
+	if (ret < 0)
+		goto err;
+
+	if (phy >= 0) {
+		if (devad < 0)
+			gsw->mii_write(gsw, phy, reg, value);
+		else
+			gsw->mmd_write(gsw, phy, devad, reg, value);
+	} else {
+		mt753x_reg_write(gsw, reg, value);
+	}
+
+	ret = nla_put_s32(rep_skb, MT753X_ATTR_TYPE_REG, reg);
+	if (ret < 0)
+		goto err;
+
+	ret = nla_put_s32(rep_skb, MT753X_ATTR_TYPE_VAL, value);
+	if (ret < 0)
+		goto err;
+
+	return mt753x_nl_send_reply(rep_skb, info);
+
+err:
+	if (rep_skb)
+		nlmsg_free(rep_skb);
+
+	return ret;
+}
+
+static const enum mt753x_attr mt753x_nl_cmd_read_attrs[] = {
+	MT753X_ATTR_TYPE_REG
+};
+
+static const enum mt753x_attr mt753x_nl_cmd_write_attrs[] = {
+	MT753X_ATTR_TYPE_REG,
+	MT753X_ATTR_TYPE_VAL
+};
+
+static const struct mt753x_nl_cmd_item mt753x_nl_cmds[] = {
+	{
+		.cmd = MT753X_CMD_REQUEST,
+		.require_dev = false,
+		.process = mt753x_nl_get_swdevs
+	}, {
+		.cmd = MT753X_CMD_READ,
+		.require_dev = true,
+		.process = mt753x_nl_reply_read,
+		.required_attrs = mt753x_nl_cmd_read_attrs,
+		.nr_required_attrs = ARRAY_SIZE(mt753x_nl_cmd_read_attrs),
+	}, {
+		.cmd = MT753X_CMD_WRITE,
+		.require_dev = true,
+		.process = mt753x_nl_reply_write,
+		.required_attrs = mt753x_nl_cmd_write_attrs,
+		.nr_required_attrs = ARRAY_SIZE(mt753x_nl_cmd_write_attrs),
+	}
+};
+
+static int mt753x_nl_response(struct sk_buff *skb, struct genl_info *info)
+{
+	struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
+	const struct mt753x_nl_cmd_item *cmditem = NULL;
+	struct gsw_mt753x *gsw = NULL;
+	u32 sat_req_attrs = 0;
+	int i, ret;
+
+	for (i = 0; i < ARRAY_SIZE(mt753x_nl_cmds); i++) {
+		if (hdr->cmd == mt753x_nl_cmds[i].cmd) {
+			cmditem = &mt753x_nl_cmds[i];
+			break;
+		}
+	}
+
+	if (!cmditem) {
+		pr_info("mt753x-nl: unknown cmd %u\n", hdr->cmd);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < cmditem->nr_required_attrs; i++) {
+		if (info->attrs[cmditem->required_attrs[i]])
+			sat_req_attrs++;
+	}
+
+	if (sat_req_attrs != cmditem->nr_required_attrs) {
+		pr_info("mt753x-nl: missing required attr(s) for cmd %u\n",
+			hdr->cmd);
+		return -EINVAL;
+	}
+
+	if (cmditem->require_dev) {
+		gsw = mt753x_nl_parse_find_gsw(info);
+		if (!gsw) {
+			pr_info("mt753x-nl: failed to find switch dev\n");
+			return -EINVAL;
+		}
+	}
+
+	ret = cmditem->process(info, gsw);
+
+	mt753x_put_gsw();
+
+	return ret;
+}
+
+int __init mt753x_nl_init(void)
+{
+	int ret;
+
+	ret = genl_register_family(&mt753x_nl_family);
+	if (ret) {
+		pr_info("mt753x-nl: genl_register_family_with_ops failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+void __exit mt753x_nl_exit(void)
+{
+	genl_unregister_family(&mt753x_nl_family);
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_nl.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_nl.h
new file mode 100644
index 0000000..85dc9e7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_nl.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Sirui Zhao <Sirui.Zhao@mediatek.com>
+ */
+
+#ifndef _MT753X_NL_H_
+#define _MT753X_NL_H_
+
+#define MT753X_GENL_NAME		"mt753x"
+#define MT753X_GENL_VERSION		0x1
+
+enum mt753x_cmd {
+	MT753X_CMD_UNSPEC = 0,
+	MT753X_CMD_REQUEST,
+	MT753X_CMD_REPLY,
+	MT753X_CMD_READ,
+	MT753X_CMD_WRITE,
+
+	__MT753X_CMD_MAX,
+};
+
+enum mt753x_attr {
+	MT753X_ATTR_TYPE_UNSPEC = 0,
+	MT753X_ATTR_TYPE_MESG,
+	MT753X_ATTR_TYPE_PHY,
+	MT753X_ATTR_TYPE_DEVAD,
+	MT753X_ATTR_TYPE_REG,
+	MT753X_ATTR_TYPE_VAL,
+	MT753X_ATTR_TYPE_DEV_NAME,
+	MT753X_ATTR_TYPE_DEV_ID,
+
+	__MT753X_ATTR_TYPE_MAX,
+};
+
+#define MT753X_NR_ATTR_TYPE		(__MT753X_ATTR_TYPE_MAX - 1)
+
+#ifdef __KERNEL__
+int __init mt753x_nl_init(void);
+void __exit mt753x_nl_exit(void);
+#endif /* __KERNEL__ */
+
+#endif /* _MT753X_NL_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_regs.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_regs.h
new file mode 100755
index 0000000..1784873
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_regs.h
@@ -0,0 +1,344 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#ifndef _MT753X_REGS_H_
+#define _MT753X_REGS_H_
+
+#include <linux/bitops.h>
+
+/* Values of Egress TAG Control */
+#define ETAG_CTRL_UNTAG			0
+#define ETAG_CTRL_TAG			2
+#define ETAG_CTRL_SWAP			1
+#define ETAG_CTRL_STACK			3
+
+#define VTCR				0x90
+#define VAWD1				0x94
+#define VAWD2				0x98
+
+/* Fields of VTCR */
+#define VTCR_BUSY			BIT(31)
+#define IDX_INVLD			BIT(16)
+#define VTCR_FUNC_S			12
+#define VTCR_FUNC_M			0xf000
+#define VTCR_VID_S			0
+#define VTCR_VID_M			0xfff
+
+/* Values of VTCR_FUNC */
+#define VTCR_READ_VLAN_ENTRY		0
+#define VTCR_WRITE_VLAN_ENTRY		1
+#define VTCR_INVD_VLAN_ENTRY		2
+#define VTCR_ENABLE_VLAN_ENTRY		3
+#define VTCR_READ_ACL_ENTRY		4
+#define VTCR_WRITE_ACL_ENTRY		5
+#define VTCR_READ_TRTCM_TABLE		6
+#define VTCR_WRITE_TRTCM_TABLE		7
+#define VTCR_READ_ACL_MASK_ENTRY	8
+#define VTCR_WRITE_ACL_MASK_ENTRY	9
+#define VTCR_READ_ACL_RULE_ENTRY	10
+#define VTCR_WRITE_ACL_RULE_ENTRY	11
+#define VTCR_READ_ACL_RATE_ENTRY	12
+#define VTCR_WRITE_ACL_RATE_ENTRY	13
+
+/* VLAN entry fields */
+/* VAWD1 */
+#define PORT_STAG			BIT(31)
+#define IVL_MAC				BIT(30)
+#define EG_CON				BIT(29)
+#define VTAG_EN				BIT(28)
+#define COPY_PRI			BIT(27)
+#define USER_PRI_S			24
+#define USER_PRI_M			0x7000000
+#define PORT_MEM_S			16
+#define PORT_MEM_M			0xff0000
+#define S_TAG1_S			4
+#define S_TAG1_M			0xfff0
+#define FID_S				1
+#define FID_M				0x0e
+#define VENTRY_VALID			BIT(0)
+
+/* VAWD2 */
+#define S_TAG2_S			16
+#define S_TAG2_M			0xffff0000
+#define PORT_ETAG_S(p)			((p) * 2)
+#define PORT_ETAG_M			0x03
+
+#define PORT_CTRL_BASE			0x2000
+#define PORT_CTRL_PORT_OFFSET		0x100
+#define PORT_CTRL_REG(p, r)		(PORT_CTRL_BASE + \
+					(p) * PORT_CTRL_PORT_OFFSET +  (r))
+#define CKGCR(p)			PORT_CTRL_REG(p, 0x00)
+#define PCR(p)				PORT_CTRL_REG(p, 0x04)
+#define PIC(p)				PORT_CTRL_REG(p, 0x08)
+#define PSC(p)				PORT_CTRL_REG(p, 0x0c)
+#define PVC(p)				PORT_CTRL_REG(p, 0x10)
+#define PPBV1(p)			PORT_CTRL_REG(p, 0x14)
+#define PPBV2(p)			PORT_CTRL_REG(p, 0x18)
+#define BSR(p)				PORT_CTRL_REG(p, 0x1c)
+#define STAG01				PORT_CTRL_REG(p, 0x20)
+#define STAG23				PORT_CTRL_REG(p, 0x24)
+#define STAG45				PORT_CTRL_REG(p, 0x28)
+#define STAG67				PORT_CTRL_REG(p, 0x2c)
+
+#define PPBV(p, g)			(PPBV1(p) + ((g) / 2) * 4)
+
+/* Fields of PCR */
+#define MLDV2_EN			BIT(30)
+#define EG_TAG_S			28
+#define EG_TAG_M			0x30000000
+#define PORT_PRI_S			24
+#define PORT_PRI_M			0x7000000
+#define PORT_MATRIX_S			16
+#define PORT_MATRIX_M			0xff0000
+#define UP2DSCP_EN			BIT(12)
+#define UP2TAG_EN			BIT(11)
+#define ACL_EN				BIT(10)
+#define PORT_TX_MIR			BIT(9)
+#define PORT_RX_MIR			BIT(8)
+#define ACL_MIR				BIT(7)
+#define MIS_PORT_FW_S			4
+#define MIS_PORT_FW_M			0x70
+#define VLAN_MIS			BIT(2)
+#define PORT_VLAN_S			0
+#define PORT_VLAN_M			0x03
+
+/* Values of PORT_VLAN */
+#define PORT_MATRIX_MODE		0
+#define FALLBACK_MODE			1
+#define CHECK_MODE			2
+#define SECURITY_MODE			3
+
+/* Fields of PVC */
+#define STAG_VPID_S			16
+#define STAG_VPID_M			0xffff0000
+#define DIS_PVID			BIT(15)
+#define FORCE_PVID			BIT(14)
+#define PT_VPM				BIT(12)
+#define PT_OPTION			BIT(11)
+#define PVC_EG_TAG_S			8
+#define PVC_EG_TAG_M			0x700
+#define VLAN_ATTR_S			6
+#define VLAN_ATTR_M			0xc0
+#define PVC_PORT_STAG			BIT(5)
+#define BC_LKYV_EN			BIT(4)
+#define MC_LKYV_EN			BIT(3)
+#define UC_LKYV_EN			BIT(2)
+#define ACC_FRM_S			0
+#define ACC_FRM_M			0x03
+
+/* Values of VLAN_ATTR */
+#define VA_USER_PORT			0
+#define VA_STACK_PORT			1
+#define VA_TRANSLATION_PORT		2
+#define VA_TRANSPARENT_PORT		3
+
+/* Fields of PPBV */
+#define GRP_PORT_PRI_S(g)		(((g) % 2) * 16 + 13)
+#define GRP_PORT_PRI_M			0x07
+#define GRP_PORT_VID_S(g)		(((g) % 2) * 16)
+#define GRP_PORT_VID_M			0xfff
+
+#define PORT_MAC_CTRL_BASE		0x3000
+#define PORT_MAC_CTRL_PORT_OFFSET	0x100
+#define PORT_MAC_CTRL_REG(p, r)		(PORT_MAC_CTRL_BASE + \
+					(p) * PORT_MAC_CTRL_PORT_OFFSET + (r))
+#define PMCR(p)				PORT_MAC_CTRL_REG(p, 0x00)
+#define PMEEECR(p)			PORT_MAC_CTRL_REG(p, 0x04)
+#define PMSR(p)				PORT_MAC_CTRL_REG(p, 0x08)
+#define PINT_EN(p)			PORT_MAC_CTRL_REG(p, 0x10)
+#define PINT_STS(p)			PORT_MAC_CTRL_REG(p, 0x14)
+
+#define GMACCR				(PORT_MAC_CTRL_BASE + 0xe0)
+#define TXCRC_EN			BIT(19)
+#define RXCRC_EN			BIT(18)
+#define PRMBL_LMT_EN			BIT(17)
+#define MTCC_LMT_S			9
+#define MTCC_LMT_M			0x1e00
+#define MAX_RX_JUMBO_S			2
+#define MAX_RX_JUMBO_M			0x3c
+#define MAX_RX_PKT_LEN_S		0
+#define MAX_RX_PKT_LEN_M		0x3
+
+/* Values of MAX_RX_PKT_LEN */
+#define RX_PKT_LEN_1518			0
+#define RX_PKT_LEN_1536			1
+#define RX_PKT_LEN_1522			2
+#define RX_PKT_LEN_MAX_JUMBO		3
+
+/* Fields of PMCR */
+#define IPG_CFG_S			18
+#define IPG_CFG_M			0xc0000
+#define EXT_PHY				BIT(17)
+#define MAC_MODE			BIT(16)
+#define MAC_TX_EN			BIT(14)
+#define MAC_RX_EN			BIT(13)
+#define MAC_PRE				BIT(11)
+#define BKOFF_EN			BIT(9)
+#define BACKPR_EN			BIT(8)
+#define FORCE_EEE1G			BIT(7)
+#define FORCE_EEE1000			BIT(6)
+#define FORCE_RX_FC			BIT(5)
+#define FORCE_TX_FC			BIT(4)
+#define FORCE_SPD_S			2
+#define FORCE_SPD_M			0x0c
+#define FORCE_DPX			BIT(1)
+#define FORCE_LINK			BIT(0)
+
+/* Fields of PMSR */
+#define EEE1G_STS			BIT(7)
+#define EEE100_STS			BIT(6)
+#define RX_FC_STS			BIT(5)
+#define TX_FC_STS			BIT(4)
+#define MAC_SPD_STS_S			2
+#define MAC_SPD_STS_M			0x0c
+#define MAC_DPX_STS			BIT(1)
+#define MAC_LNK_STS			BIT(0)
+
+/* Values of MAC_SPD_STS */
+#define MAC_SPD_10			0
+#define MAC_SPD_100			1
+#define MAC_SPD_1000			2
+#define MAC_SPD_2500			3
+
+/* Values of IPG_CFG */
+#define IPG_96BIT			0
+#define IPG_96BIT_WITH_SHORT_IPG	1
+#define IPG_64BIT			2
+
+#define MIB_COUNTER_BASE		0x4000
+#define MIB_COUNTER_PORT_OFFSET		0x100
+#define MIB_COUNTER_REG(p, r)		(MIB_COUNTER_BASE + \
+					(p) * MIB_COUNTER_PORT_OFFSET + (r))
+#define STATS_TDPC			0x00
+#define STATS_TCRC			0x04
+#define STATS_TUPC			0x08
+#define STATS_TMPC			0x0C
+#define STATS_TBPC			0x10
+#define STATS_TCEC			0x14
+#define STATS_TSCEC			0x18
+#define STATS_TMCEC			0x1C
+#define STATS_TDEC			0x20
+#define STATS_TLCEC			0x24
+#define STATS_TXCEC			0x28
+#define STATS_TPPC			0x2C
+#define STATS_TL64PC			0x30
+#define STATS_TL65PC			0x34
+#define STATS_TL128PC			0x38
+#define STATS_TL256PC			0x3C
+#define STATS_TL512PC			0x40
+#define STATS_TL1024PC			0x44
+#define STATS_TOC			0x48
+#define STATS_RDPC			0x60
+#define STATS_RFPC			0x64
+#define STATS_RUPC			0x68
+#define STATS_RMPC			0x6C
+#define STATS_RBPC			0x70
+#define STATS_RAEPC			0x74
+#define STATS_RCEPC			0x78
+#define STATS_RUSPC			0x7C
+#define STATS_RFEPC			0x80
+#define STATS_ROSPC			0x84
+#define STATS_RJEPC			0x88
+#define STATS_RPPC			0x8C
+#define STATS_RL64PC			0x90
+#define STATS_RL65PC			0x94
+#define STATS_RL128PC			0x98
+#define STATS_RL256PC			0x9C
+#define STATS_RL512PC			0xA0
+#define STATS_RL1024PC			0xA4
+#define STATS_ROC			0xA8
+#define STATS_RDPC_CTRL			0xB0
+#define STATS_RDPC_ING			0xB4
+#define STATS_RDPC_ARL			0xB8
+
+#define SYS_CTRL			0x7000
+#define SW_PHY_RST			BIT(2)
+#define SW_SYS_RST			BIT(1)
+#define SW_REG_RST			BIT(0)
+
+#define SYS_INT_EN			0x7008
+#define SYS_INT_STS			0x700c
+#define MAC_PC_INT			BIT(16)
+#define PHY_INT(p)			BIT((p) + 8)
+#define PHY_LC_INT(p)			BIT(p)
+
+#define PHY_IAC				0x701c
+#define PHY_ACS_ST			BIT(31)
+#define MDIO_REG_ADDR_S			25
+#define MDIO_REG_ADDR_M			0x3e000000
+#define MDIO_PHY_ADDR_S			20
+#define MDIO_PHY_ADDR_M			0x1f00000
+#define MDIO_CMD_S			18
+#define MDIO_CMD_M			0xc0000
+#define MDIO_ST_S			16
+#define MDIO_ST_M			0x30000
+#define MDIO_RW_DATA_S			0
+#define MDIO_RW_DATA_M			0xffff
+
+/* MDIO_CMD: MDIO commands */
+#define MDIO_CMD_ADDR			0
+#define MDIO_CMD_WRITE			1
+#define MDIO_CMD_READ			2
+#define MDIO_CMD_READ_C45		3
+
+/* MDIO_ST: MDIO start field */
+#define MDIO_ST_C45			0
+#define MDIO_ST_C22			1
+
+#define HWSTRAP				0x7800
+#define MHWSTRAP			0x7804
+
+/* Internal GPHY Page Control Register */
+#define PHY_CL22_PAGE_CTRL		0x1f
+#define PHY_TR_PAGE			0x52b5
+
+/* Internal GPHY Token Ring Access Registers */
+#define PHY_TR_CTRL			0x10
+#define PHY_TR_LOW_DATA			0x11
+#define PHY_TR_HIGH_DATA		0x12
+
+/* Fields of PHY_TR_CTRL */
+#define PHY_TR_PKT_XMT_STA		BIT(15)
+#define PHY_TR_WR_S			13
+#define PHY_TR_CH_ADDR_S		11
+#define PHY_TR_NODE_ADDR_S		7
+#define PHY_TR_DATA_ADDR_S		1
+
+enum phy_tr_wr {
+	PHY_TR_WRITE = 0,
+	PHY_TR_READ = 1,
+};
+
+/* Helper macro for GPHY Token Ring Access */
+#define PHY_TR_LOW_VAL(x)		((x) & 0xffff)
+#define PHY_TR_HIGH_VAL(x)		(((x) & 0xff0000) >> 16)
+
+/* Token Ring Channels */
+#define PMA_CH				0x1
+#define DSP_CH				0x2
+
+/* Token Ring Nodes */
+#define PMA_NOD				0xf
+#define DSP_NOD				0xd
+
+/* Token Ring register range */
+enum tr_pma_reg_addr {
+	PMA_MIN = 0x0,
+	PMA_01  = 0x1,
+	PMA_17  = 0x17,
+	PMA_18  = 0x18,
+	PMA_MAX = 0x3d,
+};
+
+enum tr_dsp_reg_addr {
+	DSP_MIN = 0x0,
+	DSP_06  = 0x6,
+	DSP_08  = 0x8,
+	DSP_0f  = 0xf,
+	DSP_10  = 0x10,
+	DSP_MAX = 0x3e,
+};
+#endif /* _MT753X_REGS_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_swconfig.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_swconfig.c
new file mode 100755
index 0000000..7a05952
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_swconfig.c
@@ -0,0 +1,517 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include <linux/if.h>
+#include <linux/list.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/netlink.h>
+#include <linux/bitops.h>
+#include <net/genetlink.h>
+#include <linux/delay.h>
+#include <linux/phy.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/lockdep.h>
+#include <linux/workqueue.h>
+#include <linux/of_device.h>
+
+#include "mt753x.h"
+#include "mt753x_swconfig.h"
+#include "mt753x_regs.h"
+
+#define MT753X_PORT_MIB_TXB_ID	18	/* TxByte */
+#define MT753X_PORT_MIB_RXB_ID	37	/* RxByte */
+
+#define MIB_DESC(_s, _o, _n)   \
+	{                       \
+		.size = (_s),   \
+		.offset = (_o), \
+		.name = (_n),   \
+	}
+
+struct mt753x_mib_desc {
+	unsigned int size;
+	unsigned int offset;
+	const char *name;
+};
+
+static const struct mt753x_mib_desc mt753x_mibs[] = {
+	MIB_DESC(1, STATS_TDPC, "TxDrop"),
+	MIB_DESC(1, STATS_TCRC, "TxCRC"),
+	MIB_DESC(1, STATS_TUPC, "TxUni"),
+	MIB_DESC(1, STATS_TMPC, "TxMulti"),
+	MIB_DESC(1, STATS_TBPC, "TxBroad"),
+	MIB_DESC(1, STATS_TCEC, "TxCollision"),
+	MIB_DESC(1, STATS_TSCEC, "TxSingleCol"),
+	MIB_DESC(1, STATS_TMCEC, "TxMultiCol"),
+	MIB_DESC(1, STATS_TDEC, "TxDefer"),
+	MIB_DESC(1, STATS_TLCEC, "TxLateCol"),
+	MIB_DESC(1, STATS_TXCEC, "TxExcCol"),
+	MIB_DESC(1, STATS_TPPC, "TxPause"),
+	MIB_DESC(1, STATS_TL64PC, "Tx64Byte"),
+	MIB_DESC(1, STATS_TL65PC, "Tx65Byte"),
+	MIB_DESC(1, STATS_TL128PC, "Tx128Byte"),
+	MIB_DESC(1, STATS_TL256PC, "Tx256Byte"),
+	MIB_DESC(1, STATS_TL512PC, "Tx512Byte"),
+	MIB_DESC(1, STATS_TL1024PC, "Tx1024Byte"),
+	MIB_DESC(2, STATS_TOC, "TxByte"),
+	MIB_DESC(1, STATS_RDPC, "RxDrop"),
+	MIB_DESC(1, STATS_RFPC, "RxFiltered"),
+	MIB_DESC(1, STATS_RUPC, "RxUni"),
+	MIB_DESC(1, STATS_RMPC, "RxMulti"),
+	MIB_DESC(1, STATS_RBPC, "RxBroad"),
+	MIB_DESC(1, STATS_RAEPC, "RxAlignErr"),
+	MIB_DESC(1, STATS_RCEPC, "RxCRC"),
+	MIB_DESC(1, STATS_RUSPC, "RxUnderSize"),
+	MIB_DESC(1, STATS_RFEPC, "RxFragment"),
+	MIB_DESC(1, STATS_ROSPC, "RxOverSize"),
+	MIB_DESC(1, STATS_RJEPC, "RxJabber"),
+	MIB_DESC(1, STATS_RPPC, "RxPause"),
+	MIB_DESC(1, STATS_RL64PC, "Rx64Byte"),
+	MIB_DESC(1, STATS_RL65PC, "Rx65Byte"),
+	MIB_DESC(1, STATS_RL128PC, "Rx128Byte"),
+	MIB_DESC(1, STATS_RL256PC, "Rx256Byte"),
+	MIB_DESC(1, STATS_RL512PC, "Rx512Byte"),
+	MIB_DESC(1, STATS_RL1024PC, "Rx1024Byte"),
+	MIB_DESC(2, STATS_ROC, "RxByte"),
+	MIB_DESC(1, STATS_RDPC_CTRL, "RxCtrlDrop"),
+	MIB_DESC(1, STATS_RDPC_ING, "RxIngDrop"),
+	MIB_DESC(1, STATS_RDPC_ARL, "RxARLDrop")
+};
+
+enum {
+	/* Global attributes. */
+	MT753X_ATTR_ENABLE_VLAN,
+};
+
+static int mt753x_get_vlan_enable(struct switch_dev *dev,
+				  const struct switch_attr *attr,
+				  struct switch_val *val)
+{
+	struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev);
+
+	val->value.i = gsw->global_vlan_enable;
+
+	return 0;
+}
+
+static int mt753x_set_vlan_enable(struct switch_dev *dev,
+				  const struct switch_attr *attr,
+				  struct switch_val *val)
+{
+	struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev);
+
+	gsw->global_vlan_enable = val->value.i != 0;
+
+	return 0;
+}
+
+static int mt753x_get_port_pvid(struct switch_dev *dev, int port, int *val)
+{
+	struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev);
+
+	if (port >= MT753X_NUM_PORTS)
+		return -EINVAL;
+
+	*val = mt753x_reg_read(gsw, PPBV1(port));
+	*val &= GRP_PORT_VID_M;
+
+	return 0;
+}
+
+static int mt753x_set_port_pvid(struct switch_dev *dev, int port, int pvid)
+{
+	struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev);
+
+	if (port >= MT753X_NUM_PORTS)
+		return -EINVAL;
+
+	if (pvid < MT753X_MIN_VID || pvid > MT753X_MAX_VID)
+		return -EINVAL;
+
+	gsw->port_entries[port].pvid = pvid;
+
+	return 0;
+}
+
+static int mt753x_get_vlan_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev);
+	u32 member;
+	u32 etags;
+	int i;
+
+	val->len = 0;
+
+	if (val->port_vlan < 0 || val->port_vlan >= MT753X_NUM_VLANS)
+		return -EINVAL;
+
+	mt753x_vlan_ctrl(gsw, VTCR_READ_VLAN_ENTRY, val->port_vlan);
+
+	member = mt753x_reg_read(gsw, VAWD1);
+	member &= PORT_MEM_M;
+	member >>= PORT_MEM_S;
+
+	etags = mt753x_reg_read(gsw, VAWD2);
+
+	for (i = 0; i < MT753X_NUM_PORTS; i++) {
+		struct switch_port *p;
+		int etag;
+
+		if (!(member & BIT(i)))
+			continue;
+
+		p = &val->value.ports[val->len++];
+		p->id = i;
+
+		etag = (etags >> PORT_ETAG_S(i)) & PORT_ETAG_M;
+
+		if (etag == ETAG_CTRL_TAG)
+			p->flags |= BIT(SWITCH_PORT_FLAG_TAGGED);
+		else if (etag != ETAG_CTRL_UNTAG)
+			dev_info(gsw->dev,
+				 "vlan egress tag control neither untag nor tag.\n");
+	}
+
+	return 0;
+}
+
+static int mt753x_set_vlan_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev);
+	u8 member = 0;
+	u8 etags = 0;
+	int i;
+
+	if (val->port_vlan < 0 || val->port_vlan >= MT753X_NUM_VLANS ||
+	    val->len > MT753X_NUM_PORTS)
+		return -EINVAL;
+
+	for (i = 0; i < val->len; i++) {
+		struct switch_port *p = &val->value.ports[i];
+
+		if (p->id >= MT753X_NUM_PORTS)
+			return -EINVAL;
+
+		member |= BIT(p->id);
+
+		if (p->flags & BIT(SWITCH_PORT_FLAG_TAGGED))
+			etags |= BIT(p->id);
+	}
+
+	gsw->vlan_entries[val->port_vlan].member = member;
+	gsw->vlan_entries[val->port_vlan].etags = etags;
+
+	return 0;
+}
+
+static int mt753x_set_vid(struct switch_dev *dev,
+			  const struct switch_attr *attr,
+			  struct switch_val *val)
+{
+	struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev);
+	int vlan;
+	u16 vid;
+
+	vlan = val->port_vlan;
+	vid = (u16)val->value.i;
+
+	if (vlan < 0 || vlan >= MT753X_NUM_VLANS)
+		return -EINVAL;
+
+	if (vid < MT753X_MIN_VID || vid > MT753X_MAX_VID)
+		return -EINVAL;
+
+	gsw->vlan_entries[vlan].vid = vid;
+	return 0;
+}
+
+static int mt753x_get_vid(struct switch_dev *dev,
+			  const struct switch_attr *attr,
+			  struct switch_val *val)
+{
+	val->value.i = val->port_vlan;
+	return 0;
+}
+
+static int mt753x_get_port_link(struct switch_dev *dev, int port,
+				struct switch_port_link *link)
+{
+	struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev);
+	u32 speed, pmsr;
+
+	if (port < 0 || port >= MT753X_NUM_PORTS)
+		return -EINVAL;
+
+	pmsr = mt753x_reg_read(gsw, PMSR(port));
+
+	link->link = pmsr & MAC_LNK_STS;
+	link->duplex = pmsr & MAC_DPX_STS;
+	speed = (pmsr & MAC_SPD_STS_M) >> MAC_SPD_STS_S;
+
+	switch (speed) {
+	case MAC_SPD_10:
+		link->speed = SWITCH_PORT_SPEED_10;
+		break;
+	case MAC_SPD_100:
+		link->speed = SWITCH_PORT_SPEED_100;
+		break;
+	case MAC_SPD_1000:
+		link->speed = SWITCH_PORT_SPEED_1000;
+		break;
+	case MAC_SPD_2500:
+		/* TODO: swconfig has no support for 2500 now */
+		link->speed = SWITCH_PORT_SPEED_UNKNOWN;
+		break;
+	}
+
+	return 0;
+}
+
+static int mt753x_set_port_link(struct switch_dev *dev, int port,
+				struct switch_port_link *link)
+{
+#ifndef MODULE
+	if (port >= MT753X_NUM_PHYS)
+		return -EINVAL;
+
+	return switch_generic_set_link(dev, port, link);
+#else
+	return -ENOTSUPP;
+#endif
+}
+
+static u64 get_mib_counter(struct gsw_mt753x *gsw, int i, int port)
+{
+	unsigned int offset;
+	u64 lo, hi, hi2;
+
+	offset = mt753x_mibs[i].offset;
+
+	if (mt753x_mibs[i].size == 1)
+		return mt753x_reg_read(gsw, MIB_COUNTER_REG(port, offset));
+
+	do {
+		hi = mt753x_reg_read(gsw, MIB_COUNTER_REG(port, offset + 4));
+		lo = mt753x_reg_read(gsw, MIB_COUNTER_REG(port, offset));
+		hi2 = mt753x_reg_read(gsw, MIB_COUNTER_REG(port, offset + 4));
+	} while (hi2 != hi);
+
+	return (hi << 32) | lo;
+}
+
+static int mt753x_get_port_mib(struct switch_dev *dev,
+			       const struct switch_attr *attr,
+			       struct switch_val *val)
+{
+	static char buf[4096];
+	struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev);
+	int i, len = 0;
+
+	if (val->port_vlan >= MT753X_NUM_PORTS)
+		return -EINVAL;
+
+	len += snprintf(buf + len, sizeof(buf) - len,
+			"Port %d MIB counters\n", val->port_vlan);
+
+	for (i = 0; i < ARRAY_SIZE(mt753x_mibs); ++i) {
+		u64 counter;
+
+		len += snprintf(buf + len, sizeof(buf) - len,
+				"%-11s: ", mt753x_mibs[i].name);
+		counter = get_mib_counter(gsw, i, val->port_vlan);
+		len += snprintf(buf + len, sizeof(buf) - len, "%llu\n",
+				counter);
+	}
+
+	val->value.s = buf;
+	val->len = len;
+	return 0;
+}
+
+static int mt753x_get_port_stats(struct switch_dev *dev, int port,
+				 struct switch_port_stats *stats)
+{
+	struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev);
+
+	if (port < 0 || port >= MT753X_NUM_PORTS)
+		return -EINVAL;
+
+	stats->tx_bytes = get_mib_counter(gsw, MT753X_PORT_MIB_TXB_ID, port);
+	stats->rx_bytes = get_mib_counter(gsw, MT753X_PORT_MIB_RXB_ID, port);
+
+	return 0;
+}
+
+static void mt753x_port_isolation(struct gsw_mt753x *gsw)
+{
+	int i;
+
+	for (i = 0; i < MT753X_NUM_PORTS; i++)
+		mt753x_reg_write(gsw, PCR(i),
+				 BIT(gsw->cpu_port) << PORT_MATRIX_S);
+
+	mt753x_reg_write(gsw, PCR(gsw->cpu_port), PORT_MATRIX_M);
+
+	for (i = 0; i < MT753X_NUM_PORTS; i++) {
+		u32 pvc_mode = 0x8100 << STAG_VPID_S;
+
+		if ((gsw->port5_cfg.stag_on && i == 5) ||
+		    (gsw->port6_cfg.stag_on && i == 6))
+			pvc_mode |= PVC_PORT_STAG;
+		else
+			pvc_mode |= (VA_TRANSPARENT_PORT << VLAN_ATTR_S);
+
+		mt753x_reg_write(gsw, PVC(i), pvc_mode);
+	}
+}
+
+static int mt753x_apply_config(struct switch_dev *dev)
+{
+	struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev);
+
+	if (!gsw->global_vlan_enable) {
+		mt753x_port_isolation(gsw);
+		return 0;
+	}
+
+	mt753x_apply_vlan_config(gsw);
+
+	return 0;
+}
+
+static int mt753x_reset_switch(struct switch_dev *dev)
+{
+	struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev);
+	int i;
+
+	memset(gsw->port_entries, 0, sizeof(gsw->port_entries));
+	memset(gsw->vlan_entries, 0, sizeof(gsw->vlan_entries));
+
+	/* set default vid of each vlan to the same number of vlan, so the vid
+	 * won't need be set explicitly.
+	 */
+	for (i = 0; i < MT753X_NUM_VLANS; i++)
+		gsw->vlan_entries[i].vid = i;
+
+	return 0;
+}
+
+static int mt753x_phy_read16(struct switch_dev *dev, int addr, u8 reg,
+			     u16 *value)
+{
+	struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev);
+
+	*value = gsw->mii_read(gsw, addr, reg);
+
+	return 0;
+}
+
+static int mt753x_phy_write16(struct switch_dev *dev, int addr, u8 reg,
+			      u16 value)
+{
+	struct gsw_mt753x *gsw = container_of(dev, struct gsw_mt753x, swdev);
+
+	gsw->mii_write(gsw, addr, reg, value);
+
+	return 0;
+}
+
+static const struct switch_attr mt753x_global[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "VLAN mode (1:enabled)",
+		.max = 1,
+		.id = MT753X_ATTR_ENABLE_VLAN,
+		.get = mt753x_get_vlan_enable,
+		.set = mt753x_set_vlan_enable,
+	}
+};
+
+static const struct switch_attr mt753x_port[] = {
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "mib",
+		.description = "Get MIB counters for port",
+		.get = mt753x_get_port_mib,
+		.set = NULL,
+	},
+};
+
+static const struct switch_attr mt753x_vlan[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "vid",
+		.description = "VLAN ID (0-4094)",
+		.set = mt753x_set_vid,
+		.get = mt753x_get_vid,
+		.max = 4094,
+	},
+};
+
+static const struct switch_dev_ops mt753x_swdev_ops = {
+	.attr_global = {
+		.attr = mt753x_global,
+		.n_attr = ARRAY_SIZE(mt753x_global),
+	},
+	.attr_port = {
+		.attr = mt753x_port,
+		.n_attr = ARRAY_SIZE(mt753x_port),
+	},
+	.attr_vlan = {
+		.attr = mt753x_vlan,
+		.n_attr = ARRAY_SIZE(mt753x_vlan),
+	},
+	.get_vlan_ports = mt753x_get_vlan_ports,
+	.set_vlan_ports = mt753x_set_vlan_ports,
+	.get_port_pvid = mt753x_get_port_pvid,
+	.set_port_pvid = mt753x_set_port_pvid,
+	.get_port_link = mt753x_get_port_link,
+	.set_port_link = mt753x_set_port_link,
+	.get_port_stats = mt753x_get_port_stats,
+	.apply_config = mt753x_apply_config,
+	.reset_switch = mt753x_reset_switch,
+	.phy_read16 = mt753x_phy_read16,
+	.phy_write16 = mt753x_phy_write16,
+};
+
+int mt753x_swconfig_init(struct gsw_mt753x *gsw)
+{
+	struct device_node *np = gsw->dev->of_node;
+	struct switch_dev *swdev;
+	int ret;
+
+	if (of_property_read_u32(np, "mediatek,cpuport", &gsw->cpu_port))
+		gsw->cpu_port = MT753X_DFL_CPU_PORT;
+
+	swdev = &gsw->swdev;
+
+	swdev->name = gsw->name;
+	swdev->alias = gsw->name;
+	swdev->cpu_port = gsw->cpu_port;
+	swdev->ports = MT753X_NUM_PORTS;
+	swdev->vlans = MT753X_NUM_VLANS;
+	swdev->ops = &mt753x_swdev_ops;
+
+	ret = register_switch(swdev, NULL);
+	if (ret) {
+		dev_notice(gsw->dev, "Failed to register switch %s\n",
+			   swdev->name);
+		return ret;
+	}
+
+	mt753x_apply_config(swdev);
+
+	return 0;
+}
+
+void mt753x_swconfig_destroy(struct gsw_mt753x *gsw)
+{
+	unregister_switch(&gsw->swdev);
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_swconfig.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_swconfig.h
new file mode 100644
index 0000000..f000364
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_swconfig.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#ifndef _MT753X_SWCONFIG_H_
+#define _MT753X_SWCONFIG_H_
+
+#ifdef CONFIG_SWCONFIG
+#include <linux/switch.h>
+#include "mt753x.h"
+
+int mt753x_swconfig_init(struct gsw_mt753x *gsw);
+void mt753x_swconfig_destroy(struct gsw_mt753x *gsw);
+#else
+static inline int mt753x_swconfig_init(struct gsw_mt753x *gsw)
+{
+	mt753x_apply_vlan_config(gsw);
+
+	return 0;
+}
+
+static inline void mt753x_swconfig_destroy(struct gsw_mt753x *gsw)
+{
+}
+#endif
+
+#endif /* _MT753X_SWCONFIG_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_vlan.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_vlan.c
new file mode 100755
index 0000000..9667097
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_vlan.c
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ */
+
+#include "mt753x.h"
+#include "mt753x_regs.h"
+
+struct mt753x_mapping mt753x_def_mapping[] = {
+	{
+		.name = "llllw",
+		.pvids = { 1, 1, 1, 1, 2, 2, 1 },
+		.members = { 0, 0x4f, 0x30 },
+		.etags = { 0, 0, 0 },
+		.vids = { 0, 1, 2 },
+	}, {
+		.name = "wllll",
+		.pvids = { 2, 1, 1, 1, 1, 2, 1 },
+		.members = { 0, 0x5e, 0x21 },
+		.etags = { 0, 0, 0 },
+		.vids = { 0, 1, 2 },
+	}, {
+		.name = "lwlll",
+		.pvids = { 1, 2, 1, 1, 1, 2, 1 },
+		.members = { 0, 0x5d, 0x22 },
+		.etags = { 0, 0, 0 },
+		.vids = { 0, 1, 2 },
+	}, {
+		.name = "lllll",
+		.pvids = { 1, 1, 1, 1, 1, 1, 1 },
+		.members = { 0, 0x7f },
+		.etags = { 0, 0 },
+		.vids = { 0, 1 },
+	},
+};
+
+void mt753x_vlan_ctrl(struct gsw_mt753x *gsw, u32 cmd, u32 val)
+{
+	int i;
+
+	mt753x_reg_write(gsw, VTCR,
+			 VTCR_BUSY | ((cmd << VTCR_FUNC_S) & VTCR_FUNC_M) |
+			 (val & VTCR_VID_M));
+
+	for (i = 0; i < 300; i++) {
+		u32 val = mt753x_reg_read(gsw, VTCR);
+
+		if ((val & VTCR_BUSY) == 0)
+			break;
+
+		usleep_range(1000, 1100);
+	}
+
+	if (i == 300)
+		dev_info(gsw->dev, "vtcr timeout\n");
+}
+
+static void mt753x_write_vlan_entry(struct gsw_mt753x *gsw, int vlan, u16 vid,
+				    u8 ports, u8 etags)
+{
+	int port;
+	u32 val;
+
+	/* vlan port membership */
+	if (ports)
+		mt753x_reg_write(gsw, VAWD1,
+				 IVL_MAC | VTAG_EN | VENTRY_VALID |
+				 ((ports << PORT_MEM_S) & PORT_MEM_M));
+	else
+		mt753x_reg_write(gsw, VAWD1, 0);
+
+	/* egress mode */
+	val = 0;
+	for (port = 0; port < MT753X_NUM_PORTS; port++) {
+		if (etags & BIT(port))
+			val |= ETAG_CTRL_TAG << PORT_ETAG_S(port);
+		else
+			val |= ETAG_CTRL_UNTAG << PORT_ETAG_S(port);
+	}
+	mt753x_reg_write(gsw, VAWD2, val);
+
+	/* write to vlan table */
+	mt753x_vlan_ctrl(gsw, VTCR_WRITE_VLAN_ENTRY, vid);
+}
+
+void mt753x_apply_vlan_config(struct gsw_mt753x *gsw)
+{
+	int i, j;
+	u8 tag_ports;
+	u8 untag_ports;
+
+	/* set all ports as security mode */
+	for (i = 0; i < MT753X_NUM_PORTS; i++)
+		mt753x_reg_write(gsw, PCR(i),
+				 PORT_MATRIX_M | SECURITY_MODE);
+
+	/* check if a port is used in tag/untag vlan egress mode */
+	tag_ports = 0;
+	untag_ports = 0;
+
+	for (i = 0; i < MT753X_NUM_VLANS; i++) {
+		u8 member = gsw->vlan_entries[i].member;
+		u8 etags = gsw->vlan_entries[i].etags;
+
+		if (!member)
+			continue;
+
+		for (j = 0; j < MT753X_NUM_PORTS; j++) {
+			if (!(member & BIT(j)))
+				continue;
+
+			if (etags & BIT(j))
+				tag_ports |= 1u << j;
+			else
+				untag_ports |= 1u << j;
+		}
+	}
+
+	/* set all untag-only ports as transparent and the rest as user port */
+	for (i = 0; i < MT753X_NUM_PORTS; i++) {
+		u32 pvc_mode = 0x8100 << STAG_VPID_S;
+
+		if (untag_ports & BIT(i) && !(tag_ports & BIT(i)))
+			pvc_mode = (0x8100 << STAG_VPID_S) |
+				(VA_TRANSPARENT_PORT << VLAN_ATTR_S);
+
+		if ((gsw->port5_cfg.stag_on && i == 5) ||
+		    (gsw->port6_cfg.stag_on && i == 6))
+			pvc_mode = (0x8100 << STAG_VPID_S) | PVC_PORT_STAG;
+
+		mt753x_reg_write(gsw, PVC(i), pvc_mode);
+	}
+
+	/* first clear the switch vlan table */
+	for (i = 0; i < MT753X_NUM_VLANS; i++)
+		mt753x_write_vlan_entry(gsw, i, i, 0, 0);
+
+	/* now program only vlans with members to avoid
+	 * clobbering remapped entries in later iterations
+	 */
+	for (i = 0; i < MT753X_NUM_VLANS; i++) {
+		u16 vid = gsw->vlan_entries[i].vid;
+		u8 member = gsw->vlan_entries[i].member;
+		u8 etags = gsw->vlan_entries[i].etags;
+
+		if (member)
+			mt753x_write_vlan_entry(gsw, i, vid, member, etags);
+	}
+
+	/* Port Default PVID */
+	for (i = 0; i < MT753X_NUM_PORTS; i++) {
+		int vlan = gsw->port_entries[i].pvid;
+		u16 pvid = 0;
+		u32 val;
+
+		if (vlan < MT753X_NUM_VLANS && gsw->vlan_entries[vlan].member)
+			pvid = gsw->vlan_entries[vlan].vid;
+
+		val = mt753x_reg_read(gsw, PPBV1(i));
+		val &= ~GRP_PORT_VID_M;
+		val |= pvid;
+		mt753x_reg_write(gsw, PPBV1(i), val);
+	}
+}
+
+struct mt753x_mapping *mt753x_find_mapping(struct device_node *np)
+{
+	const char *map;
+	int i;
+
+	if (of_property_read_string(np, "mediatek,portmap", &map))
+		return NULL;
+
+	for (i = 0; i < ARRAY_SIZE(mt753x_def_mapping); i++)
+		if (!strcmp(map, mt753x_def_mapping[i].name))
+			return &mt753x_def_mapping[i];
+
+	return NULL;
+}
+
+void mt753x_apply_mapping(struct gsw_mt753x *gsw, struct mt753x_mapping *map)
+{
+	int i = 0;
+
+	for (i = 0; i < MT753X_NUM_PORTS; i++)
+		gsw->port_entries[i].pvid = map->pvids[i];
+
+	for (i = 0; i < MT753X_NUM_VLANS; i++) {
+		gsw->vlan_entries[i].member = map->members[i];
+		gsw->vlan_entries[i].etags = map->etags[i];
+		gsw->vlan_entries[i].vid = map->vids[i];
+	}
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_vlan.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_vlan.h
new file mode 100644
index 0000000..c726b8e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_vlan.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ */
+
+#ifndef _MT753X_VLAN_H_
+#define _MT753X_VLAN_H_
+
+#define MT753X_NUM_PORTS	7
+#define MT753X_NUM_VLANS	4095
+#define MT753X_MAX_VID		4095
+#define MT753X_MIN_VID		0
+
+struct gsw_mt753x;
+
+struct mt753x_port_entry {
+	u16	pvid;
+};
+
+struct mt753x_vlan_entry {
+	u16	vid;
+	u8	member;
+	u8	etags;
+};
+
+struct mt753x_mapping {
+	char	*name;
+	u16	pvids[MT753X_NUM_PORTS];
+	u8	members[MT753X_NUM_VLANS];
+	u8	etags[MT753X_NUM_VLANS];
+	u16	vids[MT753X_NUM_VLANS];
+};
+
+extern struct mt753x_mapping mt753x_defaults[];
+
+void mt753x_vlan_ctrl(struct gsw_mt753x *gsw, u32 cmd, u32 val);
+void mt753x_apply_vlan_config(struct gsw_mt753x *gsw);
+struct mt753x_mapping *mt753x_find_mapping(struct device_node *np);
+void mt753x_apply_mapping(struct gsw_mt753x *gsw, struct mt753x_mapping *map);
+#endif /* _MT753X_VLAN_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/Makefile
new file mode 100644
index 0000000..0f2891e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/Makefile
@@ -0,0 +1,66 @@
+obj-$(CONFIG_RTL8367S_GSW) += rtl8367s_gsw.o
+rtl8367s_gsw-objs := rtl8367s_mdio.o rtl8367s_dbg.o
+ifeq ($(CONFIG_SWCONFIG),y)
+rtl8367s_gsw-objs += rtl8367s.o
+endif
+rtl8367s_gsw-objs += rtl8367c/acl.o
+rtl8367s_gsw-objs += rtl8367c/cpu.o
+rtl8367s_gsw-objs += rtl8367c/dot1x.o
+rtl8367s_gsw-objs += rtl8367c/eee.o
+rtl8367s_gsw-objs += rtl8367c/igmp.o
+rtl8367s_gsw-objs += rtl8367c/interrupt.o
+rtl8367s_gsw-objs += rtl8367c/l2.o
+rtl8367s_gsw-objs += rtl8367c/leaky.o
+rtl8367s_gsw-objs += rtl8367c/led.o
+rtl8367s_gsw-objs += rtl8367c/mirror.o
+rtl8367s_gsw-objs += rtl8367c/oam.o
+rtl8367s_gsw-objs += rtl8367c/port.o
+rtl8367s_gsw-objs += rtl8367c/ptp.o
+rtl8367s_gsw-objs += rtl8367c/qos.o
+rtl8367s_gsw-objs += rtl8367c/rate.o
+rtl8367s_gsw-objs += rtl8367c/rldp.o
+rtl8367s_gsw-objs += rtl8367c/rtk_switch.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_acl.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_cputag.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_dot1x.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_eav.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_eee.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_fc.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_green.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_hsb.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_igmp.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_inbwctrl.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_interrupt.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_led.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_lut.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_meter.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_mib.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_mirror.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_misc.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_oam.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_phy.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_port.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_portIsolation.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_qos.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_rldp.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_rma.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_scheduling.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_storm.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_svlan.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_trunking.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_unknownMulticast.o
+rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_vlan.o
+rtl8367s_gsw-objs += rtl8367c/smi.o
+rtl8367s_gsw-objs += rtl8367c/stat.o
+rtl8367s_gsw-objs += rtl8367c/storm.o
+rtl8367s_gsw-objs += rtl8367c/svlan.o
+rtl8367s_gsw-objs += rtl8367c/trap.o
+rtl8367s_gsw-objs += rtl8367c/trunk.o
+rtl8367s_gsw-objs += rtl8367c/vlan.o
+
+ccflags-y += -Werror -D_LITTLE_ENDIAN -DMDC_MDIO_OPERATION
+
+ccflags-y += -Idrivers/net/phy/rtk/rtl8367c/include
+ccflags-y += -Iinclude/linux/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/modules.builtin b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/modules.builtin
new file mode 100644
index 0000000..961a70a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/modules.builtin
@@ -0,0 +1 @@
+kernel/drivers/net/phy/rtk/rtl8367s_gsw.ko
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/acl.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/acl.c
new file mode 100644
index 0000000..75e5a5e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/acl.c
@@ -0,0 +1,2061 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in ACL module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <acl.h>
+#include <vlan.h>
+#include <svlan.h>
+#include <rate.h>
+#include <string.h>
+
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_acl.h>
+#include <rtl8367c_asicdrv_hsb.h>
+#include <rtl8367c_asicdrv_vlan.h>
+#include <rtl8367c_asicdrv_svlan.h>
+#include <rtl8367c_asicdrv_cputag.h>
+#include <rtl8367c_asicdrv_mib.h>
+
+CONST_T rtk_uint8 filter_templateField[RTL8367C_ACLTEMPLATENO][RTL8367C_ACLRULEFIELDNO] = {
+    {ACL_DMAC0,             ACL_DMAC1,          ACL_DMAC2,          ACL_SMAC0,          ACL_SMAC1,          ACL_SMAC2,          ACL_ETHERTYPE,      ACL_FIELD_SELECT15},
+    {ACL_IP4SIP0,           ACL_IP4SIP1,        ACL_IP4DIP0,        ACL_IP4DIP1,        ACL_FIELD_SELECT13, ACL_FIELD_SELECT14, ACL_FIELD_SELECT02, ACL_FIELD_SELECT15},
+    {ACL_IP6SIP0WITHIPV4,   ACL_IP6SIP1WITHIPV4,ACL_FIELD_SELECT03, ACL_FIELD_SELECT04, ACL_FIELD_SELECT05, ACL_FIELD_SELECT06, ACL_FIELD_SELECT07, ACL_FIELD_SELECT08},
+    {ACL_IP6DIP0WITHIPV4,   ACL_IP6DIP1WITHIPV4,ACL_FIELD_SELECT09, ACL_FIELD_SELECT10, ACL_FIELD_SELECT11, ACL_FIELD_SELECT12, ACL_FIELD_SELECT13, ACL_FIELD_SELECT14},
+    {ACL_VIDRANGE,          ACL_IPRANGE,        ACL_PORTRANGE,      ACL_CTAG,           ACL_STAG,           ACL_FIELD_SELECT13, ACL_FIELD_SELECT14, ACL_FIELD_SELECT15}
+};
+
+CONST_T rtk_uint8 filter_advanceCaretagField[RTL8367C_ACLTEMPLATENO][2] = {
+    {TRUE,      7},
+    {TRUE,      7},
+    {FALSE,     0},
+    {FALSE,     0},
+    {TRUE,      7},
+};
+
+
+CONST_T rtk_uint8 filter_fieldTemplateIndex[FILTER_FIELD_END][RTK_FILTER_FIELD_USED_MAX] = {
+    {0x00, 0x01,0x02},
+    {0x03, 0x04,0x05},
+    {0x06},
+    {0x43},
+    {0x44},
+    {0x10, 0x11},
+    {0x12, 0x13},
+    {0x24},
+    {0x25},
+    {0x35},
+    {0x35},
+    {0x20, 0x21,0x22,0x23},
+    {0x30, 0x31,0x32,0x33},
+    {0x26},
+    {0x27},
+    {0x14},
+    {0x15},
+    {0x16},
+    {0x14},
+    {0x15},
+    {0x14},
+    {0x14},
+    {0x14},
+
+    {0x40},
+    {0x41},
+    {0x42},
+
+    {0x14},
+    {0x15},
+    {0x16},
+    {0x22},
+    {0x23},
+    {0x24},
+    {0x25},
+    {0x26},
+    {0x27},
+    {0x32},
+    {0x33},
+    {0x34},
+    {0x35},
+    {0x36},
+    {0x37},
+    {0x47},
+
+    {0xFF} /* Pattern Match */
+};
+
+CONST_T rtk_uint8 filter_fieldSize[FILTER_FIELD_END] = {
+    3, 3, 1, 1, 1,
+    2, 2, 1, 1, 1, 1, 4, 4, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    8
+};
+
+CONST_T rtk_uint16 field_selector[RTL8367C_FIELDSEL_FORMAT_NUMBER][2] =
+{
+    {FIELDSEL_FORMAT_DEFAULT, 0},    /* Field Selector 0 */
+    {FIELDSEL_FORMAT_DEFAULT, 0},    /* Field Selector 1 */
+    {FIELDSEL_FORMAT_IPPAYLOAD, 12}, /* Field Selector 2 */
+    {FIELDSEL_FORMAT_IPV6, 10},      /* Field Selector 3 */
+    {FIELDSEL_FORMAT_IPV6, 8},       /* Field Selector 4 */
+    {FIELDSEL_FORMAT_IPV4, 0},       /* Field Selector 5 */
+    {FIELDSEL_FORMAT_IPV4, 8},       /* Field Selector 6 */
+    {FIELDSEL_FORMAT_IPV6, 0},       /* Field Selector 7 */
+    {FIELDSEL_FORMAT_IPV6, 6},       /* Field Selector 8 */
+    {FIELDSEL_FORMAT_IPV6, 26},      /* Field Selector 9 */
+    {FIELDSEL_FORMAT_IPV6, 24},      /* Field Selector 10 */
+    {FIELDSEL_FORMAT_DEFAULT, 0},    /* Field Selector 11 */
+    {FIELDSEL_FORMAT_IPV4, 6},       /* Field Selector 12 */
+    {FIELDSEL_FORMAT_IPPAYLOAD, 0},  /* Field Selector 13 */
+    {FIELDSEL_FORMAT_IPPAYLOAD, 2},  /* Field Selector 14 */
+    {FIELDSEL_FORMAT_DEFAULT, 0}     /* Field Selector 15 */
+};
+
+
+static rtk_api_ret_t _rtk_filter_igrAcl_writeDataField(rtl8367c_aclrule *aclRule, rtk_filter_field_t *fieldPtr);
+
+
+/* Function Name:
+ *      rtk_filter_igrAcl_init
+ * Description:
+ *      ACL initialization function
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_NULL_POINTER - Pointer pFilter_field or pFilter_cfg point to NULL.
+ * Note:
+ *      This function enable and intialize ACL function
+ */
+rtk_api_ret_t rtk_filter_igrAcl_init(void)
+{
+    rtl8367c_acltemplate_t       aclTemp;
+    rtk_uint32                 i, j;
+    rtk_api_ret_t          ret;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((ret = rtk_filter_igrAcl_cfg_delAll()) != RT_ERR_OK)
+        return ret;
+
+    for(i = 0; i < RTL8367C_ACLTEMPLATENO; i++)
+    {
+        for(j = 0; j < RTL8367C_ACLRULEFIELDNO;j++)
+            aclTemp.field[j] = filter_templateField[i][j];
+
+        if ((ret = rtl8367c_setAsicAclTemplate(i, &aclTemp)) != RT_ERR_OK)
+            return ret;
+    }
+
+    for(i = 0; i < RTL8367C_FIELDSEL_FORMAT_NUMBER; i++)
+    {
+        if ((ret = rtl8367c_setAsicFieldSelector(i, field_selector[i][0], field_selector[i][1])) != RT_ERR_OK)
+            return ret;
+    }
+
+    RTK_SCAN_ALL_PHY_PORTMASK(i)
+    {
+        if ((ret = rtl8367c_setAsicAcl(i, TRUE)) != RT_ERR_OK)
+            return ret;
+
+        if ((ret = rtl8367c_setAsicAclUnmatchedPermit(i, TRUE)) != RT_ERR_OK)
+            return ret;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_filter_igrAcl_field_add
+ * Description:
+ *      Add comparison rule to an ACL configuration
+ * Input:
+ *      pFilter_cfg     - The ACL configuration that this function will add comparison rule
+ *      pFilter_field   - The comparison rule that will be added.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_NULL_POINTER     - Pointer pFilter_field or pFilter_cfg point to NULL.
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ * Note:
+ *      This function add a comparison rule (*pFilter_field) to an ACL configuration (*pFilter_cfg).
+ *      Pointer pFilter_cfg points to an ACL configuration structure, this structure keeps multiple ACL
+ *      comparison rules by means of linked list. Pointer pFilter_field will be added to linked
+ *      list keeped by structure that pFilter_cfg points to.
+ */
+rtk_api_ret_t rtk_filter_igrAcl_field_add(rtk_filter_cfg_t* pFilter_cfg, rtk_filter_field_t* pFilter_field)
+{
+    rtk_uint32 i;
+    rtk_filter_field_t *tailPtr;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pFilter_cfg || NULL == pFilter_field)
+        return RT_ERR_NULL_POINTER;
+
+    if(pFilter_field->fieldType >= FILTER_FIELD_END)
+        return RT_ERR_ENTRY_INDEX;
+
+
+    if(0 == pFilter_field->fieldTemplateNo)
+    {
+        pFilter_field->fieldTemplateNo = filter_fieldSize[pFilter_field->fieldType];
+
+        for(i = 0; i < pFilter_field->fieldTemplateNo; i++)
+        {
+            pFilter_field->fieldTemplateIdx[i] = filter_fieldTemplateIndex[pFilter_field->fieldType][i];
+        }
+    }
+
+    if(NULL == pFilter_cfg->fieldHead)
+    {
+        pFilter_cfg->fieldHead = pFilter_field;
+    }
+    else
+    {
+        if (pFilter_cfg->fieldHead->next == NULL)
+        {
+            pFilter_cfg->fieldHead->next = pFilter_field;
+        }
+        else
+        {
+            tailPtr = pFilter_cfg->fieldHead->next;
+            while( tailPtr->next != NULL)
+            {
+                tailPtr = tailPtr->next;
+            }
+            tailPtr->next = pFilter_field;
+        }
+    }
+
+    return RT_ERR_OK;
+}
+
+static rtk_api_ret_t _rtk_filter_igrAcl_writeDataField(rtl8367c_aclrule *aclRule, rtk_filter_field_t *fieldPtr)
+{
+    rtk_uint32 i, tempIdx,fieldIdx, ipValue, ipMask;
+    rtk_uint32 ip6addr[RTK_IPV6_ADDR_WORD_LENGTH];
+    rtk_uint32 ip6mask[RTK_IPV6_ADDR_WORD_LENGTH];
+
+    for(i = 0; i < fieldPtr->fieldTemplateNo; i++)
+    {
+        tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4;
+
+        aclRule[tempIdx].valid = TRUE;
+    }
+
+    switch (fieldPtr->fieldType)
+    {
+    /* use DMAC structure as representative for mac structure */
+    case FILTER_FIELD_DMAC:
+    case FILTER_FIELD_SMAC:
+
+        for(i = 0; i < fieldPtr->fieldTemplateNo; i++)
+        {
+            tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4;
+            fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F;
+
+            aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.mac.value.octet[5 - i*2] | (fieldPtr->filter_pattern_union.mac.value.octet[5 - (i*2 + 1)] << 8);
+            aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.mac.mask.octet[5 - i*2] | (fieldPtr->filter_pattern_union.mac.mask.octet[5 - (i*2 + 1)] << 8);
+        }
+        break;
+    case FILTER_FIELD_ETHERTYPE:
+        for(i = 0; i < fieldPtr->fieldTemplateNo; i++)
+        {
+            tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4;
+            fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F;
+
+            aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.etherType.value;
+            aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.etherType.mask;
+        }
+        break;
+    case FILTER_FIELD_IPV4_SIP:
+    case FILTER_FIELD_IPV4_DIP:
+
+        ipValue = fieldPtr->filter_pattern_union.sip.value;
+        ipMask = fieldPtr->filter_pattern_union.sip.mask;
+
+        for(i = 0; i < fieldPtr->fieldTemplateNo; i++)
+        {
+            tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4;
+            fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F;
+
+            aclRule[tempIdx].data_bits.field[fieldIdx] = (0xFFFF & (ipValue >> (i*16)));
+            aclRule[tempIdx].care_bits.field[fieldIdx] = (0xFFFF & (ipMask >> (i*16)));
+        }
+        break;
+    case FILTER_FIELD_IPV4_TOS:
+        for(i = 0; i < fieldPtr->fieldTemplateNo; i++)
+        {
+            tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4;
+            fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F;
+
+            aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.ipTos.value & 0xFF;
+            aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.ipTos.mask  & 0xFF;
+        }
+        break;
+    case FILTER_FIELD_IPV4_PROTOCOL:
+        for(i = 0; i < fieldPtr->fieldTemplateNo; i++)
+        {
+            tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4;
+            fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F;
+
+            aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.protocol.value & 0xFF;
+            aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.protocol.mask  & 0xFF;
+        }
+        break;
+    case FILTER_FIELD_IPV6_SIPV6:
+    case FILTER_FIELD_IPV6_DIPV6:
+        for(i = 0; i < RTK_IPV6_ADDR_WORD_LENGTH; i++)
+        {
+            ip6addr[i] = fieldPtr->filter_pattern_union.sipv6.value.addr[i];
+            ip6mask[i] = fieldPtr->filter_pattern_union.sipv6.mask.addr[i];
+        }
+
+        for(i = 0; i < fieldPtr->fieldTemplateNo; i++)
+        {
+            tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4;
+            fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F;
+
+            if(i < 2)
+            {
+                aclRule[tempIdx].data_bits.field[fieldIdx] = ((ip6addr[0] & (0xFFFF << (i * 16))) >> (i * 16));
+                aclRule[tempIdx].care_bits.field[fieldIdx] = ((ip6mask[0] & (0xFFFF << (i * 16))) >> (i * 16));
+            }
+            else
+            {
+                /*default acl template for ipv6 address supports MSB 32-bits and LSB 32-bits only*/
+                aclRule[tempIdx].data_bits.field[fieldIdx] = ((ip6addr[3] & (0xFFFF << ((i&1) * 16))) >> ((i&1) * 16));
+                aclRule[tempIdx].care_bits.field[fieldIdx] = ((ip6mask[3] & (0xFFFF << ((i&1) * 16))) >> ((i&1) * 16));
+            }
+        }
+
+        break;
+    case FILTER_FIELD_CTAG:
+    case FILTER_FIELD_STAG:
+
+        for(i = 0; i < fieldPtr->fieldTemplateNo; i++)
+        {
+            tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4;
+            fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F;
+
+            aclRule[tempIdx].data_bits.field[fieldIdx] = (fieldPtr->filter_pattern_union.l2tag.pri.value << 13) | (fieldPtr->filter_pattern_union.l2tag.cfi.value << 12) | fieldPtr->filter_pattern_union.l2tag.vid.value;
+            aclRule[tempIdx].care_bits.field[fieldIdx] = (fieldPtr->filter_pattern_union.l2tag.pri.mask << 13) | (fieldPtr->filter_pattern_union.l2tag.cfi.mask << 12) | fieldPtr->filter_pattern_union.l2tag.vid.mask;
+        }
+        break;
+    case FILTER_FIELD_IPV4_FLAG:
+
+        for(i = 0; i < fieldPtr->fieldTemplateNo; i++)
+        {
+            tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4;
+            fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F;
+
+            aclRule[tempIdx].data_bits.field[fieldIdx] &= 0x1FFF;
+            aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.ipFlag.xf.value << 15);
+            aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.ipFlag.df.value << 14);
+            aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.ipFlag.mf.value << 13);
+
+            aclRule[tempIdx].care_bits.field[fieldIdx] &= 0x1FFF;
+            aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.ipFlag.xf.mask << 15);
+            aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.ipFlag.df.mask << 14);
+            aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.ipFlag.mf.mask << 13);
+        }
+
+        break;
+    case FILTER_FIELD_IPV4_OFFSET:
+
+        for(i = 0; i < fieldPtr->fieldTemplateNo; i++)
+        {
+            tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4;
+            fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F;
+
+            aclRule[tempIdx].data_bits.field[fieldIdx] &= 0xE000;
+            aclRule[tempIdx].data_bits.field[fieldIdx] |= fieldPtr->filter_pattern_union.inData.value;
+
+            aclRule[tempIdx].care_bits.field[fieldIdx] &= 0xE000;
+            aclRule[tempIdx].care_bits.field[fieldIdx] |= fieldPtr->filter_pattern_union.inData.mask;
+        }
+
+        break;
+
+    case FILTER_FIELD_IPV6_TRAFFIC_CLASS:
+        for(i = 0; i < fieldPtr->fieldTemplateNo; i++)
+        {
+            tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4;
+            fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F;
+
+
+            aclRule[tempIdx].data_bits.field[fieldIdx] = (fieldPtr->filter_pattern_union.inData.value << 4)&0x0FF0;
+            aclRule[tempIdx].care_bits.field[fieldIdx] = (fieldPtr->filter_pattern_union.inData.mask << 4)&0x0FF0;
+        }
+        break;
+    case FILTER_FIELD_IPV6_NEXT_HEADER:
+        for(i = 0; i < fieldPtr->fieldTemplateNo; i++)
+        {
+            tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4;
+            fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F;
+
+            aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.inData.value << 8;
+            aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.inData.mask << 8;
+        }
+        break;
+    case FILTER_FIELD_TCP_SPORT:
+        for(i = 0; i < fieldPtr->fieldTemplateNo; i++)
+        {
+            tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4;
+            fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F;
+
+            aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.tcpSrcPort.value;
+            aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.tcpSrcPort.mask;
+        }
+        break;
+    case FILTER_FIELD_TCP_DPORT:
+        for(i = 0; i < fieldPtr->fieldTemplateNo; i++)
+        {
+            tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4;
+            fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F;
+
+            aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.tcpDstPort.value;
+            aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.tcpDstPort.mask;
+        }
+        break;
+    case FILTER_FIELD_TCP_FLAG:
+
+        for(i = 0; i < fieldPtr->fieldTemplateNo; i++)
+        {
+            tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4;
+            fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F;
+
+            aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.cwr.value << 7);
+            aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.ece.value << 6);
+            aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.urg.value << 5);
+            aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.ack.value << 4);
+            aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.psh.value << 3);
+            aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.rst.value << 2);
+            aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.syn.value << 1);
+            aclRule[tempIdx].data_bits.field[fieldIdx] |= fieldPtr->filter_pattern_union.tcpFlag.fin.value;
+
+            aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.cwr.mask << 7);
+            aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.ece.mask << 6);
+            aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.urg.mask << 5);
+            aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.ack.mask << 4);
+            aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.psh.mask << 3);
+            aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.rst.mask << 2);
+            aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.syn.mask << 1);
+            aclRule[tempIdx].care_bits.field[fieldIdx] |= fieldPtr->filter_pattern_union.tcpFlag.fin.mask;
+        }
+        break;
+    case FILTER_FIELD_UDP_SPORT:
+        for(i = 0; i < fieldPtr->fieldTemplateNo; i++)
+        {
+            tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4;
+            fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F;
+
+            aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.udpSrcPort.value;
+            aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.udpSrcPort.mask;
+        }
+        break;
+    case FILTER_FIELD_UDP_DPORT:
+        for(i = 0; i < fieldPtr->fieldTemplateNo; i++)
+        {
+            tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4;
+            fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F;
+
+            aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.udpDstPort.value;
+            aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.udpDstPort.mask;
+        }
+        break;
+    case FILTER_FIELD_ICMP_CODE:
+        for(i = 0; i < fieldPtr->fieldTemplateNo; i++)
+        {
+            tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4;
+            fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F;
+
+            aclRule[tempIdx].data_bits.field[fieldIdx] &= 0xFF00;
+            aclRule[tempIdx].data_bits.field[fieldIdx] |= fieldPtr->filter_pattern_union.icmpCode.value;
+            aclRule[tempIdx].care_bits.field[fieldIdx] &= 0xFF00;
+            aclRule[tempIdx].care_bits.field[fieldIdx] |= fieldPtr->filter_pattern_union.icmpCode.mask;
+        }
+        break;
+    case FILTER_FIELD_ICMP_TYPE:
+        for(i = 0; i < fieldPtr->fieldTemplateNo; i++)
+        {
+            tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4;
+            fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F;
+
+            aclRule[tempIdx].data_bits.field[fieldIdx] &= 0x00FF;
+            aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.icmpType.value << 8);
+            aclRule[tempIdx].care_bits.field[fieldIdx] &= 0x00FF;
+            aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.icmpType.mask << 8);
+        }
+        break;
+    case FILTER_FIELD_IGMP_TYPE:
+        for(i = 0; i < fieldPtr->fieldTemplateNo; i++)
+        {
+            tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4;
+            fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F;
+
+            aclRule[tempIdx].data_bits.field[fieldIdx] = (fieldPtr->filter_pattern_union.igmpType.value << 8);
+            aclRule[tempIdx].care_bits.field[fieldIdx] = (fieldPtr->filter_pattern_union.igmpType.mask << 8);
+        }
+        break;
+    case FILTER_FIELD_PATTERN_MATCH:
+        for(i = 0; i < fieldPtr->fieldTemplateNo; i++)
+        {
+            tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4;
+            fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F;
+
+            aclRule[tempIdx].data_bits.field[fieldIdx] = ((fieldPtr->filter_pattern_union.pattern.value[i/2] >> (16 * (i%2))) & 0x0000FFFF );
+            aclRule[tempIdx].care_bits.field[fieldIdx] = ((fieldPtr->filter_pattern_union.pattern.mask[i/2] >> (16 * (i%2))) & 0x0000FFFF );
+        }
+        break;
+    case FILTER_FIELD_VID_RANGE:
+    case FILTER_FIELD_IP_RANGE:
+    case FILTER_FIELD_PORT_RANGE:
+    default:
+        tempIdx = (fieldPtr->fieldTemplateIdx[0] & 0xF0) >> 4;
+        fieldIdx = fieldPtr->fieldTemplateIdx[0] & 0x0F;
+
+        aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.inData.value;
+        aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.inData.mask;
+        break;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_filter_igrAcl_cfg_add
+ * Description:
+ *      Add an ACL configuration to ASIC
+ * Input:
+ *      filter_id       - Start index of ACL configuration.
+ *      pFilter_cfg     - The ACL configuration that this function will add comparison rule
+ *      pFilter_action  - Action(s) of ACL configuration.
+ * Output:
+ *      ruleNum - number of rules written in acl table
+ * Return:
+ *      RT_ERR_OK                               - OK
+ *      RT_ERR_FAILED                           - Failed
+ *      RT_ERR_SMI                              - SMI access error
+ *      RT_ERR_NULL_POINTER                     - Pointer pFilter_field or pFilter_cfg point to NULL.
+ *      RT_ERR_INPUT                            - Invalid input parameters.
+ *      RT_ERR_ENTRY_INDEX                      - Invalid filter_id .
+ *      RT_ERR_NULL_POINTER                     - Pointer pFilter_action or pFilter_cfg point to NULL.
+ *      RT_ERR_FILTER_INACL_ACT_NOT_SUPPORT     - Action is not supported in this chip.
+ *      RT_ERR_FILTER_INACL_RULE_NOT_SUPPORT    - Rule is not supported.
+ * Note:
+ *      This function store pFilter_cfg, pFilter_action into ASIC. The starting
+ *      index(es) is filter_id.
+ */
+rtk_api_ret_t rtk_filter_igrAcl_cfg_add(rtk_filter_id_t filter_id, rtk_filter_cfg_t* pFilter_cfg, rtk_filter_action_t* pFilter_action, rtk_filter_number_t *ruleNum)
+{
+    rtk_api_ret_t               retVal;
+    rtk_uint32                  careTagData, careTagMask;
+    rtk_uint32                  i,vidx, svidx, actType, ruleId;
+    rtk_uint32                  aclActCtrl;
+    rtk_uint32                  cpuPort;
+    rtk_filter_field_t*         fieldPtr;
+    rtl8367c_aclrule            aclRule[RTL8367C_ACLTEMPLATENO];
+    rtl8367c_aclrule            tempRule;
+    rtl8367c_acl_act_t          aclAct;
+    rtk_uint32                  noRulesAdd;
+    rtk_uint32                  portmask;
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(filter_id > RTL8367C_ACLRULEMAX )
+        return RT_ERR_ENTRY_INDEX;
+
+    if((NULL == pFilter_cfg) || (NULL == pFilter_action) || (NULL == ruleNum))
+        return RT_ERR_NULL_POINTER;
+
+    fieldPtr = pFilter_cfg->fieldHead;
+
+    /* init RULE */
+    for(i = 0; i < RTL8367C_ACLTEMPLATENO; i++)
+    {
+        memset(&aclRule[i], 0, sizeof(rtl8367c_aclrule));
+
+        aclRule[i].data_bits.type= i;
+        aclRule[i].care_bits.type= 0x7;
+    }
+
+    while(NULL != fieldPtr)
+    {
+        _rtk_filter_igrAcl_writeDataField(aclRule, fieldPtr);
+
+        fieldPtr = fieldPtr->next;
+    }
+
+    /*set care tag mask in User Defined Field 15*/
+    /*Follow care tag should not be used while ACL template and User defined fields are fully control by system designer*/
+    /*those advanced packet type care tag is used in default template design structure only*/
+    careTagData = 0;
+    careTagMask = 0;
+
+    for(i = CARE_TAG_TCP; i < CARE_TAG_END; i++)
+    {
+        if(pFilter_cfg->careTag.tagType[i].mask)
+            careTagMask = careTagMask | (1 << (i-CARE_TAG_TCP));
+
+        if(pFilter_cfg->careTag.tagType[i].value)
+            careTagData = careTagData | (1 << (i-CARE_TAG_TCP));
+    }
+
+    if(careTagData || careTagMask)
+    {
+        i = 0;
+        while(i < RTL8367C_ACLTEMPLATENO)
+        {
+            if(aclRule[i].valid == 1 && filter_advanceCaretagField[i][0] == TRUE)
+            {
+
+                aclRule[i].data_bits.field[filter_advanceCaretagField[i][1]] = careTagData & 0xFFFF;
+                aclRule[i].care_bits.field[filter_advanceCaretagField[i][1]] = careTagMask & 0xFFFF;
+                break;
+            }
+            i++;
+        }
+        /*none of previous used template containing field 15*/
+        if(i == RTL8367C_ACLTEMPLATENO)
+        {
+            i = 0;
+            while(i < RTL8367C_ACLTEMPLATENO)
+            {
+                if(filter_advanceCaretagField[i][0] == TRUE)
+                {
+                    aclRule[i].data_bits.field[filter_advanceCaretagField[i][1]] = careTagData & 0xFFFF;
+                    aclRule[i].care_bits.field[filter_advanceCaretagField[i][1]] = careTagMask & 0xFFFF;
+                    aclRule[i].valid = 1;
+                    break;
+                }
+                i++;
+            }
+        }
+    }
+
+    /*Check rule number*/
+    noRulesAdd = 0;
+    for(i = 0; i < RTL8367C_ACLTEMPLATENO; i++)
+    {
+        if(1 == aclRule[i].valid)
+        {
+            noRulesAdd ++;
+        }
+    }
+
+    *ruleNum = noRulesAdd;
+
+    if((filter_id + noRulesAdd - 1) > RTL8367C_ACLRULEMAX)
+    {
+        return RT_ERR_ENTRY_INDEX;
+    }
+
+    /*set care tag mask in TAG Indicator*/
+    careTagData = 0;
+    careTagMask = 0;
+
+    for(i = 0; i <= CARE_TAG_IPV6;i++)
+    {
+        if(0 == pFilter_cfg->careTag.tagType[i].mask )
+        {
+            careTagMask &=  ~(1 << i);
+        }
+        else
+        {
+            careTagMask |= (1 << i);
+            if(0 == pFilter_cfg->careTag.tagType[i].value )
+                careTagData &= ~(1 << i);
+            else
+                careTagData |= (1 << i);
+        }
+    }
+
+    for(i = 0; i < RTL8367C_ACLTEMPLATENO; i++)
+    {
+        aclRule[i].data_bits.tag_exist = (careTagData) & ACL_RULE_CARETAG_MASK;
+        aclRule[i].care_bits.tag_exist = (careTagMask) & ACL_RULE_CARETAG_MASK;
+    }
+
+    RTK_CHK_PORTMASK_VALID(&pFilter_cfg->activeport.value);
+    RTK_CHK_PORTMASK_VALID(&pFilter_cfg->activeport.mask);
+
+    for(i = 0; i < RTL8367C_ACLTEMPLATENO; i++)
+    {
+        if(TRUE == aclRule[i].valid)
+        {
+            if(rtk_switch_portmask_L2P_get(&pFilter_cfg->activeport.value, &portmask) != RT_ERR_OK)
+                return RT_ERR_PORT_MASK;
+
+            aclRule[i].data_bits.active_portmsk = portmask;
+
+            if(rtk_switch_portmask_L2P_get(&pFilter_cfg->activeport.mask, &portmask) != RT_ERR_OK)
+                return RT_ERR_PORT_MASK;
+
+            aclRule[i].care_bits.active_portmsk = portmask;
+        }
+    }
+
+    if(pFilter_cfg->invert >= FILTER_INVERT_END )
+        return RT_ERR_INPUT;
+
+
+    /*Last action gets high priority if actions are the same*/
+    memset(&aclAct, 0, sizeof(rtl8367c_acl_act_t));
+    aclActCtrl = 0;
+    for(actType = 0; actType < FILTER_ENACT_END; actType ++)
+    {
+        if(pFilter_action->actEnable[actType])
+        {
+            switch (actType)
+            {
+            case FILTER_ENACT_CVLAN_INGRESS:
+                if(pFilter_action->filterCvlanVid > RTL8367C_EVIDMAX)
+                    return RT_ERR_INPUT;
+
+                if((retVal = rtk_vlan_checkAndCreateMbr(pFilter_action->filterCvlanVid, &vidx)) != RT_ERR_OK)
+                {
+                    return retVal;
+                }
+                aclAct.cact = FILTER_ENACT_CVLAN_TYPE(actType);
+                aclAct.cvidx_cact = vidx;
+
+                if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK))
+                {
+                    if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_TAGONLY)
+                        aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG;
+                }
+                else
+                {
+                    aclAct.cact_ext = FILTER_ENACT_CACTEXT_VLANONLY;
+                }
+
+                aclActCtrl |= FILTER_ENACT_CVLAN_MASK;
+                break;
+            case FILTER_ENACT_CVLAN_EGRESS:
+                if(pFilter_action->filterCvlanVid > RTL8367C_EVIDMAX)
+                    return RT_ERR_INPUT;
+
+                if((retVal = rtk_vlan_checkAndCreateMbr(pFilter_action->filterCvlanVid, &vidx)) != RT_ERR_OK)
+                    return retVal;
+
+                aclAct.cact = FILTER_ENACT_CVLAN_TYPE(actType);
+                aclAct.cvidx_cact = vidx;
+
+                if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK))
+                {
+                    if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_TAGONLY)
+                        aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG;
+                }
+                else
+                {
+                    aclAct.cact_ext = FILTER_ENACT_CACTEXT_VLANONLY;
+                }
+
+                aclActCtrl |= FILTER_ENACT_CVLAN_MASK;
+                break;
+             case FILTER_ENACT_CVLAN_SVID:
+
+                aclAct.cact = FILTER_ENACT_CVLAN_TYPE(actType);
+
+                if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK))
+                {
+                    if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_TAGONLY)
+                        aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG;
+                }
+                else
+                {
+                    aclAct.cact_ext = FILTER_ENACT_CACTEXT_VLANONLY;
+                }
+
+                aclActCtrl |= FILTER_ENACT_CVLAN_MASK;
+                break;
+             case FILTER_ENACT_POLICING_1:
+                if(pFilter_action->filterPolicingIdx[1] >= (RTK_METER_NUM + RTL8367C_MAX_LOG_CNT_NUM))
+                    return RT_ERR_INPUT;
+
+                aclAct.cact = FILTER_ENACT_CVLAN_TYPE(actType);
+                aclAct.cvidx_cact = pFilter_action->filterPolicingIdx[1];
+
+                if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK))
+                {
+                    if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_TAGONLY)
+                        aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG;
+                }
+                else
+                {
+                    aclAct.cact_ext = FILTER_ENACT_CACTEXT_VLANONLY;
+                }
+
+                aclActCtrl |= FILTER_ENACT_CVLAN_MASK;
+                break;
+
+            case FILTER_ENACT_SVLAN_INGRESS:
+            case FILTER_ENACT_SVLAN_EGRESS:
+
+                if((retVal = rtk_svlan_checkAndCreateMbr(pFilter_action->filterSvlanVid, &svidx)) != RT_ERR_OK)
+                    return retVal;
+
+                aclAct.sact = FILTER_ENACT_SVLAN_TYPE(actType);
+                aclAct.svidx_sact = svidx;
+                aclActCtrl |= FILTER_ENACT_SVLAN_MASK;
+                break;
+            case FILTER_ENACT_SVLAN_CVID:
+
+                aclAct.sact = FILTER_ENACT_SVLAN_TYPE(actType);
+                aclActCtrl |= FILTER_ENACT_SVLAN_MASK;
+                break;
+            case FILTER_ENACT_POLICING_2:
+                if(pFilter_action->filterPolicingIdx[2] >= (RTK_METER_NUM + RTL8367C_MAX_LOG_CNT_NUM))
+                    return RT_ERR_INPUT;
+
+                aclAct.sact = FILTER_ENACT_SVLAN_TYPE(actType);
+                aclAct.svidx_sact = pFilter_action->filterPolicingIdx[2];
+                aclActCtrl |= FILTER_ENACT_SVLAN_MASK;
+                break;
+            case FILTER_ENACT_POLICING_0:
+                if(pFilter_action->filterPolicingIdx[0] >= (RTK_METER_NUM + RTL8367C_MAX_LOG_CNT_NUM))
+                    return RT_ERR_INPUT;
+
+                aclAct.aclmeteridx = pFilter_action->filterPolicingIdx[0];
+                aclActCtrl |= FILTER_ENACT_POLICING_MASK;
+                break;
+            case FILTER_ENACT_PRIORITY:
+            case FILTER_ENACT_1P_REMARK:
+                if(pFilter_action->filterPriority > RTL8367C_PRIMAX)
+                    return RT_ERR_INPUT;
+
+                aclAct.priact = FILTER_ENACT_PRI_TYPE(actType);
+                aclAct.pridx = pFilter_action->filterPriority;
+                aclActCtrl |= FILTER_ENACT_PRIORITY_MASK;
+                break;
+            case FILTER_ENACT_DSCP_REMARK:
+                if(pFilter_action->filterPriority > RTL8367C_DSCPMAX)
+                    return RT_ERR_INPUT;
+
+                aclAct.priact = FILTER_ENACT_PRI_TYPE(actType);
+                aclAct.pridx = pFilter_action->filterPriority;
+                aclActCtrl |= FILTER_ENACT_PRIORITY_MASK;
+                break;
+            case FILTER_ENACT_POLICING_3:
+                if(pFilter_action->filterPriority >= (RTK_METER_NUM + RTL8367C_MAX_LOG_CNT_NUM))
+                    return RT_ERR_INPUT;
+
+                aclAct.priact = FILTER_ENACT_PRI_TYPE(actType);
+                aclAct.pridx = pFilter_action->filterPolicingIdx[3];
+                aclActCtrl |= FILTER_ENACT_PRIORITY_MASK;
+                break;
+            case FILTER_ENACT_DROP:
+
+                aclAct.fwdact = FILTER_ENACT_FWD_TYPE(FILTER_ENACT_REDIRECT);
+                aclAct.fwdact_ext = FALSE;
+
+                aclAct.fwdpmask = 0;
+                aclActCtrl |= FILTER_ENACT_FWD_MASK;
+                break;
+            case FILTER_ENACT_REDIRECT:
+                RTK_CHK_PORTMASK_VALID(&pFilter_action->filterPortmask);
+
+                aclAct.fwdact = FILTER_ENACT_FWD_TYPE(actType);
+                aclAct.fwdact_ext = FALSE;
+
+                if(rtk_switch_portmask_L2P_get(&pFilter_action->filterPortmask, &portmask) != RT_ERR_OK)
+                    return RT_ERR_PORT_MASK;
+                aclAct.fwdpmask = portmask;
+
+                aclActCtrl |= FILTER_ENACT_FWD_MASK;
+                break;
+
+            case FILTER_ENACT_ADD_DSTPORT:
+                RTK_CHK_PORTMASK_VALID(&pFilter_action->filterPortmask);
+
+                aclAct.fwdact = FILTER_ENACT_FWD_TYPE(actType);
+                aclAct.fwdact_ext = FALSE;
+
+                if(rtk_switch_portmask_L2P_get(&pFilter_action->filterPortmask, &portmask) != RT_ERR_OK)
+                    return RT_ERR_PORT_MASK;
+                aclAct.fwdpmask = portmask;
+
+                aclActCtrl |= FILTER_ENACT_FWD_MASK;
+                break;
+            case FILTER_ENACT_MIRROR:
+                RTK_CHK_PORTMASK_VALID(&pFilter_action->filterPortmask);
+
+                aclAct.fwdact = FILTER_ENACT_FWD_TYPE(actType);
+                aclAct.cact_ext = FALSE;
+
+                if(rtk_switch_portmask_L2P_get(&pFilter_action->filterPortmask, &portmask) != RT_ERR_OK)
+                    return RT_ERR_PORT_MASK;
+                aclAct.fwdpmask = portmask;
+
+                aclActCtrl |= FILTER_ENACT_FWD_MASK;
+                break;
+            case FILTER_ENACT_TRAP_CPU:
+
+                aclAct.fwdact = FILTER_ENACT_FWD_TYPE(actType);
+                aclAct.fwdact_ext = FALSE;
+
+                aclActCtrl |= FILTER_ENACT_FWD_MASK;
+                break;
+            case FILTER_ENACT_COPY_CPU:
+                if((retVal = rtl8367c_getAsicCputagTrapPort(&cpuPort)) != RT_ERR_OK)
+                    return retVal;
+
+                aclAct.fwdact = FILTER_ENACT_FWD_TYPE(FILTER_ENACT_MIRROR);
+                aclAct.fwdact_ext = FALSE;
+
+                aclAct.fwdpmask = 1 << cpuPort;
+                aclActCtrl |= FILTER_ENACT_FWD_MASK;
+                break;
+            case FILTER_ENACT_ISOLATION:
+                RTK_CHK_PORTMASK_VALID(&pFilter_action->filterPortmask);
+
+                aclAct.fwdact_ext = TRUE;
+
+                if(rtk_switch_portmask_L2P_get(&pFilter_action->filterPortmask, &portmask) != RT_ERR_OK)
+                    return RT_ERR_PORT_MASK;
+                aclAct.fwdpmask = portmask;
+
+                aclActCtrl |= FILTER_ENACT_FWD_MASK;
+                break;
+
+            case FILTER_ENACT_INTERRUPT:
+
+                aclAct.aclint = TRUE;
+                aclActCtrl |= FILTER_ENACT_INTGPIO_MASK;
+                break;
+            case FILTER_ENACT_GPO:
+
+                aclAct.gpio_en = TRUE;
+                aclAct.gpio_pin = pFilter_action->filterPin;
+                aclActCtrl |= FILTER_ENACT_INTGPIO_MASK;
+                break;
+             case FILTER_ENACT_EGRESSCTAG_TAG:
+
+                if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK))
+                {
+                    if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_VLANONLY)
+                        aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG;
+                }
+                else
+                {
+                    aclAct.cact_ext = FILTER_ENACT_CACTEXT_TAGONLY;
+                }
+                aclAct.tag_fmt = FILTER_CTAGFMT_TAG;
+                aclActCtrl |= FILTER_ENACT_CVLAN_MASK;
+                break;
+             case FILTER_ENACT_EGRESSCTAG_UNTAG:
+
+                if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK))
+                {
+                    if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_VLANONLY)
+                        aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG;
+                }
+                else
+                {
+                    aclAct.cact_ext = FILTER_ENACT_CACTEXT_TAGONLY;
+                }
+                aclAct.tag_fmt = FILTER_CTAGFMT_UNTAG;
+                aclActCtrl |= FILTER_ENACT_CVLAN_MASK;
+                break;
+             case FILTER_ENACT_EGRESSCTAG_KEEP:
+
+                if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK))
+                {
+                    if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_VLANONLY)
+                        aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG;
+                }
+                else
+                {
+                    aclAct.cact_ext = FILTER_ENACT_CACTEXT_TAGONLY;
+                }
+                aclAct.tag_fmt = FILTER_CTAGFMT_KEEP;
+                aclActCtrl |= FILTER_ENACT_CVLAN_MASK;
+                break;
+             case FILTER_ENACT_EGRESSCTAG_KEEPAND1PRMK:
+
+                if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK))
+                {
+                    if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_VLANONLY)
+                        aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG;
+                }
+                else
+                {
+                    aclAct.cact_ext = FILTER_ENACT_CACTEXT_TAGONLY;
+                }
+                aclAct.tag_fmt = FILTER_CTAGFMT_KEEP1PRMK;
+                aclActCtrl |= FILTER_ENACT_CVLAN_MASK;
+                break;
+           default:
+                return RT_ERR_FILTER_INACL_ACT_NOT_SUPPORT;
+            }
+        }
+    }
+
+
+    /*check if free ACL rules are enough*/
+    for(i = filter_id; i < (filter_id + noRulesAdd); i++)
+    {
+        if((retVal = rtl8367c_getAsicAclRule(i, &tempRule)) != RT_ERR_OK )
+            return retVal;
+
+        if(tempRule.valid == TRUE)
+        {
+            return RT_ERR_TBL_FULL;
+        }
+    }
+
+    ruleId = 0;
+    for(i = 0; i < RTL8367C_ACLTEMPLATENO; i++)
+    {
+        if(aclRule[i].valid == TRUE)
+        {
+            /* write ACL action control */
+            if((retVal = rtl8367c_setAsicAclActCtrl(filter_id + ruleId, aclActCtrl)) != RT_ERR_OK )
+                return retVal;
+            /* write ACL action */
+            if((retVal = rtl8367c_setAsicAclAct(filter_id + ruleId, &aclAct)) != RT_ERR_OK )
+                return retVal;
+
+            /* write ACL not */
+            if((retVal = rtl8367c_setAsicAclNot(filter_id + ruleId, pFilter_cfg->invert)) != RT_ERR_OK )
+                return retVal;
+            /* write ACL rule */
+            if((retVal = rtl8367c_setAsicAclRule(filter_id + ruleId, &aclRule[i])) != RT_ERR_OK )
+                return retVal;
+
+            /* only the first rule will be written with input action control, aclActCtrl of other rules will be zero */
+            aclActCtrl = 0;
+            memset(&aclAct, 0, sizeof(rtl8367c_acl_act_t));
+
+            ruleId ++;
+        }
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_filter_igrAcl_cfg_del
+ * Description:
+ *      Delete an ACL configuration from ASIC
+ * Input:
+ *      filter_id   - Start index of ACL configuration.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_ENTRYIDX  - Invalid filter_id.
+ * Note:
+ *      This function delete a group of ACL rules starting from filter_id.
+ */
+rtk_api_ret_t rtk_filter_igrAcl_cfg_del(rtk_filter_id_t filter_id)
+{
+    rtl8367c_aclrule initRule;
+    rtl8367c_acl_act_t  initAct;
+    rtk_api_ret_t ret;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(filter_id > RTL8367C_ACLRULEMAX )
+        return RT_ERR_FILTER_ENTRYIDX;
+
+    memset(&initRule, 0, sizeof(rtl8367c_aclrule));
+    memset(&initAct, 0, sizeof(rtl8367c_acl_act_t));
+
+    if((ret = rtl8367c_setAsicAclRule(filter_id, &initRule)) != RT_ERR_OK)
+        return ret;
+    if((ret = rtl8367c_setAsicAclActCtrl(filter_id, FILTER_ENACT_INIT_MASK))!= RT_ERR_OK)
+        return ret;
+    if((ret = rtl8367c_setAsicAclAct(filter_id, &initAct)) != RT_ERR_OK)
+        return ret;
+    if((ret = rtl8367c_setAsicAclNot(filter_id, DISABLED)) != RT_ERR_OK )
+        return ret;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_filter_igrAcl_cfg_delAll
+ * Description:
+ *      Delete all ACL entries from ASIC
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      This function delete all ACL configuration from ASIC.
+ */
+rtk_api_ret_t rtk_filter_igrAcl_cfg_delAll(void)
+{
+    rtk_uint32            i;
+    rtk_api_ret_t     ret;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    for(i = 0; i < RTL8367C_ACLRULENO; i++)
+    {
+        if((ret = rtl8367c_setAsicAclActCtrl(i, FILTER_ENACT_INIT_MASK))!= RT_ERR_OK)
+            return ret;
+        if((ret = rtl8367c_setAsicAclNot(i, DISABLED)) != RT_ERR_OK )
+            return ret;
+    }
+
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_ACL_RESET_CFG, RTL8367C_ACL_RESET_CFG_OFFSET, TRUE);;
+}
+
+/* Function Name:
+ *      rtk_filter_igrAcl_cfg_get
+ * Description:
+ *      Get one ingress acl configuration from ASIC.
+ * Input:
+ *      filter_id       - Start index of ACL configuration.
+ * Output:
+ *      pFilter_cfg     - buffer pointer of ingress acl data
+ *      pFilter_action  - buffer pointer of ingress acl action
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_NULL_POINTER     - Pointer pFilter_action or pFilter_cfg point to NULL.
+ *      RT_ERR_FILTER_ENTRYIDX  - Invalid entry index.
+ * Note:
+ *      This function get configuration from ASIC.
+ */
+rtk_api_ret_t rtk_filter_igrAcl_cfg_get(rtk_filter_id_t filter_id, rtk_filter_cfg_raw_t *pFilter_cfg, rtk_filter_action_t *pAction)
+{
+    rtk_api_ret_t               retVal;
+    rtk_uint32                  i, tmp;
+    rtl8367c_aclrule            aclRule;
+    rtl8367c_acl_act_t          aclAct;
+    rtk_uint32                  cpuPort;
+    rtl8367c_acltemplate_t      type;
+    rtl8367c_svlan_memconf_t    svlan_cfg;
+    rtl8367c_vlanconfiguser     vlanMC;
+    rtk_uint32                  phyPmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pFilter_cfg || NULL == pAction)
+        return RT_ERR_NULL_POINTER;
+
+    if(filter_id > RTL8367C_ACLRULEMAX)
+        return RT_ERR_ENTRY_INDEX;
+
+    if ((retVal = rtl8367c_getAsicAclRule(filter_id, &aclRule)) != RT_ERR_OK)
+        return retVal;
+
+    /* Check valid */
+    if(aclRule.valid == 0)
+    {
+        pFilter_cfg->valid = DISABLED;
+        return RT_ERR_OK;
+    }
+
+    phyPmask = aclRule.data_bits.active_portmsk;
+    if(rtk_switch_portmask_P2L_get(phyPmask,&(pFilter_cfg->activeport.value)) != RT_ERR_OK)
+        return RT_ERR_FAILED;
+
+    phyPmask = aclRule.care_bits.active_portmsk;
+    if(rtk_switch_portmask_P2L_get(phyPmask,&(pFilter_cfg->activeport.mask)) != RT_ERR_OK)
+        return RT_ERR_FAILED;
+
+    for(i = 0; i <= CARE_TAG_IPV6; i++)
+    {
+        if(aclRule.data_bits.tag_exist & (1 << i))
+            pFilter_cfg->careTag.tagType[i].value = 1;
+        else
+            pFilter_cfg->careTag.tagType[i].value = 0;
+
+        if (aclRule.care_bits.tag_exist & (1 << i))
+            pFilter_cfg->careTag.tagType[i].mask = 1;
+        else
+            pFilter_cfg->careTag.tagType[i].mask = 0;
+    }
+
+    if(filter_advanceCaretagField[aclRule.data_bits.type][0] == TRUE)
+    {
+        /* Advanced Care tag setting */
+        for(i = CARE_TAG_TCP; i < CARE_TAG_END; i++)
+        {
+            if(aclRule.data_bits.field[filter_advanceCaretagField[aclRule.data_bits.type][1]] & (0x0001 << (i-CARE_TAG_TCP)) )
+                pFilter_cfg->careTag.tagType[i].value = 1;
+            else
+                pFilter_cfg->careTag.tagType[i].value = 0;
+
+            if(aclRule.care_bits.field[filter_advanceCaretagField[aclRule.care_bits.type][1]] & (0x0001 << (i-CARE_TAG_TCP)) )
+                pFilter_cfg->careTag.tagType[i].mask = 1;
+            else
+                pFilter_cfg->careTag.tagType[i].mask = 0;
+        }
+    }
+
+    for(i = 0; i < RTL8367C_ACLRULEFIELDNO; i++)
+    {
+        pFilter_cfg->careFieldRaw[i] = aclRule.care_bits.field[i];
+        pFilter_cfg->dataFieldRaw[i] = aclRule.data_bits.field[i];
+    }
+
+    if ((retVal = rtl8367c_getAsicAclNot(filter_id, &tmp))!= RT_ERR_OK)
+        return retVal;
+
+    pFilter_cfg->invert = tmp;
+
+    pFilter_cfg->valid = aclRule.valid;
+
+    memset(pAction, 0, sizeof(rtk_filter_action_t));
+
+    if ((retVal = rtl8367c_getAsicAclActCtrl(filter_id, &tmp))!= RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicAclAct(filter_id, &aclAct)) != RT_ERR_OK)
+        return retVal;
+
+    if(tmp & FILTER_ENACT_FWD_MASK)
+    {
+        if(TRUE == aclAct.fwdact_ext)
+        {
+            pAction->actEnable[FILTER_ENACT_ISOLATION] = TRUE;
+
+            phyPmask = aclAct.fwdpmask;
+            if(rtk_switch_portmask_P2L_get(phyPmask,&(pAction->filterPortmask)) != RT_ERR_OK)
+                return RT_ERR_FAILED;
+        }
+        else if(aclAct.fwdact == RTL8367C_ACL_FWD_TRAP)
+        {
+            pAction->actEnable[FILTER_ENACT_TRAP_CPU] = TRUE;
+        }
+        else if (aclAct.fwdact == RTL8367C_ACL_FWD_MIRRORFUNTION )
+        {
+            pAction->actEnable[FILTER_ENACT_MIRROR] = TRUE;
+
+            phyPmask = aclAct.fwdpmask;
+            if(rtk_switch_portmask_P2L_get(phyPmask,&(pAction->filterPortmask)) != RT_ERR_OK)
+                return RT_ERR_FAILED;
+        }
+        else if (aclAct.fwdact == RTL8367C_ACL_FWD_REDIRECT)
+        {
+            if(aclAct.fwdpmask == 0 )
+                pAction->actEnable[FILTER_ENACT_DROP] = TRUE;
+            else
+            {
+                pAction->actEnable[FILTER_ENACT_REDIRECT] = TRUE;
+
+                phyPmask = aclAct.fwdpmask;
+                if(rtk_switch_portmask_P2L_get(phyPmask,&(pAction->filterPortmask)) != RT_ERR_OK)
+                    return RT_ERR_FAILED;
+            }
+        }
+        else if (aclAct.fwdact == RTL8367C_ACL_FWD_MIRROR)
+        {
+            if((retVal = rtl8367c_getAsicCputagTrapPort(&cpuPort)) != RT_ERR_OK)
+                return retVal;
+            if (aclAct.fwdpmask == (1 << cpuPort))
+            {
+                pAction->actEnable[FILTER_ENACT_COPY_CPU] = TRUE;
+            }
+            else
+            {
+                pAction->actEnable[FILTER_ENACT_ADD_DSTPORT] = TRUE;
+
+                phyPmask = aclAct.fwdpmask;
+                if(rtk_switch_portmask_P2L_get(phyPmask,&(pAction->filterPortmask)) != RT_ERR_OK)
+                    return RT_ERR_FAILED;
+            }
+        }
+        else
+        {
+            return RT_ERR_FAILED;
+        }
+    }
+
+    if(tmp & FILTER_ENACT_POLICING_MASK)
+    {
+        pAction->actEnable[FILTER_ENACT_POLICING_0] = TRUE;
+        pAction->filterPolicingIdx[0] = aclAct.aclmeteridx;
+    }
+
+    if(tmp & FILTER_ENACT_PRIORITY_MASK)
+    {
+        if(aclAct.priact == FILTER_ENACT_PRI_TYPE(FILTER_ENACT_PRIORITY))
+        {
+            pAction->actEnable[FILTER_ENACT_PRIORITY] = TRUE;
+            pAction->filterPriority = aclAct.pridx;
+        }
+        else if(aclAct.priact == FILTER_ENACT_PRI_TYPE(FILTER_ENACT_1P_REMARK))
+        {
+            pAction->actEnable[FILTER_ENACT_1P_REMARK] = TRUE;
+            pAction->filterPriority = aclAct.pridx;
+        }
+        else if(aclAct.priact == FILTER_ENACT_PRI_TYPE(FILTER_ENACT_DSCP_REMARK))
+        {
+            pAction->actEnable[FILTER_ENACT_DSCP_REMARK] = TRUE;
+            pAction->filterPriority = aclAct.pridx;
+        }
+        else if(aclAct.priact == FILTER_ENACT_PRI_TYPE(FILTER_ENACT_POLICING_3))
+        {
+            pAction->actEnable[FILTER_ENACT_POLICING_3] = TRUE;
+            pAction->filterPolicingIdx[3]  = aclAct.pridx;
+        }
+    }
+
+    if(tmp & FILTER_ENACT_SVLAN_MASK)
+    {
+        if(aclAct.sact == FILTER_ENACT_SVLAN_TYPE(FILTER_ENACT_SVLAN_INGRESS))
+        {
+            if((retVal = rtl8367c_getAsicSvlanMemberConfiguration(aclAct.svidx_sact, &svlan_cfg)) != RT_ERR_OK)
+                return retVal;
+
+            pAction->actEnable[FILTER_ENACT_SVLAN_INGRESS] = TRUE;
+            pAction->filterSvlanIdx = aclAct.svidx_sact;
+            pAction->filterSvlanVid = svlan_cfg.vs_svid;
+        }
+        else if(aclAct.sact == FILTER_ENACT_SVLAN_TYPE(FILTER_ENACT_SVLAN_EGRESS))
+        {
+            if((retVal = rtl8367c_getAsicSvlanMemberConfiguration(aclAct.svidx_sact, &svlan_cfg)) != RT_ERR_OK)
+                return retVal;
+
+            pAction->actEnable[FILTER_ENACT_SVLAN_EGRESS] = TRUE;
+            pAction->filterSvlanIdx = aclAct.svidx_sact;
+            pAction->filterSvlanVid = svlan_cfg.vs_svid;
+        }
+        else if(aclAct.sact == FILTER_ENACT_SVLAN_TYPE(FILTER_ENACT_SVLAN_CVID))
+            pAction->actEnable[FILTER_ENACT_SVLAN_CVID] = TRUE;
+        else if(aclAct.sact == FILTER_ENACT_SVLAN_TYPE(FILTER_ENACT_POLICING_2))
+        {
+            pAction->actEnable[FILTER_ENACT_POLICING_2] = TRUE;
+            pAction->filterPolicingIdx[2]  = aclAct.svidx_sact;
+        }
+    }
+
+
+    if(tmp & FILTER_ENACT_CVLAN_MASK)
+    {
+        if(FILTER_ENACT_CACTEXT_TAGONLY == aclAct.cact_ext ||
+            FILTER_ENACT_CACTEXT_BOTHVLANTAG == aclAct.cact_ext )
+        {
+            if(FILTER_CTAGFMT_UNTAG == aclAct.tag_fmt)
+            {
+                pAction->actEnable[FILTER_ENACT_EGRESSCTAG_UNTAG] = TRUE;
+            }
+            else if(FILTER_CTAGFMT_TAG == aclAct.tag_fmt)
+            {
+                pAction->actEnable[FILTER_ENACT_EGRESSCTAG_TAG] = TRUE;
+            }
+            else if(FILTER_CTAGFMT_KEEP == aclAct.tag_fmt)
+            {
+                pAction->actEnable[FILTER_ENACT_EGRESSCTAG_KEEP] = TRUE;
+            }
+             else if(FILTER_CTAGFMT_KEEP1PRMK== aclAct.tag_fmt)
+            {
+                pAction->actEnable[FILTER_ENACT_EGRESSCTAG_KEEPAND1PRMK] = TRUE;
+            }
+
+        }
+
+        if(FILTER_ENACT_CACTEXT_VLANONLY == aclAct.cact_ext ||
+            FILTER_ENACT_CACTEXT_BOTHVLANTAG == aclAct.cact_ext )
+        {
+            if(aclAct.cact == FILTER_ENACT_CVLAN_TYPE(FILTER_ENACT_CVLAN_INGRESS))
+            {
+                if((retVal = rtl8367c_getAsicVlanMemberConfig(aclAct.cvidx_cact, &vlanMC)) != RT_ERR_OK)
+                    return retVal;
+
+                pAction->actEnable[FILTER_ENACT_CVLAN_INGRESS] = TRUE;
+                pAction->filterCvlanIdx  = aclAct.cvidx_cact;
+                pAction->filterCvlanVid  = vlanMC.evid;
+            }
+            else if(aclAct.cact == FILTER_ENACT_CVLAN_TYPE(FILTER_ENACT_CVLAN_EGRESS))
+            {
+                if((retVal = rtl8367c_getAsicVlanMemberConfig(aclAct.cvidx_cact, &vlanMC)) != RT_ERR_OK)
+                    return retVal;
+
+                pAction->actEnable[FILTER_ENACT_CVLAN_EGRESS] = TRUE;
+                pAction->filterCvlanIdx  = aclAct.cvidx_cact;
+                pAction->filterCvlanVid  = vlanMC.evid;
+            }
+            else if(aclAct.cact == FILTER_ENACT_CVLAN_TYPE(FILTER_ENACT_CVLAN_SVID))
+            {
+                pAction->actEnable[FILTER_ENACT_CVLAN_SVID] = TRUE;
+            }
+            else if(aclAct.cact == FILTER_ENACT_CVLAN_TYPE(FILTER_ENACT_POLICING_1))
+            {
+                pAction->actEnable[FILTER_ENACT_POLICING_1] = TRUE;
+                pAction->filterPolicingIdx[1]  = aclAct.cvidx_cact;
+            }
+        }
+    }
+
+    if(tmp & FILTER_ENACT_INTGPIO_MASK)
+    {
+        if(TRUE == aclAct.aclint)
+        {
+            pAction->actEnable[FILTER_ENACT_INTERRUPT] = TRUE;
+        }
+
+        if(TRUE == aclAct.gpio_en)
+        {
+            pAction->actEnable[FILTER_ENACT_GPO] = TRUE;
+            pAction->filterPin = aclAct.gpio_pin;
+        }
+    }
+
+    /* Get field type of RAW data */
+    if ((retVal = rtl8367c_getAsicAclTemplate(aclRule.data_bits.type, &type))!= RT_ERR_OK)
+        return retVal;
+
+    for(i = 0; i < RTL8367C_ACLRULEFIELDNO; i++)
+    {
+        pFilter_cfg->fieldRawType[i] = type.field[i];
+    }/* end of for(i...) */
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_filter_igrAcl_unmatchAction_set
+ * Description:
+ *      Set action to packets when no ACL configuration match
+ * Input:
+ *      port    - Port id.
+ *      action  - Action.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port id.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This function sets action of packets when no ACL configruation matches.
+ */
+rtk_api_ret_t rtk_filter_igrAcl_unmatchAction_set(rtk_port_t port, rtk_filter_unmatch_action_t action)
+{
+    rtk_api_ret_t ret;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(action >= FILTER_UNMATCH_END)
+        return RT_ERR_INPUT;
+
+    if((ret = rtl8367c_setAsicAclUnmatchedPermit(rtk_switch_port_L2P_get(port), action)) != RT_ERR_OK)
+       return ret;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_filter_igrAcl_unmatchAction_get
+ * Description:
+ *      Get action to packets when no ACL configuration match
+ * Input:
+ *      port    - Port id.
+ * Output:
+ *      pAction - Action.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port id.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This function gets action of packets when no ACL configruation matches.
+ */
+rtk_api_ret_t rtk_filter_igrAcl_unmatchAction_get(rtk_port_t port, rtk_filter_unmatch_action_t* pAction)
+{
+    rtk_api_ret_t ret;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pAction)
+        return RT_ERR_NULL_POINTER;
+
+    /* Check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if((ret = rtl8367c_getAsicAclUnmatchedPermit(rtk_switch_port_L2P_get(port), pAction)) != RT_ERR_OK)
+       return ret;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_filter_igrAcl_state_set
+ * Description:
+ *      Set state of ingress ACL.
+ * Input:
+ *      port    - Port id.
+ *      state   - Ingress ACL state.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port id.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This function gets action of packets when no ACL configruation matches.
+ */
+rtk_api_ret_t rtk_filter_igrAcl_state_set(rtk_port_t port, rtk_filter_state_t state)
+{
+    rtk_api_ret_t ret;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(state >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if((ret = rtl8367c_setAsicAcl(rtk_switch_port_L2P_get(port), state)) != RT_ERR_OK)
+       return ret;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_filter_igrAcl_state_get
+ * Description:
+ *      Get state of ingress ACL.
+ * Input:
+ *      port    - Port id.
+ * Output:
+ *      pState  - Ingress ACL state.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port id.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This function gets action of packets when no ACL configruation matches.
+ */
+rtk_api_ret_t rtk_filter_igrAcl_state_get(rtk_port_t port, rtk_filter_state_t* pState)
+{
+    rtk_api_ret_t ret;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pState)
+        return RT_ERR_NULL_POINTER;
+
+    /* Check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if((ret = rtl8367c_getAsicAcl(rtk_switch_port_L2P_get(port), pState)) != RT_ERR_OK)
+       return ret;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtk_filter_igrAcl_template_set
+ * Description:
+ *      Set template of ingress ACL.
+ * Input:
+ *      template - Ingress ACL template
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Invalid input parameters.
+ * Note:
+ *      This function set ACL template.
+ */
+rtk_api_ret_t rtk_filter_igrAcl_template_set(rtk_filter_template_t *aclTemplate)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 idxField;
+    rtl8367c_acltemplate_t aclType;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(aclTemplate->index >= RTK_MAX_NUM_OF_FILTER_TYPE)
+        return RT_ERR_INPUT;
+
+    for(idxField = 0; idxField < RTK_MAX_NUM_OF_FILTER_FIELD; idxField++)
+    {
+        if(aclTemplate->fieldType[idxField] < FILTER_FIELD_RAW_DMAC_15_0 ||
+            (aclTemplate->fieldType[idxField] > FILTER_FIELD_RAW_CTAG && aclTemplate->fieldType[idxField] < FILTER_FIELD_RAW_IPV4_SIP_15_0 ) ||
+            (aclTemplate->fieldType[idxField] > FILTER_FIELD_RAW_IPV4_DIP_31_16 && aclTemplate->fieldType[idxField] < FILTER_FIELD_RAW_IPV6_SIP_15_0 ) ||
+            (aclTemplate->fieldType[idxField] > FILTER_FIELD_RAW_IPV6_DIP_31_16 && aclTemplate->fieldType[idxField] < FILTER_FIELD_RAW_VIDRANGE ) ||
+            (aclTemplate->fieldType[idxField] > FILTER_FIELD_RAW_FIELD_VALID && aclTemplate->fieldType[idxField] < FILTER_FIELD_RAW_FIELD_SELECT00 ) ||
+            aclTemplate->fieldType[idxField] >= FILTER_FIELD_RAW_END)
+        {
+            return RT_ERR_INPUT;
+        }
+    }
+
+    for(idxField = 0; idxField < RTK_MAX_NUM_OF_FILTER_FIELD; idxField++)
+    {
+        aclType.field[idxField] = aclTemplate->fieldType[idxField];
+    }
+
+    if((retVal = rtl8367c_setAsicAclTemplate(aclTemplate->index, &aclType)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_filter_igrAcl_template_get
+ * Description:
+ *      Get template of ingress ACL.
+ * Input:
+ *      template - Ingress ACL template
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      This function gets template of ACL.
+ */
+rtk_api_ret_t rtk_filter_igrAcl_template_get(rtk_filter_template_t *aclTemplate)
+{
+    rtk_api_ret_t ret;
+    rtk_uint32 idxField;
+    rtl8367c_acltemplate_t aclType;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == aclTemplate)
+        return RT_ERR_NULL_POINTER;
+
+    if(aclTemplate->index >= RTK_MAX_NUM_OF_FILTER_TYPE)
+        return RT_ERR_INPUT;
+
+   if((ret = rtl8367c_getAsicAclTemplate(aclTemplate->index, &aclType)) != RT_ERR_OK)
+       return ret;
+
+    for(idxField = 0; idxField < RTK_MAX_NUM_OF_FILTER_FIELD; idxField ++)
+    {
+        aclTemplate->fieldType[idxField] = aclType.field[idxField];
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_filter_igrAcl_field_sel_set
+ * Description:
+ *      Set user defined field selectors in HSB
+ * Input:
+ *      index       - index of field selector 0-15
+ *      format      - Format of field selector
+ *      offset      - Retrieving data offset
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      System support 16 user defined field selctors.
+ *      Each selector can be enabled or disable.
+ *      User can defined retrieving 16-bits in many predefiend
+ *      standard l2/l3/l4 payload.
+ */
+rtk_api_ret_t rtk_filter_igrAcl_field_sel_set(rtk_uint32 index, rtk_field_sel_t format, rtk_uint32 offset)
+{
+    rtk_api_ret_t ret;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(index >= RTL8367C_FIELDSEL_FORMAT_NUMBER)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(format >= FORMAT_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(offset > RTL8367C_FIELDSEL_MAX_OFFSET)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if((ret = rtl8367c_setAsicFieldSelector(index, (rtk_uint32)format, offset)) != RT_ERR_OK)
+       return ret;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_filter_igrAcl_field_sel_get
+ * Description:
+ *      Get user defined field selectors in HSB
+ * Input:
+ *      index       - index of field selector 0-15
+ * Output:
+ *      pFormat     - Format of field selector
+ *      pOffset     - Retrieving data offset
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      None.
+ */
+rtk_api_ret_t rtk_filter_igrAcl_field_sel_get(rtk_uint32 index, rtk_field_sel_t *pFormat, rtk_uint32 *pOffset)
+{
+    rtk_api_ret_t ret;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pFormat || NULL == pOffset)
+        return RT_ERR_NULL_POINTER;
+
+    if(index >= RTL8367C_FIELDSEL_FORMAT_NUMBER)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if((ret = rtl8367c_getAsicFieldSelector(index, pFormat, pOffset)) != RT_ERR_OK)
+       return ret;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_filter_iprange_set
+ * Description:
+ *      Set IP Range check
+ * Input:
+ *      index       - index of IP Range 0-15
+ *      type        - IP Range check type, 0:Delete a entry, 1: IPv4_SIP, 2: IPv4_DIP, 3:IPv6_SIP, 4:IPv6_DIP
+ *      upperIp     - The upper bound of IP range
+ *      lowerIp     - The lower Bound of IP range
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_OUT_OF_RANGE    - The parameter is out of range
+ *      RT_ERR_INPUT           - Input error
+ * Note:
+ *      upperIp must be larger or equal than lowerIp.
+ */
+rtk_api_ret_t rtk_filter_iprange_set(rtk_uint32 index, rtk_filter_iprange_t type, ipaddr_t upperIp, ipaddr_t lowerIp)
+{
+    rtk_api_ret_t ret;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(index > RTL8367C_ACLRANGEMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(type >= IPRANGE_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(lowerIp > upperIp)
+        return RT_ERR_INPUT;
+
+    if((ret = rtl8367c_setAsicAclIpRange(index, type, upperIp, lowerIp)) != RT_ERR_OK)
+       return ret;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_filter_iprange_get
+ * Description:
+ *      Set IP Range check
+ * Input:
+ *      index       - index of IP Range 0-15
+ * Output:
+ *      pType        - IP Range check type, 0:Delete a entry, 1: IPv4_SIP, 2: IPv4_DIP, 3:IPv6_SIP, 4:IPv6_DIP
+ *      pUpperIp     - The upper bound of IP range
+ *      pLowerIp     - The lower Bound of IP range
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_OUT_OF_RANGE    - The parameter is out of range
+ * Note:
+ *      None.
+ */
+rtk_api_ret_t rtk_filter_iprange_get(rtk_uint32 index, rtk_filter_iprange_t *pType, ipaddr_t *pUpperIp, ipaddr_t *pLowerIp)
+{
+    rtk_api_ret_t ret;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if((NULL == pType) || (NULL == pUpperIp) || (NULL == pLowerIp))
+        return RT_ERR_NULL_POINTER;
+
+    if(index > RTL8367C_ACLRANGEMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if((ret = rtl8367c_getAsicAclIpRange(index, pType, pUpperIp, pLowerIp)) != RT_ERR_OK)
+       return ret;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_filter_vidrange_set
+ * Description:
+ *      Set VID Range check
+ * Input:
+ *      index       - index of VID Range 0-15
+ *      type        - IP Range check type, 0:Delete a entry, 1: CVID, 2: SVID
+ *      upperVid    - The upper bound of VID range
+ *      lowerVid    - The lower Bound of VID range
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_OUT_OF_RANGE    - The parameter is out of range
+ *      RT_ERR_INPUT           - Input error
+ * Note:
+ *      upperVid must be larger or equal than lowerVid.
+ */
+rtk_api_ret_t rtk_filter_vidrange_set(rtk_uint32 index, rtk_filter_vidrange_t type, rtk_uint32 upperVid, rtk_uint32 lowerVid)
+{
+    rtk_api_ret_t ret;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(index > RTL8367C_ACLRANGEMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(type >= VIDRANGE_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(lowerVid > upperVid)
+        return RT_ERR_INPUT;
+
+    if( (upperVid > RTL8367C_VIDMAX) || (lowerVid > RTL8367C_VIDMAX))
+        return RT_ERR_OUT_OF_RANGE;
+
+    if((ret = rtl8367c_setAsicAclVidRange(index, type, upperVid, lowerVid)) != RT_ERR_OK)
+       return ret;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_filter_vidrange_get
+ * Description:
+ *      Get VID Range check
+ * Input:
+ *      index       - index of VID Range 0-15
+ * Output:
+ *      pType        - IP Range check type, 0:Unused, 1: CVID, 2: SVID
+ *      pUpperVid    - The upper bound of VID range
+ *      pLowerVid    - The lower Bound of VID range
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_OUT_OF_RANGE    - The parameter is out of range
+ * Note:
+ *      None.
+ */
+rtk_api_ret_t rtk_filter_vidrange_get(rtk_uint32 index, rtk_filter_vidrange_t *pType, rtk_uint32 *pUpperVid, rtk_uint32 *pLowerVid)
+{
+    rtk_api_ret_t ret;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if((NULL == pType) || (NULL == pUpperVid) || (NULL == pLowerVid))
+        return RT_ERR_NULL_POINTER;
+
+    if(index > RTL8367C_ACLRANGEMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if((ret = rtl8367c_getAsicAclVidRange(index, pType, pUpperVid, pLowerVid)) != RT_ERR_OK)
+       return ret;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_filter_portrange_set
+ * Description:
+ *      Set Port Range check
+ * Input:
+ *      index       - index of Port Range 0-15
+ *      type        - IP Range check type, 0:Delete a entry, 1: Source Port, 2: Destnation Port
+ *      upperPort   - The upper bound of Port range
+ *      lowerPort   - The lower Bound of Port range
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_OUT_OF_RANGE    - The parameter is out of range
+ *      RT_ERR_INPUT           - Input error
+ * Note:
+ *      upperPort must be larger or equal than lowerPort.
+ */
+rtk_api_ret_t rtk_filter_portrange_set(rtk_uint32 index, rtk_filter_portrange_t type, rtk_uint32 upperPort, rtk_uint32 lowerPort)
+{
+    rtk_api_ret_t ret;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(index > RTL8367C_ACLRANGEMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(type >= PORTRANGE_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(lowerPort > upperPort)
+        return RT_ERR_INPUT;
+
+    if(upperPort > RTL8367C_ACL_PORTRANGEMAX)
+        return RT_ERR_INPUT;
+
+    if(lowerPort > RTL8367C_ACL_PORTRANGEMAX)
+        return RT_ERR_INPUT;
+
+    if((ret = rtl8367c_setAsicAclPortRange(index, type, upperPort, lowerPort)) != RT_ERR_OK)
+       return ret;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_filter_portrange_get
+ * Description:
+ *      Set Port Range check
+ * Input:
+ *      index       - index of Port Range 0-15
+ * Output:
+ *      pType       - IP Range check type, 0:Delete a entry, 1: Source Port, 2: Destnation Port
+ *      pUpperPort  - The upper bound of Port range
+ *      pLowerPort  - The lower Bound of Port range
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_OUT_OF_RANGE    - The parameter is out of range
+ *      RT_ERR_INPUT           - Input error
+ * Note:
+ *      None.
+ */
+rtk_api_ret_t rtk_filter_portrange_get(rtk_uint32 index, rtk_filter_portrange_t *pType, rtk_uint32 *pUpperPort, rtk_uint32 *pLowerPort)
+{
+    rtk_api_ret_t ret;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if((NULL == pType) || (NULL == pUpperPort) || (NULL == pLowerPort))
+        return RT_ERR_NULL_POINTER;
+
+    if(index > RTL8367C_ACLRANGEMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if((ret = rtl8367c_getAsicAclPortRange(index, pType, pUpperPort, pLowerPort)) != RT_ERR_OK)
+       return ret;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_filter_igrAclPolarity_set
+ * Description:
+ *      Set ACL Goip control palarity
+ * Input:
+ *      polarity - 1: High, 0: Low
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      none
+ */
+rtk_api_ret_t rtk_filter_igrAclPolarity_set(rtk_uint32 polarity)
+{
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(polarity > 1)
+        return RT_ERR_OUT_OF_RANGE;
+    return rtl8367c_setAsicAclGpioPolarity(polarity);
+}
+/* Function Name:
+ *      rtk_filter_igrAclPolarity_get
+ * Description:
+ *      Get ACL Goip control palarity
+ * Input:
+ *      pPolarity - 1: High, 0: Low
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      none
+ */
+rtk_api_ret_t rtk_filter_igrAclPolarity_get(rtk_uint32* pPolarity)
+{
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pPolarity)
+        return RT_ERR_NULL_POINTER;
+
+    return rtl8367c_getAsicAclGpioPolarity(pPolarity);
+}
+
+
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/cpu.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/cpu.c
new file mode 100644
index 0000000..d1cd95b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/cpu.c
@@ -0,0 +1,537 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in CPU module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <cpu.h>
+#include <string.h>
+
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_cputag.h>
+
+/* Function Name:
+ *      rtk_cpu_enable_set
+ * Description:
+ *      Set CPU port function enable/disable.
+ * Input:
+ *      enable - CPU port function enable
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can set CPU port function enable/disable.
+ */
+rtk_api_ret_t rtk_cpu_enable_set(rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (enable >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if ((retVal = rtl8367c_setAsicCputagEnable(enable)) != RT_ERR_OK)
+        return retVal;
+
+    if (DISABLED == enable)
+    {
+        if ((retVal = rtl8367c_setAsicCputagPortmask(0)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_cpu_enable_get
+ * Description:
+ *      Get CPU port and its setting.
+ * Input:
+ *      None
+ * Output:
+ *      pEnable - CPU port function enable
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_L2_NO_CPU_PORT   - CPU port is not exist
+ * Note:
+ *      The API can get CPU port function enable/disable.
+ */
+rtk_api_ret_t rtk_cpu_enable_get(rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicCputagEnable(pEnable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_cpu_tagPort_set
+ * Description:
+ *      Set CPU port and CPU tag insert mode.
+ * Input:
+ *      port - Port id.
+ *      mode - CPU tag insert for packets egress from CPU port.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can set CPU port and inserting proprietary CPU tag mode (Length/Type 0x8899)
+ *      to the frame that transmitting to CPU port.
+ *      The inset cpu tag mode is as following:
+ *      - CPU_INSERT_TO_ALL
+ *      - CPU_INSERT_TO_TRAPPING
+ *      - CPU_INSERT_TO_NONE
+ */
+rtk_api_ret_t rtk_cpu_tagPort_set(rtk_port_t port, rtk_cpu_insert_t mode)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (mode >= CPU_INSERT_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicCputagPortmask(1<<rtk_switch_port_L2P_get(port))) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicCputagTrapPort(rtk_switch_port_L2P_get(port))) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicCputagInsertMode(mode)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_cpu_tagPort_get
+ * Description:
+ *      Get CPU port and CPU tag insert mode.
+ * Input:
+ *      None
+ * Output:
+ *      pPort - Port id.
+ *      pMode - CPU tag insert for packets egress from CPU port, 0:all insert 1:Only for trapped packets 2:no insert.
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_L2_NO_CPU_PORT   - CPU port is not exist
+ * Note:
+ *      The API can get configured CPU port and its setting.
+ *      The inset cpu tag mode is as following:
+ *      - CPU_INSERT_TO_ALL
+ *      - CPU_INSERT_TO_TRAPPING
+ *      - CPU_INSERT_TO_NONE
+ */
+rtk_api_ret_t rtk_cpu_tagPort_get(rtk_port_t *pPort, rtk_cpu_insert_t *pMode)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmsk, port;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pPort)
+        return RT_ERR_NULL_POINTER;
+
+    if(NULL == pMode)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicCputagPortmask(&pmsk)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicCputagTrapPort(&port)) != RT_ERR_OK)
+        return retVal;
+
+    *pPort = rtk_switch_port_P2L_get(port);
+
+    if ((retVal = rtl8367c_getAsicCputagInsertMode(pMode)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_cpu_awarePort_set
+ * Description:
+ *      Set CPU aware port mask.
+ * Input:
+ *      portmask - Port mask.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK      - Invalid port mask.
+ * Note:
+ *      The API can set configured CPU aware port mask.
+ */
+rtk_api_ret_t rtk_cpu_awarePort_set(rtk_portmask_t *pPortmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 phyMbrPmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Valid port mask */
+    if(NULL == pPortmask)
+        return RT_ERR_NULL_POINTER;
+
+    /* Check port mask valid */
+    RTK_CHK_PORTMASK_VALID(pPortmask);
+
+    if(rtk_switch_portmask_L2P_get(pPortmask, &phyMbrPmask) != RT_ERR_OK)
+        return RT_ERR_FAILED;
+
+    if ((retVal = rtl8367c_setAsicCputagPortmask(phyMbrPmask)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_cpu_awarePort_get
+ * Description:
+ *      Get CPU aware port mask.
+ * Input:
+ *      None
+ * Output:
+ *      pPortmask - Port mask.
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ * Note:
+ *      The API can get configured CPU aware port mask.
+ */
+rtk_api_ret_t rtk_cpu_awarePort_get(rtk_portmask_t *pPortmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmsk;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pPortmask)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicCputagPortmask(&pmsk)) != RT_ERR_OK)
+        return retVal;
+
+    if(rtk_switch_portmask_P2L_get(pmsk, pPortmask) != RT_ERR_OK)
+        return RT_ERR_FAILED;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_cpu_tagPosition_set
+ * Description:
+ *      Set CPU tag position.
+ * Input:
+ *      position - CPU tag position.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT      - Invalid input.
+ * Note:
+ *      The API can set CPU tag position.
+ */
+rtk_api_ret_t rtk_cpu_tagPosition_set(rtk_cpu_position_t position)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (position >= CPU_POS_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicCputagPosition(position)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_cpu_tagPosition_get
+ * Description:
+ *      Get CPU tag position.
+ * Input:
+ *      None
+ * Output:
+ *      pPosition - CPU tag position.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT      - Invalid input.
+ * Note:
+ *      The API can get CPU tag position.
+ */
+rtk_api_ret_t rtk_cpu_tagPosition_get(rtk_cpu_position_t *pPosition)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pPosition)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicCputagPosition(pPosition)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_cpu_tagLength_set
+ * Description:
+ *      Set CPU tag length.
+ * Input:
+ *      length - CPU tag length.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT      - Invalid input.
+ * Note:
+ *      The API can set CPU tag length.
+ */
+rtk_api_ret_t rtk_cpu_tagLength_set(rtk_cpu_tag_length_t length)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (length >= CPU_LEN_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicCputagMode(length)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_cpu_tagLength_get
+ * Description:
+ *      Get CPU tag length.
+ * Input:
+ *      None
+ * Output:
+ *      pLength - CPU tag length.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT      - Invalid input.
+ * Note:
+ *      The API can get CPU tag length.
+ */
+rtk_api_ret_t rtk_cpu_tagLength_get(rtk_cpu_tag_length_t *pLength)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pLength)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicCputagMode(pLength)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_cpu_priRemap_set
+ * Description:
+ *      Configure CPU priorities mapping to internal absolute priority.
+ * Input:
+ *      int_pri     - internal priority value.
+ *      new_pri    - new internal priority value.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_VLAN_PRIORITY    - Invalid 1p priority.
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ * Note:
+ *      Priority of CPU tag assignment for internal asic priority, and it is used for queue usage and packet scheduling.
+ */
+rtk_api_ret_t rtk_cpu_priRemap_set(rtk_pri_t int_pri, rtk_pri_t new_pri)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (new_pri > RTL8367C_PRIMAX || int_pri > RTL8367C_PRIMAX)
+        return  RT_ERR_VLAN_PRIORITY;
+
+    if ((retVal = rtl8367c_setAsicCputagPriorityRemapping(int_pri, new_pri)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_cpu_priRemap_get
+ * Description:
+ *      Configure CPU priorities mapping to internal absolute priority.
+ * Input:
+ *      int_pri     - internal priority value.
+ * Output:
+ *      pNew_pri    - new internal priority value.
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_VLAN_PRIORITY    - Invalid 1p priority.
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ * Note:
+ *      Priority of CPU tag assignment for internal asic priority, and it is used for queue usage and packet scheduling.
+ */
+rtk_api_ret_t rtk_cpu_priRemap_get(rtk_pri_t int_pri, rtk_pri_t *pNew_pri)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pNew_pri)
+        return RT_ERR_NULL_POINTER;
+
+    if (int_pri > RTL8367C_PRIMAX)
+        return  RT_ERR_QOS_INT_PRIORITY;
+
+    if ((retVal = rtl8367c_getAsicCputagPriorityRemapping(int_pri, pNew_pri)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_cpu_acceptLength_set
+ * Description:
+ *      Set CPU accept  length.
+ * Input:
+ *      length - CPU tag length.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT      - Invalid input.
+ * Note:
+ *      The API can set CPU accept length.
+ */
+rtk_api_ret_t rtk_cpu_acceptLength_set(rtk_cpu_rx_length_t length)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (length >= CPU_RX_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicCputagRxMinLength(length)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_cpu_acceptLength_get
+ * Description:
+ *      Get CPU accept length.
+ * Input:
+ *      None
+ * Output:
+ *      pLength - CPU tag length.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT      - Invalid input.
+ * Note:
+ *      The API can get CPU accept length.
+ */
+rtk_api_ret_t rtk_cpu_acceptLength_get(rtk_cpu_rx_length_t *pLength)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pLength)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicCputagRxMinLength(pLength)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/dot1x.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/dot1x.c
new file mode 100644
index 0000000..c9b146a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/dot1x.c
@@ -0,0 +1,843 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 75783 $
+ * $Date: 2017-02-13 14:54:53 +0800 (週一, 13 二月 2017) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in 1X module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <dot1x.h>
+#include <string.h>
+#include <vlan.h>
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_dot1x.h>
+#include <rtl8367c_asicdrv_rma.h>
+#include <rtl8367c_asicdrv_lut.h>
+#include <rtl8367c_asicdrv_vlan.h>
+
+/* Function Name:
+ *      rtk_dot1x_unauthPacketOper_set
+ * Description:
+ *      Set 802.1x unauth action configuration.
+ * Input:
+ *      port            - Port id.
+ *      unauth_action   - 802.1X unauth action.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ * Note:
+ *      This API can set 802.1x unauth action configuration.
+ *      The unauth action is as following:
+ *      - DOT1X_ACTION_DROP
+ *      - DOT1X_ACTION_TRAP2CPU
+ *      - DOT1X_ACTION_GUESTVLAN
+ */
+rtk_api_ret_t rtk_dot1x_unauthPacketOper_set(rtk_port_t port, rtk_dot1x_unauth_action_t unauth_action)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (unauth_action >= DOT1X_ACTION_END)
+        return RT_ERR_DOT1X_PROC;
+
+    if ((retVal = rtl8367c_setAsic1xProcConfig(rtk_switch_port_L2P_get(port), unauth_action)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_unauthPacketOper_get
+ * Description:
+ *      Get 802.1x unauth action configuration.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pUnauth_action - 802.1X unauth action.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API can get 802.1x unauth action configuration.
+ *      The unauth action is as following:
+ *      - DOT1X_ACTION_DROP
+ *      - DOT1X_ACTION_TRAP2CPU
+ *      - DOT1X_ACTION_GUESTVLAN
+ */
+rtk_api_ret_t rtk_dot1x_unauthPacketOper_get(rtk_port_t port, rtk_dot1x_unauth_action_t *pUnauth_action)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pUnauth_action)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsic1xProcConfig(rtk_switch_port_L2P_get(port), pUnauth_action)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_eapolFrame2CpuEnable_set
+ * Description:
+ *      Set 802.1x EAPOL packet trap to CPU configuration
+ * Input:
+ *      enable - The status of 802.1x EAPOL packet.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_ENABLE       - Invalid enable input.
+ * Note:
+ *      To support 802.1x authentication functionality, EAPOL frame (ether type = 0x888E) has to
+ *      be trapped to CPU.
+ *      The status of EAPOL frame trap to CPU is as following:
+ *      - DISABLED
+ *      - ENABLED
+ */
+rtk_api_ret_t rtk_dot1x_eapolFrame2CpuEnable_set(rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_rma_t rmacfg;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (enable >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if ((retVal = rtl8367c_getAsicRma(3, &rmacfg)) != RT_ERR_OK)
+        return retVal;
+
+    if (ENABLED == enable)
+        rmacfg.operation = RMAOP_TRAP_TO_CPU;
+    else if (DISABLED == enable)
+        rmacfg.operation = RMAOP_FORWARD;
+
+    if ((retVal = rtl8367c_setAsicRma(3, &rmacfg)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_eapolFrame2CpuEnable_get
+ * Description:
+ *      Get 802.1x EAPOL packet trap to CPU configuration
+ * Input:
+ *      None
+ * Output:
+ *      pEnable - The status of 802.1x EAPOL packet.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      To support 802.1x authentication functionality, EAPOL frame (ether type = 0x888E) has to
+ *      be trapped to CPU.
+ *      The status of EAPOL frame trap to CPU is as following:
+ *      - DISABLED
+ *      - ENABLED
+ */
+rtk_api_ret_t rtk_dot1x_eapolFrame2CpuEnable_get(rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_rma_t rmacfg;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicRma(3, &rmacfg)) != RT_ERR_OK)
+        return retVal;
+
+    if (RMAOP_TRAP_TO_CPU == rmacfg.operation)
+        *pEnable = ENABLED;
+    else
+        *pEnable = DISABLED;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_portBasedEnable_set
+ * Description:
+ *      Set 802.1x port-based enable configuration
+ * Input:
+ *      port - Port id.
+ *      enable - The status of 802.1x port.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number.
+ *      RT_ERR_ENABLE               - Invalid enable input.
+ *      RT_ERR_DOT1X_PORTBASEDPNEN  - 802.1X port-based enable error
+ * Note:
+ *      The API can update the port-based port enable register content. If a port is 802.1x
+ *      port based network access control "enabled", it should be authenticated so packets
+ *      from that port won't be dropped or trapped to CPU.
+ *      The status of 802.1x port-based network access control is as following:
+ *      - DISABLED
+ *      - ENABLED
+ */
+rtk_api_ret_t rtk_dot1x_portBasedEnable_set(rtk_port_t port, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (enable >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if ((retVal = rtl8367c_setAsic1xPBEnConfig(rtk_switch_port_L2P_get(port),enable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_portBasedEnable_get
+ * Description:
+ *      Get 802.1x port-based enable configuration
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEnable - The status of 802.1x port.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get the 802.1x port-based port status.
+ */
+rtk_api_ret_t rtk_dot1x_portBasedEnable_get(rtk_port_t port, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsic1xPBEnConfig(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_portBasedAuthStatus_set
+ * Description:
+ *      Set 802.1x port-based auth. port configuration
+ * Input:
+ *      port - Port id.
+ *      port_auth - The status of 802.1x port.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number.
+ *     RT_ERR_DOT1X_PORTBASEDAUTH   - 802.1X port-based auth error
+ * Note:
+ *      The authenticated status of 802.1x port-based network access control is as following:
+ *      - UNAUTH
+ *      - AUTH
+ */
+rtk_api_ret_t rtk_dot1x_portBasedAuthStatus_set(rtk_port_t port, rtk_dot1x_auth_status_t port_auth)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+     if (port_auth >= AUTH_STATUS_END)
+        return RT_ERR_DOT1X_PORTBASEDAUTH;
+
+    if ((retVal = rtl8367c_setAsic1xPBAuthConfig(rtk_switch_port_L2P_get(port), port_auth)) != RT_ERR_OK)
+        return retVal;
+
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_portBasedAuthStatus_get
+ * Description:
+ *      Get 802.1x port-based auth. port configuration
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pPort_auth - The status of 802.1x port.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get 802.1x port-based port auth.information.
+ */
+rtk_api_ret_t rtk_dot1x_portBasedAuthStatus_get(rtk_port_t port, rtk_dot1x_auth_status_t *pPort_auth)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pPort_auth)
+        return RT_ERR_NULL_POINTER;
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if ((retVal = rtl8367c_getAsic1xPBAuthConfig(rtk_switch_port_L2P_get(port), pPort_auth)) != RT_ERR_OK)
+        return retVal;
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_portBasedDirection_set
+ * Description:
+ *      Set 802.1x port-based operational direction configuration
+ * Input:
+ *      port            - Port id.
+ *      port_direction  - Operation direction
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number.
+ *      RT_ERR_DOT1X_PORTBASEDOPDIR - 802.1X port-based operation direction error
+ * Note:
+ *      The operate controlled direction of 802.1x port-based network access control is as following:
+ *      - BOTH
+ *      - IN
+ */
+rtk_api_ret_t rtk_dot1x_portBasedDirection_set(rtk_port_t port, rtk_dot1x_direction_t port_direction)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (port_direction >= DIRECTION_END)
+        return RT_ERR_DOT1X_PORTBASEDOPDIR;
+
+    if ((retVal = rtl8367c_setAsic1xPBOpdirConfig(rtk_switch_port_L2P_get(port), port_direction)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_portBasedDirection_get
+ * Description:
+ *      Get 802.1X port-based operational direction configuration
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pPort_direction - Operation direction
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get 802.1x port-based operational direction information.
+ */
+rtk_api_ret_t rtk_dot1x_portBasedDirection_get(rtk_port_t port, rtk_dot1x_direction_t *pPort_direction)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pPort_direction)
+        return RT_ERR_NULL_POINTER;
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if ((retVal = rtl8367c_getAsic1xPBOpdirConfig(rtk_switch_port_L2P_get(port), pPort_direction)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_macBasedEnable_set
+ * Description:
+ *      Set 802.1x mac-based port enable configuration
+ * Input:
+ *      port - Port id.
+ *      enable - The status of 802.1x port.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number.
+ *      RT_ERR_ENABLE               - Invalid enable input.
+ *      RT_ERR_DOT1X_MACBASEDPNEN   - 802.1X mac-based enable error
+ * Note:
+ *      If a port is 802.1x MAC based network access control "enabled", the incoming packets should
+ *       be authenticated so packets from that port won't be dropped or trapped to CPU.
+ *      The status of 802.1x MAC-based network access control is as following:
+ *      - DISABLED
+ *      - ENABLED
+ */
+rtk_api_ret_t rtk_dot1x_macBasedEnable_set(rtk_port_t port, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (enable >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if ((retVal = rtl8367c_setAsic1xMBEnConfig(rtk_switch_port_L2P_get(port),enable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_macBasedEnable_get
+ * Description:
+ *      Get 802.1x mac-based port enable configuration
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEnable - The status of 802.1x port.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      If a port is 802.1x MAC based network access control "enabled", the incoming packets should
+ *      be authenticated so packets from that port wont be dropped or trapped to CPU.
+ *      The status of 802.1x MAC-based network access control is as following:
+ *      - DISABLED
+ *      - ENABLED
+ */
+rtk_api_ret_t rtk_dot1x_macBasedEnable_get(rtk_port_t port, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if ((retVal = rtl8367c_getAsic1xMBEnConfig(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_macBasedAuthMac_add
+ * Description:
+ *      Add an authenticated MAC to ASIC
+ * Input:
+ *      port        - Port id.
+ *      pAuth_mac   - The authenticated MAC.
+ *      fid         - filtering database.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number.
+ *      RT_ERR_ENABLE               - Invalid enable input.
+ *      RT_ERR_DOT1X_MACBASEDPNEN   - 802.1X mac-based enable error
+ * Note:
+ *      The API can add a 802.1x authenticated MAC address to port. If the MAC does not exist in LUT,
+ *      user can't add this MAC to auth status.
+ */
+rtk_api_ret_t rtk_dot1x_macBasedAuthMac_add(rtk_port_t port, rtk_mac_t *pAuth_mac, rtk_fid_t fid)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 method;
+    rtl8367c_luttb l2Table;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* must be unicast address */
+    if ((pAuth_mac == NULL) || (pAuth_mac->octet[0] & 0x1))
+        return RT_ERR_MAC;
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (fid > RTL8367C_FIDMAX)
+        return RT_ERR_L2_FID;
+
+    memset(&l2Table, 0, sizeof(rtl8367c_luttb));
+
+    /* fill key (MAC,FID) to get L2 entry */
+    memcpy(l2Table.mac.octet, pAuth_mac->octet, ETHER_ADDR_LEN);
+    l2Table.fid = fid;
+    method = LUTREADMETHOD_MAC;
+    retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table);
+    if ( RT_ERR_OK == retVal)
+    {
+        if (l2Table.spa != rtk_switch_port_L2P_get(port))
+            return RT_ERR_DOT1X_MAC_PORT_MISMATCH;
+
+        memcpy(l2Table.mac.octet, pAuth_mac->octet, ETHER_ADDR_LEN);
+        l2Table.fid = fid;
+        l2Table.efid = 0;
+        l2Table.auth = 1;
+        retVal = rtl8367c_setAsicL2LookupTb(&l2Table);
+        return retVal;
+    }
+    else
+        return retVal;
+
+}
+
+/* Function Name:
+ *      rtk_dot1x_macBasedAuthMac_del
+ * Description:
+ *      Delete an authenticated MAC to ASIC
+ * Input:
+ *      port - Port id.
+ *      pAuth_mac - The authenticated MAC.
+ *      fid - filtering database.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_MAC          - Invalid MAC address.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can delete a 802.1x authenticated MAC address to port. It only change the auth status of
+ *      the MAC and won't delete it from LUT.
+ */
+rtk_api_ret_t rtk_dot1x_macBasedAuthMac_del(rtk_port_t port, rtk_mac_t *pAuth_mac, rtk_fid_t fid)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 method;
+    rtl8367c_luttb l2Table;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* must be unicast address */
+    if ((pAuth_mac == NULL) || (pAuth_mac->octet[0] & 0x1))
+        return RT_ERR_MAC;
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (fid > RTL8367C_FIDMAX)
+        return RT_ERR_L2_FID;
+
+    memset(&l2Table, 0, sizeof(rtl8367c_luttb));
+
+    /* fill key (MAC,FID) to get L2 entry */
+    memcpy(l2Table.mac.octet, pAuth_mac->octet, ETHER_ADDR_LEN);
+    l2Table.fid = fid;
+    method = LUTREADMETHOD_MAC;
+    retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table);
+    if (RT_ERR_OK == retVal)
+    {
+        if (l2Table.spa != rtk_switch_port_L2P_get(port))
+            return RT_ERR_DOT1X_MAC_PORT_MISMATCH;
+
+        memcpy(l2Table.mac.octet, pAuth_mac->octet, ETHER_ADDR_LEN);
+        l2Table.fid = fid;
+        l2Table.auth = 0;
+        retVal = rtl8367c_setAsicL2LookupTb(&l2Table);
+        return retVal;
+    }
+    else
+        return retVal;
+
+}
+
+/* Function Name:
+ *      rtk_dot1x_macBasedDirection_set
+ * Description:
+ *      Set 802.1x mac-based operational direction configuration
+ * Input:
+ *      mac_direction - Operation direction
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_INPUT                - Invalid input parameter.
+ *      RT_ERR_DOT1X_MACBASEDOPDIR  - 802.1X mac-based operation direction error
+ * Note:
+ *      The operate controlled direction of 802.1x mac-based network access control is as following:
+ *      - BOTH
+ *      - IN
+ */
+rtk_api_ret_t rtk_dot1x_macBasedDirection_set(rtk_dot1x_direction_t mac_direction)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (mac_direction >= DIRECTION_END)
+        return RT_ERR_DOT1X_MACBASEDOPDIR;
+
+    if ((retVal = rtl8367c_setAsic1xMBOpdirConfig(mac_direction)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_macBasedDirection_get
+ * Description:
+ *      Get 802.1x mac-based operational direction configuration
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pMac_direction - Operation direction
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get 802.1x mac-based operational direction information.
+ */
+rtk_api_ret_t rtk_dot1x_macBasedDirection_get(rtk_dot1x_direction_t *pMac_direction)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pMac_direction)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsic1xMBOpdirConfig(pMac_direction)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      Set 802.1x guest VLAN configuration
+ * Description:
+ *      Set 802.1x mac-based operational direction configuration
+ * Input:
+ *      vid - 802.1x guest VLAN ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ * Note:
+ *      The operate controlled 802.1x guest VLAN
+ */
+rtk_api_ret_t rtk_dot1x_guestVlan_set(rtk_vlan_t vid)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 index;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* vid must be 0~4095 */
+    if (vid > RTL8367C_VIDMAX)
+        return RT_ERR_VLAN_VID;
+
+    if((retVal = rtk_vlan_checkAndCreateMbr(vid, &index)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsic1xGuestVidx(index)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_guestVlan_get
+ * Description:
+ *      Get 802.1x guest VLAN configuration
+ * Input:
+ *      None
+ * Output:
+ *      pVid - 802.1x guest VLAN ID
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get 802.1x guest VLAN information.
+ */
+rtk_api_ret_t rtk_dot1x_guestVlan_get(rtk_vlan_t *pVid)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 gvidx;
+    rtl8367c_vlanconfiguser vlanMC;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pVid)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsic1xGuestVidx(&gvidx)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicVlanMemberConfig(gvidx, &vlanMC)) != RT_ERR_OK)
+        return retVal;
+
+    *pVid = vlanMC.evid;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_guestVlan2Auth_set
+ * Description:
+ *      Set 802.1x guest VLAN to auth host configuration
+ * Input:
+ *      enable - The status of guest VLAN to auth host.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ * Note:
+ *      The operational direction of 802.1x guest VLAN to auth host control is as following:
+ *      - ENABLED
+ *      - DISABLED
+ */
+rtk_api_ret_t rtk_dot1x_guestVlan2Auth_set(rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (enable >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if ((retVal = rtl8367c_setAsic1xGVOpdir(enable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_dot1x_guestVlan2Auth_get
+ * Description:
+ *      Get 802.1x guest VLAN to auth host configuration
+ * Input:
+ *      None
+ * Output:
+ *      pEnable - The status of guest VLAN to auth host.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get 802.1x guest VLAN to auth host information.
+ */
+rtk_api_ret_t rtk_dot1x_guestVlan2Auth_get(rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsic1xGVOpdir(pEnable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/eee.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/eee.c
new file mode 100644
index 0000000..cd14c2c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/eee.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 48156 $
+ * $Date: 2014-05-29 16:39:06 +0800 (週四, 29 五月 2014) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in EEE module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <eee.h>
+#include <string.h>
+
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_eee.h>
+#include <rtl8367c_asicdrv_phy.h>
+
+/* Function Name:
+ *      rtk_eee_init
+ * Description:
+ *      EEE function initialization.
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      This API is used to initialize EEE status.
+ */
+rtk_api_ret_t rtk_eee_init(void)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if((retVal = rtl8367c_setAsicRegBit(0x0018, 10, 1)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicRegBit(0x0018, 11, 1)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_eee_portEnable_set
+ * Description:
+ *      Set enable status of EEE function.
+ * Input:
+ *      port - port id.
+ *      enable - enable EEE status.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_PORT_ID - Invalid port number.
+ *      RT_ERR_ENABLE - Invalid enable input.
+ * Note:
+ *      This API can set EEE function to the specific port.
+ *      The configuration of the port is as following:
+ *      - DISABLE
+ *      - ENABLE
+ */
+rtk_api_ret_t rtk_eee_portEnable_set(rtk_port_t port, rtk_enable_t enable)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32      regData;
+    rtk_uint32    phy_port;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port is UTP port */
+    RTK_CHK_PORT_IS_UTP(port);
+
+    if (enable>=RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    phy_port = rtk_switch_port_L2P_get(port);
+
+    if ((retVal = rtl8367c_setAsicEee100M(phy_port,enable))!=RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtl8367c_setAsicEeeGiga(phy_port,enable))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicPHYReg(phy_port, RTL8367C_PHY_PAGE_ADDRESS, 0))!=RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtl8367c_getAsicPHYReg(phy_port, 0, &regData))!=RT_ERR_OK)
+        return retVal;
+    regData |= 0x0200;
+    if ((retVal = rtl8367c_setAsicPHYReg(phy_port, 0, regData))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_eee_portEnable_get
+ * Description:
+ *      Get enable status of EEE function
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEnable - Back pressure status.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_PORT_ID - Invalid port number.
+ * Note:
+ *      This API can get EEE function to the specific port.
+ *      The configuration of the port is as following:
+ *      - DISABLE
+ *      - ENABLE
+ */
+
+rtk_api_ret_t rtk_eee_portEnable_get(rtk_port_t port, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 regData1, regData2;
+    rtk_uint32    phy_port;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port is UTP port */
+    RTK_CHK_PORT_IS_UTP(port);
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    phy_port = rtk_switch_port_L2P_get(port);
+
+    if ((retVal = rtl8367c_getAsicEee100M(phy_port,&regData1))!=RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtl8367c_getAsicEeeGiga(phy_port,&regData2))!=RT_ERR_OK)
+        return retVal;
+
+    if (regData1==1&&regData2==1)
+        *pEnable = ENABLED;
+    else
+        *pEnable = DISABLED;
+
+    return RT_ERR_OK;
+}
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/i2c.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/i2c.c
new file mode 100644
index 0000000..17a5f37
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/i2c.c
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 63932 $
+ * $Date: 2015-12-08 14:06:29 +0800 (周二, 08 十二月 2015) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in i2c module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <port.h>
+#include <string.h>
+#include <rtl8367c_reg.h>
+
+#include <rtl8367c_asicdrv_i2c.h>
+#include <rtk_switch.h>
+#include <rtl8367c_asicdrv.h>
+#include <rtk_types.h>
+#include <i2c.h>
+
+
+static rtk_I2C_16bit_mode_t rtk_i2c_mode = I2C_LSB_16BIT_MODE;
+
+
+/* Function Name:
+ *      rtk_i2c_init
+ * Description:
+ *      I2C smart function initialization.
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ * Note:
+ *      This API is used to initialize EEE status.
+ *      need used GPIO pins
+ *      OpenDrain and clock
+ */
+rtk_api_ret_t rtk_i2c_init(void)
+{
+    rtk_uint32 retVal;
+  switch_chip_t ChipID;
+  /* probe switch */
+  if((retVal = rtk_switch_probe(&ChipID)) != RT_ERR_OK)
+      return retVal;
+
+  if( ChipID == CHIP_RTL8370B )
+  {
+   /*set GPIO8, GPIO9, OpenDrain as I2C, clock = 252KHZ   */
+      if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_SYS_CTL, 0x5c3f)) != RT_ERR_OK)
+        return retVal;
+  }
+  else
+      return RT_ERR_FAILED;
+  return  RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_i2c_mode_set
+ * Description:
+ *      Set I2C data byte-order.
+ * Input:
+ *      i2cmode - byte-order mode
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ * Note:
+ *      This API can set I2c traffic's byte-order .
+ */
+rtk_api_ret_t rtk_i2c_mode_set( rtk_I2C_16bit_mode_t i2cmode )
+{
+    if(i2cmode >= I2C_Mode_END)
+    {
+        return RT_ERR_INPUT;
+    }
+    else if(i2cmode == I2C_70B_LSB_16BIT_MODE)
+    {
+        rtk_i2c_mode = I2C_70B_LSB_16BIT_MODE;
+
+        return RT_ERR_OK;
+    }
+    else if( i2cmode == I2C_LSB_16BIT_MODE)
+    {
+        rtk_i2c_mode = I2C_LSB_16BIT_MODE;
+        return RT_ERR_OK;
+    }
+    else
+        return RT_ERR_FAILED;
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_i2c_mode_get
+ * Description:
+ *      Get i2c traffic byte-order setting.
+ * Input:
+ *      None
+ * Output:
+ *      pI2cMode - i2c byte-order
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_NULL_POINTER     - input parameter is null pointer
+ * Note:
+ *      The API can get i2c traffic byte-order setting.
+ */
+rtk_api_ret_t rtk_i2c_mode_get( rtk_I2C_16bit_mode_t * pI2cMode)
+{
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+    if(NULL == pI2cMode)
+        return RT_ERR_NULL_POINTER;
+    if(rtk_i2c_mode == I2C_70B_LSB_16BIT_MODE)
+        *pI2cMode = 1;
+    else if ((rtk_i2c_mode == I2C_LSB_16BIT_MODE))
+        *pI2cMode = 0;
+    else
+        return RT_ERR_FAILED;
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_i2c_gpioPinGroup_set
+ * Description:
+ *      Set i2c SDA & SCL used GPIO pins group.
+ * Input:
+ *      pins_group - GPIO pins group
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ * Note:
+ *      The API can set i2c used gpio pins group.
+ *      There are three group pins could be used
+ */
+rtk_api_ret_t rtk_i2c_gpioPinGroup_set( rtk_I2C_gpio_pin_t pins_group )
+{
+    rtk_uint32 retVal;
+
+
+    if( ( pins_group > I2C_GPIO_PIN_END )|| ( pins_group < I2C_GPIO_PIN_8_9) )
+        return RT_ERR_INPUT;
+
+    if( (retVal = rtl8367c_setAsicI2CGpioPinGroup(pins_group) ) != RT_ERR_OK )
+        return retVal ;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_i2c_gpioPinGroup_get
+ * Description:
+ *      Get i2c SDA & SCL used GPIO pins group.
+ * Input:
+ *      None
+ * Output:
+ *      pPins_group - GPIO pins group
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_NULL_POINTER     - input parameter is null pointer
+ * Note:
+ *      The API can get i2c used gpio pins group.
+ *      There are three group pins could be used
+ */
+rtk_api_ret_t rtk_i2c_gpioPinGroup_get( rtk_I2C_gpio_pin_t * pPins_group )
+{
+    rtk_uint32 retVal;
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pPins_group)
+        return RT_ERR_NULL_POINTER;
+    if( (retVal = rtl8367c_getAsicI2CGpioPinGroup(pPins_group) ) != RT_ERR_OK )
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_i2c_data_read
+ * Description:
+ *      read i2c slave device register.
+ * Input:
+ *      deviceAddr   -   access Slave device address
+ *      slaveRegAddr -   access Slave register address
+ * Output:
+ *      pRegData     -   read data
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_NULL_POINTER     - input parameter is null pointer
+ * Note:
+ *      The API can access i2c slave and read i2c slave device register.
+ */
+rtk_api_ret_t rtk_i2c_data_read(rtk_uint8 deviceAddr, rtk_uint32 slaveRegAddr, rtk_uint32 *pRegData)
+{
+     rtk_uint32 retVal, counter=0;
+     rtk_uint8 controlByte_W, controlByte_R;
+     rtk_uint8 slaveRegAddr_L, slaveRegAddr_H = 0x0, temp;
+     rtk_uint8 regData_L, regData_H;
+
+   /* control byte :deviceAddress + W,  deviceAddress + R   */
+    controlByte_W = (rtk_uint8)(deviceAddr << 1) ;
+    controlByte_R = (rtk_uint8)(controlByte_W | 0x1);
+
+    slaveRegAddr_L = (rtk_uint8) (slaveRegAddr & 0x00FF) ;
+    slaveRegAddr_H = (rtk_uint8) (slaveRegAddr >>8) ;
+
+    if( rtk_i2c_mode == I2C_70B_LSB_16BIT_MODE)
+    {
+        temp = slaveRegAddr_L ;
+        slaveRegAddr_L = slaveRegAddr_H;
+        slaveRegAddr_H = temp;
+    }
+
+
+  /*check bus state: idle*/
+  for(counter = 3000; counter>0; counter--)
+  {
+    if ( (retVal = rtl8367c_setAsicI2C_checkBusIdle() ) == RT_ERR_OK)
+         break;
+  }
+  if( counter ==0 )
+      return retVal; /*i2c is busy*/
+
+   /*tx Start cmd*/
+   if( (retVal = rtl8367c_setAsicI2CStartCmd() ) != RT_ERR_OK )
+       return retVal ;
+
+
+  /*tx control _W*/
+   if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(controlByte_W))!= RT_ERR_OK )
+      return retVal ;
+
+
+  /*check if RX ack from slave*/
+   if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK )
+        return retVal;
+
+    /* tx slave buffer address low 8 bits */
+   if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(slaveRegAddr_L))!= RT_ERR_OK )
+         return retVal  ;
+
+   /*check if RX ack from slave*/
+   if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK )
+        return retVal;
+
+
+
+        /* tx slave buffer address high 8 bits */
+   if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(slaveRegAddr_H))!= RT_ERR_OK )
+         return retVal  ;
+
+
+   /*check if RX ack from slave*/
+   if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK )
+        return retVal;
+
+
+   /*tx Start cmd*/
+   if( (retVal = rtl8367c_setAsicI2CStartCmd() ) != RT_ERR_OK )
+       return retVal ;
+
+      /*tx control _R*/
+   if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(controlByte_R))!= RT_ERR_OK )
+       return retVal ;
+
+
+  /*check if RX ack from slave*/
+   if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK )
+        return retVal;
+
+
+    /* rx low 8bit data*/
+   if( ( retVal = rtl8367c_setAsicI2CRxOneCharCmd( &regData_L) ) != RT_ERR_OK )
+        return retVal;
+
+
+
+    /* tx ack to slave, keep receive */
+    if( (retVal = rtl8367c_setAsicI2CTxAckCmd()) != RT_ERR_OK )
+        return retVal;
+
+     /* rx high 8bit data*/
+    if( ( retVal = rtl8367c_setAsicI2CRxOneCharCmd( &regData_H) ) != RT_ERR_OK )
+        return retVal;
+
+
+
+    /* tx Noack to slave, Stop receive */
+     if( (retVal = rtl8367c_setAsicI2CTxNoAckCmd()) != RT_ERR_OK )
+        return retVal;
+
+
+    /*tx Stop cmd */
+    if( (retVal = rtl8367c_setAsicI2CStopCmd()) != RT_ERR_OK )
+        return retVal;
+
+    *pRegData = (regData_H << 8) | regData_L;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_i2c_data_write
+ * Description:
+ *      write data to i2c slave device register
+ * Input:
+ *      deviceAddr   -   access Slave device address
+ *      slaveRegAddr -   access Slave register address
+ *      regData      -   data to set
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ * Note:
+ *      The API can access i2c slave and setting i2c slave device register.
+ */
+rtk_api_ret_t rtk_i2c_data_write(rtk_uint8 deviceAddr, rtk_uint32 slaveRegAddr, rtk_uint32 regData)
+{
+     rtk_uint32 retVal,counter;
+     rtk_uint8 controlByte_W;
+     rtk_uint8 slaveRegAddr_L, slaveRegAddr_H = 0x0, temp;
+     rtk_uint8 regData_L, regData_H;
+
+  /* control byte :deviceAddress + W    */
+    controlByte_W = (rtk_uint8)(deviceAddr<< 1) ;
+
+    slaveRegAddr_L = (rtk_uint8) (slaveRegAddr & 0x00FF) ;
+    slaveRegAddr_H = (rtk_uint8) (slaveRegAddr >>8) ;
+
+    regData_H   = (rtk_uint8) (regData>> 8);
+    regData_L   = (rtk_uint8) (regData & 0x00FF);
+
+    if( rtk_i2c_mode == I2C_70B_LSB_16BIT_MODE)
+    {
+        temp = slaveRegAddr_L ;
+        slaveRegAddr_L = slaveRegAddr_H;
+        slaveRegAddr_H = temp;
+    }
+
+
+  /*check bus state: idle*/
+  for(counter = 3000; counter>0; counter--)
+  {
+    if ( (retVal = rtl8367c_setAsicI2C_checkBusIdle() ) == RT_ERR_OK)
+        break;
+  }
+
+  if( counter ==0 )
+      return retVal; /*i2c is busy*/
+
+
+   /*tx Start cmd*/
+   if( (retVal = rtl8367c_setAsicI2CStartCmd() ) != RT_ERR_OK )
+       return retVal ;
+
+
+  /*tx control _W*/
+   if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(controlByte_W))!= RT_ERR_OK )
+      return retVal ;
+
+
+  /*check if RX ack from slave*/
+   if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK )
+        return retVal;
+
+
+    /* tx slave buffer address low 8 bits */
+   if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(slaveRegAddr_L))!= RT_ERR_OK )
+        return retVal;
+
+
+   /*check if RX ack from slave*/
+   if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK )
+        return retVal;
+
+
+   /* tx slave buffer address high 8 bits */
+   if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(slaveRegAddr_H))!= RT_ERR_OK )
+        return retVal;
+
+
+   /*check if RX ack from slave*/
+   if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK )
+        return retVal;
+
+
+     /*tx Datavlue LSB*/
+   if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(regData_L))!= RT_ERR_OK )
+        return retVal;
+
+
+   /*check if RX ack from slave*/
+   if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK )
+        return retVal;
+
+
+   /*tx Datavlue MSB*/
+   if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(regData_H))!= RT_ERR_OK )
+        return retVal;
+
+
+   /*check if RX ack from slave*/
+   if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK )
+        return retVal;
+
+
+    /*tx Stop cmd */
+    if( (retVal = rtl8367c_setAsicI2CStopCmd()) != RT_ERR_OK )
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/igmp.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/igmp.c
new file mode 100644
index 0000000..170cbda
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/igmp.c
@@ -0,0 +1,1555 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in IGMP module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <igmp.h>
+#include <string.h>
+
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_igmp.h>
+#include <rtl8367c_asicdrv_lut.h>
+
+
+/* Function Name:
+ *      rtk_igmp_init
+ * Description:
+ *      This API enables H/W IGMP and set a default initial configuration.
+ * Input:
+ *      None.
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      This API enables H/W IGMP and set a default initial configuration.
+ */
+rtk_api_ret_t rtk_igmp_init(void)
+{
+    rtk_api_ret_t retVal;
+    rtk_port_t port;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((retVal = rtl8367c_setAsicLutIpMulticastLookup(ENABLED))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicLutIpLookupMethod(1))!=RT_ERR_OK)
+        return retVal;
+
+    RTK_SCAN_ALL_PHY_PORTMASK(port)
+    {
+        if ((retVal = rtl8367c_setAsicIGMPv1Opeartion(port, PROTOCOL_OP_ASIC))!=RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicIGMPv2Opeartion(port, PROTOCOL_OP_ASIC))!=RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicIGMPv3Opeartion(port, PROTOCOL_OP_FLOOD))!=RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicMLDv1Opeartion(port, PROTOCOL_OP_ASIC))!=RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicMLDv2Opeartion(port, PROTOCOL_OP_FLOOD))!=RT_ERR_OK)
+            return retVal;
+    }
+
+    if ((retVal = rtl8367c_setAsicIGMPAllowDynamicRouterPort(rtk_switch_phyPortMask_get()))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicIGMPFastLeaveEn(ENABLED))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicIGMPReportLeaveFlood(1))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicIgmp(ENABLED))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_state_set
+ * Description:
+ *      This API set H/W IGMP state.
+ * Input:
+ *      enabled     - H/W IGMP state
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error parameter
+ * Note:
+ *      This API set H/W IGMP state.
+ */
+rtk_api_ret_t rtk_igmp_state_set(rtk_enable_t enabled)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (enabled >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicIgmp(enabled))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_state_get
+ * Description:
+ *      This API get H/W IGMP state.
+ * Input:
+ *      None.
+ * Output:
+ *      pEnabled        - H/W IGMP state
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error parameter
+ * Note:
+ *      This API set current H/W IGMP state.
+ */
+rtk_api_ret_t rtk_igmp_state_get(rtk_enable_t *pEnabled)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(pEnabled == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicIgmp(pEnabled))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_static_router_port_set
+ * Description:
+ *      Configure static router port
+ * Input:
+ *      pPortmask    - Static Port mask
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_PORT_MASK       - Error parameter
+ * Note:
+ *      This API set static router port
+ */
+rtk_api_ret_t rtk_igmp_static_router_port_set(rtk_portmask_t *pPortmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Valid port mask */
+    if(pPortmask == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    RTK_CHK_PORTMASK_VALID(pPortmask);
+
+    if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicIGMPStaticRouterPort(pmask))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_static_router_port_get
+ * Description:
+ *      Get static router port
+ * Input:
+ *      None.
+ * Output:
+ *      pPortmask       - Static port mask
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_PORT_MASK       - Error parameter
+ * Note:
+ *      This API get static router port
+ */
+rtk_api_ret_t rtk_igmp_static_router_port_get(rtk_portmask_t *pPortmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(pPortmask == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicIGMPStaticRouterPort(&pmask))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_protocol_set
+ * Description:
+ *      set IGMP/MLD protocol action
+ * Input:
+ *      port        - Port ID
+ *      protocol    - IGMP/MLD protocol
+ *      action      - Per-port and per-protocol IGMP action seeting
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_PORT_MASK       - Error parameter
+ * Note:
+ *      This API set IGMP/MLD protocol action
+ */
+rtk_api_ret_t rtk_igmp_protocol_set(rtk_port_t port, rtk_igmp_protocol_t protocol, rtk_igmp_action_t action)
+{
+    rtk_uint32      operation;
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(protocol >= PROTOCOL_END)
+        return RT_ERR_INPUT;
+
+    if(action >= IGMP_ACTION_END)
+        return RT_ERR_INPUT;
+
+    switch(action)
+    {
+        case IGMP_ACTION_FORWARD:
+            operation = PROTOCOL_OP_FLOOD;
+            break;
+        case IGMP_ACTION_TRAP2CPU:
+            operation = PROTOCOL_OP_TRAP;
+            break;
+        case IGMP_ACTION_DROP:
+            operation = PROTOCOL_OP_DROP;
+            break;
+        case IGMP_ACTION_ASIC:
+            operation = PROTOCOL_OP_ASIC;
+            break;
+        default:
+            return RT_ERR_INPUT;
+    }
+
+    switch(protocol)
+    {
+        case PROTOCOL_IGMPv1:
+            if ((retVal = rtl8367c_setAsicIGMPv1Opeartion(rtk_switch_port_L2P_get(port), operation))!=RT_ERR_OK)
+                return retVal;
+
+            break;
+        case PROTOCOL_IGMPv2:
+            if ((retVal = rtl8367c_setAsicIGMPv2Opeartion(rtk_switch_port_L2P_get(port), operation))!=RT_ERR_OK)
+                return retVal;
+
+            break;
+        case PROTOCOL_IGMPv3:
+            if ((retVal = rtl8367c_setAsicIGMPv3Opeartion(rtk_switch_port_L2P_get(port), operation))!=RT_ERR_OK)
+                return retVal;
+
+            break;
+        case PROTOCOL_MLDv1:
+            if ((retVal = rtl8367c_setAsicMLDv1Opeartion(rtk_switch_port_L2P_get(port), operation))!=RT_ERR_OK)
+                return retVal;
+
+            break;
+        case PROTOCOL_MLDv2:
+            if ((retVal = rtl8367c_setAsicMLDv2Opeartion(rtk_switch_port_L2P_get(port), operation))!=RT_ERR_OK)
+                return retVal;
+
+            break;
+        default:
+            return RT_ERR_INPUT;
+
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_protocol_get
+ * Description:
+ *      set IGMP/MLD protocol action
+ * Input:
+ *      port        - Port ID
+ *      protocol    - IGMP/MLD protocol
+ *      action      - Per-port and per-protocol IGMP action seeting
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_PORT_MASK       - Error parameter
+ * Note:
+ *      This API set IGMP/MLD protocol action
+ */
+rtk_api_ret_t rtk_igmp_protocol_get(rtk_port_t port, rtk_igmp_protocol_t protocol, rtk_igmp_action_t *pAction)
+{
+    rtk_uint32      operation;
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(protocol >= PROTOCOL_END)
+        return RT_ERR_INPUT;
+
+    if(pAction == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    switch(protocol)
+    {
+        case PROTOCOL_IGMPv1:
+            if ((retVal = rtl8367c_getAsicIGMPv1Opeartion(rtk_switch_port_L2P_get(port), &operation))!=RT_ERR_OK)
+                return retVal;
+
+            break;
+        case PROTOCOL_IGMPv2:
+            if ((retVal = rtl8367c_getAsicIGMPv2Opeartion(rtk_switch_port_L2P_get(port), &operation))!=RT_ERR_OK)
+                return retVal;
+
+            break;
+        case PROTOCOL_IGMPv3:
+            if ((retVal = rtl8367c_getAsicIGMPv3Opeartion(rtk_switch_port_L2P_get(port), &operation))!=RT_ERR_OK)
+                return retVal;
+
+            break;
+        case PROTOCOL_MLDv1:
+            if ((retVal = rtl8367c_getAsicMLDv1Opeartion(rtk_switch_port_L2P_get(port), &operation))!=RT_ERR_OK)
+                return retVal;
+
+            break;
+        case PROTOCOL_MLDv2:
+            if ((retVal = rtl8367c_getAsicMLDv2Opeartion(rtk_switch_port_L2P_get(port), &operation))!=RT_ERR_OK)
+                return retVal;
+
+            break;
+        default:
+            return RT_ERR_INPUT;
+
+    }
+
+    switch(operation)
+    {
+        case PROTOCOL_OP_FLOOD:
+            *pAction = IGMP_ACTION_FORWARD;
+            break;
+        case PROTOCOL_OP_TRAP:
+            *pAction = IGMP_ACTION_TRAP2CPU;
+            break;
+        case PROTOCOL_OP_DROP:
+            *pAction = IGMP_ACTION_DROP;
+            break;
+        case PROTOCOL_OP_ASIC:
+            *pAction = IGMP_ACTION_ASIC;
+            break;
+        default:
+            return RT_ERR_FAILED;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_fastLeave_set
+ * Description:
+ *      set IGMP/MLD FastLeave state
+ * Input:
+ *      state       - ENABLED: Enable FastLeave, DISABLED: disable FastLeave
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      This API set IGMP/MLD FastLeave state
+ */
+rtk_api_ret_t rtk_igmp_fastLeave_set(rtk_enable_t state)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(state >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicIGMPFastLeaveEn((rtk_uint32)state))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_fastLeave_get
+ * Description:
+ *      get IGMP/MLD FastLeave state
+ * Input:
+ *      None
+ * Output:
+ *      pState      - ENABLED: Enable FastLeave, DISABLED: disable FastLeave
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_NULL_POINTER    - NULL pointer
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      This API get IGMP/MLD FastLeave state
+ */
+rtk_api_ret_t rtk_igmp_fastLeave_get(rtk_enable_t *pState)
+{
+    rtk_uint32      fast_leave;
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(pState == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicIGMPFastLeaveEn(&fast_leave))!=RT_ERR_OK)
+        return retVal;
+
+    *pState = ((fast_leave == 1) ? ENABLED : DISABLED);
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_maxGroup_set
+ * Description:
+ *      Set per port multicast group learning limit.
+ * Input:
+ *      port        - Port ID
+ *      group       - The number of multicast group learning limit.
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_PORT_ID         - Error Port ID
+ *      RT_ERR_OUT_OF_RANGE    - parameter out of range
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      This API set per port multicast group learning limit.
+ */
+rtk_api_ret_t rtk_igmp_maxGroup_set(rtk_port_t port, rtk_uint32 group)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(group > RTL8367C_IGMP_MAX_GOUP)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if ((retVal = rtl8367c_setAsicIGMPPortMAXGroup(rtk_switch_port_L2P_get(port), group))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_maxGroup_get
+ * Description:
+ *      Get per port multicast group learning limit.
+ * Input:
+ *      port        - Port ID
+ * Output:
+ *      pGroup      - The number of multicast group learning limit.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_PORT_ID         - Error Port ID
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      This API get per port multicast group learning limit.
+ */
+rtk_api_ret_t rtk_igmp_maxGroup_get(rtk_port_t port, rtk_uint32 *pGroup)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(pGroup == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicIGMPPortMAXGroup(rtk_switch_port_L2P_get(port), pGroup))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_currentGroup_get
+ * Description:
+ *      Get per port multicast group learning count.
+ * Input:
+ *      port        - Port ID
+ * Output:
+ *      pGroup      - The number of multicast group learning count.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_PORT_ID         - Error Port ID
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      This API get per port multicast group learning count.
+ */
+rtk_api_ret_t rtk_igmp_currentGroup_get(rtk_port_t port, rtk_uint32 *pGroup)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(pGroup == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicIGMPPortCurrentGroup(rtk_switch_port_L2P_get(port), pGroup))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_tableFullAction_set
+ * Description:
+ *      set IGMP/MLD Table Full Action
+ * Input:
+ *      action      - Table Full Action
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ */
+rtk_api_ret_t rtk_igmp_tableFullAction_set(rtk_igmp_tableFullAction_t action)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(action >= IGMP_TABLE_FULL_OP_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicIGMPTableFullOP((rtk_uint32)action))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_tableFullAction_get
+ * Description:
+ *      get IGMP/MLD Table Full Action
+ * Input:
+ *      None
+ * Output:
+ *      pAction     - Table Full Action
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ */
+rtk_api_ret_t rtk_igmp_tableFullAction_get(rtk_igmp_tableFullAction_t *pAction)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pAction)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicIGMPTableFullOP((rtk_uint32 *)pAction))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_checksumErrorAction_set
+ * Description:
+ *      set IGMP/MLD Checksum Error Action
+ * Input:
+ *      action      - Checksum error Action
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ */
+rtk_api_ret_t rtk_igmp_checksumErrorAction_set(rtk_igmp_checksumErrorAction_t action)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(action >= IGMP_CRC_ERR_OP_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicIGMPCRCErrOP((rtk_uint32)action))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_igmp_checksumErrorAction_get
+ * Description:
+ *      get IGMP/MLD Checksum Error Action
+ * Input:
+ *      None
+ * Output:
+ *      pAction     - Checksum error Action
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ */
+rtk_api_ret_t rtk_igmp_checksumErrorAction_get(rtk_igmp_checksumErrorAction_t *pAction)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pAction)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicIGMPCRCErrOP((rtk_uint32 *)pAction))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_leaveTimer_set
+ * Description:
+ *      set IGMP/MLD Leave timer
+ * Input:
+ *      timer       - Leave timer
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ */
+rtk_api_ret_t rtk_igmp_leaveTimer_set(rtk_uint32 timer)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(timer > RTL8367C_MAX_LEAVE_TIMER)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicIGMPLeaveTimer(timer))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_leaveTimer_get
+ * Description:
+ *      get IGMP/MLD Leave timer
+ * Input:
+ *      None
+ * Output:
+ *      pTimer      - Leave Timer.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ */
+rtk_api_ret_t rtk_igmp_leaveTimer_get(rtk_uint32 *pTimer)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pTimer)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicIGMPLeaveTimer(pTimer))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_queryInterval_set
+ * Description:
+ *      set IGMP/MLD Query Interval
+ * Input:
+ *      interval     - Query Interval
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ */
+rtk_api_ret_t rtk_igmp_queryInterval_set(rtk_uint32 interval)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(interval > RTL8367C_MAX_QUERY_INT)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicIGMPQueryInterval(interval))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_queryInterval_get
+ * Description:
+ *      get IGMP/MLD Query Interval
+ * Input:
+ *      None.
+ * Output:
+ *      pInterval   - Query Interval
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ */
+rtk_api_ret_t rtk_igmp_queryInterval_get(rtk_uint32 *pInterval)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pInterval)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicIGMPQueryInterval(pInterval))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_robustness_set
+ * Description:
+ *      set IGMP/MLD Robustness value
+ * Input:
+ *      robustness     - Robustness value
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ */
+rtk_api_ret_t rtk_igmp_robustness_set(rtk_uint32 robustness)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(robustness > RTL8367C_MAX_ROB_VAR)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicIGMPRobVar(robustness))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_robustness_get
+ * Description:
+ *      get IGMP/MLD Robustness value
+ * Input:
+ *      None
+ * Output:
+ *      pRobustness     - Robustness value.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ */
+rtk_api_ret_t rtk_igmp_robustness_get(rtk_uint32 *pRobustness)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pRobustness)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicIGMPRobVar(pRobustness))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_dynamicRouterRortAllow_set
+ * Description:
+ *      Configure dynamic router port allow option
+ * Input:
+ *      pPortmask    - Dynamic Port allow mask
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_PORT_MASK       - Error parameter
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_igmp_dynamicRouterPortAllow_set(rtk_portmask_t *pPortmask)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32 pmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pPortmask)
+        return RT_ERR_NULL_POINTER;
+
+    RTK_CHK_PORTMASK_VALID(pPortmask);
+
+    if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicIGMPAllowDynamicRouterPort(pmask))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_dynamicRouterRortAllow_get
+ * Description:
+ *      Get dynamic router port allow option
+ * Input:
+ *      None.
+ * Output:
+ *      pPortmask    - Dynamic Port allow mask
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_PORT_MASK       - Error parameter
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_igmp_dynamicRouterPortAllow_get(rtk_portmask_t *pPortmask)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32 pmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pPortmask)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicIGMPAllowDynamicRouterPort(&pmask))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_dynamicRouterPort_get
+ * Description:
+ *      Get dynamic router port
+ * Input:
+ *      None.
+ * Output:
+ *      pDynamicRouterPort    - Dynamic Router Port
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_PORT_MASK       - Error parameter
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_igmp_dynamicRouterPort_get(rtk_igmp_dynamicRouterPort_t *pDynamicRouterPort)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32 port;
+    rtk_uint32 timer;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pDynamicRouterPort)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicIGMPdynamicRouterPort1(&port, &timer))!= RT_ERR_OK)
+        return retVal;
+
+    if (port == RTL8367C_ROUTER_PORT_INVALID)
+    {
+        pDynamicRouterPort->dynamicRouterPort0Valid = DISABLED;
+        pDynamicRouterPort->dynamicRouterPort0      = 0;
+        pDynamicRouterPort->dynamicRouterPort0Timer = 0;
+    }
+    else
+    {
+        pDynamicRouterPort->dynamicRouterPort0Valid = ENABLED;
+        pDynamicRouterPort->dynamicRouterPort0      = rtk_switch_port_P2L_get(port);
+        pDynamicRouterPort->dynamicRouterPort0Timer = timer;
+    }
+
+    if ((retVal = rtl8367c_getAsicIGMPdynamicRouterPort2(&port, &timer))!= RT_ERR_OK)
+        return retVal;
+
+    if (port == RTL8367C_ROUTER_PORT_INVALID)
+    {
+        pDynamicRouterPort->dynamicRouterPort1Valid = DISABLED;
+        pDynamicRouterPort->dynamicRouterPort1      = 0;
+        pDynamicRouterPort->dynamicRouterPort1Timer = 0;
+    }
+    else
+    {
+        pDynamicRouterPort->dynamicRouterPort1Valid = ENABLED;
+        pDynamicRouterPort->dynamicRouterPort1      = rtk_switch_port_P2L_get(port);
+        pDynamicRouterPort->dynamicRouterPort1Timer = timer;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_suppressionEnable_set
+ * Description:
+ *      Configure IGMPv1/v2 & MLDv1 Report/Leave/Done suppression
+ * Input:
+ *      reportSuppression   - Report suppression
+ *      leaveSuppression    - Leave suppression
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error Input
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_igmp_suppressionEnable_set(rtk_enable_t reportSuppression, rtk_enable_t leaveSuppression)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(reportSuppression >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if(leaveSuppression >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicIGMPSuppression((rtk_uint32)reportSuppression, (rtk_uint32)leaveSuppression))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_suppressionEnable_get
+ * Description:
+ *      Get IGMPv1/v2 & MLDv1 Report/Leave/Done suppression
+ * Input:
+ *      None
+ * Output:
+ *      pReportSuppression  - Report suppression
+ *      pLeaveSuppression   - Leave suppression
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_igmp_suppressionEnable_get(rtk_enable_t *pReportSuppression, rtk_enable_t *pLeaveSuppression)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pReportSuppression)
+        return RT_ERR_NULL_POINTER;
+
+    if(NULL == pLeaveSuppression)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicIGMPSuppression((rtk_uint32 *)pReportSuppression, (rtk_uint32 *)pLeaveSuppression))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_portRxPktEnable_set
+ * Description:
+ *      Configure IGMP/MLD RX Packet configuration
+ * Input:
+ *      port       - Port ID
+ *      pRxCfg     - RX Packet Configuration
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_igmp_portRxPktEnable_set(rtk_port_t port, rtk_igmp_rxPktEnable_t *pRxCfg)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pRxCfg)
+        return RT_ERR_NULL_POINTER;
+
+    if(pRxCfg->rxQuery >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if(pRxCfg->rxReport >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if(pRxCfg->rxLeave >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if(pRxCfg->rxMRP >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if(pRxCfg->rxMcast >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicIGMPQueryRX(rtk_switch_port_L2P_get(port), (rtk_uint32)pRxCfg->rxQuery))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicIGMPReportRX(rtk_switch_port_L2P_get(port), (rtk_uint32)pRxCfg->rxReport))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicIGMPLeaveRX(rtk_switch_port_L2P_get(port), (rtk_uint32)pRxCfg->rxLeave))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicIGMPMRPRX(rtk_switch_port_L2P_get(port), (rtk_uint32)pRxCfg->rxMRP))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicIGMPMcDataRX(rtk_switch_port_L2P_get(port), (rtk_uint32)pRxCfg->rxMcast))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_portRxPktEnable_get
+ * Description:
+ *      Get IGMP/MLD RX Packet configuration
+ * Input:
+ *      port       - Port ID
+ *      pRxCfg     - RX Packet Configuration
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_igmp_portRxPktEnable_get(rtk_port_t port, rtk_igmp_rxPktEnable_t *pRxCfg)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pRxCfg)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicIGMPQueryRX(rtk_switch_port_L2P_get(port), (rtk_uint32 *)&(pRxCfg->rxQuery)))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicIGMPReportRX(rtk_switch_port_L2P_get(port), (rtk_uint32 *)&(pRxCfg->rxReport)))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicIGMPLeaveRX(rtk_switch_port_L2P_get(port), (rtk_uint32 *)&(pRxCfg->rxLeave)))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicIGMPMRPRX(rtk_switch_port_L2P_get(port), (rtk_uint32 *)&(pRxCfg->rxMRP)))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicIGMPMcDataRX(rtk_switch_port_L2P_get(port), (rtk_uint32 *)&(pRxCfg->rxMcast)))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_groupInfo_get
+ * Description:
+ *      Get IGMP/MLD Group database
+ * Input:
+ *      indes       - Index (0~255)
+ * Output:
+ *      pGroup      - Group database information.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_igmp_groupInfo_get(rtk_uint32 index, rtk_igmp_groupInfo_t *pGroup)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32      valid;
+    rtl8367c_igmpgroup  grp;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check index */
+    if(index > RTL8367C_IGMP_MAX_GOUP)
+        return RT_ERR_INPUT;
+
+    if(NULL == pGroup)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicIGMPGroup(index, &valid, &grp))!=RT_ERR_OK)
+        return retVal;
+
+    memset(pGroup, 0x00, sizeof(rtk_igmp_groupInfo_t));
+    pGroup->valid = valid;
+    pGroup->reportSuppFlag = grp.report_supp_flag;
+
+    if(grp.p0_timer != 0)
+    {
+        RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(0));
+        pGroup->timer[rtk_switch_port_P2L_get(0)] = grp.p0_timer;
+    }
+
+    if(grp.p1_timer != 0)
+    {
+        RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(1));
+        pGroup->timer[rtk_switch_port_P2L_get(1)] = grp.p1_timer;
+    }
+
+    if(grp.p2_timer != 0)
+    {
+        RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(2));
+        pGroup->timer[rtk_switch_port_P2L_get(2)] = grp.p2_timer;
+    }
+
+    if(grp.p3_timer != 0)
+    {
+        RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(3));
+        pGroup->timer[rtk_switch_port_P2L_get(3)] = grp.p3_timer;
+    }
+
+    if(grp.p4_timer != 0)
+    {
+        RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(4));
+        pGroup->timer[rtk_switch_port_P2L_get(4)] = grp.p4_timer;
+    }
+
+    if(grp.p5_timer != 0)
+    {
+        RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(5));
+        pGroup->timer[rtk_switch_port_P2L_get(5)] = grp.p5_timer;
+    }
+
+    if(grp.p6_timer != 0)
+    {
+        RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(6));
+        pGroup->timer[rtk_switch_port_P2L_get(6)] = grp.p6_timer;
+    }
+
+    if(grp.p7_timer != 0)
+    {
+        RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(7));
+        pGroup->timer[rtk_switch_port_P2L_get(7)] = grp.p7_timer;
+    }
+
+    if(grp.p8_timer != 0)
+    {
+        RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(8));
+        pGroup->timer[rtk_switch_port_P2L_get(8)] = grp.p8_timer;
+    }
+
+    if(grp.p9_timer != 0)
+    {
+        RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(9));
+        pGroup->timer[rtk_switch_port_P2L_get(9)] = grp.p9_timer;
+    }
+
+    if(grp.p10_timer != 0)
+    {
+        RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(10));
+        pGroup->timer[rtk_switch_port_P2L_get(10)] = grp.p10_timer;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_ReportLeaveFwdAction_set
+ * Description:
+ *      Set Report Leave packet forwarding action
+ * Input:
+ *      action      - Action
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error Input
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_igmp_ReportLeaveFwdAction_set(rtk_igmp_ReportLeaveFwdAct_t action)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32      regData;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    switch(action)
+    {
+        case IGMP_REPORT_LEAVE_TO_ROUTER:
+            regData = 1;
+            break;
+        case IGMP_REPORT_LEAVE_TO_ALLPORT:
+            regData = 2;
+            break;
+        case IGMP_REPORT_LEAVE_TO_ROUTER_PORT_ADV:
+            regData = 3;
+            break;
+        default:
+            return RT_ERR_INPUT;
+    }
+
+    if ((retVal = rtl8367c_setAsicIGMPReportLeaveFlood(regData))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_ReportLeaveFwdAction_get
+ * Description:
+ *      Get Report Leave packet forwarding action
+ * Input:
+ *      action      - Action
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_NULL_POINTER    - Null Pointer
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_igmp_ReportLeaveFwdAction_get(rtk_igmp_ReportLeaveFwdAct_t *pAction)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32      regData;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pAction)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicIGMPReportLeaveFlood(&regData))!=RT_ERR_OK)
+        return retVal;
+
+    switch(regData)
+    {
+        case 1:
+            *pAction = IGMP_REPORT_LEAVE_TO_ROUTER;
+            break;
+        case 2:
+            *pAction = IGMP_REPORT_LEAVE_TO_ALLPORT;
+            break;
+        case 3:
+            *pAction = IGMP_REPORT_LEAVE_TO_ROUTER_PORT_ADV;
+            break;
+        default:
+            return RT_ERR_FAILED;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_dropLeaveZeroEnable_set
+ * Description:
+ *      Set the function of droppping Leave packet with group IP = 0.0.0.0
+ * Input:
+ *      enabled      - Action 1: drop, 0:pass
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error Input
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_igmp_dropLeaveZeroEnable_set(rtk_enable_t enabled)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(enabled >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicIGMPDropLeaveZero(enabled))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+
+}
+
+/* Function Name:
+ *      rtk_igmp_dropLeaveZeroEnable_get
+ * Description:
+ *      Get the function of droppping Leave packet with group IP = 0.0.0.0
+ * Input:
+ *      None
+ * Output:
+ *      pEnabled.   - Action 1: drop, 0:pass
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_NULL_POINTER    - Null Pointer
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_igmp_dropLeaveZeroEnable_get(rtk_enable_t *pEnabled)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pEnabled)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicIGMPDropLeaveZero((rtk_uint32 *)pEnabled))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+
+}
+
+/* Function Name:
+ *      rtk_igmp_bypassGroupRange_set
+ * Description:
+ *      Set Bypass group
+ * Input:
+ *      group       - bypassed group
+ *      enabled     - enabled 1: Bypassed, 0: not bypass
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error Input
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_igmp_bypassGroupRange_set(rtk_igmp_bypassGroup_t group, rtk_enable_t enabled)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(group >= IGMP_BYPASS_GROUP_END)
+        return RT_ERR_INPUT;
+
+    if(enabled >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicIGMPBypassGroup(group, enabled))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_igmp_bypassGroupRange_get
+ * Description:
+ *      get Bypass group
+ * Input:
+ *      group       - bypassed group
+ * Output:
+ *      pEnable     - enabled 1: Bypassed, 0: not bypass
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_NULL_POINTER    - Null Pointer
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_igmp_bypassGroupRange_get(rtk_igmp_bypassGroup_t group, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(group >= IGMP_BYPASS_GROUP_END)
+        return RT_ERR_INPUT;
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicIGMPBypassGroup(group, pEnable))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/acl.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/acl.h
new file mode 100644
index 0000000..6308da8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/acl.h
@@ -0,0 +1,990 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes ACL module high-layer API defination
+ *
+ */
+
+#ifndef __RTK_API_ACL_H__
+#define __RTK_API_ACL_H__
+
+/*
+ * Data Type Declaration
+ */
+#define RTK_FILTER_RAW_FIELD_NUMBER                8
+
+#define ACL_DEFAULT_ABILITY                         0
+#define ACL_DEFAULT_UNMATCH_PERMIT                  1
+
+#define ACL_RULE_FREE                               0
+#define ACL_RULE_INAVAILABLE                        1
+#define ACL_RULE_CARETAG_MASK                       0x1F
+#define FILTER_POLICING_MAX                         4
+#define FILTER_LOGGING_MAX                          8
+#define FILTER_PATTERN_MAX                          4
+
+#define FILTER_ENACT_CVLAN_MASK         0x01
+#define FILTER_ENACT_SVLAN_MASK         0x02
+#define FILTER_ENACT_PRIORITY_MASK      0x04
+#define FILTER_ENACT_POLICING_MASK      0x08
+#define FILTER_ENACT_FWD_MASK           0x10
+#define FILTER_ENACT_INTGPIO_MASK       0x20
+#define FILTER_ENACT_INIT_MASK          0x3F
+
+typedef enum rtk_filter_act_cactext_e
+{
+    FILTER_ENACT_CACTEXT_VLANONLY=0,
+    FILTER_ENACT_CACTEXT_BOTHVLANTAG,
+    FILTER_ENACT_CACTEXT_TAGONLY,
+    FILTER_ENACT_CACTEXT_END,
+
+
+}rtk_filter_act_cactext_t;
+
+typedef enum rtk_filter_act_ctagfmt_e
+{
+    FILTER_CTAGFMT_UNTAG=0,
+    FILTER_CTAGFMT_TAG,
+    FILTER_CTAGFMT_KEEP,
+    FILTER_CTAGFMT_KEEP1PRMK,
+
+
+}rtk_filter_act_ctag_t;
+
+
+
+
+
+#define RTK_MAX_NUM_OF_FILTER_TYPE                  5
+#define RTK_MAX_NUM_OF_FILTER_FIELD                 8
+
+#define RTK_DOT_1AS_TIMESTAMP_UNIT_IN_WORD_LENGTH   3UL
+#define RTK_IPV6_ADDR_WORD_LENGTH                   4UL
+
+#define FILTER_ENACT_CVLAN_TYPE(type)   (type - FILTER_ENACT_CVLAN_INGRESS)
+#define FILTER_ENACT_SVLAN_TYPE(type)   (type - FILTER_ENACT_SVLAN_INGRESS)
+#define FILTER_ENACT_FWD_TYPE(type)     (type - FILTER_ENACT_ADD_DSTPORT)
+#define FILTER_ENACT_PRI_TYPE(type)     (type - FILTER_ENACT_PRIORITY)
+
+#define RTK_FILTER_FIELD_USED_MAX                   8
+#define RTK_FILTER_FIELD_INDEX(template, index)     ((template << 4) + index)
+
+
+typedef enum rtk_filter_act_enable_e
+{
+    /* CVLAN */
+    FILTER_ENACT_CVLAN_INGRESS = 0,
+    FILTER_ENACT_CVLAN_EGRESS,
+    FILTER_ENACT_CVLAN_SVID,
+    FILTER_ENACT_POLICING_1,
+
+    /* SVLAN */
+    FILTER_ENACT_SVLAN_INGRESS,
+    FILTER_ENACT_SVLAN_EGRESS,
+    FILTER_ENACT_SVLAN_CVID,
+    FILTER_ENACT_POLICING_2,
+
+    /* Policing and Logging */
+    FILTER_ENACT_POLICING_0,
+
+    /* Forward */
+    FILTER_ENACT_COPY_CPU,
+    FILTER_ENACT_DROP,
+    FILTER_ENACT_ADD_DSTPORT,
+    FILTER_ENACT_REDIRECT,
+    FILTER_ENACT_MIRROR,
+    FILTER_ENACT_TRAP_CPU,
+    FILTER_ENACT_ISOLATION,
+
+    /* QoS */
+    FILTER_ENACT_PRIORITY,
+    FILTER_ENACT_DSCP_REMARK,
+    FILTER_ENACT_1P_REMARK,
+    FILTER_ENACT_POLICING_3,
+
+    /* Interrutp and GPO */
+    FILTER_ENACT_INTERRUPT,
+    FILTER_ENACT_GPO,
+
+    /*VLAN tag*/
+    FILTER_ENACT_EGRESSCTAG_UNTAG,
+    FILTER_ENACT_EGRESSCTAG_TAG,
+    FILTER_ENACT_EGRESSCTAG_KEEP,
+    FILTER_ENACT_EGRESSCTAG_KEEPAND1PRMK,
+
+    FILTER_ENACT_END,
+} rtk_filter_act_enable_t;
+
+
+typedef struct
+{
+    rtk_filter_act_enable_t actEnable[FILTER_ENACT_END];
+
+    /* CVLAN acton */
+    rtk_uint32      filterCvlanVid;
+    rtk_uint32      filterCvlanIdx;
+    /* SVLAN action */
+    rtk_uint32      filterSvlanVid;
+    rtk_uint32      filterSvlanIdx;
+
+    /* Policing action */
+    rtk_uint32      filterPolicingIdx[FILTER_POLICING_MAX];
+
+    /* Forwarding action */
+    rtk_portmask_t  filterPortmask;
+
+    /* QOS action */
+    rtk_uint32      filterPriority;
+
+    /*GPO*/
+    rtk_uint32      filterPin;
+
+} rtk_filter_action_t;
+
+typedef struct rtk_filter_flag_s
+{
+    rtk_uint32 value;
+    rtk_uint32 mask;
+} rtk_filter_flag_t;
+
+typedef enum rtk_filter_care_tag_index_e
+{
+    CARE_TAG_CTAG = 0,
+    CARE_TAG_STAG,
+    CARE_TAG_PPPOE,
+    CARE_TAG_IPV4,
+    CARE_TAG_IPV6,
+    CARE_TAG_TCP,
+    CARE_TAG_UDP,
+    CARE_TAG_ARP,
+    CARE_TAG_RSV1,
+    CARE_TAG_RSV2,
+    CARE_TAG_ICMP,
+    CARE_TAG_IGMP,
+    CARE_TAG_LLC,
+    CARE_TAG_RSV3,
+    CARE_TAG_HTTP,
+    CARE_TAG_RSV4,
+    CARE_TAG_RSV5,
+    CARE_TAG_DHCP,
+    CARE_TAG_DHCPV6,
+    CARE_TAG_SNMP,
+    CARE_TAG_OAM,
+    CARE_TAG_END,
+} rtk_filter_care_tag_index_t;
+
+typedef struct rtk_filter_care_tag_s
+{
+    rtk_filter_flag_t tagType[CARE_TAG_END];
+} rtk_filter_care_tag_t;
+
+typedef struct rtk_filter_field rtk_filter_field_t;
+
+typedef struct
+{
+    rtk_uint32 value[RTK_DOT_1AS_TIMESTAMP_UNIT_IN_WORD_LENGTH];
+} rtk_filter_dot1as_timestamp_t;
+
+typedef enum rtk_filter_field_data_type_e
+{
+    FILTER_FIELD_DATA_MASK = 0,
+    FILTER_FIELD_DATA_RANGE,
+    FILTER_FIELD_DATA_END ,
+} rtk_filter_field_data_type_t;
+
+typedef struct rtk_filter_ip_s
+{
+    rtk_uint32 dataType;
+    rtk_uint32 rangeStart;
+    rtk_uint32 rangeEnd;
+    rtk_uint32 value;
+    rtk_uint32 mask;
+} rtk_filter_ip_t;
+
+typedef struct rtk_filter_mac_s
+{
+    rtk_uint32 dataType;
+    rtk_mac_t value;
+    rtk_mac_t mask;
+    rtk_mac_t rangeStart;
+    rtk_mac_t rangeEnd;
+} rtk_filter_mac_t;
+
+typedef rtk_uint32 rtk_filter_op_t;
+
+typedef struct rtk_filter_value_s
+{
+    rtk_uint32 dataType;
+    rtk_uint32 value;
+    rtk_uint32 mask;
+    rtk_uint32 rangeStart;
+    rtk_uint32 rangeEnd;
+
+} rtk_filter_value_t;
+
+typedef struct rtk_filter_activeport_s
+{
+    rtk_portmask_t value;
+    rtk_portmask_t mask;
+
+} rtk_filter_activeport_t;
+
+
+
+typedef struct rtk_filter_tag_s
+{
+    rtk_filter_value_t pri;
+    rtk_filter_flag_t cfi;
+    rtk_filter_value_t vid;
+} rtk_filter_tag_t;
+
+typedef struct rtk_filter_ipFlag_s
+{
+    rtk_filter_flag_t xf;
+    rtk_filter_flag_t mf;
+    rtk_filter_flag_t df;
+} rtk_filter_ipFlag_t;
+
+typedef struct
+{
+    rtk_uint32 addr[RTK_IPV6_ADDR_WORD_LENGTH];
+} rtk_filter_ip6_addr_t;
+
+typedef struct
+{
+    rtk_uint32 dataType;
+    rtk_filter_ip6_addr_t value;
+    rtk_filter_ip6_addr_t mask;
+    rtk_filter_ip6_addr_t rangeStart;
+    rtk_filter_ip6_addr_t rangeEnd;
+} rtk_filter_ip6_t;
+
+typedef rtk_uint32 rtk_filter_number_t;
+
+typedef struct rtk_filter_pattern_s
+{
+    rtk_uint32 value[FILTER_PATTERN_MAX];
+    rtk_uint32 mask[FILTER_PATTERN_MAX];
+} rtk_filter_pattern_t;
+
+typedef struct rtk_filter_tcpFlag_s
+{
+    rtk_filter_flag_t urg;
+    rtk_filter_flag_t ack;
+    rtk_filter_flag_t psh;
+    rtk_filter_flag_t rst;
+    rtk_filter_flag_t syn;
+    rtk_filter_flag_t fin;
+    rtk_filter_flag_t ns;
+    rtk_filter_flag_t cwr;
+    rtk_filter_flag_t ece;
+} rtk_filter_tcpFlag_t;
+
+typedef rtk_uint32 rtk_filter_field_raw_t;
+
+typedef enum rtk_filter_field_temple_input_e
+{
+    FILTER_FIELD_TEMPLE_INPUT_TYPE = 0,
+    FILTER_FIELD_TEMPLE_INPUT_INDEX,
+    FILTER_FIELD_TEMPLE_INPUT_MAX ,
+} rtk_filter_field_temple_input_t;
+
+struct rtk_filter_field
+{
+    rtk_uint32 fieldType;
+
+    union
+    {
+        /* L2 struct */
+        rtk_filter_mac_t       dmac;
+        rtk_filter_mac_t       smac;
+        rtk_filter_value_t     etherType;
+        rtk_filter_tag_t       ctag;
+        rtk_filter_tag_t       relayCtag;
+        rtk_filter_tag_t       stag;
+        rtk_filter_tag_t       l2tag;
+        rtk_filter_dot1as_timestamp_t dot1asTimeStamp;
+        rtk_filter_mac_t       mac;
+
+        /* L3 struct */
+        rtk_filter_ip_t      sip;
+        rtk_filter_ip_t      dip;
+        rtk_filter_ip_t      ip;
+        rtk_filter_value_t   protocol;
+        rtk_filter_value_t   ipTos;
+        rtk_filter_ipFlag_t  ipFlag;
+        rtk_filter_value_t   ipOffset;
+        rtk_filter_ip6_t     sipv6;
+        rtk_filter_ip6_t     dipv6;
+        rtk_filter_ip6_t     ipv6;
+        rtk_filter_value_t   ipv6TrafficClass;
+        rtk_filter_value_t   ipv6NextHeader;
+        rtk_filter_value_t   flowLabel;
+
+        /* L4 struct */
+        rtk_filter_value_t   tcpSrcPort;
+        rtk_filter_value_t   tcpDstPort;
+        rtk_filter_tcpFlag_t tcpFlag;
+        rtk_filter_value_t   tcpSeqNumber;
+        rtk_filter_value_t   tcpAckNumber;
+        rtk_filter_value_t   udpSrcPort;
+        rtk_filter_value_t   udpDstPort;
+        rtk_filter_value_t   icmpCode;
+        rtk_filter_value_t   icmpType;
+        rtk_filter_value_t   igmpType;
+
+        /* pattern match */
+        rtk_filter_pattern_t pattern;
+
+        rtk_filter_value_t   inData;
+
+    } filter_pattern_union;
+
+    rtk_uint32 fieldTemplateNo;
+    rtk_uint32 fieldTemplateIdx[RTK_FILTER_FIELD_USED_MAX];
+
+    struct rtk_filter_field *next;
+};
+
+typedef enum rtk_filter_field_type_e
+{
+    FILTER_FIELD_DMAC = 0,
+    FILTER_FIELD_SMAC,
+    FILTER_FIELD_ETHERTYPE,
+    FILTER_FIELD_CTAG,
+    FILTER_FIELD_STAG,
+
+    FILTER_FIELD_IPV4_SIP,
+    FILTER_FIELD_IPV4_DIP,
+    FILTER_FIELD_IPV4_TOS,
+    FILTER_FIELD_IPV4_PROTOCOL,
+    FILTER_FIELD_IPV4_FLAG,
+    FILTER_FIELD_IPV4_OFFSET,
+    FILTER_FIELD_IPV6_SIPV6,
+    FILTER_FIELD_IPV6_DIPV6,
+    FILTER_FIELD_IPV6_TRAFFIC_CLASS,
+    FILTER_FIELD_IPV6_NEXT_HEADER,
+
+    FILTER_FIELD_TCP_SPORT,
+    FILTER_FIELD_TCP_DPORT,
+    FILTER_FIELD_TCP_FLAG,
+    FILTER_FIELD_UDP_SPORT,
+    FILTER_FIELD_UDP_DPORT,
+    FILTER_FIELD_ICMP_CODE,
+    FILTER_FIELD_ICMP_TYPE,
+    FILTER_FIELD_IGMP_TYPE,
+
+    FILTER_FIELD_VID_RANGE,
+    FILTER_FIELD_IP_RANGE,
+    FILTER_FIELD_PORT_RANGE,
+
+    FILTER_FIELD_USER_DEFINED00,
+    FILTER_FIELD_USER_DEFINED01,
+    FILTER_FIELD_USER_DEFINED02,
+    FILTER_FIELD_USER_DEFINED03,
+    FILTER_FIELD_USER_DEFINED04,
+    FILTER_FIELD_USER_DEFINED05,
+    FILTER_FIELD_USER_DEFINED06,
+    FILTER_FIELD_USER_DEFINED07,
+    FILTER_FIELD_USER_DEFINED08,
+    FILTER_FIELD_USER_DEFINED09,
+    FILTER_FIELD_USER_DEFINED10,
+    FILTER_FIELD_USER_DEFINED11,
+    FILTER_FIELD_USER_DEFINED12,
+    FILTER_FIELD_USER_DEFINED13,
+    FILTER_FIELD_USER_DEFINED14,
+    FILTER_FIELD_USER_DEFINED15,
+
+    FILTER_FIELD_PATTERN_MATCH,
+
+    FILTER_FIELD_END,
+} rtk_filter_field_type_t;
+
+
+typedef enum rtk_filter_field_type_raw_e
+{
+    FILTER_FIELD_RAW_UNUSED = 0,
+    FILTER_FIELD_RAW_DMAC_15_0,
+    FILTER_FIELD_RAW_DMAC_31_16,
+    FILTER_FIELD_RAW_DMAC_47_32,
+    FILTER_FIELD_RAW_SMAC_15_0,
+    FILTER_FIELD_RAW_SMAC_31_16,
+    FILTER_FIELD_RAW_SMAC_47_32,
+    FILTER_FIELD_RAW_ETHERTYPE,
+    FILTER_FIELD_RAW_STAG,
+    FILTER_FIELD_RAW_CTAG,
+
+    FILTER_FIELD_RAW_IPV4_SIP_15_0 = 0x10,
+    FILTER_FIELD_RAW_IPV4_SIP_31_16,
+    FILTER_FIELD_RAW_IPV4_DIP_15_0,
+    FILTER_FIELD_RAW_IPV4_DIP_31_16,
+
+
+    FILTER_FIELD_RAW_IPV6_SIP_15_0 = 0x20,
+    FILTER_FIELD_RAW_IPV6_SIP_31_16,
+    FILTER_FIELD_RAW_IPV6_DIP_15_0 = 0x28,
+    FILTER_FIELD_RAW_IPV6_DIP_31_16,
+
+    FILTER_FIELD_RAW_VIDRANGE = 0x30,
+    FILTER_FIELD_RAW_IPRANGE,
+    FILTER_FIELD_RAW_PORTRANGE,
+    FILTER_FIELD_RAW_FIELD_VALID,
+
+    FILTER_FIELD_RAW_FIELD_SELECT00 = 0x40,
+    FILTER_FIELD_RAW_FIELD_SELECT01,
+    FILTER_FIELD_RAW_FIELD_SELECT02,
+    FILTER_FIELD_RAW_FIELD_SELECT03,
+    FILTER_FIELD_RAW_FIELD_SELECT04,
+    FILTER_FIELD_RAW_FIELD_SELECT05,
+    FILTER_FIELD_RAW_FIELD_SELECT06,
+    FILTER_FIELD_RAW_FIELD_SELECT07,
+    FILTER_FIELD_RAW_FIELD_SELECT08,
+    FILTER_FIELD_RAW_FIELD_SELECT09,
+    FILTER_FIELD_RAW_FIELD_SELECT10,
+    FILTER_FIELD_RAW_FIELD_SELECT11,
+    FILTER_FIELD_RAW_FIELD_SELECT12,
+    FILTER_FIELD_RAW_FIELD_SELECT13,
+    FILTER_FIELD_RAW_FIELD_SELECT14,
+    FILTER_FIELD_RAW_FIELD_SELECT15,
+
+    FILTER_FIELD_RAW_END,
+} rtk_filter_field_type_raw_t;
+
+typedef enum rtk_filter_flag_care_type_e
+{
+    FILTER_FLAG_CARE_DONT_CARE = 0,
+    FILTER_FLAG_CARE_1,
+    FILTER_FLAG_CARE_0,
+    FILTER_FLAG_END
+} rtk_filter_flag_care_type_t;
+
+typedef rtk_uint32  rtk_filter_id_t;    /* filter id type */
+
+typedef enum rtk_filter_invert_e
+{
+    FILTER_INVERT_DISABLE = 0,
+    FILTER_INVERT_ENABLE,
+    FILTER_INVERT_END,
+} rtk_filter_invert_t;
+
+typedef rtk_uint32 rtk_filter_state_t;
+
+typedef rtk_uint32 rtk_filter_unmatch_action_t;
+
+typedef enum rtk_filter_unmatch_action_e
+{
+    FILTER_UNMATCH_DROP = 0,
+    FILTER_UNMATCH_PERMIT,
+    FILTER_UNMATCH_END,
+} rtk_filter_unmatch_action_type_t;
+
+typedef struct
+{
+    rtk_filter_field_t      *fieldHead;
+    rtk_filter_care_tag_t   careTag;
+    rtk_filter_activeport_t activeport;
+
+    rtk_filter_invert_t     invert;
+} rtk_filter_cfg_t;
+
+typedef struct
+{
+    rtk_filter_field_raw_t      dataFieldRaw[RTK_FILTER_RAW_FIELD_NUMBER];
+    rtk_filter_field_raw_t      careFieldRaw[RTK_FILTER_RAW_FIELD_NUMBER];
+    rtk_filter_field_type_raw_t fieldRawType[RTK_FILTER_RAW_FIELD_NUMBER];
+    rtk_filter_care_tag_t       careTag;
+    rtk_filter_activeport_t     activeport;
+
+    rtk_filter_invert_t         invert;
+    rtk_enable_t                valid;
+} rtk_filter_cfg_raw_t;
+
+typedef struct
+{
+    rtk_uint32 index;
+    rtk_filter_field_type_raw_t fieldType[RTK_FILTER_RAW_FIELD_NUMBER];
+} rtk_filter_template_t;
+
+typedef enum rtk_field_sel_e
+{
+    FORMAT_DEFAULT = 0,
+    FORMAT_RAW,
+    FORMAT_LLC,
+    FORMAT_IPV4,
+    FORMAT_ARP,
+    FORMAT_IPV6,
+    FORMAT_IPPAYLOAD,
+    FORMAT_L4PAYLOAD,
+    FORMAT_END
+}rtk_field_sel_t;
+
+typedef enum rtk_filter_iprange_e
+{
+    IPRANGE_UNUSED = 0,
+    IPRANGE_IPV4_SIP,
+    IPRANGE_IPV4_DIP,
+    IPRANGE_IPV6_SIP,
+    IPRANGE_IPV6_DIP,
+    IPRANGE_END
+}rtk_filter_iprange_t;
+
+typedef enum rtk_filter_vidrange_e
+{
+    VIDRANGE_UNUSED = 0,
+    VIDRANGE_CVID,
+    VIDRANGE_SVID,
+    VIDRANGE_END
+}rtk_filter_vidrange_t;
+
+typedef enum rtk_filter_portrange_e
+{
+    PORTRANGE_UNUSED = 0,
+    PORTRANGE_SPORT,
+    PORTRANGE_DPORT,
+    PORTRANGE_END
+}rtk_filter_portrange_t;
+
+/* Function Name:
+ *      rtk_filter_igrAcl_init
+ * Description:
+ *      ACL initialization function
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_NULL_POINTER - Pointer pFilter_field or pFilter_cfg point to NULL.
+ * Note:
+ *      This function enable and intialize ACL function
+ */
+extern rtk_api_ret_t rtk_filter_igrAcl_init(void);
+
+/* Function Name:
+ *      rtk_filter_igrAcl_field_add
+ * Description:
+ *      Add comparison rule to an ACL configuration
+ * Input:
+ *      pFilter_cfg     - The ACL configuration that this function will add comparison rule
+ *      pFilter_field   - The comparison rule that will be added.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_NULL_POINTER     - Pointer pFilter_field or pFilter_cfg point to NULL.
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ * Note:
+ *      This function add a comparison rule (*pFilter_field) to an ACL configuration (*pFilter_cfg).
+ *      Pointer pFilter_cfg points to an ACL configuration structure, this structure keeps multiple ACL
+ *      comparison rules by means of linked list. Pointer pFilter_field will be added to linked
+ *      list keeped by structure that pFilter_cfg points to.
+ */
+extern rtk_api_ret_t rtk_filter_igrAcl_field_add(rtk_filter_cfg_t *pFilter_cfg, rtk_filter_field_t *pFilter_field);
+
+/* Function Name:
+ *      rtk_filter_igrAcl_cfg_add
+ * Description:
+ *      Add an ACL configuration to ASIC
+ * Input:
+ *      filter_id       - Start index of ACL configuration.
+ *      pFilter_cfg     - The ACL configuration that this function will add comparison rule
+ *      pFilter_action  - Action(s) of ACL configuration.
+ * Output:
+ *      ruleNum - number of rules written in acl table
+ * Return:
+ *      RT_ERR_OK                               - OK
+ *      RT_ERR_FAILED                           - Failed
+ *      RT_ERR_SMI                              - SMI access error
+ *      RT_ERR_NULL_POINTER                     - Pointer pFilter_field or pFilter_cfg point to NULL.
+ *      RT_ERR_INPUT                            - Invalid input parameters.
+ *      RT_ERR_ENTRY_INDEX                      - Invalid filter_id .
+ *      RT_ERR_NULL_POINTER                     - Pointer pFilter_action or pFilter_cfg point to NULL.
+ *      RT_ERR_FILTER_INACL_ACT_NOT_SUPPORT     - Action is not supported in this chip.
+ *      RT_ERR_FILTER_INACL_RULE_NOT_SUPPORT    - Rule is not supported.
+ * Note:
+ *      This function store pFilter_cfg, pFilter_action into ASIC. The starting
+ *      index(es) is filter_id.
+ */
+extern rtk_api_ret_t rtk_filter_igrAcl_cfg_add(rtk_filter_id_t filter_id, rtk_filter_cfg_t *pFilter_cfg, rtk_filter_action_t *pAction, rtk_filter_number_t *ruleNum);
+
+/* Function Name:
+ *      rtk_filter_igrAcl_cfg_del
+ * Description:
+ *      Delete an ACL configuration from ASIC
+ * Input:
+ *      filter_id   - Start index of ACL configuration.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_ENTRYIDX  - Invalid filter_id.
+ * Note:
+ *      This function delete a group of ACL rules starting from filter_id.
+ */
+extern rtk_api_ret_t rtk_filter_igrAcl_cfg_del(rtk_filter_id_t filter_id);
+
+/* Function Name:
+ *      rtk_filter_igrAcl_cfg_delAll
+ * Description:
+ *      Delete all ACL entries from ASIC
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      This function delete all ACL configuration from ASIC.
+ */
+extern rtk_api_ret_t rtk_filter_igrAcl_cfg_delAll(void);
+
+/* Function Name:
+ *      rtk_filter_igrAcl_cfg_get
+ * Description:
+ *      Get one ingress acl configuration from ASIC.
+ * Input:
+ *      filter_id       - Start index of ACL configuration.
+ * Output:
+ *      pFilter_cfg     - buffer pointer of ingress acl data
+ *      pFilter_action  - buffer pointer of ingress acl action
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_NULL_POINTER     - Pointer pFilter_action or pFilter_cfg point to NULL.
+ *      RT_ERR_FILTER_ENTRYIDX  - Invalid entry index.
+ * Note:
+ *      This function delete all ACL configuration from ASIC.
+ */
+extern rtk_api_ret_t rtk_filter_igrAcl_cfg_get(rtk_filter_id_t filter_id, rtk_filter_cfg_raw_t *pFilter_cfg, rtk_filter_action_t *pAction);
+
+/* Function Name:
+ *      rtk_filter_igrAcl_unmatchAction_set
+ * Description:
+ *      Set action to packets when no ACL configuration match
+ * Input:
+ *      port    - Port id.
+ *      action  - Action.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port id.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This function sets action of packets when no ACL configruation matches.
+ */
+extern rtk_api_ret_t rtk_filter_igrAcl_unmatchAction_set(rtk_port_t port, rtk_filter_unmatch_action_t action);
+
+/* Function Name:
+ *      rtk_filter_igrAcl_unmatchAction_get
+ * Description:
+ *      Get action to packets when no ACL configuration match
+ * Input:
+ *      port    - Port id.
+ * Output:
+ *      pAction - Action.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port id.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This function gets action of packets when no ACL configruation matches.
+ */
+extern rtk_api_ret_t rtk_filter_igrAcl_unmatchAction_get(rtk_port_t port, rtk_filter_unmatch_action_t* action);
+
+/* Function Name:
+ *      rtk_filter_igrAcl_state_set
+ * Description:
+ *      Set state of ingress ACL.
+ * Input:
+ *      port    - Port id.
+ *      state   - Ingress ACL state.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port id.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This function gets action of packets when no ACL configruation matches.
+ */
+extern rtk_api_ret_t rtk_filter_igrAcl_state_set(rtk_port_t port, rtk_filter_state_t state);
+
+/* Function Name:
+ *      rtk_filter_igrAcl_state_get
+ * Description:
+ *      Get state of ingress ACL.
+ * Input:
+ *      port    - Port id.
+ * Output:
+ *      pState  - Ingress ACL state.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port id.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This function gets action of packets when no ACL configruation matches.
+ */
+extern rtk_api_ret_t rtk_filter_igrAcl_state_get(rtk_port_t port, rtk_filter_state_t* state);
+
+/* Function Name:
+ *      rtk_filter_igrAcl_template_set
+ * Description:
+ *      Set template of ingress ACL.
+ * Input:
+ *      template - Ingress ACL template
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Invalid input parameters.
+ * Note:
+ *      This function set ACL template.
+ */
+extern rtk_api_ret_t rtk_filter_igrAcl_template_set(rtk_filter_template_t *aclTemplate);
+
+/* Function Name:
+ *      rtk_filter_igrAcl_template_get
+ * Description:
+ *      Get template of ingress ACL.
+ * Input:
+ *      template - Ingress ACL template
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      This function gets template of ACL.
+ */
+extern rtk_api_ret_t rtk_filter_igrAcl_template_get(rtk_filter_template_t *aclTemplate);
+
+/* Function Name:
+ *      rtk_filter_igrAcl_field_sel_set
+ * Description:
+ *      Set user defined field selectors in HSB
+ * Input:
+ *      index       - index of field selector 0-15
+ *      format      - Format of field selector
+ *      offset      - Retrieving data offset
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      System support 16 user defined field selctors.
+ *      Each selector can be enabled or disable.
+ *      User can defined retrieving 16-bits in many predefiend
+ *      standard l2/l3/l4 payload.
+ */
+extern rtk_api_ret_t rtk_filter_igrAcl_field_sel_set(rtk_uint32 index, rtk_field_sel_t format, rtk_uint32 offset);
+
+/* Function Name:
+ *      rtk_filter_igrAcl_field_sel_get
+ * Description:
+ *      Get user defined field selectors in HSB
+ * Input:
+ *      index       - index of field selector 0-15
+ * Output:
+ *      pFormat     - Format of field selector
+ *      pOffset     - Retrieving data offset
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      None.
+ */
+extern rtk_api_ret_t rtk_filter_igrAcl_field_sel_get(rtk_uint32 index, rtk_field_sel_t *pFormat, rtk_uint32 *pOffset);
+
+/* Function Name:
+ *      rtk_filter_iprange_set
+ * Description:
+ *      Set IP Range check
+ * Input:
+ *      index       - index of IP Range 0-15
+ *      type        - IP Range check type, 0:Delete a entry, 1: IPv4_SIP, 2: IPv4_DIP, 3:IPv6_SIP, 4:IPv6_DIP
+ *      upperIp     - The upper bound of IP range
+ *      lowerIp     - The lower Bound of IP range
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_OUT_OF_RANGE    - The parameter is out of range
+ *      RT_ERR_INPUT           - Input error
+ * Note:
+ *      upperIp must be larger or equal than lowerIp.
+ */
+extern rtk_api_ret_t rtk_filter_iprange_set(rtk_uint32 index, rtk_filter_iprange_t type, ipaddr_t upperIp, ipaddr_t lowerIp);
+
+/* Function Name:
+ *      rtk_filter_iprange_get
+ * Description:
+ *      Set IP Range check
+ * Input:
+ *      index       - index of IP Range 0-15
+ * Output:
+ *      pType        - IP Range check type, 0:Delete a entry, 1: IPv4_SIP, 2: IPv4_DIP, 3:IPv6_SIP, 4:IPv6_DIP
+ *      pUpperIp     - The upper bound of IP range
+ *      pLowerIp     - The lower Bound of IP range
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_OUT_OF_RANGE    - The parameter is out of range
+ * Note:
+ *      upperIp must be larger or equal than lowerIp.
+ */
+extern rtk_api_ret_t rtk_filter_iprange_get(rtk_uint32 index, rtk_filter_iprange_t *pType, ipaddr_t *pUpperIp, ipaddr_t *pLowerIp);
+
+/* Function Name:
+ *      rtk_filter_vidrange_set
+ * Description:
+ *      Set VID Range check
+ * Input:
+ *      index       - index of VID Range 0-15
+ *      type        - IP Range check type, 0:Delete a entry, 1: CVID, 2: SVID
+ *      upperVid    - The upper bound of VID range
+ *      lowerVid    - The lower Bound of VID range
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_OUT_OF_RANGE    - The parameter is out of range
+ *      RT_ERR_INPUT           - Input error
+ * Note:
+ *      upperVid must be larger or equal than lowerVid.
+ */
+extern rtk_api_ret_t rtk_filter_vidrange_set(rtk_uint32 index, rtk_filter_vidrange_t type, rtk_uint32 upperVid, rtk_uint32 lowerVid);
+
+/* Function Name:
+ *      rtk_filter_vidrange_get
+ * Description:
+ *      Get VID Range check
+ * Input:
+ *      index       - index of VID Range 0-15
+ * Output:
+ *      pType        - IP Range check type, 0:Unused, 1: CVID, 2: SVID
+ *      pUpperVid    - The upper bound of VID range
+ *      pLowerVid    - The lower Bound of VID range
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_OUT_OF_RANGE    - The parameter is out of range
+ * Note:
+ *      None.
+ */
+extern rtk_api_ret_t rtk_filter_vidrange_get(rtk_uint32 index, rtk_filter_vidrange_t *pType, rtk_uint32 *pUpperVid, rtk_uint32 *pLowerVid);
+
+/* Function Name:
+ *      rtk_filter_portrange_set
+ * Description:
+ *      Set Port Range check
+ * Input:
+ *      index       - index of Port Range 0-15
+ *      type        - IP Range check type, 0:Delete a entry, 1: Source Port, 2: Destnation Port
+ *      upperPort   - The upper bound of Port range
+ *      lowerPort   - The lower Bound of Port range
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_OUT_OF_RANGE    - The parameter is out of range
+ *      RT_ERR_INPUT           - Input error
+ * Note:
+ *      upperPort must be larger or equal than lowerPort.
+ */
+extern rtk_api_ret_t rtk_filter_portrange_set(rtk_uint32 index, rtk_filter_portrange_t type, rtk_uint32 upperPort, rtk_uint32 lowerPort);
+
+/* Function Name:
+ *      rtk_filter_portrange_get
+ * Description:
+ *      Set Port Range check
+ * Input:
+ *      index       - index of Port Range 0-15
+ * Output:
+ *      pType       - IP Range check type, 0:Delete a entry, 1: Source Port, 2: Destnation Port
+ *      pUpperPort  - The upper bound of Port range
+ *      pLowerPort  - The lower Bound of Port range
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_OUT_OF_RANGE    - The parameter is out of range
+ *      RT_ERR_INPUT           - Input error
+ * Note:
+ *      None.
+ */
+extern rtk_api_ret_t rtk_filter_portrange_get(rtk_uint32 index, rtk_filter_portrange_t *pType, rtk_uint32 *pUpperPort, rtk_uint32 *pLowerPort);
+
+/* Function Name:
+ *      rtk_filter_igrAclPolarity_set
+ * Description:
+ *      Set ACL Goip control palarity
+ * Input:
+ *      polarity - 1: High, 0: Low
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      none
+ */
+extern rtk_api_ret_t rtk_filter_igrAclPolarity_set(rtk_uint32 polarity);
+
+/* Function Name:
+ *      rtk_filter_igrAclPolarity_get
+ * Description:
+ *      Get ACL Goip control palarity
+ * Input:
+ *      pPolarity - 1: High, 0: Low
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      none
+ */
+extern rtk_api_ret_t rtk_filter_igrAclPolarity_get(rtk_uint32* pPolarity);
+
+
+#endif /* __RTK_API_ACL_H__ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/cpu.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/cpu.h
new file mode 100644
index 0000000..5544aca
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/cpu.h
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes CPU module high-layer API defination
+ *
+ */
+
+#ifndef __RTK_API_CPU_H__
+#define __RTK_API_CPU_H__
+
+
+/*
+ * Data Type Declaration
+ */
+typedef enum rtk_cpu_insert_e
+{
+    CPU_INSERT_TO_ALL = 0,
+    CPU_INSERT_TO_TRAPPING,
+    CPU_INSERT_TO_NONE,
+    CPU_INSERT_END
+}rtk_cpu_insert_t;
+
+typedef enum rtk_cpu_position_e
+{
+    CPU_POS_AFTER_SA = 0,
+    CPU_POS_BEFORE_CRC,
+    CPU_POS_END
+}rtk_cpu_position_t;
+
+typedef enum rtk_cpu_tag_length_e
+{
+    CPU_LEN_8BYTES = 0,
+    CPU_LEN_4BYTES,
+    CPU_LEN_END
+}rtk_cpu_tag_length_t;
+
+
+typedef enum rtk_cpu_rx_length_e
+{
+    CPU_RX_72BYTES = 0,
+    CPU_RX_64BYTES,
+    CPU_RX_END
+}rtk_cpu_rx_length_t;
+
+
+/* Function Name:
+ *      rtk_cpu_enable_set
+ * Description:
+ *      Set CPU port function enable/disable.
+ * Input:
+ *      enable - CPU port function enable
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can set CPU port function enable/disable.
+ */
+extern rtk_api_ret_t rtk_cpu_enable_set(rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_cpu_enable_get
+ * Description:
+ *      Get CPU port and its setting.
+ * Input:
+ *      None
+ * Output:
+ *      pEnable - CPU port function enable
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_L2_NO_CPU_PORT   - CPU port is not exist
+ * Note:
+ *      The API can get CPU port function enable/disable.
+ */
+extern rtk_api_ret_t rtk_cpu_enable_get(rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_cpu_tagPort_set
+ * Description:
+ *      Set CPU port and CPU tag insert mode.
+ * Input:
+ *      port - Port id.
+ *      mode - CPU tag insert for packets egress from CPU port.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can set CPU port and inserting proprietary CPU tag mode (Length/Type 0x8899)
+ *      to the frame that transmitting to CPU port.
+ *      The inset cpu tag mode is as following:
+ *      - CPU_INSERT_TO_ALL
+ *      - CPU_INSERT_TO_TRAPPING
+ *      - CPU_INSERT_TO_NONE
+ */
+extern rtk_api_ret_t rtk_cpu_tagPort_set(rtk_port_t port, rtk_cpu_insert_t mode);
+
+/* Function Name:
+ *      rtk_cpu_tagPort_get
+ * Description:
+ *      Get CPU port and CPU tag insert mode.
+ * Input:
+ *      None
+ * Output:
+ *      pPort - Port id.
+ *      pMode - CPU tag insert for packets egress from CPU port, 0:all insert 1:Only for trapped packets 2:no insert.
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_L2_NO_CPU_PORT   - CPU port is not exist
+ * Note:
+ *      The API can get configured CPU port and its setting.
+ *      The inset cpu tag mode is as following:
+ *      - CPU_INSERT_TO_ALL
+ *      - CPU_INSERT_TO_TRAPPING
+ *      - CPU_INSERT_TO_NONE
+ */
+extern rtk_api_ret_t rtk_cpu_tagPort_get(rtk_port_t *pPort, rtk_cpu_insert_t *pMode);
+
+/* Function Name:
+ *      rtk_cpu_awarePort_set
+ * Description:
+ *      Set CPU aware port mask.
+ * Input:
+ *      portmask - Port mask.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK      - Invalid port mask.
+ * Note:
+ *      The API can set configured CPU aware port mask.
+ */
+extern rtk_api_ret_t rtk_cpu_awarePort_set(rtk_portmask_t *pPortmask);
+
+
+/* Function Name:
+ *      rtk_cpu_awarePort_get
+ * Description:
+ *      Get CPU aware port mask.
+ * Input:
+ *      None
+ * Output:
+ *      pPortmask - Port mask.
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ * Note:
+ *      The API can get configured CPU aware port mask.
+ */
+extern rtk_api_ret_t rtk_cpu_awarePort_get(rtk_portmask_t *pPortmask);
+
+/* Function Name:
+ *      rtk_cpu_tagPosition_set
+ * Description:
+ *      Set CPU tag position.
+ * Input:
+ *      position - CPU tag position.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT      - Invalid input.
+ * Note:
+ *      The API can set CPU tag position.
+ */
+extern rtk_api_ret_t rtk_cpu_tagPosition_set(rtk_cpu_position_t position);
+
+/* Function Name:
+ *      rtk_cpu_tagPosition_get
+ * Description:
+ *      Get CPU tag position.
+ * Input:
+ *      None
+ * Output:
+ *      pPosition - CPU tag position.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT      - Invalid input.
+ * Note:
+ *      The API can get CPU tag position.
+ */
+extern rtk_api_ret_t rtk_cpu_tagPosition_get(rtk_cpu_position_t *pPosition);
+
+/* Function Name:
+ *      rtk_cpu_tagLength_set
+ * Description:
+ *      Set CPU tag length.
+ * Input:
+ *      length - CPU tag length.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT      - Invalid input.
+ * Note:
+ *      The API can set CPU tag length.
+ */
+extern rtk_api_ret_t rtk_cpu_tagLength_set(rtk_cpu_tag_length_t length);
+
+/* Function Name:
+ *      rtk_cpu_tagLength_get
+ * Description:
+ *      Get CPU tag length.
+ * Input:
+ *      None
+ * Output:
+ *      pLength - CPU tag length.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT      - Invalid input.
+ * Note:
+ *      The API can get CPU tag length.
+ */
+extern rtk_api_ret_t rtk_cpu_tagLength_get(rtk_cpu_tag_length_t *pLength);
+
+/* Function Name:
+ *      rtk_cpu_acceptLength_set
+ * Description:
+ *      Set CPU accept  length.
+ * Input:
+ *      length - CPU tag length.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT      - Invalid input.
+ * Note:
+ *      The API can set CPU accept length.
+ */
+extern rtk_api_ret_t rtk_cpu_acceptLength_set(rtk_cpu_rx_length_t length);
+
+/* Function Name:
+ *      rtk_cpu_acceptLength_get
+ * Description:
+ *      Get CPU accept length.
+ * Input:
+ *      None
+ * Output:
+ *      pLength - CPU tag length.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT      - Invalid input.
+ * Note:
+ *      The API can get CPU accept length.
+ */
+extern rtk_api_ret_t rtk_cpu_acceptLength_get(rtk_cpu_rx_length_t *pLength);
+
+/* Function Name:
+ *      rtk_cpu_priRemap_set
+ * Description:
+ *      Configure CPU priorities mapping to internal absolute priority.
+ * Input:
+ *      int_pri     - internal priority value.
+ *      new_pri    - new internal priority value.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_VLAN_PRIORITY    - Invalid 1p priority.
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ * Note:
+ *      Priority of CPU tag assignment for internal asic priority, and it is used for queue usage and packet scheduling.
+ */
+extern rtk_api_ret_t rtk_cpu_priRemap_set(rtk_pri_t int_pri, rtk_pri_t new_pri);
+
+/* Function Name:
+ *      rtk_cpu_priRemap_get
+ * Description:
+ *      Configure CPU priorities mapping to internal absolute priority.
+ * Input:
+ *      int_pri     - internal priority value.
+ * Output:
+ *      pNew_pri    - new internal priority value.
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_VLAN_PRIORITY    - Invalid 1p priority.
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ * Note:
+ *      Priority of CPU tag assignment for internal asic priority, and it is used for queue usage and packet scheduling.
+ */
+extern rtk_api_ret_t rtk_cpu_priRemap_get(rtk_pri_t int_pri, rtk_pri_t *pNew_pri);
+
+
+#endif /* __RTK_API_CPU_H__ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/dot1x.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/dot1x.h
new file mode 100644
index 0000000..ef0a05a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/dot1x.h
@@ -0,0 +1,470 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes 1X module high-layer API defination
+ *
+ */
+
+#ifndef __RTK_API_DOT1X_H__
+#define __RTK_API_DOT1X_H__
+
+
+/* Type of port-based dot1x auth/unauth*/
+typedef enum rtk_dot1x_auth_status_e
+{
+    UNAUTH = 0,
+    AUTH,
+    AUTH_STATUS_END
+} rtk_dot1x_auth_status_t;
+
+typedef enum rtk_dot1x_direction_e
+{
+    DIR_BOTH = 0,
+    DIR_IN,
+    DIRECTION_END
+} rtk_dot1x_direction_t;
+
+/* unauth pkt action */
+typedef enum rtk_dot1x_unauth_action_e
+{
+    DOT1X_ACTION_DROP = 0,
+    DOT1X_ACTION_TRAP2CPU,
+    DOT1X_ACTION_GUESTVLAN,
+    DOT1X_ACTION_END
+} rtk_dot1x_unauth_action_t;
+
+/* Function Name:
+ *      rtk_dot1x_unauthPacketOper_set
+ * Description:
+ *      Set 802.1x unauth action configuration.
+ * Input:
+ *      port            - Port id.
+ *      unauth_action   - 802.1X unauth action.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ * Note:
+ *      This API can set 802.1x unauth action configuration.
+ *      The unauth action is as following:
+ *      - DOT1X_ACTION_DROP
+ *      - DOT1X_ACTION_TRAP2CPU
+ *      - DOT1X_ACTION_GUESTVLAN
+ */
+extern rtk_api_ret_t rtk_dot1x_unauthPacketOper_set(rtk_port_t port, rtk_dot1x_unauth_action_t unauth_action);
+
+/* Function Name:
+ *      rtk_dot1x_unauthPacketOper_get
+ * Description:
+ *      Get 802.1x unauth action configuration.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pUnauth_action - 802.1X unauth action.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API can get 802.1x unauth action configuration.
+ *      The unauth action is as following:
+ *      - DOT1X_ACTION_DROP
+ *      - DOT1X_ACTION_TRAP2CPU
+ *      - DOT1X_ACTION_GUESTVLAN
+ */
+extern rtk_api_ret_t rtk_dot1x_unauthPacketOper_get(rtk_port_t port, rtk_dot1x_unauth_action_t *pUnauth_action);
+
+/* Function Name:
+ *      rtk_dot1x_eapolFrame2CpuEnable_set
+ * Description:
+ *      Set 802.1x EAPOL packet trap to CPU configuration
+ * Input:
+ *      enable - The status of 802.1x EAPOL packet.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_ENABLE       - Invalid enable input.
+ * Note:
+ *      To support 802.1x authentication functionality, EAPOL frame (ether type = 0x888E) has to
+ *      be trapped to CPU.
+ *      The status of EAPOL frame trap to CPU is as following:
+ *      - DISABLED
+ *      - ENABLED
+ */
+extern rtk_api_ret_t rtk_dot1x_eapolFrame2CpuEnable_set(rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_dot1x_eapolFrame2CpuEnable_get
+ * Description:
+ *      Get 802.1x EAPOL packet trap to CPU configuration
+ * Input:
+ *      None
+ * Output:
+ *      pEnable - The status of 802.1x EAPOL packet.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      To support 802.1x authentication functionality, EAPOL frame (ether type = 0x888E) has to
+ *      be trapped to CPU.
+ *      The status of EAPOL frame trap to CPU is as following:
+ *      - DISABLED
+ *      - ENABLED
+ */
+extern rtk_api_ret_t rtk_dot1x_eapolFrame2CpuEnable_get(rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_dot1x_portBasedEnable_set
+ * Description:
+ *      Set 802.1x port-based enable configuration
+ * Input:
+ *      port - Port id.
+ *      enable - The status of 802.1x port.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number.
+ *      RT_ERR_ENABLE               - Invalid enable input.
+ *      RT_ERR_DOT1X_PORTBASEDPNEN  - 802.1X port-based enable error
+ * Note:
+ *      The API can update the port-based port enable register content. If a port is 802.1x
+ *      port based network access control "enabled", it should be authenticated so packets
+ *      from that port won't be dropped or trapped to CPU.
+ *      The status of 802.1x port-based network access control is as following:
+ *      - DISABLED
+ *      - ENABLED
+ */
+extern rtk_api_ret_t rtk_dot1x_portBasedEnable_set(rtk_port_t port, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_dot1x_portBasedEnable_get
+ * Description:
+ *      Get 802.1x port-based enable configuration
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEnable - The status of 802.1x port.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get the 802.1x port-based port status.
+ */
+extern rtk_api_ret_t rtk_dot1x_portBasedEnable_get(rtk_port_t port, rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_dot1x_portBasedAuthStatus_set
+ * Description:
+ *      Set 802.1x port-based auth. port configuration
+ * Input:
+ *      port - Port id.
+ *      port_auth - The status of 802.1x port.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number.
+ *     RT_ERR_DOT1X_PORTBASEDAUTH   - 802.1X port-based auth error
+ * Note:
+ *      The authenticated status of 802.1x port-based network access control is as following:
+ *      - UNAUTH
+ *      - AUTH
+ */
+extern rtk_api_ret_t rtk_dot1x_portBasedAuthStatus_set(rtk_port_t port, rtk_dot1x_auth_status_t port_auth);
+
+/* Function Name:
+ *      rtk_dot1x_portBasedAuthStatus_get
+ * Description:
+ *      Get 802.1x port-based auth. port configuration
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pPort_auth - The status of 802.1x port.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get 802.1x port-based port auth.information.
+ */
+extern rtk_api_ret_t rtk_dot1x_portBasedAuthStatus_get(rtk_port_t port, rtk_dot1x_auth_status_t *pPort_auth);
+
+/* Function Name:
+ *      rtk_dot1x_portBasedDirection_set
+ * Description:
+ *      Set 802.1x port-based operational direction configuration
+ * Input:
+ *      port            - Port id.
+ *      port_direction  - Operation direction
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number.
+ *      RT_ERR_DOT1X_PORTBASEDOPDIR - 802.1X port-based operation direction error
+ * Note:
+ *      The operate controlled direction of 802.1x port-based network access control is as following:
+ *      - BOTH
+ *      - IN
+ */
+extern rtk_api_ret_t rtk_dot1x_portBasedDirection_set(rtk_port_t port, rtk_dot1x_direction_t port_direction);
+
+/* Function Name:
+ *      rtk_dot1x_portBasedDirection_get
+ * Description:
+ *      Get 802.1X port-based operational direction configuration
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pPort_direction - Operation direction
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get 802.1x port-based operational direction information.
+ */
+extern rtk_api_ret_t rtk_dot1x_portBasedDirection_get(rtk_port_t port, rtk_dot1x_direction_t *pPort_direction);
+
+/* Function Name:
+ *      rtk_dot1x_macBasedEnable_set
+ * Description:
+ *      Set 802.1x mac-based port enable configuration
+ * Input:
+ *      port - Port id.
+ *      enable - The status of 802.1x port.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number.
+ *      RT_ERR_ENABLE               - Invalid enable input.
+ *      RT_ERR_DOT1X_MACBASEDPNEN   - 802.1X mac-based enable error
+ * Note:
+ *      If a port is 802.1x MAC based network access control "enabled", the incoming packets should
+ *       be authenticated so packets from that port won't be dropped or trapped to CPU.
+ *      The status of 802.1x MAC-based network access control is as following:
+ *      - DISABLED
+ *      - ENABLED
+ */
+extern rtk_api_ret_t rtk_dot1x_macBasedEnable_set(rtk_port_t port, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_dot1x_macBasedEnable_get
+ * Description:
+ *      Get 802.1x mac-based port enable configuration
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEnable - The status of 802.1x port.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      If a port is 802.1x MAC based network access control "enabled", the incoming packets should
+ *      be authenticated so packets from that port wont be dropped or trapped to CPU.
+ *      The status of 802.1x MAC-based network access control is as following:
+ *      - DISABLED
+ *      - ENABLED
+ */
+extern rtk_api_ret_t rtk_dot1x_macBasedEnable_get(rtk_port_t port, rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_dot1x_macBasedAuthMac_add
+ * Description:
+ *      Add an authenticated MAC to ASIC
+ * Input:
+ *      port        - Port id.
+ *      pAuth_mac   - The authenticated MAC.
+ *      fid         - filtering database.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number.
+ *      RT_ERR_ENABLE               - Invalid enable input.
+ *      RT_ERR_DOT1X_MACBASEDPNEN   - 802.1X mac-based enable error
+ * Note:
+ *      The API can add a 802.1x authenticated MAC address to port. If the MAC does not exist in LUT,
+ *      user can't add this MAC to auth status.
+ */
+extern rtk_api_ret_t rtk_dot1x_macBasedAuthMac_add(rtk_port_t port, rtk_mac_t *pAuth_mac, rtk_fid_t fid);
+
+/* Function Name:
+ *      rtk_dot1x_macBasedAuthMac_del
+ * Description:
+ *      Delete an authenticated MAC to ASIC
+ * Input:
+ *      port - Port id.
+ *      pAuth_mac - The authenticated MAC.
+ *      fid - filtering database.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_MAC          - Invalid MAC address.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can delete a 802.1x authenticated MAC address to port. It only change the auth status of
+ *      the MAC and won't delete it from LUT.
+ */
+extern rtk_api_ret_t rtk_dot1x_macBasedAuthMac_del(rtk_port_t port, rtk_mac_t *pAuth_mac, rtk_fid_t fid);
+
+/* Function Name:
+ *      rtk_dot1x_macBasedDirection_set
+ * Description:
+ *      Set 802.1x mac-based operational direction configuration
+ * Input:
+ *      mac_direction - Operation direction
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_INPUT                - Invalid input parameter.
+ *      RT_ERR_DOT1X_MACBASEDOPDIR  - 802.1X mac-based operation direction error
+ * Note:
+ *      The operate controlled direction of 802.1x mac-based network access control is as following:
+ *      - BOTH
+ *      - IN
+ */
+extern rtk_api_ret_t rtk_dot1x_macBasedDirection_set(rtk_dot1x_direction_t mac_direction);
+
+/* Function Name:
+ *      rtk_dot1x_macBasedDirection_get
+ * Description:
+ *      Get 802.1x mac-based operational direction configuration
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pMac_direction - Operation direction
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get 802.1x mac-based operational direction information.
+ */
+extern rtk_api_ret_t rtk_dot1x_macBasedDirection_get(rtk_dot1x_direction_t *pMac_direction);
+
+/* Function Name:
+ *      Set 802.1x guest VLAN configuration
+ * Description:
+ *      Set 802.1x mac-based operational direction configuration
+ * Input:
+ *      vid - 802.1x guest VLAN ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ * Note:
+ *      The operate controlled 802.1x guest VLAN
+ */
+extern rtk_api_ret_t rtk_dot1x_guestVlan_set(rtk_vlan_t vid);
+
+/* Function Name:
+ *      rtk_dot1x_guestVlan_get
+ * Description:
+ *      Get 802.1x guest VLAN configuration
+ * Input:
+ *      None
+ * Output:
+ *      pVid - 802.1x guest VLAN ID
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get 802.1x guest VLAN information.
+ */
+extern rtk_api_ret_t rtk_dot1x_guestVlan_get(rtk_vlan_t *pVid);
+
+/* Function Name:
+ *      rtk_dot1x_guestVlan2Auth_set
+ * Description:
+ *      Set 802.1x guest VLAN to auth host configuration
+ * Input:
+ *      enable - The status of guest VLAN to auth host.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ * Note:
+ *      The operational direction of 802.1x guest VLAN to auth host control is as following:
+ *      - ENABLED
+ *      - DISABLED
+ */
+extern rtk_api_ret_t rtk_dot1x_guestVlan2Auth_set(rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_dot1x_guestVlan2Auth_get
+ * Description:
+ *      Get 802.1x guest VLAN to auth host configuration
+ * Input:
+ *      None
+ * Output:
+ *      pEnable - The status of guest VLAN to auth host.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get 802.1x guest VLAN to auth host information.
+ */
+extern rtk_api_ret_t rtk_dot1x_guestVlan2Auth_get(rtk_enable_t *pEnable);
+
+
+#endif /* __RTK_API_DOT1X_H__ */
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/eee.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/eee.h
new file mode 100644
index 0000000..b670998
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/eee.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes EEE module high-layer API defination
+ *
+ */
+
+#ifndef __RTK_API_EEE_H__
+#define __RTK_API_EEE_H__
+
+/* Function Name:
+ *      rtk_eee_init
+ * Description:
+ *      EEE function initialization.
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      This API is used to initialize EEE status.
+ */
+extern rtk_api_ret_t rtk_eee_init(void);
+
+/* Function Name:
+ *      rtk_eee_portEnable_set
+ * Description:
+ *      Set enable status of EEE function.
+ * Input:
+ *      port - port id.
+ *      enable - enable EEE status.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_PORT_ID - Invalid port number.
+ *      RT_ERR_ENABLE - Invalid enable input.
+ * Note:
+ *      This API can set EEE function to the specific port.
+ *      The configuration of the port is as following:
+ *      - DISABLE
+ *      - ENABLE
+ */
+extern rtk_api_ret_t rtk_eee_portEnable_set(rtk_port_t port, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_eee_portEnable_get
+ * Description:
+ *      Get port admin configuration of the specific port.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEnable - Back pressure status.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_PORT_ID - Invalid port number.
+ * Note:
+ *      This API can set EEE function to the specific port.
+ *      The configuration of the port is as following:
+ *      - DISABLE
+ *      - ENABLE
+ */
+extern rtk_api_ret_t rtk_eee_portEnable_get(rtk_port_t port, rtk_enable_t *pEnable);
+
+
+#endif /* __RTK_API_EEE_H__ */
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/i2c.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/i2c.h
new file mode 100644
index 0000000..2c7f075
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/i2c.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes I2C module high-layer API defination
+ *
+ */
+
+
+#ifndef __RTK_API_I2C_H__
+#define __RTK_API_I2C_H__
+#include <rtk_types.h>
+
+#define I2C_GPIO_MAX_GROUP (3)
+
+typedef enum rtk_I2C_16bit_mode_e{
+    I2C_LSB_16BIT_MODE = 0,
+    I2C_70B_LSB_16BIT_MODE,
+    I2C_Mode_END
+}rtk_I2C_16bit_mode_t;
+
+
+typedef enum rtk_I2C_gpio_pin_e{
+    I2C_GPIO_PIN_8_9 = 0,
+    I2C_GPIO_PIN_15_16 ,
+    I2C_GPIO_PIN_35_36 ,
+    I2C_GPIO_PIN_END
+}rtk_I2C_gpio_pin_t;
+
+
+/* Function Name:
+ *      rtk_i2c_data_read
+ * Description:
+ *      read i2c slave device register.
+ * Input:
+ *      deviceAddr   -   access Slave device address
+ *      slaveRegAddr -   access Slave register address
+ * Output:
+ *      pRegData     -   read data
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_NULL_POINTER     - input parameter is null pointer
+ * Note:
+ *      The API can access i2c slave and read i2c slave device register.
+ */
+extern rtk_api_ret_t rtk_i2c_data_read(rtk_uint8 deviceAddr, rtk_uint32 slaveRegAddr, rtk_uint32 *pRegData);
+
+/* Function Name:
+ *      rtk_i2c_data_write
+ * Description:
+ *      write data to i2c slave device register
+ * Input:
+ *      deviceAddr   -   access Slave device address
+ *      slaveRegAddr -   access Slave register address
+ *      regData      -   data to set
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ * Note:
+ *      The API can access i2c slave and setting i2c slave device register.
+ */
+extern rtk_api_ret_t rtk_i2c_data_write(rtk_uint8 deviceAddr, rtk_uint32 slaveRegAddr, rtk_uint32 regData);
+
+
+/* Function Name:
+ *      rtk_i2c_init
+ * Description:
+ *      I2C smart function initialization.
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ * Note:
+ *      This API is used to initialize EEE status.
+ *      need used GPIO pins
+ *      OpenDrain and clock
+ */
+extern rtk_api_ret_t rtk_i2c_init(void);
+
+/* Function Name:
+ *      rtk_i2c_mode_set
+ * Description:
+ *      Set I2C data byte-order.
+ * Input:
+ *      i2cmode - byte-order mode
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ * Note:
+ *      This API can set I2c traffic's byte-order .
+ */
+extern rtk_api_ret_t rtk_i2c_mode_set( rtk_I2C_16bit_mode_t i2cmode);
+
+/* Function Name:
+ *      rtk_i2c_mode_get
+ * Description:
+ *      Get i2c traffic byte-order setting.
+ * Input:
+ *      None
+ * Output:
+ *      pI2cMode - i2c byte-order
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_NULL_POINTER     - input parameter is null pointer
+ * Note:
+ *      The API can get i2c traffic byte-order setting.
+ */
+extern rtk_api_ret_t rtk_i2c_mode_get( rtk_I2C_16bit_mode_t * pI2cMode);
+
+
+/* Function Name:
+ *      rtk_i2c_gpioPinGroup_set
+ * Description:
+ *      Set i2c SDA & SCL used GPIO pins group.
+ * Input:
+ *      pins_group - GPIO pins group
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ * Note:
+ *      The API can set i2c used gpio pins group.
+ *      There are three group pins could be used
+ */
+extern rtk_api_ret_t rtk_i2c_gpioPinGroup_set( rtk_I2C_gpio_pin_t pins_group);
+
+/* Function Name:
+ *      rtk_i2c_gpioPinGroup_get
+ * Description:
+ *      Get i2c SDA & SCL used GPIO pins group.
+ * Input:
+ *      None
+ * Output:
+ *      pPins_group - GPIO pins group
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_NULL_POINTER     - input parameter is null pointer
+ * Note:
+ *      The API can get i2c used gpio pins group.
+ *      There are three group pins could be used
+ */
+extern rtk_api_ret_t rtk_i2c_gpioPinGroup_get(rtk_I2C_gpio_pin_t * pPins_group);
+
+
+
+
+
+
+
+#endif
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/igmp.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/igmp.h
new file mode 100644
index 0000000..f088b0c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/igmp.h
@@ -0,0 +1,769 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes IGMP module high-layer API defination
+ *
+ */
+
+#ifndef __RTK_API_IGMP_H__
+#define __RTK_API_IGMP_H__
+
+/*
+ * Data Type Declaration
+ */
+typedef enum rtk_igmp_type_e
+{
+    IGMP_IPV4 = 0,
+    IGMP_PPPOE_IPV4,
+    IGMP_MLD,
+    IGMP_PPPOE_MLD,
+    IGMP_TYPE_END
+} rtk_igmp_type_t;
+
+typedef enum rtk_trap_igmp_action_e
+{
+    IGMP_ACTION_FORWARD = 0,
+    IGMP_ACTION_TRAP2CPU,
+    IGMP_ACTION_DROP,
+    IGMP_ACTION_ASIC,
+    IGMP_ACTION_END
+} rtk_igmp_action_t;
+
+typedef enum rtk_igmp_protocol_e
+{
+    PROTOCOL_IGMPv1 = 0,
+    PROTOCOL_IGMPv2,
+    PROTOCOL_IGMPv3,
+    PROTOCOL_MLDv1,
+    PROTOCOL_MLDv2,
+    PROTOCOL_END
+} rtk_igmp_protocol_t;
+
+typedef enum rtk_igmp_tableFullAction_e
+{
+    IGMP_TABLE_FULL_FORWARD = 0,
+    IGMP_TABLE_FULL_DROP,
+    IGMP_TABLE_FULL_TRAP,
+    IGMP_TABLE_FULL_OP_END
+}rtk_igmp_tableFullAction_t;
+
+typedef enum rtk_igmp_checksumErrorAction_e
+{
+    IGMP_CRC_ERR_DROP = 0,
+    IGMP_CRC_ERR_TRAP,
+    IGMP_CRC_ERR_FORWARD,
+    IGMP_CRC_ERR_OP_END
+}rtk_igmp_checksumErrorAction_t;
+
+typedef enum rtk_igmp_bypassGroup_e
+{
+    IGMP_BYPASS_224_0_0_X = 0,
+    IGMP_BYPASS_224_0_1_X,
+    IGMP_BYPASS_239_255_255_X,
+    IGMP_BYPASS_IPV6_00XX,
+    IGMP_BYPASS_GROUP_END
+}rtk_igmp_bypassGroup_t;
+
+
+typedef struct rtk_igmp_dynamicRouterPort_s
+{
+    rtk_enable_t    dynamicRouterPort0Valid;
+    rtk_port_t      dynamicRouterPort0;
+    rtk_uint32      dynamicRouterPort0Timer;
+    rtk_enable_t    dynamicRouterPort1Valid;
+    rtk_port_t      dynamicRouterPort1;
+    rtk_uint32      dynamicRouterPort1Timer;
+
+}rtk_igmp_dynamicRouterPort_t;
+
+typedef struct rtk_igmp_rxPktEnable_s
+{
+    rtk_enable_t rxQuery;
+    rtk_enable_t rxReport;
+    rtk_enable_t rxLeave;
+    rtk_enable_t rxMRP;
+    rtk_enable_t rxMcast;
+}rtk_igmp_rxPktEnable_t;
+
+typedef struct rtk_igmp_groupInfo_s
+{
+    rtk_enable_t    valid;
+    rtk_portmask_t  member;
+    rtk_uint32      timer[RTK_PORT_MAX];
+    rtk_uint32      reportSuppFlag;
+}rtk_igmp_groupInfo_t;
+
+typedef enum rtk_igmp_ReportLeaveFwdAct_e
+{
+    IGMP_REPORT_LEAVE_TO_ROUTER = 0,
+    IGMP_REPORT_LEAVE_TO_ALLPORT,
+    IGMP_REPORT_LEAVE_TO_ROUTER_PORT_ADV,
+    IGMP_REPORT_LEAVE_ACT_END
+}rtk_igmp_ReportLeaveFwdAct_t;
+
+/* Function Name:
+ *      rtk_igmp_init
+ * Description:
+ *      This API enables H/W IGMP and set a default initial configuration.
+ * Input:
+ *      None.
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      This API enables H/W IGMP and set a default initial configuration.
+ */
+extern rtk_api_ret_t rtk_igmp_init(void);
+
+/* Function Name:
+ *      rtk_igmp_state_set
+ * Description:
+ *      This API set H/W IGMP state.
+ * Input:
+ *      enabled     - H/W IGMP state
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error parameter
+ * Note:
+ *      This API set H/W IGMP state.
+ */
+extern rtk_api_ret_t rtk_igmp_state_set(rtk_enable_t enabled);
+
+/* Function Name:
+ *      rtk_igmp_state_get
+ * Description:
+ *      This API get H/W IGMP state.
+ * Input:
+ *      None.
+ * Output:
+ *      pEnabled        - H/W IGMP state
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error parameter
+ * Note:
+ *      This API set current H/W IGMP state.
+ */
+extern rtk_api_ret_t rtk_igmp_state_get(rtk_enable_t *pEnabled);
+
+/* Function Name:
+ *      rtk_igmp_static_router_port_set
+ * Description:
+ *      Configure static router port
+ * Input:
+ *      pPortmask    - Static Port mask
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_PORT_MASK       - Error parameter
+ * Note:
+ *      This API set static router port
+ */
+extern rtk_api_ret_t rtk_igmp_static_router_port_set(rtk_portmask_t *pPortmask);
+
+/* Function Name:
+ *      rtk_igmp_static_router_port_get
+ * Description:
+ *      Get static router port
+ * Input:
+ *      None.
+ * Output:
+ *      pPortmask       - Static port mask
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_PORT_MASK       - Error parameter
+ * Note:
+ *      This API get static router port
+ */
+extern rtk_api_ret_t rtk_igmp_static_router_port_get(rtk_portmask_t *pPortmask);
+
+/* Function Name:
+ *      rtk_igmp_protocol_set
+ * Description:
+ *      set IGMP/MLD protocol action
+ * Input:
+ *      port        - Port ID
+ *      protocol    - IGMP/MLD protocol
+ *      action      - Per-port and per-protocol IGMP action seeting
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_PORT_MASK       - Error parameter
+ * Note:
+ *      This API set IGMP/MLD protocol action
+ */
+extern rtk_api_ret_t rtk_igmp_protocol_set(rtk_port_t port, rtk_igmp_protocol_t protocol, rtk_igmp_action_t action);
+
+/* Function Name:
+ *      rtk_igmp_protocol_get
+ * Description:
+ *      set IGMP/MLD protocol action
+ * Input:
+ *      port        - Port ID
+ *      protocol    - IGMP/MLD protocol
+ *      action      - Per-port and per-protocol IGMP action seeting
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_PORT_MASK       - Error parameter
+ * Note:
+ *      This API set IGMP/MLD protocol action
+ */
+extern rtk_api_ret_t rtk_igmp_protocol_get(rtk_port_t port, rtk_igmp_protocol_t protocol, rtk_igmp_action_t *pAction);
+
+/* Function Name:
+ *      rtk_igmp_fastLeave_set
+ * Description:
+ *      set IGMP/MLD FastLeave state
+ * Input:
+ *      state       - ENABLED: Enable FastLeave, DISABLED: disable FastLeave
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      This API set IGMP/MLD FastLeave state
+ */
+extern rtk_api_ret_t rtk_igmp_fastLeave_set(rtk_enable_t state);
+
+/* Function Name:
+ *      rtk_igmp_fastLeave_get
+ * Description:
+ *      get IGMP/MLD FastLeave state
+ * Input:
+ *      None
+ * Output:
+ *      pState      - ENABLED: Enable FastLeave, DISABLED: disable FastLeave
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_NULL_POINTER    - NULL pointer
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      This API get IGMP/MLD FastLeave state
+ */
+extern rtk_api_ret_t rtk_igmp_fastLeave_get(rtk_enable_t *pState);
+
+/* Function Name:
+ *      rtk_igmp_maxGroup_set
+ * Description:
+ *      Set per port multicast group learning limit.
+ * Input:
+ *      port        - Port ID
+ *      group       - The number of multicast group learning limit.
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_PORT_ID         - Error Port ID
+ *      RT_ERR_OUT_OF_RANGE    - parameter out of range
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      This API set per port multicast group learning limit.
+ */
+extern rtk_api_ret_t rtk_igmp_maxGroup_set(rtk_port_t port, rtk_uint32 group);
+
+/* Function Name:
+ *      rtk_igmp_maxGroup_get
+ * Description:
+ *      Get per port multicast group learning limit.
+ * Input:
+ *      port        - Port ID
+ * Output:
+ *      pGroup      - The number of multicast group learning limit.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_PORT_ID         - Error Port ID
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      This API get per port multicast group learning limit.
+ */
+extern rtk_api_ret_t rtk_igmp_maxGroup_get(rtk_port_t port, rtk_uint32 *pGroup);
+
+/* Function Name:
+ *      rtk_igmp_currentGroup_get
+ * Description:
+ *      Get per port multicast group learning count.
+ * Input:
+ *      port        - Port ID
+ * Output:
+ *      pGroup      - The number of multicast group learning count.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_PORT_ID         - Error Port ID
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      This API get per port multicast group learning count.
+ */
+extern rtk_api_ret_t rtk_igmp_currentGroup_get(rtk_port_t port, rtk_uint32 *pGroup);
+
+/* Function Name:
+ *      rtk_igmp_tableFullAction_set
+ * Description:
+ *      set IGMP/MLD Table Full Action
+ * Input:
+ *      action      - Table Full Action
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ */
+extern rtk_api_ret_t rtk_igmp_tableFullAction_set(rtk_igmp_tableFullAction_t action);
+
+/* Function Name:
+ *      rtk_igmp_tableFullAction_get
+ * Description:
+ *      get IGMP/MLD Table Full Action
+ * Input:
+ *      None
+ * Output:
+ *      pAction     - Table Full Action
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ */
+extern rtk_api_ret_t rtk_igmp_tableFullAction_get(rtk_igmp_tableFullAction_t *pAction);
+
+/* Function Name:
+ *      rtk_igmp_checksumErrorAction_set
+ * Description:
+ *      set IGMP/MLD Checksum Error Action
+ * Input:
+ *      action      - Checksum error Action
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ */
+extern rtk_api_ret_t rtk_igmp_checksumErrorAction_set(rtk_igmp_checksumErrorAction_t action);
+
+/* Function Name:
+ *      rtk_igmp_checksumErrorAction_get
+ * Description:
+ *      get IGMP/MLD Checksum Error Action
+ * Input:
+ *      None
+ * Output:
+ *      pAction     - Checksum error Action
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ */
+extern rtk_api_ret_t rtk_igmp_checksumErrorAction_get(rtk_igmp_checksumErrorAction_t *pAction);
+
+/* Function Name:
+ *      rtk_igmp_leaveTimer_set
+ * Description:
+ *      set IGMP/MLD Leave timer
+ * Input:
+ *      timer       - Leave timer
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ */
+extern rtk_api_ret_t rtk_igmp_leaveTimer_set(rtk_uint32 timer);
+
+/* Function Name:
+ *      rtk_igmp_leaveTimer_get
+ * Description:
+ *      get IGMP/MLD Leave timer
+ * Input:
+ *      None
+ * Output:
+ *      pTimer      - Leave Timer.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ */
+extern rtk_api_ret_t rtk_igmp_leaveTimer_get(rtk_uint32 *pTimer);
+
+/* Function Name:
+ *      rtk_igmp_queryInterval_set
+ * Description:
+ *      set IGMP/MLD Query Interval
+ * Input:
+ *      interval     - Query Interval
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ */
+extern rtk_api_ret_t rtk_igmp_queryInterval_set(rtk_uint32 interval);
+
+/* Function Name:
+ *      rtk_igmp_queryInterval_get
+ * Description:
+ *      get IGMP/MLD Query Interval
+ * Input:
+ *      None.
+ * Output:
+ *      pInterval   - Query Interval
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ */
+extern rtk_api_ret_t rtk_igmp_queryInterval_get(rtk_uint32 *pInterval);
+
+/* Function Name:
+ *      rtk_igmp_robustness_set
+ * Description:
+ *      set IGMP/MLD Robustness value
+ * Input:
+ *      robustness     - Robustness value
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ */
+extern rtk_api_ret_t rtk_igmp_robustness_set(rtk_uint32 robustness);
+
+/* Function Name:
+ *      rtk_igmp_robustness_get
+ * Description:
+ *      get IGMP/MLD Robustness value
+ * Input:
+ *      None
+ * Output:
+ *      pRobustness     - Robustness value.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ */
+extern rtk_api_ret_t rtk_igmp_robustness_get(rtk_uint32 *pRobustness);
+
+/* Function Name:
+ *      rtk_igmp_dynamicRouterRortAllow_set
+ * Description:
+ *      Configure dynamic router port allow option
+ * Input:
+ *      pPortmask    - Dynamic Port allow mask
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_PORT_MASK       - Error parameter
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_igmp_dynamicRouterPortAllow_set(rtk_portmask_t *pPortmask);
+
+/* Function Name:
+ *      rtk_igmp_dynamicRouterRortAllow_get
+ * Description:
+ *      Get dynamic router port allow option
+ * Input:
+ *      None.
+ * Output:
+ *      pPortmask    - Dynamic Port allow mask
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_PORT_MASK       - Error parameter
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_igmp_dynamicRouterPortAllow_get(rtk_portmask_t *pPortmask);
+
+/* Function Name:
+ *      rtk_igmp_dynamicRouterPort_get
+ * Description:
+ *      Get dynamic router port
+ * Input:
+ *      None.
+ * Output:
+ *      pDynamicRouterPort    - Dynamic Router Port
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_PORT_MASK       - Error parameter
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_igmp_dynamicRouterPort_get(rtk_igmp_dynamicRouterPort_t *pDynamicRouterPort);
+
+/* Function Name:
+ *      rtk_igmp_suppressionEnable_set
+ * Description:
+ *      Configure IGMPv1/v2 & MLDv1 Report/Leave/Done suppression
+ * Input:
+ *      reportSuppression   - Report suppression
+ *      leaveSuppression    - Leave suppression
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error Input
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_igmp_suppressionEnable_set(rtk_enable_t reportSuppression, rtk_enable_t leaveSuppression);
+
+/* Function Name:
+ *      rtk_igmp_suppressionEnable_get
+ * Description:
+ *      Get IGMPv1/v2 & MLDv1 Report/Leave/Done suppression
+ * Input:
+ *      None
+ * Output:
+ *      pReportSuppression  - Report suppression
+ *      pLeaveSuppression   - Leave suppression
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_igmp_suppressionEnable_get(rtk_enable_t *pReportSuppression, rtk_enable_t *pLeaveSuppression);
+
+/* Function Name:
+ *      rtk_igmp_portRxPktEnable_set
+ * Description:
+ *      Configure IGMP/MLD RX Packet configuration
+ * Input:
+ *      port       - Port ID
+ *      pRxCfg     - RX Packet Configuration
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_igmp_portRxPktEnable_set(rtk_port_t port, rtk_igmp_rxPktEnable_t *pRxCfg);
+
+/* Function Name:
+ *      rtk_igmp_portRxPktEnable_get
+ * Description:
+ *      Get IGMP/MLD RX Packet configuration
+ * Input:
+ *      port       - Port ID
+ *      pRxCfg     - RX Packet Configuration
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_igmp_portRxPktEnable_get(rtk_port_t port, rtk_igmp_rxPktEnable_t *pRxCfg);
+
+/* Function Name:
+ *      rtk_igmp_groupInfo_get
+ * Description:
+ *      Get IGMP/MLD Group database
+ * Input:
+ *      indes       - Index (0~255)
+ * Output:
+ *      pGroup      - Group database information.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_igmp_groupInfo_get(rtk_uint32 index, rtk_igmp_groupInfo_t *pGroup);
+
+/* Function Name:
+ *      rtk_igmp_ReportLeaveFwdAction_set
+ * Description:
+ *      Set Report Leave packet forwarding action
+ * Input:
+ *      action      - Action
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error Input
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_igmp_ReportLeaveFwdAction_set(rtk_igmp_ReportLeaveFwdAct_t action);
+
+/* Function Name:
+ *      rtk_igmp_ReportLeaveFwdAction_get
+ * Description:
+ *      Get Report Leave packet forwarding action
+ * Input:
+ *      action      - Action
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_NULL_POINTER    - Null Pointer
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_igmp_ReportLeaveFwdAction_get(rtk_igmp_ReportLeaveFwdAct_t *pAction);
+
+/* Function Name:
+ *      rtk_igmp_dropLeaveZeroEnable_set
+ * Description:
+ *      Set the function of droppping Leave packet with group IP = 0.0.0.0
+ * Input:
+ *      enabled      - Action 1: drop, 0:pass
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error Input
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_igmp_dropLeaveZeroEnable_set(rtk_enable_t enabled);
+
+/* Function Name:
+ *      rtk_igmp_dropLeaveZeroEnable_get
+ * Description:
+ *      Get the function of droppping Leave packet with group IP = 0.0.0.0
+ * Input:
+ *      None
+ * Output:
+ *      pEnabled.   - Action 1: drop, 0:pass
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_NULL_POINTER    - Null Pointer
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_igmp_dropLeaveZeroEnable_get(rtk_enable_t *pEnabled);
+
+/* Function Name:
+ *      rtk_igmp_bypassGroupRange_set
+ * Description:
+ *      Set Bypass group
+ * Input:
+ *      group       - bypassed group
+ *      enabled     - enabled 1: Bypassed, 0: not bypass
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error Input
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_igmp_bypassGroupRange_set(rtk_igmp_bypassGroup_t group, rtk_enable_t enabled);
+
+/* Function Name:
+ *      rtk_igmp_bypassGroupRange_get
+ * Description:
+ *      get Bypass group
+ * Input:
+ *      group       - bypassed group
+ * Output:
+ *      pEnable     - enabled 1: Bypassed, 0: not bypass
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error Input
+ *      RT_ERR_NULL_POINTER    - Null Pointer
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_igmp_bypassGroupRange_get(rtk_igmp_bypassGroup_t group, rtk_enable_t *pEnable);
+
+#endif /* __RTK_API_IGMP_H__ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/interrupt.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/interrupt.h
new file mode 100644
index 0000000..f2689eb
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/interrupt.h
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes Interrupt module high-layer API defination
+ *
+ */
+
+#ifndef __RTK_API_INTERRUPT_H__
+#define __RTK_API_INTERRUPT_H__
+
+
+/*
+ * Data Type Declaration
+ */
+#define RTK_MAX_NUM_OF_INTERRUPT_TYPE               1
+
+
+typedef struct  rtk_int_status_s
+{
+    rtk_uint16 value[RTK_MAX_NUM_OF_INTERRUPT_TYPE];
+} rtk_int_status_t;
+
+typedef struct rtk_int_info_s
+{
+    rtk_portmask_t  portMask;
+    rtk_uint32      meterMask;
+    rtk_uint32      systemLearnOver;
+}rtk_int_info_t;
+
+typedef enum rtk_int_type_e
+{
+    INT_TYPE_LINK_STATUS = 0,
+    INT_TYPE_METER_EXCEED,
+    INT_TYPE_LEARN_LIMIT,
+    INT_TYPE_LINK_SPEED,
+    INT_TYPE_CONGEST,
+    INT_TYPE_GREEN_FEATURE,
+    INT_TYPE_LOOP_DETECT,
+    INT_TYPE_8051,
+    INT_TYPE_CABLE_DIAG,
+    INT_TYPE_ACL,
+    INT_TYPE_RESERVED, /* Unused */
+    INT_TYPE_SLIENT,
+    INT_TYPE_END
+}rtk_int_type_t;
+
+typedef enum rtk_int_advType_e
+{
+    ADV_L2_LEARN_PORT_MASK = 0,
+    ADV_SPEED_CHANGE_PORT_MASK,
+    ADV_SPECIAL_CONGESTION_PORT_MASK,
+    ADV_PORT_LINKDOWN_PORT_MASK,
+    ADV_PORT_LINKUP_PORT_MASK,
+    ADV_METER_EXCEED_MASK,
+    ADV_RLDP_LOOPED,
+    ADV_RLDP_RELEASED,
+    ADV_END,
+} rtk_int_advType_t;
+
+typedef enum rtk_int_polarity_e
+{
+    INT_POLAR_HIGH = 0,
+    INT_POLAR_LOW,
+    INT_POLAR_END
+} rtk_int_polarity_t;
+
+/* Function Name:
+ *      rtk_int_polarity_set
+ * Description:
+ *      Set interrupt polarity configuration.
+ * Input:
+ *      type - Interruptpolarity type.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can set interrupt polarity configuration.
+ */
+extern rtk_api_ret_t rtk_int_polarity_set(rtk_int_polarity_t type);
+
+/* Function Name:
+ *      rtk_int_polarity_get
+ * Description:
+ *      Get interrupt polarity configuration.
+ * Input:
+ *      None
+ * Output:
+ *      pType - Interruptpolarity type.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      The API can get interrupt polarity configuration.
+ */
+extern rtk_api_ret_t rtk_int_polarity_get(rtk_int_polarity_t *pType);
+
+/* Function Name:
+ *      rtk_int_control_set
+ * Description:
+ *      Set interrupt trigger status configuration.
+ * Input:
+ *      type - Interrupt type.
+ *      enable - Interrupt status.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_ENABLE       - Invalid enable input.
+ * Note:
+ *      The API can set interrupt status configuration.
+ *      The interrupt trigger status is shown in the following:
+ *      - INT_TYPE_LINK_STATUS
+ *      - INT_TYPE_METER_EXCEED
+ *      - INT_TYPE_LEARN_LIMIT
+ *      - INT_TYPE_LINK_SPEED
+ *      - INT_TYPE_CONGEST
+ *      - INT_TYPE_GREEN_FEATURE
+ *      - INT_TYPE_LOOP_DETECT
+ *      - INT_TYPE_8051,
+ *      - INT_TYPE_CABLE_DIAG,
+ *      - INT_TYPE_ACL,
+ *      - INT_TYPE_SLIENT
+ */
+extern rtk_api_ret_t rtk_int_control_set(rtk_int_type_t type, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_int_control_get
+ * Description:
+ *      Get interrupt trigger status configuration.
+ * Input:
+ *      type - Interrupt type.
+ * Output:
+ *      pEnable - Interrupt status.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get interrupt status configuration.
+ *      The interrupt trigger status is shown in the following:
+ *      - INT_TYPE_LINK_STATUS
+ *      - INT_TYPE_METER_EXCEED
+ *      - INT_TYPE_LEARN_LIMIT
+ *      - INT_TYPE_LINK_SPEED
+ *      - INT_TYPE_CONGEST
+ *      - INT_TYPE_GREEN_FEATURE
+ *      - INT_TYPE_LOOP_DETECT
+ *      - INT_TYPE_8051,
+ *      - INT_TYPE_CABLE_DIAG,
+ *      - INT_TYPE_ACL,
+ *      - INT_TYPE_SLIENT
+ */
+extern rtk_api_ret_t rtk_int_control_get(rtk_int_type_t type, rtk_enable_t* pEnable);
+
+/* Function Name:
+ *      rtk_int_status_set
+ * Description:
+ *      Set interrupt trigger status to clean.
+ * Input:
+ *      None
+ * Output:
+ *      pStatusMask - Interrupt status bit mask.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT - Invalid input parameters.
+ * Note:
+ *      The API can clean interrupt trigger status when interrupt happened.
+ *      The interrupt trigger status is shown in the following:
+ *      - INT_TYPE_LINK_STATUS    (value[0] (Bit0))
+ *      - INT_TYPE_METER_EXCEED   (value[0] (Bit1))
+ *      - INT_TYPE_LEARN_LIMIT    (value[0] (Bit2))
+ *      - INT_TYPE_LINK_SPEED     (value[0] (Bit3))
+ *      - INT_TYPE_CONGEST        (value[0] (Bit4))
+ *      - INT_TYPE_GREEN_FEATURE  (value[0] (Bit5))
+ *      - INT_TYPE_LOOP_DETECT    (value[0] (Bit6))
+ *      - INT_TYPE_8051           (value[0] (Bit7))
+ *      - INT_TYPE_CABLE_DIAG     (value[0] (Bit8))
+ *      - INT_TYPE_ACL            (value[0] (Bit9))
+ *      - INT_TYPE_SLIENT         (value[0] (Bit11))
+ *      The status will be cleared after execute this API.
+ */
+extern rtk_api_ret_t rtk_int_status_set(rtk_int_status_t *pStatusMask);
+
+/* Function Name:
+ *      rtk_int_status_get
+ * Description:
+ *      Get interrupt trigger status.
+ * Input:
+ *      None
+ * Output:
+ *      pStatusMask - Interrupt status bit mask.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get interrupt trigger status when interrupt happened.
+ *      The interrupt trigger status is shown in the following:
+ *      - INT_TYPE_LINK_STATUS    (value[0] (Bit0))
+ *      - INT_TYPE_METER_EXCEED   (value[0] (Bit1))
+ *      - INT_TYPE_LEARN_LIMIT    (value[0] (Bit2))
+ *      - INT_TYPE_LINK_SPEED     (value[0] (Bit3))
+ *      - INT_TYPE_CONGEST        (value[0] (Bit4))
+ *      - INT_TYPE_GREEN_FEATURE  (value[0] (Bit5))
+ *      - INT_TYPE_LOOP_DETECT    (value[0] (Bit6))
+ *      - INT_TYPE_8051           (value[0] (Bit7))
+ *      - INT_TYPE_CABLE_DIAG     (value[0] (Bit8))
+ *      - INT_TYPE_ACL            (value[0] (Bit9))
+ *      - INT_TYPE_SLIENT         (value[0] (Bit11))
+ *
+ */
+extern rtk_api_ret_t rtk_int_status_get(rtk_int_status_t* pStatusMask);
+
+/* Function Name:
+ *      rtk_int_advanceInfo_get
+ * Description:
+ *      Get interrupt advanced information.
+ * Input:
+ *      adv_type - Advanced interrupt type.
+ * Output:
+ *      info - Information per type.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API can get advanced information when interrupt happened.
+ *      The status will be cleared after execute this API.
+ */
+extern rtk_api_ret_t rtk_int_advanceInfo_get(rtk_int_advType_t adv_type, rtk_int_info_t* info);
+
+
+#endif /* __RTK_API_INTERRUPT_H__ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/l2.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/l2.h
new file mode 100644
index 0000000..e0ccdbe
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/l2.h
@@ -0,0 +1,1181 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes L2 module high-layer API defination
+ *
+ */
+
+#ifndef __RTK_API_L2_H__
+#define __RTK_API_L2_H__
+
+
+/*
+ * Data Type Declaration
+ */
+#define RTK_MAX_NUM_OF_LEARN_LIMIT                  (rtk_switch_maxLutAddrNumber_get())
+
+#define RTK_MAC_ADDR_LEN                            6
+#define RTK_MAX_LUT_ADDRESS                         (RTK_MAX_NUM_OF_LEARN_LIMIT)
+#define RTK_MAX_LUT_ADDR_ID                         (RTK_MAX_LUT_ADDRESS - 1)
+
+typedef rtk_uint32 rtk_l2_age_time_t;
+
+typedef enum rtk_l2_flood_type_e
+{
+    FLOOD_UNKNOWNDA = 0,
+    FLOOD_UNKNOWNMC,
+    FLOOD_BC,
+    FLOOD_END
+} rtk_l2_flood_type_t;
+
+typedef rtk_uint32 rtk_l2_flushItem_t;
+
+typedef enum rtk_l2_flushType_e
+{
+    FLUSH_TYPE_BY_PORT = 0,       /* physical port       */
+    FLUSH_TYPE_BY_PORT_VID,       /* physical port + VID */
+    FLUSH_TYPE_BY_PORT_FID,       /* physical port + FID */
+    FLUSH_TYPE_END
+} rtk_l2_flushType_t;
+
+typedef struct rtk_l2_flushCfg_s
+{
+    rtk_enable_t    flushByVid;
+    rtk_vlan_t      vid;
+    rtk_enable_t    flushByFid;
+    rtk_uint32      fid;
+    rtk_enable_t    flushByPort;
+    rtk_port_t      port;
+    rtk_enable_t    flushByMac;
+    rtk_mac_t       ucastAddr;
+    rtk_enable_t    flushStaticAddr;
+    rtk_enable_t    flushAddrOnAllPorts; /* this is used when flushByVid */
+} rtk_l2_flushCfg_t;
+
+typedef enum rtk_l2_read_method_e{
+
+    READMETHOD_MAC = 0,
+    READMETHOD_ADDRESS,
+    READMETHOD_NEXT_ADDRESS,
+    READMETHOD_NEXT_L2UC,
+    READMETHOD_NEXT_L2MC,
+    READMETHOD_NEXT_L3MC,
+    READMETHOD_NEXT_L2L3MC,
+    READMETHOD_NEXT_L2UCSPA,
+    READMETHOD_END
+}rtk_l2_read_method_t;
+
+/* l2 limit learning count action */
+typedef enum rtk_l2_limitLearnCntAction_e
+{
+    LIMIT_LEARN_CNT_ACTION_DROP = 0,
+    LIMIT_LEARN_CNT_ACTION_FORWARD,
+    LIMIT_LEARN_CNT_ACTION_TO_CPU,
+    LIMIT_LEARN_CNT_ACTION_END
+} rtk_l2_limitLearnCntAction_t;
+
+typedef enum rtk_l2_ipmc_lookup_type_e
+{
+    LOOKUP_MAC = 0,
+    LOOKUP_IP,
+    LOOKUP_IP_VID,
+    LOOKUP_END
+} rtk_l2_ipmc_lookup_type_t;
+
+/* l2 address table - unicast data structure */
+typedef struct rtk_l2_ucastAddr_s
+{
+    rtk_mac_t       mac;
+    rtk_uint32      ivl;
+    rtk_uint32      cvid;
+    rtk_uint32      fid;
+    rtk_uint32      efid;
+    rtk_uint32      port;
+    rtk_uint32      sa_block;
+    rtk_uint32      da_block;
+    rtk_uint32      auth;
+    rtk_uint32      is_static;
+    rtk_uint32      priority;
+    rtk_uint32      sa_pri_en;
+    rtk_uint32      fwd_pri_en;
+    rtk_uint32      address;
+}rtk_l2_ucastAddr_t;
+
+/* l2 address table - multicast data structure */
+typedef struct rtk_l2_mcastAddr_s
+{
+    rtk_uint32      vid;
+    rtk_mac_t       mac;
+    rtk_uint32      fid;
+    rtk_portmask_t  portmask;
+    rtk_uint32      ivl;
+    rtk_uint32      priority;
+    rtk_uint32      fwd_pri_en;
+    rtk_uint32      igmp_asic;
+    rtk_uint32      igmp_index;
+    rtk_uint32      address;
+}rtk_l2_mcastAddr_t;
+
+/* l2 address table - ip multicast data structure */
+typedef struct rtk_l2_ipMcastAddr_s
+{
+    ipaddr_t        dip;
+    ipaddr_t        sip;
+    rtk_portmask_t  portmask;
+    rtk_uint32      priority;
+    rtk_uint32      fwd_pri_en;
+    rtk_uint32      igmp_asic;
+    rtk_uint32      igmp_index;
+    rtk_uint32      address;
+}rtk_l2_ipMcastAddr_t;
+
+/* l2 address table - ip VID multicast data structure */
+typedef struct rtk_l2_ipVidMcastAddr_s
+{
+    ipaddr_t        dip;
+    ipaddr_t        sip;
+    rtk_uint32      vid;
+    rtk_portmask_t  portmask;
+    rtk_uint32      address;
+}rtk_l2_ipVidMcastAddr_t;
+
+typedef struct rtk_l2_addr_table_s
+{
+    rtk_uint32  index;
+    ipaddr_t    sip;
+    ipaddr_t    dip;
+    rtk_mac_t   mac;
+    rtk_uint32  sa_block;
+    rtk_uint32  auth;
+    rtk_portmask_t  portmask;
+    rtk_uint32  age;
+    rtk_uint32  ivl;
+    rtk_uint32  cvid;
+    rtk_uint32  fid;
+    rtk_uint32  is_ipmul;
+    rtk_uint32  is_static;
+    rtk_uint32  is_ipvidmul;
+    rtk_uint32  l3_vid;
+}rtk_l2_addr_table_t;
+
+typedef enum rtk_l2_clearStatus_e
+{
+    L2_CLEAR_STATE_FINISH = 0,
+    L2_CLEAR_STATE_BUSY,
+    L2_CLEAR_STATE_END
+}rtk_l2_clearStatus_t;
+
+/* Function Name:
+ *      rtk_l2_init
+ * Description:
+ *      Initialize l2 module of the specified device.
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK          - OK
+ *      RT_ERR_FAILED      - Failed
+ *      RT_ERR_SMI         - SMI access error
+ * Note:
+ *      Initialize l2 module before calling any l2 APIs.
+ */
+extern rtk_api_ret_t rtk_l2_init(void);
+
+/* Function Name:
+ *      rtk_l2_addr_add
+ * Description:
+ *      Add LUT unicast entry.
+ * Input:
+ *      pMac - 6 bytes unicast(I/G bit is 0) mac address to be written into LUT.
+ *      pL2_data - Unicast entry parameter
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_MAC              - Invalid MAC address.
+ *      RT_ERR_L2_FID           - Invalid FID .
+ *      RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries.
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ * Note:
+ *      If the unicast mac address already existed in LUT, it will udpate the status of the entry.
+ *      Otherwise, it will find an empty or asic auto learned entry to write. If all the entries
+ *      with the same hash value can't be replaced, ASIC will return a RT_ERR_L2_INDEXTBL_FULL error.
+ */
+extern rtk_api_ret_t rtk_l2_addr_add(rtk_mac_t *pMac, rtk_l2_ucastAddr_t *pL2_data);
+
+/* Function Name:
+ *      rtk_l2_addr_get
+ * Description:
+ *      Get LUT unicast entry.
+ * Input:
+ *      pMac    - 6 bytes unicast(I/G bit is 0) mac address to be written into LUT.
+ * Output:
+ *      pL2_data - Unicast entry parameter
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number.
+ *      RT_ERR_MAC                  - Invalid MAC address.
+ *      RT_ERR_L2_FID               - Invalid FID .
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *      If the unicast mac address existed in LUT, it will return the port and fid where
+ *      the mac is learned. Otherwise, it will return a RT_ERR_L2_ENTRY_NOTFOUND error.
+ */
+extern rtk_api_ret_t rtk_l2_addr_get(rtk_mac_t *pMac, rtk_l2_ucastAddr_t *pL2_data);
+
+/* Function Name:
+ *      rtk_l2_addr_next_get
+ * Description:
+ *      Get Next LUT unicast entry.
+ * Input:
+ *      read_method     - The reading method.
+ *      port            - The port number if the read_metohd is READMETHOD_NEXT_L2UCSPA
+ *      pAddress        - The Address ID
+ * Output:
+ *      pL2_data - Unicast entry parameter
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number.
+ *      RT_ERR_MAC                  - Invalid MAC address.
+ *      RT_ERR_L2_FID               - Invalid FID .
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *      Get the next unicast entry after the current entry pointed by pAddress.
+ *      The address of next entry is returned by pAddress. User can use (address + 1)
+ *      as pAddress to call this API again for dumping all entries is LUT.
+ */
+extern rtk_api_ret_t rtk_l2_addr_next_get(rtk_l2_read_method_t read_method, rtk_port_t port, rtk_uint32 *pAddress, rtk_l2_ucastAddr_t *pL2_data);
+
+/* Function Name:
+ *      rtk_l2_addr_del
+ * Description:
+ *      Delete LUT unicast entry.
+ * Input:
+ *      pMac - 6 bytes unicast(I/G bit is 0) mac address to be written into LUT.
+ *      fid - Filtering database
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number.
+ *      RT_ERR_MAC                  - Invalid MAC address.
+ *      RT_ERR_L2_FID               - Invalid FID .
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *      If the mac has existed in the LUT, it will be deleted. Otherwise, it will return RT_ERR_L2_ENTRY_NOTFOUND.
+ */
+extern rtk_api_ret_t rtk_l2_addr_del(rtk_mac_t *pMac, rtk_l2_ucastAddr_t *pL2_data);
+
+/* Function Name:
+ *      rtk_l2_mcastAddr_add
+ * Description:
+ *      Add LUT multicast entry.
+ * Input:
+ *      pMcastAddr  - L2 multicast entry structure
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_MAC              - Invalid MAC address.
+ *      RT_ERR_L2_FID           - Invalid FID .
+ *      RT_ERR_L2_VID           - Invalid VID .
+ *      RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries.
+ *      RT_ERR_PORT_MASK        - Invalid portmask.
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ * Note:
+ *      If the multicast mac address already existed in the LUT, it will udpate the
+ *      port mask of the entry. Otherwise, it will find an empty or asic auto learned
+ *      entry to write. If all the entries with the same hash value can't be replaced,
+ *      ASIC will return a RT_ERR_L2_INDEXTBL_FULL error.
+ */
+extern rtk_api_ret_t rtk_l2_mcastAddr_add(rtk_l2_mcastAddr_t *pMcastAddr);
+
+/* Function Name:
+ *      rtk_l2_mcastAddr_get
+ * Description:
+ *      Get LUT multicast entry.
+ * Input:
+ *      pMcastAddr  - L2 multicast entry structure
+ * Output:
+ *      pMcastAddr  - L2 multicast entry structure
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_MAC                  - Invalid MAC address.
+ *      RT_ERR_L2_FID               - Invalid FID .
+ *      RT_ERR_L2_VID               - Invalid VID .
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *      If the multicast mac address existed in the LUT, it will return the port where
+ *      the mac is learned. Otherwise, it will return a RT_ERR_L2_ENTRY_NOTFOUND error.
+ */
+extern rtk_api_ret_t rtk_l2_mcastAddr_get(rtk_l2_mcastAddr_t *pMcastAddr);
+
+/* Function Name:
+ *      rtk_l2_mcastAddr_next_get
+ * Description:
+ *      Get Next L2 Multicast entry.
+ * Input:
+ *      pAddress        - The Address ID
+ * Output:
+ *      pMcastAddr  - L2 multicast entry structure
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *      Get the next L2 multicast entry after the current entry pointed by pAddress.
+ *      The address of next entry is returned by pAddress. User can use (address + 1)
+ *      as pAddress to call this API again for dumping all multicast entries is LUT.
+ */
+extern rtk_api_ret_t rtk_l2_mcastAddr_next_get(rtk_uint32 *pAddress, rtk_l2_mcastAddr_t *pMcastAddr);
+
+/* Function Name:
+ *      rtk_l2_mcastAddr_del
+ * Description:
+ *      Delete LUT multicast entry.
+ * Input:
+ *      pMcastAddr  - L2 multicast entry structure
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_MAC                  - Invalid MAC address.
+ *      RT_ERR_L2_FID               - Invalid FID .
+ *      RT_ERR_L2_VID               - Invalid VID .
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *      If the mac has existed in the LUT, it will be deleted. Otherwise, it will return RT_ERR_L2_ENTRY_NOTFOUND.
+ */
+extern rtk_api_ret_t rtk_l2_mcastAddr_del(rtk_l2_mcastAddr_t *pMcastAddr);
+
+/* Function Name:
+ *      rtk_l2_ipMcastAddr_add
+ * Description:
+ *      Add Lut IP multicast entry
+ * Input:
+ *      pIpMcastAddr    - IP Multicast entry
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries.
+ *      RT_ERR_PORT_MASK        - Invalid portmask.
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ * Note:
+ *      System supports L2 entry with IP multicast DIP/SIP to forward IP multicasting frame as user
+ *      desired. If this function is enabled, then system will be looked up L2 IP multicast entry to
+ *      forward IP multicast frame directly without flooding.
+ */
+extern rtk_api_ret_t rtk_l2_ipMcastAddr_add(rtk_l2_ipMcastAddr_t *pIpMcastAddr);
+
+/* Function Name:
+ *      rtk_l2_ipMcastAddr_get
+ * Description:
+ *      Get LUT IP multicast entry.
+ * Input:
+ *      pIpMcastAddr    - IP Multicast entry
+ * Output:
+ *      pIpMcastAddr    - IP Multicast entry
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *      The API can get Lut table of IP multicast entry.
+ */
+extern rtk_api_ret_t rtk_l2_ipMcastAddr_get(rtk_l2_ipMcastAddr_t *pIpMcastAddr);
+
+/* Function Name:
+ *      rtk_l2_ipMcastAddr_next_get
+ * Description:
+ *      Get Next IP Multicast entry.
+ * Input:
+ *      pAddress        - The Address ID
+ * Output:
+ *      pIpMcastAddr    - IP Multicast entry
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *      Get the next IP multicast entry after the current entry pointed by pAddress.
+ *      The address of next entry is returned by pAddress. User can use (address + 1)
+ *      as pAddress to call this API again for dumping all IP multicast entries is LUT.
+ */
+extern rtk_api_ret_t rtk_l2_ipMcastAddr_next_get(rtk_uint32 *pAddress, rtk_l2_ipMcastAddr_t *pIpMcastAddr);
+
+/* Function Name:
+ *      rtk_l2_ipMcastAddr_del
+ * Description:
+ *      Delete a ip multicast address entry from the specified device.
+ * Input:
+ *      pIpMcastAddr    - IP Multicast entry
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *      The API can delete a IP multicast address entry from the specified device.
+ */
+extern rtk_api_ret_t rtk_l2_ipMcastAddr_del(rtk_l2_ipMcastAddr_t *pIpMcastAddr);
+
+/* Function Name:
+ *      rtk_l2_ipVidMcastAddr_add
+ * Description:
+ *      Add Lut IP multicast+VID entry
+ * Input:
+ *      pIpVidMcastAddr - IP & VID multicast Entry
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries.
+ *      RT_ERR_PORT_MASK        - Invalid portmask.
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_l2_ipVidMcastAddr_add(rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr);
+
+/* Function Name:
+ *      rtk_l2_ipVidMcastAddr_get
+ * Description:
+ *      Get LUT IP multicast+VID entry.
+ * Input:
+ *      pIpVidMcastAddr - IP & VID multicast Entry
+ * Output:
+ *      pIpVidMcastAddr - IP & VID multicast Entry
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_l2_ipVidMcastAddr_get(rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr);
+
+/* Function Name:
+ *      rtk_l2_ipVidMcastAddr_next_get
+ * Description:
+ *      Get Next IP Multicast+VID entry.
+ * Input:
+ *      pAddress        - The Address ID
+ * Output:
+ *      pIpVidMcastAddr - IP & VID multicast Entry
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *      Get the next IP multicast entry after the current entry pointed by pAddress.
+ *      The address of next entry is returned by pAddress. User can use (address + 1)
+ *      as pAddress to call this API again for dumping all IP multicast entries is LUT.
+ */
+extern rtk_api_ret_t rtk_l2_ipVidMcastAddr_next_get(rtk_uint32 *pAddress, rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr);
+
+/* Function Name:
+ *      rtk_l2_ipVidMcastAddr_del
+ * Description:
+ *      Delete a ip multicast+VID address entry from the specified device.
+ * Input:
+ *      pIpVidMcastAddr - IP & VID multicast Entry
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_l2_ipVidMcastAddr_del(rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr);
+
+/* Function Name:
+ *      rtk_l2_ucastAddr_flush
+ * Description:
+ *      Flush L2 mac address by type in the specified device (both dynamic and static).
+ * Input:
+ *      pConfig - flush configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_VLAN_VID     - Invalid VID parameter.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      flushByVid          - 1: Flush by VID, 0: Don't flush by VID
+ *      vid                 - VID (0 ~ 4095)
+ *      flushByFid          - 1: Flush by FID, 0: Don't flush by FID
+ *      fid                 - FID (0 ~ 15)
+ *      flushByPort         - 1: Flush by Port, 0: Don't flush by Port
+ *      port                - Port ID
+ *      flushByMac          - Not Supported
+ *      ucastAddr           - Not Supported
+ *      flushStaticAddr     - 1: Flush both Static and Dynamic entries, 0: Flush only Dynamic entries
+ *      flushAddrOnAllPorts - 1: Flush VID-matched entries at all ports, 0: Flush VID-matched entries per port.
+ */
+extern rtk_api_ret_t rtk_l2_ucastAddr_flush(rtk_l2_flushCfg_t *pConfig);
+
+/* Function Name:
+ *      rtk_l2_table_clear
+ * Description:
+ *      Flush all static & dynamic entries in LUT.
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_l2_table_clear(void);
+
+/* Function Name:
+ *      rtk_l2_table_clearStatus_get
+ * Description:
+ *      Get table clear status
+ * Input:
+ *      None
+ * Output:
+ *      pStatus - Clear status, 1:Busy, 0:finish
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_l2_table_clearStatus_get(rtk_l2_clearStatus_t *pStatus);
+
+/* Function Name:
+ *      rtk_l2_flushLinkDownPortAddrEnable_set
+ * Description:
+ *      Set HW flush linkdown port mac configuration of the specified device.
+ * Input:
+ *      port - Port id.
+ *      enable - link down flush status
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_ENABLE       - Invalid enable input.
+ * Note:
+ *      The status of flush linkdown port address is as following:
+ *      - DISABLED
+ *      - ENABLED
+ */
+extern rtk_api_ret_t rtk_l2_flushLinkDownPortAddrEnable_set(rtk_port_t port, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_l2_flushLinkDownPortAddrEnable_get
+ * Description:
+ *      Get HW flush linkdown port mac configuration of the specified device.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEnable - link down flush status
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The status of flush linkdown port address is as following:
+ *      - DISABLED
+ *      - ENABLED
+ */
+extern rtk_api_ret_t rtk_l2_flushLinkDownPortAddrEnable_get(rtk_port_t port, rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_l2_agingEnable_set
+ * Description:
+ *      Set L2 LUT aging status per port setting.
+ * Input:
+ *      port    - Port id.
+ *      enable  - Aging status
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_ENABLE       - Invalid enable input.
+ * Note:
+ *      This API can be used to set L2 LUT aging status per port.
+ */
+extern rtk_api_ret_t rtk_l2_agingEnable_set(rtk_port_t port, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_l2_agingEnable_get
+ * Description:
+ *      Get L2 LUT aging status per port setting.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEnable - Aging status
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API can be used to get L2 LUT aging function per port.
+ */
+extern rtk_api_ret_t rtk_l2_agingEnable_get(rtk_port_t port, rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_l2_limitLearningCnt_set
+ * Description:
+ *      Set per-Port auto learning limit number
+ * Input:
+ *      port    - Port id.
+ *      mac_cnt - Auto learning entries limit number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number.
+ *      RT_ERR_LIMITED_L2ENTRY_NUM  - Invalid auto learning limit number
+ * Note:
+ *      The API can set per-port ASIC auto learning limit number from 0(disable learning)
+ *      to 8k.
+ */
+extern rtk_api_ret_t rtk_l2_limitLearningCnt_set(rtk_port_t port, rtk_mac_cnt_t mac_cnt);
+
+/* Function Name:
+ *      rtk_l2_limitLearningCnt_get
+ * Description:
+ *      Get per-Port auto learning limit number
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pMac_cnt - Auto learning entries limit number
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get per-port ASIC auto learning limit number.
+ */
+extern rtk_api_ret_t rtk_l2_limitLearningCnt_get(rtk_port_t port, rtk_mac_cnt_t *pMac_cnt);
+
+/* Function Name:
+ *      rtk_l2_limitSystemLearningCnt_set
+ * Description:
+ *      Set System auto learning limit number
+ * Input:
+ *      mac_cnt - Auto learning entries limit number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_LIMITED_L2ENTRY_NUM  - Invalid auto learning limit number
+ * Note:
+ *      The API can set system ASIC auto learning limit number from 0(disable learning)
+ *      to 2112.
+ */
+extern rtk_api_ret_t rtk_l2_limitSystemLearningCnt_set(rtk_mac_cnt_t mac_cnt);
+
+/* Function Name:
+ *      rtk_l2_limitSystemLearningCnt_get
+ * Description:
+ *      Get System auto learning limit number
+ * Input:
+ *      None
+ * Output:
+ *      pMac_cnt - Auto learning entries limit number
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get system ASIC auto learning limit number.
+ */
+extern rtk_api_ret_t rtk_l2_limitSystemLearningCnt_get(rtk_mac_cnt_t *pMac_cnt);
+
+/* Function Name:
+ *      rtk_l2_limitLearningCntAction_set
+ * Description:
+ *      Configure auto learn over limit number action.
+ * Input:
+ *      port - Port id.
+ *      action - Auto learning entries limit number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_NOT_ALLOWED  - Invalid learn over action
+ * Note:
+ *      The API can set SA unknown packet action while auto learn limit number is over
+ *      The action symbol as following:
+ *      - LIMIT_LEARN_CNT_ACTION_DROP,
+ *      - LIMIT_LEARN_CNT_ACTION_FORWARD,
+ *      - LIMIT_LEARN_CNT_ACTION_TO_CPU,
+ */
+extern rtk_api_ret_t rtk_l2_limitLearningCntAction_set(rtk_port_t port, rtk_l2_limitLearnCntAction_t action);
+
+/* Function Name:
+ *      rtk_l2_limitLearningCntAction_get
+ * Description:
+ *      Get auto learn over limit number action.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pAction - Learn over action
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get SA unknown packet action while auto learn limit number is over
+ *      The action symbol as following:
+ *      - LIMIT_LEARN_CNT_ACTION_DROP,
+ *      - LIMIT_LEARN_CNT_ACTION_FORWARD,
+ *      - LIMIT_LEARN_CNT_ACTION_TO_CPU,
+ */
+extern rtk_api_ret_t rtk_l2_limitLearningCntAction_get(rtk_port_t port, rtk_l2_limitLearnCntAction_t *pAction);
+
+/* Function Name:
+ *      rtk_l2_limitSystemLearningCntAction_set
+ * Description:
+ *      Configure system auto learn over limit number action.
+ * Input:
+ *      port - Port id.
+ *      action - Auto learning entries limit number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_NOT_ALLOWED  - Invalid learn over action
+ * Note:
+ *      The API can set SA unknown packet action while auto learn limit number is over
+ *      The action symbol as following:
+ *      - LIMIT_LEARN_CNT_ACTION_DROP,
+ *      - LIMIT_LEARN_CNT_ACTION_FORWARD,
+ *      - LIMIT_LEARN_CNT_ACTION_TO_CPU,
+ */
+extern rtk_api_ret_t rtk_l2_limitSystemLearningCntAction_set(rtk_l2_limitLearnCntAction_t action);
+
+/* Function Name:
+ *      rtk_l2_limitSystemLearningCntAction_get
+ * Description:
+ *      Get system auto learn over limit number action.
+ * Input:
+ *      None.
+ * Output:
+ *      pAction - Learn over action
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get SA unknown packet action while auto learn limit number is over
+ *      The action symbol as following:
+ *      - LIMIT_LEARN_CNT_ACTION_DROP,
+ *      - LIMIT_LEARN_CNT_ACTION_FORWARD,
+ *      - LIMIT_LEARN_CNT_ACTION_TO_CPU,
+ */
+extern rtk_api_ret_t rtk_l2_limitSystemLearningCntAction_get(rtk_l2_limitLearnCntAction_t *pAction);
+
+/* Function Name:
+ *      rtk_l2_limitSystemLearningCntPortMask_set
+ * Description:
+ *      Configure system auto learn portmask
+ * Input:
+ *      pPortmask - Port Mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK    - Invalid port mask.
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_l2_limitSystemLearningCntPortMask_set(rtk_portmask_t *pPortmask);
+
+/* Function Name:
+ *      rtk_l2_limitSystemLearningCntPortMask_get
+ * Description:
+ *      get system auto learn portmask
+ * Input:
+ *      None
+ * Output:
+ *      pPortmask - Port Mask
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_NULL_POINTER - Null pointer.
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_l2_limitSystemLearningCntPortMask_get(rtk_portmask_t *pPortmask);
+
+/* Function Name:
+ *      rtk_l2_learningCnt_get
+ * Description:
+ *      Get per-Port current auto learning number
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pMac_cnt - ASIC auto learning entries number
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get per-port ASIC auto learning number
+ */
+extern rtk_api_ret_t rtk_l2_learningCnt_get(rtk_port_t port, rtk_mac_cnt_t *pMac_cnt);
+
+/* Function Name:
+ *      rtk_l2_floodPortMask_set
+ * Description:
+ *      Set flooding portmask
+ * Input:
+ *      type - flooding type.
+ *      pFlood_portmask - flooding porkmask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK    - Invalid portmask.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API can set the flooding mask.
+ *      The flooding type is as following:
+ *      - FLOOD_UNKNOWNDA
+ *      - FLOOD_UNKNOWNMC
+ *      - FLOOD_BC
+ */
+extern rtk_api_ret_t rtk_l2_floodPortMask_set(rtk_l2_flood_type_t floood_type, rtk_portmask_t *pFlood_portmask);
+
+/* Function Name:
+ *      rtk_l2_floodPortMask_get
+ * Description:
+ *      Get flooding portmask
+ * Input:
+ *      type - flooding type.
+ * Output:
+ *      pFlood_portmask - flooding porkmask
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API can get the flooding mask.
+ *      The flooding type is as following:
+ *      - FLOOD_UNKNOWNDA
+ *      - FLOOD_UNKNOWNMC
+ *      - FLOOD_BC
+ */
+extern rtk_api_ret_t rtk_l2_floodPortMask_get(rtk_l2_flood_type_t floood_type, rtk_portmask_t *pFlood_portmask);
+
+/* Function Name:
+ *      rtk_l2_localPktPermit_set
+ * Description:
+ *      Set permittion of frames if source port and destination port are the same.
+ * Input:
+ *      port - Port id.
+ *      permit - permittion status
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_ENABLE       - Invalid permit value.
+ * Note:
+ *      This API is setted to permit frame if its source port is equal to destination port.
+ */
+extern rtk_api_ret_t rtk_l2_localPktPermit_set(rtk_port_t port, rtk_enable_t permit);
+
+/* Function Name:
+ *      rtk_l2_localPktPermit_get
+ * Description:
+ *      Get permittion of frames if source port and destination port are the same.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pPermit - permittion status
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API is to get permittion status for frames if its source port is equal to destination port.
+ */
+extern rtk_api_ret_t rtk_l2_localPktPermit_get(rtk_port_t port, rtk_enable_t *pPermit);
+
+/* Function Name:
+ *      rtk_l2_aging_set
+ * Description:
+ *      Set LUT agging out speed
+ * Input:
+ *      aging_time - Agging out time.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - input out of range.
+ * Note:
+ *      The API can set LUT agging out period for each entry and the range is from 14s to 800s.
+ */
+extern rtk_api_ret_t rtk_l2_aging_set(rtk_l2_age_time_t aging_time);
+
+/* Function Name:
+ *      rtk_l2_aging_get
+ * Description:
+ *      Get LUT agging out time
+ * Input:
+ *      None
+ * Output:
+ *      pEnable - Aging status
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get LUT agging out period for each entry.
+ */
+extern rtk_api_ret_t rtk_l2_aging_get(rtk_l2_age_time_t *pAging_time);
+
+/* Function Name:
+ *      rtk_l2_ipMcastAddrLookup_set
+ * Description:
+ *      Set Lut IP multicast lookup function
+ * Input:
+ *      type - Lookup type for IPMC packet.
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK          - OK
+ *      RT_ERR_FAILED      - Failed
+ *      RT_ERR_SMI         - SMI access error
+ * Note:
+ *      This API can work with rtk_l2_ipMcastAddrLookupException_add.
+ *      If users set the lookup type to DIP, the group in exception table
+ *      will be lookup by DIP+SIP
+ *      If users set the lookup type to DIP+SIP, the group in exception table
+ *      will be lookup by only DIP
+ */
+extern rtk_api_ret_t rtk_l2_ipMcastAddrLookup_set(rtk_l2_ipmc_lookup_type_t type);
+
+/* Function Name:
+ *      rtk_l2_ipMcastAddrLookup_get
+ * Description:
+ *      Get Lut IP multicast lookup function
+ * Input:
+ *      None.
+ * Output:
+ *      pType - Lookup type for IPMC packet.
+ * Return:
+ *      RT_ERR_OK          - OK
+ *      RT_ERR_FAILED      - Failed
+ *      RT_ERR_SMI         - SMI access error
+ * Note:
+ *      None.
+ */
+extern rtk_api_ret_t rtk_l2_ipMcastAddrLookup_get(rtk_l2_ipmc_lookup_type_t *pType);
+
+/* Function Name:
+ *      rtk_l2_ipMcastForwardRouterPort_set
+ * Description:
+ *      Set IPMC packet forward to rounter port also or not
+ * Input:
+ *      enabled - 1: Inlcude router port, 0, exclude router port
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK          - OK
+ *      RT_ERR_FAILED      - Failed
+ *      RT_ERR_SMI         - SMI access error
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_l2_ipMcastForwardRouterPort_set(rtk_enable_t enabled);
+
+/* Function Name:
+ *      rtk_l2_ipMcastForwardRouterPort_get
+ * Description:
+ *      Get IPMC packet forward to rounter port also or not
+ * Input:
+ *      None.
+ * Output:
+ *      pEnabled    - 1: Inlcude router port, 0, exclude router port
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_NULL_POINTER - Null pointer
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_l2_ipMcastForwardRouterPort_get(rtk_enable_t *pEnabled);
+
+/* Function Name:
+ *      rtk_l2_ipMcastGroupEntry_add
+ * Description:
+ *      Add an IP Multicast entry to group table
+ * Input:
+ *      ip_addr     - IP address
+ *      vid         - VLAN ID
+ *      pPortmask   - portmask
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK          - OK
+ *      RT_ERR_FAILED      - Failed
+ *      RT_ERR_SMI         - SMI access error
+ *      RT_ERR_TBL_FULL    - Table Full
+ * Note:
+ *      Add an entry to IP Multicast Group table.
+ */
+extern rtk_api_ret_t rtk_l2_ipMcastGroupEntry_add(ipaddr_t ip_addr, rtk_uint32 vid, rtk_portmask_t *pPortmask);
+
+/* Function Name:
+ *      rtk_l2_ipMcastGroupEntry_del
+ * Description:
+ *      Delete an entry from IP Multicast group table
+ * Input:
+ *      ip_addr     - IP address
+ *      vid         - VLAN ID
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK          - OK
+ *      RT_ERR_FAILED      - Failed
+ *      RT_ERR_SMI         - SMI access error
+ *      RT_ERR_TBL_FULL    - Table Full
+ * Note:
+ *      Delete an entry from IP Multicast group table.
+ */
+extern rtk_api_ret_t rtk_l2_ipMcastGroupEntry_del(ipaddr_t ip_addr, rtk_uint32 vid);
+
+/* Function Name:
+ *      rtk_l2_ipMcastGroupEntry_get
+ * Description:
+ *      get an entry from IP Multicast group table
+ * Input:
+ *      ip_addr     - IP address
+ *      vid         - VLAN ID
+ * Output:
+ *      pPortmask   - member port mask
+ * Return:
+ *      RT_ERR_OK          - OK
+ *      RT_ERR_FAILED      - Failed
+ *      RT_ERR_SMI         - SMI access error
+ *      RT_ERR_TBL_FULL    - Table Full
+ * Note:
+ *      Delete an entry from IP Multicast group table.
+ */
+extern rtk_api_ret_t rtk_l2_ipMcastGroupEntry_get(ipaddr_t ip_addr, rtk_uint32 vid, rtk_portmask_t *pPortmask);
+
+/* Function Name:
+ *      rtk_l2_entry_get
+ * Description:
+ *      Get LUT unicast entry.
+ * Input:
+ *      pL2_entry - Index field in the structure.
+ * Output:
+ *      pL2_entry - other fields such as MAC, port, age...
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_L2_EMPTY_ENTRY   - Empty LUT entry.
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ * Note:
+ *      This API is used to get address by index from 0~2111.
+ */
+extern rtk_api_ret_t rtk_l2_entry_get(rtk_l2_addr_table_t *pL2_entry);
+
+
+#endif /* __RTK_API_L2_H__ */
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/leaky.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/leaky.h
new file mode 100644
index 0000000..13ef60d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/leaky.h
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes Leaky module high-layer API defination
+ *
+ */
+
+#ifndef __RTK_API_LEAKY_H__
+#define __RTK_API_LEAKY_H__
+
+
+typedef enum rtk_leaky_type_e
+{
+    LEAKY_BRG_GROUP = 0,
+    LEAKY_FD_PAUSE,
+    LEAKY_SP_MCAST,
+    LEAKY_1X_PAE,
+    LEAKY_UNDEF_BRG_04,
+    LEAKY_UNDEF_BRG_05,
+    LEAKY_UNDEF_BRG_06,
+    LEAKY_UNDEF_BRG_07,
+    LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS,
+    LEAKY_UNDEF_BRG_09,
+    LEAKY_UNDEF_BRG_0A,
+    LEAKY_UNDEF_BRG_0B,
+    LEAKY_UNDEF_BRG_0C,
+    LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS,
+    LEAKY_8021AB,
+    LEAKY_UNDEF_BRG_0F,
+    LEAKY_BRG_MNGEMENT,
+    LEAKY_UNDEFINED_11,
+    LEAKY_UNDEFINED_12,
+    LEAKY_UNDEFINED_13,
+    LEAKY_UNDEFINED_14,
+    LEAKY_UNDEFINED_15,
+    LEAKY_UNDEFINED_16,
+    LEAKY_UNDEFINED_17,
+    LEAKY_UNDEFINED_18,
+    LEAKY_UNDEFINED_19,
+    LEAKY_UNDEFINED_1A,
+    LEAKY_UNDEFINED_1B,
+    LEAKY_UNDEFINED_1C,
+    LEAKY_UNDEFINED_1D,
+    LEAKY_UNDEFINED_1E,
+    LEAKY_UNDEFINED_1F,
+    LEAKY_GMRP,
+    LEAKY_GVRP,
+    LEAKY_UNDEF_GARP_22,
+    LEAKY_UNDEF_GARP_23,
+    LEAKY_UNDEF_GARP_24,
+    LEAKY_UNDEF_GARP_25,
+    LEAKY_UNDEF_GARP_26,
+    LEAKY_UNDEF_GARP_27,
+    LEAKY_UNDEF_GARP_28,
+    LEAKY_UNDEF_GARP_29,
+    LEAKY_UNDEF_GARP_2A,
+    LEAKY_UNDEF_GARP_2B,
+    LEAKY_UNDEF_GARP_2C,
+    LEAKY_UNDEF_GARP_2D,
+    LEAKY_UNDEF_GARP_2E,
+    LEAKY_UNDEF_GARP_2F,
+    LEAKY_IGMP,
+    LEAKY_IPMULTICAST,
+    LEAKY_CDP,
+    LEAKY_CSSTP,
+    LEAKY_LLDP,
+    LEAKY_END,
+}rtk_leaky_type_t;
+
+/* Function Name:
+ *      rtk_leaky_vlan_set
+ * Description:
+ *      Set VLAN leaky.
+ * Input:
+ *      type - Packet type for VLAN leaky.
+ *      enable - Leaky status.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_ENABLE       - Invalid enable input
+ * Note:
+ *      This API can set VLAN leaky for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP packets.
+ *      The leaky frame types are as following:
+ *      - LEAKY_BRG_GROUP,
+ *      - LEAKY_FD_PAUSE,
+ *      - LEAKY_SP_MCAST,
+ *      - LEAKY_1X_PAE,
+ *      - LEAKY_UNDEF_BRG_04,
+ *      - LEAKY_UNDEF_BRG_05,
+ *      - LEAKY_UNDEF_BRG_06,
+ *      - LEAKY_UNDEF_BRG_07,
+ *      - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS,
+ *      - LEAKY_UNDEF_BRG_09,
+ *      - LEAKY_UNDEF_BRG_0A,
+ *      - LEAKY_UNDEF_BRG_0B,
+ *      - LEAKY_UNDEF_BRG_0C,
+ *      - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS,
+ *      - LEAKY_8021AB,
+ *      - LEAKY_UNDEF_BRG_0F,
+ *      - LEAKY_BRG_MNGEMENT,
+ *      - LEAKY_UNDEFINED_11,
+ *      - LEAKY_UNDEFINED_12,
+ *      - LEAKY_UNDEFINED_13,
+ *      - LEAKY_UNDEFINED_14,
+ *      - LEAKY_UNDEFINED_15,
+ *      - LEAKY_UNDEFINED_16,
+ *      - LEAKY_UNDEFINED_17,
+ *      - LEAKY_UNDEFINED_18,
+ *      - LEAKY_UNDEFINED_19,
+ *      - LEAKY_UNDEFINED_1A,
+ *      - LEAKY_UNDEFINED_1B,
+ *      - LEAKY_UNDEFINED_1C,
+ *      - LEAKY_UNDEFINED_1D,
+ *      - LEAKY_UNDEFINED_1E,
+ *      - LEAKY_UNDEFINED_1F,
+ *      - LEAKY_GMRP,
+ *      - LEAKY_GVRP,
+ *      - LEAKY_UNDEF_GARP_22,
+ *      - LEAKY_UNDEF_GARP_23,
+ *      - LEAKY_UNDEF_GARP_24,
+ *      - LEAKY_UNDEF_GARP_25,
+ *      - LEAKY_UNDEF_GARP_26,
+ *      - LEAKY_UNDEF_GARP_27,
+ *      - LEAKY_UNDEF_GARP_28,
+ *      - LEAKY_UNDEF_GARP_29,
+ *      - LEAKY_UNDEF_GARP_2A,
+ *      - LEAKY_UNDEF_GARP_2B,
+ *      - LEAKY_UNDEF_GARP_2C,
+ *      - LEAKY_UNDEF_GARP_2D,
+ *      - LEAKY_UNDEF_GARP_2E,
+ *      - LEAKY_UNDEF_GARP_2F,
+ *      - LEAKY_IGMP,
+ *      - LEAKY_IPMULTICAST.
+ *      - LEAKY_CDP,
+ *      - LEAKY_CSSTP,
+ *      - LEAKY_LLDP.
+ */
+extern rtk_api_ret_t rtk_leaky_vlan_set(rtk_leaky_type_t type, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_leaky_vlan_get
+ * Description:
+ *      Get VLAN leaky.
+ * Input:
+ *      type - Packet type for VLAN leaky.
+ * Output:
+ *      pEnable - Leaky status.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API can get VLAN leaky status for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP  packets.
+ *      The leaky frame types are as following:
+ *      - LEAKY_BRG_GROUP,
+ *      - LEAKY_FD_PAUSE,
+ *      - LEAKY_SP_MCAST,
+ *      - LEAKY_1X_PAE,
+ *      - LEAKY_UNDEF_BRG_04,
+ *      - LEAKY_UNDEF_BRG_05,
+ *      - LEAKY_UNDEF_BRG_06,
+ *      - LEAKY_UNDEF_BRG_07,
+ *      - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS,
+ *      - LEAKY_UNDEF_BRG_09,
+ *      - LEAKY_UNDEF_BRG_0A,
+ *      - LEAKY_UNDEF_BRG_0B,
+ *      - LEAKY_UNDEF_BRG_0C,
+ *      - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS,
+ *      - LEAKY_8021AB,
+ *      - LEAKY_UNDEF_BRG_0F,
+ *      - LEAKY_BRG_MNGEMENT,
+ *      - LEAKY_UNDEFINED_11,
+ *      - LEAKY_UNDEFINED_12,
+ *      - LEAKY_UNDEFINED_13,
+ *      - LEAKY_UNDEFINED_14,
+ *      - LEAKY_UNDEFINED_15,
+ *      - LEAKY_UNDEFINED_16,
+ *      - LEAKY_UNDEFINED_17,
+ *      - LEAKY_UNDEFINED_18,
+ *      - LEAKY_UNDEFINED_19,
+ *      - LEAKY_UNDEFINED_1A,
+ *      - LEAKY_UNDEFINED_1B,
+ *      - LEAKY_UNDEFINED_1C,
+ *      - LEAKY_UNDEFINED_1D,
+ *      - LEAKY_UNDEFINED_1E,
+ *      - LEAKY_UNDEFINED_1F,
+ *      - LEAKY_GMRP,
+ *      - LEAKY_GVRP,
+ *      - LEAKY_UNDEF_GARP_22,
+ *      - LEAKY_UNDEF_GARP_23,
+ *      - LEAKY_UNDEF_GARP_24,
+ *      - LEAKY_UNDEF_GARP_25,
+ *      - LEAKY_UNDEF_GARP_26,
+ *      - LEAKY_UNDEF_GARP_27,
+ *      - LEAKY_UNDEF_GARP_28,
+ *      - LEAKY_UNDEF_GARP_29,
+ *      - LEAKY_UNDEF_GARP_2A,
+ *      - LEAKY_UNDEF_GARP_2B,
+ *      - LEAKY_UNDEF_GARP_2C,
+ *      - LEAKY_UNDEF_GARP_2D,
+ *      - LEAKY_UNDEF_GARP_2E,
+ *      - LEAKY_UNDEF_GARP_2F,
+ *      - LEAKY_IGMP,
+ *      - LEAKY_IPMULTICAST.
+ *      - LEAKY_CDP,
+ *      - LEAKY_CSSTP,
+ *      - LEAKY_LLDP.
+ */
+extern rtk_api_ret_t rtk_leaky_vlan_get(rtk_leaky_type_t type, rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_leaky_portIsolation_set
+ * Description:
+ *      Set port isolation leaky.
+ * Input:
+ *      type - Packet type for port isolation leaky.
+ *      enable - Leaky status.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_ENABLE       - Invalid enable input
+ * Note:
+ *      This API can set port isolation leaky for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP  packets.
+ *      The leaky frame types are as following:
+ *      - LEAKY_BRG_GROUP,
+ *      - LEAKY_FD_PAUSE,
+ *      - LEAKY_SP_MCAST,
+ *      - LEAKY_1X_PAE,
+ *      - LEAKY_UNDEF_BRG_04,
+ *      - LEAKY_UNDEF_BRG_05,
+ *      - LEAKY_UNDEF_BRG_06,
+ *      - LEAKY_UNDEF_BRG_07,
+ *      - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS,
+ *      - LEAKY_UNDEF_BRG_09,
+ *      - LEAKY_UNDEF_BRG_0A,
+ *      - LEAKY_UNDEF_BRG_0B,
+ *      - LEAKY_UNDEF_BRG_0C,
+ *      - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS,
+ *      - LEAKY_8021AB,
+ *      - LEAKY_UNDEF_BRG_0F,
+ *      - LEAKY_BRG_MNGEMENT,
+ *      - LEAKY_UNDEFINED_11,
+ *      - LEAKY_UNDEFINED_12,
+ *      - LEAKY_UNDEFINED_13,
+ *      - LEAKY_UNDEFINED_14,
+ *      - LEAKY_UNDEFINED_15,
+ *      - LEAKY_UNDEFINED_16,
+ *      - LEAKY_UNDEFINED_17,
+ *      - LEAKY_UNDEFINED_18,
+ *      - LEAKY_UNDEFINED_19,
+ *      - LEAKY_UNDEFINED_1A,
+ *      - LEAKY_UNDEFINED_1B,
+ *      - LEAKY_UNDEFINED_1C,
+ *      - LEAKY_UNDEFINED_1D,
+ *      - LEAKY_UNDEFINED_1E,
+ *      - LEAKY_UNDEFINED_1F,
+ *      - LEAKY_GMRP,
+ *      - LEAKY_GVRP,
+ *      - LEAKY_UNDEF_GARP_22,
+ *      - LEAKY_UNDEF_GARP_23,
+ *      - LEAKY_UNDEF_GARP_24,
+ *      - LEAKY_UNDEF_GARP_25,
+ *      - LEAKY_UNDEF_GARP_26,
+ *      - LEAKY_UNDEF_GARP_27,
+ *      - LEAKY_UNDEF_GARP_28,
+ *      - LEAKY_UNDEF_GARP_29,
+ *      - LEAKY_UNDEF_GARP_2A,
+ *      - LEAKY_UNDEF_GARP_2B,
+ *      - LEAKY_UNDEF_GARP_2C,
+ *      - LEAKY_UNDEF_GARP_2D,
+ *      - LEAKY_UNDEF_GARP_2E,
+ *      - LEAKY_UNDEF_GARP_2F,
+ *      - LEAKY_IGMP,
+ *      - LEAKY_IPMULTICAST.
+ *      - LEAKY_CDP,
+ *      - LEAKY_CSSTP,
+ *      - LEAKY_LLDP.
+ */
+extern rtk_api_ret_t rtk_leaky_portIsolation_set(rtk_leaky_type_t type, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_leaky_portIsolation_get
+ * Description:
+ *      Get port isolation leaky.
+ * Input:
+ *      type - Packet type for port isolation leaky.
+ * Output:
+ *      pEnable - Leaky status.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API can get port isolation leaky status for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP  packets.
+ *      The leaky frame types are as following:
+ *      - LEAKY_BRG_GROUP,
+ *      - LEAKY_FD_PAUSE,
+ *      - LEAKY_SP_MCAST,
+ *      - LEAKY_1X_PAE,
+ *      - LEAKY_UNDEF_BRG_04,
+ *      - LEAKY_UNDEF_BRG_05,
+ *      - LEAKY_UNDEF_BRG_06,
+ *      - LEAKY_UNDEF_BRG_07,
+ *      - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS,
+ *      - LEAKY_UNDEF_BRG_09,
+ *      - LEAKY_UNDEF_BRG_0A,
+ *      - LEAKY_UNDEF_BRG_0B,
+ *      - LEAKY_UNDEF_BRG_0C,
+ *      - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS,
+ *      - LEAKY_8021AB,
+ *      - LEAKY_UNDEF_BRG_0F,
+ *      - LEAKY_BRG_MNGEMENT,
+ *      - LEAKY_UNDEFINED_11,
+ *      - LEAKY_UNDEFINED_12,
+ *      - LEAKY_UNDEFINED_13,
+ *      - LEAKY_UNDEFINED_14,
+ *      - LEAKY_UNDEFINED_15,
+ *      - LEAKY_UNDEFINED_16,
+ *      - LEAKY_UNDEFINED_17,
+ *      - LEAKY_UNDEFINED_18,
+ *      - LEAKY_UNDEFINED_19,
+ *      - LEAKY_UNDEFINED_1A,
+ *      - LEAKY_UNDEFINED_1B,
+ *      - LEAKY_UNDEFINED_1C,
+ *      - LEAKY_UNDEFINED_1D,
+ *      - LEAKY_UNDEFINED_1E,
+ *      - LEAKY_UNDEFINED_1F,
+ *      - LEAKY_GMRP,
+ *      - LEAKY_GVRP,
+ *      - LEAKY_UNDEF_GARP_22,
+ *      - LEAKY_UNDEF_GARP_23,
+ *      - LEAKY_UNDEF_GARP_24,
+ *      - LEAKY_UNDEF_GARP_25,
+ *      - LEAKY_UNDEF_GARP_26,
+ *      - LEAKY_UNDEF_GARP_27,
+ *      - LEAKY_UNDEF_GARP_28,
+ *      - LEAKY_UNDEF_GARP_29,
+ *      - LEAKY_UNDEF_GARP_2A,
+ *      - LEAKY_UNDEF_GARP_2B,
+ *      - LEAKY_UNDEF_GARP_2C,
+ *      - LEAKY_UNDEF_GARP_2D,
+ *      - LEAKY_UNDEF_GARP_2E,
+ *      - LEAKY_UNDEF_GARP_2F,
+ *      - LEAKY_IGMP,
+ *      - LEAKY_IPMULTICAST.
+ *      - LEAKY_CDP,
+ *      - LEAKY_CSSTP,
+ *      - LEAKY_LLDP.
+ */
+extern rtk_api_ret_t rtk_leaky_portIsolation_get(rtk_leaky_type_t type, rtk_enable_t *pEnable);
+
+#endif /* __RTK_API_LEAKY_H__ */
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/led.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/led.h
new file mode 100644
index 0000000..71acc7c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/led.h
@@ -0,0 +1,481 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes LED module high-layer API defination
+ *
+ */
+
+#ifndef __RTK_API_LED_H__
+#define __RTK_API_LED_H__
+
+typedef enum rtk_led_operation_e
+{
+    LED_OP_SCAN=0,
+    LED_OP_PARALLEL,
+    LED_OP_SERIAL,
+    LED_OP_END,
+}rtk_led_operation_t;
+
+
+typedef enum rtk_led_active_e
+{
+    LED_ACTIVE_HIGH=0,
+    LED_ACTIVE_LOW,
+    LED_ACTIVE_END,
+}rtk_led_active_t;
+
+typedef enum rtk_led_config_e
+{
+    LED_CONFIG_LEDOFF=0,
+    LED_CONFIG_DUPCOL,
+    LED_CONFIG_LINK_ACT,
+    LED_CONFIG_SPD1000,
+    LED_CONFIG_SPD100,
+    LED_CONFIG_SPD10,
+    LED_CONFIG_SPD1000ACT,
+    LED_CONFIG_SPD100ACT,
+    LED_CONFIG_SPD10ACT,
+    LED_CONFIG_SPD10010ACT,
+    LED_CONFIG_LOOPDETECT,
+    LED_CONFIG_EEE,
+    LED_CONFIG_LINKRX,
+    LED_CONFIG_LINKTX,
+    LED_CONFIG_MASTER,
+    LED_CONFIG_ACT,
+    LED_CONFIG_END,
+}rtk_led_congig_t;
+
+typedef struct rtk_led_ability_s
+{
+    rtk_enable_t link_10m;
+    rtk_enable_t link_100m;
+    rtk_enable_t link_500m;
+    rtk_enable_t link_1000m;
+    rtk_enable_t act_rx;
+    rtk_enable_t act_tx;
+}rtk_led_ability_t;
+
+typedef enum rtk_led_blink_rate_e
+{
+    LED_BLINKRATE_32MS=0,
+    LED_BLINKRATE_64MS,
+    LED_BLINKRATE_128MS,
+    LED_BLINKRATE_256MS,
+    LED_BLINKRATE_512MS,
+    LED_BLINKRATE_1024MS,
+    LED_BLINKRATE_48MS,
+    LED_BLINKRATE_96MS,
+    LED_BLINKRATE_END,
+}rtk_led_blink_rate_t;
+
+typedef enum rtk_led_group_e
+{
+    LED_GROUP_0 = 0,
+    LED_GROUP_1,
+    LED_GROUP_2,
+    LED_GROUP_END
+}rtk_led_group_t;
+
+
+typedef enum rtk_led_force_mode_e
+{
+    LED_FORCE_NORMAL=0,
+    LED_FORCE_BLINK,
+    LED_FORCE_OFF,
+    LED_FORCE_ON,
+    LED_FORCE_END
+}rtk_led_force_mode_t;
+
+typedef enum rtk_led_serialOutput_e
+{
+    SERIAL_LED_NONE = 0,
+    SERIAL_LED_0,
+    SERIAL_LED_0_1,
+    SERIAL_LED_0_2,
+    SERIAL_LED_END,
+}rtk_led_serialOutput_t;
+
+
+/* Function Name:
+ *      rtk_led_enable_set
+ * Description:
+ *      Set Led enable congiuration
+ * Input:
+ *      group       - LED group id.
+ *      pPortmask    - LED enable port mask.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can be used to enable LED per port per group.
+ */
+extern rtk_api_ret_t rtk_led_enable_set(rtk_led_group_t group, rtk_portmask_t *pPortmask);
+
+/* Function Name:
+ *      rtk_led_enable_get
+ * Description:
+ *      Get Led enable congiuration
+ * Input:
+ *      group - LED group id.
+ * Output:
+ *      pPortmask - LED enable port mask.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can be used to get LED enable status.
+ */
+extern rtk_api_ret_t rtk_led_enable_get(rtk_led_group_t group, rtk_portmask_t *pPortmask);
+
+/* Function Name:
+ *      rtk_led_operation_set
+ * Description:
+ *      Set Led operation mode
+ * Input:
+ *      mode - LED operation mode.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can set Led operation mode.
+ *      The modes that can be set are as following:
+ *      - LED_OP_SCAN,
+ *      - LED_OP_PARALLEL,
+ *      - LED_OP_SERIAL,
+ */
+extern rtk_api_ret_t rtk_led_operation_set(rtk_led_operation_t mode);
+
+/* Function Name:
+ *      rtk_led_operation_get
+ * Description:
+ *      Get Led operation mode
+ * Input:
+ *      None
+ * Output:
+ *      pMode - Support LED operation mode.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get Led operation mode.
+ *      The modes that can be set are as following:
+ *      - LED_OP_SCAN,
+ *      - LED_OP_PARALLEL,
+ *      - LED_OP_SERIAL,
+ */
+extern rtk_api_ret_t rtk_led_operation_get(rtk_led_operation_t *pMode);
+
+/* Function Name:
+ *      rtk_led_modeForce_set
+ * Description:
+ *      Set Led group to congiuration force mode
+ * Input:
+ *      port    - port ID
+ *      group   - Support LED group id.
+ *      mode    - Support LED force mode.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Error Port ID
+ * Note:
+ *      The API can force to one force mode.
+ *      The force modes that can be set are as following:
+ *      - LED_FORCE_NORMAL,
+ *      - LED_FORCE_BLINK,
+ *      - LED_FORCE_OFF,
+ *      - LED_FORCE_ON.
+ */
+extern rtk_api_ret_t rtk_led_modeForce_set(rtk_port_t port, rtk_led_group_t group, rtk_led_force_mode_t mode);
+
+/* Function Name:
+ *      rtk_led_modeForce_get
+ * Description:
+ *      Get Led group to congiuration force mode
+ * Input:
+ *      port  - port ID
+ *      group - Support LED group id.
+ *      pMode - Support LED force mode.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Error Port ID
+ * Note:
+ *      The API can get forced Led group mode.
+ *      The force modes that can be set are as following:
+ *      - LED_FORCE_NORMAL,
+ *      - LED_FORCE_BLINK,
+ *      - LED_FORCE_OFF,
+ *      - LED_FORCE_ON.
+ */
+extern rtk_api_ret_t rtk_led_modeForce_get(rtk_port_t port, rtk_led_group_t group, rtk_led_force_mode_t *pMode);
+
+/* Function Name:
+ *      rtk_led_blinkRate_set
+ * Description:
+ *      Set LED blinking rate
+ * Input:
+ *      blinkRate - blinking rate.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      ASIC support 6 types of LED blinking rates at 43ms, 84ms, 120ms, 170ms, 340ms and 670ms.
+ */
+extern rtk_api_ret_t rtk_led_blinkRate_set(rtk_led_blink_rate_t blinkRate);
+
+/* Function Name:
+ *      rtk_led_blinkRate_get
+ * Description:
+ *      Get LED blinking rate at mode 0 to mode 3
+ * Input:
+ *      None
+ * Output:
+ *      pBlinkRate - blinking rate.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      There are  6 types of LED blinking rates at 43ms, 84ms, 120ms, 170ms, 340ms and 670ms.
+ */
+extern rtk_api_ret_t rtk_led_blinkRate_get(rtk_led_blink_rate_t *pBlinkRate);
+
+/* Function Name:
+ *      rtk_led_groupConfig_set
+ * Description:
+ *      Set per group Led to congiuration mode
+ * Input:
+ *      group   - LED group.
+ *      config  - LED configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can set LED indicated information configuration for each LED group with 1 to 1 led mapping to each port.
+ *      - Definition  LED Statuses      Description
+ *      - 0000        LED_Off           LED pin Tri-State.
+ *      - 0001        Dup/Col           Collision, Full duplex Indicator.
+ *      - 0010        Link/Act          Link, Activity Indicator.
+ *      - 0011        Spd1000           1000Mb/s Speed Indicator.
+ *      - 0100        Spd100            100Mb/s Speed Indicator.
+ *      - 0101        Spd10             10Mb/s Speed Indicator.
+ *      - 0110        Spd1000/Act       1000Mb/s Speed/Activity Indicator.
+ *      - 0111        Spd100/Act        100Mb/s Speed/Activity Indicator.
+ *      - 1000        Spd10/Act         10Mb/s Speed/Activity Indicator.
+ *      - 1001        Spd100 (10)/Act   10/100Mb/s Speed/Activity Indicator.
+ *      - 1010        LoopDetect        LoopDetect Indicator.
+ *      - 1011        EEE               EEE Indicator.
+ *      - 1100        Link/Rx           Link, Activity Indicator.
+ *      - 1101        Link/Tx           Link, Activity Indicator.
+ *      - 1110        Master            Link on Master Indicator.
+ *      - 1111        Act               Activity Indicator. Low for link established.
+ */
+extern rtk_api_ret_t rtk_led_groupConfig_set(rtk_led_group_t group, rtk_led_congig_t config);
+
+/* Function Name:
+ *      rtk_led_groupConfig_get
+ * Description:
+ *      Get Led group congiuration mode
+ * Input:
+ *      group - LED group.
+ * Output:
+ *      pConfig - LED configuration.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *       The API can get LED indicated information configuration for each LED group.
+ */
+extern rtk_api_ret_t rtk_led_groupConfig_get(rtk_led_group_t group, rtk_led_congig_t *pConfig);
+
+/* Function Name:
+ *      rtk_led_groupAbility_set
+ * Description:
+ *      Configure per group Led ability
+ * Input:
+ *      group    - LED group.
+ *      pAbility - LED ability
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      None.
+ */
+
+extern rtk_api_ret_t rtk_led_groupAbility_set(rtk_led_group_t group, rtk_led_ability_t *pAbility);
+
+/* Function Name:
+ *      rtk_led_groupAbility_get
+ * Description:
+ *      Get per group Led ability
+ * Input:
+ *      group    - LED group.
+ *      pAbility - LED ability
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      None.
+ */
+
+extern rtk_api_ret_t rtk_led_groupAbility_get(rtk_led_group_t group, rtk_led_ability_t *pAbility);
+
+/* Function Name:
+ *      rtk_led_serialMode_set
+ * Description:
+ *      Set Led serial mode active congiuration
+ * Input:
+ *      active - LED group.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can set LED serial mode active congiuration.
+ */
+extern rtk_api_ret_t rtk_led_serialMode_set(rtk_led_active_t active);
+
+/* Function Name:
+ *      rtk_led_serialMode_get
+ * Description:
+ *      Get Led group congiuration mode
+ * Input:
+ *      group - LED group.
+ * Output:
+ *      pConfig - LED configuration.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *       The API can get LED serial mode active configuration.
+ */
+extern rtk_api_ret_t rtk_led_serialMode_get(rtk_led_active_t *pActive);
+
+/* Function Name:
+ *      rtk_led_OutputEnable_set
+ * Description:
+ *      This API set LED I/O state.
+ * Input:
+ *      enabled     - LED I/O state
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error parameter
+ * Note:
+ *      This API set LED I/O state.
+ */
+extern rtk_api_ret_t rtk_led_OutputEnable_set(rtk_enable_t state);
+
+
+/* Function Name:
+ *      rtk_led_OutputEnable_get
+ * Description:
+ *      This API get LED I/O state.
+ * Input:
+ *      None.
+ * Output:
+ *      pEnabled        - LED I/O state
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error parameter
+ * Note:
+ *      This API set current LED I/O  state.
+ */
+extern rtk_api_ret_t rtk_led_OutputEnable_get(rtk_enable_t *pState);
+
+/* Function Name:
+ *      rtk_led_serialModePortmask_set
+ * Description:
+ *      This API configure Serial LED output Group and portmask
+ * Input:
+ *      output          - output group
+ *      pPortmask       - output portmask
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error parameter
+ * Note:
+ *      None.
+ */
+extern rtk_api_ret_t rtk_led_serialModePortmask_set(rtk_led_serialOutput_t output, rtk_portmask_t *pPortmask);
+
+/* Function Name:
+ *      rtk_led_serialModePortmask_get
+ * Description:
+ *      This API get Serial LED output Group and portmask
+ * Input:
+ *      None.
+ * Output:
+ *      pOutput         - output group
+ *      pPortmask       - output portmask
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error parameter
+ * Note:
+ *      None.
+ */
+extern rtk_api_ret_t rtk_led_serialModePortmask_get(rtk_led_serialOutput_t *pOutput, rtk_portmask_t *pPortmask);
+
+#endif /* __RTK_API_LED_H__ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/mirror.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/mirror.h
new file mode 100644
index 0000000..1e984b7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/mirror.h
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes Mirror module high-layer API defination
+ *
+ */
+
+#ifndef __RTK_API_MIRROR_H__
+#define __RTK_API_MIRROR_H__
+
+typedef enum rtk_mirror_keep_e
+{
+    MIRROR_FOLLOW_VLAN = 0,
+    MIRROR_KEEP_ORIGINAL,
+    MIRROR_KEEP_END
+}rtk_mirror_keep_t;
+
+
+/* Function Name:
+ *      rtk_mirror_portBased_set
+ * Description:
+ *      Set port mirror function.
+ * Input:
+ *      mirroring_port          - Monitor port.
+ *      pMirrored_rx_portmask   - Rx mirror port mask.
+ *      pMirrored_tx_portmask   - Tx mirror port mask.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_PORT_MASK    - Invalid portmask.
+ * Note:
+ *      The API is to set mirror function of source port and mirror port.
+ *      The mirror port can only be set to one port and the TX and RX mirror ports
+ *      should be identical.
+ */
+extern rtk_api_ret_t rtk_mirror_portBased_set(rtk_port_t mirroring_port, rtk_portmask_t *pMirrored_rx_portmask, rtk_portmask_t *pMirrored_tx_portmask);
+
+/* Function Name:
+ *      rtk_mirror_portBased_get
+ * Description:
+ *      Get port mirror function.
+ * Input:
+ *      None
+ * Output:
+ *      pMirroring_port         - Monitor port.
+ *      pMirrored_rx_portmask   - Rx mirror port mask.
+ *      pMirrored_tx_portmask   - Tx mirror port mask.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API is to get mirror function of source port and mirror port.
+ */
+extern rtk_api_ret_t rtk_mirror_portBased_get(rtk_port_t* pMirroring_port, rtk_portmask_t *pMirrored_rx_portmask, rtk_portmask_t *pMirrored_tx_portmask);
+
+/* Function Name:
+ *      rtk_mirror_portIso_set
+ * Description:
+ *      Set mirror port isolation.
+ * Input:
+ *      enable |Mirror isolation status.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_ENABLE       - Invalid enable input
+ * Note:
+ *      The API is to set mirror isolation function that prevent normal forwarding packets to miror port.
+ */
+extern rtk_api_ret_t rtk_mirror_portIso_set(rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_mirror_portIso_get
+ * Description:
+ *      Get mirror port isolation.
+ * Input:
+ *      None
+ * Output:
+ *      pEnable |Mirror isolation status.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API is to get mirror isolation status.
+ */
+extern rtk_api_ret_t rtk_mirror_portIso_get(rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_mirror_vlanLeaky_set
+ * Description:
+ *      Set mirror VLAN leaky.
+ * Input:
+ *      txenable -TX leaky enable.
+ *      rxenable - RX leaky enable.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_ENABLE       - Invalid enable input
+ * Note:
+ *      The API is to set mirror VLAN leaky function forwarding packets to miror port.
+ */
+extern rtk_api_ret_t rtk_mirror_vlanLeaky_set(rtk_enable_t txenable, rtk_enable_t rxenable);
+
+
+/* Function Name:
+ *      rtk_mirror_vlanLeaky_get
+ * Description:
+ *      Get mirror VLAN leaky.
+ * Input:
+ *      None
+ * Output:
+ *      pTxenable - TX leaky enable.
+ *      pRxenable - RX leaky enable.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API is to get mirror VLAN leaky status.
+ */
+extern rtk_api_ret_t rtk_mirror_vlanLeaky_get(rtk_enable_t *pTxenable, rtk_enable_t *pRxenable);
+
+/* Function Name:
+ *      rtk_mirror_isolationLeaky_set
+ * Description:
+ *      Set mirror Isolation leaky.
+ * Input:
+ *      txenable -TX leaky enable.
+ *      rxenable - RX leaky enable.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_ENABLE       - Invalid enable input
+ * Note:
+ *      The API is to set mirror VLAN leaky function forwarding packets to miror port.
+ */
+extern rtk_api_ret_t rtk_mirror_isolationLeaky_set(rtk_enable_t txenable, rtk_enable_t rxenable);
+
+/* Function Name:
+ *      rtk_mirror_isolationLeaky_get
+ * Description:
+ *      Get mirror isolation leaky.
+ * Input:
+ *      None
+ * Output:
+ *      pTxenable - TX leaky enable.
+ *      pRxenable - RX leaky enable.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API is to get mirror isolation leaky status.
+ */
+extern rtk_api_ret_t rtk_mirror_isolationLeaky_get(rtk_enable_t *pTxenable, rtk_enable_t *pRxenable);
+
+/* Function Name:
+ *      rtk_mirror_keep_set
+ * Description:
+ *      Set mirror packet format keep.
+ * Input:
+ *      mode - -mirror keep mode.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_ENABLE       - Invalid enable input
+ * Note:
+ *      The API is to set  -mirror keep mode.
+ *      The mirror keep mode is as following:
+ *      - MIRROR_FOLLOW_VLAN
+ *      - MIRROR_KEEP_ORIGINAL
+ *      - MIRROR_KEEP_END
+ */
+extern rtk_api_ret_t rtk_mirror_keep_set(rtk_mirror_keep_t mode);
+
+
+/* Function Name:
+ *      rtk_mirror_keep_get
+ * Description:
+ *      Get mirror packet format keep.
+ * Input:
+ *      None
+ * Output:
+ *      pMode -mirror keep mode.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API is to get mirror keep mode.
+  *      The mirror keep mode is as following:
+ *      - MIRROR_FOLLOW_VLAN
+ *      - MIRROR_KEEP_ORIGINAL
+ *      - MIRROR_KEEP_END
+ */
+extern rtk_api_ret_t rtk_mirror_keep_get(rtk_mirror_keep_t *pMode);
+
+/* Function Name:
+ *      rtk_mirror_override_set
+ * Description:
+ *      Set port mirror override function.
+ * Input:
+ *      rxMirror        - 1: output mirrored packet, 0: output normal forward packet
+ *      txMirror        - 1: output mirrored packet, 0: output normal forward packet
+ *      aclMirror       - 1: output mirrored packet, 0: output normal forward packet
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      The API is to set mirror override function.
+ *      This function control the output format when a port output
+ *      normal forward & mirrored packet at the same time.
+ */
+extern rtk_api_ret_t rtk_mirror_override_set(rtk_enable_t rxMirror, rtk_enable_t txMirror, rtk_enable_t aclMirror);
+
+/* Function Name:
+ *      rtk_mirror_override_get
+ * Description:
+ *      Get port mirror override function.
+ * Input:
+ *      None
+ * Output:
+ *      pRxMirror       - 1: output mirrored packet, 0: output normal forward packet
+ *      pTxMirror       - 1: output mirrored packet, 0: output normal forward packet
+ *      pAclMirror      - 1: output mirrored packet, 0: output normal forward packet
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_NULL_POINTER - Null Pointer
+ * Note:
+ *      The API is to Get mirror override function.
+ *      This function control the output format when a port output
+ *      normal forward & mirrored packet at the same time.
+ */
+extern rtk_api_ret_t rtk_mirror_override_get(rtk_enable_t *pRxMirror, rtk_enable_t *pTxMirror, rtk_enable_t *pAclMirror);
+
+#endif /* __RTK_API_MIRROR_H__ */
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/oam.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/oam.h
new file mode 100644
index 0000000..1fc14bd
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/oam.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes the following modules and sub-modules
+ *           (1) OAM (802.3ah) configuration
+ *
+ */
+
+#ifndef __RTK_OAM_H__
+#define __RTK_OAM_H__
+
+/*
+ * Symbol Definition
+ */
+
+
+/*
+ * Data Declaration
+ */
+
+
+/*
+ * Macro Declaration
+ */
+
+typedef enum rtk_oam_parser_act_e
+{
+    OAM_PARSER_ACTION_FORWARD = 0,
+    OAM_PARSER_ACTION_LOOPBACK,
+    OAM_PARSER_ACTION_DISCARD,
+    OAM_PARSER_ACTION_END,
+
+} rtk_oam_parser_act_t;
+
+typedef enum rtk_oam_multiplexer_act_e
+{
+    OAM_MULTIPLEXER_ACTION_FORWARD = 0,
+    OAM_MULTIPLEXER_ACTION_DISCARD,
+    OAM_MULTIPLEXER_ACTION_CPUONLY,
+    OAM_MULTIPLEXER_ACTION_END,
+
+} rtk_oam_multiplexer_act_t;
+
+
+/*
+ * Function Declaration
+ */
+
+/* Function Name:
+ *      rtk_oam_init
+ * Description:
+ *      Initialize oam module.
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ * Note:
+ *      Must initialize oam module before calling any oam APIs.
+ */
+extern rtk_api_ret_t rtk_oam_init(void);
+
+/* Function Name:
+ *      rtk_oam_state_set
+ * Description:
+ *      This API set OAM state.
+ * Input:
+ *      enabled     -OAMstate
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error parameter
+ * Note:
+ *      This API set OAM state.
+ */
+extern rtk_api_ret_t rtk_oam_state_set(rtk_enable_t enabled);
+
+/* Function Name:
+ *      rtk_oam_state_get
+ * Description:
+ *      This API get OAM state.
+ * Input:
+ *      None.
+ * Output:
+ *      pEnabled        - H/W IGMP state
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error parameter
+ * Note:
+ *      This API set current OAM state.
+ */
+extern rtk_api_ret_t rtk_oam_state_get(rtk_enable_t *pEnabled);
+
+
+/* Module Name : OAM */
+
+/* Function Name:
+ *      rtk_oam_parserAction_set
+ * Description:
+ *      Set OAM parser action
+ * Input:
+ *      port    - port id
+ *      action  - parser action
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID      - invalid port id
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_oam_parserAction_set(rtk_port_t port, rtk_oam_parser_act_t action);
+
+/* Function Name:
+ *      rtk_oam_parserAction_set
+ * Description:
+ *      Get OAM parser action
+ * Input:
+ *      port    - port id
+ * Output:
+ *      pAction  - parser action
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID      - invalid port id
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_oam_parserAction_get(rtk_port_t port, rtk_oam_parser_act_t *pAction);
+
+
+/* Function Name:
+ *      rtk_oam_multiplexerAction_set
+ * Description:
+ *      Set OAM multiplexer action
+ * Input:
+ *      port    - port id
+ *      action  - parser action
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID      - invalid port id
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_oam_multiplexerAction_set(rtk_port_t port, rtk_oam_multiplexer_act_t action);
+
+/* Function Name:
+ *      rtk_oam_multiplexerAction_set
+ * Description:
+ *      Get OAM multiplexer action
+ * Input:
+ *      port    - port id
+ * Output:
+ *      pAction  - parser action
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID      - invalid port id
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_oam_multiplexerAction_get(rtk_port_t port, rtk_oam_multiplexer_act_t *pAction);
+
+
+#endif /* __RTK_OAM_H__ */
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/port.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/port.h
new file mode 100644
index 0000000..fcac1bc
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/port.h
@@ -0,0 +1,959 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes port module high-layer API defination
+ *
+ */
+
+#ifndef __RTK_API_PORT_H__
+#define __RTK_API_PORT_H__
+
+/*
+ * Data Type Declaration
+ */
+
+#define PHY_CONTROL_REG                             0
+#define PHY_STATUS_REG                              1
+#define PHY_AN_ADVERTISEMENT_REG                    4
+#define PHY_AN_LINKPARTNER_REG                      5
+#define PHY_1000_BASET_CONTROL_REG                  9
+#define PHY_1000_BASET_STATUS_REG                   10
+#define PHY_RESOLVED_REG                            26
+
+#define RTK_EFID_MAX                                0x7
+
+#define RTK_FIBER_FORCE_1000M                       3
+#define RTK_FIBER_FORCE_100M                        5
+#define RTK_FIBER_FORCE_100M1000M                   7
+
+#define RTK_INDRECT_ACCESS_CRTL                     0x1f00
+#define RTK_INDRECT_ACCESS_STATUS                   0x1f01
+#define RTK_INDRECT_ACCESS_ADDRESS                  0x1f02
+#define RTK_INDRECT_ACCESS_WRITE_DATA               0x1f03
+#define RTK_INDRECT_ACCESS_READ_DATA                0x1f04
+#define RTK_INDRECT_ACCESS_DELAY                    0x1f80
+#define RTK_INDRECT_ACCESS_BURST                    0x1f81
+#define RTK_RW_MASK                                 0x2
+#define RTK_CMD_MASK                                0x1
+#define RTK_PHY_BUSY_OFFSET                         2
+
+
+typedef enum rtk_mode_ext_e
+{
+    MODE_EXT_DISABLE = 0,
+    MODE_EXT_RGMII,
+    MODE_EXT_MII_MAC,
+    MODE_EXT_MII_PHY,
+    MODE_EXT_TMII_MAC,
+    MODE_EXT_TMII_PHY,
+    MODE_EXT_GMII,
+    MODE_EXT_RMII_MAC,
+    MODE_EXT_RMII_PHY,
+    MODE_EXT_SGMII,
+    MODE_EXT_HSGMII,
+    MODE_EXT_1000X_100FX,
+    MODE_EXT_1000X,
+    MODE_EXT_100FX,
+    MODE_EXT_RGMII_2,
+    MODE_EXT_MII_MAC_2,
+    MODE_EXT_MII_PHY_2,
+    MODE_EXT_TMII_MAC_2,
+    MODE_EXT_TMII_PHY_2,
+    MODE_EXT_RMII_MAC_2,
+    MODE_EXT_RMII_PHY_2,
+    MODE_EXT_END
+} rtk_mode_ext_t;
+
+typedef enum rtk_port_duplex_e
+{
+    PORT_HALF_DUPLEX = 0,
+    PORT_FULL_DUPLEX,
+    PORT_DUPLEX_END
+} rtk_port_duplex_t;
+
+typedef enum rtk_port_linkStatus_e
+{
+    PORT_LINKDOWN = 0,
+    PORT_LINKUP,
+    PORT_LINKSTATUS_END
+} rtk_port_linkStatus_t;
+
+typedef struct  rtk_port_mac_ability_s
+{
+    rtk_uint32 forcemode;
+    rtk_uint32 speed;
+    rtk_uint32 duplex;
+    rtk_uint32 link;
+    rtk_uint32 nway;
+    rtk_uint32 txpause;
+    rtk_uint32 rxpause;
+}rtk_port_mac_ability_t;
+
+typedef struct rtk_port_phy_ability_s
+{
+    rtk_uint32    AutoNegotiation;  /*PHY register 0.12 setting for auto-negotiation process*/
+    rtk_uint32    Half_10;          /*PHY register 4.5 setting for 10BASE-TX half duplex capable*/
+    rtk_uint32    Full_10;          /*PHY register 4.6 setting for 10BASE-TX full duplex capable*/
+    rtk_uint32    Half_100;         /*PHY register 4.7 setting for 100BASE-TX half duplex capable*/
+    rtk_uint32    Full_100;         /*PHY register 4.8 setting for 100BASE-TX full duplex capable*/
+    rtk_uint32    Full_1000;        /*PHY register 9.9 setting for 1000BASE-T full duplex capable*/
+    rtk_uint32    FC;               /*PHY register 4.10 setting for flow control capability*/
+    rtk_uint32    AsyFC;            /*PHY register 4.11 setting for  asymmetric flow control capability*/
+} rtk_port_phy_ability_t;
+
+typedef rtk_uint32  rtk_port_phy_data_t;     /* phy page  */
+
+typedef enum rtk_port_phy_mdix_mode_e
+{
+    PHY_AUTO_CROSSOVER_MODE= 0,
+    PHY_FORCE_MDI_MODE,
+    PHY_FORCE_MDIX_MODE,
+    PHY_FORCE_MODE_END
+} rtk_port_phy_mdix_mode_t;
+
+typedef enum rtk_port_phy_mdix_status_e
+{
+    PHY_STATUS_AUTO_MDI_MODE= 0,
+    PHY_STATUS_AUTO_MDIX_MODE,
+    PHY_STATUS_FORCE_MDI_MODE,
+    PHY_STATUS_FORCE_MDIX_MODE,
+    PHY_STATUS_FORCE_MODE_END
+} rtk_port_phy_mdix_status_t;
+
+typedef rtk_uint32  rtk_port_phy_page_t;     /* phy page  */
+
+typedef enum rtk_port_phy_reg_e
+{
+    PHY_REG_CONTROL             = 0,
+    PHY_REG_STATUS,
+    PHY_REG_IDENTIFIER_1,
+    PHY_REG_IDENTIFIER_2,
+    PHY_REG_AN_ADVERTISEMENT,
+    PHY_REG_AN_LINKPARTNER,
+    PHY_REG_1000_BASET_CONTROL  = 9,
+    PHY_REG_1000_BASET_STATUS,
+    PHY_REG_END                 = 32
+} rtk_port_phy_reg_t;
+
+typedef enum rtk_port_phy_test_mode_e
+{
+    PHY_TEST_MODE_NORMAL= 0,
+    PHY_TEST_MODE_1,
+    PHY_TEST_MODE_2,
+    PHY_TEST_MODE_3,
+    PHY_TEST_MODE_4,
+    PHY_TEST_MODE_END
+} rtk_port_phy_test_mode_t;
+
+typedef enum rtk_port_speed_e
+{
+    PORT_SPEED_10M = 0,
+    PORT_SPEED_100M,
+    PORT_SPEED_1000M,
+    PORT_SPEED_500M,
+    PORT_SPEED_2500M,
+    PORT_SPEED_END
+} rtk_port_speed_t;
+
+typedef enum rtk_port_media_e
+{
+    PORT_MEDIA_COPPER = 0,
+    PORT_MEDIA_FIBER,
+    PORT_MEDIA_END
+}rtk_port_media_t;
+
+typedef struct rtk_rtctResult_s
+{
+    rtk_port_speed_t    linkType;
+    union
+    {
+        struct fe_result_s
+        {
+            rtk_uint32      isRxShort;
+            rtk_uint32      isTxShort;
+            rtk_uint32      isRxOpen;
+            rtk_uint32      isTxOpen;
+            rtk_uint32      isRxMismatch;
+            rtk_uint32      isTxMismatch;
+            rtk_uint32      isRxLinedriver;
+            rtk_uint32      isTxLinedriver;
+            rtk_uint32      rxLen;
+            rtk_uint32      txLen;
+        } fe_result;
+
+        struct ge_result_s
+        {
+            rtk_uint32      channelAShort;
+            rtk_uint32      channelBShort;
+            rtk_uint32      channelCShort;
+            rtk_uint32      channelDShort;
+
+            rtk_uint32      channelAOpen;
+            rtk_uint32      channelBOpen;
+            rtk_uint32      channelCOpen;
+            rtk_uint32      channelDOpen;
+
+            rtk_uint32      channelAMismatch;
+            rtk_uint32      channelBMismatch;
+            rtk_uint32      channelCMismatch;
+            rtk_uint32      channelDMismatch;
+
+            rtk_uint32      channelALinedriver;
+            rtk_uint32      channelBLinedriver;
+            rtk_uint32      channelCLinedriver;
+            rtk_uint32      channelDLinedriver;
+
+            rtk_uint32      channelALen;
+            rtk_uint32      channelBLen;
+            rtk_uint32      channelCLen;
+            rtk_uint32      channelDLen;
+        } ge_result;
+    }result;
+} rtk_rtctResult_t;
+
+/* Function Name:
+ *      rtk_port_phyAutoNegoAbility_set
+ * Description:
+ *      Set ethernet PHY auto-negotiation desired ability.
+ * Input:
+ *      port        - port id.
+ *      pAbility    - Ability structure
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_PHY_REG_ID       - Invalid PHY address
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy
+ * Note:
+ *      If Full_1000 bit is set to 1, the AutoNegotiation will be automatic set to 1. While both AutoNegotiation and Full_1000 are set to 0, the PHY speed and duplex selection will
+ *      be set as following 100F > 100H > 10F > 10H priority sequence.
+ */
+extern rtk_api_ret_t rtk_port_phyAutoNegoAbility_set(rtk_port_t port, rtk_port_phy_ability_t *pAbility);
+
+/* Function Name:
+ *      rtk_port_phyAutoNegoAbility_get
+ * Description:
+ *      Get PHY ability through PHY registers.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pAbility - Ability structure
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_PHY_REG_ID       - Invalid PHY address
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy
+ * Note:
+ *      Get the capablity of specified PHY.
+ */
+extern rtk_api_ret_t rtk_port_phyAutoNegoAbility_get(rtk_port_t port, rtk_port_phy_ability_t *pAbility);
+
+/* Function Name:
+ *      rtk_port_phyForceModeAbility_set
+ * Description:
+ *      Set the port speed/duplex mode/pause/asy_pause in the PHY force mode.
+ * Input:
+ *      port        - port id.
+ *      pAbility    - Ability structure
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_PHY_REG_ID       - Invalid PHY address
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy
+ * Note:
+ *      While both AutoNegotiation and Full_1000 are set to 0, the PHY speed and duplex selection will
+ *      be set as following 100F > 100H > 10F > 10H priority sequence.
+ */
+extern rtk_api_ret_t rtk_port_phyForceModeAbility_set(rtk_port_t port, rtk_port_phy_ability_t *pAbility);
+
+/* Function Name:
+ *      rtk_port_phyForceModeAbility_get
+ * Description:
+ *      Get PHY ability through PHY registers.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pAbility - Ability structure
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_PHY_REG_ID       - Invalid PHY address
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy
+ * Note:
+ *      Get the capablity of specified PHY.
+ */
+extern rtk_api_ret_t rtk_port_phyForceModeAbility_get(rtk_port_t port, rtk_port_phy_ability_t *pAbility);
+
+/* Function Name:
+ *      rtk_port_phyStatus_get
+ * Description:
+ *      Get ethernet PHY linking status
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      linkStatus  - PHY link status
+ *      speed       - PHY link speed
+ *      duplex      - PHY duplex mode
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_PHY_REG_ID       - Invalid PHY address
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy
+ * Note:
+ *      API will return auto negotiation status of phy.
+ */
+extern rtk_api_ret_t rtk_port_phyStatus_get(rtk_port_t port, rtk_port_linkStatus_t *pLinkStatus, rtk_port_speed_t *pSpeed, rtk_port_duplex_t *pDuplex);
+
+/* Function Name:
+ *      rtk_port_macForceLink_set
+ * Description:
+ *      Set port force linking configuration.
+ * Input:
+ *      port            - port id.
+ *      pPortability    - port ability configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API can set Port/MAC force mode properties.
+ */
+extern rtk_api_ret_t rtk_port_macForceLink_set(rtk_port_t port, rtk_port_mac_ability_t *pPortability);
+
+/* Function Name:
+ *      rtk_port_macForceLink_get
+ * Description:
+ *      Get port force linking configuration.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pPortability - port ability configuration
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API can get Port/MAC force mode properties.
+ */
+extern rtk_api_ret_t rtk_port_macForceLink_get(rtk_port_t port, rtk_port_mac_ability_t *pPortability);
+
+/* Function Name:
+ *      rtk_port_macForceLinkExt_set
+ * Description:
+ *      Set external interface force linking configuration.
+ * Input:
+ *      port            - external port ID
+ *      mode            - external interface mode
+ *      pPortability    - port ability configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API can set external interface force mode properties.
+ *      The external interface can be set to:
+ *      - MODE_EXT_DISABLE,
+ *      - MODE_EXT_RGMII,
+ *      - MODE_EXT_MII_MAC,
+ *      - MODE_EXT_MII_PHY,
+ *      - MODE_EXT_TMII_MAC,
+ *      - MODE_EXT_TMII_PHY,
+ *      - MODE_EXT_GMII,
+ *      - MODE_EXT_RMII_MAC,
+ *      - MODE_EXT_RMII_PHY,
+ *      - MODE_EXT_SGMII,
+ *      - MODE_EXT_HSGMII,
+ *      - MODE_EXT_1000X_100FX,
+ *      - MODE_EXT_1000X,
+ *      - MODE_EXT_100FX,
+ */
+extern rtk_api_ret_t rtk_port_macForceLinkExt_set(rtk_port_t port, rtk_mode_ext_t mode, rtk_port_mac_ability_t *pPortability);
+
+/* Function Name:
+ *      rtk_port_macForceLinkExt_get
+ * Description:
+ *      Set external interface force linking configuration.
+ * Input:
+ *      port            - external port ID
+ * Output:
+ *      pMode           - external interface mode
+ *      pPortability    - port ability configuration
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API can get external interface force mode properties.
+ */
+extern rtk_api_ret_t rtk_port_macForceLinkExt_get(rtk_port_t port, rtk_mode_ext_t *pMode, rtk_port_mac_ability_t *pPortability);
+
+/* Function Name:
+ *      rtk_port_macStatus_get
+ * Description:
+ *      Get port link status.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pPortstatus - port ability configuration
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API can get Port/PHY properties.
+ */
+extern rtk_api_ret_t rtk_port_macStatus_get(rtk_port_t port, rtk_port_mac_ability_t *pPortstatus);
+
+/* Function Name:
+ *      rtk_port_macLocalLoopbackEnable_set
+ * Description:
+ *      Set Port Local Loopback. (Redirect TX to RX.)
+ * Input:
+ *      port    - Port id.
+ *      enable  - Loopback state, 0:disable, 1:enable
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API can enable/disable Local loopback in MAC.
+ *      For UTP port, This API will also enable the digital
+ *      loopback bit in PHY register for sync of speed between
+ *      PHY and MAC. For EXT port, users need to force the
+ *      link state by themself.
+ */
+extern rtk_api_ret_t rtk_port_macLocalLoopbackEnable_set(rtk_port_t port, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_port_macLocalLoopbackEnable_get
+ * Description:
+ *      Get Port Local Loopback. (Redirect TX to RX.)
+ * Input:
+ *      port    - Port id.
+ * Output:
+ *      pEnable  - Loopback state, 0:disable, 1:enable
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      None.
+ */
+extern rtk_api_ret_t rtk_port_macLocalLoopbackEnable_get(rtk_port_t port, rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_port_phyReg_set
+ * Description:
+ *      Set PHY register data of the specific port.
+ * Input:
+ *      port    - port id.
+ *      reg     - Register id
+ *      regData - Register data
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_PHY_REG_ID       - Invalid PHY address
+ *      RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy
+ * Note:
+ *      This API can set PHY register data of the specific port.
+ */
+extern rtk_api_ret_t rtk_port_phyReg_set(rtk_port_t port, rtk_port_phy_reg_t reg, rtk_port_phy_data_t value);
+
+/* Function Name:
+ *      rtk_port_phyReg_get
+ * Description:
+ *      Get PHY register data of the specific port.
+ * Input:
+ *      port    - Port id.
+ *      reg     - Register id
+ * Output:
+ *      pData   - Register data
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_PHY_REG_ID       - Invalid PHY address
+ *      RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy
+ * Note:
+ *      This API can get PHY register data of the specific port.
+ */
+extern rtk_api_ret_t rtk_port_phyReg_get(rtk_port_t port, rtk_port_phy_reg_t reg, rtk_port_phy_data_t *pData);
+
+/* Function Name:
+ *      rtk_port_backpressureEnable_set
+ * Description:
+ *      Set the half duplex backpressure enable status of the specific port.
+ * Input:
+ *      port    - port id.
+ *      enable  - Back pressure status.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_ENABLE       - Invalid enable input.
+ * Note:
+ *      This API can set the half duplex backpressure enable status of the specific port.
+ *      The half duplex backpressure enable status of the port is as following:
+ *      - DISABLE
+ *      - ENABLE
+ */
+extern rtk_api_ret_t rtk_port_backpressureEnable_set(rtk_port_t port, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_port_backpressureEnable_get
+ * Description:
+ *      Get the half duplex backpressure enable status of the specific port.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEnable - Back pressure status.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API can get the half duplex backpressure enable status of the specific port.
+ *      The half duplex backpressure enable status of the port is as following:
+ *      - DISABLE
+ *      - ENABLE
+ */
+extern rtk_api_ret_t rtk_port_backpressureEnable_get(rtk_port_t port, rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_port_adminEnable_set
+ * Description:
+ *      Set port admin configuration of the specific port.
+ * Input:
+ *      port    - port id.
+ *      enable  - Back pressure status.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_ENABLE       - Invalid enable input.
+ * Note:
+ *      This API can set port admin configuration of the specific port.
+ *      The port admin configuration of the port is as following:
+ *      - DISABLE
+ *      - ENABLE
+ */
+extern rtk_api_ret_t rtk_port_adminEnable_set(rtk_port_t port, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_port_adminEnable_get
+ * Description:
+ *      Get port admin configurationof the specific port.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEnable - Back pressure status.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API can get port admin configuration of the specific port.
+ *      The port admin configuration of the port is as following:
+ *      - DISABLE
+ *      - ENABLE
+ */
+extern rtk_api_ret_t rtk_port_adminEnable_get(rtk_port_t port, rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_port_isolation_set
+ * Description:
+ *      Set permitted port isolation portmask
+ * Input:
+ *      port         - port id.
+ *      pPortmask    - Permit port mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_PORT_MASK    - Invalid portmask.
+ * Note:
+ *      This API set the port mask that a port can trasmit packet to of each port
+ *      A port can only transmit packet to ports included in permitted portmask
+ */
+extern rtk_api_ret_t rtk_port_isolation_set(rtk_port_t port, rtk_portmask_t *pPortmask);
+
+/* Function Name:
+ *      rtk_port_isolation_get
+ * Description:
+ *      Get permitted port isolation portmask
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pPortmask - Permit port mask
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API get the port mask that a port can trasmit packet to of each port
+ *      A port can only transmit packet to ports included in permitted portmask
+ */
+extern rtk_api_ret_t rtk_port_isolation_get(rtk_port_t port, rtk_portmask_t *pPortmask);
+
+/* Function Name:
+ *      rtk_port_rgmiiDelayExt_set
+ * Description:
+ *      Set RGMII interface delay value for TX and RX.
+ * Input:
+ *      txDelay - TX delay value, 1 for delay 2ns and 0 for no-delay
+ *      rxDelay - RX delay value, 0~7 for delay setup.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API can set external interface 2 RGMII delay.
+ *      In TX delay, there are 2 selection: no-delay and 2ns delay.
+ *      In RX dekay, there are 8 steps for delay tunning. 0 for no-delay, and 7 for maximum delay.
+ */
+extern rtk_api_ret_t rtk_port_rgmiiDelayExt_set(rtk_port_t port, rtk_data_t txDelay, rtk_data_t rxDelay);
+
+/* Function Name:
+ *      rtk_port_rgmiiDelayExt_get
+ * Description:
+ *      Get RGMII interface delay value for TX and RX.
+ * Input:
+ *      None
+ * Output:
+ *      pTxDelay - TX delay value
+ *      pRxDelay - RX delay value
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API can set external interface 2 RGMII delay.
+ *      In TX delay, there are 2 selection: no-delay and 2ns delay.
+ *      In RX dekay, there are 8 steps for delay tunning. 0 for n0-delay, and 7 for maximum delay.
+ */
+extern rtk_api_ret_t rtk_port_rgmiiDelayExt_get(rtk_port_t port, rtk_data_t *pTxDelay, rtk_data_t *pRxDelay);
+
+/* Function Name:
+ *      rtk_port_phyEnableAll_set
+ * Description:
+ *      Set all PHY enable status.
+ * Input:
+ *      enable - PHY Enable State.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_ENABLE       - Invalid enable input.
+ * Note:
+ *      This API can set all PHY status.
+ *      The configuration of all PHY is as following:
+ *      - DISABLE
+ *      - ENABLE
+ */
+extern rtk_api_ret_t rtk_port_phyEnableAll_set(rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_port_phyEnableAll_get
+ * Description:
+ *      Get all PHY enable status.
+ * Input:
+ *      None
+ * Output:
+ *      pEnable - PHY Enable State.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      This API can set all PHY status.
+ *      The configuration of all PHY is as following:
+ *      - DISABLE
+ *      - ENABLE
+ */
+extern rtk_api_ret_t rtk_port_phyEnableAll_get(rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_port_efid_set
+ * Description:
+ *      Set port-based enhanced filtering database
+ * Input:
+ *      port - Port id.
+ *      efid - Specified enhanced filtering database.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_L2_FID - Invalid fid.
+ *      RT_ERR_INPUT - Invalid input parameter.
+ *      RT_ERR_PORT_ID - Invalid port ID.
+ * Note:
+ *      The API can set port-based enhanced filtering database.
+ */
+extern rtk_api_ret_t rtk_port_efid_set(rtk_port_t port, rtk_data_t efid);
+
+/* Function Name:
+ *      rtk_port_efid_get
+ * Description:
+ *      Get port-based enhanced filtering database
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEfid - Specified enhanced filtering database.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT - Invalid input parameters.
+ *      RT_ERR_PORT_ID - Invalid port ID.
+ * Note:
+ *      The API can get port-based enhanced filtering database status.
+ */
+extern rtk_api_ret_t rtk_port_efid_get(rtk_port_t port, rtk_data_t *pEfid);
+
+/* Function Name:
+ *      rtk_port_phyComboPortMedia_set
+ * Description:
+ *      Set Combo port media type
+ * Input:
+ *      port    - Port id. (Should be Port 4)
+ *      media   - Media (COPPER or FIBER)
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_PORT_ID          - Invalid port ID.
+ * Note:
+ *      The API can Set Combo port media type.
+ */
+extern rtk_api_ret_t rtk_port_phyComboPortMedia_set(rtk_port_t port, rtk_port_media_t media);
+
+/* Function Name:
+ *      rtk_port_phyComboPortMedia_get
+ * Description:
+ *      Get Combo port media type
+ * Input:
+ *      port    - Port id. (Should be Port 4)
+ * Output:
+ *      pMedia  - Media (COPPER or FIBER)
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_PORT_ID          - Invalid port ID.
+ * Note:
+ *      The API can Set Combo port media type.
+ */
+extern rtk_api_ret_t rtk_port_phyComboPortMedia_get(rtk_port_t port, rtk_port_media_t *pMedia);
+
+/* Function Name:
+ *      rtk_port_rtctEnable_set
+ * Description:
+ *      Enable RTCT test
+ * Input:
+ *      pPortmask    - Port mask of RTCT enabled port
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_MASK        - Invalid port mask.
+ * Note:
+ *      The API can enable RTCT Test
+ */
+extern rtk_api_ret_t rtk_port_rtctEnable_set(rtk_portmask_t *pPortmask);
+
+/* Function Name:
+ *      rtk_port_rtctDisable_set
+ * Description:
+ *      Disable RTCT test
+ * Input:
+ *      pPortmask    - Port mask of RTCT disabled port
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_MASK        - Invalid port mask.
+ * Note:
+ *      The API can disable RTCT Test
+ */
+rtk_api_ret_t rtk_port_rtctDisable_set(rtk_portmask_t *pPortmask);
+
+
+/* Function Name:
+ *      rtk_port_rtctResult_get
+ * Description:
+ *      Get the result of RTCT test
+ * Input:
+ *      port        - Port ID
+ * Output:
+ *      pRtctResult - The result of RTCT result
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port ID.
+ *      RT_ERR_PHY_RTCT_NOT_FINISH  - Testing does not finish.
+ * Note:
+ *      The API can get RTCT test result.
+ *      RTCT test may takes 4.8 seconds to finish its test at most.
+ *      Thus, if this API return RT_ERR_PHY_RTCT_NOT_FINISH or
+ *      other error code, the result can not be referenced and
+ *      user should call this API again until this API returns
+ *      a RT_ERR_OK.
+ *      The result is stored at pRtctResult->ge_result
+ *      pRtctResult->linkType is unused.
+ *      The unit of channel length is 2.5cm. Ex. 300 means 300 * 2.5 = 750cm = 7.5M
+ */
+extern rtk_api_ret_t rtk_port_rtctResult_get(rtk_port_t port, rtk_rtctResult_t *pRtctResult);
+
+/* Function Name:
+ *      rtk_port_sds_reset
+ * Description:
+ *      Reset Serdes
+ * Input:
+ *      port        - Port ID
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port ID.
+ * Note:
+ *      The API can reset Serdes
+ */
+extern rtk_api_ret_t rtk_port_sds_reset(rtk_port_t port);
+
+/* Function Name:
+ *      rtk_port_sgmiiLinkStatus_get
+ * Description:
+ *      Get SGMII status
+ * Input:
+ *      port        - Port ID
+ * Output:
+ *      pSignalDetect   - Signal detect
+ *      pSync           - Sync
+ *      pLink           - Link
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port ID.
+ * Note:
+ *      The API can reset Serdes
+ */
+extern rtk_api_ret_t rtk_port_sgmiiLinkStatus_get(rtk_port_t port, rtk_data_t *pSignalDetect, rtk_data_t *pSync, rtk_port_linkStatus_t *pLink);
+
+/* Function Name:
+ *      rtk_port_sgmiiNway_set
+ * Description:
+ *      Configure SGMII/HSGMII port Nway state
+ * Input:
+ *      port        - Port ID
+ *      state       - Nway state
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port ID.
+ * Note:
+ *      The API configure SGMII/HSGMII port Nway state
+ */
+extern rtk_api_ret_t rtk_port_sgmiiNway_set(rtk_port_t port, rtk_enable_t state);
+
+/* Function Name:
+ *      rtk_port_sgmiiNway_get
+ * Description:
+ *      Get SGMII/HSGMII port Nway state
+ * Input:
+ *      port        - Port ID
+ * Output:
+ *      pState      - Nway state
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port ID.
+ * Note:
+ *      The API can get SGMII/HSGMII port Nway state
+ */
+extern rtk_api_ret_t rtk_port_sgmiiNway_get(rtk_port_t port, rtk_enable_t *pState);
+
+#endif /* __RTK_API_PORT_H__ */
+
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/ptp.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/ptp.h
new file mode 100644
index 0000000..6c4aca5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/ptp.h
@@ -0,0 +1,511 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes time module high-layer API defination
+ *
+ */
+
+#ifndef __RTK_API_PTP_H__
+#define __RTK_API_PTP_H__
+
+/*
+ * Symbol Definition
+ */
+#define RTK_MAX_NUM_OF_NANO_SECOND                     0x3B9AC9FF
+#define RTK_PTP_INTR_MASK                                          0xFF
+#define RTK_MAX_NUM_OF_TPID                                    0xFFFF
+
+/* Message Type */
+typedef enum rtk_ptp_msgType_e
+{
+    PTP_MSG_TYPE_TX_SYNC = 0,
+    PTP_MSG_TYPE_TX_DELAY_REQ,
+    PTP_MSG_TYPE_TX_PDELAY_REQ,
+    PTP_MSG_TYPE_TX_PDELAY_RESP,
+    PTP_MSG_TYPE_RX_SYNC,
+    PTP_MSG_TYPE_RX_DELAY_REQ,
+    PTP_MSG_TYPE_RX_PDELAY_REQ,
+    PTP_MSG_TYPE_RX_PDELAY_RESP,
+    PTP_MSG_TYPE_END
+} rtk_ptp_msgType_t;
+
+typedef enum rtk_ptp_intType_e
+{
+    PTP_INT_TYPE_TX_SYNC = 0,
+    PTP_INT_TYPE_TX_DELAY_REQ,
+    PTP_INT_TYPE_TX_PDELAY_REQ,
+    PTP_INT_TYPE_TX_PDELAY_RESP,
+    PTP_INT_TYPE_RX_SYNC,
+    PTP_INT_TYPE_RX_DELAY_REQ,
+    PTP_INT_TYPE_RX_PDELAY_REQ,
+    PTP_INT_TYPE_RX_PDELAY_RESP,
+    PTP_INT_TYPE_ALL,
+    PTP_INT_TYPE_END
+}rtk_ptp_intType_t;
+
+typedef enum rtk_ptp_sys_adjust_e
+{
+    SYS_ADJUST_PLUS = 0,
+    SYS_ADJUST_MINUS,
+    SYS_ADJUST_END
+} rtk_ptp_sys_adjust_t;
+
+
+/* Reference Time */
+typedef struct rtk_ptp_timeStamp_s
+{
+    rtk_uint32 sec;
+    rtk_uint32 nsec;
+} rtk_ptp_timeStamp_t;
+
+typedef struct rtk_ptp_info_s
+{
+    rtk_uint32 sequenceId;
+    rtk_ptp_timeStamp_t   timeStamp;
+} rtk_ptp_info_t;
+
+typedef rtk_uint32 rtk_ptp_tpid_t;
+
+typedef rtk_uint32  rtk_ptp_intStatus_t;     /* interrupt status mask  */
+
+/*
+ * Data Declaration
+ */
+
+/*
+ * Function Declaration
+ */
+/* Function Name:
+ *      rtk_time_init
+ * Description:
+ *      PTP function initialization.
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      This API is used to initialize EEE status.
+ */
+extern rtk_api_ret_t rtk_ptp_init(void);
+
+/* Function Name:
+ *      rtk_ptp_mac_set
+ * Description:
+ *      Configure PTP mac address.
+ * Input:
+ *      mac - mac address to parser PTP packets.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_ptp_mac_set(rtk_mac_t mac);
+
+/* Function Name:
+ *      rtk_ptp_mac_get
+ * Description:
+ *      Get PTP mac address.
+ * Input:
+ *      None
+ * Output:
+ *      pMac - mac address to parser PTP packets.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_ptp_mac_get(rtk_mac_t *pMac);
+
+/* Function Name:
+ *      rtk_ptp_tpid_set
+ * Description:
+ *      Configure PTP accepted outer & inner tag TPID.
+ * Input:
+ *      outerId - Ether type of S-tag frame parsing in PTP ports.
+ *      innerId - Ether type of C-tag frame parsing in PTP ports.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_ptp_tpid_set(rtk_ptp_tpid_t outerId, rtk_ptp_tpid_t innerId);
+
+/* Function Name:
+ *      rtk_ptp_tpid_get
+ * Description:
+ *      Get PTP accepted outer & inner tag TPID.
+ * Input:
+ *      None
+ * Output:
+ *      pOuterId - Ether type of S-tag frame parsing in PTP ports.
+ *      pInnerId - Ether type of C-tag frame parsing in PTP ports.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_ptp_tpid_get(rtk_ptp_tpid_t *pOuterId, rtk_ptp_tpid_t *pInnerId);
+
+/* Function Name:
+ *      rtk_ptp_refTime_set
+ * Description:
+ *      Set the reference time of the specified device.
+ * Input:
+ *      timeStamp - reference timestamp value
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT    - invalid input parameter
+ * Applicable:
+ *      8390, 8380
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_ptp_refTime_set(rtk_ptp_timeStamp_t timeStamp);
+
+/* Function Name:
+ *      rtk_ptp_refTime_get
+ * Description:
+ *      Get the reference time of the specified device.
+ * Input:
+ * Output:
+ *      pTimeStamp - pointer buffer of the reference time
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_UNIT_ID      - invalid unit id
+ *      RT_ERR_NOT_INIT     - The module is not initial
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Applicable:
+ *      8390, 8380
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_ptp_refTime_get(rtk_ptp_timeStamp_t *pTimeStamp);
+
+/* Function Name:
+ *      rtk_ptp_refTimeAdjust_set
+ * Description:
+ *      Adjust the reference time.
+ * Input:
+ *      unit      - unit id
+ *      sign      - significant
+ *      timeStamp - reference timestamp value
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_UNIT_ID  - invalid unit id
+ *      RT_ERR_NOT_INIT - The module is not initial
+ *      RT_ERR_INPUT    - invalid input parameter
+ * Note:
+ *      sign=0 for positive adjustment, sign=1 for negative adjustment.
+ */
+extern rtk_api_ret_t rtk_ptp_refTimeAdjust_set(rtk_ptp_sys_adjust_t sign, rtk_ptp_timeStamp_t timeStamp);
+
+/* Function Name:
+ *      rtk_ptp_refTimeEnable_set
+ * Description:
+ *      Set the enable state of reference time of the specified device.
+ * Input:
+ *      enable - status
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT    - invalid input parameter
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_ptp_refTimeEnable_set(rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_ptp_refTimeEnable_get
+ * Description:
+ *      Get the enable state of reference time of the specified device.
+ * Input:
+ * Output:
+ *      pEnable - status
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_UNIT_ID      - invalid unit id
+ *      RT_ERR_NOT_INIT     - The module is not initial
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Applicable:
+ *      8390, 8380
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_ptp_refTimeEnable_get(rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_ptp_portEnable_set
+ * Description:
+ *      Set PTP status of the specified port.
+ * Input:
+ *      port   - port id
+ *      enable - status
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT     - invalid port id
+ *      RT_ERR_INPUT    - invalid input parameter
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_ptp_portEnable_set(rtk_port_t port, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_ptp_portEnable_get
+ * Description:
+ *      Get PTP status of the specified port.
+ * Input:
+ *      port    - port id
+ * Output:
+ *      pEnable - status
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT         - invalid port id
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_ptp_portEnable_get(rtk_port_t port, rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_ptp_portTimestamp_get
+ * Description:
+ *      Get PTP timstamp according to the PTP identifier on the dedicated port from the specified device.
+ * Input:
+ *      unit       - unit id
+ *      port       - port id
+ *      type       - PTP message type
+ * Output:
+ *      pInfo      - pointer buffer of sequence ID and timestamp
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID      - invalid port id
+ *      RT_ERR_INPUT        - invalid input parameter
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Applicable:
+ *      8390, 8380
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_ptp_portTimestamp_get( rtk_port_t port, rtk_ptp_msgType_t type, rtk_ptp_info_t *pInfo);
+
+/* Function Name:
+ *      rtk_ptp_intControl_set
+ * Description:
+ *      Set PTP interrupt trigger status configuration.
+ * Input:
+ *      type - Interrupt type.
+ *      enable - Interrupt status.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_ENABLE       - Invalid enable input.
+ * Note:
+ *      The API can set PTP interrupt status configuration.
+ *      The interrupt trigger status is shown in the following:
+ *          PTP_INT_TYPE_TX_SYNC = 0,
+ *          PTP_INT_TYPE_TX_DELAY_REQ,
+ *          PTP_INT_TYPE_TX_PDELAY_REQ,
+ *          PTP_INT_TYPE_TX_PDELAY_RESP,
+ *          PTP_INT_TYPE_RX_SYNC,
+ *          PTP_INT_TYPE_RX_DELAY_REQ,
+ *          PTP_INT_TYPE_RX_PDELAY_REQ,
+ *          PTP_INT_TYPE_RX_PDELAY_RESP,
+ *          PTP_INT_TYPE_ALL,
+ */
+extern rtk_api_ret_t rtk_ptp_intControl_set(rtk_ptp_intType_t type, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_ptp_intControl_get
+ * Description:
+ *      Get PTP interrupt trigger status configuration.
+ * Input:
+ *      type - Interrupt type.
+ * Output:
+ *      pEnable - Interrupt status.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get interrupt status configuration.
+ *      The interrupt trigger status is shown in the following:
+ *          PTP_INT_TYPE_TX_SYNC = 0,
+ *          PTP_INT_TYPE_TX_DELAY_REQ,
+ *          PTP_INT_TYPE_TX_PDELAY_REQ,
+ *          PTP_INT_TYPE_TX_PDELAY_RESP,
+ *          PTP_INT_TYPE_RX_SYNC,
+ *          PTP_INT_TYPE_RX_DELAY_REQ,
+ *          PTP_INT_TYPE_RX_PDELAY_REQ,
+ *          PTP_INT_TYPE_RX_PDELAY_RESP,
+ */
+extern rtk_api_ret_t rtk_ptp_intControl_get(rtk_ptp_intType_t type, rtk_enable_t *pEnable);
+
+
+/* Function Name:
+ *      rtk_ptp_intStatus_get
+ * Description:
+ *      Get PTP port interrupt trigger status.
+ * Input:
+ *      port           - physical port
+ * Output:
+ *      pStatusMask - Interrupt status bit mask.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get interrupt trigger status when interrupt happened.
+ *      The interrupt trigger status is shown in the following:
+ *      - PORT 0  INT    (value[0] (Bit0))
+ *      - PORT 1  INT    (value[0] (Bit1))
+ *      - PORT 2  INT    (value[0] (Bit2))
+ *      - PORT 3  INT    (value[0] (Bit3))
+ *      - PORT 4  INT   (value[0] (Bit4))
+
+ *
+ */
+extern rtk_api_ret_t rtk_ptp_intStatus_get(rtk_ptp_intStatus_t *pStatusMask);
+
+/* Function Name:
+ *      rtk_ptp_portIntStatus_set
+ * Description:
+ *      Set PTP port interrupt trigger status to clean.
+ * Input:
+ *      port           - physical port
+ *      statusMask - Interrupt status bit mask.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT - Invalid input parameters.
+ * Note:
+ *      The API can clean interrupt trigger status when interrupt happened.
+ *      The interrupt trigger status is shown in the following:
+ *      - PTP_INT_TYPE_TX_SYNC              (value[0] (Bit0))
+ *      - PTP_INT_TYPE_TX_DELAY_REQ      (value[0] (Bit1))
+ *      - PTP_INT_TYPE_TX_PDELAY_REQ    (value[0] (Bit2))
+ *      - PTP_INT_TYPE_TX_PDELAY_RESP   (value[0] (Bit3))
+ *      - PTP_INT_TYPE_RX_SYNC              (value[0] (Bit4))
+ *      - PTP_INT_TYPE_RX_DELAY_REQ      (value[0] (Bit5))
+ *      - PTP_INT_TYPE_RX_PDELAY_REQ    (value[0] (Bit6))
+ *      - PTP_INT_TYPE_RX_PDELAY_RESP   (value[0] (Bit7))
+ *      The status will be cleared after execute this API.
+ */
+extern rtk_api_ret_t rtk_ptp_portIntStatus_set(rtk_port_t port, rtk_ptp_intStatus_t statusMask);
+
+/* Function Name:
+ *      rtk_ptp_portIntStatus_get
+ * Description:
+ *      Get PTP port interrupt trigger status.
+ * Input:
+ *      port           - physical port
+ * Output:
+ *      pStatusMask - Interrupt status bit mask.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get interrupt trigger status when interrupt happened.
+ *      The interrupt trigger status is shown in the following:
+ *      - PTP_INT_TYPE_TX_SYNC              (value[0] (Bit0))
+ *      - PTP_INT_TYPE_TX_DELAY_REQ      (value[0] (Bit1))
+ *      - PTP_INT_TYPE_TX_PDELAY_REQ    (value[0] (Bit2))
+ *      - PTP_INT_TYPE_TX_PDELAY_RESP   (value[0] (Bit3))
+ *      - PTP_INT_TYPE_RX_SYNC              (value[0] (Bit4))
+ *      - PTP_INT_TYPE_RX_DELAY_REQ      (value[0] (Bit5))
+ *      - PTP_INT_TYPE_RX_PDELAY_REQ    (value[0] (Bit6))
+ *      - PTP_INT_TYPE_RX_PDELAY_RESP   (value[0] (Bit7))
+ *
+ */
+extern rtk_api_ret_t rtk_ptp_portIntStatus_get(rtk_port_t port, rtk_ptp_intStatus_t *pStatusMask);
+
+/* Function Name:
+ *      rtk_ptp_portPtpTrap_set
+ * Description:
+ *      Set PTP packet trap of the specified port.
+ * Input:
+ *      port   - port id
+ *      enable - status
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT     - invalid port id
+ *      RT_ERR_INPUT    - invalid input parameter
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_ptp_portTrap_set(rtk_port_t port, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_ptp_portPtpEnable_get
+ * Description:
+ *      Get PTP packet trap of the specified port.
+ * Input:
+ *      port    - port id
+ * Output:
+ *      pEnable - status
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT         - invalid port id
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_ptp_portTrap_get(rtk_port_t port, rtk_enable_t *pEnable);
+
+#endif /* __RTK_API_PTP_H__ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/qos.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/qos.h
new file mode 100644
index 0000000..4be4174
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/qos.h
@@ -0,0 +1,781 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes QoS module high-layer API defination
+ *
+ */
+
+#ifndef __RTK_API_QOS_H__
+#define __RTK_API_QOS_H__
+
+/*
+ * Data Type Declaration
+ */
+#define QOS_DEFAULT_TICK_PERIOD                     (19-1)
+#define QOS_DEFAULT_BYTE_PER_TOKEN                  34
+#define QOS_DEFAULT_LK_THRESHOLD                    (34*3) /* Why use 0x400? */
+
+
+#define QOS_DEFAULT_INGRESS_BANDWIDTH               0x3FFF /* 0x3FFF => unlimit */
+#define QOS_DEFAULT_EGRESS_BANDWIDTH                0x3D08 /*( 0x3D08 + 1) * 64Kbps => 1Gbps*/
+#define QOS_DEFAULT_PREIFP                          1
+#define QOS_DEFAULT_PACKET_USED_PAGES_FC            0x60
+#define QOS_DEFAULT_PACKET_USED_FC_EN               0
+#define QOS_DEFAULT_QUEUE_BASED_FC_EN               1
+
+#define QOS_DEFAULT_PRIORITY_SELECT_PORT            8
+#define QOS_DEFAULT_PRIORITY_SELECT_1Q              0
+#define QOS_DEFAULT_PRIORITY_SELECT_ACL             0
+#define QOS_DEFAULT_PRIORITY_SELECT_DSCP            0
+
+#define QOS_DEFAULT_DSCP_MAPPING_PRIORITY           0
+
+#define QOS_DEFAULT_1Q_REMARKING_ABILITY            0
+#define QOS_DEFAULT_DSCP_REMARKING_ABILITY          0
+#define QOS_DEFAULT_QUEUE_GAP                       20
+#define QOS_DEFAULT_QUEUE_NO_MAX                    6
+#define QOS_DEFAULT_AVERAGE_PACKET_RATE             0x3FFF
+#define QOS_DEFAULT_BURST_SIZE_IN_APR               0x3F
+#define QOS_DEFAULT_PEAK_PACKET_RATE                2
+#define QOS_DEFAULT_SCHEDULER_ABILITY_APR           1     /*disable*/
+#define QOS_DEFAULT_SCHEDULER_ABILITY_PPR           1    /*disable*/
+#define QOS_DEFAULT_SCHEDULER_ABILITY_WFQ           1    /*disable*/
+
+#define QOS_WEIGHT_MAX                              127
+
+#define RTK_MAX_NUM_OF_PRIORITY                     8
+#define RTK_MAX_NUM_OF_QUEUE                        8
+
+#define RTK_PRIMAX                                             7
+#define RTK_QIDMAX                                             7
+#define RTK_DSCPMAX                                         63
+
+
+/* enum Priority Selection Index */
+typedef enum rtk_qos_priDecTbl_e
+{
+    PRIDECTBL_IDX0 = 0,
+    PRIDECTBL_IDX1,
+    PRIDECTBL_END,
+}rtk_qos_priDecTbl_t;
+
+
+/* Types of 802.1p remarking source */
+typedef enum rtk_qos_1pRmkSrc_e
+{
+    DOT1P_RMK_SRC_USER_PRI,
+    DOT1P_RMK_SRC_TAG_PRI,
+    DOT1P_RMK_SRC_END
+} rtk_qos_1pRmkSrc_t;
+
+
+/* Types of DSCP remarking source */
+typedef enum rtk_qos_dscpRmkSrc_e
+{
+    DSCP_RMK_SRC_INT_PRI,
+    DSCP_RMK_SRC_DSCP,
+    DSCP_RMK_SRC_USER_PRI,
+    DSCP_RMK_SRC_END
+} rtk_qos_dscpRmkSrc_t;
+
+
+
+
+typedef struct rtk_priority_select_s
+{
+    rtk_uint32 port_pri;
+    rtk_uint32 dot1q_pri;
+    rtk_uint32 acl_pri;
+    rtk_uint32 dscp_pri;
+    rtk_uint32 cvlan_pri;
+    rtk_uint32 svlan_pri;
+    rtk_uint32 dmac_pri;
+    rtk_uint32 smac_pri;
+} rtk_priority_select_t;
+
+typedef struct rtk_qos_pri2queue_s
+{
+    rtk_uint32 pri2queue[RTK_MAX_NUM_OF_PRIORITY];
+} rtk_qos_pri2queue_t;
+
+typedef struct rtk_qos_queue_weights_s
+{
+    rtk_uint32 weights[RTK_MAX_NUM_OF_QUEUE];
+} rtk_qos_queue_weights_t;
+
+typedef enum rtk_qos_scheduling_type_e
+{
+    WFQ = 0,        /* Weighted-Fair-Queue */
+    WRR,            /* Weighted-Round-Robin */
+    SCHEDULING_TYPE_END
+} rtk_qos_scheduling_type_t;
+
+typedef rtk_uint32  rtk_queue_num_t;    /* queue number*/
+
+/* Function Name:
+ *      rtk_qos_init
+ * Description:
+ *      Configure Qos default settings with queue number assigment to each port.
+ * Input:
+ *      queueNum - Queue number of each port.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_QUEUE_NUM    - Invalid queue number.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API will initialize related Qos setting with queue number assigment.
+ *      The queue number is from 1 to 8.
+ */
+extern rtk_api_ret_t rtk_qos_init(rtk_queue_num_t queueNum);
+
+/* Function Name:
+ *      rtk_qos_priSel_set
+ * Description:
+ *      Configure the priority order among different priority mechanism.
+ * Input:
+ *      index - Priority decision table index (0~1)
+ *      pPriDec - Priority assign for port, dscp, 802.1p, cvlan, svlan, acl based priority decision.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_QOS_SEL_PRI_SOURCE   - Invalid priority decision source parameter.
+ * Note:
+ *      ASIC will follow user priority setting of mechanisms to select mapped queue priority for receiving frame.
+ *      If two priority mechanisms are the same, the ASIC will chose the highest priority from mechanisms to
+ *      assign queue priority to receiving frame.
+ *      The priority sources are:
+ *      - PRIDEC_PORT
+ *      - PRIDEC_ACL
+ *      - PRIDEC_DSCP
+ *      - PRIDEC_1Q
+ *      - PRIDEC_1AD
+ *      - PRIDEC_CVLAN
+ *      - PRIDEC_DA
+ *      - PRIDEC_SA
+ */
+extern rtk_api_ret_t rtk_qos_priSel_set(rtk_qos_priDecTbl_t index, rtk_priority_select_t *pPriDec);
+
+
+/* Function Name:
+ *      rtk_qos_priSel_get
+ * Description:
+ *      Get the priority order configuration among different priority mechanism.
+ * Input:
+ *      index - Priority decision table index (0~1)
+ * Output:
+ *      pPriDec - Priority assign for port, dscp, 802.1p, cvlan, svlan, acl based priority decision .
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      ASIC will follow user priority setting of mechanisms to select mapped queue priority for receiving frame.
+ *      If two priority mechanisms are the same, the ASIC will chose the highest priority from mechanisms to
+ *      assign queue priority to receiving frame.
+ *      The priority sources are:
+ *      - PRIDEC_PORT,
+ *      - PRIDEC_ACL,
+ *      - PRIDEC_DSCP,
+ *      - PRIDEC_1Q,
+ *      - PRIDEC_1AD,
+ *      - PRIDEC_CVLAN,
+ *      - PRIDEC_DA,
+ *      - PRIDEC_SA,
+ */
+extern rtk_api_ret_t rtk_qos_priSel_get(rtk_qos_priDecTbl_t index, rtk_priority_select_t *pPriDec);
+
+/* Function Name:
+ *      rtk_qos_1pPriRemap_set
+ * Description:
+ *      Configure 1Q priorities mapping to internal absolute priority.
+ * Input:
+ *      dot1p_pri   - 802.1p priority value.
+ *      int_pri     - internal priority value.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_VLAN_PRIORITY    - Invalid 1p priority.
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ * Note:
+ *      Priority of 802.1Q assignment for internal asic priority, and it is used for queue usage and packet scheduling.
+ */
+extern rtk_api_ret_t rtk_qos_1pPriRemap_set(rtk_pri_t dot1p_pri, rtk_pri_t int_pri);
+
+/* Function Name:
+ *      rtk_qos_1pPriRemap_get
+ * Description:
+ *      Get 1Q priorities mapping to internal absolute priority.
+ * Input:
+ *      dot1p_pri - 802.1p priority value .
+ * Output:
+ *      pInt_pri - internal priority value.
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_VLAN_PRIORITY    - Invalid priority.
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ * Note:
+ *      Priority of 802.1Q assigment for internal asic priority, and it is uesed for queue usage and packet scheduling.
+ */
+extern rtk_api_ret_t rtk_qos_1pPriRemap_get(rtk_pri_t dot1p_pri, rtk_pri_t *pInt_pri);
+
+
+/* Function Name:
+ *      rtk_qos_1pRemarkSrcSel_set
+ * Description:
+ *      Set remarking source of 802.1p remarking.
+ * Input:
+ *      type      - remarking source
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT         - The module is not initial
+ *      RT_ERR_PORT_ID  - invalid port id
+ *      RT_ERR_INPUT            - invalid input parameter
+
+ * Note:
+ *      The API can configure 802.1p remark functionality to map original 802.1p value or internal
+ *      priority to TX DSCP value.
+ */
+extern rtk_api_ret_t rtk_qos_1pRemarkSrcSel_set(rtk_qos_1pRmkSrc_t type);
+
+/* Function Name:
+ *      rtk_qos_1pRemarkSrcSel_get
+ * Description:
+ *      Get remarking source of 802.1p remarking.
+ * Input:
+ *      none
+ * Output:
+ *      pType      - remarking source
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT         - The module is not initial
+ *      RT_ERR_PORT_ID          - invalid port id
+ *      RT_ERR_INPUT            - invalid input parameter
+ *      RT_ERR_NULL_POINTER     - input parameter may be null pointer
+
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_qos_1pRemarkSrcSel_get(rtk_qos_1pRmkSrc_t *pType);
+
+/* Function Name:
+ *      rtk_qos_dscpPriRemap_set
+ * Description:
+ *      Map dscp value to internal priority.
+ * Input:
+ *      dscp    - Dscp value of receiving frame
+ *      int_pri - internal priority value .
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_QOS_DSCP_VALUE   - Invalid DSCP value.
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ * Note:
+ *      The Differentiated Service Code Point is a selector for router's per-hop behaviors. As a selector, there is no implication that a numerically
+ *      greater DSCP implies a better network service. As can be seen, the DSCP totally overlaps the old precedence field of TOS. So if values of
+ *      DSCP are carefully chosen then backward compatibility can be achieved.
+ */
+extern rtk_api_ret_t rtk_qos_dscpPriRemap_set(rtk_dscp_t dscp, rtk_pri_t int_pri);
+
+/* Function Name:
+ *      rtk_qos_dscpPriRemap_get
+ * Description:
+ *      Get dscp value to internal priority.
+ * Input:
+ *      dscp - Dscp value of receiving frame
+ * Output:
+ *      pInt_pri - internal priority value.
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QOS_DSCP_VALUE   - Invalid DSCP value.
+ * Note:
+ *      The Differentiated Service Code Point is a selector for router's per-hop behaviors. As a selector, there is no implication that a numerically
+ *      greater DSCP implies a better network service. As can be seen, the DSCP totally overlaps the old precedence field of TOS. So if values of
+ *      DSCP are carefully chosen then backward compatibility can be achieved.
+ */
+extern rtk_api_ret_t rtk_qos_dscpPriRemap_get(rtk_dscp_t dscp, rtk_pri_t *pInt_pri);
+
+/* Function Name:
+ *      rtk_qos_portPri_set
+ * Description:
+ *      Configure priority usage to each port.
+ * Input:
+ *      port - Port id.
+ *      int_pri - internal priority value.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_QOS_SEL_PORT_PRI - Invalid port priority.
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ * Note:
+ *      The API can set priority of port assignments for queue usage and packet scheduling.
+ */
+extern rtk_api_ret_t rtk_qos_portPri_set(rtk_port_t port, rtk_pri_t int_pri) ;
+
+/* Function Name:
+ *      rtk_qos_portPri_get
+ * Description:
+ *      Get priority usage to each port.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pInt_pri - internal priority value.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get priority of port assignments for queue usage and packet scheduling.
+ */
+extern rtk_api_ret_t rtk_qos_portPri_get(rtk_port_t port, rtk_pri_t *pInt_pri) ;
+
+/* Function Name:
+ *      rtk_qos_queueNum_set
+ * Description:
+ *      Set output queue number for each port.
+ * Input:
+ *      port    - Port id.
+ *      index   - Mapping queue number (1~8)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_QUEUE_NUM    - Invalid queue number.
+ * Note:
+ *      The API can set the output queue number of the specified port. The queue number is from 1 to 8.
+ */
+extern rtk_api_ret_t rtk_qos_queueNum_set(rtk_port_t port, rtk_queue_num_t queue_num);
+
+/* Function Name:
+ *      rtk_qos_queueNum_get
+ * Description:
+ *      Get output queue number.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pQueue_num - Mapping queue number
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API will return the output queue number of the specified port. The queue number is from 1 to 8.
+ */
+extern rtk_api_ret_t rtk_qos_queueNum_get(rtk_port_t port, rtk_queue_num_t *pQueue_num);
+
+/* Function Name:
+ *      rtk_qos_priMap_set
+ * Description:
+ *      Set output queue number for each port.
+ * Input:
+ *      queue_num   - Queue number usage.
+ *      pPri2qid    - Priority mapping to queue ID.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_QUEUE_NUM        - Invalid queue number.
+ *      RT_ERR_QUEUE_ID         - Invalid queue id.
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ * Note:
+ *      ASIC supports priority mapping to queue with different queue number from 1 to 8.
+ *      For different queue numbers usage, ASIC supports different internal available queue IDs.
+ */
+extern rtk_api_ret_t rtk_qos_priMap_set(rtk_queue_num_t queue_num, rtk_qos_pri2queue_t *pPri2qid);
+
+
+/* Function Name:
+ *      rtk_qos_priMap_get
+ * Description:
+ *      Get priority to queue ID mapping table parameters.
+ * Input:
+ *      queue_num - Queue number usage.
+ * Output:
+ *      pPri2qid - Priority mapping to queue ID.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_QUEUE_NUM    - Invalid queue number.
+ * Note:
+ *      The API can return the mapping queue id of the specified priority and queue number.
+ *      The queue number is from 1 to 8.
+ */
+extern rtk_api_ret_t rtk_qos_priMap_get(rtk_queue_num_t queue_num, rtk_qos_pri2queue_t *pPri2qid);
+
+/* Function Name:
+ *      rtk_qos_schedulingQueue_set
+ * Description:
+ *      Set weight and type of queues in dedicated port.
+ * Input:
+ *      port        - Port id.
+ *      pQweights   - The array of weights for WRR/WFQ queue (0 for STRICT_PRIORITY queue).
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_QOS_QUEUE_WEIGHT - Invalid queue weight.
+ * Note:
+ *      The API can set weight and type, strict priority or weight fair queue (WFQ) for
+ *      dedicated port for using queues. If queue id is not included in queue usage,
+ *      then its type and weight setting in dummy for setting. There are priorities
+ *      as queue id in strict queues. It means strict queue id 5 carrying higher priority
+ *      than strict queue id 4. The WFQ queue weight is from 1 to 128, and weight 0 is
+ *      for strict priority queue type.
+ */
+extern rtk_api_ret_t rtk_qos_schedulingQueue_set(rtk_port_t port, rtk_qos_queue_weights_t *pQweights);
+
+/* Function Name:
+ *      rtk_qos_schedulingQueue_get
+ * Description:
+ *      Get weight and type of queues in dedicated port.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pQweights - The array of weights for WRR/WFQ queue (0 for STRICT_PRIORITY queue).
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get weight and type, strict priority or weight fair queue (WFQ) for dedicated port for using queues.
+ *      The WFQ queue weight is from 1 to 128, and weight 0 is for strict priority queue type.
+ */
+extern rtk_api_ret_t rtk_qos_schedulingQueue_get(rtk_port_t port, rtk_qos_queue_weights_t *pQweights);
+
+/* Function Name:
+ *      rtk_qos_1pRemarkEnable_set
+ * Description:
+ *      Set 1p Remarking state
+ * Input:
+ *      port        - Port id.
+ *      enable      - State of per-port 1p Remarking
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_ENABLE       - Invalid enable parameter.
+ * Note:
+ *      The API can enable or disable 802.1p remarking ability for whole system.
+ *      The status of 802.1p remark:
+ *      - DISABLED
+ *      - ENABLED
+ */
+extern rtk_api_ret_t rtk_qos_1pRemarkEnable_set(rtk_port_t port, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_qos_1pRemarkEnable_get
+ * Description:
+ *      Get 802.1p remarking ability.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEnable - Status of 802.1p remark.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get 802.1p remarking ability.
+ *      The status of 802.1p remark:
+ *      - DISABLED
+ *      - ENABLED
+ */
+extern rtk_api_ret_t rtk_qos_1pRemarkEnable_get(rtk_port_t port, rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_qos_1pRemark_set
+ * Description:
+ *      Set 802.1p remarking parameter.
+ * Input:
+ *      int_pri     - Internal priority value.
+ *      dot1p_pri   - 802.1p priority value.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_VLAN_PRIORITY    - Invalid 1p priority.
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ * Note:
+ *      The API can set 802.1p parameters source priority and new priority.
+ */
+extern rtk_api_ret_t rtk_qos_1pRemark_set(rtk_pri_t int_pri, rtk_pri_t dot1p_pri);
+
+/* Function Name:
+ *      rtk_qos_1pRemark_get
+ * Description:
+ *      Get 802.1p remarking parameter.
+ * Input:
+ *      int_pri - Internal priority value.
+ * Output:
+ *      pDot1p_pri - 802.1p priority value.
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ * Note:
+ *      The API can get 802.1p remarking parameters. It would return new priority of ingress priority.
+ */
+extern rtk_api_ret_t rtk_qos_1pRemark_get(rtk_pri_t int_pri, rtk_pri_t *pDot1p_pri);
+
+/* Function Name:
+ *      rtk_qos_dscpRemarkEnable_set
+ * Description:
+ *      Set DSCP remarking ability.
+ * Input:
+ *      port    - Port id.
+ *      enable  - status of DSCP remark.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ *      RT_ERR_ENABLE           - Invalid enable parameter.
+ * Note:
+ *      The API can enable or disable DSCP remarking ability for whole system.
+ *      The status of DSCP remark:
+ *      - DISABLED
+ *      - ENABLED
+ */
+extern rtk_api_ret_t rtk_qos_dscpRemarkEnable_set(rtk_port_t port, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_qos_dscpRemarkEnable_get
+ * Description:
+ *      Get DSCP remarking ability.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEnable - status of DSCP remarking.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get DSCP remarking ability.
+ *      The status of DSCP remark:
+ *      - DISABLED
+ *      - ENABLED
+ */
+extern rtk_api_ret_t rtk_qos_dscpRemarkEnable_get(rtk_port_t port, rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_qos_dscpRemark_set
+ * Description:
+ *      Set DSCP remarking parameter.
+ * Input:
+ *      int_pri - Internal priority value.
+ *      dscp    - DSCP value.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ *      RT_ERR_QOS_DSCP_VALUE   - Invalid DSCP value.
+ * Note:
+ *      The API can set DSCP value and mapping priority.
+ */
+extern rtk_api_ret_t rtk_qos_dscpRemark_set(rtk_pri_t int_pri, rtk_dscp_t dscp);
+
+/* Function Name:
+ *      rtk_qos_dscpRemark_get
+ * Description:
+ *      Get DSCP remarking parameter.
+ * Input:
+ *      int_pri - Internal priority value.
+ * Output:
+ *      Dscp - DSCP value.
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ * Note:
+ *      The API can get DSCP parameters. It would return DSCP value for mapping priority.
+ */
+extern rtk_api_ret_t rtk_qos_dscpRemark_get(rtk_pri_t int_pri, rtk_dscp_t *pDscp);
+
+/* Function Name:
+ *      rtk_qos_dscpRemarkSrcSel_set
+ * Description:
+ *      Set remarking source of DSCP remarking.
+ * Input:
+ *      type      - remarking source
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT         - The module is not initial
+ *      RT_ERR_PORT_ID  - invalid port id
+ *      RT_ERR_INPUT            - invalid input parameter
+
+ * Note:
+ *      The API can configure DSCP remark functionality to map original DSCP value or internal
+ *      priority to TX DSCP value.
+ */
+extern rtk_api_ret_t rtk_qos_dscpRemarkSrcSel_set(rtk_qos_dscpRmkSrc_t type);
+
+
+/* Function Name:
+ *      rtk_qos_dcpRemarkSrcSel_get
+ * Description:
+ *      Get remarking source of DSCP remarking.
+ * Input:
+ *      none
+ * Output:
+ *      pType      - remarking source
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT         - The module is not initial
+ *      RT_ERR_PORT_ID          - invalid port id
+ *      RT_ERR_INPUT            - invalid input parameter
+ *      RT_ERR_NULL_POINTER     - input parameter may be null pointer
+
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_qos_dscpRemarkSrcSel_get(rtk_qos_dscpRmkSrc_t *pType);
+
+
+/* Function Name:
+ *      rtk_qos_dscpRemark2Dscp_set
+ * Description:
+ *      Set DSCP to remarked DSCP mapping.
+ * Input:
+ *      dscp    - DSCP value
+ *      rmkDscp - remarked DSCP value
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_QOS_DSCP_VALUE   - Invalid dscp value
+ * Note:
+ *      dscp parameter can be DSCP value or internal priority according to configuration of API
+ *      dal_apollomp_qos_dscpRemarkSrcSel_set(), because DSCP remark functionality can map original DSCP
+ *      value or internal priority to TX DSCP value.
+ */
+extern rtk_api_ret_t rtk_qos_dscpRemark2Dscp_set(rtk_dscp_t dscp, rtk_dscp_t rmkDscp);
+
+/* Function Name:
+ *      rtk_qos_dscpRemark2Dscp_get
+ * Description:
+ *      Get DSCP to remarked DSCP mapping.
+ * Input:
+ *      dscp    - DSCP value
+ * Output:
+ *      pDscp   - remarked DSCP value
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_QOS_DSCP_VALUE   - Invalid dscp value
+ *      RT_ERR_NULL_POINTER     - NULL pointer
+ * Note:
+ *      None.
+ */
+extern rtk_api_ret_t rtk_qos_dscpRemark2Dscp_get(rtk_dscp_t dscp, rtk_dscp_t *pDscp);
+
+/* Function Name:
+ *      rtk_qos_portPriSelIndex_set
+ * Description:
+ *      Configure priority decision index to each port.
+ * Input:
+ *      port - Port id.
+ *      index - priority decision index.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_ENTRY_INDEX - Invalid entry index.
+ * Note:
+ *      The API can set priority of port assignments for queue usage and packet scheduling.
+ */
+extern rtk_api_ret_t rtk_qos_portPriSelIndex_set(rtk_port_t port, rtk_qos_priDecTbl_t index);
+
+/* Function Name:
+ *      rtk_qos_portPriSelIndex_get
+ * Description:
+ *      Get priority decision index from each port.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pIndex - priority decision index.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get priority of port assignments for queue usage and packet scheduling.
+ */
+extern rtk_api_ret_t rtk_qos_portPriSelIndex_get(rtk_port_t port, rtk_qos_priDecTbl_t *pIndex);
+
+#endif /* __RTK_API_QOS_H__ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rate.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rate.h
new file mode 100644
index 0000000..231ed01
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rate.h
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes rate module high-layer API defination
+ *
+ */
+
+#ifndef __RTK_API_RATE_H__
+#define __RTK_API_RATE_H__
+
+/*
+ * Include Files
+ */
+//#include <rtk_types.h>
+
+/*
+ * Data Type Declaration
+ */
+#define RTK_MAX_METER_ID            (rtk_switch_maxMeterId_get())
+#define RTK_METER_NUM               (RTK_MAX_METER_ID + 1)
+
+typedef enum rtk_meter_type_e{
+    METER_TYPE_KBPS = 0,    /* Kbps */
+    METER_TYPE_PPS,         /* Packet per second */
+    METER_TYPE_END
+}rtk_meter_type_t;
+
+
+/*
+ * Function Declaration
+ */
+
+ /* Rate */
+/* Function Name:
+ *      rtk_rate_shareMeter_set
+ * Description:
+ *      Set meter configuration
+ * Input:
+ *      index       - shared meter index
+ *      type        - shared meter type
+ *      rate        - rate of share meter
+ *      ifg_include - include IFG or not, ENABLE:include DISABLE:exclude
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter
+ *      RT_ERR_RATE             - Invalid rate
+ *      RT_ERR_INPUT            - Invalid input parameters
+ * Note:
+ *      The API can set shared meter rate and ifg include for each meter.
+ *      The rate unit is 1 kbps and the range is from 8k to 1048568k if type is METER_TYPE_KBPS and
+ *      the granularity of rate is 8 kbps.
+ *      The rate unit is packets per second and the range is 1 ~ 0x1FFF if type is METER_TYPE_PPS.
+ *      The ifg_include parameter is used
+ *      for rate calculation with/without inter-frame-gap and preamble.
+ */
+rtk_api_ret_t rtk_rate_shareMeter_set(rtk_meter_id_t index, rtk_meter_type_t type, rtk_rate_t rate, rtk_enable_t ifg_include);
+
+/* Function Name:
+ *      rtk_rate_shareMeter_get
+ * Description:
+ *      Get meter configuration
+ * Input:
+ *      index        - shared meter index
+ * Output:
+ *      pType        - Meter Type
+ *      pRate        - pointer of rate of share meter
+ *      pIfg_include - include IFG or not, ENABLE:include DISABLE:exclude
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_rate_shareMeter_get(rtk_meter_id_t index, rtk_meter_type_t *pType, rtk_rate_t *pRate, rtk_enable_t *pIfg_include);
+
+/* Function Name:
+ *      rtk_rate_shareMeterBucket_set
+ * Description:
+ *      Set meter Bucket Size
+ * Input:
+ *      index        - shared meter index
+ *      bucket_size  - Bucket Size
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_INPUT            - Error Input
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter
+ * Note:
+ *      The API can set shared meter bucket size.
+ */
+extern rtk_api_ret_t rtk_rate_shareMeterBucket_set(rtk_meter_id_t index, rtk_uint32 bucket_size);
+
+/* Function Name:
+ *      rtk_rate_shareMeterBucket_get
+ * Description:
+ *      Get meter Bucket Size
+ * Input:
+ *      index        - shared meter index
+ * Output:
+ *      pBucket_size - Bucket Size
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter
+ * Note:
+ *      The API can get shared meter bucket size.
+ */
+extern rtk_api_ret_t rtk_rate_shareMeterBucket_get(rtk_meter_id_t index, rtk_uint32 *pBucket_size);
+
+/* Function Name:
+ *      rtk_rate_igrBandwidthCtrlRate_set
+ * Description:
+ *      Set port ingress bandwidth control
+ * Input:
+ *      port        - Port id
+ *      rate        - Rate of share meter
+ *      ifg_include - include IFG or not, ENABLE:include DISABLE:exclude
+ *      fc_enable   - enable flow control or not, ENABLE:use flow control DISABLE:drop
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_ENABLE       - Invalid IFG parameter.
+ *      RT_ERR_INBW_RATE    - Invalid ingress rate parameter.
+ * Note:
+ *      The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps.
+ *      The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble.
+ */
+extern rtk_api_ret_t rtk_rate_igrBandwidthCtrlRate_set( rtk_port_t port, rtk_rate_t rate,  rtk_enable_t ifg_include, rtk_enable_t fc_enable);
+
+/* Function Name:
+ *      rtk_rate_igrBandwidthCtrlRate_get
+ * Description:
+ *      Get port ingress bandwidth control
+ * Input:
+ *      port - Port id
+ * Output:
+ *      pRate           - Rate of share meter
+ *      pIfg_include    - Rate's calculation including IFG, ENABLE:include DISABLE:exclude
+ *      pFc_enable      - enable flow control or not, ENABLE:use flow control DISABLE:drop
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *     The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps.
+ *     The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble.
+ */
+extern rtk_api_ret_t rtk_rate_igrBandwidthCtrlRate_get(rtk_port_t port, rtk_rate_t *pRate, rtk_enable_t *pIfg_include, rtk_enable_t *pFc_enable);
+
+/* Function Name:
+ *      rtk_rate_egrBandwidthCtrlRate_set
+ * Description:
+ *      Set port egress bandwidth control
+ * Input:
+ *      port        - Port id
+ *      rate        - Rate of egress bandwidth
+ *      ifg_include - include IFG or not, ENABLE:include DISABLE:exclude
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_QOS_EBW_RATE - Invalid egress bandwidth/rate
+ * Note:
+ *     The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps.
+ *     The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble.
+ */
+extern rtk_api_ret_t rtk_rate_egrBandwidthCtrlRate_set(rtk_port_t port, rtk_rate_t rate,  rtk_enable_t ifg_includ);
+
+/* Function Name:
+ *      rtk_rate_egrBandwidthCtrlRate_get
+ * Description:
+ *      Get port egress bandwidth control
+ * Input:
+ *      port - Port id
+ * Output:
+ *      pRate           - Rate of egress bandwidth
+ *      pIfg_include    - Rate's calculation including IFG, ENABLE:include DISABLE:exclude
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *     The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps.
+ *     The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble.
+ */
+extern rtk_api_ret_t rtk_rate_egrBandwidthCtrlRate_get(rtk_port_t port, rtk_rate_t *pRate, rtk_enable_t *pIfg_include);
+
+/* Function Name:
+ *      rtk_rate_egrQueueBwCtrlEnable_set
+ * Description:
+ *      Set enable status of egress bandwidth control on specified queue.
+ * Input:
+ *      port   - port id
+ *      queue  - queue id
+ *      enable - enable status of egress queue bandwidth control
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID          - invalid port id
+ *      RT_ERR_QUEUE_ID         - invalid queue id
+ *      RT_ERR_INPUT            - invalid input parameter
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_rate_egrQueueBwCtrlEnable_set(rtk_port_t port, rtk_qid_t queue, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_rate_egrQueueBwCtrlRate_get
+ * Description:
+ *      Get rate of egress bandwidth control on specified queue.
+ * Input:
+ *      port  - port id
+ *      queue - queue id
+ *      pIndex - shared meter index
+ * Output:
+ *      pRate - pointer to rate of egress queue bandwidth control
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID          - invalid port id
+ *      RT_ERR_QUEUE_ID         - invalid queue id
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter id
+ * Note:
+ *    None.
+ */
+extern rtk_api_ret_t rtk_rate_egrQueueBwCtrlEnable_get(rtk_port_t port, rtk_qid_t queue, rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_rate_egrQueueBwCtrlRate_set
+ * Description:
+ *      Set rate of egress bandwidth control on specified queue.
+ * Input:
+ *      port  - port id
+ *      queue - queue id
+ *      index - shared meter index
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID          - invalid port id
+ *      RT_ERR_QUEUE_ID         - invalid queue id
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter id
+ * Note:
+ *    The actual rate control is set in shared meters.
+ *    The unit of granularity is 8Kbps.
+ */
+extern rtk_api_ret_t rtk_rate_egrQueueBwCtrlRate_set(rtk_port_t port, rtk_qid_t queue, rtk_meter_id_t index);
+
+/* Function Name:
+ *      rtk_rate_egrQueueBwCtrlRate_get
+ * Description:
+ *      Get rate of egress bandwidth control on specified queue.
+ * Input:
+ *      port  - port id
+ *      queue - queue id
+ *      pIndex - shared meter index
+ * Output:
+ *      pRate - pointer to rate of egress queue bandwidth control
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID          - invalid port id
+ *      RT_ERR_QUEUE_ID         - invalid queue id
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter id
+ * Note:
+ *    The actual rate control is set in shared meters.
+ *    The unit of granularity is 8Kbps.
+ */
+extern rtk_api_ret_t rtk_rate_egrQueueBwCtrlRate_get(rtk_port_t port, rtk_qid_t queue, rtk_meter_id_t *pIndex);
+
+#endif /* __RTK_API_RATE_H__ */
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rldp.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rldp.h
new file mode 100644
index 0000000..111de0c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rldp.h
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : Declaration of RLDP and RLPP API
+ *
+ * Feature : The file have include the following module and sub-modules
+ *           1) RLDP and RLPP configuration and status
+ *
+ */
+
+
+#ifndef __RTK_RLDP_H__
+#define __RTK_RLDP_H__
+
+
+/*
+ * Include Files
+ */
+
+
+/*
+ * Symbol Definition
+ */
+typedef enum rtk_rldp_trigger_e
+{
+    RTK_RLDP_TRIGGER_SAMOVING = 0,
+    RTK_RLDP_TRIGGER_PERIOD,
+    RTK_RLDP_TRIGGER_END
+} rtk_rldp_trigger_t;
+
+typedef enum rtk_rldp_cmpType_e
+{
+    RTK_RLDP_CMPTYPE_MAGIC = 0,     /* Compare the RLDP with magic only */
+    RTK_RLDP_CMPTYPE_MAGIC_ID,      /* Compare the RLDP with both magic + ID */
+    RTK_RLDP_CMPTYPE_END
+} rtk_rldp_cmpType_t;
+
+typedef enum rtk_rldp_loopStatus_e
+{
+    RTK_RLDP_LOOPSTS_NONE = 0,
+    RTK_RLDP_LOOPSTS_LOOPING,
+    RTK_RLDP_LOOPSTS_END
+} rtk_rldp_loopStatus_t;
+
+typedef enum rtk_rlpp_trapType_e
+{
+    RTK_RLPP_TRAPTYPE_NONE = 0,
+    RTK_RLPP_TRAPTYPE_CPU,
+    RTK_RLPP_TRAPTYPE_END
+} rtk_rlpp_trapType_t;
+
+typedef struct rtk_rldp_config_s
+{
+    rtk_enable_t        rldp_enable;
+    rtk_rldp_trigger_t trigger_mode;
+    rtk_mac_t           magic;
+    rtk_rldp_cmpType_t  compare_type;
+    rtk_uint32              interval_check; /* Checking interval for check state */
+    rtk_uint32              num_check;      /* Checking number for check state */
+    rtk_uint32              interval_loop;  /* Checking interval for loop state */
+    rtk_uint32              num_loop;       /* Checking number for loop state */
+} rtk_rldp_config_t;
+
+typedef struct rtk_rldp_portConfig_s
+{
+    rtk_enable_t        tx_enable;
+} rtk_rldp_portConfig_t;
+
+typedef struct rtk_rldp_status_s
+{
+    rtk_mac_t           id;
+} rtk_rldp_status_t;
+
+typedef struct rtk_rldp_portStatus_s
+{
+    rtk_rldp_loopStatus_t   loop_status;
+    rtk_rldp_loopStatus_t   loop_enter;
+    rtk_rldp_loopStatus_t   loop_leave;
+} rtk_rldp_portStatus_t;
+
+/*
+ * Data Declaration
+ */
+
+
+/*
+ * Macro Declaration
+ */
+
+#define RTK_RLDP_INTERVAL_MAX  0xffff
+#define RTK_RLDP_NUM_MAX       0xff
+
+
+/*
+ * Function Declaration
+ */
+
+/* Module Name : RLDP */
+
+
+/* Function Name:
+ *      rtk_rldp_config_set
+ * Description:
+ *      Set RLDP module configuration
+ * Input:
+ *      pConfig - configuration structure of RLDP
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT
+ *      RT_ERR_NULL_POINTER
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_rldp_config_set(rtk_rldp_config_t *pConfig);
+
+
+/* Function Name:
+ *      rtk_rldp_config_get
+ * Description:
+ *      Get RLDP module configuration
+ * Input:
+ *      None
+ * Output:
+ *      pConfig - configuration structure of RLDP
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT
+ *      RT_ERR_NULL_POINTER
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_rldp_config_get(rtk_rldp_config_t *pConfig);
+
+
+/* Function Name:
+ *      rtk_rldp_portConfig_set
+ * Description:
+ *      Set per port RLDP module configuration
+ * Input:
+ *      port   - port number to be configured
+ *      pPortConfig - per port configuration structure of RLDP
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT
+ *      RT_ERR_NULL_POINTER
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_rldp_portConfig_set(rtk_port_t port, rtk_rldp_portConfig_t *pPortConfig);
+
+
+/* Function Name:
+ *      rtk_rldp_portConfig_get
+ * Description:
+ *      Get per port RLDP module configuration
+ * Input:
+ *      port    - port number to be get
+ * Output:
+ *      pPortConfig - per port configuration structure of RLDP
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT
+ *      RT_ERR_NULL_POINTER
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_rldp_portConfig_get(rtk_port_t port, rtk_rldp_portConfig_t *pPortConfig);
+
+
+/* Function Name:
+ *      rtk_rldp_status_get
+ * Description:
+ *      Get RLDP module status
+ * Input:
+ *      None
+ * Output:
+ *      pStatus - status structure of RLDP
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NULL_POINTER
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_rldp_status_get(rtk_rldp_status_t *pStatus);
+
+
+/* Function Name:
+ *      rtk_rldp_portStatus_get
+ * Description:
+ *      Get RLDP module status
+ * Input:
+ *      port    - port number to be get
+ * Output:
+ *      pPortStatus - per port status structure of RLDP
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT
+ *      RT_ERR_NULL_POINTER
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_rldp_portStatus_get(rtk_port_t port, rtk_rldp_portStatus_t *pPortStatus);
+
+
+/* Function Name:
+ *      rtk_rldp_portStatus_clear
+ * Description:
+ *      Clear RLDP module status
+ * Input:
+ *      port    - port number to be clear
+ *      pPortStatus - per port status structure of RLDP
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT
+ *      RT_ERR_NULL_POINTER
+ * Note:
+ *      Clear operation effect loop_enter and loop_leave only, other field in
+ *      the structure are don't care
+ */
+extern rtk_api_ret_t rtk_rldp_portStatus_set(rtk_port_t port, rtk_rldp_portStatus_t *pPortStatus);
+
+
+/* Function Name:
+ *      rtk_rldp_portLoopPair_get
+ * Description:
+ *      Get RLDP port loop pairs
+ * Input:
+ *      port    - port number to be get
+ * Output:
+ *      pPortmask - per port related loop ports
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT
+ *      RT_ERR_NULL_POINTER
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_rldp_portLoopPair_get(rtk_port_t port, rtk_portmask_t *pPortmask);
+
+#endif /* __RTK_RLDP_H__ */
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtk_error.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtk_error.h
new file mode 100644
index 0000000..dc9c0be
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtk_error.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : Definition the error number in the SDK.
+ * Feature : error definition
+ *
+ */
+
+#ifndef __COMMON_RT_ERROR_H__
+#define __COMMON_RT_ERROR_H__
+
+/*
+ * Include Files
+ */
+
+/*
+ * Data Type Declaration
+ */
+typedef enum rt_error_code_e
+{
+    RT_ERR_FAILED = -1,                             /* General Error                                                                    */
+
+    /* 0x0000xxxx for common error code */
+    RT_ERR_OK = 0,                                  /* 0x00000000, OK                                                                   */
+    RT_ERR_INPUT,                                   /* 0x00000001, invalid input parameter                                              */
+    RT_ERR_UNIT_ID,                                 /* 0x00000002, invalid unit id                                                      */
+    RT_ERR_PORT_ID,                                 /* 0x00000003, invalid port id                                                      */
+    RT_ERR_PORT_MASK,                               /* 0x00000004, invalid port mask                                                    */
+    RT_ERR_PORT_LINKDOWN,                           /* 0x00000005, link down port status                                                */
+    RT_ERR_ENTRY_INDEX,                             /* 0x00000006, invalid entry index                                                  */
+    RT_ERR_NULL_POINTER,                            /* 0x00000007, input parameter is null pointer                                      */
+    RT_ERR_QUEUE_ID,                                /* 0x00000008, invalid queue id                                                     */
+    RT_ERR_QUEUE_NUM,                               /* 0x00000009, invalid queue number                                                 */
+    RT_ERR_BUSYWAIT_TIMEOUT,                        /* 0x0000000a, busy watting time out                                                */
+    RT_ERR_MAC,                                     /* 0x0000000b, invalid mac address                                                  */
+    RT_ERR_OUT_OF_RANGE,                            /* 0x0000000c, input parameter out of range                                         */
+    RT_ERR_CHIP_NOT_SUPPORTED,                      /* 0x0000000d, functions not supported by this chip model                           */
+    RT_ERR_SMI,                                     /* 0x0000000e, SMI error                                                            */
+    RT_ERR_NOT_INIT,                                /* 0x0000000f, The module is not initial                                            */
+    RT_ERR_CHIP_NOT_FOUND,                          /* 0x00000010, The chip can not found                                               */
+    RT_ERR_NOT_ALLOWED,                             /* 0x00000011, actions not allowed by the function                                  */
+    RT_ERR_DRIVER_NOT_FOUND,                        /* 0x00000012, The driver can not found                                             */
+    RT_ERR_SEM_LOCK_FAILED,                         /* 0x00000013, Failed to lock semaphore                                             */
+    RT_ERR_SEM_UNLOCK_FAILED,                       /* 0x00000014, Failed to unlock semaphore                                           */
+    RT_ERR_ENABLE,                                  /* 0x00000015, invalid enable parameter                                             */
+    RT_ERR_TBL_FULL,                                /* 0x00000016, input table full                                                     */
+
+    /* 0x0001xxxx for vlan */
+    RT_ERR_VLAN_VID = 0x00010000,                   /* 0x00010000, invalid vid                                                          */
+    RT_ERR_VLAN_PRIORITY,                           /* 0x00010001, invalid 1p priority                                                  */
+    RT_ERR_VLAN_EMPTY_ENTRY,                        /* 0x00010002, emtpy entry of vlan table                                            */
+    RT_ERR_VLAN_ACCEPT_FRAME_TYPE,                  /* 0x00010003, invalid accept frame type                                            */
+    RT_ERR_VLAN_EXIST,                              /* 0x00010004, vlan is exist                                                        */
+    RT_ERR_VLAN_ENTRY_NOT_FOUND,                    /* 0x00010005, specified vlan entry not found                                       */
+    RT_ERR_VLAN_PORT_MBR_EXIST,                     /* 0x00010006, member port exist in the specified vlan                              */
+    RT_ERR_VLAN_PROTO_AND_PORT,                     /* 0x00010008, invalid protocol and port based vlan                              */
+
+    /* 0x0002xxxx for svlan */
+    RT_ERR_SVLAN_ENTRY_INDEX = 0x00020000,          /* 0x00020000, invalid svid entry no                                                */
+    RT_ERR_SVLAN_ETHER_TYPE,                        /* 0x00020001, invalid SVLAN ether type                                             */
+    RT_ERR_SVLAN_TABLE_FULL,                        /* 0x00020002, no empty entry in SVLAN table                                        */
+    RT_ERR_SVLAN_ENTRY_NOT_FOUND,                   /* 0x00020003, specified svlan entry not found                                      */
+    RT_ERR_SVLAN_EXIST,                             /* 0x00020004, SVLAN entry is exist                                                 */
+    RT_ERR_SVLAN_VID,                               /* 0x00020005, invalid svid                                                         */
+
+    /* 0x0003xxxx for MSTP */
+    RT_ERR_MSTI = 0x00030000,                       /* 0x00030000, invalid msti                                                         */
+    RT_ERR_MSTP_STATE,                              /* 0x00030001, invalid spanning tree status                                         */
+    RT_ERR_MSTI_EXIST,                              /* 0x00030002, MSTI exist                                                           */
+    RT_ERR_MSTI_NOT_EXIST,                          /* 0x00030003, MSTI not exist                                                       */
+
+    /* 0x0004xxxx for BUCKET */
+    RT_ERR_TIMESLOT = 0x00040000,                   /* 0x00040000, invalid time slot                                                    */
+    RT_ERR_TOKEN,                                   /* 0x00040001, invalid token amount                                                 */
+    RT_ERR_RATE,                                    /* 0x00040002, invalid rate                                                         */
+    RT_ERR_TICK,                                    /* 0x00040003, invalid tick                                                 */
+
+    /* 0x0005xxxx for RMA */
+    RT_ERR_RMA_ADDR = 0x00050000,                   /* 0x00050000, invalid rma mac address                                              */
+    RT_ERR_RMA_ACTION,                              /* 0x00050001, invalid rma action                                                   */
+
+    /* 0x0006xxxx for L2 */
+    RT_ERR_L2_HASH_KEY = 0x00060000,                /* 0x00060000, invalid L2 Hash key                                                  */
+    RT_ERR_L2_HASH_INDEX,                           /* 0x00060001, invalid L2 Hash index                                                */
+    RT_ERR_L2_CAM_INDEX,                            /* 0x00060002, invalid L2 CAM index                                                 */
+    RT_ERR_L2_ENRTYSEL,                             /* 0x00060003, invalid EntrySel                                                     */
+    RT_ERR_L2_INDEXTABLE_INDEX,                     /* 0x00060004, invalid L2 index table(=portMask table) index                        */
+    RT_ERR_LIMITED_L2ENTRY_NUM,                     /* 0x00060005, invalid limited L2 entry number                                      */
+    RT_ERR_L2_AGGREG_PORT,                          /* 0x00060006, this aggregated port is not the lowest physical
+                                                                   port of its aggregation group                                        */
+    RT_ERR_L2_FID,                                  /* 0x00060007, invalid fid                                                          */
+    RT_ERR_L2_VID,                                 /* 0x00060008, invalid cvid                                                         */
+    RT_ERR_L2_NO_EMPTY_ENTRY,                       /* 0x00060009, no empty entry in L2 table                                           */
+    RT_ERR_L2_ENTRY_NOTFOUND,                       /* 0x0006000a, specified entry not found                                            */
+    RT_ERR_L2_INDEXTBL_FULL,                        /* 0x0006000b, the L2 index table is full                                           */
+    RT_ERR_L2_INVALID_FLOWTYPE,                     /* 0x0006000c, invalid L2 flow type                                                 */
+    RT_ERR_L2_L2UNI_PARAM,                          /* 0x0006000d, invalid L2 unicast parameter                                         */
+    RT_ERR_L2_L2MULTI_PARAM,                        /* 0x0006000e, invalid L2 multicast parameter                                       */
+    RT_ERR_L2_IPMULTI_PARAM,                        /* 0x0006000f, invalid L2 ip multicast parameter                                    */
+    RT_ERR_L2_PARTIAL_HASH_KEY,                     /* 0x00060010, invalid L2 partial Hash key                                          */
+    RT_ERR_L2_EMPTY_ENTRY,                          /* 0x00060011, the entry is empty(invalid)                                          */
+    RT_ERR_L2_FLUSH_TYPE,                           /* 0x00060012, the flush type is invalid                                            */
+    RT_ERR_L2_NO_CPU_PORT,                          /* 0x00060013, CPU port not exist                                                   */
+
+    /* 0x0007xxxx for FILTER (PIE) */
+    RT_ERR_FILTER_BLOCKNUM = 0x00070000,            /* 0x00070000, invalid block number                                                 */
+    RT_ERR_FILTER_ENTRYIDX,                         /* 0x00070001, invalid entry index                                                  */
+    RT_ERR_FILTER_CUTLINE,                          /* 0x00070002, invalid cutline value                                                */
+    RT_ERR_FILTER_FLOWTBLBLOCK,                     /* 0x00070003, block belongs to flow table                                          */
+    RT_ERR_FILTER_INACLBLOCK,                       /* 0x00070004, block belongs to ingress ACL                                         */
+    RT_ERR_FILTER_ACTION,                           /* 0x00070005, action doesn't consist to entry type                                 */
+    RT_ERR_FILTER_INACL_RULENUM,                    /* 0x00070006, invalid ACL rulenum                                                  */
+    RT_ERR_FILTER_INACL_TYPE,                       /* 0x00070007, entry type isn't an ingress ACL rule                                 */
+    RT_ERR_FILTER_INACL_EXIST,                      /* 0x00070008, ACL entry is already exit                                            */
+    RT_ERR_FILTER_INACL_EMPTY,                      /* 0x00070009, ACL entry is empty                                                   */
+    RT_ERR_FILTER_FLOWTBL_TYPE,                     /* 0x0007000a, entry type isn't an flow table rule                                  */
+    RT_ERR_FILTER_FLOWTBL_RULENUM,                  /* 0x0007000b, invalid flow table rulenum                                           */
+    RT_ERR_FILTER_FLOWTBL_EMPTY,                    /* 0x0007000c, flow table entry is empty                                            */
+    RT_ERR_FILTER_FLOWTBL_EXIST,                    /* 0x0007000d, flow table entry is already exist                                    */
+    RT_ERR_FILTER_METER_ID,                         /* 0x0007000e, invalid metering id                                                  */
+    RT_ERR_FILTER_LOG_ID,                           /* 0x0007000f, invalid log id                                                       */
+    RT_ERR_FILTER_INACL_NONE_BEGIN_IDX,             /* 0x00070010, entry index is not starting index of a group of rules                */
+    RT_ERR_FILTER_INACL_ACT_NOT_SUPPORT,            /* 0x00070011, action not support                                                    */
+    RT_ERR_FILTER_INACL_RULE_NOT_SUPPORT,           /* 0x00070012, rule not support                                                   */
+
+    /* 0x0008xxxx for ACL Rate Limit */
+    RT_ERR_ACLRL_HTHR = 0x00080000,                 /* 0x00080000, invalid high threshold                                               */
+    RT_ERR_ACLRL_TIMESLOT,                          /* 0x00080001, invalid time slot                                                    */
+    RT_ERR_ACLRL_TOKEN,                             /* 0x00080002, invalid token amount                                                 */
+    RT_ERR_ACLRL_RATE,                              /* 0x00080003, invalid rate                                                         */
+
+    /* 0x0009xxxx for Link aggregation */
+    RT_ERR_LA_CPUPORT = 0x00090000,                 /* 0x00090000, CPU port can not be aggregated port                                  */
+    RT_ERR_LA_TRUNK_ID,                             /* 0x00090001, invalid trunk id                                                     */
+    RT_ERR_LA_PORTMASK,                             /* 0x00090002, invalid port mask                                                    */
+    RT_ERR_LA_HASHMASK,                             /* 0x00090003, invalid hash mask                                                    */
+    RT_ERR_LA_DUMB,                                 /* 0x00090004, this API should be used in 802.1ad dumb mode                         */
+    RT_ERR_LA_PORTNUM_DUMB,                         /* 0x00090005, it can only aggregate at most four ports when 802.1ad dumb mode      */
+    RT_ERR_LA_PORTNUM_NORMAL,                       /* 0x00090006, it can only aggregate at most eight ports when 802.1ad normal mode   */
+    RT_ERR_LA_MEMBER_OVERLAP,                       /* 0x00090007, the specified port mask is overlapped with other group               */
+    RT_ERR_LA_NOT_MEMBER_PORT,                      /* 0x00090008, the port is not a member port of the trunk                           */
+    RT_ERR_LA_TRUNK_NOT_EXIST,                      /* 0x00090009, the trunk doesn't exist                                              */
+
+
+    /* 0x000axxxx for storm filter */
+    RT_ERR_SFC_TICK_PERIOD = 0x000a0000,            /* 0x000a0000, invalid SFC tick period                                              */
+    RT_ERR_SFC_UNKNOWN_GROUP,                       /* 0x000a0001, Unknown Storm filter group                                           */
+
+    /* 0x000bxxxx for pattern match */
+    RT_ERR_PM_MASK = 0x000b0000,                    /* 0x000b0000, invalid pattern length. Pattern length should be 8                   */
+    RT_ERR_PM_LENGTH,                               /* 0x000b0001, invalid pattern match mask, first byte must care                     */
+    RT_ERR_PM_MODE,                                 /* 0x000b0002, invalid pattern match mode                                           */
+
+    /* 0x000cxxxx for input bandwidth control */
+    RT_ERR_INBW_TICK_PERIOD = 0x000c0000,           /* 0x000c0000, invalid tick period for input bandwidth control                      */
+    RT_ERR_INBW_TOKEN_AMOUNT,                       /* 0x000c0001, invalid amount of token for input bandwidth control                  */
+    RT_ERR_INBW_FCON_VALUE,                         /* 0x000c0002, invalid flow control ON threshold value for input bandwidth control  */
+    RT_ERR_INBW_FCOFF_VALUE,                        /* 0x000c0003, invalid flow control OFF threshold value for input bandwidth control */
+    RT_ERR_INBW_FC_ALLOWANCE,                       /* 0x000c0004, invalid allowance of incomming packet for input bandwidth control    */
+    RT_ERR_INBW_RATE,                               /* 0x000c0005, invalid input bandwidth                                              */
+
+    /* 0x000dxxxx for QoS */
+    RT_ERR_QOS_1P_PRIORITY = 0x000d0000,            /* 0x000d0000, invalid 802.1P priority                                              */
+    RT_ERR_QOS_DSCP_VALUE,                          /* 0x000d0001, invalid DSCP value                                                   */
+    RT_ERR_QOS_INT_PRIORITY,                        /* 0x000d0002, invalid internal priority                                            */
+    RT_ERR_QOS_SEL_DSCP_PRI,                        /* 0x000d0003, invalid DSCP selection priority                                      */
+    RT_ERR_QOS_SEL_PORT_PRI,                        /* 0x000d0004, invalid port selection priority                                      */
+    RT_ERR_QOS_SEL_IN_ACL_PRI,                      /* 0x000d0005, invalid ingress ACL selection priority                               */
+    RT_ERR_QOS_SEL_CLASS_PRI,                       /* 0x000d0006, invalid classifier selection priority                                */
+    RT_ERR_QOS_EBW_RATE,                            /* 0x000d0007, invalid egress bandwidth rate                                        */
+    RT_ERR_QOS_SCHE_TYPE,                           /* 0x000d0008, invalid QoS scheduling type                                          */
+    RT_ERR_QOS_QUEUE_WEIGHT,                        /* 0x000d0009, invalid Queue weight                                                 */
+    RT_ERR_QOS_SEL_PRI_SOURCE,                      /* 0x000d000a, invalid selection of priority source                                                 */
+
+    /* 0x000exxxx for port ability */
+    RT_ERR_PHY_PAGE_ID = 0x000e0000,                /* 0x000e0000, invalid PHY page id                                                  */
+    RT_ERR_PHY_REG_ID,                              /* 0x000e0001, invalid PHY reg id                                                   */
+    RT_ERR_PHY_DATAMASK,                            /* 0x000e0002, invalid PHY data mask                                                */
+    RT_ERR_PHY_AUTO_NEGO_MODE,                      /* 0x000e0003, invalid PHY auto-negotiation mode*/
+    RT_ERR_PHY_SPEED,                               /* 0x000e0004, invalid PHY speed setting                                            */
+    RT_ERR_PHY_DUPLEX,                              /* 0x000e0005, invalid PHY duplex setting                                           */
+    RT_ERR_PHY_FORCE_ABILITY,                       /* 0x000e0006, invalid PHY force mode ability parameter                             */
+    RT_ERR_PHY_FORCE_1000,                          /* 0x000e0007, invalid PHY force mode 1G speed setting                              */
+    RT_ERR_PHY_TXRX,                                /* 0x000e0008, invalid PHY tx/rx                                                    */
+    RT_ERR_PHY_ID,                                  /* 0x000e0009, invalid PHY id                                                       */
+    RT_ERR_PHY_RTCT_NOT_FINISH,                     /* 0x000e000a, PHY RTCT in progress                                                 */
+
+    /* 0x000fxxxx for mirror */
+    RT_ERR_MIRROR_DIRECTION = 0x000f0000,           /* 0x000f0000, invalid error mirror direction                                       */
+    RT_ERR_MIRROR_SESSION_FULL,                     /* 0x000f0001, mirroring session is full                                            */
+    RT_ERR_MIRROR_SESSION_NOEXIST,                  /* 0x000f0002, mirroring session not exist                                          */
+    RT_ERR_MIRROR_PORT_EXIST,                       /* 0x000f0003, mirroring port already exists                                        */
+    RT_ERR_MIRROR_PORT_NOT_EXIST,                   /* 0x000f0004, mirroring port does not exists                                       */
+    RT_ERR_MIRROR_PORT_FULL,                        /* 0x000f0005, Exceeds maximum number of supported mirroring port                   */
+
+    /* 0x0010xxxx for stat */
+    RT_ERR_STAT_INVALID_GLOBAL_CNTR = 0x00100000,   /* 0x00100000, Invalid Global Counter                                               */
+    RT_ERR_STAT_INVALID_PORT_CNTR,                  /* 0x00100001, Invalid Port Counter                                                 */
+    RT_ERR_STAT_GLOBAL_CNTR_FAIL,                   /* 0x00100002, Could not retrieve/reset Global Counter                              */
+    RT_ERR_STAT_PORT_CNTR_FAIL,                     /* 0x00100003, Could not retrieve/reset Port Counter                                */
+    RT_ERR_STAT_INVALID_CNTR,                       /* 0x00100004, Invalid Counter                                                      */
+    RT_ERR_STAT_CNTR_FAIL,                          /* 0x00100005, Could not retrieve/reset Counter                                     */
+
+    /* 0x0011xxxx for dot1x */
+    RT_ERR_DOT1X_INVALID_DIRECTION = 0x00110000,    /* 0x00110000, Invalid Authentication Direction                                     */
+    RT_ERR_DOT1X_PORTBASEDPNEN,                     /* 0x00110001, Port-based enable port error                                         */
+    RT_ERR_DOT1X_PORTBASEDAUTH,                     /* 0x00110002, Port-based auth port error                                           */
+    RT_ERR_DOT1X_PORTBASEDOPDIR,                    /* 0x00110003, Port-based opdir error                                               */
+    RT_ERR_DOT1X_MACBASEDPNEN,                      /* 0x00110004, MAC-based enable port error                                          */
+    RT_ERR_DOT1X_MACBASEDOPDIR,                     /* 0x00110005, MAC-based opdir error                                                */
+    RT_ERR_DOT1X_PROC,                              /* 0x00110006, unauthorized behavior error                                          */
+    RT_ERR_DOT1X_GVLANIDX,                          /* 0x00110007, guest vlan index error                                               */
+    RT_ERR_DOT1X_GVLANTALK,                         /* 0x00110008, guest vlan OPDIR error                                               */
+    RT_ERR_DOT1X_MAC_PORT_MISMATCH,                 /* 0x00110009, Auth MAC and port mismatch eror                                      */
+
+    RT_ERR_END                                       /* The symbol is the latest symbol                                                  */
+} rt_error_code_t;
+
+
+#endif /* __COMMON_RT_ERROR_H__ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtk_hal.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtk_hal.h
new file mode 100644
index 0000000..6ddb23f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtk_hal.h
@@ -0,0 +1,44 @@
+#ifndef __RTK_HAL_H__
+#define __RTK_HAL_H__
+#include "ra_ioctl.h"
+
+#define RTK_SW_VID_RANGE        16
+void rtk_hal_switch_init(void);
+void rtk_hal_dump_mib(void);
+void rtk_hal_dump_full_mib(void);
+int rtk_hal_dump_vlan(void);
+void rtk_hal_clear_vlan(void);
+int rtk_hal_set_vlan(struct ra_switch_ioctl_data *data);
+int rtk_hal_set_ingress_rate(struct ra_switch_ioctl_data *data);
+int rtk_hal_set_egress_rate(struct ra_switch_ioctl_data *data);
+void rtk_hal_dump_table(void);
+void rtk_hal_clear_table(void);
+void rtk_hal_get_phy_status(struct ra_switch_ioctl_data *data);
+void rtk_hal_set_port_mirror(struct ra_switch_ioctl_data *data);
+void rtk_hal_read_reg(struct ra_switch_ioctl_data *data);
+void rtk_hal_write_reg(struct ra_switch_ioctl_data *data);
+void rtk_hal_qos_en(struct ra_switch_ioctl_data *data);
+void rtk_hal_qos_set_table2type(struct ra_switch_ioctl_data *data);
+void rtk_hal_qos_get_table2type(struct ra_switch_ioctl_data *data);
+void rtk_hal_qos_set_port2table(struct ra_switch_ioctl_data *data);
+void rtk_hal_qos_get_port2table(struct ra_switch_ioctl_data *data);
+void rtk_hal_qos_set_port2pri(struct ra_switch_ioctl_data *data);
+void rtk_hal_qos_get_port2pri(struct ra_switch_ioctl_data *data);
+void rtk_hal_qos_set_dscp2pri(struct ra_switch_ioctl_data *data);
+void rtk_hal_qos_get_dscp2pri(struct ra_switch_ioctl_data *data);
+void rtk_hal_qos_set_pri2queue(struct ra_switch_ioctl_data *data);
+void rtk_hal_qos_get_pri2queue(struct ra_switch_ioctl_data *data);
+void rtk_hal_qos_set_queue_weight(struct ra_switch_ioctl_data *data);
+void rtk_hal_qos_get_queue_weight(struct ra_switch_ioctl_data *data);
+void rtk_hal_enable_igmpsnoop(struct ra_switch_ioctl_data *data);
+void rtk_hal_disable_igmpsnoop(void);
+void rtk_hal_set_phy_test_mode(struct ra_switch_ioctl_data *data);
+void rtk_hal_get_phy_reg(struct ra_switch_ioctl_data *data);
+void rtk_hal_set_phy_reg(struct ra_switch_ioctl_data *data);
+void rtk_hal_vlan_tag(struct ra_switch_ioctl_data *data);
+void rtk_hal_vlan_portpvid_set(rtk_port_t port, rtk_vlan_t pvid, rtk_pri_t priority);
+void rtk_hal_add_table(struct ra_switch_ioctl_data *data);
+void rtk_hal_del_table(struct ra_switch_ioctl_data *data);
+void rtk_hal_vlan_mode(struct ra_switch_ioctl_data *data);
+void rtk_hal_set_port_trunk(struct ra_switch_ioctl_data *data);
+#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtk_switch.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtk_switch.h
new file mode 100644
index 0000000..b0ca136
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtk_switch.h
@@ -0,0 +1,737 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76336 $
+ * $Date: 2017-03-09 10:41:21 +0800 (週四, 09 三月 2017) $
+ *
+ * Purpose : RTK switch high-level API
+ * Feature : Here is a list of all functions and variables in this module.
+ *
+ */
+
+#ifndef __RTK_SWITCH_H__
+#define __RTK_SWITCH_H__
+
+#include <rtk_types.h>
+
+#define UNDEFINE_PHY_PORT   (0xFF)
+#define RTK_SWITCH_PORT_NUM (32)
+
+#define MAXPKTLEN_CFG_ID_MAX (1)
+
+#define RTK_SWITCH_MAX_PKTLEN (0x3FFF)
+
+typedef enum init_state_e
+{
+    INIT_NOT_COMPLETED = 0,
+    INIT_COMPLETED,
+    INIT_STATE_END
+} init_state_t;
+
+typedef enum switch_chip_e
+{
+    CHIP_RTL8367C = 0,
+    CHIP_RTL8370B,
+    CHIP_RTL8364B,
+    CHIP_RTL8363SC_VB,
+    CHIP_END
+}switch_chip_t;
+
+typedef enum port_type_e
+{
+    UTP_PORT = 0,
+    EXT_PORT,
+    UNKNOWN_PORT = 0xFF,
+    PORT_TYPE_END
+}port_type_t;
+
+typedef struct rtk_switch_halCtrl_s
+{
+    switch_chip_t   switch_type;
+    rtk_uint32      l2p_port[RTK_SWITCH_PORT_NUM];
+    rtk_uint32      p2l_port[RTK_SWITCH_PORT_NUM];
+    port_type_t     log_port_type[RTK_SWITCH_PORT_NUM];
+    rtk_uint32      ptp_port[RTK_SWITCH_PORT_NUM];
+    rtk_uint32      valid_portmask;
+    rtk_uint32      valid_utp_portmask;
+    rtk_uint32      valid_ext_portmask;
+    rtk_uint32      valid_cpu_portmask;
+    rtk_uint32      min_phy_port;
+    rtk_uint32      max_phy_port;
+    rtk_uint32      phy_portmask;
+    rtk_uint32      combo_logical_port;
+    rtk_uint32      hsg_logical_port;
+    rtk_uint32      sg_logical_portmask;
+    rtk_uint32      max_meter_id;
+    rtk_uint32      max_lut_addr_num;
+    rtk_uint32      trunk_group_mask;
+
+}rtk_switch_halCtrl_t;
+
+typedef enum rtk_switch_maxPktLen_linkSpeed_e {
+     MAXPKTLEN_LINK_SPEED_FE = 0,
+     MAXPKTLEN_LINK_SPEED_GE,
+     MAXPKTLEN_LINK_SPEED_END,
+} rtk_switch_maxPktLen_linkSpeed_t;
+
+
+/* UTIL MACRO */
+#define RTK_CHK_INIT_STATE()                                \
+    do                                                      \
+    {                                                       \
+        if(rtk_switch_initialState_get() != INIT_COMPLETED) \
+        {                                                   \
+            return RT_ERR_NOT_INIT;                         \
+        }                                                   \
+    }while(0)
+
+#define RTK_CHK_PORT_VALID(__port__)                            \
+    do                                                          \
+    {                                                           \
+        if(rtk_switch_logicalPortCheck(__port__) != RT_ERR_OK)  \
+        {                                                       \
+            return RT_ERR_PORT_ID;                              \
+        }                                                       \
+    }while(0)
+
+#define RTK_CHK_PORT_IS_UTP(__port__)                           \
+    do                                                          \
+    {                                                           \
+        if(rtk_switch_isUtpPort(__port__) != RT_ERR_OK)         \
+        {                                                       \
+            return RT_ERR_PORT_ID;                              \
+        }                                                       \
+    }while(0)
+
+#define RTK_CHK_PORT_IS_EXT(__port__)                           \
+    do                                                          \
+    {                                                           \
+        if(rtk_switch_isExtPort(__port__) != RT_ERR_OK)         \
+        {                                                       \
+            return RT_ERR_PORT_ID;                              \
+        }                                                       \
+    }while(0)
+
+#define RTK_CHK_PORT_IS_COMBO(__port__)                         \
+    do                                                          \
+    {                                                           \
+        if(rtk_switch_isComboPort(__port__) != RT_ERR_OK)       \
+        {                                                       \
+            return RT_ERR_PORT_ID;                              \
+        }                                                       \
+    }while(0)
+
+#define RTK_CHK_PORT_IS_PTP(__port__)                           \
+    do                                                          \
+    {                                                           \
+        if(rtk_switch_isPtpPort(__port__) != RT_ERR_OK)         \
+        {                                                       \
+            return RT_ERR_PORT_ID;                              \
+        }                                                       \
+    }while(0)
+
+#define RTK_CHK_PORTMASK_VALID(__portmask__)                        \
+    do                                                              \
+    {                                                               \
+        if(rtk_switch_isPortMaskValid(__portmask__) != RT_ERR_OK)   \
+        {                                                           \
+            return RT_ERR_PORT_MASK;                                \
+        }                                                           \
+    }while(0)
+
+#define RTK_CHK_PORTMASK_VALID_ONLY_UTP(__portmask__)               \
+    do                                                              \
+    {                                                               \
+        if(rtk_switch_isPortMaskUtp(__portmask__) != RT_ERR_OK)     \
+        {                                                           \
+            return RT_ERR_PORT_MASK;                                \
+        }                                                           \
+    }while(0)
+
+#define RTK_CHK_PORTMASK_VALID_ONLY_EXT(__portmask__)               \
+    do                                                              \
+    {                                                               \
+        if(rtk_switch_isPortMaskExt(__portmask__) != RT_ERR_OK)     \
+        {                                                           \
+            return RT_ERR_PORT_MASK;                                \
+        }                                                           \
+    }while(0)
+
+#define RTK_CHK_TRUNK_GROUP_VALID(__grpId__)                        \
+    do                                                              \
+    {                                                               \
+        if(rtk_switch_isValidTrunkGrpId(__grpId__) != RT_ERR_OK)    \
+        {                                                           \
+            return RT_ERR_LA_TRUNK_ID;                              \
+        }                                                           \
+    }while(0)
+
+#define RTK_PORTMASK_IS_PORT_SET(__portmask__, __port__)    (((__portmask__).bits[0] & (0x00000001 << __port__)) ? 1 : 0)
+#define RTK_PORTMASK_IS_EMPTY(__portmask__)                 (((__portmask__).bits[0] == 0) ? 1 : 0)
+#define RTK_PORTMASK_CLEAR(__portmask__)                    ((__portmask__).bits[0] = 0)
+#define RTK_PORTMASK_PORT_SET(__portmask__, __port__)       ((__portmask__).bits[0] |= (0x00000001 << __port__))
+#define RTK_PORTMASK_PORT_CLEAR(__portmask__, __port__)     ((__portmask__).bits[0] &= ~(0x00000001 << __port__))
+#define RTK_PORTMASK_ALLPORT_SET(__portmask__)              (rtk_switch_logPortMask_get(&__portmask__))
+#define RTK_PORTMASK_SCAN(__portmask__, __port__)           for(__port__ = 0; __port__ < RTK_SWITCH_PORT_NUM; __port__++)  if(RTK_PORTMASK_IS_PORT_SET(__portmask__, __port__))
+#define RTK_PORTMASK_COMPARE(__portmask_A__, __portmask_B__)    ((__portmask_A__).bits[0] - (__portmask_B__).bits[0])
+
+#define RTK_SCAN_ALL_PHY_PORTMASK(__port__)                 for(__port__ = 0; __port__ < RTK_SWITCH_PORT_NUM; __port__++)  if( (rtk_switch_phyPortMask_get() & (0x00000001 << __port__)))
+#define RTK_SCAN_ALL_LOG_PORT(__port__)                     for(__port__ = 0; __port__ < RTK_SWITCH_PORT_NUM; __port__++)  if( rtk_switch_logicalPortCheck(__port__) == RT_ERR_OK)
+#define RTK_SCAN_ALL_LOG_PORTMASK(__portmask__)             for((__portmask__).bits[0] = 0; (__portmask__).bits[0] < 0x7FFFF; (__portmask__).bits[0]++)  if( rtk_switch_isPortMaskValid(&__portmask__) == RT_ERR_OK)
+
+/* Port mask defination */
+#define RTK_PHY_PORTMASK_ALL                                (rtk_switch_phyPortMask_get())
+
+/* Port defination*/
+#define RTK_MAX_LOGICAL_PORT_ID                             (rtk_switch_maxLogicalPort_get())
+
+/* Function Name:
+ *      rtk_switch_probe
+ * Description:
+ *      Probe switch
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Switch probed
+ *      RT_ERR_FAILED   - Switch Unprobed.
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_switch_probe(switch_chip_t *pSwitchChip);
+
+/* Function Name:
+ *      rtk_switch_initialState_set
+ * Description:
+ *      Set initial status
+ * Input:
+ *      state   - Initial state;
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Initialized
+ *      RT_ERR_FAILED   - Uninitialized
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_switch_initialState_set(init_state_t state);
+
+/* Function Name:
+ *      rtk_switch_initialState_get
+ * Description:
+ *      Get initial status
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      INIT_COMPLETED     - Initialized
+ *      INIT_NOT_COMPLETED - Uninitialized
+ * Note:
+ *
+ */
+extern init_state_t rtk_switch_initialState_get(void);
+
+/* Function Name:
+ *      rtk_switch_logicalPortCheck
+ * Description:
+ *      Check logical port ID.
+ * Input:
+ *      logicalPort     - logical port ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Port ID is correct
+ *      RT_ERR_FAILED   - Port ID is not correct
+ *      RT_ERR_NOT_INIT - Not Initialize
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_switch_logicalPortCheck(rtk_port_t logicalPort);
+
+/* Function Name:
+ *      rtk_switch_isUtpPort
+ * Description:
+ *      Check is logical port a UTP port
+ * Input:
+ *      logicalPort     - logical port ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Port ID is a UTP port
+ *      RT_ERR_FAILED   - Port ID is not a UTP port
+ *      RT_ERR_NOT_INIT - Not Initialize
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_switch_isUtpPort(rtk_port_t logicalPort);
+
+/* Function Name:
+ *      rtk_switch_isExtPort
+ * Description:
+ *      Check is logical port a Extension port
+ * Input:
+ *      logicalPort     - logical port ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Port ID is a EXT port
+ *      RT_ERR_FAILED   - Port ID is not a EXT port
+ *      RT_ERR_NOT_INIT - Not Initialize
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_switch_isExtPort(rtk_port_t logicalPort);
+
+/* Function Name:
+ *      rtk_switch_isHsgPort
+ * Description:
+ *      Check is logical port a HSG port
+ * Input:
+ *      logicalPort     - logical port ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Port ID is a HSG port
+ *      RT_ERR_FAILED   - Port ID is not a HSG port
+ *      RT_ERR_NOT_INIT - Not Initialize
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_switch_isHsgPort(rtk_port_t logicalPort);
+
+/* Function Name:
+ *      rtk_switch_isSgmiiPort
+ * Description:
+ *      Check is logical port a SGMII port
+ * Input:
+ *      logicalPort     - logical port ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Port ID is a SGMII port
+ *      RT_ERR_FAILED   - Port ID is not a SGMII port
+ *      RT_ERR_NOT_INIT - Not Initialize
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_switch_isSgmiiPort(rtk_port_t logicalPort);
+
+/* Function Name:
+ *      rtk_switch_isCPUPort
+ * Description:
+ *      Check is logical port a CPU port
+ * Input:
+ *      logicalPort     - logical port ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Port ID is a CPU port
+ *      RT_ERR_FAILED   - Port ID is not a CPU port
+ *      RT_ERR_NOT_INIT - Not Initialize
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_switch_isCPUPort(rtk_port_t logicalPort);
+
+/* Function Name:
+ *      rtk_switch_isComboPort
+ * Description:
+ *      Check is logical port a Combo port
+ * Input:
+ *      logicalPort     - logical port ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Port ID is a combo port
+ *      RT_ERR_FAILED   - Port ID is not a combo port
+ *      RT_ERR_NOT_INIT - Not Initialize
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_switch_isComboPort(rtk_port_t logicalPort);
+
+/* Function Name:
+ *      rtk_switch_ComboPort_get
+ * Description:
+ *      Get Combo port ID
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      Port ID of combo port
+ * Note:
+ *
+ */
+extern rtk_uint32 rtk_switch_ComboPort_get(void);
+
+/* Function Name:
+ *      rtk_switch_isPtpPort
+ * Description:
+ *      Check is logical port a PTP port
+ * Input:
+ *      logicalPort     - logical port ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Port ID is a PTP port
+ *      RT_ERR_FAILED   - Port ID is not a PTP port
+ *      RT_ERR_NOT_INIT - Not Initialize
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_switch_isPtpPort(rtk_port_t logicalPort);
+
+/* Function Name:
+ *      rtk_switch_port_L2P_get
+ * Description:
+ *      Get physical port ID
+ * Input:
+ *      logicalPort       - logical port ID
+ * Output:
+ *      None
+ * Return:
+ *      Physical port ID
+ * Note:
+ *
+ */
+extern rtk_uint32 rtk_switch_port_L2P_get(rtk_port_t logicalPort);
+
+/* Function Name:
+ *      rtk_switch_port_P2L_get
+ * Description:
+ *      Get logical port ID
+ * Input:
+ *      physicalPort       - physical port ID
+ * Output:
+ *      None
+ * Return:
+ *      logical port ID
+ * Note:
+ *
+ */
+extern rtk_port_t rtk_switch_port_P2L_get(rtk_uint32 physicalPort);
+
+/* Function Name:
+ *      rtk_switch_isPortMaskValid
+ * Description:
+ *      Check portmask is valid or not
+ * Input:
+ *      pPmask       - logical port mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - port mask is valid
+ *      RT_ERR_FAILED       - port mask is not valid
+ *      RT_ERR_NOT_INIT     - Not Initialize
+ *      RT_ERR_NULL_POINTER - Null pointer
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_switch_isPortMaskValid(rtk_portmask_t *pPmask);
+
+/* Function Name:
+ *      rtk_switch_isPortMaskUtp
+ * Description:
+ *      Check all ports in portmask are only UTP port
+ * Input:
+ *      pPmask       - logical port mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Only UTP port in port mask
+ *      RT_ERR_FAILED       - Not only UTP port in port mask
+ *      RT_ERR_NOT_INIT     - Not Initialize
+ *      RT_ERR_NULL_POINTER - Null pointer
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_switch_isPortMaskUtp(rtk_portmask_t *pPmask);
+
+/* Function Name:
+ *      rtk_switch_isPortMaskExt
+ * Description:
+ *      Check all ports in portmask are only EXT port
+ * Input:
+ *      pPmask       - logical port mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Only EXT port in port mask
+ *      RT_ERR_FAILED       - Not only EXT port in port mask
+ *      RT_ERR_NOT_INIT     - Not Initialize
+ *      RT_ERR_NULL_POINTER - Null pointer
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_switch_isPortMaskExt(rtk_portmask_t *pPmask);
+
+/* Function Name:
+ *      rtk_switch_portmask_L2P_get
+ * Description:
+ *      Get physicl portmask from logical portmask
+ * Input:
+ *      pLogicalPmask       - logical port mask
+ * Output:
+ *      pPhysicalPortmask   - physical port mask
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_NOT_INIT     - Not Initialize
+ *      RT_ERR_NULL_POINTER - Null pointer
+ *      RT_ERR_PORT_MASK    - Error port mask
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_switch_portmask_L2P_get(rtk_portmask_t *pLogicalPmask, rtk_uint32 *pPhysicalPortmask);
+
+/* Function Name:
+ *      rtk_switch_portmask_P2L_get
+ * Description:
+ *      Get logical portmask from physical portmask
+ * Input:
+ *      physicalPortmask    - physical port mask
+ * Output:
+ *      pLogicalPmask       - logical port mask
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_NOT_INIT     - Not Initialize
+ *      RT_ERR_NULL_POINTER - Null pointer
+ *      RT_ERR_PORT_MASK    - Error port mask
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_switch_portmask_P2L_get(rtk_uint32 physicalPortmask, rtk_portmask_t *pLogicalPmask);
+
+/* Function Name:
+ *      rtk_switch_phyPortMask_get
+ * Description:
+ *      Get physical portmask
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      0x00                - Not Initialize
+ *      Other value         - Physical port mask
+ * Note:
+ *
+ */
+rtk_uint32 rtk_switch_phyPortMask_get(void);
+
+/* Function Name:
+ *      rtk_switch_logPortMask_get
+ * Description:
+ *      Get Logical portmask
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_NOT_INIT     - Not Initialize
+ *      RT_ERR_NULL_POINTER - Null pointer
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_switch_logPortMask_get(rtk_portmask_t *pPortmask);
+
+/* Function Name:
+ *      rtk_switch_init
+ * Description:
+ *      Set chip to default configuration enviroment
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      The API can set chip registers to default configuration for different release chip model.
+ */
+extern rtk_api_ret_t rtk_switch_init(void);
+
+/* Function Name:
+ *      rtk_switch_portMaxPktLen_set
+ * Description:
+ *      Set Max packet length
+ * Input:
+ *      port    - Port ID
+ *      speed   - Speed
+ *      cfgId   - Configuration ID
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Error Input
+ * Note:
+ */
+extern rtk_api_ret_t rtk_switch_portMaxPktLen_set(rtk_port_t port, rtk_switch_maxPktLen_linkSpeed_t speed, rtk_uint32 cfgId);
+
+/* Function Name:
+ *      rtk_switch_portMaxPktLen_get
+ * Description:
+ *      Get Max packet length
+ * Input:
+ *      port    - Port ID
+ *      speed   - Speed
+ * Output:
+ *      pCfgId  - Configuration ID
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Error Input
+ * Note:
+ */
+extern rtk_api_ret_t rtk_switch_portMaxPktLen_get(rtk_port_t port, rtk_switch_maxPktLen_linkSpeed_t speed, rtk_uint32 *pCfgId);
+
+/* Function Name:
+ *      rtk_switch_maxPktLenCfg_set
+ * Description:
+ *      Set Max packet length configuration
+ * Input:
+ *      cfgId   - Configuration ID
+ *      pktLen  - Max packet length
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Error Input
+ * Note:
+ */
+extern rtk_api_ret_t rtk_switch_maxPktLenCfg_set(rtk_uint32 cfgId, rtk_uint32 pktLen);
+
+/* Function Name:
+ *      rtk_switch_maxPktLenCfg_get
+ * Description:
+ *      Get Max packet length configuration
+ * Input:
+ *      cfgId   - Configuration ID
+ *      pPktLen - Max packet length
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Error Input
+ * Note:
+ */
+extern rtk_api_ret_t rtk_switch_maxPktLenCfg_get(rtk_uint32 cfgId, rtk_uint32 *pPktLen);
+
+/* Function Name:
+ *      rtk_switch_greenEthernet_set
+ * Description:
+ *      Set all Ports Green Ethernet state.
+ * Input:
+ *      enable - Green Ethernet state.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - OK
+ *      RT_ERR_FAILED   - Failed
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_ENABLE   - Invalid enable input.
+ * Note:
+ *      This API can set all Ports Green Ethernet state.
+ *      The configuration is as following:
+ *      - DISABLE
+ *      - ENABLE
+ */
+extern rtk_api_ret_t rtk_switch_greenEthernet_set(rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_switch_greenEthernet_get
+ * Description:
+ *      Get all Ports Green Ethernet state.
+ * Input:
+ *      None
+ * Output:
+ *      pEnable - Green Ethernet state.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      This API can get Green Ethernet state.
+ */
+extern rtk_api_ret_t rtk_switch_greenEthernet_get(rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_switch_maxLogicalPort_get
+ * Description:
+ *      Get Max logical port ID
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      Max logical port
+ * Note:
+ *      This API can get max logical port
+ */
+extern rtk_port_t rtk_switch_maxLogicalPort_get(void);
+
+/* Function Name:
+ *      rtk_switch_maxMeterId_get
+ * Description:
+ *      Get Max Meter ID
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      0x00                - Not Initialize
+ *      Other value         - Max Meter ID
+ * Note:
+ *
+ */
+extern rtk_uint32 rtk_switch_maxMeterId_get(void);
+
+/* Function Name:
+ *      rtk_switch_maxLutAddrNumber_get
+ * Description:
+ *      Get Max LUT Address number
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      0x00                - Not Initialize
+ *      Other value         - Max LUT Address number
+ * Note:
+ *
+ */
+extern rtk_uint32 rtk_switch_maxLutAddrNumber_get(void);
+
+/* Function Name:
+ *      rtk_switch_isValidTrunkGrpId
+ * Description:
+ *      Check if trunk group is valid or not
+ * Input:
+ *      grpId       - Group ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Trunk Group ID is valid
+ *      RT_ERR_LA_TRUNK_ID  - Trunk Group ID is not valid
+ * Note:
+ *
+ */
+rtk_uint32 rtk_switch_isValidTrunkGrpId(rtk_uint32 grpId);
+
+#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtk_types.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtk_types.h
new file mode 100644
index 0000000..589ecb7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtk_types.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level type enum definition.
+ * Feature :
+ *
+ */
+
+#ifndef _RTL8367C_TYPES_H_
+#define _RTL8367C_TYPES_H_
+
+//#include <stdio.h>
+
+typedef unsigned long long      rtk_uint64;
+typedef long long               rtk_int64;
+typedef unsigned int            rtk_uint32;
+typedef int                     rtk_int32;
+typedef unsigned short          rtk_uint16;
+typedef short                   rtk_int16;
+typedef unsigned char           rtk_uint8;
+typedef char                    rtk_int8;
+
+#define CONST_T     const
+
+#define RTK_TOTAL_NUM_OF_WORD_FOR_1BIT_PORT_LIST    1
+
+#define RTK_MAX_NUM_OF_PORT                         8
+#define RTK_PORT_ID_MAX                             (RTK_MAX_NUM_OF_PORT-1)
+#define RTK_PHY_ID_MAX                              (RTK_MAX_NUM_OF_PORT-4)
+#define RTK_MAX_PORT_MASK                           0xFF
+
+#define RTK_WHOLE_SYSTEM                            0xFF
+
+typedef struct rtk_portmask_s
+{
+    rtk_uint32  bits[RTK_TOTAL_NUM_OF_WORD_FOR_1BIT_PORT_LIST];
+} rtk_portmask_t;
+
+typedef enum rtk_enable_e
+{
+    DISABLED = 0,
+    ENABLED,
+    RTK_ENABLE_END
+} rtk_enable_t;
+
+#ifndef ETHER_ADDR_LEN
+#define ETHER_ADDR_LEN      6
+#endif
+
+/* ethernet address type */
+typedef struct  rtk_mac_s
+{
+    rtk_uint8 octet[ETHER_ADDR_LEN];
+} rtk_mac_t;
+
+typedef rtk_uint32  rtk_pri_t;      /* priority vlaue */
+typedef rtk_uint32  rtk_qid_t;      /* queue id type */
+typedef rtk_uint32  rtk_data_t;
+typedef rtk_uint32  rtk_dscp_t;     /* dscp vlaue */
+typedef rtk_uint32  rtk_fid_t;      /* filter id type */
+typedef rtk_uint32  rtk_vlan_t;     /* vlan id type */
+typedef rtk_uint32  rtk_mac_cnt_t;  /* MAC count type  */
+typedef rtk_uint32  rtk_meter_id_t; /* meter id type  */
+typedef rtk_uint32  rtk_rate_t;     /* rate type  */
+
+typedef enum rtk_port_e
+{
+    UTP_PORT0 = 0,
+    UTP_PORT1,
+    UTP_PORT2,
+    UTP_PORT3,
+    UTP_PORT4,
+    UTP_PORT5,
+    UTP_PORT6,
+    UTP_PORT7,
+
+    EXT_PORT0 = 16,
+    EXT_PORT1,
+    EXT_PORT2,
+
+    UNDEFINE_PORT = 30,
+    RTK_PORT_MAX = 31
+} rtk_port_t;
+
+
+#ifndef _RTL_TYPES_H
+
+#if 0
+typedef unsigned long long      uint64;
+typedef long long               int64;
+typedef unsigned int            uint32;
+typedef int                     int32;
+typedef unsigned short          uint16;
+typedef short                   int16;
+typedef unsigned char           uint8;
+typedef char                    int8;
+#endif
+
+typedef rtk_uint32                  ipaddr_t;
+typedef rtk_uint32                  memaddr;
+
+#ifndef ETHER_ADDR_LEN
+#define ETHER_ADDR_LEN      6
+#endif
+
+typedef struct ether_addr_s {
+    rtk_uint8 octet[ETHER_ADDR_LEN];
+} ether_addr_t;
+
+#ifdef __KERNEL__
+#define rtlglue_printf printk
+#else
+#define rtlglue_printf printf
+#endif
+#define PRINT           rtlglue_printf
+#endif /*_RTL_TYPES_H*/
+
+/* type abstraction */
+#ifdef EMBEDDED_SUPPORT
+
+typedef rtk_int16                   rtk_api_ret_t;
+typedef rtk_int16                   ret_t;
+typedef rtk_uint32                  rtk_u_long;
+
+#else
+
+typedef rtk_int32                   rtk_api_ret_t;
+typedef rtk_int32                   ret_t;
+typedef rtk_uint64                  rtk_u_long_t;
+
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define CONST           const
+#endif /* _RTL8367C_TYPES_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv.h
new file mode 100644
index 0000000..55cb41b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature :
+ *
+ */
+
+
+#ifndef _RTL8367C_ASICDRV_H_
+#define _RTL8367C_ASICDRV_H_
+
+#include <rtk_types.h>
+#include <rtk_error.h>
+#include <rtl8367c_reg.h>
+#include <rtl8367c_base.h>
+
+#define RTL8367C_REGBITLENGTH               16
+#define RTL8367C_REGDATAMAX                 0xFFFF
+
+#define RTL8367C_VIDMAX                     0xFFF
+#define RTL8367C_EVIDMAX                    0x1FFF
+#define RTL8367C_CVIDXNO                    32
+#define RTL8367C_CVIDXMAX                   (RTL8367C_CVIDXNO-1)
+
+#define RTL8367C_PRIMAX                     7
+#define RTL8367C_DSCPMAX                    63
+
+#define RTL8367C_PORTNO                     11
+#define RTL8367C_PORTIDMAX                  (RTL8367C_PORTNO-1)
+#define RTL8367C_PMSKMAX                    ((1<<(RTL8367C_PORTNO))-1)
+#define RTL8367C_PORTMASK                   0x7FF
+
+#define RTL8367C_PHYNO                      5
+#define RTL8367C_PHYIDMAX                  (RTL8367C_PHYNO-1)
+
+#define RTL8367C_SVIDXNO                    64
+#define RTL8367C_SVIDXMAX                   (RTL8367C_SVIDXNO-1)
+#define RTL8367C_MSTIMAX                    15
+
+#define RTL8367C_METERNO                    64
+#define RTL8367C_METERMAX                   (RTL8367C_METERNO-1)
+#define RTL8367C_METERBUCKETSIZEMAX         0xFFFF
+
+#define RTL8367C_QUEUENO                    8
+#define RTL8367C_QIDMAX                     (RTL8367C_QUEUENO-1)
+
+#define RTL8367C_PHY_BUSY_CHECK_COUNTER     1000
+
+#define RTL8367C_QOS_GRANULARTY_MAX         0x7FFFF
+#define RTL8367C_QOS_GRANULARTY_LSB_MASK    0xFFFF
+#define RTL8367C_QOS_GRANULARTY_LSB_OFFSET  0
+#define RTL8367C_QOS_GRANULARTY_MSB_MASK    0x70000
+#define RTL8367C_QOS_GRANULARTY_MSB_OFFSET  16
+
+#define RTL8367C_QOS_GRANULARTY_UNIT_KBPS   8
+
+#define RTL8367C_QOS_RATE_INPUT_MAX         (0x1FFFF * 8)
+#define RTL8367C_QOS_RATE_INPUT_MAX_HSG     (0x7FFFF * 8)
+#define RTL8367C_QOS_RATE_INPUT_MIN         8
+#define RTL8367C_QOS_PPS_INPUT_MAX          (0x7FFFF)
+#define RTL8367C_QOS_PPS_INPUT_MIN          1
+
+#define RTL8367C_QUEUE_MASK                 0xFF
+
+#define RTL8367C_EFIDMAX                    0x7
+#define RTL8367C_FIDMAX                     0xF
+
+#define RTL8367C_EAV_SECONDMAX                  0xFFFFFFFF
+#define RTL8367C_EAV_NANOSECONDMAX          0x3B9AC9FF
+
+
+/* the above macro is generated by genDotH */
+#define RTL8367C_VALID_REG_NO               3869
+
+/*=======================================================================
+ *  Enum
+ *========================================================================*/
+enum RTL8367C_TABLE_ACCESS_OP
+{
+    TB_OP_READ = 0,
+    TB_OP_WRITE
+};
+
+enum RTL8367C_TABLE_ACCESS_TARGET
+{
+    TB_TARGET_ACLRULE = 1,
+    TB_TARGET_ACLACT,
+    TB_TARGET_CVLAN,
+    TB_TARGET_L2,
+    TB_TARGET_IGMP_GROUP
+};
+
+#define RTL8367C_TABLE_ACCESS_REG_DATA(op, target)    ((op << 3) | target)
+
+/*=======================================================================
+ *  Structures
+ *========================================================================*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern ret_t rtl8367c_setAsicRegBit(rtk_uint32 reg, rtk_uint32 bit, rtk_uint32 value);
+extern ret_t rtl8367c_getAsicRegBit(rtk_uint32 reg, rtk_uint32 bit, rtk_uint32 *pValue);
+
+extern ret_t rtl8367c_setAsicRegBits(rtk_uint32 reg, rtk_uint32 bits, rtk_uint32 value);
+extern ret_t rtl8367c_getAsicRegBits(rtk_uint32 reg, rtk_uint32 bits, rtk_uint32 *pValue);
+
+extern ret_t rtl8367c_setAsicReg(rtk_uint32 reg, rtk_uint32 value);
+extern ret_t rtl8367c_getAsicReg(rtk_uint32 reg, rtk_uint32 *pValue);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+#endif /*#ifndef _RTL8367C_ASICDRV_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_acl.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_acl.h
new file mode 100644
index 0000000..8ae69ac
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_acl.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : ACL related function drivers
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_ACL_H_
+#define _RTL8367C_ASICDRV_ACL_H_
+
+#include <rtl8367c_asicdrv.h>
+
+#define RTL8367C_ACLRULENO                  96
+
+#define RTL8367C_ACLRULEMAX                 (RTL8367C_ACLRULENO-1)
+#define RTL8367C_ACLRULEFIELDNO             8
+#define RTL8367C_ACLTEMPLATENO              5
+#define RTL8367C_ACLTYPEMAX                 (RTL8367C_ACLTEMPLATENO-1)
+
+#define RTL8367C_ACLRULETBLEN               9
+#define RTL8367C_ACLACTTBLEN                4
+#define RTL8367C_ACLRULETBADDR(type, rule)  ((type << 6) | rule)
+#define RTL8367C_ACLRULETBADDR2(type, rule) ((type << 5) | (rule + 64))
+
+#define ACL_ACT_CVLAN_ENABLE_MASK           0x1
+#define ACL_ACT_SVLAN_ENABLE_MASK           0x2
+#define ACL_ACT_PRIORITY_ENABLE_MASK        0x4
+#define ACL_ACT_POLICING_ENABLE_MASK        0x8
+#define ACL_ACT_FWD_ENABLE_MASK             0x10
+#define ACL_ACT_INTGPIO_ENABLE_MASK         0x20
+
+#define RTL8367C_ACLRULETAGBITS             5
+
+#define RTL8367C_ACLRANGENO                 16
+
+#define RTL8367C_ACLRANGEMAX                (RTL8367C_ACLRANGENO-1)
+
+#define RTL8367C_ACL_PORTRANGEMAX           (0xFFFF)
+#define RTL8367C_ACL_ACT_TABLE_LEN          (4)
+
+enum ACLTCAMTYPES
+{
+    CAREBITS= 0,
+    DATABITS
+};
+
+typedef enum aclFwdAct
+{
+    RTL8367C_ACL_FWD_MIRROR = 0,
+    RTL8367C_ACL_FWD_REDIRECT,
+    RTL8367C_ACL_FWD_MIRRORFUNTION,
+    RTL8367C_ACL_FWD_TRAP,
+} rtl8367c_aclFwd_t;
+
+enum ACLFIELDTYPES
+{
+    ACL_UNUSED,
+    ACL_DMAC0,
+    ACL_DMAC1,
+    ACL_DMAC2,
+    ACL_SMAC0,
+    ACL_SMAC1,
+    ACL_SMAC2,
+    ACL_ETHERTYPE,
+    ACL_STAG,
+    ACL_CTAG,
+    ACL_IP4SIP0 = 0x10,
+    ACL_IP4SIP1,
+    ACL_IP4DIP0,
+    ACL_IP4DIP1,
+    ACL_IP6SIP0WITHIPV4 = 0x20,
+    ACL_IP6SIP1WITHIPV4,
+    ACL_IP6DIP0WITHIPV4 = 0x28,
+    ACL_IP6DIP1WITHIPV4,
+    ACL_VIDRANGE = 0x30,
+    ACL_IPRANGE,
+    ACL_PORTRANGE,
+    ACL_FIELD_VALID,
+    ACL_FIELD_SELECT00 = 0x40,
+    ACL_FIELD_SELECT01,
+    ACL_FIELD_SELECT02,
+    ACL_FIELD_SELECT03,
+    ACL_FIELD_SELECT04,
+    ACL_FIELD_SELECT05,
+    ACL_FIELD_SELECT06,
+    ACL_FIELD_SELECT07,
+    ACL_FIELD_SELECT08,
+    ACL_FIELD_SELECT09,
+    ACL_FIELD_SELECT10,
+    ACL_FIELD_SELECT11,
+    ACL_FIELD_SELECT12,
+    ACL_FIELD_SELECT13,
+    ACL_FIELD_SELECT14,
+    ACL_FIELD_SELECT15,
+    ACL_TCPSPORT = 0x80,
+    ACL_TCPDPORT,
+    ACL_TCPFLAG,
+    ACL_UDPSPORT,
+    ACL_UDPDPORT,
+    ACL_ICMPCODETYPE,
+    ACL_IGMPTYPE,
+    ACL_SPORT,
+    ACL_DPORT,
+    ACL_IP4TOSPROTO,
+    ACL_IP4FLAGOFF,
+    ACL_TCNH,
+    ACL_CPUTAG,
+    ACL_L2PAYLOAD,
+    ACL_IP6SIP0,
+    ACL_IP6SIP1,
+    ACL_IP6SIP2,
+    ACL_IP6SIP3,
+    ACL_IP6SIP4,
+    ACL_IP6SIP5,
+    ACL_IP6SIP6,
+    ACL_IP6SIP7,
+    ACL_IP6DIP0,
+    ACL_IP6DIP1,
+    ACL_IP6DIP2,
+    ACL_IP6DIP3,
+    ACL_IP6DIP4,
+    ACL_IP6DIP5,
+    ACL_IP6DIP6,
+    ACL_IP6DIP7,
+    ACL_TYPE_END
+};
+
+struct acl_rule_smi_st{
+    rtk_uint16 rule_info;
+    rtk_uint16 field[RTL8367C_ACLRULEFIELDNO];
+};
+
+struct acl_rule_smi_ext_st{
+    rtk_uint16 rule_info;
+};
+
+typedef struct ACLRULESMI{
+    struct acl_rule_smi_st  care_bits;
+    rtk_uint16      valid:1;
+    struct acl_rule_smi_st  data_bits;
+
+    struct acl_rule_smi_ext_st care_bits_ext;
+    struct acl_rule_smi_ext_st data_bits_ext;
+}rtl8367c_aclrulesmi;
+
+struct acl_rule_st{
+    rtk_uint16 active_portmsk:11;
+    rtk_uint16 type:3;
+    rtk_uint16 tag_exist:5;
+    rtk_uint16 field[RTL8367C_ACLRULEFIELDNO];
+};
+
+typedef struct ACLRULE{
+    struct acl_rule_st  data_bits;
+    rtk_uint16      valid:1;
+    struct acl_rule_st  care_bits;
+}rtl8367c_aclrule;
+
+
+typedef struct rtl8367c_acltemplate_s{
+    rtk_uint8 field[8];
+}rtl8367c_acltemplate_t;
+
+
+typedef struct acl_act_s{
+    rtk_uint16 cvidx_cact:7;
+    rtk_uint16 cact:2;
+    rtk_uint16 svidx_sact:7;
+    rtk_uint16 sact:2;
+
+
+    rtk_uint16 aclmeteridx:7;
+    rtk_uint16 fwdpmask:11;
+    rtk_uint16 fwdact:2;
+
+    rtk_uint16 pridx:7;
+    rtk_uint16 priact:2;
+    rtk_uint16 gpio_pin:4;
+    rtk_uint16 gpio_en:1;
+    rtk_uint16 aclint:1;
+
+    rtk_uint16 cact_ext:2;
+    rtk_uint16 fwdact_ext:1;
+    rtk_uint16 tag_fmt:2;
+}rtl8367c_acl_act_t;
+
+typedef struct acl_rule_union_s
+{
+    rtl8367c_aclrule aclRule;
+    rtl8367c_acl_act_t aclAct;
+    rtk_uint32 aclActCtrl;
+    rtk_uint32 aclNot;
+}rtl8367c_acl_rule_union_t;
+
+
+extern ret_t rtl8367c_setAsicAcl(rtk_uint32 port, rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicAcl(rtk_uint32 port, rtk_uint32* pEnabled);
+extern ret_t rtl8367c_setAsicAclUnmatchedPermit(rtk_uint32 port, rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicAclUnmatchedPermit(rtk_uint32 port, rtk_uint32* pEnabled);
+extern ret_t rtl8367c_setAsicAclRule(rtk_uint32 index, rtl8367c_aclrule *pAclRule);
+extern ret_t rtl8367c_getAsicAclRule(rtk_uint32 index, rtl8367c_aclrule *pAclRule);
+extern ret_t rtl8367c_setAsicAclNot(rtk_uint32 index, rtk_uint32 not);
+extern ret_t rtl8367c_getAsicAclNot(rtk_uint32 index, rtk_uint32* pNot);
+extern ret_t rtl8367c_setAsicAclTemplate(rtk_uint32 index, rtl8367c_acltemplate_t* pAclType);
+extern ret_t rtl8367c_getAsicAclTemplate(rtk_uint32 index, rtl8367c_acltemplate_t *pAclType);
+extern ret_t rtl8367c_setAsicAclAct(rtk_uint32 index, rtl8367c_acl_act_t* pAclAct);
+extern ret_t rtl8367c_getAsicAclAct(rtk_uint32 index, rtl8367c_acl_act_t *pAclAct);
+extern ret_t rtl8367c_setAsicAclActCtrl(rtk_uint32 index, rtk_uint32 aclActCtrl);
+extern ret_t rtl8367c_getAsicAclActCtrl(rtk_uint32 index, rtk_uint32 *aclActCtrl);
+extern ret_t rtl8367c_setAsicAclPortRange(rtk_uint32 index, rtk_uint32 type, rtk_uint32 upperPort, rtk_uint32 lowerPort);
+extern ret_t rtl8367c_getAsicAclPortRange(rtk_uint32 index, rtk_uint32* pType, rtk_uint32* pUpperPort, rtk_uint32* pLowerPort);
+extern ret_t rtl8367c_setAsicAclVidRange(rtk_uint32 index, rtk_uint32 type, rtk_uint32 upperVid, rtk_uint32 lowerVid);
+extern ret_t rtl8367c_getAsicAclVidRange(rtk_uint32 index, rtk_uint32* pType, rtk_uint32* pUpperVid, rtk_uint32* pLowerVid);
+extern ret_t rtl8367c_setAsicAclIpRange(rtk_uint32 index, rtk_uint32 type, ipaddr_t upperIp, ipaddr_t lowerIp);
+extern ret_t rtl8367c_getAsicAclIpRange(rtk_uint32 index, rtk_uint32* pType, ipaddr_t* pUpperIp, ipaddr_t* pLowerIp);
+extern ret_t rtl8367c_setAsicAclGpioPolarity(rtk_uint32 polarity);
+extern ret_t rtl8367c_getAsicAclGpioPolarity(rtk_uint32* pPolarity);
+
+#endif /*_RTL8367C_ASICDRV_ACL_H_*/
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_cputag.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_cputag.h
new file mode 100644
index 0000000..f7a4601
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_cputag.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Proprietary CPU-tag related function drivers
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_CPUTAG_H_
+#define _RTL8367C_ASICDRV_CPUTAG_H_
+
+#include <rtl8367c_asicdrv.h>
+
+enum CPUTAG_INSERT_MODE
+{
+    CPUTAG_INSERT_TO_ALL = 0,
+    CPUTAG_INSERT_TO_TRAPPING,
+    CPUTAG_INSERT_TO_NO,
+    CPUTAG_INSERT_END
+};
+
+extern ret_t rtl8367c_setAsicCputagEnable(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicCputagEnable(rtk_uint32 *pEnabled);
+extern ret_t rtl8367c_setAsicCputagTrapPort(rtk_uint32 port);
+extern ret_t rtl8367c_getAsicCputagTrapPort(rtk_uint32 *pPort);
+extern ret_t rtl8367c_setAsicCputagPortmask(rtk_uint32 portmask);
+extern ret_t rtl8367c_getAsicCputagPortmask(rtk_uint32 *pPmsk);
+extern ret_t rtl8367c_setAsicCputagInsertMode(rtk_uint32 mode);
+extern ret_t rtl8367c_getAsicCputagInsertMode(rtk_uint32 *pMode);
+extern ret_t rtl8367c_setAsicCputagPriorityRemapping(rtk_uint32 srcPri, rtk_uint32 newPri);
+extern ret_t rtl8367c_getAsicCputagPriorityRemapping(rtk_uint32 srcPri, rtk_uint32 *pNewPri);
+extern ret_t rtl8367c_setAsicCputagPosition(rtk_uint32 postion);
+extern ret_t rtl8367c_getAsicCputagPosition(rtk_uint32* pPostion);
+extern ret_t rtl8367c_setAsicCputagMode(rtk_uint32 mode);
+extern ret_t rtl8367c_getAsicCputagMode(rtk_uint32 *pMode);
+extern ret_t rtl8367c_setAsicCputagRxMinLength(rtk_uint32 mode);
+extern ret_t rtl8367c_getAsicCputagRxMinLength(rtk_uint32 *pMode);
+
+#endif /*#ifndef _RTL8367C_ASICDRV_CPUTAG_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_dot1x.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_dot1x.h
new file mode 100644
index 0000000..7639ae7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_dot1x.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : 802.1X related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_DOT1X_H_
+#define _RTL8367C_ASICDRV_DOT1X_H_
+
+#include <rtl8367c_asicdrv.h>
+
+enum DOT1X_UNAUTH_BEHAV
+{
+    DOT1X_UNAUTH_DROP = 0,
+    DOT1X_UNAUTH_TRAP,
+    DOT1X_UNAUTH_GVLAN,
+    DOT1X_UNAUTH_END
+};
+
+extern ret_t rtl8367c_setAsic1xPBEnConfig(rtk_uint32 port, rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsic1xPBEnConfig(rtk_uint32 port, rtk_uint32 *pEnabled);
+extern ret_t rtl8367c_setAsic1xPBAuthConfig(rtk_uint32 port, rtk_uint32 auth);
+extern ret_t rtl8367c_getAsic1xPBAuthConfig(rtk_uint32 port, rtk_uint32 *pAuth);
+extern ret_t rtl8367c_setAsic1xPBOpdirConfig(rtk_uint32 port, rtk_uint32 opdir);
+extern ret_t rtl8367c_getAsic1xPBOpdirConfig(rtk_uint32 port, rtk_uint32 *pOpdir);
+extern ret_t rtl8367c_setAsic1xMBEnConfig(rtk_uint32 port, rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsic1xMBEnConfig(rtk_uint32 port, rtk_uint32 *pEnabled);
+extern ret_t rtl8367c_setAsic1xMBOpdirConfig(rtk_uint32 opdir);
+extern ret_t rtl8367c_getAsic1xMBOpdirConfig(rtk_uint32 *pOpdir);
+extern ret_t rtl8367c_setAsic1xProcConfig(rtk_uint32 port, rtk_uint32 proc);
+extern ret_t rtl8367c_getAsic1xProcConfig(rtk_uint32 port, rtk_uint32 *pProc);
+extern ret_t rtl8367c_setAsic1xGuestVidx(rtk_uint32 index);
+extern ret_t rtl8367c_getAsic1xGuestVidx(rtk_uint32 *pIndex);
+extern ret_t rtl8367c_setAsic1xGVOpdir(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsic1xGVOpdir(rtk_uint32 *pEnabled);
+extern ret_t rtl8367c_setAsic1xTrapPriority(rtk_uint32 priority);
+extern ret_t rtl8367c_getAsic1xTrapPriority(rtk_uint32 *pPriority);
+
+
+#endif /*_RTL8367C_ASICDRV_DOT1X_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eav.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eav.h
new file mode 100644
index 0000000..b633f66
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eav.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Ethernet AV related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_EAV_H_
+#define _RTL8367C_ASICDRV_EAV_H_
+
+#include <rtl8367c_asicdrv.h>
+
+typedef enum RTL8367C_PTP_TIME_CMD_E
+{
+    PTP_TIME_READ = 0,
+    PTP_TIME_WRITE,
+    PTP_TIME_INC,
+    PTP_TIME_DEC,
+    PTP_TIME_CMD_END
+}RTL8367C_PTP_TIME_CMD;
+
+typedef enum RTL8367C_PTP_TIME_ADJ_E
+{
+    PTP_TIME_ADJ_INC = 0,
+    PTP_TIME_ADJ_DEC,
+    PTP_TIME_ADJ_END
+}RTL8367C_PTP_TIME_ADJ;
+
+typedef enum RTL8367C_PTP_TIME_CTRL_E
+{
+    PTP_TIME_CTRL_STOP = 0,
+    PTP_TIME_CTRL_START,
+    PTP_TIME_CTRL_END
+}RTL8367C_PTP_TIME_CTRL;
+
+typedef enum RTL8367C_PTP_INTR_IMRS_E
+{
+    PTP_IMRS_TX_SYNC,
+    PTP_IMRS_TX_DELAY_REQ,
+    PTP_IMRS_TX_PDELAY_REQ,
+    PTP_IMRS_TX_PDELAY_RESP,
+    PTP_IMRS_RX_SYNC,
+    PTP_IMRS_RX_DELAY_REQ,
+    PTP_IMRS_RX_PDELAY_REQ,
+    PTP_IMRS_RX_PDELAY_RESP,
+    PTP_IMRS_END,
+}RTL8367C_PTP_INTR_IMRS;
+
+
+typedef enum RTL8367C_PTP_PKT_TYPE_E
+{
+    PTP_PKT_TYPE_TX_SYNC,
+    PTP_PKT_TYPE_TX_DELAY_REQ,
+    PTP_PKT_TYPE_TX_PDELAY_REQ,
+    PTP_PKT_TYPE_TX_PDELAY_RESP,
+    PTP_PKT_TYPE_RX_SYNC,
+    PTP_PKT_TYPE_RX_DELAY_REQ,
+    PTP_PKT_TYPE_RX_PDELAY_REQ,
+    PTP_PKT_TYPE_RX_PDELAY_RESP,
+    PTP_PKT_TYPE_END,
+}RTL8367C_PTP_PKT_TYPE;
+
+typedef struct  rtl8367c_ptp_time_stamp_s{
+    rtk_uint32 sequence_id;
+    rtk_uint32 second;
+    rtk_uint32 nano_second;
+}rtl8367c_ptp_time_stamp_t;
+
+#define RTL8367C_PTP_INTR_MASK        0xFF
+
+#define RTL8367C_PTP_PORT_MASK        0x3FF
+
+extern ret_t rtl8367c_setAsicEavMacAddress(ether_addr_t mac);
+extern ret_t rtl8367c_getAsicEavMacAddress(ether_addr_t *pMac);
+extern ret_t rtl8367c_setAsicEavTpid(rtk_uint32 outerTag, rtk_uint32 innerTag);
+extern ret_t rtl8367c_getAsicEavTpid(rtk_uint32* pOuterTag, rtk_uint32* pInnerTag);
+extern ret_t rtl8367c_setAsicEavSysTime(rtk_uint32 second, rtk_uint32 nanoSecond);
+extern ret_t rtl8367c_getAsicEavSysTime(rtk_uint32* pSecond, rtk_uint32* pNanoSecond);
+extern ret_t rtl8367c_setAsicEavSysTimeAdjust(rtk_uint32 type, rtk_uint32 second, rtk_uint32 nanoSecond);
+extern ret_t rtl8367c_setAsicEavSysTimeCtrl(rtk_uint32 control);
+extern ret_t rtl8367c_getAsicEavSysTimeCtrl(rtk_uint32* pControl);
+extern ret_t rtl8367c_setAsicEavInterruptMask(rtk_uint32 imr);
+extern ret_t rtl8367c_getAsicEavInterruptMask(rtk_uint32* pImr);
+extern ret_t rtl8367c_getAsicEavInterruptStatus(rtk_uint32* pIms);
+extern ret_t rtl8367c_setAsicEavPortInterruptStatus(rtk_uint32 port, rtk_uint32 ims);
+extern ret_t rtl8367c_getAsicEavPortInterruptStatus(rtk_uint32 port, rtk_uint32* pIms);
+extern ret_t rtl8367c_setAsicEavPortEnable(rtk_uint32 port, rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicEavPortEnable(rtk_uint32 port, rtk_uint32 *pEnabled);
+extern ret_t rtl8367c_getAsicEavPortTimeStamp(rtk_uint32 port, rtk_uint32 type, rtl8367c_ptp_time_stamp_t* timeStamp);
+
+extern ret_t rtl8367c_setAsicEavTrap(rtk_uint32 port, rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicEavTrap(rtk_uint32 port, rtk_uint32 *pEnabled);
+extern ret_t rtl8367c_setAsicEavEnable(rtk_uint32 port, rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicEavEnable(rtk_uint32 port, rtk_uint32 *pEnabled);
+extern ret_t rtl8367c_setAsicEavPriRemapping(rtk_uint32 srcpriority, rtk_uint32 priority);
+extern ret_t rtl8367c_getAsicEavPriRemapping(rtk_uint32 srcpriority, rtk_uint32 *pPriority);
+
+#endif /*#ifndef _RTL8367C_ASICDRV_EAV_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eee.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eee.h
new file mode 100644
index 0000000..6bedce6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eee.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 48989 $
+ * $Date: 2014-07-01 15:45:24 +0800 (¶g¤G, 01 ¤C¤ë 2014) $
+ *
+ * Purpose : RTL8370 switch high-level API for RTL8367C
+ * Feature :
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_EEE_H_
+#define _RTL8367C_ASICDRV_EEE_H_
+
+#include <rtl8367c_asicdrv.h>
+
+#define EEE_OCP_PHY_ADDR    (0xA5D0)
+
+extern ret_t rtl8367c_setAsicEee100M(rtk_uint32 port, rtk_uint32 enable);
+extern ret_t rtl8367c_getAsicEee100M(rtk_uint32 port, rtk_uint32 *enable);
+extern ret_t rtl8367c_setAsicEeeGiga(rtk_uint32 port, rtk_uint32 enable);
+extern ret_t rtl8367c_getAsicEeeGiga(rtk_uint32 port, rtk_uint32 *enable);
+
+
+#endif /*_RTL8367C_ASICDRV_EEE_H_*/
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_fc.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_fc.h
new file mode 100644
index 0000000..ce67cde
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_fc.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Flow control related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_FC_H_
+#define _RTL8367C_ASICDRV_FC_H_
+
+#include <rtl8367c_asicdrv.h>
+
+#define RTL8367C_PAGE_NUMBER    0x600
+
+
+enum FLOW_CONTROL_TYPE
+{
+    FC_EGRESS = 0,
+    FC_INGRESS,
+};
+
+enum FC_JUMBO_SIZE
+{
+    FC_JUMBO_SIZE_3K = 0,
+    FC_JUMBO_SIZE_4K,
+    FC_JUMBO_SIZE_6K,
+    FC_JUMBO_SIZE_9K,
+    FC_JUMBO_SIZE_END,
+
+};
+
+
+extern ret_t rtl8367c_setAsicFlowControlSelect(rtk_uint32 select);
+extern ret_t rtl8367c_getAsicFlowControlSelect(rtk_uint32 *pSelect);
+extern ret_t rtl8367c_setAsicFlowControlJumboMode(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicFlowControlJumboMode(rtk_uint32* pEnabled);
+extern ret_t rtl8367c_setAsicFlowControlJumboModeSize(rtk_uint32 size);
+extern ret_t rtl8367c_getAsicFlowControlJumboModeSize(rtk_uint32* pSize);
+extern ret_t rtl8367c_setAsicFlowControlQueueEgressEnable(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicFlowControlQueueEgressEnable(rtk_uint32 port, rtk_uint32 qid, rtk_uint32* pEnabled);
+extern ret_t rtl8367c_setAsicFlowControlDropAll(rtk_uint32 dropall);
+extern ret_t rtl8367c_getAsicFlowControlDropAll(rtk_uint32* pDropall);
+extern ret_t rtl8367c_setAsicFlowControlPauseAllThreshold(rtk_uint32 threshold);
+extern ret_t rtl8367c_getAsicFlowControlPauseAllThreshold(rtk_uint32 *pThreshold);
+extern ret_t rtl8367c_setAsicFlowControlSystemThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold);
+extern ret_t rtl8367c_getAsicFlowControlSystemThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold);
+extern ret_t rtl8367c_setAsicFlowControlSharedThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold);
+extern ret_t rtl8367c_getAsicFlowControlSharedThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold);
+extern ret_t rtl8367c_setAsicFlowControlPortThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold);
+extern ret_t rtl8367c_getAsicFlowControlPortThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold);
+extern ret_t rtl8367c_setAsicFlowControlPortPrivateThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold);
+extern ret_t rtl8367c_getAsicFlowControlPortPrivateThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold);
+extern ret_t rtl8367c_setAsicFlowControlSystemDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold);
+extern ret_t rtl8367c_getAsicFlowControlSystemDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold);
+extern ret_t rtl8367c_setAsicFlowControlSharedDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold);
+extern ret_t rtl8367c_getAsicFlowControlSharedDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold);
+extern ret_t rtl8367c_setAsicFlowControlPortDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold);
+extern ret_t rtl8367c_getAsicFlowControlPortDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold);
+extern ret_t rtl8367c_setAsicFlowControlPortPrivateDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold);
+extern ret_t rtl8367c_getAsicFlowControlPortPrivateDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold);
+extern ret_t rtl8367c_setAsicFlowControlSystemJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold);
+extern ret_t rtl8367c_getAsicFlowControlSystemJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold);
+extern ret_t rtl8367c_setAsicFlowControlSharedJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold);
+extern ret_t rtl8367c_getAsicFlowControlSharedJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold);
+extern ret_t rtl8367c_setAsicFlowControlPortJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold);
+extern ret_t rtl8367c_getAsicFlowControlPortJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold);
+extern ret_t rtl8367c_setAsicFlowControlPortPrivateJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold);
+extern ret_t rtl8367c_getAsicFlowControlPortPrivateJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold);
+
+extern ret_t rtl8367c_setAsicEgressFlowControlPortDropGap(rtk_uint32 gap);
+extern ret_t rtl8367c_getAsicEgressFlowControlPortDropGap(rtk_uint32 *pGap);
+extern ret_t rtl8367c_setAsicEgressFlowControlQueueDropGap(rtk_uint32 gap);
+extern ret_t rtl8367c_getAsicEgressFlowControlQueueDropGap(rtk_uint32 *pGap);
+extern ret_t rtl8367c_setAsicEgressFlowControlPortDropThreshold(rtk_uint32 port, rtk_uint32 threshold);
+extern ret_t rtl8367c_getAsicEgressFlowControlPortDropThreshold(rtk_uint32 port, rtk_uint32 *pThreshold);
+extern ret_t rtl8367c_setAsicEgressFlowControlQueueDropThreshold(rtk_uint32 qid, rtk_uint32 threshold);
+extern ret_t rtl8367c_getAsicEgressFlowControlQueueDropThreshold(rtk_uint32 qid, rtk_uint32 *pThreshold);
+extern ret_t rtl8367c_getAsicEgressQueueEmptyPortMask(rtk_uint32 *pPortmask);
+extern ret_t rtl8367c_getAsicTotalPage(rtk_uint32 *pPageCount);
+extern ret_t rtl8367c_getAsicPulbicPage(rtk_uint32 *pPageCount);
+extern ret_t rtl8367c_getAsicMaxTotalPage(rtk_uint32 *pPageCount);
+extern ret_t rtl8367c_getAsicMaxPulbicPage(rtk_uint32 *pPageCount);
+extern ret_t rtl8367c_getAsicPortPage(rtk_uint32 port, rtk_uint32 *pPageCount);
+extern ret_t rtl8367c_getAsicPortPageMax(rtk_uint32 port, rtk_uint32 *pPageCount);
+extern ret_t rtl8367c_setAsicFlowControlEgressPortIndep(rtk_uint32 port, rtk_uint32 enable);
+extern ret_t rtl8367c_getAsicFlowControlEgressPortIndep(rtk_uint32 port, rtk_uint32 *pEnable);
+
+#endif /*_RTL8367C_ASICDRV_FC_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_green.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_green.h
new file mode 100644
index 0000000..38fd085
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_green.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Green ethernet related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_GREEN_H_
+#define _RTL8367C_ASICDRV_GREEN_H_
+
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_phy.h>
+
+#define PHY_POWERSAVING_REG                         24
+
+extern ret_t rtl8367c_setAsicGreenTrafficType(rtk_uint32 priority, rtk_uint32 traffictype);
+extern ret_t rtl8367c_getAsicGreenTrafficType(rtk_uint32 priority, rtk_uint32* pTraffictype);
+extern ret_t rtl8367c_getAsicGreenPortPage(rtk_uint32 port, rtk_uint32* pPage);
+extern ret_t rtl8367c_getAsicGreenHighPriorityTraffic(rtk_uint32 port, rtk_uint32* pIndicator);
+extern ret_t rtl8367c_setAsicGreenHighPriorityTraffic(rtk_uint32 port);
+extern ret_t rtl8367c_setAsicGreenEthernet(rtk_uint32 port, rtk_uint32 green);
+extern ret_t rtl8367c_getAsicGreenEthernet(rtk_uint32 port, rtk_uint32* green);
+extern ret_t rtl8367c_setAsicPowerSaving(rtk_uint32 phy, rtk_uint32 enable);
+extern ret_t rtl8367c_getAsicPowerSaving(rtk_uint32 phy, rtk_uint32* enable);
+#endif /*#ifndef _RTL8367C_ASICDRV_GREEN_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_hsb.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_hsb.h
new file mode 100644
index 0000000..f4f9bb3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_hsb.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Field selector related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV__HSB_H_
+#define _RTL8367C_ASICDRV__HSB_H_
+
+#include <rtl8367c_asicdrv.h>
+
+#define RTL8367C_FIELDSEL_FORMAT_NUMBER      (16)
+#define RTL8367C_FIELDSEL_MAX_OFFSET         (255)
+
+enum FIELDSEL_FORMAT_FORMAT
+{
+    FIELDSEL_FORMAT_DEFAULT = 0,
+    FIELDSEL_FORMAT_RAW,
+    FIELDSEL_FORMAT_LLC,
+    FIELDSEL_FORMAT_IPV4,
+    FIELDSEL_FORMAT_ARP,
+    FIELDSEL_FORMAT_IPV6,
+    FIELDSEL_FORMAT_IPPAYLOAD,
+    FIELDSEL_FORMAT_L4PAYLOAD,
+    FIELDSEL_FORMAT_END
+};
+
+extern ret_t rtl8367c_setAsicFieldSelector(rtk_uint32 index, rtk_uint32 format, rtk_uint32 offset);
+extern ret_t rtl8367c_getAsicFieldSelector(rtk_uint32 index, rtk_uint32* pFormat, rtk_uint32* pOffset);
+
+#endif /*_RTL8367C_ASICDRV__HSB_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_i2c.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_i2c.h
new file mode 100644
index 0000000..d5b095a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_i2c.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 38651 $
+ * $Date: 2016-02-27 14:32:56 +0800 (©P¤T, 17 ¥|¤ë 2016) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : I2C related functions
+ *
+ */
+
+
+#ifndef _RTL8367C_ASICDRV_I2C_H_
+#define _RTL8367C_ASICDRV_I2C_H_
+#include <rtk_types.h>
+#include <rtl8367c_asicdrv.h>
+
+
+#define TIMEROUT_FOR_MICROSEMI (0x400)
+
+#define GPIO_INPUT 1
+#define GPIO_OUTPUT 2
+
+extern ret_t rtl8367c_setAsicI2C_checkBusIdle(void);
+extern ret_t rtl8367c_setAsicI2CStartCmd(void);
+extern ret_t rtl8367c_setAsicI2CStopCmd(void);
+extern ret_t rtl8367c_setAsicI2CTxOneCharCmd(rtk_uint8 oneChar);
+extern ret_t rtl8367c_setAsicI2CcheckRxAck(void);
+extern ret_t rtl8367c_setAsicI2CRxOneCharCmd(rtk_uint8 *pValue);
+extern ret_t rtl8367c_setAsicI2CTxAckCmd(void);
+extern ret_t rtl8367c_setAsicI2CTxNoAckCmd(void);
+extern ret_t rtl8367c_setAsicI2CSoftRSTseqCmd(void);
+extern ret_t rtl8367c_setAsicI2CGpioPinGroup(rtk_uint32 pinGroup_ID);
+extern ret_t rtl8367c_getAsicI2CGpioPinGroup(rtk_uint32 * pPinGroup_ID);
+
+
+
+
+
+#endif /*#ifndef _RTL8367C_ASICDRV_I2C_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_igmp.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_igmp.h
new file mode 100644
index 0000000..b879b6b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_igmp.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : IGMP related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_IGMP_H_
+#define _RTL8367C_ASICDRV_IGMP_H_
+
+/****************************************************************/
+/* Header File inclusion                                        */
+/****************************************************************/
+#include <rtl8367c_asicdrv.h>
+
+#define RTL8367C_MAX_LEAVE_TIMER        (7)
+#define RTL8367C_MAX_QUERY_INT          (0xFFFF)
+#define RTL8367C_MAX_ROB_VAR            (7)
+
+#define RTL8367C_IGMP_GOUP_NO           (256)
+#define RTL8367C_IGMP_MAX_GOUP          (0xFF)
+#define RTL8367C_IGMP_GRP_BLEN          (3)
+#define RTL8367C_ROUTER_PORT_INVALID    (0xF)
+
+enum RTL8367C_IGMPTABLE_FULL_OP
+{
+    TABLE_FULL_FORWARD = 0,
+    TABLE_FULL_DROP,
+    TABLE_FULL_TRAP,
+    TABLE_FULL_OP_END
+};
+
+enum RTL8367C_CRC_ERR_OP
+{
+    CRC_ERR_DROP = 0,
+    CRC_ERR_TRAP,
+    CRC_ERR_FORWARD,
+    CRC_ERR_OP_END
+};
+
+enum RTL8367C_IGMP_MLD_PROTOCOL_OP
+{
+    PROTOCOL_OP_ASIC = 0,
+    PROTOCOL_OP_FLOOD,
+    PROTOCOL_OP_TRAP,
+    PROTOCOL_OP_DROP,
+    PROTOCOL_OP_END
+};
+
+enum RTL8367C_IGMP_MLD_BYPASS_GROUP
+{
+    BYPASS_224_0_0_X = 0,
+    BYPASS_224_0_1_X,
+    BYPASS_239_255_255_X,
+    BYPASS_IPV6_00XX,
+    BYPASS_GROUP_END
+};
+
+typedef struct
+{
+    rtk_uint32 p0_timer;
+    rtk_uint32 p1_timer;
+    rtk_uint32 p2_timer;
+    rtk_uint32 p3_timer;
+    rtk_uint32 p4_timer;
+    rtk_uint32 p5_timer;
+    rtk_uint32 p6_timer;
+    rtk_uint32 p7_timer;
+    rtk_uint32 p8_timer;
+    rtk_uint32 p9_timer;
+    rtk_uint32 p10_timer;
+    rtk_uint32 report_supp_flag;
+
+}rtl8367c_igmpgroup;
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * This program is the proprietary software of Realtek Semiconductor
+ * Corporation and/or its licensors, and only be used, duplicated,
+ * modified or distributed under the authorized license from Realtek.
+ *
+ * ANY USE OF THE SOFTWARE OTHER THAN AS AUTHORIZED UNDER
+ * THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : IGMP related functions
+ *
+ */
+#include <rtl8367c_asicdrv_igmp.h>
+
+ret_t rtl8367c_setAsicIgmp(rtk_uint32 enabled);
+ret_t rtl8367c_getAsicIgmp(rtk_uint32 *pEnabled);
+ret_t rtl8367c_setAsicIpMulticastVlanLeaky(rtk_uint32 port, rtk_uint32 enabled );
+ret_t rtl8367c_getAsicIpMulticastVlanLeaky(rtk_uint32 port, rtk_uint32 *pEnabled );
+ret_t rtl8367c_setAsicIGMPTableFullOP(rtk_uint32 operation);
+ret_t rtl8367c_getAsicIGMPTableFullOP(rtk_uint32 *pOperation);
+ret_t rtl8367c_setAsicIGMPCRCErrOP(rtk_uint32 operation);
+ret_t rtl8367c_getAsicIGMPCRCErrOP(rtk_uint32 *pOperation);
+ret_t rtl8367c_setAsicIGMPFastLeaveEn(rtk_uint32 enabled);
+ret_t rtl8367c_getAsicIGMPFastLeaveEn(rtk_uint32 *pEnabled);
+ret_t rtl8367c_setAsicIGMPLeaveTimer(rtk_uint32 leave_timer);
+ret_t rtl8367c_getAsicIGMPLeaveTimer(rtk_uint32 *pLeave_timer);
+ret_t rtl8367c_setAsicIGMPQueryInterval(rtk_uint32 interval);
+ret_t rtl8367c_getAsicIGMPQueryInterval(rtk_uint32 *pInterval);
+ret_t rtl8367c_setAsicIGMPRobVar(rtk_uint32 rob_var);
+ret_t rtl8367c_getAsicIGMPRobVar(rtk_uint32 *pRob_var);
+ret_t rtl8367c_setAsicIGMPStaticRouterPort(rtk_uint32 pmsk);
+ret_t rtl8367c_getAsicIGMPStaticRouterPort(rtk_uint32 *pMsk);
+ret_t rtl8367c_setAsicIGMPAllowDynamicRouterPort(rtk_uint32 pmsk);
+ret_t rtl8367c_getAsicIGMPAllowDynamicRouterPort(rtk_uint32 *pPmsk);
+ret_t rtl8367c_getAsicIGMPdynamicRouterPort1(rtk_uint32 *pPort, rtk_uint32 *pTimer);
+ret_t rtl8367c_getAsicIGMPdynamicRouterPort2(rtk_uint32 *pPort, rtk_uint32 *pTimer);
+ret_t rtl8367c_setAsicIGMPSuppression(rtk_uint32 report_supp_enabled, rtk_uint32 leave_supp_enabled);
+ret_t rtl8367c_getAsicIGMPSuppression(rtk_uint32 *pReport_supp_enabled, rtk_uint32 *pLeave_supp_enabled);
+ret_t rtl8367c_setAsicIGMPQueryRX(rtk_uint32 port, rtk_uint32 allow_query);
+ret_t rtl8367c_getAsicIGMPQueryRX(rtk_uint32 port, rtk_uint32 *pAllow_query);
+ret_t rtl8367c_setAsicIGMPReportRX(rtk_uint32 port, rtk_uint32 allow_report);
+ret_t rtl8367c_getAsicIGMPReportRX(rtk_uint32 port, rtk_uint32 *pAllow_report);
+ret_t rtl8367c_setAsicIGMPLeaveRX(rtk_uint32 port, rtk_uint32 allow_leave);
+ret_t rtl8367c_getAsicIGMPLeaveRX(rtk_uint32 port, rtk_uint32 *pAllow_leave);
+ret_t rtl8367c_setAsicIGMPMRPRX(rtk_uint32 port, rtk_uint32 allow_mrp);
+ret_t rtl8367c_getAsicIGMPMRPRX(rtk_uint32 port, rtk_uint32 *pAllow_mrp);
+ret_t rtl8367c_setAsicIGMPMcDataRX(rtk_uint32 port, rtk_uint32 allow_mcdata);
+ret_t rtl8367c_getAsicIGMPMcDataRX(rtk_uint32 port, rtk_uint32 *pAllow_mcdata);
+ret_t rtl8367c_setAsicIGMPv1Opeartion(rtk_uint32 port, rtk_uint32 igmpv1_op);
+ret_t rtl8367c_getAsicIGMPv1Opeartion(rtk_uint32 port, rtk_uint32 *pIgmpv1_op);
+ret_t rtl8367c_setAsicIGMPv2Opeartion(rtk_uint32 port, rtk_uint32 igmpv2_op);
+ret_t rtl8367c_getAsicIGMPv2Opeartion(rtk_uint32 port, rtk_uint32 *pIgmpv2_op);
+ret_t rtl8367c_setAsicIGMPv3Opeartion(rtk_uint32 port, rtk_uint32 igmpv3_op);
+ret_t rtl8367c_getAsicIGMPv3Opeartion(rtk_uint32 port, rtk_uint32 *pIgmpv3_op);
+ret_t rtl8367c_setAsicMLDv1Opeartion(rtk_uint32 port, rtk_uint32 mldv1_op);
+ret_t rtl8367c_getAsicMLDv1Opeartion(rtk_uint32 port, rtk_uint32 *pMldv1_op);
+ret_t rtl8367c_setAsicMLDv2Opeartion(rtk_uint32 port, rtk_uint32 mldv2_op);
+ret_t rtl8367c_getAsicMLDv2Opeartion(rtk_uint32 port, rtk_uint32 *pMldv2_op);
+ret_t rtl8367c_setAsicIGMPPortMAXGroup(rtk_uint32 port, rtk_uint32 max_group);
+ret_t rtl8367c_getAsicIGMPPortMAXGroup(rtk_uint32 port, rtk_uint32 *pMax_group);
+ret_t rtl8367c_getAsicIGMPPortCurrentGroup(rtk_uint32 port, rtk_uint32 *pCurrent_group);
+ret_t rtl8367c_getAsicIGMPGroup(rtk_uint32 idx, rtk_uint32 *pValid, rtl8367c_igmpgroup *pGrp);
+ret_t rtl8367c_setAsicIpMulticastPortIsoLeaky(rtk_uint32 port, rtk_uint32 enabled);
+ret_t rtl8367c_getAsicIpMulticastPortIsoLeaky(rtk_uint32 port, rtk_uint32 *pEnabled);
+ret_t rtl8367c_setAsicIGMPReportLeaveFlood(rtk_uint32 flood);
+ret_t rtl8367c_getAsicIGMPReportLeaveFlood(rtk_uint32 *pFlood);
+ret_t rtl8367c_setAsicIGMPDropLeaveZero(rtk_uint32 drop);
+ret_t rtl8367c_getAsicIGMPDropLeaveZero(rtk_uint32 *pDrop);
+ret_t rtl8367c_setAsicIGMPBypassStormCTRL(rtk_uint32 bypass);
+ret_t rtl8367c_getAsicIGMPBypassStormCTRL(rtk_uint32 *pBypass);
+ret_t rtl8367c_setAsicIGMPIsoLeaky(rtk_uint32 leaky);
+ret_t rtl8367c_getAsicIGMPIsoLeaky(rtk_uint32 *pLeaky);
+ret_t rtl8367c_setAsicIGMPVLANLeaky(rtk_uint32 leaky);
+ret_t rtl8367c_getAsicIGMPVLANLeaky(rtk_uint32 *pLeaky);
+ret_t rtl8367c_setAsicIGMPBypassGroup(rtk_uint32 bypassType, rtk_uint32 enabled);
+ret_t rtl8367c_getAsicIGMPBypassGroup(rtk_uint32 bypassType, rtk_uint32 *pEnabled);
+
+#endif /*#ifndef _RTL8367C_ASICDRV_IGMP_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_inbwctrl.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_inbwctrl.h
new file mode 100644
index 0000000..10f3545
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_inbwctrl.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Ingress bandwidth control related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_INBWCTRL_H_
+#define _RTL8367C_ASICDRV_INBWCTRL_H_
+
+#include <rtl8367c_asicdrv.h>
+
+extern ret_t rtl8367c_setAsicPortIngressBandwidth(rtk_uint32 port, rtk_uint32 bandwidth, rtk_uint32 preifg, rtk_uint32 enableFC);
+extern ret_t rtl8367c_getAsicPortIngressBandwidth(rtk_uint32 port, rtk_uint32* pBandwidth, rtk_uint32* pPreifg, rtk_uint32* pEnableFC );
+extern ret_t rtl8367c_setAsicPortIngressBandwidthBypass(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicPortIngressBandwidthBypass(rtk_uint32* pEnabled);
+
+
+#endif /*_RTL8367C_ASICDRV_INBWCTRL_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_interrupt.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_interrupt.h
new file mode 100644
index 0000000..8b78014
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_interrupt.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Interrupt related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_INTERRUPT_H_
+#define _RTL8367C_ASICDRV_INTERRUPT_H_
+
+#include <rtl8367c_asicdrv.h>
+
+typedef enum RTL8367C_INTR_IMRS_E
+{
+    IMRS_LINK_CHANGE,
+    IMRS_METER_EXCEED,
+    IMRS_L2_LEARN,
+    IMRS_SPEED_CHANGE,
+    IMRS_SPECIAL_CONGESTION,
+    IMRS_GREEN_FEATURE,
+    IMRS_LOOP_DETECTION,
+    IMRS_8051,
+    IMRS_CABLE_DIAG,
+    IMRS_ACL,
+    IMRS_RESERVED, /* Unused */
+    IMRS_SLIENT,
+    IMRS_END,
+}RTL8367C_INTR_IMRS;
+
+typedef enum RTL8367C_INTR_INDICATOR_E
+{
+    INTRST_L2_LEARN = 0,
+    INTRST_SPEED_CHANGE,
+    INTRST_SPECIAL_CONGESTION,
+    INTRST_PORT_LINKDOWN,
+    INTRST_PORT_LINKUP,
+    INTRST_METER0_15,
+    INTRST_METER16_31,
+    INTRST_RLDP_LOOPED,
+    INTRST_RLDP_RELEASED,
+    INTRST_SYS_LEARN,
+    INTRST_END,
+}RTL8367C_INTR_INDICATOR;
+
+extern ret_t rtl8367c_setAsicInterruptPolarity(rtk_uint32 polarity);
+extern ret_t rtl8367c_getAsicInterruptPolarity(rtk_uint32* pPolarity);
+extern ret_t rtl8367c_setAsicInterruptMask(rtk_uint32 imr);
+extern ret_t rtl8367c_getAsicInterruptMask(rtk_uint32* pImr);
+extern ret_t rtl8367c_setAsicInterruptStatus(rtk_uint32 ims);
+extern ret_t rtl8367c_getAsicInterruptStatus(rtk_uint32* pIms);
+extern ret_t rtl8367c_setAsicInterruptRelatedStatus(rtk_uint32 type, rtk_uint32 status);
+extern ret_t rtl8367c_getAsicInterruptRelatedStatus(rtk_uint32 type, rtk_uint32* pStatus);
+
+
+#endif /*#ifndef _RTL8367C_ASICDRV_INTERRUPT_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_led.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_led.h
new file mode 100644
index 0000000..a7f8e20
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_led.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : LED related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_LED_H_
+#define _RTL8367C_ASICDRV_LED_H_
+
+#include <rtl8367c_asicdrv.h>
+
+#define RTL8367C_LEDGROUPNO                 3
+#define RTL8367C_LEDGROUPMASK               0x7
+#define RTL8367C_LED_FORCE_MODE_BASE        RTL8367C_REG_CPU_FORCE_LED0_CFG0
+#define RTL8367C_LED_FORCE_CTRL             RTL8367C_REG_CPU_FORCE_LED_CFG
+
+enum RTL8367C_LEDOP{
+
+    LEDOP_SCAN0=0,
+    LEDOP_SCAN1,
+    LEDOP_PARALLEL,
+    LEDOP_SERIAL,
+    LEDOP_END,
+};
+
+enum RTL8367C_LEDSERACT{
+
+    LEDSERACT_HIGH=0,
+    LEDSERACT_LOW,
+    LEDSERACT_MAX,
+};
+
+enum RTL8367C_LEDSER{
+
+    LEDSER_16G=0,
+    LEDSER_8G,
+    LEDSER_MAX,
+};
+
+enum RTL8367C_LEDCONF{
+
+    LEDCONF_LEDOFF=0,
+    LEDCONF_DUPCOL,
+    LEDCONF_LINK_ACT,
+    LEDCONF_SPD1000,
+    LEDCONF_SPD100,
+    LEDCONF_SPD10,
+    LEDCONF_SPD1000ACT,
+    LEDCONF_SPD100ACT,
+    LEDCONF_SPD10ACT,
+    LEDCONF_SPD10010ACT,
+    LEDCONF_LOOPDETECT,
+    LEDCONF_EEE,
+    LEDCONF_LINKRX,
+    LEDCONF_LINKTX,
+    LEDCONF_MASTER,
+    LEDCONF_ACT,
+    LEDCONF_END
+};
+
+enum RTL8367C_LEDBLINKRATE{
+
+    LEDBLINKRATE_32MS=0,
+    LEDBLINKRATE_64MS,
+    LEDBLINKRATE_128MS,
+    LEDBLINKRATE_256MS,
+    LEDBLINKRATE_512MS,
+    LEDBLINKRATE_1024MS,
+    LEDBLINKRATE_48MS,
+    LEDBLINKRATE_96MS,
+    LEDBLINKRATE_END,
+};
+
+enum RTL8367C_LEDFORCEMODE{
+
+    LEDFORCEMODE_NORMAL=0,
+    LEDFORCEMODE_BLINK,
+    LEDFORCEMODE_OFF,
+    LEDFORCEMODE_ON,
+    LEDFORCEMODE_END,
+};
+
+enum RTL8367C_LEDFORCERATE{
+
+    LEDFORCERATE_512MS=0,
+    LEDFORCERATE_1024MS,
+    LEDFORCERATE_2048MS,
+    LEDFORCERATE_NORMAL,
+    LEDFORCERATE_END,
+
+};
+
+enum RTL8367C_LEDMODE
+{
+    RTL8367C_LED_MODE_0 = 0,
+    RTL8367C_LED_MODE_1,
+    RTL8367C_LED_MODE_2,
+    RTL8367C_LED_MODE_3,
+    RTL8367C_LED_MODE_END
+};
+
+extern ret_t rtl8367c_setAsicLedIndicateInfoConfig(rtk_uint32 ledno, rtk_uint32 config);
+extern ret_t rtl8367c_getAsicLedIndicateInfoConfig(rtk_uint32 ledno, rtk_uint32* pConfig);
+extern ret_t rtl8367c_setAsicForceLed(rtk_uint32 port, rtk_uint32 group, rtk_uint32 mode);
+extern ret_t rtl8367c_getAsicForceLed(rtk_uint32 port, rtk_uint32 group, rtk_uint32* pMode);
+extern ret_t rtl8367c_setAsicForceGroupLed(rtk_uint32 groupmask, rtk_uint32 mode);
+extern ret_t rtl8367c_getAsicForceGroupLed(rtk_uint32* groupmask, rtk_uint32* pMode);
+extern ret_t rtl8367c_setAsicLedBlinkRate(rtk_uint32 blinkRate);
+extern ret_t rtl8367c_getAsicLedBlinkRate(rtk_uint32* pBlinkRate);
+extern ret_t rtl8367c_setAsicLedForceBlinkRate(rtk_uint32 blinkRate);
+extern ret_t rtl8367c_getAsicLedForceBlinkRate(rtk_uint32* pBlinkRate);
+extern ret_t rtl8367c_setAsicLedGroupMode(rtk_uint32 mode);
+extern ret_t rtl8367c_getAsicLedGroupMode(rtk_uint32* pMode);
+extern ret_t rtl8367c_setAsicLedGroupEnable(rtk_uint32 group, rtk_uint32 portmask);
+extern ret_t rtl8367c_getAsicLedGroupEnable(rtk_uint32 group, rtk_uint32 *portmask);
+extern ret_t rtl8367c_setAsicLedOperationMode(rtk_uint32 mode);
+extern ret_t rtl8367c_getAsicLedOperationMode(rtk_uint32 *mode);
+extern ret_t rtl8367c_setAsicLedSerialModeConfig(rtk_uint32 active, rtk_uint32 serimode);
+extern ret_t rtl8367c_getAsicLedSerialModeConfig(rtk_uint32 *active, rtk_uint32 *serimode);
+extern ret_t rtl8367c_setAsicLedOutputEnable(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicLedOutputEnable(rtk_uint32 *ptr_enabled);
+extern ret_t rtl8367c_setAsicLedSerialOutput(rtk_uint32 output, rtk_uint32 pmask);
+extern ret_t rtl8367c_getAsicLedSerialOutput(rtk_uint32 *pOutput, rtk_uint32 *pPmask);
+
+
+#endif /*#ifndef _RTL8367C_ASICDRV_LED_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_lut.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_lut.h
new file mode 100644
index 0000000..c94ea07
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_lut.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : LUT related functions
+ *
+ */
+
+
+#ifndef _RTL8367C_ASICDRV_LUT_H_
+#define _RTL8367C_ASICDRV_LUT_H_
+
+#include <rtl8367c_asicdrv.h>
+
+#define RTL8367C_LUT_AGETIMERMAX        (7)
+#define RTL8367C_LUT_AGESPEEDMAX        (3)
+#define RTL8367C_LUT_LEARNLIMITMAX      (0x1040)
+#define RTL8367C_LUT_ADDRMAX            (0x103F)
+#define RTL8367C_LUT_IPMCGRP_TABLE_MAX  (0x3F)
+#define RTL8367C_LUT_ENTRY_SIZE         (6)
+#define RTL8367C_LUT_BUSY_CHECK_NO      (10)
+
+#define RTL8367C_LUT_TABLE_SIZE         (6)
+
+enum RTL8367C_LUTHASHMETHOD{
+
+    LUTHASHMETHOD_SVL=0,
+    LUTHASHMETHOD_IVL,
+    LUTHASHMETHOD_END,
+};
+
+
+enum RTL8367C_LRNOVERACT{
+
+    LRNOVERACT_FORWARD=0,
+    LRNOVERACT_DROP,
+    LRNOVERACT_TRAP,
+    LRNOVERACT_END,
+};
+
+enum RTL8367C_LUTREADMETHOD{
+
+    LUTREADMETHOD_MAC =0,
+    LUTREADMETHOD_ADDRESS,
+    LUTREADMETHOD_NEXT_ADDRESS,
+    LUTREADMETHOD_NEXT_L2UC,
+    LUTREADMETHOD_NEXT_L2MC,
+    LUTREADMETHOD_NEXT_L3MC,
+    LUTREADMETHOD_NEXT_L2L3MC,
+    LUTREADMETHOD_NEXT_L2UCSPA,
+};
+
+enum RTL8367C_FLUSHMODE
+{
+    FLUSHMDOE_PORT = 0,
+    FLUSHMDOE_VID,
+    FLUSHMDOE_FID,
+    FLUSHMDOE_END,
+};
+
+enum RTL8367C_FLUSHTYPE
+{
+    FLUSHTYPE_DYNAMIC = 0,
+    FLUSHTYPE_BOTH,
+    FLUSHTYPE_END,
+};
+
+
+typedef struct LUTTABLE{
+
+    ipaddr_t sip;
+    ipaddr_t dip;
+    ether_addr_t mac;
+    rtk_uint16 ivl_svl:1;
+    rtk_uint16 cvid_fid:12;
+    rtk_uint16 fid:4;
+    rtk_uint16 efid:3;
+
+    rtk_uint16 nosalearn:1;
+    rtk_uint16 da_block:1;
+    rtk_uint16 sa_block:1;
+    rtk_uint16 auth:1;
+    rtk_uint16 lut_pri:3;
+    rtk_uint16 sa_en:1;
+    rtk_uint16 fwd_en:1;
+    rtk_uint16 mbr:11;
+    rtk_uint16 spa:4;
+    rtk_uint16 age:3;
+    rtk_uint16 l3lookup:1;
+    rtk_uint16 igmp_asic:1;
+    rtk_uint16 igmpidx:8;
+
+    rtk_uint16 lookup_hit:1;
+    rtk_uint16 lookup_busy:1;
+    rtk_uint16 address:13;
+
+    rtk_uint16 l3vidlookup:1;
+    rtk_uint16 l3_vid:12;
+
+    rtk_uint16 wait_time;
+
+}rtl8367c_luttb;
+
+extern ret_t rtl8367c_setAsicLutIpMulticastLookup(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicLutIpMulticastLookup(rtk_uint32* pEnabled);
+extern ret_t rtl8367c_setAsicLutIpMulticastVidLookup(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicLutIpMulticastVidLookup(rtk_uint32* pEnabled);
+extern ret_t rtl8367c_setAsicLutAgeTimerSpeed(rtk_uint32 timer, rtk_uint32 speed);
+extern ret_t rtl8367c_getAsicLutAgeTimerSpeed(rtk_uint32* pTimer, rtk_uint32* pSpeed);
+extern ret_t rtl8367c_setAsicLutCamTbUsage(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicLutCamTbUsage(rtk_uint32* pEnabled);
+extern ret_t rtl8367c_getAsicLutCamType(rtk_uint32* pType);
+extern ret_t rtl8367c_setAsicLutLearnLimitNo(rtk_uint32 port, rtk_uint32 number);
+extern ret_t rtl8367c_getAsicLutLearnLimitNo(rtk_uint32 port, rtk_uint32* pNumber);
+extern ret_t rtl8367c_setAsicSystemLutLearnLimitNo(rtk_uint32 number);
+extern ret_t rtl8367c_getAsicSystemLutLearnLimitNo(rtk_uint32 *pNumber);
+extern ret_t rtl8367c_setAsicLutLearnOverAct(rtk_uint32 action);
+extern ret_t rtl8367c_getAsicLutLearnOverAct(rtk_uint32* pAction);
+extern ret_t rtl8367c_setAsicSystemLutLearnOverAct(rtk_uint32 action);
+extern ret_t rtl8367c_getAsicSystemLutLearnOverAct(rtk_uint32 *pAction);
+extern ret_t rtl8367c_setAsicSystemLutLearnPortMask(rtk_uint32 portmask);
+extern ret_t rtl8367c_getAsicSystemLutLearnPortMask(rtk_uint32 *pPortmask);
+extern ret_t rtl8367c_setAsicL2LookupTb(rtl8367c_luttb *pL2Table);
+extern ret_t rtl8367c_getAsicL2LookupTb(rtk_uint32 method, rtl8367c_luttb *pL2Table);
+extern ret_t rtl8367c_getAsicLutLearnNo(rtk_uint32 port, rtk_uint32* pNumber);
+extern ret_t rtl8367c_setAsicLutIpLookupMethod(rtk_uint32 type);
+extern ret_t rtl8367c_getAsicLutIpLookupMethod(rtk_uint32* pType);
+extern ret_t rtl8367c_setAsicLutForceFlush(rtk_uint32 portmask);
+extern ret_t rtl8367c_getAsicLutForceFlushStatus(rtk_uint32 *pPortmask);
+extern ret_t rtl8367c_setAsicLutFlushMode(rtk_uint32 mode);
+extern ret_t rtl8367c_getAsicLutFlushMode(rtk_uint32* pMode);
+extern ret_t rtl8367c_setAsicLutFlushType(rtk_uint32 type);
+extern ret_t rtl8367c_getAsicLutFlushType(rtk_uint32* pType);
+extern ret_t rtl8367c_setAsicLutFlushVid(rtk_uint32 vid);
+extern ret_t rtl8367c_getAsicLutFlushVid(rtk_uint32* pVid);
+extern ret_t rtl8367c_setAsicLutFlushFid(rtk_uint32 fid);
+extern ret_t rtl8367c_getAsicLutFlushFid(rtk_uint32* pFid);
+extern ret_t rtl8367c_setAsicLutDisableAging(rtk_uint32 port, rtk_uint32 disabled);
+extern ret_t rtl8367c_getAsicLutDisableAging(rtk_uint32 port, rtk_uint32 *pDisabled);
+extern ret_t rtl8367c_setAsicLutIPMCGroup(rtk_uint32 index, ipaddr_t group_addr, rtk_uint32 vid, rtk_uint32 pmask, rtk_uint32 valid);
+extern ret_t rtl8367c_getAsicLutIPMCGroup(rtk_uint32 index, ipaddr_t *pGroup_addr, rtk_uint32 *pVid, rtk_uint32 *pPmask, rtk_uint32 *pValid);
+extern ret_t rtl8367c_setAsicLutLinkDownForceAging(rtk_uint32 enable);
+extern ret_t rtl8367c_getAsicLutLinkDownForceAging(rtk_uint32 *pEnable);
+extern ret_t rtl8367c_setAsicLutFlushAll(void);
+extern ret_t rtl8367c_getAsicLutFlushAllStatus(rtk_uint32 *pBusyStatus);
+extern ret_t rtl8367c_setAsicLutIpmcFwdRouterPort(rtk_uint32 enable);
+extern ret_t rtl8367c_getAsicLutIpmcFwdRouterPort(rtk_uint32 *pEnable);
+
+#endif /*_RTL8367C_ASICDRV_LUT_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_meter.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_meter.h
new file mode 100644
index 0000000..ba761a9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_meter.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Shared meter related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_METER_H_
+#define _RTL8367C_ASICDRV_METER_H_
+
+#include <rtl8367c_asicdrv.h>
+
+
+extern ret_t rtl8367c_setAsicShareMeter(rtk_uint32 index, rtk_uint32 rate, rtk_uint32 ifg);
+extern ret_t rtl8367c_getAsicShareMeter(rtk_uint32 index, rtk_uint32 *pRate, rtk_uint32 *pIfg);
+extern ret_t rtl8367c_setAsicShareMeterBucketSize(rtk_uint32 index, rtk_uint32 lbThreshold);
+extern ret_t rtl8367c_getAsicShareMeterBucketSize(rtk_uint32 index, rtk_uint32 *pLbThreshold);
+extern ret_t rtl8367c_setAsicShareMeterType(rtk_uint32 index, rtk_uint32 type);
+extern ret_t rtl8367c_getAsicShareMeterType(rtk_uint32 index, rtk_uint32 *pType);
+extern ret_t rtl8367c_setAsicMeterExceedStatus(rtk_uint32 index);
+extern ret_t rtl8367c_getAsicMeterExceedStatus(rtk_uint32 index, rtk_uint32* pStatus);
+
+#endif /*_RTL8367C_ASICDRV_FC_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mib.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mib.h
new file mode 100644
index 0000000..ca46e0f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mib.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : MIB related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_MIB_H_
+#define _RTL8367C_ASICDRV_MIB_H_
+
+#include <rtl8367c_asicdrv.h>
+
+#define RTL8367C_MIB_PORT_OFFSET                (0x7C)
+#define RTL8367C_MIB_LEARNENTRYDISCARD_OFFSET   (0x420)
+
+#define RTL8367C_MAX_LOG_CNT_NUM                (32)
+#define RTL8367C_MIB_MAX_LOG_CNT_IDX            (RTL8367C_MAX_LOG_CNT_NUM - 1)
+#define RTL8367C_MIB_LOG_CNT_OFFSET             (0x3E0)
+#define RTL8367C_MIB_MAX_LOG_MODE_IDX           (16-1)
+
+typedef enum RTL8367C_MIBCOUNTER_E{
+
+    /* RX */
+    ifInOctets = 0,
+
+    dot3StatsFCSErrors,
+    dot3StatsSymbolErrors,
+    dot3InPauseFrames,
+    dot3ControlInUnknownOpcodes,
+
+    etherStatsFragments,
+    etherStatsJabbers,
+    ifInUcastPkts,
+    etherStatsDropEvents,
+
+    ifInMulticastPkts,
+    ifInBroadcastPkts,
+    inMldChecksumError,
+    inIgmpChecksumError,
+    inMldSpecificQuery,
+    inMldGeneralQuery,
+    inIgmpSpecificQuery,
+    inIgmpGeneralQuery,
+    inMldLeaves,
+    inIgmpLeaves,
+
+    /* TX/RX */
+    etherStatsOctets,
+
+    etherStatsUnderSizePkts,
+    etherOversizeStats,
+    etherStatsPkts64Octets,
+    etherStatsPkts65to127Octets,
+    etherStatsPkts128to255Octets,
+    etherStatsPkts256to511Octets,
+    etherStatsPkts512to1023Octets,
+    etherStatsPkts1024to1518Octets,
+
+    /* TX */
+    ifOutOctets,
+
+    dot3StatsSingleCollisionFrames,
+    dot3StatMultipleCollisionFrames,
+    dot3sDeferredTransmissions,
+    dot3StatsLateCollisions,
+    etherStatsCollisions,
+    dot3StatsExcessiveCollisions,
+    dot3OutPauseFrames,
+    ifOutDiscards,
+
+    /* ALE */
+    dot1dTpPortInDiscards,
+    ifOutUcastPkts,
+    ifOutMulticastPkts,
+    ifOutBroadcastPkts,
+    outOampduPkts,
+    inOampduPkts,
+
+    inIgmpJoinsSuccess,
+    inIgmpJoinsFail,
+    inMldJoinsSuccess,
+    inMldJoinsFail,
+    inReportSuppressionDrop,
+    inLeaveSuppressionDrop,
+    outIgmpReports,
+    outIgmpLeaves,
+    outIgmpGeneralQuery,
+    outIgmpSpecificQuery,
+    outMldReports,
+    outMldLeaves,
+    outMldGeneralQuery,
+    outMldSpecificQuery,
+    inKnownMulticastPkts,
+
+    /*Device only */
+    dot1dTpLearnedEntryDiscards,
+    RTL8367C_MIBS_NUMBER,
+
+}RTL8367C_MIBCOUNTER;
+
+
+extern ret_t rtl8367c_setAsicMIBsCounterReset(rtk_uint32 greset, rtk_uint32 qmreset, rtk_uint32 pmask);
+extern ret_t rtl8367c_getAsicMIBsCounter(rtk_uint32 port,RTL8367C_MIBCOUNTER mibIdx, rtk_uint64* pCounter);
+extern ret_t rtl8367c_getAsicMIBsLogCounter(rtk_uint32 index, rtk_uint32 *pCounter);
+extern ret_t rtl8367c_getAsicMIBsControl(rtk_uint32* pMask);
+
+extern ret_t rtl8367c_setAsicMIBsResetValue(rtk_uint32 value);
+extern ret_t rtl8367c_getAsicMIBsResetValue(rtk_uint32* value);
+
+extern ret_t rtl8367c_setAsicMIBsUsageMode(rtk_uint32 mode);
+extern ret_t rtl8367c_getAsicMIBsUsageMode(rtk_uint32* pMode);
+extern ret_t rtl8367c_setAsicMIBsTimer(rtk_uint32 timer);
+extern ret_t rtl8367c_getAsicMIBsTimer(rtk_uint32* pTimer);
+extern ret_t rtl8367c_setAsicMIBsLoggingMode(rtk_uint32 index, rtk_uint32 mode);
+extern ret_t rtl8367c_getAsicMIBsLoggingMode(rtk_uint32 index, rtk_uint32* pMode);
+extern ret_t rtl8367c_setAsicMIBsLoggingType(rtk_uint32 index, rtk_uint32 type);
+extern ret_t rtl8367c_getAsicMIBsLoggingType(rtk_uint32 index, rtk_uint32* pType);
+extern ret_t rtl8367c_setAsicMIBsResetLoggingCounter(rtk_uint32 index);
+extern ret_t rtl8367c_setAsicMIBsLength(rtk_uint32 txLengthMode, rtk_uint32 rxLengthMode);
+extern ret_t rtl8367c_getAsicMIBsLength(rtk_uint32 *pTxLengthMode, rtk_uint32 *pRxLengthMode);
+
+#endif /*#ifndef _RTL8367C_ASICDRV_MIB_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mirror.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mirror.h
new file mode 100644
index 0000000..23b788d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mirror.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Port mirror related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_MIRROR_H_
+#define _RTL8367C_ASICDRV_MIRROR_H_
+
+#include <rtl8367c_asicdrv.h>
+
+extern ret_t rtl8367c_setAsicPortMirror(rtk_uint32 source, rtk_uint32 monitor);
+extern ret_t rtl8367c_getAsicPortMirror(rtk_uint32 *pSource, rtk_uint32 *pMonitor);
+extern ret_t rtl8367c_setAsicPortMirrorRxFunction(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicPortMirrorRxFunction(rtk_uint32* pEnabled);
+extern ret_t rtl8367c_setAsicPortMirrorTxFunction(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicPortMirrorTxFunction(rtk_uint32* pEnabled);
+extern ret_t rtl8367c_setAsicPortMirrorIsolation(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicPortMirrorIsolation(rtk_uint32* pEnabled);
+extern ret_t rtl8367c_setAsicPortMirrorPriority(rtk_uint32 priority);
+extern ret_t rtl8367c_getAsicPortMirrorPriority(rtk_uint32* pPriority);
+extern ret_t rtl8367c_setAsicPortMirrorMask(rtk_uint32 SourcePortmask);
+extern ret_t rtl8367c_getAsicPortMirrorMask(rtk_uint32 *pSourcePortmask);
+extern ret_t rtl8367c_setAsicPortMirrorVlanRxLeaky(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicPortMirrorVlanRxLeaky(rtk_uint32* pEnabled);
+extern ret_t rtl8367c_setAsicPortMirrorVlanTxLeaky(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicPortMirrorVlanTxLeaky(rtk_uint32* pEnabled);
+extern ret_t rtl8367c_setAsicPortMirrorIsolationRxLeaky(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicPortMirrorIsolationRxLeaky(rtk_uint32* pEnabled);
+extern ret_t rtl8367c_setAsicPortMirrorIsolationTxLeaky(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicPortMirrorIsolationTxLeaky(rtk_uint32* pEnabled);
+extern ret_t rtl8367c_setAsicPortMirrorRealKeep(rtk_uint32 mode);
+extern ret_t rtl8367c_getAsicPortMirrorRealKeep(rtk_uint32* pMode);
+extern ret_t rtl8367c_setAsicPortMirrorOverride(rtk_uint32 rxMirror, rtk_uint32 txMirror, rtk_uint32 aclMirror);
+extern ret_t rtl8367c_getAsicPortMirrorOverride(rtk_uint32 *pRxMirror, rtk_uint32 *pTxMirror, rtk_uint32 *pAclMirror);
+
+#endif /*#ifndef _RTL8367C_ASICDRV_MIRROR_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_misc.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_misc.h
new file mode 100644
index 0000000..c666a7b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_misc.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Miscellaneous functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_MISC_H_
+#define _RTL8367C_ASICDRV_MISC_H_
+
+#include <rtl8367c_asicdrv.h>
+
+extern ret_t rtl8367c_setAsicMacAddress(ether_addr_t mac);
+extern ret_t rtl8367c_getAsicMacAddress(ether_addr_t *pMac);
+extern ret_t rtl8367c_getAsicDebugInfo(rtk_uint32 port, rtk_uint32 *pDebugifo);
+extern ret_t rtl8367c_setAsicPortJamMode(rtk_uint32 mode);
+extern ret_t rtl8367c_getAsicPortJamMode(rtk_uint32* pMode);
+extern ret_t rtl8367c_setAsicMaxLengthCfg(rtk_uint32 cfgId, rtk_uint32 maxLength);
+extern ret_t rtl8367c_getAsicMaxLengthCfg(rtk_uint32 cfgId, rtk_uint32 *pMaxLength);
+extern ret_t rtl8367c_setAsicMaxLength(rtk_uint32 port, rtk_uint32 type, rtk_uint32 cfgId);
+extern ret_t rtl8367c_getAsicMaxLength(rtk_uint32 port, rtk_uint32 type, rtk_uint32 *pCfgId);
+
+#endif /*_RTL8367C_ASICDRV_MISC_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_oam.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_oam.h
new file mode 100644
index 0000000..c09dc76
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_oam.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 42321 $
+ * $Date: 2013-08-26 13:51:29 +0800 (¶g¤@, 26 ¤K¤ë 2013) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : OAM related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_OAM_H_
+#define _RTL8367C_ASICDRV_OAM_H_
+
+#include <rtl8367c_asicdrv.h>
+
+enum OAMPARACT
+{
+    OAM_PARFWD = 0,
+    OAM_PARLB,
+    OAM_PARDISCARD,
+    OAM_PARFWDCPU
+};
+
+enum OAMMULACT
+{
+    OAM_MULFWD = 0,
+    OAM_MULDISCARD,
+    OAM_MULCPU
+};
+
+extern ret_t rtl8367c_setAsicOamParser(rtk_uint32 port, rtk_uint32 parser);
+extern ret_t rtl8367c_getAsicOamParser(rtk_uint32 port, rtk_uint32* pParser);
+extern ret_t rtl8367c_setAsicOamMultiplexer(rtk_uint32 port, rtk_uint32 multiplexer);
+extern ret_t rtl8367c_getAsicOamMultiplexer(rtk_uint32 port, rtk_uint32* pMultiplexer);
+extern ret_t rtl8367c_setAsicOamCpuPri(rtk_uint32 priority);
+extern ret_t rtl8367c_getAsicOamCpuPri(rtk_uint32 *pPriority);
+extern ret_t rtl8367c_setAsicOamEnable(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicOamEnable(rtk_uint32 *pEnabled);
+#endif /*_RTL8367C_ASICDRV_OAM_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_phy.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_phy.h
new file mode 100644
index 0000000..e993d6e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_phy.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : PHY related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_PHY_H_
+#define _RTL8367C_ASICDRV_PHY_H_
+
+#include <rtl8367c_asicdrv.h>
+
+#define RTL8367C_PHY_REGNOMAX           0x1F
+#define RTL8367C_PHY_EXTERNALMAX        0x7
+
+#define RTL8367C_PHY_BASE               0x2000
+#define RTL8367C_PHY_EXT_BASE           0xA000
+
+#define RTL8367C_PHY_OFFSET             5
+#define RTL8367C_PHY_EXT_OFFSET         9
+
+#define RTL8367C_PHY_PAGE_ADDRESS       31
+
+
+extern ret_t rtl8367c_setAsicPHYReg(rtk_uint32 phyNo, rtk_uint32 phyAddr, rtk_uint32 regData );
+extern ret_t rtl8367c_getAsicPHYReg(rtk_uint32 phyNo, rtk_uint32 phyAddr, rtk_uint32* pRegData );
+extern ret_t rtl8367c_setAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 ocpData );
+extern ret_t rtl8367c_getAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 *pRegData );
+extern ret_t rtl8367c_setAsicSdsReg(rtk_uint32 sdsId, rtk_uint32 sdsReg, rtk_uint32 sdsPage,  rtk_uint32 value);
+extern ret_t rtl8367c_getAsicSdsReg(rtk_uint32 sdsId, rtk_uint32 sdsReg, rtk_uint32 sdsPage, rtk_uint32 *value);
+
+#endif /*#ifndef _RTL8367C_ASICDRV_PHY_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_port.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_port.h
new file mode 100644
index 0000000..ad99d85
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_port.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76333 $
+ * $Date: 2017-03-09 09:33:15 +0800 (¶g¥|, 09 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Port security related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_PORTSECURITY_H_
+#define _RTL8367C_ASICDRV_PORTSECURITY_H_
+
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_unknownMulticast.h>
+#include <rtl8367c_asicdrv_phy.h>
+
+/****************************************************************/
+/* Type Definition                                              */
+/****************************************************************/
+
+#define RTL8367C_MAC7       7
+#define RTL8367C_EXTNO       3
+
+#define RTL8367C_RTCT_PAGE          (11)
+#define RTL8367C_RTCT_RESULT_A_REG  (27)
+#define RTL8367C_RTCT_RESULT_B_REG  (28)
+#define RTL8367C_RTCT_RESULT_C_REG  (29)
+#define RTL8367C_RTCT_RESULT_D_REG  (30)
+#define RTL8367C_RTCT_STATUS_REG    (26)
+
+enum L2_SECURITY_BEHAVE
+{
+    L2_BEHAVE_FLOODING = 0,
+    L2_BEHAVE_DROP,
+    L2_BEHAVE_TRAP,
+    L2_BEHAVE_END
+};
+
+enum L2_UNDA_BEHAVE
+{
+    L2_UNDA_BEHAVE_FLOODING_PMASK = 0,
+    L2_UNDA_BEHAVE_DROP,
+    L2_UNDA_BEHAVE_TRAP,
+    L2_UNDA_BEHAVE_FLOODING,
+    L2_UNDA_BEHAVE_END
+};
+
+enum L2_SECURITY_SA_BEHAVE
+{
+    L2_BEHAVE_SA_FLOODING = 0,
+    L2_BEHAVE_SA_DROP,
+    L2_BEHAVE_SA_TRAP,
+    L2_BEHAVE_SA_COPY28051,
+    L2_BEHAVE_SA_END
+};
+
+/* enum for port current link speed */
+enum SPEEDMODE
+{
+    SPD_10M = 0,
+    SPD_100M,
+    SPD_1000M,
+    SPD_2500M
+};
+
+/* enum for mac link mode */
+enum LINKMODE
+{
+    MAC_NORMAL = 0,
+    MAC_FORCE,
+};
+
+/* enum for port current link duplex mode */
+enum DUPLEXMODE
+{
+    HALF_DUPLEX = 0,
+    FULL_DUPLEX
+};
+
+/* enum for port current MST mode */
+enum MSTMODE
+{
+    SLAVE_MODE= 0,
+    MASTER_MODE
+};
+
+
+enum EXTMODE
+{
+    EXT_DISABLE = 0,
+    EXT_RGMII,
+    EXT_MII_MAC,
+    EXT_MII_PHY,
+    EXT_TMII_MAC,
+    EXT_TMII_PHY,
+    EXT_GMII,
+    EXT_RMII_MAC,
+    EXT_RMII_PHY,
+    EXT_SGMII,
+    EXT_HSGMII,
+    EXT_1000X_100FX,
+    EXT_1000X,
+    EXT_100FX,
+    EXT_RGMII_2,
+    EXT_MII_MAC_2,
+    EXT_MII_PHY_2,
+    EXT_TMII_MAC_2,
+    EXT_TMII_PHY_2,
+    EXT_RMII_MAC_2,
+    EXT_RMII_PHY_2,
+    EXT_END
+};
+
+enum DOSTYPE
+{
+    DOS_DAEQSA = 0,
+    DOS_LANDATTACKS,
+    DOS_BLATATTACKS,
+    DOS_SYNFINSCAN,
+    DOS_XMASCAN,
+    DOS_NULLSCAN,
+    DOS_SYN1024,
+    DOS_TCPSHORTHDR,
+    DOS_TCPFRAGERROR,
+    DOS_ICMPFRAGMENT,
+    DOS_END,
+
+};
+
+typedef struct  rtl8367c_port_ability_s{
+    rtk_uint16 forcemode;
+    rtk_uint16 mstfault;
+    rtk_uint16 mstmode;
+    rtk_uint16 nway;
+    rtk_uint16 txpause;
+    rtk_uint16 rxpause;
+    rtk_uint16 link;
+    rtk_uint16 duplex;
+    rtk_uint16 speed;
+}rtl8367c_port_ability_t;
+
+typedef struct  rtl8367c_port_status_s{
+
+    rtk_uint16 lpi1000;
+    rtk_uint16 lpi100;
+    rtk_uint16 mstfault;
+    rtk_uint16 mstmode;
+    rtk_uint16 nway;
+    rtk_uint16 txpause;
+    rtk_uint16 rxpause;
+    rtk_uint16 link;
+    rtk_uint16 duplex;
+    rtk_uint16 speed;
+
+}rtl8367c_port_status_t;
+
+typedef struct rtct_result_s
+{
+    rtk_uint32      channelAShort;
+    rtk_uint32      channelBShort;
+    rtk_uint32      channelCShort;
+    rtk_uint32      channelDShort;
+
+    rtk_uint32      channelAOpen;
+    rtk_uint32      channelBOpen;
+    rtk_uint32      channelCOpen;
+    rtk_uint32      channelDOpen;
+
+    rtk_uint32      channelAMismatch;
+    rtk_uint32      channelBMismatch;
+    rtk_uint32      channelCMismatch;
+    rtk_uint32      channelDMismatch;
+
+    rtk_uint32      channelALinedriver;
+    rtk_uint32      channelBLinedriver;
+    rtk_uint32      channelCLinedriver;
+    rtk_uint32      channelDLinedriver;
+
+    rtk_uint32      channelALen;
+    rtk_uint32      channelBLen;
+    rtk_uint32      channelCLen;
+    rtk_uint32      channelDLen;
+} rtl8367c_port_rtct_result_t;
+
+
+/****************************************************************/
+/* Driver Proto Type Definition                                 */
+/****************************************************************/
+extern ret_t rtl8367c_setAsicPortUnknownDaBehavior(rtk_uint32 port, rtk_uint32 behavior);
+extern ret_t rtl8367c_getAsicPortUnknownDaBehavior(rtk_uint32 port, rtk_uint32 *pBehavior);
+extern ret_t rtl8367c_setAsicPortUnknownSaBehavior(rtk_uint32 behavior);
+extern ret_t rtl8367c_getAsicPortUnknownSaBehavior(rtk_uint32 *pBehavior);
+extern ret_t rtl8367c_setAsicPortUnmatchedSaBehavior(rtk_uint32 behavior);
+extern ret_t rtl8367c_getAsicPortUnmatchedSaBehavior(rtk_uint32 *pBehavior);
+extern ret_t rtl8367c_setAsicPortUnmatchedSaMoving(rtk_uint32 port, rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicPortUnmatchedSaMoving(rtk_uint32 port, rtk_uint32 *pEnabled);
+extern ret_t rtl8367c_setAsicPortUnknownDaFloodingPortmask(rtk_uint32 portmask);
+extern ret_t rtl8367c_getAsicPortUnknownDaFloodingPortmask(rtk_uint32 *pPortmask);
+extern ret_t rtl8367c_setAsicPortUnknownMulticastFloodingPortmask(rtk_uint32 portmask);
+extern ret_t rtl8367c_getAsicPortUnknownMulticastFloodingPortmask(rtk_uint32 *pPortmask);
+extern ret_t rtl8367c_setAsicPortBcastFloodingPortmask(rtk_uint32 portmask);
+extern ret_t rtl8367c_getAsicPortBcastFloodingPortmask(rtk_uint32 *pPortmask);
+extern ret_t rtl8367c_setAsicPortBlockSpa(rtk_uint32 port, rtk_uint32 block);
+extern ret_t rtl8367c_getAsicPortBlockSpa(rtk_uint32 port, rtk_uint32 *pBlock);
+extern ret_t rtl8367c_setAsicPortForceLink(rtk_uint32 port, rtl8367c_port_ability_t *pPortAbility);
+extern ret_t rtl8367c_getAsicPortForceLink(rtk_uint32 port, rtl8367c_port_ability_t *pPortAbility);
+extern ret_t rtl8367c_getAsicPortStatus(rtk_uint32 port, rtl8367c_port_status_t *pPortStatus);
+extern ret_t rtl8367c_setAsicPortForceLinkExt(rtk_uint32 id, rtl8367c_port_ability_t *pPortAbility);
+extern ret_t rtl8367c_getAsicPortForceLinkExt(rtk_uint32 id, rtl8367c_port_ability_t *pPortAbility);
+extern ret_t rtl8367c_setAsicPortExtMode(rtk_uint32 id, rtk_uint32 mode);
+extern ret_t rtl8367c_getAsicPortExtMode(rtk_uint32 id, rtk_uint32 *pMode);
+extern ret_t rtl8367c_setAsicPortDos(rtk_uint32 type, rtk_uint32 drop);
+extern ret_t rtl8367c_getAsicPortDos(rtk_uint32 type, rtk_uint32* pDrop);
+extern ret_t rtl8367c_setAsicPortEnableAll(rtk_uint32 enable);
+extern ret_t rtl8367c_getAsicPortEnableAll(rtk_uint32 *pEnable);
+extern ret_t rtl8367c_setAsicPortSmallIpg(rtk_uint32 port, rtk_uint32 enable);
+extern ret_t rtl8367c_getAsicPortSmallIpg(rtk_uint32 port, rtk_uint32* pEnable);
+extern ret_t rtl8367c_setAsicPortLoopback(rtk_uint32 port, rtk_uint32 enable);
+extern ret_t rtl8367c_getAsicPortLoopback(rtk_uint32 port, rtk_uint32 *pEnable);
+extern ret_t rtl8367c_setAsicPortRTCTEnable(rtk_uint32 portmask);
+extern ret_t rtl8367c_setAsicPortRTCTDisable(rtk_uint32 portmask);
+extern ret_t rtl8367c_getAsicPortRTCTResult(rtk_uint32 port, rtl8367c_port_rtct_result_t *pResult);
+extern ret_t rtl8367c_sdsReset(rtk_uint32 id);
+extern ret_t rtl8367c_getSdsLinkStatus(rtk_uint32 ext_id, rtk_uint32 *pSignalDetect, rtk_uint32 *pSync, rtk_uint32 *pLink);
+extern ret_t rtl8367c_setSgmiiNway(rtk_uint32 ext_id, rtk_uint32 state);
+extern ret_t rtl8367c_getSgmiiNway(rtk_uint32 ext_id, rtk_uint32 *pState);
+
+#endif /*_RTL8367C_ASICDRV_PORTSECURITY_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_portIsolation.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_portIsolation.h
new file mode 100644
index 0000000..e23d88e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_portIsolation.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Port isolation related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_PORTISOLATION_H_
+#define _RTL8367C_ASICDRV_PORTISOLATION_H_
+
+#include <rtl8367c_asicdrv.h>
+
+extern ret_t rtl8367c_setAsicPortIsolationPermittedPortmask(rtk_uint32 port, rtk_uint32 permitPortmask);
+extern ret_t rtl8367c_getAsicPortIsolationPermittedPortmask(rtk_uint32 port, rtk_uint32 *pPermitPortmask);
+extern ret_t rtl8367c_setAsicPortIsolationEfid(rtk_uint32 port, rtk_uint32 efid);
+extern ret_t rtl8367c_getAsicPortIsolationEfid(rtk_uint32 port, rtk_uint32 *pEfid);
+
+#endif /*_RTL8367C_ASICDRV_PORTISOLATION_H_*/
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_qos.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_qos.h
new file mode 100644
index 0000000..26042bf
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_qos.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Qos related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_QOS_H_
+#define _RTL8367C_ASICDRV_QOS_H_
+
+#include <rtl8367c_asicdrv.h>
+
+#define RTL8367C_DECISIONPRIMAX    0xFF
+
+/* enum Priority Selection Types */
+enum PRIDECISION
+{
+    PRIDEC_PORT = 0,
+    PRIDEC_ACL,
+    PRIDEC_DSCP,
+    PRIDEC_1Q,
+    PRIDEC_1AD,
+    PRIDEC_CVLAN,
+    PRIDEC_DA,
+    PRIDEC_SA,
+    PRIDEC_END,
+};
+
+/* enum Priority Selection Index */
+enum RTL8367C_PRIDEC_TABLE
+{
+    PRIDEC_IDX0 = 0,
+    PRIDEC_IDX1,
+    PRIDEC_IDX_END,
+};
+
+enum RTL8367C_DOT1P_PRISEL
+{
+    DOT1P_PRISEL_USER =  0,
+    DOT1P_PRISEL_TAG,
+    DOT1P_PRISEL_END
+};
+
+enum RTL8367C_DSCP_PRISEL
+{
+    DSCP_PRISEL_INTERNAL =  0,
+    DSCP_PRISEL_DSCP,
+    DSCP_PRISEL_USER ,
+    DSCP_PRISEL_END
+};
+
+
+extern ret_t rtl8367c_setAsicRemarkingDot1pAbility(rtk_uint32 port, rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicRemarkingDot1pAbility(rtk_uint32 port, rtk_uint32* pEnabled);
+extern ret_t rtl8367c_setAsicRemarkingDot1pParameter(rtk_uint32 priority, rtk_uint32 newPriority );
+extern ret_t rtl8367c_getAsicRemarkingDot1pParameter(rtk_uint32 priority, rtk_uint32 *pNewPriority );
+extern  ret_t rtl8367c_setAsicRemarkingDot1pSrc(rtk_uint32 type);
+extern  ret_t rtl8367c_getAsicRemarkingDot1pSrc(rtk_uint32 *pType);
+extern ret_t rtl8367c_setAsicRemarkingDscpAbility(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicRemarkingDscpAbility(rtk_uint32* pEnabled);
+extern ret_t rtl8367c_setAsicRemarkingDscpParameter(rtk_uint32 priority, rtk_uint32 newDscp );
+extern ret_t rtl8367c_getAsicRemarkingDscpParameter(rtk_uint32 priority, rtk_uint32* pNewDscp );
+
+extern ret_t rtl8367c_setAsicPriorityDot1qRemapping(rtk_uint32 srcpriority, rtk_uint32 priority );
+extern ret_t rtl8367c_getAsicPriorityDot1qRemapping(rtk_uint32 srcpriority, rtk_uint32 *pPriority );
+extern ret_t rtl8367c_setAsicPriorityDscpBased(rtk_uint32 dscp, rtk_uint32 priority );
+extern ret_t rtl8367c_getAsicPriorityDscpBased(rtk_uint32 dscp, rtk_uint32 *pPriority );
+extern ret_t rtl8367c_setAsicPriorityPortBased(rtk_uint32 port, rtk_uint32 priority );
+extern ret_t rtl8367c_getAsicPriorityPortBased(rtk_uint32 port, rtk_uint32 *pPriority );
+extern ret_t rtl8367c_setAsicPriorityDecision(rtk_uint32 index, rtk_uint32 prisrc, rtk_uint32 decisionPri);
+extern ret_t rtl8367c_getAsicPriorityDecision(rtk_uint32 index, rtk_uint32 prisrc, rtk_uint32* pDecisionPri);
+extern ret_t rtl8367c_setAsicPriorityToQIDMappingTable(rtk_uint32 qnum, rtk_uint32 priority, rtk_uint32 qid );
+extern ret_t rtl8367c_getAsicPriorityToQIDMappingTable(rtk_uint32 qnum, rtk_uint32 priority, rtk_uint32* pQid);
+extern ret_t rtl8367c_setAsicOutputQueueMappingIndex(rtk_uint32 port, rtk_uint32 qnum );
+extern ret_t rtl8367c_getAsicOutputQueueMappingIndex(rtk_uint32 port, rtk_uint32 *pQnum );
+
+extern ret_t rtl8367c_setAsicRemarkingDscpSrc(rtk_uint32 type);
+extern ret_t rtl8367c_getAsicRemarkingDscpSrc(rtk_uint32 *pType);
+extern ret_t rtl8367c_setAsicRemarkingDscp2Dscp(rtk_uint32 dscp, rtk_uint32 rmkDscp);
+extern ret_t rtl8367c_getAsicRemarkingDscp2Dscp(rtk_uint32 dscp, rtk_uint32 *pRmkDscp);
+
+extern ret_t rtl8367c_setAsicPortPriorityDecisionIndex(rtk_uint32 port, rtk_uint32 index );
+extern ret_t rtl8367c_getAsicPortPriorityDecisionIndex(rtk_uint32 port, rtk_uint32 *pIndex );
+
+#endif /*#ifndef _RTL8367C_ASICDRV_QOS_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rldp.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rldp.h
new file mode 100644
index 0000000..cde970b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rldp.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 42321 $
+ * $Date: 2013-08-26 13:51:29 +0800 (¶g¤@, 26 ¤K¤ë 2013) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : RLDP related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_RLDP_H_
+#define _RTL8367C_ASICDRV_RLDP_H_
+
+#include <rtl8367c_asicdrv.h>
+#include <string.h>
+
+extern ret_t rtl8367c_setAsicRldp(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicRldp(rtk_uint32 *pEnabled);
+extern ret_t rtl8367c_setAsicRldpEnable8051(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicRldpEnable8051(rtk_uint32 *pEnabled);
+extern ret_t rtl8367c_setAsicRldpCompareRandomNumber(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicRldpCompareRandomNumber(rtk_uint32 *pEnabled);
+extern ret_t rtl8367c_setAsicRldpIndicatorSource(rtk_uint32 src);
+extern ret_t rtl8367c_getAsicRldpIndicatorSource(rtk_uint32 *pSrc);
+extern ret_t rtl8367c_setAsicRldpCheckingStatePara(rtk_uint32 retryCount, rtk_uint32 retryPeriod);
+extern ret_t rtl8367c_getAsicRldpCheckingStatePara(rtk_uint32 *pRetryCount, rtk_uint32 *pRetryPeriod);
+extern ret_t rtl8367c_setAsicRldpLoopStatePara(rtk_uint32 retryCount, rtk_uint32 retryPeriod);
+extern ret_t rtl8367c_getAsicRldpLoopStatePara(rtk_uint32 *pRetryCount, rtk_uint32 *pRetryPeriod);
+extern ret_t rtl8367c_setAsicRldpTxPortmask(rtk_uint32 portmask);
+extern ret_t rtl8367c_getAsicRldpTxPortmask(rtk_uint32 *pPortmask);
+extern ret_t rtl8367c_setAsicRldpMagicNum(ether_addr_t seed);
+extern ret_t rtl8367c_getAsicRldpMagicNum(ether_addr_t *pSeed);
+extern ret_t rtl8367c_getAsicRldpLoopedPortmask(rtk_uint32 *pPortmask);
+extern ret_t rtl8367c_setAsicRldp8051Portmask(rtk_uint32 portmask);
+extern ret_t rtl8367c_getAsicRldp8051Portmask(rtk_uint32 *pPortmask);
+
+
+extern ret_t rtl8367c_getAsicRldpRandomNumber(ether_addr_t *pRandNumber);
+extern ret_t rtl8367c_getAsicRldpLoopedPortPair(rtk_uint32 port, rtk_uint32 *pLoopedPair);
+extern ret_t rtl8367c_setAsicRlppTrap8051(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicRlppTrap8051(rtk_uint32 *pEnabled);
+
+extern ret_t rtl8367c_setAsicRldpLeaveLoopedPortmask(rtk_uint32 portmask);
+extern ret_t rtl8367c_getAsicRldpLeaveLoopedPortmask(rtk_uint32 *pPortmask);
+
+extern ret_t rtl8367c_setAsicRldpEnterLoopedPortmask(rtk_uint32 portmask);
+extern ret_t rtl8367c_getAsicRldpEnterLoopedPortmask(rtk_uint32 *pPortmask);
+
+extern ret_t rtl8367c_setAsicRldpTriggerMode(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicRldpTriggerMode(rtk_uint32 *pEnabled);
+
+#endif /*_RTL8367C_ASICDRV_RLDP_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rma.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rma.h
new file mode 100644
index 0000000..10c7075
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rma.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 64716 $
+ * $Date: 2015-12-31 16:31:55 +0800 (¶g¥|, 31 ¤Q¤G¤ë 2015) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : RMA related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_RMA_H_
+#define _RTL8367C_ASICDRV_RMA_H_
+
+#include <rtl8367c_asicdrv.h>
+
+#define RTL8367C_RMAMAX                     0x2F
+
+enum RTL8367C_RMAOP
+{
+    RMAOP_FORWARD = 0,
+    RMAOP_TRAP_TO_CPU,
+    RMAOP_DROP,
+    RMAOP_FORWARD_EXCLUDE_CPU,
+    RMAOP_END
+};
+
+
+typedef struct  rtl8367c_rma_s{
+
+    rtk_uint16 operation;
+    rtk_uint16 discard_storm_filter;
+    rtk_uint16 trap_priority;
+    rtk_uint16 keep_format;
+    rtk_uint16 vlan_leaky;
+    rtk_uint16 portiso_leaky;
+
+}rtl8367c_rma_t;
+
+
+extern ret_t rtl8367c_setAsicRma(rtk_uint32 index, rtl8367c_rma_t* pRmacfg);
+extern ret_t rtl8367c_getAsicRma(rtk_uint32 index, rtl8367c_rma_t* pRmacfg);
+extern ret_t rtl8367c_setAsicRmaCdp(rtl8367c_rma_t* pRmacfg);
+extern ret_t rtl8367c_getAsicRmaCdp(rtl8367c_rma_t* pRmacfg);
+extern ret_t rtl8367c_setAsicRmaCsstp(rtl8367c_rma_t* pRmacfg);
+extern ret_t rtl8367c_getAsicRmaCsstp(rtl8367c_rma_t* pRmacfg);
+extern ret_t rtl8367c_setAsicRmaLldp(rtk_uint32 enabled, rtl8367c_rma_t* pRmacfg);
+extern ret_t rtl8367c_getAsicRmaLldp(rtk_uint32 *pEnabled, rtl8367c_rma_t* pRmacfg);
+
+#endif /*#ifndef _RTL8367C_ASICDRV_RMA_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_scheduling.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_scheduling.h
new file mode 100644
index 0000000..919a4ca
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_scheduling.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Packet Scheduling related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_SCHEDULING_H_
+#define _RTL8367C_ASICDRV_SCHEDULING_H_
+
+#include <rtl8367c_asicdrv.h>
+
+#define RTL8367C_QWEIGHTMAX    0x7F
+#define RTL8367C_PORT_QUEUE_METER_INDEX_MAX    7
+
+/* enum for queue type */
+enum QUEUETYPE
+{
+    QTYPE_STRICT = 0,
+    QTYPE_WFQ,
+};
+extern ret_t rtl8367c_setAsicLeakyBucketParameter(rtk_uint32 tick, rtk_uint32 token);
+extern ret_t rtl8367c_getAsicLeakyBucketParameter(rtk_uint32 *tick, rtk_uint32 *token);
+extern ret_t rtl8367c_setAsicAprMeter(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 apridx);
+extern ret_t rtl8367c_getAsicAprMeter(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 *apridx);
+extern ret_t rtl8367c_setAsicPprMeter(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 ppridx);
+extern ret_t rtl8367c_getAsicPprMeter(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 *ppridx);
+extern ret_t rtl8367c_setAsicAprEnable(rtk_uint32 port, rtk_uint32 aprEnable);
+extern ret_t rtl8367c_getAsicAprEnable(rtk_uint32 port, rtk_uint32 *aprEnable);
+extern ret_t rtl8367c_setAsicPprEnable(rtk_uint32 port, rtk_uint32 pprEnable);
+extern ret_t rtl8367c_getAsicPprEnable(rtk_uint32 port, rtk_uint32 *pprEnable);
+
+extern ret_t rtl8367c_setAsicWFQWeight(rtk_uint32, rtk_uint32 queueid, rtk_uint32 weight );
+extern ret_t rtl8367c_getAsicWFQWeight(rtk_uint32, rtk_uint32 queueid, rtk_uint32 *weight );
+extern ret_t rtl8367c_setAsicWFQBurstSize(rtk_uint32 burstsize);
+extern ret_t rtl8367c_getAsicWFQBurstSize(rtk_uint32 *burstsize);
+
+extern ret_t rtl8367c_setAsicQueueType(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 queueType);
+extern ret_t rtl8367c_getAsicQueueType(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 *queueType);
+extern ret_t rtl8367c_setAsicQueueRate(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 ppridx, rtk_uint32 apridx );
+extern ret_t rtl8367c_getAsicQueueRate(rtk_uint32 port, rtk_uint32 qid, rtk_uint32* ppridx, rtk_uint32* apridx );
+extern ret_t rtl8367c_setAsicPortEgressRate(rtk_uint32 port, rtk_uint32 rate);
+extern ret_t rtl8367c_getAsicPortEgressRate(rtk_uint32 port, rtk_uint32 *rate);
+extern ret_t rtl8367c_setAsicPortEgressRateIfg(rtk_uint32 ifg);
+extern ret_t rtl8367c_getAsicPortEgressRateIfg(rtk_uint32 *ifg);
+
+#endif /*_RTL8367C_ASICDRV_SCHEDULING_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_storm.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_storm.h
new file mode 100644
index 0000000..3865b52
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_storm.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Storm control filtering related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_STORM_H_
+#define _RTL8367C_ASICDRV_STORM_H_
+
+#include <rtl8367c_asicdrv.h>
+
+extern ret_t rtl8367c_setAsicStormFilterBroadcastEnable(rtk_uint32 port, rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicStormFilterBroadcastEnable(rtk_uint32 port, rtk_uint32 *pEnabled);
+extern ret_t rtl8367c_setAsicStormFilterBroadcastMeter(rtk_uint32 port, rtk_uint32 meter);
+extern ret_t rtl8367c_getAsicStormFilterBroadcastMeter(rtk_uint32 port, rtk_uint32 *pMeter);
+extern ret_t rtl8367c_setAsicStormFilterMulticastEnable(rtk_uint32 port, rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicStormFilterMulticastEnable(rtk_uint32 port, rtk_uint32 *pEnabled);
+extern ret_t rtl8367c_setAsicStormFilterMulticastMeter(rtk_uint32 port, rtk_uint32 meter);
+extern ret_t rtl8367c_getAsicStormFilterMulticastMeter(rtk_uint32 port, rtk_uint32 *pMeter);
+extern ret_t rtl8367c_setAsicStormFilterUnknownMulticastEnable(rtk_uint32 port, rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicStormFilterUnknownMulticastEnable(rtk_uint32 port, rtk_uint32 *pEnabled);
+extern ret_t rtl8367c_setAsicStormFilterUnknownMulticastMeter(rtk_uint32 port, rtk_uint32 meter);
+extern ret_t rtl8367c_getAsicStormFilterUnknownMulticastMeter(rtk_uint32 port, rtk_uint32 *pMeter);
+extern ret_t rtl8367c_setAsicStormFilterUnknownUnicastEnable(rtk_uint32 port, rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicStormFilterUnknownUnicastEnable(rtk_uint32 port, rtk_uint32 *pEnabled);
+extern ret_t rtl8367c_setAsicStormFilterUnknownUnicastMeter(rtk_uint32 port, rtk_uint32 meter);
+extern ret_t rtl8367c_getAsicStormFilterUnknownUnicastMeter(rtk_uint32 port, rtk_uint32 *pMeter);
+extern ret_t rtl8367c_setAsicStormFilterExtBroadcastMeter(rtk_uint32 meter);
+extern ret_t rtl8367c_getAsicStormFilterExtBroadcastMeter(rtk_uint32 *pMeter);
+extern ret_t rtl8367c_setAsicStormFilterExtMulticastMeter(rtk_uint32 meter);
+extern ret_t rtl8367c_getAsicStormFilterExtMulticastMeter(rtk_uint32 *pMeter);
+extern ret_t rtl8367c_setAsicStormFilterExtUnknownMulticastMeter(rtk_uint32 meter);
+extern ret_t rtl8367c_getAsicStormFilterExtUnknownMulticastMeter(rtk_uint32 *pMeter);
+extern ret_t rtl8367c_setAsicStormFilterExtUnknownUnicastMeter(rtk_uint32 meter);
+extern ret_t rtl8367c_getAsicStormFilterExtUnknownUnicastMeter(rtk_uint32 *pMeter);
+extern ret_t rtl8367c_setAsicStormFilterExtBroadcastEnable(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicStormFilterExtBroadcastEnable(rtk_uint32 *pEnabled);
+extern ret_t rtl8367c_setAsicStormFilterExtMulticastEnable(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicStormFilterExtMulticastEnable(rtk_uint32 *pEnabled);
+extern ret_t rtl8367c_setAsicStormFilterExtUnknownMulticastEnable(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicStormFilterExtUnknownMulticastEnable(rtk_uint32 *pEnabled);
+extern ret_t rtl8367c_setAsicStormFilterExtUnknownUnicastEnable(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicStormFilterExtUnknownUnicastEnable(rtk_uint32 *pEnabled);
+extern ret_t rtl8367c_setAsicStormFilterExtEnablePortMask(rtk_uint32 portmask);
+extern ret_t rtl8367c_getAsicStormFilterExtEnablePortMask(rtk_uint32 *pPortmask);
+
+
+#endif /*_RTL8367C_ASICDRV_STORM_H_*/
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_svlan.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_svlan.h
new file mode 100644
index 0000000..5a6a4a8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_svlan.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : SVLAN related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_SVLAN_H_
+#define _RTL8367C_ASICDRV_SVLAN_H_
+
+#include <rtl8367c_asicdrv.h>
+
+#define RTL8367C_C2SIDXNO               128
+#define RTL8367C_C2SIDXMAX              (RTL8367C_C2SIDXNO-1)
+#define RTL8367C_MC2SIDXNO              32
+#define RTL8367C_MC2SIDXMAX             (RTL8367C_MC2SIDXNO-1)
+#define RTL8367C_SP2CIDXNO              128
+#define RTL8367C_SP2CMAX                (RTL8367C_SP2CIDXNO-1)
+
+#define RTL8367C_SVLAN_MEMCONF_LEN      4
+#define RTL8367C_SVLAN_MC2S_LEN         5
+#define RTL8367C_SVLAN_SP2C_LEN         2
+
+enum RTL8367C_SPRISEL
+{
+    SPRISEL_INTERNALPRI =  0,
+    SPRISEL_CTAGPRI,
+    SPRISEL_VSPRI,
+    SPRISEL_PBPRI,
+    SPRISEL_END
+};
+
+enum RTL8367C_SUNACCEPT
+{
+    SUNACCEPT_DROP =  0,
+    SUNACCEPT_TRAP,
+    SUNACCEPT_SVLAN,
+    SUNACCEPT_END
+};
+
+enum RTL8367C_SVLAN_MC2S_MODE
+{
+    SVLAN_MC2S_MODE_MAC =  0,
+    SVLAN_MC2S_MODE_IP,
+    SVLAN_MC2S_MODE_END
+};
+
+
+typedef struct  rtl8367c_svlan_memconf_s{
+
+    rtk_uint16 vs_member:11;
+    rtk_uint16 vs_untag:11;
+
+    rtk_uint16 vs_fid_msti:4;
+    rtk_uint16 vs_priority:3;
+    rtk_uint16 vs_force_fid:1;
+    rtk_uint16 reserved:8;
+
+    rtk_uint16 vs_svid:12;
+    rtk_uint16 vs_efiden:1;
+    rtk_uint16 vs_efid:3;
+
+
+}rtl8367c_svlan_memconf_t;
+
+
+typedef struct  rtl8367c_svlan_mc2s_s{
+
+    rtk_uint16 valid:1;
+    rtk_uint16 format:1;
+    rtk_uint16 svidx:6;
+    rtk_uint32 sdata;
+    rtk_uint32 smask;
+}rtl8367c_svlan_mc2s_t;
+
+
+typedef struct  rtl8367c_svlan_s2c_s{
+
+    rtk_uint16 valid:1;
+    rtk_uint16 svidx:6;
+    rtk_uint16 dstport:4;
+    rtk_uint32 vid:12;
+}rtl8367c_svlan_s2c_t;
+
+extern ret_t rtl8367c_setAsicSvlanIngressUntag(rtk_uint32 mode);
+extern ret_t rtl8367c_getAsicSvlanIngressUntag(rtk_uint32* pMode);
+extern ret_t rtl8367c_setAsicSvlanIngressUnmatch(rtk_uint32 mode);
+extern ret_t rtl8367c_getAsicSvlanIngressUnmatch(rtk_uint32* pMode);
+extern ret_t rtl8367c_setAsicSvlanTrapPriority(rtk_uint32 priority);
+extern ret_t rtl8367c_getAsicSvlanTrapPriority(rtk_uint32* pPriority);
+extern ret_t rtl8367c_setAsicSvlanDefaultVlan(rtk_uint32 port, rtk_uint32 index);
+extern ret_t rtl8367c_getAsicSvlanDefaultVlan(rtk_uint32 port, rtk_uint32* pIndex);
+
+extern ret_t rtl8367c_setAsicSvlanMemberConfiguration(rtk_uint32 index,rtl8367c_svlan_memconf_t* pSvlanMemCfg);
+extern ret_t rtl8367c_getAsicSvlanMemberConfiguration(rtk_uint32 index,rtl8367c_svlan_memconf_t* pSvlanMemCfg);
+
+extern ret_t rtl8367c_setAsicSvlanPrioritySel(rtk_uint32 priSel);
+extern ret_t rtl8367c_getAsicSvlanPrioritySel(rtk_uint32* pPriSel);
+extern ret_t rtl8367c_setAsicSvlanTpid(rtk_uint32 protocolType);
+extern ret_t rtl8367c_getAsicSvlanTpid(rtk_uint32* pProtocolType);
+extern ret_t rtl8367c_setAsicSvlanUplinkPortMask(rtk_uint32 portMask);
+extern ret_t rtl8367c_getAsicSvlanUplinkPortMask(rtk_uint32* pPortmask);
+extern ret_t rtl8367c_setAsicSvlanEgressUnassign(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicSvlanEgressUnassign(rtk_uint32* pEnabled);
+extern ret_t rtl8367c_setAsicSvlanC2SConf(rtk_uint32 index, rtk_uint32 evid, rtk_uint32 portmask, rtk_uint32 svidx);
+extern ret_t rtl8367c_getAsicSvlanC2SConf(rtk_uint32 index, rtk_uint32* pEvid, rtk_uint32* pPortmask, rtk_uint32* pSvidx);
+extern ret_t rtl8367c_setAsicSvlanMC2SConf(rtk_uint32 index,rtl8367c_svlan_mc2s_t* pSvlanMc2sCfg);
+extern ret_t rtl8367c_getAsicSvlanMC2SConf(rtk_uint32 index,rtl8367c_svlan_mc2s_t* pSvlanMc2sCfg);
+extern ret_t rtl8367c_setAsicSvlanSP2CConf(rtk_uint32 index,rtl8367c_svlan_s2c_t* pSvlanSp2cCfg);
+extern ret_t rtl8367c_getAsicSvlanSP2CConf(rtk_uint32 index,rtl8367c_svlan_s2c_t* pSvlanSp2cCfg);
+extern ret_t rtl8367c_setAsicSvlanDmacCvidSel(rtk_uint32 port, rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicSvlanDmacCvidSel(rtk_uint32 port, rtk_uint32* pEnabled);
+extern ret_t rtl8367c_setAsicSvlanUntagVlan(rtk_uint32 index);
+extern ret_t rtl8367c_getAsicSvlanUntagVlan(rtk_uint32* pIndex);
+extern ret_t rtl8367c_setAsicSvlanUnmatchVlan(rtk_uint32 index);
+extern ret_t rtl8367c_getAsicSvlanUnmatchVlan(rtk_uint32* pIndex);
+extern ret_t rtl8367c_setAsicSvlanLookupType(rtk_uint32 type);
+extern ret_t rtl8367c_getAsicSvlanLookupType(rtk_uint32* pType);
+
+
+#endif /*#ifndef _RTL8367C_ASICDRV_SVLAN_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_trunking.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_trunking.h
new file mode 100644
index 0000000..2e3a682
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_trunking.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Port trunking related functions
+ *
+ */
+
+
+#ifndef _RTL8367C_ASICDRV_TRUNKING_H_
+#define _RTL8367C_ASICDRV_TRUNKING_H_
+
+#include <rtl8367c_asicdrv.h>
+
+#define RTL8367C_MAX_TRUNK_GID              (2)
+#define RTL8367C_TRUNKING_PORTNO            (4)
+#define RTL8367C_TRUNKING1_PORTN0           (2)
+#define RTL8367C_TRUNKING_HASHVALUE_MAX     (15)
+
+extern ret_t rtl8367c_setAsicTrunkingGroup(rtk_uint32 group, rtk_uint32 portmask);
+extern ret_t rtl8367c_getAsicTrunkingGroup(rtk_uint32 group, rtk_uint32* pPortmask);
+extern ret_t rtl8367c_setAsicTrunkingFlood(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicTrunkingFlood(rtk_uint32* pEnabled);
+extern ret_t rtl8367c_setAsicTrunkingHashSelect(rtk_uint32 hashsel);
+extern ret_t rtl8367c_getAsicTrunkingHashSelect(rtk_uint32* pHashsel);
+
+extern ret_t rtl8367c_getAsicQeueuEmptyStatus(rtk_uint32* pPortmask);
+
+extern ret_t rtl8367c_setAsicTrunkingMode(rtk_uint32 mode);
+extern ret_t rtl8367c_getAsicTrunkingMode(rtk_uint32* pMode);
+extern ret_t rtl8367c_setAsicTrunkingFc(rtk_uint32 group, rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicTrunkingFc(rtk_uint32 group, rtk_uint32* pEnabled);
+extern ret_t rtl8367c_setAsicTrunkingHashTable(rtk_uint32 hashval, rtk_uint32 portId);
+extern ret_t rtl8367c_getAsicTrunkingHashTable(rtk_uint32 hashval, rtk_uint32* pPortId);
+extern ret_t rtl8367c_setAsicTrunkingHashTable1(rtk_uint32 hashval, rtk_uint32 portId);
+extern ret_t rtl8367c_getAsicTrunkingHashTable1(rtk_uint32 hashval, rtk_uint32* pPortId);
+
+#endif /*_RTL8367C_ASICDRV_TRUNKING_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_unknownMulticast.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_unknownMulticast.h
new file mode 100644
index 0000000..d142d25
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_unknownMulticast.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Unkown multicast related functions
+ *
+ */
+
+#ifndef _RTL8367C_ASICDRV_UNKNOWNMULTICAST_H_
+#define _RTL8367C_ASICDRV_UNKNOWNMULTICAST_H_
+
+#include <rtl8367c_asicdrv.h>
+
+enum L2_UNKOWN_MULTICAST_BEHAVE
+{
+    L2_UNKOWN_MULTICAST_FLOODING = 0,
+    L2_UNKOWN_MULTICAST_DROP,
+    L2_UNKOWN_MULTICAST_TRAP,
+    L2_UNKOWN_MULTICAST_DROP_EXCLUDE_RMA,
+    L2_UNKOWN_MULTICAST_END
+};
+
+enum L3_UNKOWN_MULTICAST_BEHAVE
+{
+    L3_UNKOWN_MULTICAST_FLOODING = 0,
+    L3_UNKOWN_MULTICAST_DROP,
+    L3_UNKOWN_MULTICAST_TRAP,
+    L3_UNKOWN_MULTICAST_ROUTER,
+    L3_UNKOWN_MULTICAST_END
+};
+
+enum MULTICASTTYPE{
+    MULTICAST_TYPE_IPV4 = 0,
+    MULTICAST_TYPE_IPV6,
+    MULTICAST_TYPE_L2,
+    MULTICAST_TYPE_END
+};
+
+extern ret_t rtl8367c_setAsicUnknownL2MulticastBehavior(rtk_uint32 port, rtk_uint32 behave);
+extern ret_t rtl8367c_getAsicUnknownL2MulticastBehavior(rtk_uint32 port, rtk_uint32 *pBehave);
+extern ret_t rtl8367c_setAsicUnknownIPv4MulticastBehavior(rtk_uint32 port, rtk_uint32 behave);
+extern ret_t rtl8367c_getAsicUnknownIPv4MulticastBehavior(rtk_uint32 port, rtk_uint32 *pBehave);
+extern ret_t rtl8367c_setAsicUnknownIPv6MulticastBehavior(rtk_uint32 port, rtk_uint32 behave);
+extern ret_t rtl8367c_getAsicUnknownIPv6MulticastBehavior(rtk_uint32 port, rtk_uint32 *pBehave);
+extern ret_t rtl8367c_setAsicUnknownMulticastTrapPriority(rtk_uint32 priority);
+extern ret_t rtl8367c_getAsicUnknownMulticastTrapPriority(rtk_uint32 *pPriority);
+
+#endif /*_RTL8367C_ASICDRV_UNKNOWNMULTICAST_H_*/
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_vlan.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_vlan.h
new file mode 100644
index 0000000..6184865
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_vlan.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : VLAN related functions
+ *
+ */
+
+
+#ifndef _RTL8367C_ASICDRV_VLAN_H_
+#define _RTL8367C_ASICDRV_VLAN_H_
+
+/****************************************************************/
+/* Header File inclusion                                        */
+/****************************************************************/
+#include <rtl8367c_asicdrv.h>
+
+/****************************************************************/
+/* Constant Definition                                          */
+/****************************************************************/
+#define RTL8367C_PROTOVLAN_GIDX_MAX 3
+#define RTL8367C_PROTOVLAN_GROUPNO  4
+
+#define RTL8367C_VLAN_BUSY_CHECK_NO     (10)
+
+#define RTL8367C_VLAN_MBRCFG_LEN    (4)
+#define RTL8367C_VLAN_4KTABLE_LEN   (3)
+
+/****************************************************************/
+/* Type Definition                                              */
+/****************************************************************/
+typedef struct  VLANCONFIGUSER
+{
+    rtk_uint16  evid;
+    rtk_uint16  mbr;
+    rtk_uint16  fid_msti;
+    rtk_uint16  envlanpol;
+    rtk_uint16  meteridx;
+    rtk_uint16  vbpen;
+    rtk_uint16  vbpri;
+}rtl8367c_vlanconfiguser;
+
+typedef struct  USER_VLANTABLE{
+
+    rtk_uint16  vid;
+    rtk_uint16  mbr;
+    rtk_uint16  untag;
+    rtk_uint16  fid_msti;
+    rtk_uint16  envlanpol;
+    rtk_uint16  meteridx;
+    rtk_uint16  vbpen;
+    rtk_uint16  vbpri;
+    rtk_uint16  ivl_svl;
+
+}rtl8367c_user_vlan4kentry;
+
+typedef enum
+{
+    FRAME_TYPE_BOTH = 0,
+    FRAME_TYPE_TAGGED_ONLY,
+    FRAME_TYPE_UNTAGGED_ONLY,
+    FRAME_TYPE_MAX_BOUND
+} rtl8367c_accframetype;
+
+typedef enum
+{
+    EG_TAG_MODE_ORI = 0,
+    EG_TAG_MODE_KEEP,
+    EG_TAG_MODE_PRI_TAG,
+    EG_TAG_MODE_REAL_KEEP,
+    EG_TAG_MODE_END
+} rtl8367c_egtagmode;
+
+typedef enum
+{
+    PPVLAN_FRAME_TYPE_ETHERNET = 0,
+    PPVLAN_FRAME_TYPE_LLC,
+    PPVLAN_FRAME_TYPE_RFC1042,
+    PPVLAN_FRAME_TYPE_END
+} rtl8367c_provlan_frametype;
+
+enum RTL8367C_STPST
+{
+    STPST_DISABLED = 0,
+    STPST_BLOCKING,
+    STPST_LEARNING,
+    STPST_FORWARDING
+};
+
+enum RTL8367C_RESVIDACT
+{
+    RES_VID_ACT_UNTAG = 0,
+    RES_VID_ACT_TAG,
+    RES_VID_ACT_END
+};
+
+typedef struct
+{
+    rtl8367c_provlan_frametype  frameType;
+    rtk_uint32                      etherType;
+} rtl8367c_protocolgdatacfg;
+
+typedef struct
+{
+    rtk_uint32 valid;
+    rtk_uint32 vlan_idx;
+    rtk_uint32 priority;
+} rtl8367c_protocolvlancfg;
+
+extern ret_t rtl8367c_setAsicVlanMemberConfig(rtk_uint32 index, rtl8367c_vlanconfiguser *pVlanCg);
+extern ret_t rtl8367c_getAsicVlanMemberConfig(rtk_uint32 index, rtl8367c_vlanconfiguser *pVlanCg);
+extern ret_t rtl8367c_setAsicVlan4kEntry(rtl8367c_user_vlan4kentry *pVlan4kEntry );
+extern ret_t rtl8367c_getAsicVlan4kEntry(rtl8367c_user_vlan4kentry *pVlan4kEntry );
+extern ret_t rtl8367c_setAsicVlanAccpetFrameType(rtk_uint32 port, rtl8367c_accframetype frameType);
+extern ret_t rtl8367c_getAsicVlanAccpetFrameType(rtk_uint32 port, rtl8367c_accframetype *pFrameType);
+extern ret_t rtl8367c_setAsicVlanIngressFilter(rtk_uint32 port, rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicVlanIngressFilter(rtk_uint32 port, rtk_uint32 *pEnable);
+extern ret_t rtl8367c_setAsicVlanEgressTagMode(rtk_uint32 port, rtl8367c_egtagmode tagMode);
+extern ret_t rtl8367c_getAsicVlanEgressTagMode(rtk_uint32 port, rtl8367c_egtagmode *pTagMode);
+extern ret_t rtl8367c_setAsicVlanPortBasedVID(rtk_uint32 port, rtk_uint32 index, rtk_uint32 pri);
+extern ret_t rtl8367c_getAsicVlanPortBasedVID(rtk_uint32 port, rtk_uint32 *pIndex, rtk_uint32 *pPri);
+extern ret_t rtl8367c_setAsicVlanProtocolBasedGroupData(rtk_uint32 index, rtl8367c_protocolgdatacfg *pPbCfg);
+extern ret_t rtl8367c_getAsicVlanProtocolBasedGroupData(rtk_uint32 index, rtl8367c_protocolgdatacfg *pPbCfg);
+extern ret_t rtl8367c_setAsicVlanPortAndProtocolBased(rtk_uint32 port, rtk_uint32 index, rtl8367c_protocolvlancfg *pPpbCfg);
+extern ret_t rtl8367c_getAsicVlanPortAndProtocolBased(rtk_uint32 port, rtk_uint32 index, rtl8367c_protocolvlancfg *pPpbCfg);
+extern ret_t rtl8367c_setAsicVlanFilter(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicVlanFilter(rtk_uint32* pEnabled);
+
+extern ret_t rtl8367c_setAsicPortBasedFid(rtk_uint32 port, rtk_uint32 fid);
+extern ret_t rtl8367c_getAsicPortBasedFid(rtk_uint32 port, rtk_uint32* pFid);
+extern ret_t rtl8367c_setAsicPortBasedFidEn(rtk_uint32 port, rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicPortBasedFidEn(rtk_uint32 port, rtk_uint32* pEnabled);
+extern ret_t rtl8367c_setAsicSpanningTreeStatus(rtk_uint32 port, rtk_uint32 msti, rtk_uint32 state);
+extern ret_t rtl8367c_getAsicSpanningTreeStatus(rtk_uint32 port, rtk_uint32 msti, rtk_uint32* pState);
+extern ret_t rtl8367c_setAsicVlanUntagDscpPriorityEn(rtk_uint32 enabled);
+extern ret_t rtl8367c_getAsicVlanUntagDscpPriorityEn(rtk_uint32* enabled);
+extern ret_t rtl8367c_setAsicVlanTransparent(rtk_uint32 port, rtk_uint32 portmask);
+extern ret_t rtl8367c_getAsicVlanTransparent(rtk_uint32 port, rtk_uint32 *pPortmask);
+extern ret_t rtl8367c_setAsicVlanEgressKeep(rtk_uint32 port, rtk_uint32 portmask);
+extern ret_t rtl8367c_getAsicVlanEgressKeep(rtk_uint32 port, rtk_uint32* pPortmask);
+extern ret_t rtl8367c_setReservedVidAction(rtk_uint32 vid0Action, rtk_uint32 vid4095Action);
+extern ret_t rtl8367c_getReservedVidAction(rtk_uint32 *pVid0Action, rtk_uint32 *pVid4095Action);
+extern ret_t rtl8367c_setRealKeepRemarkEn(rtk_uint32 enabled);
+extern ret_t rtl8367c_getRealKeepRemarkEn(rtk_uint32 *pEnabled);
+extern ret_t rtl8367c_resetVlan(void);
+
+#endif /*#ifndef _RTL8367C_ASICDRV_VLAN_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_base.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_base.h
new file mode 100644
index 0000000..676ca8e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_base.h
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Regsiter MACRO related definition
+ *
+ */
+
+#ifndef _RTL8367C_BASE_H_
+#define _RTL8367C_BASE_H_
+
+#include <rtl8367c_reg.h>
+
+/* (16'h0000) port_reg */
+
+#define    RTL8367C_PORT_SPECIAL_CONGEST_MODE_TIMER_BASE        RTL8367C_REG_PKTGEN_PORT0_TIMER
+#define    RTL8367C_PORT_SPECIAL_CONGEST_MODE_TIMER_REG(port)    (RTL8367C_PORT_SPECIAL_CONGEST_MODE_TIMER_BASE + (port << 5))
+
+#define    RTL8367C_PORT_MISC_CFG_BASE                            RTL8367C_REG_PORT0_MISC_CFG
+#define    RTL8367C_PORT_MISC_CFG_REG(port)                        (RTL8367C_PORT_MISC_CFG_BASE + (port << 5))
+#define    RTL8367C_1QREMARK_ENABLE_OFFSET                         RTL8367C_PORT0_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET
+#define    RTL8367C_1QREMARK_ENABLE_MASK                        RTL8367C_PORT0_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK
+
+#define    RTL8367C_INGRESSBW_PORT_IFG_MASK                        RTL8367C_PORT0_MISC_CFG_INGRESSBW_IFG_MASK
+#define    RTL8367C_VLAN_EGRESS_MDOE_MASK                        RTL8367C_PORT0_MISC_CFG_VLAN_EGRESS_MODE_MASK
+#define    RTL8367C_SPECIALCONGEST_SUSTAIN_TIMER_MASK            RTL8367C_PORT0_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK
+
+#define    RTL8367C_INGRESSBW_PORT_RATE_LSB_BASE                RTL8367C_REG_INGRESSBW_PORT0_RATE_CTRL0
+#define    RTL8367C_INGRESSBW_PORT_RATE_LSB_REG(port)            (RTL8367C_INGRESSBW_PORT_RATE_LSB_BASE + (port << 5))
+
+#define    RTL8367C_PORT_SMALL_IPG_REG(port)                    (RTL8367C_REG_PORT0_MISC_CFG + (port*0x20))
+
+#define    RTL8367C_PORT_EEE_CFG_BASE                           RTL8367C_REG_PORT0_EEECFG
+#define    RTL8367C_PORT_EEE_CFG_REG(port)                      (RTL8367C_REG_PORT0_EEECFG + (port << 5))
+#define    RTL8367C_PORT_EEE_100M_OFFSET                        RTL8367C_PORT0_EEECFG_EEE_100M_OFFSET
+#define    RTL8367C_PORT_EEE_100M_MASK                          RTL8367C_PORT0_EEECFG_EEE_100M_MASK
+#define    RTL8367C_PORT_EEE_GIGA_OFFSET                        RTL8367C_PORT0_EEECFG_EEE_GIGA_500M_OFFSET
+#define    RTL8367C_PORT_EEE_GIGA_MASK                          RTL8367C_PORT0_EEECFG_EEE_GIGA_500M_MASK
+
+
+/* (16'h0200) outq_reg */
+
+#define    RTL8367C_FLOWCTRL_QUEUE_DROP_ON_BASE                    RTL8367C_REG_FLOWCTRL_QUEUE0_DROP_ON
+#define    RTL8367C_FLOWCTRL_QUEUE_DROP_ON_REG(queue)            (RTL8367C_FLOWCTRL_QUEUE_DROP_ON_BASE + queue)
+#define    RTL8367C_FLOWCTRL_QUEUE_DROP_ON_MASK                    RTL8367C_FLOWCTRL_QUEUE0_DROP_ON_MASK
+
+#define    RTL8367C_FLOWCTRL_PORT_DROP_ON_BASE                    RTL8367C_REG_FLOWCTRL_PORT0_DROP_ON
+#define    RTL8367C_FLOWCTRL_PORT_DROP_ON_REG(PORT)                (RTL8367C_FLOWCTRL_PORT_DROP_ON_BASE + PORT)
+#define    RTL8367C_FLOWCTRL_PORT_DROP_ON_MASK                    RTL8367C_FLOWCTRL_PORT0_DROP_ON_MASK
+
+#define    RTL8367C_FLOWCTRL_PORT_GAP_REG                        RTL8367C_REG_FLOWCTRL_PORT_GAP
+#define    RTL8367C_FLOWCTRL_QUEUE_GAP_REG                        RTL8367C_REG_FLOWCTRL_QUEUE_GAP
+#define    RTL8367C_FLOWCTRL_PORT_QEMPTY_REG                    RTL8367C_REG_PORT_QEMPTY
+
+/* (16'h0300) sch_reg */
+
+#define    RTL8367C_SCHEDULE_WFQ_BURST_SIZE_REG                    RTL8367C_REG_SCHEDULE_WFQ_BURST_SIZE
+
+#define    RTL8367C_SCHEDULE_QUEUE_TYPE_BASE                    RTL8367C_REG_SCHEDULE_QUEUE_TYPE_CTRL0
+#define    RTL8367C_SCHEDULE_QUEUE_TYPE_REG(port)                (RTL8367C_SCHEDULE_QUEUE_TYPE_BASE + (port >> 1))
+#define    RTL8367C_SCHEDULE_QUEUE_TYPE_OFFSET(port, queue)        (((port & 0x1) << 3) + queue)
+#define    RTL8367C_SCHEDULE_QUEUE_TYPE_MASK(port, queue)         RTL8367C_SCHEDULE_QUEUE_TYPE_OFFSET(port, queue)
+
+#define    RTL8367C_SCHEDULE_PORT_QUEUE_WFQ_WEIGHT_BASE            RTL8367C_REG_SCHEDULE_PORT0_QUEUE0_WFQ_WEIGHT
+#define    RTL8367C_SCHEDULE_PORT_QUEUE_WFQ_WEIGHT_REG(port, queue)    (RTL8367C_SCHEDULE_PORT_QUEUE_WFQ_WEIGHT_BASE + (port << 3) + queue)
+
+#define    RTL8367C_SCHEDULE_APR_CTRL_REG                       RTL8367C_REG_SCHEDULE_APR_CTRL0
+#define    RTL8367C_SCHEDULE_APR_CTRL_OFFSET(port)                (port)
+#define    RTL8367C_SCHEDULE_APR_CTRL_MASK(port)                (1 << RTL8367C_SCHEDULE_APR_CTRL_OFFSET(port))
+
+#define    RTL8367C_SCHEDULE_PORT_APR_METER_BASE                RTL8367C_REG_SCHEDULE_PORT0_APR_METER_CTRL0
+#define    RTL8367C_SCHEDULE_PORT_APR_METER_REG(port, queue)    (RTL8367C_SCHEDULE_PORT_APR_METER_BASE + (port << 2) + (queue / 5))
+#define    RTL8367C_SCHEDULE_PORT_APR_METER_OFFSET(queue)        (3 * (queue % 5))
+#define    RTL8367C_SCHEDULE_PORT_APR_METER_MASK(queue)            (RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE0_APR_METER_MASK << RTL8367C_SCHEDULE_PORT_APR_METER_OFFSET(queue))
+
+#define    RTL8367C_PORT_EGRESSBW_LSB_BASE                        RTL8367C_REG_PORT0_EGRESSBW_CTRL0
+#define    RTL8367C_PORT_EGRESSBW_LSB_REG(port)                    (RTL8367C_PORT_EGRESSBW_LSB_BASE + (port << 1))
+
+#define    RTL8367C_PORT_EGRESSBW_MSB_BASE                        RTL8367C_REG_PORT0_EGRESSBW_CTRL1
+#define    RTL8367C_PORT_EGRESSBW_MSB_REG(port)                    (RTL8367C_PORT_EGRESSBW_MSB_BASE + (port << 1))
+
+/* (16'h0500) table_reg */
+
+#define    RTL8367C_TABLE_ACCESS_CTRL_REG                        RTL8367C_REG_TABLE_ACCESS_CTRL
+
+#define    RTL8367C_TABLE_ACCESS_ADDR_REG                        RTL8367C_REG_TABLE_ACCESS_ADDR
+
+#define    RTL8367C_TABLE_ACCESS_STATUS_REG                        RTL8367C_REG_TABLE_LUT_ADDR
+
+#define    RTL8367C_TABLE_ACCESS_WRDATA_BASE                    RTL8367C_REG_TABLE_WRITE_DATA0
+#define    RTL8367C_TABLE_ACCESS_WRDATA_REG(index)                (RTL8367C_TABLE_ACCESS_WRDATA_BASE + index)
+
+#define    RTL8367C_TABLE_ACCESS_RDDATA_BASE                    RTL8367C_REG_TABLE_READ_DATA0
+#define    RTL8367C_TABLE_ACCESS_RDDATA_REG(index)                (RTL8367C_TABLE_ACCESS_RDDATA_BASE + index)
+
+
+
+/* (16'h0600) acl_reg */
+
+#define    RTL8367C_ACL_RULE_TEMPLATE_CTRL_BASE                    RTL8367C_REG_ACL_RULE_TEMPLATE0_CTRL0
+#define    RTL8367C_ACL_RULE_TEMPLATE_CTRL_REG(template)        (RTL8367C_ACL_RULE_TEMPLATE_CTRL_BASE + template * 0x4)
+#define    RTL8367C_ACL_TEMPLATE_FIELD_OFFSET(field)            ((field & 0x01) <<3)
+#define    RTL8367C_ACL_TEMPLATE_FIELD_MASK(field)                (0x3F << RTL8367C_ACL_TEMPLATE_FIELD_OFFSET(field))
+
+#define    RTL8367C_ACL_ACTION_CTRL_BASE                        RTL8367C_REG_ACL_ACTION_CTRL0
+#define    RTL8367C_ACL_ACTION_CTRL_REG(rule)                   (RTL8367C_ACL_ACTION_CTRL_BASE + (rule >> 1))
+#define    RTL8367C_ACL_ACTION_CTRL2_BASE                        RTL8367C_REG_ACL_ACTION_CTRL32
+#define    RTL8367C_ACL_ACTION_CTRL2_REG(rule)                  (RTL8367C_ACL_ACTION_CTRL2_BASE + ((rule-64) >> 1))
+
+#define    RTL8367C_ACL_OP_NOT_OFFSET(rule)                        (6 + ((rule & 0x1) << 3))
+#define    RTL8367C_ACL_OP_NOT_MASK(rule)                        (1 << RTL8367C_ACL_OP_NOT_OFFSET(rule))
+#define    RTL8367C_ACL_OP_ACTION_OFFSET(rule)                    ((rule & 0x1) << 3)
+#define    RTL8367C_ACL_OP_ACTION_MASK(rule)                    (0x3F << RTL8367C_ACL_OP_ACTION_OFFSET(rule))
+
+#define    RTL8367C_ACL_ENABLE_REG                                RTL8367C_REG_ACL_ENABLE
+#define    RTL8367C_ACL_UNMATCH_PERMIT_REG                        RTL8367C_REG_ACL_UNMATCH_PERMIT
+
+/* (16'h0700) cvlan_reg */
+
+#define    RTL8367C_VLAN_PVID_CTRL_BASE                            RTL8367C_REG_VLAN_PVID_CTRL0
+#define    RTL8367C_VLAN_PVID_CTRL_REG(port)                    (RTL8367C_VLAN_PVID_CTRL_BASE + (port >> 1))
+#define    RTL8367C_PORT_VIDX_OFFSET(port)                        ((port &1)<<3)
+#define    RTL8367C_PORT_VIDX_MASK(port)                        (RTL8367C_PORT0_VIDX_MASK << RTL8367C_PORT_VIDX_OFFSET(port))
+
+#define    RTL8367C_VLAN_PPB_VALID_BASE                            RTL8367C_REG_VLAN_PPB0_VALID
+#define    RTL8367C_VLAN_PPB_VALID_REG(item)                    (RTL8367C_VLAN_PPB_VALID_BASE + (item << 3))
+
+#define    RTL8367C_VLAN_PPB_CTRL_BASE                            RTL8367C_REG_VLAN_PPB0_CTRL0
+#define    RTL8367C_VLAN_PPB_CTRL_REG(item, port)               (RTL8367C_VLAN_PPB_CTRL_BASE + (item << 3) + (port / 3) )
+#define    RTL8367C_VLAN_PPB_CTRL_OFFSET(port)                    ((port % 3) * 5)
+#define    RTL8367C_VLAN_PPB_CTRL_MASK(port)                    (RTL8367C_VLAN_PPB0_CTRL0_PORT0_INDEX_MASK << RTL8367C_VLAN_PPB_CTRL_OFFSET(port))
+
+#define    RTL8367C_VLAN_PPB_FRAMETYPE_BASE                    RTL8367C_REG_VLAN_PPB0_CTRL2
+#define    RTL8367C_VLAN_PPB_FRAMETYPE_REG(item)               (RTL8367C_VLAN_PPB_FRAMETYPE_BASE + (item << 3))
+#define    RTL8367C_VLAN_PPB_FRAMETYPE_MASK                    RTL8367C_VLAN_PPB0_CTRL2_FRAME_TYPE_MASK
+
+#define    RTL8367C_VLAN_PPB_ETHERTYPR_BASE                        RTL8367C_REG_VLAN_PPB0_CTRL3
+#define    RTL8367C_VLAN_PPB_ETHERTYPR_REG(item)                (RTL8367C_VLAN_PPB_ETHERTYPR_BASE + (item << 3))
+
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION_BASE                RTL8367C_REG_VLAN_MEMBER_CONFIGURATION0_CTRL0
+
+
+#define    RTL8367C_VLAN_CTRL_REG                                RTL8367C_REG_VLAN_CTRL
+
+#define    RTL8367C_VLAN_INGRESS_REG                            RTL8367C_REG_VLAN_INGRESS
+
+#define    RTL8367C_VLAN_ACCEPT_FRAME_TYPE_BASE                    RTL8367C_REG_VLAN_ACCEPT_FRAME_TYPE_CTRL0
+#define    RTL8367C_VLAN_ACCEPT_FRAME_TYPE_REG(port)            (RTL8367C_VLAN_ACCEPT_FRAME_TYPE_BASE + (port >> 3))
+#define    RTL8367C_VLAN_ACCEPT_FRAME_TYPE_MASK(port)           (RTL8367C_PORT0_FRAME_TYPE_MASK << ((port & 0x7) << 1))
+
+#define    RTL8367C_PORT_EFID_BASE                                RTL8367C_REG_PORT_EFID_CTRL0
+#define    RTL8367C_PORT_EFID_REG(port)                            (RTL8367C_PORT_EFID_BASE + (port >> 2))
+#define    RTL8367C_PORT_EFID_OFFSET(port)                         ((port & 0x3) << 2)
+#define    RTL8367C_PORT_EFID_MASK(port)                        (RTL8367C_PORT0_EFID_MASK << RTL8367C_PORT_EFID_OFFSET(port))
+
+#define    RTL8367C_PORT_PBFIDEN_REG                            RTL8367C_REG_PORT_PBFIDEN
+
+#define    RTL8367C_PORT_PBFID_BASE                             RTL8367C_REG_PORT0_PBFID
+#define    RTL8367C_PORT_PBFID_REG(port)                        (RTL8367C_PORT_PBFID_BASE + port)
+
+/* (16'h0800) dpm_reg */
+
+#define    RTL8367C_RMA_CTRL_BASE                                RTL8367C_REG_RMA_CTRL00
+
+
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_BASE                RTL8367C_REG_VLAN_PORTBASED_PRIORITY_CTRL0
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_REG(port)            (RTL8367C_VLAN_PORTBASED_PRIORITY_BASE + (port >> 2))
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_OFFSET(port)        ((port & 0x3) << 2)
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_MASK(port)            (0x7 << RTL8367C_VLAN_PORTBASED_PRIORITY_OFFSET(port))
+
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM_BASE                    RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM0_CTRL0
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM_REG(port, item)        (RTL8367C_VLAN_PPB_PRIORITY_ITEM_BASE + (item << 2)+ (port>>2))
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM_OFFSET(port)            ((port & 0x3) <<2)
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM_MASK(port)            (RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT0_PRIORITY_MASK << RTL8367C_VLAN_PPB_PRIORITY_ITEM_OFFSET(port))
+
+#define    RTL8367C_QOS_1Q_PRIORITY_REMAPPING_BASE                RTL8367C_REG_QOS_1Q_PRIORITY_REMAPPING_CTRL0
+#define    RTL8367C_QOS_1Q_PRIORITY_REMAPPING_REG(pri)            (RTL8367C_QOS_1Q_PRIORITY_REMAPPING_BASE + (pri >> 2))
+#define    RTL8367C_QOS_1Q_PRIORITY_REMAPPING_OFFSET(pri)        ((pri & 0x3) << 2)
+#define    RTL8367C_QOS_1Q_PRIORITY_REMAPPING_MASK(pri)            (0x7 << RTL8367C_QOS_1Q_PRIORITY_REMAPPING_OFFSET(pri))
+
+#define    RTL8367C_QOS_DSCP_TO_PRIORITY_BASE                    RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL0
+#define    RTL8367C_QOS_DSCP_TO_PRIORITY_REG(dscp)                (RTL8367C_QOS_DSCP_TO_PRIORITY_BASE + (dscp >> 2))
+#define    RTL8367C_QOS_DSCP_TO_PRIORITY_OFFSET(dscp)            ((dscp & 0x3) << 2)
+#define    RTL8367C_QOS_DSCP_TO_PRIORITY_MASK(dscp)                (0x7 << RTL8367C_QOS_DSCP_TO_PRIORITY_OFFSET(dscp))
+
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_BASE                    RTL8367C_REG_QOS_PORTBASED_PRIORITY_CTRL0
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_REG(port)            (RTL8367C_QOS_PORTBASED_PRIORITY_BASE + (port >> 2))
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_OFFSET(port)            ((port & 0x3) << 2)
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_MASK(port)            (0x7 << RTL8367C_QOS_PORTBASED_PRIORITY_OFFSET(port))
+
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_BASE            RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION_CTRL0
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_REG(src)        (RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_BASE + (src >> 1))
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_OFFSET(src)  ((src & 1) << 3)
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_MASK(src)    (RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL0_QOS_PORT_WEIGHT_MASK << RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_OFFSET(src))
+
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_BASE            RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION2_CTRL0
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_REG(src)        (RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_BASE + (src >> 1))
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_OFFSET(src)  ((src & 1) << 3)
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_MASK(src)    (RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL0_QOS_PORT_WEIGHT_MASK << RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_OFFSET(src))
+
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_IDX_CTRL            RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION_IDX
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_IDX(port)  (1 << port)
+
+#define    RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_BASE            RTL8367C_REG_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0
+#define    RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_REG(pri)        (RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_BASE + (pri >> 2))
+#define    RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_OFFSET(pri)  ((pri & 0x3) << 2)
+#define    RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_MASK(pri)    (RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY0_MASK << RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_OFFSET(pri))
+
+#define    RTL8367C_QOS_TRAP_PRIORITY_CTRL0_REG                RTL8367C_REG_QOS_TRAP_PRIORITY0
+
+#define    RTL8367C_QOS_TRAP_PRIORITY_CTRL1_REG                RTL8367C_REG_QOS_TRAP_PRIORITY1
+
+#define    RTL8367C_QOS_DSCP_TO_DSCP_BASE                             RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL0
+#define    RTL8367C_QOS_DSCP_TO_DSCP_REG(dscp)                     (RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL0 + (dscp >> 1))
+#define    RTL8367C_QOS_DSCP_TO_DSCP_OFFSET(dscp)                ((dscp & 0x1) << 8)
+#define    RTL8367C_QOS_DSCP_TO_DSCP_MASK(dscp)                   (0x3F << RTL8367C_QOS_DSCP_TO_DSCP_OFFSET(dscp))
+
+#define    RTL8367C_UNUCAST_FLOADING_PMSK_REG                    RTL8367C_REG_UNDA_FLOODING_PMSK
+
+#define    RTL8367C_UNMCAST_FLOADING_PMSK_REG                    RTL8367C_REG_UNMCAST_FLOADING_PMSK
+
+#define    RTL8367C_BCAST_FLOADING_PMSK_REG                        RTL8367C_REG_BCAST_FLOADING_PMSK
+
+#define    RTL8367C_PORT_ISOLATION_PORT_MASK_BASE                RTL8367C_REG_PORT_ISOLATION_PORT0_MASK
+#define    RTL8367C_PORT_ISOLATION_PORT_MASK_REG(port)            (RTL8367C_PORT_ISOLATION_PORT_MASK_BASE + port)
+
+#define    RTL8367C_FORCE_CTRL_REG                                RTL8367C_REG_FORCE_CTRL
+
+#define    RTL8367C_SOURCE_PORT_BLOCK_REG                        RTL8367C_REG_SOURCE_PORT_PERMIT
+
+#define    RTL8367C_IPMCAST_VLAN_LEAKY_REG                        RTL8367C_REG_IPMCAST_VLAN_LEAKY
+
+#define    RTL8367C_IPMCAST_PORTISO_LEAKY_REG                    RTL8367C_REG_IPMCAST_PORTISO_LEAKY
+
+#define    RTL8367C_PORT_SECURIT_CTRL_REG                        RTL8367C_REG_PORT_SECURITY_CTRL
+
+#define    RTL8367C_UNKNOWN_IPV4_MULTICAST_BASE                    RTL8367C_REG_UNKNOWN_IPV4_MULTICAST_CTRL0
+#define    RTL8367C_UNKNOWN_IPV4_MULTICAST_REG(port)            (RTL8367C_UNKNOWN_IPV4_MULTICAST_BASE + (port >> 3))
+#define    RTL8367C_UNKNOWN_IPV4_MULTICAST_OFFSET(port)            ((port & 0x7) << 1)
+#define    RTL8367C_UNKNOWN_IPV4_MULTICAST_MASK(port)            (RTL8367C_PORT0_UNKNOWN_IP4_MCAST_MASK << RTL8367C_UNKNOWN_IPV4_MULTICAST_OFFSET(port))
+
+#define    RTL8367C_UNKNOWN_IPV6_MULTICAST_BASE                    RTL8367C_REG_UNKNOWN_IPV6_MULTICAST_CTRL0
+#define    RTL8367C_UNKNOWN_IPV6_MULTICAST_REG(port)            (RTL8367C_UNKNOWN_IPV6_MULTICAST_BASE + (port >> 3))
+#define    RTL8367C_UNKNOWN_IPV6_MULTICAST_OFFSET(port)            ((port & 0x7) << 1)
+#define    RTL8367C_UNKNOWN_IPV6_MULTICAST_MASK(port)            (RTL8367C_PORT0_UNKNOWN_IP4_MCAST_MASK << RTL8367C_UNKNOWN_IPV6_MULTICAST_OFFSET(port))
+
+#define    RTL8367C_UNKNOWN_L2_MULTICAST_BASE                    RTL8367C_REG_UNKNOWN_L2_MULTICAST_CTRL0
+#define    RTL8367C_UNKNOWN_L2_MULTICAST_REG(port)                (RTL8367C_UNKNOWN_L2_MULTICAST_BASE + (port >> 3))
+#define    RTL8367C_UNKNOWN_L2_MULTICAST_OFFSET(port)            ((port & 0x7) << 1)
+#define    RTL8367C_UNKNOWN_L2_MULTICAST_MASK(port)                (RTL8367C_PORT0_UNKNOWN_L2_MCAST_MASK << RTL8367C_UNKNOWN_L2_MULTICAST_OFFSET(port))
+
+#define    RTL8367C_PORT_TRUNK_CTRL_REG                            RTL8367C_REG_PORT_TRUNK_CTRL
+#define    RTL8367C_PORT_TRUNK_HASH_MASK                           0x007F
+
+#define    RTL8367C_PORT_TRUNK_GROUP_MASK_REG    RTL8367C_REG_PORT_TRUNK_GROUP_MASK
+#define    RTL8367C_PORT_TRUNK_GROUP_MASK_OFFSET(group)    (group << 2)
+#define    RTL8367C_PORT_TRUNK_GROUP_MASK_MASK(group)    (RTL8367C_PORT_TRUNK_GROUP0_MASK_MASK << RTL8367C_PORT_TRUNK_GROUP_MASK_OFFSET(group))
+
+#define    RTL8367C_PORT_TRUNK_FLOWCTRL_REG                        RTL8367C_REG_PORT_TRUNK_FLOWCTRL
+
+#define    RTL8367C_QOS_PORT_QUEUE_NUMBER_BASE                    RTL8367C_REG_QOS_PORT_QUEUE_NUMBER_CTRL0
+#define    RTL8367C_QOS_PORT_QUEUE_NUMBER_REG(port)                (RTL8367C_QOS_PORT_QUEUE_NUMBER_BASE + (port >> 2))
+#define    RTL8367C_QOS_PORT_QUEUE_NUMBER_OFFSET(port)            ((port & 0x3) << 2)
+#define    RTL8367C_QOS_PORT_QUEUE_NUMBER_MASK(port)            (0x7 << RTL8367C_QOS_PORT_QUEUE_NUMBER_OFFSET(port))
+
+#define    RTL8367C_QOS_1Q_PRIORITY_TO_QID_BASE                    RTL8367C_REG_QOS_1Q_PRIORITY_TO_QID_CTRL0
+#define    RTL8367C_QOS_1Q_PRIORITY_TO_QID_REG(index, pri)        (RTL8367C_QOS_1Q_PRIORITY_TO_QID_BASE + (index << 1) + (pri >> 2))
+#define    RTL8367C_QOS_1Q_PRIORITY_TO_QID_OFFSET(pri)            ((pri & 0x3) << 2)
+#define    RTL8367C_QOS_1Q_PRIORITY_TO_QID_MASK(pri)            (RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK << RTL8367C_QOS_1Q_PRIORITY_TO_QID_OFFSET(pri))
+
+#define    RTL8367C_DEBUG_INFO_BASE                                RTL8367C_REG_PORT_DEBUG_INFO_CTRL0
+#define    RTL8367C_DEBUG_INFO_REG(port)                        (RTL8367C_DEBUG_INFO_BASE + (port >>1))
+#define    RTL8367C_DEBUG_INFO_OFFSET(port)                        ((port&1)<<3)
+#define    RTL8367C_DEBUG_INFO_MASK(port)                        (RTL8367C_PORT0_DEBUG_INFO_MASK << RTL8367C_DEBUG_INFO_OFFSET(port))
+
+/* (16'h0a00) l2_reg */
+
+#define    RTL8367C_VLAN_MSTI_BASE                                RTL8367C_REG_VLAN_MSTI0_CTRL0
+#define    RTL8367C_VLAN_MSTI_REG(tree, port)                    (RTL8367C_VLAN_MSTI_BASE + (tree << 1) + (port >> 3))
+#define    RTL8367C_VLAN_MSTI_OFFSET(port)                        ((port & 0x7) << 1)
+#define    RTL8367C_VLAN_MSTI_MASK(port)                        (RTL8367C_VLAN_MSTI0_CTRL0_PORT0_STATE_MASK << RTL8367C_VLAN_MSTI_OFFSET(port))
+
+#define    RTL8367C_LUT_PORT_LEARN_LIMITNO_BASE                    RTL8367C_REG_LUT_PORT0_LEARN_LIMITNO
+#define    RTL8367C_LUT_PORT_LEARN_LIMITNO_REG(port)            (RTL8367C_LUT_PORT_LEARN_LIMITNO_BASE + port)
+
+#define    RTL8367C_LUT_CFG_REG                                    RTL8367C_REG_LUT_CFG
+
+#define    RTL8367C_LUT_AGEOUT_CTRL_REG                            RTL8367C_REG_LUT_AGEOUT_CTRL
+
+#define    RTL8367C_FORCE_FLUSH_REG                                RTL8367C_REG_FORCE_FLUSH
+
+#define    RTL8367C_STORM_BCAST_REG                                RTL8367C_REG_STORM_BCAST
+
+#define    RTL8367C_STORM_MCAST_REG                                RTL8367C_REG_STORM_MCAST
+
+#define    RTL8367C_STORM_UNKNOWN_UCAST_REG                        RTL8367C_REG_STORM_UNKOWN_UCAST
+
+#define    RTL8367C_STORM_UNKNOWN_MCAST_REG                        RTL8367C_REG_STORM_UNKOWN_MCAST
+
+#define    RTL8367C_STORM_BCAST_METER_CTRL_BASE                    RTL8367C_REG_STORM_BCAST_METER_CTRL0
+#define    RTL8367C_STORM_BCAST_METER_CTRL_REG(port)            (RTL8367C_STORM_BCAST_METER_CTRL_BASE + (port >> 1))
+#define    RTL8367C_STORM_BCAST_METER_CTRL_OFFSET(port)            ((port & 0x1) << 3)
+#define    RTL8367C_STORM_BCAST_METER_CTRL_MASK(port)            (0xFF << RTL8367C_STORM_BCAST_METER_CTRL_OFFSET(port))
+
+#define    RTL8367C_STORM_MCAST_METER_CTRL_BASE                    RTL8367C_REG_STORM_MCAST_METER_CTRL0
+#define    RTL8367C_STORM_MCAST_METER_CTRL_REG(port)            (RTL8367C_STORM_MCAST_METER_CTRL_BASE + (port >> 1))
+#define    RTL8367C_STORM_MCAST_METER_CTRL_OFFSET(port)            ((port & 0x1) << 3)
+#define    RTL8367C_STORM_MCAST_METER_CTRL_MASK(port)            (0xFF << RTL8367C_STORM_MCAST_METER_CTRL_OFFSET(port))
+
+#define    RTL8367C_STORM_UNDA_METER_CTRL_BASE                    RTL8367C_REG_STORM_UNDA_METER_CTRL0
+#define    RTL8367C_STORM_UNDA_METER_CTRL_REG(port)                (RTL8367C_STORM_UNDA_METER_CTRL_BASE + (port >> 1))
+#define    RTL8367C_STORM_UNDA_METER_CTRL_OFFSET(port)            ((port & 0x1) << 3)
+#define    RTL8367C_STORM_UNDA_METER_CTRL_MASK(port)            (0xFF << RTL8367C_STORM_UNDA_METER_CTRL_OFFSET(port))
+
+#define    RTL8367C_STORM_UNMC_METER_CTRL_BASE                    RTL8367C_REG_STORM_UNMC_METER_CTRL0
+#define    RTL8367C_STORM_UNMC_METER_CTRL_REG(port)                (RTL8367C_STORM_UNMC_METER_CTRL_BASE + (port >> 1))
+#define    RTL8367C_STORM_UNMC_METER_CTRL_OFFSET(port)            ((port & 0x1) << 3)
+#define    RTL8367C_STORM_UNMC_METER_CTRL_MASK(port)            (0xFF << RTL8367C_STORM_UNMC_METER_CTRL_OFFSET(port))
+
+#define    RTL8367C_OAM_PARSER_OFFSET(port)                        (port*2)
+#define    RTL8367C_OAM_PARSER_MASK(port)                        (RTL8367C_PORT0_PARACT_MASK << RTL8367C_OAM_PARSER_OFFSET(port))
+
+#define    RTL8367C_OAM_MULTIPLEXER_OFFSET(port)                (port*2)
+#define    RTL8367C_OAM_MULTIPLEXER_MASK(port)                    (RTL8367C_PORT0_PARACT_MASK << RTL8367C_OAM_MULTIPLEXER_OFFSET(port))
+
+#define    RTL8367C_OAM_CTRL_REG                                RTL8367C_REG_OAM_CTRL
+
+#define    RTL8367C_DOT1X_PORT_ENABLE_REG                        RTL8367C_REG_DOT1X_PORT_ENABLE
+
+#define    RTL8367C_DOT1X_MAC_ENABLE_REG                        RTL8367C_REG_DOT1X_MAC_ENABLE
+
+#define    RTL8367C_DOT1X_PORT_AUTH_REG                            RTL8367C_REG_DOT1X_PORT_AUTH
+
+#define    RTL8367C_DOT1X_PORT_OPDIR_REG                        RTL8367C_REG_DOT1X_PORT_OPDIR
+
+#define    RTL8367C_DOT1X_UNAUTH_ACT_BASE                        RTL8367C_REG_DOT1X_UNAUTH_ACT_W0
+#define    RTL8367C_DOT1X_UNAUTH_ACT_OFFSET(port)                ((port & 0x7) << 1)
+#define    RTL8367C_DOT1X_UNAUTH_ACT_MASK(port)                    (RTL8367C_DOT1X_PORT0_UNAUTHBH_MASK << RTL8367C_DOT1X_UNAUTH_ACT_OFFSET(port))
+
+#define    RTL8367C_DOT1X_CFG_REG                                RTL8367C_REG_DOT1X_CFG
+
+#define    RTL8367C_REG_L2_LRN_CNT_BASE                            RTL8367C_REG_L2_LRN_CNT_CTRL0
+#define    RTL8367C_REG_L2_LRN_CNT_REG(port)                    (RTL8367C_REG_L2_LRN_CNT_BASE + port)
+
+/* (16'h0b00) mltvlan_reg */
+
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY_BASE_REG(index)        (RTL8367C_REG_SVLAN_MCAST2S_ENTRY0_CTRL0 + index*5)
+
+/* (16'h0c00) svlan_reg */
+
+#define    RTL8367C_SVLAN_MEMBERCFG_BASE_REG(index)                (RTL8367C_REG_SVLAN_MEMBERCFG0_CTRL1 + index*3)
+#define    RTL8367C_SVLAN_C2SCFG_BASE_REG(index)                  (RTL8367C_REG_SVLAN_C2SCFG0_CTRL0+ index*3)
+#define    RTL8367C_SVLAN_CFG_REG                                RTL8367C_REG_SVLAN_CFG
+
+/* (16'h0f00) hsactrl_reg */
+
+#define    RTL8367C_SVLAN_S2C_ENTRY_BASE_REG(index)                (RTL8367C_REG_SVLAN_SP2C_ENTRY0_CTRL0 + index*2)
+
+/* (16'h1000) mib_reg */
+
+#define    RTL8367C_MIB_COUNTER_BASE_REG                        RTL8367C_REG_MIB_COUNTER0
+
+#define    RTL8367C_MIB_ADDRESS_REG                                RTL8367C_REG_MIB_ADDRESS
+
+#define    RTL8367C_MIB_CTRL_REG                                RTL8367C_REG_MIB_CTRL0
+#define    RTL8367C_MIB_PORT07_MASK                                (0xFF<<RTL8367C_PORT0_RESET_OFFSET)
+
+/* (16'h1100) intrpt_reg */
+
+#define    RTL8367C_INTR_CTRL_REG                                RTL8367C_REG_INTR_CTRL
+
+#define    RTL8367C_INTR_IMR_REG                                RTL8367C_REG_INTR_IMR
+
+#define    RTL8367C_INTR_IMS_REG                                RTL8367C_REG_INTR_IMS
+
+#define    RTL8367C_INTR_INDICATOR_BASED                        RTL8367C_REG_LEARN_OVER_INDICATOR
+#define    RTL8367C_LEARN_OVER_INDICATOR_REG                    RTL8367C_REG_LEARN_OVER_INDICATOR
+
+#define    RTL8367C_SPEED_CHANGE_INDICATOR_REG                    RTL8367C_REG_SPEED_CHANGE_INDICATOR
+
+#define    RTL8367C_PORT_LINKDOWN_INDICATOR_REG                    RTL8367C_REG_PORT_LINKDOWN_INDICATOR
+
+#define    RTL8367C_PORT_LINKUP_INDICATOR_REG                    RTL8367C_REG_PORT_LINKUP_INDICATOR
+
+#define    RTL8367C_REG_METER_EXCEED_INDICATOR_BASE                RTL8367C_REG_METER_EXCEED_INDICATOR0
+#define    RTL8367C_REG_METER_EXCEED_INDICATOR_REG(meter)        (RTL8367C_REG_METER_EXCEED_INDICATOR_BASE + (meter >> 4))
+#define    RTL8367C_REG_METER_EXCEED_INDICATOR_OFFSET(meter)    (meter & 0xF)
+
+/* (16'h1200) swcore_reg */
+
+#define    RTL8367C_VS_TPID_REG                                    RTL8367C_REG_VS_TPID
+
+#define    RTL8367C_SWITCH_MAC_BASE                                RTL8367C_REG_SWITCH_MAC0
+
+#define    RTL8367C_REMARKING_CTRL_REG                            RTL8367C_REG_SWITCH_CTRL0
+
+#define    RTL8367C_QOS_DSCP_REMARK_BASE                        RTL8367C_REG_QOS_DSCP_REMARK_CTRL0
+#define    RTL8367C_QOS_DSCP_REMARK_REG(pri)                    (RTL8367C_QOS_DSCP_REMARK_BASE + (pri >> 1))
+#define    RTL8367C_QOS_DSCP_REMARK_OFFSET(pri)                    (((pri) & 0x1) << 3)
+#define    RTL8367C_QOS_DSCP_REMARK_MASK(pri)                    (0x3F << RTL8367C_QOS_DSCP_REMARK_OFFSET(pri))
+
+#define    RTL8367C_QOS_1Q_REMARK_BASE                            RTL8367C_REG_QOS_1Q_REMARK_CTRL0
+#define    RTL8367C_QOS_1Q_REMARK_REG(pri)                        (RTL8367C_QOS_1Q_REMARK_BASE + (pri >> 2))
+#define    RTL8367C_QOS_1Q_REMARK_OFFSET(pri)                    ((pri & 0x3) << 2)
+#define    RTL8367C_QOS_1Q_REMARK_MASK(pri)                        (0x7 << RTL8367C_QOS_1Q_REMARK_OFFSET(pri))
+
+#define    RTL8367C_PTKGEN_PAYLOAD_CTRL0_REG                    RTL8367C_REG_PTKGEN_PAYLOAD_CTRL0
+
+#define    RTL8367C_PTKGEN_PAYLOAD_CTRL1_REG                    RTL8367C_REG_PTKGEN_PAYLOAD_CTRL1
+
+#define    RTL8367C_SVLAN_UPLINK_PORTMASK_REG                    RTL8367C_REG_SVLAN_UPLINK_PORTMASK
+
+#define    RTL8367C_CPU_PORT_MASK_REG                            RTL8367C_REG_CPU_PORT_MASK
+
+#define    RTL8367C_CPU_CTRL_REG                                RTL8367C_REG_CPU_CTRL
+
+#define    RTL8367C_MIRROR_CTRL_REG                                RTL8367C_REG_MIRROR_CTRL
+
+
+#define    RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_BASE            RTL8367C_REG_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL0
+#define    RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG(port)        (RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_BASE + (port >> 1))
+#define    RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG_OFFSET(port)    ((port & 0x1) << 3)
+#define    RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG_MASK(port)    (RTL8367C_PORT0_QUEUE_MASK_MASK << RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG_OFFSET(port))
+
+
+#define    RTL8367C_FLOWCTRL_PORT_PAGE_COUNTER_BASE                RTL8367C_REG_FLOWCTRL_PORT0_PAGE_COUNTER
+#define    RTL8367C_FLOWCTRL_PORT_PAGE_COUNTER_REG(port)        (RTL8367C_FLOWCTRL_PORT_PAGE_COUNTER_BASE + port)
+#define    RTL8367C_FLOWCTRL_PORT_PAGE_COUNTER_MASK                RTL8367C_FLOWCTRL_PORT0_PAGE_COUNTER_MASK
+
+#define    RTL8367C_FLOWCTRL_PORT_PAGE_MAX_BASE                    RTL8367C_REG_FLOWCTRL_PORT0_PAGE_MAX
+#define    RTL8367C_FLOWCTRL_PORT_PAGE_MAX_REG(port)            (RTL8367C_FLOWCTRL_PORT_PAGE_MAX_BASE + port)
+#define    RTL8367C_FLOWCTRL_PORT_PAGE_MAX_MASK                    RTL8367C_FLOWCTRL_PORT0_PAGE_MAX_MASK
+
+#define    RTL8367C_FIELD_SELECTOR_REG(index)                    (RTL8367C_REG_FIELD_SELECTOR0 + index)
+#define    RTL8367C_FIELD_SELECTOR_ENABLE_OFFSET                 RTL8367C_FIELD_SELECTOR0_ENABLE_OFFSET
+#define    RTL8367C_FIELD_SELECTOR_ENABLE_MASK                    RTL8367C_FIELD_SELECTOR0_ENABLE_MASK
+#define    RTL8367C_FIELD_SELECTOR_FORMAT_OFFSET                RTL8367C_FIELD_SELECTOR0_FORMAT_OFFSET
+#define    RTL8367C_FIELD_SELECTOR_FORMAT_MASK                    RTL8367C_FIELD_SELECTOR0_FORMAT_MASK
+#define    RTL8367C_FIELD_SELECTOR_OFFSET_OFFSET                  RTL8367C_FIELD_SELECTOR0_OFFSET_OFFSET
+#define    RTL8367C_FIELD_SELECTOR_OFFSET_MASK                    RTL8367C_FIELD_SELECTOR0_OFFSET_MASK
+
+/* (16'h1300) chip_reg*/
+
+/* (16'h1400) mtrpool_reg */
+#define    RTL8367C_METER_RATE_BASE                                RTL8367C_REG_METER0_RATE_CTRL0
+#define    RTL8367C_METER_RATE_REG(meter)                        ((meter << 1) + RTL8367C_METER_RATE_BASE)
+
+#define    RTL8367C_METER_BUCKET_SIZE_BASE                        RTL8367C_REG_METER0_BUCKET_SIZE
+#define    RTL8367C_METER_BUCKET_SIZE_REG(meter)                (RTL8367C_METER_BUCKET_SIZE_BASE + meter)
+
+#define    RTL8367C_LEAKY_BUCKET_TICK_REG                        RTL8367C_REG_METER_CTRL0
+#define    RTL8367C_LEAKY_BUCKET_TICK_OFFSET                    RTL8367C_METER_TICK_OFFSET
+#define    RTL8367C_LEAKY_BUCKET_TICK_MASK                        RTL8367C_METER_TICK_MASK
+
+#define    RTL8367C_LEAKY_BUCKET_TOKEN_REG                        RTL8367C_REG_METER_CTRL1
+#define    RTL8367C_LEAKY_BUCKET_TOKEN_OFFSET                    RTL8367C_METER_CTRL1_OFFSET
+#define    RTL8367C_LEAKY_BUCKET_TOKEN_MASK                        RTL8367C_METER_CTRL1_MASK
+
+#define    RTL8367C_METER_OVERRATE_INDICATOR_BASE                RTL8367C_REG_METER_OVERRATE_INDICATOR0
+#define    RTL8367C_METER_OVERRATE_INDICATOR_REG(meter)            (RTL8367C_METER_OVERRATE_INDICATOR_BASE + (meter >> 4))
+#define    RTL8367C_METER_EXCEED_OFFSET(meter)                    (meter & 0xF)
+#define    RTL8367C_METER_EXCEED_MASK(meter)                    (1 << RTL8367C_METER_EXCEED_OFFSET(meter))
+
+#define    RTL8367C_METER_IFG_CTRL_BASE                            RTL8367C_REG_METER_IFG_CTRL0
+#define    RTL8367C_METER_IFG_CTRL_REG(meter)                    (RTL8367C_METER_IFG_CTRL_BASE + (meter >> 4))
+#define    RTL8367C_METER_IFG_OFFSET(meter)                        (meter & 0xF)
+#define    RTL8367C_METER_IFG_MASK(meter)                        (1 << RTL8367C_METER_IFG_OFFSET(meter))
+
+#define    RTL8367C_FLOWCTRL_CTRL_REG                            RTL8367C_REG_FLOWCTRL_CTRL0
+
+/* (16'h1800)8051_RLDP_EEE_reg */
+#define    RTL8367C_EEELLDP_CTRL0_REG                            RTL8367C_REG_EEELLDP_CTRL0
+
+#define    RTL8367C_EEELLDP_CTRL1_REG                            RTL8367C_REG_EEELLDP_CTRL1
+
+#define    RTL8367C_EEELLDP_PMSK_REG                            RTL8367C_REG_EEELLDP_PMSK
+
+#define    RTL8367C_EEELLDP_TX_FRAMEU_REG_BASE                    RTL8367C_REG_EEELLDP_FRAMEU00
+
+#define    RTL8367C_EEELLDP_TX_CAP_FRAMEL_REG_BASE                RTL8367C_REG_EEELLDP_CAP_FRAMEL00
+
+#define    RTL8367C_EEELLDP_RX_VALUE_PORT_BASE                    RTL8367C_REG_EEELLDP_RX_VALUE_P00_00
+#define    RTL8367C_EEELLDP_RX_VALUE_PORT_REG(port)                (RTL8367C_EEELLDP_RX_VALUE_PORT_BASE + (port * 9))
+
+#define    RTL8367C_RLDP_CTRL0_REG                                RTL8367C_REG_RLDP_CTRL0
+#define    RTL8367C_RLDP_MODE_OFFSET    14
+
+#define    RTL8367C_RLDP_RETRY_COUNT_REG                        RTL8367C_REG_RLDP_CTRL1
+
+#define    RTL8367C_RLDP_RETRY_PERIOD_LOOPSTATE_REG                RTL8367C_REG_RLDP_CTRL2
+
+#define    RTL8367C_RLDP_RETRY_PERIOD_CHKSTATE_REG                RTL8367C_REG_RLDP_CTRL3
+
+#define    RTL8367C_RLDP_TX_PMSK_REG                            RTL8367C_REG_RLDP_CTRL4
+
+#define    RTL8367C_RLDP_RAND_NUM_REG_BASE                        RTL8367C_REG_RLDP_RAND_NUM0
+
+#define    RTL8367C_RLDP_MAGIC_NUM_REG_BASE                        RTL8367C_REG_RLDP_MAGIC_NUM0
+
+#define    RTL8367C_RLDP_LOOP_PMSK_REG                            RTL8367C_REG_RLDP_LOOPSTATUS_INDICATOR
+
+#define    RTL8367C_RLDP_LOOP_PORT_BASE                            RTL8367C_REG_RLDP_LOOP_PORT_REG0
+#define    RTL8367C_RLDP_LOOP_PORT_REG(port)                    (RTL8367C_RLDP_LOOP_PORT_BASE + (port >> 1))
+#define    RTL8367C_RLDP_LOOP_PORT_OFFSET(port)                    ((port & 0x1) << 3)
+#define    RTL8367C_RLDP_LOOP_PORT_MASK(port)                    (RTL8367C_RLDP_LOOP_PORT_00_MASK << RTL8367C_RLDP_LOOP_PORT_OFFSET(port))
+
+#define    RTL8367C_PAGEMETER_PORT_BASE                            RTL8367C_REG_PAGEMETER_PORT0_CTRL0
+#define    RTL8367C_PAGEMETER_PORT_REG(port)                    (RTL8367C_PAGEMETER_PORT_BASE + 0x20*port)
+
+#define    RTL8367C_HIGHPRI_INDICATOR_REG                        RTL8367C_REG_HIGHPRI_INDICATOR
+#define    RTL8367C_PORT_INDICATOR_OFFSET(port)                    (port)
+#define    RTL8367C_PORT_INDICATOR_MASK(port)                    (RTL8367C_PORT0_INDICATOR_MASK << RTL8367C_PORT_INDICATOR_OFFSET(port))
+
+#define    RTL8367C_HIGHPRI_CFG_REG                                RTL8367C_REG_HIGHPRI_CFG
+
+#define    RTL8367C_EAV_PRIORITY_REMAPPING_BASE                    RTL8367C_REG_EAV_CTRL1
+#define    RTL8367C_EAV_PRIORITY_REMAPPING_REG(pri)                (RTL8367C_EAV_PRIORITY_REMAPPING_BASE + (pri >> 2))
+#define    RTL8367C_EAV_PRIORITY_REMAPPING_OFFSET(pri)            ((pri & 0x3) * RTL8367C_REMAP_EAV_PRI1_REGEN_OFFSET)
+#define    RTL8367C_EAV_PRIORITY_REMAPPING_MASK(pri)            (RTL8367C_REMAP_EAV_PRI0_REGEN_MASK << RTL8367C_EAV_PRIORITY_REMAPPING_OFFSET(pri))
+
+#define    RTL8367C_EEEP_CFG_BASE                                RTL8367C_REG_PORT0_EEECFG
+#define    RTL8367C_EEEP_CFG_REG(port)                            (RTL8367C_EEEP_CFG_BASE + (port*0x20))
+
+#define    RTL8367C_PKG_CFG_BASE                                RTL8367C_REG_PKTGEN_PORT0_CTRL
+#define    RTL8367C_PKG_CFG_REG(port)                            (RTL8367C_PKG_CFG_BASE + (port*0x20))
+
+#define    RTL8367C_PKG_DA_BASE                                    RTL8367C_REG_PKTGEN_PORT0_DA0
+#define    RTL8367C_PKG_DA_REG(port)                            (RTL8367C_PKG_DA_BASE + (port*0x20))
+
+#define    RTL8367C_PKG_SA_BASE                                    RTL8367C_REG_PKTGEN_PORT0_SA0
+#define    RTL8367C_PKG_SA_REG(port)                            (RTL8367C_PKG_SA_BASE + (port*0x20))
+
+#define    RTL8367C_PKG_NUM_BASE                                RTL8367C_REG_PKTGEN_PORT0_COUNTER0
+#define    RTL8367C_PKG_NUM_REG(port)                            (RTL8367C_PKG_NUM_BASE + (port*0x20))
+
+#define    RTL8367C_PKG_LENGTH_BASE                                RTL8367C_REG_PKTGEN_PORT0_TX_LENGTH
+#define    RTL8367C_PKG_LENGTH_REG(port)                        (RTL8367C_PKG_LENGTH_BASE + (port*0x20))
+
+/* (16'h1c00)IGMP_MLD_reg */
+#define    RTL8367C_IGMP_GROUP_USAGE_BASE                       RTL8367C_REG_IGMP_GROUP_USAGE_LIST0
+#define    RTL8367C_IGMP_GROUP_USAGE_REG(idx)                   (RTL8367C_IGMP_GROUP_USAGE_BASE + (idx / 16))
+
+#define    RTL8367C_FALLBACK_BASE                               RTL8367C_REG_FALLBACK_PORT0_CFG0
+#define    RTL8367C_FALLBACK_PORT_CFG_REG(port)                 (RTL8367C_FALLBACK_BASE + (port * 4))
+#define    RTL8367C_FALLBACK_PORT_MON_CNT_REG(port)             (RTL8367C_FALLBACK_BASE + 1 + (port * 4))
+#define    RTL8367C_FALLBACK_PORT_ERR_CNT_REG(port)             (RTL8367C_FALLBACK_BASE + 3 + (port * 4))
+
+
+/* (16'h6400)timer_1588 */
+#define    RTL8367C_EAV_CFG_BASE                                              RTL8367C_REG_P0_EAV_CFG
+#define    RTL8367C_EAV_PORT_CFG_REG(port)                              (RTL8367C_EAV_CFG_BASE + (port *0x10))
+#define    RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET                 RTL8367C_P0_EAV_CFG_PTP_PHY_EN_EN_OFFSET
+#define    RTL8367C_EAV_CFG_RX_PDELAY_RESP_OFFSET                RTL8367C_P0_EAV_CFG_RX_PDELAY_RESP_OFFSET
+#define    RTL8367C_EAV_CFG_RX_PDELAY_REQ_OFFSET                 RTL8367C_P0_EAV_CFG_RX_PDELAY_REQ_OFFSET
+#define    RTL8367C_EAV_CFG_RX_DELAY_REQ_OFFSET                   RTL8367C_P0_EAV_CFG_RX_DELAY_REQ_OFFSET
+#define    RTL8367C_EAV_CFG_RX_SYNC_OFFSET                            RTL8367C_P0_EAV_CFG_RX_SYNC_OFFSET
+#define    RTL8367C_EAV_CFG_TX_PDELAY_RESP_OFFSET                RTL8367C_P0_EAV_CFG_TX_PDELAY_RESP_OFFSET
+#define    RTL8367C_EAV_CFG_TX_PDELAY_REQ_OFFSET                 RTL8367C_P0_EAV_CFG_TX_PDELAY_REQ_OFFSET
+#define    RTL8367C_EAV_CFG_TX_DELAY_REQ_OFFSET                   RTL8367C_P0_EAV_CFG_TX_DELAY_REQ_OFFSET
+#define    RTL8367C_EAV_CFG_TX_SYNC_OFFSET                            RTL8367C_P0_EAV_CFG_TX_SYNC_OFFSET
+
+#define    RTL8367C_REG_TX_SYNC_SEQ_ID_BASE                       RTL8367C_REG_P0_TX_SYNC_SEQ_ID
+#define    RTL8367C_REG_TX_SYNC_SEQ_ID(port)                        (RTL8367C_REG_TX_SYNC_SEQ_ID_BASE + (port *0x10))
+#define    RTL8367C_REG_SEQ_ID(port, type)                              (RTL8367C_REG_TX_SYNC_SEQ_ID_BASE + type + (port *0x10))
+
+#define    RTL8367C_REG_TX_DELAY_REQ_SEQ_ID_BASE              RTL8367C_REG_P0_TX_DELAY_REQ_SEQ_ID
+#define    RTL8367C_REG_TX_PDELAY_REQ_SEQ_ID_BASE          RTL8367C_REG_P0_TX_PDELAY_REQ_SEQ_ID
+#define    RTL8367C_REG_TX_PDELAY_RESP_SEQ_ID_BASE        RTL8367C_REG_P0_TX_PDELAY_RESP_SEQ_ID
+#define    RTL8367C_REG_RX_SYNC_SEQ_ID_BASE                        RTL8367C_REG_P0_RX_SYNC_SEQ_ID
+#define    RTL8367C_REG_RX_DELAY_REQ_SEQ_ID_BASE            RTL8367C_REG_P0_RX_DELAY_REQ_SEQ_ID
+#define    RTL8367C_REG_RX_PDELAY_REQ_SEQ_ID_BASE        RTL8367C_REG_P0_RX_PDELAY_REQ_SEQ_ID
+#define    RTL8367C_REG_RX_PDELAY_RESP_SEQ_ID_BASE        RTL8367C_REG_P0_RX_PDELAY_RESP_SEQ_ID
+
+#define    RTL8367C_REG_PORT_NSEC_L_BASE                            RTL8367C_REG_P0_PORT_NSEC_15_0
+#define    RTL8367C_REG_PORT_NSEC_L(port)                            (RTL8367C_REG_PORT_NSEC_L_BASE + (port *0x10))
+#define    RTL8367C_REG_PORT_NSEC_H_BASE                            RTL8367C_REG_P0_PORT_NSEC_26_16
+#define    RTL8367C_REG_PORT_NSEC_H(port)                            (RTL8367C_REG_PORT_NSEC_H_BASE + (port *0x10))
+#define    RTL8367C_PORT_NSEC_H_OFFSET                                RTL8367C_P0_PORT_NSEC_26_16_OFFSET
+#define    RTL8367C_PORT_NSEC_H_MASK                                   RTL8367C_P0_PORT_NSEC_26_16_MASK
+
+#define    RTL8367C_REG_PORT_SEC_L_BASE                                RTL8367C_REG_P0_PORT_SEC_15_0
+#define    RTL8367C_REG_PORT_SEC_L(port)                            (RTL8367C_REG_PORT_SEC_L_BASE + (port *0x10))
+#define    RTL8367C_REG_PORT_SEC_H_BASE                            RTL8367C_REG_P0_PORT_SEC_31_16
+#define    RTL8367C_REG_PORT_SEC_H(port)                            (RTL8367C_REG_PORT_SEC_H_BASE + (port *0x10))
+
+#endif /*#ifndef _RTL8367C_BASE_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_reg.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_reg.h
new file mode 100644
index 0000000..eb4f48b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_reg.h
@@ -0,0 +1,22819 @@
+#ifndef _RTL8367C_REG_H_
+#define _RTL8367C_REG_H_
+
+/************************************************************
+auto-generated register address and field data
+*************************************************************/
+
+/* (16'h0000)port_reg */
+
+#define    RTL8367C_REG_PORT0_CGST_HALF_CFG    0x0000
+#define    RTL8367C_PORT0_CGST_HALF_CFG_CONGESTION_TIME_OFFSET    4
+#define    RTL8367C_PORT0_CGST_HALF_CFG_CONGESTION_TIME_MASK    0xF0
+#define    RTL8367C_PORT0_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT0_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_PKTGEN_PORT0_CTRL    0x0001
+#define    RTL8367C_PKTGEN_PORT0_CTRL_STATUS_OFFSET    15
+#define    RTL8367C_PKTGEN_PORT0_CTRL_STATUS_MASK    0x8000
+#define    RTL8367C_PKTGEN_PORT0_CTRL_PKTGEN_STS_OFFSET    13
+#define    RTL8367C_PKTGEN_PORT0_CTRL_PKTGEN_STS_MASK    0x2000
+#define    RTL8367C_PKTGEN_PORT0_CTRL_CRC_NO_ERROR_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT0_CTRL_CRC_NO_ERROR_MASK    0x10
+#define    RTL8367C_PKTGEN_PORT0_CTRL_CMD_START_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT0_CTRL_CMD_START_MASK    0x1
+
+#define    RTL8367C_REG_TX_ERR_CNT_PORT0    0x0002
+#define    RTL8367C_TX_ERR_CNT_PORT0_OFFSET    0
+#define    RTL8367C_TX_ERR_CNT_PORT0_MASK    0x7
+
+#define    RTL8367C_REG_PKTGEN_PORT0_DA0    0x0003
+
+#define    RTL8367C_REG_PKTGEN_PORT0_DA1    0x0004
+
+#define    RTL8367C_REG_PKTGEN_PORT0_DA2    0x0005
+
+#define    RTL8367C_REG_PKTGEN_PORT0_SA0    0x0006
+
+#define    RTL8367C_REG_PKTGEN_PORT0_SA1    0x0007
+
+#define    RTL8367C_REG_PKTGEN_PORT0_SA2    0x0008
+
+#define    RTL8367C_REG_PKTGEN_PORT0_COUNTER0    0x0009
+
+#define    RTL8367C_REG_PKTGEN_PORT0_COUNTER1    0x000a
+#define    RTL8367C_PKTGEN_PORT0_COUNTER1_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT0_COUNTER1_MASK    0xFF
+
+#define    RTL8367C_REG_PKTGEN_PORT0_TX_LENGTH    0x000b
+#define    RTL8367C_PKTGEN_PORT0_TX_LENGTH_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT0_TX_LENGTH_MASK    0x3FFF
+
+#define    RTL8367C_REG_PKTGEN_PORT0_TIMER    0x000d
+#define    RTL8367C_PKTGEN_PORT0_TIMER_TIMER_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT0_TIMER_TIMER_MASK    0xF0
+#define    RTL8367C_PKTGEN_PORT0_TIMER_RX_DMA_ERR_FLAG_OFFSET    3
+#define    RTL8367C_PKTGEN_PORT0_TIMER_RX_DMA_ERR_FLAG_MASK    0x8
+
+#define    RTL8367C_REG_PORT0_MISC_CFG    0x000e
+#define    RTL8367C_PORT0_MISC_CFG_SMALL_TAG_IPG_OFFSET    15
+#define    RTL8367C_PORT0_MISC_CFG_SMALL_TAG_IPG_MASK    0x8000
+#define    RTL8367C_PORT0_MISC_CFG_TX_ITFSP_MODE_OFFSET    14
+#define    RTL8367C_PORT0_MISC_CFG_TX_ITFSP_MODE_MASK    0x4000
+#define    RTL8367C_PORT0_MISC_CFG_FLOWCTRL_INDEP_OFFSET    13
+#define    RTL8367C_PORT0_MISC_CFG_FLOWCTRL_INDEP_MASK    0x2000
+#define    RTL8367C_PORT0_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET    12
+#define    RTL8367C_PORT0_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK    0x1000
+#define    RTL8367C_PORT0_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET    11
+#define    RTL8367C_PORT0_MISC_CFG_INGRESSBW_FLOWCTRL_MASK    0x800
+#define    RTL8367C_PORT0_MISC_CFG_INGRESSBW_IFG_OFFSET    10
+#define    RTL8367C_PORT0_MISC_CFG_INGRESSBW_IFG_MASK    0x400
+#define    RTL8367C_PORT0_MISC_CFG_RX_SPC_OFFSET    9
+#define    RTL8367C_PORT0_MISC_CFG_RX_SPC_MASK    0x200
+#define    RTL8367C_PORT0_MISC_CFG_CRC_SKIP_OFFSET    8
+#define    RTL8367C_PORT0_MISC_CFG_CRC_SKIP_MASK    0x100
+#define    RTL8367C_PORT0_MISC_CFG_PKTGEN_TX_FIRST_OFFSET    7
+#define    RTL8367C_PORT0_MISC_CFG_PKTGEN_TX_FIRST_MASK    0x80
+#define    RTL8367C_PORT0_MISC_CFG_MAC_LOOPBACK_OFFSET    6
+#define    RTL8367C_PORT0_MISC_CFG_MAC_LOOPBACK_MASK    0x40
+#define    RTL8367C_PORT0_MISC_CFG_VLAN_EGRESS_MODE_OFFSET    4
+#define    RTL8367C_PORT0_MISC_CFG_VLAN_EGRESS_MODE_MASK    0x30
+#define    RTL8367C_PORT0_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT0_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_INGRESSBW_PORT0_RATE_CTRL0    0x000f
+
+#define    RTL8367C_REG_INGRESSBW_PORT0_RATE_CTRL1    0x0010
+#define    RTL8367C_INGRESSBW_PORT0_RATE_CTRL1_DUMMY_OFFSET    3
+#define    RTL8367C_INGRESSBW_PORT0_RATE_CTRL1_DUMMY_MASK    0xFFF8
+#define    RTL8367C_INGRESSBW_PORT0_RATE_CTRL1_INGRESSBW_RATE16_OFFSET    0
+#define    RTL8367C_INGRESSBW_PORT0_RATE_CTRL1_INGRESSBW_RATE16_MASK    0x7
+
+#define    RTL8367C_REG_PORT0_FORCE_RATE0    0x0011
+
+#define    RTL8367C_REG_PORT0_FORCE_RATE1    0x0012
+
+#define    RTL8367C_REG_PORT0_CURENT_RATE0    0x0013
+
+#define    RTL8367C_REG_PORT0_CURENT_RATE1    0x0014
+
+#define    RTL8367C_REG_PORT0_PAGE_COUNTER    0x0015
+#define    RTL8367C_PORT0_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_PORT0_PAGE_COUNTER_MASK    0x7F
+
+#define    RTL8367C_REG_PAGEMETER_PORT0_CTRL0    0x0016
+
+#define    RTL8367C_REG_PAGEMETER_PORT0_CTRL1    0x0017
+
+#define    RTL8367C_REG_PORT0_EEECFG    0x0018
+#define    RTL8367C_PORT0_EEECFG_EEEP_ENABLE_TX_OFFSET    14
+#define    RTL8367C_PORT0_EEECFG_EEEP_ENABLE_TX_MASK    0x4000
+#define    RTL8367C_PORT0_EEECFG_EEEP_ENABLE_RX_OFFSET    13
+#define    RTL8367C_PORT0_EEECFG_EEEP_ENABLE_RX_MASK    0x2000
+#define    RTL8367C_PORT0_EEECFG_EEE_FORCE_OFFSET    12
+#define    RTL8367C_PORT0_EEECFG_EEE_FORCE_MASK    0x1000
+#define    RTL8367C_PORT0_EEECFG_EEE_100M_OFFSET    11
+#define    RTL8367C_PORT0_EEECFG_EEE_100M_MASK    0x800
+#define    RTL8367C_PORT0_EEECFG_EEE_GIGA_500M_OFFSET    10
+#define    RTL8367C_PORT0_EEECFG_EEE_GIGA_500M_MASK    0x400
+#define    RTL8367C_PORT0_EEECFG_EEE_TX_OFFSET    9
+#define    RTL8367C_PORT0_EEECFG_EEE_TX_MASK    0x200
+#define    RTL8367C_PORT0_EEECFG_EEE_RX_OFFSET    8
+#define    RTL8367C_PORT0_EEECFG_EEE_RX_MASK    0x100
+#define    RTL8367C_PORT0_EEECFG_EEE_DSP_RX_OFFSET    6
+#define    RTL8367C_PORT0_EEECFG_EEE_DSP_RX_MASK    0x40
+#define    RTL8367C_PORT0_EEECFG_EEE_LPI_OFFSET    5
+#define    RTL8367C_PORT0_EEECFG_EEE_LPI_MASK    0x20
+#define    RTL8367C_PORT0_EEECFG_EEE_TX_LPI_OFFSET    4
+#define    RTL8367C_PORT0_EEECFG_EEE_TX_LPI_MASK    0x10
+#define    RTL8367C_PORT0_EEECFG_EEE_RX_LPI_OFFSET    3
+#define    RTL8367C_PORT0_EEECFG_EEE_RX_LPI_MASK    0x8
+#define    RTL8367C_PORT0_EEECFG_EEE_PAUSE_INDICATOR_OFFSET    2
+#define    RTL8367C_PORT0_EEECFG_EEE_PAUSE_INDICATOR_MASK    0x4
+#define    RTL8367C_PORT0_EEECFG_EEE_WAKE_REQ_OFFSET    1
+#define    RTL8367C_PORT0_EEECFG_EEE_WAKE_REQ_MASK    0x2
+#define    RTL8367C_PORT0_EEECFG_EEE_SLEEP_REQ_OFFSET    0
+#define    RTL8367C_PORT0_EEECFG_EEE_SLEEP_REQ_MASK    0x1
+
+#define    RTL8367C_REG_PORT0_EEETXMTR    0x0019
+
+#define    RTL8367C_REG_PORT0_EEERXMTR    0x001a
+
+#define    RTL8367C_REG_PORT0_EEEPTXMTR    0x001b
+
+#define    RTL8367C_REG_PORT0_EEEPRXMTR    0x001c
+
+#define    RTL8367C_REG_PTP_PORT0_CFG1    0x001e
+#define    RTL8367C_PTP_PORT0_CFG1_OFFSET    7
+#define    RTL8367C_PTP_PORT0_CFG1_MASK    0xFF
+
+#define    RTL8367C_REG_P0_MSIC1    0x001f
+#define    RTL8367C_P0_MSIC1_OFFSET    0
+#define    RTL8367C_P0_MSIC1_MASK    0x1
+
+#define    RTL8367C_REG_PORT1_CGST_HALF_CFG    0x0020
+#define    RTL8367C_PORT1_CGST_HALF_CFG_CONGESTION_TIME_OFFSET    4
+#define    RTL8367C_PORT1_CGST_HALF_CFG_CONGESTION_TIME_MASK    0xF0
+#define    RTL8367C_PORT1_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT1_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_PKTGEN_PORT1_CTRL    0x0021
+#define    RTL8367C_PKTGEN_PORT1_CTRL_STATUS_OFFSET    15
+#define    RTL8367C_PKTGEN_PORT1_CTRL_STATUS_MASK    0x8000
+#define    RTL8367C_PKTGEN_PORT1_CTRL_PKTGEN_STS_OFFSET    13
+#define    RTL8367C_PKTGEN_PORT1_CTRL_PKTGEN_STS_MASK    0x2000
+#define    RTL8367C_PKTGEN_PORT1_CTRL_CRC_NO_ERROR_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT1_CTRL_CRC_NO_ERROR_MASK    0x10
+#define    RTL8367C_PKTGEN_PORT1_CTRL_CMD_START_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT1_CTRL_CMD_START_MASK    0x1
+
+#define    RTL8367C_REG_TX_ERR_CNT_PORT1    0x0022
+#define    RTL8367C_TX_ERR_CNT_PORT1_OFFSET    0
+#define    RTL8367C_TX_ERR_CNT_PORT1_MASK    0x7
+
+#define    RTL8367C_REG_PKTGEN_PORT1_DA0    0x0023
+
+#define    RTL8367C_REG_PKTGEN_PORT1_DA1    0x0024
+
+#define    RTL8367C_REG_PKTGEN_PORT1_DA2    0x0025
+
+#define    RTL8367C_REG_PKTGEN_PORT1_SA0    0x0026
+
+#define    RTL8367C_REG_PKTGEN_PORT1_SA1    0x0027
+
+#define    RTL8367C_REG_PKTGEN_PORT1_SA2    0x0028
+
+#define    RTL8367C_REG_PKTGEN_PORT1_COUNTER0    0x0029
+
+#define    RTL8367C_REG_PKTGEN_PORT1_COUNTER1    0x002a
+#define    RTL8367C_PKTGEN_PORT1_COUNTER1_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT1_COUNTER1_MASK    0xFF
+
+#define    RTL8367C_REG_PKTGEN_PORT1_TX_LENGTH    0x002b
+#define    RTL8367C_PKTGEN_PORT1_TX_LENGTH_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT1_TX_LENGTH_MASK    0x3FFF
+
+#define    RTL8367C_REG_PKTGEN_PORT1_TIMER    0x002d
+#define    RTL8367C_PKTGEN_PORT1_TIMER_TIMER_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT1_TIMER_TIMER_MASK    0xF0
+#define    RTL8367C_PKTGEN_PORT1_TIMER_RX_DMA_ERR_FLAG_OFFSET    3
+#define    RTL8367C_PKTGEN_PORT1_TIMER_RX_DMA_ERR_FLAG_MASK    0x8
+
+#define    RTL8367C_REG_PORT1_MISC_CFG    0x002e
+#define    RTL8367C_PORT1_MISC_CFG_SMALL_TAG_IPG_OFFSET    15
+#define    RTL8367C_PORT1_MISC_CFG_SMALL_TAG_IPG_MASK    0x8000
+#define    RTL8367C_PORT1_MISC_CFG_TX_ITFSP_MODE_OFFSET    14
+#define    RTL8367C_PORT1_MISC_CFG_TX_ITFSP_MODE_MASK    0x4000
+#define    RTL8367C_PORT1_MISC_CFG_FLOWCTRL_INDEP_OFFSET    13
+#define    RTL8367C_PORT1_MISC_CFG_FLOWCTRL_INDEP_MASK    0x2000
+#define    RTL8367C_PORT1_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET    12
+#define    RTL8367C_PORT1_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK    0x1000
+#define    RTL8367C_PORT1_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET    11
+#define    RTL8367C_PORT1_MISC_CFG_INGRESSBW_FLOWCTRL_MASK    0x800
+#define    RTL8367C_PORT1_MISC_CFG_INGRESSBW_IFG_OFFSET    10
+#define    RTL8367C_PORT1_MISC_CFG_INGRESSBW_IFG_MASK    0x400
+#define    RTL8367C_PORT1_MISC_CFG_RX_SPC_OFFSET    9
+#define    RTL8367C_PORT1_MISC_CFG_RX_SPC_MASK    0x200
+#define    RTL8367C_PORT1_MISC_CFG_CRC_SKIP_OFFSET    8
+#define    RTL8367C_PORT1_MISC_CFG_CRC_SKIP_MASK    0x100
+#define    RTL8367C_PORT1_MISC_CFG_PKTGEN_TX_FIRST_OFFSET    7
+#define    RTL8367C_PORT1_MISC_CFG_PKTGEN_TX_FIRST_MASK    0x80
+#define    RTL8367C_PORT1_MISC_CFG_MAC_LOOPBACK_OFFSET    6
+#define    RTL8367C_PORT1_MISC_CFG_MAC_LOOPBACK_MASK    0x40
+#define    RTL8367C_PORT1_MISC_CFG_VLAN_EGRESS_MODE_OFFSET    4
+#define    RTL8367C_PORT1_MISC_CFG_VLAN_EGRESS_MODE_MASK    0x30
+#define    RTL8367C_PORT1_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT1_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_INGRESSBW_PORT1_RATE_CTRL0    0x002f
+
+#define    RTL8367C_REG_INGRESSBW_PORT1_RATE_CTRL1    0x0030
+#define    RTL8367C_INGRESSBW_PORT1_RATE_CTRL1_DUMMY_OFFSET    3
+#define    RTL8367C_INGRESSBW_PORT1_RATE_CTRL1_DUMMY_MASK    0xFFF8
+#define    RTL8367C_INGRESSBW_PORT1_RATE_CTRL1_INGRESSBW_RATE16_OFFSET    0
+#define    RTL8367C_INGRESSBW_PORT1_RATE_CTRL1_INGRESSBW_RATE16_MASK    0x7
+
+#define    RTL8367C_REG_PORT1_FORCE_RATE0    0x0031
+
+#define    RTL8367C_REG_PORT1_FORCE_RATE1    0x0032
+
+#define    RTL8367C_REG_PORT1_CURENT_RATE0    0x0033
+
+#define    RTL8367C_REG_PORT1_CURENT_RATE1    0x0034
+
+#define    RTL8367C_REG_PORT1_PAGE_COUNTER    0x0035
+#define    RTL8367C_PORT1_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_PORT1_PAGE_COUNTER_MASK    0x7F
+
+#define    RTL8367C_REG_PAGEMETER_PORT1_CTRL0    0x0036
+
+#define    RTL8367C_REG_PAGEMETER_PORT1_CTRL1    0x0037
+
+#define    RTL8367C_REG_PORT1_EEECFG    0x0038
+#define    RTL8367C_PORT1_EEECFG_EEEP_ENABLE_TX_OFFSET    14
+#define    RTL8367C_PORT1_EEECFG_EEEP_ENABLE_TX_MASK    0x4000
+#define    RTL8367C_PORT1_EEECFG_EEEP_ENABLE_RX_OFFSET    13
+#define    RTL8367C_PORT1_EEECFG_EEEP_ENABLE_RX_MASK    0x2000
+#define    RTL8367C_PORT1_EEECFG_EEE_FORCE_OFFSET    12
+#define    RTL8367C_PORT1_EEECFG_EEE_FORCE_MASK    0x1000
+#define    RTL8367C_PORT1_EEECFG_EEE_100M_OFFSET    11
+#define    RTL8367C_PORT1_EEECFG_EEE_100M_MASK    0x800
+#define    RTL8367C_PORT1_EEECFG_EEE_GIGA_500M_OFFSET    10
+#define    RTL8367C_PORT1_EEECFG_EEE_GIGA_500M_MASK    0x400
+#define    RTL8367C_PORT1_EEECFG_EEE_TX_OFFSET    9
+#define    RTL8367C_PORT1_EEECFG_EEE_TX_MASK    0x200
+#define    RTL8367C_PORT1_EEECFG_EEE_RX_OFFSET    8
+#define    RTL8367C_PORT1_EEECFG_EEE_RX_MASK    0x100
+#define    RTL8367C_PORT1_EEECFG_EEE_DSP_RX_OFFSET    6
+#define    RTL8367C_PORT1_EEECFG_EEE_DSP_RX_MASK    0x40
+#define    RTL8367C_PORT1_EEECFG_EEE_LPI_OFFSET    5
+#define    RTL8367C_PORT1_EEECFG_EEE_LPI_MASK    0x20
+#define    RTL8367C_PORT1_EEECFG_EEE_TX_LPI_OFFSET    4
+#define    RTL8367C_PORT1_EEECFG_EEE_TX_LPI_MASK    0x10
+#define    RTL8367C_PORT1_EEECFG_EEE_RX_LPI_OFFSET    3
+#define    RTL8367C_PORT1_EEECFG_EEE_RX_LPI_MASK    0x8
+#define    RTL8367C_PORT1_EEECFG_EEE_PAUSE_INDICATOR_OFFSET    2
+#define    RTL8367C_PORT1_EEECFG_EEE_PAUSE_INDICATOR_MASK    0x4
+#define    RTL8367C_PORT1_EEECFG_EEE_WAKE_REQ_OFFSET    1
+#define    RTL8367C_PORT1_EEECFG_EEE_WAKE_REQ_MASK    0x2
+#define    RTL8367C_PORT1_EEECFG_EEE_SLEEP_REQ_OFFSET    0
+#define    RTL8367C_PORT1_EEECFG_EEE_SLEEP_REQ_MASK    0x1
+
+#define    RTL8367C_REG_PORT1_EEETXMTR    0x0039
+
+#define    RTL8367C_REG_PORT1_EEERXMTR    0x003a
+
+#define    RTL8367C_REG_PORT1_EEEPTXMTR    0x003b
+
+#define    RTL8367C_REG_PORT1_EEEPRXMTR    0x003c
+
+#define    RTL8367C_REG_PTP_PORT1_CFG1    0x003e
+#define    RTL8367C_PTP_PORT1_CFG1_OFFSET    7
+#define    RTL8367C_PTP_PORT1_CFG1_MASK    0xFF
+
+#define    RTL8367C_REG_P1_MSIC1    0x003f
+#define    RTL8367C_P1_MSIC1_OFFSET    0
+#define    RTL8367C_P1_MSIC1_MASK    0x1
+
+#define    RTL8367C_REG_PORT2_CGST_HALF_CFG    0x0040
+#define    RTL8367C_PORT2_CGST_HALF_CFG_CONGESTION_TIME_OFFSET    4
+#define    RTL8367C_PORT2_CGST_HALF_CFG_CONGESTION_TIME_MASK    0xF0
+#define    RTL8367C_PORT2_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT2_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_PKTGEN_PORT2_CTRL    0x0041
+#define    RTL8367C_PKTGEN_PORT2_CTRL_STATUS_OFFSET    15
+#define    RTL8367C_PKTGEN_PORT2_CTRL_STATUS_MASK    0x8000
+#define    RTL8367C_PKTGEN_PORT2_CTRL_PKTGEN_STS_OFFSET    13
+#define    RTL8367C_PKTGEN_PORT2_CTRL_PKTGEN_STS_MASK    0x2000
+#define    RTL8367C_PKTGEN_PORT2_CTRL_CRC_NO_ERROR_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT2_CTRL_CRC_NO_ERROR_MASK    0x10
+#define    RTL8367C_PKTGEN_PORT2_CTRL_CMD_START_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT2_CTRL_CMD_START_MASK    0x1
+
+#define    RTL8367C_REG_TX_ERR_CNT_PORT2    0x0042
+#define    RTL8367C_TX_ERR_CNT_PORT2_OFFSET    0
+#define    RTL8367C_TX_ERR_CNT_PORT2_MASK    0x7
+
+#define    RTL8367C_REG_PKTGEN_PORT2_DA0    0x0043
+
+#define    RTL8367C_REG_PKTGEN_PORT2_DA1    0x0044
+
+#define    RTL8367C_REG_PKTGEN_PORT2_DA2    0x0045
+
+#define    RTL8367C_REG_PKTGEN_PORT2_SA0    0x0046
+
+#define    RTL8367C_REG_PKTGEN_PORT2_SA1    0x0047
+
+#define    RTL8367C_REG_PKTGEN_PORT2_SA2    0x0048
+
+#define    RTL8367C_REG_PKTGEN_PORT2_COUNTER0    0x0049
+
+#define    RTL8367C_REG_PKTGEN_PORT2_COUNTER1    0x004a
+#define    RTL8367C_PKTGEN_PORT2_COUNTER1_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT2_COUNTER1_MASK    0xFF
+
+#define    RTL8367C_REG_PKTGEN_PORT2_TX_LENGTH    0x004b
+#define    RTL8367C_PKTGEN_PORT2_TX_LENGTH_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT2_TX_LENGTH_MASK    0x3FFF
+
+#define    RTL8367C_REG_PKTGEN_PORT2_TIMER    0x004d
+#define    RTL8367C_PKTGEN_PORT2_TIMER_TIMER_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT2_TIMER_TIMER_MASK    0xF0
+#define    RTL8367C_PKTGEN_PORT2_TIMER_RX_DMA_ERR_FLAG_OFFSET    3
+#define    RTL8367C_PKTGEN_PORT2_TIMER_RX_DMA_ERR_FLAG_MASK    0x8
+
+#define    RTL8367C_REG_PORT2_MISC_CFG    0x004e
+#define    RTL8367C_PORT2_MISC_CFG_SMALL_TAG_IPG_OFFSET    15
+#define    RTL8367C_PORT2_MISC_CFG_SMALL_TAG_IPG_MASK    0x8000
+#define    RTL8367C_PORT2_MISC_CFG_TX_ITFSP_MODE_OFFSET    14
+#define    RTL8367C_PORT2_MISC_CFG_TX_ITFSP_MODE_MASK    0x4000
+#define    RTL8367C_PORT2_MISC_CFG_FLOWCTRL_INDEP_OFFSET    13
+#define    RTL8367C_PORT2_MISC_CFG_FLOWCTRL_INDEP_MASK    0x2000
+#define    RTL8367C_PORT2_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET    12
+#define    RTL8367C_PORT2_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK    0x1000
+#define    RTL8367C_PORT2_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET    11
+#define    RTL8367C_PORT2_MISC_CFG_INGRESSBW_FLOWCTRL_MASK    0x800
+#define    RTL8367C_PORT2_MISC_CFG_INGRESSBW_IFG_OFFSET    10
+#define    RTL8367C_PORT2_MISC_CFG_INGRESSBW_IFG_MASK    0x400
+#define    RTL8367C_PORT2_MISC_CFG_RX_SPC_OFFSET    9
+#define    RTL8367C_PORT2_MISC_CFG_RX_SPC_MASK    0x200
+#define    RTL8367C_PORT2_MISC_CFG_CRC_SKIP_OFFSET    8
+#define    RTL8367C_PORT2_MISC_CFG_CRC_SKIP_MASK    0x100
+#define    RTL8367C_PORT2_MISC_CFG_PKTGEN_TX_FIRST_OFFSET    7
+#define    RTL8367C_PORT2_MISC_CFG_PKTGEN_TX_FIRST_MASK    0x80
+#define    RTL8367C_PORT2_MISC_CFG_MAC_LOOPBACK_OFFSET    6
+#define    RTL8367C_PORT2_MISC_CFG_MAC_LOOPBACK_MASK    0x40
+#define    RTL8367C_PORT2_MISC_CFG_VLAN_EGRESS_MODE_OFFSET    4
+#define    RTL8367C_PORT2_MISC_CFG_VLAN_EGRESS_MODE_MASK    0x30
+#define    RTL8367C_PORT2_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT2_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_INGRESSBW_PORT2_RATE_CTRL0    0x004f
+
+#define    RTL8367C_REG_INGRESSBW_PORT2_RATE_CTRL1    0x0050
+#define    RTL8367C_INGRESSBW_PORT2_RATE_CTRL1_DUMMY_OFFSET    3
+#define    RTL8367C_INGRESSBW_PORT2_RATE_CTRL1_DUMMY_MASK    0xFFF8
+#define    RTL8367C_INGRESSBW_PORT2_RATE_CTRL1_INGRESSBW_RATE16_OFFSET    0
+#define    RTL8367C_INGRESSBW_PORT2_RATE_CTRL1_INGRESSBW_RATE16_MASK    0x7
+
+#define    RTL8367C_REG_PORT2_FORCE_RATE0    0x0051
+
+#define    RTL8367C_REG_PORT2_FORCE_RATE1    0x0052
+
+#define    RTL8367C_REG_PORT2_CURENT_RATE0    0x0053
+
+#define    RTL8367C_REG_PORT2_CURENT_RATE1    0x0054
+
+#define    RTL8367C_REG_PORT2_PAGE_COUNTER    0x0055
+#define    RTL8367C_PORT2_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_PORT2_PAGE_COUNTER_MASK    0x7F
+
+#define    RTL8367C_REG_PAGEMETER_PORT2_CTRL0    0x0056
+
+#define    RTL8367C_REG_PAGEMETER_PORT2_CTRL1    0x0057
+
+#define    RTL8367C_REG_PORT2_EEECFG    0x0058
+#define    RTL8367C_PORT2_EEECFG_EEEP_ENABLE_TX_OFFSET    14
+#define    RTL8367C_PORT2_EEECFG_EEEP_ENABLE_TX_MASK    0x4000
+#define    RTL8367C_PORT2_EEECFG_EEEP_ENABLE_RX_OFFSET    13
+#define    RTL8367C_PORT2_EEECFG_EEEP_ENABLE_RX_MASK    0x2000
+#define    RTL8367C_PORT2_EEECFG_EEE_FORCE_OFFSET    12
+#define    RTL8367C_PORT2_EEECFG_EEE_FORCE_MASK    0x1000
+#define    RTL8367C_PORT2_EEECFG_EEE_100M_OFFSET    11
+#define    RTL8367C_PORT2_EEECFG_EEE_100M_MASK    0x800
+#define    RTL8367C_PORT2_EEECFG_EEE_GIGA_500M_OFFSET    10
+#define    RTL8367C_PORT2_EEECFG_EEE_GIGA_500M_MASK    0x400
+#define    RTL8367C_PORT2_EEECFG_EEE_TX_OFFSET    9
+#define    RTL8367C_PORT2_EEECFG_EEE_TX_MASK    0x200
+#define    RTL8367C_PORT2_EEECFG_EEE_RX_OFFSET    8
+#define    RTL8367C_PORT2_EEECFG_EEE_RX_MASK    0x100
+#define    RTL8367C_PORT2_EEECFG_EEE_DSP_RX_OFFSET    6
+#define    RTL8367C_PORT2_EEECFG_EEE_DSP_RX_MASK    0x40
+#define    RTL8367C_PORT2_EEECFG_EEE_LPI_OFFSET    5
+#define    RTL8367C_PORT2_EEECFG_EEE_LPI_MASK    0x20
+#define    RTL8367C_PORT2_EEECFG_EEE_TX_LPI_OFFSET    4
+#define    RTL8367C_PORT2_EEECFG_EEE_TX_LPI_MASK    0x10
+#define    RTL8367C_PORT2_EEECFG_EEE_RX_LPI_OFFSET    3
+#define    RTL8367C_PORT2_EEECFG_EEE_RX_LPI_MASK    0x8
+#define    RTL8367C_PORT2_EEECFG_EEE_PAUSE_INDICATOR_OFFSET    2
+#define    RTL8367C_PORT2_EEECFG_EEE_PAUSE_INDICATOR_MASK    0x4
+#define    RTL8367C_PORT2_EEECFG_EEE_WAKE_REQ_OFFSET    1
+#define    RTL8367C_PORT2_EEECFG_EEE_WAKE_REQ_MASK    0x2
+#define    RTL8367C_PORT2_EEECFG_EEE_SLEEP_REQ_OFFSET    0
+#define    RTL8367C_PORT2_EEECFG_EEE_SLEEP_REQ_MASK    0x1
+
+#define    RTL8367C_REG_PORT2_EEETXMTR    0x0059
+
+#define    RTL8367C_REG_PORT2_EEERXMTR    0x005a
+
+#define    RTL8367C_REG_PORT2_EEEPTXMTR    0x005b
+
+#define    RTL8367C_REG_PORT2_EEEPRXMTR    0x005c
+
+#define    RTL8367C_REG_PTP_PORT2_CFG1    0x005e
+#define    RTL8367C_PTP_PORT2_CFG1_OFFSET    7
+#define    RTL8367C_PTP_PORT2_CFG1_MASK    0xFF
+
+#define    RTL8367C_REG_P2_MSIC1    0x005f
+#define    RTL8367C_P2_MSIC1_OFFSET    0
+#define    RTL8367C_P2_MSIC1_MASK    0x1
+
+#define    RTL8367C_REG_PORT3_CGST_HALF_CFG    0x0060
+#define    RTL8367C_PORT3_CGST_HALF_CFG_CONGESTION_TIME_OFFSET    4
+#define    RTL8367C_PORT3_CGST_HALF_CFG_CONGESTION_TIME_MASK    0xF0
+#define    RTL8367C_PORT3_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT3_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_PKTGEN_PORT3_CTRL    0x0061
+#define    RTL8367C_PKTGEN_PORT3_CTRL_STATUS_OFFSET    15
+#define    RTL8367C_PKTGEN_PORT3_CTRL_STATUS_MASK    0x8000
+#define    RTL8367C_PKTGEN_PORT3_CTRL_PKTGEN_STS_OFFSET    13
+#define    RTL8367C_PKTGEN_PORT3_CTRL_PKTGEN_STS_MASK    0x2000
+#define    RTL8367C_PKTGEN_PORT3_CTRL_CRC_NO_ERROR_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT3_CTRL_CRC_NO_ERROR_MASK    0x10
+#define    RTL8367C_PKTGEN_PORT3_CTRL_CMD_START_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT3_CTRL_CMD_START_MASK    0x1
+
+#define    RTL8367C_REG_TX_ERR_CNT_PORT3    0x0062
+#define    RTL8367C_TX_ERR_CNT_PORT3_OFFSET    0
+#define    RTL8367C_TX_ERR_CNT_PORT3_MASK    0x7
+
+#define    RTL8367C_REG_PKTGEN_PORT3_DA0    0x0063
+
+#define    RTL8367C_REG_PKTGEN_PORT3_DA1    0x0064
+
+#define    RTL8367C_REG_PKTGEN_PORT3_DA2    0x0065
+
+#define    RTL8367C_REG_PKTGEN_PORT3_SA0    0x0066
+
+#define    RTL8367C_REG_PKTGEN_PORT3_SA1    0x0067
+
+#define    RTL8367C_REG_PKTGEN_PORT3_SA2    0x0068
+
+#define    RTL8367C_REG_PKTGEN_PORT3_COUNTER0    0x0069
+
+#define    RTL8367C_REG_PKTGEN_PORT3_COUNTER1    0x006a
+#define    RTL8367C_PKTGEN_PORT3_COUNTER1_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT3_COUNTER1_MASK    0xFF
+
+#define    RTL8367C_REG_PKTGEN_PORT3_TX_LENGTH    0x006b
+#define    RTL8367C_PKTGEN_PORT3_TX_LENGTH_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT3_TX_LENGTH_MASK    0x3FFF
+
+#define    RTL8367C_REG_PKTGEN_PORT3_TIMER    0x006d
+#define    RTL8367C_PKTGEN_PORT3_TIMER_TIMER_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT3_TIMER_TIMER_MASK    0xF0
+#define    RTL8367C_PKTGEN_PORT3_TIMER_RX_DMA_ERR_FLAG_OFFSET    3
+#define    RTL8367C_PKTGEN_PORT3_TIMER_RX_DMA_ERR_FLAG_MASK    0x8
+
+#define    RTL8367C_REG_PORT3_MISC_CFG    0x006e
+#define    RTL8367C_PORT3_MISC_CFG_SMALL_TAG_IPG_OFFSET    15
+#define    RTL8367C_PORT3_MISC_CFG_SMALL_TAG_IPG_MASK    0x8000
+#define    RTL8367C_PORT3_MISC_CFG_TX_ITFSP_MODE_OFFSET    14
+#define    RTL8367C_PORT3_MISC_CFG_TX_ITFSP_MODE_MASK    0x4000
+#define    RTL8367C_PORT3_MISC_CFG_FLOWCTRL_INDEP_OFFSET    13
+#define    RTL8367C_PORT3_MISC_CFG_FLOWCTRL_INDEP_MASK    0x2000
+#define    RTL8367C_PORT3_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET    12
+#define    RTL8367C_PORT3_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK    0x1000
+#define    RTL8367C_PORT3_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET    11
+#define    RTL8367C_PORT3_MISC_CFG_INGRESSBW_FLOWCTRL_MASK    0x800
+#define    RTL8367C_PORT3_MISC_CFG_INGRESSBW_IFG_OFFSET    10
+#define    RTL8367C_PORT3_MISC_CFG_INGRESSBW_IFG_MASK    0x400
+#define    RTL8367C_PORT3_MISC_CFG_RX_SPC_OFFSET    9
+#define    RTL8367C_PORT3_MISC_CFG_RX_SPC_MASK    0x200
+#define    RTL8367C_PORT3_MISC_CFG_CRC_SKIP_OFFSET    8
+#define    RTL8367C_PORT3_MISC_CFG_CRC_SKIP_MASK    0x100
+#define    RTL8367C_PORT3_MISC_CFG_PKTGEN_TX_FIRST_OFFSET    7
+#define    RTL8367C_PORT3_MISC_CFG_PKTGEN_TX_FIRST_MASK    0x80
+#define    RTL8367C_PORT3_MISC_CFG_MAC_LOOPBACK_OFFSET    6
+#define    RTL8367C_PORT3_MISC_CFG_MAC_LOOPBACK_MASK    0x40
+#define    RTL8367C_PORT3_MISC_CFG_VLAN_EGRESS_MODE_OFFSET    4
+#define    RTL8367C_PORT3_MISC_CFG_VLAN_EGRESS_MODE_MASK    0x30
+#define    RTL8367C_PORT3_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT3_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_INGRESSBW_PORT3_RATE_CTRL0    0x006f
+
+#define    RTL8367C_REG_INGRESSBW_PORT3_RATE_CTRL1    0x0070
+#define    RTL8367C_INGRESSBW_PORT3_RATE_CTRL1_DUMMY_OFFSET    3
+#define    RTL8367C_INGRESSBW_PORT3_RATE_CTRL1_DUMMY_MASK    0xFFF8
+#define    RTL8367C_INGRESSBW_PORT3_RATE_CTRL1_INGRESSBW_RATE16_OFFSET    0
+#define    RTL8367C_INGRESSBW_PORT3_RATE_CTRL1_INGRESSBW_RATE16_MASK    0x7
+
+#define    RTL8367C_REG_PORT3_FORCE_RATE0    0x0071
+
+#define    RTL8367C_REG_PORT3_FORCE_RATE1    0x0072
+
+#define    RTL8367C_REG_PORT3_CURENT_RATE0    0x0073
+
+#define    RTL8367C_REG_PORT3_CURENT_RATE1    0x0074
+
+#define    RTL8367C_REG_PORT3_PAGE_COUNTER    0x0075
+#define    RTL8367C_PORT3_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_PORT3_PAGE_COUNTER_MASK    0x7F
+
+#define    RTL8367C_REG_PAGEMETER_PORT3_CTRL0    0x0076
+
+#define    RTL8367C_REG_PAGEMETER_PORT3_CTRL1    0x0077
+
+#define    RTL8367C_REG_PORT3_EEECFG    0x0078
+#define    RTL8367C_PORT3_EEECFG_EEEP_ENABLE_TX_OFFSET    14
+#define    RTL8367C_PORT3_EEECFG_EEEP_ENABLE_TX_MASK    0x4000
+#define    RTL8367C_PORT3_EEECFG_EEEP_ENABLE_RX_OFFSET    13
+#define    RTL8367C_PORT3_EEECFG_EEEP_ENABLE_RX_MASK    0x2000
+#define    RTL8367C_PORT3_EEECFG_EEE_FORCE_OFFSET    12
+#define    RTL8367C_PORT3_EEECFG_EEE_FORCE_MASK    0x1000
+#define    RTL8367C_PORT3_EEECFG_EEE_100M_OFFSET    11
+#define    RTL8367C_PORT3_EEECFG_EEE_100M_MASK    0x800
+#define    RTL8367C_PORT3_EEECFG_EEE_GIGA_500M_OFFSET    10
+#define    RTL8367C_PORT3_EEECFG_EEE_GIGA_500M_MASK    0x400
+#define    RTL8367C_PORT3_EEECFG_EEE_TX_OFFSET    9
+#define    RTL8367C_PORT3_EEECFG_EEE_TX_MASK    0x200
+#define    RTL8367C_PORT3_EEECFG_EEE_RX_OFFSET    8
+#define    RTL8367C_PORT3_EEECFG_EEE_RX_MASK    0x100
+#define    RTL8367C_PORT3_EEECFG_EEE_DSP_RX_OFFSET    6
+#define    RTL8367C_PORT3_EEECFG_EEE_DSP_RX_MASK    0x40
+#define    RTL8367C_PORT3_EEECFG_EEE_LPI_OFFSET    5
+#define    RTL8367C_PORT3_EEECFG_EEE_LPI_MASK    0x20
+#define    RTL8367C_PORT3_EEECFG_EEE_TX_LPI_OFFSET    4
+#define    RTL8367C_PORT3_EEECFG_EEE_TX_LPI_MASK    0x10
+#define    RTL8367C_PORT3_EEECFG_EEE_RX_LPI_OFFSET    3
+#define    RTL8367C_PORT3_EEECFG_EEE_RX_LPI_MASK    0x8
+#define    RTL8367C_PORT3_EEECFG_EEE_PAUSE_INDICATOR_OFFSET    2
+#define    RTL8367C_PORT3_EEECFG_EEE_PAUSE_INDICATOR_MASK    0x4
+#define    RTL8367C_PORT3_EEECFG_EEE_WAKE_REQ_OFFSET    1
+#define    RTL8367C_PORT3_EEECFG_EEE_WAKE_REQ_MASK    0x2
+#define    RTL8367C_PORT3_EEECFG_EEE_SLEEP_REQ_OFFSET    0
+#define    RTL8367C_PORT3_EEECFG_EEE_SLEEP_REQ_MASK    0x1
+
+#define    RTL8367C_REG_PORT3_EEETXMTR    0x0079
+
+#define    RTL8367C_REG_PORT3_EEERXMTR    0x007a
+
+#define    RTL8367C_REG_PORT3_EEEPTXMTR    0x007b
+
+#define    RTL8367C_REG_PORT3_EEEPRXMTR    0x007c
+
+#define    RTL8367C_REG_PTP_PORT3_CFG1    0x007e
+#define    RTL8367C_PTP_PORT3_CFG1_OFFSET    7
+#define    RTL8367C_PTP_PORT3_CFG1_MASK    0xFF
+
+#define    RTL8367C_REG_P3_MSIC1    0x007f
+#define    RTL8367C_P3_MSIC1_OFFSET    0
+#define    RTL8367C_P3_MSIC1_MASK    0x1
+
+#define    RTL8367C_REG_PORT4_CGST_HALF_CFG    0x0080
+#define    RTL8367C_PORT4_CGST_HALF_CFG_CONGESTION_TIME_OFFSET    4
+#define    RTL8367C_PORT4_CGST_HALF_CFG_CONGESTION_TIME_MASK    0xF0
+#define    RTL8367C_PORT4_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT4_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_PKTGEN_PORT4_CTRL    0x0081
+#define    RTL8367C_PKTGEN_PORT4_CTRL_STATUS_OFFSET    15
+#define    RTL8367C_PKTGEN_PORT4_CTRL_STATUS_MASK    0x8000
+#define    RTL8367C_PKTGEN_PORT4_CTRL_PKTGEN_STS_OFFSET    13
+#define    RTL8367C_PKTGEN_PORT4_CTRL_PKTGEN_STS_MASK    0x2000
+#define    RTL8367C_PKTGEN_PORT4_CTRL_CRC_NO_ERROR_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT4_CTRL_CRC_NO_ERROR_MASK    0x10
+#define    RTL8367C_PKTGEN_PORT4_CTRL_CMD_START_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT4_CTRL_CMD_START_MASK    0x1
+
+#define    RTL8367C_REG_TX_ERR_CNT_PORT4    0x0082
+#define    RTL8367C_TX_ERR_CNT_PORT4_OFFSET    0
+#define    RTL8367C_TX_ERR_CNT_PORT4_MASK    0x7
+
+#define    RTL8367C_REG_PKTGEN_PORT4_DA0    0x0083
+
+#define    RTL8367C_REG_PKTGEN_PORT4_DA1    0x0084
+
+#define    RTL8367C_REG_PKTGEN_PORT4_DA2    0x0085
+
+#define    RTL8367C_REG_PKTGEN_PORT4_SA0    0x0086
+
+#define    RTL8367C_REG_PKTGEN_PORT4_SA1    0x0087
+
+#define    RTL8367C_REG_PKTGEN_PORT4_SA2    0x0088
+
+#define    RTL8367C_REG_PKTGEN_PORT4_COUNTER0    0x0089
+
+#define    RTL8367C_REG_PKTGEN_PORT4_COUNTER1    0x008a
+#define    RTL8367C_PKTGEN_PORT4_COUNTER1_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT4_COUNTER1_MASK    0xFF
+
+#define    RTL8367C_REG_PKTGEN_PORT4_TX_LENGTH    0x008b
+#define    RTL8367C_PKTGEN_PORT4_TX_LENGTH_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT4_TX_LENGTH_MASK    0x3FFF
+
+#define    RTL8367C_REG_PKTGEN_PORT4_TIMER    0x008d
+#define    RTL8367C_PKTGEN_PORT4_TIMER_TIMER_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT4_TIMER_TIMER_MASK    0xF0
+#define    RTL8367C_PKTGEN_PORT4_TIMER_RX_DMA_ERR_FLAG_OFFSET    3
+#define    RTL8367C_PKTGEN_PORT4_TIMER_RX_DMA_ERR_FLAG_MASK    0x8
+
+#define    RTL8367C_REG_PORT4_MISC_CFG    0x008e
+#define    RTL8367C_PORT4_MISC_CFG_SMALL_TAG_IPG_OFFSET    15
+#define    RTL8367C_PORT4_MISC_CFG_SMALL_TAG_IPG_MASK    0x8000
+#define    RTL8367C_PORT4_MISC_CFG_TX_ITFSP_MODE_OFFSET    14
+#define    RTL8367C_PORT4_MISC_CFG_TX_ITFSP_MODE_MASK    0x4000
+#define    RTL8367C_PORT4_MISC_CFG_FLOWCTRL_INDEP_OFFSET    13
+#define    RTL8367C_PORT4_MISC_CFG_FLOWCTRL_INDEP_MASK    0x2000
+#define    RTL8367C_PORT4_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET    12
+#define    RTL8367C_PORT4_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK    0x1000
+#define    RTL8367C_PORT4_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET    11
+#define    RTL8367C_PORT4_MISC_CFG_INGRESSBW_FLOWCTRL_MASK    0x800
+#define    RTL8367C_PORT4_MISC_CFG_INGRESSBW_IFG_OFFSET    10
+#define    RTL8367C_PORT4_MISC_CFG_INGRESSBW_IFG_MASK    0x400
+#define    RTL8367C_PORT4_MISC_CFG_RX_SPC_OFFSET    9
+#define    RTL8367C_PORT4_MISC_CFG_RX_SPC_MASK    0x200
+#define    RTL8367C_PORT4_MISC_CFG_CRC_SKIP_OFFSET    8
+#define    RTL8367C_PORT4_MISC_CFG_CRC_SKIP_MASK    0x100
+#define    RTL8367C_PORT4_MISC_CFG_PKTGEN_TX_FIRST_OFFSET    7
+#define    RTL8367C_PORT4_MISC_CFG_PKTGEN_TX_FIRST_MASK    0x80
+#define    RTL8367C_PORT4_MISC_CFG_MAC_LOOPBACK_OFFSET    6
+#define    RTL8367C_PORT4_MISC_CFG_MAC_LOOPBACK_MASK    0x40
+#define    RTL8367C_PORT4_MISC_CFG_VLAN_EGRESS_MODE_OFFSET    4
+#define    RTL8367C_PORT4_MISC_CFG_VLAN_EGRESS_MODE_MASK    0x30
+#define    RTL8367C_PORT4_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT4_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_INGRESSBW_PORT4_RATE_CTRL0    0x008f
+
+#define    RTL8367C_REG_INGRESSBW_PORT4_RATE_CTRL1    0x0090
+#define    RTL8367C_INGRESSBW_PORT4_RATE_CTRL1_DUMMY_OFFSET    3
+#define    RTL8367C_INGRESSBW_PORT4_RATE_CTRL1_DUMMY_MASK    0xFFF8
+#define    RTL8367C_INGRESSBW_PORT4_RATE_CTRL1_INGRESSBW_RATE16_OFFSET    0
+#define    RTL8367C_INGRESSBW_PORT4_RATE_CTRL1_INGRESSBW_RATE16_MASK    0x7
+
+#define    RTL8367C_REG_PORT4_FORCE_RATE0    0x0091
+
+#define    RTL8367C_REG_PORT4_FORCE_RATE1    0x0092
+
+#define    RTL8367C_REG_PORT4_CURENT_RATE0    0x0093
+
+#define    RTL8367C_REG_PORT4_CURENT_RATE1    0x0094
+
+#define    RTL8367C_REG_PORT4_PAGE_COUNTER    0x0095
+#define    RTL8367C_PORT4_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_PORT4_PAGE_COUNTER_MASK    0x7F
+
+#define    RTL8367C_REG_PAGEMETER_PORT4_CTRL0    0x0096
+
+#define    RTL8367C_REG_PAGEMETER_PORT4_CTRL1    0x0097
+
+#define    RTL8367C_REG_PORT4_EEECFG    0x0098
+#define    RTL8367C_PORT4_EEECFG_EEEP_ENABLE_TX_OFFSET    14
+#define    RTL8367C_PORT4_EEECFG_EEEP_ENABLE_TX_MASK    0x4000
+#define    RTL8367C_PORT4_EEECFG_EEEP_ENABLE_RX_OFFSET    13
+#define    RTL8367C_PORT4_EEECFG_EEEP_ENABLE_RX_MASK    0x2000
+#define    RTL8367C_PORT4_EEECFG_EEE_FORCE_OFFSET    12
+#define    RTL8367C_PORT4_EEECFG_EEE_FORCE_MASK    0x1000
+#define    RTL8367C_PORT4_EEECFG_EEE_100M_OFFSET    11
+#define    RTL8367C_PORT4_EEECFG_EEE_100M_MASK    0x800
+#define    RTL8367C_PORT4_EEECFG_EEE_GIGA_500M_OFFSET    10
+#define    RTL8367C_PORT4_EEECFG_EEE_GIGA_500M_MASK    0x400
+#define    RTL8367C_PORT4_EEECFG_EEE_TX_OFFSET    9
+#define    RTL8367C_PORT4_EEECFG_EEE_TX_MASK    0x200
+#define    RTL8367C_PORT4_EEECFG_EEE_RX_OFFSET    8
+#define    RTL8367C_PORT4_EEECFG_EEE_RX_MASK    0x100
+#define    RTL8367C_PORT4_EEECFG_EEE_DSP_RX_OFFSET    6
+#define    RTL8367C_PORT4_EEECFG_EEE_DSP_RX_MASK    0x40
+#define    RTL8367C_PORT4_EEECFG_EEE_LPI_OFFSET    5
+#define    RTL8367C_PORT4_EEECFG_EEE_LPI_MASK    0x20
+#define    RTL8367C_PORT4_EEECFG_EEE_TX_LPI_OFFSET    4
+#define    RTL8367C_PORT4_EEECFG_EEE_TX_LPI_MASK    0x10
+#define    RTL8367C_PORT4_EEECFG_EEE_RX_LPI_OFFSET    3
+#define    RTL8367C_PORT4_EEECFG_EEE_RX_LPI_MASK    0x8
+#define    RTL8367C_PORT4_EEECFG_EEE_PAUSE_INDICATOR_OFFSET    2
+#define    RTL8367C_PORT4_EEECFG_EEE_PAUSE_INDICATOR_MASK    0x4
+#define    RTL8367C_PORT4_EEECFG_EEE_WAKE_REQ_OFFSET    1
+#define    RTL8367C_PORT4_EEECFG_EEE_WAKE_REQ_MASK    0x2
+#define    RTL8367C_PORT4_EEECFG_EEE_SLEEP_REQ_OFFSET    0
+#define    RTL8367C_PORT4_EEECFG_EEE_SLEEP_REQ_MASK    0x1
+
+#define    RTL8367C_REG_PORT4_EEETXMTR    0x0099
+
+#define    RTL8367C_REG_PORT4_EEERXMTR    0x009a
+
+#define    RTL8367C_REG_PORT4_EEEPTXMTR    0x009b
+
+#define    RTL8367C_REG_PORT4_EEEPRXMTR    0x009c
+
+#define    RTL8367C_REG_PTP_PORT4_CFG1    0x009e
+#define    RTL8367C_PTP_PORT4_CFG1_OFFSET    7
+#define    RTL8367C_PTP_PORT4_CFG1_MASK    0xFF
+
+#define    RTL8367C_REG_P4_MSIC1    0x009f
+#define    RTL8367C_P4_MSIC1_OFFSET    0
+#define    RTL8367C_P4_MSIC1_MASK    0x1
+
+#define    RTL8367C_REG_PORT5_CGST_HALF_CFG    0x00a0
+#define    RTL8367C_PORT5_CGST_HALF_CFG_CONGESTION_TIME_OFFSET    4
+#define    RTL8367C_PORT5_CGST_HALF_CFG_CONGESTION_TIME_MASK    0xF0
+#define    RTL8367C_PORT5_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT5_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_PKTGEN_PORT5_CTRL    0x00a1
+#define    RTL8367C_PKTGEN_PORT5_CTRL_STATUS_OFFSET    15
+#define    RTL8367C_PKTGEN_PORT5_CTRL_STATUS_MASK    0x8000
+#define    RTL8367C_PKTGEN_PORT5_CTRL_PKTGEN_STS_OFFSET    13
+#define    RTL8367C_PKTGEN_PORT5_CTRL_PKTGEN_STS_MASK    0x2000
+#define    RTL8367C_PKTGEN_PORT5_CTRL_CRC_NO_ERROR_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT5_CTRL_CRC_NO_ERROR_MASK    0x10
+#define    RTL8367C_PKTGEN_PORT5_CTRL_CMD_START_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT5_CTRL_CMD_START_MASK    0x1
+
+#define    RTL8367C_REG_TX_ERR_CNT_PORT5    0x00a2
+#define    RTL8367C_TX_ERR_CNT_PORT5_OFFSET    0
+#define    RTL8367C_TX_ERR_CNT_PORT5_MASK    0x7
+
+#define    RTL8367C_REG_PKTGEN_PORT5_DA0    0x00a3
+
+#define    RTL8367C_REG_PKTGEN_PORT5_DA1    0x00a4
+
+#define    RTL8367C_REG_PKTGEN_PORT5_DA2    0x00a5
+
+#define    RTL8367C_REG_PKTGEN_PORT5_SA0    0x00a6
+
+#define    RTL8367C_REG_PKTGEN_PORT5_SA1    0x00a7
+
+#define    RTL8367C_REG_PKTGEN_PORT5_SA2    0x00a8
+
+#define    RTL8367C_REG_PKTGEN_PORT5_COUNTER0    0x00a9
+
+#define    RTL8367C_REG_PKTGEN_PORT5_COUNTER1    0x00aa
+#define    RTL8367C_PKTGEN_PORT5_COUNTER1_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT5_COUNTER1_MASK    0xFF
+
+#define    RTL8367C_REG_PKTGEN_PORT5_TX_LENGTH    0x00ab
+#define    RTL8367C_PKTGEN_PORT5_TX_LENGTH_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT5_TX_LENGTH_MASK    0x3FFF
+
+#define    RTL8367C_REG_PKTGEN_PORT5_TIMER    0x00ad
+#define    RTL8367C_PKTGEN_PORT5_TIMER_TIMER_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT5_TIMER_TIMER_MASK    0xF0
+#define    RTL8367C_PKTGEN_PORT5_TIMER_RX_DMA_ERR_FLAG_OFFSET    3
+#define    RTL8367C_PKTGEN_PORT5_TIMER_RX_DMA_ERR_FLAG_MASK    0x8
+
+#define    RTL8367C_REG_PORT5_MISC_CFG    0x00ae
+#define    RTL8367C_PORT5_MISC_CFG_SMALL_TAG_IPG_OFFSET    15
+#define    RTL8367C_PORT5_MISC_CFG_SMALL_TAG_IPG_MASK    0x8000
+#define    RTL8367C_PORT5_MISC_CFG_TX_ITFSP_MODE_OFFSET    14
+#define    RTL8367C_PORT5_MISC_CFG_TX_ITFSP_MODE_MASK    0x4000
+#define    RTL8367C_PORT5_MISC_CFG_FLOWCTRL_INDEP_OFFSET    13
+#define    RTL8367C_PORT5_MISC_CFG_FLOWCTRL_INDEP_MASK    0x2000
+#define    RTL8367C_PORT5_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET    12
+#define    RTL8367C_PORT5_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK    0x1000
+#define    RTL8367C_PORT5_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET    11
+#define    RTL8367C_PORT5_MISC_CFG_INGRESSBW_FLOWCTRL_MASK    0x800
+#define    RTL8367C_PORT5_MISC_CFG_INGRESSBW_IFG_OFFSET    10
+#define    RTL8367C_PORT5_MISC_CFG_INGRESSBW_IFG_MASK    0x400
+#define    RTL8367C_PORT5_MISC_CFG_RX_SPC_OFFSET    9
+#define    RTL8367C_PORT5_MISC_CFG_RX_SPC_MASK    0x200
+#define    RTL8367C_PORT5_MISC_CFG_CRC_SKIP_OFFSET    8
+#define    RTL8367C_PORT5_MISC_CFG_CRC_SKIP_MASK    0x100
+#define    RTL8367C_PORT5_MISC_CFG_PKTGEN_TX_FIRST_OFFSET    7
+#define    RTL8367C_PORT5_MISC_CFG_PKTGEN_TX_FIRST_MASK    0x80
+#define    RTL8367C_PORT5_MISC_CFG_MAC_LOOPBACK_OFFSET    6
+#define    RTL8367C_PORT5_MISC_CFG_MAC_LOOPBACK_MASK    0x40
+#define    RTL8367C_PORT5_MISC_CFG_VLAN_EGRESS_MODE_OFFSET    4
+#define    RTL8367C_PORT5_MISC_CFG_VLAN_EGRESS_MODE_MASK    0x30
+#define    RTL8367C_PORT5_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT5_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_INGRESSBW_PORT5_RATE_CTRL0    0x00af
+
+#define    RTL8367C_REG_INGRESSBW_PORT5_RATE_CTRL1    0x00b0
+#define    RTL8367C_INGRESSBW_PORT5_RATE_CTRL1_DUMMY_OFFSET    3
+#define    RTL8367C_INGRESSBW_PORT5_RATE_CTRL1_DUMMY_MASK    0xFFF8
+#define    RTL8367C_INGRESSBW_PORT5_RATE_CTRL1_INGRESSBW_RATE16_OFFSET    0
+#define    RTL8367C_INGRESSBW_PORT5_RATE_CTRL1_INGRESSBW_RATE16_MASK    0x7
+
+#define    RTL8367C_REG_PORT5_FORCE_RATE0    0x00b1
+
+#define    RTL8367C_REG_PORT5_FORCE_RATE1    0x00b2
+
+#define    RTL8367C_REG_PORT5_CURENT_RATE0    0x00b3
+
+#define    RTL8367C_REG_PORT5_CURENT_RATE1    0x00b4
+
+#define    RTL8367C_REG_PORT5_PAGE_COUNTER    0x00b5
+#define    RTL8367C_PORT5_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_PORT5_PAGE_COUNTER_MASK    0x7F
+
+#define    RTL8367C_REG_PAGEMETER_PORT5_CTRL0    0x00b6
+
+#define    RTL8367C_REG_PAGEMETER_PORT5_CTRL1    0x00b7
+
+#define    RTL8367C_REG_PORT5_EEECFG    0x00b8
+#define    RTL8367C_PORT5_EEECFG_EEEP_ENABLE_TX_OFFSET    14
+#define    RTL8367C_PORT5_EEECFG_EEEP_ENABLE_TX_MASK    0x4000
+#define    RTL8367C_PORT5_EEECFG_EEEP_ENABLE_RX_OFFSET    13
+#define    RTL8367C_PORT5_EEECFG_EEEP_ENABLE_RX_MASK    0x2000
+#define    RTL8367C_PORT5_EEECFG_EEE_FORCE_OFFSET    12
+#define    RTL8367C_PORT5_EEECFG_EEE_FORCE_MASK    0x1000
+#define    RTL8367C_PORT5_EEECFG_EEE_100M_OFFSET    11
+#define    RTL8367C_PORT5_EEECFG_EEE_100M_MASK    0x800
+#define    RTL8367C_PORT5_EEECFG_EEE_GIGA_500M_OFFSET    10
+#define    RTL8367C_PORT5_EEECFG_EEE_GIGA_500M_MASK    0x400
+#define    RTL8367C_PORT5_EEECFG_EEE_TX_OFFSET    9
+#define    RTL8367C_PORT5_EEECFG_EEE_TX_MASK    0x200
+#define    RTL8367C_PORT5_EEECFG_EEE_RX_OFFSET    8
+#define    RTL8367C_PORT5_EEECFG_EEE_RX_MASK    0x100
+#define    RTL8367C_PORT5_EEECFG_EEE_DSP_RX_OFFSET    6
+#define    RTL8367C_PORT5_EEECFG_EEE_DSP_RX_MASK    0x40
+#define    RTL8367C_PORT5_EEECFG_EEE_LPI_OFFSET    5
+#define    RTL8367C_PORT5_EEECFG_EEE_LPI_MASK    0x20
+#define    RTL8367C_PORT5_EEECFG_EEE_TX_LPI_OFFSET    4
+#define    RTL8367C_PORT5_EEECFG_EEE_TX_LPI_MASK    0x10
+#define    RTL8367C_PORT5_EEECFG_EEE_RX_LPI_OFFSET    3
+#define    RTL8367C_PORT5_EEECFG_EEE_RX_LPI_MASK    0x8
+#define    RTL8367C_PORT5_EEECFG_EEE_PAUSE_INDICATOR_OFFSET    2
+#define    RTL8367C_PORT5_EEECFG_EEE_PAUSE_INDICATOR_MASK    0x4
+#define    RTL8367C_PORT5_EEECFG_EEE_WAKE_REQ_OFFSET    1
+#define    RTL8367C_PORT5_EEECFG_EEE_WAKE_REQ_MASK    0x2
+#define    RTL8367C_PORT5_EEECFG_EEE_SLEEP_REQ_OFFSET    0
+#define    RTL8367C_PORT5_EEECFG_EEE_SLEEP_REQ_MASK    0x1
+
+#define    RTL8367C_REG_PORT5_EEETXMTR    0x00b9
+
+#define    RTL8367C_REG_PORT5_EEERXMTR    0x00ba
+
+#define    RTL8367C_REG_PORT5_EEEPTXMTR    0x00bb
+
+#define    RTL8367C_REG_PORT5_EEEPRXMTR    0x00bc
+
+#define    RTL8367C_REG_PTP_PORT5_CFG1    0x00be
+#define    RTL8367C_PTP_PORT5_CFG1_OFFSET    7
+#define    RTL8367C_PTP_PORT5_CFG1_MASK    0xFF
+
+#define    RTL8367C_REG_P5_MSIC1    0x00bf
+#define    RTL8367C_P5_MSIC1_OFFSET    0
+#define    RTL8367C_P5_MSIC1_MASK    0x1
+
+#define    RTL8367C_REG_PORT6_CGST_HALF_CFG    0x00c0
+#define    RTL8367C_PORT6_CGST_HALF_CFG_CONGESTION_TIME_OFFSET    4
+#define    RTL8367C_PORT6_CGST_HALF_CFG_CONGESTION_TIME_MASK    0xF0
+#define    RTL8367C_PORT6_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT6_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_PKTGEN_PORT6_CTRL    0x00c1
+#define    RTL8367C_PKTGEN_PORT6_CTRL_STATUS_OFFSET    15
+#define    RTL8367C_PKTGEN_PORT6_CTRL_STATUS_MASK    0x8000
+#define    RTL8367C_PKTGEN_PORT6_CTRL_PKTGEN_STS_OFFSET    13
+#define    RTL8367C_PKTGEN_PORT6_CTRL_PKTGEN_STS_MASK    0x2000
+#define    RTL8367C_PKTGEN_PORT6_CTRL_CRC_NO_ERROR_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT6_CTRL_CRC_NO_ERROR_MASK    0x10
+#define    RTL8367C_PKTGEN_PORT6_CTRL_CMD_START_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT6_CTRL_CMD_START_MASK    0x1
+
+#define    RTL8367C_REG_TX_ERR_CNT_PORT6    0x00c2
+#define    RTL8367C_TX_ERR_CNT_PORT6_OFFSET    0
+#define    RTL8367C_TX_ERR_CNT_PORT6_MASK    0x7
+
+#define    RTL8367C_REG_PKTGEN_PORT6_DA0    0x00c3
+
+#define    RTL8367C_REG_PKTGEN_PORT6_DA1    0x00c4
+
+#define    RTL8367C_REG_PKTGEN_PORT6_DA2    0x00c5
+
+#define    RTL8367C_REG_PKTGEN_PORT6_SA0    0x00c6
+
+#define    RTL8367C_REG_PKTGEN_PORT6_SA1    0x00c7
+
+#define    RTL8367C_REG_PKTGEN_PORT6_SA2    0x00c8
+
+#define    RTL8367C_REG_PKTGEN_PORT6_COUNTER0    0x00c9
+
+#define    RTL8367C_REG_PKTGEN_PORT6_COUNTER1    0x00ca
+#define    RTL8367C_PKTGEN_PORT6_COUNTER1_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT6_COUNTER1_MASK    0xFF
+
+#define    RTL8367C_REG_PKTGEN_PORT6_TX_LENGTH    0x00cb
+#define    RTL8367C_PKTGEN_PORT6_TX_LENGTH_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT6_TX_LENGTH_MASK    0x3FFF
+
+#define    RTL8367C_REG_PKTGEN_PORT6_TIMER    0x00cd
+#define    RTL8367C_PKTGEN_PORT6_TIMER_TIMER_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT6_TIMER_TIMER_MASK    0xF0
+#define    RTL8367C_PKTGEN_PORT6_TIMER_RX_DMA_ERR_FLAG_OFFSET    3
+#define    RTL8367C_PKTGEN_PORT6_TIMER_RX_DMA_ERR_FLAG_MASK    0x8
+
+#define    RTL8367C_REG_PORT6_MISC_CFG    0x00ce
+#define    RTL8367C_PORT6_MISC_CFG_SMALL_TAG_IPG_OFFSET    15
+#define    RTL8367C_PORT6_MISC_CFG_SMALL_TAG_IPG_MASK    0x8000
+#define    RTL8367C_PORT6_MISC_CFG_TX_ITFSP_MODE_OFFSET    14
+#define    RTL8367C_PORT6_MISC_CFG_TX_ITFSP_MODE_MASK    0x4000
+#define    RTL8367C_PORT6_MISC_CFG_FLOWCTRL_INDEP_OFFSET    13
+#define    RTL8367C_PORT6_MISC_CFG_FLOWCTRL_INDEP_MASK    0x2000
+#define    RTL8367C_PORT6_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET    12
+#define    RTL8367C_PORT6_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK    0x1000
+#define    RTL8367C_PORT6_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET    11
+#define    RTL8367C_PORT6_MISC_CFG_INGRESSBW_FLOWCTRL_MASK    0x800
+#define    RTL8367C_PORT6_MISC_CFG_INGRESSBW_IFG_OFFSET    10
+#define    RTL8367C_PORT6_MISC_CFG_INGRESSBW_IFG_MASK    0x400
+#define    RTL8367C_PORT6_MISC_CFG_RX_SPC_OFFSET    9
+#define    RTL8367C_PORT6_MISC_CFG_RX_SPC_MASK    0x200
+#define    RTL8367C_PORT6_MISC_CFG_CRC_SKIP_OFFSET    8
+#define    RTL8367C_PORT6_MISC_CFG_CRC_SKIP_MASK    0x100
+#define    RTL8367C_PORT6_MISC_CFG_PKTGEN_TX_FIRST_OFFSET    7
+#define    RTL8367C_PORT6_MISC_CFG_PKTGEN_TX_FIRST_MASK    0x80
+#define    RTL8367C_PORT6_MISC_CFG_MAC_LOOPBACK_OFFSET    6
+#define    RTL8367C_PORT6_MISC_CFG_MAC_LOOPBACK_MASK    0x40
+#define    RTL8367C_PORT6_MISC_CFG_VLAN_EGRESS_MODE_OFFSET    4
+#define    RTL8367C_PORT6_MISC_CFG_VLAN_EGRESS_MODE_MASK    0x30
+#define    RTL8367C_PORT6_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT6_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_INGRESSBW_PORT6_RATE_CTRL0    0x00cf
+
+#define    RTL8367C_REG_INGRESSBW_PORT6_RATE_CTRL1    0x00d0
+#define    RTL8367C_INGRESSBW_PORT6_RATE_CTRL1_DUMMY_OFFSET    3
+#define    RTL8367C_INGRESSBW_PORT6_RATE_CTRL1_DUMMY_MASK    0xFFF8
+#define    RTL8367C_INGRESSBW_PORT6_RATE_CTRL1_INGRESSBW_RATE16_OFFSET    0
+#define    RTL8367C_INGRESSBW_PORT6_RATE_CTRL1_INGRESSBW_RATE16_MASK    0x7
+
+#define    RTL8367C_REG_PORT6_FORCE_RATE0    0x00d1
+
+#define    RTL8367C_REG_PORT6_FORCE_RATE1    0x00d2
+
+#define    RTL8367C_REG_PORT6_CURENT_RATE0    0x00d3
+
+#define    RTL8367C_REG_PORT6_CURENT_RATE1    0x00d4
+
+#define    RTL8367C_REG_PORT6_PAGE_COUNTER    0x00d5
+#define    RTL8367C_PORT6_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_PORT6_PAGE_COUNTER_MASK    0x7F
+
+#define    RTL8367C_REG_PAGEMETER_PORT6_CTRL0    0x00d6
+
+#define    RTL8367C_REG_PAGEMETER_PORT6_CTRL1    0x00d7
+
+#define    RTL8367C_REG_PORT6_EEECFG    0x00d8
+#define    RTL8367C_PORT6_EEECFG_EEEP_ENABLE_TX_OFFSET    14
+#define    RTL8367C_PORT6_EEECFG_EEEP_ENABLE_TX_MASK    0x4000
+#define    RTL8367C_PORT6_EEECFG_EEEP_ENABLE_RX_OFFSET    13
+#define    RTL8367C_PORT6_EEECFG_EEEP_ENABLE_RX_MASK    0x2000
+#define    RTL8367C_PORT6_EEECFG_EEE_FORCE_OFFSET    12
+#define    RTL8367C_PORT6_EEECFG_EEE_FORCE_MASK    0x1000
+#define    RTL8367C_PORT6_EEECFG_EEE_100M_OFFSET    11
+#define    RTL8367C_PORT6_EEECFG_EEE_100M_MASK    0x800
+#define    RTL8367C_PORT6_EEECFG_EEE_GIGA_500M_OFFSET    10
+#define    RTL8367C_PORT6_EEECFG_EEE_GIGA_500M_MASK    0x400
+#define    RTL8367C_PORT6_EEECFG_EEE_TX_OFFSET    9
+#define    RTL8367C_PORT6_EEECFG_EEE_TX_MASK    0x200
+#define    RTL8367C_PORT6_EEECFG_EEE_RX_OFFSET    8
+#define    RTL8367C_PORT6_EEECFG_EEE_RX_MASK    0x100
+#define    RTL8367C_PORT6_EEECFG_EEE_DSP_RX_OFFSET    6
+#define    RTL8367C_PORT6_EEECFG_EEE_DSP_RX_MASK    0x40
+#define    RTL8367C_PORT6_EEECFG_EEE_LPI_OFFSET    5
+#define    RTL8367C_PORT6_EEECFG_EEE_LPI_MASK    0x20
+#define    RTL8367C_PORT6_EEECFG_EEE_TX_LPI_OFFSET    4
+#define    RTL8367C_PORT6_EEECFG_EEE_TX_LPI_MASK    0x10
+#define    RTL8367C_PORT6_EEECFG_EEE_RX_LPI_OFFSET    3
+#define    RTL8367C_PORT6_EEECFG_EEE_RX_LPI_MASK    0x8
+#define    RTL8367C_PORT6_EEECFG_EEE_PAUSE_INDICATOR_OFFSET    2
+#define    RTL8367C_PORT6_EEECFG_EEE_PAUSE_INDICATOR_MASK    0x4
+#define    RTL8367C_PORT6_EEECFG_EEE_WAKE_REQ_OFFSET    1
+#define    RTL8367C_PORT6_EEECFG_EEE_WAKE_REQ_MASK    0x2
+#define    RTL8367C_PORT6_EEECFG_EEE_SLEEP_REQ_OFFSET    0
+#define    RTL8367C_PORT6_EEECFG_EEE_SLEEP_REQ_MASK    0x1
+
+#define    RTL8367C_REG_PORT6_EEETXMTR    0x00d9
+
+#define    RTL8367C_REG_PORT6_EEERXMTR    0x00da
+
+#define    RTL8367C_REG_PORT6_EEEPTXMTR    0x00db
+
+#define    RTL8367C_REG_PORT6_EEEPRXMTR    0x00dc
+
+#define    RTL8367C_REG_PTP_PORT6_CFG1    0x00de
+#define    RTL8367C_PTP_PORT6_CFG1_OFFSET    7
+#define    RTL8367C_PTP_PORT6_CFG1_MASK    0xFF
+
+#define    RTL8367C_REG_P6_MSIC1    0x00df
+#define    RTL8367C_P6_MSIC1_OFFSET    0
+#define    RTL8367C_P6_MSIC1_MASK    0x1
+
+#define    RTL8367C_REG_PORT7_CGST_HALF_CFG    0x00e0
+#define    RTL8367C_PORT7_CGST_HALF_CFG_CONGESTION_TIME_OFFSET    4
+#define    RTL8367C_PORT7_CGST_HALF_CFG_CONGESTION_TIME_MASK    0xF0
+#define    RTL8367C_PORT7_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT7_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_PKTGEN_PORT7_CTRL    0x00e1
+#define    RTL8367C_PKTGEN_PORT7_CTRL_STATUS_OFFSET    15
+#define    RTL8367C_PKTGEN_PORT7_CTRL_STATUS_MASK    0x8000
+#define    RTL8367C_PKTGEN_PORT7_CTRL_PKTGEN_STS_OFFSET    13
+#define    RTL8367C_PKTGEN_PORT7_CTRL_PKTGEN_STS_MASK    0x2000
+#define    RTL8367C_PKTGEN_PORT7_CTRL_CRC_NO_ERROR_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT7_CTRL_CRC_NO_ERROR_MASK    0x10
+#define    RTL8367C_PKTGEN_PORT7_CTRL_CMD_START_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT7_CTRL_CMD_START_MASK    0x1
+
+#define    RTL8367C_REG_TX_ERR_CNT_PORT7    0x00e2
+#define    RTL8367C_TX_ERR_CNT_PORT7_OFFSET    0
+#define    RTL8367C_TX_ERR_CNT_PORT7_MASK    0x7
+
+#define    RTL8367C_REG_PKTGEN_PORT7_DA0    0x00e3
+
+#define    RTL8367C_REG_PKTGEN_PORT7_DA1    0x00e4
+
+#define    RTL8367C_REG_PKTGEN_PORT7_DA2    0x00e5
+
+#define    RTL8367C_REG_PKTGEN_PORT7_SA0    0x00e6
+
+#define    RTL8367C_REG_PKTGEN_PORT7_SA1    0x00e7
+
+#define    RTL8367C_REG_PKTGEN_PORT7_SA2    0x00e8
+
+#define    RTL8367C_REG_PKTGEN_PORT7_COUNTER0    0x00e9
+
+#define    RTL8367C_REG_PKTGEN_PORT7_COUNTER1    0x00ea
+#define    RTL8367C_PKTGEN_PORT7_COUNTER1_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT7_COUNTER1_MASK    0xFF
+
+#define    RTL8367C_REG_PKTGEN_PORT7_TX_LENGTH    0x00eb
+#define    RTL8367C_PKTGEN_PORT7_TX_LENGTH_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT7_TX_LENGTH_MASK    0x3FFF
+
+#define    RTL8367C_REG_PKTGEN_PORT7_TIMER    0x00ed
+#define    RTL8367C_PKTGEN_PORT7_TIMER_TIMER_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT7_TIMER_TIMER_MASK    0xF0
+#define    RTL8367C_PKTGEN_PORT7_TIMER_RX_DMA_ERR_FLAG_OFFSET    3
+#define    RTL8367C_PKTGEN_PORT7_TIMER_RX_DMA_ERR_FLAG_MASK    0x8
+
+#define    RTL8367C_REG_PORT7_MISC_CFG    0x00ee
+#define    RTL8367C_PORT7_MISC_CFG_SMALL_TAG_IPG_OFFSET    15
+#define    RTL8367C_PORT7_MISC_CFG_SMALL_TAG_IPG_MASK    0x8000
+#define    RTL8367C_PORT7_MISC_CFG_TX_ITFSP_MODE_OFFSET    14
+#define    RTL8367C_PORT7_MISC_CFG_TX_ITFSP_MODE_MASK    0x4000
+#define    RTL8367C_PORT7_MISC_CFG_FLOWCTRL_INDEP_OFFSET    13
+#define    RTL8367C_PORT7_MISC_CFG_FLOWCTRL_INDEP_MASK    0x2000
+#define    RTL8367C_PORT7_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET    12
+#define    RTL8367C_PORT7_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK    0x1000
+#define    RTL8367C_PORT7_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET    11
+#define    RTL8367C_PORT7_MISC_CFG_INGRESSBW_FLOWCTRL_MASK    0x800
+#define    RTL8367C_PORT7_MISC_CFG_INGRESSBW_IFG_OFFSET    10
+#define    RTL8367C_PORT7_MISC_CFG_INGRESSBW_IFG_MASK    0x400
+#define    RTL8367C_PORT7_MISC_CFG_RX_SPC_OFFSET    9
+#define    RTL8367C_PORT7_MISC_CFG_RX_SPC_MASK    0x200
+#define    RTL8367C_PORT7_MISC_CFG_CRC_SKIP_OFFSET    8
+#define    RTL8367C_PORT7_MISC_CFG_CRC_SKIP_MASK    0x100
+#define    RTL8367C_PORT7_MISC_CFG_PKTGEN_TX_FIRST_OFFSET    7
+#define    RTL8367C_PORT7_MISC_CFG_PKTGEN_TX_FIRST_MASK    0x80
+#define    RTL8367C_PORT7_MISC_CFG_MAC_LOOPBACK_OFFSET    6
+#define    RTL8367C_PORT7_MISC_CFG_MAC_LOOPBACK_MASK    0x40
+#define    RTL8367C_PORT7_MISC_CFG_VLAN_EGRESS_MODE_OFFSET    4
+#define    RTL8367C_PORT7_MISC_CFG_VLAN_EGRESS_MODE_MASK    0x30
+#define    RTL8367C_PORT7_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT7_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_INGRESSBW_PORT7_RATE_CTRL0    0x00ef
+
+#define    RTL8367C_REG_INGRESSBW_PORT7_RATE_CTRL1    0x00f0
+#define    RTL8367C_INGRESSBW_PORT7_RATE_CTRL1_DUMMY_OFFSET    3
+#define    RTL8367C_INGRESSBW_PORT7_RATE_CTRL1_DUMMY_MASK    0xFFF8
+#define    RTL8367C_INGRESSBW_PORT7_RATE_CTRL1_INGRESSBW_RATE16_OFFSET    0
+#define    RTL8367C_INGRESSBW_PORT7_RATE_CTRL1_INGRESSBW_RATE16_MASK    0x7
+
+#define    RTL8367C_REG_PORT7_FORCE_RATE0    0x00f1
+
+#define    RTL8367C_REG_PORT7_FORCE_RATE1    0x00f2
+
+#define    RTL8367C_REG_PORT7_CURENT_RATE0    0x00f3
+
+#define    RTL8367C_REG_PORT7_CURENT_RATE1    0x00f4
+
+#define    RTL8367C_REG_PORT7_PAGE_COUNTER    0x00f5
+#define    RTL8367C_PORT7_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_PORT7_PAGE_COUNTER_MASK    0x7F
+
+#define    RTL8367C_REG_PAGEMETER_PORT7_CTRL0    0x00f6
+
+#define    RTL8367C_REG_PAGEMETER_PORT7_CTRL1    0x00f7
+
+#define    RTL8367C_REG_PORT7_EEECFG    0x00f8
+#define    RTL8367C_PORT7_EEECFG_EEEP_ENABLE_TX_OFFSET    14
+#define    RTL8367C_PORT7_EEECFG_EEEP_ENABLE_TX_MASK    0x4000
+#define    RTL8367C_PORT7_EEECFG_EEEP_ENABLE_RX_OFFSET    13
+#define    RTL8367C_PORT7_EEECFG_EEEP_ENABLE_RX_MASK    0x2000
+#define    RTL8367C_PORT7_EEECFG_EEE_FORCE_OFFSET    12
+#define    RTL8367C_PORT7_EEECFG_EEE_FORCE_MASK    0x1000
+#define    RTL8367C_PORT7_EEECFG_EEE_100M_OFFSET    11
+#define    RTL8367C_PORT7_EEECFG_EEE_100M_MASK    0x800
+#define    RTL8367C_PORT7_EEECFG_EEE_GIGA_500M_OFFSET    10
+#define    RTL8367C_PORT7_EEECFG_EEE_GIGA_500M_MASK    0x400
+#define    RTL8367C_PORT7_EEECFG_EEE_TX_OFFSET    9
+#define    RTL8367C_PORT7_EEECFG_EEE_TX_MASK    0x200
+#define    RTL8367C_PORT7_EEECFG_EEE_RX_OFFSET    8
+#define    RTL8367C_PORT7_EEECFG_EEE_RX_MASK    0x100
+#define    RTL8367C_PORT7_EEECFG_EEE_DSP_RX_OFFSET    6
+#define    RTL8367C_PORT7_EEECFG_EEE_DSP_RX_MASK    0x40
+#define    RTL8367C_PORT7_EEECFG_EEE_LPI_OFFSET    5
+#define    RTL8367C_PORT7_EEECFG_EEE_LPI_MASK    0x20
+#define    RTL8367C_PORT7_EEECFG_EEE_TX_LPI_OFFSET    4
+#define    RTL8367C_PORT7_EEECFG_EEE_TX_LPI_MASK    0x10
+#define    RTL8367C_PORT7_EEECFG_EEE_RX_LPI_OFFSET    3
+#define    RTL8367C_PORT7_EEECFG_EEE_RX_LPI_MASK    0x8
+#define    RTL8367C_PORT7_EEECFG_EEE_PAUSE_INDICATOR_OFFSET    2
+#define    RTL8367C_PORT7_EEECFG_EEE_PAUSE_INDICATOR_MASK    0x4
+#define    RTL8367C_PORT7_EEECFG_EEE_WAKE_REQ_OFFSET    1
+#define    RTL8367C_PORT7_EEECFG_EEE_WAKE_REQ_MASK    0x2
+#define    RTL8367C_PORT7_EEECFG_EEE_SLEEP_REQ_OFFSET    0
+#define    RTL8367C_PORT7_EEECFG_EEE_SLEEP_REQ_MASK    0x1
+
+#define    RTL8367C_REG_PORT7_EEETXMTR    0x00f9
+
+#define    RTL8367C_REG_PORT7_EEERXMTR    0x00fa
+
+#define    RTL8367C_REG_PORT7_EEEPTXMTR    0x00fb
+
+#define    RTL8367C_REG_PORT7_EEEPRXMTR    0x00fc
+
+#define    RTL8367C_REG_PTP_PORT7_CFG1    0x00fe
+#define    RTL8367C_PTP_PORT7_CFG1_OFFSET    7
+#define    RTL8367C_PTP_PORT7_CFG1_MASK    0xFF
+
+#define    RTL8367C_REG_P7_MSIC1    0x00ff
+#define    RTL8367C_P7_MSIC1_OFFSET    0
+#define    RTL8367C_P7_MSIC1_MASK    0x1
+
+#define    RTL8367C_REG_PORT8_CGST_HALF_CFG    0x0100
+#define    RTL8367C_PORT8_CGST_HALF_CFG_CONGESTION_TIME_OFFSET    4
+#define    RTL8367C_PORT8_CGST_HALF_CFG_CONGESTION_TIME_MASK    0xF0
+#define    RTL8367C_PORT8_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT8_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_PKTGEN_PORT8_CTRL    0x0101
+#define    RTL8367C_PKTGEN_PORT8_CTRL_STATUS_OFFSET    15
+#define    RTL8367C_PKTGEN_PORT8_CTRL_STATUS_MASK    0x8000
+#define    RTL8367C_PKTGEN_PORT8_CTRL_PKTGEN_STS_OFFSET    13
+#define    RTL8367C_PKTGEN_PORT8_CTRL_PKTGEN_STS_MASK    0x2000
+#define    RTL8367C_PKTGEN_PORT8_CTRL_CRC_NO_ERROR_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT8_CTRL_CRC_NO_ERROR_MASK    0x10
+#define    RTL8367C_PKTGEN_PORT8_CTRL_CMD_START_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT8_CTRL_CMD_START_MASK    0x1
+
+#define    RTL8367C_REG_TX_ERR_CNT_PORT8    0x0102
+#define    RTL8367C_TX_ERR_CNT_PORT8_OFFSET    0
+#define    RTL8367C_TX_ERR_CNT_PORT8_MASK    0x7
+
+#define    RTL8367C_REG_PKTGEN_PORT8_DA0    0x0103
+
+#define    RTL8367C_REG_PKTGEN_PORT8_DA1    0x0104
+
+#define    RTL8367C_REG_PKTGEN_PORT8_DA2    0x0105
+
+#define    RTL8367C_REG_PKTGEN_PORT8_SA0    0x0106
+
+#define    RTL8367C_REG_PKTGEN_PORT8_SA1    0x0107
+
+#define    RTL8367C_REG_PKTGEN_PORT8_SA2    0x0108
+
+#define    RTL8367C_REG_PKTGEN_PORT8_COUNTER0    0x0109
+
+#define    RTL8367C_REG_PKTGEN_PORT8_COUNTER1    0x010a
+#define    RTL8367C_PKTGEN_PORT8_COUNTER1_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT8_COUNTER1_MASK    0xFF
+
+#define    RTL8367C_REG_PKTGEN_PORT8_TX_LENGTH    0x010b
+#define    RTL8367C_PKTGEN_PORT8_TX_LENGTH_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT8_TX_LENGTH_MASK    0x3FFF
+
+#define    RTL8367C_REG_PKTGEN_PORT8_TIMER    0x010d
+#define    RTL8367C_PKTGEN_PORT8_TIMER_TIMER_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT8_TIMER_TIMER_MASK    0xF0
+#define    RTL8367C_PKTGEN_PORT8_TIMER_RX_DMA_ERR_FLAG_OFFSET    3
+#define    RTL8367C_PKTGEN_PORT8_TIMER_RX_DMA_ERR_FLAG_MASK    0x8
+
+#define    RTL8367C_REG_PORT8_MISC_CFG    0x010e
+#define    RTL8367C_PORT8_MISC_CFG_SMALL_TAG_IPG_OFFSET    15
+#define    RTL8367C_PORT8_MISC_CFG_SMALL_TAG_IPG_MASK    0x8000
+#define    RTL8367C_PORT8_MISC_CFG_TX_ITFSP_MODE_OFFSET    14
+#define    RTL8367C_PORT8_MISC_CFG_TX_ITFSP_MODE_MASK    0x4000
+#define    RTL8367C_PORT8_MISC_CFG_FLOWCTRL_INDEP_OFFSET    13
+#define    RTL8367C_PORT8_MISC_CFG_FLOWCTRL_INDEP_MASK    0x2000
+#define    RTL8367C_PORT8_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET    12
+#define    RTL8367C_PORT8_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK    0x1000
+#define    RTL8367C_PORT8_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET    11
+#define    RTL8367C_PORT8_MISC_CFG_INGRESSBW_FLOWCTRL_MASK    0x800
+#define    RTL8367C_PORT8_MISC_CFG_INGRESSBW_IFG_OFFSET    10
+#define    RTL8367C_PORT8_MISC_CFG_INGRESSBW_IFG_MASK    0x400
+#define    RTL8367C_PORT8_MISC_CFG_RX_SPC_OFFSET    9
+#define    RTL8367C_PORT8_MISC_CFG_RX_SPC_MASK    0x200
+#define    RTL8367C_PORT8_MISC_CFG_CRC_SKIP_OFFSET    8
+#define    RTL8367C_PORT8_MISC_CFG_CRC_SKIP_MASK    0x100
+#define    RTL8367C_PORT8_MISC_CFG_PKTGEN_TX_FIRST_OFFSET    7
+#define    RTL8367C_PORT8_MISC_CFG_PKTGEN_TX_FIRST_MASK    0x80
+#define    RTL8367C_PORT8_MISC_CFG_MAC_LOOPBACK_OFFSET    6
+#define    RTL8367C_PORT8_MISC_CFG_MAC_LOOPBACK_MASK    0x40
+#define    RTL8367C_PORT8_MISC_CFG_VLAN_EGRESS_MODE_OFFSET    4
+#define    RTL8367C_PORT8_MISC_CFG_VLAN_EGRESS_MODE_MASK    0x30
+#define    RTL8367C_PORT8_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT8_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_INGRESSBW_PORT8_RATE_CTRL0    0x010f
+
+#define    RTL8367C_REG_INGRESSBW_PORT8_RATE_CTRL1    0x0110
+#define    RTL8367C_INGRESSBW_PORT8_RATE_CTRL1_DUMMY_OFFSET    3
+#define    RTL8367C_INGRESSBW_PORT8_RATE_CTRL1_DUMMY_MASK    0xFFF8
+#define    RTL8367C_INGRESSBW_PORT8_RATE_CTRL1_INGRESSBW_RATE16_OFFSET    0
+#define    RTL8367C_INGRESSBW_PORT8_RATE_CTRL1_INGRESSBW_RATE16_MASK    0x7
+
+#define    RTL8367C_REG_PORT8_FORCE_RATE0    0x0111
+
+#define    RTL8367C_REG_PORT8_FORCE_RATE1    0x0112
+
+#define    RTL8367C_REG_PORT8_CURENT_RATE0    0x0113
+
+#define    RTL8367C_REG_PORT8_CURENT_RATE1    0x0114
+
+#define    RTL8367C_REG_PORT8_PAGE_COUNTER    0x0115
+#define    RTL8367C_PORT8_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_PORT8_PAGE_COUNTER_MASK    0x7F
+
+#define    RTL8367C_REG_PAGEMETER_PORT8_CTRL0    0x0116
+
+#define    RTL8367C_REG_PAGEMETER_PORT8_CTRL1    0x0117
+
+#define    RTL8367C_REG_PORT8_EEECFG    0x0118
+#define    RTL8367C_PORT8_EEECFG_EEEP_ENABLE_TX_OFFSET    14
+#define    RTL8367C_PORT8_EEECFG_EEEP_ENABLE_TX_MASK    0x4000
+#define    RTL8367C_PORT8_EEECFG_EEEP_ENABLE_RX_OFFSET    13
+#define    RTL8367C_PORT8_EEECFG_EEEP_ENABLE_RX_MASK    0x2000
+#define    RTL8367C_PORT8_EEECFG_EEE_FORCE_OFFSET    12
+#define    RTL8367C_PORT8_EEECFG_EEE_FORCE_MASK    0x1000
+#define    RTL8367C_PORT8_EEECFG_EEE_100M_OFFSET    11
+#define    RTL8367C_PORT8_EEECFG_EEE_100M_MASK    0x800
+#define    RTL8367C_PORT8_EEECFG_EEE_GIGA_500M_OFFSET    10
+#define    RTL8367C_PORT8_EEECFG_EEE_GIGA_500M_MASK    0x400
+#define    RTL8367C_PORT8_EEECFG_EEE_TX_OFFSET    9
+#define    RTL8367C_PORT8_EEECFG_EEE_TX_MASK    0x200
+#define    RTL8367C_PORT8_EEECFG_EEE_RX_OFFSET    8
+#define    RTL8367C_PORT8_EEECFG_EEE_RX_MASK    0x100
+#define    RTL8367C_PORT8_EEECFG_EEE_DSP_RX_OFFSET    6
+#define    RTL8367C_PORT8_EEECFG_EEE_DSP_RX_MASK    0x40
+#define    RTL8367C_PORT8_EEECFG_EEE_LPI_OFFSET    5
+#define    RTL8367C_PORT8_EEECFG_EEE_LPI_MASK    0x20
+#define    RTL8367C_PORT8_EEECFG_EEE_TX_LPI_OFFSET    4
+#define    RTL8367C_PORT8_EEECFG_EEE_TX_LPI_MASK    0x10
+#define    RTL8367C_PORT8_EEECFG_EEE_RX_LPI_OFFSET    3
+#define    RTL8367C_PORT8_EEECFG_EEE_RX_LPI_MASK    0x8
+#define    RTL8367C_PORT8_EEECFG_EEE_PAUSE_INDICATOR_OFFSET    2
+#define    RTL8367C_PORT8_EEECFG_EEE_PAUSE_INDICATOR_MASK    0x4
+#define    RTL8367C_PORT8_EEECFG_EEE_WAKE_REQ_OFFSET    1
+#define    RTL8367C_PORT8_EEECFG_EEE_WAKE_REQ_MASK    0x2
+#define    RTL8367C_PORT8_EEECFG_EEE_SLEEP_REQ_OFFSET    0
+#define    RTL8367C_PORT8_EEECFG_EEE_SLEEP_REQ_MASK    0x1
+
+#define    RTL8367C_REG_PORT8_EEETXMTR    0x0119
+
+#define    RTL8367C_REG_PORT8_EEERXMTR    0x011a
+
+#define    RTL8367C_REG_PORT8_EEEPTXMTR    0x011b
+
+#define    RTL8367C_REG_PORT8_EEEPRXMTR    0x011c
+
+#define    RTL8367C_REG_PTP_PORT8_CFG1    0x011e
+#define    RTL8367C_PTP_PORT8_CFG1_OFFSET    7
+#define    RTL8367C_PTP_PORT8_CFG1_MASK    0xFF
+
+#define    RTL8367C_REG_P8_MSIC1    0x011f
+#define    RTL8367C_P8_MSIC1_OFFSET    0
+#define    RTL8367C_P8_MSIC1_MASK    0x1
+
+#define    RTL8367C_REG_PORT9_CGST_HALF_CFG    0x0120
+#define    RTL8367C_PORT9_CGST_HALF_CFG_CONGESTION_TIME_OFFSET    4
+#define    RTL8367C_PORT9_CGST_HALF_CFG_CONGESTION_TIME_MASK    0xF0
+#define    RTL8367C_PORT9_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT9_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_PKTGEN_PORT9_CTRL    0x0121
+#define    RTL8367C_PKTGEN_PORT9_CTRL_STATUS_OFFSET    15
+#define    RTL8367C_PKTGEN_PORT9_CTRL_STATUS_MASK    0x8000
+#define    RTL8367C_PKTGEN_PORT9_CTRL_PKTGEN_STS_OFFSET    13
+#define    RTL8367C_PKTGEN_PORT9_CTRL_PKTGEN_STS_MASK    0x2000
+#define    RTL8367C_PKTGEN_PORT9_CTRL_CRC_NO_ERROR_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT9_CTRL_CRC_NO_ERROR_MASK    0x10
+#define    RTL8367C_PKTGEN_PORT9_CTRL_CMD_START_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT9_CTRL_CMD_START_MASK    0x1
+
+#define    RTL8367C_REG_TX_ERR_CNT_PORT9    0x0122
+#define    RTL8367C_TX_ERR_CNT_PORT9_OFFSET    0
+#define    RTL8367C_TX_ERR_CNT_PORT9_MASK    0x7
+
+#define    RTL8367C_REG_PKTGEN_PORT9_DA0    0x0123
+
+#define    RTL8367C_REG_PKTGEN_PORT9_DA1    0x0124
+
+#define    RTL8367C_REG_PKTGEN_PORT9_DA2    0x0125
+
+#define    RTL8367C_REG_PKTGEN_PORT9_SA0    0x0126
+
+#define    RTL8367C_REG_PKTGEN_PORT9_SA1    0x0127
+
+#define    RTL8367C_REG_PKTGEN_PORT9_SA2    0x0128
+
+#define    RTL8367C_REG_PKTGEN_PORT9_COUNTER0    0x0129
+
+#define    RTL8367C_REG_PKTGEN_PORT9_COUNTER1    0x012a
+#define    RTL8367C_PKTGEN_PORT9_COUNTER1_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT9_COUNTER1_MASK    0xFF
+
+#define    RTL8367C_REG_PKTGEN_PORT9_TX_LENGTH    0x012b
+#define    RTL8367C_PKTGEN_PORT9_TX_LENGTH_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT9_TX_LENGTH_MASK    0x3FFF
+
+#define    RTL8367C_REG_PKTGEN_PORT9_TIMER    0x012d
+#define    RTL8367C_PKTGEN_PORT9_TIMER_TIMER_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT9_TIMER_TIMER_MASK    0xF0
+#define    RTL8367C_PKTGEN_PORT9_TIMER_RX_DMA_ERR_FLAG_OFFSET    3
+#define    RTL8367C_PKTGEN_PORT9_TIMER_RX_DMA_ERR_FLAG_MASK    0x8
+
+#define    RTL8367C_REG_PORT9_MISC_CFG    0x012e
+#define    RTL8367C_PORT9_MISC_CFG_SMALL_TAG_IPG_OFFSET    15
+#define    RTL8367C_PORT9_MISC_CFG_SMALL_TAG_IPG_MASK    0x8000
+#define    RTL8367C_PORT9_MISC_CFG_TX_ITFSP_MODE_OFFSET    14
+#define    RTL8367C_PORT9_MISC_CFG_TX_ITFSP_MODE_MASK    0x4000
+#define    RTL8367C_PORT9_MISC_CFG_FLOWCTRL_INDEP_OFFSET    13
+#define    RTL8367C_PORT9_MISC_CFG_FLOWCTRL_INDEP_MASK    0x2000
+#define    RTL8367C_PORT9_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET    12
+#define    RTL8367C_PORT9_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK    0x1000
+#define    RTL8367C_PORT9_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET    11
+#define    RTL8367C_PORT9_MISC_CFG_INGRESSBW_FLOWCTRL_MASK    0x800
+#define    RTL8367C_PORT9_MISC_CFG_INGRESSBW_IFG_OFFSET    10
+#define    RTL8367C_PORT9_MISC_CFG_INGRESSBW_IFG_MASK    0x400
+#define    RTL8367C_PORT9_MISC_CFG_RX_SPC_OFFSET    9
+#define    RTL8367C_PORT9_MISC_CFG_RX_SPC_MASK    0x200
+#define    RTL8367C_PORT9_MISC_CFG_CRC_SKIP_OFFSET    8
+#define    RTL8367C_PORT9_MISC_CFG_CRC_SKIP_MASK    0x100
+#define    RTL8367C_PORT9_MISC_CFG_PKTGEN_TX_FIRST_OFFSET    7
+#define    RTL8367C_PORT9_MISC_CFG_PKTGEN_TX_FIRST_MASK    0x80
+#define    RTL8367C_PORT9_MISC_CFG_MAC_LOOPBACK_OFFSET    6
+#define    RTL8367C_PORT9_MISC_CFG_MAC_LOOPBACK_MASK    0x40
+#define    RTL8367C_PORT9_MISC_CFG_VLAN_EGRESS_MODE_OFFSET    4
+#define    RTL8367C_PORT9_MISC_CFG_VLAN_EGRESS_MODE_MASK    0x30
+#define    RTL8367C_PORT9_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT9_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_INGRESSBW_PORT9_RATE_CTRL0    0x012f
+
+#define    RTL8367C_REG_INGRESSBW_PORT9_RATE_CTRL1    0x0130
+#define    RTL8367C_INGRESSBW_PORT9_RATE_CTRL1_DUMMY_OFFSET    3
+#define    RTL8367C_INGRESSBW_PORT9_RATE_CTRL1_DUMMY_MASK    0xFFF8
+#define    RTL8367C_INGRESSBW_PORT9_RATE_CTRL1_INGRESSBW_RATE16_OFFSET    0
+#define    RTL8367C_INGRESSBW_PORT9_RATE_CTRL1_INGRESSBW_RATE16_MASK    0x7
+
+#define    RTL8367C_REG_PORT9_FORCE_RATE0    0x0131
+
+#define    RTL8367C_REG_PORT9_FORCE_RATE1    0x0132
+
+#define    RTL8367C_REG_PORT9_CURENT_RATE0    0x0133
+
+#define    RTL8367C_REG_PORT9_CURENT_RATE1    0x0134
+
+#define    RTL8367C_REG_PORT9_PAGE_COUNTER    0x0135
+#define    RTL8367C_PORT9_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_PORT9_PAGE_COUNTER_MASK    0x7F
+
+#define    RTL8367C_REG_PAGEMETER_PORT9_CTRL0    0x0136
+
+#define    RTL8367C_REG_PAGEMETER_PORT9_CTRL1    0x0137
+
+#define    RTL8367C_REG_PORT9_EEECFG    0x0138
+#define    RTL8367C_PORT9_EEECFG_EEEP_ENABLE_TX_OFFSET    14
+#define    RTL8367C_PORT9_EEECFG_EEEP_ENABLE_TX_MASK    0x4000
+#define    RTL8367C_PORT9_EEECFG_EEEP_ENABLE_RX_OFFSET    13
+#define    RTL8367C_PORT9_EEECFG_EEEP_ENABLE_RX_MASK    0x2000
+#define    RTL8367C_PORT9_EEECFG_EEE_FORCE_OFFSET    12
+#define    RTL8367C_PORT9_EEECFG_EEE_FORCE_MASK    0x1000
+#define    RTL8367C_PORT9_EEECFG_EEE_100M_OFFSET    11
+#define    RTL8367C_PORT9_EEECFG_EEE_100M_MASK    0x800
+#define    RTL8367C_PORT9_EEECFG_EEE_GIGA_500M_OFFSET    10
+#define    RTL8367C_PORT9_EEECFG_EEE_GIGA_500M_MASK    0x400
+#define    RTL8367C_PORT9_EEECFG_EEE_TX_OFFSET    9
+#define    RTL8367C_PORT9_EEECFG_EEE_TX_MASK    0x200
+#define    RTL8367C_PORT9_EEECFG_EEE_RX_OFFSET    8
+#define    RTL8367C_PORT9_EEECFG_EEE_RX_MASK    0x100
+#define    RTL8367C_PORT9_EEECFG_EEE_DSP_RX_OFFSET    6
+#define    RTL8367C_PORT9_EEECFG_EEE_DSP_RX_MASK    0x40
+#define    RTL8367C_PORT9_EEECFG_EEE_LPI_OFFSET    5
+#define    RTL8367C_PORT9_EEECFG_EEE_LPI_MASK    0x20
+#define    RTL8367C_PORT9_EEECFG_EEE_TX_LPI_OFFSET    4
+#define    RTL8367C_PORT9_EEECFG_EEE_TX_LPI_MASK    0x10
+#define    RTL8367C_PORT9_EEECFG_EEE_RX_LPI_OFFSET    3
+#define    RTL8367C_PORT9_EEECFG_EEE_RX_LPI_MASK    0x8
+#define    RTL8367C_PORT9_EEECFG_EEE_PAUSE_INDICATOR_OFFSET    2
+#define    RTL8367C_PORT9_EEECFG_EEE_PAUSE_INDICATOR_MASK    0x4
+#define    RTL8367C_PORT9_EEECFG_EEE_WAKE_REQ_OFFSET    1
+#define    RTL8367C_PORT9_EEECFG_EEE_WAKE_REQ_MASK    0x2
+#define    RTL8367C_PORT9_EEECFG_EEE_SLEEP_REQ_OFFSET    0
+#define    RTL8367C_PORT9_EEECFG_EEE_SLEEP_REQ_MASK    0x1
+
+#define    RTL8367C_REG_PORT9_EEETXMTR    0x0139
+
+#define    RTL8367C_REG_PORT9_EEERXMTR    0x013a
+
+#define    RTL8367C_REG_PORT9_EEEPTXMTR    0x013b
+
+#define    RTL8367C_REG_PORT9_EEEPRXMTR    0x013c
+
+#define    RTL8367C_REG_PTP_PORT9_CFG1    0x013e
+#define    RTL8367C_PTP_PORT9_CFG1_OFFSET    7
+#define    RTL8367C_PTP_PORT9_CFG1_MASK    0xFF
+
+#define    RTL8367C_REG_P9_MSIC1    0x013f
+#define    RTL8367C_P9_MSIC1_OFFSET    0
+#define    RTL8367C_P9_MSIC1_MASK    0x1
+
+#define    RTL8367C_REG_PORT10_CGST_HALF_CFG    0x0140
+#define    RTL8367C_PORT10_CGST_HALF_CFG_CONGESTION_TIME_OFFSET    4
+#define    RTL8367C_PORT10_CGST_HALF_CFG_CONGESTION_TIME_MASK    0xF0
+#define    RTL8367C_PORT10_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT10_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_PKTGEN_PORT10_CTRL    0x0141
+#define    RTL8367C_PKTGEN_PORT10_CTRL_STATUS_OFFSET    15
+#define    RTL8367C_PKTGEN_PORT10_CTRL_STATUS_MASK    0x8000
+#define    RTL8367C_PKTGEN_PORT10_CTRL_PKTGEN_STS_OFFSET    13
+#define    RTL8367C_PKTGEN_PORT10_CTRL_PKTGEN_STS_MASK    0x2000
+#define    RTL8367C_PKTGEN_PORT10_CTRL_CRC_NO_ERROR_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT10_CTRL_CRC_NO_ERROR_MASK    0x10
+#define    RTL8367C_PKTGEN_PORT10_CTRL_CMD_START_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT10_CTRL_CMD_START_MASK    0x1
+
+#define    RTL8367C_REG_TX_ERR_CNT_PORT10    0x0142
+#define    RTL8367C_TX_ERR_CNT_PORT10_OFFSET    0
+#define    RTL8367C_TX_ERR_CNT_PORT10_MASK    0x7
+
+#define    RTL8367C_REG_PKTGEN_PORT10_DA0    0x0143
+
+#define    RTL8367C_REG_PKTGEN_PORT10_DA1    0x0144
+
+#define    RTL8367C_REG_PKTGEN_PORT10_DA2    0x0145
+
+#define    RTL8367C_REG_PKTGEN_PORT10_SA0    0x0146
+
+#define    RTL8367C_REG_PKTGEN_PORT10_SA1    0x0147
+
+#define    RTL8367C_REG_PKTGEN_PORT10_SA2    0x0148
+
+#define    RTL8367C_REG_PKTGEN_PORT10_COUNTER0    0x0149
+
+#define    RTL8367C_REG_PKTGEN_PORT10_COUNTER1    0x014a
+#define    RTL8367C_PKTGEN_PORT10_COUNTER1_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT10_COUNTER1_MASK    0xFF
+
+#define    RTL8367C_REG_PKTGEN_PORT10_TX_LENGTH    0x014b
+#define    RTL8367C_PKTGEN_PORT10_TX_LENGTH_OFFSET    0
+#define    RTL8367C_PKTGEN_PORT10_TX_LENGTH_MASK    0x3FFF
+
+#define    RTL8367C_REG_PKTGEN_PORT10_TIMER    0x014d
+#define    RTL8367C_PKTGEN_PORT10_TIMER_TIMER_OFFSET    4
+#define    RTL8367C_PKTGEN_PORT10_TIMER_TIMER_MASK    0xF0
+#define    RTL8367C_PKTGEN_PORT10_TIMER_RX_DMA_ERR_FLAG_OFFSET    3
+#define    RTL8367C_PKTGEN_PORT10_TIMER_RX_DMA_ERR_FLAG_MASK    0x8
+
+#define    RTL8367C_REG_PORT10_MISC_CFG    0x014e
+#define    RTL8367C_PORT10_MISC_CFG_SMALL_TAG_IPG_OFFSET    15
+#define    RTL8367C_PORT10_MISC_CFG_SMALL_TAG_IPG_MASK    0x8000
+#define    RTL8367C_PORT10_MISC_CFG_TX_ITFSP_MODE_OFFSET    14
+#define    RTL8367C_PORT10_MISC_CFG_TX_ITFSP_MODE_MASK    0x4000
+#define    RTL8367C_PORT10_MISC_CFG_FLOWCTRL_INDEP_OFFSET    13
+#define    RTL8367C_PORT10_MISC_CFG_FLOWCTRL_INDEP_MASK    0x2000
+#define    RTL8367C_PORT10_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET    12
+#define    RTL8367C_PORT10_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK    0x1000
+#define    RTL8367C_PORT10_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET    11
+#define    RTL8367C_PORT10_MISC_CFG_INGRESSBW_FLOWCTRL_MASK    0x800
+#define    RTL8367C_PORT10_MISC_CFG_INGRESSBW_IFG_OFFSET    10
+#define    RTL8367C_PORT10_MISC_CFG_INGRESSBW_IFG_MASK    0x400
+#define    RTL8367C_PORT10_MISC_CFG_RX_SPC_OFFSET    9
+#define    RTL8367C_PORT10_MISC_CFG_RX_SPC_MASK    0x200
+#define    RTL8367C_PORT10_MISC_CFG_CRC_SKIP_OFFSET    8
+#define    RTL8367C_PORT10_MISC_CFG_CRC_SKIP_MASK    0x100
+#define    RTL8367C_PORT10_MISC_CFG_PKTGEN_TX_FIRST_OFFSET    7
+#define    RTL8367C_PORT10_MISC_CFG_PKTGEN_TX_FIRST_MASK    0x80
+#define    RTL8367C_PORT10_MISC_CFG_MAC_LOOPBACK_OFFSET    6
+#define    RTL8367C_PORT10_MISC_CFG_MAC_LOOPBACK_MASK    0x40
+#define    RTL8367C_PORT10_MISC_CFG_VLAN_EGRESS_MODE_OFFSET    4
+#define    RTL8367C_PORT10_MISC_CFG_VLAN_EGRESS_MODE_MASK    0x30
+#define    RTL8367C_PORT10_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET    0
+#define    RTL8367C_PORT10_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK    0xF
+
+#define    RTL8367C_REG_INGRESSBW_PORT10_RATE_CTRL0    0x014f
+
+#define    RTL8367C_REG_INGRESSBW_PORT10_RATE_CTRL1    0x0150
+#define    RTL8367C_INGRESSBW_PORT10_RATE_CTRL1_DUMMY_OFFSET    3
+#define    RTL8367C_INGRESSBW_PORT10_RATE_CTRL1_DUMMY_MASK    0xFFF8
+#define    RTL8367C_INGRESSBW_PORT10_RATE_CTRL1_INGRESSBW_RATE16_OFFSET    0
+#define    RTL8367C_INGRESSBW_PORT10_RATE_CTRL1_INGRESSBW_RATE16_MASK    0x7
+
+#define    RTL8367C_REG_PORT10_FORCE_RATE0    0x0151
+
+#define    RTL8367C_REG_PORT10_FORCE_RATE1    0x0152
+
+#define    RTL8367C_REG_PORT10_CURENT_RATE0    0x0153
+
+#define    RTL8367C_REG_PORT10_CURENT_RATE1    0x0154
+
+#define    RTL8367C_REG_PORT10_PAGE_COUNTER    0x0155
+#define    RTL8367C_PORT10_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_PORT10_PAGE_COUNTER_MASK    0x7F
+
+#define    RTL8367C_REG_PAGEMETER_PORT10_CTRL0    0x0156
+
+#define    RTL8367C_REG_PAGEMETER_PORT10_CTRL1    0x0157
+
+#define    RTL8367C_REG_PORT10_EEECFG    0x0158
+#define    RTL8367C_PORT10_EEECFG_EEEP_ENABLE_TX_OFFSET    14
+#define    RTL8367C_PORT10_EEECFG_EEEP_ENABLE_TX_MASK    0x4000
+#define    RTL8367C_PORT10_EEECFG_EEEP_ENABLE_RX_OFFSET    13
+#define    RTL8367C_PORT10_EEECFG_EEEP_ENABLE_RX_MASK    0x2000
+#define    RTL8367C_PORT10_EEECFG_EEE_FORCE_OFFSET    12
+#define    RTL8367C_PORT10_EEECFG_EEE_FORCE_MASK    0x1000
+#define    RTL8367C_PORT10_EEECFG_EEE_100M_OFFSET    11
+#define    RTL8367C_PORT10_EEECFG_EEE_100M_MASK    0x800
+#define    RTL8367C_PORT10_EEECFG_EEE_GIGA_500M_OFFSET    10
+#define    RTL8367C_PORT10_EEECFG_EEE_GIGA_500M_MASK    0x400
+#define    RTL8367C_PORT10_EEECFG_EEE_TX_OFFSET    9
+#define    RTL8367C_PORT10_EEECFG_EEE_TX_MASK    0x200
+#define    RTL8367C_PORT10_EEECFG_EEE_RX_OFFSET    8
+#define    RTL8367C_PORT10_EEECFG_EEE_RX_MASK    0x100
+#define    RTL8367C_PORT10_EEECFG_EEE_DSP_RX_OFFSET    6
+#define    RTL8367C_PORT10_EEECFG_EEE_DSP_RX_MASK    0x40
+#define    RTL8367C_PORT10_EEECFG_EEE_LPI_OFFSET    5
+#define    RTL8367C_PORT10_EEECFG_EEE_LPI_MASK    0x20
+#define    RTL8367C_PORT10_EEECFG_EEE_TX_LPI_OFFSET    4
+#define    RTL8367C_PORT10_EEECFG_EEE_TX_LPI_MASK    0x10
+#define    RTL8367C_PORT10_EEECFG_EEE_RX_LPI_OFFSET    3
+#define    RTL8367C_PORT10_EEECFG_EEE_RX_LPI_MASK    0x8
+#define    RTL8367C_PORT10_EEECFG_EEE_PAUSE_INDICATOR_OFFSET    2
+#define    RTL8367C_PORT10_EEECFG_EEE_PAUSE_INDICATOR_MASK    0x4
+#define    RTL8367C_PORT10_EEECFG_EEE_WAKE_REQ_OFFSET    1
+#define    RTL8367C_PORT10_EEECFG_EEE_WAKE_REQ_MASK    0x2
+#define    RTL8367C_PORT10_EEECFG_EEE_SLEEP_REQ_OFFSET    0
+#define    RTL8367C_PORT10_EEECFG_EEE_SLEEP_REQ_MASK    0x1
+
+#define    RTL8367C_REG_PORT10_EEETXMTR    0x0159
+
+#define    RTL8367C_REG_PORT10_EEERXMTR    0x015a
+
+#define    RTL8367C_REG_PORT10_EEEPTXMTR    0x015b
+
+#define    RTL8367C_REG_PORT10_EEEPRXMTR    0x015c
+
+#define    RTL8367C_REG_PTP_PORT10_CFG1    0x015e
+#define    RTL8367C_PTP_PORT10_CFG1_OFFSET    7
+#define    RTL8367C_PTP_PORT10_CFG1_MASK    0xFF
+
+#define    RTL8367C_REG_P10_MSIC1    0x015f
+#define    RTL8367C_P10_MSIC1_OFFSET    0
+#define    RTL8367C_P10_MSIC1_MASK    0x1
+
+/* (16'h0200)outq_reg */
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE0_DROP_ON    0x0200
+#define    RTL8367C_FLOWCTRL_QUEUE0_DROP_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE0_DROP_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE1_DROP_ON    0x0201
+#define    RTL8367C_FLOWCTRL_QUEUE1_DROP_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE1_DROP_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE2_DROP_ON    0x0202
+#define    RTL8367C_FLOWCTRL_QUEUE2_DROP_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE2_DROP_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE3_DROP_ON    0x0203
+#define    RTL8367C_FLOWCTRL_QUEUE3_DROP_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE3_DROP_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE4_DROP_ON    0x0204
+#define    RTL8367C_FLOWCTRL_QUEUE4_DROP_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE4_DROP_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE5_DROP_ON    0x0205
+#define    RTL8367C_FLOWCTRL_QUEUE5_DROP_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE5_DROP_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE6_DROP_ON    0x0206
+#define    RTL8367C_FLOWCTRL_QUEUE6_DROP_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE6_DROP_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE7_DROP_ON    0x0207
+#define    RTL8367C_FLOWCTRL_QUEUE7_DROP_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE7_DROP_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT0_DROP_ON    0x0208
+#define    RTL8367C_FLOWCTRL_PORT0_DROP_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT0_DROP_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT1_DROP_ON    0x0209
+#define    RTL8367C_FLOWCTRL_PORT1_DROP_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT1_DROP_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT2_DROP_ON    0x020a
+#define    RTL8367C_FLOWCTRL_PORT2_DROP_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT2_DROP_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT3_DROP_ON    0x020b
+#define    RTL8367C_FLOWCTRL_PORT3_DROP_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT3_DROP_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT4_DROP_ON    0x020c
+#define    RTL8367C_FLOWCTRL_PORT4_DROP_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT4_DROP_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT5_DROP_ON    0x020d
+#define    RTL8367C_FLOWCTRL_PORT5_DROP_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT5_DROP_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT6_DROP_ON    0x020e
+#define    RTL8367C_FLOWCTRL_PORT6_DROP_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT6_DROP_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT7_DROP_ON    0x020f
+#define    RTL8367C_FLOWCTRL_PORT7_DROP_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT7_DROP_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT8_DROP_ON    0x0210
+#define    RTL8367C_FLOWCTRL_PORT8_DROP_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT8_DROP_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT9_DROP_ON    0x0211
+#define    RTL8367C_FLOWCTRL_PORT9_DROP_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT9_DROP_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT10_DROP_ON    0x0212
+#define    RTL8367C_FLOWCTRL_PORT10_DROP_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT10_DROP_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT_GAP    0x0218
+#define    RTL8367C_FLOWCTRL_PORT_GAP_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT_GAP_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE_GAP    0x0219
+#define    RTL8367C_FLOWCTRL_QUEUE_GAP_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE_GAP_MASK    0x7FF
+
+#define    RTL8367C_REG_PORT_QEMPTY    0x022d
+#define    RTL8367C_PORT_QEMPTY_OFFSET    0
+#define    RTL8367C_PORT_QEMPTY_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_DEBUG_CTRL0    0x022e
+#define    RTL8367C_FLOWCTRL_DEBUG_CTRL0_OFFSET    0
+#define    RTL8367C_FLOWCTRL_DEBUG_CTRL0_MASK    0xF
+
+#define    RTL8367C_REG_FLOWCTRL_DEBUG_CTRL1    0x022f
+#define    RTL8367C_TOTAL_OFFSET    9
+#define    RTL8367C_TOTAL_MASK    0x200
+#define    RTL8367C_PORT_MAX_OFFSET    8
+#define    RTL8367C_PORT_MAX_MASK    0x100
+#define    RTL8367C_QMAX_MASK_OFFSET    0
+#define    RTL8367C_QMAX_MASK_MASK    0xFF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE0_PAGE_COUNT    0x0230
+#define    RTL8367C_FLOWCTRL_QUEUE0_PAGE_COUNT_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE0_PAGE_COUNT_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE1_PAGE_COUNT    0x0231
+#define    RTL8367C_FLOWCTRL_QUEUE1_PAGE_COUNT_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE1_PAGE_COUNT_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE2_PAGE_COUNT    0x0232
+#define    RTL8367C_FLOWCTRL_QUEUE2_PAGE_COUNT_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE2_PAGE_COUNT_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE3_PAGE_COUNT    0x0233
+#define    RTL8367C_FLOWCTRL_QUEUE3_PAGE_COUNT_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE3_PAGE_COUNT_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE4_PAGE_COUNT    0x0234
+#define    RTL8367C_FLOWCTRL_QUEUE4_PAGE_COUNT_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE4_PAGE_COUNT_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE5_PAGE_COUNT    0x0235
+#define    RTL8367C_FLOWCTRL_QUEUE5_PAGE_COUNT_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE5_PAGE_COUNT_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE6_PAGE_COUNT    0x0236
+#define    RTL8367C_FLOWCTRL_QUEUE6_PAGE_COUNT_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE6_PAGE_COUNT_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE7_PAGE_COUNT    0x0237
+#define    RTL8367C_FLOWCTRL_QUEUE7_PAGE_COUNT_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE7_PAGE_COUNT_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT_PAGE_COUNT    0x0238
+#define    RTL8367C_FLOWCTRL_PORT_PAGE_COUNT_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT_PAGE_COUNT_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE0_MAX_PAGE_COUNT    0x0239
+#define    RTL8367C_FLOWCTRL_QUEUE0_MAX_PAGE_COUNT_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE0_MAX_PAGE_COUNT_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE1_MAX_PAGE_COUNT    0x023a
+#define    RTL8367C_FLOWCTRL_QUEUE1_MAX_PAGE_COUNT_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE1_MAX_PAGE_COUNT_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE2_MAX_PAGE_COUNT    0x023b
+#define    RTL8367C_FLOWCTRL_QUEUE2_MAX_PAGE_COUNT_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE2_MAX_PAGE_COUNT_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE3_MAX_PAGE_COUNT    0x023c
+#define    RTL8367C_FLOWCTRL_QUEUE3_MAX_PAGE_COUNT_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE3_MAX_PAGE_COUNT_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE4_MAX_PAGE_COUNT    0x023d
+#define    RTL8367C_FLOWCTRL_QUEUE4_MAX_PAGE_COUNT_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE4_MAX_PAGE_COUNT_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE5_MAX_PAGE_COUNT    0x023e
+#define    RTL8367C_FLOWCTRL_QUEUE5_MAX_PAGE_COUNT_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE5_MAX_PAGE_COUNT_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE6_MAX_PAGE_COUNT    0x023f
+#define    RTL8367C_FLOWCTRL_QUEUE6_MAX_PAGE_COUNT_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE6_MAX_PAGE_COUNT_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_QUEUE7_MAX_PAGE_COUNT    0x0240
+#define    RTL8367C_FLOWCTRL_QUEUE7_MAX_PAGE_COUNT_OFFSET    0
+#define    RTL8367C_FLOWCTRL_QUEUE7_MAX_PAGE_COUNT_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT_MAX_PAGE_COUNT    0x0241
+#define    RTL8367C_FLOWCTRL_PORT_MAX_PAGE_COUNT_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT_MAX_PAGE_COUNT_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_TOTAL_PACKET_COUNT    0x0243
+
+#define    RTL8367C_REG_HIGH_QUEUE_MASK0    0x0244
+#define    RTL8367C_PORT1_HIGH_QUEUE_MASK_OFFSET    8
+#define    RTL8367C_PORT1_HIGH_QUEUE_MASK_MASK    0xFF00
+#define    RTL8367C_PORT0_HIGH_QUEUE_MASK_OFFSET    0
+#define    RTL8367C_PORT0_HIGH_QUEUE_MASK_MASK    0xFF
+
+#define    RTL8367C_REG_HIGH_QUEUE_MASK1    0x0245
+#define    RTL8367C_PORT3_HIGH_QUEUE_MASK_OFFSET    8
+#define    RTL8367C_PORT3_HIGH_QUEUE_MASK_MASK    0xFF00
+#define    RTL8367C_PORT2_HIGH_QUEUE_MASK_OFFSET    0
+#define    RTL8367C_PORT2_HIGH_QUEUE_MASK_MASK    0xFF
+
+#define    RTL8367C_REG_HIGH_QUEUE_MASK2    0x0246
+#define    RTL8367C_PORT5_HIGH_QUEUE_MASK_OFFSET    8
+#define    RTL8367C_PORT5_HIGH_QUEUE_MASK_MASK    0xFF00
+#define    RTL8367C_PORT4_HIGH_QUEUE_MASK_OFFSET    0
+#define    RTL8367C_PORT4_HIGH_QUEUE_MASK_MASK    0xFF
+
+#define    RTL8367C_REG_HIGH_QUEUE_MASK3    0x0247
+#define    RTL8367C_PORT7_HIGH_QUEUE_MASK_OFFSET    8
+#define    RTL8367C_PORT7_HIGH_QUEUE_MASK_MASK    0xFF00
+#define    RTL8367C_PORT6_HIGH_QUEUE_MASK_OFFSET    0
+#define    RTL8367C_PORT6_HIGH_QUEUE_MASK_MASK    0xFF
+
+#define    RTL8367C_REG_HIGH_QUEUE_MASK4    0x0248
+#define    RTL8367C_PORT9_HIGH_QUEUE_MASK_OFFSET    8
+#define    RTL8367C_PORT9_HIGH_QUEUE_MASK_MASK    0xFF00
+#define    RTL8367C_PORT8_HIGH_QUEUE_MASK_OFFSET    0
+#define    RTL8367C_PORT8_HIGH_QUEUE_MASK_MASK    0xFF
+
+#define    RTL8367C_REG_HIGH_QUEUE_MASK5    0x0249
+#define    RTL8367C_HIGH_QUEUE_MASK5_OFFSET    0
+#define    RTL8367C_HIGH_QUEUE_MASK5_MASK    0xFF
+
+#define    RTL8367C_REG_LOW_QUEUE_TH    0x024c
+#define    RTL8367C_LOW_QUEUE_TH_OFFSET    0
+#define    RTL8367C_LOW_QUEUE_TH_MASK    0x7FF
+
+#define    RTL8367C_REG_TH_TX_PREFET    0x0250
+#define    RTL8367C_TH_TX_PREFET_OFFSET    0
+#define    RTL8367C_TH_TX_PREFET_MASK    0xFF
+
+#define    RTL8367C_REG_DUMMY_0251    0x0251
+
+#define    RTL8367C_REG_DUMMY_0252    0x0252
+
+#define    RTL8367C_REG_DUMMY_0253    0x0253
+
+#define    RTL8367C_REG_DUMMY_0254    0x0254
+
+#define    RTL8367C_REG_DUMMY_0255    0x0255
+
+#define    RTL8367C_REG_DUMMY_0256    0x0256
+
+#define    RTL8367C_REG_DUMMY_0257    0x0257
+
+#define    RTL8367C_REG_DUMMY_0258    0x0258
+
+#define    RTL8367C_REG_DUMMY_0259    0x0259
+
+#define    RTL8367C_REG_DUMMY_025A    0x025A
+
+#define    RTL8367C_REG_DUMMY_025B    0x025B
+
+#define    RTL8367C_REG_DUMMY_025C    0x025C
+
+#define    RTL8367C_REG_Q_TXPKT_CNT_CTL    0x025d
+#define    RTL8367C_QUEUE_PKT_CNT_CLR_OFFSET    4
+#define    RTL8367C_QUEUE_PKT_CNT_CLR_MASK    0x10
+#define    RTL8367C_PORT_ID_QUEUE_PKT_CNT_OFFSET    0
+#define    RTL8367C_PORT_ID_QUEUE_PKT_CNT_MASK    0xF
+
+#define    RTL8367C_REG_Q0_TXPKT_CNT_L    0x025e
+
+#define    RTL8367C_REG_Q0_TXPKT_CNT_H    0x025f
+
+#define    RTL8367C_REG_Q1_TXPKT_CNT_L    0x0260
+
+#define    RTL8367C_REG_Q1_TXPKT_CNT_H    0x0261
+
+#define    RTL8367C_REG_Q2_TXPKT_CNT_L    0x0262
+
+#define    RTL8367C_REG_Q2_TXPKT_CNT_H    0x0263
+
+#define    RTL8367C_REG_Q3_TXPKT_CNT_L    0x0264
+
+#define    RTL8367C_REG_Q3_TXPKT_CNT_H    0x0265
+
+#define    RTL8367C_REG_Q4_TXPKT_CNT_L    0x0266
+
+#define    RTL8367C_REG_Q4_TXPKT_CNT_H    0x0267
+
+#define    RTL8367C_REG_Q5_TXPKT_CNT_L    0x0268
+
+#define    RTL8367C_REG_Q5_TXPKT_CNT_H    0x0269
+
+#define    RTL8367C_REG_Q6_TXPKT_CNT_L    0x026a
+
+#define    RTL8367C_REG_Q6_TXPKT_CNT_H    0x026b
+
+#define    RTL8367C_REG_Q7_TXPKT_CNT_L    0x026c
+
+#define    RTL8367C_REG_Q7_TXPKT_CNT_H    0x026d
+
+/* (16'h0300)sch_reg */
+
+#define    RTL8367C_REG_SCHEDULE_WFQ_CTRL    0x0300
+#define    RTL8367C_SCHEDULE_WFQ_CTRL_OFFSET    0
+#define    RTL8367C_SCHEDULE_WFQ_CTRL_MASK    0x1
+
+#define    RTL8367C_REG_SCHEDULE_WFQ_BURST_SIZE    0x0301
+
+#define    RTL8367C_REG_SCHEDULE_QUEUE_TYPE_CTRL0    0x0302
+#define    RTL8367C_PORT1_QUEUE7_TYPE_OFFSET    15
+#define    RTL8367C_PORT1_QUEUE7_TYPE_MASK    0x8000
+#define    RTL8367C_PORT1_QUEUE6_TYPE_OFFSET    14
+#define    RTL8367C_PORT1_QUEUE6_TYPE_MASK    0x4000
+#define    RTL8367C_PORT1_QUEUE5_TYPE_OFFSET    13
+#define    RTL8367C_PORT1_QUEUE5_TYPE_MASK    0x2000
+#define    RTL8367C_PORT1_QUEUE4_TYPE_OFFSET    12
+#define    RTL8367C_PORT1_QUEUE4_TYPE_MASK    0x1000
+#define    RTL8367C_PORT1_QUEUE3_TYPE_OFFSET    11
+#define    RTL8367C_PORT1_QUEUE3_TYPE_MASK    0x800
+#define    RTL8367C_PORT1_QUEUE2_TYPE_OFFSET    10
+#define    RTL8367C_PORT1_QUEUE2_TYPE_MASK    0x400
+#define    RTL8367C_PORT1_QUEUE1_TYPE_OFFSET    9
+#define    RTL8367C_PORT1_QUEUE1_TYPE_MASK    0x200
+#define    RTL8367C_PORT1_QUEUE0_TYPE_OFFSET    8
+#define    RTL8367C_PORT1_QUEUE0_TYPE_MASK    0x100
+#define    RTL8367C_PORT0_QUEUE7_TYPE_OFFSET    7
+#define    RTL8367C_PORT0_QUEUE7_TYPE_MASK    0x80
+#define    RTL8367C_PORT0_QUEUE6_TYPE_OFFSET    6
+#define    RTL8367C_PORT0_QUEUE6_TYPE_MASK    0x40
+#define    RTL8367C_PORT0_QUEUE5_TYPE_OFFSET    5
+#define    RTL8367C_PORT0_QUEUE5_TYPE_MASK    0x20
+#define    RTL8367C_PORT0_QUEUE4_TYPE_OFFSET    4
+#define    RTL8367C_PORT0_QUEUE4_TYPE_MASK    0x10
+#define    RTL8367C_PORT0_QUEUE3_TYPE_OFFSET    3
+#define    RTL8367C_PORT0_QUEUE3_TYPE_MASK    0x8
+#define    RTL8367C_PORT0_QUEUE2_TYPE_OFFSET    2
+#define    RTL8367C_PORT0_QUEUE2_TYPE_MASK    0x4
+#define    RTL8367C_PORT0_QUEUE1_TYPE_OFFSET    1
+#define    RTL8367C_PORT0_QUEUE1_TYPE_MASK    0x2
+#define    RTL8367C_PORT0_QUEUE0_TYPE_OFFSET    0
+#define    RTL8367C_PORT0_QUEUE0_TYPE_MASK    0x1
+
+#define    RTL8367C_REG_SCHEDULE_QUEUE_TYPE_CTRL1    0x0303
+#define    RTL8367C_PORT3_QUEUE7_TYPE_OFFSET    15
+#define    RTL8367C_PORT3_QUEUE7_TYPE_MASK    0x8000
+#define    RTL8367C_PORT3_QUEUE6_TYPE_OFFSET    14
+#define    RTL8367C_PORT3_QUEUE6_TYPE_MASK    0x4000
+#define    RTL8367C_PORT3_QUEUE5_TYPE_OFFSET    13
+#define    RTL8367C_PORT3_QUEUE5_TYPE_MASK    0x2000
+#define    RTL8367C_PORT3_QUEUE4_TYPE_OFFSET    12
+#define    RTL8367C_PORT3_QUEUE4_TYPE_MASK    0x1000
+#define    RTL8367C_PORT3_QUEUE3_TYPE_OFFSET    11
+#define    RTL8367C_PORT3_QUEUE3_TYPE_MASK    0x800
+#define    RTL8367C_PORT3_QUEUE2_TYPE_OFFSET    10
+#define    RTL8367C_PORT3_QUEUE2_TYPE_MASK    0x400
+#define    RTL8367C_PORT3_QUEUE1_TYPE_OFFSET    9
+#define    RTL8367C_PORT3_QUEUE1_TYPE_MASK    0x200
+#define    RTL8367C_PORT3_QUEUE0_TYPE_OFFSET    8
+#define    RTL8367C_PORT3_QUEUE0_TYPE_MASK    0x100
+#define    RTL8367C_PORT2_QUEUE7_TYPE_OFFSET    7
+#define    RTL8367C_PORT2_QUEUE7_TYPE_MASK    0x80
+#define    RTL8367C_PORT2_QUEUE6_TYPE_OFFSET    6
+#define    RTL8367C_PORT2_QUEUE6_TYPE_MASK    0x40
+#define    RTL8367C_PORT2_QUEUE5_TYPE_OFFSET    5
+#define    RTL8367C_PORT2_QUEUE5_TYPE_MASK    0x20
+#define    RTL8367C_PORT2_QUEUE4_TYPE_OFFSET    4
+#define    RTL8367C_PORT2_QUEUE4_TYPE_MASK    0x10
+#define    RTL8367C_PORT2_QUEUE3_TYPE_OFFSET    3
+#define    RTL8367C_PORT2_QUEUE3_TYPE_MASK    0x8
+#define    RTL8367C_PORT2_QUEUE2_TYPE_OFFSET    2
+#define    RTL8367C_PORT2_QUEUE2_TYPE_MASK    0x4
+#define    RTL8367C_PORT2_QUEUE1_TYPE_OFFSET    1
+#define    RTL8367C_PORT2_QUEUE1_TYPE_MASK    0x2
+#define    RTL8367C_PORT2_QUEUE0_TYPE_OFFSET    0
+#define    RTL8367C_PORT2_QUEUE0_TYPE_MASK    0x1
+
+#define    RTL8367C_REG_SCHEDULE_QUEUE_TYPE_CTRL2    0x0304
+#define    RTL8367C_PORT5_QUEUE7_TYPE_OFFSET    15
+#define    RTL8367C_PORT5_QUEUE7_TYPE_MASK    0x8000
+#define    RTL8367C_PORT5_QUEUE6_TYPE_OFFSET    14
+#define    RTL8367C_PORT5_QUEUE6_TYPE_MASK    0x4000
+#define    RTL8367C_PORT5_QUEUE5_TYPE_OFFSET    13
+#define    RTL8367C_PORT5_QUEUE5_TYPE_MASK    0x2000
+#define    RTL8367C_PORT5_QUEUE4_TYPE_OFFSET    12
+#define    RTL8367C_PORT5_QUEUE4_TYPE_MASK    0x1000
+#define    RTL8367C_PORT5_QUEUE3_TYPE_OFFSET    11
+#define    RTL8367C_PORT5_QUEUE3_TYPE_MASK    0x800
+#define    RTL8367C_PORT5_QUEUE2_TYPE_OFFSET    10
+#define    RTL8367C_PORT5_QUEUE2_TYPE_MASK    0x400
+#define    RTL8367C_PORT5_QUEUE1_TYPE_OFFSET    9
+#define    RTL8367C_PORT5_QUEUE1_TYPE_MASK    0x200
+#define    RTL8367C_PORT5_QUEUE0_TYPE_OFFSET    8
+#define    RTL8367C_PORT5_QUEUE0_TYPE_MASK    0x100
+#define    RTL8367C_PORT4_QUEUE7_TYPE_OFFSET    7
+#define    RTL8367C_PORT4_QUEUE7_TYPE_MASK    0x80
+#define    RTL8367C_PORT4_QUEUE6_TYPE_OFFSET    6
+#define    RTL8367C_PORT4_QUEUE6_TYPE_MASK    0x40
+#define    RTL8367C_PORT4_QUEUE5_TYPE_OFFSET    5
+#define    RTL8367C_PORT4_QUEUE5_TYPE_MASK    0x20
+#define    RTL8367C_PORT4_QUEUE4_TYPE_OFFSET    4
+#define    RTL8367C_PORT4_QUEUE4_TYPE_MASK    0x10
+#define    RTL8367C_PORT4_QUEUE3_TYPE_OFFSET    3
+#define    RTL8367C_PORT4_QUEUE3_TYPE_MASK    0x8
+#define    RTL8367C_PORT4_QUEUE2_TYPE_OFFSET    2
+#define    RTL8367C_PORT4_QUEUE2_TYPE_MASK    0x4
+#define    RTL8367C_PORT4_QUEUE1_TYPE_OFFSET    1
+#define    RTL8367C_PORT4_QUEUE1_TYPE_MASK    0x2
+#define    RTL8367C_PORT4_QUEUE0_TYPE_OFFSET    0
+#define    RTL8367C_PORT4_QUEUE0_TYPE_MASK    0x1
+
+#define    RTL8367C_REG_SCHEDULE_QUEUE_TYPE_CTRL3    0x0305
+#define    RTL8367C_PORT7_QUEUE7_TYPE_OFFSET    15
+#define    RTL8367C_PORT7_QUEUE7_TYPE_MASK    0x8000
+#define    RTL8367C_PORT7_QUEUE6_TYPE_OFFSET    14
+#define    RTL8367C_PORT7_QUEUE6_TYPE_MASK    0x4000
+#define    RTL8367C_PORT7_QUEUE5_TYPE_OFFSET    13
+#define    RTL8367C_PORT7_QUEUE5_TYPE_MASK    0x2000
+#define    RTL8367C_PORT7_QUEUE4_TYPE_OFFSET    12
+#define    RTL8367C_PORT7_QUEUE4_TYPE_MASK    0x1000
+#define    RTL8367C_PORT7_QUEUE3_TYPE_OFFSET    11
+#define    RTL8367C_PORT7_QUEUE3_TYPE_MASK    0x800
+#define    RTL8367C_PORT7_QUEUE2_TYPE_OFFSET    10
+#define    RTL8367C_PORT7_QUEUE2_TYPE_MASK    0x400
+#define    RTL8367C_PORT7_QUEUE1_TYPE_OFFSET    9
+#define    RTL8367C_PORT7_QUEUE1_TYPE_MASK    0x200
+#define    RTL8367C_PORT7_QUEUE0_TYPE_OFFSET    8
+#define    RTL8367C_PORT7_QUEUE0_TYPE_MASK    0x100
+#define    RTL8367C_PORT6_QUEUE7_TYPE_OFFSET    7
+#define    RTL8367C_PORT6_QUEUE7_TYPE_MASK    0x80
+#define    RTL8367C_PORT6_QUEUE6_TYPE_OFFSET    6
+#define    RTL8367C_PORT6_QUEUE6_TYPE_MASK    0x40
+#define    RTL8367C_PORT6_QUEUE5_TYPE_OFFSET    5
+#define    RTL8367C_PORT6_QUEUE5_TYPE_MASK    0x20
+#define    RTL8367C_PORT6_QUEUE4_TYPE_OFFSET    4
+#define    RTL8367C_PORT6_QUEUE4_TYPE_MASK    0x10
+#define    RTL8367C_PORT6_QUEUE3_TYPE_OFFSET    3
+#define    RTL8367C_PORT6_QUEUE3_TYPE_MASK    0x8
+#define    RTL8367C_PORT6_QUEUE2_TYPE_OFFSET    2
+#define    RTL8367C_PORT6_QUEUE2_TYPE_MASK    0x4
+#define    RTL8367C_PORT6_QUEUE1_TYPE_OFFSET    1
+#define    RTL8367C_PORT6_QUEUE1_TYPE_MASK    0x2
+#define    RTL8367C_SCHEDULE_QUEUE_TYPE_CTRL3_PORT6_QUEUE0_TYPE_OFFSET    0
+#define    RTL8367C_SCHEDULE_QUEUE_TYPE_CTRL3_PORT6_QUEUE0_TYPE_MASK    0x1
+
+#define    RTL8367C_REG_SCHEDULE_QUEUE_TYPE_CTRL4    0x0306
+#define    RTL8367C_PORT9_QUEUE7_TYPE_OFFSET    15
+#define    RTL8367C_PORT9_QUEUE7_TYPE_MASK    0x8000
+#define    RTL8367C_PORT9_QUEUE6_TYPE_OFFSET    14
+#define    RTL8367C_PORT9_QUEUE6_TYPE_MASK    0x4000
+#define    RTL8367C_PORT9_QUEUE5_TYPE_OFFSET    13
+#define    RTL8367C_PORT9_QUEUE5_TYPE_MASK    0x2000
+#define    RTL8367C_PORT9_QUEUE4_TYPE_OFFSET    12
+#define    RTL8367C_PORT9_QUEUE4_TYPE_MASK    0x1000
+#define    RTL8367C_PORT9_QUEUE3_TYPE_OFFSET    11
+#define    RTL8367C_PORT9_QUEUE3_TYPE_MASK    0x800
+#define    RTL8367C_PORT9_QUEUE2_TYPE_OFFSET    10
+#define    RTL8367C_PORT9_QUEUE2_TYPE_MASK    0x400
+#define    RTL8367C_PORT9_QUEUE1_TYPE_OFFSET    9
+#define    RTL8367C_PORT9_QUEUE1_TYPE_MASK    0x200
+#define    RTL8367C_PORT9_QUEUE0_TYPE_OFFSET    8
+#define    RTL8367C_PORT9_QUEUE0_TYPE_MASK    0x100
+#define    RTL8367C_PORT8_QUEUE7_TYPE_OFFSET    7
+#define    RTL8367C_PORT8_QUEUE7_TYPE_MASK    0x80
+#define    RTL8367C_PORT8_QUEUE6_TYPE_OFFSET    6
+#define    RTL8367C_PORT8_QUEUE6_TYPE_MASK    0x40
+#define    RTL8367C_PORT8_QUEUE5_TYPE_OFFSET    5
+#define    RTL8367C_PORT8_QUEUE5_TYPE_MASK    0x20
+#define    RTL8367C_PORT8_QUEUE4_TYPE_OFFSET    4
+#define    RTL8367C_PORT8_QUEUE4_TYPE_MASK    0x10
+#define    RTL8367C_PORT8_QUEUE3_TYPE_OFFSET    3
+#define    RTL8367C_PORT8_QUEUE3_TYPE_MASK    0x8
+#define    RTL8367C_PORT8_QUEUE2_TYPE_OFFSET    2
+#define    RTL8367C_PORT8_QUEUE2_TYPE_MASK    0x4
+#define    RTL8367C_PORT8_QUEUE1_TYPE_OFFSET    1
+#define    RTL8367C_PORT8_QUEUE1_TYPE_MASK    0x2
+#define    RTL8367C_SCHEDULE_QUEUE_TYPE_CTRL4_PORT6_QUEUE0_TYPE_OFFSET    0
+#define    RTL8367C_SCHEDULE_QUEUE_TYPE_CTRL4_PORT6_QUEUE0_TYPE_MASK    0x1
+
+#define    RTL8367C_REG_SCHEDULE_QUEUE_TYPE_CTRL5    0x0307
+#define    RTL8367C_PORT10_QUEUE7_TYPE_OFFSET    7
+#define    RTL8367C_PORT10_QUEUE7_TYPE_MASK    0x80
+#define    RTL8367C_PORT10_QUEUE6_TYPE_OFFSET    6
+#define    RTL8367C_PORT10_QUEUE6_TYPE_MASK    0x40
+#define    RTL8367C_PORT10_QUEUE5_TYPE_OFFSET    5
+#define    RTL8367C_PORT10_QUEUE5_TYPE_MASK    0x20
+#define    RTL8367C_PORT10_QUEUE4_TYPE_OFFSET    4
+#define    RTL8367C_PORT10_QUEUE4_TYPE_MASK    0x10
+#define    RTL8367C_PORT10_QUEUE3_TYPE_OFFSET    3
+#define    RTL8367C_PORT10_QUEUE3_TYPE_MASK    0x8
+#define    RTL8367C_PORT10_QUEUE2_TYPE_OFFSET    2
+#define    RTL8367C_PORT10_QUEUE2_TYPE_MASK    0x4
+#define    RTL8367C_PORT10_QUEUE1_TYPE_OFFSET    1
+#define    RTL8367C_PORT10_QUEUE1_TYPE_MASK    0x2
+#define    RTL8367C_PORT10_QUEUE0_TYPE_OFFSET    0
+#define    RTL8367C_PORT10_QUEUE0_TYPE_MASK    0x1
+
+#define    RTL8367C_REG_SCHEDULE_APR_CTRL0    0x030a
+#define    RTL8367C_PORT10_APR_ENABLE_OFFSET    10
+#define    RTL8367C_PORT10_APR_ENABLE_MASK    0x400
+#define    RTL8367C_PORT9_APR_ENABLE_OFFSET    9
+#define    RTL8367C_PORT9_APR_ENABLE_MASK    0x200
+#define    RTL8367C_PORT8_APR_ENABLE_OFFSET    8
+#define    RTL8367C_PORT8_APR_ENABLE_MASK    0x100
+#define    RTL8367C_PORT7_APR_ENABLE_OFFSET    7
+#define    RTL8367C_PORT7_APR_ENABLE_MASK    0x80
+#define    RTL8367C_PORT6_APR_ENABLE_OFFSET    6
+#define    RTL8367C_PORT6_APR_ENABLE_MASK    0x40
+#define    RTL8367C_PORT5_APR_ENABLE_OFFSET    5
+#define    RTL8367C_PORT5_APR_ENABLE_MASK    0x20
+#define    RTL8367C_PORT4_APR_ENABLE_OFFSET    4
+#define    RTL8367C_PORT4_APR_ENABLE_MASK    0x10
+#define    RTL8367C_PORT3_APR_ENABLE_OFFSET    3
+#define    RTL8367C_PORT3_APR_ENABLE_MASK    0x8
+#define    RTL8367C_PORT2_APR_ENABLE_OFFSET    2
+#define    RTL8367C_PORT2_APR_ENABLE_MASK    0x4
+#define    RTL8367C_PORT1_APR_ENABLE_OFFSET    1
+#define    RTL8367C_PORT1_APR_ENABLE_MASK    0x2
+#define    RTL8367C_PORT0_APR_ENABLE_OFFSET    0
+#define    RTL8367C_PORT0_APR_ENABLE_MASK    0x1
+
+#define    RTL8367C_REG_SCHEDULE_PORT0_QUEUE0_WFQ_WEIGHT    0x030c
+
+#define    RTL8367C_REG_SCHEDULE_PORT0_QUEUE1_WFQ_WEIGHT    0x030d
+#define    RTL8367C_SCHEDULE_PORT0_QUEUE1_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT0_QUEUE1_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT0_QUEUE2_WFQ_WEIGHT    0x030e
+#define    RTL8367C_SCHEDULE_PORT0_QUEUE2_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT0_QUEUE2_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT0_QUEUE3_WFQ_WEIGHT    0x030f
+#define    RTL8367C_SCHEDULE_PORT0_QUEUE3_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT0_QUEUE3_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT0_QUEUE4_WFQ_WEIGHT    0x0310
+#define    RTL8367C_SCHEDULE_PORT0_QUEUE4_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT0_QUEUE4_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT0_QUEUE5_WFQ_WEIGHT    0x0311
+#define    RTL8367C_SCHEDULE_PORT0_QUEUE5_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT0_QUEUE5_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT0_QUEUE6_WFQ_WEIGHT    0x0312
+#define    RTL8367C_SCHEDULE_PORT0_QUEUE6_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT0_QUEUE6_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT0_QUEUE7_WFQ_WEIGHT    0x0313
+#define    RTL8367C_SCHEDULE_PORT0_QUEUE7_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT0_QUEUE7_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT1_QUEUE0_WFQ_WEIGHT    0x0314
+
+#define    RTL8367C_REG_SCHEDULE_PORT1_QUEUE1_WFQ_WEIGHT    0x0315
+#define    RTL8367C_SCHEDULE_PORT1_QUEUE1_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT1_QUEUE1_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT1_QUEUE2_WFQ_WEIGHT    0x0316
+#define    RTL8367C_SCHEDULE_PORT1_QUEUE2_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT1_QUEUE2_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT1_QUEUE3_WFQ_WEIGHT    0x0317
+#define    RTL8367C_SCHEDULE_PORT1_QUEUE3_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT1_QUEUE3_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT1_QUEUE4_WFQ_WEIGHT    0x0318
+#define    RTL8367C_SCHEDULE_PORT1_QUEUE4_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT1_QUEUE4_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT1_QUEUE5_WFQ_WEIGHT    0x0319
+#define    RTL8367C_SCHEDULE_PORT1_QUEUE5_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT1_QUEUE5_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT1_QUEUE6_WFQ_WEIGHT    0x031a
+#define    RTL8367C_SCHEDULE_PORT1_QUEUE6_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT1_QUEUE6_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT1_QUEUE7_WFQ_WEIGHT    0x031b
+#define    RTL8367C_SCHEDULE_PORT1_QUEUE7_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT1_QUEUE7_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT2_QUEUE0_WFQ_WEIGHT    0x031c
+
+#define    RTL8367C_REG_SCHEDULE_PORT2_QUEUE1_WFQ_WEIGHT    0x031d
+#define    RTL8367C_SCHEDULE_PORT2_QUEUE1_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT2_QUEUE1_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT2_QUEUE2_WFQ_WEIGHT    0x031e
+#define    RTL8367C_SCHEDULE_PORT2_QUEUE2_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT2_QUEUE2_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT2_QUEUE3_WFQ_WEIGHT    0x031f
+#define    RTL8367C_SCHEDULE_PORT2_QUEUE3_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT2_QUEUE3_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT2_QUEUE4_WFQ_WEIGHT    0x0320
+#define    RTL8367C_SCHEDULE_PORT2_QUEUE4_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT2_QUEUE4_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT2_QUEUE5_WFQ_WEIGHT    0x0321
+#define    RTL8367C_SCHEDULE_PORT2_QUEUE5_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT2_QUEUE5_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT2_QUEUE6_WFQ_WEIGHT    0x0322
+#define    RTL8367C_SCHEDULE_PORT2_QUEUE6_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT2_QUEUE6_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT2_QUEUE7_WFQ_WEIGHT    0x0323
+#define    RTL8367C_SCHEDULE_PORT2_QUEUE7_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT2_QUEUE7_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT3_QUEUE0_WFQ_WEIGHT    0x0324
+
+#define    RTL8367C_REG_SCHEDULE_PORT3_QUEUE1_WFQ_WEIGHT    0x0325
+#define    RTL8367C_SCHEDULE_PORT3_QUEUE1_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT3_QUEUE1_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT3_QUEUE2_WFQ_WEIGHT    0x0326
+#define    RTL8367C_SCHEDULE_PORT3_QUEUE2_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT3_QUEUE2_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT3_QUEUE3_WFQ_WEIGHT    0x0327
+#define    RTL8367C_SCHEDULE_PORT3_QUEUE3_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT3_QUEUE3_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT3_QUEUE4_WFQ_WEIGHT    0x0328
+#define    RTL8367C_SCHEDULE_PORT3_QUEUE4_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT3_QUEUE4_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT3_QUEUE5_WFQ_WEIGHT    0x0329
+#define    RTL8367C_SCHEDULE_PORT3_QUEUE5_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT3_QUEUE5_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT3_QUEUE6_WFQ_WEIGHT    0x032a
+#define    RTL8367C_SCHEDULE_PORT3_QUEUE6_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT3_QUEUE6_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT3_QUEUE7_WFQ_WEIGHT    0x032b
+#define    RTL8367C_SCHEDULE_PORT3_QUEUE7_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT3_QUEUE7_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT4_QUEUE0_WFQ_WEIGHT    0x032c
+
+#define    RTL8367C_REG_SCHEDULE_PORT4_QUEUE1_WFQ_WEIGHT    0x032d
+#define    RTL8367C_SCHEDULE_PORT4_QUEUE1_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT4_QUEUE1_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT4_QUEUE2_WFQ_WEIGHT    0x032e
+#define    RTL8367C_SCHEDULE_PORT4_QUEUE2_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT4_QUEUE2_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT4_QUEUE3_WFQ_WEIGHT    0x032f
+#define    RTL8367C_SCHEDULE_PORT4_QUEUE3_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT4_QUEUE3_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT4_QUEUE4_WFQ_WEIGHT    0x0330
+#define    RTL8367C_SCHEDULE_PORT4_QUEUE4_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT4_QUEUE4_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT4_QUEUE5_WFQ_WEIGHT    0x0331
+#define    RTL8367C_SCHEDULE_PORT4_QUEUE5_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT4_QUEUE5_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT4_QUEUE6_WFQ_WEIGHT    0x0332
+#define    RTL8367C_SCHEDULE_PORT4_QUEUE6_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT4_QUEUE6_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT4_QUEUE7_WFQ_WEIGHT    0x0333
+#define    RTL8367C_SCHEDULE_PORT4_QUEUE7_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT4_QUEUE7_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT5_QUEUE0_WFQ_WEIGHT    0x0334
+
+#define    RTL8367C_REG_SCHEDULE_PORT5_QUEUE1_WFQ_WEIGHT    0x0335
+#define    RTL8367C_SCHEDULE_PORT5_QUEUE1_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT5_QUEUE1_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT5_QUEUE2_WFQ_WEIGHT    0x0336
+#define    RTL8367C_SCHEDULE_PORT5_QUEUE2_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT5_QUEUE2_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT5_QUEUE3_WFQ_WEIGHT    0x0337
+#define    RTL8367C_SCHEDULE_PORT5_QUEUE3_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT5_QUEUE3_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT5_QUEUE4_WFQ_WEIGHT    0x0338
+#define    RTL8367C_SCHEDULE_PORT5_QUEUE4_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT5_QUEUE4_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT5_QUEUE5_WFQ_WEIGHT    0x0339
+#define    RTL8367C_SCHEDULE_PORT5_QUEUE5_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT5_QUEUE5_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT5_QUEUE6_WFQ_WEIGHT    0x033a
+#define    RTL8367C_SCHEDULE_PORT5_QUEUE6_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT5_QUEUE6_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT5_QUEUE7_WFQ_WEIGHT    0x033b
+#define    RTL8367C_SCHEDULE_PORT5_QUEUE7_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT5_QUEUE7_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT6_QUEUE0_WFQ_WEIGHT    0x033c
+
+#define    RTL8367C_REG_SCHEDULE_PORT6_QUEUE1_WFQ_WEIGHT    0x033d
+#define    RTL8367C_SCHEDULE_PORT6_QUEUE1_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT6_QUEUE1_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT6_QUEUE2_WFQ_WEIGHT    0x033e
+#define    RTL8367C_SCHEDULE_PORT6_QUEUE2_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT6_QUEUE2_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT6_QUEUE3_WFQ_WEIGHT    0x033f
+#define    RTL8367C_SCHEDULE_PORT6_QUEUE3_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT6_QUEUE3_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT6_QUEUE4_WFQ_WEIGHT    0x0340
+#define    RTL8367C_SCHEDULE_PORT6_QUEUE4_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT6_QUEUE4_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT6_QUEUE5_WFQ_WEIGHT    0x0341
+#define    RTL8367C_SCHEDULE_PORT6_QUEUE5_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT6_QUEUE5_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT6_QUEUE6_WFQ_WEIGHT    0x0342
+#define    RTL8367C_SCHEDULE_PORT6_QUEUE6_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT6_QUEUE6_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT6_QUEUE7_WFQ_WEIGHT    0x0343
+#define    RTL8367C_SCHEDULE_PORT6_QUEUE7_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT6_QUEUE7_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT7_QUEUE0_WFQ_WEIGHT    0x0344
+
+#define    RTL8367C_REG_SCHEDULE_PORT7_QUEUE1_WFQ_WEIGHT    0x0345
+#define    RTL8367C_SCHEDULE_PORT7_QUEUE1_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT7_QUEUE1_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT7_QUEUE2_WFQ_WEIGHT    0x0346
+#define    RTL8367C_SCHEDULE_PORT7_QUEUE2_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT7_QUEUE2_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT7_QUEUE3_WFQ_WEIGHT    0x0347
+#define    RTL8367C_SCHEDULE_PORT7_QUEUE3_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT7_QUEUE3_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT7_QUEUE4_WFQ_WEIGHT    0x0348
+#define    RTL8367C_SCHEDULE_PORT7_QUEUE4_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT7_QUEUE4_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT7_QUEUE5_WFQ_WEIGHT    0x0349
+#define    RTL8367C_SCHEDULE_PORT7_QUEUE5_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT7_QUEUE5_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT7_QUEUE6_WFQ_WEIGHT    0x034a
+#define    RTL8367C_SCHEDULE_PORT7_QUEUE6_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT7_QUEUE6_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT7_QUEUE7_WFQ_WEIGHT    0x034b
+#define    RTL8367C_SCHEDULE_PORT7_QUEUE7_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT7_QUEUE7_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT8_QUEUE0_WFQ_WEIGHT    0x034c
+
+#define    RTL8367C_REG_SCHEDULE_PORT8_QUEUE1_WFQ_WEIGHT    0x034d
+#define    RTL8367C_SCHEDULE_PORT8_QUEUE1_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT8_QUEUE1_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT8_QUEUE2_WFQ_WEIGHT    0x034e
+#define    RTL8367C_SCHEDULE_PORT8_QUEUE2_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT8_QUEUE2_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT8_QUEUE3_WFQ_WEIGHT    0x034f
+#define    RTL8367C_SCHEDULE_PORT8_QUEUE3_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT8_QUEUE3_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT8_QUEUE4_WFQ_WEIGHT    0x0350
+#define    RTL8367C_SCHEDULE_PORT8_QUEUE4_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT8_QUEUE4_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT8_QUEUE5_WFQ_WEIGHT    0x0351
+#define    RTL8367C_SCHEDULE_PORT8_QUEUE5_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT8_QUEUE5_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT8_QUEUE6_WFQ_WEIGHT    0x0352
+#define    RTL8367C_SCHEDULE_PORT8_QUEUE6_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT8_QUEUE6_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT8_QUEUE7_WFQ_WEIGHT    0x0353
+#define    RTL8367C_SCHEDULE_PORT8_QUEUE7_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT8_QUEUE7_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT9_QUEUE0_WFQ_WEIGHT    0x0354
+
+#define    RTL8367C_REG_SCHEDULE_PORT9_QUEUE1_WFQ_WEIGHT    0x0355
+#define    RTL8367C_SCHEDULE_PORT9_QUEUE1_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT9_QUEUE1_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT9_QUEUE2_WFQ_WEIGHT    0x0356
+#define    RTL8367C_SCHEDULE_PORT9_QUEUE2_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT9_QUEUE2_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT9_QUEUE3_WFQ_WEIGHT    0x0357
+#define    RTL8367C_SCHEDULE_PORT9_QUEUE3_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT9_QUEUE3_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT9_QUEUE4_WFQ_WEIGHT    0x0358
+#define    RTL8367C_SCHEDULE_PORT9_QUEUE4_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT9_QUEUE4_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT9_QUEUE5_WFQ_WEIGHT    0x0359
+#define    RTL8367C_SCHEDULE_PORT9_QUEUE5_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT9_QUEUE5_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT9_QUEUE6_WFQ_WEIGHT    0x035a
+#define    RTL8367C_SCHEDULE_PORT9_QUEUE6_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT9_QUEUE6_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT9_QUEUE7_WFQ_WEIGHT    0x035b
+#define    RTL8367C_SCHEDULE_PORT9_QUEUE7_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT9_QUEUE7_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT10_QUEUE0_WFQ_WEIGHT    0x035c
+
+#define    RTL8367C_REG_SCHEDULE_PORT10_QUEUE1_WFQ_WEIGHT    0x035d
+#define    RTL8367C_SCHEDULE_PORT10_QUEUE1_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT10_QUEUE1_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT10_QUEUE2_WFQ_WEIGHT    0x035e
+#define    RTL8367C_SCHEDULE_PORT10_QUEUE2_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT10_QUEUE2_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT10_QUEUE3_WFQ_WEIGHT    0x035f
+#define    RTL8367C_SCHEDULE_PORT10_QUEUE3_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT10_QUEUE3_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT10_QUEUE4_WFQ_WEIGHT    0x0360
+#define    RTL8367C_SCHEDULE_PORT10_QUEUE4_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT10_QUEUE4_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT10_QUEUE5_WFQ_WEIGHT    0x0361
+#define    RTL8367C_SCHEDULE_PORT10_QUEUE5_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT10_QUEUE5_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT10_QUEUE6_WFQ_WEIGHT    0x0362
+#define    RTL8367C_SCHEDULE_PORT10_QUEUE6_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT10_QUEUE6_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_SCHEDULE_PORT10_QUEUE7_WFQ_WEIGHT    0x0363
+#define    RTL8367C_SCHEDULE_PORT10_QUEUE7_WFQ_WEIGHT_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT10_QUEUE7_WFQ_WEIGHT_MASK    0x7F
+
+#define    RTL8367C_REG_PORT0_EGRESSBW_CTRL0    0x038c
+
+#define    RTL8367C_REG_PORT0_EGRESSBW_CTRL1    0x038d
+#define    RTL8367C_PORT0_EGRESSBW_CTRL1_OFFSET    0
+#define    RTL8367C_PORT0_EGRESSBW_CTRL1_MASK    0x1
+
+#define    RTL8367C_REG_PORT1_EGRESSBW_CTRL0    0x038e
+
+#define    RTL8367C_REG_PORT1_EGRESSBW_CTRL1    0x038f
+#define    RTL8367C_PORT1_EGRESSBW_CTRL1_OFFSET    0
+#define    RTL8367C_PORT1_EGRESSBW_CTRL1_MASK    0x1
+
+#define    RTL8367C_REG_PORT2_EGRESSBW_CTRL0    0x0390
+
+#define    RTL8367C_REG_PORT2_EGRESSBW_CTRL1    0x0391
+#define    RTL8367C_PORT2_EGRESSBW_CTRL1_OFFSET    0
+#define    RTL8367C_PORT2_EGRESSBW_CTRL1_MASK    0x1
+
+#define    RTL8367C_REG_PORT3_EGRESSBW_CTRL0    0x0392
+
+#define    RTL8367C_REG_PORT3_EGRESSBW_CTRL1    0x0393
+#define    RTL8367C_PORT3_EGRESSBW_CTRL1_OFFSET    0
+#define    RTL8367C_PORT3_EGRESSBW_CTRL1_MASK    0x1
+
+#define    RTL8367C_REG_PORT4_EGRESSBW_CTRL0    0x0394
+
+#define    RTL8367C_REG_PORT4_EGRESSBW_CTRL1    0x0395
+#define    RTL8367C_PORT4_EGRESSBW_CTRL1_OFFSET    0
+#define    RTL8367C_PORT4_EGRESSBW_CTRL1_MASK    0x1
+
+#define    RTL8367C_REG_PORT5_EGRESSBW_CTRL0    0x0396
+
+#define    RTL8367C_REG_PORT5_EGRESSBW_CTRL1    0x0397
+#define    RTL8367C_PORT5_EGRESSBW_CTRL1_OFFSET    0
+#define    RTL8367C_PORT5_EGRESSBW_CTRL1_MASK    0x1
+
+#define    RTL8367C_REG_PORT6_EGRESSBW_CTRL0    0x0398
+
+#define    RTL8367C_REG_PORT6_EGRESSBW_CTRL1    0x0399
+#define    RTL8367C_PORT6_EGRESSBW_CTRL1_OFFSET    0
+#define    RTL8367C_PORT6_EGRESSBW_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_PORT7_EGRESSBW_CTRL0    0x039a
+
+#define    RTL8367C_REG_PORT7_EGRESSBW_CTRL1    0x039b
+#define    RTL8367C_PORT7_EGRESSBW_CTRL1_OFFSET    0
+#define    RTL8367C_PORT7_EGRESSBW_CTRL1_MASK    0x1
+
+#define    RTL8367C_REG_PORT8_EGRESSBW_CTRL0    0x039c
+
+#define    RTL8367C_REG_PORT8_EGRESSBW_CTRL1    0x039d
+#define    RTL8367C_PORT8_EGRESSBW_CTRL1_OFFSET    0
+#define    RTL8367C_PORT8_EGRESSBW_CTRL1_MASK    0x1
+
+#define    RTL8367C_REG_PORT9_EGRESSBW_CTRL0    0x039e
+
+#define    RTL8367C_REG_PORT9_EGRESSBW_CTRL1    0x039f
+#define    RTL8367C_PORT9_EGRESSBW_CTRL1_OFFSET    0
+#define    RTL8367C_PORT9_EGRESSBW_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_PORT10_EGRESSBW_CTRL0    0x03a0
+
+#define    RTL8367C_REG_PORT10_EGRESSBW_CTRL1    0x03a1
+#define    RTL8367C_PORT10_EGRESSBW_CTRL1_OFFSET    0
+#define    RTL8367C_PORT10_EGRESSBW_CTRL1_MASK    0x1
+
+#define    RTL8367C_REG_SCHEDULE_PORT0_APR_METER_CTRL0    0x03ac
+#define    RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET    12
+#define    RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE4_APR_METER_MASK    0x7000
+#define    RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET    9
+#define    RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE3_APR_METER_MASK    0xE00
+#define    RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE2_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE1_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE0_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_SCHEDULE_PORT0_APR_METER_CTRL1    0x03ad
+#define    RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL1_QUEUE7_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL1_QUEUE6_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL1_QUEUE5_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_SCHEDULE_PORT1_APR_METER_CTRL0    0x03b0
+#define    RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET    12
+#define    RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE4_APR_METER_MASK    0x7000
+#define    RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET    9
+#define    RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE3_APR_METER_MASK    0xE00
+#define    RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE2_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE1_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE0_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_SCHEDULE_PORT1_APR_METER_CTRL1    0x03b1
+#define    RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL1_QUEUE7_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL1_QUEUE6_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL1_QUEUE5_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_SCHEDULE_PORT2_APR_METER_CTRL0    0x03b4
+#define    RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET    12
+#define    RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE4_APR_METER_MASK    0x7000
+#define    RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET    9
+#define    RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE3_APR_METER_MASK    0xE00
+#define    RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE2_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE1_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE0_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_SCHEDULE_PORT2_APR_METER_CTRL1    0x03b5
+#define    RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL1_QUEUE7_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL1_QUEUE6_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL1_QUEUE5_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_SCHEDULE_PORT3_APR_METER_CTRL0    0x03b8
+#define    RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET    12
+#define    RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE4_APR_METER_MASK    0x7000
+#define    RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET    9
+#define    RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE3_APR_METER_MASK    0xE00
+#define    RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE2_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE1_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE0_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_SCHEDULE_PORT3_APR_METER_CTRL1    0x03b9
+#define    RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL1_QUEUE7_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL1_QUEUE6_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL1_QUEUE5_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_SCHEDULE_PORT4_APR_METER_CTRL0    0x03bc
+#define    RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET    12
+#define    RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE4_APR_METER_MASK    0x7000
+#define    RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET    9
+#define    RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE3_APR_METER_MASK    0xE00
+#define    RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE2_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE1_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE0_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_SCHEDULE_PORT4_APR_METER_CTRL1    0x03bd
+#define    RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL1_QUEUE7_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL1_QUEUE6_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL1_QUEUE5_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_SCHEDULE_PORT5_APR_METER_CTRL0    0x03c0
+#define    RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET    12
+#define    RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE4_APR_METER_MASK    0x7000
+#define    RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET    9
+#define    RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE3_APR_METER_MASK    0xE00
+#define    RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE2_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE1_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE0_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_SCHEDULE_PORT5_APR_METER_CTRL1    0x03c1
+#define    RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL1_QUEUE7_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL1_QUEUE6_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL1_QUEUE5_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_SCHEDULE_PORT6_APR_METER_CTRL0    0x03c4
+#define    RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET    12
+#define    RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE4_APR_METER_MASK    0x7000
+#define    RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET    9
+#define    RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE3_APR_METER_MASK    0xE00
+#define    RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE2_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE1_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE0_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_SCHEDULE_PORT6_APR_METER_CTRL1    0x03c5
+#define    RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL1_QUEUE7_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL1_QUEUE6_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL1_QUEUE5_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_SCHEDULE_PORT7_APR_METER_CTRL0    0x03c8
+#define    RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET    12
+#define    RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE4_APR_METER_MASK    0x7000
+#define    RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET    9
+#define    RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE3_APR_METER_MASK    0xE00
+#define    RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE2_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE1_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE0_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_SCHEDULE_PORT7_APR_METER_CTRL1    0x03c9
+#define    RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL1_QUEUE7_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL1_QUEUE6_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL1_QUEUE5_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_SCHEDULE_PORT8_APR_METER_CTRL0    0x03ca
+#define    RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET    12
+#define    RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE4_APR_METER_MASK    0x7000
+#define    RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET    9
+#define    RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE3_APR_METER_MASK    0xE00
+#define    RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE2_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE1_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE0_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_SCHEDULE_PORT8_APR_METER_CTRL1    0x03cb
+#define    RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL1_QUEUE7_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL1_QUEUE6_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL1_QUEUE5_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_SCHEDULE_PORT9_APR_METER_CTRL0    0x03cc
+#define    RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET    12
+#define    RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE4_APR_METER_MASK    0x7000
+#define    RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET    9
+#define    RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE3_APR_METER_MASK    0xE00
+#define    RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE2_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE1_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE0_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_SCHEDULE_PORT9_APR_METER_CTRL1    0x03cd
+#define    RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL1_QUEUE7_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL1_QUEUE6_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL1_QUEUE5_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_SCHEDULE_PORT10_APR_METER_CTRL0    0x03ce
+#define    RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET    12
+#define    RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE4_APR_METER_MASK    0x7000
+#define    RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET    9
+#define    RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE3_APR_METER_MASK    0xE00
+#define    RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE2_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE1_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE0_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_SCHEDULE_PORT10_APR_METER_CTRL1    0x03cf
+#define    RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET    6
+#define    RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL1_QUEUE7_APR_METER_MASK    0x1C0
+#define    RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET    3
+#define    RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL1_QUEUE6_APR_METER_MASK    0x38
+#define    RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET    0
+#define    RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL1_QUEUE5_APR_METER_MASK    0x7
+
+#define    RTL8367C_REG_LINE_RATE_1G_L    0x03ec
+
+#define    RTL8367C_REG_LINE_RATE_1G_H    0x03ed
+#define    RTL8367C_LINE_RATE_1G_H_OFFSET    0
+#define    RTL8367C_LINE_RATE_1G_H_MASK    0x1
+
+#define    RTL8367C_REG_LINE_RATE_100_L    0x03ee
+
+#define    RTL8367C_REG_LINE_RATE_100_H    0x03ef
+#define    RTL8367C_LINE_RATE_100_H_OFFSET    0
+#define    RTL8367C_LINE_RATE_100_H_MASK    0x1
+
+#define    RTL8367C_REG_LINE_RATE_10_L    0x03f0
+
+#define    RTL8367C_REG_LINE_RATE_10_H    0x03f1
+#define    RTL8367C_LINE_RATE_10_H_OFFSET    0
+#define    RTL8367C_LINE_RATE_10_H_MASK    0x1
+
+#define    RTL8367C_REG_DUMMY_03f2    0x03f2
+
+#define    RTL8367C_REG_DUMMY_03f3    0x03f3
+
+#define    RTL8367C_REG_DUMMY_03f4    0x03f4
+
+#define    RTL8367C_REG_DUMMY_03f5    0x03f5
+
+#define    RTL8367C_REG_DUMMY_03f6    0x03f6
+
+#define    RTL8367C_REG_BYPASS_LINE_RATE    0x03f7
+#define    RTL8367C_BYPASS_PORT10_CONSTRAINT_OFFSET    5
+#define    RTL8367C_BYPASS_PORT10_CONSTRAINT_MASK    0x20
+#define    RTL8367C_BYPASS_PORT9_CONSTRAINT_OFFSET    4
+#define    RTL8367C_BYPASS_PORT9_CONSTRAINT_MASK    0x10
+#define    RTL8367C_BYPASS_PORT8_CONSTRAINT_OFFSET    3
+#define    RTL8367C_BYPASS_PORT8_CONSTRAINT_MASK    0x8
+#define    RTL8367C_BYPASS_PORT7_CONSTRAINT_OFFSET    2
+#define    RTL8367C_BYPASS_PORT7_CONSTRAINT_MASK    0x4
+#define    RTL8367C_BYPASS_PORT6_CONSTRAINT_OFFSET    1
+#define    RTL8367C_BYPASS_PORT6_CONSTRAINT_MASK    0x2
+#define    RTL8367C_BYPASS_PORT5_CONSTRAINT_OFFSET    0
+#define    RTL8367C_BYPASS_PORT5_CONSTRAINT_MASK    0x1
+
+#define    RTL8367C_REG_LINE_RATE_500_H    0x03f8
+#define    RTL8367C_LINE_RATE_500_H_OFFSET    0
+#define    RTL8367C_LINE_RATE_500_H_MASK    0x7
+
+#define    RTL8367C_REG_LINE_RATE_500_L    0x03f9
+
+#define    RTL8367C_REG_LINE_RATE_HSG_H    0x03fa
+#define    RTL8367C_LINE_RATE_HSG_H_OFFSET    0
+#define    RTL8367C_LINE_RATE_HSG_H_MASK    0x7
+
+#define    RTL8367C_REG_LINE_RATE_HSG_L    0x03fb
+
+/* (16'h0500)table_reg */
+
+#define    RTL8367C_REG_TABLE_ACCESS_CTRL    0x0500
+#define    RTL8367C_TABLE_ACCESS_CTRL_SPA_OFFSET    8
+#define    RTL8367C_TABLE_ACCESS_CTRL_SPA_MASK    0xF00
+#define    RTL8367C_ACCESS_METHOD_OFFSET    4
+#define    RTL8367C_ACCESS_METHOD_MASK    0x70
+#define    RTL8367C_COMMAND_TYPE_OFFSET    3
+#define    RTL8367C_COMMAND_TYPE_MASK    0x8
+#define    RTL8367C_TABLE_TYPE_OFFSET    0
+#define    RTL8367C_TABLE_TYPE_MASK    0x7
+
+#define    RTL8367C_REG_TABLE_ACCESS_ADDR    0x0501
+#define    RTL8367C_TABLE_ACCESS_ADDR_OFFSET    0
+#define    RTL8367C_TABLE_ACCESS_ADDR_MASK    0x1FFF
+
+#define    RTL8367C_REG_TABLE_LUT_ADDR    0x0502
+#define    RTL8367C_ADDRESS2_OFFSET    14
+#define    RTL8367C_ADDRESS2_MASK    0x4000
+#define    RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET    13
+#define    RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_MASK    0x2000
+#define    RTL8367C_HIT_STATUS_OFFSET    12
+#define    RTL8367C_HIT_STATUS_MASK    0x1000
+#define    RTL8367C_TABLE_LUT_ADDR_TYPE_OFFSET    11
+#define    RTL8367C_TABLE_LUT_ADDR_TYPE_MASK    0x800
+#define    RTL8367C_TABLE_LUT_ADDR_ADDRESS_OFFSET    0
+#define    RTL8367C_TABLE_LUT_ADDR_ADDRESS_MASK    0x7FF
+
+#define    RTL8367C_REG_HSA_HSB_LATCH    0x0503
+#define    RTL8367C_LATCH_ALWAYS_OFFSET    15
+#define    RTL8367C_LATCH_ALWAYS_MASK    0x8000
+#define    RTL8367C_LATCH_FIRST_OFFSET    14
+#define    RTL8367C_LATCH_FIRST_MASK    0x4000
+#define    RTL8367C_SPA_EN_OFFSET    13
+#define    RTL8367C_SPA_EN_MASK    0x2000
+#define    RTL8367C_FORWARD_EN_OFFSET    12
+#define    RTL8367C_FORWARD_EN_MASK    0x1000
+#define    RTL8367C_REASON_EN_OFFSET    11
+#define    RTL8367C_REASON_EN_MASK    0x800
+#define    RTL8367C_HSA_HSB_LATCH_SPA_OFFSET    8
+#define    RTL8367C_HSA_HSB_LATCH_SPA_MASK    0x700
+#define    RTL8367C_FORWARD_OFFSET    6
+#define    RTL8367C_FORWARD_MASK    0xC0
+#define    RTL8367C_REASON_OFFSET    0
+#define    RTL8367C_REASON_MASK    0x3F
+
+#define    RTL8367C_REG_HSA_HSB_LATCH2    0x0504
+#define    RTL8367C_HSA_HSB_LATCH2_Reserved_OFFSET    1
+#define    RTL8367C_HSA_HSB_LATCH2_Reserved_MASK    0xFFFE
+#define    RTL8367C_SPA2_OFFSET    0
+#define    RTL8367C_SPA2_MASK    0x1
+
+#define    RTL8367C_REG_TABLE_WRITE_DATA0    0x0510
+
+#define    RTL8367C_REG_TABLE_WRITE_DATA1    0x0511
+
+#define    RTL8367C_REG_TABLE_WRITE_DATA2    0x0512
+
+#define    RTL8367C_REG_TABLE_WRITE_DATA3    0x0513
+
+#define    RTL8367C_REG_TABLE_WRITE_DATA4    0x0514
+
+#define    RTL8367C_REG_TABLE_WRITE_DATA5    0x0515
+
+#define    RTL8367C_REG_TABLE_WRITE_DATA6    0x0516
+
+#define    RTL8367C_REG_TABLE_WRITE_DATA7    0x0517
+
+#define    RTL8367C_REG_TABLE_WRITE_DATA8    0x0518
+
+#define    RTL8367C_REG_TABLE_WRITE_DATA9    0x0519
+#define    RTL8367C_TABLE_WRITE_DATA9_OFFSET    0
+#define    RTL8367C_TABLE_WRITE_DATA9_MASK    0xF
+
+#define    RTL8367C_REG_TABLE_READ_DATA0    0x0520
+
+#define    RTL8367C_REG_TABLE_READ_DATA1    0x0521
+
+#define    RTL8367C_REG_TABLE_READ_DATA2    0x0522
+
+#define    RTL8367C_REG_TABLE_READ_DATA3    0x0523
+
+#define    RTL8367C_REG_TABLE_READ_DATA4    0x0524
+
+#define    RTL8367C_REG_TABLE_READ_DATA5    0x0525
+
+#define    RTL8367C_REG_TABLE_READ_DATA6    0x0526
+
+#define    RTL8367C_REG_TABLE_READ_DATA7    0x0527
+
+#define    RTL8367C_REG_TABLE_READ_DATA8    0x0528
+
+#define    RTL8367C_REG_TABLE_READ_DATA9    0x0529
+#define    RTL8367C_TABLE_READ_DATA9_OFFSET    0
+#define    RTL8367C_TABLE_READ_DATA9_MASK    0xF
+
+#define    RTL8367C_REG_TBL_DUMMY00    0x0550
+
+#define    RTL8367C_REG_TBL_DUMMY01    0x0551
+
+/* (16'h0600)acl_reg */
+
+#define    RTL8367C_REG_ACL_RULE_TEMPLATE0_CTRL0    0x0600
+#define    RTL8367C_ACL_RULE_TEMPLATE0_CTRL0_FIELD1_OFFSET    8
+#define    RTL8367C_ACL_RULE_TEMPLATE0_CTRL0_FIELD1_MASK    0x7F00
+#define    RTL8367C_ACL_RULE_TEMPLATE0_CTRL0_FIELD0_OFFSET    0
+#define    RTL8367C_ACL_RULE_TEMPLATE0_CTRL0_FIELD0_MASK    0x7F
+
+#define    RTL8367C_REG_ACL_RULE_TEMPLATE0_CTRL1    0x0601
+#define    RTL8367C_ACL_RULE_TEMPLATE0_CTRL1_FIELD3_OFFSET    8
+#define    RTL8367C_ACL_RULE_TEMPLATE0_CTRL1_FIELD3_MASK    0x7F00
+#define    RTL8367C_ACL_RULE_TEMPLATE0_CTRL1_FIELD2_OFFSET    0
+#define    RTL8367C_ACL_RULE_TEMPLATE0_CTRL1_FIELD2_MASK    0x7F
+
+#define    RTL8367C_REG_ACL_RULE_TEMPLATE0_CTRL2    0x0602
+#define    RTL8367C_ACL_RULE_TEMPLATE0_CTRL2_FIELD5_OFFSET    8
+#define    RTL8367C_ACL_RULE_TEMPLATE0_CTRL2_FIELD5_MASK    0x7F00
+#define    RTL8367C_ACL_RULE_TEMPLATE0_CTRL2_FIELD4_OFFSET    0
+#define    RTL8367C_ACL_RULE_TEMPLATE0_CTRL2_FIELD4_MASK    0x7F
+
+#define    RTL8367C_REG_ACL_RULE_TEMPLATE0_CTRL3    0x0603
+#define    RTL8367C_ACL_RULE_TEMPLATE0_CTRL3_FIELD7_OFFSET    8
+#define    RTL8367C_ACL_RULE_TEMPLATE0_CTRL3_FIELD7_MASK    0x7F00
+#define    RTL8367C_ACL_RULE_TEMPLATE0_CTRL3_FIELD6_OFFSET    0
+#define    RTL8367C_ACL_RULE_TEMPLATE0_CTRL3_FIELD6_MASK    0x7F
+
+#define    RTL8367C_REG_ACL_RULE_TEMPLATE1_CTRL0    0x0604
+#define    RTL8367C_ACL_RULE_TEMPLATE1_CTRL0_FIELD1_OFFSET    8
+#define    RTL8367C_ACL_RULE_TEMPLATE1_CTRL0_FIELD1_MASK    0x7F00
+#define    RTL8367C_ACL_RULE_TEMPLATE1_CTRL0_FIELD0_OFFSET    0
+#define    RTL8367C_ACL_RULE_TEMPLATE1_CTRL0_FIELD0_MASK    0x7F
+
+#define    RTL8367C_REG_ACL_RULE_TEMPLATE1_CTRL1    0x0605
+#define    RTL8367C_ACL_RULE_TEMPLATE1_CTRL1_FIELD3_OFFSET    8
+#define    RTL8367C_ACL_RULE_TEMPLATE1_CTRL1_FIELD3_MASK    0x7F00
+#define    RTL8367C_ACL_RULE_TEMPLATE1_CTRL1_FIELD2_OFFSET    0
+#define    RTL8367C_ACL_RULE_TEMPLATE1_CTRL1_FIELD2_MASK    0x7F
+
+#define    RTL8367C_REG_ACL_RULE_TEMPLATE1_CTRL2    0x0606
+#define    RTL8367C_ACL_RULE_TEMPLATE1_CTRL2_FIELD5_OFFSET    8
+#define    RTL8367C_ACL_RULE_TEMPLATE1_CTRL2_FIELD5_MASK    0x7F00
+#define    RTL8367C_ACL_RULE_TEMPLATE1_CTRL2_FIELD4_OFFSET    0
+#define    RTL8367C_ACL_RULE_TEMPLATE1_CTRL2_FIELD4_MASK    0x7F
+
+#define    RTL8367C_REG_ACL_RULE_TEMPLATE1_CTRL3    0x0607
+#define    RTL8367C_ACL_RULE_TEMPLATE1_CTRL3_FIELD7_OFFSET    8
+#define    RTL8367C_ACL_RULE_TEMPLATE1_CTRL3_FIELD7_MASK    0x7F00
+#define    RTL8367C_ACL_RULE_TEMPLATE1_CTRL3_FIELD6_OFFSET    0
+#define    RTL8367C_ACL_RULE_TEMPLATE1_CTRL3_FIELD6_MASK    0x7F
+
+#define    RTL8367C_REG_ACL_RULE_TEMPLATE2_CTRL0    0x0608
+#define    RTL8367C_ACL_RULE_TEMPLATE2_CTRL0_FIELD1_OFFSET    8
+#define    RTL8367C_ACL_RULE_TEMPLATE2_CTRL0_FIELD1_MASK    0x7F00
+#define    RTL8367C_ACL_RULE_TEMPLATE2_CTRL0_FIELD0_OFFSET    0
+#define    RTL8367C_ACL_RULE_TEMPLATE2_CTRL0_FIELD0_MASK    0x7F
+
+#define    RTL8367C_REG_ACL_RULE_TEMPLATE2_CTRL1    0x0609
+#define    RTL8367C_ACL_RULE_TEMPLATE2_CTRL1_FIELD3_OFFSET    8
+#define    RTL8367C_ACL_RULE_TEMPLATE2_CTRL1_FIELD3_MASK    0x7F00
+#define    RTL8367C_ACL_RULE_TEMPLATE2_CTRL1_FIELD2_OFFSET    0
+#define    RTL8367C_ACL_RULE_TEMPLATE2_CTRL1_FIELD2_MASK    0x7F
+
+#define    RTL8367C_REG_ACL_RULE_TEMPLATE2_CTRL2    0x060a
+#define    RTL8367C_ACL_RULE_TEMPLATE2_CTRL2_FIELD5_OFFSET    8
+#define    RTL8367C_ACL_RULE_TEMPLATE2_CTRL2_FIELD5_MASK    0x7F00
+#define    RTL8367C_ACL_RULE_TEMPLATE2_CTRL2_FIELD4_OFFSET    0
+#define    RTL8367C_ACL_RULE_TEMPLATE2_CTRL2_FIELD4_MASK    0x7F
+
+#define    RTL8367C_REG_ACL_RULE_TEMPLATE2_CTRL3    0x060b
+#define    RTL8367C_ACL_RULE_TEMPLATE2_CTRL3_FIELD7_OFFSET    8
+#define    RTL8367C_ACL_RULE_TEMPLATE2_CTRL3_FIELD7_MASK    0x7F00
+#define    RTL8367C_ACL_RULE_TEMPLATE2_CTRL3_FIELD6_OFFSET    0
+#define    RTL8367C_ACL_RULE_TEMPLATE2_CTRL3_FIELD6_MASK    0x7F
+
+#define    RTL8367C_REG_ACL_RULE_TEMPLATE3_CTRL0    0x060c
+#define    RTL8367C_ACL_RULE_TEMPLATE3_CTRL0_FIELD1_OFFSET    8
+#define    RTL8367C_ACL_RULE_TEMPLATE3_CTRL0_FIELD1_MASK    0x7F00
+#define    RTL8367C_ACL_RULE_TEMPLATE3_CTRL0_FIELD0_OFFSET    0
+#define    RTL8367C_ACL_RULE_TEMPLATE3_CTRL0_FIELD0_MASK    0x7F
+
+#define    RTL8367C_REG_ACL_RULE_TEMPLATE3_CTRL1    0x060d
+#define    RTL8367C_ACL_RULE_TEMPLATE3_CTRL1_FIELD3_OFFSET    8
+#define    RTL8367C_ACL_RULE_TEMPLATE3_CTRL1_FIELD3_MASK    0x7F00
+#define    RTL8367C_ACL_RULE_TEMPLATE3_CTRL1_FIELD2_OFFSET    0
+#define    RTL8367C_ACL_RULE_TEMPLATE3_CTRL1_FIELD2_MASK    0x7F
+
+#define    RTL8367C_REG_ACL_RULE_TEMPLATE3_CTRL2    0x060e
+#define    RTL8367C_ACL_RULE_TEMPLATE3_CTRL2_FIELD5_OFFSET    8
+#define    RTL8367C_ACL_RULE_TEMPLATE3_CTRL2_FIELD5_MASK    0x7F00
+#define    RTL8367C_ACL_RULE_TEMPLATE3_CTRL2_FIELD4_OFFSET    0
+#define    RTL8367C_ACL_RULE_TEMPLATE3_CTRL2_FIELD4_MASK    0x7F
+
+#define    RTL8367C_REG_ACL_RULE_TEMPLATE3_CTRL3    0x060f
+#define    RTL8367C_ACL_RULE_TEMPLATE3_CTRL3_FIELD7_OFFSET    8
+#define    RTL8367C_ACL_RULE_TEMPLATE3_CTRL3_FIELD7_MASK    0x7F00
+#define    RTL8367C_ACL_RULE_TEMPLATE3_CTRL3_FIELD6_OFFSET    0
+#define    RTL8367C_ACL_RULE_TEMPLATE3_CTRL3_FIELD6_MASK    0x7F
+
+#define    RTL8367C_REG_ACL_RULE_TEMPLATE4_CTRL0    0x0610
+#define    RTL8367C_ACL_RULE_TEMPLATE4_CTRL0_FIELD1_OFFSET    8
+#define    RTL8367C_ACL_RULE_TEMPLATE4_CTRL0_FIELD1_MASK    0x7F00
+#define    RTL8367C_ACL_RULE_TEMPLATE4_CTRL0_FIELD0_OFFSET    0
+#define    RTL8367C_ACL_RULE_TEMPLATE4_CTRL0_FIELD0_MASK    0x7F
+
+#define    RTL8367C_REG_ACL_RULE_TEMPLATE4_CTRL1    0x0611
+#define    RTL8367C_ACL_RULE_TEMPLATE4_CTRL1_FIELD3_OFFSET    8
+#define    RTL8367C_ACL_RULE_TEMPLATE4_CTRL1_FIELD3_MASK    0x7F00
+#define    RTL8367C_ACL_RULE_TEMPLATE4_CTRL1_FIELD2_OFFSET    0
+#define    RTL8367C_ACL_RULE_TEMPLATE4_CTRL1_FIELD2_MASK    0x7F
+
+#define    RTL8367C_REG_ACL_RULE_TEMPLATE4_CTRL2    0x0612
+#define    RTL8367C_ACL_RULE_TEMPLATE4_CTRL2_FIELD5_OFFSET    8
+#define    RTL8367C_ACL_RULE_TEMPLATE4_CTRL2_FIELD5_MASK    0x7F00
+#define    RTL8367C_ACL_RULE_TEMPLATE4_CTRL2_FIELD4_OFFSET    0
+#define    RTL8367C_ACL_RULE_TEMPLATE4_CTRL2_FIELD4_MASK    0x7F
+
+#define    RTL8367C_REG_ACL_RULE_TEMPLATE4_CTRL3    0x0613
+#define    RTL8367C_ACL_RULE_TEMPLATE4_CTRL3_FIELD7_OFFSET    8
+#define    RTL8367C_ACL_RULE_TEMPLATE4_CTRL3_FIELD7_MASK    0x7F00
+#define    RTL8367C_ACL_RULE_TEMPLATE4_CTRL3_FIELD6_OFFSET    0
+#define    RTL8367C_ACL_RULE_TEMPLATE4_CTRL3_FIELD6_MASK    0x7F
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL0    0x0614
+#define    RTL8367C_OP1_NOT_OFFSET    14
+#define    RTL8367C_OP1_NOT_MASK    0x4000
+#define    RTL8367C_ACT1_GPIO_OFFSET    13
+#define    RTL8367C_ACT1_GPIO_MASK    0x2000
+#define    RTL8367C_ACT1_FORWARD_OFFSET    12
+#define    RTL8367C_ACT1_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT1_POLICING_OFFSET    11
+#define    RTL8367C_ACT1_POLICING_MASK    0x800
+#define    RTL8367C_ACT1_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT1_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT1_SVID_OFFSET    9
+#define    RTL8367C_ACT1_SVID_MASK    0x200
+#define    RTL8367C_ACT1_CVID_OFFSET    8
+#define    RTL8367C_ACT1_CVID_MASK    0x100
+#define    RTL8367C_OP0_NOT_OFFSET    6
+#define    RTL8367C_OP0_NOT_MASK    0x40
+#define    RTL8367C_ACT0_GPIO_OFFSET    5
+#define    RTL8367C_ACT0_GPIO_MASK    0x20
+#define    RTL8367C_ACT0_FORWARD_OFFSET    4
+#define    RTL8367C_ACT0_FORWARD_MASK    0x10
+#define    RTL8367C_ACT0_POLICING_OFFSET    3
+#define    RTL8367C_ACT0_POLICING_MASK    0x8
+#define    RTL8367C_ACT0_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT0_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT0_SVID_OFFSET    1
+#define    RTL8367C_ACT0_SVID_MASK    0x2
+#define    RTL8367C_ACT0_CVID_OFFSET    0
+#define    RTL8367C_ACT0_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL1    0x0615
+#define    RTL8367C_OP3_NOT_OFFSET    14
+#define    RTL8367C_OP3_NOT_MASK    0x4000
+#define    RTL8367C_ACT3_GPIO_OFFSET    13
+#define    RTL8367C_ACT3_GPIO_MASK    0x2000
+#define    RTL8367C_ACT3_FORWARD_OFFSET    12
+#define    RTL8367C_ACT3_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT3_POLICING_OFFSET    11
+#define    RTL8367C_ACT3_POLICING_MASK    0x800
+#define    RTL8367C_ACT3_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT3_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT3_SVID_OFFSET    9
+#define    RTL8367C_ACT3_SVID_MASK    0x200
+#define    RTL8367C_ACT3_CVID_OFFSET    8
+#define    RTL8367C_ACT3_CVID_MASK    0x100
+#define    RTL8367C_OP2_NOT_OFFSET    6
+#define    RTL8367C_OP2_NOT_MASK    0x40
+#define    RTL8367C_ACT2_GPIO_OFFSET    5
+#define    RTL8367C_ACT2_GPIO_MASK    0x20
+#define    RTL8367C_ACT2_FORWARD_OFFSET    4
+#define    RTL8367C_ACT2_FORWARD_MASK    0x10
+#define    RTL8367C_ACT2_POLICING_OFFSET    3
+#define    RTL8367C_ACT2_POLICING_MASK    0x8
+#define    RTL8367C_ACT2_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT2_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT2_SVID_OFFSET    1
+#define    RTL8367C_ACT2_SVID_MASK    0x2
+#define    RTL8367C_ACT2_CVID_OFFSET    0
+#define    RTL8367C_ACT2_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL2    0x0616
+#define    RTL8367C_OP5_NOT_OFFSET    14
+#define    RTL8367C_OP5_NOT_MASK    0x4000
+#define    RTL8367C_ACT5_GPIO_OFFSET    13
+#define    RTL8367C_ACT5_GPIO_MASK    0x2000
+#define    RTL8367C_ACT5_FORWARD_OFFSET    12
+#define    RTL8367C_ACT5_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT5_POLICING_OFFSET    11
+#define    RTL8367C_ACT5_POLICING_MASK    0x800
+#define    RTL8367C_ACT5_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT5_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT5_SVID_OFFSET    9
+#define    RTL8367C_ACT5_SVID_MASK    0x200
+#define    RTL8367C_ACT5_CVID_OFFSET    8
+#define    RTL8367C_ACT5_CVID_MASK    0x100
+#define    RTL8367C_OP4_NOT_OFFSET    6
+#define    RTL8367C_OP4_NOT_MASK    0x40
+#define    RTL8367C_ACT4_GPIO_OFFSET    5
+#define    RTL8367C_ACT4_GPIO_MASK    0x20
+#define    RTL8367C_ACT4_FORWARD_OFFSET    4
+#define    RTL8367C_ACT4_FORWARD_MASK    0x10
+#define    RTL8367C_ACT4_POLICING_OFFSET    3
+#define    RTL8367C_ACT4_POLICING_MASK    0x8
+#define    RTL8367C_ACT4_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT4_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT4_SVID_OFFSET    1
+#define    RTL8367C_ACT4_SVID_MASK    0x2
+#define    RTL8367C_ACT4_CVID_OFFSET    0
+#define    RTL8367C_ACT4_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL3    0x0617
+#define    RTL8367C_OP7_NOT_OFFSET    14
+#define    RTL8367C_OP7_NOT_MASK    0x4000
+#define    RTL8367C_ACT7_GPIO_OFFSET    13
+#define    RTL8367C_ACT7_GPIO_MASK    0x2000
+#define    RTL8367C_ACT7_FORWARD_OFFSET    12
+#define    RTL8367C_ACT7_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT7_POLICING_OFFSET    11
+#define    RTL8367C_ACT7_POLICING_MASK    0x800
+#define    RTL8367C_ACT7_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT7_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT7_SVID_OFFSET    9
+#define    RTL8367C_ACT7_SVID_MASK    0x200
+#define    RTL8367C_ACT7_CVID_OFFSET    8
+#define    RTL8367C_ACT7_CVID_MASK    0x100
+#define    RTL8367C_OP6_NOT_OFFSET    6
+#define    RTL8367C_OP6_NOT_MASK    0x40
+#define    RTL8367C_ACT6_GPIO_OFFSET    5
+#define    RTL8367C_ACT6_GPIO_MASK    0x20
+#define    RTL8367C_ACT6_FORWARD_OFFSET    4
+#define    RTL8367C_ACT6_FORWARD_MASK    0x10
+#define    RTL8367C_ACT6_POLICING_OFFSET    3
+#define    RTL8367C_ACT6_POLICING_MASK    0x8
+#define    RTL8367C_ACT6_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT6_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT6_SVID_OFFSET    1
+#define    RTL8367C_ACT6_SVID_MASK    0x2
+#define    RTL8367C_ACT6_CVID_OFFSET    0
+#define    RTL8367C_ACT6_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL4    0x0618
+#define    RTL8367C_OP9_NOT_OFFSET    14
+#define    RTL8367C_OP9_NOT_MASK    0x4000
+#define    RTL8367C_ACT9_GPIO_OFFSET    13
+#define    RTL8367C_ACT9_GPIO_MASK    0x2000
+#define    RTL8367C_ACT9_FORWARD_OFFSET    12
+#define    RTL8367C_ACT9_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT9_POLICING_OFFSET    11
+#define    RTL8367C_ACT9_POLICING_MASK    0x800
+#define    RTL8367C_ACT9_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT9_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT9_SVID_OFFSET    9
+#define    RTL8367C_ACT9_SVID_MASK    0x200
+#define    RTL8367C_ACT9_CVID_OFFSET    8
+#define    RTL8367C_ACT9_CVID_MASK    0x100
+#define    RTL8367C_OP8_NOT_OFFSET    6
+#define    RTL8367C_OP8_NOT_MASK    0x40
+#define    RTL8367C_ACT8_GPIO_OFFSET    5
+#define    RTL8367C_ACT8_GPIO_MASK    0x20
+#define    RTL8367C_ACT8_FORWARD_OFFSET    4
+#define    RTL8367C_ACT8_FORWARD_MASK    0x10
+#define    RTL8367C_ACT8_POLICING_OFFSET    3
+#define    RTL8367C_ACT8_POLICING_MASK    0x8
+#define    RTL8367C_ACT8_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT8_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT8_SVID_OFFSET    1
+#define    RTL8367C_ACT8_SVID_MASK    0x2
+#define    RTL8367C_ACT8_CVID_OFFSET    0
+#define    RTL8367C_ACT8_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL5    0x0619
+#define    RTL8367C_OP11_NOT_OFFSET    14
+#define    RTL8367C_OP11_NOT_MASK    0x4000
+#define    RTL8367C_ACT11_GPIO_OFFSET    13
+#define    RTL8367C_ACT11_GPIO_MASK    0x2000
+#define    RTL8367C_ACT11_FORWARD_OFFSET    12
+#define    RTL8367C_ACT11_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT11_POLICING_OFFSET    11
+#define    RTL8367C_ACT11_POLICING_MASK    0x800
+#define    RTL8367C_ACT11_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT11_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT11_SVID_OFFSET    9
+#define    RTL8367C_ACT11_SVID_MASK    0x200
+#define    RTL8367C_ACT11_CVID_OFFSET    8
+#define    RTL8367C_ACT11_CVID_MASK    0x100
+#define    RTL8367C_OP10_NOT_OFFSET    6
+#define    RTL8367C_OP10_NOT_MASK    0x40
+#define    RTL8367C_ACT10_GPIO_OFFSET    5
+#define    RTL8367C_ACT10_GPIO_MASK    0x20
+#define    RTL8367C_ACT10_FORWARD_OFFSET    4
+#define    RTL8367C_ACT10_FORWARD_MASK    0x10
+#define    RTL8367C_ACT10_POLICING_OFFSET    3
+#define    RTL8367C_ACT10_POLICING_MASK    0x8
+#define    RTL8367C_ACT10_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT10_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT10_SVID_OFFSET    1
+#define    RTL8367C_ACT10_SVID_MASK    0x2
+#define    RTL8367C_ACT10_CVID_OFFSET    0
+#define    RTL8367C_ACT10_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL6    0x061a
+#define    RTL8367C_OP13_NOT_OFFSET    14
+#define    RTL8367C_OP13_NOT_MASK    0x4000
+#define    RTL8367C_ACT13_GPIO_OFFSET    13
+#define    RTL8367C_ACT13_GPIO_MASK    0x2000
+#define    RTL8367C_ACT13_FORWARD_OFFSET    12
+#define    RTL8367C_ACT13_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT13_POLICING_OFFSET    11
+#define    RTL8367C_ACT13_POLICING_MASK    0x800
+#define    RTL8367C_ACT13_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT13_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT13_SVID_OFFSET    9
+#define    RTL8367C_ACT13_SVID_MASK    0x200
+#define    RTL8367C_ACT13_CVID_OFFSET    8
+#define    RTL8367C_ACT13_CVID_MASK    0x100
+#define    RTL8367C_OP12_NOT_OFFSET    6
+#define    RTL8367C_OP12_NOT_MASK    0x40
+#define    RTL8367C_ACT12_GPIO_OFFSET    5
+#define    RTL8367C_ACT12_GPIO_MASK    0x20
+#define    RTL8367C_ACT12_FORWARD_OFFSET    4
+#define    RTL8367C_ACT12_FORWARD_MASK    0x10
+#define    RTL8367C_ACT12_POLICING_OFFSET    3
+#define    RTL8367C_ACT12_POLICING_MASK    0x8
+#define    RTL8367C_ACT12_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT12_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT12_SVID_OFFSET    1
+#define    RTL8367C_ACT12_SVID_MASK    0x2
+#define    RTL8367C_ACT12_CVID_OFFSET    0
+#define    RTL8367C_ACT12_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL7    0x061b
+#define    RTL8367C_OP15_NOT_OFFSET    14
+#define    RTL8367C_OP15_NOT_MASK    0x4000
+#define    RTL8367C_ACT15_GPIO_OFFSET    13
+#define    RTL8367C_ACT15_GPIO_MASK    0x2000
+#define    RTL8367C_ACT15_FORWARD_OFFSET    12
+#define    RTL8367C_ACT15_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT15_POLICING_OFFSET    11
+#define    RTL8367C_ACT15_POLICING_MASK    0x800
+#define    RTL8367C_ACT15_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT15_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT15_SVID_OFFSET    9
+#define    RTL8367C_ACT15_SVID_MASK    0x200
+#define    RTL8367C_ACT15_CVID_OFFSET    8
+#define    RTL8367C_ACT15_CVID_MASK    0x100
+#define    RTL8367C_OP14_NOT_OFFSET    6
+#define    RTL8367C_OP14_NOT_MASK    0x40
+#define    RTL8367C_ACT14_GPIO_OFFSET    5
+#define    RTL8367C_ACT14_GPIO_MASK    0x20
+#define    RTL8367C_ACT14_FORWARD_OFFSET    4
+#define    RTL8367C_ACT14_FORWARD_MASK    0x10
+#define    RTL8367C_ACT14_POLICING_OFFSET    3
+#define    RTL8367C_ACT14_POLICING_MASK    0x8
+#define    RTL8367C_ACT14_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT14_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT14_SVID_OFFSET    1
+#define    RTL8367C_ACT14_SVID_MASK    0x2
+#define    RTL8367C_ACT14_CVID_OFFSET    0
+#define    RTL8367C_ACT14_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL8    0x061c
+#define    RTL8367C_OP17_NOT_OFFSET    14
+#define    RTL8367C_OP17_NOT_MASK    0x4000
+#define    RTL8367C_ACT17_GPIO_OFFSET    13
+#define    RTL8367C_ACT17_GPIO_MASK    0x2000
+#define    RTL8367C_ACT17_FORWARD_OFFSET    12
+#define    RTL8367C_ACT17_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT17_POLICING_OFFSET    11
+#define    RTL8367C_ACT17_POLICING_MASK    0x800
+#define    RTL8367C_ACT17_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT17_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT17_SVID_OFFSET    9
+#define    RTL8367C_ACT17_SVID_MASK    0x200
+#define    RTL8367C_ACT17_CVID_OFFSET    8
+#define    RTL8367C_ACT17_CVID_MASK    0x100
+#define    RTL8367C_OP16_NOT_OFFSET    6
+#define    RTL8367C_OP16_NOT_MASK    0x40
+#define    RTL8367C_ACT16_GPIO_OFFSET    5
+#define    RTL8367C_ACT16_GPIO_MASK    0x20
+#define    RTL8367C_ACT16_FORWARD_OFFSET    4
+#define    RTL8367C_ACT16_FORWARD_MASK    0x10
+#define    RTL8367C_ACT16_POLICING_OFFSET    3
+#define    RTL8367C_ACT16_POLICING_MASK    0x8
+#define    RTL8367C_ACT16_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT16_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT16_SVID_OFFSET    1
+#define    RTL8367C_ACT16_SVID_MASK    0x2
+#define    RTL8367C_ACT16_CVID_OFFSET    0
+#define    RTL8367C_ACT16_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL9    0x061d
+#define    RTL8367C_OP19_NOT_OFFSET    14
+#define    RTL8367C_OP19_NOT_MASK    0x4000
+#define    RTL8367C_ACT19_GPIO_OFFSET    13
+#define    RTL8367C_ACT19_GPIO_MASK    0x2000
+#define    RTL8367C_ACT19_FORWARD_OFFSET    12
+#define    RTL8367C_ACT19_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT19_POLICING_OFFSET    11
+#define    RTL8367C_ACT19_POLICING_MASK    0x800
+#define    RTL8367C_ACT19_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT19_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT19_SVID_OFFSET    9
+#define    RTL8367C_ACT19_SVID_MASK    0x200
+#define    RTL8367C_ACT19_CVID_OFFSET    8
+#define    RTL8367C_ACT19_CVID_MASK    0x100
+#define    RTL8367C_OP18_NOT_OFFSET    6
+#define    RTL8367C_OP18_NOT_MASK    0x40
+#define    RTL8367C_ACT18_GPIO_OFFSET    5
+#define    RTL8367C_ACT18_GPIO_MASK    0x20
+#define    RTL8367C_ACT18_FORWARD_OFFSET    4
+#define    RTL8367C_ACT18_FORWARD_MASK    0x10
+#define    RTL8367C_ACT18_POLICING_OFFSET    3
+#define    RTL8367C_ACT18_POLICING_MASK    0x8
+#define    RTL8367C_ACT18_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT18_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT18_SVID_OFFSET    1
+#define    RTL8367C_ACT18_SVID_MASK    0x2
+#define    RTL8367C_ACT18_CVID_OFFSET    0
+#define    RTL8367C_ACT18_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL10    0x061e
+#define    RTL8367C_OP21_NOT_OFFSET    14
+#define    RTL8367C_OP21_NOT_MASK    0x4000
+#define    RTL8367C_ACT21_GPIO_OFFSET    13
+#define    RTL8367C_ACT21_GPIO_MASK    0x2000
+#define    RTL8367C_ACT21_FORWARD_OFFSET    12
+#define    RTL8367C_ACT21_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT21_POLICING_OFFSET    11
+#define    RTL8367C_ACT21_POLICING_MASK    0x800
+#define    RTL8367C_ACT21_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT21_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT21_SVID_OFFSET    9
+#define    RTL8367C_ACT21_SVID_MASK    0x200
+#define    RTL8367C_ACT21_CVID_OFFSET    8
+#define    RTL8367C_ACT21_CVID_MASK    0x100
+#define    RTL8367C_OP20_NOT_OFFSET    6
+#define    RTL8367C_OP20_NOT_MASK    0x40
+#define    RTL8367C_ACT20_GPIO_OFFSET    5
+#define    RTL8367C_ACT20_GPIO_MASK    0x20
+#define    RTL8367C_ACT20_FORWARD_OFFSET    4
+#define    RTL8367C_ACT20_FORWARD_MASK    0x10
+#define    RTL8367C_ACT20_POLICING_OFFSET    3
+#define    RTL8367C_ACT20_POLICING_MASK    0x8
+#define    RTL8367C_ACT20_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT20_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT20_SVID_OFFSET    1
+#define    RTL8367C_ACT20_SVID_MASK    0x2
+#define    RTL8367C_ACT20_CVID_OFFSET    0
+#define    RTL8367C_ACT20_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL11    0x061f
+#define    RTL8367C_OP23_NOT_OFFSET    14
+#define    RTL8367C_OP23_NOT_MASK    0x4000
+#define    RTL8367C_ACT23_GPIO_OFFSET    13
+#define    RTL8367C_ACT23_GPIO_MASK    0x2000
+#define    RTL8367C_ACT23_FORWARD_OFFSET    12
+#define    RTL8367C_ACT23_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT23_POLICING_OFFSET    11
+#define    RTL8367C_ACT23_POLICING_MASK    0x800
+#define    RTL8367C_ACT23_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT23_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT23_SVID_OFFSET    9
+#define    RTL8367C_ACT23_SVID_MASK    0x200
+#define    RTL8367C_ACT23_CVID_OFFSET    8
+#define    RTL8367C_ACT23_CVID_MASK    0x100
+#define    RTL8367C_OP22_NOT_OFFSET    6
+#define    RTL8367C_OP22_NOT_MASK    0x40
+#define    RTL8367C_ACT22_GPIO_OFFSET    5
+#define    RTL8367C_ACT22_GPIO_MASK    0x20
+#define    RTL8367C_ACT22_FORWARD_OFFSET    4
+#define    RTL8367C_ACT22_FORWARD_MASK    0x10
+#define    RTL8367C_ACT22_POLICING_OFFSET    3
+#define    RTL8367C_ACT22_POLICING_MASK    0x8
+#define    RTL8367C_ACT22_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT22_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT22_SVID_OFFSET    1
+#define    RTL8367C_ACT22_SVID_MASK    0x2
+#define    RTL8367C_ACT22_CVID_OFFSET    0
+#define    RTL8367C_ACT22_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL12    0x0620
+#define    RTL8367C_OP25_NOT_OFFSET    14
+#define    RTL8367C_OP25_NOT_MASK    0x4000
+#define    RTL8367C_ACT25_GPIO_OFFSET    13
+#define    RTL8367C_ACT25_GPIO_MASK    0x2000
+#define    RTL8367C_ACT25_FORWARD_OFFSET    12
+#define    RTL8367C_ACT25_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT25_POLICING_OFFSET    11
+#define    RTL8367C_ACT25_POLICING_MASK    0x800
+#define    RTL8367C_ACT25_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT25_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT25_SVID_OFFSET    9
+#define    RTL8367C_ACT25_SVID_MASK    0x200
+#define    RTL8367C_ACT25_CVID_OFFSET    8
+#define    RTL8367C_ACT25_CVID_MASK    0x100
+#define    RTL8367C_OP24_NOT_OFFSET    6
+#define    RTL8367C_OP24_NOT_MASK    0x40
+#define    RTL8367C_ACT24_GPIO_OFFSET    5
+#define    RTL8367C_ACT24_GPIO_MASK    0x20
+#define    RTL8367C_ACT24_FORWARD_OFFSET    4
+#define    RTL8367C_ACT24_FORWARD_MASK    0x10
+#define    RTL8367C_ACT24_POLICING_OFFSET    3
+#define    RTL8367C_ACT24_POLICING_MASK    0x8
+#define    RTL8367C_ACT24_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT24_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT24_SVID_OFFSET    1
+#define    RTL8367C_ACT24_SVID_MASK    0x2
+#define    RTL8367C_ACT24_CVID_OFFSET    0
+#define    RTL8367C_ACT24_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL13    0x0621
+#define    RTL8367C_OP27_NOT_OFFSET    14
+#define    RTL8367C_OP27_NOT_MASK    0x4000
+#define    RTL8367C_ACT27_GPIO_OFFSET    13
+#define    RTL8367C_ACT27_GPIO_MASK    0x2000
+#define    RTL8367C_ACT27_FORWARD_OFFSET    12
+#define    RTL8367C_ACT27_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT27_POLICING_OFFSET    11
+#define    RTL8367C_ACT27_POLICING_MASK    0x800
+#define    RTL8367C_ACT27_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT27_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT27_SVID_OFFSET    9
+#define    RTL8367C_ACT27_SVID_MASK    0x200
+#define    RTL8367C_ACT27_CVID_OFFSET    8
+#define    RTL8367C_ACT27_CVID_MASK    0x100
+#define    RTL8367C_OP26_NOT_OFFSET    6
+#define    RTL8367C_OP26_NOT_MASK    0x40
+#define    RTL8367C_ACT26_GPIO_OFFSET    5
+#define    RTL8367C_ACT26_GPIO_MASK    0x20
+#define    RTL8367C_ACT26_FORWARD_OFFSET    4
+#define    RTL8367C_ACT26_FORWARD_MASK    0x10
+#define    RTL8367C_ACT26_POLICING_OFFSET    3
+#define    RTL8367C_ACT26_POLICING_MASK    0x8
+#define    RTL8367C_ACT26_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT26_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT26_SVID_OFFSET    1
+#define    RTL8367C_ACT26_SVID_MASK    0x2
+#define    RTL8367C_ACT26_CVID_OFFSET    0
+#define    RTL8367C_ACT26_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL14    0x0622
+#define    RTL8367C_OP29_NOT_OFFSET    14
+#define    RTL8367C_OP29_NOT_MASK    0x4000
+#define    RTL8367C_ACT29_GPIO_OFFSET    13
+#define    RTL8367C_ACT29_GPIO_MASK    0x2000
+#define    RTL8367C_ACT29_FORWARD_OFFSET    12
+#define    RTL8367C_ACT29_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT29_POLICING_OFFSET    11
+#define    RTL8367C_ACT29_POLICING_MASK    0x800
+#define    RTL8367C_ACT29_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT29_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT29_SVID_OFFSET    9
+#define    RTL8367C_ACT29_SVID_MASK    0x200
+#define    RTL8367C_ACT29_CVID_OFFSET    8
+#define    RTL8367C_ACT29_CVID_MASK    0x100
+#define    RTL8367C_OP28_NOT_OFFSET    6
+#define    RTL8367C_OP28_NOT_MASK    0x40
+#define    RTL8367C_ACT28_GPIO_OFFSET    5
+#define    RTL8367C_ACT28_GPIO_MASK    0x20
+#define    RTL8367C_ACT28_FORWARD_OFFSET    4
+#define    RTL8367C_ACT28_FORWARD_MASK    0x10
+#define    RTL8367C_ACT28_POLICING_OFFSET    3
+#define    RTL8367C_ACT28_POLICING_MASK    0x8
+#define    RTL8367C_ACT28_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT28_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT28_SVID_OFFSET    1
+#define    RTL8367C_ACT28_SVID_MASK    0x2
+#define    RTL8367C_ACT28_CVID_OFFSET    0
+#define    RTL8367C_ACT28_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL15    0x0623
+#define    RTL8367C_OP31_NOT_OFFSET    14
+#define    RTL8367C_OP31_NOT_MASK    0x4000
+#define    RTL8367C_ACT31_GPIO_OFFSET    13
+#define    RTL8367C_ACT31_GPIO_MASK    0x2000
+#define    RTL8367C_ACT31_FORWARD_OFFSET    12
+#define    RTL8367C_ACT31_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT31_POLICING_OFFSET    11
+#define    RTL8367C_ACT31_POLICING_MASK    0x800
+#define    RTL8367C_ACT31_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT31_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT31_SVID_OFFSET    9
+#define    RTL8367C_ACT31_SVID_MASK    0x200
+#define    RTL8367C_ACT31_CVID_OFFSET    8
+#define    RTL8367C_ACT31_CVID_MASK    0x100
+#define    RTL8367C_OP30_NOT_OFFSET    6
+#define    RTL8367C_OP30_NOT_MASK    0x40
+#define    RTL8367C_ACT30_GPIO_OFFSET    5
+#define    RTL8367C_ACT30_GPIO_MASK    0x20
+#define    RTL8367C_ACT30_FORWARD_OFFSET    4
+#define    RTL8367C_ACT30_FORWARD_MASK    0x10
+#define    RTL8367C_ACT30_POLICING_OFFSET    3
+#define    RTL8367C_ACT30_POLICING_MASK    0x8
+#define    RTL8367C_ACT30_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT30_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT30_SVID_OFFSET    1
+#define    RTL8367C_ACT30_SVID_MASK    0x2
+#define    RTL8367C_ACT30_CVID_OFFSET    0
+#define    RTL8367C_ACT30_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL16    0x0624
+#define    RTL8367C_OP33_NOT_OFFSET    14
+#define    RTL8367C_OP33_NOT_MASK    0x4000
+#define    RTL8367C_ACT33_GPIO_OFFSET    13
+#define    RTL8367C_ACT33_GPIO_MASK    0x2000
+#define    RTL8367C_ACT33_FORWARD_OFFSET    12
+#define    RTL8367C_ACT33_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT33_POLICING_OFFSET    11
+#define    RTL8367C_ACT33_POLICING_MASK    0x800
+#define    RTL8367C_ACT33_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT33_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT33_SVID_OFFSET    9
+#define    RTL8367C_ACT33_SVID_MASK    0x200
+#define    RTL8367C_ACT33_CVID_OFFSET    8
+#define    RTL8367C_ACT33_CVID_MASK    0x100
+#define    RTL8367C_OP32_NOT_OFFSET    6
+#define    RTL8367C_OP32_NOT_MASK    0x40
+#define    RTL8367C_ACT32_GPIO_OFFSET    5
+#define    RTL8367C_ACT32_GPIO_MASK    0x20
+#define    RTL8367C_ACT32_FORWARD_OFFSET    4
+#define    RTL8367C_ACT32_FORWARD_MASK    0x10
+#define    RTL8367C_ACT32_POLICING_OFFSET    3
+#define    RTL8367C_ACT32_POLICING_MASK    0x8
+#define    RTL8367C_ACT32_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT32_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT32_SVID_OFFSET    1
+#define    RTL8367C_ACT32_SVID_MASK    0x2
+#define    RTL8367C_ACT32_CVID_OFFSET    0
+#define    RTL8367C_ACT32_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL17    0x0625
+#define    RTL8367C_OP35_NOT_OFFSET    14
+#define    RTL8367C_OP35_NOT_MASK    0x4000
+#define    RTL8367C_ACT35_GPIO_OFFSET    13
+#define    RTL8367C_ACT35_GPIO_MASK    0x2000
+#define    RTL8367C_ACT35_FORWARD_OFFSET    12
+#define    RTL8367C_ACT35_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT35_POLICING_OFFSET    11
+#define    RTL8367C_ACT35_POLICING_MASK    0x800
+#define    RTL8367C_ACT35_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT35_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT35_SVID_OFFSET    9
+#define    RTL8367C_ACT35_SVID_MASK    0x200
+#define    RTL8367C_ACT35_CVID_OFFSET    8
+#define    RTL8367C_ACT35_CVID_MASK    0x100
+#define    RTL8367C_OP34_NOT_OFFSET    6
+#define    RTL8367C_OP34_NOT_MASK    0x40
+#define    RTL8367C_ACT34_GPIO_OFFSET    5
+#define    RTL8367C_ACT34_GPIO_MASK    0x20
+#define    RTL8367C_ACT34_FORWARD_OFFSET    4
+#define    RTL8367C_ACT34_FORWARD_MASK    0x10
+#define    RTL8367C_ACT34_POLICING_OFFSET    3
+#define    RTL8367C_ACT34_POLICING_MASK    0x8
+#define    RTL8367C_ACT34_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT34_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT34_SVID_OFFSET    1
+#define    RTL8367C_ACT34_SVID_MASK    0x2
+#define    RTL8367C_ACT34_CVID_OFFSET    0
+#define    RTL8367C_ACT34_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL18    0x0626
+#define    RTL8367C_OP37_NOT_OFFSET    14
+#define    RTL8367C_OP37_NOT_MASK    0x4000
+#define    RTL8367C_ACT37_GPIO_OFFSET    13
+#define    RTL8367C_ACT37_GPIO_MASK    0x2000
+#define    RTL8367C_ACT37_FORWARD_OFFSET    12
+#define    RTL8367C_ACT37_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT37_POLICING_OFFSET    11
+#define    RTL8367C_ACT37_POLICING_MASK    0x800
+#define    RTL8367C_ACT37_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT37_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT37_SVID_OFFSET    9
+#define    RTL8367C_ACT37_SVID_MASK    0x200
+#define    RTL8367C_ACT37_CVID_OFFSET    8
+#define    RTL8367C_ACT37_CVID_MASK    0x100
+#define    RTL8367C_OP36_NOT_OFFSET    6
+#define    RTL8367C_OP36_NOT_MASK    0x40
+#define    RTL8367C_ACT36_GPIO_OFFSET    5
+#define    RTL8367C_ACT36_GPIO_MASK    0x20
+#define    RTL8367C_ACT36_FORWARD_OFFSET    4
+#define    RTL8367C_ACT36_FORWARD_MASK    0x10
+#define    RTL8367C_ACT36_POLICING_OFFSET    3
+#define    RTL8367C_ACT36_POLICING_MASK    0x8
+#define    RTL8367C_ACT36_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT36_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT36_SVID_OFFSET    1
+#define    RTL8367C_ACT36_SVID_MASK    0x2
+#define    RTL8367C_ACT36_CVID_OFFSET    0
+#define    RTL8367C_ACT36_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL19    0x0627
+#define    RTL8367C_OP39_NOT_OFFSET    14
+#define    RTL8367C_OP39_NOT_MASK    0x4000
+#define    RTL8367C_ACT39_GPIO_OFFSET    13
+#define    RTL8367C_ACT39_GPIO_MASK    0x2000
+#define    RTL8367C_ACT39_FORWARD_OFFSET    12
+#define    RTL8367C_ACT39_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT39_POLICING_OFFSET    11
+#define    RTL8367C_ACT39_POLICING_MASK    0x800
+#define    RTL8367C_ACT39_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT39_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT39_SVID_OFFSET    9
+#define    RTL8367C_ACT39_SVID_MASK    0x200
+#define    RTL8367C_ACT39_CVID_OFFSET    8
+#define    RTL8367C_ACT39_CVID_MASK    0x100
+#define    RTL8367C_OP38_NOT_OFFSET    6
+#define    RTL8367C_OP38_NOT_MASK    0x40
+#define    RTL8367C_ACT38_GPIO_OFFSET    5
+#define    RTL8367C_ACT38_GPIO_MASK    0x20
+#define    RTL8367C_ACT38_FORWARD_OFFSET    4
+#define    RTL8367C_ACT38_FORWARD_MASK    0x10
+#define    RTL8367C_ACT38_POLICING_OFFSET    3
+#define    RTL8367C_ACT38_POLICING_MASK    0x8
+#define    RTL8367C_ACT38_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT38_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT38_SVID_OFFSET    1
+#define    RTL8367C_ACT38_SVID_MASK    0x2
+#define    RTL8367C_ACT38_CVID_OFFSET    0
+#define    RTL8367C_ACT38_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL20    0x0628
+#define    RTL8367C_OP41_NOT_OFFSET    14
+#define    RTL8367C_OP41_NOT_MASK    0x4000
+#define    RTL8367C_ACT41_GPIO_OFFSET    13
+#define    RTL8367C_ACT41_GPIO_MASK    0x2000
+#define    RTL8367C_ACT41_FORWARD_OFFSET    12
+#define    RTL8367C_ACT41_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT41_POLICING_OFFSET    11
+#define    RTL8367C_ACT41_POLICING_MASK    0x800
+#define    RTL8367C_ACT41_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT41_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT41_SVID_OFFSET    9
+#define    RTL8367C_ACT41_SVID_MASK    0x200
+#define    RTL8367C_ACT41_CVID_OFFSET    8
+#define    RTL8367C_ACT41_CVID_MASK    0x100
+#define    RTL8367C_OP40_NOT_OFFSET    6
+#define    RTL8367C_OP40_NOT_MASK    0x40
+#define    RTL8367C_ACT40_GPIO_OFFSET    5
+#define    RTL8367C_ACT40_GPIO_MASK    0x20
+#define    RTL8367C_ACT40_FORWARD_OFFSET    4
+#define    RTL8367C_ACT40_FORWARD_MASK    0x10
+#define    RTL8367C_ACT40_POLICING_OFFSET    3
+#define    RTL8367C_ACT40_POLICING_MASK    0x8
+#define    RTL8367C_ACT40_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT40_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT40_SVID_OFFSET    1
+#define    RTL8367C_ACT40_SVID_MASK    0x2
+#define    RTL8367C_ACT40_CVID_OFFSET    0
+#define    RTL8367C_ACT40_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL21    0x0629
+#define    RTL8367C_OP43_NOT_OFFSET    14
+#define    RTL8367C_OP43_NOT_MASK    0x4000
+#define    RTL8367C_ACT43_GPIO_OFFSET    13
+#define    RTL8367C_ACT43_GPIO_MASK    0x2000
+#define    RTL8367C_ACT43_FORWARD_OFFSET    12
+#define    RTL8367C_ACT43_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT43_POLICING_OFFSET    11
+#define    RTL8367C_ACT43_POLICING_MASK    0x800
+#define    RTL8367C_ACT43_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT43_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT43_SVID_OFFSET    9
+#define    RTL8367C_ACT43_SVID_MASK    0x200
+#define    RTL8367C_ACT43_CVID_OFFSET    8
+#define    RTL8367C_ACT43_CVID_MASK    0x100
+#define    RTL8367C_OP42_NOT_OFFSET    6
+#define    RTL8367C_OP42_NOT_MASK    0x40
+#define    RTL8367C_ACT42_GPIO_OFFSET    5
+#define    RTL8367C_ACT42_GPIO_MASK    0x20
+#define    RTL8367C_ACT42_FORWARD_OFFSET    4
+#define    RTL8367C_ACT42_FORWARD_MASK    0x10
+#define    RTL8367C_ACT42_POLICING_OFFSET    3
+#define    RTL8367C_ACT42_POLICING_MASK    0x8
+#define    RTL8367C_ACT42_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT42_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT42_SVID_OFFSET    1
+#define    RTL8367C_ACT42_SVID_MASK    0x2
+#define    RTL8367C_ACT42_CVID_OFFSET    0
+#define    RTL8367C_ACT42_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL22    0x062a
+#define    RTL8367C_OP45_NOT_OFFSET    14
+#define    RTL8367C_OP45_NOT_MASK    0x4000
+#define    RTL8367C_ACT45_GPIO_OFFSET    13
+#define    RTL8367C_ACT45_GPIO_MASK    0x2000
+#define    RTL8367C_ACT45_FORWARD_OFFSET    12
+#define    RTL8367C_ACT45_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT45_POLICING_OFFSET    11
+#define    RTL8367C_ACT45_POLICING_MASK    0x800
+#define    RTL8367C_ACT45_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT45_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT45_SVID_OFFSET    9
+#define    RTL8367C_ACT45_SVID_MASK    0x200
+#define    RTL8367C_ACT45_CVID_OFFSET    8
+#define    RTL8367C_ACT45_CVID_MASK    0x100
+#define    RTL8367C_OP44_NOT_OFFSET    6
+#define    RTL8367C_OP44_NOT_MASK    0x40
+#define    RTL8367C_ACT44_GPIO_OFFSET    5
+#define    RTL8367C_ACT44_GPIO_MASK    0x20
+#define    RTL8367C_ACT44_FORWARD_OFFSET    4
+#define    RTL8367C_ACT44_FORWARD_MASK    0x10
+#define    RTL8367C_ACT44_POLICING_OFFSET    3
+#define    RTL8367C_ACT44_POLICING_MASK    0x8
+#define    RTL8367C_ACT44_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT44_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT44_SVID_OFFSET    1
+#define    RTL8367C_ACT44_SVID_MASK    0x2
+#define    RTL8367C_ACT44_CVID_OFFSET    0
+#define    RTL8367C_ACT44_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL23    0x062b
+#define    RTL8367C_OP47_NOT_OFFSET    14
+#define    RTL8367C_OP47_NOT_MASK    0x4000
+#define    RTL8367C_ACT47_GPIO_OFFSET    13
+#define    RTL8367C_ACT47_GPIO_MASK    0x2000
+#define    RTL8367C_ACT47_FORWARD_OFFSET    12
+#define    RTL8367C_ACT47_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT47_POLICING_OFFSET    11
+#define    RTL8367C_ACT47_POLICING_MASK    0x800
+#define    RTL8367C_ACT47_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT47_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT47_SVID_OFFSET    9
+#define    RTL8367C_ACT47_SVID_MASK    0x200
+#define    RTL8367C_ACT47_CVID_OFFSET    8
+#define    RTL8367C_ACT47_CVID_MASK    0x100
+#define    RTL8367C_OP46_NOT_OFFSET    6
+#define    RTL8367C_OP46_NOT_MASK    0x40
+#define    RTL8367C_ACT46_GPIO_OFFSET    5
+#define    RTL8367C_ACT46_GPIO_MASK    0x20
+#define    RTL8367C_ACT46_FORWARD_OFFSET    4
+#define    RTL8367C_ACT46_FORWARD_MASK    0x10
+#define    RTL8367C_ACT46_POLICING_OFFSET    3
+#define    RTL8367C_ACT46_POLICING_MASK    0x8
+#define    RTL8367C_ACT46_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT46_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT46_SVID_OFFSET    1
+#define    RTL8367C_ACT46_SVID_MASK    0x2
+#define    RTL8367C_ACT46_CVID_OFFSET    0
+#define    RTL8367C_ACT46_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL24    0x062c
+#define    RTL8367C_OP49_NOT_OFFSET    14
+#define    RTL8367C_OP49_NOT_MASK    0x4000
+#define    RTL8367C_ACT49_GPIO_OFFSET    13
+#define    RTL8367C_ACT49_GPIO_MASK    0x2000
+#define    RTL8367C_ACT49_FORWARD_OFFSET    12
+#define    RTL8367C_ACT49_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT49_POLICING_OFFSET    11
+#define    RTL8367C_ACT49_POLICING_MASK    0x800
+#define    RTL8367C_ACT49_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT49_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT49_SVID_OFFSET    9
+#define    RTL8367C_ACT49_SVID_MASK    0x200
+#define    RTL8367C_ACT49_CVID_OFFSET    8
+#define    RTL8367C_ACT49_CVID_MASK    0x100
+#define    RTL8367C_OP48_NOT_OFFSET    6
+#define    RTL8367C_OP48_NOT_MASK    0x40
+#define    RTL8367C_ACT48_GPIO_OFFSET    5
+#define    RTL8367C_ACT48_GPIO_MASK    0x20
+#define    RTL8367C_ACT48_FORWARD_OFFSET    4
+#define    RTL8367C_ACT48_FORWARD_MASK    0x10
+#define    RTL8367C_ACT48_POLICING_OFFSET    3
+#define    RTL8367C_ACT48_POLICING_MASK    0x8
+#define    RTL8367C_ACT48_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT48_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT48_SVID_OFFSET    1
+#define    RTL8367C_ACT48_SVID_MASK    0x2
+#define    RTL8367C_ACT48_CVID_OFFSET    0
+#define    RTL8367C_ACT48_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL25    0x062d
+#define    RTL8367C_OP51_NOT_OFFSET    14
+#define    RTL8367C_OP51_NOT_MASK    0x4000
+#define    RTL8367C_ACT51_GPIO_OFFSET    13
+#define    RTL8367C_ACT51_GPIO_MASK    0x2000
+#define    RTL8367C_ACT51_FORWARD_OFFSET    12
+#define    RTL8367C_ACT51_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT51_POLICING_OFFSET    11
+#define    RTL8367C_ACT51_POLICING_MASK    0x800
+#define    RTL8367C_ACT51_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT51_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT51_SVID_OFFSET    9
+#define    RTL8367C_ACT51_SVID_MASK    0x200
+#define    RTL8367C_ACT51_CVID_OFFSET    8
+#define    RTL8367C_ACT51_CVID_MASK    0x100
+#define    RTL8367C_OP50_NOT_OFFSET    6
+#define    RTL8367C_OP50_NOT_MASK    0x40
+#define    RTL8367C_ACT50_GPIO_OFFSET    5
+#define    RTL8367C_ACT50_GPIO_MASK    0x20
+#define    RTL8367C_ACT50_FORWARD_OFFSET    4
+#define    RTL8367C_ACT50_FORWARD_MASK    0x10
+#define    RTL8367C_ACT50_POLICING_OFFSET    3
+#define    RTL8367C_ACT50_POLICING_MASK    0x8
+#define    RTL8367C_ACT50_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT50_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT50_SVID_OFFSET    1
+#define    RTL8367C_ACT50_SVID_MASK    0x2
+#define    RTL8367C_ACT50_CVID_OFFSET    0
+#define    RTL8367C_ACT50_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL26    0x062e
+#define    RTL8367C_OP53_NOT_OFFSET    14
+#define    RTL8367C_OP53_NOT_MASK    0x4000
+#define    RTL8367C_ACT53_GPIO_OFFSET    13
+#define    RTL8367C_ACT53_GPIO_MASK    0x2000
+#define    RTL8367C_ACT53_FORWARD_OFFSET    12
+#define    RTL8367C_ACT53_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT53_POLICING_OFFSET    11
+#define    RTL8367C_ACT53_POLICING_MASK    0x800
+#define    RTL8367C_ACT53_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT53_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT53_SVID_OFFSET    9
+#define    RTL8367C_ACT53_SVID_MASK    0x200
+#define    RTL8367C_ACT53_CVID_OFFSET    8
+#define    RTL8367C_ACT53_CVID_MASK    0x100
+#define    RTL8367C_OP52_NOT_OFFSET    6
+#define    RTL8367C_OP52_NOT_MASK    0x40
+#define    RTL8367C_ACT52_GPIO_OFFSET    5
+#define    RTL8367C_ACT52_GPIO_MASK    0x20
+#define    RTL8367C_ACT52_FORWARD_OFFSET    4
+#define    RTL8367C_ACT52_FORWARD_MASK    0x10
+#define    RTL8367C_ACT52_POLICING_OFFSET    3
+#define    RTL8367C_ACT52_POLICING_MASK    0x8
+#define    RTL8367C_ACT52_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT52_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT52_SVID_OFFSET    1
+#define    RTL8367C_ACT52_SVID_MASK    0x2
+#define    RTL8367C_ACT52_CVID_OFFSET    0
+#define    RTL8367C_ACT52_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL27    0x062f
+#define    RTL8367C_OP55_NOT_OFFSET    14
+#define    RTL8367C_OP55_NOT_MASK    0x4000
+#define    RTL8367C_ACT55_GPIO_OFFSET    13
+#define    RTL8367C_ACT55_GPIO_MASK    0x2000
+#define    RTL8367C_ACT55_FORWARD_OFFSET    12
+#define    RTL8367C_ACT55_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT55_POLICING_OFFSET    11
+#define    RTL8367C_ACT55_POLICING_MASK    0x800
+#define    RTL8367C_ACT55_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT55_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT55_SVID_OFFSET    9
+#define    RTL8367C_ACT55_SVID_MASK    0x200
+#define    RTL8367C_ACT55_CVID_OFFSET    8
+#define    RTL8367C_ACT55_CVID_MASK    0x100
+#define    RTL8367C_OP54_NOT_OFFSET    6
+#define    RTL8367C_OP54_NOT_MASK    0x40
+#define    RTL8367C_ACT54_GPIO_OFFSET    5
+#define    RTL8367C_ACT54_GPIO_MASK    0x20
+#define    RTL8367C_ACT54_FORWARD_OFFSET    4
+#define    RTL8367C_ACT54_FORWARD_MASK    0x10
+#define    RTL8367C_ACT54_POLICING_OFFSET    3
+#define    RTL8367C_ACT54_POLICING_MASK    0x8
+#define    RTL8367C_ACT54_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT54_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT54_SVID_OFFSET    1
+#define    RTL8367C_ACT54_SVID_MASK    0x2
+#define    RTL8367C_ACT54_CVID_OFFSET    0
+#define    RTL8367C_ACT54_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL28    0x0630
+#define    RTL8367C_OP57_NOT_OFFSET    14
+#define    RTL8367C_OP57_NOT_MASK    0x4000
+#define    RTL8367C_ACT57_GPIO_OFFSET    13
+#define    RTL8367C_ACT57_GPIO_MASK    0x2000
+#define    RTL8367C_ACT57_FORWARD_OFFSET    12
+#define    RTL8367C_ACT57_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT57_POLICING_OFFSET    11
+#define    RTL8367C_ACT57_POLICING_MASK    0x800
+#define    RTL8367C_ACT57_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT57_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT57_SVID_OFFSET    9
+#define    RTL8367C_ACT57_SVID_MASK    0x200
+#define    RTL8367C_ACT57_CVID_OFFSET    8
+#define    RTL8367C_ACT57_CVID_MASK    0x100
+#define    RTL8367C_OP56_NOT_OFFSET    6
+#define    RTL8367C_OP56_NOT_MASK    0x40
+#define    RTL8367C_ACT56_GPIO_OFFSET    5
+#define    RTL8367C_ACT56_GPIO_MASK    0x20
+#define    RTL8367C_ACT56_FORWARD_OFFSET    4
+#define    RTL8367C_ACT56_FORWARD_MASK    0x10
+#define    RTL8367C_ACT56_POLICING_OFFSET    3
+#define    RTL8367C_ACT56_POLICING_MASK    0x8
+#define    RTL8367C_ACT56_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT56_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT56_SVID_OFFSET    1
+#define    RTL8367C_ACT56_SVID_MASK    0x2
+#define    RTL8367C_ACT56_CVID_OFFSET    0
+#define    RTL8367C_ACT56_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL29    0x0631
+#define    RTL8367C_OP59_NOT_OFFSET    14
+#define    RTL8367C_OP59_NOT_MASK    0x4000
+#define    RTL8367C_ACT59_GPIO_OFFSET    13
+#define    RTL8367C_ACT59_GPIO_MASK    0x2000
+#define    RTL8367C_ACT59_FORWARD_OFFSET    12
+#define    RTL8367C_ACT59_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT59_POLICING_OFFSET    11
+#define    RTL8367C_ACT59_POLICING_MASK    0x800
+#define    RTL8367C_ACT59_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT59_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT59_SVID_OFFSET    9
+#define    RTL8367C_ACT59_SVID_MASK    0x200
+#define    RTL8367C_ACT59_CVID_OFFSET    8
+#define    RTL8367C_ACT59_CVID_MASK    0x100
+#define    RTL8367C_OP58_NOT_OFFSET    6
+#define    RTL8367C_OP58_NOT_MASK    0x40
+#define    RTL8367C_ACT58_GPIO_OFFSET    5
+#define    RTL8367C_ACT58_GPIO_MASK    0x20
+#define    RTL8367C_ACT58_FORWARD_OFFSET    4
+#define    RTL8367C_ACT58_FORWARD_MASK    0x10
+#define    RTL8367C_ACT58_POLICING_OFFSET    3
+#define    RTL8367C_ACT58_POLICING_MASK    0x8
+#define    RTL8367C_ACT58_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT58_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT58_SVID_OFFSET    1
+#define    RTL8367C_ACT58_SVID_MASK    0x2
+#define    RTL8367C_ACT58_CVID_OFFSET    0
+#define    RTL8367C_ACT58_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL30    0x0632
+#define    RTL8367C_OP61_NOT_OFFSET    14
+#define    RTL8367C_OP61_NOT_MASK    0x4000
+#define    RTL8367C_ACT61_GPIO_OFFSET    13
+#define    RTL8367C_ACT61_GPIO_MASK    0x2000
+#define    RTL8367C_ACT61_FORWARD_OFFSET    12
+#define    RTL8367C_ACT61_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT61_POLICING_OFFSET    11
+#define    RTL8367C_ACT61_POLICING_MASK    0x800
+#define    RTL8367C_ACT61_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT61_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT61_SVID_OFFSET    9
+#define    RTL8367C_ACT61_SVID_MASK    0x200
+#define    RTL8367C_ACT61_CVID_OFFSET    8
+#define    RTL8367C_ACT61_CVID_MASK    0x100
+#define    RTL8367C_OP60_NOT_OFFSET    6
+#define    RTL8367C_OP60_NOT_MASK    0x40
+#define    RTL8367C_ACT60_GPIO_OFFSET    5
+#define    RTL8367C_ACT60_GPIO_MASK    0x20
+#define    RTL8367C_ACT60_FORWARD_OFFSET    4
+#define    RTL8367C_ACT60_FORWARD_MASK    0x10
+#define    RTL8367C_ACT60_POLICING_OFFSET    3
+#define    RTL8367C_ACT60_POLICING_MASK    0x8
+#define    RTL8367C_ACT60_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT60_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT60_SVID_OFFSET    1
+#define    RTL8367C_ACT60_SVID_MASK    0x2
+#define    RTL8367C_ACT60_CVID_OFFSET    0
+#define    RTL8367C_ACT60_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL31    0x0633
+#define    RTL8367C_OP63_NOT_OFFSET    14
+#define    RTL8367C_OP63_NOT_MASK    0x4000
+#define    RTL8367C_ACT63_GPIO_OFFSET    13
+#define    RTL8367C_ACT63_GPIO_MASK    0x2000
+#define    RTL8367C_ACT63_FORWARD_OFFSET    12
+#define    RTL8367C_ACT63_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT63_POLICING_OFFSET    11
+#define    RTL8367C_ACT63_POLICING_MASK    0x800
+#define    RTL8367C_ACT63_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT63_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT63_SVID_OFFSET    9
+#define    RTL8367C_ACT63_SVID_MASK    0x200
+#define    RTL8367C_ACT63_CVID_OFFSET    8
+#define    RTL8367C_ACT63_CVID_MASK    0x100
+#define    RTL8367C_OP62_NOT_OFFSET    6
+#define    RTL8367C_OP62_NOT_MASK    0x40
+#define    RTL8367C_ACT62_GPIO_OFFSET    5
+#define    RTL8367C_ACT62_GPIO_MASK    0x20
+#define    RTL8367C_ACT62_FORWARD_OFFSET    4
+#define    RTL8367C_ACT62_FORWARD_MASK    0x10
+#define    RTL8367C_ACT62_POLICING_OFFSET    3
+#define    RTL8367C_ACT62_POLICING_MASK    0x8
+#define    RTL8367C_ACT62_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT62_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT62_SVID_OFFSET    1
+#define    RTL8367C_ACT62_SVID_MASK    0x2
+#define    RTL8367C_ACT62_CVID_OFFSET    0
+#define    RTL8367C_ACT62_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL0    0x0635
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL1    0x0636
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL2    0x0637
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY0_CTRL2_OFFSET    0
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY0_CTRL2_MASK    0x3
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY1_CTRL0    0x0638
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY1_CTRL1    0x0639
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY1_CTRL2    0x063a
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY1_CTRL2_OFFSET    0
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY1_CTRL2_MASK    0x3
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY2_CTRL0    0x063b
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY2_CTRL1    0x063c
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY2_CTRL2    0x063d
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY2_CTRL2_OFFSET    0
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY2_CTRL2_MASK    0x3
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY3_CTRL0    0x063e
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY3_CTRL1    0x063f
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY3_CTRL2    0x0640
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY3_CTRL2_OFFSET    0
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY3_CTRL2_MASK    0x3
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY4_CTRL0    0x0641
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY4_CTRL1    0x0642
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY4_CTRL2    0x0643
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY4_CTRL2_OFFSET    0
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY4_CTRL2_MASK    0x3
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY5_CTRL0    0x0644
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY5_CTRL1    0x0645
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY5_CTRL2    0x0646
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY5_CTRL2_OFFSET    0
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY5_CTRL2_MASK    0x3
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY6_CTRL0    0x0647
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY6_CTRL1    0x0648
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY6_CTRL2    0x0649
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY6_CTRL2_OFFSET    0
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY6_CTRL2_MASK    0x3
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY7_CTRL0    0x064a
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY7_CTRL1    0x064b
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY7_CTRL2    0x064c
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY7_CTRL2_OFFSET    0
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY7_CTRL2_MASK    0x3
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY8_CTRL0    0x064d
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY8_CTRL1    0x064e
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY8_CTRL2    0x064f
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY8_CTRL2_OFFSET    0
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY8_CTRL2_MASK    0x3
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY9_CTRL0    0x0650
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY9_CTRL1    0x0651
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY9_CTRL2    0x0652
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY9_CTRL2_OFFSET    0
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY9_CTRL2_MASK    0x3
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY10_CTRL0    0x0653
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY10_CTRL1    0x0654
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY10_CTRL2    0x0655
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY10_CTRL2_OFFSET    0
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY10_CTRL2_MASK    0x3
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY11_CTRL0    0x0656
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY11_CTRL1    0x0657
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY11_CTRL2    0x0658
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY11_CTRL2_OFFSET    0
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY11_CTRL2_MASK    0x3
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY12_CTRL0    0x0659
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY12_CTRL1    0x065a
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY12_CTRL2    0x065b
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY12_CTRL2_OFFSET    0
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY12_CTRL2_MASK    0x3
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY13_CTRL0    0x065c
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY13_CTRL1    0x065d
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY13_CTRL2    0x065e
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY13_CTRL2_OFFSET    0
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY13_CTRL2_MASK    0x3
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY14_CTRL0    0x065f
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY14_CTRL1    0x0660
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY14_CTRL2    0x0661
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY14_CTRL2_OFFSET    0
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY14_CTRL2_MASK    0x3
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY15_CTRL0    0x0662
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY15_CTRL1    0x0663
+
+#define    RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY15_CTRL2    0x0664
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY15_CTRL2_OFFSET    0
+#define    RTL8367C_ACL_SDPORT_RANGE_ENTRY15_CTRL2_MASK    0x3
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY0_CTRL0    0x0665
+#define    RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL0_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL0_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY0_CTRL1    0x0666
+#define    RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_TYPE_OFFSET    12
+#define    RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_TYPE_MASK    0x3000
+#define    RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_HIGH_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_HIGH_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY1_CTRL0    0x0667
+#define    RTL8367C_ACL_VID_RANGE_ENTRY1_CTRL0_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY1_CTRL0_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY1_CTRL1    0x0668
+#define    RTL8367C_ACL_VID_RANGE_ENTRY1_CTRL1_CHECK1_TYPE_OFFSET    12
+#define    RTL8367C_ACL_VID_RANGE_ENTRY1_CTRL1_CHECK1_TYPE_MASK    0x3000
+#define    RTL8367C_ACL_VID_RANGE_ENTRY1_CTRL1_CHECK1_HIGH_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY1_CTRL1_CHECK1_HIGH_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY2_CTRL0    0x0669
+#define    RTL8367C_ACL_VID_RANGE_ENTRY2_CTRL0_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY2_CTRL0_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY2_CTRL1    0x066a
+#define    RTL8367C_ACL_VID_RANGE_ENTRY2_CTRL1_CHECK2_TYPE_OFFSET    12
+#define    RTL8367C_ACL_VID_RANGE_ENTRY2_CTRL1_CHECK2_TYPE_MASK    0x3000
+#define    RTL8367C_ACL_VID_RANGE_ENTRY2_CTRL1_CHECK2_HIGH_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY2_CTRL1_CHECK2_HIGH_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY3_CTRL0    0x066b
+#define    RTL8367C_ACL_VID_RANGE_ENTRY3_CTRL0_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY3_CTRL0_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY3_CTRL1    0x066c
+#define    RTL8367C_ACL_VID_RANGE_ENTRY3_CTRL1_CHECK3_TYPE_OFFSET    12
+#define    RTL8367C_ACL_VID_RANGE_ENTRY3_CTRL1_CHECK3_TYPE_MASK    0x3000
+#define    RTL8367C_ACL_VID_RANGE_ENTRY3_CTRL1_CHECK3_HIGH_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY3_CTRL1_CHECK3_HIGH_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY4_CTRL0    0x066d
+#define    RTL8367C_ACL_VID_RANGE_ENTRY4_CTRL0_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY4_CTRL0_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY4_CTRL1    0x066e
+#define    RTL8367C_ACL_VID_RANGE_ENTRY4_CTRL1_CHECK4_TYPE_OFFSET    12
+#define    RTL8367C_ACL_VID_RANGE_ENTRY4_CTRL1_CHECK4_TYPE_MASK    0x3000
+#define    RTL8367C_ACL_VID_RANGE_ENTRY4_CTRL1_CHECK4_HIGH_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY4_CTRL1_CHECK4_HIGH_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY5_CTRL0    0x066f
+#define    RTL8367C_ACL_VID_RANGE_ENTRY5_CTRL0_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY5_CTRL0_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY5_CTRL1    0x0670
+#define    RTL8367C_ACL_VID_RANGE_ENTRY5_CTRL1_CHECK5_TYPE_OFFSET    12
+#define    RTL8367C_ACL_VID_RANGE_ENTRY5_CTRL1_CHECK5_TYPE_MASK    0x3000
+#define    RTL8367C_ACL_VID_RANGE_ENTRY5_CTRL1_CHECK5_HIGH_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY5_CTRL1_CHECK5_HIGH_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY6_CTRL0    0x0671
+#define    RTL8367C_ACL_VID_RANGE_ENTRY6_CTRL0_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY6_CTRL0_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY6_CTRL1    0x0672
+#define    RTL8367C_ACL_VID_RANGE_ENTRY6_CTRL1_CHECK6_TYPE_OFFSET    12
+#define    RTL8367C_ACL_VID_RANGE_ENTRY6_CTRL1_CHECK6_TYPE_MASK    0x3000
+#define    RTL8367C_ACL_VID_RANGE_ENTRY6_CTRL1_CHECK6_HIGH_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY6_CTRL1_CHECK6_HIGH_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY7_CTRL0    0x0673
+#define    RTL8367C_ACL_VID_RANGE_ENTRY7_CTRL0_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY7_CTRL0_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY7_CTRL1    0x0674
+#define    RTL8367C_ACL_VID_RANGE_ENTRY7_CTRL1_CHECK7_TYPE_OFFSET    12
+#define    RTL8367C_ACL_VID_RANGE_ENTRY7_CTRL1_CHECK7_TYPE_MASK    0x3000
+#define    RTL8367C_ACL_VID_RANGE_ENTRY7_CTRL1_CHECK7_HIGH_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY7_CTRL1_CHECK7_HIGH_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY8_CTRL0    0x0675
+#define    RTL8367C_ACL_VID_RANGE_ENTRY8_CTRL0_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY8_CTRL0_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY8_CTRL1    0x0676
+#define    RTL8367C_ACL_VID_RANGE_ENTRY8_CTRL1_CHECK8_TYPE_OFFSET    12
+#define    RTL8367C_ACL_VID_RANGE_ENTRY8_CTRL1_CHECK8_TYPE_MASK    0x3000
+#define    RTL8367C_ACL_VID_RANGE_ENTRY8_CTRL1_CHECK8_HIGH_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY8_CTRL1_CHECK8_HIGH_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY9_CTRL0    0x0677
+#define    RTL8367C_ACL_VID_RANGE_ENTRY9_CTRL0_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY9_CTRL0_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY9_CTRL1    0x0678
+#define    RTL8367C_ACL_VID_RANGE_ENTRY9_CTRL1_CHECK9_TYPE_OFFSET    12
+#define    RTL8367C_ACL_VID_RANGE_ENTRY9_CTRL1_CHECK9_TYPE_MASK    0x3000
+#define    RTL8367C_ACL_VID_RANGE_ENTRY9_CTRL1_CHECK9_HIGH_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY9_CTRL1_CHECK9_HIGH_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY10_CTRL0    0x0679
+#define    RTL8367C_ACL_VID_RANGE_ENTRY10_CTRL0_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY10_CTRL0_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY10_CTRL1    0x067a
+#define    RTL8367C_ACL_VID_RANGE_ENTRY10_CTRL1_CHECK10_TYPE_OFFSET    12
+#define    RTL8367C_ACL_VID_RANGE_ENTRY10_CTRL1_CHECK10_TYPE_MASK    0x3000
+#define    RTL8367C_ACL_VID_RANGE_ENTRY10_CTRL1_CHECK10_HIGH_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY10_CTRL1_CHECK10_HIGH_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY11_CTRL0    0x067b
+#define    RTL8367C_ACL_VID_RANGE_ENTRY11_CTRL0_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY11_CTRL0_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY11_CTRL1    0x067c
+#define    RTL8367C_ACL_VID_RANGE_ENTRY11_CTRL1_CHECK11_TYPE_OFFSET    12
+#define    RTL8367C_ACL_VID_RANGE_ENTRY11_CTRL1_CHECK11_TYPE_MASK    0x3000
+#define    RTL8367C_ACL_VID_RANGE_ENTRY11_CTRL1_CHECK11_HIGH_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY11_CTRL1_CHECK11_HIGH_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY12_CTRL0    0x067d
+#define    RTL8367C_ACL_VID_RANGE_ENTRY12_CTRL0_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY12_CTRL0_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY12_CTRL1    0x067e
+#define    RTL8367C_ACL_VID_RANGE_ENTRY12_CTRL1_CHECK12_TYPE_OFFSET    12
+#define    RTL8367C_ACL_VID_RANGE_ENTRY12_CTRL1_CHECK12_TYPE_MASK    0x3000
+#define    RTL8367C_ACL_VID_RANGE_ENTRY12_CTRL1_CHECK12_HIGH_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY12_CTRL1_CHECK12_HIGH_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY13_CTRL0    0x067f
+#define    RTL8367C_ACL_VID_RANGE_ENTRY13_CTRL0_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY13_CTRL0_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY13_CTRL1    0x0680
+#define    RTL8367C_ACL_VID_RANGE_ENTRY13_CTRL1_CHECK13_TYPE_OFFSET    12
+#define    RTL8367C_ACL_VID_RANGE_ENTRY13_CTRL1_CHECK13_TYPE_MASK    0x3000
+#define    RTL8367C_ACL_VID_RANGE_ENTRY13_CTRL1_CHECK13_HIGH_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY13_CTRL1_CHECK13_HIGH_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY14_CTRL0    0x0681
+#define    RTL8367C_ACL_VID_RANGE_ENTRY14_CTRL0_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY14_CTRL0_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY14_CTRL1    0x0682
+#define    RTL8367C_ACL_VID_RANGE_ENTRY14_CTRL1_CHECK14_TYPE_OFFSET    12
+#define    RTL8367C_ACL_VID_RANGE_ENTRY14_CTRL1_CHECK14_TYPE_MASK    0x3000
+#define    RTL8367C_ACL_VID_RANGE_ENTRY14_CTRL1_CHECK14_HIGH_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY14_CTRL1_CHECK14_HIGH_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY15_CTRL0    0x0683
+#define    RTL8367C_ACL_VID_RANGE_ENTRY15_CTRL0_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY15_CTRL0_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_VID_RANGE_ENTRY15_CTRL1    0x0684
+#define    RTL8367C_ACL_VID_RANGE_ENTRY15_CTRL1_CHECK15_TYPE_OFFSET    12
+#define    RTL8367C_ACL_VID_RANGE_ENTRY15_CTRL1_CHECK15_TYPE_MASK    0x3000
+#define    RTL8367C_ACL_VID_RANGE_ENTRY15_CTRL1_CHECK15_HIGH_OFFSET    0
+#define    RTL8367C_ACL_VID_RANGE_ENTRY15_CTRL1_CHECK15_HIGH_MASK    0xFFF
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL0    0x0685
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL1    0x0686
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL2    0x0687
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL3    0x0688
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL4    0x0689
+#define    RTL8367C_ACL_IP_RANGE_ENTRY0_CTRL4_OFFSET    0
+#define    RTL8367C_ACL_IP_RANGE_ENTRY0_CTRL4_MASK    0x7
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY1_CTRL0    0x068a
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY1_CTRL1    0x068b
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY1_CTRL2    0x068c
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY1_CTRL3    0x068d
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY1_CTRL4    0x068e
+#define    RTL8367C_ACL_IP_RANGE_ENTRY1_CTRL4_OFFSET    0
+#define    RTL8367C_ACL_IP_RANGE_ENTRY1_CTRL4_MASK    0x7
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY2_CTRL0    0x068f
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY2_CTRL1    0x0690
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY2_CTRL2    0x0691
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY2_CTRL3    0x0692
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY2_CTRL4    0x0693
+#define    RTL8367C_ACL_IP_RANGE_ENTRY2_CTRL4_OFFSET    0
+#define    RTL8367C_ACL_IP_RANGE_ENTRY2_CTRL4_MASK    0x7
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY3_CTRL0    0x0694
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY3_CTRL1    0x0695
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY3_CTRL2    0x0696
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY3_CTRL3    0x0697
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY3_CTRL4    0x0698
+#define    RTL8367C_ACL_IP_RANGE_ENTRY3_CTRL4_OFFSET    0
+#define    RTL8367C_ACL_IP_RANGE_ENTRY3_CTRL4_MASK    0x7
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY4_CTRL0    0x0699
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY4_CTRL1    0x069a
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY4_CTRL2    0x069b
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY4_CTRL3    0x069c
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY4_CTRL4    0x069d
+#define    RTL8367C_ACL_IP_RANGE_ENTRY4_CTRL4_OFFSET    0
+#define    RTL8367C_ACL_IP_RANGE_ENTRY4_CTRL4_MASK    0x7
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY5_CTRL0    0x069e
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY5_CTRL1    0x069f
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY5_CTRL2    0x06a0
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY5_CTRL3    0x06a1
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY5_CTRL4    0x06a2
+#define    RTL8367C_ACL_IP_RANGE_ENTRY5_CTRL4_OFFSET    0
+#define    RTL8367C_ACL_IP_RANGE_ENTRY5_CTRL4_MASK    0x7
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY6_CTRL0    0x06a3
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY6_CTRL1    0x06a4
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY6_CTRL2    0x06a5
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY6_CTRL3    0x06a6
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY6_CTRL4    0x06a7
+#define    RTL8367C_ACL_IP_RANGE_ENTRY6_CTRL4_OFFSET    0
+#define    RTL8367C_ACL_IP_RANGE_ENTRY6_CTRL4_MASK    0x7
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY7_CTRL0    0x06a8
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY7_CTRL1    0x06a9
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY7_CTRL2    0x06aa
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY7_CTRL3    0x06ab
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY7_CTRL4    0x06ac
+#define    RTL8367C_ACL_IP_RANGE_ENTRY7_CTRL4_OFFSET    0
+#define    RTL8367C_ACL_IP_RANGE_ENTRY7_CTRL4_MASK    0x7
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY8_CTRL0    0x06ad
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY8_CTRL1    0x06ae
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY8_CTRL2    0x06af
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY8_CTRL3    0x06b0
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY8_CTRL4    0x06b1
+#define    RTL8367C_ACL_IP_RANGE_ENTRY8_CTRL4_OFFSET    0
+#define    RTL8367C_ACL_IP_RANGE_ENTRY8_CTRL4_MASK    0x7
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY9_CTRL0    0x06b2
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY9_CTRL1    0x06b3
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY9_CTRL2    0x06b4
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY9_CTRL3    0x06b5
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY9_CTRL4    0x06b6
+#define    RTL8367C_ACL_IP_RANGE_ENTRY9_CTRL4_OFFSET    0
+#define    RTL8367C_ACL_IP_RANGE_ENTRY9_CTRL4_MASK    0x7
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY10_CTRL0    0x06b7
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY10_CTRL1    0x06b8
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY10_CTRL2    0x06b9
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY10_CTRL3    0x06ba
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY10_CTRL4    0x06bb
+#define    RTL8367C_ACL_IP_RANGE_ENTRY10_CTRL4_OFFSET    0
+#define    RTL8367C_ACL_IP_RANGE_ENTRY10_CTRL4_MASK    0x7
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY11_CTRL0    0x06bc
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY11_CTRL1    0x06bd
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY11_CTRL2    0x06be
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY11_CTRL3    0x06bf
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY11_CTRL4    0x06c0
+#define    RTL8367C_ACL_IP_RANGE_ENTRY11_CTRL4_OFFSET    0
+#define    RTL8367C_ACL_IP_RANGE_ENTRY11_CTRL4_MASK    0x7
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY12_CTRL0    0x06c1
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY12_CTRL1    0x06c2
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY12_CTRL2    0x06c3
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY12_CTRL3    0x06c4
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY12_CTRL4    0x06c5
+#define    RTL8367C_ACL_IP_RANGE_ENTRY12_CTRL4_OFFSET    0
+#define    RTL8367C_ACL_IP_RANGE_ENTRY12_CTRL4_MASK    0x7
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY13_CTRL0    0x06c6
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY13_CTRL1    0x06c7
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY13_CTRL2    0x06c8
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY13_CTRL3    0x06c9
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY13_CTRL4    0x06ca
+#define    RTL8367C_ACL_IP_RANGE_ENTRY13_CTRL4_OFFSET    0
+#define    RTL8367C_ACL_IP_RANGE_ENTRY13_CTRL4_MASK    0x7
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY14_CTRL0    0x06cb
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY14_CTRL1    0x06cc
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY14_CTRL2    0x06cd
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY14_CTRL3    0x06ce
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY14_CTRL4    0x06cf
+#define    RTL8367C_ACL_IP_RANGE_ENTRY14_CTRL4_OFFSET    0
+#define    RTL8367C_ACL_IP_RANGE_ENTRY14_CTRL4_MASK    0x7
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY15_CTRL0    0x06d0
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY15_CTRL1    0x06d1
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY15_CTRL2    0x06d2
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY15_CTRL3    0x06d3
+
+#define    RTL8367C_REG_ACL_IP_RANGE_ENTRY15_CTRL4    0x06d4
+#define    RTL8367C_ACL_IP_RANGE_ENTRY15_CTRL4_OFFSET    0
+#define    RTL8367C_ACL_IP_RANGE_ENTRY15_CTRL4_MASK    0x7
+
+#define    RTL8367C_REG_ACL_ENABLE    0x06d5
+#define    RTL8367C_PORT10_ENABLE_OFFSET    10
+#define    RTL8367C_PORT10_ENABLE_MASK    0x400
+#define    RTL8367C_PORT9_ENABLE_OFFSET    9
+#define    RTL8367C_PORT9_ENABLE_MASK    0x200
+#define    RTL8367C_PORT8_ENABLE_OFFSET    8
+#define    RTL8367C_PORT8_ENABLE_MASK    0x100
+#define    RTL8367C_PORT7_ENABLE_OFFSET    7
+#define    RTL8367C_PORT7_ENABLE_MASK    0x80
+#define    RTL8367C_PORT6_ENABLE_OFFSET    6
+#define    RTL8367C_PORT6_ENABLE_MASK    0x40
+#define    RTL8367C_PORT5_ENABLE_OFFSET    5
+#define    RTL8367C_PORT5_ENABLE_MASK    0x20
+#define    RTL8367C_PORT4_ENABLE_OFFSET    4
+#define    RTL8367C_PORT4_ENABLE_MASK    0x10
+#define    RTL8367C_PORT3_ENABLE_OFFSET    3
+#define    RTL8367C_PORT3_ENABLE_MASK    0x8
+#define    RTL8367C_PORT2_ENABLE_OFFSET    2
+#define    RTL8367C_PORT2_ENABLE_MASK    0x4
+#define    RTL8367C_PORT1_ENABLE_OFFSET    1
+#define    RTL8367C_PORT1_ENABLE_MASK    0x2
+#define    RTL8367C_PORT0_ENABLE_OFFSET    0
+#define    RTL8367C_PORT0_ENABLE_MASK    0x1
+
+#define    RTL8367C_REG_ACL_UNMATCH_PERMIT    0x06d6
+#define    RTL8367C_PORT10_PERMIT_OFFSET    10
+#define    RTL8367C_PORT10_PERMIT_MASK    0x400
+#define    RTL8367C_PORT9_PERMIT_OFFSET    9
+#define    RTL8367C_PORT9_PERMIT_MASK    0x200
+#define    RTL8367C_PORT8_PERMIT_OFFSET    8
+#define    RTL8367C_PORT8_PERMIT_MASK    0x100
+#define    RTL8367C_PORT7_PERMIT_OFFSET    7
+#define    RTL8367C_PORT7_PERMIT_MASK    0x80
+#define    RTL8367C_PORT6_PERMIT_OFFSET    6
+#define    RTL8367C_PORT6_PERMIT_MASK    0x40
+#define    RTL8367C_PORT5_PERMIT_OFFSET    5
+#define    RTL8367C_PORT5_PERMIT_MASK    0x20
+#define    RTL8367C_PORT4_PERMIT_OFFSET    4
+#define    RTL8367C_PORT4_PERMIT_MASK    0x10
+#define    RTL8367C_PORT3_PERMIT_OFFSET    3
+#define    RTL8367C_PORT3_PERMIT_MASK    0x8
+#define    RTL8367C_PORT2_PERMIT_OFFSET    2
+#define    RTL8367C_PORT2_PERMIT_MASK    0x4
+#define    RTL8367C_PORT1_PERMIT_OFFSET    1
+#define    RTL8367C_PORT1_PERMIT_MASK    0x2
+#define    RTL8367C_PORT0_PERMIT_OFFSET    0
+#define    RTL8367C_PORT0_PERMIT_MASK    0x1
+
+#define    RTL8367C_REG_ACL_GPIO_POLARITY    0x06d7
+#define    RTL8367C_ACL_GPIO_POLARITY_OFFSET    0
+#define    RTL8367C_ACL_GPIO_POLARITY_MASK    0x1
+
+#define    RTL8367C_REG_ACL_LOG_CNT_TYPE    0x06d8
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER15_TYPE_OFFSET    15
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER15_TYPE_MASK    0x8000
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER14_TYPE_OFFSET    14
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER14_TYPE_MASK    0x4000
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER13_TYPE_OFFSET    13
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER13_TYPE_MASK    0x2000
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER12_TYPE_OFFSET    12
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER12_TYPE_MASK    0x1000
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER11_TYPE_OFFSET    11
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER11_TYPE_MASK    0x800
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER10_TYPE_OFFSET    10
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER10_TYPE_MASK    0x400
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER9_TYPE_OFFSET    9
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER9_TYPE_MASK    0x200
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER8_TYPE_OFFSET    8
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER8_TYPE_MASK    0x100
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER7_TYPE_OFFSET    7
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER7_TYPE_MASK    0x80
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER6_TYPE_OFFSET    6
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER6_TYPE_MASK    0x40
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER5_TYPE_OFFSET    5
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER5_TYPE_MASK    0x20
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER4_TYPE_OFFSET    4
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER4_TYPE_MASK    0x10
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER3_TYPE_OFFSET    3
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER3_TYPE_MASK    0x8
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER2_TYPE_OFFSET    2
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER2_TYPE_MASK    0x4
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER1_TYPE_OFFSET    1
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER1_TYPE_MASK    0x2
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER0_TYPE_OFFSET    0
+#define    RTL8367C_ACL_LOG_CNT_TYPE_COUNTER0_TYPE_MASK    0x1
+
+#define    RTL8367C_REG_ACL_RESET_CFG    0x06d9
+#define    RTL8367C_ACL_RESET_CFG_OFFSET    0
+#define    RTL8367C_ACL_RESET_CFG_MASK    0x1
+
+#define    RTL8367C_REG_ACL_DUMMY00    0x06E0
+
+#define    RTL8367C_REG_ACL_DUMMY01    0x06E1
+
+#define    RTL8367C_REG_ACL_DUMMY02    0x06E2
+
+#define    RTL8367C_REG_ACL_DUMMY03    0x06E3
+
+#define    RTL8367C_REG_ACL_DUMMY04    0x06E4
+
+#define    RTL8367C_REG_ACL_DUMMY05    0x06E5
+
+#define    RTL8367C_REG_ACL_DUMMY06    0x06E6
+
+#define    RTL8367C_REG_ACL_DUMMY07    0x06E7
+
+#define    RTL8367C_REG_ACL_REASON_01    0x06E8
+#define    RTL8367C_ACL_ACT_1_OFFSET    8
+#define    RTL8367C_ACL_ACT_1_MASK    0xFF00
+#define    RTL8367C_ACL_ACT_0_OFFSET    0
+#define    RTL8367C_ACL_ACT_0_MASK    0xFF
+
+#define    RTL8367C_REG_ACL_REASON_23    0x06E9
+#define    RTL8367C_ACL_ACT_3_OFFSET    8
+#define    RTL8367C_ACL_ACT_3_MASK    0xFF00
+#define    RTL8367C_ACL_ACT_2_OFFSET    0
+#define    RTL8367C_ACL_ACT_2_MASK    0xFF
+
+#define    RTL8367C_REG_ACL_REASON_45    0x06EA
+#define    RTL8367C_ACL_ACT_5_OFFSET    8
+#define    RTL8367C_ACL_ACT_5_MASK    0xFF00
+#define    RTL8367C_ACL_ACT_4_OFFSET    0
+#define    RTL8367C_ACL_ACT_4_MASK    0xFF
+
+#define    RTL8367C_REG_ACL_ACCESS_MODE    0x06EB
+#define    RTL8367C_ACL_ACCESS_MODE_OFFSET    0
+#define    RTL8367C_ACL_ACCESS_MODE_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL32    0x06F0
+#define    RTL8367C_OP65_NOT_OFFSET    14
+#define    RTL8367C_OP65_NOT_MASK    0x4000
+#define    RTL8367C_ACT65_GPIO_OFFSET    13
+#define    RTL8367C_ACT65_GPIO_MASK    0x2000
+#define    RTL8367C_ACT65_FORWARD_OFFSET    12
+#define    RTL8367C_ACT65_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT65_POLICING_OFFSET    11
+#define    RTL8367C_ACT65_POLICING_MASK    0x800
+#define    RTL8367C_ACT65_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT65_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT65_SVID_OFFSET    9
+#define    RTL8367C_ACT65_SVID_MASK    0x200
+#define    RTL8367C_ACT65_CVID_OFFSET    8
+#define    RTL8367C_ACT65_CVID_MASK    0x100
+#define    RTL8367C_OP64_NOT_OFFSET    6
+#define    RTL8367C_OP64_NOT_MASK    0x40
+#define    RTL8367C_ACT64_GPIO_OFFSET    5
+#define    RTL8367C_ACT64_GPIO_MASK    0x20
+#define    RTL8367C_ACT64_FORWARD_OFFSET    4
+#define    RTL8367C_ACT64_FORWARD_MASK    0x10
+#define    RTL8367C_ACT64_POLICING_OFFSET    3
+#define    RTL8367C_ACT64_POLICING_MASK    0x8
+#define    RTL8367C_ACT64_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT64_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT64_SVID_OFFSET    1
+#define    RTL8367C_ACT64_SVID_MASK    0x2
+#define    RTL8367C_ACT64_CVID_OFFSET    0
+#define    RTL8367C_ACT64_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL33    0x06F1
+#define    RTL8367C_OP67_NOT_OFFSET    14
+#define    RTL8367C_OP67_NOT_MASK    0x4000
+#define    RTL8367C_ACT67_GPIO_OFFSET    13
+#define    RTL8367C_ACT67_GPIO_MASK    0x2000
+#define    RTL8367C_ACT67_FORWARD_OFFSET    12
+#define    RTL8367C_ACT67_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT67_POLICING_OFFSET    11
+#define    RTL8367C_ACT67_POLICING_MASK    0x800
+#define    RTL8367C_ACT67_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT67_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT67_SVID_OFFSET    9
+#define    RTL8367C_ACT67_SVID_MASK    0x200
+#define    RTL8367C_ACT67_CVID_OFFSET    8
+#define    RTL8367C_ACT67_CVID_MASK    0x100
+#define    RTL8367C_OP66_NOT_OFFSET    6
+#define    RTL8367C_OP66_NOT_MASK    0x40
+#define    RTL8367C_ACT66_GPIO_OFFSET    5
+#define    RTL8367C_ACT66_GPIO_MASK    0x20
+#define    RTL8367C_ACT66_FORWARD_OFFSET    4
+#define    RTL8367C_ACT66_FORWARD_MASK    0x10
+#define    RTL8367C_ACT66_POLICING_OFFSET    3
+#define    RTL8367C_ACT66_POLICING_MASK    0x8
+#define    RTL8367C_ACT66_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT66_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT66_SVID_OFFSET    1
+#define    RTL8367C_ACT66_SVID_MASK    0x2
+#define    RTL8367C_ACT66_CVID_OFFSET    0
+#define    RTL8367C_ACT66_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL34    0x06F2
+#define    RTL8367C_OP69_NOT_OFFSET    14
+#define    RTL8367C_OP69_NOT_MASK    0x4000
+#define    RTL8367C_ACT69_GPIO_OFFSET    13
+#define    RTL8367C_ACT69_GPIO_MASK    0x2000
+#define    RTL8367C_ACT69_FORWARD_OFFSET    12
+#define    RTL8367C_ACT69_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT69_POLICING_OFFSET    11
+#define    RTL8367C_ACT69_POLICING_MASK    0x800
+#define    RTL8367C_ACT69_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT69_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT69_SVID_OFFSET    9
+#define    RTL8367C_ACT69_SVID_MASK    0x200
+#define    RTL8367C_ACT69_CVID_OFFSET    8
+#define    RTL8367C_ACT69_CVID_MASK    0x100
+#define    RTL8367C_OP68_NOT_OFFSET    6
+#define    RTL8367C_OP68_NOT_MASK    0x40
+#define    RTL8367C_ACT68_GPIO_OFFSET    5
+#define    RTL8367C_ACT68_GPIO_MASK    0x20
+#define    RTL8367C_ACT68_FORWARD_OFFSET    4
+#define    RTL8367C_ACT68_FORWARD_MASK    0x10
+#define    RTL8367C_ACT68_POLICING_OFFSET    3
+#define    RTL8367C_ACT68_POLICING_MASK    0x8
+#define    RTL8367C_ACT68_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT68_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT68_SVID_OFFSET    1
+#define    RTL8367C_ACT68_SVID_MASK    0x2
+#define    RTL8367C_ACT68_CVID_OFFSET    0
+#define    RTL8367C_ACT68_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL35    0x06F3
+#define    RTL8367C_OP71_NOT_OFFSET    14
+#define    RTL8367C_OP71_NOT_MASK    0x4000
+#define    RTL8367C_ACT71_GPIO_OFFSET    13
+#define    RTL8367C_ACT71_GPIO_MASK    0x2000
+#define    RTL8367C_ACT71_FORWARD_OFFSET    12
+#define    RTL8367C_ACT71_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT71_POLICING_OFFSET    11
+#define    RTL8367C_ACT71_POLICING_MASK    0x800
+#define    RTL8367C_ACT71_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT71_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT71_SVID_OFFSET    9
+#define    RTL8367C_ACT71_SVID_MASK    0x200
+#define    RTL8367C_ACT71_CVID_OFFSET    8
+#define    RTL8367C_ACT71_CVID_MASK    0x100
+#define    RTL8367C_OP70_NOT_OFFSET    6
+#define    RTL8367C_OP70_NOT_MASK    0x40
+#define    RTL8367C_ACT70_GPIO_OFFSET    5
+#define    RTL8367C_ACT70_GPIO_MASK    0x20
+#define    RTL8367C_ACT70_FORWARD_OFFSET    4
+#define    RTL8367C_ACT70_FORWARD_MASK    0x10
+#define    RTL8367C_ACT70_POLICING_OFFSET    3
+#define    RTL8367C_ACT70_POLICING_MASK    0x8
+#define    RTL8367C_ACT70_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT70_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT70_SVID_OFFSET    1
+#define    RTL8367C_ACT70_SVID_MASK    0x2
+#define    RTL8367C_ACT70_CVID_OFFSET    0
+#define    RTL8367C_ACT70_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL36    0x06F4
+#define    RTL8367C_OP73_NOT_OFFSET    14
+#define    RTL8367C_OP73_NOT_MASK    0x4000
+#define    RTL8367C_ACT73_GPIO_OFFSET    13
+#define    RTL8367C_ACT73_GPIO_MASK    0x2000
+#define    RTL8367C_ACT73_FORWARD_OFFSET    12
+#define    RTL8367C_ACT73_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT73_POLICING_OFFSET    11
+#define    RTL8367C_ACT73_POLICING_MASK    0x800
+#define    RTL8367C_ACT73_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT73_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT73_SVID_OFFSET    9
+#define    RTL8367C_ACT73_SVID_MASK    0x200
+#define    RTL8367C_ACT73_CVID_OFFSET    8
+#define    RTL8367C_ACT73_CVID_MASK    0x100
+#define    RTL8367C_OP72_NOT_OFFSET    6
+#define    RTL8367C_OP72_NOT_MASK    0x40
+#define    RTL8367C_ACT72_GPIO_OFFSET    5
+#define    RTL8367C_ACT72_GPIO_MASK    0x20
+#define    RTL8367C_ACT72_FORWARD_OFFSET    4
+#define    RTL8367C_ACT72_FORWARD_MASK    0x10
+#define    RTL8367C_ACT72_POLICING_OFFSET    3
+#define    RTL8367C_ACT72_POLICING_MASK    0x8
+#define    RTL8367C_ACT72_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT72_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT72_SVID_OFFSET    1
+#define    RTL8367C_ACT72_SVID_MASK    0x2
+#define    RTL8367C_ACT72_CVID_OFFSET    0
+#define    RTL8367C_ACT72_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL37    0x06F5
+#define    RTL8367C_OP75_NOT_OFFSET    14
+#define    RTL8367C_OP75_NOT_MASK    0x4000
+#define    RTL8367C_ACT75_GPIO_OFFSET    13
+#define    RTL8367C_ACT75_GPIO_MASK    0x2000
+#define    RTL8367C_ACT75_FORWARD_OFFSET    12
+#define    RTL8367C_ACT75_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT75_POLICING_OFFSET    11
+#define    RTL8367C_ACT75_POLICING_MASK    0x800
+#define    RTL8367C_ACT75_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT75_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT75_SVID_OFFSET    9
+#define    RTL8367C_ACT75_SVID_MASK    0x200
+#define    RTL8367C_ACT75_CVID_OFFSET    8
+#define    RTL8367C_ACT75_CVID_MASK    0x100
+#define    RTL8367C_OP74_NOT_OFFSET    6
+#define    RTL8367C_OP74_NOT_MASK    0x40
+#define    RTL8367C_ACT74_GPIO_OFFSET    5
+#define    RTL8367C_ACT74_GPIO_MASK    0x20
+#define    RTL8367C_ACT74_FORWARD_OFFSET    4
+#define    RTL8367C_ACT74_FORWARD_MASK    0x10
+#define    RTL8367C_ACT74_POLICING_OFFSET    3
+#define    RTL8367C_ACT74_POLICING_MASK    0x8
+#define    RTL8367C_ACT74_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT74_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT74_SVID_OFFSET    1
+#define    RTL8367C_ACT74_SVID_MASK    0x2
+#define    RTL8367C_ACT74_CVID_OFFSET    0
+#define    RTL8367C_ACT74_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL38    0x06F6
+#define    RTL8367C_OP77_NOT_OFFSET    14
+#define    RTL8367C_OP77_NOT_MASK    0x4000
+#define    RTL8367C_ACT77_GPIO_OFFSET    13
+#define    RTL8367C_ACT77_GPIO_MASK    0x2000
+#define    RTL8367C_ACT77_FORWARD_OFFSET    12
+#define    RTL8367C_ACT77_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT77_POLICING_OFFSET    11
+#define    RTL8367C_ACT77_POLICING_MASK    0x800
+#define    RTL8367C_ACT77_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT77_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT77_SVID_OFFSET    9
+#define    RTL8367C_ACT77_SVID_MASK    0x200
+#define    RTL8367C_ACT77_CVID_OFFSET    8
+#define    RTL8367C_ACT77_CVID_MASK    0x100
+#define    RTL8367C_OP76_NOT_OFFSET    6
+#define    RTL8367C_OP76_NOT_MASK    0x40
+#define    RTL8367C_ACT76_GPIO_OFFSET    5
+#define    RTL8367C_ACT76_GPIO_MASK    0x20
+#define    RTL8367C_ACT76_FORWARD_OFFSET    4
+#define    RTL8367C_ACT76_FORWARD_MASK    0x10
+#define    RTL8367C_ACT76_POLICING_OFFSET    3
+#define    RTL8367C_ACT76_POLICING_MASK    0x8
+#define    RTL8367C_ACT76_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT76_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT76_SVID_OFFSET    1
+#define    RTL8367C_ACT76_SVID_MASK    0x2
+#define    RTL8367C_ACT76_CVID_OFFSET    0
+#define    RTL8367C_ACT76_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL39    0x06F7
+#define    RTL8367C_OP79_NOT_OFFSET    14
+#define    RTL8367C_OP79_NOT_MASK    0x4000
+#define    RTL8367C_ACT79_GPIO_OFFSET    13
+#define    RTL8367C_ACT79_GPIO_MASK    0x2000
+#define    RTL8367C_ACT79_FORWARD_OFFSET    12
+#define    RTL8367C_ACT79_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT79_POLICING_OFFSET    11
+#define    RTL8367C_ACT79_POLICING_MASK    0x800
+#define    RTL8367C_ACT79_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT79_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT79_SVID_OFFSET    9
+#define    RTL8367C_ACT79_SVID_MASK    0x200
+#define    RTL8367C_ACT79_CVID_OFFSET    8
+#define    RTL8367C_ACT79_CVID_MASK    0x100
+#define    RTL8367C_OP78_NOT_OFFSET    6
+#define    RTL8367C_OP78_NOT_MASK    0x40
+#define    RTL8367C_ACT78_GPIO_OFFSET    5
+#define    RTL8367C_ACT78_GPIO_MASK    0x20
+#define    RTL8367C_ACT78_FORWARD_OFFSET    4
+#define    RTL8367C_ACT78_FORWARD_MASK    0x10
+#define    RTL8367C_ACT78_POLICING_OFFSET    3
+#define    RTL8367C_ACT78_POLICING_MASK    0x8
+#define    RTL8367C_ACT78_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT78_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT78_SVID_OFFSET    1
+#define    RTL8367C_ACT78_SVID_MASK    0x2
+#define    RTL8367C_ACT78_CVID_OFFSET    0
+#define    RTL8367C_ACT78_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL40    0x06F8
+#define    RTL8367C_OP81_NOT_OFFSET    14
+#define    RTL8367C_OP81_NOT_MASK    0x4000
+#define    RTL8367C_ACT81_GPIO_OFFSET    13
+#define    RTL8367C_ACT81_GPIO_MASK    0x2000
+#define    RTL8367C_ACT81_FORWARD_OFFSET    12
+#define    RTL8367C_ACT81_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT81_POLICING_OFFSET    11
+#define    RTL8367C_ACT81_POLICING_MASK    0x800
+#define    RTL8367C_ACT81_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT81_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT81_SVID_OFFSET    9
+#define    RTL8367C_ACT81_SVID_MASK    0x200
+#define    RTL8367C_ACT81_CVID_OFFSET    8
+#define    RTL8367C_ACT81_CVID_MASK    0x100
+#define    RTL8367C_OP80_NOT_OFFSET    6
+#define    RTL8367C_OP80_NOT_MASK    0x40
+#define    RTL8367C_ACT80_GPIO_OFFSET    5
+#define    RTL8367C_ACT80_GPIO_MASK    0x20
+#define    RTL8367C_ACT80_FORWARD_OFFSET    4
+#define    RTL8367C_ACT80_FORWARD_MASK    0x10
+#define    RTL8367C_ACT80_POLICING_OFFSET    3
+#define    RTL8367C_ACT80_POLICING_MASK    0x8
+#define    RTL8367C_ACT80_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT80_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT80_SVID_OFFSET    1
+#define    RTL8367C_ACT80_SVID_MASK    0x2
+#define    RTL8367C_ACT80_CVID_OFFSET    0
+#define    RTL8367C_ACT80_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL41    0x06F9
+#define    RTL8367C_OP83_NOT_OFFSET    14
+#define    RTL8367C_OP83_NOT_MASK    0x4000
+#define    RTL8367C_ACT83_GPIO_OFFSET    13
+#define    RTL8367C_ACT83_GPIO_MASK    0x2000
+#define    RTL8367C_ACT83_FORWARD_OFFSET    12
+#define    RTL8367C_ACT83_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT83_POLICING_OFFSET    11
+#define    RTL8367C_ACT83_POLICING_MASK    0x800
+#define    RTL8367C_ACT83_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT83_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT83_SVID_OFFSET    9
+#define    RTL8367C_ACT83_SVID_MASK    0x200
+#define    RTL8367C_ACT83_CVID_OFFSET    8
+#define    RTL8367C_ACT83_CVID_MASK    0x100
+#define    RTL8367C_OP82_NOT_OFFSET    6
+#define    RTL8367C_OP82_NOT_MASK    0x40
+#define    RTL8367C_ACT82_GPIO_OFFSET    5
+#define    RTL8367C_ACT82_GPIO_MASK    0x20
+#define    RTL8367C_ACT82_FORWARD_OFFSET    4
+#define    RTL8367C_ACT82_FORWARD_MASK    0x10
+#define    RTL8367C_ACT82_POLICING_OFFSET    3
+#define    RTL8367C_ACT82_POLICING_MASK    0x8
+#define    RTL8367C_ACT82_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT82_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT82_SVID_OFFSET    1
+#define    RTL8367C_ACT82_SVID_MASK    0x2
+#define    RTL8367C_ACT82_CVID_OFFSET    0
+#define    RTL8367C_ACT82_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL42    0x06FA
+#define    RTL8367C_OP85_NOT_OFFSET    14
+#define    RTL8367C_OP85_NOT_MASK    0x4000
+#define    RTL8367C_ACT85_GPIO_OFFSET    13
+#define    RTL8367C_ACT85_GPIO_MASK    0x2000
+#define    RTL8367C_ACT85_FORWARD_OFFSET    12
+#define    RTL8367C_ACT85_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT85_POLICING_OFFSET    11
+#define    RTL8367C_ACT85_POLICING_MASK    0x800
+#define    RTL8367C_ACT85_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT85_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT85_SVID_OFFSET    9
+#define    RTL8367C_ACT85_SVID_MASK    0x200
+#define    RTL8367C_ACT85_CVID_OFFSET    8
+#define    RTL8367C_ACT85_CVID_MASK    0x100
+#define    RTL8367C_OP84_NOT_OFFSET    6
+#define    RTL8367C_OP84_NOT_MASK    0x40
+#define    RTL8367C_ACT84_GPIO_OFFSET    5
+#define    RTL8367C_ACT84_GPIO_MASK    0x20
+#define    RTL8367C_ACT84_FORWARD_OFFSET    4
+#define    RTL8367C_ACT84_FORWARD_MASK    0x10
+#define    RTL8367C_ACT84_POLICING_OFFSET    3
+#define    RTL8367C_ACT84_POLICING_MASK    0x8
+#define    RTL8367C_ACT84_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT84_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT84_SVID_OFFSET    1
+#define    RTL8367C_ACT84_SVID_MASK    0x2
+#define    RTL8367C_ACT84_CVID_OFFSET    0
+#define    RTL8367C_ACT84_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL43    0x06FB
+#define    RTL8367C_OP87_NOT_OFFSET    14
+#define    RTL8367C_OP87_NOT_MASK    0x4000
+#define    RTL8367C_ACT87_GPIO_OFFSET    13
+#define    RTL8367C_ACT87_GPIO_MASK    0x2000
+#define    RTL8367C_ACT87_FORWARD_OFFSET    12
+#define    RTL8367C_ACT87_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT87_POLICING_OFFSET    11
+#define    RTL8367C_ACT87_POLICING_MASK    0x800
+#define    RTL8367C_ACT87_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT87_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT87_SVID_OFFSET    9
+#define    RTL8367C_ACT87_SVID_MASK    0x200
+#define    RTL8367C_ACT87_CVID_OFFSET    8
+#define    RTL8367C_ACT87_CVID_MASK    0x100
+#define    RTL8367C_OP86_NOT_OFFSET    6
+#define    RTL8367C_OP86_NOT_MASK    0x40
+#define    RTL8367C_ACT86_GPIO_OFFSET    5
+#define    RTL8367C_ACT86_GPIO_MASK    0x20
+#define    RTL8367C_ACT86_FORWARD_OFFSET    4
+#define    RTL8367C_ACT86_FORWARD_MASK    0x10
+#define    RTL8367C_ACT86_POLICING_OFFSET    3
+#define    RTL8367C_ACT86_POLICING_MASK    0x8
+#define    RTL8367C_ACT86_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT86_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT86_SVID_OFFSET    1
+#define    RTL8367C_ACT86_SVID_MASK    0x2
+#define    RTL8367C_ACT86_CVID_OFFSET    0
+#define    RTL8367C_ACT86_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL44    0x06FC
+#define    RTL8367C_OP89_NOT_OFFSET    14
+#define    RTL8367C_OP89_NOT_MASK    0x4000
+#define    RTL8367C_ACT89_GPIO_OFFSET    13
+#define    RTL8367C_ACT89_GPIO_MASK    0x2000
+#define    RTL8367C_ACT89_FORWARD_OFFSET    12
+#define    RTL8367C_ACT89_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT89_POLICING_OFFSET    11
+#define    RTL8367C_ACT89_POLICING_MASK    0x800
+#define    RTL8367C_ACT89_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT89_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT89_SVID_OFFSET    9
+#define    RTL8367C_ACT89_SVID_MASK    0x200
+#define    RTL8367C_ACT89_CVID_OFFSET    8
+#define    RTL8367C_ACT89_CVID_MASK    0x100
+#define    RTL8367C_OP88_NOT_OFFSET    6
+#define    RTL8367C_OP88_NOT_MASK    0x40
+#define    RTL8367C_ACT88_GPIO_OFFSET    5
+#define    RTL8367C_ACT88_GPIO_MASK    0x20
+#define    RTL8367C_ACT88_FORWARD_OFFSET    4
+#define    RTL8367C_ACT88_FORWARD_MASK    0x10
+#define    RTL8367C_ACT88_POLICING_OFFSET    3
+#define    RTL8367C_ACT88_POLICING_MASK    0x8
+#define    RTL8367C_ACT88_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT88_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT88_SVID_OFFSET    1
+#define    RTL8367C_ACT88_SVID_MASK    0x2
+#define    RTL8367C_ACT88_CVID_OFFSET    0
+#define    RTL8367C_ACT88_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL45    0x06FD
+#define    RTL8367C_OP91_NOT_OFFSET    14
+#define    RTL8367C_OP91_NOT_MASK    0x4000
+#define    RTL8367C_ACT91_GPIO_OFFSET    13
+#define    RTL8367C_ACT91_GPIO_MASK    0x2000
+#define    RTL8367C_ACT91_FORWARD_OFFSET    12
+#define    RTL8367C_ACT91_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT91_POLICING_OFFSET    11
+#define    RTL8367C_ACT91_POLICING_MASK    0x800
+#define    RTL8367C_ACT91_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT91_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT91_SVID_OFFSET    9
+#define    RTL8367C_ACT91_SVID_MASK    0x200
+#define    RTL8367C_ACT91_CVID_OFFSET    8
+#define    RTL8367C_ACT91_CVID_MASK    0x100
+#define    RTL8367C_OP90_NOT_OFFSET    6
+#define    RTL8367C_OP90_NOT_MASK    0x40
+#define    RTL8367C_ACT90_GPIO_OFFSET    5
+#define    RTL8367C_ACT90_GPIO_MASK    0x20
+#define    RTL8367C_ACT90_FORWARD_OFFSET    4
+#define    RTL8367C_ACT90_FORWARD_MASK    0x10
+#define    RTL8367C_ACT90_POLICING_OFFSET    3
+#define    RTL8367C_ACT90_POLICING_MASK    0x8
+#define    RTL8367C_ACT90_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT90_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT90_SVID_OFFSET    1
+#define    RTL8367C_ACT90_SVID_MASK    0x2
+#define    RTL8367C_ACT90_CVID_OFFSET    0
+#define    RTL8367C_ACT90_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL46    0x06FE
+#define    RTL8367C_OP93_NOT_OFFSET    14
+#define    RTL8367C_OP93_NOT_MASK    0x4000
+#define    RTL8367C_ACT93_GPIO_OFFSET    13
+#define    RTL8367C_ACT93_GPIO_MASK    0x2000
+#define    RTL8367C_ACT93_FORWARD_OFFSET    12
+#define    RTL8367C_ACT93_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT93_POLICING_OFFSET    11
+#define    RTL8367C_ACT93_POLICING_MASK    0x800
+#define    RTL8367C_ACT93_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT93_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT93_SVID_OFFSET    9
+#define    RTL8367C_ACT93_SVID_MASK    0x200
+#define    RTL8367C_ACT93_CVID_OFFSET    8
+#define    RTL8367C_ACT93_CVID_MASK    0x100
+#define    RTL8367C_OP92_NOT_OFFSET    6
+#define    RTL8367C_OP92_NOT_MASK    0x40
+#define    RTL8367C_ACT92_GPIO_OFFSET    5
+#define    RTL8367C_ACT92_GPIO_MASK    0x20
+#define    RTL8367C_ACT92_FORWARD_OFFSET    4
+#define    RTL8367C_ACT92_FORWARD_MASK    0x10
+#define    RTL8367C_ACT92_POLICING_OFFSET    3
+#define    RTL8367C_ACT92_POLICING_MASK    0x8
+#define    RTL8367C_ACT92_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT92_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT92_SVID_OFFSET    1
+#define    RTL8367C_ACT92_SVID_MASK    0x2
+#define    RTL8367C_ACT92_CVID_OFFSET    0
+#define    RTL8367C_ACT92_CVID_MASK    0x1
+
+#define    RTL8367C_REG_ACL_ACTION_CTRL47    0x06FF
+#define    RTL8367C_OP95_NOT_OFFSET    14
+#define    RTL8367C_OP95_NOT_MASK    0x4000
+#define    RTL8367C_ACT95_GPIO_OFFSET    13
+#define    RTL8367C_ACT95_GPIO_MASK    0x2000
+#define    RTL8367C_ACT95_FORWARD_OFFSET    12
+#define    RTL8367C_ACT95_FORWARD_MASK    0x1000
+#define    RTL8367C_ACT95_POLICING_OFFSET    11
+#define    RTL8367C_ACT95_POLICING_MASK    0x800
+#define    RTL8367C_ACT95_PRIORITY_OFFSET    10
+#define    RTL8367C_ACT95_PRIORITY_MASK    0x400
+#define    RTL8367C_ACT95_SVID_OFFSET    9
+#define    RTL8367C_ACT95_SVID_MASK    0x200
+#define    RTL8367C_ACT95_CVID_OFFSET    8
+#define    RTL8367C_ACT95_CVID_MASK    0x100
+#define    RTL8367C_OP94_NOT_OFFSET    6
+#define    RTL8367C_OP94_NOT_MASK    0x40
+#define    RTL8367C_ACT94_GPIO_OFFSET    5
+#define    RTL8367C_ACT94_GPIO_MASK    0x20
+#define    RTL8367C_ACT94_FORWARD_OFFSET    4
+#define    RTL8367C_ACT94_FORWARD_MASK    0x10
+#define    RTL8367C_ACT94_POLICING_OFFSET    3
+#define    RTL8367C_ACT94_POLICING_MASK    0x8
+#define    RTL8367C_ACT94_PRIORITY_OFFSET    2
+#define    RTL8367C_ACT94_PRIORITY_MASK    0x4
+#define    RTL8367C_ACT94_SVID_OFFSET    1
+#define    RTL8367C_ACT94_SVID_MASK    0x2
+#define    RTL8367C_ACT94_CVID_OFFSET    0
+#define    RTL8367C_ACT94_CVID_MASK    0x1
+
+/* (16'h0700)cvlan_reg */
+
+#define    RTL8367C_REG_VLAN_PVID_CTRL0    0x0700
+#define    RTL8367C_PORT1_VIDX_OFFSET    8
+#define    RTL8367C_PORT1_VIDX_MASK    0x1F00
+#define    RTL8367C_PORT0_VIDX_OFFSET    0
+#define    RTL8367C_PORT0_VIDX_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PVID_CTRL1    0x0701
+#define    RTL8367C_PORT3_VIDX_OFFSET    8
+#define    RTL8367C_PORT3_VIDX_MASK    0x1F00
+#define    RTL8367C_PORT2_VIDX_OFFSET    0
+#define    RTL8367C_PORT2_VIDX_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PVID_CTRL2    0x0702
+#define    RTL8367C_PORT5_VIDX_OFFSET    8
+#define    RTL8367C_PORT5_VIDX_MASK    0x1F00
+#define    RTL8367C_PORT4_VIDX_OFFSET    0
+#define    RTL8367C_PORT4_VIDX_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PVID_CTRL3    0x0703
+#define    RTL8367C_PORT7_VIDX_OFFSET    8
+#define    RTL8367C_PORT7_VIDX_MASK    0x1F00
+#define    RTL8367C_PORT6_VIDX_OFFSET    0
+#define    RTL8367C_PORT6_VIDX_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PVID_CTRL4    0x0704
+#define    RTL8367C_PORT9_VIDX_OFFSET    8
+#define    RTL8367C_PORT9_VIDX_MASK    0x1F00
+#define    RTL8367C_PORT8_VIDX_OFFSET    0
+#define    RTL8367C_PORT8_VIDX_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PVID_CTRL5    0x0705
+#define    RTL8367C_VLAN_PVID_CTRL5_OFFSET    0
+#define    RTL8367C_VLAN_PVID_CTRL5_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PPB0_VALID    0x0708
+#define    RTL8367C_VLAN_PPB0_VALID_VALID_EXT_OFFSET    8
+#define    RTL8367C_VLAN_PPB0_VALID_VALID_EXT_MASK    0x700
+#define    RTL8367C_VLAN_PPB0_VALID_VALID_OFFSET    0
+#define    RTL8367C_VLAN_PPB0_VALID_VALID_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_PPB0_CTRL0    0x0709
+#define    RTL8367C_VLAN_PPB0_CTRL0_PORT2_INDEX_OFFSET    10
+#define    RTL8367C_VLAN_PPB0_CTRL0_PORT2_INDEX_MASK    0x7C00
+#define    RTL8367C_VLAN_PPB0_CTRL0_PORT1_INDEX_OFFSET    5
+#define    RTL8367C_VLAN_PPB0_CTRL0_PORT1_INDEX_MASK    0x3E0
+#define    RTL8367C_VLAN_PPB0_CTRL0_PORT0_INDEX_OFFSET    0
+#define    RTL8367C_VLAN_PPB0_CTRL0_PORT0_INDEX_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PPB0_CTRL1    0x070a
+#define    RTL8367C_VLAN_PPB0_CTRL1_PORT5_INDEX_OFFSET    10
+#define    RTL8367C_VLAN_PPB0_CTRL1_PORT5_INDEX_MASK    0x7C00
+#define    RTL8367C_VLAN_PPB0_CTRL1_PORT4_INDEX_OFFSET    5
+#define    RTL8367C_VLAN_PPB0_CTRL1_PORT4_INDEX_MASK    0x3E0
+#define    RTL8367C_VLAN_PPB0_CTRL1_PORT3_INDEX_OFFSET    0
+#define    RTL8367C_VLAN_PPB0_CTRL1_PORT3_INDEX_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PPB0_CTRL2    0x070b
+#define    RTL8367C_VLAN_PPB0_CTRL2_FRAME_TYPE_OFFSET    10
+#define    RTL8367C_VLAN_PPB0_CTRL2_FRAME_TYPE_MASK    0xC00
+#define    RTL8367C_VLAN_PPB0_CTRL2_PORT7_INDEX_OFFSET    5
+#define    RTL8367C_VLAN_PPB0_CTRL2_PORT7_INDEX_MASK    0x3E0
+#define    RTL8367C_VLAN_PPB0_CTRL2_PORT6_INDEX_OFFSET    0
+#define    RTL8367C_VLAN_PPB0_CTRL2_PORT6_INDEX_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PPB0_CTRL4    0x070c
+#define    RTL8367C_VLAN_PPB0_CTRL4_PORT10_INDEX_OFFSET    10
+#define    RTL8367C_VLAN_PPB0_CTRL4_PORT10_INDEX_MASK    0x7C00
+#define    RTL8367C_VLAN_PPB0_CTRL4_PORT9_INDEX_OFFSET    5
+#define    RTL8367C_VLAN_PPB0_CTRL4_PORT9_INDEX_MASK    0x3E0
+#define    RTL8367C_VLAN_PPB0_CTRL4_PORT8_INDEX_OFFSET    0
+#define    RTL8367C_VLAN_PPB0_CTRL4_PORT8_INDEX_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PPB0_CTRL3    0x070f
+
+#define    RTL8367C_REG_VLAN_PPB1_VALID    0x0710
+#define    RTL8367C_VLAN_PPB1_VALID_VALID_EXT_OFFSET    8
+#define    RTL8367C_VLAN_PPB1_VALID_VALID_EXT_MASK    0x700
+#define    RTL8367C_VLAN_PPB1_VALID_VALID_OFFSET    0
+#define    RTL8367C_VLAN_PPB1_VALID_VALID_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_PPB1_CTRL0    0x0711
+#define    RTL8367C_VLAN_PPB1_CTRL0_PORT2_INDEX_OFFSET    10
+#define    RTL8367C_VLAN_PPB1_CTRL0_PORT2_INDEX_MASK    0x7C00
+#define    RTL8367C_VLAN_PPB1_CTRL0_PORT1_INDEX_OFFSET    5
+#define    RTL8367C_VLAN_PPB1_CTRL0_PORT1_INDEX_MASK    0x3E0
+#define    RTL8367C_VLAN_PPB1_CTRL0_PORT0_INDEX_OFFSET    0
+#define    RTL8367C_VLAN_PPB1_CTRL0_PORT0_INDEX_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PPB1_CTRL1    0x0712
+#define    RTL8367C_VLAN_PPB1_CTRL1_PORT5_INDEX_OFFSET    10
+#define    RTL8367C_VLAN_PPB1_CTRL1_PORT5_INDEX_MASK    0x7C00
+#define    RTL8367C_VLAN_PPB1_CTRL1_PORT4_INDEX_OFFSET    5
+#define    RTL8367C_VLAN_PPB1_CTRL1_PORT4_INDEX_MASK    0x3E0
+#define    RTL8367C_VLAN_PPB1_CTRL1_PORT3_INDEX_OFFSET    0
+#define    RTL8367C_VLAN_PPB1_CTRL1_PORT3_INDEX_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PPB1_CTRL2    0x0713
+#define    RTL8367C_VLAN_PPB1_CTRL2_FRAME_TYPE_OFFSET    10
+#define    RTL8367C_VLAN_PPB1_CTRL2_FRAME_TYPE_MASK    0xC00
+#define    RTL8367C_VLAN_PPB1_CTRL2_PORT7_INDEX_OFFSET    5
+#define    RTL8367C_VLAN_PPB1_CTRL2_PORT7_INDEX_MASK    0x3E0
+#define    RTL8367C_VLAN_PPB1_CTRL2_PORT6_INDEX_OFFSET    0
+#define    RTL8367C_VLAN_PPB1_CTRL2_PORT6_INDEX_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PPB1_CTRL4    0x0714
+#define    RTL8367C_VLAN_PPB1_CTRL4_PORT10_INDEX_OFFSET    10
+#define    RTL8367C_VLAN_PPB1_CTRL4_PORT10_INDEX_MASK    0x7C00
+#define    RTL8367C_VLAN_PPB1_CTRL4_PORT9_INDEX_OFFSET    5
+#define    RTL8367C_VLAN_PPB1_CTRL4_PORT9_INDEX_MASK    0x3E0
+#define    RTL8367C_VLAN_PPB1_CTRL4_PORT8_INDEX_OFFSET    0
+#define    RTL8367C_VLAN_PPB1_CTRL4_PORT8_INDEX_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PPB1_CTRL3    0x0717
+
+#define    RTL8367C_REG_VLAN_PPB2_VALID    0x0718
+#define    RTL8367C_VLAN_PPB2_VALID_VALID_EXT_OFFSET    8
+#define    RTL8367C_VLAN_PPB2_VALID_VALID_EXT_MASK    0x700
+#define    RTL8367C_VLAN_PPB2_VALID_VALID_OFFSET    0
+#define    RTL8367C_VLAN_PPB2_VALID_VALID_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_PPB2_CTRL0    0x0719
+#define    RTL8367C_VLAN_PPB2_CTRL0_PORT2_INDEX_OFFSET    10
+#define    RTL8367C_VLAN_PPB2_CTRL0_PORT2_INDEX_MASK    0x7C00
+#define    RTL8367C_VLAN_PPB2_CTRL0_PORT1_INDEX_OFFSET    5
+#define    RTL8367C_VLAN_PPB2_CTRL0_PORT1_INDEX_MASK    0x3E0
+#define    RTL8367C_VLAN_PPB2_CTRL0_PORT0_INDEX_OFFSET    0
+#define    RTL8367C_VLAN_PPB2_CTRL0_PORT0_INDEX_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PPB2_CTRL1    0x071a
+#define    RTL8367C_VLAN_PPB2_CTRL1_PORT5_INDEX_OFFSET    10
+#define    RTL8367C_VLAN_PPB2_CTRL1_PORT5_INDEX_MASK    0x7C00
+#define    RTL8367C_VLAN_PPB2_CTRL1_PORT4_INDEX_OFFSET    5
+#define    RTL8367C_VLAN_PPB2_CTRL1_PORT4_INDEX_MASK    0x3E0
+#define    RTL8367C_VLAN_PPB2_CTRL1_PORT3_INDEX_OFFSET    0
+#define    RTL8367C_VLAN_PPB2_CTRL1_PORT3_INDEX_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PPB2_CTRL2    0x071b
+#define    RTL8367C_VLAN_PPB2_CTRL2_FRAME_TYPE_OFFSET    10
+#define    RTL8367C_VLAN_PPB2_CTRL2_FRAME_TYPE_MASK    0xC00
+#define    RTL8367C_VLAN_PPB2_CTRL2_PORT7_INDEX_OFFSET    5
+#define    RTL8367C_VLAN_PPB2_CTRL2_PORT7_INDEX_MASK    0x3E0
+#define    RTL8367C_VLAN_PPB2_CTRL2_PORT6_INDEX_OFFSET    0
+#define    RTL8367C_VLAN_PPB2_CTRL2_PORT6_INDEX_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PPB2_CTRL4    0x071c
+#define    RTL8367C_VLAN_PPB2_CTRL4_PORT10_INDEX_OFFSET    10
+#define    RTL8367C_VLAN_PPB2_CTRL4_PORT10_INDEX_MASK    0x7C00
+#define    RTL8367C_VLAN_PPB2_CTRL4_PORT9_INDEX_OFFSET    5
+#define    RTL8367C_VLAN_PPB2_CTRL4_PORT9_INDEX_MASK    0x3E0
+#define    RTL8367C_VLAN_PPB2_CTRL4_PORT8_INDEX_OFFSET    0
+#define    RTL8367C_VLAN_PPB2_CTRL4_PORT8_INDEX_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PPB2_CTRL3    0x071f
+
+#define    RTL8367C_REG_VLAN_PPB3_VALID    0x0720
+#define    RTL8367C_VLAN_PPB3_VALID_VALID_EXT_OFFSET    8
+#define    RTL8367C_VLAN_PPB3_VALID_VALID_EXT_MASK    0x700
+#define    RTL8367C_VLAN_PPB3_VALID_VALID_OFFSET    0
+#define    RTL8367C_VLAN_PPB3_VALID_VALID_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_PPB3_CTRL0    0x0721
+#define    RTL8367C_VLAN_PPB3_CTRL0_PORT2_INDEX_OFFSET    10
+#define    RTL8367C_VLAN_PPB3_CTRL0_PORT2_INDEX_MASK    0x7C00
+#define    RTL8367C_VLAN_PPB3_CTRL0_PORT1_INDEX_OFFSET    5
+#define    RTL8367C_VLAN_PPB3_CTRL0_PORT1_INDEX_MASK    0x3E0
+#define    RTL8367C_VLAN_PPB3_CTRL0_PORT0_INDEX_OFFSET    0
+#define    RTL8367C_VLAN_PPB3_CTRL0_PORT0_INDEX_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PPB3_CTRL1    0x0722
+#define    RTL8367C_VLAN_PPB3_CTRL1_PORT5_INDEX_OFFSET    10
+#define    RTL8367C_VLAN_PPB3_CTRL1_PORT5_INDEX_MASK    0x7C00
+#define    RTL8367C_VLAN_PPB3_CTRL1_PORT4_INDEX_OFFSET    5
+#define    RTL8367C_VLAN_PPB3_CTRL1_PORT4_INDEX_MASK    0x3E0
+#define    RTL8367C_VLAN_PPB3_CTRL1_PORT3_INDEX_OFFSET    0
+#define    RTL8367C_VLAN_PPB3_CTRL1_PORT3_INDEX_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PPB3_CTRL2    0x0723
+#define    RTL8367C_VLAN_PPB3_CTRL2_FRAME_TYPE_OFFSET    10
+#define    RTL8367C_VLAN_PPB3_CTRL2_FRAME_TYPE_MASK    0xC00
+#define    RTL8367C_VLAN_PPB3_CTRL2_PORT7_INDEX_OFFSET    5
+#define    RTL8367C_VLAN_PPB3_CTRL2_PORT7_INDEX_MASK    0x3E0
+#define    RTL8367C_VLAN_PPB3_CTRL2_PORT6_INDEX_OFFSET    0
+#define    RTL8367C_VLAN_PPB3_CTRL2_PORT6_INDEX_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PPB3_CTRL4    0x0724
+#define    RTL8367C_VLAN_PPB3_CTRL4_PORT10_INDEX_OFFSET    10
+#define    RTL8367C_VLAN_PPB3_CTRL4_PORT10_INDEX_MASK    0x7C00
+#define    RTL8367C_VLAN_PPB3_CTRL4_PORT9_INDEX_OFFSET    5
+#define    RTL8367C_VLAN_PPB3_CTRL4_PORT9_INDEX_MASK    0x3E0
+#define    RTL8367C_VLAN_PPB3_CTRL4_PORT8_INDEX_OFFSET    0
+#define    RTL8367C_VLAN_PPB3_CTRL4_PORT8_INDEX_MASK    0x1F
+
+#define    RTL8367C_REG_VLAN_PPB3_CTRL3    0x0727
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION0_CTRL0    0x0728
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION0_CTRL1    0x0729
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION0_CTRL2    0x072a
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION0_CTRL3    0x072b
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION1_CTRL0    0x072c
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION1_CTRL1    0x072d
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION1_CTRL2    0x072e
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION1_CTRL3    0x072f
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION2_CTRL0    0x0730
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION2_CTRL1    0x0731
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION2_CTRL2    0x0732
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION2_CTRL3    0x0733
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION3_CTRL0    0x0734
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION3_CTRL1    0x0735
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION3_CTRL2    0x0736
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION3_CTRL3    0x0737
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION4_CTRL0    0x0738
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION4_CTRL1    0x0739
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION4_CTRL2    0x073a
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION4_CTRL3    0x073b
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION5_CTRL0    0x073c
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION5_CTRL1    0x073d
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION5_CTRL2    0x073e
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION5_CTRL3    0x073f
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION6_CTRL0    0x0740
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION6_CTRL1    0x0741
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION6_CTRL2    0x0742
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION6_CTRL3    0x0743
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION7_CTRL0    0x0744
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION7_CTRL1    0x0745
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION7_CTRL2    0x0746
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION7_CTRL3    0x0747
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION8_CTRL0    0x0748
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION8_CTRL1    0x0749
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION8_CTRL2    0x074a
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION8_CTRL3    0x074b
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION9_CTRL0    0x074c
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION9_CTRL1    0x074d
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION9_CTRL2    0x074e
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION9_CTRL3    0x074f
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION10_CTRL0    0x0750
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION10_CTRL1    0x0751
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION10_CTRL2    0x0752
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION10_CTRL3    0x0753
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION11_CTRL0    0x0754
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION11_CTRL1    0x0755
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION11_CTRL2    0x0756
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION11_CTRL3    0x0757
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION12_CTRL0    0x0758
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION12_CTRL1    0x0759
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION12_CTRL2    0x075a
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION12_CTRL3    0x075b
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION13_CTRL0    0x075c
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION13_CTRL1    0x075d
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION13_CTRL2    0x075e
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION13_CTRL3    0x075f
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION14_CTRL0    0x0760
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION14_CTRL1    0x0761
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION14_CTRL2    0x0762
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION14_CTRL3    0x0763
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION15_CTRL0    0x0764
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION15_CTRL1    0x0765
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION15_CTRL2    0x0766
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION15_CTRL3    0x0767
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION16_CTRL0    0x0768
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION16_CTRL1    0x0769
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION16_CTRL2    0x076a
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION16_CTRL3    0x076b
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION17_CTRL0    0x076c
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION17_CTRL1    0x076d
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION17_CTRL2    0x076e
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION17_CTRL3    0x076f
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION18_CTRL0    0x0770
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION18_CTRL1    0x0771
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION18_CTRL2    0x0772
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION18_CTRL3    0x0773
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION19_CTRL0    0x0774
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION19_CTRL1    0x0775
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION19_CTRL2    0x0776
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION19_CTRL3    0x0777
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION20_CTRL0    0x0778
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION20_CTRL1    0x0779
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION20_CTRL2    0x077a
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION20_CTRL3    0x077b
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION21_CTRL0    0x077c
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION21_CTRL1    0x077d
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION21_CTRL2    0x077e
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION21_CTRL3    0x077f
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION22_CTRL0    0x0780
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION22_CTRL1    0x0781
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION22_CTRL2    0x0782
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION22_CTRL3    0x0783
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION23_CTRL0    0x0784
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION23_CTRL1    0x0785
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION23_CTRL2    0x0786
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION23_CTRL3    0x0787
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION24_CTRL0    0x0788
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION24_CTRL1    0x0789
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION24_CTRL2    0x078a
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION24_CTRL3    0x078b
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION25_CTRL0    0x078c
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION25_CTRL1    0x078d
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION25_CTRL2    0x078e
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION25_CTRL3    0x078f
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION26_CTRL0    0x0790
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION26_CTRL1    0x0791
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION26_CTRL2    0x0792
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION26_CTRL3    0x0793
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION27_CTRL0    0x0794
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION27_CTRL1    0x0795
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION27_CTRL2    0x0796
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION27_CTRL3    0x0797
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION28_CTRL0    0x0798
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION28_CTRL1    0x0799
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION28_CTRL2    0x079a
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION28_CTRL3    0x079b
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION29_CTRL0    0x079c
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION29_CTRL1    0x079d
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION29_CTRL2    0x079e
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION29_CTRL3    0x079f
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION30_CTRL0    0x07a0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION30_CTRL1    0x07a1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION30_CTRL2    0x07a2
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION30_CTRL3    0x07a3
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION31_CTRL0    0x07a4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL0_MBR_EXT_OFFSET    8
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL0_MBR_EXT_MASK    0x700
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL0_MBR_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL0_MBR_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION31_CTRL1    0x07a5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL1_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION31_CTRL2    0x07a6
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_METERIDX_EXT_OFFSET    10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_METERIDX_EXT_MASK    0x400
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_METERIDX_OFFSET    5
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_METERIDX_MASK    0x3E0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_ENVLANPOL_OFFSET    4
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_ENVLANPOL_MASK    0x10
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_VBPRI_OFFSET    1
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_VBPRI_MASK    0xE
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_VBPEN_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_VBPEN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_MEMBER_CONFIGURATION31_CTRL3    0x07a7
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_VLAN_CTRL    0x07a8
+#define    RTL8367C_VLAN_CTRL_OFFSET    0
+#define    RTL8367C_VLAN_CTRL_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_INGRESS    0x07a9
+#define    RTL8367C_VLAN_INGRESS_OFFSET    0
+#define    RTL8367C_VLAN_INGRESS_MASK    0x7FF
+
+#define    RTL8367C_REG_VLAN_ACCEPT_FRAME_TYPE_CTRL0    0x07aa
+#define    RTL8367C_PORT7_FRAME_TYPE_OFFSET    14
+#define    RTL8367C_PORT7_FRAME_TYPE_MASK    0xC000
+#define    RTL8367C_PORT6_FRAME_TYPE_OFFSET    12
+#define    RTL8367C_PORT6_FRAME_TYPE_MASK    0x3000
+#define    RTL8367C_PORT5_FRAME_TYPE_OFFSET    10
+#define    RTL8367C_PORT5_FRAME_TYPE_MASK    0xC00
+#define    RTL8367C_PORT4_FRAME_TYPE_OFFSET    8
+#define    RTL8367C_PORT4_FRAME_TYPE_MASK    0x300
+#define    RTL8367C_PORT3_FRAME_TYPE_OFFSET    6
+#define    RTL8367C_PORT3_FRAME_TYPE_MASK    0xC0
+#define    RTL8367C_PORT2_FRAME_TYPE_OFFSET    4
+#define    RTL8367C_PORT2_FRAME_TYPE_MASK    0x30
+#define    RTL8367C_PORT1_FRAME_TYPE_OFFSET    2
+#define    RTL8367C_PORT1_FRAME_TYPE_MASK    0xC
+#define    RTL8367C_PORT0_FRAME_TYPE_OFFSET    0
+#define    RTL8367C_PORT0_FRAME_TYPE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_ACCEPT_FRAME_TYPE_CTRL1    0x07ab
+#define    RTL8367C_PORT10_FRAME_TYPE_OFFSET    4
+#define    RTL8367C_PORT10_FRAME_TYPE_MASK    0x30
+#define    RTL8367C_PORT9_FRAME_TYPE_OFFSET    2
+#define    RTL8367C_PORT9_FRAME_TYPE_MASK    0xC
+#define    RTL8367C_PORT8_FRAME_TYPE_OFFSET    0
+#define    RTL8367C_PORT8_FRAME_TYPE_MASK    0x3
+
+#define    RTL8367C_REG_PORT_PBFIDEN    0x07ac
+#define    RTL8367C_PORT_PBFIDEN_OFFSET    0
+#define    RTL8367C_PORT_PBFIDEN_MASK    0x7FF
+
+#define    RTL8367C_REG_PORT0_PBFID    0x07ad
+#define    RTL8367C_PORT0_PBFID_OFFSET    0
+#define    RTL8367C_PORT0_PBFID_MASK    0xF
+
+#define    RTL8367C_REG_PORT1_PBFID    0x07ae
+#define    RTL8367C_PORT1_PBFID_OFFSET    0
+#define    RTL8367C_PORT1_PBFID_MASK    0xF
+
+#define    RTL8367C_REG_PORT2_PBFID    0x07af
+#define    RTL8367C_PORT2_PBFID_OFFSET    0
+#define    RTL8367C_PORT2_PBFID_MASK    0xF
+
+#define    RTL8367C_REG_PORT3_PBFID    0x07b0
+#define    RTL8367C_PORT3_PBFID_OFFSET    0
+#define    RTL8367C_PORT3_PBFID_MASK    0xF
+
+#define    RTL8367C_REG_PORT4_PBFID    0x07b1
+#define    RTL8367C_PORT4_PBFID_OFFSET    0
+#define    RTL8367C_PORT4_PBFID_MASK    0xF
+
+#define    RTL8367C_REG_PORT5_PBFID    0x07b2
+#define    RTL8367C_PORT5_PBFID_OFFSET    0
+#define    RTL8367C_PORT5_PBFID_MASK    0xF
+
+#define    RTL8367C_REG_PORT6_PBFID    0x07b3
+#define    RTL8367C_PORT6_PBFID_OFFSET    0
+#define    RTL8367C_PORT6_PBFID_MASK    0xF
+
+#define    RTL8367C_REG_PORT7_PBFID    0x07b4
+#define    RTL8367C_PORT7_PBFID_OFFSET    0
+#define    RTL8367C_PORT7_PBFID_MASK    0xF
+
+#define    RTL8367C_REG_VLAN_EXT_CTRL    0x07b5
+#define    RTL8367C_VLAN_1P_REMARK_BYPASS_REALKEEP_OFFSET    2
+#define    RTL8367C_VLAN_1P_REMARK_BYPASS_REALKEEP_MASK    0x4
+#define    RTL8367C_VLAN_VID4095_TYPE_OFFSET    1
+#define    RTL8367C_VLAN_VID4095_TYPE_MASK    0x2
+#define    RTL8367C_VLAN_VID0_TYPE_OFFSET    0
+#define    RTL8367C_VLAN_VID0_TYPE_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_EXT_CTRL2    0x07b6
+#define    RTL8367C_VLAN_EXT_CTRL2_OFFSET    0
+#define    RTL8367C_VLAN_EXT_CTRL2_MASK    0x1
+
+#define    RTL8367C_REG_PORT8_PBFID    0x07b7
+#define    RTL8367C_PORT8_PBFID_OFFSET    0
+#define    RTL8367C_PORT8_PBFID_MASK    0xF
+
+#define    RTL8367C_REG_PORT9_PBFID    0x07b8
+#define    RTL8367C_PORT9_PBFID_OFFSET    0
+#define    RTL8367C_PORT9_PBFID_MASK    0xF
+
+#define    RTL8367C_REG_PORT10_PBFID    0x07b9
+#define    RTL8367C_PORT10_PBFID_OFFSET    0
+#define    RTL8367C_PORT10_PBFID_MASK    0xF
+
+#define    RTL8367C_REG_CVLAN_DUMMY00    0x07E0
+
+#define    RTL8367C_REG_CVLAN_DUMMY01    0x07E1
+
+#define    RTL8367C_REG_CVLAN_DUMMY02    0x07E2
+
+#define    RTL8367C_REG_CVLAN_DUMMY03    0x07E3
+
+#define    RTL8367C_REG_CVLAN_DUMMY04    0x07E4
+
+#define    RTL8367C_REG_CVLAN_DUMMY05    0x07E5
+
+#define    RTL8367C_REG_CVLAN_DUMMY06    0x07E6
+
+#define    RTL8367C_REG_CVLAN_DUMMY07    0x07E7
+
+#define    RTL8367C_REG_CVLAN_DUMMY08    0x07E8
+
+#define    RTL8367C_REG_CVLAN_DUMMY09    0x07E9
+
+#define    RTL8367C_REG_CVLAN_DUMMY10    0x07EA
+
+#define    RTL8367C_REG_CVLAN_DUMMY11    0x07EB
+
+#define    RTL8367C_REG_CVLAN_DUMMY12    0x07EC
+
+#define    RTL8367C_REG_CVLAN_DUMMY13    0x07ED
+
+#define    RTL8367C_REG_CVLAN_DUMMY14    0x07EE
+
+#define    RTL8367C_REG_CVLAN_DUMMY15    0x07EF
+
+/* (16'h0800)dpm_reg */
+
+#define    RTL8367C_REG_RMA_CTRL00    0x0800
+#define    RTL8367C_RMA_CTRL00_OPERATION_OFFSET    7
+#define    RTL8367C_RMA_CTRL00_OPERATION_MASK    0x180
+#define    RTL8367C_RMA_CTRL00_DISCARD_STORM_FILTER_OFFSET    6
+#define    RTL8367C_RMA_CTRL00_DISCARD_STORM_FILTER_MASK    0x40
+#define    RTL8367C_TRAP_PRIORITY_OFFSET    3
+#define    RTL8367C_TRAP_PRIORITY_MASK    0x38
+#define    RTL8367C_RMA_CTRL00_KEEP_FORMAT_OFFSET    2
+#define    RTL8367C_RMA_CTRL00_KEEP_FORMAT_MASK    0x4
+#define    RTL8367C_RMA_CTRL00_VLAN_LEAKY_OFFSET    1
+#define    RTL8367C_RMA_CTRL00_VLAN_LEAKY_MASK    0x2
+#define    RTL8367C_RMA_CTRL00_PORTISO_LEAKY_OFFSET    0
+#define    RTL8367C_RMA_CTRL00_PORTISO_LEAKY_MASK    0x1
+
+#define    RTL8367C_REG_RMA_CTRL01    0x0801
+#define    RTL8367C_RMA_CTRL01_OPERATION_OFFSET    7
+#define    RTL8367C_RMA_CTRL01_OPERATION_MASK    0x180
+#define    RTL8367C_RMA_CTRL01_DISCARD_STORM_FILTER_OFFSET    6
+#define    RTL8367C_RMA_CTRL01_DISCARD_STORM_FILTER_MASK    0x40
+#define    RTL8367C_RMA_CTRL01_KEEP_FORMAT_OFFSET    2
+#define    RTL8367C_RMA_CTRL01_KEEP_FORMAT_MASK    0x4
+#define    RTL8367C_RMA_CTRL01_VLAN_LEAKY_OFFSET    1
+#define    RTL8367C_RMA_CTRL01_VLAN_LEAKY_MASK    0x2
+#define    RTL8367C_RMA_CTRL01_PORTISO_LEAKY_OFFSET    0
+#define    RTL8367C_RMA_CTRL01_PORTISO_LEAKY_MASK    0x1
+
+#define    RTL8367C_REG_RMA_CTRL02    0x0802
+#define    RTL8367C_RMA_CTRL02_OPERATION_OFFSET    7
+#define    RTL8367C_RMA_CTRL02_OPERATION_MASK    0x180
+#define    RTL8367C_RMA_CTRL02_DISCARD_STORM_FILTER_OFFSET    6
+#define    RTL8367C_RMA_CTRL02_DISCARD_STORM_FILTER_MASK    0x40
+#define    RTL8367C_RMA_CTRL02_KEEP_FORMAT_OFFSET    2
+#define    RTL8367C_RMA_CTRL02_KEEP_FORMAT_MASK    0x4
+#define    RTL8367C_RMA_CTRL02_VLAN_LEAKY_OFFSET    1
+#define    RTL8367C_RMA_CTRL02_VLAN_LEAKY_MASK    0x2
+#define    RTL8367C_RMA_CTRL02_PORTISO_LEAKY_OFFSET    0
+#define    RTL8367C_RMA_CTRL02_PORTISO_LEAKY_MASK    0x1
+
+#define    RTL8367C_REG_RMA_CTRL03    0x0803
+#define    RTL8367C_RMA_CTRL03_OPERATION_OFFSET    7
+#define    RTL8367C_RMA_CTRL03_OPERATION_MASK    0x180
+#define    RTL8367C_RMA_CTRL03_DISCARD_STORM_FILTER_OFFSET    6
+#define    RTL8367C_RMA_CTRL03_DISCARD_STORM_FILTER_MASK    0x40
+#define    RTL8367C_RMA_CTRL03_KEEP_FORMAT_OFFSET    2
+#define    RTL8367C_RMA_CTRL03_KEEP_FORMAT_MASK    0x4
+#define    RTL8367C_RMA_CTRL03_VLAN_LEAKY_OFFSET    1
+#define    RTL8367C_RMA_CTRL03_VLAN_LEAKY_MASK    0x2
+#define    RTL8367C_RMA_CTRL03_PORTISO_LEAKY_OFFSET    0
+#define    RTL8367C_RMA_CTRL03_PORTISO_LEAKY_MASK    0x1
+
+#define    RTL8367C_REG_RMA_CTRL04    0x0804
+#define    RTL8367C_RMA_CTRL04_OPERATION_OFFSET    7
+#define    RTL8367C_RMA_CTRL04_OPERATION_MASK    0x180
+#define    RTL8367C_RMA_CTRL04_DISCARD_STORM_FILTER_OFFSET    6
+#define    RTL8367C_RMA_CTRL04_DISCARD_STORM_FILTER_MASK    0x40
+#define    RTL8367C_RMA_CTRL04_KEEP_FORMAT_OFFSET    2
+#define    RTL8367C_RMA_CTRL04_KEEP_FORMAT_MASK    0x4
+#define    RTL8367C_RMA_CTRL04_VLAN_LEAKY_OFFSET    1
+#define    RTL8367C_RMA_CTRL04_VLAN_LEAKY_MASK    0x2
+#define    RTL8367C_RMA_CTRL04_PORTISO_LEAKY_OFFSET    0
+#define    RTL8367C_RMA_CTRL04_PORTISO_LEAKY_MASK    0x1
+
+#define    RTL8367C_REG_RMA_CTRL08    0x0808
+#define    RTL8367C_RMA_CTRL08_OPERATION_OFFSET    7
+#define    RTL8367C_RMA_CTRL08_OPERATION_MASK    0x180
+#define    RTL8367C_RMA_CTRL08_DISCARD_STORM_FILTER_OFFSET    6
+#define    RTL8367C_RMA_CTRL08_DISCARD_STORM_FILTER_MASK    0x40
+#define    RTL8367C_RMA_CTRL08_KEEP_FORMAT_OFFSET    2
+#define    RTL8367C_RMA_CTRL08_KEEP_FORMAT_MASK    0x4
+#define    RTL8367C_RMA_CTRL08_VLAN_LEAKY_OFFSET    1
+#define    RTL8367C_RMA_CTRL08_VLAN_LEAKY_MASK    0x2
+#define    RTL8367C_RMA_CTRL08_PORTISO_LEAKY_OFFSET    0
+#define    RTL8367C_RMA_CTRL08_PORTISO_LEAKY_MASK    0x1
+
+#define    RTL8367C_REG_RMA_CTRL0D    0x080d
+#define    RTL8367C_RMA_CTRL0D_OPERATION_OFFSET    7
+#define    RTL8367C_RMA_CTRL0D_OPERATION_MASK    0x180
+#define    RTL8367C_RMA_CTRL0D_DISCARD_STORM_FILTER_OFFSET    6
+#define    RTL8367C_RMA_CTRL0D_DISCARD_STORM_FILTER_MASK    0x40
+#define    RTL8367C_RMA_CTRL0D_KEEP_FORMAT_OFFSET    2
+#define    RTL8367C_RMA_CTRL0D_KEEP_FORMAT_MASK    0x4
+#define    RTL8367C_RMA_CTRL0D_VLAN_LEAKY_OFFSET    1
+#define    RTL8367C_RMA_CTRL0D_VLAN_LEAKY_MASK    0x2
+#define    RTL8367C_RMA_CTRL0D_PORTISO_LEAKY_OFFSET    0
+#define    RTL8367C_RMA_CTRL0D_PORTISO_LEAKY_MASK    0x1
+
+#define    RTL8367C_REG_RMA_CTRL0E    0x080e
+#define    RTL8367C_RMA_CTRL0E_OPERATION_OFFSET    7
+#define    RTL8367C_RMA_CTRL0E_OPERATION_MASK    0x180
+#define    RTL8367C_RMA_CTRL0E_DISCARD_STORM_FILTER_OFFSET    6
+#define    RTL8367C_RMA_CTRL0E_DISCARD_STORM_FILTER_MASK    0x40
+#define    RTL8367C_RMA_CTRL0E_KEEP_FORMAT_OFFSET    2
+#define    RTL8367C_RMA_CTRL0E_KEEP_FORMAT_MASK    0x4
+#define    RTL8367C_RMA_CTRL0E_VLAN_LEAKY_OFFSET    1
+#define    RTL8367C_RMA_CTRL0E_VLAN_LEAKY_MASK    0x2
+#define    RTL8367C_RMA_CTRL0E_PORTISO_LEAKY_OFFSET    0
+#define    RTL8367C_RMA_CTRL0E_PORTISO_LEAKY_MASK    0x1
+
+#define    RTL8367C_REG_RMA_CTRL10    0x0810
+#define    RTL8367C_RMA_CTRL10_OPERATION_OFFSET    7
+#define    RTL8367C_RMA_CTRL10_OPERATION_MASK    0x180
+#define    RTL8367C_RMA_CTRL10_DISCARD_STORM_FILTER_OFFSET    6
+#define    RTL8367C_RMA_CTRL10_DISCARD_STORM_FILTER_MASK    0x40
+#define    RTL8367C_RMA_CTRL10_KEEP_FORMAT_OFFSET    2
+#define    RTL8367C_RMA_CTRL10_KEEP_FORMAT_MASK    0x4
+#define    RTL8367C_RMA_CTRL10_VLAN_LEAKY_OFFSET    1
+#define    RTL8367C_RMA_CTRL10_VLAN_LEAKY_MASK    0x2
+#define    RTL8367C_RMA_CTRL10_PORTISO_LEAKY_OFFSET    0
+#define    RTL8367C_RMA_CTRL10_PORTISO_LEAKY_MASK    0x1
+
+#define    RTL8367C_REG_RMA_CTRL11    0x0811
+#define    RTL8367C_RMA_CTRL11_OPERATION_OFFSET    7
+#define    RTL8367C_RMA_CTRL11_OPERATION_MASK    0x180
+#define    RTL8367C_RMA_CTRL11_DISCARD_STORM_FILTER_OFFSET    6
+#define    RTL8367C_RMA_CTRL11_DISCARD_STORM_FILTER_MASK    0x40
+#define    RTL8367C_RMA_CTRL11_KEEP_FORMAT_OFFSET    2
+#define    RTL8367C_RMA_CTRL11_KEEP_FORMAT_MASK    0x4
+#define    RTL8367C_RMA_CTRL11_VLAN_LEAKY_OFFSET    1
+#define    RTL8367C_RMA_CTRL11_VLAN_LEAKY_MASK    0x2
+#define    RTL8367C_RMA_CTRL11_PORTISO_LEAKY_OFFSET    0
+#define    RTL8367C_RMA_CTRL11_PORTISO_LEAKY_MASK    0x1
+
+#define    RTL8367C_REG_RMA_CTRL12    0x0812
+#define    RTL8367C_RMA_CTRL12_OPERATION_OFFSET    7
+#define    RTL8367C_RMA_CTRL12_OPERATION_MASK    0x180
+#define    RTL8367C_RMA_CTRL12_DISCARD_STORM_FILTER_OFFSET    6
+#define    RTL8367C_RMA_CTRL12_DISCARD_STORM_FILTER_MASK    0x40
+#define    RTL8367C_RMA_CTRL12_KEEP_FORMAT_OFFSET    2
+#define    RTL8367C_RMA_CTRL12_KEEP_FORMAT_MASK    0x4
+#define    RTL8367C_RMA_CTRL12_VLAN_LEAKY_OFFSET    1
+#define    RTL8367C_RMA_CTRL12_VLAN_LEAKY_MASK    0x2
+#define    RTL8367C_RMA_CTRL12_PORTISO_LEAKY_OFFSET    0
+#define    RTL8367C_RMA_CTRL12_PORTISO_LEAKY_MASK    0x1
+
+#define    RTL8367C_REG_RMA_CTRL13    0x0813
+#define    RTL8367C_RMA_CTRL13_OPERATION_OFFSET    7
+#define    RTL8367C_RMA_CTRL13_OPERATION_MASK    0x180
+#define    RTL8367C_RMA_CTRL13_DISCARD_STORM_FILTER_OFFSET    6
+#define    RTL8367C_RMA_CTRL13_DISCARD_STORM_FILTER_MASK    0x40
+#define    RTL8367C_RMA_CTRL13_KEEP_FORMAT_OFFSET    2
+#define    RTL8367C_RMA_CTRL13_KEEP_FORMAT_MASK    0x4
+#define    RTL8367C_RMA_CTRL13_VLAN_LEAKY_OFFSET    1
+#define    RTL8367C_RMA_CTRL13_VLAN_LEAKY_MASK    0x2
+#define    RTL8367C_RMA_CTRL13_PORTISO_LEAKY_OFFSET    0
+#define    RTL8367C_RMA_CTRL13_PORTISO_LEAKY_MASK    0x1
+
+#define    RTL8367C_REG_RMA_CTRL18    0x0818
+#define    RTL8367C_RMA_CTRL18_OPERATION_OFFSET    7
+#define    RTL8367C_RMA_CTRL18_OPERATION_MASK    0x180
+#define    RTL8367C_RMA_CTRL18_DISCARD_STORM_FILTER_OFFSET    6
+#define    RTL8367C_RMA_CTRL18_DISCARD_STORM_FILTER_MASK    0x40
+#define    RTL8367C_RMA_CTRL18_KEEP_FORMAT_OFFSET    2
+#define    RTL8367C_RMA_CTRL18_KEEP_FORMAT_MASK    0x4
+#define    RTL8367C_RMA_CTRL18_VLAN_LEAKY_OFFSET    1
+#define    RTL8367C_RMA_CTRL18_VLAN_LEAKY_MASK    0x2
+#define    RTL8367C_RMA_CTRL18_PORTISO_LEAKY_OFFSET    0
+#define    RTL8367C_RMA_CTRL18_PORTISO_LEAKY_MASK    0x1
+
+#define    RTL8367C_REG_RMA_CTRL1A    0x081a
+#define    RTL8367C_RMA_CTRL1A_OPERATION_OFFSET    7
+#define    RTL8367C_RMA_CTRL1A_OPERATION_MASK    0x180
+#define    RTL8367C_RMA_CTRL1A_DISCARD_STORM_FILTER_OFFSET    6
+#define    RTL8367C_RMA_CTRL1A_DISCARD_STORM_FILTER_MASK    0x40
+#define    RTL8367C_RMA_CTRL1A_KEEP_FORMAT_OFFSET    2
+#define    RTL8367C_RMA_CTRL1A_KEEP_FORMAT_MASK    0x4
+#define    RTL8367C_RMA_CTRL1A_VLAN_LEAKY_OFFSET    1
+#define    RTL8367C_RMA_CTRL1A_VLAN_LEAKY_MASK    0x2
+#define    RTL8367C_RMA_CTRL1A_PORTISO_LEAKY_OFFSET    0
+#define    RTL8367C_RMA_CTRL1A_PORTISO_LEAKY_MASK    0x1
+
+#define    RTL8367C_REG_RMA_CTRL20    0x0820
+#define    RTL8367C_RMA_CTRL20_OPERATION_OFFSET    7
+#define    RTL8367C_RMA_CTRL20_OPERATION_MASK    0x180
+#define    RTL8367C_RMA_CTRL20_DISCARD_STORM_FILTER_OFFSET    6
+#define    RTL8367C_RMA_CTRL20_DISCARD_STORM_FILTER_MASK    0x40
+#define    RTL8367C_RMA_CTRL20_KEEP_FORMAT_OFFSET    2
+#define    RTL8367C_RMA_CTRL20_KEEP_FORMAT_MASK    0x4
+#define    RTL8367C_RMA_CTRL20_VLAN_LEAKY_OFFSET    1
+#define    RTL8367C_RMA_CTRL20_VLAN_LEAKY_MASK    0x2
+#define    RTL8367C_RMA_CTRL20_PORTISO_LEAKY_OFFSET    0
+#define    RTL8367C_RMA_CTRL20_PORTISO_LEAKY_MASK    0x1
+
+#define    RTL8367C_REG_RMA_CTRL21    0x0821
+#define    RTL8367C_RMA_CTRL21_OPERATION_OFFSET    7
+#define    RTL8367C_RMA_CTRL21_OPERATION_MASK    0x180
+#define    RTL8367C_RMA_CTRL21_DISCARD_STORM_FILTER_OFFSET    6
+#define    RTL8367C_RMA_CTRL21_DISCARD_STORM_FILTER_MASK    0x40
+#define    RTL8367C_RMA_CTRL21_KEEP_FORMAT_OFFSET    2
+#define    RTL8367C_RMA_CTRL21_KEEP_FORMAT_MASK    0x4
+#define    RTL8367C_RMA_CTRL21_VLAN_LEAKY_OFFSET    1
+#define    RTL8367C_RMA_CTRL21_VLAN_LEAKY_MASK    0x2
+#define    RTL8367C_RMA_CTRL21_PORTISO_LEAKY_OFFSET    0
+#define    RTL8367C_RMA_CTRL21_PORTISO_LEAKY_MASK    0x1
+
+#define    RTL8367C_REG_RMA_CTRL22    0x0822
+#define    RTL8367C_RMA_CTRL22_OPERATION_OFFSET    7
+#define    RTL8367C_RMA_CTRL22_OPERATION_MASK    0x180
+#define    RTL8367C_RMA_CTRL22_DISCARD_STORM_FILTER_OFFSET    6
+#define    RTL8367C_RMA_CTRL22_DISCARD_STORM_FILTER_MASK    0x40
+#define    RTL8367C_RMA_CTRL22_KEEP_FORMAT_OFFSET    2
+#define    RTL8367C_RMA_CTRL22_KEEP_FORMAT_MASK    0x4
+#define    RTL8367C_RMA_CTRL22_VLAN_LEAKY_OFFSET    1
+#define    RTL8367C_RMA_CTRL22_VLAN_LEAKY_MASK    0x2
+#define    RTL8367C_RMA_CTRL22_PORTISO_LEAKY_OFFSET    0
+#define    RTL8367C_RMA_CTRL22_PORTISO_LEAKY_MASK    0x1
+
+#define    RTL8367C_REG_RMA_CTRL_CDP    0x0830
+#define    RTL8367C_RMA_CTRL_CDP_OPERATION_OFFSET    7
+#define    RTL8367C_RMA_CTRL_CDP_OPERATION_MASK    0x180
+#define    RTL8367C_RMA_CTRL_CDP_DISCARD_STORM_FILTER_OFFSET    6
+#define    RTL8367C_RMA_CTRL_CDP_DISCARD_STORM_FILTER_MASK    0x40
+#define    RTL8367C_RMA_CTRL_CDP_KEEP_FORMAT_OFFSET    2
+#define    RTL8367C_RMA_CTRL_CDP_KEEP_FORMAT_MASK    0x4
+#define    RTL8367C_RMA_CTRL_CDP_VLAN_LEAKY_OFFSET    1
+#define    RTL8367C_RMA_CTRL_CDP_VLAN_LEAKY_MASK    0x2
+#define    RTL8367C_RMA_CTRL_CDP_PORTISO_LEAKY_OFFSET    0
+#define    RTL8367C_RMA_CTRL_CDP_PORTISO_LEAKY_MASK    0x1
+
+#define    RTL8367C_REG_RMA_CTRL_CSSTP    0x0831
+#define    RTL8367C_RMA_CTRL_CSSTP_OPERATION_OFFSET    7
+#define    RTL8367C_RMA_CTRL_CSSTP_OPERATION_MASK    0x180
+#define    RTL8367C_RMA_CTRL_CSSTP_DISCARD_STORM_FILTER_OFFSET    6
+#define    RTL8367C_RMA_CTRL_CSSTP_DISCARD_STORM_FILTER_MASK    0x40
+#define    RTL8367C_RMA_CTRL_CSSTP_KEEP_FORMAT_OFFSET    2
+#define    RTL8367C_RMA_CTRL_CSSTP_KEEP_FORMAT_MASK    0x4
+#define    RTL8367C_RMA_CTRL_CSSTP_VLAN_LEAKY_OFFSET    1
+#define    RTL8367C_RMA_CTRL_CSSTP_VLAN_LEAKY_MASK    0x2
+#define    RTL8367C_RMA_CTRL_CSSTP_PORTISO_LEAKY_OFFSET    0
+#define    RTL8367C_RMA_CTRL_CSSTP_PORTISO_LEAKY_MASK    0x1
+
+#define    RTL8367C_REG_RMA_CTRL_LLDP    0x0832
+#define    RTL8367C_RMA_CTRL_LLDP_OPERATION_OFFSET    7
+#define    RTL8367C_RMA_CTRL_LLDP_OPERATION_MASK    0x180
+#define    RTL8367C_RMA_CTRL_LLDP_DISCARD_STORM_FILTER_OFFSET    6
+#define    RTL8367C_RMA_CTRL_LLDP_DISCARD_STORM_FILTER_MASK    0x40
+#define    RTL8367C_RMA_CTRL_LLDP_KEEP_FORMAT_OFFSET    2
+#define    RTL8367C_RMA_CTRL_LLDP_KEEP_FORMAT_MASK    0x4
+#define    RTL8367C_RMA_CTRL_LLDP_VLAN_LEAKY_OFFSET    1
+#define    RTL8367C_RMA_CTRL_LLDP_VLAN_LEAKY_MASK    0x2
+#define    RTL8367C_RMA_CTRL_LLDP_PORTISO_LEAKY_OFFSET    0
+#define    RTL8367C_RMA_CTRL_LLDP_PORTISO_LEAKY_MASK    0x1
+
+#define    RTL8367C_REG_RMA_LLDP_EN    0x0833
+#define    RTL8367C_RMA_LLDP_EN_OFFSET    0
+#define    RTL8367C_RMA_LLDP_EN_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_PORTBASED_PRIORITY_CTRL0    0x0851
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT3_PRIORITY_OFFSET    12
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT3_PRIORITY_MASK    0x7000
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT2_PRIORITY_OFFSET    8
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT2_PRIORITY_MASK    0x700
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT1_PRIORITY_OFFSET    4
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT1_PRIORITY_MASK    0x70
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT0_PRIORITY_OFFSET    0
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT0_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_VLAN_PORTBASED_PRIORITY_CTRL1    0x0852
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT7_PRIORITY_OFFSET    12
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT7_PRIORITY_MASK    0x7000
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT6_PRIORITY_OFFSET    8
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT6_PRIORITY_MASK    0x700
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT5_PRIORITY_OFFSET    4
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT5_PRIORITY_MASK    0x70
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT4_PRIORITY_OFFSET    0
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT4_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_VLAN_PORTBASED_PRIORITY_CTRL2    0x0853
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL2_PORT10_PRIORITY_OFFSET    8
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL2_PORT10_PRIORITY_MASK    0x700
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL2_PORT9_PRIORITY_OFFSET    4
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL2_PORT9_PRIORITY_MASK    0x70
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL2_PORT8_PRIORITY_OFFSET    0
+#define    RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL2_PORT8_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM0_CTRL0    0x0855
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT3_PRIORITY_OFFSET    12
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT3_PRIORITY_MASK    0x7000
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT2_PRIORITY_OFFSET    8
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT2_PRIORITY_MASK    0x700
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT1_PRIORITY_OFFSET    4
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT1_PRIORITY_MASK    0x70
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT0_PRIORITY_OFFSET    0
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT0_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM0_CTRL1    0x0856
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT7_PRIORITY_OFFSET    12
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT7_PRIORITY_MASK    0x7000
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT6_PRIORITY_OFFSET    8
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT6_PRIORITY_MASK    0x700
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT5_PRIORITY_OFFSET    4
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT5_PRIORITY_MASK    0x70
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT4_PRIORITY_OFFSET    0
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT4_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM0_CTRL2    0x0857
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL2_PORT10_PRIORITY_OFFSET    8
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL2_PORT10_PRIORITY_MASK    0x700
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL2_PORT9_PRIORITY_OFFSET    4
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL2_PORT9_PRIORITY_MASK    0x70
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL2_PORT8_PRIORITY_OFFSET    0
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL2_PORT8_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM1_CTRL0    0x0859
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT3_PRIORITY_OFFSET    12
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT3_PRIORITY_MASK    0x7000
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT2_PRIORITY_OFFSET    8
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT2_PRIORITY_MASK    0x700
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT1_PRIORITY_OFFSET    4
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT1_PRIORITY_MASK    0x70
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT0_PRIORITY_OFFSET    0
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT0_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM1_CTRL1    0x085a
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT7_PRIORITY_OFFSET    12
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT7_PRIORITY_MASK    0x7000
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT6_PRIORITY_OFFSET    8
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT6_PRIORITY_MASK    0x700
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT5_PRIORITY_OFFSET    4
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT5_PRIORITY_MASK    0x70
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT4_PRIORITY_OFFSET    0
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT4_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM1_CTRL2    0x085b
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL2_PORT10_PRIORITY_OFFSET    8
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL2_PORT10_PRIORITY_MASK    0x700
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL2_PORT9_PRIORITY_OFFSET    4
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL2_PORT9_PRIORITY_MASK    0x70
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL2_PORT8_PRIORITY_OFFSET    0
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL2_PORT8_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM2_CTRL0    0x085d
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT3_PRIORITY_OFFSET    12
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT3_PRIORITY_MASK    0x7000
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT2_PRIORITY_OFFSET    8
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT2_PRIORITY_MASK    0x700
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT1_PRIORITY_OFFSET    4
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT1_PRIORITY_MASK    0x70
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT0_PRIORITY_OFFSET    0
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT0_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM2_CTRL1    0x085e
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT7_PRIORITY_OFFSET    12
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT7_PRIORITY_MASK    0x7000
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT6_PRIORITY_OFFSET    8
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT6_PRIORITY_MASK    0x700
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT5_PRIORITY_OFFSET    4
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT5_PRIORITY_MASK    0x70
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT4_PRIORITY_OFFSET    0
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT4_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM2_CTRL2    0x085f
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL2_PORT10_PRIORITY_OFFSET    8
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL2_PORT10_PRIORITY_MASK    0x700
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL2_PORT9_PRIORITY_OFFSET    4
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL2_PORT9_PRIORITY_MASK    0x70
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL2_PORT8_PRIORITY_OFFSET    0
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL2_PORT8_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM3_CTRL0    0x0861
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT3_PRIORITY_OFFSET    12
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT3_PRIORITY_MASK    0x7000
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT2_PRIORITY_OFFSET    8
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT2_PRIORITY_MASK    0x700
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT1_PRIORITY_OFFSET    4
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT1_PRIORITY_MASK    0x70
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT0_PRIORITY_OFFSET    0
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT0_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM3_CTRL1    0x0862
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT7_PRIORITY_OFFSET    12
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT7_PRIORITY_MASK    0x7000
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT6_PRIORITY_OFFSET    8
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT6_PRIORITY_MASK    0x700
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT5_PRIORITY_OFFSET    4
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT5_PRIORITY_MASK    0x70
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT4_PRIORITY_OFFSET    0
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT4_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM3_CTRL2    0x0863
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL2_PORT10_PRIORITY_OFFSET    8
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL2_PORT10_PRIORITY_MASK    0x700
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL2_PORT9_PRIORITY_OFFSET    4
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL2_PORT9_PRIORITY_MASK    0x70
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL2_PORT8_PRIORITY_OFFSET    0
+#define    RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL2_PORT8_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_QOS_1Q_PRIORITY_REMAPPING_CTRL0    0x0865
+#define    RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY3_OFFSET    12
+#define    RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY3_MASK    0x7000
+#define    RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY2_OFFSET    8
+#define    RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY2_MASK    0x700
+#define    RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY1_OFFSET    4
+#define    RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY1_MASK    0x70
+#define    RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY0_OFFSET    0
+#define    RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY0_MASK    0x7
+
+#define    RTL8367C_REG_QOS_1Q_PRIORITY_REMAPPING_CTRL1    0x0866
+#define    RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY7_OFFSET    12
+#define    RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY7_MASK    0x7000
+#define    RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY6_OFFSET    8
+#define    RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY6_MASK    0x700
+#define    RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY5_OFFSET    4
+#define    RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY5_MASK    0x70
+#define    RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY4_OFFSET    0
+#define    RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY4_MASK    0x7
+
+#define    RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL0    0x0867
+#define    RTL8367C_DSCP3_PRIORITY_OFFSET    12
+#define    RTL8367C_DSCP3_PRIORITY_MASK    0x7000
+#define    RTL8367C_DSCP2_PRIORITY_OFFSET    8
+#define    RTL8367C_DSCP2_PRIORITY_MASK    0x700
+#define    RTL8367C_DSCP1_PRIORITY_OFFSET    4
+#define    RTL8367C_DSCP1_PRIORITY_MASK    0x70
+#define    RTL8367C_DSCP0_PRIORITY_OFFSET    0
+#define    RTL8367C_DSCP0_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL1    0x0868
+#define    RTL8367C_DSCP7_PRIORITY_OFFSET    12
+#define    RTL8367C_DSCP7_PRIORITY_MASK    0x7000
+#define    RTL8367C_DSCP6_PRIORITY_OFFSET    8
+#define    RTL8367C_DSCP6_PRIORITY_MASK    0x700
+#define    RTL8367C_DSCP5_PRIORITY_OFFSET    4
+#define    RTL8367C_DSCP5_PRIORITY_MASK    0x70
+#define    RTL8367C_DSCP4_PRIORITY_OFFSET    0
+#define    RTL8367C_DSCP4_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL2    0x0869
+#define    RTL8367C_DSCP11_PRIORITY_OFFSET    12
+#define    RTL8367C_DSCP11_PRIORITY_MASK    0x7000
+#define    RTL8367C_DSCP10_PRIORITY_OFFSET    8
+#define    RTL8367C_DSCP10_PRIORITY_MASK    0x700
+#define    RTL8367C_DSCP9_PRIORITY_OFFSET    4
+#define    RTL8367C_DSCP9_PRIORITY_MASK    0x70
+#define    RTL8367C_DSCP8_PRIORITY_OFFSET    0
+#define    RTL8367C_DSCP8_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL3    0x086a
+#define    RTL8367C_DSCP15_PRIORITY_OFFSET    12
+#define    RTL8367C_DSCP15_PRIORITY_MASK    0x7000
+#define    RTL8367C_DSCP14_PRIORITY_OFFSET    8
+#define    RTL8367C_DSCP14_PRIORITY_MASK    0x700
+#define    RTL8367C_DSCP13_PRIORITY_OFFSET    4
+#define    RTL8367C_DSCP13_PRIORITY_MASK    0x70
+#define    RTL8367C_DSCP12_PRIORITY_OFFSET    0
+#define    RTL8367C_DSCP12_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL4    0x086b
+#define    RTL8367C_DSCP19_PRIORITY_OFFSET    12
+#define    RTL8367C_DSCP19_PRIORITY_MASK    0x7000
+#define    RTL8367C_DSCP18_PRIORITY_OFFSET    8
+#define    RTL8367C_DSCP18_PRIORITY_MASK    0x700
+#define    RTL8367C_DSCP17_PRIORITY_OFFSET    4
+#define    RTL8367C_DSCP17_PRIORITY_MASK    0x70
+#define    RTL8367C_DSCP16_PRIORITY_OFFSET    0
+#define    RTL8367C_DSCP16_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL5    0x086c
+#define    RTL8367C_DSCP23_PRIORITY_OFFSET    12
+#define    RTL8367C_DSCP23_PRIORITY_MASK    0x7000
+#define    RTL8367C_DSCP22_PRIORITY_OFFSET    8
+#define    RTL8367C_DSCP22_PRIORITY_MASK    0x700
+#define    RTL8367C_DSCP21_PRIORITY_OFFSET    4
+#define    RTL8367C_DSCP21_PRIORITY_MASK    0x70
+#define    RTL8367C_DSCP20_PRIORITY_OFFSET    0
+#define    RTL8367C_DSCP20_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL6    0x086d
+#define    RTL8367C_DSCP27_PRIORITY_OFFSET    12
+#define    RTL8367C_DSCP27_PRIORITY_MASK    0x7000
+#define    RTL8367C_DSCP26_PRIORITY_OFFSET    8
+#define    RTL8367C_DSCP26_PRIORITY_MASK    0x700
+#define    RTL8367C_DSCP25_PRIORITY_OFFSET    4
+#define    RTL8367C_DSCP25_PRIORITY_MASK    0x70
+#define    RTL8367C_DSCP24_PRIORITY_OFFSET    0
+#define    RTL8367C_DSCP24_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL7    0x086e
+#define    RTL8367C_DSCP31_PRIORITY_OFFSET    12
+#define    RTL8367C_DSCP31_PRIORITY_MASK    0x7000
+#define    RTL8367C_DSCP30_PRIORITY_OFFSET    8
+#define    RTL8367C_DSCP30_PRIORITY_MASK    0x700
+#define    RTL8367C_DSCP29_PRIORITY_OFFSET    4
+#define    RTL8367C_DSCP29_PRIORITY_MASK    0x70
+#define    RTL8367C_DSCP28_PRIORITY_OFFSET    0
+#define    RTL8367C_DSCP28_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL8    0x086f
+#define    RTL8367C_DSCP35_PRIORITY_OFFSET    12
+#define    RTL8367C_DSCP35_PRIORITY_MASK    0x7000
+#define    RTL8367C_DSCP34_PRIORITY_OFFSET    8
+#define    RTL8367C_DSCP34_PRIORITY_MASK    0x700
+#define    RTL8367C_DSCP33_PRIORITY_OFFSET    4
+#define    RTL8367C_DSCP33_PRIORITY_MASK    0x70
+#define    RTL8367C_DSCP32_PRIORITY_OFFSET    0
+#define    RTL8367C_DSCP32_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL9    0x0870
+#define    RTL8367C_DSCP39_PRIORITY_OFFSET    12
+#define    RTL8367C_DSCP39_PRIORITY_MASK    0x7000
+#define    RTL8367C_DSCP38_PRIORITY_OFFSET    8
+#define    RTL8367C_DSCP38_PRIORITY_MASK    0x700
+#define    RTL8367C_DSCP37_PRIORITY_OFFSET    4
+#define    RTL8367C_DSCP37_PRIORITY_MASK    0x70
+#define    RTL8367C_DSCP36_PRIORITY_OFFSET    0
+#define    RTL8367C_DSCP36_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL10    0x0871
+#define    RTL8367C_DSCP43_PRIORITY_OFFSET    12
+#define    RTL8367C_DSCP43_PRIORITY_MASK    0x7000
+#define    RTL8367C_DSCP42_PRIORITY_OFFSET    8
+#define    RTL8367C_DSCP42_PRIORITY_MASK    0x700
+#define    RTL8367C_DSCP41_PRIORITY_OFFSET    4
+#define    RTL8367C_DSCP41_PRIORITY_MASK    0x70
+#define    RTL8367C_DSCP40_PRIORITY_OFFSET    0
+#define    RTL8367C_DSCP40_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL11    0x0872
+#define    RTL8367C_DSCP47_PRIORITY_OFFSET    12
+#define    RTL8367C_DSCP47_PRIORITY_MASK    0x7000
+#define    RTL8367C_DSCP46_PRIORITY_OFFSET    8
+#define    RTL8367C_DSCP46_PRIORITY_MASK    0x700
+#define    RTL8367C_DSCP45_PRIORITY_OFFSET    4
+#define    RTL8367C_DSCP45_PRIORITY_MASK    0x70
+#define    RTL8367C_DSCP44_PRIORITY_OFFSET    0
+#define    RTL8367C_DSCP44_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL12    0x0873
+#define    RTL8367C_DSCP51_PRIORITY_OFFSET    12
+#define    RTL8367C_DSCP51_PRIORITY_MASK    0x7000
+#define    RTL8367C_DSCP50_PRIORITY_OFFSET    8
+#define    RTL8367C_DSCP50_PRIORITY_MASK    0x700
+#define    RTL8367C_DSCP49_PRIORITY_OFFSET    4
+#define    RTL8367C_DSCP49_PRIORITY_MASK    0x70
+#define    RTL8367C_DSCP48_PRIORITY_OFFSET    0
+#define    RTL8367C_DSCP48_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL13    0x0874
+#define    RTL8367C_DSCP55_PRIORITY_OFFSET    12
+#define    RTL8367C_DSCP55_PRIORITY_MASK    0x7000
+#define    RTL8367C_DSCP54_PRIORITY_OFFSET    8
+#define    RTL8367C_DSCP54_PRIORITY_MASK    0x700
+#define    RTL8367C_DSCP53_PRIORITY_OFFSET    4
+#define    RTL8367C_DSCP53_PRIORITY_MASK    0x70
+#define    RTL8367C_DSCP52_PRIORITY_OFFSET    0
+#define    RTL8367C_DSCP52_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL14    0x0875
+#define    RTL8367C_DSCP59_PRIORITY_OFFSET    12
+#define    RTL8367C_DSCP59_PRIORITY_MASK    0x7000
+#define    RTL8367C_DSCP58_PRIORITY_OFFSET    8
+#define    RTL8367C_DSCP58_PRIORITY_MASK    0x700
+#define    RTL8367C_DSCP57_PRIORITY_OFFSET    4
+#define    RTL8367C_DSCP57_PRIORITY_MASK    0x70
+#define    RTL8367C_DSCP56_PRIORITY_OFFSET    0
+#define    RTL8367C_DSCP56_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL15    0x0876
+#define    RTL8367C_DSCP63_PRIORITY_OFFSET    12
+#define    RTL8367C_DSCP63_PRIORITY_MASK    0x7000
+#define    RTL8367C_DSCP62_PRIORITY_OFFSET    8
+#define    RTL8367C_DSCP62_PRIORITY_MASK    0x700
+#define    RTL8367C_DSCP61_PRIORITY_OFFSET    4
+#define    RTL8367C_DSCP61_PRIORITY_MASK    0x70
+#define    RTL8367C_DSCP60_PRIORITY_OFFSET    0
+#define    RTL8367C_DSCP60_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_QOS_PORTBASED_PRIORITY_CTRL0    0x0877
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT3_PRIORITY_OFFSET    12
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT3_PRIORITY_MASK    0x7000
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT2_PRIORITY_OFFSET    8
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT2_PRIORITY_MASK    0x700
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT1_PRIORITY_OFFSET    4
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT1_PRIORITY_MASK    0x70
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT0_PRIORITY_OFFSET    0
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT0_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_QOS_PORTBASED_PRIORITY_CTRL1    0x0878
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT7_PRIORITY_OFFSET    12
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT7_PRIORITY_MASK    0x7000
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT6_PRIORITY_OFFSET    8
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT6_PRIORITY_MASK    0x700
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT5_PRIORITY_OFFSET    4
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT5_PRIORITY_MASK    0x70
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT4_PRIORITY_OFFSET    0
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT4_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_DUMMY0879    0x0879
+#define    RTL8367C_DUMMY0879_OFFSET    0
+#define    RTL8367C_DUMMY0879_MASK    0x1
+
+#define    RTL8367C_REG_QOS_PORTBASED_PRIORITY_CTRL2    0x087a
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL2_PORT10_PRIORITY_OFFSET    8
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL2_PORT10_PRIORITY_MASK    0x700
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL2_PORT9_PRIORITY_OFFSET    4
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL2_PORT9_PRIORITY_MASK    0x70
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL2_PORT8_PRIORITY_OFFSET    0
+#define    RTL8367C_QOS_PORTBASED_PRIORITY_CTRL2_PORT8_PRIORITY_MASK    0x7
+
+#define    RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION_CTRL0    0x087b
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL0_QOS_ACL_WEIGHT_OFFSET    8
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL0_QOS_ACL_WEIGHT_MASK    0xFF00
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL0_QOS_PORT_WEIGHT_OFFSET    0
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL0_QOS_PORT_WEIGHT_MASK    0xFF
+
+#define    RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION_CTRL1    0x087c
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL1_QOS_DOT1Q_WEIGHT_OFFSET    8
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL1_QOS_DOT1Q_WEIGHT_MASK    0xFF00
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL1_QOS_DSCP_WEIGHT_OFFSET    0
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL1_QOS_DSCP_WEIGHT_MASK    0xFF
+
+#define    RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION_CTRL2    0x087d
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL2_QOS_CVLAN_WEIGHT_OFFSET    8
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL2_QOS_CVLAN_WEIGHT_MASK    0xFF00
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL2_QOS_SVLAN_WEIGHT_OFFSET    0
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL2_QOS_SVLAN_WEIGHT_MASK    0xFF
+
+#define    RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION_CTRL3    0x087e
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL3_QOS_SA_WEIGHT_OFFSET    8
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL3_QOS_SA_WEIGHT_MASK    0xFF00
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL3_QOS_LUTFWD_WEIGHT_OFFSET    0
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL3_QOS_LUTFWD_WEIGHT_MASK    0xFF
+
+#define    RTL8367C_REG_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0    0x087f
+#define    RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY3_OFFSET    12
+#define    RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY3_MASK    0x7000
+#define    RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY2_OFFSET    8
+#define    RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY2_MASK    0x700
+#define    RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY1_OFFSET    4
+#define    RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY1_MASK    0x70
+#define    RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY0_OFFSET    0
+#define    RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY0_MASK    0x7
+
+#define    RTL8367C_REG_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1    0x0880
+#define    RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY7_OFFSET    12
+#define    RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY7_MASK    0x7000
+#define    RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY6_OFFSET    8
+#define    RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY6_MASK    0x700
+#define    RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY5_OFFSET    4
+#define    RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY5_MASK    0x70
+#define    RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY4_OFFSET    0
+#define    RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY4_MASK    0x7
+
+#define    RTL8367C_REG_QOS_TRAP_PRIORITY0    0x0881
+#define    RTL8367C_UNKNOWN_MC_PRIORTY_OFFSET    12
+#define    RTL8367C_UNKNOWN_MC_PRIORTY_MASK    0x7000
+#define    RTL8367C_SVLAN_PRIOIRTY_OFFSET    8
+#define    RTL8367C_SVLAN_PRIOIRTY_MASK    0x700
+#define    RTL8367C_OAM_PRIOIRTY_OFFSET    4
+#define    RTL8367C_OAM_PRIOIRTY_MASK    0x70
+#define    RTL8367C_DOT1X_PRIORTY_OFFSET    0
+#define    RTL8367C_DOT1X_PRIORTY_MASK    0x7
+
+#define    RTL8367C_REG_QOS_TRAP_PRIORITY1    0x0882
+#define    RTL8367C_DW8051_TRAP_PRI_OFFSET    4
+#define    RTL8367C_DW8051_TRAP_PRI_MASK    0x70
+#define    RTL8367C_EEELLDP_TRAP_PRI_OFFSET    0
+#define    RTL8367C_EEELLDP_TRAP_PRI_MASK    0x7
+
+#define    RTL8367C_REG_MAX_LENGTH_CFG    0x0883
+#define    RTL8367C_MAX_LENGTH_GIGA_OFFSET    8
+#define    RTL8367C_MAX_LENGTH_GIGA_MASK    0xFF00
+#define    RTL8367C_MAX_LENGTH_10_100M_OFFSET    0
+#define    RTL8367C_MAX_LENGTH_10_100M_MASK    0xFF
+
+#define    RTL8367C_REG_MAX_LEN_RX_TX    0x0884
+#define    RTL8367C_MAX_LEN_RX_TX_OFFSET    0
+#define    RTL8367C_MAX_LEN_RX_TX_MASK    0x3
+
+#define    RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION2_CTRL0    0x0885
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL0_QOS_ACL_WEIGHT_OFFSET    8
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL0_QOS_ACL_WEIGHT_MASK    0xFF00
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL0_QOS_PORT_WEIGHT_OFFSET    0
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL0_QOS_PORT_WEIGHT_MASK    0xFF
+
+#define    RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION2_CTRL1    0x0886
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL1_QOS_DOT1Q_WEIGHT_OFFSET    8
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL1_QOS_DOT1Q_WEIGHT_MASK    0xFF00
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL1_QOS_DSCP_WEIGHT_OFFSET    0
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL1_QOS_DSCP_WEIGHT_MASK    0xFF
+
+#define    RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION2_CTRL2    0x0887
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL2_QOS_CVLAN_WEIGHT_OFFSET    8
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL2_QOS_CVLAN_WEIGHT_MASK    0xFF00
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL2_QOS_SVLAN_WEIGHT_OFFSET    0
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL2_QOS_SVLAN_WEIGHT_MASK    0xFF
+
+#define    RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION2_CTRL3    0x0888
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL3_QOS_SA_WEIGHT_OFFSET    8
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL3_QOS_SA_WEIGHT_MASK    0xFF00
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL3_QOS_LUTFWD_WEIGHT_OFFSET    0
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL3_QOS_LUTFWD_WEIGHT_MASK    0xFF
+
+#define    RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION_IDX    0x0889
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_IDX_OFFSET    0
+#define    RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_IDX_MASK    0x7FF
+
+#define    RTL8367C_REG_MAX_LENGTH_CFG_EXT    0x088a
+#define    RTL8367C_MAX_LENGTH_GIGA_EXT_OFFSET    3
+#define    RTL8367C_MAX_LENGTH_GIGA_EXT_MASK    0x38
+#define    RTL8367C_MAX_LENGTH_10_100M_EXT_OFFSET    0
+#define    RTL8367C_MAX_LENGTH_10_100M_EXT_MASK    0x7
+
+#define    RTL8367C_REG_MAX_LEN_RX_TX_CFG0    0x088c
+#define    RTL8367C_MAX_LEN_RX_TX_CFG0_OFFSET    0
+#define    RTL8367C_MAX_LEN_RX_TX_CFG0_MASK    0x3FFF
+
+#define    RTL8367C_REG_MAX_LEN_RX_TX_CFG1    0x088d
+#define    RTL8367C_MAX_LEN_RX_TX_CFG1_OFFSET    0
+#define    RTL8367C_MAX_LEN_RX_TX_CFG1_MASK    0x3FFF
+
+#define    RTL8367C_REG_UNDA_FLOODING_PMSK    0x0890
+#define    RTL8367C_UNDA_FLOODING_PMSK_OFFSET    0
+#define    RTL8367C_UNDA_FLOODING_PMSK_MASK    0x7FF
+
+#define    RTL8367C_REG_UNMCAST_FLOADING_PMSK    0x0891
+#define    RTL8367C_UNMCAST_FLOADING_PMSK_OFFSET    0
+#define    RTL8367C_UNMCAST_FLOADING_PMSK_MASK    0x7FF
+
+#define    RTL8367C_REG_BCAST_FLOADING_PMSK    0x0892
+#define    RTL8367C_BCAST_FLOADING_PMSK_OFFSET    0
+#define    RTL8367C_BCAST_FLOADING_PMSK_MASK    0x7FF
+
+#define    RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL2    0x08a0
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH7_OFFSET    14
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH7_MASK    0xC000
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH6_OFFSET    12
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH6_MASK    0x3000
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH5_OFFSET    10
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH5_MASK    0xC00
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH4_OFFSET    8
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH4_MASK    0x300
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH3_OFFSET    6
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH3_MASK    0xC0
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH2_OFFSET    4
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH2_MASK    0x30
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH1_OFFSET    2
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH1_MASK    0xC
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH0_OFFSET    0
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH0_MASK    0x3
+
+#define    RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL3    0x08a1
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH15_OFFSET    14
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH15_MASK    0xC000
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH14_OFFSET    12
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH14_MASK    0x3000
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH13_OFFSET    10
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH13_MASK    0xC00
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH12_OFFSET    8
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH12_MASK    0x300
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH11_OFFSET    6
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH11_MASK    0xC0
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH10_OFFSET    4
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH10_MASK    0x30
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH9_OFFSET    2
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH9_MASK    0xC
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH8_OFFSET    0
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH8_MASK    0x3
+
+#define    RTL8367C_REG_PORT_ISOLATION_PORT0_MASK    0x08a2
+#define    RTL8367C_PORT_ISOLATION_PORT0_MASK_OFFSET    0
+#define    RTL8367C_PORT_ISOLATION_PORT0_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_PORT_ISOLATION_PORT1_MASK    0x08a3
+#define    RTL8367C_PORT_ISOLATION_PORT1_MASK_OFFSET    0
+#define    RTL8367C_PORT_ISOLATION_PORT1_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_PORT_ISOLATION_PORT2_MASK    0x08a4
+#define    RTL8367C_PORT_ISOLATION_PORT2_MASK_OFFSET    0
+#define    RTL8367C_PORT_ISOLATION_PORT2_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_PORT_ISOLATION_PORT3_MASK    0x08a5
+#define    RTL8367C_PORT_ISOLATION_PORT3_MASK_OFFSET    0
+#define    RTL8367C_PORT_ISOLATION_PORT3_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_PORT_ISOLATION_PORT4_MASK    0x08a6
+#define    RTL8367C_PORT_ISOLATION_PORT4_MASK_OFFSET    0
+#define    RTL8367C_PORT_ISOLATION_PORT4_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_PORT_ISOLATION_PORT5_MASK    0x08a7
+#define    RTL8367C_PORT_ISOLATION_PORT5_MASK_OFFSET    0
+#define    RTL8367C_PORT_ISOLATION_PORT5_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_PORT_ISOLATION_PORT6_MASK    0x08a8
+#define    RTL8367C_PORT_ISOLATION_PORT6_MASK_OFFSET    0
+#define    RTL8367C_PORT_ISOLATION_PORT6_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_PORT_ISOLATION_PORT7_MASK    0x08a9
+#define    RTL8367C_PORT_ISOLATION_PORT7_MASK_OFFSET    0
+#define    RTL8367C_PORT_ISOLATION_PORT7_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_PORT_ISOLATION_PORT8_MASK    0x08aa
+#define    RTL8367C_PORT_ISOLATION_PORT8_MASK_OFFSET    0
+#define    RTL8367C_PORT_ISOLATION_PORT8_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_PORT_ISOLATION_PORT9_MASK    0x08ab
+#define    RTL8367C_PORT_ISOLATION_PORT9_MASK_OFFSET    0
+#define    RTL8367C_PORT_ISOLATION_PORT9_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_PORT_ISOLATION_PORT10_MASK    0x08ac
+#define    RTL8367C_PORT_ISOLATION_PORT10_MASK_OFFSET    0
+#define    RTL8367C_PORT_ISOLATION_PORT10_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_FORCE_CTRL    0x08b4
+#define    RTL8367C_FORCE_CTRL_OFFSET    0
+#define    RTL8367C_FORCE_CTRL_MASK    0x7FF
+
+#define    RTL8367C_REG_FORCE_PORT0_MASK    0x08b5
+#define    RTL8367C_FORCE_PORT0_MASK_OFFSET    0
+#define    RTL8367C_FORCE_PORT0_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_FORCE_PORT1_MASK    0x08b6
+#define    RTL8367C_FORCE_PORT1_MASK_OFFSET    0
+#define    RTL8367C_FORCE_PORT1_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_FORCE_PORT2_MASK    0x08b7
+#define    RTL8367C_FORCE_PORT2_MASK_OFFSET    0
+#define    RTL8367C_FORCE_PORT2_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_FORCE_PORT3_MASK    0x08b8
+#define    RTL8367C_FORCE_PORT3_MASK_OFFSET    0
+#define    RTL8367C_FORCE_PORT3_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_FORCE_PORT4_MASK    0x08b9
+#define    RTL8367C_FORCE_PORT4_MASK_OFFSET    0
+#define    RTL8367C_FORCE_PORT4_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_FORCE_PORT5_MASK    0x08ba
+#define    RTL8367C_FORCE_PORT5_MASK_OFFSET    0
+#define    RTL8367C_FORCE_PORT5_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_FORCE_PORT6_MASK    0x08bb
+#define    RTL8367C_FORCE_PORT6_MASK_OFFSET    0
+#define    RTL8367C_FORCE_PORT6_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_FORCE_PORT7_MASK    0x08bc
+#define    RTL8367C_FORCE_PORT7_MASK_OFFSET    0
+#define    RTL8367C_FORCE_PORT7_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_FORCE_PORT8_MASK    0x08bd
+#define    RTL8367C_FORCE_PORT8_MASK_OFFSET    0
+#define    RTL8367C_FORCE_PORT8_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_FORCE_PORT9_MASK    0x08be
+#define    RTL8367C_FORCE_PORT9_MASK_OFFSET    0
+#define    RTL8367C_FORCE_PORT9_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_FORCE_PORT10_MASK    0x08bf
+#define    RTL8367C_FORCE_PORT10_MASK_OFFSET    0
+#define    RTL8367C_FORCE_PORT10_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_SOURCE_PORT_PERMIT    0x08c5
+#define    RTL8367C_SOURCE_PORT_PERMIT_OFFSET    0
+#define    RTL8367C_SOURCE_PORT_PERMIT_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMCAST_VLAN_LEAKY    0x08c6
+#define    RTL8367C_IPMCAST_VLAN_LEAKY_OFFSET    0
+#define    RTL8367C_IPMCAST_VLAN_LEAKY_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMCAST_PORTISO_LEAKY    0x08c7
+#define    RTL8367C_IPMCAST_PORTISO_LEAKY_OFFSET    0
+#define    RTL8367C_IPMCAST_PORTISO_LEAKY_MASK    0x7FF
+
+#define    RTL8367C_REG_PORT_SECURITY_CTRL    0x08c8
+#define    RTL8367C_UNKNOWN_UNICAST_DA_BEHAVE_OFFSET    6
+#define    RTL8367C_UNKNOWN_UNICAST_DA_BEHAVE_MASK    0xC0
+#define    RTL8367C_LUT_LEARN_OVER_ACT_OFFSET    4
+#define    RTL8367C_LUT_LEARN_OVER_ACT_MASK    0x30
+#define    RTL8367C_UNMATCHED_SA_BEHAVE_OFFSET    2
+#define    RTL8367C_UNMATCHED_SA_BEHAVE_MASK    0xC
+#define    RTL8367C_UNKNOWN_SA_BEHAVE_OFFSET    0
+#define    RTL8367C_UNKNOWN_SA_BEHAVE_MASK    0x3
+
+#define    RTL8367C_REG_UNKNOWN_IPV4_MULTICAST_CTRL0    0x08c9
+#define    RTL8367C_PORT7_UNKNOWN_IP4_MCAST_OFFSET    14
+#define    RTL8367C_PORT7_UNKNOWN_IP4_MCAST_MASK    0xC000
+#define    RTL8367C_PORT6_UNKNOWN_IP4_MCAST_OFFSET    12
+#define    RTL8367C_PORT6_UNKNOWN_IP4_MCAST_MASK    0x3000
+#define    RTL8367C_PORT5_UNKNOWN_IP4_MCAST_OFFSET    10
+#define    RTL8367C_PORT5_UNKNOWN_IP4_MCAST_MASK    0xC00
+#define    RTL8367C_PORT4_UNKNOWN_IP4_MCAST_OFFSET    8
+#define    RTL8367C_PORT4_UNKNOWN_IP4_MCAST_MASK    0x300
+#define    RTL8367C_PORT3_UNKNOWN_IP4_MCAST_OFFSET    6
+#define    RTL8367C_PORT3_UNKNOWN_IP4_MCAST_MASK    0xC0
+#define    RTL8367C_PORT2_UNKNOWN_IP4_MCAST_OFFSET    4
+#define    RTL8367C_PORT2_UNKNOWN_IP4_MCAST_MASK    0x30
+#define    RTL8367C_PORT1_UNKNOWN_IP4_MCAST_OFFSET    2
+#define    RTL8367C_PORT1_UNKNOWN_IP4_MCAST_MASK    0xC
+#define    RTL8367C_PORT0_UNKNOWN_IP4_MCAST_OFFSET    0
+#define    RTL8367C_PORT0_UNKNOWN_IP4_MCAST_MASK    0x3
+
+#define    RTL8367C_REG_UNKNOWN_IPV4_MULTICAST_CTRL1    0x08ca
+#define    RTL8367C_PORT10_UNKNOWN_IP4_MCAST_OFFSET    4
+#define    RTL8367C_PORT10_UNKNOWN_IP4_MCAST_MASK    0x30
+#define    RTL8367C_PORT9_UNKNOWN_IP4_MCAST_OFFSET    2
+#define    RTL8367C_PORT9_UNKNOWN_IP4_MCAST_MASK    0xC
+#define    RTL8367C_PORT8_UNKNOWN_IP4_MCAST_OFFSET    0
+#define    RTL8367C_PORT8_UNKNOWN_IP4_MCAST_MASK    0x3
+
+#define    RTL8367C_REG_UNKNOWN_IPV6_MULTICAST_CTRL0    0x08cb
+#define    RTL8367C_PORT7_UNKNOWN_IP6_MCAST_OFFSET    14
+#define    RTL8367C_PORT7_UNKNOWN_IP6_MCAST_MASK    0xC000
+#define    RTL8367C_PORT6_UNKNOWN_IP6_MCAST_OFFSET    12
+#define    RTL8367C_PORT6_UNKNOWN_IP6_MCAST_MASK    0x3000
+#define    RTL8367C_PORT5_UNKNOWN_IP6_MCAST_OFFSET    10
+#define    RTL8367C_PORT5_UNKNOWN_IP6_MCAST_MASK    0xC00
+#define    RTL8367C_PORT4_UNKNOWN_IP6_MCAST_OFFSET    8
+#define    RTL8367C_PORT4_UNKNOWN_IP6_MCAST_MASK    0x300
+#define    RTL8367C_PORT3_UNKNOWN_IP6_MCAST_OFFSET    6
+#define    RTL8367C_PORT3_UNKNOWN_IP6_MCAST_MASK    0xC0
+#define    RTL8367C_PORT2_UNKNOWN_IP6_MCAST_OFFSET    4
+#define    RTL8367C_PORT2_UNKNOWN_IP6_MCAST_MASK    0x30
+#define    RTL8367C_PORT1_UNKNOWN_IP6_MCAST_OFFSET    2
+#define    RTL8367C_PORT1_UNKNOWN_IP6_MCAST_MASK    0xC
+#define    RTL8367C_PORT0_UNKNOWN_IP6_MCAST_OFFSET    0
+#define    RTL8367C_PORT0_UNKNOWN_IP6_MCAST_MASK    0x3
+
+#define    RTL8367C_REG_UNKNOWN_IPV6_MULTICAST_CTRL1    0x08cc
+#define    RTL8367C_PORT10_UNKNOWN_IP6_MCAST_OFFSET    4
+#define    RTL8367C_PORT10_UNKNOWN_IP6_MCAST_MASK    0x30
+#define    RTL8367C_PORT9_UNKNOWN_IP6_MCAST_OFFSET    2
+#define    RTL8367C_PORT9_UNKNOWN_IP6_MCAST_MASK    0xC
+#define    RTL8367C_PORT8_UNKNOWN_IP6_MCAST_OFFSET    0
+#define    RTL8367C_PORT8_UNKNOWN_IP6_MCAST_MASK    0x3
+
+#define    RTL8367C_REG_UNKNOWN_L2_MULTICAST_CTRL0    0x08cd
+#define    RTL8367C_PORT7_UNKNOWN_L2_MCAST_OFFSET    14
+#define    RTL8367C_PORT7_UNKNOWN_L2_MCAST_MASK    0xC000
+#define    RTL8367C_PORT6_UNKNOWN_L2_MCAST_OFFSET    12
+#define    RTL8367C_PORT6_UNKNOWN_L2_MCAST_MASK    0x3000
+#define    RTL8367C_PORT5_UNKNOWN_L2_MCAST_OFFSET    10
+#define    RTL8367C_PORT5_UNKNOWN_L2_MCAST_MASK    0xC00
+#define    RTL8367C_PORT4_UNKNOWN_L2_MCAST_OFFSET    8
+#define    RTL8367C_PORT4_UNKNOWN_L2_MCAST_MASK    0x300
+#define    RTL8367C_PORT3_UNKNOWN_L2_MCAST_OFFSET    6
+#define    RTL8367C_PORT3_UNKNOWN_L2_MCAST_MASK    0xC0
+#define    RTL8367C_PORT2_UNKNOWN_L2_MCAST_OFFSET    4
+#define    RTL8367C_PORT2_UNKNOWN_L2_MCAST_MASK    0x30
+#define    RTL8367C_PORT1_UNKNOWN_L2_MCAST_OFFSET    2
+#define    RTL8367C_PORT1_UNKNOWN_L2_MCAST_MASK    0xC
+#define    RTL8367C_PORT0_UNKNOWN_L2_MCAST_OFFSET    0
+#define    RTL8367C_PORT0_UNKNOWN_L2_MCAST_MASK    0x3
+
+#define    RTL8367C_REG_PORT_TRUNK_DROP_CTRL    0x08ce
+#define    RTL8367C_PORT_TRUNK_DROP_CTRL_OFFSET    0
+#define    RTL8367C_PORT_TRUNK_DROP_CTRL_MASK    0x1
+
+#define    RTL8367C_REG_PORT_TRUNK_CTRL    0x08cf
+#define    RTL8367C_PORT_TRUNK_DUMB_OFFSET    8
+#define    RTL8367C_PORT_TRUNK_DUMB_MASK    0x100
+#define    RTL8367C_PORT_TRUNK_FLOOD_OFFSET    7
+#define    RTL8367C_PORT_TRUNK_FLOOD_MASK    0x80
+#define    RTL8367C_DPORT_HASH_OFFSET    6
+#define    RTL8367C_DPORT_HASH_MASK    0x40
+#define    RTL8367C_SPORT_HASH_OFFSET    5
+#define    RTL8367C_SPORT_HASH_MASK    0x20
+#define    RTL8367C_DIP_HASH_OFFSET    4
+#define    RTL8367C_DIP_HASH_MASK    0x10
+#define    RTL8367C_SIP_HASH_OFFSET    3
+#define    RTL8367C_SIP_HASH_MASK    0x8
+#define    RTL8367C_DMAC_HASH_OFFSET    2
+#define    RTL8367C_DMAC_HASH_MASK    0x4
+#define    RTL8367C_SMAC_HASH_OFFSET    1
+#define    RTL8367C_SMAC_HASH_MASK    0x2
+#define    RTL8367C_SPA_HASH_OFFSET    0
+#define    RTL8367C_SPA_HASH_MASK    0x1
+
+#define    RTL8367C_REG_PORT_TRUNK_GROUP_MASK    0x08d0
+#define    RTL8367C_PORT_TRUNK_GROUP2_MASK_OFFSET    8
+#define    RTL8367C_PORT_TRUNK_GROUP2_MASK_MASK    0x300
+#define    RTL8367C_PORT_TRUNK_GROUP1_MASK_OFFSET    4
+#define    RTL8367C_PORT_TRUNK_GROUP1_MASK_MASK    0xF0
+#define    RTL8367C_PORT_TRUNK_GROUP0_MASK_OFFSET    0
+#define    RTL8367C_PORT_TRUNK_GROUP0_MASK_MASK    0xF
+
+#define    RTL8367C_REG_PORT_TRUNK_FLOWCTRL    0x08d1
+#define    RTL8367C_EN_FLOWCTRL_TG2_OFFSET    2
+#define    RTL8367C_EN_FLOWCTRL_TG2_MASK    0x4
+#define    RTL8367C_EN_FLOWCTRL_TG1_OFFSET    1
+#define    RTL8367C_EN_FLOWCTRL_TG1_MASK    0x2
+#define    RTL8367C_EN_FLOWCTRL_TG0_OFFSET    0
+#define    RTL8367C_EN_FLOWCTRL_TG0_MASK    0x1
+
+#define    RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL0    0x08d2
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH7_OFFSET    14
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH7_MASK    0xC000
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH6_OFFSET    12
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH6_MASK    0x3000
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH5_OFFSET    10
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH5_MASK    0xC00
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH4_OFFSET    8
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH4_MASK    0x300
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH3_OFFSET    6
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH3_MASK    0xC0
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH2_OFFSET    4
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH2_MASK    0x30
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH1_OFFSET    2
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH1_MASK    0xC
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH0_OFFSET    0
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH0_MASK    0x3
+
+#define    RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL1    0x08d3
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH15_OFFSET    14
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH15_MASK    0xC000
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH14_OFFSET    12
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH14_MASK    0x3000
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH13_OFFSET    10
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH13_MASK    0xC00
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH12_OFFSET    8
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH12_MASK    0x300
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH11_OFFSET    6
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH11_MASK    0xC0
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH10_OFFSET    4
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH10_MASK    0x30
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH9_OFFSET    2
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH9_MASK    0xC
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH8_OFFSET    0
+#define    RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH8_MASK    0x3
+
+#define    RTL8367C_REG_DOS_CFG    0x08d4
+#define    RTL8367C_DROP_ICMPFRAGMENT_OFFSET    9
+#define    RTL8367C_DROP_ICMPFRAGMENT_MASK    0x200
+#define    RTL8367C_DROP_TCPFRAGERROR_OFFSET    8
+#define    RTL8367C_DROP_TCPFRAGERROR_MASK    0x100
+#define    RTL8367C_DROP_TCPSHORTHDR_OFFSET    7
+#define    RTL8367C_DROP_TCPSHORTHDR_MASK    0x80
+#define    RTL8367C_DROP_SYN1024_OFFSET    6
+#define    RTL8367C_DROP_SYN1024_MASK    0x40
+#define    RTL8367C_DROP_NULLSCAN_OFFSET    5
+#define    RTL8367C_DROP_NULLSCAN_MASK    0x20
+#define    RTL8367C_DROP_XMASCAN_OFFSET    4
+#define    RTL8367C_DROP_XMASCAN_MASK    0x10
+#define    RTL8367C_DROP_SYNFINSCAN_OFFSET    3
+#define    RTL8367C_DROP_SYNFINSCAN_MASK    0x8
+#define    RTL8367C_DROP_BLATATTACKS_OFFSET    2
+#define    RTL8367C_DROP_BLATATTACKS_MASK    0x4
+#define    RTL8367C_DROP_LANDATTACKS_OFFSET    1
+#define    RTL8367C_DROP_LANDATTACKS_MASK    0x2
+#define    RTL8367C_DROP_DAEQSA_OFFSET    0
+#define    RTL8367C_DROP_DAEQSA_MASK    0x1
+
+#define    RTL8367C_REG_UNKNOWN_L2_MULTICAST_CTRL1    0x08d5
+#define    RTL8367C_PORT10_UNKNOWN_L2_MCAST_OFFSET    4
+#define    RTL8367C_PORT10_UNKNOWN_L2_MCAST_MASK    0x30
+#define    RTL8367C_PORT9_UNKNOWN_L2_MCAST_OFFSET    2
+#define    RTL8367C_PORT9_UNKNOWN_L2_MCAST_MASK    0xC
+#define    RTL8367C_PORT8_UNKNOWN_L2_MCAST_OFFSET    0
+#define    RTL8367C_PORT8_UNKNOWN_L2_MCAST_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4    0x08d6
+#define    RTL8367C_PORT9_VLAN_KEEP_MASK_OFFSET    8
+#define    RTL8367C_PORT9_VLAN_KEEP_MASK_MASK    0xFF00
+#define    RTL8367C_PORT8_VLAN_KEEP_MASK_OFFSET    0
+#define    RTL8367C_PORT8_VLAN_KEEP_MASK_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5    0x08d7
+#define    RTL8367C_VLAN_EGRESS_KEEP_CTRL5_OFFSET    0
+#define    RTL8367C_VLAN_EGRESS_KEEP_CTRL5_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0_EXT    0x08d8
+#define    RTL8367C_PORT1_VLAN_KEEP_MASK_EXT_OFFSET    3
+#define    RTL8367C_PORT1_VLAN_KEEP_MASK_EXT_MASK    0x38
+#define    RTL8367C_PORT0_VLAN_KEEP_MASK_EXT_OFFSET    0
+#define    RTL8367C_PORT0_VLAN_KEEP_MASK_EXT_MASK    0x7
+
+#define    RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL1_EXT    0x08d9
+#define    RTL8367C_PORT3_VLAN_KEEP_MASK_EXT_OFFSET    3
+#define    RTL8367C_PORT3_VLAN_KEEP_MASK_EXT_MASK    0x38
+#define    RTL8367C_PORT2_VLAN_KEEP_MASK_EXT_OFFSET    0
+#define    RTL8367C_PORT2_VLAN_KEEP_MASK_EXT_MASK    0x7
+
+#define    RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL2_EXT    0x08da
+#define    RTL8367C_PORT5_VLAN_KEEP_MASK_EXT_OFFSET    3
+#define    RTL8367C_PORT5_VLAN_KEEP_MASK_EXT_MASK    0x38
+#define    RTL8367C_PORT4_VLAN_KEEP_MASK_EXT_OFFSET    0
+#define    RTL8367C_PORT4_VLAN_KEEP_MASK_EXT_MASK    0x7
+
+#define    RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL3_EXT    0x08db
+#define    RTL8367C_PORT7_VLAN_KEEP_MASK_EXT_OFFSET    3
+#define    RTL8367C_PORT7_VLAN_KEEP_MASK_EXT_MASK    0x38
+#define    RTL8367C_PORT6_VLAN_KEEP_MASK_EXT_OFFSET    0
+#define    RTL8367C_PORT6_VLAN_KEEP_MASK_EXT_MASK    0x7
+
+#define    RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4_EXT    0x08dc
+#define    RTL8367C_PORT9_VLAN_KEEP_MASK_EXT_OFFSET    3
+#define    RTL8367C_PORT9_VLAN_KEEP_MASK_EXT_MASK    0x38
+#define    RTL8367C_PORT8_VLAN_KEEP_MASK_EXT_OFFSET    0
+#define    RTL8367C_PORT8_VLAN_KEEP_MASK_EXT_MASK    0x7
+
+#define    RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5_EXT    0x08dd
+#define    RTL8367C_VLAN_EGRESS_KEEP_CTRL5_EXT_OFFSET    0
+#define    RTL8367C_VLAN_EGRESS_KEEP_CTRL5_EXT_MASK    0x7
+
+#define    RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL10    0x08de
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL10_OFFSET    0
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL10_MASK    0x7FF
+
+#define    RTL8367C_REG_FPGA_VER_CEN    0x08e0
+
+#define    RTL8367C_REG_FPGA_TIME_CEN    0x08e1
+
+#define    RTL8367C_REG_FPGA_DATE_CEN    0x08e2
+
+#define    RTL8367C_REG_QOS_PORT_QUEUE_NUMBER_CTRL0    0x0900
+#define    RTL8367C_PORT3_NUMBER_OFFSET    12
+#define    RTL8367C_PORT3_NUMBER_MASK    0x7000
+#define    RTL8367C_PORT2_NUMBER_OFFSET    8
+#define    RTL8367C_PORT2_NUMBER_MASK    0x700
+#define    RTL8367C_PORT1_NUMBER_OFFSET    4
+#define    RTL8367C_PORT1_NUMBER_MASK    0x70
+#define    RTL8367C_PORT0_NUMBER_OFFSET    0
+#define    RTL8367C_PORT0_NUMBER_MASK    0x7
+
+#define    RTL8367C_REG_QOS_PORT_QUEUE_NUMBER_CTRL1    0x0901
+#define    RTL8367C_PORT7_NUMBER_OFFSET    12
+#define    RTL8367C_PORT7_NUMBER_MASK    0x7000
+#define    RTL8367C_PORT6_NUMBER_OFFSET    8
+#define    RTL8367C_PORT6_NUMBER_MASK    0x700
+#define    RTL8367C_PORT5_NUMBER_OFFSET    4
+#define    RTL8367C_PORT5_NUMBER_MASK    0x70
+#define    RTL8367C_PORT4_NUMBER_OFFSET    0
+#define    RTL8367C_PORT4_NUMBER_MASK    0x7
+
+#define    RTL8367C_REG_QOS_PORT_QUEUE_NUMBER_CTRL2    0x0902
+#define    RTL8367C_PORT10_NUMBER_OFFSET    8
+#define    RTL8367C_PORT10_NUMBER_MASK    0x700
+#define    RTL8367C_PORT9_NUMBER_OFFSET    4
+#define    RTL8367C_PORT9_NUMBER_MASK    0x70
+#define    RTL8367C_PORT8_NUMBER_OFFSET    0
+#define    RTL8367C_PORT8_NUMBER_MASK    0x7
+
+#define    RTL8367C_REG_QOS_1Q_PRIORITY_TO_QID_CTRL0    0x0904
+#define    RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET    12
+#define    RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK    0x7000
+#define    RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET    8
+#define    RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK    0x700
+#define    RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET    4
+#define    RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK    0x70
+#define    RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET    0
+#define    RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK    0x7
+
+#define    RTL8367C_REG_QOS_1Q_PRIORITY_TO_QID_CTRL1    0x0905
+#define    RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET    12
+#define    RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK    0x7000
+#define    RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET    8
+#define    RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK    0x700
+#define    RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET    4
+#define    RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK    0x70
+#define    RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET    0
+#define    RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK    0x7
+
+#define    RTL8367C_REG_QOS_2Q_PRIORITY_TO_QID_CTRL0    0x0906
+#define    RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET    12
+#define    RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK    0x7000
+#define    RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET    8
+#define    RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK    0x700
+#define    RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET    4
+#define    RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK    0x70
+#define    RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET    0
+#define    RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK    0x7
+
+#define    RTL8367C_REG_QOS_2Q_PRIORITY_TO_QID_CTRL1    0x0907
+#define    RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET    12
+#define    RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK    0x7000
+#define    RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET    8
+#define    RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK    0x700
+#define    RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET    4
+#define    RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK    0x70
+#define    RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET    0
+#define    RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK    0x7
+
+#define    RTL8367C_REG_QOS_3Q_PRIORITY_TO_QID_CTRL0    0x0908
+#define    RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET    12
+#define    RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK    0x7000
+#define    RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET    8
+#define    RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK    0x700
+#define    RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET    4
+#define    RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK    0x70
+#define    RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET    0
+#define    RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK    0x7
+
+#define    RTL8367C_REG_QOS_3Q_PRIORITY_TO_QID_CTRL1    0x0909
+#define    RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET    12
+#define    RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK    0x7000
+#define    RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET    8
+#define    RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK    0x700
+#define    RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET    4
+#define    RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK    0x70
+#define    RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET    0
+#define    RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK    0x7
+
+#define    RTL8367C_REG_QOS_4Q_PRIORITY_TO_QID_CTRL0    0x090a
+#define    RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET    12
+#define    RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK    0x7000
+#define    RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET    8
+#define    RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK    0x700
+#define    RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET    4
+#define    RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK    0x70
+#define    RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET    0
+#define    RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK    0x7
+
+#define    RTL8367C_REG_QOS_4Q_PRIORITY_TO_QID_CTRL1    0x090b
+#define    RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET    12
+#define    RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK    0x7000
+#define    RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET    8
+#define    RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK    0x700
+#define    RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET    4
+#define    RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK    0x70
+#define    RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET    0
+#define    RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK    0x7
+
+#define    RTL8367C_REG_QOS_5Q_PRIORITY_TO_QID_CTRL0    0x090c
+#define    RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET    12
+#define    RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK    0x7000
+#define    RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET    8
+#define    RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK    0x700
+#define    RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET    4
+#define    RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK    0x70
+#define    RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET    0
+#define    RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK    0x7
+
+#define    RTL8367C_REG_QOS_5Q_PRIORITY_TO_QID_CTRL1    0x090d
+#define    RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET    12
+#define    RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK    0x7000
+#define    RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET    8
+#define    RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK    0x700
+#define    RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET    4
+#define    RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK    0x70
+#define    RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET    0
+#define    RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK    0x7
+
+#define    RTL8367C_REG_QOS_6Q_PRIORITY_TO_QID_CTRL0    0x090e
+#define    RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET    12
+#define    RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK    0x7000
+#define    RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET    8
+#define    RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK    0x700
+#define    RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET    4
+#define    RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK    0x70
+#define    RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET    0
+#define    RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK    0x7
+
+#define    RTL8367C_REG_QOS_6Q_PRIORITY_TO_QID_CTRL1    0x090f
+#define    RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET    12
+#define    RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK    0x7000
+#define    RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET    8
+#define    RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK    0x700
+#define    RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET    4
+#define    RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK    0x70
+#define    RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET    0
+#define    RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK    0x7
+
+#define    RTL8367C_REG_QOS_7Q_PRIORITY_TO_QID_CTRL0    0x0910
+#define    RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET    12
+#define    RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK    0x7000
+#define    RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET    8
+#define    RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK    0x700
+#define    RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET    4
+#define    RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK    0x70
+#define    RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET    0
+#define    RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK    0x7
+
+#define    RTL8367C_REG_QOS_7Q_PRIORITY_TO_QID_CTRL1    0x0911
+#define    RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET    12
+#define    RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK    0x7000
+#define    RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET    8
+#define    RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK    0x700
+#define    RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET    4
+#define    RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK    0x70
+#define    RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET    0
+#define    RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK    0x7
+
+#define    RTL8367C_REG_QOS_8Q_PRIORITY_TO_QID_CTRL0    0x0912
+#define    RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET    12
+#define    RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK    0x7000
+#define    RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET    8
+#define    RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK    0x700
+#define    RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET    4
+#define    RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK    0x70
+#define    RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET    0
+#define    RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK    0x7
+
+#define    RTL8367C_REG_QOS_8Q_PRIORITY_TO_QID_CTRL1    0x0913
+#define    RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET    12
+#define    RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK    0x7000
+#define    RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET    8
+#define    RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK    0x700
+#define    RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET    4
+#define    RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK    0x70
+#define    RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET    0
+#define    RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK    0x7
+
+#define    RTL8367C_REG_HIGHPRI_INDICATOR    0x0915
+#define    RTL8367C_PORT10_INDICATOR_OFFSET    10
+#define    RTL8367C_PORT10_INDICATOR_MASK    0x400
+#define    RTL8367C_PORT9_INDICATOR_OFFSET    9
+#define    RTL8367C_PORT9_INDICATOR_MASK    0x200
+#define    RTL8367C_PORT8_INDICATOR_OFFSET    8
+#define    RTL8367C_PORT8_INDICATOR_MASK    0x100
+#define    RTL8367C_PORT7_INDICATOR_OFFSET    7
+#define    RTL8367C_PORT7_INDICATOR_MASK    0x80
+#define    RTL8367C_PORT6_INDICATOR_OFFSET    6
+#define    RTL8367C_PORT6_INDICATOR_MASK    0x40
+#define    RTL8367C_PORT5_INDICATOR_OFFSET    5
+#define    RTL8367C_PORT5_INDICATOR_MASK    0x20
+#define    RTL8367C_PORT4_INDICATOR_OFFSET    4
+#define    RTL8367C_PORT4_INDICATOR_MASK    0x10
+#define    RTL8367C_PORT3_INDICATOR_OFFSET    3
+#define    RTL8367C_PORT3_INDICATOR_MASK    0x8
+#define    RTL8367C_PORT2_INDICATOR_OFFSET    2
+#define    RTL8367C_PORT2_INDICATOR_MASK    0x4
+#define    RTL8367C_PORT1_INDICATOR_OFFSET    1
+#define    RTL8367C_PORT1_INDICATOR_MASK    0x2
+#define    RTL8367C_PORT0_INDICATOR_OFFSET    0
+#define    RTL8367C_PORT0_INDICATOR_MASK    0x1
+
+#define    RTL8367C_REG_HIGHPRI_CFG    0x0916
+#define    RTL8367C_HIGHPRI_CFG_OFFSET    0
+#define    RTL8367C_HIGHPRI_CFG_MASK    0xFF
+
+#define    RTL8367C_REG_PORT_DEBUG_INFO_CTRL0    0x0917
+#define    RTL8367C_PORT1_DEBUG_INFO_OFFSET    8
+#define    RTL8367C_PORT1_DEBUG_INFO_MASK    0xFF00
+#define    RTL8367C_PORT0_DEBUG_INFO_OFFSET    0
+#define    RTL8367C_PORT0_DEBUG_INFO_MASK    0xFF
+
+#define    RTL8367C_REG_PORT_DEBUG_INFO_CTRL1    0x0918
+#define    RTL8367C_PORT3_DEBUG_INFO_OFFSET    8
+#define    RTL8367C_PORT3_DEBUG_INFO_MASK    0xFF00
+#define    RTL8367C_PORT2_DEBUG_INFO_OFFSET    0
+#define    RTL8367C_PORT2_DEBUG_INFO_MASK    0xFF
+
+#define    RTL8367C_REG_PORT_DEBUG_INFO_CTRL2    0x0919
+#define    RTL8367C_PORT5_DEBUG_INFO_OFFSET    8
+#define    RTL8367C_PORT5_DEBUG_INFO_MASK    0xFF00
+#define    RTL8367C_PORT4_DEBUG_INFO_OFFSET    0
+#define    RTL8367C_PORT4_DEBUG_INFO_MASK    0xFF
+
+#define    RTL8367C_REG_PORT_DEBUG_INFO_CTRL3    0x091a
+#define    RTL8367C_PORT7_DEBUG_INFO_OFFSET    8
+#define    RTL8367C_PORT7_DEBUG_INFO_MASK    0xFF00
+#define    RTL8367C_PORT6_DEBUG_INFO_OFFSET    0
+#define    RTL8367C_PORT6_DEBUG_INFO_MASK    0xFF
+
+#define    RTL8367C_REG_PORT_DEBUG_INFO_CTRL4    0x091b
+#define    RTL8367C_PORT9_DEBUG_INFO_OFFSET    8
+#define    RTL8367C_PORT9_DEBUG_INFO_MASK    0xFF00
+#define    RTL8367C_PORT8_DEBUG_INFO_OFFSET    0
+#define    RTL8367C_PORT8_DEBUG_INFO_MASK    0xFF
+
+#define    RTL8367C_REG_PORT_DEBUG_INFO_CTRL5    0x091c
+#define    RTL8367C_PORT10_DEBUG_INFO_OFFSET    0
+#define    RTL8367C_PORT10_DEBUG_INFO_MASK    0xFF
+
+#define    RTL8367C_REG_PORT_DEBUG_INFO_CTRL6    0x091d
+#define    RTL8367C_PORT7_DEBUG_INDICATOR_OFFSET    14
+#define    RTL8367C_PORT7_DEBUG_INDICATOR_MASK    0xC000
+#define    RTL8367C_PORT6_DEBUG_INDICATOR_OFFSET    12
+#define    RTL8367C_PORT6_DEBUG_INDICATOR_MASK    0x3000
+#define    RTL8367C_PORT5_DEBUG_INDICATOR_OFFSET    10
+#define    RTL8367C_PORT5_DEBUG_INDICATOR_MASK    0xC00
+#define    RTL8367C_PORT4_DEBUG_INDICATOR_OFFSET    8
+#define    RTL8367C_PORT4_DEBUG_INDICATOR_MASK    0x300
+#define    RTL8367C_PORT3_DEBUG_INDICATOR_OFFSET    6
+#define    RTL8367C_PORT3_DEBUG_INDICATOR_MASK    0xC0
+#define    RTL8367C_PORT2_DEBUG_INDICATOR_OFFSET    4
+#define    RTL8367C_PORT2_DEBUG_INDICATOR_MASK    0x30
+#define    RTL8367C_PORT1_DEBUG_INDICATOR_OFFSET    2
+#define    RTL8367C_PORT1_DEBUG_INDICATOR_MASK    0xC
+#define    RTL8367C_PORT0_DEBUG_INDICATOR_OFFSET    0
+#define    RTL8367C_PORT0_DEBUG_INDICATOR_MASK    0x3
+
+#define    RTL8367C_REG_PORT_DEBUG_INFO_CTRL7    0x091e
+#define    RTL8367C_PORT10_DEBUG_INDICATOR_OFFSET    4
+#define    RTL8367C_PORT10_DEBUG_INDICATOR_MASK    0x30
+#define    RTL8367C_PORT9_DEBUG_INDICATOR_OFFSET    2
+#define    RTL8367C_PORT9_DEBUG_INDICATOR_MASK    0xC
+#define    RTL8367C_PORT8_DEBUG_INDICATOR_OFFSET    0
+#define    RTL8367C_PORT8_DEBUG_INDICATOR_MASK    0x3
+
+#define    RTL8367C_REG_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL0    0x0930
+#define    RTL8367C_PORT1_QUEUE_MASK_OFFSET    8
+#define    RTL8367C_PORT1_QUEUE_MASK_MASK    0xFF00
+#define    RTL8367C_PORT0_QUEUE_MASK_OFFSET    0
+#define    RTL8367C_PORT0_QUEUE_MASK_MASK    0xFF
+
+#define    RTL8367C_REG_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL1    0x0931
+#define    RTL8367C_PORT3_QUEUE_MASK_OFFSET    8
+#define    RTL8367C_PORT3_QUEUE_MASK_MASK    0xFF00
+#define    RTL8367C_PORT2_QUEUE_MASK_OFFSET    0
+#define    RTL8367C_PORT2_QUEUE_MASK_MASK    0xFF
+
+#define    RTL8367C_REG_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL2    0x0932
+#define    RTL8367C_PORT5_QUEUE_MASK_OFFSET    8
+#define    RTL8367C_PORT5_QUEUE_MASK_MASK    0xFF00
+#define    RTL8367C_PORT4_QUEUE_MASK_OFFSET    0
+#define    RTL8367C_PORT4_QUEUE_MASK_MASK    0xFF
+
+#define    RTL8367C_REG_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL3    0x0933
+#define    RTL8367C_PORT7_QUEUE_MASK_OFFSET    8
+#define    RTL8367C_PORT7_QUEUE_MASK_MASK    0xFF00
+#define    RTL8367C_PORT6_QUEUE_MASK_OFFSET    0
+#define    RTL8367C_PORT6_QUEUE_MASK_MASK    0xFF
+
+#define    RTL8367C_REG_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL4    0x0934
+#define    RTL8367C_PORT9_QUEUE_MASK_OFFSET    8
+#define    RTL8367C_PORT9_QUEUE_MASK_MASK    0xFF00
+#define    RTL8367C_PORT8_QUEUE_MASK_OFFSET    0
+#define    RTL8367C_PORT8_QUEUE_MASK_MASK    0xFF
+
+#define    RTL8367C_REG_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL5    0x0935
+#define    RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL5_OFFSET    0
+#define    RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL5_MASK    0xFF
+
+#define    RTL8367C_REG_FLOWCRTL_EGRESS_PORT_ENABLE    0x0938
+#define    RTL8367C_FLOWCRTL_EGRESS_PORT_ENABLE_OFFSET    0
+#define    RTL8367C_FLOWCRTL_EGRESS_PORT_ENABLE_MASK    0xFF
+
+#define    RTL8367C_REG_EAV_CTRL    0x0939
+#define    RTL8367C_EAV_TRAP_CPU_OFFSET    1
+#define    RTL8367C_EAV_TRAP_CPU_MASK    0x2
+#define    RTL8367C_EAV_TRAP_8051_OFFSET    0
+#define    RTL8367C_EAV_TRAP_8051_MASK    0x1
+
+#define    RTL8367C_REG_UNTAG_DSCP_PRI_CFG    0x093a
+#define    RTL8367C_UNTAG_DSCP_PRI_CFG_OFFSET    0
+#define    RTL8367C_UNTAG_DSCP_PRI_CFG_MASK    0x1
+
+#define    RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0    0x093b
+#define    RTL8367C_PORT1_VLAN_KEEP_MASK_OFFSET    8
+#define    RTL8367C_PORT1_VLAN_KEEP_MASK_MASK    0xFF00
+#define    RTL8367C_PORT0_VLAN_KEEP_MASK_OFFSET    0
+#define    RTL8367C_PORT0_VLAN_KEEP_MASK_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL1    0x093c
+#define    RTL8367C_PORT3_VLAN_KEEP_MASK_OFFSET    8
+#define    RTL8367C_PORT3_VLAN_KEEP_MASK_MASK    0xFF00
+#define    RTL8367C_PORT2_VLAN_KEEP_MASK_OFFSET    0
+#define    RTL8367C_PORT2_VLAN_KEEP_MASK_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL2    0x093d
+#define    RTL8367C_PORT5_VLAN_KEEP_MASK_OFFSET    8
+#define    RTL8367C_PORT5_VLAN_KEEP_MASK_MASK    0xFF00
+#define    RTL8367C_PORT4_VLAN_KEEP_MASK_OFFSET    0
+#define    RTL8367C_PORT4_VLAN_KEEP_MASK_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL3    0x093e
+#define    RTL8367C_PORT7_VLAN_KEEP_MASK_OFFSET    8
+#define    RTL8367C_PORT7_VLAN_KEEP_MASK_MASK    0xFF00
+#define    RTL8367C_PORT6_VLAN_KEEP_MASK_OFFSET    0
+#define    RTL8367C_PORT6_VLAN_KEEP_MASK_MASK    0xFF
+
+#define    RTL8367C_REG_VLAN_TRANSPARENT_EN_CFG    0x093f
+#define    RTL8367C_VLAN_TRANSPARENT_EN_CFG_OFFSET    0
+#define    RTL8367C_VLAN_TRANSPARENT_EN_CFG_MASK    0x1
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY0_H    0x0940
+#define    RTL8367C_IPMC_GROUP_ENTRY0_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY0_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY0_L    0x0941
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY1_H    0x0942
+#define    RTL8367C_IPMC_GROUP_ENTRY1_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY1_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY1_L    0x0943
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY2_H    0x0944
+#define    RTL8367C_IPMC_GROUP_ENTRY2_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY2_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY2_L    0x0945
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY3_H    0x0946
+#define    RTL8367C_IPMC_GROUP_ENTRY3_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY3_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY3_L    0x0947
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY4_H    0x0948
+#define    RTL8367C_IPMC_GROUP_ENTRY4_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY4_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY4_L    0x0949
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY5_H    0x094a
+#define    RTL8367C_IPMC_GROUP_ENTRY5_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY5_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY5_L    0x094b
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY6_H    0x094c
+#define    RTL8367C_IPMC_GROUP_ENTRY6_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY6_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY6_L    0x094d
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY7_H    0x094e
+#define    RTL8367C_IPMC_GROUP_ENTRY7_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY7_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY7_L    0x094f
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY8_H    0x0950
+#define    RTL8367C_IPMC_GROUP_ENTRY8_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY8_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY8_L    0x0951
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY9_H    0x0952
+#define    RTL8367C_IPMC_GROUP_ENTRY9_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY9_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY9_L    0x0953
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY10_H    0x0954
+#define    RTL8367C_IPMC_GROUP_ENTRY10_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY10_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY10_L    0x0955
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY11_H    0x0956
+#define    RTL8367C_IPMC_GROUP_ENTRY11_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY11_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY11_L    0x0957
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY12_H    0x0958
+#define    RTL8367C_IPMC_GROUP_ENTRY12_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY12_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY12_L    0x0959
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY13_H    0x095a
+#define    RTL8367C_IPMC_GROUP_ENTRY13_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY13_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY13_L    0x095b
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY14_H    0x095c
+#define    RTL8367C_IPMC_GROUP_ENTRY14_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY14_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY14_L    0x095d
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY15_H    0x095e
+#define    RTL8367C_IPMC_GROUP_ENTRY15_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY15_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY15_L    0x095f
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY16_H    0x0960
+#define    RTL8367C_IPMC_GROUP_ENTRY16_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY16_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY16_L    0x0961
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY17_H    0x0962
+#define    RTL8367C_IPMC_GROUP_ENTRY17_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY17_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY17_L    0x0963
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY18_H    0x0964
+#define    RTL8367C_IPMC_GROUP_ENTRY18_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY18_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY18_L    0x0965
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY19_H    0x0966
+#define    RTL8367C_IPMC_GROUP_ENTRY19_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY19_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY19_L    0x0967
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY20_H    0x0968
+#define    RTL8367C_IPMC_GROUP_ENTRY20_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY20_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY20_L    0x0969
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY21_H    0x096a
+#define    RTL8367C_IPMC_GROUP_ENTRY21_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY21_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY21_L    0x096b
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY22_H    0x096c
+#define    RTL8367C_IPMC_GROUP_ENTRY22_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY22_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY22_L    0x096d
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY23_H    0x096e
+#define    RTL8367C_IPMC_GROUP_ENTRY23_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY23_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY23_L    0x096f
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY24_H    0x0970
+#define    RTL8367C_IPMC_GROUP_ENTRY24_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY24_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY24_L    0x0971
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY25_H    0x0972
+#define    RTL8367C_IPMC_GROUP_ENTRY25_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY25_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY25_L    0x0973
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY26_H    0x0974
+#define    RTL8367C_IPMC_GROUP_ENTRY26_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY26_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY26_L    0x0975
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY27_H    0x0976
+#define    RTL8367C_IPMC_GROUP_ENTRY27_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY27_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY27_L    0x0977
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY28_H    0x0978
+#define    RTL8367C_IPMC_GROUP_ENTRY28_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY28_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY28_L    0x0979
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY29_H    0x097a
+#define    RTL8367C_IPMC_GROUP_ENTRY29_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY29_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY29_L    0x097b
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY30_H    0x097c
+#define    RTL8367C_IPMC_GROUP_ENTRY30_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY30_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY30_L    0x097d
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY31_H    0x097e
+#define    RTL8367C_IPMC_GROUP_ENTRY31_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY31_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY31_L    0x097f
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY32_H    0x0980
+#define    RTL8367C_IPMC_GROUP_ENTRY32_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY32_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY32_L    0x0981
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY33_H    0x0982
+#define    RTL8367C_IPMC_GROUP_ENTRY33_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY33_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY33_L    0x0983
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY34_H    0x0984
+#define    RTL8367C_IPMC_GROUP_ENTRY34_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY34_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY34_L    0x0985
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY35_H    0x0986
+#define    RTL8367C_IPMC_GROUP_ENTRY35_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY35_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY35_L    0x0987
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY36_H    0x0988
+#define    RTL8367C_IPMC_GROUP_ENTRY36_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY36_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY36_L    0x0989
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY37_H    0x098a
+#define    RTL8367C_IPMC_GROUP_ENTRY37_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY37_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY37_L    0x098b
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY38_H    0x098c
+#define    RTL8367C_IPMC_GROUP_ENTRY38_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY38_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY38_L    0x098d
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY39_H    0x098e
+#define    RTL8367C_IPMC_GROUP_ENTRY39_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY39_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY39_L    0x098f
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY40_H    0x0990
+#define    RTL8367C_IPMC_GROUP_ENTRY40_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY40_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY40_L    0x0991
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY41_H    0x0992
+#define    RTL8367C_IPMC_GROUP_ENTRY41_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY41_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY41_L    0x0993
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY42_H    0x0994
+#define    RTL8367C_IPMC_GROUP_ENTRY42_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY42_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY42_L    0x0995
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY43_H    0x0996
+#define    RTL8367C_IPMC_GROUP_ENTRY43_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY43_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY43_L    0x0997
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY44_H    0x0998
+#define    RTL8367C_IPMC_GROUP_ENTRY44_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY44_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY44_L    0x0999
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY45_H    0x099a
+#define    RTL8367C_IPMC_GROUP_ENTRY45_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY45_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY45_L    0x099b
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY46_H    0x099c
+#define    RTL8367C_IPMC_GROUP_ENTRY46_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY46_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY46_L    0x099d
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY47_H    0x099e
+#define    RTL8367C_IPMC_GROUP_ENTRY47_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY47_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY47_L    0x099f
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY48_H    0x09a0
+#define    RTL8367C_IPMC_GROUP_ENTRY48_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY48_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY48_L    0x09a1
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY49_H    0x09a2
+#define    RTL8367C_IPMC_GROUP_ENTRY49_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY49_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY49_L    0x09a3
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY50_H    0x09a4
+#define    RTL8367C_IPMC_GROUP_ENTRY50_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY50_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY50_L    0x09a5
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY51_H    0x09a6
+#define    RTL8367C_IPMC_GROUP_ENTRY51_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY51_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY51_L    0x09a7
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY52_H    0x09a8
+#define    RTL8367C_IPMC_GROUP_ENTRY52_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY52_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY52_L    0x09a9
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY53_H    0x09aa
+#define    RTL8367C_IPMC_GROUP_ENTRY53_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY53_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY53_L    0x09ab
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY54_H    0x09ac
+#define    RTL8367C_IPMC_GROUP_ENTRY54_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY54_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY54_L    0x09ad
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY55_H    0x09ae
+#define    RTL8367C_IPMC_GROUP_ENTRY55_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY55_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY55_L    0x09af
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY56_H    0x09b0
+#define    RTL8367C_IPMC_GROUP_ENTRY56_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY56_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY56_L    0x09b1
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY57_H    0x09b2
+#define    RTL8367C_IPMC_GROUP_ENTRY57_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY57_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY57_L    0x09b3
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY58_H    0x09b4
+#define    RTL8367C_IPMC_GROUP_ENTRY58_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY58_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY58_L    0x09b5
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY59_H    0x09b6
+#define    RTL8367C_IPMC_GROUP_ENTRY59_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY59_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY59_L    0x09b7
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY60_H    0x09b8
+#define    RTL8367C_IPMC_GROUP_ENTRY60_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY60_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY60_L    0x09b9
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY61_H    0x09ba
+#define    RTL8367C_IPMC_GROUP_ENTRY61_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY61_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY61_L    0x09bb
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY62_H    0x09bc
+#define    RTL8367C_IPMC_GROUP_ENTRY62_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY62_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY62_L    0x09bd
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY63_H    0x09be
+#define    RTL8367C_IPMC_GROUP_ENTRY63_H_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_ENTRY63_H_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_ENTRY63_L    0x09bf
+
+#define    RTL8367C_REG_UNKNOWN_UNICAST_DA_PORT_BEHAVE    0x09C0
+#define    RTL8367C_Port7_ACTION_OFFSET    14
+#define    RTL8367C_Port7_ACTION_MASK    0xC000
+#define    RTL8367C_Port6_ACTION_OFFSET    12
+#define    RTL8367C_Port6_ACTION_MASK    0x3000
+#define    RTL8367C_Port5_ACTION_OFFSET    10
+#define    RTL8367C_Port5_ACTION_MASK    0xC00
+#define    RTL8367C_Port4_ACTION_OFFSET    8
+#define    RTL8367C_Port4_ACTION_MASK    0x300
+#define    RTL8367C_Port3_ACTION_OFFSET    6
+#define    RTL8367C_Port3_ACTION_MASK    0xC0
+#define    RTL8367C_Port2_ACTION_OFFSET    4
+#define    RTL8367C_Port2_ACTION_MASK    0x30
+#define    RTL8367C_Port1_ACTION_OFFSET    2
+#define    RTL8367C_Port1_ACTION_MASK    0xC
+#define    RTL8367C_Port0_ACTION_OFFSET    0
+#define    RTL8367C_Port0_ACTION_MASK    0x3
+
+#define    RTL8367C_REG_MIRROR_CTRL3    0x09C1
+#define    RTL8367C_MIRROR_ACL_OVERRIDE_EN_OFFSET    2
+#define    RTL8367C_MIRROR_ACL_OVERRIDE_EN_MASK    0x4
+#define    RTL8367C_MIRROR_TX_OVERRIDE_EN_OFFSET    1
+#define    RTL8367C_MIRROR_TX_OVERRIDE_EN_MASK    0x2
+#define    RTL8367C_MIRROR_RX_OVERRIDE_EN_OFFSET    0
+#define    RTL8367C_MIRROR_RX_OVERRIDE_EN_MASK    0x1
+
+#define    RTL8367C_REG_DPM_DUMMY02    0x09C2
+
+#define    RTL8367C_REG_DPM_DUMMY03    0x09C3
+
+#define    RTL8367C_REG_DPM_DUMMY04    0x09C4
+
+#define    RTL8367C_REG_DPM_DUMMY05    0x09C5
+
+#define    RTL8367C_REG_DPM_DUMMY06    0x09C6
+
+#define    RTL8367C_REG_DPM_DUMMY07    0x09C7
+
+#define    RTL8367C_REG_DPM_DUMMY08    0x09C8
+
+#define    RTL8367C_REG_DPM_DUMMY09    0x09C9
+
+#define    RTL8367C_REG_DPM_DUMMY10    0x09CA
+
+#define    RTL8367C_REG_DPM_DUMMY11    0x09CB
+
+#define    RTL8367C_REG_DPM_DUMMY12    0x09CC
+
+#define    RTL8367C_REG_DPM_DUMMY13    0x09CD
+
+#define    RTL8367C_REG_DPM_DUMMY14    0x09CE
+
+#define    RTL8367C_REG_DPM_DUMMY15    0x09CF
+
+#define    RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL0    0x09D0
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL0_OFFSET    0
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL0_MASK    0x7FF
+
+#define    RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL1    0x09D1
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL1_OFFSET    0
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL1_MASK    0x7FF
+
+#define    RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL2    0x09D2
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL2_OFFSET    0
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL2_MASK    0x7FF
+
+#define    RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL3    0x09D3
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL3_OFFSET    0
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL3_MASK    0x7FF
+
+#define    RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL4    0x09D4
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL4_OFFSET    0
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL4_MASK    0x7FF
+
+#define    RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL5    0x09D5
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL5_OFFSET    0
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL5_MASK    0x7FF
+
+#define    RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL6    0x09D6
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL6_OFFSET    0
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL6_MASK    0x7FF
+
+#define    RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL7    0x09D7
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL7_OFFSET    0
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL7_MASK    0x7FF
+
+#define    RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL8    0x09D8
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL8_OFFSET    0
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL8_MASK    0x7FF
+
+#define    RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL9    0x09D9
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL9_OFFSET    0
+#define    RTL8367C_VLAN_EGRESS_TRANS_CTRL9_MASK    0x7FF
+
+#define    RTL8367C_REG_MIRROR_CTRL2    0x09DA
+#define    RTL8367C_MIRROR_REALKEEP_EN_OFFSET    4
+#define    RTL8367C_MIRROR_REALKEEP_EN_MASK    0x10
+#define    RTL8367C_MIRROR_RX_ISOLATION_LEAKY_OFFSET    3
+#define    RTL8367C_MIRROR_RX_ISOLATION_LEAKY_MASK    0x8
+#define    RTL8367C_MIRROR_TX_ISOLATION_LEAKY_OFFSET    2
+#define    RTL8367C_MIRROR_TX_ISOLATION_LEAKY_MASK    0x4
+#define    RTL8367C_MIRROR_RX_VLAN_LEAKY_OFFSET    1
+#define    RTL8367C_MIRROR_RX_VLAN_LEAKY_MASK    0x2
+#define    RTL8367C_MIRROR_TX_VLAN_LEAKY_OFFSET    0
+#define    RTL8367C_MIRROR_TX_VLAN_LEAKY_MASK    0x1
+
+#define    RTL8367C_REG_OUTPUT_DROP_CFG    0x09DB
+#define    RTL8367C_ENABLE_PMASK_EXT_OFFSET    13
+#define    RTL8367C_ENABLE_PMASK_EXT_MASK    0xE000
+#define    RTL8367C_ENABLE_BC_OFFSET    12
+#define    RTL8367C_ENABLE_BC_MASK    0x1000
+#define    RTL8367C_ENABLE_MC_OFFSET    11
+#define    RTL8367C_ENABLE_MC_MASK    0x800
+#define    RTL8367C_ENABLE_UC_OFFSET    10
+#define    RTL8367C_ENABLE_UC_MASK    0x400
+#define    RTL8367C_ENABLE_PMASK_OFFSET    0
+#define    RTL8367C_ENABLE_PMASK_MASK    0xFF
+
+#define    RTL8367C_REG_UNKNOWN_UNICAST_DA_PORT_BEHAVE_EXT    0x09DC
+#define    RTL8367C_PORT10_ACTION_OFFSET    4
+#define    RTL8367C_PORT10_ACTION_MASK    0x30
+#define    RTL8367C_PORT9_ACTION_OFFSET    2
+#define    RTL8367C_PORT9_ACTION_MASK    0xC
+#define    RTL8367C_PORT8_ACTION_OFFSET    0
+#define    RTL8367C_PORT8_ACTION_MASK    0x3
+
+#define    RTL8367C_REG_RMK_CFG_SEL_CTRL    0x09DF
+#define    RTL8367C_RMK_1Q_CFG_SEL_OFFSET    2
+#define    RTL8367C_RMK_1Q_CFG_SEL_MASK    0x4
+#define    RTL8367C_RMK_DSCP_CFG_SEL_OFFSET    0
+#define    RTL8367C_RMK_DSCP_CFG_SEL_MASK    0x3
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL0    0x09E0
+#define    RTL8367C_DSCP1_DSCP_OFFSET    8
+#define    RTL8367C_DSCP1_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP0_DSCP_OFFSET    0
+#define    RTL8367C_DSCP0_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL1    0x09E1
+#define    RTL8367C_DSCP3_DSCP_OFFSET    8
+#define    RTL8367C_DSCP3_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP2_DSCP_OFFSET    0
+#define    RTL8367C_DSCP2_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL2    0x09E2
+#define    RTL8367C_DSCP5_DSCP_OFFSET    8
+#define    RTL8367C_DSCP5_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP4_DSCP_OFFSET    0
+#define    RTL8367C_DSCP4_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL3    0x09E3
+#define    RTL8367C_DSCP7_DSCP_OFFSET    8
+#define    RTL8367C_DSCP7_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP6_DSCP_OFFSET    0
+#define    RTL8367C_DSCP6_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL4    0x09E4
+#define    RTL8367C_DSCP9_DSCP_OFFSET    8
+#define    RTL8367C_DSCP9_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP8_DSCP_OFFSET    0
+#define    RTL8367C_DSCP8_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL5    0x09E5
+#define    RTL8367C_DSCP11_DSCP_OFFSET    8
+#define    RTL8367C_DSCP11_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP10_DSCP_OFFSET    0
+#define    RTL8367C_DSCP10_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL6    0x09E6
+#define    RTL8367C_DSCP13_DSCP_OFFSET    8
+#define    RTL8367C_DSCP13_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP12_DSCP_OFFSET    0
+#define    RTL8367C_DSCP12_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL7    0x09E7
+#define    RTL8367C_DSCP15_DSCP_OFFSET    8
+#define    RTL8367C_DSCP15_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP14_DSCP_OFFSET    0
+#define    RTL8367C_DSCP14_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL8    0x09E8
+#define    RTL8367C_DSCP17_DSCP_OFFSET    8
+#define    RTL8367C_DSCP17_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP16_DSCP_OFFSET    0
+#define    RTL8367C_DSCP16_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL9    0x09E9
+#define    RTL8367C_DSCP19_DSCP_OFFSET    8
+#define    RTL8367C_DSCP19_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP18_DSCP_OFFSET    0
+#define    RTL8367C_DSCP18_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL10    0x09EA
+#define    RTL8367C_DSCP21_DSCP_OFFSET    8
+#define    RTL8367C_DSCP21_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP20_DSCP_OFFSET    0
+#define    RTL8367C_DSCP20_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL11    0x09EB
+#define    RTL8367C_DSCP23_DSCP_OFFSET    8
+#define    RTL8367C_DSCP23_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP22_DSCP_OFFSET    0
+#define    RTL8367C_DSCP22_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL12    0x09EC
+#define    RTL8367C_DSCP25_DSCP_OFFSET    8
+#define    RTL8367C_DSCP25_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP24_DSCP_OFFSET    0
+#define    RTL8367C_DSCP24_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL13    0x09ED
+#define    RTL8367C_DSCP27_DSCP_OFFSET    8
+#define    RTL8367C_DSCP27_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP26_DSCP_OFFSET    0
+#define    RTL8367C_DSCP26_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL14    0x09EE
+#define    RTL8367C_DSCP29_DSCP_OFFSET    8
+#define    RTL8367C_DSCP29_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP28_DSCP_OFFSET    0
+#define    RTL8367C_DSCP28_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL15    0x09EF
+#define    RTL8367C_DSCP31_DSCP_OFFSET    8
+#define    RTL8367C_DSCP31_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP30_DSCP_OFFSET    0
+#define    RTL8367C_DSCP30_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL16    0x09F0
+#define    RTL8367C_DSCP33_DSCP_OFFSET    8
+#define    RTL8367C_DSCP33_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP32_DSCP_OFFSET    0
+#define    RTL8367C_DSCP32_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL17    0x09F1
+#define    RTL8367C_DSCP35_DSCP_OFFSET    8
+#define    RTL8367C_DSCP35_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP34_DSCP_OFFSET    0
+#define    RTL8367C_DSCP34_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL18    0x09F2
+#define    RTL8367C_DSCP37_DSCP_OFFSET    8
+#define    RTL8367C_DSCP37_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP36_DSCP_OFFSET    0
+#define    RTL8367C_DSCP36_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL19    0x09F3
+#define    RTL8367C_DSCP39_DSCP_OFFSET    8
+#define    RTL8367C_DSCP39_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP38_DSCP_OFFSET    0
+#define    RTL8367C_DSCP38_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL20    0x09F4
+#define    RTL8367C_DSCP41_DSCP_OFFSET    8
+#define    RTL8367C_DSCP41_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP40_DSCP_OFFSET    0
+#define    RTL8367C_DSCP40_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL21    0x09F5
+#define    RTL8367C_DSCP43_DSCP_OFFSET    8
+#define    RTL8367C_DSCP43_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP42_DSCP_OFFSET    0
+#define    RTL8367C_DSCP42_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL22    0x09F6
+#define    RTL8367C_DSCP45_DSCP_OFFSET    8
+#define    RTL8367C_DSCP45_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP44_DSCP_OFFSET    0
+#define    RTL8367C_DSCP44_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL23    0x09F7
+#define    RTL8367C_DSCP47_DSCP_OFFSET    8
+#define    RTL8367C_DSCP47_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP46_DSCP_OFFSET    0
+#define    RTL8367C_DSCP46_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL24    0x09F8
+#define    RTL8367C_DSCP49_DSCP_OFFSET    8
+#define    RTL8367C_DSCP49_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP48_DSCP_OFFSET    0
+#define    RTL8367C_DSCP48_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL25    0x09F9
+#define    RTL8367C_DSCP51_DSCP_OFFSET    8
+#define    RTL8367C_DSCP51_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP50_DSCP_OFFSET    0
+#define    RTL8367C_DSCP50_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL26    0x09FA
+#define    RTL8367C_DSCP53_DSCP_OFFSET    8
+#define    RTL8367C_DSCP53_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP52_DSCP_OFFSET    0
+#define    RTL8367C_DSCP52_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL27    0x09FB
+#define    RTL8367C_DSCP55_DSCP_OFFSET    8
+#define    RTL8367C_DSCP55_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP54_DSCP_OFFSET    0
+#define    RTL8367C_DSCP54_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL28    0x09FC
+#define    RTL8367C_DSCP57_DSCP_OFFSET    8
+#define    RTL8367C_DSCP57_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP56_DSCP_OFFSET    0
+#define    RTL8367C_DSCP56_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL29    0x09FD
+#define    RTL8367C_DSCP59_DSCP_OFFSET    8
+#define    RTL8367C_DSCP59_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP58_DSCP_OFFSET    0
+#define    RTL8367C_DSCP58_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL30    0x09FE
+#define    RTL8367C_DSCP61_DSCP_OFFSET    8
+#define    RTL8367C_DSCP61_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP60_DSCP_OFFSET    0
+#define    RTL8367C_DSCP60_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL31    0x09FF
+#define    RTL8367C_DSCP63_DSCP_OFFSET    8
+#define    RTL8367C_DSCP63_DSCP_MASK    0x3F00
+#define    RTL8367C_DSCP62_DSCP_OFFSET    0
+#define    RTL8367C_DSCP62_DSCP_MASK    0x3F
+
+/* (16'h0a00)l2_reg */
+
+#define    RTL8367C_REG_VLAN_MSTI0_CTRL0    0x0a00
+#define    RTL8367C_VLAN_MSTI0_CTRL0_PORT7_STATE_OFFSET    14
+#define    RTL8367C_VLAN_MSTI0_CTRL0_PORT7_STATE_MASK    0xC000
+#define    RTL8367C_VLAN_MSTI0_CTRL0_PORT6_STATE_OFFSET    12
+#define    RTL8367C_VLAN_MSTI0_CTRL0_PORT6_STATE_MASK    0x3000
+#define    RTL8367C_VLAN_MSTI0_CTRL0_PORT5_STATE_OFFSET    10
+#define    RTL8367C_VLAN_MSTI0_CTRL0_PORT5_STATE_MASK    0xC00
+#define    RTL8367C_VLAN_MSTI0_CTRL0_PORT4_STATE_OFFSET    8
+#define    RTL8367C_VLAN_MSTI0_CTRL0_PORT4_STATE_MASK    0x300
+#define    RTL8367C_VLAN_MSTI0_CTRL0_PORT3_STATE_OFFSET    6
+#define    RTL8367C_VLAN_MSTI0_CTRL0_PORT3_STATE_MASK    0xC0
+#define    RTL8367C_VLAN_MSTI0_CTRL0_PORT2_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI0_CTRL0_PORT2_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI0_CTRL0_PORT1_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI0_CTRL0_PORT1_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI0_CTRL0_PORT0_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI0_CTRL0_PORT0_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI0_CTRL1    0x0a01
+#define    RTL8367C_VLAN_MSTI0_CTRL1_PORT10_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI0_CTRL1_PORT10_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI0_CTRL1_PORT9_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI0_CTRL1_PORT9_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI0_CTRL1_PORT8_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI0_CTRL1_PORT8_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI1_CTRL0    0x0a02
+#define    RTL8367C_VLAN_MSTI1_CTRL0_PORT7_STATE_OFFSET    14
+#define    RTL8367C_VLAN_MSTI1_CTRL0_PORT7_STATE_MASK    0xC000
+#define    RTL8367C_VLAN_MSTI1_CTRL0_PORT6_STATE_OFFSET    12
+#define    RTL8367C_VLAN_MSTI1_CTRL0_PORT6_STATE_MASK    0x3000
+#define    RTL8367C_VLAN_MSTI1_CTRL0_PORT5_STATE_OFFSET    10
+#define    RTL8367C_VLAN_MSTI1_CTRL0_PORT5_STATE_MASK    0xC00
+#define    RTL8367C_VLAN_MSTI1_CTRL0_PORT4_STATE_OFFSET    8
+#define    RTL8367C_VLAN_MSTI1_CTRL0_PORT4_STATE_MASK    0x300
+#define    RTL8367C_VLAN_MSTI1_CTRL0_PORT3_STATE_OFFSET    6
+#define    RTL8367C_VLAN_MSTI1_CTRL0_PORT3_STATE_MASK    0xC0
+#define    RTL8367C_VLAN_MSTI1_CTRL0_PORT2_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI1_CTRL0_PORT2_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI1_CTRL0_PORT1_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI1_CTRL0_PORT1_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI1_CTRL0_PORT0_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI1_CTRL0_PORT0_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI1_CTRL1    0x0a03
+#define    RTL8367C_VLAN_MSTI1_CTRL1_PORT10_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI1_CTRL1_PORT10_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI1_CTRL1_PORT9_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI1_CTRL1_PORT9_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI1_CTRL1_PORT8_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI1_CTRL1_PORT8_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI2_CTRL0    0x0a04
+#define    RTL8367C_VLAN_MSTI2_CTRL0_PORT7_STATE_OFFSET    14
+#define    RTL8367C_VLAN_MSTI2_CTRL0_PORT7_STATE_MASK    0xC000
+#define    RTL8367C_VLAN_MSTI2_CTRL0_PORT6_STATE_OFFSET    12
+#define    RTL8367C_VLAN_MSTI2_CTRL0_PORT6_STATE_MASK    0x3000
+#define    RTL8367C_VLAN_MSTI2_CTRL0_PORT5_STATE_OFFSET    10
+#define    RTL8367C_VLAN_MSTI2_CTRL0_PORT5_STATE_MASK    0xC00
+#define    RTL8367C_VLAN_MSTI2_CTRL0_PORT4_STATE_OFFSET    8
+#define    RTL8367C_VLAN_MSTI2_CTRL0_PORT4_STATE_MASK    0x300
+#define    RTL8367C_VLAN_MSTI2_CTRL0_PORT3_STATE_OFFSET    6
+#define    RTL8367C_VLAN_MSTI2_CTRL0_PORT3_STATE_MASK    0xC0
+#define    RTL8367C_VLAN_MSTI2_CTRL0_PORT2_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI2_CTRL0_PORT2_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI2_CTRL0_PORT1_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI2_CTRL0_PORT1_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI2_CTRL0_PORT0_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI2_CTRL0_PORT0_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI2_CTRL1    0x0a05
+#define    RTL8367C_VLAN_MSTI2_CTRL1_PORT10_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI2_CTRL1_PORT10_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI2_CTRL1_PORT9_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI2_CTRL1_PORT9_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI2_CTRL1_PORT8_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI2_CTRL1_PORT8_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI3_CTRL0    0x0a06
+#define    RTL8367C_VLAN_MSTI3_CTRL0_PORT7_STATE_OFFSET    14
+#define    RTL8367C_VLAN_MSTI3_CTRL0_PORT7_STATE_MASK    0xC000
+#define    RTL8367C_VLAN_MSTI3_CTRL0_PORT6_STATE_OFFSET    12
+#define    RTL8367C_VLAN_MSTI3_CTRL0_PORT6_STATE_MASK    0x3000
+#define    RTL8367C_VLAN_MSTI3_CTRL0_PORT5_STATE_OFFSET    10
+#define    RTL8367C_VLAN_MSTI3_CTRL0_PORT5_STATE_MASK    0xC00
+#define    RTL8367C_VLAN_MSTI3_CTRL0_PORT4_STATE_OFFSET    8
+#define    RTL8367C_VLAN_MSTI3_CTRL0_PORT4_STATE_MASK    0x300
+#define    RTL8367C_VLAN_MSTI3_CTRL0_PORT3_STATE_OFFSET    6
+#define    RTL8367C_VLAN_MSTI3_CTRL0_PORT3_STATE_MASK    0xC0
+#define    RTL8367C_VLAN_MSTI3_CTRL0_PORT2_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI3_CTRL0_PORT2_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI3_CTRL0_PORT1_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI3_CTRL0_PORT1_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI3_CTRL0_PORT0_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI3_CTRL0_PORT0_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI3_CTRL1    0x0a07
+#define    RTL8367C_VLAN_MSTI3_CTRL1_PORT10_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI3_CTRL1_PORT10_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI3_CTRL1_PORT9_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI3_CTRL1_PORT9_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI3_CTRL1_PORT8_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI3_CTRL1_PORT8_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI4_CTRL0    0x0a08
+#define    RTL8367C_VLAN_MSTI4_CTRL0_PORT7_STATE_OFFSET    14
+#define    RTL8367C_VLAN_MSTI4_CTRL0_PORT7_STATE_MASK    0xC000
+#define    RTL8367C_VLAN_MSTI4_CTRL0_PORT6_STATE_OFFSET    12
+#define    RTL8367C_VLAN_MSTI4_CTRL0_PORT6_STATE_MASK    0x3000
+#define    RTL8367C_VLAN_MSTI4_CTRL0_PORT5_STATE_OFFSET    10
+#define    RTL8367C_VLAN_MSTI4_CTRL0_PORT5_STATE_MASK    0xC00
+#define    RTL8367C_VLAN_MSTI4_CTRL0_PORT4_STATE_OFFSET    8
+#define    RTL8367C_VLAN_MSTI4_CTRL0_PORT4_STATE_MASK    0x300
+#define    RTL8367C_VLAN_MSTI4_CTRL0_PORT3_STATE_OFFSET    6
+#define    RTL8367C_VLAN_MSTI4_CTRL0_PORT3_STATE_MASK    0xC0
+#define    RTL8367C_VLAN_MSTI4_CTRL0_PORT2_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI4_CTRL0_PORT2_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI4_CTRL0_PORT1_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI4_CTRL0_PORT1_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI4_CTRL0_PORT0_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI4_CTRL0_PORT0_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI4_CTRL1    0x0a09
+#define    RTL8367C_VLAN_MSTI4_CTRL1_PORT10_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI4_CTRL1_PORT10_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI4_CTRL1_PORT9_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI4_CTRL1_PORT9_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI4_CTRL1_PORT8_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI4_CTRL1_PORT8_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI5_CTRL0    0x0a0a
+#define    RTL8367C_VLAN_MSTI5_CTRL0_PORT7_STATE_OFFSET    14
+#define    RTL8367C_VLAN_MSTI5_CTRL0_PORT7_STATE_MASK    0xC000
+#define    RTL8367C_VLAN_MSTI5_CTRL0_PORT6_STATE_OFFSET    12
+#define    RTL8367C_VLAN_MSTI5_CTRL0_PORT6_STATE_MASK    0x3000
+#define    RTL8367C_VLAN_MSTI5_CTRL0_PORT5_STATE_OFFSET    10
+#define    RTL8367C_VLAN_MSTI5_CTRL0_PORT5_STATE_MASK    0xC00
+#define    RTL8367C_VLAN_MSTI5_CTRL0_PORT4_STATE_OFFSET    8
+#define    RTL8367C_VLAN_MSTI5_CTRL0_PORT4_STATE_MASK    0x300
+#define    RTL8367C_VLAN_MSTI5_CTRL0_PORT3_STATE_OFFSET    6
+#define    RTL8367C_VLAN_MSTI5_CTRL0_PORT3_STATE_MASK    0xC0
+#define    RTL8367C_VLAN_MSTI5_CTRL0_PORT2_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI5_CTRL0_PORT2_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI5_CTRL0_PORT1_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI5_CTRL0_PORT1_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI5_CTRL0_PORT0_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI5_CTRL0_PORT0_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI5_CTRL1    0x0a0b
+#define    RTL8367C_VLAN_MSTI5_CTRL1_PORT10_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI5_CTRL1_PORT10_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI5_CTRL1_PORT9_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI5_CTRL1_PORT9_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI5_CTRL1_PORT8_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI5_CTRL1_PORT8_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI6_CTRL0    0x0a0c
+#define    RTL8367C_VLAN_MSTI6_CTRL0_PORT7_STATE_OFFSET    14
+#define    RTL8367C_VLAN_MSTI6_CTRL0_PORT7_STATE_MASK    0xC000
+#define    RTL8367C_VLAN_MSTI6_CTRL0_PORT6_STATE_OFFSET    12
+#define    RTL8367C_VLAN_MSTI6_CTRL0_PORT6_STATE_MASK    0x3000
+#define    RTL8367C_VLAN_MSTI6_CTRL0_PORT5_STATE_OFFSET    10
+#define    RTL8367C_VLAN_MSTI6_CTRL0_PORT5_STATE_MASK    0xC00
+#define    RTL8367C_VLAN_MSTI6_CTRL0_PORT4_STATE_OFFSET    8
+#define    RTL8367C_VLAN_MSTI6_CTRL0_PORT4_STATE_MASK    0x300
+#define    RTL8367C_VLAN_MSTI6_CTRL0_PORT3_STATE_OFFSET    6
+#define    RTL8367C_VLAN_MSTI6_CTRL0_PORT3_STATE_MASK    0xC0
+#define    RTL8367C_VLAN_MSTI6_CTRL0_PORT2_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI6_CTRL0_PORT2_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI6_CTRL0_PORT1_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI6_CTRL0_PORT1_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI6_CTRL0_PORT0_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI6_CTRL0_PORT0_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI6_CTRL1    0x0a0d
+#define    RTL8367C_VLAN_MSTI6_CTRL1_PORT10_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI6_CTRL1_PORT10_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI6_CTRL1_PORT9_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI6_CTRL1_PORT9_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI6_CTRL1_PORT8_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI6_CTRL1_PORT8_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI7_CTRL0    0x0a0e
+#define    RTL8367C_VLAN_MSTI7_CTRL0_PORT7_STATE_OFFSET    14
+#define    RTL8367C_VLAN_MSTI7_CTRL0_PORT7_STATE_MASK    0xC000
+#define    RTL8367C_VLAN_MSTI7_CTRL0_PORT6_STATE_OFFSET    12
+#define    RTL8367C_VLAN_MSTI7_CTRL0_PORT6_STATE_MASK    0x3000
+#define    RTL8367C_VLAN_MSTI7_CTRL0_PORT5_STATE_OFFSET    10
+#define    RTL8367C_VLAN_MSTI7_CTRL0_PORT5_STATE_MASK    0xC00
+#define    RTL8367C_VLAN_MSTI7_CTRL0_PORT4_STATE_OFFSET    8
+#define    RTL8367C_VLAN_MSTI7_CTRL0_PORT4_STATE_MASK    0x300
+#define    RTL8367C_VLAN_MSTI7_CTRL0_PORT3_STATE_OFFSET    6
+#define    RTL8367C_VLAN_MSTI7_CTRL0_PORT3_STATE_MASK    0xC0
+#define    RTL8367C_VLAN_MSTI7_CTRL0_PORT2_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI7_CTRL0_PORT2_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI7_CTRL0_PORT1_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI7_CTRL0_PORT1_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI7_CTRL0_PORT0_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI7_CTRL0_PORT0_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI7_CTRL1    0x0a0f
+#define    RTL8367C_VLAN_MSTI7_CTRL1_PORT10_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI7_CTRL1_PORT10_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI7_CTRL1_PORT9_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI7_CTRL1_PORT9_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI7_CTRL1_PORT8_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI7_CTRL1_PORT8_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI8_CTRL0    0x0a10
+#define    RTL8367C_VLAN_MSTI8_CTRL0_PORT7_STATE_OFFSET    14
+#define    RTL8367C_VLAN_MSTI8_CTRL0_PORT7_STATE_MASK    0xC000
+#define    RTL8367C_VLAN_MSTI8_CTRL0_PORT6_STATE_OFFSET    12
+#define    RTL8367C_VLAN_MSTI8_CTRL0_PORT6_STATE_MASK    0x3000
+#define    RTL8367C_VLAN_MSTI8_CTRL0_PORT5_STATE_OFFSET    10
+#define    RTL8367C_VLAN_MSTI8_CTRL0_PORT5_STATE_MASK    0xC00
+#define    RTL8367C_VLAN_MSTI8_CTRL0_PORT4_STATE_OFFSET    8
+#define    RTL8367C_VLAN_MSTI8_CTRL0_PORT4_STATE_MASK    0x300
+#define    RTL8367C_VLAN_MSTI8_CTRL0_PORT3_STATE_OFFSET    6
+#define    RTL8367C_VLAN_MSTI8_CTRL0_PORT3_STATE_MASK    0xC0
+#define    RTL8367C_VLAN_MSTI8_CTRL0_PORT2_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI8_CTRL0_PORT2_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI8_CTRL0_PORT1_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI8_CTRL0_PORT1_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI8_CTRL0_PORT0_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI8_CTRL0_PORT0_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI8_CTRL1    0x0a11
+#define    RTL8367C_VLAN_MSTI8_CTRL1_PORT10_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI8_CTRL1_PORT10_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI8_CTRL1_PORT9_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI8_CTRL1_PORT9_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI8_CTRL1_PORT8_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI8_CTRL1_PORT8_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI9_CTRL0    0x0a12
+#define    RTL8367C_VLAN_MSTI9_CTRL0_PORT7_STATE_OFFSET    14
+#define    RTL8367C_VLAN_MSTI9_CTRL0_PORT7_STATE_MASK    0xC000
+#define    RTL8367C_VLAN_MSTI9_CTRL0_PORT6_STATE_OFFSET    12
+#define    RTL8367C_VLAN_MSTI9_CTRL0_PORT6_STATE_MASK    0x3000
+#define    RTL8367C_VLAN_MSTI9_CTRL0_PORT5_STATE_OFFSET    10
+#define    RTL8367C_VLAN_MSTI9_CTRL0_PORT5_STATE_MASK    0xC00
+#define    RTL8367C_VLAN_MSTI9_CTRL0_PORT4_STATE_OFFSET    8
+#define    RTL8367C_VLAN_MSTI9_CTRL0_PORT4_STATE_MASK    0x300
+#define    RTL8367C_VLAN_MSTI9_CTRL0_PORT3_STATE_OFFSET    6
+#define    RTL8367C_VLAN_MSTI9_CTRL0_PORT3_STATE_MASK    0xC0
+#define    RTL8367C_VLAN_MSTI9_CTRL0_PORT2_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI9_CTRL0_PORT2_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI9_CTRL0_PORT1_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI9_CTRL0_PORT1_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI9_CTRL0_PORT0_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI9_CTRL0_PORT0_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI9_CTRL1    0x0a13
+#define    RTL8367C_VLAN_MSTI9_CTRL1_PORT10_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI9_CTRL1_PORT10_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI9_CTRL1_PORT9_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI9_CTRL1_PORT9_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI9_CTRL1_PORT8_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI9_CTRL1_PORT8_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI10_CTRL0    0x0a14
+#define    RTL8367C_VLAN_MSTI10_CTRL0_PORT7_STATE_OFFSET    14
+#define    RTL8367C_VLAN_MSTI10_CTRL0_PORT7_STATE_MASK    0xC000
+#define    RTL8367C_VLAN_MSTI10_CTRL0_PORT6_STATE_OFFSET    12
+#define    RTL8367C_VLAN_MSTI10_CTRL0_PORT6_STATE_MASK    0x3000
+#define    RTL8367C_VLAN_MSTI10_CTRL0_PORT5_STATE_OFFSET    10
+#define    RTL8367C_VLAN_MSTI10_CTRL0_PORT5_STATE_MASK    0xC00
+#define    RTL8367C_VLAN_MSTI10_CTRL0_PORT4_STATE_OFFSET    8
+#define    RTL8367C_VLAN_MSTI10_CTRL0_PORT4_STATE_MASK    0x300
+#define    RTL8367C_VLAN_MSTI10_CTRL0_PORT3_STATE_OFFSET    6
+#define    RTL8367C_VLAN_MSTI10_CTRL0_PORT3_STATE_MASK    0xC0
+#define    RTL8367C_VLAN_MSTI10_CTRL0_PORT2_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI10_CTRL0_PORT2_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI10_CTRL0_PORT1_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI10_CTRL0_PORT1_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI10_CTRL0_PORT0_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI10_CTRL0_PORT0_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI10_CTRL1    0x0a15
+#define    RTL8367C_VLAN_MSTI10_CTRL1_PORT10_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI10_CTRL1_PORT10_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI10_CTRL1_PORT9_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI10_CTRL1_PORT9_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI10_CTRL1_PORT8_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI10_CTRL1_PORT8_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI11_CTRL0    0x0a16
+#define    RTL8367C_VLAN_MSTI11_CTRL0_PORT7_STATE_OFFSET    14
+#define    RTL8367C_VLAN_MSTI11_CTRL0_PORT7_STATE_MASK    0xC000
+#define    RTL8367C_VLAN_MSTI11_CTRL0_PORT6_STATE_OFFSET    12
+#define    RTL8367C_VLAN_MSTI11_CTRL0_PORT6_STATE_MASK    0x3000
+#define    RTL8367C_VLAN_MSTI11_CTRL0_PORT5_STATE_OFFSET    10
+#define    RTL8367C_VLAN_MSTI11_CTRL0_PORT5_STATE_MASK    0xC00
+#define    RTL8367C_VLAN_MSTI11_CTRL0_PORT4_STATE_OFFSET    8
+#define    RTL8367C_VLAN_MSTI11_CTRL0_PORT4_STATE_MASK    0x300
+#define    RTL8367C_VLAN_MSTI11_CTRL0_PORT3_STATE_OFFSET    6
+#define    RTL8367C_VLAN_MSTI11_CTRL0_PORT3_STATE_MASK    0xC0
+#define    RTL8367C_VLAN_MSTI11_CTRL0_PORT2_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI11_CTRL0_PORT2_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI11_CTRL0_PORT1_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI11_CTRL0_PORT1_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI11_CTRL0_PORT0_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI11_CTRL0_PORT0_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI11_CTRL1    0x0a17
+#define    RTL8367C_VLAN_MSTI11_CTRL1_PORT10_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI11_CTRL1_PORT10_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI11_CTRL1_PORT9_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI11_CTRL1_PORT9_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI11_CTRL1_PORT8_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI11_CTRL1_PORT8_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI12_CTRL0    0x0a18
+#define    RTL8367C_VLAN_MSTI12_CTRL0_PORT7_STATE_OFFSET    14
+#define    RTL8367C_VLAN_MSTI12_CTRL0_PORT7_STATE_MASK    0xC000
+#define    RTL8367C_VLAN_MSTI12_CTRL0_PORT6_STATE_OFFSET    12
+#define    RTL8367C_VLAN_MSTI12_CTRL0_PORT6_STATE_MASK    0x3000
+#define    RTL8367C_VLAN_MSTI12_CTRL0_PORT5_STATE_OFFSET    10
+#define    RTL8367C_VLAN_MSTI12_CTRL0_PORT5_STATE_MASK    0xC00
+#define    RTL8367C_VLAN_MSTI12_CTRL0_PORT4_STATE_OFFSET    8
+#define    RTL8367C_VLAN_MSTI12_CTRL0_PORT4_STATE_MASK    0x300
+#define    RTL8367C_VLAN_MSTI12_CTRL0_PORT3_STATE_OFFSET    6
+#define    RTL8367C_VLAN_MSTI12_CTRL0_PORT3_STATE_MASK    0xC0
+#define    RTL8367C_VLAN_MSTI12_CTRL0_PORT2_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI12_CTRL0_PORT2_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI12_CTRL0_PORT1_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI12_CTRL0_PORT1_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI12_CTRL0_PORT0_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI12_CTRL0_PORT0_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI12_CTRL1    0x0a19
+#define    RTL8367C_VLAN_MSTI12_CTRL1_PORT10_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI12_CTRL1_PORT10_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI12_CTRL1_PORT9_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI12_CTRL1_PORT9_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI12_CTRL1_PORT8_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI12_CTRL1_PORT8_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI13_CTRL0    0x0a1a
+#define    RTL8367C_VLAN_MSTI13_CTRL0_PORT7_STATE_OFFSET    14
+#define    RTL8367C_VLAN_MSTI13_CTRL0_PORT7_STATE_MASK    0xC000
+#define    RTL8367C_VLAN_MSTI13_CTRL0_PORT6_STATE_OFFSET    12
+#define    RTL8367C_VLAN_MSTI13_CTRL0_PORT6_STATE_MASK    0x3000
+#define    RTL8367C_VLAN_MSTI13_CTRL0_PORT5_STATE_OFFSET    10
+#define    RTL8367C_VLAN_MSTI13_CTRL0_PORT5_STATE_MASK    0xC00
+#define    RTL8367C_VLAN_MSTI13_CTRL0_PORT4_STATE_OFFSET    8
+#define    RTL8367C_VLAN_MSTI13_CTRL0_PORT4_STATE_MASK    0x300
+#define    RTL8367C_VLAN_MSTI13_CTRL0_PORT3_STATE_OFFSET    6
+#define    RTL8367C_VLAN_MSTI13_CTRL0_PORT3_STATE_MASK    0xC0
+#define    RTL8367C_VLAN_MSTI13_CTRL0_PORT2_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI13_CTRL0_PORT2_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI13_CTRL0_PORT1_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI13_CTRL0_PORT1_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI13_CTRL0_PORT0_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI13_CTRL0_PORT0_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI13_CTRL1    0x0a1b
+#define    RTL8367C_VLAN_MSTI13_CTRL1_PORT10_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI13_CTRL1_PORT10_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI13_CTRL1_PORT9_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI13_CTRL1_PORT9_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI13_CTRL1_PORT8_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI13_CTRL1_PORT8_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI14_CTRL0    0x0a1c
+#define    RTL8367C_VLAN_MSTI14_CTRL0_PORT7_STATE_OFFSET    14
+#define    RTL8367C_VLAN_MSTI14_CTRL0_PORT7_STATE_MASK    0xC000
+#define    RTL8367C_VLAN_MSTI14_CTRL0_PORT6_STATE_OFFSET    12
+#define    RTL8367C_VLAN_MSTI14_CTRL0_PORT6_STATE_MASK    0x3000
+#define    RTL8367C_VLAN_MSTI14_CTRL0_PORT5_STATE_OFFSET    10
+#define    RTL8367C_VLAN_MSTI14_CTRL0_PORT5_STATE_MASK    0xC00
+#define    RTL8367C_VLAN_MSTI14_CTRL0_PORT4_STATE_OFFSET    8
+#define    RTL8367C_VLAN_MSTI14_CTRL0_PORT4_STATE_MASK    0x300
+#define    RTL8367C_VLAN_MSTI14_CTRL0_PORT3_STATE_OFFSET    6
+#define    RTL8367C_VLAN_MSTI14_CTRL0_PORT3_STATE_MASK    0xC0
+#define    RTL8367C_VLAN_MSTI14_CTRL0_PORT2_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI14_CTRL0_PORT2_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI14_CTRL0_PORT1_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI14_CTRL0_PORT1_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI14_CTRL0_PORT0_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI14_CTRL0_PORT0_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI14_CTRL1    0x0a1d
+#define    RTL8367C_VLAN_MSTI14_CTRL1_PORT10_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI14_CTRL1_PORT10_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI14_CTRL1_PORT9_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI14_CTRL1_PORT9_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI14_CTRL1_PORT8_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI14_CTRL1_PORT8_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI15_CTRL0    0x0a1e
+#define    RTL8367C_VLAN_MSTI15_CTRL0_PORT7_STATE_OFFSET    14
+#define    RTL8367C_VLAN_MSTI15_CTRL0_PORT7_STATE_MASK    0xC000
+#define    RTL8367C_VLAN_MSTI15_CTRL0_PORT6_STATE_OFFSET    12
+#define    RTL8367C_VLAN_MSTI15_CTRL0_PORT6_STATE_MASK    0x3000
+#define    RTL8367C_VLAN_MSTI15_CTRL0_PORT5_STATE_OFFSET    10
+#define    RTL8367C_VLAN_MSTI15_CTRL0_PORT5_STATE_MASK    0xC00
+#define    RTL8367C_VLAN_MSTI15_CTRL0_PORT4_STATE_OFFSET    8
+#define    RTL8367C_VLAN_MSTI15_CTRL0_PORT4_STATE_MASK    0x300
+#define    RTL8367C_VLAN_MSTI15_CTRL0_PORT3_STATE_OFFSET    6
+#define    RTL8367C_VLAN_MSTI15_CTRL0_PORT3_STATE_MASK    0xC0
+#define    RTL8367C_VLAN_MSTI15_CTRL0_PORT2_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI15_CTRL0_PORT2_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI15_CTRL0_PORT1_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI15_CTRL0_PORT1_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI15_CTRL0_PORT0_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI15_CTRL0_PORT0_STATE_MASK    0x3
+
+#define    RTL8367C_REG_VLAN_MSTI15_CTRL1    0x0a1f
+#define    RTL8367C_VLAN_MSTI15_CTRL1_PORT10_STATE_OFFSET    4
+#define    RTL8367C_VLAN_MSTI15_CTRL1_PORT10_STATE_MASK    0x30
+#define    RTL8367C_VLAN_MSTI15_CTRL1_PORT9_STATE_OFFSET    2
+#define    RTL8367C_VLAN_MSTI15_CTRL1_PORT9_STATE_MASK    0xC
+#define    RTL8367C_VLAN_MSTI15_CTRL1_PORT8_STATE_OFFSET    0
+#define    RTL8367C_VLAN_MSTI15_CTRL1_PORT8_STATE_MASK    0x3
+
+#define    RTL8367C_REG_LUT_PORT0_LEARN_LIMITNO    0x0a20
+#define    RTL8367C_LUT_PORT0_LEARN_LIMITNO_OFFSET    0
+#define    RTL8367C_LUT_PORT0_LEARN_LIMITNO_MASK    0x1FFF
+
+#define    RTL8367C_REG_LUT_PORT1_LEARN_LIMITNO    0x0a21
+#define    RTL8367C_LUT_PORT1_LEARN_LIMITNO_OFFSET    0
+#define    RTL8367C_LUT_PORT1_LEARN_LIMITNO_MASK    0x1FFF
+
+#define    RTL8367C_REG_LUT_PORT2_LEARN_LIMITNO    0x0a22
+#define    RTL8367C_LUT_PORT2_LEARN_LIMITNO_OFFSET    0
+#define    RTL8367C_LUT_PORT2_LEARN_LIMITNO_MASK    0x1FFF
+
+#define    RTL8367C_REG_LUT_PORT3_LEARN_LIMITNO    0x0a23
+#define    RTL8367C_LUT_PORT3_LEARN_LIMITNO_OFFSET    0
+#define    RTL8367C_LUT_PORT3_LEARN_LIMITNO_MASK    0x1FFF
+
+#define    RTL8367C_REG_LUT_PORT4_LEARN_LIMITNO    0x0a24
+#define    RTL8367C_LUT_PORT4_LEARN_LIMITNO_OFFSET    0
+#define    RTL8367C_LUT_PORT4_LEARN_LIMITNO_MASK    0x1FFF
+
+#define    RTL8367C_REG_LUT_PORT5_LEARN_LIMITNO    0x0a25
+#define    RTL8367C_LUT_PORT5_LEARN_LIMITNO_OFFSET    0
+#define    RTL8367C_LUT_PORT5_LEARN_LIMITNO_MASK    0x1FFF
+
+#define    RTL8367C_REG_LUT_PORT6_LEARN_LIMITNO    0x0a26
+#define    RTL8367C_LUT_PORT6_LEARN_LIMITNO_OFFSET    0
+#define    RTL8367C_LUT_PORT6_LEARN_LIMITNO_MASK    0x1FFF
+
+#define    RTL8367C_REG_LUT_PORT7_LEARN_LIMITNO    0x0a27
+#define    RTL8367C_LUT_PORT7_LEARN_LIMITNO_OFFSET    0
+#define    RTL8367C_LUT_PORT7_LEARN_LIMITNO_MASK    0x1FFF
+
+#define    RTL8367C_REG_LUT_SYS_LEARN_LIMITNO    0x0a28
+#define    RTL8367C_LUT_SYS_LEARN_LIMITNO_OFFSET    0
+#define    RTL8367C_LUT_SYS_LEARN_LIMITNO_MASK    0x1FFF
+
+#define    RTL8367C_REG_LUT_LRN_SYS_LMT_CTRL    0x0a29
+#define    RTL8367C_LUT_SYSTEM_LEARN_PMASK1_OFFSET    12
+#define    RTL8367C_LUT_SYSTEM_LEARN_PMASK1_MASK    0x7000
+#define    RTL8367C_LUT_SYSTEM_LEARN_OVER_ACT_OFFSET    10
+#define    RTL8367C_LUT_SYSTEM_LEARN_OVER_ACT_MASK    0xC00
+#define    RTL8367C_LUT_SYSTEM_LEARN_PMASK_OFFSET    0
+#define    RTL8367C_LUT_SYSTEM_LEARN_PMASK_MASK    0xFF
+
+#define    RTL8367C_REG_LUT_PORT8_LEARN_LIMITNO    0x0a2a
+#define    RTL8367C_LUT_PORT8_LEARN_LIMITNO_OFFSET    0
+#define    RTL8367C_LUT_PORT8_LEARN_LIMITNO_MASK    0x1FFF
+
+#define    RTL8367C_REG_LUT_PORT9_LEARN_LIMITNO    0x0a2b
+#define    RTL8367C_LUT_PORT9_LEARN_LIMITNO_OFFSET    0
+#define    RTL8367C_LUT_PORT9_LEARN_LIMITNO_MASK    0x1FFF
+
+#define    RTL8367C_REG_LUT_PORT10_LEARN_LIMITNO    0x0a2c
+#define    RTL8367C_LUT_PORT10_LEARN_LIMITNO_OFFSET    0
+#define    RTL8367C_LUT_PORT10_LEARN_LIMITNO_MASK    0x1FFF
+
+#define    RTL8367C_REG_LUT_CFG    0x0a30
+#define    RTL8367C_AGE_SPEED_OFFSET    8
+#define    RTL8367C_AGE_SPEED_MASK    0x300
+#define    RTL8367C_BCAM_DISABLE_OFFSET    6
+#define    RTL8367C_BCAM_DISABLE_MASK    0x40
+#define    RTL8367C_LINKDOWN_AGEOUT_OFFSET    5
+#define    RTL8367C_LINKDOWN_AGEOUT_MASK    0x20
+#define    RTL8367C_LUT_IPMC_HASH_OFFSET    4
+#define    RTL8367C_LUT_IPMC_HASH_MASK    0x10
+#define    RTL8367C_LUT_IPMC_LOOKUP_OP_OFFSET    3
+#define    RTL8367C_LUT_IPMC_LOOKUP_OP_MASK    0x8
+#define    RTL8367C_AGE_TIMER_OFFSET    0
+#define    RTL8367C_AGE_TIMER_MASK    0x7
+
+#define    RTL8367C_REG_LUT_AGEOUT_CTRL    0x0a31
+#define    RTL8367C_LUT_AGEOUT_CTRL_OFFSET    0
+#define    RTL8367C_LUT_AGEOUT_CTRL_MASK    0x7FF
+
+#define    RTL8367C_REG_PORT_EFID_CTRL0    0x0a32
+#define    RTL8367C_PORT3_EFID_OFFSET    12
+#define    RTL8367C_PORT3_EFID_MASK    0x7000
+#define    RTL8367C_PORT2_EFID_OFFSET    8
+#define    RTL8367C_PORT2_EFID_MASK    0x700
+#define    RTL8367C_PORT1_EFID_OFFSET    4
+#define    RTL8367C_PORT1_EFID_MASK    0x70
+#define    RTL8367C_PORT0_EFID_OFFSET    0
+#define    RTL8367C_PORT0_EFID_MASK    0x7
+
+#define    RTL8367C_REG_PORT_EFID_CTRL1    0x0a33
+#define    RTL8367C_PORT7_EFID_OFFSET    12
+#define    RTL8367C_PORT7_EFID_MASK    0x7000
+#define    RTL8367C_PORT6_EFID_OFFSET    8
+#define    RTL8367C_PORT6_EFID_MASK    0x700
+#define    RTL8367C_PORT5_EFID_OFFSET    4
+#define    RTL8367C_PORT5_EFID_MASK    0x70
+#define    RTL8367C_PORT4_EFID_OFFSET    0
+#define    RTL8367C_PORT4_EFID_MASK    0x7
+
+#define    RTL8367C_REG_PORT_EFID_CTRL2    0x0a34
+#define    RTL8367C_PORT10_EFID_OFFSET    8
+#define    RTL8367C_PORT10_EFID_MASK    0x700
+#define    RTL8367C_PORT9_EFID_OFFSET    4
+#define    RTL8367C_PORT9_EFID_MASK    0x70
+#define    RTL8367C_PORT8_EFID_OFFSET    0
+#define    RTL8367C_PORT8_EFID_MASK    0x7
+
+#define    RTL8367C_REG_FORCE_FLUSH1    0x0a35
+#define    RTL8367C_BUSY_STATUS1_OFFSET    3
+#define    RTL8367C_BUSY_STATUS1_MASK    0x38
+#define    RTL8367C_PORTMASK1_OFFSET    0
+#define    RTL8367C_PORTMASK1_MASK    0x7
+
+#define    RTL8367C_REG_FORCE_FLUSH    0x0a36
+#define    RTL8367C_BUSY_STATUS_OFFSET    8
+#define    RTL8367C_BUSY_STATUS_MASK    0xFF00
+#define    RTL8367C_FORCE_FLUSH_PORTMASK_OFFSET    0
+#define    RTL8367C_FORCE_FLUSH_PORTMASK_MASK    0xFF
+
+#define    RTL8367C_REG_L2_FLUSH_CTRL1    0x0a37
+#define    RTL8367C_LUT_FLUSH_FID_OFFSET    12
+#define    RTL8367C_LUT_FLUSH_FID_MASK    0xF000
+#define    RTL8367C_LUT_FLUSH_VID_OFFSET    0
+#define    RTL8367C_LUT_FLUSH_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_L2_FLUSH_CTRL2    0x0a38
+#define    RTL8367C_LUT_FLUSH_TYPE_OFFSET    2
+#define    RTL8367C_LUT_FLUSH_TYPE_MASK    0x4
+#define    RTL8367C_LUT_FLUSH_MODE_OFFSET    0
+#define    RTL8367C_LUT_FLUSH_MODE_MASK    0x3
+
+#define    RTL8367C_REG_L2_FLUSH_CTRL3    0x0a39
+#define    RTL8367C_L2_FLUSH_CTRL3_OFFSET    0
+#define    RTL8367C_L2_FLUSH_CTRL3_MASK    0x1
+
+#define    RTL8367C_REG_LUT_CFG2    0x0a3a
+#define    RTL8367C_LUT_IPMC_FWD_RPORT_OFFSET    1
+#define    RTL8367C_LUT_IPMC_FWD_RPORT_MASK    0x2
+#define    RTL8367C_LUT_IPMC_VID_HASH_OFFSET    0
+#define    RTL8367C_LUT_IPMC_VID_HASH_MASK    0x1
+
+#define    RTL8367C_REG_FLUSH_STATUS    0x0a3f
+#define    RTL8367C_FLUSH_STATUS_OFFSET    0
+#define    RTL8367C_FLUSH_STATUS_MASK    0x1
+
+#define    RTL8367C_REG_STORM_BCAST    0x0a40
+#define    RTL8367C_STORM_BCAST_OFFSET    0
+#define    RTL8367C_STORM_BCAST_MASK    0x7FF
+
+#define    RTL8367C_REG_STORM_MCAST    0x0a41
+#define    RTL8367C_STORM_MCAST_OFFSET    0
+#define    RTL8367C_STORM_MCAST_MASK    0x7FF
+
+#define    RTL8367C_REG_STORM_UNKOWN_UCAST    0x0a42
+#define    RTL8367C_STORM_UNKOWN_UCAST_OFFSET    0
+#define    RTL8367C_STORM_UNKOWN_UCAST_MASK    0x7FF
+
+#define    RTL8367C_REG_STORM_UNKOWN_MCAST    0x0a43
+#define    RTL8367C_STORM_UNKOWN_MCAST_OFFSET    0
+#define    RTL8367C_STORM_UNKOWN_MCAST_MASK    0x7FF
+
+#define    RTL8367C_REG_STORM_BCAST_METER_CTRL0    0x0a44
+#define    RTL8367C_STORM_BCAST_METER_CTRL0_PORT1_METERIDX_OFFSET    8
+#define    RTL8367C_STORM_BCAST_METER_CTRL0_PORT1_METERIDX_MASK    0x3F00
+#define    RTL8367C_STORM_BCAST_METER_CTRL0_PORT0_METERIDX_OFFSET    0
+#define    RTL8367C_STORM_BCAST_METER_CTRL0_PORT0_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_BCAST_METER_CTRL1    0x0a45
+#define    RTL8367C_STORM_BCAST_METER_CTRL1_PORT3_METERIDX_OFFSET    8
+#define    RTL8367C_STORM_BCAST_METER_CTRL1_PORT3_METERIDX_MASK    0x3F00
+#define    RTL8367C_STORM_BCAST_METER_CTRL1_PORT2_METERIDX_OFFSET    0
+#define    RTL8367C_STORM_BCAST_METER_CTRL1_PORT2_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_BCAST_METER_CTRL2    0x0a46
+#define    RTL8367C_STORM_BCAST_METER_CTRL2_PORT5_METERIDX_OFFSET    8
+#define    RTL8367C_STORM_BCAST_METER_CTRL2_PORT5_METERIDX_MASK    0x3F00
+#define    RTL8367C_STORM_BCAST_METER_CTRL2_PORT4_METERIDX_OFFSET    0
+#define    RTL8367C_STORM_BCAST_METER_CTRL2_PORT4_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_BCAST_METER_CTRL3    0x0a47
+#define    RTL8367C_STORM_BCAST_METER_CTRL3_PORT7_METERIDX_OFFSET    8
+#define    RTL8367C_STORM_BCAST_METER_CTRL3_PORT7_METERIDX_MASK    0x3F00
+#define    RTL8367C_STORM_BCAST_METER_CTRL3_PORT6_METERIDX_OFFSET    0
+#define    RTL8367C_STORM_BCAST_METER_CTRL3_PORT6_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_BCAST_METER_CTRL4    0x0a48
+#define    RTL8367C_STORM_BCAST_METER_CTRL4_PORT9_METERIDX_OFFSET    8
+#define    RTL8367C_STORM_BCAST_METER_CTRL4_PORT9_METERIDX_MASK    0x3F00
+#define    RTL8367C_STORM_BCAST_METER_CTRL4_PORT8_METERIDX_OFFSET    0
+#define    RTL8367C_STORM_BCAST_METER_CTRL4_PORT8_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_BCAST_METER_CTRL5    0x0a49
+#define    RTL8367C_STORM_BCAST_METER_CTRL5_OFFSET    0
+#define    RTL8367C_STORM_BCAST_METER_CTRL5_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_MCAST_METER_CTRL0    0x0a4c
+#define    RTL8367C_STORM_MCAST_METER_CTRL0_PORT1_METERIDX_OFFSET    8
+#define    RTL8367C_STORM_MCAST_METER_CTRL0_PORT1_METERIDX_MASK    0x3F00
+#define    RTL8367C_STORM_MCAST_METER_CTRL0_PORT0_METERIDX_OFFSET    0
+#define    RTL8367C_STORM_MCAST_METER_CTRL0_PORT0_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_MCAST_METER_CTRL1    0x0a4d
+#define    RTL8367C_STORM_MCAST_METER_CTRL1_PORT3_METERIDX_OFFSET    8
+#define    RTL8367C_STORM_MCAST_METER_CTRL1_PORT3_METERIDX_MASK    0x3F00
+#define    RTL8367C_STORM_MCAST_METER_CTRL1_PORT2_METERIDX_OFFSET    0
+#define    RTL8367C_STORM_MCAST_METER_CTRL1_PORT2_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_MCAST_METER_CTRL2    0x0a4e
+#define    RTL8367C_STORM_MCAST_METER_CTRL2_PORT5_METERIDX_OFFSET    8
+#define    RTL8367C_STORM_MCAST_METER_CTRL2_PORT5_METERIDX_MASK    0x3F00
+#define    RTL8367C_STORM_MCAST_METER_CTRL2_PORT4_METERIDX_OFFSET    0
+#define    RTL8367C_STORM_MCAST_METER_CTRL2_PORT4_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_MCAST_METER_CTRL3    0x0a4f
+#define    RTL8367C_STORM_MCAST_METER_CTRL3_PORT7_METERIDX_OFFSET    8
+#define    RTL8367C_STORM_MCAST_METER_CTRL3_PORT7_METERIDX_MASK    0x3F00
+#define    RTL8367C_STORM_MCAST_METER_CTRL3_PORT6_METERIDX_OFFSET    0
+#define    RTL8367C_STORM_MCAST_METER_CTRL3_PORT6_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_MCAST_METER_CTRL4    0x0a50
+#define    RTL8367C_STORM_MCAST_METER_CTRL4_PORT9_METERIDX_OFFSET    8
+#define    RTL8367C_STORM_MCAST_METER_CTRL4_PORT9_METERIDX_MASK    0x3F00
+#define    RTL8367C_STORM_MCAST_METER_CTRL4_PORT8_METERIDX_OFFSET    0
+#define    RTL8367C_STORM_MCAST_METER_CTRL4_PORT8_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_MCAST_METER_CTRL5    0x0a51
+#define    RTL8367C_STORM_MCAST_METER_CTRL5_OFFSET    0
+#define    RTL8367C_STORM_MCAST_METER_CTRL5_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_UNDA_METER_CTRL0    0x0a54
+#define    RTL8367C_STORM_UNDA_METER_CTRL0_PORT1_METERIDX_OFFSET    8
+#define    RTL8367C_STORM_UNDA_METER_CTRL0_PORT1_METERIDX_MASK    0x3F00
+#define    RTL8367C_STORM_UNDA_METER_CTRL0_PORT0_METERIDX_OFFSET    0
+#define    RTL8367C_STORM_UNDA_METER_CTRL0_PORT0_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_UNDA_METER_CTRL1    0x0a55
+#define    RTL8367C_STORM_UNDA_METER_CTRL1_PORT3_METERIDX_OFFSET    8
+#define    RTL8367C_STORM_UNDA_METER_CTRL1_PORT3_METERIDX_MASK    0x3F00
+#define    RTL8367C_STORM_UNDA_METER_CTRL1_PORT2_METERIDX_OFFSET    0
+#define    RTL8367C_STORM_UNDA_METER_CTRL1_PORT2_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_UNDA_METER_CTRL2    0x0a56
+#define    RTL8367C_STORM_UNDA_METER_CTRL2_PORT5_METERIDX_OFFSET    8
+#define    RTL8367C_STORM_UNDA_METER_CTRL2_PORT5_METERIDX_MASK    0x3F00
+#define    RTL8367C_STORM_UNDA_METER_CTRL2_PORT4_METERIDX_OFFSET    0
+#define    RTL8367C_STORM_UNDA_METER_CTRL2_PORT4_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_UNDA_METER_CTRL3    0x0a57
+#define    RTL8367C_STORM_UNDA_METER_CTRL3_PORT7_METERIDX_OFFSET    8
+#define    RTL8367C_STORM_UNDA_METER_CTRL3_PORT7_METERIDX_MASK    0x3F00
+#define    RTL8367C_STORM_UNDA_METER_CTRL3_PORT6_METERIDX_OFFSET    0
+#define    RTL8367C_STORM_UNDA_METER_CTRL3_PORT6_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_UNDA_METER_CTRL4    0x0a58
+#define    RTL8367C_STORM_UNDA_METER_CTRL4_PORT9_METERIDX_OFFSET    8
+#define    RTL8367C_STORM_UNDA_METER_CTRL4_PORT9_METERIDX_MASK    0x3F00
+#define    RTL8367C_STORM_UNDA_METER_CTRL4_PORT8_METERIDX_OFFSET    0
+#define    RTL8367C_STORM_UNDA_METER_CTRL4_PORT8_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_UNDA_METER_CTRL5    0x0a59
+#define    RTL8367C_STORM_UNDA_METER_CTRL5_OFFSET    0
+#define    RTL8367C_STORM_UNDA_METER_CTRL5_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_UNMC_METER_CTRL0    0x0a5c
+#define    RTL8367C_STORM_UNMC_METER_CTRL0_PORT1_METERIDX_OFFSET    8
+#define    RTL8367C_STORM_UNMC_METER_CTRL0_PORT1_METERIDX_MASK    0x3F00
+#define    RTL8367C_STORM_UNMC_METER_CTRL0_PORT0_METERIDX_OFFSET    0
+#define    RTL8367C_STORM_UNMC_METER_CTRL0_PORT0_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_UNMC_METER_CTRL1    0x0a5d
+#define    RTL8367C_STORM_UNMC_METER_CTRL1_PORT3_METERIDX_OFFSET    8
+#define    RTL8367C_STORM_UNMC_METER_CTRL1_PORT3_METERIDX_MASK    0x3F00
+#define    RTL8367C_STORM_UNMC_METER_CTRL1_PORT2_METERIDX_OFFSET    0
+#define    RTL8367C_STORM_UNMC_METER_CTRL1_PORT2_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_UNMC_METER_CTRL2    0x0a5e
+#define    RTL8367C_STORM_UNMC_METER_CTRL2_PORT5_METERIDX_OFFSET    8
+#define    RTL8367C_STORM_UNMC_METER_CTRL2_PORT5_METERIDX_MASK    0x3F00
+#define    RTL8367C_STORM_UNMC_METER_CTRL2_PORT4_METERIDX_OFFSET    0
+#define    RTL8367C_STORM_UNMC_METER_CTRL2_PORT4_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_UNMC_METER_CTRL3    0x0a5f
+#define    RTL8367C_STORM_UNMC_METER_CTRL3_PORT7_METERIDX_OFFSET    8
+#define    RTL8367C_STORM_UNMC_METER_CTRL3_PORT7_METERIDX_MASK    0x3F00
+#define    RTL8367C_STORM_UNMC_METER_CTRL3_PORT6_METERIDX_OFFSET    0
+#define    RTL8367C_STORM_UNMC_METER_CTRL3_PORT6_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_EXT_CFG    0x0a60
+#define    RTL8367C_STORM_EXT_EN_PORTMASK_EXT_OFFSET    14
+#define    RTL8367C_STORM_EXT_EN_PORTMASK_EXT_MASK    0x4000
+#define    RTL8367C_STORM_UNKNOWN_MCAST_EXT_EN_OFFSET    13
+#define    RTL8367C_STORM_UNKNOWN_MCAST_EXT_EN_MASK    0x2000
+#define    RTL8367C_STORM_UNKNOWN_UCAST_EXT_EN_OFFSET    12
+#define    RTL8367C_STORM_UNKNOWN_UCAST_EXT_EN_MASK    0x1000
+#define    RTL8367C_STORM_MCAST_EXT_EN_OFFSET    11
+#define    RTL8367C_STORM_MCAST_EXT_EN_MASK    0x800
+#define    RTL8367C_STORM_BCAST_EXT_EN_OFFSET    10
+#define    RTL8367C_STORM_BCAST_EXT_EN_MASK    0x400
+#define    RTL8367C_STORM_EXT_EN_PORTMASK_OFFSET    0
+#define    RTL8367C_STORM_EXT_EN_PORTMASK_MASK    0x3FF
+
+#define    RTL8367C_REG_STORM_EXT_MTRIDX_CFG0    0x0a61
+#define    RTL8367C_MC_STORM_EXT_METERIDX_OFFSET    8
+#define    RTL8367C_MC_STORM_EXT_METERIDX_MASK    0x3F00
+#define    RTL8367C_BC_STORM_EXT_METERIDX_OFFSET    0
+#define    RTL8367C_BC_STORM_EXT_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_EXT_MTRIDX_CFG1    0x0a62
+#define    RTL8367C_UNMC_STORM_EXT_METERIDX_OFFSET    8
+#define    RTL8367C_UNMC_STORM_EXT_METERIDX_MASK    0x3F00
+#define    RTL8367C_UNUC_STORM_EXT_METERIDX_OFFSET    0
+#define    RTL8367C_UNUC_STORM_EXT_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_UNMC_METER_CTRL4    0x0a63
+#define    RTL8367C_STORM_UNMC_METER_CTRL4_PORT9_METERIDX_OFFSET    8
+#define    RTL8367C_STORM_UNMC_METER_CTRL4_PORT9_METERIDX_MASK    0x3F00
+#define    RTL8367C_STORM_UNMC_METER_CTRL4_PORT8_METERIDX_OFFSET    0
+#define    RTL8367C_STORM_UNMC_METER_CTRL4_PORT8_METERIDX_MASK    0x3F
+
+#define    RTL8367C_REG_STORM_UNMC_METER_CTRL5    0x0a64
+#define    RTL8367C_STORM_UNMC_METER_CTRL5_OFFSET    0
+#define    RTL8367C_STORM_UNMC_METER_CTRL5_MASK    0x3F
+
+#define    RTL8367C_REG_OAM_PARSER_CTRL0    0x0a70
+#define    RTL8367C_PORT7_PARACT_OFFSET    14
+#define    RTL8367C_PORT7_PARACT_MASK    0xC000
+#define    RTL8367C_PORT6_PARACT_OFFSET    12
+#define    RTL8367C_PORT6_PARACT_MASK    0x3000
+#define    RTL8367C_PORT5_PARACT_OFFSET    10
+#define    RTL8367C_PORT5_PARACT_MASK    0xC00
+#define    RTL8367C_PORT4_PARACT_OFFSET    8
+#define    RTL8367C_PORT4_PARACT_MASK    0x300
+#define    RTL8367C_PORT3_PARACT_OFFSET    6
+#define    RTL8367C_PORT3_PARACT_MASK    0xC0
+#define    RTL8367C_PORT2_PARACT_OFFSET    4
+#define    RTL8367C_PORT2_PARACT_MASK    0x30
+#define    RTL8367C_PORT1_PARACT_OFFSET    2
+#define    RTL8367C_PORT1_PARACT_MASK    0xC
+#define    RTL8367C_PORT0_PARACT_OFFSET    0
+#define    RTL8367C_PORT0_PARACT_MASK    0x3
+
+#define    RTL8367C_REG_OAM_PARSER_CTRL1    0x0a71
+#define    RTL8367C_PORT10_PARACT_OFFSET    4
+#define    RTL8367C_PORT10_PARACT_MASK    0x30
+#define    RTL8367C_PORT9_PARACT_OFFSET    2
+#define    RTL8367C_PORT9_PARACT_MASK    0xC
+#define    RTL8367C_PORT8_PARACT_OFFSET    0
+#define    RTL8367C_PORT8_PARACT_MASK    0x3
+
+#define    RTL8367C_REG_OAM_MULTIPLEXER_CTRL0    0x0a72
+#define    RTL8367C_PORT7_MULACT_OFFSET    14
+#define    RTL8367C_PORT7_MULACT_MASK    0xC000
+#define    RTL8367C_PORT6_MULACT_OFFSET    12
+#define    RTL8367C_PORT6_MULACT_MASK    0x3000
+#define    RTL8367C_PORT5_MULACT_OFFSET    10
+#define    RTL8367C_PORT5_MULACT_MASK    0xC00
+#define    RTL8367C_PORT4_MULACT_OFFSET    8
+#define    RTL8367C_PORT4_MULACT_MASK    0x300
+#define    RTL8367C_PORT3_MULACT_OFFSET    6
+#define    RTL8367C_PORT3_MULACT_MASK    0xC0
+#define    RTL8367C_PORT2_MULACT_OFFSET    4
+#define    RTL8367C_PORT2_MULACT_MASK    0x30
+#define    RTL8367C_PORT1_MULACT_OFFSET    2
+#define    RTL8367C_PORT1_MULACT_MASK    0xC
+#define    RTL8367C_PORT0_MULACT_OFFSET    0
+#define    RTL8367C_PORT0_MULACT_MASK    0x3
+
+#define    RTL8367C_REG_OAM_MULTIPLEXER_CTRL1    0x0a73
+#define    RTL8367C_PORT10_MULACT_OFFSET    4
+#define    RTL8367C_PORT10_MULACT_MASK    0x30
+#define    RTL8367C_PORT9_MULACT_OFFSET    2
+#define    RTL8367C_PORT9_MULACT_MASK    0xC
+#define    RTL8367C_PORT8_MULACT_OFFSET    0
+#define    RTL8367C_PORT8_MULACT_MASK    0x3
+
+#define    RTL8367C_REG_OAM_CTRL    0x0a74
+#define    RTL8367C_OAM_CTRL_OFFSET    0
+#define    RTL8367C_OAM_CTRL_MASK    0x1
+
+#define    RTL8367C_REG_DOT1X_PORT_ENABLE    0x0a80
+#define    RTL8367C_DOT1X_PORT_ENABLE_OFFSET    0
+#define    RTL8367C_DOT1X_PORT_ENABLE_MASK    0x7FF
+
+#define    RTL8367C_REG_DOT1X_MAC_ENABLE    0x0a81
+#define    RTL8367C_DOT1X_MAC_ENABLE_OFFSET    0
+#define    RTL8367C_DOT1X_MAC_ENABLE_MASK    0x7FF
+
+#define    RTL8367C_REG_DOT1X_PORT_AUTH    0x0a82
+#define    RTL8367C_DOT1X_PORT_AUTH_OFFSET    0
+#define    RTL8367C_DOT1X_PORT_AUTH_MASK    0x7FF
+
+#define    RTL8367C_REG_DOT1X_PORT_OPDIR    0x0a83
+#define    RTL8367C_DOT1X_PORT_OPDIR_OFFSET    0
+#define    RTL8367C_DOT1X_PORT_OPDIR_MASK    0x7FF
+
+#define    RTL8367C_REG_DOT1X_UNAUTH_ACT_W0    0x0a84
+#define    RTL8367C_DOT1X_PORT7_UNAUTHBH_OFFSET    14
+#define    RTL8367C_DOT1X_PORT7_UNAUTHBH_MASK    0xC000
+#define    RTL8367C_DOT1X_PORT6_UNAUTHBH_OFFSET    12
+#define    RTL8367C_DOT1X_PORT6_UNAUTHBH_MASK    0x3000
+#define    RTL8367C_DOT1X_PORT5_UNAUTHBH_OFFSET    10
+#define    RTL8367C_DOT1X_PORT5_UNAUTHBH_MASK    0xC00
+#define    RTL8367C_DOT1X_PORT4_UNAUTHBH_OFFSET    8
+#define    RTL8367C_DOT1X_PORT4_UNAUTHBH_MASK    0x300
+#define    RTL8367C_DOT1X_PORT3_UNAUTHBH_OFFSET    6
+#define    RTL8367C_DOT1X_PORT3_UNAUTHBH_MASK    0xC0
+#define    RTL8367C_DOT1X_PORT2_UNAUTHBH_OFFSET    4
+#define    RTL8367C_DOT1X_PORT2_UNAUTHBH_MASK    0x30
+#define    RTL8367C_DOT1X_PORT1_UNAUTHBH_OFFSET    2
+#define    RTL8367C_DOT1X_PORT1_UNAUTHBH_MASK    0xC
+#define    RTL8367C_DOT1X_PORT0_UNAUTHBH_OFFSET    0
+#define    RTL8367C_DOT1X_PORT0_UNAUTHBH_MASK    0x3
+
+#define    RTL8367C_REG_DOT1X_UNAUTH_ACT_W1    0x0a85
+#define    RTL8367C_DOT1X_PORT10_UNAUTHBH_OFFSET    4
+#define    RTL8367C_DOT1X_PORT10_UNAUTHBH_MASK    0x30
+#define    RTL8367C_DOT1X_PORT9_UNAUTHBH_OFFSET    2
+#define    RTL8367C_DOT1X_PORT9_UNAUTHBH_MASK    0xC
+#define    RTL8367C_DOT1X_PORT8_UNAUTHBH_OFFSET    0
+#define    RTL8367C_DOT1X_PORT8_UNAUTHBH_MASK    0x3
+
+#define    RTL8367C_REG_DOT1X_CFG    0x0a86
+#define    RTL8367C_DOT1X_GVOPDIR_OFFSET    6
+#define    RTL8367C_DOT1X_GVOPDIR_MASK    0x40
+#define    RTL8367C_DOT1X_MAC_OPDIR_OFFSET    5
+#define    RTL8367C_DOT1X_MAC_OPDIR_MASK    0x20
+#define    RTL8367C_DOT1X_GVIDX_OFFSET    0
+#define    RTL8367C_DOT1X_GVIDX_MASK    0x1F
+
+#define    RTL8367C_REG_L2_LRN_CNT_CTRL0    0x0a87
+#define    RTL8367C_L2_LRN_CNT_CTRL0_OFFSET    0
+#define    RTL8367C_L2_LRN_CNT_CTRL0_MASK    0x1FFF
+
+#define    RTL8367C_REG_L2_LRN_CNT_CTRL1    0x0a88
+#define    RTL8367C_L2_LRN_CNT_CTRL1_OFFSET    0
+#define    RTL8367C_L2_LRN_CNT_CTRL1_MASK    0x1FFF
+
+#define    RTL8367C_REG_L2_LRN_CNT_CTRL2    0x0a89
+#define    RTL8367C_L2_LRN_CNT_CTRL2_OFFSET    0
+#define    RTL8367C_L2_LRN_CNT_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_L2_LRN_CNT_CTRL3    0x0a8a
+#define    RTL8367C_L2_LRN_CNT_CTRL3_OFFSET    0
+#define    RTL8367C_L2_LRN_CNT_CTRL3_MASK    0x1FFF
+
+#define    RTL8367C_REG_L2_LRN_CNT_CTRL4    0x0a8b
+#define    RTL8367C_L2_LRN_CNT_CTRL4_OFFSET    0
+#define    RTL8367C_L2_LRN_CNT_CTRL4_MASK    0x1FFF
+
+#define    RTL8367C_REG_L2_LRN_CNT_CTRL5    0x0a8c
+#define    RTL8367C_L2_LRN_CNT_CTRL5_OFFSET    0
+#define    RTL8367C_L2_LRN_CNT_CTRL5_MASK    0x1FFF
+
+#define    RTL8367C_REG_L2_LRN_CNT_CTRL6    0x0a8d
+#define    RTL8367C_L2_LRN_CNT_CTRL6_OFFSET    0
+#define    RTL8367C_L2_LRN_CNT_CTRL6_MASK    0x1FFF
+
+#define    RTL8367C_REG_L2_LRN_CNT_CTRL7    0x0a8e
+#define    RTL8367C_L2_LRN_CNT_CTRL7_OFFSET    0
+#define    RTL8367C_L2_LRN_CNT_CTRL7_MASK    0x1FFF
+
+#define    RTL8367C_REG_L2_LRN_CNT_CTRL8    0x0a8f
+#define    RTL8367C_L2_LRN_CNT_CTRL8_OFFSET    0
+#define    RTL8367C_L2_LRN_CNT_CTRL8_MASK    0x1FFF
+
+#define    RTL8367C_REG_L2_LRN_CNT_CTRL9    0x0a90
+#define    RTL8367C_L2_LRN_CNT_CTRL9_OFFSET    0
+#define    RTL8367C_L2_LRN_CNT_CTRL9_MASK    0x1FFF
+
+#define    RTL8367C_REG_L2_LRN_CNT_CTRL10    0x0a92
+#define    RTL8367C_L2_LRN_CNT_CTRL10_OFFSET    0
+#define    RTL8367C_L2_LRN_CNT_CTRL10_MASK    0x1FFF
+
+#define    RTL8367C_REG_LUT_LRN_UNDER_STATUS    0x0a91
+#define    RTL8367C_LUT_LRN_UNDER_STATUS_OFFSET    0
+#define    RTL8367C_LUT_LRN_UNDER_STATUS_MASK    0x7FF
+
+#define    RTL8367C_REG_L2_SA_MOVING_FORBID    0x0aa0
+#define    RTL8367C_L2_SA_MOVING_FORBID_OFFSET    0
+#define    RTL8367C_L2_SA_MOVING_FORBID_MASK    0x7FF
+
+#define    RTL8367C_REG_DRPORT_LEARN_CTRL    0x0aa1
+#define    RTL8367C_FORBID1_OFFSET    1
+#define    RTL8367C_FORBID1_MASK    0x2
+#define    RTL8367C_FORBID0_OFFSET    0
+#define    RTL8367C_FORBID0_MASK    0x1
+
+#define    RTL8367C_REG_L2_DUMMY02    0x0aa2
+
+#define    RTL8367C_REG_L2_DUMMY03    0x0aa3
+
+#define    RTL8367C_REG_L2_DUMMY04    0x0aa4
+
+#define    RTL8367C_REG_L2_DUMMY05    0x0aa5
+
+#define    RTL8367C_REG_L2_DUMMY06    0x0aa6
+
+#define    RTL8367C_REG_L2_DUMMY07    0x0aa7
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_00    0x0AC0
+#define    RTL8367C_IPMC_GROUP_PMSK_00_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_00_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_01    0x0AC1
+#define    RTL8367C_IPMC_GROUP_PMSK_01_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_01_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_02    0x0AC2
+#define    RTL8367C_IPMC_GROUP_PMSK_02_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_02_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_03    0x0AC3
+#define    RTL8367C_IPMC_GROUP_PMSK_03_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_03_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_04    0x0AC4
+#define    RTL8367C_IPMC_GROUP_PMSK_04_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_04_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_05    0x0AC5
+#define    RTL8367C_IPMC_GROUP_PMSK_05_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_05_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_06    0x0AC6
+#define    RTL8367C_IPMC_GROUP_PMSK_06_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_06_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_07    0x0AC7
+#define    RTL8367C_IPMC_GROUP_PMSK_07_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_07_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_08    0x0AC8
+#define    RTL8367C_IPMC_GROUP_PMSK_08_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_08_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_09    0x0AC9
+#define    RTL8367C_IPMC_GROUP_PMSK_09_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_09_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_10    0x0ACA
+#define    RTL8367C_IPMC_GROUP_PMSK_10_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_10_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_11    0x0ACB
+#define    RTL8367C_IPMC_GROUP_PMSK_11_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_11_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_12    0x0ACC
+#define    RTL8367C_IPMC_GROUP_PMSK_12_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_12_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_13    0x0ACD
+#define    RTL8367C_IPMC_GROUP_PMSK_13_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_13_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_14    0x0ACE
+#define    RTL8367C_IPMC_GROUP_PMSK_14_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_14_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_15    0x0ACF
+#define    RTL8367C_IPMC_GROUP_PMSK_15_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_15_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_16    0x0AD0
+#define    RTL8367C_IPMC_GROUP_PMSK_16_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_16_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_17    0x0AD1
+#define    RTL8367C_IPMC_GROUP_PMSK_17_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_17_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_18    0x0AD2
+#define    RTL8367C_IPMC_GROUP_PMSK_18_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_18_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_19    0x0AD3
+#define    RTL8367C_IPMC_GROUP_PMSK_19_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_19_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_20    0x0AD4
+#define    RTL8367C_IPMC_GROUP_PMSK_20_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_20_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_21    0x0AD5
+#define    RTL8367C_IPMC_GROUP_PMSK_21_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_21_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_22    0x0AD6
+#define    RTL8367C_IPMC_GROUP_PMSK_22_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_22_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_23    0x0AD7
+#define    RTL8367C_IPMC_GROUP_PMSK_23_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_23_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_24    0x0AD8
+#define    RTL8367C_IPMC_GROUP_PMSK_24_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_24_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_25    0x0AD9
+#define    RTL8367C_IPMC_GROUP_PMSK_25_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_25_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_26    0x0ADA
+#define    RTL8367C_IPMC_GROUP_PMSK_26_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_26_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_27    0x0ADB
+#define    RTL8367C_IPMC_GROUP_PMSK_27_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_27_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_28    0x0ADC
+#define    RTL8367C_IPMC_GROUP_PMSK_28_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_28_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_29    0x0ADD
+#define    RTL8367C_IPMC_GROUP_PMSK_29_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_29_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_30    0x0ADE
+#define    RTL8367C_IPMC_GROUP_PMSK_30_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_30_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_31    0x0ADF
+#define    RTL8367C_IPMC_GROUP_PMSK_31_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_31_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_32    0x0AE0
+#define    RTL8367C_IPMC_GROUP_PMSK_32_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_32_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_33    0x0AE1
+#define    RTL8367C_IPMC_GROUP_PMSK_33_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_33_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_34    0x0AE2
+#define    RTL8367C_IPMC_GROUP_PMSK_34_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_34_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_35    0x0AE3
+#define    RTL8367C_IPMC_GROUP_PMSK_35_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_35_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_36    0x0AE4
+#define    RTL8367C_IPMC_GROUP_PMSK_36_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_36_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_37    0x0AE5
+#define    RTL8367C_IPMC_GROUP_PMSK_37_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_37_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_38    0x0AE6
+#define    RTL8367C_IPMC_GROUP_PMSK_38_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_38_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_39    0x0AE7
+#define    RTL8367C_IPMC_GROUP_PMSK_39_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_39_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_40    0x0AE8
+#define    RTL8367C_IPMC_GROUP_PMSK_40_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_40_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_41    0x0AE9
+#define    RTL8367C_IPMC_GROUP_PMSK_41_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_41_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_42    0x0AEA
+#define    RTL8367C_IPMC_GROUP_PMSK_42_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_42_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_43    0x0AEB
+#define    RTL8367C_IPMC_GROUP_PMSK_43_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_43_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_44    0x0AEC
+#define    RTL8367C_IPMC_GROUP_PMSK_44_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_44_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_45    0x0AED
+#define    RTL8367C_IPMC_GROUP_PMSK_45_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_45_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_46    0x0AEE
+#define    RTL8367C_IPMC_GROUP_PMSK_46_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_46_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_47    0x0AEF
+#define    RTL8367C_IPMC_GROUP_PMSK_47_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_47_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_48    0x0AF0
+#define    RTL8367C_IPMC_GROUP_PMSK_48_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_48_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_49    0x0AF1
+#define    RTL8367C_IPMC_GROUP_PMSK_49_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_49_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_50    0x0AF2
+#define    RTL8367C_IPMC_GROUP_PMSK_50_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_50_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_51    0x0AF3
+#define    RTL8367C_IPMC_GROUP_PMSK_51_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_51_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_52    0x0AF4
+#define    RTL8367C_IPMC_GROUP_PMSK_52_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_52_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_53    0x0AF5
+#define    RTL8367C_IPMC_GROUP_PMSK_53_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_53_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_54    0x0AF6
+#define    RTL8367C_IPMC_GROUP_PMSK_54_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_54_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_55    0x0AF7
+#define    RTL8367C_IPMC_GROUP_PMSK_55_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_55_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_56    0x0AF8
+#define    RTL8367C_IPMC_GROUP_PMSK_56_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_56_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_57    0x0AF9
+#define    RTL8367C_IPMC_GROUP_PMSK_57_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_57_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_58    0x0AFA
+#define    RTL8367C_IPMC_GROUP_PMSK_58_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_58_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_59    0x0AFB
+#define    RTL8367C_IPMC_GROUP_PMSK_59_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_59_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_60    0x0AFC
+#define    RTL8367C_IPMC_GROUP_PMSK_60_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_60_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_61    0x0AFD
+#define    RTL8367C_IPMC_GROUP_PMSK_61_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_61_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_62    0x0AFE
+#define    RTL8367C_IPMC_GROUP_PMSK_62_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_62_MASK    0x7FF
+
+#define    RTL8367C_REG_IPMC_GROUP_PMSK_63    0x0AFF
+#define    RTL8367C_IPMC_GROUP_PMSK_63_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_PMSK_63_MASK    0x7FF
+
+/* (16'h0b00)mltvlan_reg */
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY0_CTRL0    0x0b00
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY0_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY0_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY0_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY0_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY0_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY0_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY0_CTRL1    0x0b01
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY0_CTRL2    0x0b02
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY0_CTRL3    0x0b03
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY0_CTRL4    0x0b04
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY1_CTRL0    0x0b05
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY1_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY1_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY1_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY1_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY1_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY1_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY1_CTRL1    0x0b06
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY1_CTRL2    0x0b07
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY1_CTRL3    0x0b08
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY1_CTRL4    0x0b09
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY2_CTRL0    0x0b0a
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY2_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY2_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY2_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY2_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY2_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY2_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY2_CTRL1    0x0b0b
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY2_CTRL2    0x0b0c
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY2_CTRL3    0x0b0d
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY2_CTRL4    0x0b0e
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY3_CTRL0    0x0b0f
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY3_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY3_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY3_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY3_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY3_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY3_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY3_CTRL1    0x0b10
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY3_CTRL2    0x0b11
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY3_CTRL3    0x0b12
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY3_CTRL4    0x0b13
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY4_CTRL0    0x0b14
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY4_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY4_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY4_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY4_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY4_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY4_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY4_CTRL1    0x0b15
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY4_CTRL2    0x0b16
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY4_CTRL3    0x0b17
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY4_CTRL4    0x0b18
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY5_CTRL0    0x0b19
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY5_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY5_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY5_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY5_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY5_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY5_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY5_CTRL1    0x0b1a
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY5_CTRL2    0x0b1b
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY5_CTRL3    0x0b1c
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY5_CTRL4    0x0b1d
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY6_CTRL0    0x0b1e
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY6_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY6_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY6_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY6_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY6_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY6_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY6_CTRL1    0x0b1f
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY6_CTRL2    0x0b20
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY6_CTRL3    0x0b21
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY6_CTRL4    0x0b22
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY7_CTRL0    0x0b23
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY7_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY7_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY7_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY7_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY7_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY7_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY7_CTRL1    0x0b24
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY7_CTRL2    0x0b25
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY7_CTRL3    0x0b26
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY7_CTRL4    0x0b27
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY8_CTRL0    0x0b28
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY8_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY8_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY8_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY8_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY8_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY8_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY8_CTRL1    0x0b29
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY8_CTRL2    0x0b2a
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY8_CTRL3    0x0b2b
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY8_CTRL4    0x0b2c
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY9_CTRL0    0x0b2d
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY9_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY9_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY9_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY9_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY9_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY9_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY9_CTRL1    0x0b2e
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY9_CTRL2    0x0b2f
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY9_CTRL3    0x0b30
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY9_CTRL4    0x0b31
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY10_CTRL0    0x0b32
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY10_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY10_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY10_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY10_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY10_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY10_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY10_CTRL1    0x0b33
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY10_CTRL2    0x0b34
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY10_CTRL3    0x0b35
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY10_CTRL4    0x0b36
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY11_CTRL0    0x0b37
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY11_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY11_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY11_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY11_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY11_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY11_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY11_CTRL1    0x0b38
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY11_CTRL2    0x0b39
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY11_CTRL3    0x0b3a
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY11_CTRL4    0x0b3b
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY12_CTRL0    0x0b3c
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY12_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY12_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY12_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY12_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY12_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY12_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY12_CTRL1    0x0b3d
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY12_CTRL2    0x0b3e
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY12_CTRL3    0x0b3f
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY12_CTRL4    0x0b40
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY13_CTRL0    0x0b41
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY13_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY13_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY13_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY13_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY13_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY13_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY13_CTRL1    0x0b42
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY13_CTRL2    0x0b43
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY13_CTRL3    0x0b44
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY13_CTRL4    0x0b45
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY14_CTRL0    0x0b46
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY14_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY14_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY14_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY14_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY14_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY14_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY14_CTRL1    0x0b47
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY14_CTRL2    0x0b48
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY14_CTRL3    0x0b49
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY14_CTRL4    0x0b4a
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY15_CTRL0    0x0b4b
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY15_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY15_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY15_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY15_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY15_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY15_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY15_CTRL1    0x0b4c
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY15_CTRL2    0x0b4d
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY15_CTRL3    0x0b4e
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY15_CTRL4    0x0b4f
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY16_CTRL0    0x0b50
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY16_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY16_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY16_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY16_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY16_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY16_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY16_CTRL1    0x0b51
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY16_CTRL2    0x0b52
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY16_CTRL3    0x0b53
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY16_CTRL4    0x0b54
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY17_CTRL0    0x0b55
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY17_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY17_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY17_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY17_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY17_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY17_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY17_CTRL1    0x0b56
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY17_CTRL2    0x0b57
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY17_CTRL3    0x0b58
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY17_CTRL4    0x0b59
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY18_CTRL0    0x0b5a
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY18_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY18_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY18_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY18_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY18_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY18_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY18_CTRL1    0x0b5b
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY18_CTRL2    0x0b5c
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY18_CTRL3    0x0b5d
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY18_CTRL4    0x0b5e
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY19_CTRL0    0x0b5f
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY19_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY19_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY19_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY19_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY19_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY19_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY19_CTRL1    0x0b60
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY19_CTRL2    0x0b61
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY19_CTRL3    0x0b62
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY19_CTRL4    0x0b63
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY20_CTRL0    0x0b64
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY20_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY20_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY20_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY20_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY20_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY20_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY20_CTRL1    0x0b65
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY20_CTRL2    0x0b66
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY20_CTRL3    0x0b67
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY20_CTRL4    0x0b68
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY21_CTRL0    0x0b69
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY21_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY21_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY21_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY21_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY21_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY21_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY21_CTRL1    0x0b6a
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY21_CTRL2    0x0b6b
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY21_CTRL3    0x0b6c
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY21_CTRL4    0x0b6d
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY22_CTRL0    0x0b6e
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY22_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY22_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY22_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY22_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY22_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY22_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY22_CTRL1    0x0b6f
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY22_CTRL2    0x0b70
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY22_CTRL3    0x0b71
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY22_CTRL4    0x0b72
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY23_CTRL0    0x0b73
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY23_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY23_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY23_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY23_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY23_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY23_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY23_CTRL1    0x0b74
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY23_CTRL2    0x0b75
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY23_CTRL3    0x0b76
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY23_CTRL4    0x0b77
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY24_CTRL0    0x0b78
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY24_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY24_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY24_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY24_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY24_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY24_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY24_CTRL1    0x0b79
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY24_CTRL2    0x0b7a
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY24_CTRL3    0x0b7b
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY24_CTRL4    0x0b7c
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY25_CTRL0    0x0b7d
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY25_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY25_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY25_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY25_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY25_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY25_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY25_CTRL1    0x0b7e
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY25_CTRL2    0x0b7f
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY25_CTRL3    0x0b80
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY25_CTRL4    0x0b81
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY26_CTRL0    0x0b82
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY26_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY26_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY26_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY26_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY26_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY26_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY26_CTRL1    0x0b83
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY26_CTRL2    0x0b84
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY26_CTRL3    0x0b85
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY26_CTRL4    0x0b86
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY27_CTRL0    0x0b87
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY27_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY27_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY27_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY27_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY27_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY27_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY27_CTRL1    0x0b88
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY27_CTRL2    0x0b89
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY27_CTRL3    0x0b8a
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY27_CTRL4    0x0b8b
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY28_CTRL0    0x0b8c
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY28_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY28_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY28_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY28_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY28_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY28_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY28_CTRL1    0x0b8d
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY28_CTRL2    0x0b8e
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY28_CTRL3    0x0b8f
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY28_CTRL4    0x0b90
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY29_CTRL0    0x0b91
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY29_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY29_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY29_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY29_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY29_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY29_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY29_CTRL1    0x0b92
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY29_CTRL2    0x0b93
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY29_CTRL3    0x0b94
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY29_CTRL4    0x0b95
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY30_CTRL0    0x0b96
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY30_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY30_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY30_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY30_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY30_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY30_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY30_CTRL1    0x0b97
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY30_CTRL2    0x0b98
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY30_CTRL3    0x0b99
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY30_CTRL4    0x0b9a
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY31_CTRL0    0x0b9b
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY31_CTRL0_VALID_OFFSET    7
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY31_CTRL0_VALID_MASK    0x80
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY31_CTRL0_FORMAT_OFFSET    6
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY31_CTRL0_FORMAT_MASK    0x40
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY31_CTRL0_SVIDX_OFFSET    0
+#define    RTL8367C_SVLAN_MCAST2S_ENTRY31_CTRL0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY31_CTRL1    0x0b9c
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY31_CTRL2    0x0b9d
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY31_CTRL3    0x0b9e
+
+#define    RTL8367C_REG_SVLAN_MCAST2S_ENTRY31_CTRL4    0x0b9f
+
+#define    RTL8367C_REG_MLTVLAN_DUMMY_0    0x0ba0
+
+#define    RTL8367C_REG_MLTVLAN_DUMMY_1    0x0ba1
+
+#define    RTL8367C_REG_MLTVLAN_DUMMY_2    0x0ba2
+
+#define    RTL8367C_REG_MLTVLAN_DUMMY_3    0x0ba3
+
+#define    RTL8367C_REG_MLTVLAN_DUMMY_4    0x0ba4
+
+#define    RTL8367C_REG_MLTVLAN_DUMMY_5    0x0ba5
+
+#define    RTL8367C_REG_MLTVLAN_DUMMY_6    0x0ba6
+
+#define    RTL8367C_REG_MLTVLAN_DUMMY_7    0x0ba7
+
+/* (16'h0c00)svlan_reg */
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG0_CTRL1    0x0c01
+#define    RTL8367C_SVLAN_MEMBERCFG0_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG0_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG0_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG0_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG0_CTRL2    0x0c02
+#define    RTL8367C_SVLAN_MEMBERCFG0_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG0_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG0_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG0_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG0_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG0_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG0_CTRL3    0x0c03
+#define    RTL8367C_SVLAN_MEMBERCFG0_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG0_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG0_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG0_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG0_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG0_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG1_CTRL1    0x0c04
+#define    RTL8367C_SVLAN_MEMBERCFG1_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG1_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG1_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG1_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG1_CTRL2    0x0c05
+#define    RTL8367C_SVLAN_MEMBERCFG1_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG1_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG1_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG1_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG1_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG1_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG1_CTRL3    0x0c06
+#define    RTL8367C_SVLAN_MEMBERCFG1_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG1_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG1_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG1_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG1_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG1_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG2_CTRL1    0x0c07
+#define    RTL8367C_SVLAN_MEMBERCFG2_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG2_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG2_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG2_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG2_CTRL2    0x0c08
+#define    RTL8367C_SVLAN_MEMBERCFG2_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG2_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG2_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG2_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG2_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG2_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG2_CTRL3    0x0c09
+#define    RTL8367C_SVLAN_MEMBERCFG2_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG2_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG2_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG2_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG2_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG2_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG3_CTRL1    0x0c0a
+#define    RTL8367C_SVLAN_MEMBERCFG3_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG3_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG3_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG3_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG3_CTRL2    0x0c0b
+#define    RTL8367C_SVLAN_MEMBERCFG3_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG3_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG3_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG3_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG3_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG3_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG3_CTRL3    0x0c0c
+#define    RTL8367C_SVLAN_MEMBERCFG3_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG3_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG3_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG3_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG3_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG3_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG4_CTRL1    0x0c0d
+#define    RTL8367C_SVLAN_MEMBERCFG4_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG4_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG4_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG4_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG4_CTRL2    0x0c0e
+#define    RTL8367C_SVLAN_MEMBERCFG4_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG4_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG4_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG4_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG4_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG4_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG4_CTRL3    0x0c0f
+#define    RTL8367C_SVLAN_MEMBERCFG4_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG4_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG4_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG4_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG4_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG4_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG5_CTRL1    0x0c10
+#define    RTL8367C_SVLAN_MEMBERCFG5_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG5_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG5_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG5_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG5_CTRL2    0x0c11
+#define    RTL8367C_SVLAN_MEMBERCFG5_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG5_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG5_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG5_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG5_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG5_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG5_CTRL3    0x0c12
+#define    RTL8367C_SVLAN_MEMBERCFG5_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG5_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG5_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG5_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG5_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG5_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG6_CTRL1    0x0c13
+#define    RTL8367C_SVLAN_MEMBERCFG6_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG6_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG6_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG6_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG6_CTRL2    0x0c14
+#define    RTL8367C_SVLAN_MEMBERCFG6_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG6_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG6_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG6_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG6_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG6_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG6_CTRL3    0x0c15
+#define    RTL8367C_SVLAN_MEMBERCFG6_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG6_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG6_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG6_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG6_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG6_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG7_CTRL1    0x0c16
+#define    RTL8367C_SVLAN_MEMBERCFG7_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG7_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG7_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG7_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG7_CTRL2    0x0c17
+#define    RTL8367C_SVLAN_MEMBERCFG7_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG7_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG7_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG7_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG7_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG7_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG7_CTRL3    0x0c18
+#define    RTL8367C_SVLAN_MEMBERCFG7_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG7_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG7_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG7_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG7_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG7_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG8_CTRL1    0x0c19
+#define    RTL8367C_SVLAN_MEMBERCFG8_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG8_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG8_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG8_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG8_CTRL2    0x0c1a
+#define    RTL8367C_SVLAN_MEMBERCFG8_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG8_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG8_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG8_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG8_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG8_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG8_CTRL3    0x0c1b
+#define    RTL8367C_SVLAN_MEMBERCFG8_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG8_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG8_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG8_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG8_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG8_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG9_CTRL1    0x0c1c
+#define    RTL8367C_SVLAN_MEMBERCFG9_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG9_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG9_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG9_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG9_CTRL2    0x0c1d
+#define    RTL8367C_SVLAN_MEMBERCFG9_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG9_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG9_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG9_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG9_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG9_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG9_CTRL3    0x0c1e
+#define    RTL8367C_SVLAN_MEMBERCFG9_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG9_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG9_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG9_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG9_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG9_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG10_CTRL1    0x0c1f
+#define    RTL8367C_SVLAN_MEMBERCFG10_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG10_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG10_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG10_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG10_CTRL2    0x0c20
+#define    RTL8367C_SVLAN_MEMBERCFG10_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG10_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG10_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG10_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG10_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG10_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG10_CTRL3    0x0c21
+#define    RTL8367C_SVLAN_MEMBERCFG10_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG10_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG10_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG10_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG10_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG10_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG11_CTRL1    0x0c22
+#define    RTL8367C_SVLAN_MEMBERCFG11_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG11_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG11_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG11_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG11_CTRL2    0x0c23
+#define    RTL8367C_SVLAN_MEMBERCFG11_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG11_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG11_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG11_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG11_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG11_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG11_CTRL3    0x0c24
+#define    RTL8367C_SVLAN_MEMBERCFG11_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG11_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG11_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG11_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG11_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG11_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG12_CTRL1    0x0c25
+#define    RTL8367C_SVLAN_MEMBERCFG12_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG12_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG12_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG12_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG12_CTRL2    0x0c26
+#define    RTL8367C_SVLAN_MEMBERCFG12_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG12_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG12_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG12_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG12_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG12_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG12_CTRL3    0x0c27
+#define    RTL8367C_SVLAN_MEMBERCFG12_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG12_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG12_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG12_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG12_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG12_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG13_CTRL1    0x0c28
+#define    RTL8367C_SVLAN_MEMBERCFG13_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG13_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG13_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG13_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG13_CTRL2    0x0c29
+#define    RTL8367C_SVLAN_MEMBERCFG13_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG13_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG13_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG13_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG13_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG13_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG13_CTRL3    0x0c2a
+#define    RTL8367C_SVLAN_MEMBERCFG13_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG13_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG13_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG13_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG13_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG13_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG14_CTRL1    0x0c2b
+#define    RTL8367C_SVLAN_MEMBERCFG14_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG14_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG14_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG14_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG14_CTRL2    0x0c2c
+#define    RTL8367C_SVLAN_MEMBERCFG14_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG14_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG14_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG14_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG14_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG14_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG14_CTRL3    0x0c2d
+#define    RTL8367C_SVLAN_MEMBERCFG14_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG14_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG14_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG14_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG14_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG14_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG15_CTRL1    0x0c2e
+#define    RTL8367C_SVLAN_MEMBERCFG15_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG15_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG15_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG15_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG15_CTRL2    0x0c2f
+#define    RTL8367C_SVLAN_MEMBERCFG15_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG15_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG15_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG15_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG15_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG15_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG15_CTRL3    0x0c30
+#define    RTL8367C_SVLAN_MEMBERCFG15_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG15_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG15_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG15_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG15_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG15_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG16_CTRL1    0x0c31
+#define    RTL8367C_SVLAN_MEMBERCFG16_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG16_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG16_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG16_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG16_CTRL2    0x0c32
+#define    RTL8367C_SVLAN_MEMBERCFG16_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG16_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG16_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG16_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG16_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG16_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG16_CTRL3    0x0c33
+#define    RTL8367C_SVLAN_MEMBERCFG16_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG16_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG16_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG16_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG16_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG16_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG17_CTRL1    0x0c34
+#define    RTL8367C_SVLAN_MEMBERCFG17_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG17_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG17_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG17_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG17_CTRL2    0x0c35
+#define    RTL8367C_SVLAN_MEMBERCFG17_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG17_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG17_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG17_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG17_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG17_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG17_CTRL3    0x0c36
+#define    RTL8367C_SVLAN_MEMBERCFG17_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG17_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG17_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG17_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG17_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG17_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG18_CTRL1    0x0c37
+#define    RTL8367C_SVLAN_MEMBERCFG18_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG18_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG18_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG18_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG18_CTRL2    0x0c38
+#define    RTL8367C_SVLAN_MEMBERCFG18_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG18_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG18_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG18_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG18_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG18_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG18_CTRL3    0x0c39
+#define    RTL8367C_SVLAN_MEMBERCFG18_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG18_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG18_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG18_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG18_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG18_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG19_CTRL1    0x0c3a
+#define    RTL8367C_SVLAN_MEMBERCFG19_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG19_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG19_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG19_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG19_CTRL2    0x0c3b
+#define    RTL8367C_SVLAN_MEMBERCFG19_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG19_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG19_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG19_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG19_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG19_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG19_CTRL3    0x0c3c
+#define    RTL8367C_SVLAN_MEMBERCFG19_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG19_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG19_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG19_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG19_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG19_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG20_CTRL1    0x0c3d
+#define    RTL8367C_SVLAN_MEMBERCFG20_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG20_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG20_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG20_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG20_CTRL2    0x0c3e
+#define    RTL8367C_SVLAN_MEMBERCFG20_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG20_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG20_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG20_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG20_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG20_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG20_CTRL3    0x0c3f
+#define    RTL8367C_SVLAN_MEMBERCFG20_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG20_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG20_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG20_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG20_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG20_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG21_CTRL1    0x0c40
+#define    RTL8367C_SVLAN_MEMBERCFG21_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG21_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG21_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG21_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG21_CTRL2    0x0c41
+#define    RTL8367C_SVLAN_MEMBERCFG21_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG21_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG21_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG21_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG21_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG21_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG21_CTRL3    0x0c42
+#define    RTL8367C_SVLAN_MEMBERCFG21_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG21_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG21_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG21_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG21_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG21_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG22_CTRL1    0x0c43
+#define    RTL8367C_SVLAN_MEMBERCFG22_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG22_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG22_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG22_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG22_CTRL2    0x0c44
+#define    RTL8367C_SVLAN_MEMBERCFG22_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG22_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG22_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG22_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG22_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG22_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG22_CTRL3    0x0c45
+#define    RTL8367C_SVLAN_MEMBERCFG22_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG22_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG22_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG22_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG22_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG22_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG23_CTRL1    0x0c46
+#define    RTL8367C_SVLAN_MEMBERCFG23_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG23_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG23_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG23_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG23_CTRL2    0x0c47
+#define    RTL8367C_SVLAN_MEMBERCFG23_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG23_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG23_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG23_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG23_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG23_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG23_CTRL3    0x0c48
+#define    RTL8367C_SVLAN_MEMBERCFG23_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG23_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG23_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG23_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG23_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG23_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG24_CTRL1    0x0c49
+#define    RTL8367C_SVLAN_MEMBERCFG24_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG24_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG24_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG24_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG24_CTRL2    0x0c4a
+#define    RTL8367C_SVLAN_MEMBERCFG24_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG24_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG24_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG24_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG24_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG24_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG24_CTRL3    0x0c4b
+#define    RTL8367C_SVLAN_MEMBERCFG24_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG24_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG24_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG24_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG24_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG24_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG25_CTRL1    0x0c4c
+#define    RTL8367C_SVLAN_MEMBERCFG25_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG25_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG25_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG25_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG25_CTRL2    0x0c4d
+#define    RTL8367C_SVLAN_MEMBERCFG25_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG25_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG25_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG25_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG25_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG25_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG25_CTRL3    0x0c4e
+#define    RTL8367C_SVLAN_MEMBERCFG25_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG25_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG25_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG25_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG25_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG25_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG26_CTRL1    0x0c4f
+#define    RTL8367C_SVLAN_MEMBERCFG26_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG26_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG26_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG26_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG26_CTRL2    0x0c50
+#define    RTL8367C_SVLAN_MEMBERCFG26_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG26_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG26_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG26_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG26_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG26_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG26_CTRL3    0x0c51
+#define    RTL8367C_SVLAN_MEMBERCFG26_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG26_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG26_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG26_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG26_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG26_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG27_CTRL1    0x0c52
+#define    RTL8367C_SVLAN_MEMBERCFG27_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG27_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG27_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG27_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG27_CTRL2    0x0c53
+#define    RTL8367C_SVLAN_MEMBERCFG27_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG27_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG27_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG27_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG27_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG27_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG27_CTRL3    0x0c54
+#define    RTL8367C_SVLAN_MEMBERCFG27_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG27_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG27_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG27_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG27_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG27_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG28_CTRL1    0x0c55
+#define    RTL8367C_SVLAN_MEMBERCFG28_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG28_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG28_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG28_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG28_CTRL2    0x0c56
+#define    RTL8367C_SVLAN_MEMBERCFG28_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG28_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG28_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG28_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG28_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG28_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG28_CTRL3    0x0c57
+#define    RTL8367C_SVLAN_MEMBERCFG28_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG28_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG28_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG28_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG28_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG28_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG29_CTRL1    0x0c58
+#define    RTL8367C_SVLAN_MEMBERCFG29_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG29_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG29_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG29_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG29_CTRL2    0x0c59
+#define    RTL8367C_SVLAN_MEMBERCFG29_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG29_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG29_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG29_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG29_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG29_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG29_CTRL3    0x0c5a
+#define    RTL8367C_SVLAN_MEMBERCFG29_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG29_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG29_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG29_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG29_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG29_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG30_CTRL1    0x0c5b
+#define    RTL8367C_SVLAN_MEMBERCFG30_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG30_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG30_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG30_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG30_CTRL2    0x0c5c
+#define    RTL8367C_SVLAN_MEMBERCFG30_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG30_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG30_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG30_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG30_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG30_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG30_CTRL3    0x0c5d
+#define    RTL8367C_SVLAN_MEMBERCFG30_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG30_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG30_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG30_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG30_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG30_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG31_CTRL1    0x0c5e
+#define    RTL8367C_SVLAN_MEMBERCFG31_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG31_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG31_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG31_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG31_CTRL2    0x0c5f
+#define    RTL8367C_SVLAN_MEMBERCFG31_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG31_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG31_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG31_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG31_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG31_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG31_CTRL3    0x0c60
+#define    RTL8367C_SVLAN_MEMBERCFG31_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG31_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG31_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG31_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG31_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG31_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG32_CTRL1    0x0c61
+#define    RTL8367C_SVLAN_MEMBERCFG32_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG32_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG32_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG32_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG32_CTRL2    0x0c62
+#define    RTL8367C_SVLAN_MEMBERCFG32_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG32_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG32_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG32_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG32_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG32_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG32_CTRL3    0x0c63
+#define    RTL8367C_SVLAN_MEMBERCFG32_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG32_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG32_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG32_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG32_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG32_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG33_CTRL1    0x0c64
+#define    RTL8367C_SVLAN_MEMBERCFG33_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG33_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG33_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG33_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG33_CTRL2    0x0c65
+#define    RTL8367C_SVLAN_MEMBERCFG33_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG33_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG33_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG33_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG33_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG33_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG33_CTRL3    0x0c66
+#define    RTL8367C_SVLAN_MEMBERCFG33_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG33_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG33_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG33_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG33_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG33_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG34_CTRL1    0x0c67
+#define    RTL8367C_SVLAN_MEMBERCFG34_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG34_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG34_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG34_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG34_CTRL2    0x0c68
+#define    RTL8367C_SVLAN_MEMBERCFG34_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG34_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG34_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG34_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG34_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG34_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG34_CTRL3    0x0c69
+#define    RTL8367C_SVLAN_MEMBERCFG34_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG34_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG34_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG34_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG34_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG34_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG35_CTRL1    0x0c6a
+#define    RTL8367C_SVLAN_MEMBERCFG35_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG35_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG35_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG35_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG35_CTRL2    0x0c6b
+#define    RTL8367C_SVLAN_MEMBERCFG35_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG35_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG35_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG35_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG35_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG35_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG35_CTRL3    0x0c6c
+#define    RTL8367C_SVLAN_MEMBERCFG35_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG35_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG35_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG35_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG35_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG35_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG36_CTRL1    0x0c6d
+#define    RTL8367C_SVLAN_MEMBERCFG36_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG36_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG36_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG36_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG36_CTRL2    0x0c6e
+#define    RTL8367C_SVLAN_MEMBERCFG36_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG36_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG36_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG36_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG36_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG36_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG36_CTRL3    0x0c6f
+#define    RTL8367C_SVLAN_MEMBERCFG36_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG36_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG36_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG36_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG36_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG36_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG37_CTRL1    0x0c70
+#define    RTL8367C_SVLAN_MEMBERCFG37_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG37_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG37_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG37_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG37_CTRL2    0x0c71
+#define    RTL8367C_SVLAN_MEMBERCFG37_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG37_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG37_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG37_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG37_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG37_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG37_CTRL3    0x0c72
+#define    RTL8367C_SVLAN_MEMBERCFG37_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG37_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG37_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG37_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG37_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG37_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG38_CTRL1    0x0c73
+#define    RTL8367C_SVLAN_MEMBERCFG38_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG38_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG38_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG38_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG38_CTRL2    0x0c74
+#define    RTL8367C_SVLAN_MEMBERCFG38_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG38_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG38_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG38_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG38_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG38_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG38_CTRL3    0x0c75
+#define    RTL8367C_SVLAN_MEMBERCFG38_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG38_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG38_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG38_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG38_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG38_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG39_CTRL1    0x0c76
+#define    RTL8367C_SVLAN_MEMBERCFG39_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG39_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG39_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG39_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG39_CTRL2    0x0c77
+#define    RTL8367C_SVLAN_MEMBERCFG39_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG39_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG39_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG39_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG39_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG39_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG39_CTRL3    0x0c78
+#define    RTL8367C_SVLAN_MEMBERCFG39_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG39_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG39_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG39_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG39_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG39_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG40_CTRL1    0x0c79
+#define    RTL8367C_SVLAN_MEMBERCFG40_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG40_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG40_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG40_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG40_CTRL2    0x0c7a
+#define    RTL8367C_SVLAN_MEMBERCFG40_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG40_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG40_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG40_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG40_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG40_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG40_CTRL3    0x0c7b
+#define    RTL8367C_SVLAN_MEMBERCFG40_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG40_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG40_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG40_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG40_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG40_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG41_CTRL1    0x0c7c
+#define    RTL8367C_SVLAN_MEMBERCFG41_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG41_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG41_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG41_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG41_CTRL2    0x0c7d
+#define    RTL8367C_SVLAN_MEMBERCFG41_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG41_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG41_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG41_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG41_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG41_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG41_CTRL3    0x0c7e
+#define    RTL8367C_SVLAN_MEMBERCFG41_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG41_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG41_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG41_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG41_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG41_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG42_CTRL1    0x0c7f
+#define    RTL8367C_SVLAN_MEMBERCFG42_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG42_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG42_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG42_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG42_CTRL2    0x0c80
+#define    RTL8367C_SVLAN_MEMBERCFG42_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG42_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG42_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG42_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG42_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG42_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG42_CTRL3    0x0c81
+#define    RTL8367C_SVLAN_MEMBERCFG42_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG42_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG42_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG42_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG42_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG42_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG43_CTRL1    0x0c82
+#define    RTL8367C_SVLAN_MEMBERCFG43_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG43_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG43_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG43_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG43_CTRL2    0x0c83
+#define    RTL8367C_SVLAN_MEMBERCFG43_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG43_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG43_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG43_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG43_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG43_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG43_CTRL3    0x0c84
+#define    RTL8367C_SVLAN_MEMBERCFG43_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG43_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG43_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG43_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG43_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG43_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG44_CTRL1    0x0c85
+#define    RTL8367C_SVLAN_MEMBERCFG44_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG44_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG44_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG44_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG44_CTRL2    0x0c86
+#define    RTL8367C_SVLAN_MEMBERCFG44_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG44_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG44_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG44_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG44_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG44_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG44_CTRL3    0x0c87
+#define    RTL8367C_SVLAN_MEMBERCFG44_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG44_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG44_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG44_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG44_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG44_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG45_CTRL1    0x0c88
+#define    RTL8367C_SVLAN_MEMBERCFG45_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG45_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG45_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG45_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG45_CTRL2    0x0c89
+#define    RTL8367C_SVLAN_MEMBERCFG45_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG45_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG45_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG45_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG45_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG45_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG45_CTRL3    0x0c8a
+#define    RTL8367C_SVLAN_MEMBERCFG45_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG45_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG45_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG45_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG45_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG45_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG46_CTRL1    0x0c8b
+#define    RTL8367C_SVLAN_MEMBERCFG46_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG46_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG46_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG46_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG46_CTRL2    0x0c8c
+#define    RTL8367C_SVLAN_MEMBERCFG46_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG46_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG46_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG46_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG46_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG46_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG46_CTRL3    0x0c8d
+#define    RTL8367C_SVLAN_MEMBERCFG46_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG46_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG46_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG46_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG46_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG46_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG47_CTRL1    0x0c8e
+#define    RTL8367C_SVLAN_MEMBERCFG47_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG47_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG47_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG47_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG47_CTRL2    0x0c8f
+#define    RTL8367C_SVLAN_MEMBERCFG47_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG47_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG47_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG47_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG47_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG47_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG47_CTRL3    0x0c90
+#define    RTL8367C_SVLAN_MEMBERCFG47_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG47_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG47_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG47_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG47_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG47_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG48_CTRL1    0x0c91
+#define    RTL8367C_SVLAN_MEMBERCFG48_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG48_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG48_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG48_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG48_CTRL2    0x0c92
+#define    RTL8367C_SVLAN_MEMBERCFG48_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG48_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG48_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG48_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG48_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG48_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG48_CTRL3    0x0c93
+#define    RTL8367C_SVLAN_MEMBERCFG48_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG48_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG48_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG48_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG48_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG48_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG49_CTRL1    0x0c94
+#define    RTL8367C_SVLAN_MEMBERCFG49_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG49_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG49_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG49_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG49_CTRL2    0x0c95
+#define    RTL8367C_SVLAN_MEMBERCFG49_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG49_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG49_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG49_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG49_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG49_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG49_CTRL3    0x0c96
+#define    RTL8367C_SVLAN_MEMBERCFG49_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG49_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG49_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG49_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG49_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG49_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG50_CTRL1    0x0c97
+#define    RTL8367C_SVLAN_MEMBERCFG50_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG50_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG50_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG50_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG50_CTRL2    0x0c98
+#define    RTL8367C_SVLAN_MEMBERCFG50_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG50_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG50_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG50_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG50_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG50_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG50_CTRL3    0x0c99
+#define    RTL8367C_SVLAN_MEMBERCFG50_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG50_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG50_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG50_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG50_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG50_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG51_CTRL1    0x0c9a
+#define    RTL8367C_SVLAN_MEMBERCFG51_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG51_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG51_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG51_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG51_CTRL2    0x0c9b
+#define    RTL8367C_SVLAN_MEMBERCFG51_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG51_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG51_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG51_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG51_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG51_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG51_CTRL3    0x0c9c
+#define    RTL8367C_SVLAN_MEMBERCFG51_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG51_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG51_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG51_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG51_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG51_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG52_CTRL1    0x0c9d
+#define    RTL8367C_SVLAN_MEMBERCFG52_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG52_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG52_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG52_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG52_CTRL2    0x0c9e
+#define    RTL8367C_SVLAN_MEMBERCFG52_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG52_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG52_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG52_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG52_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG52_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG52_CTRL3    0x0c9f
+#define    RTL8367C_SVLAN_MEMBERCFG52_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG52_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG52_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG52_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG52_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG52_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG53_CTRL1    0x0ca0
+#define    RTL8367C_SVLAN_MEMBERCFG53_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG53_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG53_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG53_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG53_CTRL2    0x0ca1
+#define    RTL8367C_SVLAN_MEMBERCFG53_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG53_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG53_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG53_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG53_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG53_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG53_CTRL3    0x0ca2
+#define    RTL8367C_SVLAN_MEMBERCFG53_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG53_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG53_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG53_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG53_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG53_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG54_CTRL1    0x0ca3
+#define    RTL8367C_SVLAN_MEMBERCFG54_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG54_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG54_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG54_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG54_CTRL2    0x0ca4
+#define    RTL8367C_SVLAN_MEMBERCFG54_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG54_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG54_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG54_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG54_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG54_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG54_CTRL3    0x0ca5
+#define    RTL8367C_SVLAN_MEMBERCFG54_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG54_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG54_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG54_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG54_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG54_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG55_CTRL1    0x0ca6
+#define    RTL8367C_SVLAN_MEMBERCFG55_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG55_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG55_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG55_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG55_CTRL2    0x0ca7
+#define    RTL8367C_SVLAN_MEMBERCFG55_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG55_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG55_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG55_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG55_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG55_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG55_CTRL3    0x0ca8
+#define    RTL8367C_SVLAN_MEMBERCFG55_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG55_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG55_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG55_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG55_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG55_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG56_CTRL1    0x0ca9
+#define    RTL8367C_SVLAN_MEMBERCFG56_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG56_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG56_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG56_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG56_CTRL2    0x0caa
+#define    RTL8367C_SVLAN_MEMBERCFG56_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG56_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG56_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG56_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG56_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG56_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG56_CTRL3    0x0cab
+#define    RTL8367C_SVLAN_MEMBERCFG56_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG56_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG56_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG56_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG56_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG56_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG57_CTRL1    0x0cac
+#define    RTL8367C_SVLAN_MEMBERCFG57_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG57_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG57_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG57_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG57_CTRL2    0x0cad
+#define    RTL8367C_SVLAN_MEMBERCFG57_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG57_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG57_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG57_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG57_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG57_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG57_CTRL3    0x0cae
+#define    RTL8367C_SVLAN_MEMBERCFG57_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG57_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG57_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG57_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG57_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG57_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG58_CTRL1    0x0caf
+#define    RTL8367C_SVLAN_MEMBERCFG58_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG58_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG58_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG58_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG58_CTRL2    0x0cb0
+#define    RTL8367C_SVLAN_MEMBERCFG58_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG58_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG58_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG58_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG58_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG58_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG58_CTRL3    0x0cb1
+#define    RTL8367C_SVLAN_MEMBERCFG58_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG58_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG58_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG58_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG58_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG58_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG59_CTRL1    0x0cb2
+#define    RTL8367C_SVLAN_MEMBERCFG59_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG59_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG59_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG59_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG59_CTRL2    0x0cb3
+#define    RTL8367C_SVLAN_MEMBERCFG59_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG59_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG59_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG59_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG59_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG59_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG59_CTRL3    0x0cb4
+#define    RTL8367C_SVLAN_MEMBERCFG59_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG59_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG59_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG59_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG59_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG59_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG60_CTRL1    0x0cb5
+#define    RTL8367C_SVLAN_MEMBERCFG60_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG60_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG60_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG60_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG60_CTRL2    0x0cb6
+#define    RTL8367C_SVLAN_MEMBERCFG60_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG60_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG60_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG60_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG60_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG60_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG60_CTRL3    0x0cb7
+#define    RTL8367C_SVLAN_MEMBERCFG60_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG60_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG60_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG60_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG60_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG60_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG61_CTRL1    0x0cb8
+#define    RTL8367C_SVLAN_MEMBERCFG61_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG61_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG61_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG61_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG61_CTRL2    0x0cb9
+#define    RTL8367C_SVLAN_MEMBERCFG61_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG61_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG61_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG61_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG61_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG61_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG61_CTRL3    0x0cba
+#define    RTL8367C_SVLAN_MEMBERCFG61_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG61_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG61_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG61_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG61_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG61_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG62_CTRL1    0x0cbb
+#define    RTL8367C_SVLAN_MEMBERCFG62_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG62_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG62_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG62_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG62_CTRL2    0x0cbc
+#define    RTL8367C_SVLAN_MEMBERCFG62_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG62_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG62_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG62_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG62_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG62_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG62_CTRL3    0x0cbd
+#define    RTL8367C_SVLAN_MEMBERCFG62_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG62_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG62_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG62_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG62_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG62_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG63_CTRL1    0x0cbe
+#define    RTL8367C_SVLAN_MEMBERCFG63_CTRL1_VS_UNTAGSET_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG63_CTRL1_VS_UNTAGSET_MASK    0xFF00
+#define    RTL8367C_SVLAN_MEMBERCFG63_CTRL1_VS_SMBR_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG63_CTRL1_VS_SMBR_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG63_CTRL2    0x0cbf
+#define    RTL8367C_SVLAN_MEMBERCFG63_CTRL2_VS_FIDEN_OFFSET    7
+#define    RTL8367C_SVLAN_MEMBERCFG63_CTRL2_VS_FIDEN_MASK    0x80
+#define    RTL8367C_SVLAN_MEMBERCFG63_CTRL2_VS_SPRI_OFFSET    4
+#define    RTL8367C_SVLAN_MEMBERCFG63_CTRL2_VS_SPRI_MASK    0x70
+#define    RTL8367C_SVLAN_MEMBERCFG63_CTRL2_VS_FID_MSTI_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG63_CTRL2_VS_FID_MSTI_MASK    0xF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG63_CTRL3    0x0cc0
+#define    RTL8367C_SVLAN_MEMBERCFG63_CTRL3_VS_EFID_OFFSET    13
+#define    RTL8367C_SVLAN_MEMBERCFG63_CTRL3_VS_EFID_MASK    0xE000
+#define    RTL8367C_SVLAN_MEMBERCFG63_CTRL3_VS_EFIDEN_OFFSET    12
+#define    RTL8367C_SVLAN_MEMBERCFG63_CTRL3_VS_EFIDEN_MASK    0x1000
+#define    RTL8367C_SVLAN_MEMBERCFG63_CTRL3_VS_SVID_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG63_CTRL3_VS_SVID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG0_CTRL4    0x0cc1
+#define    RTL8367C_SVLAN_MEMBERCFG0_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG0_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG0_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG0_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG1_CTRL4    0x0cc2
+#define    RTL8367C_SVLAN_MEMBERCFG1_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG1_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG1_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG1_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG2_CTRL4    0x0cc3
+#define    RTL8367C_SVLAN_MEMBERCFG2_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG2_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG2_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG2_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG3_CTRL4    0x0cc4
+#define    RTL8367C_SVLAN_MEMBERCFG3_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG3_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG3_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG3_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG4_CTRL4    0x0cc5
+#define    RTL8367C_SVLAN_MEMBERCFG4_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG4_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG4_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG4_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG5_CTRL4    0x0cc6
+#define    RTL8367C_SVLAN_MEMBERCFG5_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG5_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG5_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG5_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG6_CTRL4    0x0cc7
+#define    RTL8367C_SVLAN_MEMBERCFG6_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG6_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG6_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG6_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG7_CTRL4    0x0cc8
+#define    RTL8367C_SVLAN_MEMBERCFG7_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG7_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG7_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG7_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG8_CTRL4    0x0cc9
+#define    RTL8367C_SVLAN_MEMBERCFG8_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG8_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG8_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG8_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG9_CTRL4    0x0cca
+#define    RTL8367C_SVLAN_MEMBERCFG9_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG9_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG9_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG9_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG10_CTRL4    0x0ccb
+#define    RTL8367C_SVLAN_MEMBERCFG10_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG10_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG10_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG10_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG11_CTRL4    0x0ccc
+#define    RTL8367C_SVLAN_MEMBERCFG11_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG11_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG11_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG11_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG12_CTRL4    0x0ccd
+#define    RTL8367C_SVLAN_MEMBERCFG12_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG12_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG12_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG12_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG13_CTRL4    0x0cce
+#define    RTL8367C_SVLAN_MEMBERCFG13_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG13_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG13_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG13_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG14_CTRL4    0x0ccf
+#define    RTL8367C_SVLAN_MEMBERCFG14_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG14_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG14_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG14_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG15_CTRL4    0x0cd0
+#define    RTL8367C_SVLAN_MEMBERCFG15_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG15_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG15_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG15_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG16_CTRL4    0x0cd1
+#define    RTL8367C_SVLAN_MEMBERCFG16_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG16_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG16_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG16_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG17_CTRL4    0x0cd2
+#define    RTL8367C_SVLAN_MEMBERCFG17_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG17_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG17_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG17_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG18_CTRL4    0x0cd3
+#define    RTL8367C_SVLAN_MEMBERCFG18_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG18_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG18_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG18_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG19_CTRL4    0x0cd4
+#define    RTL8367C_SVLAN_MEMBERCFG19_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG19_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG19_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG19_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG20_CTRL4    0x0cd5
+#define    RTL8367C_SVLAN_MEMBERCFG20_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG20_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG20_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG20_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG21_CTRL4    0x0cd6
+#define    RTL8367C_SVLAN_MEMBERCFG21_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG21_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG21_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG21_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG22_CTRL4    0x0cd7
+#define    RTL8367C_SVLAN_MEMBERCFG22_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG22_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG22_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG22_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG23_CTRL4    0x0cd8
+#define    RTL8367C_SVLAN_MEMBERCFG23_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG23_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG23_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG23_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG24_CTRL4    0x0cd9
+#define    RTL8367C_SVLAN_MEMBERCFG24_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG24_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG24_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG24_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG25_CTRL4    0x0cda
+#define    RTL8367C_SVLAN_MEMBERCFG25_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG25_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG25_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG25_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG26_CTRL4    0x0cdb
+#define    RTL8367C_SVLAN_MEMBERCFG26_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG26_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG26_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG26_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG27_CTRL4    0x0cdc
+#define    RTL8367C_SVLAN_MEMBERCFG27_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG27_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG27_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG27_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG28_CTRL4    0x0cdd
+#define    RTL8367C_SVLAN_MEMBERCFG28_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG28_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG28_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG28_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG29_CTRL4    0x0cde
+#define    RTL8367C_SVLAN_MEMBERCFG29_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG29_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG29_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG29_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG30_CTRL4    0x0cdf
+#define    RTL8367C_SVLAN_MEMBERCFG30_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG30_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG30_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG30_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG31_CTRL4    0x0ce0
+#define    RTL8367C_SVLAN_MEMBERCFG31_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG31_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG31_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG31_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG32_CTRL4    0x0ce1
+#define    RTL8367C_SVLAN_MEMBERCFG32_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG32_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG32_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG32_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG33_CTRL4    0x0ce2
+#define    RTL8367C_SVLAN_MEMBERCFG33_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG33_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG33_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG33_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG34_CTRL4    0x0ce3
+#define    RTL8367C_SVLAN_MEMBERCFG34_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG34_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG34_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG34_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG35_CTRL4    0x0ce4
+#define    RTL8367C_SVLAN_MEMBERCFG35_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG35_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG35_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG35_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG36_CTRL4    0x0ce5
+#define    RTL8367C_SVLAN_MEMBERCFG36_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG36_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG36_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG36_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG37_CTRL4    0x0ce6
+#define    RTL8367C_SVLAN_MEMBERCFG37_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG37_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG37_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG37_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG38_CTRL4    0x0ce7
+#define    RTL8367C_SVLAN_MEMBERCFG38_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG38_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG38_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG38_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG39_CTRL4    0x0ce8
+#define    RTL8367C_SVLAN_MEMBERCFG39_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG39_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG39_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG39_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG40_CTRL4    0x0ce9
+#define    RTL8367C_SVLAN_MEMBERCFG40_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG40_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG40_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG40_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG41_CTRL4    0x0cea
+#define    RTL8367C_SVLAN_MEMBERCFG41_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG41_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG41_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG41_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG42_CTRL4    0x0ceb
+#define    RTL8367C_SVLAN_MEMBERCFG42_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG42_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG42_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG42_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG43_CTRL4    0x0cec
+#define    RTL8367C_SVLAN_MEMBERCFG43_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG43_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG43_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG43_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG44_CTRL4    0x0ced
+#define    RTL8367C_SVLAN_MEMBERCFG44_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG44_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG44_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG44_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG45_CTRL4    0x0cee
+#define    RTL8367C_SVLAN_MEMBERCFG45_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG45_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG45_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG45_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG46_CTRL4    0x0cef
+#define    RTL8367C_SVLAN_MEMBERCFG46_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG46_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG46_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG46_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG47_CTRL4    0x0cf0
+#define    RTL8367C_SVLAN_MEMBERCFG47_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG47_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG47_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG47_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG48_CTRL4    0x0cf1
+#define    RTL8367C_SVLAN_MEMBERCFG48_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG48_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG48_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG48_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG49_CTRL4    0x0cf2
+#define    RTL8367C_SVLAN_MEMBERCFG49_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG49_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG49_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG49_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG50_CTRL4    0x0cf3
+#define    RTL8367C_SVLAN_MEMBERCFG50_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG50_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG50_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG50_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG51_CTRL4    0x0cf4
+#define    RTL8367C_SVLAN_MEMBERCFG51_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG51_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG51_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG51_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG52_CTRL4    0x0cf5
+#define    RTL8367C_SVLAN_MEMBERCFG52_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG52_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG52_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG52_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG53_CTRL4    0x0cf6
+#define    RTL8367C_SVLAN_MEMBERCFG53_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG53_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG53_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG53_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG54_CTRL4    0x0cf7
+#define    RTL8367C_SVLAN_MEMBERCFG54_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG54_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG54_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG54_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG55_CTRL4    0x0cf8
+#define    RTL8367C_SVLAN_MEMBERCFG55_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG55_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG55_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG55_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG56_CTRL4    0x0cf9
+#define    RTL8367C_SVLAN_MEMBERCFG56_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG56_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG56_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG56_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG57_CTRL4    0x0cfa
+#define    RTL8367C_SVLAN_MEMBERCFG57_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG57_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG57_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG57_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG58_CTRL4    0x0cfb
+#define    RTL8367C_SVLAN_MEMBERCFG58_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG58_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG58_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG58_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG59_CTRL4    0x0cfc
+#define    RTL8367C_SVLAN_MEMBERCFG59_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG59_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG59_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG59_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG60_CTRL4    0x0cfd
+#define    RTL8367C_SVLAN_MEMBERCFG60_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG60_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG60_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG60_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG61_CTRL4    0x0cfe
+#define    RTL8367C_SVLAN_MEMBERCFG61_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG61_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG61_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG61_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG62_CTRL4    0x0cff
+#define    RTL8367C_SVLAN_MEMBERCFG62_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG62_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG62_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG62_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_C2SCFG0_CTRL0    0x0d00
+#define    RTL8367C_SVLAN_C2SCFG0_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG0_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG0_CTRL1    0x0d01
+#define    RTL8367C_SVLAN_C2SCFG0_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG0_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG0_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG0_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG0_CTRL2    0x0d02
+#define    RTL8367C_SVLAN_C2SCFG0_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG0_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG1_CTRL0    0x0d03
+#define    RTL8367C_SVLAN_C2SCFG1_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG1_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG1_CTRL1    0x0d04
+#define    RTL8367C_SVLAN_C2SCFG1_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG1_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG1_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG1_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG1_CTRL2    0x0d05
+#define    RTL8367C_SVLAN_C2SCFG1_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG1_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG2_CTRL0    0x0d06
+#define    RTL8367C_SVLAN_C2SCFG2_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG2_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG2_CTRL1    0x0d07
+#define    RTL8367C_SVLAN_C2SCFG2_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG2_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG2_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG2_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG2_CTRL2    0x0d08
+#define    RTL8367C_SVLAN_C2SCFG2_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG2_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG3_CTRL0    0x0d09
+#define    RTL8367C_SVLAN_C2SCFG3_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG3_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG3_CTRL1    0x0d0a
+#define    RTL8367C_SVLAN_C2SCFG3_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG3_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG3_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG3_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG3_CTRL2    0x0d0b
+#define    RTL8367C_SVLAN_C2SCFG3_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG3_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG4_CTRL0    0x0d0c
+#define    RTL8367C_SVLAN_C2SCFG4_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG4_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG4_CTRL1    0x0d0d
+#define    RTL8367C_SVLAN_C2SCFG4_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG4_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG4_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG4_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG4_CTRL2    0x0d0e
+#define    RTL8367C_SVLAN_C2SCFG4_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG4_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG5_CTRL0    0x0d0f
+#define    RTL8367C_SVLAN_C2SCFG5_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG5_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG5_CTRL1    0x0d10
+#define    RTL8367C_SVLAN_C2SCFG5_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG5_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG5_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG5_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG5_CTRL2    0x0d11
+#define    RTL8367C_SVLAN_C2SCFG5_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG5_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG6_CTRL0    0x0d12
+#define    RTL8367C_SVLAN_C2SCFG6_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG6_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG6_CTRL1    0x0d13
+#define    RTL8367C_SVLAN_C2SCFG6_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG6_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG6_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG6_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG6_CTRL2    0x0d14
+#define    RTL8367C_SVLAN_C2SCFG6_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG6_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG7_CTRL0    0x0d15
+#define    RTL8367C_SVLAN_C2SCFG7_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG7_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG7_CTRL1    0x0d16
+#define    RTL8367C_SVLAN_C2SCFG7_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG7_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG7_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG7_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG7_CTRL2    0x0d17
+#define    RTL8367C_SVLAN_C2SCFG7_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG7_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG8_CTRL0    0x0d18
+#define    RTL8367C_SVLAN_C2SCFG8_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG8_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG8_CTRL1    0x0d19
+#define    RTL8367C_SVLAN_C2SCFG8_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG8_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG8_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG8_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG8_CTRL2    0x0d1a
+#define    RTL8367C_SVLAN_C2SCFG8_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG8_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG9_CTRL0    0x0d1b
+#define    RTL8367C_SVLAN_C2SCFG9_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG9_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG9_CTRL1    0x0d1c
+#define    RTL8367C_SVLAN_C2SCFG9_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG9_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG9_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG9_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG9_CTRL2    0x0d1d
+#define    RTL8367C_SVLAN_C2SCFG9_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG9_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG10_CTRL0    0x0d1e
+#define    RTL8367C_SVLAN_C2SCFG10_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG10_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG10_CTRL1    0x0d1f
+#define    RTL8367C_SVLAN_C2SCFG10_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG10_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG10_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG10_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG10_CTRL2    0x0d20
+#define    RTL8367C_SVLAN_C2SCFG10_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG10_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG11_CTRL0    0x0d21
+#define    RTL8367C_SVLAN_C2SCFG11_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG11_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG11_CTRL1    0x0d22
+#define    RTL8367C_SVLAN_C2SCFG11_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG11_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG11_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG11_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG11_CTRL2    0x0d23
+#define    RTL8367C_SVLAN_C2SCFG11_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG11_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG12_CTRL0    0x0d24
+#define    RTL8367C_SVLAN_C2SCFG12_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG12_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG12_CTRL1    0x0d25
+#define    RTL8367C_SVLAN_C2SCFG12_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG12_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG12_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG12_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG12_CTRL2    0x0d26
+#define    RTL8367C_SVLAN_C2SCFG12_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG12_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG13_CTRL0    0x0d27
+#define    RTL8367C_SVLAN_C2SCFG13_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG13_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG13_CTRL1    0x0d28
+#define    RTL8367C_SVLAN_C2SCFG13_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG13_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG13_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG13_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG13_CTRL2    0x0d29
+#define    RTL8367C_SVLAN_C2SCFG13_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG13_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG14_CTRL0    0x0d2a
+#define    RTL8367C_SVLAN_C2SCFG14_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG14_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG14_CTRL1    0x0d2b
+#define    RTL8367C_SVLAN_C2SCFG14_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG14_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG14_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG14_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG14_CTRL2    0x0d2c
+#define    RTL8367C_SVLAN_C2SCFG14_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG14_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG15_CTRL0    0x0d2d
+#define    RTL8367C_SVLAN_C2SCFG15_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG15_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG15_CTRL1    0x0d2e
+#define    RTL8367C_SVLAN_C2SCFG15_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG15_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG15_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG15_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG15_CTRL2    0x0d2f
+#define    RTL8367C_SVLAN_C2SCFG15_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG15_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG16_CTRL0    0x0d30
+#define    RTL8367C_SVLAN_C2SCFG16_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG16_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG16_CTRL1    0x0d31
+#define    RTL8367C_SVLAN_C2SCFG16_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG16_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG16_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG16_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG16_CTRL2    0x0d32
+#define    RTL8367C_SVLAN_C2SCFG16_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG16_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG17_CTRL0    0x0d33
+#define    RTL8367C_SVLAN_C2SCFG17_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG17_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG17_CTRL1    0x0d34
+#define    RTL8367C_SVLAN_C2SCFG17_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG17_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG17_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG17_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG17_CTRL2    0x0d35
+#define    RTL8367C_SVLAN_C2SCFG17_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG17_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG18_CTRL0    0x0d36
+#define    RTL8367C_SVLAN_C2SCFG18_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG18_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG18_CTRL1    0x0d37
+#define    RTL8367C_SVLAN_C2SCFG18_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG18_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG18_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG18_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG18_CTRL2    0x0d38
+#define    RTL8367C_SVLAN_C2SCFG18_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG18_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG19_CTRL0    0x0d39
+#define    RTL8367C_SVLAN_C2SCFG19_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG19_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG19_CTRL1    0x0d3a
+#define    RTL8367C_SVLAN_C2SCFG19_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG19_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG19_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG19_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG19_CTRL2    0x0d3b
+#define    RTL8367C_SVLAN_C2SCFG19_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG19_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG20_CTRL0    0x0d3c
+#define    RTL8367C_SVLAN_C2SCFG20_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG20_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG20_CTRL1    0x0d3d
+#define    RTL8367C_SVLAN_C2SCFG20_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG20_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG20_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG20_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG20_CTRL2    0x0d3e
+#define    RTL8367C_SVLAN_C2SCFG20_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG20_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG21_CTRL0    0x0d3f
+#define    RTL8367C_SVLAN_C2SCFG21_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG21_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG21_CTRL1    0x0d40
+#define    RTL8367C_SVLAN_C2SCFG21_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG21_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG21_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG21_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG21_CTRL2    0x0d41
+#define    RTL8367C_SVLAN_C2SCFG21_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG21_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG22_CTRL0    0x0d42
+#define    RTL8367C_SVLAN_C2SCFG22_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG22_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG22_CTRL1    0x0d43
+#define    RTL8367C_SVLAN_C2SCFG22_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG22_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG22_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG22_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG22_CTRL2    0x0d44
+#define    RTL8367C_SVLAN_C2SCFG22_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG22_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG23_CTRL0    0x0d45
+#define    RTL8367C_SVLAN_C2SCFG23_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG23_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG23_CTRL1    0x0d46
+#define    RTL8367C_SVLAN_C2SCFG23_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG23_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG23_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG23_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG23_CTRL2    0x0d47
+#define    RTL8367C_SVLAN_C2SCFG23_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG23_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG24_CTRL0    0x0d48
+#define    RTL8367C_SVLAN_C2SCFG24_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG24_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG24_CTRL1    0x0d49
+#define    RTL8367C_SVLAN_C2SCFG24_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG24_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG24_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG24_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG24_CTRL2    0x0d4a
+#define    RTL8367C_SVLAN_C2SCFG24_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG24_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG25_CTRL0    0x0d4b
+#define    RTL8367C_SVLAN_C2SCFG25_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG25_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG25_CTRL1    0x0d4c
+#define    RTL8367C_SVLAN_C2SCFG25_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG25_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG25_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG25_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG25_CTRL2    0x0d4d
+#define    RTL8367C_SVLAN_C2SCFG25_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG25_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG26_CTRL0    0x0d4e
+#define    RTL8367C_SVLAN_C2SCFG26_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG26_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG26_CTRL1    0x0d4f
+#define    RTL8367C_SVLAN_C2SCFG26_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG26_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG26_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG26_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG26_CTRL2    0x0d50
+#define    RTL8367C_SVLAN_C2SCFG26_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG26_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG27_CTRL0    0x0d51
+#define    RTL8367C_SVLAN_C2SCFG27_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG27_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG27_CTRL1    0x0d52
+#define    RTL8367C_SVLAN_C2SCFG27_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG27_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG27_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG27_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG27_CTRL2    0x0d53
+#define    RTL8367C_SVLAN_C2SCFG27_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG27_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG28_CTRL0    0x0d54
+#define    RTL8367C_SVLAN_C2SCFG28_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG28_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG28_CTRL1    0x0d55
+#define    RTL8367C_SVLAN_C2SCFG28_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG28_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG28_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG28_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG28_CTRL2    0x0d56
+#define    RTL8367C_SVLAN_C2SCFG28_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG28_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG29_CTRL0    0x0d57
+#define    RTL8367C_SVLAN_C2SCFG29_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG29_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG29_CTRL1    0x0d58
+#define    RTL8367C_SVLAN_C2SCFG29_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG29_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG29_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG29_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG29_CTRL2    0x0d59
+#define    RTL8367C_SVLAN_C2SCFG29_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG29_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG30_CTRL0    0x0d5a
+#define    RTL8367C_SVLAN_C2SCFG30_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG30_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG30_CTRL1    0x0d5b
+#define    RTL8367C_SVLAN_C2SCFG30_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG30_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG30_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG30_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG30_CTRL2    0x0d5c
+#define    RTL8367C_SVLAN_C2SCFG30_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG30_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG31_CTRL0    0x0d5d
+#define    RTL8367C_SVLAN_C2SCFG31_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG31_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG31_CTRL1    0x0d5e
+#define    RTL8367C_SVLAN_C2SCFG31_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG31_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG31_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG31_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG31_CTRL2    0x0d5f
+#define    RTL8367C_SVLAN_C2SCFG31_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG31_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG32_CTRL0    0x0d60
+#define    RTL8367C_SVLAN_C2SCFG32_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG32_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG32_CTRL1    0x0d61
+#define    RTL8367C_SVLAN_C2SCFG32_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG32_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG32_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG32_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG32_CTRL2    0x0d62
+#define    RTL8367C_SVLAN_C2SCFG32_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG32_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG33_CTRL0    0x0d63
+#define    RTL8367C_SVLAN_C2SCFG33_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG33_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG33_CTRL1    0x0d64
+#define    RTL8367C_SVLAN_C2SCFG33_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG33_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG33_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG33_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG33_CTRL2    0x0d65
+#define    RTL8367C_SVLAN_C2SCFG33_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG33_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG34_CTRL0    0x0d66
+#define    RTL8367C_SVLAN_C2SCFG34_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG34_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG34_CTRL1    0x0d67
+#define    RTL8367C_SVLAN_C2SCFG34_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG34_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG34_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG34_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG34_CTRL2    0x0d68
+#define    RTL8367C_SVLAN_C2SCFG34_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG34_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG35_CTRL0    0x0d69
+#define    RTL8367C_SVLAN_C2SCFG35_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG35_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG35_CTRL1    0x0d6a
+#define    RTL8367C_SVLAN_C2SCFG35_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG35_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG35_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG35_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG35_CTRL2    0x0d6b
+#define    RTL8367C_SVLAN_C2SCFG35_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG35_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG36_CTRL0    0x0d6c
+#define    RTL8367C_SVLAN_C2SCFG36_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG36_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG36_CTRL1    0x0d6d
+#define    RTL8367C_SVLAN_C2SCFG36_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG36_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG36_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG36_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG36_CTRL2    0x0d6e
+#define    RTL8367C_SVLAN_C2SCFG36_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG36_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG37_CTRL0    0x0d6f
+#define    RTL8367C_SVLAN_C2SCFG37_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG37_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG37_CTRL1    0x0d70
+#define    RTL8367C_SVLAN_C2SCFG37_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG37_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG37_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG37_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG37_CTRL2    0x0d71
+#define    RTL8367C_SVLAN_C2SCFG37_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG37_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG38_CTRL0    0x0d72
+#define    RTL8367C_SVLAN_C2SCFG38_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG38_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG38_CTRL1    0x0d73
+#define    RTL8367C_SVLAN_C2SCFG38_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG38_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG38_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG38_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG38_CTRL2    0x0d74
+#define    RTL8367C_SVLAN_C2SCFG38_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG38_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG39_CTRL0    0x0d75
+#define    RTL8367C_SVLAN_C2SCFG39_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG39_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG39_CTRL1    0x0d76
+#define    RTL8367C_SVLAN_C2SCFG39_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG39_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG39_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG39_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG39_CTRL2    0x0d77
+#define    RTL8367C_SVLAN_C2SCFG39_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG39_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG40_CTRL0    0x0d78
+#define    RTL8367C_SVLAN_C2SCFG40_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG40_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG40_CTRL1    0x0d79
+#define    RTL8367C_SVLAN_C2SCFG40_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG40_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG40_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG40_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG40_CTRL2    0x0d7a
+#define    RTL8367C_SVLAN_C2SCFG40_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG40_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG41_CTRL0    0x0d7b
+#define    RTL8367C_SVLAN_C2SCFG41_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG41_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG41_CTRL1    0x0d7c
+#define    RTL8367C_SVLAN_C2SCFG41_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG41_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG41_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG41_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG41_CTRL2    0x0d7d
+#define    RTL8367C_SVLAN_C2SCFG41_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG41_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG42_CTRL0    0x0d7e
+#define    RTL8367C_SVLAN_C2SCFG42_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG42_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG42_CTRL1    0x0d7f
+#define    RTL8367C_SVLAN_C2SCFG42_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG42_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG42_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG42_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG42_CTRL2    0x0d80
+#define    RTL8367C_SVLAN_C2SCFG42_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG42_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG43_CTRL0    0x0d81
+#define    RTL8367C_SVLAN_C2SCFG43_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG43_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG43_CTRL1    0x0d82
+#define    RTL8367C_SVLAN_C2SCFG43_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG43_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG43_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG43_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG43_CTRL2    0x0d83
+#define    RTL8367C_SVLAN_C2SCFG43_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG43_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG44_CTRL0    0x0d84
+#define    RTL8367C_SVLAN_C2SCFG44_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG44_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG44_CTRL1    0x0d85
+#define    RTL8367C_SVLAN_C2SCFG44_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG44_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG44_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG44_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG44_CTRL2    0x0d86
+#define    RTL8367C_SVLAN_C2SCFG44_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG44_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG45_CTRL0    0x0d87
+#define    RTL8367C_SVLAN_C2SCFG45_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG45_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG45_CTRL1    0x0d88
+#define    RTL8367C_SVLAN_C2SCFG45_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG45_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG45_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG45_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG45_CTRL2    0x0d89
+#define    RTL8367C_SVLAN_C2SCFG45_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG45_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG46_CTRL0    0x0d8a
+#define    RTL8367C_SVLAN_C2SCFG46_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG46_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG46_CTRL1    0x0d8b
+#define    RTL8367C_SVLAN_C2SCFG46_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG46_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG46_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG46_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG46_CTRL2    0x0d8c
+#define    RTL8367C_SVLAN_C2SCFG46_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG46_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG47_CTRL0    0x0d8d
+#define    RTL8367C_SVLAN_C2SCFG47_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG47_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG47_CTRL1    0x0d8e
+#define    RTL8367C_SVLAN_C2SCFG47_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG47_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG47_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG47_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG47_CTRL2    0x0d8f
+#define    RTL8367C_SVLAN_C2SCFG47_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG47_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG48_CTRL0    0x0d90
+#define    RTL8367C_SVLAN_C2SCFG48_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG48_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG48_CTRL1    0x0d91
+#define    RTL8367C_SVLAN_C2SCFG48_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG48_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG48_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG48_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG48_CTRL2    0x0d92
+#define    RTL8367C_SVLAN_C2SCFG48_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG48_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG49_CTRL0    0x0d93
+#define    RTL8367C_SVLAN_C2SCFG49_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG49_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG49_CTRL1    0x0d94
+#define    RTL8367C_SVLAN_C2SCFG49_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG49_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG49_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG49_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG49_CTRL2    0x0d95
+#define    RTL8367C_SVLAN_C2SCFG49_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG49_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG50_CTRL0    0x0d96
+#define    RTL8367C_SVLAN_C2SCFG50_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG50_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG50_CTRL1    0x0d97
+#define    RTL8367C_SVLAN_C2SCFG50_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG50_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG50_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG50_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG50_CTRL2    0x0d98
+#define    RTL8367C_SVLAN_C2SCFG50_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG50_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG51_CTRL0    0x0d99
+#define    RTL8367C_SVLAN_C2SCFG51_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG51_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG51_CTRL1    0x0d9a
+#define    RTL8367C_SVLAN_C2SCFG51_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG51_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG51_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG51_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG51_CTRL2    0x0d9b
+#define    RTL8367C_SVLAN_C2SCFG51_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG51_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG52_CTRL0    0x0d9c
+#define    RTL8367C_SVLAN_C2SCFG52_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG52_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG52_CTRL1    0x0d9d
+#define    RTL8367C_SVLAN_C2SCFG52_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG52_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG52_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG52_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG52_CTRL2    0x0d9e
+#define    RTL8367C_SVLAN_C2SCFG52_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG52_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG53_CTRL0    0x0d9f
+#define    RTL8367C_SVLAN_C2SCFG53_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG53_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG53_CTRL1    0x0da0
+#define    RTL8367C_SVLAN_C2SCFG53_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG53_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG53_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG53_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG53_CTRL2    0x0da1
+#define    RTL8367C_SVLAN_C2SCFG53_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG53_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG54_CTRL0    0x0da2
+#define    RTL8367C_SVLAN_C2SCFG54_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG54_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG54_CTRL1    0x0da3
+#define    RTL8367C_SVLAN_C2SCFG54_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG54_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG54_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG54_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG54_CTRL2    0x0da4
+#define    RTL8367C_SVLAN_C2SCFG54_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG54_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG55_CTRL0    0x0da5
+#define    RTL8367C_SVLAN_C2SCFG55_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG55_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG55_CTRL1    0x0da6
+#define    RTL8367C_SVLAN_C2SCFG55_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG55_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG55_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG55_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG55_CTRL2    0x0da7
+#define    RTL8367C_SVLAN_C2SCFG55_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG55_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG56_CTRL0    0x0da8
+#define    RTL8367C_SVLAN_C2SCFG56_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG56_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG56_CTRL1    0x0da9
+#define    RTL8367C_SVLAN_C2SCFG56_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG56_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG56_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG56_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG56_CTRL2    0x0daa
+#define    RTL8367C_SVLAN_C2SCFG56_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG56_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG57_CTRL0    0x0dab
+#define    RTL8367C_SVLAN_C2SCFG57_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG57_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG57_CTRL1    0x0dac
+#define    RTL8367C_SVLAN_C2SCFG57_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG57_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG57_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG57_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG57_CTRL2    0x0dad
+#define    RTL8367C_SVLAN_C2SCFG57_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG57_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG58_CTRL0    0x0dae
+#define    RTL8367C_SVLAN_C2SCFG58_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG58_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG58_CTRL1    0x0daf
+#define    RTL8367C_SVLAN_C2SCFG58_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG58_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG58_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG58_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG58_CTRL2    0x0db0
+#define    RTL8367C_SVLAN_C2SCFG58_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG58_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG59_CTRL0    0x0db1
+#define    RTL8367C_SVLAN_C2SCFG59_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG59_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG59_CTRL1    0x0db2
+#define    RTL8367C_SVLAN_C2SCFG59_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG59_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG59_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG59_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG59_CTRL2    0x0db3
+#define    RTL8367C_SVLAN_C2SCFG59_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG59_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG60_CTRL0    0x0db4
+#define    RTL8367C_SVLAN_C2SCFG60_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG60_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG60_CTRL1    0x0db5
+#define    RTL8367C_SVLAN_C2SCFG60_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG60_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG60_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG60_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG60_CTRL2    0x0db6
+#define    RTL8367C_SVLAN_C2SCFG60_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG60_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG61_CTRL0    0x0db7
+#define    RTL8367C_SVLAN_C2SCFG61_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG61_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG61_CTRL1    0x0db8
+#define    RTL8367C_SVLAN_C2SCFG61_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG61_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG61_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG61_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG61_CTRL2    0x0db9
+#define    RTL8367C_SVLAN_C2SCFG61_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG61_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG62_CTRL0    0x0dba
+#define    RTL8367C_SVLAN_C2SCFG62_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG62_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG62_CTRL1    0x0dbb
+#define    RTL8367C_SVLAN_C2SCFG62_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG62_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG62_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG62_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG62_CTRL2    0x0dbc
+#define    RTL8367C_SVLAN_C2SCFG62_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG62_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG63_CTRL0    0x0dbd
+#define    RTL8367C_SVLAN_C2SCFG63_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG63_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG63_CTRL1    0x0dbe
+#define    RTL8367C_SVLAN_C2SCFG63_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG63_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG63_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG63_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG63_CTRL2    0x0dbf
+#define    RTL8367C_SVLAN_C2SCFG63_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG63_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG64_CTRL0    0x0dc0
+#define    RTL8367C_SVLAN_C2SCFG64_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG64_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG64_CTRL1    0x0dc1
+#define    RTL8367C_SVLAN_C2SCFG64_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG64_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG64_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG64_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG64_CTRL2    0x0dc2
+#define    RTL8367C_SVLAN_C2SCFG64_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG64_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG65_CTRL0    0x0dc3
+#define    RTL8367C_SVLAN_C2SCFG65_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG65_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG65_CTRL1    0x0dc4
+#define    RTL8367C_SVLAN_C2SCFG65_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG65_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG65_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG65_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG65_CTRL2    0x0dc5
+#define    RTL8367C_SVLAN_C2SCFG65_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG65_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG66_CTRL0    0x0dc6
+#define    RTL8367C_SVLAN_C2SCFG66_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG66_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG66_CTRL1    0x0dc7
+#define    RTL8367C_SVLAN_C2SCFG66_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG66_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG66_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG66_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG66_CTRL2    0x0dc8
+#define    RTL8367C_SVLAN_C2SCFG66_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG66_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG67_CTRL0    0x0dc9
+#define    RTL8367C_SVLAN_C2SCFG67_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG67_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG67_CTRL1    0x0dca
+#define    RTL8367C_SVLAN_C2SCFG67_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG67_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG67_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG67_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG67_CTRL2    0x0dcb
+#define    RTL8367C_SVLAN_C2SCFG67_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG67_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG68_CTRL0    0x0dcc
+#define    RTL8367C_SVLAN_C2SCFG68_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG68_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG68_CTRL1    0x0dcd
+#define    RTL8367C_SVLAN_C2SCFG68_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG68_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG68_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG68_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG68_CTRL2    0x0dce
+#define    RTL8367C_SVLAN_C2SCFG68_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG68_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG69_CTRL0    0x0dcf
+#define    RTL8367C_SVLAN_C2SCFG69_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG69_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG69_CTRL1    0x0dd0
+#define    RTL8367C_SVLAN_C2SCFG69_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG69_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG69_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG69_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG69_CTRL2    0x0dd1
+#define    RTL8367C_SVLAN_C2SCFG69_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG69_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG70_CTRL0    0x0dd2
+#define    RTL8367C_SVLAN_C2SCFG70_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG70_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG70_CTRL1    0x0dd3
+#define    RTL8367C_SVLAN_C2SCFG70_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG70_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG70_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG70_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG70_CTRL2    0x0dd4
+#define    RTL8367C_SVLAN_C2SCFG70_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG70_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG71_CTRL0    0x0dd5
+#define    RTL8367C_SVLAN_C2SCFG71_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG71_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG71_CTRL1    0x0dd6
+#define    RTL8367C_SVLAN_C2SCFG71_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG71_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG71_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG71_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG71_CTRL2    0x0dd7
+#define    RTL8367C_SVLAN_C2SCFG71_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG71_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG72_CTRL0    0x0dd8
+#define    RTL8367C_SVLAN_C2SCFG72_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG72_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG72_CTRL1    0x0dd9
+#define    RTL8367C_SVLAN_C2SCFG72_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG72_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG72_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG72_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG72_CTRL2    0x0dda
+#define    RTL8367C_SVLAN_C2SCFG72_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG72_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG73_CTRL0    0x0ddb
+#define    RTL8367C_SVLAN_C2SCFG73_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG73_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG73_CTRL1    0x0ddc
+#define    RTL8367C_SVLAN_C2SCFG73_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG73_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG73_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG73_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG73_CTRL2    0x0ddd
+#define    RTL8367C_SVLAN_C2SCFG73_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG73_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG74_CTRL0    0x0dde
+#define    RTL8367C_SVLAN_C2SCFG74_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG74_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG74_CTRL1    0x0ddf
+#define    RTL8367C_SVLAN_C2SCFG74_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG74_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG74_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG74_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG74_CTRL2    0x0de0
+#define    RTL8367C_SVLAN_C2SCFG74_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG74_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG75_CTRL0    0x0de1
+#define    RTL8367C_SVLAN_C2SCFG75_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG75_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG75_CTRL1    0x0de2
+#define    RTL8367C_SVLAN_C2SCFG75_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG75_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG75_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG75_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG75_CTRL2    0x0de3
+#define    RTL8367C_SVLAN_C2SCFG75_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG75_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG76_CTRL0    0x0de4
+#define    RTL8367C_SVLAN_C2SCFG76_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG76_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG76_CTRL1    0x0de5
+#define    RTL8367C_SVLAN_C2SCFG76_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG76_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG76_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG76_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG76_CTRL2    0x0de6
+#define    RTL8367C_SVLAN_C2SCFG76_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG76_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG77_CTRL0    0x0de7
+#define    RTL8367C_SVLAN_C2SCFG77_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG77_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG77_CTRL1    0x0de8
+#define    RTL8367C_SVLAN_C2SCFG77_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG77_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG77_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG77_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG77_CTRL2    0x0de9
+#define    RTL8367C_SVLAN_C2SCFG77_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG77_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG78_CTRL0    0x0dea
+#define    RTL8367C_SVLAN_C2SCFG78_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG78_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG78_CTRL1    0x0deb
+#define    RTL8367C_SVLAN_C2SCFG78_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG78_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG78_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG78_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG78_CTRL2    0x0dec
+#define    RTL8367C_SVLAN_C2SCFG78_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG78_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG79_CTRL0    0x0ded
+#define    RTL8367C_SVLAN_C2SCFG79_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG79_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG79_CTRL1    0x0dee
+#define    RTL8367C_SVLAN_C2SCFG79_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG79_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG79_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG79_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG79_CTRL2    0x0def
+#define    RTL8367C_SVLAN_C2SCFG79_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG79_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG80_CTRL0    0x0df0
+#define    RTL8367C_SVLAN_C2SCFG80_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG80_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG80_CTRL1    0x0df1
+#define    RTL8367C_SVLAN_C2SCFG80_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG80_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG80_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG80_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG80_CTRL2    0x0df2
+#define    RTL8367C_SVLAN_C2SCFG80_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG80_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG81_CTRL0    0x0df3
+#define    RTL8367C_SVLAN_C2SCFG81_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG81_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG81_CTRL1    0x0df4
+#define    RTL8367C_SVLAN_C2SCFG81_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG81_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG81_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG81_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG81_CTRL2    0x0df5
+#define    RTL8367C_SVLAN_C2SCFG81_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG81_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG82_CTRL0    0x0df6
+#define    RTL8367C_SVLAN_C2SCFG82_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG82_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG82_CTRL1    0x0df7
+#define    RTL8367C_SVLAN_C2SCFG82_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG82_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG82_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG82_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG82_CTRL2    0x0df8
+#define    RTL8367C_SVLAN_C2SCFG82_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG82_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG83_CTRL0    0x0df9
+#define    RTL8367C_SVLAN_C2SCFG83_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG83_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG83_CTRL1    0x0dfa
+#define    RTL8367C_SVLAN_C2SCFG83_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG83_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG83_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG83_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG83_CTRL2    0x0dfb
+#define    RTL8367C_SVLAN_C2SCFG83_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG83_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG84_CTRL0    0x0dfc
+#define    RTL8367C_SVLAN_C2SCFG84_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG84_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG84_CTRL1    0x0dfd
+#define    RTL8367C_SVLAN_C2SCFG84_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG84_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG84_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG84_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG84_CTRL2    0x0dfe
+#define    RTL8367C_SVLAN_C2SCFG84_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG84_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG85_CTRL0    0x0dff
+#define    RTL8367C_SVLAN_C2SCFG85_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG85_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG85_CTRL1    0x0e00
+#define    RTL8367C_SVLAN_C2SCFG85_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG85_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG85_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG85_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG85_CTRL2    0x0e01
+#define    RTL8367C_SVLAN_C2SCFG85_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG85_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG86_CTRL0    0x0e02
+#define    RTL8367C_SVLAN_C2SCFG86_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG86_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG86_CTRL1    0x0e03
+#define    RTL8367C_SVLAN_C2SCFG86_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG86_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG86_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG86_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG86_CTRL2    0x0e04
+#define    RTL8367C_SVLAN_C2SCFG86_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG86_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG87_CTRL0    0x0e05
+#define    RTL8367C_SVLAN_C2SCFG87_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG87_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG87_CTRL1    0x0e06
+#define    RTL8367C_SVLAN_C2SCFG87_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG87_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG87_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG87_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG87_CTRL2    0x0e07
+#define    RTL8367C_SVLAN_C2SCFG87_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG87_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG88_CTRL0    0x0e08
+#define    RTL8367C_SVLAN_C2SCFG88_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG88_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG88_CTRL1    0x0e09
+#define    RTL8367C_SVLAN_C2SCFG88_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG88_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG88_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG88_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG88_CTRL2    0x0e0a
+#define    RTL8367C_SVLAN_C2SCFG88_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG88_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG89_CTRL0    0x0e0b
+#define    RTL8367C_SVLAN_C2SCFG89_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG89_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG89_CTRL1    0x0e0c
+#define    RTL8367C_SVLAN_C2SCFG89_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG89_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG89_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG89_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG89_CTRL2    0x0e0d
+#define    RTL8367C_SVLAN_C2SCFG89_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG89_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG90_CTRL0    0x0e0e
+#define    RTL8367C_SVLAN_C2SCFG90_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG90_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG90_CTRL1    0x0e0f
+#define    RTL8367C_SVLAN_C2SCFG90_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG90_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG90_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG90_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG90_CTRL2    0x0e10
+#define    RTL8367C_SVLAN_C2SCFG90_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG90_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG91_CTRL0    0x0e11
+#define    RTL8367C_SVLAN_C2SCFG91_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG91_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG91_CTRL1    0x0e12
+#define    RTL8367C_SVLAN_C2SCFG91_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG91_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG91_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG91_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG91_CTRL2    0x0e13
+#define    RTL8367C_SVLAN_C2SCFG91_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG91_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG92_CTRL0    0x0e14
+#define    RTL8367C_SVLAN_C2SCFG92_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG92_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG92_CTRL1    0x0e15
+#define    RTL8367C_SVLAN_C2SCFG92_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG92_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG92_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG92_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG92_CTRL2    0x0e16
+#define    RTL8367C_SVLAN_C2SCFG92_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG92_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG93_CTRL0    0x0e17
+#define    RTL8367C_SVLAN_C2SCFG93_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG93_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG93_CTRL1    0x0e18
+#define    RTL8367C_SVLAN_C2SCFG93_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG93_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG93_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG93_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG93_CTRL2    0x0e19
+#define    RTL8367C_SVLAN_C2SCFG93_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG93_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG94_CTRL0    0x0e1a
+#define    RTL8367C_SVLAN_C2SCFG94_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG94_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG94_CTRL1    0x0e1b
+#define    RTL8367C_SVLAN_C2SCFG94_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG94_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG94_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG94_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG94_CTRL2    0x0e1c
+#define    RTL8367C_SVLAN_C2SCFG94_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG94_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG95_CTRL0    0x0e1d
+#define    RTL8367C_SVLAN_C2SCFG95_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG95_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG95_CTRL1    0x0e1e
+#define    RTL8367C_SVLAN_C2SCFG95_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG95_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG95_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG95_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG95_CTRL2    0x0e1f
+#define    RTL8367C_SVLAN_C2SCFG95_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG95_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG96_CTRL0    0x0e20
+#define    RTL8367C_SVLAN_C2SCFG96_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG96_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG96_CTRL1    0x0e21
+#define    RTL8367C_SVLAN_C2SCFG96_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG96_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG96_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG96_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG96_CTRL2    0x0e22
+#define    RTL8367C_SVLAN_C2SCFG96_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG96_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG97_CTRL0    0x0e23
+#define    RTL8367C_SVLAN_C2SCFG97_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG97_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG97_CTRL1    0x0e24
+#define    RTL8367C_SVLAN_C2SCFG97_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG97_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG97_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG97_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG97_CTRL2    0x0e25
+#define    RTL8367C_SVLAN_C2SCFG97_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG97_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG98_CTRL0    0x0e26
+#define    RTL8367C_SVLAN_C2SCFG98_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG98_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG98_CTRL1    0x0e27
+#define    RTL8367C_SVLAN_C2SCFG98_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG98_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG98_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG98_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG98_CTRL2    0x0e28
+#define    RTL8367C_SVLAN_C2SCFG98_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG98_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG99_CTRL0    0x0e29
+#define    RTL8367C_SVLAN_C2SCFG99_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG99_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG99_CTRL1    0x0e2a
+#define    RTL8367C_SVLAN_C2SCFG99_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG99_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG99_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG99_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG99_CTRL2    0x0e2b
+#define    RTL8367C_SVLAN_C2SCFG99_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG99_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG100_CTRL0    0x0e2c
+#define    RTL8367C_SVLAN_C2SCFG100_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG100_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG100_CTRL1    0x0e2d
+#define    RTL8367C_SVLAN_C2SCFG100_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG100_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG100_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG100_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG100_CTRL2    0x0e2e
+#define    RTL8367C_SVLAN_C2SCFG100_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG100_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG101_CTRL0    0x0e2f
+#define    RTL8367C_SVLAN_C2SCFG101_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG101_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG101_CTRL1    0x0e30
+#define    RTL8367C_SVLAN_C2SCFG101_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG101_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG101_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG101_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG101_CTRL2    0x0e31
+#define    RTL8367C_SVLAN_C2SCFG101_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG101_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG102_CTRL0    0x0e32
+#define    RTL8367C_SVLAN_C2SCFG102_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG102_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG102_CTRL1    0x0e33
+#define    RTL8367C_SVLAN_C2SCFG102_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG102_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG102_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG102_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG102_CTRL2    0x0e34
+#define    RTL8367C_SVLAN_C2SCFG102_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG102_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG103_CTRL0    0x0e35
+#define    RTL8367C_SVLAN_C2SCFG103_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG103_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG103_CTRL1    0x0e36
+#define    RTL8367C_SVLAN_C2SCFG103_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG103_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG103_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG103_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG103_CTRL2    0x0e37
+#define    RTL8367C_SVLAN_C2SCFG103_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG103_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG104_CTRL0    0x0e38
+#define    RTL8367C_SVLAN_C2SCFG104_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG104_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG104_CTRL1    0x0e39
+#define    RTL8367C_SVLAN_C2SCFG104_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG104_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG104_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG104_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG104_CTRL2    0x0e3a
+#define    RTL8367C_SVLAN_C2SCFG104_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG104_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG105_CTRL0    0x0e3b
+#define    RTL8367C_SVLAN_C2SCFG105_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG105_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG105_CTRL1    0x0e3c
+#define    RTL8367C_SVLAN_C2SCFG105_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG105_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG105_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG105_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG105_CTRL2    0x0e3d
+#define    RTL8367C_SVLAN_C2SCFG105_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG105_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG106_CTRL0    0x0e3e
+#define    RTL8367C_SVLAN_C2SCFG106_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG106_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG106_CTRL1    0x0e3f
+#define    RTL8367C_SVLAN_C2SCFG106_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG106_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG106_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG106_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG106_CTRL2    0x0e40
+#define    RTL8367C_SVLAN_C2SCFG106_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG106_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG107_CTRL0    0x0e41
+#define    RTL8367C_SVLAN_C2SCFG107_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG107_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG107_CTRL1    0x0e42
+#define    RTL8367C_SVLAN_C2SCFG107_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG107_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG107_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG107_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG107_CTRL2    0x0e43
+#define    RTL8367C_SVLAN_C2SCFG107_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG107_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG108_CTRL0    0x0e44
+#define    RTL8367C_SVLAN_C2SCFG108_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG108_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG108_CTRL1    0x0e45
+#define    RTL8367C_SVLAN_C2SCFG108_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG108_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG108_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG108_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG108_CTRL2    0x0e46
+#define    RTL8367C_SVLAN_C2SCFG108_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG108_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG109_CTRL0    0x0e47
+#define    RTL8367C_SVLAN_C2SCFG109_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG109_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG109_CTRL1    0x0e48
+#define    RTL8367C_SVLAN_C2SCFG109_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG109_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG109_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG109_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG109_CTRL2    0x0e49
+#define    RTL8367C_SVLAN_C2SCFG109_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG109_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG110_CTRL0    0x0e4a
+#define    RTL8367C_SVLAN_C2SCFG110_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG110_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG110_CTRL1    0x0e4b
+#define    RTL8367C_SVLAN_C2SCFG110_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG110_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG110_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG110_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG110_CTRL2    0x0e4c
+#define    RTL8367C_SVLAN_C2SCFG110_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG110_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG111_CTRL0    0x0e4d
+#define    RTL8367C_SVLAN_C2SCFG111_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG111_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG111_CTRL1    0x0e4e
+#define    RTL8367C_SVLAN_C2SCFG111_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG111_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG111_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG111_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG111_CTRL2    0x0e4f
+#define    RTL8367C_SVLAN_C2SCFG111_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG111_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG112_CTRL0    0x0e50
+#define    RTL8367C_SVLAN_C2SCFG112_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG112_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG112_CTRL1    0x0e51
+#define    RTL8367C_SVLAN_C2SCFG112_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG112_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG112_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG112_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG112_CTRL2    0x0e52
+#define    RTL8367C_SVLAN_C2SCFG112_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG112_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG113_CTRL0    0x0e53
+#define    RTL8367C_SVLAN_C2SCFG113_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG113_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG113_CTRL1    0x0e54
+#define    RTL8367C_SVLAN_C2SCFG113_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG113_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG113_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG113_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG113_CTRL2    0x0e55
+#define    RTL8367C_SVLAN_C2SCFG113_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG113_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG114_CTRL0    0x0e56
+#define    RTL8367C_SVLAN_C2SCFG114_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG114_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG114_CTRL1    0x0e57
+#define    RTL8367C_SVLAN_C2SCFG114_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG114_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG114_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG114_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG114_CTRL2    0x0e58
+#define    RTL8367C_SVLAN_C2SCFG114_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG114_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG115_CTRL0    0x0e59
+#define    RTL8367C_SVLAN_C2SCFG115_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG115_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG115_CTRL1    0x0e5a
+#define    RTL8367C_SVLAN_C2SCFG115_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG115_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG115_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG115_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG115_CTRL2    0x0e5b
+#define    RTL8367C_SVLAN_C2SCFG115_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG115_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG116_CTRL0    0x0e5c
+#define    RTL8367C_SVLAN_C2SCFG116_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG116_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG116_CTRL1    0x0e5d
+#define    RTL8367C_SVLAN_C2SCFG116_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG116_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG116_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG116_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG116_CTRL2    0x0e5e
+#define    RTL8367C_SVLAN_C2SCFG116_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG116_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG117_CTRL0    0x0e5f
+#define    RTL8367C_SVLAN_C2SCFG117_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG117_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG117_CTRL1    0x0e60
+#define    RTL8367C_SVLAN_C2SCFG117_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG117_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG117_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG117_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG117_CTRL2    0x0e61
+#define    RTL8367C_SVLAN_C2SCFG117_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG117_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG118_CTRL0    0x0e62
+#define    RTL8367C_SVLAN_C2SCFG118_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG118_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG118_CTRL1    0x0e63
+#define    RTL8367C_SVLAN_C2SCFG118_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG118_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG118_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG118_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG118_CTRL2    0x0e64
+#define    RTL8367C_SVLAN_C2SCFG118_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG118_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG119_CTRL0    0x0e65
+#define    RTL8367C_SVLAN_C2SCFG119_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG119_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG119_CTRL1    0x0e66
+#define    RTL8367C_SVLAN_C2SCFG119_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG119_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG119_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG119_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG119_CTRL2    0x0e67
+#define    RTL8367C_SVLAN_C2SCFG119_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG119_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG120_CTRL0    0x0e68
+#define    RTL8367C_SVLAN_C2SCFG120_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG120_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG120_CTRL1    0x0e69
+#define    RTL8367C_SVLAN_C2SCFG120_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG120_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG120_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG120_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG120_CTRL2    0x0e6a
+#define    RTL8367C_SVLAN_C2SCFG120_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG120_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG121_CTRL0    0x0e6b
+#define    RTL8367C_SVLAN_C2SCFG121_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG121_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG121_CTRL1    0x0e6c
+#define    RTL8367C_SVLAN_C2SCFG121_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG121_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG121_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG121_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG121_CTRL2    0x0e6d
+#define    RTL8367C_SVLAN_C2SCFG121_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG121_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG122_CTRL0    0x0e6e
+#define    RTL8367C_SVLAN_C2SCFG122_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG122_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG122_CTRL1    0x0e6f
+#define    RTL8367C_SVLAN_C2SCFG122_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG122_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG122_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG122_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG122_CTRL2    0x0e70
+#define    RTL8367C_SVLAN_C2SCFG122_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG122_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG123_CTRL0    0x0e71
+#define    RTL8367C_SVLAN_C2SCFG123_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG123_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG123_CTRL1    0x0e72
+#define    RTL8367C_SVLAN_C2SCFG123_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG123_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG123_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG123_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG123_CTRL2    0x0e73
+#define    RTL8367C_SVLAN_C2SCFG123_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG123_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG124_CTRL0    0x0e74
+#define    RTL8367C_SVLAN_C2SCFG124_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG124_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG124_CTRL1    0x0e75
+#define    RTL8367C_SVLAN_C2SCFG124_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG124_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG124_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG124_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG124_CTRL2    0x0e76
+#define    RTL8367C_SVLAN_C2SCFG124_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG124_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG125_CTRL0    0x0e77
+#define    RTL8367C_SVLAN_C2SCFG125_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG125_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG125_CTRL1    0x0e78
+#define    RTL8367C_SVLAN_C2SCFG125_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG125_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG125_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG125_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG125_CTRL2    0x0e79
+#define    RTL8367C_SVLAN_C2SCFG125_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG125_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG126_CTRL0    0x0e7a
+#define    RTL8367C_SVLAN_C2SCFG126_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG126_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG126_CTRL1    0x0e7b
+#define    RTL8367C_SVLAN_C2SCFG126_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG126_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG126_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG126_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG126_CTRL2    0x0e7c
+#define    RTL8367C_SVLAN_C2SCFG126_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG126_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG127_CTRL0    0x0e7d
+#define    RTL8367C_SVLAN_C2SCFG127_CTRL0_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG127_CTRL0_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_C2SCFG127_CTRL1    0x0e7e
+#define    RTL8367C_SVLAN_C2SCFG127_CTRL1_C2SENPMSK_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_C2SCFG127_CTRL1_C2SENPMSK_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_C2SCFG127_CTRL1_C2SENPMSK_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG127_CTRL1_C2SENPMSK_MASK    0xFF
+
+#define    RTL8367C_REG_SVLAN_C2SCFG127_CTRL2    0x0e7f
+#define    RTL8367C_SVLAN_C2SCFG127_CTRL2_OFFSET    0
+#define    RTL8367C_SVLAN_C2SCFG127_CTRL2_MASK    0x1FFF
+
+#define    RTL8367C_REG_SVLAN_CFG    0x0e80
+#define    RTL8367C_VS_PORT7_DMACVIDSEL_OFFSET    14
+#define    RTL8367C_VS_PORT7_DMACVIDSEL_MASK    0x4000
+#define    RTL8367C_VS_PORT6_DMACVIDSEL_OFFSET    13
+#define    RTL8367C_VS_PORT6_DMACVIDSEL_MASK    0x2000
+#define    RTL8367C_VS_PORT5_DMACVIDSEL_OFFSET    12
+#define    RTL8367C_VS_PORT5_DMACVIDSEL_MASK    0x1000
+#define    RTL8367C_VS_PORT4_DMACVIDSEL_OFFSET    11
+#define    RTL8367C_VS_PORT4_DMACVIDSEL_MASK    0x800
+#define    RTL8367C_VS_PORT3_DMACVIDSEL_OFFSET    10
+#define    RTL8367C_VS_PORT3_DMACVIDSEL_MASK    0x400
+#define    RTL8367C_VS_PORT2_DMACVIDSEL_OFFSET    9
+#define    RTL8367C_VS_PORT2_DMACVIDSEL_MASK    0x200
+#define    RTL8367C_VS_PORT1_DMACVIDSEL_OFFSET    8
+#define    RTL8367C_VS_PORT1_DMACVIDSEL_MASK    0x100
+#define    RTL8367C_VS_PORT0_DMACVIDSEL_OFFSET    7
+#define    RTL8367C_VS_PORT0_DMACVIDSEL_MASK    0x80
+#define    RTL8367C_VS_UIFSEG_OFFSET    6
+#define    RTL8367C_VS_UIFSEG_MASK    0x40
+#define    RTL8367C_VS_UNMAT_OFFSET    4
+#define    RTL8367C_VS_UNMAT_MASK    0x30
+#define    RTL8367C_VS_UNTAG_OFFSET    2
+#define    RTL8367C_VS_UNTAG_MASK    0xC
+#define    RTL8367C_VS_SPRISEL_OFFSET    0
+#define    RTL8367C_VS_SPRISEL_MASK    0x3
+
+#define    RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL0    0x0e81
+#define    RTL8367C_VS_PORT1_SVIDX_OFFSET    8
+#define    RTL8367C_VS_PORT1_SVIDX_MASK    0x3F00
+#define    RTL8367C_VS_PORT0_SVIDX_OFFSET    0
+#define    RTL8367C_VS_PORT0_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL1    0x0e82
+#define    RTL8367C_VS_PORT3_SVIDX_OFFSET    8
+#define    RTL8367C_VS_PORT3_SVIDX_MASK    0x3F00
+#define    RTL8367C_VS_PORT2_SVIDX_OFFSET    0
+#define    RTL8367C_VS_PORT2_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL2    0x0e83
+#define    RTL8367C_VS_PORT5_SVIDX_OFFSET    8
+#define    RTL8367C_VS_PORT5_SVIDX_MASK    0x3F00
+#define    RTL8367C_VS_PORT4_SVIDX_OFFSET    0
+#define    RTL8367C_VS_PORT4_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL3    0x0e84
+#define    RTL8367C_VS_PORT7_SVIDX_OFFSET    8
+#define    RTL8367C_VS_PORT7_SVIDX_MASK    0x3F00
+#define    RTL8367C_VS_PORT6_SVIDX_OFFSET    0
+#define    RTL8367C_VS_PORT6_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_UNTAG_UNMAT_CFG    0x0e85
+#define    RTL8367C_VS_UNTAG_SVIDX_OFFSET    8
+#define    RTL8367C_VS_UNTAG_SVIDX_MASK    0x3F00
+#define    RTL8367C_VS_UNMAT_SVIDX_OFFSET    0
+#define    RTL8367C_VS_UNMAT_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_LOOKUP_TYPE    0x0e86
+#define    RTL8367C_SVLAN_LOOKUP_TYPE_OFFSET    0
+#define    RTL8367C_SVLAN_LOOKUP_TYPE_MASK    0x1
+
+#define    RTL8367C_REG_IPMC_GROUP_VALID_15_0    0x0e87
+
+#define    RTL8367C_REG_IPMC_GROUP_VALID_31_16    0x0e88
+
+#define    RTL8367C_REG_IPMC_GROUP_VALID_47_32    0x0e89
+
+#define    RTL8367C_REG_IPMC_GROUP_VALID_63_48    0x0e8a
+
+#define    RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL4    0x0e8b
+#define    RTL8367C_VS_PORT9_SVIDX_OFFSET    8
+#define    RTL8367C_VS_PORT9_SVIDX_MASK    0x3F00
+#define    RTL8367C_VS_PORT8_SVIDX_OFFSET    0
+#define    RTL8367C_VS_PORT8_SVIDX_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL5    0x0e8c
+#define    RTL8367C_SVLAN_PORTBASED_SVIDX_CTRL5_OFFSET    0
+#define    RTL8367C_SVLAN_PORTBASED_SVIDX_CTRL5_MASK    0x3F
+
+#define    RTL8367C_REG_SVLAN_CFG_EXT    0x0e8d
+#define    RTL8367C_VS_PORT10_DMACVIDSEL_OFFSET    2
+#define    RTL8367C_VS_PORT10_DMACVIDSEL_MASK    0x4
+#define    RTL8367C_VS_PORT9_DMACVIDSEL_OFFSET    1
+#define    RTL8367C_VS_PORT9_DMACVIDSEL_MASK    0x2
+#define    RTL8367C_VS_PORT8_DMACVIDSEL_OFFSET    0
+#define    RTL8367C_VS_PORT8_DMACVIDSEL_MASK    0x1
+
+#define    RTL8367C_REG_SVLAN_MEMBERCFG63_CTRL4    0x0e8e
+#define    RTL8367C_SVLAN_MEMBERCFG63_CTRL4_VS_UNTAGSET_EXT_OFFSET    8
+#define    RTL8367C_SVLAN_MEMBERCFG63_CTRL4_VS_UNTAGSET_EXT_MASK    0x700
+#define    RTL8367C_SVLAN_MEMBERCFG63_CTRL4_VS_SMBR_EXT_OFFSET    0
+#define    RTL8367C_SVLAN_MEMBERCFG63_CTRL4_VS_SMBR_EXT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_DUMMY_0    0x0e90
+
+#define    RTL8367C_REG_SVLAN_DUMMY_1    0x0e91
+
+#define    RTL8367C_REG_SVLAN_DUMMY_2    0x0e92
+
+#define    RTL8367C_REG_SVLAN_DUMMY_3    0x0e93
+
+#define    RTL8367C_REG_SVLAN_DUMMY_4    0x0e94
+
+#define    RTL8367C_REG_SVLAN_DUMMY_5    0x0e95
+
+#define    RTL8367C_REG_SVLAN_DUMMY_6    0x0e96
+
+#define    RTL8367C_REG_SVLAN_DUMMY_7    0x0e97
+
+#define    RTL8367C_REG_SVLAN_DUMMY_8    0x0e98
+
+#define    RTL8367C_REG_SVLAN_DUMMY_9    0x0e99
+
+#define    RTL8367C_REG_SVLAN_DUMMY_10    0x0e9a
+
+#define    RTL8367C_REG_SVLAN_DUMMY_11    0x0e9b
+
+#define    RTL8367C_REG_SVLAN_DUMMY_12    0x0e9c
+
+#define    RTL8367C_REG_SVLAN_DUMMY_13    0x0e9d
+
+#define    RTL8367C_REG_SVLAN_DUMMY_14    0x0e9e
+
+#define    RTL8367C_REG_SVLAN_DUMMY_15    0x0e9f
+
+#define    RTL8367C_REG_SVLAN_DUMMY_16    0x0ea0
+
+#define    RTL8367C_REG_SVLAN_DUMMY_17    0x0ea1
+
+#define    RTL8367C_REG_SVLAN_DUMMY_18    0x0ea2
+
+#define    RTL8367C_REG_SVLAN_DUMMY_19    0x0ea3
+
+#define    RTL8367C_REG_SVLAN_DUMMY_20    0x0ea4
+
+#define    RTL8367C_REG_SVLAN_DUMMY_21    0x0ea5
+
+#define    RTL8367C_REG_SVLAN_DUMMY_22    0x0ea6
+
+#define    RTL8367C_REG_SVLAN_DUMMY_23    0x0ea7
+
+#define    RTL8367C_REG_SVLAN_DUMMY_24    0x0ea8
+
+#define    RTL8367C_REG_SVLAN_DUMMY_25    0x0ea9
+
+#define    RTL8367C_REG_SVLAN_DUMMY_26    0x0eaa
+
+#define    RTL8367C_REG_SVLAN_DUMMY_27    0x0eab
+
+#define    RTL8367C_REG_SVLAN_DUMMY_28    0x0eac
+
+#define    RTL8367C_REG_SVLAN_DUMMY_29    0x0ead
+
+#define    RTL8367C_REG_SVLAN_DUMMY_30    0x0eae
+
+#define    RTL8367C_REG_SVLAN_DUMMY_31    0x0eaf
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_00    0x0eb0
+#define    RTL8367C_IPMC_GROUP_VID_00_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_00_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_01    0x0eb1
+#define    RTL8367C_IPMC_GROUP_VID_01_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_01_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_02    0x0eb2
+#define    RTL8367C_IPMC_GROUP_VID_02_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_02_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_03    0x0eb3
+#define    RTL8367C_IPMC_GROUP_VID_03_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_03_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_04    0x0eb4
+#define    RTL8367C_IPMC_GROUP_VID_04_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_04_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_05    0x0eb5
+#define    RTL8367C_IPMC_GROUP_VID_05_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_05_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_06    0x0eb6
+#define    RTL8367C_IPMC_GROUP_VID_06_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_06_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_07    0x0eb7
+#define    RTL8367C_IPMC_GROUP_VID_07_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_07_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_08    0x0eb8
+#define    RTL8367C_IPMC_GROUP_VID_08_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_08_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_09    0x0eb9
+#define    RTL8367C_IPMC_GROUP_VID_09_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_09_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_10    0x0eba
+#define    RTL8367C_IPMC_GROUP_VID_10_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_10_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_11    0x0ebb
+#define    RTL8367C_IPMC_GROUP_VID_11_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_11_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_12    0x0ebc
+#define    RTL8367C_IPMC_GROUP_VID_12_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_12_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_13    0x0ebd
+#define    RTL8367C_IPMC_GROUP_VID_13_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_13_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_14    0x0ebe
+#define    RTL8367C_IPMC_GROUP_VID_14_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_14_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_15    0x0ebf
+#define    RTL8367C_IPMC_GROUP_VID_15_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_15_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_16    0x0ec0
+#define    RTL8367C_IPMC_GROUP_VID_16_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_16_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_17    0x0ec1
+#define    RTL8367C_IPMC_GROUP_VID_17_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_17_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_18    0x0ec2
+#define    RTL8367C_IPMC_GROUP_VID_18_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_18_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_19    0x0ec3
+#define    RTL8367C_IPMC_GROUP_VID_19_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_19_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_20    0x0ec4
+#define    RTL8367C_IPMC_GROUP_VID_20_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_20_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_21    0x0ec5
+#define    RTL8367C_IPMC_GROUP_VID_21_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_21_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_22    0x0ec6
+#define    RTL8367C_IPMC_GROUP_VID_22_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_22_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_23    0x0ec7
+#define    RTL8367C_IPMC_GROUP_VID_23_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_23_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_24    0x0ec8
+#define    RTL8367C_IPMC_GROUP_VID_24_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_24_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_25    0x0ec9
+#define    RTL8367C_IPMC_GROUP_VID_25_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_25_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_26    0x0eca
+#define    RTL8367C_IPMC_GROUP_VID_26_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_26_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_27    0x0ecb
+#define    RTL8367C_IPMC_GROUP_VID_27_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_27_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_28    0x0ecc
+#define    RTL8367C_IPMC_GROUP_VID_28_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_28_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_29    0x0ecd
+#define    RTL8367C_IPMC_GROUP_VID_29_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_29_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_30    0x0ece
+#define    RTL8367C_IPMC_GROUP_VID_30_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_30_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_31    0x0ecf
+#define    RTL8367C_IPMC_GROUP_VID_31_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_31_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_32    0x0ed0
+#define    RTL8367C_IPMC_GROUP_VID_32_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_32_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_33    0x0ed1
+#define    RTL8367C_IPMC_GROUP_VID_33_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_33_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_34    0x0ed2
+#define    RTL8367C_IPMC_GROUP_VID_34_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_34_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_35    0x0ed3
+#define    RTL8367C_IPMC_GROUP_VID_35_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_35_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_36    0x0ed4
+#define    RTL8367C_IPMC_GROUP_VID_36_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_36_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_37    0x0ed5
+#define    RTL8367C_IPMC_GROUP_VID_37_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_37_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_38    0x0ed6
+#define    RTL8367C_IPMC_GROUP_VID_38_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_38_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_39    0x0ed7
+#define    RTL8367C_IPMC_GROUP_VID_39_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_39_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_40    0x0ed8
+#define    RTL8367C_IPMC_GROUP_VID_40_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_40_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_41    0x0ed9
+#define    RTL8367C_IPMC_GROUP_VID_41_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_41_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_42    0x0eda
+#define    RTL8367C_IPMC_GROUP_VID_42_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_42_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_43    0x0edb
+#define    RTL8367C_IPMC_GROUP_VID_43_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_43_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_44    0x0edc
+#define    RTL8367C_IPMC_GROUP_VID_44_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_44_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_45    0x0edd
+#define    RTL8367C_IPMC_GROUP_VID_45_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_45_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_46    0x0ede
+#define    RTL8367C_IPMC_GROUP_VID_46_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_46_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_47    0x0edf
+#define    RTL8367C_IPMC_GROUP_VID_47_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_47_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_48    0x0ef0
+#define    RTL8367C_IPMC_GROUP_VID_48_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_48_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_49    0x0ef1
+#define    RTL8367C_IPMC_GROUP_VID_49_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_49_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_50    0x0ef2
+#define    RTL8367C_IPMC_GROUP_VID_50_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_50_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_51    0x0ef3
+#define    RTL8367C_IPMC_GROUP_VID_51_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_51_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_52    0x0ef4
+#define    RTL8367C_IPMC_GROUP_VID_52_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_52_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_53    0x0ef5
+#define    RTL8367C_IPMC_GROUP_VID_53_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_53_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_54    0x0ef6
+#define    RTL8367C_IPMC_GROUP_VID_54_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_54_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_55    0x0ef7
+#define    RTL8367C_IPMC_GROUP_VID_55_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_55_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_56    0x0ef8
+#define    RTL8367C_IPMC_GROUP_VID_56_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_56_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_57    0x0ef9
+#define    RTL8367C_IPMC_GROUP_VID_57_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_57_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_58    0x0efa
+#define    RTL8367C_IPMC_GROUP_VID_58_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_58_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_59    0x0efb
+#define    RTL8367C_IPMC_GROUP_VID_59_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_59_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_60    0x0efc
+#define    RTL8367C_IPMC_GROUP_VID_60_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_60_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_61    0x0efd
+#define    RTL8367C_IPMC_GROUP_VID_61_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_61_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_62    0x0efe
+#define    RTL8367C_IPMC_GROUP_VID_62_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_62_MASK    0xFFF
+
+#define    RTL8367C_REG_IPMC_GROUP_VID_63    0x0eff
+#define    RTL8367C_IPMC_GROUP_VID_63_OFFSET    0
+#define    RTL8367C_IPMC_GROUP_VID_63_MASK    0xFFF
+
+/* (16'h0f00)hsactrl_reg */
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY0_CTRL0    0x0f00
+#define    RTL8367C_SVLAN_SP2C_ENTRY0_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY0_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY0_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY0_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY0_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY0_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY0_CTRL1    0x0f01
+#define    RTL8367C_SVLAN_SP2C_ENTRY0_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY0_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY0_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY0_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY1_CTRL0    0x0f02
+#define    RTL8367C_SVLAN_SP2C_ENTRY1_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY1_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY1_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY1_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY1_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY1_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY1_CTRL1    0x0f03
+#define    RTL8367C_SVLAN_SP2C_ENTRY1_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY1_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY1_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY1_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY2_CTRL0    0x0f04
+#define    RTL8367C_SVLAN_SP2C_ENTRY2_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY2_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY2_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY2_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY2_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY2_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY2_CTRL1    0x0f05
+#define    RTL8367C_SVLAN_SP2C_ENTRY2_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY2_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY2_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY2_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY3_CTRL0    0x0f06
+#define    RTL8367C_SVLAN_SP2C_ENTRY3_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY3_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY3_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY3_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY3_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY3_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY3_CTRL1    0x0f07
+#define    RTL8367C_SVLAN_SP2C_ENTRY3_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY3_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY3_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY3_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY4_CTRL0    0x0f08
+#define    RTL8367C_SVLAN_SP2C_ENTRY4_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY4_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY4_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY4_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY4_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY4_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY4_CTRL1    0x0f09
+#define    RTL8367C_SVLAN_SP2C_ENTRY4_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY4_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY4_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY4_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY5_CTRL0    0x0f0a
+#define    RTL8367C_SVLAN_SP2C_ENTRY5_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY5_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY5_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY5_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY5_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY5_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY5_CTRL1    0x0f0b
+#define    RTL8367C_SVLAN_SP2C_ENTRY5_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY5_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY5_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY5_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY6_CTRL0    0x0f0c
+#define    RTL8367C_SVLAN_SP2C_ENTRY6_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY6_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY6_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY6_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY6_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY6_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY6_CTRL1    0x0f0d
+#define    RTL8367C_SVLAN_SP2C_ENTRY6_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY6_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY6_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY6_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY7_CTRL0    0x0f0e
+#define    RTL8367C_SVLAN_SP2C_ENTRY7_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY7_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY7_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY7_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY7_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY7_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY7_CTRL1    0x0f0f
+#define    RTL8367C_SVLAN_SP2C_ENTRY7_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY7_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY7_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY7_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY8_CTRL0    0x0f10
+#define    RTL8367C_SVLAN_SP2C_ENTRY8_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY8_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY8_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY8_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY8_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY8_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY8_CTRL1    0x0f11
+#define    RTL8367C_SVLAN_SP2C_ENTRY8_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY8_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY8_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY8_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY9_CTRL0    0x0f12
+#define    RTL8367C_SVLAN_SP2C_ENTRY9_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY9_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY9_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY9_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY9_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY9_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY9_CTRL1    0x0f13
+#define    RTL8367C_SVLAN_SP2C_ENTRY9_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY9_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY9_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY9_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY10_CTRL0    0x0f14
+#define    RTL8367C_SVLAN_SP2C_ENTRY10_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY10_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY10_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY10_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY10_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY10_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY10_CTRL1    0x0f15
+#define    RTL8367C_SVLAN_SP2C_ENTRY10_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY10_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY10_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY10_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY11_CTRL0    0x0f16
+#define    RTL8367C_SVLAN_SP2C_ENTRY11_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY11_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY11_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY11_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY11_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY11_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY11_CTRL1    0x0f17
+#define    RTL8367C_SVLAN_SP2C_ENTRY11_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY11_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY11_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY11_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY12_CTRL0    0x0f18
+#define    RTL8367C_SVLAN_SP2C_ENTRY12_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY12_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY12_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY12_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY12_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY12_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY12_CTRL1    0x0f19
+#define    RTL8367C_SVLAN_SP2C_ENTRY12_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY12_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY12_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY12_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY13_CTRL0    0x0f1a
+#define    RTL8367C_SVLAN_SP2C_ENTRY13_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY13_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY13_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY13_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY13_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY13_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY13_CTRL1    0x0f1b
+#define    RTL8367C_SVLAN_SP2C_ENTRY13_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY13_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY13_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY13_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY14_CTRL0    0x0f1c
+#define    RTL8367C_SVLAN_SP2C_ENTRY14_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY14_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY14_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY14_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY14_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY14_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY14_CTRL1    0x0f1d
+#define    RTL8367C_SVLAN_SP2C_ENTRY14_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY14_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY14_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY14_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY15_CTRL0    0x0f1e
+#define    RTL8367C_SVLAN_SP2C_ENTRY15_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY15_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY15_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY15_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY15_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY15_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY15_CTRL1    0x0f1f
+#define    RTL8367C_SVLAN_SP2C_ENTRY15_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY15_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY15_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY15_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY16_CTRL0    0x0f20
+#define    RTL8367C_SVLAN_SP2C_ENTRY16_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY16_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY16_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY16_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY16_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY16_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY16_CTRL1    0x0f21
+#define    RTL8367C_SVLAN_SP2C_ENTRY16_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY16_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY16_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY16_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY17_CTRL0    0x0f22
+#define    RTL8367C_SVLAN_SP2C_ENTRY17_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY17_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY17_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY17_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY17_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY17_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY17_CTRL1    0x0f23
+#define    RTL8367C_SVLAN_SP2C_ENTRY17_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY17_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY17_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY17_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY18_CTRL0    0x0f24
+#define    RTL8367C_SVLAN_SP2C_ENTRY18_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY18_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY18_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY18_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY18_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY18_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY18_CTRL1    0x0f25
+#define    RTL8367C_SVLAN_SP2C_ENTRY18_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY18_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY18_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY18_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY19_CTRL0    0x0f26
+#define    RTL8367C_SVLAN_SP2C_ENTRY19_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY19_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY19_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY19_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY19_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY19_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY19_CTRL1    0x0f27
+#define    RTL8367C_SVLAN_SP2C_ENTRY19_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY19_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY19_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY19_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY20_CTRL0    0x0f28
+#define    RTL8367C_SVLAN_SP2C_ENTRY20_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY20_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY20_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY20_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY20_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY20_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY20_CTRL1    0x0f29
+#define    RTL8367C_SVLAN_SP2C_ENTRY20_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY20_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY20_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY20_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY21_CTRL0    0x0f2a
+#define    RTL8367C_SVLAN_SP2C_ENTRY21_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY21_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY21_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY21_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY21_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY21_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY21_CTRL1    0x0f2b
+#define    RTL8367C_SVLAN_SP2C_ENTRY21_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY21_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY21_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY21_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY22_CTRL0    0x0f2c
+#define    RTL8367C_SVLAN_SP2C_ENTRY22_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY22_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY22_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY22_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY22_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY22_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY22_CTRL1    0x0f2d
+#define    RTL8367C_SVLAN_SP2C_ENTRY22_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY22_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY22_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY22_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY23_CTRL0    0x0f2e
+#define    RTL8367C_SVLAN_SP2C_ENTRY23_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY23_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY23_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY23_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY23_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY23_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY23_CTRL1    0x0f2f
+#define    RTL8367C_SVLAN_SP2C_ENTRY23_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY23_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY23_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY23_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY24_CTRL0    0x0f30
+#define    RTL8367C_SVLAN_SP2C_ENTRY24_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY24_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY24_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY24_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY24_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY24_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY24_CTRL1    0x0f31
+#define    RTL8367C_SVLAN_SP2C_ENTRY24_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY24_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY24_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY24_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY25_CTRL0    0x0f32
+#define    RTL8367C_SVLAN_SP2C_ENTRY25_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY25_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY25_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY25_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY25_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY25_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY25_CTRL1    0x0f33
+#define    RTL8367C_SVLAN_SP2C_ENTRY25_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY25_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY25_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY25_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY26_CTRL0    0x0f34
+#define    RTL8367C_SVLAN_SP2C_ENTRY26_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY26_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY26_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY26_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY26_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY26_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY26_CTRL1    0x0f35
+#define    RTL8367C_SVLAN_SP2C_ENTRY26_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY26_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY26_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY26_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY27_CTRL0    0x0f36
+#define    RTL8367C_SVLAN_SP2C_ENTRY27_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY27_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY27_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY27_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY27_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY27_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY27_CTRL1    0x0f37
+#define    RTL8367C_SVLAN_SP2C_ENTRY27_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY27_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY27_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY27_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY28_CTRL0    0x0f38
+#define    RTL8367C_SVLAN_SP2C_ENTRY28_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY28_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY28_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY28_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY28_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY28_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY28_CTRL1    0x0f39
+#define    RTL8367C_SVLAN_SP2C_ENTRY28_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY28_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY28_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY28_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY29_CTRL0    0x0f3a
+#define    RTL8367C_SVLAN_SP2C_ENTRY29_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY29_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY29_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY29_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY29_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY29_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY29_CTRL1    0x0f3b
+#define    RTL8367C_SVLAN_SP2C_ENTRY29_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY29_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY29_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY29_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY30_CTRL0    0x0f3c
+#define    RTL8367C_SVLAN_SP2C_ENTRY30_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY30_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY30_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY30_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY30_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY30_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY30_CTRL1    0x0f3d
+#define    RTL8367C_SVLAN_SP2C_ENTRY30_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY30_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY30_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY30_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY31_CTRL0    0x0f3e
+#define    RTL8367C_SVLAN_SP2C_ENTRY31_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY31_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY31_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY31_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY31_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY31_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY31_CTRL1    0x0f3f
+#define    RTL8367C_SVLAN_SP2C_ENTRY31_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY31_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY31_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY31_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY32_CTRL0    0x0f40
+#define    RTL8367C_SVLAN_SP2C_ENTRY32_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY32_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY32_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY32_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY32_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY32_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY32_CTRL1    0x0f41
+#define    RTL8367C_SVLAN_SP2C_ENTRY32_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY32_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY32_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY32_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY33_CTRL0    0x0f42
+#define    RTL8367C_SVLAN_SP2C_ENTRY33_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY33_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY33_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY33_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY33_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY33_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY33_CTRL1    0x0f43
+#define    RTL8367C_SVLAN_SP2C_ENTRY33_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY33_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY33_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY33_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY34_CTRL0    0x0f44
+#define    RTL8367C_SVLAN_SP2C_ENTRY34_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY34_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY34_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY34_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY34_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY34_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY34_CTRL1    0x0f45
+#define    RTL8367C_SVLAN_SP2C_ENTRY34_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY34_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY34_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY34_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY35_CTRL0    0x0f46
+#define    RTL8367C_SVLAN_SP2C_ENTRY35_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY35_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY35_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY35_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY35_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY35_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY35_CTRL1    0x0f47
+#define    RTL8367C_SVLAN_SP2C_ENTRY35_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY35_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY35_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY35_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY36_CTRL0    0x0f48
+#define    RTL8367C_SVLAN_SP2C_ENTRY36_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY36_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY36_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY36_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY36_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY36_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY36_CTRL1    0x0f49
+#define    RTL8367C_SVLAN_SP2C_ENTRY36_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY36_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY36_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY36_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY37_CTRL0    0x0f4a
+#define    RTL8367C_SVLAN_SP2C_ENTRY37_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY37_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY37_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY37_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY37_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY37_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY37_CTRL1    0x0f4b
+#define    RTL8367C_SVLAN_SP2C_ENTRY37_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY37_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY37_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY37_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY38_CTRL0    0x0f4c
+#define    RTL8367C_SVLAN_SP2C_ENTRY38_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY38_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY38_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY38_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY38_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY38_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY38_CTRL1    0x0f4d
+#define    RTL8367C_SVLAN_SP2C_ENTRY38_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY38_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY38_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY38_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY39_CTRL0    0x0f4e
+#define    RTL8367C_SVLAN_SP2C_ENTRY39_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY39_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY39_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY39_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY39_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY39_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY39_CTRL1    0x0f4f
+#define    RTL8367C_SVLAN_SP2C_ENTRY39_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY39_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY39_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY39_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY40_CTRL0    0x0f50
+#define    RTL8367C_SVLAN_SP2C_ENTRY40_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY40_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY40_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY40_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY40_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY40_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY40_CTRL1    0x0f51
+#define    RTL8367C_SVLAN_SP2C_ENTRY40_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY40_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY40_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY40_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY41_CTRL0    0x0f52
+#define    RTL8367C_SVLAN_SP2C_ENTRY41_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY41_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY41_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY41_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY41_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY41_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY41_CTRL1    0x0f53
+#define    RTL8367C_SVLAN_SP2C_ENTRY41_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY41_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY41_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY41_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY42_CTRL0    0x0f54
+#define    RTL8367C_SVLAN_SP2C_ENTRY42_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY42_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY42_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY42_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY42_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY42_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY42_CTRL1    0x0f55
+#define    RTL8367C_SVLAN_SP2C_ENTRY42_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY42_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY42_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY42_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY43_CTRL0    0x0f56
+#define    RTL8367C_SVLAN_SP2C_ENTRY43_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY43_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY43_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY43_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY43_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY43_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY43_CTRL1    0x0f57
+#define    RTL8367C_SVLAN_SP2C_ENTRY43_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY43_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY43_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY43_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY44_CTRL0    0x0f58
+#define    RTL8367C_SVLAN_SP2C_ENTRY44_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY44_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY44_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY44_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY44_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY44_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY44_CTRL1    0x0f59
+#define    RTL8367C_SVLAN_SP2C_ENTRY44_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY44_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY44_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY44_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY45_CTRL0    0x0f5a
+#define    RTL8367C_SVLAN_SP2C_ENTRY45_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY45_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY45_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY45_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY45_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY45_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY45_CTRL1    0x0f5b
+#define    RTL8367C_SVLAN_SP2C_ENTRY45_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY45_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY45_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY45_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY46_CTRL0    0x0f5c
+#define    RTL8367C_SVLAN_SP2C_ENTRY46_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY46_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY46_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY46_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY46_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY46_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY46_CTRL1    0x0f5d
+#define    RTL8367C_SVLAN_SP2C_ENTRY46_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY46_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY46_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY46_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY47_CTRL0    0x0f5e
+#define    RTL8367C_SVLAN_SP2C_ENTRY47_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY47_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY47_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY47_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY47_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY47_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY47_CTRL1    0x0f5f
+#define    RTL8367C_SVLAN_SP2C_ENTRY47_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY47_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY47_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY47_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY48_CTRL0    0x0f60
+#define    RTL8367C_SVLAN_SP2C_ENTRY48_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY48_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY48_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY48_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY48_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY48_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY48_CTRL1    0x0f61
+#define    RTL8367C_SVLAN_SP2C_ENTRY48_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY48_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY48_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY48_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY49_CTRL0    0x0f62
+#define    RTL8367C_SVLAN_SP2C_ENTRY49_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY49_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY49_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY49_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY49_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY49_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY49_CTRL1    0x0f63
+#define    RTL8367C_SVLAN_SP2C_ENTRY49_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY49_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY49_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY49_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY50_CTRL0    0x0f64
+#define    RTL8367C_SVLAN_SP2C_ENTRY50_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY50_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY50_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY50_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY50_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY50_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY50_CTRL1    0x0f65
+#define    RTL8367C_SVLAN_SP2C_ENTRY50_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY50_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY50_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY50_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY51_CTRL0    0x0f66
+#define    RTL8367C_SVLAN_SP2C_ENTRY51_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY51_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY51_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY51_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY51_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY51_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY51_CTRL1    0x0f67
+#define    RTL8367C_SVLAN_SP2C_ENTRY51_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY51_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY51_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY51_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY52_CTRL0    0x0f68
+#define    RTL8367C_SVLAN_SP2C_ENTRY52_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY52_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY52_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY52_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY52_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY52_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY52_CTRL1    0x0f69
+#define    RTL8367C_SVLAN_SP2C_ENTRY52_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY52_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY52_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY52_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY53_CTRL0    0x0f6a
+#define    RTL8367C_SVLAN_SP2C_ENTRY53_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY53_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY53_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY53_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY53_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY53_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY53_CTRL1    0x0f6b
+#define    RTL8367C_SVLAN_SP2C_ENTRY53_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY53_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY53_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY53_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY54_CTRL0    0x0f6c
+#define    RTL8367C_SVLAN_SP2C_ENTRY54_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY54_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY54_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY54_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY54_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY54_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY54_CTRL1    0x0f6d
+#define    RTL8367C_SVLAN_SP2C_ENTRY54_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY54_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY54_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY54_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY55_CTRL0    0x0f6e
+#define    RTL8367C_SVLAN_SP2C_ENTRY55_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY55_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY55_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY55_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY55_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY55_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY55_CTRL1    0x0f6f
+#define    RTL8367C_SVLAN_SP2C_ENTRY55_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY55_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY55_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY55_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY56_CTRL0    0x0f70
+#define    RTL8367C_SVLAN_SP2C_ENTRY56_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY56_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY56_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY56_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY56_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY56_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY56_CTRL1    0x0f71
+#define    RTL8367C_SVLAN_SP2C_ENTRY56_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY56_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY56_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY56_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY57_CTRL0    0x0f72
+#define    RTL8367C_SVLAN_SP2C_ENTRY57_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY57_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY57_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY57_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY57_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY57_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY57_CTRL1    0x0f73
+#define    RTL8367C_SVLAN_SP2C_ENTRY57_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY57_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY57_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY57_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY58_CTRL0    0x0f74
+#define    RTL8367C_SVLAN_SP2C_ENTRY58_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY58_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY58_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY58_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY58_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY58_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY58_CTRL1    0x0f75
+#define    RTL8367C_SVLAN_SP2C_ENTRY58_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY58_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY58_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY58_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY59_CTRL0    0x0f76
+#define    RTL8367C_SVLAN_SP2C_ENTRY59_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY59_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY59_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY59_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY59_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY59_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY59_CTRL1    0x0f77
+#define    RTL8367C_SVLAN_SP2C_ENTRY59_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY59_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY59_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY59_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY60_CTRL0    0x0f78
+#define    RTL8367C_SVLAN_SP2C_ENTRY60_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY60_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY60_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY60_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY60_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY60_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY60_CTRL1    0x0f79
+#define    RTL8367C_SVLAN_SP2C_ENTRY60_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY60_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY60_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY60_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY61_CTRL0    0x0f7a
+#define    RTL8367C_SVLAN_SP2C_ENTRY61_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY61_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY61_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY61_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY61_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY61_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY61_CTRL1    0x0f7b
+#define    RTL8367C_SVLAN_SP2C_ENTRY61_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY61_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY61_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY61_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY62_CTRL0    0x0f7c
+#define    RTL8367C_SVLAN_SP2C_ENTRY62_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY62_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY62_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY62_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY62_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY62_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY62_CTRL1    0x0f7d
+#define    RTL8367C_SVLAN_SP2C_ENTRY62_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY62_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY62_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY62_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY63_CTRL0    0x0f7e
+#define    RTL8367C_SVLAN_SP2C_ENTRY63_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY63_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY63_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY63_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY63_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY63_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY63_CTRL1    0x0f7f
+#define    RTL8367C_SVLAN_SP2C_ENTRY63_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY63_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY63_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY63_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY64_CTRL0    0x0f80
+#define    RTL8367C_SVLAN_SP2C_ENTRY64_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY64_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY64_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY64_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY64_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY64_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY64_CTRL1    0x0f81
+#define    RTL8367C_SVLAN_SP2C_ENTRY64_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY64_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY64_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY64_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY65_CTRL0    0x0f82
+#define    RTL8367C_SVLAN_SP2C_ENTRY65_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY65_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY65_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY65_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY65_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY65_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY65_CTRL1    0x0f83
+#define    RTL8367C_SVLAN_SP2C_ENTRY65_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY65_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY65_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY65_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY66_CTRL0    0x0f84
+#define    RTL8367C_SVLAN_SP2C_ENTRY66_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY66_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY66_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY66_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY66_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY66_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY66_CTRL1    0x0f85
+#define    RTL8367C_SVLAN_SP2C_ENTRY66_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY66_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY66_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY66_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY67_CTRL0    0x0f86
+#define    RTL8367C_SVLAN_SP2C_ENTRY67_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY67_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY67_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY67_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY67_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY67_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY67_CTRL1    0x0f87
+#define    RTL8367C_SVLAN_SP2C_ENTRY67_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY67_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY67_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY67_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY68_CTRL0    0x0f88
+#define    RTL8367C_SVLAN_SP2C_ENTRY68_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY68_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY68_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY68_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY68_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY68_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY68_CTRL1    0x0f89
+#define    RTL8367C_SVLAN_SP2C_ENTRY68_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY68_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY68_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY68_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY69_CTRL0    0x0f8a
+#define    RTL8367C_SVLAN_SP2C_ENTRY69_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY69_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY69_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY69_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY69_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY69_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY69_CTRL1    0x0f8b
+#define    RTL8367C_SVLAN_SP2C_ENTRY69_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY69_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY69_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY69_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY70_CTRL0    0x0f8c
+#define    RTL8367C_SVLAN_SP2C_ENTRY70_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY70_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY70_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY70_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY70_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY70_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY70_CTRL1    0x0f8d
+#define    RTL8367C_SVLAN_SP2C_ENTRY70_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY70_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY70_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY70_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY71_CTRL0    0x0f8e
+#define    RTL8367C_SVLAN_SP2C_ENTRY71_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY71_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY71_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY71_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY71_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY71_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY71_CTRL1    0x0f8f
+#define    RTL8367C_SVLAN_SP2C_ENTRY71_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY71_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY71_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY71_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY72_CTRL0    0x0f90
+#define    RTL8367C_SVLAN_SP2C_ENTRY72_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY72_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY72_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY72_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY72_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY72_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY72_CTRL1    0x0f91
+#define    RTL8367C_SVLAN_SP2C_ENTRY72_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY72_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY72_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY72_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY73_CTRL0    0x0f92
+#define    RTL8367C_SVLAN_SP2C_ENTRY73_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY73_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY73_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY73_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY73_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY73_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY73_CTRL1    0x0f93
+#define    RTL8367C_SVLAN_SP2C_ENTRY73_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY73_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY73_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY73_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY74_CTRL0    0x0f94
+#define    RTL8367C_SVLAN_SP2C_ENTRY74_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY74_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY74_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY74_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY74_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY74_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY74_CTRL1    0x0f95
+#define    RTL8367C_SVLAN_SP2C_ENTRY74_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY74_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY74_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY74_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY75_CTRL0    0x0f96
+#define    RTL8367C_SVLAN_SP2C_ENTRY75_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY75_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY75_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY75_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY75_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY75_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY75_CTRL1    0x0f97
+#define    RTL8367C_SVLAN_SP2C_ENTRY75_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY75_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY75_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY75_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY76_CTRL0    0x0f98
+#define    RTL8367C_SVLAN_SP2C_ENTRY76_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY76_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY76_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY76_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY76_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY76_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY76_CTRL1    0x0f99
+#define    RTL8367C_SVLAN_SP2C_ENTRY76_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY76_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY76_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY76_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY77_CTRL0    0x0f9a
+#define    RTL8367C_SVLAN_SP2C_ENTRY77_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY77_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY77_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY77_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY77_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY77_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY77_CTRL1    0x0f9b
+#define    RTL8367C_SVLAN_SP2C_ENTRY77_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY77_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY77_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY77_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY78_CTRL0    0x0f9c
+#define    RTL8367C_SVLAN_SP2C_ENTRY78_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY78_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY78_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY78_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY78_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY78_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY78_CTRL1    0x0f9d
+#define    RTL8367C_SVLAN_SP2C_ENTRY78_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY78_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY78_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY78_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY79_CTRL0    0x0f9e
+#define    RTL8367C_SVLAN_SP2C_ENTRY79_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY79_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY79_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY79_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY79_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY79_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY79_CTRL1    0x0f9f
+#define    RTL8367C_SVLAN_SP2C_ENTRY79_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY79_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY79_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY79_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY80_CTRL0    0x0fa0
+#define    RTL8367C_SVLAN_SP2C_ENTRY80_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY80_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY80_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY80_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY80_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY80_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY80_CTRL1    0x0fa1
+#define    RTL8367C_SVLAN_SP2C_ENTRY80_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY80_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY80_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY80_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY81_CTRL0    0x0fa2
+#define    RTL8367C_SVLAN_SP2C_ENTRY81_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY81_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY81_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY81_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY81_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY81_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY81_CTRL1    0x0fa3
+#define    RTL8367C_SVLAN_SP2C_ENTRY81_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY81_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY81_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY81_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY82_CTRL0    0x0fa4
+#define    RTL8367C_SVLAN_SP2C_ENTRY82_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY82_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY82_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY82_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY82_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY82_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY82_CTRL1    0x0fa5
+#define    RTL8367C_SVLAN_SP2C_ENTRY82_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY82_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY82_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY82_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY83_CTRL0    0x0fa6
+#define    RTL8367C_SVLAN_SP2C_ENTRY83_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY83_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY83_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY83_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY83_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY83_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY83_CTRL1    0x0fa7
+#define    RTL8367C_SVLAN_SP2C_ENTRY83_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY83_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY83_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY83_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY84_CTRL0    0x0fa8
+#define    RTL8367C_SVLAN_SP2C_ENTRY84_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY84_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY84_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY84_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY84_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY84_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY84_CTRL1    0x0fa9
+#define    RTL8367C_SVLAN_SP2C_ENTRY84_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY84_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY84_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY84_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY85_CTRL0    0x0faa
+#define    RTL8367C_SVLAN_SP2C_ENTRY85_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY85_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY85_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY85_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY85_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY85_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY85_CTRL1    0x0fab
+#define    RTL8367C_SVLAN_SP2C_ENTRY85_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY85_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY85_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY85_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY86_CTRL0    0x0fac
+#define    RTL8367C_SVLAN_SP2C_ENTRY86_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY86_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY86_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY86_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY86_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY86_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY86_CTRL1    0x0fad
+#define    RTL8367C_SVLAN_SP2C_ENTRY86_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY86_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY86_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY86_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY87_CTRL0    0x0fae
+#define    RTL8367C_SVLAN_SP2C_ENTRY87_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY87_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY87_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY87_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY87_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY87_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY87_CTRL1    0x0faf
+#define    RTL8367C_SVLAN_SP2C_ENTRY87_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY87_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY87_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY87_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY88_CTRL0    0x0fb0
+#define    RTL8367C_SVLAN_SP2C_ENTRY88_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY88_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY88_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY88_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY88_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY88_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY88_CTRL1    0x0fb1
+#define    RTL8367C_SVLAN_SP2C_ENTRY88_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY88_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY88_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY88_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY89_CTRL0    0x0fb2
+#define    RTL8367C_SVLAN_SP2C_ENTRY89_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY89_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY89_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY89_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY89_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY89_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY89_CTRL1    0x0fb3
+#define    RTL8367C_SVLAN_SP2C_ENTRY89_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY89_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY89_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY89_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY90_CTRL0    0x0fb4
+#define    RTL8367C_SVLAN_SP2C_ENTRY90_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY90_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY90_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY90_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY90_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY90_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY90_CTRL1    0x0fb5
+#define    RTL8367C_SVLAN_SP2C_ENTRY90_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY90_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY90_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY90_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY91_CTRL0    0x0fb6
+#define    RTL8367C_SVLAN_SP2C_ENTRY91_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY91_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY91_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY91_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY91_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY91_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY91_CTRL1    0x0fb7
+#define    RTL8367C_SVLAN_SP2C_ENTRY91_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY91_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY91_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY91_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY92_CTRL0    0x0fb8
+#define    RTL8367C_SVLAN_SP2C_ENTRY92_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY92_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY92_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY92_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY92_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY92_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY92_CTRL1    0x0fb9
+#define    RTL8367C_SVLAN_SP2C_ENTRY92_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY92_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY92_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY92_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY93_CTRL0    0x0fba
+#define    RTL8367C_SVLAN_SP2C_ENTRY93_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY93_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY93_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY93_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY93_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY93_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY93_CTRL1    0x0fbb
+#define    RTL8367C_SVLAN_SP2C_ENTRY93_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY93_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY93_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY93_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY94_CTRL0    0x0fbc
+#define    RTL8367C_SVLAN_SP2C_ENTRY94_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY94_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY94_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY94_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY94_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY94_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY94_CTRL1    0x0fbd
+#define    RTL8367C_SVLAN_SP2C_ENTRY94_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY94_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY94_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY94_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY95_CTRL0    0x0fbe
+#define    RTL8367C_SVLAN_SP2C_ENTRY95_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY95_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY95_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY95_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY95_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY95_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY95_CTRL1    0x0fbf
+#define    RTL8367C_SVLAN_SP2C_ENTRY95_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY95_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY95_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY95_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY96_CTRL0    0x0fc0
+#define    RTL8367C_SVLAN_SP2C_ENTRY96_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY96_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY96_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY96_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY96_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY96_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY96_CTRL1    0x0fc1
+#define    RTL8367C_SVLAN_SP2C_ENTRY96_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY96_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY96_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY96_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY97_CTRL0    0x0fc2
+#define    RTL8367C_SVLAN_SP2C_ENTRY97_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY97_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY97_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY97_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY97_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY97_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY97_CTRL1    0x0fc3
+#define    RTL8367C_SVLAN_SP2C_ENTRY97_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY97_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY97_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY97_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY98_CTRL0    0x0fc4
+#define    RTL8367C_SVLAN_SP2C_ENTRY98_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY98_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY98_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY98_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY98_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY98_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY98_CTRL1    0x0fc5
+#define    RTL8367C_SVLAN_SP2C_ENTRY98_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY98_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY98_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY98_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY99_CTRL0    0x0fc6
+#define    RTL8367C_SVLAN_SP2C_ENTRY99_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY99_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY99_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY99_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY99_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY99_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY99_CTRL1    0x0fc7
+#define    RTL8367C_SVLAN_SP2C_ENTRY99_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY99_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY99_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY99_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY100_CTRL0    0x0fc8
+#define    RTL8367C_SVLAN_SP2C_ENTRY100_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY100_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY100_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY100_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY100_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY100_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY100_CTRL1    0x0fc9
+#define    RTL8367C_SVLAN_SP2C_ENTRY100_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY100_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY100_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY100_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY101_CTRL0    0x0fca
+#define    RTL8367C_SVLAN_SP2C_ENTRY101_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY101_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY101_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY101_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY101_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY101_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY101_CTRL1    0x0fcb
+#define    RTL8367C_SVLAN_SP2C_ENTRY101_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY101_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY101_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY101_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY102_CTRL0    0x0fcc
+#define    RTL8367C_SVLAN_SP2C_ENTRY102_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY102_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY102_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY102_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY102_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY102_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY102_CTRL1    0x0fcd
+#define    RTL8367C_SVLAN_SP2C_ENTRY102_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY102_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY102_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY102_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY103_CTRL0    0x0fce
+#define    RTL8367C_SVLAN_SP2C_ENTRY103_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY103_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY103_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY103_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY103_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY103_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY103_CTRL1    0x0fcf
+#define    RTL8367C_SVLAN_SP2C_ENTRY103_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY103_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY103_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY103_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY104_CTRL0    0x0fd0
+#define    RTL8367C_SVLAN_SP2C_ENTRY104_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY104_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY104_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY104_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY104_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY104_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY104_CTRL1    0x0fd1
+#define    RTL8367C_SVLAN_SP2C_ENTRY104_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY104_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY104_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY104_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY105_CTRL0    0x0fd2
+#define    RTL8367C_SVLAN_SP2C_ENTRY105_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY105_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY105_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY105_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY105_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY105_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY105_CTRL1    0x0fd3
+#define    RTL8367C_SVLAN_SP2C_ENTRY105_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY105_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY105_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY105_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY106_CTRL0    0x0fd4
+#define    RTL8367C_SVLAN_SP2C_ENTRY106_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY106_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY106_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY106_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY106_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY106_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY106_CTRL1    0x0fd5
+#define    RTL8367C_SVLAN_SP2C_ENTRY106_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY106_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY106_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY106_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY107_CTRL0    0x0fd6
+#define    RTL8367C_SVLAN_SP2C_ENTRY107_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY107_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY107_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY107_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY107_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY107_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY107_CTRL1    0x0fd7
+#define    RTL8367C_SVLAN_SP2C_ENTRY107_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY107_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY107_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY107_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY108_CTRL0    0x0fd8
+#define    RTL8367C_SVLAN_SP2C_ENTRY108_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY108_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY108_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY108_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY108_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY108_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY108_CTRL1    0x0fd9
+#define    RTL8367C_SVLAN_SP2C_ENTRY108_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY108_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY108_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY108_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY109_CTRL0    0x0fda
+#define    RTL8367C_SVLAN_SP2C_ENTRY109_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY109_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY109_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY109_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY109_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY109_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY109_CTRL1    0x0fdb
+#define    RTL8367C_SVLAN_SP2C_ENTRY109_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY109_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY109_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY109_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY110_CTRL0    0x0fdc
+#define    RTL8367C_SVLAN_SP2C_ENTRY110_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY110_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY110_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY110_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY110_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY110_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY110_CTRL1    0x0fdd
+#define    RTL8367C_SVLAN_SP2C_ENTRY110_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY110_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY110_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY110_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY111_CTRL0    0x0fde
+#define    RTL8367C_SVLAN_SP2C_ENTRY111_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY111_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY111_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY111_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY111_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY111_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY111_CTRL1    0x0fdf
+#define    RTL8367C_SVLAN_SP2C_ENTRY111_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY111_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY111_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY111_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY112_CTRL0    0x0fe0
+#define    RTL8367C_SVLAN_SP2C_ENTRY112_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY112_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY112_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY112_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY112_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY112_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY112_CTRL1    0x0fe1
+#define    RTL8367C_SVLAN_SP2C_ENTRY112_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY112_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY112_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY112_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY113_CTRL0    0x0fe2
+#define    RTL8367C_SVLAN_SP2C_ENTRY113_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY113_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY113_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY113_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY113_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY113_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY113_CTRL1    0x0fe3
+#define    RTL8367C_SVLAN_SP2C_ENTRY113_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY113_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY113_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY113_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY114_CTRL0    0x0fe4
+#define    RTL8367C_SVLAN_SP2C_ENTRY114_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY114_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY114_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY114_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY114_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY114_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY114_CTRL1    0x0fe5
+#define    RTL8367C_SVLAN_SP2C_ENTRY114_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY114_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY114_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY114_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY115_CTRL0    0x0fe6
+#define    RTL8367C_SVLAN_SP2C_ENTRY115_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY115_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY115_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY115_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY115_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY115_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY115_CTRL1    0x0fe7
+#define    RTL8367C_SVLAN_SP2C_ENTRY115_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY115_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY115_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY115_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY116_CTRL0    0x0fe8
+#define    RTL8367C_SVLAN_SP2C_ENTRY116_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY116_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY116_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY116_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY116_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY116_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY116_CTRL1    0x0fe9
+#define    RTL8367C_SVLAN_SP2C_ENTRY116_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY116_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY116_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY116_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY117_CTRL0    0x0fea
+#define    RTL8367C_SVLAN_SP2C_ENTRY117_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY117_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY117_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY117_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY117_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY117_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY117_CTRL1    0x0feb
+#define    RTL8367C_SVLAN_SP2C_ENTRY117_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY117_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY117_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY117_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY118_CTRL0    0x0fec
+#define    RTL8367C_SVLAN_SP2C_ENTRY118_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY118_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY118_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY118_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY118_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY118_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY118_CTRL1    0x0fed
+#define    RTL8367C_SVLAN_SP2C_ENTRY118_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY118_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY118_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY118_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY119_CTRL0    0x0fee
+#define    RTL8367C_SVLAN_SP2C_ENTRY119_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY119_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY119_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY119_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY119_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY119_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY119_CTRL1    0x0fef
+#define    RTL8367C_SVLAN_SP2C_ENTRY119_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY119_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY119_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY119_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY120_CTRL0    0x0ff0
+#define    RTL8367C_SVLAN_SP2C_ENTRY120_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY120_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY120_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY120_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY120_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY120_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY120_CTRL1    0x0ff1
+#define    RTL8367C_SVLAN_SP2C_ENTRY120_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY120_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY120_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY120_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY121_CTRL0    0x0ff2
+#define    RTL8367C_SVLAN_SP2C_ENTRY121_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY121_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY121_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY121_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY121_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY121_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY121_CTRL1    0x0ff3
+#define    RTL8367C_SVLAN_SP2C_ENTRY121_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY121_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY121_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY121_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY122_CTRL0    0x0ff4
+#define    RTL8367C_SVLAN_SP2C_ENTRY122_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY122_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY122_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY122_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY122_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY122_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY122_CTRL1    0x0ff5
+#define    RTL8367C_SVLAN_SP2C_ENTRY122_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY122_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY122_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY122_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY123_CTRL0    0x0ff6
+#define    RTL8367C_SVLAN_SP2C_ENTRY123_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY123_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY123_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY123_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY123_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY123_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY123_CTRL1    0x0ff7
+#define    RTL8367C_SVLAN_SP2C_ENTRY123_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY123_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY123_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY123_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY124_CTRL0    0x0ff8
+#define    RTL8367C_SVLAN_SP2C_ENTRY124_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY124_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY124_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY124_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY124_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY124_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY124_CTRL1    0x0ff9
+#define    RTL8367C_SVLAN_SP2C_ENTRY124_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY124_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY124_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY124_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY125_CTRL0    0x0ffa
+#define    RTL8367C_SVLAN_SP2C_ENTRY125_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY125_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY125_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY125_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY125_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY125_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY125_CTRL1    0x0ffb
+#define    RTL8367C_SVLAN_SP2C_ENTRY125_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY125_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY125_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY125_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY126_CTRL0    0x0ffc
+#define    RTL8367C_SVLAN_SP2C_ENTRY126_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY126_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY126_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY126_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY126_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY126_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY126_CTRL1    0x0ffd
+#define    RTL8367C_SVLAN_SP2C_ENTRY126_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY126_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY126_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY126_CTRL1_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY127_CTRL0    0x0ffe
+#define    RTL8367C_SVLAN_SP2C_ENTRY127_CTRL0_DST_PORT1_OFFSET    9
+#define    RTL8367C_SVLAN_SP2C_ENTRY127_CTRL0_DST_PORT1_MASK    0x200
+#define    RTL8367C_SVLAN_SP2C_ENTRY127_CTRL0_SVIDX_OFFSET    3
+#define    RTL8367C_SVLAN_SP2C_ENTRY127_CTRL0_SVIDX_MASK    0x1F8
+#define    RTL8367C_SVLAN_SP2C_ENTRY127_CTRL0_DST_PORT_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY127_CTRL0_DST_PORT_MASK    0x7
+
+#define    RTL8367C_REG_SVLAN_SP2C_ENTRY127_CTRL1    0x0fff
+#define    RTL8367C_SVLAN_SP2C_ENTRY127_CTRL1_VALID_OFFSET    12
+#define    RTL8367C_SVLAN_SP2C_ENTRY127_CTRL1_VALID_MASK    0x1000
+#define    RTL8367C_SVLAN_SP2C_ENTRY127_CTRL1_VID_OFFSET    0
+#define    RTL8367C_SVLAN_SP2C_ENTRY127_CTRL1_VID_MASK    0xFFF
+
+/* (16'h1000)mib_reg */
+
+#define    RTL8367C_REG_MIB_COUNTER0    0x1000
+
+#define    RTL8367C_REG_MIB_COUNTER1    0x1001
+
+#define    RTL8367C_REG_MIB_COUNTER2    0x1002
+
+#define    RTL8367C_REG_MIB_COUNTER3    0x1003
+
+#define    RTL8367C_REG_MIB_ADDRESS    0x1004
+#define    RTL8367C_MIB_ADDRESS_OFFSET    0
+#define    RTL8367C_MIB_ADDRESS_MASK    0x1FF
+
+#define    RTL8367C_REG_MIB_CTRL0    0x1005
+#define    RTL8367C_PORT10_RESET_OFFSET    15
+#define    RTL8367C_PORT10_RESET_MASK    0x8000
+#define    RTL8367C_PORT9_RESET_OFFSET    14
+#define    RTL8367C_PORT9_RESET_MASK    0x4000
+#define    RTL8367C_PORT8_RESET_OFFSET    13
+#define    RTL8367C_PORT8_RESET_MASK    0x2000
+#define    RTL8367C_RESET_VALUE_OFFSET    12
+#define    RTL8367C_RESET_VALUE_MASK    0x1000
+#define    RTL8367C_GLOBAL_RESET_OFFSET    11
+#define    RTL8367C_GLOBAL_RESET_MASK    0x800
+#define    RTL8367C_QM_RESET_OFFSET    10
+#define    RTL8367C_QM_RESET_MASK    0x400
+#define    RTL8367C_PORT7_RESET_OFFSET    9
+#define    RTL8367C_PORT7_RESET_MASK    0x200
+#define    RTL8367C_PORT6_RESET_OFFSET    8
+#define    RTL8367C_PORT6_RESET_MASK    0x100
+#define    RTL8367C_PORT5_RESET_OFFSET    7
+#define    RTL8367C_PORT5_RESET_MASK    0x80
+#define    RTL8367C_PORT4_RESET_OFFSET    6
+#define    RTL8367C_PORT4_RESET_MASK    0x40
+#define    RTL8367C_PORT3_RESET_OFFSET    5
+#define    RTL8367C_PORT3_RESET_MASK    0x20
+#define    RTL8367C_PORT2_RESET_OFFSET    4
+#define    RTL8367C_PORT2_RESET_MASK    0x10
+#define    RTL8367C_PORT1_RESET_OFFSET    3
+#define    RTL8367C_PORT1_RESET_MASK    0x8
+#define    RTL8367C_PORT0_RESET_OFFSET    2
+#define    RTL8367C_PORT0_RESET_MASK    0x4
+#define    RTL8367C_RESET_FLAG_OFFSET    1
+#define    RTL8367C_RESET_FLAG_MASK    0x2
+#define    RTL8367C_MIB_CTRL0_BUSY_FLAG_OFFSET    0
+#define    RTL8367C_MIB_CTRL0_BUSY_FLAG_MASK    0x1
+
+#define    RTL8367C_REG_MIB_CTRL1    0x1007
+#define    RTL8367C_COUNTER15_RESET_OFFSET    15
+#define    RTL8367C_COUNTER15_RESET_MASK    0x8000
+#define    RTL8367C_COUNTER14_RESET_OFFSET    14
+#define    RTL8367C_COUNTER14_RESET_MASK    0x4000
+#define    RTL8367C_COUNTER13_RESET_OFFSET    13
+#define    RTL8367C_COUNTER13_RESET_MASK    0x2000
+#define    RTL8367C_COUNTER12_RESET_OFFSET    12
+#define    RTL8367C_COUNTER12_RESET_MASK    0x1000
+#define    RTL8367C_COUNTER11_RESET_OFFSET    11
+#define    RTL8367C_COUNTER11_RESET_MASK    0x800
+#define    RTL8367C_COUNTER10_RESET_OFFSET    10
+#define    RTL8367C_COUNTER10_RESET_MASK    0x400
+#define    RTL8367C_COUNTER9_RESET_OFFSET    9
+#define    RTL8367C_COUNTER9_RESET_MASK    0x200
+#define    RTL8367C_COUNTER8_RESET_OFFSET    8
+#define    RTL8367C_COUNTER8_RESET_MASK    0x100
+#define    RTL8367C_COUNTER7_RESET_OFFSET    7
+#define    RTL8367C_COUNTER7_RESET_MASK    0x80
+#define    RTL8367C_COUNTER6_RESET_OFFSET    6
+#define    RTL8367C_COUNTER6_RESET_MASK    0x40
+#define    RTL8367C_COUNTER5_RESET_OFFSET    5
+#define    RTL8367C_COUNTER5_RESET_MASK    0x20
+#define    RTL8367C_COUNTER4_RESET_OFFSET    4
+#define    RTL8367C_COUNTER4_RESET_MASK    0x10
+#define    RTL8367C_COUNTER3_RESET_OFFSET    3
+#define    RTL8367C_COUNTER3_RESET_MASK    0x8
+#define    RTL8367C_COUNTER2_RESET_OFFSET    2
+#define    RTL8367C_COUNTER2_RESET_MASK    0x4
+#define    RTL8367C_COUNTER1_RESET_OFFSET    1
+#define    RTL8367C_COUNTER1_RESET_MASK    0x2
+#define    RTL8367C_COUNTER0_RESET_OFFSET    0
+#define    RTL8367C_COUNTER0_RESET_MASK    0x1
+
+#define    RTL8367C_REG_MIB_CTRL2    0x1008
+#define    RTL8367C_COUNTER31_RESET_OFFSET    15
+#define    RTL8367C_COUNTER31_RESET_MASK    0x8000
+#define    RTL8367C_COUNTER30_RESET_OFFSET    14
+#define    RTL8367C_COUNTER30_RESET_MASK    0x4000
+#define    RTL8367C_COUNTER29_RESET_OFFSET    13
+#define    RTL8367C_COUNTER29_RESET_MASK    0x2000
+#define    RTL8367C_COUNTER28_RESET_OFFSET    12
+#define    RTL8367C_COUNTER28_RESET_MASK    0x1000
+#define    RTL8367C_COUNTER27_RESET_OFFSET    11
+#define    RTL8367C_COUNTER27_RESET_MASK    0x800
+#define    RTL8367C_COUNTER26_RESET_OFFSET    10
+#define    RTL8367C_COUNTER26_RESET_MASK    0x400
+#define    RTL8367C_COUNTER25_RESET_OFFSET    9
+#define    RTL8367C_COUNTER25_RESET_MASK    0x200
+#define    RTL8367C_COUNTER24_RESET_OFFSET    8
+#define    RTL8367C_COUNTER24_RESET_MASK    0x100
+#define    RTL8367C_COUNTER23_RESET_OFFSET    7
+#define    RTL8367C_COUNTER23_RESET_MASK    0x80
+#define    RTL8367C_COUNTER22_RESET_OFFSET    6
+#define    RTL8367C_COUNTER22_RESET_MASK    0x40
+#define    RTL8367C_COUNTER21_RESET_OFFSET    5
+#define    RTL8367C_COUNTER21_RESET_MASK    0x20
+#define    RTL8367C_COUNTER20_RESET_OFFSET    4
+#define    RTL8367C_COUNTER20_RESET_MASK    0x10
+#define    RTL8367C_COUNTER19_RESET_OFFSET    3
+#define    RTL8367C_COUNTER19_RESET_MASK    0x8
+#define    RTL8367C_COUNTER18_RESET_OFFSET    2
+#define    RTL8367C_COUNTER18_RESET_MASK    0x4
+#define    RTL8367C_COUNTER17_RESET_OFFSET    1
+#define    RTL8367C_COUNTER17_RESET_MASK    0x2
+#define    RTL8367C_COUNTER16_RESET_OFFSET    0
+#define    RTL8367C_COUNTER16_RESET_MASK    0x1
+
+#define    RTL8367C_REG_MIB_CTRL3    0x1009
+#define    RTL8367C_COUNTER15_MODE_OFFSET    15
+#define    RTL8367C_COUNTER15_MODE_MASK    0x8000
+#define    RTL8367C_COUNTER14_MODE_OFFSET    14
+#define    RTL8367C_COUNTER14_MODE_MASK    0x4000
+#define    RTL8367C_COUNTER13_MODE_OFFSET    13
+#define    RTL8367C_COUNTER13_MODE_MASK    0x2000
+#define    RTL8367C_COUNTER12_MODE_OFFSET    12
+#define    RTL8367C_COUNTER12_MODE_MASK    0x1000
+#define    RTL8367C_COUNTER11_MODE_OFFSET    11
+#define    RTL8367C_COUNTER11_MODE_MASK    0x800
+#define    RTL8367C_COUNTER10_MODE_OFFSET    10
+#define    RTL8367C_COUNTER10_MODE_MASK    0x400
+#define    RTL8367C_COUNTER9_MODE_OFFSET    9
+#define    RTL8367C_COUNTER9_MODE_MASK    0x200
+#define    RTL8367C_COUNTER8_MODE_OFFSET    8
+#define    RTL8367C_COUNTER8_MODE_MASK    0x100
+#define    RTL8367C_COUNTER7_MODE_OFFSET    7
+#define    RTL8367C_COUNTER7_MODE_MASK    0x80
+#define    RTL8367C_COUNTER6_MODE_OFFSET    6
+#define    RTL8367C_COUNTER6_MODE_MASK    0x40
+#define    RTL8367C_COUNTER5_MODE_OFFSET    5
+#define    RTL8367C_COUNTER5_MODE_MASK    0x20
+#define    RTL8367C_COUNTER4_MODE_OFFSET    4
+#define    RTL8367C_COUNTER4_MODE_MASK    0x10
+#define    RTL8367C_COUNTER3_MODE_OFFSET    3
+#define    RTL8367C_COUNTER3_MODE_MASK    0x8
+#define    RTL8367C_COUNTER2_MODE_OFFSET    2
+#define    RTL8367C_COUNTER2_MODE_MASK    0x4
+#define    RTL8367C_COUNTER1_MODE_OFFSET    1
+#define    RTL8367C_COUNTER1_MODE_MASK    0x2
+#define    RTL8367C_COUNTER0_MODE_OFFSET    0
+#define    RTL8367C_COUNTER0_MODE_MASK    0x1
+
+#define    RTL8367C_REG_MIB_CTRL4    0x100a
+#define    RTL8367C_MIB_USAGE_MODE_OFFSET    8
+#define    RTL8367C_MIB_USAGE_MODE_MASK    0x100
+#define    RTL8367C_MIB_TIMER_OFFSET    0
+#define    RTL8367C_MIB_TIMER_MASK    0xFF
+
+#define    RTL8367C_REG_MIB_CTRL5    0x100b
+#define    RTL8367C_MIB_CTRL5_COUNTER15_TYPE_OFFSET    15
+#define    RTL8367C_MIB_CTRL5_COUNTER15_TYPE_MASK    0x8000
+#define    RTL8367C_MIB_CTRL5_COUNTER14_TYPE_OFFSET    14
+#define    RTL8367C_MIB_CTRL5_COUNTER14_TYPE_MASK    0x4000
+#define    RTL8367C_MIB_CTRL5_COUNTER13_TYPE_OFFSET    13
+#define    RTL8367C_MIB_CTRL5_COUNTER13_TYPE_MASK    0x2000
+#define    RTL8367C_MIB_CTRL5_COUNTER12_TYPE_OFFSET    12
+#define    RTL8367C_MIB_CTRL5_COUNTER12_TYPE_MASK    0x1000
+#define    RTL8367C_MIB_CTRL5_COUNTER11_TYPE_OFFSET    11
+#define    RTL8367C_MIB_CTRL5_COUNTER11_TYPE_MASK    0x800
+#define    RTL8367C_MIB_CTRL5_COUNTER10_TYPE_OFFSET    10
+#define    RTL8367C_MIB_CTRL5_COUNTER10_TYPE_MASK    0x400
+#define    RTL8367C_MIB_CTRL5_COUNTER9_TYPE_OFFSET    9
+#define    RTL8367C_MIB_CTRL5_COUNTER9_TYPE_MASK    0x200
+#define    RTL8367C_MIB_CTRL5_COUNTER8_TYPE_OFFSET    8
+#define    RTL8367C_MIB_CTRL5_COUNTER8_TYPE_MASK    0x100
+#define    RTL8367C_MIB_CTRL5_COUNTER7_TYPE_OFFSET    7
+#define    RTL8367C_MIB_CTRL5_COUNTER7_TYPE_MASK    0x80
+#define    RTL8367C_MIB_CTRL5_COUNTER6_TYPE_OFFSET    6
+#define    RTL8367C_MIB_CTRL5_COUNTER6_TYPE_MASK    0x40
+#define    RTL8367C_MIB_CTRL5_COUNTER5_TYPE_OFFSET    5
+#define    RTL8367C_MIB_CTRL5_COUNTER5_TYPE_MASK    0x20
+#define    RTL8367C_MIB_CTRL5_COUNTER4_TYPE_OFFSET    4
+#define    RTL8367C_MIB_CTRL5_COUNTER4_TYPE_MASK    0x10
+#define    RTL8367C_MIB_CTRL5_COUNTER3_TYPE_OFFSET    3
+#define    RTL8367C_MIB_CTRL5_COUNTER3_TYPE_MASK    0x8
+#define    RTL8367C_MIB_CTRL5_COUNTER2_TYPE_OFFSET    2
+#define    RTL8367C_MIB_CTRL5_COUNTER2_TYPE_MASK    0x4
+#define    RTL8367C_MIB_CTRL5_COUNTER1_TYPE_OFFSET    1
+#define    RTL8367C_MIB_CTRL5_COUNTER1_TYPE_MASK    0x2
+#define    RTL8367C_MIB_CTRL5_COUNTER0_TYPE_OFFSET    0
+#define    RTL8367C_MIB_CTRL5_COUNTER0_TYPE_MASK    0x1
+
+/* (16'h1100)intrpt_reg */
+
+#define    RTL8367C_REG_INTR_CTRL    0x1100
+#define    RTL8367C_INTR_CTRL_OFFSET    0
+#define    RTL8367C_INTR_CTRL_MASK    0x1
+
+#define    RTL8367C_REG_INTR_IMR    0x1101
+#define    RTL8367C_INTR_IMR_SLIENT_START_2_OFFSET    12
+#define    RTL8367C_INTR_IMR_SLIENT_START_2_MASK    0x1000
+#define    RTL8367C_INTR_IMR_SLIENT_START_OFFSET    11
+#define    RTL8367C_INTR_IMR_SLIENT_START_MASK    0x800
+#define    RTL8367C_INTR_IMR_ACL_ACTION_OFFSET    9
+#define    RTL8367C_INTR_IMR_ACL_ACTION_MASK    0x200
+#define    RTL8367C_INTR_IMR_CABLE_DIAG_FIN_OFFSET    8
+#define    RTL8367C_INTR_IMR_CABLE_DIAG_FIN_MASK    0x100
+#define    RTL8367C_INTR_IMR_INTERRUPT_8051_OFFSET    7
+#define    RTL8367C_INTR_IMR_INTERRUPT_8051_MASK    0x80
+#define    RTL8367C_INTR_IMR_LOOP_DETECTION_OFFSET    6
+#define    RTL8367C_INTR_IMR_LOOP_DETECTION_MASK    0x40
+#define    RTL8367C_INTR_IMR_GREEN_TIMER_OFFSET    5
+#define    RTL8367C_INTR_IMR_GREEN_TIMER_MASK    0x20
+#define    RTL8367C_INTR_IMR_SPECIAL_CONGEST_OFFSET    4
+#define    RTL8367C_INTR_IMR_SPECIAL_CONGEST_MASK    0x10
+#define    RTL8367C_INTR_IMR_SPEED_CHANGE_OFFSET    3
+#define    RTL8367C_INTR_IMR_SPEED_CHANGE_MASK    0x8
+#define    RTL8367C_INTR_IMR_LEARN_OVER_OFFSET    2
+#define    RTL8367C_INTR_IMR_LEARN_OVER_MASK    0x4
+#define    RTL8367C_INTR_IMR_METER_EXCEEDED_OFFSET    1
+#define    RTL8367C_INTR_IMR_METER_EXCEEDED_MASK    0x2
+#define    RTL8367C_INTR_IMR_LINK_CHANGE_OFFSET    0
+#define    RTL8367C_INTR_IMR_LINK_CHANGE_MASK    0x1
+
+#define    RTL8367C_REG_INTR_IMS    0x1102
+#define    RTL8367C_INTR_IMS_SLIENT_START_2_OFFSET    12
+#define    RTL8367C_INTR_IMS_SLIENT_START_2_MASK    0x1000
+#define    RTL8367C_INTR_IMS_SLIENT_START_OFFSET    11
+#define    RTL8367C_INTR_IMS_SLIENT_START_MASK    0x800
+#define    RTL8367C_INTR_IMS_ACL_ACTION_OFFSET    9
+#define    RTL8367C_INTR_IMS_ACL_ACTION_MASK    0x200
+#define    RTL8367C_INTR_IMS_CABLE_DIAG_FIN_OFFSET    8
+#define    RTL8367C_INTR_IMS_CABLE_DIAG_FIN_MASK    0x100
+#define    RTL8367C_INTR_IMS_INTERRUPT_8051_OFFSET    7
+#define    RTL8367C_INTR_IMS_INTERRUPT_8051_MASK    0x80
+#define    RTL8367C_INTR_IMS_LOOP_DETECTION_OFFSET    6
+#define    RTL8367C_INTR_IMS_LOOP_DETECTION_MASK    0x40
+#define    RTL8367C_INTR_IMS_GREEN_TIMER_OFFSET    5
+#define    RTL8367C_INTR_IMS_GREEN_TIMER_MASK    0x20
+#define    RTL8367C_INTR_IMS_SPECIAL_CONGEST_OFFSET    4
+#define    RTL8367C_INTR_IMS_SPECIAL_CONGEST_MASK    0x10
+#define    RTL8367C_INTR_IMS_SPEED_CHANGE_OFFSET    3
+#define    RTL8367C_INTR_IMS_SPEED_CHANGE_MASK    0x8
+#define    RTL8367C_INTR_IMS_LEARN_OVER_OFFSET    2
+#define    RTL8367C_INTR_IMS_LEARN_OVER_MASK    0x4
+#define    RTL8367C_INTR_IMS_METER_EXCEEDED_OFFSET    1
+#define    RTL8367C_INTR_IMS_METER_EXCEEDED_MASK    0x2
+#define    RTL8367C_INTR_IMS_LINK_CHANGE_OFFSET    0
+#define    RTL8367C_INTR_IMS_LINK_CHANGE_MASK    0x1
+
+#define    RTL8367C_REG_LEARN_OVER_INDICATOR    0x1103
+#define    RTL8367C_LEARN_OVER_INDICATOR_OFFSET    0
+#define    RTL8367C_LEARN_OVER_INDICATOR_MASK    0x7FF
+
+#define    RTL8367C_REG_SPEED_CHANGE_INDICATOR    0x1104
+#define    RTL8367C_SPEED_CHANGE_INDICATOR_OFFSET    0
+#define    RTL8367C_SPEED_CHANGE_INDICATOR_MASK    0x7FF
+
+#define    RTL8367C_REG_SPECIAL_CONGEST_INDICATOR    0x1105
+#define    RTL8367C_SPECIAL_CONGEST_INDICATOR_OFFSET    0
+#define    RTL8367C_SPECIAL_CONGEST_INDICATOR_MASK    0x7FF
+
+#define    RTL8367C_REG_PORT_LINKDOWN_INDICATOR    0x1106
+#define    RTL8367C_PORT_LINKDOWN_INDICATOR_OFFSET    0
+#define    RTL8367C_PORT_LINKDOWN_INDICATOR_MASK    0x7FF
+
+#define    RTL8367C_REG_PORT_LINKUP_INDICATOR    0x1107
+#define    RTL8367C_PORT_LINKUP_INDICATOR_OFFSET    0
+#define    RTL8367C_PORT_LINKUP_INDICATOR_MASK    0x7FF
+
+#define    RTL8367C_REG_SYSTEM_LEARN_OVER_INDICATOR    0x1108
+#define    RTL8367C_SYSTEM_LEARN_OVER_INDICATOR_OFFSET    0
+#define    RTL8367C_SYSTEM_LEARN_OVER_INDICATOR_MASK    0x1
+
+#define    RTL8367C_REG_INTR_IMR_8051    0x1118
+#define    RTL8367C_INTR_IMR_8051_SLIENT_START_2_OFFSET    13
+#define    RTL8367C_INTR_IMR_8051_SLIENT_START_2_MASK    0x2000
+#define    RTL8367C_INTR_IMR_8051_SLIENT_START_OFFSET    12
+#define    RTL8367C_INTR_IMR_8051_SLIENT_START_MASK    0x1000
+#define    RTL8367C_INTR_IMR_8051_ACL_ACTION_OFFSET    10
+#define    RTL8367C_INTR_IMR_8051_ACL_ACTION_MASK    0x400
+#define    RTL8367C_INTR_IMR_8051_SAMOVING_8051_OFFSET    9
+#define    RTL8367C_INTR_IMR_8051_SAMOVING_8051_MASK    0x200
+#define    RTL8367C_INTR_IMR_8051_CABLE_DIAG_FIN_8051_OFFSET    8
+#define    RTL8367C_INTR_IMR_8051_CABLE_DIAG_FIN_8051_MASK    0x100
+#define    RTL8367C_INTR_IMR_8051_EEELLDP_8051_OFFSET    7
+#define    RTL8367C_INTR_IMR_8051_EEELLDP_8051_MASK    0x80
+#define    RTL8367C_INTR_IMR_8051_LOOP_DETECTION_8051_OFFSET    6
+#define    RTL8367C_INTR_IMR_8051_LOOP_DETECTION_8051_MASK    0x40
+#define    RTL8367C_INTR_IMR_8051_GREEN_TIMER_8051_OFFSET    5
+#define    RTL8367C_INTR_IMR_8051_GREEN_TIMER_8051_MASK    0x20
+#define    RTL8367C_INTR_IMR_8051_SPECIAL_CONGEST_8051_OFFSET    4
+#define    RTL8367C_INTR_IMR_8051_SPECIAL_CONGEST_8051_MASK    0x10
+#define    RTL8367C_INTR_IMR_8051_SPEED_CHANGE_8051_OFFSET    3
+#define    RTL8367C_INTR_IMR_8051_SPEED_CHANGE_8051_MASK    0x8
+#define    RTL8367C_INTR_IMR_8051_LEARN_OVER_8051_OFFSET    2
+#define    RTL8367C_INTR_IMR_8051_LEARN_OVER_8051_MASK    0x4
+#define    RTL8367C_INTR_IMR_8051_METER_EXCEEDED_8051_OFFSET    1
+#define    RTL8367C_INTR_IMR_8051_METER_EXCEEDED_8051_MASK    0x2
+#define    RTL8367C_INTR_IMR_8051_LINK_CHANGE_8051_OFFSET    0
+#define    RTL8367C_INTR_IMR_8051_LINK_CHANGE_8051_MASK    0x1
+
+#define    RTL8367C_REG_INTR_IMS_8051    0x1119
+#define    RTL8367C_INTR_IMS_8051_SLIENT_START_2_OFFSET    13
+#define    RTL8367C_INTR_IMS_8051_SLIENT_START_2_MASK    0x2000
+#define    RTL8367C_INTR_IMS_8051_SLIENT_START_OFFSET    12
+#define    RTL8367C_INTR_IMS_8051_SLIENT_START_MASK    0x1000
+#define    RTL8367C_INTR_IMS_8051_ACL_ACTION_OFFSET    10
+#define    RTL8367C_INTR_IMS_8051_ACL_ACTION_MASK    0x400
+#define    RTL8367C_INTR_IMS_8051_SAMOVING_8051_OFFSET    9
+#define    RTL8367C_INTR_IMS_8051_SAMOVING_8051_MASK    0x200
+#define    RTL8367C_INTR_IMS_8051_CABLE_DIAG_FIN_8051_OFFSET    8
+#define    RTL8367C_INTR_IMS_8051_CABLE_DIAG_FIN_8051_MASK    0x100
+#define    RTL8367C_INTR_IMS_8051_EEELLDP_8051_OFFSET    7
+#define    RTL8367C_INTR_IMS_8051_EEELLDP_8051_MASK    0x80
+#define    RTL8367C_INTR_IMS_8051_LOOP_DETECTION_8051_OFFSET    6
+#define    RTL8367C_INTR_IMS_8051_LOOP_DETECTION_8051_MASK    0x40
+#define    RTL8367C_INTR_IMS_8051_GREEN_TIMER_8051_OFFSET    5
+#define    RTL8367C_INTR_IMS_8051_GREEN_TIMER_8051_MASK    0x20
+#define    RTL8367C_INTR_IMS_8051_SPECIAL_CONGEST_8051_OFFSET    4
+#define    RTL8367C_INTR_IMS_8051_SPECIAL_CONGEST_8051_MASK    0x10
+#define    RTL8367C_INTR_IMS_8051_SPEED_CHANGE_8051_OFFSET    3
+#define    RTL8367C_INTR_IMS_8051_SPEED_CHANGE_8051_MASK    0x8
+#define    RTL8367C_INTR_IMS_8051_LEARN_OVER_8051_OFFSET    2
+#define    RTL8367C_INTR_IMS_8051_LEARN_OVER_8051_MASK    0x4
+#define    RTL8367C_INTR_IMS_8051_METER_EXCEEDED_8051_OFFSET    1
+#define    RTL8367C_INTR_IMS_8051_METER_EXCEEDED_8051_MASK    0x2
+#define    RTL8367C_INTR_IMS_8051_LINK_CHANGE_8051_OFFSET    0
+#define    RTL8367C_INTR_IMS_8051_LINK_CHANGE_8051_MASK    0x1
+
+#define    RTL8367C_REG_DW8051_INT_CPU    0x111a
+#define    RTL8367C_DW8051_INT_CPU_OFFSET    0
+#define    RTL8367C_DW8051_INT_CPU_MASK    0x1
+
+#define    RTL8367C_REG_LEARN_OVER_INDICATOR_8051    0x1120
+#define    RTL8367C_LEARN_OVER_INDICATOR_8051_OFFSET    0
+#define    RTL8367C_LEARN_OVER_INDICATOR_8051_MASK    0x7FF
+
+#define    RTL8367C_REG_SPEED_CHANGE_INDICATOR_8051    0x1121
+#define    RTL8367C_SPEED_CHANGE_INDICATOR_8051_OFFSET    0
+#define    RTL8367C_SPEED_CHANGE_INDICATOR_8051_MASK    0x7FF
+
+#define    RTL8367C_REG_SPECIAL_CONGEST_INDICATOR_8051    0x1122
+#define    RTL8367C_SPECIAL_CONGEST_INDICATOR_8051_OFFSET    0
+#define    RTL8367C_SPECIAL_CONGEST_INDICATOR_8051_MASK    0x7FF
+
+#define    RTL8367C_REG_PORT_LINKDOWN_INDICATOR_8051    0x1123
+#define    RTL8367C_PORT_LINKDOWN_INDICATOR_8051_OFFSET    0
+#define    RTL8367C_PORT_LINKDOWN_INDICATOR_8051_MASK    0x7FF
+
+#define    RTL8367C_REG_PORT_LINKUP_INDICATOR_8051    0x1124
+#define    RTL8367C_PORT_LINKUP_INDICATOR_8051_OFFSET    0
+#define    RTL8367C_PORT_LINKUP_INDICATOR_8051_MASK    0x7FF
+
+#define    RTL8367C_REG_DUMMY_1125    0x1125
+
+#define    RTL8367C_REG_DUMMY_1126    0x1126
+
+#define    RTL8367C_REG_DUMMY_1127    0x1127
+
+#define    RTL8367C_REG_DUMMY_1128    0x1128
+
+#define    RTL8367C_REG_DUMMY_1129    0x1129
+
+#define    RTL8367C_REG_INTR_IMS_BUFFER_RESET    0x112a
+#define    RTL8367C_INTR_IMS_BUFFER_RESET_IMR_BUFF_RESET_OFFSET    1
+#define    RTL8367C_INTR_IMS_BUFFER_RESET_IMR_BUFF_RESET_MASK    0x2
+#define    RTL8367C_INTR_IMS_BUFFER_RESET_BUFFER_RESET_OFFSET    0
+#define    RTL8367C_INTR_IMS_BUFFER_RESET_BUFFER_RESET_MASK    0x1
+
+#define    RTL8367C_REG_INTR_IMS_8051_BUFFER_RESET    0x112b
+#define    RTL8367C_INTR_IMS_8051_BUFFER_RESET_IMR_BUFF_RESET_OFFSET    1
+#define    RTL8367C_INTR_IMS_8051_BUFFER_RESET_IMR_BUFF_RESET_MASK    0x2
+#define    RTL8367C_INTR_IMS_8051_BUFFER_RESET_BUFFER_RESET_OFFSET    0
+#define    RTL8367C_INTR_IMS_8051_BUFFER_RESET_BUFFER_RESET_MASK    0x1
+
+#define    RTL8367C_REG_GPHY_INTRPT_8051    0x112c
+#define    RTL8367C_IMS_GPHY_8051_H_OFFSET    13
+#define    RTL8367C_IMS_GPHY_8051_H_MASK    0xE000
+#define    RTL8367C_IMR_GPHY_8051_H_OFFSET    10
+#define    RTL8367C_IMR_GPHY_8051_H_MASK    0x1C00
+#define    RTL8367C_IMS_GPHY_8051_OFFSET    5
+#define    RTL8367C_IMS_GPHY_8051_MASK    0x3E0
+#define    RTL8367C_IMR_GPHY_8051_OFFSET    0
+#define    RTL8367C_IMR_GPHY_8051_MASK    0x1F
+
+#define    RTL8367C_REG_GPHY_INTRPT    0x112d
+#define    RTL8367C_IMS_GPHY_H_OFFSET    13
+#define    RTL8367C_IMS_GPHY_H_MASK    0xE000
+#define    RTL8367C_IMR_GPHY_H_OFFSET    10
+#define    RTL8367C_IMR_GPHY_H_MASK    0x1C00
+#define    RTL8367C_IMS_GPHY_OFFSET    5
+#define    RTL8367C_IMS_GPHY_MASK    0x3E0
+#define    RTL8367C_IMR_GPHY_OFFSET    0
+#define    RTL8367C_IMR_GPHY_MASK    0x1F
+
+#define    RTL8367C_REG_THERMAL_INTRPT    0x112e
+#define    RTL8367C_IMS_TM_HIGH_OFFSET    3
+#define    RTL8367C_IMS_TM_HIGH_MASK    0x8
+#define    RTL8367C_IMR_TM_HIGH_OFFSET    2
+#define    RTL8367C_IMR_TM_HIGH_MASK    0x4
+#define    RTL8367C_IMS_TM_LOW_OFFSET    1
+#define    RTL8367C_IMS_TM_LOW_MASK    0x2
+#define    RTL8367C_IMR_TM_LOW_OFFSET    0
+#define    RTL8367C_IMR_TM_LOW_MASK    0x1
+
+#define    RTL8367C_REG_THERMAL_INTRPT_8051    0x112f
+#define    RTL8367C_IMS_TM_HIGH_8051_OFFSET    3
+#define    RTL8367C_IMS_TM_HIGH_8051_MASK    0x8
+#define    RTL8367C_IMR_TM_HIGH_8051_OFFSET    2
+#define    RTL8367C_IMR_TM_HIGH_8051_MASK    0x4
+#define    RTL8367C_IMS_TM_LOW_8051_OFFSET    1
+#define    RTL8367C_IMS_TM_LOW_8051_MASK    0x2
+#define    RTL8367C_IMR_TM_LOW_8051_OFFSET    0
+#define    RTL8367C_IMR_TM_LOW_8051_MASK    0x1
+
+#define    RTL8367C_REG_SDS_LINK_CHG_INT    0x1130
+#define    RTL8367C_IMS_SDS_LINK_STS_C7_OFFSET    15
+#define    RTL8367C_IMS_SDS_LINK_STS_C7_MASK    0x8000
+#define    RTL8367C_IMS_SDS_LINK_STS_C6_OFFSET    14
+#define    RTL8367C_IMS_SDS_LINK_STS_C6_MASK    0x4000
+#define    RTL8367C_IMS_SDS_LINK_STS_C5_OFFSET    13
+#define    RTL8367C_IMS_SDS_LINK_STS_C5_MASK    0x2000
+#define    RTL8367C_IMS_SDS_LINK_STS_C4_OFFSET    12
+#define    RTL8367C_IMS_SDS_LINK_STS_C4_MASK    0x1000
+#define    RTL8367C_IMS_SDS_LINK_STS_C3_OFFSET    11
+#define    RTL8367C_IMS_SDS_LINK_STS_C3_MASK    0x800
+#define    RTL8367C_IMS_SDS_LINK_STS_C2_OFFSET    10
+#define    RTL8367C_IMS_SDS_LINK_STS_C2_MASK    0x400
+#define    RTL8367C_IMS_SDS_LINK_STS_C1_OFFSET    9
+#define    RTL8367C_IMS_SDS_LINK_STS_C1_MASK    0x200
+#define    RTL8367C_IMS_SDS_LINK_STS_C0_OFFSET    8
+#define    RTL8367C_IMS_SDS_LINK_STS_C0_MASK    0x100
+#define    RTL8367C_IMR_SDS_LINK_STS_C7_OFFSET    7
+#define    RTL8367C_IMR_SDS_LINK_STS_C7_MASK    0x80
+#define    RTL8367C_IMR_SDS_LINK_STS_C6_OFFSET    6
+#define    RTL8367C_IMR_SDS_LINK_STS_C6_MASK    0x40
+#define    RTL8367C_IMR_SDS_LINK_STS_C5_OFFSET    5
+#define    RTL8367C_IMR_SDS_LINK_STS_C5_MASK    0x20
+#define    RTL8367C_IMR_SDS_LINK_STS_C4_OFFSET    4
+#define    RTL8367C_IMR_SDS_LINK_STS_C4_MASK    0x10
+#define    RTL8367C_IMR_SDS_LINK_STS_C3_OFFSET    3
+#define    RTL8367C_IMR_SDS_LINK_STS_C3_MASK    0x8
+#define    RTL8367C_IMR_SDS_LINK_STS_C2_OFFSET    2
+#define    RTL8367C_IMR_SDS_LINK_STS_C2_MASK    0x4
+#define    RTL8367C_IMR_SDS_LINK_STS_C1_OFFSET    1
+#define    RTL8367C_IMR_SDS_LINK_STS_C1_MASK    0x2
+#define    RTL8367C_IMR_SDS_LINK_STS_C0_OFFSET    0
+#define    RTL8367C_IMR_SDS_LINK_STS_C0_MASK    0x1
+
+#define    RTL8367C_REG_SDS_LINK_CHG_INT_8051    0x1131
+#define    RTL8367C_IMS_SDS_LINK_STS_C7_8051_OFFSET    15
+#define    RTL8367C_IMS_SDS_LINK_STS_C7_8051_MASK    0x8000
+#define    RTL8367C_IMS_SDS_LINK_STS_C6_8051_OFFSET    14
+#define    RTL8367C_IMS_SDS_LINK_STS_C6_8051_MASK    0x4000
+#define    RTL8367C_IMS_SDS_LINK_STS_C5_8051_OFFSET    13
+#define    RTL8367C_IMS_SDS_LINK_STS_C5_8051_MASK    0x2000
+#define    RTL8367C_IMS_SDS_LINK_STS_C4_8051_OFFSET    12
+#define    RTL8367C_IMS_SDS_LINK_STS_C4_8051_MASK    0x1000
+#define    RTL8367C_IMS_SDS_LINK_STS_C3_8051_OFFSET    11
+#define    RTL8367C_IMS_SDS_LINK_STS_C3_8051_MASK    0x800
+#define    RTL8367C_IMS_SDS_LINK_STS_C2_8051_OFFSET    10
+#define    RTL8367C_IMS_SDS_LINK_STS_C2_8051_MASK    0x400
+#define    RTL8367C_IMS_SDS_LINK_STS_C1_8051_OFFSET    9
+#define    RTL8367C_IMS_SDS_LINK_STS_C1_8051_MASK    0x200
+#define    RTL8367C_IMS_SDS_LINK_STS_C0_8051_OFFSET    8
+#define    RTL8367C_IMS_SDS_LINK_STS_C0_8051_MASK    0x100
+#define    RTL8367C_IMR_SDS_LINK_STS_C7_8051_OFFSET    7
+#define    RTL8367C_IMR_SDS_LINK_STS_C7_8051_MASK    0x80
+#define    RTL8367C_IMR_SDS_LINK_STS_C6_8051_OFFSET    6
+#define    RTL8367C_IMR_SDS_LINK_STS_C6_8051_MASK    0x40
+#define    RTL8367C_IMR_SDS_LINK_STS_C5_8051_OFFSET    5
+#define    RTL8367C_IMR_SDS_LINK_STS_C5_8051_MASK    0x20
+#define    RTL8367C_IMR_SDS_LINK_STS_C4_8051_OFFSET    4
+#define    RTL8367C_IMR_SDS_LINK_STS_C4_8051_MASK    0x10
+#define    RTL8367C_IMR_SDS_LINK_STS_C3_8051_OFFSET    3
+#define    RTL8367C_IMR_SDS_LINK_STS_C3_8051_MASK    0x8
+#define    RTL8367C_IMR_SDS_LINK_STS_C2_8051_OFFSET    2
+#define    RTL8367C_IMR_SDS_LINK_STS_C2_8051_MASK    0x4
+#define    RTL8367C_IMR_SDS_LINK_STS_C1_8051_OFFSET    1
+#define    RTL8367C_IMR_SDS_LINK_STS_C1_8051_MASK    0x2
+#define    RTL8367C_IMR_SDS_LINK_STS_C0_8051_OFFSET    0
+#define    RTL8367C_IMR_SDS_LINK_STS_C0_8051_MASK    0x1
+
+/* (16'h1200)swcore_reg */
+
+#define    RTL8367C_REG_MAX_LENGTH_LIMINT_IPG    0x1200
+#define    RTL8367C_MAX_LENTH_CTRL_OFFSET    13
+#define    RTL8367C_MAX_LENTH_CTRL_MASK    0x6000
+#define    RTL8367C_PAGES_BEFORE_FCDROP_OFFSET    6
+#define    RTL8367C_PAGES_BEFORE_FCDROP_MASK    0x1FC0
+#define    RTL8367C_CHECK_MIN_IPG_RXDV_OFFSET    5
+#define    RTL8367C_CHECK_MIN_IPG_RXDV_MASK    0x20
+#define    RTL8367C_LIMIT_IPG_CFG_OFFSET    0
+#define    RTL8367C_LIMIT_IPG_CFG_MASK    0x1F
+
+#define    RTL8367C_REG_IOL_RXDROP_CFG    0x1201
+#define    RTL8367C_RX_IOL_MAX_LENGTH_CFG_OFFSET    13
+#define    RTL8367C_RX_IOL_MAX_LENGTH_CFG_MASK    0x2000
+#define    RTL8367C_RX_IOL_ERROR_LENGTH_CFG_OFFSET    12
+#define    RTL8367C_RX_IOL_ERROR_LENGTH_CFG_MASK    0x1000
+#define    RTL8367C_RX_NODROP_PAUSE_CFG_OFFSET    8
+#define    RTL8367C_RX_NODROP_PAUSE_CFG_MASK    0x100
+#define    RTL8367C_RX_DV_CNT_CFG_OFFSET    0
+#define    RTL8367C_RX_DV_CNT_CFG_MASK    0x3F
+
+#define    RTL8367C_REG_VS_TPID    0x1202
+
+#define    RTL8367C_REG_INBW_BOUND    0x1203
+#define    RTL8367C_LBOUND_OFFSET    4
+#define    RTL8367C_LBOUND_MASK    0xF0
+#define    RTL8367C_HBOUND_OFFSET    0
+#define    RTL8367C_HBOUND_MASK    0xF
+
+#define    RTL8367C_REG_CFG_TX_ITFSP_OP    0x1204
+#define    RTL8367C_MASK_OFFSET    1
+#define    RTL8367C_MASK_MASK    0x2
+#define    RTL8367C_OP_OFFSET    0
+#define    RTL8367C_OP_MASK    0x1
+
+#define    RTL8367C_REG_INBW_BOUND2    0x1205
+#define    RTL8367C_LBOUND2_H_OFFSET    9
+#define    RTL8367C_LBOUND2_H_MASK    0x200
+#define    RTL8367C_HBOUND2_H_OFFSET    8
+#define    RTL8367C_HBOUND2_H_MASK    0x100
+#define    RTL8367C_LBOUND2_OFFSET    4
+#define    RTL8367C_LBOUND2_MASK    0xF0
+#define    RTL8367C_HBOUND2_OFFSET    0
+#define    RTL8367C_HBOUND2_MASK    0xF
+
+#define    RTL8367C_REG_CFG_48PASS1_DROP    0x1206
+#define    RTL8367C_CFG_48PASS1_DROP_OFFSET    0
+#define    RTL8367C_CFG_48PASS1_DROP_MASK    0x1
+
+#define    RTL8367C_REG_CFG_BACKPRESSURE    0x1207
+#define    RTL8367C_LONGTXE_OFFSET    12
+#define    RTL8367C_LONGTXE_MASK    0x1000
+#define    RTL8367C_EN_BYPASS_ERROR_OFFSET    8
+#define    RTL8367C_EN_BYPASS_ERROR_MASK    0x100
+#define    RTL8367C_EN_BACKPRESSURE_OFFSET    4
+#define    RTL8367C_EN_BACKPRESSURE_MASK    0x10
+#define    RTL8367C_EN_48_PASS_1_OFFSET    0
+#define    RTL8367C_EN_48_PASS_1_MASK    0x1
+
+#define    RTL8367C_REG_CFG_UNHIOL    0x1208
+#define    RTL8367C_IOL_BACKOFF_OFFSET    12
+#define    RTL8367C_IOL_BACKOFF_MASK    0x1000
+#define    RTL8367C_BACKOFF_RANDOM_TIME_OFFSET    8
+#define    RTL8367C_BACKOFF_RANDOM_TIME_MASK    0x100
+#define    RTL8367C_DISABLE_BACK_OFF_OFFSET    4
+#define    RTL8367C_DISABLE_BACK_OFF_MASK    0x10
+#define    RTL8367C_IPG_COMPENSATION_OFFSET    0
+#define    RTL8367C_IPG_COMPENSATION_MASK    0x1
+
+#define    RTL8367C_REG_SWITCH_MAC0    0x1209
+
+#define    RTL8367C_REG_SWITCH_MAC1    0x120a
+
+#define    RTL8367C_REG_SWITCH_MAC2    0x120b
+
+#define    RTL8367C_REG_SWITCH_CTRL0    0x120c
+#define    RTL8367C_REMARKING_DSCP_ENABLE_OFFSET    8
+#define    RTL8367C_REMARKING_DSCP_ENABLE_MASK    0x100
+#define    RTL8367C_SHORT_IPG_OFFSET    4
+#define    RTL8367C_SHORT_IPG_MASK    0x10
+#define    RTL8367C_PAUSE_MAX128_OFFSET    0
+#define    RTL8367C_PAUSE_MAX128_MASK    0x1
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_CTRL0    0x120d
+#define    RTL8367C_INTPRI1_DSCP_OFFSET    8
+#define    RTL8367C_INTPRI1_DSCP_MASK    0x3F00
+#define    RTL8367C_INTPRI0_DSCP_OFFSET    0
+#define    RTL8367C_INTPRI0_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_CTRL1    0x120e
+#define    RTL8367C_INTPRI3_DSCP_OFFSET    8
+#define    RTL8367C_INTPRI3_DSCP_MASK    0x3F00
+#define    RTL8367C_INTPRI2_DSCP_OFFSET    0
+#define    RTL8367C_INTPRI2_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_CTRL2    0x120f
+#define    RTL8367C_INTPRI5_DSCP_OFFSET    8
+#define    RTL8367C_INTPRI5_DSCP_MASK    0x3F00
+#define    RTL8367C_INTPRI4_DSCP_OFFSET    0
+#define    RTL8367C_INTPRI4_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_DSCP_REMARK_CTRL3    0x1210
+#define    RTL8367C_INTPRI7_DSCP_OFFSET    8
+#define    RTL8367C_INTPRI7_DSCP_MASK    0x3F00
+#define    RTL8367C_INTPRI6_DSCP_OFFSET    0
+#define    RTL8367C_INTPRI6_DSCP_MASK    0x3F
+
+#define    RTL8367C_REG_QOS_1Q_REMARK_CTRL0    0x1211
+#define    RTL8367C_INTPRI3_PRI_OFFSET    12
+#define    RTL8367C_INTPRI3_PRI_MASK    0x7000
+#define    RTL8367C_INTPRI2_PRI_OFFSET    8
+#define    RTL8367C_INTPRI2_PRI_MASK    0x700
+#define    RTL8367C_INTPRI1_PRI_OFFSET    4
+#define    RTL8367C_INTPRI1_PRI_MASK    0x70
+#define    RTL8367C_INTPRI0_PRI_OFFSET    0
+#define    RTL8367C_INTPRI0_PRI_MASK    0x7
+
+#define    RTL8367C_REG_QOS_1Q_REMARK_CTRL1    0x1212
+#define    RTL8367C_INTPRI7_PRI_OFFSET    12
+#define    RTL8367C_INTPRI7_PRI_MASK    0x7000
+#define    RTL8367C_INTPRI6_PRI_OFFSET    8
+#define    RTL8367C_INTPRI6_PRI_MASK    0x700
+#define    RTL8367C_INTPRI5_PRI_OFFSET    4
+#define    RTL8367C_INTPRI5_PRI_MASK    0x70
+#define    RTL8367C_INTPRI4_PRI_OFFSET    0
+#define    RTL8367C_INTPRI4_PRI_MASK    0x7
+
+#define    RTL8367C_REG_PKTGEN_COMMAND    0x1213
+#define    RTL8367C_PKTGEN_STOP_OFFSET    8
+#define    RTL8367C_PKTGEN_STOP_MASK    0x100
+#define    RTL8367C_PKTGEN_START_OFFSET    4
+#define    RTL8367C_PKTGEN_START_MASK    0x10
+#define    RTL8367C_PKTGEN_BYPASS_FLOWCONTROL_OFFSET    0
+#define    RTL8367C_PKTGEN_BYPASS_FLOWCONTROL_MASK    0x1
+
+#define    RTL8367C_REG_SW_DUMMY0    0x1214
+#define    RTL8367C_SW_DUMMY0_DUMMY_OFFSET    4
+#define    RTL8367C_SW_DUMMY0_DUMMY_MASK    0xFFF0
+#define    RTL8367C_EEE_DEFER_TXLPI_OFFSET    3
+#define    RTL8367C_EEE_DEFER_TXLPI_MASK    0x8
+#define    RTL8367C_INGRESSBW_BYPASS_EN_OFFSET    2
+#define    RTL8367C_INGRESSBW_BYPASS_EN_MASK    0x4
+#define    RTL8367C_CFG_RX_MIN_OFFSET    0
+#define    RTL8367C_CFG_RX_MIN_MASK    0x3
+
+#define    RTL8367C_REG_SW_DUMMY1    0x1215
+
+#define    RTL8367C_REG_PKTGEN_PAUSE_TIME    0x1216
+
+#define    RTL8367C_REG_SVLAN_UPLINK_PORTMASK    0x1218
+#define    RTL8367C_SVLAN_UPLINK_PORTMASK_OFFSET    0
+#define    RTL8367C_SVLAN_UPLINK_PORTMASK_MASK    0x7FF
+
+#define    RTL8367C_REG_CPU_PORT_MASK    0x1219
+#define    RTL8367C_CPU_PORT_MASK_OFFSET    0
+#define    RTL8367C_CPU_PORT_MASK_MASK    0x7FF
+
+#define    RTL8367C_REG_CPU_CTRL    0x121a
+#define    RTL8367C_CPU_TRAP_PORT_EXT_OFFSET    10
+#define    RTL8367C_CPU_TRAP_PORT_EXT_MASK    0x400
+#define    RTL8367C_CPU_TAG_FORMAT_OFFSET    9
+#define    RTL8367C_CPU_TAG_FORMAT_MASK    0x200
+#define    RTL8367C_IOL_16DROP_OFFSET    8
+#define    RTL8367C_IOL_16DROP_MASK    0x100
+#define    RTL8367C_CPU_TAG_RXBYTECOUNT_OFFSET    7
+#define    RTL8367C_CPU_TAG_RXBYTECOUNT_MASK    0x80
+#define    RTL8367C_CPU_TAG_POSITION_OFFSET    6
+#define    RTL8367C_CPU_TAG_POSITION_MASK    0x40
+#define    RTL8367C_CPU_TRAP_PORT_OFFSET    3
+#define    RTL8367C_CPU_TRAP_PORT_MASK    0x38
+#define    RTL8367C_CPU_INSERTMODE_OFFSET    1
+#define    RTL8367C_CPU_INSERTMODE_MASK    0x6
+#define    RTL8367C_CPU_EN_OFFSET    0
+#define    RTL8367C_CPU_EN_MASK    0x1
+
+#define    RTL8367C_REG_MIRROR_CTRL    0x121c
+#define    RTL8367C_MIRROR_CTRL_DUMMY_OFFSET    12
+#define    RTL8367C_MIRROR_CTRL_DUMMY_MASK    0xF000
+#define    RTL8367C_MIRROR_ISO_OFFSET    11
+#define    RTL8367C_MIRROR_ISO_MASK    0x800
+#define    RTL8367C_MIRROR_TX_OFFSET    10
+#define    RTL8367C_MIRROR_TX_MASK    0x400
+#define    RTL8367C_MIRROR_RX_OFFSET    9
+#define    RTL8367C_MIRROR_RX_MASK    0x200
+#define    RTL8367C_MIRROR_MONITOR_PORT_OFFSET    4
+#define    RTL8367C_MIRROR_MONITOR_PORT_MASK    0xF0
+#define    RTL8367C_MIRROR_SOURCE_PORT_OFFSET    0
+#define    RTL8367C_MIRROR_SOURCE_PORT_MASK    0xF
+
+#define    RTL8367C_REG_FLOWCTRL_CTRL0    0x121d
+#define    RTL8367C_FLOWCTRL_TYPE_OFFSET    15
+#define    RTL8367C_FLOWCTRL_TYPE_MASK    0x8000
+#define    RTL8367C_DROP_ALL_THRESHOLD_OFFSET    5
+#define    RTL8367C_DROP_ALL_THRESHOLD_MASK    0x7FE0
+#define    RTL8367C_DROP_ALL_THRESHOLD_MSB_OFFSET    4
+#define    RTL8367C_DROP_ALL_THRESHOLD_MSB_MASK    0x10
+#define    RTL8367C_ITFSP_REG_OFFSET    0
+#define    RTL8367C_ITFSP_REG_MASK    0x7
+
+#define    RTL8367C_REG_FLOWCTRL_ALL_ON    0x121e
+#define    RTL8367C_CFG_RLDPACT_OFFSET    12
+#define    RTL8367C_CFG_RLDPACT_MASK    0x1000
+#define    RTL8367C_FLOWCTRL_ALL_ON_THRESHOLD_OFFSET    0
+#define    RTL8367C_FLOWCTRL_ALL_ON_THRESHOLD_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_SYS_ON    0x121f
+#define    RTL8367C_FLOWCTRL_SYS_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_SYS_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_SYS_OFF    0x1220
+#define    RTL8367C_FLOWCTRL_SYS_OFF_OFFSET    0
+#define    RTL8367C_FLOWCTRL_SYS_OFF_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_SHARE_ON    0x1221
+#define    RTL8367C_FLOWCTRL_SHARE_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_SHARE_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_SHARE_OFF    0x1222
+#define    RTL8367C_FLOWCTRL_SHARE_OFF_OFFSET    0
+#define    RTL8367C_FLOWCTRL_SHARE_OFF_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_FCOFF_SYS_ON    0x1223
+#define    RTL8367C_FLOWCTRL_FCOFF_SYS_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_FCOFF_SYS_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_FCOFF_SYS_OFF    0x1224
+#define    RTL8367C_FLOWCTRL_FCOFF_SYS_OFF_OFFSET    0
+#define    RTL8367C_FLOWCTRL_FCOFF_SYS_OFF_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_FCOFF_SHARE_ON    0x1225
+#define    RTL8367C_FLOWCTRL_FCOFF_SHARE_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_FCOFF_SHARE_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_FCOFF_SHARE_OFF    0x1226
+#define    RTL8367C_FLOWCTRL_FCOFF_SHARE_OFF_OFFSET    0
+#define    RTL8367C_FLOWCTRL_FCOFF_SHARE_OFF_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT_ON    0x1227
+#define    RTL8367C_FLOWCTRL_PORT_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT_OFF    0x1228
+#define    RTL8367C_FLOWCTRL_PORT_OFF_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT_OFF_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT_PRIVATE_ON    0x1229
+#define    RTL8367C_FLOWCTRL_PORT_PRIVATE_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT_PRIVATE_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT_PRIVATE_OFF    0x122a
+#define    RTL8367C_FLOWCTRL_PORT_PRIVATE_OFF_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT_PRIVATE_OFF_MASK    0x7FF
+
+#define    RTL8367C_REG_RRCP_CTRL0    0x122b
+#define    RTL8367C_COL_SEL_OFFSET    14
+#define    RTL8367C_COL_SEL_MASK    0x4000
+#define    RTL8367C_CRS_SEL_OFFSET    13
+#define    RTL8367C_CRS_SEL_MASK    0x2000
+#define    RTL8367C_RRCP_PBVLAN_EN_OFFSET    11
+#define    RTL8367C_RRCP_PBVLAN_EN_MASK    0x800
+#define    RTL8367C_RRCPV3_SECURITY_CRC_OFFSET    10
+#define    RTL8367C_RRCPV3_SECURITY_CRC_MASK    0x400
+#define    RTL8367C_RRCPV3_HANDLE_OFFSET    8
+#define    RTL8367C_RRCPV3_HANDLE_MASK    0x300
+#define    RTL8367C_RRCPV1_MALFORMED_ACT_OFFSET    5
+#define    RTL8367C_RRCPV1_MALFORMED_ACT_MASK    0x60
+#define    RTL8367C_RRCP_VLANLEAKY_OFFSET    4
+#define    RTL8367C_RRCP_VLANLEAKY_MASK    0x10
+#define    RTL8367C_RRCPV1_SECURITY_CRC_GET_OFFSET    3
+#define    RTL8367C_RRCPV1_SECURITY_CRC_GET_MASK    0x8
+#define    RTL8367C_RRCPV1_SECURITY_CRC_SET_OFFSET    2
+#define    RTL8367C_RRCPV1_SECURITY_CRC_SET_MASK    0x4
+#define    RTL8367C_RRCPV1_HANDLE_OFFSET    1
+#define    RTL8367C_RRCPV1_HANDLE_MASK    0x2
+#define    RTL8367C_RRCP_ENABLE_OFFSET    0
+#define    RTL8367C_RRCP_ENABLE_MASK    0x1
+
+#define    RTL8367C_REG_RRCP_CTRL1    0x122c
+#define    RTL8367C_RRCP_ADMIN_PMSK_OFFSET    8
+#define    RTL8367C_RRCP_ADMIN_PMSK_MASK    0xFF00
+#define    RTL8367C_RRCP_AUTH_PMSK_OFFSET    0
+#define    RTL8367C_RRCP_AUTH_PMSK_MASK    0xFF
+
+#define    RTL8367C_REG_RRCP_CTRL2    0x122d
+#define    RTL8367C_RRCPV1_HELLOFWD_TAG_OFFSET    9
+#define    RTL8367C_RRCPV1_HELLOFWD_TAG_MASK    0x600
+#define    RTL8367C_RRCP_FWD_TAG_OFFSET    7
+#define    RTL8367C_RRCP_FWD_TAG_MASK    0x180
+#define    RTL8367C_RRCPV1_REPLY_TAG_OFFSET    6
+#define    RTL8367C_RRCPV1_REPLY_TAG_MASK    0x40
+#define    RTL8367C_RRCPV1_HELLO_COUNT_OFFSET    3
+#define    RTL8367C_RRCPV1_HELLO_COUNT_MASK    0x38
+#define    RTL8367C_RRCPV1_HELLO_PEDIOD_OFFSET    0
+#define    RTL8367C_RRCPV1_HELLO_PEDIOD_MASK    0x3
+
+#define    RTL8367C_REG_RRCP_CTRL3    0x122e
+#define    RTL8367C_RRCP_TAG_PRIORITY_OFFSET    13
+#define    RTL8367C_RRCP_TAG_PRIORITY_MASK    0xE000
+#define    RTL8367C_RRCP_TAG_VID_OFFSET    0
+#define    RTL8367C_RRCP_TAG_VID_MASK    0xFFF
+
+#define    RTL8367C_REG_FLOWCTRL_FCOFF_PORT_ON    0x122f
+#define    RTL8367C_FLOWCTRL_FCOFF_PORT_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_FCOFF_PORT_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_FCOFF_PORT_OFF    0x1230
+#define    RTL8367C_FLOWCTRL_FCOFF_PORT_OFF_OFFSET    0
+#define    RTL8367C_FLOWCTRL_FCOFF_PORT_OFF_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_FCOFF_PORT_PRIVATE_ON    0x1231
+#define    RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_FCOFF_PORT_PRIVATE_OFF    0x1232
+#define    RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_OFF_OFFSET    0
+#define    RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_OFF_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_JUMBO_SYS_ON    0x1233
+#define    RTL8367C_FLOWCTRL_JUMBO_SYS_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_JUMBO_SYS_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_JUMBO_SYS_OFF    0x1234
+#define    RTL8367C_FLOWCTRL_JUMBO_SYS_OFF_OFFSET    0
+#define    RTL8367C_FLOWCTRL_JUMBO_SYS_OFF_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_JUMBO_SHARE_ON    0x1235
+#define    RTL8367C_FLOWCTRL_JUMBO_SHARE_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_JUMBO_SHARE_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_JUMBO_SHARE_OFF    0x1236
+#define    RTL8367C_FLOWCTRL_JUMBO_SHARE_OFF_OFFSET    0
+#define    RTL8367C_FLOWCTRL_JUMBO_SHARE_OFF_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_JUMBO_PORT_ON    0x1237
+#define    RTL8367C_FLOWCTRL_JUMBO_PORT_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_JUMBO_PORT_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_JUMBO_PORT_OFF    0x1238
+#define    RTL8367C_FLOWCTRL_JUMBO_PORT_OFF_OFFSET    0
+#define    RTL8367C_FLOWCTRL_JUMBO_PORT_OFF_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_JUMBO_PORT_PRIVATE_ON    0x1239
+#define    RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_ON_OFFSET    0
+#define    RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_ON_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_JUMBO_PORT_PRIVATE_OFF    0x123a
+#define    RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_OFF_OFFSET    0
+#define    RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_OFF_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_JUMBO_SIZE    0x123b
+#define    RTL8367C_JUMBO_MODE_OFFSET    2
+#define    RTL8367C_JUMBO_MODE_MASK    0x4
+#define    RTL8367C_JUMBO_SIZE_OFFSET    0
+#define    RTL8367C_JUMBO_SIZE_MASK    0x3
+
+#define    RTL8367C_REG_FLOWCTRL_TOTAL_PAGE_COUNTER    0x124c
+#define    RTL8367C_FLOWCTRL_TOTAL_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_FLOWCTRL_TOTAL_PAGE_COUNTER_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PUBLIC_PAGE_COUNTER    0x124d
+#define    RTL8367C_FLOWCTRL_PUBLIC_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PUBLIC_PAGE_COUNTER_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_TOTAL_PAGE_MAX    0x124e
+#define    RTL8367C_FLOWCTRL_TOTAL_PAGE_MAX_OFFSET    0
+#define    RTL8367C_FLOWCTRL_TOTAL_PAGE_MAX_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PUBLIC_PAGE_MAX    0x124f
+#define    RTL8367C_FLOWCTRL_PUBLIC_PAGE_MAX_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PUBLIC_PAGE_MAX_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT0_PAGE_COUNTER    0x1250
+#define    RTL8367C_FLOWCTRL_PORT0_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT0_PAGE_COUNTER_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT1_PAGE_COUNTER    0x1251
+#define    RTL8367C_FLOWCTRL_PORT1_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT1_PAGE_COUNTER_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT2_PAGE_COUNTER    0x1252
+#define    RTL8367C_FLOWCTRL_PORT2_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT2_PAGE_COUNTER_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT3_PAGE_COUNTER    0x1253
+#define    RTL8367C_FLOWCTRL_PORT3_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT3_PAGE_COUNTER_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT4_PAGE_COUNTER    0x1254
+#define    RTL8367C_FLOWCTRL_PORT4_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT4_PAGE_COUNTER_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT5_PAGE_COUNTER    0x1255
+#define    RTL8367C_FLOWCTRL_PORT5_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT5_PAGE_COUNTER_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT6_PAGE_COUNTER    0x1256
+#define    RTL8367C_FLOWCTRL_PORT6_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT6_PAGE_COUNTER_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT7_PAGE_COUNTER    0x1257
+#define    RTL8367C_FLOWCTRL_PORT7_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT7_PAGE_COUNTER_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PUBLIC_FCOFF_PAGE_COUNTER    0x1258
+#define    RTL8367C_FLOWCTRL_PUBLIC_FCOFF_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PUBLIC_FCOFF_PAGE_COUNTER_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PUBLIC_JUMBO_PAGE_COUNTER    0x1259
+#define    RTL8367C_FLOWCTRL_PUBLIC_JUMBO_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PUBLIC_JUMBO_PAGE_COUNTER_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_MAX_PUBLIC_FCOFF_PAGE_COUNTER    0x125a
+#define    RTL8367C_FLOWCTRL_MAX_PUBLIC_FCOFF_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_FLOWCTRL_MAX_PUBLIC_FCOFF_PAGE_COUNTER_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_MAX_PUBLIC_JUMBO_PAGE_COUNTER    0x125b
+#define    RTL8367C_FLOWCTRL_MAX_PUBLIC_JUMBO_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_FLOWCTRL_MAX_PUBLIC_JUMBO_PAGE_COUNTER_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT0_PAGE_MAX    0x1260
+#define    RTL8367C_FLOWCTRL_PORT0_PAGE_MAX_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT0_PAGE_MAX_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT1_PAGE_MAX    0x1261
+#define    RTL8367C_FLOWCTRL_PORT1_PAGE_MAX_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT1_PAGE_MAX_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT2_PAGE_MAX    0x1262
+#define    RTL8367C_FLOWCTRL_PORT2_PAGE_MAX_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT2_PAGE_MAX_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT3_PAGE_MAX    0x1263
+#define    RTL8367C_FLOWCTRL_PORT3_PAGE_MAX_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT3_PAGE_MAX_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT4_PAGE_MAX    0x1264
+#define    RTL8367C_FLOWCTRL_PORT4_PAGE_MAX_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT4_PAGE_MAX_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT5_PAGE_MAX    0x1265
+#define    RTL8367C_FLOWCTRL_PORT5_PAGE_MAX_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT5_PAGE_MAX_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT6_PAGE_MAX    0x1266
+#define    RTL8367C_FLOWCTRL_PORT6_PAGE_MAX_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT6_PAGE_MAX_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT7_PAGE_MAX    0x1267
+#define    RTL8367C_FLOWCTRL_PORT7_PAGE_MAX_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT7_PAGE_MAX_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PAGE_COUNT_CLEAR    0x1268
+#define    RTL8367C_DIS_SKIP_FP_OFFSET    1
+#define    RTL8367C_DIS_SKIP_FP_MASK    0x2
+#define    RTL8367C_PAGE_COUNT_CLEAR_OFFSET    0
+#define    RTL8367C_PAGE_COUNT_CLEAR_MASK    0x1
+
+#define    RTL8367C_REG_FLOWCTRL_PORT8_PAGE_MAX    0x1269
+#define    RTL8367C_FLOWCTRL_PORT8_PAGE_MAX_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT8_PAGE_MAX_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT9_PAGE_MAX    0x126a
+#define    RTL8367C_FLOWCTRL_PORT9_PAGE_MAX_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT9_PAGE_MAX_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT10_PAGE_MAX    0x126b
+#define    RTL8367C_FLOWCTRL_PORT10_PAGE_MAX_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT10_PAGE_MAX_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT8_PAGE_COUNTER    0x126c
+#define    RTL8367C_FLOWCTRL_PORT8_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT8_PAGE_COUNTER_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT9_PAGE_COUNTER    0x126d
+#define    RTL8367C_FLOWCTRL_PORT9_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT9_PAGE_COUNTER_MASK    0x7FF
+
+#define    RTL8367C_REG_FLOWCTRL_PORT10_PAGE_COUNTER    0x126e
+#define    RTL8367C_FLOWCTRL_PORT10_PAGE_COUNTER_OFFSET    0
+#define    RTL8367C_FLOWCTRL_PORT10_PAGE_COUNTER_MASK    0x7FF
+
+#define    RTL8367C_REG_RRCP_CTRL1_H    0x126f
+#define    RTL8367C_RRCP_ADMIN_PMSK_P10_8_OFFSET    3
+#define    RTL8367C_RRCP_ADMIN_PMSK_P10_8_MASK    0x38
+#define    RTL8367C_RRCP_AUTH_PMSK_P10_8_OFFSET    0
+#define    RTL8367C_RRCP_AUTH_PMSK_P10_8_MASK    0x7
+
+#define    RTL8367C_REG_EMA_CTRL0    0x1270
+#define    RTL8367C_CFG_DVSE_VIAROM_OFFSET    13
+#define    RTL8367C_CFG_DVSE_VIAROM_MASK    0x2000
+#define    RTL8367C_CFG_DVSE_MIBRAM_OFFSET    12
+#define    RTL8367C_CFG_DVSE_MIBRAM_MASK    0x1000
+#define    RTL8367C_CFG_DVSE_IROM_OFFSET    11
+#define    RTL8367C_CFG_DVSE_IROM_MASK    0x800
+#define    RTL8367C_CFG_DVSE_ERAM_OFFSET    10
+#define    RTL8367C_CFG_DVSE_ERAM_MASK    0x400
+#define    RTL8367C_CFG_DVSE_IRAM_OFFSET    9
+#define    RTL8367C_CFG_DVSE_IRAM_MASK    0x200
+#define    RTL8367C_CFG_DVSE_NICRAM_OFFSET    8
+#define    RTL8367C_CFG_DVSE_NICRAM_MASK    0x100
+#define    RTL8367C_CFG_DVSE_CVLANRAM_OFFSET    7
+#define    RTL8367C_CFG_DVSE_CVLANRAM_MASK    0x80
+#define    RTL8367C_CFG_DVSE_ACTRAM_OFFSET    6
+#define    RTL8367C_CFG_DVSE_ACTRAM_MASK    0x40
+#define    RTL8367C_CFG_DVSE_INQRAM_OFFSET    5
+#define    RTL8367C_CFG_DVSE_INQRAM_MASK    0x20
+#define    RTL8367C_CFG_DVSE_HSARAM_OFFSET    4
+#define    RTL8367C_CFG_DVSE_HSARAM_MASK    0x10
+#define    RTL8367C_CFG_DVSE_OUTQRAM_OFFSET    3
+#define    RTL8367C_CFG_DVSE_OUTQRAM_MASK    0x8
+#define    RTL8367C_CFG_DVSE_HTRAM_OFFSET    2
+#define    RTL8367C_CFG_DVSE_HTRAM_MASK    0x4
+#define    RTL8367C_CFG_DVSE_PBRAM_OFFSET    1
+#define    RTL8367C_CFG_DVSE_PBRAM_MASK    0x2
+#define    RTL8367C_CFG_DVSE_L2RAM_OFFSET    0
+#define    RTL8367C_CFG_DVSE_L2RAM_MASK    0x1
+
+#define    RTL8367C_REG_EMA_CTRL1    0x1271
+#define    RTL8367C_CFG_DVS_OUTQRAM_OFFSET    12
+#define    RTL8367C_CFG_DVS_OUTQRAM_MASK    0xF000
+#define    RTL8367C_CFG_DVS_HTRAM_OFFSET    8
+#define    RTL8367C_CFG_DVS_HTRAM_MASK    0x700
+#define    RTL8367C_CFG_DVS_PBRAM_OFFSET    4
+#define    RTL8367C_CFG_DVS_PBRAM_MASK    0xF0
+#define    RTL8367C_CFG_DVS_L2RAM_OFFSET    0
+#define    RTL8367C_CFG_DVS_L2RAM_MASK    0xF
+
+#define    RTL8367C_REG_EMA_CTRL2    0x1272
+#define    RTL8367C_CFG_DVS_CVLANRAM_OFFSET    12
+#define    RTL8367C_CFG_DVS_CVLANRAM_MASK    0xF000
+#define    RTL8367C_CFG_DVS_ACTRAM_OFFSET    8
+#define    RTL8367C_CFG_DVS_ACTRAM_MASK    0xF00
+#define    RTL8367C_CFG_DVS_INQRAM_OFFSET    4
+#define    RTL8367C_CFG_DVS_INQRAM_MASK    0xF0
+#define    RTL8367C_CFG_DVS_HSARAM_OFFSET    0
+#define    RTL8367C_CFG_DVS_HSARAM_MASK    0xF
+
+#define    RTL8367C_REG_EMA_CTRL3    0x1273
+#define    RTL8367C_CFG_DVS_IROM_OFFSET    12
+#define    RTL8367C_CFG_DVS_IROM_MASK    0xF000
+#define    RTL8367C_CFG_DVS_ERAM_OFFSET    8
+#define    RTL8367C_CFG_DVS_ERAM_MASK    0xF00
+#define    RTL8367C_CFG_DVS_IRAM_OFFSET    4
+#define    RTL8367C_CFG_DVS_IRAM_MASK    0xF0
+#define    RTL8367C_CFG_DVS_NICRAM_OFFSET    0
+#define    RTL8367C_CFG_DVS_NICRAM_MASK    0xF
+
+#define    RTL8367C_REG_EMA_CTRL4    0x1274
+#define    RTL8367C_CFG_DVS_VIAROM_OFFSET    4
+#define    RTL8367C_CFG_DVS_VIAROM_MASK    0xF0
+#define    RTL8367C_CFG_DVS_MIBRAM_OFFSET    0
+#define    RTL8367C_CFG_DVS_MIBRAM_MASK    0xF
+
+#define    RTL8367C_REG_DIAG_MODE    0x1275
+#define    RTL8367C_DIAG_MODE_OFFSET    0
+#define    RTL8367C_DIAG_MODE_MASK    0x1F
+
+#define    RTL8367C_REG_BIST_MODE    0x1276
+
+#define    RTL8367C_REG_STS_BIST_DONE    0x1277
+
+#define    RTL8367C_REG_STS_BIST_RLT0    0x1278
+#define    RTL8367C_STS_BIST_RLT0_OFFSET    0
+#define    RTL8367C_STS_BIST_RLT0_MASK    0x1
+
+#define    RTL8367C_REG_STS_BIST_RLT1    0x1279
+
+#define    RTL8367C_REG_STS_BIST_RLT2    0x127a
+
+#define    RTL8367C_REG_STS_BIST_RLT3    0x127b
+#define    RTL8367C_STS_BIST_RLT3_OFFSET    0
+#define    RTL8367C_STS_BIST_RLT3_MASK    0x3FF
+
+#define    RTL8367C_REG_STS_BIST_RLT4    0x127c
+#define    RTL8367C_STS_BIST_RLT4_OFFSET    0
+#define    RTL8367C_STS_BIST_RLT4_MASK    0x7
+
+#define    RTL8367C_REG_VIAROM_MISR    0x127d
+
+#define    RTL8367C_REG_DRF_BIST_MODE    0x1280
+#define    RTL8367C_DRF_TCAMDEL_OFFSET    15
+#define    RTL8367C_DRF_TCAMDEL_MASK    0x8000
+#define    RTL8367C_CFG_DRF_BIST_MODE_OFFSET    0
+#define    RTL8367C_CFG_DRF_BIST_MODE_MASK    0x7FFF
+
+#define    RTL8367C_REG_STS_DRF_BIST    0x1281
+#define    RTL8367C_STS_DRF_BIST_OFFSET    0
+#define    RTL8367C_STS_DRF_BIST_MASK    0x7FFF
+
+#define    RTL8367C_REG_STS_DRF_BIST_RLT0    0x1282
+#define    RTL8367C_STS_DRF_BIST_RLT0_OFFSET    0
+#define    RTL8367C_STS_DRF_BIST_RLT0_MASK    0x1
+
+#define    RTL8367C_REG_STS_DRF_BIST_RLT1    0x1283
+
+#define    RTL8367C_REG_STS_DRF_BIST_RLT2    0x1284
+
+#define    RTL8367C_REG_STS_DRF_BIST_RLT3    0x1285
+#define    RTL8367C_STS_DRF_BIST_RLT3_OFFSET    0
+#define    RTL8367C_STS_DRF_BIST_RLT3_MASK    0x3FF
+
+#define    RTL8367C_REG_STS_DRF_BIST_RLT4    0x1286
+#define    RTL8367C_STS_DRF_BIST_RLT4_OFFSET    0
+#define    RTL8367C_STS_DRF_BIST_RLT4_MASK    0x7FFF
+
+#define    RTL8367C_REG_RAM_DRF_CTRL    0x1289
+#define    RTL8367C_RAM_DRF_CTRL_OFFSET    0
+#define    RTL8367C_RAM_DRF_CTRL_MASK    0x1
+
+#define    RTL8367C_REG_MIB_RMON_LEN_CTRL    0x128a
+#define    RTL8367C_RX_LENGTH_CTRL_OFFSET    1
+#define    RTL8367C_RX_LENGTH_CTRL_MASK    0x2
+#define    RTL8367C_TX_LENGTH_CTRL_OFFSET    0
+#define    RTL8367C_TX_LENGTH_CTRL_MASK    0x1
+
+#define    RTL8367C_REG_COND0_BISR_OUT0    0x1290
+
+#define    RTL8367C_REG_COND0_BISR_OUT1    0x1291
+
+#define    RTL8367C_REG_COND0_BISR_OUT2    0x1292
+
+#define    RTL8367C_REG_COND0_BISR_OUT3    0x1293
+
+#define    RTL8367C_REG_COND0_BISR_OUT4    0x1294
+#define    RTL8367C_COND0_BISR_OUT4_OFFSET    0
+#define    RTL8367C_COND0_BISR_OUT4_MASK    0x3F
+
+#define    RTL8367C_REG_COND0_BISR_OUT5    0x1295
+#define    RTL8367C_COND0_BISR_OUT5_OFFSET    0
+#define    RTL8367C_COND0_BISR_OUT5_MASK    0x7
+
+#define    RTL8367C_REG_CHG_DUPLEX_CFG    0x1296
+#define    RTL8367C_CHG_COL_CNT_PORT_OFFSET    13
+#define    RTL8367C_CHG_COL_CNT_PORT_MASK    0xE000
+#define    RTL8367C_CHG_COL_CNT_OFFSET    8
+#define    RTL8367C_CHG_COL_CNT_MASK    0x1F00
+#define    RTL8367C_CFG_CHG_DUP_EN_OFFSET    7
+#define    RTL8367C_CFG_CHG_DUP_EN_MASK    0x80
+#define    RTL8367C_CFG_CHG_DUP_THR_OFFSET    2
+#define    RTL8367C_CFG_CHG_DUP_THR_MASK    0x7C
+#define    RTL8367C_CFG_CHG_DUP_CONGEST_OFFSET    1
+#define    RTL8367C_CFG_CHG_DUP_CONGEST_MASK    0x2
+#define    RTL8367C_CFG_CHG_DUP_REF_OFFSET    0
+#define    RTL8367C_CFG_CHG_DUP_REF_MASK    0x1
+
+#define    RTL8367C_REG_COND0_BIST_PASS    0x1297
+#define    RTL8367C_COND0_DRF_BIST_NOFAIL_OFFSET    1
+#define    RTL8367C_COND0_DRF_BIST_NOFAIL_MASK    0x2
+#define    RTL8367C_COND0_BIST_NOFAIL_OFFSET    0
+#define    RTL8367C_COND0_BIST_NOFAIL_MASK    0x1
+
+#define    RTL8367C_REG_COND1_BISR_OUT0    0x1298
+
+#define    RTL8367C_REG_COND1_BISR_OUT1    0x1299
+
+#define    RTL8367C_REG_COND1_BISR_OUT2    0x129a
+
+#define    RTL8367C_REG_COND1_BISR_OUT3    0x129b
+
+#define    RTL8367C_REG_COND1_BISR_OUT4    0x129c
+#define    RTL8367C_COND1_BISR_OUT4_OFFSET    0
+#define    RTL8367C_COND1_BISR_OUT4_MASK    0x3F
+
+#define    RTL8367C_REG_COND1_BISR_OUT5    0x129d
+#define    RTL8367C_COND1_BISR_OUT5_OFFSET    0
+#define    RTL8367C_COND1_BISR_OUT5_MASK    0x7
+
+#define    RTL8367C_REG_COND1_BIST_PASS    0x129f
+#define    RTL8367C_COND1_DRF_BIST_NOFAIL_OFFSET    1
+#define    RTL8367C_COND1_DRF_BIST_NOFAIL_MASK    0x2
+#define    RTL8367C_COND1_BIST_NOFAIL_OFFSET    0
+#define    RTL8367C_COND1_BIST_NOFAIL_MASK    0x1
+
+#define    RTL8367C_REG_EEE_TX_THR_Giga_500M    0x12a0
+
+#define    RTL8367C_REG_EEE_TX_THR_FE    0x12a1
+
+#define    RTL8367C_REG_EEE_MISC    0x12a3
+#define    RTL8367C_EEE_REQ_SET1_OFFSET    13
+#define    RTL8367C_EEE_REQ_SET1_MASK    0x2000
+#define    RTL8367C_EEE_REQ_SET0_OFFSET    12
+#define    RTL8367C_EEE_REQ_SET0_MASK    0x1000
+#define    RTL8367C_EEE_WAKE_SET1_OFFSET    9
+#define    RTL8367C_EEE_WAKE_SET1_MASK    0x200
+#define    RTL8367C_EEE_Wake_SET0_OFFSET    8
+#define    RTL8367C_EEE_Wake_SET0_MASK    0x100
+#define    RTL8367C_EEE_TU_GIGA_500M_OFFSET    4
+#define    RTL8367C_EEE_TU_GIGA_500M_MASK    0x30
+#define    RTL8367C_EEE_TU_100M_OFFSET    2
+#define    RTL8367C_EEE_TU_100M_MASK    0xC
+
+#define    RTL8367C_REG_EEE_GIGA_CTRL0    0x12a4
+#define    RTL8367C_EEE_TW_GIGA_OFFSET    8
+#define    RTL8367C_EEE_TW_GIGA_MASK    0xFF00
+#define    RTL8367C_EEE_TR_GIGA_500M_OFFSET    0
+#define    RTL8367C_EEE_TR_GIGA_500M_MASK    0xFF
+
+#define    RTL8367C_REG_EEE_GIGA_CTRL1    0x12a5
+#define    RTL8367C_EEE_TD_GIGA_500M_OFFSET    8
+#define    RTL8367C_EEE_TD_GIGA_500M_MASK    0xFF00
+#define    RTL8367C_EEE_TP_GIGA_OFFSET    0
+#define    RTL8367C_EEE_TP_GIGA_MASK    0xFF
+
+#define    RTL8367C_REG_EEE_100M_CTRL0    0x12a6
+#define    RTL8367C_EEE_TW_100M_OFFSET    8
+#define    RTL8367C_EEE_TW_100M_MASK    0xFF00
+#define    RTL8367C_EEE_TR_100M_OFFSET    0
+#define    RTL8367C_EEE_TR_100M_MASK    0xFF
+
+#define    RTL8367C_REG_EEE_100M_CTRL1    0x12a7
+#define    RTL8367C_EEE_TD_100M_OFFSET    8
+#define    RTL8367C_EEE_TD_100M_MASK    0xFF00
+#define    RTL8367C_EEE_TP_100M_OFFSET    0
+#define    RTL8367C_EEE_TP_100M_MASK    0xFF
+
+#define    RTL8367C_REG_RX_FC_REG    0x12aa
+#define    RTL8367C_EN_EEE_HALF_DUP_OFFSET    8
+#define    RTL8367C_EN_EEE_HALF_DUP_MASK    0x100
+#define    RTL8367C_RX_PGCNT_OFFSET    0
+#define    RTL8367C_RX_PGCNT_MASK    0xFF
+
+#define    RTL8367C_REG_MAX_FIFO_SIZE    0x12af
+#define    RTL8367C_MAX_FIFO_SIZE_OFFSET    0
+#define    RTL8367C_MAX_FIFO_SIZE_MASK    0xF
+
+#define    RTL8367C_REG_EEEP_RX_RATE_GIGA    0x12b0
+
+#define    RTL8367C_REG_EEEP_RX_RATE_100M    0x12b1
+
+#define    RTL8367C_REG_DUMMY_REG_12_2    0x12b2
+
+#define    RTL8367C_REG_EEEP_TX_RATE_GIGA    0x12b3
+
+#define    RTL8367C_REG_EEEP_TX_RATE_100M    0x12b4
+
+#define    RTL8367C_REG_DUMMY_REG_12_3    0x12b5
+
+#define    RTL8367C_REG_EEEP_GIGA_CTRL0    0x12b6
+#define    RTL8367C_EEEP_TR_GIGA_OFFSET    8
+#define    RTL8367C_EEEP_TR_GIGA_MASK    0xFF00
+#define    RTL8367C_EEEP_RW_GIGA_MST_OFFSET    0
+#define    RTL8367C_EEEP_RW_GIGA_MST_MASK    0xFF
+
+#define    RTL8367C_REG_EEEP_GIGA_CTRL1    0x12b7
+#define    RTL8367C_EEEP_TW_GIGA_OFFSET    8
+#define    RTL8367C_EEEP_TW_GIGA_MASK    0xFF00
+#define    RTL8367C_EEEP_TP_GIGA_OFFSET    0
+#define    RTL8367C_EEEP_TP_GIGA_MASK    0xFF
+
+#define    RTL8367C_REG_EEEP_GIGA_CTRL2    0x12b8
+#define    RTL8367C_EEEP_TXEN_GIGA_OFFSET    12
+#define    RTL8367C_EEEP_TXEN_GIGA_MASK    0x1000
+#define    RTL8367C_EEEP_TU_GIGA_OFFSET    8
+#define    RTL8367C_EEEP_TU_GIGA_MASK    0x300
+#define    RTL8367C_EEEP_TS_GIGA_OFFSET    0
+#define    RTL8367C_EEEP_TS_GIGA_MASK    0xFF
+
+#define    RTL8367C_REG_EEEP_100M_CTRL0    0x12b9
+#define    RTL8367C_EEEP_TR_100M_OFFSET    8
+#define    RTL8367C_EEEP_TR_100M_MASK    0xFF00
+#define    RTL8367C_EEEP_RW_100M_OFFSET    0
+#define    RTL8367C_EEEP_RW_100M_MASK    0xFF
+
+#define    RTL8367C_REG_EEEP_100M_CTRL1    0x12ba
+#define    RTL8367C_EEEP_TW_100M_OFFSET    8
+#define    RTL8367C_EEEP_TW_100M_MASK    0xFF00
+#define    RTL8367C_EEEP_TP_100M_OFFSET    0
+#define    RTL8367C_EEEP_TP_100M_MASK    0xFF
+
+#define    RTL8367C_REG_EEEP_100M_CTRL2    0x12bb
+#define    RTL8367C_EEEP_TXEN_100M_OFFSET    12
+#define    RTL8367C_EEEP_TXEN_100M_MASK    0x1000
+#define    RTL8367C_EEEP_TU_100M_OFFSET    8
+#define    RTL8367C_EEEP_TU_100M_MASK    0x300
+#define    RTL8367C_EEEP_TS_100M_OFFSET    0
+#define    RTL8367C_EEEP_TS_100M_MASK    0xFF
+
+#define    RTL8367C_REG_EEEP_CTRL0    0x12bc
+#define    RTL8367C_EEEP_CTRL0_DUMMY_OFFSET    8
+#define    RTL8367C_EEEP_CTRL0_DUMMY_MASK    0xFF00
+#define    RTL8367C_EEEP_SLEEP_STEP_OFFSET    0
+#define    RTL8367C_EEEP_SLEEP_STEP_MASK    0xFF
+
+#define    RTL8367C_REG_EEEP_CTRL1    0x12bd
+#define    RTL8367C_EEEP_TXR_GIGA_OFFSET    8
+#define    RTL8367C_EEEP_TXR_GIGA_MASK    0xFF00
+#define    RTL8367C_EEEP_TXR_100M_OFFSET    0
+#define    RTL8367C_EEEP_TXR_100M_MASK    0xFF
+
+#define    RTL8367C_REG_BACK_PRESSURE_IPG    0x12be
+#define    RTL8367C_BACK_PRESSURE_IPG_OFFSET    0
+#define    RTL8367C_BACK_PRESSURE_IPG_MASK    0x3
+
+#define    RTL8367C_REG_TX_ESD_LEVEL    0x12bf
+#define    RTL8367C_TX_ESD_LEVEL_MODE_OFFSET    8
+#define    RTL8367C_TX_ESD_LEVEL_MODE_MASK    0x100
+#define    RTL8367C_LEVEL_OFFSET    0
+#define    RTL8367C_LEVEL_MASK    0xFF
+
+#define    RTL8367C_REG_RRCP_CTRL4    0x12e0
+
+#define    RTL8367C_REG_RRCP_CTRL5    0x12e1
+
+#define    RTL8367C_REG_RRCP_CTRL6    0x12e2
+
+#define    RTL8367C_REG_RRCP_CTRL7    0x12e3
+
+#define    RTL8367C_REG_RRCP_CTRL8    0x12e4
+
+#define    RTL8367C_REG_RRCP_CTRL9    0x12e5
+
+#define    RTL8367C_REG_RRCP_CTRL10    0x12e6
+
+#define    RTL8367C_REG_FIELD_SELECTOR0    0x12e7
+#define    RTL8367C_FIELD_SELECTOR0_FORMAT_OFFSET    8
+#define    RTL8367C_FIELD_SELECTOR0_FORMAT_MASK    0x700
+#define    RTL8367C_FIELD_SELECTOR0_OFFSET_OFFSET    0
+#define    RTL8367C_FIELD_SELECTOR0_OFFSET_MASK    0xFF
+
+#define    RTL8367C_REG_FIELD_SELECTOR1    0x12e8
+#define    RTL8367C_FIELD_SELECTOR1_FORMAT_OFFSET    8
+#define    RTL8367C_FIELD_SELECTOR1_FORMAT_MASK    0x700
+#define    RTL8367C_FIELD_SELECTOR1_OFFSET_OFFSET    0
+#define    RTL8367C_FIELD_SELECTOR1_OFFSET_MASK    0xFF
+
+#define    RTL8367C_REG_FIELD_SELECTOR2    0x12e9
+#define    RTL8367C_FIELD_SELECTOR2_FORMAT_OFFSET    8
+#define    RTL8367C_FIELD_SELECTOR2_FORMAT_MASK    0x700
+#define    RTL8367C_FIELD_SELECTOR2_OFFSET_OFFSET    0
+#define    RTL8367C_FIELD_SELECTOR2_OFFSET_MASK    0xFF
+
+#define    RTL8367C_REG_FIELD_SELECTOR3    0x12ea
+#define    RTL8367C_FIELD_SELECTOR3_FORMAT_OFFSET    8
+#define    RTL8367C_FIELD_SELECTOR3_FORMAT_MASK    0x700
+#define    RTL8367C_FIELD_SELECTOR3_OFFSET_OFFSET    0
+#define    RTL8367C_FIELD_SELECTOR3_OFFSET_MASK    0xFF
+
+#define    RTL8367C_REG_FIELD_SELECTOR4    0x12eb
+#define    RTL8367C_FIELD_SELECTOR4_FORMAT_OFFSET    8
+#define    RTL8367C_FIELD_SELECTOR4_FORMAT_MASK    0x700
+#define    RTL8367C_FIELD_SELECTOR4_OFFSET_OFFSET    0
+#define    RTL8367C_FIELD_SELECTOR4_OFFSET_MASK    0xFF
+
+#define    RTL8367C_REG_FIELD_SELECTOR5    0x12ec
+#define    RTL8367C_FIELD_SELECTOR5_FORMAT_OFFSET    8
+#define    RTL8367C_FIELD_SELECTOR5_FORMAT_MASK    0x700
+#define    RTL8367C_FIELD_SELECTOR5_OFFSET_OFFSET    0
+#define    RTL8367C_FIELD_SELECTOR5_OFFSET_MASK    0xFF
+
+#define    RTL8367C_REG_FIELD_SELECTOR6    0x12ed
+#define    RTL8367C_FIELD_SELECTOR6_FORMAT_OFFSET    8
+#define    RTL8367C_FIELD_SELECTOR6_FORMAT_MASK    0x700
+#define    RTL8367C_FIELD_SELECTOR6_OFFSET_OFFSET    0
+#define    RTL8367C_FIELD_SELECTOR6_OFFSET_MASK    0xFF
+
+#define    RTL8367C_REG_FIELD_SELECTOR7    0x12ee
+#define    RTL8367C_FIELD_SELECTOR7_FORMAT_OFFSET    8
+#define    RTL8367C_FIELD_SELECTOR7_FORMAT_MASK    0x700
+#define    RTL8367C_FIELD_SELECTOR7_OFFSET_OFFSET    0
+#define    RTL8367C_FIELD_SELECTOR7_OFFSET_MASK    0xFF
+
+#define    RTL8367C_REG_FIELD_SELECTOR8    0x12ef
+#define    RTL8367C_FIELD_SELECTOR8_FORMAT_OFFSET    8
+#define    RTL8367C_FIELD_SELECTOR8_FORMAT_MASK    0x700
+#define    RTL8367C_FIELD_SELECTOR8_OFFSET_OFFSET    0
+#define    RTL8367C_FIELD_SELECTOR8_OFFSET_MASK    0xFF
+
+#define    RTL8367C_REG_FIELD_SELECTOR9    0x12f0
+#define    RTL8367C_FIELD_SELECTOR9_FORMAT_OFFSET    8
+#define    RTL8367C_FIELD_SELECTOR9_FORMAT_MASK    0x700
+#define    RTL8367C_FIELD_SELECTOR9_OFFSET_OFFSET    0
+#define    RTL8367C_FIELD_SELECTOR9_OFFSET_MASK    0xFF
+
+#define    RTL8367C_REG_FIELD_SELECTOR10    0x12f1
+#define    RTL8367C_FIELD_SELECTOR10_FORMAT_OFFSET    8
+#define    RTL8367C_FIELD_SELECTOR10_FORMAT_MASK    0x700
+#define    RTL8367C_FIELD_SELECTOR10_OFFSET_OFFSET    0
+#define    RTL8367C_FIELD_SELECTOR10_OFFSET_MASK    0xFF
+
+#define    RTL8367C_REG_FIELD_SELECTOR11    0x12f2
+#define    RTL8367C_FIELD_SELECTOR11_FORMAT_OFFSET    8
+#define    RTL8367C_FIELD_SELECTOR11_FORMAT_MASK    0x700
+#define    RTL8367C_FIELD_SELECTOR11_OFFSET_OFFSET    0
+#define    RTL8367C_FIELD_SELECTOR11_OFFSET_MASK    0xFF
+
+#define    RTL8367C_REG_FIELD_SELECTOR12    0x12f3
+#define    RTL8367C_FIELD_SELECTOR12_FORMAT_OFFSET    8
+#define    RTL8367C_FIELD_SELECTOR12_FORMAT_MASK    0x700
+#define    RTL8367C_FIELD_SELECTOR12_OFFSET_OFFSET    0
+#define    RTL8367C_FIELD_SELECTOR12_OFFSET_MASK    0xFF
+
+#define    RTL8367C_REG_FIELD_SELECTOR13    0x12f4
+#define    RTL8367C_FIELD_SELECTOR13_FORMAT_OFFSET    8
+#define    RTL8367C_FIELD_SELECTOR13_FORMAT_MASK    0x700
+#define    RTL8367C_FIELD_SELECTOR13_OFFSET_OFFSET    0
+#define    RTL8367C_FIELD_SELECTOR13_OFFSET_MASK    0xFF
+
+#define    RTL8367C_REG_FIELD_SELECTOR14    0x12f5
+#define    RTL8367C_FIELD_SELECTOR14_FORMAT_OFFSET    8
+#define    RTL8367C_FIELD_SELECTOR14_FORMAT_MASK    0x700
+#define    RTL8367C_FIELD_SELECTOR14_OFFSET_OFFSET    0
+#define    RTL8367C_FIELD_SELECTOR14_OFFSET_MASK    0xFF
+
+#define    RTL8367C_REG_FIELD_SELECTOR15    0x12f6
+#define    RTL8367C_FIELD_SELECTOR15_FORMAT_OFFSET    8
+#define    RTL8367C_FIELD_SELECTOR15_FORMAT_MASK    0x700
+#define    RTL8367C_FIELD_SELECTOR15_OFFSET_OFFSET    0
+#define    RTL8367C_FIELD_SELECTOR15_OFFSET_MASK    0xFF
+
+#define    RTL8367C_REG_HWPKT_GEN_MISC_H    0x12f7
+#define    RTL8367C_PKT_GEN_SUSPEND_P10_8_OFFSET    3
+#define    RTL8367C_PKT_GEN_SUSPEND_P10_8_MASK    0x38
+#define    RTL8367C_PKT_GEN_STATUS_P10_8_OFFSET    0
+#define    RTL8367C_PKT_GEN_STATUS_P10_8_MASK    0x7
+
+#define    RTL8367C_REG_MIRROR_SRC_PMSK    0x12fb
+#define    RTL8367C_MIRROR_SRC_PMSK_OFFSET    0
+#define    RTL8367C_MIRROR_SRC_PMSK_MASK    0x7FF
+
+#define    RTL8367C_REG_EEE_BURSTSIZE    0x12fc
+
+#define    RTL8367C_REG_EEE_IFG_CFG    0x12fd
+#define    RTL8367C_EEE_IFG_CFG_OFFSET    0
+#define    RTL8367C_EEE_IFG_CFG_MASK    0x1
+
+#define    RTL8367C_REG_FPGA_VER_MAC    0x12fe
+
+#define    RTL8367C_REG_HWPKT_GEN_MISC    0x12ff
+#define    RTL8367C_PKT_GEN_SUSPEND_OFFSET    8
+#define    RTL8367C_PKT_GEN_SUSPEND_MASK    0xFF00
+#define    RTL8367C_PKT_GEN_STATUS_OFFSET    0
+#define    RTL8367C_PKT_GEN_STATUS_MASK    0xFF
+
+/* (16'h1300)chip_reg */
+
+#define    RTL8367C_REG_CHIP_NUMBER    0x1300
+
+#define    RTL8367C_REG_CHIP_VER    0x1301
+#define    RTL8367C_VERID_OFFSET    12
+#define    RTL8367C_VERID_MASK    0xF000
+#define    RTL8367C_MCID_OFFSET    8
+#define    RTL8367C_MCID_MASK    0xF00
+#define    RTL8367C_MODEL_ID_OFFSET    4
+#define    RTL8367C_MODEL_ID_MASK    0xF0
+#define    RTL8367C_AFE_VERSION_OFFSET    0
+#define    RTL8367C_AFE_VERSION_MASK    0x1
+
+#define    RTL8367C_REG_CHIP_DEBUG0    0x1303
+#define    RTL8367C_SEL33_EXT2_OFFSET    10
+#define    RTL8367C_SEL33_EXT2_MASK    0x400
+#define    RTL8367C_SEL33_EXT1_OFFSET    9
+#define    RTL8367C_SEL33_EXT1_MASK    0x200
+#define    RTL8367C_SEL33_EXT0_OFFSET    8
+#define    RTL8367C_SEL33_EXT0_MASK    0x100
+#define    RTL8367C_DRI_OTHER_OFFSET    7
+#define    RTL8367C_DRI_OTHER_MASK    0x80
+#define    RTL8367C_DRI_EXT1_RG_OFFSET    6
+#define    RTL8367C_DRI_EXT1_RG_MASK    0x40
+#define    RTL8367C_DRI_EXT0_RG_OFFSET    5
+#define    RTL8367C_DRI_EXT0_RG_MASK    0x20
+#define    RTL8367C_DRI_EXT1_OFFSET    4
+#define    RTL8367C_DRI_EXT1_MASK    0x10
+#define    RTL8367C_DRI_EXT0_OFFSET    3
+#define    RTL8367C_DRI_EXT0_MASK    0x8
+#define    RTL8367C_SLR_OTHER_OFFSET    2
+#define    RTL8367C_SLR_OTHER_MASK    0x4
+#define    RTL8367C_SLR_EXT1_OFFSET    1
+#define    RTL8367C_SLR_EXT1_MASK    0x2
+#define    RTL8367C_SLR_EXT0_OFFSET    0
+#define    RTL8367C_SLR_EXT0_MASK    0x1
+
+#define    RTL8367C_REG_CHIP_DEBUG1    0x1304
+#define    RTL8367C_RG1_DN_OFFSET    12
+#define    RTL8367C_RG1_DN_MASK    0x7000
+#define    RTL8367C_RG1_DP_OFFSET    8
+#define    RTL8367C_RG1_DP_MASK    0x700
+#define    RTL8367C_RG0_DN_OFFSET    4
+#define    RTL8367C_RG0_DN_MASK    0x70
+#define    RTL8367C_RG0_DP_OFFSET    0
+#define    RTL8367C_RG0_DP_MASK    0x7
+
+#define    RTL8367C_REG_DIGITAL_INTERFACE_SELECT    0x1305
+#define    RTL8367C_ORG_COL_OFFSET    15
+#define    RTL8367C_ORG_COL_MASK    0x8000
+#define    RTL8367C_ORG_CRS_OFFSET    14
+#define    RTL8367C_ORG_CRS_MASK    0x4000
+#define    RTL8367C_SKIP_MII_1_RXER_OFFSET    13
+#define    RTL8367C_SKIP_MII_1_RXER_MASK    0x2000
+#define    RTL8367C_SKIP_MII_0_RXER_OFFSET    12
+#define    RTL8367C_SKIP_MII_0_RXER_MASK    0x1000
+#define    RTL8367C_SELECT_GMII_1_OFFSET    4
+#define    RTL8367C_SELECT_GMII_1_MASK    0xF0
+#define    RTL8367C_SELECT_GMII_0_OFFSET    0
+#define    RTL8367C_SELECT_GMII_0_MASK    0xF
+
+#define    RTL8367C_REG_EXT0_RGMXF    0x1306
+#define    RTL8367C_EXT0_RGTX_INV_OFFSET    6
+#define    RTL8367C_EXT0_RGTX_INV_MASK    0x40
+#define    RTL8367C_EXT0_RGRX_INV_OFFSET    5
+#define    RTL8367C_EXT0_RGRX_INV_MASK    0x20
+#define    RTL8367C_EXT0_RGMXF_OFFSET    0
+#define    RTL8367C_EXT0_RGMXF_MASK    0x1F
+
+#define    RTL8367C_REG_EXT1_RGMXF    0x1307
+#define    RTL8367C_EXT1_RGTX_INV_OFFSET    6
+#define    RTL8367C_EXT1_RGTX_INV_MASK    0x40
+#define    RTL8367C_EXT1_RGRX_INV_OFFSET    5
+#define    RTL8367C_EXT1_RGRX_INV_MASK    0x20
+#define    RTL8367C_EXT1_RGMXF_OFFSET    0
+#define    RTL8367C_EXT1_RGMXF_MASK    0x1F
+
+#define    RTL8367C_REG_BISR_CTRL    0x1308
+#define    RTL8367C_BISR_CTRL_OFFSET    0
+#define    RTL8367C_BISR_CTRL_MASK    0x7
+
+#define    RTL8367C_REG_SLF_IF    0x1309
+#define    RTL8367C_LINK_DOWN_CLR_FIFO_OFFSET    7
+#define    RTL8367C_LINK_DOWN_CLR_FIFO_MASK    0x80
+#define    RTL8367C_LOOPBACK_OFFSET    6
+#define    RTL8367C_LOOPBACK_MASK    0x40
+#define    RTL8367C_WATER_LEVEL_OFFSET    4
+#define    RTL8367C_WATER_LEVEL_MASK    0x30
+#define    RTL8367C_SLF_IF_OFFSET    0
+#define    RTL8367C_SLF_IF_MASK    0x3
+
+#define    RTL8367C_REG_I2C_CLOCK_DIV    0x130a
+#define    RTL8367C_I2C_CLOCK_DIV_OFFSET    0
+#define    RTL8367C_I2C_CLOCK_DIV_MASK    0x3FF
+
+#define    RTL8367C_REG_MDX_MDC_DIV    0x130b
+#define    RTL8367C_MDX_MDC_DIV_OFFSET    0
+#define    RTL8367C_MDX_MDC_DIV_MASK    0x3FF
+
+#define    RTL8367C_REG_MISCELLANEOUS_CONFIGURE0    0x130c
+#define    RTL8367C_ADCCKI_FROM_PAD_OFFSET    14
+#define    RTL8367C_ADCCKI_FROM_PAD_MASK    0x4000
+#define    RTL8367C_ADCCKI_EN_OFFSET    13
+#define    RTL8367C_ADCCKI_EN_MASK    0x2000
+#define    RTL8367C_FLASH_ENABLE_OFFSET    12
+#define    RTL8367C_FLASH_ENABLE_MASK    0x1000
+#define    RTL8367C_EEE_ENABLE_OFFSET    11
+#define    RTL8367C_EEE_ENABLE_MASK    0x800
+#define    RTL8367C_NIC_ENABLE_OFFSET    10
+#define    RTL8367C_NIC_ENABLE_MASK    0x400
+#define    RTL8367C_FT_ENABLE_OFFSET    9
+#define    RTL8367C_FT_ENABLE_MASK    0x200
+#define    RTL8367C_OLT_ENABLE_OFFSET    8
+#define    RTL8367C_OLT_ENABLE_MASK    0x100
+#define    RTL8367C_RTCT_EN_OFFSET    7
+#define    RTL8367C_RTCT_EN_MASK    0x80
+#define    RTL8367C_PON_LIGHT_EN_OFFSET    6
+#define    RTL8367C_PON_LIGHT_EN_MASK    0x40
+#define    RTL8367C_DW8051_EN_OFFSET    5
+#define    RTL8367C_DW8051_EN_MASK    0x20
+#define    RTL8367C_AUTOLOAD_EN_OFFSET    4
+#define    RTL8367C_AUTOLOAD_EN_MASK    0x10
+#define    RTL8367C_NRESTORE_EN_OFFSET    3
+#define    RTL8367C_NRESTORE_EN_MASK    0x8
+#define    RTL8367C_DIS_PON_TABLE_INIT_OFFSET    2
+#define    RTL8367C_DIS_PON_TABLE_INIT_MASK    0x4
+#define    RTL8367C_DIS_PON_BIST_OFFSET    1
+#define    RTL8367C_DIS_PON_BIST_MASK    0x2
+#define    RTL8367C_EFUSE_EN_OFFSET    0
+#define    RTL8367C_EFUSE_EN_MASK    0x1
+
+#define    RTL8367C_REG_MISCELLANEOUS_CONFIGURE1    0x130d
+#define    RTL8367C_EEPROM_DEV_ADR_OFFSET    8
+#define    RTL8367C_EEPROM_DEV_ADR_MASK    0x7F00
+#define    RTL8367C_EEPROM_MSB_OFFSET    7
+#define    RTL8367C_EEPROM_MSB_MASK    0x80
+#define    RTL8367C_EEPROM_ADDRESS_16B_OFFSET    6
+#define    RTL8367C_EEPROM_ADDRESS_16B_MASK    0x40
+#define    RTL8367C_EEPROM_DWONLOAD_COMPLETE_OFFSET    3
+#define    RTL8367C_EEPROM_DWONLOAD_COMPLETE_MASK    0x8
+#define    RTL8367C_SPI_SLAVE_EN_OFFSET    2
+#define    RTL8367C_SPI_SLAVE_EN_MASK    0x4
+#define    RTL8367C_SMI_SEL_OFFSET    0
+#define    RTL8367C_SMI_SEL_MASK    0x3
+
+#define    RTL8367C_REG_PHY_AD    0x130f
+#define    RTL8367C_EN_PHY_MAX_POWER_OFFSET    14
+#define    RTL8367C_EN_PHY_MAX_POWER_MASK    0x4000
+#define    RTL8367C_EN_PHY_SEL_DEG_OFFSET    13
+#define    RTL8367C_EN_PHY_SEL_DEG_MASK    0x2000
+#define    RTL8367C_EXTPHY_AD_OFFSET    8
+#define    RTL8367C_EXTPHY_AD_MASK    0x1F00
+#define    RTL8367C_EN_PHY_LOW_POWER_MODE_OFFSET    7
+#define    RTL8367C_EN_PHY_LOW_POWER_MODE_MASK    0x80
+#define    RTL8367C_EN_PHY_GREEN_OFFSET    6
+#define    RTL8367C_EN_PHY_GREEN_MASK    0x40
+#define    RTL8367C_PDNPHY_OFFSET    5
+#define    RTL8367C_PDNPHY_MASK    0x20
+#define    RTL8367C_INTPHY_AD_OFFSET    0
+#define    RTL8367C_INTPHY_AD_MASK    0x1F
+
+#define    RTL8367C_REG_DIGITAL_INTERFACE0_FORCE    0x1310
+#define    RTL8367C_GMII_0_FORCE_OFFSET    12
+#define    RTL8367C_GMII_0_FORCE_MASK    0x1000
+#define    RTL8367C_RGMII_0_FORCE_OFFSET    0
+#define    RTL8367C_RGMII_0_FORCE_MASK    0xFFF
+
+#define    RTL8367C_REG_DIGITAL_INTERFACE1_FORCE    0x1311
+#define    RTL8367C_GMII_1_FORCE_OFFSET    12
+#define    RTL8367C_GMII_1_FORCE_MASK    0x1000
+#define    RTL8367C_RGMII_1_FORCE_OFFSET    0
+#define    RTL8367C_RGMII_1_FORCE_MASK    0xFFF
+
+#define    RTL8367C_REG_MAC0_FORCE_SELECT    0x1312
+#define    RTL8367C_EN_MAC0_FORCE_OFFSET    12
+#define    RTL8367C_EN_MAC0_FORCE_MASK    0x1000
+#define    RTL8367C_MAC0_FORCE_ABLTY_OFFSET    0
+#define    RTL8367C_MAC0_FORCE_ABLTY_MASK    0xFFF
+
+#define    RTL8367C_REG_MAC1_FORCE_SELECT    0x1313
+#define    RTL8367C_EN_MAC1_FORCE_OFFSET    12
+#define    RTL8367C_EN_MAC1_FORCE_MASK    0x1000
+#define    RTL8367C_MAC1_FORCE_ABLTY_OFFSET    0
+#define    RTL8367C_MAC1_FORCE_ABLTY_MASK    0xFFF
+
+#define    RTL8367C_REG_MAC2_FORCE_SELECT    0x1314
+#define    RTL8367C_EN_MAC2_FORCE_OFFSET    12
+#define    RTL8367C_EN_MAC2_FORCE_MASK    0x1000
+#define    RTL8367C_MAC2_FORCE_ABLTY_OFFSET    0
+#define    RTL8367C_MAC2_FORCE_ABLTY_MASK    0xFFF
+
+#define    RTL8367C_REG_MAC3_FORCE_SELECT    0x1315
+#define    RTL8367C_EN_MAC3_FORCE_OFFSET    12
+#define    RTL8367C_EN_MAC3_FORCE_MASK    0x1000
+#define    RTL8367C_MAC3_FORCE_ABLTY_OFFSET    0
+#define    RTL8367C_MAC3_FORCE_ABLTY_MASK    0xFFF
+
+#define    RTL8367C_REG_MAC4_FORCE_SELECT    0x1316
+#define    RTL8367C_EN_MAC4_FORCE_OFFSET    12
+#define    RTL8367C_EN_MAC4_FORCE_MASK    0x1000
+#define    RTL8367C_MAC4_FORCE_ABLTY_OFFSET    0
+#define    RTL8367C_MAC4_FORCE_ABLTY_MASK    0xFFF
+
+#define    RTL8367C_REG_MAC5_FORCE_SELECT    0x1317
+#define    RTL8367C_EN_MAC5_FORCE_OFFSET    12
+#define    RTL8367C_EN_MAC5_FORCE_MASK    0x1000
+#define    RTL8367C_MAC5_FORCE_ABLTY_OFFSET    0
+#define    RTL8367C_MAC5_FORCE_ABLTY_MASK    0xFFF
+
+#define    RTL8367C_REG_MAC6_FORCE_SELECT    0x1318
+#define    RTL8367C_EN_MAC6_FORCE_OFFSET    12
+#define    RTL8367C_EN_MAC6_FORCE_MASK    0x1000
+#define    RTL8367C_MAC6_FORCE_ABLTY_OFFSET    0
+#define    RTL8367C_MAC6_FORCE_ABLTY_MASK    0xFFF
+
+#define    RTL8367C_REG_MAC7_FORCE_SELECT    0x1319
+#define    RTL8367C_EN_MAC7_FORCE_OFFSET    12
+#define    RTL8367C_EN_MAC7_FORCE_MASK    0x1000
+#define    RTL8367C_MAC7_FORCE_ABLTY_OFFSET    0
+#define    RTL8367C_MAC7_FORCE_ABLTY_MASK    0xFFF
+
+#define    RTL8367C_REG_M10_FORCE_SELECT    0x131c
+#define    RTL8367C_EN_M10_FORCE_OFFSET    12
+#define    RTL8367C_EN_M10_FORCE_MASK    0x1000
+#define    RTL8367C_M10_FORCE_ABLTY_OFFSET    0
+#define    RTL8367C_M10_FORCE_ABLTY_MASK    0xFFF
+
+#define    RTL8367C_REG_CHIP_RESET    0x1322
+#define    RTL8367C_GPHY_RESET_OFFSET    6
+#define    RTL8367C_GPHY_RESET_MASK    0x40
+#define    RTL8367C_NIC_RST_OFFSET    5
+#define    RTL8367C_NIC_RST_MASK    0x20
+#define    RTL8367C_DW8051_RST_OFFSET    4
+#define    RTL8367C_DW8051_RST_MASK    0x10
+#define    RTL8367C_SDS_RST_OFFSET    3
+#define    RTL8367C_SDS_RST_MASK    0x8
+#define    RTL8367C_CONFIG_RST_OFFSET    2
+#define    RTL8367C_CONFIG_RST_MASK    0x4
+#define    RTL8367C_SW_RST_OFFSET    1
+#define    RTL8367C_SW_RST_MASK    0x2
+#define    RTL8367C_CHIP_RST_OFFSET    0
+#define    RTL8367C_CHIP_RST_MASK    0x1
+
+#define    RTL8367C_REG_DIGITAL_DEBUG_0    0x1323
+
+#define    RTL8367C_REG_DIGITAL_DEBUG_1    0x1324
+
+#define    RTL8367C_REG_INTERNAL_PHY_MDC_DRIVER    0x1325
+#define    RTL8367C_INTERNAL_PHY_MDC_DRIVER_OFFSET    0
+#define    RTL8367C_INTERNAL_PHY_MDC_DRIVER_MASK    0x3FF
+
+#define    RTL8367C_REG_LINKDOWN_TIME_CTRL    0x1326
+#define    RTL8367C_LINKDOWN_TIME_CFG_OFFSET    9
+#define    RTL8367C_LINKDOWN_TIME_CFG_MASK    0x7E00
+#define    RTL8367C_LINKDOWN_TIME_ENABLE_OFFSET    8
+#define    RTL8367C_LINKDOWN_TIME_ENABLE_MASK    0x100
+#define    RTL8367C_LINKDOWN_TIME_OFFSET    0
+#define    RTL8367C_LINKDOWN_TIME_MASK    0xFF
+
+#define    RTL8367C_REG_PHYACK_TIMEOUT    0x1331
+
+#define    RTL8367C_REG_MDXACK_TIMEOUT    0x1333
+
+#define    RTL8367C_REG_DW8051_RDY    0x1336
+#define    RTL8367C_VIAROM_WRITE_EN_OFFSET    9
+#define    RTL8367C_VIAROM_WRITE_EN_MASK    0x200
+#define    RTL8367C_SPIF_CK2_OFFSET    8
+#define    RTL8367C_SPIF_CK2_MASK    0x100
+#define    RTL8367C_RRCP_MDOE_OFFSET    7
+#define    RTL8367C_RRCP_MDOE_MASK    0x80
+#define    RTL8367C_DW8051_RATE_OFFSET    4
+#define    RTL8367C_DW8051_RATE_MASK    0x70
+#define    RTL8367C_IROM_MSB_OFFSET    2
+#define    RTL8367C_IROM_MSB_MASK    0xC
+#define    RTL8367C_ACS_IROM_ENABLE_OFFSET    1
+#define    RTL8367C_ACS_IROM_ENABLE_MASK    0x2
+#define    RTL8367C_DW8051_READY_OFFSET    0
+#define    RTL8367C_DW8051_READY_MASK    0x1
+
+#define    RTL8367C_REG_BIST_CTRL    0x133c
+#define    RTL8367C_DRF_BIST_DONE_ALL_OFFSET    5
+#define    RTL8367C_DRF_BIST_DONE_ALL_MASK    0x20
+#define    RTL8367C_DRF_BIST_PAUSE_ALL_OFFSET    4
+#define    RTL8367C_DRF_BIST_PAUSE_ALL_MASK    0x10
+#define    RTL8367C_BIST_DOAN_ALL_OFFSET    3
+#define    RTL8367C_BIST_DOAN_ALL_MASK    0x8
+#define    RTL8367C_BIST_PASS_OFFSET    0
+#define    RTL8367C_BIST_PASS_MASK    0x7
+
+#define    RTL8367C_REG_DIAG_MODE2    0x133d
+#define    RTL8367C_DIAG_MODE2_ACTRAM_OFFSET    1
+#define    RTL8367C_DIAG_MODE2_ACTRAM_MASK    0x2
+#define    RTL8367C_DIAG_MODE2_BCAM_ACTION_OFFSET    0
+#define    RTL8367C_DIAG_MODE2_BCAM_ACTION_MASK    0x1
+
+#define    RTL8367C_REG_MDX_PHY_REG0    0x133e
+#define    RTL8367C_PHY_BRD_MASK_OFFSET    4
+#define    RTL8367C_PHY_BRD_MASK_MASK    0x1F0
+#define    RTL8367C_MDX_INDACC_PAGE_OFFSET    0
+#define    RTL8367C_MDX_INDACC_PAGE_MASK    0xF
+
+#define    RTL8367C_REG_MDX_PHY_REG1    0x133f
+#define    RTL8367C_PHY_BRD_MODE_OFFSET    5
+#define    RTL8367C_PHY_BRD_MODE_MASK    0x20
+#define    RTL8367C_BRD_PHYAD_OFFSET    0
+#define    RTL8367C_BRD_PHYAD_MASK    0x1F
+
+#define    RTL8367C_REG_DEBUG_SIGNAL_SELECT_SW    0x1340
+
+#define    RTL8367C_REG_DEBUG_SIGNAL_SELECT_B    0x1341
+#define    RTL8367C_DEBUG_MX_OFFSET    9
+#define    RTL8367C_DEBUG_MX_MASK    0xE00
+#define    RTL8367C_DEBUG_SHIFT_MISC_OFFSET    6
+#define    RTL8367C_DEBUG_SHIFT_MISC_MASK    0x1C0
+#define    RTL8367C_DEBUG_SHIFT_SW_OFFSET    3
+#define    RTL8367C_DEBUG_SHIFT_SW_MASK    0x38
+#define    RTL8367C_DEBUG_SHIFT_GPHY_OFFSET    0
+#define    RTL8367C_DEBUG_SHIFT_GPHY_MASK    0x7
+
+#define    RTL8367C_REG_DEBUG_SIGNAL_I    0x1343
+
+#define    RTL8367C_REG_DEBUG_SIGNAL_H    0x1344
+
+#define    RTL8367C_REG_DBGO_SEL_GPHY    0x1345
+
+#define    RTL8367C_REG_DBGO_SEL_MISC    0x1346
+
+#define    RTL8367C_REG_BYPASS_ABLTY_LOCK    0x1349
+#define    RTL8367C_BYPASS_ABLTY_LOCK_OFFSET    0
+#define    RTL8367C_BYPASS_ABLTY_LOCK_MASK    0xFF
+
+#define    RTL8367C_REG_BYPASS_ABLTY_LOCK_EXT    0x134a
+#define    RTL8367C_BYPASS_P10_ABILIITY_LOCK_OFFSET    3
+#define    RTL8367C_BYPASS_P10_ABILIITY_LOCK_MASK    0x8
+#define    RTL8367C_BYPASS_EXT_ABILITY_LOCK_OFFSET    0
+#define    RTL8367C_BYPASS_EXT_ABILITY_LOCK_MASK    0x7
+
+#define    RTL8367C_REG_ACL_GPIO    0x134f
+#define    RTL8367C_ACL_GPIO_13_OFFSET    13
+#define    RTL8367C_ACL_GPIO_13_MASK    0x2000
+#define    RTL8367C_ACL_GPIO_12_OFFSET    12
+#define    RTL8367C_ACL_GPIO_12_MASK    0x1000
+#define    RTL8367C_ACL_GPIO_11_OFFSET    11
+#define    RTL8367C_ACL_GPIO_11_MASK    0x800
+#define    RTL8367C_ACL_GPIO_10_OFFSET    10
+#define    RTL8367C_ACL_GPIO_10_MASK    0x400
+#define    RTL8367C_ACL_GPIO_9_OFFSET    9
+#define    RTL8367C_ACL_GPIO_9_MASK    0x200
+#define    RTL8367C_ACL_GPIO_8_OFFSET    8
+#define    RTL8367C_ACL_GPIO_8_MASK    0x100
+#define    RTL8367C_ACL_GPIO_7_OFFSET    7
+#define    RTL8367C_ACL_GPIO_7_MASK    0x80
+#define    RTL8367C_ACL_GPIO_6_OFFSET    6
+#define    RTL8367C_ACL_GPIO_6_MASK    0x40
+#define    RTL8367C_ACL_GPIO_5_OFFSET    5
+#define    RTL8367C_ACL_GPIO_5_MASK    0x20
+#define    RTL8367C_ACL_GPIO_4_OFFSET    4
+#define    RTL8367C_ACL_GPIO_4_MASK    0x10
+#define    RTL8367C_ACL_GPIO_3_OFFSET    3
+#define    RTL8367C_ACL_GPIO_3_MASK    0x8
+#define    RTL8367C_ACL_GPIO_2_OFFSET    2
+#define    RTL8367C_ACL_GPIO_2_MASK    0x4
+#define    RTL8367C_ACL_GPIO_1_OFFSET    1
+#define    RTL8367C_ACL_GPIO_1_MASK    0x2
+#define    RTL8367C_ACL_GPIO_0_OFFSET    0
+#define    RTL8367C_ACL_GPIO_0_MASK    0x1
+
+#define    RTL8367C_REG_EN_GPIO    0x1350
+#define    RTL8367C_EN_GPIO_13_OFFSET    13
+#define    RTL8367C_EN_GPIO_13_MASK    0x2000
+#define    RTL8367C_EN_GPIO_12_OFFSET    12
+#define    RTL8367C_EN_GPIO_12_MASK    0x1000
+#define    RTL8367C_EN_GPIO_11_OFFSET    11
+#define    RTL8367C_EN_GPIO_11_MASK    0x800
+#define    RTL8367C_EN_GPIO_10_OFFSET    10
+#define    RTL8367C_EN_GPIO_10_MASK    0x400
+#define    RTL8367C_EN_GPIO_9_OFFSET    9
+#define    RTL8367C_EN_GPIO_9_MASK    0x200
+#define    RTL8367C_EN_GPIO_8_OFFSET    8
+#define    RTL8367C_EN_GPIO_8_MASK    0x100
+#define    RTL8367C_EN_GPIO_7_OFFSET    7
+#define    RTL8367C_EN_GPIO_7_MASK    0x80
+#define    RTL8367C_EN_GPIO_6_OFFSET    6
+#define    RTL8367C_EN_GPIO_6_MASK    0x40
+#define    RTL8367C_EN_GPIO_5_OFFSET    5
+#define    RTL8367C_EN_GPIO_5_MASK    0x20
+#define    RTL8367C_EN_GPIO_4_OFFSET    4
+#define    RTL8367C_EN_GPIO_4_MASK    0x10
+#define    RTL8367C_EN_GPIO_3_OFFSET    3
+#define    RTL8367C_EN_GPIO_3_MASK    0x8
+#define    RTL8367C_EN_GPIO_2_OFFSET    2
+#define    RTL8367C_EN_GPIO_2_MASK    0x4
+#define    RTL8367C_EN_GPIO_1_OFFSET    1
+#define    RTL8367C_EN_GPIO_1_MASK    0x2
+#define    RTL8367C_EN_GPIO_0_OFFSET    0
+#define    RTL8367C_EN_GPIO_0_MASK    0x1
+
+#define    RTL8367C_REG_CFG_MULTI_PIN    0x1351
+#define    RTL8367C_CFG_MULTI_PIN_OFFSET    0
+#define    RTL8367C_CFG_MULTI_PIN_MASK    0x3
+
+#define    RTL8367C_REG_PORT0_STATUS    0x1352
+#define    RTL8367C_PORT0_STATUS_EN_1000_LPI_OFFSET    11
+#define    RTL8367C_PORT0_STATUS_EN_1000_LPI_MASK    0x800
+#define    RTL8367C_PORT0_STATUS_EN_100_LPI_OFFSET    10
+#define    RTL8367C_PORT0_STATUS_EN_100_LPI_MASK    0x400
+#define    RTL8367C_PORT0_STATUS_NWAY_FAULT_OFFSET    9
+#define    RTL8367C_PORT0_STATUS_NWAY_FAULT_MASK    0x200
+#define    RTL8367C_PORT0_STATUS_LINK_ON_MASTER_OFFSET    8
+#define    RTL8367C_PORT0_STATUS_LINK_ON_MASTER_MASK    0x100
+#define    RTL8367C_PORT0_STATUS_NWAY_CAP_OFFSET    7
+#define    RTL8367C_PORT0_STATUS_NWAY_CAP_MASK    0x80
+#define    RTL8367C_PORT0_STATUS_TX_FLOWCTRL_CAP_OFFSET    6
+#define    RTL8367C_PORT0_STATUS_TX_FLOWCTRL_CAP_MASK    0x40
+#define    RTL8367C_PORT0_STATUS_RX_FLOWCTRL_CAP_OFFSET    5
+#define    RTL8367C_PORT0_STATUS_RX_FLOWCTRL_CAP_MASK    0x20
+#define    RTL8367C_PORT0_STATUS_LINK_STATE_OFFSET    4
+#define    RTL8367C_PORT0_STATUS_LINK_STATE_MASK    0x10
+#define    RTL8367C_PORT0_STATUS_FULL_DUPLUX_CAP_OFFSET    2
+#define    RTL8367C_PORT0_STATUS_FULL_DUPLUX_CAP_MASK    0x4
+#define    RTL8367C_PORT0_STATUS_LINK_SPEED_OFFSET    0
+#define    RTL8367C_PORT0_STATUS_LINK_SPEED_MASK    0x3
+
+#define    RTL8367C_REG_PORT1_STATUS    0x1353
+#define    RTL8367C_PORT1_STATUS_EN_1000_LPI_OFFSET    11
+#define    RTL8367C_PORT1_STATUS_EN_1000_LPI_MASK    0x800
+#define    RTL8367C_PORT1_STATUS_EN_100_LPI_OFFSET    10
+#define    RTL8367C_PORT1_STATUS_EN_100_LPI_MASK    0x400
+#define    RTL8367C_PORT1_STATUS_NWAY_FAULT_OFFSET    9
+#define    RTL8367C_PORT1_STATUS_NWAY_FAULT_MASK    0x200
+#define    RTL8367C_PORT1_STATUS_LINK_ON_MASTER_OFFSET    8
+#define    RTL8367C_PORT1_STATUS_LINK_ON_MASTER_MASK    0x100
+#define    RTL8367C_PORT1_STATUS_NWAY_CAP_OFFSET    7
+#define    RTL8367C_PORT1_STATUS_NWAY_CAP_MASK    0x80
+#define    RTL8367C_PORT1_STATUS_TX_FLOWCTRL_CAP_OFFSET    6
+#define    RTL8367C_PORT1_STATUS_TX_FLOWCTRL_CAP_MASK    0x40
+#define    RTL8367C_PORT1_STATUS_RX_FLOWCTRL_CAP_OFFSET    5
+#define    RTL8367C_PORT1_STATUS_RX_FLOWCTRL_CAP_MASK    0x20
+#define    RTL8367C_PORT1_STATUS_LINK_STATE_OFFSET    4
+#define    RTL8367C_PORT1_STATUS_LINK_STATE_MASK    0x10
+#define    RTL8367C_PORT1_STATUS_FULL_DUPLUX_CAP_OFFSET    2
+#define    RTL8367C_PORT1_STATUS_FULL_DUPLUX_CAP_MASK    0x4
+#define    RTL8367C_PORT1_STATUS_LINK_SPEED_OFFSET    0
+#define    RTL8367C_PORT1_STATUS_LINK_SPEED_MASK    0x3
+
+#define    RTL8367C_REG_PORT2_STATUS    0x1354
+#define    RTL8367C_PORT2_STATUS_EN_1000_LPI_OFFSET    11
+#define    RTL8367C_PORT2_STATUS_EN_1000_LPI_MASK    0x800
+#define    RTL8367C_PORT2_STATUS_EN_100_LPI_OFFSET    10
+#define    RTL8367C_PORT2_STATUS_EN_100_LPI_MASK    0x400
+#define    RTL8367C_PORT2_STATUS_NWAY_FAULT_OFFSET    9
+#define    RTL8367C_PORT2_STATUS_NWAY_FAULT_MASK    0x200
+#define    RTL8367C_PORT2_STATUS_LINK_ON_MASTER_OFFSET    8
+#define    RTL8367C_PORT2_STATUS_LINK_ON_MASTER_MASK    0x100
+#define    RTL8367C_PORT2_STATUS_NWAY_CAP_OFFSET    7
+#define    RTL8367C_PORT2_STATUS_NWAY_CAP_MASK    0x80
+#define    RTL8367C_PORT2_STATUS_TX_FLOWCTRL_CAP_OFFSET    6
+#define    RTL8367C_PORT2_STATUS_TX_FLOWCTRL_CAP_MASK    0x40
+#define    RTL8367C_PORT2_STATUS_RX_FLOWCTRL_CAP_OFFSET    5
+#define    RTL8367C_PORT2_STATUS_RX_FLOWCTRL_CAP_MASK    0x20
+#define    RTL8367C_PORT2_STATUS_LINK_STATE_OFFSET    4
+#define    RTL8367C_PORT2_STATUS_LINK_STATE_MASK    0x10
+#define    RTL8367C_PORT2_STATUS_FULL_DUPLUX_CAP_OFFSET    2
+#define    RTL8367C_PORT2_STATUS_FULL_DUPLUX_CAP_MASK    0x4
+#define    RTL8367C_PORT2_STATUS_LINK_SPEED_OFFSET    0
+#define    RTL8367C_PORT2_STATUS_LINK_SPEED_MASK    0x3
+
+#define    RTL8367C_REG_PORT3_STATUS    0x1355
+#define    RTL8367C_PORT3_STATUS_EN_1000_LPI_OFFSET    11
+#define    RTL8367C_PORT3_STATUS_EN_1000_LPI_MASK    0x800
+#define    RTL8367C_PORT3_STATUS_EN_100_LPI_OFFSET    10
+#define    RTL8367C_PORT3_STATUS_EN_100_LPI_MASK    0x400
+#define    RTL8367C_PORT3_STATUS_NWAY_FAULT_OFFSET    9
+#define    RTL8367C_PORT3_STATUS_NWAY_FAULT_MASK    0x200
+#define    RTL8367C_PORT3_STATUS_LINK_ON_MASTER_OFFSET    8
+#define    RTL8367C_PORT3_STATUS_LINK_ON_MASTER_MASK    0x100
+#define    RTL8367C_PORT3_STATUS_NWAY_CAP_OFFSET    7
+#define    RTL8367C_PORT3_STATUS_NWAY_CAP_MASK    0x80
+#define    RTL8367C_PORT3_STATUS_TX_FLOWCTRL_CAP_OFFSET    6
+#define    RTL8367C_PORT3_STATUS_TX_FLOWCTRL_CAP_MASK    0x40
+#define    RTL8367C_PORT3_STATUS_RX_FLOWCTRL_CAP_OFFSET    5
+#define    RTL8367C_PORT3_STATUS_RX_FLOWCTRL_CAP_MASK    0x20
+#define    RTL8367C_PORT3_STATUS_LINK_STATE_OFFSET    4
+#define    RTL8367C_PORT3_STATUS_LINK_STATE_MASK    0x10
+#define    RTL8367C_PORT3_STATUS_FULL_DUPLUX_CAP_OFFSET    2
+#define    RTL8367C_PORT3_STATUS_FULL_DUPLUX_CAP_MASK    0x4
+#define    RTL8367C_PORT3_STATUS_LINK_SPEED_OFFSET    0
+#define    RTL8367C_PORT3_STATUS_LINK_SPEED_MASK    0x3
+
+#define    RTL8367C_REG_PORT4_STATUS    0x1356
+#define    RTL8367C_PORT4_STATUS_EN_1000_LPI_OFFSET    11
+#define    RTL8367C_PORT4_STATUS_EN_1000_LPI_MASK    0x800
+#define    RTL8367C_PORT4_STATUS_EN_100_LPI_OFFSET    10
+#define    RTL8367C_PORT4_STATUS_EN_100_LPI_MASK    0x400
+#define    RTL8367C_PORT4_STATUS_NWAY_FAULT_OFFSET    9
+#define    RTL8367C_PORT4_STATUS_NWAY_FAULT_MASK    0x200
+#define    RTL8367C_PORT4_STATUS_LINK_ON_MASTER_OFFSET    8
+#define    RTL8367C_PORT4_STATUS_LINK_ON_MASTER_MASK    0x100
+#define    RTL8367C_PORT4_STATUS_NWAY_CAP_OFFSET    7
+#define    RTL8367C_PORT4_STATUS_NWAY_CAP_MASK    0x80
+#define    RTL8367C_PORT4_STATUS_TX_FLOWCTRL_CAP_OFFSET    6
+#define    RTL8367C_PORT4_STATUS_TX_FLOWCTRL_CAP_MASK    0x40
+#define    RTL8367C_PORT4_STATUS_RX_FLOWCTRL_CAP_OFFSET    5
+#define    RTL8367C_PORT4_STATUS_RX_FLOWCTRL_CAP_MASK    0x20
+#define    RTL8367C_PORT4_STATUS_LINK_STATE_OFFSET    4
+#define    RTL8367C_PORT4_STATUS_LINK_STATE_MASK    0x10
+#define    RTL8367C_PORT4_STATUS_FULL_DUPLUX_CAP_OFFSET    2
+#define    RTL8367C_PORT4_STATUS_FULL_DUPLUX_CAP_MASK    0x4
+#define    RTL8367C_PORT4_STATUS_LINK_SPEED_OFFSET    0
+#define    RTL8367C_PORT4_STATUS_LINK_SPEED_MASK    0x3
+
+#define    RTL8367C_REG_PORT5_STATUS    0x1357
+#define    RTL8367C_PORT5_STATUS_EN_1000_LPI_OFFSET    11
+#define    RTL8367C_PORT5_STATUS_EN_1000_LPI_MASK    0x800
+#define    RTL8367C_PORT5_STATUS_EN_100_LPI_OFFSET    10
+#define    RTL8367C_PORT5_STATUS_EN_100_LPI_MASK    0x400
+#define    RTL8367C_PORT5_STATUS_NWAY_FAULT_OFFSET    9
+#define    RTL8367C_PORT5_STATUS_NWAY_FAULT_MASK    0x200
+#define    RTL8367C_PORT5_STATUS_LINK_ON_MASTER_OFFSET    8
+#define    RTL8367C_PORT5_STATUS_LINK_ON_MASTER_MASK    0x100
+#define    RTL8367C_PORT5_STATUS_NWAY_CAP_OFFSET    7
+#define    RTL8367C_PORT5_STATUS_NWAY_CAP_MASK    0x80
+#define    RTL8367C_PORT5_STATUS_TX_FLOWCTRL_CAP_OFFSET    6
+#define    RTL8367C_PORT5_STATUS_TX_FLOWCTRL_CAP_MASK    0x40
+#define    RTL8367C_PORT5_STATUS_RX_FLOWCTRL_CAP_OFFSET    5
+#define    RTL8367C_PORT5_STATUS_RX_FLOWCTRL_CAP_MASK    0x20
+#define    RTL8367C_PORT5_STATUS_LINK_STATE_OFFSET    4
+#define    RTL8367C_PORT5_STATUS_LINK_STATE_MASK    0x10
+#define    RTL8367C_PORT5_STATUS_FULL_DUPLUX_CAP_OFFSET    2
+#define    RTL8367C_PORT5_STATUS_FULL_DUPLUX_CAP_MASK    0x4
+#define    RTL8367C_PORT5_STATUS_LINK_SPEED_OFFSET    0
+#define    RTL8367C_PORT5_STATUS_LINK_SPEED_MASK    0x3
+
+#define    RTL8367C_REG_PORT6_STATUS    0x1358
+#define    RTL8367C_PORT6_STATUS_EN_1000_LPI_OFFSET    11
+#define    RTL8367C_PORT6_STATUS_EN_1000_LPI_MASK    0x800
+#define    RTL8367C_PORT6_STATUS_EN_100_LPI_OFFSET    10
+#define    RTL8367C_PORT6_STATUS_EN_100_LPI_MASK    0x400
+#define    RTL8367C_PORT6_STATUS_NWAY_FAULT_OFFSET    9
+#define    RTL8367C_PORT6_STATUS_NWAY_FAULT_MASK    0x200
+#define    RTL8367C_PORT6_STATUS_LINK_ON_MASTER_OFFSET    8
+#define    RTL8367C_PORT6_STATUS_LINK_ON_MASTER_MASK    0x100
+#define    RTL8367C_PORT6_STATUS_NWAY_CAP_OFFSET    7
+#define    RTL8367C_PORT6_STATUS_NWAY_CAP_MASK    0x80
+#define    RTL8367C_PORT6_STATUS_TX_FLOWCTRL_CAP_OFFSET    6
+#define    RTL8367C_PORT6_STATUS_TX_FLOWCTRL_CAP_MASK    0x40
+#define    RTL8367C_PORT6_STATUS_RX_FLOWCTRL_CAP_OFFSET    5
+#define    RTL8367C_PORT6_STATUS_RX_FLOWCTRL_CAP_MASK    0x20
+#define    RTL8367C_PORT6_STATUS_LINK_STATE_OFFSET    4
+#define    RTL8367C_PORT6_STATUS_LINK_STATE_MASK    0x10
+#define    RTL8367C_PORT6_STATUS_FULL_DUPLUX_CAP_OFFSET    2
+#define    RTL8367C_PORT6_STATUS_FULL_DUPLUX_CAP_MASK    0x4
+#define    RTL8367C_PORT6_STATUS_LINK_SPEED_OFFSET    0
+#define    RTL8367C_PORT6_STATUS_LINK_SPEED_MASK    0x3
+
+#define    RTL8367C_REG_PORT7_STATUS    0x1359
+#define    RTL8367C_PORT7_STATUS_EN_1000_LPI_OFFSET    11
+#define    RTL8367C_PORT7_STATUS_EN_1000_LPI_MASK    0x800
+#define    RTL8367C_PORT7_STATUS_EN_100_LPI_OFFSET    10
+#define    RTL8367C_PORT7_STATUS_EN_100_LPI_MASK    0x400
+#define    RTL8367C_PORT7_STATUS_NWAY_FAULT_OFFSET    9
+#define    RTL8367C_PORT7_STATUS_NWAY_FAULT_MASK    0x200
+#define    RTL8367C_PORT7_STATUS_LINK_ON_MASTER_OFFSET    8
+#define    RTL8367C_PORT7_STATUS_LINK_ON_MASTER_MASK    0x100
+#define    RTL8367C_PORT7_STATUS_NWAY_CAP_OFFSET    7
+#define    RTL8367C_PORT7_STATUS_NWAY_CAP_MASK    0x80
+#define    RTL8367C_PORT7_STATUS_TX_FLOWCTRL_CAP_OFFSET    6
+#define    RTL8367C_PORT7_STATUS_TX_FLOWCTRL_CAP_MASK    0x40
+#define    RTL8367C_PORT7_STATUS_RX_FLOWCTRL_CAP_OFFSET    5
+#define    RTL8367C_PORT7_STATUS_RX_FLOWCTRL_CAP_MASK    0x20
+#define    RTL8367C_PORT7_STATUS_LINK_STATE_OFFSET    4
+#define    RTL8367C_PORT7_STATUS_LINK_STATE_MASK    0x10
+#define    RTL8367C_PORT7_STATUS_FULL_DUPLUX_CAP_OFFSET    2
+#define    RTL8367C_PORT7_STATUS_FULL_DUPLUX_CAP_MASK    0x4
+#define    RTL8367C_PORT7_STATUS_LINK_SPEED_OFFSET    0
+#define    RTL8367C_PORT7_STATUS_LINK_SPEED_MASK    0x3
+
+#define    RTL8367C_REG_PORT8_STATUS    0x135a
+#define    RTL8367C_PORT8_STATUS_EN_1000_LPI_OFFSET    11
+#define    RTL8367C_PORT8_STATUS_EN_1000_LPI_MASK    0x800
+#define    RTL8367C_PORT8_STATUS_EN_100_LPI_OFFSET    10
+#define    RTL8367C_PORT8_STATUS_EN_100_LPI_MASK    0x400
+#define    RTL8367C_PORT8_STATUS_NWAY_FAULT_OFFSET    9
+#define    RTL8367C_PORT8_STATUS_NWAY_FAULT_MASK    0x200
+#define    RTL8367C_PORT8_STATUS_LINK_ON_MASTER_OFFSET    8
+#define    RTL8367C_PORT8_STATUS_LINK_ON_MASTER_MASK    0x100
+#define    RTL8367C_PORT8_STATUS_NWAY_CAP_OFFSET    7
+#define    RTL8367C_PORT8_STATUS_NWAY_CAP_MASK    0x80
+#define    RTL8367C_PORT8_STATUS_TX_FLOWCTRL_CAP_OFFSET    6
+#define    RTL8367C_PORT8_STATUS_TX_FLOWCTRL_CAP_MASK    0x40
+#define    RTL8367C_PORT8_STATUS_RX_FLOWCTRL_CAP_OFFSET    5
+#define    RTL8367C_PORT8_STATUS_RX_FLOWCTRL_CAP_MASK    0x20
+#define    RTL8367C_PORT8_STATUS_LINK_STATE_OFFSET    4
+#define    RTL8367C_PORT8_STATUS_LINK_STATE_MASK    0x10
+#define    RTL8367C_PORT8_STATUS_FULL_DUPLUX_CAP_OFFSET    2
+#define    RTL8367C_PORT8_STATUS_FULL_DUPLUX_CAP_MASK    0x4
+#define    RTL8367C_PORT8_STATUS_LINK_SPEED_OFFSET    0
+#define    RTL8367C_PORT8_STATUS_LINK_SPEED_MASK    0x3
+
+#define    RTL8367C_REG_PORT9_STATUS    0x135b
+#define    RTL8367C_PORT9_STATUS_EN_1000_LPI_OFFSET    11
+#define    RTL8367C_PORT9_STATUS_EN_1000_LPI_MASK    0x800
+#define    RTL8367C_PORT9_STATUS_EN_100_LPI_OFFSET    10
+#define    RTL8367C_PORT9_STATUS_EN_100_LPI_MASK    0x400
+#define    RTL8367C_PORT9_STATUS_NWAY_FAULT_OFFSET    9
+#define    RTL8367C_PORT9_STATUS_NWAY_FAULT_MASK    0x200
+#define    RTL8367C_PORT9_STATUS_LINK_ON_MASTER_OFFSET    8
+#define    RTL8367C_PORT9_STATUS_LINK_ON_MASTER_MASK    0x100
+#define    RTL8367C_PORT9_STATUS_NWAY_CAP_OFFSET    7
+#define    RTL8367C_PORT9_STATUS_NWAY_CAP_MASK    0x80
+#define    RTL8367C_PORT9_STATUS_TX_FLOWCTRL_CAP_OFFSET    6
+#define    RTL8367C_PORT9_STATUS_TX_FLOWCTRL_CAP_MASK    0x40
+#define    RTL8367C_PORT9_STATUS_RX_FLOWCTRL_CAP_OFFSET    5
+#define    RTL8367C_PORT9_STATUS_RX_FLOWCTRL_CAP_MASK    0x20
+#define    RTL8367C_PORT9_STATUS_LINK_STATE_OFFSET    4
+#define    RTL8367C_PORT9_STATUS_LINK_STATE_MASK    0x10
+#define    RTL8367C_PORT9_STATUS_FULL_DUPLUX_CAP_OFFSET    2
+#define    RTL8367C_PORT9_STATUS_FULL_DUPLUX_CAP_MASK    0x4
+#define    RTL8367C_PORT9_STATUS_LINK_SPEED_OFFSET    0
+#define    RTL8367C_PORT9_STATUS_LINK_SPEED_MASK    0x3
+
+#define    RTL8367C_REG_PORT10_STATUS    0x135c
+#define    RTL8367C_PORT10_STATUS_EN_1000_LPI_OFFSET    11
+#define    RTL8367C_PORT10_STATUS_EN_1000_LPI_MASK    0x800
+#define    RTL8367C_PORT10_STATUS_EN_100_LPI_OFFSET    10
+#define    RTL8367C_PORT10_STATUS_EN_100_LPI_MASK    0x400
+#define    RTL8367C_PORT10_STATUS_NWAY_FAULT_OFFSET    9
+#define    RTL8367C_PORT10_STATUS_NWAY_FAULT_MASK    0x200
+#define    RTL8367C_PORT10_STATUS_LINK_ON_MASTER_OFFSET    8
+#define    RTL8367C_PORT10_STATUS_LINK_ON_MASTER_MASK    0x100
+#define    RTL8367C_PORT10_STATUS_NWAY_CAP_OFFSET    7
+#define    RTL8367C_PORT10_STATUS_NWAY_CAP_MASK    0x80
+#define    RTL8367C_PORT10_STATUS_TX_FLOWCTRL_CAP_OFFSET    6
+#define    RTL8367C_PORT10_STATUS_TX_FLOWCTRL_CAP_MASK    0x40
+#define    RTL8367C_PORT10_STATUS_RX_FLOWCTRL_CAP_OFFSET    5
+#define    RTL8367C_PORT10_STATUS_RX_FLOWCTRL_CAP_MASK    0x20
+#define    RTL8367C_PORT10_STATUS_LINK_STATE_OFFSET    4
+#define    RTL8367C_PORT10_STATUS_LINK_STATE_MASK    0x10
+#define    RTL8367C_PORT10_STATUS_FULL_DUPLUX_CAP_OFFSET    2
+#define    RTL8367C_PORT10_STATUS_FULL_DUPLUX_CAP_MASK    0x4
+#define    RTL8367C_PORT10_STATUS_LINK_SPEED_OFFSET    0
+#define    RTL8367C_PORT10_STATUS_LINK_SPEED_MASK    0x3
+
+#define    RTL8367C_REG_UPS_CTRL0    0x1362
+#define    RTL8367C_P3_REF_SD_BIT0_OFFSET    8
+#define    RTL8367C_P3_REF_SD_BIT0_MASK    0xFF00
+#define    RTL8367C_P2_REF_SD_OFFSET    0
+#define    RTL8367C_P2_REF_SD_MASK    0xFF
+
+#define    RTL8367C_REG_UPS_CTRL1    0x1363
+#define    RTL8367C_UPS_OUT_OFFSET    8
+#define    RTL8367C_UPS_OUT_MASK    0xFF00
+#define    RTL8367C_UPS_WRITE_PULSE_OFFSET    1
+#define    RTL8367C_UPS_WRITE_PULSE_MASK    0x2
+#define    RTL8367C_UPS_EN_OFFSET    0
+#define    RTL8367C_UPS_EN_MASK    0x1
+
+#define    RTL8367C_REG_UPS_CTRL2    0x1364
+#define    RTL8367C_IGNOE_MAC8_LINK_OFFSET    15
+#define    RTL8367C_IGNOE_MAC8_LINK_MASK    0x8000
+#define    RTL8367C_AGREE_SLEEP_OFFSET    14
+#define    RTL8367C_AGREE_SLEEP_MASK    0x4000
+#define    RTL8367C_WAIT_FOR_AGREEMENT_OFFSET    13
+#define    RTL8367C_WAIT_FOR_AGREEMENT_MASK    0x2000
+#define    RTL8367C_WAKE_UP_BY_LINK_OFFSET    12
+#define    RTL8367C_WAKE_UP_BY_LINK_MASK    0x1000
+#define    RTL8367C_WAKE_UP_BY_PHY_OFFSET    11
+#define    RTL8367C_WAKE_UP_BY_PHY_MASK    0x800
+#define    RTL8367C_SLOW_CLK_TGL_RATE_OFFSET    7
+#define    RTL8367C_SLOW_CLK_TGL_RATE_MASK    0x780
+#define    RTL8367C_PLL_G1_CTRL_EN_OFFSET    6
+#define    RTL8367C_PLL_G1_CTRL_EN_MASK    0x40
+#define    RTL8367C_PLL_G0_CTRL_EN_OFFSET    5
+#define    RTL8367C_PLL_G0_CTRL_EN_MASK    0x20
+#define    RTL8367C_SLOW_DOWN_PLL_EN_OFFSET    4
+#define    RTL8367C_SLOW_DOWN_PLL_EN_MASK    0x10
+#define    RTL8367C_SLOW_DOWN_CLK_EN_OFFSET    3
+#define    RTL8367C_SLOW_DOWN_CLK_EN_MASK    0x8
+#define    RTL8367C_GATING_CLK_SDS_EN_OFFSET    2
+#define    RTL8367C_GATING_CLK_SDS_EN_MASK    0x4
+#define    RTL8367C_GATING_CLK_CHIP_EN_OFFSET    1
+#define    RTL8367C_GATING_CLK_CHIP_EN_MASK    0x2
+#define    RTL8367C_GATING_SW_EN_OFFSET    0
+#define    RTL8367C_GATING_SW_EN_MASK    0x1
+
+#define    RTL8367C_REG_GATING_CLK_1    0x1365
+#define    RTL8367C_ALDPS_MODE_4_OFFSET    15
+#define    RTL8367C_ALDPS_MODE_4_MASK    0x8000
+#define    RTL8367C_ALDPS_MODE_3_OFFSET    14
+#define    RTL8367C_ALDPS_MODE_3_MASK    0x4000
+#define    RTL8367C_ALDPS_MODE_2_OFFSET    13
+#define    RTL8367C_ALDPS_MODE_2_MASK    0x2000
+#define    RTL8367C_ALDPS_MODE_1_OFFSET    12
+#define    RTL8367C_ALDPS_MODE_1_MASK    0x1000
+#define    RTL8367C_ALDPS_MODE_0_OFFSET    11
+#define    RTL8367C_ALDPS_MODE_0_MASK    0x800
+#define    RTL8367C_UPS_DBGO_OFFSET    10
+#define    RTL8367C_UPS_DBGO_MASK    0x400
+#define    RTL8367C_IFMX_AFF_NOT_FF_OUT_OFFSET    9
+#define    RTL8367C_IFMX_AFF_NOT_FF_OUT_MASK    0x200
+#define    RTL8367C_WATER_LEVEL_FD_OFFSET    6
+#define    RTL8367C_WATER_LEVEL_FD_MASK    0x1C0
+#define    RTL8367C_WATER_LEVEL_Y2X_OFFSET    3
+#define    RTL8367C_WATER_LEVEL_Y2X_MASK    0x38
+#define    RTL8367C_WATER_LEVEL_X2Y_2_OFFSET    2
+#define    RTL8367C_WATER_LEVEL_X2Y_2_MASK    0x4
+#define    RTL8367C_IGNOE_MAC10_LINK_OFFSET    1
+#define    RTL8367C_IGNOE_MAC10_LINK_MASK    0x2
+#define    RTL8367C_IGNOE_MAC9_LINK_OFFSET    0
+#define    RTL8367C_IGNOE_MAC9_LINK_MASK    0x1
+
+#define    RTL8367C_REG_UPS_CTRL4    0x1366
+#define    RTL8367C_PROB_EN_OFFSET    6
+#define    RTL8367C_PROB_EN_MASK    0x40
+#define    RTL8367C_PLL_DOWN_OFFSET    1
+#define    RTL8367C_PLL_DOWN_MASK    0x2
+#define    RTL8367C_XTAL_DOWN_OFFSET    0
+#define    RTL8367C_XTAL_DOWN_MASK    0x1
+
+#define    RTL8367C_REG_UPS_CTRL5    0x1367
+#define    RTL8367C_FRC_CPU_ACPT_OFFSET    3
+#define    RTL8367C_FRC_CPU_ACPT_MASK    0x8
+#define    RTL8367C_UPS_CPU_ACPT_OFFSET    2
+#define    RTL8367C_UPS_CPU_ACPT_MASK    0x4
+#define    RTL8367C_UPS_DBG_4_OFFSET    0
+#define    RTL8367C_UPS_DBG_4_MASK    0x3
+
+#define    RTL8367C_REG_UPS_CTRL6    0x1368
+#define    RTL8367C_UPS_CTRL6_OFFSET    0
+#define    RTL8367C_UPS_CTRL6_MASK    0xF
+
+#define    RTL8367C_REG_EFUSE_CMD_70B    0x1369
+
+#define    RTL8367C_REG_EFUSE_CMD    0x1370
+#define    RTL8367C_EFUSE_TIME_OUT_FLAG_OFFSET    3
+#define    RTL8367C_EFUSE_TIME_OUT_FLAG_MASK    0x8
+#define    RTL8367C_EFUSE_ACCESS_BUSY_OFFSET    2
+#define    RTL8367C_EFUSE_ACCESS_BUSY_MASK    0x4
+#define    RTL8367C_EFUSE_COMMAND_EN_OFFSET    1
+#define    RTL8367C_EFUSE_COMMAND_EN_MASK    0x2
+#define    RTL8367C_EFUSE_WR_OFFSET    0
+#define    RTL8367C_EFUSE_WR_MASK    0x1
+
+#define    RTL8367C_REG_EFUSE_ADR    0x1371
+#define    RTL8367C_DUMMY_15_10_OFFSET    8
+#define    RTL8367C_DUMMY_15_10_MASK    0xFF00
+#define    RTL8367C_EFUSE_ADDRESS_OFFSET    0
+#define    RTL8367C_EFUSE_ADDRESS_MASK    0xFF
+
+#define    RTL8367C_REG_EFUSE_WDAT    0x1372
+
+#define    RTL8367C_REG_EFUSE_RDAT    0x1373
+
+#define    RTL8367C_REG_I2C_CTRL    0x1374
+#define    RTL8367C_MDX_MST_FAIL_LAT_OFFSET    1
+#define    RTL8367C_MDX_MST_FAIL_LAT_MASK    0x2
+#define    RTL8367C_MDX_MST_FAIL_CLRPS_OFFSET    0
+#define    RTL8367C_MDX_MST_FAIL_CLRPS_MASK    0x1
+
+#define    RTL8367C_REG_EEE_CFG    0x1375
+#define    RTL8367C_CFG_BYPASS_GATELPTD_OFFSET    11
+#define    RTL8367C_CFG_BYPASS_GATELPTD_MASK    0x800
+#define    RTL8367C_EEE_ABT_ADDR2_OFFSET    6
+#define    RTL8367C_EEE_ABT_ADDR2_MASK    0x7C0
+#define    RTL8367C_EEE_ABT_ADDR1_OFFSET    1
+#define    RTL8367C_EEE_ABT_ADDR1_MASK    0x3E
+#define    RTL8367C_EEE_POLL_EN_OFFSET    0
+#define    RTL8367C_EEE_POLL_EN_MASK    0x1
+
+#define    RTL8367C_REG_EEE_PAGE    0x1376
+
+#define    RTL8367C_REG_EEE_EXT_PAGE    0x1377
+
+#define    RTL8367C_REG_EEE_EN_SPD1000    0x1378
+
+#define    RTL8367C_REG_EEE_EN_SPD100    0x1379
+
+#define    RTL8367C_REG_EEE_LP_SPD1000    0x137a
+
+#define    RTL8367C_REG_EEE_LP_SPD100    0x137b
+
+#define    RTL8367C_REG_DW8051_PRO_REG0    0x13a0
+
+#define    RTL8367C_REG_DW8051_PRO_REG1    0x13a1
+
+#define    RTL8367C_REG_DW8051_PRO_REG2    0x13a2
+
+#define    RTL8367C_REG_DW8051_PRO_REG3    0x13a3
+
+#define    RTL8367C_REG_DW8051_PRO_REG4    0x13a4
+
+#define    RTL8367C_REG_DW8051_PRO_REG5    0x13a5
+
+#define    RTL8367C_REG_DW8051_PRO_REG6    0x13a6
+
+#define    RTL8367C_REG_DW8051_PRO_REG7    0x13a7
+
+#define    RTL8367C_REG_PROTECT_ID    0x13c0
+
+#define    RTL8367C_REG_CHIP_VER_INTL    0x13c1
+#define    RTL8367C_CHIP_VER_INTL_OFFSET    0
+#define    RTL8367C_CHIP_VER_INTL_MASK    0xF
+
+#define    RTL8367C_REG_MAGIC_ID    0x13c2
+
+#define    RTL8367C_REG_DIGITAL_INTERFACE_SELECT_1    0x13c3
+#define    RTL8367C_SKIP_MII_2_RXER_OFFSET    4
+#define    RTL8367C_SKIP_MII_2_RXER_MASK    0x10
+#define    RTL8367C_SELECT_GMII_2_OFFSET    0
+#define    RTL8367C_SELECT_GMII_2_MASK    0xF
+
+#define    RTL8367C_REG_DIGITAL_INTERFACE2_FORCE    0x13c4
+#define    RTL8367C_GMII_2_FORCE_OFFSET    12
+#define    RTL8367C_GMII_2_FORCE_MASK    0x1000
+#define    RTL8367C_RGMII_2_FORCE_OFFSET    0
+#define    RTL8367C_RGMII_2_FORCE_MASK    0xFFF
+
+#define    RTL8367C_REG_EXT2_RGMXF    0x13c5
+#define    RTL8367C_EXT2_RGTX_INV_OFFSET    6
+#define    RTL8367C_EXT2_RGTX_INV_MASK    0x40
+#define    RTL8367C_EXT2_RGRX_INV_OFFSET    5
+#define    RTL8367C_EXT2_RGRX_INV_MASK    0x20
+#define    RTL8367C_EXT2_RGMXF_OFFSET    0
+#define    RTL8367C_EXT2_RGMXF_MASK    0x1F
+
+#define    RTL8367C_REG_ROUTER_UPS_CFG    0x13c6
+#define    RTL8367C_UPS_Status_OFFSET    1
+#define    RTL8367C_UPS_Status_MASK    0x2
+#define    RTL8367C_SoftStart_OFFSET    0
+#define    RTL8367C_SoftStart_MASK    0x1
+
+#define    RTL8367C_REG_CTRL_GPIO    0x13c7
+#define    RTL8367C_CTRL_GPIO_13_OFFSET    13
+#define    RTL8367C_CTRL_GPIO_13_MASK    0x2000
+#define    RTL8367C_CTRL_GPIO_12_OFFSET    12
+#define    RTL8367C_CTRL_GPIO_12_MASK    0x1000
+#define    RTL8367C_CTRL_GPIO_11_OFFSET    11
+#define    RTL8367C_CTRL_GPIO_11_MASK    0x800
+#define    RTL8367C_CTRL_GPIO_10_OFFSET    10
+#define    RTL8367C_CTRL_GPIO_10_MASK    0x400
+#define    RTL8367C_CTRL_GPIO_9_OFFSET    9
+#define    RTL8367C_CTRL_GPIO_9_MASK    0x200
+#define    RTL8367C_CTRL_GPIO_8_OFFSET    8
+#define    RTL8367C_CTRL_GPIO_8_MASK    0x100
+#define    RTL8367C_CTRL_GPIO_7_OFFSET    7
+#define    RTL8367C_CTRL_GPIO_7_MASK    0x80
+#define    RTL8367C_CTRL_GPIO_6_OFFSET    6
+#define    RTL8367C_CTRL_GPIO_6_MASK    0x40
+#define    RTL8367C_CTRL_GPIO_5_OFFSET    5
+#define    RTL8367C_CTRL_GPIO_5_MASK    0x20
+#define    RTL8367C_CTRL_GPIO_4_OFFSET    4
+#define    RTL8367C_CTRL_GPIO_4_MASK    0x10
+#define    RTL8367C_CTRL_GPIO_3_OFFSET    3
+#define    RTL8367C_CTRL_GPIO_3_MASK    0x8
+#define    RTL8367C_CTRL_GPIO_2_OFFSET    2
+#define    RTL8367C_CTRL_GPIO_2_MASK    0x4
+#define    RTL8367C_CTRL_GPIO_1_OFFSET    1
+#define    RTL8367C_CTRL_GPIO_1_MASK    0x2
+#define    RTL8367C_CTRL_GPIO_0_OFFSET    0
+#define    RTL8367C_CTRL_GPIO_0_MASK    0x1
+
+#define    RTL8367C_REG_SEL_GPIO    0x13c8
+#define    RTL8367C_SEL_GPIO_13_OFFSET    13
+#define    RTL8367C_SEL_GPIO_13_MASK    0x2000
+#define    RTL8367C_SEL_GPIO_12_OFFSET    12
+#define    RTL8367C_SEL_GPIO_12_MASK    0x1000
+#define    RTL8367C_SEL_GPIO_11_OFFSET    11
+#define    RTL8367C_SEL_GPIO_11_MASK    0x800
+#define    RTL8367C_SEL_GPIO_10_OFFSET    10
+#define    RTL8367C_SEL_GPIO_10_MASK    0x400
+#define    RTL8367C_SEL_GPIO_9_OFFSET    9
+#define    RTL8367C_SEL_GPIO_9_MASK    0x200
+#define    RTL8367C_SEL_GPIO_8_OFFSET    8
+#define    RTL8367C_SEL_GPIO_8_MASK    0x100
+#define    RTL8367C_SEL_GPIO_7_OFFSET    7
+#define    RTL8367C_SEL_GPIO_7_MASK    0x80
+#define    RTL8367C_SEL_GPIO_6_OFFSET    6
+#define    RTL8367C_SEL_GPIO_6_MASK    0x40
+#define    RTL8367C_SEL_GPIO_5_OFFSET    5
+#define    RTL8367C_SEL_GPIO_5_MASK    0x20
+#define    RTL8367C_SEL_GPIO_4_OFFSET    4
+#define    RTL8367C_SEL_GPIO_4_MASK    0x10
+#define    RTL8367C_SEL_GPIO_3_OFFSET    3
+#define    RTL8367C_SEL_GPIO_3_MASK    0x8
+#define    RTL8367C_SEL_GPIO_2_OFFSET    2
+#define    RTL8367C_SEL_GPIO_2_MASK    0x4
+#define    RTL8367C_SEL_GPIO_1_OFFSET    1
+#define    RTL8367C_SEL_GPIO_1_MASK    0x2
+#define    RTL8367C_SEL_GPIO_0_OFFSET    0
+#define    RTL8367C_SEL_GPIO_0_MASK    0x1
+
+#define    RTL8367C_REG_STATUS_GPIO    0x13c9
+#define    RTL8367C_STATUS_GPIO_OFFSET    0
+#define    RTL8367C_STATUS_GPIO_MASK    0x3FFF
+
+#define    RTL8367C_REG_SYNC_ETH_CFG    0x13e0
+#define    RTL8367C_DUMMY2_OFFSET    9
+#define    RTL8367C_DUMMY2_MASK    0xFE00
+#define    RTL8367C_RFC2819_TYPE_OFFSET    8
+#define    RTL8367C_RFC2819_TYPE_MASK    0x100
+#define    RTL8367C_DUMMY1_OFFSET    7
+#define    RTL8367C_DUMMY1_MASK    0x80
+#define    RTL8367C_FIBER_SYNCE125_L_SEL_OFFSET    6
+#define    RTL8367C_FIBER_SYNCE125_L_SEL_MASK    0x40
+#define    RTL8367C_SYNC_ETH_EN_RTT2_OFFSET    5
+#define    RTL8367C_SYNC_ETH_EN_RTT2_MASK    0x20
+#define    RTL8367C_SYNC_ETH_EN_RTT1_OFFSET    4
+#define    RTL8367C_SYNC_ETH_EN_RTT1_MASK    0x10
+#define    RTL8367C_SYNC_ETH_SEL_DPLL_OFFSET    3
+#define    RTL8367C_SYNC_ETH_SEL_DPLL_MASK    0x8
+#define    RTL8367C_SYNC_ETH_SEL_PHYREF_OFFSET    2
+#define    RTL8367C_SYNC_ETH_SEL_PHYREF_MASK    0x4
+#define    RTL8367C_SYNC_ETH_SEL_XTAL_OFFSET    1
+#define    RTL8367C_SYNC_ETH_SEL_XTAL_MASK    0x2
+#define    RTL8367C_DUMMY0_OFFSET    0
+#define    RTL8367C_DUMMY0_MASK    0x1
+
+#define    RTL8367C_REG_LED_DRI_CFG    0x13e1
+#define    RTL8367C_LED_DRI_CFG_DUMMY_OFFSET    1
+#define    RTL8367C_LED_DRI_CFG_DUMMY_MASK    0xFFFE
+#define    RTL8367C_LED_DRIVING_OFFSET    0
+#define    RTL8367C_LED_DRIVING_MASK    0x1
+
+#define    RTL8367C_REG_CHIP_DEBUG2    0x13e2
+#define    RTL8367C_RG2_DN_OFFSET    6
+#define    RTL8367C_RG2_DN_MASK    0x1C0
+#define    RTL8367C_RG2_DP_OFFSET    3
+#define    RTL8367C_RG2_DP_MASK    0x38
+#define    RTL8367C_DRI_EXT2_RG_OFFSET    2
+#define    RTL8367C_DRI_EXT2_RG_MASK    0x4
+#define    RTL8367C_DRI_EXT2_OFFSET    1
+#define    RTL8367C_DRI_EXT2_MASK    0x2
+#define    RTL8367C_SLR_EXT2_OFFSET    0
+#define    RTL8367C_SLR_EXT2_MASK    0x1
+
+#define    RTL8367C_REG_DIGITAL_DEBUG_2    0x13e3
+
+#define    RTL8367C_REG_FIBER_RTL_OUI_CFG0    0x13e4
+#define    RTL8367C_FIBER_RTL_OUI_CFG0_OFFSET    0
+#define    RTL8367C_FIBER_RTL_OUI_CFG0_MASK    0xFF
+
+#define    RTL8367C_REG_FIBER_RTL_OUI_CFG1    0x13e5
+
+#define    RTL8367C_REG_FIBER_CFG_0    0x13e6
+#define    RTL8367C_REV_NUM_OFFSET    8
+#define    RTL8367C_REV_NUM_MASK    0xF00
+#define    RTL8367C_MODEL_NUM_OFFSET    0
+#define    RTL8367C_MODEL_NUM_MASK    0x3F
+
+#define    RTL8367C_REG_FIBER_CFG_1    0x13e7
+#define    RTL8367C_SDS_FRC_REG4_OFFSET    12
+#define    RTL8367C_SDS_FRC_REG4_MASK    0x1000
+#define    RTL8367C_SDS_FRC_REG4_FIB100_OFFSET    11
+#define    RTL8367C_SDS_FRC_REG4_FIB100_MASK    0x800
+#define    RTL8367C_SEL_MASK_ONL_OFFSET    5
+#define    RTL8367C_SEL_MASK_ONL_MASK    0x20
+#define    RTL8367C_DIS_QUALITY_IN_MASK_OFFSET    4
+#define    RTL8367C_DIS_QUALITY_IN_MASK_MASK    0x10
+#define    RTL8367C_SDS_FRC_MODE_OFFSET    3
+#define    RTL8367C_SDS_FRC_MODE_MASK    0x8
+#define    RTL8367C_SDS_MODE_OFFSET    0
+#define    RTL8367C_SDS_MODE_MASK    0x7
+
+#define    RTL8367C_REG_FIBER_CFG_2    0x13e8
+#define    RTL8367C_SEL_SDET_PS_OFFSET    12
+#define    RTL8367C_SEL_SDET_PS_MASK    0xF000
+#define    RTL8367C_UTP_DIS_RX_OFFSET    10
+#define    RTL8367C_UTP_DIS_RX_MASK    0xC00
+#define    RTL8367C_UTP_FRC_LD_OFFSET    8
+#define    RTL8367C_UTP_FRC_LD_MASK    0x300
+#define    RTL8367C_SDS_RX_DISABLE_OFFSET    6
+#define    RTL8367C_SDS_RX_DISABLE_MASK    0xC0
+#define    RTL8367C_SDS_TX_DISABLE_OFFSET    4
+#define    RTL8367C_SDS_TX_DISABLE_MASK    0x30
+#define    RTL8367C_FIBER_CFG_2_SDS_PWR_ISO_OFFSET    2
+#define    RTL8367C_FIBER_CFG_2_SDS_PWR_ISO_MASK    0xC
+#define    RTL8367C_SDS_FRC_LD_OFFSET    0
+#define    RTL8367C_SDS_FRC_LD_MASK    0x3
+
+#define    RTL8367C_REG_FIBER_CFG_3    0x13e9
+#define    RTL8367C_FIBER_CFG_3_OFFSET    0
+#define    RTL8367C_FIBER_CFG_3_MASK    0xFFF
+
+#define    RTL8367C_REG_FIBER_CFG_4    0x13ea
+
+#define    RTL8367C_REG_UTP_FIB_DET    0x13eb
+#define    RTL8367C_FORCE_SEL_FIBER_OFFSET    14
+#define    RTL8367C_FORCE_SEL_FIBER_MASK    0xC000
+#define    RTL8367C_FIB_FINAL_TIMER_OFFSET    12
+#define    RTL8367C_FIB_FINAL_TIMER_MASK    0x3000
+#define    RTL8367C_FIB_LINK_TIMER_OFFSET    10
+#define    RTL8367C_FIB_LINK_TIMER_MASK    0xC00
+#define    RTL8367C_FIB_SDET_TIMER_OFFSET    8
+#define    RTL8367C_FIB_SDET_TIMER_MASK    0x300
+#define    RTL8367C_UTP_LINK_TIMER_OFFSET    6
+#define    RTL8367C_UTP_LINK_TIMER_MASK    0xC0
+#define    RTL8367C_UTP_SDET_TIMER_OFFSET    4
+#define    RTL8367C_UTP_SDET_TIMER_MASK    0x30
+#define    RTL8367C_FORCE_AUTODET_OFFSET    3
+#define    RTL8367C_FORCE_AUTODET_MASK    0x8
+#define    RTL8367C_AUTODET_FSM_CLR_OFFSET    2
+#define    RTL8367C_AUTODET_FSM_CLR_MASK    0x4
+#define    RTL8367C_UTP_FIRST_OFFSET    1
+#define    RTL8367C_UTP_FIRST_MASK    0x2
+#define    RTL8367C_UTP_FIB_DISAUTODET_OFFSET    0
+#define    RTL8367C_UTP_FIB_DISAUTODET_MASK    0x1
+
+#define    RTL8367C_REG_NRESTORE_MAGIC_NUM    0x13ec
+#define    RTL8367C_NRESTORE_MAGIC_NUM_MASK    0xFFFF
+#define    RTL8367C_EEPROM_PROGRAM_CYCLE_OFFSET    0
+#define    RTL8367C_EEPROM_PROGRAM_CYCLE_MASK    0x3
+
+#define    RTL8367C_REG_MAC_ACTIVE    0x13ee
+#define    RTL8367C_MAC_ACTIVE_H_OFFSET    9
+#define    RTL8367C_MAC_ACTIVE_H_MASK    0xE00
+#define    RTL8367C_FORCE_MAC_ACTIVE_OFFSET    8
+#define    RTL8367C_FORCE_MAC_ACTIVE_MASK    0x100
+#define    RTL8367C_MAC_ACTIVE_OFFSET    0
+#define    RTL8367C_MAC_ACTIVE_MASK    0xFF
+
+#define    RTL8367C_REG_SERDES_RESULT    0x13ef
+#define    RTL8367C_FIB100_DET_1_OFFSET    12
+#define    RTL8367C_FIB100_DET_1_MASK    0x1000
+#define    RTL8367C_FIB_ISO_1_OFFSET    11
+#define    RTL8367C_FIB_ISO_1_MASK    0x800
+#define    RTL8367C_SDS_ANFAULT_1_OFFSET    10
+#define    RTL8367C_SDS_ANFAULT_1_MASK    0x400
+#define    RTL8367C_SDS_INTB_1_OFFSET    9
+#define    RTL8367C_SDS_INTB_1_MASK    0x200
+#define    RTL8367C_SDS_LINK_OK_1_OFFSET    8
+#define    RTL8367C_SDS_LINK_OK_1_MASK    0x100
+#define    RTL8367C_FIB100_DET_OFFSET    4
+#define    RTL8367C_FIB100_DET_MASK    0x10
+#define    RTL8367C_FIB_ISO_OFFSET    3
+#define    RTL8367C_FIB_ISO_MASK    0x8
+#define    RTL8367C_SDS_ANFAULT_OFFSET    2
+#define    RTL8367C_SDS_ANFAULT_MASK    0x4
+#define    RTL8367C_SDS_INTB_OFFSET    1
+#define    RTL8367C_SDS_INTB_MASK    0x2
+#define    RTL8367C_SDS_LINK_OK_OFFSET    0
+#define    RTL8367C_SDS_LINK_OK_MASK    0x1
+
+#define    RTL8367C_REG_CHIP_ECO    0x13f0
+#define    RTL8367C_CFG_CHIP_ECO_OFFSET    1
+#define    RTL8367C_CFG_CHIP_ECO_MASK    0xFFFE
+#define    RTL8367C_CFG_CKOUTEN_OFFSET    0
+#define    RTL8367C_CFG_CKOUTEN_MASK    0x1
+
+#define    RTL8367C_REG_WAKELPI_SLOT_PRD    0x13f1
+#define    RTL8367C_WAKELPI_SLOT_PRD_OFFSET    0
+#define    RTL8367C_WAKELPI_SLOT_PRD_MASK    0x1F
+
+#define    RTL8367C_REG_WAKELPI_SLOT_PG0    0x13f2
+#define    RTL8367C_WAKELPI_SLOT_P1_OFFSET    8
+#define    RTL8367C_WAKELPI_SLOT_P1_MASK    0x1F00
+#define    RTL8367C_WAKELPI_SLOT_P0_OFFSET    0
+#define    RTL8367C_WAKELPI_SLOT_P0_MASK    0x1F
+
+#define    RTL8367C_REG_WAKELPI_SLOT_PG1    0x13f3
+#define    RTL8367C_WAKELPI_SLOT_P3_OFFSET    8
+#define    RTL8367C_WAKELPI_SLOT_P3_MASK    0x1F00
+#define    RTL8367C_WAKELPI_SLOT_P2_OFFSET    0
+#define    RTL8367C_WAKELPI_SLOT_P2_MASK    0x1F
+
+#define    RTL8367C_REG_WAKELPI_SLOT_PG2    0x13f4
+#define    RTL8367C_WAKELPI_SLOT_P5_OFFSET    8
+#define    RTL8367C_WAKELPI_SLOT_P5_MASK    0x1F00
+#define    RTL8367C_WAKELPI_SLOT_P4_OFFSET    0
+#define    RTL8367C_WAKELPI_SLOT_P4_MASK    0x1F
+
+#define    RTL8367C_REG_WAKELPI_SLOT_PG3    0x13f5
+#define    RTL8367C_WAKELPI_SLOT_P7_OFFSET    8
+#define    RTL8367C_WAKELPI_SLOT_P7_MASK    0x1F00
+#define    RTL8367C_WAKELPI_SLOT_P6_OFFSET    0
+#define    RTL8367C_WAKELPI_SLOT_P6_MASK    0x1F
+
+#define    RTL8367C_REG_SYNC_FIFO_0    0x13f6
+#define    RTL8367C_SYNC_FIFO_TX_OFFSET    8
+#define    RTL8367C_SYNC_FIFO_TX_MASK    0x700
+#define    RTL8367C_SYNC_FIFO_RX_OFFSET    0
+#define    RTL8367C_SYNC_FIFO_RX_MASK    0xFF
+
+#define    RTL8367C_REG_SYNC_FIFO_1    0x13f7
+#define    RTL8367C_SYNC_FIFO_RX_ERR_P10_8_OFFSET    11
+#define    RTL8367C_SYNC_FIFO_RX_ERR_P10_8_MASK    0x3800
+#define    RTL8367C_SYNC_FIFO_TX_ERR_OFFSET    8
+#define    RTL8367C_SYNC_FIFO_TX_ERR_MASK    0x700
+#define    RTL8367C_SYNC_FIFO_RX_ERR_OFFSET    0
+#define    RTL8367C_SYNC_FIFO_RX_ERR_MASK    0xFF
+
+#define    RTL8367C_REG_RGM_EEE    0x13f8
+#define    RTL8367C_EXT2_PAD_STOP_EN_OFFSET    14
+#define    RTL8367C_EXT2_PAD_STOP_EN_MASK    0x4000
+#define    RTL8367C_EXT1_PAD_STOP_EN_OFFSET    13
+#define    RTL8367C_EXT1_PAD_STOP_EN_MASK    0x2000
+#define    RTL8367C_EXT0_PAD_STOP_EN_OFFSET    12
+#define    RTL8367C_EXT0_PAD_STOP_EN_MASK    0x1000
+#define    RTL8367C_EXT2_CYCLE_PAD_OFFSET    8
+#define    RTL8367C_EXT2_CYCLE_PAD_MASK    0xF00
+#define    RTL8367C_EXT1_CYCLE_PAD_OFFSET    4
+#define    RTL8367C_EXT1_CYCLE_PAD_MASK    0xF0
+#define    RTL8367C_EXT0_CYCLE_PAD_OFFSET    0
+#define    RTL8367C_EXT0_CYCLE_PAD_MASK    0xF
+
+#define    RTL8367C_REG_EXT_TXC_DLY    0x13f9
+#define    RTL8367C_EXT1_GMII_TX_DELAY_OFFSET    12
+#define    RTL8367C_EXT1_GMII_TX_DELAY_MASK    0x7000
+#define    RTL8367C_EXT0_GMII_TX_DELAY_OFFSET    9
+#define    RTL8367C_EXT0_GMII_TX_DELAY_MASK    0xE00
+#define    RTL8367C_EXT2_RGMII_TX_DELAY_OFFSET    6
+#define    RTL8367C_EXT2_RGMII_TX_DELAY_MASK    0x1C0
+#define    RTL8367C_EXT1_RGMII_TX_DELAY_OFFSET    3
+#define    RTL8367C_EXT1_RGMII_TX_DELAY_MASK    0x38
+#define    RTL8367C_EXT0_RGMII_TX_DELAY_OFFSET    0
+#define    RTL8367C_EXT0_RGMII_TX_DELAY_MASK    0x7
+
+#define    RTL8367C_REG_IO_MISC_CTRL    0x13fa
+#define    RTL8367C_IO_BUZZER_EN_OFFSET    3
+#define    RTL8367C_IO_BUZZER_EN_MASK    0x8
+#define    RTL8367C_IO_INTRPT_EN_OFFSET    2
+#define    RTL8367C_IO_INTRPT_EN_MASK    0x4
+#define    RTL8367C_IO_NRESTORE_EN_OFFSET    1
+#define    RTL8367C_IO_NRESTORE_EN_MASK    0x2
+#define    RTL8367C_IO_UART_EN_OFFSET    0
+#define    RTL8367C_IO_UART_EN_MASK    0x1
+
+#define    RTL8367C_REG_CHIP_DUMMY_NO    0x13fb
+#define    RTL8367C_CHIP_DUMMY_NO_OFFSET    0
+#define    RTL8367C_CHIP_DUMMY_NO_MASK    0xF
+
+#define    RTL8367C_REG_RC_CALIB_CFG    0x13fc
+#define    RTL8367C_TRIG_BURN_EFUSE_OFFSET    9
+#define    RTL8367C_TRIG_BURN_EFUSE_MASK    0x200
+#define    RTL8367C_AMP_CALIB_FAIL_OFFSET    8
+#define    RTL8367C_AMP_CALIB_FAIL_MASK    0x100
+#define    RTL8367C_R_CALIB_FAIL_OFFSET    7
+#define    RTL8367C_R_CALIB_FAIL_MASK    0x80
+#define    RTL8367C_CFG_CALIB_MODE_OFFSET    6
+#define    RTL8367C_CFG_CALIB_MODE_MASK    0x40
+#define    RTL8367C_CENTER_PORT_SEL_OFFSET    3
+#define    RTL8367C_CENTER_PORT_SEL_MASK    0x38
+#define    RTL8367C_CALIB_FINISH_OFFSET    2
+#define    RTL8367C_CALIB_FINISH_MASK    0x4
+#define    RTL8367C_CFG_CALIB_OPTION_OFFSET    1
+#define    RTL8367C_CFG_CALIB_OPTION_MASK    0x2
+#define    RTL8367C_CFG_CALIB_EN_OFFSET    0
+#define    RTL8367C_CFG_CALIB_EN_MASK    0x1
+
+#define    RTL8367C_REG_WAKELPI_SLOT_PG4    0x13fd
+#define    RTL8367C_WAKELPI_SLOT_P9_OFFSET    8
+#define    RTL8367C_WAKELPI_SLOT_P9_MASK    0x1F00
+#define    RTL8367C_WAKELPI_SLOT_P8_OFFSET    0
+#define    RTL8367C_WAKELPI_SLOT_P8_MASK    0x1F
+
+#define    RTL8367C_REG_WAKELPI_SLOT_PG5    0x13fe
+#define    RTL8367C_WAKELPI_SLOT_PG5_OFFSET    0
+#define    RTL8367C_WAKELPI_SLOT_PG5_MASK    0x1F
+
+/* (16'h1400)mtrpool_reg */
+
+#define    RTL8367C_REG_METER0_RATE_CTRL0    0x1400
+
+#define    RTL8367C_REG_METER0_RATE_CTRL1    0x1401
+#define    RTL8367C_METER0_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER0_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER1_RATE_CTRL0    0x1402
+
+#define    RTL8367C_REG_METER1_RATE_CTRL1    0x1403
+#define    RTL8367C_METER1_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER1_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER2_RATE_CTRL0    0x1404
+
+#define    RTL8367C_REG_METER2_RATE_CTRL1    0x1405
+#define    RTL8367C_METER2_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER2_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER3_RATE_CTRL0    0x1406
+
+#define    RTL8367C_REG_METER3_RATE_CTRL1    0x1407
+#define    RTL8367C_METER3_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER3_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER4_RATE_CTRL0    0x1408
+
+#define    RTL8367C_REG_METER4_RATE_CTRL1    0x1409
+#define    RTL8367C_METER4_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER4_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER5_RATE_CTRL0    0x140a
+
+#define    RTL8367C_REG_METER5_RATE_CTRL1    0x140b
+#define    RTL8367C_METER5_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER5_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER6_RATE_CTRL0    0x140c
+
+#define    RTL8367C_REG_METER6_RATE_CTRL1    0x140d
+#define    RTL8367C_METER6_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER6_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER7_RATE_CTRL0    0x140e
+
+#define    RTL8367C_REG_METER7_RATE_CTRL1    0x140f
+#define    RTL8367C_METER7_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER7_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER8_RATE_CTRL0    0x1410
+
+#define    RTL8367C_REG_METER8_RATE_CTRL1    0x1411
+#define    RTL8367C_METER8_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER8_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER9_RATE_CTRL0    0x1412
+
+#define    RTL8367C_REG_METER9_RATE_CTRL1    0x1413
+#define    RTL8367C_METER9_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER9_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER10_RATE_CTRL0    0x1414
+
+#define    RTL8367C_REG_METER10_RATE_CTRL1    0x1415
+#define    RTL8367C_METER10_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER10_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER11_RATE_CTRL0    0x1416
+
+#define    RTL8367C_REG_METER11_RATE_CTRL1    0x1417
+#define    RTL8367C_METER11_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER11_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER12_RATE_CTRL0    0x1418
+
+#define    RTL8367C_REG_METER12_RATE_CTRL1    0x1419
+#define    RTL8367C_METER12_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER12_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER13_RATE_CTRL0    0x141a
+
+#define    RTL8367C_REG_METER13_RATE_CTRL1    0x141b
+#define    RTL8367C_METER13_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER13_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER14_RATE_CTRL0    0x141c
+
+#define    RTL8367C_REG_METER14_RATE_CTRL1    0x141d
+#define    RTL8367C_METER14_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER14_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER15_RATE_CTRL0    0x141e
+
+#define    RTL8367C_REG_METER15_RATE_CTRL1    0x141f
+#define    RTL8367C_METER15_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER15_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER16_RATE_CTRL0    0x1420
+
+#define    RTL8367C_REG_METER16_RATE_CTRL1    0x1421
+#define    RTL8367C_METER16_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER16_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER17_RATE_CTRL0    0x1422
+
+#define    RTL8367C_REG_METER17_RATE_CTRL1    0x1423
+#define    RTL8367C_METER17_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER17_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER18_RATE_CTRL0    0x1424
+
+#define    RTL8367C_REG_METER18_RATE_CTRL1    0x1425
+#define    RTL8367C_METER18_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER18_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER19_RATE_CTRL0    0x1426
+
+#define    RTL8367C_REG_METER19_RATE_CTRL1    0x1427
+#define    RTL8367C_METER19_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER19_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER20_RATE_CTRL0    0x1428
+
+#define    RTL8367C_REG_METER20_RATE_CTRL1    0x1429
+#define    RTL8367C_METER20_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER20_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER21_RATE_CTRL0    0x142a
+
+#define    RTL8367C_REG_METER21_RATE_CTRL1    0x142b
+#define    RTL8367C_METER21_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER21_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER22_RATE_CTRL0    0x142c
+
+#define    RTL8367C_REG_METER22_RATE_CTRL1    0x142d
+#define    RTL8367C_METER22_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER22_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER23_RATE_CTRL0    0x142e
+
+#define    RTL8367C_REG_METER23_RATE_CTRL1    0x142f
+#define    RTL8367C_METER23_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER23_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER24_RATE_CTRL0    0x1430
+
+#define    RTL8367C_REG_METER24_RATE_CTRL1    0x1431
+#define    RTL8367C_METER24_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER24_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER25_RATE_CTRL0    0x1432
+
+#define    RTL8367C_REG_METER25_RATE_CTRL1    0x1433
+#define    RTL8367C_METER25_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER25_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER26_RATE_CTRL0    0x1434
+
+#define    RTL8367C_REG_METER26_RATE_CTRL1    0x1435
+#define    RTL8367C_METER26_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER26_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER27_RATE_CTRL0    0x1436
+
+#define    RTL8367C_REG_METER27_RATE_CTRL1    0x1437
+#define    RTL8367C_METER27_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER27_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER28_RATE_CTRL0    0x1438
+
+#define    RTL8367C_REG_METER28_RATE_CTRL1    0x1439
+#define    RTL8367C_METER28_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER28_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER29_RATE_CTRL0    0x143a
+
+#define    RTL8367C_REG_METER29_RATE_CTRL1    0x143b
+#define    RTL8367C_METER29_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER29_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER30_RATE_CTRL0    0x143c
+
+#define    RTL8367C_REG_METER30_RATE_CTRL1    0x143d
+#define    RTL8367C_METER30_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER30_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER31_RATE_CTRL0    0x143e
+
+#define    RTL8367C_REG_METER31_RATE_CTRL1    0x143f
+#define    RTL8367C_METER31_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER31_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER_MODE_SETTING0    0x1440
+
+#define    RTL8367C_REG_METER_MODE_SETTING1    0x1441
+
+#define    RTL8367C_REG_METER_MODE_TOKEN_CFG    0x1442
+#define    RTL8367C_METER_MODE_TOKEN_CFG_OFFSET    0
+#define    RTL8367C_METER_MODE_TOKEN_CFG_MASK    0x7FF
+
+#define    RTL8367C_REG_METER0_BUCKET_SIZE    0x1600
+
+#define    RTL8367C_REG_METER1_BUCKET_SIZE    0x1601
+
+#define    RTL8367C_REG_METER2_BUCKET_SIZE    0x1602
+
+#define    RTL8367C_REG_METER3_BUCKET_SIZE    0x1603
+
+#define    RTL8367C_REG_METER4_BUCKET_SIZE    0x1604
+
+#define    RTL8367C_REG_METER5_BUCKET_SIZE    0x1605
+
+#define    RTL8367C_REG_METER6_BUCKET_SIZE    0x1606
+
+#define    RTL8367C_REG_METER7_BUCKET_SIZE    0x1607
+
+#define    RTL8367C_REG_METER8_BUCKET_SIZE    0x1608
+
+#define    RTL8367C_REG_METER9_BUCKET_SIZE    0x1609
+
+#define    RTL8367C_REG_METER10_BUCKET_SIZE    0x160a
+
+#define    RTL8367C_REG_METER11_BUCKET_SIZE    0x160b
+
+#define    RTL8367C_REG_METER12_BUCKET_SIZE    0x160c
+
+#define    RTL8367C_REG_METER13_BUCKET_SIZE    0x160d
+
+#define    RTL8367C_REG_METER14_BUCKET_SIZE    0x160e
+
+#define    RTL8367C_REG_METER15_BUCKET_SIZE    0x160f
+
+#define    RTL8367C_REG_METER16_BUCKET_SIZE    0x1610
+
+#define    RTL8367C_REG_METER17_BUCKET_SIZE    0x1611
+
+#define    RTL8367C_REG_METER18_BUCKET_SIZE    0x1612
+
+#define    RTL8367C_REG_METER19_BUCKET_SIZE    0x1613
+
+#define    RTL8367C_REG_METER20_BUCKET_SIZE    0x1614
+
+#define    RTL8367C_REG_METER21_BUCKET_SIZE    0x1615
+
+#define    RTL8367C_REG_METER22_BUCKET_SIZE    0x1616
+
+#define    RTL8367C_REG_METER23_BUCKET_SIZE    0x1617
+
+#define    RTL8367C_REG_METER24_BUCKET_SIZE    0x1618
+
+#define    RTL8367C_REG_METER25_BUCKET_SIZE    0x1619
+
+#define    RTL8367C_REG_METER26_BUCKET_SIZE    0x161a
+
+#define    RTL8367C_REG_METER27_BUCKET_SIZE    0x161b
+
+#define    RTL8367C_REG_METER28_BUCKET_SIZE    0x161c
+
+#define    RTL8367C_REG_METER29_BUCKET_SIZE    0x161d
+
+#define    RTL8367C_REG_METER30_BUCKET_SIZE    0x161e
+
+#define    RTL8367C_REG_METER31_BUCKET_SIZE    0x161f
+
+#define    RTL8367C_REG_METER_CTRL0    0x1700
+#define    RTL8367C_METER_OP_OFFSET    8
+#define    RTL8367C_METER_OP_MASK    0x100
+#define    RTL8367C_METER_TICK_OFFSET    0
+#define    RTL8367C_METER_TICK_MASK    0xFF
+
+#define    RTL8367C_REG_METER_CTRL1    0x1701
+#define    RTL8367C_METER_CTRL1_OFFSET    0
+#define    RTL8367C_METER_CTRL1_MASK    0xFF
+
+#define    RTL8367C_REG_METER_OVERRATE_INDICATOR0    0x1702
+
+#define    RTL8367C_REG_METER_OVERRATE_INDICATOR1    0x1703
+
+#define    RTL8367C_REG_METER_OVERRATE_INDICATOR0_8051    0x1704
+
+#define    RTL8367C_REG_METER_OVERRATE_INDICATOR1_8051    0x1705
+
+#define    RTL8367C_REG_METER_IFG_CTRL0    0x1712
+#define    RTL8367C_METER15_IFG_OFFSET    15
+#define    RTL8367C_METER15_IFG_MASK    0x8000
+#define    RTL8367C_METER14_IFG_OFFSET    14
+#define    RTL8367C_METER14_IFG_MASK    0x4000
+#define    RTL8367C_METER13_IFG_OFFSET    13
+#define    RTL8367C_METER13_IFG_MASK    0x2000
+#define    RTL8367C_METER12_IFG_OFFSET    12
+#define    RTL8367C_METER12_IFG_MASK    0x1000
+#define    RTL8367C_METER11_IFG_OFFSET    11
+#define    RTL8367C_METER11_IFG_MASK    0x800
+#define    RTL8367C_METER10_IFG_OFFSET    10
+#define    RTL8367C_METER10_IFG_MASK    0x400
+#define    RTL8367C_METER9_IFG_OFFSET    9
+#define    RTL8367C_METER9_IFG_MASK    0x200
+#define    RTL8367C_METER8_IFG_OFFSET    8
+#define    RTL8367C_METER8_IFG_MASK    0x100
+#define    RTL8367C_METER7_IFG_OFFSET    7
+#define    RTL8367C_METER7_IFG_MASK    0x80
+#define    RTL8367C_METER6_IFG_OFFSET    6
+#define    RTL8367C_METER6_IFG_MASK    0x40
+#define    RTL8367C_METER5_IFG_OFFSET    5
+#define    RTL8367C_METER5_IFG_MASK    0x20
+#define    RTL8367C_METER4_IFG_OFFSET    4
+#define    RTL8367C_METER4_IFG_MASK    0x10
+#define    RTL8367C_METER3_IFG_OFFSET    3
+#define    RTL8367C_METER3_IFG_MASK    0x8
+#define    RTL8367C_METER2_IFG_OFFSET    2
+#define    RTL8367C_METER2_IFG_MASK    0x4
+#define    RTL8367C_METER1_IFG_OFFSET    1
+#define    RTL8367C_METER1_IFG_MASK    0x2
+#define    RTL8367C_METER0_IFG_OFFSET    0
+#define    RTL8367C_METER0_IFG_MASK    0x1
+
+#define    RTL8367C_REG_METER_IFG_CTRL1    0x1713
+#define    RTL8367C_METER31_IFG_OFFSET    15
+#define    RTL8367C_METER31_IFG_MASK    0x8000
+#define    RTL8367C_METER30_IFG_OFFSET    14
+#define    RTL8367C_METER30_IFG_MASK    0x4000
+#define    RTL8367C_METER29_IFG_OFFSET    13
+#define    RTL8367C_METER29_IFG_MASK    0x2000
+#define    RTL8367C_METER28_IFG_OFFSET    12
+#define    RTL8367C_METER28_IFG_MASK    0x1000
+#define    RTL8367C_METER27_IFG_OFFSET    11
+#define    RTL8367C_METER27_IFG_MASK    0x800
+#define    RTL8367C_METER26_IFG_OFFSET    10
+#define    RTL8367C_METER26_IFG_MASK    0x400
+#define    RTL8367C_METER25_IFG_OFFSET    9
+#define    RTL8367C_METER25_IFG_MASK    0x200
+#define    RTL8367C_METER24_IFG_OFFSET    8
+#define    RTL8367C_METER24_IFG_MASK    0x100
+#define    RTL8367C_METER23_IFG_OFFSET    7
+#define    RTL8367C_METER23_IFG_MASK    0x80
+#define    RTL8367C_METER22_IFG_OFFSET    6
+#define    RTL8367C_METER22_IFG_MASK    0x40
+#define    RTL8367C_METER21_IFG_OFFSET    5
+#define    RTL8367C_METER21_IFG_MASK    0x20
+#define    RTL8367C_METER20_IFG_OFFSET    4
+#define    RTL8367C_METER20_IFG_MASK    0x10
+#define    RTL8367C_METER19_IFG_OFFSET    3
+#define    RTL8367C_METER19_IFG_MASK    0x8
+#define    RTL8367C_METER18_IFG_OFFSET    2
+#define    RTL8367C_METER18_IFG_MASK    0x4
+#define    RTL8367C_METER17_IFG_OFFSET    1
+#define    RTL8367C_METER17_IFG_MASK    0x2
+#define    RTL8367C_METER16_IFG_OFFSET    0
+#define    RTL8367C_METER16_IFG_MASK    0x1
+
+#define    RTL8367C_REG_METER_CTRL2    0x1722
+#define    RTL8367C_cfg_mtr_tick_8g_OFFSET    8
+#define    RTL8367C_cfg_mtr_tick_8g_MASK    0xFF00
+#define    RTL8367C_cfg_mtr_dec_cnt_8g_OFFSET    0
+#define    RTL8367C_cfg_mtr_dec_cnt_8g_MASK    0xFF
+
+#define    RTL8367C_REG_DUMMY_1723    0x1723
+
+#define    RTL8367C_REG_DUMMY_1724    0x1724
+
+#define    RTL8367C_REG_DUMMY_1725    0x1725
+
+#define    RTL8367C_REG_DUMMY_1726    0x1726
+
+#define    RTL8367C_REG_DUMMY_1727    0x1727
+
+#define    RTL8367C_REG_DUMMY_1728    0x1728
+
+#define    RTL8367C_REG_DUMMY_1729    0x1729
+
+#define    RTL8367C_REG_DUMMY_172A    0x172a
+
+#define    RTL8367C_REG_DUMMY_172B    0x172b
+
+#define    RTL8367C_REG_DUMMY_172C    0x172c
+
+#define    RTL8367C_REG_DUMMY_172D    0x172d
+
+#define    RTL8367C_REG_DUMMY_172E    0x172e
+
+#define    RTL8367C_REG_DUMMY_172F    0x172f
+
+#define    RTL8367C_REG_DUMMY_1730    0x1730
+
+#define    RTL8367C_REG_DUMMY_1731    0x1731
+
+#define    RTL8367C_REG_METER32_RATE_CTRL0    0x1740
+
+#define    RTL8367C_REG_METER32_RATE_CTRL1    0x1741
+#define    RTL8367C_METER32_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER32_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER33_RATE_CTRL0    0x1742
+
+#define    RTL8367C_REG_METER33_RATE_CTRL1    0x1743
+#define    RTL8367C_METER33_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER33_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER34_RATE_CTRL0    0x1744
+
+#define    RTL8367C_REG_METER34_RATE_CTRL1    0x1745
+#define    RTL8367C_METER34_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER34_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER35_RATE_CTRL0    0x1746
+
+#define    RTL8367C_REG_METER35_RATE_CTRL1    0x1747
+#define    RTL8367C_METER35_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER35_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER36_RATE_CTRL0    0x1748
+
+#define    RTL8367C_REG_METER36_RATE_CTRL1    0x1749
+#define    RTL8367C_METER36_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER36_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER37_RATE_CTRL0    0x174a
+
+#define    RTL8367C_REG_METER37_RATE_CTRL1    0x174b
+#define    RTL8367C_METER37_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER37_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER38_RATE_CTRL0    0x174c
+
+#define    RTL8367C_REG_METER38_RATE_CTRL1    0x174d
+#define    RTL8367C_METER38_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER38_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER39_RATE_CTRL0    0x174e
+
+#define    RTL8367C_REG_METER39_RATE_CTRL1    0x174f
+#define    RTL8367C_METER39_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER39_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER40_RATE_CTRL0    0x1750
+
+#define    RTL8367C_REG_METER40_RATE_CTRL1    0x1751
+#define    RTL8367C_METER40_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER40_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER41_RATE_CTRL0    0x1752
+
+#define    RTL8367C_REG_METER41_RATE_CTRL1    0x1753
+#define    RTL8367C_METER41_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER41_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER42_RATE_CTRL0    0x1754
+
+#define    RTL8367C_REG_METER42_RATE_CTRL1    0x1755
+#define    RTL8367C_METER42_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER42_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER43_RATE_CTRL0    0x1756
+
+#define    RTL8367C_REG_METER43_RATE_CTRL1    0x1757
+#define    RTL8367C_METER43_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER43_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER44_RATE_CTRL0    0x1758
+
+#define    RTL8367C_REG_METER44_RATE_CTRL1    0x1759
+#define    RTL8367C_METER44_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER44_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER45_RATE_CTRL0    0x175a
+
+#define    RTL8367C_REG_METER45_RATE_CTRL1    0x175b
+#define    RTL8367C_METER45_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER45_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER46_RATE_CTRL0    0x175c
+
+#define    RTL8367C_REG_METER46_RATE_CTRL1    0x175d
+#define    RTL8367C_METER46_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER46_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER47_RATE_CTRL0    0x175e
+
+#define    RTL8367C_REG_METER47_RATE_CTRL1    0x175f
+#define    RTL8367C_METER47_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER47_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER48_RATE_CTRL0    0x1760
+
+#define    RTL8367C_REG_METER48_RATE_CTRL1    0x1761
+#define    RTL8367C_METER48_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER48_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER49_RATE_CTRL0    0x1762
+
+#define    RTL8367C_REG_METER49_RATE_CTRL1    0x1763
+#define    RTL8367C_METER49_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER49_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER50_RATE_CTRL0    0x1764
+
+#define    RTL8367C_REG_METER50_RATE_CTRL1    0x1765
+#define    RTL8367C_METER50_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER50_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER51_RATE_CTRL0    0x1766
+
+#define    RTL8367C_REG_METER51_RATE_CTRL1    0x1767
+#define    RTL8367C_METER51_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER51_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER52_RATE_CTRL0    0x1768
+
+#define    RTL8367C_REG_METER52_RATE_CTRL1    0x1769
+#define    RTL8367C_METER52_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER52_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER53_RATE_CTRL0    0x176a
+
+#define    RTL8367C_REG_METER53_RATE_CTRL1    0x176b
+#define    RTL8367C_METER53_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER53_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER54_RATE_CTRL0    0x176c
+
+#define    RTL8367C_REG_METER54_RATE_CTRL1    0x176d
+#define    RTL8367C_METER54_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER54_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER55_RATE_CTRL0    0x176e
+
+#define    RTL8367C_REG_METER55_RATE_CTRL1    0x176f
+#define    RTL8367C_METER55_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER55_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER56_RATE_CTRL0    0x1770
+
+#define    RTL8367C_REG_METER56_RATE_CTRL1    0x1771
+#define    RTL8367C_METER56_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER56_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER57_RATE_CTRL0    0x1772
+
+#define    RTL8367C_REG_METER57_RATE_CTRL1    0x1773
+#define    RTL8367C_METER57_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER57_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER58_RATE_CTRL0    0x1774
+
+#define    RTL8367C_REG_METER58_RATE_CTRL1    0x1775
+#define    RTL8367C_METER58_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER58_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER59_RATE_CTRL0    0x1776
+
+#define    RTL8367C_REG_METER59_RATE_CTRL1    0x1777
+#define    RTL8367C_METER59_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER59_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER60_RATE_CTRL0    0x1778
+
+#define    RTL8367C_REG_METER60_RATE_CTRL1    0x1779
+#define    RTL8367C_METER60_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER60_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER61_RATE_CTRL0    0x177a
+
+#define    RTL8367C_REG_METER61_RATE_CTRL1    0x177b
+#define    RTL8367C_METER61_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER61_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER62_RATE_CTRL0    0x177c
+
+#define    RTL8367C_REG_METER62_RATE_CTRL1    0x177d
+#define    RTL8367C_METER62_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER62_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER63_RATE_CTRL0    0x177e
+
+#define    RTL8367C_REG_METER63_RATE_CTRL1    0x177f
+#define    RTL8367C_METER63_RATE_CTRL1_OFFSET    0
+#define    RTL8367C_METER63_RATE_CTRL1_MASK    0x7
+
+#define    RTL8367C_REG_METER_MODE_SETTING2    0x1780
+
+#define    RTL8367C_REG_METER_MODE_SETTING3    0x1781
+
+#define    RTL8367C_REG_METER32_BUCKET_SIZE    0x1790
+
+#define    RTL8367C_REG_METER33_BUCKET_SIZE    0x1791
+
+#define    RTL8367C_REG_METER34_BUCKET_SIZE    0x1792
+
+#define    RTL8367C_REG_METER35_BUCKET_SIZE    0x1793
+
+#define    RTL8367C_REG_METER36_BUCKET_SIZE    0x1794
+
+#define    RTL8367C_REG_METER37_BUCKET_SIZE    0x1795
+
+#define    RTL8367C_REG_METER38_BUCKET_SIZE    0x1796
+
+#define    RTL8367C_REG_METER39_BUCKET_SIZE    0x1797
+
+#define    RTL8367C_REG_METER40_BUCKET_SIZE    0x1798
+
+#define    RTL8367C_REG_METER41_BUCKET_SIZE    0x1799
+
+#define    RTL8367C_REG_METER42_BUCKET_SIZE    0x179a
+
+#define    RTL8367C_REG_METER43_BUCKET_SIZE    0x179b
+
+#define    RTL8367C_REG_METER44_BUCKET_SIZE    0x179c
+
+#define    RTL8367C_REG_METER45_BUCKET_SIZE    0x179d
+
+#define    RTL8367C_REG_METER46_BUCKET_SIZE    0x179e
+
+#define    RTL8367C_REG_METER47_BUCKET_SIZE    0x179f
+
+#define    RTL8367C_REG_METER48_BUCKET_SIZE    0x17a0
+
+#define    RTL8367C_REG_METER49_BUCKET_SIZE    0x17a1
+
+#define    RTL8367C_REG_METER50_BUCKET_SIZE    0x17a2
+
+#define    RTL8367C_REG_METER51_BUCKET_SIZE    0x17a3
+
+#define    RTL8367C_REG_METER52_BUCKET_SIZE    0x17a4
+
+#define    RTL8367C_REG_METER53_BUCKET_SIZE    0x17a5
+
+#define    RTL8367C_REG_METER54_BUCKET_SIZE    0x17a6
+
+#define    RTL8367C_REG_METER55_BUCKET_SIZE    0x17a7
+
+#define    RTL8367C_REG_METER56_BUCKET_SIZE    0x17a8
+
+#define    RTL8367C_REG_METER57_BUCKET_SIZE    0x17a9
+
+#define    RTL8367C_REG_METER58_BUCKET_SIZE    0x17aa
+
+#define    RTL8367C_REG_METER59_BUCKET_SIZE    0x17ab
+
+#define    RTL8367C_REG_METER60_BUCKET_SIZE    0x17ac
+
+#define    RTL8367C_REG_METER61_BUCKET_SIZE    0x17ad
+
+#define    RTL8367C_REG_METER62_BUCKET_SIZE    0x17ae
+
+#define    RTL8367C_REG_METER63_BUCKET_SIZE    0x17af
+
+#define    RTL8367C_REG_METER_OVERRATE_INDICATOR2    0x17b0
+
+#define    RTL8367C_REG_METER_OVERRATE_INDICATOR3    0x17b1
+
+#define    RTL8367C_REG_METER_OVERRATE_INDICATOR2_8051    0x17b2
+
+#define    RTL8367C_REG_METER_OVERRATE_INDICATOR3_8051    0x17b3
+
+#define    RTL8367C_REG_METER_IFG_CTRL2    0x17b4
+#define    RTL8367C_METER47_IFG_OFFSET    15
+#define    RTL8367C_METER47_IFG_MASK    0x8000
+#define    RTL8367C_METER46_IFG_OFFSET    14
+#define    RTL8367C_METER46_IFG_MASK    0x4000
+#define    RTL8367C_METER45_IFG_OFFSET    13
+#define    RTL8367C_METER45_IFG_MASK    0x2000
+#define    RTL8367C_METER44_IFG_OFFSET    12
+#define    RTL8367C_METER44_IFG_MASK    0x1000
+#define    RTL8367C_METER43_IFG_OFFSET    11
+#define    RTL8367C_METER43_IFG_MASK    0x800
+#define    RTL8367C_METER42_IFG_OFFSET    10
+#define    RTL8367C_METER42_IFG_MASK    0x400
+#define    RTL8367C_METER41_IFG_OFFSET    9
+#define    RTL8367C_METER41_IFG_MASK    0x200
+#define    RTL8367C_METER40_IFG_OFFSET    8
+#define    RTL8367C_METER40_IFG_MASK    0x100
+#define    RTL8367C_METER39_IFG_OFFSET    7
+#define    RTL8367C_METER39_IFG_MASK    0x80
+#define    RTL8367C_METER38_IFG_OFFSET    6
+#define    RTL8367C_METER38_IFG_MASK    0x40
+#define    RTL8367C_METER37_IFG_OFFSET    5
+#define    RTL8367C_METER37_IFG_MASK    0x20
+#define    RTL8367C_METER36_IFG_OFFSET    4
+#define    RTL8367C_METER36_IFG_MASK    0x10
+#define    RTL8367C_METER35_IFG_OFFSET    3
+#define    RTL8367C_METER35_IFG_MASK    0x8
+#define    RTL8367C_METER34_IFG_OFFSET    2
+#define    RTL8367C_METER34_IFG_MASK    0x4
+#define    RTL8367C_METER33_IFG_OFFSET    1
+#define    RTL8367C_METER33_IFG_MASK    0x2
+#define    RTL8367C_METER32_IFG_OFFSET    0
+#define    RTL8367C_METER32_IFG_MASK    0x1
+
+#define    RTL8367C_REG_METER_IFG_CTRL3    0x17b5
+#define    RTL8367C_METER63_IFG_OFFSET    15
+#define    RTL8367C_METER63_IFG_MASK    0x8000
+#define    RTL8367C_METER62_IFG_OFFSET    14
+#define    RTL8367C_METER62_IFG_MASK    0x4000
+#define    RTL8367C_METER61_IFG_OFFSET    13
+#define    RTL8367C_METER61_IFG_MASK    0x2000
+#define    RTL8367C_METER60_IFG_OFFSET    12
+#define    RTL8367C_METER60_IFG_MASK    0x1000
+#define    RTL8367C_METER59_IFG_OFFSET    11
+#define    RTL8367C_METER59_IFG_MASK    0x800
+#define    RTL8367C_METER58_IFG_OFFSET    10
+#define    RTL8367C_METER58_IFG_MASK    0x400
+#define    RTL8367C_METER57_IFG_OFFSET    9
+#define    RTL8367C_METER57_IFG_MASK    0x200
+#define    RTL8367C_METER56_IFG_OFFSET    8
+#define    RTL8367C_METER56_IFG_MASK    0x100
+#define    RTL8367C_METER55_IFG_OFFSET    7
+#define    RTL8367C_METER55_IFG_MASK    0x80
+#define    RTL8367C_METER54_IFG_OFFSET    6
+#define    RTL8367C_METER54_IFG_MASK    0x40
+#define    RTL8367C_METER53_IFG_OFFSET    5
+#define    RTL8367C_METER53_IFG_MASK    0x20
+#define    RTL8367C_METER52_IFG_OFFSET    4
+#define    RTL8367C_METER52_IFG_MASK    0x10
+#define    RTL8367C_METER51_IFG_OFFSET    3
+#define    RTL8367C_METER51_IFG_MASK    0x8
+#define    RTL8367C_METER50_IFG_OFFSET    2
+#define    RTL8367C_METER50_IFG_MASK    0x4
+#define    RTL8367C_METER49_IFG_OFFSET    1
+#define    RTL8367C_METER49_IFG_MASK    0x2
+#define    RTL8367C_METER48_IFG_OFFSET    0
+#define    RTL8367C_METER48_IFG_MASK    0x1
+
+#define    RTL8367C_REG_METER_MISC    0x17b6
+#define    RTL8367C_METER_MISC_OFFSET    0
+#define    RTL8367C_METER_MISC_MASK    0x1
+
+/* (16'h1800)8051_RLDP_EEE_reg */
+
+#define    RTL8367C_REG_EEELLDP_CTRL0    0x1820
+#define    RTL8367C_EEELLDP_SUBTYPE_OFFSET    6
+#define    RTL8367C_EEELLDP_SUBTYPE_MASK    0x3FC0
+#define    RTL8367C_EEELLDP_TRAP_8051_OFFSET    2
+#define    RTL8367C_EEELLDP_TRAP_8051_MASK    0x4
+#define    RTL8367C_EEELLDP_TRAP_CPU_OFFSET    1
+#define    RTL8367C_EEELLDP_TRAP_CPU_MASK    0x2
+#define    RTL8367C_EEELLDP_ENABLE_OFFSET    0
+#define    RTL8367C_EEELLDP_ENABLE_MASK    0x1
+
+#define    RTL8367C_REG_EEELLDP_PMSK    0x1822
+#define    RTL8367C_EEELLDP_PMSK_OFFSET    0
+#define    RTL8367C_EEELLDP_PMSK_MASK    0x7FF
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P00_08    0x1843
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P00_07    0x1844
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P00_06    0x1845
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P00_05    0x1846
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P00_04    0x1847
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P00_03    0x1848
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P00_02    0x1849
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P00_01    0x184a
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P00_00    0x184b
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P01_08    0x184c
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P01_07    0x184d
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P01_06    0x184e
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P01_05    0x184f
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P01_04    0x1850
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P01_03    0x1851
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P01_02    0x1852
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P01_01    0x1853
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P01_00    0x1854
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P02_08    0x1855
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P02_07    0x1856
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P02_06    0x1857
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P02_05    0x1858
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P02_04    0x1859
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P02_03    0x185a
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P02_02    0x185b
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P02_01    0x185c
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P02_00    0x185d
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P03_08    0x185e
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P03_07    0x185f
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P03_06    0x1860
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P03_05    0x1861
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P03_04    0x1862
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P03_03    0x1863
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P03_02    0x1864
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P03_01    0x1865
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P03_00    0x1866
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P04_08    0x1867
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P04_07    0x1868
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P04_06    0x1869
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P04_05    0x186a
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P04_04    0x186b
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P04_03    0x186c
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P04_02    0x186d
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P04_01    0x186e
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P04_00    0x186f
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P05_08    0x1870
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P05_07    0x1871
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P05_06    0x1872
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P05_05    0x1873
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P05_04    0x1874
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P05_03    0x1875
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P05_02    0x1876
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P05_01    0x1877
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P05_00    0x1878
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P06_08    0x1879
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P06_07    0x187a
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P06_06    0x187b
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P06_05    0x187c
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P06_04    0x187d
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P06_03    0x187e
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P06_02    0x187f
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P06_01    0x1880
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P06_00    0x1881
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P07_08    0x1882
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P07_07    0x1883
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P07_06    0x1884
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P07_05    0x1885
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P07_04    0x1886
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P07_03    0x1887
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P07_02    0x1888
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P07_01    0x1889
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P07_00    0x188a
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P08_08    0x188b
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P08_07    0x188c
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P08_06    0x188d
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P08_05    0x188e
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P08_04    0x188f
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P08_03    0x1890
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P08_02    0x1891
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P08_01    0x1892
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P08_00    0x1893
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P09_08    0x1894
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P09_07    0x1895
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P09_06    0x1896
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P09_05    0x1897
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P09_04    0x1898
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P09_03    0x1899
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P09_02    0x189a
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P09_01    0x189b
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P09_00    0x189c
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P10_08    0x189d
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P10_07    0x189e
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P10_06    0x189f
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P10_05    0x18a0
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P10_04    0x18a1
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P10_03    0x18a2
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P10_02    0x18a3
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P10_01    0x18a4
+
+#define    RTL8367C_REG_EEELLDP_RX_VALUE_P10_00    0x18a5
+
+#define    RTL8367C_REG_RLDP_CTRL0    0x18e0
+#define    RTL8367C_RLDP_TRIGGER_MODE_OFFSET    14
+#define    RTL8367C_RLDP_TRIGGER_MODE_MASK    0x4000
+#define    RTL8367C_RLDP_8051_LOOP_PORTMSK_OFFSET    6
+#define    RTL8367C_RLDP_8051_LOOP_PORTMSK_MASK    0x3FC0
+#define    RTL8367C_RLPP_8051_TRAP_OFFSET    5
+#define    RTL8367C_RLPP_8051_TRAP_MASK    0x20
+#define    RTL8367C_RLDP_INDICATOR_SOURCE_OFFSET    4
+#define    RTL8367C_RLDP_INDICATOR_SOURCE_MASK    0x10
+#define    RTL8367C_RLDP_GEN_RANDOM_OFFSET    3
+#define    RTL8367C_RLDP_GEN_RANDOM_MASK    0x8
+#define    RTL8367C_RLDP_COMP_ID_OFFSET    2
+#define    RTL8367C_RLDP_COMP_ID_MASK    0x4
+#define    RTL8367C_RLDP_8051_ENABLE_OFFSET    1
+#define    RTL8367C_RLDP_8051_ENABLE_MASK    0x2
+#define    RTL8367C_RLDP_ENABLE_OFFSET    0
+#define    RTL8367C_RLDP_ENABLE_MASK    0x1
+
+#define    RTL8367C_REG_RLDP_CTRL1    0x18e1
+#define    RTL8367C_RLDP_RETRY_COUNT_LOOPSTATE_OFFSET    8
+#define    RTL8367C_RLDP_RETRY_COUNT_LOOPSTATE_MASK    0xFF00
+#define    RTL8367C_RLDP_RETRY_COUNT_CHKSTATE_OFFSET    0
+#define    RTL8367C_RLDP_RETRY_COUNT_CHKSTATE_MASK    0xFF
+
+#define    RTL8367C_REG_RLDP_CTRL2    0x18e2
+
+#define    RTL8367C_REG_RLDP_CTRL3    0x18e3
+
+#define    RTL8367C_REG_RLDP_CTRL4    0x18e4
+#define    RTL8367C_RLDP_CTRL4_OFFSET    0
+#define    RTL8367C_RLDP_CTRL4_MASK    0x7FF
+
+#define    RTL8367C_REG_RLDP_RAND_NUM0    0x18e5
+
+#define    RTL8367C_REG_RLDP_RAND_NUM1    0x18e6
+
+#define    RTL8367C_REG_RLDP_RAND_NUM2    0x18e7
+
+#define    RTL8367C_REG_RLDP_MAGIC_NUM0    0x18e8
+
+#define    RTL8367C_REG_RLDP_MAGIC_NUM1    0x18e9
+
+#define    RTL8367C_REG_RLDP_MAGIC_NUM2    0x18ea
+
+#define    RTL8367C_REG_RLDP_LOOPED_INDICATOR    0x18eb
+#define    RTL8367C_RLDP_LOOPED_INDICATOR_OFFSET    0
+#define    RTL8367C_RLDP_LOOPED_INDICATOR_MASK    0x7FF
+
+#define    RTL8367C_REG_RLDP_LOOP_PORT_REG0    0x18ec
+#define    RTL8367C_RLDP_LOOP_PORT_01_OFFSET    8
+#define    RTL8367C_RLDP_LOOP_PORT_01_MASK    0xF00
+#define    RTL8367C_RLDP_LOOP_PORT_00_OFFSET    0
+#define    RTL8367C_RLDP_LOOP_PORT_00_MASK    0xF
+
+#define    RTL8367C_REG_RLDP_LOOP_PORT_REG1    0x18ed
+#define    RTL8367C_RLDP_LOOP_PORT_03_OFFSET    8
+#define    RTL8367C_RLDP_LOOP_PORT_03_MASK    0xF00
+#define    RTL8367C_RLDP_LOOP_PORT_02_OFFSET    0
+#define    RTL8367C_RLDP_LOOP_PORT_02_MASK    0xF
+
+#define    RTL8367C_REG_RLDP_LOOP_PORT_REG2    0x18ee
+#define    RTL8367C_RLDP_LOOP_PORT_05_OFFSET    8
+#define    RTL8367C_RLDP_LOOP_PORT_05_MASK    0xF00
+#define    RTL8367C_RLDP_LOOP_PORT_04_OFFSET    0
+#define    RTL8367C_RLDP_LOOP_PORT_04_MASK    0xF
+
+#define    RTL8367C_REG_RLDP_LOOP_PORT_REG3    0x18ef
+#define    RTL8367C_RLDP_LOOP_PORT_07_OFFSET    8
+#define    RTL8367C_RLDP_LOOP_PORT_07_MASK    0xF00
+#define    RTL8367C_RLDP_LOOP_PORT_06_OFFSET    0
+#define    RTL8367C_RLDP_LOOP_PORT_06_MASK    0xF
+
+#define    RTL8367C_REG_RLDP_RELEASED_INDICATOR    0x18f0
+#define    RTL8367C_RLDP_RELEASED_INDICATOR_OFFSET    0
+#define    RTL8367C_RLDP_RELEASED_INDICATOR_MASK    0x7FF
+
+#define    RTL8367C_REG_RLDP_LOOPSTATUS_INDICATOR    0x18f1
+#define    RTL8367C_RLDP_LOOPSTATUS_INDICATOR_OFFSET    0
+#define    RTL8367C_RLDP_LOOPSTATUS_INDICATOR_MASK    0x7FF
+
+#define    RTL8367C_REG_RLDP_LOOP_PORT_REG4    0x18f2
+#define    RTL8367C_RLDP_LOOP_PORT_9_OFFSET    8
+#define    RTL8367C_RLDP_LOOP_PORT_9_MASK    0xF00
+#define    RTL8367C_RLDP_LOOP_PORT_8_OFFSET    0
+#define    RTL8367C_RLDP_LOOP_PORT_8_MASK    0xF
+
+#define    RTL8367C_REG_RLDP_LOOP_PORT_REG5    0x18f3
+#define    RTL8367C_RLDP_LOOP_PORT_REG5_OFFSET    0
+#define    RTL8367C_RLDP_LOOP_PORT_REG5_MASK    0xF
+
+#define    RTL8367C_REG_RLDP_CTRL5    0x18f4
+#define    RTL8367C_RLDP_CTRL5_OFFSET    0
+#define    RTL8367C_RLDP_CTRL5_MASK    0x7
+
+/* (16'h1900)EEE_EEEP_reg */
+
+#define    RTL8367C_REG_EEE_500M_CTRL0    0x1900
+#define    RTL8367C_EEE_500M_CTRL0_OFFSET    0
+#define    RTL8367C_EEE_500M_CTRL0_MASK    0xFF
+
+#define    RTL8367C_REG_EEE_RXIDLE_GIGA_CTRL    0x1901
+#define    RTL8367C_EEE_RXIDLE_GIGA_EN_OFFSET    8
+#define    RTL8367C_EEE_RXIDLE_GIGA_EN_MASK    0x100
+#define    RTL8367C_EEE_RXIDLE_GIGA_OFFSET    0
+#define    RTL8367C_EEE_RXIDLE_GIGA_MASK    0xFF
+
+#define    RTL8367C_REG_EEE_RXIDLE_500M_CTRL    0x1902
+#define    RTL8367C_EEE_RXIDLE_500M_EN_OFFSET    8
+#define    RTL8367C_EEE_RXIDLE_500M_EN_MASK    0x100
+#define    RTL8367C_EEE_RXIDLE_500M_OFFSET    0
+#define    RTL8367C_EEE_RXIDLE_500M_MASK    0xFF
+
+#define    RTL8367C_REG_EEE_DECISION_GIGA_500M    0x1903
+#define    RTL8367C_EEE_DECISION_GIGA_OFFSET    8
+#define    RTL8367C_EEE_DECISION_GIGA_MASK    0xFF00
+#define    RTL8367C_EEE_DECISION_500M_OFFSET    0
+#define    RTL8367C_EEE_DECISION_500M_MASK    0xFF
+
+#define    RTL8367C_REG_EEE_DECISION_100M    0x1904
+#define    RTL8367C_EEE_DECISION_100M_OFFSET    0
+#define    RTL8367C_EEE_DECISION_100M_MASK    0xFF
+
+#define    RTL8367C_REG_EEEP_DEFER_TXLPI    0x1905
+#define    RTL8367C_EEEP_DEFER_TXLPI_OFFSET    0
+#define    RTL8367C_EEEP_DEFER_TXLPI_MASK    0x1
+
+#define    RTL8367C_REG_EEEP_EN    0x1906
+#define    RTL8367C_EEEP_SLAVE_EN_OFFSET    3
+#define    RTL8367C_EEEP_SLAVE_EN_MASK    0x8
+#define    RTL8367C_EEEP_100M_OFFSET    2
+#define    RTL8367C_EEEP_100M_MASK    0x4
+#define    RTL8367C_EEEP_500M_OFFSET    1
+#define    RTL8367C_EEEP_500M_MASK    0x2
+#define    RTL8367C_EEEP_GIGA_OFFSET    0
+#define    RTL8367C_EEEP_GIGA_MASK    0x1
+
+#define    RTL8367C_REG_EEEP_TI_GIGA_500M    0x1907
+#define    RTL8367C_EEEP_TI_GIGA_OFFSET    8
+#define    RTL8367C_EEEP_TI_GIGA_MASK    0xFF00
+#define    RTL8367C_EEEP_TI_500M_OFFSET    0
+#define    RTL8367C_EEEP_TI_500M_MASK    0xFF
+
+#define    RTL8367C_REG_EEEP_TI_100M    0x1908
+#define    RTL8367C_EEEP_TI_100M_OFFSET    0
+#define    RTL8367C_EEEP_TI_100M_MASK    0xFF
+
+#define    RTL8367C_REG_EEEP_CTRL2    0x1909
+#define    RTL8367C_EEEP_CTRL2_OFFSET    0
+#define    RTL8367C_EEEP_CTRL2_MASK    0xFF
+
+#define    RTL8367C_REG_EEEP_RX_RATE_500M    0x190b
+
+#define    RTL8367C_REG_EEEP_RW_GIGA_SLV    0x190c
+#define    RTL8367C_EEEP_RW_GIGA_SLV_OFFSET    0
+#define    RTL8367C_EEEP_RW_GIGA_SLV_MASK    0xFF
+
+#define    RTL8367C_REG_EEEP_TMR_GIGA    0x190d
+#define    RTL8367C_RX_IDLE_EEEP_GIGA_OFFSET    8
+#define    RTL8367C_RX_IDLE_EEEP_GIGA_MASK    0xFF00
+#define    RTL8367C_RX_MIN_SLP_TMR_GIGA_OFFSET    0
+#define    RTL8367C_RX_MIN_SLP_TMR_GIGA_MASK    0xFF
+
+#define    RTL8367C_REG_EEEP_TMR_500M    0x190e
+#define    RTL8367C_RX_IDLE_EEEP_500M_OFFSET    8
+#define    RTL8367C_RX_IDLE_EEEP_500M_MASK    0xFF00
+#define    RTL8367C_RX_MIN_SLP_TMR_500M_OFFSET    0
+#define    RTL8367C_RX_MIN_SLP_TMR_500M_MASK    0xFF
+
+#define    RTL8367C_REG_EEEP_TMR_100M    0x190f
+#define    RTL8367C_RX_IDLE_EEEP_100M_OFFSET    8
+#define    RTL8367C_RX_IDLE_EEEP_100M_MASK    0xFF00
+#define    RTL8367C_RX_MIN_SLP_TMR_100M_OFFSET    0
+#define    RTL8367C_RX_MIN_SLP_TMR_100M_MASK    0xFF
+
+#define    RTL8367C_REG_EEEP_RW_500M_MST_SLV    0x1910
+#define    RTL8367C_EEEP_RW_500M_MST_OFFSET    8
+#define    RTL8367C_EEEP_RW_500M_MST_MASK    0xFF00
+#define    RTL8367C_EEEP_RW_500M_SLV_OFFSET    0
+#define    RTL8367C_EEEP_RW_500M_SLV_MASK    0xFF
+
+#define    RTL8367C_REG_EEEP_500M_CTRL0    0x1911
+#define    RTL8367C_EEEP_500M_CTRL0_OFFSET    0
+#define    RTL8367C_EEEP_500M_CTRL0_MASK    0xFF
+
+#define    RTL8367C_REG_EEEP_500M_CTRL1    0x1912
+#define    RTL8367C_EEEP_TW_500M_OFFSET    8
+#define    RTL8367C_EEEP_TW_500M_MASK    0xFF00
+#define    RTL8367C_EEEP_TP_500M_OFFSET    0
+#define    RTL8367C_EEEP_TP_500M_MASK    0xFF
+
+#define    RTL8367C_REG_EEEP_500M_CTRL2    0x1913
+#define    RTL8367C_EEEP_TXEN_500M_OFFSET    12
+#define    RTL8367C_EEEP_TXEN_500M_MASK    0x1000
+#define    RTL8367C_EEEP_TU_500M_OFFSET    8
+#define    RTL8367C_EEEP_TU_500M_MASK    0x300
+#define    RTL8367C_EEEP_TS_500M_OFFSET    0
+#define    RTL8367C_EEEP_TS_500M_MASK    0xFF
+
+#define    RTL8367C_REG_EEE_NEW_CTRL0    0x1914
+#define    RTL8367C_LINK_UP_DELAY_OFFSET    3
+#define    RTL8367C_LINK_UP_DELAY_MASK    0x18
+#define    RTL8367C_EEE_TXLPI_ORI_OFFSET    2
+#define    RTL8367C_EEE_TXLPI_ORI_MASK    0x4
+#define    RTL8367C_REALTX_SEL_OFFSET    1
+#define    RTL8367C_REALTX_SEL_MASK    0x2
+#define    RTL8367C_EN_FC_EFCT_OFFSET    0
+#define    RTL8367C_EN_FC_EFCT_MASK    0x1
+
+#define    RTL8367C_REG_EEE_LONGIDLE_100M    0x1915
+#define    RTL8367C_EEE_LONGIDLE_100M_OFFSET    0
+#define    RTL8367C_EEE_LONGIDLE_100M_MASK    0x3FF
+
+#define    RTL8367C_REG_EEE_LONGIDLE_500M    0x1916
+#define    RTL8367C_EEE_LONGIDLE_500M_OFFSET    0
+#define    RTL8367C_EEE_LONGIDLE_500M_MASK    0x3FF
+
+#define    RTL8367C_REG_EEE_LONGIDLE_GIGA    0x1917
+#define    RTL8367C_EEE_LONGIDLE_GIGA_OFFSET    0
+#define    RTL8367C_EEE_LONGIDLE_GIGA_MASK    0x3FF
+
+#define    RTL8367C_REG_EEE_MINIPG_100M    0x1918
+
+#define    RTL8367C_REG_EEE_MINIPG_500M    0x1919
+
+#define    RTL8367C_REG_EEE_MINIPG_GIGA    0x191A
+
+#define    RTL8367C_REG_EEE_LONGIDLE_CTRL0    0x191B
+#define    RTL8367C_TX_IDLEN_REQ_100M_OFFSET    10
+#define    RTL8367C_TX_IDLEN_REQ_100M_MASK    0x400
+#define    RTL8367C_TX_IDLEN_REQ_500M_OFFSET    9
+#define    RTL8367C_TX_IDLEN_REQ_500M_MASK    0x200
+#define    RTL8367C_TX_IDLEN_REQ_GIGA_OFFSET    8
+#define    RTL8367C_TX_IDLEN_REQ_GIGA_MASK    0x100
+#define    RTL8367C_EEE_LONGIDLE_CTRL0_TX_LPI_MINIPG_100M_OFFSET    0
+#define    RTL8367C_EEE_LONGIDLE_CTRL0_TX_LPI_MINIPG_100M_MASK    0xFF
+
+#define    RTL8367C_REG_EEE_LONGIDLE_CTRL1    0x191C
+#define    RTL8367C_EEE_LONGIDLE_CTRL1_TX_LPI_MINIPG_GELITE_OFFSET    8
+#define    RTL8367C_EEE_LONGIDLE_CTRL1_TX_LPI_MINIPG_GELITE_MASK    0xFF00
+#define    RTL8367C_EEE_LONGIDLE_CTRL1_TX_LPI_MINIPG_GIGA_OFFSET    0
+#define    RTL8367C_EEE_LONGIDLE_CTRL1_TX_LPI_MINIPG_GIGA_MASK    0xFF
+
+#define    RTL8367C_REG_EEE_TD_CTRL_H    0x191d
+#define    RTL8367C_REF_RXLPI_OFFSET    8
+#define    RTL8367C_REF_RXLPI_MASK    0x100
+#define    RTL8367C_LOW_Q_TX_DELAY_GE_500M_H_OFFSET    4
+#define    RTL8367C_LOW_Q_TX_DELAY_GE_500M_H_MASK    0xF0
+#define    RTL8367C_LOW_Q_TX_DELAY_FE_H_OFFSET    0
+#define    RTL8367C_LOW_Q_TX_DELAY_FE_H_MASK    0xF
+
+/* (16'h1a00)nic_reg */
+
+#define    RTL8367C_REG_NIC_RXRDRL    0x1a04
+#define    RTL8367C_NIC_RXRDRL_OFFSET    0
+#define    RTL8367C_NIC_RXRDRL_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_RXRDRH    0x1a05
+#define    RTL8367C_NIC_RXRDRH_OFFSET    0
+#define    RTL8367C_NIC_RXRDRH_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_TXASRL    0x1a08
+#define    RTL8367C_NIC_TXASRL_OFFSET    0
+#define    RTL8367C_NIC_TXASRL_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_TXASRH    0x1a09
+#define    RTL8367C_NIC_TXASRH_OFFSET    0
+#define    RTL8367C_NIC_TXASRH_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_RXCMDR    0x1a0c
+#define    RTL8367C_NIC_RXCMDR_OFFSET    0
+#define    RTL8367C_NIC_RXCMDR_MASK    0x1
+
+#define    RTL8367C_REG_NIC_TXCMDR    0x1a0d
+#define    RTL8367C_NIC_TXCMDR_OFFSET    0
+#define    RTL8367C_NIC_TXCMDR_MASK    0x1
+
+#define    RTL8367C_REG_NIC_IMS    0x1a0e
+#define    RTL8367C_NIC_RXIS_OFFSET    7
+#define    RTL8367C_NIC_RXIS_MASK    0x80
+#define    RTL8367C_NIC_TXIS_OFFSET    6
+#define    RTL8367C_NIC_TXIS_MASK    0x40
+#define    RTL8367C_NIC_TXES_OFFSET    5
+#define    RTL8367C_NIC_TXES_MASK    0x20
+#define    RTL8367C_NIC_IMS_DMY_OFFSET    4
+#define    RTL8367C_NIC_IMS_DMY_MASK    0x10
+#define    RTL8367C_NIC_RXBUS_OFFSET    3
+#define    RTL8367C_NIC_RXBUS_MASK    0x8
+#define    RTL8367C_NIC_TXBOS_OFFSET    2
+#define    RTL8367C_NIC_TXBOS_MASK    0x4
+#define    RTL8367C_NIC_RXMIS_OFFSET    1
+#define    RTL8367C_NIC_RXMIS_MASK    0x2
+#define    RTL8367C_NIC_TXNLS_OFFSET    0
+#define    RTL8367C_NIC_TXNLS_MASK    0x1
+
+#define    RTL8367C_REG_NIC_IMR    0x1a0f
+#define    RTL8367C_NIC_RXIE_OFFSET    7
+#define    RTL8367C_NIC_RXIE_MASK    0x80
+#define    RTL8367C_NIC_TXIE_OFFSET    6
+#define    RTL8367C_NIC_TXIE_MASK    0x40
+#define    RTL8367C_NIC_TXEE_OFFSET    5
+#define    RTL8367C_NIC_TXEE_MASK    0x20
+#define    RTL8367C_NIC_IMR_DMY_OFFSET    4
+#define    RTL8367C_NIC_IMR_DMY_MASK    0x10
+#define    RTL8367C_NIC_RXBUE_OFFSET    3
+#define    RTL8367C_NIC_RXBUE_MASK    0x8
+#define    RTL8367C_NIC_TXBOE_OFFSET    2
+#define    RTL8367C_NIC_TXBOE_MASK    0x4
+#define    RTL8367C_NIC_RXMIE_OFFSET    1
+#define    RTL8367C_NIC_RXMIE_MASK    0x2
+#define    RTL8367C_NIC_TXNLE_OFFSET    0
+#define    RTL8367C_NIC_TXNLE_MASK    0x1
+
+#define    RTL8367C_REG_NIC_RXCR0    0x1a14
+#define    RTL8367C_NIC_HFPPE_OFFSET    7
+#define    RTL8367C_NIC_HFPPE_MASK    0x80
+#define    RTL8367C_NIC_HFMPE_OFFSET    6
+#define    RTL8367C_NIC_HFMPE_MASK    0x40
+#define    RTL8367C_NIC_RXBPE_OFFSET    5
+#define    RTL8367C_NIC_RXBPE_MASK    0x20
+#define    RTL8367C_NIC_RXMPE_OFFSET    4
+#define    RTL8367C_NIC_RXMPE_MASK    0x10
+#define    RTL8367C_NIC_RXPPS_OFFSET    2
+#define    RTL8367C_NIC_RXPPS_MASK    0xC
+#define    RTL8367C_NIC_RXAPE_OFFSET    1
+#define    RTL8367C_NIC_RXAPE_MASK    0x2
+#define    RTL8367C_NIC_ARPPE_OFFSET    0
+#define    RTL8367C_NIC_ARPPE_MASK    0x1
+
+#define    RTL8367C_REG_NIC_RXCR1    0x1a15
+#define    RTL8367C_NIC_RL4CEPE_OFFSET    4
+#define    RTL8367C_NIC_RL4CEPE_MASK    0x10
+#define    RTL8367C_NIC_RL3CEPE_OFFSET    3
+#define    RTL8367C_NIC_RL3CEPE_MASK    0x8
+#define    RTL8367C_NIC_RCRCEPE_OFFSET    2
+#define    RTL8367C_NIC_RCRCEPE_MASK    0x4
+#define    RTL8367C_NIC_RMCRC_OFFSET    1
+#define    RTL8367C_NIC_RMCRC_MASK    0x2
+#define    RTL8367C_NIC_RXENABLE_OFFSET    0
+#define    RTL8367C_NIC_RXENABLE_MASK    0x1
+
+#define    RTL8367C_REG_NIC_TXCR    0x1a16
+#define    RTL8367C_NIC_LBE_OFFSET    2
+#define    RTL8367C_NIC_LBE_MASK    0x4
+#define    RTL8367C_NIC_TXMFM_OFFSET    1
+#define    RTL8367C_NIC_TXMFM_MASK    0x2
+#define    RTL8367C_NIC_TXENABLE_OFFSET    0
+#define    RTL8367C_NIC_TXENABLE_MASK    0x1
+
+#define    RTL8367C_REG_NIC_GCR    0x1a17
+#define    RTL8367C_DUMMY_7_6_OFFSET    6
+#define    RTL8367C_DUMMY_7_6_MASK    0xC0
+#define    RTL8367C_NIC_RXMTU_OFFSET    4
+#define    RTL8367C_NIC_RXMTU_MASK    0x30
+#define    RTL8367C_NIC_GCR_DUMMY_0_OFFSET    0
+#define    RTL8367C_NIC_GCR_DUMMY_0_MASK    0x1
+
+#define    RTL8367C_REG_NIC_MHR0    0x1a24
+#define    RTL8367C_NIC_MHR0_OFFSET    0
+#define    RTL8367C_NIC_MHR0_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_MHR1    0x1a25
+#define    RTL8367C_NIC_MHR1_OFFSET    0
+#define    RTL8367C_NIC_MHR1_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_MHR2    0x1a26
+#define    RTL8367C_NIC_MHR2_OFFSET    0
+#define    RTL8367C_NIC_MHR2_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_MHR3    0x1a27
+#define    RTL8367C_NIC_MHR3_OFFSET    0
+#define    RTL8367C_NIC_MHR3_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_MHR4    0x1a28
+#define    RTL8367C_NIC_MHR4_OFFSET    0
+#define    RTL8367C_NIC_MHR4_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_MHR5    0x1a29
+#define    RTL8367C_NIC_MHR5_OFFSET    0
+#define    RTL8367C_NIC_MHR5_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_MHR6    0x1a2a
+#define    RTL8367C_NIC_MHR6_OFFSET    0
+#define    RTL8367C_NIC_MHR6_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_MHR7    0x1a2b
+#define    RTL8367C_NIC_MHR7_OFFSET    0
+#define    RTL8367C_NIC_MHR7_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_PAHR0    0x1a2c
+#define    RTL8367C_NIC_PAHR0_OFFSET    0
+#define    RTL8367C_NIC_PAHR0_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_PAHR1    0x1a2d
+#define    RTL8367C_NIC_PAHR1_OFFSET    0
+#define    RTL8367C_NIC_PAHR1_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_PAHR2    0x1a2e
+#define    RTL8367C_NIC_PAHR2_OFFSET    0
+#define    RTL8367C_NIC_PAHR2_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_PAHR3    0x1a2f
+#define    RTL8367C_NIC_PAHR3_OFFSET    0
+#define    RTL8367C_NIC_PAHR3_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_PAHR4    0x1a30
+#define    RTL8367C_NIC_PAHR4_OFFSET    0
+#define    RTL8367C_NIC_PAHR4_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_PAHR5    0x1a31
+#define    RTL8367C_NIC_PAHR5_OFFSET    0
+#define    RTL8367C_NIC_PAHR5_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_PAHR6    0x1a32
+#define    RTL8367C_NIC_PAHR6_OFFSET    0
+#define    RTL8367C_NIC_PAHR6_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_PAHR7    0x1a33
+#define    RTL8367C_NIC_PAHR7_OFFSET    0
+#define    RTL8367C_NIC_PAHR7_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_TXSTOPRL    0x1a44
+#define    RTL8367C_NIC_TXSTOPRL_OFFSET    0
+#define    RTL8367C_NIC_TXSTOPRL_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_TXSTOPRH    0x1a45
+#define    RTL8367C_NIC_TXSTOPRH_OFFSET    0
+#define    RTL8367C_NIC_TXSTOPRH_MASK    0x3
+
+#define    RTL8367C_REG_NIC_RXSTOPRL    0x1a46
+#define    RTL8367C_NIC_RXSTOPRL_OFFSET    0
+#define    RTL8367C_NIC_RXSTOPRL_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_RXSTOPRH    0x1a47
+#define    RTL8367C_NIC_RXSTOPRH_OFFSET    0
+#define    RTL8367C_NIC_RXSTOPRH_MASK    0x3
+
+#define    RTL8367C_REG_NIC_RXFSTR    0x1a48
+#define    RTL8367C_NIC_RXFSTR_OFFSET    0
+#define    RTL8367C_NIC_RXFSTR_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_RXMBTRL    0x1a4c
+#define    RTL8367C_NIC_RXMBTRL_OFFSET    0
+#define    RTL8367C_NIC_RXMBTRL_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_RXMBTRH    0x1a4d
+#define    RTL8367C_NIC_RXMBTRH_OFFSET    0
+#define    RTL8367C_NIC_RXMBTRH_MASK    0x7F
+
+#define    RTL8367C_REG_NIC_RXMPTR    0x1a4e
+#define    RTL8367C_NIC_RXMPTR_OFFSET    0
+#define    RTL8367C_NIC_RXMPTR_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_T0TR    0x1a4f
+#define    RTL8367C_NIC_T0TR_OFFSET    0
+#define    RTL8367C_NIC_T0TR_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_CRXCPRL    0x1a50
+#define    RTL8367C_NIC_CRXCPRL_OFFSET    0
+#define    RTL8367C_NIC_CRXCPRL_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_CRXCPRH    0x1a51
+#define    RTL8367C_NIC_CRXCPRH_OFFSET    0
+#define    RTL8367C_NIC_CRXCPRH_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_CTXCPRL    0x1a52
+#define    RTL8367C_NIC_CTXCPRL_OFFSET    0
+#define    RTL8367C_NIC_CTXCPRL_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_CTXPCRH    0x1a53
+#define    RTL8367C_NIC_CTXPCRH_OFFSET    0
+#define    RTL8367C_NIC_CTXPCRH_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_SRXCURPKTRL    0x1a54
+#define    RTL8367C_NIC_SRXCURPKTRL_OFFSET    0
+#define    RTL8367C_NIC_SRXCURPKTRL_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_SRXCURPKTRH    0x1a55
+#define    RTL8367C_NIC_SRXCURPKTRH_OFFSET    0
+#define    RTL8367C_NIC_SRXCURPKTRH_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_STXCURPKTRL    0x1a56
+#define    RTL8367C_NIC_STXCURPKTRL_OFFSET    0
+#define    RTL8367C_NIC_STXCURPKTRL_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_STXCURPKTRH    0x1a57
+#define    RTL8367C_NIC_STXCURPKTRH_OFFSET    0
+#define    RTL8367C_NIC_STXCURPKTRH_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_STXPKTLENRL    0x1a58
+#define    RTL8367C_NIC_STXPKTLENRL_OFFSET    0
+#define    RTL8367C_NIC_STXPKTLENRL_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_STXPKTLENRH    0x1a59
+#define    RTL8367C_NIC_STXPKTLENRH_OFFSET    0
+#define    RTL8367C_NIC_STXPKTLENRH_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_STXCURUNITRL    0x1a5a
+#define    RTL8367C_NIC_STXCURUNITRL_OFFSET    0
+#define    RTL8367C_NIC_STXCURUNITRL_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_STXCURUNITRH    0x1a5b
+#define    RTL8367C_NIC_STXCURUNITRH_OFFSET    0
+#define    RTL8367C_NIC_STXCURUNITRH_MASK    0xFF
+
+#define    RTL8367C_REG_NIC_DROP_MODE    0x1a5c
+#define    RTL8367C_NIC_RXDV_MODE_OFFSET    1
+#define    RTL8367C_NIC_RXDV_MODE_MASK    0x2
+#define    RTL8367C_NIC_DROP_MODE_OFFSET    0
+#define    RTL8367C_NIC_DROP_MODE_MASK    0x1
+
+/* (16'h1b00)LED */
+
+#define    RTL8367C_REG_LED_SYS_CONFIG    0x1b00
+#define    RTL8367C_LED_SYS_CONFIG_DUMMY_15_OFFSET    15
+#define    RTL8367C_LED_SYS_CONFIG_DUMMY_15_MASK    0x8000
+#define    RTL8367C_LED_SERIAL_OUT_MODE_OFFSET    14
+#define    RTL8367C_LED_SERIAL_OUT_MODE_MASK    0x4000
+#define    RTL8367C_LED_EEE_LPI_MODE_OFFSET    13
+#define    RTL8367C_LED_EEE_LPI_MODE_MASK    0x2000
+#define    RTL8367C_LED_EEE_LPI_EN_OFFSET    12
+#define    RTL8367C_LED_EEE_LPI_EN_MASK    0x1000
+#define    RTL8367C_LED_EEE_LPI_10_OFFSET    11
+#define    RTL8367C_LED_EEE_LPI_10_MASK    0x800
+#define    RTL8367C_LED_EEE_CAP_10_OFFSET    10
+#define    RTL8367C_LED_EEE_CAP_10_MASK    0x400
+#define    RTL8367C_LED_LPI_SEL_OFFSET    8
+#define    RTL8367C_LED_LPI_SEL_MASK    0x300
+#define    RTL8367C_SERI_LED_ACT_LOW_OFFSET    7
+#define    RTL8367C_SERI_LED_ACT_LOW_MASK    0x80
+#define    RTL8367C_LED_POWERON_2_OFFSET    6
+#define    RTL8367C_LED_POWERON_2_MASK    0x40
+#define    RTL8367C_LED_POWERON_1_OFFSET    5
+#define    RTL8367C_LED_POWERON_1_MASK    0x20
+#define    RTL8367C_LED_POWERON_0_OFFSET    4
+#define    RTL8367C_LED_POWERON_0_MASK    0x10
+#define    RTL8367C_LED_IO_DISABLE_OFFSET    3
+#define    RTL8367C_LED_IO_DISABLE_MASK    0x8
+#define    RTL8367C_DUMMY_2_2_OFFSET    2
+#define    RTL8367C_DUMMY_2_2_MASK    0x4
+#define    RTL8367C_LED_SELECT_OFFSET    0
+#define    RTL8367C_LED_SELECT_MASK    0x3
+
+#define    RTL8367C_REG_LED_SYS_CONFIG2    0x1b01
+#define    RTL8367C_LED_SYS_CONFIG2_DUMMY_OFFSET    2
+#define    RTL8367C_LED_SYS_CONFIG2_DUMMY_MASK    0xFFFC
+#define    RTL8367C_GATE_LPTD_BYPASS_OFFSET    1
+#define    RTL8367C_GATE_LPTD_BYPASS_MASK    0x2
+#define    RTL8367C_LED_SPD_MODE_OFFSET    0
+#define    RTL8367C_LED_SPD_MODE_MASK    0x1
+
+#define    RTL8367C_REG_LED_MODE    0x1b02
+#define    RTL8367C_DLINK_TIME_OFFSET    15
+#define    RTL8367C_DLINK_TIME_MASK    0x8000
+#define    RTL8367C_LED_BUZZ_DUTY_OFFSET    14
+#define    RTL8367C_LED_BUZZ_DUTY_MASK    0x4000
+#define    RTL8367C_BUZZER_RATE_OFFSET    12
+#define    RTL8367C_BUZZER_RATE_MASK    0x3000
+#define    RTL8367C_LOOP_DETECT_MODE_OFFSET    11
+#define    RTL8367C_LOOP_DETECT_MODE_MASK    0x800
+#define    RTL8367C_SEL_PWRON_TIME_OFFSET    9
+#define    RTL8367C_SEL_PWRON_TIME_MASK    0x600
+#define    RTL8367C_EN_DLINK_LED_OFFSET    8
+#define    RTL8367C_EN_DLINK_LED_MASK    0x100
+#define    RTL8367C_LOOP_DETECT_RATE_OFFSET    6
+#define    RTL8367C_LOOP_DETECT_RATE_MASK    0xC0
+#define    RTL8367C_FORCE_RATE_OFFSET    4
+#define    RTL8367C_FORCE_RATE_MASK    0x30
+#define    RTL8367C_SEL_LEDRATE_OFFSET    1
+#define    RTL8367C_SEL_LEDRATE_MASK    0xE
+#define    RTL8367C_SPEED_UP_OFFSET    0
+#define    RTL8367C_SPEED_UP_MASK    0x1
+
+#define    RTL8367C_REG_LED_CONFIGURATION    0x1b03
+#define    RTL8367C_LED_CONFIGURATION_DUMMY_OFFSET    15
+#define    RTL8367C_LED_CONFIGURATION_DUMMY_MASK    0x8000
+#define    RTL8367C_LED_CONFIG_SEL_OFFSET    14
+#define    RTL8367C_LED_CONFIG_SEL_MASK    0x4000
+#define    RTL8367C_DATA_LED_OFFSET    12
+#define    RTL8367C_DATA_LED_MASK    0x3000
+#define    RTL8367C_LED2_CFG_OFFSET    8
+#define    RTL8367C_LED2_CFG_MASK    0xF00
+#define    RTL8367C_LED1_CFG_OFFSET    4
+#define    RTL8367C_LED1_CFG_MASK    0xF0
+#define    RTL8367C_LED0_CFG_OFFSET    0
+#define    RTL8367C_LED0_CFG_MASK    0xF
+
+#define    RTL8367C_REG_RTCT_RESULTS_CFG    0x1b04
+#define    RTL8367C_RTCT_2PAIR_FTT_OFFSET    15
+#define    RTL8367C_RTCT_2PAIR_FTT_MASK    0x8000
+#define    RTL8367C_RTCT_2PAIR_MODE_OFFSET    14
+#define    RTL8367C_RTCT_2PAIR_MODE_MASK    0x4000
+#define    RTL8367C_BLINK_EN_OFFSET    13
+#define    RTL8367C_BLINK_EN_MASK    0x2000
+#define    RTL8367C_TIMEOUT_OFFSET    12
+#define    RTL8367C_TIMEOUT_MASK    0x1000
+#define    RTL8367C_EN_CD_SAME_SHORT_OFFSET    11
+#define    RTL8367C_EN_CD_SAME_SHORT_MASK    0x800
+#define    RTL8367C_EN_CD_SAME_OPEN_OFFSET    10
+#define    RTL8367C_EN_CD_SAME_OPEN_MASK    0x400
+#define    RTL8367C_EN_CD_SAME_LINEDRIVER_OFFSET    9
+#define    RTL8367C_EN_CD_SAME_LINEDRIVER_MASK    0x200
+#define    RTL8367C_EN_CD_SAME_MISMATCH_OFFSET    8
+#define    RTL8367C_EN_CD_SAME_MISMATCH_MASK    0x100
+#define    RTL8367C_EN_CD_SHORT_OFFSET    7
+#define    RTL8367C_EN_CD_SHORT_MASK    0x80
+#define    RTL8367C_EN_AB_SHORT_OFFSET    6
+#define    RTL8367C_EN_AB_SHORT_MASK    0x40
+#define    RTL8367C_EN_CD_OPEN_OFFSET    5
+#define    RTL8367C_EN_CD_OPEN_MASK    0x20
+#define    RTL8367C_EN_AB_OPEN_OFFSET    4
+#define    RTL8367C_EN_AB_OPEN_MASK    0x10
+#define    RTL8367C_EN_CD_MISMATCH_OFFSET    3
+#define    RTL8367C_EN_CD_MISMATCH_MASK    0x8
+#define    RTL8367C_EN_AB_MISMATCH_OFFSET    2
+#define    RTL8367C_EN_AB_MISMATCH_MASK    0x4
+#define    RTL8367C_EN_CD_LINEDRIVER_OFFSET    1
+#define    RTL8367C_EN_CD_LINEDRIVER_MASK    0x2
+#define    RTL8367C_EN_AB_LINEDRIVER_OFFSET    0
+#define    RTL8367C_EN_AB_LINEDRIVER_MASK    0x1
+
+#define    RTL8367C_REG_RTCT_LED    0x1b05
+#define    RTL8367C_DUMMY_1b05a_OFFSET    12
+#define    RTL8367C_DUMMY_1b05a_MASK    0xF000
+#define    RTL8367C_RTCT_LED2_OFFSET    8
+#define    RTL8367C_RTCT_LED2_MASK    0xF00
+#define    RTL8367C_RTCT_LED1_OFFSET    4
+#define    RTL8367C_RTCT_LED1_MASK    0xF0
+#define    RTL8367C_RTCT_LED0_OFFSET    0
+#define    RTL8367C_RTCT_LED0_MASK    0xF
+
+#define    RTL8367C_REG_CPU_FORCE_LED_CFG    0x1b07
+#define    RTL8367C_DUMMY_1b07a_OFFSET    8
+#define    RTL8367C_DUMMY_1b07a_MASK    0xFF00
+#define    RTL8367C_LED_FORCE_MODE_OFFSET    2
+#define    RTL8367C_LED_FORCE_MODE_MASK    0xFC
+#define    RTL8367C_FORCE_MODE_OFFSET    0
+#define    RTL8367C_FORCE_MODE_MASK    0x3
+
+#define    RTL8367C_REG_CPU_FORCE_LED0_CFG0    0x1b08
+#define    RTL8367C_PORT7_LED0_MODE_OFFSET    14
+#define    RTL8367C_PORT7_LED0_MODE_MASK    0xC000
+#define    RTL8367C_PORT6_LED0_MODE_OFFSET    12
+#define    RTL8367C_PORT6_LED0_MODE_MASK    0x3000
+#define    RTL8367C_PORT5_LED0_MODE_OFFSET    10
+#define    RTL8367C_PORT5_LED0_MODE_MASK    0xC00
+#define    RTL8367C_PORT4_LED0_MODE_OFFSET    8
+#define    RTL8367C_PORT4_LED0_MODE_MASK    0x300
+#define    RTL8367C_PORT3_LED0_MODE_OFFSET    6
+#define    RTL8367C_PORT3_LED0_MODE_MASK    0xC0
+#define    RTL8367C_PORT2_LED0_MODE_OFFSET    4
+#define    RTL8367C_PORT2_LED0_MODE_MASK    0x30
+#define    RTL8367C_PORT1_LED0_MODE_OFFSET    2
+#define    RTL8367C_PORT1_LED0_MODE_MASK    0xC
+#define    RTL8367C_PORT0_LED0_MODE_OFFSET    0
+#define    RTL8367C_PORT0_LED0_MODE_MASK    0x3
+
+#define    RTL8367C_REG_CPU_FORCE_LED0_CFG1    0x1b09
+#define    RTL8367C_DUMMY_1b09a_OFFSET    4
+#define    RTL8367C_DUMMY_1b09a_MASK    0xFFF0
+#define    RTL8367C_PORT9_LED0_MODE_OFFSET    2
+#define    RTL8367C_PORT9_LED0_MODE_MASK    0xC
+#define    RTL8367C_PORT8_LED0_MODE_OFFSET    0
+#define    RTL8367C_PORT8_LED0_MODE_MASK    0x3
+
+#define    RTL8367C_REG_CPU_FORCE_LED1_CFG0    0x1b0a
+#define    RTL8367C_PORT7_LED1_MODE_OFFSET    14
+#define    RTL8367C_PORT7_LED1_MODE_MASK    0xC000
+#define    RTL8367C_PORT6_LED1_MODE_OFFSET    12
+#define    RTL8367C_PORT6_LED1_MODE_MASK    0x3000
+#define    RTL8367C_PORT5_LED1_MODE_OFFSET    10
+#define    RTL8367C_PORT5_LED1_MODE_MASK    0xC00
+#define    RTL8367C_PORT4_LED1_MODE_OFFSET    8
+#define    RTL8367C_PORT4_LED1_MODE_MASK    0x300
+#define    RTL8367C_PORT3_LED1_MODE_OFFSET    6
+#define    RTL8367C_PORT3_LED1_MODE_MASK    0xC0
+#define    RTL8367C_PORT2_LED1_MODE_OFFSET    4
+#define    RTL8367C_PORT2_LED1_MODE_MASK    0x30
+#define    RTL8367C_PORT1_LED1_MODE_OFFSET    2
+#define    RTL8367C_PORT1_LED1_MODE_MASK    0xC
+#define    RTL8367C_PORT0_LED1_MODE_OFFSET    0
+#define    RTL8367C_PORT0_LED1_MODE_MASK    0x3
+
+#define    RTL8367C_REG_CPU_FORCE_LED1_CFG1    0x1b0b
+#define    RTL8367C_DUMMY_1b0ba_OFFSET    4
+#define    RTL8367C_DUMMY_1b0ba_MASK    0xFFF0
+#define    RTL8367C_PORT9_LED1_MODE_OFFSET    2
+#define    RTL8367C_PORT9_LED1_MODE_MASK    0xC
+#define    RTL8367C_PORT8_LED1_MODE_OFFSET    0
+#define    RTL8367C_PORT8_LED1_MODE_MASK    0x3
+
+#define    RTL8367C_REG_CPU_FORCE_LED2_CFG0    0x1b0c
+#define    RTL8367C_PORT7_LED2_MODE_OFFSET    14
+#define    RTL8367C_PORT7_LED2_MODE_MASK    0xC000
+#define    RTL8367C_PORT6_LED2_MODE_OFFSET    12
+#define    RTL8367C_PORT6_LED2_MODE_MASK    0x3000
+#define    RTL8367C_PORT5_LED2_MODE_OFFSET    10
+#define    RTL8367C_PORT5_LED2_MODE_MASK    0xC00
+#define    RTL8367C_PORT4_LED2_MODE_OFFSET    8
+#define    RTL8367C_PORT4_LED2_MODE_MASK    0x300
+#define    RTL8367C_PORT3_LED2_MODE_OFFSET    6
+#define    RTL8367C_PORT3_LED2_MODE_MASK    0xC0
+#define    RTL8367C_PORT2_LED2_MODE_OFFSET    4
+#define    RTL8367C_PORT2_LED2_MODE_MASK    0x30
+#define    RTL8367C_PORT1_LED2_MODE_OFFSET    2
+#define    RTL8367C_PORT1_LED2_MODE_MASK    0xC
+#define    RTL8367C_PORT0_LED2_MODE_OFFSET    0
+#define    RTL8367C_PORT0_LED2_MODE_MASK    0x3
+
+#define    RTL8367C_REG_CPU_FORCE_LED2_CFG1    0x1b0d
+#define    RTL8367C_DUMMY_1b0da_OFFSET    4
+#define    RTL8367C_DUMMY_1b0da_MASK    0xFFF0
+#define    RTL8367C_PORT9_LED2_MODE_OFFSET    2
+#define    RTL8367C_PORT9_LED2_MODE_MASK    0xC
+#define    RTL8367C_PORT8_LED2_MODE_OFFSET    0
+#define    RTL8367C_PORT8_LED2_MODE_MASK    0x3
+
+#define    RTL8367C_REG_LED_ACTIVE_LOW_CFG0    0x1b0e
+#define    RTL8367C_LED_ACTIVE_LOW_CFG0_DUMMY_15_OFFSET    15
+#define    RTL8367C_LED_ACTIVE_LOW_CFG0_DUMMY_15_MASK    0x8000
+#define    RTL8367C_PORT3_LED_ACTIVE_LOW_OFFSET    12
+#define    RTL8367C_PORT3_LED_ACTIVE_LOW_MASK    0x7000
+#define    RTL8367C_LED_ACTIVE_LOW_CFG0_DUMMY_11_OFFSET    11
+#define    RTL8367C_LED_ACTIVE_LOW_CFG0_DUMMY_11_MASK    0x800
+#define    RTL8367C_PORT2_LED_ACTIVE_LOW_OFFSET    8
+#define    RTL8367C_PORT2_LED_ACTIVE_LOW_MASK    0x700
+#define    RTL8367C_DUMMY_7_OFFSET    7
+#define    RTL8367C_DUMMY_7_MASK    0x80
+#define    RTL8367C_PORT1_LED_ACTIVE_LOW_OFFSET    4
+#define    RTL8367C_PORT1_LED_ACTIVE_LOW_MASK    0x70
+#define    RTL8367C_DUMMY_3_OFFSET    3
+#define    RTL8367C_DUMMY_3_MASK    0x8
+#define    RTL8367C_PORT0_LED_ACTIVE_LOW_OFFSET    0
+#define    RTL8367C_PORT0_LED_ACTIVE_LOW_MASK    0x7
+
+#define    RTL8367C_REG_LED_ACTIVE_LOW_CFG1    0x1b0f
+#define    RTL8367C_LED_ACTIVE_LOW_CFG1_DUMMY_15_OFFSET    15
+#define    RTL8367C_LED_ACTIVE_LOW_CFG1_DUMMY_15_MASK    0x8000
+#define    RTL8367C_PORT7_LED_ACTIVE_LOW_OFFSET    12
+#define    RTL8367C_PORT7_LED_ACTIVE_LOW_MASK    0x7000
+#define    RTL8367C_LED_ACTIVE_LOW_CFG1_DUMMY_11_OFFSET    11
+#define    RTL8367C_LED_ACTIVE_LOW_CFG1_DUMMY_11_MASK    0x800
+#define    RTL8367C_PORT6_LED_ACTIVE_LOW_OFFSET    8
+#define    RTL8367C_PORT6_LED_ACTIVE_LOW_MASK    0x700
+#define    RTL8367C_DUMMY_1b0f_b_OFFSET    7
+#define    RTL8367C_DUMMY_1b0f_b_MASK    0x80
+#define    RTL8367C_PORT5_LED_ACTIVE_LOW_OFFSET    4
+#define    RTL8367C_PORT5_LED_ACTIVE_LOW_MASK    0x70
+#define    RTL8367C_DUMMY_1b0f_a_OFFSET    3
+#define    RTL8367C_DUMMY_1b0f_a_MASK    0x8
+#define    RTL8367C_PORT4_LED_ACTIVE_LOW_OFFSET    0
+#define    RTL8367C_PORT4_LED_ACTIVE_LOW_MASK    0x7
+
+#define    RTL8367C_REG_LED_ACTIVE_LOW_CFG2    0x1b10
+#define    RTL8367C_DUMMY_1b10_b_OFFSET    7
+#define    RTL8367C_DUMMY_1b10_b_MASK    0xFF80
+#define    RTL8367C_PORT9_LED_ACTIVE_LOW_OFFSET    4
+#define    RTL8367C_PORT9_LED_ACTIVE_LOW_MASK    0x70
+#define    RTL8367C_DUMMY_1b10_a_OFFSET    3
+#define    RTL8367C_DUMMY_1b10_a_MASK    0x8
+#define    RTL8367C_PORT8_LED_ACTIVE_LOW_OFFSET    0
+#define    RTL8367C_PORT8_LED_ACTIVE_LOW_MASK    0x7
+
+#define    RTL8367C_REG_SEL_RTCT_PARA    0x1b21
+#define    RTL8367C_DO_RTCT_COMMAND_OFFSET    15
+#define    RTL8367C_DO_RTCT_COMMAND_MASK    0x8000
+#define    RTL8367C_SEL_RTCT_PARA_DUMMY_OFFSET    12
+#define    RTL8367C_SEL_RTCT_PARA_DUMMY_MASK    0x7000
+#define    RTL8367C_SEL_RTCT_RLSTLED_TIME_OFFSET    10
+#define    RTL8367C_SEL_RTCT_RLSTLED_TIME_MASK    0xC00
+#define    RTL8367C_SEL_RTCT_TEST_LED_TIME_OFFSET    8
+#define    RTL8367C_SEL_RTCT_TEST_LED_TIME_MASK    0x300
+#define    RTL8367C_EN_SCAN_RTCT_OFFSET    7
+#define    RTL8367C_EN_SCAN_RTCT_MASK    0x80
+#define    RTL8367C_EN_RTCT_TIMOUT_OFFSET    6
+#define    RTL8367C_EN_RTCT_TIMOUT_MASK    0x40
+#define    RTL8367C_EN_ALL_RTCT_OFFSET    5
+#define    RTL8367C_EN_ALL_RTCT_MASK    0x20
+#define    RTL8367C_SEL_RTCT_PLE_WID_OFFSET    0
+#define    RTL8367C_SEL_RTCT_PLE_WID_MASK    0x1F
+
+#define    RTL8367C_REG_RTCT_ENABLE    0x1b22
+#define    RTL8367C_RTCT_ENABLE_DUMMY_OFFSET    8
+#define    RTL8367C_RTCT_ENABLE_DUMMY_MASK    0xFF00
+#define    RTL8367C_RTCT_ENABLE_PORT_MASK_OFFSET    0
+#define    RTL8367C_RTCT_ENABLE_PORT_MASK_MASK    0xFF
+
+#define    RTL8367C_REG_RTCT_TIMEOUT    0x1b23
+
+#define    RTL8367C_REG_PARA_LED_IO_EN1    0x1b24
+#define    RTL8367C_LED1_PARA_P07_00_OFFSET    8
+#define    RTL8367C_LED1_PARA_P07_00_MASK    0xFF00
+#define    RTL8367C_LED0_PARA_P07_00_OFFSET    0
+#define    RTL8367C_LED0_PARA_P07_00_MASK    0xFF
+
+#define    RTL8367C_REG_PARA_LED_IO_EN2    0x1b25
+#define    RTL8367C_DUMMY_15_8_OFFSET    8
+#define    RTL8367C_DUMMY_15_8_MASK    0xFF00
+#define    RTL8367C_LED2_PARA_P07_00_OFFSET    0
+#define    RTL8367C_LED2_PARA_P07_00_MASK    0xFF
+
+#define    RTL8367C_REG_SCAN0_LED_IO_EN1    0x1b26
+#define    RTL8367C_SCAN0_LED_IO_EN1_DUMMY_OFFSET    3
+#define    RTL8367C_SCAN0_LED_IO_EN1_DUMMY_MASK    0xFFF8
+#define    RTL8367C_LED_LOOP_DET_BUZZER_EN_OFFSET    2
+#define    RTL8367C_LED_LOOP_DET_BUZZER_EN_MASK    0x4
+#define    RTL8367C_LED_SERI_DATA_EN_OFFSET    1
+#define    RTL8367C_LED_SERI_DATA_EN_MASK    0x2
+#define    RTL8367C_LED_SERI_CLK_EN_OFFSET    0
+#define    RTL8367C_LED_SERI_CLK_EN_MASK    0x1
+
+#define    RTL8367C_REG_SCAN1_LED_IO_EN2    0x1b27
+#define    RTL8367C_LED_SCAN1_BI_PORT_EN_OFFSET    8
+#define    RTL8367C_LED_SCAN1_BI_PORT_EN_MASK    0xFF00
+#define    RTL8367C_LED_SCAN1_BI_STA_EN_OFFSET    7
+#define    RTL8367C_LED_SCAN1_BI_STA_EN_MASK    0x80
+#define    RTL8367C_SCAN1_LED_IO_EN2_DUMMY_0_OFFSET    6
+#define    RTL8367C_SCAN1_LED_IO_EN2_DUMMY_0_MASK    0x40
+#define    RTL8367C_LED_SCAN1_SI_PORT_EN_OFFSET    2
+#define    RTL8367C_LED_SCAN1_SI_PORT_EN_MASK    0x3C
+#define    RTL8367C_LED_SCAN1_SI_STA_EN_OFFSET    0
+#define    RTL8367C_LED_SCAN1_SI_STA_EN_MASK    0x3
+
+#define    RTL8367C_REG_LPI_LED_OPT1    0x1b28
+#define    RTL8367C_LPI_TAG4_OFFSET    12
+#define    RTL8367C_LPI_TAG4_MASK    0xF000
+#define    RTL8367C_LPI_TAG3_OFFSET    8
+#define    RTL8367C_LPI_TAG3_MASK    0xF00
+#define    RTL8367C_LPI_TAG2_OFFSET    4
+#define    RTL8367C_LPI_TAG2_MASK    0xF0
+#define    RTL8367C_LPI_TAG1_OFFSET    0
+#define    RTL8367C_LPI_TAG1_MASK    0xF
+
+#define    RTL8367C_REG_LPI_LED_OPT2    0x1b29
+#define    RTL8367C_LPI_LED_OPT2_DUMMY_OFFSET    15
+#define    RTL8367C_LPI_LED_OPT2_DUMMY_MASK    0x8000
+#define    RTL8367C_LPI_LED2_WEAK_OFFSET    14
+#define    RTL8367C_LPI_LED2_WEAK_MASK    0x4000
+#define    RTL8367C_LPI_LED1_WEAK_OFFSET    13
+#define    RTL8367C_LPI_LED1_WEAK_MASK    0x2000
+#define    RTL8367C_LPI_LED0_WEAK_OFFSET    12
+#define    RTL8367C_LPI_LED0_WEAK_MASK    0x1000
+#define    RTL8367C_LPI_LED2_OFFSET    11
+#define    RTL8367C_LPI_LED2_MASK    0x800
+#define    RTL8367C_LPI_LED1_OFFSET    10
+#define    RTL8367C_LPI_LED1_MASK    0x400
+#define    RTL8367C_LPI_LED0_OFFSET    9
+#define    RTL8367C_LPI_LED0_MASK    0x200
+#define    RTL8367C_LPI_TAG8_OFFSET    8
+#define    RTL8367C_LPI_TAG8_MASK    0x100
+#define    RTL8367C_LPI_TAG7_OFFSET    6
+#define    RTL8367C_LPI_TAG7_MASK    0xC0
+#define    RTL8367C_LPI_TAG6_OFFSET    4
+#define    RTL8367C_LPI_TAG6_MASK    0x30
+#define    RTL8367C_LPI_TAG5_OFFSET    0
+#define    RTL8367C_LPI_TAG5_MASK    0xF
+
+#define    RTL8367C_REG_LPI_LED_OPT3    0x1b2a
+#define    RTL8367C_LPI_LED_OPT3_DUMMY_OFFSET    3
+#define    RTL8367C_LPI_LED_OPT3_DUMMY_MASK    0xFFF8
+#define    RTL8367C_RESTORE_LED_RATE_SEL_OFFSET    1
+#define    RTL8367C_RESTORE_LED_RATE_SEL_MASK    0x6
+#define    RTL8367C_RESTORE_LED_SEL_OFFSET    0
+#define    RTL8367C_RESTORE_LED_SEL_MASK    0x1
+
+#define    RTL8367C_REG_P0_LED_MUX    0x1b2b
+#define    RTL8367C_CFG_P0_LED2_MUX_OFFSET    10
+#define    RTL8367C_CFG_P0_LED2_MUX_MASK    0x7C00
+#define    RTL8367C_CFG_P0_LED1_MUX_OFFSET    5
+#define    RTL8367C_CFG_P0_LED1_MUX_MASK    0x3E0
+#define    RTL8367C_CFG_P0_LED0_MUX_OFFSET    0
+#define    RTL8367C_CFG_P0_LED0_MUX_MASK    0x1F
+
+#define    RTL8367C_REG_P1_LED_MUX    0x1b2c
+#define    RTL8367C_CFG_P1_LED2_MUX_OFFSET    10
+#define    RTL8367C_CFG_P1_LED2_MUX_MASK    0x7C00
+#define    RTL8367C_CFG_P1_LED1_MUX_OFFSET    5
+#define    RTL8367C_CFG_P1_LED1_MUX_MASK    0x3E0
+#define    RTL8367C_CFG_P1_LED0_MUX_OFFSET    0
+#define    RTL8367C_CFG_P1_LED0_MUX_MASK    0x1F
+
+#define    RTL8367C_REG_P2_LED_MUX    0x1b2d
+#define    RTL8367C_CFG_P2_LED2_MUX_OFFSET    10
+#define    RTL8367C_CFG_P2_LED2_MUX_MASK    0x7C00
+#define    RTL8367C_CFG_P2_LED1_MUX_OFFSET    5
+#define    RTL8367C_CFG_P2_LED1_MUX_MASK    0x3E0
+#define    RTL8367C_CFG_P2_LED0_MUX_OFFSET    0
+#define    RTL8367C_CFG_P2_LED0_MUX_MASK    0x1F
+
+#define    RTL8367C_REG_P3_LED_MUX    0x1b2e
+#define    RTL8367C_CFG_P3_LED2_MUX_OFFSET    10
+#define    RTL8367C_CFG_P3_LED2_MUX_MASK    0x7C00
+#define    RTL8367C_CFG_P3_LED1_MUX_OFFSET    5
+#define    RTL8367C_CFG_P3_LED1_MUX_MASK    0x3E0
+#define    RTL8367C_CFG_P3_LED0_MUX_OFFSET    0
+#define    RTL8367C_CFG_P3_LED0_MUX_MASK    0x1F
+
+#define    RTL8367C_REG_P4_LED_MUX    0x1b2f
+#define    RTL8367C_CFG_P4_LED2_MUX_OFFSET    10
+#define    RTL8367C_CFG_P4_LED2_MUX_MASK    0x7C00
+#define    RTL8367C_CFG_P4_LED1_MUX_OFFSET    5
+#define    RTL8367C_CFG_P4_LED1_MUX_MASK    0x3E0
+#define    RTL8367C_CFG_P4_LED0_MUX_OFFSET    0
+#define    RTL8367C_CFG_P4_LED0_MUX_MASK    0x1F
+
+#define    RTL8367C_REG_LED0_DATA_CTRL    0x1b30
+#define    RTL8367C_CFG_DATA_LED0_SEL_OFFSET    6
+#define    RTL8367C_CFG_DATA_LED0_SEL_MASK    0x40
+#define    RTL8367C_CFG_DATA_LED0_ACT_OFFSET    4
+#define    RTL8367C_CFG_DATA_LED0_ACT_MASK    0x30
+#define    RTL8367C_CFG_DATA_LED0_SPD_OFFSET    0
+#define    RTL8367C_CFG_DATA_LED0_SPD_MASK    0xF
+
+#define    RTL8367C_REG_LED1_DATA_CTRL    0x1b31
+#define    RTL8367C_CFG_DATA_LED1_SEL_OFFSET    6
+#define    RTL8367C_CFG_DATA_LED1_SEL_MASK    0x40
+#define    RTL8367C_CFG_DATA_LED1_ACT_OFFSET    4
+#define    RTL8367C_CFG_DATA_LED1_ACT_MASK    0x30
+#define    RTL8367C_CFG_DATA_LED1_SPD_OFFSET    0
+#define    RTL8367C_CFG_DATA_LED1_SPD_MASK    0xF
+
+#define    RTL8367C_REG_LED2_DATA_CTRL    0x1b32
+#define    RTL8367C_CFG_DATA_LED2_SEL_OFFSET    6
+#define    RTL8367C_CFG_DATA_LED2_SEL_MASK    0x40
+#define    RTL8367C_CFG_DATA_LED2_ACT_OFFSET    4
+#define    RTL8367C_CFG_DATA_LED2_ACT_MASK    0x30
+#define    RTL8367C_CFG_DATA_LED2_SPD_OFFSET    0
+#define    RTL8367C_CFG_DATA_LED2_SPD_MASK    0xF
+
+#define    RTL8367C_REG_PARA_LED_IO_EN3    0x1b33
+#define    RTL8367C_dummy_1b33a_OFFSET    6
+#define    RTL8367C_dummy_1b33a_MASK    0xFFC0
+#define    RTL8367C_LED2_PARA_P09_08_OFFSET    4
+#define    RTL8367C_LED2_PARA_P09_08_MASK    0x30
+#define    RTL8367C_LED1_PARA_P09_08_OFFSET    2
+#define    RTL8367C_LED1_PARA_P09_08_MASK    0xC
+#define    RTL8367C_LED0_PARA_P09_08_OFFSET    0
+#define    RTL8367C_LED0_PARA_P09_08_MASK    0x3
+
+#define    RTL8367C_REG_SCAN1_LED_IO_EN3    0x1b34
+#define    RTL8367C_dummy_1b34a_OFFSET    3
+#define    RTL8367C_dummy_1b34a_MASK    0xFFF8
+#define    RTL8367C_LED_SCAN1_BI_PORT9_8_EN_OFFSET    1
+#define    RTL8367C_LED_SCAN1_BI_PORT9_8_EN_MASK    0x6
+#define    RTL8367C_LED_SCAN1_SI_PORT9_8_EN_OFFSET    0
+#define    RTL8367C_LED_SCAN1_SI_PORT9_8_EN_MASK    0x1
+
+#define    RTL8367C_REG_P5_LED_MUX    0x1b35
+#define    RTL8367C_CFG_P5_LED2_MUX_OFFSET    10
+#define    RTL8367C_CFG_P5_LED2_MUX_MASK    0x7C00
+#define    RTL8367C_CFG_P5_LED1_MUX_OFFSET    5
+#define    RTL8367C_CFG_P5_LED1_MUX_MASK    0x3E0
+#define    RTL8367C_CFG_P5_LED0_MUX_OFFSET    0
+#define    RTL8367C_CFG_P5_LED0_MUX_MASK    0x1F
+
+#define    RTL8367C_REG_P6_LED_MUX    0x1b36
+#define    RTL8367C_CFG_P6_LED2_MUX_OFFSET    10
+#define    RTL8367C_CFG_P6_LED2_MUX_MASK    0x7C00
+#define    RTL8367C_CFG_P6_LED1_MUX_OFFSET    5
+#define    RTL8367C_CFG_P6_LED1_MUX_MASK    0x3E0
+#define    RTL8367C_CFG_P6_LED0_MUX_OFFSET    0
+#define    RTL8367C_CFG_P6_LED0_MUX_MASK    0x1F
+
+#define    RTL8367C_REG_P7_LED_MUX    0x1b37
+#define    RTL8367C_CFG_P7_LED2_MUX_OFFSET    10
+#define    RTL8367C_CFG_P7_LED2_MUX_MASK    0x7C00
+#define    RTL8367C_CFG_P7_LED1_MUX_OFFSET    5
+#define    RTL8367C_CFG_P7_LED1_MUX_MASK    0x3E0
+#define    RTL8367C_CFG_P7_LED0_MUX_OFFSET    0
+#define    RTL8367C_CFG_P7_LED0_MUX_MASK    0x1F
+
+#define    RTL8367C_REG_P8_LED_MUX    0x1b38
+#define    RTL8367C_CFG_P8_LED2_MUX_OFFSET    10
+#define    RTL8367C_CFG_P8_LED2_MUX_MASK    0x7C00
+#define    RTL8367C_CFG_P8_LED1_MUX_OFFSET    5
+#define    RTL8367C_CFG_P8_LED1_MUX_MASK    0x3E0
+#define    RTL8367C_CFG_P8_LED0_MUX_OFFSET    0
+#define    RTL8367C_CFG_P8_LED0_MUX_MASK    0x1F
+
+#define    RTL8367C_REG_P9_LED_MUX    0x1b39
+#define    RTL8367C_CFG_P9_LED2_MUX_OFFSET    10
+#define    RTL8367C_CFG_P9_LED2_MUX_MASK    0x7C00
+#define    RTL8367C_CFG_P9_LED1_MUX_OFFSET    5
+#define    RTL8367C_CFG_P9_LED1_MUX_MASK    0x3E0
+#define    RTL8367C_CFG_P9_LED0_MUX_OFFSET    0
+#define    RTL8367C_CFG_P9_LED0_MUX_MASK    0x1F
+
+#define    RTL8367C_REG_SERIAL_LED_CTRL    0x1b3a
+#define    RTL8367C_SERIAL_LED_SHIFT_SEQUENCE_OFFSET    13
+#define    RTL8367C_SERIAL_LED_SHIFT_SEQUENCE_MASK    0x6000
+#define    RTL8367C_SERIAL_LED_SHIFT_SEQUENCE_EN_OFFSET    12
+#define    RTL8367C_SERIAL_LED_SHIFT_SEQUENCE_EN_MASK    0x1000
+#define    RTL8367C_SERIAL_LED_GROUP_NUM_OFFSET    10
+#define    RTL8367C_SERIAL_LED_GROUP_NUM_MASK    0xC00
+#define    RTL8367C_SERIAL_LED_PORT_EN_OFFSET    0
+#define    RTL8367C_SERIAL_LED_PORT_EN_MASK    0x3FF
+
+/* (16'h1c00)IGMP_EAV */
+
+#define    RTL8367C_REG_IGMP_MLD_CFG0    0x1c00
+#define    RTL8367C_IGMP_MLD_PORTISO_LEAKY_OFFSET    15
+#define    RTL8367C_IGMP_MLD_PORTISO_LEAKY_MASK    0x8000
+#define    RTL8367C_IGMP_MLD_VLAN_LEAKY_OFFSET    14
+#define    RTL8367C_IGMP_MLD_VLAN_LEAKY_MASK    0x4000
+#define    RTL8367C_IGMP_MLD_DISCARD_STORM_FILTER_OFFSET    13
+#define    RTL8367C_IGMP_MLD_DISCARD_STORM_FILTER_MASK    0x2000
+#define    RTL8367C_REPORT_FORWARD_OFFSET    12
+#define    RTL8367C_REPORT_FORWARD_MASK    0x1000
+#define    RTL8367C_ROBURSTNESS_VAR_OFFSET    9
+#define    RTL8367C_ROBURSTNESS_VAR_MASK    0xE00
+#define    RTL8367C_LEAVE_SUPPRESSION_OFFSET    8
+#define    RTL8367C_LEAVE_SUPPRESSION_MASK    0x100
+#define    RTL8367C_REPORT_SUPPRESSION_OFFSET    7
+#define    RTL8367C_REPORT_SUPPRESSION_MASK    0x80
+#define    RTL8367C_LEAVE_TIMER_OFFSET    4
+#define    RTL8367C_LEAVE_TIMER_MASK    0x70
+#define    RTL8367C_FAST_LEAVE_EN_OFFSET    3
+#define    RTL8367C_FAST_LEAVE_EN_MASK    0x8
+#define    RTL8367C_CKS_ERR_OP_OFFSET    1
+#define    RTL8367C_CKS_ERR_OP_MASK    0x6
+#define    RTL8367C_IGMP_MLD_EN_OFFSET    0
+#define    RTL8367C_IGMP_MLD_EN_MASK    0x1
+
+#define    RTL8367C_REG_IGMP_MLD_CFG1    0x1c01
+#define    RTL8367C_DROP_LEAVE_ZERO_OFFSET    2
+#define    RTL8367C_DROP_LEAVE_ZERO_MASK    0x4
+#define    RTL8367C_TABLE_FULL_OP_OFFSET    0
+#define    RTL8367C_TABLE_FULL_OP_MASK    0x3
+
+#define    RTL8367C_REG_IGMP_MLD_CFG2    0x1c02
+
+#define    RTL8367C_REG_IGMP_DYNAMIC_ROUTER_PORT    0x1c03
+#define    RTL8367C_D_ROUTER_PORT_2_OFFSET    11
+#define    RTL8367C_D_ROUTER_PORT_2_MASK    0x7800
+#define    RTL8367C_D_ROUTER_PORT_TMR_2_OFFSET    8
+#define    RTL8367C_D_ROUTER_PORT_TMR_2_MASK    0x700
+#define    RTL8367C_D_ROUTER_PORT_1_OFFSET    3
+#define    RTL8367C_D_ROUTER_PORT_1_MASK    0x78
+#define    RTL8367C_D_ROUTER_PORT_TMR_1_OFFSET    0
+#define    RTL8367C_D_ROUTER_PORT_TMR_1_MASK    0x7
+
+#define    RTL8367C_REG_IGMP_STATIC_ROUTER_PORT    0x1c04
+#define    RTL8367C_IGMP_STATIC_ROUTER_PORT_OFFSET    0
+#define    RTL8367C_IGMP_STATIC_ROUTER_PORT_MASK    0x7FF
+
+#define    RTL8367C_REG_IGMP_PORT0_CONTROL    0x1c05
+#define    RTL8367C_IGMP_PORT0_CONTROL_ALLOW_QUERY_OFFSET    14
+#define    RTL8367C_IGMP_PORT0_CONTROL_ALLOW_QUERY_MASK    0x4000
+#define    RTL8367C_IGMP_PORT0_CONTROL_ALLOW_REPORT_OFFSET    13
+#define    RTL8367C_IGMP_PORT0_CONTROL_ALLOW_REPORT_MASK    0x2000
+#define    RTL8367C_IGMP_PORT0_CONTROL_ALLOW_LEAVE_OFFSET    12
+#define    RTL8367C_IGMP_PORT0_CONTROL_ALLOW_LEAVE_MASK    0x1000
+#define    RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MRP_OFFSET    11
+#define    RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MRP_MASK    0x800
+#define    RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MC_DATA_OFFSET    10
+#define    RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MC_DATA_MASK    0x400
+#define    RTL8367C_IGMP_PORT0_CONTROL_MLDv2_OP_OFFSET    8
+#define    RTL8367C_IGMP_PORT0_CONTROL_MLDv2_OP_MASK    0x300
+#define    RTL8367C_IGMP_PORT0_CONTROL_MLDv1_OP_OFFSET    6
+#define    RTL8367C_IGMP_PORT0_CONTROL_MLDv1_OP_MASK    0xC0
+#define    RTL8367C_IGMP_PORT0_CONTROL_IGMPV3_OP_OFFSET    4
+#define    RTL8367C_IGMP_PORT0_CONTROL_IGMPV3_OP_MASK    0x30
+#define    RTL8367C_IGMP_PORT0_CONTROL_IGMPV2_OP_OFFSET    2
+#define    RTL8367C_IGMP_PORT0_CONTROL_IGMPV2_OP_MASK    0xC
+#define    RTL8367C_IGMP_PORT0_CONTROL_IGMPV1_OP_OFFSET    0
+#define    RTL8367C_IGMP_PORT0_CONTROL_IGMPV1_OP_MASK    0x3
+
+#define    RTL8367C_REG_IGMP_PORT1_CONTROL    0x1c06
+#define    RTL8367C_IGMP_PORT1_CONTROL_ALLOW_QUERY_OFFSET    14
+#define    RTL8367C_IGMP_PORT1_CONTROL_ALLOW_QUERY_MASK    0x4000
+#define    RTL8367C_IGMP_PORT1_CONTROL_ALLOW_REPORT_OFFSET    13
+#define    RTL8367C_IGMP_PORT1_CONTROL_ALLOW_REPORT_MASK    0x2000
+#define    RTL8367C_IGMP_PORT1_CONTROL_ALLOW_LEAVE_OFFSET    12
+#define    RTL8367C_IGMP_PORT1_CONTROL_ALLOW_LEAVE_MASK    0x1000
+#define    RTL8367C_IGMP_PORT1_CONTROL_ALLOW_MRP_OFFSET    11
+#define    RTL8367C_IGMP_PORT1_CONTROL_ALLOW_MRP_MASK    0x800
+#define    RTL8367C_IGMP_PORT1_CONTROL_ALLOW_MC_DATA_OFFSET    10
+#define    RTL8367C_IGMP_PORT1_CONTROL_ALLOW_MC_DATA_MASK    0x400
+#define    RTL8367C_IGMP_PORT1_CONTROL_MLDv2_OP_OFFSET    8
+#define    RTL8367C_IGMP_PORT1_CONTROL_MLDv2_OP_MASK    0x300
+#define    RTL8367C_IGMP_PORT1_CONTROL_MLDv1_OP_OFFSET    6
+#define    RTL8367C_IGMP_PORT1_CONTROL_MLDv1_OP_MASK    0xC0
+#define    RTL8367C_IGMP_PORT1_CONTROL_IGMPV3_OP_OFFSET    4
+#define    RTL8367C_IGMP_PORT1_CONTROL_IGMPV3_OP_MASK    0x30
+#define    RTL8367C_IGMP_PORT1_CONTROL_IGMPV2_OP_OFFSET    2
+#define    RTL8367C_IGMP_PORT1_CONTROL_IGMPV2_OP_MASK    0xC
+#define    RTL8367C_IGMP_PORT1_CONTROL_IGMPV1_OP_OFFSET    0
+#define    RTL8367C_IGMP_PORT1_CONTROL_IGMPV1_OP_MASK    0x3
+
+#define    RTL8367C_REG_IGMP_PORT2_CONTROL    0x1c07
+#define    RTL8367C_IGMP_PORT2_CONTROL_ALLOW_QUERY_OFFSET    14
+#define    RTL8367C_IGMP_PORT2_CONTROL_ALLOW_QUERY_MASK    0x4000
+#define    RTL8367C_IGMP_PORT2_CONTROL_ALLOW_REPORT_OFFSET    13
+#define    RTL8367C_IGMP_PORT2_CONTROL_ALLOW_REPORT_MASK    0x2000
+#define    RTL8367C_IGMP_PORT2_CONTROL_ALLOW_LEAVE_OFFSET    12
+#define    RTL8367C_IGMP_PORT2_CONTROL_ALLOW_LEAVE_MASK    0x1000
+#define    RTL8367C_IGMP_PORT2_CONTROL_ALLOW_MRP_OFFSET    11
+#define    RTL8367C_IGMP_PORT2_CONTROL_ALLOW_MRP_MASK    0x800
+#define    RTL8367C_IGMP_PORT2_CONTROL_ALLOW_MC_DATA_OFFSET    10
+#define    RTL8367C_IGMP_PORT2_CONTROL_ALLOW_MC_DATA_MASK    0x400
+#define    RTL8367C_IGMP_PORT2_CONTROL_MLDv2_OP_OFFSET    8
+#define    RTL8367C_IGMP_PORT2_CONTROL_MLDv2_OP_MASK    0x300
+#define    RTL8367C_IGMP_PORT2_CONTROL_MLDv1_OP_OFFSET    6
+#define    RTL8367C_IGMP_PORT2_CONTROL_MLDv1_OP_MASK    0xC0
+#define    RTL8367C_IGMP_PORT2_CONTROL_IGMPV3_OP_OFFSET    4
+#define    RTL8367C_IGMP_PORT2_CONTROL_IGMPV3_OP_MASK    0x30
+#define    RTL8367C_IGMP_PORT2_CONTROL_IGMPV2_OP_OFFSET    2
+#define    RTL8367C_IGMP_PORT2_CONTROL_IGMPV2_OP_MASK    0xC
+#define    RTL8367C_IGMP_PORT2_CONTROL_IGMPV1_OP_OFFSET    0
+#define    RTL8367C_IGMP_PORT2_CONTROL_IGMPV1_OP_MASK    0x3
+
+#define    RTL8367C_REG_IGMP_PORT3_CONTROL    0x1c08
+#define    RTL8367C_IGMP_PORT3_CONTROL_ALLOW_QUERY_OFFSET    14
+#define    RTL8367C_IGMP_PORT3_CONTROL_ALLOW_QUERY_MASK    0x4000
+#define    RTL8367C_IGMP_PORT3_CONTROL_ALLOW_REPORT_OFFSET    13
+#define    RTL8367C_IGMP_PORT3_CONTROL_ALLOW_REPORT_MASK    0x2000
+#define    RTL8367C_IGMP_PORT3_CONTROL_ALLOW_LEAVE_OFFSET    12
+#define    RTL8367C_IGMP_PORT3_CONTROL_ALLOW_LEAVE_MASK    0x1000
+#define    RTL8367C_IGMP_PORT3_CONTROL_ALLOW_MRP_OFFSET    11
+#define    RTL8367C_IGMP_PORT3_CONTROL_ALLOW_MRP_MASK    0x800
+#define    RTL8367C_IGMP_PORT3_CONTROL_ALLOW_MC_DATA_OFFSET    10
+#define    RTL8367C_IGMP_PORT3_CONTROL_ALLOW_MC_DATA_MASK    0x400
+#define    RTL8367C_IGMP_PORT3_CONTROL_MLDv2_OP_OFFSET    8
+#define    RTL8367C_IGMP_PORT3_CONTROL_MLDv2_OP_MASK    0x300
+#define    RTL8367C_IGMP_PORT3_CONTROL_MLDv1_OP_OFFSET    6
+#define    RTL8367C_IGMP_PORT3_CONTROL_MLDv1_OP_MASK    0xC0
+#define    RTL8367C_IGMP_PORT3_CONTROL_IGMPV3_OP_OFFSET    4
+#define    RTL8367C_IGMP_PORT3_CONTROL_IGMPV3_OP_MASK    0x30
+#define    RTL8367C_IGMP_PORT3_CONTROL_IGMPV2_OP_OFFSET    2
+#define    RTL8367C_IGMP_PORT3_CONTROL_IGMPV2_OP_MASK    0xC
+#define    RTL8367C_IGMP_PORT3_CONTROL_IGMPV1_OP_OFFSET    0
+#define    RTL8367C_IGMP_PORT3_CONTROL_IGMPV1_OP_MASK    0x3
+
+#define    RTL8367C_REG_IGMP_PORT4_CONTROL    0x1c09
+#define    RTL8367C_IGMP_PORT4_CONTROL_ALLOW_QUERY_OFFSET    14
+#define    RTL8367C_IGMP_PORT4_CONTROL_ALLOW_QUERY_MASK    0x4000
+#define    RTL8367C_IGMP_PORT4_CONTROL_ALLOW_REPORT_OFFSET    13
+#define    RTL8367C_IGMP_PORT4_CONTROL_ALLOW_REPORT_MASK    0x2000
+#define    RTL8367C_IGMP_PORT4_CONTROL_ALLOW_LEAVE_OFFSET    12
+#define    RTL8367C_IGMP_PORT4_CONTROL_ALLOW_LEAVE_MASK    0x1000
+#define    RTL8367C_IGMP_PORT4_CONTROL_ALLOW_MRP_OFFSET    11
+#define    RTL8367C_IGMP_PORT4_CONTROL_ALLOW_MRP_MASK    0x800
+#define    RTL8367C_IGMP_PORT4_CONTROL_ALLOW_MC_DATA_OFFSET    10
+#define    RTL8367C_IGMP_PORT4_CONTROL_ALLOW_MC_DATA_MASK    0x400
+#define    RTL8367C_IGMP_PORT4_CONTROL_MLDv2_OP_OFFSET    8
+#define    RTL8367C_IGMP_PORT4_CONTROL_MLDv2_OP_MASK    0x300
+#define    RTL8367C_IGMP_PORT4_CONTROL_MLDv1_OP_OFFSET    6
+#define    RTL8367C_IGMP_PORT4_CONTROL_MLDv1_OP_MASK    0xC0
+#define    RTL8367C_IGMP_PORT4_CONTROL_IGMPV3_OP_OFFSET    4
+#define    RTL8367C_IGMP_PORT4_CONTROL_IGMPV3_OP_MASK    0x30
+#define    RTL8367C_IGMP_PORT4_CONTROL_IGMPV2_OP_OFFSET    2
+#define    RTL8367C_IGMP_PORT4_CONTROL_IGMPV2_OP_MASK    0xC
+#define    RTL8367C_IGMP_PORT4_CONTROL_IGMPV1_OP_OFFSET    0
+#define    RTL8367C_IGMP_PORT4_CONTROL_IGMPV1_OP_MASK    0x3
+
+#define    RTL8367C_REG_IGMP_PORT5_CONTROL    0x1c0a
+#define    RTL8367C_IGMP_PORT5_CONTROL_ALLOW_QUERY_OFFSET    14
+#define    RTL8367C_IGMP_PORT5_CONTROL_ALLOW_QUERY_MASK    0x4000
+#define    RTL8367C_IGMP_PORT5_CONTROL_ALLOW_REPORT_OFFSET    13
+#define    RTL8367C_IGMP_PORT5_CONTROL_ALLOW_REPORT_MASK    0x2000
+#define    RTL8367C_IGMP_PORT5_CONTROL_ALLOW_LEAVE_OFFSET    12
+#define    RTL8367C_IGMP_PORT5_CONTROL_ALLOW_LEAVE_MASK    0x1000
+#define    RTL8367C_IGMP_PORT5_CONTROL_ALLOW_MRP_OFFSET    11
+#define    RTL8367C_IGMP_PORT5_CONTROL_ALLOW_MRP_MASK    0x800
+#define    RTL8367C_IGMP_PORT5_CONTROL_ALLOW_MC_DATA_OFFSET    10
+#define    RTL8367C_IGMP_PORT5_CONTROL_ALLOW_MC_DATA_MASK    0x400
+#define    RTL8367C_IGMP_PORT5_CONTROL_MLDv2_OP_OFFSET    8
+#define    RTL8367C_IGMP_PORT5_CONTROL_MLDv2_OP_MASK    0x300
+#define    RTL8367C_IGMP_PORT5_CONTROL_MLDv1_OP_OFFSET    6
+#define    RTL8367C_IGMP_PORT5_CONTROL_MLDv1_OP_MASK    0xC0
+#define    RTL8367C_IGMP_PORT5_CONTROL_IGMPV3_OP_OFFSET    4
+#define    RTL8367C_IGMP_PORT5_CONTROL_IGMPV3_OP_MASK    0x30
+#define    RTL8367C_IGMP_PORT5_CONTROL_IGMPV2_OP_OFFSET    2
+#define    RTL8367C_IGMP_PORT5_CONTROL_IGMPV2_OP_MASK    0xC
+#define    RTL8367C_IGMP_PORT5_CONTROL_IGMPV1_OP_OFFSET    0
+#define    RTL8367C_IGMP_PORT5_CONTROL_IGMPV1_OP_MASK    0x3
+
+#define    RTL8367C_REG_IGMP_PORT6_CONTROL    0x1c0b
+#define    RTL8367C_IGMP_PORT6_CONTROL_ALLOW_QUERY_OFFSET    14
+#define    RTL8367C_IGMP_PORT6_CONTROL_ALLOW_QUERY_MASK    0x4000
+#define    RTL8367C_IGMP_PORT6_CONTROL_ALLOW_REPORT_OFFSET    13
+#define    RTL8367C_IGMP_PORT6_CONTROL_ALLOW_REPORT_MASK    0x2000
+#define    RTL8367C_IGMP_PORT6_CONTROL_ALLOW_LEAVE_OFFSET    12
+#define    RTL8367C_IGMP_PORT6_CONTROL_ALLOW_LEAVE_MASK    0x1000
+#define    RTL8367C_IGMP_PORT6_CONTROL_ALLOW_MRP_OFFSET    11
+#define    RTL8367C_IGMP_PORT6_CONTROL_ALLOW_MRP_MASK    0x800
+#define    RTL8367C_IGMP_PORT6_CONTROL_ALLOW_MC_DATA_OFFSET    10
+#define    RTL8367C_IGMP_PORT6_CONTROL_ALLOW_MC_DATA_MASK    0x400
+#define    RTL8367C_IGMP_PORT6_CONTROL_MLDv2_OP_OFFSET    8
+#define    RTL8367C_IGMP_PORT6_CONTROL_MLDv2_OP_MASK    0x300
+#define    RTL8367C_IGMP_PORT6_CONTROL_MLDv1_OP_OFFSET    6
+#define    RTL8367C_IGMP_PORT6_CONTROL_MLDv1_OP_MASK    0xC0
+#define    RTL8367C_IGMP_PORT6_CONTROL_IGMPV3_OP_OFFSET    4
+#define    RTL8367C_IGMP_PORT6_CONTROL_IGMPV3_OP_MASK    0x30
+#define    RTL8367C_IGMP_PORT6_CONTROL_IGMPV2_OP_OFFSET    2
+#define    RTL8367C_IGMP_PORT6_CONTROL_IGMPV2_OP_MASK    0xC
+#define    RTL8367C_IGMP_PORT6_CONTROL_IGMPV1_OP_OFFSET    0
+#define    RTL8367C_IGMP_PORT6_CONTROL_IGMPV1_OP_MASK    0x3
+
+#define    RTL8367C_REG_IGMP_PORT7_CONTROL    0x1c0c
+#define    RTL8367C_IGMP_PORT7_CONTROL_ALLOW_QUERY_OFFSET    14
+#define    RTL8367C_IGMP_PORT7_CONTROL_ALLOW_QUERY_MASK    0x4000
+#define    RTL8367C_IGMP_PORT7_CONTROL_ALLOW_REPORT_OFFSET    13
+#define    RTL8367C_IGMP_PORT7_CONTROL_ALLOW_REPORT_MASK    0x2000
+#define    RTL8367C_IGMP_PORT7_CONTROL_ALLOW_LEAVE_OFFSET    12
+#define    RTL8367C_IGMP_PORT7_CONTROL_ALLOW_LEAVE_MASK    0x1000
+#define    RTL8367C_IGMP_PORT7_CONTROL_ALLOW_MRP_OFFSET    11
+#define    RTL8367C_IGMP_PORT7_CONTROL_ALLOW_MRP_MASK    0x800
+#define    RTL8367C_IGMP_PORT7_CONTROL_ALLOW_MC_DATA_OFFSET    10
+#define    RTL8367C_IGMP_PORT7_CONTROL_ALLOW_MC_DATA_MASK    0x400
+#define    RTL8367C_IGMP_PORT7_CONTROL_MLDv2_OP_OFFSET    8
+#define    RTL8367C_IGMP_PORT7_CONTROL_MLDv2_OP_MASK    0x300
+#define    RTL8367C_IGMP_PORT7_CONTROL_MLDv1_OP_OFFSET    6
+#define    RTL8367C_IGMP_PORT7_CONTROL_MLDv1_OP_MASK    0xC0
+#define    RTL8367C_IGMP_PORT7_CONTROL_IGMPV3_OP_OFFSET    4
+#define    RTL8367C_IGMP_PORT7_CONTROL_IGMPV3_OP_MASK    0x30
+#define    RTL8367C_IGMP_PORT7_CONTROL_IGMPV2_OP_OFFSET    2
+#define    RTL8367C_IGMP_PORT7_CONTROL_IGMPV2_OP_MASK    0xC
+#define    RTL8367C_IGMP_PORT7_CONTROL_IGMPV1_OP_OFFSET    0
+#define    RTL8367C_IGMP_PORT7_CONTROL_IGMPV1_OP_MASK    0x3
+
+#define    RTL8367C_REG_IGMP_PORT01_MAX_GROUP    0x1c0d
+#define    RTL8367C_PORT1_MAX_GROUP_OFFSET    8
+#define    RTL8367C_PORT1_MAX_GROUP_MASK    0xFF00
+#define    RTL8367C_PORT0_MAX_GROUP_OFFSET    0
+#define    RTL8367C_PORT0_MAX_GROUP_MASK    0xFF
+
+#define    RTL8367C_REG_IGMP_PORT23_MAX_GROUP    0x1c0e
+#define    RTL8367C_PORT3_MAX_GROUP_OFFSET    8
+#define    RTL8367C_PORT3_MAX_GROUP_MASK    0xFF00
+#define    RTL8367C_PORT2_MAX_GROUP_OFFSET    0
+#define    RTL8367C_PORT2_MAX_GROUP_MASK    0xFF
+
+#define    RTL8367C_REG_IGMP_PORT45_MAX_GROUP    0x1c0f
+#define    RTL8367C_PORT5_MAX_GROUP_OFFSET    8
+#define    RTL8367C_PORT5_MAX_GROUP_MASK    0xFF00
+#define    RTL8367C_PORT4_MAX_GROUP_OFFSET    0
+#define    RTL8367C_PORT4_MAX_GROUP_MASK    0xFF
+
+#define    RTL8367C_REG_IGMP_PORT67_MAX_GROUP    0x1c10
+#define    RTL8367C_PORT7_MAX_GROUP_OFFSET    8
+#define    RTL8367C_PORT7_MAX_GROUP_MASK    0xFF00
+#define    RTL8367C_PORT6_MAX_GROUP_OFFSET    0
+#define    RTL8367C_PORT6_MAX_GROUP_MASK    0xFF
+
+#define    RTL8367C_REG_IGMP_PORT01_CURRENT_GROUP    0x1c11
+#define    RTL8367C_PORT1_CURRENT_GROUP_OFFSET    8
+#define    RTL8367C_PORT1_CURRENT_GROUP_MASK    0xFF00
+#define    RTL8367C_PORT0_CURRENT_GROUP_OFFSET    0
+#define    RTL8367C_PORT0_CURRENT_GROUP_MASK    0xFF
+
+#define    RTL8367C_REG_IGMP_PORT23_CURRENT_GROUP    0x1c12
+#define    RTL8367C_PORT3_CURRENT_GROUP_OFFSET    8
+#define    RTL8367C_PORT3_CURRENT_GROUP_MASK    0xFF00
+#define    RTL8367C_PORT2_CURRENT_GROUP_OFFSET    0
+#define    RTL8367C_PORT2_CURRENT_GROUP_MASK    0xFF
+
+#define    RTL8367C_REG_IGMP_PORT45_CURRENT_GROUP    0x1c13
+#define    RTL8367C_PORT5_CURRENT_GROUP_OFFSET    8
+#define    RTL8367C_PORT5_CURRENT_GROUP_MASK    0xFF00
+#define    RTL8367C_PORT4_CURRENT_GROUP_OFFSET    0
+#define    RTL8367C_PORT4_CURRENT_GROUP_MASK    0xFF
+
+#define    RTL8367C_REG_IGMP_PORT67_CURRENT_GROUP    0x1c14
+#define    RTL8367C_PORT7_CURRENT_GROUP_OFFSET    8
+#define    RTL8367C_PORT7_CURRENT_GROUP_MASK    0xFF00
+#define    RTL8367C_PORT6_CURRENT_GROUP_OFFSET    0
+#define    RTL8367C_PORT6_CURRENT_GROUP_MASK    0xFF
+
+#define    RTL8367C_REG_IGMP_MLD_CFG3    0x1c15
+#define    RTL8367C_IGMP_MLD_IP6_BYPASS_OFFSET    5
+#define    RTL8367C_IGMP_MLD_IP6_BYPASS_MASK    0x20
+#define    RTL8367C_IGMP_MLD_IP4_BYPASS_239_255_255_OFFSET    4
+#define    RTL8367C_IGMP_MLD_IP4_BYPASS_239_255_255_MASK    0x10
+#define    RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_1_OFFSET    3
+#define    RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_1_MASK    0x8
+#define    RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_0_OFFSET    2
+#define    RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_0_MASK    0x4
+#define    RTL8367C_REPORT_LEAVE_FORWARD_OFFSET    0
+#define    RTL8367C_REPORT_LEAVE_FORWARD_MASK    0x3
+
+#define    RTL8367C_REG_IGMP_MLD_CFG4    0x1c16
+#define    RTL8367C_IGMP_MLD_CFG4_OFFSET    0
+#define    RTL8367C_IGMP_MLD_CFG4_MASK    0x7FF
+
+#define    RTL8367C_REG_IGMP_GROUP_USAGE_LIST0    0x1c20
+
+#define    RTL8367C_REG_IGMP_GROUP_USAGE_LIST1    0x1c21
+
+#define    RTL8367C_REG_IGMP_GROUP_USAGE_LIST2    0x1c22
+
+#define    RTL8367C_REG_IGMP_GROUP_USAGE_LIST3    0x1c23
+
+#define    RTL8367C_REG_IGMP_GROUP_USAGE_LIST4    0x1c24
+
+#define    RTL8367C_REG_IGMP_GROUP_USAGE_LIST5    0x1c25
+
+#define    RTL8367C_REG_IGMP_GROUP_USAGE_LIST6    0x1c26
+
+#define    RTL8367C_REG_IGMP_GROUP_USAGE_LIST7    0x1c27
+
+#define    RTL8367C_REG_IGMP_GROUP_USAGE_LIST8    0x1c28
+
+#define    RTL8367C_REG_IGMP_GROUP_USAGE_LIST9    0x1c29
+
+#define    RTL8367C_REG_IGMP_GROUP_USAGE_LIST10    0x1c2a
+
+#define    RTL8367C_REG_IGMP_GROUP_USAGE_LIST11    0x1c2b
+
+#define    RTL8367C_REG_IGMP_GROUP_USAGE_LIST12    0x1c2c
+
+#define    RTL8367C_REG_IGMP_GROUP_USAGE_LIST13    0x1c2d
+
+#define    RTL8367C_REG_IGMP_GROUP_USAGE_LIST14    0x1c2e
+
+#define    RTL8367C_REG_IGMP_GROUP_USAGE_LIST15    0x1c2f
+
+#define    RTL8367C_REG_EAV_CTRL0    0x1c30
+#define    RTL8367C_EAV_CTRL0_OFFSET    0
+#define    RTL8367C_EAV_CTRL0_MASK    0xFF
+
+#define    RTL8367C_REG_EAV_CTRL1    0x1c31
+#define    RTL8367C_REMAP_EAV_PRI3_REGEN_OFFSET    9
+#define    RTL8367C_REMAP_EAV_PRI3_REGEN_MASK    0xE00
+#define    RTL8367C_REMAP_EAV_PRI2_REGEN_OFFSET    6
+#define    RTL8367C_REMAP_EAV_PRI2_REGEN_MASK    0x1C0
+#define    RTL8367C_REMAP_EAV_PRI1_REGEN_OFFSET    3
+#define    RTL8367C_REMAP_EAV_PRI1_REGEN_MASK    0x38
+#define    RTL8367C_REMAP_EAV_PRI0_REGEN_OFFSET    0
+#define    RTL8367C_REMAP_EAV_PRI0_REGEN_MASK    0x7
+
+#define    RTL8367C_REG_EAV_CTRL2    0x1c32
+#define    RTL8367C_REMAP_EAV_PRI7_REGEN_OFFSET    9
+#define    RTL8367C_REMAP_EAV_PRI7_REGEN_MASK    0xE00
+#define    RTL8367C_REMAP_EAV_PRI6_REGEN_OFFSET    6
+#define    RTL8367C_REMAP_EAV_PRI6_REGEN_MASK    0x1C0
+#define    RTL8367C_REMAP_EAV_PRI5_REGEN_OFFSET    3
+#define    RTL8367C_REMAP_EAV_PRI5_REGEN_MASK    0x38
+#define    RTL8367C_REMAP_EAV_PRI4_REGEN_OFFSET    0
+#define    RTL8367C_REMAP_EAV_PRI4_REGEN_MASK    0x7
+
+#define    RTL8367C_REG_SYS_TIME_FREQ    0x1c43
+
+#define    RTL8367C_REG_SYS_TIME_OFFSET_L    0x1c44
+
+#define    RTL8367C_REG_SYS_TIME_OFFSET_H    0x1c45
+
+#define    RTL8367C_REG_SYS_TIME_OFFSET_512NS_L    0x1c46
+
+#define    RTL8367C_REG_SYS_TIME_OFFSET_512NS_H    0x1c47
+#define    RTL8367C_SYS_TIME_OFFSET_TUNE_OFFSET    5
+#define    RTL8367C_SYS_TIME_OFFSET_TUNE_MASK    0x20
+#define    RTL8367C_SYS_TIME_OFFSET_512NS_H_SYS_TIME_OFFSET_512NS_OFFSET    0
+#define    RTL8367C_SYS_TIME_OFFSET_512NS_H_SYS_TIME_OFFSET_512NS_MASK    0x1F
+
+#define    RTL8367C_REG_SYS_TIME_SEC_TRANSIT    0x1c48
+#define    RTL8367C_SYS_TIME_SEC_TRANSIT_OFFSET    0
+#define    RTL8367C_SYS_TIME_SEC_TRANSIT_MASK    0x1
+
+#define    RTL8367C_REG_SYS_TIME_SEC_HIGH_L    0x1c49
+
+#define    RTL8367C_REG_SYS_TIME_SEC_HIGH_H    0x1c4a
+
+#define    RTL8367C_REG_SYS_TIME_512NS_L    0x1c4b
+
+#define    RTL8367C_REG_SYS_TIME_512NS_H    0x1c4c
+#define    RTL8367C_SYS_TIME_512NS_H_OFFSET    0
+#define    RTL8367C_SYS_TIME_512NS_H_MASK    0x1F
+
+#define    RTL8367C_REG_FALLBACK_CTRL    0x1c70
+#define    RTL8367C_FALLBACK_PL_DEC_EN_OFFSET    15
+#define    RTL8367C_FALLBACK_PL_DEC_EN_MASK    0x8000
+#define    RTL8367C_FALLBACK_MONITOR_TIMEOUT_IGNORE_OFFSET    14
+#define    RTL8367C_FALLBACK_MONITOR_TIMEOUT_IGNORE_MASK    0x4000
+#define    RTL8367C_FALLBACK_ERROR_RATIO_THRESHOLD_OFFSET    11
+#define    RTL8367C_FALLBACK_ERROR_RATIO_THRESHOLD_MASK    0x3800
+#define    RTL8367C_FALLBACK_MONITORMAX_OFFSET    8
+#define    RTL8367C_FALLBACK_MONITORMAX_MASK    0x700
+#define    RTL8367C_FALLBACK_MONITOR_TIMEOUT_OFFSET    0
+#define    RTL8367C_FALLBACK_MONITOR_TIMEOUT_MASK    0xFF
+
+#define    RTL8367C_REG_FALLBACK_PORT0_CFG0    0x1c71
+#define    RTL8367C_FALLBACK_PORT0_CFG0_RESET_POWER_LEVEL_OFFSET    15
+#define    RTL8367C_FALLBACK_PORT0_CFG0_RESET_POWER_LEVEL_MASK    0x8000
+#define    RTL8367C_FALLBACK_PORT0_CFG0_ENABLE_OFFSET    14
+#define    RTL8367C_FALLBACK_PORT0_CFG0_ENABLE_MASK    0x4000
+
+#define    RTL8367C_REG_FALLBACK_PORT0_CFG1    0x1c72
+
+#define    RTL8367C_REG_FALLBACK_PORT0_CFG2    0x1c73
+#define    RTL8367C_FALLBACK_PORT0_CFG2_OFFSET    0
+#define    RTL8367C_FALLBACK_PORT0_CFG2_MASK    0xFFF
+
+#define    RTL8367C_REG_FALLBACK_PORT0_CFG3    0x1c74
+#define    RTL8367C_FALLBACK_PORT0_CFG3_OFFSET    0
+#define    RTL8367C_FALLBACK_PORT0_CFG3_MASK    0xFF
+
+#define    RTL8367C_REG_FALLBACK_PORT1_CFG0    0x1c75
+#define    RTL8367C_FALLBACK_PORT1_CFG0_RESET_POWER_LEVEL_OFFSET    15
+#define    RTL8367C_FALLBACK_PORT1_CFG0_RESET_POWER_LEVEL_MASK    0x8000
+#define    RTL8367C_FALLBACK_PORT1_CFG0_ENABLE_OFFSET    14
+#define    RTL8367C_FALLBACK_PORT1_CFG0_ENABLE_MASK    0x4000
+
+#define    RTL8367C_REG_FALLBACK_PORT1_CFG1    0x1c76
+
+#define    RTL8367C_REG_FALLBACK_PORT1_CFG2    0x1c77
+#define    RTL8367C_FALLBACK_PORT1_CFG2_OFFSET    0
+#define    RTL8367C_FALLBACK_PORT1_CFG2_MASK    0xFFF
+
+#define    RTL8367C_REG_FALLBACK_PORT1_CFG3    0x1c78
+#define    RTL8367C_FALLBACK_PORT1_CFG3_OFFSET    0
+#define    RTL8367C_FALLBACK_PORT1_CFG3_MASK    0xFF
+
+#define    RTL8367C_REG_FALLBACK_PORT2_CFG0    0x1c79
+#define    RTL8367C_FALLBACK_PORT2_CFG0_RESET_POWER_LEVEL_OFFSET    15
+#define    RTL8367C_FALLBACK_PORT2_CFG0_RESET_POWER_LEVEL_MASK    0x8000
+#define    RTL8367C_FALLBACK_PORT2_CFG0_ENABLE_OFFSET    14
+#define    RTL8367C_FALLBACK_PORT2_CFG0_ENABLE_MASK    0x4000
+
+#define    RTL8367C_REG_FALLBACK_PORT2_CFG1    0x1c7a
+
+#define    RTL8367C_REG_FALLBACK_PORT2_CFG2    0x1c7b
+#define    RTL8367C_FALLBACK_PORT2_CFG2_OFFSET    0
+#define    RTL8367C_FALLBACK_PORT2_CFG2_MASK    0xFFF
+
+#define    RTL8367C_REG_FALLBACK_PORT2_CFG3    0x1c7c
+#define    RTL8367C_FALLBACK_PORT2_CFG3_OFFSET    0
+#define    RTL8367C_FALLBACK_PORT2_CFG3_MASK    0xFF
+
+#define    RTL8367C_REG_FALLBACK_PORT3_CFG0    0x1c7d
+#define    RTL8367C_FALLBACK_PORT3_CFG0_RESET_POWER_LEVEL_OFFSET    15
+#define    RTL8367C_FALLBACK_PORT3_CFG0_RESET_POWER_LEVEL_MASK    0x8000
+#define    RTL8367C_FALLBACK_PORT3_CFG0_ENABLE_OFFSET    14
+#define    RTL8367C_FALLBACK_PORT3_CFG0_ENABLE_MASK    0x4000
+
+#define    RTL8367C_REG_FALLBACK_PORT3_CFG1    0x1c7e
+
+#define    RTL8367C_REG_FALLBACK_PORT3_CFG2    0x1c7f
+#define    RTL8367C_FALLBACK_PORT3_CFG2_OFFSET    0
+#define    RTL8367C_FALLBACK_PORT3_CFG2_MASK    0xFFF
+
+#define    RTL8367C_REG_FALLBACK_PORT3_CFG3    0x1c80
+#define    RTL8367C_FALLBACK_PORT3_CFG3_OFFSET    0
+#define    RTL8367C_FALLBACK_PORT3_CFG3_MASK    0xFF
+
+#define    RTL8367C_REG_FALLBACK_PORT4_CFG0    0x1c81
+#define    RTL8367C_FALLBACK_PORT4_CFG0_RESET_POWER_LEVEL_OFFSET    15
+#define    RTL8367C_FALLBACK_PORT4_CFG0_RESET_POWER_LEVEL_MASK    0x8000
+#define    RTL8367C_FALLBACK_PORT4_CFG0_ENABLE_OFFSET    14
+#define    RTL8367C_FALLBACK_PORT4_CFG0_ENABLE_MASK    0x4000
+
+#define    RTL8367C_REG_FALLBACK_PORT4_CFG1    0x1c82
+
+#define    RTL8367C_REG_FALLBACK_PORT4_CFG2    0x1c83
+#define    RTL8367C_FALLBACK_PORT4_CFG2_OFFSET    0
+#define    RTL8367C_FALLBACK_PORT4_CFG2_MASK    0xFFF
+
+#define    RTL8367C_REG_FALLBACK_PORT4_CFG3    0x1c84
+#define    RTL8367C_FALLBACK_PORT4_CFG3_OFFSET    0
+#define    RTL8367C_FALLBACK_PORT4_CFG3_MASK    0xFF
+
+#define    RTL8367C_REG_FALLBACK_CTRL1    0x1c85
+#define    RTL8367C_FALLBACK_VALIDFLOW_OFFSET    8
+#define    RTL8367C_FALLBACK_VALIDFLOW_MASK    0xFF00
+#define    RTL8367C_FALLBACK_STOP_TMR_OFFSET    0
+#define    RTL8367C_FALLBACK_STOP_TMR_MASK    0x1
+
+#define    RTL8367C_REG_FALLBACK_CPL    0x1c86
+#define    RTL8367C_PORT4_CPL_OFFSET    4
+#define    RTL8367C_PORT4_CPL_MASK    0x10
+#define    RTL8367C_PORT3_CPL_OFFSET    3
+#define    RTL8367C_PORT3_CPL_MASK    0x8
+#define    RTL8367C_PORT2_CPL_OFFSET    2
+#define    RTL8367C_PORT2_CPL_MASK    0x4
+#define    RTL8367C_PORT1_CPL_OFFSET    1
+#define    RTL8367C_PORT1_CPL_MASK    0x2
+#define    RTL8367C_PORT0_CPL_OFFSET    0
+#define    RTL8367C_PORT0_CPL_MASK    0x1
+
+#define    RTL8367C_REG_FALLBACK_PHY_PAGE    0x1c87
+#define    RTL8367C_FALLBACK_PHY_PAGE_OFFSET    0
+#define    RTL8367C_FALLBACK_PHY_PAGE_MASK    0xFFF
+
+#define    RTL8367C_REG_FALLBACK_PHY_REG    0x1c88
+#define    RTL8367C_FALLBACK_PHY_REG_OFFSET    0
+#define    RTL8367C_FALLBACK_PHY_REG_MASK    0x1F
+
+#define    RTL8367C_REG_AFBK_INFO_X0    0x1c89
+
+#define    RTL8367C_REG_AFBK_INFO_X1    0x1c8a
+
+#define    RTL8367C_REG_AFBK_INFO_X2    0x1c8b
+
+#define    RTL8367C_REG_AFBK_INFO_X3    0x1c8c
+
+#define    RTL8367C_REG_AFBK_INFO_X4    0x1c8d
+
+#define    RTL8367C_REG_AFBK_INFO_X5    0x1c8e
+
+#define    RTL8367C_REG_AFBK_INFO_X6    0x1c8f
+
+#define    RTL8367C_REG_AFBK_INFO_X7    0x1c90
+
+#define    RTL8367C_REG_AFBK_INFO_X8    0x1c91
+
+#define    RTL8367C_REG_AFBK_INFO_X9    0x1c92
+
+#define    RTL8367C_REG_AFBK_INFO_X10    0x1c93
+
+#define    RTL8367C_REG_AFBK_INFO_X11    0x1c94
+
+#define    RTL8367C_REG_FALLBACK_PORT5_CFG0    0x1ca0
+#define    RTL8367C_FALLBACK_PORT5_CFG0_RESET_POWER_LEVEL_OFFSET    15
+#define    RTL8367C_FALLBACK_PORT5_CFG0_RESET_POWER_LEVEL_MASK    0x8000
+#define    RTL8367C_FALLBACK_PORT5_CFG0_ENABLE_OFFSET    14
+#define    RTL8367C_FALLBACK_PORT5_CFG0_ENABLE_MASK    0x4000
+
+#define    RTL8367C_REG_FALLBACK_PORT5_CFG1    0x1ca1
+
+#define    RTL8367C_REG_FALLBACK_PORT5_CFG2    0x1ca2
+#define    RTL8367C_FALLBACK_PORT5_CFG2_OFFSET    0
+#define    RTL8367C_FALLBACK_PORT5_CFG2_MASK    0xFFF
+
+#define    RTL8367C_REG_FALLBACK_PORT5_CFG3    0x1ca3
+#define    RTL8367C_FALLBACK_PORT5_CFG3_OFFSET    0
+#define    RTL8367C_FALLBACK_PORT5_CFG3_MASK    0xFF
+
+#define    RTL8367C_REG_FALLBACK_PORT6_CFG0    0x1ca4
+#define    RTL8367C_FALLBACK_PORT6_CFG0_RESET_POWER_LEVEL_OFFSET    15
+#define    RTL8367C_FALLBACK_PORT6_CFG0_RESET_POWER_LEVEL_MASK    0x8000
+#define    RTL8367C_FALLBACK_PORT6_CFG0_ENABLE_OFFSET    14
+#define    RTL8367C_FALLBACK_PORT6_CFG0_ENABLE_MASK    0x4000
+
+#define    RTL8367C_REG_FALLBACK_PORT6_CFG1    0x1ca5
+
+#define    RTL8367C_REG_FALLBACK_PORT6_CFG2    0x1ca6
+#define    RTL8367C_FALLBACK_PORT6_CFG2_OFFSET    0
+#define    RTL8367C_FALLBACK_PORT6_CFG2_MASK    0xFFF
+
+#define    RTL8367C_REG_FALLBACK_PORT6_CFG3    0x1ca7
+#define    RTL8367C_FALLBACK_PORT6_CFG3_OFFSET    0
+#define    RTL8367C_FALLBACK_PORT6_CFG3_MASK    0xFF
+
+#define    RTL8367C_REG_FALLBACK_PORT7_CFG0    0x1ca8
+#define    RTL8367C_FALLBACK_PORT7_CFG0_RESET_POWER_LEVEL_OFFSET    15
+#define    RTL8367C_FALLBACK_PORT7_CFG0_RESET_POWER_LEVEL_MASK    0x8000
+#define    RTL8367C_FALLBACK_PORT7_CFG0_ENABLE_OFFSET    14
+#define    RTL8367C_FALLBACK_PORT7_CFG0_ENABLE_MASK    0x4000
+
+#define    RTL8367C_REG_FALLBACK_PORT7_CFG1    0x1ca9
+
+#define    RTL8367C_REG_FALLBACK_PORT7_CFG2    0x1caa
+#define    RTL8367C_FALLBACK_PORT7_CFG2_OFFSET    0
+#define    RTL8367C_FALLBACK_PORT7_CFG2_MASK    0xFFF
+
+#define    RTL8367C_REG_FALLBACK_PORT7_CFG3    0x1cab
+#define    RTL8367C_FALLBACK_PORT7_CFG3_OFFSET    0
+#define    RTL8367C_FALLBACK_PORT7_CFG3_MASK    0xFF
+
+#define    RTL8367C_REG_IGMP_PORT8_CONTROL    0x1cb0
+#define    RTL8367C_IGMP_PORT8_CONTROL_ALLOW_QUERY_OFFSET    14
+#define    RTL8367C_IGMP_PORT8_CONTROL_ALLOW_QUERY_MASK    0x4000
+#define    RTL8367C_IGMP_PORT8_CONTROL_ALLOW_REPORT_OFFSET    13
+#define    RTL8367C_IGMP_PORT8_CONTROL_ALLOW_REPORT_MASK    0x2000
+#define    RTL8367C_IGMP_PORT8_CONTROL_ALLOW_LEAVE_OFFSET    12
+#define    RTL8367C_IGMP_PORT8_CONTROL_ALLOW_LEAVE_MASK    0x1000
+#define    RTL8367C_IGMP_PORT8_CONTROL_ALLOW_MRP_OFFSET    11
+#define    RTL8367C_IGMP_PORT8_CONTROL_ALLOW_MRP_MASK    0x800
+#define    RTL8367C_IGMP_PORT8_CONTROL_ALLOW_MC_DATA_OFFSET    10
+#define    RTL8367C_IGMP_PORT8_CONTROL_ALLOW_MC_DATA_MASK    0x400
+#define    RTL8367C_IGMP_PORT8_CONTROL_MLDv2_OP_OFFSET    8
+#define    RTL8367C_IGMP_PORT8_CONTROL_MLDv2_OP_MASK    0x300
+#define    RTL8367C_IGMP_PORT8_CONTROL_MLDv1_OP_OFFSET    6
+#define    RTL8367C_IGMP_PORT8_CONTROL_MLDv1_OP_MASK    0xC0
+#define    RTL8367C_IGMP_PORT8_CONTROL_IGMPV3_OP_OFFSET    4
+#define    RTL8367C_IGMP_PORT8_CONTROL_IGMPV3_OP_MASK    0x30
+#define    RTL8367C_IGMP_PORT8_CONTROL_IGMPV2_OP_OFFSET    2
+#define    RTL8367C_IGMP_PORT8_CONTROL_IGMPV2_OP_MASK    0xC
+#define    RTL8367C_IGMP_PORT8_CONTROL_IGMPV1_OP_OFFSET    0
+#define    RTL8367C_IGMP_PORT8_CONTROL_IGMPV1_OP_MASK    0x3
+
+#define    RTL8367C_REG_IGMP_PORT9_CONTROL    0x1cb1
+#define    RTL8367C_IGMP_PORT9_CONTROL_ALLOW_QUERY_OFFSET    14
+#define    RTL8367C_IGMP_PORT9_CONTROL_ALLOW_QUERY_MASK    0x4000
+#define    RTL8367C_IGMP_PORT9_CONTROL_ALLOW_REPORT_OFFSET    13
+#define    RTL8367C_IGMP_PORT9_CONTROL_ALLOW_REPORT_MASK    0x2000
+#define    RTL8367C_IGMP_PORT9_CONTROL_ALLOW_LEAVE_OFFSET    12
+#define    RTL8367C_IGMP_PORT9_CONTROL_ALLOW_LEAVE_MASK    0x1000
+#define    RTL8367C_IGMP_PORT9_CONTROL_ALLOW_MRP_OFFSET    11
+#define    RTL8367C_IGMP_PORT9_CONTROL_ALLOW_MRP_MASK    0x800
+#define    RTL8367C_IGMP_PORT9_CONTROL_ALLOW_MC_DATA_OFFSET    10
+#define    RTL8367C_IGMP_PORT9_CONTROL_ALLOW_MC_DATA_MASK    0x400
+#define    RTL8367C_IGMP_PORT9_CONTROL_MLDv2_OP_OFFSET    8
+#define    RTL8367C_IGMP_PORT9_CONTROL_MLDv2_OP_MASK    0x300
+#define    RTL8367C_IGMP_PORT9_CONTROL_MLDv1_OP_OFFSET    6
+#define    RTL8367C_IGMP_PORT9_CONTROL_MLDv1_OP_MASK    0xC0
+#define    RTL8367C_IGMP_PORT9_CONTROL_IGMPV3_OP_OFFSET    4
+#define    RTL8367C_IGMP_PORT9_CONTROL_IGMPV3_OP_MASK    0x30
+#define    RTL8367C_IGMP_PORT9_CONTROL_IGMPV2_OP_OFFSET    2
+#define    RTL8367C_IGMP_PORT9_CONTROL_IGMPV2_OP_MASK    0xC
+#define    RTL8367C_IGMP_PORT9_CONTROL_IGMPV1_OP_OFFSET    0
+#define    RTL8367C_IGMP_PORT9_CONTROL_IGMPV1_OP_MASK    0x3
+
+#define    RTL8367C_REG_IGMP_PORT10_CONTROL    0x1cb2
+#define    RTL8367C_IGMP_PORT10_CONTROL_ALLOW_QUERY_OFFSET    14
+#define    RTL8367C_IGMP_PORT10_CONTROL_ALLOW_QUERY_MASK    0x4000
+#define    RTL8367C_IGMP_PORT10_CONTROL_ALLOW_REPORT_OFFSET    13
+#define    RTL8367C_IGMP_PORT10_CONTROL_ALLOW_REPORT_MASK    0x2000
+#define    RTL8367C_IGMP_PORT10_CONTROL_ALLOW_LEAVE_OFFSET    12
+#define    RTL8367C_IGMP_PORT10_CONTROL_ALLOW_LEAVE_MASK    0x1000
+#define    RTL8367C_IGMP_PORT10_CONTROL_ALLOW_MRP_OFFSET    11
+#define    RTL8367C_IGMP_PORT10_CONTROL_ALLOW_MRP_MASK    0x800
+#define    RTL8367C_IGMP_PORT10_CONTROL_ALLOW_MC_DATA_OFFSET    10
+#define    RTL8367C_IGMP_PORT10_CONTROL_ALLOW_MC_DATA_MASK    0x400
+#define    RTL8367C_IGMP_PORT10_CONTROL_MLDv2_OP_OFFSET    8
+#define    RTL8367C_IGMP_PORT10_CONTROL_MLDv2_OP_MASK    0x300
+#define    RTL8367C_IGMP_PORT10_CONTROL_MLDv1_OP_OFFSET    6
+#define    RTL8367C_IGMP_PORT10_CONTROL_MLDv1_OP_MASK    0xC0
+#define    RTL8367C_IGMP_PORT10_CONTROL_IGMPV3_OP_OFFSET    4
+#define    RTL8367C_IGMP_PORT10_CONTROL_IGMPV3_OP_MASK    0x30
+#define    RTL8367C_IGMP_PORT10_CONTROL_IGMPV2_OP_OFFSET    2
+#define    RTL8367C_IGMP_PORT10_CONTROL_IGMPV2_OP_MASK    0xC
+#define    RTL8367C_IGMP_PORT10_CONTROL_IGMPV1_OP_OFFSET    0
+#define    RTL8367C_IGMP_PORT10_CONTROL_IGMPV1_OP_MASK    0x3
+
+#define    RTL8367C_REG_IGMP_PORT89_MAX_GROUP    0x1cb3
+#define    RTL8367C_PORT9_MAX_GROUP_OFFSET    8
+#define    RTL8367C_PORT9_MAX_GROUP_MASK    0xFF00
+#define    RTL8367C_PORT8_MAX_GROUP_OFFSET    0
+#define    RTL8367C_PORT8_MAX_GROUP_MASK    0xFF
+
+#define    RTL8367C_REG_IGMP_PORT10_MAX_GROUP    0x1cb4
+#define    RTL8367C_IGMP_PORT10_MAX_GROUP_OFFSET    0
+#define    RTL8367C_IGMP_PORT10_MAX_GROUP_MASK    0xFF
+
+#define    RTL8367C_REG_IGMP_PORT89_CURRENT_GROUP    0x1cb5
+#define    RTL8367C_PORT9_CURRENT_GROUP_OFFSET    8
+#define    RTL8367C_PORT9_CURRENT_GROUP_MASK    0xFF00
+#define    RTL8367C_PORT8_CURRENT_GROUP_OFFSET    0
+#define    RTL8367C_PORT8_CURRENT_GROUP_MASK    0xFF
+
+#define    RTL8367C_REG_IGMP_PORT10_CURRENT_GROUP    0x1cb6
+#define    RTL8367C_IGMP_PORT10_CURRENT_GROUP_OFFSET    0
+#define    RTL8367C_IGMP_PORT10_CURRENT_GROUP_MASK    0xFF
+
+#define    RTL8367C_REG_IGMP_L3_CHECKSUM_CHECK    0x1cb7
+#define    RTL8367C_IGMP_L3_CHECKSUM_CHECK_OFFSET    0
+#define    RTL8367C_IGMP_L3_CHECKSUM_CHECK_MASK    0x1
+
+/* (16'h1d00)chip_70b_reg */
+
+#define    RTL8367C_REG_PCSXF_CFG    0x1d00
+#define    RTL8367C_PCSXF_CFG_Reserved_OFFSET    15
+#define    RTL8367C_PCSXF_CFG_Reserved_MASK    0x8000
+#define    RTL8367C_CFG_RST_RXFIFO_P7_5_OFFSET    12
+#define    RTL8367C_CFG_RST_RXFIFO_P7_5_MASK    0x7000
+#define    RTL8367C_CFG_PCSXF_OFFSET    8
+#define    RTL8367C_CFG_PCSXF_MASK    0xF00
+#define    RTL8367C_CFG_RST_RXFIFO_OFFSET    3
+#define    RTL8367C_CFG_RST_RXFIFO_MASK    0xF8
+#define    RTL8367C_CFG_COL2RXDV_OFFSET    2
+#define    RTL8367C_CFG_COL2RXDV_MASK    0x4
+#define    RTL8367C_CFG_PHY_SDET_OFFSET    0
+#define    RTL8367C_CFG_PHY_SDET_MASK    0x3
+
+#define    RTL8367C_REG_PHYID_CFG0    0x1d01
+#define    RTL8367C_CFG_PHY_BRD_MODE_P7_5_OFFSET    11
+#define    RTL8367C_CFG_PHY_BRD_MODE_P7_5_MASK    0x3800
+#define    RTL8367C_CFG_PHYAD_14C_OFFSET    10
+#define    RTL8367C_CFG_PHYAD_14C_MASK    0x400
+#define    RTL8367C_CFG_PHY_BRD_MODE_OFFSET    5
+#define    RTL8367C_CFG_PHY_BRD_MODE_MASK    0x3E0
+#define    RTL8367C_CFG_BRD_PHYAD_OFFSET    0
+#define    RTL8367C_CFG_BRD_PHYAD_MASK    0x1F
+
+#define    RTL8367C_REG_PHYID_CFG1    0x1d02
+#define    RTL8367C_CFG_MSK_MDI_OFFSET    5
+#define    RTL8367C_CFG_MSK_MDI_MASK    0x1FE0
+#define    RTL8367C_CFG_BASE_PHYAD_OFFSET    0
+#define    RTL8367C_CFG_BASE_PHYAD_MASK    0x1F
+
+#define    RTL8367C_REG_PHY_POLL_CFG0    0x1d03
+#define    RTL8367C_CFG_HOTCMD_PRD_EN_OFFSET    15
+#define    RTL8367C_CFG_HOTCMD_PRD_EN_MASK    0x8000
+#define    RTL8367C_CFG_HOTCMD_EN_OFFSET    12
+#define    RTL8367C_CFG_HOTCMD_EN_MASK    0x7000
+#define    RTL8367C_CFG_POLL_PERIOD_OFFSET    8
+#define    RTL8367C_CFG_POLL_PERIOD_MASK    0xF00
+#define    RTL8367C_CFG_PERI_CMDS_RD_OFFSET    4
+#define    RTL8367C_CFG_PERI_CMDS_RD_MASK    0xF0
+#define    RTL8367C_CFG_PERI_CMDS_WR_OFFSET    0
+#define    RTL8367C_CFG_PERI_CMDS_WR_MASK    0xF
+
+#define    RTL8367C_REG_PHY_POLL_CFG1    0x1d04
+
+#define    RTL8367C_REG_PHY_POLL_CFG2    0x1d05
+
+#define    RTL8367C_REG_PHY_POLL_CFG3    0x1d06
+
+#define    RTL8367C_REG_PHY_POLL_CFG4    0x1d07
+
+#define    RTL8367C_REG_PHY_POLL_CFG5    0x1d08
+
+#define    RTL8367C_REG_PHY_POLL_CFG6    0x1d09
+
+#define    RTL8367C_REG_PHY_POLL_CFG7    0x1d0a
+
+#define    RTL8367C_REG_PHY_POLL_CFG8    0x1d0b
+
+#define    RTL8367C_REG_PHY_POLL_CFG9    0x1d0c
+
+#define    RTL8367C_REG_PHY_POLL_CFG10    0x1d0d
+
+#define    RTL8367C_REG_PHY_POLL_CFG11    0x1d0e
+
+#define    RTL8367C_REG_PHY_POLL_CFG12    0x1d0f
+
+#define    RTL8367C_REG_EFUSE_MISC    0x1d10
+#define    RTL8367C_CFG_SA_SEL_OFFSET    5
+#define    RTL8367C_CFG_SA_SEL_MASK    0x20
+#define    RTL8367C_CFG_PHYAD00_OFFSET    0
+#define    RTL8367C_CFG_PHYAD00_MASK    0x1F
+
+#define    RTL8367C_REG_SDS_MISC    0x1d11
+#define    RTL8367C_CFG_SGMII_RXFC_OFFSET    14
+#define    RTL8367C_CFG_SGMII_RXFC_MASK    0x4000
+#define    RTL8367C_CFG_SGMII_TXFC_OFFSET    13
+#define    RTL8367C_CFG_SGMII_TXFC_MASK    0x2000
+#define    RTL8367C_INB_ARB_OFFSET    12
+#define    RTL8367C_INB_ARB_MASK    0x1000
+#define    RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET    11
+#define    RTL8367C_CFG_MAC8_SEL_HSGMII_MASK    0x800
+#define    RTL8367C_CFG_SGMII_FDUP_OFFSET    10
+#define    RTL8367C_CFG_SGMII_FDUP_MASK    0x400
+#define    RTL8367C_CFG_SGMII_LINK_OFFSET    9
+#define    RTL8367C_CFG_SGMII_LINK_MASK    0x200
+#define    RTL8367C_CFG_SGMII_SPD_OFFSET    7
+#define    RTL8367C_CFG_SGMII_SPD_MASK    0x180
+#define    RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET    6
+#define    RTL8367C_CFG_MAC8_SEL_SGMII_MASK    0x40
+#define    RTL8367C_CFG_INB_SEL_OFFSET    3
+#define    RTL8367C_CFG_INB_SEL_MASK    0x38
+#define    RTL8367C_CFG_SDS_MODE_18C_OFFSET    0
+#define    RTL8367C_CFG_SDS_MODE_18C_MASK    0x7
+
+#define    RTL8367C_REG_FIFO_CTRL    0x1d12
+#define    RTL8367C_CFG_LINK_DOWN_CLR_FIFO_OFFSET    11
+#define    RTL8367C_CFG_LINK_DOWN_CLR_FIFO_MASK    0x800
+#define    RTL8367C_CFG_LPBK_OFFSET    10
+#define    RTL8367C_CFG_LPBK_MASK    0x400
+#define    RTL8367C_CFG_NOT_FF_OUT_OFFSET    9
+#define    RTL8367C_CFG_NOT_FF_OUT_MASK    0x200
+#define    RTL8367C_CFG_WATER_LEVEL_FD_OFFSET    6
+#define    RTL8367C_CFG_WATER_LEVEL_FD_MASK    0x1C0
+#define    RTL8367C_CFG_WATER_LEVEL_Y2X_OFFSET    3
+#define    RTL8367C_CFG_WATER_LEVEL_Y2X_MASK    0x38
+#define    RTL8367C_CFG_WATER_LEVEL_X2Y_OFFSET    0
+#define    RTL8367C_CFG_WATER_LEVEL_X2Y_MASK    0x7
+
+#define    RTL8367C_REG_BCAM_SETTING    0x1d13
+#define    RTL8367C_CFG_BCAM_MDS_OFFSET    3
+#define    RTL8367C_CFG_BCAM_MDS_MASK    0x18
+#define    RTL8367C_CFG_BCAM_RDS_OFFSET    0
+#define    RTL8367C_CFG_BCAM_RDS_MASK    0x7
+
+#define    RTL8367C_REG_GPHY_ACS_MISC    0x1d14
+#define    RTL8367C_CFG_SEL_GPHY_SMI_OFFSET    3
+#define    RTL8367C_CFG_SEL_GPHY_SMI_MASK    0x8
+#define    RTL8367C_CFG_BRD_PHYIDX_OFFSET    0
+#define    RTL8367C_CFG_BRD_PHYIDX_MASK    0x7
+
+#define    RTL8367C_REG_GPHY_OCP_MSB_0    0x1d15
+#define    RTL8367C_CFG_CPU_OCPADR_MSB_OFFSET    6
+#define    RTL8367C_CFG_CPU_OCPADR_MSB_MASK    0xFC0
+#define    RTL8367C_CFG_DW8051_OCPADR_MSB_OFFSET    0
+#define    RTL8367C_CFG_DW8051_OCPADR_MSB_MASK    0x3F
+
+#define    RTL8367C_REG_GPHY_OCP_MSB_1    0x1d16
+#define    RTL8367C_CFG_PATCH_OCPADR_MSB_OFFSET    6
+#define    RTL8367C_CFG_PATCH_OCPADR_MSB_MASK    0xFC0
+#define    RTL8367C_CFG_PHYSTS_OCPADR_MSB_OFFSET    0
+#define    RTL8367C_CFG_PHYSTS_OCPADR_MSB_MASK    0x3F
+
+#define    RTL8367C_REG_GPHY_OCP_MSB_2    0x1d17
+#define    RTL8367C_CFG_RRCP_OCPADR_MSB_OFFSET    6
+#define    RTL8367C_CFG_RRCP_OCPADR_MSB_MASK    0xFC0
+#define    RTL8367C_CFG_RTCT_OCPADR_MSB_OFFSET    0
+#define    RTL8367C_CFG_RTCT_OCPADR_MSB_MASK    0x3F
+
+#define    RTL8367C_REG_GPHY_OCP_MSB_3    0x1d18
+#define    RTL8367C_GPHY_OCP_MSB_3_OFFSET    0
+#define    RTL8367C_GPHY_OCP_MSB_3_MASK    0x3F
+
+#define    RTL8367C_REG_GPIO_67C_I_X0    0x1d19
+
+#define    RTL8367C_REG_GPIO_67C_I_X1    0x1d1a
+
+#define    RTL8367C_REG_GPIO_67C_I_X2    0x1d1b
+
+#define    RTL8367C_REG_GPIO_67C_I_X3    0x1d1c
+#define    RTL8367C_GPIO_67C_I_X3_OFFSET    0
+#define    RTL8367C_GPIO_67C_I_X3_MASK    0x3FFF
+
+#define    RTL8367C_REG_GPIO_67C_O_X0    0x1d1d
+
+#define    RTL8367C_REG_GPIO_67C_O_X1    0x1d1e
+
+#define    RTL8367C_REG_GPIO_67C_O_X2    0x1d1f
+
+#define    RTL8367C_REG_GPIO_67C_O_X3    0x1d20
+#define    RTL8367C_GPIO_67C_O_X3_OFFSET    0
+#define    RTL8367C_GPIO_67C_O_X3_MASK    0x3FFF
+
+#define    RTL8367C_REG_GPIO_67C_OE_X0    0x1d21
+
+#define    RTL8367C_REG_GPIO_67C_OE_X1    0x1d22
+
+#define    RTL8367C_REG_GPIO_67C_OE_X2    0x1d23
+
+#define    RTL8367C_REG_GPIO_67C_OE_X3    0x1d24
+#define    RTL8367C_GPIO_67C_OE_X3_OFFSET    0
+#define    RTL8367C_GPIO_67C_OE_X3_MASK    0x3FFF
+
+#define    RTL8367C_REG_GPIO_MODE_67C_X0    0x1d25
+
+#define    RTL8367C_REG_GPIO_MODE_67C_X1    0x1d26
+
+#define    RTL8367C_REG_GPIO_MODE_67C_X2    0x1d27
+
+#define    RTL8367C_REG_GPIO_MODE_67C_X3    0x1d28
+#define    RTL8367C_GPIO_MODE_67C_X3_OFFSET    0
+#define    RTL8367C_GPIO_MODE_67C_X3_MASK    0x3FFF
+
+#define    RTL8367C_REG_WGPHY_MISC_0    0x1d29
+#define    RTL8367C_CFG_INIPHY_DISGIGA_P7_5_OFFSET    13
+#define    RTL8367C_CFG_INIPHY_DISGIGA_P7_5_MASK    0xE000
+#define    RTL8367C_CFG_INIPHY_PWRUP_OFFSET    5
+#define    RTL8367C_CFG_INIPHY_PWRUP_MASK    0x1FE0
+#define    RTL8367C_CFG_INIPHY_DISGIGA_OFFSET    0
+#define    RTL8367C_CFG_INIPHY_DISGIGA_MASK    0x1F
+
+#define    RTL8367C_REG_WGPHY_MISC_1    0x1d2a
+#define    RTL8367C_WGPHY_MISC_1_OFFSET    0
+#define    RTL8367C_WGPHY_MISC_1_MASK    0xFF
+
+#define    RTL8367C_REG_WGPHY_MISC_2    0x1d2b
+#define    RTL8367C_WGPHY_MISC_2_OFFSET    0
+#define    RTL8367C_WGPHY_MISC_2_MASK    0x3FF
+
+#define    RTL8367C_REG_CFG_AFBK_GPHY_0    0x1d2c
+#define    RTL8367C_CFG_AFBK_GPHY_0_OFFSET    0
+#define    RTL8367C_CFG_AFBK_GPHY_0_MASK    0x1F
+
+#define    RTL8367C_REG_CFG_AFBK_GPHY_1    0x1d2d
+#define    RTL8367C_CFG_AFBK_GPHY_1_OFFSET    0
+#define    RTL8367C_CFG_AFBK_GPHY_1_MASK    0xFFF
+
+#define    RTL8367C_REG_EF_SLV_CTRL_0    0x1d2e
+#define    RTL8367C_EF_SLV_BUSY_OFFSET    11
+#define    RTL8367C_EF_SLV_BUSY_MASK    0x800
+#define    RTL8367C_EF_SLV_ACK_OFFSET    10
+#define    RTL8367C_EF_SLV_ACK_MASK    0x400
+#define    RTL8367C_EF_SLV_A_OFFSET    2
+#define    RTL8367C_EF_SLV_A_MASK    0x3FC
+#define    RTL8367C_EF_SLV_WE_OFFSET    1
+#define    RTL8367C_EF_SLV_WE_MASK    0x2
+#define    RTL8367C_EF_SLV_CE_OFFSET    0
+#define    RTL8367C_EF_SLV_CE_MASK    0x1
+
+#define    RTL8367C_REG_EF_SLV_CTRL_1    0x1d2f
+
+#define    RTL8367C_REG_EF_SLV_CTRL_2    0x1d30
+
+#define    RTL8367C_REG_EFUSE_MISC_1    0x1d31
+#define    RTL8367C_EF_EN_EFUSE_OFFSET    10
+#define    RTL8367C_EF_EN_EFUSE_MASK    0x400
+#define    RTL8367C_EF_MODEL_ID_OFFSET    6
+#define    RTL8367C_EF_MODEL_ID_MASK    0x3C0
+#define    RTL8367C_EF_RSVD_OFFSET    2
+#define    RTL8367C_EF_RSVD_MASK    0x3C
+#define    RTL8367C_EF_SYS_CLK_OFFSET    0
+#define    RTL8367C_EF_SYS_CLK_MASK    0x3
+
+#define    RTL8367C_REG_IO_MISC_FUNC    0x1d32
+#define    RTL8367C_TST_MODE_OFFSET    3
+#define    RTL8367C_TST_MODE_MASK    0x8
+#define    RTL8367C_UART_EN_OFFSET    2
+#define    RTL8367C_UART_EN_MASK    0x4
+#define    RTL8367C_INT_EN_OFFSET    1
+#define    RTL8367C_INT_EN_MASK    0x2
+#define    RTL8367C_BUZ_EN_OFFSET    0
+#define    RTL8367C_BUZ_EN_MASK    0x1
+
+#define    RTL8367C_REG_HTRAM_DVS    0x1d33
+#define    RTL8367C_HTRAM_DVS_OFFSET    0
+#define    RTL8367C_HTRAM_DVS_MASK    0x1
+
+#define    RTL8367C_REG_EF_SLV_CTRL_3    0x1d34
+#define    RTL8367C_EF_SLV_CTRL_3_OFFSET    0
+#define    RTL8367C_EF_SLV_CTRL_3_MASK    0x1
+
+#define    RTL8367C_REG_INBAND_EN14C    0x1d35
+#define    RTL8367C_INBAND_EN14C_OFFSET    0
+#define    RTL8367C_INBAND_EN14C_MASK    0x1
+
+#define    RTL8367C_REG_CFG_SWR_L    0x1d36
+#define    RTL8367C_ANARG_RDY_SWR_L_OFFSET    14
+#define    RTL8367C_ANARG_RDY_SWR_L_MASK    0x4000
+#define    RTL8367C_ANARG_VALID_SWR_L_OFFSET    13
+#define    RTL8367C_ANARG_VALID_SWR_L_MASK    0x2000
+#define    RTL8367C_SAW_SWR_L_OFFSET    9
+#define    RTL8367C_SAW_SWR_L_MASK    0x1E00
+#define    RTL8367C_SAW_VALID_SWR_L_OFFSET    8
+#define    RTL8367C_SAW_VALID_SWR_L_MASK    0x100
+#define    RTL8367C_UPS_DBGO_L_OFFSET    0
+#define    RTL8367C_UPS_DBGO_L_MASK    0xFF
+
+#define    RTL8367C_REG_BTCAM_CTRL    0x1d37
+#define    RTL8367C_TCAM_RDS_OFFSET    2
+#define    RTL8367C_TCAM_RDS_MASK    0x1C
+#define    RTL8367C_TCAM_MDS_OFFSET    0
+#define    RTL8367C_TCAM_MDS_MASK    0x3
+
+#define    RTL8367C_REG_PBRAM_BISR_CTRL    0x1d38
+#define    RTL8367C_HAS_HLDRMP_MD_OFFSET    9
+#define    RTL8367C_HAS_HLDRMP_MD_MASK    0x200
+#define    RTL8367C_PB_HLDRMP_MD_OFFSET    8
+#define    RTL8367C_PB_HLDRMP_MD_MASK    0x100
+#define    RTL8367C_HAS_BISR_BIRSTN_OFFSET    7
+#define    RTL8367C_HAS_BISR_BIRSTN_MASK    0x80
+#define    RTL8367C_SEC_RUN_HSA_OFFSET    6
+#define    RTL8367C_SEC_RUN_HSA_MASK    0x40
+#define    RTL8367C_HAS_HLDRMP_VAL_OFFSET    5
+#define    RTL8367C_HAS_HLDRMP_VAL_MASK    0x20
+#define    RTL8367C_HAS_BISR_PWRSTN_OFFSET    4
+#define    RTL8367C_HAS_BISR_PWRSTN_MASK    0x10
+#define    RTL8367C_SEC_RUN_PB_OFFSET    3
+#define    RTL8367C_SEC_RUN_PB_MASK    0x8
+#define    RTL8367C_PB_HLDRMP_VAL_OFFSET    2
+#define    RTL8367C_PB_HLDRMP_VAL_MASK    0x4
+#define    RTL8367C_PB_BISR_BIRSTN_OFFSET    1
+#define    RTL8367C_PB_BISR_BIRSTN_MASK    0x2
+#define    RTL8367C_PB_BISR_PWRSTN_OFFSET    0
+#define    RTL8367C_PB_BISR_PWRSTN_MASK    0x1
+
+#define    RTL8367C_REG_CVLANRAM_BISR_CTRL    0x1d39
+#define    RTL8367C_SEC_RUN_CVLAN_OFFSET    4
+#define    RTL8367C_SEC_RUN_CVLAN_MASK    0x10
+#define    RTL8367C_CVALN_HLDRMP_MD_OFFSET    3
+#define    RTL8367C_CVALN_HLDRMP_MD_MASK    0x8
+#define    RTL8367C_CVALN_HLDRMP_VAL_OFFSET    2
+#define    RTL8367C_CVALN_HLDRMP_VAL_MASK    0x4
+#define    RTL8367C_CVLAN_BISR_BIRSTN_OFFSET    1
+#define    RTL8367C_CVLAN_BISR_BIRSTN_MASK    0x2
+#define    RTL8367C_CVLAN_BISR_PWRSTN_OFFSET    0
+#define    RTL8367C_CVLAN_BISR_PWRSTN_MASK    0x1
+
+#define    RTL8367C_REG_CFG_1588_TIMER_EN_GPI    0x1d3a
+#define    RTL8367C_CFG_1588_TIMER_EN_GPI_OFFSET    0
+#define    RTL8367C_CFG_1588_TIMER_EN_GPI_MASK    0x1
+
+#define    RTL8367C_REG_MDIO_PRMB_SUPP    0x1d3b
+#define    RTL8367C_FIB_HIPRI_OFFSET    14
+#define    RTL8367C_FIB_HIPRI_MASK    0x4000
+#define    RTL8367C_SMT_EN_OFFSET    13
+#define    RTL8367C_SMT_EN_MASK    0x2000
+#define    RTL8367C_P4_FB_CPL_OFFSET    12
+#define    RTL8367C_P4_FB_CPL_MASK    0x1000
+#define    RTL8367C_P3_FB_CPL_OFFSET    11
+#define    RTL8367C_P3_FB_CPL_MASK    0x800
+#define    RTL8367C_P2_FB_CPL_OFFSET    10
+#define    RTL8367C_P2_FB_CPL_MASK    0x400
+#define    RTL8367C_P1_FB_CPL_OFFSET    9
+#define    RTL8367C_P1_FB_CPL_MASK    0x200
+#define    RTL8367C_P0_FB_CPL_OFFSET    8
+#define    RTL8367C_P0_FB_CPL_MASK    0x100
+#define    RTL8367C_DBG_PKG_8367N_OFFSET    7
+#define    RTL8367C_DBG_PKG_8367N_MASK    0x80
+#define    RTL8367C_DBG_PKG_8367VB_OFFSET    6
+#define    RTL8367C_DBG_PKG_8367VB_MASK    0x40
+#define    RTL8367C_CFG_DEBUG_EN_OFFSET    5
+#define    RTL8367C_CFG_DEBUG_EN_MASK    0x20
+#define    RTL8367C_CFG_TMR_ACK_OFFSET    1
+#define    RTL8367C_CFG_TMR_ACK_MASK    0x1E
+#define    RTL8367C_CFG_PRMB_SUPP_OFFSET    0
+#define    RTL8367C_CFG_PRMB_SUPP_MASK    0x1
+
+#define    RTL8367C_REG_BOND4READ    0x1d3c
+#define    RTL8367C_BOND_BOID0_OFFSET    8
+#define    RTL8367C_BOND_BOID0_MASK    0x100
+#define    RTL8367C_BOND_SYSCLK_OFFSET    7
+#define    RTL8367C_BOND_SYSCLK_MASK    0x80
+#define    RTL8367C_BOND_PHYMODE_OFFSET    6
+#define    RTL8367C_BOND_PHYMODE_MASK    0x40
+#define    RTL8367C_BOND_DIS_PON_BIST_OFFSET    5
+#define    RTL8367C_BOND_DIS_PON_BIST_MASK    0x20
+#define    RTL8367C_BOND_DIS_TABLE_INIT_OFFSET    4
+#define    RTL8367C_BOND_DIS_TABLE_INIT_MASK    0x10
+#define    RTL8367C_BOND_BYP_AFE_PLL_OFFSET    3
+#define    RTL8367C_BOND_BYP_AFE_PLL_MASK    0x8
+#define    RTL8367C_BOND_BYP_AFE_POR_OFFSET    2
+#define    RTL8367C_BOND_BYP_AFE_POR_MASK    0x4
+#define    RTL8367C_BOND_BISR_COND_OFFSET    1
+#define    RTL8367C_BOND_BISR_COND_MASK    0x2
+#define    RTL8367C_BOND_EF_EN_OFFSET    0
+#define    RTL8367C_BOND_EF_EN_MASK    0x1
+
+#define    RTL8367C_REG_REG_TO_ECO0    0x1d3d
+
+#define    RTL8367C_REG_REG_TO_ECO1    0x1d3e
+
+#define    RTL8367C_REG_REG_TO_ECO2    0x1d3f
+
+#define    RTL8367C_REG_REG_TO_ECO3    0x1d40
+
+#define    RTL8367C_REG_REG_TO_ECO4    0x1d41
+
+#define    RTL8367C_REG_PHYSTS_CTRL0    0x1d42
+#define    RTL8367C_MACRX_DUPDET_EN_OFFSET    5
+#define    RTL8367C_MACRX_DUPDET_EN_MASK    0x20
+#define    RTL8367C_LNKUP_DLY_EN_OFFSET    4
+#define    RTL8367C_LNKUP_DLY_EN_MASK    0x10
+#define    RTL8367C_GE_100M_LNKUP_DLY_OFFSET    2
+#define    RTL8367C_GE_100M_LNKUP_DLY_MASK    0xC
+#define    RTL8367C_PHYSTS_10M_LNKUP_DLY_OFFSET    0
+#define    RTL8367C_PHYSTS_10M_LNKUP_DLY_MASK    0x3
+
+#define    RTL8367C_REG_SSC_CTRL0_0    0x1d44
+#define    RTL8367C_SSC_CTRL0_0_SSC_TYPE_OFFSET    13
+#define    RTL8367C_SSC_CTRL0_0_SSC_TYPE_MASK    0x2000
+#define    RTL8367C_SSC_CTRL0_0_PHASE_LIM_SEL_OFFSET    5
+#define    RTL8367C_SSC_CTRL0_0_PHASE_LIM_SEL_MASK    0x1FE0
+#define    RTL8367C_SSC_CTRL0_0_PHASE_LIM_EN_OFFSET    4
+#define    RTL8367C_SSC_CTRL0_0_PHASE_LIM_EN_MASK    0x10
+#define    RTL8367C_SSC_CTRL0_0_DLL_MODE_OFFSET    2
+#define    RTL8367C_SSC_CTRL0_0_DLL_MODE_MASK    0xC
+#define    RTL8367C_SSC_CTRL0_0_SSC_EN_OFFSET    1
+#define    RTL8367C_SSC_CTRL0_0_SSC_EN_MASK    0x2
+#define    RTL8367C_SSC_CTRL0_0_SSC_MODE_OFFSET    0
+#define    RTL8367C_SSC_CTRL0_0_SSC_MODE_MASK    0x1
+
+#define    RTL8367C_REG_SSC_RDM_SEED    0x1d45
+
+#define    RTL8367C_REG_SSC_PN_POLY_SEL    0x1d46
+
+#define    RTL8367C_REG_SSC_CTRL0_3    0x1d47
+#define    RTL8367C_SSC_CTRL0_3_PHSFT_CNT_OFFSET    8
+#define    RTL8367C_SSC_CTRL0_3_PHSFT_CNT_MASK    0x7F00
+#define    RTL8367C_SSC_CTRL0_3_PHSFT_A_OFFSET    7
+#define    RTL8367C_SSC_CTRL0_3_PHSFT_A_MASK    0x80
+#define    RTL8367C_SSC_CTRL0_3_PHSFT_B_OFFSET    6
+#define    RTL8367C_SSC_CTRL0_3_PHSFT_B_MASK    0x40
+#define    RTL8367C_SSC_CTRL0_3_PHSFT_UPDN_OFFSET    5
+#define    RTL8367C_SSC_CTRL0_3_PHSFT_UPDN_MASK    0x20
+#define    RTL8367C_SSC_CTRL0_3_PHSFT_PRD_OFFSET    4
+#define    RTL8367C_SSC_CTRL0_3_PHSFT_PRD_MASK    0x10
+#define    RTL8367C_SSC_CTRL0_3_PN_POLY_DEG_OFFSET    0
+#define    RTL8367C_SSC_CTRL0_3_PN_POLY_DEG_MASK    0xF
+
+#define    RTL8367C_REG_SSC_CTRL0_4    0x1d48
+#define    RTL8367C_SSC_CTRL0_4_SSC_UP1DN0_OFFSET    15
+#define    RTL8367C_SSC_CTRL0_4_SSC_UP1DN0_MASK    0x8000
+#define    RTL8367C_SSC_CTRL0_4_SSC_PERIOD_OFFSET    8
+#define    RTL8367C_SSC_CTRL0_4_SSC_PERIOD_MASK    0x7F00
+#define    RTL8367C_SSC_CTRL0_4_SSC_OFFSET_OFFSET    0
+#define    RTL8367C_SSC_CTRL0_4_SSC_OFFSET_MASK    0xFF
+
+#define    RTL8367C_REG_SSC_CTRL0_5    0x1d49
+#define    RTL8367C_SSC_CTRL0_5_PH_OFS_TOG_OFFSET    15
+#define    RTL8367C_SSC_CTRL0_5_PH_OFS_TOG_MASK    0x8000
+#define    RTL8367C_SSC_CTRL0_5_PH_OFS_OFFSET    10
+#define    RTL8367C_SSC_CTRL0_5_PH_OFS_MASK    0x7C00
+#define    RTL8367C_SSC_CTRL0_5_SSC_STEP_OFFSET    4
+#define    RTL8367C_SSC_CTRL0_5_SSC_STEP_MASK    0x3F0
+#define    RTL8367C_SSC_CTRL0_5_SSC_TEST_MODE_OFFSET    2
+#define    RTL8367C_SSC_CTRL0_5_SSC_TEST_MODE_MASK    0xC
+#define    RTL8367C_SSC_CTRL0_5_SSC_PH_CFG_OFFSET    0
+#define    RTL8367C_SSC_CTRL0_5_SSC_PH_CFG_MASK    0x3
+
+#define    RTL8367C_REG_SSC_STS0    0x1d4a
+#define    RTL8367C_SSC_STS0_OFS_BUSY_OFFSET    13
+#define    RTL8367C_SSC_STS0_OFS_BUSY_MASK    0x2000
+#define    RTL8367C_SSC_STS0_OFS_TOTAL_R_OFFSET    8
+#define    RTL8367C_SSC_STS0_OFS_TOTAL_R_MASK    0x1F00
+#define    RTL8367C_SSC_STS0_CNT_GRY0_OFFSET    4
+#define    RTL8367C_SSC_STS0_CNT_GRY0_MASK    0xF0
+#define    RTL8367C_SSC_STS0_OFS_GRY0_OFFSET    0
+#define    RTL8367C_SSC_STS0_OFS_GRY0_MASK    0xF
+
+#define    RTL8367C_REG_SSC_CTRL1_0    0x1d4b
+#define    RTL8367C_SSC_CTRL1_0_SSC_TYPE_OFFSET    13
+#define    RTL8367C_SSC_CTRL1_0_SSC_TYPE_MASK    0x2000
+#define    RTL8367C_SSC_CTRL1_0_PHASE_LIM_SEL_OFFSET    5
+#define    RTL8367C_SSC_CTRL1_0_PHASE_LIM_SEL_MASK    0x1FE0
+#define    RTL8367C_SSC_CTRL1_0_PHASE_LIM_EN_OFFSET    4
+#define    RTL8367C_SSC_CTRL1_0_PHASE_LIM_EN_MASK    0x10
+#define    RTL8367C_SSC_CTRL1_0_DLL_MODE_OFFSET    2
+#define    RTL8367C_SSC_CTRL1_0_DLL_MODE_MASK    0xC
+#define    RTL8367C_SSC_CTRL1_0_SSC_EN_OFFSET    1
+#define    RTL8367C_SSC_CTRL1_0_SSC_EN_MASK    0x2
+#define    RTL8367C_SSC_CTRL1_0_SSC_MODE_OFFSET    0
+#define    RTL8367C_SSC_CTRL1_0_SSC_MODE_MASK    0x1
+
+#define    RTL8367C_REG_SSC_RDM_SEED1    0x1d4c
+
+#define    RTL8367C_REG_SSC_PN_POLY_SEL1    0x1d4d
+
+#define    RTL8367C_REG_SSC_CTRL1_3    0x1d4e
+#define    RTL8367C_SSC_CTRL1_3_PHSFT_CNT_OFFSET    8
+#define    RTL8367C_SSC_CTRL1_3_PHSFT_CNT_MASK    0x7F00
+#define    RTL8367C_SSC_CTRL1_3_PHSFT_A_OFFSET    7
+#define    RTL8367C_SSC_CTRL1_3_PHSFT_A_MASK    0x80
+#define    RTL8367C_SSC_CTRL1_3_PHSFT_B_OFFSET    6
+#define    RTL8367C_SSC_CTRL1_3_PHSFT_B_MASK    0x40
+#define    RTL8367C_SSC_CTRL1_3_PHSFT_UPDN_OFFSET    5
+#define    RTL8367C_SSC_CTRL1_3_PHSFT_UPDN_MASK    0x20
+#define    RTL8367C_SSC_CTRL1_3_PHSFT_PRD_OFFSET    4
+#define    RTL8367C_SSC_CTRL1_3_PHSFT_PRD_MASK    0x10
+#define    RTL8367C_SSC_CTRL1_3_PN_POLY_DEG_OFFSET    0
+#define    RTL8367C_SSC_CTRL1_3_PN_POLY_DEG_MASK    0xF
+
+#define    RTL8367C_REG_SSC_CTRL1_4    0x1d4f
+#define    RTL8367C_SSC_CTRL1_4_SSC_UP1DN0_OFFSET    15
+#define    RTL8367C_SSC_CTRL1_4_SSC_UP1DN0_MASK    0x8000
+#define    RTL8367C_SSC_CTRL1_4_SSC_PERIOD_OFFSET    8
+#define    RTL8367C_SSC_CTRL1_4_SSC_PERIOD_MASK    0x7F00
+#define    RTL8367C_SSC_CTRL1_4_SSC_OFFSET_OFFSET    0
+#define    RTL8367C_SSC_CTRL1_4_SSC_OFFSET_MASK    0xFF
+
+#define    RTL8367C_REG_SSC_CTRL1_5    0x1d50
+#define    RTL8367C_SSC_CTRL1_5_PH_OFS_TOG_OFFSET    15
+#define    RTL8367C_SSC_CTRL1_5_PH_OFS_TOG_MASK    0x8000
+#define    RTL8367C_SSC_CTRL1_5_PH_OFS_OFFSET    10
+#define    RTL8367C_SSC_CTRL1_5_PH_OFS_MASK    0x7C00
+#define    RTL8367C_SSC_CTRL1_5_SSC_STEP_OFFSET    4
+#define    RTL8367C_SSC_CTRL1_5_SSC_STEP_MASK    0x3F0
+#define    RTL8367C_SSC_CTRL1_5_SSC_TEST_MODE_OFFSET    2
+#define    RTL8367C_SSC_CTRL1_5_SSC_TEST_MODE_MASK    0xC
+#define    RTL8367C_SSC_CTRL1_5_SSC_PH_CFG_OFFSET    0
+#define    RTL8367C_SSC_CTRL1_5_SSC_PH_CFG_MASK    0x3
+
+#define    RTL8367C_REG_SSC_STS1    0x1d51
+#define    RTL8367C_SSC_STS1_OFS_BUSY_OFFSET    13
+#define    RTL8367C_SSC_STS1_OFS_BUSY_MASK    0x2000
+#define    RTL8367C_SSC_STS1_OFS_TOTAL_R_OFFSET    8
+#define    RTL8367C_SSC_STS1_OFS_TOTAL_R_MASK    0x1F00
+#define    RTL8367C_SSC_STS1_CNT_GRY0_OFFSET    4
+#define    RTL8367C_SSC_STS1_CNT_GRY0_MASK    0xF0
+#define    RTL8367C_SSC_STS1_OFS_GRY0_OFFSET    0
+#define    RTL8367C_SSC_STS1_OFS_GRY0_MASK    0xF
+
+#define    RTL8367C_REG_SSC_CTRL2_0    0x1d52
+#define    RTL8367C_SSC_CTRL2_0_SSC_TYPE_OFFSET    13
+#define    RTL8367C_SSC_CTRL2_0_SSC_TYPE_MASK    0x2000
+#define    RTL8367C_SSC_CTRL2_0_PHASE_LIM_SEL_OFFSET    5
+#define    RTL8367C_SSC_CTRL2_0_PHASE_LIM_SEL_MASK    0x1FE0
+#define    RTL8367C_SSC_CTRL2_0_PHASE_LIM_EN_OFFSET    4
+#define    RTL8367C_SSC_CTRL2_0_PHASE_LIM_EN_MASK    0x10
+#define    RTL8367C_SSC_CTRL2_0_DLL_MODE_OFFSET    2
+#define    RTL8367C_SSC_CTRL2_0_DLL_MODE_MASK    0xC
+#define    RTL8367C_SSC_CTRL2_0_SSC_EN_OFFSET    1
+#define    RTL8367C_SSC_CTRL2_0_SSC_EN_MASK    0x2
+#define    RTL8367C_SSC_CTRL2_0_SSC_MODE_OFFSET    0
+#define    RTL8367C_SSC_CTRL2_0_SSC_MODE_MASK    0x1
+
+#define    RTL8367C_REG_SSC_RDM_SEED2    0x1d53
+
+#define    RTL8367C_REG_SSC_PN_POLY_SEL2    0x1d54
+
+#define    RTL8367C_REG_SSC_CTRL2_3    0x1d55
+#define    RTL8367C_SSC_CTRL2_3_PHSFT_CNT_OFFSET    8
+#define    RTL8367C_SSC_CTRL2_3_PHSFT_CNT_MASK    0x7F00
+#define    RTL8367C_SSC_CTRL2_3_PHSFT_A_OFFSET    7
+#define    RTL8367C_SSC_CTRL2_3_PHSFT_A_MASK    0x80
+#define    RTL8367C_SSC_CTRL2_3_PHSFT_B_OFFSET    6
+#define    RTL8367C_SSC_CTRL2_3_PHSFT_B_MASK    0x40
+#define    RTL8367C_SSC_CTRL2_3_PHSFT_UPDN_OFFSET    5
+#define    RTL8367C_SSC_CTRL2_3_PHSFT_UPDN_MASK    0x20
+#define    RTL8367C_SSC_CTRL2_3_PHSFT_PRD_OFFSET    4
+#define    RTL8367C_SSC_CTRL2_3_PHSFT_PRD_MASK    0x10
+#define    RTL8367C_SSC_CTRL2_3_PN_POLY_DEG_OFFSET    0
+#define    RTL8367C_SSC_CTRL2_3_PN_POLY_DEG_MASK    0xF
+
+#define    RTL8367C_REG_SSC_CTRL2_4    0x1d56
+#define    RTL8367C_SSC_CTRL2_4_SSC_UP1DN0_OFFSET    15
+#define    RTL8367C_SSC_CTRL2_4_SSC_UP1DN0_MASK    0x8000
+#define    RTL8367C_SSC_CTRL2_4_SSC_PERIOD_OFFSET    8
+#define    RTL8367C_SSC_CTRL2_4_SSC_PERIOD_MASK    0x7F00
+#define    RTL8367C_SSC_CTRL2_4_SSC_OFFSET_OFFSET    0
+#define    RTL8367C_SSC_CTRL2_4_SSC_OFFSET_MASK    0xFF
+
+#define    RTL8367C_REG_SSC_CTRL2_5    0x1d57
+#define    RTL8367C_SSC_CTRL2_5_PH_OFS_TOG_OFFSET    15
+#define    RTL8367C_SSC_CTRL2_5_PH_OFS_TOG_MASK    0x8000
+#define    RTL8367C_SSC_CTRL2_5_PH_OFS_OFFSET    10
+#define    RTL8367C_SSC_CTRL2_5_PH_OFS_MASK    0x7C00
+#define    RTL8367C_SSC_CTRL2_5_SSC_STEP_OFFSET    4
+#define    RTL8367C_SSC_CTRL2_5_SSC_STEP_MASK    0x3F0
+#define    RTL8367C_SSC_CTRL2_5_SSC_TEST_MODE_OFFSET    2
+#define    RTL8367C_SSC_CTRL2_5_SSC_TEST_MODE_MASK    0xC
+#define    RTL8367C_SSC_CTRL2_5_SSC_PH_CFG_OFFSET    0
+#define    RTL8367C_SSC_CTRL2_5_SSC_PH_CFG_MASK    0x3
+
+#define    RTL8367C_REG_SSC_STS2    0x1d58
+#define    RTL8367C_SSC_STS2_OFS_BUSY_OFFSET    13
+#define    RTL8367C_SSC_STS2_OFS_BUSY_MASK    0x2000
+#define    RTL8367C_SSC_STS2_OFS_TOTAL_R_OFFSET    8
+#define    RTL8367C_SSC_STS2_OFS_TOTAL_R_MASK    0x1F00
+#define    RTL8367C_SSC_STS2_CNT_GRY0_OFFSET    4
+#define    RTL8367C_SSC_STS2_CNT_GRY0_MASK    0xF0
+#define    RTL8367C_SSC_STS2_OFS_GRY0_OFFSET    0
+#define    RTL8367C_SSC_STS2_OFS_GRY0_MASK    0xF
+
+#define    RTL8367C_REG_SSC_CTRL3_0    0x1d59
+#define    RTL8367C_SSC_CTRL3_0_SSC_TYPE_OFFSET    13
+#define    RTL8367C_SSC_CTRL3_0_SSC_TYPE_MASK    0x2000
+#define    RTL8367C_SSC_CTRL3_0_PHASE_LIM_SEL_OFFSET    5
+#define    RTL8367C_SSC_CTRL3_0_PHASE_LIM_SEL_MASK    0x1FE0
+#define    RTL8367C_SSC_CTRL3_0_PHASE_LIM_EN_OFFSET    4
+#define    RTL8367C_SSC_CTRL3_0_PHASE_LIM_EN_MASK    0x10
+#define    RTL8367C_SSC_CTRL3_0_DLL_MODE_OFFSET    2
+#define    RTL8367C_SSC_CTRL3_0_DLL_MODE_MASK    0xC
+#define    RTL8367C_SSC_CTRL3_0_SSC_EN_OFFSET    1
+#define    RTL8367C_SSC_CTRL3_0_SSC_EN_MASK    0x2
+#define    RTL8367C_SSC_CTRL3_0_SSC_MODE_OFFSET    0
+#define    RTL8367C_SSC_CTRL3_0_SSC_MODE_MASK    0x1
+
+#define    RTL8367C_REG_SSC_RDM_SEED3    0x1d5a
+
+#define    RTL8367C_REG_SSC_PN_POLY_SEL3    0x1d5b
+
+#define    RTL8367C_REG_SSC_CTRL3_3    0x1d5c
+#define    RTL8367C_SSC_CTRL3_3_PHSFT_CNT_OFFSET    8
+#define    RTL8367C_SSC_CTRL3_3_PHSFT_CNT_MASK    0x7F00
+#define    RTL8367C_SSC_CTRL3_3_PHSFT_A_OFFSET    7
+#define    RTL8367C_SSC_CTRL3_3_PHSFT_A_MASK    0x80
+#define    RTL8367C_SSC_CTRL3_3_PHSFT_B_OFFSET    6
+#define    RTL8367C_SSC_CTRL3_3_PHSFT_B_MASK    0x40
+#define    RTL8367C_SSC_CTRL3_3_PHSFT_UPDN_OFFSET    5
+#define    RTL8367C_SSC_CTRL3_3_PHSFT_UPDN_MASK    0x20
+#define    RTL8367C_SSC_CTRL3_3_PHSFT_PRD_OFFSET    4
+#define    RTL8367C_SSC_CTRL3_3_PHSFT_PRD_MASK    0x10
+#define    RTL8367C_SSC_CTRL3_3_PN_POLY_DEG_OFFSET    0
+#define    RTL8367C_SSC_CTRL3_3_PN_POLY_DEG_MASK    0xF
+
+#define    RTL8367C_REG_SSC_CTRL3_4    0x1d5d
+#define    RTL8367C_SSC_CTRL3_4_SSC_UP1DN0_OFFSET    15
+#define    RTL8367C_SSC_CTRL3_4_SSC_UP1DN0_MASK    0x8000
+#define    RTL8367C_SSC_CTRL3_4_SSC_PERIOD_OFFSET    8
+#define    RTL8367C_SSC_CTRL3_4_SSC_PERIOD_MASK    0x7F00
+#define    RTL8367C_SSC_CTRL3_4_SSC_OFFSET_OFFSET    0
+#define    RTL8367C_SSC_CTRL3_4_SSC_OFFSET_MASK    0xFF
+
+#define    RTL8367C_REG_SSC_CTRL3_5    0x1d5e
+#define    RTL8367C_SSC_CTRL3_5_PH_OFS_TOG_OFFSET    15
+#define    RTL8367C_SSC_CTRL3_5_PH_OFS_TOG_MASK    0x8000
+#define    RTL8367C_SSC_CTRL3_5_PH_OFS_OFFSET    10
+#define    RTL8367C_SSC_CTRL3_5_PH_OFS_MASK    0x7C00
+#define    RTL8367C_SSC_CTRL3_5_SSC_STEP_OFFSET    4
+#define    RTL8367C_SSC_CTRL3_5_SSC_STEP_MASK    0x3F0
+#define    RTL8367C_SSC_CTRL3_5_SSC_TEST_MODE_OFFSET    2
+#define    RTL8367C_SSC_CTRL3_5_SSC_TEST_MODE_MASK    0xC
+#define    RTL8367C_SSC_CTRL3_5_SSC_PH_CFG_OFFSET    0
+#define    RTL8367C_SSC_CTRL3_5_SSC_PH_CFG_MASK    0x3
+
+#define    RTL8367C_REG_SSC_STS3    0x1d5f
+#define    RTL8367C_SSC_STS3_OFS_BUSY_OFFSET    13
+#define    RTL8367C_SSC_STS3_OFS_BUSY_MASK    0x2000
+#define    RTL8367C_SSC_STS3_OFS_TOTAL_R_OFFSET    8
+#define    RTL8367C_SSC_STS3_OFS_TOTAL_R_MASK    0x1F00
+#define    RTL8367C_SSC_STS3_CNT_GRY0_OFFSET    4
+#define    RTL8367C_SSC_STS3_CNT_GRY0_MASK    0xF0
+#define    RTL8367C_SSC_STS3_OFS_GRY0_OFFSET    0
+#define    RTL8367C_SSC_STS3_OFS_GRY0_MASK    0xF
+
+#define    RTL8367C_REG_PHY_POLL_CFG13    0x1d60
+
+#define    RTL8367C_REG_PHY_POLL_CFG14    0x1d61
+
+#define    RTL8367C_REG_FRC_SYS_CLK    0x1d62
+#define    RTL8367C_SYSCLK_FRC_MD_OFFSET    1
+#define    RTL8367C_SYSCLK_FRC_MD_MASK    0x2
+#define    RTL8367C_SYSCLK_FRC_VAL_OFFSET    0
+#define    RTL8367C_SYSCLK_FRC_VAL_MASK    0x1
+
+#define    RTL8367C_REG_AFE_SSC_CTRL    0x1d63
+#define    RTL8367C_PH_RSTB_TXD1_OFFSET    9
+#define    RTL8367C_PH_RSTB_TXD1_MASK    0x200
+#define    RTL8367C_PH_RSTB_TXC1_OFFSET    8
+#define    RTL8367C_PH_RSTB_TXC1_MASK    0x100
+#define    RTL8367C_PH_RSTB_TXD0_OFFSET    7
+#define    RTL8367C_PH_RSTB_TXD0_MASK    0x80
+#define    RTL8367C_PH_RSTB_TXC0_OFFSET    6
+#define    RTL8367C_PH_RSTB_TXC0_MASK    0x40
+#define    RTL8367C_PH_RSTBSYS_OFFSET    5
+#define    RTL8367C_PH_RSTBSYS_MASK    0x20
+#define    RTL8367C_PH_RSTB8051_OFFSET    4
+#define    RTL8367C_PH_RSTB8051_MASK    0x10
+#define    RTL8367C_OREG_SSC_OFFSET    0
+#define    RTL8367C_OREG_SSC_MASK    0xF
+
+#define    RTL8367C_REG_BUFF_RST_CTRL0    0x1d64
+#define    RTL8367C_BUFFRST_TXESD_EN_OFFSET    13
+#define    RTL8367C_BUFFRST_TXESD_EN_MASK    0x2000
+#define    RTL8367C_BUFF_RST_TIME_LONG_OFFSET    8
+#define    RTL8367C_BUFF_RST_TIME_LONG_MASK    0x1F00
+#define    RTL8367C_BUFF_RST_TIME_SHORT_OFFSET    3
+#define    RTL8367C_BUFF_RST_TIME_SHORT_MASK    0xF8
+#define    RTL8367C_SW_BUFF_RST_OFFSET    2
+#define    RTL8367C_SW_BUFF_RST_MASK    0x4
+#define    RTL8367C_IMS_BUFF_RST_OFFSET    1
+#define    RTL8367C_IMS_BUFF_RST_MASK    0x2
+#define    RTL8367C_IMR_BUFF_RST_OFFSET    0
+#define    RTL8367C_IMR_BUFF_RST_MASK    0x1
+
+#define    RTL8367C_REG_BUFF_RST_CTRL1    0x1d65
+#define    RTL8367C_BUFFRST_SYSOVER_EN_OFFSET    10
+#define    RTL8367C_BUFFRST_SYSOVER_EN_MASK    0x400
+#define    RTL8367C_BUFFRST_SYSOVER_THR_OFFSET    0
+#define    RTL8367C_BUFFRST_SYSOVER_THR_MASK    0x3FF
+
+#define    RTL8367C_REG_BUFF_RST_CTRL2    0x1d66
+#define    RTL8367C_BUFFRST_QOVER_EN_OFFSET    10
+#define    RTL8367C_BUFFRST_QOVER_EN_MASK    0x400
+#define    RTL8367C_BUFFRST_QOVER_THR_OFFSET    0
+#define    RTL8367C_BUFFRST_QOVER_THR_MASK    0x3FF
+
+#define    RTL8367C_REG_BUFF_RST_CTRL3    0x1d67
+#define    RTL8367C_DSC_TIMER_OFFSET    11
+#define    RTL8367C_DSC_TIMER_MASK    0x7800
+#define    RTL8367C_BUFFRST_DSCOVER_THR_OFFSET    1
+#define    RTL8367C_BUFFRST_DSCOVER_THR_MASK    0x7FE
+#define    RTL8367C_BUFFRST_DSCOVER_EN_OFFSET    0
+#define    RTL8367C_BUFFRST_DSCOVER_EN_MASK    0x1
+
+#define    RTL8367C_REG_BUFF_RST_CTRL4    0x1d68
+#define    RTL8367C_INDSC_TIMER_OFFSET    11
+#define    RTL8367C_INDSC_TIMER_MASK    0x7800
+#define    RTL8367C_BUFFRST_INDSCOVER_THR_OFFSET    1
+#define    RTL8367C_BUFFRST_INDSCOVER_THR_MASK    0x7FE
+#define    RTL8367C_BUFFRST_INDSCOVER_EN_OFFSET    0
+#define    RTL8367C_BUFFRST_INDSCOVER_EN_MASK    0x1
+
+#define    RTL8367C_REG_BUFF_RST_CTRL5    0x1d69
+#define    RTL8367C_TX_ESD_MODE_OFFSET    8
+#define    RTL8367C_TX_ESD_MODE_MASK    0x100
+#define    RTL8367C_TX_ESD_LVL_OFFSET    0
+#define    RTL8367C_TX_ESD_LVL_MASK    0xFF
+
+#define    RTL8367C_REG_TOP_CON0    0x1d70
+#define    RTL8367C_TOP_CON0_SDS_PWR_ISO_1_OFFSET    15
+#define    RTL8367C_TOP_CON0_SDS_PWR_ISO_1_MASK    0x8000
+#define    RTL8367C_OCP_TIMEOUT_P7_5_OFFSET    12
+#define    RTL8367C_OCP_TIMEOUT_P7_5_MASK    0x7000
+#define    RTL8367C_FIB_EEE_AB_OFFSET    11
+#define    RTL8367C_FIB_EEE_AB_MASK    0x800
+#define    RTL8367C_ADCCKIEN_OFFSET    10
+#define    RTL8367C_ADCCKIEN_MASK    0x400
+#define    RTL8367C_OCP_TIMEOUT_OFFSET    5
+#define    RTL8367C_OCP_TIMEOUT_MASK    0x3E0
+#define    RTL8367C_TOP_CON0_SDS_PWR_ISO_OFFSET    4
+#define    RTL8367C_TOP_CON0_SDS_PWR_ISO_MASK    0x10
+#define    RTL8367C_RG2_TXC_SEL_OFFSET    3
+#define    RTL8367C_RG2_TXC_SEL_MASK    0x8
+#define    RTL8367C_RG1TXC_SEL_OFFSET    2
+#define    RTL8367C_RG1TXC_SEL_MASK    0x4
+#define    RTL8367C_SYNC_1588_EN_OFFSET    1
+#define    RTL8367C_SYNC_1588_EN_MASK    0x2
+#define    RTL8367C_LS_MODE_OFFSET    0
+#define    RTL8367C_LS_MODE_MASK    0x1
+
+#define    RTL8367C_REG_TOP_CON1    0x1d71
+#define    RTL8367C_TA_CHK_EN_OFFSET    2
+#define    RTL8367C_TA_CHK_EN_MASK    0x4
+#define    RTL8367C_SLV_EG_SEL_OFFSET    1
+#define    RTL8367C_SLV_EG_SEL_MASK    0x2
+#define    RTL8367C_IIC_OP_DRAIN_OFFSET    0
+#define    RTL8367C_IIC_OP_DRAIN_MASK    0x1
+
+#define    RTL8367C_REG_SWR_FPWM    0x1d72
+#define    RTL8367C_SWR_FPWM_OFFSET    0
+#define    RTL8367C_SWR_FPWM_MASK    0x1
+
+#define    RTL8367C_REG_EEEP_CTRL_500M    0x1d73
+
+#define    RTL8367C_REG_SHORT_PRMB    0x1d74
+#define    RTL8367C_SHORT_PRMB_OFFSET    0
+#define    RTL8367C_SHORT_PRMB_MASK    0x1
+
+#define    RTL8367C_REG_INDSC_THR_CTRL    0x1d75
+#define    RTL8367C_INDSC_THR_CTRL_OFFSET    0
+#define    RTL8367C_INDSC_THR_CTRL_MASK    0x7FF
+
+#define    RTL8367C_REG_SET_PAD_CTRL_NEW    0x1d80
+#define    RTL8367C_SET_PAD_CTRL_NEW_OFFSET    0
+#define    RTL8367C_SET_PAD_CTRL_NEW_MASK    0x1
+
+#define    RTL8367C_REG_SET_PAD_DRI_0    0x1d81
+
+#define    RTL8367C_REG_SET_PAD_DRI_1    0x1d82
+
+#define    RTL8367C_REG_SET_PAD_DRI_2    0x1d83
+
+#define    RTL8367C_REG_SET_PAD_SLEW_0    0x1d84
+
+#define    RTL8367C_REG_SET_PAD_SLEW_1    0x1d85
+
+#define    RTL8367C_REG_SET_PAD_SLEW_2    0x1d86
+
+#define    RTL8367C_REG_SET_PAD_SMT_0    0x1d87
+
+#define    RTL8367C_REG_SET_PAD_SMT_1    0x1d88
+
+#define    RTL8367C_REG_SET_PAD_SMT_2    0x1d89
+
+#define    RTL8367C_REG_M_I2C_CTL_STA_REG    0x1d8a
+#define    RTL8367C_TX_RX_DATA_OFFSET    8
+#define    RTL8367C_TX_RX_DATA_MASK    0xFF00
+#define    RTL8367C_DUMB_RW_ERR_OFFSET    7
+#define    RTL8367C_DUMB_RW_ERR_MASK    0x80
+#define    RTL8367C_SLV_ACK_FLAG_OFFSET    6
+#define    RTL8367C_SLV_ACK_FLAG_MASK    0x40
+#define    RTL8367C_M_I2C_BUS_IDLE_OFFSET    5
+#define    RTL8367C_M_I2C_BUS_IDLE_MASK    0x20
+#define    RTL8367C_I2C_CMD_TYPE_OFFSET    1
+#define    RTL8367C_I2C_CMD_TYPE_MASK    0x1E
+#define    RTL8367C_I2C_CMD_EXEC_OFFSET    0
+#define    RTL8367C_I2C_CMD_EXEC_MASK    0x1
+
+#define    RTL8367C_REG_M_I2C_DUMB_RW_ADDR_0    0x1d8b
+
+#define    RTL8367C_REG_M_I2C_DUMB_RW_ADDR_1    0x1d8c
+
+#define    RTL8367C_REG_M_I2C_DUMB_RW_DATA_0    0x1d8d
+
+#define    RTL8367C_REG_M_I2C_DUMB_RW_DATA_1    0x1d8e
+
+#define    RTL8367C_REG_M_I2C_DUMB_RW_CTL    0x1d8f
+#define    RTL8367C_DUMB_I2C_CTL_CODE_OFFSET    8
+#define    RTL8367C_DUMB_I2C_CTL_CODE_MASK    0x7F00
+#define    RTL8367C_DUMB_RW_I2C_FORMAT_OFFSET    4
+#define    RTL8367C_DUMB_RW_I2C_FORMAT_MASK    0x10
+#define    RTL8367C_DUMB_RW_DATA_MODE_OFFSET    2
+#define    RTL8367C_DUMB_RW_DATA_MODE_MASK    0xC
+#define    RTL8367C_DUMB_RW_ADDR_MODE_OFFSET    0
+#define    RTL8367C_DUMB_RW_ADDR_MODE_MASK    0x3
+
+#define    RTL8367C_REG_M_I2C_SYS_CTL    0x1d90
+#define    RTL8367C_M_I2C_SCL_IO_MUX_OFFSET    12
+#define    RTL8367C_M_I2C_SCL_IO_MUX_MASK    0x3000
+#define    RTL8367C_M_I2C_SDA_IO_MUX_OFFSET    10
+#define    RTL8367C_M_I2C_SDA_IO_MUX_MASK    0xC00
+#define    RTL8367C_M_I2C_SDA_OD_EN_OFFSET    9
+#define    RTL8367C_M_I2C_SDA_OD_EN_MASK    0x200
+#define    RTL8367C_M_I2C_SCL_OD_EN_OFFSET    8
+#define    RTL8367C_M_I2C_SCL_OD_EN_MASK    0x100
+#define    RTL8367C_M_I2C_SCL_F_DIV_OFFSET    0
+#define    RTL8367C_M_I2C_SCL_F_DIV_MASK    0xFF
+
+#define    RTL8367C_REG_HT_PB_SRAM_CTRL    0x1da0
+#define    RTL8367C_HTPB_RW_OFFSET    2
+#define    RTL8367C_HTPB_RW_MASK    0x4
+#define    RTL8367C_HTPB_SEL_OFFSET    1
+#define    RTL8367C_HTPB_SEL_MASK    0x2
+#define    RTL8367C_HTPB_CE_OFFSET    0
+#define    RTL8367C_HTPB_CE_MASK    0x1
+
+#define    RTL8367C_REG_HT_PB_SRAM_ADDR    0x1da1
+
+#define    RTL8367C_REG_HT_PB_SRAM_DIN0    0x1da2
+
+#define    RTL8367C_REG_HT_PB_SRAM_DIN1    0x1da3
+
+#define    RTL8367C_REG_HT_PB_SRAM_DOUT0    0x1da4
+
+#define    RTL8367C_REG_HT_PB_SRAM_DOUT1    0x1da5
+
+#define    RTL8367C_REG_PHY_STAT_0    0x1db0
+
+#define    RTL8367C_REG_PHY_STAT_1    0x1db1
+
+#define    RTL8367C_REG_PHY_STAT_2    0x1db2
+
+#define    RTL8367C_REG_PHY_STAT_3    0x1db3
+
+#define    RTL8367C_REG_PHY_STAT_4    0x1db4
+
+#define    RTL8367C_REG_PHY_STAT_5    0x1db5
+
+#define    RTL8367C_REG_PHY_STAT_6    0x1db6
+
+#define    RTL8367C_REG_PHY_STAT_7    0x1db7
+
+#define    RTL8367C_REG_SDS_STAT_0    0x1db8
+
+#define    RTL8367C_REG_SDS_STAT_1    0x1db9
+
+#define    RTL8367C_REG_MAC_LINK_STAT_0    0x1dba
+#define    RTL8367C_MAC_LINK_STAT_CUR_0_OFFSET    8
+#define    RTL8367C_MAC_LINK_STAT_CUR_0_MASK    0xFF00
+#define    RTL8367C_MAC_LINK_STAT_LATCH_0_OFFSET    0
+#define    RTL8367C_MAC_LINK_STAT_LATCH_0_MASK    0xFF
+
+#define    RTL8367C_REG_MAC_LINK_STAT_1    0x1dbb
+#define    RTL8367C_MAC_LINK_STAT_1_Reserved_OFFSET    6
+#define    RTL8367C_MAC_LINK_STAT_1_Reserved_MASK    0xFFC0
+#define    RTL8367C_MAC_LINK_STAT_CUR_1_OFFSET    3
+#define    RTL8367C_MAC_LINK_STAT_CUR_1_MASK    0x38
+#define    RTL8367C_MAC_LINK_STAT_LATCH_1_OFFSET    0
+#define    RTL8367C_MAC_LINK_STAT_LATCH_1_MASK    0x7
+
+#define    RTL8367C_REG_MISC_CONTROL_1    0x1dc0
+#define    RTL8367C_P7_FB_CPL_OFFSET    2
+#define    RTL8367C_P7_FB_CPL_MASK    0x4
+#define    RTL8367C_P6_FB_CPL_OFFSET    1
+#define    RTL8367C_P6_FB_CPL_MASK    0x2
+#define    RTL8367C_P5_FB_CPL_OFFSET    0
+#define    RTL8367C_P5_FB_CPL_MASK    0x1
+
+#define    RTL8367C_REG_SDS_MISC_1    0x1dc1
+#define    RTL8367C_CFG_SGMII_RXFC_1_OFFSET    14
+#define    RTL8367C_CFG_SGMII_RXFC_1_MASK    0x4000
+#define    RTL8367C_CFG_SGMII_TXFC_1_OFFSET    13
+#define    RTL8367C_CFG_SGMII_TXFC_1_MASK    0x2000
+#define    RTL8367C_CFG_MAC9_SEL_HSGMII_OFFSET    11
+#define    RTL8367C_CFG_MAC9_SEL_HSGMII_MASK    0x800
+#define    RTL8367C_CFG_SGMII_FDUP_1_OFFSET    10
+#define    RTL8367C_CFG_SGMII_FDUP_1_MASK    0x400
+#define    RTL8367C_CFG_SGMII_LINK_1_OFFSET    9
+#define    RTL8367C_CFG_SGMII_LINK_1_MASK    0x200
+#define    RTL8367C_CFG_SGMII_SPD_1_OFFSET    7
+#define    RTL8367C_CFG_SGMII_SPD_1_MASK    0x180
+#define    RTL8367C_CFG_MAC9_SEL_SGMII_OFFSET    6
+#define    RTL8367C_CFG_MAC9_SEL_SGMII_MASK    0x40
+#define    RTL8367C_CFG_SDS_MODE_14C_1_OFFSET    0
+#define    RTL8367C_CFG_SDS_MODE_14C_1_MASK    0x7
+
+#define    RTL8367C_REG_FIBER_CFG_2_1    0x1dc2
+#define    RTL8367C_SDS_RX_DISABLE_1_OFFSET    6
+#define    RTL8367C_SDS_RX_DISABLE_1_MASK    0xC0
+#define    RTL8367C_SDS_TX_DISABLE_1_OFFSET    4
+#define    RTL8367C_SDS_TX_DISABLE_1_MASK    0x30
+#define    RTL8367C_FIBER_CFG_2_1_SDS_PWR_ISO_1_OFFSET    2
+#define    RTL8367C_FIBER_CFG_2_1_SDS_PWR_ISO_1_MASK    0xC
+#define    RTL8367C_SDS_FRC_LD_1_OFFSET    0
+#define    RTL8367C_SDS_FRC_LD_1_MASK    0x3
+
+#define    RTL8367C_REG_FIBER_CFG_1_1    0x1dc3
+#define    RTL8367C_SDS_FRC_REG4_1_OFFSET    12
+#define    RTL8367C_SDS_FRC_REG4_1_MASK    0x1000
+#define    RTL8367C_SDS_FRC_REG4_FIB100_1_OFFSET    11
+#define    RTL8367C_SDS_FRC_REG4_FIB100_1_MASK    0x800
+#define    RTL8367C_SDS_FRC_MODE_1_OFFSET    3
+#define    RTL8367C_SDS_FRC_MODE_1_MASK    0x8
+#define    RTL8367C_SDS_MODE_1_OFFSET    0
+#define    RTL8367C_SDS_MODE_1_MASK    0x7
+
+#define    RTL8367C_REG_PHYSTS_CTRL0_1    0x1dc4
+#define    RTL8367C_LNKUP_DLY_EN_EXT2_OFFSET    9
+#define    RTL8367C_LNKUP_DLY_EN_EXT2_MASK    0x200
+#define    RTL8367C_GE_100M_LNKUP_DLY_EXT2_OFFSET    7
+#define    RTL8367C_GE_100M_LNKUP_DLY_EXT2_MASK    0x180
+#define    RTL8367C_PHYSTS_10M_LNKUP_DLY_EXT2_OFFSET    5
+#define    RTL8367C_PHYSTS_10M_LNKUP_DLY_EXT2_MASK    0x60
+#define    RTL8367C_LNKUP_DLY_EN_EXT1_OFFSET    4
+#define    RTL8367C_LNKUP_DLY_EN_EXT1_MASK    0x10
+#define    RTL8367C_GE_100M_LNKUP_DLY_EXT1_OFFSET    2
+#define    RTL8367C_GE_100M_LNKUP_DLY_EXT1_MASK    0xC
+#define    RTL8367C_PHYSTS_10M_LNKUP_DLY_EXT1_OFFSET    0
+#define    RTL8367C_PHYSTS_10M_LNKUP_DLY_EXT1_MASK    0x3
+
+#define    RTL8367C_REG_FIBER_CFG_3_1    0x1dc5
+#define    RTL8367C_FIBER_CFG_3_1_OFFSET    0
+#define    RTL8367C_FIBER_CFG_3_1_MASK    0xFFF
+
+#define    RTL8367C_REG_FIBER_CFG_4_1    0x1dc6
+
+#define    RTL8367C_REG_BUFF_RST_CTRL2_2    0x1dc7
+#define    RTL8367C_Cfg_buffrst_sysover_thr_1_OFFSET    3
+#define    RTL8367C_Cfg_buffrst_sysover_thr_1_MASK    0x8
+#define    RTL8367C_Cfg_buffrst_qover_thr_OFFSET    2
+#define    RTL8367C_Cfg_buffrst_qover_thr_MASK    0x4
+#define    RTL8367C_Cfg_buffrst_indscover_thr_1_OFFSET    1
+#define    RTL8367C_Cfg_buffrst_indscover_thr_1_MASK    0x2
+#define    RTL8367C_Cfg_buffrst_dscover_thr_1_OFFSET    0
+#define    RTL8367C_Cfg_buffrst_dscover_thr_1_MASK    0x1
+
+#define    RTL8367C_REG_PHY_DEBUG_CNT_CTRL    0x1dc8
+#define    RTL8367C_PHY_MIB_RST_7_OFFSET    15
+#define    RTL8367C_PHY_MIB_RST_7_MASK    0x8000
+#define    RTL8367C_PHY_MIB_RST_6_OFFSET    14
+#define    RTL8367C_PHY_MIB_RST_6_MASK    0x4000
+#define    RTL8367C_PHY_MIB_RST_5_OFFSET    13
+#define    RTL8367C_PHY_MIB_RST_5_MASK    0x2000
+#define    RTL8367C_PHY_MIB_RST_4_OFFSET    12
+#define    RTL8367C_PHY_MIB_RST_4_MASK    0x1000
+#define    RTL8367C_PHY_MIB_RST_3_OFFSET    11
+#define    RTL8367C_PHY_MIB_RST_3_MASK    0x800
+#define    RTL8367C_PHY_MIB_RST_2_OFFSET    10
+#define    RTL8367C_PHY_MIB_RST_2_MASK    0x400
+#define    RTL8367C_PHY_MIB_RST_1_OFFSET    9
+#define    RTL8367C_PHY_MIB_RST_1_MASK    0x200
+#define    RTL8367C_PHY_MIB_RST_0_OFFSET    8
+#define    RTL8367C_PHY_MIB_RST_0_MASK    0x100
+#define    RTL8367C_PHY_MIB_EN_7_OFFSET    7
+#define    RTL8367C_PHY_MIB_EN_7_MASK    0x80
+#define    RTL8367C_PHY_MIB_EN_6_OFFSET    6
+#define    RTL8367C_PHY_MIB_EN_6_MASK    0x40
+#define    RTL8367C_PHY_MIB_EN_5_OFFSET    5
+#define    RTL8367C_PHY_MIB_EN_5_MASK    0x20
+#define    RTL8367C_PHY_MIB_EN_4_OFFSET    4
+#define    RTL8367C_PHY_MIB_EN_4_MASK    0x10
+#define    RTL8367C_PHY_MIB_EN_3_OFFSET    3
+#define    RTL8367C_PHY_MIB_EN_3_MASK    0x8
+#define    RTL8367C_PHY_MIB_EN_2_OFFSET    2
+#define    RTL8367C_PHY_MIB_EN_2_MASK    0x4
+#define    RTL8367C_PHY_MIB_EN_1_OFFSET    1
+#define    RTL8367C_PHY_MIB_EN_1_MASK    0x2
+#define    RTL8367C_PHY_MIB_EN_0_OFFSET    0
+#define    RTL8367C_PHY_MIB_EN_0_MASK    0x1
+
+#define    RTL8367C_REG_TXPKT_CNT_L_0    0x1dc9
+
+#define    RTL8367C_REG_TXPKT_CNT_H_0    0x1dca
+
+#define    RTL8367C_REG_RXPKT_CNT_L_0    0x1dcb
+
+#define    RTL8367C_REG_RXPKT_CNT_H_0    0x1dcc
+
+#define    RTL8367C_REG_TX_CRC_0    0x1dcd
+
+#define    RTL8367C_REG_RX_CRC_0    0x1dce
+
+#define    RTL8367C_REG_TXPKT_CNT_L_1    0x1dcf
+
+#define    RTL8367C_REG_TXPKT_CNT_H_1    0x1dd0
+
+#define    RTL8367C_REG_RXPKT_CNT_L_1    0x1dd1
+
+#define    RTL8367C_REG_RXPKT_CNT_H_1    0x1dd2
+
+#define    RTL8367C_REG_TX_CRC_1    0x1dd3
+
+#define    RTL8367C_REG_RX_CRC_1    0x1dd4
+
+#define    RTL8367C_REG_TXPKT_CNT_L_2    0x1dd5
+
+#define    RTL8367C_REG_TXPKT_CNT_H_2    0x1dd6
+
+#define    RTL8367C_REG_RXPKT_CNT_L_2    0x1dd7
+
+#define    RTL8367C_REG_RXPKT_CNT_H_2    0x1dd8
+
+#define    RTL8367C_REG_TX_CRC_2    0x1dd9
+
+#define    RTL8367C_REG_RX_CRC_2    0x1dda
+
+#define    RTL8367C_REG_TXPKT_CNT_L_3    0x1ddb
+
+#define    RTL8367C_REG_TXPKT_CNT_H_3    0x1ddc
+
+#define    RTL8367C_REG_RXPKT_CNT_L_3    0x1ddd
+
+#define    RTL8367C_REG_RXPKT_CNT_H_3    0x1dde
+
+#define    RTL8367C_REG_TX_CRC_3    0x1ddf
+
+#define    RTL8367C_REG_RX_CRC_3    0x1de0
+
+#define    RTL8367C_REG_TXPKT_CNT_L_4    0x1de1
+
+#define    RTL8367C_REG_TXPKT_CNT_H_4    0x1de2
+
+#define    RTL8367C_REG_RXPKT_CNT_L_4    0x1de3
+
+#define    RTL8367C_REG_RXPKT_CNT_H_4    0x1de4
+
+#define    RTL8367C_REG_TX_CRC_4    0x1de5
+
+#define    RTL8367C_REG_RX_CRC_4    0x1de6
+
+#define    RTL8367C_REG_TXPKT_CNT_L_5    0x1de7
+
+#define    RTL8367C_REG_TXPKT_CNT_H_5    0x1de8
+
+#define    RTL8367C_REG_RXPKT_CNT_L_5    0x1de9
+
+#define    RTL8367C_REG_RXPKT_CNT_H_5    0x1dea
+
+#define    RTL8367C_REG_TX_CRC_5    0x1deb
+
+#define    RTL8367C_REG_RX_CRC_5    0x1dec
+
+#define    RTL8367C_REG_TXPKT_CNT_L_6    0x1ded
+
+#define    RTL8367C_REG_TXPKT_CNT_H_6    0x1dee
+
+#define    RTL8367C_REG_RXPKT_CNT_L_6    0x1def
+
+#define    RTL8367C_REG_RXPKT_CNT_H_6    0x1df0
+
+#define    RTL8367C_REG_TX_CRC_6    0x1df1
+
+#define    RTL8367C_REG_RX_CRC_6    0x1df2
+
+#define    RTL8367C_REG_TXPKT_CNT_L_7    0x1df3
+
+#define    RTL8367C_REG_TXPKT_CNT_H_7    0x1df4
+
+#define    RTL8367C_REG_RXPKT_CNT_L_7    0x1df5
+
+#define    RTL8367C_REG_RXPKT_CNT_H_7    0x1df6
+
+#define    RTL8367C_REG_TX_CRC_7    0x1df7
+
+#define    RTL8367C_REG_RX_CRC_7    0x1df8
+
+#define    RTL8367C_REG_BOND_DBG_0    0x1df9
+
+#define    RTL8367C_REG_BOND_DBG_1    0x1dfa
+
+#define    RTL8367C_REG_STRP_DBG_0    0x1dfb
+
+#define    RTL8367C_REG_STRP_DBG_1    0x1dfc
+
+#define    RTL8367C_REG_STRP_DBG_2    0x1dfd
+
+/* (16'h1f00)patch_reg */
+
+#define    RTL8367C_REG_INDRECT_ACCESS_CTRL    0x1f00
+#define    RTL8367C_RW_OFFSET    1
+#define    RTL8367C_RW_MASK    0x2
+#define    RTL8367C_CMD_OFFSET    0
+#define    RTL8367C_CMD_MASK    0x1
+
+#define    RTL8367C_REG_INDRECT_ACCESS_STATUS    0x1f01
+#define    RTL8367C_INDRECT_ACCESS_STATUS_OFFSET    2
+#define    RTL8367C_INDRECT_ACCESS_STATUS_MASK    0x7
+
+#define    RTL8367C_REG_INDRECT_ACCESS_ADDRESS    0x1f02
+
+#define    RTL8367C_REG_INDRECT_ACCESS_WRITE_DATA    0x1f03
+
+#define    RTL8367C_REG_INDRECT_ACCESS_READ_DATA    0x1f04
+
+/* (16'h6200)fib_page */
+
+#define    RTL8367C_REG_FIB0_CFG00    0x6200
+#define    RTL8367C_FIB0_CFG00_CFG_FIB_RST_OFFSET    15
+#define    RTL8367C_FIB0_CFG00_CFG_FIB_RST_MASK    0x8000
+#define    RTL8367C_FIB0_CFG00_CFG_FIB_LPK_OFFSET    14
+#define    RTL8367C_FIB0_CFG00_CFG_FIB_LPK_MASK    0x4000
+#define    RTL8367C_FIB0_CFG00_CFG_FIB_SPD_RD_0_OFFSET    13
+#define    RTL8367C_FIB0_CFG00_CFG_FIB_SPD_RD_0_MASK    0x2000
+#define    RTL8367C_FIB0_CFG00_CFG_FIB_ANEN_OFFSET    12
+#define    RTL8367C_FIB0_CFG00_CFG_FIB_ANEN_MASK    0x1000
+#define    RTL8367C_FIB0_CFG00_CFG_FIB_PDOWN_OFFSET    11
+#define    RTL8367C_FIB0_CFG00_CFG_FIB_PDOWN_MASK    0x800
+#define    RTL8367C_FIB0_CFG00_CFG_FIB_ISO_OFFSET    10
+#define    RTL8367C_FIB0_CFG00_CFG_FIB_ISO_MASK    0x400
+#define    RTL8367C_FIB0_CFG00_CFG_FIB_RESTART_OFFSET    9
+#define    RTL8367C_FIB0_CFG00_CFG_FIB_RESTART_MASK    0x200
+#define    RTL8367C_FIB0_CFG00_CFG_FIB_FULLDUP_OFFSET    8
+#define    RTL8367C_FIB0_CFG00_CFG_FIB_FULLDUP_MASK    0x100
+#define    RTL8367C_FIB0_CFG00_CFG_FIB_SPD_RD_1_OFFSET    6
+#define    RTL8367C_FIB0_CFG00_CFG_FIB_SPD_RD_1_MASK    0x40
+#define    RTL8367C_FIB0_CFG00_CFG_FIB_FRCTX_OFFSET    5
+#define    RTL8367C_FIB0_CFG00_CFG_FIB_FRCTX_MASK    0x20
+
+#define    RTL8367C_REG_FIB0_CFG01    0x6201
+#define    RTL8367C_FIB0_CFG01_CAPBILITY_OFFSET    6
+#define    RTL8367C_FIB0_CFG01_CAPBILITY_MASK    0xFFC0
+#define    RTL8367C_FIB0_CFG01_AN_COMPLETE_OFFSET    5
+#define    RTL8367C_FIB0_CFG01_AN_COMPLETE_MASK    0x20
+#define    RTL8367C_FIB0_CFG01_R_FAULT_OFFSET    4
+#define    RTL8367C_FIB0_CFG01_R_FAULT_MASK    0x10
+#define    RTL8367C_FIB0_CFG01_NWAY_ABILITY_OFFSET    3
+#define    RTL8367C_FIB0_CFG01_NWAY_ABILITY_MASK    0x8
+#define    RTL8367C_FIB0_CFG01_LINK_STATUS_OFFSET    2
+#define    RTL8367C_FIB0_CFG01_LINK_STATUS_MASK    0x4
+#define    RTL8367C_FIB0_CFG01_JABBER_DETECT_OFFSET    1
+#define    RTL8367C_FIB0_CFG01_JABBER_DETECT_MASK    0x2
+#define    RTL8367C_FIB0_CFG01_EXTENDED_CAPBILITY_OFFSET    0
+#define    RTL8367C_FIB0_CFG01_EXTENDED_CAPBILITY_MASK    0x1
+
+#define    RTL8367C_REG_FIB0_CFG02    0x6202
+
+#define    RTL8367C_REG_FIB0_CFG03    0x6203
+#define    RTL8367C_FIB0_CFG03_REALTEK_OUI5_0_OFFSET    10
+#define    RTL8367C_FIB0_CFG03_REALTEK_OUI5_0_MASK    0xFC00
+#define    RTL8367C_FIB0_CFG03_MODEL_NO_OFFSET    4
+#define    RTL8367C_FIB0_CFG03_MODEL_NO_MASK    0x3F0
+#define    RTL8367C_FIB0_CFG03_REVISION_NO_OFFSET    0
+#define    RTL8367C_FIB0_CFG03_REVISION_NO_MASK    0xF
+
+#define    RTL8367C_REG_FIB0_CFG04    0x6204
+
+#define    RTL8367C_REG_FIB0_CFG05    0x6205
+
+#define    RTL8367C_REG_FIB0_CFG06    0x6206
+#define    RTL8367C_FIB0_CFG06_FIB_NP_EN_OFFSET    2
+#define    RTL8367C_FIB0_CFG06_FIB_NP_EN_MASK    0x4
+#define    RTL8367C_FIB0_CFG06_RXPAGE_OFFSET    1
+#define    RTL8367C_FIB0_CFG06_RXPAGE_MASK    0x2
+
+#define    RTL8367C_REG_FIB0_CFG07    0x6207
+
+#define    RTL8367C_REG_FIB0_CFG08    0x6208
+
+#define    RTL8367C_REG_FIB0_CFG09    0x6209
+
+#define    RTL8367C_REG_FIB0_CFG10    0x620a
+
+#define    RTL8367C_REG_FIB0_CFG11    0x620b
+
+#define    RTL8367C_REG_FIB0_CFG12    0x620c
+
+#define    RTL8367C_REG_FIB0_CFG13    0x620d
+#define    RTL8367C_FIB0_CFG13_INDR_FUNC_OFFSET    14
+#define    RTL8367C_FIB0_CFG13_INDR_FUNC_MASK    0xC000
+#define    RTL8367C_FIB0_CFG13_DUMMY_OFFSET    5
+#define    RTL8367C_FIB0_CFG13_DUMMY_MASK    0x3FE0
+#define    RTL8367C_FIB0_CFG13_INDR_DEVAD_OFFSET    0
+#define    RTL8367C_FIB0_CFG13_INDR_DEVAD_MASK    0x1F
+
+#define    RTL8367C_REG_FIB0_CFG14    0x620e
+
+#define    RTL8367C_REG_FIB0_CFG15    0x620f
+
+#define    RTL8367C_REG_FIB1_CFG00    0x6210
+#define    RTL8367C_FIB1_CFG00_CFG_FIB_RST_OFFSET    15
+#define    RTL8367C_FIB1_CFG00_CFG_FIB_RST_MASK    0x8000
+#define    RTL8367C_FIB1_CFG00_CFG_FIB_LPK_OFFSET    14
+#define    RTL8367C_FIB1_CFG00_CFG_FIB_LPK_MASK    0x4000
+#define    RTL8367C_FIB1_CFG00_CFG_FIB_SPD_RD_0_OFFSET    13
+#define    RTL8367C_FIB1_CFG00_CFG_FIB_SPD_RD_0_MASK    0x2000
+#define    RTL8367C_FIB1_CFG00_CFG_FIB_ANEN_OFFSET    12
+#define    RTL8367C_FIB1_CFG00_CFG_FIB_ANEN_MASK    0x1000
+#define    RTL8367C_FIB1_CFG00_CFG_FIB_PDOWN_OFFSET    11
+#define    RTL8367C_FIB1_CFG00_CFG_FIB_PDOWN_MASK    0x800
+#define    RTL8367C_FIB1_CFG00_CFG_FIB_ISO_OFFSET    10
+#define    RTL8367C_FIB1_CFG00_CFG_FIB_ISO_MASK    0x400
+#define    RTL8367C_FIB1_CFG00_CFG_FIB_RESTART_OFFSET    9
+#define    RTL8367C_FIB1_CFG00_CFG_FIB_RESTART_MASK    0x200
+#define    RTL8367C_FIB1_CFG00_CFG_FIB_FULLDUP_OFFSET    8
+#define    RTL8367C_FIB1_CFG00_CFG_FIB_FULLDUP_MASK    0x100
+#define    RTL8367C_FIB1_CFG00_CFG_FIB_SPD_RD_1_OFFSET    6
+#define    RTL8367C_FIB1_CFG00_CFG_FIB_SPD_RD_1_MASK    0x40
+#define    RTL8367C_FIB1_CFG00_CFG_FIB_FRCTX_OFFSET    5
+#define    RTL8367C_FIB1_CFG00_CFG_FIB_FRCTX_MASK    0x20
+
+#define    RTL8367C_REG_FIB1_CFG01    0x6211
+#define    RTL8367C_FIB1_CFG01_CAPBILITY_OFFSET    6
+#define    RTL8367C_FIB1_CFG01_CAPBILITY_MASK    0xFFC0
+#define    RTL8367C_FIB1_CFG01_AN_COMPLETE_OFFSET    5
+#define    RTL8367C_FIB1_CFG01_AN_COMPLETE_MASK    0x20
+#define    RTL8367C_FIB1_CFG01_R_FAULT_OFFSET    4
+#define    RTL8367C_FIB1_CFG01_R_FAULT_MASK    0x10
+#define    RTL8367C_FIB1_CFG01_NWAY_ABILITY_OFFSET    3
+#define    RTL8367C_FIB1_CFG01_NWAY_ABILITY_MASK    0x8
+#define    RTL8367C_FIB1_CFG01_LINK_STATUS_OFFSET    2
+#define    RTL8367C_FIB1_CFG01_LINK_STATUS_MASK    0x4
+#define    RTL8367C_FIB1_CFG01_JABBER_DETECT_OFFSET    1
+#define    RTL8367C_FIB1_CFG01_JABBER_DETECT_MASK    0x2
+#define    RTL8367C_FIB1_CFG01_EXTENDED_CAPBILITY_OFFSET    0
+#define    RTL8367C_FIB1_CFG01_EXTENDED_CAPBILITY_MASK    0x1
+
+#define    RTL8367C_REG_FIB1_CFG02    0x6212
+
+#define    RTL8367C_REG_FIB1_CFG03    0x6213
+#define    RTL8367C_FIB1_CFG03_REALTEK_OUI5_0_OFFSET    10
+#define    RTL8367C_FIB1_CFG03_REALTEK_OUI5_0_MASK    0xFC00
+#define    RTL8367C_FIB1_CFG03_MODEL_NO_OFFSET    4
+#define    RTL8367C_FIB1_CFG03_MODEL_NO_MASK    0x3F0
+#define    RTL8367C_FIB1_CFG03_REVISION_NO_OFFSET    0
+#define    RTL8367C_FIB1_CFG03_REVISION_NO_MASK    0xF
+
+#define    RTL8367C_REG_FIB1_CFG04    0x6214
+
+#define    RTL8367C_REG_FIB1_CFG05    0x6215
+
+#define    RTL8367C_REG_FIB1_CFG06    0x6216
+#define    RTL8367C_FIB1_CFG06_FIB_NP_EN_OFFSET    2
+#define    RTL8367C_FIB1_CFG06_FIB_NP_EN_MASK    0x4
+#define    RTL8367C_FIB1_CFG06_RXPAGE_OFFSET    1
+#define    RTL8367C_FIB1_CFG06_RXPAGE_MASK    0x2
+
+#define    RTL8367C_REG_FIB1_CFG07    0x6217
+
+#define    RTL8367C_REG_FIB1_CFG08    0x6218
+
+#define    RTL8367C_REG_FIB1_CFG09    0x6219
+
+#define    RTL8367C_REG_FIB1_CFG10    0x621a
+
+#define    RTL8367C_REG_FIB1_CFG11    0x621b
+
+#define    RTL8367C_REG_FIB1_CFG12    0x621c
+
+#define    RTL8367C_REG_FIB1_CFG13    0x621d
+#define    RTL8367C_FIB1_CFG13_INDR_FUNC_OFFSET    14
+#define    RTL8367C_FIB1_CFG13_INDR_FUNC_MASK    0xC000
+#define    RTL8367C_FIB1_CFG13_DUMMY_OFFSET    5
+#define    RTL8367C_FIB1_CFG13_DUMMY_MASK    0x3FE0
+#define    RTL8367C_FIB1_CFG13_INDR_DEVAD_OFFSET    0
+#define    RTL8367C_FIB1_CFG13_INDR_DEVAD_MASK    0x1F
+
+#define    RTL8367C_REG_FIB1_CFG14    0x621e
+
+#define    RTL8367C_REG_FIB1_CFG15    0x621f
+
+/* (16'h6400)timer_1588 */
+
+#define    RTL8367C_REG_PTP_TIME_NSEC_L_NSEC    0x6400
+
+#define    RTL8367C_REG_PTP_TIME_NSEC_H_NSEC    0x6401
+#define    RTL8367C_PTP_TIME_NSEC_H_EXEC_OFFSET    15
+#define    RTL8367C_PTP_TIME_NSEC_H_EXEC_MASK    0x8000
+#define    RTL8367C_PTP_TIME_NSEC_H_CMD_OFFSET    12
+#define    RTL8367C_PTP_TIME_NSEC_H_CMD_MASK    0x3000
+#define    RTL8367C_PTP_TIME_NSEC_H_NSEC_OFFSET    0
+#define    RTL8367C_PTP_TIME_NSEC_H_NSEC_MASK    0x7FF
+
+#define    RTL8367C_REG_PTP_TIME_SEC_L_SEC    0x6402
+
+#define    RTL8367C_REG_PTP_TIME_SEC_H_SEC    0x6403
+
+#define    RTL8367C_REG_PTP_TIME_CFG    0x6404
+#define    RTL8367C_CFG_TIMER_EN_FRC_OFFSET    2
+#define    RTL8367C_CFG_TIMER_EN_FRC_MASK    0x4
+#define    RTL8367C_CFG_TIMER_1588_EN_OFFSET    1
+#define    RTL8367C_CFG_TIMER_1588_EN_MASK    0x2
+#define    RTL8367C_CFG_CLK_SRC_OFFSET    0
+#define    RTL8367C_CFG_CLK_SRC_MASK    0x1
+
+#define    RTL8367C_REG_OTAG_TPID    0x6405
+
+#define    RTL8367C_REG_ITAG_TPID    0x6406
+
+#define    RTL8367C_REG_MAC_ADDR_L    0x6407
+
+#define    RTL8367C_REG_MAC_ADDR_M    0x6408
+
+#define    RTL8367C_REG_MAC_ADDR_H    0x6409
+
+#define    RTL8367C_REG_PTP_TIME_NSEC_L_NSEC_RD    0x640a
+
+#define    RTL8367C_REG_PTP_TIME_NSEC_H_NSEC_RD    0x640b
+#define    RTL8367C_PTP_TIME_NSEC_H_NSEC_RD_OFFSET    0
+#define    RTL8367C_PTP_TIME_NSEC_H_NSEC_RD_MASK    0x7FF
+
+#define    RTL8367C_REG_PTP_TIME_SEC_L_SEC_RD    0x640c
+
+#define    RTL8367C_REG_PTP_TIME_SEC_H_SEC_RD    0x640d
+
+#define    RTL8367C_REG_PTP_TIME_CFG2    0x640e
+#define    RTL8367C_CFG_EN_OFFLOAD_OFFSET    9
+#define    RTL8367C_CFG_EN_OFFLOAD_MASK    0x200
+#define    RTL8367C_CFG_SAVE_OFF_TS_OFFSET    8
+#define    RTL8367C_CFG_SAVE_OFF_TS_MASK    0x100
+#define    RTL8367C_CFG_IMR_OFFSET    0
+#define    RTL8367C_CFG_IMR_MASK    0xFF
+
+#define    RTL8367C_REG_PTP_INTERRUPT_CFG    0x640f
+#define    RTL8367C_P9_INTERRUPT_OFFSET    9
+#define    RTL8367C_P9_INTERRUPT_MASK    0x200
+#define    RTL8367C_P8_INTERRUPT_OFFSET    8
+#define    RTL8367C_P8_INTERRUPT_MASK    0x100
+#define    RTL8367C_P7_INTERRUPT_OFFSET    7
+#define    RTL8367C_P7_INTERRUPT_MASK    0x80
+#define    RTL8367C_P6_INTERRUPT_OFFSET    6
+#define    RTL8367C_P6_INTERRUPT_MASK    0x40
+#define    RTL8367C_P5_INTERRUPT_OFFSET    5
+#define    RTL8367C_P5_INTERRUPT_MASK    0x20
+#define    RTL8367C_P4_INTERRUPT_OFFSET    4
+#define    RTL8367C_P4_INTERRUPT_MASK    0x10
+#define    RTL8367C_P3_INTERRUPT_OFFSET    3
+#define    RTL8367C_P3_INTERRUPT_MASK    0x8
+#define    RTL8367C_P2_INTERRUPT_OFFSET    2
+#define    RTL8367C_P2_INTERRUPT_MASK    0x4
+#define    RTL8367C_P1_INTERRUPT_OFFSET    1
+#define    RTL8367C_P1_INTERRUPT_MASK    0x2
+#define    RTL8367C_P0_INTERRUPT_OFFSET    0
+#define    RTL8367C_P0_INTERRUPT_MASK    0x1
+
+#define    RTL8367C_REG_P0_TX_SYNC_SEQ_ID    0x6410
+
+#define    RTL8367C_REG_P0_TX_DELAY_REQ_SEQ_ID    0x6411
+
+#define    RTL8367C_REG_P0_TX_PDELAY_REQ_SEQ_ID    0x6412
+
+#define    RTL8367C_REG_P0_TX_PDELAY_RESP_SEQ_ID    0x6413
+
+#define    RTL8367C_REG_P0_RX_SYNC_SEQ_ID    0x6414
+
+#define    RTL8367C_REG_P0_RX_DELAY_REQ_SEQ_ID    0x6415
+
+#define    RTL8367C_REG_P0_RX_PDELAY_REQ_SEQ_ID    0x6416
+
+#define    RTL8367C_REG_P0_RX_PDELAY_RESP_SEQ_ID    0x6417
+
+#define    RTL8367C_REG_P0_PORT_NSEC_15_0    0x6418
+
+#define    RTL8367C_REG_P0_PORT_NSEC_26_16    0x6419
+#define    RTL8367C_P0_PORT_NSEC_26_16_OFFSET    0
+#define    RTL8367C_P0_PORT_NSEC_26_16_MASK    0x7FF
+
+#define    RTL8367C_REG_P0_PORT_SEC_15_0    0x641a
+
+#define    RTL8367C_REG_P0_PORT_SEC_31_16    0x641b
+
+#define    RTL8367C_REG_P0_EAV_CFG    0x641c
+#define    RTL8367C_P0_EAV_CFG_PTP_PHY_EN_EN_OFFSET    8
+#define    RTL8367C_P0_EAV_CFG_PTP_PHY_EN_EN_MASK    0x100
+#define    RTL8367C_P0_EAV_CFG_RX_PDELAY_RESP_OFFSET    7
+#define    RTL8367C_P0_EAV_CFG_RX_PDELAY_RESP_MASK    0x80
+#define    RTL8367C_P0_EAV_CFG_RX_PDELAY_REQ_OFFSET    6
+#define    RTL8367C_P0_EAV_CFG_RX_PDELAY_REQ_MASK    0x40
+#define    RTL8367C_P0_EAV_CFG_RX_DELAY_REQ_OFFSET    5
+#define    RTL8367C_P0_EAV_CFG_RX_DELAY_REQ_MASK    0x20
+#define    RTL8367C_P0_EAV_CFG_RX_SYNC_OFFSET    4
+#define    RTL8367C_P0_EAV_CFG_RX_SYNC_MASK    0x10
+#define    RTL8367C_P0_EAV_CFG_TX_PDELAY_RESP_OFFSET    3
+#define    RTL8367C_P0_EAV_CFG_TX_PDELAY_RESP_MASK    0x8
+#define    RTL8367C_P0_EAV_CFG_TX_PDELAY_REQ_OFFSET    2
+#define    RTL8367C_P0_EAV_CFG_TX_PDELAY_REQ_MASK    0x4
+#define    RTL8367C_P0_EAV_CFG_TX_DELAY_REQ_OFFSET    1
+#define    RTL8367C_P0_EAV_CFG_TX_DELAY_REQ_MASK    0x2
+#define    RTL8367C_P0_EAV_CFG_TX_SYNC_OFFSET    0
+#define    RTL8367C_P0_EAV_CFG_TX_SYNC_MASK    0x1
+
+#define    RTL8367C_REG_P1_TX_SYNC_SEQ_ID    0x6420
+
+#define    RTL8367C_REG_P1_TX_DELAY_REQ_SEQ_ID    0x6421
+
+#define    RTL8367C_REG_P1_TX_PDELAY_REQ_SEQ_ID    0x6422
+
+#define    RTL8367C_REG_P1_TX_PDELAY_RESP_SEQ_ID    0x6423
+
+#define    RTL8367C_REG_P1_RX_SYNC_SEQ_ID    0x6424
+
+#define    RTL8367C_REG_P1_RX_DELAY_REQ_SEQ_ID    0x6425
+
+#define    RTL8367C_REG_P1_RX_PDELAY_REQ_SEQ_ID    0x6426
+
+#define    RTL8367C_REG_P1_RX_PDELAY_RESP_SEQ_ID    0x6427
+
+#define    RTL8367C_REG_P1_PORT_NSEC_15_0    0x6428
+
+#define    RTL8367C_REG_P1_PORT_NSEC_26_16    0x6429
+#define    RTL8367C_P1_PORT_NSEC_26_16_OFFSET    0
+#define    RTL8367C_P1_PORT_NSEC_26_16_MASK    0x7FF
+
+#define    RTL8367C_REG_P1_PORT_SEC_15_0    0x642a
+
+#define    RTL8367C_REG_P1_PORT_SEC_31_16    0x642b
+
+#define    RTL8367C_REG_P1_EAV_CFG    0x642c
+#define    RTL8367C_P1_EAV_CFG_PTP_PHY_EN_EN_OFFSET    8
+#define    RTL8367C_P1_EAV_CFG_PTP_PHY_EN_EN_MASK    0x100
+#define    RTL8367C_P1_EAV_CFG_RX_PDELAY_RESP_OFFSET    7
+#define    RTL8367C_P1_EAV_CFG_RX_PDELAY_RESP_MASK    0x80
+#define    RTL8367C_P1_EAV_CFG_RX_PDELAY_REQ_OFFSET    6
+#define    RTL8367C_P1_EAV_CFG_RX_PDELAY_REQ_MASK    0x40
+#define    RTL8367C_P1_EAV_CFG_RX_DELAY_REQ_OFFSET    5
+#define    RTL8367C_P1_EAV_CFG_RX_DELAY_REQ_MASK    0x20
+#define    RTL8367C_P1_EAV_CFG_RX_SYNC_OFFSET    4
+#define    RTL8367C_P1_EAV_CFG_RX_SYNC_MASK    0x10
+#define    RTL8367C_P1_EAV_CFG_TX_PDELAY_RESP_OFFSET    3
+#define    RTL8367C_P1_EAV_CFG_TX_PDELAY_RESP_MASK    0x8
+#define    RTL8367C_P1_EAV_CFG_TX_PDELAY_REQ_OFFSET    2
+#define    RTL8367C_P1_EAV_CFG_TX_PDELAY_REQ_MASK    0x4
+#define    RTL8367C_P1_EAV_CFG_TX_DELAY_REQ_OFFSET    1
+#define    RTL8367C_P1_EAV_CFG_TX_DELAY_REQ_MASK    0x2
+#define    RTL8367C_P1_EAV_CFG_TX_SYNC_OFFSET    0
+#define    RTL8367C_P1_EAV_CFG_TX_SYNC_MASK    0x1
+
+#define    RTL8367C_REG_P2_TX_SYNC_SEQ_ID    0x6430
+
+#define    RTL8367C_REG_P2_TX_DELAY_REQ_SEQ_ID    0x6431
+
+#define    RTL8367C_REG_P2_TX_PDELAY_REQ_SEQ_ID    0x6432
+
+#define    RTL8367C_REG_P2_TX_PDELAY_RESP_SEQ_ID    0x6433
+
+#define    RTL8367C_REG_P2_RX_SYNC_SEQ_ID    0x6434
+
+#define    RTL8367C_REG_P2_RX_DELAY_REQ_SEQ_ID    0x6435
+
+#define    RTL8367C_REG_P2_RX_PDELAY_REQ_SEQ_ID    0x6436
+
+#define    RTL8367C_REG_P2_RX_PDELAY_RESP_SEQ_ID    0x6437
+
+#define    RTL8367C_REG_P2_PORT_NSEC_15_0    0x6438
+
+#define    RTL8367C_REG_P2_PORT_NSEC_26_16    0x6439
+#define    RTL8367C_P2_PORT_NSEC_26_16_OFFSET    0
+#define    RTL8367C_P2_PORT_NSEC_26_16_MASK    0x7FF
+
+#define    RTL8367C_REG_P2_PORT_SEC_15_0    0x643a
+
+#define    RTL8367C_REG_P2_PORT_SEC_31_16    0x643b
+
+#define    RTL8367C_REG_P2_EAV_CFG    0x643c
+#define    RTL8367C_P2_EAV_CFG_PTP_PHY_EN_EN_OFFSET    8
+#define    RTL8367C_P2_EAV_CFG_PTP_PHY_EN_EN_MASK    0x100
+#define    RTL8367C_P2_EAV_CFG_RX_PDELAY_RESP_OFFSET    7
+#define    RTL8367C_P2_EAV_CFG_RX_PDELAY_RESP_MASK    0x80
+#define    RTL8367C_P2_EAV_CFG_RX_PDELAY_REQ_OFFSET    6
+#define    RTL8367C_P2_EAV_CFG_RX_PDELAY_REQ_MASK    0x40
+#define    RTL8367C_P2_EAV_CFG_RX_DELAY_REQ_OFFSET    5
+#define    RTL8367C_P2_EAV_CFG_RX_DELAY_REQ_MASK    0x20
+#define    RTL8367C_P2_EAV_CFG_RX_SYNC_OFFSET    4
+#define    RTL8367C_P2_EAV_CFG_RX_SYNC_MASK    0x10
+#define    RTL8367C_P2_EAV_CFG_TX_PDELAY_RESP_OFFSET    3
+#define    RTL8367C_P2_EAV_CFG_TX_PDELAY_RESP_MASK    0x8
+#define    RTL8367C_P2_EAV_CFG_TX_PDELAY_REQ_OFFSET    2
+#define    RTL8367C_P2_EAV_CFG_TX_PDELAY_REQ_MASK    0x4
+#define    RTL8367C_P2_EAV_CFG_TX_DELAY_REQ_OFFSET    1
+#define    RTL8367C_P2_EAV_CFG_TX_DELAY_REQ_MASK    0x2
+#define    RTL8367C_P2_EAV_CFG_TX_SYNC_OFFSET    0
+#define    RTL8367C_P2_EAV_CFG_TX_SYNC_MASK    0x1
+
+#define    RTL8367C_REG_P3_TX_SYNC_SEQ_ID    0x6440
+
+#define    RTL8367C_REG_P3_TX_DELAY_REQ_SEQ_ID    0x6441
+
+#define    RTL8367C_REG_P3_TX_PDELAY_REQ_SEQ_ID    0x6442
+
+#define    RTL8367C_REG_P3_TX_PDELAY_RESP_SEQ_ID    0x6443
+
+#define    RTL8367C_REG_P3_RX_SYNC_SEQ_ID    0x6444
+
+#define    RTL8367C_REG_P3_RX_DELAY_REQ_SEQ_ID    0x6445
+
+#define    RTL8367C_REG_P3_RX_PDELAY_REQ_SEQ_ID    0x6446
+
+#define    RTL8367C_REG_P3_RX_PDELAY_RESP_SEQ_ID    0x6447
+
+#define    RTL8367C_REG_P3_PORT_NSEC_15_0    0x6448
+
+#define    RTL8367C_REG_P3_PORT_NSEC_26_16    0x6449
+#define    RTL8367C_P3_PORT_NSEC_26_16_OFFSET    0
+#define    RTL8367C_P3_PORT_NSEC_26_16_MASK    0x7FF
+
+#define    RTL8367C_REG_P3_PORT_SEC_15_0    0x644a
+
+#define    RTL8367C_REG_P3_PORT_SEC_31_16    0x644b
+
+#define    RTL8367C_REG_P3_EAV_CFG    0x644c
+#define    RTL8367C_P3_EAV_CFG_PTP_PHY_EN_EN_OFFSET    8
+#define    RTL8367C_P3_EAV_CFG_PTP_PHY_EN_EN_MASK    0x100
+#define    RTL8367C_P3_EAV_CFG_RX_PDELAY_RESP_OFFSET    7
+#define    RTL8367C_P3_EAV_CFG_RX_PDELAY_RESP_MASK    0x80
+#define    RTL8367C_P3_EAV_CFG_RX_PDELAY_REQ_OFFSET    6
+#define    RTL8367C_P3_EAV_CFG_RX_PDELAY_REQ_MASK    0x40
+#define    RTL8367C_P3_EAV_CFG_RX_DELAY_REQ_OFFSET    5
+#define    RTL8367C_P3_EAV_CFG_RX_DELAY_REQ_MASK    0x20
+#define    RTL8367C_P3_EAV_CFG_RX_SYNC_OFFSET    4
+#define    RTL8367C_P3_EAV_CFG_RX_SYNC_MASK    0x10
+#define    RTL8367C_P3_EAV_CFG_TX_PDELAY_RESP_OFFSET    3
+#define    RTL8367C_P3_EAV_CFG_TX_PDELAY_RESP_MASK    0x8
+#define    RTL8367C_P3_EAV_CFG_TX_PDELAY_REQ_OFFSET    2
+#define    RTL8367C_P3_EAV_CFG_TX_PDELAY_REQ_MASK    0x4
+#define    RTL8367C_P3_EAV_CFG_TX_DELAY_REQ_OFFSET    1
+#define    RTL8367C_P3_EAV_CFG_TX_DELAY_REQ_MASK    0x2
+#define    RTL8367C_P3_EAV_CFG_TX_SYNC_OFFSET    0
+#define    RTL8367C_P3_EAV_CFG_TX_SYNC_MASK    0x1
+
+#define    RTL8367C_REG_P4_TX_SYNC_SEQ_ID    0x6450
+
+#define    RTL8367C_REG_P4_TX_DELAY_REQ_SEQ_ID    0x6451
+
+#define    RTL8367C_REG_P4_TX_PDELAY_REQ_SEQ_ID    0x6452
+
+#define    RTL8367C_REG_P4_TX_PDELAY_RESP_SEQ_ID    0x6453
+
+#define    RTL8367C_REG_P4_RX_SYNC_SEQ_ID    0x6454
+
+#define    RTL8367C_REG_P4_RX_DELAY_REQ_SEQ_ID    0x6455
+
+#define    RTL8367C_REG_P4_RX_PDELAY_REQ_SEQ_ID    0x6456
+
+#define    RTL8367C_REG_P4_RX_PDELAY_RESP_SEQ_ID    0x6457
+
+#define    RTL8367C_REG_P4_PORT_NSEC_15_0    0x6458
+
+#define    RTL8367C_REG_P4_PORT_NSEC_26_16    0x6459
+#define    RTL8367C_P4_PORT_NSEC_26_16_OFFSET    0
+#define    RTL8367C_P4_PORT_NSEC_26_16_MASK    0x7FF
+
+#define    RTL8367C_REG_P4_PORT_SEC_15_0    0x645a
+
+#define    RTL8367C_REG_P4_PORT_SEC_31_16    0x645b
+
+#define    RTL8367C_REG_P4_EAV_CFG    0x645c
+#define    RTL8367C_P4_EAV_CFG_PTP_PHY_EN_EN_OFFSET    8
+#define    RTL8367C_P4_EAV_CFG_PTP_PHY_EN_EN_MASK    0x100
+#define    RTL8367C_P4_EAV_CFG_RX_PDELAY_RESP_OFFSET    7
+#define    RTL8367C_P4_EAV_CFG_RX_PDELAY_RESP_MASK    0x80
+#define    RTL8367C_P4_EAV_CFG_RX_PDELAY_REQ_OFFSET    6
+#define    RTL8367C_P4_EAV_CFG_RX_PDELAY_REQ_MASK    0x40
+#define    RTL8367C_P4_EAV_CFG_RX_DELAY_REQ_OFFSET    5
+#define    RTL8367C_P4_EAV_CFG_RX_DELAY_REQ_MASK    0x20
+#define    RTL8367C_P4_EAV_CFG_RX_SYNC_OFFSET    4
+#define    RTL8367C_P4_EAV_CFG_RX_SYNC_MASK    0x10
+#define    RTL8367C_P4_EAV_CFG_TX_PDELAY_RESP_OFFSET    3
+#define    RTL8367C_P4_EAV_CFG_TX_PDELAY_RESP_MASK    0x8
+#define    RTL8367C_P4_EAV_CFG_TX_PDELAY_REQ_OFFSET    2
+#define    RTL8367C_P4_EAV_CFG_TX_PDELAY_REQ_MASK    0x4
+#define    RTL8367C_P4_EAV_CFG_TX_DELAY_REQ_OFFSET    1
+#define    RTL8367C_P4_EAV_CFG_TX_DELAY_REQ_MASK    0x2
+#define    RTL8367C_P4_EAV_CFG_TX_SYNC_OFFSET    0
+#define    RTL8367C_P4_EAV_CFG_TX_SYNC_MASK    0x1
+
+#define    RTL8367C_REG_P6_TX_SYNC_SEQ_ID    0x6460
+
+#define    RTL8367C_REG_P6_TX_DELAY_REQ_SEQ_ID    0x6461
+
+#define    RTL8367C_REG_P6_TX_PDELAY_REQ_SEQ_ID    0x6462
+
+#define    RTL8367C_REG_P6_TX_PDELAY_RESP_SEQ_ID    0x6463
+
+#define    RTL8367C_REG_P6_RX_SYNC_SEQ_ID    0x6464
+
+#define    RTL8367C_REG_P6_RX_DELAY_REQ_SEQ_ID    0x6465
+
+#define    RTL8367C_REG_P6_RX_PDELAY_REQ_SEQ_ID    0x6466
+
+#define    RTL8367C_REG_P6_RX_PDELAY_RESP_SEQ_ID    0x6467
+
+#define    RTL8367C_REG_P6_PORT_NSEC_15_0    0x6468
+
+#define    RTL8367C_REG_P6_PORT_NSEC_26_16    0x6469
+#define    RTL8367C_P6_PORT_NSEC_26_16_OFFSET    0
+#define    RTL8367C_P6_PORT_NSEC_26_16_MASK    0x7FF
+
+#define    RTL8367C_REG_P6_PORT_SEC_15_0    0x646a
+
+#define    RTL8367C_REG_P6_PORT_SEC_31_16    0x646b
+
+#define    RTL8367C_REG_P6_EAV_CFG    0x646c
+#define    RTL8367C_P6_EAV_CFG_PTP_PHY_EN_EN_OFFSET    8
+#define    RTL8367C_P6_EAV_CFG_PTP_PHY_EN_EN_MASK    0x100
+#define    RTL8367C_P6_EAV_CFG_RX_PDELAY_RESP_OFFSET    7
+#define    RTL8367C_P6_EAV_CFG_RX_PDELAY_RESP_MASK    0x80
+#define    RTL8367C_P6_EAV_CFG_RX_PDELAY_REQ_OFFSET    6
+#define    RTL8367C_P6_EAV_CFG_RX_PDELAY_REQ_MASK    0x40
+#define    RTL8367C_P6_EAV_CFG_RX_DELAY_REQ_OFFSET    5
+#define    RTL8367C_P6_EAV_CFG_RX_DELAY_REQ_MASK    0x20
+#define    RTL8367C_P6_EAV_CFG_RX_SYNC_OFFSET    4
+#define    RTL8367C_P6_EAV_CFG_RX_SYNC_MASK    0x10
+#define    RTL8367C_P6_EAV_CFG_TX_PDELAY_RESP_OFFSET    3
+#define    RTL8367C_P6_EAV_CFG_TX_PDELAY_RESP_MASK    0x8
+#define    RTL8367C_P6_EAV_CFG_TX_PDELAY_REQ_OFFSET    2
+#define    RTL8367C_P6_EAV_CFG_TX_PDELAY_REQ_MASK    0x4
+#define    RTL8367C_P6_EAV_CFG_TX_DELAY_REQ_OFFSET    1
+#define    RTL8367C_P6_EAV_CFG_TX_DELAY_REQ_MASK    0x2
+#define    RTL8367C_P6_EAV_CFG_TX_SYNC_OFFSET    0
+#define    RTL8367C_P6_EAV_CFG_TX_SYNC_MASK    0x1
+
+#define    RTL8367C_REG_P7_TX_SYNC_SEQ_ID    0x6470
+
+#define    RTL8367C_REG_P7_TX_DELAY_REQ_SEQ_ID    0x6471
+
+#define    RTL8367C_REG_P7_TX_PDELAY_REQ_SEQ_ID    0x6472
+
+#define    RTL8367C_REG_P7_TX_PDELAY_RESP_SEQ_ID    0x6473
+
+#define    RTL8367C_REG_P7_RX_SYNC_SEQ_ID    0x6474
+
+#define    RTL8367C_REG_P7_RX_DELAY_REQ_SEQ_ID    0x6475
+
+#define    RTL8367C_REG_P7_RX_PDELAY_REQ_SEQ_ID    0x6476
+
+#define    RTL8367C_REG_P7_RX_PDELAY_RESP_SEQ_ID    0x6477
+
+#define    RTL8367C_REG_P7_PORT_NSEC_15_0    0x6478
+
+#define    RTL8367C_REG_P7_PORT_NSEC_26_16    0x6479
+#define    RTL8367C_P7_PORT_NSEC_26_16_OFFSET    0
+#define    RTL8367C_P7_PORT_NSEC_26_16_MASK    0x7FF
+
+#define    RTL8367C_REG_P7_PORT_SEC_15_0    0x647a
+
+#define    RTL8367C_REG_P7_PORT_SEC_31_16    0x647b
+
+#define    RTL8367C_REG_P7_EAV_CFG    0x647c
+#define    RTL8367C_P7_EAV_CFG_PTP_PHY_EN_EN_OFFSET    8
+#define    RTL8367C_P7_EAV_CFG_PTP_PHY_EN_EN_MASK    0x100
+#define    RTL8367C_P7_EAV_CFG_RX_PDELAY_RESP_OFFSET    7
+#define    RTL8367C_P7_EAV_CFG_RX_PDELAY_RESP_MASK    0x80
+#define    RTL8367C_P7_EAV_CFG_RX_PDELAY_REQ_OFFSET    6
+#define    RTL8367C_P7_EAV_CFG_RX_PDELAY_REQ_MASK    0x40
+#define    RTL8367C_P7_EAV_CFG_RX_DELAY_REQ_OFFSET    5
+#define    RTL8367C_P7_EAV_CFG_RX_DELAY_REQ_MASK    0x20
+#define    RTL8367C_P7_EAV_CFG_RX_SYNC_OFFSET    4
+#define    RTL8367C_P7_EAV_CFG_RX_SYNC_MASK    0x10
+#define    RTL8367C_P7_EAV_CFG_TX_PDELAY_RESP_OFFSET    3
+#define    RTL8367C_P7_EAV_CFG_TX_PDELAY_RESP_MASK    0x8
+#define    RTL8367C_P7_EAV_CFG_TX_PDELAY_REQ_OFFSET    2
+#define    RTL8367C_P7_EAV_CFG_TX_PDELAY_REQ_MASK    0x4
+#define    RTL8367C_P7_EAV_CFG_TX_DELAY_REQ_OFFSET    1
+#define    RTL8367C_P7_EAV_CFG_TX_DELAY_REQ_MASK    0x2
+#define    RTL8367C_P7_EAV_CFG_TX_SYNC_OFFSET    0
+#define    RTL8367C_P7_EAV_CFG_TX_SYNC_MASK    0x1
+
+#define    RTL8367C_REG_P5_TX_SYNC_SEQ_ID    0x6480
+
+#define    RTL8367C_REG_P5_TX_DELAY_REQ_SEQ_ID    0x6481
+
+#define    RTL8367C_REG_P5_TX_PDELAY_REQ_SEQ_ID    0x6482
+
+#define    RTL8367C_REG_P5_TX_PDELAY_RESP_SEQ_ID    0x6483
+
+#define    RTL8367C_REG_P5_RX_SYNC_SEQ_ID    0x6484
+
+#define    RTL8367C_REG_P5_RX_DELAY_REQ_SEQ_ID    0x6485
+
+#define    RTL8367C_REG_P5_RX_PDELAY_REQ_SEQ_ID    0x6486
+
+#define    RTL8367C_REG_P5_RX_PDELAY_RESP_SEQ_ID    0x6487
+
+#define    RTL8367C_REG_P5_PORT_NSEC_15_0    0x6488
+
+#define    RTL8367C_REG_P5_PORT_NSEC_26_16    0x6489
+#define    RTL8367C_P5_PORT_NSEC_26_16_OFFSET    0
+#define    RTL8367C_P5_PORT_NSEC_26_16_MASK    0x7FF
+
+#define    RTL8367C_REG_P5_PORT_SEC_15_0    0x648a
+
+#define    RTL8367C_REG_P5_PORT_SEC_31_16    0x648b
+
+#define    RTL8367C_REG_P5_EAV_CFG    0x648c
+#define    RTL8367C_P5_EAV_CFG_PTP_PHY_EN_EN_OFFSET    8
+#define    RTL8367C_P5_EAV_CFG_PTP_PHY_EN_EN_MASK    0x100
+#define    RTL8367C_P5_EAV_CFG_RX_PDELAY_RESP_OFFSET    7
+#define    RTL8367C_P5_EAV_CFG_RX_PDELAY_RESP_MASK    0x80
+#define    RTL8367C_P5_EAV_CFG_RX_PDELAY_REQ_OFFSET    6
+#define    RTL8367C_P5_EAV_CFG_RX_PDELAY_REQ_MASK    0x40
+#define    RTL8367C_P5_EAV_CFG_RX_DELAY_REQ_OFFSET    5
+#define    RTL8367C_P5_EAV_CFG_RX_DELAY_REQ_MASK    0x20
+#define    RTL8367C_P5_EAV_CFG_RX_SYNC_OFFSET    4
+#define    RTL8367C_P5_EAV_CFG_RX_SYNC_MASK    0x10
+#define    RTL8367C_P5_EAV_CFG_TX_PDELAY_RESP_OFFSET    3
+#define    RTL8367C_P5_EAV_CFG_TX_PDELAY_RESP_MASK    0x8
+#define    RTL8367C_P5_EAV_CFG_TX_PDELAY_REQ_OFFSET    2
+#define    RTL8367C_P5_EAV_CFG_TX_PDELAY_REQ_MASK    0x4
+#define    RTL8367C_P5_EAV_CFG_TX_DELAY_REQ_OFFSET    1
+#define    RTL8367C_P5_EAV_CFG_TX_DELAY_REQ_MASK    0x2
+#define    RTL8367C_P5_EAV_CFG_TX_SYNC_OFFSET    0
+#define    RTL8367C_P5_EAV_CFG_TX_SYNC_MASK    0x1
+
+#define    RTL8367C_REG_P8_TX_SYNC_SEQ_ID    0x6490
+
+#define    RTL8367C_REG_P8_TX_DELAY_REQ_SEQ_ID    0x6491
+
+#define    RTL8367C_REG_P8_TX_PDELAY_REQ_SEQ_ID    0x6492
+
+#define    RTL8367C_REG_P8_TX_PDELAY_RESP_SEQ_ID    0x6493
+
+#define    RTL8367C_REG_P8_RX_SYNC_SEQ_ID    0x6494
+
+#define    RTL8367C_REG_P8_RX_DELAY_REQ_SEQ_ID    0x6495
+
+#define    RTL8367C_REG_P8_RX_PDELAY_REQ_SEQ_ID    0x6496
+
+#define    RTL8367C_REG_P8_RX_PDELAY_RESP_SEQ_ID    0x6497
+
+#define    RTL8367C_REG_P8_PORT_NSEC_15_0    0x6498
+
+#define    RTL8367C_REG_P8_PORT_NSEC_26_16    0x6499
+#define    RTL8367C_P8_PORT_NSEC_26_16_OFFSET    0
+#define    RTL8367C_P8_PORT_NSEC_26_16_MASK    0x7FF
+
+#define    RTL8367C_REG_P8_PORT_SEC_15_0    0x649a
+
+#define    RTL8367C_REG_P8_PORT_SEC_31_16    0x649b
+
+#define    RTL8367C_REG_P8_EAV_CFG    0x649c
+#define    RTL8367C_P8_EAV_CFG_PTP_PHY_EN_EN_OFFSET    8
+#define    RTL8367C_P8_EAV_CFG_PTP_PHY_EN_EN_MASK    0x100
+#define    RTL8367C_P8_EAV_CFG_RX_PDELAY_RESP_OFFSET    7
+#define    RTL8367C_P8_EAV_CFG_RX_PDELAY_RESP_MASK    0x80
+#define    RTL8367C_P8_EAV_CFG_RX_PDELAY_REQ_OFFSET    6
+#define    RTL8367C_P8_EAV_CFG_RX_PDELAY_REQ_MASK    0x40
+#define    RTL8367C_P8_EAV_CFG_RX_DELAY_REQ_OFFSET    5
+#define    RTL8367C_P8_EAV_CFG_RX_DELAY_REQ_MASK    0x20
+#define    RTL8367C_P8_EAV_CFG_RX_SYNC_OFFSET    4
+#define    RTL8367C_P8_EAV_CFG_RX_SYNC_MASK    0x10
+#define    RTL8367C_P8_EAV_CFG_TX_PDELAY_RESP_OFFSET    3
+#define    RTL8367C_P8_EAV_CFG_TX_PDELAY_RESP_MASK    0x8
+#define    RTL8367C_P8_EAV_CFG_TX_PDELAY_REQ_OFFSET    2
+#define    RTL8367C_P8_EAV_CFG_TX_PDELAY_REQ_MASK    0x4
+#define    RTL8367C_P8_EAV_CFG_TX_DELAY_REQ_OFFSET    1
+#define    RTL8367C_P8_EAV_CFG_TX_DELAY_REQ_MASK    0x2
+#define    RTL8367C_P8_EAV_CFG_TX_SYNC_OFFSET    0
+#define    RTL8367C_P8_EAV_CFG_TX_SYNC_MASK    0x1
+
+#define    RTL8367C_REG_P9_TX_SYNC_SEQ_ID    0x64a0
+
+#define    RTL8367C_REG_P9_TX_DELAY_REQ_SEQ_ID    0x64a1
+
+#define    RTL8367C_REG_P9_TX_PDELAY_REQ_SEQ_ID    0x64a2
+
+#define    RTL8367C_REG_P9_TX_PDELAY_RESP_SEQ_ID    0x64a3
+
+#define    RTL8367C_REG_P9_RX_SYNC_SEQ_ID    0x64a4
+
+#define    RTL8367C_REG_P9_RX_DELAY_REQ_SEQ_ID    0x64a5
+
+#define    RTL8367C_REG_P9_RX_PDELAY_REQ_SEQ_ID    0x64a6
+
+#define    RTL8367C_REG_P9_RX_PDELAY_RESP_SEQ_ID    0x64a7
+
+#define    RTL8367C_REG_P9_PORT_NSEC_15_0    0x64a8
+
+#define    RTL8367C_REG_P9_PORT_NSEC_26_16    0x64a9
+#define    RTL8367C_P9_PORT_NSEC_26_16_OFFSET    0
+#define    RTL8367C_P9_PORT_NSEC_26_16_MASK    0x7FF
+
+#define    RTL8367C_REG_P9_PORT_SEC_15_0    0x64aa
+
+#define    RTL8367C_REG_P9_PORT_SEC_31_16    0x64ab
+
+#define    RTL8367C_REG_P9_EAV_CFG    0x64ac
+#define    RTL8367C_P9_EAV_CFG_PTP_PHY_EN_EN_OFFSET    8
+#define    RTL8367C_P9_EAV_CFG_PTP_PHY_EN_EN_MASK    0x100
+#define    RTL8367C_P9_EAV_CFG_RX_PDELAY_RESP_OFFSET    7
+#define    RTL8367C_P9_EAV_CFG_RX_PDELAY_RESP_MASK    0x80
+#define    RTL8367C_P9_EAV_CFG_RX_PDELAY_REQ_OFFSET    6
+#define    RTL8367C_P9_EAV_CFG_RX_PDELAY_REQ_MASK    0x40
+#define    RTL8367C_P9_EAV_CFG_RX_DELAY_REQ_OFFSET    5
+#define    RTL8367C_P9_EAV_CFG_RX_DELAY_REQ_MASK    0x20
+#define    RTL8367C_P9_EAV_CFG_RX_SYNC_OFFSET    4
+#define    RTL8367C_P9_EAV_CFG_RX_SYNC_MASK    0x10
+#define    RTL8367C_P9_EAV_CFG_TX_PDELAY_RESP_OFFSET    3
+#define    RTL8367C_P9_EAV_CFG_TX_PDELAY_RESP_MASK    0x8
+#define    RTL8367C_P9_EAV_CFG_TX_PDELAY_REQ_OFFSET    2
+#define    RTL8367C_P9_EAV_CFG_TX_PDELAY_REQ_MASK    0x4
+#define    RTL8367C_P9_EAV_CFG_TX_DELAY_REQ_OFFSET    1
+#define    RTL8367C_P9_EAV_CFG_TX_DELAY_REQ_MASK    0x2
+#define    RTL8367C_P9_EAV_CFG_TX_SYNC_OFFSET    0
+#define    RTL8367C_P9_EAV_CFG_TX_SYNC_MASK    0x1
+
+/* (16'h6600)sds_indacs_reg */
+
+#define    RTL8367C_REG_SDS_INDACS_CMD    0x6600
+#define    RTL8367C_SDS_CMD_BUSY_OFFSET    8
+#define    RTL8367C_SDS_CMD_BUSY_MASK    0x100
+#define    RTL8367C_SDS_CMD_OFFSET    7
+#define    RTL8367C_SDS_CMD_MASK    0x80
+#define    RTL8367C_SDS_RWOP_OFFSET    6
+#define    RTL8367C_SDS_RWOP_MASK    0x40
+#define    RTL8367C_SDS_INDEX_OFFSET    0
+#define    RTL8367C_SDS_INDEX_MASK    0x3F
+
+#define    RTL8367C_REG_SDS_INDACS_ADR    0x6601
+#define    RTL8367C_SDS_PAGE_OFFSET    5
+#define    RTL8367C_SDS_PAGE_MASK    0x7E0
+#define    RTL8367C_SDS_REGAD_OFFSET    0
+#define    RTL8367C_SDS_REGAD_MASK    0x1F
+
+#define    RTL8367C_REG_SDS_INDACS_DATA    0x6602
+
+
+#endif /*#ifndef _RTL8367C_REG_H_*/
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/smi.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/smi.h
new file mode 100644
index 0000000..b77d760
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/smi.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367C switch low-level function for access register
+ * Feature : SMI related functions
+ *
+ */
+
+#ifndef __SMI_H__
+#define __SMI_H__
+
+#include <rtk_types.h>
+#include "rtk_error.h"
+
+#define MDC_MDIO_CTRL0_REG          31
+#define MDC_MDIO_START_REG          29
+#define MDC_MDIO_CTRL1_REG          21
+#define MDC_MDIO_ADDRESS_REG        23
+#define MDC_MDIO_DATA_WRITE_REG     24
+#define MDC_MDIO_DATA_READ_REG      25
+#define MDC_MDIO_PREAMBLE_LEN       32
+
+#define MDC_MDIO_START_OP          0xFFFF
+#define MDC_MDIO_ADDR_OP           0x000E
+#define MDC_MDIO_READ_OP           0x0001
+#define MDC_MDIO_WRITE_OP          0x0003
+
+#define SPI_READ_OP                 0x3
+#define SPI_WRITE_OP                0x2
+#define SPI_READ_OP_LEN             0x8
+#define SPI_WRITE_OP_LEN            0x8
+#define SPI_REG_LEN                 16
+#define SPI_DATA_LEN                16
+
+#define GPIO_DIR_IN                 1
+#define GPIO_DIR_OUT                0
+
+#define ack_timer                   5
+
+#define DELAY                        10000
+#define CLK_DURATION(clk)            { int i; for(i=0; i<clk; i++); }
+
+rtk_int32 smi_read(rtk_uint32 mAddrs, rtk_uint32 *rData);
+rtk_int32 smi_write(rtk_uint32 mAddrs, rtk_uint32 rData);
+
+#endif /* __SMI_H__ */
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/stat.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/stat.h
new file mode 100644
index 0000000..a735763
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/stat.h
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes MIB module high-layer API defination
+ *
+ */
+
+#ifndef __RTK_API_STAT_H__
+#define __RTK_API_STAT_H__
+
+/*
+ * Data Type Declaration
+ */
+typedef rtk_u_long_t rtk_stat_counter_t;
+
+/* global statistic counter structure */
+typedef struct rtk_stat_global_cntr_s
+{
+    rtk_uint64 dot1dTpLearnedEntryDiscards;
+}rtk_stat_global_cntr_t;
+
+typedef enum rtk_stat_global_type_e
+{
+    DOT1D_TP_LEARNED_ENTRY_DISCARDS_INDEX = 58,
+    MIB_GLOBAL_CNTR_END
+}rtk_stat_global_type_t;
+
+/* port statistic counter structure */
+typedef struct rtk_stat_port_cntr_s
+{
+    rtk_uint64 ifInOctets;
+    rtk_uint32 dot3StatsFCSErrors;
+    rtk_uint32 dot3StatsSymbolErrors;
+    rtk_uint32 dot3InPauseFrames;
+    rtk_uint32 dot3ControlInUnknownOpcodes;
+    rtk_uint32 etherStatsFragments;
+    rtk_uint32 etherStatsJabbers;
+    rtk_uint32 ifInUcastPkts;
+    rtk_uint32 etherStatsDropEvents;
+    rtk_uint64 etherStatsOctets;
+    rtk_uint32 etherStatsUndersizePkts;
+    rtk_uint32 etherStatsOversizePkts;
+    rtk_uint32 etherStatsPkts64Octets;
+    rtk_uint32 etherStatsPkts65to127Octets;
+    rtk_uint32 etherStatsPkts128to255Octets;
+    rtk_uint32 etherStatsPkts256to511Octets;
+    rtk_uint32 etherStatsPkts512to1023Octets;
+    rtk_uint32 etherStatsPkts1024toMaxOctets;
+    rtk_uint32 etherStatsMcastPkts;
+    rtk_uint32 etherStatsBcastPkts;
+    rtk_uint64 ifOutOctets;
+    rtk_uint32 dot3StatsSingleCollisionFrames;
+    rtk_uint32 dot3StatsMultipleCollisionFrames;
+    rtk_uint32 dot3StatsDeferredTransmissions;
+    rtk_uint32 dot3StatsLateCollisions;
+    rtk_uint32 etherStatsCollisions;
+    rtk_uint32 dot3StatsExcessiveCollisions;
+    rtk_uint32 dot3OutPauseFrames;
+    rtk_uint32 dot1dBasePortDelayExceededDiscards;
+    rtk_uint32 dot1dTpPortInDiscards;
+    rtk_uint32 ifOutUcastPkts;
+    rtk_uint32 ifOutMulticastPkts;
+    rtk_uint32 ifOutBrocastPkts;
+    rtk_uint32 outOampduPkts;
+    rtk_uint32 inOampduPkts;
+    rtk_uint32 pktgenPkts;
+    rtk_uint32 inMldChecksumError;
+    rtk_uint32 inIgmpChecksumError;
+    rtk_uint32 inMldSpecificQuery;
+    rtk_uint32 inMldGeneralQuery;
+    rtk_uint32 inIgmpSpecificQuery;
+    rtk_uint32 inIgmpGeneralQuery;
+    rtk_uint32 inMldLeaves;
+    rtk_uint32 inIgmpLeaves;
+    rtk_uint32 inIgmpJoinsSuccess;
+    rtk_uint32 inIgmpJoinsFail;
+    rtk_uint32 inMldJoinsSuccess;
+    rtk_uint32 inMldJoinsFail;
+    rtk_uint32 inReportSuppressionDrop;
+    rtk_uint32 inLeaveSuppressionDrop;
+    rtk_uint32 outIgmpReports;
+    rtk_uint32 outIgmpLeaves;
+    rtk_uint32 outIgmpGeneralQuery;
+    rtk_uint32 outIgmpSpecificQuery;
+    rtk_uint32 outMldReports;
+    rtk_uint32 outMldLeaves;
+    rtk_uint32 outMldGeneralQuery;
+    rtk_uint32 outMldSpecificQuery;
+    rtk_uint32 inKnownMulticastPkts;
+    rtk_uint32 ifInMulticastPkts;
+    rtk_uint32 ifInBroadcastPkts;
+    rtk_uint32 ifOutDiscards;
+}rtk_stat_port_cntr_t;
+
+/* port statistic counter index */
+typedef enum rtk_stat_port_type_e
+{
+    STAT_IfInOctets = 0,
+    STAT_Dot3StatsFCSErrors,
+    STAT_Dot3StatsSymbolErrors,
+    STAT_Dot3InPauseFrames,
+    STAT_Dot3ControlInUnknownOpcodes,
+    STAT_EtherStatsFragments,
+    STAT_EtherStatsJabbers,
+    STAT_IfInUcastPkts,
+    STAT_EtherStatsDropEvents,
+    STAT_EtherStatsOctets,
+    STAT_EtherStatsUnderSizePkts,
+    STAT_EtherOversizeStats,
+    STAT_EtherStatsPkts64Octets,
+    STAT_EtherStatsPkts65to127Octets,
+    STAT_EtherStatsPkts128to255Octets,
+    STAT_EtherStatsPkts256to511Octets,
+    STAT_EtherStatsPkts512to1023Octets,
+    STAT_EtherStatsPkts1024to1518Octets,
+    STAT_EtherStatsMulticastPkts,
+    STAT_EtherStatsBroadcastPkts,
+    STAT_IfOutOctets,
+    STAT_Dot3StatsSingleCollisionFrames,
+    STAT_Dot3StatsMultipleCollisionFrames,
+    STAT_Dot3StatsDeferredTransmissions,
+    STAT_Dot3StatsLateCollisions,
+    STAT_EtherStatsCollisions,
+    STAT_Dot3StatsExcessiveCollisions,
+    STAT_Dot3OutPauseFrames,
+    STAT_Dot1dBasePortDelayExceededDiscards,
+    STAT_Dot1dTpPortInDiscards,
+    STAT_IfOutUcastPkts,
+    STAT_IfOutMulticastPkts,
+    STAT_IfOutBroadcastPkts,
+    STAT_OutOampduPkts,
+    STAT_InOampduPkts,
+    STAT_PktgenPkts,
+    STAT_InMldChecksumError,
+    STAT_InIgmpChecksumError,
+    STAT_InMldSpecificQuery,
+    STAT_InMldGeneralQuery,
+    STAT_InIgmpSpecificQuery,
+    STAT_InIgmpGeneralQuery,
+    STAT_InMldLeaves,
+    STAT_InIgmpInterfaceLeaves,
+    STAT_InIgmpJoinsSuccess,
+    STAT_InIgmpJoinsFail,
+    STAT_InMldJoinsSuccess,
+    STAT_InMldJoinsFail,
+    STAT_InReportSuppressionDrop,
+    STAT_InLeaveSuppressionDrop,
+    STAT_OutIgmpReports,
+    STAT_OutIgmpLeaves,
+    STAT_OutIgmpGeneralQuery,
+    STAT_OutIgmpSpecificQuery,
+    STAT_OutMldReports,
+    STAT_OutMldLeaves,
+    STAT_OutMldGeneralQuery,
+    STAT_OutMldSpecificQuery,
+    STAT_InKnownMulticastPkts,
+    STAT_IfInMulticastPkts,
+    STAT_IfInBroadcastPkts,
+    STAT_IfOutDiscards,
+    STAT_PORT_CNTR_END
+}rtk_stat_port_type_t;
+
+typedef enum rtk_logging_counter_mode_e
+{
+    LOGGING_MODE_32BIT = 0,
+    LOGGING_MODE_64BIT,
+    LOGGING_MODE_END
+}rtk_logging_counter_mode_t;
+
+typedef enum rtk_logging_counter_type_e
+{
+    LOGGING_TYPE_PACKET = 0,
+    LOGGING_TYPE_BYTE,
+    LOGGING_TYPE_END
+}rtk_logging_counter_type_t;
+
+typedef enum rtk_stat_lengthMode_e
+{
+    LENGTH_MODE_EXC_TAG = 0,
+    LENGTH_MODE_INC_TAG,
+    LENGTH_MODE_END
+}rtk_stat_lengthMode_t;
+
+
+
+/* Function Name:
+ *      rtk_stat_global_reset
+ * Description:
+ *      Reset global MIB counter.
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      Reset MIB counter of ports. API will use global reset while port mask is all-ports.
+ */
+extern rtk_api_ret_t rtk_stat_global_reset(void);
+
+/* Function Name:
+ *      rtk_stat_port_reset
+ * Description:
+ *      Reset per port MIB counter by port.
+ * Input:
+ *      port - port id.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_stat_port_reset(rtk_port_t port);
+
+/* Function Name:
+ *      rtk_stat_queueManage_reset
+ * Description:
+ *      Reset queue manage MIB counter.
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_stat_queueManage_reset(void);
+
+/* Function Name:
+ *      rtk_stat_global_get
+ * Description:
+ *      Get global MIB counter
+ * Input:
+ *      cntr_idx - global counter index.
+ * Output:
+ *      pCntr - global counter value.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      Get global MIB counter by index definition.
+ */
+extern rtk_api_ret_t rtk_stat_global_get(rtk_stat_global_type_t cntr_idx, rtk_stat_counter_t *pCntr);
+
+/* Function Name:
+ *      rtk_stat_global_getAll
+ * Description:
+ *      Get all global MIB counter
+ * Input:
+ *      None
+ * Output:
+ *      pGlobal_cntrs - global counter structure.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      Get all global MIB counter by index definition.
+ */
+extern rtk_api_ret_t rtk_stat_global_getAll(rtk_stat_global_cntr_t *pGlobal_cntrs);
+
+/* Function Name:
+ *      rtk_stat_port_get
+ * Description:
+ *      Get per port MIB counter by index
+ * Input:
+ *      port        - port id.
+ *      cntr_idx    - port counter index.
+ * Output:
+ *      pCntr - MIB retrived counter.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      Get per port MIB counter by index definition.
+ */
+extern rtk_api_ret_t rtk_stat_port_get(rtk_port_t port, rtk_stat_port_type_t cntr_idx, rtk_stat_counter_t *pCntr);
+
+/* Function Name:
+ *      rtk_stat_port_getAll
+ * Description:
+ *      Get all counters of one specified port in the specified device.
+ * Input:
+ *      port - port id.
+ * Output:
+ *      pPort_cntrs - buffer pointer of counter value.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      Get all MIB counters of one port.
+ */
+extern rtk_api_ret_t rtk_stat_port_getAll(rtk_port_t port, rtk_stat_port_cntr_t *pPort_cntrs);
+
+/* Function Name:
+ *      rtk_stat_logging_counterCfg_set
+ * Description:
+ *      Set the type and mode of Logging Counter
+ * Input:
+ *      idx     - The index of Logging Counter. Should be even number only.(0,2,4,6,8.....30)
+ *      mode    - 32 bits or 64 bits mode
+ *      type    - Packet counter or byte counter
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_OUT_OF_RANGE - Out of range.
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      Set the type and mode of Logging Counter.
+ */
+extern rtk_api_ret_t rtk_stat_logging_counterCfg_set(rtk_uint32 idx, rtk_logging_counter_mode_t mode, rtk_logging_counter_type_t type);
+
+/* Function Name:
+ *      rtk_stat_logging_counterCfg_get
+ * Description:
+ *      Get the type and mode of Logging Counter
+ * Input:
+ *      idx     - The index of Logging Counter. Should be even number only.(0,2,4,6,8.....30)
+ * Output:
+ *      pMode   - 32 bits or 64 bits mode
+ *      pType   - Packet counter or byte counter
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_OUT_OF_RANGE - Out of range.
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_NULL_POINTER - NULL Pointer
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      Get the type and mode of Logging Counter.
+ */
+extern rtk_api_ret_t rtk_stat_logging_counterCfg_get(rtk_uint32 idx, rtk_logging_counter_mode_t *pMode, rtk_logging_counter_type_t *pType);
+
+/* Function Name:
+ *      rtk_stat_logging_counter_reset
+ * Description:
+ *      Reset Logging Counter
+ * Input:
+ *      idx     - The index of Logging Counter. (0~31)
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_OUT_OF_RANGE - Out of range.
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      Reset Logging Counter.
+ */
+extern rtk_api_ret_t rtk_stat_logging_counter_reset(rtk_uint32 idx);
+
+/* Function Name:
+ *      rtk_stat_logging_counter_get
+ * Description:
+ *      Get Logging Counter
+ * Input:
+ *      idx     - The index of Logging Counter. (0~31)
+ * Output:
+ *      pCnt    - Logging counter value
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_OUT_OF_RANGE - Out of range.
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      Get Logging Counter.
+ */
+extern rtk_api_ret_t rtk_stat_logging_counter_get(rtk_uint32 idx, rtk_uint32 *pCnt);
+
+/* Function Name:
+ *      rtk_stat_lengthMode_set
+ * Description:
+ *      Set Legnth mode.
+ * Input:
+ *      txMode     - The length counting mode
+ *      rxMode     - The length counting mode
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_INPUT        - Out of range.
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_stat_lengthMode_set(rtk_stat_lengthMode_t txMode, rtk_stat_lengthMode_t rxMode);
+
+/* Function Name:
+ *      rtk_stat_lengthMode_get
+ * Description:
+ *      Get Legnth mode.
+ * Input:
+ *      None.
+ * Output:
+ *      pTxMode       - The length counting mode
+ *      pRxMode       - The length counting mode
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_INPUT        - Out of range.
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ */
+extern rtk_api_ret_t rtk_stat_lengthMode_get(rtk_stat_lengthMode_t *pTxMode, rtk_stat_lengthMode_t *pRxMode);
+
+#endif /* __RTK_API_STAT_H__ */
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/storm.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/storm.h
new file mode 100644
index 0000000..55a50d7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/storm.h
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes Storm module high-layer API defination
+ *
+ */
+
+#ifndef __RTK_API_STORM_H__
+#define __RTK_API_STORM_H__
+
+#define STORM_UNUC_INDEX                            28
+#define STORM_UNMC_INDEX                            29
+#define STORM_MC_INDEX                              30
+#define STORM_BC_INDEX                              31
+
+typedef enum rtk_rate_storm_group_e
+{
+    STORM_GROUP_UNKNOWN_UNICAST = 0,
+    STORM_GROUP_UNKNOWN_MULTICAST,
+    STORM_GROUP_MULTICAST,
+    STORM_GROUP_BROADCAST,
+    STORM_GROUP_END
+} rtk_rate_storm_group_t;
+
+typedef enum rtk_storm_bypass_e
+{
+    BYPASS_BRG_GROUP = 0,
+    BYPASS_FD_PAUSE,
+    BYPASS_SP_MCAST,
+    BYPASS_1X_PAE,
+    BYPASS_UNDEF_BRG_04,
+    BYPASS_UNDEF_BRG_05,
+    BYPASS_UNDEF_BRG_06,
+    BYPASS_UNDEF_BRG_07,
+    BYPASS_PROVIDER_BRIDGE_GROUP_ADDRESS,
+    BYPASS_UNDEF_BRG_09,
+    BYPASS_UNDEF_BRG_0A,
+    BYPASS_UNDEF_BRG_0B,
+    BYPASS_UNDEF_BRG_0C,
+    BYPASS_PROVIDER_BRIDGE_GVRP_ADDRESS,
+    BYPASS_8021AB,
+    BYPASS_UNDEF_BRG_0F,
+    BYPASS_BRG_MNGEMENT,
+    BYPASS_UNDEFINED_11,
+    BYPASS_UNDEFINED_12,
+    BYPASS_UNDEFINED_13,
+    BYPASS_UNDEFINED_14,
+    BYPASS_UNDEFINED_15,
+    BYPASS_UNDEFINED_16,
+    BYPASS_UNDEFINED_17,
+    BYPASS_UNDEFINED_18,
+    BYPASS_UNDEFINED_19,
+    BYPASS_UNDEFINED_1A,
+    BYPASS_UNDEFINED_1B,
+    BYPASS_UNDEFINED_1C,
+    BYPASS_UNDEFINED_1D,
+    BYPASS_UNDEFINED_1E,
+    BYPASS_UNDEFINED_1F,
+    BYPASS_GMRP,
+    BYPASS_GVRP,
+    BYPASS_UNDEF_GARP_22,
+    BYPASS_UNDEF_GARP_23,
+    BYPASS_UNDEF_GARP_24,
+    BYPASS_UNDEF_GARP_25,
+    BYPASS_UNDEF_GARP_26,
+    BYPASS_UNDEF_GARP_27,
+    BYPASS_UNDEF_GARP_28,
+    BYPASS_UNDEF_GARP_29,
+    BYPASS_UNDEF_GARP_2A,
+    BYPASS_UNDEF_GARP_2B,
+    BYPASS_UNDEF_GARP_2C,
+    BYPASS_UNDEF_GARP_2D,
+    BYPASS_UNDEF_GARP_2E,
+    BYPASS_UNDEF_GARP_2F,
+    BYPASS_IGMP,
+    BYPASS_CDP,
+    BYPASS_CSSTP,
+    BYPASS_LLDP,
+    BYPASS_END,
+}rtk_storm_bypass_t;
+
+/* Function Name:
+ *      rtk_rate_stormControlMeterIdx_set
+ * Description:
+ *      Set the storm control meter index.
+ * Input:
+ *      port       - port id
+ *      storm_type - storm group type
+ *      index       - storm control meter index.
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID - Invalid port id
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_rate_stormControlMeterIdx_set(rtk_port_t port, rtk_rate_storm_group_t stormType, rtk_uint32 index);
+
+/* Function Name:
+ *      rtk_rate_stormControlMeterIdx_get
+ * Description:
+ *      Get the storm control meter index.
+ * Input:
+ *      port       - port id
+ *      storm_type - storm group type
+ * Output:
+ *      pIndex     - storm control meter index.
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID - Invalid port id
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_rate_stormControlMeterIdx_get(rtk_port_t port, rtk_rate_storm_group_t stormType, rtk_uint32 *pIndex);
+
+/* Function Name:
+ *      rtk_rate_stormControlPortEnable_set
+ * Description:
+ *      Set enable status of storm control on specified port.
+ * Input:
+ *      port       - port id
+ *      stormType  - storm group type
+ *      enable     - enable status of storm control
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT          - The module is not initial
+ *      RT_ERR_PORT_ID           - invalid port id
+ *      RT_ERR_INPUT             - invalid input parameter
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_rate_stormControlPortEnable_set(rtk_port_t port, rtk_rate_storm_group_t stormType, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_rate_stormControlPortEnable_set
+ * Description:
+ *      Set enable status of storm control on specified port.
+ * Input:
+ *      port       - port id
+ *      stormType  - storm group type
+ * Output:
+ *      pEnable     - enable status of storm control
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT          - The module is not initial
+ *      RT_ERR_PORT_ID           - invalid port id
+ *      RT_ERR_INPUT             - invalid input parameter
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_rate_stormControlPortEnable_get(rtk_port_t port, rtk_rate_storm_group_t stormType, rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_storm_bypass_set
+ * Description:
+ *      Set bypass storm filter control configuration.
+ * Input:
+ *      type    - Bypass storm filter control type.
+ *      enable  - Bypass status.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_ENABLE       - Invalid IFG parameter
+ * Note:
+ *
+ *      This API can set per-port bypass stomr filter control frame type including RMA and igmp.
+ *      The bypass frame type is as following:
+ *      - BYPASS_BRG_GROUP,
+ *      - BYPASS_FD_PAUSE,
+ *      - BYPASS_SP_MCAST,
+ *      - BYPASS_1X_PAE,
+ *      - BYPASS_UNDEF_BRG_04,
+ *      - BYPASS_UNDEF_BRG_05,
+ *      - BYPASS_UNDEF_BRG_06,
+ *      - BYPASS_UNDEF_BRG_07,
+ *      - BYPASS_PROVIDER_BRIDGE_GROUP_ADDRESS,
+ *      - BYPASS_UNDEF_BRG_09,
+ *      - BYPASS_UNDEF_BRG_0A,
+ *      - BYPASS_UNDEF_BRG_0B,
+ *      - BYPASS_UNDEF_BRG_0C,
+ *      - BYPASS_PROVIDER_BRIDGE_GVRP_ADDRESS,
+ *      - BYPASS_8021AB,
+ *      - BYPASS_UNDEF_BRG_0F,
+ *      - BYPASS_BRG_MNGEMENT,
+ *      - BYPASS_UNDEFINED_11,
+ *      - BYPASS_UNDEFINED_12,
+ *      - BYPASS_UNDEFINED_13,
+ *      - BYPASS_UNDEFINED_14,
+ *      - BYPASS_UNDEFINED_15,
+ *      - BYPASS_UNDEFINED_16,
+ *      - BYPASS_UNDEFINED_17,
+ *      - BYPASS_UNDEFINED_18,
+ *      - BYPASS_UNDEFINED_19,
+ *      - BYPASS_UNDEFINED_1A,
+ *      - BYPASS_UNDEFINED_1B,
+ *      - BYPASS_UNDEFINED_1C,
+ *      - BYPASS_UNDEFINED_1D,
+ *      - BYPASS_UNDEFINED_1E,
+ *      - BYPASS_UNDEFINED_1F,
+ *      - BYPASS_GMRP,
+ *      - BYPASS_GVRP,
+ *      - BYPASS_UNDEF_GARP_22,
+ *      - BYPASS_UNDEF_GARP_23,
+ *      - BYPASS_UNDEF_GARP_24,
+ *      - BYPASS_UNDEF_GARP_25,
+ *      - BYPASS_UNDEF_GARP_26,
+ *      - BYPASS_UNDEF_GARP_27,
+ *      - BYPASS_UNDEF_GARP_28,
+ *      - BYPASS_UNDEF_GARP_29,
+ *      - BYPASS_UNDEF_GARP_2A,
+ *      - BYPASS_UNDEF_GARP_2B,
+ *      - BYPASS_UNDEF_GARP_2C,
+ *      - BYPASS_UNDEF_GARP_2D,
+ *      - BYPASS_UNDEF_GARP_2E,
+ *      - BYPASS_UNDEF_GARP_2F,
+ *      - BYPASS_IGMP.
+ */
+extern rtk_api_ret_t rtk_storm_bypass_set(rtk_storm_bypass_t type, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_storm_bypass_get
+ * Description:
+ *      Get bypass storm filter control configuration.
+ * Input:
+ *      type - Bypass storm filter control type.
+ * Output:
+ *      pEnable - Bypass status.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API can get per-port bypass stomr filter control frame type including RMA and igmp.
+ *      The bypass frame type is as following:
+ *      - BYPASS_BRG_GROUP,
+ *      - BYPASS_FD_PAUSE,
+ *      - BYPASS_SP_MCAST,
+ *      - BYPASS_1X_PAE,
+ *      - BYPASS_UNDEF_BRG_04,
+ *      - BYPASS_UNDEF_BRG_05,
+ *      - BYPASS_UNDEF_BRG_06,
+ *      - BYPASS_UNDEF_BRG_07,
+ *      - BYPASS_PROVIDER_BRIDGE_GROUP_ADDRESS,
+ *      - BYPASS_UNDEF_BRG_09,
+ *      - BYPASS_UNDEF_BRG_0A,
+ *      - BYPASS_UNDEF_BRG_0B,
+ *      - BYPASS_UNDEF_BRG_0C,
+ *      - BYPASS_PROVIDER_BRIDGE_GVRP_ADDRESS,
+ *      - BYPASS_8021AB,
+ *      - BYPASS_UNDEF_BRG_0F,
+ *      - BYPASS_BRG_MNGEMENT,
+ *      - BYPASS_UNDEFINED_11,
+ *      - BYPASS_UNDEFINED_12,
+ *      - BYPASS_UNDEFINED_13,
+ *      - BYPASS_UNDEFINED_14,
+ *      - BYPASS_UNDEFINED_15,
+ *      - BYPASS_UNDEFINED_16,
+ *      - BYPASS_UNDEFINED_17,
+ *      - BYPASS_UNDEFINED_18,
+ *      - BYPASS_UNDEFINED_19,
+ *      - BYPASS_UNDEFINED_1A,
+ *      - BYPASS_UNDEFINED_1B,
+ *      - BYPASS_UNDEFINED_1C,
+ *      - BYPASS_UNDEFINED_1D,
+ *      - BYPASS_UNDEFINED_1E,
+ *      - BYPASS_UNDEFINED_1F,
+ *      - BYPASS_GMRP,
+ *      - BYPASS_GVRP,
+ *      - BYPASS_UNDEF_GARP_22,
+ *      - BYPASS_UNDEF_GARP_23,
+ *      - BYPASS_UNDEF_GARP_24,
+ *      - BYPASS_UNDEF_GARP_25,
+ *      - BYPASS_UNDEF_GARP_26,
+ *      - BYPASS_UNDEF_GARP_27,
+ *      - BYPASS_UNDEF_GARP_28,
+ *      - BYPASS_UNDEF_GARP_29,
+ *      - BYPASS_UNDEF_GARP_2A,
+ *      - BYPASS_UNDEF_GARP_2B,
+ *      - BYPASS_UNDEF_GARP_2C,
+ *      - BYPASS_UNDEF_GARP_2D,
+ *      - BYPASS_UNDEF_GARP_2E,
+ *      - BYPASS_UNDEF_GARP_2F,
+ *      - BYPASS_IGMP.
+ */
+extern rtk_api_ret_t rtk_storm_bypass_get(rtk_storm_bypass_t type, rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_rate_stormControlExtPortmask_set
+ * Description:
+ *      Set externsion storm control port mask
+ * Input:
+ *      pPortmask  - port mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT          - The module is not initial
+ *      RT_ERR_INPUT             - invalid input parameter
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_rate_stormControlExtPortmask_set(rtk_portmask_t *pPortmask);
+
+/* Function Name:
+ *      rtk_rate_stormControlExtPortmask_get
+ * Description:
+ *      Set externsion storm control port mask
+ * Input:
+ *      None
+ * Output:
+ *      pPortmask  - port mask
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT          - The module is not initial
+ *      RT_ERR_INPUT             - invalid input parameter
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_rate_stormControlExtPortmask_get(rtk_portmask_t *pPortmask);
+
+/* Function Name:
+ *      rtk_rate_stormControlExtEnable_set
+ * Description:
+ *      Set externsion storm control state
+ * Input:
+ *      stormType   - storm group type
+ *      enable      - externsion storm control state
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT          - The module is not initial
+ *      RT_ERR_INPUT             - invalid input parameter
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_rate_stormControlExtEnable_set(rtk_rate_storm_group_t stormType, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_rate_stormControlExtEnable_get
+ * Description:
+ *      Get externsion storm control state
+ * Input:
+ *      stormType   - storm group type
+ * Output:
+ *      pEnable     - externsion storm control state
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT          - The module is not initial
+ *      RT_ERR_INPUT             - invalid input parameter
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_rate_stormControlExtEnable_get(rtk_rate_storm_group_t stormType, rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_rate_stormControlExtMeterIdx_set
+ * Description:
+ *      Set externsion storm control meter index
+ * Input:
+ *      stormType   - storm group type
+ *      index       - externsion storm control state
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT          - The module is not initial
+ *      RT_ERR_INPUT             - invalid input parameter
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_rate_stormControlExtMeterIdx_set(rtk_rate_storm_group_t stormType, rtk_uint32 index);
+
+/* Function Name:
+ *      rtk_rate_stormControlExtMeterIdx_get
+ * Description:
+ *      Get externsion storm control meter index
+ * Input:
+ *      stormType   - storm group type
+ *      pIndex      - externsion storm control state
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT          - The module is not initial
+ *      RT_ERR_INPUT             - invalid input parameter
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_rate_stormControlExtMeterIdx_get(rtk_rate_storm_group_t stormType, rtk_uint32 *pIndex);
+
+
+
+#endif /* __RTK_API_STORM_H__ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/svlan.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/svlan.h
new file mode 100644
index 0000000..bcdb02f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/svlan.h
@@ -0,0 +1,896 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes SVLAN module high-layer API defination
+ *
+ */
+
+#ifndef __RTK_API_SVLAN_H__
+#define __RTK_API_SVLAN_H__
+
+typedef rtk_uint32 rtk_svlan_index_t;
+
+typedef struct rtk_svlan_memberCfg_s{
+    rtk_uint32 svid;
+    rtk_portmask_t memberport;
+    rtk_portmask_t untagport;
+    rtk_uint32 fiden;
+    rtk_uint32 fid;
+    rtk_uint32 priority;
+    rtk_uint32 efiden;
+    rtk_uint32 efid;
+}rtk_svlan_memberCfg_t;
+
+typedef enum rtk_svlan_pri_ref_e
+{
+    REF_INTERNAL_PRI = 0,
+    REF_CTAG_PRI,
+    REF_SVLAN_PRI,
+    REF_PB_PRI,
+    REF_PRI_END
+} rtk_svlan_pri_ref_t;
+
+
+typedef rtk_uint32 rtk_svlan_tpid_t;
+
+typedef enum rtk_svlan_untag_action_e
+{
+    UNTAG_DROP = 0,
+    UNTAG_TRAP,
+    UNTAG_ASSIGN,
+    UNTAG_END
+} rtk_svlan_untag_action_t;
+
+typedef enum rtk_svlan_unmatch_action_e
+{
+    UNMATCH_DROP = 0,
+    UNMATCH_TRAP,
+    UNMATCH_ASSIGN,
+    UNMATCH_END
+} rtk_svlan_unmatch_action_t;
+
+typedef enum rtk_svlan_unassign_action_e
+{
+    UNASSIGN_PBSVID = 0,
+    UNASSIGN_TRAP,
+    UNASSIGN_END
+} rtk_svlan_unassign_action_t;
+
+
+typedef enum rtk_svlan_lookupType_e
+{
+    SVLAN_LOOKUP_S64MBRCGF  = 0,
+    SVLAN_LOOKUP_C4KVLAN,
+    SVLAN_LOOKUP_END,
+
+} rtk_svlan_lookupType_t;
+
+/* Function Name:
+ *      rtk_svlan_init
+ * Description:
+ *      Initialize SVLAN Configuration
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      Ether type of S-tag in 802.1ad is 0x88a8 and there are existed ether type 0x9100 and 0x9200 for Q-in-Q SLAN design.
+ *      User can set mathced ether type as service provider supported protocol.
+ */
+extern rtk_api_ret_t rtk_svlan_init(void);
+
+/* Function Name:
+ *      rtk_svlan_servicePort_add
+ * Description:
+ *      Add one service port in the specified device
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API is setting which port is connected to provider switch. All frames receiving from this port must
+ *      contain accept SVID in S-tag field.
+ */
+extern rtk_api_ret_t rtk_svlan_servicePort_add(rtk_port_t port);
+
+/* Function Name:
+ *      rtk_svlan_servicePort_get
+ * Description:
+ *      Get service ports in the specified device.
+ * Input:
+ *      None
+ * Output:
+ *      pSvlan_portmask - pointer buffer of svlan ports.
+ * Return:
+ *      RT_ERR_OK          - OK
+ *      RT_ERR_FAILED      - Failed
+ *      RT_ERR_SMI         - SMI access error
+ * Note:
+ *      This API is setting which port is connected to provider switch. All frames receiving from this port must
+ *      contain accept SVID in S-tag field.
+ */
+extern rtk_api_ret_t rtk_svlan_servicePort_get(rtk_portmask_t *pSvlan_portmask);
+
+/* Function Name:
+ *      rtk_svlan_servicePort_del
+ * Description:
+ *      Delete one service port in the specified device
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API is removing SVLAN service port in the specified device.
+ */
+extern rtk_api_ret_t rtk_svlan_servicePort_del(rtk_port_t port);
+
+/* Function Name:
+ *      rtk_svlan_tpidEntry_set
+ * Description:
+ *      Configure accepted S-VLAN ether type.
+ * Input:
+ *      svlan_tag_id - Ether type of S-tag frame parsing in uplink ports.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ * Note:
+ *      Ether type of S-tag in 802.1ad is 0x88a8 and there are existed ether type 0x9100 and 0x9200 for Q-in-Q SLAN design.
+ *      User can set mathced ether type as service provider supported protocol.
+ */
+extern rtk_api_ret_t rtk_svlan_tpidEntry_set(rtk_uint32 svlan_tag_id);
+
+/* Function Name:
+ *      rtk_svlan_tpidEntry_get
+ * Description:
+ *      Get accepted S-VLAN ether type setting.
+ * Input:
+ *      None
+ * Output:
+ *      pSvlan_tag_id -  Ether type of S-tag frame parsing in uplink ports.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      This API is setting which port is connected to provider switch. All frames receiving from this port must
+ *      contain accept SVID in S-tag field.
+ */
+extern rtk_api_ret_t rtk_svlan_tpidEntry_get(rtk_uint32 *pSvlan_tag_id);
+
+/* Function Name:
+ *      rtk_svlan_priorityRef_set
+ * Description:
+ *      Set S-VLAN upstream priority reference setting.
+ * Input:
+ *      ref - reference selection parameter.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ * Note:
+ *      The API can set the upstream SVLAN tag priority reference source. The related priority
+ *      sources are as following:
+ *      - REF_INTERNAL_PRI,
+ *      - REF_CTAG_PRI,
+ *      - REF_SVLAN_PRI,
+ *      - REF_PB_PRI.
+ */
+extern rtk_api_ret_t rtk_svlan_priorityRef_set(rtk_svlan_pri_ref_t ref);
+
+/* Function Name:
+ *      rtk_svlan_priorityRef_get
+ * Description:
+ *      Get S-VLAN upstream priority reference setting.
+ * Input:
+ *      None
+ * Output:
+ *      pRef - reference selection parameter.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      The API can get the upstream SVLAN tag priority reference source. The related priority
+ *      sources are as following:
+ *      - REF_INTERNAL_PRI,
+ *      - REF_CTAG_PRI,
+ *      - REF_SVLAN_PRI,
+ *      - REF_PB_PRI
+ */
+extern rtk_api_ret_t rtk_svlan_priorityRef_get(rtk_svlan_pri_ref_t *pRef);
+
+/* Function Name:
+ *      rtk_svlan_memberPortEntry_set
+ * Description:
+ *      Configure system SVLAN member content
+ * Input:
+ *      svid - SVLAN id
+ *      psvlan_cfg - SVLAN member configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameter.
+ *      RT_ERR_SVLAN_VID        - Invalid SVLAN VID parameter.
+ *      RT_ERR_PORT_MASK        - Invalid portmask.
+ *      RT_ERR_SVLAN_TABLE_FULL - SVLAN configuration is full.
+ * Note:
+ *      The API can set system 64 accepted s-tag frame format. Only 64 SVID S-tag frame will be accpeted
+ *      to receiving from uplink ports. Other SVID S-tag frame or S-untagged frame will be droped by default setup.
+ *      - rtk_svlan_memberCfg_t->svid is SVID of SVLAN member configuration.
+ *      - rtk_svlan_memberCfg_t->memberport is member port mask of SVLAN member configuration.
+ *      - rtk_svlan_memberCfg_t->fid is filtering database of SVLAN member configuration.
+ *      - rtk_svlan_memberCfg_t->priority is priority of SVLAN member configuration.
+ */
+extern rtk_api_ret_t rtk_svlan_memberPortEntry_set(rtk_uint32 svid_idx, rtk_svlan_memberCfg_t *psvlan_cfg);
+
+/* Function Name:
+ *      rtk_svlan_memberPortEntry_get
+ * Description:
+ *      Get SVLAN member Configure.
+ * Input:
+ *      svid - SVLAN id
+ * Output:
+ *      pSvlan_cfg - SVLAN member configuration
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      The API can get system 64 accepted s-tag frame format. Only 64 SVID S-tag frame will be accpeted
+ *      to receiving from uplink ports. Other SVID S-tag frame or S-untagged frame will be droped.
+ */
+extern rtk_api_ret_t rtk_svlan_memberPortEntry_get(rtk_uint32 svid_idx, rtk_svlan_memberCfg_t *pSvlan_cfg);
+
+/* Function Name:
+ *      rtk_svlan_memberPortEntry_adv_set
+ * Description:
+ *      Configure system SVLAN member by index
+ * Input:
+ *      idx         - Index (0 ~ 63)
+ *      psvlan_cfg  - SVLAN member configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameter.
+ *      RT_ERR_SVLAN_VID        - Invalid SVLAN VID parameter.
+ *      RT_ERR_PORT_MASK        - Invalid portmask.
+ *      RT_ERR_SVLAN_TABLE_FULL - SVLAN configuration is full.
+ * Note:
+ *      The API can set system 64 accepted s-tag frame format by index.
+ *      - rtk_svlan_memberCfg_t->svid is SVID of SVLAN member configuration.
+ *      - rtk_svlan_memberCfg_t->memberport is member port mask of SVLAN member configuration.
+ *      - rtk_svlan_memberCfg_t->fid is filtering database of SVLAN member configuration.
+ *      - rtk_svlan_memberCfg_t->priority is priority of SVLAN member configuration.
+ */
+extern rtk_api_ret_t rtk_svlan_memberPortEntry_adv_set(rtk_uint32 idx, rtk_svlan_memberCfg_t *pSvlan_cfg);
+
+/* Function Name:
+ *      rtk_svlan_memberPortEntry_adv_get
+ * Description:
+ *      Get SVLAN member Configure by index.
+ * Input:
+ *      idx         - Index (0 ~ 63)
+ * Output:
+ *      pSvlan_cfg  - SVLAN member configuration
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      The API can get system 64 accepted s-tag frame format. Only 64 SVID S-tag frame will be accpeted
+ *      to receiving from uplink ports. Other SVID S-tag frame or S-untagged frame will be droped.
+ */
+extern rtk_api_ret_t rtk_svlan_memberPortEntry_adv_get(rtk_uint32 idx, rtk_svlan_memberCfg_t *pSvlan_cfg);
+
+/* Function Name:
+ *      rtk_svlan_defaultSvlan_set
+ * Description:
+ *      Configure default egress SVLAN.
+ * Input:
+ *      port - Source port
+ *      svid - SVLAN id
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_INPUT                    - Invalid input parameter.
+ *      RT_ERR_SVLAN_VID                - Invalid SVLAN VID parameter.
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ * Note:
+ *      The API can set port n S-tag format index while receiving frame from port n
+ *      is transmit through uplink port with s-tag field
+ */
+extern rtk_api_ret_t rtk_svlan_defaultSvlan_set(rtk_port_t port, rtk_vlan_t svid);
+
+/* Function Name:
+ *      rtk_svlan_defaultSvlan_get
+ * Description:
+ *      Get the configure default egress SVLAN.
+ * Input:
+ *      port - Source port
+ * Output:
+ *      pSvid - SVLAN VID
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get port n S-tag format index while receiving frame from port n
+ *      is transmit through uplink port with s-tag field
+ */
+extern rtk_api_ret_t rtk_svlan_defaultSvlan_get(rtk_port_t port, rtk_vlan_t *pSvid);
+
+/* Function Name:
+ *      rtk_svlan_c2s_add
+ * Description:
+ *      Configure SVLAN C2S table
+ * Input:
+ *      vid - VLAN ID
+ *      src_port - Ingress Port
+ *      svid - SVLAN VID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port ID.
+ *      RT_ERR_SVLAN_VID    - Invalid SVLAN VID parameter.
+ *      RT_ERR_VLAN_VID     - Invalid VID parameter.
+ *      RT_ERR_OUT_OF_RANGE - input out of range.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can set system C2S configuration. ASIC will check upstream's VID and assign related
+ *      SVID to mathed packet. There are 128 SVLAN C2S configurations.
+ */
+extern rtk_api_ret_t rtk_svlan_c2s_add(rtk_vlan_t vid, rtk_port_t src_port, rtk_vlan_t svid);
+
+/* Function Name:
+ *      rtk_svlan_c2s_del
+ * Description:
+ *      Delete one C2S entry
+ * Input:
+ *      vid - VLAN ID
+ *      src_port - Ingress Port
+ *      svid - SVLAN VID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_VLAN_VID         - Invalid VID parameter.
+ *      RT_ERR_PORT_ID          - Invalid port ID.
+ *      RT_ERR_OUT_OF_RANGE     - input out of range.
+ * Note:
+ *      The API can delete system C2S configuration. There are 128 SVLAN C2S configurations.
+ */
+extern rtk_api_ret_t rtk_svlan_c2s_del(rtk_vlan_t vid, rtk_port_t src_port);
+
+/* Function Name:
+ *      rtk_svlan_c2s_get
+ * Description:
+ *      Get configure SVLAN C2S table
+ * Input:
+ *      vid - VLAN ID
+ *      src_port - Ingress Port
+ * Output:
+ *      pSvid - SVLAN ID
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port ID.
+ *      RT_ERR_OUT_OF_RANGE - input out of range.
+ * Note:
+ *     The API can get system C2S configuration. There are 128 SVLAN C2S configurations.
+ */
+extern rtk_api_ret_t rtk_svlan_c2s_get(rtk_vlan_t vid, rtk_port_t src_port, rtk_vlan_t *pSvid);
+
+/* Function Name:
+ *      rtk_svlan_untag_action_set
+ * Description:
+ *      Configure Action of downstream Un-Stag packet
+ * Input:
+ *      action  - Action for UnStag
+ *      svid    - The SVID assigned to UnStag packet
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_SVLAN_VID                - Invalid SVLAN VID parameter.
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ *      RT_ERR_OUT_OF_RANGE             - input out of range.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      The API can configure action of downstream Un-Stag packet. A SVID assigned
+ *      to the un-stag is also supported by this API. The parameter of svid is
+ *      only referenced when the action is set to UNTAG_ASSIGN
+ */
+extern rtk_api_ret_t rtk_svlan_untag_action_set(rtk_svlan_untag_action_t action, rtk_vlan_t svid);
+
+/* Function Name:
+ *      rtk_svlan_untag_action_get
+ * Description:
+ *      Get Action of downstream Un-Stag packet
+ * Input:
+ *      None
+ * Output:
+ *      pAction  - Action for UnStag
+ *      pSvid    - The SVID assigned to UnStag packet
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_SVLAN_VID                - Invalid SVLAN VID parameter.
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ *      RT_ERR_OUT_OF_RANGE             - input out of range.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      The API can Get action of downstream Un-Stag packet. A SVID assigned
+ *      to the un-stag is also retrieved by this API. The parameter pSvid is
+ *      only refernced when the action is UNTAG_ASSIGN
+ */
+extern rtk_api_ret_t rtk_svlan_untag_action_get(rtk_svlan_untag_action_t *pAction, rtk_vlan_t *pSvid);
+
+/* Function Name:
+ *      rtk_svlan_unmatch_action_set
+ * Description:
+ *      Configure Action of downstream Unmatch packet
+ * Input:
+ *      action  - Action for Unmatch
+ *      svid    - The SVID assigned to Unmatch packet
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_SVLAN_VID                - Invalid SVLAN VID parameter.
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ *      RT_ERR_OUT_OF_RANGE             - input out of range.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      The API can configure action of downstream Un-match packet. A SVID assigned
+ *      to the un-match is also supported by this API. The parameter od svid is
+ *      only refernced when the action is set to UNMATCH_ASSIGN
+ */
+extern rtk_api_ret_t rtk_svlan_unmatch_action_set(rtk_svlan_unmatch_action_t action, rtk_vlan_t svid);
+
+/* Function Name:
+ *      rtk_svlan_unmatch_action_get
+ * Description:
+ *      Get Action of downstream Unmatch packet
+ * Input:
+ *      None
+ * Output:
+ *      pAction  - Action for Unmatch
+ *      pSvid    - The SVID assigned to Unmatch packet
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_SVLAN_VID                - Invalid SVLAN VID parameter.
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ *      RT_ERR_OUT_OF_RANGE             - input out of range.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      The API can Get action of downstream Un-match packet. A SVID assigned
+ *      to the un-match is also retrieved by this API. The parameter pSvid is
+ *      only refernced when the action is UNMATCH_ASSIGN
+ */
+extern rtk_api_ret_t rtk_svlan_unmatch_action_get(rtk_svlan_unmatch_action_t *pAction, rtk_vlan_t *pSvid);
+
+/* Function Name:
+ *      rtk_svlan_dmac_vidsel_set
+ * Description:
+ *      Set DMAC CVID selection
+ * Input:
+ *      port    - Port
+ *      enable  - state of DMAC CVID Selection
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_SVLAN_VID                - Invalid SVLAN VID parameter.
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ *      RT_ERR_OUT_OF_RANGE             - input out of range.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      This API can set DMAC CVID Selection state
+ */
+extern rtk_api_ret_t rtk_svlan_dmac_vidsel_set(rtk_port_t port, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_svlan_dmac_vidsel_get
+ * Description:
+ *      Get DMAC CVID selection
+ * Input:
+ *      port    - Port
+ * Output:
+ *      pEnable - state of DMAC CVID Selection
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_SVLAN_VID                - Invalid SVLAN VID parameter.
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ *      RT_ERR_OUT_OF_RANGE             - input out of range.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      This API can get DMAC CVID Selection state
+ */
+extern rtk_api_ret_t rtk_svlan_dmac_vidsel_get(rtk_port_t port, rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_svlan_ipmc2s_add
+ * Description:
+ *      add ip multicast address to SVLAN
+ * Input:
+ *      svid    - SVLAN VID
+ *      ipmc    - ip multicast address
+ *      ipmcMsk - ip multicast mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_SVLAN_VID                - Invalid SVLAN VID parameter.
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ *      RT_ERR_OUT_OF_RANGE             - input out of range.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      The API can set IP mutlicast to SVID configuration. If upstream packet is IPv4 multicast
+ *      packet and DIP is matched MC2S configuration, ASIC will assign egress SVID to the packet.
+ *      There are 32 SVLAN multicast configurations for IP and L2 multicast.
+ */
+extern rtk_api_ret_t rtk_svlan_ipmc2s_add(ipaddr_t ipmc, ipaddr_t ipmcMsk, rtk_vlan_t svid);
+
+/* Function Name:
+ *      rtk_svlan_ipmc2s_del
+ * Description:
+ *      delete ip multicast address to SVLAN
+ * Input:
+ *      ipmc    - ip multicast address
+ *      ipmcMsk - ip multicast mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_SVLAN_VID        - Invalid SVLAN VID parameter.
+ *      RT_ERR_OUT_OF_RANGE     - input out of range.
+ * Note:
+ *      The API can delete IP mutlicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast.
+ */
+extern rtk_api_ret_t rtk_svlan_ipmc2s_del(ipaddr_t ipmc, ipaddr_t ipmcMsk);
+
+/* Function Name:
+ *      rtk_svlan_ipmc2s_get
+ * Description:
+ *      Get ip multicast address to SVLAN
+ * Input:
+ *      ipmc    - ip multicast address
+ *      ipmcMsk - ip multicast mask
+ * Output:
+ *      pSvid - SVLAN VID
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_OUT_OF_RANGE - input out of range.
+ * Note:
+ *      The API can get IP mutlicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast.
+ */
+extern rtk_api_ret_t rtk_svlan_ipmc2s_get(ipaddr_t ipmc, ipaddr_t ipmcMsk, rtk_vlan_t *pSvid);
+
+/* Function Name:
+ *      rtk_svlan_l2mc2s_add
+ * Description:
+ *      Add L2 multicast address to SVLAN
+ * Input:
+ *      mac     - L2 multicast address
+ *      macMsk  - L2 multicast address mask
+ *      svid    - SVLAN VID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_SVLAN_VID                - Invalid SVLAN VID parameter.
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ *      RT_ERR_OUT_OF_RANGE             - input out of range.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      The API can set L2 Mutlicast to SVID configuration. If upstream packet is L2 multicast
+ *      packet and DMAC is matched, ASIC will assign egress SVID to the packet. There are 32
+ *      SVLAN multicast configurations for IP and L2 multicast.
+ */
+extern rtk_api_ret_t rtk_svlan_l2mc2s_add(rtk_mac_t mac, rtk_mac_t macMsk, rtk_vlan_t svid);
+
+/* Function Name:
+ *      rtk_svlan_l2mc2s_del
+ * Description:
+ *      delete L2 multicast address to SVLAN
+ * Input:
+ *      mac     - L2 multicast address
+ *      macMsk  - L2 multicast address mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_SVLAN_VID        - Invalid SVLAN VID parameter.
+ *      RT_ERR_OUT_OF_RANGE     - input out of range.
+ * Note:
+ *      The API can delete Mutlicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast.
+ */
+extern rtk_api_ret_t rtk_svlan_l2mc2s_del(rtk_mac_t mac, rtk_mac_t macMsk);
+
+/* Function Name:
+ *      rtk_svlan_l2mc2s_get
+ * Description:
+ *      Get L2 multicast address to SVLAN
+ * Input:
+ *      mac     - L2 multicast address
+ *      macMsk  - L2 multicast address mask
+ * Output:
+ *      pSvid   - SVLAN VID
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_OUT_OF_RANGE     - input out of range.
+ * Note:
+ *      The API can get L2 mutlicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast.
+ */
+extern rtk_api_ret_t rtk_svlan_l2mc2s_get(rtk_mac_t mac, rtk_mac_t macMsk, rtk_vlan_t *pSvid);
+
+/* Function Name:
+ *      rtk_svlan_sp2c_add
+ * Description:
+ *      Add system SP2C configuration
+ * Input:
+ *      cvid        - VLAN ID
+ *      dst_port    - Destination port of SVLAN to CVLAN configuration
+ *      svid        - SVLAN VID
+ *
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_SVLAN_VID    - Invalid SVLAN VID parameter.
+ *      RT_ERR_VLAN_VID     - Invalid VID parameter.
+ *      RT_ERR_OUT_OF_RANGE - input out of range.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can add SVID & Destination Port to CVLAN configuration. The downstream frames with assigned
+ *      SVID will be add C-tag with assigned CVID if the output port is the assigned destination port.
+ *      There are 128 SP2C configurations.
+ */
+extern rtk_api_ret_t rtk_svlan_sp2c_add(rtk_vlan_t svid, rtk_port_t dst_port, rtk_vlan_t cvid);
+
+/* Function Name:
+ *      rtk_svlan_sp2c_get
+ * Description:
+ *      Get configure system SP2C content
+ * Input:
+ *      svid        - SVLAN VID
+ *      dst_port    - Destination port of SVLAN to CVLAN configuration
+ * Output:
+ *      pCvid - VLAN ID
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_OUT_OF_RANGE - input out of range.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_SVLAN_VID    - Invalid SVLAN VID parameter.
+ * Note:
+ *     The API can get SVID & Destination Port to CVLAN configuration. There are 128 SP2C configurations.
+ */
+extern rtk_api_ret_t rtk_svlan_sp2c_get(rtk_vlan_t svid, rtk_port_t dst_port, rtk_vlan_t *pCvid);
+
+/* Function Name:
+ *      rtk_svlan_sp2c_del
+ * Description:
+ *      Delete system SP2C configuration
+ * Input:
+ *      svid        - SVLAN VID
+ *      dst_port    - Destination port of SVLAN to CVLAN configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_SVLAN_VID    - Invalid SVLAN VID parameter.
+ *      RT_ERR_OUT_OF_RANGE - input out of range.
+ * Note:
+ *      The API can delete SVID & Destination Port to CVLAN configuration. There are 128 SP2C configurations.
+ */
+extern rtk_api_ret_t rtk_svlan_sp2c_del(rtk_vlan_t svid, rtk_port_t dst_port);
+
+
+/* Function Name:
+ *      rtk_svlan_lookupType_set
+ * Description:
+ *      Set lookup type of SVLAN
+ * Input:
+ *      type        - lookup type
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ * Note:
+ *      none
+ */
+extern rtk_api_ret_t rtk_svlan_lookupType_set(rtk_svlan_lookupType_t type);
+
+/* Function Name:
+ *      rtk_svlan_lookupType_get
+ * Description:
+ *      Get lookup type of SVLAN
+ * Input:
+ *      pType       - lookup type
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ * Note:
+ *      none
+ */
+extern rtk_api_ret_t rtk_svlan_lookupType_get(rtk_svlan_lookupType_t *pType);
+
+/* Function Name:
+ *      rtk_svlan_trapPri_set
+ * Description:
+ *      Set svlan trap priority
+ * Input:
+ *      priority - priority for trap packets
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_QOS_INT_PRIORITY
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_svlan_trapPri_set(rtk_pri_t priority);
+
+/* Function Name:
+ *      rtk_svlan_trapPri_get
+ * Description:
+ *      Get svlan trap priority
+ * Input:
+ *      None
+ * Output:
+ *      pPriority - priority for trap packets
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_svlan_trapPri_get(rtk_pri_t *pPriority);
+
+/* Function Name:
+ *      rtk_svlan_unassign_action_set
+ * Description:
+ *      Configure Action of upstream without svid assign action
+ * Input:
+ *      action  - Action for Un-assign
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_OUT_OF_RANGE             - input out of range.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      The API can configure action of upstream Un-assign svid packet. If action is not
+ *      trap to CPU, the port-based SVID sure be assign as system need
+ */
+extern rtk_api_ret_t rtk_svlan_unassign_action_set(rtk_svlan_unassign_action_t action);
+
+/* Function Name:
+ *      rtk_svlan_unassign_action_get
+ * Description:
+ *      Get action of upstream without svid assignment
+ * Input:
+ *      None
+ * Output:
+ *      pAction  - Action for Un-assign
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ * Note:
+ *      None
+ */
+extern rtk_api_ret_t rtk_svlan_unassign_action_get(rtk_svlan_unassign_action_t *pAction);
+
+
+/* Function Name:
+ *      rtk_svlan_checkAndCreateMbr
+ * Description:
+ *      Check and create Member configuration and return index
+ * Input:
+ *      vid  - VLAN id.
+ * Output:
+ *      pIndex  - Member configuration index
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_VLAN_VID     - Invalid VLAN ID.
+ *      RT_ERR_TBL_FULL     - Member Configuration table full
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_svlan_checkAndCreateMbr(rtk_vlan_t vid, rtk_uint32 *pIndex);
+
+
+#endif /* __RTK_API_SVLAN_H__ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/trap.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/trap.h
new file mode 100644
index 0000000..0cdb64a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/trap.h
@@ -0,0 +1,757 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes Trap module high-layer API defination
+ *
+ */
+
+#ifndef __RTK_API_TRAP_H__
+#define __RTK_API_TRAP_H__
+
+
+typedef enum rtk_trap_type_e
+{
+    TRAP_BRG_GROUP = 0,
+    TRAP_FD_PAUSE,
+    TRAP_SP_MCAST,
+    TRAP_1X_PAE,
+    TRAP_UNDEF_BRG_04,
+    TRAP_UNDEF_BRG_05,
+    TRAP_UNDEF_BRG_06,
+    TRAP_UNDEF_BRG_07,
+    TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS,
+    TRAP_UNDEF_BRG_09,
+    TRAP_UNDEF_BRG_0A,
+    TRAP_UNDEF_BRG_0B,
+    TRAP_UNDEF_BRG_0C,
+    TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS,
+    TRAP_8021AB,
+    TRAP_UNDEF_BRG_0F,
+    TRAP_BRG_MNGEMENT,
+    TRAP_UNDEFINED_11,
+    TRAP_UNDEFINED_12,
+    TRAP_UNDEFINED_13,
+    TRAP_UNDEFINED_14,
+    TRAP_UNDEFINED_15,
+    TRAP_UNDEFINED_16,
+    TRAP_UNDEFINED_17,
+    TRAP_UNDEFINED_18,
+    TRAP_UNDEFINED_19,
+    TRAP_UNDEFINED_1A,
+    TRAP_UNDEFINED_1B,
+    TRAP_UNDEFINED_1C,
+    TRAP_UNDEFINED_1D,
+    TRAP_UNDEFINED_1E,
+    TRAP_UNDEFINED_1F,
+    TRAP_GMRP,
+    TRAP_GVRP,
+    TRAP_UNDEF_GARP_22,
+    TRAP_UNDEF_GARP_23,
+    TRAP_UNDEF_GARP_24,
+    TRAP_UNDEF_GARP_25,
+    TRAP_UNDEF_GARP_26,
+    TRAP_UNDEF_GARP_27,
+    TRAP_UNDEF_GARP_28,
+    TRAP_UNDEF_GARP_29,
+    TRAP_UNDEF_GARP_2A,
+    TRAP_UNDEF_GARP_2B,
+    TRAP_UNDEF_GARP_2C,
+    TRAP_UNDEF_GARP_2D,
+    TRAP_UNDEF_GARP_2E,
+    TRAP_UNDEF_GARP_2F,
+    TRAP_CDP,
+    TRAP_CSSTP,
+    TRAP_LLDP,
+    TRAP_END,
+}rtk_trap_type_t;
+
+
+typedef enum rtk_mcast_type_e
+{
+    MCAST_L2 = 0,
+    MCAST_IPV4,
+    MCAST_IPV6,
+    MCAST_END
+} rtk_mcast_type_t;
+
+typedef enum rtk_trap_mcast_action_e
+{
+    MCAST_ACTION_FORWARD = 0,
+    MCAST_ACTION_DROP,
+    MCAST_ACTION_TRAP2CPU,
+    MCAST_ACTION_ROUTER_PORT,
+    MCAST_ACTION_DROP_EX_RMA,
+    MCAST_ACTION_END
+} rtk_trap_mcast_action_t;
+
+typedef enum rtk_trap_rma_action_e
+{
+    RMA_ACTION_FORWARD = 0,
+    RMA_ACTION_TRAP2CPU,
+    RMA_ACTION_DROP,
+    RMA_ACTION_FORWARD_EXCLUDE_CPU,
+    RMA_ACTION_END
+} rtk_trap_rma_action_t;
+
+typedef enum rtk_trap_ucast_action_e
+{
+    UCAST_ACTION_FORWARD_PMASK = 0,
+    UCAST_ACTION_DROP,
+    UCAST_ACTION_TRAP2CPU,
+    UCAST_ACTION_FLOODING,
+    UCAST_ACTION_END
+} rtk_trap_ucast_action_t;
+
+typedef enum rtk_trap_ucast_type_e
+{
+    UCAST_UNKNOWNDA = 0,
+    UCAST_UNKNOWNSA,
+    UCAST_UNMATCHSA,
+    UCAST_END
+} rtk_trap_ucast_type_t;
+
+typedef enum rtk_trap_reason_type_e
+{
+    TRAP_REASON_RMA = 0,
+    TRAP_REASON_OAM,
+    TRAP_REASON_1XUNAUTH,
+    TRAP_REASON_VLANSTACK,
+    TRAP_REASON_UNKNOWNMC,
+    TRAP_REASON_END,
+} rtk_trap_reason_type_t;
+
+
+/* Function Name:
+ *      rtk_trap_unknownUnicastPktAction_set
+ * Description:
+ *      Set unknown unicast packet action configuration.
+ * Input:
+ *      port            - ingress port ID for unknown unicast packet
+ *      ucast_action    - Unknown unicast action.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                  - OK
+ *      RT_ERR_FAILED              - Failed
+ *      RT_ERR_SMI                 - SMI access error
+ *      RT_ERR_NOT_ALLOWED         - Invalid action.
+ *      RT_ERR_INPUT               - Invalid input parameters.
+ * Note:
+ *      This API can set unknown unicast packet action configuration.
+ *      The unknown unicast action is as following:
+ *          - UCAST_ACTION_FORWARD_PMASK
+ *          - UCAST_ACTION_DROP
+ *          - UCAST_ACTION_TRAP2CPU
+ *          - UCAST_ACTION_FLOODING
+ */
+rtk_api_ret_t rtk_trap_unknownUnicastPktAction_set(rtk_port_t port, rtk_trap_ucast_action_t ucast_action);
+
+/* Function Name:
+ *      rtk_trap_unknownUnicastPktAction_get
+ * Description:
+ *      Get unknown unicast packet action configuration.
+ * Input:
+ *      port            - ingress port ID for unknown unicast packet
+ * Output:
+ *      pUcast_action   - Unknown unicast action.
+ * Return:
+ *      RT_ERR_OK                  - OK
+ *      RT_ERR_FAILED              - Failed
+ *      RT_ERR_SMI                 - SMI access error
+ *      RT_ERR_NOT_ALLOWED         - Invalid action.
+ *      RT_ERR_INPUT               - Invalid input parameters.
+ *      RT_ERR_NULL_POINTER        - Null pointer
+ * Note:
+ *      This API can get unknown unicast packet action configuration.
+ *      The unknown unicast action is as following:
+ *          - UCAST_ACTION_FORWARD_PMASK
+ *          - UCAST_ACTION_DROP
+ *          - UCAST_ACTION_TRAP2CPU
+ *          - UCAST_ACTION_FLOODING
+ */
+rtk_api_ret_t rtk_trap_unknownUnicastPktAction_get(rtk_port_t port, rtk_trap_ucast_action_t *pUcast_action);
+
+/* Function Name:
+ *      rtk_trap_unknownMacPktAction_set
+ * Description:
+ *      Set unknown source MAC packet action configuration.
+ * Input:
+ *      ucast_action    - Unknown source MAC action.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                  - OK
+ *      RT_ERR_FAILED              - Failed
+ *      RT_ERR_SMI                 - SMI access error
+ *      RT_ERR_NOT_ALLOWED         - Invalid action.
+ *      RT_ERR_INPUT               - Invalid input parameters.
+ * Note:
+ *      This API can set unknown unicast packet action configuration.
+ *      The unknown unicast action is as following:
+ *          - UCAST_ACTION_FORWARD_PMASK
+ *          - UCAST_ACTION_DROP
+ *          - UCAST_ACTION_TRAP2CPU
+ */
+extern rtk_api_ret_t rtk_trap_unknownMacPktAction_set(rtk_trap_ucast_action_t ucast_action);
+
+/* Function Name:
+ *      rtk_trap_unknownMacPktAction_get
+ * Description:
+ *      Get unknown source MAC packet action configuration.
+ * Input:
+ *      None.
+ * Output:
+ *      pUcast_action   - Unknown source MAC action.
+ * Return:
+ *      RT_ERR_OK                  - OK
+ *      RT_ERR_FAILED              - Failed
+ *      RT_ERR_SMI                 - SMI access error
+ *      RT_ERR_NULL_POINTER        - Null Pointer.
+ *      RT_ERR_INPUT               - Invalid input parameters.
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_trap_unknownMacPktAction_get(rtk_trap_ucast_action_t *pUcast_action);
+
+/* Function Name:
+ *      rtk_trap_unmatchMacPktAction_set
+ * Description:
+ *      Set unmatch source MAC packet action configuration.
+ * Input:
+ *      ucast_action    - Unknown source MAC action.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                  - OK
+ *      RT_ERR_FAILED              - Failed
+ *      RT_ERR_SMI                 - SMI access error
+ *      RT_ERR_NOT_ALLOWED         - Invalid action.
+ *      RT_ERR_INPUT               - Invalid input parameters.
+ * Note:
+ *      This API can set unknown unicast packet action configuration.
+ *      The unknown unicast action is as following:
+ *          - UCAST_ACTION_FORWARD_PMASK
+ *          - UCAST_ACTION_DROP
+ *          - UCAST_ACTION_TRAP2CPU
+ */
+extern rtk_api_ret_t rtk_trap_unmatchMacPktAction_set(rtk_trap_ucast_action_t ucast_action);
+
+/* Function Name:
+ *      rtk_trap_unmatchMacPktAction_get
+ * Description:
+ *      Get unmatch source MAC packet action configuration.
+ * Input:
+ *      None.
+ * Output:
+ *      pUcast_action   - Unknown source MAC action.
+ * Return:
+ *      RT_ERR_OK                  - OK
+ *      RT_ERR_FAILED              - Failed
+ *      RT_ERR_SMI                 - SMI access error
+ *      RT_ERR_NOT_ALLOWED         - Invalid action.
+ *      RT_ERR_INPUT               - Invalid input parameters.
+ * Note:
+ *      This API can set unknown unicast packet action configuration.
+ *      The unknown unicast action is as following:
+ *          - UCAST_ACTION_FORWARD_PMASK
+ *          - UCAST_ACTION_DROP
+ *          - UCAST_ACTION_TRAP2CPU
+ */
+extern rtk_api_ret_t rtk_trap_unmatchMacPktAction_get(rtk_trap_ucast_action_t *pUcast_action);
+
+/* Function Name:
+ *      rtk_trap_unmatchMacMoving_set
+ * Description:
+ *      Set unmatch source MAC packet moving state.
+ * Input:
+ *      port        - Port ID.
+ *      enable      - ENABLED: allow SA moving, DISABLE: don't allow SA moving.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                  - OK
+ *      RT_ERR_FAILED              - Failed
+ *      RT_ERR_SMI                 - SMI access error
+ *      RT_ERR_NOT_ALLOWED         - Invalid action.
+ *      RT_ERR_INPUT               - Invalid input parameters.
+ * Note:
+ */
+extern rtk_api_ret_t rtk_trap_unmatchMacMoving_set(rtk_port_t port, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_trap_unmatchMacMoving_get
+ * Description:
+ *      Set unmatch source MAC packet moving state.
+ * Input:
+ *      port        - Port ID.
+ * Output:
+ *      pEnable     - ENABLED: allow SA moving, DISABLE: don't allow SA moving.
+ * Return:
+ *      RT_ERR_OK                  - OK
+ *      RT_ERR_FAILED              - Failed
+ *      RT_ERR_SMI                 - SMI access error
+ *      RT_ERR_NOT_ALLOWED         - Invalid action.
+ *      RT_ERR_INPUT               - Invalid input parameters.
+ * Note:
+ */
+extern rtk_api_ret_t rtk_trap_unmatchMacMoving_get(rtk_port_t port, rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_trap_unknownMcastPktAction_set
+ * Description:
+ *      Set behavior of unknown multicast
+ * Input:
+ *      port            - Port id.
+ *      type            - unknown multicast packet type.
+ *      mcast_action    - unknown multicast action.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_NOT_ALLOWED  - Invalid action.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      When receives an unknown multicast packet, switch may trap, drop or flood this packet
+ *      (1) The unknown multicast packet type is as following:
+ *          - MCAST_L2
+ *          - MCAST_IPV4
+ *          - MCAST_IPV6
+ *      (2) The unknown multicast action is as following:
+ *          - MCAST_ACTION_FORWARD
+ *          - MCAST_ACTION_DROP
+ *          - MCAST_ACTION_TRAP2CPU
+ */
+extern rtk_api_ret_t rtk_trap_unknownMcastPktAction_set(rtk_port_t port, rtk_mcast_type_t type, rtk_trap_mcast_action_t mcast_action);
+
+/* Function Name:
+ *      rtk_trap_unknownMcastPktAction_get
+ * Description:
+ *      Get behavior of unknown multicast
+ * Input:
+ *      type - unknown multicast packet type.
+ * Output:
+ *      pMcast_action - unknown multicast action.
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_NOT_ALLOWED      - Invalid operation.
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ * Note:
+ *      When receives an unknown multicast packet, switch may trap, drop or flood this packet
+ *      (1) The unknown multicast packet type is as following:
+ *          - MCAST_L2
+ *          - MCAST_IPV4
+ *          - MCAST_IPV6
+ *      (2) The unknown multicast action is as following:
+ *          - MCAST_ACTION_FORWARD
+ *          - MCAST_ACTION_DROP
+ *          - MCAST_ACTION_TRAP2CPU
+ */
+extern rtk_api_ret_t rtk_trap_unknownMcastPktAction_get(rtk_port_t port, rtk_mcast_type_t type, rtk_trap_mcast_action_t *pMcast_action);
+
+/* Function Name:
+ *      rtk_trap_lldpEnable_set
+ * Description:
+ *      Set LLDP enable.
+ * Input:
+ *      enabled - LLDP enable, 0: follow RMA, 1: use LLDP action.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_NOT_ALLOWED      - Invalid action.
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ * Note:
+ *      - DMAC                                                 Assignment
+ *      - 01:80:c2:00:00:0e ethertype = 0x88CC    LLDP
+ *      - 01:80:c2:00:00:03 ethertype = 0x88CC
+ *      - 01:80:c2:00:00:00 ethertype = 0x88CC
+
+ */
+extern rtk_api_ret_t rtk_trap_lldpEnable_set(rtk_enable_t enabled);
+
+/* Function Name:
+ *      rtk_trap_lldpEnable_get
+ * Description:
+ *      Get LLDP status.
+ * Input:
+ *      None
+ * Output:
+ *      pEnabled - LLDP enable, 0: follow RMA, 1: use LLDP action.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      LLDP is as following definition.
+ *      - DMAC                                                 Assignment
+ *      - 01:80:c2:00:00:0e ethertype = 0x88CC    LLDP
+ *      - 01:80:c2:00:00:03 ethertype = 0x88CC
+ *      - 01:80:c2:00:00:00 ethertype = 0x88CC
+ */
+extern rtk_api_ret_t rtk_trap_lldpEnable_get(rtk_enable_t *pEnabled);
+
+/* Function Name:
+ *      rtk_trap_reasonTrapToCpuPriority_set
+ * Description:
+ *      Set priority value of a packet that trapped to CPU port according to specific reason.
+ * Input:
+ *      type     - reason that trap to CPU port.
+ *      priority - internal priority that is going to be set for specific trap reason.
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT - The module is not initial
+ *      RT_ERR_INPUT    - Invalid input parameter
+ * Note:
+ *      Currently the trap reason that supported are listed as follows:
+ *      - TRAP_REASON_RMA
+ *      - TRAP_REASON_OAM
+ *      - TRAP_REASON_1XUNAUTH
+ *      - TRAP_REASON_VLANSTACK
+ *      - TRAP_REASON_UNKNOWNMC
+ */
+extern rtk_api_ret_t rtk_trap_reasonTrapToCpuPriority_set(rtk_trap_reason_type_t type, rtk_pri_t priority);
+
+/* Function Name:
+ *      rtk_trap_reasonTrapToCpuPriority_get
+ * Description:
+ *      Get priority value of a packet that trapped to CPU port according to specific reason.
+ * Input:
+ *      type      - reason that trap to CPU port.
+ * Output:
+ *      pPriority - configured internal priority for such reason.
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT     - The module is not initial
+ *      RT_ERR_INPUT        - Invalid input parameter
+ *      RT_ERR_NULL_POINTER - NULL pointer
+ * Note:
+ *      Currently the trap reason that supported are listed as follows:
+ *      - TRAP_REASON_RMA
+ *      - TRAP_REASON_OAM
+ *      - TRAP_REASON_1XUNAUTH
+ *      - TRAP_REASON_VLANSTACK
+ *      - TRAP_REASON_UNKNOWNMC
+ */
+extern rtk_api_ret_t rtk_trap_reasonTrapToCpuPriority_get(rtk_trap_reason_type_t type, rtk_pri_t *pPriority);
+
+/* Function Name:
+ *      rtk_trap_rmaAction_set
+ * Description:
+ *      Set Reserved multicast address action configuration.
+ * Input:
+ *      type    - rma type.
+ *      rma_action - RMA action.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_ENABLE       - Invalid IFG parameter
+ * Note:
+ *
+ *      There are 48 types of Reserved Multicast Address frame for application usage.
+ *      (1)They are as following definition.
+ *      - TRAP_BRG_GROUP,
+ *      - TRAP_FD_PAUSE,
+ *      - TRAP_SP_MCAST,
+ *      - TRAP_1X_PAE,
+ *      - TRAP_UNDEF_BRG_04,
+ *      - TRAP_UNDEF_BRG_05,
+ *      - TRAP_UNDEF_BRG_06,
+ *      - TRAP_UNDEF_BRG_07,
+ *      - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS,
+ *      - TRAP_UNDEF_BRG_09,
+ *      - TRAP_UNDEF_BRG_0A,
+ *      - TRAP_UNDEF_BRG_0B,
+ *      - TRAP_UNDEF_BRG_0C,
+ *      - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS,
+ *      - TRAP_8021AB,
+ *      - TRAP_UNDEF_BRG_0F,
+ *      - TRAP_BRG_MNGEMENT,
+ *      - TRAP_UNDEFINED_11,
+ *      - TRAP_UNDEFINED_12,
+ *      - TRAP_UNDEFINED_13,
+ *      - TRAP_UNDEFINED_14,
+ *      - TRAP_UNDEFINED_15,
+ *      - TRAP_UNDEFINED_16,
+ *      - TRAP_UNDEFINED_17,
+ *      - TRAP_UNDEFINED_18,
+ *      - TRAP_UNDEFINED_19,
+ *      - TRAP_UNDEFINED_1A,
+ *      - TRAP_UNDEFINED_1B,
+ *      - TRAP_UNDEFINED_1C,
+ *      - TRAP_UNDEFINED_1D,
+ *      - TRAP_UNDEFINED_1E,
+ *      - TRAP_UNDEFINED_1F,
+ *      - TRAP_GMRP,
+ *      - TRAP_GVRP,
+ *      - TRAP_UNDEF_GARP_22,
+ *      - TRAP_UNDEF_GARP_23,
+ *      - TRAP_UNDEF_GARP_24,
+ *      - TRAP_UNDEF_GARP_25,
+ *      - TRAP_UNDEF_GARP_26,
+ *      - TRAP_UNDEF_GARP_27,
+ *      - TRAP_UNDEF_GARP_28,
+ *      - TRAP_UNDEF_GARP_29,
+ *      - TRAP_UNDEF_GARP_2A,
+ *      - TRAP_UNDEF_GARP_2B,
+ *      - TRAP_UNDEF_GARP_2C,
+ *      - TRAP_UNDEF_GARP_2D,
+ *      - TRAP_UNDEF_GARP_2E,
+ *      - TRAP_UNDEF_GARP_2F,
+ *      - TRAP_CDP.
+ *      - TRAP_CSSTP.
+ *      - TRAP_LLDP.
+ *      (2) The RMA action is as following:
+ *      - RMA_ACTION_FORWARD
+ *      - RMA_ACTION_TRAP2CPU
+ *      - RMA_ACTION_DROP
+ *      - RMA_ACTION_FORWARD_EXCLUDE_CPU
+ */
+extern rtk_api_ret_t rtk_trap_rmaAction_set(rtk_trap_type_t type, rtk_trap_rma_action_t rma_action);
+
+/* Function Name:
+ *      rtk_trap_rmaAction_get
+ * Description:
+ *      Get Reserved multicast address action configuration.
+ * Input:
+ *      type - rma type.
+ * Output:
+ *      pRma_action - RMA action.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      There are 48 types of Reserved Multicast Address frame for application usage.
+ *      (1)They are as following definition.
+ *      - TRAP_BRG_GROUP,
+ *      - TRAP_FD_PAUSE,
+ *      - TRAP_SP_MCAST,
+ *      - TRAP_1X_PAE,
+ *      - TRAP_UNDEF_BRG_04,
+ *      - TRAP_UNDEF_BRG_05,
+ *      - TRAP_UNDEF_BRG_06,
+ *      - TRAP_UNDEF_BRG_07,
+ *      - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS,
+ *      - TRAP_UNDEF_BRG_09,
+ *      - TRAP_UNDEF_BRG_0A,
+ *      - TRAP_UNDEF_BRG_0B,
+ *      - TRAP_UNDEF_BRG_0C,
+ *      - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS,
+ *      - TRAP_8021AB,
+ *      - TRAP_UNDEF_BRG_0F,
+ *      - TRAP_BRG_MNGEMENT,
+ *      - TRAP_UNDEFINED_11,
+ *      - TRAP_UNDEFINED_12,
+ *      - TRAP_UNDEFINED_13,
+ *      - TRAP_UNDEFINED_14,
+ *      - TRAP_UNDEFINED_15,
+ *      - TRAP_UNDEFINED_16,
+ *      - TRAP_UNDEFINED_17,
+ *      - TRAP_UNDEFINED_18,
+ *      - TRAP_UNDEFINED_19,
+ *      - TRAP_UNDEFINED_1A,
+ *      - TRAP_UNDEFINED_1B,
+ *      - TRAP_UNDEFINED_1C,
+ *      - TRAP_UNDEFINED_1D,
+ *      - TRAP_UNDEFINED_1E,
+ *      - TRAP_UNDEFINED_1F,
+ *      - TRAP_GMRP,
+ *      - TRAP_GVRP,
+ *      - TRAP_UNDEF_GARP_22,
+ *      - TRAP_UNDEF_GARP_23,
+ *      - TRAP_UNDEF_GARP_24,
+ *      - TRAP_UNDEF_GARP_25,
+ *      - TRAP_UNDEF_GARP_26,
+ *      - TRAP_UNDEF_GARP_27,
+ *      - TRAP_UNDEF_GARP_28,
+ *      - TRAP_UNDEF_GARP_29,
+ *      - TRAP_UNDEF_GARP_2A,
+ *      - TRAP_UNDEF_GARP_2B,
+ *      - TRAP_UNDEF_GARP_2C,
+ *      - TRAP_UNDEF_GARP_2D,
+ *      - TRAP_UNDEF_GARP_2E,
+ *      - TRAP_UNDEF_GARP_2F,
+ *      - TRAP_CDP.
+ *      - TRAP_CSSTP.
+ *      - TRAP_LLDP.
+ *      (2) The RMA action is as following:
+ *      - RMA_ACTION_FORWARD
+ *      - RMA_ACTION_TRAP2CPU
+ *      - RMA_ACTION_DROP
+ *      - RMA_ACTION_FORWARD_EXCLUDE_CPU
+ */
+extern rtk_api_ret_t rtk_trap_rmaAction_get(rtk_trap_type_t type, rtk_trap_rma_action_t *pRma_action);
+
+/* Function Name:
+ *      rtk_trap_rmaKeepFormat_set
+ * Description:
+ *      Set Reserved multicast address keep format configuration.
+ * Input:
+ *      type    - rma type.
+ *      enable - enable keep format.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_ENABLE       - Invalid IFG parameter
+ * Note:
+ *
+ *      There are 48 types of Reserved Multicast Address frame for application usage.
+ *      They are as following definition.
+ *      - TRAP_BRG_GROUP,
+ *      - TRAP_FD_PAUSE,
+ *      - TRAP_SP_MCAST,
+ *      - TRAP_1X_PAE,
+ *      - TRAP_UNDEF_BRG_04,
+ *      - TRAP_UNDEF_BRG_05,
+ *      - TRAP_UNDEF_BRG_06,
+ *      - TRAP_UNDEF_BRG_07,
+ *      - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS,
+ *      - TRAP_UNDEF_BRG_09,
+ *      - TRAP_UNDEF_BRG_0A,
+ *      - TRAP_UNDEF_BRG_0B,
+ *      - TRAP_UNDEF_BRG_0C,
+ *      - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS,
+ *      - TRAP_8021AB,
+ *      - TRAP_UNDEF_BRG_0F,
+ *      - TRAP_BRG_MNGEMENT,
+ *      - TRAP_UNDEFINED_11,
+ *      - TRAP_UNDEFINED_12,
+ *      - TRAP_UNDEFINED_13,
+ *      - TRAP_UNDEFINED_14,
+ *      - TRAP_UNDEFINED_15,
+ *      - TRAP_UNDEFINED_16,
+ *      - TRAP_UNDEFINED_17,
+ *      - TRAP_UNDEFINED_18,
+ *      - TRAP_UNDEFINED_19,
+ *      - TRAP_UNDEFINED_1A,
+ *      - TRAP_UNDEFINED_1B,
+ *      - TRAP_UNDEFINED_1C,
+ *      - TRAP_UNDEFINED_1D,
+ *      - TRAP_UNDEFINED_1E,
+ *      - TRAP_UNDEFINED_1F,
+ *      - TRAP_GMRP,
+ *      - TRAP_GVRP,
+ *      - TRAP_UNDEF_GARP_22,
+ *      - TRAP_UNDEF_GARP_23,
+ *      - TRAP_UNDEF_GARP_24,
+ *      - TRAP_UNDEF_GARP_25,
+ *      - TRAP_UNDEF_GARP_26,
+ *      - TRAP_UNDEF_GARP_27,
+ *      - TRAP_UNDEF_GARP_28,
+ *      - TRAP_UNDEF_GARP_29,
+ *      - TRAP_UNDEF_GARP_2A,
+ *      - TRAP_UNDEF_GARP_2B,
+ *      - TRAP_UNDEF_GARP_2C,
+ *      - TRAP_UNDEF_GARP_2D,
+ *      - TRAP_UNDEF_GARP_2E,
+ *      - TRAP_UNDEF_GARP_2F,
+ *      - TRAP_CDP.
+ *      - TRAP_CSSTP.
+ *      - TRAP_LLDP.
+ */
+extern rtk_api_ret_t rtk_trap_rmaKeepFormat_set(rtk_trap_type_t type, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_trap_rmaKeepFormat_get
+ * Description:
+ *      Get Reserved multicast address action configuration.
+ * Input:
+ *      type - rma type.
+ * Output:
+ *      pEnable - keep format status.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      There are 48 types of Reserved Multicast Address frame for application usage.
+ *      They are as following definition.
+ *      - TRAP_BRG_GROUP,
+ *      - TRAP_FD_PAUSE,
+ *      - TRAP_SP_MCAST,
+ *      - TRAP_1X_PAE,
+ *      - TRAP_UNDEF_BRG_04,
+ *      - TRAP_UNDEF_BRG_05,
+ *      - TRAP_UNDEF_BRG_06,
+ *      - TRAP_UNDEF_BRG_07,
+ *      - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS,
+ *      - TRAP_UNDEF_BRG_09,
+ *      - TRAP_UNDEF_BRG_0A,
+ *      - TRAP_UNDEF_BRG_0B,
+ *      - TRAP_UNDEF_BRG_0C,
+ *      - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS,
+ *      - TRAP_8021AB,
+ *      - TRAP_UNDEF_BRG_0F,
+ *      - TRAP_BRG_MNGEMENT,
+ *      - TRAP_UNDEFINED_11,
+ *      - TRAP_UNDEFINED_12,
+ *      - TRAP_UNDEFINED_13,
+ *      - TRAP_UNDEFINED_14,
+ *      - TRAP_UNDEFINED_15,
+ *      - TRAP_UNDEFINED_16,
+ *      - TRAP_UNDEFINED_17,
+ *      - TRAP_UNDEFINED_18,
+ *      - TRAP_UNDEFINED_19,
+ *      - TRAP_UNDEFINED_1A,
+ *      - TRAP_UNDEFINED_1B,
+ *      - TRAP_UNDEFINED_1C,
+ *      - TRAP_UNDEFINED_1D,
+ *      - TRAP_UNDEFINED_1E,
+ *      - TRAP_UNDEFINED_1F,
+ *      - TRAP_GMRP,
+ *      - TRAP_GVRP,
+ *      - TRAP_UNDEF_GARP_22,
+ *      - TRAP_UNDEF_GARP_23,
+ *      - TRAP_UNDEF_GARP_24,
+ *      - TRAP_UNDEF_GARP_25,
+ *      - TRAP_UNDEF_GARP_26,
+ *      - TRAP_UNDEF_GARP_27,
+ *      - TRAP_UNDEF_GARP_28,
+ *      - TRAP_UNDEF_GARP_29,
+ *      - TRAP_UNDEF_GARP_2A,
+ *      - TRAP_UNDEF_GARP_2B,
+ *      - TRAP_UNDEF_GARP_2C,
+ *      - TRAP_UNDEF_GARP_2D,
+ *      - TRAP_UNDEF_GARP_2E,
+ *      - TRAP_UNDEF_GARP_2F,
+ *      - TRAP_CDP.
+ *      - TRAP_CSSTP.
+ *      - TRAP_LLDP.
+ */
+extern rtk_api_ret_t rtk_trap_rmaKeepFormat_get(rtk_trap_type_t type, rtk_enable_t *pEnable);
+
+
+#endif /* __RTK_API_TRAP_H__ */
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/trunk.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/trunk.h
new file mode 100644
index 0000000..dff6176
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/trunk.h
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes Trunk module high-layer TRUNK defination
+ *
+ */
+
+#ifndef __RTK_API_TRUNK_H__
+#define __RTK_API_TRUNK_H__
+
+/*
+ * Data Type Declaration
+ */
+#define    RTK_TRUNK_DPORT_HASH_MASK     0x40
+#define    RTK_TRUNK_SPORT_HASH_MASK     0x20
+#define    RTK_TRUNK_DIP_HASH_MASK       0x10
+#define    RTK_TRUNK_SIP_HASH_MASK       0x8
+#define    RTK_TRUNK_DMAC_HASH_MASK      0x4
+#define    RTK_TRUNK_SMAC_HASH_MASK      0x2
+#define    RTK_TRUNK_SPA_HASH_MASK       0x1
+
+
+#define RTK_MAX_NUM_OF_TRUNK_HASH_VAL               16
+
+typedef struct  rtk_trunk_hashVal2Port_s
+{
+    rtk_uint8 value[RTK_MAX_NUM_OF_TRUNK_HASH_VAL];
+} rtk_trunk_hashVal2Port_t;
+
+typedef enum rtk_trunk_group_e
+{
+    TRUNK_GROUP0 = 0,
+    TRUNK_GROUP1,
+    TRUNK_GROUP2,
+    TRUNK_GROUP3,
+    TRUNK_GROUP_END
+} rtk_trunk_group_t;
+
+typedef enum rtk_trunk_separateType_e
+{
+    SEPARATE_NONE = 0,
+    SEPARATE_FLOOD,
+    SEPARATE_END
+
+} rtk_trunk_separateType_t;
+
+typedef enum rtk_trunk_mode_e
+{
+    TRUNK_MODE_NORMAL = 0,
+    TRUNK_MODE_DUMB,
+    TRUNK_MODE_END
+} rtk_trunk_mode_t;
+
+/* Function Name:
+ *      rtk_trunk_port_set
+ * Description:
+ *      Set trunking group available port mask
+ * Input:
+ *      trk_gid                 - trunk group id
+ *      pTrunk_member_portmask  - Logic trunking member port mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_LA_TRUNK_ID  - Invalid trunking group
+ *      RT_ERR_PORT_MASK    - Invalid portmask.
+ * Note:
+ *      The API can set port trunking group port mask. Each port trunking group has max 4 ports.
+ *      If enabled port mask has less than 2 ports available setting, then this trunking group function is disabled.
+ */
+extern rtk_api_ret_t rtk_trunk_port_set(rtk_trunk_group_t trk_gid, rtk_portmask_t *pTrunk_member_portmask);
+
+/* Function Name:
+ *      rtk_trunk_port_get
+ * Description:
+ *      Get trunking group available port mask
+ * Input:
+ *      trk_gid - trunk group id
+ * Output:
+ *      pTrunk_member_portmask - Logic trunking member port mask
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_LA_TRUNK_ID  - Invalid trunking group
+ * Note:
+ *      The API can get 2 port trunking group.
+ */
+extern rtk_api_ret_t rtk_trunk_port_get(rtk_trunk_group_t trk_gid, rtk_portmask_t *pTrunk_member_portmask);
+
+/* Function Name:
+ *      rtk_trunk_distributionAlgorithm_set
+ * Description:
+ *      Set port trunking hash select sources
+ * Input:
+ *      trk_gid         - trunk group id
+ *      algo_bitmask    - Bitmask of the distribution algorithm
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_LA_TRUNK_ID  - Invalid trunking group
+ *      RT_ERR_LA_HASHMASK  - Hash algorithm selection error.
+ *      RT_ERR_PORT_MASK    - Invalid portmask.
+ * Note:
+ *      The API can set port trunking hash algorithm sources.
+ *      7 bits mask for link aggregation group0 hash parameter selection {DIP, SIP, DMAC, SMAC, SPA}
+ *      - 0b0000001: SPA
+ *      - 0b0000010: SMAC
+ *      - 0b0000100: DMAC
+ *      - 0b0001000: SIP
+ *      - 0b0010000: DIP
+ *      - 0b0100000: TCP/UDP Source Port
+ *      - 0b1000000: TCP/UDP Destination Port
+ *      Example:
+ *      - 0b0000011: SMAC & SPA
+ *      - Note that it could be an arbitrary combination or independent set
+ */
+extern rtk_api_ret_t rtk_trunk_distributionAlgorithm_set(rtk_trunk_group_t trk_gid, rtk_uint32 algo_bitmask);
+
+/* Function Name:
+ *      rtk_trunk_distributionAlgorithm_get
+ * Description:
+ *      Get port trunking hash select sources
+ * Input:
+ *      trk_gid - trunk group id
+ * Output:
+ *      pAlgo_bitmask -  Bitmask of the distribution algorithm
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_LA_TRUNK_ID  - Invalid trunking group
+ * Note:
+ *      The API can get port trunking hash algorithm sources.
+ */
+extern rtk_api_ret_t rtk_trunk_distributionAlgorithm_get(rtk_trunk_group_t trk_gid, rtk_uint32 *pAlgo_bitmask);
+
+/* Function Name:
+ *      rtk_trunk_trafficSeparate_set
+ * Description:
+ *      Set the traffic separation setting of a trunk group from the specified device.
+ * Input:
+ *      trk_gid      - trunk group id
+ *      separateType     - traffic separation setting
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_UNIT_ID     - invalid unit id
+ *      RT_ERR_LA_TRUNK_ID - invalid trunk ID
+ *      RT_ERR_LA_HASHMASK - invalid hash mask
+ * Note:
+ *      SEPARATE_NONE: disable traffic separation
+ *      SEPARATE_FLOOD: trunk MSB link up port is dedicated to TX flooding (L2 lookup miss) traffic
+ */
+extern rtk_api_ret_t rtk_trunk_trafficSeparate_set(rtk_trunk_group_t trk_gid, rtk_trunk_separateType_t separateType);
+
+/* Function Name:
+ *      rtk_trunk_trafficSeparate_get
+ * Description:
+ *      Get the traffic separation setting of a trunk group from the specified device.
+ * Input:
+ *      trk_gid        - trunk group id
+ * Output:
+ *      pSeparateType   - pointer separated traffic type
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_UNIT_ID      - invalid unit id
+ *      RT_ERR_LA_TRUNK_ID  - invalid trunk ID
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Note:
+ *      SEPARATE_NONE: disable traffic separation
+ *      SEPARATE_FLOOD: trunk MSB link up port is dedicated to TX flooding (L2 lookup miss) traffic
+ */
+extern rtk_api_ret_t rtk_trunk_trafficSeparate_get(rtk_trunk_group_t trk_gid, rtk_trunk_separateType_t *pSeparateType);
+
+
+/* Function Name:
+ *      rtk_trunk_mode_set
+ * Description:
+ *      Set the trunk mode to the specified device.
+ * Input:
+ *      mode - trunk mode
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT   - invalid input parameter
+ * Note:
+ *      The enum of the trunk mode as following
+ *      - TRUNK_MODE_NORMAL
+ *      - TRUNK_MODE_DUMB
+ */
+extern rtk_api_ret_t rtk_trunk_mode_set(rtk_trunk_mode_t mode);
+
+/* Function Name:
+ *      rtk_trunk_mode_get
+ * Description:
+ *      Get the trunk mode from the specified device.
+ * Input:
+ *      None
+ * Output:
+ *      pMode - pointer buffer of trunk mode
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Note:
+ *      The enum of the trunk mode as following
+ *      - TRUNK_MODE_NORMAL
+ *      - TRUNK_MODE_DUMB
+ */
+extern rtk_api_ret_t rtk_trunk_mode_get(rtk_trunk_mode_t *pMode);
+
+/* Function Name:
+ *      rtk_trunk_trafficPause_set
+ * Description:
+ *      Set the traffic pause setting of a trunk group.
+ * Input:
+ *      trk_gid      - trunk group id
+ *      enable       - traffic pause state
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_LA_TRUNK_ID - invalid trunk ID
+ * Note:
+ *      None.
+ */
+extern rtk_api_ret_t rtk_trunk_trafficPause_set(rtk_trunk_group_t trk_gid, rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_trunk_trafficPause_get
+ * Description:
+ *      Get the traffic pause setting of a trunk group.
+ * Input:
+ *      trk_gid        - trunk group id
+ * Output:
+ *      pEnable        - pointer of traffic pause state.
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_LA_TRUNK_ID  - invalid trunk ID
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Note:
+ *      None.
+ */
+extern rtk_api_ret_t rtk_trunk_trafficPause_get(rtk_trunk_group_t trk_gid, rtk_enable_t *pEnable);
+
+/* Function Name:
+ *      rtk_trunk_hashMappingTable_set
+ * Description:
+ *      Set hash value to port array in the trunk group id from the specified device.
+ * Input:
+ *      trk_gid          - trunk group id
+ *      pHash2Port_array - ports associate with the hash value
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_UNIT_ID            - invalid unit id
+ *      RT_ERR_LA_TRUNK_ID        - invalid trunk ID
+ *      RT_ERR_NULL_POINTER       - input parameter may be null pointer
+ *      RT_ERR_LA_TRUNK_NOT_EXIST - the trunk doesn't exist
+ *      RT_ERR_LA_NOT_MEMBER_PORT - the port is not a member port of the trunk
+ *      RT_ERR_LA_CPUPORT         - CPU port can not be aggregated port
+ * Note:
+ *      Trunk group 0 & 1 shares the same hash mapping table.
+ *      Trunk group 2 uses a independent table.
+ */
+extern rtk_api_ret_t rtk_trunk_hashMappingTable_set(rtk_trunk_group_t trk_gid, rtk_trunk_hashVal2Port_t *pHash2Port_array);
+
+/* Function Name:
+ *      rtk_trunk_hashMappingTable_get
+ * Description:
+ *      Get hash value to port array in the trunk group id from the specified device.
+ * Input:
+ *      trk_gid          - trunk group id
+ * Output:
+ *      pHash2Port_array - pointer buffer of ports associate with the hash value
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_UNIT_ID      - invalid unit id
+ *      RT_ERR_LA_TRUNK_ID  - invalid trunk ID
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Note:
+ *      Trunk group 0 & 1 shares the same hash mapping table.
+ *      Trunk group 2 uses a independent table.
+ */
+extern rtk_api_ret_t rtk_trunk_hashMappingTable_get(rtk_trunk_group_t trk_gid, rtk_trunk_hashVal2Port_t *pHash2Port_array);
+
+/* Function Name:
+ *      rtk_trunk_portQueueEmpty_get
+ * Description:
+ *      Get the port mask which all queues are empty.
+ * Input:
+ *      None.
+ * Output:
+ *      pEmpty_portmask   - pointer empty port mask
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Note:
+ *      None.
+ */
+extern rtk_api_ret_t rtk_trunk_portQueueEmpty_get(rtk_portmask_t *pEmpty_portmask);
+
+#endif /* __RTK_API_TRUNK_H__ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/vlan.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/vlan.h
new file mode 100644
index 0000000..8569fc0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/include/vlan.h
@@ -0,0 +1,892 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367/RTL8367C switch high-level API
+ *
+ * Feature : The file includes Trap module high-layer VLAN defination
+ *
+ */
+
+#ifndef __RTK_API_VLAN_H__
+#define __RTK_API_VLAN_H__
+
+
+/*
+ * Data Type Declaration
+ */
+#define RTK_MAX_NUM_OF_PROTO_TYPE                   0xFFFF
+#define RTK_MAX_NUM_OF_MSTI                         0xF
+#define RTK_FID_MAX                                 0xF
+
+typedef struct  rtk_vlan_cfg_s
+{
+    rtk_portmask_t  mbr;
+    rtk_portmask_t  untag;
+    rtk_uint16      ivl_en;
+    rtk_uint16      fid_msti;
+    rtk_uint16      envlanpol;
+    rtk_uint16      meteridx;
+    rtk_uint16      vbpen;
+    rtk_uint16      vbpri;
+}rtk_vlan_cfg_t;
+
+typedef struct  rtk_vlan_mbrcfg_s
+{
+    rtk_uint16      evid;
+    rtk_portmask_t  mbr;
+    rtk_uint16      fid_msti;
+    rtk_uint16      envlanpol;
+    rtk_uint16      meteridx;
+    rtk_uint16      vbpen;
+    rtk_uint16      vbpri;
+}rtk_vlan_mbrcfg_t;
+
+typedef rtk_uint32  rtk_stp_msti_id_t;     /* MSTI ID  */
+
+typedef enum rtk_stp_state_e
+{
+    STP_STATE_DISABLED = 0,
+    STP_STATE_BLOCKING,
+    STP_STATE_LEARNING,
+    STP_STATE_FORWARDING,
+    STP_STATE_END
+} rtk_stp_state_t;
+
+typedef rtk_uint32  rtk_vlan_proto_type_t;     /* protocol and port based VLAN protocol type  */
+
+
+typedef enum rtk_vlan_acceptFrameType_e
+{
+    ACCEPT_FRAME_TYPE_ALL = 0,             /* untagged, priority-tagged and tagged */
+    ACCEPT_FRAME_TYPE_TAG_ONLY,         /* tagged */
+    ACCEPT_FRAME_TYPE_UNTAG_ONLY,     /* untagged and priority-tagged */
+    ACCEPT_FRAME_TYPE_END
+} rtk_vlan_acceptFrameType_t;
+
+
+/* frame type of protocol vlan - reference 802.1v standard */
+typedef enum rtk_vlan_protoVlan_frameType_e
+{
+    FRAME_TYPE_ETHERNET = 0,
+    FRAME_TYPE_LLCOTHER,
+    FRAME_TYPE_RFC1042,
+    FRAME_TYPE_END
+} rtk_vlan_protoVlan_frameType_t;
+
+/* Protocol-and-port-based Vlan structure */
+typedef struct rtk_vlan_protoAndPortInfo_s
+{
+    rtk_uint32                         proto_type;
+    rtk_vlan_protoVlan_frameType_t frame_type;
+    rtk_vlan_t                     cvid;
+    rtk_pri_t                     cpri;
+}rtk_vlan_protoAndPortInfo_t;
+
+/* tagged mode of VLAN - reference realtek private specification */
+typedef enum rtk_vlan_tagMode_e
+{
+    VLAN_TAG_MODE_ORIGINAL = 0,
+    VLAN_TAG_MODE_KEEP_FORMAT,
+    VLAN_TAG_MODE_PRI,
+    VLAN_TAG_MODE_REAL_KEEP_FORMAT,
+    VLAN_TAG_MODE_END
+} rtk_vlan_tagMode_t;
+
+typedef enum rtk_vlan_resVidAction_e
+{
+    RESVID_ACTION_UNTAG = 0,
+    RESVID_ACTION_TAG,
+    RESVID_ACTION_END
+}
+rtk_vlan_resVidAction_t;
+
+/* Function Name:
+ *      rtk_vlan_init
+ * Description:
+ *      Initialize VLAN.
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      VLAN is disabled by default. User has to call this API to enable VLAN before
+ *      using it. And It will set a default VLAN(vid 1) including all ports and set
+ *      all ports PVID to the default VLAN.
+ */
+extern rtk_api_ret_t rtk_vlan_init(void);
+
+/* Function Name:
+ *      rtk_vlan_set
+ * Description:
+ *      Set a VLAN entry.
+ * Input:
+ *      vid - VLAN ID to configure.
+ *      pVlanCfg - VLAN Configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ *      RT_ERR_L2_FID               - Invalid FID.
+ *      RT_ERR_VLAN_PORT_MBR_EXIST  - Invalid member port mask.
+ *      RT_ERR_VLAN_VID             - Invalid VID parameter.
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_vlan_set(rtk_vlan_t vid, rtk_vlan_cfg_t *pVlanCfg);
+
+/* Function Name:
+ *      rtk_vlan_get
+ * Description:
+ *      Get a VLAN entry.
+ * Input:
+ *      vid - VLAN ID to configure.
+ * Output:
+ *      pVlanCfg - VLAN Configuration
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_VLAN_VID     - Invalid VID parameter.
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_vlan_get(rtk_vlan_t vid, rtk_vlan_cfg_t *pVlanCfg);
+
+/* Function Name:
+ *      rtk_vlan_egrFilterEnable_set
+ * Description:
+ *      Set VLAN egress filter.
+ * Input:
+ *      egrFilter - Egress filtering
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_ENABLE       - Invalid input parameters.
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_vlan_egrFilterEnable_set(rtk_enable_t egrFilter);
+
+/* Function Name:
+ *      rtk_vlan_egrFilterEnable_get
+ * Description:
+ *      Get VLAN egress filter.
+ * Input:
+ *      pEgrFilter - Egress filtering
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_NULL_POINTER - NULL Pointer.
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_vlan_egrFilterEnable_get(rtk_enable_t *pEgrFilter);
+
+/* Function Name:
+ *      rtk_vlan_mbrCfg_set
+ * Description:
+ *      Set a VLAN Member Configuration entry by index.
+ * Input:
+ *      idx     - Index of VLAN Member Configuration.
+ *      pMbrcfg - VLAN member Configuration.
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_VLAN_VID     - Invalid VID parameter.
+ * Note:
+ *     Set a VLAN Member Configuration entry by index.
+ */
+extern rtk_api_ret_t rtk_vlan_mbrCfg_set(rtk_uint32 idx, rtk_vlan_mbrcfg_t *pMbrcfg);
+
+/* Function Name:
+ *      rtk_vlan_mbrCfg_get
+ * Description:
+ *      Get a VLAN Member Configuration entry by index.
+ * Input:
+ *      idx - Index of VLAN Member Configuration.
+ * Output:
+ *      pMbrcfg - VLAN member Configuration.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_VLAN_VID     - Invalid VID parameter.
+ * Note:
+ *     Get a VLAN Member Configuration entry by index.
+ */
+extern rtk_api_ret_t rtk_vlan_mbrCfg_get(rtk_uint32 idx, rtk_vlan_mbrcfg_t *pMbrcfg);
+
+/* Function Name:
+ *     rtk_vlan_portPvid_set
+ * Description:
+ *      Set port to specified VLAN ID(PVID).
+ * Input:
+ *      port - Port id.
+ *      pvid - Specified VLAN ID.
+ *      priority - 802.1p priority for the PVID.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number.
+ *      RT_ERR_VLAN_PRIORITY        - Invalid priority.
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND - VLAN entry not found.
+ *      RT_ERR_VLAN_VID             - Invalid VID parameter.
+ * Note:
+ *       The API is used for Port-based VLAN. The untagged frame received from the
+ *       port will be classified to the specified VLAN and assigned to the specified priority.
+ */
+extern rtk_api_ret_t rtk_vlan_portPvid_set(rtk_port_t port, rtk_vlan_t pvid, rtk_pri_t priority);
+
+/* Function Name:
+ *      rtk_vlan_portPvid_get
+ * Description:
+ *      Get VLAN ID(PVID) on specified port.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pPvid - Specified VLAN ID.
+ *      pPriority - 802.1p priority for the PVID.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *     The API can get the PVID and 802.1p priority for the PVID of Port-based VLAN.
+ */
+extern rtk_api_ret_t rtk_vlan_portPvid_get(rtk_port_t port, rtk_vlan_t *pPvid, rtk_pri_t *pPriority);
+
+/* Function Name:
+ *      rtk_vlan_portIgrFilterEnable_set
+ * Description:
+ *      Set VLAN ingress for each port.
+ * Input:
+ *      port - Port id.
+ *      igr_filter - VLAN ingress function enable status.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_ENABLE       - Invalid enable input
+ * Note:
+ *      The status of vlan ingress filter is as following:
+ *      - DISABLED
+ *      - ENABLED
+ *      While VLAN function is enabled, ASIC will decide VLAN ID for each received frame and get belonged member
+ *      ports from VLAN table. If received port is not belonged to VLAN member ports, ASIC will drop received frame if VLAN ingress function is enabled.
+ */
+extern rtk_api_ret_t rtk_vlan_portIgrFilterEnable_set(rtk_port_t port, rtk_enable_t igr_filter);
+
+/* Function Name:
+ *      rtk_vlan_portIgrFilterEnable_get
+ * Description:
+ *      Get VLAN Ingress Filter
+ * Input:
+ *      port        - Port id.
+ * Output:
+ *      pIgr_filter - VLAN ingress function enable status.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *     The API can Get the VLAN ingress filter status.
+ *     The status of vlan ingress filter is as following:
+ *     - DISABLED
+ *     - ENABLED
+ */
+extern rtk_api_ret_t rtk_vlan_portIgrFilterEnable_get(rtk_port_t port, rtk_enable_t *pIgr_filter);
+
+/* Function Name:
+ *      rtk_vlan_portAcceptFrameType_set
+ * Description:
+ *      Set VLAN accept_frame_type
+ * Input:
+ *      port                - Port id.
+ *      accept_frame_type   - accept frame type
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_PORT_ID                  - Invalid port number.
+ *      RT_ERR_VLAN_ACCEPT_FRAME_TYPE   - Invalid frame type.
+ * Note:
+ *      The API is used for checking 802.1Q tagged frames.
+ *      The accept frame type as following:
+ *      - ACCEPT_FRAME_TYPE_ALL
+ *      - ACCEPT_FRAME_TYPE_TAG_ONLY
+ *      - ACCEPT_FRAME_TYPE_UNTAG_ONLY
+ */
+extern rtk_api_ret_t rtk_vlan_portAcceptFrameType_set(rtk_port_t port, rtk_vlan_acceptFrameType_t accept_frame_type);
+
+/* Function Name:
+ *      rtk_vlan_portAcceptFrameType_get
+ * Description:
+ *      Get VLAN accept_frame_type
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pAccept_frame_type - accept frame type
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *     The API can Get the VLAN ingress filter.
+ *     The accept frame type as following:
+ *     - ACCEPT_FRAME_TYPE_ALL
+ *     - ACCEPT_FRAME_TYPE_TAG_ONLY
+ *     - ACCEPT_FRAME_TYPE_UNTAG_ONLY
+ */
+extern rtk_api_ret_t rtk_vlan_portAcceptFrameType_get(rtk_port_t port, rtk_vlan_acceptFrameType_t *pAccept_frame_type);
+
+/* Function Name:
+ *      rtk_vlan_tagMode_set
+ * Description:
+ *      Set CVLAN egress tag mode
+ * Input:
+ *      port        - Port id.
+ *      tag_mode    - The egress tag mode.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ *      RT_ERR_ENABLE       - Invalid enable input.
+ * Note:
+ *      The API can set Egress tag mode. There are 4 mode for egress tag:
+ *      - VLAN_TAG_MODE_ORIGINAL,
+ *      - VLAN_TAG_MODE_KEEP_FORMAT,
+ *      - VLAN_TAG_MODE_PRI.
+ *      - VLAN_TAG_MODE_REAL_KEEP_FORMAT,
+ */
+extern rtk_api_ret_t rtk_vlan_tagMode_set(rtk_port_t port, rtk_vlan_tagMode_t tag_mode);
+
+/* Function Name:
+ *      rtk_vlan_tagMode_get
+ * Description:
+ *      Get CVLAN egress tag mode
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pTag_mode - The egress tag mode.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get Egress tag mode. There are 4 mode for egress tag:
+ *      - VLAN_TAG_MODE_ORIGINAL,
+ *      - VLAN_TAG_MODE_KEEP_FORMAT,
+ *      - VLAN_TAG_MODE_PRI.
+ *      - VLAN_TAG_MODE_REAL_KEEP_FORMAT,
+ */
+extern rtk_api_ret_t rtk_vlan_tagMode_get(rtk_port_t port, rtk_vlan_tagMode_t *pTag_mode);
+
+/* Function Name:
+ *      rtk_vlan_transparent_set
+ * Description:
+ *      Set VLAN transparent mode
+ * Input:
+ *      egr_port        - Egress Port id.
+ *      pIgr_pmask      - Ingress Port Mask.
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      None.
+ */
+extern rtk_api_ret_t rtk_vlan_transparent_set(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask);
+
+/* Function Name:
+ *      rtk_vlan_transparent_get
+ * Description:
+ *      Get VLAN transparent mode
+ * Input:
+ *      egr_port        - Egress Port id.
+ * Output:
+ *      pIgr_pmask      - Ingress Port Mask
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      None.
+ */
+extern rtk_api_ret_t rtk_vlan_transparent_get(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask);
+
+/* Function Name:
+ *      rtk_vlan_keep_set
+ * Description:
+ *      Set VLAN egress keep mode
+ * Input:
+ *      egr_port        - Egress Port id.
+ *      pIgr_pmask      - Ingress Port Mask.
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      None.
+ */
+extern rtk_api_ret_t rtk_vlan_keep_set(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask);
+
+/* Function Name:
+ *      rtk_vlan_keep_get
+ * Description:
+ *      Get VLAN egress keep mode
+ * Input:
+ *      egr_port        - Egress Port id.
+ * Output:
+ *      pIgr_pmask      - Ingress Port Mask
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      None.
+ */
+extern rtk_api_ret_t rtk_vlan_keep_get(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask);
+
+/* Function Name:
+ *      rtk_vlan_stg_set
+ * Description:
+ *      Set spanning tree group instance of the vlan to the specified device
+ * Input:
+ *      vid - Specified VLAN ID.
+ *      stg - spanning tree group instance.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_MSTI         - Invalid msti parameter
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ *      RT_ERR_VLAN_VID     - Invalid VID parameter.
+ * Note:
+ *      The API can set spanning tree group instance of the vlan to the specified device.
+ */
+extern rtk_api_ret_t rtk_vlan_stg_set(rtk_vlan_t vid, rtk_stp_msti_id_t stg);
+
+/* Function Name:
+ *      rtk_vlan_stg_get
+ * Description:
+ *      Get spanning tree group instance of the vlan to the specified device
+ * Input:
+ *      vid - Specified VLAN ID.
+ * Output:
+ *      pStg - spanning tree group instance.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_VLAN_VID     - Invalid VID parameter.
+ * Note:
+ *      The API can get spanning tree group instance of the vlan to the specified device.
+ */
+extern rtk_api_ret_t rtk_vlan_stg_get(rtk_vlan_t vid, rtk_stp_msti_id_t *pStg);
+
+/* Function Name:
+ *      rtk_vlan_protoAndPortBasedVlan_add
+ * Description:
+ *      Add the protocol-and-port-based vlan to the specified port of device.
+ * Input:
+ *      port  - Port id.
+ *      pInfo - Protocol and port based VLAN configuration information.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_VLAN_VID         - Invalid VID parameter.
+ *      RT_ERR_VLAN_PRIORITY    - Invalid priority.
+ *      RT_ERR_TBL_FULL         - Table is full.
+ *      RT_ERR_OUT_OF_RANGE     - input out of range.
+ * Note:
+ *      The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline
+ *      The frame type is shown in the following:
+ *      - FRAME_TYPE_ETHERNET
+ *      - FRAME_TYPE_RFC1042
+ *      - FRAME_TYPE_LLCOTHER
+ */
+extern rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_add(rtk_port_t port, rtk_vlan_protoAndPortInfo_t *pInfo);
+
+/* Function Name:
+ *      rtk_vlan_protoAndPortBasedVlan_get
+ * Description:
+ *      Get the protocol-and-port-based vlan to the specified port of device.
+ * Input:
+ *      port - Port id.
+ *      proto_type - protocol-and-port-based vlan protocol type.
+ *      frame_type - protocol-and-port-based vlan frame type.
+ * Output:
+ *      pInfo - Protocol and port based VLAN configuration information.
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_OUT_OF_RANGE     - input out of range.
+ *      RT_ERR_TBL_FULL         - Table is full.
+ * Note:
+ *     The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline
+ *     The frame type is shown in the following:
+ *      - FRAME_TYPE_ETHERNET
+ *      - FRAME_TYPE_RFC1042
+ *      - FRAME_TYPE_LLCOTHER
+ */
+extern rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_get(rtk_port_t port, rtk_vlan_proto_type_t proto_type, rtk_vlan_protoVlan_frameType_t frame_type, rtk_vlan_protoAndPortInfo_t *pInfo);
+
+/* Function Name:
+ *      rtk_vlan_protoAndPortBasedVlan_del
+ * Description:
+ *      Delete the protocol-and-port-based vlan from the specified port of device.
+ * Input:
+ *      port        - Port id.
+ *      proto_type  - protocol-and-port-based vlan protocol type.
+ *      frame_type  - protocol-and-port-based vlan frame type.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_OUT_OF_RANGE     - input out of range.
+ *      RT_ERR_TBL_FULL         - Table is full.
+ * Note:
+ *     The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline
+ *     The frame type is shown in the following:
+ *      - FRAME_TYPE_ETHERNET
+ *      - FRAME_TYPE_RFC1042
+ *      - FRAME_TYPE_LLCOTHER
+ */
+extern rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_del(rtk_port_t port, rtk_vlan_proto_type_t proto_type, rtk_vlan_protoVlan_frameType_t frame_type);
+
+/* Function Name:
+ *      rtk_vlan_protoAndPortBasedVlan_delAll
+ * Description:
+ *     Delete all protocol-and-port-based vlans from the specified port of device.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_OUT_OF_RANGE     - input out of range.
+ * Note:
+ *     The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline
+ *     Delete all flow table protocol-and-port-based vlan entries.
+ */
+extern rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_delAll(rtk_port_t port);
+
+/* Function Name:
+ *      rtk_vlan_portFid_set
+ * Description:
+ *      Set port-based filtering database
+ * Input:
+ *      port - Port id.
+ *      enable - ebable port-based FID
+ *      fid - Specified filtering database.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_L2_FID - Invalid fid.
+ *      RT_ERR_INPUT - Invalid input parameter.
+ *      RT_ERR_PORT_ID - Invalid port ID.
+ * Note:
+ *      The API can set port-based filtering database. If the function is enabled, all input
+ *      packets will be assigned to the port-based fid regardless vlan tag.
+ */
+extern rtk_api_ret_t rtk_vlan_portFid_set(rtk_port_t port, rtk_enable_t enable, rtk_fid_t fid);
+
+/* Function Name:
+ *      rtk_vlan_portFid_get
+ * Description:
+ *      Get port-based filtering database
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEnable - ebable port-based FID
+ *      pFid - Specified filtering database.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT - Invalid input parameters.
+ *      RT_ERR_PORT_ID - Invalid port ID.
+ * Note:
+ *      The API can get port-based filtering database status. If the function is enabled, all input
+ *      packets will be assigned to the port-based fid regardless vlan tag.
+ */
+extern rtk_api_ret_t rtk_vlan_portFid_get(rtk_port_t port, rtk_enable_t *pEnable, rtk_fid_t *pFid);
+
+/* Function Name:
+ *      rtk_vlan_UntagDscpPriorityEnable_set
+ * Description:
+ *      Set Untag DSCP priority assign
+ * Input:
+ *      enable - state of Untag DSCP priority assign
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_ENABLE          - Invalid input parameters.
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_vlan_UntagDscpPriorityEnable_set(rtk_enable_t enable);
+
+/* Function Name:
+ *      rtk_vlan_UntagDscpPriorityEnable_get
+ * Description:
+ *      Get Untag DSCP priority assign
+ * Input:
+ *      None
+ * Output:
+ *      pEnable - state of Untag DSCP priority assign
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_vlan_UntagDscpPriorityEnable_get(rtk_enable_t *pEnable);
+
+
+/*Spanning Tree*/
+/* Function Name:
+ *      rtk_stp_mstpState_set
+ * Description:
+ *      Configure spanning tree state per each port.
+ * Input:
+ *      port - Port id
+ *      msti - Multiple spanning tree instance.
+ *      stp_state - Spanning tree state for msti
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_MSTI         - Invalid msti parameter.
+ *      RT_ERR_MSTP_STATE   - Invalid STP state.
+ * Note:
+ *      System supports per-port multiple spanning tree state for each msti.
+ *      There are four states supported by ASIC.
+ *      - STP_STATE_DISABLED
+ *      - STP_STATE_BLOCKING
+ *      - STP_STATE_LEARNING
+ *      - STP_STATE_FORWARDING
+ */
+extern rtk_api_ret_t rtk_stp_mstpState_set(rtk_stp_msti_id_t msti, rtk_port_t port, rtk_stp_state_t stp_state);
+
+/* Function Name:
+ *      rtk_stp_mstpState_get
+ * Description:
+ *      Get spanning tree state per each port.
+ * Input:
+ *      port - Port id.
+ *      msti - Multiple spanning tree instance.
+ * Output:
+ *      pStp_state - Spanning tree state for msti
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_MSTI         - Invalid msti parameter.
+ * Note:
+ *      System supports per-port multiple spanning tree state for each msti.
+ *      There are four states supported by ASIC.
+ *      - STP_STATE_DISABLED
+ *      - STP_STATE_BLOCKING
+ *      - STP_STATE_LEARNING
+ *      - STP_STATE_FORWARDING
+ */
+extern rtk_api_ret_t rtk_stp_mstpState_get(rtk_stp_msti_id_t msti, rtk_port_t port, rtk_stp_state_t *pStp_state);
+
+/* Function Name:
+ *      rtk_vlan_checkAndCreateMbr
+ * Description:
+ *      Check and create Member configuration and return index
+ * Input:
+ *      vid  - VLAN id.
+ * Output:
+ *      pIndex  - Member configuration index
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_VLAN_VID     - Invalid VLAN ID.
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND - VLAN not found
+ *      RT_ERR_TBL_FULL     - Member Configuration table full
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_vlan_checkAndCreateMbr(rtk_vlan_t vid, rtk_uint32 *pIndex);
+
+/* Function Name:
+ *      rtk_vlan_reservedVidAction_set
+ * Description:
+ *      Set Action of VLAN ID = 0 & 4095 tagged packet
+ * Input:
+ *      action_vid0     - Action for VID 0.
+ *      action_vid4095  - Action for VID 4095.
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Error Input
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_vlan_reservedVidAction_set(rtk_vlan_resVidAction_t action_vid0, rtk_vlan_resVidAction_t action_vid4095);
+
+/* Function Name:
+ *      rtk_vlan_reservedVidAction_get
+ * Description:
+ *      Get Action of VLAN ID = 0 & 4095 tagged packet
+ * Input:
+ *      pAction_vid0     - Action for VID 0.
+ *      pAction_vid4095  - Action for VID 4095.
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_NULL_POINTER - NULL Pointer
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_vlan_reservedVidAction_get(rtk_vlan_resVidAction_t *pAction_vid0, rtk_vlan_resVidAction_t *pAction_vid4095);
+
+/* Function Name:
+ *      rtk_vlan_realKeepRemarkEnable_set
+ * Description:
+ *      Set Real keep 1p remarking feature
+ * Input:
+ *      enabled     - State of 1p remarking at real keep packet
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Error Input
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_vlan_realKeepRemarkEnable_set(rtk_enable_t enabled);
+
+/* Function Name:
+ *      rtk_vlan_realKeepRemarkEnable_get
+ * Description:
+ *      Get Real keep 1p remarking feature
+ * Input:
+ *      None.
+ * Output:
+ *      pEnabled     - State of 1p remarking at real keep packet
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Error Input
+ * Note:
+ *
+ */
+extern rtk_api_ret_t rtk_vlan_realKeepRemarkEnable_get(rtk_enable_t *pEnabled);
+
+/* Function Name:
+ *      rtk_vlan_reset
+ * Description:
+ *      Reset VLAN
+ * Input:
+ *      None.
+ * Output:
+ *      pEnabled     - State of 1p remarking at real keep packet
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Error Input
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_vlan_reset(void);
+
+#endif /* __RTK_API_VLAN_H__ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/interrupt.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/interrupt.c
new file mode 100644
index 0000000..165ee41
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/interrupt.c
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in Interrupt module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <interrupt.h>
+#include <string.h>
+
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_interrupt.h>
+
+/* Function Name:
+ *      rtk_int_polarity_set
+ * Description:
+ *      Set interrupt polarity configuration.
+ * Input:
+ *      type - Interruptpolarity type.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can set interrupt polarity configuration.
+ */
+rtk_api_ret_t rtk_int_polarity_set(rtk_int_polarity_t type)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(type >= INT_POLAR_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicInterruptPolarity(type)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_int_polarity_get
+ * Description:
+ *      Get interrupt polarity configuration.
+ * Input:
+ *      None
+ * Output:
+ *      pType - Interruptpolarity type.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      The API can get interrupt polarity configuration.
+ */
+rtk_api_ret_t rtk_int_polarity_get(rtk_int_polarity_t *pType)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pType)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicInterruptPolarity(pType)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_int_control_set
+ * Description:
+ *      Set interrupt trigger status configuration.
+ * Input:
+ *      type - Interrupt type.
+ *      enable - Interrupt status.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_ENABLE       - Invalid enable input.
+ * Note:
+ *      The API can set interrupt status configuration.
+ *      The interrupt trigger status is shown in the following:
+ *      - INT_TYPE_LINK_STATUS
+ *      - INT_TYPE_METER_EXCEED
+ *      - INT_TYPE_LEARN_LIMIT
+ *      - INT_TYPE_LINK_SPEED
+ *      - INT_TYPE_CONGEST
+ *      - INT_TYPE_GREEN_FEATURE
+ *      - INT_TYPE_LOOP_DETECT
+ *      - INT_TYPE_8051,
+ *      - INT_TYPE_CABLE_DIAG,
+ *      - INT_TYPE_ACL,
+ *      - INT_TYPE_SLIENT
+ */
+rtk_api_ret_t rtk_int_control_set(rtk_int_type_t type, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 mask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (type >= INT_TYPE_END)
+        return RT_ERR_INPUT;
+
+    if (type == INT_TYPE_RESERVED)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_getAsicInterruptMask(&mask)) != RT_ERR_OK)
+        return retVal;
+
+    if (ENABLED == enable)
+        mask = mask | (1<<type);
+    else if (DISABLED == enable)
+        mask = mask & ~(1<<type);
+    else
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicInterruptMask(mask)) != RT_ERR_OK)
+        return retVal;
+
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_int_control_get
+ * Description:
+ *      Get interrupt trigger status configuration.
+ * Input:
+ *      type - Interrupt type.
+ * Output:
+ *      pEnable - Interrupt status.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get interrupt status configuration.
+ *      The interrupt trigger status is shown in the following:
+ *      - INT_TYPE_LINK_STATUS
+ *      - INT_TYPE_METER_EXCEED
+ *      - INT_TYPE_LEARN_LIMIT
+ *      - INT_TYPE_LINK_SPEED
+ *      - INT_TYPE_CONGEST
+ *      - INT_TYPE_GREEN_FEATURE
+ *      - INT_TYPE_LOOP_DETECT
+ *      - INT_TYPE_8051,
+ *      - INT_TYPE_CABLE_DIAG,
+ *      - INT_TYPE_ACL,
+ *      - INT_TYPE_UPS,
+ *      - INT_TYPE_SLIENT
+ */
+rtk_api_ret_t rtk_int_control_get(rtk_int_type_t type, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 mask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicInterruptMask(&mask)) != RT_ERR_OK)
+        return retVal;
+
+    if (0 == (mask&(1<<type)))
+        *pEnable=DISABLED;
+    else
+        *pEnable=ENABLED;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_int_status_set
+ * Description:
+ *      Set interrupt trigger status to clean.
+ * Input:
+ *      None
+ * Output:
+ *      pStatusMask - Interrupt status bit mask.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT - Invalid input parameters.
+ * Note:
+ *      The API can clean interrupt trigger status when interrupt happened.
+ *      The interrupt trigger status is shown in the following:
+ *      - INT_TYPE_LINK_STATUS    (value[0] (Bit0))
+ *      - INT_TYPE_METER_EXCEED   (value[0] (Bit1))
+ *      - INT_TYPE_LEARN_LIMIT    (value[0] (Bit2))
+ *      - INT_TYPE_LINK_SPEED     (value[0] (Bit3))
+ *      - INT_TYPE_CONGEST        (value[0] (Bit4))
+ *      - INT_TYPE_GREEN_FEATURE  (value[0] (Bit5))
+ *      - INT_TYPE_LOOP_DETECT    (value[0] (Bit6))
+ *      - INT_TYPE_8051           (value[0] (Bit7))
+ *      - INT_TYPE_CABLE_DIAG     (value[0] (Bit8))
+ *      - INT_TYPE_ACL            (value[0] (Bit9))
+ *      - INT_TYPE_SLIENT         (value[0] (Bit11))
+ *      The status will be cleared after execute this API.
+ */
+rtk_api_ret_t rtk_int_status_set(rtk_int_status_t *pStatusMask)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pStatusMask)
+        return RT_ERR_NULL_POINTER;
+
+    if(pStatusMask->value[0] & (0x0001 << INT_TYPE_RESERVED))
+        return RT_ERR_INPUT;
+
+    if(pStatusMask->value[0] >= (0x0001 << INT_TYPE_END))
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicInterruptStatus((rtk_uint32)pStatusMask->value[0]))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_int_status_get
+ * Description:
+ *      Get interrupt trigger status.
+ * Input:
+ *      None
+ * Output:
+ *      pStatusMask - Interrupt status bit mask.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get interrupt trigger status when interrupt happened.
+ *      The interrupt trigger status is shown in the following:
+ *      - INT_TYPE_LINK_STATUS    (value[0] (Bit0))
+ *      - INT_TYPE_METER_EXCEED   (value[0] (Bit1))
+ *      - INT_TYPE_LEARN_LIMIT    (value[0] (Bit2))
+ *      - INT_TYPE_LINK_SPEED     (value[0] (Bit3))
+ *      - INT_TYPE_CONGEST        (value[0] (Bit4))
+ *      - INT_TYPE_GREEN_FEATURE  (value[0] (Bit5))
+ *      - INT_TYPE_LOOP_DETECT    (value[0] (Bit6))
+ *      - INT_TYPE_8051           (value[0] (Bit7))
+ *      - INT_TYPE_CABLE_DIAG     (value[0] (Bit8))
+ *      - INT_TYPE_ACL            (value[0] (Bit9))
+ *      - INT_TYPE_SLIENT         (value[0] (Bit11))
+ *
+ */
+rtk_api_ret_t rtk_int_status_get(rtk_int_status_t* pStatusMask)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32          ims_mask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pStatusMask)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicInterruptStatus(&ims_mask)) != RT_ERR_OK)
+        return retVal;
+
+    pStatusMask->value[0] = (ims_mask & 0x00000FFF);
+    return RT_ERR_OK;
+}
+
+#define ADV_NOT_SUPPORT (0xFFFF)
+static rtk_api_ret_t _rtk_int_Advidx_get(rtk_int_advType_t adv_type, rtk_uint32 *pAsic_idx)
+{
+    rtk_uint32 asic_idx[ADV_END] =
+    {
+        INTRST_L2_LEARN,
+        INTRST_SPEED_CHANGE,
+        INTRST_SPECIAL_CONGESTION,
+        INTRST_PORT_LINKDOWN,
+        INTRST_PORT_LINKUP,
+        ADV_NOT_SUPPORT,
+        INTRST_RLDP_LOOPED,
+        INTRST_RLDP_RELEASED,
+    };
+
+    if(adv_type >= ADV_END)
+        return RT_ERR_INPUT;
+
+    if(asic_idx[adv_type] == ADV_NOT_SUPPORT)
+        return RT_ERR_CHIP_NOT_SUPPORTED;
+
+    *pAsic_idx = asic_idx[adv_type];
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_int_advanceInfo_get
+ * Description:
+ *      Get interrupt advanced information.
+ * Input:
+ *      adv_type - Advanced interrupt type.
+ * Output:
+ *      info - Information per type.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API can get advanced information when interrupt happened.
+ *      The status will be cleared after execute this API.
+ */
+rtk_api_ret_t rtk_int_advanceInfo_get(rtk_int_advType_t adv_type, rtk_int_info_t *pInfo)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32      data;
+    rtk_uint32      intAdvType;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(adv_type >= ADV_END)
+        return RT_ERR_INPUT;
+
+    if(NULL == pInfo)
+        return RT_ERR_NULL_POINTER;
+
+    if(adv_type != ADV_METER_EXCEED_MASK)
+    {
+        if((retVal = _rtk_int_Advidx_get(adv_type, &intAdvType)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    switch(adv_type)
+    {
+        case ADV_L2_LEARN_PORT_MASK:
+            /* Get physical portmask */
+            if((retVal = rtl8367c_getAsicInterruptRelatedStatus(intAdvType, &data)) != RT_ERR_OK)
+                return retVal;
+
+            /* Clear Advanced Info */
+            if((retVal = rtl8367c_setAsicInterruptRelatedStatus(intAdvType, 0xFFFF)) != RT_ERR_OK)
+                return retVal;
+
+            /* Translate to logical portmask */
+            if((retVal = rtk_switch_portmask_P2L_get(data, &(pInfo->portMask))) != RT_ERR_OK)
+                return retVal;
+
+            /* Get system learn */
+            if((retVal = rtl8367c_getAsicInterruptRelatedStatus(INTRST_SYS_LEARN, &data)) != RT_ERR_OK)
+                return retVal;
+
+            /* Clear system learn */
+            if((retVal = rtl8367c_setAsicInterruptRelatedStatus(INTRST_SYS_LEARN, 0x0001)) != RT_ERR_OK)
+                return retVal;
+
+            pInfo->systemLearnOver = data;
+            break;
+        case ADV_SPEED_CHANGE_PORT_MASK:
+        case ADV_SPECIAL_CONGESTION_PORT_MASK:
+        case ADV_PORT_LINKDOWN_PORT_MASK:
+        case ADV_PORT_LINKUP_PORT_MASK:
+        case ADV_RLDP_LOOPED:
+        case ADV_RLDP_RELEASED:
+            /* Get physical portmask */
+            if((retVal = rtl8367c_getAsicInterruptRelatedStatus(intAdvType, &data)) != RT_ERR_OK)
+                return retVal;
+
+            /* Clear Advanced Info */
+            if((retVal = rtl8367c_setAsicInterruptRelatedStatus(intAdvType, 0xFFFF)) != RT_ERR_OK)
+                return retVal;
+
+            /* Translate to logical portmask */
+            if((retVal = rtk_switch_portmask_P2L_get(data, &(pInfo->portMask))) != RT_ERR_OK)
+                return retVal;
+
+            break;
+        case ADV_METER_EXCEED_MASK:
+            /* Get Meter Mask */
+            if((retVal = rtl8367c_getAsicInterruptRelatedStatus(INTRST_METER0_15, &data)) != RT_ERR_OK)
+                return retVal;
+
+            /* Clear Advanced Info */
+            if((retVal = rtl8367c_setAsicInterruptRelatedStatus(INTRST_METER0_15, 0xFFFF)) != RT_ERR_OK)
+                return retVal;
+
+            pInfo->meterMask = data & 0xFFFF;
+
+            /* Get Meter Mask */
+            if((retVal = rtl8367c_getAsicInterruptRelatedStatus(INTRST_METER16_31, &data)) != RT_ERR_OK)
+                return retVal;
+
+            /* Clear Advanced Info */
+            if((retVal = rtl8367c_setAsicInterruptRelatedStatus(INTRST_METER16_31, 0xFFFF)) != RT_ERR_OK)
+                return retVal;
+
+            pInfo->meterMask = pInfo->meterMask | ((data << 16) & 0xFFFF0000);
+
+            break;
+        default:
+            return RT_ERR_INPUT;
+    }
+
+    return RT_ERR_OK;
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/l2.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/l2.c
new file mode 100644
index 0000000..feff0b2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/l2.c
@@ -0,0 +1,2911 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in L2 module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <l2.h>
+#include <string.h>
+
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_lut.h>
+#include <rtl8367c_asicdrv_port.h>
+
+/* Function Name:
+ *      rtk_l2_init
+ * Description:
+ *      Initialize l2 module of the specified device.
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK          - OK
+ *      RT_ERR_FAILED      - Failed
+ *      RT_ERR_SMI         - SMI access error
+ * Note:
+ *      Initialize l2 module before calling any l2 APIs.
+ */
+rtk_api_ret_t rtk_l2_init(void)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 port;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((retVal = rtl8367c_setAsicLutIpMulticastLookup(DISABLED)) != RT_ERR_OK)
+        return retVal;
+
+    /*Enable CAM Usage*/
+    if ((retVal = rtl8367c_setAsicLutCamTbUsage(ENABLED)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicLutAgeTimerSpeed(6,2)) != RT_ERR_OK)
+        return retVal;
+
+    RTK_SCAN_ALL_LOG_PORT(port)
+    {
+        if ((retVal = rtl8367c_setAsicLutLearnLimitNo(rtk_switch_port_L2P_get(port), rtk_switch_maxLutAddrNumber_get())) != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_l2_addr_add
+ * Description:
+ *      Add LUT unicast entry.
+ * Input:
+ *      pMac - 6 bytes unicast(I/G bit is 0) mac address to be written into LUT.
+ *      pL2_data - Unicast entry parameter
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_MAC              - Invalid MAC address.
+ *      RT_ERR_L2_FID           - Invalid FID .
+ *      RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries.
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ * Note:
+ *      If the unicast mac address already existed in LUT, it will udpate the status of the entry.
+ *      Otherwise, it will find an empty or asic auto learned entry to write. If all the entries
+ *      with the same hash value can't be replaced, ASIC will return a RT_ERR_L2_INDEXTBL_FULL error.
+ */
+rtk_api_ret_t rtk_l2_addr_add(rtk_mac_t *pMac, rtk_l2_ucastAddr_t *pL2_data)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 method;
+    rtl8367c_luttb l2Table;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* must be unicast address */
+    if ((pMac == NULL) || (pMac->octet[0] & 0x1))
+        return RT_ERR_MAC;
+
+    if(pL2_data == NULL)
+        return RT_ERR_MAC;
+
+    RTK_CHK_PORT_VALID(pL2_data->port);
+
+    if (pL2_data->ivl >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if (pL2_data->cvid > RTL8367C_VIDMAX)
+        return RT_ERR_L2_VID;
+
+    if (pL2_data->fid > RTL8367C_FIDMAX)
+        return RT_ERR_L2_FID;
+
+    if (pL2_data->is_static>= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if (pL2_data->sa_block>= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if (pL2_data->da_block>= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if (pL2_data->auth>= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if (pL2_data->efid> RTL8367C_EFIDMAX)
+        return RT_ERR_INPUT;
+
+    if (pL2_data->priority > RTL8367C_PRIMAX)
+        return RT_ERR_INPUT;
+
+    if (pL2_data->sa_pri_en >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if (pL2_data->fwd_pri_en >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    memset(&l2Table, 0, sizeof(rtl8367c_luttb));
+
+    /* fill key (MAC,FID) to get L2 entry */
+    memcpy(l2Table.mac.octet, pMac->octet, ETHER_ADDR_LEN);
+    l2Table.ivl_svl     = pL2_data->ivl;
+    l2Table.fid         = pL2_data->fid;
+    l2Table.cvid_fid    = pL2_data->cvid;
+    l2Table.efid        = pL2_data->efid;
+    method = LUTREADMETHOD_MAC;
+    retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table);
+    if (RT_ERR_OK == retVal )
+    {
+        memcpy(l2Table.mac.octet, pMac->octet, ETHER_ADDR_LEN);
+        l2Table.ivl_svl     = pL2_data->ivl;
+        l2Table.cvid_fid    = pL2_data->cvid;
+        l2Table.fid         = pL2_data->fid;
+        l2Table.efid        = pL2_data->efid;
+        l2Table.spa         = rtk_switch_port_L2P_get(pL2_data->port);
+        l2Table.nosalearn   = pL2_data->is_static;
+        l2Table.sa_block    = pL2_data->sa_block;
+        l2Table.da_block    = pL2_data->da_block;
+        l2Table.l3lookup    = 0;
+        l2Table.auth        = pL2_data->auth;
+        l2Table.age         = 6;
+        l2Table.lut_pri     = pL2_data->priority;
+        l2Table.sa_en       = pL2_data->sa_pri_en;
+        l2Table.fwd_en      = pL2_data->fwd_pri_en;
+        if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK)
+            return retVal;
+
+        pL2_data->address = l2Table.address;
+        return RT_ERR_OK;
+    }
+    else if (RT_ERR_L2_ENTRY_NOTFOUND == retVal )
+    {
+        memset(&l2Table, 0, sizeof(rtl8367c_luttb));
+        memcpy(l2Table.mac.octet, pMac->octet, ETHER_ADDR_LEN);
+        l2Table.ivl_svl     = pL2_data->ivl;
+        l2Table.cvid_fid    = pL2_data->cvid;
+        l2Table.fid         = pL2_data->fid;
+        l2Table.efid        = pL2_data->efid;
+        l2Table.spa         = rtk_switch_port_L2P_get(pL2_data->port);
+        l2Table.nosalearn   = pL2_data->is_static;
+        l2Table.sa_block    = pL2_data->sa_block;
+        l2Table.da_block    = pL2_data->da_block;
+        l2Table.l3lookup    = 0;
+        l2Table.auth        = pL2_data->auth;
+        l2Table.age         = 6;
+        l2Table.lut_pri     = pL2_data->priority;
+        l2Table.sa_en       = pL2_data->sa_pri_en;
+        l2Table.fwd_en      = pL2_data->fwd_pri_en;
+
+        if ((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK)
+            return retVal;
+
+        pL2_data->address = l2Table.address;
+
+        method = LUTREADMETHOD_MAC;
+        retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table);
+        if (RT_ERR_L2_ENTRY_NOTFOUND == retVal )
+            return RT_ERR_L2_INDEXTBL_FULL;
+        else
+            return retVal;
+    }
+    else
+        return retVal;
+
+}
+
+/* Function Name:
+ *      rtk_l2_addr_get
+ * Description:
+ *      Get LUT unicast entry.
+ * Input:
+ *      pMac    - 6 bytes unicast(I/G bit is 0) mac address to be written into LUT.
+ * Output:
+ *      pL2_data - Unicast entry parameter
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number.
+ *      RT_ERR_MAC                  - Invalid MAC address.
+ *      RT_ERR_L2_FID               - Invalid FID .
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *      If the unicast mac address existed in LUT, it will return the port and fid where
+ *      the mac is learned. Otherwise, it will return a RT_ERR_L2_ENTRY_NOTFOUND error.
+ */
+rtk_api_ret_t rtk_l2_addr_get(rtk_mac_t *pMac, rtk_l2_ucastAddr_t *pL2_data)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 method;
+    rtl8367c_luttb l2Table;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* must be unicast address */
+    if ((pMac == NULL) || (pMac->octet[0] & 0x1))
+        return RT_ERR_MAC;
+
+    if (pL2_data->fid > RTL8367C_FIDMAX || pL2_data->efid > RTL8367C_EFIDMAX)
+        return RT_ERR_L2_FID;
+
+    memset(&l2Table, 0, sizeof(rtl8367c_luttb));
+
+    memcpy(l2Table.mac.octet, pMac->octet, ETHER_ADDR_LEN);
+    l2Table.ivl_svl     = pL2_data->ivl;
+    l2Table.cvid_fid    = pL2_data->cvid;
+    l2Table.fid         = pL2_data->fid;
+    l2Table.efid        = pL2_data->efid;
+    method = LUTREADMETHOD_MAC;
+
+    if ((retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table)) != RT_ERR_OK)
+        return retVal;
+
+    memcpy(pL2_data->mac.octet, pMac->octet,ETHER_ADDR_LEN);
+    pL2_data->port      = rtk_switch_port_P2L_get(l2Table.spa);
+    pL2_data->fid       = l2Table.fid;
+    pL2_data->efid      = l2Table.efid;
+    pL2_data->ivl       = l2Table.ivl_svl;
+    pL2_data->cvid      = l2Table.cvid_fid;
+    pL2_data->is_static = l2Table.nosalearn;
+    pL2_data->auth      = l2Table.auth;
+    pL2_data->sa_block  = l2Table.sa_block;
+    pL2_data->da_block  = l2Table.da_block;
+    pL2_data->priority  = l2Table.lut_pri;
+    pL2_data->sa_pri_en = l2Table.sa_en;
+    pL2_data->fwd_pri_en= l2Table.fwd_en;
+    pL2_data->address   = l2Table.address;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_addr_next_get
+ * Description:
+ *      Get Next LUT unicast entry.
+ * Input:
+ *      read_method     - The reading method.
+ *      port            - The port number if the read_metohd is READMETHOD_NEXT_L2UCSPA
+ *      pAddress        - The Address ID
+ * Output:
+ *      pL2_data - Unicast entry parameter
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number.
+ *      RT_ERR_MAC                  - Invalid MAC address.
+ *      RT_ERR_L2_FID               - Invalid FID .
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *      Get the next unicast entry after the current entry pointed by pAddress.
+ *      The address of next entry is returned by pAddress. User can use (address + 1)
+ *      as pAddress to call this API again for dumping all entries is LUT.
+ */
+rtk_api_ret_t rtk_l2_addr_next_get(rtk_l2_read_method_t read_method, rtk_port_t port, rtk_uint32 *pAddress, rtk_l2_ucastAddr_t *pL2_data)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32      method;
+    rtl8367c_luttb  l2Table;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Error Checking */
+    if ((pL2_data == NULL) || (pAddress == NULL))
+        return RT_ERR_MAC;
+
+    if(read_method == READMETHOD_NEXT_L2UC)
+        method = LUTREADMETHOD_NEXT_L2UC;
+    else if(read_method == READMETHOD_NEXT_L2UCSPA)
+        method = LUTREADMETHOD_NEXT_L2UCSPA;
+    else
+        return RT_ERR_INPUT;
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(*pAddress > RTK_MAX_LUT_ADDR_ID )
+        return RT_ERR_L2_L2UNI_PARAM;
+
+    memset(&l2Table, 0, sizeof(rtl8367c_luttb));
+    l2Table.address = *pAddress;
+
+    if(read_method == READMETHOD_NEXT_L2UCSPA)
+        l2Table.spa = rtk_switch_port_L2P_get(port);
+
+    if ((retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table)) != RT_ERR_OK)
+        return retVal;
+
+    if(l2Table.address < *pAddress)
+        return RT_ERR_L2_ENTRY_NOTFOUND;
+
+    memcpy(pL2_data->mac.octet, l2Table.mac.octet, ETHER_ADDR_LEN);
+    pL2_data->port      = rtk_switch_port_P2L_get(l2Table.spa);
+    pL2_data->fid       = l2Table.fid;
+    pL2_data->efid      = l2Table.efid;
+    pL2_data->ivl       = l2Table.ivl_svl;
+    pL2_data->cvid      = l2Table.cvid_fid;
+    pL2_data->is_static = l2Table.nosalearn;
+    pL2_data->auth      = l2Table.auth;
+    pL2_data->sa_block  = l2Table.sa_block;
+    pL2_data->da_block  = l2Table.da_block;
+    pL2_data->priority  = l2Table.lut_pri;
+    pL2_data->sa_pri_en = l2Table.sa_en;
+    pL2_data->fwd_pri_en= l2Table.fwd_en;
+    pL2_data->address   = l2Table.address;
+
+    *pAddress = l2Table.address;
+
+    return RT_ERR_OK;
+
+}
+
+/* Function Name:
+ *      rtk_l2_addr_del
+ * Description:
+ *      Delete LUT unicast entry.
+ * Input:
+ *      pMac - 6 bytes unicast(I/G bit is 0) mac address to be written into LUT.
+ *      fid - Filtering database
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number.
+ *      RT_ERR_MAC                  - Invalid MAC address.
+ *      RT_ERR_L2_FID               - Invalid FID .
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *      If the mac has existed in the LUT, it will be deleted. Otherwise, it will return RT_ERR_L2_ENTRY_NOTFOUND.
+ */
+rtk_api_ret_t rtk_l2_addr_del(rtk_mac_t *pMac, rtk_l2_ucastAddr_t *pL2_data)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 method;
+    rtl8367c_luttb l2Table;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* must be unicast address */
+    if ((pMac == NULL) || (pMac->octet[0] & 0x1))
+        return RT_ERR_MAC;
+
+    if (pL2_data->fid > RTL8367C_FIDMAX || pL2_data->efid > RTL8367C_EFIDMAX)
+        return RT_ERR_L2_FID;
+
+    memset(&l2Table, 0, sizeof(rtl8367c_luttb));
+
+    /* fill key (MAC,FID) to get L2 entry */
+    memcpy(l2Table.mac.octet, pMac->octet, ETHER_ADDR_LEN);
+    l2Table.ivl_svl     = pL2_data->ivl;
+    l2Table.cvid_fid    = pL2_data->cvid;
+    l2Table.fid         = pL2_data->fid;
+    l2Table.efid        = pL2_data->efid;
+    method = LUTREADMETHOD_MAC;
+    retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table);
+    if (RT_ERR_OK ==  retVal)
+    {
+        memcpy(l2Table.mac.octet, pMac->octet, ETHER_ADDR_LEN);
+        l2Table.ivl_svl     = pL2_data->ivl;
+        l2Table.cvid_fid    = pL2_data->cvid;
+        l2Table.fid = pL2_data->fid;
+        l2Table.efid = pL2_data->efid;
+        l2Table.spa = 0;
+        l2Table.nosalearn = 0;
+        l2Table.sa_block = 0;
+        l2Table.da_block = 0;
+        l2Table.auth = 0;
+        l2Table.age = 0;
+        l2Table.lut_pri = 0;
+        l2Table.sa_en = 0;
+        l2Table.fwd_en = 0;
+        if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK)
+            return retVal;
+
+        pL2_data->address = l2Table.address;
+        return RT_ERR_OK;
+    }
+    else
+        return retVal;
+}
+
+/* Function Name:
+ *      rtk_l2_mcastAddr_add
+ * Description:
+ *      Add LUT multicast entry.
+ * Input:
+ *      pMcastAddr  - L2 multicast entry structure
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_MAC              - Invalid MAC address.
+ *      RT_ERR_L2_FID           - Invalid FID .
+ *      RT_ERR_L2_VID           - Invalid VID .
+ *      RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries.
+ *      RT_ERR_PORT_MASK        - Invalid portmask.
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ * Note:
+ *      If the multicast mac address already existed in the LUT, it will udpate the
+ *      port mask of the entry. Otherwise, it will find an empty or asic auto learned
+ *      entry to write. If all the entries with the same hash value can't be replaced,
+ *      ASIC will return a RT_ERR_L2_INDEXTBL_FULL error.
+ */
+rtk_api_ret_t rtk_l2_mcastAddr_add(rtk_l2_mcastAddr_t *pMcastAddr)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32      method;
+    rtl8367c_luttb  l2Table;
+    rtk_uint32      pmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pMcastAddr)
+        return RT_ERR_NULL_POINTER;
+
+    /* must be L2 multicast address */
+    if( (pMcastAddr->mac.octet[0] & 0x01) != 0x01)
+        return RT_ERR_MAC;
+
+    RTK_CHK_PORTMASK_VALID(&pMcastAddr->portmask);
+
+    if(pMcastAddr->ivl == 1)
+    {
+        if (pMcastAddr->vid > RTL8367C_VIDMAX)
+            return RT_ERR_L2_VID;
+    }
+    else if(pMcastAddr->ivl == 0)
+    {
+        if (pMcastAddr->fid > RTL8367C_FIDMAX)
+            return RT_ERR_L2_FID;
+    }
+    else
+        return RT_ERR_INPUT;
+
+    if(pMcastAddr->fwd_pri_en >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if(pMcastAddr->priority > RTL8367C_PRIMAX)
+        return RT_ERR_INPUT;
+
+    /* Get physical port mask */
+    if ((retVal = rtk_switch_portmask_L2P_get(&pMcastAddr->portmask, &pmask)) != RT_ERR_OK)
+        return retVal;
+
+    memset(&l2Table, 0, sizeof(rtl8367c_luttb));
+
+    /* fill key (MAC,FID) to get L2 entry */
+    memcpy(l2Table.mac.octet, pMcastAddr->mac.octet, ETHER_ADDR_LEN);
+    l2Table.ivl_svl     = pMcastAddr->ivl;
+
+    if(pMcastAddr->ivl)
+        l2Table.cvid_fid    = pMcastAddr->vid;
+    else
+        l2Table.cvid_fid    = pMcastAddr->fid;
+
+    method = LUTREADMETHOD_MAC;
+    retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table);
+    if (RT_ERR_OK == retVal)
+    {
+        memcpy(l2Table.mac.octet, pMcastAddr->mac.octet, ETHER_ADDR_LEN);
+        l2Table.ivl_svl     = pMcastAddr->ivl;
+
+        if(pMcastAddr->ivl)
+            l2Table.cvid_fid    = pMcastAddr->vid;
+        else
+            l2Table.cvid_fid    = pMcastAddr->fid;
+
+        l2Table.mbr         = pmask;
+        l2Table.nosalearn   = 1;
+        l2Table.l3lookup    = 0;
+        l2Table.lut_pri     = pMcastAddr->priority;
+        l2Table.fwd_en      = pMcastAddr->fwd_pri_en;
+        if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK)
+            return retVal;
+
+        pMcastAddr->address = l2Table.address;
+        return RT_ERR_OK;
+    }
+    else if (RT_ERR_L2_ENTRY_NOTFOUND == retVal)
+    {
+        memset(&l2Table, 0, sizeof(rtl8367c_luttb));
+        memcpy(l2Table.mac.octet, pMcastAddr->mac.octet, ETHER_ADDR_LEN);
+        l2Table.ivl_svl     = pMcastAddr->ivl;
+        if(pMcastAddr->ivl)
+            l2Table.cvid_fid    = pMcastAddr->vid;
+        else
+            l2Table.cvid_fid    = pMcastAddr->fid;
+
+        l2Table.mbr         = pmask;
+        l2Table.nosalearn   = 1;
+        l2Table.l3lookup    = 0;
+        l2Table.lut_pri     = pMcastAddr->priority;
+        l2Table.fwd_en      = pMcastAddr->fwd_pri_en;
+        if ((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK)
+            return retVal;
+
+        pMcastAddr->address = l2Table.address;
+
+        method = LUTREADMETHOD_MAC;
+        retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table);
+        if (RT_ERR_L2_ENTRY_NOTFOUND == retVal)
+            return     RT_ERR_L2_INDEXTBL_FULL;
+        else
+            return retVal;
+    }
+    else
+        return retVal;
+
+}
+
+/* Function Name:
+ *      rtk_l2_mcastAddr_get
+ * Description:
+ *      Get LUT multicast entry.
+ * Input:
+ *      pMcastAddr  - L2 multicast entry structure
+ * Output:
+ *      pMcastAddr  - L2 multicast entry structure
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_MAC                  - Invalid MAC address.
+ *      RT_ERR_L2_FID               - Invalid FID .
+ *      RT_ERR_L2_VID               - Invalid VID .
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *      If the multicast mac address existed in the LUT, it will return the port where
+ *      the mac is learned. Otherwise, it will return a RT_ERR_L2_ENTRY_NOTFOUND error.
+ */
+rtk_api_ret_t rtk_l2_mcastAddr_get(rtk_l2_mcastAddr_t *pMcastAddr)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 method;
+    rtl8367c_luttb l2Table;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pMcastAddr)
+        return RT_ERR_NULL_POINTER;
+
+    /* must be L2 multicast address */
+    if( (pMcastAddr->mac.octet[0] & 0x01) != 0x01)
+        return RT_ERR_MAC;
+
+    if(pMcastAddr->ivl == 1)
+    {
+        if (pMcastAddr->vid > RTL8367C_VIDMAX)
+            return RT_ERR_L2_VID;
+    }
+    else if(pMcastAddr->ivl == 0)
+    {
+        if (pMcastAddr->fid > RTL8367C_FIDMAX)
+            return RT_ERR_L2_FID;
+    }
+    else
+        return RT_ERR_INPUT;
+
+    memset(&l2Table, 0, sizeof(rtl8367c_luttb));
+    memcpy(l2Table.mac.octet, pMcastAddr->mac.octet, ETHER_ADDR_LEN);
+    l2Table.ivl_svl     = pMcastAddr->ivl;
+
+    if(pMcastAddr->ivl)
+        l2Table.cvid_fid    = pMcastAddr->vid;
+    else
+        l2Table.cvid_fid    = pMcastAddr->fid;
+
+    method = LUTREADMETHOD_MAC;
+
+    if ((retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table)) != RT_ERR_OK)
+        return retVal;
+
+    pMcastAddr->priority    = l2Table.lut_pri;
+    pMcastAddr->fwd_pri_en  = l2Table.fwd_en;
+    pMcastAddr->igmp_asic   = l2Table.igmp_asic;
+    pMcastAddr->igmp_index  = l2Table.igmpidx;
+    pMcastAddr->address     = l2Table.address;
+
+    /* Get Logical port mask */
+    if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &pMcastAddr->portmask)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_mcastAddr_next_get
+ * Description:
+ *      Get Next L2 Multicast entry.
+ * Input:
+ *      pAddress        - The Address ID
+ * Output:
+ *      pMcastAddr  - L2 multicast entry structure
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *      Get the next L2 multicast entry after the current entry pointed by pAddress.
+ *      The address of next entry is returned by pAddress. User can use (address + 1)
+ *      as pAddress to call this API again for dumping all multicast entries is LUT.
+ */
+rtk_api_ret_t rtk_l2_mcastAddr_next_get(rtk_uint32 *pAddress, rtk_l2_mcastAddr_t *pMcastAddr)
+{
+    rtk_api_ret_t   retVal;
+    rtl8367c_luttb  l2Table;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Error Checking */
+    if ((pAddress == NULL) || (pMcastAddr == NULL))
+        return RT_ERR_INPUT;
+
+    if(*pAddress > RTK_MAX_LUT_ADDR_ID )
+        return RT_ERR_L2_L2UNI_PARAM;
+
+    memset(&l2Table, 0, sizeof(rtl8367c_luttb));
+    l2Table.address = *pAddress;
+
+    if ((retVal = rtl8367c_getAsicL2LookupTb(LUTREADMETHOD_NEXT_L2MC, &l2Table)) != RT_ERR_OK)
+        return retVal;
+
+    if(l2Table.address < *pAddress)
+        return RT_ERR_L2_ENTRY_NOTFOUND;
+
+    memcpy(pMcastAddr->mac.octet, l2Table.mac.octet, ETHER_ADDR_LEN);
+    pMcastAddr->ivl     = l2Table.ivl_svl;
+
+    if(pMcastAddr->ivl)
+        pMcastAddr->vid = l2Table.cvid_fid;
+    else
+        pMcastAddr->fid = l2Table.cvid_fid;
+
+    pMcastAddr->priority    = l2Table.lut_pri;
+    pMcastAddr->fwd_pri_en  = l2Table.fwd_en;
+    pMcastAddr->igmp_asic   = l2Table.igmp_asic;
+    pMcastAddr->igmp_index  = l2Table.igmpidx;
+    pMcastAddr->address     = l2Table.address;
+
+    /* Get Logical port mask */
+    if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &pMcastAddr->portmask)) != RT_ERR_OK)
+        return retVal;
+
+    *pAddress = l2Table.address;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_mcastAddr_del
+ * Description:
+ *      Delete LUT multicast entry.
+ * Input:
+ *      pMcastAddr  - L2 multicast entry structure
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_MAC                  - Invalid MAC address.
+ *      RT_ERR_L2_FID               - Invalid FID .
+ *      RT_ERR_L2_VID               - Invalid VID .
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *      If the mac has existed in the LUT, it will be deleted. Otherwise, it will return RT_ERR_L2_ENTRY_NOTFOUND.
+ */
+rtk_api_ret_t rtk_l2_mcastAddr_del(rtk_l2_mcastAddr_t *pMcastAddr)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 method;
+    rtl8367c_luttb l2Table;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pMcastAddr)
+        return RT_ERR_NULL_POINTER;
+
+    /* must be L2 multicast address */
+    if( (pMcastAddr->mac.octet[0] & 0x01) != 0x01)
+        return RT_ERR_MAC;
+
+    if(pMcastAddr->ivl == 1)
+    {
+        if (pMcastAddr->vid > RTL8367C_VIDMAX)
+            return RT_ERR_L2_VID;
+    }
+    else if(pMcastAddr->ivl == 0)
+    {
+        if (pMcastAddr->fid > RTL8367C_FIDMAX)
+            return RT_ERR_L2_FID;
+    }
+    else
+        return RT_ERR_INPUT;
+
+    memset(&l2Table, 0, sizeof(rtl8367c_luttb));
+
+    /* fill key (MAC,FID) to get L2 entry */
+    memcpy(l2Table.mac.octet, pMcastAddr->mac.octet, ETHER_ADDR_LEN);
+    l2Table.ivl_svl     = pMcastAddr->ivl;
+
+    if(pMcastAddr->ivl)
+        l2Table.cvid_fid    = pMcastAddr->vid;
+    else
+        l2Table.cvid_fid    = pMcastAddr->fid;
+
+    method = LUTREADMETHOD_MAC;
+    retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table);
+    if (RT_ERR_OK == retVal)
+    {
+        memcpy(l2Table.mac.octet, pMcastAddr->mac.octet, ETHER_ADDR_LEN);
+        l2Table.ivl_svl     = pMcastAddr->ivl;
+
+        if(pMcastAddr->ivl)
+            l2Table.cvid_fid    = pMcastAddr->vid;
+        else
+            l2Table.cvid_fid    = pMcastAddr->fid;
+
+        l2Table.mbr         = 0;
+        l2Table.nosalearn   = 0;
+        l2Table.sa_block    = 0;
+        l2Table.l3lookup    = 0;
+        l2Table.lut_pri     = 0;
+        l2Table.fwd_en      = 0;
+        if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK)
+            return retVal;
+
+        pMcastAddr->address = l2Table.address;
+        return RT_ERR_OK;
+    }
+    else
+        return retVal;
+}
+
+/* Function Name:
+ *      rtk_l2_ipMcastAddr_add
+ * Description:
+ *      Add Lut IP multicast entry
+ * Input:
+ *      pIpMcastAddr    - IP Multicast entry
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries.
+ *      RT_ERR_PORT_MASK        - Invalid portmask.
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ * Note:
+ *      System supports L2 entry with IP multicast DIP/SIP to forward IP multicasting frame as user
+ *      desired. If this function is enabled, then system will be looked up L2 IP multicast entry to
+ *      forward IP multicast frame directly without flooding.
+ */
+rtk_api_ret_t rtk_l2_ipMcastAddr_add(rtk_l2_ipMcastAddr_t *pIpMcastAddr)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 method;
+    rtl8367c_luttb l2Table;
+    rtk_uint32 pmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pIpMcastAddr)
+        return RT_ERR_NULL_POINTER;
+
+    /* check port mask */
+    RTK_CHK_PORTMASK_VALID(&pIpMcastAddr->portmask);
+
+    if( (pIpMcastAddr->dip & 0xF0000000) != 0xE0000000)
+        return RT_ERR_INPUT;
+
+    if(pIpMcastAddr->fwd_pri_en >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if(pIpMcastAddr->priority > RTL8367C_PRIMAX)
+        return RT_ERR_INPUT;
+
+    /* Get Physical port mask */
+    if ((retVal = rtk_switch_portmask_L2P_get(&pIpMcastAddr->portmask, &pmask)) != RT_ERR_OK)
+        return retVal;
+
+    memset(&l2Table, 0x00, sizeof(rtl8367c_luttb));
+    l2Table.sip = pIpMcastAddr->sip;
+    l2Table.dip = pIpMcastAddr->dip;
+    l2Table.l3lookup = 1;
+    l2Table.l3vidlookup = 0;
+    method = LUTREADMETHOD_MAC;
+    retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table);
+    if (RT_ERR_OK == retVal)
+    {
+        l2Table.sip = pIpMcastAddr->sip;
+        l2Table.dip = pIpMcastAddr->dip;
+        l2Table.mbr = pmask;
+        l2Table.nosalearn = 1;
+        l2Table.l3lookup = 1;
+        l2Table.l3vidlookup = 0;
+        l2Table.lut_pri = pIpMcastAddr->priority;
+        l2Table.fwd_en  = pIpMcastAddr->fwd_pri_en;
+        if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK)
+            return retVal;
+
+        pIpMcastAddr->address = l2Table.address;
+        return RT_ERR_OK;
+    }
+    else if (RT_ERR_L2_ENTRY_NOTFOUND == retVal)
+    {
+        memset(&l2Table, 0, sizeof(rtl8367c_luttb));
+        l2Table.sip = pIpMcastAddr->sip;
+        l2Table.dip = pIpMcastAddr->dip;
+        l2Table.mbr = pmask;
+        l2Table.nosalearn = 1;
+        l2Table.l3lookup = 1;
+        l2Table.l3vidlookup = 0;
+        l2Table.lut_pri = pIpMcastAddr->priority;
+        l2Table.fwd_en  = pIpMcastAddr->fwd_pri_en;
+        if ((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK)
+            return retVal;
+
+        pIpMcastAddr->address = l2Table.address;
+
+        method = LUTREADMETHOD_MAC;
+        retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table);
+        if (RT_ERR_L2_ENTRY_NOTFOUND == retVal)
+            return     RT_ERR_L2_INDEXTBL_FULL;
+        else
+            return retVal;
+
+    }
+    else
+        return retVal;
+
+}
+
+/* Function Name:
+ *      rtk_l2_ipMcastAddr_get
+ * Description:
+ *      Get LUT IP multicast entry.
+ * Input:
+ *      pIpMcastAddr    - IP Multicast entry
+ * Output:
+ *      pIpMcastAddr    - IP Multicast entry
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *      The API can get Lut table of IP multicast entry.
+ */
+rtk_api_ret_t rtk_l2_ipMcastAddr_get(rtk_l2_ipMcastAddr_t *pIpMcastAddr)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 method;
+    rtl8367c_luttb l2Table;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pIpMcastAddr)
+        return RT_ERR_NULL_POINTER;
+
+    if( (pIpMcastAddr->dip & 0xF0000000) != 0xE0000000)
+        return RT_ERR_INPUT;
+
+    memset(&l2Table, 0x00, sizeof(rtl8367c_luttb));
+    l2Table.sip = pIpMcastAddr->sip;
+    l2Table.dip = pIpMcastAddr->dip;
+    l2Table.l3lookup = 1;
+    l2Table.l3vidlookup = 0;
+    method = LUTREADMETHOD_MAC;
+    if ((retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table)) != RT_ERR_OK)
+        return retVal;
+
+    /* Get Logical port mask */
+    if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &pIpMcastAddr->portmask)) != RT_ERR_OK)
+        return retVal;
+
+    pIpMcastAddr->priority      = l2Table.lut_pri;
+    pIpMcastAddr->fwd_pri_en    = l2Table.fwd_en;
+    pIpMcastAddr->igmp_asic     = l2Table.igmp_asic;
+    pIpMcastAddr->igmp_index    = l2Table.igmpidx;
+    pIpMcastAddr->address       = l2Table.address;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_ipMcastAddr_next_get
+ * Description:
+ *      Get Next IP Multicast entry.
+ * Input:
+ *      pAddress        - The Address ID
+ * Output:
+ *      pIpMcastAddr    - IP Multicast entry
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *      Get the next IP multicast entry after the current entry pointed by pAddress.
+ *      The address of next entry is returned by pAddress. User can use (address + 1)
+ *      as pAddress to call this API again for dumping all IP multicast entries is LUT.
+ */
+rtk_api_ret_t rtk_l2_ipMcastAddr_next_get(rtk_uint32 *pAddress, rtk_l2_ipMcastAddr_t *pIpMcastAddr)
+{
+    rtk_api_ret_t   retVal;
+    rtl8367c_luttb  l2Table;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Error Checking */
+    if ((pAddress == NULL) || (pIpMcastAddr == NULL) )
+        return RT_ERR_INPUT;
+
+    if(*pAddress > RTK_MAX_LUT_ADDR_ID )
+        return RT_ERR_L2_L2UNI_PARAM;
+
+    memset(&l2Table, 0, sizeof(rtl8367c_luttb));
+    l2Table.address = *pAddress;
+
+    do
+    {
+        if ((retVal = rtl8367c_getAsicL2LookupTb(LUTREADMETHOD_NEXT_L3MC, &l2Table)) != RT_ERR_OK)
+            return retVal;
+
+        if(l2Table.address < *pAddress)
+            return RT_ERR_L2_ENTRY_NOTFOUND;
+
+    }while(l2Table.l3vidlookup == 1);
+
+    pIpMcastAddr->sip = l2Table.sip;
+    pIpMcastAddr->dip = l2Table.dip;
+
+    /* Get Logical port mask */
+    if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &pIpMcastAddr->portmask)) != RT_ERR_OK)
+        return retVal;
+
+    pIpMcastAddr->priority      = l2Table.lut_pri;
+    pIpMcastAddr->fwd_pri_en    = l2Table.fwd_en;
+    pIpMcastAddr->igmp_asic     = l2Table.igmp_asic;
+    pIpMcastAddr->igmp_index    = l2Table.igmpidx;
+    pIpMcastAddr->address       = l2Table.address;
+    *pAddress = l2Table.address;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_ipMcastAddr_del
+ * Description:
+ *      Delete a ip multicast address entry from the specified device.
+ * Input:
+ *      pIpMcastAddr    - IP Multicast entry
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *      The API can delete a IP multicast address entry from the specified device.
+ */
+rtk_api_ret_t rtk_l2_ipMcastAddr_del(rtk_l2_ipMcastAddr_t *pIpMcastAddr)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 method;
+    rtl8367c_luttb l2Table;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Error Checking */
+    if (pIpMcastAddr == NULL)
+        return RT_ERR_INPUT;
+
+    if( (pIpMcastAddr->dip & 0xF0000000) != 0xE0000000)
+        return RT_ERR_INPUT;
+
+    memset(&l2Table, 0x00, sizeof(rtl8367c_luttb));
+    l2Table.sip = pIpMcastAddr->sip;
+    l2Table.dip = pIpMcastAddr->dip;
+    l2Table.l3lookup = 1;
+    l2Table.l3vidlookup = 0;
+    method = LUTREADMETHOD_MAC;
+    retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table);
+    if (RT_ERR_OK == retVal)
+    {
+        l2Table.sip = pIpMcastAddr->sip;
+        l2Table.dip = pIpMcastAddr->dip;
+        l2Table.mbr = 0;
+        l2Table.nosalearn = 0;
+        l2Table.l3lookup = 1;
+        l2Table.l3vidlookup = 0;
+        l2Table.lut_pri = 0;
+        l2Table.fwd_en  = 0;
+        if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK)
+            return retVal;
+
+        pIpMcastAddr->address = l2Table.address;
+        return RT_ERR_OK;
+    }
+    else
+        return retVal;
+}
+
+/* Function Name:
+ *      rtk_l2_ipVidMcastAddr_add
+ * Description:
+ *      Add Lut IP multicast+VID entry
+ * Input:
+ *      pIpVidMcastAddr - IP & VID multicast Entry
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries.
+ *      RT_ERR_PORT_MASK        - Invalid portmask.
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_l2_ipVidMcastAddr_add(rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 method;
+    rtl8367c_luttb l2Table;
+    rtk_uint32 pmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pIpVidMcastAddr)
+        return RT_ERR_NULL_POINTER;
+
+    /* check port mask */
+    RTK_CHK_PORTMASK_VALID(&pIpVidMcastAddr->portmask);
+
+    if (pIpVidMcastAddr->vid > RTL8367C_VIDMAX)
+        return RT_ERR_L2_VID;
+
+    if( (pIpVidMcastAddr->dip & 0xF0000000) != 0xE0000000)
+        return RT_ERR_INPUT;
+
+    /* Get Physical port mask */
+    if ((retVal = rtk_switch_portmask_L2P_get(&pIpVidMcastAddr->portmask, &pmask)) != RT_ERR_OK)
+        return retVal;
+
+    memset(&l2Table, 0x00, sizeof(rtl8367c_luttb));
+    l2Table.sip = pIpVidMcastAddr->sip;
+    l2Table.dip = pIpVidMcastAddr->dip;
+    l2Table.l3lookup = 1;
+    l2Table.l3vidlookup = 1;
+    l2Table.l3_vid = pIpVidMcastAddr->vid;
+    method = LUTREADMETHOD_MAC;
+    retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table);
+    if (RT_ERR_OK == retVal)
+    {
+        l2Table.sip = pIpVidMcastAddr->sip;
+        l2Table.dip = pIpVidMcastAddr->dip;
+        l2Table.mbr = pmask;
+        l2Table.nosalearn = 1;
+        l2Table.l3lookup = 1;
+        l2Table.l3vidlookup = 1;
+        l2Table.l3_vid = pIpVidMcastAddr->vid;
+        if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK)
+            return retVal;
+
+        pIpVidMcastAddr->address = l2Table.address;
+        return RT_ERR_OK;
+    }
+    else if (RT_ERR_L2_ENTRY_NOTFOUND == retVal)
+    {
+        memset(&l2Table, 0, sizeof(rtl8367c_luttb));
+        l2Table.sip = pIpVidMcastAddr->sip;
+        l2Table.dip = pIpVidMcastAddr->dip;
+        l2Table.mbr = pmask;
+        l2Table.nosalearn = 1;
+        l2Table.l3lookup = 1;
+        l2Table.l3vidlookup = 1;
+        l2Table.l3_vid = pIpVidMcastAddr->vid;
+        if ((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK)
+            return retVal;
+
+        pIpVidMcastAddr->address = l2Table.address;
+
+        method = LUTREADMETHOD_MAC;
+        retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table);
+        if (RT_ERR_L2_ENTRY_NOTFOUND == retVal)
+            return     RT_ERR_L2_INDEXTBL_FULL;
+        else
+            return retVal;
+
+    }
+    else
+        return retVal;
+}
+
+/* Function Name:
+ *      rtk_l2_ipVidMcastAddr_get
+ * Description:
+ *      Get LUT IP multicast+VID entry.
+ * Input:
+ *      pIpVidMcastAddr - IP & VID multicast Entry
+ * Output:
+ *      pIpVidMcastAddr - IP & VID multicast Entry
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_l2_ipVidMcastAddr_get(rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 method;
+    rtl8367c_luttb l2Table;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pIpVidMcastAddr)
+        return RT_ERR_NULL_POINTER;
+
+    if (pIpVidMcastAddr->vid > RTL8367C_VIDMAX)
+        return RT_ERR_L2_VID;
+
+    if( (pIpVidMcastAddr->dip & 0xF0000000) != 0xE0000000)
+        return RT_ERR_INPUT;
+
+    memset(&l2Table, 0x00, sizeof(rtl8367c_luttb));
+    l2Table.sip = pIpVidMcastAddr->sip;
+    l2Table.dip = pIpVidMcastAddr->dip;
+    l2Table.l3lookup = 1;
+    l2Table.l3vidlookup = 1;
+    l2Table.l3_vid = pIpVidMcastAddr->vid;
+    method = LUTREADMETHOD_MAC;
+    if ((retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table)) != RT_ERR_OK)
+        return retVal;
+
+    pIpVidMcastAddr->address = l2Table.address;
+
+     /* Get Logical port mask */
+    if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &pIpVidMcastAddr->portmask)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_ipVidMcastAddr_next_get
+ * Description:
+ *      Get Next IP Multicast+VID entry.
+ * Input:
+ *      pAddress        - The Address ID
+ * Output:
+ *      pIpVidMcastAddr - IP & VID multicast Entry
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *      Get the next IP multicast entry after the current entry pointed by pAddress.
+ *      The address of next entry is returned by pAddress. User can use (address + 1)
+ *      as pAddress to call this API again for dumping all IP multicast entries is LUT.
+ */
+rtk_api_ret_t rtk_l2_ipVidMcastAddr_next_get(rtk_uint32 *pAddress, rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr)
+{
+    rtk_api_ret_t   retVal;
+    rtl8367c_luttb  l2Table;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Error Checking */
+    if ((pAddress == NULL) || (pIpVidMcastAddr == NULL))
+        return RT_ERR_INPUT;
+
+    if(*pAddress > RTK_MAX_LUT_ADDR_ID )
+        return RT_ERR_L2_L2UNI_PARAM;
+
+    memset(&l2Table, 0, sizeof(rtl8367c_luttb));
+    l2Table.address = *pAddress;
+
+    do
+    {
+        if ((retVal = rtl8367c_getAsicL2LookupTb(LUTREADMETHOD_NEXT_L3MC, &l2Table)) != RT_ERR_OK)
+            return retVal;
+
+        if(l2Table.address < *pAddress)
+            return RT_ERR_L2_ENTRY_NOTFOUND;
+
+    }while(l2Table.l3vidlookup == 0);
+
+    pIpVidMcastAddr->sip        = l2Table.sip;
+    pIpVidMcastAddr->dip        = l2Table.dip;
+    pIpVidMcastAddr->vid        = l2Table.l3_vid;
+    pIpVidMcastAddr->address    = l2Table.address;
+
+    /* Get Logical port mask */
+    if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &pIpVidMcastAddr->portmask)) != RT_ERR_OK)
+        return retVal;
+
+    *pAddress = l2Table.address;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_ipVidMcastAddr_del
+ * Description:
+ *      Delete a ip multicast+VID address entry from the specified device.
+ * Input:
+ *      pIpVidMcastAddr - IP & VID multicast Entry
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_L2_ENTRY_NOTFOUND    - No such LUT entry.
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_l2_ipVidMcastAddr_del(rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 method;
+    rtl8367c_luttb l2Table;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pIpVidMcastAddr)
+        return RT_ERR_NULL_POINTER;
+
+    if (pIpVidMcastAddr->vid > RTL8367C_VIDMAX)
+        return RT_ERR_L2_VID;
+
+    if( (pIpVidMcastAddr->dip & 0xF0000000) != 0xE0000000)
+        return RT_ERR_INPUT;
+
+    memset(&l2Table, 0x00, sizeof(rtl8367c_luttb));
+    l2Table.sip = pIpVidMcastAddr->sip;
+    l2Table.dip = pIpVidMcastAddr->dip;
+    l2Table.l3lookup = 1;
+    l2Table.l3vidlookup = 1;
+    l2Table.l3_vid = pIpVidMcastAddr->vid;
+    method = LUTREADMETHOD_MAC;
+    retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table);
+    if (RT_ERR_OK == retVal)
+    {
+        l2Table.sip = pIpVidMcastAddr->sip;
+        l2Table.dip = pIpVidMcastAddr->dip;
+        l2Table.mbr= 0;
+        l2Table.nosalearn = 0;
+        l2Table.l3lookup = 1;
+        l2Table.l3vidlookup = 1;
+        l2Table.l3_vid = pIpVidMcastAddr->vid;
+        if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK)
+            return retVal;
+
+        pIpVidMcastAddr->address = l2Table.address;
+        return RT_ERR_OK;
+    }
+    else
+        return retVal;
+}
+
+/* Function Name:
+ *      rtk_l2_ucastAddr_flush
+ * Description:
+ *      Flush L2 mac address by type in the specified device (both dynamic and static).
+ * Input:
+ *      pConfig - flush configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_VLAN_VID     - Invalid VID parameter.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      flushByVid          - 1: Flush by VID, 0: Don't flush by VID
+ *      vid                 - VID (0 ~ 4095)
+ *      flushByFid          - 1: Flush by FID, 0: Don't flush by FID
+ *      fid                 - FID (0 ~ 15)
+ *      flushByPort         - 1: Flush by Port, 0: Don't flush by Port
+ *      port                - Port ID
+ *      flushByMac          - Not Supported
+ *      ucastAddr           - Not Supported
+ *      flushStaticAddr     - 1: Flush both Static and Dynamic entries, 0: Flush only Dynamic entries
+ *      flushAddrOnAllPorts - 1: Flush VID-matched entries at all ports, 0: Flush VID-matched entries per port.
+ */
+rtk_api_ret_t rtk_l2_ucastAddr_flush(rtk_l2_flushCfg_t *pConfig)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(pConfig == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    if(pConfig->flushByVid >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if(pConfig->flushByFid >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if(pConfig->flushByPort >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if(pConfig->flushByMac >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if(pConfig->flushStaticAddr >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if(pConfig->flushAddrOnAllPorts >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if(pConfig->vid > RTL8367C_VIDMAX)
+        return RT_ERR_VLAN_VID;
+
+    if(pConfig->fid > RTL8367C_FIDMAX)
+        return RT_ERR_INPUT;
+
+    /* check port valid */
+    RTK_CHK_PORT_VALID(pConfig->port);
+
+    if(pConfig->flushByVid == ENABLED)
+    {
+        if ((retVal = rtl8367c_setAsicLutFlushMode(FLUSHMDOE_VID)) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicLutFlushVid(pConfig->vid)) != RT_ERR_OK)
+                return retVal;
+
+        if ((retVal = rtl8367c_setAsicLutFlushType((pConfig->flushStaticAddr == ENABLED) ? FLUSHTYPE_BOTH : FLUSHTYPE_DYNAMIC)) != RT_ERR_OK)
+            return retVal;
+
+        if(pConfig->flushAddrOnAllPorts == ENABLED)
+        {
+            if ((retVal = rtl8367c_setAsicLutForceFlush(RTL8367C_PORTMASK)) != RT_ERR_OK)
+                return retVal;
+        }
+        else if(pConfig->flushByPort == ENABLED)
+        {
+            if ((retVal = rtl8367c_setAsicLutForceFlush(1 << rtk_switch_port_L2P_get(pConfig->port))) != RT_ERR_OK)
+                return retVal;
+        }
+        else
+            return RT_ERR_INPUT;
+    }
+    else if(pConfig->flushByFid == ENABLED)
+    {
+        if ((retVal = rtl8367c_setAsicLutFlushMode(FLUSHMDOE_FID)) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicLutFlushFid(pConfig->fid)) != RT_ERR_OK)
+                return retVal;
+
+        if ((retVal = rtl8367c_setAsicLutFlushType((pConfig->flushStaticAddr == ENABLED) ? FLUSHTYPE_BOTH : FLUSHTYPE_DYNAMIC)) != RT_ERR_OK)
+            return retVal;
+
+        if(pConfig->flushAddrOnAllPorts == ENABLED)
+        {
+            if ((retVal = rtl8367c_setAsicLutForceFlush(RTL8367C_PORTMASK)) != RT_ERR_OK)
+                return retVal;
+        }
+        else if(pConfig->flushByPort == ENABLED)
+        {
+            if ((retVal = rtl8367c_setAsicLutForceFlush(1 << rtk_switch_port_L2P_get(pConfig->port))) != RT_ERR_OK)
+                return retVal;
+        }
+        else
+            return RT_ERR_INPUT;
+    }
+    else if(pConfig->flushByPort == ENABLED)
+    {
+        if ((retVal = rtl8367c_setAsicLutFlushType((pConfig->flushStaticAddr == ENABLED) ? FLUSHTYPE_BOTH : FLUSHTYPE_DYNAMIC)) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicLutFlushMode(FLUSHMDOE_PORT)) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicLutForceFlush(1 << rtk_switch_port_L2P_get(pConfig->port))) != RT_ERR_OK)
+            return retVal;
+    }
+    else if(pConfig->flushByMac == ENABLED)
+    {
+        /* Should use API "rtk_l2_addr_del" to remove a specified entry*/
+        return RT_ERR_CHIP_NOT_SUPPORTED;
+    }
+    else
+        return RT_ERR_INPUT;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_table_clear
+ * Description:
+ *      Flush all static & dynamic entries in LUT.
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_l2_table_clear(void)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((retVal = rtl8367c_setAsicLutFlushAll()) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_table_clearStatus_get
+ * Description:
+ *      Get table clear status
+ * Input:
+ *      None
+ * Output:
+ *      pStatus - Clear status, 1:Busy, 0:finish
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_l2_table_clearStatus_get(rtk_l2_clearStatus_t *pStatus)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pStatus)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicLutFlushAllStatus((rtk_uint32 *)pStatus)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_flushLinkDownPortAddrEnable_set
+ * Description:
+ *      Set HW flush linkdown port mac configuration of the specified device.
+ * Input:
+ *      port - Port id.
+ *      enable - link down flush status
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_ENABLE       - Invalid enable input.
+ * Note:
+ *      The status of flush linkdown port address is as following:
+ *      - DISABLED
+ *      - ENABLED
+ */
+rtk_api_ret_t rtk_l2_flushLinkDownPortAddrEnable_set(rtk_port_t port, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (port != RTK_WHOLE_SYSTEM)
+        return RT_ERR_PORT_ID;
+
+    if (enable >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if ((retVal = rtl8367c_setAsicLutLinkDownForceAging(enable)) != RT_ERR_OK)
+        return retVal;
+
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_flushLinkDownPortAddrEnable_get
+ * Description:
+ *      Get HW flush linkdown port mac configuration of the specified device.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEnable - link down flush status
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The status of flush linkdown port address is as following:
+ *      - DISABLED
+ *      - ENABLED
+ */
+rtk_api_ret_t rtk_l2_flushLinkDownPortAddrEnable_get(rtk_port_t port, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (port != RTK_WHOLE_SYSTEM)
+        return RT_ERR_PORT_ID;
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicLutLinkDownForceAging(pEnable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_agingEnable_set
+ * Description:
+ *      Set L2 LUT aging status per port setting.
+ * Input:
+ *      port    - Port id.
+ *      enable  - Aging status
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_ENABLE       - Invalid enable input.
+ * Note:
+ *      This API can be used to set L2 LUT aging status per port.
+ */
+rtk_api_ret_t rtk_l2_agingEnable_set(rtk_port_t port, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (enable >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if(enable == 1)
+        enable = 0;
+    else
+        enable = 1;
+
+    if ((retVal = rtl8367c_setAsicLutDisableAging(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_agingEnable_get
+ * Description:
+ *      Get L2 LUT aging status per port setting.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEnable - Aging status
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API can be used to get L2 LUT aging function per port.
+ */
+rtk_api_ret_t rtk_l2_agingEnable_get(rtk_port_t port, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicLutDisableAging(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK)
+        return retVal;
+
+    if(*pEnable == 1)
+        *pEnable = 0;
+    else
+        *pEnable = 1;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_limitLearningCnt_set
+ * Description:
+ *      Set per-Port auto learning limit number
+ * Input:
+ *      port    - Port id.
+ *      mac_cnt - Auto learning entries limit number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number.
+ *      RT_ERR_LIMITED_L2ENTRY_NUM  - Invalid auto learning limit number
+ * Note:
+ *      The API can set per-port ASIC auto learning limit number from 0(disable learning)
+ *      to 2112.
+ */
+rtk_api_ret_t rtk_l2_limitLearningCnt_set(rtk_port_t port, rtk_mac_cnt_t mac_cnt)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (mac_cnt > rtk_switch_maxLutAddrNumber_get())
+        return RT_ERR_LIMITED_L2ENTRY_NUM;
+
+    if ((retVal = rtl8367c_setAsicLutLearnLimitNo(rtk_switch_port_L2P_get(port), mac_cnt)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_limitLearningCnt_get
+ * Description:
+ *      Get per-Port auto learning limit number
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pMac_cnt - Auto learning entries limit number
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get per-port ASIC auto learning limit number.
+ */
+rtk_api_ret_t rtk_l2_limitLearningCnt_get(rtk_port_t port, rtk_mac_cnt_t *pMac_cnt)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pMac_cnt)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicLutLearnLimitNo(rtk_switch_port_L2P_get(port), pMac_cnt)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_limitSystemLearningCnt_set
+ * Description:
+ *      Set System auto learning limit number
+ * Input:
+ *      mac_cnt - Auto learning entries limit number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_LIMITED_L2ENTRY_NUM  - Invalid auto learning limit number
+ * Note:
+ *      The API can set system ASIC auto learning limit number from 0(disable learning)
+ *      to 2112.
+ */
+rtk_api_ret_t rtk_l2_limitSystemLearningCnt_set(rtk_mac_cnt_t mac_cnt)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (mac_cnt > rtk_switch_maxLutAddrNumber_get())
+        return RT_ERR_LIMITED_L2ENTRY_NUM;
+
+    if ((retVal = rtl8367c_setAsicSystemLutLearnLimitNo(mac_cnt)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_limitSystemLearningCnt_get
+ * Description:
+ *      Get System auto learning limit number
+ * Input:
+ *      None
+ * Output:
+ *      pMac_cnt - Auto learning entries limit number
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get system ASIC auto learning limit number.
+ */
+rtk_api_ret_t rtk_l2_limitSystemLearningCnt_get(rtk_mac_cnt_t *pMac_cnt)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pMac_cnt)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicSystemLutLearnLimitNo(pMac_cnt)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_limitLearningCntAction_set
+ * Description:
+ *      Configure auto learn over limit number action.
+ * Input:
+ *      port - Port id.
+ *      action - Auto learning entries limit number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_NOT_ALLOWED  - Invalid learn over action
+ * Note:
+ *      The API can set SA unknown packet action while auto learn limit number is over
+ *      The action symbol as following:
+ *      - LIMIT_LEARN_CNT_ACTION_DROP,
+ *      - LIMIT_LEARN_CNT_ACTION_FORWARD,
+ *      - LIMIT_LEARN_CNT_ACTION_TO_CPU,
+ */
+rtk_api_ret_t rtk_l2_limitLearningCntAction_set(rtk_port_t port, rtk_l2_limitLearnCntAction_t action)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 data;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (port != RTK_WHOLE_SYSTEM)
+        return RT_ERR_PORT_ID;
+
+    if ( LIMIT_LEARN_CNT_ACTION_DROP == action )
+        data = 1;
+    else if ( LIMIT_LEARN_CNT_ACTION_FORWARD == action )
+        data = 0;
+    else if ( LIMIT_LEARN_CNT_ACTION_TO_CPU == action )
+        data = 2;
+    else
+        return RT_ERR_NOT_ALLOWED;
+
+    if ((retVal = rtl8367c_setAsicLutLearnOverAct(data)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_limitLearningCntAction_get
+ * Description:
+ *      Get auto learn over limit number action.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pAction - Learn over action
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get SA unknown packet action while auto learn limit number is over
+ *      The action symbol as following:
+ *      - LIMIT_LEARN_CNT_ACTION_DROP,
+ *      - LIMIT_LEARN_CNT_ACTION_FORWARD,
+ *      - LIMIT_LEARN_CNT_ACTION_TO_CPU,
+ */
+rtk_api_ret_t rtk_l2_limitLearningCntAction_get(rtk_port_t port, rtk_l2_limitLearnCntAction_t *pAction)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 action;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (port != RTK_WHOLE_SYSTEM)
+        return RT_ERR_PORT_ID;
+
+    if(NULL == pAction)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicLutLearnOverAct(&action)) != RT_ERR_OK)
+        return retVal;
+
+    if ( 1 == action )
+        *pAction = LIMIT_LEARN_CNT_ACTION_DROP;
+    else if ( 0 == action )
+        *pAction = LIMIT_LEARN_CNT_ACTION_FORWARD;
+    else if ( 2 == action )
+        *pAction = LIMIT_LEARN_CNT_ACTION_TO_CPU;
+    else
+    *pAction = action;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_limitSystemLearningCntAction_set
+ * Description:
+ *      Configure system auto learn over limit number action.
+ * Input:
+ *      port - Port id.
+ *      action - Auto learning entries limit number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_NOT_ALLOWED  - Invalid learn over action
+ * Note:
+ *      The API can set SA unknown packet action while auto learn limit number is over
+ *      The action symbol as following:
+ *      - LIMIT_LEARN_CNT_ACTION_DROP,
+ *      - LIMIT_LEARN_CNT_ACTION_FORWARD,
+ *      - LIMIT_LEARN_CNT_ACTION_TO_CPU,
+ */
+rtk_api_ret_t rtk_l2_limitSystemLearningCntAction_set(rtk_l2_limitLearnCntAction_t action)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 data;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ( LIMIT_LEARN_CNT_ACTION_DROP == action )
+        data = 1;
+    else if ( LIMIT_LEARN_CNT_ACTION_FORWARD == action )
+        data = 0;
+    else if ( LIMIT_LEARN_CNT_ACTION_TO_CPU == action )
+        data = 2;
+    else
+        return RT_ERR_NOT_ALLOWED;
+
+    if ((retVal = rtl8367c_setAsicSystemLutLearnOverAct(data)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_limitSystemLearningCntAction_get
+ * Description:
+ *      Get system auto learn over limit number action.
+ * Input:
+ *      None.
+ * Output:
+ *      pAction - Learn over action
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get SA unknown packet action while auto learn limit number is over
+ *      The action symbol as following:
+ *      - LIMIT_LEARN_CNT_ACTION_DROP,
+ *      - LIMIT_LEARN_CNT_ACTION_FORWARD,
+ *      - LIMIT_LEARN_CNT_ACTION_TO_CPU,
+ */
+rtk_api_ret_t rtk_l2_limitSystemLearningCntAction_get(rtk_l2_limitLearnCntAction_t *pAction)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 action;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pAction)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicSystemLutLearnOverAct(&action)) != RT_ERR_OK)
+        return retVal;
+
+    if ( 1 == action )
+        *pAction = LIMIT_LEARN_CNT_ACTION_DROP;
+    else if ( 0 == action )
+        *pAction = LIMIT_LEARN_CNT_ACTION_FORWARD;
+    else if ( 2 == action )
+        *pAction = LIMIT_LEARN_CNT_ACTION_TO_CPU;
+    else
+    *pAction = action;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_limitSystemLearningCntPortMask_set
+ * Description:
+ *      Configure system auto learn portmask
+ * Input:
+ *      pPortmask - Port Mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK    - Invalid port mask.
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_l2_limitSystemLearningCntPortMask_set(rtk_portmask_t *pPortmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pPortmask)
+        return RT_ERR_NULL_POINTER;
+
+    /* Check port mask */
+    RTK_CHK_PORTMASK_VALID(pPortmask);
+
+    if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicSystemLutLearnPortMask(pmask)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_limitSystemLearningCntPortMask_get
+ * Description:
+ *      get system auto learn portmask
+ * Input:
+ *      None
+ * Output:
+ *      pPortmask - Port Mask
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_NULL_POINTER - Null pointer.
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_l2_limitSystemLearningCntPortMask_get(rtk_portmask_t *pPortmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pPortmask)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicSystemLutLearnPortMask(&pmask)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_learningCnt_get
+ * Description:
+ *      Get per-Port current auto learning number
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pMac_cnt - ASIC auto learning entries number
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get per-port ASIC auto learning number
+ */
+rtk_api_ret_t rtk_l2_learningCnt_get(rtk_port_t port, rtk_mac_cnt_t *pMac_cnt)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pMac_cnt)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicLutLearnNo(rtk_switch_port_L2P_get(port), pMac_cnt)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_floodPortMask_set
+ * Description:
+ *      Set flooding portmask
+ * Input:
+ *      type - flooding type.
+ *      pFlood_portmask - flooding porkmask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK    - Invalid portmask.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API can set the flooding mask.
+ *      The flooding type is as following:
+ *      - FLOOD_UNKNOWNDA
+ *      - FLOOD_UNKNOWNMC
+ *      - FLOOD_BC
+ */
+rtk_api_ret_t rtk_l2_floodPortMask_set(rtk_l2_flood_type_t floood_type, rtk_portmask_t *pFlood_portmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (floood_type >= FLOOD_END)
+        return RT_ERR_INPUT;
+
+    /* check port valid */
+    RTK_CHK_PORTMASK_VALID(pFlood_portmask);
+
+    /* Get Physical port mask */
+    if ((retVal = rtk_switch_portmask_L2P_get(pFlood_portmask, &pmask))!=RT_ERR_OK)
+        return retVal;
+
+    switch (floood_type)
+    {
+        case FLOOD_UNKNOWNDA:
+            if ((retVal = rtl8367c_setAsicPortUnknownDaFloodingPortmask(pmask)) != RT_ERR_OK)
+                return retVal;
+            break;
+        case FLOOD_UNKNOWNMC:
+            if ((retVal = rtl8367c_setAsicPortUnknownMulticastFloodingPortmask(pmask)) != RT_ERR_OK)
+                return retVal;
+            break;
+        case FLOOD_BC:
+            if ((retVal = rtl8367c_setAsicPortBcastFloodingPortmask(pmask)) != RT_ERR_OK)
+                return retVal;
+            break;
+        default:
+            break;
+    }
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtk_l2_floodPortMask_get
+ * Description:
+ *      Get flooding portmask
+ * Input:
+ *      type - flooding type.
+ * Output:
+ *      pFlood_portmask - flooding porkmask
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API can get the flooding mask.
+ *      The flooding type is as following:
+ *      - FLOOD_UNKNOWNDA
+ *      - FLOOD_UNKNOWNMC
+ *      - FLOOD_BC
+ */
+rtk_api_ret_t rtk_l2_floodPortMask_get(rtk_l2_flood_type_t floood_type, rtk_portmask_t *pFlood_portmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (floood_type >= FLOOD_END)
+        return RT_ERR_INPUT;
+
+    if(NULL == pFlood_portmask)
+        return RT_ERR_NULL_POINTER;
+
+    switch (floood_type)
+    {
+        case FLOOD_UNKNOWNDA:
+            if ((retVal = rtl8367c_getAsicPortUnknownDaFloodingPortmask(&pmask)) != RT_ERR_OK)
+                return retVal;
+            break;
+        case FLOOD_UNKNOWNMC:
+            if ((retVal = rtl8367c_getAsicPortUnknownMulticastFloodingPortmask(&pmask)) != RT_ERR_OK)
+                return retVal;
+            break;
+        case FLOOD_BC:
+            if ((retVal = rtl8367c_getAsicPortBcastFloodingPortmask(&pmask)) != RT_ERR_OK)
+                return retVal;
+            break;
+        default:
+            break;
+    }
+
+    /* Get Logical port mask */
+    if ((retVal = rtk_switch_portmask_P2L_get(pmask, pFlood_portmask))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_localPktPermit_set
+ * Description:
+ *      Set permittion of frames if source port and destination port are the same.
+ * Input:
+ *      port - Port id.
+ *      permit - permittion status
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_ENABLE       - Invalid permit value.
+ * Note:
+ *      This API is setted to permit frame if its source port is equal to destination port.
+ */
+rtk_api_ret_t rtk_l2_localPktPermit_set(rtk_port_t port, rtk_enable_t permit)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (permit >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if ((retVal = rtl8367c_setAsicPortBlockSpa(rtk_switch_port_L2P_get(port), permit)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_localPktPermit_get
+ * Description:
+ *      Get permittion of frames if source port and destination port are the same.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pPermit - permittion status
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API is to get permittion status for frames if its source port is equal to destination port.
+ */
+rtk_api_ret_t rtk_l2_localPktPermit_get(rtk_port_t port, rtk_enable_t *pPermit)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pPermit)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicPortBlockSpa(rtk_switch_port_L2P_get(port), pPermit)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_aging_set
+ * Description:
+ *      Set LUT agging out speed
+ * Input:
+ *      aging_time - Agging out time.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - input out of range.
+ * Note:
+ *      The API can set LUT agging out period for each entry and the range is from 45s to 458s.
+ */
+rtk_api_ret_t rtk_l2_aging_set(rtk_l2_age_time_t aging_time)
+{
+    rtk_uint32 i;
+    CONST_T rtk_uint32 agePara[10][3] = {
+        {45, 0, 1}, {88, 0, 2}, {133, 0, 3}, {177, 0, 4}, {221, 0, 5}, {266, 0, 6}, {310, 0, 7},
+        {354, 2, 6}, {413, 2, 7}, {458, 3, 7}};
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (aging_time>agePara[9][0])
+        return RT_ERR_OUT_OF_RANGE;
+
+    for (i = 0; i<10; i++)
+    {
+        if (aging_time<=agePara[i][0])
+        {
+            return rtl8367c_setAsicLutAgeTimerSpeed(agePara[i][2], agePara[i][1]);
+        }
+    }
+
+    return RT_ERR_FAILED;
+}
+
+/* Function Name:
+ *      rtk_l2_aging_get
+ * Description:
+ *      Get LUT agging out time
+ * Input:
+ *      None
+ * Output:
+ *      pEnable - Aging status
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get LUT agging out period for each entry.
+ */
+rtk_api_ret_t rtk_l2_aging_get(rtk_l2_age_time_t *pAging_time)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 i,time, speed;
+    CONST_T rtk_uint32 agePara[10][3] = {
+        {45, 0, 1}, {88, 0, 2}, {133, 0, 3}, {177, 0, 4}, {221, 0, 5}, {266, 0, 6}, {310, 0, 7},
+        {354, 2, 6}, {413, 2, 7}, {458, 3, 7}};
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pAging_time)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicLutAgeTimerSpeed(&time, &speed)) != RT_ERR_OK)
+        return retVal;
+
+    for (i = 0; i<10; i++)
+    {
+        if (time==agePara[i][2]&&speed==agePara[i][1])
+        {
+            *pAging_time = agePara[i][0];
+            return RT_ERR_OK;
+        }
+    }
+
+    return RT_ERR_FAILED;
+}
+
+/* Function Name:
+ *      rtk_l2_ipMcastAddrLookup_set
+ * Description:
+ *      Set Lut IP multicast lookup function
+ * Input:
+ *      type - Lookup type for IPMC packet.
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK          - OK
+ *      RT_ERR_FAILED      - Failed
+ *      RT_ERR_SMI         - SMI access error
+ * Note:
+ *      LOOKUP_MAC      - Lookup by MAC address
+ *      LOOKUP_IP       - Lookup by IP address
+ *      LOOKUP_IP_VID   - Lookup by IP address & VLAN ID
+ */
+rtk_api_ret_t rtk_l2_ipMcastAddrLookup_set(rtk_l2_ipmc_lookup_type_t type)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(type == LOOKUP_MAC)
+    {
+        if((retVal = rtl8367c_setAsicLutIpMulticastLookup(DISABLED)) != RT_ERR_OK)
+            return retVal;
+    }
+    else if(type == LOOKUP_IP)
+    {
+        if((retVal = rtl8367c_setAsicLutIpMulticastLookup(ENABLED)) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicLutIpMulticastVidLookup(DISABLED))!=RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicLutIpLookupMethod(1))!=RT_ERR_OK)
+            return retVal;
+    }
+    else if(type == LOOKUP_IP_VID)
+    {
+        if((retVal = rtl8367c_setAsicLutIpMulticastLookup(ENABLED)) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicLutIpMulticastVidLookup(ENABLED))!=RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicLutIpLookupMethod(1))!=RT_ERR_OK)
+            return retVal;
+    }
+    else
+        return RT_ERR_INPUT;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_ipMcastAddrLookup_get
+ * Description:
+ *      Get Lut IP multicast lookup function
+ * Input:
+ *      None.
+ * Output:
+ *      pType - Lookup type for IPMC packet.
+ * Return:
+ *      RT_ERR_OK          - OK
+ *      RT_ERR_FAILED      - Failed
+ *      RT_ERR_SMI         - SMI access error
+ * Note:
+ *      None.
+ */
+rtk_api_ret_t rtk_l2_ipMcastAddrLookup_get(rtk_l2_ipmc_lookup_type_t *pType)
+{
+    rtk_api_ret_t       retVal;
+    rtk_uint32          enabled, vid_lookup;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pType)
+        return RT_ERR_NULL_POINTER;
+
+    if((retVal = rtl8367c_getAsicLutIpMulticastLookup(&enabled)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicLutIpMulticastVidLookup(&vid_lookup))!=RT_ERR_OK)
+        return retVal;
+
+    if(enabled == ENABLED)
+    {
+        if(vid_lookup == ENABLED)
+            *pType = LOOKUP_IP_VID;
+        else
+            *pType = LOOKUP_IP;
+    }
+    else
+        *pType = LOOKUP_MAC;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_ipMcastForwardRouterPort_set
+ * Description:
+ *      Set IPMC packet forward to rounter port also or not
+ * Input:
+ *      enabled - 1: Inlcude router port, 0, exclude router port
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK          - OK
+ *      RT_ERR_FAILED      - Failed
+ *      RT_ERR_SMI         - SMI access error
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_l2_ipMcastForwardRouterPort_set(rtk_enable_t enabled)
+{
+    rtk_api_ret_t       retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (enabled >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if((retVal = rtl8367c_setAsicLutIpmcFwdRouterPort(enabled)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_ipMcastForwardRouterPort_get
+ * Description:
+ *      Get IPMC packet forward to rounter port also or not
+ * Input:
+ *      None.
+ * Output:
+ *      pEnabled    - 1: Inlcude router port, 0, exclude router port
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_NULL_POINTER - Null pointer
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_l2_ipMcastForwardRouterPort_get(rtk_enable_t *pEnabled)
+{
+    rtk_api_ret_t       retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (NULL == pEnabled)
+        return RT_ERR_NULL_POINTER;
+
+    if((retVal = rtl8367c_getAsicLutIpmcFwdRouterPort(pEnabled)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_ipMcastGroupEntry_add
+ * Description:
+ *      Add an IP Multicast entry to group table
+ * Input:
+ *      ip_addr     - IP address
+ *      vid         - VLAN ID
+ *      pPortmask   - portmask
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK          - OK
+ *      RT_ERR_FAILED      - Failed
+ *      RT_ERR_SMI         - SMI access error
+ *      RT_ERR_TBL_FULL    - Table Full
+ * Note:
+ *      Add an entry to IP Multicast Group table.
+ */
+rtk_api_ret_t rtk_l2_ipMcastGroupEntry_add(ipaddr_t ip_addr, rtk_uint32 vid, rtk_portmask_t *pPortmask)
+{
+    rtk_uint32      empty_idx = 0xFFFF;
+    rtk_int32       index;
+    ipaddr_t        group_addr;
+    rtk_uint32      group_vid;
+    rtk_uint32      pmask;
+    rtk_uint32      valid;
+    rtk_uint32      physicalPortmask;
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (vid > RTL8367C_VIDMAX)
+        return RT_ERR_L2_VID;
+
+    if(NULL == pPortmask)
+        return RT_ERR_NULL_POINTER;
+
+    if((ip_addr & 0xF0000000) != 0xE0000000)
+        return RT_ERR_INPUT;
+
+    /* Get Physical port mask */
+    if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &physicalPortmask))!=RT_ERR_OK)
+        return retVal;
+
+    for(index = 0; index <= RTL8367C_LUT_IPMCGRP_TABLE_MAX; index++)
+    {
+        if ((retVal = rtl8367c_getAsicLutIPMCGroup((rtk_uint32)index, &group_addr, &group_vid, &pmask, &valid))!=RT_ERR_OK)
+            return retVal;
+
+        if( (valid == ENABLED) && (group_addr == ip_addr) && (group_vid == vid) )
+        {
+            if(pmask != physicalPortmask)
+            {
+                pmask = physicalPortmask;
+                if ((retVal = rtl8367c_setAsicLutIPMCGroup(index, ip_addr, vid, pmask, valid))!=RT_ERR_OK)
+                    return retVal;
+            }
+
+            return RT_ERR_OK;
+        }
+
+        if( (valid == DISABLED) && (empty_idx == 0xFFFF) ) /* Unused */
+            empty_idx = (rtk_uint32)index;
+    }
+
+    if(empty_idx == 0xFFFF)
+        return RT_ERR_TBL_FULL;
+
+    pmask = physicalPortmask;
+    if ((retVal = rtl8367c_setAsicLutIPMCGroup(empty_idx, ip_addr, vid, pmask, ENABLED))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_l2_ipMcastGroupEntry_del
+ * Description:
+ *      Delete an entry from IP Multicast group table
+ * Input:
+ *      ip_addr     - IP address
+ *      vid         - VLAN ID
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK          - OK
+ *      RT_ERR_FAILED      - Failed
+ *      RT_ERR_SMI         - SMI access error
+ *      RT_ERR_TBL_FULL    - Table Full
+ * Note:
+ *      Delete an entry from IP Multicast group table.
+ */
+rtk_api_ret_t rtk_l2_ipMcastGroupEntry_del(ipaddr_t ip_addr, rtk_uint32 vid)
+{
+    rtk_int32       index;
+    ipaddr_t        group_addr;
+    rtk_uint32      group_vid;
+    rtk_uint32      pmask;
+    rtk_uint32      valid;
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (vid > RTL8367C_VIDMAX)
+        return RT_ERR_L2_VID;
+
+    if((ip_addr & 0xF0000000) != 0xE0000000)
+        return RT_ERR_INPUT;
+
+    for(index = 0; index <= RTL8367C_LUT_IPMCGRP_TABLE_MAX; index++)
+    {
+        if ((retVal = rtl8367c_getAsicLutIPMCGroup((rtk_uint32)index, &group_addr, &group_vid, &pmask, &valid))!=RT_ERR_OK)
+            return retVal;
+
+        if( (valid == ENABLED) && (group_addr == ip_addr) && (group_vid == vid) )
+        {
+            group_addr = 0xE0000000;
+            group_vid = 0;
+            pmask = 0;
+            if ((retVal = rtl8367c_setAsicLutIPMCGroup(index, group_addr, group_vid, pmask, DISABLED))!=RT_ERR_OK)
+                return retVal;
+
+            return RT_ERR_OK;
+        }
+    }
+
+    return RT_ERR_FAILED;
+}
+
+/* Function Name:
+ *      rtk_l2_ipMcastGroupEntry_get
+ * Description:
+ *      get an entry from IP Multicast group table
+ * Input:
+ *      ip_addr     - IP address
+ *      vid         - VLAN ID
+ * Output:
+ *      pPortmask   - member port mask
+ * Return:
+ *      RT_ERR_OK          - OK
+ *      RT_ERR_FAILED      - Failed
+ *      RT_ERR_SMI         - SMI access error
+ *      RT_ERR_TBL_FULL    - Table Full
+ * Note:
+ *      Delete an entry from IP Multicast group table.
+ */
+rtk_api_ret_t rtk_l2_ipMcastGroupEntry_get(ipaddr_t ip_addr, rtk_uint32 vid, rtk_portmask_t *pPortmask)
+{
+    rtk_int32       index;
+    ipaddr_t        group_addr;
+    rtk_uint32      group_vid;
+    rtk_uint32      valid;
+    rtk_uint32      pmask;
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if((ip_addr & 0xF0000000) != 0xE0000000)
+        return RT_ERR_INPUT;
+
+    if (vid > RTL8367C_VIDMAX)
+        return RT_ERR_L2_VID;
+
+    if(NULL == pPortmask)
+        return RT_ERR_NULL_POINTER;
+
+    for(index = 0; index <= RTL8367C_LUT_IPMCGRP_TABLE_MAX; index++)
+    {
+        if ((retVal = rtl8367c_getAsicLutIPMCGroup((rtk_uint32)index, &group_addr, &group_vid, &pmask, &valid))!=RT_ERR_OK)
+            return retVal;
+
+        if( (valid == ENABLED) && (group_addr == ip_addr) && (group_vid == vid) )
+        {
+            if ((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask))!=RT_ERR_OK)
+                return retVal;
+
+            return RT_ERR_OK;
+        }
+    }
+
+    return RT_ERR_FAILED;
+}
+
+/* Function Name:
+ *      rtk_l2_entry_get
+ * Description:
+ *      Get LUT unicast entry.
+ * Input:
+ *      pL2_entry - Index field in the structure.
+ * Output:
+ *      pL2_entry - other fields such as MAC, port, age...
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_L2_EMPTY_ENTRY   - Empty LUT entry.
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ * Note:
+ *      This API is used to get address by index from 0~2111.
+ */
+rtk_api_ret_t rtk_l2_entry_get(rtk_l2_addr_table_t *pL2_entry)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 method;
+    rtl8367c_luttb l2Table;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (pL2_entry->index >= rtk_switch_maxLutAddrNumber_get())
+        return RT_ERR_INPUT;
+
+    memset(&l2Table, 0x00, sizeof(rtl8367c_luttb));
+    l2Table.address= pL2_entry->index;
+    method = LUTREADMETHOD_ADDRESS;
+    if ((retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table)) != RT_ERR_OK)
+        return retVal;
+
+    if ((pL2_entry->index>0x800)&&(l2Table.lookup_hit==0))
+         return RT_ERR_L2_EMPTY_ENTRY;
+
+    if(l2Table.l3lookup)
+    {
+        if(l2Table.l3vidlookup)
+        {
+            memset(&pL2_entry->mac, 0, sizeof(rtk_mac_t));
+            pL2_entry->is_ipmul  = l2Table.l3lookup;
+            pL2_entry->sip       = l2Table.sip;
+            pL2_entry->dip       = l2Table.dip;
+            pL2_entry->is_static = l2Table.nosalearn;
+
+            /* Get Logical port mask */
+            if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &(pL2_entry->portmask)))!=RT_ERR_OK)
+                return retVal;
+
+            pL2_entry->fid       = 0;
+            pL2_entry->age       = 0;
+            pL2_entry->auth      = 0;
+            pL2_entry->sa_block  = 0;
+            pL2_entry->is_ipvidmul = 1;
+            pL2_entry->l3_vid      = l2Table.l3_vid;
+        }
+        else
+        {
+            memset(&pL2_entry->mac, 0, sizeof(rtk_mac_t));
+            pL2_entry->is_ipmul  = l2Table.l3lookup;
+            pL2_entry->sip       = l2Table.sip;
+            pL2_entry->dip       = l2Table.dip;
+            pL2_entry->is_static = l2Table.nosalearn;
+
+            /* Get Logical port mask */
+            if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &(pL2_entry->portmask)))!=RT_ERR_OK)
+                return retVal;
+
+            pL2_entry->fid       = 0;
+            pL2_entry->age       = 0;
+            pL2_entry->auth      = 0;
+            pL2_entry->sa_block  = 0;
+            pL2_entry->is_ipvidmul = 0;
+            pL2_entry->l3_vid      = 0;
+        }
+    }
+    else if(l2Table.mac.octet[0]&0x01)
+    {
+        memset(&pL2_entry->sip, 0, sizeof(ipaddr_t));
+        memset(&pL2_entry->dip, 0, sizeof(ipaddr_t));
+        pL2_entry->mac.octet[0] = l2Table.mac.octet[0];
+        pL2_entry->mac.octet[1] = l2Table.mac.octet[1];
+        pL2_entry->mac.octet[2] = l2Table.mac.octet[2];
+        pL2_entry->mac.octet[3] = l2Table.mac.octet[3];
+        pL2_entry->mac.octet[4] = l2Table.mac.octet[4];
+        pL2_entry->mac.octet[5] = l2Table.mac.octet[5];
+        pL2_entry->is_ipmul  = l2Table.l3lookup;
+        pL2_entry->is_static = l2Table.nosalearn;
+
+        /* Get Logical port mask */
+        if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &(pL2_entry->portmask)))!=RT_ERR_OK)
+            return retVal;
+
+        pL2_entry->ivl       = l2Table.ivl_svl;
+        if(l2Table.ivl_svl == 1) /* IVL */
+        {
+            pL2_entry->cvid      = l2Table.cvid_fid;
+            pL2_entry->fid       = 0;
+        }
+        else /* SVL*/
+        {
+            pL2_entry->cvid      = 0;
+            pL2_entry->fid       = l2Table.cvid_fid;
+        }
+        pL2_entry->auth      = l2Table.auth;
+        pL2_entry->sa_block  = l2Table.sa_block;
+        pL2_entry->age       = 0;
+        pL2_entry->is_ipvidmul = 0;
+        pL2_entry->l3_vid      = 0;
+    }
+    else if((l2Table.age != 0)||(l2Table.nosalearn == 1))
+    {
+        memset(&pL2_entry->sip, 0, sizeof(ipaddr_t));
+        memset(&pL2_entry->dip, 0, sizeof(ipaddr_t));
+        pL2_entry->mac.octet[0] = l2Table.mac.octet[0];
+        pL2_entry->mac.octet[1] = l2Table.mac.octet[1];
+        pL2_entry->mac.octet[2] = l2Table.mac.octet[2];
+        pL2_entry->mac.octet[3] = l2Table.mac.octet[3];
+        pL2_entry->mac.octet[4] = l2Table.mac.octet[4];
+        pL2_entry->mac.octet[5] = l2Table.mac.octet[5];
+        pL2_entry->is_ipmul  = l2Table.l3lookup;
+        pL2_entry->is_static = l2Table.nosalearn;
+
+        /* Get Logical port mask */
+        if ((retVal = rtk_switch_portmask_P2L_get(1<<(l2Table.spa), &(pL2_entry->portmask)))!=RT_ERR_OK)
+            return retVal;
+
+        pL2_entry->ivl       = l2Table.ivl_svl;
+        pL2_entry->cvid      = l2Table.cvid_fid;
+        pL2_entry->fid       = l2Table.fid;
+        pL2_entry->auth      = l2Table.auth;
+        pL2_entry->sa_block  = l2Table.sa_block;
+        pL2_entry->age       = l2Table.age;
+        pL2_entry->is_ipvidmul = 0;
+        pL2_entry->l3_vid      = 0;
+    }
+    else
+       return RT_ERR_L2_EMPTY_ENTRY;
+
+    return RT_ERR_OK;
+}
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/leaky.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/leaky.c
new file mode 100644
index 0000000..1b7d50a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/leaky.c
@@ -0,0 +1,590 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in Leaky module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <leaky.h>
+#include <string.h>
+
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_portIsolation.h>
+#include <rtl8367c_asicdrv_rma.h>
+#include <rtl8367c_asicdrv_igmp.h>
+
+
+/* Function Name:
+ *      rtk_leaky_vlan_set
+ * Description:
+ *      Set VLAN leaky.
+ * Input:
+ *      type - Packet type for VLAN leaky.
+ *      enable - Leaky status.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_ENABLE       - Invalid enable input
+ * Note:
+ *      This API can set VLAN leaky for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP packets.
+ *      The leaky frame types are as following:
+ *      - LEAKY_BRG_GROUP,
+ *      - LEAKY_FD_PAUSE,
+ *      - LEAKY_SP_MCAST,
+ *      - LEAKY_1X_PAE,
+ *      - LEAKY_UNDEF_BRG_04,
+ *      - LEAKY_UNDEF_BRG_05,
+ *      - LEAKY_UNDEF_BRG_06,
+ *      - LEAKY_UNDEF_BRG_07,
+ *      - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS,
+ *      - LEAKY_UNDEF_BRG_09,
+ *      - LEAKY_UNDEF_BRG_0A,
+ *      - LEAKY_UNDEF_BRG_0B,
+ *      - LEAKY_UNDEF_BRG_0C,
+ *      - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS,
+ *      - LEAKY_8021AB,
+ *      - LEAKY_UNDEF_BRG_0F,
+ *      - LEAKY_BRG_MNGEMENT,
+ *      - LEAKY_UNDEFINED_11,
+ *      - LEAKY_UNDEFINED_12,
+ *      - LEAKY_UNDEFINED_13,
+ *      - LEAKY_UNDEFINED_14,
+ *      - LEAKY_UNDEFINED_15,
+ *      - LEAKY_UNDEFINED_16,
+ *      - LEAKY_UNDEFINED_17,
+ *      - LEAKY_UNDEFINED_18,
+ *      - LEAKY_UNDEFINED_19,
+ *      - LEAKY_UNDEFINED_1A,
+ *      - LEAKY_UNDEFINED_1B,
+ *      - LEAKY_UNDEFINED_1C,
+ *      - LEAKY_UNDEFINED_1D,
+ *      - LEAKY_UNDEFINED_1E,
+ *      - LEAKY_UNDEFINED_1F,
+ *      - LEAKY_GMRP,
+ *      - LEAKY_GVRP,
+ *      - LEAKY_UNDEF_GARP_22,
+ *      - LEAKY_UNDEF_GARP_23,
+ *      - LEAKY_UNDEF_GARP_24,
+ *      - LEAKY_UNDEF_GARP_25,
+ *      - LEAKY_UNDEF_GARP_26,
+ *      - LEAKY_UNDEF_GARP_27,
+ *      - LEAKY_UNDEF_GARP_28,
+ *      - LEAKY_UNDEF_GARP_29,
+ *      - LEAKY_UNDEF_GARP_2A,
+ *      - LEAKY_UNDEF_GARP_2B,
+ *      - LEAKY_UNDEF_GARP_2C,
+ *      - LEAKY_UNDEF_GARP_2D,
+ *      - LEAKY_UNDEF_GARP_2E,
+ *      - LEAKY_UNDEF_GARP_2F,
+ *      - LEAKY_IGMP,
+ *      - LEAKY_IPMULTICAST.
+ *      - LEAKY_CDP,
+ *      - LEAKY_CSSTP,
+ *      - LEAKY_LLDP.
+ */
+rtk_api_ret_t rtk_leaky_vlan_set(rtk_leaky_type_t type, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 port;
+    rtl8367c_rma_t rmacfg;
+    rtk_uint32 tmp;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (type >= LEAKY_END)
+        return RT_ERR_INPUT;
+
+    if (enable >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if (type >= 0 && type <= LEAKY_UNDEF_GARP_2F)
+    {
+        if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        rmacfg.vlan_leaky = enable;
+
+        if ((retVal = rtl8367c_setAsicRma(type, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+    }
+    else if (LEAKY_IPMULTICAST == type)
+    {
+        for (port = 0; port <= RTK_PORT_ID_MAX; port++)
+        {
+            if ((retVal = rtl8367c_setAsicIpMulticastVlanLeaky(port,enable)) != RT_ERR_OK)
+                return retVal;
+        }
+    }
+    else if (LEAKY_IGMP == type)
+    {
+        if ((retVal = rtl8367c_setAsicIGMPVLANLeaky(enable)) != RT_ERR_OK)
+            return retVal;
+    }
+    else if (LEAKY_CDP == type)
+    {
+        if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        rmacfg.vlan_leaky = enable;
+
+        if ((retVal = rtl8367c_setAsicRmaCdp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+    }
+    else if (LEAKY_CSSTP == type)
+    {
+        if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        rmacfg.vlan_leaky = enable;
+
+        if ((retVal = rtl8367c_setAsicRmaCsstp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+    }
+    else if (LEAKY_LLDP == type)
+    {
+        if ((retVal = rtl8367c_getAsicRmaLldp(&tmp,&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        rmacfg.vlan_leaky = enable;
+
+        if ((retVal = rtl8367c_setAsicRmaLldp(tmp, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_leaky_vlan_get
+ * Description:
+ *      Get VLAN leaky.
+ * Input:
+ *      type - Packet type for VLAN leaky.
+ * Output:
+ *      pEnable - Leaky status.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API can get VLAN leaky status for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP  packets.
+ *      The leaky frame types are as following:
+ *      - LEAKY_BRG_GROUP,
+ *      - LEAKY_FD_PAUSE,
+ *      - LEAKY_SP_MCAST,
+ *      - LEAKY_1X_PAE,
+ *      - LEAKY_UNDEF_BRG_04,
+ *      - LEAKY_UNDEF_BRG_05,
+ *      - LEAKY_UNDEF_BRG_06,
+ *      - LEAKY_UNDEF_BRG_07,
+ *      - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS,
+ *      - LEAKY_UNDEF_BRG_09,
+ *      - LEAKY_UNDEF_BRG_0A,
+ *      - LEAKY_UNDEF_BRG_0B,
+ *      - LEAKY_UNDEF_BRG_0C,
+ *      - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS,
+ *      - LEAKY_8021AB,
+ *      - LEAKY_UNDEF_BRG_0F,
+ *      - LEAKY_BRG_MNGEMENT,
+ *      - LEAKY_UNDEFINED_11,
+ *      - LEAKY_UNDEFINED_12,
+ *      - LEAKY_UNDEFINED_13,
+ *      - LEAKY_UNDEFINED_14,
+ *      - LEAKY_UNDEFINED_15,
+ *      - LEAKY_UNDEFINED_16,
+ *      - LEAKY_UNDEFINED_17,
+ *      - LEAKY_UNDEFINED_18,
+ *      - LEAKY_UNDEFINED_19,
+ *      - LEAKY_UNDEFINED_1A,
+ *      - LEAKY_UNDEFINED_1B,
+ *      - LEAKY_UNDEFINED_1C,
+ *      - LEAKY_UNDEFINED_1D,
+ *      - LEAKY_UNDEFINED_1E,
+ *      - LEAKY_UNDEFINED_1F,
+ *      - LEAKY_GMRP,
+ *      - LEAKY_GVRP,
+ *      - LEAKY_UNDEF_GARP_22,
+ *      - LEAKY_UNDEF_GARP_23,
+ *      - LEAKY_UNDEF_GARP_24,
+ *      - LEAKY_UNDEF_GARP_25,
+ *      - LEAKY_UNDEF_GARP_26,
+ *      - LEAKY_UNDEF_GARP_27,
+ *      - LEAKY_UNDEF_GARP_28,
+ *      - LEAKY_UNDEF_GARP_29,
+ *      - LEAKY_UNDEF_GARP_2A,
+ *      - LEAKY_UNDEF_GARP_2B,
+ *      - LEAKY_UNDEF_GARP_2C,
+ *      - LEAKY_UNDEF_GARP_2D,
+ *      - LEAKY_UNDEF_GARP_2E,
+ *      - LEAKY_UNDEF_GARP_2F,
+ *      - LEAKY_IGMP,
+ *      - LEAKY_IPMULTICAST.
+ *      - LEAKY_CDP,
+ *      - LEAKY_CSSTP,
+ *      - LEAKY_LLDP.
+ */
+rtk_api_ret_t rtk_leaky_vlan_get(rtk_leaky_type_t type, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 port,tmp;
+    rtl8367c_rma_t rmacfg;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (type >= LEAKY_END)
+        return RT_ERR_INPUT;
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if (type >= 0 && type <= LEAKY_UNDEF_GARP_2F)
+    {
+        if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        *pEnable = rmacfg.vlan_leaky;
+
+    }
+    else if (LEAKY_IPMULTICAST == type)
+    {
+        for (port = 0; port <= RTK_PORT_ID_MAX; port++)
+        {
+            if ((retVal = rtl8367c_getAsicIpMulticastVlanLeaky(port, &tmp)) != RT_ERR_OK)
+                return retVal;
+            if (port>0&&(tmp!=*pEnable))
+                return RT_ERR_FAILED;
+            *pEnable = tmp;
+        }
+    }
+    else if (LEAKY_IGMP == type)
+    {
+        if ((retVal = rtl8367c_getAsicIGMPVLANLeaky(&tmp)) != RT_ERR_OK)
+            return retVal;
+
+        *pEnable = tmp;
+    }
+    else if (LEAKY_CDP == type)
+    {
+        if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        *pEnable = rmacfg.vlan_leaky;
+    }
+    else if (LEAKY_CSSTP == type)
+    {
+        if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        *pEnable = rmacfg.vlan_leaky;
+    }
+    else if (LEAKY_LLDP == type)
+    {
+        if ((retVal = rtl8367c_getAsicRmaLldp(&tmp, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        *pEnable = rmacfg.vlan_leaky;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_leaky_portIsolation_set
+ * Description:
+ *      Set port isolation leaky.
+ * Input:
+ *      type - Packet type for port isolation leaky.
+ *      enable - Leaky status.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_ENABLE       - Invalid enable input
+ * Note:
+ *      This API can set port isolation leaky for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP  packets.
+ *      The leaky frame types are as following:
+ *      - LEAKY_BRG_GROUP,
+ *      - LEAKY_FD_PAUSE,
+ *      - LEAKY_SP_MCAST,
+ *      - LEAKY_1X_PAE,
+ *      - LEAKY_UNDEF_BRG_04,
+ *      - LEAKY_UNDEF_BRG_05,
+ *      - LEAKY_UNDEF_BRG_06,
+ *      - LEAKY_UNDEF_BRG_07,
+ *      - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS,
+ *      - LEAKY_UNDEF_BRG_09,
+ *      - LEAKY_UNDEF_BRG_0A,
+ *      - LEAKY_UNDEF_BRG_0B,
+ *      - LEAKY_UNDEF_BRG_0C,
+ *      - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS,
+ *      - LEAKY_8021AB,
+ *      - LEAKY_UNDEF_BRG_0F,
+ *      - LEAKY_BRG_MNGEMENT,
+ *      - LEAKY_UNDEFINED_11,
+ *      - LEAKY_UNDEFINED_12,
+ *      - LEAKY_UNDEFINED_13,
+ *      - LEAKY_UNDEFINED_14,
+ *      - LEAKY_UNDEFINED_15,
+ *      - LEAKY_UNDEFINED_16,
+ *      - LEAKY_UNDEFINED_17,
+ *      - LEAKY_UNDEFINED_18,
+ *      - LEAKY_UNDEFINED_19,
+ *      - LEAKY_UNDEFINED_1A,
+ *      - LEAKY_UNDEFINED_1B,
+ *      - LEAKY_UNDEFINED_1C,
+ *      - LEAKY_UNDEFINED_1D,
+ *      - LEAKY_UNDEFINED_1E,
+ *      - LEAKY_UNDEFINED_1F,
+ *      - LEAKY_GMRP,
+ *      - LEAKY_GVRP,
+ *      - LEAKY_UNDEF_GARP_22,
+ *      - LEAKY_UNDEF_GARP_23,
+ *      - LEAKY_UNDEF_GARP_24,
+ *      - LEAKY_UNDEF_GARP_25,
+ *      - LEAKY_UNDEF_GARP_26,
+ *      - LEAKY_UNDEF_GARP_27,
+ *      - LEAKY_UNDEF_GARP_28,
+ *      - LEAKY_UNDEF_GARP_29,
+ *      - LEAKY_UNDEF_GARP_2A,
+ *      - LEAKY_UNDEF_GARP_2B,
+ *      - LEAKY_UNDEF_GARP_2C,
+ *      - LEAKY_UNDEF_GARP_2D,
+ *      - LEAKY_UNDEF_GARP_2E,
+ *      - LEAKY_UNDEF_GARP_2F,
+ *      - LEAKY_IGMP,
+ *      - LEAKY_IPMULTICAST.
+ *      - LEAKY_CDP,
+ *      - LEAKY_CSSTP,
+ *      - LEAKY_LLDP.
+ */
+rtk_api_ret_t rtk_leaky_portIsolation_set(rtk_leaky_type_t type, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 port;
+    rtl8367c_rma_t rmacfg;
+    rtk_uint32 tmp;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (type >= LEAKY_END)
+        return RT_ERR_INPUT;
+
+    if (enable >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if (type >= 0 && type <= LEAKY_UNDEF_GARP_2F)
+    {
+        if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        rmacfg.portiso_leaky = enable;
+
+        if ((retVal = rtl8367c_setAsicRma(type, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+    }
+    else if (LEAKY_IPMULTICAST == type)
+    {
+        for (port = 0; port < RTK_MAX_NUM_OF_PORT; port++)
+        {
+            if ((retVal = rtl8367c_setAsicIpMulticastPortIsoLeaky(port,enable)) != RT_ERR_OK)
+                return retVal;
+        }
+    }
+    else if (LEAKY_IGMP == type)
+    {
+        if ((retVal = rtl8367c_setAsicIGMPIsoLeaky(enable)) != RT_ERR_OK)
+            return retVal;
+    }
+    else if (LEAKY_CDP == type)
+    {
+        if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        rmacfg.portiso_leaky = enable;
+
+        if ((retVal = rtl8367c_setAsicRmaCdp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+    }
+    else if (LEAKY_CSSTP == type)
+    {
+        if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        rmacfg.portiso_leaky = enable;
+
+        if ((retVal = rtl8367c_setAsicRmaCsstp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+    }
+    else if (LEAKY_LLDP == type)
+    {
+        if ((retVal = rtl8367c_getAsicRmaLldp(&tmp, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        rmacfg.portiso_leaky = enable;
+
+        if ((retVal = rtl8367c_setAsicRmaLldp(tmp, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_leaky_portIsolation_get
+ * Description:
+ *      Get port isolation leaky.
+ * Input:
+ *      type - Packet type for port isolation leaky.
+ * Output:
+ *      pEnable - Leaky status.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API can get port isolation leaky status for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP  packets.
+ *      The leaky frame types are as following:
+ *      - LEAKY_BRG_GROUP,
+ *      - LEAKY_FD_PAUSE,
+ *      - LEAKY_SP_MCAST,
+ *      - LEAKY_1X_PAE,
+ *      - LEAKY_UNDEF_BRG_04,
+ *      - LEAKY_UNDEF_BRG_05,
+ *      - LEAKY_UNDEF_BRG_06,
+ *      - LEAKY_UNDEF_BRG_07,
+ *      - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS,
+ *      - LEAKY_UNDEF_BRG_09,
+ *      - LEAKY_UNDEF_BRG_0A,
+ *      - LEAKY_UNDEF_BRG_0B,
+ *      - LEAKY_UNDEF_BRG_0C,
+ *      - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS,
+ *      - LEAKY_8021AB,
+ *      - LEAKY_UNDEF_BRG_0F,
+ *      - LEAKY_BRG_MNGEMENT,
+ *      - LEAKY_UNDEFINED_11,
+ *      - LEAKY_UNDEFINED_12,
+ *      - LEAKY_UNDEFINED_13,
+ *      - LEAKY_UNDEFINED_14,
+ *      - LEAKY_UNDEFINED_15,
+ *      - LEAKY_UNDEFINED_16,
+ *      - LEAKY_UNDEFINED_17,
+ *      - LEAKY_UNDEFINED_18,
+ *      - LEAKY_UNDEFINED_19,
+ *      - LEAKY_UNDEFINED_1A,
+ *      - LEAKY_UNDEFINED_1B,
+ *      - LEAKY_UNDEFINED_1C,
+ *      - LEAKY_UNDEFINED_1D,
+ *      - LEAKY_UNDEFINED_1E,
+ *      - LEAKY_UNDEFINED_1F,
+ *      - LEAKY_GMRP,
+ *      - LEAKY_GVRP,
+ *      - LEAKY_UNDEF_GARP_22,
+ *      - LEAKY_UNDEF_GARP_23,
+ *      - LEAKY_UNDEF_GARP_24,
+ *      - LEAKY_UNDEF_GARP_25,
+ *      - LEAKY_UNDEF_GARP_26,
+ *      - LEAKY_UNDEF_GARP_27,
+ *      - LEAKY_UNDEF_GARP_28,
+ *      - LEAKY_UNDEF_GARP_29,
+ *      - LEAKY_UNDEF_GARP_2A,
+ *      - LEAKY_UNDEF_GARP_2B,
+ *      - LEAKY_UNDEF_GARP_2C,
+ *      - LEAKY_UNDEF_GARP_2D,
+ *      - LEAKY_UNDEF_GARP_2E,
+ *      - LEAKY_UNDEF_GARP_2F,
+ *      - LEAKY_IGMP,
+ *      - LEAKY_IPMULTICAST.
+ *      - LEAKY_CDP,
+ *      - LEAKY_CSSTP,
+ *      - LEAKY_LLDP.
+ */
+rtk_api_ret_t rtk_leaky_portIsolation_get(rtk_leaky_type_t type, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 port, tmp;
+    rtl8367c_rma_t rmacfg;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (type >= LEAKY_END)
+        return RT_ERR_INPUT;
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if (type >= 0 && type <= LEAKY_UNDEF_GARP_2F)
+    {
+        if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        *pEnable = rmacfg.portiso_leaky;
+
+    }
+    else if (LEAKY_IPMULTICAST == type)
+    {
+        for (port = 0; port < RTK_MAX_NUM_OF_PORT; port++)
+        {
+            if ((retVal = rtl8367c_getAsicIpMulticastPortIsoLeaky(port, &tmp)) != RT_ERR_OK)
+                return retVal;
+            if (port > 0 &&(tmp != *pEnable))
+                return RT_ERR_FAILED;
+            *pEnable = tmp;
+        }
+    }
+    else if (LEAKY_IGMP == type)
+    {
+        if ((retVal = rtl8367c_getAsicIGMPIsoLeaky(&tmp)) != RT_ERR_OK)
+            return retVal;
+
+        *pEnable = tmp;
+    }
+    else if (LEAKY_CDP == type)
+    {
+        if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        *pEnable = rmacfg.portiso_leaky;
+    }
+    else if (LEAKY_CSSTP == type)
+    {
+        if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        *pEnable = rmacfg.portiso_leaky;
+    }
+    else if (LEAKY_LLDP == type)
+    {
+        if ((retVal = rtl8367c_getAsicRmaLldp(&tmp, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        *pEnable = rmacfg.portiso_leaky;
+    }
+
+
+    return RT_ERR_OK;
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/led.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/led.c
new file mode 100644
index 0000000..c00c331
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/led.c
@@ -0,0 +1,792 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in LED module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <led.h>
+#include <string.h>
+
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_led.h>
+
+
+/* Function Name:
+ *      rtk_led_enable_set
+ * Description:
+ *      Set Led enable congiuration
+ * Input:
+ *      group       - LED group id.
+ *      pPortmask   - LED enable port mask.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_MASK    - Error portmask
+ * Note:
+ *      The API can be used to enable LED per port per group.
+ */
+rtk_api_ret_t rtk_led_enable_set(rtk_led_group_t group, rtk_portmask_t *pPortmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmask;
+    rtk_port_t port;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (group >= LED_GROUP_END)
+        return RT_ERR_INPUT;
+
+    RTK_CHK_PORTMASK_VALID(pPortmask);
+
+    RTK_PORTMASK_SCAN((*pPortmask), port)
+    {
+        if(rtk_switch_isCPUPort(port) == RT_ERR_OK)
+            return RT_ERR_PORT_MASK;
+    }
+
+    if((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicLedGroupEnable(group, pmask)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_led_enable_get
+ * Description:
+ *      Get Led enable congiuration
+ * Input:
+ *      group - LED group id.
+ * Output:
+ *      pPortmask - LED enable port mask.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can be used to get LED enable status.
+ */
+rtk_api_ret_t rtk_led_enable_get(rtk_led_group_t group, rtk_portmask_t *pPortmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (group >= LED_GROUP_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_getAsicLedGroupEnable(group, &pmask)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+
+}
+
+/* Function Name:
+ *      rtk_led_operation_set
+ * Description:
+ *      Set Led operation mode
+ * Input:
+ *      mode - LED operation mode.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can set Led operation mode.
+ *      The modes that can be set are as following:
+ *      - LED_OP_SCAN,
+ *      - LED_OP_PARALLEL,
+ *      - LED_OP_SERIAL,
+ */
+rtk_api_ret_t rtk_led_operation_set(rtk_led_operation_t mode)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 regData;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ( mode >= LED_OP_END)
+      return RT_ERR_INPUT;
+
+    switch (mode)
+    {
+        case LED_OP_PARALLEL:
+            regData = LEDOP_PARALLEL;
+            break;
+        case LED_OP_SERIAL:
+            regData = LEDOP_SERIAL;
+            break;
+        default:
+            return RT_ERR_CHIP_NOT_SUPPORTED;
+            break;
+    }
+
+    if ((retVal = rtl8367c_setAsicLedOperationMode(regData)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_led_operation_get
+ * Description:
+ *      Get Led operation mode
+ * Input:
+ *      None
+ * Output:
+ *      pMode - Support LED operation mode.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get Led operation mode.
+ *      The modes that can be set are as following:
+ *      - LED_OP_SCAN,
+ *      - LED_OP_PARALLEL,
+ *      - LED_OP_SERIAL,
+ */
+rtk_api_ret_t rtk_led_operation_get(rtk_led_operation_t *pMode)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 regData;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pMode)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicLedOperationMode(&regData)) != RT_ERR_OK)
+        return retVal;
+
+    if (regData == LEDOP_SERIAL)
+        *pMode = LED_OP_SERIAL;
+    else if (regData ==LEDOP_PARALLEL)
+        *pMode = LED_OP_PARALLEL;
+    else
+       return RT_ERR_FAILED;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_led_modeForce_set
+ * Description:
+ *      Set Led group to congiuration force mode
+ * Input:
+ *      port    - port ID
+ *      group   - Support LED group id.
+ *      mode    - Support LED force mode.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Error Port ID
+ * Note:
+ *      The API can force to one force mode.
+ *      The force modes that can be set are as following:
+ *      - LED_FORCE_NORMAL,
+ *      - LED_FORCE_BLINK,
+ *      - LED_FORCE_OFF,
+ *      - LED_FORCE_ON.
+ */
+rtk_api_ret_t rtk_led_modeForce_set(rtk_port_t port, rtk_led_group_t group, rtk_led_force_mode_t mode)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    /* No LED for CPU port */
+    if(rtk_switch_isCPUPort(port) == RT_ERR_OK)
+        return RT_ERR_PORT_ID;
+
+    if (group >= LED_GROUP_END)
+        return RT_ERR_INPUT;
+
+    if (mode >= LED_FORCE_END)
+        return RT_ERR_NOT_ALLOWED;
+
+    if ((retVal = rtl8367c_setAsicForceLed(rtk_switch_port_L2P_get(port), group, mode)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_led_modeForce_get
+ * Description:
+ *      Get Led group to congiuration force mode
+ * Input:
+ *      port  - port ID
+ *      group - Support LED group id.
+ *      pMode - Support LED force mode.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Error Port ID
+ * Note:
+ *      The API can get forced Led group mode.
+ *      The force modes that can be set are as following:
+ *      - LED_FORCE_NORMAL,
+ *      - LED_FORCE_BLINK,
+ *      - LED_FORCE_OFF,
+ *      - LED_FORCE_ON.
+ */
+rtk_api_ret_t rtk_led_modeForce_get(rtk_port_t port, rtk_led_group_t group, rtk_led_force_mode_t *pMode)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    /* No LED for CPU port */
+    if(rtk_switch_isCPUPort(port) == RT_ERR_OK)
+        return RT_ERR_PORT_ID;
+
+    if (group >= LED_GROUP_END)
+        return RT_ERR_INPUT;
+
+    if (NULL == pMode)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicForceLed(rtk_switch_port_L2P_get(port), group, pMode)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_led_blinkRate_set
+ * Description:
+ *      Set LED blinking rate
+ * Input:
+ *      blinkRate - blinking rate.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      ASIC support 6 types of LED blinking rates at 43ms, 84ms, 120ms, 170ms, 340ms and 670ms.
+ */
+rtk_api_ret_t rtk_led_blinkRate_set(rtk_led_blink_rate_t blinkRate)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (blinkRate >= LED_BLINKRATE_END)
+        return RT_ERR_FAILED;
+
+    if ((retVal = rtl8367c_setAsicLedBlinkRate(blinkRate)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_led_blinkRate_get
+ * Description:
+ *      Get LED blinking rate at mode 0 to mode 3
+ * Input:
+ *      None
+ * Output:
+ *      pBlinkRate - blinking rate.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      There are  6 types of LED blinking rates at 43ms, 84ms, 120ms, 170ms, 340ms and 670ms.
+ */
+rtk_api_ret_t rtk_led_blinkRate_get(rtk_led_blink_rate_t *pBlinkRate)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pBlinkRate)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicLedBlinkRate(pBlinkRate)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_led_groupConfig_set
+ * Description:
+ *      Set per group Led to congiuration mode
+ * Input:
+ *      group   - LED group.
+ *      config  - LED configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can set LED indicated information configuration for each LED group with 1 to 1 led mapping to each port.
+ *      - Definition  LED Statuses      Description
+ *      - 0000        LED_Off           LED pin Tri-State.
+ *      - 0001        Dup/Col           Collision, Full duplex Indicator.
+ *      - 0010        Link/Act          Link, Activity Indicator.
+ *      - 0011        Spd1000           1000Mb/s Speed Indicator.
+ *      - 0100        Spd100            100Mb/s Speed Indicator.
+ *      - 0101        Spd10             10Mb/s Speed Indicator.
+ *      - 0110        Spd1000/Act       1000Mb/s Speed/Activity Indicator.
+ *      - 0111        Spd100/Act        100Mb/s Speed/Activity Indicator.
+ *      - 1000        Spd10/Act         10Mb/s Speed/Activity Indicator.
+ *      - 1001        Spd100 (10)/Act   10/100Mb/s Speed/Activity Indicator.
+ *      - 1010        LoopDetect        LoopDetect Indicator.
+ *      - 1011        EEE               EEE Indicator.
+ *      - 1100        Link/Rx           Link, Activity Indicator.
+ *      - 1101        Link/Tx           Link, Activity Indicator.
+ *      - 1110        Master            Link on Master Indicator.
+ *      - 1111        Act               Activity Indicator. Low for link established.
+ */
+rtk_api_ret_t rtk_led_groupConfig_set(rtk_led_group_t group, rtk_led_congig_t config)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (LED_GROUP_END <= group)
+        return RT_ERR_FAILED;
+
+    if (LED_CONFIG_END <= config)
+        return RT_ERR_FAILED;
+
+    if ((retVal = rtl8367c_setAsicLedIndicateInfoConfig(group, config)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_led_groupConfig_get
+ * Description:
+ *      Get Led group congiuration mode
+ * Input:
+ *      group - LED group.
+ * Output:
+ *      pConfig - LED configuration.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *       The API can get LED indicated information configuration for each LED group.
+ */
+rtk_api_ret_t rtk_led_groupConfig_get(rtk_led_group_t group, rtk_led_congig_t *pConfig)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (LED_GROUP_END <= group)
+        return RT_ERR_FAILED;
+
+    if(NULL == pConfig)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicLedIndicateInfoConfig(group, pConfig)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_led_groupAbility_set
+ * Description:
+ *      Configure per group Led ability
+ * Input:
+ *      group    - LED group.
+ *      pAbility - LED ability
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      None.
+ */
+
+rtk_api_ret_t rtk_led_groupAbility_set(rtk_led_group_t group, rtk_led_ability_t *pAbility)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 regData;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (LED_GROUP_END <= group)
+        return RT_ERR_FAILED;
+
+    if(pAbility == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    if( (pAbility->link_10m >= RTK_ENABLE_END) || (pAbility->link_100m >= RTK_ENABLE_END)||
+        (pAbility->link_500m >= RTK_ENABLE_END) || (pAbility->link_1000m >= RTK_ENABLE_END)||
+        (pAbility->act_rx >= RTK_ENABLE_END) || (pAbility->act_tx >= RTK_ENABLE_END) )
+    {
+        return RT_ERR_INPUT;
+    }
+
+    if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_LED0_DATA_CTRL + (rtk_uint32)group, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    if(pAbility->link_10m == ENABLED)
+        regData |= 0x0001;
+    else
+        regData &= ~0x0001;
+
+    if(pAbility->link_100m == ENABLED)
+        regData |= 0x0002;
+    else
+        regData &= ~0x0002;
+
+    if(pAbility->link_500m == ENABLED)
+        regData |= 0x0004;
+    else
+        regData &= ~0x0004;
+
+    if(pAbility->link_1000m == ENABLED)
+        regData |= 0x0008;
+    else
+        regData &= ~0x0008;
+
+    if(pAbility->act_rx == ENABLED)
+        regData |= 0x0010;
+    else
+        regData &= ~0x0010;
+
+    if(pAbility->act_tx == ENABLED)
+        regData |= 0x0020;
+    else
+        regData &= ~0x0020;
+
+    regData |= (0x0001 << 6);
+
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_LED0_DATA_CTRL + (rtk_uint32)group, regData)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_led_groupAbility_get
+ * Description:
+ *      Get per group Led ability
+ * Input:
+ *      group    - LED group.
+ *      pAbility - LED ability
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      None.
+ */
+
+rtk_api_ret_t rtk_led_groupAbility_get(rtk_led_group_t group, rtk_led_ability_t *pAbility)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 regData;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (LED_GROUP_END <= group)
+        return RT_ERR_FAILED;
+
+    if(pAbility == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_LED0_DATA_CTRL + (rtk_uint32)group, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    pAbility->link_10m = (regData & 0x0001) ? ENABLED : DISABLED;
+    pAbility->link_100m = (regData & 0x0002) ? ENABLED : DISABLED;
+    pAbility->link_500m = (regData & 0x0004) ? ENABLED : DISABLED;
+    pAbility->link_1000m = (regData & 0x0008) ? ENABLED : DISABLED;
+    pAbility->act_rx = (regData & 0x0010) ? ENABLED : DISABLED;
+    pAbility->act_tx = (regData & 0x0020) ? ENABLED : DISABLED;
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_led_serialMode_set
+ * Description:
+ *      Set Led serial mode active congiuration
+ * Input:
+ *      active - LED group.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can set LED serial mode active congiuration.
+ */
+rtk_api_ret_t rtk_led_serialMode_set(rtk_led_active_t active)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ( active >= LED_ACTIVE_END)
+        return RT_ERR_INPUT;
+
+     if ((retVal = rtl8367c_setAsicLedSerialModeConfig(active,1))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_led_serialMode_get
+ * Description:
+ *      Get Led group congiuration mode
+ * Input:
+ *      group - LED group.
+ * Output:
+ *      pConfig - LED configuration.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *       The API can get LED serial mode active configuration.
+ */
+rtk_api_ret_t rtk_led_serialMode_get(rtk_led_active_t *pActive)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 regData;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pActive)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicLedSerialModeConfig(pActive,&regData))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_led_OutputEnable_set
+ * Description:
+ *      This API set LED I/O state.
+ * Input:
+ *      enabled     - LED I/O state
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error parameter
+ * Note:
+ *      This API set LED I/O state.
+ */
+rtk_api_ret_t rtk_led_OutputEnable_set(rtk_enable_t state)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (state >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicLedOutputEnable(state))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_led_OutputEnable_get
+ * Description:
+ *      This API get LED I/O state.
+ * Input:
+ *      None.
+ * Output:
+ *      pEnabled        - LED I/O state
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error parameter
+ * Note:
+ *      This API set current LED I/O  state.
+ */
+rtk_api_ret_t rtk_led_OutputEnable_get(rtk_enable_t *pState)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(pState == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicLedOutputEnable(pState))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+
+}
+
+/* Function Name:
+ *      rtk_led_serialModePortmask_set
+ * Description:
+ *      This API configure Serial LED output Group and portmask
+ * Input:
+ *      output          - output group
+ *      pPortmask       - output portmask
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error parameter
+ * Note:
+ *      None.
+ */
+rtk_api_ret_t rtk_led_serialModePortmask_set(rtk_led_serialOutput_t output, rtk_portmask_t *pPortmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(output >= SERIAL_LED_END)
+        return RT_ERR_INPUT;
+
+    if(pPortmask == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicLedSerialOutput((rtk_uint32)output, pmask))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_led_serialModePortmask_get
+ * Description:
+ *      This API get Serial LED output Group and portmask
+ * Input:
+ *      None.
+ * Output:
+ *      pOutput         - output group
+ *      pPortmask       - output portmask
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error parameter
+ * Note:
+ *      None.
+ */
+rtk_api_ret_t rtk_led_serialModePortmask_get(rtk_led_serialOutput_t *pOutput, rtk_portmask_t *pPortmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(pOutput == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    if(pPortmask == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicLedSerialOutput((rtk_uint32 *)pOutput, &pmask))!=RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/mirror.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/mirror.c
new file mode 100644
index 0000000..1921d1a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/mirror.c
@@ -0,0 +1,548 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in Mirror module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <mirror.h>
+#include <string.h>
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_mirror.h>
+
+/* Function Name:
+ *      rtk_mirror_portBased_set
+ * Description:
+ *      Set port mirror function.
+ * Input:
+ *      mirroring_port          - Monitor port.
+ *      pMirrored_rx_portmask   - Rx mirror port mask.
+ *      pMirrored_tx_portmask   - Tx mirror port mask.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_PORT_MASK    - Invalid portmask.
+ * Note:
+ *      The API is to set mirror function of source port and mirror port.
+ *      The mirror port can only be set to one port and the TX and RX mirror ports
+ *      should be identical.
+ */
+rtk_api_ret_t rtk_mirror_portBased_set(rtk_port_t mirroring_port, rtk_portmask_t *pMirrored_rx_portmask, rtk_portmask_t *pMirrored_tx_portmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_enable_t mirRx, mirTx;
+    rtk_uint32 i, pmask;
+    rtk_port_t source_port;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port valid */
+    RTK_CHK_PORT_VALID(mirroring_port);
+
+    if(NULL == pMirrored_rx_portmask)
+        return RT_ERR_NULL_POINTER;
+
+    if(NULL == pMirrored_tx_portmask)
+        return RT_ERR_NULL_POINTER;
+
+    RTK_CHK_PORTMASK_VALID(pMirrored_rx_portmask);
+
+    RTK_CHK_PORTMASK_VALID(pMirrored_tx_portmask);
+
+    /*Mirror Sorce Port Mask Check*/
+    if (pMirrored_tx_portmask->bits[0]!=pMirrored_rx_portmask->bits[0]&&pMirrored_tx_portmask->bits[0]!=0&&pMirrored_rx_portmask->bits[0]!=0)
+        return RT_ERR_PORT_MASK;
+
+     /*mirror port != source port*/
+    if(RTK_PORTMASK_IS_PORT_SET((*pMirrored_tx_portmask), mirroring_port) || RTK_PORTMASK_IS_PORT_SET((*pMirrored_rx_portmask), mirroring_port))
+        return RT_ERR_PORT_MASK;
+
+    source_port = rtk_switch_maxLogicalPort_get();
+
+    RTK_SCAN_ALL_LOG_PORT(i)
+    {
+        if (pMirrored_tx_portmask->bits[0]&(1<<i))
+        {
+            source_port = i;
+            break;
+        }
+
+        if (pMirrored_rx_portmask->bits[0]&(1<<i))
+        {
+            source_port = i;
+            break;
+        }
+    }
+
+    if ((retVal = rtl8367c_setAsicPortMirror(rtk_switch_port_L2P_get(source_port), rtk_switch_port_L2P_get(mirroring_port))) != RT_ERR_OK)
+        return retVal;
+    if(pMirrored_rx_portmask->bits[0] != 0)
+    {
+        if ((retVal = rtk_switch_portmask_L2P_get(pMirrored_rx_portmask, &pmask)) != RT_ERR_OK)
+            return retVal;
+        if ((retVal = rtl8367c_setAsicPortMirrorMask(pmask)) != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        if ((retVal = rtk_switch_portmask_L2P_get(pMirrored_tx_portmask, &pmask)) != RT_ERR_OK)
+            return retVal;
+        if ((retVal = rtl8367c_setAsicPortMirrorMask(pmask)) != RT_ERR_OK)
+            return retVal;
+    }
+
+
+    if (pMirrored_rx_portmask->bits[0])
+        mirRx = ENABLED;
+    else
+        mirRx = DISABLED;
+
+    if ((retVal = rtl8367c_setAsicPortMirrorRxFunction(mirRx)) != RT_ERR_OK)
+        return retVal;
+
+    if (pMirrored_tx_portmask->bits[0])
+        mirTx = ENABLED;
+    else
+        mirTx = DISABLED;
+
+    if ((retVal = rtl8367c_setAsicPortMirrorTxFunction(mirTx)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+
+}
+
+/* Function Name:
+ *      rtk_mirror_portBased_get
+ * Description:
+ *      Get port mirror function.
+ * Input:
+ *      None
+ * Output:
+ *      pMirroring_port         - Monitor port.
+ *      pMirrored_rx_portmask   - Rx mirror port mask.
+ *      pMirrored_tx_portmask   - Tx mirror port mask.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API is to get mirror function of source port and mirror port.
+ */
+rtk_api_ret_t rtk_mirror_portBased_get(rtk_port_t *pMirroring_port, rtk_portmask_t *pMirrored_rx_portmask, rtk_portmask_t *pMirrored_tx_portmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_port_t source_port;
+    rtk_enable_t mirRx, mirTx;
+    rtk_uint32 sport, mport, pmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pMirrored_rx_portmask)
+        return RT_ERR_NULL_POINTER;
+
+    if(NULL == pMirrored_tx_portmask)
+        return RT_ERR_NULL_POINTER;
+
+    if(NULL == pMirroring_port)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicPortMirror(&sport, &mport)) != RT_ERR_OK)
+        return retVal;
+    source_port = rtk_switch_port_P2L_get(sport);
+    *pMirroring_port = rtk_switch_port_P2L_get(mport);
+
+    if ((retVal = rtl8367c_getAsicPortMirrorRxFunction((rtk_uint32*)&mirRx)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicPortMirrorTxFunction((rtk_uint32*)&mirTx)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicPortMirrorMask(&pmask)) != RT_ERR_OK)
+        return retVal;
+
+    if (DISABLED == mirRx)
+        pMirrored_rx_portmask->bits[0]=0;
+    else
+    {
+        if ((retVal = rtk_switch_portmask_P2L_get(pmask, pMirrored_rx_portmask)) != RT_ERR_OK)
+            return retVal;
+        pMirrored_rx_portmask->bits[0] |= 1<<source_port;
+    }
+
+     if (DISABLED == mirTx)
+        pMirrored_tx_portmask->bits[0]=0;
+    else
+    {
+        if ((retVal = rtk_switch_portmask_P2L_get(pmask, pMirrored_tx_portmask)) != RT_ERR_OK)
+            return retVal;
+        pMirrored_tx_portmask->bits[0] |= 1<<source_port;
+    }
+
+    return RT_ERR_OK;
+
+}
+
+/* Function Name:
+ *      rtk_mirror_portIso_set
+ * Description:
+ *      Set mirror port isolation.
+ * Input:
+ *      enable |Mirror isolation status.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_ENABLE       - Invalid enable input
+ * Note:
+ *      The API is to set mirror isolation function that prevent normal forwarding packets to miror port.
+ */
+rtk_api_ret_t rtk_mirror_portIso_set(rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (enable >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if ((retVal = rtl8367c_setAsicPortMirrorIsolation(enable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_mirror_portIso_get
+ * Description:
+ *      Get mirror port isolation.
+ * Input:
+ *      None
+ * Output:
+ *      pEnable |Mirror isolation status.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API is to get mirror isolation status.
+ */
+rtk_api_ret_t rtk_mirror_portIso_get(rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicPortMirrorIsolation(pEnable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_mirror_vlanLeaky_set
+ * Description:
+ *      Set mirror VLAN leaky.
+ * Input:
+ *      txenable -TX leaky enable.
+ *      rxenable - RX leaky enable.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_ENABLE       - Invalid enable input
+ * Note:
+ *      The API is to set mirror VLAN leaky function forwarding packets to miror port.
+ */
+rtk_api_ret_t rtk_mirror_vlanLeaky_set(rtk_enable_t txenable, rtk_enable_t rxenable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((txenable >= RTK_ENABLE_END) ||(rxenable >= RTK_ENABLE_END))
+        return RT_ERR_ENABLE;
+
+    if ((retVal = rtl8367c_setAsicPortMirrorVlanTxLeaky(txenable)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicPortMirrorVlanRxLeaky(rxenable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_mirror_vlanLeaky_get
+ * Description:
+ *      Get mirror VLAN leaky.
+ * Input:
+ *      None
+ * Output:
+ *      pTxenable - TX leaky enable.
+ *      pRxenable - RX leaky enable.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API is to get mirror VLAN leaky status.
+ */
+rtk_api_ret_t rtk_mirror_vlanLeaky_get(rtk_enable_t *pTxenable, rtk_enable_t *pRxenable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if( (NULL == pTxenable) || (NULL == pRxenable) )
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicPortMirrorVlanTxLeaky(pTxenable)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicPortMirrorVlanRxLeaky(pRxenable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_mirror_isolationLeaky_set
+ * Description:
+ *      Set mirror Isolation leaky.
+ * Input:
+ *      txenable -TX leaky enable.
+ *      rxenable - RX leaky enable.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_ENABLE       - Invalid enable input
+ * Note:
+ *      The API is to set mirror VLAN leaky function forwarding packets to miror port.
+ */
+rtk_api_ret_t rtk_mirror_isolationLeaky_set(rtk_enable_t txenable, rtk_enable_t rxenable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((txenable >= RTK_ENABLE_END) ||(rxenable >= RTK_ENABLE_END))
+        return RT_ERR_ENABLE;
+
+    if ((retVal = rtl8367c_setAsicPortMirrorIsolationTxLeaky(txenable)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicPortMirrorIsolationRxLeaky(rxenable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_mirror_isolationLeaky_get
+ * Description:
+ *      Get mirror isolation leaky.
+ * Input:
+ *      None
+ * Output:
+ *      pTxenable - TX leaky enable.
+ *      pRxenable - RX leaky enable.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API is to get mirror isolation leaky status.
+ */
+rtk_api_ret_t rtk_mirror_isolationLeaky_get(rtk_enable_t *pTxenable, rtk_enable_t *pRxenable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if( (NULL == pTxenable) || (NULL == pRxenable) )
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicPortMirrorIsolationTxLeaky(pTxenable)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicPortMirrorIsolationRxLeaky(pRxenable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_mirror_keep_set
+ * Description:
+ *      Set mirror packet format keep.
+ * Input:
+ *      mode - -mirror keep mode.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_ENABLE       - Invalid enable input
+ * Note:
+ *      The API is to set  -mirror keep mode.
+ *      The mirror keep mode is as following:
+ *      - MIRROR_FOLLOW_VLAN
+ *      - MIRROR_KEEP_ORIGINAL
+ *      - MIRROR_KEEP_END
+ */
+rtk_api_ret_t rtk_mirror_keep_set(rtk_mirror_keep_t mode)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (mode >= MIRROR_KEEP_END)
+        return RT_ERR_ENABLE;
+
+    if ((retVal = rtl8367c_setAsicPortMirrorRealKeep(mode)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_mirror_keep_get
+ * Description:
+ *      Get mirror packet format keep.
+ * Input:
+ *      None
+ * Output:
+ *      pMode -mirror keep mode.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API is to get mirror keep mode.
+  *      The mirror keep mode is as following:
+ *      - MIRROR_FOLLOW_VLAN
+ *      - MIRROR_KEEP_ORIGINAL
+ *      - MIRROR_KEEP_END
+ */
+rtk_api_ret_t rtk_mirror_keep_get(rtk_mirror_keep_t *pMode)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pMode)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicPortMirrorRealKeep(pMode)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_mirror_override_set
+ * Description:
+ *      Set port mirror override function.
+ * Input:
+ *      rxMirror        - 1: output mirrored packet, 0: output normal forward packet
+ *      txMirror        - 1: output mirrored packet, 0: output normal forward packet
+ *      aclMirror       - 1: output mirrored packet, 0: output normal forward packet
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      The API is to set mirror override function.
+ *      This function control the output format when a port output
+ *      normal forward & mirrored packet at the same time.
+ */
+rtk_api_ret_t rtk_mirror_override_set(rtk_enable_t rxMirror, rtk_enable_t txMirror, rtk_enable_t aclMirror)
+{
+    rtk_api_ret_t retVal;
+
+    if( (rxMirror >= RTK_ENABLE_END) || (txMirror >= RTK_ENABLE_END) || (aclMirror >= RTK_ENABLE_END))
+        return RT_ERR_ENABLE;
+
+    if ((retVal = rtl8367c_setAsicPortMirrorOverride((rtk_uint32)rxMirror, (rtk_uint32)txMirror, (rtk_uint32)aclMirror)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_mirror_override_get
+ * Description:
+ *      Get port mirror override function.
+ * Input:
+ *      None
+ * Output:
+ *      pRxMirror       - 1: output mirrored packet, 0: output normal forward packet
+ *      pTxMirror       - 1: output mirrored packet, 0: output normal forward packet
+ *      pAclMirror      - 1: output mirrored packet, 0: output normal forward packet
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_NULL_POINTER - Null Pointer
+ * Note:
+ *      The API is to Get mirror override function.
+ *      This function control the output format when a port output
+ *      normal forward & mirrored packet at the same time.
+ */
+rtk_api_ret_t rtk_mirror_override_get(rtk_enable_t *pRxMirror, rtk_enable_t *pTxMirror, rtk_enable_t *pAclMirror)
+{
+    rtk_api_ret_t retVal;
+
+    if( (pRxMirror == NULL) || (pTxMirror == NULL) || (pAclMirror == NULL))
+        return RT_ERR_ENABLE;
+
+    if ((retVal = rtl8367c_getAsicPortMirrorOverride((rtk_uint32 *)pRxMirror, (rtk_uint32 *)pTxMirror, (rtk_uint32 *)pAclMirror)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/oam.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/oam.c
new file mode 100644
index 0000000..dc1559a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/oam.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in OAM(802.3ah)  module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <oam.h>
+#include <string.h>
+
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_oam.h>
+
+
+/* Module Name : OAM */
+
+/* Function Name:
+ *      rtk_oam_init
+ * Description:
+ *      Initialize oam module.
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ * Note:
+ *      Must initialize oam module before calling any oam APIs.
+ */
+rtk_api_ret_t rtk_oam_init(void)
+{
+    return RT_ERR_OK;
+} /* end of rtk_oam_init */
+
+
+/* Function Name:
+ *      rtk_oam_state_set
+ * Description:
+ *      This API set OAM state.
+ * Input:
+ *      enabled     -OAMstate
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error parameter
+ * Note:
+ *      This API set OAM state.
+ */
+rtk_api_ret_t rtk_oam_state_set(rtk_enable_t enabled)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (enabled >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicOamEnable(enabled))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_oam_state_get
+ * Description:
+ *      This API get OAM state.
+ * Input:
+ *      None.
+ * Output:
+ *      pEnabled        - H/W IGMP state
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT           - Error parameter
+ * Note:
+ *      This API set current OAM state.
+ */
+rtk_api_ret_t rtk_oam_state_get(rtk_enable_t *pEnabled)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((retVal = rtl8367c_getAsicOamEnable(pEnabled))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+
+
+/* Function Name:
+ *      rtk_oam_parserAction_set
+ * Description:
+ *      Set OAM parser action
+ * Input:
+ *      port    - port id
+ *      action  - parser action
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID      - invalid port id
+ * Note:
+ *      None
+ */
+rtk_api_ret_t  rtk_oam_parserAction_set(rtk_port_t port, rtk_oam_parser_act_t action)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (action >= OAM_PARSER_ACTION_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicOamParser(rtk_switch_port_L2P_get(port), action))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_oam_parserAction_set
+ * Description:
+ *      Get OAM parser action
+ * Input:
+ *      port    - port id
+ * Output:
+ *      pAction  - parser action
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID      - invalid port id
+ * Note:
+ *      None
+ */
+rtk_api_ret_t  rtk_oam_parserAction_get(rtk_port_t port, rtk_oam_parser_act_t *pAction)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if ((retVal = rtl8367c_getAsicOamParser(rtk_switch_port_L2P_get(port), pAction))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_oam_multiplexerAction_set
+ * Description:
+ *      Set OAM multiplexer action
+ * Input:
+ *      port    - port id
+ *      action  - parser action
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID      - invalid port id
+ * Note:
+ *      None
+ */
+rtk_api_ret_t  rtk_oam_multiplexerAction_set(rtk_port_t port, rtk_oam_multiplexer_act_t action)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (action >= OAM_MULTIPLEXER_ACTION_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicOamMultiplexer(rtk_switch_port_L2P_get(port), action))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_oam_parserAction_set
+ * Description:
+ *      Get OAM multiplexer action
+ * Input:
+ *      port    - port id
+ * Output:
+ *      pAction  - parser action
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID      - invalid port id
+ * Note:
+ *      None
+ */
+rtk_api_ret_t  rtk_oam_multiplexerAction_get(rtk_port_t port, rtk_oam_multiplexer_act_t *pAction)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if ((retVal = rtl8367c_getAsicOamMultiplexer(rtk_switch_port_L2P_get(port), pAction))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/port.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/port.c
new file mode 100644
index 0000000..9f99d1b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/port.c
@@ -0,0 +1,2467 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in Port module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <port.h>
+#include <string.h>
+
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_port.h>
+#include <rtl8367c_asicdrv_misc.h>
+#include <rtl8367c_asicdrv_portIsolation.h>
+
+#define FIBER_INIT_SIZE 1507
+CONST_T rtk_uint8 Fiber[FIBER_INIT_SIZE] = {
+0x02,0x04,0x41,0xE4,0xF5,0xA8,0xD2,0xAF,
+0x22,0x00,0x00,0x02,0x05,0x2D,0xE4,0x90,
+0x06,0x2A,0xF0,0xFD,0x7C,0x01,0x7F,0x3F,
+0x7E,0x1D,0x12,0x05,0xAF,0x7D,0x40,0x12,
+0x02,0x5F,0xE4,0xFF,0xFE,0xFD,0x80,0x08,
+0x12,0x05,0x9E,0x50,0x0C,0x12,0x05,0x8B,
+0xFC,0x90,0x06,0x24,0x12,0x03,0x76,0x80,
+0xEF,0xE4,0xF5,0xA8,0xD2,0xAF,0x7D,0x1F,
+0xFC,0x7F,0x49,0x7E,0x13,0x12,0x05,0xAF,
+0x12,0x05,0xD6,0x7D,0xD7,0x12,0x02,0x1E,
+0x7D,0x80,0x12,0x01,0xCA,0x7D,0x94,0x7C,
+0xF9,0x12,0x02,0x3B,0x7D,0x81,0x12,0x01,
+0xCA,0x7D,0xA2,0x7C,0x31,0x12,0x02,0x3B,
+0x7D,0x82,0x12,0x01,0xDF,0x7D,0x60,0x7C,
+0x69,0x12,0x02,0x43,0x7D,0x83,0x12,0x01,
+0xDF,0x7D,0x28,0x7C,0x97,0x12,0x02,0x43,
+0x7D,0x84,0x12,0x01,0xF4,0x7D,0x85,0x7C,
+0x9D,0x12,0x02,0x57,0x7D,0x23,0x12,0x01,
+0xF4,0x7D,0x10,0x7C,0xD8,0x12,0x02,0x57,
+0x7D,0x24,0x7C,0x04,0x12,0x02,0x28,0x7D,
+0x00,0x12,0x02,0x1E,0x7D,0x2F,0x12,0x02,
+0x09,0x7D,0x20,0x7C,0x0F,0x7F,0x02,0x7E,
+0x66,0x12,0x05,0xAF,0x7D,0x01,0x12,0x02,
+0x09,0x7D,0x04,0x7C,0x00,0x7F,0x01,0x7E,
+0x66,0x12,0x05,0xAF,0x7D,0x80,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x12,0x05,0xAF,0x7F,
+0x02,0x7E,0x66,0x12,0x02,0x4B,0x44,0x02,
+0xFF,0x90,0x06,0x28,0xEE,0xF0,0xA3,0xEF,
+0xF0,0x44,0x04,0xFF,0x90,0x06,0x28,0xEE,
+0xF0,0xFC,0xA3,0xEF,0xF0,0xFD,0x7F,0x02,
+0x7E,0x66,0x12,0x05,0xAF,0x7D,0x04,0x7C,
+0x00,0x12,0x02,0x28,0x7D,0xB9,0x7C,0x15,
+0x7F,0xEB,0x7E,0x13,0x12,0x05,0xAF,0x7D,
+0x07,0x7C,0x00,0x7F,0xE7,0x7E,0x13,0x12,
+0x05,0xAF,0x7D,0x40,0x7C,0x11,0x7F,0x00,
+0x7E,0x62,0x12,0x05,0xAF,0x12,0x03,0x82,
+0x7D,0x41,0x12,0x02,0x5F,0xE4,0xFF,0xFE,
+0xFD,0x80,0x08,0x12,0x05,0x9E,0x50,0x0C,
+0x12,0x05,0x8B,0xFC,0x90,0x06,0x24,0x12,
+0x03,0x76,0x80,0xEF,0xC2,0x00,0xC2,0x01,
+0xD2,0xA9,0xD2,0x8C,0x7F,0x01,0x7E,0x62,
+0x12,0x02,0x4B,0x30,0xE2,0x05,0xE4,0xA3,
+0xF0,0x80,0xF1,0x90,0x06,0x2A,0xE0,0x70,
+0x12,0x12,0x01,0x89,0x90,0x06,0x2A,0x74,
+0x01,0xF0,0xE4,0x90,0x06,0x2D,0xF0,0xA3,
+0xF0,0x80,0xD9,0xC3,0x90,0x06,0x2E,0xE0,
+0x94,0x64,0x90,0x06,0x2D,0xE0,0x94,0x00,
+0x40,0xCA,0xE4,0xF0,0xA3,0xF0,0x12,0x01,
+0x89,0x90,0x06,0x2A,0x74,0x01,0xF0,0x80,
+0xBB,0x7D,0x04,0xFC,0x7F,0x02,0x7E,0x66,
+0x12,0x05,0xAF,0x7D,0x00,0x7C,0x04,0x7F,
+0x01,0x7E,0x66,0x12,0x05,0xAF,0x7D,0xC0,
+0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,0x05,
+0xAF,0xE4,0xFD,0xFC,0x7F,0x02,0x7E,0x66,
+0x12,0x05,0xAF,0x7D,0x00,0x7C,0x04,0x7F,
+0x01,0x7E,0x66,0x12,0x05,0xAF,0x7D,0xC0,
+0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,0x05,
+0xAF,0x22,0x7C,0x04,0x7F,0x01,0x7E,0x66,
+0x12,0x05,0xAF,0x7D,0xC0,0x7C,0x00,0x7F,
+0x00,0x7E,0x66,0x12,0x05,0xAF,0x22,0x7C,
+0x04,0x7F,0x01,0x7E,0x66,0x12,0x05,0xAF,
+0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66,
+0x12,0x05,0xAF,0x22,0x7C,0x04,0x7F,0x01,
+0x7E,0x66,0x12,0x05,0xAF,0x7D,0xC0,0x7C,
+0x00,0x7F,0x00,0x7E,0x66,0x12,0x05,0xAF,
+0x22,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12,
+0x05,0xAF,0x7D,0xC0,0x7C,0x00,0x7F,0x00,
+0x7E,0x66,0x12,0x05,0xAF,0x22,0x7C,0x04,
+0x7F,0x02,0x7E,0x66,0x12,0x05,0xAF,0x22,
+0x7F,0x01,0x7E,0x66,0x12,0x05,0xAF,0x7D,
+0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,
+0x05,0xAF,0x22,0x7F,0x02,0x7E,0x66,0x12,
+0x05,0xAF,0x22,0x7F,0x02,0x7E,0x66,0x12,
+0x05,0xAF,0x22,0x12,0x05,0x67,0x90,0x06,
+0x28,0xEE,0xF0,0xA3,0xEF,0xF0,0x22,0x7F,
+0x02,0x7E,0x66,0x12,0x05,0xAF,0x22,0x7C,
+0x00,0x7F,0x36,0x7E,0x13,0x12,0x05,0xAF,
+0x22,0xC5,0xF0,0xF8,0xA3,0xE0,0x28,0xF0,
+0xC5,0xF0,0xF8,0xE5,0x82,0x15,0x82,0x70,
+0x02,0x15,0x83,0xE0,0x38,0xF0,0x22,0x75,
+0xF0,0x08,0x75,0x82,0x00,0xEF,0x2F,0xFF,
+0xEE,0x33,0xFE,0xCD,0x33,0xCD,0xCC,0x33,
+0xCC,0xC5,0x82,0x33,0xC5,0x82,0x9B,0xED,
+0x9A,0xEC,0x99,0xE5,0x82,0x98,0x40,0x0C,
+0xF5,0x82,0xEE,0x9B,0xFE,0xED,0x9A,0xFD,
+0xEC,0x99,0xFC,0x0F,0xD5,0xF0,0xD6,0xE4,
+0xCE,0xFB,0xE4,0xCD,0xFA,0xE4,0xCC,0xF9,
+0xA8,0x82,0x22,0xB8,0x00,0xC1,0xB9,0x00,
+0x59,0xBA,0x00,0x2D,0xEC,0x8B,0xF0,0x84,
+0xCF,0xCE,0xCD,0xFC,0xE5,0xF0,0xCB,0xF9,
+0x78,0x18,0xEF,0x2F,0xFF,0xEE,0x33,0xFE,
+0xED,0x33,0xFD,0xEC,0x33,0xFC,0xEB,0x33,
+0xFB,0x10,0xD7,0x03,0x99,0x40,0x04,0xEB,
+0x99,0xFB,0x0F,0xD8,0xE5,0xE4,0xF9,0xFA,
+0x22,0x78,0x18,0xEF,0x2F,0xFF,0xEE,0x33,
+0xFE,0xED,0x33,0xFD,0xEC,0x33,0xFC,0xC9,
+0x33,0xC9,0x10,0xD7,0x05,0x9B,0xE9,0x9A,
+0x40,0x07,0xEC,0x9B,0xFC,0xE9,0x9A,0xF9,
+0x0F,0xD8,0xE0,0xE4,0xC9,0xFA,0xE4,0xCC,
+0xFB,0x22,0x75,0xF0,0x10,0xEF,0x2F,0xFF,
+0xEE,0x33,0xFE,0xED,0x33,0xFD,0xCC,0x33,
+0xCC,0xC8,0x33,0xC8,0x10,0xD7,0x07,0x9B,
+0xEC,0x9A,0xE8,0x99,0x40,0x0A,0xED,0x9B,
+0xFD,0xEC,0x9A,0xFC,0xE8,0x99,0xF8,0x0F,
+0xD5,0xF0,0xDA,0xE4,0xCD,0xFB,0xE4,0xCC,
+0xFA,0xE4,0xC8,0xF9,0x22,0xEB,0x9F,0xF5,
+0xF0,0xEA,0x9E,0x42,0xF0,0xE9,0x9D,0x42,
+0xF0,0xE8,0x9C,0x45,0xF0,0x22,0xE0,0xFC,
+0xA3,0xE0,0xFD,0xA3,0xE0,0xFE,0xA3,0xE0,
+0xFF,0x22,0xE0,0xF8,0xA3,0xE0,0xF9,0xA3,
+0xE0,0xFA,0xA3,0xE0,0xFB,0x22,0xEC,0xF0,
+0xA3,0xED,0xF0,0xA3,0xEE,0xF0,0xA3,0xEF,
+0xF0,0x22,0x12,0x03,0xF8,0x12,0x04,0x1A,
+0x44,0x40,0x12,0x04,0x0F,0x7D,0x03,0x7C,
+0x00,0x12,0x04,0x23,0x12,0x05,0xAF,0x12,
+0x03,0xF8,0x12,0x04,0x1A,0x54,0xBF,0x12,
+0x04,0x0F,0x7D,0x03,0x7C,0x00,0x12,0x03,
+0xD0,0x7F,0x02,0x7E,0x66,0x12,0x05,0x67,
+0xEF,0x54,0xFD,0x54,0xFE,0x12,0x04,0x33,
+0x12,0x03,0xD0,0x7F,0x02,0x7E,0x66,0x12,
+0x05,0x67,0xEF,0x44,0x02,0x44,0x01,0x12,
+0x04,0x33,0x12,0x04,0x23,0x02,0x05,0xAF,
+0x7F,0x01,0x7E,0x66,0x12,0x05,0xAF,0x7D,
+0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,
+0x05,0xAF,0xE4,0xFD,0xFC,0x7F,0x01,0x7E,
+0x66,0x12,0x05,0xAF,0x7D,0x80,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x12,0x05,0xAF,0x22,
+0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E,0x66,
+0x12,0x05,0xAF,0x7D,0x80,0x7C,0x00,0x7F,
+0x00,0x7E,0x66,0x12,0x05,0xAF,0x22,0xFD,
+0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,0x05,
+0xAF,0x22,0x7F,0x02,0x7E,0x66,0x12,0x05,
+0x67,0xEF,0x22,0x7F,0x01,0x7E,0x66,0x12,
+0x05,0xAF,0x7D,0xC0,0x7C,0x00,0x7F,0x00,
+0x7E,0x66,0x22,0xFD,0xAC,0x06,0x7F,0x02,
+0x7E,0x66,0x12,0x05,0xAF,0xE4,0xFD,0xFC,
+0x22,0x78,0x7F,0xE4,0xF6,0xD8,0xFD,0x75,
+0x81,0x3C,0x02,0x04,0x88,0x02,0x00,0x0E,
+0xE4,0x93,0xA3,0xF8,0xE4,0x93,0xA3,0x40,
+0x03,0xF6,0x80,0x01,0xF2,0x08,0xDF,0xF4,
+0x80,0x29,0xE4,0x93,0xA3,0xF8,0x54,0x07,
+0x24,0x0C,0xC8,0xC3,0x33,0xC4,0x54,0x0F,
+0x44,0x20,0xC8,0x83,0x40,0x04,0xF4,0x56,
+0x80,0x01,0x46,0xF6,0xDF,0xE4,0x80,0x0B,
+0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,
+0x90,0x05,0xCB,0xE4,0x7E,0x01,0x93,0x60,
+0xBC,0xA3,0xFF,0x54,0x3F,0x30,0xE5,0x09,
+0x54,0x1F,0xFE,0xE4,0x93,0xA3,0x60,0x01,
+0x0E,0xCF,0x54,0xC0,0x25,0xE0,0x60,0xA8,
+0x40,0xB8,0xE4,0x93,0xA3,0xFA,0xE4,0x93,
+0xA3,0xF8,0xE4,0x93,0xA3,0xC8,0xC5,0x82,
+0xC8,0xCA,0xC5,0x83,0xCA,0xF0,0xA3,0xC8,
+0xC5,0x82,0xC8,0xCA,0xC5,0x83,0xCA,0xDF,
+0xE9,0xDE,0xE7,0x80,0xBE,0x75,0x0F,0x80,
+0x75,0x0E,0x7E,0x75,0x0D,0xAA,0x75,0x0C,
+0x83,0xE4,0xF5,0x10,0x75,0x0B,0xA0,0x75,
+0x0A,0xAC,0x75,0x09,0xB9,0x75,0x08,0x03,
+0x75,0x89,0x11,0x7B,0x60,0x7A,0x09,0xF9,
+0xF8,0xAF,0x0B,0xAE,0x0A,0xAD,0x09,0xAC,
+0x08,0x12,0x02,0xBB,0xAD,0x07,0xAC,0x06,
+0xC3,0xE4,0x9D,0xFD,0xE4,0x9C,0xFC,0x78,
+0x17,0xF6,0xAF,0x05,0xEF,0x08,0xF6,0x18,
+0xE6,0xF5,0x8C,0x08,0xE6,0xF5,0x8A,0x74,
+0x0D,0x2D,0xFD,0xE4,0x3C,0x18,0xF6,0xAF,
+0x05,0xEF,0x08,0xF6,0x75,0x88,0x10,0x53,
+0x8E,0xC7,0xD2,0xA9,0x22,0xC0,0xE0,0xC0,
+0xF0,0xC0,0x83,0xC0,0x82,0xC0,0xD0,0x75,
+0xD0,0x00,0xC0,0x00,0x78,0x17,0xE6,0xF5,
+0x8C,0x78,0x18,0xE6,0xF5,0x8A,0x90,0x06,
+0x2B,0xE4,0x75,0xF0,0x01,0x12,0x02,0x69,
+0x90,0x06,0x2D,0xE4,0x75,0xF0,0x01,0x12,
+0x02,0x69,0xD0,0x00,0xD0,0xD0,0xD0,0x82,
+0xD0,0x83,0xD0,0xF0,0xD0,0xE0,0x32,0xC2,
+0xAF,0xAD,0x07,0xAC,0x06,0x8C,0xA2,0x8D,
+0xA3,0x75,0xA0,0x01,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAE,
+0xA1,0xBE,0x00,0xF0,0xAE,0xA6,0xAF,0xA7,
+0xD2,0xAF,0x22,0x90,0x06,0x24,0x12,0x03,
+0x5E,0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE,
+0xE4,0x3D,0xFD,0xE4,0x3C,0x22,0xE4,0x7F,
+0x20,0x7E,0x4E,0xFD,0xFC,0x90,0x06,0x24,
+0x12,0x03,0x6A,0xC3,0x02,0x03,0x4D,0xC2,
+0xAF,0xAB,0x07,0xAA,0x06,0x8A,0xA2,0x8B,
+0xA3,0x8C,0xA4,0x8D,0xA5,0x75,0xA0,0x03,
+0x00,0x00,0x00,0xAA,0xA1,0xBA,0x00,0xF8,
+0xD2,0xAF,0x22,0x42,0x06,0x2D,0x00,0x00,
+0x42,0x06,0x2B,0x00,0x00,0x00,0x12,0x05,
+0xDF,0x12,0x04,0xCD,0x02,0x00,0x03,0xE4,
+0xF5,0x8E,0x22};
+
+static rtk_api_ret_t _rtk_port_FiberModeAbility_set(rtk_port_t port, rtk_port_phy_ability_t *pAbility)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32      regData;
+
+    /* Check Combo port or not */
+    RTK_CHK_PORT_IS_COMBO(port);
+
+    /* Flow Control */
+    if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_FIB0_CFG04, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    if (pAbility->AsyFC == 1)
+        regData |= (0x0001 << 8);
+    else
+        regData &= ~(0x0001 << 8);
+
+    if (pAbility->FC == 1)
+        regData |= (0x0001 << 7);
+    else
+        regData &= ~(0x0001 << 7);
+
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_FIB0_CFG04, regData)) != RT_ERR_OK)
+        return retVal;
+
+    /* Speed ability */
+    if( (pAbility->Full_1000 == 1) && (pAbility->Full_100 == 1) && (pAbility->AutoNegotiation == 1) )
+    {
+        if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_FRC_MODE_OFFSET, 0)) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_MODE_MASK, 7)) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_FIB0_CFG00, 0x1140)) != RT_ERR_OK)
+            return retVal;
+    }
+    else if(pAbility->Full_1000 == 1)
+    {
+        if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_FRC_MODE_OFFSET, 1)) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_MODE_MASK, 4)) != RT_ERR_OK)
+            return retVal;
+
+        if(pAbility->AutoNegotiation == 1)
+        {
+            if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_FIB0_CFG00, 0x1140)) != RT_ERR_OK)
+                return retVal;
+        }
+        else
+        {
+            if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_FIB0_CFG00, 0x0140)) != RT_ERR_OK)
+                return retVal;
+        }
+    }
+    else if(pAbility->Full_100 == 1)
+    {
+        if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_FRC_MODE_OFFSET, 1)) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_MODE_MASK, 5)) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_FIB0_CFG00, 0x2100)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    /* Digital software reset */
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0003)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x0080)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_SDS_INDACS_DATA, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    regData |= (0x0001 << 6);
+
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, regData)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0003)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
+        return retVal;
+
+    regData &= ~(0x0001 << 6);
+
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, regData)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0003)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
+        return retVal;
+
+    /* CDR reset */
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x1401))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0000))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x1403))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0000))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+static rtk_api_ret_t _rtk_port_FiberModeAbility_get(rtk_port_t port, rtk_port_phy_ability_t *pAbility)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32      data, regData;
+
+    /* Check Combo port or not */
+    RTK_CHK_PORT_IS_COMBO(port);
+
+    memset(pAbility, 0x00, sizeof(rtk_port_phy_ability_t));
+
+    /* Flow Control */
+    if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_FRC_REG4_OFFSET, 1)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_FRC_REG4_FIB100_OFFSET, 0)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0044)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x0080)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_SDS_INDACS_DATA, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    if(regData & (0x0001 << 8))
+        pAbility->AsyFC = 1;
+
+    if(regData & (0x0001 << 7))
+        pAbility->FC = 1;
+
+    /* Speed ability */
+    if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_FRC_MODE_OFFSET, &data)) != RT_ERR_OK)
+            return retVal;
+
+    if(data == 0)
+    {
+        pAbility->AutoNegotiation = 1;
+        pAbility->Full_1000 = 1;
+        pAbility->Full_100 = 1;
+    }
+    else
+    {
+        if ((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_MODE_MASK, &data)) != RT_ERR_OK)
+            return retVal;
+
+        if(data == 4)
+        {
+            pAbility->Full_1000 = 1;
+
+            if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_FIB0_CFG00, &data)) != RT_ERR_OK)
+                return retVal;
+
+            if(data & 0x1000)
+                pAbility->AutoNegotiation = 1;
+            else
+                pAbility->AutoNegotiation = 0;
+        }
+        else if(data == 5)
+            pAbility->Full_100 = 1;
+        else
+            return RT_ERR_FAILED;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_phyAutoNegoAbility_set
+ * Description:
+ *      Set ethernet PHY auto-negotiation desired ability.
+ * Input:
+ *      port        - port id.
+ *      pAbility    - Ability structure
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_PHY_REG_ID       - Invalid PHY address
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy
+ * Note:
+ *      If Full_1000 bit is set to 1, the AutoNegotiation will be automatic set to 1. While both AutoNegotiation and Full_1000 are set to 0, the PHY speed and duplex selection will
+ *      be set as following 100F > 100H > 10F > 10H priority sequence.
+ */
+rtk_api_ret_t rtk_port_phyAutoNegoAbility_set(rtk_port_t port, rtk_port_phy_ability_t *pAbility)
+{
+    rtk_api_ret_t       retVal;
+    rtk_uint32          phyData;
+    rtk_uint32          phyEnMsk0;
+    rtk_uint32          phyEnMsk4;
+    rtk_uint32          phyEnMsk9;
+    rtk_port_media_t    media_type;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_IS_UTP(port);
+
+    if(NULL == pAbility)
+        return RT_ERR_NULL_POINTER;
+
+    if (pAbility->Half_10 >= RTK_ENABLE_END || pAbility->Full_10 >= RTK_ENABLE_END ||
+       pAbility->Half_100 >= RTK_ENABLE_END || pAbility->Full_100 >= RTK_ENABLE_END ||
+       pAbility->Full_1000 >= RTK_ENABLE_END || pAbility->AutoNegotiation >= RTK_ENABLE_END ||
+       pAbility->AsyFC >= RTK_ENABLE_END || pAbility->FC >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if (rtk_switch_isComboPort(port) == RT_ERR_OK)
+    {
+        if ((retVal = rtk_port_phyComboPortMedia_get(port, &media_type)) != RT_ERR_OK)
+            return retVal;
+
+        if(media_type == PORT_MEDIA_FIBER)
+        {
+            return _rtk_port_FiberModeAbility_set(port, pAbility);
+        }
+    }
+
+    /*for PHY auto mode setup*/
+    pAbility->AutoNegotiation = 1;
+
+    phyEnMsk0 = 0;
+    phyEnMsk4 = 0;
+    phyEnMsk9 = 0;
+
+    if (1 == pAbility->Half_10)
+    {
+        /*10BASE-TX half duplex capable in reg 4.5*/
+        phyEnMsk4 = phyEnMsk4 | (1 << 5);
+
+        /*Speed selection [1:0] */
+        /* 11=Reserved*/
+        /* 10= 1000Mpbs*/
+        /* 01= 100Mpbs*/
+        /* 00= 10Mpbs*/
+        phyEnMsk0 = phyEnMsk0 & (~(1 << 6));
+        phyEnMsk0 = phyEnMsk0 & (~(1 << 13));
+    }
+
+    if (1 == pAbility->Full_10)
+    {
+        /*10BASE-TX full duplex capable in reg 4.6*/
+        phyEnMsk4 = phyEnMsk4 | (1 << 6);
+        /*Speed selection [1:0] */
+        /* 11=Reserved*/
+        /* 10= 1000Mpbs*/
+        /* 01= 100Mpbs*/
+        /* 00= 10Mpbs*/
+        phyEnMsk0 = phyEnMsk0 & (~(1 << 6));
+        phyEnMsk0 = phyEnMsk0 & (~(1 << 13));
+
+        /*Full duplex mode in reg 0.8*/
+        phyEnMsk0 = phyEnMsk0 | (1 << 8);
+
+    }
+
+    if (1 == pAbility->Half_100)
+    {
+        /*100BASE-TX half duplex capable in reg 4.7*/
+        phyEnMsk4 = phyEnMsk4 | (1 << 7);
+        /*Speed selection [1:0] */
+        /* 11=Reserved*/
+        /* 10= 1000Mpbs*/
+        /* 01= 100Mpbs*/
+        /* 00= 10Mpbs*/
+        phyEnMsk0 = phyEnMsk0 & (~(1 << 6));
+        phyEnMsk0 = phyEnMsk0 | (1 << 13);
+    }
+
+
+    if (1 == pAbility->Full_100)
+    {
+        /*100BASE-TX full duplex capable in reg 4.8*/
+        phyEnMsk4 = phyEnMsk4 | (1 << 8);
+        /*Speed selection [1:0] */
+        /* 11=Reserved*/
+        /* 10= 1000Mpbs*/
+        /* 01= 100Mpbs*/
+        /* 00= 10Mpbs*/
+        phyEnMsk0 = phyEnMsk0 & (~(1 << 6));
+        phyEnMsk0 = phyEnMsk0 | (1 << 13);
+        /*Full duplex mode in reg 0.8*/
+        phyEnMsk0 = phyEnMsk0 | (1 << 8);
+    }
+
+
+    if (1 == pAbility->Full_1000)
+    {
+        /*1000 BASE-T FULL duplex capable setting in reg 9.9*/
+        phyEnMsk9 = phyEnMsk9 | (1 << 9);
+
+        /*Speed selection [1:0] */
+        /* 11=Reserved*/
+        /* 10= 1000Mpbs*/
+        /* 01= 100Mpbs*/
+        /* 00= 10Mpbs*/
+        phyEnMsk0 = phyEnMsk0 | (1 << 6);
+        phyEnMsk0 = phyEnMsk0 & (~(1 << 13));
+
+
+        /*Auto-Negotiation setting in reg 0.12*/
+        phyEnMsk0 = phyEnMsk0 | (1 << 12);
+
+     }
+
+    if (1 == pAbility->AutoNegotiation)
+    {
+        /*Auto-Negotiation setting in reg 0.12*/
+        phyEnMsk0 = phyEnMsk0 | (1 << 12);
+    }
+
+    if (1 == pAbility->AsyFC)
+    {
+        /*Asymetric flow control in reg 4.11*/
+        phyEnMsk4 = phyEnMsk4 | (1 << 11);
+    }
+    if (1 == pAbility->FC)
+    {
+        /*Flow control in reg 4.10*/
+        phyEnMsk4 = phyEnMsk4 | (1 << 10);
+    }
+
+    /*1000 BASE-T control register setting*/
+    if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_1000_BASET_CONTROL_REG, &phyData)) != RT_ERR_OK)
+        return retVal;
+
+    phyData = (phyData & (~0x0200)) | phyEnMsk9 ;
+
+    if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_1000_BASET_CONTROL_REG, phyData)) != RT_ERR_OK)
+        return retVal;
+
+    /*Auto-Negotiation control register setting*/
+    if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_AN_ADVERTISEMENT_REG, &phyData)) != RT_ERR_OK)
+        return retVal;
+
+    phyData = (phyData & (~0x0DE0)) | phyEnMsk4;
+    if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_AN_ADVERTISEMENT_REG, phyData)) != RT_ERR_OK)
+        return retVal;
+
+    /*Control register setting and restart auto*/
+    if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, &phyData)) != RT_ERR_OK)
+        return retVal;
+
+    phyData = (phyData & (~0x3140)) | phyEnMsk0;
+    /*If have auto-negotiation capable, then restart auto negotiation*/
+    if (1 == pAbility->AutoNegotiation)
+    {
+        phyData = phyData | (1 << 9);
+    }
+
+    if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, phyData)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_phyAutoNegoAbility_get
+ * Description:
+ *      Get PHY ability through PHY registers.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pAbility - Ability structure
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_PHY_REG_ID       - Invalid PHY address
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy
+ * Note:
+ *      Get the capablity of specified PHY.
+ */
+rtk_api_ret_t rtk_port_phyAutoNegoAbility_get(rtk_port_t port, rtk_port_phy_ability_t *pAbility)
+{
+    rtk_api_ret_t       retVal;
+    rtk_uint32          phyData0;
+    rtk_uint32          phyData4;
+    rtk_uint32          phyData9;
+    rtk_port_media_t    media_type;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_IS_UTP(port);
+
+    if(NULL == pAbility)
+        return RT_ERR_NULL_POINTER;
+
+    if (rtk_switch_isComboPort(port) == RT_ERR_OK)
+    {
+        if ((retVal = rtk_port_phyComboPortMedia_get(port, &media_type)) != RT_ERR_OK)
+            return retVal;
+
+        if(media_type == PORT_MEDIA_FIBER)
+        {
+            return _rtk_port_FiberModeAbility_get(port, pAbility);
+        }
+    }
+
+    /*Control register setting and restart auto*/
+    if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, &phyData0)) != RT_ERR_OK)
+        return retVal;
+
+    /*Auto-Negotiation control register setting*/
+    if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_AN_ADVERTISEMENT_REG, &phyData4)) != RT_ERR_OK)
+        return retVal;
+
+    /*1000 BASE-T control register setting*/
+    if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_1000_BASET_CONTROL_REG, &phyData9)) != RT_ERR_OK)
+        return retVal;
+
+    if (phyData9 & (1 << 9))
+        pAbility->Full_1000 = 1;
+    else
+        pAbility->Full_1000 = 0;
+
+    if (phyData4 & (1 << 11))
+        pAbility->AsyFC = 1;
+    else
+        pAbility->AsyFC = 0;
+
+    if (phyData4 & (1 << 10))
+        pAbility->FC = 1;
+    else
+        pAbility->FC = 0;
+
+
+    if (phyData4 & (1 << 8))
+        pAbility->Full_100 = 1;
+    else
+        pAbility->Full_100 = 0;
+
+    if (phyData4 & (1 << 7))
+        pAbility->Half_100 = 1;
+    else
+        pAbility->Half_100 = 0;
+
+    if (phyData4 & (1 << 6))
+        pAbility->Full_10 = 1;
+    else
+        pAbility->Full_10 = 0;
+
+    if (phyData4 & (1 << 5))
+        pAbility->Half_10 = 1;
+    else
+        pAbility->Half_10 = 0;
+
+
+    if (phyData0 & (1 << 12))
+        pAbility->AutoNegotiation = 1;
+    else
+        pAbility->AutoNegotiation = 0;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_phyForceModeAbility_set
+ * Description:
+ *      Set the port speed/duplex mode/pause/asy_pause in the PHY force mode.
+ * Input:
+ *      port        - port id.
+ *      pAbility    - Ability structure
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_PHY_REG_ID       - Invalid PHY address
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy
+ * Note:
+ *      While both AutoNegotiation and Full_1000 are set to 0, the PHY speed and duplex selection will
+ *      be set as following 100F > 100H > 10F > 10H priority sequence.
+ *      This API can be used to configure combo port in fiber mode.
+ *      The possible parameters in fiber mode are Full_1000 and Full 100.
+ *      All the other fields in rtk_port_phy_ability_t will be ignored in fiber port.
+ */
+rtk_api_ret_t rtk_port_phyForceModeAbility_set(rtk_port_t port, rtk_port_phy_ability_t *pAbility)
+{
+     rtk_api_ret_t      retVal;
+     rtk_uint32         phyData;
+     rtk_uint32         phyEnMsk0;
+     rtk_uint32         phyEnMsk4;
+     rtk_uint32         phyEnMsk9;
+     rtk_port_media_t   media_type;
+
+     /* Check initialization state */
+     RTK_CHK_INIT_STATE();
+
+     /* Check Port Valid */
+     RTK_CHK_PORT_IS_UTP(port);
+
+     if(NULL == pAbility)
+        return RT_ERR_NULL_POINTER;
+
+     if (pAbility->Half_10 >= RTK_ENABLE_END || pAbility->Full_10 >= RTK_ENABLE_END ||
+        pAbility->Half_100 >= RTK_ENABLE_END || pAbility->Full_100 >= RTK_ENABLE_END ||
+        pAbility->Full_1000 >= RTK_ENABLE_END || pAbility->AutoNegotiation >= RTK_ENABLE_END ||
+        pAbility->AsyFC >= RTK_ENABLE_END || pAbility->FC >= RTK_ENABLE_END)
+         return RT_ERR_INPUT;
+
+     if (rtk_switch_isComboPort(port) == RT_ERR_OK)
+     {
+         if ((retVal = rtk_port_phyComboPortMedia_get(port, &media_type)) != RT_ERR_OK)
+             return retVal;
+
+         if(media_type == PORT_MEDIA_FIBER)
+         {
+             return _rtk_port_FiberModeAbility_set(port, pAbility);
+         }
+     }
+
+     if (1 == pAbility->Full_1000)
+         return RT_ERR_INPUT;
+
+     /*for PHY force mode setup*/
+     pAbility->AutoNegotiation = 0;
+
+     phyEnMsk0 = 0;
+     phyEnMsk4 = 0;
+     phyEnMsk9 = 0;
+
+     if (1 == pAbility->Half_10)
+     {
+         /*10BASE-TX half duplex capable in reg 4.5*/
+         phyEnMsk4 = phyEnMsk4 | (1 << 5);
+
+         /*Speed selection [1:0] */
+         /* 11=Reserved*/
+         /* 10= 1000Mpbs*/
+         /* 01= 100Mpbs*/
+         /* 00= 10Mpbs*/
+         phyEnMsk0 = phyEnMsk0 & (~(1 << 6));
+         phyEnMsk0 = phyEnMsk0 & (~(1 << 13));
+     }
+
+     if (1 == pAbility->Full_10)
+     {
+         /*10BASE-TX full duplex capable in reg 4.6*/
+         phyEnMsk4 = phyEnMsk4 | (1 << 6);
+         /*Speed selection [1:0] */
+         /* 11=Reserved*/
+         /* 10= 1000Mpbs*/
+         /* 01= 100Mpbs*/
+         /* 00= 10Mpbs*/
+         phyEnMsk0 = phyEnMsk0 & (~(1 << 6));
+         phyEnMsk0 = phyEnMsk0 & (~(1 << 13));
+
+         /*Full duplex mode in reg 0.8*/
+         phyEnMsk0 = phyEnMsk0 | (1 << 8);
+
+     }
+
+     if (1 == pAbility->Half_100)
+     {
+         /*100BASE-TX half duplex capable in reg 4.7*/
+         phyEnMsk4 = phyEnMsk4 | (1 << 7);
+         /*Speed selection [1:0] */
+         /* 11=Reserved*/
+         /* 10= 1000Mpbs*/
+         /* 01= 100Mpbs*/
+         /* 00= 10Mpbs*/
+         phyEnMsk0 = phyEnMsk0 & (~(1 << 6));
+         phyEnMsk0 = phyEnMsk0 | (1 << 13);
+     }
+
+
+     if (1 == pAbility->Full_100)
+     {
+         /*100BASE-TX full duplex capable in reg 4.8*/
+         phyEnMsk4 = phyEnMsk4 | (1 << 8);
+         /*Speed selection [1:0] */
+         /* 11=Reserved*/
+         /* 10= 1000Mpbs*/
+         /* 01= 100Mpbs*/
+         /* 00= 10Mpbs*/
+         phyEnMsk0 = phyEnMsk0 & (~(1 << 6));
+         phyEnMsk0 = phyEnMsk0 | (1 << 13);
+         /*Full duplex mode in reg 0.8*/
+         phyEnMsk0 = phyEnMsk0 | (1 << 8);
+     }
+
+     if (1 == pAbility->AsyFC)
+     {
+         /*Asymetric flow control in reg 4.11*/
+         phyEnMsk4 = phyEnMsk4 | (1 << 11);
+     }
+     if (1 == pAbility->FC)
+     {
+         /*Flow control in reg 4.10*/
+         phyEnMsk4 = phyEnMsk4 | ((1 << 10));
+     }
+
+     /*1000 BASE-T control register setting*/
+     if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_1000_BASET_CONTROL_REG, &phyData)) != RT_ERR_OK)
+         return retVal;
+
+     phyData = (phyData & (~0x0200)) | phyEnMsk9 ;
+
+     if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_1000_BASET_CONTROL_REG, phyData)) != RT_ERR_OK)
+         return retVal;
+
+     /*Auto-Negotiation control register setting*/
+     if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_AN_ADVERTISEMENT_REG, &phyData)) != RT_ERR_OK)
+         return retVal;
+
+     phyData = (phyData & (~0x0DE0)) | phyEnMsk4;
+     if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_AN_ADVERTISEMENT_REG, phyData)) != RT_ERR_OK)
+         return retVal;
+
+     /*Control register setting and power off/on*/
+     phyData = phyEnMsk0 & (~(1 << 12));
+     phyData |= (1 << 11);   /* power down PHY, bit 11 should be set to 1 */
+     if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, phyData)) != RT_ERR_OK)
+         return retVal;
+
+     phyData = phyData & (~(1 << 11));   /* power on PHY, bit 11 should be set to 0*/
+     if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, phyData)) != RT_ERR_OK)
+         return retVal;
+
+     return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_phyForceModeAbility_get
+ * Description:
+ *      Get PHY ability through PHY registers.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pAbility - Ability structure
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_PHY_REG_ID       - Invalid PHY address
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy
+ * Note:
+ *      Get the capablity of specified PHY.
+ */
+rtk_api_ret_t rtk_port_phyForceModeAbility_get(rtk_port_t port, rtk_port_phy_ability_t *pAbility)
+{
+    rtk_api_ret_t       retVal;
+    rtk_uint32          phyData0;
+    rtk_uint32          phyData4;
+    rtk_uint32          phyData9;
+    rtk_port_media_t    media_type;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+     RTK_CHK_PORT_IS_UTP(port);
+
+     if(NULL == pAbility)
+        return RT_ERR_NULL_POINTER;
+
+     if (rtk_switch_isComboPort(port) == RT_ERR_OK)
+     {
+         if ((retVal = rtk_port_phyComboPortMedia_get(port, &media_type)) != RT_ERR_OK)
+             return retVal;
+
+         if(media_type == PORT_MEDIA_FIBER)
+         {
+             return _rtk_port_FiberModeAbility_get(port, pAbility);
+         }
+     }
+
+    /*Control register setting and restart auto*/
+    if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, &phyData0)) != RT_ERR_OK)
+        return retVal;
+
+    /*Auto-Negotiation control register setting*/
+    if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_AN_ADVERTISEMENT_REG, &phyData4)) != RT_ERR_OK)
+        return retVal;
+
+    /*1000 BASE-T control register setting*/
+    if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_1000_BASET_CONTROL_REG, &phyData9)) != RT_ERR_OK)
+        return retVal;
+
+    if (phyData9 & (1 << 9))
+        pAbility->Full_1000 = 1;
+    else
+        pAbility->Full_1000 = 0;
+
+    if (phyData4 & (1 << 11))
+        pAbility->AsyFC = 1;
+    else
+        pAbility->AsyFC = 0;
+
+    if (phyData4 & ((1 << 10)))
+        pAbility->FC = 1;
+    else
+        pAbility->FC = 0;
+
+
+    if (phyData4 & (1 << 8))
+        pAbility->Full_100 = 1;
+    else
+        pAbility->Full_100 = 0;
+
+    if (phyData4 & (1 << 7))
+        pAbility->Half_100 = 1;
+    else
+        pAbility->Half_100 = 0;
+
+    if (phyData4 & (1 << 6))
+        pAbility->Full_10 = 1;
+    else
+        pAbility->Full_10 = 0;
+
+    if (phyData4 & (1 << 5))
+        pAbility->Half_10 = 1;
+    else
+        pAbility->Half_10 = 0;
+
+
+    if (phyData0 & (1 << 12))
+        pAbility->AutoNegotiation = 1;
+    else
+        pAbility->AutoNegotiation = 0;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_phyStatus_get
+ * Description:
+ *      Get ethernet PHY linking status
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      linkStatus  - PHY link status
+ *      speed       - PHY link speed
+ *      duplex      - PHY duplex mode
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_PHY_REG_ID       - Invalid PHY address
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy
+ * Note:
+ *      API will return auto negotiation status of phy.
+ */
+rtk_api_ret_t rtk_port_phyStatus_get(rtk_port_t port, rtk_port_linkStatus_t *pLinkStatus, rtk_port_speed_t *pSpeed, rtk_port_duplex_t *pDuplex)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 phyData;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_IS_UTP(port);
+
+    if( (NULL == pLinkStatus) || (NULL == pSpeed) || (NULL == pDuplex) )
+        return RT_ERR_NULL_POINTER;
+
+    /*Get PHY resolved register*/
+    if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_RESOLVED_REG, &phyData)) != RT_ERR_OK)
+        return retVal;
+
+    /*check link status*/
+    if (phyData & (1<<2))
+    {
+        *pLinkStatus = 1;
+
+        /*check link speed*/
+        *pSpeed = (phyData&0x0030) >> 4;
+
+        /*check link duplex*/
+        *pDuplex = (phyData&0x0008) >> 3;
+    }
+    else
+    {
+        *pLinkStatus = 0;
+        *pSpeed = 0;
+        *pDuplex = 0;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_macForceLink_set
+ * Description:
+ *      Set port force linking configuration.
+ * Input:
+ *      port            - port id.
+ *      pPortability    - port ability configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API can set Port/MAC force mode properties.
+ */
+rtk_api_ret_t rtk_port_macForceLink_set(rtk_port_t port, rtk_port_mac_ability_t *pPortability)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_port_ability_t ability;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_IS_UTP(port);
+
+    if(NULL == pPortability)
+        return RT_ERR_NULL_POINTER;
+
+    if (pPortability->forcemode >1|| pPortability->speed > 2 || pPortability->duplex > 1 ||
+       pPortability->link > 1 || pPortability->nway > 1 || pPortability->txpause > 1 || pPortability->rxpause > 1)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_getAsicPortForceLink(rtk_switch_port_L2P_get(port), &ability)) != RT_ERR_OK)
+        return retVal;
+
+    ability.forcemode = pPortability->forcemode;
+    ability.speed     = pPortability->speed;
+    ability.duplex    = pPortability->duplex;
+    ability.link      = pPortability->link;
+    ability.nway      = pPortability->nway;
+    ability.txpause   = pPortability->txpause;
+    ability.rxpause   = pPortability->rxpause;
+
+    if ((retVal = rtl8367c_setAsicPortForceLink(rtk_switch_port_L2P_get(port), &ability)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_macForceLink_get
+ * Description:
+ *      Get port force linking configuration.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pPortability - port ability configuration
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API can get Port/MAC force mode properties.
+ */
+rtk_api_ret_t rtk_port_macForceLink_get(rtk_port_t port, rtk_port_mac_ability_t *pPortability)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_port_ability_t ability;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_IS_UTP(port);
+
+    if(NULL == pPortability)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicPortForceLink(rtk_switch_port_L2P_get(port), &ability)) != RT_ERR_OK)
+        return retVal;
+
+    pPortability->forcemode = ability.forcemode;
+    pPortability->speed     = ability.speed;
+    pPortability->duplex    = ability.duplex;
+    pPortability->link      = ability.link;
+    pPortability->nway      = ability.nway;
+    pPortability->txpause   = ability.txpause;
+    pPortability->rxpause   = ability.rxpause;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_macForceLinkExt_set
+ * Description:
+ *      Set external interface force linking configuration.
+ * Input:
+ *      port            - external port ID
+ *      mode            - external interface mode
+ *      pPortability    - port ability configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API can set external interface force mode properties.
+ *      The external interface can be set to:
+ *      - MODE_EXT_DISABLE,
+ *      - MODE_EXT_RGMII,
+ *      - MODE_EXT_MII_MAC,
+ *      - MODE_EXT_MII_PHY,
+ *      - MODE_EXT_TMII_MAC,
+ *      - MODE_EXT_TMII_PHY,
+ *      - MODE_EXT_GMII,
+ *      - MODE_EXT_RMII_MAC,
+ *      - MODE_EXT_RMII_PHY,
+ *      - MODE_EXT_SGMII,
+ *      - MODE_EXT_HSGMII,
+ *      - MODE_EXT_1000X_100FX,
+ *      - MODE_EXT_1000X,
+ *      - MODE_EXT_100FX,
+ */
+rtk_api_ret_t rtk_port_macForceLinkExt_set(rtk_port_t port, rtk_mode_ext_t mode, rtk_port_mac_ability_t *pPortability)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_port_ability_t ability;
+    rtk_uint32 ext_id;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_IS_EXT(port);
+
+    if(NULL == pPortability)
+        return RT_ERR_NULL_POINTER;
+
+    if (mode >=MODE_EXT_END)
+        return RT_ERR_INPUT;
+
+    if(mode == MODE_EXT_HSGMII)
+    {
+        if (pPortability->forcemode > 1 || pPortability->speed != PORT_SPEED_2500M || pPortability->duplex != PORT_FULL_DUPLEX ||
+           pPortability->link >= PORT_LINKSTATUS_END || pPortability->nway > 1 || pPortability->txpause > 1 || pPortability->rxpause > 1)
+            return RT_ERR_INPUT;
+
+        if(rtk_switch_isHsgPort(port) != RT_ERR_OK)
+            return RT_ERR_PORT_ID;
+    }
+    else
+    {
+        if (pPortability->forcemode > 1 || pPortability->speed > PORT_SPEED_1000M || pPortability->duplex >= PORT_DUPLEX_END ||
+           pPortability->link >= PORT_LINKSTATUS_END || pPortability->nway > 1 || pPortability->txpause > 1 || pPortability->rxpause > 1)
+            return RT_ERR_INPUT;
+    }
+
+    ext_id = port - 15;
+
+    if(mode == MODE_EXT_DISABLE)
+    {
+        memset(&ability, 0x00, sizeof(rtl8367c_port_ability_t));
+        if ((retVal = rtl8367c_setAsicPortForceLinkExt(ext_id, &ability)) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicPortExtMode(ext_id, mode)) != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        if ((retVal = rtl8367c_setAsicPortExtMode(ext_id, mode)) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_getAsicPortForceLinkExt(ext_id, &ability)) != RT_ERR_OK)
+            return retVal;
+
+        ability.forcemode = pPortability->forcemode;
+        ability.speed     = (mode == MODE_EXT_HSGMII) ? PORT_SPEED_1000M : pPortability->speed;
+        ability.duplex    = pPortability->duplex;
+        ability.link      = pPortability->link;
+        ability.nway      = pPortability->nway;
+        ability.txpause   = pPortability->txpause;
+        ability.rxpause   = pPortability->rxpause;
+
+        if ((retVal = rtl8367c_setAsicPortForceLinkExt(ext_id, &ability)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_macForceLinkExt_get
+ * Description:
+ *      Set external interface force linking configuration.
+ * Input:
+ *      port            - external port ID
+ * Output:
+ *      pMode           - external interface mode
+ *      pPortability    - port ability configuration
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API can get external interface force mode properties.
+ */
+rtk_api_ret_t rtk_port_macForceLinkExt_get(rtk_port_t port, rtk_mode_ext_t *pMode, rtk_port_mac_ability_t *pPortability)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_port_ability_t ability;
+    rtk_uint32 ext_id;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_IS_EXT(port);
+
+    if(NULL == pMode)
+        return RT_ERR_NULL_POINTER;
+
+    if(NULL == pPortability)
+        return RT_ERR_NULL_POINTER;
+
+    ext_id = port - 15;
+
+    if ((retVal = rtl8367c_getAsicPortExtMode(ext_id, (rtk_uint32 *)pMode)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicPortForceLinkExt(ext_id, &ability)) != RT_ERR_OK)
+        return retVal;
+
+    pPortability->forcemode = ability.forcemode;
+    pPortability->speed     = (*pMode == MODE_EXT_HSGMII) ? PORT_SPEED_2500M : ability.speed;
+    pPortability->duplex    = ability.duplex;
+    pPortability->link      = ability.link;
+    pPortability->nway      = ability.nway;
+    pPortability->txpause   = ability.txpause;
+    pPortability->rxpause   = ability.rxpause;
+
+    return RT_ERR_OK;
+
+}
+
+/* Function Name:
+ *      rtk_port_macStatus_get
+ * Description:
+ *      Get port link status.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pPortstatus - port ability configuration
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API can get Port/PHY properties.
+ */
+rtk_api_ret_t rtk_port_macStatus_get(rtk_port_t port, rtk_port_mac_ability_t *pPortstatus)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_port_status_t status;
+    rtk_uint32 hsgsel;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pPortstatus)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicPortStatus(rtk_switch_port_L2P_get(port), &status)) != RT_ERR_OK)
+        return retVal;
+
+
+    pPortstatus->duplex    = status.duplex;
+    pPortstatus->link      = status.link;
+    pPortstatus->nway      = status.nway;
+    pPortstatus->txpause   = status.txpause;
+    pPortstatus->rxpause   = status.rxpause;
+
+    if( (retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, &hsgsel)) != RT_ERR_OK)
+            return retVal;
+
+    if( (rtk_switch_isHsgPort(port) == RT_ERR_OK) && (hsgsel == 1) )
+        pPortstatus->speed = PORT_SPEED_2500M;
+    else
+        pPortstatus->speed = status.speed;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_macLocalLoopbackEnable_set
+ * Description:
+ *      Set Port Local Loopback. (Redirect TX to RX.)
+ * Input:
+ *      port    - Port id.
+ *      enable  - Loopback state, 0:disable, 1:enable
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API can enable/disable Local loopback in MAC.
+ *      For UTP port, This API will also enable the digital
+ *      loopback bit in PHY register for sync of speed between
+ *      PHY and MAC. For EXT port, users need to force the
+ *      link state by themself.
+ */
+rtk_api_ret_t rtk_port_macLocalLoopbackEnable_set(rtk_port_t port, rtk_enable_t enable)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32      data;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(enable >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicPortLoopback(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK)
+        return retVal;
+
+    if(rtk_switch_isUtpPort(port) == RT_ERR_OK)
+    {
+        if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, &data)) != RT_ERR_OK)
+            return retVal;
+
+        if(enable == ENABLED)
+            data |= (0x0001 << 14);
+        else
+            data &= ~(0x0001 << 14);
+
+        if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, data)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_macLocalLoopbackEnable_get
+ * Description:
+ *      Get Port Local Loopback. (Redirect TX to RX.)
+ * Input:
+ *      port    - Port id.
+ * Output:
+ *      pEnable  - Loopback state, 0:disable, 1:enable
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      None.
+ */
+rtk_api_ret_t rtk_port_macLocalLoopbackEnable_get(rtk_port_t port, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicPortLoopback(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_phyReg_set
+ * Description:
+ *      Set PHY register data of the specific port.
+ * Input:
+ *      port    - port id.
+ *      reg     - Register id
+ *      regData - Register data
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_PHY_REG_ID       - Invalid PHY address
+ *      RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy
+ * Note:
+ *      This API can set PHY register data of the specific port.
+ */
+rtk_api_ret_t rtk_port_phyReg_set(rtk_port_t port, rtk_port_phy_reg_t reg, rtk_port_phy_data_t regData)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_IS_UTP(port);
+
+    if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), reg, regData)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_phyReg_get
+ * Description:
+ *      Get PHY register data of the specific port.
+ * Input:
+ *      port    - Port id.
+ *      reg     - Register id
+ * Output:
+ *      pData   - Register data
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_PHY_REG_ID       - Invalid PHY address
+ *      RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy
+ * Note:
+ *      This API can get PHY register data of the specific port.
+ */
+rtk_api_ret_t rtk_port_phyReg_get(rtk_port_t port, rtk_port_phy_reg_t reg, rtk_port_phy_data_t *pData)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_IS_UTP(port);
+
+    if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), reg, pData)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_backpressureEnable_set
+ * Description:
+ *      Set the half duplex backpressure enable status of the specific port.
+ * Input:
+ *      port    - port id.
+ *      enable  - Back pressure status.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_ENABLE       - Invalid enable input.
+ * Note:
+ *      This API can set the half duplex backpressure enable status of the specific port.
+ *      The half duplex backpressure enable status of the port is as following:
+ *      - DISABLE(Defer)
+ *      - ENABLE (Backpressure)
+ */
+rtk_api_ret_t rtk_port_backpressureEnable_set(rtk_port_t port, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (port != RTK_WHOLE_SYSTEM)
+        return RT_ERR_PORT_ID;
+
+    if (enable >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicPortJamMode(!enable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_backpressureEnable_get
+ * Description:
+ *      Get the half duplex backpressure enable status of the specific port.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEnable - Back pressure status.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API can get the half duplex backpressure enable status of the specific port.
+ *      The half duplex backpressure enable status of the port is as following:
+ *      - DISABLE(Defer)
+ *      - ENABLE (Backpressure)
+ */
+rtk_api_ret_t rtk_port_backpressureEnable_get(rtk_port_t port, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 regData;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (port != RTK_WHOLE_SYSTEM)
+        return RT_ERR_PORT_ID;
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicPortJamMode(&regData)) != RT_ERR_OK)
+        return retVal;
+
+    *pEnable = !regData;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_adminEnable_set
+ * Description:
+ *      Set port admin configuration of the specific port.
+ * Input:
+ *      port    - port id.
+ *      enable  - Back pressure status.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_ENABLE       - Invalid enable input.
+ * Note:
+ *      This API can set port admin configuration of the specific port.
+ *      The port admin configuration of the port is as following:
+ *      - DISABLE
+ *      - ENABLE
+ */
+rtk_api_ret_t rtk_port_adminEnable_set(rtk_port_t port, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32      data;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_IS_UTP(port);
+
+    if (enable >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtk_port_phyReg_get(port, PHY_CONTROL_REG, &data)) != RT_ERR_OK)
+        return retVal;
+
+    if (ENABLED == enable)
+    {
+        data &= 0xF7FF;
+        data |= 0x0200;
+    }
+    else if (DISABLED == enable)
+    {
+        data |= 0x0800;
+    }
+
+    if ((retVal = rtk_port_phyReg_set(port, PHY_CONTROL_REG, data)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_adminEnable_get
+ * Description:
+ *      Get port admin configurationof the specific port.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEnable - Back pressure status.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API can get port admin configuration of the specific port.
+ *      The port admin configuration of the port is as following:
+ *      - DISABLE
+ *      - ENABLE
+ */
+rtk_api_ret_t rtk_port_adminEnable_get(rtk_port_t port, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32      data;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_IS_UTP(port);
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtk_port_phyReg_get(port, PHY_CONTROL_REG, &data)) != RT_ERR_OK)
+        return retVal;
+
+    if ( (data & 0x0800) == 0x0800)
+    {
+        *pEnable = DISABLED;
+    }
+    else
+    {
+        *pEnable = ENABLED;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_isolation_set
+ * Description:
+ *      Set permitted port isolation portmask
+ * Input:
+ *      port         - port id.
+ *      pPortmask    - Permit port mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_PORT_MASK    - Invalid portmask.
+ * Note:
+ *      This API set the port mask that a port can trasmit packet to of each port
+ *      A port can only transmit packet to ports included in permitted portmask
+ */
+rtk_api_ret_t rtk_port_isolation_set(rtk_port_t port, rtk_portmask_t *pPortmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pPortmask)
+        return RT_ERR_NULL_POINTER;
+
+    /* check port mask */
+    RTK_CHK_PORTMASK_VALID(pPortmask);
+
+    if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicPortIsolationPermittedPortmask(rtk_switch_port_L2P_get(port), pmask)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_isolation_get
+ * Description:
+ *      Get permitted port isolation portmask
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pPortmask - Permit port mask
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API get the port mask that a port can trasmit packet to of each port
+ *      A port can only transmit packet to ports included in permitted portmask
+ */
+rtk_api_ret_t rtk_port_isolation_get(rtk_port_t port, rtk_portmask_t *pPortmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pPortmask)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicPortIsolationPermittedPortmask(rtk_switch_port_L2P_get(port), &pmask)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_rgmiiDelayExt_set
+ * Description:
+ *      Set RGMII interface delay value for TX and RX.
+ * Input:
+ *      txDelay - TX delay value, 1 for delay 2ns and 0 for no-delay
+ *      rxDelay - RX delay value, 0~7 for delay setup.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API can set external interface 2 RGMII delay.
+ *      In TX delay, there are 2 selection: no-delay and 2ns delay.
+ *      In RX dekay, there are 8 steps for delay tunning. 0 for no-delay, and 7 for maximum delay.
+ */
+rtk_api_ret_t rtk_port_rgmiiDelayExt_set(rtk_port_t port, rtk_data_t txDelay, rtk_data_t rxDelay)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 regAddr, regData;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_IS_EXT(port);
+
+    if ((txDelay > 1) || (rxDelay > 7))
+        return RT_ERR_INPUT;
+
+    if(port == EXT_PORT0)
+        regAddr = RTL8367C_REG_EXT1_RGMXF;
+    else if(port == EXT_PORT1)
+        regAddr = RTL8367C_REG_EXT2_RGMXF;
+    else
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_getAsicReg(regAddr, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    regData = (regData & 0xFFF0) | ((txDelay << 3) & 0x0008) | (rxDelay & 0x0007);
+
+    if ((retVal = rtl8367c_setAsicReg(regAddr, regData)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_rgmiiDelayExt_get
+ * Description:
+ *      Get RGMII interface delay value for TX and RX.
+ * Input:
+ *      None
+ * Output:
+ *      pTxDelay - TX delay value
+ *      pRxDelay - RX delay value
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API can set external interface 2 RGMII delay.
+ *      In TX delay, there are 2 selection: no-delay and 2ns delay.
+ *      In RX dekay, there are 8 steps for delay tunning. 0 for n0-delay, and 7 for maximum delay.
+ */
+rtk_api_ret_t rtk_port_rgmiiDelayExt_get(rtk_port_t port, rtk_data_t *pTxDelay, rtk_data_t *pRxDelay)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 regAddr, regData;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_IS_EXT(port);
+
+    if( (NULL == pTxDelay) || (NULL == pRxDelay) )
+        return RT_ERR_NULL_POINTER;
+
+    if(port == EXT_PORT0)
+        regAddr = RTL8367C_REG_EXT1_RGMXF;
+    else if(port == EXT_PORT1)
+        regAddr = RTL8367C_REG_EXT2_RGMXF;
+    else
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_getAsicReg(regAddr, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    *pTxDelay = (regData & 0x0008) >> 3;
+    *pRxDelay = regData & 0x0007;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_phyEnableAll_set
+ * Description:
+ *      Set all PHY enable status.
+ * Input:
+ *      enable - PHY Enable State.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_ENABLE       - Invalid enable input.
+ * Note:
+ *      This API can set all PHY status.
+ *      The configuration of all PHY is as following:
+ *      - DISABLE
+ *      - ENABLE
+ */
+rtk_api_ret_t rtk_port_phyEnableAll_set(rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 data;
+    rtk_uint32 port;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (enable >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if ((retVal = rtl8367c_setAsicPortEnableAll(enable)) != RT_ERR_OK)
+        return retVal;
+
+    RTK_SCAN_ALL_LOG_PORT(port)
+    {
+        if(rtk_switch_isUtpPort(port) == RT_ERR_OK)
+        {
+            if ((retVal = rtk_port_phyReg_get(port, PHY_CONTROL_REG, &data)) != RT_ERR_OK)
+                return retVal;
+
+            if (ENABLED == enable)
+            {
+                data &= 0xF7FF;
+                data |= 0x0200;
+            }
+            else
+            {
+                data |= 0x0800;
+            }
+
+            if ((retVal = rtk_port_phyReg_set(port, PHY_CONTROL_REG, data)) != RT_ERR_OK)
+                return retVal;
+        }
+    }
+
+    return RT_ERR_OK;
+
+}
+
+/* Function Name:
+ *      rtk_port_phyEnableAll_get
+ * Description:
+ *      Get all PHY enable status.
+ * Input:
+ *      None
+ * Output:
+ *      pEnable - PHY Enable State.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      This API can set all PHY status.
+ *      The configuration of all PHY is as following:
+ *      - DISABLE
+ *      - ENABLE
+ */
+rtk_api_ret_t rtk_port_phyEnableAll_get(rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicPortEnableAll(pEnable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_efid_set
+ * Description:
+ *      Set port-based enhanced filtering database
+ * Input:
+ *      port - Port id.
+ *      efid - Specified enhanced filtering database.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_L2_FID - Invalid fid.
+ *      RT_ERR_INPUT - Invalid input parameter.
+ *      RT_ERR_PORT_ID - Invalid port ID.
+ * Note:
+ *      The API can set port-based enhanced filtering database.
+ */
+rtk_api_ret_t rtk_port_efid_set(rtk_port_t port, rtk_data_t efid)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    /* efid must be 0~7 */
+    if (efid > RTK_EFID_MAX)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicPortIsolationEfid(rtk_switch_port_L2P_get(port), efid))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_efid_get
+ * Description:
+ *      Get port-based enhanced filtering database
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEfid - Specified enhanced filtering database.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT - Invalid input parameters.
+ *      RT_ERR_PORT_ID - Invalid port ID.
+ * Note:
+ *      The API can get port-based enhanced filtering database status.
+ */
+rtk_api_ret_t rtk_port_efid_get(rtk_port_t port, rtk_data_t *pEfid)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pEfid)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicPortIsolationEfid(rtk_switch_port_L2P_get(port), pEfid))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_phyComboPortMedia_set
+ * Description:
+ *      Set Combo port media type
+ * Input:
+ *      port    - Port id.
+ *      media   - Media (COPPER or FIBER)
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_PORT_ID          - Invalid port ID.
+ * Note:
+ *      The API can Set Combo port media type.
+ */
+rtk_api_ret_t rtk_port_phyComboPortMedia_set(rtk_port_t port, rtk_port_media_t media)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 regData;
+    rtk_uint32 idx;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_IS_UTP(port);
+
+    /* Check Combo Port ID */
+    RTK_CHK_PORT_IS_COMBO(port);
+
+    if (media >= PORT_MEDIA_END)
+        return RT_ERR_INPUT;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_getAsicReg(0x1300, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK)
+        return retVal;
+
+    if(regData != 0x6367)
+        return RT_ERR_CHIP_NOT_SUPPORTED;
+
+    if(media == PORT_MEDIA_FIBER)
+    {
+        /* software init */
+        if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_CHIP_RESET, RTL8367C_DW8051_RST_OFFSET, 1)) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MISCELLANEOUS_CONFIGURE0, RTL8367C_DW8051_EN_OFFSET, 1)) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_ACS_IROM_ENABLE_OFFSET, 1)) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_IROM_MSB_OFFSET, 0)) != RT_ERR_OK)
+            return retVal;
+
+        for(idx = 0; idx < FIBER_INIT_SIZE; idx++)
+        {
+            if ((retVal = rtl8367c_setAsicReg(0xE000 + idx, (rtk_uint32)Fiber[idx])) != RT_ERR_OK)
+                return retVal;
+        }
+
+        if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_IROM_MSB_OFFSET, 0)) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_ACS_IROM_ENABLE_OFFSET, 0)) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_CHIP_RESET, RTL8367C_DW8051_RST_OFFSET, 0)) != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_UTP_FIB_DET, RTL8367C_UTP_FIRST_OFFSET, 1))!=RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_DW8051_READY_OFFSET, 0)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_phyComboPortMedia_get
+ * Description:
+ *      Get Combo port media type
+ * Input:
+ *      port    - Port id.
+ * Output:
+ *      pMedia  - Media (COPPER or FIBER)
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_PORT_ID          - Invalid port ID.
+ * Note:
+ *      The API can Set Combo port media type.
+ */
+rtk_api_ret_t rtk_port_phyComboPortMedia_get(rtk_port_t port, rtk_port_media_t *pMedia)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32      regData;
+    rtk_uint32      data;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_IS_UTP(port);
+
+    /* Check Combo Port ID */
+    RTK_CHK_PORT_IS_COMBO(port);
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_getAsicReg(0x1300, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK)
+        return retVal;
+
+    if(regData != 0x6367)
+    {
+        *pMedia = PORT_MEDIA_COPPER;
+    }
+    else
+    {
+        if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_UTP_FIB_DET, RTL8367C_UTP_FIRST_OFFSET, &data))!=RT_ERR_OK)
+                return retVal;
+
+        if(data == 1)
+            *pMedia = PORT_MEDIA_COPPER;
+        else
+            *pMedia = PORT_MEDIA_FIBER;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_rtctEnable_set
+ * Description:
+ *      Enable RTCT test
+ * Input:
+ *      pPortmask    - Port mask of RTCT enabled port
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_MASK        - Invalid port mask.
+ * Note:
+ *      The API can enable RTCT Test
+ */
+rtk_api_ret_t rtk_port_rtctEnable_set(rtk_portmask_t *pPortmask)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Mask Valid */
+    RTK_CHK_PORTMASK_VALID_ONLY_UTP(pPortmask);
+
+    if ((retVal = rtl8367c_setAsicPortRTCTEnable(pPortmask->bits[0]))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_rtctDisable_set
+ * Description:
+ *      Disable RTCT test
+ * Input:
+ *      pPortmask    - Port mask of RTCT disabled port
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_MASK        - Invalid port mask.
+ * Note:
+ *      The API can disable RTCT Test
+ */
+rtk_api_ret_t rtk_port_rtctDisable_set(rtk_portmask_t *pPortmask)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Mask Valid */
+    RTK_CHK_PORTMASK_VALID_ONLY_UTP(pPortmask);
+
+    if ((retVal = rtl8367c_setAsicPortRTCTDisable(pPortmask->bits[0]))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_port_rtctResult_get
+ * Description:
+ *      Get the result of RTCT test
+ * Input:
+ *      port        - Port ID
+ * Output:
+ *      pRtctResult - The result of RTCT result
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port ID.
+ *      RT_ERR_PHY_RTCT_NOT_FINISH  - Testing does not finish.
+ * Note:
+ *      The API can get RTCT test result.
+ *      RTCT test may takes 4.8 seconds to finish its test at most.
+ *      Thus, if this API return RT_ERR_PHY_RTCT_NOT_FINISH or
+ *      other error code, the result can not be referenced and
+ *      user should call this API again until this API returns
+ *      a RT_ERR_OK.
+ *      The result is stored at pRtctResult->ge_result
+ *      pRtctResult->linkType is unused.
+ *      The unit of channel length is 2.5cm. Ex. 300 means 300 * 2.5 = 750cm = 7.5M
+ */
+rtk_api_ret_t rtk_port_rtctResult_get(rtk_port_t port, rtk_rtctResult_t *pRtctResult)
+{
+    rtk_api_ret_t               retVal;
+    rtl8367c_port_rtct_result_t result;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_IS_UTP(port);
+
+    memset(pRtctResult, 0x00, sizeof(rtk_rtctResult_t));
+    if ((retVal = rtl8367c_getAsicPortRTCTResult(port, &result))!=RT_ERR_OK)
+        return retVal;
+
+    pRtctResult->result.ge_result.channelALen = result.channelALen;
+    pRtctResult->result.ge_result.channelBLen = result.channelBLen;
+    pRtctResult->result.ge_result.channelCLen = result.channelCLen;
+    pRtctResult->result.ge_result.channelDLen = result.channelDLen;
+
+    pRtctResult->result.ge_result.channelALinedriver = result.channelALinedriver;
+    pRtctResult->result.ge_result.channelBLinedriver = result.channelBLinedriver;
+    pRtctResult->result.ge_result.channelCLinedriver = result.channelCLinedriver;
+    pRtctResult->result.ge_result.channelDLinedriver = result.channelDLinedriver;
+
+    pRtctResult->result.ge_result.channelAMismatch = result.channelAMismatch;
+    pRtctResult->result.ge_result.channelBMismatch = result.channelBMismatch;
+    pRtctResult->result.ge_result.channelCMismatch = result.channelCMismatch;
+    pRtctResult->result.ge_result.channelDMismatch = result.channelDMismatch;
+
+    pRtctResult->result.ge_result.channelAOpen = result.channelAOpen;
+    pRtctResult->result.ge_result.channelBOpen = result.channelBOpen;
+    pRtctResult->result.ge_result.channelCOpen = result.channelCOpen;
+    pRtctResult->result.ge_result.channelDOpen = result.channelDOpen;
+
+    pRtctResult->result.ge_result.channelAShort = result.channelAShort;
+    pRtctResult->result.ge_result.channelBShort = result.channelBShort;
+    pRtctResult->result.ge_result.channelCShort = result.channelCShort;
+    pRtctResult->result.ge_result.channelDShort = result.channelDShort;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_port_sds_reset
+ * Description:
+ *      Reset Serdes
+ * Input:
+ *      port        - Port ID
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port ID.
+ * Note:
+ *      The API can reset Serdes
+ */
+rtk_api_ret_t rtk_port_sds_reset(rtk_port_t port)
+{
+    rtk_uint32 ext_id;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    if(rtk_switch_isSgmiiPort(port) != RT_ERR_OK)
+        return RT_ERR_PORT_ID;
+
+    ext_id = port - 15;
+    return rtl8367c_sdsReset(ext_id);
+}
+
+/* Function Name:
+ *      rtk_port_sgmiiLinkStatus_get
+ * Description:
+ *      Get SGMII status
+ * Input:
+ *      port        - Port ID
+ * Output:
+ *      pSignalDetect   - Signal detect
+ *      pSync           - Sync
+ *      pLink           - Link
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port ID.
+ * Note:
+ *      The API can reset Serdes
+ */
+rtk_api_ret_t rtk_port_sgmiiLinkStatus_get(rtk_port_t port, rtk_data_t *pSignalDetect, rtk_data_t *pSync, rtk_port_linkStatus_t *pLink)
+{
+    rtk_uint32 ext_id;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    if(rtk_switch_isSgmiiPort(port) != RT_ERR_OK)
+        return RT_ERR_PORT_ID;
+
+    if(NULL == pSignalDetect)
+        return RT_ERR_NULL_POINTER;
+
+    if(NULL == pSync)
+        return RT_ERR_NULL_POINTER;
+
+    if(NULL == pLink)
+        return RT_ERR_NULL_POINTER;
+
+    ext_id = port - 15;
+    return rtl8367c_getSdsLinkStatus(ext_id, (rtk_uint32 *)pSignalDetect, (rtk_uint32 *)pSync, (rtk_uint32 *)pLink);
+}
+
+/* Function Name:
+ *      rtk_port_sgmiiNway_set
+ * Description:
+ *      Configure SGMII/HSGMII port Nway state
+ * Input:
+ *      port        - Port ID
+ *      state       - Nway state
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port ID.
+ * Note:
+ *      The API configure SGMII/HSGMII port Nway state
+ */
+rtk_api_ret_t rtk_port_sgmiiNway_set(rtk_port_t port, rtk_enable_t state)
+{
+    rtk_uint32 ext_id;
+
+     /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    if(rtk_switch_isSgmiiPort(port) != RT_ERR_OK)
+        return RT_ERR_PORT_ID;
+
+    if(state >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    ext_id = port - 15;
+    return rtl8367c_setSgmiiNway(ext_id, (rtk_uint32)state);
+}
+
+/* Function Name:
+ *      rtk_port_sgmiiNway_get
+ * Description:
+ *      Get SGMII/HSGMII port Nway state
+ * Input:
+ *      port        - Port ID
+ * Output:
+ *      pState      - Nway state
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port ID.
+ * Note:
+ *      The API can get SGMII/HSGMII port Nway state
+ */
+rtk_api_ret_t rtk_port_sgmiiNway_get(rtk_port_t port, rtk_enable_t *pState)
+{
+    rtk_uint32 ext_id;
+
+     /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    if(rtk_switch_isSgmiiPort(port) != RT_ERR_OK)
+        return RT_ERR_PORT_ID;
+
+    if(NULL == pState)
+        return RT_ERR_NULL_POINTER;
+
+    ext_id = port - 15;
+    return rtl8367c_getSgmiiNway(ext_id, (rtk_uint32 *)pState);
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/ptp.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/ptp.c
new file mode 100644
index 0000000..40962a0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/ptp.c
@@ -0,0 +1,759 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 39583 $
+ * $Date: 2013-05-20 16:59:23 +0800 (星期一, 20 五月 2013) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in time module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <ptp.h>
+#include <string.h>
+
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_eav.h>
+
+/* Function Name:
+ *      rtk_ptp_init
+ * Description:
+ *      PTP function initialization.
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      This API is used to initialize PTP status.
+ */
+rtk_api_ret_t rtk_ptp_init(void)
+{
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_ptp_mac_set
+ * Description:
+ *      Configure PTP mac address.
+ * Input:
+ *      mac - mac address to parser PTP packets.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_ptp_mac_set(rtk_mac_t mac)
+{
+    rtk_api_ret_t retVal;
+    ether_addr_t sw_mac;
+
+    memcpy(sw_mac.octet, mac.octet, ETHER_ADDR_LEN);
+
+    if((retVal=rtl8367c_setAsicEavMacAddress(sw_mac))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_ptp_mac_get
+ * Description:
+ *      Get PTP mac address.
+ * Input:
+ *      None
+ * Output:
+ *      pMac - mac address to parser PTP packets.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_ptp_mac_get(rtk_mac_t *pMac)
+{
+    rtk_api_ret_t retVal;
+    ether_addr_t sw_mac;
+
+    if((retVal=rtl8367c_getAsicEavMacAddress(&sw_mac))!=RT_ERR_OK)
+        return retVal;
+
+    memcpy(pMac->octet, sw_mac.octet, ETHER_ADDR_LEN);
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_ptp_tpid_set
+ * Description:
+ *      Configure PTP accepted outer & inner tag TPID.
+ * Input:
+ *      outerId - Ether type of S-tag frame parsing in PTP ports.
+ *      innerId - Ether type of C-tag frame parsing in PTP ports.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_ptp_tpid_set(rtk_ptp_tpid_t outerId, rtk_ptp_tpid_t innerId)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((outerId>RTK_MAX_NUM_OF_TPID) ||(innerId>RTK_MAX_NUM_OF_TPID))
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicEavTpid(outerId, innerId)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_ptp_tpid_get
+ * Description:
+ *      Get PTP accepted outer & inner tag TPID.
+ * Input:
+ *      None
+ * Output:
+ *      pOuterId - Ether type of S-tag frame parsing in PTP ports.
+ *      pInnerId - Ether type of C-tag frame parsing in PTP ports.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_ptp_tpid_get(rtk_ptp_tpid_t *pOuterId, rtk_ptp_tpid_t *pInnerId)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((retVal = rtl8367c_getAsicEavTpid(pOuterId, pInnerId)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_ptp_refTime_set
+ * Description:
+ *      Set the reference time of the specified device.
+ * Input:
+ *      timeStamp - reference timestamp value
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT    - invalid input parameter
+ * Applicable:
+ *      8390, 8380
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_ptp_refTime_set(rtk_ptp_timeStamp_t timeStamp)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (timeStamp.nsec > RTK_MAX_NUM_OF_NANO_SECOND)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicEavSysTime(timeStamp.sec, timeStamp.nsec))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_ptp_refTime_get
+ * Description:
+ *      Get the reference time of the specified device.
+ * Input:
+ * Output:
+ *      pTimeStamp - pointer buffer of the reference time
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_UNIT_ID      - invalid unit id
+ *      RT_ERR_NOT_INIT     - The module is not initial
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Applicable:
+ *      8390, 8380
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_ptp_refTime_get(rtk_ptp_timeStamp_t *pTimeStamp)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((retVal = rtl8367c_getAsicEavSysTime(&pTimeStamp->sec, &pTimeStamp->nsec))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_ptp_refTimeAdjust_set
+ * Description:
+ *      Adjust the reference time.
+ * Input:
+ *      unit      - unit id
+ *      sign      - significant
+ *      timeStamp - reference timestamp value
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_UNIT_ID  - invalid unit id
+ *      RT_ERR_NOT_INIT - The module is not initial
+ *      RT_ERR_INPUT    - invalid input parameter
+ * Note:
+ *      sign=0 for positive adjustment, sign=1 for negative adjustment.
+ */
+rtk_api_ret_t rtk_ptp_refTimeAdjust_set(rtk_ptp_sys_adjust_t sign, rtk_ptp_timeStamp_t timeStamp)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (timeStamp.nsec > RTK_MAX_NUM_OF_NANO_SECOND)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicEavSysTimeAdjust(sign, timeStamp.sec, timeStamp.nsec))!=RT_ERR_OK)
+        return retVal;
+
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_ptp_refTimeEnable_set
+ * Description:
+ *      Set the enable state of reference time of the specified device.
+ * Input:
+ *      enable - status
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT    - invalid input parameter
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_ptp_refTimeEnable_set(rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (enable >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if ((retVal = rtl8367c_setAsicEavSysTimeCtrl(enable))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_ptp_refTimeEnable_get
+ * Description:
+ *      Get the enable state of reference time of the specified device.
+ * Input:
+ * Output:
+ *      pEnable - status
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_UNIT_ID      - invalid unit id
+ *      RT_ERR_NOT_INIT     - The module is not initial
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Applicable:
+ *      8390, 8380
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_ptp_refTimeEnable_get(rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((retVal = rtl8367c_getAsicEavSysTimeCtrl(pEnable))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_ptp_portEnable_set
+ * Description:
+ *      Set PTP status of the specified port.
+ * Input:
+ *      port   - port id
+ *      enable - status
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT     - invalid port id
+ *      RT_ERR_INPUT    - invalid input parameter
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_ptp_portEnable_set(rtk_port_t port, rtk_enable_t enable)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port is PTP port */
+    RTK_CHK_PORT_IS_PTP(port);
+
+    if (enable>=RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicEavPortEnable(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_ptp_portEnable_get
+ * Description:
+ *      Get PTP status of the specified port.
+ * Input:
+ *      port    - port id
+ * Output:
+ *      pEnable - status
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT         - invalid port id
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_ptp_portEnable_get(rtk_port_t port, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port is PTP port */
+    RTK_CHK_PORT_IS_PTP(port);
+
+    if ((retVal = rtl8367c_getAsicEavPortEnable(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_ptp_portTimestamp_get
+ * Description:
+ *      Get PTP timstamp according to the PTP identifier on the dedicated port from the specified device.
+ * Input:
+ *      unit       - unit id
+ *      port       - port id
+ *      type       - PTP message type
+ * Output:
+ *      pInfo      - pointer buffer of sequence ID and timestamp
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID      - invalid port id
+ *      RT_ERR_INPUT        - invalid input parameter
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Applicable:
+ *      8390, 8380
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_ptp_portTimestamp_get( rtk_port_t port, rtk_ptp_msgType_t type, rtk_ptp_info_t *pInfo)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_ptp_time_stamp_t time;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port is PTP port */
+    RTK_CHK_PORT_IS_PTP(port);
+
+    if ((retVal = rtl8367c_getAsicEavPortTimeStamp(rtk_switch_port_L2P_get(port), type, &time)) != RT_ERR_OK)
+        return retVal;
+
+    pInfo->sequenceId = time.sequence_id;
+    pInfo->timeStamp.sec = time.second;
+    pInfo->timeStamp.nsec = time.nano_second;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_ptp_intControl_set
+ * Description:
+ *      Set PTP interrupt trigger status configuration.
+ * Input:
+ *      type - Interrupt type.
+ *      enable - Interrupt status.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_ENABLE       - Invalid enable input.
+ * Note:
+ *      The API can set PTP interrupt status configuration.
+ *      The interrupt trigger status is shown in the following:
+ *          PTP_INT_TYPE_TX_SYNC = 0,
+ *          PTP_INT_TYPE_TX_DELAY_REQ,
+ *          PTP_INT_TYPE_TX_PDELAY_REQ,
+ *          PTP_INT_TYPE_TX_PDELAY_RESP,
+ *          PTP_INT_TYPE_RX_SYNC,
+ *          PTP_INT_TYPE_RX_DELAY_REQ,
+ *          PTP_INT_TYPE_RX_PDELAY_REQ,
+ *          PTP_INT_TYPE_RX_PDELAY_RESP,
+ *          PTP_INT_TYPE_ALL,
+ */
+rtk_api_ret_t rtk_ptp_intControl_set(rtk_ptp_intType_t type, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 mask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (type>=PTP_INT_TYPE_END)
+        return RT_ERR_INPUT;
+
+    if (PTP_INT_TYPE_ALL!=type)
+    {
+        if ((retVal = rtl8367c_getAsicEavInterruptMask(&mask)) != RT_ERR_OK)
+            return retVal;
+
+        if (ENABLED == enable)
+            mask = mask | (1<<type);
+        else if (DISABLED == enable)
+            mask = mask & ~(1<<type);
+        else
+            return RT_ERR_INPUT;
+
+        if ((retVal = rtl8367c_setAsicEavInterruptMask(mask)) != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        if (ENABLED == enable)
+            mask = RTK_PTP_INTR_MASK;
+        else if (DISABLED == enable)
+            mask = 0;
+        else
+            return RT_ERR_INPUT;
+
+        if ((retVal = rtl8367c_setAsicEavInterruptMask(mask)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_ptp_intControl_get
+ * Description:
+ *      Get PTP interrupt trigger status configuration.
+ * Input:
+ *      type - Interrupt type.
+ * Output:
+ *      pEnable - Interrupt status.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get interrupt status configuration.
+ *      The interrupt trigger status is shown in the following:
+ *          PTP_INT_TYPE_TX_SYNC = 0,
+ *          PTP_INT_TYPE_TX_DELAY_REQ,
+ *          PTP_INT_TYPE_TX_PDELAY_REQ,
+ *          PTP_INT_TYPE_TX_PDELAY_RESP,
+ *          PTP_INT_TYPE_RX_SYNC,
+ *          PTP_INT_TYPE_RX_DELAY_REQ,
+ *          PTP_INT_TYPE_RX_PDELAY_REQ,
+ *          PTP_INT_TYPE_RX_PDELAY_RESP,
+ */
+rtk_api_ret_t rtk_ptp_intControl_get(rtk_ptp_intType_t type, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 mask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (type>=PTP_INT_TYPE_ALL)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_getAsicEavInterruptMask(&mask)) != RT_ERR_OK)
+        return retVal;
+
+    if (0 == (mask&(1<<type)))
+        *pEnable=DISABLED;
+    else
+        *pEnable=ENABLED;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_ptp_intStatus_get
+ * Description:
+ *      Get PTP port interrupt trigger status.
+ * Input:
+ *      port           - physical port
+ * Output:
+ *      pStatusMask - Interrupt status bit mask.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get interrupt trigger status when interrupt happened.
+ *      The interrupt trigger status is shown in the following:
+ *      - PORT 0  INT    (value[0] (Bit0))
+ *      - PORT 1  INT    (value[0] (Bit1))
+ *      - PORT 2  INT    (value[0] (Bit2))
+ *      - PORT 3  INT    (value[0] (Bit3))
+ *      - PORT 4  INT   (value[0] (Bit4))
+
+ *
+ */
+rtk_api_ret_t rtk_ptp_intStatus_get(rtk_ptp_intStatus_t *pStatusMask)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pStatusMask)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicEavInterruptStatus(pStatusMask)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+
+
+/* Function Name:
+ *      rtk_ptp_portIntStatus_set
+ * Description:
+ *      Set PTP port interrupt trigger status to clean.
+ * Input:
+ *      port           - physical port
+ *      statusMask - Interrupt status bit mask.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT - Invalid input parameters.
+ * Note:
+ *      The API can clean interrupt trigger status when interrupt happened.
+ *      The interrupt trigger status is shown in the following:
+ *      - PTP_INT_TYPE_TX_SYNC              (value[0] (Bit0))
+ *      - PTP_INT_TYPE_TX_DELAY_REQ      (value[0] (Bit1))
+ *      - PTP_INT_TYPE_TX_PDELAY_REQ    (value[0] (Bit2))
+ *      - PTP_INT_TYPE_TX_PDELAY_RESP   (value[0] (Bit3))
+ *      - PTP_INT_TYPE_RX_SYNC              (value[0] (Bit4))
+ *      - PTP_INT_TYPE_RX_DELAY_REQ      (value[0] (Bit5))
+ *      - PTP_INT_TYPE_RX_PDELAY_REQ    (value[0] (Bit6))
+ *      - PTP_INT_TYPE_RX_PDELAY_RESP   (value[0] (Bit7))
+ *      The status will be cleared after execute this API.
+ */
+rtk_api_ret_t rtk_ptp_portIntStatus_set(rtk_port_t port, rtk_ptp_intStatus_t statusMask)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port is PTP port */
+    RTK_CHK_PORT_IS_PTP(port);
+
+    if ((retVal = rtl8367c_setAsicEavPortInterruptStatus(rtk_switch_port_L2P_get(port), statusMask))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_ptp_portIntStatus_get
+ * Description:
+ *      Get PTP port interrupt trigger status.
+ * Input:
+ *      port           - physical port
+ * Output:
+ *      pStatusMask - Interrupt status bit mask.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get interrupt trigger status when interrupt happened.
+ *      The interrupt trigger status is shown in the following:
+ *      - PTP_INT_TYPE_TX_SYNC              (value[0] (Bit0))
+ *      - PTP_INT_TYPE_TX_DELAY_REQ      (value[0] (Bit1))
+ *      - PTP_INT_TYPE_TX_PDELAY_REQ    (value[0] (Bit2))
+ *      - PTP_INT_TYPE_TX_PDELAY_RESP   (value[0] (Bit3))
+ *      - PTP_INT_TYPE_RX_SYNC              (value[0] (Bit4))
+ *      - PTP_INT_TYPE_RX_DELAY_REQ      (value[0] (Bit5))
+ *      - PTP_INT_TYPE_RX_PDELAY_REQ    (value[0] (Bit6))
+ *      - PTP_INT_TYPE_RX_PDELAY_RESP   (value[0] (Bit7))
+ *
+ */
+rtk_api_ret_t rtk_ptp_portIntStatus_get(rtk_port_t port, rtk_ptp_intStatus_t *pStatusMask)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port is PTP port */
+    RTK_CHK_PORT_IS_PTP(port);
+
+    if(NULL == pStatusMask)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicEavPortInterruptStatus(rtk_switch_port_L2P_get(port), pStatusMask)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_ptp_portPtpTrap_set
+ * Description:
+ *      Set PTP packet trap of the specified port.
+ * Input:
+ *      port   - port id
+ *      enable - status
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT     - invalid port id
+ *      RT_ERR_INPUT    - invalid input parameter
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_ptp_portTrap_set(rtk_port_t port, rtk_enable_t enable)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (enable>=RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicEavTrap(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_ptp_portPtpEnable_get
+ * Description:
+ *      Get PTP packet trap of the specified port.
+ * Input:
+ *      port    - port id
+ * Output:
+ *      pEnable - status
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT         - invalid port id
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_ptp_portTrap_get(rtk_port_t port, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if ((retVal = rtl8367c_getAsicEavTrap(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/qos.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/qos.c
new file mode 100644
index 0000000..70067a3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/qos.c
@@ -0,0 +1,1452 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in QoS module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <qos.h>
+#include <string.h>
+
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_qos.h>
+#include <rtl8367c_asicdrv_fc.h>
+#include <rtl8367c_asicdrv_scheduling.h>
+
+/* Function Name:
+ *      rtk_qos_init
+ * Description:
+ *      Configure Qos default settings with queue number assigment to each port.
+ * Input:
+ *      queueNum - Queue number of each port.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_QUEUE_NUM    - Invalid queue number.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API will initialize related Qos setting with queue number assigment.
+ *      The queue number is from 1 to 8.
+ */
+rtk_api_ret_t rtk_qos_init(rtk_queue_num_t queueNum)
+{
+    CONST_T rtk_uint16 g_prioritytToQid[8][8]= {
+            {0, 0,0,0,0,0,0,0},
+            {0, 0,0,0,7,7,7,7},
+            {0, 0,0,0,1,1,7,7},
+            {0, 0,1,1,2,2,7,7},
+            {0, 0,1,1,2,3,7,7},
+            {0, 0,1,2,3,4,7,7},
+            {0, 0,1,2,3,4,5,7},
+            {0,1,2,3,4,5,6,7}
+    };
+
+    CONST_T rtk_uint32 g_priorityDecision[8] = {0x01, 0x80,0x04,0x02,0x20,0x40,0x10,0x08};
+    CONST_T rtk_uint32 g_prioritytRemap[8] = {0,1,2,3,4,5,6,7};
+
+    rtk_api_ret_t retVal;
+    rtk_uint32 qmapidx;
+    rtk_uint32 priority;
+    rtk_uint32 priDec;
+    rtk_uint32 port;
+    rtk_uint32 dscp;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (queueNum <= 0 || queueNum > RTK_MAX_NUM_OF_QUEUE)
+        return RT_ERR_QUEUE_NUM;
+
+    /*Set Output Queue Number*/
+    if (RTK_MAX_NUM_OF_QUEUE == queueNum)
+        qmapidx = 0;
+    else
+        qmapidx = queueNum;
+
+    RTK_SCAN_ALL_PHY_PORTMASK(port)
+    {
+        if ((retVal = rtl8367c_setAsicOutputQueueMappingIndex(port, qmapidx)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    /*Set Priority to Qid*/
+    for (priority = 0; priority <= RTK_PRIMAX; priority++)
+    {
+        if ((retVal = rtl8367c_setAsicPriorityToQIDMappingTable(queueNum - 1, priority, g_prioritytToQid[queueNum - 1][priority])) != RT_ERR_OK)
+            return retVal;
+    }
+
+    /*Set Flow Control Type to Ingress Flow Control*/
+    if ((retVal = rtl8367c_setAsicFlowControlSelect(FC_INGRESS)) != RT_ERR_OK)
+        return retVal;
+
+
+    /*Priority Decision Order*/
+    for (priDec = 0;priDec < PRIDEC_END;priDec++)
+    {
+        if ((retVal = rtl8367c_setAsicPriorityDecision(PRIDECTBL_IDX0, priDec, g_priorityDecision[priDec])) != RT_ERR_OK)
+            return retVal;
+        if ((retVal = rtl8367c_setAsicPriorityDecision(PRIDECTBL_IDX1, priDec, g_priorityDecision[priDec])) != RT_ERR_OK)
+            return retVal;
+    }
+
+    /*Set Port-based Priority to 0*/
+    RTK_SCAN_ALL_PHY_PORTMASK(port)
+    {
+        if ((retVal = rtl8367c_setAsicPriorityPortBased(port, 0)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    /*Disable 1p Remarking*/
+    RTK_SCAN_ALL_PHY_PORTMASK(port)
+    {
+        if ((retVal = rtl8367c_setAsicRemarkingDot1pAbility(port, DISABLED)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    /*Disable DSCP Remarking*/
+    if ((retVal = rtl8367c_setAsicRemarkingDscpAbility(DISABLED)) != RT_ERR_OK)
+        return retVal;
+
+    /*Set 1p & DSCP  Priority Remapping & Remarking*/
+    for (priority = 0; priority <= RTL8367C_PRIMAX; priority++)
+    {
+        if ((retVal = rtl8367c_setAsicPriorityDot1qRemapping(priority, g_prioritytRemap[priority])) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicRemarkingDot1pParameter(priority, 0)) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_setAsicRemarkingDscpParameter(priority, 0)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    /*Set DSCP Priority*/
+    for (dscp = 0; dscp <= 63; dscp++)
+    {
+        if ((retVal = rtl8367c_setAsicPriorityDscpBased(dscp, 0)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    /* Finetune B/T value */
+    if((retVal = rtl8367c_setAsicReg(0x1722, 0x1158)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_priSel_set
+ * Description:
+ *      Configure the priority order among different priority mechanism.
+ * Input:
+ *      index - Priority decision table index (0~1)
+ *      pPriDec - Priority assign for port, dscp, 802.1p, cvlan, svlan, acl based priority decision.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_QOS_SEL_PRI_SOURCE   - Invalid priority decision source parameter.
+ * Note:
+ *      ASIC will follow user priority setting of mechanisms to select mapped queue priority for receiving frame.
+ *      If two priority mechanisms are the same, the ASIC will chose the highest priority from mechanisms to
+ *      assign queue priority to receiving frame.
+ *      The priority sources are:
+ *      - PRIDEC_PORT
+ *      - PRIDEC_ACL
+ *      - PRIDEC_DSCP
+ *      - PRIDEC_1Q
+ *      - PRIDEC_1AD
+ *      - PRIDEC_CVLAN
+ *      - PRIDEC_DA
+ *      - PRIDEC_SA
+ */
+rtk_api_ret_t rtk_qos_priSel_set(rtk_qos_priDecTbl_t index, rtk_priority_select_t *pPriDec)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 port_pow;
+    rtk_uint32 dot1q_pow;
+    rtk_uint32 dscp_pow;
+    rtk_uint32 acl_pow;
+    rtk_uint32 svlan_pow;
+    rtk_uint32 cvlan_pow;
+    rtk_uint32 smac_pow;
+    rtk_uint32 dmac_pow;
+    rtk_uint32 i;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (index < 0 || index >= PRIDECTBL_END)
+        return RT_ERR_ENTRY_INDEX;
+
+    if (pPriDec->port_pri >= 8 || pPriDec->dot1q_pri >= 8 || pPriDec->acl_pri >= 8 || pPriDec->dscp_pri >= 8 ||
+       pPriDec->cvlan_pri >= 8 || pPriDec->svlan_pri >= 8 || pPriDec->dmac_pri >= 8 || pPriDec->smac_pri >= 8)
+        return RT_ERR_QOS_SEL_PRI_SOURCE;
+
+    port_pow = 1;
+    for (i = pPriDec->port_pri; i > 0; i--)
+        port_pow = (port_pow)*2;
+
+    dot1q_pow = 1;
+    for (i = pPriDec->dot1q_pri; i > 0; i--)
+        dot1q_pow = (dot1q_pow)*2;
+
+    acl_pow = 1;
+    for (i = pPriDec->acl_pri; i > 0; i--)
+        acl_pow = (acl_pow)*2;
+
+    dscp_pow = 1;
+    for (i = pPriDec->dscp_pri; i > 0; i--)
+        dscp_pow = (dscp_pow)*2;
+
+    svlan_pow = 1;
+    for (i = pPriDec->svlan_pri; i > 0; i--)
+        svlan_pow = (svlan_pow)*2;
+
+    cvlan_pow = 1;
+    for (i = pPriDec->cvlan_pri; i > 0; i--)
+        cvlan_pow = (cvlan_pow)*2;
+
+    dmac_pow = 1;
+    for (i = pPriDec->dmac_pri; i > 0; i--)
+        dmac_pow = (dmac_pow)*2;
+
+    smac_pow = 1;
+    for (i = pPriDec->smac_pri; i > 0; i--)
+        smac_pow = (smac_pow)*2;
+
+    if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_PORT, port_pow)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_ACL, acl_pow)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_DSCP, dscp_pow)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_1Q, dot1q_pow)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_1AD, svlan_pow)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_CVLAN, cvlan_pow)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_DA, dmac_pow)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_SA, smac_pow)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_priSel_get
+ * Description:
+ *      Get the priority order configuration among different priority mechanism.
+ * Input:
+ *      index - Priority decision table index (0~1)
+ * Output:
+ *      pPriDec - Priority assign for port, dscp, 802.1p, cvlan, svlan, acl based priority decision .
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      ASIC will follow user priority setting of mechanisms to select mapped queue priority for receiving frame.
+ *      If two priority mechanisms are the same, the ASIC will chose the highest priority from mechanisms to
+ *      assign queue priority to receiving frame.
+ *      The priority sources are:
+ *      - PRIDEC_PORT,
+ *      - PRIDEC_ACL,
+ *      - PRIDEC_DSCP,
+ *      - PRIDEC_1Q,
+ *      - PRIDEC_1AD,
+ *      - PRIDEC_CVLAN,
+ *      - PRIDEC_DA,
+ *      - PRIDEC_SA,
+ */
+rtk_api_ret_t rtk_qos_priSel_get(rtk_qos_priDecTbl_t index, rtk_priority_select_t *pPriDec)
+{
+
+    rtk_api_ret_t retVal;
+    rtk_int32 i;
+    rtk_uint32 port_pow;
+    rtk_uint32 dot1q_pow;
+    rtk_uint32 dscp_pow;
+    rtk_uint32 acl_pow;
+    rtk_uint32 svlan_pow;
+    rtk_uint32 cvlan_pow;
+    rtk_uint32 smac_pow;
+    rtk_uint32 dmac_pow;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (index < 0 || index >= PRIDECTBL_END)
+        return RT_ERR_ENTRY_INDEX;
+
+    if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_PORT, &port_pow)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_ACL, &acl_pow)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_DSCP, &dscp_pow)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_1Q, &dot1q_pow)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_1AD, &svlan_pow)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_CVLAN, &cvlan_pow)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_DA, &dmac_pow)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_SA, &smac_pow)) != RT_ERR_OK)
+        return retVal;
+
+    for (i = 31; i >= 0; i--)
+    {
+        if (port_pow & (1 << i))
+        {
+            pPriDec->port_pri = i;
+            break;
+        }
+    }
+
+    for (i = 31; i >= 0; i--)
+    {
+        if (dot1q_pow & (1 << i))
+        {
+            pPriDec->dot1q_pri = i;
+            break;
+        }
+    }
+
+    for (i = 31; i >= 0; i--)
+    {
+        if (acl_pow & (1 << i))
+        {
+            pPriDec->acl_pri = i;
+            break;
+        }
+    }
+
+    for (i = 31; i >= 0; i--)
+    {
+        if (dscp_pow & (1 << i))
+        {
+            pPriDec->dscp_pri = i;
+            break;
+        }
+    }
+
+    for (i = 31; i >= 0; i--)
+    {
+        if (svlan_pow & (1 << i))
+        {
+            pPriDec->svlan_pri = i;
+            break;
+        }
+    }
+
+    for (i = 31;i  >= 0; i--)
+    {
+        if (cvlan_pow & (1 << i))
+        {
+            pPriDec->cvlan_pri = i;
+            break;
+        }
+    }
+
+    for (i = 31; i >= 0; i--)
+    {
+        if (dmac_pow&(1<<i))
+        {
+            pPriDec->dmac_pri = i;
+            break;
+        }
+    }
+
+    for (i = 31; i >= 0; i--)
+    {
+        if (smac_pow & (1 << i))
+        {
+            pPriDec->smac_pri = i;
+            break;
+        }
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_1pPriRemap_set
+ * Description:
+ *      Configure 1Q priorities mapping to internal absolute priority.
+ * Input:
+ *      dot1p_pri   - 802.1p priority value.
+ *      int_pri     - internal priority value.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_VLAN_PRIORITY    - Invalid 1p priority.
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ * Note:
+ *      Priority of 802.1Q assignment for internal asic priority, and it is used for queue usage and packet scheduling.
+ */
+rtk_api_ret_t rtk_qos_1pPriRemap_set(rtk_pri_t dot1p_pri, rtk_pri_t int_pri)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (dot1p_pri > RTL8367C_PRIMAX || int_pri > RTL8367C_PRIMAX)
+        return  RT_ERR_VLAN_PRIORITY;
+
+    if ((retVal = rtl8367c_setAsicPriorityDot1qRemapping(dot1p_pri, int_pri)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_1pPriRemap_get
+ * Description:
+ *      Get 1Q priorities mapping to internal absolute priority.
+ * Input:
+ *      dot1p_pri - 802.1p priority value .
+ * Output:
+ *      pInt_pri - internal priority value.
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_VLAN_PRIORITY    - Invalid priority.
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ * Note:
+ *      Priority of 802.1Q assigment for internal asic priority, and it is uesed for queue usage and packet scheduling.
+ */
+rtk_api_ret_t rtk_qos_1pPriRemap_get(rtk_pri_t dot1p_pri, rtk_pri_t *pInt_pri)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (dot1p_pri > RTL8367C_PRIMAX)
+        return  RT_ERR_QOS_INT_PRIORITY;
+
+    if ((retVal = rtl8367c_getAsicPriorityDot1qRemapping(dot1p_pri, pInt_pri)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_dscpPriRemap_set
+ * Description:
+ *      Map dscp value to internal priority.
+ * Input:
+ *      dscp    - Dscp value of receiving frame
+ *      int_pri - internal priority value .
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_QOS_DSCP_VALUE   - Invalid DSCP value.
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ * Note:
+ *      The Differentiated Service Code Point is a selector for router's per-hop behaviors. As a selector, there is no implication that a numerically
+ *      greater DSCP implies a better network service. As can be seen, the DSCP totally overlaps the old precedence field of TOS. So if values of
+ *      DSCP are carefully chosen then backward compatibility can be achieved.
+ */
+rtk_api_ret_t rtk_qos_dscpPriRemap_set(rtk_dscp_t dscp, rtk_pri_t int_pri)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (int_pri > RTL8367C_PRIMAX )
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    if (dscp > RTL8367C_DSCPMAX)
+        return RT_ERR_QOS_DSCP_VALUE;
+
+    if ((retVal = rtl8367c_setAsicPriorityDscpBased(dscp, int_pri)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_dscpPriRemap_get
+ * Description:
+ *      Get dscp value to internal priority.
+ * Input:
+ *      dscp - Dscp value of receiving frame
+ * Output:
+ *      pInt_pri - internal priority value.
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QOS_DSCP_VALUE   - Invalid DSCP value.
+ * Note:
+ *      The Differentiated Service Code Point is a selector for router's per-hop behaviors. As a selector, there is no implication that a numerically
+ *      greater DSCP implies a better network service. As can be seen, the DSCP totally overlaps the old precedence field of TOS. So if values of
+ *      DSCP are carefully chosen then backward compatibility can be achieved.
+ */
+rtk_api_ret_t rtk_qos_dscpPriRemap_get(rtk_dscp_t dscp, rtk_pri_t *pInt_pri)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (dscp > RTL8367C_DSCPMAX)
+        return RT_ERR_QOS_DSCP_VALUE;
+
+    if ((retVal = rtl8367c_getAsicPriorityDscpBased(dscp, pInt_pri)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_portPri_set
+ * Description:
+ *      Configure priority usage to each port.
+ * Input:
+ *      port - Port id.
+ *      int_pri - internal priority value.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_QOS_SEL_PORT_PRI - Invalid port priority.
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ * Note:
+ *      The API can set priority of port assignments for queue usage and packet scheduling.
+ */
+rtk_api_ret_t rtk_qos_portPri_set(rtk_port_t port, rtk_pri_t int_pri)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (int_pri > RTL8367C_PRIMAX )
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    if ((retVal = rtl8367c_setAsicPriorityPortBased(rtk_switch_port_L2P_get(port), int_pri)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_portPri_get
+ * Description:
+ *      Get priority usage to each port.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pInt_pri - internal priority value.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get priority of port assignments for queue usage and packet scheduling.
+ */
+rtk_api_ret_t rtk_qos_portPri_get(rtk_port_t port, rtk_pri_t *pInt_pri)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if ((retVal = rtl8367c_getAsicPriorityPortBased(rtk_switch_port_L2P_get(port), pInt_pri)) != RT_ERR_OK)
+        return retVal;
+
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_queueNum_set
+ * Description:
+ *      Set output queue number for each port.
+ * Input:
+ *      port    - Port id.
+ *      index   - Mapping queue number (1~8)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_QUEUE_NUM    - Invalid queue number.
+ * Note:
+ *      The API can set the output queue number of the specified port. The queue number is from 1 to 8.
+ */
+rtk_api_ret_t rtk_qos_queueNum_set(rtk_port_t port, rtk_queue_num_t queue_num)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if ((0 == queue_num) || (queue_num > RTK_MAX_NUM_OF_QUEUE))
+        return RT_ERR_FAILED;
+
+    if (RTK_MAX_NUM_OF_QUEUE == queue_num)
+        queue_num = 0;
+
+    if ((retVal = rtl8367c_setAsicOutputQueueMappingIndex(rtk_switch_port_L2P_get(port), queue_num)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_queueNum_get
+ * Description:
+ *      Get output queue number.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pQueue_num - Mapping queue number
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API will return the output queue number of the specified port. The queue number is from 1 to 8.
+ */
+rtk_api_ret_t rtk_qos_queueNum_get(rtk_port_t port, rtk_queue_num_t *pQueue_num)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 qidx;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if ((retVal = rtl8367c_getAsicOutputQueueMappingIndex(rtk_switch_port_L2P_get(port), &qidx)) != RT_ERR_OK)
+        return retVal;
+
+    if (0 == qidx)
+        *pQueue_num = 8;
+    else
+        *pQueue_num = qidx;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_priMap_set
+ * Description:
+ *      Set output queue number for each port.
+ * Input:
+ *      queue_num   - Queue number usage.
+ *      pPri2qid    - Priority mapping to queue ID.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_QUEUE_NUM        - Invalid queue number.
+ *      RT_ERR_QUEUE_ID         - Invalid queue id.
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ * Note:
+ *      ASIC supports priority mapping to queue with different queue number from 1 to 8.
+ *      For different queue numbers usage, ASIC supports different internal available queue IDs.
+ */
+rtk_api_ret_t rtk_qos_priMap_set(rtk_queue_num_t queue_num, rtk_qos_pri2queue_t *pPri2qid)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pri;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((0 == queue_num) || (queue_num > RTK_MAX_NUM_OF_QUEUE))
+        return RT_ERR_QUEUE_NUM;
+
+    for (pri = 0; pri <= RTK_PRIMAX; pri++)
+    {
+        if (pPri2qid->pri2queue[pri] > RTK_QIDMAX)
+            return RT_ERR_QUEUE_ID;
+
+        if ((retVal = rtl8367c_setAsicPriorityToQIDMappingTable(queue_num - 1, pri, pPri2qid->pri2queue[pri])) != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_priMap_get
+ * Description:
+ *      Get priority to queue ID mapping table parameters.
+ * Input:
+ *      queue_num - Queue number usage.
+ * Output:
+ *      pPri2qid - Priority mapping to queue ID.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_QUEUE_NUM    - Invalid queue number.
+ * Note:
+ *      The API can return the mapping queue id of the specified priority and queue number.
+ *      The queue number is from 1 to 8.
+ */
+rtk_api_ret_t rtk_qos_priMap_get(rtk_queue_num_t queue_num, rtk_qos_pri2queue_t *pPri2qid)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pri;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((0 == queue_num) || (queue_num > RTK_MAX_NUM_OF_QUEUE))
+        return RT_ERR_QUEUE_NUM;
+
+    for (pri = 0; pri <= RTK_PRIMAX; pri++)
+    {
+        if ((retVal = rtl8367c_getAsicPriorityToQIDMappingTable(queue_num-1, pri, &pPri2qid->pri2queue[pri])) != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_schedulingQueue_set
+ * Description:
+ *      Set weight and type of queues in dedicated port.
+ * Input:
+ *      port        - Port id.
+ *      pQweights   - The array of weights for WRR/WFQ queue (0 for STRICT_PRIORITY queue).
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_QOS_QUEUE_WEIGHT - Invalid queue weight.
+ * Note:
+ *      The API can set weight and type, strict priority or weight fair queue (WFQ) for
+ *      dedicated port for using queues. If queue id is not included in queue usage,
+ *      then its type and weight setting in dummy for setting. There are priorities
+ *      as queue id in strict queues. It means strict queue id 5 carrying higher priority
+ *      than strict queue id 4. The WFQ queue weight is from 1 to 127, and weight 0 is
+ *      for strict priority queue type.
+ */
+rtk_api_ret_t rtk_qos_schedulingQueue_set(rtk_port_t port, rtk_qos_queue_weights_t *pQweights)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 qid;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    for (qid = 0; qid < RTL8367C_QUEUENO; qid ++)
+    {
+
+        if (pQweights->weights[qid] > QOS_WEIGHT_MAX)
+            return RT_ERR_QOS_QUEUE_WEIGHT;
+
+        if (0 == pQweights->weights[qid])
+        {
+            if ((retVal = rtl8367c_setAsicQueueType(rtk_switch_port_L2P_get(port), qid, QTYPE_STRICT)) != RT_ERR_OK)
+                return retVal;
+        }
+        else
+        {
+            if ((retVal = rtl8367c_setAsicQueueType(rtk_switch_port_L2P_get(port), qid, QTYPE_WFQ)) != RT_ERR_OK)
+                return retVal;
+
+            if ((retVal = rtl8367c_setAsicWFQWeight(rtk_switch_port_L2P_get(port),qid, pQweights->weights[qid])) != RT_ERR_OK)
+                return retVal;
+        }
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_schedulingQueue_get
+ * Description:
+ *      Get weight and type of queues in dedicated port.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pQweights - The array of weights for WRR/WFQ queue (0 for STRICT_PRIORITY queue).
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get weight and type, strict priority or weight fair queue (WFQ) for dedicated port for using queues.
+ *      The WFQ queue weight is from 1 to 127, and weight 0 is for strict priority queue type.
+ */
+rtk_api_ret_t rtk_qos_schedulingQueue_get(rtk_port_t port, rtk_qos_queue_weights_t *pQweights)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 qid,qtype,qweight;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    for (qid = 0; qid < RTL8367C_QUEUENO; qid++)
+    {
+        if ((retVal = rtl8367c_getAsicQueueType(rtk_switch_port_L2P_get(port), qid, &qtype)) != RT_ERR_OK)
+            return retVal;
+
+        if (QTYPE_STRICT == qtype)
+        {
+            pQweights->weights[qid] = 0;
+        }
+        else if (QTYPE_WFQ == qtype)
+        {
+            if ((retVal = rtl8367c_getAsicWFQWeight(rtk_switch_port_L2P_get(port), qid, &qweight)) != RT_ERR_OK)
+                return retVal;
+            pQweights->weights[qid] = qweight;
+        }
+    }
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_1pRemarkEnable_set
+ * Description:
+ *      Set 1p Remarking state
+ * Input:
+ *      port        - Port id.
+ *      enable      - State of per-port 1p Remarking
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_ENABLE       - Invalid enable parameter.
+ * Note:
+ *      The API can enable or disable 802.1p remarking ability for whole system.
+ *      The status of 802.1p remark:
+ *      - DISABLED
+ *      - ENABLED
+ */
+rtk_api_ret_t rtk_qos_1pRemarkEnable_set(rtk_port_t port, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (enable >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicRemarkingDot1pAbility(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_1pRemarkEnable_get
+ * Description:
+ *      Get 802.1p remarking ability.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEnable - Status of 802.1p remark.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get 802.1p remarking ability.
+ *      The status of 802.1p remark:
+ *      - DISABLED
+ *      - ENABLED
+ */
+rtk_api_ret_t rtk_qos_1pRemarkEnable_get(rtk_port_t port, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if ((retVal = rtl8367c_getAsicRemarkingDot1pAbility(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_1pRemark_set
+ * Description:
+ *      Set 802.1p remarking parameter.
+ * Input:
+ *      int_pri     - Internal priority value.
+ *      dot1p_pri   - 802.1p priority value.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_VLAN_PRIORITY    - Invalid 1p priority.
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ * Note:
+ *      The API can set 802.1p parameters source priority and new priority.
+ */
+rtk_api_ret_t rtk_qos_1pRemark_set(rtk_pri_t int_pri, rtk_pri_t dot1p_pri)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (int_pri > RTL8367C_PRIMAX )
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    if (dot1p_pri > RTL8367C_PRIMAX)
+        return RT_ERR_VLAN_PRIORITY;
+
+    if ((retVal = rtl8367c_setAsicRemarkingDot1pParameter(int_pri, dot1p_pri)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_1pRemark_get
+ * Description:
+ *      Get 802.1p remarking parameter.
+ * Input:
+ *      int_pri - Internal priority value.
+ * Output:
+ *      pDot1p_pri - 802.1p priority value.
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ * Note:
+ *      The API can get 802.1p remarking parameters. It would return new priority of ingress priority.
+ */
+rtk_api_ret_t rtk_qos_1pRemark_get(rtk_pri_t int_pri, rtk_pri_t *pDot1p_pri)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (int_pri > RTL8367C_PRIMAX )
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    if ((retVal = rtl8367c_getAsicRemarkingDot1pParameter(int_pri, pDot1p_pri)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_1pRemarkSrcSel_set
+ * Description:
+ *      Set remarking source of 802.1p remarking.
+ * Input:
+ *      type      - remarking source
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT         - The module is not initial
+ *      RT_ERR_PORT_ID  - invalid port id
+ *      RT_ERR_INPUT            - invalid input parameter
+
+ * Note:
+ *      The API can configure 802.1p remark functionality to map original 802.1p value or internal
+ *      priority to TX DSCP value.
+ */
+rtk_api_ret_t rtk_qos_1pRemarkSrcSel_set(rtk_qos_1pRmkSrc_t type)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (type >= DOT1P_RMK_SRC_END )
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    if ((retVal = rtl8367c_setAsicRemarkingDot1pSrc(type)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_1pRemarkSrcSel_get
+ * Description:
+ *      Get remarking source of 802.1p remarking.
+ * Input:
+ *      none
+ * Output:
+ *      pType      - remarking source
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT         - The module is not initial
+ *      RT_ERR_PORT_ID          - invalid port id
+ *      RT_ERR_INPUT            - invalid input parameter
+ *      RT_ERR_NULL_POINTER     - input parameter may be null pointer
+
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_qos_1pRemarkSrcSel_get(rtk_qos_1pRmkSrc_t *pType)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((retVal = rtl8367c_getAsicRemarkingDot1pSrc(pType)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_qos_dscpRemarkEnable_set
+ * Description:
+ *      Set DSCP remarking ability.
+ * Input:
+ *      port    - Port id.
+ *      enable  - status of DSCP remark.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ *      RT_ERR_ENABLE           - Invalid enable parameter.
+ * Note:
+ *      The API can enable or disable DSCP remarking ability for whole system.
+ *      The status of DSCP remark:
+ *      - DISABLED
+ *      - ENABLED
+ */
+rtk_api_ret_t rtk_qos_dscpRemarkEnable_set(rtk_port_t port, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /*for whole system function, the port value should be 0xFF*/
+    if (port != RTK_WHOLE_SYSTEM)
+        return RT_ERR_PORT_ID;
+
+    if (enable >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicRemarkingDscpAbility(enable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_dscpRemarkEnable_get
+ * Description:
+ *      Get DSCP remarking ability.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEnable - status of DSCP remarking.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get DSCP remarking ability.
+ *      The status of DSCP remark:
+ *      - DISABLED
+ *      - ENABLED
+ */
+rtk_api_ret_t rtk_qos_dscpRemarkEnable_get(rtk_port_t port, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /*for whole system function, the port value should be 0xFF*/
+    if (port != RTK_WHOLE_SYSTEM)
+        return RT_ERR_PORT_ID;
+
+    if ((retVal = rtl8367c_getAsicRemarkingDscpAbility(pEnable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_dscpRemark_set
+ * Description:
+ *      Set DSCP remarking parameter.
+ * Input:
+ *      int_pri - Internal priority value.
+ *      dscp    - DSCP value.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ *      RT_ERR_QOS_DSCP_VALUE   - Invalid DSCP value.
+ * Note:
+ *      The API can set DSCP value and mapping priority.
+ */
+rtk_api_ret_t rtk_qos_dscpRemark_set(rtk_pri_t int_pri, rtk_dscp_t dscp)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (int_pri > RTK_PRIMAX )
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    if (dscp > RTK_DSCPMAX)
+        return RT_ERR_QOS_DSCP_VALUE;
+
+    if ((retVal = rtl8367c_setAsicRemarkingDscpParameter(int_pri, dscp)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_qos_dscpRemark_get
+ * Description:
+ *      Get DSCP remarking parameter.
+ * Input:
+ *      int_pri - Internal priority value.
+ * Output:
+ *      Dscp - DSCP value.
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority.
+ * Note:
+ *      The API can get DSCP parameters. It would return DSCP value for mapping priority.
+ */
+rtk_api_ret_t rtk_qos_dscpRemark_get(rtk_pri_t int_pri, rtk_dscp_t *pDscp)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (int_pri > RTK_PRIMAX )
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    if ((retVal = rtl8367c_getAsicRemarkingDscpParameter(int_pri, pDscp)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_dscpRemarkSrcSel_set
+ * Description:
+ *      Set remarking source of DSCP remarking.
+ * Input:
+ *      type      - remarking source
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT         - The module is not initial
+ *      RT_ERR_PORT_ID  - invalid port id
+ *      RT_ERR_INPUT            - invalid input parameter
+
+ * Note:
+ *      The API can configure DSCP remark functionality to map original DSCP value or internal
+ *      priority to TX DSCP value.
+ */
+rtk_api_ret_t rtk_qos_dscpRemarkSrcSel_set(rtk_qos_dscpRmkSrc_t type)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (type >= DSCP_RMK_SRC_END )
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    if ((retVal = rtl8367c_setAsicRemarkingDscpSrc(type)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_dcpRemarkSrcSel_get
+ * Description:
+ *      Get remarking source of DSCP remarking.
+ * Input:
+ *      none
+ * Output:
+ *      pType      - remarking source
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT         - The module is not initial
+ *      RT_ERR_PORT_ID          - invalid port id
+ *      RT_ERR_INPUT            - invalid input parameter
+ *      RT_ERR_NULL_POINTER     - input parameter may be null pointer
+
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_qos_dscpRemarkSrcSel_get(rtk_qos_dscpRmkSrc_t *pType)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((retVal = rtl8367c_getAsicRemarkingDscpSrc(pType)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_dscpRemark2Dscp_set
+ * Description:
+ *      Set DSCP to remarked DSCP mapping.
+ * Input:
+ *      dscp    - DSCP value
+ *      rmkDscp - remarked DSCP value
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_QOS_DSCP_VALUE   - Invalid dscp value
+ * Note:
+ *      dscp parameter can be DSCP value or internal priority according to configuration of API
+ *      dal_apollomp_qos_dscpRemarkSrcSel_set(), because DSCP remark functionality can map original DSCP
+ *      value or internal priority to TX DSCP value.
+ */
+rtk_api_ret_t rtk_qos_dscpRemark2Dscp_set(rtk_dscp_t dscp, rtk_dscp_t rmkDscp)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((dscp > RTK_DSCPMAX) || (rmkDscp > RTK_DSCPMAX))
+        return RT_ERR_QOS_DSCP_VALUE;
+
+    if ((retVal = rtl8367c_setAsicRemarkingDscp2Dscp(dscp, rmkDscp)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_dscpRemark2Dscp_get
+ * Description:
+ *      Get DSCP to remarked DSCP mapping.
+ * Input:
+ *      dscp    - DSCP value
+ * Output:
+ *      pDscp   - remarked DSCP value
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_QOS_DSCP_VALUE   - Invalid dscp value
+ *      RT_ERR_NULL_POINTER     - NULL pointer
+ * Note:
+ *      None.
+ */
+rtk_api_ret_t rtk_qos_dscpRemark2Dscp_get(rtk_dscp_t dscp, rtk_dscp_t *pDscp)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (dscp > RTK_DSCPMAX)
+        return RT_ERR_QOS_DSCP_VALUE;
+
+    if ((retVal = rtl8367c_getAsicRemarkingDscp2Dscp(dscp, pDscp)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_portPriSelIndex_set
+ * Description:
+ *      Configure priority decision index to each port.
+ * Input:
+ *      port - Port id.
+ *      index - priority decision index.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_ENTRY_INDEX - Invalid entry index.
+ * Note:
+ *      The API can set priority of port assignments for queue usage and packet scheduling.
+ */
+rtk_api_ret_t rtk_qos_portPriSelIndex_set(rtk_port_t port, rtk_qos_priDecTbl_t index)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (index >= PRIDECTBL_END )
+        return RT_ERR_ENTRY_INDEX;
+
+    if ((retVal = rtl8367c_setAsicPortPriorityDecisionIndex(rtk_switch_port_L2P_get(port), index)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_qos_portPriSelIndex_get
+ * Description:
+ *      Get priority decision index from each port.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pIndex - priority decision index.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get priority of port assignments for queue usage and packet scheduling.
+ */
+rtk_api_ret_t rtk_qos_portPriSelIndex_get(rtk_port_t port, rtk_qos_priDecTbl_t *pIndex)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if ((retVal = rtl8367c_getAsicPortPriorityDecisionIndex(rtk_switch_port_L2P_get(port), pIndex)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rate.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rate.c
new file mode 100644
index 0000000..a077e0c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rate.c
@@ -0,0 +1,607 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in rate module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <rate.h>
+#include <qos.h>
+#include <string.h>
+
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_meter.h>
+#include <rtl8367c_asicdrv_inbwctrl.h>
+#include <rtl8367c_asicdrv_scheduling.h>
+
+/* Function Name:
+ *      rtk_rate_shareMeter_set
+ * Description:
+ *      Set meter configuration
+ * Input:
+ *      index       - shared meter index
+ *      type        - shared meter type
+ *      rate        - rate of share meter
+ *      ifg_include - include IFG or not, ENABLE:include DISABLE:exclude
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter
+ *      RT_ERR_RATE             - Invalid rate
+ *      RT_ERR_INPUT            - Invalid input parameters
+ * Note:
+ *      The API can set shared meter rate and ifg include for each meter.
+ *      The rate unit is 1 kbps and the range is from 8k to 1048568k if type is METER_TYPE_KBPS and
+ *      the granularity of rate is 8 kbps.
+ *      The rate unit is packets per second and the range is 1 ~ 0x1FFF if type is METER_TYPE_PPS.
+ *      The ifg_include parameter is used
+ *      for rate calculation with/without inter-frame-gap and preamble.
+ */
+rtk_api_ret_t rtk_rate_shareMeter_set(rtk_meter_id_t index, rtk_meter_type_t type, rtk_rate_t rate, rtk_enable_t ifg_include)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (index > RTK_MAX_METER_ID)
+        return RT_ERR_FILTER_METER_ID;
+
+    if (type >= METER_TYPE_END)
+        return RT_ERR_INPUT;
+
+    if (ifg_include >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    switch (type)
+    {
+        case METER_TYPE_KBPS:
+            if (rate > RTL8367C_QOS_RATE_INPUT_MAX_HSG || rate < RTL8367C_QOS_RATE_INPUT_MIN)
+                return RT_ERR_RATE ;
+
+            if ((retVal = rtl8367c_setAsicShareMeter(index, rate >> 3, ifg_include)) != RT_ERR_OK)
+                return retVal;
+
+            break;
+        case METER_TYPE_PPS:
+            if (rate > RTL8367C_QOS_PPS_INPUT_MAX || rate < RTL8367C_QOS_PPS_INPUT_MIN)
+                return RT_ERR_RATE ;
+
+            if ((retVal = rtl8367c_setAsicShareMeter(index, rate, ifg_include)) != RT_ERR_OK)
+                return retVal;
+
+            break;
+        default:
+            return RT_ERR_INPUT;
+    }
+
+    /* Set Type */
+    if ((retVal = rtl8367c_setAsicShareMeterType(index, (rtk_uint32)type)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_rate_shareMeter_get
+ * Description:
+ *      Get meter configuration
+ * Input:
+ *      index        - shared meter index
+ * Output:
+ *      pType        - Meter Type
+ *      pRate        - pointer of rate of share meter
+ *      pIfg_include - include IFG or not, ENABLE:include DISABLE:exclude
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_rate_shareMeter_get(rtk_meter_id_t index, rtk_meter_type_t *pType, rtk_rate_t *pRate, rtk_enable_t *pIfg_include)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 regData;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (index > RTK_MAX_METER_ID)
+        return RT_ERR_FILTER_METER_ID;
+
+    if(NULL == pType)
+        return RT_ERR_NULL_POINTER;
+
+    if(NULL == pRate)
+        return RT_ERR_NULL_POINTER;
+
+    if(NULL == pIfg_include)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicShareMeter(index, &regData, pIfg_include)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicShareMeterType(index, (rtk_uint32 *)pType)) != RT_ERR_OK)
+        return retVal;
+
+    if(*pType == METER_TYPE_KBPS)
+        *pRate = regData<<3;
+    else
+        *pRate = regData;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_rate_shareMeterBucket_set
+ * Description:
+ *      Set meter Bucket Size
+ * Input:
+ *      index        - shared meter index
+ *      bucket_size  - Bucket Size
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_INPUT            - Error Input
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter
+ * Note:
+ *      The API can set shared meter bucket size.
+ */
+rtk_api_ret_t rtk_rate_shareMeterBucket_set(rtk_meter_id_t index, rtk_uint32 bucket_size)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (index > RTK_MAX_METER_ID)
+        return RT_ERR_FILTER_METER_ID;
+
+    if(bucket_size > RTL8367C_METERBUCKETSIZEMAX)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicShareMeterBucketSize(index, bucket_size)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_rate_shareMeterBucket_get
+ * Description:
+ *      Get meter Bucket Size
+ * Input:
+ *      index        - shared meter index
+ * Output:
+ *      pBucket_size - Bucket Size
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter
+ * Note:
+ *      The API can get shared meter bucket size.
+ */
+rtk_api_ret_t rtk_rate_shareMeterBucket_get(rtk_meter_id_t index, rtk_uint32 *pBucket_size)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (index > RTK_MAX_METER_ID)
+        return RT_ERR_FILTER_METER_ID;
+
+    if(NULL == pBucket_size)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicShareMeterBucketSize(index, pBucket_size)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_rate_igrBandwidthCtrlRate_set
+ * Description:
+ *      Set port ingress bandwidth control
+ * Input:
+ *      port        - Port id
+ *      rate        - Rate of share meter
+ *      ifg_include - include IFG or not, ENABLE:include DISABLE:exclude
+ *      fc_enable   - enable flow control or not, ENABLE:use flow control DISABLE:drop
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_ENABLE       - Invalid IFG parameter.
+ *      RT_ERR_INBW_RATE    - Invalid ingress rate parameter.
+ * Note:
+ *      The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps.
+ *      The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble.
+ */
+rtk_api_ret_t rtk_rate_igrBandwidthCtrlRate_set(rtk_port_t port, rtk_rate_t rate, rtk_enable_t ifg_include, rtk_enable_t fc_enable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(ifg_include >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if(fc_enable >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if(rtk_switch_isHsgPort(port) == RT_ERR_OK)
+    {
+        if ((rate > RTL8367C_QOS_RATE_INPUT_MAX_HSG) || (rate < RTL8367C_QOS_RATE_INPUT_MIN))
+            return RT_ERR_QOS_EBW_RATE ;
+    }
+    else
+    {
+        if ((rate > RTL8367C_QOS_RATE_INPUT_MAX) || (rate < RTL8367C_QOS_RATE_INPUT_MIN))
+            return RT_ERR_QOS_EBW_RATE ;
+    }
+
+    if ((retVal = rtl8367c_setAsicPortIngressBandwidth(rtk_switch_port_L2P_get(port), rate>>3, ifg_include,fc_enable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_rate_igrBandwidthCtrlRate_get
+ * Description:
+ *      Get port ingress bandwidth control
+ * Input:
+ *      port - Port id
+ * Output:
+ *      pRate           - Rate of share meter
+ *      pIfg_include    - Rate's calculation including IFG, ENABLE:include DISABLE:exclude
+ *      pFc_enable      - enable flow control or not, ENABLE:use flow control DISABLE:drop
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *     The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps.
+ *     The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble.
+ */
+rtk_api_ret_t rtk_rate_igrBandwidthCtrlRate_get(rtk_port_t port, rtk_rate_t *pRate, rtk_enable_t *pIfg_include, rtk_enable_t *pFc_enable)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 regData;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pIfg_include)
+        return RT_ERR_NULL_POINTER;
+
+    if(NULL == pFc_enable)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicPortIngressBandwidth(rtk_switch_port_L2P_get(port), &regData, pIfg_include, pFc_enable)) != RT_ERR_OK)
+        return retVal;
+
+    *pRate = regData<<3;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_rate_egrBandwidthCtrlRate_set
+ * Description:
+ *      Set port egress bandwidth control
+ * Input:
+ *      port        - Port id
+ *      rate        - Rate of egress bandwidth
+ *      ifg_include - include IFG or not, ENABLE:include DISABLE:exclude
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_QOS_EBW_RATE - Invalid egress bandwidth/rate
+ * Note:
+ *     The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps.
+ *     The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble.
+ */
+rtk_api_ret_t rtk_rate_egrBandwidthCtrlRate_set( rtk_port_t port, rtk_rate_t rate,  rtk_enable_t ifg_include)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(rtk_switch_isHsgPort(port) == RT_ERR_OK)
+    {
+        if ((rate > RTL8367C_QOS_RATE_INPUT_MAX_HSG) || (rate < RTL8367C_QOS_RATE_INPUT_MIN))
+            return RT_ERR_QOS_EBW_RATE ;
+    }
+    else
+    {
+        if ((rate > RTL8367C_QOS_RATE_INPUT_MAX) || (rate < RTL8367C_QOS_RATE_INPUT_MIN))
+            return RT_ERR_QOS_EBW_RATE ;
+    }
+
+    if (ifg_include >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if ((retVal = rtl8367c_setAsicPortEgressRate(rtk_switch_port_L2P_get(port), rate>>3)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicPortEgressRateIfg(ifg_include)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_rate_egrBandwidthCtrlRate_get
+ * Description:
+ *      Get port egress bandwidth control
+ * Input:
+ *      port - Port id
+ * Output:
+ *      pRate           - Rate of egress bandwidth
+ *      pIfg_include    - Rate's calculation including IFG, ENABLE:include DISABLE:exclude
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *     The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps.
+ *     The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble.
+ */
+rtk_api_ret_t rtk_rate_egrBandwidthCtrlRate_get(rtk_port_t port, rtk_rate_t *pRate, rtk_enable_t *pIfg_include)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 regData;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pRate)
+        return RT_ERR_NULL_POINTER;
+
+    if(NULL == pIfg_include)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicPortEgressRate(rtk_switch_port_L2P_get(port), &regData)) != RT_ERR_OK)
+        return retVal;
+
+    *pRate = regData << 3;
+
+    if ((retVal = rtl8367c_getAsicPortEgressRateIfg((rtk_uint32*)pIfg_include)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_rate_egrQueueBwCtrlEnable_get
+ * Description:
+ *      Get enable status of egress bandwidth control on specified queue.
+ * Input:
+ *      unit    - unit id
+ *      port    - port id
+ *      queue   - queue id
+ * Output:
+ *      pEnable - Pointer to enable status of egress queue bandwidth control
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID          - invalid port id
+ *      RT_ERR_QUEUE_ID         - invalid queue id
+ *      RT_ERR_NULL_POINTER     - input parameter may be null pointer
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_rate_egrQueueBwCtrlEnable_get(rtk_port_t port, rtk_qid_t queue, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    /*for whole port function, the queue value should be 0xFF*/
+    if (queue != RTK_WHOLE_SYSTEM)
+        return RT_ERR_QUEUE_ID;
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicAprEnable(rtk_switch_port_L2P_get(port),pEnable))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_rate_egrQueueBwCtrlEnable_set
+ * Description:
+ *      Set enable status of egress bandwidth control on specified queue.
+ * Input:
+ *      port   - port id
+ *      queue  - queue id
+ *      enable - enable status of egress queue bandwidth control
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID          - invalid port id
+ *      RT_ERR_QUEUE_ID         - invalid queue id
+ *      RT_ERR_INPUT            - invalid input parameter
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_rate_egrQueueBwCtrlEnable_set(rtk_port_t port, rtk_qid_t queue, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    /*for whole port function, the queue value should be 0xFF*/
+    if (queue != RTK_WHOLE_SYSTEM)
+        return RT_ERR_QUEUE_ID;
+
+    if (enable>=RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicAprEnable(rtk_switch_port_L2P_get(port), enable))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_rate_egrQueueBwCtrlRate_get
+ * Description:
+ *      Get rate of egress bandwidth control on specified queue.
+ * Input:
+ *      port  - port id
+ *      queue - queue id
+ *      pIndex - shared meter index
+ * Output:
+ *      pRate - pointer to rate of egress queue bandwidth control
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID          - invalid port id
+ *      RT_ERR_QUEUE_ID         - invalid queue id
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter id
+ * Note:
+ *    The actual rate control is set in shared meters.
+ *    The unit of granularity is 8Kbps.
+ */
+rtk_api_ret_t rtk_rate_egrQueueBwCtrlRate_get(rtk_port_t port, rtk_qid_t queue, rtk_meter_id_t *pIndex)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 offset_idx;
+    rtk_uint32 phy_port;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (queue >= RTK_MAX_NUM_OF_QUEUE)
+        return RT_ERR_QUEUE_ID;
+
+    if(NULL == pIndex)
+        return RT_ERR_NULL_POINTER;
+
+    phy_port = rtk_switch_port_L2P_get(port);
+    if ((retVal=rtl8367c_getAsicAprMeter(phy_port, queue,&offset_idx))!=RT_ERR_OK)
+        return retVal;
+
+    *pIndex = offset_idx + ((phy_port%4)*8);
+
+     return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_rate_egrQueueBwCtrlRate_set
+ * Description:
+ *      Set rate of egress bandwidth control on specified queue.
+ * Input:
+ *      port  - port id
+ *      queue - queue id
+ *      index - shared meter index
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID          - invalid port id
+ *      RT_ERR_QUEUE_ID         - invalid queue id
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter id
+ * Note:
+ *    The actual rate control is set in shared meters.
+ *    The unit of granularity is 8Kbps.
+ */
+rtk_api_ret_t rtk_rate_egrQueueBwCtrlRate_set(rtk_port_t port, rtk_qid_t queue, rtk_meter_id_t index)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 offset_idx;
+    rtk_uint32 phy_port;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (queue >= RTK_MAX_NUM_OF_QUEUE)
+        return RT_ERR_QUEUE_ID;
+
+    if (index > RTK_MAX_METER_ID)
+        return RT_ERR_FILTER_METER_ID;
+
+    phy_port = rtk_switch_port_L2P_get(port);
+    if (index < ((phy_port%4)*8) ||  index > (7 + (phy_port%4)*8))
+        return RT_ERR_FILTER_METER_ID;
+
+    offset_idx = index - ((phy_port%4)*8);
+
+    if ((retVal=rtl8367c_setAsicAprMeter(phy_port,queue,offset_idx))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rldp.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rldp.c
new file mode 100644
index 0000000..d3ca029
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rldp.c
@@ -0,0 +1,468 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (¶g¤T, 08 ¤T¤ë 2017) $
+ *
+ * Purpose : Declaration of RLDP and RLPP API
+ *
+ * Feature : The file have include the following module and sub-modules
+ *           1) RLDP and RLPP configuration and status
+ *
+ */
+
+
+/*
+ * Include Files
+ */
+#include <rtk_switch.h>
+#include <rtk_error.h>
+//#include <rtk_types.h>
+#include <rldp.h>
+
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_rldp.h>
+
+/*
+ * Symbol Definition
+ */
+
+
+/*
+ * Data Declaration
+ */
+
+
+/*
+ * Macro Declaration
+ */
+
+
+/*
+ * Function Declaration
+ */
+
+/* Module Name : RLDP */
+
+/* Function Name:
+ *      rtk_rldp_config_set
+ * Description:
+ *      Set RLDP module configuration
+ * Input:
+ *      pConfig - configuration structure of RLDP
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT
+ *      RT_ERR_NULL_POINTER
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_rldp_config_set(rtk_rldp_config_t *pConfig)
+{
+    rtk_api_ret_t retVal;
+    ether_addr_t magic;
+    rtk_uint32 pmsk;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (pConfig->rldp_enable >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if (pConfig->trigger_mode >= RTK_RLDP_TRIGGER_END)
+        return RT_ERR_INPUT;
+
+    if (pConfig->compare_type >= RTK_RLDP_CMPTYPE_END)
+        return RT_ERR_INPUT;
+
+    if (pConfig->num_check >= RTK_RLDP_NUM_MAX)
+        return RT_ERR_INPUT;
+
+    if (pConfig->interval_check >= RTK_RLDP_INTERVAL_MAX)
+        return RT_ERR_INPUT;
+
+    if (pConfig->num_loop >= RTK_RLDP_NUM_MAX)
+        return RT_ERR_INPUT;
+
+    if (pConfig->interval_loop >= RTK_RLDP_INTERVAL_MAX)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_getAsicRldpTxPortmask(&pmsk))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicRldpTxPortmask(0x00))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicRldpTxPortmask(pmsk))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicRldp(pConfig->rldp_enable))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicRldpTriggerMode(pConfig->trigger_mode))!=RT_ERR_OK)
+        return retVal;
+
+    memcpy(&magic, &pConfig->magic, sizeof(ether_addr_t));
+    if ((retVal = rtl8367c_setAsicRldpMagicNum(magic))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicRldpCompareRandomNumber(pConfig->compare_type))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicRldpCompareRandomNumber(pConfig->compare_type))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicRldpCheckingStatePara(pConfig->num_check, pConfig->interval_check))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicRldpLoopStatePara(pConfig->num_loop, pConfig->interval_loop))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_rldp_config_get
+ * Description:
+ *      Get RLDP module configuration
+ * Input:
+ *      None
+ * Output:
+ *      pConfig - configuration structure of RLDP
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT
+ *      RT_ERR_NULL_POINTER
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_rldp_config_get(rtk_rldp_config_t *pConfig)
+{
+    rtk_api_ret_t retVal;
+    ether_addr_t magic;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((retVal = rtl8367c_getAsicRldp(&pConfig->rldp_enable))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicRldpTriggerMode(&pConfig->trigger_mode))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicRldpMagicNum(&magic))!=RT_ERR_OK)
+        return retVal;
+    memcpy(&pConfig->magic, &magic, sizeof(ether_addr_t));
+
+    if ((retVal = rtl8367c_getAsicRldpCompareRandomNumber(&pConfig->compare_type))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicRldpCompareRandomNumber(&pConfig->compare_type))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicRldpCheckingStatePara(&pConfig->num_check, &pConfig->interval_check))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicRldpLoopStatePara(&pConfig->num_loop, &pConfig->interval_loop))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_rldp_portConfig_set
+ * Description:
+ *      Set per port RLDP module configuration
+ * Input:
+ *      port   - port number to be configured
+ *      pPortConfig - per port configuration structure of RLDP
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT
+ *      RT_ERR_NULL_POINTER
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_rldp_portConfig_set(rtk_port_t port, rtk_rldp_portConfig_t *pPortConfig)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmsk;
+    rtk_uint32 phy_port;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (pPortConfig->tx_enable>= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    phy_port = rtk_switch_port_L2P_get(port);
+
+    if ((retVal = rtl8367c_getAsicRldpTxPortmask(&pmsk))!=RT_ERR_OK)
+        return retVal;
+
+    if (pPortConfig->tx_enable)
+    {
+         pmsk |=(1<<phy_port);
+    }
+    else
+    {
+         pmsk &= ~(1<<phy_port);
+    }
+
+    if ((retVal = rtl8367c_setAsicRldpTxPortmask(pmsk))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+
+} /* end of rtk_rldp_portConfig_set */
+
+
+/* Function Name:
+ *      rtk_rldp_portConfig_get
+ * Description:
+ *      Get per port RLDP module configuration
+ * Input:
+ *      port    - port number to be get
+ * Output:
+ *      pPortConfig - per port configuration structure of RLDP
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT
+ *      RT_ERR_NULL_POINTER
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_rldp_portConfig_get(rtk_port_t port, rtk_rldp_portConfig_t *pPortConfig)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmsk;
+    rtk_portmask_t logicalPmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if ((retVal = rtl8367c_getAsicRldpTxPortmask(&pmsk))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtk_switch_portmask_P2L_get(pmsk, &logicalPmask)) != RT_ERR_OK)
+        return retVal;
+
+
+    if (logicalPmask.bits[0] & (1<<port))
+    {
+         pPortConfig->tx_enable = ENABLED;
+    }
+    else
+    {
+         pPortConfig->tx_enable = DISABLED;
+    }
+
+    return RT_ERR_OK;
+} /* end of rtk_rldp_portConfig_get */
+
+
+/* Function Name:
+ *      rtk_rldp_status_get
+ * Description:
+ *      Get RLDP module status
+ * Input:
+ *      None
+ * Output:
+ *      pStatus - status structure of RLDP
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NULL_POINTER
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_rldp_status_get(rtk_rldp_status_t *pStatus)
+{
+    rtk_api_ret_t retVal;
+    ether_addr_t seed;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((retVal = rtl8367c_getAsicRldpRandomNumber(&seed))!=RT_ERR_OK)
+        return retVal;
+    memcpy(&pStatus->id, &seed, sizeof(ether_addr_t));
+
+    return RT_ERR_OK;
+} /* end of rtk_rldp_status_get */
+
+
+/* Function Name:
+ *      rtk_rldp_portStatus_get
+ * Description:
+ *      Get RLDP module status
+ * Input:
+ *      port    - port number to be get
+ * Output:
+ *      pPortStatus - per port status structure of RLDP
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT
+ *      RT_ERR_NULL_POINTER
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_rldp_portStatus_get(rtk_port_t port, rtk_rldp_portStatus_t *pPortStatus)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmsk;
+    rtk_portmask_t logicalPmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if ((retVal = rtl8367c_getAsicRldpLoopedPortmask(&pmsk))!=RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtk_switch_portmask_P2L_get(pmsk, &logicalPmask)) != RT_ERR_OK)
+        return retVal;
+
+    if (logicalPmask.bits[0] & (1<<port))
+    {
+         pPortStatus->loop_status = RTK_RLDP_LOOPSTS_LOOPING;
+    }
+    else
+    {
+         pPortStatus->loop_status  = RTK_RLDP_LOOPSTS_NONE;
+    }
+
+    if ((retVal = rtl8367c_getAsicRldpEnterLoopedPortmask(&pmsk))!=RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtk_switch_portmask_P2L_get(pmsk, &logicalPmask)) != RT_ERR_OK)
+        return retVal;
+
+    if (logicalPmask.bits[0] & (1<<port))
+    {
+         pPortStatus->loop_enter = RTK_RLDP_LOOPSTS_LOOPING;
+    }
+    else
+    {
+         pPortStatus->loop_enter  = RTK_RLDP_LOOPSTS_NONE;
+    }
+
+    if ((retVal = rtl8367c_getAsicRldpLeaveLoopedPortmask(&pmsk))!=RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtk_switch_portmask_P2L_get(pmsk, &logicalPmask)) != RT_ERR_OK)
+        return retVal;
+
+    if (logicalPmask.bits[0] & (1<<port))
+    {
+         pPortStatus->loop_leave = RTK_RLDP_LOOPSTS_LOOPING;
+    }
+    else
+    {
+         pPortStatus->loop_leave  = RTK_RLDP_LOOPSTS_NONE;
+    }
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_rldp_portStatus_clear
+ * Description:
+ *      Clear RLDP module status
+ * Input:
+ *      port    - port number to be clear
+ *      pPortStatus - per port status structure of RLDP
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT
+ *      RT_ERR_NULL_POINTER
+ * Note:
+ *      Clear operation effect loop_enter and loop_leave only, other field in
+ *      the structure are don't care. Loop status cab't be clean.
+ */
+rtk_api_ret_t rtk_rldp_portStatus_set(rtk_port_t port, rtk_rldp_portStatus_t *pPortStatus)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmsk;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    pmsk = (pPortStatus->loop_enter)<<rtk_switch_port_L2P_get(port);
+    if ((retVal = rtl8367c_setAsicRldpEnterLoopedPortmask(pmsk))!=RT_ERR_OK)
+        return retVal;
+
+    pmsk = (pPortStatus->loop_leave)<<rtk_switch_port_L2P_get(port);
+    if ((retVal = rtl8367c_setAsicRldpLeaveLoopedPortmask(pmsk))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_rldp_portLoopPair_get
+ * Description:
+ *      Get RLDP port loop pairs
+ * Input:
+ *      port    - port number to be get
+ * Output:
+ *      pPortmask - per port related loop ports
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT
+ *      RT_ERR_NULL_POINTER
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_rldp_portLoopPair_get(rtk_port_t port, rtk_portmask_t *pPortmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmsk;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if ((retVal = rtl8367c_getAsicRldpLoopedPortPair(rtk_switch_port_L2P_get(port), &pmsk))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtk_switch_portmask_P2L_get(pmsk, pPortmask)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtk_hal.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtk_hal.c
new file mode 100644
index 0000000..b937349
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtk_hal.c
@@ -0,0 +1,839 @@
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include  "./include/rtk_switch.h"
+#include  "./include/vlan.h"
+#include  "./include/port.h"
+#include  "./include/rate.h"
+#include  "./include/rtk_hal.h"
+#include  "./include/l2.h"
+#include  "./include/stat.h"
+#include  "./include/igmp.h"
+#include  "./include/trap.h"
+#include  "./include/leaky.h"
+#include  "./include/mirror.h"
+#include  "./include/rtl8367c_asicdrv_port.h"
+#include  "./include/rtl8367c_asicdrv_mib.h"
+#include  "./include/smi.h"
+#include  "./include/qos.h"
+#include  "./include/trunk.h"
+
+void rtk_hal_switch_init(void)
+{
+	if(rtk_switch_init() != 0)
+        printk("rtk_switch_init failed\n");
+	mdelay(500);
+	/*vlan init */
+	if (rtk_vlan_init() != 0)
+        printk("rtk_vlan_init failed\n");
+}
+
+void rtk_hal_dump_full_mib(void)
+{
+	rtk_port_t port;
+	rtk_stat_counter_t Cntr;
+	rtk_stat_port_type_t cntr_idx;
+
+	for (port = UTP_PORT0; port < (UTP_PORT0 + 5); port++) {
+		printk("\nPort%d\n", port);
+		for (cntr_idx = STAT_IfInOctets; cntr_idx < STAT_PORT_CNTR_END; cntr_idx ++) {
+			rtk_stat_port_get(port, cntr_idx, &Cntr);
+			printk("%8llu ", Cntr);
+			if (((cntr_idx%10) == 9))
+				printk("\n");
+		}
+	}
+
+	for (port = EXT_PORT0; port < (EXT_PORT0 + 2); port++) {
+		printk("\nPort%d\n", port);
+		for (cntr_idx = STAT_IfInOctets; cntr_idx < STAT_PORT_CNTR_END; cntr_idx ++) {
+			rtk_stat_port_get(port, cntr_idx, &Cntr);
+			printk("%8llu ", Cntr);
+			if (((cntr_idx%10) == 9))
+				printk("\n");
+		}
+	}
+	rtk_stat_global_reset();
+}
+void rtk_dump_mib_type(rtk_stat_port_type_t cntr_idx)
+{
+	rtk_port_t port;
+	rtk_stat_counter_t Cntr;
+
+	for (port = UTP_PORT0; port < (UTP_PORT0 + 5); port++) {
+		rtk_stat_port_get(port, cntr_idx, &Cntr);
+		printk("%8llu", Cntr);
+	}
+	for (port = EXT_PORT0; port < (EXT_PORT0 + 2); port++) {
+		rtk_stat_port_get(port, cntr_idx, &Cntr);
+		printk("%8llu", Cntr);
+	}
+	printk("\n");
+}
+
+void rtk_hal_dump_mib(void)
+{
+
+	printk("==================%8s%8s%8s%8s%8s%8s%8s\n", "Port0", "Port1",
+	       "Port2", "Port3", "Port4", "Port16", "Port17");
+	/* Get TX Unicast Pkts */
+	printk("TX Unicast Pkts  :");
+	rtk_dump_mib_type(STAT_IfOutUcastPkts);
+	/* Get TX Multicast Pkts */
+	printk("TX Multicast Pkts:");
+	rtk_dump_mib_type(STAT_IfOutMulticastPkts);
+	/* Get TX BroadCast Pkts */
+	printk("TX BroadCast Pkts:");
+	rtk_dump_mib_type(STAT_IfOutBroadcastPkts);
+	/* Get TX Collisions */
+	/* Get TX Puase Frames */
+	printk("TX Pause Frames  :");
+	rtk_dump_mib_type(STAT_Dot3OutPauseFrames);
+	/* Get TX Drop Events */
+	/* Get RX Unicast Pkts */
+	printk("RX Unicast Pkts  :");
+	rtk_dump_mib_type(STAT_IfInUcastPkts);
+	/* Get RX Multicast Pkts */
+	printk("RX Multicast Pkts:");
+	rtk_dump_mib_type(STAT_IfInMulticastPkts);
+	/* Get RX Broadcast Pkts */
+	printk("RX Broadcast Pkts:");
+	rtk_dump_mib_type(STAT_IfInBroadcastPkts);
+	/* Get RX FCS Erros */
+	printk("RX FCS Errors    :");
+	rtk_dump_mib_type(STAT_Dot3StatsFCSErrors);
+	/* Get RX Undersize Pkts */
+	printk("RX Undersize Pkts:");
+	rtk_dump_mib_type(STAT_EtherStatsUnderSizePkts);
+	/* Get RX Discard Pkts */
+	printk("RX Discard Pkts  :");
+	rtk_dump_mib_type(STAT_Dot1dTpPortInDiscards);
+	/* Get RX Fragments */
+	printk("RX Fragments     :");
+	rtk_dump_mib_type(STAT_EtherStatsFragments);
+	/* Get RX Oversize Pkts */
+	printk("RX Oversize Pkts :");
+	rtk_dump_mib_type(STAT_EtherOversizeStats);
+	/* Get RX Jabbers */
+	printk("RX Jabbers       :");
+	rtk_dump_mib_type(STAT_EtherStatsJabbers);
+	/* Get RX Pause Frames */
+	printk("RX Pause Frames  :");
+	rtk_dump_mib_type(STAT_Dot3InPauseFrames);
+	/* clear MIB */
+	rtk_stat_global_reset();
+}
+EXPORT_SYMBOL(rtk_hal_dump_mib);
+
+int rtk_hal_dump_vlan(void)
+{
+	rtk_vlan_cfg_t vlan;
+	int i;
+
+	printk("vid    portmap\n");
+	for (i = 0; i < RTK_SW_VID_RANGE; i++) {
+		rtk_vlan_get(i, &vlan);
+		printk("%3d    ", i);
+		printk("%c",
+		       RTK_PORTMASK_IS_PORT_SET(vlan.mbr,
+						UTP_PORT0) ? '1' : '-');
+		printk("%c",
+		       RTK_PORTMASK_IS_PORT_SET(vlan.mbr,
+						UTP_PORT1) ? '1' : '-');
+		printk("%c",
+		       RTK_PORTMASK_IS_PORT_SET(vlan.mbr,
+						UTP_PORT2) ? '1' : '-');
+		printk("%c",
+		       RTK_PORTMASK_IS_PORT_SET(vlan.mbr,
+						UTP_PORT3) ? '1' : '-');
+		printk("%c",
+		       RTK_PORTMASK_IS_PORT_SET(vlan.mbr,
+						UTP_PORT4) ? '1' : '-');
+		printk("%c",
+		       RTK_PORTMASK_IS_PORT_SET(vlan.mbr,
+						EXT_PORT0) ? '1' : '-');
+		printk("%c",
+		       RTK_PORTMASK_IS_PORT_SET(vlan.mbr,
+						EXT_PORT1) ? '1' : '-');
+		printk("\n");
+	}
+	return 0;
+}
+
+void rtk_hal_clear_vlan(void)
+{
+	rtk_api_ret_t ret;
+
+	ret =  rtk_vlan_reset();
+    if (ret != RT_ERR_OK)
+        printk("rtk_vlan_reset failed\n");
+}
+
+int rtk_hal_set_vlan(struct ra_switch_ioctl_data *data)
+{
+	rtk_vlan_cfg_t vlan;
+	rtk_api_ret_t ret;
+	int i;
+
+	/* clear vlan entry first */
+	memset(&vlan, 0x00, sizeof(rtk_vlan_cfg_t));
+	RTK_PORTMASK_CLEAR(vlan.mbr);
+	RTK_PORTMASK_CLEAR(vlan.untag);
+	rtk_vlan_set(data->vid, &vlan);
+
+	memset(&vlan, 0x00, sizeof(rtk_vlan_cfg_t));
+	for (i = 0; i < 5; i++) {
+		if (data->port_map & (1 << i)) {
+			RTK_PORTMASK_PORT_SET(vlan.mbr, i);
+			RTK_PORTMASK_PORT_SET(vlan.untag, i);
+			rtk_vlan_portPvid_set(i, data->vid, 0);
+		}
+	}
+	for (i = 0; i < 2; i++) {
+		if (data->port_map & (1 << (i + 5))) {
+			RTK_PORTMASK_PORT_SET(vlan.mbr, (i + EXT_PORT0));
+			RTK_PORTMASK_PORT_SET(vlan.untag, (i + EXT_PORT0));
+			rtk_vlan_portPvid_set((i + EXT_PORT0), data->vid, 0);
+		}
+	}
+	vlan.ivl_en = 1;
+	ret = rtk_vlan_set(data->vid, &vlan);
+
+	return 0;
+}
+
+void rtk_hal_vlan_portpvid_set(rtk_port_t port, rtk_vlan_t pvid, rtk_pri_t priority)
+{
+	rtk_vlan_portPvid_set(port, pvid, priority);
+}
+
+int rtk_hal_set_ingress_rate(struct ra_switch_ioctl_data *data)
+{
+	rtk_api_ret_t ret;
+
+	if (data->on_off == 1)
+		ret =
+		    rtk_rate_igrBandwidthCtrlRate_set(data->port, data->bw, 0,
+						      1);
+	else
+		ret =
+		    rtk_rate_igrBandwidthCtrlRate_set(data->port, 1048568, 0,
+						      1);
+
+	return ret;
+}
+
+int rtk_hal_set_egress_rate(struct ra_switch_ioctl_data *data)
+{
+	rtk_api_ret_t ret;
+
+	if (data->on_off == 1)
+		ret =
+		    rtk_rate_egrBandwidthCtrlRate_set(data->port, data->bw, 1);
+	else
+		ret = rtk_rate_egrBandwidthCtrlRate_set(data->port, 1048568, 1);
+
+	return ret;
+}
+
+void rtk_hal_dump_table(void)
+{
+	rtk_uint32 i;
+	rtk_uint32 address = 0;
+	rtk_l2_ucastAddr_t l2_data;
+	rtk_l2_ipMcastAddr_t ipMcastAddr;
+
+	printk("hash  port(0:17)   fid   vid  mac-address\n");
+	while (1) {
+		if (rtk_l2_addr_next_get(READMETHOD_NEXT_L2UC, UTP_PORT0, &address, &l2_data) != RT_ERR_OK) {
+			break;
+		} else {
+			printk("%03x   ", l2_data.address);
+			for (i = 0; i < 5; i++)
+				if ( l2_data.port == i)
+					printk("1");
+				else
+					printk("-");
+			for (i = 16; i < 18; i++)
+				if ( l2_data.port == i)
+					printk("1");
+				else
+					printk("-");
+
+			printk("      %2d", l2_data.fid);
+			printk("  %4d", l2_data.cvid);
+			printk("  %02x%02x%02x%02x%02x%02x\n", l2_data.mac.octet[0],
+			l2_data.mac.octet[1], l2_data.mac.octet[2], l2_data.mac.octet[3], 
+			l2_data.mac.octet[4], l2_data.mac.octet[5]);
+			address ++;
+			}
+	}
+
+	address = 0;
+	while (1) {
+        if (rtk_l2_ipMcastAddr_next_get(&address, &ipMcastAddr) != RT_ERR_OK) {
+            break;
+        } else {
+            printk("%03x   ", ipMcastAddr.address);
+            for (i = 0; i < 5; i++)
+                printk("%c", RTK_PORTMASK_IS_PORT_SET(ipMcastAddr.portmask, i) ? '1' : '-');
+            for (i = 16; i < 18; i++)
+                printk("%c", RTK_PORTMASK_IS_PORT_SET(ipMcastAddr.portmask, i) ? '1' : '-');
+			printk("                ");
+			printk("01005E%06x\n", (ipMcastAddr.dip & 0xefffff));
+            address ++;
+            }
+    }
+}
+
+void rtk_hal_clear_table(void)
+{
+	rtk_api_ret_t ret;
+
+	ret = rtk_l2_table_clear();
+	if (ret != RT_ERR_OK)
+		printk("rtk_l2_table_clear failed\n");
+}
+
+void rtk_hal_add_table(struct ra_switch_ioctl_data *data)
+{
+	rtk_api_ret_t ret;
+	rtk_l2_ucastAddr_t l2_entry;
+	rtk_mac_t mac;
+
+	mac.octet[0] =data->mac[0];
+	mac.octet[1] =data->mac[1];
+	mac.octet[2] =data->mac[2];
+	mac.octet[3] =data->mac[3];
+	mac.octet[4] =data->mac[4];
+	mac.octet[5] =data->mac[5];
+
+	memset(&l2_entry, 0x00, sizeof(rtk_l2_ucastAddr_t));
+	l2_entry.port = data->port;
+	l2_entry.ivl = 1;
+	l2_entry.cvid = data->vid;
+	l2_entry.fid = 0;
+	l2_entry.efid = 0;
+	l2_entry.is_static = 1;
+	ret = rtk_l2_addr_add(&mac, &l2_entry);
+	if (ret != RT_ERR_OK)
+		printk("rtk_hal_add_table failed\n");
+}
+
+void rtk_hal_del_table(struct ra_switch_ioctl_data *data)
+{
+	rtk_api_ret_t ret;
+	rtk_l2_ucastAddr_t l2_entry;
+	rtk_mac_t mac;
+
+	mac.octet[0] =data->mac[0];
+	mac.octet[1] =data->mac[1];
+	mac.octet[2] =data->mac[2];
+	mac.octet[3] =data->mac[3];
+	mac.octet[4] =data->mac[4];
+	mac.octet[5] =data->mac[5];
+
+	memset(&l2_entry, 0x00, sizeof(rtk_l2_ucastAddr_t));
+	l2_entry.port = data->port;
+	l2_entry.ivl = 1;
+	l2_entry.cvid = data->vid;
+	l2_entry.fid = 0;
+	l2_entry.efid = 0;
+	ret = rtk_l2_addr_del(&mac, &l2_entry);
+	if (ret != RT_ERR_OK)
+		printk("rtk_hal_add_table failed\n");
+}
+void rtk_hal_get_phy_status(struct ra_switch_ioctl_data *data)
+{
+	rtk_port_linkStatus_t linkStatus;
+	rtk_port_speed_t speed;
+	rtk_port_duplex_t duplex;
+
+    rtk_port_phyStatus_get(data->port, &linkStatus, &speed, &duplex);
+    printk("Port%d Status:\n", data->port);
+	if (linkStatus == 1) {
+        printk("Link Up");
+        if (speed == 0)
+			printk(" 10M");
+		else if (speed == 1)
+			printk(" 100M");
+		else if (speed == 2)
+            printk(" 1000M");
+        if (duplex == 0)
+			printk(" Half Duplex\n");
+		else
+			printk(" Full Duplex\n");
+	} else
+		printk("Link Down\n");
+
+}
+
+void rtk_hal_set_port_mirror(struct ra_switch_ioctl_data *data)
+{
+	rtk_portmask_t rx_portmask;
+	rtk_portmask_t tx_portmask;
+	rtk_api_ret_t ret;
+	int i;
+
+	rtk_mirror_portIso_set(ENABLED);
+	RTK_PORTMASK_CLEAR(rx_portmask);
+	RTK_PORTMASK_CLEAR(tx_portmask);
+    for (i = 0; i < 5; i++)
+		if (data->rx_port_map & (1 << i))
+			RTK_PORTMASK_PORT_SET(rx_portmask, i);
+	for (i = 0; i < 2; i++)
+		if (data->rx_port_map & (1 << (i + 5)))
+			RTK_PORTMASK_PORT_SET(rx_portmask, (i + EXT_PORT0));
+
+	RTK_PORTMASK_CLEAR(tx_portmask);
+    for (i = 0; i < 5; i++)
+        if (data->tx_port_map & (1 << i))
+            RTK_PORTMASK_PORT_SET(tx_portmask, i);
+    for (i = 0; i < 2; i++)
+        if (data->tx_port_map & (1 << (i + 5)))
+            RTK_PORTMASK_PORT_SET(tx_portmask, (i + EXT_PORT0));
+
+    ret = rtk_mirror_portBased_set(data->port, &rx_portmask, &tx_portmask);
+	if (!ret)
+		printk("rtk_mirror_portBased_set success\n");
+}
+
+void rtk_hal_read_reg(struct ra_switch_ioctl_data *data)
+{
+	ret_t retVal;
+
+	retVal = smi_read(data->reg_addr, &data->reg_val);
+	if(retVal != RT_ERR_OK)
+		printk("switch reg read failed\n");
+	else
+		printk("reg0x%x = 0x%x\n", data->reg_addr, data->reg_val);
+}
+
+void rtk_hal_write_reg(struct ra_switch_ioctl_data *data)
+{
+	ret_t retVal;
+
+    retVal = smi_write(data->reg_addr, data->reg_val);
+    if(retVal != RT_ERR_OK)
+        printk("switch reg write failed\n");
+    else
+        printk("write switch reg0x%x 0x%x success\n", data->reg_addr, data->reg_val);
+}
+
+void rtk_hal_get_phy_reg(struct ra_switch_ioctl_data *data)
+{
+	ret_t retVal;
+	rtk_port_phy_data_t Data;
+
+	retVal = rtk_port_phyReg_get(data->port, data->reg_addr, &Data);
+	if (retVal == RT_ERR_OK)
+		printk("Get: phy[%d].reg[%d] = 0x%04x\n", data->port, data->reg_addr, Data);
+	else
+		printk("read phy reg failed\n");
+}
+
+void rtk_hal_set_phy_reg(struct ra_switch_ioctl_data *data)
+{
+	ret_t retVal;
+
+	retVal = rtk_port_phyReg_set(data->port, data->reg_addr, data->reg_val);
+	if (retVal == RT_ERR_OK)
+		printk("Set: phy[%d].reg[%d] = 0x%04x\n", data->port, data->reg_addr, data->reg_val);
+	else
+		printk("write phy reg failed\n");
+}
+void rtk_hal_qos_en(struct ra_switch_ioctl_data *data)
+{
+
+	if (data->on_off == 1) {
+		if (rtk_qos_init(8) != 0)
+			printk("rtk_qos_init(8) failed\n");
+	}
+	else {
+		if (rtk_qos_init(1) != 0)
+            printk("rtk_qos_init(1) failed\n");
+	}
+}
+
+void rtk_hal_qos_set_table2type(struct ra_switch_ioctl_data *data)
+{
+	rtk_api_ret_t ret;
+	rtk_priority_select_t PriDec;
+
+	/* write all pri to 0 */
+	PriDec.port_pri = 0;
+    PriDec.dot1q_pri = 0;
+    PriDec.acl_pri = 0;
+    PriDec.cvlan_pri = 0;
+    PriDec.svlan_pri = 0;
+    PriDec.dscp_pri = 0;
+    PriDec.dmac_pri = 0;
+    PriDec.smac_pri = 0;
+
+	if (data->qos_type == 0)
+		PriDec.port_pri = 1;
+	else if (data->qos_type == 1)
+		PriDec.dot1q_pri = 1;
+	else if (data->qos_type == 2)
+		PriDec.acl_pri = 1;
+	else if (data->qos_type == 3)
+		PriDec.dscp_pri = 1;
+	else if (data->qos_type == 4)
+		PriDec.cvlan_pri = 1;
+	else if (data->qos_type == 5)
+		PriDec.svlan_pri = 1;
+	else if (data->qos_type == 6)
+		PriDec.dmac_pri = 1;
+	else if (data->qos_type == 7)
+		PriDec.smac_pri = 1;
+
+	if (data->qos_table_idx == 0)
+		ret = rtk_qos_priSel_set(PRIDECTBL_IDX0, &PriDec);
+	else
+		ret = rtk_qos_priSel_set(PRIDECTBL_IDX1, &PriDec);
+
+	if (ret != 0)
+		printk("rtk_qos_priSel_set failed\n");
+
+}
+
+void rtk_hal_qos_get_table2type(struct ra_switch_ioctl_data *data)
+{
+	rtk_api_ret_t ret;
+	rtk_priority_select_t PriDec;
+
+	if (data->qos_table_idx == 0)
+        ret = rtk_qos_priSel_get(PRIDECTBL_IDX0, &PriDec);
+    else
+        ret = rtk_qos_priSel_get(PRIDECTBL_IDX1, &PriDec);
+
+	if (ret != 0)
+        printk("rtk_qos_priSel_set failed\n");
+    else {
+		printk("port_pri  = %d\n", PriDec.port_pri);
+		printk("dot1q_pri = %d\n", PriDec.dot1q_pri);
+		printk("acl_pri   = %d\n", PriDec.acl_pri);
+		printk("dscp_pri  = %d\n", PriDec.dscp_pri);
+		printk("cvlan_pri = %d\n", PriDec.cvlan_pri);
+		printk("svlan_pri = %d\n", PriDec.svlan_pri);
+		printk("dmac_pri  = %d\n", PriDec.dmac_pri);
+		printk("smac_pri  = %d\n", PriDec.smac_pri);
+	}
+}
+
+void rtk_hal_qos_set_port2table(struct ra_switch_ioctl_data *data)
+{
+	rtk_api_ret_t ret;
+	
+	ret = rtk_qos_portPriSelIndex_set(data->port, data->qos_table_idx);
+	if (ret != 0)
+		printk("rtk_qos_portPriSelIndex_set failed\n");
+}
+
+void rtk_hal_qos_get_port2table(struct ra_switch_ioctl_data *data)
+{
+	rtk_api_ret_t ret;
+	rtk_qos_priDecTbl_t Index;
+	
+	ret = rtk_qos_portPriSelIndex_get(data->port, &Index);
+	if (ret != 0)
+		printk("rtk_qos_portPriSelIndex_set failed\n");
+	else
+		printk("port%d belongs to table%d\n", data->port, Index);
+}
+
+void rtk_hal_qos_set_port2pri(struct ra_switch_ioctl_data *data)
+{
+	rtk_api_ret_t ret;
+
+	ret = rtk_qos_portPri_set(data->port, data->qos_pri);
+	if (ret != 0)
+		printk("rtk_qos_portPri_set failed\n");
+}
+
+void rtk_hal_qos_get_port2pri(struct ra_switch_ioctl_data *data)
+{
+	rtk_api_ret_t ret;
+	rtk_pri_t Int_pri;
+
+	ret = rtk_qos_portPri_get(data->port, &Int_pri);
+	if (ret != 0)
+		printk("rtk_qos_portPri_set failed\n");
+	else
+		printk("port%d priority = %d\n", data->port, Int_pri);
+}
+
+void rtk_hal_qos_set_dscp2pri(struct ra_switch_ioctl_data *data)
+{
+	rtk_api_ret_t ret;
+
+	ret = rtk_qos_dscpPriRemap_set(data->qos_dscp, data->qos_pri);
+	if (ret != 0)
+		printk("rtk_qos_dscpPriRemap_set failed\n");
+}
+
+void rtk_hal_qos_get_dscp2pri(struct ra_switch_ioctl_data *data)
+{
+	rtk_api_ret_t ret;
+	rtk_pri_t Int_pri;
+
+	ret = rtk_qos_dscpPriRemap_get(data->qos_dscp, &Int_pri);
+	if (ret != 0)
+		printk("rtk_qos_dscpPriRemap_set failed\n");
+	else
+		printk("dscp%d priority is %d\n", data->qos_dscp, Int_pri);
+}
+
+void rtk_hal_qos_set_pri2queue(struct ra_switch_ioctl_data *data)
+{
+	rtk_api_ret_t ret;
+	rtk_qos_pri2queue_t pri2qid;
+
+	ret = rtk_qos_priMap_get(8, &pri2qid);
+	pri2qid.pri2queue[data->qos_queue_num] = data->qos_pri;
+	ret = rtk_qos_priMap_set(8, &pri2qid);
+	if (ret != 0)
+		printk("rtk_qos_priMap_set failed\n");
+}
+
+void rtk_hal_qos_get_pri2queue(struct ra_switch_ioctl_data *data)
+{
+	int i;
+	rtk_api_ret_t ret;
+	rtk_qos_pri2queue_t pri2qid;
+
+	ret = rtk_qos_priMap_get(8, &pri2qid);
+	if (ret != 0)
+		printk("rtk_qos_priMap_get failed\n");
+	else {
+		for (i = 0; i < 8; i++)
+			printk("pri2qid.pri2queue[%d] = %d\n", i, pri2qid.pri2queue[i]);
+	}
+}
+
+void rtk_hal_qos_set_queue_weight(struct ra_switch_ioctl_data *data)
+{
+	rtk_api_ret_t ret;
+	rtk_qos_queue_weights_t qweights;
+
+	ret = rtk_qos_schedulingQueue_get(data->port, &qweights);
+	qweights.weights[data->qos_queue_num] = data->qos_weight;
+	ret = rtk_qos_schedulingQueue_set(data->port, &qweights);
+	if (ret != 0)
+		printk("rtk_qos_schedulingQueue_set failed\n");
+}
+
+void rtk_hal_qos_get_queue_weight(struct ra_switch_ioctl_data *data)
+{
+	int i;
+	rtk_api_ret_t ret;
+	rtk_qos_queue_weights_t qweights;
+
+	ret = rtk_qos_schedulingQueue_get(data->port, &qweights);
+	if (ret != 0)
+		printk("rtk_qos_schedulingQueue_get failed\n");
+	else {
+		printk("=== Port%d queue weight ===\n", data->port);
+		for (i = 0; i < 8; i++)
+			printk("qweights.weights[%d] = %d\n",i ,qweights.weights[i]);
+	}
+}
+
+void rtk_hal_enable_igmpsnoop(struct ra_switch_ioctl_data *data)
+{
+	rtk_api_ret_t ret;
+	rtk_portmask_t pmask;
+	
+
+	ret = rtk_igmp_init();
+	if (data->on_off == 1) {
+		RTK_PORTMASK_CLEAR(pmask);
+		RTK_PORTMASK_PORT_SET(pmask, EXT_PORT0);
+		ret |= rtk_igmp_static_router_port_set(&pmask);
+		ret |= rtk_igmp_protocol_set(UTP_PORT4, PROTOCOL_IGMPv1, IGMP_ACTION_FORWARD);
+		ret |= rtk_igmp_protocol_set(UTP_PORT4, PROTOCOL_IGMPv2, IGMP_ACTION_FORWARD);
+		ret |= rtk_igmp_protocol_set(UTP_PORT4, PROTOCOL_MLDv1, IGMP_ACTION_FORWARD);
+		ret |= rtk_igmp_protocol_set(EXT_PORT1, PROTOCOL_IGMPv1, IGMP_ACTION_FORWARD);
+		ret |= rtk_igmp_protocol_set(EXT_PORT1, PROTOCOL_IGMPv2, IGMP_ACTION_FORWARD);
+		ret |= rtk_igmp_protocol_set(EXT_PORT1, PROTOCOL_MLDv1, IGMP_ACTION_FORWARD);
+		ret |= rtk_igmp_protocol_set(UTP_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC);
+		ret |= rtk_igmp_protocol_set(UTP_PORT1, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC);
+		ret |= rtk_igmp_protocol_set(UTP_PORT2, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC);
+		ret |= rtk_igmp_protocol_set(UTP_PORT3, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC);
+		ret |= rtk_igmp_protocol_set(EXT_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC);
+
+		ret |= rtk_leaky_vlan_set(LEAKY_IPMULTICAST, ENABLED);
+		ret |= rtk_l2_ipMcastForwardRouterPort_set(DISABLED);
+		/* drop unknown multicast packets*/
+		/* ret |= rtk_trap_unknownMcastPktAction_set(UTP_PORT4, MCAST_IPV4, MCAST_ACTION_DROP);*/
+	} else {
+		RTK_PORTMASK_CLEAR(pmask);
+        RTK_PORTMASK_PORT_SET(pmask, EXT_PORT0);
+        RTK_PORTMASK_PORT_SET(pmask, EXT_PORT1);
+		ret |= rtk_igmp_protocol_set(UTP_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC);
+		ret |= rtk_igmp_protocol_set(UTP_PORT1, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC);
+		ret |= rtk_igmp_protocol_set(UTP_PORT2, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC);
+		ret |= rtk_igmp_protocol_set(UTP_PORT3, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC);
+		ret |= rtk_igmp_protocol_set(EXT_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC);
+
+		ret |= rtk_igmp_static_router_port_set(&pmask);
+	}
+	if(ret != RT_ERR_OK)
+		printk("enable switch igmpsnoop failed\n");
+}
+
+void rtk_hal_disable_igmpsnoop(void)
+{
+	if (rtk_igmp_state_set(DISABLED) != RT_ERR_OK)
+		printk("Disable IGMP SNOOPING failed\n");
+}
+
+rtk_api_ret_t rtk_port_phyTestMode_set(rtk_port_t port, rtk_port_phy_test_mode_t mode)
+{
+    rtk_uint32          data, regData, i;
+    rtk_api_ret_t       retVal;
+
+    RTK_CHK_PORT_IS_UTP(port);
+
+    if(mode >= PHY_TEST_MODE_END)
+        return RT_ERR_INPUT;
+
+    if( (mode == PHY_TEST_MODE_2) || (mode == PHY_TEST_MODE_3) )
+        return RT_ERR_INPUT;
+
+    if (PHY_TEST_MODE_NORMAL != mode)
+    {
+        /* Other port should be Normal mode */
+        RTK_SCAN_ALL_LOG_PORT(i)
+        {
+            if(rtk_switch_isUtpPort(i) == RT_ERR_OK)
+            {
+                if(i != port)
+                {
+                    if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(i), 9, &data)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((data & 0xE000) != 0)
+                        return RT_ERR_NOT_ALLOWED;
+                }
+            }
+        }
+    }
+
+    if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), 9, &data)) != RT_ERR_OK)
+        return retVal;
+
+    data &= ~0xE000;
+    data |= (mode << 13);
+    if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), 9, data)) != RT_ERR_OK)
+        return retVal;
+
+    if (PHY_TEST_MODE_4 == mode)
+    {
+        if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK)
+            return retVal;
+
+        if((retVal = rtl8367c_getAsicReg(0x1300, &regData)) != RT_ERR_OK)
+            return retVal;
+
+        if( (regData == 0x0276) || (regData == 0x0597) )
+        {
+            if ((retVal = rtl8367c_setAsicPHYOCPReg(rtk_switch_port_L2P_get(port), 0xbcc2, 0xF4F4)) != RT_ERR_OK)
+                return retVal;
+        }
+
+        if( (regData == 0x6367) )
+        {
+            if ((retVal = rtl8367c_setAsicPHYOCPReg(rtk_switch_port_L2P_get(port), 0xa436, 0x80c1)) != RT_ERR_OK)
+                return retVal;
+
+            if ((retVal = rtl8367c_setAsicPHYOCPReg(rtk_switch_port_L2P_get(port), 0xa438, 0xfe00)) != RT_ERR_OK)
+                return retVal;
+        }
+    }
+
+    return RT_ERR_OK;
+}
+
+void rtk_hal_set_phy_test_mode(struct ra_switch_ioctl_data *data)
+{
+	rtk_api_ret_t ret;
+
+    ret = rtk_port_phyTestMode_set(data->port, data->mode);
+	if (ret != RT_ERR_OK)
+		printk("rtk_port_phyTestMode_set failed\n");
+	else
+		printk("set port%d in test mode %d.\n", data->port, data->mode);
+}
+
+void rtk_hal_set_port_trunk(struct ra_switch_ioctl_data *data)
+{
+
+	rtk_api_ret_t ret;
+	rtk_portmask_t member;
+	int i;
+
+	RTK_PORTMASK_CLEAR(member);
+	for (i = 0; i < 4; i++) {
+		if (data->port_map & (1 << i))
+			RTK_PORTMASK_PORT_SET(member, i);
+    }
+
+	ret = rtk_trunk_port_set(TRUNK_GROUP0, &member);
+	if (ret != RT_ERR_OK)
+		printk("rtk_trunk_port_set failed\n");
+
+	ret = rtk_trunk_distributionAlgorithm_set(RTK_WHOLE_SYSTEM, 0x7F);
+	if (ret != RT_ERR_OK)
+		printk("rtk_trunk_distributionAlgorithm_set failed\n");
+}
+
+void rtk_hal_vlan_tag(struct ra_switch_ioctl_data *data)
+{
+	rtk_api_ret_t ret;
+	rtk_vlan_cfg_t vlan;
+
+    ret = rtk_vlan_get(data->vid, &vlan);
+	if (ret != RT_ERR_OK)
+		printk("rtk_vlan_get failed\n");
+	else {
+		if (data->on_off == 0)
+			RTK_PORTMASK_PORT_SET(vlan.untag, data->port);
+		else
+			RTK_PORTMASK_PORT_CLEAR(vlan.untag, data->port);
+		
+		ret = rtk_vlan_set(data->vid, &vlan);
+		if (ret != RT_ERR_OK)
+			printk("rtk_vlan_set failed\n");
+	}
+}
+
+void rtk_hal_vlan_mode(struct ra_switch_ioctl_data *data)
+{
+	rtk_vlan_cfg_t vlan1, vlan2;
+	rtk_api_ret_t ret;
+
+	ret = rtk_vlan_get(1, &vlan1);
+	if (ret != RT_ERR_OK)
+		printk("rtk_vlan_get failed\n");
+
+	ret = rtk_vlan_get(2, &vlan2);
+	if (ret != RT_ERR_OK)
+		printk("rtk_vlan_get failed\n");
+
+	if (data->mode == 0) { //ivl
+		vlan1.ivl_en = 1;
+		vlan1.fid_msti = 0;
+		rtk_vlan_set(1, &vlan1);
+		vlan2.ivl_en = 1;
+		vlan2.fid_msti = 0;
+		rtk_vlan_set(2, &vlan2);
+	} else if(data->mode == 1) {//svl
+		vlan1.ivl_en = 0;
+		vlan1.fid_msti = 0;
+		rtk_vlan_set(1, &vlan1);
+		vlan2.ivl_en = 0;
+		vlan2.fid_msti = 1;
+		rtk_vlan_set(2, &vlan2);
+	} else
+		printk("mode not supported\n");
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtk_switch.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtk_switch.c
new file mode 100644
index 0000000..0bb0db0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtk_switch.c
@@ -0,0 +1,1796 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76336 $
+ * $Date: 2017-03-09 10:41:21 +0800 (週四, 09 三月 2017) $
+ *
+ * Purpose : RTK switch high-level API
+ * Feature : Here is a list of all functions and variables in this module.
+ *
+ */
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <string.h>
+
+#include <rate.h>
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_misc.h>
+#include <rtl8367c_asicdrv_green.h>
+#include <rtl8367c_asicdrv_lut.h>
+#include <rtl8367c_asicdrv_rma.h>
+#include <rtl8367c_asicdrv_mirror.h>
+
+#if defined(FORCE_PROBE_RTL8367C)
+static init_state_t    init_state = INIT_COMPLETED;
+#elif defined(FORCE_PROBE_RTL8370B)
+static init_state_t    init_state = INIT_COMPLETED;
+#elif defined(FORCE_PROBE_RTL8364B)
+static init_state_t    init_state = INIT_COMPLETED;
+#elif defined(FORCE_PROBE_RTL8363SC_VB)
+static init_state_t    init_state = INIT_COMPLETED;
+#else
+static init_state_t    init_state = INIT_NOT_COMPLETED;
+#endif
+
+#define AUTO_PROBE (!defined(FORCE_PROBE_RTL8367C) && !defined(FORCE_PROBE_RTL8370B) && !defined(FORCE_PROBE_RTL8364B) && !defined(FORCE_PROBE_RTL8363SC_VB))
+
+#if (AUTO_PROBE || defined(FORCE_PROBE_RTL8367C))
+static rtk_switch_halCtrl_t rtl8367c_hal_Ctrl =
+{
+    /* Switch Chip */
+    CHIP_RTL8367C,
+
+    /* Logical to Physical */
+    {0, 1, 2, 3, 4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+     6, 7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+
+    /* Physical to Logical */
+    {UTP_PORT0, UTP_PORT1, UTP_PORT2, UTP_PORT3, UTP_PORT4, UNDEFINE_PORT, EXT_PORT0, EXT_PORT1,
+     UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT,
+     UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT,
+     UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT},
+
+    /* Port Type */
+    {UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT,
+     UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT,
+     EXT_PORT, EXT_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT,
+     UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT},
+
+    /* PTP port */
+    {1, 1, 1, 1, 1, 0, 0, 0,
+     0, 0, 0, 0, 0, 0, 0, 0,
+     0, 0, 0, 0, 0, 0, 0, 0,
+     0, 0, 0, 0, 0, 0, 0, 0 },
+
+    /* Valid port mask */
+    ( (0x1 << UTP_PORT0) | (0x1 << UTP_PORT1) | (0x1 << UTP_PORT2) | (0x1 << UTP_PORT3) | (0x1 << UTP_PORT4) | (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ),
+
+    /* Valid UTP port mask */
+    ( (0x1 << UTP_PORT0) | (0x1 << UTP_PORT1) | (0x1 << UTP_PORT2) | (0x1 << UTP_PORT3) | (0x1 << UTP_PORT4) ),
+
+    /* Valid EXT port mask */
+    ( (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ),
+
+    /* Valid CPU port mask */
+    0x00,
+
+    /* Minimum physical port number */
+    0,
+
+    /* Maxmum physical port number */
+    7,
+
+    /* Physical port mask */
+    0xDF,
+
+    /* Combo Logical port ID */
+    4,
+
+    /* HSG Logical port ID */
+    EXT_PORT0,
+
+    /* SGMII Logical portmask */
+    (0x1 << EXT_PORT0),
+
+    /* Max Meter ID */
+    31,
+
+    /* MAX LUT Address Number */
+    2112,
+
+    /* Trunk Group Mask */
+    0x03
+};
+#endif
+
+#if (AUTO_PROBE || defined(FORCE_PROBE_RTL8370B))
+static rtk_switch_halCtrl_t rtl8370b_hal_Ctrl =
+{
+    /* Switch Chip */
+    CHIP_RTL8370B,
+
+    /* Logical to Physical */
+    {0, 1, 2, 3, 4, 5, 6, 7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+     8, 9, 10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+
+    /* Physical to Logical */
+    {UTP_PORT0, UTP_PORT1, UTP_PORT2, UTP_PORT3, UTP_PORT4, UTP_PORT5, UTP_PORT6, UTP_PORT7,
+     EXT_PORT0, EXT_PORT1, EXT_PORT2, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT,
+     UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT,
+     UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT},
+
+    /* Port Type */
+    {UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT,
+     UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT,
+     EXT_PORT, EXT_PORT, EXT_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT,
+     UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT},
+
+    /* PTP port */
+    {1, 1, 1, 1, 1, 1, 1, 1,
+     0, 0, 0, 0, 0, 0, 0, 0,
+     1, 1, 0, 0, 0, 0, 0, 0,
+     0, 0, 0, 0, 0, 0, 0, 0 },
+
+    /* Valid port mask */
+    ( (0x1 << UTP_PORT0) | (0x1 << UTP_PORT1) | (0x1 << UTP_PORT2) | (0x1 << UTP_PORT3) | (0x1 << UTP_PORT4) | (0x1 << UTP_PORT5) | (0x1 << UTP_PORT6) | (0x1 << UTP_PORT7) | (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) | (0x1 << EXT_PORT2) ),
+
+    /* Valid UTP port mask */
+    ( (0x1 << UTP_PORT0) | (0x1 << UTP_PORT1) | (0x1 << UTP_PORT2) | (0x1 << UTP_PORT3) | (0x1 << UTP_PORT4) | (0x1 << UTP_PORT5) | (0x1 << UTP_PORT6) | (0x1 << UTP_PORT7) ),
+
+    /* Valid EXT port mask */
+    ( (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) | (0x1 << EXT_PORT2) ),
+
+    /* Valid CPU port mask */
+    (0x1 << EXT_PORT2),
+
+    /* Minimum physical port number */
+    0,
+
+    /* Maxmum physical port number */
+    10,
+
+    /* Physical port mask */
+    0x7FF,
+
+    /* Combo Logical port ID */
+    7,
+
+    /* HSG Logical port ID */
+    EXT_PORT1,
+
+    /* SGMII Logical portmask */
+    ( (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ),
+
+    /* Max Meter ID */
+    63,
+
+    /* MAX LUT Address Number 4096 + 64*/
+    4160,
+
+    /* Trunk Group Mask */
+    0x07
+};
+#endif
+
+#if (AUTO_PROBE || defined(FORCE_PROBE_RTL8364B))
+static rtk_switch_halCtrl_t rtl8364b_hal_Ctrl =
+{
+    /* Switch Chip */
+    CHIP_RTL8364B,
+
+    /* Logical to Physical */
+    {0xFF, 1, 0xFF, 3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+     6, 7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+
+    /* Physical to Logical */
+    {UNDEFINE_PORT, UTP_PORT1, UNDEFINE_PORT, UTP_PORT3, UNDEFINE_PORT, UNDEFINE_PORT, EXT_PORT0, EXT_PORT1,
+     UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT,
+     UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT,
+     UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT},
+
+    /* Port Type */
+    {UNKNOWN_PORT, UTP_PORT, UNKNOWN_PORT, UTP_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT,
+     UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT,
+     EXT_PORT, EXT_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT,
+     UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT},
+
+    /* PTP port */
+    {0, 0, 0, 0, 0, 0, 0, 0,
+     0, 0, 0, 0, 0, 0, 0, 0,
+     0, 0, 0, 0, 0, 0, 0, 0,
+     0, 0, 0, 0, 0, 0, 0, 0 },
+
+    /* Valid port mask */
+    ( (0x1 << UTP_PORT1) | (0x1 << UTP_PORT3) | (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ),
+
+    /* Valid UTP port mask */
+    ( (0x1 << UTP_PORT1) | (0x1 << UTP_PORT3) ),
+
+    /* Valid EXT port mask */
+    ( (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ),
+
+    /* Valid CPU port mask */
+    0x00,
+
+    /* Minimum physical port number */
+    0,
+
+    /* Maxmum physical port number */
+    7,
+
+    /* Physical port mask */
+    0xCA,
+
+    /* Combo Logical port ID */
+    4,
+
+    /* HSG Logical port ID */
+    EXT_PORT0,
+
+    /* SGMII Logical portmask */
+    ( (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ),
+
+    /* Max Meter ID */
+    32,
+
+    /* MAX LUT Address Number */
+    2112,
+
+    /* Trunk Group Mask */
+    0x01
+};
+#endif
+
+#if (AUTO_PROBE || defined(FORCE_PROBE_RTL8363SC_VB))
+static rtk_switch_halCtrl_t rtl8363sc_vb_hal_Ctrl =
+{
+    /* Switch Chip */
+    CHIP_RTL8363SC_VB,
+
+    /* Logical to Physical */
+    {0xFF, 0xFF, 1, 3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+     6, 7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+
+    /* Physical to Logical */
+    {UNDEFINE_PORT, UTP_PORT2, UNDEFINE_PORT, UTP_PORT3, UNDEFINE_PORT, UNDEFINE_PORT, EXT_PORT0, EXT_PORT1,
+     UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT,
+     UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT,
+     UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT},
+
+    /* Port Type */
+    {UNKNOWN_PORT, UNKNOWN_PORT, UTP_PORT, UTP_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT,
+     UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT,
+     EXT_PORT, EXT_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT,
+     UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT},
+
+    /* PTP port */
+    {0, 0, 0, 0, 0, 0, 0, 0,
+     0, 0, 0, 0, 0, 0, 0, 0,
+     0, 0, 0, 0, 0, 0, 0, 0,
+     0, 0, 0, 0, 0, 0, 0, 0 },
+
+    /* Valid port mask */
+    ( (0x1 << UTP_PORT2) | (0x1 << UTP_PORT3) | (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ),
+
+    /* Valid UTP port mask */
+    ( (0x1 << UTP_PORT2) | (0x1 << UTP_PORT3) ),
+
+    /* Valid EXT port mask */
+    ( (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ),
+
+    /* Valid CPU port mask */
+    0x00,
+
+    /* Minimum physical port number */
+    0,
+
+    /* Maxmum physical port number */
+    7,
+
+    /* Physical port mask */
+    0xCA,
+
+    /* Combo Logical port ID */
+    4,
+
+    /* HSG Logical port ID */
+    EXT_PORT0,
+
+    /* SGMII Logical portmask */
+    ( (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ),
+
+    /* Max Meter ID */
+    32,
+
+    /* MAX LUT Address Number */
+    2112,
+
+    /* Trunk Group Mask */
+    0x01
+};
+#endif
+
+#if defined(FORCE_PROBE_RTL8367C)
+static rtk_switch_halCtrl_t *halCtrl = &rtl8367c_hal_Ctrl;
+#elif defined(FORCE_PROBE_RTL8370B)
+static rtk_switch_halCtrl_t *halCtrl = &rtl8370b_hal_Ctrl;
+#elif defined(FORCE_PROBE_RTL8364B)
+static rtk_switch_halCtrl_t *halCtrl = &rtl8364b_hal_Ctrl;
+#elif defined(FORCE_PROBE_RTL8363SC_VB)
+static rtk_switch_halCtrl_t *halCtrl = &rtl8363sc_vb_hal_Ctrl;
+#else
+static rtk_switch_halCtrl_t *halCtrl = NULL;
+#endif
+
+static rtk_uint32 PatchChipData[210][2] =
+{
+        {0xa436, 0x8028}, {0xa438, 0x6800}, {0xb82e, 0x0001}, {0xa436, 0xb820}, {0xa438, 0x0090}, {0xa436, 0xa012}, {0xa438, 0x0000}, {0xa436, 0xa014}, {0xa438, 0x2c04}, {0xa438, 0x2c6c},
+        {0xa438, 0x2c75}, {0xa438, 0x2c77}, {0xa438, 0x1414}, {0xa438, 0x1579}, {0xa438, 0x1536}, {0xa438, 0xc432}, {0xa438, 0x32c0}, {0xa438, 0x42d6}, {0xa438, 0x32b5}, {0xa438, 0x003e},
+        {0xa438, 0x614c}, {0xa438, 0x1569}, {0xa438, 0xd705}, {0xa438, 0x318c}, {0xa438, 0x42d6}, {0xa438, 0xd702}, {0xa438, 0x31ef}, {0xa438, 0x42d6}, {0xa438, 0x629c}, {0xa438, 0x2c04},
+        {0xa438, 0x653c}, {0xa438, 0x422a}, {0xa438, 0x5d83}, {0xa438, 0xd06a}, {0xa438, 0xd1b0}, {0xa438, 0x1536}, {0xa438, 0xc43a}, {0xa438, 0x32c0}, {0xa438, 0x42d6}, {0xa438, 0x32b5},
+        {0xa438, 0x003e}, {0xa438, 0x314a}, {0xa438, 0x42fe}, {0xa438, 0x337b}, {0xa438, 0x02d6}, {0xa438, 0x3063}, {0xa438, 0x0c1b}, {0xa438, 0x22fe}, {0xa438, 0xc435}, {0xa438, 0xd0be},
+        {0xa438, 0xd1f7}, {0xa438, 0xe0f0}, {0xa438, 0x1a40}, {0xa438, 0xa320}, {0xa438, 0xd702}, {0xa438, 0x154a}, {0xa438, 0xc434}, {0xa438, 0x32c0}, {0xa438, 0x42d6}, {0xa438, 0x32b5},
+        {0xa438, 0x003e}, {0xa438, 0x60ec}, {0xa438, 0x1569}, {0xa438, 0xd705}, {0xa438, 0x619f}, {0xa438, 0xd702}, {0xa438, 0x414f}, {0xa438, 0x2c2e}, {0xa438, 0x610a}, {0xa438, 0xd705},
+        {0xa438, 0x5e1f}, {0xa438, 0xc43f}, {0xa438, 0xc88b}, {0xa438, 0xd702}, {0xa438, 0x7fe0}, {0xa438, 0x22f3}, {0xa438, 0xd0a0}, {0xa438, 0xd1b2}, {0xa438, 0xd0c3}, {0xa438, 0xd1c3},
+        {0xa438, 0x8d01}, {0xa438, 0x1536}, {0xa438, 0xc438}, {0xa438, 0xe0f0}, {0xa438, 0x1a80}, {0xa438, 0xd706}, {0xa438, 0x60c0}, {0xa438, 0xd710}, {0xa438, 0x409e}, {0xa438, 0xa804},
+        {0xa438, 0xad01}, {0xa438, 0x8804}, {0xa438, 0xd702}, {0xa438, 0x32c0}, {0xa438, 0x42d6}, {0xa438, 0x32b5}, {0xa438, 0x003e}, {0xa438, 0x405b}, {0xa438, 0x1576}, {0xa438, 0x7c9c},
+        {0xa438, 0x60ec}, {0xa438, 0x1569}, {0xa438, 0xd702}, {0xa438, 0x5d43}, {0xa438, 0x31ef}, {0xa438, 0x02fe}, {0xa438, 0x22d6}, {0xa438, 0x590a}, {0xa438, 0xd706}, {0xa438, 0x5c80},
+        {0xa438, 0xd702}, {0xa438, 0x5c44}, {0xa438, 0x3063}, {0xa438, 0x02d6}, {0xa438, 0x5be2}, {0xa438, 0x22fb}, {0xa438, 0xa240}, {0xa438, 0xa104}, {0xa438, 0x8c03}, {0xa438, 0x8178},
+        {0xa438, 0xd701}, {0xa438, 0x31ad}, {0xa438, 0x4917}, {0xa438, 0x8102}, {0xa438, 0x2917}, {0xa438, 0xc302}, {0xa438, 0x268a}, {0xa436, 0xA01A}, {0xa438, 0x0000}, {0xa436, 0xA006},
+        {0xa438, 0x0fff}, {0xa436, 0xA004}, {0xa438, 0x0689}, {0xa436, 0xA002}, {0xa438, 0x0911}, {0xa436, 0xA000}, {0xa438, 0x7302}, {0xa436, 0xB820}, {0xa438, 0x0010}, {0xa436, 0x8412},
+        {0xa438, 0xaf84}, {0xa438, 0x1eaf}, {0xa438, 0x8427}, {0xa438, 0xaf84}, {0xa438, 0x27af}, {0xa438, 0x8427}, {0xa438, 0x0251}, {0xa438, 0x6802}, {0xa438, 0x8427}, {0xa438, 0xaf04},
+        {0xa438, 0x0af8}, {0xa438, 0xf9bf}, {0xa438, 0x5581}, {0xa438, 0x0255}, {0xa438, 0x27ef}, {0xa438, 0x310d}, {0xa438, 0x345b}, {0xa438, 0x0fa3}, {0xa438, 0x032a}, {0xa438, 0xe087},
+        {0xa438, 0xffac}, {0xa438, 0x2040}, {0xa438, 0xbf56}, {0xa438, 0x7402}, {0xa438, 0x5527}, {0xa438, 0xef31}, {0xa438, 0xef20}, {0xa438, 0xe787}, {0xa438, 0xfee6}, {0xa438, 0x87fd},
+        {0xa438, 0xd488}, {0xa438, 0x88bf}, {0xa438, 0x5674}, {0xa438, 0x0254}, {0xa438, 0xe3e0}, {0xa438, 0x87ff}, {0xa438, 0xf720}, {0xa438, 0xe487}, {0xa438, 0xffaf}, {0xa438, 0x847e},
+        {0xa438, 0xe087}, {0xa438, 0xffad}, {0xa438, 0x2016}, {0xa438, 0xe387}, {0xa438, 0xfee2}, {0xa438, 0x87fd}, {0xa438, 0xef45}, {0xa438, 0xbf56}, {0xa438, 0x7402}, {0xa438, 0x54e3},
+        {0xa438, 0xe087}, {0xa438, 0xfff6}, {0xa438, 0x20e4}, {0xa438, 0x87ff}, {0xa438, 0xfdfc}, {0xa438, 0x0400}, {0xa436, 0xb818}, {0xa438, 0x0407}, {0xa436, 0xb81a}, {0xa438, 0xfffd},
+        {0xa436, 0xb81c}, {0xa438, 0xfffd}, {0xa436, 0xb81e}, {0xa438, 0xfffd}, {0xa436, 0xb832}, {0xa438, 0x0001}, {0xb820, 0x0000}, {0xb82e, 0x0000}, {0xa436, 0x8028}, {0xa438, 0x0000}
+};
+
+static rtk_api_ret_t _rtk_switch_init_8367c(void)
+{
+    rtk_port_t port;
+    rtk_uint32 retVal;
+    rtk_uint32 regData;
+    rtk_uint32 regValue;
+
+    if( (retVal = rtl8367c_setAsicReg(0x13c2, 0x0249)) != RT_ERR_OK)
+        return retVal;
+
+    if( (retVal = rtl8367c_getAsicReg(0x1301, &regValue)) != RT_ERR_OK)
+        return retVal;
+
+    if( (retVal = rtl8367c_setAsicReg(0x13c2, 0x0000)) != RT_ERR_OK)
+        return retVal;
+
+    RTK_SCAN_ALL_LOG_PORT(port)
+    {
+         if(rtk_switch_isUtpPort(port) == RT_ERR_OK)
+         {
+             if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_PORT0_EEECFG + (0x20 * port), RTL8367C_PORT0_EEECFG_EEE_100M_OFFSET, 1)) != RT_ERR_OK)
+                 return retVal;
+
+             if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_PORT0_EEECFG + (0x20 * port), RTL8367C_PORT0_EEECFG_EEE_GIGA_500M_OFFSET, 1)) != RT_ERR_OK)
+                 return retVal;
+
+             if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_PORT0_EEECFG + (0x20 * port), RTL8367C_PORT0_EEECFG_EEE_TX_OFFSET, 1)) != RT_ERR_OK)
+                 return retVal;
+
+             if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_PORT0_EEECFG + (0x20 * port), RTL8367C_PORT0_EEECFG_EEE_RX_OFFSET, 1)) != RT_ERR_OK)
+                 return retVal;
+
+             if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xA428, &regData)) != RT_ERR_OK)
+                return retVal;
+
+             regData &= ~(0x0200);
+             if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA428, regData)) != RT_ERR_OK)
+                 return retVal;
+
+             if((regValue & 0x00F0) == 0x00A0)
+             {
+                 if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xA5D0, &regData)) != RT_ERR_OK)
+                     return retVal;
+
+                 regData |= 0x0006;
+                 if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA5D0, regData)) != RT_ERR_OK)
+                     return retVal;
+             }
+         }
+    }
+
+    if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_UTP_FIB_DET, 0x15BB)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x1303, 0x06D6)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x1304, 0x0700)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x13E2, 0x003F)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x13F9, 0x0090)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x121e, 0x03CA)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x1233, 0x0352)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x1237, 0x00a0)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x123a, 0x0030)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x1239, 0x0084)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x0301, 0x1000)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x1349, 0x001F)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicRegBit(0x18e0, 0, 0)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicRegBit(0x122b, 14, 1)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicRegBits(0x1305, 0xC000, 3)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+static rtk_api_ret_t _rtk_switch_init_8370b(void)
+{
+    ret_t retVal;
+    rtk_uint32 regData, tmp = 0;
+    rtk_uint32 i, prf, counter;
+    rtk_uint32 long_link[8] = {0x0210, 0x03e8, 0x0218, 0x03f0, 0x0220, 0x03f8, 0x0208, 0x03e0 };
+
+    if((retVal = rtl8367c_setAsicRegBits(0x1205, 0x0300, 3)) != RT_ERR_OK)
+        return retVal;
+
+
+    for(i=0; i<8; i++)
+    {
+      if ((retVal = rtl8367c_getAsicPHYOCPReg(i, 0xa420, &regData)) != RT_ERR_OK)
+          return retVal;
+        tmp = regData & 0x7 ;
+       if(tmp == 0x3)
+       {
+           prf = 1;
+           if((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xb83e, 0x6fa9)) != RT_ERR_OK)
+              return retVal;
+           if((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xb840, 0xa9)) != RT_ERR_OK)
+               return retVal;
+           for(counter = 0; counter < 10000; counter++); //delay
+
+           if ((retVal = rtl8367c_getAsicPHYOCPReg(i, 0xb820, &regData)) != RT_ERR_OK)
+               return retVal;
+           tmp = regData | 0x10;
+           if ((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xb820, tmp)) != RT_ERR_OK)
+               return retVal;
+           for(counter = 0; counter < 10000; counter++); //delay
+           counter = 0;
+           do{
+              counter = counter + 1;
+              if ((retVal = rtl8367c_getAsicPHYOCPReg(i, 0xb800, &regData)) != RT_ERR_OK)
+                   return retVal;
+              tmp = regData & 0x40;
+              if(tmp != 0)
+                break;
+           } while (counter < 20);   //Wait for patch ready = 1...
+       }
+   }
+    if ((retVal = rtl8367c_getAsicReg(0x1d01, &regData)) != RT_ERR_OK)
+        return retVal;
+    tmp = regData;
+    tmp = tmp | 0x3BE0; /*Broadcast port enable*/
+    tmp = tmp & 0xFFE0; /*Phy_id = 0 */
+    if((retVal = rtl8367c_setAsicReg(0x1d01, tmp)) != RT_ERR_OK)
+        return retVal;
+
+    for(i=0;i < 210; i++)
+    {
+        if((retVal = rtl8367c_setAsicPHYOCPReg(0, PatchChipData[i][0], PatchChipData[i][1])) != RT_ERR_OK)
+             return retVal;
+    }
+
+   if((retVal = rtl8367c_setAsicReg(0x1d01, regData)) != RT_ERR_OK)
+        return retVal;
+
+    for(i=0; i < 8; i++)
+    {
+        if((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xa4b4, long_link[i])) != RT_ERR_OK)
+             return retVal;
+    }
+
+  if (prf == 0x1)
+     {
+        for(i=0; i<8; i++)
+        {
+         if ((retVal = rtl8367c_getAsicPHYOCPReg(i, 0xb820, &regData)) != RT_ERR_OK)
+             return retVal;
+       tmp = regData & 0xFFEF;
+       if ((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xb820, tmp)) != RT_ERR_OK)
+             return retVal;
+
+       for(counter = 0; counter < 10000; counter++); //delay
+
+       counter = 0;
+       do{
+            counter = counter + 1;
+            if ((retVal = rtl8367c_getAsicPHYOCPReg(i, 0xb800, &regData)) != RT_ERR_OK)
+              return retVal;
+            tmp = regData & 0x40;
+            if( tmp == 0 )
+               break;
+       } while (counter < 20);   //Wait for patch ready = 1...
+      if ((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xb83e, 0x6f48)) != RT_ERR_OK)
+          return retVal;
+      if ((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xb840, 0xfa)) != RT_ERR_OK)
+          return retVal;
+          }
+   }
+
+    /*Check phy link status*/
+    for(i=0; i<8; i++)
+    {
+      if ((retVal = rtl8367c_getAsicPHYOCPReg(i, 0xa400, &regData)) != RT_ERR_OK)
+          return retVal;
+      tmp = regData & 0x800;
+        if(tmp == 0x0)
+            {
+              tmp = regData | 0x200;
+          if ((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xa400, tmp)) != RT_ERR_OK)
+             return retVal;
+            }
+    }
+
+  for(counter = 0; counter < 10000; counter++); //delay
+
+  return RT_ERR_OK;
+}
+
+static rtk_api_ret_t _rtk_switch_init_8364b(void)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+
+    /*enable EEE, include mac & phy*/
+
+    if ((retVal = rtl8367c_setAsicRegBits(0x38, 0x300, 3)) != RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtl8367c_setAsicRegBits(0x78, 0x300, 3)) != RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtl8367c_setAsicRegBits(0xd8, 0x300, 0)) != RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtl8367c_setAsicRegBits(0xf8, 0x300, 0)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicPHYOCPReg(1, 0xa5d0, 6)) != RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtl8367c_setAsicPHYOCPReg(3, 0xa5d0, 6)) != RT_ERR_OK)
+        return retVal;
+
+    /*PAD para*/
+
+    /*EXT1 PAD Para*/
+    if ((retVal = rtl8367c_getAsicReg(0x1303, &regData)) != RT_ERR_OK)
+        return retVal;
+    regData &= 0xFFFFFFFE;
+    regData |= 0x250;
+    if((retVal = rtl8367c_setAsicReg(0x1303, regData)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicRegBits(0x1304, 0x7000, 0)) != RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtl8367c_setAsicRegBits(0x1304, 0x700, 7)) != RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtl8367c_setAsicRegBits(0x13f9, 0x38, 0)) != RT_ERR_OK)
+        return retVal;
+
+    /*EXT2 PAD Para*/
+    if ((retVal = rtl8367c_setAsicRegBit(0x1303, 10, 1)) != RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtl8367c_setAsicRegBits(0x13E2, 0x1ff, 0x26)) != RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtl8367c_setAsicRegBits(0x13f9, 0x1c0, 0)) != RT_ERR_OK)
+        return retVal;
+
+
+    /*SDS PATCH*/
+    /*SP_CFG_EN_LINK_FIB1G*/
+    if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &regData)) != RT_ERR_OK)
+        return retVal;
+    regData |= 0x4;
+    if((retVal = rtl8367c_setAsicSdsReg(0,4,0, regData)) != RT_ERR_OK)
+        return retVal;
+
+    /*FIB100 Down-speed*/
+    if((retVal = rtl8367c_getAsicSdsReg(0, 1, 0, &regData)) != RT_ERR_OK)
+        return retVal;
+    regData |= 0x20;
+    if((retVal = rtl8367c_setAsicSdsReg(0,1,0, regData)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+static rtk_api_ret_t _rtk_switch_init_8363sc_vb(void)
+{
+
+    ret_t retVal;
+    rtk_uint32 regData;
+
+    /*enable EEE, include mac & phy*/
+
+    if ((retVal = rtl8367c_setAsicRegBits(0x38, 0x300, 3)) != RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtl8367c_setAsicRegBits(0x78, 0x300, 3)) != RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtl8367c_setAsicRegBits(0xd8, 0x300, 0)) != RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtl8367c_setAsicRegBits(0xf8, 0x300, 0)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicPHYOCPReg(1, 0xa5d0, 6)) != RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtl8367c_setAsicPHYOCPReg(3, 0xa5d0, 6)) != RT_ERR_OK)
+        return retVal;
+
+    /*PAD para*/
+
+    /*EXT1 PAD Para*/
+    if ((retVal = rtl8367c_getAsicReg(0x1303, &regData)) != RT_ERR_OK)
+        return retVal;
+    regData &= 0xFFFFFFFE;
+    regData |= 0x250;
+    if((retVal = rtl8367c_setAsicReg(0x1303, regData)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicRegBits(0x1304, 0x7000, 0)) != RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtl8367c_setAsicRegBits(0x1304, 0x700, 7)) != RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtl8367c_setAsicRegBits(0x13f9, 0x38, 0)) != RT_ERR_OK)
+        return retVal;
+
+    /*EXT2 PAD Para*/
+    if ((retVal = rtl8367c_setAsicRegBit(0x1303, 10, 1)) != RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtl8367c_setAsicRegBits(0x13E2, 0x1ff, 0x26)) != RT_ERR_OK)
+        return retVal;
+    if ((retVal = rtl8367c_setAsicRegBits(0x13f9, 0x1c0, 0)) != RT_ERR_OK)
+        return retVal;
+
+
+    /*SDS PATCH*/
+    /*SP_CFG_EN_LINK_FIB1G*/
+    if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &regData)) != RT_ERR_OK)
+        return retVal;
+    regData |= 0x4;
+    if((retVal = rtl8367c_setAsicSdsReg(0,4,0, regData)) != RT_ERR_OK)
+        return retVal;
+
+    /*FIB100 Down-speed*/
+    if((retVal = rtl8367c_getAsicSdsReg(0, 1, 0, &regData)) != RT_ERR_OK)
+        return retVal;
+    regData |= 0x20;
+    if((retVal = rtl8367c_setAsicSdsReg(0,1,0, regData)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_switch_probe
+ * Description:
+ *      Probe switch
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Switch probed
+ *      RT_ERR_FAILED   - Switch Unprobed.
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_switch_probe(switch_chip_t *pSwitchChip)
+{
+#if defined(FORCE_PROBE_RTL8367C)
+
+    *pSwitchChip = CHIP_RTL8367C;
+    halCtrl = &rtl8367c_hal_Ctrl;
+
+#elif defined(FORCE_PROBE_RTL8370B)
+
+    *pSwitchChip = CHIP_RTL8370B;
+    halCtrl = &rtl8370b_hal_Ctrl;
+
+#elif defined(FORCE_PROBE_RTL8364B)
+
+    *pSwitchChip = CHIP_RTL8364B;
+    halCtrl = &rtl8364b_hal_Ctrl;
+
+#elif defined(FORCE_PROBE_RTL8363SC_VB)
+
+    *pSwitchChip = CHIP_RTL8363SC_VB;
+    halCtrl = &rtl8363sc_vb_hal_Ctrl;
+
+#else
+    rtk_uint32 retVal;
+    rtk_uint32 data, regValue;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_getAsicReg(0x1300, &data)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_getAsicReg(0x1301, &regValue)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK)
+        return retVal;
+
+    switch (data)
+    {
+        case 0x0276:
+        case 0x0597:
+        case 0x6367:
+            *pSwitchChip = CHIP_RTL8367C;
+            halCtrl = &rtl8367c_hal_Ctrl;
+            break;
+        case 0x0652:
+        case 0x6368:
+            *pSwitchChip = CHIP_RTL8370B;
+            halCtrl = &rtl8370b_hal_Ctrl;
+            break;
+        case 0x0801:
+        case 0x6511:
+            if( (regValue & 0x00F0) == 0x0080)
+            {
+                *pSwitchChip = CHIP_RTL8363SC_VB;
+                halCtrl = &rtl8363sc_vb_hal_Ctrl;
+            }
+            else
+            {
+                *pSwitchChip = CHIP_RTL8364B;
+                halCtrl = &rtl8364b_hal_Ctrl;
+            }
+            break;
+        default:
+            return RT_ERR_FAILED;
+    }
+#endif
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_switch_initialState_set
+ * Description:
+ *      Set initial status
+ * Input:
+ *      state   - Initial state;
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Initialized
+ *      RT_ERR_FAILED   - Uninitialized
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_switch_initialState_set(init_state_t state)
+{
+    if(state >= INIT_STATE_END)
+        return RT_ERR_FAILED;
+
+    init_state = state;
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_switch_initialState_get
+ * Description:
+ *      Get initial status
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      INIT_COMPLETED     - Initialized
+ *      INIT_NOT_COMPLETED - Uninitialized
+ * Note:
+ *
+ */
+init_state_t rtk_switch_initialState_get(void)
+{
+    return init_state;
+}
+
+/* Function Name:
+ *      rtk_switch_logicalPortCheck
+ * Description:
+ *      Check logical port ID.
+ * Input:
+ *      logicalPort     - logical port ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Port ID is correct
+ *      RT_ERR_FAILED   - Port ID is not correct
+ *      RT_ERR_NOT_INIT - Not Initialize
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_switch_logicalPortCheck(rtk_port_t logicalPort)
+{
+    if(init_state != INIT_COMPLETED)
+        return RT_ERR_NOT_INIT;
+
+    if(logicalPort >= RTK_SWITCH_PORT_NUM)
+        return RT_ERR_FAILED;
+
+    if(halCtrl->l2p_port[logicalPort] == 0xFF)
+        return RT_ERR_FAILED;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_switch_isUtpPort
+ * Description:
+ *      Check is logical port a UTP port
+ * Input:
+ *      logicalPort     - logical port ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Port ID is a UTP port
+ *      RT_ERR_FAILED   - Port ID is not a UTP port
+ *      RT_ERR_NOT_INIT - Not Initialize
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_switch_isUtpPort(rtk_port_t logicalPort)
+{
+    if(init_state != INIT_COMPLETED)
+        return RT_ERR_NOT_INIT;
+
+    if(logicalPort >= RTK_SWITCH_PORT_NUM)
+        return RT_ERR_FAILED;
+
+    if(halCtrl->log_port_type[logicalPort] == UTP_PORT)
+        return RT_ERR_OK;
+    else
+        return RT_ERR_FAILED;
+}
+
+/* Function Name:
+ *      rtk_switch_isExtPort
+ * Description:
+ *      Check is logical port a Extension port
+ * Input:
+ *      logicalPort     - logical port ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Port ID is a EXT port
+ *      RT_ERR_FAILED   - Port ID is not a EXT port
+ *      RT_ERR_NOT_INIT - Not Initialize
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_switch_isExtPort(rtk_port_t logicalPort)
+{
+    if(init_state != INIT_COMPLETED)
+        return RT_ERR_NOT_INIT;
+
+    if(logicalPort >= RTK_SWITCH_PORT_NUM)
+        return RT_ERR_FAILED;
+
+    if(halCtrl->log_port_type[logicalPort] == EXT_PORT)
+        return RT_ERR_OK;
+    else
+        return RT_ERR_FAILED;
+}
+
+
+/* Function Name:
+ *      rtk_switch_isHsgPort
+ * Description:
+ *      Check is logical port a HSG port
+ * Input:
+ *      logicalPort     - logical port ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Port ID is a HSG port
+ *      RT_ERR_FAILED   - Port ID is not a HSG port
+ *      RT_ERR_NOT_INIT - Not Initialize
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_switch_isHsgPort(rtk_port_t logicalPort)
+{
+    if(init_state != INIT_COMPLETED)
+        return RT_ERR_NOT_INIT;
+
+    if(logicalPort >= RTK_SWITCH_PORT_NUM)
+        return RT_ERR_FAILED;
+
+    if(logicalPort == halCtrl->hsg_logical_port)
+        return RT_ERR_OK;
+    else
+        return RT_ERR_FAILED;
+}
+
+/* Function Name:
+ *      rtk_switch_isSgmiiPort
+ * Description:
+ *      Check is logical port a SGMII port
+ * Input:
+ *      logicalPort     - logical port ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Port ID is a SGMII port
+ *      RT_ERR_FAILED   - Port ID is not a SGMII port
+ *      RT_ERR_NOT_INIT - Not Initialize
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_switch_isSgmiiPort(rtk_port_t logicalPort)
+{
+    if(init_state != INIT_COMPLETED)
+        return RT_ERR_NOT_INIT;
+
+    if(logicalPort >= RTK_SWITCH_PORT_NUM)
+        return RT_ERR_FAILED;
+
+    if( ((0x01 << logicalPort) & halCtrl->sg_logical_portmask) != 0)
+        return RT_ERR_OK;
+    else
+        return RT_ERR_FAILED;
+}
+
+/* Function Name:
+ *      rtk_switch_isCPUPort
+ * Description:
+ *      Check is logical port a CPU port
+ * Input:
+ *      logicalPort     - logical port ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Port ID is a CPU port
+ *      RT_ERR_FAILED   - Port ID is not a CPU port
+ *      RT_ERR_NOT_INIT - Not Initialize
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_switch_isCPUPort(rtk_port_t logicalPort)
+{
+    if(init_state != INIT_COMPLETED)
+        return RT_ERR_NOT_INIT;
+
+    if(logicalPort >= RTK_SWITCH_PORT_NUM)
+        return RT_ERR_FAILED;
+
+    if( ((0x01 << logicalPort) & halCtrl->valid_cpu_portmask) != 0)
+        return RT_ERR_OK;
+    else
+        return RT_ERR_FAILED;
+}
+
+/* Function Name:
+ *      rtk_switch_isComboPort
+ * Description:
+ *      Check is logical port a Combo port
+ * Input:
+ *      logicalPort     - logical port ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Port ID is a combo port
+ *      RT_ERR_FAILED   - Port ID is not a combo port
+ *      RT_ERR_NOT_INIT - Not Initialize
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_switch_isComboPort(rtk_port_t logicalPort)
+{
+    if(init_state != INIT_COMPLETED)
+        return RT_ERR_NOT_INIT;
+
+    if(logicalPort >= RTK_SWITCH_PORT_NUM)
+        return RT_ERR_FAILED;
+
+    if(halCtrl->combo_logical_port == logicalPort)
+        return RT_ERR_OK;
+    else
+        return RT_ERR_FAILED;
+}
+
+/* Function Name:
+ *      rtk_switch_ComboPort_get
+ * Description:
+ *      Get Combo port ID
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      Port ID of combo port
+ * Note:
+ *
+ */
+rtk_uint32 rtk_switch_ComboPort_get(void)
+{
+    return halCtrl->combo_logical_port;
+}
+
+/* Function Name:
+ *      rtk_switch_isPtpPort
+ * Description:
+ *      Check is logical port a PTP port
+ * Input:
+ *      logicalPort     - logical port ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Port ID is a PTP port
+ *      RT_ERR_FAILED   - Port ID is not a PTP port
+ *      RT_ERR_NOT_INIT - Not Initialize
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_switch_isPtpPort(rtk_port_t logicalPort)
+{
+    if(init_state != INIT_COMPLETED)
+        return RT_ERR_NOT_INIT;
+
+    if(logicalPort >= RTK_SWITCH_PORT_NUM)
+        return RT_ERR_FAILED;
+
+    if(halCtrl->ptp_port[logicalPort] == 1)
+        return RT_ERR_OK;
+    else
+        return RT_ERR_FAILED;
+}
+
+/* Function Name:
+ *      rtk_switch_port_L2P_get
+ * Description:
+ *      Get physical port ID
+ * Input:
+ *      logicalPort       - logical port ID
+ * Output:
+ *      None
+ * Return:
+ *      Physical port ID
+ * Note:
+ *
+ */
+rtk_uint32 rtk_switch_port_L2P_get(rtk_port_t logicalPort)
+{
+    if(init_state != INIT_COMPLETED)
+        return UNDEFINE_PHY_PORT;
+
+    if(logicalPort >= RTK_SWITCH_PORT_NUM)
+        return UNDEFINE_PHY_PORT;
+
+    return (halCtrl->l2p_port[logicalPort]);
+}
+
+/* Function Name:
+ *      rtk_switch_port_P2L_get
+ * Description:
+ *      Get logical port ID
+ * Input:
+ *      physicalPort       - physical port ID
+ * Output:
+ *      None
+ * Return:
+ *      logical port ID
+ * Note:
+ *
+ */
+rtk_port_t rtk_switch_port_P2L_get(rtk_uint32 physicalPort)
+{
+    if(init_state != INIT_COMPLETED)
+        return UNDEFINE_PORT;
+
+    if(physicalPort >= RTK_SWITCH_PORT_NUM)
+        return UNDEFINE_PORT;
+
+    return (halCtrl->p2l_port[physicalPort]);
+}
+
+/* Function Name:
+ *      rtk_switch_isPortMaskValid
+ * Description:
+ *      Check portmask is valid or not
+ * Input:
+ *      pPmask       - logical port mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - port mask is valid
+ *      RT_ERR_FAILED       - port mask is not valid
+ *      RT_ERR_NOT_INIT     - Not Initialize
+ *      RT_ERR_NULL_POINTER - Null pointer
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_switch_isPortMaskValid(rtk_portmask_t *pPmask)
+{
+    if(init_state != INIT_COMPLETED)
+        return RT_ERR_NOT_INIT;
+
+    if(NULL == pPmask)
+        return RT_ERR_NULL_POINTER;
+
+    if( (pPmask->bits[0] | halCtrl->valid_portmask) != halCtrl->valid_portmask )
+        return RT_ERR_FAILED;
+    else
+        return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_switch_isPortMaskUtp
+ * Description:
+ *      Check all ports in portmask are only UTP port
+ * Input:
+ *      pPmask       - logical port mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Only UTP port in port mask
+ *      RT_ERR_FAILED       - Not only UTP port in port mask
+ *      RT_ERR_NOT_INIT     - Not Initialize
+ *      RT_ERR_NULL_POINTER - Null pointer
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_switch_isPortMaskUtp(rtk_portmask_t *pPmask)
+{
+    if(init_state != INIT_COMPLETED)
+        return RT_ERR_NOT_INIT;
+
+    if(NULL == pPmask)
+        return RT_ERR_NULL_POINTER;
+
+    if( (pPmask->bits[0] | halCtrl->valid_utp_portmask) != halCtrl->valid_utp_portmask )
+        return RT_ERR_FAILED;
+    else
+        return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_switch_isPortMaskExt
+ * Description:
+ *      Check all ports in portmask are only EXT port
+ * Input:
+ *      pPmask       - logical port mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Only EXT port in port mask
+ *      RT_ERR_FAILED       - Not only EXT port in port mask
+ *      RT_ERR_NOT_INIT     - Not Initialize
+ *      RT_ERR_NULL_POINTER - Null pointer
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_switch_isPortMaskExt(rtk_portmask_t *pPmask)
+{
+    if(init_state != INIT_COMPLETED)
+        return RT_ERR_NOT_INIT;
+
+    if(NULL == pPmask)
+        return RT_ERR_NULL_POINTER;
+
+    if( (pPmask->bits[0] | halCtrl->valid_ext_portmask) != halCtrl->valid_ext_portmask )
+        return RT_ERR_FAILED;
+    else
+        return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_switch_portmask_L2P_get
+ * Description:
+ *      Get physicl portmask from logical portmask
+ * Input:
+ *      pLogicalPmask       - logical port mask
+ * Output:
+ *      pPhysicalPortmask   - physical port mask
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_NOT_INIT     - Not Initialize
+ *      RT_ERR_NULL_POINTER - Null pointer
+ *      RT_ERR_PORT_MASK    - Error port mask
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_switch_portmask_L2P_get(rtk_portmask_t *pLogicalPmask, rtk_uint32 *pPhysicalPortmask)
+{
+    rtk_uint32 log_port, phy_port;
+
+    if(init_state != INIT_COMPLETED)
+        return RT_ERR_NOT_INIT;
+
+    if(NULL == pLogicalPmask)
+        return RT_ERR_NULL_POINTER;
+
+    if(NULL == pPhysicalPortmask)
+        return RT_ERR_NULL_POINTER;
+
+    if(rtk_switch_isPortMaskValid(pLogicalPmask) != RT_ERR_OK)
+        return RT_ERR_PORT_MASK;
+
+    /* reset physical port mask */
+    *pPhysicalPortmask = 0;
+
+    RTK_PORTMASK_SCAN((*pLogicalPmask), log_port)
+    {
+        phy_port = rtk_switch_port_L2P_get((rtk_port_t)log_port);
+        *pPhysicalPortmask |= (0x0001 << phy_port);
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_switch_portmask_P2L_get
+ * Description:
+ *      Get logical portmask from physical portmask
+ * Input:
+ *      physicalPortmask    - physical port mask
+ * Output:
+ *      pLogicalPmask       - logical port mask
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_NOT_INIT     - Not Initialize
+ *      RT_ERR_NULL_POINTER - Null pointer
+ *      RT_ERR_PORT_MASK    - Error port mask
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_switch_portmask_P2L_get(rtk_uint32 physicalPortmask, rtk_portmask_t *pLogicalPmask)
+{
+    rtk_uint32 log_port, phy_port;
+
+    if(init_state != INIT_COMPLETED)
+        return RT_ERR_NOT_INIT;
+
+    if(NULL == pLogicalPmask)
+        return RT_ERR_NULL_POINTER;
+
+    RTK_PORTMASK_CLEAR(*pLogicalPmask);
+
+    for(phy_port = halCtrl->min_phy_port; phy_port <= halCtrl->max_phy_port; phy_port++)
+    {
+        if(physicalPortmask & (0x0001 << phy_port))
+        {
+            log_port = rtk_switch_port_P2L_get(phy_port);
+            if(log_port != UNDEFINE_PORT)
+            {
+                RTK_PORTMASK_PORT_SET(*pLogicalPmask, log_port);
+            }
+        }
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_switch_phyPortMask_get
+ * Description:
+ *      Get physical portmask
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      0x00                - Not Initialize
+ *      Other value         - Physical port mask
+ * Note:
+ *
+ */
+rtk_uint32 rtk_switch_phyPortMask_get(void)
+{
+    if(init_state != INIT_COMPLETED)
+        return 0x00; /* No port in portmask */
+
+    return (halCtrl->phy_portmask);
+}
+
+/* Function Name:
+ *      rtk_switch_logPortMask_get
+ * Description:
+ *      Get Logical portmask
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_NOT_INIT     - Not Initialize
+ *      RT_ERR_NULL_POINTER - Null pointer
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_switch_logPortMask_get(rtk_portmask_t *pPortmask)
+{
+    if(init_state != INIT_COMPLETED)
+        return RT_ERR_FAILED;
+
+    if(NULL == pPortmask)
+        return RT_ERR_NULL_POINTER;
+
+    pPortmask->bits[0] = halCtrl->valid_portmask;
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_switch_init
+ * Description:
+ *      Set chip to default configuration enviroment
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      The API can set chip registers to default configuration for different release chip model.
+ */
+rtk_api_ret_t rtk_switch_init(void)
+{
+    rtk_uint32  retVal;
+    rtl8367c_rma_t rmaCfg;
+    switch_chip_t   switchChip;
+
+    /* probe switch */
+    if((retVal = rtk_switch_probe(&switchChip)) != RT_ERR_OK)
+        return retVal;
+
+    /* Set initial state */
+
+    if((retVal = rtk_switch_initialState_set(INIT_COMPLETED)) != RT_ERR_OK)
+        return retVal;
+
+    /* Initial */
+    switch(switchChip)
+    {
+        case CHIP_RTL8367C:
+            if((retVal = _rtk_switch_init_8367c()) != RT_ERR_OK)
+                return retVal;
+            break;
+        case CHIP_RTL8370B:
+            if((retVal = _rtk_switch_init_8370b()) != RT_ERR_OK)
+                return retVal;
+            break;
+        case CHIP_RTL8364B:
+            if((retVal = _rtk_switch_init_8364b()) != RT_ERR_OK)
+                return retVal;
+            break;
+        case CHIP_RTL8363SC_VB:
+            if((retVal = _rtk_switch_init_8363sc_vb()) != RT_ERR_OK)
+                return retVal;
+            break;
+        default:
+            return RT_ERR_CHIP_NOT_FOUND;
+    }
+
+    /* Set Old max packet length to 16K */
+    if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_MAX_LENGTH_LIMINT_IPG, RTL8367C_MAX_LENTH_CTRL_MASK, 3)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_MAX_LEN_RX_TX, RTL8367C_MAX_LEN_RX_TX_MASK, 3)) != RT_ERR_OK)
+        return retVal;
+
+    /* ACL Mode */
+    if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_ACL_ACCESS_MODE, RTL8367C_ACL_ACCESS_MODE_MASK, 1)) != RT_ERR_OK)
+        return retVal;
+
+    /* Max rate */
+    if((retVal = rtk_rate_igrBandwidthCtrlRate_set(halCtrl->hsg_logical_port, RTL8367C_QOS_RATE_INPUT_MAX_HSG, DISABLED, ENABLED)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtk_rate_egrBandwidthCtrlRate_set(halCtrl->hsg_logical_port, RTL8367C_QOS_RATE_INPUT_MAX_HSG, ENABLED)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x03fa, 0x0007)) != RT_ERR_OK)
+        return retVal;
+
+    /* Change unknown DA to per port setting */
+    if((retVal = rtl8367c_setAsicRegBits(RTL8367C_PORT_SECURIT_CTRL_REG, RTL8367C_UNKNOWN_UNICAST_DA_BEHAVE_MASK, 3)) != RT_ERR_OK)
+        return retVal;
+
+    /* LUT lookup OP = 1 */
+    if ((retVal = rtl8367c_setAsicLutIpLookupMethod(1))!=RT_ERR_OK)
+        return retVal;
+
+    /* Set RMA */
+    rmaCfg.portiso_leaky = 0;
+    rmaCfg.vlan_leaky = 0;
+    rmaCfg.keep_format = 0;
+    rmaCfg.trap_priority = 0;
+    rmaCfg.discard_storm_filter = 0;
+    rmaCfg.operation = 0;
+    if ((retVal = rtl8367c_setAsicRma(2, &rmaCfg))!=RT_ERR_OK)
+        return retVal;
+
+    /* Enable TX Mirror isolation leaky */
+    if ((retVal = rtl8367c_setAsicPortMirrorIsolationTxLeaky(ENABLED)) != RT_ERR_OK)
+        return retVal;
+
+    /* INT EN */
+    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IO_MISC_FUNC, RTL8367C_INT_EN_OFFSET, 1)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_switch_portMaxPktLen_set
+ * Description:
+ *      Set Max packet length
+ * Input:
+ *      port    - Port ID
+ *      speed   - Speed
+ *      cfgId   - Configuration ID
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Error Input
+ * Note:
+ */
+rtk_api_ret_t rtk_switch_portMaxPktLen_set(rtk_port_t port, rtk_switch_maxPktLen_linkSpeed_t speed, rtk_uint32 cfgId)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(speed >= MAXPKTLEN_LINK_SPEED_END)
+        return RT_ERR_INPUT;
+
+    if(cfgId > MAXPKTLEN_CFG_ID_MAX)
+        return RT_ERR_INPUT;
+
+    if((retVal = rtl8367c_setAsicMaxLength(rtk_switch_port_L2P_get(port), (rtk_uint32)speed, cfgId)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_switch_portMaxPktLen_get
+ * Description:
+ *      Get Max packet length
+ * Input:
+ *      port    - Port ID
+ *      speed   - Speed
+ * Output:
+ *      pCfgId  - Configuration ID
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Error Input
+ * Note:
+ */
+rtk_api_ret_t rtk_switch_portMaxPktLen_get(rtk_port_t port, rtk_switch_maxPktLen_linkSpeed_t speed, rtk_uint32 *pCfgId)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(speed >= MAXPKTLEN_LINK_SPEED_END)
+        return RT_ERR_INPUT;
+
+    if(NULL == pCfgId)
+        return RT_ERR_NULL_POINTER;
+
+    if((retVal = rtl8367c_getAsicMaxLength(rtk_switch_port_L2P_get(port), (rtk_uint32)speed, pCfgId)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_switch_maxPktLenCfg_set
+ * Description:
+ *      Set Max packet length configuration
+ * Input:
+ *      cfgId   - Configuration ID
+ *      pktLen  - Max packet length
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Error Input
+ * Note:
+ */
+rtk_api_ret_t rtk_switch_maxPktLenCfg_set(rtk_uint32 cfgId, rtk_uint32 pktLen)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(cfgId > MAXPKTLEN_CFG_ID_MAX)
+        return RT_ERR_INPUT;
+
+    if(pktLen > RTK_SWITCH_MAX_PKTLEN)
+        return RT_ERR_INPUT;
+
+    if((retVal = rtl8367c_setAsicMaxLengthCfg(cfgId, pktLen)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_switch_maxPktLenCfg_get
+ * Description:
+ *      Get Max packet length configuration
+ * Input:
+ *      cfgId   - Configuration ID
+ *      pPktLen - Max packet length
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Error Input
+ * Note:
+ */
+rtk_api_ret_t rtk_switch_maxPktLenCfg_get(rtk_uint32 cfgId, rtk_uint32 *pPktLen)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(cfgId > MAXPKTLEN_CFG_ID_MAX)
+        return RT_ERR_INPUT;
+
+    if(NULL == pPktLen)
+        return RT_ERR_NULL_POINTER;
+
+    if((retVal = rtl8367c_getAsicMaxLengthCfg(cfgId, pPktLen)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_switch_greenEthernet_set
+ * Description:
+ *      Set all Ports Green Ethernet state.
+ * Input:
+ *      enable - Green Ethernet state.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - OK
+ *      RT_ERR_FAILED   - Failed
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_ENABLE   - Invalid enable input.
+ * Note:
+ *      This API can set all Ports Green Ethernet state.
+ *      The configuration is as following:
+ *      - DISABLE
+ *      - ENABLE
+ */
+rtk_api_ret_t rtk_switch_greenEthernet_set(rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 port;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    RTK_SCAN_ALL_LOG_PORT(port)
+    {
+        if(rtk_switch_isUtpPort(port) == RT_ERR_OK)
+        {
+            if ((retVal = rtl8367c_setAsicPowerSaving(rtk_switch_port_L2P_get(port),enable))!=RT_ERR_OK)
+                return retVal;
+
+            if ((retVal = rtl8367c_setAsicGreenEthernet(rtk_switch_port_L2P_get(port), enable))!=RT_ERR_OK)
+                return retVal;
+        }
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_switch_greenEthernet_get
+ * Description:
+ *      Get all Ports Green Ethernet state.
+ * Input:
+ *      None
+ * Output:
+ *      pEnable - Green Ethernet state.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ * Note:
+ *      This API can get Green Ethernet state.
+ */
+rtk_api_ret_t rtk_switch_greenEthernet_get(rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 port;
+    rtk_uint32 state;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    RTK_SCAN_ALL_LOG_PORT(port)
+    {
+        if(rtk_switch_isUtpPort(port) == RT_ERR_OK)
+        {
+            if ((retVal = rtl8367c_getAsicPowerSaving(rtk_switch_port_L2P_get(port), &state))!=RT_ERR_OK)
+                return retVal;
+
+            if(state == DISABLED)
+            {
+                *pEnable = DISABLED;
+                return RT_ERR_OK;
+            }
+
+            if ((retVal = rtl8367c_getAsicGreenEthernet(rtk_switch_port_L2P_get(port), &state))!=RT_ERR_OK)
+                return retVal;
+
+            if(state == DISABLED)
+            {
+                *pEnable = DISABLED;
+                return RT_ERR_OK;
+            }
+        }
+    }
+
+    *pEnable = ENABLED;
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_switch_maxLogicalPort_get
+ * Description:
+ *      Get Max logical port ID
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      Max logical port
+ * Note:
+ *      This API can get max logical port
+ */
+rtk_port_t rtk_switch_maxLogicalPort_get(void)
+{
+    rtk_port_t port, maxLogicalPort = 0;
+
+    /* Check initialization state */
+    if(rtk_switch_initialState_get() != INIT_COMPLETED)
+    {
+        return UNDEFINE_PORT;
+    }
+
+    for(port = 0; port < RTK_SWITCH_PORT_NUM; port++)
+    {
+        if( (halCtrl->log_port_type[port] == UTP_PORT) || (halCtrl->log_port_type[port] == EXT_PORT) )
+            maxLogicalPort = port;
+    }
+
+    return maxLogicalPort;
+}
+
+/* Function Name:
+ *      rtk_switch_maxMeterId_get
+ * Description:
+ *      Get Max Meter ID
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      0x00                - Not Initialize
+ *      Other value         - Max Meter ID
+ * Note:
+ *
+ */
+rtk_uint32 rtk_switch_maxMeterId_get(void)
+{
+    if(init_state != INIT_COMPLETED)
+        return 0x00;
+
+    return (halCtrl->max_meter_id);
+}
+
+/* Function Name:
+ *      rtk_switch_maxLutAddrNumber_get
+ * Description:
+ *      Get Max LUT Address number
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      0x00                - Not Initialize
+ *      Other value         - Max LUT Address number
+ * Note:
+ *
+ */
+rtk_uint32 rtk_switch_maxLutAddrNumber_get(void)
+{
+    if(init_state != INIT_COMPLETED)
+        return 0x00;
+
+    return (halCtrl->max_lut_addr_num);
+}
+
+/* Function Name:
+ *      rtk_switch_isValidTrunkGrpId
+ * Description:
+ *      Check if trunk group is valid or not
+ * Input:
+ *      grpId       - Group ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Trunk Group ID is valid
+ *      RT_ERR_LA_TRUNK_ID  - Trunk Group ID is not valid
+ * Note:
+ *
+ */
+rtk_uint32 rtk_switch_isValidTrunkGrpId(rtk_uint32 grpId)
+{
+    if(init_state != INIT_COMPLETED)
+        return 0x00;
+
+    if( (halCtrl->trunk_group_mask & (0x01 << grpId) ) != 0)
+        return RT_ERR_OK;
+    else
+        return RT_ERR_LA_TRUNK_ID;
+
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv.c
new file mode 100644
index 0000000..7858edc
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv.c
@@ -0,0 +1,639 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature :
+ *
+ */
+
+#include <rtl8367c_asicdrv.h>
+
+#if defined(RTK_X86_ASICDRV)
+#include <I2Clib.h>
+#else
+#include <smi.h>
+#endif
+
+/*for driver verify testing only*/
+#ifdef CONFIG_RTL8367C_ASICDRV_TEST
+#define CLE_VIRTUAL_REG_SIZE        0x10000
+rtk_uint16 CleVirtualReg[CLE_VIRTUAL_REG_SIZE];
+#endif
+
+#if defined(CONFIG_RTL865X_CLE) || defined (RTK_X86_CLE)
+rtk_uint32 cleDebuggingDisplay;
+#endif
+
+#ifdef EMBEDDED_SUPPORT
+extern void setReg(rtk_uint16, rtk_uint16);
+extern rtk_uint16 getReg(rtk_uint16);
+#endif
+
+/* Function Name:
+ *      rtl8367c_setAsicRegBit
+ * Description:
+ *      Set a bit value of a specified register
+ * Input:
+ *      reg     - register's address
+ *      bit     - bit location
+ *      value   - value to set. It can be value 0 or 1.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_INPUT    - Invalid input parameter
+ * Note:
+ *      Set a bit of a specified register to 1 or 0.
+ */
+ret_t rtl8367c_setAsicRegBit(rtk_uint32 reg, rtk_uint32 bit, rtk_uint32 value)
+{
+
+#if defined(RTK_X86_ASICDRV)
+    rtk_uint32 regData;
+    ret_t retVal;
+
+    if(bit >= RTL8367C_REGBITLENGTH)
+        return RT_ERR_INPUT;
+
+    retVal = Access_Read(reg, 2, &regData);
+    if(TRUE != retVal)
+        return RT_ERR_SMI;
+
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData);
+
+    if(value)
+        regData = regData | (1 << bit);
+    else
+        regData = regData & (~(1 << bit));
+
+    retVal = Access_Write(reg,2, regData);
+    if(TRUE != retVal)
+        return RT_ERR_SMI;
+
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("W[0x%4.4x]=0x%4.4x\n", reg, regData);
+
+
+#elif defined(CONFIG_RTL8367C_ASICDRV_TEST)
+
+    if(bit >= RTL8367C_REGBITLENGTH)
+        return RT_ERR_INPUT;
+
+    else if(reg >= CLE_VIRTUAL_REG_SIZE)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(value)
+    {
+        CleVirtualReg[reg] =  CleVirtualReg[reg] | (1 << bit);
+    }
+    else
+    {
+        CleVirtualReg[reg] =  CleVirtualReg[reg] & (~(1 << bit));
+    }
+
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("W[0x%4.4x]=0x%4.4x\n", reg, CleVirtualReg[reg]);
+
+#elif defined(EMBEDDED_SUPPORT)
+    rtk_uint16 tmp;
+
+    if(reg > RTL8367C_REGDATAMAX || value > 1)
+        return RT_ERR_INPUT;
+
+    tmp = getReg(reg);
+    tmp &= (1 << bitIdx);
+    tmp |= (value << bitIdx);
+    setReg(reg, tmp);
+
+#else
+    rtk_uint32 regData;
+    ret_t retVal;
+
+    if(bit >= RTL8367C_REGBITLENGTH)
+        return RT_ERR_INPUT;
+
+    retVal = smi_read(reg, &regData);
+    if(retVal != RT_ERR_OK)
+        return RT_ERR_SMI;
+
+  #ifdef CONFIG_RTL865X_CLE
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData);
+  #endif
+    if(value)
+        regData = regData | (1 << bit);
+    else
+        regData = regData & (~(1 << bit));
+
+    retVal = smi_write(reg, regData);
+    if(retVal != RT_ERR_OK)
+        return RT_ERR_SMI;
+
+  #ifdef CONFIG_RTL865X_CLE
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("W[0x%4.4x]=0x%4.4x\n", reg, regData);
+  #endif
+
+#endif
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicRegBit
+ * Description:
+ *      Get a bit value of a specified register
+ * Input:
+ *      reg     - register's address
+ *      bit     - bit location
+ *      value   - value to get.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_INPUT    - Invalid input parameter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRegBit(rtk_uint32 reg, rtk_uint32 bit, rtk_uint32 *pValue)
+{
+
+#if defined(RTK_X86_ASICDRV)
+
+    rtk_uint32 regData;
+    ret_t retVal;
+
+    if(bit >= RTL8367C_REGBITLENGTH)
+        return RT_ERR_INPUT;
+
+    retVal = Access_Read(reg, 2, &regData);
+    if(TRUE != retVal)
+        return RT_ERR_SMI;
+
+    *pValue = (regData & (0x1 << bit)) >> bit;
+
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData);
+
+#elif defined(CONFIG_RTL8367C_ASICDRV_TEST)
+
+    if(bit >= RTL8367C_REGBITLENGTH)
+        return RT_ERR_INPUT;
+
+    if(reg >= CLE_VIRTUAL_REG_SIZE)
+        return RT_ERR_OUT_OF_RANGE;
+
+    *pValue = (CleVirtualReg[reg] & (0x1 << bit)) >> bit;
+
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("R[0x%4.4x]=0x%4.4x\n", reg, CleVirtualReg[reg]);
+
+#elif defined(EMBEDDED_SUPPORT)
+    rtk_uint16 tmp;
+
+    if(reg > RTL8367C_REGDATAMAX )
+        return RT_ERR_INPUT;
+
+    tmp = getReg(reg);
+    tmp = tmp >> bitIdx;
+    tmp &= 1;
+    *value = tmp;
+#else
+    rtk_uint32 regData;
+    ret_t retVal;
+
+    retVal = smi_read(reg, &regData);
+    if(retVal != RT_ERR_OK)
+        return RT_ERR_SMI;
+
+  #ifdef CONFIG_RTL865X_CLE
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData);
+  #endif
+
+    *pValue = (regData & (0x1 << bit)) >> bit;
+
+#endif
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicRegBits
+ * Description:
+ *      Set bits value of a specified register
+ * Input:
+ *      reg     - register's address
+ *      bits    - bits mask for setting
+ *      value   - bits value for setting
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_INPUT    - Invalid input parameter
+ * Note:
+ *      Set bits of a specified register to value. Both bits and value are be treated as bit-mask
+ */
+ret_t rtl8367c_setAsicRegBits(rtk_uint32 reg, rtk_uint32 bits, rtk_uint32 value)
+{
+
+#if defined(RTK_X86_ASICDRV)
+
+    rtk_uint32 regData;
+    ret_t retVal;
+    rtk_uint32 bitsShift;
+    rtk_uint32 valueShifted;
+
+    if(bits >= (1 << RTL8367C_REGBITLENGTH) )
+        return RT_ERR_INPUT;
+
+    bitsShift = 0;
+    while(!(bits & (1 << bitsShift)))
+    {
+        bitsShift++;
+        if(bitsShift >= RTL8367C_REGBITLENGTH)
+            return RT_ERR_INPUT;
+    }
+
+    valueShifted = value << bitsShift;
+    if(valueShifted > RTL8367C_REGDATAMAX)
+        return RT_ERR_INPUT;
+
+    retVal = Access_Read(reg, 2, &regData);
+    if(TRUE != retVal)
+        return RT_ERR_SMI;
+
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData);
+
+    regData = regData & (~bits);
+    regData = regData | (valueShifted & bits);
+
+    retVal = Access_Write(reg,2, regData);
+    if(TRUE != retVal)
+        return RT_ERR_SMI;
+
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("W[0x%4.4x]=0x%4.4x\n", reg, regData);
+
+#elif defined(CONFIG_RTL8367C_ASICDRV_TEST)
+    rtk_uint32 regData;
+    rtk_uint32 bitsShift;
+    rtk_uint32 valueShifted;
+
+    if(bits >= (1 << RTL8367C_REGBITLENGTH) )
+        return RT_ERR_INPUT;
+
+    bitsShift = 0;
+    while(!(bits & (1 << bitsShift)))
+    {
+        bitsShift++;
+        if(bitsShift >= RTL8367C_REGBITLENGTH)
+            return RT_ERR_INPUT;
+    }
+    valueShifted = value << bitsShift;
+
+    if(valueShifted > RTL8367C_REGDATAMAX)
+        return RT_ERR_INPUT;
+
+    if(reg >= CLE_VIRTUAL_REG_SIZE)
+        return RT_ERR_OUT_OF_RANGE;
+
+    regData = CleVirtualReg[reg] & (~bits);
+    regData = regData | (valueShifted & bits);
+
+    CleVirtualReg[reg] = regData;
+
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("W[0x%4.4x]=0x%4.4x\n", reg, regData);
+
+#elif defined(EMBEDDED_SUPPORT)
+    rtk_uint32 regData;
+    rtk_uint32 bitsShift;
+    rtk_uint32 valueShifted;
+
+    if(reg > RTL8367C_REGDATAMAX )
+        return RT_ERR_INPUT;
+
+    if(bits >= (1 << RTL8367C_REGBITLENGTH) )
+        return RT_ERR_INPUT;
+
+    bitsShift = 0;
+    while(!(bits & (1 << bitsShift)))
+    {
+        bitsShift++;
+        if(bitsShift >= RTL8367C_REGBITLENGTH)
+            return RT_ERR_INPUT;
+    }
+
+    valueShifted = value << bitsShift;
+    if(valueShifted > RTL8367C_REGDATAMAX)
+        return RT_ERR_INPUT;
+
+    regData = getReg(reg);
+    regData = regData & (~bits);
+    regData = regData | (valueShifted & bits);
+
+    setReg(reg, regData);
+
+#else
+    rtk_uint32 regData;
+    ret_t retVal;
+    rtk_uint32 bitsShift;
+    rtk_uint32 valueShifted;
+
+    if(bits >= (1 << RTL8367C_REGBITLENGTH) )
+        return RT_ERR_INPUT;
+
+    bitsShift = 0;
+    while(!(bits & (1 << bitsShift)))
+    {
+        bitsShift++;
+        if(bitsShift >= RTL8367C_REGBITLENGTH)
+            return RT_ERR_INPUT;
+    }
+    valueShifted = value << bitsShift;
+
+    if(valueShifted > RTL8367C_REGDATAMAX)
+        return RT_ERR_INPUT;
+
+    retVal = smi_read(reg, &regData);
+    if(retVal != RT_ERR_OK)
+        return RT_ERR_SMI;
+  #ifdef CONFIG_RTL865X_CLE
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData);
+  #endif
+
+    regData = regData & (~bits);
+    regData = regData | (valueShifted & bits);
+
+    retVal = smi_write(reg, regData);
+    if(retVal != RT_ERR_OK)
+        return RT_ERR_SMI;
+  #ifdef CONFIG_RTL865X_CLE
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("W[0x%4.4x]=0x%4.4x\n", reg, regData);
+  #endif
+#endif
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicRegBits
+ * Description:
+ *      Get bits value of a specified register
+ * Input:
+ *      reg     - register's address
+ *      bits    - bits mask for setting
+ *      value   - bits value for setting
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_INPUT    - Invalid input parameter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRegBits(rtk_uint32 reg, rtk_uint32 bits, rtk_uint32 *pValue)
+{
+
+#if defined(RTK_X86_ASICDRV)
+
+    rtk_uint32 regData;
+    ret_t retVal;
+    rtk_uint32 bitsShift;
+
+    if(bits >= (1 << RTL8367C_REGBITLENGTH) )
+        return RT_ERR_INPUT;
+
+    bitsShift = 0;
+    while(!(bits & (1 << bitsShift)))
+    {
+        bitsShift++;
+        if(bitsShift >= RTL8367C_REGBITLENGTH)
+            return RT_ERR_INPUT;
+    }
+
+    retVal = Access_Read(reg, 2, &regData);
+    if(TRUE != retVal)
+        return RT_ERR_SMI;
+
+    *pValue = (regData & bits) >> bitsShift;
+
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData);
+
+#elif defined(CONFIG_RTL8367C_ASICDRV_TEST)
+    rtk_uint32 bitsShift;
+
+    if(bits >= (1 << RTL8367C_REGBITLENGTH) )
+        return RT_ERR_INPUT;
+
+    bitsShift = 0;
+    while(!(bits & (1 << bitsShift)))
+    {
+        bitsShift++;
+        if(bitsShift >= RTL8367C_REGBITLENGTH)
+            return RT_ERR_INPUT;
+    }
+
+    if(reg >= CLE_VIRTUAL_REG_SIZE)
+        return RT_ERR_OUT_OF_RANGE;
+
+     *pValue = (CleVirtualReg[reg] & bits) >> bitsShift;
+
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("R[0x%4.4x]=0x%4.4x\n", reg, CleVirtualReg[reg]);
+
+#elif defined(EMBEDDED_SUPPORT)
+    rtk_uint32 regData;
+    rtk_uint32 bitsShift;
+
+    if(reg > RTL8367C_REGDATAMAX )
+        return RT_ERR_INPUT;
+
+    if(bits >= (1UL << RTL8367C_REGBITLENGTH) )
+        return RT_ERR_INPUT;
+
+    bitsShift = 0;
+    while(!(bits & (1UL << bitsShift)))
+    {
+        bitsShift++;
+        if(bitsShift >= RTL8367C_REGBITLENGTH)
+            return RT_ERR_INPUT;
+    }
+
+    regData = getReg(reg);
+    *value = (regData & bits) >> bitsShift;
+
+#else
+    rtk_uint32 regData;
+    ret_t retVal;
+    rtk_uint32 bitsShift;
+
+    if(bits>= (1<<RTL8367C_REGBITLENGTH) )
+        return RT_ERR_INPUT;
+
+    bitsShift = 0;
+    while(!(bits & (1 << bitsShift)))
+    {
+        bitsShift++;
+        if(bitsShift >= RTL8367C_REGBITLENGTH)
+            return RT_ERR_INPUT;
+    }
+
+    retVal = smi_read(reg, &regData);
+    if(retVal != RT_ERR_OK) return RT_ERR_SMI;
+
+    *pValue = (regData & bits) >> bitsShift;
+  #ifdef CONFIG_RTL865X_CLE
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("R[0x%4.4x]=0x%4.4x\n",reg, regData);
+  #endif
+
+#endif
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicReg
+ * Description:
+ *      Set content of asic register
+ * Input:
+ *      reg     - register's address
+ *      value   - Value setting to register
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      The value will be set to ASIC mapping address only and it is always return RT_ERR_OK while setting un-mapping address registers
+ */
+ret_t rtl8367c_setAsicReg(rtk_uint32 reg, rtk_uint32 value)
+{
+#if defined(RTK_X86_ASICDRV)/*RTK-CNSD2-NickWu-20061222: for x86 compile*/
+
+    ret_t retVal;
+
+    retVal = Access_Write(reg,2,value);
+    if(TRUE != retVal) return RT_ERR_SMI;
+
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("W[0x%4.4x]=0x%4.4x\n",reg,value);
+
+#elif defined(CONFIG_RTL8367C_ASICDRV_TEST)
+
+    /*MIBs emulating*/
+    if(reg == RTL8367C_REG_MIB_ADDRESS)
+    {
+        CleVirtualReg[RTL8367C_MIB_COUNTER_BASE_REG] = 0x1;
+        CleVirtualReg[RTL8367C_MIB_COUNTER_BASE_REG+1] = 0x2;
+        CleVirtualReg[RTL8367C_MIB_COUNTER_BASE_REG+2] = 0x3;
+        CleVirtualReg[RTL8367C_MIB_COUNTER_BASE_REG+3] = 0x4;
+    }
+
+    if(reg >= CLE_VIRTUAL_REG_SIZE)
+        return RT_ERR_OUT_OF_RANGE;
+
+    CleVirtualReg[reg] = value;
+
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("W[0x%4.4x]=0x%4.4x\n",reg,CleVirtualReg[reg]);
+
+#elif defined(EMBEDDED_SUPPORT)
+    if(reg > RTL8367C_REGDATAMAX || value > RTL8367C_REGDATAMAX )
+        return RT_ERR_INPUT;
+
+    setReg(reg, value);
+
+#else
+    ret_t retVal;
+
+    retVal = smi_write(reg, value);
+    if(retVal != RT_ERR_OK)
+        return RT_ERR_SMI;
+  #ifdef CONFIG_RTL865X_CLE
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("W[0x%4.4x]=0x%4.4x\n",reg,value);
+  #endif
+
+#endif
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicReg
+ * Description:
+ *      Get content of asic register
+ * Input:
+ *      reg     - register's address
+ *      value   - Value setting to register
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      Value 0x0000 will be returned for ASIC un-mapping address
+ */
+ret_t rtl8367c_getAsicReg(rtk_uint32 reg, rtk_uint32 *pValue)
+{
+
+#if defined(RTK_X86_ASICDRV)
+
+    rtk_uint32 regData;
+    ret_t retVal;
+
+    retVal = Access_Read(reg, 2, &regData);
+    if(TRUE != retVal)
+        return RT_ERR_SMI;
+
+    *pValue = regData;
+
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData);
+
+#elif defined(CONFIG_RTL8367C_ASICDRV_TEST)
+    if(reg >= CLE_VIRTUAL_REG_SIZE)
+        return RT_ERR_OUT_OF_RANGE;
+
+    *pValue = CleVirtualReg[reg];
+
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("R[0x%4.4x]=0x%4.4x\n", reg, CleVirtualReg[reg]);
+
+#elif defined(EMBEDDED_SUPPORT)
+    if(reg > RTL8367C_REGDATAMAX  )
+        return RT_ERR_INPUT;
+
+    *value = getReg(reg);
+
+#else
+    rtk_uint32 regData;
+    ret_t retVal;
+
+    retVal = smi_read(reg, &regData);
+    if(retVal != RT_ERR_OK)
+        return RT_ERR_SMI;
+
+    *pValue = regData;
+  #ifdef CONFIG_RTL865X_CLE
+    if(0x8367B == cleDebuggingDisplay)
+        PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData);
+  #endif
+
+#endif
+
+    return RT_ERR_OK;
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_acl.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_acl.c
new file mode 100644
index 0000000..d9ccd97
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_acl.c
@@ -0,0 +1,1173 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : ACL related function drivers
+ *
+ */
+#include <rtl8367c_asicdrv_acl.h>
+
+#include <string.h>
+
+#if defined(CONFIG_RTL8367C_ASICDRV_TEST)
+rtl8367c_aclrulesmi Rtl8370sVirtualAclRuleTable[RTL8367C_ACLRULENO];
+rtk_uint16 Rtl8370sVirtualAclActTable[RTL8367C_ACLRULENO][RTL8367C_ACL_ACT_TABLE_LEN];
+#endif
+
+/*
+    Exchange structure type define with MMI and SMI
+*/
+static void _rtl8367c_aclRuleStSmi2User( rtl8367c_aclrule *pAclUser, rtl8367c_aclrulesmi *pAclSmi)
+{
+    rtk_uint8 *care_ptr, *data_ptr;
+    rtk_uint8 care_tmp, data_tmp;
+    rtk_uint32 i;
+
+    pAclUser->data_bits.active_portmsk = (((pAclSmi->data_bits_ext.rule_info >> 1) & 0x0007) << 8) | ((pAclSmi->data_bits.rule_info >> 8) & 0x00FF);
+    pAclUser->data_bits.type = (pAclSmi->data_bits.rule_info & 0x0007);
+    pAclUser->data_bits.tag_exist = (pAclSmi->data_bits.rule_info & 0x00F8) >> 3;
+
+    care_ptr = (rtk_uint8*)&pAclSmi->care_bits;
+    data_ptr = (rtk_uint8*)&pAclSmi->data_bits;
+
+    for ( i = 0; i < sizeof(struct acl_rule_smi_st); i++)
+    {
+        care_tmp = *(care_ptr + i) ^ (*(data_ptr + i));
+        data_tmp = *(data_ptr + i);
+
+        *(care_ptr + i) = care_tmp;
+        *(data_ptr + i) = data_tmp;
+    }
+
+    care_ptr = (rtk_uint8*)&pAclSmi->care_bits_ext;
+    data_ptr = (rtk_uint8*)&pAclSmi->data_bits_ext;
+    care_tmp = (*care_ptr) ^ (*data_ptr);
+    data_tmp = (*data_ptr);
+    *care_ptr = care_tmp;
+    *data_ptr = data_tmp;
+
+    for(i = 0; i < RTL8367C_ACLRULEFIELDNO; i++)
+        pAclUser->data_bits.field[i] = pAclSmi->data_bits.field[i];
+
+    pAclUser->valid = pAclSmi->valid;
+
+    pAclUser->care_bits.active_portmsk = (((pAclSmi->care_bits_ext.rule_info >> 1) & 0x0007) << 8) | ((pAclSmi->care_bits.rule_info >> 8) & 0x00FF);
+    pAclUser->care_bits.type = (pAclSmi->care_bits.rule_info & 0x0007);
+    pAclUser->care_bits.tag_exist = (pAclSmi->care_bits.rule_info & 0x00F8) >> 3;
+
+    for(i = 0; i < RTL8367C_ACLRULEFIELDNO; i++)
+        pAclUser->care_bits.field[i] = pAclSmi->care_bits.field[i];
+}
+
+/*
+    Exchange structure type define with MMI and SMI
+*/
+static void _rtl8367c_aclRuleStUser2Smi(rtl8367c_aclrule *pAclUser, rtl8367c_aclrulesmi *pAclSmi)
+{
+    rtk_uint8 *care_ptr, *data_ptr;
+    rtk_uint8 care_tmp, data_tmp;
+    rtk_uint32 i;
+
+    pAclSmi->data_bits_ext.rule_info = ((pAclUser->data_bits.active_portmsk >> 8) & 0x7) << 1;
+    pAclSmi->data_bits.rule_info = ((pAclUser->data_bits.active_portmsk & 0xff) << 8) | ((pAclUser->data_bits.tag_exist & 0x1F) << 3) | (pAclUser->data_bits.type & 0x07);
+
+    for(i = 0;i < RTL8367C_ACLRULEFIELDNO; i++)
+        pAclSmi->data_bits.field[i] = pAclUser->data_bits.field[i];
+
+    pAclSmi->valid = pAclUser->valid;
+
+    pAclSmi->care_bits_ext.rule_info = ((pAclUser->care_bits.active_portmsk >> 8) & 0x7) << 1;
+    pAclSmi->care_bits.rule_info = ((pAclUser->care_bits.active_portmsk & 0xff) << 8) | ((pAclUser->care_bits.tag_exist & 0x1F) << 3) | (pAclUser->care_bits.type & 0x07);
+
+    for(i = 0; i < RTL8367C_ACLRULEFIELDNO; i++)
+        pAclSmi->care_bits.field[i] = pAclUser->care_bits.field[i];
+
+    care_ptr = (rtk_uint8*)&pAclSmi->care_bits;
+    data_ptr = (rtk_uint8*)&pAclSmi->data_bits;
+
+    for ( i = 0; i < sizeof(struct acl_rule_smi_st); i++)
+    {
+        care_tmp = *(care_ptr + i) & ~(*(data_ptr + i));
+        data_tmp = *(care_ptr + i) & *(data_ptr + i);
+
+        *(care_ptr + i) = care_tmp;
+        *(data_ptr + i) = data_tmp;
+    }
+
+    care_ptr = (rtk_uint8*)&pAclSmi->care_bits_ext;
+    data_ptr = (rtk_uint8*)&pAclSmi->data_bits_ext;
+    care_tmp = *care_ptr & ~(*data_ptr);
+    data_tmp = *care_ptr & *data_ptr;
+
+    *care_ptr = care_tmp;
+    *data_ptr = data_tmp;
+}
+
+/*
+    Exchange structure type define with MMI and SMI
+*/
+static void _rtl8367c_aclActStSmi2User(rtl8367c_acl_act_t *pAclUser, rtk_uint16 *pAclSmi)
+{
+    pAclUser->cact = (pAclSmi[0] & 0x00C0) >> 6;
+    pAclUser->cvidx_cact = (pAclSmi[0] & 0x003F) | (((pAclSmi[3] & 0x0008) >> 3) << 6);
+
+    pAclUser->sact = (pAclSmi[0] & 0xC000) >> 14;
+    pAclUser->svidx_sact = ((pAclSmi[0] & 0x3F00) >> 8) | (((pAclSmi[3] & 0x0010) >> 4) << 6);
+
+    pAclUser->aclmeteridx = (pAclSmi[1] & 0x003F) | (((pAclSmi[3] & 0x0020) >> 5) << 6);
+
+    pAclUser->fwdact = (pAclSmi[1] & 0xC000) >> 14;
+    pAclUser->fwdpmask = ((pAclSmi[1] & 0x3FC0) >> 6) | (((pAclSmi[3] & 0x01C0) >> 6) << 8);
+
+    pAclUser->priact = (pAclSmi[2] & 0x00C0) >> 6;
+    pAclUser->pridx = (pAclSmi[2] & 0x003F) | (((pAclSmi[3] & 0x0200) >> 9) << 6);
+
+    pAclUser->aclint = (pAclSmi[2] & 0x2000) >> 13;
+    pAclUser->gpio_en = (pAclSmi[2] & 0x1000) >> 12;
+    pAclUser->gpio_pin = (pAclSmi[2] & 0x0F00) >> 8;
+
+    pAclUser->cact_ext = (pAclSmi[2] & 0xC000) >> 14;
+    pAclUser->tag_fmt = (pAclSmi[3] & 0x0003);
+    pAclUser->fwdact_ext = (pAclSmi[3] & 0x0004) >> 2;
+}
+
+/*
+    Exchange structure type define with MMI and SMI
+*/
+static void _rtl8367c_aclActStUser2Smi(rtl8367c_acl_act_t *pAclUser, rtk_uint16 *pAclSmi)
+{
+    pAclSmi[0] |= (pAclUser->cvidx_cact & 0x003F);
+    pAclSmi[0] |= (pAclUser->cact & 0x0003) << 6;
+    pAclSmi[0] |= (pAclUser->svidx_sact & 0x003F) << 8;
+    pAclSmi[0] |= (pAclUser->sact & 0x0003) << 14;
+
+    pAclSmi[1] |= (pAclUser->aclmeteridx & 0x003F);
+    pAclSmi[1] |= (pAclUser->fwdpmask & 0x00FF) << 6;
+    pAclSmi[1] |= (pAclUser->fwdact & 0x0003) << 14;
+
+    pAclSmi[2] |= (pAclUser->pridx & 0x003F);
+    pAclSmi[2] |= (pAclUser->priact & 0x0003) << 6;
+    pAclSmi[2] |= (pAclUser->gpio_pin & 0x000F) << 8;
+    pAclSmi[2] |= (pAclUser->gpio_en & 0x0001) << 12;
+    pAclSmi[2] |= (pAclUser->aclint & 0x0001) << 13;
+    pAclSmi[2] |= (pAclUser->cact_ext & 0x0003) << 14;
+
+    pAclSmi[3] |= (pAclUser->tag_fmt & 0x0003);
+    pAclSmi[3] |= (pAclUser->fwdact_ext & 0x0001) << 2;
+    pAclSmi[3] |= ((pAclUser->cvidx_cact & 0x0040) >> 6) << 3;
+    pAclSmi[3] |= ((pAclUser->svidx_sact & 0x0040) >> 6) << 4;
+    pAclSmi[3] |= ((pAclUser->aclmeteridx & 0x0040) >> 6) << 5;
+    pAclSmi[3] |= ((pAclUser->fwdpmask & 0x0700) >> 8) << 6;
+    pAclSmi[3] |= ((pAclUser->pridx & 0x0040) >> 6) << 9;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicAcl
+ * Description:
+ *      Set port acl function enable/disable
+ * Input:
+ *      port    - Physical port number (0~10)
+ *      enabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicAcl(rtk_uint32 port, rtk_uint32 enabled)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_ACL_ENABLE_REG, port, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicAcl
+ * Description:
+ *      Get port acl function enable/disable
+ * Input:
+ *      port    - Physical port number (0~10)
+ *      enabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicAcl(rtk_uint32 port, rtk_uint32* pEnabled)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_ACL_ENABLE_REG, port, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicAclUnmatchedPermit
+ * Description:
+ *      Set port acl function unmatched permit action
+ * Input:
+ *      port    - Physical port number (0~10)
+ *      enabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicAclUnmatchedPermit(rtk_uint32 port, rtk_uint32 enabled)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_ACL_UNMATCH_PERMIT_REG, port, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicAclUnmatchedPermit
+ * Description:
+ *      Get port acl function unmatched permit action
+ * Input:
+ *      port    - Physical port number (0~10)
+ *      enabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicAclUnmatchedPermit(rtk_uint32 port, rtk_uint32* pEnabled)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_ACL_UNMATCH_PERMIT_REG, port, pEnabled);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicAclRule
+ * Description:
+ *      Set acl rule content
+ * Input:
+ *      index   - ACL rule index (0-95) of 96 ACL rules
+ *      pAclRule - ACL rule stucture for setting
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - Invalid ACL rule index (0-95)
+ * Note:
+ *      System supported 95 shared 289-bit ACL ingress rule. Index was available at range 0-95 only.
+ *      If software want to modify ACL rule, the ACL function should be disable at first or unspecify
+ *      acl action will be executed.
+ *      One ACL rule structure has three parts setting:
+ *      Bit 0-147       Data Bits of this Rule
+ *      Bit 148     Valid Bit
+ *      Bit 149-296 Care Bits of this Rule
+ *      There are four kinds of field in Data Bits and Care Bits: Active Portmask, Type, Tag Exist, and 8 fields
+ */
+ret_t rtl8367c_setAsicAclRule(rtk_uint32 index, rtl8367c_aclrule* pAclRule)
+{
+    rtl8367c_aclrulesmi aclRuleSmi;
+    rtk_uint16* tableAddr;
+    rtk_uint32 regAddr;
+    rtk_uint32  regData;
+    rtk_uint32 i;
+    ret_t retVal;
+
+    if(index > RTL8367C_ACLRULEMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    memset(&aclRuleSmi, 0x00, sizeof(rtl8367c_aclrulesmi));
+
+    _rtl8367c_aclRuleStUser2Smi(pAclRule, &aclRuleSmi);
+
+    /* Write valid bit = 0 */
+    regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG;
+    if(index >= 64)
+        regData = RTL8367C_ACLRULETBADDR2(DATABITS, index);
+    else
+        regData = RTL8367C_ACLRULETBADDR(DATABITS, index);
+    retVal = rtl8367c_setAsicReg(regAddr,regData);
+    if(retVal !=RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_TABLE_ACCESS_WRDATA_REG(RTL8367C_ACLRULETBLEN), 0x1, 0);
+    if(retVal !=RT_ERR_OK)
+        return retVal;
+
+    regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG;
+    regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_WRITE, TB_TARGET_ACLRULE);
+    retVal = rtl8367c_setAsicReg(regAddr, regData);
+    if(retVal !=RT_ERR_OK)
+        return retVal;
+
+
+
+    /* Write ACS_ADR register */
+    regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG;
+    if(index >= 64)
+        regData = RTL8367C_ACLRULETBADDR2(CAREBITS, index);
+    else
+        regData = RTL8367C_ACLRULETBADDR(CAREBITS, index);
+    retVal = rtl8367c_setAsicReg(regAddr, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /* Write Care Bits to ACS_DATA registers */
+     tableAddr = (rtk_uint16*)&aclRuleSmi.care_bits;
+     regAddr = RTL8367C_TABLE_ACCESS_WRDATA_BASE;
+
+    for(i = 0; i < RTL8367C_ACLRULETBLEN; i++)
+    {
+        regData = *tableAddr;
+        retVal = rtl8367c_setAsicReg(regAddr, regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        regAddr++;
+        tableAddr++;
+    }
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_TABLE_ACCESS_WRDATA_REG(RTL8367C_ACLRULETBLEN), (0x0007 << 1), (aclRuleSmi.care_bits_ext.rule_info >> 1) & 0x0007);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /* Write ACS_CMD register */
+    regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG;
+    regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_WRITE, TB_TARGET_ACLRULE);
+    retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK,regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+
+
+    /* Write ACS_ADR register for data bits */
+    regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG;
+    if(index >= 64)
+        regData = RTL8367C_ACLRULETBADDR2(DATABITS, index);
+    else
+        regData = RTL8367C_ACLRULETBADDR(DATABITS, index);
+
+    retVal = rtl8367c_setAsicReg(regAddr, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /* Write Data Bits to ACS_DATA registers */
+     tableAddr = (rtk_uint16*)&aclRuleSmi.data_bits;
+     regAddr = RTL8367C_TABLE_ACCESS_WRDATA_BASE;
+
+    for(i = 0; i < RTL8367C_ACLRULETBLEN; i++)
+    {
+        regData = *tableAddr;
+        retVal = rtl8367c_setAsicReg(regAddr, regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        regAddr++;
+        tableAddr++;
+    }
+
+    retVal = rtl8367c_setAsicRegBit(RTL8367C_TABLE_ACCESS_WRDATA_REG(RTL8367C_ACLRULETBLEN), 0, aclRuleSmi.valid);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_TABLE_ACCESS_WRDATA_REG(RTL8367C_ACLRULETBLEN), (0x0007 << 1), (aclRuleSmi.data_bits_ext.rule_info >> 1) & 0x0007);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /* Write ACS_CMD register for care bits*/
+    regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG;
+    regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_WRITE, TB_TARGET_ACLRULE);
+    retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+#ifdef CONFIG_RTL8367C_ASICDRV_TEST
+    memcpy(&Rtl8370sVirtualAclRuleTable[index], &aclRuleSmi, sizeof(rtl8367c_aclrulesmi));
+#endif
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicAclRule
+ * Description:
+ *      Get acl rule content
+ * Input:
+ *      index   - ACL rule index (0-63) of 64 ACL rules
+ *      pAclRule - ACL rule stucture for setting
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - Invalid ACL rule index (0-63)
+  * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicAclRule(rtk_uint32 index, rtl8367c_aclrule *pAclRule)
+{
+    rtl8367c_aclrulesmi aclRuleSmi;
+    rtk_uint32 regAddr, regData;
+    ret_t retVal;
+    rtk_uint16* tableAddr;
+    rtk_uint32 i;
+
+    if(index > RTL8367C_ACLRULEMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    memset(&aclRuleSmi, 0x00, sizeof(rtl8367c_aclrulesmi));
+
+    /* Write ACS_ADR register for data bits */
+    regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG;
+    if(index >= 64)
+        regData = RTL8367C_ACLRULETBADDR2(DATABITS, index);
+    else
+        regData = RTL8367C_ACLRULETBADDR(DATABITS, index);
+
+    retVal = rtl8367c_setAsicReg(regAddr, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+
+    /* Write ACS_CMD register */
+    regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG;
+    regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_READ, TB_TARGET_ACLRULE);
+    retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /* Read Data Bits */
+    regAddr = RTL8367C_TABLE_ACCESS_RDDATA_BASE;
+    tableAddr = (rtk_uint16*)&aclRuleSmi.data_bits;
+    for(i = 0; i < RTL8367C_ACLRULETBLEN; i++)
+    {
+        retVal = rtl8367c_getAsicReg(regAddr, &regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        *tableAddr = regData;
+
+        regAddr ++;
+        tableAddr ++;
+    }
+
+    /* Read Valid Bit */
+    retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_RDDATA_REG(RTL8367C_ACLRULETBLEN), 0, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+    aclRuleSmi.valid = regData & 0x1;
+    /* Read active_portmsk_ext Bits */
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_TABLE_ACCESS_RDDATA_REG(RTL8367C_ACLRULETBLEN), 0x7<<1, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+    aclRuleSmi.data_bits_ext.rule_info = (regData % 0x0007) << 1;
+
+
+    /* Write ACS_ADR register for carebits*/
+    regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG;
+    if(index >= 64)
+        regData = RTL8367C_ACLRULETBADDR2(CAREBITS, index);
+    else
+        regData = RTL8367C_ACLRULETBADDR(CAREBITS, index);
+
+    retVal = rtl8367c_setAsicReg(regAddr, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /* Write ACS_CMD register */
+    regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG;
+    regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_READ, TB_TARGET_ACLRULE);
+    retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /* Read Care Bits */
+    regAddr = RTL8367C_TABLE_ACCESS_RDDATA_BASE;
+    tableAddr = (rtk_uint16*)&aclRuleSmi.care_bits;
+    for(i = 0; i < RTL8367C_ACLRULETBLEN; i++)
+    {
+        retVal = rtl8367c_getAsicReg(regAddr, &regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        *tableAddr = regData;
+
+        regAddr ++;
+        tableAddr ++;
+    }
+    /* Read active_portmsk_ext care Bits */
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_TABLE_ACCESS_RDDATA_REG(RTL8367C_ACLRULETBLEN), 0x7<<1, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+    aclRuleSmi.care_bits_ext.rule_info = (regData & 0x0007) << 1;
+
+#ifdef CONFIG_RTL8367C_ASICDRV_TEST
+    memcpy(&aclRuleSmi,&Rtl8370sVirtualAclRuleTable[index], sizeof(rtl8367c_aclrulesmi));
+#endif
+
+     _rtl8367c_aclRuleStSmi2User(pAclRule, &aclRuleSmi);
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicAclNot
+ * Description:
+ *      Set rule comparison result inversion / no inversion
+ * Input:
+ *      index   - ACL rule index (0-95) of 96 ACL rules
+ *      not     - 1: inverse, 0: don't inverse
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - Invalid ACL rule index (0-95)
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicAclNot(rtk_uint32 index, rtk_uint32 not)
+{
+    if(index > RTL8367C_ACLRULEMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(index < 64)
+        return rtl8367c_setAsicRegBit(RTL8367C_ACL_ACTION_CTRL_REG(index), RTL8367C_ACL_OP_NOT_OFFSET(index), not);
+    else
+        return rtl8367c_setAsicRegBit(RTL8367C_ACL_ACTION_CTRL2_REG(index), RTL8367C_ACL_OP_NOT_OFFSET(index), not);
+
+}
+/* Function Name:
+ *      rtl8367c_getAsicAcl
+ * Description:
+ *      Get rule comparison result inversion / no inversion
+ * Input:
+ *      index   - ACL rule index (0-95) of 95 ACL rules
+ *      pNot    - 1: inverse, 0: don't inverse
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - Invalid ACL rule index (0-95)
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicAclNot(rtk_uint32 index, rtk_uint32* pNot)
+{
+    if(index > RTL8367C_ACLRULEMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(index < 64)
+        return rtl8367c_getAsicRegBit(RTL8367C_ACL_ACTION_CTRL_REG(index), RTL8367C_ACL_OP_NOT_OFFSET(index), pNot);
+    else
+        return rtl8367c_getAsicRegBit(RTL8367C_ACL_ACTION_CTRL2_REG(index), RTL8367C_ACL_OP_NOT_OFFSET(index), pNot);
+
+}
+/* Function Name:
+ *      rtl8367c_setAsicAclTemplate
+ * Description:
+ *      Set fields of a ACL Template
+ * Input:
+ *      index   - ACL template index(0~4)
+ *      pAclType - ACL type stucture for setting
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - Invalid ACL template index(0~4)
+ * Note:
+ *      The API can set type field of the 5 ACL rule templates.
+ *      Each type has 8 fields. One field means what data in one field of a ACL rule means
+ *      8 fields of ACL rule 0~95 is descripted by one type in ACL group
+ */
+ret_t rtl8367c_setAsicAclTemplate(rtk_uint32 index, rtl8367c_acltemplate_t* pAclType)
+{
+    ret_t retVal;
+    rtk_uint32 i;
+    rtk_uint32 regAddr, regData;
+
+    if(index >= RTL8367C_ACLTEMPLATENO)
+        return RT_ERR_OUT_OF_RANGE;
+
+    regAddr = RTL8367C_ACL_RULE_TEMPLATE_CTRL_REG(index);
+
+    for(i = 0; i < (RTL8367C_ACLRULEFIELDNO/2); i++)
+    {
+        regData = pAclType->field[i*2+1];
+        regData = regData << 8 | pAclType->field[i*2];
+
+        retVal = rtl8367c_setAsicReg(regAddr + i, regData);
+
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicAclTemplate
+ * Description:
+ *      Get fields of a ACL Template
+ * Input:
+ *      index   - ACL template index(0~4)
+ *      pAclType - ACL type stucture for setting
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - Invalid ACL template index(0~4)
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicAclTemplate(rtk_uint32 index, rtl8367c_acltemplate_t *pAclType)
+{
+    ret_t retVal;
+    rtk_uint32 i;
+    rtk_uint32 regData, regAddr;
+
+    if(index >= RTL8367C_ACLTEMPLATENO)
+        return RT_ERR_OUT_OF_RANGE;
+
+    regAddr = RTL8367C_ACL_RULE_TEMPLATE_CTRL_REG(index);
+
+    for(i = 0; i < (RTL8367C_ACLRULEFIELDNO/2); i++)
+    {
+        retVal = rtl8367c_getAsicReg(regAddr + i,&regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        pAclType->field[i*2] = regData & 0xFF;
+        pAclType->field[i*2 + 1] = (regData >> 8) & 0xFF;
+    }
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicAclAct
+ * Description:
+ *      Set ACL rule matched Action
+ * Input:
+ *      index   - ACL rule index (0-95) of 96 ACL rules
+ *      pAclAct     - ACL action stucture for setting
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - Invalid ACL rule index (0-95)
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicAclAct(rtk_uint32 index, rtl8367c_acl_act_t* pAclAct)
+{
+    rtk_uint16 aclActSmi[RTL8367C_ACL_ACT_TABLE_LEN];
+    ret_t retVal;
+    rtk_uint32 regAddr, regData;
+    rtk_uint16* tableAddr;
+    rtk_uint32 i;
+
+    if(index > RTL8367C_ACLRULEMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    memset(aclActSmi, 0x00, sizeof(rtk_uint16) * RTL8367C_ACL_ACT_TABLE_LEN);
+     _rtl8367c_aclActStUser2Smi(pAclAct, aclActSmi);
+
+    /* Write ACS_ADR register for data bits */
+    regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG;
+    regData = index;
+    retVal = rtl8367c_setAsicReg(regAddr, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /* Write Data Bits to ACS_DATA registers */
+     tableAddr = aclActSmi;
+     regAddr = RTL8367C_TABLE_ACCESS_WRDATA_BASE;
+
+    for(i = 0; i < RTL8367C_ACLACTTBLEN; i++)
+    {
+        regData = *tableAddr;
+        retVal = rtl8367c_setAsicReg(regAddr, regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        regAddr++;
+        tableAddr++;
+    }
+
+    /* Write ACS_CMD register for care bits*/
+    regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG;
+    regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_WRITE, TB_TARGET_ACLACT);
+    retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+#ifdef CONFIG_RTL8367C_ASICDRV_TEST
+    memcpy(&Rtl8370sVirtualAclActTable[index][0], aclActSmi, sizeof(rtk_uint16) * RTL8367C_ACL_ACT_TABLE_LEN);
+#endif
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicAclAct
+ * Description:
+ *      Get ACL rule matched Action
+ * Input:
+ *      index   - ACL rule index (0-95) of 96 ACL rules
+ *      pAclAct     - ACL action stucture for setting
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - Invalid ACL rule index (0-95)
+  * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicAclAct(rtk_uint32 index, rtl8367c_acl_act_t *pAclAct)
+{
+    rtk_uint16 aclActSmi[RTL8367C_ACL_ACT_TABLE_LEN];
+    ret_t retVal;
+    rtk_uint32 regAddr, regData;
+    rtk_uint16 *tableAddr;
+    rtk_uint32 i;
+
+    if(index > RTL8367C_ACLRULEMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    memset(aclActSmi, 0x00, sizeof(rtk_uint16) * RTL8367C_ACL_ACT_TABLE_LEN);
+
+    /* Write ACS_ADR register for data bits */
+    regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG;
+    regData = index;
+    retVal = rtl8367c_setAsicReg(regAddr, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /* Write ACS_CMD register */
+    regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG;
+    regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_READ, TB_TARGET_ACLACT);
+    retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /* Read Data Bits */
+    regAddr = RTL8367C_TABLE_ACCESS_RDDATA_BASE;
+    tableAddr = aclActSmi;
+    for(i = 0; i < RTL8367C_ACLACTTBLEN; i++)
+    {
+        retVal = rtl8367c_getAsicReg(regAddr, &regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        *tableAddr = regData;
+
+        regAddr ++;
+        tableAddr ++;
+    }
+
+#ifdef CONFIG_RTL8367C_ASICDRV_TEST
+    memcpy(aclActSmi, &Rtl8370sVirtualAclActTable[index][0], sizeof(rtk_uint16) * RTL8367C_ACL_ACT_TABLE_LEN);
+#endif
+
+     _rtl8367c_aclActStSmi2User(pAclAct, aclActSmi);
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicAclActCtrl
+ * Description:
+ *      Set ACL rule matched Action Control Bits
+ * Input:
+ *      index       - ACL rule index (0-95) of 96 ACL rules
+ *      aclActCtrl  - 6 ACL Control Bits
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - Invalid ACL rule index (0-95)
+ * Note:
+ *      ACL Action Control Bits Indicate which actions will be take when a rule matches
+ */
+ret_t rtl8367c_setAsicAclActCtrl(rtk_uint32 index, rtk_uint32 aclActCtrl)
+{
+    ret_t retVal;
+
+    if(index > RTL8367C_ACLRULEMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(index >= 64)
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_ACL_ACTION_CTRL2_REG(index), RTL8367C_ACL_OP_ACTION_MASK(index), aclActCtrl);
+    else
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_ACL_ACTION_CTRL_REG(index), RTL8367C_ACL_OP_ACTION_MASK(index), aclActCtrl);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicAclActCtrl
+ * Description:
+ *      Get ACL rule matched Action Control Bits
+ * Input:
+ *      index       - ACL rule index (0-95) of 96 ACL rules
+ *      pAclActCtrl     - 6 ACL Control Bits
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - Invalid ACL rule index (0-95)
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicAclActCtrl(rtk_uint32 index, rtk_uint32 *pAclActCtrl)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+
+    if(index > RTL8367C_ACLRULEMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(index >= 64)
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_ACL_ACTION_CTRL2_REG(index), RTL8367C_ACL_OP_ACTION_MASK(index), &regData);
+    else
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_ACL_ACTION_CTRL_REG(index), RTL8367C_ACL_OP_ACTION_MASK(index), &regData);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *pAclActCtrl = regData;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicAclPortRange
+ * Description:
+ *      Set ACL TCP/UDP range check
+ * Input:
+ *      index       - TCP/UDP port range check table index
+ *      type        - Range check type
+ *      upperPort   - TCP/UDP port range upper bound
+ *      lowerPort   - TCP/UDP port range lower bound
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - Invalid TCP/UDP port range check table index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicAclPortRange(rtk_uint32 index, rtk_uint32 type, rtk_uint32 upperPort, rtk_uint32 lowerPort)
+{
+    ret_t retVal;
+
+    if(index > RTL8367C_ACLRANGEMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL2 + index*3, RTL8367C_ACL_SDPORT_RANGE_ENTRY0_CTRL2_MASK, type);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL1 + index*3, upperPort);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL0 + index*3, lowerPort);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicAclPortRange
+ * Description:
+ *      Get ACL TCP/UDP range check
+ * Input:
+ *      index       - TCP/UDP port range check table index
+ *      pType       - Range check type
+ *      pUpperPort  - TCP/UDP port range upper bound
+ *      pLowerPort  - TCP/UDP port range lower bound
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - Invalid TCP/UDP port range check table index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicAclPortRange(rtk_uint32 index, rtk_uint32* pType, rtk_uint32* pUpperPort, rtk_uint32* pLowerPort)
+{
+    ret_t retVal;
+
+    if(index > RTL8367C_ACLRANGEMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL2 + index*3, RTL8367C_ACL_SDPORT_RANGE_ENTRY0_CTRL2_MASK, pType);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL1 + index*3, pUpperPort);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL0 + index*3, pLowerPort);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicAclVidRange
+ * Description:
+ *      Set ACL VID range check
+ * Input:
+ *      index       - ACL VID range check index(0~15)
+ *      type        - Range check type
+ *      upperVid    - VID range upper bound
+ *      lowerVid    - VID range lower bound
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - Invalid ACL  VID range check index(0~15)
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicAclVidRange(rtk_uint32 index, rtk_uint32 type, rtk_uint32 upperVid, rtk_uint32 lowerVid)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+
+    if(index > RTL8367C_ACLRANGEMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    regData = ((type << RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_TYPE_OFFSET) & RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_TYPE_MASK) |
+                (upperVid & RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_HIGH_MASK);
+
+    retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_VID_RANGE_ENTRY0_CTRL1 + index*2, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_VID_RANGE_ENTRY0_CTRL0 + index*2, lowerVid);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicAclVidRange
+ * Description:
+ *      Get ACL VID range check
+ * Input:
+ *      index       - ACL VID range check index(0~15)
+ *      pType       - Range check type
+ *      pUpperVid   - VID range upper bound
+ *      pLowerVid   - VID range lower bound
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - Invalid ACL VID range check index(0~15)
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicAclVidRange(rtk_uint32 index, rtk_uint32* pType, rtk_uint32* pUpperVid, rtk_uint32* pLowerVid)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+
+    if(index > RTL8367C_ACLRANGEMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_VID_RANGE_ENTRY0_CTRL1 + index*2, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *pType = (regData & RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_TYPE_MASK) >> RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_TYPE_OFFSET;
+    *pUpperVid = regData & RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_HIGH_MASK;
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_VID_RANGE_ENTRY0_CTRL0 + index*2, pLowerVid);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicAclIpRange
+ * Description:
+ *      Set ACL IP range check
+ * Input:
+ *      index       - ACL IP range check index(0~15)
+ *      type        - Range check type
+ *      upperIp     - IP range upper bound
+ *      lowerIp     - IP range lower bound
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - Invalid ACL IP range check index(0~15)
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicAclIpRange(rtk_uint32 index, rtk_uint32 type, ipaddr_t upperIp, ipaddr_t lowerIp)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+    ipaddr_t ipData;
+
+    if(index > RTL8367C_ACLRANGEMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL4 + index*5, RTL8367C_ACL_IP_RANGE_ENTRY0_CTRL4_MASK, type);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    ipData = upperIp;
+
+    regData = ipData & 0xFFFF;
+    retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL2 + index*5, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    regData = (ipData>>16) & 0xFFFF;
+    retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL3 + index*5, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    ipData = lowerIp;
+
+    regData = ipData & 0xFFFF;
+    retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL0 + index*5, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    regData = (ipData>>16) & 0xFFFF;
+    retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL1 + index*5, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicAclIpRange
+ * Description:
+ *      Get ACL IP range check
+ * Input:
+ *      index       - ACL IP range check index(0~15)
+ *      pType       - Range check type
+ *      pUpperIp    - IP range upper bound
+ *      pLowerIp    - IP range lower bound
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - Invalid ACL IP range check index(0~15)
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicAclIpRange(rtk_uint32 index, rtk_uint32* pType, ipaddr_t* pUpperIp, ipaddr_t* pLowerIp)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+    ipaddr_t ipData;
+
+    if(index > RTL8367C_ACLRANGEMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL4 + index*5, RTL8367C_ACL_IP_RANGE_ENTRY0_CTRL4_MASK, pType);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL2 + index*5, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+    ipData = regData;
+
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL3 + index*5, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    ipData = (regData <<16) | ipData;
+    *pUpperIp = ipData;
+
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL0 + index*5, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+    ipData = regData;
+
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL1 + index*5, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    ipData = (regData << 16) | ipData;
+    *pLowerIp = ipData;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicAclGpioPolarity
+ * Description:
+ *      Set ACL Goip control palarity
+ * Input:
+ *      polarity - 1: High, 0: Low
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      none
+ */
+ret_t rtl8367c_setAsicAclGpioPolarity(rtk_uint32 polarity)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_ACL_GPIO_POLARITY, RTL8367C_ACL_GPIO_POLARITY_OFFSET, polarity);
+}
+/* Function Name:
+ *      rtl8367c_getAsicAclGpioPolarity
+ * Description:
+ *      Get ACL Goip control palarity
+ * Input:
+ *      pPolarity - 1: High, 0: Low
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      none
+ */
+ret_t rtl8367c_getAsicAclGpioPolarity(rtk_uint32* pPolarity)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_ACL_GPIO_POLARITY, RTL8367C_ACL_GPIO_POLARITY_OFFSET, pPolarity);
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_cputag.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_cputag.c
new file mode 100644
index 0000000..d22bf65
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_cputag.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Proprietary CPU-tag related function drivers
+ *
+ */
+#include <rtl8367c_asicdrv_cputag.h>
+/* Function Name:
+ *      rtl8367c_setAsicCputagEnable
+ * Description:
+ *      Set cpu tag function enable/disable
+ * Input:
+ *      enabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_ENABLE   - Invalid enable/disable input
+ * Note:
+ *      If CPU tag function is disabled, CPU tag will not be added to frame
+ *      forwarded to CPU port, and all ports cannot parse CPU tag.
+ */
+ret_t rtl8367c_setAsicCputagEnable(rtk_uint32 enabled)
+{
+    if(enabled > 1)
+        return RT_ERR_ENABLE;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_EN_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicCputagEnable
+ * Description:
+ *      Get cpu tag function enable/disable
+ * Input:
+ *      pEnabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicCputagEnable(rtk_uint32 *pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_EN_OFFSET, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicCputagTrapPort
+ * Description:
+ *      Set cpu tag trap port
+ * Input:
+ *      port - port number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *     API can set destination port of trapping frame
+ */
+ret_t rtl8367c_setAsicCputagTrapPort(rtk_uint32 port)
+{
+    ret_t retVal;
+
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TRAP_PORT_MASK, port & 7);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TRAP_PORT_EXT_MASK, (port>>3) & 1);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicCputagTrapPort
+ * Description:
+ *      Get cpu tag trap port
+ * Input:
+ *      pPort - port number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *     None
+ */
+ret_t rtl8367c_getAsicCputagTrapPort(rtk_uint32 *pPort)
+{
+    ret_t retVal;
+    rtk_uint32 tmpPort;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TRAP_PORT_MASK, &tmpPort);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+    *pPort = tmpPort;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TRAP_PORT_EXT_MASK, &tmpPort);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+    *pPort |= (tmpPort & 1) << 3;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicCputagPortmask
+ * Description:
+ *      Set ports that can parse CPU tag
+ * Input:
+ *      portmask - port mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK    - Invalid portmask
+ * Note:
+ *     None
+ */
+ret_t rtl8367c_setAsicCputagPortmask(rtk_uint32 portmask)
+{
+    if(portmask > RTL8367C_PORTMASK)
+        return RT_ERR_PORT_MASK;
+
+    return rtl8367c_setAsicReg(RTL8367C_CPU_PORT_MASK_REG, portmask);
+}
+/* Function Name:
+ *      rtl8367c_getAsicCputagPortmask
+ * Description:
+ *      Get ports that can parse CPU tag
+ * Input:
+ *      pPortmask - port mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *     None
+ */
+ret_t rtl8367c_getAsicCputagPortmask(rtk_uint32 *pPortmask)
+{
+    return rtl8367c_getAsicReg(RTL8367C_CPU_PORT_MASK_REG, pPortmask);
+}
+/* Function Name:
+ *      rtl8367c_setAsicCputagInsertMode
+ * Description:
+ *      Set CPU-tag insert mode
+ * Input:
+ *      mode - 0: insert to all packets; 1: insert to trapped packets; 2: don't insert
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_NOT_ALLOWED  - Actions not allowed by the function
+ * Note:
+ *     None
+ */
+ret_t rtl8367c_setAsicCputagInsertMode(rtk_uint32 mode)
+{
+    if(mode >= CPUTAG_INSERT_END)
+        return RT_ERR_NOT_ALLOWED;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_INSERTMODE_MASK, mode);
+}
+/* Function Name:
+ *      rtl8367c_getAsicCputagInsertMode
+ * Description:
+ *      Get CPU-tag insert mode
+ * Input:
+ *      pMode - 0: insert to all packets; 1: insert to trapped packets; 2: don't insert
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *     None
+ */
+ret_t rtl8367c_getAsicCputagInsertMode(rtk_uint32 *pMode)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_INSERTMODE_MASK, pMode);
+}
+/* Function Name:
+ *      rtl8367c_setAsicCputagPriorityRemapping
+ * Description:
+ *      Set queue assignment of CPU port
+ * Input:
+ *      srcPri - internal priority (0~7)
+ *      newPri - internal priority after remapping (0~7)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY     - Invalid priority
+ * Note:
+ *     None
+ */
+ret_t rtl8367c_setAsicCputagPriorityRemapping(rtk_uint32 srcPri, rtk_uint32 newPri)
+{
+    if((srcPri > RTL8367C_PRIMAX) || (newPri > RTL8367C_PRIMAX))
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_REG(srcPri), RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_MASK(srcPri), newPri);
+}
+/* Function Name:
+ *      rtl8367c_getAsicCputagPriorityRemapping
+ * Description:
+ *      Get queue assignment of CPU port
+ * Input:
+ *      srcPri - internal priority (0~7)
+ *      pNewPri - internal priority after remapping (0~7)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY     - Invalid priority
+ * Note:
+ *     None
+ */
+ret_t rtl8367c_getAsicCputagPriorityRemapping(rtk_uint32 srcPri, rtk_uint32 *pNewPri)
+{
+    if(srcPri > RTL8367C_PRIMAX)
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_REG(srcPri), RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_MASK(srcPri), pNewPri);
+}
+/* Function Name:
+ *      rtl8367c_setAsicCputagPosition
+ * Description:
+ *      Set cpu tag insert position
+ * Input:
+ *      postion - 1: After entire packet(before CRC field), 0: After MAC_SA (Default)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ * Note:
+ *     None
+ */
+ret_t rtl8367c_setAsicCputagPosition(rtk_uint32 postion)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TAG_POSITION_OFFSET, postion);
+}
+/* Function Name:
+ *      rtl8367c_getAsicCputagPosition
+ * Description:
+ *      Get cpu tag insert position
+ * Input:
+ *      pPostion - 1: After entire packet(before CRC field), 0: After MAC_SA (Default)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ * Note:
+ *     None
+ */
+ret_t rtl8367c_getAsicCputagPosition(rtk_uint32* pPostion)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TAG_POSITION_OFFSET, pPostion);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicCputagMode
+ * Description:
+ *      Set cpu tag mode
+ * Input:
+ *      mode - 1: 4bytes mode, 0: 8bytes mode
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_INPUT    - Invalid input parameters
+ * Note:
+ *      If CPU tag function is disabled, CPU tag will not be added to frame
+ *      forwarded to CPU port, and all ports cannot parse CPU tag.
+ */
+ret_t rtl8367c_setAsicCputagMode(rtk_uint32 mode)
+{
+    if(mode > 1)
+        return RT_ERR_INPUT;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TAG_FORMAT_OFFSET, mode);
+}
+/* Function Name:
+ *      rtl8367c_getAsicCputagMode
+ * Description:
+ *      Get cpu tag mode
+ * Input:
+ *      pMode - 1: 4bytes mode, 0: 8bytes mode
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicCputagMode(rtk_uint32 *pMode)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TAG_FORMAT_OFFSET, pMode);
+}
+/* Function Name:
+ *      rtl8367c_setAsicCputagRxMinLength
+ * Description:
+ *      Set cpu tag mode
+ * Input:
+ *      mode - 1: 64bytes, 0: 72bytes
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_INPUT    - Invalid input parameters
+ * Note:
+ *      If CPU tag function is disabled, CPU tag will not be added to frame
+ *      forwarded to CPU port, and all ports cannot parse CPU tag.
+ */
+ret_t rtl8367c_setAsicCputagRxMinLength(rtk_uint32 mode)
+{
+    if(mode > 1)
+        return RT_ERR_INPUT;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TAG_RXBYTECOUNT_OFFSET, mode);
+}
+/* Function Name:
+ *      rtl8367c_getAsicCputagRxMinLength
+ * Description:
+ *      Get cpu tag mode
+ * Input:
+ *      pMode - 1: 64bytes, 0: 72bytes
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicCputagRxMinLength(rtk_uint32 *pMode)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TAG_RXBYTECOUNT_OFFSET, pMode);
+}
+
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_dot1x.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_dot1x.c
new file mode 100644
index 0000000..73153e1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_dot1x.c
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : 802.1X related functions
+ *
+ */
+#include <rtl8367c_asicdrv_dot1x.h>
+/* Function Name:
+ *      rtl8367c_setAsic1xPBEnConfig
+ * Description:
+ *      Set 802.1x port-based port enable configuration
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      enabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsic1xPBEnConfig(rtk_uint32 port, rtk_uint32 enabled)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_DOT1X_PORT_ENABLE_REG, port, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsic1xPBEnConfig
+ * Description:
+ *      Get 802.1x port-based port enable configuration
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pEnabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsic1xPBEnConfig(rtk_uint32 port, rtk_uint32 *pEnabled)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_DOT1X_PORT_ENABLE_REG, port, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsic1xPBAuthConfig
+ * Description:
+ *      Set 802.1x port-based authorised port configuration
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      auth    - 1: authorised, 0: non-authorised
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsic1xPBAuthConfig(rtk_uint32 port, rtk_uint32 auth)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_DOT1X_PORT_AUTH_REG, port, auth);
+}
+/* Function Name:
+ *      rtl8367c_getAsic1xPBAuthConfig
+ * Description:
+ *      Get 802.1x port-based authorised port configuration
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pAuth   - 1: authorised, 0: non-authorised
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsic1xPBAuthConfig(rtk_uint32 port, rtk_uint32 *pAuth)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_DOT1X_PORT_AUTH_REG, port, pAuth);
+}
+/* Function Name:
+ *      rtl8367c_setAsic1xPBOpdirConfig
+ * Description:
+ *      Set 802.1x port-based operational direction
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      opdir   - Operation direction 1: IN, 0:BOTH
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsic1xPBOpdirConfig(rtk_uint32 port, rtk_uint32 opdir)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_DOT1X_PORT_OPDIR_REG, port, opdir);
+}
+/* Function Name:
+ *      rtl8367c_getAsic1xPBOpdirConfig
+ * Description:
+ *      Get 802.1x port-based operational direction
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pOpdir  - Operation direction 1: IN, 0:BOTH
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsic1xPBOpdirConfig(rtk_uint32 port, rtk_uint32* pOpdir)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_DOT1X_PORT_OPDIR_REG, port, pOpdir);
+}
+/* Function Name:
+ *      rtl8367c_setAsic1xMBEnConfig
+ * Description:
+ *      Set 802.1x mac-based port enable configuration
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      enabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsic1xMBEnConfig(rtk_uint32 port, rtk_uint32 enabled)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_DOT1X_MAC_ENABLE_REG, port, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsic1xMBEnConfig
+ * Description:
+ *      Get 802.1x mac-based port enable configuration
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pEnabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsic1xMBEnConfig(rtk_uint32 port, rtk_uint32 *pEnabled)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_DOT1X_MAC_ENABLE_REG, port, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsic1xMBOpdirConfig
+ * Description:
+ *      Set 802.1x mac-based operational direction
+ * Input:
+ *      opdir       - Operation direction 1: IN, 0:BOTH
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsic1xMBOpdirConfig(rtk_uint32 opdir)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_DOT1X_CFG_REG, RTL8367C_DOT1X_MAC_OPDIR_OFFSET, opdir);
+}
+/* Function Name:
+ *      rtl8367c_getAsic1xMBOpdirConfig
+ * Description:
+ *      Get 802.1x mac-based operational direction
+ * Input:
+ *      pOpdir      - Operation direction 1: IN, 0:BOTH
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsic1xMBOpdirConfig(rtk_uint32 *pOpdir)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_DOT1X_CFG_REG, RTL8367C_DOT1X_MAC_OPDIR_OFFSET, pOpdir);
+}
+/* Function Name:
+ *      rtl8367c_setAsic1xProcConfig
+ * Description:
+ *      Set 802.1x unauth. behavior configuration
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      proc    - 802.1x unauth. behavior configuration 0:drop 1:trap to CPU 2:Guest VLAN
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_DOT1X_PROC   - Unauthorized behavior error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsic1xProcConfig(rtk_uint32 port, rtk_uint32 proc)
+{
+
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if(proc >= DOT1X_UNAUTH_END)
+        return RT_ERR_DOT1X_PROC;
+
+    if(port < 8)
+    {
+        return rtl8367c_setAsicRegBits(RTL8367C_DOT1X_UNAUTH_ACT_BASE, RTL8367C_DOT1X_UNAUTH_ACT_MASK(port),proc);
+    }
+    else
+    {
+        return rtl8367c_setAsicRegBits(RTL8367C_REG_DOT1X_UNAUTH_ACT_W1, RTL8367C_DOT1X_UNAUTH_ACT_MASK(port),proc);
+    }
+}
+/* Function Name:
+ *      rtl8367c_getAsic1xProcConfig
+ * Description:
+ *      Get 802.1x unauth. behavior configuration
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pProc   - 802.1x unauth. behavior configuration 0:drop 1:trap to CPU 2:Guest VLAN
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsic1xProcConfig(rtk_uint32 port, rtk_uint32* pProc)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if(port < 8)
+    return rtl8367c_getAsicRegBits(RTL8367C_DOT1X_UNAUTH_ACT_BASE, RTL8367C_DOT1X_UNAUTH_ACT_MASK(port),pProc);
+    else
+        return rtl8367c_getAsicRegBits(RTL8367C_REG_DOT1X_UNAUTH_ACT_W1, RTL8367C_DOT1X_UNAUTH_ACT_MASK(port),pProc);
+}
+/* Function Name:
+ *      rtl8367c_setAsic1xGuestVidx
+ * Description:
+ *      Set 802.1x guest vlan index
+ * Input:
+ *      index   - 802.1x guest vlan index (0~31)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_DOT1X_GVLANIDX   - Invalid cvid index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsic1xGuestVidx(rtk_uint32 index)
+{
+    if(index >= RTL8367C_CVIDXNO)
+        return RT_ERR_DOT1X_GVLANIDX;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_DOT1X_CFG_REG, RTL8367C_DOT1X_GVIDX_MASK, index);
+}
+/* Function Name:
+ *      rtl8367c_getAsic1xGuestVidx
+ * Description:
+ *      Get 802.1x guest vlan index
+ * Input:
+ *      pIndex  - 802.1x guest vlan index (0~31)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsic1xGuestVidx(rtk_uint32 *pIndex)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_DOT1X_CFG_REG, RTL8367C_DOT1X_GVIDX_MASK, pIndex);
+}
+/* Function Name:
+ *      rtl8367c_setAsic1xGVOpdir
+ * Description:
+ *      Set 802.1x guest vlan talk to auth. DA
+ * Input:
+ *      enabled     - 0:disable 1:enable
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsic1xGVOpdir(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_DOT1X_CFG_REG, RTL8367C_DOT1X_GVOPDIR_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsic1xGVOpdir
+ * Description:
+ *      Get 802.1x guest vlan talk to auth. DA
+ * Input:
+ *      pEnabled        - 0:disable 1:enable
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsic1xGVOpdir(rtk_uint32 *pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_DOT1X_CFG_REG, RTL8367C_DOT1X_GVOPDIR_OFFSET, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsic1xTrapPriority
+ * Description:
+ *      Set 802.1x Trap priority
+ * Input:
+ *      priority    - priority (0~7)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsic1xTrapPriority(rtk_uint32 priority)
+{
+    if(priority > RTL8367C_PRIMAX)
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_QOS_TRAP_PRIORITY0, RTL8367C_DOT1X_PRIORTY_MASK,priority);
+}
+/* Function Name:
+ *      rtl8367c_getAsic1xTrapPriority
+ * Description:
+ *      Get 802.1x Trap priority
+ * Input:
+ *      pPriority   - priority (0~7)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsic1xTrapPriority(rtk_uint32 *pPriority)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_QOS_TRAP_PRIORITY0, RTL8367C_DOT1X_PRIORTY_MASK, pPriority);
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eav.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eav.c
new file mode 100644
index 0000000..370b7c6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eav.c
@@ -0,0 +1,877 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Ethernet AV related functions
+ *
+ */
+
+#include <rtl8367c_asicdrv_eav.h>
+/* Function Name:
+ *      rtl8367c_setAsicEavMacAddress
+ * Description:
+ *      Set PTP MAC address
+ * Input:
+ *      mac     - PTP mac
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK         - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicEavMacAddress(ether_addr_t mac)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+    rtk_uint8 *accessPtr;
+    rtk_uint32 i;
+
+    accessPtr =  (rtk_uint8*)&mac;
+
+    regData = *accessPtr;
+    accessPtr ++;
+    regData = (regData << 8) | *accessPtr;
+    accessPtr ++;
+    for(i = 0; i <=2; i++)
+    {
+        retVal = rtl8367c_setAsicReg(RTL8367C_REG_MAC_ADDR_H - i, regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        regData = *accessPtr;
+        accessPtr ++;
+        regData = (regData << 8) | *accessPtr;
+        accessPtr ++;
+    }
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicEavMacAddress
+ * Description:
+ *      Get PTP MAC address
+ * Input:
+ *      None
+ * Output:
+ *      pMac     - PTP  mac
+ * Return:
+ *      RT_ERR_OK         - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicEavMacAddress(ether_addr_t *pMac)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+    rtk_uint8 *accessPtr;
+    rtk_uint32 i;
+
+    accessPtr = (rtk_uint8*)pMac;
+
+    for(i = 0; i <= 2; i++)
+    {
+        retVal = rtl8367c_getAsicReg(RTL8367C_REG_MAC_ADDR_H - i, &regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        *accessPtr = (regData & 0xFF00) >> 8;
+        accessPtr ++;
+        *accessPtr = regData & 0xFF;
+        accessPtr ++;
+    }
+
+    return retVal;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicEavTpid
+ * Description:
+ *      Set PTP parser tag TPID.
+ * Input:
+ *       outerTag - outter tag TPID
+ *       innerTag  - inner tag TPID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *     None
+ */
+ret_t rtl8367c_setAsicEavTpid(rtk_uint32 outerTag, rtk_uint32 innerTag)
+{
+    ret_t retVal;
+
+    if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_OTAG_TPID, outerTag)) != RT_ERR_OK)
+        return retVal;
+    if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_ITAG_TPID, innerTag)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicEavTpid
+ * Description:
+ *      Get PTP parser tag TPID.
+ * Input:
+ *      None
+ * Output:
+ *       pOuterTag - outter tag TPID
+ *       pInnerTag  - inner tag TPID
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicEavTpid(rtk_uint32* pOuterTag, rtk_uint32* pInnerTag)
+{
+    ret_t retVal;
+
+    if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_OTAG_TPID, pOuterTag)) != RT_ERR_OK)
+        return retVal;
+    if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_ITAG_TPID, pInnerTag)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicEavSysTime
+ * Description:
+ *      Set PTP system time
+ * Input:
+ *      second - seconds
+ *      nanoSecond - nano seconds
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK     - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      The time granuality is 8 nano seconds.
+ */
+ret_t rtl8367c_setAsicEavSysTime(rtk_uint32 second, rtk_uint32 nanoSecond)
+{
+    ret_t retVal;
+    rtk_uint32 sec_h, sec_l, nsec8_h, nsec8_l;
+    rtk_uint32 nano_second_8;
+    rtk_uint32 regData, busyFlag, count;
+
+    if(nanoSecond > RTL8367C_EAV_NANOSECONDMAX)
+        return RT_ERR_INPUT;
+
+    regData = 0;
+    sec_h = second >>16;
+    sec_l = second & 0xFFFF;
+    nano_second_8 = nanoSecond >> 3;
+    nsec8_h = (nano_second_8 >>16) & RTL8367C_PTP_TIME_NSEC_H_NSEC_MASK;
+    nsec8_l = nano_second_8 &0xFFFF;
+
+    if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_SEC_H_SEC, sec_h)) != RT_ERR_OK)
+        return retVal;
+    if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_SEC_L_SEC, sec_l)) != RT_ERR_OK)
+        return retVal;
+    if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_NSEC_L_NSEC, nsec8_l)) != RT_ERR_OK)
+        return retVal;
+
+    regData = nsec8_h | (PTP_TIME_WRITE<<RTL8367C_PTP_TIME_NSEC_H_CMD_OFFSET) | RTL8367C_PTP_TIME_NSEC_H_EXEC_MASK;
+
+    if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_NSEC_H_NSEC, regData)) != RT_ERR_OK)
+        return retVal;
+
+    count = 0;
+    do {
+        if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_PTP_TIME_NSEC_H_NSEC, RTL8367C_PTP_TIME_NSEC_H_EXEC_OFFSET, &busyFlag)) != RT_ERR_OK)
+            return retVal;
+        count++;
+    } while ((busyFlag != 0)&&(count<5));
+
+    if (busyFlag != 0)
+        return RT_ERR_BUSYWAIT_TIMEOUT;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicEavSysTime
+ * Description:
+ *      Get PTP system time
+ * Input:
+ *      None
+ * Output:
+ *      second - seconds
+ *      nanoSecond - nano seconds
+ * Return:
+ *      RT_ERR_OK     - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      The time granuality is 8 nano seconds.
+ */
+ret_t rtl8367c_getAsicEavSysTime(rtk_uint32* pSecond, rtk_uint32* pNanoSecond)
+{
+    ret_t retVal;
+    rtk_uint32 sec_h, sec_l, nsec8_h, nsec8_l;
+    rtk_uint32 nano_second_8;
+    rtk_uint32 regData, busyFlag, count;
+
+    regData = 0;
+    regData = (PTP_TIME_READ<<RTL8367C_PTP_TIME_NSEC_H_CMD_OFFSET) | RTL8367C_PTP_TIME_NSEC_H_EXEC_MASK;
+
+    if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_NSEC_H_NSEC, regData)) != RT_ERR_OK)
+        return retVal;
+
+    count = 0;
+    do {
+        if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_PTP_TIME_NSEC_H_NSEC, RTL8367C_PTP_TIME_NSEC_H_EXEC_OFFSET, &busyFlag)) != RT_ERR_OK)
+            return retVal;
+        count++;
+    } while ((busyFlag != 0)&&(count<5));
+
+    if (busyFlag != 0)
+        return RT_ERR_BUSYWAIT_TIMEOUT;
+
+    if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_PTP_TIME_SEC_H_SEC_RD, &sec_h)) != RT_ERR_OK)
+        return retVal;
+    if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_PTP_TIME_SEC_L_SEC_RD, &sec_l)) != RT_ERR_OK)
+        return retVal;
+    if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_PTP_TIME_NSEC_H_NSEC_RD, RTL8367C_PTP_TIME_NSEC_H_NSEC_RD_MASK,&nsec8_h)) != RT_ERR_OK)
+        return retVal;
+    if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_PTP_TIME_NSEC_L_NSEC_RD, &nsec8_l)) != RT_ERR_OK)
+        return retVal;
+
+    *pSecond = (sec_h<<16) | sec_l;
+    nano_second_8 = (nsec8_h<<16) | nsec8_l;
+    *pNanoSecond = nano_second_8<<3;
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtl8367c_setAsicEavSysTimeAdjust
+ * Description:
+ *      Set PTP system time adjust
+ * Input:
+ *      type - incresae or decrease
+ *      second - seconds
+ *      nanoSecond - nano seconds
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK     - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      Ethernet AV second offset of timer for tuning
+ */
+ret_t rtl8367c_setAsicEavSysTimeAdjust(rtk_uint32 type, rtk_uint32 second, rtk_uint32 nanoSecond)
+{
+    ret_t retVal;
+    rtk_uint32 sec_h, sec_l, nsec8_h, nsec8_l;
+    rtk_uint32 nano_second_8;
+    rtk_uint32 regData, busyFlag, count;
+
+    if (type >= PTP_TIME_ADJ_END)
+        return RT_ERR_INPUT;
+    if(nanoSecond > RTL8367C_EAV_NANOSECONDMAX)
+        return RT_ERR_INPUT;
+
+    regData = 0;
+    sec_h = second >>16;
+    sec_l = second & 0xFFFF;
+    nano_second_8 = nanoSecond >> 3;
+    nsec8_h = (nano_second_8 >>16) & RTL8367C_PTP_TIME_NSEC_H_NSEC_MASK;
+    nsec8_l = nano_second_8 &0xFFFF;
+
+    if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_SEC_H_SEC, sec_h)) != RT_ERR_OK)
+        return retVal;
+    if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_SEC_L_SEC, sec_l)) != RT_ERR_OK)
+        return retVal;
+    if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_NSEC_L_NSEC, nsec8_l)) != RT_ERR_OK)
+        return retVal;
+
+    if (PTP_TIME_ADJ_INC == type)
+        regData = nsec8_h | (PTP_TIME_INC<<RTL8367C_PTP_TIME_NSEC_H_CMD_OFFSET) | RTL8367C_PTP_TIME_NSEC_H_EXEC_MASK;
+    else
+        regData = nsec8_h | (PTP_TIME_DEC<<RTL8367C_PTP_TIME_NSEC_H_CMD_OFFSET) | RTL8367C_PTP_TIME_NSEC_H_EXEC_MASK;
+
+    if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_NSEC_H_NSEC, regData)) != RT_ERR_OK)
+        return retVal;
+
+    count = 0;
+    do {
+        if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_PTP_TIME_NSEC_H_NSEC, RTL8367C_PTP_TIME_NSEC_H_EXEC_OFFSET, &busyFlag)) != RT_ERR_OK)
+            return retVal;
+        count++;
+    } while ((busyFlag != 0)&&(count<5));
+
+    if (busyFlag != 0)
+        return RT_ERR_BUSYWAIT_TIMEOUT;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicEavSysTimeCtrl
+ * Description:
+ *      Set PTP system time control
+ * Input:
+ *      command - start or stop
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK     - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicEavSysTimeCtrl(rtk_uint32 control)
+{
+    ret_t  retVal;
+    rtk_uint32 regData;
+
+    if (control>=PTP_TIME_CTRL_END)
+         return RT_ERR_INPUT;
+
+    regData = 0;
+    if (PTP_TIME_CTRL_START == control)
+            regData = RTL8367C_CFG_TIMER_EN_FRC_MASK | RTL8367C_CFG_TIMER_1588_EN_MASK;
+    else
+        regData = 0;
+
+    if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_CFG, regData)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicEavSysTimeCtrl
+ * Description:
+ *      Get PTP system time control
+ * Input:
+ *      None
+ * Output:
+ *      pControl - start or stop
+ * Return:
+ *      RT_ERR_OK     - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicEavSysTimeCtrl(rtk_uint32* pControl)
+{
+    ret_t  retVal;
+    rtk_uint32 regData;
+    rtk_uint32 mask;
+
+    mask = RTL8367C_CFG_TIMER_EN_FRC_MASK | RTL8367C_CFG_TIMER_1588_EN_MASK;
+
+    if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_PTP_TIME_CFG, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    if( (regData & mask) == mask)
+        *pControl = PTP_TIME_CTRL_START;
+    else if( (regData & mask) == 0)
+        *pControl = PTP_TIME_CTRL_STOP;
+    else
+        return RT_ERR_NOT_ALLOWED;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicEavInterruptMask
+ * Description:
+ *      Set PTP interrupt enable mask
+ * Input:
+ *      imr     - Interrupt mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      [0]:TX_SYNC,
+ *      [1]:TX_DELAY,
+ *      [2]:TX_PDELAY_REQ,
+ *      [3]:TX_PDELAY_RESP,
+ *      [4]:RX_SYNC,
+ *      [5]:RX_DELAY,
+ *      [6]:RX_PDELAY_REQ,
+ *      [7]:RX_PDELAY_RESP,
+ */
+ret_t rtl8367c_setAsicEavInterruptMask(rtk_uint32 imr)
+{
+    if ((imr&(RTL8367C_PTP_INTR_MASK<<8))>0)
+         return RT_ERR_INPUT;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_PTP_TIME_CFG2, RTL8367C_PTP_INTR_MASK, imr);
+}
+/* Function Name:
+ *      rtl8367c_getAsicEavInterruptMask
+ * Description:
+ *      Get PTP interrupt enable mask
+ * Input:
+ *      pImr    - Interrupt mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      [0]:TX_SYNC,
+ *      [1]:TX_DELAY,
+ *      [2]:TX_PDELAY_REQ,
+ *      [3]:TX_PDELAY_RESP,
+ *      [4]:RX_SYNC,
+ *      [5]:RX_DELAY,
+ *      [6]:RX_PDELAY_REQ,
+ *      [7]:RX_PDELAY_RESP,
+ */
+ret_t rtl8367c_getAsicEavInterruptMask(rtk_uint32* pImr)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_PTP_TIME_CFG2, RTL8367C_PTP_INTR_MASK, pImr);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicEavInterruptStatus
+ * Description:
+ *      Get PTP interrupt port status mask
+ * Input:
+ *      pIms    - Interrupt mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      [0]:p0 interrupt,
+ *      [1]:p1 interrupt,
+ *      [2]:p2 interrupt,
+ *      [3]:p3 interrupt,
+ *      [4]:p4 interrupt,
+ */
+ret_t rtl8367c_getAsicEavInterruptStatus(rtk_uint32* pIms)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_PTP_INTERRUPT_CFG, RTL8367C_PTP_PORT_MASK, pIms);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicInterruptMask
+ * Description:
+ *      Clear interrupt enable mask
+ * Input:
+ *      ims     - Interrupt status mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      This API can be used to clear ASIC interrupt status and register will be cleared by writting 1.
+ *      [0]:TX_SYNC,
+ *      [1]:TX_DELAY,
+ *      [2]:TX_PDELAY_REQ,
+ *      [3]:TX_PDELAY_RESP,
+ *      [4]:RX_SYNC,
+ *      [5]:RX_DELAY,
+ *      [6]:RX_PDELAY_REQ,
+ *      [7]:RX_PDELAY_RESP,
+ */
+ret_t rtl8367c_setAsicEavPortInterruptStatus(rtk_uint32 port, rtk_uint32 ims)
+{
+
+    if(port > RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if(port < 5)
+        return rtl8367c_setAsicRegBits(RTL8367C_EAV_PORT_CFG_REG(port), RTL8367C_PTP_INTR_MASK,ims);
+    else if(port == 5)
+        return rtl8367c_setAsicRegBits(RTL8367C_REG_P5_EAV_CFG, RTL8367C_PTP_INTR_MASK,ims);
+    else if(port == 6)
+        return rtl8367c_setAsicRegBits(RTL8367C_REG_P6_EAV_CFG, RTL8367C_PTP_INTR_MASK,ims);
+    else if(port == 7)
+        return rtl8367c_setAsicRegBits(RTL8367C_REG_P7_EAV_CFG, RTL8367C_PTP_INTR_MASK,ims);
+    else if(port == 8)
+        return rtl8367c_setAsicRegBits(RTL8367C_REG_P8_EAV_CFG, RTL8367C_PTP_INTR_MASK,ims);
+    else if(port == 9)
+        return rtl8367c_setAsicRegBits(RTL8367C_REG_P9_EAV_CFG, RTL8367C_PTP_INTR_MASK,ims);
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicInterruptStatus
+ * Description:
+ *      Get interrupt enable mask
+ * Input:
+ *      pIms    - Interrupt status mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      [0]:TX_SYNC,
+ *      [1]:TX_DELAY,
+ *      [2]:TX_PDELAY_REQ,
+ *      [3]:TX_PDELAY_RESP,
+ *      [4]:RX_SYNC,
+ *      [5]:RX_DELAY,
+ *      [6]:RX_PDELAY_REQ,
+ *      [7]:RX_PDELAY_RESP,
+ */
+ret_t rtl8367c_getAsicEavPortInterruptStatus(rtk_uint32 port, rtk_uint32* pIms)
+{
+
+    if(port > RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+    if(port < 5)
+        return rtl8367c_getAsicRegBits(RTL8367C_EAV_PORT_CFG_REG(port), RTL8367C_PTP_INTR_MASK, pIms);
+    else if(port == 5)
+        return rtl8367c_getAsicRegBits(RTL8367C_REG_P5_EAV_CFG, RTL8367C_PTP_INTR_MASK, pIms);
+    else if(port == 6)
+        return rtl8367c_getAsicRegBits(RTL8367C_REG_P6_EAV_CFG, RTL8367C_PTP_INTR_MASK,pIms);
+    else if(port == 7)
+        return rtl8367c_getAsicRegBits(RTL8367C_REG_P7_EAV_CFG, RTL8367C_PTP_INTR_MASK,pIms);
+    else if(port == 8)
+        return rtl8367c_getAsicRegBits(RTL8367C_REG_P8_EAV_CFG, RTL8367C_PTP_INTR_MASK,pIms);
+    else if(port == 9)
+        return rtl8367c_getAsicRegBits(RTL8367C_REG_P9_EAV_CFG, RTL8367C_PTP_INTR_MASK,pIms);
+
+    return RT_ERR_OK;
+
+}
+
+
+/* Function Name:
+ *      rtl8367c_setAsicEavPortEnable
+ * Description:
+ *      Set per-port EAV function enable/disable
+ * Input:
+ *      port         - Physical port number (0~9)
+ *      enabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK         - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      If EAV function is enabled, PTP event messgae packet will be attached PTP timestamp for trapping
+ */
+ret_t rtl8367c_setAsicEavPortEnable(rtk_uint32 port, rtk_uint32 enabled)
+{
+    if(port > RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if(port < 5)
+        return rtl8367c_setAsicRegBit(RTL8367C_EAV_PORT_CFG_REG(port), RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, enabled);
+    else if(port == 5)
+        return rtl8367c_setAsicRegBit(RTL8367C_REG_P5_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, enabled);
+    else if(port == 6)
+        return rtl8367c_setAsicRegBit(RTL8367C_REG_P6_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, enabled);
+    else if(port == 7)
+        return rtl8367c_setAsicRegBit(RTL8367C_REG_P7_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, enabled);
+    else if(port == 8)
+        return rtl8367c_setAsicRegBit(RTL8367C_REG_P8_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, enabled);
+    else if(port == 9)
+        return rtl8367c_setAsicRegBit(RTL8367C_REG_P9_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, enabled);
+
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicEavPortEnable
+ * Description:
+ *      Get per-port EAV function enable/disable
+ * Input:
+ *      port         - Physical port number (0~9)
+ *      pEnabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK         - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicEavPortEnable(rtk_uint32 port, rtk_uint32 *pEnabled)
+{
+    if(port > RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+
+
+    if(port < 5)
+        return rtl8367c_getAsicRegBit(RTL8367C_EAV_PORT_CFG_REG(port), RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, pEnabled);
+    else if(port == 5)
+        return rtl8367c_getAsicRegBit(RTL8367C_REG_P5_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, pEnabled);
+    else if(port == 6)
+        return rtl8367c_getAsicRegBit(RTL8367C_REG_P6_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, pEnabled);
+    else if(port == 7)
+        return rtl8367c_getAsicRegBit(RTL8367C_REG_P7_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, pEnabled);
+    else if(port == 8)
+        return rtl8367c_getAsicRegBit(RTL8367C_REG_P8_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, pEnabled);
+    else if(port == 9)
+        return rtl8367c_getAsicRegBit(RTL8367C_REG_P9_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, pEnabled);
+
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicEavPortTimeStamp
+ * Description:
+ *      Get PTP port time stamp
+ * Input:
+ *      port         - Physical port number (0~9)
+ *      type     -  PTP packet type
+ * Output:
+ *      timeStamp - seconds
+ * Return:
+ *      RT_ERR_OK     - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      The time granuality is 8 nano seconds.
+ */
+ret_t rtl8367c_getAsicEavPortTimeStamp(rtk_uint32 port, rtk_uint32 type, rtl8367c_ptp_time_stamp_t* timeStamp)
+{
+    ret_t retVal;
+    rtk_uint32 sec_h, sec_l, nsec8_h, nsec8_l;
+    rtk_uint32 nano_second_8;
+
+    if(port > 9)
+        return RT_ERR_PORT_ID;
+    if(type >= PTP_PKT_TYPE_END)
+        return RT_ERR_INPUT;
+
+    if(port < 5){
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_SEQ_ID(port, type), &timeStamp->sequence_id))!=  RT_ERR_OK)
+            return retVal;
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_PORT_SEC_H(port) , &sec_h)) != RT_ERR_OK)
+           return retVal;
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_PORT_SEC_L(port), &sec_l)) != RT_ERR_OK)
+           return retVal;
+        if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_NSEC_H(port) , RTL8367C_PORT_NSEC_H_MASK,&nsec8_h)) != RT_ERR_OK)
+           return retVal;
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_PORT_NSEC_L(port) , &nsec8_l)) != RT_ERR_OK)
+           return retVal;
+    }else if(port == 5){
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P5_TX_SYNC_SEQ_ID+type, &timeStamp->sequence_id))!=  RT_ERR_OK)
+            return retVal;
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P5_PORT_SEC_31_16, &sec_h)) != RT_ERR_OK)
+           return retVal;
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P5_PORT_SEC_15_0, &sec_l)) != RT_ERR_OK)
+           return retVal;
+        if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_P5_PORT_NSEC_26_16 , RTL8367C_PORT_NSEC_H_MASK,&nsec8_h)) != RT_ERR_OK)
+           return retVal;
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P5_PORT_NSEC_15_0, &nsec8_l)) != RT_ERR_OK)
+           return retVal;
+    }else if(port == 6){
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P6_TX_SYNC_SEQ_ID+type, &timeStamp->sequence_id))!=  RT_ERR_OK)
+            return retVal;
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P6_PORT_SEC_31_16, &sec_h)) != RT_ERR_OK)
+           return retVal;
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P6_PORT_SEC_15_0, &sec_l)) != RT_ERR_OK)
+           return retVal;
+        if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_P6_PORT_NSEC_26_16 , RTL8367C_PORT_NSEC_H_MASK,&nsec8_h)) != RT_ERR_OK)
+           return retVal;
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P6_PORT_NSEC_15_0, &nsec8_l)) != RT_ERR_OK)
+           return retVal;
+    }else if(port == 7){
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P7_TX_SYNC_SEQ_ID+type, &timeStamp->sequence_id))!=  RT_ERR_OK)
+            return retVal;
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P7_PORT_SEC_31_16, &sec_h)) != RT_ERR_OK)
+           return retVal;
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P7_PORT_SEC_15_0, &sec_l)) != RT_ERR_OK)
+           return retVal;
+        if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_P7_PORT_NSEC_26_16 , RTL8367C_PORT_NSEC_H_MASK,&nsec8_h)) != RT_ERR_OK)
+           return retVal;
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P7_PORT_NSEC_15_0, &nsec8_l)) != RT_ERR_OK)
+           return retVal;
+    }else if(port == 8){
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P8_TX_SYNC_SEQ_ID+type, &timeStamp->sequence_id))!=  RT_ERR_OK)
+            return retVal;
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P8_PORT_SEC_31_16, &sec_h)) != RT_ERR_OK)
+           return retVal;
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P8_PORT_SEC_15_0, &sec_l)) != RT_ERR_OK)
+           return retVal;
+        if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_P8_PORT_NSEC_26_16 , RTL8367C_PORT_NSEC_H_MASK,&nsec8_h)) != RT_ERR_OK)
+           return retVal;
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P8_PORT_NSEC_15_0, &nsec8_l)) != RT_ERR_OK)
+           return retVal;
+    }else if(port == 9){
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P9_TX_SYNC_SEQ_ID+type, &timeStamp->sequence_id))!=  RT_ERR_OK)
+            return retVal;
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P9_PORT_SEC_31_16, &sec_h)) != RT_ERR_OK)
+           return retVal;
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P9_PORT_SEC_15_0, &sec_l)) != RT_ERR_OK)
+           return retVal;
+        if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_P9_PORT_NSEC_26_16 , RTL8367C_PORT_NSEC_H_MASK,&nsec8_h)) != RT_ERR_OK)
+           return retVal;
+        if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P9_PORT_NSEC_15_0, &nsec8_l)) != RT_ERR_OK)
+           return retVal;
+    }
+
+    timeStamp->second = (sec_h<<16) | sec_l;
+    nano_second_8 = (nsec8_h<<16) | nsec8_l;
+    timeStamp->nano_second = nano_second_8<<3;
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtl8367c_setAsicEavTrap
+ * Description:
+ *      Set per-port PTP packet trap to CPU
+ * Input:
+ *      port         - Physical port number (0~5)
+ *      enabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK         - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      If EAV trap enabled, switch will trap PTP packet to CPU
+ */
+ret_t rtl8367c_setAsicEavTrap(rtk_uint32 port, rtk_uint32 enabled)
+{
+    if(port > RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_PTP_PORT0_CFG1 + (port * 0x20), RTL8367C_PTP_PORT0_CFG1_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicEavTimeSyncEn
+ * Description:
+ *      Get per-port EPTP packet trap to CPU
+ * Input:
+ *      port         - Physical port number (0~5)
+ *      pEnabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK         - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicEavTrap(rtk_uint32 port, rtk_uint32 *pEnabled)
+{
+    if(port > RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_PTP_PORT0_CFG1 + (port * 0x20), RTL8367C_PTP_PORT0_CFG1_OFFSET, pEnabled);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicEavEnable
+ * Description:
+ *      Set per-port EAV function enable/disable
+ * Input:
+ *      port         - Physical port number (0~5)
+ *      enabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK         - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      If EAV function is enabled, PTP event messgae packet will be attached PTP timestamp for trapping
+ */
+ret_t rtl8367c_setAsicEavEnable(rtk_uint32 port, rtk_uint32 enabled)
+{
+    if(port > RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_EAV_CTRL0, port, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicEavEnable
+ * Description:
+ *      Get per-port EAV function enable/disable
+ * Input:
+ *      port         - Physical port number (0~5)
+ *      pEnabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK         - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicEavEnable(rtk_uint32 port, rtk_uint32 *pEnabled)
+{
+    if(port > RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_EAV_CTRL0, port, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicEavPriRemapping
+ * Description:
+ *      Set non-EAV streaming priority remapping
+ * Input:
+ *      srcpriority - Priority value
+ *      priority     - Absolute priority value
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                     - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY      - Invalid priority
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicEavPriRemapping(rtk_uint32 srcpriority, rtk_uint32 priority)
+{
+    if(srcpriority > RTL8367C_PRIMAX || priority > RTL8367C_PRIMAX)
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_EAV_PRIORITY_REMAPPING_REG(srcpriority), RTL8367C_EAV_PRIORITY_REMAPPING_MASK(srcpriority),priority);
+}
+/* Function Name:
+ *      rtl8367c_getAsicEavPriRemapping
+ * Description:
+ *      Get non-EAV streaming priority remapping
+ * Input:
+ *      srcpriority - Priority value
+ *      pPriority     - Absolute priority value
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                     - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY      - Invalid priority
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicEavPriRemapping(rtk_uint32 srcpriority, rtk_uint32 *pPriority)
+{
+    if(srcpriority > RTL8367C_PRIMAX )
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_EAV_PRIORITY_REMAPPING_REG(srcpriority), RTL8367C_EAV_PRIORITY_REMAPPING_MASK(srcpriority),pPriority);
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eee.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eee.c
new file mode 100644
index 0000000..f4dda6a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eee.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 48989 $
+ * $Date: 2014-07-01 15:45:24 +0800 (週二, 01 七月 2014) $
+ *
+ * Purpose : RTL8370 switch high-level API for RTL8367C
+ * Feature :
+ *
+ */
+
+#include <rtl8367c_asicdrv_eee.h>
+#include <rtl8367c_asicdrv_phy.h>
+
+/*
+@func ret_t | rtl8367c_setAsicEee100M | Set eee force mode function enable/disable.
+@parm rtk_uint32 | port | The port number.
+@parm rtk_uint32 | enabled | 1: enabled, 0: disabled.
+@rvalue RT_ERR_OK | Success.
+@rvalue RT_ERR_SMI | SMI access error.
+@rvalue RT_ERR_INPUT | Invalid input parameter.
+@comm
+    This API set the 100M EEE enable function.
+
+*/
+ret_t rtl8367c_setAsicEee100M(rtk_uint32 port, rtk_uint32 enable)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32      regData;
+
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if (enable > 1)
+        return RT_ERR_INPUT;
+
+    if((retVal = rtl8367c_getAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    if(enable)
+        regData |= (0x0001 << 1);
+    else
+        regData &= ~(0x0001 << 1);
+
+    if((retVal = rtl8367c_setAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, regData)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/*
+@func ret_t | rtl8367c_getAsicEee100M | Get 100M eee enable/disable.
+@parm rtk_uint32 | port | The port number.
+@parm rtk_uint32* | enabled | 1: enabled, 0: disabled.
+@rvalue RT_ERR_OK | Success.
+@rvalue RT_ERR_SMI | SMI access error.
+@rvalue RT_ERR_INPUT | Invalid input parameter.
+@comm
+    This API get the 100M EEE function.
+*/
+ret_t rtl8367c_getAsicEee100M(rtk_uint32 port, rtk_uint32 *enable)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32      regData;
+
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if((retVal = rtl8367c_getAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    *enable = (regData & (0x0001 << 1)) ? ENABLED : DISABLED;
+    return RT_ERR_OK;
+}
+
+/*
+@func ret_t | rtl8367c_setAsicEeeGiga | Set eee force mode function enable/disable.
+@parm rtk_uint32 | port | The port number.
+@parm rtk_uint32 | enabled | 1: enabled, 0: disabled.
+@rvalue RT_ERR_OK | Success.
+@rvalue RT_ERR_SMI | SMI access error.
+@rvalue RT_ERR_INPUT | Invalid input parameter.
+@comm
+    This API set the 100M EEE enable function.
+
+*/
+ret_t rtl8367c_setAsicEeeGiga(rtk_uint32 port, rtk_uint32 enable)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32      regData;
+
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if (enable > 1)
+        return RT_ERR_INPUT;
+
+    if((retVal = rtl8367c_getAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    if(enable)
+        regData |= (0x0001 << 2);
+    else
+        regData &= ~(0x0001 << 2);
+
+    if((retVal = rtl8367c_setAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, regData)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/*
+@func ret_t | rtl8367c_getAsicEeeGiga | Get 100M eee enable/disable.
+@parm rtk_uint32 | port | The port number.
+@parm rtk_uint32* | enabled | 1: enabled, 0: disabled.
+@rvalue RT_ERR_OK | Success.
+@rvalue RT_ERR_SMI | SMI access error.
+@rvalue RT_ERR_INPUT | Invalid input parameter.
+@comm
+    This API get the 100M EEE function.
+*/
+ret_t rtl8367c_getAsicEeeGiga(rtk_uint32 port, rtk_uint32 *enable)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32      regData;
+
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if((retVal = rtl8367c_getAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    *enable = (regData & (0x0001 << 2)) ? ENABLED : DISABLED;
+    return RT_ERR_OK;
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_fc.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_fc.c
new file mode 100644
index 0000000..28f49b1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_fc.c
@@ -0,0 +1,1354 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Flow control related functions
+ *
+ */
+
+#include <rtl8367c_asicdrv_fc.h>
+/* Function Name:
+ *      rtl8367c_setAsicFlowControlSelect
+ * Description:
+ *      Set system flow control type
+ * Input:
+ *      select      - System flow control type 1: Ingress flow control 0:Egress flow control
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicFlowControlSelect(rtk_uint32 select)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_FLOWCTRL_CTRL0, RTL8367C_FLOWCTRL_TYPE_OFFSET, select);
+}
+/* Function Name:
+ *      rtl8367c_getAsicFlowControlSelect
+ * Description:
+ *      Get system flow control type
+ * Input:
+ *      pSelect         - System flow control type 1: Ingress flow control 0:Egress flow control
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicFlowControlSelect(rtk_uint32 *pSelect)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_FLOWCTRL_CTRL0, RTL8367C_FLOWCTRL_TYPE_OFFSET, pSelect);
+}
+/* Function Name:
+ *      rtl8367c_setAsicFlowControlJumboMode
+ * Description:
+ *      Set Jumbo threhsold for flow control
+ * Input:
+ *      enabled         - Jumbo mode flow control 1: Enable 0:Disable
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicFlowControlJumboMode(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_FLOWCTRL_JUMBO_SIZE, RTL8367C_JUMBO_MODE_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicFlowControlJumboMode
+ * Description:
+ *      Get Jumbo threhsold for flow control
+ * Input:
+ *      pEnabled        - Jumbo mode flow control 1: Enable 0:Disable
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicFlowControlJumboMode(rtk_uint32* pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_FLOWCTRL_JUMBO_SIZE, RTL8367C_JUMBO_MODE_OFFSET, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicFlowControlJumboModeSize
+ * Description:
+ *      Set Jumbo size for Jumbo mode flow control
+ * Input:
+ *      size        - Jumbo size 0:3Kbytes 1:4Kbytes 2:6Kbytes 3:9Kbytes
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicFlowControlJumboModeSize(rtk_uint32 size)
+{
+    if(size >= FC_JUMBO_SIZE_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SIZE, RTL8367C_JUMBO_SIZE_MASK, size);
+}
+/* Function Name:
+ *      rtl8367c_getAsicFlowControlJumboModeSize
+ * Description:
+ *      Get Jumbo size for Jumbo mode flow control
+ * Input:
+ *      pSize       - Jumbo size 0:3Kbytes 1:4Kbytes 2:6Kbytes 3:9Kbytes
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicFlowControlJumboModeSize(rtk_uint32* pSize)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SIZE, RTL8367C_JUMBO_SIZE_MASK, pSize);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicFlowControlQueueEgressEnable
+ * Description:
+ *      Set flow control ability for each queue
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      qid     - Queue id
+ *      enabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ *      RT_ERR_QUEUE_ID - Invalid queue id
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicFlowControlQueueEgressEnable(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 enabled)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(qid > RTL8367C_QIDMAX)
+        return RT_ERR_QUEUE_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG(port), RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG_OFFSET(port)+ qid, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicFlowControlQueueEgressEnable
+ * Description:
+ *      Get flow control ability for each queue
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      qid     - Queue id
+ *      pEnabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ *      RT_ERR_QUEUE_ID - Invalid queue id
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicFlowControlQueueEgressEnable(rtk_uint32 port, rtk_uint32 qid, rtk_uint32* pEnabled)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(qid > RTL8367C_QIDMAX)
+        return RT_ERR_QUEUE_ID;
+
+    return  rtl8367c_getAsicRegBit(RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG(port), RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG_OFFSET(port)+ qid, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicFlowControlDropAll
+ * Description:
+ *      Set system-based drop parameters
+ * Input:
+ *      dropall     - Whole system drop threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicFlowControlDropAll(rtk_uint32 dropall)
+{
+    if(dropall >= RTL8367C_PAGE_NUMBER)
+        return RT_ERR_OUT_OF_RANGE;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_CTRL0, RTL8367C_DROP_ALL_THRESHOLD_MASK, dropall);
+}
+/* Function Name:
+ *      rtl8367c_getAsicFlowControlDropAll
+ * Description:
+ *      Get system-based drop parameters
+ * Input:
+ *      pDropall    - Whole system drop threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicFlowControlDropAll(rtk_uint32* pDropall)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_CTRL0, RTL8367C_DROP_ALL_THRESHOLD_MASK, pDropall);
+}
+/* Function Name:
+ *      rtl8367c_setAsicFlowControlPauseAll
+ * Description:
+ *      Set system-based all ports enable flow control parameters
+ * Input:
+ *      threshold   - Whole system pause all threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicFlowControlPauseAllThreshold(rtk_uint32 threshold)
+{
+    if(threshold >= RTL8367C_PAGE_NUMBER)
+        return RT_ERR_OUT_OF_RANGE;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_ALL_ON, RTL8367C_FLOWCTRL_ALL_ON_THRESHOLD_MASK, threshold);
+}
+/* Function Name:
+ *      rtl8367c_getAsicFlowControlPauseAllThreshold
+ * Description:
+ *      Get system-based all ports enable flow control parameters
+ * Input:
+ *      pThreshold  - Whole system pause all threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicFlowControlPauseAllThreshold(rtk_uint32 *pThreshold)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_ALL_ON, RTL8367C_FLOWCTRL_ALL_ON_THRESHOLD_MASK, pThreshold);
+}
+/* Function Name:
+ *      rtl8367c_setAsicFlowControlSystemThreshold
+ * Description:
+ *      Set system-based flow control parameters
+ * Input:
+ *      onThreshold     - Flow control turn ON threshold
+ *      offThreshold    - Flow control turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicFlowControlSystemThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold)
+{
+    ret_t retVal;
+
+    if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER))
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_SYS_OFF, RTL8367C_FLOWCTRL_SYS_OFF_MASK, offThreshold);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_SYS_ON, RTL8367C_FLOWCTRL_SYS_ON_MASK, onThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicFlowControlSystemThreshold
+ * Description:
+ *      Get system-based flow control parameters
+ * Input:
+ *      pOnThreshold    - Flow control turn ON threshold
+ *      pOffThreshold   - Flow control turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicFlowControlSystemThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_SYS_OFF, RTL8367C_FLOWCTRL_SYS_OFF_MASK, pOffThreshold);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_SYS_ON, RTL8367C_FLOWCTRL_SYS_ON_MASK, pOnThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_setAsicFlowControlSharedThreshold
+ * Description:
+ *      Set share-based flow control parameters
+ * Input:
+ *      onThreshold     - Flow control turn ON threshold
+ *      offThreshold    - Flow control turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicFlowControlSharedThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold)
+{
+    ret_t retVal;
+
+    if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER))
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_SHARE_OFF, RTL8367C_FLOWCTRL_SHARE_OFF_MASK, offThreshold);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_SHARE_ON, RTL8367C_FLOWCTRL_SHARE_ON_MASK, onThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicFlowControlSharedThreshold
+ * Description:
+ *      Get share-based flow control parameters
+ * Input:
+ *      pOnThreshold    - Flow control turn ON threshold
+ *      pOffThreshold   - Flow control turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicFlowControlSharedThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_SHARE_OFF, RTL8367C_FLOWCTRL_SHARE_OFF_MASK, pOffThreshold);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_SHARE_ON, RTL8367C_FLOWCTRL_SHARE_ON_MASK, pOnThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_setAsicFlowControlPortThreshold
+ * Description:
+ *      Set Port-based flow control parameters
+ * Input:
+ *      onThreshold     - Flow control turn ON threshold
+ *      offThreshold    - Flow control turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicFlowControlPortThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold)
+{
+    ret_t retVal;
+
+    if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER))
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_OFF, RTL8367C_FLOWCTRL_PORT_OFF_MASK, offThreshold);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_ON, RTL8367C_FLOWCTRL_PORT_ON_MASK, onThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicFlowControlPortThreshold
+ * Description:
+ *      Get Port-based flow control parameters
+ * Input:
+ *      pOnThreshold    - Flow control turn ON threshold
+ *      pOffThreshold   - Flow control turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicFlowControlPortThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_OFF, RTL8367C_FLOWCTRL_PORT_OFF_MASK, pOffThreshold);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_ON, RTL8367C_FLOWCTRL_PORT_ON_MASK, pOnThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_setAsicFlowControlPortPrivateThreshold
+ * Description:
+ *      Set Port-private-based flow control parameters
+ * Input:
+ *      onThreshold     - Flow control turn ON threshold
+ *      offThreshold    - Flow control turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicFlowControlPortPrivateThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold)
+{
+    ret_t retVal;
+
+    if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER))
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_PRIVATE_OFF, RTL8367C_FLOWCTRL_PORT_PRIVATE_OFF_MASK, offThreshold);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_PRIVATE_ON, RTL8367C_FLOWCTRL_PORT_PRIVATE_ON_MASK, onThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicFlowControlPortPrivateThreshold
+ * Description:
+ *      Get Port-private-based flow control parameters
+ * Input:
+ *      pOnThreshold    - Flow control turn ON threshold
+ *      pOffThreshold   - Flow control turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicFlowControlPortPrivateThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_PRIVATE_OFF, RTL8367C_FLOWCTRL_PORT_PRIVATE_OFF_MASK, pOffThreshold);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_PRIVATE_ON, RTL8367C_FLOWCTRL_PORT_PRIVATE_ON_MASK, pOnThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_setAsicFlowControlSystemDropThreshold
+ * Description:
+ *      Set system-based drop parameters
+ * Input:
+ *      onThreshold     - Drop turn ON threshold
+ *      offThreshold    - Drop turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicFlowControlSystemDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold)
+{
+    ret_t retVal;
+
+    if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER))
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SYS_OFF, RTL8367C_FLOWCTRL_FCOFF_SYS_OFF_MASK, offThreshold);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SYS_ON, RTL8367C_FLOWCTRL_FCOFF_SYS_ON_MASK, onThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicFlowControlSystemDropThreshold
+ * Description:
+ *      Get system-based drop parameters
+ * Input:
+ *      pOnThreshold    - Drop turn ON threshold
+ *      pOffThreshold   - Drop turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicFlowControlSystemDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SYS_OFF, RTL8367C_FLOWCTRL_FCOFF_SYS_OFF_MASK, pOffThreshold);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SYS_ON, RTL8367C_FLOWCTRL_FCOFF_SYS_ON_MASK, pOnThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_setAsicFlowControlSharedDropThreshold
+ * Description:
+ *      Set share-based fdrop parameters
+ * Input:
+ *      onThreshold     - Drop turn ON threshold
+ *      offThreshold    - Drop turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicFlowControlSharedDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold)
+{
+    ret_t retVal;
+
+    if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER))
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SHARE_OFF, RTL8367C_FLOWCTRL_FCOFF_SHARE_OFF_MASK, offThreshold);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SHARE_ON, RTL8367C_FLOWCTRL_FCOFF_SHARE_ON_MASK, onThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicFlowControlSharedDropThreshold
+ * Description:
+ *      Get share-based fdrop parameters
+ * Input:
+ *      pOnThreshold    - Drop turn ON threshold
+ *      pOffThreshold   - Drop turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicFlowControlSharedDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SHARE_OFF, RTL8367C_FLOWCTRL_FCOFF_SHARE_OFF_MASK, pOffThreshold);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SHARE_ON, RTL8367C_FLOWCTRL_FCOFF_SHARE_ON_MASK, pOnThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_setAsicFlowControlPortDropThreshold
+ * Description:
+ *      Set Port-based drop parameters
+ * Input:
+ *      onThreshold     - Drop turn ON threshold
+ *      offThreshold    - Drop turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicFlowControlPortDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold)
+{
+    ret_t retVal;
+
+    if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER))
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_OFF, RTL8367C_FLOWCTRL_FCOFF_PORT_OFF_MASK, offThreshold);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_ON, RTL8367C_FLOWCTRL_FCOFF_PORT_ON_MASK, onThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicFlowControlPortDropThreshold
+ * Description:
+ *      Get Port-based drop parameters
+ * Input:
+ *      pOnThreshold    - Drop turn ON threshold
+ *      pOffThreshold   - Drop turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicFlowControlPortDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_OFF, RTL8367C_FLOWCTRL_FCOFF_PORT_OFF_MASK, pOffThreshold);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_ON, RTL8367C_FLOWCTRL_FCOFF_PORT_ON_MASK, pOnThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_setAsicFlowControlPortPrivateDropThreshold
+ * Description:
+ *      Set Port-private-based drop parameters
+ * Input:
+ *      onThreshold     - Drop turn ON threshold
+ *      offThreshold    - Drop turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicFlowControlPortPrivateDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold)
+{
+    ret_t retVal;
+
+    if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER))
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_PRIVATE_OFF, RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_OFF_MASK, offThreshold);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_PRIVATE_ON, RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_ON_MASK, onThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicFlowControlPortPrivateDropThreshold
+ * Description:
+ *      Get Port-private-based drop parameters
+ * Input:
+ *      pOnThreshold    - Drop turn ON threshold
+ *      pOffThreshold   - Drop turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicFlowControlPortPrivateDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_PRIVATE_OFF, RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_OFF_MASK, pOffThreshold);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_PRIVATE_ON, RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_ON_MASK, pOnThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_setAsicFlowControlSystemJumboThreshold
+ * Description:
+ *      Set Jumbo system-based flow control parameters
+ * Input:
+ *      onThreshold     - Flow control turn ON threshold
+ *      offThreshold    - Flow control turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicFlowControlSystemJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold)
+{
+    ret_t retVal;
+
+    if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER))
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SYS_OFF, RTL8367C_FLOWCTRL_JUMBO_SYS_OFF_MASK, offThreshold);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SYS_ON, RTL8367C_FLOWCTRL_JUMBO_SYS_ON_MASK, onThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicFlowControlSystemJumboThreshold
+ * Description:
+ *      Get Jumbo system-based flow control parameters
+ * Input:
+ *      pOnThreshold    - Flow control turn ON threshold
+ *      pOffThreshold   - Flow control turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicFlowControlSystemJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SYS_OFF, RTL8367C_FLOWCTRL_JUMBO_SYS_OFF_MASK, pOffThreshold);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SYS_ON, RTL8367C_FLOWCTRL_JUMBO_SYS_ON_MASK, pOnThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_setAsicFlowControlSharedJumboThreshold
+ * Description:
+ *      Set Jumbo share-based flow control parameters
+ * Input:
+ *      onThreshold     - Flow control turn ON threshold
+ *      offThreshold    - Flow control turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicFlowControlSharedJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold)
+{
+    ret_t retVal;
+
+    if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER))
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SHARE_OFF, RTL8367C_FLOWCTRL_JUMBO_SHARE_OFF_MASK, offThreshold);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SHARE_ON, RTL8367C_FLOWCTRL_JUMBO_SHARE_ON_MASK, onThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicFlowControlSharedJumboThreshold
+ * Description:
+ *      Get Jumbo share-based flow control parameters
+ * Input:
+ *      pOnThreshold    - Flow control turn ON threshold
+ *      pOffThreshold   - Flow control turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicFlowControlSharedJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SHARE_OFF, RTL8367C_FLOWCTRL_JUMBO_SHARE_OFF_MASK, pOffThreshold);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SHARE_ON, RTL8367C_FLOWCTRL_JUMBO_SHARE_ON_MASK, pOnThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_setAsicFlowControlPortJumboThreshold
+ * Description:
+ *      Set Jumbo Port-based flow control parameters
+ * Input:
+ *      onThreshold     - Flow control turn ON threshold
+ *      offThreshold    - Flow control turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicFlowControlPortJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold)
+{
+    ret_t retVal;
+
+    if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER))
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_OFF, RTL8367C_FLOWCTRL_JUMBO_PORT_OFF_MASK, offThreshold);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_ON, RTL8367C_FLOWCTRL_JUMBO_PORT_ON_MASK, onThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicFlowControlPortJumboThreshold
+ * Description:
+ *      Get Jumbo Port-based flow control parameters
+ * Input:
+ *      pOnThreshold    - Flow control turn ON threshold
+ *      pOffThreshold   - Flow control turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicFlowControlPortJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_OFF, RTL8367C_FLOWCTRL_JUMBO_PORT_OFF_MASK, pOffThreshold);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_ON, RTL8367C_FLOWCTRL_JUMBO_PORT_ON_MASK, pOnThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_setAsicFlowControlPortPrivateJumboThreshold
+ * Description:
+ *      Set Jumbo Port-private-based flow control parameters
+ * Input:
+ *      onThreshold     - Flow control turn ON threshold
+ *      offThreshold    - Flow control turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicFlowControlPortPrivateJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold)
+{
+    ret_t retVal;
+
+    if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER))
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_PRIVATE_OFF, RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_OFF_MASK, offThreshold);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_PRIVATE_ON, RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_ON_MASK, onThreshold);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicFlowControlPortPrivateJumboThreshold
+ * Description:
+ *      Get Jumbo Port-private-based flow control parameters
+ * Input:
+ *      pOnThreshold    - Flow control turn ON threshold
+ *      pOffThreshold   - Flow control turn OFF threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicFlowControlPortPrivateJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_PRIVATE_OFF, RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_OFF_MASK, pOffThreshold);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_PRIVATE_ON, RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_ON_MASK, pOnThreshold);
+
+    return retVal;
+}
+
+
+
+/* Function Name:
+ *      rtl8367c_setAsicEgressFlowControlQueueDropThreshold
+ * Description:
+ *      Set Queue-based egress flow control turn on or ingress flow control drop on threshold
+ * Input:
+ *      qid         - The queue id
+ *      threshold   - Queue-based flown control/drop turn ON threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ *      RT_ERR_QUEUE_ID     - Invalid queue id
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicEgressFlowControlQueueDropThreshold(rtk_uint32 qid, rtk_uint32 threshold)
+{
+    if( threshold >= RTL8367C_PAGE_NUMBER)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(qid > RTL8367C_QIDMAX)
+        return RT_ERR_QUEUE_ID;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_FLOWCTRL_QUEUE_DROP_ON_REG(qid), RTL8367C_FLOWCTRL_QUEUE_DROP_ON_MASK, threshold);
+}
+/* Function Name:
+ *      rtl8367c_getAsicEgressFlowControlQueueDropThreshold
+ * Description:
+ *      Get Queue-based egress flow control turn on or ingress flow control drop on threshold
+ * Input:
+ *      qid         - The queue id
+ *      pThreshold  - Queue-based flown control/drop turn ON threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_QUEUE_ID     - Invalid queue id
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicEgressFlowControlQueueDropThreshold(rtk_uint32 qid, rtk_uint32 *pThreshold)
+{
+    if(qid > RTL8367C_QIDMAX)
+      return RT_ERR_QUEUE_ID;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_FLOWCTRL_QUEUE_DROP_ON_REG(qid), RTL8367C_FLOWCTRL_QUEUE_DROP_ON_MASK, pThreshold);
+}
+/* Function Name:
+ *      rtl8367c_setAsicEgressFlowControlPortDropThreshold
+ * Description:
+ *      Set port-based egress flow control turn on or ingress flow control drop on threshold
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      threshold   - Queue-based flown control/drop turn ON threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicEgressFlowControlPortDropThreshold(rtk_uint32 port, rtk_uint32 threshold)
+{
+    if(port > RTL8367C_PORTIDMAX)
+      return RT_ERR_PORT_ID;
+
+    if(threshold >= RTL8367C_PAGE_NUMBER)
+      return RT_ERR_OUT_OF_RANGE;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_FLOWCTRL_PORT_DROP_ON_REG(port), RTL8367C_FLOWCTRL_PORT_DROP_ON_MASK, threshold);
+}
+/* Function Name:
+ *      rtl8367c_setAsicEgressFlowControlPortDropThreshold
+ * Description:
+ *      Set port-based egress flow control turn on or ingress flow control drop on threshold
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      pThreshold  - Queue-based flown control/drop turn ON threshold
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicEgressFlowControlPortDropThreshold(rtk_uint32 port, rtk_uint32 *pThreshold)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_FLOWCTRL_PORT_DROP_ON_REG(port), RTL8367C_FLOWCTRL_PORT_DROP_ON_MASK, pThreshold);
+}
+/* Function Name:
+ *      rtl8367c_setAsicEgressFlowControlPortDropGap
+ * Description:
+ *      Set port-based egress flow control turn off or ingress flow control drop off gap
+ * Input:
+ *      gap     - Flow control/drop turn OFF threshold = turn ON threshold - gap
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicEgressFlowControlPortDropGap(rtk_uint32 gap)
+{
+    if(gap >= RTL8367C_PAGE_NUMBER)
+        return RT_ERR_OUT_OF_RANGE;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_GAP, RTL8367C_FLOWCTRL_PORT_GAP_MASK, gap);
+}
+/* Function Name:
+ *      rtl8367c_getAsicEgressFlowControlPortDropGap
+ * Description:
+ *      Get port-based egress flow control turn off or ingress flow control drop off gap
+ * Input:
+ *      pGap    - Flow control/drop turn OFF threshold = turn ON threshold - gap
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicEgressFlowControlPortDropGap(rtk_uint32 *pGap)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_GAP, RTL8367C_FLOWCTRL_PORT_GAP_MASK, pGap);
+}
+/* Function Name:
+ *      rtl8367c_setAsicEgressFlowControlQueueDropGap
+ * Description:
+ *      Set Queue-based egress flow control turn off or ingress flow control drop off gap
+ * Input:
+ *      gap     - Flow control/drop turn OFF threshold = turn ON threshold - gap
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicEgressFlowControlQueueDropGap(rtk_uint32 gap)
+{
+    if(gap >= RTL8367C_PAGE_NUMBER)
+        return RT_ERR_OUT_OF_RANGE;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_QUEUE_GAP, RTL8367C_FLOWCTRL_QUEUE_GAP_MASK, gap);
+}
+/* Function Name:
+ *      rtl8367c_getAsicEgressFlowControlQueueDropGap
+ * Description:
+ *      Get Queue-based egress flow control turn off or ingress flow control drop off gap
+ * Input:
+ *      pGap    - Flow control/drop turn OFF threshold = turn ON threshold - gap
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicEgressFlowControlQueueDropGap(rtk_uint32 *pGap)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_QUEUE_GAP, RTL8367C_FLOWCTRL_QUEUE_GAP_MASK, pGap);
+}
+/* Function Name:
+ *      rtl8367c_getAsicEgressQueueEmptyPortMask
+ * Description:
+ *      Get queue empty port mask
+ * Input:
+ *      pPortmask   -  Queue empty port mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicEgressQueueEmptyPortMask(rtk_uint32 *pPortmask)
+{
+    return rtl8367c_getAsicReg(RTL8367C_REG_PORT_QEMPTY, pPortmask);
+}
+/* Function Name:
+ *      rtl8367c_getAsicTotalPage
+ * Description:
+ *      Get system total page usage number
+ * Input:
+ *      pPageCount  -  page usage number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicTotalPage(rtk_uint32 *pPageCount)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_TOTAL_PAGE_COUNTER, RTL8367C_FLOWCTRL_TOTAL_PAGE_COUNTER_MASK, pPageCount);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPulbicPage
+ * Description:
+ *      Get system public page usage number
+ * Input:
+ *      pPageCount  -  page usage number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPulbicPage(rtk_uint32 *pPageCount)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PUBLIC_PAGE_COUNTER, RTL8367C_FLOWCTRL_PUBLIC_PAGE_COUNTER_MASK, pPageCount);
+}
+/* Function Name:
+ *      rtl8367c_getAsicMaxTotalPage
+ * Description:
+ *      Get system total page max usage number
+ * Input:
+ *      pPageCount  -  page usage number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicMaxTotalPage(rtk_uint32 *pPageCount)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_TOTAL_PAGE_MAX, RTL8367C_FLOWCTRL_TOTAL_PAGE_MAX_MASK, pPageCount);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPulbicPage
+ * Description:
+ *      Get system public page max usage number
+ * Input:
+ *      pPageCount  -  page usage number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicMaxPulbicPage(rtk_uint32 *pPageCount)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PUBLIC_PAGE_MAX, RTL8367C_FLOWCTRL_PUBLIC_PAGE_MAX_MASK, pPageCount);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortPage
+ * Description:
+ *      Get per-port page usage number
+ * Input:
+ *      port        -  Physical port number (0~7)
+ *      pPageCount  -  page usage number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortPage(rtk_uint32 port, rtk_uint32 *pPageCount)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(port < 8)
+        return rtl8367c_getAsicRegBits(RTL8367C_FLOWCTRL_PORT_PAGE_COUNTER_REG(port), RTL8367C_FLOWCTRL_PORT_PAGE_COUNTER_MASK, pPageCount);
+    else
+        return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT8_PAGE_COUNTER+port - 8, RTL8367C_FLOWCTRL_PORT_PAGE_COUNTER_MASK, pPageCount);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortPage
+ * Description:
+ *      Get per-port page max usage number
+ * Input:
+ *      port        -  Physical port number (0~7)
+ *      pPageCount  -  page usage number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortPageMax(rtk_uint32 port, rtk_uint32 *pPageCount)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+    if(port < 8)
+        return rtl8367c_getAsicRegBits(RTL8367C_FLOWCTRL_PORT_PAGE_MAX_REG(port), RTL8367C_FLOWCTRL_PORT_PAGE_MAX_MASK, pPageCount);
+    else
+        return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT0_PAGE_MAX+port-8, RTL8367C_FLOWCTRL_PORT_PAGE_MAX_MASK, pPageCount);
+
+
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicFlowControlEgressPortIndep
+ * Description:
+ *      Set per-port egress flow control independent
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      enabled     - Egress port flow control usage 1:enable 0:disable.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicFlowControlEgressPortIndep(rtk_uint32 port, rtk_uint32 enable)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_PORT0_MISC_CFG + (port *0x20), RTL8367C_PORT0_MISC_CFG_FLOWCTRL_INDEP_OFFSET,enable);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicFlowControlEgressPortIndep
+ * Description:
+ *      Get per-port egress flow control independent
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      enabled     - Egress port flow control usage 1:enable 0:disable.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicFlowControlEgressPortIndep(rtk_uint32 port, rtk_uint32 *pEnable)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_PORT0_MISC_CFG + (port *0x20),RTL8367C_PORT0_MISC_CFG_FLOWCTRL_INDEP_OFFSET,pEnable);
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_green.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_green.c
new file mode 100644
index 0000000..a386238
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_green.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Green ethernet related functions
+ *
+ */
+#include <rtl8367c_asicdrv_green.h>
+
+/* Function Name:
+ *      rtl8367c_getAsicGreenPortPage
+ * Description:
+ *      Get per-Port ingress page usage per second
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pPage   - page number of ingress packet occuping per second
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      Ingress traffic occuping page number per second for high layer green feature usage
+ */
+ret_t rtl8367c_getAsicGreenPortPage(rtk_uint32 port, rtk_uint32* pPage)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+    rtk_uint32 pageMeter;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_PAGEMETER_PORT_REG(port), &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+   pageMeter = regData;
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_PAGEMETER_PORT_REG(port) + 1, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    pageMeter = pageMeter + (regData << 16);
+
+    *pPage = pageMeter;
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicGreenTrafficType
+ * Description:
+ *      Set traffic type for each priority
+ * Input:
+ *      priority    - internal priority (0~7)
+ *      traffictype - high/low traffic type, 1:high priority traffic type, 0:low priority traffic type
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicGreenTrafficType(rtk_uint32 priority, rtk_uint32 traffictype)
+{
+
+    if(priority > RTL8367C_PRIMAX)
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_HIGHPRI_CFG, priority, (traffictype?1:0));
+}
+/* Function Name:
+ *      rtl8367c_getAsicGreenTrafficType
+ * Description:
+ *      Get traffic type for each priority
+ * Input:
+ *      priority    - internal priority (0~7)
+ *      pTraffictype - high/low traffic type, 1:high priority traffic type, 0:low priority traffic type
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicGreenTrafficType(rtk_uint32 priority, rtk_uint32* pTraffictype)
+{
+    if(priority > RTL8367C_PRIMAX)
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_HIGHPRI_CFG, priority, pTraffictype);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicGreenHighPriorityTraffic
+ * Description:
+ *      Set indicator which ASIC had received high priority traffic
+ * Input:
+ *      port            - Physical port number (0~7)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicGreenHighPriorityTraffic(rtk_uint32 port)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_HIGHPRI_INDICATOR, port, 1);
+}
+
+
+/* Function Name:
+ *      rtl8367c_getAsicGreenHighPriorityTraffic
+ * Description:
+ *      Get indicator which ASIC had received high priority traffic or not
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      pIndicator  - Have received high priority traffic indicator. If 1 means ASCI had received high priority in 1second checking priod
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicGreenHighPriorityTraffic(rtk_uint32 port, rtk_uint32* pIndicator)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_HIGHPRI_INDICATOR, port, pIndicator);
+}
+
+/*
+@func rtk_int32 | rtl8367c_setAsicGreenEthernet | Set green ethernet function.
+@parm rtk_uint32 | green | Green feature function usage 1:enable 0:disable.
+@rvalue RT_ERR_OK | Success.
+@rvalue RT_ERR_SMI | SMI access error.
+@comm
+    The API can set Green Ethernet function to reduce power consumption. While green feature is enabled, ASIC will automatic
+ detect the cable length and then select different power mode for best performance with minimums power consumption. Link down
+ ports will enter power savining mode in 10 seconds after the cable disconnected if power saving function is enabled.
+*/
+ret_t rtl8367c_setAsicGreenEthernet(rtk_uint32 port, rtk_uint32 green)
+{
+    ret_t retVal;
+    rtk_uint32 checkCounter;
+    rtk_uint32 regData;
+    rtk_uint32 phy_status;
+    rtk_uint32 patchData[6][2] = { {0x809A, 0x8911}, {0x80A3, 0x9233}, {0x80AC, 0xA444}, {0x809F, 0x6B20}, {0x80A8, 0x6B22}, {0x80B1, 0x6B23} };
+    rtk_uint32 idx;
+    rtk_uint32 data;
+
+    if (green > 1)
+        return RT_ERR_INPUT;
+
+    /* 0xa420[2:0] */
+    if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xA420, &regData)) != RT_ERR_OK)
+        return retVal;
+    phy_status = (regData & 0x0007);
+
+    if(phy_status == 3)
+    {
+        /* 0xb820[4] = 1 */
+        if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xB820, &regData)) != RT_ERR_OK)
+            return retVal;
+
+        regData |= (0x0001 << 4);
+
+        if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xB820, regData)) != RT_ERR_OK)
+            return retVal;
+
+        /* wait 0xb800[6] = 1 */
+        checkCounter = 100;
+        while(checkCounter)
+        {
+            retVal = rtl8367c_getAsicPHYOCPReg(port, 0xB800, &regData);
+            if( (retVal != RT_ERR_OK) || ((regData & 0x0040) != 0x0040) )
+            {
+                checkCounter --;
+                if(0 == checkCounter)
+                    return RT_ERR_BUSYWAIT_TIMEOUT;
+            }
+            else
+                checkCounter = 0;
+        }
+    }
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_getAsicReg(0x1300, &data)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK)
+        return retVal;
+
+    switch (data)
+    {
+        case 0x0276:
+        case 0x0597:
+        case 0x6367:
+            if(green)
+            {
+                for(idx = 0; idx < 6; idx++ )
+                {
+                    if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA436, patchData[idx][0])) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA438, patchData[idx][1])) != RT_ERR_OK)
+                        return retVal;
+                }
+            }
+            break;
+        default:
+            break;;
+    }
+
+
+
+    /* 0xa436 = 0x8011 */
+    if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA436, 0x8011)) != RT_ERR_OK)
+        return retVal;
+
+    /* wr 0xa438[15] = 0: disable, 1: enable */
+    if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xA438, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    if(green)
+        regData |= 0x8000;
+    else
+        regData &= 0x7FFF;
+
+    if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA438, regData)) != RT_ERR_OK)
+        return retVal;
+
+    if(phy_status == 3)
+    {
+        /* 0xb820[4] = 0  */
+        if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xB820, &regData)) != RT_ERR_OK)
+            return retVal;
+
+        regData &= ~(0x0001 << 4);
+
+        if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xB820, regData)) != RT_ERR_OK)
+            return retVal;
+
+        /* wait 0xb800[6] = 0 */
+        checkCounter = 100;
+        while(checkCounter)
+        {
+            retVal = rtl8367c_getAsicPHYOCPReg(port, 0xB800, &regData);
+            if( (retVal != RT_ERR_OK) || ((regData & 0x0040) != 0x0000) )
+            {
+                checkCounter --;
+                if(0 == checkCounter)
+                    return RT_ERR_BUSYWAIT_TIMEOUT;
+            }
+            else
+                checkCounter = 0;
+        }
+    }
+
+    return RT_ERR_OK;
+}
+
+/*
+@func rtk_int32 | rtl8367c_getAsicGreenEthernet | Get green ethernet function.
+@parm rtk_uint32 | *green | Green feature function usage 1:enable 0:disable.
+@rvalue RT_ERR_OK | Success.
+@rvalue RT_ERR_SMI | SMI access error.
+@comm
+    The API can set Green Ethernet function to reduce power consumption. While green feature is enabled, ASIC will automatic
+ detect the cable length and then select different power mode for best performance with minimums power consumption. Link down
+ ports will enter power savining mode in 10 seconds after the cable disconnected if power saving function is enabled.
+*/
+ret_t rtl8367c_getAsicGreenEthernet(rtk_uint32 port, rtk_uint32* green)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+
+    /* 0xa436 = 0x8011 */
+    if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA436, 0x8011)) != RT_ERR_OK)
+        return retVal;
+
+    /* wr 0xa438[15] = 0: disable, 1: enable */
+    if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xA438, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    if(regData & 0x8000)
+        *green = ENABLED;
+    else
+        *green = DISABLED;
+
+    return RT_ERR_OK;
+}
+
+
+/*
+@func ret_t | rtl8367c_setAsicPowerSaving | Set power saving mode
+@parm rtk_uint32 | phy | phy number
+@parm rtk_uint32 | enable | enable power saving mode.
+@rvalue RT_ERR_OK | Success.
+@rvalue RT_ERR_SMI | SMI access error.
+@rvalue RT_ERR_PORT_ID | Invalid port number.
+@comm
+    The API can set power saving mode per phy.
+*/
+ret_t rtl8367c_setAsicPowerSaving(rtk_uint32 phy, rtk_uint32 enable)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 phyData;
+    rtk_uint32 regData;
+    rtk_uint32 phy_status;
+    rtk_uint32 checkCounter;
+
+    if (enable > 1)
+        return RT_ERR_INPUT;
+
+    /* 0xa420[2:0] */
+    if((retVal = rtl8367c_getAsicPHYOCPReg(phy, 0xA420, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    phy_status = (regData & 0x0007);
+
+    if(phy_status == 3)
+    {
+        /* 0xb820[4] = 1 */
+        if((retVal = rtl8367c_getAsicPHYOCPReg(phy, 0xB820, &regData)) != RT_ERR_OK)
+            return retVal;
+
+        regData |= (0x0001 << 4);
+
+        if((retVal = rtl8367c_setAsicPHYOCPReg(phy, 0xB820, regData)) != RT_ERR_OK)
+            return retVal;
+
+        /* wait 0xb800[6] = 1 */
+        checkCounter = 100;
+        while(checkCounter)
+        {
+            retVal = rtl8367c_getAsicPHYOCPReg(phy, 0xB800, &regData);
+            if( (retVal != RT_ERR_OK) || ((regData & 0x0040) != 0x0040) )
+            {
+                checkCounter --;
+                if(0 == checkCounter)
+                {
+                     return RT_ERR_BUSYWAIT_TIMEOUT;
+                }
+            }
+            else
+                checkCounter = 0;
+        }
+    }
+
+    if ((retVal = rtl8367c_getAsicPHYReg(phy,PHY_POWERSAVING_REG,&phyData))!=RT_ERR_OK)
+        return retVal;
+
+    phyData = phyData & ~(0x0001 << 2);
+    phyData = phyData | (enable << 2);
+
+    if ((retVal = rtl8367c_setAsicPHYReg(phy,PHY_POWERSAVING_REG,phyData))!=RT_ERR_OK)
+        return retVal;
+
+    if(phy_status == 3)
+    {
+        /* 0xb820[4] = 0  */
+        if((retVal = rtl8367c_getAsicPHYOCPReg(phy, 0xB820, &regData)) != RT_ERR_OK)
+            return retVal;
+
+        regData &= ~(0x0001 << 4);
+
+        if((retVal = rtl8367c_setAsicPHYOCPReg(phy, 0xB820, regData)) != RT_ERR_OK)
+            return retVal;
+
+        /* wait 0xb800[6] = 0 */
+        checkCounter = 100;
+        while(checkCounter)
+        {
+            retVal = rtl8367c_getAsicPHYOCPReg(phy, 0xB800, &regData);
+            if( (retVal != RT_ERR_OK) || ((regData & 0x0040) != 0x0000) )
+            {
+                checkCounter --;
+                if(0 == checkCounter)
+                {
+                    return RT_ERR_BUSYWAIT_TIMEOUT;
+                }
+            }
+            else
+                checkCounter = 0;
+        }
+    }
+
+    return RT_ERR_OK;
+}
+
+/*
+@func ret_t | rtl8367c_getAsicPowerSaving | Get power saving mode
+@parm rtk_uint32 | port | The port number
+@parm rtk_uint32* | enable | enable power saving mode.
+@rvalue RT_ERR_OK | Success.
+@rvalue RT_ERR_SMI | SMI access error.
+@rvalue RT_ERR_PORT_ID | Invalid port number.
+@comm
+    The API can get power saving mode per phy.
+*/
+ret_t rtl8367c_getAsicPowerSaving(rtk_uint32 phy, rtk_uint32* enable)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 phyData;
+
+    if(NULL == enable)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicPHYReg(phy,PHY_POWERSAVING_REG,&phyData))!=RT_ERR_OK)
+        return retVal;
+
+    if ((phyData & 0x0004) > 0)
+        *enable = 1;
+    else
+        *enable = 0;
+
+    return RT_ERR_OK;
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_hsb.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_hsb.c
new file mode 100644
index 0000000..435368d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_hsb.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Field selector related functions
+ *
+ */
+#include <rtl8367c_asicdrv_hsb.h>
+/* Function Name:
+ *      rtl8367c_setAsicFieldSelector
+ * Description:
+ *      Set user defined field selectors in HSB
+ * Input:
+ *      index       - index of field selector 0-15
+ *      format      - Format of field selector
+ *      offset      - Retrieving data offset
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      System support 16 user defined field selctors.
+ *      Each selector can be enabled or disable. User can defined retrieving 16-bits in many predefiend
+ *      standard l2/l3/l4 payload.
+ */
+ret_t rtl8367c_setAsicFieldSelector(rtk_uint32 index, rtk_uint32 format, rtk_uint32 offset)
+{
+    rtk_uint32 regData;
+
+    if(index > RTL8367C_FIELDSEL_FORMAT_NUMBER)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(format >= FIELDSEL_FORMAT_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    regData = (((format << RTL8367C_FIELD_SELECTOR_FORMAT_OFFSET) & RTL8367C_FIELD_SELECTOR_FORMAT_MASK ) |
+               ((offset << RTL8367C_FIELD_SELECTOR_OFFSET_OFFSET) & RTL8367C_FIELD_SELECTOR_OFFSET_MASK ));
+
+    return rtl8367c_setAsicReg(RTL8367C_FIELD_SELECTOR_REG(index), regData);
+}
+/* Function Name:
+ *      rtl8367c_getAsicFieldSelector
+ * Description:
+ *      Get user defined field selectors in HSB
+ * Input:
+ *      index       - index of field selector 0-15
+ *      pFormat     - Format of field selector
+ *      pOffset     - Retrieving data offset
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicFieldSelector(rtk_uint32 index, rtk_uint32* pFormat, rtk_uint32* pOffset)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_FIELD_SELECTOR_REG(index), &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *pFormat    = ((regData & RTL8367C_FIELD_SELECTOR_FORMAT_MASK) >> RTL8367C_FIELD_SELECTOR_FORMAT_OFFSET);
+    *pOffset    = ((regData & RTL8367C_FIELD_SELECTOR_OFFSET_MASK) >> RTL8367C_FIELD_SELECTOR_OFFSET_OFFSET);
+
+    return RT_ERR_OK;
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_i2c.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_i2c.c
new file mode 100644
index 0000000..69f20a0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_i2c.c
@@ -0,0 +1,474 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 38651 $
+ * $Date: 2016-02-27 14:32:56 +0800 (周三, 17 四月 2016) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : I2C related functions
+ *
+ */
+
+
+#include <rtl8367c_asicdrv_i2c.h>
+#include <rtk_error.h>
+#include <rtk_types.h>
+
+
+
+/* Function Name:
+ *      rtl8367c_setAsicI2C_checkBusIdle
+ * Description:
+ *      Check i2c bus status idle or not
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                - Success
+ *      RT_ERR_BUSYWAIT_TIMEOUT  - i2c bus is busy
+ * Note:
+ *      This API can check i2c bus status.
+ */
+ret_t rtl8367c_setAsicI2C_checkBusIdle(void)
+{
+    rtk_uint32 regData;
+    ret_t retVal;
+
+    if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_M_I2C_BUS_IDLE_OFFSET, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    if(regData == 0x0001)
+        return RT_ERR_OK; /*i2c is idle*/
+    else
+        return RT_ERR_BUSYWAIT_TIMEOUT; /*i2c is busy*/
+}
+
+
+/* Function Name:
+ *      rtl8367c_setAsicI2CStartCmd
+ * Description:
+ *      Set I2C start command
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                - Success
+ * Note:
+ *      This API can set i2c start command ,start a i2c traffic  .
+ */
+ret_t rtl8367c_setAsicI2CStartCmd(void)
+{
+    rtk_uint32 regData;
+    ret_t retVal;
+
+    /* Bits [4-1] = 0b0000, Start Command; Bit [0] = 1, Trigger the Command */
+    if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, &regData)) != RT_ERR_OK)
+        return retVal;
+    regData &= 0xFFE0;
+    regData |= 0x0001;
+
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, regData)) != RT_ERR_OK)
+        return retVal;
+
+    /* wait for command finished */
+    do{
+       if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_I2C_CMD_EXEC_OFFSET, &regData)) != RT_ERR_OK)
+            return retVal;
+    }while( regData != 0x0);
+
+    return RT_ERR_OK ;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicI2CStopCmd
+ * Description:
+ *      Set I2C stop command
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                - Success
+ * Note:
+ *      This API can set i2c stop command ,stop a i2c traffic.
+ */
+ret_t rtl8367c_setAsicI2CStopCmd(void)
+{
+
+    rtk_uint32 regData;
+    ret_t retVal;
+
+    /* Bits [4-1] = 0b0001, Stop Command; Bit [0] = 1, Trigger the Command */
+    if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, &regData)) != RT_ERR_OK)
+        return retVal;
+    regData &= 0xFFE0;
+    regData |= 0x0003;
+
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, regData)) != RT_ERR_OK)
+        return retVal;
+
+
+    /* wait for command finished */
+    do{
+       if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_I2C_CMD_EXEC_OFFSET, &regData)) != RT_ERR_OK)
+            return retVal;
+    }while( regData != 0x0);
+
+    return RT_ERR_OK ;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicI2CTxOneCharCmd
+ * Description:
+ *      Set I2C Tx a char command, with a 8-bit data
+ * Input:
+ *      oneChar - 8-bit data
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                - Success
+ * Note:
+ *      This API can set i2c Tx command and with a 8-bit data.
+ */
+ret_t rtl8367c_setAsicI2CTxOneCharCmd(rtk_uint8 oneChar)
+{
+    rtk_uint32 regData;
+    ret_t retVal;
+
+    /* Bits [4-1] = 0b0010, tx one char; Bit [0] = 1, Trigger the Command */
+    if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    regData &= 0xFFE0;
+    regData |= 0x0005;
+    regData &= 0x00FF;
+    regData |= (rtk_uint16) (oneChar << 8);
+
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, regData)) != RT_ERR_OK)
+        return retVal;
+
+
+   /* wait for command finished */
+    do{
+       if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_I2C_CMD_EXEC_OFFSET, &regData)) != RT_ERR_OK)
+            return retVal;
+    }while( regData != 0x0);
+
+    return RT_ERR_OK ;
+}
+
+
+/* Function Name:
+ *      rtl8367c_setAsicI2CcheckRxAck
+ * Description:
+ *      Check if rx an Ack
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                - Success
+ * Note:
+ *      This API can check if rx an ack from i2c slave.
+ */
+ret_t rtl8367c_setAsicI2CcheckRxAck(void)
+{
+    rtk_uint32 regData;
+    ret_t retVal;
+    rtk_uint32 count = 0;
+
+    do{
+         count++;
+         if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_SLV_ACK_FLAG_OFFSET, &regData)) != RT_ERR_OK)
+            return retVal;
+    }while( (regData != 0x1) && (count < TIMEROUT_FOR_MICROSEMI) );
+
+    if(regData != 0x1)
+        return RT_ERR_FAILED;
+    else
+        return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtl8367c_setAsicI2CRxOneCharCmd
+ * Description:
+ *      Set I2C Rx command and get 8-bit data
+ * Input:
+ *      None
+ * Output:
+ *      pValue - 8bit-data
+ * Return:
+ *      RT_ERR_OK                - Success
+ * Note:
+ *      This API can set I2C Rx command and get 8-bit data.
+ */
+ret_t rtl8367c_setAsicI2CRxOneCharCmd(rtk_uint8 *pValue)
+{
+    rtk_uint32 regData;
+    ret_t retVal;
+
+    /* Bits [4-1] = 0b0011, Rx one char; Bit [0] = 1, Trigger the Command */
+    if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, &regData)) != RT_ERR_OK)
+        return retVal;
+    regData &= 0xFFE0;
+    regData |= 0x0007;
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, regData)) != RT_ERR_OK)
+        return retVal;
+
+    /* wait for command finished */
+     do{
+        if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, &regData)) != RT_ERR_OK)
+             return retVal;
+     }while( (regData & 0x1) != 0x0);
+
+    *pValue = (rtk_uint8)(regData >> 8);
+     return RT_ERR_OK ;
+
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicI2CTxAckCmd
+ * Description:
+ *      Set I2C Tx ACK command
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                - Success
+ * Note:
+ *      This API can set I2C Tx ack command.
+ */
+ret_t rtl8367c_setAsicI2CTxAckCmd(void)
+{
+    rtk_uint32 regData;
+    ret_t retVal;
+
+    /* Bits [4-1] = 0b0100, tx ACK Command; Bit [0] = 1, Trigger the Command */
+    if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, &regData)) != RT_ERR_OK)
+        return retVal;
+    regData &= 0xFFE0;
+    regData |= 0x0009;
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, regData)) != RT_ERR_OK)
+        return retVal;
+
+     /* wait for command finished */
+    do{
+       if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_I2C_CMD_EXEC_OFFSET, &regData)) != RT_ERR_OK)
+            return retVal;
+    }while( regData != 0x0);
+
+    return RT_ERR_OK ;
+
+}
+
+
+/* Function Name:
+ *      rtl8367c_setAsicI2CTxNoAckCmd
+ * Description:
+ *      Set I2C master Tx noACK command
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                - Success
+ * Note:
+ *      This API can set I2C master Tx noACK command.
+ */
+ret_t rtl8367c_setAsicI2CTxNoAckCmd(void)
+{
+    rtk_uint32 regData;
+    ret_t retVal;
+
+    /* Bits [4-1] = 0b0101, tx noACK Command; Bit [0] = 1, Trigger the Command */
+    if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, &regData)) != RT_ERR_OK)
+        return retVal;
+    regData &= 0xFFE0;
+    regData |= 0x000b;
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, regData)) != RT_ERR_OK)
+        return retVal;
+
+     /* wait for command finished */
+    do{
+       if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_I2C_CMD_EXEC_OFFSET, &regData)) != RT_ERR_OK)
+            return retVal;
+    }while( regData != 0x0);
+
+    return RT_ERR_OK ;
+
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicI2CSoftRSTseqCmd
+ * Description:
+ *      set I2C master tx soft reset command
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                - Success
+ * Note:
+ *      This API can set I2C master tx soft reset command.
+ */
+ret_t rtl8367c_setAsicI2CSoftRSTseqCmd(void)
+{
+
+    rtk_uint32 regData;
+    ret_t retVal;
+
+    /*Bits [4-1] = 0b0110, tx soft reset Command;  Bit [0] = 1, Trigger the Command */
+    if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, &regData)) != RT_ERR_OK)
+        return retVal;
+    regData &= 0xFFE0;
+    regData |= 0x000d;
+
+    if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, regData)) != RT_ERR_OK)
+        return retVal;
+
+
+    /* wait for command finished */
+    do{
+       if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_I2C_CMD_EXEC_OFFSET, &regData)) != RT_ERR_OK)
+            return retVal;
+    }while( regData != 0x0);
+
+    return RT_ERR_OK ;
+}
+
+
+/* Function Name:
+ *      rtl8367c_setAsicI2CGpioPinGroup
+ * Description:
+ *      set I2C function used gpio pins
+ * Input:
+ *      pinGroup_ID - gpio pins group
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                - Success
+ *      RT_ERR_INPUT             _ Invalid input parameter
+ * Note:
+ *      This API can set I2C function used gpio pins.
+ *      There are three group gpio pins
+ */
+ret_t rtl8367c_setAsicI2CGpioPinGroup(rtk_uint32 pinGroup_ID)
+{
+    rtk_uint32 regData;
+    ret_t retVal;
+
+    if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_SYS_CTL, &regData)) != RT_ERR_OK)
+         return retVal;
+    if( pinGroup_ID==0 )
+    {
+        regData &= 0x0FFF;
+        regData |= 0x5000;
+
+        if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_SYS_CTL, regData)) != RT_ERR_OK)
+             return retVal;
+    }
+
+    else if( pinGroup_ID==1 )
+    {
+        regData &= 0x0FFF;
+        regData |= 0xA000;
+
+        if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_SYS_CTL, regData)) != RT_ERR_OK)
+             return retVal;
+    }
+
+    else if( pinGroup_ID==2 )
+    {
+        regData &= 0x0FFF;
+        regData |= 0xF000;
+
+        if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_SYS_CTL, regData)) != RT_ERR_OK)
+             return retVal;
+    }
+    else
+        return RT_ERR_INPUT;
+
+    return RT_ERR_OK ;
+
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicI2CGpioPinGroup
+ * Description:
+ *      set I2C function used gpio pins
+ * Input:
+ *      pinGroup_ID - gpio pins group
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                - Success
+ *      RT_ERR_INPUT             _ Invalid input parameter
+ * Note:
+ *      This API can set I2C function used gpio pins.
+ *      There are three group gpio pins
+ */
+ret_t rtl8367c_getAsicI2CGpioPinGroup(rtk_uint32 * pPinGroup_ID)
+{
+
+    rtk_uint32 regData;
+    ret_t retVal;
+    if( (retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_SYS_CTL, &regData)) != RT_ERR_OK)
+        return retVal;
+    regData &= 0xF000 ;
+    regData = (regData >> 12);
+
+    if( regData == 0x5 )
+        *pPinGroup_ID = 0;
+    else if(regData == 0xA)
+        *pPinGroup_ID = 1;
+    else if(regData == 0xF)
+        *pPinGroup_ID = 2;
+    else
+       return RT_ERR_FAILED;
+    return RT_ERR_OK ;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_igmp.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_igmp.c
new file mode 100644
index 0000000..e0e734d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_igmp.c
@@ -0,0 +1,2109 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : IGMP related functions
+ *
+ */
+#include <rtl8367c_asicdrv_igmp.h>
+/* Function Name:
+ *      rtl8367c_setAsicIgmp
+ * Description:
+ *      Set IGMP/MLD state
+ * Input:
+ *      enabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIgmp(rtk_uint32 enabled)
+{
+    ret_t retVal;
+
+    /* Enable/Disable H/W IGMP/MLD */
+    retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_EN_OFFSET, enabled);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicIgmp
+ * Description:
+ *      Get IGMP/MLD state
+ * Input:
+ *      enabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIgmp(rtk_uint32 *ptr_enabled)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_EN_OFFSET, ptr_enabled);
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_setAsicIpMulticastVlanLeaky
+ * Description:
+ *      Set IP multicast VLAN Leaky function
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      enabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      When enabling this function,
+ *      if the lookup result(forwarding portmap) of IP Multicast packet is over VLAN boundary,
+ *      the packet can be forwarded across VLAN
+ */
+ret_t rtl8367c_setAsicIpMulticastVlanLeaky(rtk_uint32 port, rtk_uint32 enabled)
+{
+    ret_t  retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IPMCAST_VLAN_LEAKY, port, enabled);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicIpMulticastVlanLeaky
+ * Description:
+ *      Get IP multicast VLAN Leaky function
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      enabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIpMulticastVlanLeaky(rtk_uint32 port, rtk_uint32 *ptr_enabled)
+{
+    ret_t  retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_IPMCAST_VLAN_LEAKY, port, ptr_enabled);
+
+    return retVal;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPTableFullOP
+ * Description:
+ *      Set Table Full operation
+ * Input:
+ *      operation   - The operation should be taken when the IGMP table is full.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter is out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPTableFullOP(rtk_uint32 operation)
+{
+    ret_t  retVal;
+
+    if(operation >= TABLE_FULL_OP_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    /* Table full Operation */
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG1, RTL8367C_TABLE_FULL_OP_MASK, operation);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPTableFullOP
+ * Description:
+ *      Get Table Full operation
+ * Input:
+ *      None
+ * Output:
+ *      poperation  - The operation should be taken when the IGMP table is full.
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPTableFullOP(rtk_uint32 *poperation)
+{
+    ret_t   retVal;
+    rtk_uint32  value;
+
+    /* Table full Operation */
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG1, RTL8367C_TABLE_FULL_OP_MASK, &value);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *poperation = value;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPCRCErrOP
+ * Description:
+ *      Set the operation when ASIC receive a Checksum error packet
+ * Input:
+ *      operation   -The operation when ASIC receive a Checksum error packet
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter is out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPCRCErrOP(rtk_uint32 operation)
+{
+    ret_t  retVal;
+
+    if(operation >= CRC_ERR_OP_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    /* CRC Error Operation */
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_CKS_ERR_OP_MASK, operation);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPCRCErrOP
+ * Description:
+ *      Get the operation when ASIC receive a Checksum error packet
+ * Input:
+ *      None
+ * Output:
+ *      poperation  - The operation of Checksum error packet
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPCRCErrOP(rtk_uint32 *poperation)
+{
+    ret_t   retVal;
+    rtk_uint32  value;
+
+    /* CRC Error Operation */
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_CKS_ERR_OP_MASK, &value);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *poperation = value;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPFastLeaveEn
+ * Description:
+ *      Enable/Disable Fast Leave
+ * Input:
+ *      enabled - 1:enable Fast Leave; 0:disable Fast Leave
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPFastLeaveEn(rtk_uint32 enabled)
+{
+    ret_t  retVal;
+
+    /* Fast Leave */
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_FAST_LEAVE_EN_MASK, (enabled >= 1) ? 1 : 0);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPFastLeaveEn
+ * Description:
+ *      Get Fast Leave state
+ * Input:
+ *      None
+ * Output:
+ *      penabled        - 1:enable Fast Leave; 0:disable Fast Leave
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPFastLeaveEn(rtk_uint32 *penabled)
+{
+    ret_t   retVal;
+    rtk_uint32  value;
+
+    /* Fast Leave */
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_FAST_LEAVE_EN_MASK, &value);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *penabled = value;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPLeaveTimer
+ * Description:
+ *      Set the Leave timer of IGMP/MLD
+ * Input:
+ *      leave_timer     - Leave timer
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter is out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPLeaveTimer(rtk_uint32 leave_timer)
+{
+    ret_t  retVal;
+
+    if(leave_timer > RTL8367C_MAX_LEAVE_TIMER)
+        return RT_ERR_OUT_OF_RANGE;
+
+    /* Leave timer */
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_LEAVE_TIMER_MASK, leave_timer);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPLeaveTimer
+ * Description:
+ *      Get the Leave timer of IGMP/MLD
+ * Input:
+ *      None
+ * Output:
+ *      pleave_timer    - Leave timer
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPLeaveTimer(rtk_uint32 *pleave_timer)
+{
+    ret_t   retVal;
+    rtk_uint32  value;
+
+    /* Leave timer */
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_LEAVE_TIMER_MASK, &value);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *pleave_timer = value;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPQueryInterval
+ * Description:
+ *      Set Query Interval of IGMP/MLD
+ * Input:
+ *      interval    - Query Interval
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter is out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPQueryInterval(rtk_uint32 interval)
+{
+    ret_t  retVal;
+
+    if(interval > RTL8367C_MAX_QUERY_INT)
+        return RT_ERR_OUT_OF_RANGE;
+
+    /* Query Interval */
+    retVal = rtl8367c_setAsicReg(RTL8367C_REG_IGMP_MLD_CFG2, interval);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPQueryInterval
+ * Description:
+ *      Get Query Interval of IGMP/MLD
+ * Input:
+ *      None
+ * Output:
+ *      pinterval       - Query Interval
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPQueryInterval(rtk_uint32 *pinterval)
+{
+    ret_t   retVal;
+    rtk_uint32  value;
+
+    /* Query Interval */
+    retVal = rtl8367c_getAsicReg(RTL8367C_REG_IGMP_MLD_CFG2, &value);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *pinterval = value;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPRobVar
+ * Description:
+ *      Set Robustness Variable of IGMP/MLD
+ * Input:
+ *      rob_var     - Robustness Variable
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter is out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPRobVar(rtk_uint32 rob_var)
+{
+    ret_t  retVal;
+
+    if(rob_var > RTL8367C_MAX_ROB_VAR)
+        return RT_ERR_OUT_OF_RANGE;
+
+    /* Bourstness variable */
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_ROBURSTNESS_VAR_MASK, rob_var);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPRobVar
+ * Description:
+ *      Get Robustness Variable of IGMP/MLD
+ * Input:
+ *      none
+ * Output:
+ *      prob_var     - Robustness Variable
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPRobVar(rtk_uint32 *prob_var)
+{
+    ret_t   retVal;
+    rtk_uint32  value;
+
+    /* Bourstness variable */
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_ROBURSTNESS_VAR_MASK, &value);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *prob_var = value;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPStaticRouterPort
+ * Description:
+ *      Set IGMP static router port mask
+ * Input:
+ *      pmsk    - Static portmask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK    - Invalid port mask
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPStaticRouterPort(rtk_uint32 pmsk)
+{
+    if(pmsk > RTL8367C_PORTMASK)
+        return RT_ERR_PORT_MASK;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_STATIC_ROUTER_PORT, RTL8367C_IGMP_STATIC_ROUTER_PORT_MASK, pmsk);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPStaticRouterPort
+ * Description:
+ *      Get IGMP static router port mask
+ * Input:
+ *      pmsk    - Static portmask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPStaticRouterPort(rtk_uint32 *pmsk)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_STATIC_ROUTER_PORT, RTL8367C_IGMP_STATIC_ROUTER_PORT_MASK, pmsk);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPAllowDynamicRouterPort
+ * Description:
+ *      Set IGMP dynamic router port allow mask
+ * Input:
+ *      pmsk    - Allow dynamic router port mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK    - Invalid port mask
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPAllowDynamicRouterPort(rtk_uint32 pmsk)
+{
+    return rtl8367c_setAsicReg(RTL8367C_REG_IGMP_MLD_CFG4, pmsk);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPAllowDynamicRouterPort
+ * Description:
+ *      Get IGMP dynamic router port allow mask
+ * Input:
+ *      None.
+ * Output:
+ *      pPmsk   - Allow dynamic router port mask
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK    - Invalid port mask
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPAllowDynamicRouterPort(rtk_uint32 *pPmsk)
+{
+    return rtl8367c_getAsicReg(RTL8367C_REG_IGMP_MLD_CFG4, pPmsk);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPdynamicRouterPort1
+ * Description:
+ *      Get 1st dynamic router port and timer
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      timer   - router port timer
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPdynamicRouterPort1(rtk_uint32 *port, rtk_uint32 *timer)
+{
+    ret_t   retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_DYNAMIC_ROUTER_PORT, RTL8367C_D_ROUTER_PORT_1_MASK, port);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_DYNAMIC_ROUTER_PORT, RTL8367C_D_ROUTER_PORT_TMR_1_MASK, timer);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPdynamicRouterPort2
+ * Description:
+ *      Get 2nd dynamic router port and timer
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      timer   - router port timer
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPdynamicRouterPort2(rtk_uint32 *port, rtk_uint32 *timer)
+{
+    ret_t   retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_DYNAMIC_ROUTER_PORT, RTL8367C_D_ROUTER_PORT_2_MASK, port);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_DYNAMIC_ROUTER_PORT, RTL8367C_D_ROUTER_PORT_TMR_2_MASK, timer);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPSuppression
+ * Description:
+ *      Set the suppression function
+ * Input:
+ *      report_supp_enabled     - Report suppression, 1:Enable, 0:disable
+ *      leave_supp_enabled      - Leave suppression, 1:Enable, 0:disable
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPSuppression(rtk_uint32 report_supp_enabled, rtk_uint32 leave_supp_enabled)
+{
+    ret_t   retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_REPORT_SUPPRESSION_MASK, report_supp_enabled);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_LEAVE_SUPPRESSION_MASK, leave_supp_enabled);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPSuppression
+ * Description:
+ *      Get the suppression function
+ * Input:
+ *      report_supp_enabled     - Report suppression, 1:Enable, 0:disable
+ *      leave_supp_enabled      - Leave suppression, 1:Enable, 0:disable
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPSuppression(rtk_uint32 *report_supp_enabled, rtk_uint32 *leave_supp_enabled)
+{
+    ret_t   retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_REPORT_SUPPRESSION_MASK, report_supp_enabled);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_LEAVE_SUPPRESSION_MASK, leave_supp_enabled);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPQueryRX
+ * Description:
+ *      Set port-based Query packet RX allowance
+ * Input:
+ *      port            - port number
+ *      allow_query     - allowance of Query packet RX, 1:Allow, 0:Drop
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_PORT_ID  - Error PORT ID
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPQueryRX(rtk_uint32 port, rtk_uint32 allow_query)
+{
+    ret_t   retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    /* Allow Query */
+    if (port < 8)
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_QUERY_MASK, allow_query);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_QUERY_MASK, allow_query);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPQueryRX
+ * Description:
+ *      Get port-based Query packet RX allowance
+ * Input:
+ *      port            - port number
+ * Output:
+ *      allow_query     - allowance of Query packet RX, 1:Allow, 0:Drop
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_PORT_ID  - Error PORT ID
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPQueryRX(rtk_uint32 port, rtk_uint32 *allow_query)
+{
+    ret_t   retVal;
+    rtk_uint32  value;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    /* Allow Query */
+    if (port < 8)
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_QUERY_MASK, &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_QUERY_MASK, &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    *allow_query = value;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPReportRX
+ * Description:
+ *      Set port-based Report packet RX allowance
+ * Input:
+ *      port            - port number
+ *      allow_report    - allowance of Report packet RX, 1:Allow, 0:Drop
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_PORT_ID  - Error PORT ID
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPReportRX(rtk_uint32 port, rtk_uint32 allow_report)
+{
+    ret_t   retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(port < 8)
+    {
+    /* Allow Report */
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_REPORT_MASK, allow_report);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_REPORT_MASK, allow_report);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPReportRX
+ * Description:
+ *      Get port-based Report packet RX allowance
+ * Input:
+ *      port            - port number
+ * Output:
+ *      allow_report    - allowance of Report packet RX, 1:Allow, 0:Drop
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_PORT_ID  - Error PORT ID
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPReportRX(rtk_uint32 port, rtk_uint32 *allow_report)
+{
+    ret_t   retVal;
+    rtk_uint32  value;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(port < 8)
+    {
+        /* Allow Report */
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_REPORT_MASK, &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_REPORT_MASK, &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    *allow_report = value;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPLeaveRX
+ * Description:
+ *      Set port-based Leave packet RX allowance
+ * Input:
+ *      port            - port number
+ *      allow_leave     - allowance of Leave packet RX, 1:Allow, 0:Drop
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_PORT_ID  - Error PORT ID
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPLeaveRX(rtk_uint32 port, rtk_uint32 allow_leave)
+{
+    ret_t   retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(port < 8)
+    {
+        /* Allow Leave */
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_LEAVE_MASK, allow_leave);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_LEAVE_MASK, allow_leave);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPLeaveRX
+ * Description:
+ *      Get port-based Leave packet RX allowance
+ * Input:
+ *      port            - port number
+ * Output:
+ *      allow_leave     - allowance of Leave packet RX, 1:Allow, 0:Drop
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_PORT_ID  - Error PORT ID
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPLeaveRX(rtk_uint32 port, rtk_uint32 *allow_leave)
+{
+    ret_t   retVal;
+    rtk_uint32  value;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(port < 8)
+    {
+    /* Allow Leave */
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_LEAVE_MASK, &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_LEAVE_MASK, &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    *allow_leave = value;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPMRPRX
+ * Description:
+ *      Set port-based Multicast Routing Protocol packet RX allowance
+ * Input:
+ *      port            - port number
+ *      allow_mrp       - allowance of Multicast Routing Protocol packet RX, 1:Allow, 0:Drop
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_PORT_ID  - Error PORT ID
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPMRPRX(rtk_uint32 port, rtk_uint32 allow_mrp)
+{
+    ret_t   retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(port < 8)
+    {
+    /* Allow Multicast Routing Protocol */
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MRP_MASK, allow_mrp);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MRP_MASK, allow_mrp);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPMRPRX
+ * Description:
+ *      Get port-based Multicast Routing Protocol packet RX allowance
+ * Input:
+ *      port            - port number
+ * Output:
+ *      allow_mrp       - allowance of Multicast Routing Protocol packet RX, 1:Allow, 0:Drop
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_PORT_ID  - Error PORT ID
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPMRPRX(rtk_uint32 port, rtk_uint32 *allow_mrp)
+{
+    ret_t   retVal;
+    rtk_uint32  value;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    /* Allow Multicast Routing Protocol */
+    if(port < 8)
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MRP_MASK, &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MRP_MASK, &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    *allow_mrp = value;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPMcDataRX
+ * Description:
+ *      Set port-based Multicast data packet RX allowance
+ * Input:
+ *      port            - port number
+ *      allow_mcdata    - allowance of Multicast data packet RX, 1:Allow, 0:Drop
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_PORT_ID  - Error PORT ID
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPMcDataRX(rtk_uint32 port, rtk_uint32 allow_mcdata)
+{
+    ret_t   retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    /* Allow Multicast Data */
+    if(port < 8)
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MC_DATA_MASK, allow_mcdata);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MC_DATA_MASK, allow_mcdata);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPMcDataRX
+ * Description:
+ *      Get port-based Multicast data packet RX allowance
+ * Input:
+ *      port            - port number
+ * Output:
+ *      allow_mcdata    - allowance of Multicast data packet RX, 1:Allow, 0:Drop
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_PORT_ID  - Error PORT ID
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPMcDataRX(rtk_uint32 port, rtk_uint32 *allow_mcdata)
+{
+    ret_t   retVal;
+    rtk_uint32  value;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    /* Allow Multicast data */
+    if(port < 8)
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MC_DATA_MASK, &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MC_DATA_MASK, &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    *allow_mcdata = value;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPv1Opeartion
+ * Description:
+ *      Set port-based IGMPv1 Control packet action
+ * Input:
+ *      port            - port number
+ *      igmpv1_op       - IGMPv1 control packet action
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_PORT_ID  - Error PORT ID
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPv1Opeartion(rtk_uint32 port, rtk_uint32 igmpv1_op)
+{
+    ret_t   retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(igmpv1_op >= PROTOCOL_OP_END)
+        return RT_ERR_INPUT;
+
+    /* IGMPv1 operation */
+    if(port < 8)
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_IGMPV1_OP_MASK, igmpv1_op);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_IGMPV1_OP_MASK, igmpv1_op);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPv1Opeartion
+ * Description:
+ *      Get port-based IGMPv1 Control packet action
+ * Input:
+ *      port            - port number
+ * Output:
+ *      igmpv1_op       - IGMPv1 control packet action
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_PORT_ID  - Error PORT ID
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPv1Opeartion(rtk_uint32 port, rtk_uint32 *igmpv1_op)
+{
+    ret_t   retVal;
+    rtk_uint32  value;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    /* IGMPv1 operation */
+    if(port < 8)
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_IGMPV1_OP_MASK, &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_IGMPV1_OP_MASK, &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    *igmpv1_op = value;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPv2Opeartion
+ * Description:
+ *      Set port-based IGMPv2 Control packet action
+ * Input:
+ *      port            - port number
+ *      igmpv2_op       - IGMPv2 control packet action
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_PORT_ID  - Error PORT ID
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPv2Opeartion(rtk_uint32 port, rtk_uint32 igmpv2_op)
+{
+    ret_t   retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(igmpv2_op >= PROTOCOL_OP_END)
+        return RT_ERR_INPUT;
+
+    /* IGMPv2 operation */
+    if(port < 8)
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_IGMPV2_OP_MASK, igmpv2_op);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_IGMPV2_OP_MASK, igmpv2_op);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPv2Opeartion
+ * Description:
+ *      Get port-based IGMPv2 Control packet action
+ * Input:
+ *      port            - port number
+ * Output:
+ *      igmpv2_op       - IGMPv2 control packet action
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_PORT_ID  - Error PORT ID
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPv2Opeartion(rtk_uint32 port, rtk_uint32 *igmpv2_op)
+{
+    ret_t   retVal;
+    rtk_uint32  value;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    /* IGMPv2 operation */
+    if(port < 8)
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_IGMPV2_OP_MASK, &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_IGMPV2_OP_MASK, &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    *igmpv2_op = value;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPv3Opeartion
+ * Description:
+ *      Set port-based IGMPv3 Control packet action
+ * Input:
+ *      port            - port number
+ *      igmpv3_op       - IGMPv3 control packet action
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_PORT_ID  - Error PORT ID
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPv3Opeartion(rtk_uint32 port, rtk_uint32 igmpv3_op)
+{
+    ret_t   retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(igmpv3_op >= PROTOCOL_OP_END)
+        return RT_ERR_INPUT;
+
+    /* IGMPv3 operation */
+    if(port < 8)
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_IGMPV3_OP_MASK, igmpv3_op);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_IGMPV3_OP_MASK, igmpv3_op);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPv3Opeartion
+ * Description:
+ *      Get port-based IGMPv3 Control packet action
+ * Input:
+ *      port            - port number
+ * Output:
+ *      igmpv3_op       - IGMPv3 control packet action
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_PORT_ID  - Error PORT ID
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPv3Opeartion(rtk_uint32 port, rtk_uint32 *igmpv3_op)
+{
+    ret_t   retVal;
+    rtk_uint32  value;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    /* IGMPv3 operation */
+    if(port < 8)
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_IGMPV3_OP_MASK, &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_IGMPV3_OP_MASK, &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    *igmpv3_op = value;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicMLDv1Opeartion
+ * Description:
+ *      Set port-based MLDv1 Control packet action
+ * Input:
+ *      port            - port number
+ *      mldv1_op        - MLDv1 control packet action
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_PORT_ID  - Error PORT ID
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicMLDv1Opeartion(rtk_uint32 port, rtk_uint32 mldv1_op)
+{
+    ret_t   retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(mldv1_op >= PROTOCOL_OP_END)
+        return RT_ERR_INPUT;
+
+    /* MLDv1 operation */
+    if(port < 8)
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_MLDv1_OP_MASK, mldv1_op);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_MLDv1_OP_MASK, mldv1_op);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicMLDv1Opeartion
+ * Description:
+ *      Get port-based MLDv1 Control packet action
+ * Input:
+ *      port            - port number
+ * Output:
+ *      mldv1_op        - MLDv1 control packet action
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_PORT_ID  - Error PORT ID
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicMLDv1Opeartion(rtk_uint32 port, rtk_uint32 *mldv1_op)
+{
+    ret_t   retVal;
+    rtk_uint32  value;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    /* MLDv1 operation */
+    if(port < 8)
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_MLDv1_OP_MASK, &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_MLDv1_OP_MASK, &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    *mldv1_op = value;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicMLDv2Opeartion
+ * Description:
+ *      Set port-based MLDv2 Control packet action
+ * Input:
+ *      port            - port number
+ *      mldv2_op        - MLDv2 control packet action
+ * Output:
+ *      none
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_PORT_ID  - Error PORT ID
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicMLDv2Opeartion(rtk_uint32 port, rtk_uint32 mldv2_op)
+{
+    ret_t   retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(mldv2_op >= PROTOCOL_OP_END)
+        return RT_ERR_INPUT;
+
+    /* MLDv2 operation */
+    if(port < 8)
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_MLDv2_OP_MASK, mldv2_op);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_MLDv2_OP_MASK, mldv2_op);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicMLDv2Opeartion
+ * Description:
+ *      Get port-based MLDv2 Control packet action
+ * Input:
+ *      port            - port number
+ * Output:
+ *      mldv2_op        - MLDv2 control packet action
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_PORT_ID  - Error PORT ID
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicMLDv2Opeartion(rtk_uint32 port, rtk_uint32 *mldv2_op)
+{
+    ret_t   retVal;
+    rtk_uint32  value;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    /* MLDv2 operation */
+    if(port < 8)
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_MLDv2_OP_MASK, &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_MLDv2_OP_MASK, &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    *mldv2_op = value;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPPortMAXGroup
+ * Description:
+ *      Set per-port Max group number
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      max_group   - max IGMP group
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPPortMAXGroup(rtk_uint32 port, rtk_uint32 max_group)
+{
+    ret_t retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(max_group > RTL8367C_IGMP_MAX_GOUP)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(port < 8)
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT01_MAX_GROUP + (port/2), RTL8367C_PORT0_MAX_GROUP_MASK << (RTL8367C_PORT1_MAX_GROUP_OFFSET * (port%2)), max_group);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT89_MAX_GROUP + (port/2), RTL8367C_PORT0_MAX_GROUP_MASK << (RTL8367C_PORT1_MAX_GROUP_OFFSET * (port%2)), max_group);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicIGMPPortMAXGroup
+ * Description:
+ *      Get per-port Max group number
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      max_group   - max IGMP group
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPPortMAXGroup(rtk_uint32 port, rtk_uint32 *max_group)
+{
+    ret_t   retVal;
+    rtk_uint32  value;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(port < 8)
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT01_MAX_GROUP + (port/2), RTL8367C_PORT0_MAX_GROUP_MASK << (RTL8367C_PORT1_MAX_GROUP_OFFSET * (port%2)), &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT89_MAX_GROUP + (port/2), RTL8367C_PORT0_MAX_GROUP_MASK << (RTL8367C_PORT1_MAX_GROUP_OFFSET * (port%2)), &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    *max_group = value;
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicIGMPPortCurrentGroup
+ * Description:
+ *      Get per-port current group number
+ * Input:
+ *      port            - Physical port number (0~7)
+ *      current_group   - current IGMP group
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPPortCurrentGroup(rtk_uint32 port, rtk_uint32 *current_group)
+{
+    ret_t   retVal;
+    rtk_uint32  value;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(port < 8)
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT01_CURRENT_GROUP + (port/2), RTL8367C_PORT0_CURRENT_GROUP_MASK << (RTL8367C_PORT1_CURRENT_GROUP_OFFSET * (port%2)), &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT89_CURRENT_GROUP + ((port - 8)/2), RTL8367C_PORT0_CURRENT_GROUP_MASK << (RTL8367C_PORT1_CURRENT_GROUP_OFFSET * (port%2)), &value);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    *current_group = value;
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicIGMPGroup
+ * Description:
+ *      Get IGMP group
+ * Input:
+ *      idx     - Group index (0~255)
+ *      valid   - valid bit
+ *      grp     - IGMP group
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - Group index is out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPGroup(rtk_uint32 idx, rtk_uint32 *valid, rtl8367c_igmpgroup *grp)
+{
+    ret_t   retVal;
+    rtk_uint32  regAddr, regData;
+    rtk_uint32  i;
+    rtk_uint32  groupInfo = 0;
+
+    if(idx > RTL8367C_IGMP_MAX_GOUP)
+        return RT_ERR_OUT_OF_RANGE;
+
+    /* Write ACS_ADR register for data bits */
+    regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG;
+    regData = idx;
+    retVal = rtl8367c_setAsicReg(regAddr, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /* Write ACS_CMD register */
+    regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG;
+    regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_READ, TB_TARGET_IGMP_GROUP);
+    retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /* Read Data Bits */
+    regAddr = RTL8367C_TABLE_ACCESS_RDDATA_BASE;
+    for(i = 0 ;i <= 1; i++)
+    {
+        retVal = rtl8367c_getAsicReg(regAddr, &regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        groupInfo |= ((regData & 0xFFFF) << (i * 16));
+        regAddr ++;
+    }
+
+    grp->p0_timer = groupInfo & 0x00000007;
+    grp->p1_timer = (groupInfo >> 3) & 0x00000007;
+    grp->p2_timer = (groupInfo >> 6) & 0x00000007;
+    grp->p3_timer = (groupInfo >> 9) & 0x00000007;
+    grp->p4_timer = (groupInfo >> 12) & 0x00000007;
+    grp->p5_timer = (groupInfo >> 15) & 0x00000007;
+    grp->p6_timer = (groupInfo >> 18) & 0x00000007;
+    grp->p7_timer = (groupInfo >> 21) & 0x00000007;
+    grp->report_supp_flag = (groupInfo >> 24) & 0x00000001;
+    grp->p8_timer = (groupInfo >> 25) & 0x00000007;
+    grp->p9_timer = (groupInfo >> 28) & 0x00000007;
+    grp->p10_timer = (groupInfo >> 31) & 0x00000001;
+
+    regAddr = RTL8367C_TABLE_ACCESS_RDDATA_BASE + 2;
+    retVal = rtl8367c_getAsicReg(regAddr, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    grp->p10_timer |= (regData & 0x00000003) << 1;
+
+    /* Valid bit */
+    retVal = rtl8367c_getAsicReg(RTL8367C_IGMP_GROUP_USAGE_REG(idx), &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *valid = ((regData & (0x0001 << (idx %16))) != 0) ? 1 : 0;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicIpMulticastPortIsoLeaky
+ * Description:
+ *      Set IP multicast Port Isolation leaky
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      enabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIpMulticastPortIsoLeaky(rtk_uint32 port, rtk_uint32 enabled)
+{
+    ret_t   retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_IPMCAST_PORTISO_LEAKY_REG, (0x0001 << port), enabled);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIpMulticastPortIsoLeaky
+ * Description:
+ *      Get IP multicast Port Isolation leaky
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      enabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIpMulticastPortIsoLeaky(rtk_uint32 port, rtk_uint32 *enabled)
+{
+    ret_t   retVal;
+    rtk_uint32  regData;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_IPMCAST_PORTISO_LEAKY_REG, (0x0001 << port), &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *enabled = regData;
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPReportLeaveFlood
+ * Description:
+ *      Set IGMP/MLD Report/Leave flood
+ * Input:
+ *      flood   - 0: Reserved, 1: flooding to router ports, 2: flooding to all ports, 3: flooding to router port or to all ports if there is no router port
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPReportLeaveFlood(rtk_uint32 flood)
+{
+    ret_t   retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG3, RTL8367C_REPORT_LEAVE_FORWARD_MASK, flood);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPReportLeaveFlood
+ * Description:
+ *      Get IGMP/MLD Report/Leave flood
+ * Input:
+ *      None
+ * Output:
+ *      pflood  - 0: Reserved, 1: flooding to router ports, 2: flooding to all ports, 3: flooding to router port or to all ports if there is no router port
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPReportLeaveFlood(rtk_uint32 *pFlood)
+{
+    ret_t   retVal;
+    rtk_uint32  regData;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG3, RTL8367C_REPORT_LEAVE_FORWARD_MASK, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *pFlood = regData;
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPDropLeaveZero
+ * Description:
+ *      Set the function of droppping Leave packet with group IP = 0.0.0.0
+ * Input:
+ *      drop    - 1: Drop, 0:Bypass
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPDropLeaveZero(rtk_uint32 drop)
+{
+    ret_t   retVal;
+
+    retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG1, RTL8367C_DROP_LEAVE_ZERO_OFFSET, drop);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPDropLeaveZero
+ * Description:
+ *      Get the function of droppping Leave packet with group IP = 0.0.0.0
+ * Input:
+ *      None
+ * Output:
+ *      pDrop    - 1: Drop, 0:Bypass
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPDropLeaveZero(rtk_uint32 *pDrop)
+{
+    ret_t   retVal;
+    rtk_uint32  regData;
+
+    retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG1, RTL8367C_DROP_LEAVE_ZERO_OFFSET, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *pDrop = regData;
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPBypassStormCTRL
+ * Description:
+ *      Set the function of bypass strom control for IGMP/MLD packet
+ * Input:
+ *      bypass    - 1: Bypass, 0:not bypass
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPBypassStormCTRL(rtk_uint32 bypass)
+{
+    ret_t   retVal;
+
+    retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_DISCARD_STORM_FILTER_OFFSET, bypass);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPBypassStormCTRL
+ * Description:
+ *      Set the function of bypass strom control for IGMP/MLD packet
+ * Input:
+ *      None
+ * Output:
+ *      pBypass    - 1: Bypass, 0:not bypass
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPBypassStormCTRL(rtk_uint32 *pBypass)
+{
+    ret_t   retVal;
+    rtk_uint32  regData;
+
+    retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_DISCARD_STORM_FILTER_OFFSET, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *pBypass = regData;
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPIsoLeaky
+ * Description:
+ *      Set Port Isolation leaky for IGMP/MLD packet
+ * Input:
+ *      leaky    - 1: Leaky, 0:not leaky
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPIsoLeaky(rtk_uint32 leaky)
+{
+    ret_t   retVal;
+
+    retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_PORTISO_LEAKY_OFFSET, leaky);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPIsoLeaky
+ * Description:
+ *      Get Port Isolation leaky for IGMP/MLD packet
+ * Input:
+ *      Noen
+ * Output:
+ *      pLeaky    - 1: Leaky, 0:not leaky
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPIsoLeaky(rtk_uint32 *pLeaky)
+{
+    ret_t   retVal;
+    rtk_uint32  regData;
+
+    retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_PORTISO_LEAKY_OFFSET, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *pLeaky = regData;
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPVLANLeaky
+ * Description:
+ *      Set VLAN leaky for IGMP/MLD packet
+ * Input:
+ *      leaky    - 1: Leaky, 0:not leaky
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPVLANLeaky(rtk_uint32 leaky)
+{
+    ret_t   retVal;
+
+    retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_VLAN_LEAKY_OFFSET, leaky);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPVLANLeaky
+ * Description:
+ *      Get VLAN leaky for IGMP/MLD packet
+ * Input:
+ *      Noen
+ * Output:
+ *      pLeaky    - 1: Leaky, 0:not leaky
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPVLANLeaky(rtk_uint32 *pLeaky)
+{
+    ret_t   retVal;
+    rtk_uint32  regData;
+
+    retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_VLAN_LEAKY_OFFSET, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *pLeaky = regData;
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicIGMPBypassGroup
+ * Description:
+ *      Set IGMP/MLD Bypass group
+ * Input:
+ *      bypassType  - Bypass type
+ *      enabled     - enabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicIGMPBypassGroup(rtk_uint32 bypassType, rtk_uint32 enabled)
+{
+    ret_t   retVal;
+    rtk_uint32 offset;
+
+    switch(bypassType)
+    {
+        case BYPASS_224_0_0_X:
+            offset = RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_0_OFFSET;
+            break;
+        case BYPASS_224_0_1_X:
+            offset = RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_1_OFFSET;
+            break;
+        case BYPASS_239_255_255_X:
+            offset = RTL8367C_IGMP_MLD_IP4_BYPASS_239_255_255_OFFSET;
+            break;
+        case BYPASS_IPV6_00XX:
+            offset = RTL8367C_IGMP_MLD_IP6_BYPASS_OFFSET;
+            break;
+        default:
+            return RT_ERR_INPUT;
+    }
+
+    retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG3, offset, enabled);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicIGMPBypassGroup
+ * Description:
+ *      Get IGMP/MLD Bypass group
+ * Input:
+ *      bypassType  - Bypass type
+ * Output:
+ *      pEnabled    - enabled
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicIGMPBypassGroup(rtk_uint32 bypassType, rtk_uint32 *pEnabled)
+{
+    ret_t   retVal;
+    rtk_uint32 offset;
+
+    switch(bypassType)
+    {
+        case BYPASS_224_0_0_X:
+            offset = RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_0_OFFSET;
+            break;
+        case BYPASS_224_0_1_X:
+            offset = RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_1_OFFSET;
+            break;
+        case BYPASS_239_255_255_X:
+            offset = RTL8367C_IGMP_MLD_IP4_BYPASS_239_255_255_OFFSET;
+            break;
+        case BYPASS_IPV6_00XX:
+            offset = RTL8367C_IGMP_MLD_IP6_BYPASS_OFFSET;
+            break;
+        default:
+            return RT_ERR_INPUT;
+    }
+
+    retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG3, offset, pEnabled);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_inbwctrl.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_inbwctrl.c
new file mode 100644
index 0000000..abb36be
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_inbwctrl.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Ingress bandwidth control related functions
+ *
+ */
+#include <rtl8367c_asicdrv_inbwctrl.h>
+/* Function Name:
+ *      rtl8367c_setAsicPortIngressBandwidth
+ * Description:
+ *      Set per-port total ingress bandwidth
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      bandwidth   - The total ingress bandwidth (unit: 8Kbps), 0x1FFFF:disable
+ *      preifg      - Include preamble and IFG, 0:Exclude, 1:Include
+ *      enableFC    - Action when input rate exceeds. 0: Drop   1: Flow Control
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortIngressBandwidth(rtk_uint32 port, rtk_uint32 bandwidth, rtk_uint32 preifg, rtk_uint32 enableFC)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+    rtk_uint32 regAddr;
+
+    /* Invalid input parameter */
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if(bandwidth > RTL8367C_QOS_GRANULARTY_MAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    regAddr = RTL8367C_INGRESSBW_PORT_RATE_LSB_REG(port);
+    regData = bandwidth & RTL8367C_QOS_GRANULARTY_LSB_MASK;
+    retVal = rtl8367c_setAsicReg(regAddr, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    regAddr += 1;
+    regData = (bandwidth & RTL8367C_QOS_GRANULARTY_MSB_MASK) >> RTL8367C_QOS_GRANULARTY_MSB_OFFSET;
+    retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_INGRESSBW_PORT0_RATE_CTRL1_INGRESSBW_RATE16_MASK, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    regAddr = RTL8367C_PORT_MISC_CFG_REG(port);
+    retVal = rtl8367c_setAsicRegBit(regAddr, RTL8367C_PORT0_MISC_CFG_INGRESSBW_IFG_OFFSET, preifg);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    regAddr = RTL8367C_PORT_MISC_CFG_REG(port);
+    retVal = rtl8367c_setAsicRegBit(regAddr, RTL8367C_PORT0_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET, enableFC);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortIngressBandwidth
+ * Description:
+ *      Get per-port total ingress bandwidth
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      pBandwidth  - The total ingress bandwidth (unit: 8Kbps), 0x1FFFF:disable
+ *      pPreifg         - Include preamble and IFG, 0:Exclude, 1:Include
+ *      pEnableFC   - Action when input rate exceeds. 0: Drop   1: Flow Control
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortIngressBandwidth(rtk_uint32 port, rtk_uint32* pBandwidth, rtk_uint32* pPreifg, rtk_uint32* pEnableFC)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+    rtk_uint32 regAddr;
+
+    /* Invalid input parameter */
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    regAddr = RTL8367C_INGRESSBW_PORT_RATE_LSB_REG(port);
+    retVal = rtl8367c_getAsicReg(regAddr, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *pBandwidth = regData;
+
+    regAddr += 1;
+    retVal = rtl8367c_getAsicRegBits(regAddr, RTL8367C_INGRESSBW_PORT0_RATE_CTRL1_INGRESSBW_RATE16_MASK, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *pBandwidth |= (regData << RTL8367C_QOS_GRANULARTY_MSB_OFFSET);
+
+    regAddr = RTL8367C_PORT_MISC_CFG_REG(port);
+    retVal = rtl8367c_getAsicRegBit(regAddr, RTL8367C_PORT0_MISC_CFG_INGRESSBW_IFG_OFFSET, pPreifg);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    regAddr = RTL8367C_PORT_MISC_CFG_REG(port);
+    retVal = rtl8367c_getAsicRegBit(regAddr, RTL8367C_PORT0_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET, pEnableFC);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicPortIngressBandwidthBypass
+ * Description:
+ *      Set ingress bandwidth control bypasss 8899, RMA 01-80-C2-00-00-xx and IGMP
+ * Input:
+ *      enabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortIngressBandwidthBypass(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_SW_DUMMY0, RTL8367C_INGRESSBW_BYPASS_EN_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortIngressBandwidthBypass
+ * Description:
+ *      Set ingress bandwidth control bypasss 8899, RMA 01-80-C2-00-00-xx and IGMP
+ * Input:
+ *      pEnabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortIngressBandwidthBypass(rtk_uint32* pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_SW_DUMMY0, RTL8367C_INGRESSBW_BYPASS_EN_OFFSET, pEnabled);
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_interrupt.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_interrupt.c
new file mode 100644
index 0000000..fb6cbcd
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_interrupt.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Interrupt related functions
+ *
+ */
+#include <rtl8367c_asicdrv_interrupt.h>
+/* Function Name:
+ *      rtl8367c_setAsicInterruptPolarity
+ * Description:
+ *      Set interrupt trigger polarity
+ * Input:
+ *      polarity    - 0:pull high 1: pull low
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicInterruptPolarity(rtk_uint32 polarity)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_INTR_CTRL, RTL8367C_INTR_CTRL_OFFSET, polarity);
+}
+/* Function Name:
+ *      rtl8367c_getAsicInterruptPolarity
+ * Description:
+ *      Get interrupt trigger polarity
+ * Input:
+ *      pPolarity   - 0:pull high 1: pull low
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicInterruptPolarity(rtk_uint32* pPolarity)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_INTR_CTRL, RTL8367C_INTR_CTRL_OFFSET, pPolarity);
+}
+/* Function Name:
+ *      rtl8367c_setAsicInterruptMask
+ * Description:
+ *      Set interrupt enable mask
+ * Input:
+ *      imr     - Interrupt mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicInterruptMask(rtk_uint32 imr)
+{
+    return rtl8367c_setAsicReg(RTL8367C_REG_INTR_IMR, imr);
+}
+/* Function Name:
+ *      rtl8367c_getAsicInterruptMask
+ * Description:
+ *      Get interrupt enable mask
+ * Input:
+ *      pImr    - Interrupt mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicInterruptMask(rtk_uint32* pImr)
+{
+    return rtl8367c_getAsicReg(RTL8367C_REG_INTR_IMR, pImr);
+}
+/* Function Name:
+ *      rtl8367c_setAsicInterruptMask
+ * Description:
+ *      Clear interrupt enable mask
+ * Input:
+ *      ims     - Interrupt status mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      This API can be used to clear ASIC interrupt status and register will be cleared by writting 1.
+ *      [0]:Link change,
+ *      [1]:Share meter exceed,
+ *      [2]:Learn number overed,
+ *      [3]:Speed Change,
+ *      [4]:Tx special congestion
+ *      [5]:1 second green feature
+ *      [6]:loop detection
+ *      [7]:interrupt from 8051
+ *      [8]:Cable diagnostic finish
+ *      [9]:ACL action interrupt trigger
+ *      [11]: Silent Start
+ */
+ret_t rtl8367c_setAsicInterruptStatus(rtk_uint32 ims)
+{
+    return rtl8367c_setAsicReg(RTL8367C_REG_INTR_IMS, ims);
+}
+/* Function Name:
+ *      rtl8367c_getAsicInterruptStatus
+ * Description:
+ *      Get interrupt enable mask
+ * Input:
+ *      pIms    - Interrupt status mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicInterruptStatus(rtk_uint32* pIms)
+{
+    return rtl8367c_getAsicReg(RTL8367C_REG_INTR_IMS, pIms);
+}
+/* Function Name:
+ *      rtl8367c_setAsicInterruptRelatedStatus
+ * Description:
+ *      Clear interrupt status
+ * Input:
+ *      type    - per port Learn over, per-port speed change, per-port special congest, share meter exceed status
+ *      status  - exceed status, write 1 to clear
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicInterruptRelatedStatus(rtk_uint32 type, rtk_uint32 status)
+{
+    CONST rtk_uint32 indicatorAddress[INTRST_END] = {RTL8367C_REG_LEARN_OVER_INDICATOR,
+                                                    RTL8367C_REG_SPEED_CHANGE_INDICATOR,
+                                                    RTL8367C_REG_SPECIAL_CONGEST_INDICATOR,
+                                                    RTL8367C_REG_PORT_LINKDOWN_INDICATOR,
+                                                    RTL8367C_REG_PORT_LINKUP_INDICATOR,
+                                                    RTL8367C_REG_METER_OVERRATE_INDICATOR0,
+                                                    RTL8367C_REG_METER_OVERRATE_INDICATOR1,
+                                                    RTL8367C_REG_RLDP_LOOPED_INDICATOR,
+                                                    RTL8367C_REG_RLDP_RELEASED_INDICATOR,
+                                                    RTL8367C_REG_SYSTEM_LEARN_OVER_INDICATOR};
+
+    if(type >= INTRST_END )
+        return RT_ERR_OUT_OF_RANGE;
+
+    return rtl8367c_setAsicReg(indicatorAddress[type], status);
+}
+/* Function Name:
+ *      rtl8367c_getAsicInterruptRelatedStatus
+ * Description:
+ *      Get interrupt status
+ * Input:
+ *      type    - per port Learn over, per-port speed change, per-port special congest, share meter exceed status
+ *      pStatus     - exceed status, write 1 to clear
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicInterruptRelatedStatus(rtk_uint32 type, rtk_uint32* pStatus)
+{
+    CONST rtk_uint32 indicatorAddress[INTRST_END] = {RTL8367C_REG_LEARN_OVER_INDICATOR,
+                                                    RTL8367C_REG_SPEED_CHANGE_INDICATOR,
+                                                    RTL8367C_REG_SPECIAL_CONGEST_INDICATOR,
+                                                    RTL8367C_REG_PORT_LINKDOWN_INDICATOR,
+                                                    RTL8367C_REG_PORT_LINKUP_INDICATOR,
+                                                    RTL8367C_REG_METER_OVERRATE_INDICATOR0,
+                                                    RTL8367C_REG_METER_OVERRATE_INDICATOR1,
+                                                    RTL8367C_REG_RLDP_LOOPED_INDICATOR,
+                                                    RTL8367C_REG_RLDP_RELEASED_INDICATOR,
+                                                    RTL8367C_REG_SYSTEM_LEARN_OVER_INDICATOR};
+
+    if(type >= INTRST_END )
+        return RT_ERR_OUT_OF_RANGE;
+
+    return rtl8367c_getAsicReg(indicatorAddress[type], pStatus);
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_led.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_led.c
new file mode 100644
index 0000000..1189028
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_led.c
@@ -0,0 +1,727 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : LED related functions
+ *
+ */
+#include <rtl8367c_asicdrv_led.h>
+/* Function Name:
+ *      rtl8367c_setAsicLedIndicateInfoConfig
+ * Description:
+ *      Set Leds indicated information mode
+ * Input:
+ *      ledno   - LED group number. There are 1 to 1 led mapping to each port in each led group
+ *      config  - Support 16 types configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      The API can set LED indicated information configuration for each LED group with 1 to 1 led mapping to each port.
+ *      Definition        LED Statuses            Description
+ *      0000        LED_Off                LED pin Tri-State.
+ *      0001        Dup/Col                Collision, Full duplex Indicator. Blinking every 43ms when collision happens. Low for full duplex, and high for half duplex mode.
+ *      0010        Link/Act               Link, Activity Indicator. Low for link established. Link/Act Blinks every 43ms when the corresponding port is transmitting or receiving.
+ *      0011        Spd1000                1000Mb/s Speed Indicator. Low for 1000Mb/s.
+ *      0100        Spd100                 100Mb/s Speed Indicator. Low for 100Mb/s.
+ *      0101        Spd10                  10Mb/s Speed Indicator. Low for 10Mb/s.
+ *      0110        Spd1000/Act            1000Mb/s Speed/Activity Indicator. Low for 1000Mb/s. Blinks every 43ms when the corresponding port is transmitting or receiving.
+ *      0111        Spd100/Act             100Mb/s Speed/Activity Indicator. Low for 100Mb/s. Blinks every 43ms when the corresponding port is transmitting or receiving.
+ *      1000        Spd10/Act              10Mb/s Speed/Activity Indicator. Low for 10Mb/s. Blinks every 43ms when the corresponding port is transmitting or receiving.
+ *      1001        Spd100 (10)/Act        10/100Mb/s Speed/Activity Indicator. Low for 10/100Mb/s. Blinks every 43ms when the corresponding port is transmitting or receiving.
+ *      1010        Fiber                  Fiber link Indicator. Low for Fiber.
+ *      1011        Fault                  Auto-negotiation     Fault Indicator. Low for Fault.
+ *      1100        Link/Rx                Link, Activity Indicator. Low for link established. Link/Rx Blinks every 43ms when the corresponding port is transmitting.
+ *      1101        Link/Tx                Link, Activity Indicator. Low for link established. Link/Tx Blinks every 43ms when the corresponding port is receiving.
+ *      1110        Master                 Link on Master Indicator. Low for link Master established.
+ *      1111        LED_Force              Force LED output, LED output value reference
+ */
+ret_t rtl8367c_setAsicLedIndicateInfoConfig(rtk_uint32 ledno, rtk_uint32 config)
+{
+    ret_t   retVal;
+    CONST rtk_uint16 bits[RTL8367C_LEDGROUPNO] = {RTL8367C_LED0_CFG_MASK, RTL8367C_LED1_CFG_MASK, RTL8367C_LED2_CFG_MASK};
+
+    if(ledno >= RTL8367C_LEDGROUPNO)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(config >= LEDCONF_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LED_CONFIGURATION, RTL8367C_LED_CONFIG_SEL_OFFSET, 0);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_LED_CONFIGURATION, bits[ledno], config);
+}
+/* Function Name:
+ *      rtl8367c_getAsicLedIndicateInfoConfig
+ * Description:
+ *      Get Leds indicated information mode
+ * Input:
+ *      ledno   - LED group number. There are 1 to 1 led mapping to each port in each led group
+ *      pConfig     - Support 16 types configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicLedIndicateInfoConfig(rtk_uint32 ledno, rtk_uint32* pConfig)
+{
+    CONST rtk_uint16 bits[RTL8367C_LEDGROUPNO]= {RTL8367C_LED0_CFG_MASK, RTL8367C_LED1_CFG_MASK, RTL8367C_LED2_CFG_MASK};
+
+    if(ledno >= RTL8367C_LEDGROUPNO)
+        return RT_ERR_OUT_OF_RANGE;
+
+    /* Get register value */
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_LED_CONFIGURATION, bits[ledno], pConfig);
+}
+/* Function Name:
+ *      rtl8367c_setAsicLedGroupMode
+ * Description:
+ *      Set Led Group mode
+ * Input:
+ *      mode    - LED mode
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicLedGroupMode(rtk_uint32 mode)
+{
+    ret_t retVal;
+
+    /* Invalid input parameter */
+    if(mode >= RTL8367C_LED_MODE_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LED_CONFIGURATION, RTL8367C_LED_CONFIG_SEL_OFFSET, 1);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_LED_CONFIGURATION, RTL8367C_DATA_LED_MASK, mode);
+}
+/* Function Name:
+ *      rtl8367c_getAsicLedGroupMode
+ * Description:
+ *      Get Led Group mode
+ * Input:
+ *      pMode   - LED mode
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicLedGroupMode(rtk_uint32* pMode)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+
+    retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_LED_CONFIGURATION, RTL8367C_LED_CONFIG_SEL_OFFSET, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    if(regData!=1)
+        return RT_ERR_FAILED;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_LED_CONFIGURATION, RTL8367C_DATA_LED_MASK, pMode);
+}
+/* Function Name:
+ *      rtl8367c_setAsicForceLeds
+ * Description:
+ *      Set group LED mode
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      group   - LED group number
+ *      mode    - LED mode
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicForceLed(rtk_uint32 port, rtk_uint32 group, rtk_uint32 mode)
+{
+    rtk_uint16 regAddr;
+    ret_t retVal;
+
+    /* Invalid input parameter */
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(group >= RTL8367C_LEDGROUPNO)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(mode >= LEDFORCEMODE_END)
+        return RT_ERR_OUT_OF_RANGE;
+    /* Set Related Registers */
+    if(port < 8){
+        regAddr = RTL8367C_LED_FORCE_MODE_BASE + (group << 1);
+        if((retVal = rtl8367c_setAsicRegBits(regAddr, 0x3 << (port * 2), mode)) != RT_ERR_OK)
+            return retVal;
+    }else if(port >= 8){
+        regAddr = RTL8367C_REG_CPU_FORCE_LED0_CFG1 + (group << 1);
+        if((retVal = rtl8367c_setAsicRegBits(regAddr, 0x3 << ((port-8) * 2), mode)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicForceLed
+ * Description:
+ *      Get group LED mode
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      group   - LED group number
+ *      pMode   - LED mode
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicForceLed(rtk_uint32 port, rtk_uint32 group, rtk_uint32* pMode)
+{
+    rtk_uint16 regAddr;
+    ret_t retVal;
+
+    /* Invalid input parameter */
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(group >= RTL8367C_LEDGROUPNO)
+        return RT_ERR_INPUT;
+
+    /* Get Related Registers */
+    if(port < 8){
+        regAddr = RTL8367C_LED_FORCE_MODE_BASE + (group << 1);
+        if((retVal = rtl8367c_getAsicRegBits(regAddr, 0x3 << (port * 2), pMode)) != RT_ERR_OK)
+            return retVal;
+    }else if(port >= 8){
+        regAddr = RTL8367C_REG_CPU_FORCE_LED0_CFG1 + (group << 1);
+        if((retVal = rtl8367c_getAsicRegBits(regAddr, 0x3 << ((port-8) * 2), pMode)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicForceGroupLed
+ * Description:
+ *      Turn on/off Led of all ports
+ * Input:
+ *      group   - LED group number
+ *      mode    - 0b00:normal mode, 0b01:force blink, 0b10:force off, 0b11:force on
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicForceGroupLed(rtk_uint32 groupmask, rtk_uint32 mode)
+{
+    ret_t retVal;
+    rtk_uint32 i,bitmask;
+    CONST rtk_uint16 bits[3]= {0x0004,0x0010,0x0040};
+
+    /* Invalid input parameter */
+    if(groupmask > RTL8367C_LEDGROUPMASK)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(mode >= LEDFORCEMODE_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    bitmask = 0;
+    for(i = 0; i <  RTL8367C_LEDGROUPNO; i++)
+    {
+        if(groupmask & (1 << i))
+        {
+            bitmask = bitmask | bits[i];
+        }
+
+    }
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_LED_FORCE_CTRL, RTL8367C_LED_FORCE_MODE_MASK, bitmask);
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_LED_FORCE_CTRL, RTL8367C_FORCE_MODE_MASK, mode);
+
+    if(LEDFORCEMODE_NORMAL == mode)
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_LED_FORCE_CTRL, RTL8367C_LED_FORCE_MODE_MASK, 0);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicForceGroupLed
+ * Description:
+ *      Turn on/off Led of all ports
+ * Input:
+ *      group   - LED group number
+ *      pMode   - 0b00:normal mode, 0b01:force blink, 0b10:force off, 0b11:force on
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicForceGroupLed(rtk_uint32* groupmask, rtk_uint32* pMode)
+{
+    ret_t retVal;
+    rtk_uint32 i,regData;
+    CONST rtk_uint16 bits[3] = {0x0004,0x0010,0x0040};
+
+    /* Get Related Registers */
+    if((retVal = rtl8367c_getAsicRegBits(RTL8367C_LED_FORCE_CTRL, RTL8367C_LED_FORCE_MODE_MASK, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    for(i = 0; i< RTL8367C_LEDGROUPNO; i++)
+    {
+        if((regData & bits[i]) == bits[i])
+        {
+            *groupmask = *groupmask | (1 << i);
+        }
+    }
+
+    return rtl8367c_getAsicRegBits(RTL8367C_LED_FORCE_CTRL, RTL8367C_FORCE_MODE_MASK, pMode);
+}
+/* Function Name:
+ *      rtl8367c_setAsicLedBlinkRate
+ * Description:
+ *      Set led blinking rate at mode 0 to mode 3
+ * Input:
+ *      blinkRate   - Support 6 blink rates
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      LED blink rate can be at 43ms, 84ms, 120ms, 170ms, 340ms and 670ms
+ */
+ret_t rtl8367c_setAsicLedBlinkRate(rtk_uint32 blinkRate)
+{
+    if(blinkRate >= LEDBLINKRATE_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_LED_MODE, RTL8367C_SEL_LEDRATE_MASK, blinkRate);
+}
+/* Function Name:
+ *      rtl8367c_getAsicLedBlinkRate
+ * Description:
+ *      Get led blinking rate at mode 0 to mode 3
+ * Input:
+ *      pBlinkRate  - Support 6 blink rates
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicLedBlinkRate(rtk_uint32* pBlinkRate)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_LED_MODE, RTL8367C_SEL_LEDRATE_MASK, pBlinkRate);
+}
+/* Function Name:
+ *      rtl8367c_setAsicLedForceBlinkRate
+ * Description:
+ *      Set LEd blinking rate for force mode led
+ * Input:
+ *      blinkRate   - Support 6 blink rates
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicLedForceBlinkRate(rtk_uint32 blinkRate)
+{
+    if(blinkRate >= LEDFORCERATE_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_LED_MODE, RTL8367C_FORCE_RATE_MASK, blinkRate);
+}
+/* Function Name:
+ *      rtl8367c_getAsicLedForceBlinkRate
+ * Description:
+ *      Get LED blinking rate for force mode led
+ * Input:
+ *      pBlinkRate  - Support 6 blink rates
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicLedForceBlinkRate(rtk_uint32* pBlinkRate)
+{
+     return rtl8367c_getAsicRegBits(RTL8367C_REG_LED_MODE, RTL8367C_FORCE_RATE_MASK, pBlinkRate);
+}
+
+/*
+@func ret_t | rtl8367c_setAsicLedGroupEnable | Turn on/off Led of all system ports
+@parm rtk_uint32 | group | LED group id.
+@parm rtk_uint32 | portmask | LED port mask.
+@rvalue RT_ERR_OK | Success.
+@rvalue RT_ERR_SMI | SMI access error.
+@rvalue RT_ERR_PORT_ID | Invalid port number.
+@rvalue RT_ERR_INPUT | Invalid input value.
+@comm
+    The API can turn on/off leds of dedicated port while indicated information configuration of LED group is set to force mode.
+ */
+ret_t rtl8367c_setAsicLedGroupEnable(rtk_uint32 group, rtk_uint32 portmask)
+{
+    ret_t retVal;
+    rtk_uint32 regAddr;
+    rtk_uint32 regDataMask;
+
+    if ( group >= RTL8367C_LEDGROUPNO )
+        return RT_ERR_INPUT;
+
+    regAddr = RTL8367C_REG_PARA_LED_IO_EN1 + group/2;
+    regDataMask = 0xFF << ((group%2)*8);
+    retVal = rtl8367c_setAsicRegBits(regAddr, regDataMask, portmask&0xff);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    regAddr = RTL8367C_REG_PARA_LED_IO_EN3;
+    regDataMask = 0x3 << (group*2);
+    retVal = rtl8367c_setAsicRegBits(regAddr, regDataMask, (portmask>>8)&0x7);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+
+    return RT_ERR_OK;
+}
+
+/*
+@func ret_t | rtl8367c_getAsicLedGroupEnable | Get on/off status of Led of all system ports
+@parm rtk_uint32 | group | LED group id.
+@parm rtk_uint32 | *portmask | LED port mask.
+@rvalue RT_ERR_OK | Success.
+@rvalue RT_ERR_SMI | SMI access error.
+@rvalue RT_ERR_PORT_ID | Invalid port number.
+@rvalue RT_ERR_INPUT | Invalid input value.
+@comm
+    The API can turn on/off leds of dedicated port while indicated information configuration of LED group is set to force mode.
+ */
+ret_t rtl8367c_getAsicLedGroupEnable(rtk_uint32 group, rtk_uint32 *portmask)
+{
+    ret_t retVal;
+    rtk_uint32 regAddr;
+    rtk_uint32 regDataMask,regData;
+
+    if ( group >= RTL8367C_LEDGROUPNO )
+        return RT_ERR_INPUT;
+
+    regAddr = RTL8367C_REG_PARA_LED_IO_EN1 + group/2;
+    regDataMask = 0xFF << ((group%2)*8);
+    retVal = rtl8367c_getAsicRegBits(regAddr, regDataMask, portmask);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+
+    regAddr = RTL8367C_REG_PARA_LED_IO_EN3;
+    regDataMask = 0x3 << (group*2);
+    retVal = rtl8367c_getAsicRegBits(regAddr, regDataMask, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *portmask = (regData << 8) | *portmask;
+
+    return RT_ERR_OK;
+}
+
+/*
+@func ret_t | rtl8367c_setAsicLedOperationMode | Set LED operation mode
+@parm rtk_uint32 | mode | LED mode. 1:scan mode 1, 2:parallel mode, 3:mdx mode (serial mode)
+@rvalue RT_ERR_OK | Success.
+@rvalue RT_ERR_SMI | SMI access error.
+@rvalue RT_ERR_INPUT | Invalid input value.
+@comm
+    The API can turn on/off led serial mode and set signal to active high/low.
+ */
+ret_t rtl8367c_setAsicLedOperationMode(rtk_uint32 mode)
+{
+    ret_t retVal;
+
+    /* Invalid input parameter */
+    if( mode >= LEDOP_END)
+        return RT_ERR_INPUT;
+
+    switch(mode)
+    {
+        case LEDOP_PARALLEL:
+            if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LED_SYS_CONFIG, RTL8367C_LED_SELECT_OFFSET, 0))!=  RT_ERR_OK)
+                return retVal;
+            /*Disable serial CLK mode*/
+            if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SCAN0_LED_IO_EN1,RTL8367C_LED_SERI_CLK_EN_OFFSET, 0))!=  RT_ERR_OK)
+                return retVal;
+            /*Disable serial DATA mode*/
+            if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SCAN0_LED_IO_EN1,RTL8367C_LED_SERI_DATA_EN_OFFSET, 0))!=  RT_ERR_OK)
+                return retVal;
+            break;
+        case LEDOP_SERIAL:
+            if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LED_SYS_CONFIG, RTL8367C_LED_SELECT_OFFSET, 1))!=  RT_ERR_OK)
+                return retVal;
+            /*Enable serial CLK mode*/
+            if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SCAN0_LED_IO_EN1,RTL8367C_LED_SERI_CLK_EN_OFFSET, 1))!=  RT_ERR_OK)
+                return retVal;
+            /*Enable serial DATA mode*/
+            if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SCAN0_LED_IO_EN1,RTL8367C_LED_SERI_DATA_EN_OFFSET, 1))!=  RT_ERR_OK)
+                return retVal;
+            break;
+        default:
+            return RT_ERR_INPUT;
+            break;
+    }
+
+    return RT_ERR_OK;
+}
+
+
+/*
+@func ret_t | rtl8367c_getAsicLedOperationMode | Get LED OP mode setup
+@parm rtk_uint32*| mode | LED mode. 1:scan mode 1, 2:parallel mode, 3:mdx mode (serial mode)
+@rvalue RT_ERR_OK | Success.
+@rvalue RT_ERR_SMI | SMI access error.
+@rvalue RT_ERR_INPUT | Invalid input value.
+@comm
+    The API can get LED serial mode setup and get signal active high/low.
+ */
+ret_t rtl8367c_getAsicLedOperationMode(rtk_uint32 *mode)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+
+    if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_LED_SYS_CONFIG, RTL8367C_LED_SELECT_OFFSET, &regData))!=  RT_ERR_OK)
+        return retVal;
+
+    if (regData == 1)
+        *mode = LEDOP_SERIAL;
+    else if (regData == 0)
+        *mode = LEDOP_PARALLEL;
+    else
+        return RT_ERR_FAILED;
+
+    return RT_ERR_OK;
+}
+
+/*
+@func ret_t | rtl8367c_setAsicLedSerialModeConfig | Set LED serial mode
+@parm rtk_uint32 | active | Active High or Low.
+@rvalue RT_ERR_OK | Success.
+@rvalue RT_ERR_SMI | SMI access error.
+@rvalue RT_ERR_INPUT | Invalid input value.
+@comm
+    The API can turn on/off led serial mode and set signal to active high/low.
+ */
+ret_t rtl8367c_setAsicLedSerialModeConfig(rtk_uint32 active, rtk_uint32 serimode)
+{
+    ret_t retVal;
+
+    /* Invalid input parameter */
+    if( active >= LEDSERACT_MAX)
+        return RT_ERR_INPUT;
+    if( serimode >= LEDSER_MAX)
+        return RT_ERR_INPUT;
+
+    /* Set Active High or Low */
+    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LED_SYS_CONFIG, RTL8367C_SERI_LED_ACT_LOW_OFFSET, active)) !=  RT_ERR_OK)
+        return retVal;
+
+    /*set to 8G mode (not 16G mode)*/
+    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LED_MODE, RTL8367C_DLINK_TIME_OFFSET, serimode))!=  RT_ERR_OK)
+        return retVal;
+
+
+    return RT_ERR_OK;
+}
+
+
+/*
+@func ret_t | rtl8367c_getAsicLedSerialModeConfig | Get LED serial mode setup
+@parm rtk_uint32*| active | Active High or Low.
+@rvalue RT_ERR_OK | Success.
+@rvalue RT_ERR_SMI | SMI access error.
+@rvalue RT_ERR_INPUT | Invalid input value.
+@comm
+    The API can get LED serial mode setup and get signal active high/low.
+ */
+ret_t rtl8367c_getAsicLedSerialModeConfig(rtk_uint32 *active, rtk_uint32 *serimode)
+{
+    ret_t retVal;
+
+    if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_LED_SYS_CONFIG, RTL8367C_SERI_LED_ACT_LOW_OFFSET, active))!=  RT_ERR_OK)
+        return retVal;
+
+    /*get to 8G mode (not 16G mode)*/
+    if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_LED_MODE, RTL8367C_DLINK_TIME_OFFSET, serimode))!=  RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+
+/*
+@func ret_t | rtl8367c_setAsicLedOutputEnable | Set LED output enable
+@parm rtk_uint32 | enabled | enable or disalbe.
+@rvalue RT_ERR_OK | Success.
+@rvalue RT_ERR_SMI | SMI access error.
+@rvalue RT_ERR_INPUT | Invalid input value.
+@comm
+    The API can turn on/off LED output Enable
+ */
+ret_t rtl8367c_setAsicLedOutputEnable(rtk_uint32 enabled)
+{
+    ret_t retVal;
+    rtk_uint32 regdata;
+
+    if (enabled == 1)
+        regdata = 0;
+    else
+        regdata = 1;
+
+    /* Enable/Disable H/W IGMP/MLD */
+    retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LED_SYS_CONFIG, RTL8367C_LED_IO_DISABLE_OFFSET, regdata);
+
+    return retVal;
+}
+
+
+/*
+@func ret_t | rtl8367c_getAsicLedOutputEnable | Get LED serial mode setup
+@parm rtk_uint32*| active | Active High or Low.
+@rvalue RT_ERR_OK | Success.
+@rvalue RT_ERR_SMI | SMI access error.
+@rvalue RT_ERR_INPUT | Invalid input value.
+@comm
+    The API can get LED serial mode setup and get signal active high/low.
+ */
+ret_t rtl8367c_getAsicLedOutputEnable(rtk_uint32 *ptr_enabled)
+{
+    ret_t retVal;
+    rtk_uint32 regdata;
+
+    retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_LED_SYS_CONFIG, RTL8367C_LED_IO_DISABLE_OFFSET, &regdata);
+    if (retVal != RT_ERR_OK)
+        return retVal;
+
+    if (regdata == 1)
+        *ptr_enabled = 0;
+    else
+        *ptr_enabled = 1;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicLedSerialOutput
+ * Description:
+ *      Set serial LED output group and portmask.
+ * Input:
+ *      output      - Serial LED output group
+ *      pmask       - Serial LED output portmask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicLedSerialOutput(rtk_uint32 output, rtk_uint32 pmask)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SERIAL_LED_CTRL, RTL8367C_SERIAL_LED_GROUP_NUM_MASK, output);
+    if (retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SERIAL_LED_CTRL, RTL8367C_SERIAL_LED_PORT_EN_MASK, pmask);
+    if (retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicLedSerialOutput
+ * Description:
+ *      Get serial LED output group and portmask.
+ * Input:
+ *      None
+ * Output:
+ *      pOutput      - Serial LED output group
+ *      pPmask       - Serial LED output portmask
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicLedSerialOutput(rtk_uint32 *pOutput, rtk_uint32 *pPmask)
+{
+    ret_t retVal;
+
+    if(pOutput == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    if(pPmask == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SERIAL_LED_CTRL, RTL8367C_SERIAL_LED_GROUP_NUM_MASK, pOutput);
+    if (retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SERIAL_LED_CTRL, RTL8367C_SERIAL_LED_PORT_EN_MASK, pPmask);
+    if (retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_lut.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_lut.c
new file mode 100644
index 0000000..343a6f1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_lut.c
@@ -0,0 +1,1549 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : LUT related functions
+ *
+ */
+
+#include <rtl8367c_asicdrv_lut.h>
+
+#include <string.h>
+
+static void _rtl8367c_fdbStUser2Smi( rtl8367c_luttb *pLutSt, rtk_uint16 *pFdbSmi)
+{
+    /* L3 lookup */
+    if(pLutSt->l3lookup)
+    {
+        if(pLutSt->l3vidlookup)
+        {
+            pFdbSmi[0] = (pLutSt->sip & 0x0000FFFF);
+            pFdbSmi[1] = (pLutSt->sip & 0xFFFF0000) >> 16;
+
+            pFdbSmi[2] = (pLutSt->dip & 0x0000FFFF);
+            pFdbSmi[3] = (pLutSt->dip & 0x0FFF0000) >> 16;
+
+            pFdbSmi[3] |= (pLutSt->l3lookup & 0x0001) << 12;
+            pFdbSmi[3] |= (pLutSt->l3vidlookup & 0x0001) << 13;
+            pFdbSmi[3] |= ((pLutSt->mbr & 0x0300) >> 8) << 14;
+
+            pFdbSmi[4] |= (pLutSt->mbr & 0x00FF);
+            pFdbSmi[4] |= (pLutSt->l3_vid & 0x00FF) << 8;
+
+            pFdbSmi[5] |= ((pLutSt->l3_vid & 0x0F00) >> 8);
+            pFdbSmi[5] |= (pLutSt->nosalearn & 0x0001) << 5;
+            pFdbSmi[5] |= ((pLutSt->mbr & 0x0400) >> 10) << 7;
+        }
+        else
+        {
+            pFdbSmi[0] = (pLutSt->sip & 0x0000FFFF);
+            pFdbSmi[1] = (pLutSt->sip & 0xFFFF0000) >> 16;
+
+            pFdbSmi[2] = (pLutSt->dip & 0x0000FFFF);
+            pFdbSmi[3] = (pLutSt->dip & 0x0FFF0000) >> 16;
+
+            pFdbSmi[3] |= (pLutSt->l3lookup & 0x0001) << 12;
+            pFdbSmi[3] |= (pLutSt->l3vidlookup & 0x0001) << 13;
+            pFdbSmi[3] |= ((pLutSt->mbr & 0x0300) >> 8) << 14;
+
+            pFdbSmi[4] |= (pLutSt->mbr & 0x00FF);
+            pFdbSmi[4] |= (pLutSt->igmpidx & 0x00FF) << 8;
+
+            pFdbSmi[5] |= (pLutSt->igmp_asic & 0x0001);
+            pFdbSmi[5] |= (pLutSt->lut_pri & 0x0007) << 1;
+            pFdbSmi[5] |= (pLutSt->fwd_en & 0x0001) << 4;
+            pFdbSmi[5] |= (pLutSt->nosalearn & 0x0001) << 5;
+            pFdbSmi[5] |= ((pLutSt->mbr & 0x0400) >> 10) << 7;
+        }
+    }
+    else if(pLutSt->mac.octet[0] & 0x01) /*Multicast L2 Lookup*/
+    {
+        pFdbSmi[0] |= pLutSt->mac.octet[5];
+        pFdbSmi[0] |= pLutSt->mac.octet[4] << 8;
+
+        pFdbSmi[1] |= pLutSt->mac.octet[3];
+        pFdbSmi[1] |= pLutSt->mac.octet[2] << 8;
+
+        pFdbSmi[2] |= pLutSt->mac.octet[1];
+        pFdbSmi[2] |= pLutSt->mac.octet[0] << 8;
+
+        pFdbSmi[3] |= pLutSt->cvid_fid;
+        pFdbSmi[3] |= (pLutSt->l3lookup & 0x0001) << 12;
+        pFdbSmi[3] |= (pLutSt->ivl_svl & 0x0001) << 13;
+        pFdbSmi[3] |= ((pLutSt->mbr & 0x0300) >> 8) << 14;
+
+        pFdbSmi[4] |= (pLutSt->mbr & 0x00FF);
+        pFdbSmi[4] |= (pLutSt->igmpidx & 0x00FF) << 8;
+
+        pFdbSmi[5] |= pLutSt->igmp_asic;
+        pFdbSmi[5] |= (pLutSt->lut_pri & 0x0007) << 1;
+        pFdbSmi[5] |= (pLutSt->fwd_en & 0x0001) << 4;
+        pFdbSmi[5] |= (pLutSt->nosalearn & 0x0001) << 5;
+        pFdbSmi[5] |= ((pLutSt->mbr & 0x0400) >> 10) << 7;
+    }
+    else /*Asic auto-learning*/
+    {
+        pFdbSmi[0] |= pLutSt->mac.octet[5];
+        pFdbSmi[0] |= pLutSt->mac.octet[4] << 8;
+
+        pFdbSmi[1] |= pLutSt->mac.octet[3];
+        pFdbSmi[1] |= pLutSt->mac.octet[2] << 8;
+
+        pFdbSmi[2] |= pLutSt->mac.octet[1];
+        pFdbSmi[2] |= pLutSt->mac.octet[0] << 8;
+
+        pFdbSmi[3] |= pLutSt->cvid_fid;
+        pFdbSmi[3] |= (pLutSt->l3lookup & 0x0001) << 12;
+        pFdbSmi[3] |= (pLutSt->ivl_svl & 0x0001) << 13;
+        pFdbSmi[3] |= ((pLutSt->spa & 0x0008) >> 3) << 15;
+
+        pFdbSmi[4] |= pLutSt->efid;
+        pFdbSmi[4] |= (pLutSt->fid & 0x000F) << 3;
+        pFdbSmi[4] |= (pLutSt->sa_en & 0x0001) << 7;
+        pFdbSmi[4] |= (pLutSt->spa & 0x0007) << 8;
+        pFdbSmi[4] |= (pLutSt->age & 0x0007) << 11;
+        pFdbSmi[4] |= (pLutSt->auth & 0x0001) << 14;
+        pFdbSmi[4] |= (pLutSt->sa_block & 0x0001) << 15;
+
+        pFdbSmi[5] |= pLutSt->da_block;
+        pFdbSmi[5] |= (pLutSt->lut_pri & 0x0007) << 1;
+        pFdbSmi[5] |= (pLutSt->fwd_en & 0x0001) << 4;
+        pFdbSmi[5] |= (pLutSt->nosalearn & 0x0001) << 5;
+    }
+}
+
+
+static void _rtl8367c_fdbStSmi2User( rtl8367c_luttb *pLutSt, rtk_uint16 *pFdbSmi)
+{
+    /*L3 lookup*/
+    if(pFdbSmi[3] & 0x1000)
+    {
+        if(pFdbSmi[3] & 0x2000)
+        {
+            pLutSt->sip             = pFdbSmi[0] | (pFdbSmi[1] << 16);
+            pLutSt->dip             = pFdbSmi[2] | ((pFdbSmi[3] & 0x0FFF) << 16);
+
+            pLutSt->mbr             = (pFdbSmi[4] & 0x00FF) | (((pFdbSmi[3] & 0xC000) >> 14) << 8) | (((pFdbSmi[5] & 0x0080) >> 7) << 10);
+            pLutSt->l3_vid          = ((pFdbSmi[4] & 0xFF00) >> 8) | (pFdbSmi[5] & 0x000F);
+
+            pLutSt->l3lookup        = (pFdbSmi[3] & 0x1000) >> 12;
+            pLutSt->l3vidlookup     = (pFdbSmi[3] & 0x2000) >> 13;
+            pLutSt->nosalearn       = (pFdbSmi[5] & 0x0020) >> 5;
+        }
+        else
+        {
+            pLutSt->sip             = pFdbSmi[0] | (pFdbSmi[1] << 16);
+            pLutSt->dip             = pFdbSmi[2] | ((pFdbSmi[3] & 0x0FFF) << 16);
+
+            pLutSt->lut_pri         = (pFdbSmi[5] & 0x000E) >> 1;
+            pLutSt->fwd_en          = (pFdbSmi[5] & 0x0010) >> 4;
+
+            pLutSt->mbr             = (pFdbSmi[4] & 0x00FF) | (((pFdbSmi[3] & 0xC000) >> 14) << 8) | (((pFdbSmi[5] & 0x0080) >> 7) << 10);
+            pLutSt->igmpidx         = (pFdbSmi[4] & 0xFF00) >> 8;
+
+            pLutSt->igmp_asic       = (pFdbSmi[5] & 0x0001);
+            pLutSt->l3lookup        = (pFdbSmi[3] & 0x1000) >> 12;
+            pLutSt->nosalearn       = (pFdbSmi[5] & 0x0020) >> 5;
+        }
+    }
+    else if(pFdbSmi[2] & 0x0100) /*Multicast L2 Lookup*/
+    {
+        pLutSt->mac.octet[0]    = (pFdbSmi[2] & 0xFF00) >> 8;
+        pLutSt->mac.octet[1]    = (pFdbSmi[2] & 0x00FF);
+        pLutSt->mac.octet[2]    = (pFdbSmi[1] & 0xFF00) >> 8;
+        pLutSt->mac.octet[3]    = (pFdbSmi[1] & 0x00FF);
+        pLutSt->mac.octet[4]    = (pFdbSmi[0] & 0xFF00) >> 8;
+        pLutSt->mac.octet[5]    = (pFdbSmi[0] & 0x00FF);
+
+        pLutSt->cvid_fid        = pFdbSmi[3] & 0x0FFF;
+        pLutSt->lut_pri         = (pFdbSmi[5] & 0x000E) >> 1;
+        pLutSt->fwd_en          = (pFdbSmi[5] & 0x0010) >> 4;
+
+        pLutSt->mbr             = (pFdbSmi[4] & 0x00FF) | (((pFdbSmi[3] & 0xC000) >> 14) << 8) | (((pFdbSmi[5] & 0x0080) >> 7) << 10);
+        pLutSt->igmpidx         = (pFdbSmi[4] & 0xFF00) >> 8;
+
+        pLutSt->igmp_asic       = (pFdbSmi[5] & 0x0001);
+        pLutSt->l3lookup        = (pFdbSmi[3] & 0x1000) >> 12;
+        pLutSt->ivl_svl         = (pFdbSmi[3] & 0x2000) >> 13;
+        pLutSt->nosalearn       = (pFdbSmi[5] & 0x0020) >> 5;
+    }
+    else /*Asic auto-learning*/
+    {
+        pLutSt->mac.octet[0]    = (pFdbSmi[2] & 0xFF00) >> 8;
+        pLutSt->mac.octet[1]    = (pFdbSmi[2] & 0x00FF);
+        pLutSt->mac.octet[2]    = (pFdbSmi[1] & 0xFF00) >> 8;
+        pLutSt->mac.octet[3]    = (pFdbSmi[1] & 0x00FF);
+        pLutSt->mac.octet[4]    = (pFdbSmi[0] & 0xFF00) >> 8;
+        pLutSt->mac.octet[5]    = (pFdbSmi[0] & 0x00FF);
+
+        pLutSt->cvid_fid        = pFdbSmi[3] & 0x0FFF;
+        pLutSt->lut_pri         = (pFdbSmi[5] & 0x000E) >> 1;
+        pLutSt->fwd_en          = (pFdbSmi[5] & 0x0010) >> 4;
+
+        pLutSt->sa_en           = (pFdbSmi[4] & 0x0080) >> 7;
+        pLutSt->auth            = (pFdbSmi[4] & 0x4000) >> 14;
+        pLutSt->spa             = ((pFdbSmi[4] & 0x0700) >> 8) | (((pFdbSmi[3] & 0x8000) >> 15) << 3);
+        pLutSt->age             = (pFdbSmi[4] & 0x3800) >> 11;
+        pLutSt->fid             = (pFdbSmi[4] & 0x0078) >> 3;
+        pLutSt->efid            = (pFdbSmi[4] & 0x0007);
+        pLutSt->sa_block        = (pFdbSmi[4] & 0x8000) >> 15;
+
+        pLutSt->da_block        = (pFdbSmi[5] & 0x0001);
+        pLutSt->l3lookup        = (pFdbSmi[3] & 0x1000) >> 12;
+        pLutSt->ivl_svl         = (pFdbSmi[3] & 0x2000) >> 13;
+        pLutSt->nosalearn       = (pFdbSmi[3] & 0x0020) >> 5;
+    }
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicLutIpMulticastLookup
+ * Description:
+ *      Set Lut IP multicast lookup function
+ * Input:
+ *      enabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicLutIpMulticastLookup(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_LUT_IPMC_HASH_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicLutIpMulticastLookup
+ * Description:
+ *      Get Lut IP multicast lookup function
+ * Input:
+ *      pEnabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicLutIpMulticastLookup(rtk_uint32* pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_LUT_IPMC_HASH_OFFSET, pEnabled);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicLutIpMulticastLookup
+ * Description:
+ *      Set Lut IP multicast + VID lookup function
+ * Input:
+ *      enabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicLutIpMulticastVidLookup(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_LUT_CFG2, RTL8367C_LUT_IPMC_VID_HASH_OFFSET, enabled);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicLutIpMulticastVidLookup
+ * Description:
+ *      Get Lut IP multicast lookup function
+ * Input:
+ *      pEnabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicLutIpMulticastVidLookup(rtk_uint32* pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_LUT_CFG2, RTL8367C_LUT_IPMC_VID_HASH_OFFSET, pEnabled);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicLutIpLookupMethod
+ * Description:
+ *      Set Lut IP lookup hash with DIP or {DIP,SIP} pair
+ * Input:
+ *      type - 1: When DIP can be found in IPMC_GROUP_TABLE, use DIP+SIP Hash, otherwise, use DIP+(SIP=0.0.0.0) Hash.
+ *             0: When DIP can be found in IPMC_GROUP_TABLE, use DIP+(SIP=0.0.0.0) Hash, otherwise use DIP+SIP Hash.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicLutIpLookupMethod(rtk_uint32 type)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_LUT_IPMC_LOOKUP_OP_OFFSET, type);
+}
+/* Function Name:
+ *      rtl8367c_getAsicLutIpLookupMethod
+ * Description:
+ *      Get Lut IP lookup hash with DIP or {DIP,SIP} pair
+ * Input:
+ *      pType - 1: When DIP can be found in IPMC_GROUP_TABLE, use DIP+SIP Hash, otherwise, use DIP+(SIP=0.0.0.0) Hash.
+ *              0: When DIP can be found in IPMC_GROUP_TABLE, use DIP+(SIP=0.0.0.0) Hash, otherwise use DIP+SIP Hash.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicLutIpLookupMethod(rtk_uint32* pType)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_LUT_IPMC_LOOKUP_OP_OFFSET, pType);
+}
+/* Function Name:
+ *      rtl8367c_setAsicLutAgeTimerSpeed
+ * Description:
+ *      Set LUT agging out speed
+ * Input:
+ *      timer - Agging out timer 0:Has been aged out
+ *      speed - Agging out speed 0-fastest 3-slowest
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicLutAgeTimerSpeed(rtk_uint32 timer, rtk_uint32 speed)
+{
+    if(timer>RTL8367C_LUT_AGETIMERMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(speed >RTL8367C_LUT_AGESPEEDMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_LUT_CFG, RTL8367C_AGE_TIMER_MASK | RTL8367C_AGE_SPEED_MASK, (timer << RTL8367C_AGE_TIMER_OFFSET) | (speed << RTL8367C_AGE_SPEED_OFFSET));
+}
+/* Function Name:
+ *      rtl8367c_getAsicLutAgeTimerSpeed
+ * Description:
+ *      Get LUT agging out speed
+ * Input:
+ *      pTimer - Agging out timer 0:Has been aged out
+ *      pSpeed - Agging out speed 0-fastest 3-slowest
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicLutAgeTimerSpeed(rtk_uint32* pTimer, rtk_uint32* pSpeed)
+{
+    rtk_uint32 regData;
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_REG_LUT_CFG, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *pTimer =  (regData & RTL8367C_AGE_TIMER_MASK) >> RTL8367C_AGE_TIMER_OFFSET;
+
+    *pSpeed =  (regData & RTL8367C_AGE_SPEED_MASK) >> RTL8367C_AGE_SPEED_OFFSET;
+
+    return RT_ERR_OK;
+
+}
+/* Function Name:
+ *      rtl8367c_setAsicLutCamTbUsage
+ * Description:
+ *      Configure Lut CAM table usage
+ * Input:
+ *      enabled - L2 CAM table usage 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicLutCamTbUsage(rtk_uint32 enabled)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_BCAM_DISABLE_OFFSET, enabled ? 0 : 1);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicLutCamTbUsage
+ * Description:
+ *      Get Lut CAM table usage
+ * Input:
+ *      pEnabled - L2 CAM table usage 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicLutCamTbUsage(rtk_uint32* pEnabled)
+{
+    ret_t       retVal;
+    rtk_uint32  regData;
+
+    if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_BCAM_DISABLE_OFFSET, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    *pEnabled = regData ? 0 : 1;
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicLutLearnLimitNo
+ * Description:
+ *      Set per-Port auto learning limit number
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      number  - ASIC auto learning entries limit number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number
+ *      RT_ERR_LIMITED_L2ENTRY_NUM  - Invalid auto learning limit number
+ * Note:
+ *      None
+ */
+   /*ÐÞ¸Ä: RTL8367C_PORTIDMAX, RTL8367C_LUT_LEARNLIMITMAX, RTL8367C_LUT_PORT_LEARN_LIMITNO_REG*/
+ret_t rtl8367c_setAsicLutLearnLimitNo(rtk_uint32 port, rtk_uint32 number)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(number > RTL8367C_LUT_LEARNLIMITMAX)
+        return RT_ERR_LIMITED_L2ENTRY_NUM;
+
+    if(port < 8)
+     return rtl8367c_setAsicReg(RTL8367C_LUT_PORT_LEARN_LIMITNO_REG(port), number);
+    else
+        return rtl8367c_setAsicReg(RTL8367C_REG_LUT_PORT8_LEARN_LIMITNO+port-8, number);
+
+}
+/* Function Name:
+ *      rtl8367c_getAsicLutLearnLimitNo
+ * Description:
+ *      Get per-Port auto learning limit number
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pNumber     - ASIC auto learning entries limit number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+  /*ÐÞ¸Ä: RTL8367C_PORTIDMAX, RTL8367C_LUT_PORT_LEARN_LIMITNO_REG*/
+ret_t rtl8367c_getAsicLutLearnLimitNo(rtk_uint32 port, rtk_uint32* pNumber)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(port < 8)
+     return rtl8367c_getAsicReg(RTL8367C_LUT_PORT_LEARN_LIMITNO_REG(port), pNumber);
+    else
+        return rtl8367c_getAsicReg(RTL8367C_REG_LUT_PORT8_LEARN_LIMITNO+port-8, pNumber);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicSystemLutLearnLimitNo
+ * Description:
+ *      Set system auto learning limit number
+ * Input:
+ *      number  - ASIC auto learning entries limit number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number
+ *      RT_ERR_LIMITED_L2ENTRY_NUM  - Invalid auto learning limit number
+ * Note:
+ *      None
+ */
+  /*ÐÞ¸Ä: RTL8367C_LUT_LEARNLIMITMAX*/
+ret_t rtl8367c_setAsicSystemLutLearnLimitNo(rtk_uint32 number)
+{
+    if(number > RTL8367C_LUT_LEARNLIMITMAX)
+        return RT_ERR_LIMITED_L2ENTRY_NUM;
+
+    return rtl8367c_setAsicReg(RTL8367C_REG_LUT_SYS_LEARN_LIMITNO, number);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicSystemLutLearnLimitNo
+ * Description:
+ *      Get system auto learning limit number
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pNumber     - ASIC auto learning entries limit number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicSystemLutLearnLimitNo(rtk_uint32 *pNumber)
+{
+    if(NULL == pNumber)
+        return RT_ERR_NULL_POINTER;
+
+    return rtl8367c_getAsicReg(RTL8367C_REG_LUT_SYS_LEARN_LIMITNO, pNumber);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicLutLearnOverAct
+ * Description:
+ *      Set auto learn over limit number action
+ * Input:
+ *      action  - Learn over action 0:normal, 1:drop 2:trap
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_NOT_ALLOWED  - Invalid learn over action
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicLutLearnOverAct(rtk_uint32 action)
+{
+    if(action >= LRNOVERACT_END)
+        return RT_ERR_NOT_ALLOWED;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_PORT_SECURITY_CTRL, RTL8367C_LUT_LEARN_OVER_ACT_MASK, action);
+}
+/* Function Name:
+ *      rtl8367c_getAsicLutLearnOverAct
+ * Description:
+ *      Get auto learn over limit number action
+ * Input:
+ *      pAction     - Learn over action 0:normal, 1:drop 2:trap
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicLutLearnOverAct(rtk_uint32* pAction)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_SECURITY_CTRL, RTL8367C_LUT_LEARN_OVER_ACT_MASK, pAction);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicSystemLutLearnOverAct
+ * Description:
+ *      Set system auto learn over limit number action
+ * Input:
+ *      action  - Learn over action 0:normal, 1:drop, 2:trap
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_NOT_ALLOWED  - Invalid learn over action
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicSystemLutLearnOverAct(rtk_uint32 action)
+{
+    if(action >= LRNOVERACT_END)
+        return RT_ERR_NOT_ALLOWED;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_LUT_LRN_SYS_LMT_CTRL, RTL8367C_LUT_SYSTEM_LEARN_OVER_ACT_MASK, action);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicSystemLutLearnOverAct
+ * Description:
+ *      Get system auto learn over limit number action
+ * Input:
+ *      pAction     - Learn over action 0:normal, 1:drop 2:trap
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicSystemLutLearnOverAct(rtk_uint32 *pAction)
+{
+    if(NULL == pAction)
+        return RT_ERR_NULL_POINTER;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_LUT_LRN_SYS_LMT_CTRL, RTL8367C_LUT_SYSTEM_LEARN_OVER_ACT_MASK, pAction);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicSystemLutLearnPortMask
+ * Description:
+ *      Set system auto learn limit port mask
+ * Input:
+ *      portmask    - port mask of system learning limit
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK    - Error port mask
+ * Note:
+ *      None
+ */
+  /*ÐÞ¸Ä: RTL8367C_LUT_SYSTEM_LEARN_PMASK_MASK*/
+ret_t rtl8367c_setAsicSystemLutLearnPortMask(rtk_uint32 portmask)
+{
+    ret_t retVal;
+
+    if(portmask > RTL8367C_PORTMASK)
+        return RT_ERR_PORT_MASK;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_LUT_LRN_SYS_LMT_CTRL, RTL8367C_LUT_SYSTEM_LEARN_PMASK_MASK, portmask & 0xff);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_LUT_LRN_SYS_LMT_CTRL, RTL8367C_LUT_SYSTEM_LEARN_PMASK1_MASK, (portmask>>8) & 0x7);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicSystemLutLearnPortMask
+ * Description:
+ *      Get system auto learn limit port mask
+ * Input:
+ *      None
+ * Output:
+ *      pPortmask   - port mask of system learning limit
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_NULL_POINTER - NULL pointer
+ * Note:
+ *      None
+ */
+ /*ÐÞ¸Ä: RTL8367C_LUT_SYSTEM_LEARN_PMASK_MASK*/
+ret_t rtl8367c_getAsicSystemLutLearnPortMask(rtk_uint32 *pPortmask)
+{
+    rtk_uint32 tmpmask;
+    ret_t retVal;
+
+    if(NULL == pPortmask)
+        return RT_ERR_NULL_POINTER;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_LUT_LRN_SYS_LMT_CTRL, RTL8367C_LUT_SYSTEM_LEARN_PMASK_MASK, &tmpmask);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+    *pPortmask = tmpmask & 0xff;
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_LUT_LRN_SYS_LMT_CTRL, RTL8367C_LUT_SYSTEM_LEARN_PMASK1_MASK, &tmpmask);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+    *pPortmask |= (tmpmask & 0x7) << 8;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicL2LookupTb
+ * Description:
+ *      Set filtering database entry
+ * Input:
+ *      pL2Table    - L2 table entry writing to 8K+64 filtering database
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicL2LookupTb(rtl8367c_luttb *pL2Table)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+    rtk_uint16 *accessPtr;
+    rtk_uint32 i;
+    rtk_uint16 smil2Table[RTL8367C_LUT_TABLE_SIZE];
+    rtk_uint32 tblCmd;
+    rtk_uint32 busyCounter;
+
+    memset(smil2Table, 0x00, sizeof(rtk_uint16) * RTL8367C_LUT_TABLE_SIZE);
+    _rtl8367c_fdbStUser2Smi(pL2Table, smil2Table);
+
+    if(pL2Table->wait_time == 0)
+        busyCounter = RTL8367C_LUT_BUSY_CHECK_NO;
+    else
+        busyCounter = pL2Table->wait_time;
+
+    while(busyCounter)
+    {
+        retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET,&regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        pL2Table->lookup_busy = regData;
+        if(!regData)
+            break;
+
+        busyCounter --;
+        if(busyCounter == 0)
+            return RT_ERR_BUSYWAIT_TIMEOUT;
+    }
+
+    accessPtr = smil2Table;
+    regData = *accessPtr;
+    for(i = 0; i < RTL8367C_LUT_ENTRY_SIZE; i++)
+    {
+        retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_WRDATA_BASE + i, regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        accessPtr ++;
+        regData = *accessPtr;
+
+    }
+
+    tblCmd = (RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_WRITE,TB_TARGET_L2)) & (RTL8367C_TABLE_TYPE_MASK  | RTL8367C_COMMAND_TYPE_MASK);
+    /* Write Command */
+    retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_CTRL_REG, tblCmd);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    if(pL2Table->wait_time == 0)
+        busyCounter = RTL8367C_LUT_BUSY_CHECK_NO;
+    else
+        busyCounter = pL2Table->wait_time;
+
+    while(busyCounter)
+    {
+        retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET,&regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        pL2Table->lookup_busy = regData;
+        if(!regData)
+            break;
+
+        busyCounter --;
+        if(busyCounter == 0)
+            return RT_ERR_BUSYWAIT_TIMEOUT;
+    }
+
+    /*Read access status*/
+    retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_HIT_STATUS_OFFSET, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    pL2Table->lookup_hit = regData;
+    if(!pL2Table->lookup_hit)
+        return RT_ERR_FAILED;
+
+    /*Read access address*/
+    /*
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_TYPE_MASK | RTL8367C_TABLE_LUT_ADDR_ADDRESS_MASK,&regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    pL2Table->address = regData;*/
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_TABLE_ACCESS_STATUS_REG, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    pL2Table->address = (regData & 0x7ff) | ((regData & 0x4000) >> 3) | ((regData & 0x800) << 1);
+    pL2Table->lookup_busy = 0;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicL2LookupTb
+ * Description:
+ *      Get filtering database entry
+ * Input:
+ *      pL2Table    - L2 table entry writing to 2K+64 filtering database
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameter
+ *      RT_ERR_BUSYWAIT_TIMEOUT - LUT is busy at retrieving
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicL2LookupTb(rtk_uint32 method, rtl8367c_luttb *pL2Table)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+    rtk_uint16* accessPtr;
+    rtk_uint32 i;
+    rtk_uint16 smil2Table[RTL8367C_LUT_TABLE_SIZE];
+    rtk_uint32 busyCounter;
+    rtk_uint32 tblCmd;
+
+    if(pL2Table->wait_time == 0)
+        busyCounter = RTL8367C_LUT_BUSY_CHECK_NO;
+    else
+        busyCounter = pL2Table->wait_time;
+
+    while(busyCounter)
+    {
+        retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET,&regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        pL2Table->lookup_busy = regData;
+        if(!pL2Table->lookup_busy)
+            break;
+
+        busyCounter --;
+        if(busyCounter == 0)
+            return RT_ERR_BUSYWAIT_TIMEOUT;
+    }
+
+
+    tblCmd = (method << RTL8367C_ACCESS_METHOD_OFFSET) & RTL8367C_ACCESS_METHOD_MASK;
+
+    switch(method)
+    {
+        case LUTREADMETHOD_ADDRESS:
+        case LUTREADMETHOD_NEXT_ADDRESS:
+        case LUTREADMETHOD_NEXT_L2UC:
+        case LUTREADMETHOD_NEXT_L2MC:
+        case LUTREADMETHOD_NEXT_L3MC:
+        case LUTREADMETHOD_NEXT_L2L3MC:
+            retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_ADDR_REG, pL2Table->address);
+            if(retVal != RT_ERR_OK)
+                return retVal;
+            break;
+        case LUTREADMETHOD_MAC:
+            memset(smil2Table, 0x00, sizeof(rtk_uint16) * RTL8367C_LUT_TABLE_SIZE);
+            _rtl8367c_fdbStUser2Smi(pL2Table, smil2Table);
+
+            accessPtr = smil2Table;
+            regData = *accessPtr;
+            for(i=0; i<RTL8367C_LUT_ENTRY_SIZE; i++)
+            {
+                retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_WRDATA_BASE + i, regData);
+                if(retVal != RT_ERR_OK)
+                    return retVal;
+
+                accessPtr ++;
+                regData = *accessPtr;
+
+            }
+            break;
+        case LUTREADMETHOD_NEXT_L2UCSPA:
+            retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_ADDR_REG, pL2Table->address);
+            if(retVal != RT_ERR_OK)
+                return retVal;
+
+            tblCmd = tblCmd | ((pL2Table->spa << RTL8367C_TABLE_ACCESS_CTRL_SPA_OFFSET) & RTL8367C_TABLE_ACCESS_CTRL_SPA_MASK);
+
+            break;
+        default:
+            return RT_ERR_INPUT;
+    }
+
+    tblCmd = tblCmd | ((RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_READ,TB_TARGET_L2)) & (RTL8367C_TABLE_TYPE_MASK  | RTL8367C_COMMAND_TYPE_MASK));
+    /* Read Command */
+    retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_CTRL_REG, tblCmd);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    if(pL2Table->wait_time == 0)
+        busyCounter = RTL8367C_LUT_BUSY_CHECK_NO;
+    else
+        busyCounter = pL2Table->wait_time;
+
+    while(busyCounter)
+    {
+        retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET,&regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        pL2Table->lookup_busy = regData;
+        if(!pL2Table->lookup_busy)
+            break;
+
+        busyCounter --;
+        if(busyCounter == 0)
+            return RT_ERR_BUSYWAIT_TIMEOUT;
+    }
+
+    retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_HIT_STATUS_OFFSET,&regData);
+    if(retVal != RT_ERR_OK)
+            return retVal;
+    pL2Table->lookup_hit = regData;
+    if(!pL2Table->lookup_hit)
+        return RT_ERR_L2_ENTRY_NOTFOUND;
+
+    /*Read access address*/
+    //retVal = rtl8367c_getAsicRegBits(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_TYPE_MASK | RTL8367C_TABLE_LUT_ADDR_ADDRESS_MASK,&regData);
+    retVal = rtl8367c_getAsicReg(RTL8367C_TABLE_ACCESS_STATUS_REG, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    pL2Table->address = (regData & 0x7ff) | ((regData & 0x4000) >> 3) | ((regData & 0x800) << 1);
+
+    /*read L2 entry */
+    memset(smil2Table, 0x00, sizeof(rtk_uint16) * RTL8367C_LUT_TABLE_SIZE);
+
+    accessPtr = smil2Table;
+
+    for(i = 0; i < RTL8367C_LUT_ENTRY_SIZE; i++)
+    {
+        retVal = rtl8367c_getAsicReg(RTL8367C_TABLE_ACCESS_RDDATA_BASE + i, &regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        *accessPtr = regData;
+
+        accessPtr ++;
+    }
+
+    _rtl8367c_fdbStSmi2User(pL2Table, smil2Table);
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicLutLearnNo
+ * Description:
+ *      Get per-Port auto learning number
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pNumber     - ASIC auto learning entries number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ /*ÐÞ¸ÄRTL8367C_PORTIDMAX, RTL8367C_REG_L2_LRN_CNT_REG, port10 reg is not contnious, wait for updating of base.h*/
+ret_t rtl8367c_getAsicLutLearnNo(rtk_uint32 port, rtk_uint32* pNumber)
+{
+    ret_t retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(port < 10)
+    {
+     retVal = rtl8367c_getAsicReg(RTL8367C_REG_L2_LRN_CNT_REG(port), pNumber);
+        if (retVal != RT_ERR_OK)
+         return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_getAsicReg(RTL8367C_REG_L2_LRN_CNT_CTRL10, pNumber);
+        if (retVal != RT_ERR_OK)
+         return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicLutFlushAll
+ * Description:
+ *      Flush all entries in LUT. Includes static & dynamic entries
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicLutFlushAll(void)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_L2_FLUSH_CTRL3, RTL8367C_L2_FLUSH_CTRL3_OFFSET, 1);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicLutFlushAllStatus
+ * Description:
+ *      Get Flush all status, 1:Busy, 0 normal
+ * Input:
+ *      None
+ * Output:
+ *      pBusyStatus - Busy state
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_NULL_POINTER - Null pointer
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicLutFlushAllStatus(rtk_uint32 *pBusyStatus)
+{
+    if(NULL == pBusyStatus)
+        return RT_ERR_NULL_POINTER;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_L2_FLUSH_CTRL3, RTL8367C_L2_FLUSH_CTRL3_OFFSET, pBusyStatus);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicLutForceFlush
+ * Description:
+ *      Set per port force flush setting
+ * Input:
+ *      portmask    - portmask(0~0xFF)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK    - Invalid portmask
+ * Note:
+ *      None
+ */
+ /*port8~port10µÄÉèÖÃÔÚÁíÍâÒ»¸öregister, wait for updating of base.h, reg.h*/
+ret_t rtl8367c_setAsicLutForceFlush(rtk_uint32 portmask)
+{
+    ret_t retVal;
+
+    if(portmask > RTL8367C_PORTMASK)
+        return RT_ERR_PORT_MASK;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_FORCE_FLUSH_REG, RTL8367C_FORCE_FLUSH_PORTMASK_MASK, portmask & 0xff);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FORCE_FLUSH1, RTL8367C_PORTMASK1_MASK, (portmask >> 8) & 0x7);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicLutForceFlushStatus
+ * Description:
+ *      Get per port force flush status
+ * Input:
+ *      pPortmask   - portmask(0~0xFF)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ /*port8~port10µÄÉèÖÃÔÚÁíÍâÒ»¸öregister, wait for updating of base.h, reg.h*/
+ret_t rtl8367c_getAsicLutForceFlushStatus(rtk_uint32 *pPortmask)
+{
+    rtk_uint32 tmpMask;
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_FORCE_FLUSH_REG, RTL8367C_BUSY_STATUS_MASK,&tmpMask);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+    *pPortmask = tmpMask & 0xff;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FORCE_FLUSH1, RTL8367C_BUSY_STATUS1_MASK,&tmpMask);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+    *pPortmask |= (tmpMask & 7) << 8;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicLutFlushMode
+ * Description:
+ *      Set user force L2 pLutSt table flush mode
+ * Input:
+ *      mode    - 0:Port based 1: Port + VLAN based 2:Port + FID/MSTI based
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_NOT_ALLOWED  - Actions not allowed by the function
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicLutFlushMode(rtk_uint32 mode)
+{
+    if( mode >= FLUSHMDOE_END )
+        return RT_ERR_NOT_ALLOWED;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_L2_FLUSH_CTRL2, RTL8367C_LUT_FLUSH_MODE_MASK, mode);
+}
+/* Function Name:
+ *      rtl8367c_getAsicLutFlushMode
+ * Description:
+ *      Get user force L2 pLutSt table flush mode
+ * Input:
+ *      pMode   - 0:Port based 1: Port + VLAN based 2:Port + FID/MSTI based
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicLutFlushMode(rtk_uint32* pMode)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_L2_FLUSH_CTRL2, RTL8367C_LUT_FLUSH_MODE_MASK, pMode);
+}
+/* Function Name:
+ *      rtl8367c_setAsicLutFlushType
+ * Description:
+ *      Get L2 LUT flush type
+ * Input:
+ *      type    - 0: dynamice unicast; 1: both dynamic and static unicast entry
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicLutFlushType(rtk_uint32 type)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_L2_FLUSH_CTRL2, RTL8367C_LUT_FLUSH_TYPE_OFFSET,type);
+}
+/* Function Name:
+ *      rtl8367c_getAsicLutFlushType
+ * Description:
+ *      Set L2 LUT flush type
+ * Input:
+ *      pType   - 0: dynamice unicast; 1: both dynamic and static unicast entry
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicLutFlushType(rtk_uint32* pType)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_L2_FLUSH_CTRL2, RTL8367C_LUT_FLUSH_TYPE_OFFSET,pType);
+}
+
+
+/* Function Name:
+ *      rtl8367c_setAsicLutFlushVid
+ * Description:
+ *      Set VID of Port + VID pLutSt flush mode
+ * Input:
+ *      vid     - Vid (0~4095)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_VLAN_VID - Invalid VID parameter (0~4095)
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicLutFlushVid(rtk_uint32 vid)
+{
+    if( vid > RTL8367C_VIDMAX )
+        return RT_ERR_VLAN_VID;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_L2_FLUSH_CTRL1, RTL8367C_LUT_FLUSH_VID_MASK, vid);
+}
+/* Function Name:
+ *      rtl8367c_getAsicLutFlushVid
+ * Description:
+ *      Get VID of Port + VID pLutSt flush mode
+ * Input:
+ *      pVid    - Vid (0~4095)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicLutFlushVid(rtk_uint32* pVid)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_L2_FLUSH_CTRL1, RTL8367C_LUT_FLUSH_VID_MASK, pVid);
+}
+/* Function Name:
+ *      rtl8367c_setAsicPortFlusdFid
+ * Description:
+ *      Set FID of Port + FID pLutSt flush mode
+ * Input:
+ *      fid     - FID/MSTI for force flush
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_L2_FID   - Invalid FID (0~15)
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicLutFlushFid(rtk_uint32 fid)
+{
+    if( fid > RTL8367C_FIDMAX )
+        return RT_ERR_L2_FID;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_L2_FLUSH_CTRL1, RTL8367C_LUT_FLUSH_FID_MASK, fid);
+}
+/* Function Name:
+ *      rtl8367c_getAsicLutFlushFid
+ * Description:
+ *      Get FID of Port + FID pLutSt flush mode
+ * Input:
+ *      pFid    - FID/MSTI for force flush
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicLutFlushFid(rtk_uint32* pFid)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_L2_FLUSH_CTRL1, RTL8367C_LUT_FLUSH_FID_MASK, pFid);
+}
+/* Function Name:
+ *      rtl8367c_setAsicLutDisableAging
+ * Description:
+ *      Set L2 LUT aging per port setting
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      disabled    - 0: enable aging; 1: disabling aging
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ /*ÐÞ¸ÄRTL8367C_PORTIDMAX*/
+ret_t rtl8367c_setAsicLutDisableAging(rtk_uint32 port, rtk_uint32 disabled)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_LUT_AGEOUT_CTRL_REG, port, disabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicLutDisableAging
+ * Description:
+ *      Get L2 LUT aging per port setting
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pDisabled - 0: enable aging; 1: disabling aging
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ /*ÐÞ¸ÄRTL8367C_PORTIDMAX*/
+ret_t rtl8367c_getAsicLutDisableAging(rtk_uint32 port, rtk_uint32 *pDisabled)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_LUT_AGEOUT_CTRL_REG, port, pDisabled);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicLutIPMCGroup
+ * Description:
+ *      Set IPMC Group Table
+ * Input:
+ *      index       - the entry index in table (0 ~ 63)
+ *      group_addr  - the multicast group address (224.0.0.0 ~ 239.255.255.255)
+ *      vid         - VLAN ID
+ *      pmask       - portmask
+ *      valid       - valid bit
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_INPUT    - Invalid parameter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicLutIPMCGroup(rtk_uint32 index, ipaddr_t group_addr, rtk_uint32 vid, rtk_uint32 pmask, rtk_uint32 valid)
+{
+    rtk_uint32  regAddr, regData, bitoffset;
+    ipaddr_t    ipData;
+    ret_t       retVal;
+
+    if(index > RTL8367C_LUT_IPMCGRP_TABLE_MAX)
+        return RT_ERR_INPUT;
+
+    if (vid > RTL8367C_VIDMAX)
+        return RT_ERR_VLAN_VID;
+
+    ipData = group_addr;
+
+    if( (ipData & 0xF0000000) != 0xE0000000)    /* not in 224.0.0.0 ~ 239.255.255.255 */
+        return RT_ERR_INPUT;
+
+    /* Group Address */
+    regAddr = RTL8367C_REG_IPMC_GROUP_ENTRY0_H + (index * 2);
+    regData = ((ipData & 0x0FFFFFFF) >> 16);
+
+    if( (retVal = rtl8367c_setAsicReg(regAddr, regData)) != RT_ERR_OK)
+        return retVal;
+
+    regAddr++;
+    regData = (ipData & 0x0000FFFF);
+
+    if( (retVal = rtl8367c_setAsicReg(regAddr, regData)) != RT_ERR_OK)
+        return retVal;
+
+    /* VID */
+    regAddr = RTL8367C_REG_IPMC_GROUP_VID_00 + index;
+    regData = vid;
+
+    if( (retVal = rtl8367c_setAsicReg(regAddr, regData)) != RT_ERR_OK)
+        return retVal;
+
+    /* portmask */
+    regAddr = RTL8367C_REG_IPMC_GROUP_PMSK_00 + index;
+    regData = pmask;
+
+    if( (retVal = rtl8367c_setAsicReg(regAddr, regData)) != RT_ERR_OK)
+        return retVal;
+
+    /* valid */
+    regAddr = RTL8367C_REG_IPMC_GROUP_VALID_15_0 + (index / 16);
+    bitoffset = index % 16;
+    if( (retVal = rtl8367c_setAsicRegBit(regAddr, bitoffset, valid)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicLutIPMCGroup
+ * Description:
+ *      Set IPMC Group Table
+ * Input:
+ *      index       - the entry index in table (0 ~ 63)
+ * Output:
+ *      pGroup_addr - the multicast group address (224.0.0.0 ~ 239.255.255.255)
+ *      pVid        - VLAN ID
+ *      pPmask      - portmask
+ *      pValid      - Valid bit
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_INPUT    - Invalid parameter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicLutIPMCGroup(rtk_uint32 index, ipaddr_t *pGroup_addr, rtk_uint32 *pVid, rtk_uint32 *pPmask, rtk_uint32 *pValid)
+{
+    rtk_uint32      regAddr, regData, bitoffset;
+    ipaddr_t    ipData;
+    ret_t       retVal;
+
+    if(index > RTL8367C_LUT_IPMCGRP_TABLE_MAX)
+        return RT_ERR_INPUT;
+
+    if (NULL == pGroup_addr)
+        return RT_ERR_NULL_POINTER;
+
+    if (NULL == pVid)
+        return RT_ERR_NULL_POINTER;
+
+    if (NULL == pPmask)
+        return RT_ERR_NULL_POINTER;
+
+    /* Group address */
+    regAddr = RTL8367C_REG_IPMC_GROUP_ENTRY0_H + (index * 2);
+    if( (retVal = rtl8367c_getAsicReg(regAddr, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    *pGroup_addr = (((regData & 0x00000FFF) << 16) | 0xE0000000);
+
+    regAddr++;
+    if( (retVal = rtl8367c_getAsicReg(regAddr, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    ipData = (*pGroup_addr | (regData & 0x0000FFFF));
+    *pGroup_addr = ipData;
+
+    /* VID */
+    regAddr = RTL8367C_REG_IPMC_GROUP_VID_00 + index;
+    if( (retVal = rtl8367c_getAsicReg(regAddr, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    *pVid = regData;
+
+    /* portmask */
+    regAddr = RTL8367C_REG_IPMC_GROUP_PMSK_00 + index;
+    if( (retVal = rtl8367c_getAsicReg(regAddr, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    *pPmask = regData;
+
+    /* valid */
+    regAddr = RTL8367C_REG_IPMC_GROUP_VALID_15_0 + (index / 16);
+    bitoffset = index % 16;
+    if( (retVal = rtl8367c_getAsicRegBit(regAddr, bitoffset, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    *pValid = regData;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicLutLinkDownForceAging
+ * Description:
+ *       Set LUT link down aging setting.
+ * Input:
+ *      enable      - link down aging setting
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_ENABLE    - Invalid parameter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicLutLinkDownForceAging(rtk_uint32 enable)
+{
+    if(enable > 1)
+        return RT_ERR_ENABLE;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_LINKDOWN_AGEOUT_OFFSET, enable ? 0 : 1);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicLutLinkDownForceAging
+ * Description:
+ *       Get LUT link down aging setting.
+ * Input:
+ *      pEnable         - link down aging setting
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_ENABLE    - Invalid parameter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicLutLinkDownForceAging(rtk_uint32 *pEnable)
+{
+    rtk_uint32  value;
+    ret_t   retVal;
+
+    if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_LINKDOWN_AGEOUT_OFFSET, &value)) != RT_ERR_OK)
+        return retVal;
+
+    *pEnable = value ? 0 : 1;
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicLutIpmcFwdRouterPort
+ * Description:
+ *       Set IPMC packet forward to rounter port also or not
+ * Input:
+ *      enable      - 1: Inlcude router port, 0, exclude router port
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_ENABLE     Invalid parameter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicLutIpmcFwdRouterPort(rtk_uint32 enable)
+{
+    if(enable > 1)
+        return RT_ERR_ENABLE;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_LUT_CFG2, RTL8367C_LUT_IPMC_FWD_RPORT_OFFSET, enable);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicLutIpmcFwdRouterPort
+ * Description:
+ *       Get IPMC packet forward to rounter port also or not
+ * Input:
+ *      None
+ * Output:
+ *      pEnable         - 1: Inlcude router port, 0, exclude router port
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_NULL_POINTER     - Null pointer
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicLutIpmcFwdRouterPort(rtk_uint32 *pEnable)
+{
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_LUT_CFG2, RTL8367C_LUT_IPMC_FWD_RPORT_OFFSET, pEnable);
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_meter.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_meter.c
new file mode 100644
index 0000000..5412591
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_meter.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Shared meter related functions
+ *
+ */
+#include <rtl8367c_asicdrv_meter.h>
+/* Function Name:
+ *      rtl8367c_setAsicShareMeter
+ * Description:
+ *      Set meter configuration
+ * Input:
+ *      index   - hared meter index (0-31)
+ *      rate    - 17-bits rate of share meter, unit is 8Kpbs
+ *      ifg     - Including IFG in rate calculation, 1:include 0:exclude
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicShareMeter(rtk_uint32 index, rtk_uint32 rate, rtk_uint32 ifg)
+{
+    ret_t retVal;
+
+    if(index > RTL8367C_METERMAX)
+        return RT_ERR_FILTER_METER_ID;
+
+    if(index < 32)
+    {
+    /*19-bits Rate*/
+        retVal = rtl8367c_setAsicReg(RTL8367C_METER_RATE_REG(index), rate&0xFFFF);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        retVal = rtl8367c_setAsicReg(RTL8367C_METER_RATE_REG(index) + 1, (rate &0x70000) >> 16);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        retVal = rtl8367c_setAsicRegBit(RTL8367C_METER_IFG_CTRL_REG(index), RTL8367C_METER_IFG_OFFSET(index), ifg);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+    /*19-bits Rate*/
+        retVal = rtl8367c_setAsicReg(RTL8367C_REG_METER32_RATE_CTRL0 + ((index-32) << 1), rate&0xFFFF);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        retVal = rtl8367c_setAsicReg(RTL8367C_REG_METER32_RATE_CTRL0 + ((index-32) << 1) + 1, (rate &0x70000) >> 16);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_METER_IFG_CTRL2 + ((index-32) >> 4), RTL8367C_METER_IFG_OFFSET(index), ifg);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicShareMeter
+ * Description:
+ *      Get meter configuration
+ * Input:
+ *      index   - hared meter index (0-31)
+ *      pRate   - 17-bits rate of share meter, unit is 8Kpbs
+ *      pIfg    - Including IFG in rate calculation, 1:include 0:exclude
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicShareMeter(rtk_uint32 index, rtk_uint32 *pRate, rtk_uint32 *pIfg)
+{
+    rtk_uint32 regData;
+    rtk_uint32 regData2;
+    ret_t retVal;
+
+    if(index > RTL8367C_METERMAX)
+        return RT_ERR_FILTER_METER_ID;
+
+    if(index < 32)
+    {
+    /*17-bits Rate*/
+     retVal = rtl8367c_getAsicReg(RTL8367C_METER_RATE_REG(index), &regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+     retVal = rtl8367c_getAsicReg(RTL8367C_METER_RATE_REG(index) + 1, &regData2);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+    *pRate = ((regData2 << 16) & 0x70000) | regData;
+    /*IFG*/
+    retVal = rtl8367c_getAsicRegBit(RTL8367C_METER_IFG_CTRL_REG(index), RTL8367C_METER_IFG_OFFSET(index), pIfg);
+
+    return retVal;
+    }
+    else
+    {
+    /*17-bits Rate*/
+     retVal = rtl8367c_getAsicReg(RTL8367C_REG_METER32_RATE_CTRL0 + ((index-32) << 1), &regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+     retVal = rtl8367c_getAsicReg(RTL8367C_REG_METER32_RATE_CTRL0 + ((index-32) << 1) + 1, &regData2);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+    *pRate = ((regData2 << 16) & 0x70000) | regData;
+    /*IFG*/
+    retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_METER_IFG_CTRL2 + ((index-32) >> 4), RTL8367C_METER_IFG_OFFSET(index), pIfg);
+
+    return retVal;
+    }
+}
+/* Function Name:
+ *      rtl8367c_setAsicShareMeterBucketSize
+ * Description:
+ *      Set meter related leaky bucket threshold
+ * Input:
+ *      index       - hared meter index (0-31)
+ *      lbthreshold - Leaky bucket threshold of meter
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicShareMeterBucketSize(rtk_uint32 index, rtk_uint32 lbthreshold)
+{
+
+    if(index > RTL8367C_METERMAX)
+        return RT_ERR_FILTER_METER_ID;
+
+    if(index < 32)
+    return rtl8367c_setAsicReg(RTL8367C_METER_BUCKET_SIZE_REG(index), lbthreshold);
+    else
+       return rtl8367c_setAsicReg(RTL8367C_REG_METER32_BUCKET_SIZE + index - 32, lbthreshold);
+}
+/* Function Name:
+ *      rtl8367c_getAsicShareMeterBucketSize
+ * Description:
+ *      Get meter related leaky bucket threshold
+ * Input:
+ *      index       - hared meter index (0-31)
+ *      pLbthreshold - Leaky bucket threshold of meter
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicShareMeterBucketSize(rtk_uint32 index, rtk_uint32 *pLbthreshold)
+{
+    if(index > RTL8367C_METERMAX)
+        return RT_ERR_FILTER_METER_ID;
+
+    if(index < 32)
+    return rtl8367c_getAsicReg(RTL8367C_METER_BUCKET_SIZE_REG(index), pLbthreshold);
+    else
+       return rtl8367c_getAsicReg(RTL8367C_REG_METER32_BUCKET_SIZE + index - 32, pLbthreshold);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicShareMeterType
+ * Description:
+ *      Set meter Type
+ * Input:
+ *      index       - shared meter index (0-31)
+ *      Type        - 0: kbps, 1: pps
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicShareMeterType(rtk_uint32 index, rtk_uint32 type)
+{
+    rtk_uint32 reg;
+
+    if(index > RTL8367C_METERMAX)
+        return RT_ERR_FILTER_METER_ID;
+
+    if(index < 32)
+        reg = RTL8367C_REG_METER_MODE_SETTING0 + (index / 16);
+    else
+        reg = RTL8367C_REG_METER_MODE_SETTING2 + ((index - 32) / 16);
+    return rtl8367c_setAsicRegBit(reg, index % 16, type);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicShareMeterType
+ * Description:
+ *      Get meter Type
+ * Input:
+ *      index       - shared meter index (0-31)
+ * Output:
+ *      pType       - 0: kbps, 1: pps
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicShareMeterType(rtk_uint32 index, rtk_uint32 *pType)
+{
+    rtk_uint32 reg;
+
+    if(index > RTL8367C_METERMAX)
+        return RT_ERR_FILTER_METER_ID;
+
+    if(NULL == pType)
+        return RT_ERR_NULL_POINTER;
+
+    if(index < 32)
+        reg = RTL8367C_REG_METER_MODE_SETTING0 + (index / 16);
+    else
+        reg = RTL8367C_REG_METER_MODE_SETTING2 + ((index - 32) / 16);
+    return rtl8367c_getAsicRegBit(reg, index % 16, pType);
+}
+
+
+/* Function Name:
+ *      rtl8367c_setAsicMeterExceedStatus
+ * Description:
+ *      Clear shared meter status
+ * Input:
+ *      index       - hared meter index (0-31)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicMeterExceedStatus(rtk_uint32 index)
+{
+    if(index > RTL8367C_METERMAX)
+        return RT_ERR_FILTER_METER_ID;
+
+    if(index < 32)
+        return rtl8367c_setAsicRegBit(RTL8367C_METER_OVERRATE_INDICATOR_REG(index), RTL8367C_METER_EXCEED_OFFSET(index), 1);
+    else
+        return rtl8367c_setAsicRegBit(RTL8367C_REG_METER_OVERRATE_INDICATOR2 + ((index - 32) >> 4), RTL8367C_METER_EXCEED_OFFSET(index), 1);
+
+}
+/* Function Name:
+ *      rtl8367c_getAsicMeterExceedStatus
+ * Description:
+ *      Get shared meter status
+ * Input:
+ *      index   - hared meter index (0-31)
+ *      pStatus     - 0: rate doesn't exceed    1: rate exceeds
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter
+ * Note:
+ *      If rate is over rate*8Kbps of a meter, the state bit of this meter is set to 1.
+ */
+ret_t rtl8367c_getAsicMeterExceedStatus(rtk_uint32 index, rtk_uint32* pStatus)
+{
+    if(index > RTL8367C_METERMAX)
+        return RT_ERR_FILTER_METER_ID;
+
+    if(index < 32)
+        return rtl8367c_getAsicRegBit(RTL8367C_METER_OVERRATE_INDICATOR_REG(index), RTL8367C_METER_EXCEED_OFFSET(index), pStatus);
+    else
+        return rtl8367c_getAsicRegBit(RTL8367C_REG_METER_OVERRATE_INDICATOR2 + ((index - 32) >> 4), RTL8367C_METER_EXCEED_OFFSET(index), pStatus);
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_mib.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_mib.c
new file mode 100644
index 0000000..c9aaa01
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_mib.c
@@ -0,0 +1,570 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : MIB related functions
+ *
+ */
+
+#include <rtl8367c_asicdrv_mib.h>
+/* Function Name:
+ *      rtl8367c_setAsicMIBsCounterReset
+ * Description:
+ *      Reset global/queue manage or per-port MIB counter
+ * Input:
+ *      greset  - Global reset
+ *      qmreset - Queue maganement reset
+ *      portmask    - Port reset mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicMIBsCounterReset(rtk_uint32 greset, rtk_uint32 qmreset, rtk_uint32 portmask)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+    rtk_uint32 regBits;
+
+    regBits = RTL8367C_GLOBAL_RESET_MASK |
+                RTL8367C_QM_RESET_MASK |
+                    RTL8367C_MIB_PORT07_MASK |
+                    ((rtk_uint32)0x7 << 13);
+    regData = ((greset << RTL8367C_GLOBAL_RESET_OFFSET) & RTL8367C_GLOBAL_RESET_MASK) |
+                ((qmreset << RTL8367C_QM_RESET_OFFSET) & RTL8367C_QM_RESET_MASK) |
+                (((portmask & 0xFF) << RTL8367C_PORT0_RESET_OFFSET) & RTL8367C_MIB_PORT07_MASK) |
+                (((portmask >> 8)&0x7) << 13);
+
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_MIB_CTRL0, regBits, (regData >> RTL8367C_PORT0_RESET_OFFSET));
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicMIBsCounter
+ * Description:
+ *      Get MIBs counter
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      mibIdx      - MIB counter index
+ *      pCounter    - MIB retrived counter
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number
+ *      RT_ERR_BUSYWAIT_TIMEOUT - MIB is busy at retrieving
+ *      RT_ERR_STAT_CNTR_FAIL   - MIB is resetting
+ * Note:
+ *      Before MIBs counter retrieving, writting accessing address to ASIC at first and check the MIB
+ *      control register status. If busy bit of MIB control is set, that means MIB counter have been
+ *      waiting for preparing, then software must wait atfer this busy flag reset by ASIC. This driver
+ *      did not recycle reading user desired counter. Software must use driver again to get MIB counter
+ *      if return value is not RT_ERR_OK.
+ */
+ret_t rtl8367c_getAsicMIBsCounter(rtk_uint32 port, RTL8367C_MIBCOUNTER mibIdx, rtk_uint64* pCounter)
+{
+    ret_t retVal;
+    rtk_uint32 regAddr;
+    rtk_uint32 regData;
+    rtk_uint32 mibAddr;
+    rtk_uint32 mibOff=0;
+
+    /* address offset to MIBs counter */
+    CONST rtk_uint16 mibLength[RTL8367C_MIBS_NUMBER]= {
+        4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+        4,2,2,2,2,2,2,2,2,
+        4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+        2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
+
+    rtk_uint16 i;
+    rtk_uint64 mibCounter;
+
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(mibIdx >= RTL8367C_MIBS_NUMBER)
+        return RT_ERR_STAT_INVALID_CNTR;
+
+    if(dot1dTpLearnedEntryDiscards == mibIdx)
+    {
+        mibAddr = RTL8367C_MIB_LEARNENTRYDISCARD_OFFSET;
+    }
+    else
+    {
+        i = 0;
+        mibOff = RTL8367C_MIB_PORT_OFFSET * port;
+
+        if(port > 7)
+            mibOff = mibOff + 68;
+
+        while(i < mibIdx)
+        {
+            mibOff += mibLength[i];
+            i++;
+        }
+
+        mibAddr = mibOff;
+    }
+
+
+    /*writing access counter address first*/
+    /*This address is SRAM address, and SRAM address = MIB register address >> 2*/
+    /*then ASIC will prepare 64bits counter wait for being retrived*/
+    /*Write Mib related address to access control register*/
+    retVal = rtl8367c_setAsicReg(RTL8367C_REG_MIB_ADDRESS, (mibAddr >> 2));
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+
+
+    /* polling busy flag */
+    i = 100;
+    while(i > 0)
+    {
+        /*read MIB control register*/
+        retVal = rtl8367c_getAsicReg(RTL8367C_MIB_CTRL_REG,&regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        if((regData & RTL8367C_MIB_CTRL0_BUSY_FLAG_MASK) == 0)
+        {
+            break;
+        }
+
+        i--;
+    }
+
+    if(regData & RTL8367C_MIB_CTRL0_BUSY_FLAG_MASK)
+        return RT_ERR_BUSYWAIT_TIMEOUT;
+
+    if(regData & RTL8367C_RESET_FLAG_MASK)
+        return RT_ERR_STAT_CNTR_FAIL;
+
+    mibCounter = 0;
+    i = mibLength[mibIdx];
+    if(4 == i)
+        regAddr = RTL8367C_MIB_COUNTER_BASE_REG + 3;
+    else
+        regAddr = RTL8367C_MIB_COUNTER_BASE_REG + ((mibOff + 1) % 4);
+
+    while(i)
+    {
+        retVal = rtl8367c_getAsicReg(regAddr, &regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        mibCounter = (mibCounter << 16) | (regData & 0xFFFF);
+
+        regAddr --;
+        i --;
+
+    }
+
+    *pCounter = mibCounter;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicMIBsLogCounter
+ * Description:
+ *      Get MIBs Loggin counter
+ * Input:
+ *      index       - The index of 32 logging counter (0 ~ 31)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_ENTRY_INDEX      - Wrong index
+ *      RT_ERR_BUSYWAIT_TIMEOUT - MIB is busy at retrieving
+ *      RT_ERR_STAT_CNTR_FAIL   - MIB is resetting
+ * Note:
+ *      This API get 32 logging counter
+ */
+ret_t rtl8367c_getAsicMIBsLogCounter(rtk_uint32 index, rtk_uint32 *pCounter)
+{
+    ret_t retVal;
+    rtk_uint32 regAddr;
+    rtk_uint32 regData;
+    rtk_uint32 mibAddr;
+    rtk_uint16 i;
+    rtk_uint64 mibCounter;
+
+    if(index > RTL8367C_MIB_MAX_LOG_CNT_IDX)
+        return RT_ERR_ENTRY_INDEX;
+
+    mibAddr = RTL8367C_MIB_LOG_CNT_OFFSET + ((index / 2) * 4);
+
+    retVal = rtl8367c_setAsicReg(RTL8367C_REG_MIB_ADDRESS, (mibAddr >> 2));
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /*read MIB control register*/
+    retVal = rtl8367c_getAsicReg(RTL8367C_MIB_CTRL_REG, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    if(regData & RTL8367C_MIB_CTRL0_BUSY_FLAG_MASK)
+        return RT_ERR_BUSYWAIT_TIMEOUT;
+
+    if(regData & RTL8367C_RESET_FLAG_MASK)
+        return RT_ERR_STAT_CNTR_FAIL;
+
+    mibCounter = 0;
+    if((index % 2) == 1)
+        regAddr = RTL8367C_MIB_COUNTER_BASE_REG + 3;
+    else
+        regAddr = RTL8367C_MIB_COUNTER_BASE_REG + 1;
+
+    for(i = 0; i <= 1; i++)
+    {
+        retVal = rtl8367c_getAsicReg(regAddr, &regData);
+
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        mibCounter = (mibCounter << 16) | (regData & 0xFFFF);
+
+        regAddr --;
+    }
+
+    *pCounter = mibCounter;
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicMIBsControl
+ * Description:
+ *      Get MIB control register
+ * Input:
+ *      pMask       - MIB control status mask bit[0]-busy bit[1]
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ * Note:
+ *      Software need to check this control register atfer doing port resetting or global resetting
+ */
+ret_t rtl8367c_getAsicMIBsControl(rtk_uint32* pMask)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_MIB_CTRL_REG, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *pMask = regData & (RTL8367C_MIB_CTRL0_BUSY_FLAG_MASK | RTL8367C_RESET_FLAG_MASK);
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicMIBsResetValue
+ * Description:
+ *      Reset all counter to 0 or 1
+ * Input:
+ *      value           - Reset to value 0 or 1
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicMIBsResetValue(rtk_uint32 value)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_MIB_CTRL0, RTL8367C_RESET_VALUE_OFFSET, value);
+}
+/* Function Name:
+ *      rtl8367c_getAsicMIBsResetValue
+ * Description:
+ *      Reset all counter to 0 or 1
+ * Input:
+ *      value           - Reset to value 0 or 1
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicMIBsResetValue(rtk_uint32* value)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_MIB_CTRL0, RTL8367C_RESET_VALUE_OFFSET, value);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicMIBsUsageMode
+ * Description:
+ *      MIB update mode
+ * Input:
+ *      mode            - 1: latch all MIBs by timer 0:normal free run counting
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicMIBsUsageMode(rtk_uint32 mode)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_MIB_CTRL4, RTL8367C_MIB_USAGE_MODE_OFFSET, mode);
+}
+/* Function Name:
+ *      rtl8367c_getAsicMIBsUsageMode
+ * Description:
+ *      MIB update mode
+ * Input:
+ *      pMode           - 1: latch all MIBs by timer 0:normal free run counting
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicMIBsUsageMode(rtk_uint32* pMode)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_MIB_CTRL4, RTL8367C_MIB_USAGE_MODE_OFFSET, pMode);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicMIBsTimer
+ * Description:
+ *      MIB latching timer
+ * Input:
+ *      timer           - latch timer, unit 1 second
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicMIBsTimer(rtk_uint32 timer)
+{
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_MIB_CTRL4, RTL8367C_MIB_TIMER_MASK, timer);
+}
+/* Function Name:
+ *      rtl8367c_getAsicMIBsTimer
+ * Description:
+ *      MIB latching timer
+ * Input:
+ *      pTimer          - latch timer, unit 1 second
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicMIBsTimer(rtk_uint32* pTimer)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_MIB_CTRL4, RTL8367C_MIB_TIMER_MASK, pTimer);
+}
+/* Function Name:
+ *      rtl8367c_setAsicMIBsLoggingMode
+ * Description:
+ *      MIB logging counter mode
+ * Input:
+ *      index   - logging counter mode index (0~15)
+ *      mode    - 0:32-bits mode 1:64-bits mode
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicMIBsLoggingMode(rtk_uint32 index, rtk_uint32 mode)
+{
+    if(index > RTL8367C_MIB_MAX_LOG_MODE_IDX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_MIB_CTRL3, index,mode);
+}
+/* Function Name:
+ *      rtl8367c_getAsicMIBsLoggingMode
+ * Description:
+ *      MIB logging counter mode
+ * Input:
+ *      index   - logging counter mode index (0~15)
+ *      pMode   - 0:32-bits mode 1:64-bits mode
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicMIBsLoggingMode(rtk_uint32 index, rtk_uint32* pMode)
+{
+    if(index > RTL8367C_MIB_MAX_LOG_MODE_IDX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_MIB_CTRL3, index,pMode);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicMIBsLoggingType
+ * Description:
+ *      MIB logging counter type
+ * Input:
+ *      index   - logging counter mode index (0~15)
+ *      type    - 0:Packet count 1:Byte count
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicMIBsLoggingType(rtk_uint32 index, rtk_uint32 type)
+{
+    if(index > RTL8367C_MIB_MAX_LOG_MODE_IDX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_MIB_CTRL5, index,type);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicMIBsLoggingType
+ * Description:
+ *      MIB logging counter type
+ * Input:
+ *      index   - logging counter mode index (0~15)
+ *      pType   - 0:Packet count 1:Byte count
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicMIBsLoggingType(rtk_uint32 index, rtk_uint32* pType)
+{
+    if(index > RTL8367C_MIB_MAX_LOG_MODE_IDX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_MIB_CTRL5, index,pType);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicMIBsResetLoggingCounter
+ * Description:
+ *      MIB logging counter type
+ * Input:
+ *      index   - logging counter index (0~31)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicMIBsResetLoggingCounter(rtk_uint32 index)
+{
+    ret_t retVal;
+
+    if(index > RTL8367C_MIB_MAX_LOG_CNT_IDX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(index < 16)
+        retVal = rtl8367c_setAsicReg(RTL8367C_REG_MIB_CTRL1, 1<<index);
+    else
+        retVal = rtl8367c_setAsicReg(RTL8367C_REG_MIB_CTRL2, 1<<(index-16));
+
+    return retVal;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicMIBsLength
+ * Description:
+ *      Set MIB length couting mode
+ * Input:
+ *      txLengthMode    - 0: tag length doesn't be counted. 1: tag length is counted.
+ *      rxLengthMode    - 0: tag length doesn't be counted. 1: tag length is counted.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicMIBsLength(rtk_uint32 txLengthMode, rtk_uint32 rxLengthMode)
+{
+    ret_t retVal;
+
+    if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MIB_RMON_LEN_CTRL, RTL8367C_TX_LENGTH_CTRL_OFFSET, txLengthMode)) != RT_ERR_OK)
+        return retVal;
+
+    if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MIB_RMON_LEN_CTRL, RTL8367C_RX_LENGTH_CTRL_OFFSET, rxLengthMode)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicMIBsLength
+ * Description:
+ *      Set MIB length couting mode
+ * Input:
+ *      None.
+ * Output:
+ *      pTxLengthMode - 0: tag length doesn't be counted. 1: tag length is counted.
+ *      pRxLengthMode - 0: tag length doesn't be counted. 1: tag length is counted.
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_OUT_OF_RANGE     - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicMIBsLength(rtk_uint32 *pTxLengthMode, rtk_uint32 *pRxLengthMode)
+{
+    ret_t retVal;
+
+    if( (retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_MIB_RMON_LEN_CTRL, RTL8367C_TX_LENGTH_CTRL_OFFSET, pTxLengthMode)) != RT_ERR_OK)
+        return retVal;
+
+    if( (retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_MIB_RMON_LEN_CTRL, RTL8367C_RX_LENGTH_CTRL_OFFSET, pRxLengthMode)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_mirror.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_mirror.c
new file mode 100644
index 0000000..de945ff
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_mirror.c
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Port mirror related functions
+ *
+ */
+#include <rtl8367c_asicdrv_mirror.h>
+/* Function Name:
+ *      rtl8367c_setAsicPortMirror
+ * Description:
+ *      Set port mirror function
+ * Input:
+ *      source  - Source port
+ *      monitor - Monitor (destination) port
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortMirror(rtk_uint32 source, rtk_uint32 monitor)
+{
+    ret_t retVal;
+
+    if((source > RTL8367C_PORTIDMAX) || (monitor > RTL8367C_PORTIDMAX))
+        return RT_ERR_PORT_ID;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_SOURCE_PORT_MASK, source);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+
+    return rtl8367c_setAsicRegBits(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_MONITOR_PORT_MASK, monitor);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortMirror
+ * Description:
+ *      Get port mirror function
+ * Input:
+ *      pSource     - Source port
+ *      pMonitor - Monitor (destination) port
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortMirror(rtk_uint32 *pSource, rtk_uint32 *pMonitor)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_SOURCE_PORT_MASK, pSource);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_MONITOR_PORT_MASK, pMonitor);
+}
+/* Function Name:
+ *      rtl8367c_setAsicPortMirrorRxFunction
+ * Description:
+ *      Set the mirror function on RX of the mirrored
+ * Input:
+ *      enabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortMirrorRxFunction(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_RX_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortMirrorRxFunction
+ * Description:
+ *      Get the mirror function on RX of the mirrored
+ * Input:
+ *      pEnabled    - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortMirrorRxFunction(rtk_uint32* pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_RX_OFFSET, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicPortMirrorTxFunction
+ * Description:
+ *      Set the mirror function on TX of the mirrored
+ * Input:
+ *      enabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortMirrorTxFunction(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_TX_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortMirrorTxFunction
+ * Description:
+ *      Get the mirror function on TX of the mirrored
+ * Input:
+ *      pEnabled    - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortMirrorTxFunction(rtk_uint32* pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_TX_OFFSET, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicPortMirrorIsolation
+ * Description:
+ *      Set the traffic isolation on monitor port
+ * Input:
+ *      enabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortMirrorIsolation(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_ISO_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortMirrorIsolation
+ * Description:
+ *      Get the traffic isolation on monitor port
+ * Input:
+ *      pEnabled    - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortMirrorIsolation(rtk_uint32* pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_ISO_OFFSET, pEnabled);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicPortMirrorMask
+ * Description:
+ *      Set mirror source port mask
+ * Input:
+ *      SourcePortmask  - Source Portmask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_MASK- Port Mask Error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortMirrorMask(rtk_uint32 SourcePortmask)
+{
+    if( SourcePortmask > RTL8367C_PORTMASK)
+        return RT_ERR_PORT_MASK;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_MIRROR_SRC_PMSK, RTL8367C_MIRROR_SRC_PMSK_MASK, SourcePortmask);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicPortMirrorMask
+ * Description:
+ *      Get mirror source port mask
+ * Input:
+ *      None
+ * Output:
+ *      pSourcePortmask     - Source Portmask
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_MASK- Port Mask Error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortMirrorMask(rtk_uint32 *pSourcePortmask)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_MIRROR_SRC_PMSK, RTL8367C_MIRROR_SRC_PMSK_MASK, pSourcePortmask);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicPortMirrorVlanRxLeaky
+ * Description:
+ *      Set the mirror function of VLAN RX leaky
+ * Input:
+ *      enabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortMirrorVlanRxLeaky(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_RX_VLAN_LEAKY_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortMirrorVlanRxLeaky
+ * Description:
+ *      Get the mirror function of VLAN RX leaky
+ * Input:
+ *      pEnabled    - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortMirrorVlanRxLeaky(rtk_uint32* pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_RX_VLAN_LEAKY_OFFSET, pEnabled);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicPortMirrorVlanTxLeaky
+ * Description:
+ *      Set the mirror function of VLAN TX leaky
+ * Input:
+ *      enabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortMirrorVlanTxLeaky(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_TX_VLAN_LEAKY_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortMirrorVlanTxLeaky
+ * Description:
+ *      Get the mirror function of VLAN TX leaky
+ * Input:
+ *      pEnabled    - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortMirrorVlanTxLeaky(rtk_uint32* pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_TX_VLAN_LEAKY_OFFSET, pEnabled);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicPortMirrorIsolationRxLeaky
+ * Description:
+ *      Set the mirror function of  Isolation RX leaky
+ * Input:
+ *      enabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortMirrorIsolationRxLeaky(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_RX_ISOLATION_LEAKY_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortMirrorIsolationRxLeaky
+ * Description:
+ *      Get the mirror function of VLAN RX leaky
+ * Input:
+ *      pEnabled    - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortMirrorIsolationRxLeaky(rtk_uint32* pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_RX_ISOLATION_LEAKY_OFFSET, pEnabled);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicPortMirrorIsolationTxLeaky
+ * Description:
+ *      Set the mirror function of Isolation TX leaky
+ * Input:
+ *      enabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortMirrorIsolationTxLeaky(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_TX_ISOLATION_LEAKY_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortMirrorIsolationTxLeaky
+ * Description:
+ *      Get the mirror function of VLAN TX leaky
+ * Input:
+ *      pEnabled    - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortMirrorIsolationTxLeaky(rtk_uint32* pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_TX_ISOLATION_LEAKY_OFFSET, pEnabled);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicPortMirrorRealKeep
+ * Description:
+ *      Set the mirror function of keep format
+ * Input:
+ *      mode    - 1: keep original format, 0: follow VLAN config
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortMirrorRealKeep(rtk_uint32 mode)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_REALKEEP_EN_OFFSET, mode);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortMirrorRealKeep
+ * Description:
+ *      Get the mirror function of keep format
+ * Input:
+ *      pMode   - 1: keep original format, 0: follow VLAN config
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortMirrorRealKeep(rtk_uint32* pMode)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_REALKEEP_EN_OFFSET, pMode);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicPortMirrorOverride
+ * Description:
+ *      Set the mirror function of override
+ * Input:
+ *      rxMirror    - 1: output rx Mirror format, 0: output forward format
+ *      txMirror    - 1: output tx Mirror format, 0: output forward format
+ *      aclMirror   - 1: output ACL Mirror format, 0: output forward format
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortMirrorOverride(rtk_uint32 rxMirror, rtk_uint32 txMirror, rtk_uint32 aclMirror)
+{
+    ret_t retVal;
+
+    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL3, RTL8367C_MIRROR_RX_OVERRIDE_EN_OFFSET, rxMirror)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL3, RTL8367C_MIRROR_TX_OVERRIDE_EN_OFFSET, txMirror)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL3, RTL8367C_MIRROR_ACL_OVERRIDE_EN_OFFSET, aclMirror)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicPortMirrorOverride
+ * Description:
+ *      Get the mirror function of override
+ * Input:
+ *      None
+ * Output:
+ *      pRxMirror   - 1: output rx Mirror format, 0: output forward format
+ *      pTxMirror   - 1: output tx Mirror format, 0: output forward format
+ *      pAclMirror  - 1: output ACL Mirror format, 0: output forward format
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortMirrorOverride(rtk_uint32 *pRxMirror, rtk_uint32 *pTxMirror, rtk_uint32 *pAclMirror)
+{
+    ret_t retVal;
+
+    if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL3, RTL8367C_MIRROR_RX_OVERRIDE_EN_OFFSET, pRxMirror)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL3, RTL8367C_MIRROR_TX_OVERRIDE_EN_OFFSET, pTxMirror)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL3, RTL8367C_MIRROR_ACL_OVERRIDE_EN_OFFSET, pAclMirror)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_misc.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_misc.c
new file mode 100644
index 0000000..2189b15
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_misc.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Miscellaneous functions
+ *
+ */
+
+#include <rtl8367c_asicdrv_misc.h>
+/* Function Name:
+ *      rtl8367c_setAsicMacAddress
+ * Description:
+ *      Set switch MAC address
+ * Input:
+ *      mac     - switch mac
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicMacAddress(ether_addr_t mac)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+    rtk_uint8 *accessPtr;
+    rtk_uint32 i;
+
+    accessPtr =  (rtk_uint8*)&mac;
+
+    regData = *accessPtr;
+    accessPtr ++;
+    regData = (regData << 8) | *accessPtr;
+    accessPtr ++;
+    for(i = 0; i <=2; i++)
+    {
+        retVal = rtl8367c_setAsicReg(RTL8367C_REG_SWITCH_MAC2 - i, regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        regData = *accessPtr;
+        accessPtr ++;
+        regData = (regData << 8) | *accessPtr;
+        accessPtr ++;
+    }
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicMacAddress
+ * Description:
+ *      Get switch MAC address
+ * Input:
+ *      pMac    - switch mac
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicMacAddress(ether_addr_t *pMac)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+    rtk_uint8 *accessPtr;
+    rtk_uint32 i;
+
+
+    accessPtr = (rtk_uint8*)pMac;
+
+    for(i = 0; i <= 2; i++)
+    {
+        retVal = rtl8367c_getAsicReg(RTL8367C_REG_SWITCH_MAC2 - i, &regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        *accessPtr = (regData & 0xFF00) >> 8;
+        accessPtr ++;
+        *accessPtr = regData & 0xFF;
+        accessPtr ++;
+    }
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicDebugInfo
+ * Description:
+ *      Get per-port packet forward debugging information
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      pDebugifo   - per-port packet trap/drop/forward reason
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicDebugInfo(rtk_uint32 port, rtk_uint32 *pDebugifo)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_DEBUG_INFO_REG(port), RTL8367C_DEBUG_INFO_MASK(port), pDebugifo);
+}
+/* Function Name:
+ *      rtl8367c_setAsicPortJamMode
+ * Description:
+ *      Set half duplex flow control setting
+ * Input:
+ *      mode    - 0: Back-Pressure 1: DEFER
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortJamMode(rtk_uint32 mode)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_CFG_BACKPRESSURE, RTL8367C_LONGTXE_OFFSET,mode);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortJamMode
+ * Description:
+ *      Get half duplex flow control setting
+ * Input:
+ *      pMode   - 0: Back-Pressure 1: DEFER
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortJamMode(rtk_uint32* pMode)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_CFG_BACKPRESSURE, RTL8367C_LONGTXE_OFFSET, pMode);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicMaxLengthCfg
+ * Description:
+ *      Set Max packet length configuration
+ * Input:
+ *      cfgId       - Configuration ID
+ *      maxLength   - Max Length
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicMaxLengthCfg(rtk_uint32 cfgId, rtk_uint32 maxLength)
+{
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_MAX_LEN_RX_TX_CFG0 + cfgId, RTL8367C_MAX_LEN_RX_TX_CFG0_MASK, maxLength);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicMaxLengthCfg
+ * Description:
+ *      Get Max packet length configuration
+ * Input:
+ *      cfgId       - Configuration ID
+ *      maxLength   - Max Length
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicMaxLengthCfg(rtk_uint32 cfgId, rtk_uint32 *pMaxLength)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_MAX_LEN_RX_TX_CFG0 + cfgId, RTL8367C_MAX_LEN_RX_TX_CFG0_MASK, pMaxLength);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicMaxLength
+ * Description:
+ *      Set Max packet length
+ * Input:
+ *      port        - port ID
+ *      type        - 0: 10M/100M speed, 1: giga speed
+ *      cfgId       - Configuration ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicMaxLength(rtk_uint32 port, rtk_uint32 type, rtk_uint32 cfgId)
+{
+    ret_t retVal;
+
+    if(port < 8)
+    {
+        retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MAX_LENGTH_CFG, (type * 8) + port, cfgId);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MAX_LENGTH_CFG_EXT, (type * 3) + port - 8, cfgId);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicMaxLength
+ * Description:
+ *      Get Max packet length
+ * Input:
+ *      port        - port ID
+ *      type        - 0: 10M/100M speed, 1: giga speed
+ *      cfgId       - Configuration ID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicMaxLength(rtk_uint32 port, rtk_uint32 type, rtk_uint32 *pCfgId)
+{
+    ret_t retVal;
+
+    if(port < 8)
+    {
+        retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_MAX_LENGTH_CFG, (type * 8) + port, pCfgId);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_MAX_LENGTH_CFG_EXT, (type * 3) + port - 8, pCfgId);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    return RT_ERR_OK;
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_oam.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_oam.c
new file mode 100644
index 0000000..1556f45
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_oam.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 42321 $
+ * $Date: 2013-08-26 13:51:29 +0800 (週一, 26 八月 2013) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : OAM related functions
+ *
+ */
+
+#include <rtl8367c_asicdrv_oam.h>
+/* Function Name:
+ *      rtl8367c_setAsicOamParser
+ * Description:
+ *      Set OAM parser state
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      parser  - Per-Port OAM parser state
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_NOT_ALLOWED  - Invalid paser state
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicOamParser(rtk_uint32 port, rtk_uint32 parser)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if(parser > OAM_PARFWDCPU)
+        return RT_ERR_NOT_ALLOWED;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_OAM_PARSER_CTRL0 + port/8, RTL8367C_OAM_PARSER_MASK(port % 8), parser);
+}
+/* Function Name:
+ *      rtl8367c_getAsicOamParser
+ * Description:
+ *      Get OAM parser state
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pParser     - Per-Port OAM parser state
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicOamParser(rtk_uint32 port, rtk_uint32* pParser)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_OAM_PARSER_CTRL0 + port/8, RTL8367C_OAM_PARSER_MASK(port%8), pParser);
+}
+/* Function Name:
+ *      rtl8367c_setAsicOamMultiplexer
+ * Description:
+ *      Set OAM multiplexer state
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      multiplexer - Per-Port OAM multiplexer state
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_NOT_ALLOWED  - Invalid multiplexer state
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicOamMultiplexer(rtk_uint32 port, rtk_uint32 multiplexer)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if(multiplexer > OAM_MULCPU)
+        return RT_ERR_NOT_ALLOWED;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_OAM_MULTIPLEXER_CTRL0 + port/8, RTL8367C_OAM_MULTIPLEXER_MASK(port%8), multiplexer);
+}
+/* Function Name:
+ *      rtl8367c_getAsicOamMultiplexer
+ * Description:
+ *      Get OAM multiplexer state
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      pMultiplexer - Per-Port OAM multiplexer state
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicOamMultiplexer(rtk_uint32 port, rtk_uint32* pMultiplexer)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_OAM_MULTIPLEXER_CTRL0 + port/8, RTL8367C_OAM_MULTIPLEXER_MASK(port%8), pMultiplexer);
+}
+/* Function Name:
+ *      rtl8367c_setAsicOamCpuPri
+ * Description:
+ *      Set trap priority for OAM packet
+ * Input:
+ *      priority    - priority (0~7)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY     - Invalid priority
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicOamCpuPri(rtk_uint32 priority)
+{
+    if(priority > RTL8367C_PRIMAX)
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_QOS_TRAP_PRIORITY0, RTL8367C_OAM_PRIOIRTY_MASK, priority);
+}
+/* Function Name:
+ *      rtl8367c_getAsicOamCpuPri
+ * Description:
+ *      Get trap priority for OAM packet
+ * Input:
+ *      pPriority   - priority (0~7)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicOamCpuPri(rtk_uint32 *pPriority)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_QOS_TRAP_PRIORITY0, RTL8367C_OAM_PRIOIRTY_MASK, pPriority);
+}
+/* Function Name:
+ *      rtl8367c_setAsicOamEnable
+ * Description:
+ *      Set OAM function state
+ * Input:
+ *      enabled     - OAM function usage 1:enable, 0:disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicOamEnable(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_OAM_CTRL, RTL8367C_OAM_CTRL_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicOamEnable
+ * Description:
+ *      Get OAM function state
+ * Input:
+ *      pEnabled    - OAM function usage 1:enable, 0:disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicOamEnable(rtk_uint32 *pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_OAM_CTRL, RTL8367C_OAM_CTRL_OFFSET, pEnabled);
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_phy.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_phy.c
new file mode 100644
index 0000000..fb4db11
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_phy.c
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : PHY related functions
+ *
+ */
+#include <rtl8367c_asicdrv_phy.h>
+
+#if defined(MDC_MDIO_OPERATION)
+/* Function Name:
+ *      rtl8367c_setAsicPHYOCPReg
+ * Description:
+ *      Set PHY OCP registers
+ * Input:
+ *      phyNo   - Physical port number (0~7)
+ *      ocpAddr - OCP address
+ *      ocpData - Writing data
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PHY_REG_ID       - invalid PHY address
+ *      RT_ERR_PHY_ID           - invalid PHY no
+ *      RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 ocpData )
+{
+    ret_t retVal;
+    rtk_uint32 regAddr;
+    rtk_uint32 ocpAddrPrefix, ocpAddr9_6, ocpAddr5_1;
+
+    /* OCP prefix */
+    ocpAddrPrefix = ((ocpAddr & 0xFC00) >> 10);
+    if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_GPHY_OCP_MSB_0, RTL8367C_CFG_CPU_OCPADR_MSB_MASK, ocpAddrPrefix)) != RT_ERR_OK)
+        return retVal;
+
+    /*prepare access address*/
+    ocpAddr9_6 = ((ocpAddr >> 6) & 0x000F);
+    ocpAddr5_1 = ((ocpAddr >> 1) & 0x001F);
+    regAddr = RTL8367C_PHY_BASE | (ocpAddr9_6 << 8) | (phyNo << RTL8367C_PHY_OFFSET) | ocpAddr5_1;
+    if((retVal = rtl8367c_setAsicReg(regAddr, ocpData)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicPHYOCPReg
+ * Description:
+ *      Get PHY OCP registers
+ * Input:
+ *      phyNo   - Physical port number (0~7)
+ *      ocpAddr - PHY address
+ *      pRegData - read data
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PHY_REG_ID       - invalid PHY address
+ *      RT_ERR_PHY_ID           - invalid PHY no
+ *      RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 *pRegData )
+{
+    ret_t retVal;
+    rtk_uint32 regAddr;
+    rtk_uint32 ocpAddrPrefix, ocpAddr9_6, ocpAddr5_1;
+    /* OCP prefix */
+    ocpAddrPrefix = ((ocpAddr & 0xFC00) >> 10);
+    if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_GPHY_OCP_MSB_0, RTL8367C_CFG_CPU_OCPADR_MSB_MASK, ocpAddrPrefix)) != RT_ERR_OK)
+        return retVal;
+
+    /*prepare access address*/
+    ocpAddr9_6 = ((ocpAddr >> 6) & 0x000F);
+    ocpAddr5_1 = ((ocpAddr >> 1) & 0x001F);
+    regAddr = RTL8367C_PHY_BASE | (ocpAddr9_6 << 8) | (phyNo << RTL8367C_PHY_OFFSET) | ocpAddr5_1;
+    if((retVal = rtl8367c_getAsicReg(regAddr, pRegData)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+#else
+
+/* Function Name:
+ *      rtl8367c_setAsicPHYOCPReg
+ * Description:
+ *      Set PHY OCP registers
+ * Input:
+ *      phyNo   - Physical port number (0~7)
+ *      ocpAddr - OCP address
+ *      ocpData - Writing data
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PHY_REG_ID       - invalid PHY address
+ *      RT_ERR_PHY_ID           - invalid PHY no
+ *      RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 ocpData )
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+    rtk_uint32 busyFlag, checkCounter;
+    rtk_uint32 ocpAddrPrefix, ocpAddr9_6, ocpAddr5_1;
+
+    /*Check internal phy access busy or not*/
+    /*retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_INDRECT_ACCESS_STATUS, RTL8367C_INDRECT_ACCESS_STATUS_OFFSET,&busyFlag);*/
+    retVal = rtl8367c_getAsicReg(RTL8367C_REG_INDRECT_ACCESS_STATUS,&busyFlag);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    if(busyFlag)
+        return RT_ERR_BUSYWAIT_TIMEOUT;
+
+    /* OCP prefix */
+    ocpAddrPrefix = ((ocpAddr & 0xFC00) >> 10);
+    if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_GPHY_OCP_MSB_0, RTL8367C_CFG_CPU_OCPADR_MSB_MASK, ocpAddrPrefix)) != RT_ERR_OK)
+        return retVal;
+
+    /*prepare access data*/
+    retVal = rtl8367c_setAsicReg(RTL8367C_REG_INDRECT_ACCESS_WRITE_DATA, ocpData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /*prepare access address*/
+    ocpAddr9_6 = ((ocpAddr >> 6) & 0x000F);
+    ocpAddr5_1 = ((ocpAddr >> 1) & 0x001F);
+    regData = RTL8367C_PHY_BASE | (ocpAddr9_6 << 8) | (phyNo << RTL8367C_PHY_OFFSET) | ocpAddr5_1;
+    retVal = rtl8367c_setAsicReg(RTL8367C_REG_INDRECT_ACCESS_ADDRESS, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /*Set WRITE Command*/
+    retVal = rtl8367c_setAsicReg(RTL8367C_REG_INDRECT_ACCESS_CTRL, RTL8367C_CMD_MASK | RTL8367C_RW_MASK);
+
+    checkCounter = 100;
+    while(checkCounter)
+    {
+        retVal = rtl8367c_getAsicReg(RTL8367C_REG_INDRECT_ACCESS_STATUS,&busyFlag);
+        if((retVal != RT_ERR_OK) || busyFlag)
+        {
+            checkCounter --;
+            if(0 == checkCounter)
+                return RT_ERR_BUSYWAIT_TIMEOUT;
+        }
+        else
+        {
+            checkCounter = 0;
+        }
+    }
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicPHYOCPReg
+ * Description:
+ *      Get PHY OCP registers
+ * Input:
+ *      phyNo   - Physical port number (0~7)
+ *      ocpAddr - PHY address
+ *      pRegData - read data
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PHY_REG_ID       - invalid PHY address
+ *      RT_ERR_PHY_ID           - invalid PHY no
+ *      RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 *pRegData )
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+    rtk_uint32 busyFlag,checkCounter;
+    rtk_uint32 ocpAddrPrefix, ocpAddr9_6, ocpAddr5_1;
+    /*Check internal phy access busy or not*/
+    /*retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_INDRECT_ACCESS_STATUS, RTL8367C_INDRECT_ACCESS_STATUS_OFFSET,&busyFlag);*/
+    retVal = rtl8367c_getAsicReg(RTL8367C_REG_INDRECT_ACCESS_STATUS,&busyFlag);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    if(busyFlag)
+        return RT_ERR_BUSYWAIT_TIMEOUT;
+
+    /* OCP prefix */
+    ocpAddrPrefix = ((ocpAddr & 0xFC00) >> 10);
+    if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_GPHY_OCP_MSB_0, RTL8367C_CFG_CPU_OCPADR_MSB_MASK, ocpAddrPrefix)) != RT_ERR_OK)
+        return retVal;
+
+    /*prepare access address*/
+    ocpAddr9_6 = ((ocpAddr >> 6) & 0x000F);
+    ocpAddr5_1 = ((ocpAddr >> 1) & 0x001F);
+    regData = RTL8367C_PHY_BASE | (ocpAddr9_6 << 8) | (phyNo << RTL8367C_PHY_OFFSET) | ocpAddr5_1;
+    retVal = rtl8367c_setAsicReg(RTL8367C_REG_INDRECT_ACCESS_ADDRESS, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /*Set READ Command*/
+    retVal = rtl8367c_setAsicReg(RTL8367C_REG_INDRECT_ACCESS_CTRL, RTL8367C_CMD_MASK );
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    checkCounter = 100;
+    while(checkCounter)
+    {
+        retVal = rtl8367c_getAsicReg(RTL8367C_REG_INDRECT_ACCESS_STATUS,&busyFlag);
+        if((retVal != RT_ERR_OK) || busyFlag)
+        {
+            checkCounter --;
+            if(0 == checkCounter)
+                return RT_ERR_FAILED;
+        }
+        else
+        {
+            checkCounter = 0;
+        }
+    }
+
+    /*get PHY register*/
+    retVal = rtl8367c_getAsicReg(RTL8367C_REG_INDRECT_ACCESS_READ_DATA, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *pRegData = regData;
+
+    return RT_ERR_OK;
+}
+
+#endif
+
+/* Function Name:
+ *      rtl8367c_setAsicPHYReg
+ * Description:
+ *      Set PHY registers
+ * Input:
+ *      phyNo   - Physical port number (0~7)
+ *      phyAddr - PHY address (0~31)
+ *      phyData - Writing data
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PHY_REG_ID       - invalid PHY address
+ *      RT_ERR_PHY_ID           - invalid PHY no
+ *      RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPHYReg(rtk_uint32 phyNo, rtk_uint32 phyAddr, rtk_uint32 phyData )
+{
+    rtk_uint32 ocp_addr;
+
+    if(phyAddr > RTL8367C_PHY_REGNOMAX)
+        return RT_ERR_PHY_REG_ID;
+
+    ocp_addr = 0xa400 + phyAddr*2;
+
+    return rtl8367c_setAsicPHYOCPReg(phyNo, ocp_addr, phyData);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPHYReg
+ * Description:
+ *      Get PHY registers
+ * Input:
+ *      phyNo   - Physical port number (0~7)
+ *      phyAddr - PHY address (0~31)
+ *      pRegData - Writing data
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PHY_REG_ID       - invalid PHY address
+ *      RT_ERR_PHY_ID           - invalid PHY no
+ *      RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPHYReg(rtk_uint32 phyNo, rtk_uint32 phyAddr, rtk_uint32 *pRegData )
+{
+    rtk_uint32 ocp_addr;
+
+    if(phyAddr > RTL8367C_PHY_REGNOMAX)
+        return RT_ERR_PHY_REG_ID;
+
+    ocp_addr = 0xa400 + phyAddr*2;
+
+    return rtl8367c_getAsicPHYOCPReg(phyNo, ocp_addr, pRegData);
+}
+
+
+/* Function Name:
+ *      rtl8367c_setAsicSdsReg
+ * Description:
+ *      Set Serdes registers
+ * Input:
+ *      sdsId   - sdsid (0~1)
+ *      sdsReg - reg address (0~31)
+ *      sdsPage - Writing data
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+
+ * Note:
+ *      None
+ */
+
+ret_t rtl8367c_setAsicSdsReg(rtk_uint32 sdsId, rtk_uint32 sdsReg, rtk_uint32 sdsPage,  rtk_uint32 value)
+{
+    rtk_uint32 retVal;
+
+    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, value)) != RT_ERR_OK)
+        return retVal;
+
+    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (sdsPage<<5) | sdsReg)) != RT_ERR_OK)
+        return retVal;
+
+    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0|sdsId)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+
+}
+
+/* Function Name:
+ *      rtl8367c_getAiscSdsReg
+ * Description:
+ *      Get Serdes registers
+ * Input:
+ *      sdsId   - sdsid (0~1)
+ *      sdsReg - reg address (0~31)
+ *      sdsPage - Writing data
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicSdsReg(rtk_uint32 sdsId, rtk_uint32 sdsReg, rtk_uint32 sdsPage, rtk_uint32 *value)
+{
+    rtk_uint32 retVal, busy;
+
+    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (sdsPage<<5) | sdsReg)) != RT_ERR_OK)
+        return retVal;
+
+    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x0080|sdsId)) != RT_ERR_OK)
+        return retVal;
+
+    while(1)
+    {
+        if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_SDS_INDACS_CMD, &busy))!=RT_ERR_OK)
+            return retVal;
+
+        if ((busy & 0x100) == 0)
+            break;
+    }
+
+    if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_SDS_INDACS_DATA, value))!=RT_ERR_OK)
+            return retVal;
+
+    return RT_ERR_OK;
+}
+
+
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_port.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_port.c
new file mode 100644
index 0000000..78e80a0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_port.c
@@ -0,0 +1,5752 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76333 $
+ * $Date: 2017-03-09 09:33:15 +0800 (週四, 09 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Port security related functions
+ *
+ */
+
+#include <rtl8367c_asicdrv_port.h>
+
+#include <string.h>
+
+
+#define FIBER2_AUTO_INIT_SIZE 2038
+rtk_uint8 Fiber2_Auto[FIBER2_AUTO_INIT_SIZE] = {
+0x02,0x05,0x8F,0xE4,0xF5,0xA8,0xD2,0xAF,
+0x22,0x00,0x00,0x02,0x07,0x2C,0xC5,0xF0,
+0xF8,0xA3,0xE0,0x28,0xF0,0xC5,0xF0,0xF8,
+0xE5,0x82,0x15,0x82,0x70,0x02,0x15,0x83,
+0xE0,0x38,0xF0,0x22,0x75,0xF0,0x08,0x75,
+0x82,0x00,0xEF,0x2F,0xFF,0xEE,0x33,0xFE,
+0xCD,0x33,0xCD,0xCC,0x33,0xCC,0xC5,0x82,
+0x33,0xC5,0x82,0x9B,0xED,0x9A,0xEC,0x99,
+0xE5,0x82,0x98,0x40,0x0C,0xF5,0x82,0xEE,
+0x9B,0xFE,0xED,0x9A,0xFD,0xEC,0x99,0xFC,
+0x0F,0xD5,0xF0,0xD6,0xE4,0xCE,0xFB,0xE4,
+0xCD,0xFA,0xE4,0xCC,0xF9,0xA8,0x82,0x22,
+0xB8,0x00,0xC1,0xB9,0x00,0x59,0xBA,0x00,
+0x2D,0xEC,0x8B,0xF0,0x84,0xCF,0xCE,0xCD,
+0xFC,0xE5,0xF0,0xCB,0xF9,0x78,0x18,0xEF,
+0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33,0xFD,
+0xEC,0x33,0xFC,0xEB,0x33,0xFB,0x10,0xD7,
+0x03,0x99,0x40,0x04,0xEB,0x99,0xFB,0x0F,
+0xD8,0xE5,0xE4,0xF9,0xFA,0x22,0x78,0x18,
+0xEF,0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33,
+0xFD,0xEC,0x33,0xFC,0xC9,0x33,0xC9,0x10,
+0xD7,0x05,0x9B,0xE9,0x9A,0x40,0x07,0xEC,
+0x9B,0xFC,0xE9,0x9A,0xF9,0x0F,0xD8,0xE0,
+0xE4,0xC9,0xFA,0xE4,0xCC,0xFB,0x22,0x75,
+0xF0,0x10,0xEF,0x2F,0xFF,0xEE,0x33,0xFE,
+0xED,0x33,0xFD,0xCC,0x33,0xCC,0xC8,0x33,
+0xC8,0x10,0xD7,0x07,0x9B,0xEC,0x9A,0xE8,
+0x99,0x40,0x0A,0xED,0x9B,0xFD,0xEC,0x9A,
+0xFC,0xE8,0x99,0xF8,0x0F,0xD5,0xF0,0xDA,
+0xE4,0xCD,0xFB,0xE4,0xCC,0xFA,0xE4,0xC8,
+0xF9,0x22,0xEB,0x9F,0xF5,0xF0,0xEA,0x9E,
+0x42,0xF0,0xE9,0x9D,0x42,0xF0,0xE8,0x9C,
+0x45,0xF0,0x22,0xE0,0xFC,0xA3,0xE0,0xFD,
+0xA3,0xE0,0xFE,0xA3,0xE0,0xFF,0x22,0xE0,
+0xF8,0xA3,0xE0,0xF9,0xA3,0xE0,0xFA,0xA3,
+0xE0,0xFB,0x22,0xEC,0xF0,0xA3,0xED,0xF0,
+0xA3,0xEE,0xF0,0xA3,0xEF,0xF0,0x22,0x7D,
+0xD7,0x7C,0x04,0x7F,0x02,0x7E,0x66,0x12,
+0x07,0xAB,0x7D,0x80,0x7C,0x04,0x7F,0x01,
+0x7E,0x66,0x12,0x07,0xAB,0x7D,0xC0,0x7C,
+0x00,0x7F,0x00,0x7E,0x66,0x12,0x07,0xAB,
+0x7D,0x94,0x7C,0xF9,0x7F,0x02,0x7E,0x66,
+0x12,0x07,0xAB,0x7D,0x81,0x7C,0x04,0x7F,
+0x01,0x7E,0x66,0x12,0x07,0xAB,0x7D,0xC0,
+0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,0x07,
+0xAB,0x7D,0xA2,0x7C,0x31,0x7F,0x02,0x7E,
+0x66,0x12,0x07,0xAB,0x7D,0x82,0x7C,0x04,
+0x7F,0x01,0x7E,0x66,0x12,0x07,0xAB,0x7D,
+0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,
+0x07,0xAB,0x7D,0x60,0x7C,0x69,0x7F,0x02,
+0x7E,0x66,0x12,0x07,0xAB,0x7D,0x83,0x7C,
+0x04,0x7F,0x01,0x7E,0x66,0x12,0x07,0xAB,
+0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66,
+0x12,0x07,0xAB,0x7D,0x28,0x7C,0x97,0x7F,
+0x02,0x7E,0x66,0x12,0x07,0xAB,0x7D,0x84,
+0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12,0x07,
+0xAB,0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E,
+0x66,0x12,0x07,0xAB,0x7D,0x85,0x7C,0x9D,
+0x7F,0x02,0x7E,0x66,0x12,0x07,0xAB,0x7D,
+0x23,0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12,
+0x07,0xAB,0x7D,0xC0,0x7C,0x00,0x7F,0x00,
+0x7E,0x66,0x12,0x07,0xAB,0x7D,0x10,0x7C,
+0xD8,0x7F,0x02,0x7E,0x66,0x12,0x07,0xAB,
+0x7D,0x24,0x7C,0x04,0x7F,0x01,0x7E,0x66,
+0x12,0x07,0xAB,0x7D,0xC0,0x7C,0x00,0x7F,
+0x00,0x7E,0x66,0x12,0x07,0xAB,0x7D,0x00,
+0x7C,0x04,0x7F,0x02,0x7E,0x66,0x12,0x07,
+0xAB,0x7D,0x2F,0x7C,0x00,0x7F,0x01,0x7E,
+0x66,0x12,0x07,0xAB,0x7D,0xC0,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x02,0x07,0xAB,0x7D,
+0x03,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12,
+0x07,0xAB,0x7D,0x80,0x7C,0x00,0x7F,0x00,
+0x7E,0x66,0x12,0x07,0xAB,0x7F,0x02,0x7E,
+0x66,0x12,0x07,0x66,0xEF,0x44,0x40,0xFD,
+0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,0x07,
+0xAB,0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E,
+0x66,0x12,0x07,0xAB,0x7D,0xC0,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x12,0x07,0xAB,0x7D,
+0x03,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12,
+0x07,0xAB,0x7D,0x80,0x7C,0x00,0x7F,0x00,
+0x7E,0x66,0x12,0x07,0xAB,0x7F,0x02,0x7E,
+0x66,0x12,0x07,0x66,0xEF,0x54,0xBF,0xFD,
+0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,0x07,
+0xAB,0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E,
+0x66,0x12,0x07,0xAB,0x7D,0xC0,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x12,0x07,0xAB,0xE4,
+0xFD,0xFC,0x7F,0x01,0x7E,0x66,0x12,0x07,
+0xAB,0x7D,0x80,0x7C,0x00,0x7F,0x00,0x7E,
+0x66,0x12,0x07,0xAB,0x7F,0x02,0x7E,0x66,
+0x12,0x07,0x66,0xEF,0x54,0xFD,0x54,0xFE,
+0xFD,0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,
+0x07,0xAB,0xE4,0xFD,0xFC,0x7F,0x01,0x7E,
+0x66,0x12,0x07,0xAB,0x7D,0xC0,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x12,0x07,0xAB,0xE4,
+0xFD,0xFC,0x7F,0x01,0x7E,0x66,0x12,0x07,
+0xAB,0x7D,0x80,0x7C,0x00,0x7F,0x00,0x7E,
+0x66,0x12,0x07,0xAB,0x7F,0x02,0x7E,0x66,
+0x12,0x07,0x66,0xEF,0x44,0x02,0x44,0x01,
+0xFD,0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,
+0x07,0xAB,0xE4,0xFD,0xFC,0x7F,0x01,0x7E,
+0x66,0x12,0x07,0xAB,0x7D,0xC0,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x02,0x07,0xAB,0xE4,
+0x90,0x06,0x2C,0xF0,0xFD,0x7C,0x01,0x7F,
+0x3F,0x7E,0x1D,0x12,0x07,0xAB,0x7D,0x40,
+0x7C,0x00,0x7F,0x36,0x7E,0x13,0x12,0x07,
+0xAB,0xE4,0xFF,0xFE,0xFD,0x80,0x25,0xE4,
+0x7F,0xFF,0x7E,0xFF,0xFD,0xFC,0x90,0x06,
+0x24,0x12,0x01,0x0F,0xC3,0x12,0x00,0xF2,
+0x50,0x1B,0x90,0x06,0x24,0x12,0x01,0x03,
+0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE,0xE4,
+0x3D,0xFD,0xE4,0x3C,0xFC,0x90,0x06,0x24,
+0x12,0x01,0x1B,0x80,0xD2,0xE4,0xF5,0xA8,
+0xD2,0xAF,0x7D,0x1F,0xFC,0x7F,0x49,0x7E,
+0x13,0x12,0x07,0xAB,0x12,0x07,0xDB,0x12,
+0x01,0x27,0x12,0x06,0x1B,0x12,0x07,0x8A,
+0x12,0x06,0xEA,0x7D,0x41,0x7C,0x00,0x7F,
+0x36,0x7E,0x13,0x12,0x07,0xAB,0xE4,0xFF,
+0xFE,0xFD,0x80,0x26,0x7F,0xFF,0x7E,0xFF,
+0x7D,0x05,0x7C,0x00,0x90,0x06,0x24,0x12,
+0x01,0x0F,0xC3,0x12,0x00,0xF2,0x50,0x1B,
+0x90,0x06,0x24,0x12,0x01,0x03,0xEF,0x24,
+0x01,0xFF,0xE4,0x3E,0xFE,0xE4,0x3D,0xFD,
+0xE4,0x3C,0xFC,0x90,0x06,0x24,0x12,0x01,
+0x1B,0x80,0xD1,0xC2,0x00,0xC2,0x01,0xD2,
+0xA9,0xD2,0x8C,0x7F,0x01,0x7E,0x62,0x12,
+0x07,0x66,0xEF,0x30,0xE2,0x07,0xE4,0x90,
+0x06,0x2C,0xF0,0x80,0xEE,0x90,0x06,0x2C,
+0xE0,0x70,0x12,0x12,0x04,0xF0,0x90,0x06,
+0x2C,0x74,0x01,0xF0,0xE4,0x90,0x06,0x33,
+0xF0,0xA3,0xF0,0x80,0xD6,0xC3,0x90,0x06,
+0x34,0xE0,0x94,0x62,0x90,0x06,0x33,0xE0,
+0x94,0x00,0x40,0xC7,0xE4,0xF0,0xA3,0xF0,
+0x12,0x04,0xF0,0x90,0x06,0x2C,0x74,0x01,
+0xF0,0x80,0xB8,0x75,0x0F,0x80,0x75,0x0E,
+0x7E,0x75,0x0D,0xAA,0x75,0x0C,0x83,0xE4,
+0xF5,0x10,0x7F,0x36,0x7E,0x13,0x12,0x07,
+0x66,0xEE,0xC4,0xF8,0x54,0xF0,0xC8,0xEF,
+0xC4,0x54,0x0F,0x48,0x54,0x07,0xFB,0x7A,
+0x00,0xEA,0x70,0x4A,0xEB,0x14,0x60,0x1C,
+0x14,0x60,0x27,0x24,0xFE,0x60,0x31,0x14,
+0x60,0x3C,0x24,0x05,0x70,0x38,0x75,0x0B,
+0x00,0x75,0x0A,0xC2,0x75,0x09,0xEB,0x75,
+0x08,0x0B,0x80,0x36,0x75,0x0B,0x40,0x75,
+0x0A,0x59,0x75,0x09,0x73,0x75,0x08,0x07,
+0x80,0x28,0x75,0x0B,0x00,0x75,0x0A,0xE1,
+0x75,0x09,0xF5,0x75,0x08,0x05,0x80,0x1A,
+0x75,0x0B,0xA0,0x75,0x0A,0xAC,0x75,0x09,
+0xB9,0x75,0x08,0x03,0x80,0x0C,0x75,0x0B,
+0x00,0x75,0x0A,0x62,0x75,0x09,0x3D,0x75,
+0x08,0x01,0x75,0x89,0x11,0xE4,0x7B,0x60,
+0x7A,0x09,0xF9,0xF8,0xAF,0x0B,0xAE,0x0A,
+0xAD,0x09,0xAC,0x08,0x12,0x00,0x60,0xAA,
+0x06,0xAB,0x07,0xC3,0xE4,0x9B,0xFB,0xE4,
+0x9A,0xFA,0x78,0x17,0xF6,0xAF,0x03,0xEF,
+0x08,0xF6,0x18,0xE6,0xF5,0x8C,0x08,0xE6,
+0xF5,0x8A,0x74,0x0D,0x2B,0xFB,0xE4,0x3A,
+0x18,0xF6,0xAF,0x03,0xEF,0x08,0xF6,0x75,
+0x88,0x10,0x53,0x8E,0xC7,0xD2,0xA9,0x22,
+0x7F,0x10,0x7E,0x13,0x12,0x07,0x66,0x90,
+0x06,0x2D,0xEE,0xF0,0xA3,0xEF,0xF0,0xEE,
+0x44,0x10,0xFE,0x90,0x06,0x2D,0xF0,0xA3,
+0xEF,0xF0,0x54,0xEF,0xFF,0x90,0x06,0x2D,
+0xEE,0xF0,0xFC,0xA3,0xEF,0xF0,0xFD,0x7F,
+0x10,0x7E,0x13,0x12,0x07,0xAB,0xE4,0xFF,
+0xFE,0x0F,0xBF,0x00,0x01,0x0E,0xEF,0x64,
+0x64,0x4E,0x70,0xF5,0x7D,0x04,0x7C,0x00,
+0x7F,0x02,0x7E,0x66,0x12,0x07,0xAB,0x7D,
+0x00,0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12,
+0x07,0xAB,0x7D,0xC0,0x7C,0x00,0x7F,0x00,
+0x7E,0x66,0x12,0x07,0xAB,0xE4,0xFD,0xFC,
+0x7F,0x02,0x7E,0x66,0x12,0x07,0xAB,0x7D,
+0x00,0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12,
+0x07,0xAB,0x7D,0xC0,0x7C,0x00,0x7F,0x00,
+0x7E,0x66,0x12,0x07,0xAB,0x7F,0x10,0x7E,
+0x13,0x12,0x07,0x66,0x90,0x06,0x2D,0xEE,
+0xF0,0xA3,0xEF,0xF0,0xEE,0x54,0xEF,0x90,
+0x06,0x2D,0xF0,0xFC,0xA3,0xEF,0xF0,0xFD,
+0x7F,0x10,0x7E,0x13,0x02,0x07,0xAB,0x78,
+0x7F,0xE4,0xF6,0xD8,0xFD,0x75,0x81,0x3C,
+0x02,0x05,0xD6,0x02,0x03,0x2F,0xE4,0x93,
+0xA3,0xF8,0xE4,0x93,0xA3,0x40,0x03,0xF6,
+0x80,0x01,0xF2,0x08,0xDF,0xF4,0x80,0x29,
+0xE4,0x93,0xA3,0xF8,0x54,0x07,0x24,0x0C,
+0xC8,0xC3,0x33,0xC4,0x54,0x0F,0x44,0x20,
+0xC8,0x83,0x40,0x04,0xF4,0x56,0x80,0x01,
+0x46,0xF6,0xDF,0xE4,0x80,0x0B,0x01,0x02,
+0x04,0x08,0x10,0x20,0x40,0x80,0x90,0x07,
+0xE7,0xE4,0x7E,0x01,0x93,0x60,0xBC,0xA3,
+0xFF,0x54,0x3F,0x30,0xE5,0x09,0x54,0x1F,
+0xFE,0xE4,0x93,0xA3,0x60,0x01,0x0E,0xCF,
+0x54,0xC0,0x25,0xE0,0x60,0xA8,0x40,0xB8,
+0xE4,0x93,0xA3,0xFA,0xE4,0x93,0xA3,0xF8,
+0xE4,0x93,0xA3,0xC8,0xC5,0x82,0xC8,0xCA,
+0xC5,0x83,0xCA,0xF0,0xA3,0xC8,0xC5,0x82,
+0xC8,0xCA,0xC5,0x83,0xCA,0xDF,0xE9,0xDE,
+0xE7,0x80,0xBE,0x7D,0x40,0x7C,0x17,0x7F,
+0x11,0x7E,0x1D,0x12,0x07,0xAB,0x7F,0x41,
+0x7E,0x1D,0x12,0x07,0x66,0xEF,0x44,0x20,
+0x44,0x80,0xFD,0xAC,0x06,0x7F,0x41,0x7E,
+0x1D,0x12,0x07,0xAB,0x7D,0xBB,0x7C,0x15,
+0x7F,0xEB,0x7E,0x13,0x12,0x07,0xAB,0x7D,
+0x07,0x7C,0x00,0x7F,0xE7,0x7E,0x13,0x12,
+0x07,0xAB,0x7D,0x40,0x7C,0x11,0x7F,0x00,
+0x7E,0x62,0x12,0x07,0xAB,0x02,0x02,0x2F,
+0x7D,0xC0,0x7C,0x16,0x7F,0x11,0x7E,0x1D,
+0x12,0x07,0xAB,0x7D,0xBB,0x7C,0x15,0x7F,
+0xEB,0x7E,0x13,0x12,0x07,0xAB,0x7D,0x0D,
+0x7C,0x00,0x7F,0xE7,0x7E,0x13,0x12,0x07,
+0xAB,0x7F,0x41,0x7E,0x1D,0x12,0x07,0x66,
+0xEF,0x44,0x20,0x44,0x80,0xFD,0xAC,0x06,
+0x7F,0x41,0x7E,0x1D,0x12,0x07,0xAB,0x7D,
+0x00,0x7C,0x21,0x7F,0x00,0x7E,0x62,0x12,
+0x07,0xAB,0x02,0x02,0x2F,0x7D,0x40,0x7C,
+0x17,0x7F,0x11,0x7E,0x1D,0x12,0x07,0xAB,
+0x7D,0xBB,0x7C,0x15,0x7F,0xEB,0x7E,0x13,
+0x12,0x07,0xAB,0x7D,0x0C,0x7C,0x00,0x7F,
+0xE7,0x7E,0x13,0x12,0x07,0xAB,0x7F,0x41,
+0x7E,0x1D,0x12,0x07,0x66,0xEF,0x44,0x20,
+0x44,0x80,0xFD,0xAC,0x06,0x7F,0x41,0x7E,
+0x1D,0x12,0x07,0xAB,0x7D,0x40,0x7C,0x11,
+0x7F,0x00,0x7E,0x62,0x12,0x07,0xAB,0x02,
+0x02,0x2F,0x7D,0x04,0x7C,0x00,0x7F,0x01,
+0x7E,0x66,0x12,0x07,0xAB,0x7D,0x80,0x7C,
+0x00,0x7F,0x00,0x7E,0x66,0x12,0x07,0xAB,
+0x7F,0x02,0x7E,0x66,0x12,0x07,0x66,0xEF,
+0x44,0x02,0x44,0x04,0xFD,0xAC,0x06,0x7F,
+0x02,0x7E,0x66,0x12,0x07,0xAB,0x7D,0x04,
+0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12,0x07,
+0xAB,0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E,
+0x66,0x02,0x07,0xAB,0xC0,0xE0,0xC0,0xF0,
+0xC0,0x83,0xC0,0x82,0xC0,0xD0,0x75,0xD0,
+0x00,0xC0,0x00,0x78,0x17,0xE6,0xF5,0x8C,
+0x78,0x18,0xE6,0xF5,0x8A,0x90,0x06,0x31,
+0xE4,0x75,0xF0,0x01,0x12,0x00,0x0E,0x90,
+0x06,0x33,0xE4,0x75,0xF0,0x01,0x12,0x00,
+0x0E,0xD0,0x00,0xD0,0xD0,0xD0,0x82,0xD0,
+0x83,0xD0,0xF0,0xD0,0xE0,0x32,0xC2,0xAF,
+0xAD,0x07,0xAC,0x06,0x8C,0xA2,0x8D,0xA3,
+0x75,0xA0,0x01,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0xAE,0xA1,
+0xBE,0x00,0xF0,0xAE,0xA6,0xAF,0xA7,0xD2,
+0xAF,0x22,0x7D,0x20,0x7C,0x0F,0x7F,0x02,
+0x7E,0x66,0x12,0x07,0xAB,0x7D,0x01,0x7C,
+0x00,0x7F,0x01,0x7E,0x66,0x12,0x07,0xAB,
+0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66,
+0x02,0x07,0xAB,0xC2,0xAF,0xAB,0x07,0xAA,
+0x06,0x8A,0xA2,0x8B,0xA3,0x8C,0xA4,0x8D,
+0xA5,0x75,0xA0,0x03,0x00,0x00,0x00,0xAA,
+0xA1,0xBA,0x00,0xF8,0xD2,0xAF,0x22,0x7F,
+0x0C,0x7E,0x13,0x12,0x07,0x66,0xEF,0x44,
+0x50,0xFD,0xAC,0x06,0x7F,0x0C,0x7E,0x13,
+0x02,0x07,0xAB,0x12,0x07,0xC7,0x12,0x07,
+0xF2,0x12,0x04,0x2B,0x02,0x00,0x03,0x42,
+0x06,0x33,0x00,0x00,0x42,0x06,0x31,0x00,
+0x00,0x00,0xE4,0xF5,0x8E,0x22,};
+
+#define FIBER2_1G_INIT_SIZE 2032
+rtk_uint8 Fiber2_1G[FIBER2_1G_INIT_SIZE] = {
+0x02,0x05,0x89,0xE4,0xF5,0xA8,0xD2,0xAF,
+0x22,0x00,0x00,0x02,0x07,0x26,0xC5,0xF0,
+0xF8,0xA3,0xE0,0x28,0xF0,0xC5,0xF0,0xF8,
+0xE5,0x82,0x15,0x82,0x70,0x02,0x15,0x83,
+0xE0,0x38,0xF0,0x22,0x75,0xF0,0x08,0x75,
+0x82,0x00,0xEF,0x2F,0xFF,0xEE,0x33,0xFE,
+0xCD,0x33,0xCD,0xCC,0x33,0xCC,0xC5,0x82,
+0x33,0xC5,0x82,0x9B,0xED,0x9A,0xEC,0x99,
+0xE5,0x82,0x98,0x40,0x0C,0xF5,0x82,0xEE,
+0x9B,0xFE,0xED,0x9A,0xFD,0xEC,0x99,0xFC,
+0x0F,0xD5,0xF0,0xD6,0xE4,0xCE,0xFB,0xE4,
+0xCD,0xFA,0xE4,0xCC,0xF9,0xA8,0x82,0x22,
+0xB8,0x00,0xC1,0xB9,0x00,0x59,0xBA,0x00,
+0x2D,0xEC,0x8B,0xF0,0x84,0xCF,0xCE,0xCD,
+0xFC,0xE5,0xF0,0xCB,0xF9,0x78,0x18,0xEF,
+0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33,0xFD,
+0xEC,0x33,0xFC,0xEB,0x33,0xFB,0x10,0xD7,
+0x03,0x99,0x40,0x04,0xEB,0x99,0xFB,0x0F,
+0xD8,0xE5,0xE4,0xF9,0xFA,0x22,0x78,0x18,
+0xEF,0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33,
+0xFD,0xEC,0x33,0xFC,0xC9,0x33,0xC9,0x10,
+0xD7,0x05,0x9B,0xE9,0x9A,0x40,0x07,0xEC,
+0x9B,0xFC,0xE9,0x9A,0xF9,0x0F,0xD8,0xE0,
+0xE4,0xC9,0xFA,0xE4,0xCC,0xFB,0x22,0x75,
+0xF0,0x10,0xEF,0x2F,0xFF,0xEE,0x33,0xFE,
+0xED,0x33,0xFD,0xCC,0x33,0xCC,0xC8,0x33,
+0xC8,0x10,0xD7,0x07,0x9B,0xEC,0x9A,0xE8,
+0x99,0x40,0x0A,0xED,0x9B,0xFD,0xEC,0x9A,
+0xFC,0xE8,0x99,0xF8,0x0F,0xD5,0xF0,0xDA,
+0xE4,0xCD,0xFB,0xE4,0xCC,0xFA,0xE4,0xC8,
+0xF9,0x22,0xEB,0x9F,0xF5,0xF0,0xEA,0x9E,
+0x42,0xF0,0xE9,0x9D,0x42,0xF0,0xE8,0x9C,
+0x45,0xF0,0x22,0xE0,0xFC,0xA3,0xE0,0xFD,
+0xA3,0xE0,0xFE,0xA3,0xE0,0xFF,0x22,0xE0,
+0xF8,0xA3,0xE0,0xF9,0xA3,0xE0,0xFA,0xA3,
+0xE0,0xFB,0x22,0xEC,0xF0,0xA3,0xED,0xF0,
+0xA3,0xEE,0xF0,0xA3,0xEF,0xF0,0x22,0x7D,
+0xD7,0x7C,0x04,0x7F,0x02,0x7E,0x66,0x12,
+0x07,0xA5,0x7D,0x80,0x7C,0x04,0x7F,0x01,
+0x7E,0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,
+0x00,0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,
+0x7D,0x94,0x7C,0xF9,0x7F,0x02,0x7E,0x66,
+0x12,0x07,0xA5,0x7D,0x81,0x7C,0x04,0x7F,
+0x01,0x7E,0x66,0x12,0x07,0xA5,0x7D,0xC0,
+0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,0x07,
+0xA5,0x7D,0xA2,0x7C,0x31,0x7F,0x02,0x7E,
+0x66,0x12,0x07,0xA5,0x7D,0x82,0x7C,0x04,
+0x7F,0x01,0x7E,0x66,0x12,0x07,0xA5,0x7D,
+0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,
+0x07,0xA5,0x7D,0x60,0x7C,0x69,0x7F,0x02,
+0x7E,0x66,0x12,0x07,0xA5,0x7D,0x83,0x7C,
+0x04,0x7F,0x01,0x7E,0x66,0x12,0x07,0xA5,
+0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66,
+0x12,0x07,0xA5,0x7D,0x28,0x7C,0x97,0x7F,
+0x02,0x7E,0x66,0x12,0x07,0xA5,0x7D,0x84,
+0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12,0x07,
+0xA5,0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E,
+0x66,0x12,0x07,0xA5,0x7D,0x85,0x7C,0x9D,
+0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5,0x7D,
+0x23,0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12,
+0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F,0x00,
+0x7E,0x66,0x12,0x07,0xA5,0x7D,0x10,0x7C,
+0xD8,0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5,
+0x7D,0x24,0x7C,0x04,0x7F,0x01,0x7E,0x66,
+0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F,
+0x00,0x7E,0x66,0x12,0x07,0xA5,0x7D,0x00,
+0x7C,0x04,0x7F,0x02,0x7E,0x66,0x12,0x07,
+0xA5,0x7D,0x2F,0x7C,0x00,0x7F,0x01,0x7E,
+0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x02,0x07,0xA5,0x7D,
+0x03,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12,
+0x07,0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00,
+0x7E,0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E,
+0x66,0x12,0x07,0x60,0xEF,0x44,0x40,0xFD,
+0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,0x07,
+0xA5,0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E,
+0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0x7D,
+0x03,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12,
+0x07,0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00,
+0x7E,0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E,
+0x66,0x12,0x07,0x60,0xEF,0x54,0xBF,0xFD,
+0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,0x07,
+0xA5,0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E,
+0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0xE4,
+0xFD,0xFC,0x7F,0x01,0x7E,0x66,0x12,0x07,
+0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00,0x7E,
+0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E,0x66,
+0x12,0x07,0x60,0xEF,0x54,0xFD,0x54,0xFE,
+0xFD,0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,
+0x07,0xA5,0xE4,0xFD,0xFC,0x7F,0x01,0x7E,
+0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0xE4,
+0xFD,0xFC,0x7F,0x01,0x7E,0x66,0x12,0x07,
+0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00,0x7E,
+0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E,0x66,
+0x12,0x07,0x60,0xEF,0x44,0x02,0x44,0x01,
+0xFD,0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,
+0x07,0xA5,0xE4,0xFD,0xFC,0x7F,0x01,0x7E,
+0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x02,0x07,0xA5,0xE4,
+0x90,0x06,0x2C,0xF0,0xFD,0x7C,0x01,0x7F,
+0x3F,0x7E,0x1D,0x12,0x07,0xA5,0x7D,0x40,
+0x7C,0x00,0x7F,0x36,0x7E,0x13,0x12,0x07,
+0xA5,0xE4,0xFF,0xFE,0xFD,0x80,0x25,0xE4,
+0x7F,0xFF,0x7E,0xFF,0xFD,0xFC,0x90,0x06,
+0x24,0x12,0x01,0x0F,0xC3,0x12,0x00,0xF2,
+0x50,0x1B,0x90,0x06,0x24,0x12,0x01,0x03,
+0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE,0xE4,
+0x3D,0xFD,0xE4,0x3C,0xFC,0x90,0x06,0x24,
+0x12,0x01,0x1B,0x80,0xD2,0xE4,0xF5,0xA8,
+0xD2,0xAF,0x7D,0x1F,0xFC,0x7F,0x49,0x7E,
+0x13,0x12,0x07,0xA5,0x12,0x07,0xD5,0x12,
+0x01,0x27,0x12,0x06,0x9F,0x7D,0x41,0x7C,
+0x00,0x7F,0x36,0x7E,0x13,0x12,0x07,0xA5,
+0xE4,0xFF,0xFE,0xFD,0x80,0x26,0x7F,0xFF,
+0x7E,0xFF,0x7D,0x05,0x7C,0x00,0x90,0x06,
+0x24,0x12,0x01,0x0F,0xC3,0x12,0x00,0xF2,
+0x50,0x1B,0x90,0x06,0x24,0x12,0x01,0x03,
+0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE,0xE4,
+0x3D,0xFD,0xE4,0x3C,0xFC,0x90,0x06,0x24,
+0x12,0x01,0x1B,0x80,0xD1,0xC2,0x00,0xC2,
+0x01,0xD2,0xA9,0xD2,0x8C,0x7F,0x01,0x7E,
+0x62,0x12,0x07,0x60,0xEF,0x30,0xE2,0x07,
+0xE4,0x90,0x06,0x2C,0xF0,0x80,0xEE,0x90,
+0x06,0x2C,0xE0,0x70,0x12,0x12,0x04,0xEA,
+0x90,0x06,0x2C,0x74,0x01,0xF0,0xE4,0x90,
+0x06,0x33,0xF0,0xA3,0xF0,0x80,0xD6,0xC3,
+0x90,0x06,0x34,0xE0,0x94,0x62,0x90,0x06,
+0x33,0xE0,0x94,0x00,0x40,0xC7,0xE4,0xF0,
+0xA3,0xF0,0x12,0x04,0xEA,0x90,0x06,0x2C,
+0x74,0x01,0xF0,0x80,0xB8,0x75,0x0F,0x80,
+0x75,0x0E,0x7E,0x75,0x0D,0xAA,0x75,0x0C,
+0x83,0xE4,0xF5,0x10,0x7F,0x36,0x7E,0x13,
+0x12,0x07,0x60,0xEE,0xC4,0xF8,0x54,0xF0,
+0xC8,0xEF,0xC4,0x54,0x0F,0x48,0x54,0x07,
+0xFB,0x7A,0x00,0xEA,0x70,0x4A,0xEB,0x14,
+0x60,0x1C,0x14,0x60,0x27,0x24,0xFE,0x60,
+0x31,0x14,0x60,0x3C,0x24,0x05,0x70,0x38,
+0x75,0x0B,0x00,0x75,0x0A,0xC2,0x75,0x09,
+0xEB,0x75,0x08,0x0B,0x80,0x36,0x75,0x0B,
+0x40,0x75,0x0A,0x59,0x75,0x09,0x73,0x75,
+0x08,0x07,0x80,0x28,0x75,0x0B,0x00,0x75,
+0x0A,0xE1,0x75,0x09,0xF5,0x75,0x08,0x05,
+0x80,0x1A,0x75,0x0B,0xA0,0x75,0x0A,0xAC,
+0x75,0x09,0xB9,0x75,0x08,0x03,0x80,0x0C,
+0x75,0x0B,0x00,0x75,0x0A,0x62,0x75,0x09,
+0x3D,0x75,0x08,0x01,0x75,0x89,0x11,0xE4,
+0x7B,0x60,0x7A,0x09,0xF9,0xF8,0xAF,0x0B,
+0xAE,0x0A,0xAD,0x09,0xAC,0x08,0x12,0x00,
+0x60,0xAA,0x06,0xAB,0x07,0xC3,0xE4,0x9B,
+0xFB,0xE4,0x9A,0xFA,0x78,0x17,0xF6,0xAF,
+0x03,0xEF,0x08,0xF6,0x18,0xE6,0xF5,0x8C,
+0x08,0xE6,0xF5,0x8A,0x74,0x0D,0x2B,0xFB,
+0xE4,0x3A,0x18,0xF6,0xAF,0x03,0xEF,0x08,
+0xF6,0x75,0x88,0x10,0x53,0x8E,0xC7,0xD2,
+0xA9,0x22,0x7F,0x10,0x7E,0x13,0x12,0x07,
+0x60,0x90,0x06,0x2D,0xEE,0xF0,0xA3,0xEF,
+0xF0,0xEE,0x44,0x10,0xFE,0x90,0x06,0x2D,
+0xF0,0xA3,0xEF,0xF0,0x54,0xEF,0xFF,0x90,
+0x06,0x2D,0xEE,0xF0,0xFC,0xA3,0xEF,0xF0,
+0xFD,0x7F,0x10,0x7E,0x13,0x12,0x07,0xA5,
+0xE4,0xFF,0xFE,0x0F,0xBF,0x00,0x01,0x0E,
+0xEF,0x64,0x64,0x4E,0x70,0xF5,0x7D,0x04,
+0x7C,0x00,0x7F,0x02,0x7E,0x66,0x12,0x07,
+0xA5,0x7D,0x00,0x7C,0x04,0x7F,0x01,0x7E,
+0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0xE4,
+0xFD,0xFC,0x7F,0x02,0x7E,0x66,0x12,0x07,
+0xA5,0x7D,0x00,0x7C,0x04,0x7F,0x01,0x7E,
+0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0x7F,
+0x10,0x7E,0x13,0x12,0x07,0x60,0x90,0x06,
+0x2D,0xEE,0xF0,0xA3,0xEF,0xF0,0xEE,0x54,
+0xEF,0x90,0x06,0x2D,0xF0,0xFC,0xA3,0xEF,
+0xF0,0xFD,0x7F,0x10,0x7E,0x13,0x02,0x07,
+0xA5,0x78,0x7F,0xE4,0xF6,0xD8,0xFD,0x75,
+0x81,0x3C,0x02,0x05,0xD0,0x02,0x03,0x2F,
+0xE4,0x93,0xA3,0xF8,0xE4,0x93,0xA3,0x40,
+0x03,0xF6,0x80,0x01,0xF2,0x08,0xDF,0xF4,
+0x80,0x29,0xE4,0x93,0xA3,0xF8,0x54,0x07,
+0x24,0x0C,0xC8,0xC3,0x33,0xC4,0x54,0x0F,
+0x44,0x20,0xC8,0x83,0x40,0x04,0xF4,0x56,
+0x80,0x01,0x46,0xF6,0xDF,0xE4,0x80,0x0B,
+0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,
+0x90,0x07,0xE1,0xE4,0x7E,0x01,0x93,0x60,
+0xBC,0xA3,0xFF,0x54,0x3F,0x30,0xE5,0x09,
+0x54,0x1F,0xFE,0xE4,0x93,0xA3,0x60,0x01,
+0x0E,0xCF,0x54,0xC0,0x25,0xE0,0x60,0xA8,
+0x40,0xB8,0xE4,0x93,0xA3,0xFA,0xE4,0x93,
+0xA3,0xF8,0xE4,0x93,0xA3,0xC8,0xC5,0x82,
+0xC8,0xCA,0xC5,0x83,0xCA,0xF0,0xA3,0xC8,
+0xC5,0x82,0xC8,0xCA,0xC5,0x83,0xCA,0xDF,
+0xE9,0xDE,0xE7,0x80,0xBE,0x7D,0x40,0x7C,
+0x17,0x7F,0x11,0x7E,0x1D,0x12,0x07,0xA5,
+0x7F,0x41,0x7E,0x1D,0x12,0x07,0x60,0xEF,
+0x44,0x20,0x44,0x80,0xFD,0xAC,0x06,0x7F,
+0x41,0x7E,0x1D,0x12,0x07,0xA5,0x7D,0xBB,
+0x7C,0x15,0x7F,0xEB,0x7E,0x13,0x12,0x07,
+0xA5,0x7D,0x07,0x7C,0x00,0x7F,0xE7,0x7E,
+0x13,0x12,0x07,0xA5,0x7D,0x40,0x7C,0x11,
+0x7F,0x00,0x7E,0x62,0x12,0x07,0xA5,0x02,
+0x02,0x2F,0x7D,0xC0,0x7C,0x16,0x7F,0x11,
+0x7E,0x1D,0x12,0x07,0xA5,0x7D,0xBB,0x7C,
+0x15,0x7F,0xEB,0x7E,0x13,0x12,0x07,0xA5,
+0x7D,0x0D,0x7C,0x00,0x7F,0xE7,0x7E,0x13,
+0x12,0x07,0xA5,0x7F,0x41,0x7E,0x1D,0x12,
+0x07,0x60,0xEF,0x44,0x20,0x44,0x80,0xFD,
+0xAC,0x06,0x7F,0x41,0x7E,0x1D,0x12,0x07,
+0xA5,0x7D,0x00,0x7C,0x21,0x7F,0x00,0x7E,
+0x62,0x12,0x07,0xA5,0x02,0x02,0x2F,0x7D,
+0x40,0x7C,0x17,0x7F,0x11,0x7E,0x1D,0x12,
+0x07,0xA5,0x7D,0xBB,0x7C,0x15,0x7F,0xEB,
+0x7E,0x13,0x12,0x07,0xA5,0x7D,0x0C,0x7C,
+0x00,0x7F,0xE7,0x7E,0x13,0x12,0x07,0xA5,
+0x7F,0x41,0x7E,0x1D,0x12,0x07,0x60,0xEF,
+0x44,0x20,0x44,0x80,0xFD,0xAC,0x06,0x7F,
+0x41,0x7E,0x1D,0x12,0x07,0xA5,0x7D,0x40,
+0x7C,0x11,0x7F,0x00,0x7E,0x62,0x12,0x07,
+0xA5,0x02,0x02,0x2F,0x7D,0x04,0x7C,0x00,
+0x7F,0x01,0x7E,0x66,0x12,0x07,0xA5,0x7D,
+0x80,0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,
+0x07,0xA5,0x7F,0x02,0x7E,0x66,0x12,0x07,
+0x60,0xEF,0x44,0x02,0x44,0x04,0xFD,0xAC,
+0x06,0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5,
+0x7D,0x04,0x7C,0x00,0x7F,0x01,0x7E,0x66,
+0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F,
+0x00,0x7E,0x66,0x02,0x07,0xA5,0xC0,0xE0,
+0xC0,0xF0,0xC0,0x83,0xC0,0x82,0xC0,0xD0,
+0x75,0xD0,0x00,0xC0,0x00,0x78,0x17,0xE6,
+0xF5,0x8C,0x78,0x18,0xE6,0xF5,0x8A,0x90,
+0x06,0x31,0xE4,0x75,0xF0,0x01,0x12,0x00,
+0x0E,0x90,0x06,0x33,0xE4,0x75,0xF0,0x01,
+0x12,0x00,0x0E,0xD0,0x00,0xD0,0xD0,0xD0,
+0x82,0xD0,0x83,0xD0,0xF0,0xD0,0xE0,0x32,
+0xC2,0xAF,0xAD,0x07,0xAC,0x06,0x8C,0xA2,
+0x8D,0xA3,0x75,0xA0,0x01,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0xAE,0xA1,0xBE,0x00,0xF0,0xAE,0xA6,0xAF,
+0xA7,0xD2,0xAF,0x22,0x7D,0x20,0x7C,0x0F,
+0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5,0x7D,
+0x01,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12,
+0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F,0x00,
+0x7E,0x66,0x02,0x07,0xA5,0xC2,0xAF,0xAB,
+0x07,0xAA,0x06,0x8A,0xA2,0x8B,0xA3,0x8C,
+0xA4,0x8D,0xA5,0x75,0xA0,0x03,0x00,0x00,
+0x00,0xAA,0xA1,0xBA,0x00,0xF8,0xD2,0xAF,
+0x22,0x7F,0x0C,0x7E,0x13,0x12,0x07,0x60,
+0xEF,0x44,0x50,0xFD,0xAC,0x06,0x7F,0x0C,
+0x7E,0x13,0x02,0x07,0xA5,0x12,0x07,0xC1,
+0x12,0x07,0xEC,0x12,0x04,0x25,0x02,0x00,
+0x03,0x42,0x06,0x33,0x00,0x00,0x42,0x06,
+0x31,0x00,0x00,0x00,0xE4,0xF5,0x8E,0x22,};
+
+#define FIBER2_100M_INIT_SIZE 2032
+rtk_uint8 Fiber2_100M[FIBER2_100M_INIT_SIZE] = {
+0x02,0x05,0x89,0xE4,0xF5,0xA8,0xD2,0xAF,
+0x22,0x00,0x00,0x02,0x07,0x26,0xC5,0xF0,
+0xF8,0xA3,0xE0,0x28,0xF0,0xC5,0xF0,0xF8,
+0xE5,0x82,0x15,0x82,0x70,0x02,0x15,0x83,
+0xE0,0x38,0xF0,0x22,0x75,0xF0,0x08,0x75,
+0x82,0x00,0xEF,0x2F,0xFF,0xEE,0x33,0xFE,
+0xCD,0x33,0xCD,0xCC,0x33,0xCC,0xC5,0x82,
+0x33,0xC5,0x82,0x9B,0xED,0x9A,0xEC,0x99,
+0xE5,0x82,0x98,0x40,0x0C,0xF5,0x82,0xEE,
+0x9B,0xFE,0xED,0x9A,0xFD,0xEC,0x99,0xFC,
+0x0F,0xD5,0xF0,0xD6,0xE4,0xCE,0xFB,0xE4,
+0xCD,0xFA,0xE4,0xCC,0xF9,0xA8,0x82,0x22,
+0xB8,0x00,0xC1,0xB9,0x00,0x59,0xBA,0x00,
+0x2D,0xEC,0x8B,0xF0,0x84,0xCF,0xCE,0xCD,
+0xFC,0xE5,0xF0,0xCB,0xF9,0x78,0x18,0xEF,
+0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33,0xFD,
+0xEC,0x33,0xFC,0xEB,0x33,0xFB,0x10,0xD7,
+0x03,0x99,0x40,0x04,0xEB,0x99,0xFB,0x0F,
+0xD8,0xE5,0xE4,0xF9,0xFA,0x22,0x78,0x18,
+0xEF,0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33,
+0xFD,0xEC,0x33,0xFC,0xC9,0x33,0xC9,0x10,
+0xD7,0x05,0x9B,0xE9,0x9A,0x40,0x07,0xEC,
+0x9B,0xFC,0xE9,0x9A,0xF9,0x0F,0xD8,0xE0,
+0xE4,0xC9,0xFA,0xE4,0xCC,0xFB,0x22,0x75,
+0xF0,0x10,0xEF,0x2F,0xFF,0xEE,0x33,0xFE,
+0xED,0x33,0xFD,0xCC,0x33,0xCC,0xC8,0x33,
+0xC8,0x10,0xD7,0x07,0x9B,0xEC,0x9A,0xE8,
+0x99,0x40,0x0A,0xED,0x9B,0xFD,0xEC,0x9A,
+0xFC,0xE8,0x99,0xF8,0x0F,0xD5,0xF0,0xDA,
+0xE4,0xCD,0xFB,0xE4,0xCC,0xFA,0xE4,0xC8,
+0xF9,0x22,0xEB,0x9F,0xF5,0xF0,0xEA,0x9E,
+0x42,0xF0,0xE9,0x9D,0x42,0xF0,0xE8,0x9C,
+0x45,0xF0,0x22,0xE0,0xFC,0xA3,0xE0,0xFD,
+0xA3,0xE0,0xFE,0xA3,0xE0,0xFF,0x22,0xE0,
+0xF8,0xA3,0xE0,0xF9,0xA3,0xE0,0xFA,0xA3,
+0xE0,0xFB,0x22,0xEC,0xF0,0xA3,0xED,0xF0,
+0xA3,0xEE,0xF0,0xA3,0xEF,0xF0,0x22,0x7D,
+0xD7,0x7C,0x04,0x7F,0x02,0x7E,0x66,0x12,
+0x07,0xA5,0x7D,0x80,0x7C,0x04,0x7F,0x01,
+0x7E,0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,
+0x00,0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,
+0x7D,0x94,0x7C,0xF9,0x7F,0x02,0x7E,0x66,
+0x12,0x07,0xA5,0x7D,0x81,0x7C,0x04,0x7F,
+0x01,0x7E,0x66,0x12,0x07,0xA5,0x7D,0xC0,
+0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,0x07,
+0xA5,0x7D,0xA2,0x7C,0x31,0x7F,0x02,0x7E,
+0x66,0x12,0x07,0xA5,0x7D,0x82,0x7C,0x04,
+0x7F,0x01,0x7E,0x66,0x12,0x07,0xA5,0x7D,
+0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,
+0x07,0xA5,0x7D,0x60,0x7C,0x69,0x7F,0x02,
+0x7E,0x66,0x12,0x07,0xA5,0x7D,0x83,0x7C,
+0x04,0x7F,0x01,0x7E,0x66,0x12,0x07,0xA5,
+0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66,
+0x12,0x07,0xA5,0x7D,0x28,0x7C,0x97,0x7F,
+0x02,0x7E,0x66,0x12,0x07,0xA5,0x7D,0x84,
+0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12,0x07,
+0xA5,0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E,
+0x66,0x12,0x07,0xA5,0x7D,0x85,0x7C,0x9D,
+0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5,0x7D,
+0x23,0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12,
+0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F,0x00,
+0x7E,0x66,0x12,0x07,0xA5,0x7D,0x10,0x7C,
+0xD8,0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5,
+0x7D,0x24,0x7C,0x04,0x7F,0x01,0x7E,0x66,
+0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F,
+0x00,0x7E,0x66,0x12,0x07,0xA5,0x7D,0x00,
+0x7C,0x04,0x7F,0x02,0x7E,0x66,0x12,0x07,
+0xA5,0x7D,0x2F,0x7C,0x00,0x7F,0x01,0x7E,
+0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x02,0x07,0xA5,0x7D,
+0x03,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12,
+0x07,0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00,
+0x7E,0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E,
+0x66,0x12,0x07,0x60,0xEF,0x44,0x40,0xFD,
+0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,0x07,
+0xA5,0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E,
+0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0x7D,
+0x03,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12,
+0x07,0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00,
+0x7E,0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E,
+0x66,0x12,0x07,0x60,0xEF,0x54,0xBF,0xFD,
+0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,0x07,
+0xA5,0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E,
+0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0xE4,
+0xFD,0xFC,0x7F,0x01,0x7E,0x66,0x12,0x07,
+0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00,0x7E,
+0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E,0x66,
+0x12,0x07,0x60,0xEF,0x54,0xFD,0x54,0xFE,
+0xFD,0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,
+0x07,0xA5,0xE4,0xFD,0xFC,0x7F,0x01,0x7E,
+0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0xE4,
+0xFD,0xFC,0x7F,0x01,0x7E,0x66,0x12,0x07,
+0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00,0x7E,
+0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E,0x66,
+0x12,0x07,0x60,0xEF,0x44,0x02,0x44,0x01,
+0xFD,0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,
+0x07,0xA5,0xE4,0xFD,0xFC,0x7F,0x01,0x7E,
+0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x02,0x07,0xA5,0xE4,
+0x90,0x06,0x2C,0xF0,0xFD,0x7C,0x01,0x7F,
+0x3F,0x7E,0x1D,0x12,0x07,0xA5,0x7D,0x40,
+0x7C,0x00,0x7F,0x36,0x7E,0x13,0x12,0x07,
+0xA5,0xE4,0xFF,0xFE,0xFD,0x80,0x25,0xE4,
+0x7F,0xFF,0x7E,0xFF,0xFD,0xFC,0x90,0x06,
+0x24,0x12,0x01,0x0F,0xC3,0x12,0x00,0xF2,
+0x50,0x1B,0x90,0x06,0x24,0x12,0x01,0x03,
+0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE,0xE4,
+0x3D,0xFD,0xE4,0x3C,0xFC,0x90,0x06,0x24,
+0x12,0x01,0x1B,0x80,0xD2,0xE4,0xF5,0xA8,
+0xD2,0xAF,0x7D,0x1F,0xFC,0x7F,0x49,0x7E,
+0x13,0x12,0x07,0xA5,0x12,0x07,0xD5,0x12,
+0x01,0x27,0x12,0x06,0x5A,0x7D,0x41,0x7C,
+0x00,0x7F,0x36,0x7E,0x13,0x12,0x07,0xA5,
+0xE4,0xFF,0xFE,0xFD,0x80,0x26,0x7F,0xFF,
+0x7E,0xFF,0x7D,0x05,0x7C,0x00,0x90,0x06,
+0x24,0x12,0x01,0x0F,0xC3,0x12,0x00,0xF2,
+0x50,0x1B,0x90,0x06,0x24,0x12,0x01,0x03,
+0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE,0xE4,
+0x3D,0xFD,0xE4,0x3C,0xFC,0x90,0x06,0x24,
+0x12,0x01,0x1B,0x80,0xD1,0xC2,0x00,0xC2,
+0x01,0xD2,0xA9,0xD2,0x8C,0x7F,0x01,0x7E,
+0x62,0x12,0x07,0x60,0xEF,0x30,0xE2,0x07,
+0xE4,0x90,0x06,0x2C,0xF0,0x80,0xEE,0x90,
+0x06,0x2C,0xE0,0x70,0x12,0x12,0x04,0xEA,
+0x90,0x06,0x2C,0x74,0x01,0xF0,0xE4,0x90,
+0x06,0x33,0xF0,0xA3,0xF0,0x80,0xD6,0xC3,
+0x90,0x06,0x34,0xE0,0x94,0x62,0x90,0x06,
+0x33,0xE0,0x94,0x00,0x40,0xC7,0xE4,0xF0,
+0xA3,0xF0,0x12,0x04,0xEA,0x90,0x06,0x2C,
+0x74,0x01,0xF0,0x80,0xB8,0x75,0x0F,0x80,
+0x75,0x0E,0x7E,0x75,0x0D,0xAA,0x75,0x0C,
+0x83,0xE4,0xF5,0x10,0x7F,0x36,0x7E,0x13,
+0x12,0x07,0x60,0xEE,0xC4,0xF8,0x54,0xF0,
+0xC8,0xEF,0xC4,0x54,0x0F,0x48,0x54,0x07,
+0xFB,0x7A,0x00,0xEA,0x70,0x4A,0xEB,0x14,
+0x60,0x1C,0x14,0x60,0x27,0x24,0xFE,0x60,
+0x31,0x14,0x60,0x3C,0x24,0x05,0x70,0x38,
+0x75,0x0B,0x00,0x75,0x0A,0xC2,0x75,0x09,
+0xEB,0x75,0x08,0x0B,0x80,0x36,0x75,0x0B,
+0x40,0x75,0x0A,0x59,0x75,0x09,0x73,0x75,
+0x08,0x07,0x80,0x28,0x75,0x0B,0x00,0x75,
+0x0A,0xE1,0x75,0x09,0xF5,0x75,0x08,0x05,
+0x80,0x1A,0x75,0x0B,0xA0,0x75,0x0A,0xAC,
+0x75,0x09,0xB9,0x75,0x08,0x03,0x80,0x0C,
+0x75,0x0B,0x00,0x75,0x0A,0x62,0x75,0x09,
+0x3D,0x75,0x08,0x01,0x75,0x89,0x11,0xE4,
+0x7B,0x60,0x7A,0x09,0xF9,0xF8,0xAF,0x0B,
+0xAE,0x0A,0xAD,0x09,0xAC,0x08,0x12,0x00,
+0x60,0xAA,0x06,0xAB,0x07,0xC3,0xE4,0x9B,
+0xFB,0xE4,0x9A,0xFA,0x78,0x17,0xF6,0xAF,
+0x03,0xEF,0x08,0xF6,0x18,0xE6,0xF5,0x8C,
+0x08,0xE6,0xF5,0x8A,0x74,0x0D,0x2B,0xFB,
+0xE4,0x3A,0x18,0xF6,0xAF,0x03,0xEF,0x08,
+0xF6,0x75,0x88,0x10,0x53,0x8E,0xC7,0xD2,
+0xA9,0x22,0x7F,0x10,0x7E,0x13,0x12,0x07,
+0x60,0x90,0x06,0x2D,0xEE,0xF0,0xA3,0xEF,
+0xF0,0xEE,0x44,0x10,0xFE,0x90,0x06,0x2D,
+0xF0,0xA3,0xEF,0xF0,0x54,0xEF,0xFF,0x90,
+0x06,0x2D,0xEE,0xF0,0xFC,0xA3,0xEF,0xF0,
+0xFD,0x7F,0x10,0x7E,0x13,0x12,0x07,0xA5,
+0xE4,0xFF,0xFE,0x0F,0xBF,0x00,0x01,0x0E,
+0xEF,0x64,0x64,0x4E,0x70,0xF5,0x7D,0x04,
+0x7C,0x00,0x7F,0x02,0x7E,0x66,0x12,0x07,
+0xA5,0x7D,0x00,0x7C,0x04,0x7F,0x01,0x7E,
+0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0xE4,
+0xFD,0xFC,0x7F,0x02,0x7E,0x66,0x12,0x07,
+0xA5,0x7D,0x00,0x7C,0x04,0x7F,0x01,0x7E,
+0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0x7F,
+0x10,0x7E,0x13,0x12,0x07,0x60,0x90,0x06,
+0x2D,0xEE,0xF0,0xA3,0xEF,0xF0,0xEE,0x54,
+0xEF,0x90,0x06,0x2D,0xF0,0xFC,0xA3,0xEF,
+0xF0,0xFD,0x7F,0x10,0x7E,0x13,0x02,0x07,
+0xA5,0x78,0x7F,0xE4,0xF6,0xD8,0xFD,0x75,
+0x81,0x3C,0x02,0x05,0xD0,0x02,0x03,0x2F,
+0xE4,0x93,0xA3,0xF8,0xE4,0x93,0xA3,0x40,
+0x03,0xF6,0x80,0x01,0xF2,0x08,0xDF,0xF4,
+0x80,0x29,0xE4,0x93,0xA3,0xF8,0x54,0x07,
+0x24,0x0C,0xC8,0xC3,0x33,0xC4,0x54,0x0F,
+0x44,0x20,0xC8,0x83,0x40,0x04,0xF4,0x56,
+0x80,0x01,0x46,0xF6,0xDF,0xE4,0x80,0x0B,
+0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,
+0x90,0x07,0xE1,0xE4,0x7E,0x01,0x93,0x60,
+0xBC,0xA3,0xFF,0x54,0x3F,0x30,0xE5,0x09,
+0x54,0x1F,0xFE,0xE4,0x93,0xA3,0x60,0x01,
+0x0E,0xCF,0x54,0xC0,0x25,0xE0,0x60,0xA8,
+0x40,0xB8,0xE4,0x93,0xA3,0xFA,0xE4,0x93,
+0xA3,0xF8,0xE4,0x93,0xA3,0xC8,0xC5,0x82,
+0xC8,0xCA,0xC5,0x83,0xCA,0xF0,0xA3,0xC8,
+0xC5,0x82,0xC8,0xCA,0xC5,0x83,0xCA,0xDF,
+0xE9,0xDE,0xE7,0x80,0xBE,0x7D,0x40,0x7C,
+0x17,0x7F,0x11,0x7E,0x1D,0x12,0x07,0xA5,
+0x7F,0x41,0x7E,0x1D,0x12,0x07,0x60,0xEF,
+0x44,0x20,0x44,0x80,0xFD,0xAC,0x06,0x7F,
+0x41,0x7E,0x1D,0x12,0x07,0xA5,0x7D,0xBB,
+0x7C,0x15,0x7F,0xEB,0x7E,0x13,0x12,0x07,
+0xA5,0x7D,0x07,0x7C,0x00,0x7F,0xE7,0x7E,
+0x13,0x12,0x07,0xA5,0x7D,0x40,0x7C,0x11,
+0x7F,0x00,0x7E,0x62,0x12,0x07,0xA5,0x02,
+0x02,0x2F,0x7D,0xC0,0x7C,0x16,0x7F,0x11,
+0x7E,0x1D,0x12,0x07,0xA5,0x7D,0xBB,0x7C,
+0x15,0x7F,0xEB,0x7E,0x13,0x12,0x07,0xA5,
+0x7D,0x0D,0x7C,0x00,0x7F,0xE7,0x7E,0x13,
+0x12,0x07,0xA5,0x7F,0x41,0x7E,0x1D,0x12,
+0x07,0x60,0xEF,0x44,0x20,0x44,0x80,0xFD,
+0xAC,0x06,0x7F,0x41,0x7E,0x1D,0x12,0x07,
+0xA5,0x7D,0x00,0x7C,0x21,0x7F,0x00,0x7E,
+0x62,0x12,0x07,0xA5,0x02,0x02,0x2F,0x7D,
+0x40,0x7C,0x17,0x7F,0x11,0x7E,0x1D,0x12,
+0x07,0xA5,0x7D,0xBB,0x7C,0x15,0x7F,0xEB,
+0x7E,0x13,0x12,0x07,0xA5,0x7D,0x0C,0x7C,
+0x00,0x7F,0xE7,0x7E,0x13,0x12,0x07,0xA5,
+0x7F,0x41,0x7E,0x1D,0x12,0x07,0x60,0xEF,
+0x44,0x20,0x44,0x80,0xFD,0xAC,0x06,0x7F,
+0x41,0x7E,0x1D,0x12,0x07,0xA5,0x7D,0x40,
+0x7C,0x11,0x7F,0x00,0x7E,0x62,0x12,0x07,
+0xA5,0x02,0x02,0x2F,0x7D,0x04,0x7C,0x00,
+0x7F,0x01,0x7E,0x66,0x12,0x07,0xA5,0x7D,
+0x80,0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,
+0x07,0xA5,0x7F,0x02,0x7E,0x66,0x12,0x07,
+0x60,0xEF,0x44,0x02,0x44,0x04,0xFD,0xAC,
+0x06,0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5,
+0x7D,0x04,0x7C,0x00,0x7F,0x01,0x7E,0x66,
+0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F,
+0x00,0x7E,0x66,0x02,0x07,0xA5,0xC0,0xE0,
+0xC0,0xF0,0xC0,0x83,0xC0,0x82,0xC0,0xD0,
+0x75,0xD0,0x00,0xC0,0x00,0x78,0x17,0xE6,
+0xF5,0x8C,0x78,0x18,0xE6,0xF5,0x8A,0x90,
+0x06,0x31,0xE4,0x75,0xF0,0x01,0x12,0x00,
+0x0E,0x90,0x06,0x33,0xE4,0x75,0xF0,0x01,
+0x12,0x00,0x0E,0xD0,0x00,0xD0,0xD0,0xD0,
+0x82,0xD0,0x83,0xD0,0xF0,0xD0,0xE0,0x32,
+0xC2,0xAF,0xAD,0x07,0xAC,0x06,0x8C,0xA2,
+0x8D,0xA3,0x75,0xA0,0x01,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0xAE,0xA1,0xBE,0x00,0xF0,0xAE,0xA6,0xAF,
+0xA7,0xD2,0xAF,0x22,0x7D,0x20,0x7C,0x0F,
+0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5,0x7D,
+0x01,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12,
+0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F,0x00,
+0x7E,0x66,0x02,0x07,0xA5,0xC2,0xAF,0xAB,
+0x07,0xAA,0x06,0x8A,0xA2,0x8B,0xA3,0x8C,
+0xA4,0x8D,0xA5,0x75,0xA0,0x03,0x00,0x00,
+0x00,0xAA,0xA1,0xBA,0x00,0xF8,0xD2,0xAF,
+0x22,0x7F,0x0C,0x7E,0x13,0x12,0x07,0x60,
+0xEF,0x44,0x50,0xFD,0xAC,0x06,0x7F,0x0C,
+0x7E,0x13,0x02,0x07,0xA5,0x12,0x07,0xC1,
+0x12,0x07,0xEC,0x12,0x04,0x25,0x02,0x00,
+0x03,0x42,0x06,0x33,0x00,0x00,0x42,0x06,
+0x31,0x00,0x00,0x00,0xE4,0xF5,0x8E,0x22,};
+
+
+#define SGMII_INIT_SIZE 1183
+rtk_uint8 Sgmii_Init[SGMII_INIT_SIZE] = {
+0x02,0x03,0x81,0xE4,0xF5,0xA8,0xD2,0xAF,
+0x22,0x00,0x00,0x02,0x04,0x0D,0xC5,0xF0,
+0xF8,0xA3,0xE0,0x28,0xF0,0xC5,0xF0,0xF8,
+0xE5,0x82,0x15,0x82,0x70,0x02,0x15,0x83,
+0xE0,0x38,0xF0,0x22,0x75,0xF0,0x08,0x75,
+0x82,0x00,0xEF,0x2F,0xFF,0xEE,0x33,0xFE,
+0xCD,0x33,0xCD,0xCC,0x33,0xCC,0xC5,0x82,
+0x33,0xC5,0x82,0x9B,0xED,0x9A,0xEC,0x99,
+0xE5,0x82,0x98,0x40,0x0C,0xF5,0x82,0xEE,
+0x9B,0xFE,0xED,0x9A,0xFD,0xEC,0x99,0xFC,
+0x0F,0xD5,0xF0,0xD6,0xE4,0xCE,0xFB,0xE4,
+0xCD,0xFA,0xE4,0xCC,0xF9,0xA8,0x82,0x22,
+0xB8,0x00,0xC1,0xB9,0x00,0x59,0xBA,0x00,
+0x2D,0xEC,0x8B,0xF0,0x84,0xCF,0xCE,0xCD,
+0xFC,0xE5,0xF0,0xCB,0xF9,0x78,0x18,0xEF,
+0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33,0xFD,
+0xEC,0x33,0xFC,0xEB,0x33,0xFB,0x10,0xD7,
+0x03,0x99,0x40,0x04,0xEB,0x99,0xFB,0x0F,
+0xD8,0xE5,0xE4,0xF9,0xFA,0x22,0x78,0x18,
+0xEF,0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33,
+0xFD,0xEC,0x33,0xFC,0xC9,0x33,0xC9,0x10,
+0xD7,0x05,0x9B,0xE9,0x9A,0x40,0x07,0xEC,
+0x9B,0xFC,0xE9,0x9A,0xF9,0x0F,0xD8,0xE0,
+0xE4,0xC9,0xFA,0xE4,0xCC,0xFB,0x22,0x75,
+0xF0,0x10,0xEF,0x2F,0xFF,0xEE,0x33,0xFE,
+0xED,0x33,0xFD,0xCC,0x33,0xCC,0xC8,0x33,
+0xC8,0x10,0xD7,0x07,0x9B,0xEC,0x9A,0xE8,
+0x99,0x40,0x0A,0xED,0x9B,0xFD,0xEC,0x9A,
+0xFC,0xE8,0x99,0xF8,0x0F,0xD5,0xF0,0xDA,
+0xE4,0xCD,0xFB,0xE4,0xCC,0xFA,0xE4,0xC8,
+0xF9,0x22,0xEB,0x9F,0xF5,0xF0,0xEA,0x9E,
+0x42,0xF0,0xE9,0x9D,0x42,0xF0,0xE8,0x9C,
+0x45,0xF0,0x22,0xE0,0xFC,0xA3,0xE0,0xFD,
+0xA3,0xE0,0xFE,0xA3,0xE0,0xFF,0x22,0xE0,
+0xF8,0xA3,0xE0,0xF9,0xA3,0xE0,0xFA,0xA3,
+0xE0,0xFB,0x22,0xEC,0xF0,0xA3,0xED,0xF0,
+0xA3,0xEE,0xF0,0xA3,0xEF,0xF0,0x22,0xE4,
+0x90,0x06,0x2C,0xF0,0xFD,0x7C,0x01,0x7F,
+0x3F,0x7E,0x1D,0x12,0x04,0x6B,0x7D,0x40,
+0x7C,0x00,0x7F,0x36,0x7E,0x13,0x12,0x04,
+0x6B,0xE4,0xFF,0xFE,0xFD,0x80,0x25,0xE4,
+0x7F,0xFF,0x7E,0xFF,0xFD,0xFC,0x90,0x06,
+0x24,0x12,0x01,0x0F,0xC3,0x12,0x00,0xF2,
+0x50,0x1B,0x90,0x06,0x24,0x12,0x01,0x03,
+0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE,0xE4,
+0x3D,0xFD,0xE4,0x3C,0xFC,0x90,0x06,0x24,
+0x12,0x01,0x1B,0x80,0xD2,0xE4,0xF5,0xA8,
+0xD2,0xAF,0x7D,0x1F,0xFC,0x7F,0x49,0x7E,
+0x13,0x12,0x04,0x6B,0x12,0x04,0x92,0x7D,
+0x41,0x7C,0x00,0x7F,0x36,0x7E,0x13,0x12,
+0x04,0x6B,0xE4,0xFF,0xFE,0xFD,0x80,0x25,
+0xE4,0x7F,0x20,0x7E,0x4E,0xFD,0xFC,0x90,
+0x06,0x24,0x12,0x01,0x0F,0xC3,0x12,0x00,
+0xF2,0x50,0x1B,0x90,0x06,0x24,0x12,0x01,
+0x03,0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE,
+0xE4,0x3D,0xFD,0xE4,0x3C,0xFC,0x90,0x06,
+0x24,0x12,0x01,0x1B,0x80,0xD2,0xC2,0x00,
+0xC2,0x01,0xD2,0xA9,0xD2,0x8C,0x7F,0x01,
+0x7E,0x62,0x12,0x04,0x47,0xEF,0x30,0xE2,
+0x07,0xE4,0x90,0x06,0x2C,0xF0,0x80,0xEE,
+0x90,0x06,0x2C,0xE0,0x70,0x12,0x12,0x02,
+0xDB,0x90,0x06,0x2C,0x74,0x01,0xF0,0xE4,
+0x90,0x06,0x2F,0xF0,0xA3,0xF0,0x80,0xD6,
+0xC3,0x90,0x06,0x30,0xE0,0x94,0x62,0x90,
+0x06,0x2F,0xE0,0x94,0x00,0x40,0xC7,0xE4,
+0xF0,0xA3,0xF0,0x12,0x02,0xDB,0x90,0x06,
+0x2C,0x74,0x01,0xF0,0x80,0xB8,0x75,0x0F,
+0x80,0x75,0x0E,0x7E,0x75,0x0D,0xAA,0x75,
+0x0C,0x83,0xE4,0xF5,0x10,0x7F,0x36,0x7E,
+0x13,0x12,0x04,0x47,0xEE,0xC4,0xF8,0x54,
+0xF0,0xC8,0xEF,0xC4,0x54,0x0F,0x48,0x54,
+0x07,0xFB,0x7A,0x00,0xEA,0x70,0x4A,0xEB,
+0x14,0x60,0x1C,0x14,0x60,0x27,0x24,0xFE,
+0x60,0x31,0x14,0x60,0x3C,0x24,0x05,0x70,
+0x38,0x75,0x0B,0x00,0x75,0x0A,0xC2,0x75,
+0x09,0xEB,0x75,0x08,0x0B,0x80,0x36,0x75,
+0x0B,0x40,0x75,0x0A,0x59,0x75,0x09,0x73,
+0x75,0x08,0x07,0x80,0x28,0x75,0x0B,0x00,
+0x75,0x0A,0xE1,0x75,0x09,0xF5,0x75,0x08,
+0x05,0x80,0x1A,0x75,0x0B,0xA0,0x75,0x0A,
+0xAC,0x75,0x09,0xB9,0x75,0x08,0x03,0x80,
+0x0C,0x75,0x0B,0x00,0x75,0x0A,0x62,0x75,
+0x09,0x3D,0x75,0x08,0x01,0x75,0x89,0x11,
+0xE4,0x7B,0x60,0x7A,0x09,0xF9,0xF8,0xAF,
+0x0B,0xAE,0x0A,0xAD,0x09,0xAC,0x08,0x12,
+0x00,0x60,0xAA,0x06,0xAB,0x07,0xC3,0xE4,
+0x9B,0xFB,0xE4,0x9A,0xFA,0x78,0x17,0xF6,
+0xAF,0x03,0xEF,0x08,0xF6,0x18,0xE6,0xF5,
+0x8C,0x08,0xE6,0xF5,0x8A,0x74,0x0D,0x2B,
+0xFB,0xE4,0x3A,0x18,0xF6,0xAF,0x03,0xEF,
+0x08,0xF6,0x75,0x88,0x10,0x53,0x8E,0xC7,
+0xD2,0xA9,0x22,0x7D,0x02,0x7C,0x00,0x7F,
+0x4A,0x7E,0x13,0x12,0x04,0x6B,0x7D,0x46,
+0x7C,0x71,0x7F,0x02,0x7E,0x66,0x12,0x04,
+0x6B,0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E,
+0x66,0x12,0x04,0x6B,0x7D,0xC0,0x7C,0x00,
+0x7F,0x00,0x7E,0x66,0x12,0x04,0x6B,0xE4,
+0xFF,0xFE,0x0F,0xBF,0x00,0x01,0x0E,0xEF,
+0x64,0x64,0x4E,0x70,0xF5,0x7D,0x04,0x7C,
+0x00,0x7F,0x02,0x7E,0x66,0x12,0x04,0x6B,
+0x7D,0x00,0x7C,0x04,0x7F,0x01,0x7E,0x66,
+0x12,0x04,0x6B,0x7D,0xC0,0x7C,0x00,0x7F,
+0x00,0x7E,0x66,0x12,0x04,0x6B,0xE4,0xFD,
+0xFC,0x7F,0x02,0x7E,0x66,0x12,0x04,0x6B,
+0x7D,0x00,0x7C,0x04,0x7F,0x01,0x7E,0x66,
+0x12,0x04,0x6B,0x7D,0xC0,0x7C,0x00,0x7F,
+0x00,0x7E,0x66,0x12,0x04,0x6B,0xE4,0xFD,
+0xFC,0x7F,0x4A,0x7E,0x13,0x12,0x04,0x6B,
+0x7D,0x06,0x7C,0x71,0x7F,0x02,0x7E,0x66,
+0x12,0x04,0x6B,0x7D,0x03,0x7C,0x00,0x7F,
+0x01,0x7E,0x66,0x12,0x04,0x6B,0x7D,0xC0,
+0x7C,0x00,0x7F,0x00,0x7E,0x66,0x02,0x04,
+0x6B,0x78,0x7F,0xE4,0xF6,0xD8,0xFD,0x75,
+0x81,0x3C,0x02,0x03,0xC8,0x02,0x01,0x27,
+0xE4,0x93,0xA3,0xF8,0xE4,0x93,0xA3,0x40,
+0x03,0xF6,0x80,0x01,0xF2,0x08,0xDF,0xF4,
+0x80,0x29,0xE4,0x93,0xA3,0xF8,0x54,0x07,
+0x24,0x0C,0xC8,0xC3,0x33,0xC4,0x54,0x0F,
+0x44,0x20,0xC8,0x83,0x40,0x04,0xF4,0x56,
+0x80,0x01,0x46,0xF6,0xDF,0xE4,0x80,0x0B,
+0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,
+0x90,0x04,0x87,0xE4,0x7E,0x01,0x93,0x60,
+0xBC,0xA3,0xFF,0x54,0x3F,0x30,0xE5,0x09,
+0x54,0x1F,0xFE,0xE4,0x93,0xA3,0x60,0x01,
+0x0E,0xCF,0x54,0xC0,0x25,0xE0,0x60,0xA8,
+0x40,0xB8,0xE4,0x93,0xA3,0xFA,0xE4,0x93,
+0xA3,0xF8,0xE4,0x93,0xA3,0xC8,0xC5,0x82,
+0xC8,0xCA,0xC5,0x83,0xCA,0xF0,0xA3,0xC8,
+0xC5,0x82,0xC8,0xCA,0xC5,0x83,0xCA,0xDF,
+0xE9,0xDE,0xE7,0x80,0xBE,0xC0,0xE0,0xC0,
+0xF0,0xC0,0x83,0xC0,0x82,0xC0,0xD0,0x75,
+0xD0,0x00,0xC0,0x00,0x78,0x17,0xE6,0xF5,
+0x8C,0x78,0x18,0xE6,0xF5,0x8A,0x90,0x06,
+0x2D,0xE4,0x75,0xF0,0x01,0x12,0x00,0x0E,
+0x90,0x06,0x2F,0xE4,0x75,0xF0,0x01,0x12,
+0x00,0x0E,0xD0,0x00,0xD0,0xD0,0xD0,0x82,
+0xD0,0x83,0xD0,0xF0,0xD0,0xE0,0x32,0xC2,
+0xAF,0xAD,0x07,0xAC,0x06,0x8C,0xA2,0x8D,
+0xA3,0x75,0xA0,0x01,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAE,
+0xA1,0xBE,0x00,0xF0,0xAE,0xA6,0xAF,0xA7,
+0xD2,0xAF,0x22,0xC2,0xAF,0xAB,0x07,0xAA,
+0x06,0x8A,0xA2,0x8B,0xA3,0x8C,0xA4,0x8D,
+0xA5,0x75,0xA0,0x03,0x00,0x00,0x00,0xAA,
+0xA1,0xBA,0x00,0xF8,0xD2,0xAF,0x22,0x42,
+0x06,0x2F,0x00,0x00,0x42,0x06,0x2D,0x00,
+0x00,0x00,0x12,0x04,0x9B,0x12,0x02,0x16,
+0x02,0x00,0x03,0xE4,0xF5,0x8E,0x22,};
+
+
+/* Function Name:
+ *      rtl8367c_setAsicPortUnknownDaBehavior
+ * Description:
+ *      Set UNDA behavior
+ * Input:
+ *      port        - port ID
+ *      behavior    - 0: flooding to unknwon DA portmask; 1: drop; 2:trap; 3: flooding
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_NOT_ALLOWED  - Invalid behavior
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortUnknownDaBehavior(rtk_uint32 port, rtk_uint32 behavior)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if(behavior >= L2_UNDA_BEHAVE_END)
+        return RT_ERR_NOT_ALLOWED;
+
+    if(port < 8)
+        return rtl8367c_setAsicRegBits(RTL8367C_REG_UNKNOWN_UNICAST_DA_PORT_BEHAVE, RTL8367C_Port0_ACTION_MASK << (port * 2), behavior);
+    else
+        return rtl8367c_setAsicRegBits(RTL8367C_REG_UNKNOWN_UNICAST_DA_PORT_BEHAVE_EXT, RTL8367C_PORT8_ACTION_MASK << ((port-8) * 2), behavior);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortUnknownDaBehavior
+ * Description:
+ *      Get UNDA behavior
+ * Input:
+ *      port        - port ID
+ * Output:
+ *      pBehavior   - 0: flooding to unknwon DA portmask; 1: drop; 2:trap; 3: flooding
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortUnknownDaBehavior(rtk_uint32 port, rtk_uint32 *pBehavior)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if(port < 8)
+        return rtl8367c_getAsicRegBits(RTL8367C_REG_UNKNOWN_UNICAST_DA_PORT_BEHAVE, RTL8367C_Port0_ACTION_MASK << (port * 2), pBehavior);
+    else
+        return rtl8367c_getAsicRegBits(RTL8367C_REG_UNKNOWN_UNICAST_DA_PORT_BEHAVE_EXT, RTL8367C_PORT8_ACTION_MASK << ((port-8) * 2), pBehavior);
+}
+/* Function Name:
+ *      rtl8367c_setAsicPortUnknownSaBehavior
+ * Description:
+ *      Set UNSA behavior
+ * Input:
+ *      behavior    - 0: flooding; 1: drop; 2:trap
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_NOT_ALLOWED  - Invalid behavior
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortUnknownSaBehavior(rtk_uint32 behavior)
+{
+    if(behavior >= L2_BEHAVE_SA_END)
+        return RT_ERR_NOT_ALLOWED;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_PORT_SECURIT_CTRL_REG, RTL8367C_UNKNOWN_SA_BEHAVE_MASK, behavior);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortUnknownSaBehavior
+ * Description:
+ *      Get UNSA behavior
+ * Input:
+ *      pBehavior   - 0: flooding; 1: drop; 2:trap
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortUnknownSaBehavior(rtk_uint32 *pBehavior)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_PORT_SECURIT_CTRL_REG, RTL8367C_UNKNOWN_SA_BEHAVE_MASK, pBehavior);
+}
+/* Function Name:
+ *      rtl8367c_setAsicPortUnmatchedSaBehavior
+ * Description:
+ *      Set Unmatched SA behavior
+ * Input:
+ *      behavior    - 0: flooding; 1: drop; 2:trap
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_NOT_ALLOWED  - Invalid behavior
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortUnmatchedSaBehavior(rtk_uint32 behavior)
+{
+    if(behavior >= L2_BEHAVE_SA_END)
+        return RT_ERR_NOT_ALLOWED;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_PORT_SECURIT_CTRL_REG, RTL8367C_UNMATCHED_SA_BEHAVE_MASK, behavior);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortUnmatchedSaBehavior
+ * Description:
+ *      Get Unmatched SA behavior
+ * Input:
+ *      pBehavior   - 0: flooding; 1: drop; 2:trap
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortUnmatchedSaBehavior(rtk_uint32 *pBehavior)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_PORT_SECURIT_CTRL_REG, RTL8367C_UNMATCHED_SA_BEHAVE_MASK, pBehavior);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicPortUnmatchedSaMoving
+ * Description:
+ *      Set Unmatched SA moving state
+ * Input:
+ *      port        - Port ID
+ *      enabled     - 0: can't move to new port; 1: can move to new port
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Error Port ID
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortUnmatchedSaMoving(rtk_uint32 port, rtk_uint32 enabled)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_L2_SA_MOVING_FORBID, port, (enabled == 1) ? 0 : 1);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicPortUnmatchedSaMoving
+ * Description:
+ *      Get Unmatched SA moving state
+ * Input:
+ *      port        - Port ID
+ * Output:
+ *      pEnabled    - 0: can't move to new port; 1: can move to new port
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Error Port ID
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortUnmatchedSaMoving(rtk_uint32 port, rtk_uint32 *pEnabled)
+{
+    rtk_uint32 data;
+    ret_t retVal;
+
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_L2_SA_MOVING_FORBID, port, &data)) != RT_ERR_OK)
+        return retVal;
+
+    *pEnabled = (data == 1) ? 0 : 1;
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicPortUnknownDaFloodingPortmask
+ * Description:
+ *      Set UNDA flooding portmask
+ * Input:
+ *      portmask    - portmask(0~0xFF)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK    - Invalid portmask
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortUnknownDaFloodingPortmask(rtk_uint32 portmask)
+{
+    if(portmask > RTL8367C_PORTMASK)
+        return RT_ERR_PORT_MASK;
+
+    return rtl8367c_setAsicReg(RTL8367C_UNUCAST_FLOADING_PMSK_REG, portmask);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortUnknownDaFloodingPortmask
+ * Description:
+ *      Get UNDA flooding portmask
+ * Input:
+ *      pPortmask   - portmask(0~0xFF)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortUnknownDaFloodingPortmask(rtk_uint32 *pPortmask)
+{
+    return rtl8367c_getAsicReg(RTL8367C_UNUCAST_FLOADING_PMSK_REG, pPortmask);
+}
+/* Function Name:
+ *      rtl8367c_setAsicPortUnknownMulticastFloodingPortmask
+ * Description:
+ *      Set UNMC flooding portmask
+ * Input:
+ *      portmask    - portmask(0~0xFF)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK    - Invalid portmask
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortUnknownMulticastFloodingPortmask(rtk_uint32 portmask)
+{
+    if(portmask > RTL8367C_PORTMASK)
+        return RT_ERR_PORT_MASK;
+
+    return rtl8367c_setAsicReg(RTL8367C_UNMCAST_FLOADING_PMSK_REG, portmask);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortUnknownMulticastFloodingPortmask
+ * Description:
+ *      Get UNMC flooding portmask
+ * Input:
+ *      pPortmask   - portmask(0~0xFF)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortUnknownMulticastFloodingPortmask(rtk_uint32 *pPortmask)
+{
+    return rtl8367c_getAsicReg(RTL8367C_UNMCAST_FLOADING_PMSK_REG, pPortmask);
+}
+/* Function Name:
+ *      rtl8367c_setAsicPortBcastFloodingPortmask
+ * Description:
+ *      Set Bcast flooding portmask
+ * Input:
+ *      portmask    - portmask(0~0xFF)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK    - Invalid portmask
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortBcastFloodingPortmask(rtk_uint32 portmask)
+{
+    if(portmask > RTL8367C_PORTMASK)
+        return RT_ERR_PORT_MASK;
+
+    return rtl8367c_setAsicReg(RTL8367C_BCAST_FLOADING_PMSK_REG, portmask);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortBcastFloodingPortmask
+ * Description:
+ *      Get Bcast flooding portmask
+ * Input:
+ *      pPortmask   - portmask(0~0xFF)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortBcastFloodingPortmask(rtk_uint32 *pPortmask)
+{
+    return rtl8367c_getAsicReg(RTL8367C_BCAST_FLOADING_PMSK_REG, pPortmask);
+}
+/* Function Name:
+ *      rtl8367c_setAsicPortBlockSpa
+ * Description:
+ *      Set disabling blocking frame if source port and destination port are the same
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      permit  - 0: block; 1: permit
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortBlockSpa(rtk_uint32 port, rtk_uint32 permit)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_SOURCE_PORT_BLOCK_REG, port, permit);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortBlockSpa
+ * Description:
+ *      Get disabling blocking frame if source port and destination port are the same
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pPermit     - 0: block; 1: permit
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortBlockSpa(rtk_uint32 port, rtk_uint32* pPermit)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_SOURCE_PORT_BLOCK_REG, port, pPermit);
+}
+/* Function Name:
+ *      rtl8367c_setAsicPortDos
+ * Description:
+ *      Set DOS function
+ * Input:
+ *      type    - DOS type
+ *      drop    - 0: permit; 1: drop
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - Invalid payload index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortDos(rtk_uint32 type, rtk_uint32 drop)
+{
+    if(type >= DOS_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_DOS_CFG, RTL8367C_DROP_DAEQSA_OFFSET + type, drop);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortDos
+ * Description:
+ *      Get DOS function
+ * Input:
+ *      type    - DOS type
+ *      pDrop   - 0: permit; 1: drop
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - Invalid payload index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortDos(rtk_uint32 type, rtk_uint32* pDrop)
+{
+    if(type >= DOS_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_DOS_CFG, RTL8367C_DROP_DAEQSA_OFFSET + type,pDrop);
+}
+/* Function Name:
+ *      rtl8367c_setAsicPortForceLink
+ * Description:
+ *      Set port force linking configuration
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      pPortAbility - port ability configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortForceLink(rtk_uint32 port, rtl8367c_port_ability_t *pPortAbility)
+{
+    rtk_uint32 regData = 0;
+
+    /* Invalid input parameter */
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    regData |= pPortAbility->forcemode << 12;
+    regData |= pPortAbility->mstfault << 9;
+    regData |= pPortAbility->mstmode << 8;
+    regData |= pPortAbility->nway << 7;
+    regData |= pPortAbility->txpause << 6;
+    regData |= pPortAbility->rxpause << 5;
+    regData |= pPortAbility->link << 4;
+    regData |= pPortAbility->duplex << 2;
+    regData |= pPortAbility->speed;
+
+    return rtl8367c_setAsicReg(RTL8367C_REG_MAC0_FORCE_SELECT+port, regData);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortForceLink
+ * Description:
+ *      Get port force linking configuration
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      pPortAbility - port ability configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortForceLink(rtk_uint32 port, rtl8367c_port_ability_t *pPortAbility)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+
+    /* Invalid input parameter */
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_REG_MAC0_FORCE_SELECT + port, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    pPortAbility->forcemode = (regData >> 12) & 0x0001;
+    pPortAbility->mstfault  = (regData >> 9) & 0x0001;
+    pPortAbility->mstmode   = (regData >> 8) & 0x0001;
+    pPortAbility->nway      = (regData >> 7) & 0x0001;
+    pPortAbility->txpause   = (regData >> 6) & 0x0001;
+    pPortAbility->rxpause   = (regData >> 5) & 0x0001;
+    pPortAbility->link      = (regData >> 4) & 0x0001;
+    pPortAbility->duplex    = (regData >> 2) & 0x0001;
+    pPortAbility->speed     = regData & 0x0003;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortStatus
+ * Description:
+ *      Get port link status
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      pPortAbility - port ability configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortStatus(rtk_uint32 port, rtl8367c_port_status_t *pPortStatus)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+
+    /* Invalid input parameter */
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_REG_PORT0_STATUS+port,&regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    pPortStatus->lpi1000  = (regData >> 11) & 0x0001;
+    pPortStatus->lpi100   = (regData >> 10) & 0x0001;
+    pPortStatus->mstfault = (regData >> 9) & 0x0001;
+    pPortStatus->mstmode  = (regData >> 8) & 0x0001;
+    pPortStatus->nway     = (regData >> 7) & 0x0001;
+    pPortStatus->txpause  = (regData >> 6) & 0x0001;
+    pPortStatus->rxpause  = (regData >> 5) & 0x0001;
+    pPortStatus->link     = (regData >> 4) & 0x0001;
+    pPortStatus->duplex   = (regData >> 2) & 0x0001;
+    pPortStatus->speed    = regData  & 0x0003;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicPortForceLinkExt
+ * Description:
+ *      Set external interface force linking configuration
+ * Input:
+ *      id          - external interface id (0~2)
+ *      portAbility - port ability configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortForceLinkExt(rtk_uint32 id, rtl8367c_port_ability_t *pPortAbility)
+{
+    rtk_uint32 retVal, regValue, regValue2, type, sgmiibit, hisgmiibit;
+    rtk_uint32 reg_data = 0;
+    rtk_uint32 i = 0;
+
+    /* Invalid input parameter */
+    if(id >= RTL8367C_EXTNO)
+        return RT_ERR_OUT_OF_RANGE;
+
+    reg_data |= pPortAbility->forcemode << 12;
+    reg_data |= pPortAbility->mstfault << 9;
+    reg_data |= pPortAbility->mstmode << 8;
+    reg_data |= pPortAbility->nway << 7;
+    reg_data |= pPortAbility->txpause << 6;
+    reg_data |= pPortAbility->rxpause << 5;
+    reg_data |= pPortAbility->link << 4;
+    reg_data |= pPortAbility->duplex << 2;
+    reg_data |= pPortAbility->speed;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK)
+        return retVal;
+    /*get chip ID */
+    if((retVal = rtl8367c_getAsicReg(0x1300, &regValue)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK)
+        return retVal;
+
+    type = 0;
+
+    switch (regValue)
+    {
+        case 0x0276:
+        case 0x0597:
+        case 0x6367:
+            type = 1;
+            break;
+        case 0x0652:
+        case 0x6368:
+            type = 2;
+            break;
+        case 0x0801:
+        case 0x6511:
+            type = 3;
+            break;
+        default:
+            return RT_ERR_FAILED;
+    }
+
+    if (1 == type)
+    {
+        if(1 == id)
+        {
+            if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_REG_TO_ECO4, &regValue)) != RT_ERR_OK)
+                return retVal;
+
+            if((regValue & (0x0001 << 5)) && (regValue & (0x0001 << 7)))
+            {
+                return RT_ERR_OK;
+            }
+
+            if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK)
+                return retVal;
+        }
+
+        if(0 == id || 1 == id)
+            return rtl8367c_setAsicReg(RTL8367C_REG_DIGITAL_INTERFACE0_FORCE + id, reg_data);
+        else
+            return rtl8367c_setAsicReg(RTL8367C_REG_DIGITAL_INTERFACE2_FORCE, reg_data);
+    }
+    else if (2 == type)
+    {
+        if (1 == id)
+        {
+             if((retVal = rtl8367c_setAsicRegBit(0x1311, 2, pPortAbility->duplex)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBits(0x1311, 0x3, pPortAbility->speed)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, pPortAbility->link)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBit(0x1311, 6, pPortAbility->txpause)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBit(0x1311, 5, pPortAbility->rxpause)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBit(0x1311, 12, pPortAbility->forcemode)) != RT_ERR_OK)
+                return retVal;
+
+            if (pPortAbility->link == 1)
+            {
+                if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, 1)) != RT_ERR_OK)
+                    return retVal;
+            }
+            else
+            {
+                if((retVal = rtl8367c_setAsicRegBits(0x1311, 0x3, 2)) != RT_ERR_OK)
+                    return retVal;
+            }
+
+
+            if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK)
+                return retVal;
+        }
+        else if (2 == id)
+        {
+            if((retVal = rtl8367c_setAsicRegBit(0x13c4, 2, pPortAbility->duplex)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBits(0x13c4, 0x3, pPortAbility->speed)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBit(0x13c4, 4, pPortAbility->link)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBit(0x13c4, 6, pPortAbility->txpause)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBit(0x13c4, 5, pPortAbility->rxpause)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBit(0x13c4, 12, pPortAbility->forcemode)) != RT_ERR_OK)
+                return retVal;
+
+            if (pPortAbility->link == 1)
+            {
+                if((retVal = rtl8367c_setAsicRegBit(0x13c4, 4, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                if((retVal = rtl8367c_setAsicRegBit(0x13c4, 4, 1)) != RT_ERR_OK)
+                    return retVal;
+            }
+            else
+            {
+                if((retVal = rtl8367c_setAsicRegBits(0x13c4, 0x3, 2)) != RT_ERR_OK)
+                    return retVal;
+            }
+
+            if((retVal = rtl8367c_setAsicRegBit(0x1dc1, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBits(0x1dc1, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBit(0x1dc1, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBit(0x1dc1, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBit(0x1dc1, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK)
+                return retVal;
+        }
+
+    }
+    else if(3 == type)
+    {
+        if(1 == id)
+        {
+            if((retVal = rtl8367c_getAsicRegBit(0x1d11, 6, &sgmiibit)) != RT_ERR_OK)
+                return retVal;
+            if((retVal = rtl8367c_getAsicRegBit(0x1d11, 11, &hisgmiibit)) != RT_ERR_OK)
+                return retVal;
+
+            if ((sgmiibit == 1) || (hisgmiibit == 1))
+            {
+                /*for 1000x/100fx/1000x_100fx, param has to be set to serdes registers*/
+                if((retVal = rtl8367c_getAsicReg(0x1d41, &regValue)) != RT_ERR_OK)
+                    return retVal;
+
+                /*bit5: cfg_mac6_fib =1,  bit7: cfg_mac6_fib2=1*/
+                if((regValue & 0xa0) == 0xa0)
+                {
+                     /* new_cfg_sds_mode */
+                    if((retVal = rtl8367c_getAsicRegBits(0x1d95, 0x1f00, &regValue2)) != RT_ERR_OK)
+                        return retVal;
+
+                     /*1000X*/
+                    if(regValue2 == 0x4)
+                    {
+#if 0
+                        /* new_cfg_sds_mode:reset mode */
+                        if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK)
+                            return retVal;
+#endif
+                        /* Enable new sds mode config */
+                        if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 4 0  bit 12  set 1,  bit15~13 = 4*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFF0FFF;
+                        reg_data |= 0x9000;
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 0 2  bit 6  set 1,  bit13 set to 0, bit12 nway_en*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFFDFFF;
+                        reg_data |= 0x40;
+                        if(pPortAbility->forcemode)
+                            reg_data &= 0xffffefff;
+                        else
+                            reg_data |= 0x1000;
+
+                        if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 4 2  bit 8  rx pause,  bit7 tx pause*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        if (pPortAbility->txpause)
+                            reg_data |= 0x80;
+                        else
+                            reg_data &= (~0x80);
+
+                        if (pPortAbility->rxpause)
+                            reg_data |= 0x100;
+                        else
+                            reg_data &= (~0x100);
+
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                         /* 0 4 0  bit 12  set 0*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFFEFFF;
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        /*new_cfg_sds_mode=1000x*/
+                        if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x4)) != RT_ERR_OK)
+                            return retVal;
+
+                    }
+                    else if(regValue2 == 0x5)
+                    {
+#if 0
+                        /*100FX*/
+                        if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK)
+                            return retVal;
+#endif
+                        /*cfg_sds_mode_sel_new=1  */
+                        if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 4 0  bit 12  set 1,  bit15~13 = 5*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFF0FFF;
+                        reg_data |= 0xB000;
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 0 2  bit 6  set 0,  bit13 set to 1, bit12 0*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFFFFBF;
+                        reg_data |= 0x2000;
+                        reg_data &= 0xffffefff;
+
+                        if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 4 2  bit 8  rx pause,  bit7 tx pause*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        if (pPortAbility->txpause)
+                            reg_data |= 0x80;
+                        else
+                            reg_data &= (~0x80);
+                        if (pPortAbility->rxpause)
+                            reg_data |= 0x100;
+                        else
+                            reg_data &= (~0x100);
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                         /* 0 4 0  bit 12  set 0*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFFEFFF;
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK)
+                            return retVal;
+                       /* new_cfg_sds_mode=1000x */
+                        if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x5)) != RT_ERR_OK)
+                            return retVal;
+
+                    }
+                    else if(regValue2 == 0x7)
+                    {
+#if 0
+                        /*100FX*/
+                        if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK)
+                            return retVal;
+#endif
+                        if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 4 0  bit 12  set 1,  bit15~13 = 4*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFF0FFF;
+                        reg_data |= 0x9000;
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 0 2  bit 6  set 1,  bit13 set to 0, bit12 nway_en*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFFDFFF;
+                        reg_data |= 0x40;
+                        if(pPortAbility->forcemode)
+                            reg_data &= 0xffffefff;
+                        else
+                            reg_data |= 0x1000;
+
+                        if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 4 2  bit 8  rx pause,  bit7 tx pause*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        if (pPortAbility->txpause)
+                            reg_data |= 0x80;
+                        else
+                            reg_data &= (~0x80);
+                        if (pPortAbility->rxpause)
+                            reg_data |= 0x100;
+                        else
+                            reg_data &=(~0x100);
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                         /* 0 4 0  bit 12  set 0*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFFEFFF;
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 4 0  bit 12  set 1,  bit15~13 = 5*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFF0FFF;
+                        reg_data |= 0xB000;
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 0 2  bit 6  set 0,  bit13 set to 1, bit12 0*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFFFFBF;
+                        reg_data |= 0x2000;
+                        reg_data &= 0xffffefff;
+
+                        if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 4 2  bit 8  rx pause,  bit7 tx pause*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        if (pPortAbility->txpause)
+                            reg_data |= 0x80;
+                        else
+                            reg_data &= 0xffffff7f;
+                        if (pPortAbility->rxpause)
+                            reg_data |= 0x100;
+                        else
+                            reg_data &= 0xfffffeff;
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                         /* 0 4 0  bit 12  set 0*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFFEFFF;
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        /*sds_mode:*/
+                        if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x7)) != RT_ERR_OK)
+                            return retVal;
+
+                    }
+
+                    /*disable force ability   ---      */
+                    if((retVal = rtl8367c_setAsicRegBit(0x137c, 12, 0)) != RT_ERR_OK)
+                        return retVal;
+                    return RT_ERR_OK;
+
+                }
+
+                /* new_cfg_sds_mode */
+                if((retVal = rtl8367c_getAsicRegBits(0x1d95, 0x1f00, &regValue2)) != RT_ERR_OK)
+                    return retVal;
+                if(regValue2 == 0x2)
+                {
+#if 0
+                    /*SGMII*/
+                    if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK)
+                        return retVal;
+#endif
+                    if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK)
+                        return retVal;
+
+                    for(i=0;i<0xfff; i++);
+
+                    /* 0 2 0  bit 8-9  nway*/
+                    if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, &reg_data)) != RT_ERR_OK)
+                        return retVal;
+                    reg_data &= 0xfffffcff;
+                    if (pPortAbility->nway)
+                        reg_data &= 0xfffffcff;
+                    else
+                        reg_data |= 0x100;
+                    if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x2)) != RT_ERR_OK)
+                        return retVal;
+
+                    for(i=0;i<0xfff; i++);
+
+                    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK)
+                        return retVal;
+
+                    /*disable force ability   ---      */
+                    if((retVal = rtl8367c_setAsicRegBit(0x137c, 12, 0)) != RT_ERR_OK)
+                        return retVal;
+                    return RT_ERR_OK;
+                }
+                else if(regValue2 == 0x12)
+                {
+#if 0
+                    /*HiSGMII*/
+                    if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK)
+                        return retVal;
+#endif
+                    if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK)
+                        return retVal;
+
+                    for(i=0;i<0xfff; i++);
+
+                    /* 0 2 0  bit 8-9  nway*/
+                    if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, &reg_data)) != RT_ERR_OK)
+                        return retVal;
+                    reg_data &= 0xfffffcff;
+                    if (pPortAbility->nway)
+                        reg_data &= 0xfffffcff;
+                    else
+                        reg_data |= 0x100;
+                    if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK)
+                        return retVal;
+
+
+                    if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x12)) != RT_ERR_OK)
+                        return retVal;
+
+                    for(i=0;i<0xfff; i++);
+
+                    if((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 0x1)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK)
+                        return retVal;
+
+                    /*disable force ability   ---      */
+                    if((retVal = rtl8367c_setAsicRegBit(0x137c, 12, 0)) != RT_ERR_OK)
+                        return retVal;
+                    return RT_ERR_OK;
+
+                }
+            }
+            else
+            {
+                if((retVal = rtl8367c_getAsicRegBits(0x1d3d, 10, &regValue2)) != RT_ERR_OK)
+                    return retVal;
+                if (regValue2 == 0)
+                {
+                    /*ext1_force_ablty*/
+                    if((retVal = rtl8367c_setAsicRegBit(0x1311, 2, pPortAbility->duplex)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBits(0x1311, 0x3, pPortAbility->speed)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, pPortAbility->link)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBit(0x1311, 6, pPortAbility->txpause)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBit(0x1311, 5, pPortAbility->rxpause)) != RT_ERR_OK)
+                        return retVal;
+
+                    /*force mode for ext1*/
+                    if((retVal = rtl8367c_setAsicRegBit(0x1311, 12, pPortAbility->forcemode)) != RT_ERR_OK)
+                        return retVal;
+
+                    if (pPortAbility->link == 1)
+                    {
+                        if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, 0)) != RT_ERR_OK)
+                            return retVal;
+
+                        if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, 1)) != RT_ERR_OK)
+                            return retVal;
+                    }
+                    else
+                    {
+                        if((retVal = rtl8367c_setAsicRegBits(0x1311, 0x3, 2)) != RT_ERR_OK)
+                            return retVal;
+                    }
+
+                    /*disable force ability   ---      */
+                    if((retVal = rtl8367c_setAsicRegBit(0x137c, 12, 0)) != RT_ERR_OK)
+                        return retVal;
+                    return RT_ERR_OK;
+                }
+            }
+
+
+        }
+        else if (2 == id)
+        {
+
+            if((retVal = rtl8367c_getAsicRegBit(0x1d95, 0, &sgmiibit)) != RT_ERR_OK)
+                    return retVal;
+            if (sgmiibit == 1)
+            {
+                /*for 1000x/100fx/1000x_100fx, param has to bet set to serdes registers*/
+                if((retVal = rtl8367c_getAsicReg(0x1d95, &regValue)) != RT_ERR_OK)
+                    return retVal;
+                /*cfg_mac7_sel_sgmii=1 & cfg_mac7_fib =1*/
+                if((regValue & 0x3) == 0x3)
+                {
+                    if((retVal = rtl8367c_getAsicRegBits(0x1d95, 0x1f00, &regValue2)) != RT_ERR_OK)
+                        return retVal;
+
+                    if(regValue2 == 0x4)
+                    {
+                        /*1000X*/
+#if 0
+                        if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK)
+                            return retVal;
+#endif
+                        if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 4 0  bit 12  set 1,  bit15~13 = 4*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFF0FFF;
+                        reg_data |= 0x9000;
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 0 2  bit 6  set 1,  bit13 set to 0, bit12 nway_en*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFFDFFF;
+                        reg_data |= 0x40;
+                        if(pPortAbility->forcemode)
+                            reg_data &= 0xffffefff;
+                        else
+                            reg_data |= 0x1000;
+
+                        if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 4 2  bit 8  rx pause,  bit7 tx pause*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        if (pPortAbility->txpause)
+                            reg_data |= 0x80;
+                        else
+                            reg_data &= 0xffffff7f;
+                        if (pPortAbility->rxpause)
+                            reg_data |= 0x100;
+                        else
+                            reg_data &= 0xfffffeff;
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                         /* 0 4 0  bit 12  set 0*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFFEFFF;
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x4)) != RT_ERR_OK)
+                            return retVal;
+
+                    }
+                    else if(regValue2 == 0x5)
+                    {
+                        /*100FX*/
+#if 0
+                        if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK)
+                            return retVal;
+#endif
+                        if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 4 0  bit 12  set 1,  bit15~13 = 5*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFF0FFF;
+                        reg_data |= 0xB000;
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 0 2  bit 6  set 0,  bit13 set to 1, bit12 0*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFFFFBF;
+                        reg_data |= 0x2000;
+                        reg_data &= 0xffffefff;
+
+                        if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 4 2  bit 8  rx pause,  bit7 tx pause*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        if (pPortAbility->txpause)
+                            reg_data |= 0x80;
+                        else
+                            reg_data &= 0xffffff7f;
+                        if (pPortAbility->rxpause)
+                            reg_data |= 0x100;
+                        else
+                            reg_data &= 0xfffffeff;
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                         /* 0 4 0  bit 12  set 0*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFFEFFF;
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x5)) != RT_ERR_OK)
+                            return retVal;
+
+                    }
+                    else if(regValue2 == 0x7)
+                    {
+                        /*100FX*/
+#if 0
+                        if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK)
+                            return retVal;
+#endif
+                        if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 4 0  bit 12  set 1,  bit15~13 = 4*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFF0FFF;
+                        reg_data |= 0x9000;
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 0 2  bit 6  set 1,  bit13 set to 0, bit12 nway_en*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFFDFFF;
+                        reg_data |= 0x40;
+                        if(pPortAbility->forcemode)
+                            reg_data &= 0xffffefff;
+                        else
+                            reg_data |= 0x1000;
+
+                        if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 4 2  bit 8  rx pause,  bit7 tx pause*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        if (pPortAbility->txpause)
+                            reg_data |= 0x80;
+                        else
+                            reg_data &= 0xffffff7f;
+                        if (pPortAbility->rxpause)
+                            reg_data |= 0x100;
+                        else
+                            reg_data &= 0xfffffeff;
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                         /* 0 4 0  bit 12  set 0*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFFEFFF;
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 4 0  bit 12  set 1,  bit15~13 = 5*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFF0FFF;
+                        reg_data |= 0xB000;
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 0 2  bit 6  set 0,  bit13 set to 1, bit12 0*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFFFFBF;
+                        reg_data |= 0x2000;
+                        reg_data &= 0xffffefff;
+
+                        if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* 0 4 2  bit 8  rx pause,  bit7 tx pause*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        if (pPortAbility->txpause)
+                            reg_data |= 0x80;
+                        else
+                            reg_data  &= 0xffffff7f;
+                        if (pPortAbility->rxpause)
+                            reg_data |= 0x100;
+                        else
+                            reg_data &= 0xfffffeff;
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                         /* 0 4 0  bit 12  set 0*/
+                        if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &reg_data)) != RT_ERR_OK)
+                            return retVal;
+                        reg_data &= 0xFFFFEFFF;
+                        if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK)
+                            return retVal;
+
+                        if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x7)) != RT_ERR_OK)
+                            return retVal;
+
+                    }
+
+                    if((retVal = rtl8367c_setAsicRegBit(0x137d, 12, 0)) != RT_ERR_OK)
+                        return retVal;
+                    return RT_ERR_OK;
+
+                }
+                /* new_cfg_sds_mode */
+                if((retVal = rtl8367c_getAsicRegBits(0x1d95, 0x1f00, &regValue2)) != RT_ERR_OK)
+                        return retVal;
+                if(regValue2 == 0x2)
+                {
+                    /*SGMII*/
+#if 0
+                    if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK)
+                        return retVal;
+#endif
+                    if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK)
+                        return retVal;
+
+                    for(i=0;i<0xfff; i++);
+
+                    /* 0 2 0  bit 8-9  nway*/
+                    if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, &reg_data)) != RT_ERR_OK)
+                        return retVal;
+                    reg_data &= 0xfffffcff;
+                    if (pPortAbility->nway)
+                        reg_data &= 0xfffffcff;
+                    else
+                        reg_data |= 0x100;
+                    if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x2)) != RT_ERR_OK)
+                        return retVal;
+
+                    for(i=0;i<0xfff; i++);
+
+                    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBit(0x137d, 12, 0)) != RT_ERR_OK)
+                        return retVal;
+                    return RT_ERR_OK;
+                }
+            }
+            else
+            {
+
+                /*ext2_force_ablty*/
+                if((retVal = rtl8367c_setAsicRegBit(0x13c4, 2, pPortAbility->duplex)) != RT_ERR_OK)
+                    return retVal;
+
+                if((retVal = rtl8367c_setAsicRegBits(0x13c4, 0x3, pPortAbility->speed)) != RT_ERR_OK)
+                    return retVal;
+
+                if((retVal = rtl8367c_setAsicRegBit(0x13c4, 4, pPortAbility->link)) != RT_ERR_OK)
+                    return retVal;
+
+                if((retVal = rtl8367c_setAsicRegBit(0x13c4, 6, pPortAbility->txpause)) != RT_ERR_OK)
+                    return retVal;
+
+                if((retVal = rtl8367c_setAsicRegBit(0x13c4, 5, pPortAbility->rxpause)) != RT_ERR_OK)
+                    return retVal;
+
+                /*force mode for ext2*/
+                if((retVal = rtl8367c_setAsicRegBit(0x13c4, 12, pPortAbility->forcemode)) != RT_ERR_OK)
+                    return retVal;
+
+                if (pPortAbility->link == 1)
+                {
+                    if((retVal = rtl8367c_setAsicRegBit(0x13c4, 4, 0)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBit(0x13c4, 4, 1)) != RT_ERR_OK)
+                        return retVal;
+                }
+                else
+                {
+                    if((retVal = rtl8367c_setAsicRegBits(0x13c4, 0x3, 2)) != RT_ERR_OK)
+                        return retVal;
+                }
+
+
+                if((retVal = rtl8367c_getAsicRegBit(0x1d3d, 10, &reg_data)) != RT_ERR_OK)
+                        return retVal;
+                if(reg_data == 1)
+                {
+                if((retVal = rtl8367c_setAsicRegBit(0x1311, 2, pPortAbility->duplex)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBits(0x1311, 0x3, pPortAbility->speed)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, pPortAbility->link)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBit(0x1311, 6, pPortAbility->txpause)) != RT_ERR_OK)
+                        return retVal;
+
+                    if((retVal = rtl8367c_setAsicRegBit(0x1311, 5, pPortAbility->rxpause)) != RT_ERR_OK)
+                        return retVal;
+
+                    /*force mode for ext1*/
+                    if((retVal = rtl8367c_setAsicRegBit(0x1311, 12, pPortAbility->forcemode)) != RT_ERR_OK)
+                        return retVal;
+
+                    if (pPortAbility->link == 1)
+                    {
+                        if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, 0)) != RT_ERR_OK)
+                            return retVal;
+
+                        if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, 1)) != RT_ERR_OK)
+                            return retVal;
+                    }
+                    else
+                    {
+                        if((retVal = rtl8367c_setAsicRegBits(0x1311, 0x3, 2)) != RT_ERR_OK)
+                            return retVal;
+                    }
+                }
+
+
+            }
+
+            /*disable force ability   ---      */
+            if((retVal = rtl8367c_setAsicRegBit(0x137d, 12, 0)) != RT_ERR_OK)
+                return retVal;
+        }
+#if 0
+        if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK)
+            return retVal;
+
+        if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK)
+            return retVal;
+
+        if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK)
+            return retVal;
+
+        if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK)
+            return retVal;
+
+        if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK)
+            return retVal;
+#endif
+    }
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortForceLinkExt
+ * Description:
+ *      Get external interface force linking configuration
+ * Input:
+ *      id          - external interface id (0~1)
+ *      pPortAbility - port ability configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortForceLinkExt(rtk_uint32 id, rtl8367c_port_ability_t *pPortAbility)
+{
+    rtk_uint32  reg_data, regValue, type;
+    rtk_uint32  sgmiiSel;
+    rtk_uint32  hsgmiiSel;
+    ret_t       retVal;
+
+    /* Invalid input parameter */
+    if(id >= RTL8367C_EXTNO)
+        return RT_ERR_OUT_OF_RANGE;
+    /*cfg_magic_id  &  get chip_id*/
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_getAsicReg(0x1300, &regValue)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK)
+        return retVal;
+
+    type = 0;
+
+    switch (regValue)
+    {
+        case 0x0276:
+        case 0x0597:
+        case 0x6367:
+            type = 1;
+            break;
+        case 0x0652:
+        case 0x6368:
+            type = 2;
+            break;
+        case 0x0801:
+        case 0x6511:
+            type = 3;
+            break;
+        default:
+            return RT_ERR_FAILED;
+    }
+
+    if (1 == type)
+    {
+        if(1 == id)
+        {
+            if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET, &sgmiiSel)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, &hsgmiiSel)) != RT_ERR_OK)
+                return retVal;
+
+            if( (sgmiiSel == 1) || (hsgmiiSel == 1) )
+            {
+                memset(pPortAbility, 0x00, sizeof(rtl8367c_port_ability_t));
+                pPortAbility->forcemode = 1;
+
+                if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, &reg_data)) != RT_ERR_OK)
+                    return retVal;
+
+                pPortAbility->duplex = reg_data;
+
+                if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, &reg_data)) != RT_ERR_OK)
+                    return retVal;
+
+                pPortAbility->speed = reg_data;
+
+                if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, &reg_data)) != RT_ERR_OK)
+                    return retVal;
+
+                pPortAbility->link = reg_data;
+
+                if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, &reg_data)) != RT_ERR_OK)
+                    return retVal;
+
+                pPortAbility->txpause = reg_data;
+
+                if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, &reg_data)) != RT_ERR_OK)
+                    return retVal;
+
+                pPortAbility->rxpause = reg_data;
+
+                return RT_ERR_OK;
+            }
+        }
+
+        if(0 == id || 1 == id)
+            retVal = rtl8367c_getAsicReg(RTL8367C_REG_DIGITAL_INTERFACE0_FORCE+id, &reg_data);
+        else
+            retVal = rtl8367c_getAsicReg(RTL8367C_REG_DIGITAL_INTERFACE2_FORCE, &reg_data);
+
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        pPortAbility->forcemode = (reg_data >> 12) & 0x0001;
+        pPortAbility->mstfault  = (reg_data >> 9) & 0x0001;
+        pPortAbility->mstmode   = (reg_data >> 8) & 0x0001;
+        pPortAbility->nway      = (reg_data >> 7) & 0x0001;
+        pPortAbility->txpause   = (reg_data >> 6) & 0x0001;
+        pPortAbility->rxpause   = (reg_data >> 5) & 0x0001;
+        pPortAbility->link      = (reg_data >> 4) & 0x0001;
+        pPortAbility->duplex    = (reg_data >> 2) & 0x0001;
+        pPortAbility->speed     = reg_data & 0x0003;
+    }
+    else if (2 == type)
+    {
+        if (id == 1)
+        {
+            if ((retVal = rtl8367c_getAsicReg(0x1311, &reg_data))!=RT_ERR_OK)
+                return retVal;
+
+            pPortAbility->forcemode = (reg_data >> 12) & 1;
+            pPortAbility->duplex = (reg_data >> 2) & 1;
+            pPortAbility->link = (reg_data >> 4) & 1;
+            pPortAbility->speed = reg_data & 3;
+            pPortAbility->rxpause = (reg_data >> 5) & 1;
+            pPortAbility->txpause = (reg_data >> 6) & 1;
+        }
+        else if (2 == id)
+        {
+            if ((retVal = rtl8367c_getAsicReg(0x13c4, &reg_data))!=RT_ERR_OK)
+                return retVal;
+
+            pPortAbility->forcemode = (reg_data >> 12) & 1;
+            pPortAbility->duplex = (reg_data >> 2) & 1;
+            pPortAbility->link = (reg_data >> 4) & 1;
+            pPortAbility->speed = reg_data & 3;
+            pPortAbility->rxpause = (reg_data >> 5) & 1;
+            pPortAbility->txpause = (reg_data >> 6) & 1;
+        }
+    }
+    else if (3 == type)
+    {
+        if (id == 1)
+        {
+            if ((retVal = rtl8367c_getAsicReg(0x1311, &reg_data))!=RT_ERR_OK)
+                return retVal;
+
+            pPortAbility->forcemode = (reg_data >> 12) & 1;
+            pPortAbility->duplex = (reg_data >> 2) & 1;
+            pPortAbility->link = (reg_data >> 4) & 1;
+            pPortAbility->speed = reg_data & 3;
+            pPortAbility->rxpause = (reg_data >> 5) & 1;
+            pPortAbility->txpause = (reg_data >> 6) & 1;
+        }
+        else if (2 == id)
+        {
+            if ((retVal = rtl8367c_getAsicReg(0x13c4, &reg_data))!=RT_ERR_OK)
+                return retVal;
+
+            pPortAbility->forcemode = (reg_data >> 12) & 1;
+            pPortAbility->duplex = (reg_data >> 2) & 1;
+            pPortAbility->link = (reg_data >> 4) & 1;
+            pPortAbility->speed = reg_data & 3;
+            pPortAbility->rxpause = (reg_data >> 5) & 1;
+            pPortAbility->txpause = (reg_data >> 6) & 1;
+        }
+    }
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicPortExtMode
+ * Description:
+ *      Set external interface mode configuration
+ * Input:
+ *      id      - external interface id (0~2)
+ *      mode    - external interface mode
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortExtMode(rtk_uint32 id, rtk_uint32 mode)
+{
+    ret_t   retVal;
+    rtk_uint32 i, regValue, type, option,reg_data;
+    rtk_uint32 idx;
+    rtk_uint32 redData[][2] =   { {0x04D7, 0x0480}, {0xF994, 0x0481}, {0x21A2, 0x0482}, {0x6960, 0x0483}, {0x9728, 0x0484}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x83F2, 0x002E} };
+    rtk_uint32 redDataSB[][2] = { {0x04D7, 0x0480}, {0xF994, 0x0481}, {0x31A2, 0x0482}, {0x6960, 0x0483}, {0x9728, 0x0484}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x83F2, 0x002E} };
+    rtk_uint32 redData1[][2] =  { {0x82F1, 0x0500}, {0xF195, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} };
+    rtk_uint32 redData5[][2] =  { {0x82F1, 0x0500}, {0xF195, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} };
+    rtk_uint32 redData6[][2] =  { {0x82F1, 0x0500}, {0xF195, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} };
+    rtk_uint32 redData8[][2] =  { {0x82F1, 0x0500}, {0xF995, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} };
+    rtk_uint32 redData9[][2] =  { {0x82F1, 0x0500}, {0xF995, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} };
+    rtk_uint32 redDataHB[][2] = { {0x82F0, 0x0500}, {0xF195, 0x0501}, {0x31A2, 0x0502}, {0x7960, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} };
+
+    if(id >= RTL8367C_EXTNO)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(mode >= EXT_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    /* magic number*/
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK)
+        return retVal;
+    /* Chip num */
+    if((retVal = rtl8367c_getAsicReg(0x1300, &regValue)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK)
+        return retVal;
+
+    type = 0;
+
+    switch (regValue)
+    {
+        case 0x0276:
+        case 0x0597:
+        case 0x6367:
+            type = 1;
+            break;
+        case 0x0652:
+        case 0x6368:
+            type = 2;
+            break;
+        case 0x0801:
+        case 0x6511:
+            type = 3;
+            break;
+        default:
+            return RT_ERR_FAILED;
+    }
+
+
+    if (1==type)
+    {
+        if((mode == EXT_1000X_100FX) || (mode == EXT_1000X) || (mode == EXT_100FX))
+        {
+            if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_REG_TO_ECO4, 5, 1)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_REG_TO_ECO4, 7, 1)) != RT_ERR_OK)
+                return retVal;
+
+            if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_CHIP_RESET, RTL8367C_DW8051_RST_OFFSET, 1)) != RT_ERR_OK)
+                return retVal;
+
+            if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MISCELLANEOUS_CONFIGURE0, RTL8367C_DW8051_EN_OFFSET, 1)) != RT_ERR_OK)
+                return retVal;
+
+            if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_ACS_IROM_ENABLE_OFFSET, 1)) != RT_ERR_OK)
+                return retVal;
+
+            if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_IROM_MSB_OFFSET, 0)) != RT_ERR_OK)
+                return retVal;
+
+            if(mode == EXT_1000X_100FX)
+            {
+                for(idx = 0; idx < FIBER2_AUTO_INIT_SIZE; idx++)
+                {
+                    if ((retVal = rtl8367c_setAsicReg(0xE000 + idx, (rtk_uint32)Fiber2_Auto[idx])) != RT_ERR_OK)
+                        return retVal;
+                }
+            }
+
+            if(mode == EXT_1000X)
+            {
+                for(idx = 0; idx < FIBER2_1G_INIT_SIZE; idx++)
+                {
+                    if ((retVal = rtl8367c_setAsicReg(0xE000 + idx, (rtk_uint32)Fiber2_1G[idx])) != RT_ERR_OK)
+                        return retVal;
+                }
+            }
+
+            if(mode == EXT_100FX)
+            {
+                for(idx = 0; idx < FIBER2_100M_INIT_SIZE; idx++)
+                {
+                    if ((retVal = rtl8367c_setAsicReg(0xE000 + idx, (rtk_uint32)Fiber2_100M[idx])) != RT_ERR_OK)
+                        return retVal;
+                }
+            }
+
+            if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_IROM_MSB_OFFSET, 0)) != RT_ERR_OK)
+                return retVal;
+
+            if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_ACS_IROM_ENABLE_OFFSET, 0)) != RT_ERR_OK)
+                return retVal;
+
+            if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_CHIP_RESET, RTL8367C_DW8051_RST_OFFSET, 0)) != RT_ERR_OK)
+                return retVal;
+        }
+
+        if(mode == EXT_GMII)
+        {
+            if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_EXT0_RGMXF, RTL8367C_EXT0_RGTX_INV_OFFSET, 1)) != RT_ERR_OK)
+                return retVal;
+
+            if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_EXT1_RGMXF, RTL8367C_EXT1_RGTX_INV_OFFSET, 1)) != RT_ERR_OK)
+                return retVal;
+
+            if( (retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_EXT_TXC_DLY, RTL8367C_EXT1_GMII_TX_DELAY_MASK, 5)) != RT_ERR_OK)
+                return retVal;
+
+            if( (retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_EXT_TXC_DLY, RTL8367C_EXT0_GMII_TX_DELAY_MASK, 6)) != RT_ERR_OK)
+                return retVal;
+        }
+
+        /* Serdes reset */
+        if( (mode == EXT_TMII_MAC) || (mode == EXT_TMII_PHY) )
+        {
+            if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_BYPASS_LINE_RATE, id, 1)) != RT_ERR_OK)
+                return retVal;
+        }
+        else
+        {
+            if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_BYPASS_LINE_RATE, id, 0)) != RT_ERR_OK)
+                return retVal;
+        }
+
+        if( (mode == EXT_SGMII) || (mode == EXT_HSGMII) )
+        {
+            if(id != 1)
+                return RT_ERR_PORT_ID;
+
+            if((retVal = rtl8367c_setAsicReg(0x13C0, 0x0249)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicReg(0x13C1, &option)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicReg(0x13C0, 0x0000)) != RT_ERR_OK)
+                return retVal;
+        }
+
+        if(mode == EXT_SGMII)
+        {
+            if(option == 0)
+            {
+                for(i = 0; i <= 7; i++)
+                {
+                    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData[i][0])) != RT_ERR_OK)
+                        return retVal;
+
+                    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData[i][1])) != RT_ERR_OK)
+                        return retVal;
+
+                    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
+                        return retVal;
+                }
+            }
+            else
+            {
+                for(i = 0; i <= 7; i++)
+                {
+                    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redDataSB[i][0])) != RT_ERR_OK)
+                        return retVal;
+
+                    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redDataSB[i][1])) != RT_ERR_OK)
+                        return retVal;
+
+                    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
+                        return retVal;
+                }
+            }
+        }
+
+        if(mode == EXT_HSGMII)
+        {
+            if(option == 0)
+            {
+                if( (retVal = rtl8367c_setAsicReg(0x13c2, 0x0249)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_getAsicReg(0x1301, &regValue)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_setAsicReg(0x13c2, 0x0000)) != RT_ERR_OK)
+                    return retVal;
+
+                if ( ((regValue & 0x00F0) >> 4) == 0x0001)
+                {
+                    for(i = 0; i <= 8; i++)
+                    {
+                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData1[i][0])) != RT_ERR_OK)
+                            return retVal;
+
+                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData1[i][1])) != RT_ERR_OK)
+                            return retVal;
+
+                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
+                            return retVal;
+                    }
+                }
+                else if ( ((regValue & 0x00F0) >> 4) == 0x0005)
+                {
+                    for(i = 0; i <= 8; i++)
+                    {
+                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData5[i][0])) != RT_ERR_OK)
+                            return retVal;
+
+                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData5[i][1])) != RT_ERR_OK)
+                            return retVal;
+
+                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
+                            return retVal;
+                    }
+                }
+                else if ( ((regValue & 0x00F0) >> 4) == 0x0006)
+                {
+                    for(i = 0; i <= 8; i++)
+                    {
+                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData6[i][0])) != RT_ERR_OK)
+                            return retVal;
+
+                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData6[i][1])) != RT_ERR_OK)
+                            return retVal;
+
+                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
+                            return retVal;
+                    }
+                }
+                else if ( ((regValue & 0x00F0) >> 4) == 0x0008)
+                {
+                    for(i = 0; i <= 8; i++)
+                    {
+                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData8[i][0])) != RT_ERR_OK)
+                            return retVal;
+
+                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData8[i][1])) != RT_ERR_OK)
+                            return retVal;
+
+                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
+                            return retVal;
+                    }
+                }
+                else if ( ((regValue & 0x00F0) >> 4) == 0x0009)
+                {
+                    for(i = 0; i <= 8; i++)
+                    {
+                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData9[i][0])) != RT_ERR_OK)
+                            return retVal;
+
+                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData9[i][1])) != RT_ERR_OK)
+                            return retVal;
+
+                        if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
+                            return retVal;
+                    }
+                }
+            }
+            else
+            {
+                for(i = 0; i <= 8; i++)
+                {
+                    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redDataHB[i][0])) != RT_ERR_OK)
+                        return retVal;
+
+                    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redDataHB[i][1])) != RT_ERR_OK)
+                        return retVal;
+
+                    if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
+                        return retVal;
+                }
+            }
+        }
+
+        /* Only one ext port should care SGMII setting */
+        if(id == 1)
+        {
+
+            if(mode == EXT_SGMII)
+            {
+                if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, 0)) != RT_ERR_OK)
+                    return retVal;
+            }
+            else if(mode == EXT_HSGMII)
+            {
+                if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, 1)) != RT_ERR_OK)
+                    return retVal;
+            }
+            else
+            {
+
+                if((mode != EXT_1000X_100FX) && (mode != EXT_1000X) && (mode != EXT_100FX))
+                {
+                    if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET, 0)) != RT_ERR_OK)
+                        return retVal;
+
+                    if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, 0)) != RT_ERR_OK)
+                        return retVal;
+                }
+            }
+        }
+
+        if(0 == id || 1 == id)
+        {
+            if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_DIGITAL_INTERFACE_SELECT, RTL8367C_SELECT_GMII_0_MASK << (id * RTL8367C_SELECT_GMII_1_OFFSET), mode)) != RT_ERR_OK)
+                return retVal;
+        }
+        else
+        {
+            if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_DIGITAL_INTERFACE_SELECT_1, RTL8367C_SELECT_GMII_2_MASK, mode)) != RT_ERR_OK)
+                return retVal;
+        }
+
+        /* Serdes not reset */
+        if( (mode == EXT_SGMII) || (mode == EXT_HSGMII) )
+        {
+            if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x7106)) != RT_ERR_OK)
+                return retVal;
+
+            if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0003)) != RT_ERR_OK)
+                return retVal;
+
+            if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
+                return retVal;
+        }
+
+        if( (mode == EXT_SGMII) || (mode == EXT_HSGMII) )
+        {
+            if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_CHIP_RESET, RTL8367C_DW8051_RST_OFFSET, 1)) != RT_ERR_OK)
+                return retVal;
+
+            if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MISCELLANEOUS_CONFIGURE0, RTL8367C_DW8051_EN_OFFSET, 1)) != RT_ERR_OK)
+                return retVal;
+
+            if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_ACS_IROM_ENABLE_OFFSET, 1)) != RT_ERR_OK)
+                return retVal;
+
+            if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_IROM_MSB_OFFSET, 0)) != RT_ERR_OK)
+                return retVal;
+
+            for(idx = 0; idx < SGMII_INIT_SIZE; idx++)
+            {
+                if ((retVal = rtl8367c_setAsicReg(0xE000 + idx, (rtk_uint32)Sgmii_Init[idx])) != RT_ERR_OK)
+                    return retVal;
+            }
+
+            if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_IROM_MSB_OFFSET, 0)) != RT_ERR_OK)
+                return retVal;
+
+            if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_ACS_IROM_ENABLE_OFFSET, 0)) != RT_ERR_OK)
+                return retVal;
+
+            if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_CHIP_RESET, RTL8367C_DW8051_RST_OFFSET, 0)) != RT_ERR_OK)
+                return retVal;
+        }
+    }
+    else if (2 == type)
+    {
+        /* Serdes reset */
+        if( (mode == EXT_TMII_MAC) || (mode == EXT_TMII_PHY) )
+        {
+            if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_BYPASS_LINE_RATE, id+2, 1)) != RT_ERR_OK)
+                return retVal;
+        }
+        else
+        {
+            if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_BYPASS_LINE_RATE, id+2, 0)) != RT_ERR_OK)
+                return retVal;
+        }
+
+        /*set MAC mode*/
+        if (id == 1)
+        {
+            if(mode == EXT_HSGMII)
+                return RT_ERR_PORT_ID;
+
+            if (mode == EXT_SGMII)
+            {
+                /*cfg port8 with MII mac mode*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*enable port8 SGMII*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 14, 1)) != RT_ERR_OK)
+                    return retVal;
+            }
+            else if (mode == EXT_1000X || mode == EXT_100FX || mode == EXT_1000X_100FX)
+            {
+                /*cfg port8 with MII mac mode*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*disable port8 SGMII*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 14, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*set fiber link up*/
+                if((retVal = rtl8367c_setAsicRegBit(0x6210, 11, 0)) != RT_ERR_OK)
+                    return retVal;
+            }
+            else
+            {
+                /*cfg port8 with MII mac mode*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, mode)) != RT_ERR_OK)
+                    return retVal;
+
+                /*disable port8 SGMII*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 14, 0)) != RT_ERR_OK)
+                    return retVal;
+            }
+            /*disable SDS 1*/
+            if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 0x1f)) != RT_ERR_OK)
+                return retVal;
+        }
+        else if(id == 2)
+        {
+            if (mode == EXT_HSGMII)
+            {
+                if ((retVal = rtl8367c_setAsicReg(0x130, 7)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((retVal = rtl8367c_setAsicReg(0x39f, 7)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((retVal = rtl8367c_setAsicReg(0x3fa, 7)) != RT_ERR_OK)
+                    return retVal;
+            }
+            else
+            {
+                if ((retVal = rtl8367c_setAsicReg(0x130, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((retVal = rtl8367c_setAsicReg(0x39f, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((retVal = rtl8367c_setAsicReg(0x3fa, 4)) != RT_ERR_OK)
+                    return retVal;
+
+            }
+
+
+            if (mode == EXT_SGMII)
+            {
+                /*cfg port9 with MII mac mode*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*enable port9 SGMII*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 6, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*disable port9 HSGMII*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 7, 0)) != RT_ERR_OK)
+                    return retVal;
+            }
+            else if (mode == EXT_HSGMII)
+            {
+                /*cfg port9 with MII mac mode*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*disable port9 SGMII*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 6, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*enable port9 HSGMII*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 7, 1)) != RT_ERR_OK)
+                    return retVal;
+            }
+            else if (mode == EXT_1000X || mode == EXT_100FX || mode == EXT_1000X_100FX)
+            {
+                /*cfg port9 with MII mac mode*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*disable port9 SGMII*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 6, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*disable port9 HSGMII*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 7, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*set fiber link up*/
+                if((retVal = rtl8367c_setAsicRegBit(0x6200, 11, 0)) != RT_ERR_OK)
+                    return retVal;
+            }
+            else
+            {
+                /*cfg port9 with MII mac mode*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, mode)) != RT_ERR_OK)
+                    return retVal;
+
+                /*disable port9 SGMII*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 6, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*disable port9 HSGMII*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 7, 0)) != RT_ERR_OK)
+                    return retVal;
+            }
+            /*disable SDS 0*/
+            if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 0x1f)) != RT_ERR_OK)
+                return retVal;
+        }
+
+        /*SET TO RGMII MODE*/
+        if (mode == EXT_RGMII)
+        {
+            /*disable paral led pad*/
+            if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PARA_LED_IO_EN3, 0)) != RT_ERR_OK)
+                return retVal;
+
+            if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PARA_LED_IO_EN1, 0)) != RT_ERR_OK)
+                return retVal;
+
+            if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PARA_LED_IO_EN2, 0)) != RT_ERR_OK)
+                return retVal;
+
+            /*set MAC8 mode*/
+            if (id == 1)
+            {
+                /*1: RGMII1 bias work at 3.3V, 0: RGMII1 bias work at 2.5V*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1303, 9, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*drving 1*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1303, 6, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*drving 1*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1303, 4, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*show rate = 0*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1303, 1, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*EXT1 RGMII TXC delay 2ns*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1307, 3, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_Ext1_rgtxc_dly = 0*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x13f9, 0x38, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*RXDLY = 0*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x1307, 0x7, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_rg1_dn = 4*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x1304, 0x7000, 4)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_rg1_dp = 4*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x13f9, 0x700, 4)) != RT_ERR_OK)
+                    return retVal;
+            }
+            else if (id == 2)
+            {
+                /*1: RGMII1 bias work at 3.3V, 0: RGMII1 bias work at 2.5V*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1303, 10, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*drving 1*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x13e2, 2, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*drving 1*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x13e2, 1, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*show rate = 0*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x13e2, 0, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*EXT1 RGMII TXC delay 2ns*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x13c5, 3, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_Ext1_rgtxc_dly = 0*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x13f9, 0x1c0, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*RXDLY = 0*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x13c5, 0x7, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_rg1_dn = 4*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x13e2, 0x1c0, 4)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_rg1_dp = 4*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x13e2, 0x38, 4)) != RT_ERR_OK)
+                    return retVal;
+            }
+        }
+        else if (mode == EXT_SGMII)
+        {
+            if (id == 1)
+            {
+                /*sds 1     reg 1    page 0x21     write value  0xec91*/
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0xec91)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x21<<5) | 1)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*sds 1     reg 5    page 0x24     write value  0x5825*/
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x5825)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x24<<5) | 5)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C1)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 2)) != RT_ERR_OK)
+                    return retVal;
+
+                /*?????????????????*/
+
+            }
+            else if (id == 2)
+            {
+                /*sds 0     reg 0    page 0x28     write value  0x942c*/
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x942c)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x28<<5) | 0)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*sds 0     reg 0    page 0x24     write value  0x942c*/
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x942c)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x24<<5) | 0)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*sds 0     reg 5    page 0x21     write value  0x8dc3*/
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x8dc3)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x21<<5) | 5)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 2)) != RT_ERR_OK)
+                    return retVal;
+
+                /*?????????????????*/
+            }
+        }
+        else if (mode == EXT_HSGMII)
+        {
+            if (id == 2)
+            {
+                /*sds 0     reg 0    page 0x28     write value  0x942c*/
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x942c)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x28<<5) | 0)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*sds 0     reg 0    page 0x24     write value  0x942c*/
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x942c)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x24<<5) | 0)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*sds 0     reg 5    page 0x21     write value  0x8dc3*/
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x8dc3)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x21<<5) | 5)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
+                    return retVal;
+
+
+                /* optimizing HISGMII performance while RGMII used & */
+                /*sds 0     reg 9     page 0x21     write value 0x3931*/
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x3931)) != RT_ERR_OK)
+                        return retVal;
+
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x21<<5)|9) ) != RT_ERR_OK)
+                        return retVal;
+
+                if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK)
+                        return retVal;
+
+
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 0x12)) != RT_ERR_OK)
+                    return retVal;
+
+                /*?????????????????*/
+            }
+        }
+        else if (mode == EXT_1000X)
+        {
+            if (id == 1)
+            {
+
+                if( (retVal = rtl8367c_setAsicSdsReg(1, 1, 0x21, 0xec91)) != RT_ERR_OK)
+                    return retVal;
+                if( (retVal = rtl8367c_setAsicSdsReg(1, 5, 0x24, 0x5825)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 4)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 0x1f)) != RT_ERR_OK)
+                    return retVal;
+
+                /*patch speed change sds1 1000M*/
+                if( (retVal = rtl8367c_getAsicSdsReg(1, 4, 0, &regValue)) != RT_ERR_OK)
+                    return retVal;
+                regValue &= 0xFFFF0FFF;
+                regValue |= 0x9000;
+                if( (retVal = rtl8367c_setAsicSdsReg(1, 4, 0, regValue)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_getAsicSdsReg(1, 0, 2, &regValue)) != RT_ERR_OK)
+                    return retVal;
+                regValue &= 0xFFFFdFFF;
+                regValue |= 0x40;
+                if( (retVal = rtl8367c_setAsicSdsReg(1, 0, 2, regValue)) != RT_ERR_OK)
+                    return retVal;
+
+
+                if( (retVal = rtl8367c_getAsicSdsReg(1, 4, 0, &regValue)) != RT_ERR_OK)
+                    return retVal;
+                regValue &= 0xFFFFEFFF;
+                if( (retVal = rtl8367c_setAsicSdsReg(1, 4, 0, regValue)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 4)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x6000, 0)) != RT_ERR_OK)
+                    return retVal;
+
+            }
+            else if (id == 2)
+            {
+                if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 0x28, 0x942c)) != RT_ERR_OK)
+                    return retVal;
+                if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 0x24, 0x942c)) != RT_ERR_OK)
+                    return retVal;
+                if( (retVal = rtl8367c_setAsicSdsReg(0, 5, 0x21, 0x8dc3)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 4)) != RT_ERR_OK)
+                    return retVal;
+
+                /*patch speed change sds0 1000M*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 0x1f)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &regValue)) != RT_ERR_OK)
+                    return retVal;
+                regValue &= 0xFFFF0FFF;
+                regValue |= 0x9000;
+                if( (retVal = rtl8367c_setAsicSdsReg(0, 4, 0, regValue)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_getAsicSdsReg(0, 0, 2, &regValue)) != RT_ERR_OK)
+                    return retVal;
+                regValue &= 0xFFFFDFFF;
+                regValue |= 0x40;
+                if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 2, regValue)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &regValue)) != RT_ERR_OK)
+                    return retVal;
+                regValue &= 0xFFFFEFFF;
+                if( (retVal = rtl8367c_setAsicSdsReg(0, 4, 0, regValue)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 4)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0xe0, 0)) != RT_ERR_OK)
+                    return retVal;
+
+            }
+        }
+        else if (mode == EXT_100FX)
+        {
+            if (id == 1)
+            {
+                if( (retVal = rtl8367c_setAsicSdsReg(1, 1, 0x21, 0xec91)) != RT_ERR_OK)
+                    return retVal;
+                if( (retVal = rtl8367c_setAsicSdsReg(1, 5, 0x24, 0x5825)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 5)) != RT_ERR_OK)
+                    return retVal;
+
+                /*patch speed change sds1 100M*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 0x1f)) != RT_ERR_OK)
+                    return retVal;
+                if( (retVal = rtl8367c_getAsicSdsReg(1, 4, 0, &regValue)) != RT_ERR_OK)
+                    return retVal;
+                regValue &= 0xFFFF0FFF;
+                regValue |= 0xb000;
+                if( (retVal = rtl8367c_setAsicSdsReg(1, 4, 0, regValue)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_getAsicSdsReg(1, 0, 2, &regValue)) != RT_ERR_OK)
+                    return retVal;
+                regValue &= 0xFFFFFFBF;
+                regValue |= 0x2000;
+                if( (retVal = rtl8367c_setAsicSdsReg(1, 0, 2, regValue)) != RT_ERR_OK)
+                    return retVal;
+#if 0
+                if( (retVal = rtl8367c_setAsicReg(0x6214, 0x1a0)) != RT_ERR_OK)
+                    return retVal;
+#endif
+                if( (retVal = rtl8367c_getAsicSdsReg(1, 4, 0, &regValue)) != RT_ERR_OK)
+                    return retVal;
+                regValue &= 0xFFFFEFFF;
+                if( (retVal = rtl8367c_setAsicSdsReg(1, 4, 0, regValue)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 5)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x6000, 0)) != RT_ERR_OK)
+                    return retVal;
+            }
+            else if (id == 2)
+            {
+                if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 0x28, 0x942c)) != RT_ERR_OK)
+                    return retVal;
+                if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 0x24, 0x942c)) != RT_ERR_OK)
+                    return retVal;
+                if( (retVal = rtl8367c_setAsicSdsReg(0, 5, 0x21, 0x8dc3)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 5)) != RT_ERR_OK)
+                    return retVal;
+
+                /*patch speed change sds0 100M*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 0x1f)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &regValue)) != RT_ERR_OK)
+                    return retVal;
+                regValue &= 0xFFFF0FFF;
+                regValue |= 0xb000;
+                if( (retVal = rtl8367c_setAsicSdsReg(0, 4, 0, regValue)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_getAsicSdsReg(0, 0, 2, &regValue)) != RT_ERR_OK)
+                    return retVal;
+                regValue &= 0xFFFFFFBF;
+                regValue |= 0x2000;
+                if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 2, regValue)) != RT_ERR_OK)
+                    return retVal;
+
+                if( (retVal = rtl8367c_getAsicSdsReg(0, 4, 0, &regValue)) != RT_ERR_OK)
+                    return retVal;
+                regValue &= 0xFFFFEFFF;
+                if( (retVal = rtl8367c_setAsicSdsReg(0, 4, 0, regValue)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 5)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0xe0, 0)) != RT_ERR_OK)
+                    return retVal;
+            }
+        }
+        else if (mode == EXT_1000X_100FX)
+        {
+            if (id == 1)
+            {
+                if( (retVal = rtl8367c_setAsicSdsReg(1, 1, 0x21, 0xec91)) != RT_ERR_OK)
+                    return retVal;
+                if( (retVal = rtl8367c_setAsicSdsReg(1, 5, 0x24, 0x5825)) != RT_ERR_OK)
+                    return retVal;
+                if( (retVal = rtl8367c_setAsicSdsReg(1, 13, 0, 0x4616)) != RT_ERR_OK)
+                    return retVal;
+                if( (retVal = rtl8367c_setAsicSdsReg(1, 1, 0, 0xf20)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 7)) != RT_ERR_OK)
+                    return retVal;
+            }
+            else if (id == 2)
+            {
+                if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 0x28, 0x942c)) != RT_ERR_OK)
+                    return retVal;
+                if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 0x24, 0x942c)) != RT_ERR_OK)
+                    return retVal;
+                if( (retVal = rtl8367c_setAsicSdsReg(0, 5, 0x21, 0x8dc3)) != RT_ERR_OK)
+                    return retVal;
+                if( (retVal = rtl8367c_setAsicSdsReg(0, 13, 0, 0x4616)) != RT_ERR_OK)
+                    return retVal;
+                if( (retVal = rtl8367c_setAsicSdsReg(0, 1, 0, 0xf20)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 7)) != RT_ERR_OK)
+                    return retVal;
+            }
+        }
+
+    }
+    else if (3 == type)
+    {
+
+        /*restore patch, by designer. patch Tx FIFO issue, when not HSGMII 2.5G mode
+         #sds0, page 1, reg 1, bit4=0*/
+        if( (retVal = rtl8367c_getAsicSdsReg(0, 1, 1, &regValue)) != RT_ERR_OK)
+            return retVal;
+        regValue &= 0xFFFFFFEF;
+        if( (retVal = rtl8367c_setAsicSdsReg(0, 1, 1, regValue)) != RT_ERR_OK)
+            return retVal;
+
+        /*set for mac 6*/
+        if (1 == id)
+        {
+            /*force port6 linkdown*/
+            if ((retVal = rtl8367c_setAsicReg(0x137c, 0x1000)) != RT_ERR_OK)
+                    return retVal;
+
+            if ((retVal = rtl8367c_getAsicRegBit(0x1d9d, 6, &reg_data)) != RT_ERR_OK)
+                    return retVal;
+            while(reg_data == 0)
+            {
+                if ((retVal = rtl8367c_getAsicRegBit(0x1d9d, 6, &reg_data)) != RT_ERR_OK)
+                    return retVal;
+            }
+
+            if (mode == EXT_SGMII)
+            {
+                /* disable mac6 mode_ext1  mode*/
+                if ((retVal = rtl8367c_getAsicRegBit(0x1d3d, 10, &reg_data)) != RT_ERR_OK)
+                    return retVal;
+                if(reg_data == 0)
+                {
+                    if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 0)) != RT_ERR_OK)
+                        return retVal;
+                }
+                /*cfg_bypass_line_rate[1]=0*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 1, 0)) != RT_ERR_OK)
+                    return retVal;
+
+
+
+                /*bit5: cfg_mac6_fib=0    &   bit7: cfg_mac6_fib2=0*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 0)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac7_fib=0*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 1, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac7_sel_sgmii= 0: MAC7 is not SGMII mode*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 0, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*#cfg_sgmii_link=0*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 9, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac6_sel_hsgmii=0*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 0)) != RT_ERR_OK)
+                    return retVal;
+
+
+                /*bit13: cfg_sds_mode_sel_new=1 :Enable new sds mode config method*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*  bit[12:8]: Only valid when cfg_sds_mode_sel_new=1
+                    new_cfg_sds_mode=0x1F (reset mode) */
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac6_sel_sgmii= 1*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1
+                   new_cfg_sds_mode=0x12  */
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x2)) != RT_ERR_OK)
+                    return retVal;
+
+                /* MAC link source*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 2, 0)) != RT_ERR_OK)
+                    return retVal;
+
+
+            }
+            else if (mode == EXT_HSGMII)
+            {
+
+                /*restore patch, by designer. patch Tx FIFO issue, when  HSGMII 2.5G mode
+                 #sds0, page 1, reg 1, bit4=1*/
+                if( (retVal = rtl8367c_getAsicSdsReg(0, 1, 1, &regValue)) != RT_ERR_OK)
+                    return retVal;
+                regValue |= 0x10;
+                if( (retVal = rtl8367c_setAsicSdsReg(0, 1, 1, regValue)) != RT_ERR_OK)
+                    return retVal;
+
+                 /* mode_ext1 = disable*/
+                /* disable mac6 mode_ext1  mode*/
+                if ((retVal = rtl8367c_getAsicRegBit(0x1d3d, 10, &reg_data)) != RT_ERR_OK)
+                    return retVal;
+                if(reg_data == 0)
+                {
+                    if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 0)) != RT_ERR_OK)
+                        return retVal;
+                }
+
+                if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 1, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*bit5: cfg_mac6_fib=0   &   bit7: cfg_mac6_fib2=0*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 0)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac7_fib=0*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 1, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac7_sel_sgmii= 0*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 0, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac6_sel_sgmii=0*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 9, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac6_sel_hsgmii=1*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac6_sel_sgmii= 0*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((retVal = rtl8367c_setAsicReg(0xd0,7)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicReg(0x399, 7)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicReg(0x3fa, 7)) != RT_ERR_OK)
+                    return retVal;
+
+                /*bit13: cfg_sds_mode_sel_new=1 :Enable new sds mode config method*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK)
+                    return retVal;
+                /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1
+                   new_cfg_sds_mode=0x12  */
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x12)) != RT_ERR_OK)
+                    return retVal;
+                /*
+                1: MAC link = SGMII SerDes link
+                0: MAC link = SGMII config link £¨cfg_sgmii_link£©
+                */
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 2, 0)) != RT_ERR_OK)
+                    return retVal;
+
+            }
+            else if(mode == EXT_1000X)
+            {
+                /* 0 2 0  bit 8~9  set 0, force n-way*/
+                if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, &reg_data)) != RT_ERR_OK)
+                    return retVal;
+                reg_data &= 0xFFFFFCFF;
+                if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK)
+                        return retVal;
+
+                /* disable mac6 mode_ext1  mode*/
+                if ((retVal = rtl8367c_getAsicRegBit(0x1d3d, 10, &reg_data)) != RT_ERR_OK)
+                    return retVal;
+                if(reg_data == 0)
+                {
+                    if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 0)) != RT_ERR_OK)
+                        return retVal;
+                }
+
+                if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 1, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((retVal = rtl8367c_setAsicReg(0x1d11, 0x1500)) != RT_ERR_OK)
+                    return retVal;
+
+                /*bit13: cfg_sds_mode_sel_new=1 :Enable new sds mode config method
+                  bit[1:0]:cfg_mac7_fib= 0  &  cfg_mac7_sel_sgmii=0
+                */
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /* bit0 :UTP/Fiber auto detect function enable or not, cfg_dis_det=1:disable
+                   bit3:Force UTP/Fiber auto detect function enable or not, cfg_force_auto-detect=1 */
+                if ((retVal = rtl8367c_setAsicReg(0x13eb, 0x15bb)) != RT_ERR_OK)
+                    return retVal;
+
+                /*bit3:  Serdes force mode:cfg_sds_frc_mode=1
+                  bit[2:0]: Serdes chip mode, cfg_sds_mode=3b'100 (force sds FIB1G mode) */
+                if ((retVal = rtl8367c_setAsicReg(0x13e7, 0xc)) != RT_ERR_OK)
+                    return retVal;
+
+
+                /*bit5: cfg_mac6_fib=1 & bit7: cfg_mac6_fib2=1*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 1)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac6_sel_hsgmii=0*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac6_sel_sgmii= 1*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1
+                   new_cfg_sds_mode=0x4  */
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x4)) != RT_ERR_OK)
+                    return retVal;
+            }
+            else if(mode == EXT_100FX)
+            {
+                /* 0 2 0  bit 8~9  set 0, force n-way*/
+                if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, &reg_data)) != RT_ERR_OK)
+                    return retVal;
+                reg_data &= 0xFFFFFCFF;
+                if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK)
+                        return retVal;
+
+                /* disable mac6 mode_ext1  mode*/
+                if ((retVal = rtl8367c_getAsicRegBit(0x1d3d, 10, &reg_data)) != RT_ERR_OK)
+                    return retVal;
+                if(reg_data == 0)
+                {
+                    if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 0)) != RT_ERR_OK)
+                        return retVal;
+                }
+
+                if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 1, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((retVal = rtl8367c_setAsicReg(0x1d11, 0x1500)) != RT_ERR_OK)
+                    return retVal;
+
+                /*bit13: cfg_sds_mode_sel_new=1 :Enable new sds mode config method
+                  bit[1:0]:cfg_mac7_fib= 0  &  cfg_mac7_sel_sgmii=0
+                */
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /* bit0 :UTP/Fiber auto detect function enable or not, cfg_dis_det=1:disable
+                   bit3:Force UTP/Fiber auto detect function enable or not, cfg_force_auto-detect=1 */
+                if ((retVal = rtl8367c_setAsicReg(0x13eb, 0x15bb)) != RT_ERR_OK)
+                    return retVal;
+
+                /*!!!!! cfg_sds_frc_mode=1 &  cfg_sds_mode=3b'101 (force sds fib100M mode)*/
+                if ((retVal = rtl8367c_setAsicReg(0x13e7, 0xc)) != RT_ERR_OK)
+                    return retVal;
+
+
+                /*bit5: cfg_mac6_fib=1 & bit7: cfg_mac6_fib2=1*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 1)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac6_sel_hsgmii=0*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac6_sel_sgmii= 1*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*  bit[12:8]: Only valid when cfg_sds_mode_sel_new=1
+                    new_cfg_sds_mode=0x5 */
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x5)) != RT_ERR_OK)
+                    return retVal;
+            }
+            else if(mode == EXT_1000X_100FX)
+            {
+                /* 0 2 0  bit 8~9  set 0, force n-way*/
+                if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, &reg_data)) != RT_ERR_OK)
+                    return retVal;
+                reg_data &= 0xFFFFFCFF;
+                if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK)
+                        return retVal;
+
+                /* disable mac6 mode_ext1  mode*/
+                if ((retVal = rtl8367c_getAsicRegBit(0x1d3d, 10, &reg_data)) != RT_ERR_OK)
+                    return retVal;
+                if(reg_data == 0)
+                {
+                    if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 0)) != RT_ERR_OK)
+                        return retVal;
+                }
+
+                if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 1, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((retVal = rtl8367c_setAsicReg(0x1d11, 0x1500)) != RT_ERR_OK)
+                    return retVal;
+
+                /*bit13: cfg_sds_mode_sel_new=1 :Enable new sds mode config method
+                  bit[1:0]:cfg_mac7_fib= 0  &  cfg_mac7_sel_sgmii=0
+                */
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 0)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /* bit0 :UTP/Fiber auto detect function enable or not, cfg_dis_det=1:disable
+                   bit3:Force UTP/Fiber auto detect function enable or not, cfg_force_auto-detect=1 */
+                if ((retVal = rtl8367c_setAsicReg(0x13eb, 0x15bb)) != RT_ERR_OK)
+                    return retVal;
+
+                /*!!!!!! cfg_sds_frc_mode=1 &  cfg_sds_mode=3'b111: Fib1G/Fib100M auto detect */
+                if ((retVal = rtl8367c_setAsicReg(0x13e7, 0xc)) != RT_ERR_OK)
+                    return retVal;
+
+
+                /*bit5: cfg_mac6_fib=1 & bit7: cfg_mac6_fib2=1*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 1)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac6_sel_hsgmii=0*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac6_sel_sgmii= 1*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*  bit[12:8]: Only valid when cfg_sds_mode_sel_new=1
+                    new_cfg_sds_mode=0x7 */
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x7)) != RT_ERR_OK)
+                    return retVal;
+            }
+            else if(mode < EXT_SGMII)
+            {
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d3d, 10, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 1, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /* keep default setting, disable mac6 sel SerDes mode,*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 0)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*bit5: cfg_mac6_fib=0       &        bit7: cfg_mac6_fib2=0*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 0)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                if (mode < EXT_GMII)
+                {
+                    /* set mac6 mode*/
+                    if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, mode)) != RT_ERR_OK)
+                        return retVal;
+                }
+                else if(mode == EXT_RMII_MAC)
+                {
+                    /*!!!!!!*/
+                    if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 7)) != RT_ERR_OK)
+                        return retVal;
+                }
+                else if(mode == EXT_RMII_PHY)
+                {
+                    if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 8)) != RT_ERR_OK)
+                        return retVal;
+                }
+
+                if ((mode == EXT_TMII_MAC) || (mode == EXT_TMII_PHY))
+                {
+                    if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 1, 1)) != RT_ERR_OK)
+                        return retVal;
+                }
+            }
+
+        }
+        else if (2 == id)
+        {
+
+            /*force port7 linkdown*/
+            if ((retVal = rtl8367c_setAsicReg(0x137d, 0x1000)) != RT_ERR_OK)
+                    return retVal;
+
+            if ((retVal = rtl8367c_getAsicRegBit(0x1d9d, 7, &reg_data)) != RT_ERR_OK)
+                    return retVal;
+            while(reg_data == 0)
+            {
+                if ((retVal = rtl8367c_getAsicRegBit(0x1d9d, 7, &reg_data)) != RT_ERR_OK)
+                    return retVal;
+            }
+
+            if (mode == EXT_SGMII)
+            {
+                /*disable mac7 sel ext2 xMII mode*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf,0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*restore ext2 ability*/
+                if ((retVal = rtl8367c_setAsicReg(0x13c4, 0)) != RT_ERR_OK)
+                    return retVal;
+                /*  disable mac7  mode_ext2  */
+                if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*bit5: cfg_mac6_fib=0 & bit7: cfg_mac6_fib2=0*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 0)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*
+                   bit0:cfg_mac7_sel_sgmii=0,MAC7 is not SGMII mode
+                   bit1:cfg_mac7_fib= 0  */
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac6_sel_hsgmii=0*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac6_sel_sgmii= 1*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*Enable new sds mode config method, cfg_sds_mode_sel_new=1*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*  bit[12:8]: Only valid when cfg_sds_mode_sel_new=1
+                    new_cfg_sds_mode=0x1F (reset mode) */
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac7_sel_sgmii= 1*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 0, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*  bit[12:8]: Only valid when cfg_sds_mode_sel_new=1
+                    new_cfg_sds_mode=0x2 (SGMII mode)*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x2)) != RT_ERR_OK)
+                    return retVal;
+
+                /*select MAC link source when port6/7 be set sgmii mode £¨cfg_sgmii_link£©*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 2, 0)) != RT_ERR_OK)
+                    return retVal;
+            }
+            else if (mode == EXT_1000X)
+            {
+                /*  disable mac7 MII/TMM/RMII/GMII/RGMII mode, mode_ext2 = disable */
+                if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*restore ext2 ability*/
+                if ((retVal = rtl8367c_setAsicReg(0x13c4, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /* 0 2 0  bit 8~9  set 0, force n-way*/
+                if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, &reg_data)) != RT_ERR_OK)
+                    return retVal;
+                reg_data &= 0xFFFFFCFF;
+                if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK)
+                        return retVal;
+
+                /*restore ext2 ability*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*  keep default setting, disable mac6 sel serdes*/
+                if ((retVal = rtl8367c_setAsicReg(0x1d11, 0x1500)) != RT_ERR_OK)
+                    return retVal;
+
+                /*Enable new sds mode config method, cfg_sds_mode_sel_new=1*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*  bit[12:8]: Only valid when cfg_sds_mode_sel_new=1
+                    new_cfg_sds_mode=0x1F (reset mode) */
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK)
+                    return retVal;
+
+                /*bit5: cfg_mac6_fib=0         &        bit7: cfg_mac6_fib2=0*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 0)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac7_sel_sgmii= 1 & cfg_mac7_fib=1*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 3)) != RT_ERR_OK)
+                    return retVal;
+
+                /*new_cfg_sds_mode=0x4 (FIB1000 mode)*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x4)) != RT_ERR_OK)
+                    return retVal;
+
+            }
+            else if (mode == EXT_100FX)
+            {
+                /*  disable mac7 MII/TMM/RMII/GMII/RGMII mode, mode_ext2 = disable  */
+                if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*restore ext2 ability*/
+                if ((retVal = rtl8367c_setAsicReg(0x13c4, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /* 0 2 0  bit 8~9  set 0, force n-way*/
+                if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, &reg_data)) != RT_ERR_OK)
+                    return retVal;
+                reg_data &= 0xFFFFFCFF;
+                if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK)
+                        return retVal;
+
+                /*restore ext2 ability*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /* keep default setting, disable mac6 sel serdes*/
+                if ((retVal = rtl8367c_setAsicReg(0x1d11, 0x1500)) != RT_ERR_OK)
+                    return retVal;
+
+                /*Enable new sds mode config method, cfg_sds_mode_sel_new=1*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*  bit[12:8]: Only valid when cfg_sds_mode_sel_new=1
+                    new_cfg_sds_mode=0x1F (reset mode) */
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK)
+                    return retVal;
+
+                /*bit5: cfg_mac6_fib=0       &       bit7: cfg_mac6_fib2=0*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 0)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac7_sel_sgmii= 1 & cfg_mac7_fib=1*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 3)) != RT_ERR_OK)
+                    return retVal;
+
+                /*  bit[12:8]: Only valid when cfg_sds_mode_sel_new=1
+                    new_cfg_sds_mode=0x5  */
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x5)) != RT_ERR_OK)
+                    return retVal;
+            }
+            else if (mode == EXT_1000X_100FX)
+            {
+                /*  disable mac7 MII/TMM/RMII/GMII/RGMII mode, mode_ext2 = disable  */
+                if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*restore ext2 ability*/
+                if ((retVal = rtl8367c_setAsicReg(0x13c4, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /* 0 2 0  bit 8~9  set 0, force n-way*/
+                if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, &reg_data)) != RT_ERR_OK)
+                    return retVal;
+                reg_data &= 0xFFFFFCFF;
+                if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK)
+                        return retVal;
+
+                /*restore ext2 ability*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /* keep default setting, disable mac6 sel serdes*/
+                if ((retVal = rtl8367c_setAsicReg(0x1d11, 0x1500)) != RT_ERR_OK)
+                    return retVal;
+
+                /*Enable new sds mode config method, cfg_sds_mode_sel_new=1*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                /*  bit[12:8]: Only valid when cfg_sds_mode_sel_new=1
+                    new_cfg_sds_mode=0x1F (reset mode) */
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK)
+                    return retVal;
+
+                /*bit5: cfg_mac6_fib=0    &    bit7: cfg_mac6_fib2=0*/
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 0)) != RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac7_sel_sgmii= 1 & cfg_mac7_fib=1*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 3)) != RT_ERR_OK)
+                    return retVal;
+
+                /*  bit[12:8]: Only valid when cfg_sds_mode_sel_new=1
+                    new_cfg_sds_mode=0x7  */
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x7)) != RT_ERR_OK)
+                    return retVal;
+            }
+            else if (mode < EXT_SGMII)
+            {
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d3d, 10, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /* keep default setting, disable mac7 sel SerDes mode*/
+                if ((retVal = rtl8367c_setAsicReg(0x1d95, 0x1f00)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac7_sel_sgmii= 0 & cfg_mac7_fib=0*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /* set port7 mode*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, mode)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((mode == EXT_TMII_MAC) || (mode == EXT_TMII_PHY))
+                {
+                    if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 1)) != RT_ERR_OK)
+                        return retVal;
+                }
+
+            }
+            else if ((mode < EXT_END) && (mode > EXT_100FX))
+            {
+                if ((retVal = rtl8367c_setAsicRegBits(0x13C3, 0xf, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                /*cfg_mac7_sel_sgmii= 0 & cfg_mac7_fib=0*/
+                if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 0)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((retVal = rtl8367c_setAsicRegBit(0x1d3d, 10, 1)) != RT_ERR_OK)
+                    return retVal;
+
+                if ((retVal = rtl8367c_getAsicRegBit(0x1d11, 11, &reg_data)) != RT_ERR_OK)
+                    return retVal;
+                if(reg_data == 0)
+                {
+                    if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 1)) != RT_ERR_OK)
+                        return retVal;
+                }
+
+                /* set port7 mode*/
+                if (mode < EXT_RMII_MAC_2)
+                {
+                    if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, (mode-13))) != RT_ERR_OK)
+                        return retVal;
+                }
+                else
+                {
+                    if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, (mode-12))) != RT_ERR_OK)
+                        return retVal;
+                }
+
+                if ((mode == EXT_TMII_MAC_2) || (mode == EXT_TMII_PHY_2))
+                {
+                    if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 1)) != RT_ERR_OK)
+                        return retVal;
+                }
+            }
+
+        }
+
+    }
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortExtMode
+ * Description:
+ *      Get external interface mode configuration
+ * Input:
+ *      id      - external interface id (0~1)
+ *      pMode   - external interface mode
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortExtMode(rtk_uint32 id, rtk_uint32 *pMode)
+{
+    ret_t   retVal;
+    rtk_uint32 regData, regValue, type;
+
+    if(id >= RTL8367C_EXTNO)
+        return RT_ERR_OUT_OF_RANGE;
+    /*cfg_magic_id  &  get chip_id*/
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_getAsicReg(0x1300, &regValue)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK)
+        return retVal;
+
+    type = 0;
+
+    switch (regValue)
+    {
+        case 0x0276:
+        case 0x0597:
+        case 0x6367:
+            type = 1;
+            break;
+        case 0x0652:
+        case 0x6368:
+            type = 2;
+            break;
+        case 0x0801:
+        case 0x6511:
+            type = 3;
+            break;
+        default:
+            return RT_ERR_FAILED;
+    }
+
+
+    if (1 == type)
+    {
+
+        if (1 == id)
+        {
+            if( (retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            if(1 == regData)
+            {
+                *pMode = EXT_SGMII;
+                return RT_ERR_OK;
+            }
+
+            if( (retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            if(1 == regData)
+            {
+                *pMode = EXT_HSGMII;
+                return RT_ERR_OK;
+            }
+        }
+
+        if(0 == id || 1 == id)
+            return rtl8367c_getAsicRegBits(RTL8367C_REG_DIGITAL_INTERFACE_SELECT, RTL8367C_SELECT_GMII_0_MASK << (id * RTL8367C_SELECT_GMII_1_OFFSET), pMode);
+        else
+           return rtl8367c_getAsicRegBits(RTL8367C_REG_DIGITAL_INTERFACE_SELECT_1, RTL8367C_SELECT_GMII_2_MASK, pMode);
+
+    }
+    else if (2 == type)
+    {
+        if (1 == id)
+        {
+            if ((retVal = rtl8367c_getAsicReg(0x1d92, &regData))!=RT_ERR_OK)
+                return retVal;
+
+            if (regData & 0x4000)
+            {
+                *pMode = EXT_SGMII;
+                return RT_ERR_OK;
+            }
+
+            else if (((regData >> 8) & 0x1f) == 4)
+            {
+                *pMode = EXT_1000X;
+                return RT_ERR_OK;
+            }
+            else if (((regData >> 8) & 0x1f) == 5)
+            {
+                *pMode = EXT_100FX;
+                return RT_ERR_OK;
+            }
+            else if (((regData >> 8) & 0x1f) == 7)
+            {
+                *pMode = EXT_1000X_100FX;
+                return RT_ERR_OK;
+            }
+
+            return rtl8367c_getAsicRegBits(0x1305, 0xf0, pMode);
+        }
+        else if (2 == id)
+        {
+#if 0
+            if ((retVal = rtl8367c_getAsicRegBit(0x1d92, 6, &regData))!=RT_ERR_OK)
+                return retVal;
+
+            if (regData == 1)
+            {
+                *pMode = EXT_SGMII;
+                return RT_ERR_OK;
+            }
+
+            if ((retVal = rtl8367c_getAsicRegBit(0x1d92, 7, &regData))!=RT_ERR_OK)
+                return retVal;
+
+            if (regData == 1)
+            {
+                *pMode = EXT_HSGMII;
+                return RT_ERR_OK;
+            }
+#endif
+            if ((retVal = rtl8367c_getAsicReg(0x1d92, &regData))!=RT_ERR_OK)
+                return retVal;
+
+            if (regData & 0x40)
+            {
+                *pMode = EXT_SGMII;
+                return RT_ERR_OK;
+            }
+            else if (regData & 0x80)
+            {
+                *pMode = EXT_HSGMII;
+                return RT_ERR_OK;
+            }
+            else if ((regData & 0x1f) == 4)
+            {
+                *pMode = EXT_1000X;
+                return RT_ERR_OK;
+            }
+            else if ((regData & 0x1f) == 5)
+            {
+                *pMode = EXT_100FX;
+                return RT_ERR_OK;
+            }
+            else if ((regData & 0x1f) == 7)
+            {
+                *pMode = EXT_1000X_100FX;
+                return RT_ERR_OK;
+            }
+
+            return rtl8367c_getAsicRegBits(0x1305, 0xf, pMode);
+        }
+    }
+    else if(3 == type)
+    {
+        if (1 == id)
+        {
+            /* SDS_CFG_NEW */
+            if ((retVal = rtl8367c_getAsicReg(0x1d95, &regData))!=RT_ERR_OK)
+                return retVal;
+
+            if ((retVal = rtl8367c_getAsicReg(0x1d41, &regValue))!=RT_ERR_OK)
+                return retVal;
+
+            /* bit5: cfg_mac6_fib=1  &&  bit7: cfg_mac6_fib2 =1 */
+            if((regValue & 0xa0)  == 0xa0 )
+            {
+                /* new_cfg_sds_mode */
+                regData = regData >> 8;
+                if((regData & 0x1f) == 4)
+                {
+                    *pMode = EXT_1000X;
+                     return RT_ERR_OK;
+                }
+                else if((regData & 0x1f) == 5)
+                {
+                    *pMode = EXT_100FX;
+                     return RT_ERR_OK;
+                }
+                else if((regData & 0x1f) == 7)
+                {
+                    *pMode = EXT_1000X_100FX;
+                     return RT_ERR_OK;
+                }
+
+            }
+
+
+            if ((retVal = rtl8367c_getAsicReg(0x1d11, &regData))!=RT_ERR_OK)
+                return retVal;
+
+            /* check cfg_mac6_sel_sgmii */
+            if((regData >> 6) & 1)
+            {
+                *pMode = EXT_SGMII;
+                return RT_ERR_OK;
+            }
+            else if((regData >> 11) & 1)
+            {
+                *pMode = EXT_HSGMII;
+                return RT_ERR_OK;
+            }
+            else
+            {
+                /* check port6 MAC mode */
+                if ((retVal = rtl8367c_getAsicRegBits(0x1305, 0xf0, &regData))!=RT_ERR_OK)
+                    return retVal;
+
+                if(regData < 6)
+                    *pMode = regData;
+                else if(regData == 6)
+                    *pMode = EXT_RMII_MAC;
+                else if(regData == 7)
+                    *pMode = EXT_RMII_PHY;
+
+                return RT_ERR_OK;
+            }
+        }
+        else if (2 == id)
+        {
+            if ((retVal = rtl8367c_getAsicReg(0x1d95, &regData))!=RT_ERR_OK)
+                return retVal;
+
+            /* bit0: cfg_mac7_sel_sgmii
+               bit1: cfg_mac7_fib
+               bit[12:8]: new_cfg_sds_mode*/
+            if(((regData & 0x3) == 3) && (((regData >> 8) & 0x1f) == 0x4))
+            {
+                *pMode = EXT_1000X;
+                    return RT_ERR_OK;
+            }
+            else if (((regData & 0x3) == 3) && (((regData >> 8) & 0x1f) == 0x5))
+            {
+                *pMode = EXT_100FX;
+                    return RT_ERR_OK;
+            }
+            else if (((regData & 0x3) == 3) && (((regData >> 8) & 0x1f) == 0x7))
+            {
+                *pMode = EXT_1000X_100FX;
+                    return RT_ERR_OK;
+            }
+            else if(regData & 1)
+            {
+                *pMode = EXT_SGMII;
+                return RT_ERR_OK;
+            }
+            else
+            {
+            /* check port7 MAC mode */
+                if ((retVal = rtl8367c_getAsicRegBits(0x13c3, 0xf, &regData))!=RT_ERR_OK)
+                    return retVal;
+
+                *pMode = regData;
+
+                return RT_ERR_OK;
+            }
+        }
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8370_setAsicPortEnableAll
+ * Description:
+ *      Set ALL ports enable.
+ * Input:
+ *      enable - enable all ports.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortEnableAll(rtk_uint32 enable)
+{
+    if(enable >= 2)
+        return RT_ERR_INPUT;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_PHY_AD, RTL8367C_PDNPHY_OFFSET, !enable);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicPortEnableAll
+ * Description:
+ *      Set ALL ports enable.
+ * Input:
+ *      enable - enable all ports.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortEnableAll(rtk_uint32 *pEnable)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+
+    retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_PHY_AD, RTL8367C_PDNPHY_OFFSET, &regData);
+    if(retVal !=  RT_ERR_OK)
+        return retVal;
+
+    if (regData==0)
+        *pEnable = 1;
+    else
+        *pEnable = 0;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicPortSmallIpg
+ * Description:
+ *      Set small ipg egress mode
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      enable  - 0: normal, 1: small
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortSmallIpg(rtk_uint32 port, rtk_uint32 enable)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_PORT_SMALL_IPG_REG(port), RTL8367C_PORT0_MISC_CFG_SMALL_TAG_IPG_OFFSET, enable);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicPortSmallIpg
+ * Description:
+ *      Get small ipg egress mode
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pEnable     - 0: normal, 1: small
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortSmallIpg(rtk_uint32 port, rtk_uint32* pEnable)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_PORT_SMALL_IPG_REG(port), RTL8367C_PORT0_MISC_CFG_SMALL_TAG_IPG_OFFSET, pEnable);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicPortLoopback
+ * Description:
+ *      Set MAC loopback
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      enable  - 0: Disable, 1: enable
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortLoopback(rtk_uint32 port, rtk_uint32 enable)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_PORT_MISC_CFG_REG(port), RTL8367C_PORT0_MISC_CFG_MAC_LOOPBACK_OFFSET, enable);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicPortLoopback
+ * Description:
+ *      Set MAC loopback
+ * Input:
+ *      port    - Physical port number (0~7)
+ * Output:
+ *      pEnable - 0: Disable, 1: enable
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortLoopback(rtk_uint32 port, rtk_uint32 *pEnable)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_PORT_MISC_CFG_REG(port), RTL8367C_PORT0_MISC_CFG_MAC_LOOPBACK_OFFSET, pEnable);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicPortRTCTEnable
+ * Description:
+ *      Set RTCT Enable echo response mode
+ * Input:
+ *      portmask    - Port mask of RTCT enabled (0-4)
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK    - Invalid port mask
+ * Note:
+ *      RTCT test takes 4.8 seconds at most.
+ */
+ret_t rtl8367c_setAsicPortRTCTEnable(rtk_uint32 portmask)
+{
+    ret_t       retVal;
+    rtk_uint32  regData;
+    rtk_uint32  port;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_getAsicReg(0x1300, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    if( (regData == 0x0276) || (regData == 0x0597) )
+        return RT_ERR_CHIP_NOT_SUPPORTED;
+
+    for(port = 0; port <= 10 ; port++)
+    {
+        if(portmask & (0x0001 << port))
+        {
+             if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa422, &regData)) != RT_ERR_OK)
+                 return retVal;
+
+             regData &= 0x7FFF;
+             if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa422, regData)) != RT_ERR_OK)
+                 return retVal;
+
+             regData |= 0x00F2;/*RTCT set to  echo response mode*/
+             if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa422, regData)) != RT_ERR_OK)
+                 return retVal;
+
+             regData |= 0x0001;
+             if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa422, regData)) != RT_ERR_OK)
+                 return retVal;
+        }
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicPortRTCTDisable
+ * Description:
+ *      Set RTCT Disable
+ * Input:
+ *      portmask    - Port mask of RTCT enabled (0-4)
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK    - Invalid port mask
+ * Note:
+ *      RTCT test takes 4.8 seconds at most.
+ */
+ret_t rtl8367c_setAsicPortRTCTDisable(rtk_uint32 portmask)
+{
+    ret_t       retVal;
+    rtk_uint32  regData;
+    rtk_uint32  port;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_getAsicReg(0x1300, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    if( (regData == 0x0276) || (regData == 0x0597) )
+        return RT_ERR_CHIP_NOT_SUPPORTED;
+
+    for(port = 0; port <= 10 ; port++)
+    {
+        if(portmask & (0x0001 << port))
+        {
+             if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa422, &regData)) != RT_ERR_OK)
+                 return retVal;
+
+             regData &= 0x7FFF;
+             if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa422, regData)) != RT_ERR_OK)
+                 return retVal;
+
+             regData |= 0x00F0;
+             if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa422, regData)) != RT_ERR_OK)
+                 return retVal;
+
+             regData &= ~0x0001;
+             if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa422, regData)) != RT_ERR_OK)
+                 return retVal;
+        }
+    }
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtl8367c_getAsicPortRTCTResult
+ * Description:
+ *      Get RTCT result
+ * Input:
+ *      port    - Port ID of RTCT result
+ * Output:
+ *      pResult - The result of port ID
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_MASK            - Invalid port mask
+ *      RT_ERR_PHY_RTCT_NOT_FINISH  - RTCT test doesn't finish.
+ * Note:
+ *      RTCT test takes 4.8 seconds at most.
+ *      If this API returns RT_ERR_PHY_RTCT_NOT_FINISH,
+ *      users should wait a whole then read it again.
+ */
+ret_t rtl8367c_getAsicPortRTCTResult(rtk_uint32 port, rtl8367c_port_rtct_result_t *pResult)
+{
+    ret_t       retVal;
+    rtk_uint32  regData, finish = 1;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_getAsicReg(0x1300, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    if( (regData == 0x6367) )
+    {
+        if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa422, &regData)) != RT_ERR_OK)
+            return retVal;
+
+        if((regData & 0x8000) == 0x8000)
+        {
+            /* Channel A */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802a)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelAOpen       = (regData == 0x0048) ? 1 : 0;
+            pResult->channelAShort      = (regData == 0x0050) ? 1 : 0;
+            pResult->channelAMismatch   = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0;
+            pResult->channelALinedriver = (regData == 0x0041) ? 1 : 0;
+
+            /* Channel B */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802e)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelBOpen       = (regData == 0x0048) ? 1 : 0;
+            pResult->channelBShort      = (regData == 0x0050) ? 1 : 0;
+            pResult->channelBMismatch   = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0;
+            pResult->channelBLinedriver = (regData == 0x0041) ? 1 : 0;
+
+            /* Channel C */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8032)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelCOpen       = (regData == 0x0048) ? 1 : 0;
+            pResult->channelCShort      = (regData == 0x0050) ? 1 : 0;
+            pResult->channelCMismatch   = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0;
+            pResult->channelCLinedriver = (regData == 0x0041) ? 1 : 0;
+
+            /* Channel D */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8036)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelDOpen       = (regData == 0x0048) ? 1 : 0;
+            pResult->channelDShort      = (regData == 0x0050) ? 1 : 0;
+            pResult->channelDMismatch   = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0;
+            pResult->channelDLinedriver = (regData == 0x0041) ? 1 : 0;
+
+            /* Channel A Length */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802c)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelALen = (regData / 2);
+
+            /* Channel B Length */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8030)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelBLen = (regData / 2);
+
+            /* Channel C Length */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8034)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelCLen = (regData / 2);
+
+            /* Channel D Length */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8038)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelDLen = (regData / 2);
+        }
+        else
+            finish = 0;
+    }
+    else if(regData == 0x6368)
+    {
+        if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa422, &regData)) != RT_ERR_OK)
+            return retVal;
+
+        if((regData & 0x8000) == 0x8000)
+        {
+            /* Channel A */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802b)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelAOpen       = (regData == 0x0048) ? 1 : 0;
+            pResult->channelAShort      = (regData == 0x0050) ? 1 : 0;
+            pResult->channelAMismatch   = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0;
+            pResult->channelALinedriver = (regData == 0x0041) ? 1 : 0;
+
+            /* Channel B */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802f)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelBOpen       = (regData == 0x0048) ? 1 : 0;
+            pResult->channelBShort      = (regData == 0x0050) ? 1 : 0;
+            pResult->channelBMismatch   = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0;
+            pResult->channelBLinedriver = (regData == 0x0041) ? 1 : 0;
+
+            /* Channel C */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8033)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelCOpen       = (regData == 0x0048) ? 1 : 0;
+            pResult->channelCShort      = (regData == 0x0050) ? 1 : 0;
+            pResult->channelCMismatch   = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0;
+            pResult->channelCLinedriver = (regData == 0x0041) ? 1 : 0;
+
+            /* Channel D */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8037)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelDOpen       = (regData == 0x0048) ? 1 : 0;
+            pResult->channelDShort      = (regData == 0x0050) ? 1 : 0;
+            pResult->channelDMismatch   = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0;
+            pResult->channelDLinedriver = (regData == 0x0041) ? 1 : 0;
+
+            /* Channel A Length */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802d)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelALen = (regData / 2);
+
+            /* Channel B Length */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8031)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelBLen = (regData / 2);
+
+            /* Channel C Length */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8035)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelCLen = (regData / 2);
+
+            /* Channel D Length */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8039)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelDLen = (regData / 2);
+        }
+        else
+            finish = 0;
+
+    }
+    else if((regData == 0x6511) || (regData == 0x0801))
+    {
+        if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa422, &regData)) != RT_ERR_OK)
+            return retVal;
+
+        if((regData & 0x8000) == 0x8000)
+        {
+            /* Channel A */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802a)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelAOpen       = (regData == 0x0048) ? 1 : 0;
+            pResult->channelAShort      = (regData == 0x0050) ? 1 : 0;
+            pResult->channelAMismatch   = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0;
+            pResult->channelALinedriver = (regData == 0x0041) ? 1 : 0;
+
+            /* Channel B */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802e)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelBOpen       = (regData == 0x0048) ? 1 : 0;
+            pResult->channelBShort      = (regData == 0x0050) ? 1 : 0;
+            pResult->channelBMismatch   = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0;
+            pResult->channelBLinedriver = (regData == 0x0041) ? 1 : 0;
+
+            /* Channel C */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8032)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelCOpen       = (regData == 0x0048) ? 1 : 0;
+            pResult->channelCShort      = (regData == 0x0050) ? 1 : 0;
+            pResult->channelCMismatch   = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0;
+            pResult->channelCLinedriver = (regData == 0x0041) ? 1 : 0;
+
+            /* Channel D */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8036)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelDOpen       = (regData == 0x0048) ? 1 : 0;
+            pResult->channelDShort      = (regData == 0x0050) ? 1 : 0;
+            pResult->channelDMismatch   = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0;
+            pResult->channelDLinedriver = (regData == 0x0041) ? 1 : 0;
+
+            /* Channel A Length */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802c)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelALen = (regData / 2);
+
+            /* Channel B Length */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8030)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelBLen = (regData / 2);
+
+            /* Channel C Length */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8034)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelCLen = (regData / 2);
+
+            /* Channel D Length */
+            if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8038)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, &regData)) != RT_ERR_OK)
+                return retVal;
+
+            pResult->channelDLen = (regData / 2);
+        }
+        else
+            finish = 0;
+
+    }
+    else
+        return RT_ERR_CHIP_NOT_SUPPORTED;
+
+    if(finish == 0)
+        return RT_ERR_PHY_RTCT_NOT_FINISH;
+    else
+        return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_sdsReset
+ * Description:
+ *      Reset Serdes
+ * Input:
+ *      id  - EXT ID
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ * Note:
+ *      None.
+ */
+ret_t rtl8367c_sdsReset(rtk_uint32 id)
+{
+    rtk_uint32 retVal, regValue, state, i, option, running = 0, retVal2;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_getAsicReg(0x1300, &regValue)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK)
+        return retVal;
+
+    switch (regValue)
+    {
+        case 0x0276:
+        case 0x0597:
+        case 0x6367:
+            option = 0;
+            break;
+        case 0x0652:
+        case 0x6368:
+            option = 1;
+            break;
+        case 0x0801:
+        case 0x6511:
+            option = 2;
+            break;
+        default:
+            return RT_ERR_FAILED;
+    }
+
+    if(option == 0)
+    {
+        if (1 == id)
+        {
+            if ((retVal = rtl8367c_getAsicRegBit(0x130c, 5, &running))!=RT_ERR_OK)
+                return retVal;
+
+            if(running == 1)
+            {
+                if ((retVal = rtl8367c_setAsicRegBit(0x130c, 5, 0))!=RT_ERR_OK)
+                    return retVal;
+            }
+
+            retVal = rtl8367c_setAsicReg(0x6601, 0x0000);
+
+            if(retVal == RT_ERR_OK)
+                retVal = rtl8367c_setAsicReg(0x6602, 0x1401);
+
+            if(retVal == RT_ERR_OK)
+                retVal = rtl8367c_setAsicReg(0x6600, 0x00C0);
+
+            if(retVal == RT_ERR_OK)
+                retVal = rtl8367c_setAsicReg(0x6601, 0x0000);
+
+            if(retVal == RT_ERR_OK)
+                retVal = rtl8367c_setAsicReg(0x6602, 0x1403);
+
+            if(retVal == RT_ERR_OK)
+                retVal = rtl8367c_setAsicReg(0x6600, 0x00C0);
+
+            if(running == 1)
+            {
+                if ((retVal2 = rtl8367c_setAsicRegBit(0x130c, 5, 1))!=RT_ERR_OK)
+                    return retVal2;
+            }
+
+            if(retVal != RT_ERR_OK)
+                return retVal;
+        }
+        else
+            return RT_ERR_PORT_ID;
+    }
+    else if(option == 1)
+    {
+        if (1 == id)
+        {
+            if((retVal = rtl8367c_getAsicReg(0x1311, &state)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicReg(0x1311, 0x66)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicReg(0x1311, 0x1066)) != RT_ERR_OK)
+                return retVal;
+
+            while(1)
+            {
+                if((retVal = rtl8367c_getAsicReg(0x1d9d, &regValue)) != RT_ERR_OK)
+                    return retVal;
+                if((regValue >> 8) & 1)
+                    break;
+            }
+
+            for (i=0; i<0xffff; i++);
+
+            if((retVal = rtl8367c_setAsicReg(0x133d, 0x2)) != RT_ERR_OK)
+                return retVal;
+
+            for (i=0; i<0xffff; i++);
+
+            if((retVal = rtl8367c_setAsicReg(0x6601, 0x0)) != RT_ERR_OK)
+                return retVal;
+            if((retVal = rtl8367c_setAsicReg(0x6602, 0x1401)) != RT_ERR_OK)
+                return retVal;
+            if((retVal = rtl8367c_setAsicReg(0x6600, 0xc1)) != RT_ERR_OK)
+                return retVal;
+            if((retVal = rtl8367c_setAsicReg(0x6601, 0x0)) != RT_ERR_OK)
+                return retVal;
+            if((retVal = rtl8367c_setAsicReg(0x6602, 0x1403)) != RT_ERR_OK)
+                return retVal;
+            if((retVal = rtl8367c_setAsicReg(0x6600, 0xc1)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicReg(0x133d, 0x0)) != RT_ERR_OK)
+                return retVal;
+
+            for (i=0; i<0xffff; i++);
+
+            if((retVal = rtl8367c_setAsicReg(0x1311, state)) != RT_ERR_OK)
+                return retVal;
+
+
+        }
+        else if (2== id)
+        {
+            if((retVal = rtl8367c_getAsicReg(0x13c4, &state)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicReg(0x13c4, 0x66)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicReg(0x13c4, 0x1066)) != RT_ERR_OK)
+                return retVal;
+
+            while(1)
+            {
+                if((retVal = rtl8367c_getAsicReg(0x1d9d, &regValue)) != RT_ERR_OK)
+                    return retVal;
+                if((regValue >> 9) & 1)
+                    break;
+            }
+
+            for (i=0; i<0xffff; i++);
+
+            if((retVal = rtl8367c_setAsicReg(0x133d, 0x2)) != RT_ERR_OK)
+                return retVal;
+
+            for (i=0; i<0xffff; i++);
+
+            if((retVal = rtl8367c_setAsicReg(0x6601, 0x0)) != RT_ERR_OK)
+                return retVal;
+            if((retVal = rtl8367c_setAsicReg(0x6602, 0x1401)) != RT_ERR_OK)
+                return retVal;
+            if((retVal = rtl8367c_setAsicReg(0x6600, 0xc0)) != RT_ERR_OK)
+                return retVal;
+            if((retVal = rtl8367c_setAsicReg(0x6601, 0x0)) != RT_ERR_OK)
+                return retVal;
+            if((retVal = rtl8367c_setAsicReg(0x6602, 0x1403)) != RT_ERR_OK)
+                return retVal;
+            if((retVal = rtl8367c_setAsicReg(0x6600, 0xc0)) != RT_ERR_OK)
+                return retVal;
+
+            if((retVal = rtl8367c_setAsicReg(0x133d, 0x0)) != RT_ERR_OK)
+                return retVal;
+
+            for (i=0; i<0xffff; i++);
+
+            if((retVal = rtl8367c_setAsicReg(0x13c4, state)) != RT_ERR_OK)
+                return retVal;
+        }
+        else
+            return RT_ERR_PORT_ID;
+    }
+    else if(option == 2)
+    {
+        if ((retVal = rtl8367c_getAsicSdsReg(0, 3, 0, &regValue))!=RT_ERR_OK)
+                  return retVal;
+              regValue |= 0x40;
+              if ((retVal = rtl8367c_setAsicSdsReg(0, 3, 0, regValue))!=RT_ERR_OK)
+                  return retVal;
+
+              for (i=0; i<0xffff; i++);
+
+              regValue &= ~(0x40);
+              if ((retVal = rtl8367c_setAsicSdsReg(0, 3, 0, regValue))!=RT_ERR_OK)
+                  return retVal;
+
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getSdsLinkStatus
+ * Description:
+ *      Get SGMII status
+ * Input:
+ *      id  - EXT ID
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ * Note:
+ *      None.
+ */
+ret_t rtl8367c_getSdsLinkStatus(rtk_uint32 ext_id, rtk_uint32 *pSignalDetect, rtk_uint32 *pSync, rtk_uint32 *pLink)
+{
+    rtk_uint32 retVal, regValue, type, running = 0, retVal2;
+
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_getAsicReg(0x1300, &regValue)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK)
+        return retVal;
+
+    switch (regValue)
+    {
+        case 0x0276:
+        case 0x0597:
+        case 0x6367:
+            type = 0;
+            break;
+        case 0x0652:
+        case 0x6368:
+            type = 1;
+            break;
+        case 0x0801:
+        case 0x6511:
+            type = 2;
+            break;
+        default:
+            return RT_ERR_FAILED;
+    }
+
+    if(type == 0)
+    {
+        if (1 == ext_id)
+        {
+            if ((retVal = rtl8367c_getAsicRegBit(0x130c, 5, &running))!=RT_ERR_OK)
+                return retVal;
+
+            if(running == 1)
+            {
+                if ((retVal = rtl8367c_setAsicRegBit(0x130c, 5, 0))!=RT_ERR_OK)
+                    return retVal;
+            }
+
+            retVal = rtl8367c_setAsicReg(0x6601, 0x003D);
+
+            if(retVal == RT_ERR_OK)
+                retVal = rtl8367c_setAsicReg(0x6600, 0x0080);
+
+            if(retVal == RT_ERR_OK)
+                retVal = rtl8367c_getAsicReg(0x6602, &regValue);
+
+            if(running == 1)
+            {
+                if ((retVal2 = rtl8367c_setAsicRegBit(0x130c, 5, 1))!=RT_ERR_OK)
+                    return retVal2;
+            }
+
+            if(retVal != RT_ERR_OK)
+                return retVal;
+
+            *pSignalDetect = (regValue & 0x0100) ? 1 : 0;
+            *pSync = (regValue & 0x0001) ? 1 : 0;
+            *pLink = (regValue & 0x0010) ? 1 : 0;
+        }
+        else
+            return RT_ERR_PORT_ID;
+    }
+    else if(type == 1)
+    {
+        if (1 == ext_id)
+        {
+            if ((retVal = rtl8367c_setAsicReg(0x6601, 0x003D))!=RT_ERR_OK)
+                return retVal;
+            if ((retVal = rtl8367c_setAsicReg(0x6600, 0x0081))!=RT_ERR_OK)
+                return retVal;
+            if ((retVal = rtl8367c_getAsicReg(0x6602, &regValue))!=RT_ERR_OK)
+                return retVal;
+
+            *pSignalDetect = (regValue & 0x0100) ? 1 : 0;
+            *pSync = (regValue & 0x0001) ? 1 : 0;
+            *pLink = (regValue & 0x0010) ? 1 : 0;
+        }
+        else if (2 == ext_id)
+        {
+            if ((retVal = rtl8367c_setAsicReg(0x6601, 0x003D))!=RT_ERR_OK)
+                return retVal;
+            if ((retVal = rtl8367c_setAsicReg(0x6600, 0x0080))!=RT_ERR_OK)
+                return retVal;
+            if ((retVal = rtl8367c_getAsicReg(0x6602, &regValue))!=RT_ERR_OK)
+                return retVal;
+
+            *pSignalDetect = (regValue & 0x0100) ? 1 : 0;
+            *pSync = (regValue & 0x0001) ? 1 : 0;
+            *pLink = (regValue & 0x0010) ? 1 : 0;
+        }
+        else
+            return RT_ERR_PORT_ID;
+    }
+    else if(type == 2)
+    {
+        if((retVal = rtl8367c_getAsicSdsReg(0, 30, 1, &regValue)) != RT_ERR_OK)
+            return retVal;
+        if((retVal = rtl8367c_getAsicSdsReg(0, 30, 1, &regValue)) != RT_ERR_OK)
+            return retVal;
+
+        *pSignalDetect = (regValue & 0x0100) ? 1 : 0;
+        *pSync = (regValue & 0x0001) ? 1 : 0;
+        *pLink = (regValue & 0x0010) ? 1 : 0;
+
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setSgmiiNway
+ * Description:
+ *      Set SGMII Nway
+ * Input:
+ *      ext_id      - EXT ID
+ *      state       - SGMII Nway state
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ * Note:
+ *      None.
+ */
+ret_t rtl8367c_setSgmiiNway(rtk_uint32 ext_id, rtk_uint32 state)
+{
+    rtk_uint32 retVal, regValue, type, running = 0, retVal2;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_getAsicReg(0x1300, &regValue)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK)
+        return retVal;
+
+    switch (regValue)
+    {
+        case 0x0276:
+        case 0x0597:
+        case 0x6367:
+            type = 0;
+            break;
+        case 0x0652:
+        case 0x6368:
+            type = 1;
+            break;
+        case 0x0801:
+        case 0x6511:
+            type = 2;
+            break;
+        default:
+            return RT_ERR_FAILED;
+    }
+
+    if(type == 0)
+    {
+        if (1 == ext_id)
+        {
+            if ((retVal = rtl8367c_getAsicRegBit(0x130c, 5, &running))!=RT_ERR_OK)
+                return retVal;
+
+            if(running == 1)
+            {
+                if ((retVal = rtl8367c_setAsicRegBit(0x130c, 5, 0))!=RT_ERR_OK)
+                    return retVal;
+            }
+
+            retVal = rtl8367c_setAsicReg(0x6601, 0x0002);
+
+            if(retVal == RT_ERR_OK)
+                retVal = rtl8367c_setAsicReg(0x6600, 0x0080);
+
+            if(retVal == RT_ERR_OK)
+                retVal = rtl8367c_getAsicReg(0x6602, &regValue);
+
+            if(retVal == RT_ERR_OK)
+            {
+                if(state)
+                      regValue |= 0x0200;
+                else
+                      regValue &= ~0x0200;
+
+                regValue |= 0x0100;
+            }
+
+            if(retVal == RT_ERR_OK)
+                retVal = rtl8367c_setAsicReg(0x6602, regValue);
+
+            if(retVal == RT_ERR_OK)
+                retVal = rtl8367c_setAsicReg(0x6601, 0x0002);
+
+            if(retVal == RT_ERR_OK)
+                retVal = rtl8367c_setAsicReg(0x6600, 0x00C0);
+
+            if(running == 1)
+            {
+                if ((retVal2 = rtl8367c_setAsicRegBit(0x130c, 5, 1))!=RT_ERR_OK)
+                    return retVal2;
+            }
+
+            if(retVal != RT_ERR_OK)
+                return retVal;
+        }
+        else
+            return RT_ERR_PORT_ID;
+    }
+    else if(type == 1)
+    {
+        if (1 == ext_id)
+        {
+            if ((retVal = rtl8367c_setAsicReg(0x6601, 0x0002))!=RT_ERR_OK)
+                   return retVal;
+            if ((retVal = rtl8367c_setAsicReg(0x6600, 0x0081))!=RT_ERR_OK)
+                   return retVal;
+            if ((retVal = rtl8367c_getAsicReg(0x6602, &regValue))!=RT_ERR_OK)
+                   return retVal;
+
+            if(state)
+                  regValue |= 0x0200;
+            else
+                  regValue &= ~0x0200;
+
+            regValue |= 0x0100;
+
+            if ((retVal = rtl8367c_setAsicReg(0x6602, regValue))!=RT_ERR_OK)
+                   return retVal;
+            if ((retVal = rtl8367c_setAsicReg(0x6601, 0x0002))!=RT_ERR_OK)
+                   return retVal;
+            if ((retVal = rtl8367c_setAsicReg(0x6600, 0x00C1))!=RT_ERR_OK)
+                   return retVal;
+        }
+        else if (2 == ext_id)
+        {
+            if ((retVal = rtl8367c_setAsicReg(0x6601, 0x0002))!=RT_ERR_OK)
+                return retVal;
+            if ((retVal = rtl8367c_setAsicReg(0x6600, 0x0080))!=RT_ERR_OK)
+                return retVal;
+            if ((retVal = rtl8367c_getAsicReg(0x6602, &regValue))!=RT_ERR_OK)
+                return retVal;
+
+            if(state)
+                regValue |= 0x0200;
+            else
+                regValue &= ~0x0200;
+
+            regValue |= 0x0100;
+
+            if ((retVal = rtl8367c_setAsicReg(0x6602, regValue))!=RT_ERR_OK)
+                return retVal;
+            if ((retVal = rtl8367c_setAsicReg(0x6601, 0x0002))!=RT_ERR_OK)
+                return retVal;
+            if ((retVal = rtl8367c_setAsicReg(0x6600, 0x00C0))!=RT_ERR_OK)
+                return retVal;
+        }
+        else
+            return RT_ERR_PORT_ID;
+    }
+    else if(type == 2)
+    {
+        if ((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, &regValue))!=RT_ERR_OK)
+            return retVal;
+
+        if(state & 1)
+            regValue &= ~0x100;
+        else
+            regValue |= 0x100;
+
+        if ((retVal = rtl8367c_setAsicSdsReg(0, 2, 0, regValue))!=RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getSgmiiNway
+ * Description:
+ *      Get SGMII Nway
+ * Input:
+ *      ext_id      - EXT ID
+ *      state       - SGMII Nway state
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ * Note:
+ *      None.
+ */
+ret_t rtl8367c_getSgmiiNway(rtk_uint32 ext_id, rtk_uint32 *pState)
+{
+    rtk_uint32 retVal, regValue, type, running = 0, retVal2;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_getAsicReg(0x1300, &regValue)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK)
+        return retVal;
+
+    switch (regValue)
+    {
+        case 0x0276:
+        case 0x0597:
+        case 0x6367:
+            type = 0;
+            break;
+        case 0x0652:
+        case 0x6368:
+            type = 1;
+            break;
+        case 0x0801:
+        case 0x6511:
+            type = 2;
+            break;
+        default:
+            return RT_ERR_FAILED;
+    }
+
+    if(type == 0)
+    {
+        if (1 == ext_id)
+        {
+            if ((retVal = rtl8367c_getAsicRegBit(0x130c, 5, &running))!=RT_ERR_OK)
+                return retVal;
+
+            if(running == 1)
+            {
+                if ((retVal = rtl8367c_setAsicRegBit(0x130c, 5, 0))!=RT_ERR_OK)
+                    return retVal;
+            }
+
+            retVal = rtl8367c_setAsicReg(0x6601, 0x0002);
+
+            if(retVal == RT_ERR_OK)
+                retVal = rtl8367c_setAsicReg(0x6600, 0x0080);
+
+            if(retVal == RT_ERR_OK)
+                retVal = rtl8367c_getAsicReg(0x6602, &regValue);
+
+            if(running == 1)
+            {
+                if ((retVal2 = rtl8367c_setAsicRegBit(0x130c, 5, 1))!=RT_ERR_OK)
+                    return retVal2;
+            }
+
+            if(retVal != RT_ERR_OK)
+                return retVal;
+
+            if(regValue & 0x0200)
+                *pState = 1;
+            else
+                *pState = 0;
+        }
+        else
+            return RT_ERR_PORT_ID;
+    }
+    else if(type == 1)
+    {
+        if (1 == ext_id)
+        {
+                if ((retVal = rtl8367c_setAsicReg(0x6601, 0x0002))!=RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_setAsicReg(0x6600, 0x0081))!=RT_ERR_OK)
+                    return retVal;
+                if ((retVal = rtl8367c_getAsicReg(0x6602, &regValue))!=RT_ERR_OK)
+                    return retVal;
+
+                if(regValue & 0x0200)
+                    *pState = 1;
+                else
+                    *pState = 0;
+        }
+        else if (2 == ext_id)
+        {
+            if ((retVal = rtl8367c_setAsicReg(0x6601, 0x0002))!=RT_ERR_OK)
+                return retVal;
+            if ((retVal = rtl8367c_setAsicReg(0x6600, 0x0080))!=RT_ERR_OK)
+                return retVal;
+            if ((retVal = rtl8367c_getAsicReg(0x6602, &regValue))!=RT_ERR_OK)
+                return retVal;
+
+            if(regValue & 0x0200)
+                *pState = 1;
+            else
+                *pState = 0;
+        }
+        else
+            return RT_ERR_PORT_ID;
+    }
+    else if(type == 2)
+    {
+        if ((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, &regValue))!=RT_ERR_OK)
+            return retVal;
+
+        if(regValue & 0x100)
+            *pState = 0;
+        else
+            *pState = 1;
+    }
+
+    return RT_ERR_OK;
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_portIsolation.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_portIsolation.c
new file mode 100644
index 0000000..e0b9db4
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_portIsolation.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Port isolation related functions
+ *
+ */
+
+#include <rtl8367c_asicdrv_portIsolation.h>
+/* Function Name:
+ *      rtl8367c_setAsicPortIsolationPermittedPortmask
+ * Description:
+ *      Set permitted port isolation portmask
+ * Input:
+ *      port            - Physical port number (0~10)
+ *      permitPortmask  - port mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_PORT_MASK    - Invalid portmask
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortIsolationPermittedPortmask(rtk_uint32 port, rtk_uint32 permitPortmask)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if( permitPortmask > RTL8367C_PORTMASK)
+        return RT_ERR_PORT_MASK;
+
+    return rtl8367c_setAsicReg(RTL8367C_PORT_ISOLATION_PORT_MASK_REG(port), permitPortmask);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortIsolationPermittedPortmask
+ * Description:
+ *      Get permitted port isolation portmask
+ * Input:
+ *      port                - Physical port number (0~10)
+ *      pPermitPortmask     - port mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortIsolationPermittedPortmask(rtk_uint32 port, rtk_uint32 *pPermitPortmask)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicReg(RTL8367C_PORT_ISOLATION_PORT_MASK_REG(port), pPermitPortmask);
+}
+/* Function Name:
+ *      rtl8367c_setAsicPortIsolationEfid
+ * Description:
+ *      Set port isolation EFID
+ * Input:
+ *      port    - Physical port number (0~10)
+ *      efid    - EFID (0~7)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_OUT_OF_RANGE - Input parameter out of range
+ * Note:
+ *      EFID is used in individual learning in filtering database
+ */
+ret_t rtl8367c_setAsicPortIsolationEfid(rtk_uint32 port, rtk_uint32 efid)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if( efid > RTL8367C_EFIDMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_PORT_EFID_REG(port), RTL8367C_PORT_EFID_MASK(port), efid);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortIsolationEfid
+ * Description:
+ *      Get port isolation EFID
+ * Input:
+ *      port    - Physical port number (0~10)
+ *      pEfid   - EFID (0~7)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortIsolationEfid(rtk_uint32 port, rtk_uint32 *pEfid)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_PORT_EFID_REG(port), RTL8367C_PORT_EFID_MASK(port), pEfid);
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_qos.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_qos.c
new file mode 100644
index 0000000..89c3c3e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_qos.c
@@ -0,0 +1,778 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Qos related functions
+ *
+ */
+
+#include <rtl8367c_asicdrv_qos.h>
+/* Function Name:
+ *      rtl8367c_setAsicPriorityDot1qRemapping
+ * Description:
+ *      Set 802.1Q absolutely priority
+ * Input:
+ *      srcpriority - Priority value
+ *      priority     - Absolute priority value
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                 - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY    - Invalid priority
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPriorityDot1qRemapping(rtk_uint32 srcpriority, rtk_uint32 priority )
+{
+    if((srcpriority > RTL8367C_PRIMAX) || (priority > RTL8367C_PRIMAX))
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_QOS_1Q_PRIORITY_REMAPPING_REG(srcpriority), RTL8367C_QOS_1Q_PRIORITY_REMAPPING_MASK(srcpriority),priority);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPriorityDot1qRemapping
+ * Description:
+ *      Get 802.1Q absolutely priority
+ * Input:
+ *      srcpriority - Priority value
+ *      pPriority     - Absolute priority value
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK     - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPriorityDot1qRemapping(rtk_uint32 srcpriority, rtk_uint32 *pPriority )
+{
+    if(srcpriority > RTL8367C_PRIMAX )
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_QOS_1Q_PRIORITY_REMAPPING_REG(srcpriority), RTL8367C_QOS_1Q_PRIORITY_REMAPPING_MASK(srcpriority), pPriority);
+}
+/* Function Name:
+ *      rtl8367c_setAsicPriorityPortBased
+ * Description:
+ *      Set port based priority
+ * Input:
+ *      port         - Physical port number (0~7)
+ *      priority     - Priority value
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                 - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number
+ *      RT_ERR_QOS_INT_PRIORITY    - Invalid priority
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPriorityPortBased(rtk_uint32 port, rtk_uint32 priority )
+{
+    ret_t retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(priority > RTL8367C_PRIMAX )
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    if(port < 8)
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_QOS_PORTBASED_PRIORITY_REG(port), RTL8367C_QOS_PORTBASED_PRIORITY_MASK(port), priority);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_QOS_PORTBASED_PRIORITY_CTRL2, 0x7 << ((port - 8) << 2), priority);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicPriorityPortBased
+ * Description:
+ *      Get port based priority
+ * Input:
+ *      port         - Physical port number (0~7)
+ *      pPriority     - Priority value
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK         - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPriorityPortBased(rtk_uint32 port, rtk_uint32 *pPriority )
+{
+    ret_t retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(port < 8)
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_QOS_PORTBASED_PRIORITY_REG(port), RTL8367C_QOS_PORTBASED_PRIORITY_MASK(port), pPriority);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_QOS_PORTBASED_PRIORITY_CTRL2, 0x7 << ((port - 8) << 2), pPriority);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicPriorityDscpBased
+ * Description:
+ *      Set DSCP-based priority
+ * Input:
+ *      dscp         - DSCP value
+ *      priority     - Priority value
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                 - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QOS_DSCP_VALUE    - Invalid DSCP value
+ *      RT_ERR_QOS_INT_PRIORITY    - Invalid priority
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPriorityDscpBased(rtk_uint32 dscp, rtk_uint32 priority )
+{
+    if(priority > RTL8367C_PRIMAX )
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    if(dscp > RTL8367C_DSCPMAX)
+        return RT_ERR_QOS_DSCP_VALUE;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_QOS_DSCP_TO_PRIORITY_REG(dscp), RTL8367C_QOS_DSCP_TO_PRIORITY_MASK(dscp), priority);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPriorityDscpBased
+ * Description:
+ *      Get DSCP-based priority
+ * Input:
+ *      dscp         - DSCP value
+ *      pPriority     - Priority value
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                 - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY    - Invalid priority
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPriorityDscpBased(rtk_uint32 dscp, rtk_uint32 *pPriority )
+{
+    if(dscp > RTL8367C_DSCPMAX)
+        return RT_ERR_QOS_DSCP_VALUE;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_QOS_DSCP_TO_PRIORITY_REG(dscp), RTL8367C_QOS_DSCP_TO_PRIORITY_MASK(dscp), pPriority);
+}
+/* Function Name:
+ *      rtl8367c_setAsicPriorityDecision
+ * Description:
+ *      Set priority decision table
+ * Input:
+ *      prisrc         - Priority decision source
+ *      decisionPri - Decision priority assignment
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                     - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY        - Invalid priority
+ *      RT_ERR_QOS_SEL_PRI_SOURCE    - Invalid priority decision source parameter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPriorityDecision(rtk_uint32 index, rtk_uint32 prisrc, rtk_uint32 decisionPri)
+{
+    ret_t retVal;
+
+    if(index >= PRIDEC_IDX_END )
+        return RT_ERR_ENTRY_INDEX;
+
+    if(prisrc >= PRIDEC_END )
+        return RT_ERR_QOS_SEL_PRI_SOURCE;
+
+    if(decisionPri > RTL8367C_DECISIONPRIMAX )
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    switch(index)
+    {
+        case PRIDEC_IDX0:
+            if((retVal = rtl8367c_setAsicRegBits(RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_REG(prisrc), RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_MASK(prisrc), decisionPri))!=  RT_ERR_OK)
+                return retVal;
+            break;
+        case PRIDEC_IDX1:
+            if((retVal = rtl8367c_setAsicRegBits(RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_REG(prisrc), RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_MASK(prisrc), decisionPri))!=  RT_ERR_OK)
+                return retVal;
+            break;
+        default:
+            break;
+    };
+
+    return RT_ERR_OK;
+
+
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicPriorityDecision
+ * Description:
+ *      Get priority decision table
+ * Input:
+ *      prisrc         - Priority decision source
+ *      pDecisionPri - Decision priority assignment
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                     - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_QOS_SEL_PRI_SOURCE    - Invalid priority decision source parameter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPriorityDecision(rtk_uint32 index, rtk_uint32 prisrc, rtk_uint32* pDecisionPri)
+{
+    ret_t retVal;
+
+    if(index >= PRIDEC_IDX_END )
+        return RT_ERR_ENTRY_INDEX;
+
+    if(prisrc >= PRIDEC_END )
+        return RT_ERR_QOS_SEL_PRI_SOURCE;
+
+    switch(index)
+    {
+        case PRIDEC_IDX0:
+            if((retVal = rtl8367c_getAsicRegBits(RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_REG(prisrc), RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_MASK(prisrc), pDecisionPri))!=  RT_ERR_OK)
+                return retVal;
+            break;
+        case PRIDEC_IDX1:
+            if((retVal = rtl8367c_getAsicRegBits(RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_REG(prisrc), RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_MASK(prisrc), pDecisionPri))!=  RT_ERR_OK)
+                return retVal;
+            break;
+        default:
+            break;
+    };
+
+    return RT_ERR_OK;
+
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicPortPriorityDecisionIndex
+ * Description:
+ *      Set priority decision index for each port
+ * Input:
+ *      port     - Physical port number (0~7)
+ *      index     - Table index
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK             - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_QUEUE_NUM      - Invalid queue number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortPriorityDecisionIndex(rtk_uint32 port, rtk_uint32 index )
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(index >= PRIDEC_IDX_END)
+        return RT_ERR_ENTRY_INDEX;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_IDX_CTRL, port, index);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortPriorityDecisionIndex
+ * Description:
+ *      Get priority decision index  for each port
+ * Input:
+ *      port     - Physical port number (0~7)
+ *      pIndex     - Table index
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK             - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortPriorityDecisionIndex(rtk_uint32 port, rtk_uint32 *pIndex )
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_IDX_CTRL, port, pIndex);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicOutputQueueMappingIndex
+ * Description:
+ *      Set output queue number for each port
+ * Input:
+ *      port     - Physical port number (0~7)
+ *      index     - Mapping table index
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK             - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_QUEUE_NUM      - Invalid queue number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicOutputQueueMappingIndex(rtk_uint32 port, rtk_uint32 index )
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(index >= RTL8367C_QUEUENO)
+        return RT_ERR_QUEUE_NUM;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_QOS_PORT_QUEUE_NUMBER_REG(port), RTL8367C_QOS_PORT_QUEUE_NUMBER_MASK(port), index);
+}
+/* Function Name:
+ *      rtl8367c_getAsicOutputQueueMappingIndex
+ * Description:
+ *      Get output queue number for each port
+ * Input:
+ *      port     - Physical port number (0~7)
+ *      pIndex     - Mapping table index
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK             - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicOutputQueueMappingIndex(rtk_uint32 port, rtk_uint32 *pIndex )
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_QOS_PORT_QUEUE_NUMBER_REG(port), RTL8367C_QOS_PORT_QUEUE_NUMBER_MASK(port), pIndex);
+}
+/* Function Name:
+ *      rtl8367c_setAsicPriorityToQIDMappingTable
+ * Description:
+ *      Set priority to QID mapping table parameters
+ * Input:
+ *      index         - Mapping table index
+ *      priority     - The priority value
+ *      qid         - Queue id
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                 - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QUEUE_ID          - Invalid queue id
+ *      RT_ERR_QUEUE_NUM          - Invalid queue number
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPriorityToQIDMappingTable(rtk_uint32 index, rtk_uint32 priority, rtk_uint32 qid )
+{
+    if(index >= RTL8367C_QUEUENO)
+        return RT_ERR_QUEUE_NUM;
+
+    if(priority > RTL8367C_PRIMAX)
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    if(qid > RTL8367C_QIDMAX)
+        return RT_ERR_QUEUE_ID;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_QOS_1Q_PRIORITY_TO_QID_REG(index, priority), RTL8367C_QOS_1Q_PRIORITY_TO_QID_MASK(priority), qid);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPriorityToQIDMappingTable
+ * Description:
+ *      Get priority to QID mapping table parameters
+ * Input:
+ *      index         - Mapping table index
+ *      priority     - The priority value
+ *      pQid         - Queue id
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                 - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QUEUE_NUM          - Invalid queue number
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPriorityToQIDMappingTable(rtk_uint32 index, rtk_uint32 priority, rtk_uint32* pQid)
+{
+    if(index >= RTL8367C_QUEUENO)
+        return RT_ERR_QUEUE_NUM;
+
+    if(priority > RTL8367C_PRIMAX)
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_QOS_1Q_PRIORITY_TO_QID_REG(index, priority), RTL8367C_QOS_1Q_PRIORITY_TO_QID_MASK(priority), pQid);
+}
+/* Function Name:
+ *      rtl8367c_setAsicRemarkingDot1pAbility
+ * Description:
+ *      Set 802.1p remarking ability
+ * Input:
+ *      port     - Physical port number (0~7)
+ *      enabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK             - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicRemarkingDot1pAbility(rtk_uint32 port, rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_PORT_MISC_CFG_REG(port), RTL8367C_1QREMARK_ENABLE_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicRemarkingDot1pAbility
+ * Description:
+ *      Get 802.1p remarking ability
+ * Input:
+ *      port     - Physical port number (0~7)
+ *      pEnabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK     - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRemarkingDot1pAbility(rtk_uint32 port, rtk_uint32* pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_PORT_MISC_CFG_REG(port), RTL8367C_1QREMARK_ENABLE_OFFSET, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicRemarkingDot1pParameter
+ * Description:
+ *      Set 802.1p remarking parameter
+ * Input:
+ *      priority     - Priority value
+ *      newPriority - New priority value
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                 - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicRemarkingDot1pParameter(rtk_uint32 priority, rtk_uint32 newPriority )
+{
+    if(priority > RTL8367C_PRIMAX || newPriority > RTL8367C_PRIMAX)
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_QOS_1Q_REMARK_REG(priority), RTL8367C_QOS_1Q_REMARK_MASK(priority), newPriority);
+}
+/* Function Name:
+ *      rtl8367c_getAsicRemarkingDot1pParameter
+ * Description:
+ *      Get 802.1p remarking parameter
+ * Input:
+ *      priority     - Priority value
+ *      pNewPriority - New priority value
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                 - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRemarkingDot1pParameter(rtk_uint32 priority, rtk_uint32 *pNewPriority )
+{
+    if(priority > RTL8367C_PRIMAX )
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_QOS_1Q_REMARK_REG(priority), RTL8367C_QOS_1Q_REMARK_MASK(priority), pNewPriority);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicRemarkingDot1pSrc
+ * Description:
+ *      Set remarking source of 802.1p remarking.
+ * Input:
+ *      type      - remarking source
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT         - The module is not initial
+ *      RT_ERR_PORT_ID  - invalid port id
+ *      RT_ERR_INPUT            - invalid input parameter
+
+ * Note:
+ *      The API can configure 802.1p remark functionality to map original DSCP value or internal
+ *      priority to TX DSCP value.
+ */
+ret_t rtl8367c_setAsicRemarkingDot1pSrc(rtk_uint32 type)
+{
+
+    if(type >= DOT1P_PRISEL_END )
+        return RT_ERR_QOS_SEL_PRI_SOURCE;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_RMK_CFG_SEL_CTRL, RTL8367C_RMK_1Q_CFG_SEL_OFFSET, type);
+}
+
+
+/* Function Name:
+ *      rtl8367c_getAsicRemarkingDot1pSrc
+ * Description:
+ *      Get remarking source of 802.1p remarking.
+ * Output:
+ *      pType      - remarking source
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT         - The module is not initial
+ *      RT_ERR_PORT_ID          - invalid port id
+ *      RT_ERR_INPUT            - invalid input parameter
+ *      RT_ERR_NULL_POINTER     - input parameter may be null pointer
+
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRemarkingDot1pSrc(rtk_uint32 *pType)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_RMK_CFG_SEL_CTRL, RTL8367C_RMK_1Q_CFG_SEL_OFFSET, pType);
+}
+
+
+
+
+
+/* Function Name:
+ *      rtl8367c_setAsicRemarkingDscpAbility
+ * Description:
+ *      Set DSCP remarking ability
+ * Input:
+ *      enabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK     - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicRemarkingDscpAbility(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REMARKING_CTRL_REG, RTL8367C_REMARKING_DSCP_ENABLE_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicRemarkingDscpAbility
+ * Description:
+ *      Get DSCP remarking ability
+ * Input:
+ *      enabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK     - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRemarkingDscpAbility(rtk_uint32* pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REMARKING_CTRL_REG, RTL8367C_REMARKING_DSCP_ENABLE_OFFSET, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicRemarkingDscpParameter
+ * Description:
+ *      Set DSCP remarking parameter
+ * Input:
+ *      priority     - Priority value
+ *      newDscp     - New DSCP value
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                 - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QOS_DSCP_VALUE    - Invalid DSCP value
+ *      RT_ERR_QOS_INT_PRIORITY    - Invalid priority
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicRemarkingDscpParameter(rtk_uint32 priority, rtk_uint32 newDscp )
+{
+    if(priority > RTL8367C_PRIMAX )
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    if(newDscp > RTL8367C_DSCPMAX)
+        return RT_ERR_QOS_DSCP_VALUE;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_QOS_DSCP_REMARK_REG(priority), RTL8367C_QOS_DSCP_REMARK_MASK(priority), newDscp);
+}
+/* Function Name:
+ *      rtl8367c_getAsicRemarkingDscpParameter
+ * Description:
+ *      Get DSCP remarking parameter
+ * Input:
+ *      priority     - Priority value
+ *      pNewDscp     - New DSCP value
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                 - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY    - Invalid priority
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRemarkingDscpParameter(rtk_uint32 priority, rtk_uint32* pNewDscp )
+{
+    if(priority > RTL8367C_PRIMAX )
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_QOS_DSCP_REMARK_REG(priority), RTL8367C_QOS_DSCP_REMARK_MASK(priority), pNewDscp);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicRemarkingDscpSrc
+ * Description:
+ *      Set remarking source of DSCP remarking.
+ * Input:
+ *      type      - remarking source
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT         - The module is not initial
+ *      RT_ERR_PORT_ID  - invalid port id
+ *      RT_ERR_INPUT            - invalid input parameter
+
+ * Note:
+ *      The API can configure DSCP remark functionality to map original DSCP value or internal
+ *      priority to TX DSCP value.
+ */
+ret_t rtl8367c_setAsicRemarkingDscpSrc(rtk_uint32 type)
+{
+
+    if(type >= DSCP_PRISEL_END )
+        return RT_ERR_QOS_SEL_PRI_SOURCE;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_RMK_CFG_SEL_CTRL, RTL8367C_RMK_DSCP_CFG_SEL_MASK, type);
+}
+
+
+/* Function Name:
+ *      rtl8367c_getAsicRemarkingDscpSrc
+ * Description:
+ *      Get remarking source of DSCP remarking.
+ * Output:
+ *      pType      - remarking source
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT         - The module is not initial
+ *      RT_ERR_PORT_ID          - invalid port id
+ *      RT_ERR_INPUT            - invalid input parameter
+ *      RT_ERR_NULL_POINTER     - input parameter may be null pointer
+
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRemarkingDscpSrc(rtk_uint32 *pType)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_RMK_CFG_SEL_CTRL, RTL8367C_RMK_DSCP_CFG_SEL_MASK, pType);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicRemarkingDscp2Dscp
+ * Description:
+ *      Set DSCP to remarked DSCP mapping.
+ * Input:
+ *      dscp    - DSCP value
+ *      rmkDscp - remarked DSCP value
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_UNIT_ID          - Invalid unit id
+ *      RT_ERR_QOS_DSCP_VALUE   - Invalid dscp value
+ * Note:
+ *      dscp parameter can be DSCP value or internal priority according to configuration of API
+ *      dal_apollomp_qos_dscpRemarkSrcSel_set(), because DSCP remark functionality can map original DSCP
+ *      value or internal priority to TX DSCP value.
+ */
+ret_t rtl8367c_setAsicRemarkingDscp2Dscp(rtk_uint32 dscp, rtk_uint32 rmkDscp)
+{
+    if((dscp > RTL8367C_DSCPMAX ) || (rmkDscp > RTL8367C_DSCPMAX))
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_QOS_DSCP_TO_DSCP_REG(dscp), RTL8367C_QOS_DSCP_TO_DSCP_MASK(dscp), rmkDscp);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicRemarkingDscp2Dscp
+ * Description:
+ *      Get DSCP to remarked DSCP mapping.
+ * Input:
+ *      dscp    - DSCP value
+ * Output:
+ *      pRmkDscp   - remarked DSCP value
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_QOS_DSCP_VALUE   - Invalid dscp value
+ *      RT_ERR_NULL_POINTER     - NULL pointer
+ * Note:
+ *      None.
+ */
+ret_t rtl8367c_getAsicRemarkingDscp2Dscp(rtk_uint32 dscp, rtk_uint32 *pRmkDscp)
+{
+    if(dscp > RTL8367C_DSCPMAX)
+        return RT_ERR_QOS_DSCP_VALUE;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_QOS_DSCP_TO_DSCP_REG(dscp), RTL8367C_QOS_DSCP_TO_DSCP_MASK(dscp), pRmkDscp);
+
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rldp.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rldp.c
new file mode 100644
index 0000000..0309689
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rldp.c
@@ -0,0 +1,674 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 42321 $
+ * $Date: 2013-08-26 13:51:29 +0800 (週一, 26 八月 2013) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : RLDP related functions
+ *
+ */
+
+#include <rtl8367c_asicdrv_rldp.h>
+/* Function Name:
+ *      rtl8367c_setAsicRldp
+ * Description:
+ *      Set RLDP function enable/disable
+ * Input:
+ *      enabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicRldp(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_ENABLE_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicRldp
+ * Description:
+ *      Get RLDP function enable/disable
+ * Input:
+ *      pEnabled    - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRldp(rtk_uint32 *pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_ENABLE_OFFSET, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicRldpEnable8051
+ * Description:
+ *      Set RLDP function handled by ASIC or 8051
+ * Input:
+ *      enabled     - 1: enabled 8051, 0: disabled 8051 (RLDP is handled by ASIC)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicRldpEnable8051(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_8051_ENABLE_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicRldrtl8367c_getAsicRldpEnable8051pEnable8051
+ * Description:
+ *      Get RLDP function handled by ASIC or 8051
+ * Input:
+ *      pEnabled    - 1: enabled 8051, 0: disabled 8051 (RLDP is handled by ASIC)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRldpEnable8051(rtk_uint32 *pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_8051_ENABLE_OFFSET, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicRldpCompareRandomNumber
+ * Description:
+ *      Set enable compare the random number field and seed field of RLDP frame
+ * Input:
+ *      enabled     - 1: enabled comparing random number, 0: disabled comparing random number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicRldpCompareRandomNumber(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_COMP_ID_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicRldpCompareRandomNumber
+ * Description:
+ *      Get enable compare the random number field and seed field of RLDP frame
+ * Input:
+ *      pEnabled    - 1: enabled comparing random number, 0: disabled comparing random number
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRldpCompareRandomNumber(rtk_uint32 *pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_COMP_ID_OFFSET, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicRldpIndicatorSource
+ * Description:
+ *      Set buzzer and LED source when detecting a loop
+ * Input:
+ *      src     - 0: ASIC, 1: 8051
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicRldpIndicatorSource(rtk_uint32 src)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_INDICATOR_SOURCE_OFFSET, src);
+}
+/* Function Name:
+ *      rtl8367c_getAsicRldpIndicatorSource
+ * Description:
+ *      Get buzzer and LED source when detecting a loop
+ * Input:
+ *      pSrc    - 0: ASIC, 1: 8051
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRldpIndicatorSource(rtk_uint32 *pSrc)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_INDICATOR_SOURCE_OFFSET, pSrc);
+}
+/* Function Name:
+ *      rtl8367c_setAsicRldpCheckingStatePara
+ * Description:
+ *      Set retry count and retry period of checking state
+ * Input:
+ *      retryCount  - 0~0xFF (times)
+ *      retryPeriod - 0~0xFFFF (ms)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicRldpCheckingStatePara(rtk_uint32 retryCount, rtk_uint32 retryPeriod)
+{
+    ret_t retVal;
+
+    if(retryCount > 0xFF)
+        return RT_ERR_OUT_OF_RANGE;
+    if(retryPeriod > RTL8367C_REGDATAMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_RLDP_RETRY_COUNT_REG, RTL8367C_RLDP_RETRY_COUNT_CHKSTATE_MASK, retryCount);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return rtl8367c_setAsicReg(RTL8367C_RLDP_RETRY_PERIOD_CHKSTATE_REG, retryPeriod);
+}
+/* Function Name:
+ *      rtl8367c_getAsicRldpCheckingStatePara
+ * Description:
+ *      Get retry count and retry period of checking state
+ * Input:
+ *      pRetryCount     - 0~0xFF (times)
+ *      pRetryPeriod    - 0~0xFFFF (ms)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRldpCheckingStatePara(rtk_uint32 *pRetryCount, rtk_uint32 *pRetryPeriod)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_RLDP_RETRY_COUNT_REG, RTL8367C_RLDP_RETRY_COUNT_CHKSTATE_MASK, pRetryCount);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return rtl8367c_getAsicReg(RTL8367C_RLDP_RETRY_PERIOD_CHKSTATE_REG, pRetryPeriod);
+}
+/* Function Name:
+ *      rtl8367c_setAsicRldpLoopStatePara
+ * Description:
+ *      Set retry count and retry period of loop state
+ * Input:
+ *      retryCount  - 0~0xFF (times)
+ *      retryPeriod - 0~0xFFFF (ms)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicRldpLoopStatePara(rtk_uint32 retryCount, rtk_uint32 retryPeriod)
+{
+    ret_t retVal;
+
+    if(retryCount > 0xFF)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(retryPeriod > RTL8367C_REGDATAMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_RLDP_RETRY_COUNT_REG, RTL8367C_RLDP_RETRY_COUNT_LOOPSTATE_MASK, retryCount);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return rtl8367c_setAsicReg(RTL8367C_RLDP_RETRY_PERIOD_LOOPSTATE_REG, retryPeriod);
+}
+/* Function Name:
+ *      rtl8367c_getAsicRldpLoopStatePara
+ * Description:
+ *      Get retry count and retry period of loop state
+ * Input:
+ *      pRetryCount     - 0~0xFF (times)
+ *      pRetryPeriod    - 0~0xFFFF (ms)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - input parameter out of range
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRldpLoopStatePara(rtk_uint32 *pRetryCount, rtk_uint32 *pRetryPeriod)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_RLDP_RETRY_COUNT_REG, RTL8367C_RLDP_RETRY_COUNT_LOOPSTATE_MASK, pRetryCount);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return rtl8367c_getAsicReg(RTL8367C_RLDP_RETRY_PERIOD_LOOPSTATE_REG, pRetryPeriod);
+}
+/* Function Name:
+ *      rtl8367c_setAsicRldpTxPortmask
+ * Description:
+ *      Set portmask that send/forward RLDP frame
+ * Input:
+ *      portmask    - 0~0xFF
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK    - Invalid portmask
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicRldpTxPortmask(rtk_uint32 portmask)
+{
+    if(portmask > RTL8367C_PORTMASK)
+        return RT_ERR_PORT_MASK;
+
+    return rtl8367c_setAsicReg(RTL8367C_RLDP_TX_PMSK_REG, portmask);
+}
+/* Function Name:
+ *      rtl8367c_getAsicRldpTxPortmask
+ * Description:
+ *      Get portmask that send/forward RLDP frame
+ * Input:
+ *      pPortmask   - 0~0xFF
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRldpTxPortmask(rtk_uint32 *pPortmask)
+{
+    return rtl8367c_getAsicReg(RTL8367C_RLDP_TX_PMSK_REG, pPortmask);
+}
+/* Function Name:
+ *      rtl8367c_setAsicRldpMagicNum
+ * Description:
+ *      Set Random seed of RLDP
+ * Input:
+ *      seed    - MAC
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicRldpMagicNum(ether_addr_t seed)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+    rtk_uint16 *accessPtr;
+    rtk_uint32 i;
+
+    accessPtr = (rtk_uint16*)&seed;
+
+    for (i = 0; i < 3; i++)
+    {
+        regData = *accessPtr;
+        retVal = rtl8367c_setAsicReg(RTL8367C_RLDP_MAGIC_NUM_REG_BASE + i, regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        accessPtr++;
+    }
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicRldpMagicNum
+ * Description:
+ *      Get Random seed of RLDP
+ * Input:
+ *      pSeed   - MAC
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRldpMagicNum(ether_addr_t *pSeed)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+    rtk_uint16 *accessPtr;
+    rtk_uint32 i;
+
+    accessPtr = (rtk_uint16*)pSeed;
+
+    for(i = 0; i < 3; i++)
+    {
+        retVal = rtl8367c_getAsicReg(RTL8367C_RLDP_MAGIC_NUM_REG_BASE + i, &regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        *accessPtr = regData;
+        accessPtr++;
+    }
+
+    return retVal;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicRldpLoopedPortmask
+ * Description:
+ *      Get looped portmask
+ * Input:
+ *      pPortmask   - 0~0xFF
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRldpLoopedPortmask(rtk_uint32 *pPortmask)
+{
+    return rtl8367c_getAsicReg(RTL8367C_RLDP_LOOP_PMSK_REG, pPortmask);
+}
+/* Function Name:
+ *      rtl8367c_getAsicRldpRandomNumber
+ * Description:
+ *      Get Random number of RLDP
+ * Input:
+ *      pRandNumber     - MAC
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRldpRandomNumber(ether_addr_t *pRandNumber)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+    rtk_int16 accessPtr[3];
+    rtk_uint32 i;
+
+    for(i = 0; i < 3; i++)
+    {
+        retVal = rtl8367c_getAsicReg(RTL8367C_RLDP_RAND_NUM_REG_BASE+ i, &regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        accessPtr[i] = regData;
+    }
+
+    memcpy(pRandNumber, accessPtr, 6);
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicRldpLoopedPortmask
+ * Description:
+ *      Get port number of looped pair
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      pLoopedPair     - port (0~7)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRldpLoopedPortPair(rtk_uint32 port, rtk_uint32 *pLoopedPair)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(port < 8)
+        return rtl8367c_getAsicRegBits(RTL8367C_RLDP_LOOP_PORT_REG(port), RTL8367C_RLDP_LOOP_PORT_MASK(port), pLoopedPair);
+    else
+        return rtl8367c_getAsicRegBits(RTL8367C_REG_RLDP_LOOP_PORT_REG4 + ((port - 8) >> 1), RTL8367C_RLDP_LOOP_PORT_MASK(port), pLoopedPair);
+}
+/* Function Name:
+ *      rtl8367c_setAsicRlppTrap8051
+ * Description:
+ *      Set trap RLPP packet to 8051
+ * Input:
+ *      enabled     - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicRlppTrap8051(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLPP_8051_TRAP_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicRlppTrap8051
+ * Description:
+ *      Get trap RLPP packet to 8051
+ * Input:
+ *      pEnabled    - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRlppTrap8051(rtk_uint32 *pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLPP_8051_TRAP_OFFSET, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicRldpLeaveLoopedPortmask
+ * Description:
+ *      Clear leaved looped portmask
+ * Input:
+ *      portmask    - 0~0xFF
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicRldpLeaveLoopedPortmask(rtk_uint32 portmask)
+{
+    return rtl8367c_setAsicReg(RTL8367C_REG_RLDP_RELEASED_INDICATOR, portmask);
+}
+/* Function Name:
+ *      rtl8367c_getAsicRldpLeaveLoopedPortmask
+ * Description:
+ *      Get leaved looped portmask
+ * Input:
+ *      pPortmask   - 0~0xFF
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRldpLeaveLoopedPortmask(rtk_uint32 *pPortmask)
+{
+    return rtl8367c_getAsicReg(RTL8367C_REG_RLDP_RELEASED_INDICATOR, pPortmask);
+}
+/* Function Name:
+ *      rtl8367c_setAsicRldpEnterLoopedPortmask
+ * Description:
+ *      Clear enter loop portmask
+ * Input:
+ *      portmask    - 0~0xFF
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicRldpEnterLoopedPortmask(rtk_uint32 portmask)
+{
+    return rtl8367c_setAsicReg(RTL8367C_REG_RLDP_LOOPED_INDICATOR, portmask);
+}
+/* Function Name:
+ *      rtl8367c_getAsicRldpEnterLoopedPortmask
+ * Description:
+ *      Get enter loop portmask
+ * Input:
+ *      pPortmask   - 0~0xFF
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRldpEnterLoopedPortmask(rtk_uint32 *pPortmask)
+{
+    return rtl8367c_getAsicReg(RTL8367C_REG_RLDP_LOOPED_INDICATOR, pPortmask);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicRldpTriggerMode
+ * Description:
+ *      Set trigger RLDP mode
+ * Input:
+ *      mode    - 1: Periodically, 0: SA moving
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicRldpTriggerMode(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_TRIGGER_MODE_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicRldpTriggerMode
+ * Description:
+ *      Get trigger RLDP mode
+ * Input:
+ *      pMode   - - 1: Periodically, 0: SA moving
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRldpTriggerMode(rtk_uint32 *pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_TRIGGER_MODE_OFFSET, pEnabled);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicRldp8051Portmask
+ * Description:
+ *      Set 8051/CPU configured looped portmask
+ * Input:
+ *      portmask    - 0~0xFF
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK    - Invalid portmask
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicRldp8051Portmask(rtk_uint32 portmask)
+{
+    ret_t retVal;
+    if(portmask > RTL8367C_PORTMASK)
+        return RT_ERR_PORT_MASK;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_RLDP_CTRL0_REG,RTL8367C_RLDP_8051_LOOP_PORTMSK_MASK,portmask & 0xff);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_RLDP_CTRL5,RTL8367C_RLDP_CTRL5_MASK,(portmask >> 8) & 7);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicRldp8051Portmask
+ * Description:
+ *      Get 8051/CPU configured looped portmask
+ * Input:
+ *      pPortmask   - 0~0xFF
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRldp8051Portmask(rtk_uint32 *pPortmask)
+{
+    rtk_uint32 tmpPmsk;
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_RLDP_CTRL0_REG,RTL8367C_RLDP_8051_LOOP_PORTMSK_MASK,&tmpPmsk);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+    *pPortmask = tmpPmsk & 0xff;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_RLDP_CTRL5,RTL8367C_RLDP_CTRL5_MASK,&tmpPmsk);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+    *pPortmask |= (tmpPmsk & 7) <<8;
+
+    return RT_ERR_OK;
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rma.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rma.c
new file mode 100644
index 0000000..f297def
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rma.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 64716 $
+ * $Date: 2015-12-31 16:31:55 +0800 (週四, 31 十二月 2015) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : RMA related functions
+ *
+ */
+
+#include <rtl8367c_asicdrv_rma.h>
+/* Function Name:
+ *      rtl8367c_setAsicRma
+ * Description:
+ *      Set reserved multicast address for CPU trapping
+ * Input:
+ *      index     - reserved multicast LSB byte, 0x00~0x2F is available value
+ *      pRmacfg     - type of RMA for trapping frame type setting
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK         - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_RMA_ADDR - Invalid RMA address index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicRma(rtk_uint32 index, rtl8367c_rma_t* pRmacfg)
+{
+    rtk_uint32 regData = 0;
+    ret_t retVal;
+
+    if(index > RTL8367C_RMAMAX)
+        return RT_ERR_RMA_ADDR;
+
+    regData |= (pRmacfg->portiso_leaky & 0x0001);
+    regData |= ((pRmacfg->vlan_leaky & 0x0001) << 1);
+    regData |= ((pRmacfg->keep_format & 0x0001) << 2);
+    regData |= ((pRmacfg->trap_priority & 0x0007) << 3);
+    regData |= ((pRmacfg->discard_storm_filter & 0x0001) << 6);
+    regData |= ((pRmacfg->operation & 0x0003) << 7);
+
+    if( (index >= 0x4 && index <= 0x7) || (index >= 0x9 && index <= 0x0C) || (0x0F == index))
+        index = 0x04;
+    else if((index >= 0x13 && index <= 0x17) || (0x19 == index) || (index >= 0x1B && index <= 0x1f))
+        index = 0x13;
+    else if(index >= 0x22 && index <= 0x2F)
+        index = 0x22;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, pRmacfg->trap_priority);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return rtl8367c_setAsicReg(RTL8367C_REG_RMA_CTRL00+index, regData);
+}
+/* Function Name:
+ *      rtl8367c_getAsicRma
+ * Description:
+ *      Get reserved multicast address for CPU trapping
+ * Input:
+ *      index     - reserved multicast LSB byte, 0x00~0x2F is available value
+ *      rmacfg     - type of RMA for trapping frame type setting
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK         - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_RMA_ADDR - Invalid RMA address index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRma(rtk_uint32 index, rtl8367c_rma_t* pRmacfg)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+
+    if(index > RTL8367C_RMAMAX)
+        return RT_ERR_RMA_ADDR;
+
+    if( (index >= 0x4 && index <= 0x7) || (index >= 0x9 && index <= 0x0C) || (0x0F == index))
+        index = 0x04;
+    else if((index >= 0x13 && index <= 0x17) || (0x19 == index) || (index >= 0x1B && index <= 0x1f))
+        index = 0x13;
+    else if(index >= 0x22 && index <= 0x2F)
+        index = 0x22;
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_REG_RMA_CTRL00+index, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    pRmacfg->operation = ((regData >> 7) & 0x0003);
+    pRmacfg->discard_storm_filter = ((regData >> 6) & 0x0001);
+    pRmacfg->trap_priority = ((regData >> 3) & 0x0007);
+    pRmacfg->keep_format = ((regData >> 2) & 0x0001);
+    pRmacfg->vlan_leaky = ((regData >> 1) & 0x0001);
+    pRmacfg->portiso_leaky = (regData & 0x0001);
+
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    pRmacfg->trap_priority = regData;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicRmaCdp
+ * Description:
+ *      Set CDP(Cisco Discovery Protocol) for CPU trapping
+ * Input:
+ *      pRmacfg     - type of RMA for trapping frame type setting
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK         - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_RMA_ADDR - Invalid RMA address index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicRmaCdp(rtl8367c_rma_t* pRmacfg)
+{
+    rtk_uint32 regData = 0;
+    ret_t retVal;
+
+    if(pRmacfg->operation >= RMAOP_END)
+        return RT_ERR_RMA_ACTION;
+
+    if(pRmacfg->trap_priority > RTL8367C_PRIMAX)
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    regData |= (pRmacfg->portiso_leaky & 0x0001);
+    regData |= ((pRmacfg->vlan_leaky & 0x0001) << 1);
+    regData |= ((pRmacfg->keep_format & 0x0001) << 2);
+    regData |= ((pRmacfg->trap_priority & 0x0007) << 3);
+    regData |= ((pRmacfg->discard_storm_filter & 0x0001) << 6);
+    regData |= ((pRmacfg->operation & 0x0003) << 7);
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, pRmacfg->trap_priority);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return rtl8367c_setAsicReg(RTL8367C_REG_RMA_CTRL_CDP, regData);
+}
+/* Function Name:
+ *      rtl8367c_getAsicRmaCdp
+ * Description:
+ *      Get CDP(Cisco Discovery Protocol) for CPU trapping
+ * Input:
+ *      None
+ * Output:
+ *      pRmacfg     - type of RMA for trapping frame type setting
+ * Return:
+ *      RT_ERR_OK         - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_RMA_ADDR - Invalid RMA address index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRmaCdp(rtl8367c_rma_t* pRmacfg)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_REG_RMA_CTRL_CDP, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    pRmacfg->operation = ((regData >> 7) & 0x0003);
+    pRmacfg->discard_storm_filter = ((regData >> 6) & 0x0001);
+    pRmacfg->trap_priority = ((regData >> 3) & 0x0007);
+    pRmacfg->keep_format = ((regData >> 2) & 0x0001);
+    pRmacfg->vlan_leaky = ((regData >> 1) & 0x0001);
+    pRmacfg->portiso_leaky = (regData & 0x0001);
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    pRmacfg->trap_priority = regData;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicRmaCsstp
+ * Description:
+ *      Set CSSTP(Cisco Shared Spanning Tree Protocol) for CPU trapping
+ * Input:
+ *      pRmacfg     - type of RMA for trapping frame type setting
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK         - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_RMA_ADDR - Invalid RMA address index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicRmaCsstp(rtl8367c_rma_t* pRmacfg)
+{
+    rtk_uint32 regData = 0;
+    ret_t retVal;
+
+    if(pRmacfg->operation >= RMAOP_END)
+        return RT_ERR_RMA_ACTION;
+
+    if(pRmacfg->trap_priority > RTL8367C_PRIMAX)
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    regData |= (pRmacfg->portiso_leaky & 0x0001);
+    regData |= ((pRmacfg->vlan_leaky & 0x0001) << 1);
+    regData |= ((pRmacfg->keep_format & 0x0001) << 2);
+    regData |= ((pRmacfg->trap_priority & 0x0007) << 3);
+    regData |= ((pRmacfg->discard_storm_filter & 0x0001) << 6);
+    regData |= ((pRmacfg->operation & 0x0003) << 7);
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, pRmacfg->trap_priority);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return rtl8367c_setAsicReg(RTL8367C_REG_RMA_CTRL_CSSTP, regData);
+}
+/* Function Name:
+ *      rtl8367c_getAsicRmaCsstp
+ * Description:
+ *      Get CSSTP(Cisco Shared Spanning Tree Protocol) for CPU trapping
+ * Input:
+ *      None
+ * Output:
+ *      pRmacfg     - type of RMA for trapping frame type setting
+ * Return:
+ *      RT_ERR_OK         - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_RMA_ADDR - Invalid RMA address index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRmaCsstp(rtl8367c_rma_t* pRmacfg)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_REG_RMA_CTRL_CSSTP, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    pRmacfg->operation = ((regData >> 7) & 0x0003);
+    pRmacfg->discard_storm_filter = ((regData >> 6) & 0x0001);
+    pRmacfg->trap_priority = ((regData >> 3) & 0x0007);
+    pRmacfg->keep_format = ((regData >> 2) & 0x0001);
+    pRmacfg->vlan_leaky = ((regData >> 1) & 0x0001);
+    pRmacfg->portiso_leaky = (regData & 0x0001);
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    pRmacfg->trap_priority = regData;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicRmaLldp
+ * Description:
+ *      Set LLDP for CPU trapping
+ * Input:
+ *      pRmacfg     - type of RMA for trapping frame type setting
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK         - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_RMA_ADDR - Invalid RMA address index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicRmaLldp(rtk_uint32 enabled, rtl8367c_rma_t* pRmacfg)
+{
+    rtk_uint32 regData = 0;
+    ret_t retVal;
+
+    if(enabled > 1)
+        return RT_ERR_ENABLE;
+
+    if(pRmacfg->operation >= RMAOP_END)
+        return RT_ERR_RMA_ACTION;
+
+    if(pRmacfg->trap_priority > RTL8367C_PRIMAX)
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_RMA_LLDP_EN, RTL8367C_RMA_LLDP_EN_OFFSET,enabled);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    regData |= (pRmacfg->portiso_leaky & 0x0001);
+    regData |= ((pRmacfg->vlan_leaky & 0x0001) << 1);
+    regData |= ((pRmacfg->keep_format & 0x0001) << 2);
+    regData |= ((pRmacfg->trap_priority & 0x0007) << 3);
+    regData |= ((pRmacfg->discard_storm_filter & 0x0001) << 6);
+    regData |= ((pRmacfg->operation & 0x0003) << 7);
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, pRmacfg->trap_priority);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return rtl8367c_setAsicReg(RTL8367C_REG_RMA_CTRL_LLDP, regData);
+}
+/* Function Name:
+ *      rtl8367c_getAsicRmaLldp
+ * Description:
+ *      Get LLDP for CPU trapping
+ * Input:
+ *      None
+ * Output:
+ *      pRmacfg     - type of RMA for trapping frame type setting
+ * Return:
+ *      RT_ERR_OK         - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_RMA_ADDR - Invalid RMA address index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicRmaLldp(rtk_uint32 *pEnabled, rtl8367c_rma_t* pRmacfg)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+
+    retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_RMA_LLDP_EN, RTL8367C_RMA_LLDP_EN_OFFSET,pEnabled);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_REG_RMA_CTRL_LLDP, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    pRmacfg->operation = ((regData >> 7) & 0x0003);
+    pRmacfg->discard_storm_filter = ((regData >> 6) & 0x0001);
+    pRmacfg->trap_priority = ((regData >> 3) & 0x0007);
+    pRmacfg->keep_format = ((regData >> 2) & 0x0001);
+    pRmacfg->vlan_leaky = ((regData >> 1) & 0x0001);
+    pRmacfg->portiso_leaky = (regData & 0x0001);
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    pRmacfg->trap_priority = regData;
+
+    return RT_ERR_OK;
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_scheduling.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_scheduling.c
new file mode 100644
index 0000000..8ebd679
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_scheduling.c
@@ -0,0 +1,525 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Packet Scheduling related functions
+ *
+ */
+
+#include <rtl8367c_asicdrv_scheduling.h>
+/* Function Name:
+ *      rtl8367c_setAsicLeakyBucketParameter
+ * Description:
+ *      Set Leaky Bucket Paramters
+ * Input:
+ *      tick    - Tick is used for time slot size unit
+ *      token   - Token is used for adding budget in each time slot
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_TICK     - Invalid TICK
+ *      RT_ERR_TOKEN    - Invalid TOKEN
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicLeakyBucketParameter(rtk_uint32 tick, rtk_uint32 token)
+{
+    ret_t retVal;
+
+    if(tick > 0xFF)
+        return RT_ERR_TICK;
+
+    if(token > 0xFF)
+        return RT_ERR_TOKEN;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_LEAKY_BUCKET_TICK_REG, RTL8367C_LEAKY_BUCKET_TICK_MASK, tick);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_LEAKY_BUCKET_TOKEN_REG, RTL8367C_LEAKY_BUCKET_TOKEN_MASK, token);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicLeakyBucketParameter
+ * Description:
+ *      Get Leaky Bucket Paramters
+ * Input:
+ *      tick    - Tick is used for time slot size unit
+ *      token   - Token is used for adding budget in each time slot
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicLeakyBucketParameter(rtk_uint32 *tick, rtk_uint32 *token)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_LEAKY_BUCKET_TICK_REG, RTL8367C_LEAKY_BUCKET_TICK_MASK, tick);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_LEAKY_BUCKET_TOKEN_REG, RTL8367C_LEAKY_BUCKET_TOKEN_MASK, token);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_setAsicAprMeter
+ * Description:
+ *      Set per-port per-queue APR shared meter index
+ * Input:
+ *      port    - Physical port number (0~10)
+ *      qid     - Queue id
+ *      apridx  - dedicated shared meter index for APR (0~7)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number
+ *      RT_ERR_QUEUE_ID         - Invalid queue id
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicAprMeter(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 apridx)
+{
+    ret_t retVal;
+    rtk_uint32 regAddr;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(qid > RTL8367C_QIDMAX)
+        return RT_ERR_QUEUE_ID;
+
+    if(apridx > RTL8367C_PORT_QUEUE_METER_INDEX_MAX)
+        return RT_ERR_FILTER_METER_ID;
+
+    if(port < 8)
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_SCHEDULE_PORT_APR_METER_REG(port, qid), RTL8367C_SCHEDULE_PORT_APR_METER_MASK(qid), apridx);
+    else {
+        regAddr = RTL8367C_REG_SCHEDULE_PORT8_APR_METER_CTRL0 + ((port-8) << 1) + (qid / 5);
+        retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_SCHEDULE_PORT_APR_METER_MASK(qid), apridx);
+    }
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicAprMeter
+ * Description:
+ *      Get per-port per-queue APR shared meter index
+ * Input:
+ *      port    - Physical port number (0~10)
+ *      qid     - Queue id
+ *      apridx  - dedicated shared meter index for APR (0~7)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ *      RT_ERR_QUEUE_ID - Invalid queue id
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicAprMeter(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 *apridx)
+{
+    ret_t retVal;
+    rtk_uint32 regAddr;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(qid > RTL8367C_QIDMAX)
+        return RT_ERR_QUEUE_ID;
+
+    if(port < 8)
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_SCHEDULE_PORT_APR_METER_REG(port, qid), RTL8367C_SCHEDULE_PORT_APR_METER_MASK(qid), apridx);
+    else {
+        regAddr = RTL8367C_REG_SCHEDULE_PORT8_APR_METER_CTRL0 + ((port-8) << 1) + (qid / 5);
+        retVal = rtl8367c_getAsicRegBits(regAddr, RTL8367C_SCHEDULE_PORT_APR_METER_MASK(qid), apridx);
+    }
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_setAsicAprEnable
+ * Description:
+ *      Set per-port APR enable
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      aprEnable   - APR enable seting 1:enable 0:disable
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicAprEnable(rtk_uint32 port, rtk_uint32 aprEnable)
+{
+    ret_t retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    retVal = rtl8367c_setAsicRegBit(RTL8367C_SCHEDULE_APR_CTRL_REG, RTL8367C_SCHEDULE_APR_CTRL_OFFSET(port), aprEnable);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicAprEnable
+ * Description:
+ *      Get per-port APR enable
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      aprEnable   - APR enable seting 1:enable 0:disable
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicAprEnable(rtk_uint32 port, rtk_uint32 *aprEnable)
+{
+    ret_t retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    retVal = rtl8367c_getAsicRegBit(RTL8367C_SCHEDULE_APR_CTRL_REG, RTL8367C_SCHEDULE_APR_CTRL_OFFSET(port), aprEnable);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_setAsicWFQWeight
+ * Description:
+ *      Set weight  of a queue
+ * Input:
+ *      port    - Physical port number (0~10)
+ *      qid     - The queue ID wanted to set
+ *      qWeight - The weight value wanted to set (valid:0~127)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number
+ *      RT_ERR_QUEUE_ID         - Invalid queue id
+ *      RT_ERR_QOS_QUEUE_WEIGHT - Invalid queue weight
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicWFQWeight(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 qWeight)
+{
+    ret_t retVal;
+
+    /* Invalid input parameter */
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(qid > RTL8367C_QIDMAX)
+        return RT_ERR_QUEUE_ID;
+
+    if(qWeight > RTL8367C_QWEIGHTMAX && qid > 0)
+        return RT_ERR_QOS_QUEUE_WEIGHT;
+
+    retVal = rtl8367c_setAsicReg(RTL8367C_SCHEDULE_PORT_QUEUE_WFQ_WEIGHT_REG(port, qid), qWeight);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicWFQWeight
+ * Description:
+ *      Get weight  of a queue
+ * Input:
+ *      port    - Physical port number (0~10)
+ *      qid     - The queue ID wanted to set
+ *      qWeight - The weight value wanted to set (valid:0~127)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number
+ *      RT_ERR_QUEUE_ID         - Invalid queue id
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicWFQWeight(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 *qWeight)
+{
+    ret_t retVal;
+
+
+    /* Invalid input parameter */
+    if(port  > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(qid > RTL8367C_QIDMAX)
+        return RT_ERR_QUEUE_ID;
+
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_SCHEDULE_PORT_QUEUE_WFQ_WEIGHT_REG(port, qid), qWeight);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_setAsicWFQBurstSize
+ * Description:
+ *      Set WFQ leaky bucket burst size
+ * Input:
+ *      burstsize   - Leaky bucket burst size, unit byte
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicWFQBurstSize(rtk_uint32 burstsize)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_setAsicReg(RTL8367C_SCHEDULE_WFQ_BURST_SIZE_REG, burstsize);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicWFQBurstSize
+ * Description:
+ *      Get WFQ leaky bucket burst size
+ * Input:
+ *      burstsize   - Leaky bucket burst size, unit byte
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicWFQBurstSize(rtk_uint32 *burstsize)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_SCHEDULE_WFQ_BURST_SIZE_REG, burstsize);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_setAsicQueueType
+ * Description:
+ *      Set type of a queue
+ * Input:
+ *      port        - Physical port number (0~10)
+ *      qid         - The queue ID wanted to set
+ *      queueType   - The specified queue type. 0b0: Strict priority, 0b1: WFQ
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ *      RT_ERR_QUEUE_ID - Invalid queue id
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicQueueType(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 queueType)
+{
+    ret_t retVal;
+
+    /* Invalid input parameter */
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(qid > RTL8367C_QIDMAX)
+        return RT_ERR_QUEUE_ID;
+
+    /* Set Related Registers */
+    retVal = rtl8367c_setAsicRegBit(RTL8367C_SCHEDULE_QUEUE_TYPE_REG(port), RTL8367C_SCHEDULE_QUEUE_TYPE_OFFSET(port, qid),queueType);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicQueueType
+ * Description:
+ *      Get type of a queue
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      qid         - The queue ID wanted to set
+ *      queueType   - The specified queue type. 0b0: Strict priority, 0b1: WFQ
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ *      RT_ERR_QUEUE_ID - Invalid queue id
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicQueueType(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 *queueType)
+{
+    ret_t retVal;
+
+    /* Invalid input parameter */
+    if(port  > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(qid > RTL8367C_QIDMAX)
+        return RT_ERR_QUEUE_ID;
+
+    retVal = rtl8367c_getAsicRegBit(RTL8367C_SCHEDULE_QUEUE_TYPE_REG(port), RTL8367C_SCHEDULE_QUEUE_TYPE_OFFSET(port, qid),queueType);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_setAsicPortEgressRate
+ * Description:
+ *      Set per-port egress rate
+ * Input:
+ *      port        - Physical port number (0~10)
+ *      rate        - Egress rate
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_QOS_EBW_RATE - Invalid bandwidth/rate
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortEgressRate(rtk_uint32 port, rtk_uint32 rate)
+{
+    ret_t retVal;
+    rtk_uint32 regAddr, regData;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(rate > RTL8367C_QOS_GRANULARTY_MAX)
+        return RT_ERR_QOS_EBW_RATE;
+
+    regAddr = RTL8367C_PORT_EGRESSBW_LSB_REG(port);
+    regData = RTL8367C_QOS_GRANULARTY_LSB_MASK & rate;
+
+    retVal = rtl8367c_setAsicReg(regAddr, regData);
+
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    regAddr = RTL8367C_PORT_EGRESSBW_MSB_REG(port);
+    regData = (RTL8367C_QOS_GRANULARTY_MSB_MASK & rate) >> RTL8367C_QOS_GRANULARTY_MSB_OFFSET;
+
+    retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_PORT6_EGRESSBW_CTRL1_MASK, regData);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortEgressRate
+ * Description:
+ *      Get per-port egress rate
+ * Input:
+ *      port        - Physical port number (0~10)
+ *      rate        - Egress rate
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortEgressRate(rtk_uint32 port, rtk_uint32 *rate)
+{
+    ret_t retVal;
+    rtk_uint32 regAddr, regData,regData2;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    regAddr = RTL8367C_PORT_EGRESSBW_LSB_REG(port);
+
+    retVal = rtl8367c_getAsicReg(regAddr, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    regAddr = RTL8367C_PORT_EGRESSBW_MSB_REG(port);
+    retVal = rtl8367c_getAsicRegBits(regAddr, RTL8367C_PORT6_EGRESSBW_CTRL1_MASK, &regData2);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *rate = regData | (regData2 << RTL8367C_QOS_GRANULARTY_MSB_OFFSET);
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicPortEgressRateIfg
+ * Description:
+ *      Set per-port egress rate calculate include/exclude IFG
+ * Input:
+ *      ifg     - 1:include IFG 0:exclude IFG
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortEgressRateIfg(rtk_uint32 ifg)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SCHEDULE_WFQ_CTRL, RTL8367C_SCHEDULE_WFQ_CTRL_OFFSET, ifg);
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortEgressRateIfg
+ * Description:
+ *      Get per-port egress rate calculate include/exclude IFG
+ * Input:
+ *      ifg     - 1:include IFG 0:exclude IFG
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortEgressRateIfg(rtk_uint32 *ifg)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SCHEDULE_WFQ_CTRL, RTL8367C_SCHEDULE_WFQ_CTRL_OFFSET, ifg);
+
+    return retVal;
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_storm.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_storm.c
new file mode 100644
index 0000000..a29f647
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_storm.c
@@ -0,0 +1,851 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Storm control filtering related functions
+ *
+ */
+
+#include <rtl8367c_asicdrv_storm.h>
+/* Function Name:
+ *      rtl8367c_setAsicStormFilterBroadcastEnable
+ * Description:
+ *      Set per-port broadcast storm filter enable/disable
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      enabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicStormFilterBroadcastEnable(rtk_uint32 port, rtk_uint32 enabled)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_STORM_BCAST_REG, port, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicStormFilterBroadcastEnable
+ * Description:
+ *      Get per-port broadcast storm filter enable/disable
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pEnabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicStormFilterBroadcastEnable(rtk_uint32 port, rtk_uint32 *pEnabled)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_STORM_BCAST_REG, port, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicStormFilterBroadcastMeter
+ * Description:
+ *      Set per-port broadcast storm filter meter
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      meter   - meter index (0~31)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicStormFilterBroadcastMeter(rtk_uint32 port, rtk_uint32 meter)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if(meter > RTL8367C_METERMAX)
+        return RT_ERR_FILTER_METER_ID;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_STORM_BCAST_METER_CTRL_REG(port), RTL8367C_STORM_BCAST_METER_CTRL_MASK(port), meter);
+}
+/* Function Name:
+ *      rtl8367c_getAsicStormFilterBroadcastMeter
+ * Description:
+ *      Get per-port broadcast storm filter meter
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pMeter  - meter index (0~31)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicStormFilterBroadcastMeter(rtk_uint32 port, rtk_uint32 *pMeter)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_STORM_BCAST_METER_CTRL_REG(port), RTL8367C_STORM_BCAST_METER_CTRL_MASK(port), pMeter);
+}
+/* Function Name:
+ *      rtl8367c_setAsicStormFilterMulticastEnable
+ * Description:
+ *      Set per-port multicast storm filter enable/disable
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      enabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicStormFilterMulticastEnable(rtk_uint32 port, rtk_uint32 enabled)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_STORM_MCAST_REG, port, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicStormFilterMulticastEnable
+ * Description:
+ *      Get per-port multicast storm filter enable/disable
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pEnabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicStormFilterMulticastEnable(rtk_uint32 port, rtk_uint32 *pEnabled)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_STORM_MCAST_REG, port, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicStormFilterMulticastMeter
+ * Description:
+ *      Set per-port multicast storm filter meter
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      meter   - meter index (0~31)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicStormFilterMulticastMeter(rtk_uint32 port, rtk_uint32 meter)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if(meter > RTL8367C_METERMAX)
+        return RT_ERR_FILTER_METER_ID;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_STORM_MCAST_METER_CTRL_REG(port), RTL8367C_STORM_MCAST_METER_CTRL_MASK(port), meter);
+}
+/* Function Name:
+ *      rtl8367c_getAsicStormFilterMulticastMeter
+ * Description:
+ *      Get per-port multicast storm filter meter
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pMeter  - meter index (0~31)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicStormFilterMulticastMeter(rtk_uint32 port, rtk_uint32 *pMeter)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_STORM_MCAST_METER_CTRL_REG(port), RTL8367C_STORM_MCAST_METER_CTRL_MASK(port), pMeter);
+}
+/* Function Name:
+ *      rtl8367c_setAsicStormFilterUnknownMulticastEnable
+ * Description:
+ *      Set per-port unknown multicast storm filter enable/disable
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      enabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicStormFilterUnknownMulticastEnable(rtk_uint32 port, rtk_uint32 enabled)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_STORM_UNKNOWN_MCAST_REG, port, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicStormFilterUnknownMulticastEnable
+ * Description:
+ *      Get per-port unknown multicast storm filter enable/disable
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pEnabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicStormFilterUnknownMulticastEnable(rtk_uint32 port, rtk_uint32 *pEnabled)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_STORM_UNKNOWN_MCAST_REG, port, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicStormFilterUnknownMulticastMeter
+ * Description:
+ *      Set per-port unknown multicast storm filter meter
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      meter   - meter index (0~31)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicStormFilterUnknownMulticastMeter(rtk_uint32 port, rtk_uint32 meter)
+{
+    ret_t retVal;
+
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if(meter > RTL8367C_METERMAX)
+        return RT_ERR_FILTER_METER_ID;
+
+    if(port < 8)
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_STORM_UNMC_METER_CTRL_REG(port), RTL8367C_STORM_UNMC_METER_CTRL_MASK(port), meter);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_STORM_UNMC_METER_CTRL4 + ((port - 8) >> 1), RTL8367C_STORM_UNMC_METER_CTRL_MASK(port), meter);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicStormFilterUnknownMulticastMeter
+ * Description:
+ *      Get per-port unknown multicast storm filter meter
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pMeter  - meter index (0~31)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicStormFilterUnknownMulticastMeter(rtk_uint32 port, rtk_uint32 *pMeter)
+{
+    ret_t retVal;
+
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if(port < 8)
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_STORM_UNMC_METER_CTRL_REG(port), RTL8367C_STORM_UNMC_METER_CTRL_MASK(port), pMeter);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_STORM_UNMC_METER_CTRL4 + ((port - 8) >> 1), RTL8367C_STORM_UNMC_METER_CTRL_MASK(port), pMeter);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicStormFilterUnknownUnicastEnable
+ * Description:
+ *      Set per-port unknown unicast storm filter enable/disable
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      enabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicStormFilterUnknownUnicastEnable(rtk_uint32 port, rtk_uint32 enabled)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_STORM_UNKNOWN_UCAST_REG, port, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicStormFilterUnknownUnicastEnable
+ * Description:
+ *      get per-port unknown unicast storm filter enable/disable
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pEnabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicStormFilterUnknownUnicastEnable(rtk_uint32 port, rtk_uint32 *pEnabled)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_STORM_UNKNOWN_UCAST_REG, port, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicStormFilterUnknownUnicastMeter
+ * Description:
+ *      Set per-port unknown unicast storm filter meter
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      meter   - meter index (0~31)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicStormFilterUnknownUnicastMeter(rtk_uint32 port, rtk_uint32 meter)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if(meter > RTL8367C_METERMAX)
+        return RT_ERR_FILTER_METER_ID;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_STORM_UNDA_METER_CTRL_REG(port), RTL8367C_STORM_UNDA_METER_CTRL_MASK(port), meter);
+}
+/* Function Name:
+ *      rtl8367c_getAsicStormFilterUnknownUnicastMeter
+ * Description:
+ *      Get per-port unknown unicast storm filter meter
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pMeter  - meter index (0~31)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicStormFilterUnknownUnicastMeter(rtk_uint32 port, rtk_uint32 *pMeter)
+{
+    if(port >= RTL8367C_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_STORM_UNDA_METER_CTRL_REG(port), RTL8367C_STORM_UNDA_METER_CTRL_MASK(port), pMeter);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicStormFilterExtBroadcastMeter
+ * Description:
+ *      Set extension broadcast storm filter meter
+ * Input:
+ *      meter   - meter index (0~31)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicStormFilterExtBroadcastMeter(rtk_uint32 meter)
+{
+    if(meter > RTL8367C_METERMAX)
+        return RT_ERR_FILTER_METER_ID;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG0, RTL8367C_BC_STORM_EXT_METERIDX_MASK, meter);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicStormFilterExtBroadcastMeter
+ * Description:
+ *      get extension broadcast storm filter meter
+ * Input:
+ *      None
+ * Output:
+ *      pMeter  - meter index (0~31)
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_NULL_POINTER     - Invalid meter index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicStormFilterExtBroadcastMeter(rtk_uint32 *pMeter)
+{
+    if(NULL == pMeter)
+        return RT_ERR_NULL_POINTER;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG0, RTL8367C_BC_STORM_EXT_METERIDX_MASK, pMeter);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicStormFilterExtMulticastMeter
+ * Description:
+ *      Set extension multicast storm filter meter
+ * Input:
+ *      meter   - meter index (0~31)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicStormFilterExtMulticastMeter(rtk_uint32 meter)
+{
+    if(meter > RTL8367C_METERMAX)
+        return RT_ERR_FILTER_METER_ID;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG0, RTL8367C_MC_STORM_EXT_METERIDX_MASK, meter);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicStormFilterExtMulticastMeter
+ * Description:
+ *      get extension multicast storm filter meter
+ * Input:
+ *      None
+ * Output:
+ *      pMeter  - meter index (0~31)
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_NULL_POINTER     - Invalid meter index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicStormFilterExtMulticastMeter(rtk_uint32 *pMeter)
+{
+    if(NULL == pMeter)
+        return RT_ERR_NULL_POINTER;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG0, RTL8367C_MC_STORM_EXT_METERIDX_MASK, pMeter);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicStormFilterExtUnknownMulticastMeter
+ * Description:
+ *      Set extension unknown multicast storm filter meter
+ * Input:
+ *      meter   - meter index (0~31)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicStormFilterExtUnknownMulticastMeter(rtk_uint32 meter)
+{
+    if(meter > RTL8367C_METERMAX)
+        return RT_ERR_FILTER_METER_ID;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG1, RTL8367C_UNMC_STORM_EXT_METERIDX_MASK, meter);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicStormFilterExtUnknownMulticastMeter
+ * Description:
+ *      get extension unknown multicast storm filter meter
+ * Input:
+ *      None
+ * Output:
+ *      pMeter  - meter index (0~31)
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_NULL_POINTER     - Invalid meter index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicStormFilterExtUnknownMulticastMeter(rtk_uint32 *pMeter)
+{
+    if(NULL == pMeter)
+        return RT_ERR_NULL_POINTER;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG1, RTL8367C_UNMC_STORM_EXT_METERIDX_MASK, pMeter);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicStormFilterExtUnknownUnicastMeter
+ * Description:
+ *      Set extension unknown unicast storm filter meter
+ * Input:
+ *      meter   - meter index (0~31)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicStormFilterExtUnknownUnicastMeter(rtk_uint32 meter)
+{
+    if(meter > RTL8367C_METERMAX)
+        return RT_ERR_FILTER_METER_ID;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG1, RTL8367C_UNUC_STORM_EXT_METERIDX_MASK, meter);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicStormFilterExtUnknownUnicastMeter
+ * Description:
+ *      get extension unknown unicast storm filter meter
+ * Input:
+ *      None
+ * Output:
+ *      pMeter  - meter index (0~31)
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_NULL_POINTER     - Invalid meter index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicStormFilterExtUnknownUnicastMeter(rtk_uint32 *pMeter)
+{
+    if(NULL == pMeter)
+        return RT_ERR_NULL_POINTER;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG1, RTL8367C_UNUC_STORM_EXT_METERIDX_MASK, pMeter);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicStormFilterExtBroadcastEnable
+ * Description:
+ *      Set extension broadcast storm filter state
+ * Input:
+ *      enabled     - state
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicStormFilterExtBroadcastEnable(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_BCAST_EXT_EN_OFFSET, enabled);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicStormFilterExtBroadcastEnable
+ * Description:
+ *      Get extension broadcast storm filter state
+ * Input:
+ *      None
+ * Output:
+ *      pEnabled    - state
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_NULL_POINTER     - Null pointer
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicStormFilterExtBroadcastEnable(rtk_uint32 *pEnabled)
+{
+    if(NULL == pEnabled)
+        return RT_ERR_NULL_POINTER;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_BCAST_EXT_EN_OFFSET, pEnabled);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicStormFilterExtMulticastEnable
+ * Description:
+ *      Set extension multicast storm filter state
+ * Input:
+ *      enabled     - state
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicStormFilterExtMulticastEnable(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_MCAST_EXT_EN_OFFSET, enabled);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicStormFilterExtMulticastEnable
+ * Description:
+ *      Get extension multicast storm filter state
+ * Input:
+ *      None
+ * Output:
+ *      pEnabled    - state
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_NULL_POINTER     - Null pointer
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicStormFilterExtMulticastEnable(rtk_uint32 *pEnabled)
+{
+    if(NULL == pEnabled)
+        return RT_ERR_NULL_POINTER;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_MCAST_EXT_EN_OFFSET, pEnabled);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicStormFilterExtUnknownMulticastEnable
+ * Description:
+ *      Set extension unknown multicast storm filter state
+ * Input:
+ *      enabled     - state
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicStormFilterExtUnknownMulticastEnable(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_UNKNOWN_MCAST_EXT_EN_OFFSET, enabled);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicStormFilterExtUnknownMulticastEnable
+ * Description:
+ *      Get extension unknown multicast storm filter state
+ * Input:
+ *      None
+ * Output:
+ *      pEnabled    - state
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_NULL_POINTER     - Null pointer
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicStormFilterExtUnknownMulticastEnable(rtk_uint32 *pEnabled)
+{
+    if(NULL == pEnabled)
+        return RT_ERR_NULL_POINTER;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_UNKNOWN_MCAST_EXT_EN_OFFSET, pEnabled);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicStormFilterExtUnknownUnicastEnable
+ * Description:
+ *      Set extension unknown unicast storm filter state
+ * Input:
+ *      enabled     - state
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicStormFilterExtUnknownUnicastEnable(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_UNKNOWN_UCAST_EXT_EN_OFFSET, enabled);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicStormFilterExtUnknownUnicastEnable
+ * Description:
+ *      Get extension unknown unicast storm filter state
+ * Input:
+ *      None
+ * Output:
+ *      pEnabled    - state
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_NULL_POINTER     - Null pointer
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicStormFilterExtUnknownUnicastEnable(rtk_uint32 *pEnabled)
+{
+    if(NULL == pEnabled)
+        return RT_ERR_NULL_POINTER;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_UNKNOWN_UCAST_EXT_EN_OFFSET, pEnabled);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicStormFilterExtEnablePortMask
+ * Description:
+ *      Set extension storm filter port mask
+ * Input:
+ *      portmask    - port mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicStormFilterExtEnablePortMask(rtk_uint32 portmask)
+{
+    ret_t retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_EXT_EN_PORTMASK_MASK, portmask & 0x3FF);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_EXT_EN_PORTMASK_EXT_MASK, (portmask >> 10)&1);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicStormFilterExtEnablePortMask
+ * Description:
+ *      Get extension storm filter port mask
+ * Input:
+ *      portmask    - port mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_NULL_POINTER     - Null pointer
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicStormFilterExtEnablePortMask(rtk_uint32 *pPortmask)
+{
+    rtk_uint32 tmpPmsk;
+    ret_t retVal;
+
+    if(NULL == pPortmask)
+        return RT_ERR_NULL_POINTER;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_EXT_EN_PORTMASK_MASK, &tmpPmsk);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+    *pPortmask = tmpPmsk & 0x3ff;
+
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_EXT_EN_PORTMASK_EXT_MASK, &tmpPmsk);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+    *pPortmask |= (tmpPmsk & 1) << 10;
+
+    return RT_ERR_OK;
+}
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_svlan.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_svlan.c
new file mode 100644
index 0000000..f19ceba
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_svlan.c
@@ -0,0 +1,1003 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : SVLAN related functions
+ *
+ */
+#include <rtl8367c_asicdrv_svlan.h>
+
+#include <string.h>
+
+static void _rtl8367c_svlanConfStUser2Smi( rtl8367c_svlan_memconf_t *pUserSt, rtk_uint16 *pSmiSt)
+{
+    pSmiSt[0] |= (pUserSt->vs_member & 0x00FF);
+    pSmiSt[0] |= (pUserSt->vs_untag & 0x00FF) << 8;
+
+    pSmiSt[1] |= (pUserSt->vs_fid_msti & 0x000F);
+    pSmiSt[1] |= (pUserSt->vs_priority & 0x0007) << 4;
+    pSmiSt[1] |= (pUserSt->vs_force_fid & 0x0001) << 7;
+
+    pSmiSt[2] |= (pUserSt->vs_svid & 0x0FFF);
+    pSmiSt[2] |= (pUserSt->vs_efiden & 0x0001) << 12;
+    pSmiSt[2] |= (pUserSt->vs_efid & 0x0007) << 13;
+
+    pSmiSt[3] |= ((pUserSt->vs_member & 0x0700) >> 8);
+    pSmiSt[3] |= ((pUserSt->vs_untag & 0x0700) >> 8) << 3;
+}
+
+static void _rtl8367c_svlanConfStSmi2User( rtl8367c_svlan_memconf_t *pUserSt, rtk_uint16 *pSmiSt)
+{
+
+    pUserSt->vs_member = (pSmiSt[0] & 0x00FF) | ((pSmiSt[3] & 0x0007) << 8);
+    pUserSt->vs_untag = ((pSmiSt[0] & 0xFF00) >> 8) | (((pSmiSt[3] & 0x0038) >> 3) << 8);
+
+    pUserSt->vs_fid_msti = (pSmiSt[1] & 0x000F);
+    pUserSt->vs_priority = (pSmiSt[1] & 0x0070) >> 4;
+    pUserSt->vs_force_fid = (pSmiSt[1] & 0x0080) >> 7;
+
+    pUserSt->vs_svid = (pSmiSt[2] & 0x0FFF);
+    pUserSt->vs_efiden = (pSmiSt[2] & 0x1000) >> 12;
+    pUserSt->vs_efid = (pSmiSt[2] & 0xE000) >> 13;
+}
+
+static void _rtl8367c_svlanMc2sStUser2Smi(rtl8367c_svlan_mc2s_t *pUserSt, rtk_uint16 *pSmiSt)
+{
+    pSmiSt[0] |= (pUserSt->svidx & 0x003F);
+    pSmiSt[0] |= (pUserSt->format & 0x0001) << 6;
+    pSmiSt[0] |= (pUserSt->valid & 0x0001) << 7;
+
+    pSmiSt[1] = (rtk_uint16)(pUserSt->smask & 0x0000FFFF);
+    pSmiSt[2] = (rtk_uint16)((pUserSt->smask & 0xFFFF0000) >> 16);
+
+    pSmiSt[3] = (rtk_uint16)(pUserSt->sdata & 0x0000FFFF);
+    pSmiSt[4] = (rtk_uint16)((pUserSt->sdata & 0xFFFF0000) >> 16);
+}
+
+static void _rtl8367c_svlanMc2sStSmi2User(rtl8367c_svlan_mc2s_t *pUserSt, rtk_uint16 *pSmiSt)
+{
+    pUserSt->svidx = (pSmiSt[0] & 0x003F);
+    pUserSt->format = (pSmiSt[0] & 0x0040) >> 6;
+    pUserSt->valid = (pSmiSt[0] & 0x0080) >> 7;
+
+    pUserSt->smask = pSmiSt[1] | (pSmiSt[2] << 16);
+    pUserSt->sdata = pSmiSt[3] | (pSmiSt[4] << 16);
+}
+
+static void _rtl8367c_svlanSp2cStUser2Smi(rtl8367c_svlan_s2c_t *pUserSt, rtk_uint16 *pSmiSt)
+{
+    pSmiSt[0] |= (pUserSt->dstport & 0x0007);
+    pSmiSt[0] |= (pUserSt->svidx & 0x003F) << 3;
+    pSmiSt[0] |= ((pUserSt->dstport & 0x0008) >> 3) << 9;
+
+    pSmiSt[1] |= (pUserSt->vid & 0x0FFF);
+    pSmiSt[1] |= (pUserSt->valid & 0x0001) << 12;
+}
+
+static void _rtl8367c_svlanSp2cStSmi2User(rtl8367c_svlan_s2c_t *pUserSt, rtk_uint16 *pSmiSt)
+{
+    pUserSt->dstport = (((pSmiSt[0] & 0x0200) >> 9) << 3) | (pSmiSt[0] & 0x0007);
+    pUserSt->svidx   = (pSmiSt[0] & 0x01F8) >> 3;
+    pUserSt->vid     = (pSmiSt[1] & 0x0FFF);
+    pUserSt->valid   = (pSmiSt[1] & 0x1000) >> 12;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicSvlanUplinkPortMask
+ * Description:
+ *      Set uplink ports mask
+ * Input:
+ *      portMask    - Uplink port mask setting
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicSvlanUplinkPortMask(rtk_uint32 portMask)
+{
+    return rtl8367c_setAsicReg(RTL8367C_REG_SVLAN_UPLINK_PORTMASK, portMask);
+}
+/* Function Name:
+ *      rtl8367c_getAsicSvlanUplinkPortMask
+ * Description:
+ *      Get uplink ports mask
+ * Input:
+ *      pPortmask   - Uplink port mask setting
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicSvlanUplinkPortMask(rtk_uint32* pPortmask)
+{
+    return rtl8367c_getAsicReg(RTL8367C_REG_SVLAN_UPLINK_PORTMASK, pPortmask);
+}
+/* Function Name:
+ *      rtl8367c_setAsicSvlanTpid
+ * Description:
+ *      Set accepted S-VLAN ether type. The default ether type of S-VLAN is 0x88a8
+ * Input:
+ *      protocolType    - Ether type of S-tag frame parsing in uplink ports
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      Ether type of S-tag in 802.1ad is 0x88a8 and there are existed ether type 0x9100 and 0x9200
+ *      for Q-in-Q SLAN design. User can set mathced ether type as service provider supported protocol
+ */
+ret_t rtl8367c_setAsicSvlanTpid(rtk_uint32 protocolType)
+{
+    return rtl8367c_setAsicReg(RTL8367C_REG_VS_TPID, protocolType);
+}
+/* Function Name:
+ *      rtl8367c_getAsicReg
+ * Description:
+ *      Get accepted S-VLAN ether type. The default ether type of S-VLAN is 0x88a8
+ * Input:
+ *      pProtocolType   - Ether type of S-tag frame parsing in uplink ports
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicSvlanTpid(rtk_uint32* pProtocolType)
+{
+    return rtl8367c_getAsicReg(RTL8367C_REG_VS_TPID, pProtocolType);
+}
+/* Function Name:
+ *      rtl8367c_setAsicSvlanPrioritySel
+ * Description:
+ *      Set SVLAN priority field setting
+ * Input:
+ *      priSel  - S-priority assignment method, 0:internal priority 1:C-tag priority 2:using Svlan member configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_INPUT    - Invalid input parameter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicSvlanPrioritySel(rtk_uint32 priSel)
+{
+    if(priSel >= SPRISEL_END)
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_SPRISEL_MASK, priSel);
+}
+/* Function Name:
+ *      rtl8367c_getAsicSvlanPrioritySel
+ * Description:
+ *      Get SVLAN priority field setting
+ * Input:
+ *      pPriSel     - S-priority assignment method, 0:internal priority 1:C-tag priority 2:using Svlan member configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicSvlanPrioritySel(rtk_uint32* pPriSel)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_SPRISEL_MASK, pPriSel);
+}
+/* Function Name:
+ *      rtl8367c_setAsicSvlanTrapPriority
+ * Description:
+ *      Set trap to CPU priority assignment
+ * Input:
+ *      priority    - Priority assignment
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicSvlanTrapPriority(rtk_uint32 priority)
+{
+    if(priority > RTL8367C_PRIMAX)
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_QOS_TRAP_PRIORITY0, RTL8367C_SVLAN_PRIOIRTY_MASK, priority);
+}
+/* Function Name:
+ *      rtl8367c_getAsicSvlanTrapPriority
+ * Description:
+ *      Get trap to CPU priority assignment
+ * Input:
+ *      pPriority   - Priority assignment
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicSvlanTrapPriority(rtk_uint32* pPriority)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_QOS_TRAP_PRIORITY0, RTL8367C_SVLAN_PRIOIRTY_MASK, pPriority);
+}
+/* Function Name:
+ *      rtl8367c_setAsicSvlanDefaultVlan
+ * Description:
+ *      Set default egress SVLAN
+ * Input:
+ *      port    - Physical port number (0~10)
+ *      index   - index SVLAN member configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number
+ *      RT_ERR_SVLAN_ENTRY_INDEX    - Invalid SVLAN index parameter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicSvlanDefaultVlan(rtk_uint32 port, rtk_uint32 index)
+{
+    ret_t retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(index > RTL8367C_SVIDXMAX)
+        return RT_ERR_SVLAN_ENTRY_INDEX;
+
+    if(port < 8){
+        if(port & 1)
+            retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL0 + (port >> 1), RTL8367C_VS_PORT1_SVIDX_MASK,index);
+        else
+            retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL0 + (port >> 1), RTL8367C_VS_PORT0_SVIDX_MASK,index);
+    }else{
+        switch(port){
+            case 8:
+                retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL4, RTL8367C_VS_PORT8_SVIDX_MASK,index);
+                break;
+
+            case 9:
+                retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL4, RTL8367C_VS_PORT9_SVIDX_MASK,index);
+                break;
+
+            case 10:
+                retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL5, RTL8367C_SVLAN_PORTBASED_SVIDX_CTRL5_MASK,index);
+                break;
+        }
+    }
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicSvlanDefaultVlan
+ * Description:
+ *      Get default egress SVLAN
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pIndex  - index SVLAN member configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicSvlanDefaultVlan(rtk_uint32 port, rtk_uint32* pIndex)
+{
+    ret_t retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(port < 8){
+        if(port & 1)
+            retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL0 + (port >> 1), RTL8367C_VS_PORT1_SVIDX_MASK,pIndex);
+        else
+            retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL0 + (port >> 1), RTL8367C_VS_PORT0_SVIDX_MASK,pIndex);
+    }else{
+        switch(port){
+            case 8:
+                retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL4, RTL8367C_VS_PORT8_SVIDX_MASK,pIndex);
+                break;
+
+            case 9:
+                retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL4, RTL8367C_VS_PORT9_SVIDX_MASK,pIndex);
+                break;
+
+            case 10:
+                retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL5, RTL8367C_SVLAN_PORTBASED_SVIDX_CTRL5_MASK,pIndex);
+                break;
+        }
+    }
+
+    return retVal;
+
+}
+/* Function Name:
+ *      rtl8367c_setAsicSvlanIngressUntag
+ * Description:
+ *      Set action received un-Stag frame from unplink port
+ * Input:
+ *      mode        - 0:Drop 1:Trap 2:Assign SVLAN
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicSvlanIngressUntag(rtk_uint32 mode)
+{
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_UNTAG_MASK, mode);
+}
+/* Function Name:
+ *      rtl8367c_getAsicSvlanIngressUntag
+ * Description:
+ *      Get action received un-Stag frame from unplink port
+ * Input:
+ *      pMode       - 0:Drop 1:Trap 2:Assign SVLAN
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicSvlanIngressUntag(rtk_uint32* pMode)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_UNTAG_MASK, pMode);
+}
+/* Function Name:
+ *      rtl8367c_setAsicSvlanIngressUnmatch
+ * Description:
+ *      Set action received unmatched Stag frame from unplink port
+ * Input:
+ *      mode        - 0:Drop 1:Trap 2:Assign SVLAN
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicSvlanIngressUnmatch(rtk_uint32 mode)
+{
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_UNMAT_MASK, mode);
+}
+/* Function Name:
+ *      rtl8367c_getAsicSvlanIngressUnmatch
+ * Description:
+ *      Get action received unmatched Stag frame from unplink port
+ * Input:
+ *      pMode       - 0:Drop 1:Trap 2:Assign SVLAN
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicSvlanIngressUnmatch(rtk_uint32* pMode)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_UNMAT_MASK, pMode);
+
+}
+/* Function Name:
+ *      rtl8367c_setAsicSvlanEgressUnassign
+ * Description:
+ *      Set unplink stream without egress SVID action
+ * Input:
+ *      enabled     - 1:Trap egress unassigned frames to CPU, 0: Use SVLAN setup in VS_CPSVIDX as egress SVID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicSvlanEgressUnassign(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_UIFSEG_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicSvlanEgressUnassign
+ * Description:
+ *      Get unplink stream without egress SVID action
+ * Input:
+ *      pEnabled    - 1:Trap egress unassigned frames to CPU, 0: Use SVLAN setup in VS_CPSVIDX as egress SVID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicSvlanEgressUnassign(rtk_uint32* pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_UIFSEG_OFFSET, pEnabled);
+}
+
+
+/* Function Name:
+ *      rtl8367c_setAsicSvlanMemberConfiguration
+ * Description:
+ *      Set system 64 S-tag content
+ * Input:
+ *      index           - index of 64 s-tag configuration
+ *      pSvlanMemCfg    - SVLAN member configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_SVLAN_ENTRY_INDEX    - Invalid SVLAN index parameter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicSvlanMemberConfiguration(rtk_uint32 index, rtl8367c_svlan_memconf_t* pSvlanMemCfg)
+{
+    ret_t retVal;
+    rtk_uint32 regAddr, regData;
+    rtk_uint16 *accessPtr;
+    rtk_uint32 i;
+    rtk_uint16 smiSvlanMemConf[RTL8367C_SVLAN_MEMCONF_LEN];
+
+    if(index > RTL8367C_SVIDXMAX)
+        return RT_ERR_SVLAN_ENTRY_INDEX;
+
+    memset(smiSvlanMemConf, 0x00, sizeof(rtk_uint16) * RTL8367C_SVLAN_MEMCONF_LEN);
+    _rtl8367c_svlanConfStUser2Smi(pSvlanMemCfg, smiSvlanMemConf);
+
+    accessPtr = smiSvlanMemConf;
+
+    regData = *accessPtr;
+    for(i = 0; i < 3; i++)
+    {
+        retVal = rtl8367c_setAsicReg(RTL8367C_SVLAN_MEMBERCFG_BASE_REG(index) + i, regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        accessPtr ++;
+        regData = *accessPtr;
+    }
+
+    if(index < 63)
+        regAddr = RTL8367C_REG_SVLAN_MEMBERCFG0_CTRL4+index;
+    else if(index == 63)
+        regAddr = RTL8367C_REG_SVLAN_MEMBERCFG63_CTRL4;
+
+    retVal = rtl8367c_setAsicReg(regAddr, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+
+}
+/* Function Name:
+ *      rtl8367c_getAsicSvlanMemberConfiguration
+ * Description:
+ *      Get system 64 S-tag content
+ * Input:
+ *      index           - index of 64 s-tag configuration
+ *      pSvlanMemCfg    - SVLAN member configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_SVLAN_ENTRY_INDEX    - Invalid SVLAN index parameter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicSvlanMemberConfiguration(rtk_uint32 index,rtl8367c_svlan_memconf_t* pSvlanMemCfg)
+{
+    ret_t retVal;
+    rtk_uint32 regAddr,regData;
+    rtk_uint16 *accessPtr;
+    rtk_uint32 i;
+    rtk_uint16 smiSvlanMemConf[RTL8367C_SVLAN_MEMCONF_LEN];
+
+    if(index > RTL8367C_SVIDXMAX)
+        return RT_ERR_SVLAN_ENTRY_INDEX;
+
+    memset(smiSvlanMemConf, 0x00, sizeof(rtk_uint16) * RTL8367C_SVLAN_MEMCONF_LEN);
+
+    accessPtr = smiSvlanMemConf;
+
+    for(i = 0; i < 3; i++)
+    {
+        retVal = rtl8367c_getAsicReg(RTL8367C_SVLAN_MEMBERCFG_BASE_REG(index) + i, &regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        *accessPtr = regData;
+
+        accessPtr ++;
+    }
+
+    if(index < 63)
+        regAddr = RTL8367C_REG_SVLAN_MEMBERCFG0_CTRL4+index;
+    else if(index == 63)
+        regAddr = RTL8367C_REG_SVLAN_MEMBERCFG63_CTRL4;
+
+    retVal = rtl8367c_getAsicReg(regAddr, &regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    *accessPtr = regData;
+
+    _rtl8367c_svlanConfStSmi2User(pSvlanMemCfg, smiSvlanMemConf);
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicSvlanC2SConf
+ * Description:
+ *      Set SVLAN C2S table
+ * Input:
+ *      index   - index of 128 Svlan C2S configuration
+ *      evid    - Enhanced VID
+ *      portmask    - available c2s port mask
+ *      svidx   - index of 64 Svlan member configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_ENTRY_INDEX  - Invalid entry index
+ * Note:
+ *      ASIC will check upstream's VID and assign related SVID to mathed packet
+ */
+ret_t rtl8367c_setAsicSvlanC2SConf(rtk_uint32 index, rtk_uint32 evid, rtk_uint32 portmask, rtk_uint32 svidx)
+{
+    ret_t retVal;
+
+    if(index > RTL8367C_C2SIDXMAX)
+        return RT_ERR_ENTRY_INDEX;
+
+    retVal = rtl8367c_setAsicReg(RTL8367C_SVLAN_C2SCFG_BASE_REG(index), svidx);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicReg(RTL8367C_SVLAN_C2SCFG_BASE_REG(index) + 1, portmask);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_setAsicReg(RTL8367C_SVLAN_C2SCFG_BASE_REG(index) + 2, evid);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicSvlanC2SConf
+ * Description:
+ *      Get SVLAN C2S table
+ * Input:
+ *      index   - index of 128 Svlan C2S configuration
+ *      pEvid   - Enhanced VID
+ *      pPortmask   - available c2s port mask
+ *      pSvidx  - index of 64 Svlan member configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_ENTRY_INDEX  - Invalid entry index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicSvlanC2SConf(rtk_uint32 index, rtk_uint32* pEvid, rtk_uint32* pPortmask, rtk_uint32* pSvidx)
+{
+    ret_t retVal;
+
+    if(index > RTL8367C_C2SIDXMAX)
+        return RT_ERR_ENTRY_INDEX;
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_SVLAN_C2SCFG_BASE_REG(index), pSvidx);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_SVLAN_C2SCFG_BASE_REG(index) + 1, pPortmask);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    retVal = rtl8367c_getAsicReg(RTL8367C_SVLAN_C2SCFG_BASE_REG(index) + 2, pEvid);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicSvlanMC2SConf
+ * Description:
+ *      Set system MC2S content
+ * Input:
+ *      index           - index of 32 SVLAN 32 MC2S configuration
+ *      pSvlanMc2sCfg   - SVLAN Multicast to SVLAN member configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_ENTRY_INDEX  - Invalid entry index
+ * Note:
+ *      If upstream packet is L2 multicast or IPv4 multicast packet and DMAC/DIP is matched MC2S
+ *      configuration, ASIC will assign egress SVID to the packet
+ */
+ret_t rtl8367c_setAsicSvlanMC2SConf(rtk_uint32 index,rtl8367c_svlan_mc2s_t* pSvlanMc2sCfg)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+    rtk_uint16 *accessPtr;
+    rtk_uint32 i;
+    rtk_uint16 smiSvlanMC2S[RTL8367C_SVLAN_MC2S_LEN];
+
+    if(index > RTL8367C_MC2SIDXMAX)
+        return RT_ERR_ENTRY_INDEX;
+
+    memset(smiSvlanMC2S, 0x00, sizeof(rtk_uint16) * RTL8367C_SVLAN_MC2S_LEN);
+    _rtl8367c_svlanMc2sStUser2Smi(pSvlanMc2sCfg, smiSvlanMC2S);
+
+    accessPtr = smiSvlanMC2S;
+
+    regData = *accessPtr;
+    for(i = 0; i < 5; i++)
+    {
+        retVal = rtl8367c_setAsicReg(RTL8367C_SVLAN_MCAST2S_ENTRY_BASE_REG(index) + i, regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        accessPtr ++;
+        regData = *accessPtr;
+    }
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicSvlanMC2SConf
+ * Description:
+ *      Get system MC2S content
+ * Input:
+ *      index           - index of 32 SVLAN 32 MC2S configuration
+ *      pSvlanMc2sCfg   - SVLAN Multicast to SVLAN member configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_ENTRY_INDEX  - Invalid entry index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicSvlanMC2SConf(rtk_uint32 index, rtl8367c_svlan_mc2s_t* pSvlanMc2sCfg)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+    rtk_uint16 *accessPtr;
+    rtk_uint32 i;
+    rtk_uint16 smiSvlanMC2S[RTL8367C_SVLAN_MC2S_LEN];
+
+    if(index > RTL8367C_MC2SIDXMAX)
+        return RT_ERR_ENTRY_INDEX;
+
+    memset(smiSvlanMC2S, 0x00, sizeof(rtk_uint16) * RTL8367C_SVLAN_MC2S_LEN);
+
+    accessPtr = smiSvlanMC2S;
+
+    for(i = 0; i < 5; i++)
+    {
+        retVal = rtl8367c_getAsicReg(RTL8367C_SVLAN_MCAST2S_ENTRY_BASE_REG(index) + i, &regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        *accessPtr = regData;
+        accessPtr ++;
+    }
+
+
+    _rtl8367c_svlanMc2sStSmi2User(pSvlanMc2sCfg, smiSvlanMC2S);
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicSvlanSP2CConf
+ * Description:
+ *      Set system 128 SP2C content
+ * Input:
+ *      index           - index of 128 SVLAN & Port to CVLAN configuration
+ *      pSvlanSp2cCfg   - SVLAN & Port to CVLAN configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_ENTRY_INDEX  - Invalid entry index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicSvlanSP2CConf(rtk_uint32 index, rtl8367c_svlan_s2c_t* pSvlanSp2cCfg)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+    rtk_uint16 *accessPtr;
+    rtk_uint32 i;
+    rtk_uint16 smiSvlanSP2C[RTL8367C_SVLAN_SP2C_LEN];
+
+    if(index > RTL8367C_SP2CMAX)
+        return RT_ERR_ENTRY_INDEX;
+
+    memset(smiSvlanSP2C, 0x00, sizeof(rtk_uint16) * RTL8367C_SVLAN_SP2C_LEN);
+    _rtl8367c_svlanSp2cStUser2Smi(pSvlanSp2cCfg,smiSvlanSP2C);
+
+    accessPtr = smiSvlanSP2C;
+
+    regData = *accessPtr;
+    for(i = 0; i < 2; i++)
+    {
+        retVal = rtl8367c_setAsicReg(RTL8367C_SVLAN_S2C_ENTRY_BASE_REG(index) + i, regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        accessPtr ++;
+        regData = *accessPtr;
+    }
+
+    return retVal;
+}
+/* Function Name:
+ *      rtl8367c_getAsicSvlanSP2CConf
+ * Description:
+ *      Get system 128 SP2C content
+ * Input:
+ *      index           - index of 128 SVLAN & Port to CVLAN configuration
+ *      pSvlanSp2cCfg   - SVLAN & Port to CVLAN configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_ENTRY_INDEX  - Invalid entry index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicSvlanSP2CConf(rtk_uint32 index,rtl8367c_svlan_s2c_t* pSvlanSp2cCfg)
+{
+    ret_t retVal;
+    rtk_uint32 regData;
+    rtk_uint16 *accessPtr;
+    rtk_uint32 i;
+    rtk_uint16 smiSvlanSP2C[RTL8367C_SVLAN_SP2C_LEN];
+
+    if(index > RTL8367C_SP2CMAX)
+        return RT_ERR_ENTRY_INDEX;
+
+    memset(smiSvlanSP2C, 0x00, sizeof(rtk_uint16) * RTL8367C_SVLAN_SP2C_LEN);
+
+    accessPtr = smiSvlanSP2C;
+
+    for(i = 0; i < 2; i++)
+    {
+        retVal = rtl8367c_getAsicReg(RTL8367C_SVLAN_S2C_ENTRY_BASE_REG(index) + i, &regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        *accessPtr = regData;
+
+        accessPtr ++;
+    }
+
+    _rtl8367c_svlanSp2cStSmi2User(pSvlanSp2cCfg, smiSvlanSP2C);
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicSvlanDmacCvidSel
+ * Description:
+ *      Set downstream CVID decision by DMAC
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      enabled     - 0:disabled, 1:enabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicSvlanDmacCvidSel(rtk_uint32 port, rtk_uint32 enabled)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(port < 8)
+        return rtl8367c_setAsicRegBit(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_PORT0_DMACVIDSEL_OFFSET + port, enabled);
+    else
+        return rtl8367c_setAsicRegBit(RTL8367C_REG_SVLAN_CFG_EXT, RTL8367C_VS_PORT8_DMACVIDSEL_OFFSET + (port-8), enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicSvlanDmacCvidSel
+ * Description:
+ *      Get downstream CVID decision by DMAC
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      pEnabled    - 0:disabled, 1:enabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicSvlanDmacCvidSel(rtk_uint32 port, rtk_uint32* pEnabled)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(port < 8)
+        return rtl8367c_getAsicRegBit(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_PORT0_DMACVIDSEL_OFFSET + port, pEnabled);
+    else
+        return rtl8367c_getAsicRegBit(RTL8367C_REG_SVLAN_CFG_EXT, RTL8367C_VS_PORT8_DMACVIDSEL_OFFSET + (port-8), pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicSvlanUntagVlan
+ * Description:
+ *      Set default ingress untag SVLAN
+ * Input:
+ *      index   - index SVLAN member configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_SVLAN_ENTRY_INDEX    - Invalid SVLAN index parameter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicSvlanUntagVlan(rtk_uint32 index)
+{
+    if(index > RTL8367C_SVIDXMAX)
+        return RT_ERR_SVLAN_ENTRY_INDEX;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_UNTAG_UNMAT_CFG, RTL8367C_VS_UNTAG_SVIDX_MASK, index);
+}
+/* Function Name:
+ *      rtl8367c_getAsicSvlanUntagVlan
+ * Description:
+ *      Get default ingress untag SVLAN
+ * Input:
+ *      pIndex  - index SVLAN member configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicSvlanUntagVlan(rtk_uint32* pIndex)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_UNTAG_UNMAT_CFG, RTL8367C_VS_UNTAG_SVIDX_MASK, pIndex);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicSvlanUnmatchVlan
+ * Description:
+ *      Set default ingress unmatch SVLAN
+ * Input:
+ *      index   - index SVLAN member configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_SVLAN_ENTRY_INDEX    - Invalid SVLAN index parameter
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicSvlanUnmatchVlan(rtk_uint32 index)
+{
+    if(index > RTL8367C_SVIDXMAX)
+        return RT_ERR_SVLAN_ENTRY_INDEX;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_UNTAG_UNMAT_CFG, RTL8367C_VS_UNMAT_SVIDX_MASK, index);
+}
+/* Function Name:
+ *      rtl8367c_getAsicSvlanUnmatchVlan
+ * Description:
+ *      Get default ingress unmatch SVLAN
+ * Input:
+ *      pIndex  - index SVLAN member configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicSvlanUnmatchVlan(rtk_uint32* pIndex)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_UNTAG_UNMAT_CFG, RTL8367C_VS_UNMAT_SVIDX_MASK, pIndex);
+}
+
+
+/* Function Name:
+ *      rtl8367c_setAsicSvlanLookupType
+ * Description:
+ *      Set svlan lookup table selection
+ * Input:
+ *      type    - lookup type
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicSvlanLookupType(rtk_uint32 type)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_SVLAN_LOOKUP_TYPE, RTL8367C_SVLAN_LOOKUP_TYPE_OFFSET, type);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicSvlanLookupType
+ * Description:
+ *      Get svlan lookup table selection
+ * Input:
+ *      pType   - lookup type
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicSvlanLookupType(rtk_uint32* pType)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_SVLAN_LOOKUP_TYPE, RTL8367C_SVLAN_LOOKUP_TYPE_OFFSET, pType);
+}
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_trunking.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_trunking.c
new file mode 100644
index 0000000..26d4c29
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_trunking.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Port trunking related functions
+ *
+ */
+
+#include <rtl8367c_asicdrv_trunking.h>
+/* Function Name:
+ *      rtl8367c_setAsicTrunkingMode
+ * Description:
+ *      Set port trunking mode
+ * Input:
+ *      mode    - 1:dumb 0:user defined
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicTrunkingMode(rtk_uint32 mode)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_PORT_TRUNK_CTRL, RTL8367C_PORT_TRUNK_DUMB_OFFSET, mode);
+}
+/* Function Name:
+ *      rtl8367c_getAsicTrunkingMode
+ * Description:
+ *      Get port trunking mode
+ * Input:
+ *      pMode   - 1:dumb 0:user defined
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicTrunkingMode(rtk_uint32* pMode)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_PORT_TRUNK_CTRL, RTL8367C_PORT_TRUNK_DUMB_OFFSET, pMode);
+}
+/* Function Name:
+ *      rtl8367c_setAsicTrunkingFc
+ * Description:
+ *      Set port trunking flow control
+ * Input:
+ *      group       - Trunk Group ID
+ *      enabled     - 0:disable, 1:enable
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicTrunkingFc(rtk_uint32 group, rtk_uint32 enabled)
+{
+    ret_t       retVal;
+
+    if(group > RTL8367C_MAX_TRUNK_GID)
+        return RT_ERR_LA_TRUNK_ID;
+
+    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_PORT_TRUNK_DROP_CTRL, RTL8367C_PORT_TRUNK_DROP_CTRL_OFFSET, ENABLED)) != RT_ERR_OK)
+        return retVal;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_PORT_TRUNK_FLOWCTRL, (RTL8367C_EN_FLOWCTRL_TG0_OFFSET + group), enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicTrunkingFc
+ * Description:
+ *      Get port trunking flow control
+ * Input:
+ *      group       - Trunk Group ID
+ *      pEnabled    - 0:disable, 1:enable
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicTrunkingFc(rtk_uint32 group, rtk_uint32* pEnabled)
+{
+    if(group > RTL8367C_MAX_TRUNK_GID)
+        return RT_ERR_LA_TRUNK_ID;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_PORT_TRUNK_FLOWCTRL, (RTL8367C_EN_FLOWCTRL_TG0_OFFSET + group), pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicTrunkingGroup
+ * Description:
+ *      Set trunking group available port mask
+ * Input:
+ *      group       - Trunk Group ID
+ *      portmask    - Logic trunking enable port mask, max 4 ports
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicTrunkingGroup(rtk_uint32 group, rtk_uint32 portmask)
+{
+    if(group > RTL8367C_MAX_TRUNK_GID)
+        return RT_ERR_LA_TRUNK_ID;
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_PORT_TRUNK_GROUP_MASK, RTL8367C_PORT_TRUNK_GROUP0_MASK_MASK << (group * 4), portmask);
+}
+/* Function Name:
+ *      rtl8367c_getAsicTrunkingGroup
+ * Description:
+ *      Get trunking group available port mask
+ * Input:
+ *      group       - Trunk Group ID
+ * Output:
+ *      pPortmask   - Logic trunking enable port mask, max 4 ports
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicTrunkingGroup(rtk_uint32 group, rtk_uint32* pPortmask)
+{
+    if(group > RTL8367C_MAX_TRUNK_GID)
+        return RT_ERR_LA_TRUNK_ID;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_TRUNK_GROUP_MASK, RTL8367C_PORT_TRUNK_GROUP0_MASK_MASK << (group * 4), pPortmask);
+}
+/* Function Name:
+ *      rtl8367c_setAsicTrunkingFlood
+ * Description:
+ *      Set port trunking flood function
+ * Input:
+ *      enabled     - Port trunking flooding function 0:disable 1:enable
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicTrunkingFlood(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_PORT_TRUNK_CTRL, RTL8367C_PORT_TRUNK_FLOOD_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicTrunkingFlood
+ * Description:
+ *      Get port trunking flood function
+ * Input:
+ *      pEnabled    - Port trunking flooding function 0:disable 1:enable
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicTrunkingFlood(rtk_uint32* pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_PORT_TRUNK_CTRL, RTL8367C_PORT_TRUNK_FLOOD_OFFSET, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicTrunkingHashSelect
+ * Description:
+ *      Set port trunking hash select sources
+ * Input:
+ *      hashsel     - hash sources mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      7 bits mask for link aggregation group0 hash parameter selection {DIP, SIP, DMAC, SMAC, SPA}
+ *      0b0000001: SPA
+ *      0b0000010: SMAC
+ *      0b0000100: DMAC
+ *      0b0001000: SIP
+ *      0b0010000: DIP
+ *      0b0100000: TCP/UDP Source Port
+ *      0b1000000: TCP/UDP Destination Port
+ */
+ret_t rtl8367c_setAsicTrunkingHashSelect(rtk_uint32 hashsel)
+{
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_PORT_TRUNK_CTRL, RTL8367C_PORT_TRUNK_HASH_MASK, hashsel);
+}
+/* Function Name:
+ *      rtl8367c_getAsicTrunkingHashSelect
+ * Description:
+ *      Get port trunking hash select sources
+ * Input:
+ *      pHashsel    - hash sources mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicTrunkingHashSelect(rtk_uint32* pHashsel)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_TRUNK_CTRL, RTL8367C_PORT_TRUNK_HASH_MASK, pHashsel);
+}
+/* Function Name:
+ *      rtl8367c_getAsicQeueuEmptyStatus
+ * Description:
+ *      Get current output queue if empty status
+ * Input:
+ *      portmask    - queue empty port mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicQeueuEmptyStatus(rtk_uint32* portmask)
+{
+    return rtl8367c_getAsicReg(RTL8367C_REG_PORT_QEMPTY, portmask);
+}
+/* Function Name:
+ *      rtl8367c_setAsicTrunkingHashTable
+ * Description:
+ *      Set port trunking hash value mapping table
+ * Input:
+ *      hashval     - hashing value 0-15
+ *      portId      - trunking port id 0-3
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_OUT_OF_RANGE - Invalid hashing value (0-15)
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicTrunkingHashTable(rtk_uint32 hashval, rtk_uint32 portId)
+{
+    if(hashval > RTL8367C_TRUNKING_HASHVALUE_MAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(portId >= RTL8367C_TRUNKING_PORTNO)
+        return RT_ERR_PORT_ID;
+
+    if(hashval >= 8)
+        return rtl8367c_setAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL1, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH8_MASK<<((hashval-8)*2), portId);
+    else
+        return rtl8367c_setAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL0, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH0_MASK<<(hashval*2), portId);
+}
+/* Function Name:
+ *      rtl8367c_getAsicTrunkingHashTable
+ * Description:
+ *      Get port trunking hash value mapping table
+ * Input:
+ *      hashval     - hashing value 0-15
+ *      pPortId         - trunking port id 0-3
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - Invalid hashing value (0-15)
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicTrunkingHashTable(rtk_uint32 hashval, rtk_uint32* pPortId)
+{
+    if(hashval > RTL8367C_TRUNKING_HASHVALUE_MAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(hashval >= 8)
+        return rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL1, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH8_MASK<<((hashval-8)*2), pPortId);
+    else
+        return rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL0, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH0_MASK<<(hashval*2), pPortId);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicTrunkingHashTable1
+ * Description:
+ *      Set port trunking hash value mapping table
+ * Input:
+ *      hashval     - hashing value 0-15
+ *      portId      - trunking port id 0-3
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_OUT_OF_RANGE - Invalid hashing value (0-15)
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicTrunkingHashTable1(rtk_uint32 hashval, rtk_uint32 portId)
+{
+    if(hashval > RTL8367C_TRUNKING_HASHVALUE_MAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(portId >= RTL8367C_TRUNKING1_PORTN0)
+        return RT_ERR_PORT_ID;
+
+    if(hashval >= 8)
+        return rtl8367c_setAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL3, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH8_MASK<<((hashval-8)*2), portId);
+    else
+        return rtl8367c_setAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL2, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH0_MASK<<(hashval*2), portId);
+}
+/* Function Name:
+ *      rtl8367c_getAsicTrunkingHashTable1
+ * Description:
+ *      Get port trunking hash value mapping table
+ * Input:
+ *      hashval     - hashing value 0-15
+ *      pPortId         - trunking port id 0-3
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_OUT_OF_RANGE - Invalid hashing value (0-15)
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicTrunkingHashTable1(rtk_uint32 hashval, rtk_uint32* pPortId)
+{
+    if(hashval > RTL8367C_TRUNKING_HASHVALUE_MAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(hashval >= 8)
+        return rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL3, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH8_MASK<<((hashval-8)*2), pPortId);
+    else
+        return rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL2, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH0_MASK<<(hashval*2), pPortId);
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_unknownMulticast.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_unknownMulticast.c
new file mode 100644
index 0000000..fcebd1b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_unknownMulticast.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : Unkown multicast related functions
+ *
+ */
+
+#include <rtl8367c_asicdrv_unknownMulticast.h>
+
+/* Function Name:
+ *      rtl8367c_setAsicUnknownL2MulticastBehavior
+ * Description:
+ *      Set behavior of L2 multicast
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      behave  - 0: flooding, 1: drop, 2: trap
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_NOT_ALLOWED  - Invalid operation
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicUnknownL2MulticastBehavior(rtk_uint32 port, rtk_uint32 behave)
+{
+    ret_t retVal;
+
+    if(port >  RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(behave >= L2_UNKOWN_MULTICAST_END)
+        return RT_ERR_NOT_ALLOWED;
+    if(port < 8)
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_UNKNOWN_L2_MULTICAST_REG(port), RTL8367C_UNKNOWN_L2_MULTICAST_MASK(port), behave);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_UNKNOWN_L2_MULTICAST_CTRL1, 3 << ((port - 8) << 1), behave);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicUnknownL2MulticastBehavior
+ * Description:
+ *      Get behavior of L2 multicast
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pBehave     - 0: flooding, 1: drop, 2: trap
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicUnknownL2MulticastBehavior(rtk_uint32 port, rtk_uint32 *pBehave)
+{
+    ret_t retVal;
+
+    if(port >  RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(port < 8)
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_UNKNOWN_L2_MULTICAST_REG(port), RTL8367C_UNKNOWN_L2_MULTICAST_MASK(port), pBehave);
+        if (retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_UNKNOWN_L2_MULTICAST_CTRL1, 3 << ((port - 8) << 1), pBehave);
+        if (retVal != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicUnknownIPv4MulticastBehavior
+ * Description:
+ *      Set behavior of IPv4 multicast
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      behave  - 0: flooding, 1: drop, 2: trap
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_NOT_ALLOWED  - Invalid operation
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicUnknownIPv4MulticastBehavior(rtk_uint32 port, rtk_uint32 behave)
+{
+    if(port >  RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(behave >= L3_UNKOWN_MULTICAST_END)
+        return RT_ERR_NOT_ALLOWED;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_UNKNOWN_IPV4_MULTICAST_REG(port), RTL8367C_UNKNOWN_IPV4_MULTICAST_MASK(port), behave);
+}
+/* Function Name:
+ *      rtl8367c_getAsicUnknownIPv4MulticastBehavior
+ * Description:
+ *      Get behavior of IPv4 multicast
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pBehave     - 0: flooding, 1: drop, 2: trap
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicUnknownIPv4MulticastBehavior(rtk_uint32 port, rtk_uint32 *pBehave)
+{
+    if(port >  RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_UNKNOWN_IPV4_MULTICAST_REG(port), RTL8367C_UNKNOWN_IPV4_MULTICAST_MASK(port), pBehave);
+}
+/* Function Name:
+ *      rtl8367c_setAsicUnknownIPv6MulticastBehavior
+ * Description:
+ *      Set behavior of IPv6 multicast
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      behave  - 0: flooding, 1: drop, 2: trap
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_NOT_ALLOWED  - Invalid operation
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicUnknownIPv6MulticastBehavior(rtk_uint32 port, rtk_uint32 behave)
+{
+    if(port >  RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(behave >= L3_UNKOWN_MULTICAST_END)
+        return RT_ERR_NOT_ALLOWED;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_UNKNOWN_IPV6_MULTICAST_REG(port), RTL8367C_UNKNOWN_IPV6_MULTICAST_MASK(port), behave);
+}
+/* Function Name:
+ *      rtl8367c_getAsicUnknownIPv6MulticastBehavior
+ * Description:
+ *      Get behavior of IPv6 multicast
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pBehave     - 0: flooding, 1: drop, 2: trap
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicUnknownIPv6MulticastBehavior(rtk_uint32 port, rtk_uint32 *pBehave)
+{
+    if(port >  RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_UNKNOWN_IPV6_MULTICAST_REG(port), RTL8367C_UNKNOWN_IPV6_MULTICAST_MASK(port), pBehave);
+}
+/* Function Name:
+ *      rtl8367c_setAsicUnknownMulticastTrapPriority
+ * Description:
+ *      Set trap priority of unknown multicast frame
+ * Input:
+ *      priority    - priority (0~7)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_QOS_INT_PRIORITY - Invalid priority
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicUnknownMulticastTrapPriority(rtk_uint32 priority)
+{
+    if(priority > RTL8367C_PRIMAX)
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_QOS_TRAP_PRIORITY_CTRL0_REG, RTL8367C_UNKNOWN_MC_PRIORTY_MASK, priority);
+}
+/* Function Name:
+ *      rtl8367c_getAsicUnknownMulticastTrapPriority
+ * Description:
+ *      Get trap priority of unknown multicast frame
+ * Input:
+ *      pPriority   - priority (0~7)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK   - Success
+ *      RT_ERR_SMI  - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicUnknownMulticastTrapPriority(rtk_uint32 *pPriority)
+{
+    return rtl8367c_getAsicRegBits(RTL8367C_QOS_TRAP_PRIORITY_CTRL0_REG, RTL8367C_UNKNOWN_MC_PRIORTY_MASK, pPriority);
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_vlan.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_vlan.c
new file mode 100644
index 0000000..1e283e7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_vlan.c
@@ -0,0 +1,1505 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTL8367C switch high-level API for RTL8367C
+ * Feature : VLAN related functions
+ *
+ */
+#include <rtl8367c_asicdrv_vlan.h>
+
+#include <string.h>
+
+#if defined(CONFIG_RTL8367C_ASICDRV_TEST)
+rtl8367c_user_vlan4kentry Rtl8370sVirtualVlanTable[RTL8367C_VIDMAX + 1];
+#endif
+
+static void _rtl8367c_VlanMCStUser2Smi(rtl8367c_vlanconfiguser *pVlanCg, rtk_uint16 *pSmiVlanCfg)
+{
+    pSmiVlanCfg[0] |= pVlanCg->mbr & 0x07FF;
+
+    pSmiVlanCfg[1] |= pVlanCg->fid_msti & 0x000F;
+
+    pSmiVlanCfg[2] |= pVlanCg->vbpen & 0x0001;
+    pSmiVlanCfg[2] |= (pVlanCg->vbpri & 0x0007) << 1;
+    pSmiVlanCfg[2] |= (pVlanCg->envlanpol & 0x0001) << 4;
+    pSmiVlanCfg[2] |= (pVlanCg->meteridx & 0x003F) << 5;
+
+    pSmiVlanCfg[3] |= pVlanCg->evid & 0x1FFF;
+}
+
+static void _rtl8367c_VlanMCStSmi2User(rtk_uint16 *pSmiVlanCfg, rtl8367c_vlanconfiguser *pVlanCg)
+{
+    pVlanCg->mbr            = pSmiVlanCfg[0] & 0x07FF;
+    pVlanCg->fid_msti       = pSmiVlanCfg[1] & 0x000F;
+    pVlanCg->meteridx       = (pSmiVlanCfg[2] >> 5) & 0x003F;
+    pVlanCg->envlanpol      = (pSmiVlanCfg[2] >> 4) & 0x0001;
+    pVlanCg->vbpri          = (pSmiVlanCfg[2] >> 1) & 0x0007;
+    pVlanCg->vbpen          = pSmiVlanCfg[2] & 0x0001;
+    pVlanCg->evid           = pSmiVlanCfg[3] & 0x1FFF;
+}
+
+static void _rtl8367c_Vlan4kStUser2Smi(rtl8367c_user_vlan4kentry *pUserVlan4kEntry, rtk_uint16 *pSmiVlan4kEntry)
+{
+    pSmiVlan4kEntry[0] |= (pUserVlan4kEntry->mbr & 0x00FF);
+    pSmiVlan4kEntry[0] |= (pUserVlan4kEntry->untag & 0x00FF) << 8;
+
+    pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->fid_msti & 0x000F);
+    pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->vbpen & 0x0001) << 4;
+    pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->vbpri & 0x0007) << 5;
+    pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->envlanpol & 0x0001) << 8;
+    pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->meteridx & 0x001F) << 9;
+    pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->ivl_svl & 0x0001) << 14;
+
+    pSmiVlan4kEntry[2] |= ((pUserVlan4kEntry->mbr & 0x0700) >> 8);
+    pSmiVlan4kEntry[2] |= ((pUserVlan4kEntry->untag & 0x0700) >> 8) << 3;
+    pSmiVlan4kEntry[2] |= ((pUserVlan4kEntry->meteridx & 0x0020) >> 5) << 6;
+}
+
+
+static void _rtl8367c_Vlan4kStSmi2User(rtk_uint16 *pSmiVlan4kEntry, rtl8367c_user_vlan4kentry *pUserVlan4kEntry)
+{
+    pUserVlan4kEntry->mbr = (pSmiVlan4kEntry[0] & 0x00FF) | ((pSmiVlan4kEntry[2] & 0x0007) << 8);
+    pUserVlan4kEntry->untag = ((pSmiVlan4kEntry[0] & 0xFF00) >> 8) | (((pSmiVlan4kEntry[2] & 0x0038) >> 3) << 8);
+    pUserVlan4kEntry->fid_msti = pSmiVlan4kEntry[1] & 0x000F;
+    pUserVlan4kEntry->vbpen = (pSmiVlan4kEntry[1] & 0x0010) >> 4;
+    pUserVlan4kEntry->vbpri = (pSmiVlan4kEntry[1] & 0x00E0) >> 5;
+    pUserVlan4kEntry->envlanpol = (pSmiVlan4kEntry[1] & 0x0100) >> 8;
+    pUserVlan4kEntry->meteridx = ((pSmiVlan4kEntry[1] & 0x3E00) >> 9) | (((pSmiVlan4kEntry[2] & 0x0040) >> 6) << 5);
+    pUserVlan4kEntry->ivl_svl = (pSmiVlan4kEntry[1] & 0x4000) >> 14;
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicVlanMemberConfig
+ * Description:
+ *      Set 32 VLAN member configurations
+ * Input:
+ *      index       - VLAN member configuration index (0~31)
+ *      pVlanCg - VLAN member configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_INPUT                - Invalid input parameter
+ *      RT_ERR_L2_FID               - Invalid FID
+ *      RT_ERR_PORT_MASK            - Invalid portmask
+ *      RT_ERR_FILTER_METER_ID      - Invalid meter
+ *      RT_ERR_QOS_INT_PRIORITY     - Invalid priority
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND - Invalid VLAN member configuration index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicVlanMemberConfig(rtk_uint32 index, rtl8367c_vlanconfiguser *pVlanCg)
+{
+    ret_t  retVal;
+    rtk_uint32 regAddr;
+    rtk_uint32 regData;
+    rtk_uint16 *tableAddr;
+    rtk_uint32 page_idx;
+    rtk_uint16 smi_vlancfg[RTL8367C_VLAN_MBRCFG_LEN];
+
+    /* Error Checking  */
+    if(index > RTL8367C_CVIDXMAX)
+        return RT_ERR_VLAN_ENTRY_NOT_FOUND;
+
+    if(pVlanCg->evid > RTL8367C_EVIDMAX)
+        return RT_ERR_INPUT;
+
+
+    if(pVlanCg->mbr > RTL8367C_PORTMASK)
+        return RT_ERR_PORT_MASK;
+
+    if(pVlanCg->fid_msti > RTL8367C_FIDMAX)
+        return RT_ERR_L2_FID;
+
+    if(pVlanCg->meteridx > RTL8367C_METERMAX)
+        return RT_ERR_FILTER_METER_ID;
+
+    if(pVlanCg->vbpri > RTL8367C_PRIMAX)
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    memset(smi_vlancfg, 0x00, sizeof(rtk_uint16) * RTL8367C_VLAN_MBRCFG_LEN);
+    _rtl8367c_VlanMCStUser2Smi(pVlanCg, smi_vlancfg);
+    tableAddr = smi_vlancfg;
+
+    for(page_idx = 0; page_idx < 4; page_idx++)  /* 4 pages per VLAN Member Config */
+    {
+        regAddr = RTL8367C_VLAN_MEMBER_CONFIGURATION_BASE + (index * 4) + page_idx;
+        regData = *tableAddr;
+
+        retVal = rtl8367c_setAsicReg(regAddr, regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        tableAddr++;
+    }
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicVlanMemberConfig
+ * Description:
+ *      Get 32 VLAN member configurations
+ * Input:
+ *      index       - VLAN member configuration index (0~31)
+ *      pVlanCg - VLAN member configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_INPUT                - Invalid input parameter
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND - Invalid VLAN member configuration index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicVlanMemberConfig(rtk_uint32 index, rtl8367c_vlanconfiguser *pVlanCg)
+{
+    ret_t  retVal;
+    rtk_uint32 page_idx;
+    rtk_uint32 regAddr;
+    rtk_uint32 regData;
+    rtk_uint16 *tableAddr;
+    rtk_uint16 smi_vlancfg[RTL8367C_VLAN_MBRCFG_LEN];
+
+    if(index > RTL8367C_CVIDXMAX)
+        return RT_ERR_VLAN_ENTRY_NOT_FOUND;
+
+    memset(smi_vlancfg, 0x00, sizeof(rtk_uint16) * RTL8367C_VLAN_MBRCFG_LEN);
+    tableAddr  = smi_vlancfg;
+
+    for(page_idx = 0; page_idx < 4; page_idx++)  /* 4 pages per VLAN Member Config */
+    {
+        regAddr = RTL8367C_VLAN_MEMBER_CONFIGURATION_BASE + (index * 4) + page_idx;
+
+        retVal = rtl8367c_getAsicReg(regAddr, &regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        *tableAddr = (rtk_uint16)regData;
+        tableAddr++;
+    }
+
+    _rtl8367c_VlanMCStSmi2User(smi_vlancfg, pVlanCg);
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicVlan4kEntry
+ * Description:
+ *      Set VID mapped entry to 4K VLAN table
+ * Input:
+ *      pVlan4kEntry - 4K VLAN configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_INPUT                - Invalid input parameter
+ *      RT_ERR_L2_FID               - Invalid FID
+ *      RT_ERR_VLAN_VID             - Invalid VID parameter (0~4095)
+ *      RT_ERR_PORT_MASK            - Invalid portmask
+ *      RT_ERR_FILTER_METER_ID      - Invalid meter
+ *      RT_ERR_QOS_INT_PRIORITY     - Invalid priority
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicVlan4kEntry(rtl8367c_user_vlan4kentry *pVlan4kEntry )
+{
+    rtk_uint16              vlan_4k_entry[RTL8367C_VLAN_4KTABLE_LEN];
+    rtk_uint32                  page_idx;
+    rtk_uint16                  *tableAddr;
+    ret_t                   retVal;
+    rtk_uint32                  regData;
+
+    if(pVlan4kEntry->vid > RTL8367C_VIDMAX)
+        return RT_ERR_VLAN_VID;
+
+    if(pVlan4kEntry->mbr > RTL8367C_PORTMASK)
+        return RT_ERR_PORT_MASK;
+
+    if(pVlan4kEntry->untag > RTL8367C_PORTMASK)
+        return RT_ERR_PORT_MASK;
+
+    if(pVlan4kEntry->fid_msti > RTL8367C_FIDMAX)
+        return RT_ERR_L2_FID;
+
+    if(pVlan4kEntry->meteridx > RTL8367C_METERMAX)
+        return RT_ERR_FILTER_METER_ID;
+
+    if(pVlan4kEntry->vbpri > RTL8367C_PRIMAX)
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    memset(vlan_4k_entry, 0x00, sizeof(rtk_uint16) * RTL8367C_VLAN_4KTABLE_LEN);
+    _rtl8367c_Vlan4kStUser2Smi(pVlan4kEntry, vlan_4k_entry);
+
+    /* Prepare Data */
+    tableAddr = vlan_4k_entry;
+    for(page_idx = 0; page_idx < RTL8367C_VLAN_4KTABLE_LEN; page_idx++)
+    {
+        regData = *tableAddr;
+        retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_WRDATA_BASE + page_idx, regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        tableAddr++;
+    }
+
+    /* Write Address (VLAN_ID) */
+    regData = pVlan4kEntry->vid;
+    retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_ADDR_REG, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /* Write Command */
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_TABLE_ACCESS_CTRL_REG, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK,RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_WRITE,TB_TARGET_CVLAN));
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+#if defined(CONFIG_RTL8367C_ASICDRV_TEST)
+    memcpy(&Rtl8370sVirtualVlanTable[pVlan4kEntry->vid], pVlan4kEntry, sizeof(rtl8367c_user_vlan4kentry));
+#endif
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicVlan4kEntry
+ * Description:
+ *      Get VID mapped entry to 4K VLAN table
+ * Input:
+ *      pVlan4kEntry - 4K VLAN configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - Success
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_VLAN_VID         - Invalid VID parameter (0~4095)
+ *      RT_ERR_BUSYWAIT_TIMEOUT - LUT is busy at retrieving
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicVlan4kEntry(rtl8367c_user_vlan4kentry *pVlan4kEntry )
+{
+    rtk_uint16                  vlan_4k_entry[RTL8367C_VLAN_4KTABLE_LEN];
+    rtk_uint32                  page_idx;
+    rtk_uint16                  *tableAddr;
+    ret_t                       retVal;
+    rtk_uint32                  regData;
+    rtk_uint32                  busyCounter;
+
+    if(pVlan4kEntry->vid > RTL8367C_VIDMAX)
+        return RT_ERR_VLAN_VID;
+
+    /* Polling status */
+    busyCounter = RTL8367C_VLAN_BUSY_CHECK_NO;
+    while(busyCounter)
+    {
+        retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET,&regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        if(regData == 0)
+            break;
+
+        busyCounter --;
+        if(busyCounter == 0)
+            return RT_ERR_BUSYWAIT_TIMEOUT;
+    }
+
+    /* Write Address (VLAN_ID) */
+    regData = pVlan4kEntry->vid;
+    retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_ADDR_REG, regData);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /* Read Command */
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_TABLE_ACCESS_CTRL_REG, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_READ,TB_TARGET_CVLAN));
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /* Polling status */
+    busyCounter = RTL8367C_VLAN_BUSY_CHECK_NO;
+    while(busyCounter)
+    {
+        retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET,&regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        if(regData == 0)
+            break;
+
+        busyCounter --;
+        if(busyCounter == 0)
+            return RT_ERR_BUSYWAIT_TIMEOUT;
+    }
+
+    /* Read VLAN data from register */
+    tableAddr = vlan_4k_entry;
+    for(page_idx = 0; page_idx < RTL8367C_VLAN_4KTABLE_LEN; page_idx++)
+    {
+        retVal = rtl8367c_getAsicReg(RTL8367C_TABLE_ACCESS_RDDATA_BASE + page_idx, &regData);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+
+        *tableAddr = regData;
+        tableAddr++;
+    }
+
+    _rtl8367c_Vlan4kStSmi2User(vlan_4k_entry, pVlan4kEntry);
+
+#if defined(CONFIG_RTL8367C_ASICDRV_TEST)
+    memcpy(pVlan4kEntry, &Rtl8370sVirtualVlanTable[pVlan4kEntry->vid], sizeof(rtl8367c_user_vlan4kentry));
+#endif
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicVlanAccpetFrameType
+ * Description:
+ *      Set per-port acceptable frame type
+ * Input:
+ *      port        - Physical port number (0~10)
+ *      frameType   - The acceptable frame type
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                       - Success
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_PORT_ID                  - Invalid port number
+ *      RT_ERR_VLAN_ACCEPT_FRAME_TYPE   - Invalid frame type
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicVlanAccpetFrameType(rtk_uint32 port, rtl8367c_accframetype frameType)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(frameType >= FRAME_TYPE_MAX_BOUND)
+        return RT_ERR_VLAN_ACCEPT_FRAME_TYPE;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_VLAN_ACCEPT_FRAME_TYPE_REG(port), RTL8367C_VLAN_ACCEPT_FRAME_TYPE_MASK(port), frameType);
+}
+/* Function Name:
+ *      rtl8367c_getAsicVlanAccpetFrameType
+ * Description:
+ *      Get per-port acceptable frame type
+ * Input:
+ *      port        - Physical port number (0~10)
+ *      pFrameType  - The acceptable frame type
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                       - Success
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_PORT_ID                  - Invalid port number
+ *      RT_ERR_VLAN_ACCEPT_FRAME_TYPE   - Invalid frame type
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicVlanAccpetFrameType(rtk_uint32 port, rtl8367c_accframetype *pFrameType)
+{
+    rtk_uint32 regData;
+    ret_t  retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if((retVal = rtl8367c_getAsicRegBits(RTL8367C_VLAN_ACCEPT_FRAME_TYPE_REG(port), RTL8367C_VLAN_ACCEPT_FRAME_TYPE_MASK(port), &regData)) != RT_ERR_OK)
+        return retVal;
+
+    *pFrameType = (rtl8367c_accframetype)regData;
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicVlanIngressFilter
+ * Description:
+ *      Set VLAN Ingress Filter
+ * Input:
+ *      port        - Physical port number (0~10)
+ *      enabled     - Enable or disable Ingress filter
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicVlanIngressFilter(rtk_uint32 port, rtk_uint32 enabled)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_VLAN_INGRESS_REG, port, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicVlanIngressFilter
+ * Description:
+ *      Get VLAN Ingress Filter
+ * Input:
+ *      port        - Physical port number (0~10)
+ *      pEnable     - Enable or disable Ingress filter
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicVlanIngressFilter(rtk_uint32 port, rtk_uint32 *pEnable)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_VLAN_INGRESS_REG, port, pEnable);
+}
+/* Function Name:
+ *      rtl8367c_setAsicVlanEgressTagMode
+ * Description:
+ *      Set CVLAN egress tag mode
+ * Input:
+ *      port        - Physical port number (0~10)
+ *      tagMode     - The egress tag mode. Including Original mode, Keep tag mode and Priority tag mode
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_INPUT    - Invalid input parameter
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicVlanEgressTagMode(rtk_uint32 port, rtl8367c_egtagmode tagMode)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(tagMode >= EG_TAG_MODE_END)
+        return RT_ERR_INPUT;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_PORT_MISC_CFG_REG(port), RTL8367C_VLAN_EGRESS_MDOE_MASK, tagMode);
+}
+/* Function Name:
+ *      rtl8367c_getAsicVlanEgressTagMode
+ * Description:
+ *      Get CVLAN egress tag mode
+ * Input:
+ *      port        - Physical port number (0~10)
+ *      pTagMode    - The egress tag mode. Including Original mode, Keep tag mode and Priority tag mode
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicVlanEgressTagMode(rtk_uint32 port, rtl8367c_egtagmode *pTagMode)
+{
+    rtk_uint32 regData;
+    ret_t  retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if((retVal = rtl8367c_getAsicRegBits(RTL8367C_PORT_MISC_CFG_REG(port), RTL8367C_VLAN_EGRESS_MDOE_MASK, &regData)) != RT_ERR_OK)
+        return retVal;
+
+    *pTagMode = (rtl8367c_egtagmode)regData;
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicVlanPortBasedVID
+ * Description:
+ *      Set port based VID which is indexed to 32 VLAN member configurations
+ * Input:
+ *      port    - Physical port number (0~10)
+ *      index   - Index to VLAN member configuration
+ *      pri     - 1Q Port based VLAN priority
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number
+ *      RT_ERR_QOS_INT_PRIORITY     - Invalid priority
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND - Invalid VLAN member configuration index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicVlanPortBasedVID(rtk_uint32 port, rtk_uint32 index, rtk_uint32 pri)
+{
+    rtk_uint32 regAddr, bit_mask;
+    ret_t  retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(index > RTL8367C_CVIDXMAX)
+        return RT_ERR_VLAN_ENTRY_NOT_FOUND;
+
+    if(pri > RTL8367C_PRIMAX)
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    regAddr = RTL8367C_VLAN_PVID_CTRL_REG(port);
+    bit_mask = RTL8367C_PORT_VIDX_MASK(port);
+    retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, index);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    regAddr = RTL8367C_VLAN_PORTBASED_PRIORITY_REG(port);
+    bit_mask = RTL8367C_VLAN_PORTBASED_PRIORITY_MASK(port);
+    retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, pri);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicVlanPortBasedVID
+ * Description:
+ *      Get port based VID which is indexed to 32 VLAN member configurations
+ * Input:
+ *      port    - Physical port number (0~10)
+ *      pIndex  - Index to VLAN member configuration
+ *      pPri    - 1Q Port based VLAN priority
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicVlanPortBasedVID(rtk_uint32 port, rtk_uint32 *pIndex, rtk_uint32 *pPri)
+{
+    rtk_uint32 regAddr,bit_mask;
+    ret_t  retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    regAddr = RTL8367C_VLAN_PVID_CTRL_REG(port);
+    bit_mask = RTL8367C_PORT_VIDX_MASK(port);
+    retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, pIndex);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    regAddr = RTL8367C_VLAN_PORTBASED_PRIORITY_REG(port);
+    bit_mask = RTL8367C_VLAN_PORTBASED_PRIORITY_MASK(port);
+    retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, pPri);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicVlanProtocolBasedGroupData
+ * Description:
+ *      Set protocol and port based group database
+ * Input:
+ *      index       - Index to VLAN member configuration
+ *      pPbCfg  - Protocol and port based group database entry
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_INPUT                - Invalid input parameter
+ *      RT_ERR_VLAN_PROTO_AND_PORT  - Invalid protocol base group database index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicVlanProtocolBasedGroupData(rtk_uint32 index, rtl8367c_protocolgdatacfg *pPbCfg)
+{
+    rtk_uint32  frameType;
+    rtk_uint32  etherType;
+    ret_t   retVal;
+
+    /* Error Checking */
+    if(index > RTL8367C_PROTOVLAN_GIDX_MAX)
+        return RT_ERR_VLAN_PROTO_AND_PORT;
+
+    if(pPbCfg->frameType >= PPVLAN_FRAME_TYPE_END )
+        return RT_ERR_INPUT;
+
+    frameType = pPbCfg->frameType;
+    etherType = pPbCfg->etherType;
+
+    /* Frame type */
+    retVal = rtl8367c_setAsicRegBits(RTL8367C_VLAN_PPB_FRAMETYPE_REG(index), RTL8367C_VLAN_PPB_FRAMETYPE_MASK, frameType);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /* Ether type */
+    retVal = rtl8367c_setAsicReg(RTL8367C_VLAN_PPB_ETHERTYPR_REG(index), etherType);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicVlanProtocolBasedGroupData
+ * Description:
+ *      Get protocol and port based group database
+ * Input:
+ *      index       - Index to VLAN member configuration
+ *      pPbCfg  - Protocol and port based group database entry
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_INPUT                - Invalid input parameter
+ *      RT_ERR_VLAN_PROTO_AND_PORT  - Invalid protocol base group database index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicVlanProtocolBasedGroupData(rtk_uint32 index, rtl8367c_protocolgdatacfg *pPbCfg)
+{
+    rtk_uint32  frameType;
+    rtk_uint32  etherType;
+    ret_t   retVal;
+
+    /* Error Checking */
+    if(index > RTL8367C_PROTOVLAN_GIDX_MAX)
+        return RT_ERR_VLAN_PROTO_AND_PORT;
+
+    /* Read Frame type */
+    retVal = rtl8367c_getAsicRegBits(RTL8367C_VLAN_PPB_FRAMETYPE_REG(index), RTL8367C_VLAN_PPB_FRAMETYPE_MASK, &frameType);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /* Read Ether type */
+    retVal = rtl8367c_getAsicReg(RTL8367C_VLAN_PPB_ETHERTYPR_REG(index), &etherType);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+
+    pPbCfg->frameType = frameType;
+    pPbCfg->etherType = etherType;
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicVlanPortAndProtocolBased
+ * Description:
+ *      Set protocol and port based VLAN configuration
+ * Input:
+ *      port        - Physical port number (0~10)
+ *      index       - Index of protocol and port based database index
+ *      pPpbCfg     - Protocol and port based VLAN configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_INPUT                - Invalid input parameter
+ *      RT_ERR_PORT_ID              - Invalid port number
+ *      RT_ERR_QOS_INT_PRIORITY     - Invalid priority
+ *      RT_ERR_VLAN_PROTO_AND_PORT  - Invalid protocol base group database index
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND - Invalid VLAN member configuration index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicVlanPortAndProtocolBased(rtk_uint32 port, rtk_uint32 index, rtl8367c_protocolvlancfg *pPpbCfg)
+{
+    rtk_uint32  reg_addr, bit_mask, bit_value;
+    ret_t   retVal;
+
+    /* Error Checking */
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(index > RTL8367C_PROTOVLAN_GIDX_MAX)
+        return RT_ERR_VLAN_PROTO_AND_PORT;
+
+    if( (pPpbCfg->valid != FALSE) && (pPpbCfg->valid != TRUE) )
+        return RT_ERR_INPUT;
+
+    if(pPpbCfg->vlan_idx > RTL8367C_CVIDXMAX)
+        return RT_ERR_VLAN_ENTRY_NOT_FOUND;
+
+    if(pPpbCfg->priority > RTL8367C_PRIMAX)
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    /* Valid bit */
+    reg_addr  = RTL8367C_VLAN_PPB_VALID_REG(index);
+    bit_mask  = 0x0001 << port;
+    bit_value = ((TRUE == pPpbCfg->valid) ? 0x1 : 0x0);
+    retVal    = rtl8367c_setAsicRegBits(reg_addr, bit_mask, bit_value);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /* Calculate the actual register address for CVLAN index*/
+    if(port < 8)
+    {
+        reg_addr = RTL8367C_VLAN_PPB_CTRL_REG(index, port);
+        bit_mask = RTL8367C_VLAN_PPB_CTRL_MASK(port);
+    }
+    else if(port == 8)
+    {
+        reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4;
+        bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT8_INDEX_MASK;
+    }
+    else if(port == 9)
+    {
+        reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4;
+        bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT9_INDEX_MASK;
+    }
+    else if(port == 10)
+    {
+        reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4;
+        bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT10_INDEX_MASK;
+    }
+
+    bit_value = pPpbCfg->vlan_idx;
+    retVal  = rtl8367c_setAsicRegBits(reg_addr, bit_mask, bit_value);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    /* write priority */
+    reg_addr  = RTL8367C_VLAN_PPB_PRIORITY_ITEM_REG(port, index);
+    bit_mask  = RTL8367C_VLAN_PPB_PRIORITY_ITEM_MASK(port);
+    bit_value = pPpbCfg->priority;
+    retVal    = rtl8367c_setAsicRegBits(reg_addr, bit_mask, bit_value);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_getAsicVlanPortAndProtocolBased
+ * Description:
+ *      Get protocol and port based VLAN configuration
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      index       - Index of protocol and port based database index
+ *      pPpbCfg     - Protocol and port based VLAN configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - Success
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_INPUT                - Invalid input parameter
+ *      RT_ERR_PORT_ID              - Invalid port number
+ *      RT_ERR_VLAN_PROTO_AND_PORT  - Invalid protocol base group database index
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicVlanPortAndProtocolBased(rtk_uint32 port, rtk_uint32 index, rtl8367c_protocolvlancfg *pPpbCfg)
+{
+    rtk_uint32  reg_addr, bit_mask, bit_value;
+    ret_t   retVal;
+
+    /* Error Checking */
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(index > RTL8367C_PROTOVLAN_GIDX_MAX)
+        return RT_ERR_VLAN_PROTO_AND_PORT;
+
+    if(pPpbCfg == NULL)
+        return RT_ERR_INPUT;
+
+    /* Valid bit */
+    reg_addr  = RTL8367C_VLAN_PPB_VALID_REG(index);
+    bit_mask  = 0x0001 << port;
+    retVal    = rtl8367c_getAsicRegBits(reg_addr, bit_mask, &bit_value);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    pPpbCfg->valid = bit_value;
+
+    /* CVLAN index */
+    if(port < 8)
+    {
+        reg_addr = RTL8367C_VLAN_PPB_CTRL_REG(index, port);
+        bit_mask = RTL8367C_VLAN_PPB_CTRL_MASK(port);
+    }
+    else if(port == 8)
+    {
+        reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4;
+        bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT8_INDEX_MASK;
+    }
+    else if(port == 9)
+    {
+        reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4;
+        bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT9_INDEX_MASK;
+    }
+    else if(port == 10)
+    {
+        reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4;
+        bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT10_INDEX_MASK;
+    }
+
+    retVal = rtl8367c_getAsicRegBits(reg_addr, bit_mask, &bit_value);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    pPpbCfg->vlan_idx = bit_value;
+
+
+    /* priority */
+    reg_addr = RTL8367C_VLAN_PPB_PRIORITY_ITEM_REG(port,index);
+    bit_mask = RTL8367C_VLAN_PPB_PRIORITY_ITEM_MASK(port);
+    retVal = rtl8367c_getAsicRegBits(reg_addr, bit_mask, &bit_value);
+    if(retVal != RT_ERR_OK)
+        return retVal;
+
+    pPpbCfg->priority = bit_value;
+    return RT_ERR_OK;
+}
+/* Function Name:
+ *      rtl8367c_setAsicVlanFilter
+ * Description:
+ *      Set enable CVLAN filtering function
+ * Input:
+ *      enabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicVlanFilter(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_VLAN_CTRL, RTL8367C_VLAN_CTRL_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicVlanFilter
+ * Description:
+ *      Get enable CVLAN filtering function
+ * Input:
+ *      pEnabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicVlanFilter(rtk_uint32* pEnabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_VLAN_CTRL, RTL8367C_VLAN_CTRL_OFFSET, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicVlanUntagDscpPriorityEn
+ * Description:
+ *      Set enable Dscp to untag 1Q priority
+ * Input:
+ *      enabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicVlanUntagDscpPriorityEn(rtk_uint32 enabled)
+{
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_UNTAG_DSCP_PRI_CFG, RTL8367C_UNTAG_DSCP_PRI_CFG_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicVlanUntagDscpPriorityEn
+ * Description:
+ *      Get enable Dscp to untag 1Q priority
+ * Input:
+ *      enabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicVlanUntagDscpPriorityEn(rtk_uint32* enabled)
+{
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_UNTAG_DSCP_PRI_CFG, RTL8367C_UNTAG_DSCP_PRI_CFG_OFFSET, enabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicPortBasedFid
+ * Description:
+ *      Set port based FID
+ * Input:
+ *      port    - Physical port number (0~10)
+ *      fid     - Port based fid
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_L2_FID   - Invalid FID
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortBasedFid(rtk_uint32 port, rtk_uint32 fid)
+{
+    rtk_uint32  reg_addr;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(fid > RTL8367C_FIDMAX)
+        return RT_ERR_L2_FID;
+
+    if(port < 8)
+        return rtl8367c_setAsicReg(RTL8367C_PORT_PBFID_REG(port),fid);
+    else {
+        reg_addr = RTL8367C_REG_PORT8_PBFID + port-8;
+        return rtl8367c_setAsicReg(reg_addr, fid);
+    }
+
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortBasedFid
+ * Description:
+ *      Get port based FID
+ * Input:
+ *      port    - Physical port number (0~7)
+ *      pFid    - Port based fid
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortBasedFid(rtk_uint32 port, rtk_uint32* pFid)
+{
+    rtk_uint32  reg_addr;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(port < 8)
+        return rtl8367c_getAsicReg(RTL8367C_PORT_PBFID_REG(port), pFid);
+    else{
+        reg_addr = RTL8367C_REG_PORT8_PBFID + port-8;
+        return rtl8367c_getAsicReg(reg_addr, pFid);
+    }
+}
+/* Function Name:
+ *      rtl8367c_setAsicPortBasedFidEn
+ * Description:
+ *      Set port based FID selection enable
+ * Input:
+ *      port    - Physical port number (0~10)
+ *      enabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicPortBasedFidEn(rtk_uint32 port, rtk_uint32 enabled)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_setAsicRegBit(RTL8367C_REG_PORT_PBFIDEN,port, enabled);
+}
+/* Function Name:
+ *      rtl8367c_getAsicPortBasedFidEn
+ * Description:
+ *      Get port based FID selection enable
+ * Input:
+ *      port    - Physical port number (0~10)
+ *      pEnabled - 1: enabled, 0: disabled
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicPortBasedFidEn(rtk_uint32 port, rtk_uint32* pEnabled)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBit(RTL8367C_REG_PORT_PBFIDEN,port, pEnabled);
+}
+/* Function Name:
+ *      rtl8367c_setAsicSpanningTreeStatus
+ * Description:
+ *      Set spanning tree state per each port
+ * Input:
+ *      port    - Physical port number (0~10)
+ *      msti    - Multiple spanning tree instance
+ *      state   - Spanning tree state for msti
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_MSTI         - Invalid msti parameter
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_MSTP_STATE   - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicSpanningTreeStatus(rtk_uint32 port, rtk_uint32 msti, rtk_uint32 state)
+{
+    rtk_uint32  reg_addr,bits_msk;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(msti > RTL8367C_MSTIMAX)
+        return RT_ERR_MSTI;
+
+    if(state > STPST_FORWARDING)
+        return RT_ERR_MSTP_STATE;
+
+    if(port < 8)
+        return rtl8367c_setAsicRegBits(RTL8367C_VLAN_MSTI_REG(msti,port), RTL8367C_VLAN_MSTI_MASK(port),state);
+    else{
+        reg_addr = RTL8367C_VLAN_MSTI_REG(msti,port);
+        switch(port){
+            case 8: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT8_STATE_MASK;break;
+            case 9: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT9_STATE_MASK;break;
+            case 10: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT10_STATE_MASK;break;
+        }
+        return rtl8367c_setAsicRegBits(reg_addr, bits_msk,state);
+    }
+}
+/* Function Name:
+ *      rtl8367c_getAsicSpanningTreeStatus
+ * Description:
+ *      Set spanning tree state per each port
+ * Input:
+ *      port    - Physical port number (0~10)
+ *      msti    - Multiple spanning tree instance
+ *      pState  - Spanning tree state for msti
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_MSTI         - Invalid msti parameter
+ *      RT_ERR_PORT_ID      - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicSpanningTreeStatus(rtk_uint32 port, rtk_uint32 msti, rtk_uint32* pState)
+{
+    rtk_uint32  reg_addr,bits_msk;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(msti > RTL8367C_MSTIMAX)
+        return RT_ERR_MSTI;
+
+    if(port < 8)
+        return rtl8367c_getAsicRegBits(RTL8367C_VLAN_MSTI_REG(msti,port), RTL8367C_VLAN_MSTI_MASK(port), pState);
+    else{
+        reg_addr = RTL8367C_VLAN_MSTI_REG(msti,port);
+        switch(port){
+            case 8: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT8_STATE_MASK;break;
+            case 9: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT9_STATE_MASK;break;
+            case 10: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT10_STATE_MASK;break;
+        }
+        return rtl8367c_getAsicRegBits(reg_addr, bits_msk, pState);
+    }
+
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicVlanTransparent
+ * Description:
+ *      Set VLAN transparent
+ * Input:
+ *      port        - Physical port number (0~10)
+ *      portmask    - portmask(0~0xFF)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK    - Invalid portmask
+ *      RT_ERR_PORT_ID      - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicVlanTransparent(rtk_uint32 port, rtk_uint32 portmask)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(portmask > RTL8367C_PORTMASK)
+        return RT_ERR_PORT_MASK;
+
+    return rtl8367c_setAsicRegBits(RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL0 + port, RTL8367C_VLAN_EGRESS_TRANS_CTRL0_MASK, portmask);
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicVlanTransparent
+ * Description:
+ *      Get VLAN transparent
+ * Input:
+ *      port        - Physical port number (0~10)
+ * Output:
+ *      pPortmask   - Ingress port mask
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK    - Invalid portmask
+ *      RT_ERR_PORT_ID      - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicVlanTransparent(rtk_uint32 port, rtk_uint32 *pPortmask)
+{
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    return rtl8367c_getAsicRegBits(RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL0 + port, RTL8367C_VLAN_EGRESS_TRANS_CTRL0_MASK, pPortmask);
+}
+
+/* Function Name:
+ *      rtl8367c_setAsicVlanEgressKeep
+ * Description:
+ *      Set per egress port VLAN keep mode
+ * Input:
+ *      port        - Physical port number (0~10)
+ *      portmask    - portmask(0~0xFF)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_MASK    - Invalid portmask
+ *      RT_ERR_PORT_ID      - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setAsicVlanEgressKeep(rtk_uint32 port, rtk_uint32 portmask)
+{
+    rtk_uint32 regAddr, bit_mask;
+    ret_t  retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(portmask > RTL8367C_PORTMASK)
+        return RT_ERR_PORT_MASK;
+
+    if(port < 8){
+        retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0 + (port>>1),RTL8367C_PORT0_VLAN_KEEP_MASK_MASK<<((port&1)*8),portmask & 0xff);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+        regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0_EXT + (port>>1);
+        bit_mask = RTL8367C_PORT0_VLAN_KEEP_MASK_EXT_MASK;
+        bit_mask <<= (port&1)*3;
+        retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, (portmask>>8)&0x7);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+    }
+    else{
+        switch(port){
+            case 8:
+                regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4;
+                bit_mask = RTL8367C_PORT8_VLAN_KEEP_MASK_MASK;
+                retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, portmask & 0xff);
+                if(retVal != RT_ERR_OK)
+                    return retVal;
+                regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4_EXT;
+                bit_mask = RTL8367C_PORT8_VLAN_KEEP_MASK_EXT_MASK;
+                retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, (portmask>>8)&0x7);
+                if(retVal != RT_ERR_OK)
+                    return retVal;
+                break;
+
+            case 9:
+                regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4;
+                bit_mask = RTL8367C_PORT9_VLAN_KEEP_MASK_MASK;
+                retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, portmask & 0xff);
+                if(retVal != RT_ERR_OK)
+                    return retVal;
+                regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4_EXT;
+                bit_mask = RTL8367C_PORT9_VLAN_KEEP_MASK_EXT_MASK;
+                retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, (portmask>>8)&0x7);
+                if(retVal != RT_ERR_OK)
+                    return retVal;
+                break;
+
+            case 10:
+                regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5;
+                bit_mask = RTL8367C_VLAN_EGRESS_KEEP_CTRL5_MASK;
+                retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, portmask & 0xff);
+                if(retVal != RT_ERR_OK)
+                    return retVal;
+                regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5_EXT;
+                bit_mask = RTL8367C_VLAN_EGRESS_KEEP_CTRL5_EXT_MASK;
+                retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, (portmask>>8)&0x7);
+                if(retVal != RT_ERR_OK)
+                    return retVal;
+                break;
+        }
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getAsicVlanEgressKeep
+ * Description:
+ *      Get per egress port VLAN keep mode
+ * Input:
+ *      port        - Physical port number (0~7)
+ *      pPortmask   - portmask(0~0xFF)
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_PORT_ID  - Invalid port number
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getAsicVlanEgressKeep(rtk_uint32 port, rtk_uint32* pPortmask)
+{
+    rtk_uint32 regAddr, bit_mask, regval_l, regval_h;
+    ret_t  retVal;
+
+    if(port > RTL8367C_PORTIDMAX)
+        return RT_ERR_PORT_ID;
+
+    if(port < 8){
+        retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0 + (port>>1),RTL8367C_PORT0_VLAN_KEEP_MASK_MASK<<((port&1)*8),&regval_l);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+        regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0_EXT + (port>>1);
+        bit_mask = RTL8367C_PORT0_VLAN_KEEP_MASK_EXT_MASK;
+        bit_mask <<= (port&1)*3;
+        retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, &regval_h);
+        if(retVal != RT_ERR_OK)
+            return retVal;
+        *pPortmask = (regval_h << 8) | regval_l;
+    }
+    else{
+        switch(port){
+            case 8:
+                regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4;
+                bit_mask = RTL8367C_PORT8_VLAN_KEEP_MASK_MASK;
+                retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, &regval_l);
+                if(retVal != RT_ERR_OK)
+                    return retVal;
+                regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4_EXT;
+                bit_mask = RTL8367C_PORT8_VLAN_KEEP_MASK_EXT_MASK;
+                retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, &regval_h);
+                if(retVal != RT_ERR_OK)
+                    return retVal;
+
+                *pPortmask = (regval_h << 8) | regval_l;
+                break;
+
+            case 9:
+                regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4;
+                bit_mask = RTL8367C_PORT9_VLAN_KEEP_MASK_MASK;
+                retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, &regval_l);
+                if(retVal != RT_ERR_OK)
+                    return retVal;
+                regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4_EXT;
+                bit_mask = RTL8367C_PORT9_VLAN_KEEP_MASK_EXT_MASK;
+                retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, &regval_h);
+                if(retVal != RT_ERR_OK)
+                    return retVal;
+
+                *pPortmask = (regval_h << 8) | regval_l;
+                break;
+
+            case 10:
+                regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5;
+                bit_mask = RTL8367C_VLAN_EGRESS_KEEP_CTRL5_MASK;
+                retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, &regval_l);
+                if(retVal != RT_ERR_OK)
+                    return retVal;
+                regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5_EXT;
+                bit_mask = RTL8367C_VLAN_EGRESS_KEEP_CTRL5_EXT_MASK;
+                retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, &regval_h);
+                if(retVal != RT_ERR_OK)
+                    return retVal;
+
+                *pPortmask = (regval_h << 8) | regval_l;
+                break;
+        }
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_setReservedVidAction
+ * Description:
+ *      Set reserved VID action
+ * Input:
+ *      vid0Action      - VID 0 action
+ *      vid4095Action   - VID 4095 action
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_INPUT    - Error input
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setReservedVidAction(rtk_uint32 vid0Action, rtk_uint32 vid4095Action)
+{
+    ret_t   retVal;
+
+    if(vid0Action >= RES_VID_ACT_END)
+        return RT_ERR_INPUT;
+
+    if(vid4095Action >= RES_VID_ACT_END)
+        return RT_ERR_INPUT;
+
+    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_VID0_TYPE_OFFSET, vid0Action)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_VID4095_TYPE_OFFSET, vid4095Action)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getReservedVidAction
+ * Description:
+ *      Get reserved VID action
+ * Input:
+ *      pVid0Action     - VID 0 action
+ *      pVid4095Action  - VID 4095 action
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - Success
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_NULL_POINTER - Null pointer
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getReservedVidAction(rtk_uint32 *pVid0Action, rtk_uint32 *pVid4095Action)
+{
+    ret_t   retVal;
+
+    if(pVid0Action == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    if(pVid4095Action == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_VID0_TYPE_OFFSET, pVid0Action)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_VID4095_TYPE_OFFSET, pVid4095Action)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+
+}
+
+/* Function Name:
+ *      rtl8367c_setRealKeepRemarkEn
+ * Description:
+ *      Set Real Keep Remark
+ * Input:
+ *      enabled         - 0: 1P remarking is forbidden at real keep packet, 1: 1P remarking is enabled at real keep packet
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_INPUT    - Error input
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_setRealKeepRemarkEn(rtk_uint32 enabled)
+{
+    ret_t   retVal;
+
+    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_1P_REMARK_BYPASS_REALKEEP_OFFSET, enabled)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_getRealKeepRemarkEn
+ * Description:
+ *      Get Real Keep Remark
+ * Input:
+ *      None
+ * Output:
+ *      pEnabled        - 0: 1P remarking is forbidden at real keep packet, 1: 1P remarking is enabled at real keep packet
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ *      RT_ERR_INPUT    - Error input
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_getRealKeepRemarkEn(rtk_uint32 *pEnabled)
+{
+    ret_t   retVal;
+
+    if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_1P_REMARK_BYPASS_REALKEEP_OFFSET, pEnabled)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtl8367c_resetVlan
+ * Description:
+ *      Reset VLAN table
+ * Input:
+ *      None.
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK       - Success
+ *      RT_ERR_SMI      - SMI access error
+ * Note:
+ *      None
+ */
+ret_t rtl8367c_resetVlan(void)
+{
+    ret_t   retVal;
+
+    if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL2, RTL8367C_VLAN_EXT_CTRL2_OFFSET, 1)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/smi.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/smi.c
new file mode 100644
index 0000000..c272cad
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/smi.c
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * Purpose : RTL8367C switch low-level function for access register
+ * Feature : SMI related functions
+ *
+ */
+
+
+#include <rtk_types.h>
+#include <smi.h>
+#include "rtk_error.h"
+
+
+#if defined(MDC_MDIO_OPERATION)
+/*******************************************************************************/
+/*  MDC/MDIO porting                                                           */
+/*******************************************************************************/
+/* define the PHY ID currently used */
+/* carlos */
+#if 0
+#define MDC_MDIO_PHY_ID     0  /* PHY ID 0 or 29 */
+#else
+#define MDC_MDIO_PHY_ID     29  /* PHY ID 0 or 29 */
+#endif
+
+/* MDC/MDIO, redefine/implement the following Macro */ /*carlos*/
+#if 0
+#define MDC_MDIO_WRITE(preamableLength, phyID, regID, data)
+#define MDC_MDIO_READ(preamableLength, phyID, regID, pData)
+#else
+#define u32      unsigned int
+extern u32 mii_mgr_read(u32 phy_addr, u32 phy_register, u32 *read_data);
+extern u32 mii_mgr_write(u32 phy_addr, u32 phy_register, u32 write_data);
+
+#define MDC_MDIO_WRITE(preamableLength, phyID, regID, data) mii_mgr_write(phyID, regID, data)
+#define MDC_MDIO_READ(preamableLength, phyID, regID, pData) mii_mgr_read(phyID, regID, pData)
+#endif
+
+
+
+
+
+#elif defined(SPI_OPERATION)
+/*******************************************************************************/
+/*  SPI porting                                                                */
+/*******************************************************************************/
+/* SPI, redefine/implement the following Macro */
+#define SPI_WRITE(data, length)
+#define SPI_READ(pData, length)
+
+
+
+
+
+#else
+/*******************************************************************************/
+/*  I2C porting                                                                */
+/*******************************************************************************/
+/* Define the GPIO ID for SCK & SDA */
+rtk_uint32  smi_SCK = 1;    /* GPIO used for SMI Clock Generation */
+rtk_uint32  smi_SDA = 2;    /* GPIO used for SMI Data signal */
+
+/* I2C, redefine/implement the following Macro */
+#define GPIO_DIRECTION_SET(gpioID, direction)
+#define GPIO_DATA_SET(gpioID, data)
+#define GPIO_DATA_GET(gpioID, pData)
+
+
+
+
+
+#endif
+
+static void rtlglue_drvMutexLock(void)
+{
+    /* It is empty currently. Implement this function if Lock/Unlock function is needed */
+    return;
+}
+
+static void rtlglue_drvMutexUnlock(void)
+{
+    /* It is empty currently. Implement this function if Lock/Unlock function is needed */
+    return;
+}
+
+
+
+#if defined(MDC_MDIO_OPERATION) || defined(SPI_OPERATION)
+    /* No local function in MDC/MDIO & SPI mode */
+#else
+static void _smi_start(void)
+{
+
+    /* change GPIO pin to Output only */
+    GPIO_DIRECTION_SET(smi_SCK, GPIO_DIR_OUT);
+    GPIO_DIRECTION_SET(smi_SDA, GPIO_DIR_OUT);
+
+    /* Initial state: SCK: 0, SDA: 1 */
+    GPIO_DATA_SET(smi_SCK, 0);
+    GPIO_DATA_SET(smi_SDA, 1);
+    CLK_DURATION(DELAY);
+
+    /* CLK 1: 0 -> 1, 1 -> 0 */
+    GPIO_DATA_SET(smi_SCK, 1);
+    CLK_DURATION(DELAY);
+    GPIO_DATA_SET(smi_SCK, 0);
+    CLK_DURATION(DELAY);
+
+    /* CLK 2: */
+    GPIO_DATA_SET(smi_SCK, 1);
+    CLK_DURATION(DELAY);
+    GPIO_DATA_SET(smi_SDA, 0);
+    CLK_DURATION(DELAY);
+    GPIO_DATA_SET(smi_SCK, 0);
+    CLK_DURATION(DELAY);
+    GPIO_DATA_SET(smi_SDA, 1);
+
+}
+
+
+
+static void _smi_writeBit(rtk_uint16 signal, rtk_uint32 bitLen)
+{
+    for( ; bitLen > 0; bitLen--)
+    {
+        CLK_DURATION(DELAY);
+
+        /* prepare data */
+        if ( signal & (1<<(bitLen-1)) )
+        {
+            GPIO_DATA_SET(smi_SDA, 1);
+        }
+        else
+        {
+            GPIO_DATA_SET(smi_SDA, 0);
+        }
+        CLK_DURATION(DELAY);
+
+        /* clocking */
+        GPIO_DATA_SET(smi_SCK, 1);
+        CLK_DURATION(DELAY);
+        GPIO_DATA_SET(smi_SCK, 0);
+    }
+}
+
+
+
+static void _smi_readBit(rtk_uint32 bitLen, rtk_uint32 *rData)
+{
+    rtk_uint32 u = 0;
+
+    /* change GPIO pin to Input only */
+    GPIO_DIRECTION_SET(smi_SDA, GPIO_DIR_IN);
+
+    for (*rData = 0; bitLen > 0; bitLen--)
+    {
+        CLK_DURATION(DELAY);
+
+        /* clocking */
+        GPIO_DATA_SET(smi_SCK, 1);
+        CLK_DURATION(DELAY);
+        GPIO_DATA_GET(smi_SDA, &u);
+        GPIO_DATA_SET(smi_SCK, 0);
+
+        *rData |= (u << (bitLen - 1));
+    }
+
+    /* change GPIO pin to Output only */
+    GPIO_DIRECTION_SET(smi_SDA, GPIO_DIR_OUT);
+}
+
+
+
+static void _smi_stop(void)
+{
+
+    CLK_DURATION(DELAY);
+    GPIO_DATA_SET(smi_SDA, 0);
+    GPIO_DATA_SET(smi_SCK, 1);
+    CLK_DURATION(DELAY);
+    GPIO_DATA_SET(smi_SDA, 1);
+    CLK_DURATION(DELAY);
+    GPIO_DATA_SET(smi_SCK, 1);
+    CLK_DURATION(DELAY);
+    GPIO_DATA_SET(smi_SCK, 0);
+    CLK_DURATION(DELAY);
+    GPIO_DATA_SET(smi_SCK, 1);
+
+    /* add a click */
+    CLK_DURATION(DELAY);
+    GPIO_DATA_SET(smi_SCK, 0);
+    CLK_DURATION(DELAY);
+    GPIO_DATA_SET(smi_SCK, 1);
+
+
+    /* change GPIO pin to Input only */
+    GPIO_DIRECTION_SET(smi_SDA, GPIO_DIR_IN);
+    GPIO_DIRECTION_SET(smi_SCK, GPIO_DIR_IN);
+}
+
+#endif /* End of #if defined(MDC_MDIO_OPERATION) || defined(SPI_OPERATION) */
+
+rtk_int32 smi_read(rtk_uint32 mAddrs, rtk_uint32 *rData)
+{
+#if (!defined(MDC_MDIO_OPERATION) && !defined(SPI_OPERATION))
+    rtk_uint32 rawData=0, ACK;
+    rtk_uint8  con;
+    rtk_uint32 ret = RT_ERR_OK;
+#endif
+
+    if(mAddrs > 0xFFFF)
+        return RT_ERR_INPUT;
+
+    if(rData == NULL)
+        return RT_ERR_NULL_POINTER;
+
+#if defined(MDC_MDIO_OPERATION)
+
+    /* Lock */
+    rtlglue_drvMutexLock();
+
+    /* Write address control code to register 31 */
+    MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP);
+
+    /* Write address to register 23 */
+    MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_ADDRESS_REG, mAddrs);
+
+    /* Write read control code to register 21 */
+    MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_CTRL1_REG, MDC_MDIO_READ_OP);
+
+    /* Read data from register 25 */
+    MDC_MDIO_READ(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_DATA_READ_REG, rData);
+
+    /* Unlock */
+    rtlglue_drvMutexUnlock();
+
+    return RT_ERR_OK;
+
+#elif defined(SPI_OPERATION)
+
+    /* Lock */
+    rtlglue_drvMutexLock();
+
+    /* Write 8 bits READ OP_CODE */
+    SPI_WRITE(SPI_READ_OP, SPI_READ_OP_LEN);
+
+    /* Write 16 bits register address */
+    SPI_WRITE(mAddrs, SPI_REG_LEN);
+
+    /* Read 16 bits data */
+    SPI_READ(rData, SPI_DATA_LEN);
+
+    /* Unlock */
+    rtlglue_drvMutexUnlock();
+
+    return RT_ERR_OK;
+
+#else
+
+    /*Disable CPU interrupt to ensure that the SMI operation is atomic.
+      The API is based on RTL865X, rewrite the API if porting to other platform.*/
+    rtlglue_drvMutexLock();
+
+    _smi_start();                                /* Start SMI */
+
+    _smi_writeBit(0x0b, 4);                     /* CTRL code: 4'b1011 for RTL8370 */
+
+    _smi_writeBit(0x4, 3);                        /* CTRL code: 3'b100 */
+
+    _smi_writeBit(0x1, 1);                        /* 1: issue READ command */
+
+    con = 0;
+    do {
+        con++;
+        _smi_readBit(1, &ACK);                    /* ACK for issuing READ command*/
+    } while ((ACK != 0) && (con < ack_timer));
+
+    if (ACK != 0) ret = RT_ERR_FAILED;
+
+    _smi_writeBit((mAddrs&0xff), 8);             /* Set reg_addr[7:0] */
+
+    con = 0;
+    do {
+        con++;
+        _smi_readBit(1, &ACK);                    /* ACK for setting reg_addr[7:0] */
+    } while ((ACK != 0) && (con < ack_timer));
+
+    if (ACK != 0) ret = RT_ERR_FAILED;
+
+    _smi_writeBit((mAddrs>>8), 8);                 /* Set reg_addr[15:8] */
+
+    con = 0;
+    do {
+        con++;
+        _smi_readBit(1, &ACK);                    /* ACK by RTL8369 */
+    } while ((ACK != 0) && (con < ack_timer));
+    if (ACK != 0) ret = RT_ERR_FAILED;
+
+    _smi_readBit(8, &rawData);                    /* Read DATA [7:0] */
+    *rData = rawData&0xff;
+
+    _smi_writeBit(0x00, 1);                        /* ACK by CPU */
+
+    _smi_readBit(8, &rawData);                    /* Read DATA [15: 8] */
+
+    _smi_writeBit(0x01, 1);                        /* ACK by CPU */
+    *rData |= (rawData<<8);
+
+    _smi_stop();
+
+    rtlglue_drvMutexUnlock();/*enable CPU interrupt*/
+
+    return ret;
+#endif /* end of #if defined(MDC_MDIO_OPERATION) */
+}
+
+
+
+rtk_int32 smi_write(rtk_uint32 mAddrs, rtk_uint32 rData)
+{
+#if (!defined(MDC_MDIO_OPERATION) && !defined(SPI_OPERATION))
+    rtk_int8 con;
+    rtk_uint32 ACK;
+    rtk_uint32 ret = RT_ERR_OK;
+#endif
+
+    if(mAddrs > 0xFFFF)
+        return RT_ERR_INPUT;
+
+    if(rData > 0xFFFF)
+        return RT_ERR_INPUT;
+
+#if defined(MDC_MDIO_OPERATION)
+
+    /* Lock */
+    rtlglue_drvMutexLock();
+
+    /* Write address control code to register 31 */
+    MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP);
+
+    /* Write address to register 23 */
+    MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_ADDRESS_REG, mAddrs);
+
+    /* Write data to register 24 */
+    MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_DATA_WRITE_REG, rData);
+
+    /* Write data control code to register 21 */
+    MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_CTRL1_REG, MDC_MDIO_WRITE_OP);
+
+    /* Unlock */
+    rtlglue_drvMutexUnlock();
+
+    return RT_ERR_OK;
+
+#elif defined(SPI_OPERATION)
+
+    /* Lock */
+    rtlglue_drvMutexLock();
+
+    /* Write 8 bits WRITE OP_CODE */
+    SPI_WRITE(SPI_WRITE_OP, SPI_WRITE_OP_LEN);
+
+    /* Write 16 bits register address */
+    SPI_WRITE(mAddrs, SPI_REG_LEN);
+
+    /* Write 16 bits data */
+    SPI_WRITE(rData, SPI_DATA_LEN);
+
+    /* Unlock */
+    rtlglue_drvMutexUnlock();
+
+    return RT_ERR_OK;
+#else
+
+    /*Disable CPU interrupt to ensure that the SMI operation is atomic.
+      The API is based on RTL865X, rewrite the API if porting to other platform.*/
+    rtlglue_drvMutexLock();
+
+    _smi_start();                                /* Start SMI */
+
+    _smi_writeBit(0x0b, 4);                     /* CTRL code: 4'b1011 for RTL8370*/
+
+    _smi_writeBit(0x4, 3);                        /* CTRL code: 3'b100 */
+
+    _smi_writeBit(0x0, 1);                        /* 0: issue WRITE command */
+
+    con = 0;
+    do {
+        con++;
+        _smi_readBit(1, &ACK);                    /* ACK for issuing WRITE command*/
+    } while ((ACK != 0) && (con < ack_timer));
+    if (ACK != 0) ret = RT_ERR_FAILED;
+
+    _smi_writeBit((mAddrs&0xff), 8);             /* Set reg_addr[7:0] */
+
+    con = 0;
+    do {
+        con++;
+        _smi_readBit(1, &ACK);                    /* ACK for setting reg_addr[7:0] */
+    } while ((ACK != 0) && (con < ack_timer));
+    if (ACK != 0) ret = RT_ERR_FAILED;
+
+    _smi_writeBit((mAddrs>>8), 8);                 /* Set reg_addr[15:8] */
+
+    con = 0;
+    do {
+        con++;
+        _smi_readBit(1, &ACK);                    /* ACK for setting reg_addr[15:8] */
+    } while ((ACK != 0) && (con < ack_timer));
+    if (ACK != 0) ret = RT_ERR_FAILED;
+
+    _smi_writeBit(rData&0xff, 8);                /* Write Data [7:0] out */
+
+    con = 0;
+    do {
+        con++;
+        _smi_readBit(1, &ACK);                    /* ACK for writting data [7:0] */
+    } while ((ACK != 0) && (con < ack_timer));
+    if (ACK != 0) ret = RT_ERR_FAILED;
+
+    _smi_writeBit(rData>>8, 8);                    /* Write Data [15:8] out */
+
+    con = 0;
+    do {
+        con++;
+        _smi_readBit(1, &ACK);                        /* ACK for writting data [15:8] */
+    } while ((ACK != 0) && (con < ack_timer));
+    if (ACK != 0) ret = RT_ERR_FAILED;
+
+    _smi_stop();
+
+    rtlglue_drvMutexUnlock();/*enable CPU interrupt*/
+
+    return ret;
+#endif /* end of #if defined(MDC_MDIO_OPERATION) */
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/stat.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/stat.c
new file mode 100644
index 0000000..3a328b0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/stat.c
@@ -0,0 +1,626 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in MIB module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <stat.h>
+#include <string.h>
+
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_mib.h>
+
+/* Function Name:
+ *      rtk_stat_global_reset
+ * Description:
+ *      Reset global MIB counter.
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      Reset MIB counter of ports. API will use global reset while port mask is all-ports.
+ */
+rtk_api_ret_t rtk_stat_global_reset(void)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((retVal = rtl8367c_setAsicMIBsCounterReset(TRUE,FALSE, 0)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_stat_port_reset
+ * Description:
+ *      Reset per port MIB counter by port.
+ * Input:
+ *      port - port id.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_stat_port_reset(rtk_port_t port)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if ((retVal = rtl8367c_setAsicMIBsCounterReset(FALSE,FALSE,1 << rtk_switch_port_L2P_get(port))) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_stat_queueManage_reset
+ * Description:
+ *      Reset queue manage MIB counter.
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_stat_queueManage_reset(void)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((retVal = rtl8367c_setAsicMIBsCounterReset(FALSE,TRUE,0)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_stat_global_get
+ * Description:
+ *      Get global MIB counter
+ * Input:
+ *      cntr_idx - global counter index.
+ * Output:
+ *      pCntr - global counter value.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      Get global MIB counter by index definition.
+ */
+rtk_api_ret_t rtk_stat_global_get(rtk_stat_global_type_t cntr_idx, rtk_stat_counter_t *pCntr)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pCntr)
+        return RT_ERR_NULL_POINTER;
+
+    if (cntr_idx!=DOT1D_TP_LEARNED_ENTRY_DISCARDS_INDEX)
+        return RT_ERR_STAT_INVALID_GLOBAL_CNTR;
+
+    if ((retVal = rtl8367c_getAsicMIBsCounter(0, cntr_idx, pCntr)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_stat_global_getAll
+ * Description:
+ *      Get all global MIB counter
+ * Input:
+ *      None
+ * Output:
+ *      pGlobal_cntrs - global counter structure.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      Get all global MIB counter by index definition.
+ */
+rtk_api_ret_t rtk_stat_global_getAll(rtk_stat_global_cntr_t *pGlobal_cntrs)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pGlobal_cntrs)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicMIBsCounter(0,DOT1D_TP_LEARNED_ENTRY_DISCARDS_INDEX, &pGlobal_cntrs->dot1dTpLearnedEntryDiscards)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+#define MIB_NOT_SUPPORT     (0xFFFF)
+static rtk_api_ret_t _get_asic_mib_idx(rtk_stat_port_type_t cnt_idx, RTL8367C_MIBCOUNTER *pMib_idx)
+{
+    RTL8367C_MIBCOUNTER mib_asic_idx[STAT_PORT_CNTR_END]=
+    {
+        ifInOctets,                     /* STAT_IfInOctets */
+        dot3StatsFCSErrors,             /* STAT_Dot3StatsFCSErrors */
+        dot3StatsSymbolErrors,          /* STAT_Dot3StatsSymbolErrors */
+        dot3InPauseFrames,              /* STAT_Dot3InPauseFrames */
+        dot3ControlInUnknownOpcodes,    /* STAT_Dot3ControlInUnknownOpcodes */
+        etherStatsFragments,            /* STAT_EtherStatsFragments */
+        etherStatsJabbers,              /* STAT_EtherStatsJabbers */
+        ifInUcastPkts,                  /* STAT_IfInUcastPkts */
+        etherStatsDropEvents,           /* STAT_EtherStatsDropEvents */
+        etherStatsOctets,               /* STAT_EtherStatsOctets */
+        etherStatsUnderSizePkts,        /* STAT_EtherStatsUnderSizePkts */
+        etherOversizeStats,             /* STAT_EtherOversizeStats */
+        etherStatsPkts64Octets,         /* STAT_EtherStatsPkts64Octets */
+        etherStatsPkts65to127Octets,    /* STAT_EtherStatsPkts65to127Octets */
+        etherStatsPkts128to255Octets,   /* STAT_EtherStatsPkts128to255Octets */
+        etherStatsPkts256to511Octets,   /* STAT_EtherStatsPkts256to511Octets */
+        etherStatsPkts512to1023Octets,  /* STAT_EtherStatsPkts512to1023Octets */
+        etherStatsPkts1024to1518Octets, /* STAT_EtherStatsPkts1024to1518Octets */
+        ifInMulticastPkts,              /* STAT_EtherStatsMulticastPkts */
+        ifInBroadcastPkts,              /* STAT_EtherStatsBroadcastPkts */
+        ifOutOctets,                    /* STAT_IfOutOctets */
+        dot3StatsSingleCollisionFrames, /* STAT_Dot3StatsSingleCollisionFrames */
+        dot3StatMultipleCollisionFrames,/* STAT_Dot3StatsMultipleCollisionFrames */
+        dot3sDeferredTransmissions,     /* STAT_Dot3StatsDeferredTransmissions */
+        dot3StatsLateCollisions,        /* STAT_Dot3StatsLateCollisions */
+        etherStatsCollisions,           /* STAT_EtherStatsCollisions */
+        dot3StatsExcessiveCollisions,   /* STAT_Dot3StatsExcessiveCollisions */
+        dot3OutPauseFrames,             /* STAT_Dot3OutPauseFrames */
+        MIB_NOT_SUPPORT,                /* STAT_Dot1dBasePortDelayExceededDiscards */
+        dot1dTpPortInDiscards,          /* STAT_Dot1dTpPortInDiscards */
+        ifOutUcastPkts,                 /* STAT_IfOutUcastPkts */
+        ifOutMulticastPkts,             /* STAT_IfOutMulticastPkts */
+        ifOutBroadcastPkts,             /* STAT_IfOutBroadcastPkts */
+        outOampduPkts,                  /* STAT_OutOampduPkts */
+        inOampduPkts,                   /* STAT_InOampduPkts */
+        MIB_NOT_SUPPORT,                /* STAT_PktgenPkts */
+        inMldChecksumError,             /* STAT_InMldChecksumError */
+        inIgmpChecksumError,            /* STAT_InIgmpChecksumError */
+        inMldSpecificQuery,             /* STAT_InMldSpecificQuery */
+        inMldGeneralQuery,              /* STAT_InMldGeneralQuery */
+        inIgmpSpecificQuery,            /* STAT_InIgmpSpecificQuery */
+        inIgmpGeneralQuery,             /* STAT_InIgmpGeneralQuery */
+        inMldLeaves,                    /* STAT_InMldLeaves */
+        inIgmpLeaves,                   /* STAT_InIgmpInterfaceLeaves */
+        inIgmpJoinsSuccess,             /* STAT_InIgmpJoinsSuccess */
+        inIgmpJoinsFail,                /* STAT_InIgmpJoinsFail */
+        inMldJoinsSuccess,              /* STAT_InMldJoinsSuccess */
+        inMldJoinsFail,                 /* STAT_InMldJoinsFail */
+        inReportSuppressionDrop,        /* STAT_InReportSuppressionDrop */
+        inLeaveSuppressionDrop,         /* STAT_InLeaveSuppressionDrop */
+        outIgmpReports,                 /* STAT_OutIgmpReports */
+        outIgmpLeaves,                  /* STAT_OutIgmpLeaves */
+        outIgmpGeneralQuery,            /* STAT_OutIgmpGeneralQuery */
+        outIgmpSpecificQuery,           /* STAT_OutIgmpSpecificQuery */
+        outMldReports,                  /* STAT_OutMldReports */
+        outMldLeaves,                   /* STAT_OutMldLeaves */
+        outMldGeneralQuery,             /* STAT_OutMldGeneralQuery */
+        outMldSpecificQuery,            /* STAT_OutMldSpecificQuery */
+        inKnownMulticastPkts,           /* STAT_InKnownMulticastPkts */
+        ifInMulticastPkts,              /* STAT_IfInMulticastPkts */
+        ifInBroadcastPkts,              /* STAT_IfInBroadcastPkts */
+        ifOutDiscards                   /* STAT_IfOutDiscards */
+    };
+
+    if(cnt_idx >= STAT_PORT_CNTR_END)
+        return RT_ERR_STAT_INVALID_PORT_CNTR;
+
+    if(mib_asic_idx[cnt_idx] == MIB_NOT_SUPPORT)
+        return RT_ERR_CHIP_NOT_SUPPORTED;
+
+    *pMib_idx = mib_asic_idx[cnt_idx];
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_stat_port_get
+ * Description:
+ *      Get per port MIB counter by index
+ * Input:
+ *      port        - port id.
+ *      cntr_idx    - port counter index.
+ * Output:
+ *      pCntr - MIB retrived counter.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      Get per port MIB counter by index definition.
+ */
+rtk_api_ret_t rtk_stat_port_get(rtk_port_t port, rtk_stat_port_type_t cntr_idx, rtk_stat_counter_t *pCntr)
+{
+    rtk_api_ret_t       retVal;
+    RTL8367C_MIBCOUNTER mib_idx;
+    rtk_stat_counter_t  second_cnt;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pCntr)
+        return RT_ERR_NULL_POINTER;
+
+    /* Check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (cntr_idx>=STAT_PORT_CNTR_END)
+        return RT_ERR_STAT_INVALID_PORT_CNTR;
+
+    if((retVal = _get_asic_mib_idx(cntr_idx, &mib_idx)) != RT_ERR_OK)
+        return retVal;
+
+    if(mib_idx == MIB_NOT_SUPPORT)
+        return RT_ERR_CHIP_NOT_SUPPORTED;
+
+    if ((retVal = rtl8367c_getAsicMIBsCounter(rtk_switch_port_L2P_get(port), mib_idx, pCntr)) != RT_ERR_OK)
+        return retVal;
+
+    if(cntr_idx == STAT_EtherStatsMulticastPkts)
+    {
+        if((retVal = _get_asic_mib_idx(STAT_IfOutMulticastPkts, &mib_idx)) != RT_ERR_OK)
+            return retVal;
+
+        if((retVal = rtl8367c_getAsicMIBsCounter(rtk_switch_port_L2P_get(port), mib_idx, &second_cnt)) != RT_ERR_OK)
+            return retVal;
+
+        *pCntr += second_cnt;
+    }
+
+    if(cntr_idx == STAT_EtherStatsBroadcastPkts)
+    {
+        if((retVal = _get_asic_mib_idx(STAT_IfOutBroadcastPkts, &mib_idx)) != RT_ERR_OK)
+            return retVal;
+
+        if((retVal = rtl8367c_getAsicMIBsCounter(rtk_switch_port_L2P_get(port), mib_idx, &second_cnt)) != RT_ERR_OK)
+            return retVal;
+
+        *pCntr += second_cnt;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_stat_port_getAll
+ * Description:
+ *      Get all counters of one specified port in the specified device.
+ * Input:
+ *      port - port id.
+ * Output:
+ *      pPort_cntrs - buffer pointer of counter value.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      Get all MIB counters of one port.
+ */
+rtk_api_ret_t rtk_stat_port_getAll(rtk_port_t port, rtk_stat_port_cntr_t *pPort_cntrs)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 mibIndex;
+    rtk_uint64 mibCounter;
+    rtk_uint32 *accessPtr;
+    /* address offset to MIBs counter */
+    CONST_T rtk_uint16 mibLength[STAT_PORT_CNTR_END]= {
+        2,1,1,1,1,1,1,1,1,
+        2,1,1,1,1,1,1,1,1,1,1,
+        2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pPort_cntrs)
+        return RT_ERR_NULL_POINTER;
+
+    /* Check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    accessPtr = (rtk_uint32*)pPort_cntrs;
+    for (mibIndex=0;mibIndex<STAT_PORT_CNTR_END;mibIndex++)
+    {
+        if ((retVal = rtk_stat_port_get(port, mibIndex, &mibCounter)) != RT_ERR_OK)
+        {
+            if (retVal == RT_ERR_CHIP_NOT_SUPPORTED)
+                mibCounter = 0;
+            else
+                return retVal;
+        }
+
+        if (2 == mibLength[mibIndex])
+            *(rtk_uint64*)accessPtr = mibCounter;
+        else if (1 == mibLength[mibIndex])
+            *accessPtr = mibCounter;
+        else
+            return RT_ERR_FAILED;
+
+        accessPtr+=mibLength[mibIndex];
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_stat_logging_counterCfg_set
+ * Description:
+ *      Set the type and mode of Logging Counter
+ * Input:
+ *      idx     - The index of Logging Counter. Should be even number only.(0,2,4,6,8.....30)
+ *      mode    - 32 bits or 64 bits mode
+ *      type    - Packet counter or byte counter
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_OUT_OF_RANGE - Out of range.
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      Set the type and mode of Logging Counter.
+ */
+rtk_api_ret_t rtk_stat_logging_counterCfg_set(rtk_uint32 idx, rtk_logging_counter_mode_t mode, rtk_logging_counter_type_t type)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(idx > RTL8367C_MIB_MAX_LOG_CNT_IDX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if((idx % 2) == 1)
+        return RT_ERR_INPUT;
+
+    if(mode >= LOGGING_MODE_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(type >= LOGGING_TYPE_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if((retVal = rtl8367c_setAsicMIBsLoggingType((idx / 2), (rtk_uint32)type)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicMIBsLoggingMode((idx / 2), (rtk_uint32)mode)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_stat_logging_counterCfg_get
+ * Description:
+ *      Get the type and mode of Logging Counter
+ * Input:
+ *      idx     - The index of Logging Counter. Should be even number only.(0,2,4,6,8.....30)
+ * Output:
+ *      pMode   - 32 bits or 64 bits mode
+ *      pType   - Packet counter or byte counter
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_OUT_OF_RANGE - Out of range.
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_NULL_POINTER - NULL Pointer
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      Get the type and mode of Logging Counter.
+ */
+rtk_api_ret_t rtk_stat_logging_counterCfg_get(rtk_uint32 idx, rtk_logging_counter_mode_t *pMode, rtk_logging_counter_type_t *pType)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32      type, mode;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(idx > RTL8367C_MIB_MAX_LOG_CNT_IDX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if((idx % 2) == 1)
+        return RT_ERR_INPUT;
+
+    if(pMode == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    if(pType == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    if((retVal = rtl8367c_getAsicMIBsLoggingType((idx / 2), &type)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_getAsicMIBsLoggingMode((idx / 2), &mode)) != RT_ERR_OK)
+        return retVal;
+
+    *pMode = (rtk_logging_counter_mode_t)mode;
+    *pType = (rtk_logging_counter_type_t)type;
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_stat_logging_counter_reset
+ * Description:
+ *      Reset Logging Counter
+ * Input:
+ *      idx     - The index of Logging Counter. (0~31)
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_OUT_OF_RANGE - Out of range.
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      Reset Logging Counter.
+ */
+rtk_api_ret_t rtk_stat_logging_counter_reset(rtk_uint32 idx)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(idx > RTL8367C_MIB_MAX_LOG_CNT_IDX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if((retVal = rtl8367c_setAsicMIBsResetLoggingCounter(idx)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_stat_logging_counter_get
+ * Description:
+ *      Get Logging Counter
+ * Input:
+ *      idx     - The index of Logging Counter. (0~31)
+ * Output:
+ *      pCnt    - Logging counter value
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_OUT_OF_RANGE - Out of range.
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      Get Logging Counter.
+ */
+rtk_api_ret_t rtk_stat_logging_counter_get(rtk_uint32 idx, rtk_uint32 *pCnt)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pCnt)
+        return RT_ERR_NULL_POINTER;
+
+    if(idx > RTL8367C_MIB_MAX_LOG_CNT_IDX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if((retVal = rtl8367c_getAsicMIBsLogCounter(idx, pCnt)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_stat_lengthMode_set
+ * Description:
+ *      Set Legnth mode.
+ * Input:
+ *      txMode     - The length counting mode
+ *      rxMode     - The length counting mode
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_INPUT        - Out of range.
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_stat_lengthMode_set(rtk_stat_lengthMode_t txMode, rtk_stat_lengthMode_t rxMode)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(txMode >= LENGTH_MODE_END)
+        return RT_ERR_INPUT;
+
+    if(rxMode >= LENGTH_MODE_END)
+        return RT_ERR_INPUT;
+
+    if((retVal = rtl8367c_setAsicMIBsLength((rtk_uint32)txMode, (rtk_uint32)rxMode)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_stat_lengthMode_get
+ * Description:
+ *      Get Legnth mode.
+ * Input:
+ *      None.
+ * Output:
+ *      pTxMode       - The length counting mode
+ *      pRxMode       - The length counting mode
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_INPUT        - Out of range.
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ */
+rtk_api_ret_t rtk_stat_lengthMode_get(rtk_stat_lengthMode_t *pTxMode, rtk_stat_lengthMode_t *pRxMode)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pTxMode)
+        return RT_ERR_NULL_POINTER;
+
+    if(NULL == pRxMode)
+        return RT_ERR_NULL_POINTER;
+
+    if((retVal = rtl8367c_getAsicMIBsLength((rtk_uint32 *)pTxMode, (rtk_uint32 *)pRxMode)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/storm.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/storm.c
new file mode 100644
index 0000000..13cf4e3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/storm.c
@@ -0,0 +1,816 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in Storm module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <storm.h>
+#include <rate.h>
+#include <string.h>
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_storm.h>
+#include <rtl8367c_asicdrv_meter.h>
+#include <rtl8367c_asicdrv_rma.h>
+#include <rtl8367c_asicdrv_igmp.h>
+
+/* Function Name:
+ *      rtk_rate_stormControlMeterIdx_set
+ * Description:
+ *      Set the storm control meter index.
+ * Input:
+ *      port       - port id
+ *      storm_type - storm group type
+ *      index       - storm control meter index.
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID - Invalid port id
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_rate_stormControlMeterIdx_set(rtk_port_t port, rtk_rate_storm_group_t stormType, rtk_uint32 index)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (stormType >= STORM_GROUP_END)
+        return RT_ERR_SFC_UNKNOWN_GROUP;
+
+    if (index > RTK_MAX_METER_ID)
+        return RT_ERR_FILTER_METER_ID;
+
+    switch (stormType)
+    {
+        case STORM_GROUP_UNKNOWN_UNICAST:
+            if ((retVal = rtl8367c_setAsicStormFilterUnknownUnicastMeter(rtk_switch_port_L2P_get(port), index))!=RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_UNKNOWN_MULTICAST:
+            if ((retVal = rtl8367c_setAsicStormFilterUnknownMulticastMeter(rtk_switch_port_L2P_get(port), index))!=RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_MULTICAST:
+            if ((retVal = rtl8367c_setAsicStormFilterMulticastMeter(rtk_switch_port_L2P_get(port), index))!=RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_BROADCAST:
+            if ((retVal = rtl8367c_setAsicStormFilterBroadcastMeter(rtk_switch_port_L2P_get(port), index))!=RT_ERR_OK)
+                return retVal;
+            break;
+        default:
+            break;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_rate_stormControlMeterIdx_get
+ * Description:
+ *      Get the storm control meter index.
+ * Input:
+ *      port       - port id
+ *      storm_type - storm group type
+ * Output:
+ *      pIndex     - storm control meter index.
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_PORT_ID - Invalid port id
+ *      RT_ERR_FILTER_METER_ID  - Invalid meter
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_rate_stormControlMeterIdx_get(rtk_port_t port, rtk_rate_storm_group_t stormType, rtk_uint32 *pIndex)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (stormType >= STORM_GROUP_END)
+        return RT_ERR_SFC_UNKNOWN_GROUP;
+
+    if (NULL == pIndex )
+        return RT_ERR_NULL_POINTER;
+
+    switch (stormType)
+    {
+        case STORM_GROUP_UNKNOWN_UNICAST:
+            if ((retVal = rtl8367c_getAsicStormFilterUnknownUnicastMeter(rtk_switch_port_L2P_get(port), pIndex))!=RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_UNKNOWN_MULTICAST:
+            if ((retVal = rtl8367c_getAsicStormFilterUnknownMulticastMeter(rtk_switch_port_L2P_get(port), pIndex))!=RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_MULTICAST:
+            if ((retVal = rtl8367c_getAsicStormFilterMulticastMeter(rtk_switch_port_L2P_get(port), pIndex))!=RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_BROADCAST:
+            if ((retVal = rtl8367c_getAsicStormFilterBroadcastMeter(rtk_switch_port_L2P_get(port), pIndex))!=RT_ERR_OK)
+                return retVal;
+            break;
+        default:
+            break;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_rate_stormControlPortEnable_set
+ * Description:
+ *      Set enable status of storm control on specified port.
+ * Input:
+ *      port       - port id
+ *      stormType  - storm group type
+ *      enable     - enable status of storm control
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT          - The module is not initial
+ *      RT_ERR_PORT_ID           - invalid port id
+ *      RT_ERR_INPUT             - invalid input parameter
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_rate_stormControlPortEnable_set(rtk_port_t port, rtk_rate_storm_group_t stormType, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (stormType >= STORM_GROUP_END)
+        return RT_ERR_SFC_UNKNOWN_GROUP;
+
+    if (enable >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    switch (stormType)
+    {
+        case STORM_GROUP_UNKNOWN_UNICAST:
+            if ((retVal = rtl8367c_setAsicStormFilterUnknownUnicastEnable(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_UNKNOWN_MULTICAST:
+            if ((retVal = rtl8367c_setAsicStormFilterUnknownMulticastEnable(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_MULTICAST:
+            if ((retVal = rtl8367c_setAsicStormFilterMulticastEnable(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_BROADCAST:
+            if ((retVal = rtl8367c_setAsicStormFilterBroadcastEnable(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK)
+                return retVal;
+            break;
+        default:
+            break;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_rate_stormControlPortEnable_set
+ * Description:
+ *      Set enable status of storm control on specified port.
+ * Input:
+ *      port       - port id
+ *      stormType  - storm group type
+ * Output:
+ *      pEnable     - enable status of storm control
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT          - The module is not initial
+ *      RT_ERR_PORT_ID           - invalid port id
+ *      RT_ERR_INPUT             - invalid input parameter
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_rate_stormControlPortEnable_get(rtk_port_t port, rtk_rate_storm_group_t stormType, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (stormType >= STORM_GROUP_END)
+        return RT_ERR_SFC_UNKNOWN_GROUP;
+
+    if (NULL == pEnable)
+        return RT_ERR_ENABLE;
+
+    switch (stormType)
+    {
+        case STORM_GROUP_UNKNOWN_UNICAST:
+            if ((retVal = rtl8367c_getAsicStormFilterUnknownUnicastEnable(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_UNKNOWN_MULTICAST:
+            if ((retVal = rtl8367c_getAsicStormFilterUnknownMulticastEnable(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_MULTICAST:
+            if ((retVal = rtl8367c_getAsicStormFilterMulticastEnable(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_BROADCAST:
+            if ((retVal = rtl8367c_getAsicStormFilterBroadcastEnable(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK)
+                return retVal;
+            break;
+        default:
+            break;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_storm_bypass_set
+ * Description:
+ *      Set bypass storm filter control configuration.
+ * Input:
+ *      type    - Bypass storm filter control type.
+ *      enable  - Bypass status.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_ENABLE       - Invalid IFG parameter
+ * Note:
+ *
+ *      This API can set per-port bypass stomr filter control frame type including RMA and igmp.
+ *      The bypass frame type is as following:
+ *      - BYPASS_BRG_GROUP,
+ *      - BYPASS_FD_PAUSE,
+ *      - BYPASS_SP_MCAST,
+ *      - BYPASS_1X_PAE,
+ *      - BYPASS_UNDEF_BRG_04,
+ *      - BYPASS_UNDEF_BRG_05,
+ *      - BYPASS_UNDEF_BRG_06,
+ *      - BYPASS_UNDEF_BRG_07,
+ *      - BYPASS_PROVIDER_BRIDGE_GROUP_ADDRESS,
+ *      - BYPASS_UNDEF_BRG_09,
+ *      - BYPASS_UNDEF_BRG_0A,
+ *      - BYPASS_UNDEF_BRG_0B,
+ *      - BYPASS_UNDEF_BRG_0C,
+ *      - BYPASS_PROVIDER_BRIDGE_GVRP_ADDRESS,
+ *      - BYPASS_8021AB,
+ *      - BYPASS_UNDEF_BRG_0F,
+ *      - BYPASS_BRG_MNGEMENT,
+ *      - BYPASS_UNDEFINED_11,
+ *      - BYPASS_UNDEFINED_12,
+ *      - BYPASS_UNDEFINED_13,
+ *      - BYPASS_UNDEFINED_14,
+ *      - BYPASS_UNDEFINED_15,
+ *      - BYPASS_UNDEFINED_16,
+ *      - BYPASS_UNDEFINED_17,
+ *      - BYPASS_UNDEFINED_18,
+ *      - BYPASS_UNDEFINED_19,
+ *      - BYPASS_UNDEFINED_1A,
+ *      - BYPASS_UNDEFINED_1B,
+ *      - BYPASS_UNDEFINED_1C,
+ *      - BYPASS_UNDEFINED_1D,
+ *      - BYPASS_UNDEFINED_1E,
+ *      - BYPASS_UNDEFINED_1F,
+ *      - BYPASS_GMRP,
+ *      - BYPASS_GVRP,
+ *      - BYPASS_UNDEF_GARP_22,
+ *      - BYPASS_UNDEF_GARP_23,
+ *      - BYPASS_UNDEF_GARP_24,
+ *      - BYPASS_UNDEF_GARP_25,
+ *      - BYPASS_UNDEF_GARP_26,
+ *      - BYPASS_UNDEF_GARP_27,
+ *      - BYPASS_UNDEF_GARP_28,
+ *      - BYPASS_UNDEF_GARP_29,
+ *      - BYPASS_UNDEF_GARP_2A,
+ *      - BYPASS_UNDEF_GARP_2B,
+ *      - BYPASS_UNDEF_GARP_2C,
+ *      - BYPASS_UNDEF_GARP_2D,
+ *      - BYPASS_UNDEF_GARP_2E,
+ *      - BYPASS_UNDEF_GARP_2F,
+ *      - BYPASS_IGMP.
+ *      - BYPASS_CDP.
+ *      - BYPASS_CSSTP.
+ *      - BYPASS_LLDP.
+ */
+rtk_api_ret_t rtk_storm_bypass_set(rtk_storm_bypass_t type, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_rma_t rmacfg;
+    rtk_uint32 tmp;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (type >= BYPASS_END)
+        return RT_ERR_INPUT;
+
+    if (enable >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if (type >= 0 && type <= BYPASS_UNDEF_GARP_2F)
+    {
+        if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        rmacfg.discard_storm_filter = enable;
+
+        if ((retVal = rtl8367c_setAsicRma(type, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+    }
+    else if(type == BYPASS_IGMP)
+    {
+        if ((retVal = rtl8367c_setAsicIGMPBypassStormCTRL(enable)) != RT_ERR_OK)
+            return retVal;
+    }
+    else if (type == BYPASS_CDP)
+    {
+        if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        rmacfg.discard_storm_filter = enable;
+
+        if ((retVal = rtl8367c_setAsicRmaCdp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+    }
+    else if (type  == BYPASS_CSSTP)
+    {
+        if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        rmacfg.discard_storm_filter = enable;
+
+        if ((retVal = rtl8367c_setAsicRmaCsstp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+    }
+    else if (type  == BYPASS_LLDP)
+    {
+        if ((retVal = rtl8367c_getAsicRmaLldp(&tmp, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        rmacfg.discard_storm_filter = enable;
+
+        if ((retVal = rtl8367c_setAsicRmaLldp(tmp, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+    }
+    else
+        return RT_ERR_INPUT;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_storm_bypass_get
+ * Description:
+ *      Get bypass storm filter control configuration.
+ * Input:
+ *      type - Bypass storm filter control type.
+ * Output:
+ *      pEnable - Bypass status.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API can get per-port bypass stomr filter control frame type including RMA and igmp.
+ *      The bypass frame type is as following:
+ *      - BYPASS_BRG_GROUP,
+ *      - BYPASS_FD_PAUSE,
+ *      - BYPASS_SP_MCAST,
+ *      - BYPASS_1X_PAE,
+ *      - BYPASS_UNDEF_BRG_04,
+ *      - BYPASS_UNDEF_BRG_05,
+ *      - BYPASS_UNDEF_BRG_06,
+ *      - BYPASS_UNDEF_BRG_07,
+ *      - BYPASS_PROVIDER_BRIDGE_GROUP_ADDRESS,
+ *      - BYPASS_UNDEF_BRG_09,
+ *      - BYPASS_UNDEF_BRG_0A,
+ *      - BYPASS_UNDEF_BRG_0B,
+ *      - BYPASS_UNDEF_BRG_0C,
+ *      - BYPASS_PROVIDER_BRIDGE_GVRP_ADDRESS,
+ *      - BYPASS_8021AB,
+ *      - BYPASS_UNDEF_BRG_0F,
+ *      - BYPASS_BRG_MNGEMENT,
+ *      - BYPASS_UNDEFINED_11,
+ *      - BYPASS_UNDEFINED_12,
+ *      - BYPASS_UNDEFINED_13,
+ *      - BYPASS_UNDEFINED_14,
+ *      - BYPASS_UNDEFINED_15,
+ *      - BYPASS_UNDEFINED_16,
+ *      - BYPASS_UNDEFINED_17,
+ *      - BYPASS_UNDEFINED_18,
+ *      - BYPASS_UNDEFINED_19,
+ *      - BYPASS_UNDEFINED_1A,
+ *      - BYPASS_UNDEFINED_1B,
+ *      - BYPASS_UNDEFINED_1C,
+ *      - BYPASS_UNDEFINED_1D,
+ *      - BYPASS_UNDEFINED_1E,
+ *      - BYPASS_UNDEFINED_1F,
+ *      - BYPASS_GMRP,
+ *      - BYPASS_GVRP,
+ *      - BYPASS_UNDEF_GARP_22,
+ *      - BYPASS_UNDEF_GARP_23,
+ *      - BYPASS_UNDEF_GARP_24,
+ *      - BYPASS_UNDEF_GARP_25,
+ *      - BYPASS_UNDEF_GARP_26,
+ *      - BYPASS_UNDEF_GARP_27,
+ *      - BYPASS_UNDEF_GARP_28,
+ *      - BYPASS_UNDEF_GARP_29,
+ *      - BYPASS_UNDEF_GARP_2A,
+ *      - BYPASS_UNDEF_GARP_2B,
+ *      - BYPASS_UNDEF_GARP_2C,
+ *      - BYPASS_UNDEF_GARP_2D,
+ *      - BYPASS_UNDEF_GARP_2E,
+ *      - BYPASS_UNDEF_GARP_2F,
+ *      - BYPASS_IGMP.
+ *      - BYPASS_CDP.
+ *      - BYPASS_CSSTP.
+ *      - BYPASS_LLDP.
+ */
+rtk_api_ret_t rtk_storm_bypass_get(rtk_storm_bypass_t type, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_rma_t rmacfg;
+    rtk_uint32 tmp;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (type >= BYPASS_END)
+        return RT_ERR_INPUT;
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if (type >= 0 && type <= BYPASS_UNDEF_GARP_2F)
+    {
+        if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        *pEnable = rmacfg.discard_storm_filter;
+    }
+    else if(type == BYPASS_IGMP)
+    {
+        if ((retVal = rtl8367c_getAsicIGMPBypassStormCTRL(pEnable)) != RT_ERR_OK)
+            return retVal;
+    }
+    else if (type == BYPASS_CDP)
+    {
+        if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        *pEnable = rmacfg.discard_storm_filter;
+    }
+    else if (type == BYPASS_CSSTP)
+    {
+        if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        *pEnable = rmacfg.discard_storm_filter;
+    }
+    else if (type == BYPASS_LLDP)
+    {
+        if ((retVal = rtl8367c_getAsicRmaLldp(&tmp,&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        *pEnable = rmacfg.discard_storm_filter;
+    }
+    else
+        return RT_ERR_INPUT;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_rate_stormControlExtPortmask_set
+ * Description:
+ *      Set externsion storm control port mask
+ * Input:
+ *      pPortmask  - port mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT          - The module is not initial
+ *      RT_ERR_INPUT             - invalid input parameter
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_rate_stormControlExtPortmask_set(rtk_portmask_t *pPortmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pPortmask)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicStormFilterExtEnablePortMask(pmask)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_rate_stormControlExtPortmask_get
+ * Description:
+ *      Set externsion storm control port mask
+ * Input:
+ *      None
+ * Output:
+ *      pPortmask  - port mask
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT          - The module is not initial
+ *      RT_ERR_INPUT             - invalid input parameter
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_rate_stormControlExtPortmask_get(rtk_portmask_t *pPortmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pPortmask)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicStormFilterExtEnablePortMask(&pmask)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_rate_stormControlExtEnable_set
+ * Description:
+ *      Set externsion storm control state
+ * Input:
+ *      stormType   - storm group type
+ *      enable      - externsion storm control state
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT          - The module is not initial
+ *      RT_ERR_INPUT             - invalid input parameter
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_rate_stormControlExtEnable_set(rtk_rate_storm_group_t stormType, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (stormType >= STORM_GROUP_END)
+        return RT_ERR_SFC_UNKNOWN_GROUP;
+
+    if (enable >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    switch (stormType)
+    {
+        case STORM_GROUP_UNKNOWN_UNICAST:
+            if ((retVal = rtl8367c_setAsicStormFilterExtUnknownUnicastEnable(enable)) != RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_UNKNOWN_MULTICAST:
+            if ((retVal = rtl8367c_setAsicStormFilterExtUnknownMulticastEnable(enable)) != RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_MULTICAST:
+            if ((retVal = rtl8367c_setAsicStormFilterExtMulticastEnable(enable)) != RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_BROADCAST:
+            if ((retVal = rtl8367c_setAsicStormFilterExtBroadcastEnable(enable)) != RT_ERR_OK)
+                return retVal;
+            break;
+        default:
+            break;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_rate_stormControlExtEnable_get
+ * Description:
+ *      Get externsion storm control state
+ * Input:
+ *      stormType   - storm group type
+ * Output:
+ *      pEnable     - externsion storm control state
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT          - The module is not initial
+ *      RT_ERR_INPUT             - invalid input parameter
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_rate_stormControlExtEnable_get(rtk_rate_storm_group_t stormType, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (stormType >= STORM_GROUP_END)
+        return RT_ERR_SFC_UNKNOWN_GROUP;
+
+    if (NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    switch (stormType)
+    {
+        case STORM_GROUP_UNKNOWN_UNICAST:
+            if ((retVal = rtl8367c_getAsicStormFilterExtUnknownUnicastEnable((rtk_uint32 *)pEnable)) != RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_UNKNOWN_MULTICAST:
+            if ((retVal = rtl8367c_getAsicStormFilterExtUnknownMulticastEnable((rtk_uint32 *)pEnable)) != RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_MULTICAST:
+            if ((retVal = rtl8367c_getAsicStormFilterExtMulticastEnable((rtk_uint32 *)pEnable)) != RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_BROADCAST:
+            if ((retVal = rtl8367c_getAsicStormFilterExtBroadcastEnable((rtk_uint32 *)pEnable)) != RT_ERR_OK)
+                return retVal;
+            break;
+        default:
+            break;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_rate_stormControlExtMeterIdx_set
+ * Description:
+ *      Set externsion storm control meter index
+ * Input:
+ *      stormType   - storm group type
+ *      index       - externsion storm control state
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT          - The module is not initial
+ *      RT_ERR_INPUT             - invalid input parameter
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_rate_stormControlExtMeterIdx_set(rtk_rate_storm_group_t stormType, rtk_uint32 index)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (stormType >= STORM_GROUP_END)
+        return RT_ERR_SFC_UNKNOWN_GROUP;
+
+    if (index > RTK_MAX_METER_ID)
+        return RT_ERR_FILTER_METER_ID;
+
+    switch (stormType)
+    {
+        case STORM_GROUP_UNKNOWN_UNICAST:
+            if ((retVal = rtl8367c_setAsicStormFilterExtUnknownUnicastMeter(index))!=RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_UNKNOWN_MULTICAST:
+            if ((retVal = rtl8367c_setAsicStormFilterExtUnknownMulticastMeter(index))!=RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_MULTICAST:
+            if ((retVal = rtl8367c_setAsicStormFilterExtMulticastMeter(index))!=RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_BROADCAST:
+            if ((retVal = rtl8367c_setAsicStormFilterExtBroadcastMeter(index))!=RT_ERR_OK)
+                return retVal;
+            break;
+        default:
+            break;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_rate_stormControlExtMeterIdx_get
+ * Description:
+ *      Get externsion storm control meter index
+ * Input:
+ *      stormType   - storm group type
+ *      pIndex      - externsion storm control state
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT          - The module is not initial
+ *      RT_ERR_INPUT             - invalid input parameter
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_rate_stormControlExtMeterIdx_get(rtk_rate_storm_group_t stormType, rtk_uint32 *pIndex)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (stormType >= STORM_GROUP_END)
+        return RT_ERR_SFC_UNKNOWN_GROUP;
+
+    if(NULL == pIndex)
+        return RT_ERR_NULL_POINTER;
+
+    switch (stormType)
+    {
+        case STORM_GROUP_UNKNOWN_UNICAST:
+            if ((retVal = rtl8367c_getAsicStormFilterExtUnknownUnicastMeter(pIndex))!=RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_UNKNOWN_MULTICAST:
+            if ((retVal = rtl8367c_getAsicStormFilterExtUnknownMulticastMeter(pIndex))!=RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_MULTICAST:
+            if ((retVal = rtl8367c_getAsicStormFilterExtMulticastMeter(pIndex))!=RT_ERR_OK)
+                return retVal;
+            break;
+        case STORM_GROUP_BROADCAST:
+            if ((retVal = rtl8367c_getAsicStormFilterExtBroadcastMeter(pIndex))!=RT_ERR_OK)
+                return retVal;
+            break;
+        default:
+            break;
+    }
+
+    return RT_ERR_OK;
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/svlan.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/svlan.c
new file mode 100644
index 0000000..bf4ef04
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/svlan.c
@@ -0,0 +1,2415 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in SVLAN module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <svlan.h>
+#include <vlan.h>
+#include <string.h>
+
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_svlan.h>
+
+rtk_uint8               svlan_mbrCfgUsage[RTL8367C_SVIDXNO];
+rtk_uint16              svlan_mbrCfgVid[RTL8367C_SVIDXNO];
+rtk_svlan_lookupType_t  svlan_lookupType;
+/* Function Name:
+ *      rtk_svlan_init
+ * Description:
+ *      Initialize SVLAN Configuration
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      Ether type of S-tag in 802.1ad is 0x88a8 and there are existed ether type 0x9100 and 0x9200 for Q-in-Q SLAN design.
+ *      User can set mathced ether type as service provider supported protocol.
+ */
+rtk_api_ret_t rtk_svlan_init(void)
+{
+    rtk_uint32 i;
+    rtk_api_ret_t retVal;
+    rtl8367c_svlan_memconf_t svlanMemConf;
+    rtl8367c_svlan_s2c_t svlanSP2CConf;
+    rtl8367c_svlan_mc2s_t svlanMC2SConf;
+    rtk_uint32 svidx;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /*default use C-priority*/
+    if ((retVal = rtl8367c_setAsicSvlanPrioritySel(SPRISEL_CTAGPRI)) != RT_ERR_OK)
+        return retVal;
+
+    /*Drop SVLAN untag frame*/
+    if ((retVal = rtl8367c_setAsicSvlanIngressUntag(UNTAG_DROP)) != RT_ERR_OK)
+        return retVal;
+
+    /*Drop SVLAN unmatch frame*/
+    if ((retVal = rtl8367c_setAsicSvlanIngressUnmatch(UNMATCH_DROP)) != RT_ERR_OK)
+        return retVal;
+
+    /*Set TPID to 0x88a8*/
+    if ((retVal = rtl8367c_setAsicSvlanTpid(0x88a8)) != RT_ERR_OK)
+        return retVal;
+
+    /*Clean Uplink Port Mask to none*/
+    if ((retVal = rtl8367c_setAsicSvlanUplinkPortMask(0)) != RT_ERR_OK)
+        return retVal;
+
+    /*Clean SVLAN Member Configuration*/
+    for (i=0; i<= RTL8367C_SVIDXMAX; i++)
+    {
+        memset(&svlanMemConf, 0, sizeof(rtl8367c_svlan_memconf_t));
+        if ((retVal = rtl8367c_setAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    /*Clean C2S Configuration*/
+    for (i=0; i<= RTL8367C_C2SIDXMAX; i++)
+    {
+        if ((retVal = rtl8367c_setAsicSvlanC2SConf(i, 0,0,0)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    /*Clean SP2C Configuration*/
+    for (i=0; i <= RTL8367C_SP2CMAX ; i++)
+    {
+        memset(&svlanSP2CConf, 0, sizeof(rtl8367c_svlan_s2c_t));
+        if ((retVal = rtl8367c_setAsicSvlanSP2CConf(i, &svlanSP2CConf)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    /*Clean MC2S Configuration*/
+    for (i=0 ; i<= RTL8367C_MC2SIDXMAX; i++)
+    {
+        memset(&svlanMC2SConf, 0, sizeof(rtl8367c_svlan_mc2s_t));
+        if ((retVal = rtl8367c_setAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK)
+            return retVal;
+    }
+
+
+    if ((retVal = rtk_svlan_lookupType_set(SVLAN_LOOKUP_S64MBRCGF)) != RT_ERR_OK)
+        return retVal;
+
+
+    for (svidx = 0; svidx <= RTL8367C_SVIDXMAX; svidx++)
+    {
+        svlan_mbrCfgUsage[svidx] = FALSE;
+    }
+
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_svlan_servicePort_add
+ * Description:
+ *      Add one service port in the specified device
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      This API is setting which port is connected to provider switch. All frames receiving from this port must
+ *      contain accept SVID in S-tag field.
+ */
+rtk_api_ret_t rtk_svlan_servicePort_add(rtk_port_t port)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmsk;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if ((retVal = rtl8367c_getAsicSvlanUplinkPortMask(&pmsk)) != RT_ERR_OK)
+        return retVal;
+
+    pmsk = pmsk | (1<<rtk_switch_port_L2P_get(port));
+
+    if ((retVal = rtl8367c_setAsicSvlanUplinkPortMask(pmsk)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_svlan_servicePort_get
+ * Description:
+ *      Get service ports in the specified device.
+ * Input:
+ *      None
+ * Output:
+ *      pSvlan_portmask - pointer buffer of svlan ports.
+ * Return:
+ *      RT_ERR_OK          - OK
+ *      RT_ERR_FAILED      - Failed
+ *      RT_ERR_SMI         - SMI access error
+ * Note:
+ *      This API is setting which port is connected to provider switch. All frames receiving from this port must
+ *      contain accept SVID in S-tag field.
+ */
+rtk_api_ret_t rtk_svlan_servicePort_get(rtk_portmask_t *pSvlan_portmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 phyMbrPmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pSvlan_portmask)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicSvlanUplinkPortMask(&phyMbrPmask)) != RT_ERR_OK)
+        return retVal;
+
+    if(rtk_switch_portmask_P2L_get(phyMbrPmask, pSvlan_portmask) != RT_ERR_OK)
+        return RT_ERR_FAILED;
+
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_svlan_servicePort_del
+ * Description:
+ *      Delete one service port in the specified device
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      This API is removing SVLAN service port in the specified device.
+ */
+rtk_api_ret_t rtk_svlan_servicePort_del(rtk_port_t port)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmsk;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if ((retVal = rtl8367c_getAsicSvlanUplinkPortMask(&pmsk)) != RT_ERR_OK)
+        return retVal;
+
+    pmsk = pmsk & ~(1<<rtk_switch_port_L2P_get(port));
+
+    if ((retVal = rtl8367c_setAsicSvlanUplinkPortMask(pmsk)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_svlan_tpidEntry_set
+ * Description:
+ *      Configure accepted S-VLAN ether type.
+ * Input:
+ *      svlan_tag_id - Ether type of S-tag frame parsing in uplink ports.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ * Note:
+ *      Ether type of S-tag in 802.1ad is 0x88a8 and there are existed ether type 0x9100 and 0x9200 for Q-in-Q SLAN design.
+ *      User can set mathced ether type as service provider supported protocol.
+ */
+rtk_api_ret_t rtk_svlan_tpidEntry_set(rtk_svlan_tpid_t svlan_tag_id)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (svlan_tag_id>RTK_MAX_NUM_OF_PROTO_TYPE)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicSvlanTpid(svlan_tag_id)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_svlan_tpidEntry_get
+ * Description:
+ *      Get accepted S-VLAN ether type setting.
+ * Input:
+ *      None
+ * Output:
+ *      pSvlan_tag_id -  Ether type of S-tag frame parsing in uplink ports.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      This API is setting which port is connected to provider switch. All frames receiving from this port must
+ *      contain accept SVID in S-tag field.
+ */
+rtk_api_ret_t rtk_svlan_tpidEntry_get(rtk_svlan_tpid_t *pSvlan_tag_id)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pSvlan_tag_id)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicSvlanTpid(pSvlan_tag_id)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_svlan_priorityRef_set
+ * Description:
+ *      Set S-VLAN upstream priority reference setting.
+ * Input:
+ *      ref - reference selection parameter.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ * Note:
+ *      The API can set the upstream SVLAN tag priority reference source. The related priority
+ *      sources are as following:
+ *      - REF_INTERNAL_PRI,
+ *      - REF_CTAG_PRI,
+ *      - REF_SVLAN_PRI,
+ *      - REF_PB_PRI.
+ */
+rtk_api_ret_t rtk_svlan_priorityRef_set(rtk_svlan_pri_ref_t ref)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (ref >= REF_PRI_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicSvlanPrioritySel(ref)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_svlan_priorityRef_get
+ * Description:
+ *      Get S-VLAN upstream priority reference setting.
+ * Input:
+ *      None
+ * Output:
+ *      pRef - reference selection parameter.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      The API can get the upstream SVLAN tag priority reference source. The related priority
+ *      sources are as following:
+ *      - REF_INTERNAL_PRI,
+ *      - REF_CTAG_PRI,
+ *      - REF_SVLAN_PRI,
+ *      - REF_PB_PRI
+ */
+rtk_api_ret_t rtk_svlan_priorityRef_get(rtk_svlan_pri_ref_t *pRef)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pRef)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicSvlanPrioritySel(pRef)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_svlan_memberPortEntry_set
+ * Description:
+ *      Configure system SVLAN member content
+ * Input:
+ *      svid - SVLAN id
+ *      psvlan_cfg - SVLAN member configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameter.
+ *      RT_ERR_SVLAN_VID        - Invalid SVLAN VID parameter.
+ *      RT_ERR_PORT_MASK        - Invalid portmask.
+ *      RT_ERR_SVLAN_TABLE_FULL - SVLAN configuration is full.
+ * Note:
+ *      The API can set system 64 accepted s-tag frame format. Only 64 SVID S-tag frame will be accpeted
+ *      to receiving from uplink ports. Other SVID S-tag frame or S-untagged frame will be droped by default setup.
+ *      - rtk_svlan_memberCfg_t->svid is SVID of SVLAN member configuration.
+ *      - rtk_svlan_memberCfg_t->memberport is member port mask of SVLAN member configuration.
+ *      - rtk_svlan_memberCfg_t->fid is filtering database of SVLAN member configuration.
+ *      - rtk_svlan_memberCfg_t->priority is priority of SVLAN member configuration.
+ */
+rtk_api_ret_t rtk_svlan_memberPortEntry_set(rtk_vlan_t svid, rtk_svlan_memberCfg_t *pSvlan_cfg)
+{
+    rtk_api_ret_t retVal;
+    rtk_int32 i;
+    rtk_uint32 empty_idx;
+    rtl8367c_svlan_memconf_t svlanMemConf;
+    rtk_uint32 phyMbrPmask;
+    rtk_vlan_cfg_t vlanCfg;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pSvlan_cfg)
+        return RT_ERR_NULL_POINTER;
+
+    if(svid > RTL8367C_VIDMAX)
+        return RT_ERR_SVLAN_VID;
+
+    RTK_CHK_PORTMASK_VALID(&(pSvlan_cfg->memberport));
+
+    RTK_CHK_PORTMASK_VALID(&(pSvlan_cfg->untagport));
+
+    if (pSvlan_cfg->fiden > ENABLED)
+        return RT_ERR_ENABLE;
+
+    if (pSvlan_cfg->fid > RTL8367C_FIDMAX)
+        return RT_ERR_L2_FID;
+
+    if (pSvlan_cfg->priority > RTL8367C_PRIMAX)
+        return RT_ERR_VLAN_PRIORITY;
+
+    if (pSvlan_cfg->efiden > ENABLED)
+        return RT_ERR_ENABLE;
+
+    if (pSvlan_cfg->efid > RTL8367C_EFIDMAX)
+        return RT_ERR_L2_FID;
+
+    if(SVLAN_LOOKUP_C4KVLAN == svlan_lookupType)
+    {
+        if ((retVal = rtk_vlan_get(svid, &vlanCfg)) != RT_ERR_OK)
+            return retVal;
+
+        vlanCfg.mbr = pSvlan_cfg->memberport;
+        vlanCfg.untag = pSvlan_cfg->untagport;
+
+        if ((retVal = rtk_vlan_set(svid, &vlanCfg)) != RT_ERR_OK)
+            return retVal;
+
+        empty_idx = 0xFF;
+
+        for (i = 0; i<= RTL8367C_SVIDXMAX; i++)
+        {
+            if (svid == svlan_mbrCfgVid[i] && TRUE == svlan_mbrCfgUsage[i])
+            {
+                memset(&svlanMemConf, 0, sizeof(rtl8367c_svlan_memconf_t));
+                svlanMemConf.vs_svid        = svid;
+                svlanMemConf.vs_efiden      = pSvlan_cfg->efiden;
+                svlanMemConf.vs_efid        = pSvlan_cfg->efid;
+                svlanMemConf.vs_priority    = pSvlan_cfg->priority;
+
+                /*for create check*/
+                if(0 == svlanMemConf.vs_efiden && 0 == svlanMemConf.vs_efid)
+                    svlanMemConf.vs_efid = 1;
+
+                if ((retVal = rtl8367c_setAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK)
+                    return retVal;
+
+                return RT_ERR_OK;
+            }
+            else if (FALSE == svlan_mbrCfgUsage[i] && 0xFF == empty_idx)
+            {
+                empty_idx = i;
+            }
+        }
+
+        if (empty_idx != 0xFF)
+        {
+            svlan_mbrCfgUsage[empty_idx] = TRUE;
+            svlan_mbrCfgVid[empty_idx] = svid;
+
+            memset(&svlanMemConf, 0, sizeof(rtl8367c_svlan_memconf_t));
+            svlanMemConf.vs_svid        = svid;
+            svlanMemConf.vs_efiden      = pSvlan_cfg->efiden;
+            svlanMemConf.vs_efid        = pSvlan_cfg->efid;
+            svlanMemConf.vs_priority    = pSvlan_cfg->priority;
+
+            /*for create check*/
+            if(0 == svlanMemConf.vs_efiden && 0 == svlanMemConf.vs_efid)
+                svlanMemConf.vs_efid = 1;
+
+            if ((retVal = rtl8367c_setAsicSvlanMemberConfiguration(empty_idx, &svlanMemConf)) != RT_ERR_OK)
+                return retVal;
+
+        }
+
+        return RT_ERR_OK;
+    }
+
+
+    empty_idx = 0xFF;
+
+    for (i = 0; i<= RTL8367C_SVIDXMAX; i++)
+    {
+        /*
+        if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK)
+            return retVal;
+        */
+        if (svid == svlan_mbrCfgVid[i] && TRUE == svlan_mbrCfgUsage[i])
+        {
+            svlanMemConf.vs_svid = svid;
+
+            if(rtk_switch_portmask_L2P_get(&(pSvlan_cfg->memberport), &phyMbrPmask) != RT_ERR_OK)
+                return RT_ERR_FAILED;
+
+            svlanMemConf.vs_member = phyMbrPmask;
+
+            if(rtk_switch_portmask_L2P_get(&(pSvlan_cfg->untagport), &phyMbrPmask) != RT_ERR_OK)
+                return RT_ERR_FAILED;
+
+            svlanMemConf.vs_untag = phyMbrPmask;
+
+            svlanMemConf.vs_force_fid   = pSvlan_cfg->fiden;
+            svlanMemConf.vs_fid_msti    = pSvlan_cfg->fid;
+            svlanMemConf.vs_priority    = pSvlan_cfg->priority;
+            svlanMemConf.vs_efiden      = pSvlan_cfg->efiden;
+            svlanMemConf.vs_efid        = pSvlan_cfg->efid;
+
+            /*all items are reset means deleting*/
+            if( 0 == svlanMemConf.vs_member &&
+                0 == svlanMemConf.vs_untag &&
+                0 == svlanMemConf.vs_force_fid &&
+                0 == svlanMemConf.vs_fid_msti &&
+                0 == svlanMemConf.vs_priority &&
+                0 == svlanMemConf.vs_efiden &&
+                0 == svlanMemConf.vs_efid)
+            {
+                svlan_mbrCfgUsage[i] = FALSE;
+                svlan_mbrCfgVid[i] = 0;
+
+                /* Clear SVID also */
+                svlanMemConf.vs_svid = 0;
+            }
+            else
+            {
+                svlan_mbrCfgUsage[i] = TRUE;
+                svlan_mbrCfgVid[i] = svlanMemConf.vs_svid;
+
+                if(0 == svlanMemConf.vs_svid)
+                {
+                    /*for create check*/
+                    if(0 == svlanMemConf.vs_efiden && 0 == svlanMemConf.vs_efid)
+                    {
+                        svlanMemConf.vs_efid = 1;
+                    }
+                }
+            }
+
+            if ((retVal = rtl8367c_setAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK)
+                return retVal;
+
+            return RT_ERR_OK;
+        }
+        else if (FALSE == svlan_mbrCfgUsage[i] && 0xFF == empty_idx)
+        {
+            empty_idx = i;
+        }
+    }
+
+    if (empty_idx != 0xFF)
+    {
+        memset(&svlanMemConf, 0, sizeof(rtl8367c_svlan_memconf_t));
+        svlanMemConf.vs_svid = svid;
+
+        if(rtk_switch_portmask_L2P_get(&(pSvlan_cfg->memberport), &phyMbrPmask) != RT_ERR_OK)
+            return RT_ERR_FAILED;
+
+        svlanMemConf.vs_member = phyMbrPmask;
+
+        if(rtk_switch_portmask_L2P_get(&(pSvlan_cfg->untagport), &phyMbrPmask) != RT_ERR_OK)
+            return RT_ERR_FAILED;
+
+        svlanMemConf.vs_untag = phyMbrPmask;
+
+        svlanMemConf.vs_force_fid   = pSvlan_cfg->fiden;
+        svlanMemConf.vs_fid_msti    = pSvlan_cfg->fid;
+        svlanMemConf.vs_priority    = pSvlan_cfg->priority;
+
+        svlanMemConf.vs_efiden      = pSvlan_cfg->efiden;
+        svlanMemConf.vs_efid        = pSvlan_cfg->efid;
+
+        /*change efid for empty svid 0*/
+        if(0 == svlanMemConf.vs_svid)
+        {   /*for create check*/
+            if(0 == svlanMemConf.vs_efiden && 0 == svlanMemConf.vs_efid)
+            {
+                svlanMemConf.vs_efid = 1;
+            }
+        }
+
+        svlan_mbrCfgUsage[empty_idx] = TRUE;
+        svlan_mbrCfgVid[empty_idx] = svlanMemConf.vs_svid;
+
+        if ((retVal = rtl8367c_setAsicSvlanMemberConfiguration(empty_idx, &svlanMemConf)) != RT_ERR_OK)
+        {
+            return retVal;
+        }
+
+        return RT_ERR_OK;
+    }
+
+    return RT_ERR_SVLAN_TABLE_FULL;
+}
+
+/* Function Name:
+ *      rtk_svlan_memberPortEntry_get
+ * Description:
+ *      Get SVLAN member Configure.
+ * Input:
+ *      svid - SVLAN id
+ * Output:
+ *      pSvlan_cfg - SVLAN member configuration
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      The API can get system 64 accepted s-tag frame format. Only 64 SVID S-tag frame will be accpeted
+ *      to receiving from uplink ports. Other SVID S-tag frame or S-untagged frame will be droped.
+ */
+rtk_api_ret_t rtk_svlan_memberPortEntry_get(rtk_vlan_t svid, rtk_svlan_memberCfg_t *pSvlan_cfg)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 i;
+    rtl8367c_svlan_memconf_t svlanMemConf;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pSvlan_cfg)
+        return RT_ERR_NULL_POINTER;
+
+    if (svid > RTL8367C_VIDMAX)
+        return RT_ERR_SVLAN_VID;
+
+
+    for (i = 0; i<= RTL8367C_SVIDXMAX; i++)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK)
+            return retVal;
+
+        if (svid == svlanMemConf.vs_svid)
+        {
+            pSvlan_cfg->svid        = svlanMemConf.vs_svid;
+
+            if(rtk_switch_portmask_P2L_get(svlanMemConf.vs_member,&(pSvlan_cfg->memberport)) != RT_ERR_OK)
+                return RT_ERR_FAILED;
+
+            if(rtk_switch_portmask_P2L_get(svlanMemConf.vs_untag,&(pSvlan_cfg->untagport)) != RT_ERR_OK)
+                return RT_ERR_FAILED;
+
+            pSvlan_cfg->fiden       = svlanMemConf.vs_force_fid;
+            pSvlan_cfg->fid         = svlanMemConf.vs_fid_msti;
+            pSvlan_cfg->priority    = svlanMemConf.vs_priority;
+            pSvlan_cfg->efiden      = svlanMemConf.vs_efiden;
+            pSvlan_cfg->efid        = svlanMemConf.vs_efid;
+
+            return RT_ERR_OK;
+        }
+    }
+
+    return RT_ERR_SVLAN_ENTRY_NOT_FOUND;
+
+}
+
+/* Function Name:
+ *      rtk_svlan_memberPortEntry_adv_set
+ * Description:
+ *      Configure system SVLAN member by index
+ * Input:
+ *      idx         - Index (0 ~ 63)
+ *      psvlan_cfg  - SVLAN member configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameter.
+ *      RT_ERR_SVLAN_VID        - Invalid SVLAN VID parameter.
+ *      RT_ERR_PORT_MASK        - Invalid portmask.
+ *      RT_ERR_SVLAN_TABLE_FULL - SVLAN configuration is full.
+ * Note:
+ *      The API can set system 64 accepted s-tag frame format by index.
+ *      - rtk_svlan_memberCfg_t->svid is SVID of SVLAN member configuration.
+ *      - rtk_svlan_memberCfg_t->memberport is member port mask of SVLAN member configuration.
+ *      - rtk_svlan_memberCfg_t->fid is filtering database of SVLAN member configuration.
+ *      - rtk_svlan_memberCfg_t->priority is priority of SVLAN member configuration.
+ */
+rtk_api_ret_t rtk_svlan_memberPortEntry_adv_set(rtk_uint32 idx, rtk_svlan_memberCfg_t *pSvlan_cfg)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_svlan_memconf_t svlanMemConf;
+    rtk_uint32 phyMbrPmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pSvlan_cfg)
+        return RT_ERR_NULL_POINTER;
+
+    if (idx > RTL8367C_SVIDXMAX)
+        return RT_ERR_SVLAN_ENTRY_INDEX;
+
+    if (pSvlan_cfg->svid>RTL8367C_VIDMAX)
+        return RT_ERR_SVLAN_VID;
+
+    RTK_CHK_PORTMASK_VALID(&(pSvlan_cfg->memberport));
+
+    RTK_CHK_PORTMASK_VALID(&(pSvlan_cfg->untagport));
+
+    if (pSvlan_cfg->fiden > ENABLED)
+        return RT_ERR_ENABLE;
+
+    if (pSvlan_cfg->fid > RTL8367C_FIDMAX)
+        return RT_ERR_L2_FID;
+
+    if (pSvlan_cfg->priority > RTL8367C_PRIMAX)
+        return RT_ERR_VLAN_PRIORITY;
+
+    if (pSvlan_cfg->efiden > ENABLED)
+        return RT_ERR_ENABLE;
+
+    if (pSvlan_cfg->efid > RTL8367C_EFIDMAX)
+        return RT_ERR_L2_FID;
+
+    memset(&svlanMemConf, 0, sizeof(rtl8367c_svlan_memconf_t));
+    svlanMemConf.vs_svid        = pSvlan_cfg->svid;
+    if(rtk_switch_portmask_L2P_get(&(pSvlan_cfg->memberport), &phyMbrPmask) != RT_ERR_OK)
+        return RT_ERR_FAILED;
+
+    svlanMemConf.vs_member = phyMbrPmask;
+
+    if(rtk_switch_portmask_L2P_get(&(pSvlan_cfg->untagport), &phyMbrPmask) != RT_ERR_OK)
+        return RT_ERR_FAILED;
+
+    svlanMemConf.vs_untag = phyMbrPmask;
+
+
+    svlanMemConf.vs_force_fid   = pSvlan_cfg->fiden;
+    svlanMemConf.vs_fid_msti    = pSvlan_cfg->fid;
+    svlanMemConf.vs_priority    = pSvlan_cfg->priority;
+    svlanMemConf.vs_efiden      = pSvlan_cfg->efiden;
+    svlanMemConf.vs_efid        = pSvlan_cfg->efid;
+
+    if(0 == svlanMemConf.vs_svid &&
+        0 == svlanMemConf.vs_member &&
+        0 == svlanMemConf.vs_untag &&
+        0 == svlanMemConf.vs_force_fid &&
+        0 == svlanMemConf.vs_fid_msti &&
+        0 == svlanMemConf.vs_priority &&
+        0 == svlanMemConf.vs_efiden &&
+        0 == svlanMemConf.vs_efid)
+    {
+        svlan_mbrCfgUsage[idx] = FALSE;
+        svlan_mbrCfgVid[idx] = 0;
+    }
+    else
+    {
+        svlan_mbrCfgUsage[idx] = TRUE;
+        svlan_mbrCfgVid[idx] = svlanMemConf.vs_svid;
+    }
+
+    if ((retVal = rtl8367c_setAsicSvlanMemberConfiguration(idx, &svlanMemConf)) != RT_ERR_OK)
+        return retVal;
+
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_svlan_memberPortEntry_adv_get
+ * Description:
+ *      Get SVLAN member Configure by index.
+ * Input:
+ *      idx         - Index (0 ~ 63)
+ * Output:
+ *      pSvlan_cfg  - SVLAN member configuration
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      The API can get system 64 accepted s-tag frame format. Only 64 SVID S-tag frame will be accpeted
+ *      to receiving from uplink ports. Other SVID S-tag frame or S-untagged frame will be droped.
+ */
+rtk_api_ret_t rtk_svlan_memberPortEntry_adv_get(rtk_uint32 idx, rtk_svlan_memberCfg_t *pSvlan_cfg)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_svlan_memconf_t svlanMemConf;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pSvlan_cfg)
+        return RT_ERR_NULL_POINTER;
+
+    if (idx > RTL8367C_SVIDXMAX)
+        return RT_ERR_SVLAN_ENTRY_INDEX;
+
+    if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(idx, &svlanMemConf)) != RT_ERR_OK)
+        return retVal;
+
+    pSvlan_cfg->svid        = svlanMemConf.vs_svid;
+    if(rtk_switch_portmask_P2L_get(svlanMemConf.vs_member,&(pSvlan_cfg->memberport)) != RT_ERR_OK)
+        return RT_ERR_FAILED;
+
+    if(rtk_switch_portmask_P2L_get(svlanMemConf.vs_untag,&(pSvlan_cfg->untagport)) != RT_ERR_OK)
+        return RT_ERR_FAILED;
+
+    pSvlan_cfg->fiden       = svlanMemConf.vs_force_fid;
+    pSvlan_cfg->fid         = svlanMemConf.vs_fid_msti;
+    pSvlan_cfg->priority    = svlanMemConf.vs_priority;
+    pSvlan_cfg->efiden      = svlanMemConf.vs_efiden;
+    pSvlan_cfg->efid        = svlanMemConf.vs_efid;
+
+    return RT_ERR_OK;
+
+}
+
+/* Function Name:
+ *      rtk_svlan_defaultSvlan_set
+ * Description:
+ *      Configure default egress SVLAN.
+ * Input:
+ *      port - Source port
+ *      svid - SVLAN id
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_INPUT                    - Invalid input parameter.
+ *      RT_ERR_SVLAN_VID                - Invalid SVLAN VID parameter.
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ * Note:
+ *      The API can set port n S-tag format index while receiving frame from port n
+ *      is transmit through uplink port with s-tag field
+ */
+rtk_api_ret_t rtk_svlan_defaultSvlan_set(rtk_port_t port, rtk_vlan_t svid)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 i;
+    rtl8367c_svlan_memconf_t svlanMemConf;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    /* svid must be 0~4095 */
+    if (svid > RTL8367C_VIDMAX)
+        return RT_ERR_SVLAN_VID;
+
+    for (i = 0; i < RTL8367C_SVIDXNO; i++)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK)
+            return retVal;
+
+        if (svid == svlanMemConf.vs_svid)
+        {
+            if ((retVal = rtl8367c_setAsicSvlanDefaultVlan(rtk_switch_port_L2P_get(port), i)) != RT_ERR_OK)
+                return retVal;
+
+            return RT_ERR_OK;
+        }
+    }
+
+    return RT_ERR_SVLAN_ENTRY_NOT_FOUND;
+}
+
+/* Function Name:
+ *      rtk_svlan_defaultSvlan_get
+ * Description:
+ *      Get the configure default egress SVLAN.
+ * Input:
+ *      port - Source port
+ * Output:
+ *      pSvid - SVLAN VID
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can get port n S-tag format index while receiving frame from port n
+ *      is transmit through uplink port with s-tag field
+ */
+rtk_api_ret_t rtk_svlan_defaultSvlan_get(rtk_port_t port, rtk_vlan_t *pSvid)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 idx;
+    rtl8367c_svlan_memconf_t svlanMemConf;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pSvid)
+        return RT_ERR_NULL_POINTER;
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if ((retVal = rtl8367c_getAsicSvlanDefaultVlan(rtk_switch_port_L2P_get(port), &idx)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(idx, &svlanMemConf)) != RT_ERR_OK)
+        return retVal;
+
+    *pSvid = svlanMemConf.vs_svid;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_svlan_c2s_add
+ * Description:
+ *      Configure SVLAN C2S table
+ * Input:
+ *      vid - VLAN ID
+ *      src_port - Ingress Port
+ *      svid - SVLAN VID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port ID.
+ *      RT_ERR_SVLAN_VID    - Invalid SVLAN VID parameter.
+ *      RT_ERR_VLAN_VID     - Invalid VID parameter.
+ *      RT_ERR_OUT_OF_RANGE - input out of range.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can set system C2S configuration. ASIC will check upstream's VID and assign related
+ *      SVID to mathed packet. There are 128 SVLAN C2S configurations.
+ */
+rtk_api_ret_t rtk_svlan_c2s_add(rtk_vlan_t vid, rtk_port_t src_port, rtk_vlan_t svid)
+{
+    rtk_api_ret_t retVal, i;
+    rtk_uint32 empty_idx;
+    rtk_uint32 evid, pmsk, svidx, c2s_svidx;
+    rtl8367c_svlan_memconf_t svlanMemConf;
+    rtk_port_t phyPort;
+    rtk_uint16 doneFlag;
+
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+
+    if (vid > RTL8367C_VIDMAX)
+        return RT_ERR_VLAN_VID;
+
+    if (svid > RTL8367C_VIDMAX)
+        return RT_ERR_SVLAN_VID;
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(src_port);
+
+    phyPort = rtk_switch_port_L2P_get(src_port);
+
+    empty_idx = 0xFFFF;
+    svidx = 0xFFFF;
+    doneFlag = FALSE;
+
+    for (i = 0; i<= RTL8367C_SVIDXMAX; i++)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK)
+            return retVal;
+
+        if (svid == svlanMemConf.vs_svid)
+        {
+            svidx = i;
+            break;
+        }
+    }
+
+    if (0xFFFF == svidx)
+        return RT_ERR_SVLAN_VID;
+
+    for (i=RTL8367C_C2SIDXMAX; i>=0; i--)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanC2SConf(i, &evid, &pmsk, &c2s_svidx)) != RT_ERR_OK)
+                return retVal;
+
+        if (evid == vid)
+        {
+            /* Check Src_port */
+            if(pmsk & (1 << phyPort))
+            {
+                /* Check SVIDX */
+                if(c2s_svidx == svidx)
+                {
+                    /* All the same, do nothing */
+                }
+                else
+                {
+                    /* New svidx, remove src_port and find a new slot to add a new enrty */
+                    pmsk = pmsk & ~(1 << phyPort);
+                    if(pmsk == 0)
+                        c2s_svidx = 0;
+
+                    if ((retVal = rtl8367c_setAsicSvlanC2SConf(i, vid, pmsk, c2s_svidx)) != RT_ERR_OK)
+                        return retVal;
+                }
+            }
+            else
+            {
+                if(c2s_svidx == svidx && doneFlag == FALSE)
+                {
+                    pmsk = pmsk | (1 << phyPort);
+                    if ((retVal = rtl8367c_setAsicSvlanC2SConf(i, vid, pmsk, svidx)) != RT_ERR_OK)
+                        return retVal;
+
+                    doneFlag = TRUE;
+                }
+            }
+        }
+        else if (evid==0&&pmsk==0)
+        {
+            empty_idx = i;
+        }
+    }
+
+    if (0xFFFF != empty_idx && doneFlag ==FALSE)
+    {
+       if ((retVal = rtl8367c_setAsicSvlanC2SConf(empty_idx, vid, (1<<phyPort), svidx)) != RT_ERR_OK)
+           return retVal;
+
+       return RT_ERR_OK;
+    }
+    else if(doneFlag == TRUE)
+    {
+        return RT_ERR_OK;
+    }
+
+    return RT_ERR_OUT_OF_RANGE;
+}
+
+/* Function Name:
+ *      rtk_svlan_c2s_del
+ * Description:
+ *      Delete one C2S entry
+ * Input:
+ *      vid - VLAN ID
+ *      src_port - Ingress Port
+ *      svid - SVLAN VID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_VLAN_VID         - Invalid VID parameter.
+ *      RT_ERR_PORT_ID          - Invalid port ID.
+ *      RT_ERR_OUT_OF_RANGE     - input out of range.
+ * Note:
+ *      The API can delete system C2S configuration. There are 128 SVLAN C2S configurations.
+ */
+rtk_api_ret_t rtk_svlan_c2s_del(rtk_vlan_t vid, rtk_port_t src_port)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 i;
+    rtk_uint32 evid, pmsk, svidx;
+    rtk_port_t phyPort;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (vid > RTL8367C_EVIDMAX)
+        return RT_ERR_VLAN_VID;
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(src_port);
+    phyPort = rtk_switch_port_L2P_get(src_port);
+
+    for (i = 0; i <= RTL8367C_C2SIDXMAX; i++)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanC2SConf(i, &evid, &pmsk, &svidx)) != RT_ERR_OK)
+            return retVal;
+
+        if (evid == vid)
+        {
+            if(pmsk & (1 << phyPort))
+            {
+                pmsk = pmsk & ~(1 << phyPort);
+                if(pmsk == 0)
+                {
+                    vid = 0;
+                    svidx = 0;
+                }
+
+                if ((retVal = rtl8367c_setAsicSvlanC2SConf(i, vid, pmsk, svidx)) != RT_ERR_OK)
+                    return retVal;
+
+                return RT_ERR_OK;
+            }
+        }
+    }
+
+    return RT_ERR_OUT_OF_RANGE;
+}
+
+/* Function Name:
+ *      rtk_svlan_c2s_get
+ * Description:
+ *      Get configure SVLAN C2S table
+ * Input:
+ *      vid - VLAN ID
+ *      src_port - Ingress Port
+ * Output:
+ *      pSvid - SVLAN ID
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port ID.
+ *      RT_ERR_OUT_OF_RANGE - input out of range.
+ * Note:
+ *     The API can get system C2S configuration. There are 128 SVLAN C2S configurations.
+ */
+rtk_api_ret_t rtk_svlan_c2s_get(rtk_vlan_t vid, rtk_port_t src_port, rtk_vlan_t *pSvid)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 i;
+    rtk_uint32 evid, pmsk, svidx;
+    rtl8367c_svlan_memconf_t svlanMemConf;
+    rtk_port_t phyPort;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pSvid)
+        return RT_ERR_NULL_POINTER;
+
+    if (vid > RTL8367C_VIDMAX)
+        return RT_ERR_VLAN_VID;
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(src_port);
+    phyPort = rtk_switch_port_L2P_get(src_port);
+
+    for (i = 0; i <= RTL8367C_C2SIDXMAX; i++)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanC2SConf(i, &evid, &pmsk, &svidx)) != RT_ERR_OK)
+            return retVal;
+
+        if (evid == vid)
+        {
+            if(pmsk & (1 << phyPort))
+            {
+                if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(svidx, &svlanMemConf)) != RT_ERR_OK)
+                    return retVal;
+
+                *pSvid = svlanMemConf.vs_svid;
+                return RT_ERR_OK;
+            }
+        }
+    }
+
+    return RT_ERR_OUT_OF_RANGE;
+}
+
+/* Function Name:
+ *      rtk_svlan_untag_action_set
+ * Description:
+ *      Configure Action of downstream UnStag packet
+ * Input:
+ *      action  - Action for UnStag
+ *      svid    - The SVID assigned to UnStag packet
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_SVLAN_VID                - Invalid SVLAN VID parameter.
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ *      RT_ERR_OUT_OF_RANGE             - input out of range.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      The API can configure action of downstream Un-Stag packet. A SVID assigned
+ *      to the un-stag is also supported by this API. The parameter of svid is
+ *      only referenced when the action is set to UNTAG_ASSIGN
+ */
+rtk_api_ret_t rtk_svlan_untag_action_set(rtk_svlan_untag_action_t action, rtk_vlan_t svid)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32      i;
+    rtl8367c_svlan_memconf_t svlanMemConf;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (action >= UNTAG_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if(action == UNTAG_ASSIGN)
+    {
+        if (svid > RTL8367C_VIDMAX)
+            return RT_ERR_SVLAN_VID;
+    }
+
+    if ((retVal = rtl8367c_setAsicSvlanIngressUntag((rtk_uint32)action)) != RT_ERR_OK)
+        return retVal;
+
+    if(action == UNTAG_ASSIGN)
+    {
+        for (i = 0; i < RTL8367C_SVIDXNO; i++)
+        {
+            if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK)
+                return retVal;
+
+            if (svid == svlanMemConf.vs_svid)
+            {
+                if ((retVal = rtl8367c_setAsicSvlanUntagVlan(i)) != RT_ERR_OK)
+                    return retVal;
+
+                return RT_ERR_OK;
+            }
+        }
+
+        return RT_ERR_SVLAN_ENTRY_NOT_FOUND;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_svlan_untag_action_get
+ * Description:
+ *      Get Action of downstream UnStag packet
+ * Input:
+ *      None
+ * Output:
+ *      pAction  - Action for UnStag
+ *      pSvid    - The SVID assigned to UnStag packet
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_SVLAN_VID                - Invalid SVLAN VID parameter.
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ *      RT_ERR_OUT_OF_RANGE             - input out of range.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      The API can Get action of downstream Un-Stag packet. A SVID assigned
+ *      to the un-stag is also retrieved by this API. The parameter pSvid is
+ *      only refernced when the action is UNTAG_ASSIGN
+ */
+rtk_api_ret_t rtk_svlan_untag_action_get(rtk_svlan_untag_action_t *pAction, rtk_vlan_t *pSvid)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32      svidx;
+    rtl8367c_svlan_memconf_t svlanMemConf;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pAction || NULL == pSvid)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicSvlanIngressUntag(pAction)) != RT_ERR_OK)
+        return retVal;
+
+    if(*pAction == UNTAG_ASSIGN)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanUntagVlan(&svidx)) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(svidx, &svlanMemConf)) != RT_ERR_OK)
+            return retVal;
+
+        *pSvid = svlanMemConf.vs_svid;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_svlan_unmatch_action_set
+ * Description:
+ *      Configure Action of downstream Unmatch packet
+ * Input:
+ *      action  - Action for Unmatch
+ *      svid    - The SVID assigned to Unmatch packet
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_SVLAN_VID                - Invalid SVLAN VID parameter.
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ *      RT_ERR_OUT_OF_RANGE             - input out of range.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      The API can configure action of downstream Un-match packet. A SVID assigned
+ *      to the un-match is also supported by this API. The parameter od svid is
+ *      only refernced when the action is set to UNMATCH_ASSIGN
+ */
+rtk_api_ret_t rtk_svlan_unmatch_action_set(rtk_svlan_unmatch_action_t action, rtk_vlan_t svid)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32      i;
+    rtl8367c_svlan_memconf_t svlanMemConf;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (action >= UNMATCH_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if (action == UNMATCH_ASSIGN)
+    {
+        if (svid > RTL8367C_VIDMAX)
+            return RT_ERR_SVLAN_VID;
+    }
+
+    if ((retVal = rtl8367c_setAsicSvlanIngressUnmatch((rtk_uint32)action)) != RT_ERR_OK)
+        return retVal;
+
+    if(action == UNMATCH_ASSIGN)
+    {
+        for (i = 0; i < RTL8367C_SVIDXNO; i++)
+        {
+            if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK)
+                return retVal;
+
+            if (svid == svlanMemConf.vs_svid)
+            {
+                if ((retVal = rtl8367c_setAsicSvlanUnmatchVlan(i)) != RT_ERR_OK)
+                    return retVal;
+
+                return RT_ERR_OK;
+            }
+        }
+
+        return RT_ERR_SVLAN_ENTRY_NOT_FOUND;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_svlan_unmatch_action_get
+ * Description:
+ *      Get Action of downstream Unmatch packet
+ * Input:
+ *      None
+ * Output:
+ *      pAction  - Action for Unmatch
+ *      pSvid    - The SVID assigned to Unmatch packet
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_SVLAN_VID                - Invalid SVLAN VID parameter.
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ *      RT_ERR_OUT_OF_RANGE             - input out of range.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      The API can Get action of downstream Un-match packet. A SVID assigned
+ *      to the un-match is also retrieved by this API. The parameter pSvid is
+ *      only refernced when the action is UNMATCH_ASSIGN
+ */
+rtk_api_ret_t rtk_svlan_unmatch_action_get(rtk_svlan_unmatch_action_t *pAction, rtk_vlan_t *pSvid)
+{
+    rtk_api_ret_t   retVal;
+    rtk_uint32      svidx;
+    rtl8367c_svlan_memconf_t svlanMemConf;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pAction || NULL == pSvid)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicSvlanIngressUnmatch(pAction)) != RT_ERR_OK)
+        return retVal;
+
+    if(*pAction == UNMATCH_ASSIGN)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanUnmatchVlan(&svidx)) != RT_ERR_OK)
+            return retVal;
+
+        if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(svidx, &svlanMemConf)) != RT_ERR_OK)
+            return retVal;
+
+        *pSvid = svlanMemConf.vs_svid;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_svlan_unassign_action_set
+ * Description:
+ *      Configure Action of upstream without svid assign action
+ * Input:
+ *      action  - Action for Un-assign
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_OUT_OF_RANGE             - input out of range.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      The API can configure action of upstream Un-assign svid packet. If action is not
+ *      trap to CPU, the port-based SVID sure be assign as system need
+ */
+rtk_api_ret_t rtk_svlan_unassign_action_set(rtk_svlan_unassign_action_t action)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (action >= UNASSIGN_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_setAsicSvlanEgressUnassign((rtk_uint32)action);
+
+    return retVal;
+}
+
+/* Function Name:
+ *      rtk_svlan_unassign_action_get
+ * Description:
+ *      Get action of upstream without svid assignment
+ * Input:
+ *      None
+ * Output:
+ *      pAction  - Action for Un-assign
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_svlan_unassign_action_get(rtk_svlan_unassign_action_t *pAction)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pAction)
+        return RT_ERR_NULL_POINTER;
+
+    retVal = rtl8367c_getAsicSvlanEgressUnassign(pAction);
+
+    return retVal;
+}
+
+/* Function Name:
+ *      rtk_svlan_dmac_vidsel_set
+ * Description:
+ *      Set DMAC CVID selection
+ * Input:
+ *      port    - Port
+ *      enable  - state of DMAC CVID Selection
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_SVLAN_VID                - Invalid SVLAN VID parameter.
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ *      RT_ERR_OUT_OF_RANGE             - input out of range.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      This API can set DMAC CVID Selection state
+ */
+rtk_api_ret_t rtk_svlan_dmac_vidsel_set(rtk_port_t port, rtk_enable_t enable)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (enable >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if ((retVal = rtl8367c_setAsicSvlanDmacCvidSel(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK)
+            return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_svlan_dmac_vidsel_get
+ * Description:
+ *      Get DMAC CVID selection
+ * Input:
+ *      port    - Port
+ * Output:
+ *      pEnable - state of DMAC CVID Selection
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_SVLAN_VID                - Invalid SVLAN VID parameter.
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ *      RT_ERR_OUT_OF_RANGE             - input out of range.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      This API can get DMAC CVID Selection state
+ */
+rtk_api_ret_t rtk_svlan_dmac_vidsel_get(rtk_port_t port, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if ((retVal = rtl8367c_getAsicSvlanDmacCvidSel(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK)
+            return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_svlan_ipmc2s_add
+ * Description:
+ *      add ip multicast address to SVLAN
+ * Input:
+ *      svid    - SVLAN VID
+ *      ipmc    - ip multicast address
+ *      ipmcMsk - ip multicast mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_SVLAN_VID                - Invalid SVLAN VID parameter.
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ *      RT_ERR_OUT_OF_RANGE             - input out of range.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      The API can set IP mutlicast to SVID configuration. If upstream packet is IPv4 multicast
+ *      packet and DIP is matched MC2S configuration, ASIC will assign egress SVID to the packet.
+ *      There are 32 SVLAN multicast configurations for IP and L2 multicast.
+ */
+rtk_api_ret_t rtk_svlan_ipmc2s_add(ipaddr_t ipmc, ipaddr_t ipmcMsk,rtk_vlan_t svid)
+{
+    rtk_api_ret_t retVal, i;
+    rtk_uint32 empty_idx;
+    rtk_uint32 svidx;
+    rtl8367c_svlan_memconf_t svlanMemConf;
+    rtl8367c_svlan_mc2s_t svlanMC2SConf;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (svid > RTL8367C_VIDMAX)
+        return RT_ERR_SVLAN_VID;
+
+    if ((ipmc&0xF0000000)!=0xE0000000)
+        return RT_ERR_INPUT;
+
+    svidx = 0xFFFF;
+
+    for (i = 0; i < RTL8367C_SVIDXNO; i++)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK)
+            return retVal;
+
+        if (svid == svlanMemConf.vs_svid)
+        {
+            svidx = i;
+            break;
+        }
+    }
+
+    if (0xFFFF == svidx)
+            return RT_ERR_SVLAN_ENTRY_NOT_FOUND;
+
+
+    empty_idx = 0xFFFF;
+
+    for (i = RTL8367C_MC2SIDXMAX; i >= 0; i--)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK)
+            return retVal;
+
+        if (TRUE == svlanMC2SConf.valid)
+        {
+            if (svlanMC2SConf.format == SVLAN_MC2S_MODE_IP &&
+                svlanMC2SConf.sdata==ipmc&&
+                svlanMC2SConf.smask==ipmcMsk)
+            {
+                svlanMC2SConf.svidx = svidx;
+                if ((retVal = rtl8367c_setAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK)
+                    return retVal;
+            }
+        }
+        else
+        {
+            empty_idx = i;
+        }
+    }
+
+    if (empty_idx!=0xFFFF)
+    {
+        svlanMC2SConf.valid = TRUE;
+        svlanMC2SConf.svidx = svidx;
+        svlanMC2SConf.format = SVLAN_MC2S_MODE_IP;
+        svlanMC2SConf.sdata = ipmc;
+        svlanMC2SConf.smask = ipmcMsk;
+        if ((retVal = rtl8367c_setAsicSvlanMC2SConf(empty_idx, &svlanMC2SConf)) != RT_ERR_OK)
+            return retVal;
+        return RT_ERR_OK;
+    }
+
+    return RT_ERR_OUT_OF_RANGE;
+
+}
+
+/* Function Name:
+ *      rtk_svlan_ipmc2s_del
+ * Description:
+ *      delete ip multicast address to SVLAN
+ * Input:
+ *      ipmc    - ip multicast address
+ *      ipmcMsk - ip multicast mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_SVLAN_VID        - Invalid SVLAN VID parameter.
+ *      RT_ERR_OUT_OF_RANGE     - input out of range.
+ * Note:
+ *      The API can delete IP mutlicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast.
+ */
+rtk_api_ret_t rtk_svlan_ipmc2s_del(ipaddr_t ipmc, ipaddr_t ipmcMsk)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 i;
+    rtl8367c_svlan_mc2s_t svlanMC2SConf;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((ipmc&0xF0000000)!=0xE0000000)
+        return RT_ERR_INPUT;
+
+    for (i = 0; i <= RTL8367C_MC2SIDXMAX; i++)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK)
+            return retVal;
+
+        if (TRUE == svlanMC2SConf.valid)
+        {
+            if (svlanMC2SConf.format == SVLAN_MC2S_MODE_IP &&
+                svlanMC2SConf.sdata==ipmc&&
+                svlanMC2SConf.smask==ipmcMsk)
+            {
+                memset(&svlanMC2SConf, 0, sizeof(rtl8367c_svlan_mc2s_t));
+                if ((retVal = rtl8367c_setAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK)
+                    return retVal;
+                return RT_ERR_OK;
+            }
+        }
+    }
+
+    return RT_ERR_OUT_OF_RANGE;
+}
+
+/* Function Name:
+ *      rtk_svlan_ipmc2s_get
+ * Description:
+ *      Get ip multicast address to SVLAN
+ * Input:
+ *      ipmc    - ip multicast address
+ *      ipmcMsk - ip multicast mask
+ * Output:
+ *      pSvid - SVLAN VID
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_OUT_OF_RANGE - input out of range.
+ * Note:
+ *      The API can get IP mutlicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast.
+ */
+rtk_api_ret_t rtk_svlan_ipmc2s_get(ipaddr_t ipmc, ipaddr_t ipmcMsk, rtk_vlan_t *pSvid)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 i;
+    rtl8367c_svlan_memconf_t svlanMemConf;
+    rtl8367c_svlan_mc2s_t svlanMC2SConf;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pSvid)
+        return RT_ERR_NULL_POINTER;
+
+    if ((ipmc&0xF0000000)!=0xE0000000)
+        return RT_ERR_INPUT;
+
+    for (i = 0; i <= RTL8367C_MC2SIDXMAX; i++)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK)
+            return retVal;
+
+        if (TRUE == svlanMC2SConf.valid &&
+            svlanMC2SConf.format == SVLAN_MC2S_MODE_IP &&
+            svlanMC2SConf.sdata == ipmc &&
+            svlanMC2SConf.smask == ipmcMsk)
+        {
+            if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(svlanMC2SConf.svidx, &svlanMemConf)) != RT_ERR_OK)
+                return retVal;
+            *pSvid = svlanMemConf.vs_svid;
+            return RT_ERR_OK;
+        }
+    }
+
+    return RT_ERR_OUT_OF_RANGE;
+}
+
+/* Function Name:
+ *      rtk_svlan_l2mc2s_add
+ * Description:
+ *      Add L2 multicast address to SVLAN
+ * Input:
+ *      mac     - L2 multicast address
+ *      macMsk  - L2 multicast address mask
+ *      svid    - SVLAN VID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_SVLAN_VID                - Invalid SVLAN VID parameter.
+ *      RT_ERR_SVLAN_ENTRY_NOT_FOUND    - specified svlan entry not found.
+ *      RT_ERR_OUT_OF_RANGE             - input out of range.
+ *      RT_ERR_INPUT                    - Invalid input parameters.
+ * Note:
+ *      The API can set L2 Mutlicast to SVID configuration. If upstream packet is L2 multicast
+ *      packet and DMAC is matched, ASIC will assign egress SVID to the packet. There are 32
+ *      SVLAN multicast configurations for IP and L2 multicast.
+ */
+rtk_api_ret_t rtk_svlan_l2mc2s_add(rtk_mac_t mac, rtk_mac_t macMsk, rtk_vlan_t svid)
+{
+    rtk_api_ret_t retVal, i;
+    rtk_uint32 empty_idx;
+    rtk_uint32 svidx, l2add, l2Mask;
+    rtl8367c_svlan_memconf_t svlanMemConf;
+    rtl8367c_svlan_mc2s_t svlanMC2SConf;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (svid > RTL8367C_VIDMAX)
+        return RT_ERR_SVLAN_VID;
+
+    if (mac.octet[0]!= 1&&mac.octet[1]!=0)
+        return RT_ERR_INPUT;
+
+    l2add = (mac.octet[2] << 24) | (mac.octet[3] << 16) | (mac.octet[4] << 8) | mac.octet[5];
+    l2Mask = (macMsk.octet[2] << 24) | (macMsk.octet[3] << 16) | (macMsk.octet[4] << 8) | macMsk.octet[5];
+
+    svidx = 0xFFFF;
+
+    for (i = 0; i < RTL8367C_SVIDXNO; i++)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK)
+            return retVal;
+
+        if (svid == svlanMemConf.vs_svid)
+        {
+            svidx = i;
+            break;
+        }
+    }
+
+    if (0xFFFF == svidx)
+        return RT_ERR_SVLAN_ENTRY_NOT_FOUND;
+
+    empty_idx = 0xFFFF;
+
+    for (i = RTL8367C_MC2SIDXMAX; i >=0; i--)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK)
+            return retVal;
+
+        if (TRUE == svlanMC2SConf.valid)
+        {
+            if (svlanMC2SConf.format == SVLAN_MC2S_MODE_MAC &&
+                svlanMC2SConf.sdata==l2add&&
+                svlanMC2SConf.smask==l2Mask)
+            {
+                svlanMC2SConf.svidx = svidx;
+                if ((retVal = rtl8367c_setAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK)
+                    return retVal;
+            }
+        }
+        else
+        {
+            empty_idx = i;
+        }
+    }
+
+    if (empty_idx!=0xFFFF)
+    {
+        svlanMC2SConf.valid = TRUE;
+        svlanMC2SConf.svidx = svidx;
+        svlanMC2SConf.format = SVLAN_MC2S_MODE_MAC;
+        svlanMC2SConf.sdata = l2add;
+        svlanMC2SConf.smask = l2Mask;
+
+        if ((retVal = rtl8367c_setAsicSvlanMC2SConf(empty_idx, &svlanMC2SConf)) != RT_ERR_OK)
+            return retVal;
+        return RT_ERR_OK;
+    }
+
+    return RT_ERR_OUT_OF_RANGE;
+}
+
+/* Function Name:
+ *      rtk_svlan_l2mc2s_del
+ * Description:
+ *      delete L2 multicast address to SVLAN
+ * Input:
+ *      mac     - L2 multicast address
+ *      macMsk  - L2 multicast address mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_SVLAN_VID        - Invalid SVLAN VID parameter.
+ *      RT_ERR_OUT_OF_RANGE     - input out of range.
+ * Note:
+ *      The API can delete Mutlicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast.
+ */
+rtk_api_ret_t rtk_svlan_l2mc2s_del(rtk_mac_t mac, rtk_mac_t macMsk)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 i;
+    rtk_uint32 l2add, l2Mask;
+    rtl8367c_svlan_mc2s_t svlanMC2SConf;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (mac.octet[0]!= 1&&mac.octet[1]!=0)
+        return RT_ERR_INPUT;
+
+    l2add = (mac.octet[2] << 24) | (mac.octet[3] << 16) | (mac.octet[4] << 8) | mac.octet[5];
+    l2Mask = (macMsk.octet[2] << 24) | (macMsk.octet[3] << 16) | (macMsk.octet[4] << 8) | macMsk.octet[5];
+
+    for (i = 0; i <= RTL8367C_MC2SIDXMAX; i++)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK)
+            return retVal;
+
+        if (TRUE == svlanMC2SConf.valid)
+        {
+            if (svlanMC2SConf.format == SVLAN_MC2S_MODE_MAC &&
+                svlanMC2SConf.sdata==l2add&&
+                svlanMC2SConf.smask==l2Mask)
+            {
+                memset(&svlanMC2SConf, 0, sizeof(rtl8367c_svlan_mc2s_t));
+                if ((retVal = rtl8367c_setAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK)
+                    return retVal;
+                return RT_ERR_OK;
+            }
+        }
+    }
+
+    return RT_ERR_OUT_OF_RANGE;
+}
+
+/* Function Name:
+ *      rtk_svlan_l2mc2s_get
+ * Description:
+ *      Get L2 multicast address to SVLAN
+ * Input:
+ *      mac     - L2 multicast address
+ *      macMsk  - L2 multicast address mask
+ * Output:
+ *      pSvid - SVLAN VID
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_INPUT            - Invalid input parameters.
+ *      RT_ERR_OUT_OF_RANGE     - input out of range.
+ * Note:
+ *      The API can get L2 mutlicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast.
+ */
+rtk_api_ret_t rtk_svlan_l2mc2s_get(rtk_mac_t mac, rtk_mac_t macMsk, rtk_vlan_t *pSvid)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 i;
+    rtk_uint32 l2add,l2Mask;
+    rtl8367c_svlan_memconf_t svlanMemConf;
+    rtl8367c_svlan_mc2s_t svlanMC2SConf;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pSvid)
+        return RT_ERR_NULL_POINTER;
+
+    if (mac.octet[0]!= 1&&mac.octet[1]!=0)
+        return RT_ERR_INPUT;
+
+    l2add = (mac.octet[2] << 24) | (mac.octet[3] << 16) | (mac.octet[4] << 8) | mac.octet[5];
+    l2Mask = (macMsk.octet[2] << 24) | (macMsk.octet[3] << 16) | (macMsk.octet[4] << 8) | macMsk.octet[5];
+
+    for (i = 0; i <= RTL8367C_MC2SIDXMAX; i++)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK)
+            return retVal;
+
+        if (TRUE == svlanMC2SConf.valid)
+        {
+            if (svlanMC2SConf.format == SVLAN_MC2S_MODE_MAC &&
+                svlanMC2SConf.sdata==l2add&&
+                svlanMC2SConf.smask==l2Mask)
+            {
+                if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(svlanMC2SConf.svidx, &svlanMemConf)) != RT_ERR_OK)
+                    return retVal;
+                *pSvid = svlanMemConf.vs_svid;
+
+                return RT_ERR_OK;
+            }
+        }
+    }
+
+    return RT_ERR_OUT_OF_RANGE;
+}
+
+/* Function Name:
+ *      rtk_svlan_sp2c_add
+ * Description:
+ *      Add system SP2C configuration
+ * Input:
+ *      cvid        - VLAN ID
+ *      dst_port    - Destination port of SVLAN to CVLAN configuration
+ *      svid        - SVLAN VID
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_SVLAN_VID    - Invalid SVLAN VID parameter.
+ *      RT_ERR_VLAN_VID     - Invalid VID parameter.
+ *      RT_ERR_OUT_OF_RANGE - input out of range.
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      The API can add SVID & Destination Port to CVLAN configuration. The downstream frames with assigned
+ *      SVID will be add C-tag with assigned CVID if the output port is the assigned destination port.
+ *      There are 128 SP2C configurations.
+ */
+rtk_api_ret_t rtk_svlan_sp2c_add(rtk_vlan_t svid, rtk_port_t dst_port, rtk_vlan_t cvid)
+{
+    rtk_api_ret_t retVal, i;
+    rtk_uint32 empty_idx, svidx;
+    rtl8367c_svlan_memconf_t svlanMemConf;
+    rtl8367c_svlan_s2c_t svlanSP2CConf;
+    rtk_port_t port;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (svid > RTL8367C_VIDMAX)
+        return RT_ERR_SVLAN_VID;
+
+    if (cvid > RTL8367C_VIDMAX)
+        return RT_ERR_VLAN_VID;
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(dst_port);
+    port = rtk_switch_port_L2P_get(dst_port);
+
+    svidx = 0xFFFF;
+
+    for (i = 0; i < RTL8367C_SVIDXNO; i++)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK)
+            return retVal;
+
+        if (svid == svlanMemConf.vs_svid)
+        {
+            svidx = i;
+            break;
+        }
+    }
+
+    if (0xFFFF == svidx)
+        return RT_ERR_SVLAN_ENTRY_NOT_FOUND;
+
+    empty_idx = 0xFFFF;
+
+    for (i=RTL8367C_SP2CMAX; i >=0 ; i--)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanSP2CConf(i, &svlanSP2CConf)) != RT_ERR_OK)
+            return retVal;
+
+        if ( (svlanSP2CConf.svidx == svidx) && (svlanSP2CConf.dstport == port) && (svlanSP2CConf.valid == 1))
+        {
+            empty_idx = i;
+            break;
+        }
+        else if (svlanSP2CConf.valid == 0)
+        {
+            empty_idx = i;
+        }
+    }
+
+    if (empty_idx!=0xFFFF)
+    {
+        svlanSP2CConf.valid     = 1;
+        svlanSP2CConf.vid       = cvid;
+        svlanSP2CConf.svidx     = svidx;
+        svlanSP2CConf.dstport   = port;
+
+        if ((retVal = rtl8367c_setAsicSvlanSP2CConf(empty_idx, &svlanSP2CConf)) != RT_ERR_OK)
+            return retVal;
+        return RT_ERR_OK;
+    }
+
+    return RT_ERR_OUT_OF_RANGE;
+
+}
+
+/* Function Name:
+ *      rtk_svlan_sp2c_get
+ * Description:
+ *      Get configure system SP2C content
+ * Input:
+ *      svid        - SVLAN VID
+ *      dst_port    - Destination port of SVLAN to CVLAN configuration
+ * Output:
+ *      pCvid - VLAN ID
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_OUT_OF_RANGE - input out of range.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_SVLAN_VID    - Invalid SVLAN VID parameter.
+ * Note:
+ *     The API can get SVID & Destination Port to CVLAN configuration. There are 128 SP2C configurations.
+ */
+rtk_api_ret_t rtk_svlan_sp2c_get(rtk_vlan_t svid, rtk_port_t dst_port, rtk_vlan_t *pCvid)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 i, svidx;
+    rtl8367c_svlan_memconf_t svlanMemConf;
+    rtl8367c_svlan_s2c_t svlanSP2CConf;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pCvid)
+        return RT_ERR_NULL_POINTER;
+
+    if (svid > RTL8367C_VIDMAX)
+        return RT_ERR_SVLAN_VID;
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(dst_port);
+    dst_port = rtk_switch_port_L2P_get(dst_port);
+
+    svidx = 0xFFFF;
+
+    for (i = 0; i < RTL8367C_SVIDXNO; i++)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK)
+            return retVal;
+
+        if (svid == svlanMemConf.vs_svid)
+        {
+            svidx = i;
+            break;
+        }
+    }
+
+    if (0xFFFF == svidx)
+        return RT_ERR_SVLAN_ENTRY_NOT_FOUND;
+
+    for (i = 0; i <= RTL8367C_SP2CMAX; i++)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanSP2CConf(i, &svlanSP2CConf)) != RT_ERR_OK)
+            return retVal;
+
+        if ( (svlanSP2CConf.svidx == svidx) && (svlanSP2CConf.dstport == dst_port) && (svlanSP2CConf.valid == 1) )
+        {
+            *pCvid = svlanSP2CConf.vid;
+            return RT_ERR_OK;
+        }
+    }
+
+    return RT_ERR_OUT_OF_RANGE;
+}
+
+/* Function Name:
+ *      rtk_svlan_sp2c_del
+ * Description:
+ *      Delete system SP2C configuration
+ * Input:
+ *      svid        - SVLAN VID
+ *      dst_port    - Destination port of SVLAN to CVLAN configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_SVLAN_VID    - Invalid SVLAN VID parameter.
+ *      RT_ERR_OUT_OF_RANGE - input out of range.
+ * Note:
+ *      The API can delete SVID & Destination Port to CVLAN configuration. There are 128 SP2C configurations.
+ */
+rtk_api_ret_t rtk_svlan_sp2c_del(rtk_vlan_t svid, rtk_port_t dst_port)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 i, svidx;
+    rtl8367c_svlan_memconf_t svlanMemConf;
+    rtl8367c_svlan_s2c_t svlanSP2CConf;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (svid > RTL8367C_VIDMAX)
+        return RT_ERR_SVLAN_VID;
+
+    /* Check port Valid */
+    RTK_CHK_PORT_VALID(dst_port);
+    dst_port = rtk_switch_port_L2P_get(dst_port);
+
+    svidx = 0xFFFF;
+
+    for (i = 0; i < RTL8367C_SVIDXNO; i++)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK)
+            return retVal;
+
+        if (svid == svlanMemConf.vs_svid)
+        {
+            svidx = i;
+            break;
+        }
+    }
+
+    if (0xFFFF == svidx)
+        return RT_ERR_SVLAN_ENTRY_NOT_FOUND;
+
+    for (i = 0; i <= RTL8367C_SP2CMAX; i++)
+    {
+        if ((retVal = rtl8367c_getAsicSvlanSP2CConf(i, &svlanSP2CConf)) != RT_ERR_OK)
+            return retVal;
+
+        if ( (svlanSP2CConf.svidx == svidx) && (svlanSP2CConf.dstport == dst_port) && (svlanSP2CConf.valid == 1) )
+        {
+            svlanSP2CConf.valid     = 0;
+            svlanSP2CConf.vid       = 0;
+            svlanSP2CConf.svidx     = 0;
+            svlanSP2CConf.dstport   = 0;
+
+            if ((retVal = rtl8367c_setAsicSvlanSP2CConf(i, &svlanSP2CConf)) != RT_ERR_OK)
+                return retVal;
+            return RT_ERR_OK;
+        }
+
+    }
+
+    return RT_ERR_OUT_OF_RANGE;
+}
+
+/* Function Name:
+ *      rtk_svlan_lookupType_set
+ * Description:
+ *      Set lookup type of SVLAN
+ * Input:
+ *      type        - lookup type
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ * Note:
+ *      none
+ */
+rtk_api_ret_t rtk_svlan_lookupType_set(rtk_svlan_lookupType_t type)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (type >= SVLAN_LOOKUP_END)
+        return RT_ERR_CHIP_NOT_SUPPORTED;
+
+
+    svlan_lookupType = type;
+
+    retVal = rtl8367c_setAsicSvlanLookupType((rtk_uint32)type);
+
+    return retVal;
+}
+
+/* Function Name:
+ *      rtk_svlan_lookupType_get
+ * Description:
+ *      Get lookup type of SVLAN
+ * Input:
+ *      pType       - lookup type
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ * Note:
+ *      none
+ */
+rtk_api_ret_t rtk_svlan_lookupType_get(rtk_svlan_lookupType_t *pType)
+{
+    rtk_api_ret_t   retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pType)
+        return RT_ERR_NULL_POINTER;
+
+    retVal = rtl8367c_getAsicSvlanLookupType(pType);
+
+    svlan_lookupType = *pType;
+
+    return retVal;
+}
+
+/* Function Name:
+ *      rtk_svlan_trapPri_set
+ * Description:
+ *      Set svlan trap priority
+ * Input:
+ *      priority - priority for trap packets
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_QOS_INT_PRIORITY
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_svlan_trapPri_set(rtk_pri_t priority)
+{
+    rtk_api_ret_t   retVal;
+
+    RTK_CHK_INIT_STATE();
+
+    if(priority > RTL8367C_PRIMAX)
+        return RT_ERR_OUT_OF_RANGE;
+
+    retVal = rtl8367c_setAsicSvlanTrapPriority(priority);
+
+    return retVal;
+}   /* end of rtk_svlan_trapPri_set */
+
+/* Function Name:
+ *      rtk_svlan_trapPri_get
+ * Description:
+ *      Get svlan trap priority
+ * Input:
+ *      None
+ * Output:
+ *      pPriority - priority for trap packets
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Note:
+ *      None
+ */
+rtk_api_ret_t rtk_svlan_trapPri_get(rtk_pri_t *pPriority)
+{
+    rtk_api_ret_t   retVal;
+
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pPriority)
+        return RT_ERR_NULL_POINTER;
+
+    retVal = rtl8367c_getAsicSvlanTrapPriority(pPriority);
+
+    return retVal;
+}   /* end of rtk_svlan_trapPri_get */
+
+
+/* Function Name:
+ *      rtk_svlan_checkAndCreateMbr
+ * Description:
+ *      Check and create Member configuration and return index
+ * Input:
+ *      vid  - VLAN id.
+ * Output:
+ *      pIndex  - Member configuration index
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_VLAN_VID     - Invalid VLAN ID.
+ *      RT_ERR_TBL_FULL     - Member Configuration table full
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_svlan_checkAndCreateMbr(rtk_vlan_t vid, rtk_uint32 *pIndex)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 svidx;
+    rtk_uint32 empty_idx = 0xFFFF;
+    rtl8367c_svlan_memconf_t svlan_cfg;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* vid must be 0~4095 */
+    if (vid > RTL8367C_VIDMAX)
+        return RT_ERR_VLAN_VID;
+
+    /* Null pointer check */
+    if(NULL == pIndex)
+        return RT_ERR_NULL_POINTER;
+
+    /* Search exist entry */
+    for (svidx = 0; svidx <= RTL8367C_SVIDXMAX; svidx++)
+    {
+        if(svlan_mbrCfgUsage[svidx] == TRUE)
+        {
+            if(svlan_mbrCfgVid[svidx] == vid)
+            {
+                /* Found! return index */
+                *pIndex = svidx;
+                return RT_ERR_OK;
+            }
+        }
+        else if(empty_idx == 0xFFFF)
+        {
+            empty_idx = svidx;
+        }
+
+    }
+
+    if(empty_idx == 0xFFFF)
+    {
+        /* No empty index */
+        return RT_ERR_TBL_FULL;
+    }
+
+    svlan_mbrCfgUsage[empty_idx] = TRUE;
+    svlan_mbrCfgVid[empty_idx] = vid;
+
+    memset(&svlan_cfg, 0, sizeof(rtl8367c_svlan_memconf_t));
+
+    svlan_cfg.vs_svid = vid;
+    /*for create check*/
+    if(vid == 0)
+    {
+        svlan_cfg.vs_efid = 1;
+    }
+
+    if((retVal = rtl8367c_setAsicSvlanMemberConfiguration(empty_idx, &svlan_cfg)) != RT_ERR_OK)
+        return retVal;
+
+    *pIndex = empty_idx;
+    return RT_ERR_OK;
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/trap.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/trap.c
new file mode 100644
index 0000000..af96610
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/trap.c
@@ -0,0 +1,1229 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in Trap module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <trap.h>
+#include <string.h>
+
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_port.h>
+#include <rtl8367c_asicdrv_igmp.h>
+#include <rtl8367c_asicdrv_rma.h>
+#include <rtl8367c_asicdrv_eav.h>
+#include <rtl8367c_asicdrv_oam.h>
+#include <rtl8367c_asicdrv_svlan.h>
+#include <rtl8367c_asicdrv_unknownMulticast.h>
+#include <rtl8367c_asicdrv_dot1x.h>
+
+/* Function Name:
+ *      rtk_trap_unknownUnicastPktAction_set
+ * Description:
+ *      Set unknown unicast packet action configuration.
+ * Input:
+ *      port            - ingress port ID for unknown unicast packet
+ *      ucast_action    - Unknown unicast action.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                  - OK
+ *      RT_ERR_FAILED              - Failed
+ *      RT_ERR_SMI                 - SMI access error
+ *      RT_ERR_NOT_ALLOWED         - Invalid action.
+ *      RT_ERR_INPUT               - Invalid input parameters.
+ * Note:
+ *      This API can set unknown unicast packet action configuration.
+ *      The unknown unicast action is as following:
+ *          - UCAST_ACTION_FORWARD_PMASK
+ *          - UCAST_ACTION_DROP
+ *          - UCAST_ACTION_TRAP2CPU
+ *          - UCAST_ACTION_FLOODING
+ */
+rtk_api_ret_t rtk_trap_unknownUnicastPktAction_set(rtk_port_t port, rtk_trap_ucast_action_t ucast_action)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (ucast_action >= UCAST_ACTION_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicPortUnknownDaBehavior(rtk_switch_port_L2P_get(port), ucast_action)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trap_unknownUnicastPktAction_get
+ * Description:
+ *      Get unknown unicast packet action configuration.
+ * Input:
+ *      port            - ingress port ID for unknown unicast packet
+ * Output:
+ *      pUcast_action   - Unknown unicast action.
+ * Return:
+ *      RT_ERR_OK                  - OK
+ *      RT_ERR_FAILED              - Failed
+ *      RT_ERR_SMI                 - SMI access error
+ *      RT_ERR_NOT_ALLOWED         - Invalid action.
+ *      RT_ERR_INPUT               - Invalid input parameters.
+ *      RT_ERR_NULL_POINTER        - Null pointer
+ * Note:
+ *      This API can get unknown unicast packet action configuration.
+ *      The unknown unicast action is as following:
+ *          - UCAST_ACTION_FORWARD_PMASK
+ *          - UCAST_ACTION_DROP
+ *          - UCAST_ACTION_TRAP2CPU
+ *          - UCAST_ACTION_FLOODING
+ */
+rtk_api_ret_t rtk_trap_unknownUnicastPktAction_get(rtk_port_t port, rtk_trap_ucast_action_t *pUcast_action)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (NULL == pUcast_action)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicPortUnknownDaBehavior(rtk_switch_port_L2P_get(port), pUcast_action)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trap_unknownMacPktAction_set
+ * Description:
+ *      Set unknown source MAC packet action configuration.
+ * Input:
+ *      ucast_action    - Unknown source MAC action.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                  - OK
+ *      RT_ERR_FAILED              - Failed
+ *      RT_ERR_SMI                 - SMI access error
+ *      RT_ERR_NOT_ALLOWED         - Invalid action.
+ *      RT_ERR_INPUT               - Invalid input parameters.
+ * Note:
+ *      This API can set unknown unicast packet action configuration.
+ *      The unknown unicast action is as following:
+ *          - UCAST_ACTION_FORWARD_PMASK
+ *          - UCAST_ACTION_DROP
+ *          - UCAST_ACTION_TRAP2CPU
+ */
+rtk_api_ret_t rtk_trap_unknownMacPktAction_set(rtk_trap_ucast_action_t ucast_action)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (ucast_action >= UCAST_ACTION_FLOODING)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicPortUnknownSaBehavior(ucast_action)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trap_unknownMacPktAction_get
+ * Description:
+ *      Get unknown source MAC packet action configuration.
+ * Input:
+ *      None.
+ * Output:
+ *      pUcast_action   - Unknown source MAC action.
+ * Return:
+ *      RT_ERR_OK                  - OK
+ *      RT_ERR_FAILED              - Failed
+ *      RT_ERR_SMI                 - SMI access error
+ *      RT_ERR_NULL_POINTER        - Null Pointer.
+ *      RT_ERR_INPUT               - Invalid input parameters.
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_trap_unknownMacPktAction_get(rtk_trap_ucast_action_t *pUcast_action)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pUcast_action)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicPortUnknownSaBehavior(pUcast_action)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trap_unmatchMacPktAction_set
+ * Description:
+ *      Set unmatch source MAC packet action configuration.
+ * Input:
+ *      ucast_action    - Unknown source MAC action.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                  - OK
+ *      RT_ERR_FAILED              - Failed
+ *      RT_ERR_SMI                 - SMI access error
+ *      RT_ERR_NOT_ALLOWED         - Invalid action.
+ *      RT_ERR_INPUT               - Invalid input parameters.
+ * Note:
+ *      This API can set unknown unicast packet action configuration.
+ *      The unknown unicast action is as following:
+ *          - UCAST_ACTION_FORWARD_PMASK
+ *          - UCAST_ACTION_DROP
+ *          - UCAST_ACTION_TRAP2CPU
+ */
+rtk_api_ret_t rtk_trap_unmatchMacPktAction_set(rtk_trap_ucast_action_t ucast_action)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (ucast_action >= UCAST_ACTION_FLOODING)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicPortUnmatchedSaBehavior(ucast_action)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trap_unmatchMacPktAction_get
+ * Description:
+ *      Get unmatch source MAC packet action configuration.
+ * Input:
+ *      None.
+ * Output:
+ *      pUcast_action   - Unknown source MAC action.
+ * Return:
+ *      RT_ERR_OK                  - OK
+ *      RT_ERR_FAILED              - Failed
+ *      RT_ERR_SMI                 - SMI access error
+ *      RT_ERR_NOT_ALLOWED         - Invalid action.
+ *      RT_ERR_INPUT               - Invalid input parameters.
+ * Note:
+ *      This API can set unknown unicast packet action configuration.
+ *      The unknown unicast action is as following:
+ *          - UCAST_ACTION_FORWARD_PMASK
+ *          - UCAST_ACTION_DROP
+ *          - UCAST_ACTION_TRAP2CPU
+ */
+rtk_api_ret_t rtk_trap_unmatchMacPktAction_get(rtk_trap_ucast_action_t *pUcast_action)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pUcast_action)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicPortUnmatchedSaBehavior(pUcast_action)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trap_unmatchMacMoving_set
+ * Description:
+ *      Set unmatch source MAC packet moving state.
+ * Input:
+ *      port        - Port ID.
+ *      enable      - ENABLED: allow SA moving, DISABLE: don't allow SA moving.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                  - OK
+ *      RT_ERR_FAILED              - Failed
+ *      RT_ERR_SMI                 - SMI access error
+ *      RT_ERR_NOT_ALLOWED         - Invalid action.
+ *      RT_ERR_INPUT               - Invalid input parameters.
+ * Note:
+ */
+rtk_api_ret_t rtk_trap_unmatchMacMoving_set(rtk_port_t port, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(enable >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicPortUnmatchedSaMoving(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trap_unmatchMacMoving_get
+ * Description:
+ *      Set unmatch source MAC packet moving state.
+ * Input:
+ *      port        - Port ID.
+ * Output:
+ *      pEnable     - ENABLED: allow SA moving, DISABLE: don't allow SA moving.
+ * Return:
+ *      RT_ERR_OK                  - OK
+ *      RT_ERR_FAILED              - Failed
+ *      RT_ERR_SMI                 - SMI access error
+ *      RT_ERR_NOT_ALLOWED         - Invalid action.
+ *      RT_ERR_INPUT               - Invalid input parameters.
+ * Note:
+ */
+rtk_api_ret_t rtk_trap_unmatchMacMoving_get(rtk_port_t port, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* check port valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicPortUnmatchedSaMoving(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trap_unknownMcastPktAction_set
+ * Description:
+ *      Set behavior of unknown multicast
+ * Input:
+ *      port            - Port id.
+ *      type            - unknown multicast packet type.
+ *      mcast_action    - unknown multicast action.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID         - Invalid port number.
+ *      RT_ERR_NOT_ALLOWED     - Invalid action.
+ *      RT_ERR_INPUT         - Invalid input parameters.
+ * Note:
+ *      When receives an unknown multicast packet, switch may trap, drop or flood this packet
+ *      (1) The unknown multicast packet type is as following:
+ *          - MCAST_L2
+ *          - MCAST_IPV4
+ *          - MCAST_IPV6
+ *      (2) The unknown multicast action is as following:
+ *          - MCAST_ACTION_FORWARD
+ *          - MCAST_ACTION_DROP
+ *          - MCAST_ACTION_TRAP2CPU
+ */
+rtk_api_ret_t rtk_trap_unknownMcastPktAction_set(rtk_port_t port, rtk_mcast_type_t type, rtk_trap_mcast_action_t mcast_action)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 rawAction;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (type >= MCAST_END)
+        return RT_ERR_INPUT;
+
+    if (mcast_action >= MCAST_ACTION_END)
+        return RT_ERR_INPUT;
+
+
+    switch (type)
+    {
+        case MCAST_L2:
+            if (MCAST_ACTION_ROUTER_PORT == mcast_action)
+                return RT_ERR_INPUT;
+            else if(MCAST_ACTION_DROP_EX_RMA == mcast_action)
+                rawAction = L2_UNKOWN_MULTICAST_DROP_EXCLUDE_RMA;
+            else
+                rawAction = (rtk_uint32)mcast_action;
+
+            if ((retVal = rtl8367c_setAsicUnknownL2MulticastBehavior(rtk_switch_port_L2P_get(port), rawAction)) != RT_ERR_OK)
+                return retVal;
+
+            break;
+        case MCAST_IPV4:
+            if (MCAST_ACTION_DROP_EX_RMA == mcast_action)
+                return RT_ERR_INPUT;
+            else
+                rawAction = (rtk_uint32)mcast_action;
+
+            if ((retVal = rtl8367c_setAsicUnknownIPv4MulticastBehavior(rtk_switch_port_L2P_get(port), rawAction)) != RT_ERR_OK)
+                return retVal;
+
+            break;
+        case MCAST_IPV6:
+            if (MCAST_ACTION_DROP_EX_RMA == mcast_action)
+                return RT_ERR_INPUT;
+            else
+                rawAction = (rtk_uint32)mcast_action;
+
+            if ((retVal = rtl8367c_setAsicUnknownIPv6MulticastBehavior(rtk_switch_port_L2P_get(port), rawAction)) != RT_ERR_OK)
+                return retVal;
+
+            break;
+        default:
+            break;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trap_unknownMcastPktAction_get
+ * Description:
+ *      Get behavior of unknown multicast
+ * Input:
+ *      type - unknown multicast packet type.
+ * Output:
+ *      pMcast_action - unknown multicast action.
+ * Return:
+ *      RT_ERR_OK                  - OK
+ *      RT_ERR_FAILED              - Failed
+ *      RT_ERR_SMI                 - SMI access error
+ *      RT_ERR_PORT_ID             - Invalid port number.
+ *      RT_ERR_NOT_ALLOWED         - Invalid operation.
+ *      RT_ERR_INPUT             - Invalid input parameters.
+ * Note:
+ *      When receives an unknown multicast packet, switch may trap, drop or flood this packet
+ *      (1) The unknown multicast packet type is as following:
+ *          - MCAST_L2
+ *          - MCAST_IPV4
+ *          - MCAST_IPV6
+ *      (2) The unknown multicast action is as following:
+ *          - MCAST_ACTION_FORWARD
+ *          - MCAST_ACTION_DROP
+ *          - MCAST_ACTION_TRAP2CPU
+ */
+rtk_api_ret_t rtk_trap_unknownMcastPktAction_get(rtk_port_t port, rtk_mcast_type_t type, rtk_trap_mcast_action_t *pMcast_action)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 rawAction;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (type >= MCAST_END)
+        return RT_ERR_INPUT;
+
+    if(NULL == pMcast_action)
+        return RT_ERR_NULL_POINTER;
+
+    switch (type)
+    {
+        case MCAST_L2:
+            if ((retVal = rtl8367c_getAsicUnknownL2MulticastBehavior(rtk_switch_port_L2P_get(port), &rawAction)) != RT_ERR_OK)
+                return retVal;
+
+            if(L2_UNKOWN_MULTICAST_DROP_EXCLUDE_RMA == rawAction)
+                *pMcast_action = MCAST_ACTION_DROP_EX_RMA;
+            else
+                *pMcast_action = (rtk_trap_mcast_action_t)rawAction;
+
+            break;
+        case MCAST_IPV4:
+            if ((retVal = rtl8367c_getAsicUnknownIPv4MulticastBehavior(rtk_switch_port_L2P_get(port), &rawAction)) != RT_ERR_OK)
+                return retVal;
+
+            *pMcast_action = (rtk_trap_mcast_action_t)rawAction;
+            break;
+        case MCAST_IPV6:
+            if ((retVal = rtl8367c_getAsicUnknownIPv6MulticastBehavior(rtk_switch_port_L2P_get(port), &rawAction)) != RT_ERR_OK)
+                return retVal;
+
+            *pMcast_action = (rtk_trap_mcast_action_t)rawAction;
+            break;
+        default:
+            break;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trap_lldpEnable_set
+ * Description:
+ *      Set LLDP enable.
+ * Input:
+ *      enabled - LLDP enable, 0: follow RMA, 1: use LLDP action.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                  - OK
+ *      RT_ERR_FAILED              - Failed
+ *      RT_ERR_SMI                 - SMI access error
+ *      RT_ERR_NOT_ALLOWED         - Invalid action.
+ *      RT_ERR_INPUT             - Invalid input parameters.
+ * Note:
+ *      - DMAC                                                 Assignment
+ *      - 01:80:c2:00:00:0e ethertype = 0x88CC    LLDP
+ *      - 01:80:c2:00:00:03 ethertype = 0x88CC
+ *      - 01:80:c2:00:00:00 ethertype = 0x88CC
+
+ */
+rtk_api_ret_t rtk_trap_lldpEnable_set(rtk_enable_t enabled)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_rma_t rmacfg;
+    rtk_enable_t tmp;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (enabled >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if ((retVal = rtl8367c_getAsicRmaLldp(&tmp, &rmacfg)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicRmaLldp(enabled, &rmacfg)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trap_lldpEnable_get
+ * Description:
+ *      Get LLDP status.
+ * Input:
+ *      None
+ * Output:
+ *      pEnabled - LLDP enable, 0: follow RMA, 1: use LLDP action.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT         - Invalid input parameters.
+ * Note:
+ *      LLDP is as following definition.
+ *      - DMAC                                                 Assignment
+ *      - 01:80:c2:00:00:0e ethertype = 0x88CC    LLDP
+ *      - 01:80:c2:00:00:03 ethertype = 0x88CC
+ *      - 01:80:c2:00:00:00 ethertype = 0x88CC
+ */
+rtk_api_ret_t rtk_trap_lldpEnable_get(rtk_enable_t *pEnabled)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_rma_t rmacfg;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pEnabled)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicRmaLldp(pEnabled, &rmacfg)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trap_reasonTrapToCpuPriority_set
+ * Description:
+ *      Set priority value of a packet that trapped to CPU port according to specific reason.
+ * Input:
+ *      type     - reason that trap to CPU port.
+ *      priority - internal priority that is going to be set for specific trap reason.
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT - The module is not initial
+ *      RT_ERR_INPUT    - Invalid input parameter
+ * Note:
+ *      Currently the trap reason that supported are listed as follows:
+ *      - TRAP_REASON_RMA
+ *      - TRAP_REASON_OAM
+ *      - TRAP_REASON_1XUNAUTH
+ *      - TRAP_REASON_VLANSTACK
+ *      - TRAP_REASON_UNKNOWNMC
+ */
+rtk_api_ret_t rtk_trap_reasonTrapToCpuPriority_set(rtk_trap_reason_type_t type, rtk_pri_t priority)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_rma_t rmacfg;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (type >= TRAP_REASON_END)
+        return RT_ERR_INPUT;
+
+    if (priority > RTL8367C_PRIMAX)
+        return  RT_ERR_QOS_INT_PRIORITY;
+
+    switch (type)
+    {
+        case TRAP_REASON_RMA:
+            if ((retVal = rtl8367c_getAsicRma(0, &rmacfg)) != RT_ERR_OK)
+                return retVal;
+            rmacfg.trap_priority= priority;
+            if ((retVal = rtl8367c_setAsicRma(0, &rmacfg)) != RT_ERR_OK)
+                return retVal;
+
+            break;
+        case TRAP_REASON_OAM:
+            if ((retVal = rtl8367c_setAsicOamCpuPri(priority)) != RT_ERR_OK)
+                return retVal;
+
+            break;
+        case TRAP_REASON_1XUNAUTH:
+            if ((retVal = rtl8367c_setAsic1xTrapPriority(priority)) != RT_ERR_OK)
+                return retVal;
+
+            break;
+        case TRAP_REASON_VLANSTACK:
+            if ((retVal = rtl8367c_setAsicSvlanTrapPriority(priority)) != RT_ERR_OK)
+                return retVal;
+
+            break;
+        case TRAP_REASON_UNKNOWNMC:
+            if ((retVal = rtl8367c_setAsicUnknownMulticastTrapPriority(priority)) != RT_ERR_OK)
+                return retVal;
+
+            break;
+        default:
+            return RT_ERR_CHIP_NOT_SUPPORTED;
+    }
+
+
+    return RT_ERR_OK;
+}
+
+
+/* Function Name:
+ *      rtk_trap_reasonTrapToCpuPriority_get
+ * Description:
+ *      Get priority value of a packet that trapped to CPU port according to specific reason.
+ * Input:
+ *      type      - reason that trap to CPU port.
+ * Output:
+ *      pPriority - configured internal priority for such reason.
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NOT_INIT     - The module is not initial
+ *      RT_ERR_INPUT        - Invalid input parameter
+ *      RT_ERR_NULL_POINTER - NULL pointer
+ * Note:
+ *      Currently the trap reason that supported are listed as follows:
+ *      - TRAP_REASON_RMA
+ *      - TRAP_REASON_OAM
+ *      - TRAP_REASON_1XUNAUTH
+ *      - TRAP_REASON_VLANSTACK
+ *      - TRAP_REASON_UNKNOWNMC
+ */
+rtk_api_ret_t rtk_trap_reasonTrapToCpuPriority_get(rtk_trap_reason_type_t type, rtk_pri_t *pPriority)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_rma_t rmacfg;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (type >= TRAP_REASON_END)
+        return RT_ERR_INPUT;
+
+    if(NULL == pPriority)
+        return RT_ERR_NULL_POINTER;
+
+    switch (type)
+    {
+        case TRAP_REASON_RMA:
+            if ((retVal = rtl8367c_getAsicRma(0, &rmacfg)) != RT_ERR_OK)
+                return retVal;
+            *pPriority = rmacfg.trap_priority;
+
+            break;
+        case TRAP_REASON_OAM:
+            if ((retVal = rtl8367c_getAsicOamCpuPri(pPriority)) != RT_ERR_OK)
+                return retVal;
+
+            break;
+        case TRAP_REASON_1XUNAUTH:
+            if ((retVal = rtl8367c_getAsic1xTrapPriority(pPriority)) != RT_ERR_OK)
+                return retVal;
+
+            break;
+        case TRAP_REASON_VLANSTACK:
+            if ((retVal = rtl8367c_getAsicSvlanTrapPriority(pPriority)) != RT_ERR_OK)
+                return retVal;
+
+            break;
+        case TRAP_REASON_UNKNOWNMC:
+            if ((retVal = rtl8367c_getAsicUnknownMulticastTrapPriority(pPriority)) != RT_ERR_OK)
+                return retVal;
+
+            break;
+        default:
+            return RT_ERR_CHIP_NOT_SUPPORTED;
+
+    }
+
+    return RT_ERR_OK;
+}
+
+
+
+/* Function Name:
+ *      rtk_trap_rmaAction_set
+ * Description:
+ *      Set Reserved multicast address action configuration.
+ * Input:
+ *      type    - rma type.
+ *      rma_action - RMA action.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *
+ *      There are 48 types of Reserved Multicast Address frame for application usage.
+ *      (1)They are as following definition.
+ *      - TRAP_BRG_GROUP,
+ *      - TRAP_FD_PAUSE,
+ *      - TRAP_SP_MCAST,
+ *      - TRAP_1X_PAE,
+ *      - TRAP_UNDEF_BRG_04,
+ *      - TRAP_UNDEF_BRG_05,
+ *      - TRAP_UNDEF_BRG_06,
+ *      - TRAP_UNDEF_BRG_07,
+ *      - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS,
+ *      - TRAP_UNDEF_BRG_09,
+ *      - TRAP_UNDEF_BRG_0A,
+ *      - TRAP_UNDEF_BRG_0B,
+ *      - TRAP_UNDEF_BRG_0C,
+ *      - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS,
+ *      - TRAP_8021AB,
+ *      - TRAP_UNDEF_BRG_0F,
+ *      - TRAP_BRG_MNGEMENT,
+ *      - TRAP_UNDEFINED_11,
+ *      - TRAP_UNDEFINED_12,
+ *      - TRAP_UNDEFINED_13,
+ *      - TRAP_UNDEFINED_14,
+ *      - TRAP_UNDEFINED_15,
+ *      - TRAP_UNDEFINED_16,
+ *      - TRAP_UNDEFINED_17,
+ *      - TRAP_UNDEFINED_18,
+ *      - TRAP_UNDEFINED_19,
+ *      - TRAP_UNDEFINED_1A,
+ *      - TRAP_UNDEFINED_1B,
+ *      - TRAP_UNDEFINED_1C,
+ *      - TRAP_UNDEFINED_1D,
+ *      - TRAP_UNDEFINED_1E,
+ *      - TRAP_UNDEFINED_1F,
+ *      - TRAP_GMRP,
+ *      - TRAP_GVRP,
+ *      - TRAP_UNDEF_GARP_22,
+ *      - TRAP_UNDEF_GARP_23,
+ *      - TRAP_UNDEF_GARP_24,
+ *      - TRAP_UNDEF_GARP_25,
+ *      - TRAP_UNDEF_GARP_26,
+ *      - TRAP_UNDEF_GARP_27,
+ *      - TRAP_UNDEF_GARP_28,
+ *      - TRAP_UNDEF_GARP_29,
+ *      - TRAP_UNDEF_GARP_2A,
+ *      - TRAP_UNDEF_GARP_2B,
+ *      - TRAP_UNDEF_GARP_2C,
+ *      - TRAP_UNDEF_GARP_2D,
+ *      - TRAP_UNDEF_GARP_2E,
+ *      - TRAP_UNDEF_GARP_2F,
+ *      - TRAP_CDP.
+ *      - TRAP_CSSTP.
+ *      - TRAP_LLDP.
+ *      (2) The RMA action is as following:
+ *      - RMA_ACTION_FORWARD
+ *      - RMA_ACTION_TRAP2CPU
+ *      - RMA_ACTION_DROP
+ *      - RMA_ACTION_FORWARD_EXCLUDE_CPU
+ */
+rtk_api_ret_t rtk_trap_rmaAction_set(rtk_trap_type_t type, rtk_trap_rma_action_t rma_action)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_rma_t rmacfg;
+    rtk_uint32 tmp;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (type >= TRAP_END)
+        return RT_ERR_INPUT;
+
+    if (rma_action >= RMA_ACTION_END)
+        return RT_ERR_RMA_ACTION;
+
+    if (type >= 0 && type <= TRAP_UNDEF_GARP_2F)
+    {
+        if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        rmacfg.operation = rma_action;
+
+        if ((retVal = rtl8367c_setAsicRma(type, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+    }
+    else if (type == TRAP_CDP)
+    {
+        if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        rmacfg.operation = rma_action;
+
+        if ((retVal = rtl8367c_setAsicRmaCdp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+    }
+    else if (type  == TRAP_CSSTP)
+    {
+        if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        rmacfg.operation = rma_action;
+
+        if ((retVal = rtl8367c_setAsicRmaCsstp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+    }
+    else if (type  == TRAP_LLDP)
+    {
+        if ((retVal = rtl8367c_getAsicRmaLldp(&tmp, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        rmacfg.operation = rma_action;
+
+        if ((retVal = rtl8367c_setAsicRmaLldp(tmp, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+    }
+    else
+        return RT_ERR_INPUT;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trap_rmaAction_get
+ * Description:
+ *      Get Reserved multicast address action configuration.
+ * Input:
+ *      type - rma type.
+ * Output:
+ *      pRma_action - RMA action.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      There are 48 types of Reserved Multicast Address frame for application usage.
+ *      (1)They are as following definition.
+ *      - TRAP_BRG_GROUP,
+ *      - TRAP_FD_PAUSE,
+ *      - TRAP_SP_MCAST,
+ *      - TRAP_1X_PAE,
+ *      - TRAP_UNDEF_BRG_04,
+ *      - TRAP_UNDEF_BRG_05,
+ *      - TRAP_UNDEF_BRG_06,
+ *      - TRAP_UNDEF_BRG_07,
+ *      - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS,
+ *      - TRAP_UNDEF_BRG_09,
+ *      - TRAP_UNDEF_BRG_0A,
+ *      - TRAP_UNDEF_BRG_0B,
+ *      - TRAP_UNDEF_BRG_0C,
+ *      - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS,
+ *      - TRAP_8021AB,
+ *      - TRAP_UNDEF_BRG_0F,
+ *      - TRAP_BRG_MNGEMENT,
+ *      - TRAP_UNDEFINED_11,
+ *      - TRAP_UNDEFINED_12,
+ *      - TRAP_UNDEFINED_13,
+ *      - TRAP_UNDEFINED_14,
+ *      - TRAP_UNDEFINED_15,
+ *      - TRAP_UNDEFINED_16,
+ *      - TRAP_UNDEFINED_17,
+ *      - TRAP_UNDEFINED_18,
+ *      - TRAP_UNDEFINED_19,
+ *      - TRAP_UNDEFINED_1A,
+ *      - TRAP_UNDEFINED_1B,
+ *      - TRAP_UNDEFINED_1C,
+ *      - TRAP_UNDEFINED_1D,
+ *      - TRAP_UNDEFINED_1E,
+ *      - TRAP_UNDEFINED_1F,
+ *      - TRAP_GMRP,
+ *      - TRAP_GVRP,
+ *      - TRAP_UNDEF_GARP_22,
+ *      - TRAP_UNDEF_GARP_23,
+ *      - TRAP_UNDEF_GARP_24,
+ *      - TRAP_UNDEF_GARP_25,
+ *      - TRAP_UNDEF_GARP_26,
+ *      - TRAP_UNDEF_GARP_27,
+ *      - TRAP_UNDEF_GARP_28,
+ *      - TRAP_UNDEF_GARP_29,
+ *      - TRAP_UNDEF_GARP_2A,
+ *      - TRAP_UNDEF_GARP_2B,
+ *      - TRAP_UNDEF_GARP_2C,
+ *      - TRAP_UNDEF_GARP_2D,
+ *      - TRAP_UNDEF_GARP_2E,
+ *      - TRAP_UNDEF_GARP_2F,
+ *      - TRAP_CDP.
+ *      - TRAP_CSSTP.
+ *      - TRAP_LLDP.
+ *      (2) The RMA action is as following:
+ *      - RMA_ACTION_FORWARD
+ *      - RMA_ACTION_TRAP2CPU
+ *      - RMA_ACTION_DROP
+ *      - RMA_ACTION_FORWARD_EXCLUDE_CPU
+ */
+rtk_api_ret_t rtk_trap_rmaAction_get(rtk_trap_type_t type, rtk_trap_rma_action_t *pRma_action)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_rma_t rmacfg;
+    rtk_uint32 tmp;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (type >= TRAP_END)
+        return RT_ERR_INPUT;
+
+    if(NULL == pRma_action)
+        return RT_ERR_NULL_POINTER;
+
+    if (type >= 0 && type <= TRAP_UNDEF_GARP_2F)
+    {
+        if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        *pRma_action = rmacfg.operation;
+    }
+    else if (type == TRAP_CDP)
+    {
+        if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        *pRma_action = rmacfg.operation;
+    }
+    else if (type == TRAP_CSSTP)
+    {
+        if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        *pRma_action = rmacfg.operation;
+    }
+    else if (type == TRAP_LLDP)
+    {
+        if ((retVal = rtl8367c_getAsicRmaLldp(&tmp,&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        *pRma_action = rmacfg.operation;
+    }
+    else
+        return RT_ERR_INPUT;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trap_rmaKeepFormat_set
+ * Description:
+ *      Set Reserved multicast address keep format configuration.
+ * Input:
+ *      type    - rma type.
+ *      enable - enable keep format.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_ENABLE       - Invalid IFG parameter
+ * Note:
+ *
+ *      There are 48 types of Reserved Multicast Address frame for application usage.
+ *      They are as following definition.
+ *      - TRAP_BRG_GROUP,
+ *      - TRAP_FD_PAUSE,
+ *      - TRAP_SP_MCAST,
+ *      - TRAP_1X_PAE,
+ *      - TRAP_UNDEF_BRG_04,
+ *      - TRAP_UNDEF_BRG_05,
+ *      - TRAP_UNDEF_BRG_06,
+ *      - TRAP_UNDEF_BRG_07,
+ *      - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS,
+ *      - TRAP_UNDEF_BRG_09,
+ *      - TRAP_UNDEF_BRG_0A,
+ *      - TRAP_UNDEF_BRG_0B,
+ *      - TRAP_UNDEF_BRG_0C,
+ *      - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS,
+ *      - TRAP_8021AB,
+ *      - TRAP_UNDEF_BRG_0F,
+ *      - TRAP_BRG_MNGEMENT,
+ *      - TRAP_UNDEFINED_11,
+ *      - TRAP_UNDEFINED_12,
+ *      - TRAP_UNDEFINED_13,
+ *      - TRAP_UNDEFINED_14,
+ *      - TRAP_UNDEFINED_15,
+ *      - TRAP_UNDEFINED_16,
+ *      - TRAP_UNDEFINED_17,
+ *      - TRAP_UNDEFINED_18,
+ *      - TRAP_UNDEFINED_19,
+ *      - TRAP_UNDEFINED_1A,
+ *      - TRAP_UNDEFINED_1B,
+ *      - TRAP_UNDEFINED_1C,
+ *      - TRAP_UNDEFINED_1D,
+ *      - TRAP_UNDEFINED_1E,
+ *      - TRAP_UNDEFINED_1F,
+ *      - TRAP_GMRP,
+ *      - TRAP_GVRP,
+ *      - TRAP_UNDEF_GARP_22,
+ *      - TRAP_UNDEF_GARP_23,
+ *      - TRAP_UNDEF_GARP_24,
+ *      - TRAP_UNDEF_GARP_25,
+ *      - TRAP_UNDEF_GARP_26,
+ *      - TRAP_UNDEF_GARP_27,
+ *      - TRAP_UNDEF_GARP_28,
+ *      - TRAP_UNDEF_GARP_29,
+ *      - TRAP_UNDEF_GARP_2A,
+ *      - TRAP_UNDEF_GARP_2B,
+ *      - TRAP_UNDEF_GARP_2C,
+ *      - TRAP_UNDEF_GARP_2D,
+ *      - TRAP_UNDEF_GARP_2E,
+ *      - TRAP_UNDEF_GARP_2F,
+ *      - TRAP_CDP.
+ *      - TRAP_CSSTP.
+ *      - TRAP_LLDP.
+ */
+rtk_api_ret_t rtk_trap_rmaKeepFormat_set(rtk_trap_type_t type, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_rma_t rmacfg;
+    rtk_uint32 tmp;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (type >= TRAP_END)
+        return RT_ERR_INPUT;
+
+    if (enable >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if (type >= 0 && type <= TRAP_UNDEF_GARP_2F)
+    {
+        if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        rmacfg.keep_format = enable;
+
+        if ((retVal = rtl8367c_setAsicRma(type, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+    }
+    else if (type == TRAP_CDP)
+    {
+        if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        rmacfg.keep_format = enable;
+
+        if ((retVal = rtl8367c_setAsicRmaCdp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+    }
+    else if (type  == TRAP_CSSTP)
+    {
+        if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        rmacfg.keep_format = enable;
+
+        if ((retVal = rtl8367c_setAsicRmaCsstp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+    }
+    else if (type  == TRAP_LLDP)
+    {
+        if ((retVal = rtl8367c_getAsicRmaLldp(&tmp, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        rmacfg.keep_format = enable;
+
+        if ((retVal = rtl8367c_setAsicRmaLldp(tmp, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+    }
+    else
+        return RT_ERR_INPUT;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trap_rmaKeepFormat_get
+ * Description:
+ *      Get Reserved multicast address action configuration.
+ * Input:
+ *      type - rma type.
+ * Output:
+ *      pEnable - keep format status.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ * Note:
+ *      There are 48 types of Reserved Multicast Address frame for application usage.
+ *      They are as following definition.
+ *      - TRAP_BRG_GROUP,
+ *      - TRAP_FD_PAUSE,
+ *      - TRAP_SP_MCAST,
+ *      - TRAP_1X_PAE,
+ *      - TRAP_UNDEF_BRG_04,
+ *      - TRAP_UNDEF_BRG_05,
+ *      - TRAP_UNDEF_BRG_06,
+ *      - TRAP_UNDEF_BRG_07,
+ *      - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS,
+ *      - TRAP_UNDEF_BRG_09,
+ *      - TRAP_UNDEF_BRG_0A,
+ *      - TRAP_UNDEF_BRG_0B,
+ *      - TRAP_UNDEF_BRG_0C,
+ *      - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS,
+ *      - TRAP_8021AB,
+ *      - TRAP_UNDEF_BRG_0F,
+ *      - TRAP_BRG_MNGEMENT,
+ *      - TRAP_UNDEFINED_11,
+ *      - TRAP_UNDEFINED_12,
+ *      - TRAP_UNDEFINED_13,
+ *      - TRAP_UNDEFINED_14,
+ *      - TRAP_UNDEFINED_15,
+ *      - TRAP_UNDEFINED_16,
+ *      - TRAP_UNDEFINED_17,
+ *      - TRAP_UNDEFINED_18,
+ *      - TRAP_UNDEFINED_19,
+ *      - TRAP_UNDEFINED_1A,
+ *      - TRAP_UNDEFINED_1B,
+ *      - TRAP_UNDEFINED_1C,
+ *      - TRAP_UNDEFINED_1D,
+ *      - TRAP_UNDEFINED_1E,
+ *      - TRAP_UNDEFINED_1F,
+ *      - TRAP_GMRP,
+ *      - TRAP_GVRP,
+ *      - TRAP_UNDEF_GARP_22,
+ *      - TRAP_UNDEF_GARP_23,
+ *      - TRAP_UNDEF_GARP_24,
+ *      - TRAP_UNDEF_GARP_25,
+ *      - TRAP_UNDEF_GARP_26,
+ *      - TRAP_UNDEF_GARP_27,
+ *      - TRAP_UNDEF_GARP_28,
+ *      - TRAP_UNDEF_GARP_29,
+ *      - TRAP_UNDEF_GARP_2A,
+ *      - TRAP_UNDEF_GARP_2B,
+ *      - TRAP_UNDEF_GARP_2C,
+ *      - TRAP_UNDEF_GARP_2D,
+ *      - TRAP_UNDEF_GARP_2E,
+ *      - TRAP_UNDEF_GARP_2F,
+ *      - TRAP_CDP.
+ *      - TRAP_CSSTP.
+ *      - TRAP_LLDP.
+ */
+rtk_api_ret_t rtk_trap_rmaKeepFormat_get(rtk_trap_type_t type, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_rma_t rmacfg;
+    rtk_uint32 tmp;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (type >= TRAP_END)
+        return RT_ERR_INPUT;
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if (type >= 0 && type <= TRAP_UNDEF_GARP_2F)
+    {
+        if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        *pEnable = rmacfg.keep_format;
+    }
+    else if (type == TRAP_CDP)
+    {
+        if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        *pEnable = rmacfg.keep_format;
+    }
+    else if (type == TRAP_CSSTP)
+    {
+        if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        *pEnable = rmacfg.keep_format;
+    }
+    else if (type == TRAP_LLDP)
+    {
+        if ((retVal = rtl8367c_getAsicRmaLldp(&tmp,&rmacfg)) != RT_ERR_OK)
+            return retVal;
+
+        *pEnable = rmacfg.keep_format;
+    }
+    else
+        return RT_ERR_INPUT;
+
+    return RT_ERR_OK;
+}
+
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/trunk.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/trunk.c
new file mode 100644
index 0000000..8a88dc5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/trunk.c
@@ -0,0 +1,605 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in Trunk module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <trunk.h>
+#include <string.h>
+
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_trunking.h>
+
+/* Function Name:
+ *      rtk_trunk_port_set
+ * Description:
+ *      Set trunking group available port mask
+ * Input:
+ *      trk_gid                 - trunk group id
+ *      pTrunk_member_portmask  - Logic trunking member port mask
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_LA_TRUNK_ID  - Invalid trunking group
+ *      RT_ERR_PORT_MASK    - Invalid portmask.
+ * Note:
+ *      The API can set port trunking group port mask. Each port trunking group has max 4 ports.
+ *      If enabled port mask has less than 2 ports available setting, then this trunking group function is disabled.
+ */
+rtk_api_ret_t rtk_trunk_port_set(rtk_trunk_group_t trk_gid, rtk_portmask_t *pTrunk_member_portmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmsk;
+    rtk_uint32 regValue, type, tmp;
+
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_getAsicReg(0x1300, &regValue)) != RT_ERR_OK)
+        return retVal;
+
+    if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK)
+        return retVal;
+
+    switch (regValue)
+    {
+        case 0x0276:
+        case 0x0597:
+        case 0x6367:
+            type = 0;
+            break;
+        case 0x0652:
+        case 0x6368:
+            type = 1;
+            break;
+        case 0x0801:
+        case 0x6511:
+            type = 2;
+            break;
+        default:
+            return RT_ERR_FAILED;
+    }
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Trunk Group Valid */
+    RTK_CHK_TRUNK_GROUP_VALID(trk_gid);
+
+    if(NULL == pTrunk_member_portmask)
+        return RT_ERR_NULL_POINTER;
+
+    RTK_CHK_PORTMASK_VALID(pTrunk_member_portmask);
+
+    if((retVal = rtk_switch_portmask_L2P_get(pTrunk_member_portmask, &pmsk)) != RT_ERR_OK)
+        return retVal;
+
+    if((type == 0) || (type == 1))
+    {
+        if ((pmsk | RTL8367C_PORT_TRUNK_GROUP_MASK_MASK(trk_gid)) != (rtk_uint32)RTL8367C_PORT_TRUNK_GROUP_MASK_MASK(trk_gid))
+            return RT_ERR_PORT_MASK;
+
+        pmsk = (pmsk & RTL8367C_PORT_TRUNK_GROUP_MASK_MASK(trk_gid)) >> RTL8367C_PORT_TRUNK_GROUP_MASK_OFFSET(trk_gid);
+    }
+    else if(type == 2)
+    {
+        tmp = 0;
+
+        if(pmsk & 0x2)
+            tmp |= 1;
+        if(pmsk & 0x8)
+            tmp |=2;
+        if(pmsk & 0x80)
+            tmp |=8;
+
+        pmsk = tmp;
+    }
+
+    if ((retVal = rtl8367c_setAsicTrunkingGroup(trk_gid, pmsk)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trunk_port_get
+ * Description:
+ *      Get trunking group available port mask
+ * Input:
+ *      trk_gid - trunk group id
+ * Output:
+ *      pTrunk_member_portmask - Logic trunking member port mask
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_LA_TRUNK_ID  - Invalid trunking group
+ * Note:
+ *      The API can get 2 port trunking group.
+ */
+rtk_api_ret_t rtk_trunk_port_get(rtk_trunk_group_t trk_gid, rtk_portmask_t *pTrunk_member_portmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmsk;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Trunk Group Valid */
+    RTK_CHK_TRUNK_GROUP_VALID(trk_gid);
+
+    if ((retVal = rtl8367c_getAsicTrunkingGroup(trk_gid, &pmsk)) != RT_ERR_OK)
+        return retVal;
+
+    pmsk = pmsk << RTL8367C_PORT_TRUNK_GROUP_MASK_OFFSET(trk_gid);
+
+    if((retVal = rtk_switch_portmask_P2L_get(pmsk, pTrunk_member_portmask)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trunk_distributionAlgorithm_set
+ * Description:
+ *      Set port trunking hash select sources
+ * Input:
+ *      trk_gid         - trunk group id
+ *      algo_bitmask   - Bitmask of the distribution algorithm
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_LA_TRUNK_ID  - Invalid trunking group
+ *      RT_ERR_LA_HASHMASK  - Hash algorithm selection error.
+ *      RT_ERR_PORT_MASK    - Invalid portmask.
+ * Note:
+ *      The API can set port trunking hash algorithm sources.
+ *      7 bits mask for link aggregation group0 hash parameter selection {DIP, SIP, DMAC, SMAC, SPA}
+ *      - 0b0000001: SPA
+ *      - 0b0000010: SMAC
+ *      - 0b0000100: DMAC
+ *      - 0b0001000: SIP
+ *      - 0b0010000: DIP
+ *      - 0b0100000: TCP/UDP Source Port
+ *      - 0b1000000: TCP/UDP Destination Port
+ *      Example:
+ *      - 0b0000011: SMAC & SPA
+ *      - Note that it could be an arbitrary combination or independent set
+ */
+rtk_api_ret_t rtk_trunk_distributionAlgorithm_set(rtk_trunk_group_t trk_gid, rtk_uint32 algo_bitmask)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (trk_gid != RTK_WHOLE_SYSTEM)
+        return RT_ERR_LA_TRUNK_ID;
+
+    if (algo_bitmask >= 128)
+        return RT_ERR_LA_HASHMASK;
+
+    if ((retVal = rtl8367c_setAsicTrunkingHashSelect(algo_bitmask)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trunk_distributionAlgorithm_get
+ * Description:
+ *      Get port trunking hash select sources
+ * Input:
+ *      trk_gid - trunk group id
+ * Output:
+ *      pAlgo_bitmask -  Bitmask of the distribution algorithm
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_LA_TRUNK_ID  - Invalid trunking group
+ * Note:
+ *      The API can get port trunking hash algorithm sources.
+ */
+rtk_api_ret_t rtk_trunk_distributionAlgorithm_get(rtk_trunk_group_t trk_gid, rtk_uint32 *pAlgo_bitmask)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (trk_gid != RTK_WHOLE_SYSTEM)
+        return RT_ERR_LA_TRUNK_ID;
+
+    if(NULL == pAlgo_bitmask)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicTrunkingHashSelect((rtk_uint32 *)pAlgo_bitmask)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trunk_trafficSeparate_set
+ * Description:
+ *      Set the traffic separation setting of a trunk group from the specified device.
+ * Input:
+ *      trk_gid      - trunk group id
+ *      separateType     - traffic separation setting
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_UNIT_ID     - invalid unit id
+ *      RT_ERR_LA_TRUNK_ID - invalid trunk ID
+ *      RT_ERR_LA_HASHMASK - invalid hash mask
+ * Note:
+ *      SEPARATE_NONE: disable traffic separation
+ *      SEPARATE_FLOOD: trunk MSB link up port is dedicated to TX flooding (L2 lookup miss) traffic
+ */
+rtk_api_ret_t rtk_trunk_trafficSeparate_set(rtk_trunk_group_t trk_gid, rtk_trunk_separateType_t separateType)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 enabled;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (trk_gid != RTK_WHOLE_SYSTEM)
+        return RT_ERR_LA_TRUNK_ID;
+
+    if(separateType >= SEPARATE_END)
+        return RT_ERR_INPUT;
+
+    enabled = (separateType == SEPARATE_FLOOD) ? ENABLED : DISABLED;
+    if ((retVal = rtl8367c_setAsicTrunkingFlood(enabled)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trunk_trafficSeparate_get
+ * Description:
+ *      Get the traffic separation setting of a trunk group from the specified device.
+ * Input:
+ *      trk_gid        - trunk group id
+ * Output:
+ *      pSeparateType   - pointer separated traffic type
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_UNIT_ID      - invalid unit id
+ *      RT_ERR_LA_TRUNK_ID  - invalid trunk ID
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Note:
+ *      SEPARATE_NONE: disable traffic separation
+ *      SEPARATE_FLOOD: trunk MSB link up port is dedicated to TX flooding (L2 lookup miss) traffic
+ */
+rtk_api_ret_t rtk_trunk_trafficSeparate_get(rtk_trunk_group_t trk_gid, rtk_trunk_separateType_t *pSeparateType)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 enabled;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if (trk_gid != RTK_WHOLE_SYSTEM)
+        return RT_ERR_LA_TRUNK_ID;
+
+    if(NULL == pSeparateType)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicTrunkingFlood(&enabled)) != RT_ERR_OK)
+        return retVal;
+
+    *pSeparateType = (enabled == ENABLED) ? SEPARATE_FLOOD : SEPARATE_NONE;
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trunk_mode_set
+ * Description:
+ *      Set the trunk mode to the specified device.
+ * Input:
+ *      mode - trunk mode
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_INPUT   - invalid input parameter
+ * Note:
+ *      The enum of the trunk mode as following
+ *      - TRUNK_MODE_NORMAL
+ *      - TRUNK_MODE_DUMB
+ */
+rtk_api_ret_t rtk_trunk_mode_set(rtk_trunk_mode_t mode)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(mode >= TRUNK_MODE_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicTrunkingMode((rtk_uint32)mode)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trunk_mode_get
+ * Description:
+ *      Get the trunk mode from the specified device.
+ * Input:
+ *      None
+ * Output:
+ *      pMode - pointer buffer of trunk mode
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Note:
+ *      The enum of the trunk mode as following
+ *      - TRUNK_MODE_NORMAL
+ *      - TRUNK_MODE_DUMB
+ */
+rtk_api_ret_t rtk_trunk_mode_get(rtk_trunk_mode_t *pMode)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pMode)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicTrunkingMode((rtk_uint32 *)pMode)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trunk_trafficPause_set
+ * Description:
+ *      Set the traffic pause setting of a trunk group.
+ * Input:
+ *      trk_gid      - trunk group id
+ *      enable       - traffic pause state
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_LA_TRUNK_ID - invalid trunk ID
+ * Note:
+ *      None.
+ */
+rtk_api_ret_t rtk_trunk_trafficPause_set(rtk_trunk_group_t trk_gid, rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Trunk Group Valid */
+    RTK_CHK_TRUNK_GROUP_VALID(trk_gid);
+
+    if(enable >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setAsicTrunkingFc((rtk_uint32)trk_gid, (rtk_uint32)enable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trunk_trafficPause_get
+ * Description:
+ *      Get the traffic pause setting of a trunk group.
+ * Input:
+ *      trk_gid        - trunk group id
+ * Output:
+ *      pEnable        - pointer of traffic pause state.
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_LA_TRUNK_ID  - invalid trunk ID
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Note:
+ *      None.
+ */
+rtk_api_ret_t rtk_trunk_trafficPause_get(rtk_trunk_group_t trk_gid, rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Trunk Group Valid */
+    RTK_CHK_TRUNK_GROUP_VALID(trk_gid);
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicTrunkingFc((rtk_uint32)trk_gid, (rtk_uint32 *)pEnable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trunk_hashMappingTable_set
+ * Description:
+ *      Set hash value to port array in the trunk group id from the specified device.
+ * Input:
+ *      trk_gid          - trunk group id
+ *      pHash2Port_array - ports associate with the hash value
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_UNIT_ID            - invalid unit id
+ *      RT_ERR_LA_TRUNK_ID        - invalid trunk ID
+ *      RT_ERR_NULL_POINTER       - input parameter may be null pointer
+ *      RT_ERR_LA_TRUNK_NOT_EXIST - the trunk doesn't exist
+ *      RT_ERR_LA_NOT_MEMBER_PORT - the port is not a member port of the trunk
+ *      RT_ERR_LA_CPUPORT         - CPU port can not be aggregated port
+ * Note:
+ *      Trunk group 0 & 1 shares the same hash mapping table.
+ *      Trunk group 2 uses a independent table.
+ */
+rtk_api_ret_t rtk_trunk_hashMappingTable_set(rtk_trunk_group_t trk_gid, rtk_trunk_hashVal2Port_t *pHash2Port_array)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 hashValue;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Trunk Group Valid */
+    RTK_CHK_TRUNK_GROUP_VALID(trk_gid);
+
+    if(NULL == pHash2Port_array)
+        return RT_ERR_NULL_POINTER;
+
+    if(trk_gid <= TRUNK_GROUP1)
+    {
+        for(hashValue = 0; hashValue < RTK_MAX_NUM_OF_TRUNK_HASH_VAL; hashValue++)
+        {
+            if ((retVal = rtl8367c_setAsicTrunkingHashTable(hashValue, pHash2Port_array->value[hashValue])) != RT_ERR_OK)
+                return retVal;
+        }
+    }
+    else
+    {
+        for(hashValue = 0; hashValue < RTK_MAX_NUM_OF_TRUNK_HASH_VAL; hashValue++)
+        {
+            if ((retVal = rtl8367c_setAsicTrunkingHashTable1(hashValue, pHash2Port_array->value[hashValue])) != RT_ERR_OK)
+                return retVal;
+        }
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trunk_hashMappingTable_get
+ * Description:
+ *      Get hash value to port array in the trunk group id from the specified device.
+ * Input:
+ *      trk_gid          - trunk group id
+ * Output:
+ *      pHash2Port_array - pointer buffer of ports associate with the hash value
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_UNIT_ID      - invalid unit id
+ *      RT_ERR_LA_TRUNK_ID  - invalid trunk ID
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Note:
+ *      Trunk group 0 & 1 shares the same hash mapping table.
+ *      Trunk group 2 uses a independent table.
+ */
+rtk_api_ret_t rtk_trunk_hashMappingTable_get(rtk_trunk_group_t trk_gid, rtk_trunk_hashVal2Port_t *pHash2Port_array)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 hashValue;
+    rtk_uint32 hashPort;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Trunk Group Valid */
+    RTK_CHK_TRUNK_GROUP_VALID(trk_gid);
+
+    if(NULL == pHash2Port_array)
+        return RT_ERR_NULL_POINTER;
+
+    if(trk_gid <= TRUNK_GROUP1)
+    {
+        for(hashValue = 0; hashValue < RTK_MAX_NUM_OF_TRUNK_HASH_VAL; hashValue++)
+        {
+            if ((retVal = rtl8367c_getAsicTrunkingHashTable(hashValue, &hashPort)) != RT_ERR_OK)
+                return retVal;
+
+            pHash2Port_array->value[hashValue] = hashPort;
+        }
+    }
+    else
+    {
+        for(hashValue = 0; hashValue < RTK_MAX_NUM_OF_TRUNK_HASH_VAL; hashValue++)
+        {
+            if ((retVal = rtl8367c_getAsicTrunkingHashTable1(hashValue, &hashPort)) != RT_ERR_OK)
+                return retVal;
+
+            pHash2Port_array->value[hashValue] = hashPort;
+        }
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_trunk_portQueueEmpty_get
+ * Description:
+ *      Get the port mask which all queues are empty.
+ * Input:
+ *      None.
+ * Output:
+ *      pEmpty_portmask   - pointer empty port mask
+ * Return:
+ *      RT_ERR_OK
+ *      RT_ERR_FAILED
+ *      RT_ERR_NULL_POINTER - input parameter may be null pointer
+ * Note:
+ *      None.
+ */
+rtk_api_ret_t rtk_trunk_portQueueEmpty_get(rtk_portmask_t *pEmpty_portmask)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 pmask;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pEmpty_portmask)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicQeueuEmptyStatus(&pmask)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtk_switch_portmask_P2L_get(pmask, pEmpty_portmask)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/vlan.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/vlan.c
new file mode 100644
index 0000000..f7480c4
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367c/vlan.c
@@ -0,0 +1,2124 @@
+/*
+ * Copyright (C) 2013 Realtek Semiconductor Corp.
+ * All Rights Reserved.
+ *
+ * Unless you and Realtek execute a separate written software license
+ * agreement governing use of this software, this software is licensed
+ * to you under the terms of the GNU General Public License version 2,
+ * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ *
+ * $Revision: 76306 $
+ * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $
+ *
+ * Purpose : RTK switch high-level API for RTL8367/RTL8367C
+ * Feature : Here is a list of all functions and variables in VLAN module.
+ *
+ */
+
+#include <rtk_switch.h>
+#include <rtk_error.h>
+#include <vlan.h>
+#include <rate.h>
+#include <string.h>
+
+#include <rtl8367c_asicdrv.h>
+#include <rtl8367c_asicdrv_vlan.h>
+#include <rtl8367c_asicdrv_dot1x.h>
+
+typedef enum vlan_mbrCfgType_e
+{
+    MBRCFG_UNUSED = 0,
+    MBRCFG_USED_BY_VLAN,
+    MBRCFG_END
+}vlan_mbrCfgType_t;
+
+static rtk_vlan_t           vlan_mbrCfgVid[RTL8367C_CVIDXNO];
+static vlan_mbrCfgType_t    vlan_mbrCfgUsage[RTL8367C_CVIDXNO];
+
+/* Function Name:
+ *      rtk_vlan_init
+ * Description:
+ *      Initialize VLAN.
+ * Input:
+ *      None
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ * Note:
+ *      VLAN is disabled by default. User has to call this API to enable VLAN before
+ *      using it. And It will set a default VLAN(vid 1) including all ports and set
+ *      all ports PVID to the default VLAN.
+ */
+rtk_api_ret_t rtk_vlan_init(void)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 i;
+    rtl8367c_user_vlan4kentry vlan4K;
+    rtl8367c_vlanconfiguser vlanMC;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Clean Database */
+    memset(vlan_mbrCfgVid, 0x00, sizeof(rtk_vlan_t) * RTL8367C_CVIDXNO);
+    memset(vlan_mbrCfgUsage, 0x00, sizeof(vlan_mbrCfgType_t) * RTL8367C_CVIDXNO);
+
+    /* clean 32 VLAN member configuration */
+    for (i = 0; i <= RTL8367C_CVIDXMAX; i++)
+    {
+        vlanMC.evid = 0;
+        vlanMC.mbr = 0;
+        vlanMC.fid_msti = 0;
+        vlanMC.envlanpol = 0;
+        vlanMC.meteridx = 0;
+        vlanMC.vbpen = 0;
+        vlanMC.vbpri = 0;
+        if ((retVal = rtl8367c_setAsicVlanMemberConfig(i, &vlanMC)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    /* Set a default VLAN with vid 1 to 4K table for all ports */
+    memset(&vlan4K, 0, sizeof(rtl8367c_user_vlan4kentry));
+    vlan4K.vid = 1;
+    vlan4K.mbr = RTK_PHY_PORTMASK_ALL;
+    vlan4K.untag = RTK_PHY_PORTMASK_ALL;
+    vlan4K.fid_msti = 0;
+    if ((retVal = rtl8367c_setAsicVlan4kEntry(&vlan4K)) != RT_ERR_OK)
+        return retVal;
+
+    /* Also set the default VLAN to 32 member configuration index 0 */
+    memset(&vlanMC, 0, sizeof(rtl8367c_vlanconfiguser));
+    vlanMC.evid = 1;
+    vlanMC.mbr = RTK_PHY_PORTMASK_ALL;
+    vlanMC.fid_msti = 0;
+    if ((retVal = rtl8367c_setAsicVlanMemberConfig(0, &vlanMC)) != RT_ERR_OK)
+            return retVal;
+
+    /* Set all ports PVID to default VLAN and tag-mode to original */
+    RTK_SCAN_ALL_PHY_PORTMASK(i)
+    {
+        if ((retVal = rtl8367c_setAsicVlanPortBasedVID(i, 0, 0)) != RT_ERR_OK)
+            return retVal;
+        if ((retVal = rtl8367c_setAsicVlanEgressTagMode(i, EG_TAG_MODE_ORI)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    /* Updata Databse */
+    vlan_mbrCfgUsage[0] = MBRCFG_USED_BY_VLAN;
+    vlan_mbrCfgVid[0] = 1;
+
+    /* Enable Ingress filter */
+    RTK_SCAN_ALL_PHY_PORTMASK(i)
+    {
+        if ((retVal = rtl8367c_setAsicVlanIngressFilter(i, ENABLED)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    /* enable VLAN */
+    if ((retVal = rtl8367c_setAsicVlanFilter(ENABLED)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_set
+ * Description:
+ *      Set a VLAN entry.
+ * Input:
+ *      vid - VLAN ID to configure.
+ *      pVlanCfg - VLAN Configuration
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_INPUT                - Invalid input parameters.
+ *      RT_ERR_L2_FID               - Invalid FID.
+ *      RT_ERR_VLAN_PORT_MBR_EXIST  - Invalid member port mask.
+ *      RT_ERR_VLAN_VID             - Invalid VID parameter.
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_vlan_set(rtk_vlan_t vid, rtk_vlan_cfg_t *pVlanCfg)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 phyMbrPmask;
+    rtk_uint32 phyUntagPmask;
+    rtl8367c_user_vlan4kentry vlan4K;
+    rtl8367c_vlanconfiguser vlanMC;
+    rtk_uint32 idx;
+    rtk_uint32 empty_index = 0xffff;
+    rtk_uint32 update_evid = 0;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* vid must be 0~8191 */
+    if (vid > RTL8367C_EVIDMAX)
+        return RT_ERR_VLAN_VID;
+
+    /* Null pointer check */
+    if(NULL == pVlanCfg)
+        return RT_ERR_NULL_POINTER;
+
+    /* Check port mask valid */
+    RTK_CHK_PORTMASK_VALID(&(pVlanCfg->mbr));
+
+    if (vid <= RTL8367C_VIDMAX)
+    {
+        /* Check untag port mask valid */
+        RTK_CHK_PORTMASK_VALID(&(pVlanCfg->untag));
+    }
+
+    /* IVL_EN */
+    if(pVlanCfg->ivl_en >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    /* fid must be 0~15 */
+    if(pVlanCfg->fid_msti > RTL8367C_FIDMAX)
+        return RT_ERR_L2_FID;
+
+    /* Policing */
+    if(pVlanCfg->envlanpol >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    /* Meter ID */
+    if(pVlanCfg->meteridx > RTK_MAX_METER_ID)
+        return RT_ERR_INPUT;
+
+    /* VLAN based priority */
+    if(pVlanCfg->vbpen >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    /* Priority */
+    if(pVlanCfg->vbpri > RTL8367C_PRIMAX)
+        return RT_ERR_INPUT;
+
+    /* Get physical port mask */
+    if(rtk_switch_portmask_L2P_get(&(pVlanCfg->mbr), &phyMbrPmask) != RT_ERR_OK)
+        return RT_ERR_FAILED;
+
+    if(rtk_switch_portmask_L2P_get(&(pVlanCfg->untag), &phyUntagPmask) != RT_ERR_OK)
+        return RT_ERR_FAILED;
+
+    if (vid <= RTL8367C_VIDMAX)
+    {
+        /* update 4K table */
+        memset(&vlan4K, 0, sizeof(rtl8367c_user_vlan4kentry));
+        vlan4K.vid = vid;
+
+        vlan4K.mbr    = (phyMbrPmask & 0xFFFF);
+        vlan4K.untag  = (phyUntagPmask & 0xFFFF);
+
+        vlan4K.ivl_svl      = pVlanCfg->ivl_en;
+        vlan4K.fid_msti     = pVlanCfg->fid_msti;
+        vlan4K.envlanpol    = pVlanCfg->envlanpol;
+        vlan4K.meteridx     = pVlanCfg->meteridx;
+        vlan4K.vbpen        = pVlanCfg->vbpen;
+        vlan4K.vbpri        = pVlanCfg->vbpri;
+
+        if ((retVal = rtl8367c_setAsicVlan4kEntry(&vlan4K)) != RT_ERR_OK)
+            return retVal;
+
+        /* Update Member configuration if exist */
+        for (idx = 0; idx <= RTL8367C_CVIDXMAX; idx++)
+        {
+            if(vlan_mbrCfgUsage[idx] == MBRCFG_USED_BY_VLAN)
+            {
+                if(vlan_mbrCfgVid[idx] == vid)
+                {
+                    /* Found! Update */
+                    if(phyMbrPmask == 0x00)
+                    {
+                        /* Member port = 0x00, delete this VLAN from Member Configuration */
+                        memset(&vlanMC, 0x00, sizeof(rtl8367c_vlanconfiguser));
+                        if ((retVal = rtl8367c_setAsicVlanMemberConfig(idx, &vlanMC)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* Clear Database */
+                        vlan_mbrCfgUsage[idx] = MBRCFG_UNUSED;
+                        vlan_mbrCfgVid[idx]   = 0;
+                    }
+                    else
+                    {
+                        /* Normal VLAN config, update to member configuration */
+                        vlanMC.evid = vid;
+                        vlanMC.mbr = vlan4K.mbr;
+                        vlanMC.fid_msti = vlan4K.fid_msti;
+                        vlanMC.meteridx = vlan4K.meteridx;
+                        vlanMC.envlanpol= vlan4K.envlanpol;
+                        vlanMC.vbpen = vlan4K.vbpen;
+                        vlanMC.vbpri = vlan4K.vbpri;
+                        if ((retVal = rtl8367c_setAsicVlanMemberConfig(idx, &vlanMC)) != RT_ERR_OK)
+                            return retVal;
+                    }
+
+                    break;
+                }
+            }
+        }
+    }
+    else
+    {
+        /* vid > 4095 */
+        for (idx = 0; idx <= RTL8367C_CVIDXMAX; idx++)
+        {
+            if(vlan_mbrCfgUsage[idx] == MBRCFG_USED_BY_VLAN)
+            {
+                if(vlan_mbrCfgVid[idx] == vid)
+                {
+                    /* Found! Update */
+                    if(phyMbrPmask == 0x00)
+                    {
+                        /* Member port = 0x00, delete this VLAN from Member Configuration */
+                        memset(&vlanMC, 0x00, sizeof(rtl8367c_vlanconfiguser));
+                        if ((retVal = rtl8367c_setAsicVlanMemberConfig(idx, &vlanMC)) != RT_ERR_OK)
+                            return retVal;
+
+                        /* Clear Database */
+                        vlan_mbrCfgUsage[idx] = MBRCFG_UNUSED;
+                        vlan_mbrCfgVid[idx]   = 0;
+                    }
+                    else
+                    {
+                        /* Normal VLAN config, update to member configuration */
+                        vlanMC.evid = vid;
+                        vlanMC.mbr = phyMbrPmask;
+                        vlanMC.fid_msti = pVlanCfg->fid_msti;
+                        vlanMC.meteridx = pVlanCfg->meteridx;
+                        vlanMC.envlanpol= pVlanCfg->envlanpol;
+                        vlanMC.vbpen = pVlanCfg->vbpen;
+                        vlanMC.vbpri = pVlanCfg->vbpri;
+                        if ((retVal = rtl8367c_setAsicVlanMemberConfig(idx, &vlanMC)) != RT_ERR_OK)
+                            return retVal;
+
+                        break;
+                    }
+
+                    update_evid = 1;
+                }
+            }
+
+            if(vlan_mbrCfgUsage[idx] == MBRCFG_UNUSED)
+            {
+                if(0xffff == empty_index)
+                    empty_index = idx;
+            }
+        }
+
+        /* doesn't find out same EVID entry and there is empty index in member configuration */
+        if( (phyMbrPmask != 0x00) && (update_evid == 0) && (empty_index != 0xFFFF) )
+        {
+            vlanMC.evid = vid;
+            vlanMC.mbr = phyMbrPmask;
+            vlanMC.fid_msti = pVlanCfg->fid_msti;
+            vlanMC.meteridx = pVlanCfg->meteridx;
+            vlanMC.envlanpol= pVlanCfg->envlanpol;
+            vlanMC.vbpen = pVlanCfg->vbpen;
+            vlanMC.vbpri = pVlanCfg->vbpri;
+            if ((retVal = rtl8367c_setAsicVlanMemberConfig(empty_index, &vlanMC)) != RT_ERR_OK)
+                return retVal;
+
+            vlan_mbrCfgUsage[empty_index] = MBRCFG_USED_BY_VLAN;
+            vlan_mbrCfgVid[empty_index] = vid;
+
+        }
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_get
+ * Description:
+ *      Get a VLAN entry.
+ * Input:
+ *      vid - VLAN ID to configure.
+ * Output:
+ *      pVlanCfg - VLAN Configuration
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_VLAN_VID     - Invalid VID parameter.
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_vlan_get(rtk_vlan_t vid, rtk_vlan_cfg_t *pVlanCfg)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 phyMbrPmask;
+    rtk_uint32 phyUntagPmask;
+    rtl8367c_user_vlan4kentry vlan4K;
+    rtl8367c_vlanconfiguser vlanMC;
+    rtk_uint32 idx;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* vid must be 0~8191 */
+    if (vid > RTL8367C_EVIDMAX)
+        return RT_ERR_VLAN_VID;
+
+    /* Null pointer check */
+    if(NULL == pVlanCfg)
+        return RT_ERR_NULL_POINTER;
+
+    if (vid <= RTL8367C_VIDMAX)
+    {
+        vlan4K.vid = vid;
+
+        if ((retVal = rtl8367c_getAsicVlan4kEntry(&vlan4K)) != RT_ERR_OK)
+            return retVal;
+
+        phyMbrPmask   = vlan4K.mbr;
+        phyUntagPmask = vlan4K.untag;
+        if(rtk_switch_portmask_P2L_get(phyMbrPmask, &(pVlanCfg->mbr)) != RT_ERR_OK)
+            return RT_ERR_FAILED;
+
+        if(rtk_switch_portmask_P2L_get(phyUntagPmask, &(pVlanCfg->untag)) != RT_ERR_OK)
+            return RT_ERR_FAILED;
+
+        pVlanCfg->ivl_en    = vlan4K.ivl_svl;
+        pVlanCfg->fid_msti  = vlan4K.fid_msti;
+        pVlanCfg->envlanpol = vlan4K.envlanpol;
+        pVlanCfg->meteridx  = vlan4K.meteridx;
+        pVlanCfg->vbpen     = vlan4K.vbpen;
+        pVlanCfg->vbpri     = vlan4K.vbpri;
+    }
+    else
+    {
+        for (idx = 0; idx <= RTL8367C_CVIDXMAX; idx++)
+        {
+            if(vlan_mbrCfgUsage[idx] == MBRCFG_USED_BY_VLAN)
+            {
+                if(vlan_mbrCfgVid[idx] == vid)
+                {
+                    if ((retVal = rtl8367c_getAsicVlanMemberConfig(idx, &vlanMC)) != RT_ERR_OK)
+                        return retVal;
+
+                    phyMbrPmask   = vlanMC.mbr;
+                    if(rtk_switch_portmask_P2L_get(phyMbrPmask, &(pVlanCfg->mbr)) != RT_ERR_OK)
+                        return RT_ERR_FAILED;
+
+                    pVlanCfg->untag.bits[0] = 0;
+                    pVlanCfg->ivl_en    = 0;
+                    pVlanCfg->fid_msti  = vlanMC.fid_msti;
+                    pVlanCfg->envlanpol = vlanMC.envlanpol;
+                    pVlanCfg->meteridx  = vlanMC.meteridx;
+                    pVlanCfg->vbpen     = vlanMC.vbpen;
+                    pVlanCfg->vbpri     = vlanMC.vbpri;
+                }
+            }
+        }
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_egrFilterEnable_set
+ * Description:
+ *      Set VLAN egress filter.
+ * Input:
+ *      egrFilter - Egress filtering
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_ENABLE       - Invalid input parameters.
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_vlan_egrFilterEnable_set(rtk_enable_t egrFilter)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(egrFilter >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    /* enable VLAN */
+    if ((retVal = rtl8367c_setAsicVlanFilter((rtk_uint32)egrFilter)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_egrFilterEnable_get
+ * Description:
+ *      Get VLAN egress filter.
+ * Input:
+ *      pEgrFilter - Egress filtering
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_NULL_POINTER - NULL Pointer.
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_vlan_egrFilterEnable_get(rtk_enable_t *pEgrFilter)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 state;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pEgrFilter)
+        return RT_ERR_NULL_POINTER;
+
+    /* enable VLAN */
+    if ((retVal = rtl8367c_getAsicVlanFilter(&state)) != RT_ERR_OK)
+        return retVal;
+
+    *pEgrFilter = (rtk_enable_t)state;
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_mbrCfg_set
+ * Description:
+ *      Set a VLAN Member Configuration entry by index.
+ * Input:
+ *      idx     - Index of VLAN Member Configuration.
+ *      pMbrcfg - VLAN member Configuration.
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_VLAN_VID     - Invalid VID parameter.
+ * Note:
+ *     Set a VLAN Member Configuration entry by index.
+ */
+rtk_api_ret_t rtk_vlan_mbrCfg_set(rtk_uint32 idx, rtk_vlan_mbrcfg_t *pMbrcfg)
+{
+    rtk_api_ret_t           retVal;
+    rtk_uint32              phyMbrPmask;
+    rtl8367c_vlanconfiguser mbrCfg;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Error check */
+    if(pMbrcfg == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    if(idx > RTL8367C_CVIDXMAX)
+        return RT_ERR_INPUT;
+
+    if(pMbrcfg->evid > RTL8367C_EVIDMAX)
+        return RT_ERR_INPUT;
+
+    if(pMbrcfg->fid_msti > RTL8367C_FIDMAX)
+        return RT_ERR_L2_FID;
+
+    if(pMbrcfg->envlanpol >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if(pMbrcfg->meteridx > RTK_MAX_METER_ID)
+        return RT_ERR_FILTER_METER_ID;
+
+    if(pMbrcfg->vbpen >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if(pMbrcfg->vbpri > RTL8367C_PRIMAX)
+        return RT_ERR_QOS_INT_PRIORITY;
+
+    /* Check port mask valid */
+    RTK_CHK_PORTMASK_VALID(&(pMbrcfg->mbr));
+
+    mbrCfg.evid         = pMbrcfg->evid;
+    mbrCfg.fid_msti     = pMbrcfg->fid_msti;
+    mbrCfg.envlanpol    = pMbrcfg->envlanpol;
+    mbrCfg.meteridx     = pMbrcfg->meteridx;
+    mbrCfg.vbpen        = pMbrcfg->vbpen;
+    mbrCfg.vbpri        = pMbrcfg->vbpri;
+
+    if(rtk_switch_portmask_L2P_get(&(pMbrcfg->mbr), &phyMbrPmask) != RT_ERR_OK)
+        return RT_ERR_FAILED;
+
+    mbrCfg.mbr = phyMbrPmask;
+
+    if ((retVal = rtl8367c_setAsicVlanMemberConfig(idx, &mbrCfg)) != RT_ERR_OK)
+        return retVal;
+
+    /* Update Database */
+    if( (mbrCfg.evid == 0) && (mbrCfg.mbr == 0) )
+    {
+        vlan_mbrCfgUsage[idx] = MBRCFG_UNUSED;
+        vlan_mbrCfgVid[idx] = 0;
+    }
+    else
+    {
+        vlan_mbrCfgUsage[idx] = MBRCFG_USED_BY_VLAN;
+        vlan_mbrCfgVid[idx] = mbrCfg.evid;
+    }
+
+    return RT_ERR_OK;
+
+}
+
+/* Function Name:
+ *      rtk_vlan_mbrCfg_get
+ * Description:
+ *      Get a VLAN Member Configuration entry by index.
+ * Input:
+ *      idx - Index of VLAN Member Configuration.
+ * Output:
+ *      pMbrcfg - VLAN member Configuration.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_VLAN_VID     - Invalid VID parameter.
+ * Note:
+ *     Get a VLAN Member Configuration entry by index.
+ */
+rtk_api_ret_t rtk_vlan_mbrCfg_get(rtk_uint32 idx, rtk_vlan_mbrcfg_t *pMbrcfg)
+{
+    rtk_api_ret_t           retVal;
+    rtk_uint32              phyMbrPmask;
+    rtl8367c_vlanconfiguser mbrCfg;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Error check */
+    if(pMbrcfg == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    if(idx > RTL8367C_CVIDXMAX)
+        return RT_ERR_INPUT;
+
+    memset(&mbrCfg, 0x00, sizeof(rtl8367c_vlanconfiguser));
+    if ((retVal = rtl8367c_getAsicVlanMemberConfig(idx, &mbrCfg)) != RT_ERR_OK)
+        return retVal;
+
+    pMbrcfg->evid       = mbrCfg.evid;
+    pMbrcfg->fid_msti   = mbrCfg.fid_msti;
+    pMbrcfg->envlanpol  = mbrCfg.envlanpol;
+    pMbrcfg->meteridx   = mbrCfg.meteridx;
+    pMbrcfg->vbpen      = mbrCfg.vbpen;
+    pMbrcfg->vbpri      = mbrCfg.vbpri;
+
+    phyMbrPmask = mbrCfg.mbr;
+    if(rtk_switch_portmask_P2L_get(phyMbrPmask, &(pMbrcfg->mbr)) != RT_ERR_OK)
+        return RT_ERR_FAILED;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *     rtk_vlan_portPvid_set
+ * Description:
+ *      Set port to specified VLAN ID(PVID).
+ * Input:
+ *      port - Port id.
+ *      pvid - Specified VLAN ID.
+ *      priority - 802.1p priority for the PVID.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                   - OK
+ *      RT_ERR_FAILED               - Failed
+ *      RT_ERR_SMI                  - SMI access error
+ *      RT_ERR_PORT_ID              - Invalid port number.
+ *      RT_ERR_VLAN_PRIORITY        - Invalid priority.
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND - VLAN entry not found.
+ *      RT_ERR_VLAN_VID             - Invalid VID parameter.
+ * Note:
+ *       The API is used for Port-based VLAN. The untagged frame received from the
+ *       port will be classified to the specified VLAN and assigned to the specified priority.
+ */
+rtk_api_ret_t rtk_vlan_portPvid_set(rtk_port_t port, rtk_vlan_t pvid, rtk_pri_t priority)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 index;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    /* vid must be 0~8191 */
+    if (pvid > RTL8367C_EVIDMAX)
+        return RT_ERR_VLAN_VID;
+
+    /* priority must be 0~7 */
+    if (priority > RTL8367C_PRIMAX)
+        return RT_ERR_VLAN_PRIORITY;
+
+    if((retVal = rtk_vlan_checkAndCreateMbr(pvid, &index)) != RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicVlanPortBasedVID(rtk_switch_port_L2P_get(port), index, priority)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_portPvid_get
+ * Description:
+ *      Get VLAN ID(PVID) on specified port.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pPvid - Specified VLAN ID.
+ *      pPriority - 802.1p priority for the PVID.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *     The API can get the PVID and 802.1p priority for the PVID of Port-based VLAN.
+ */
+rtk_api_ret_t rtk_vlan_portPvid_get(rtk_port_t port, rtk_vlan_t *pPvid, rtk_pri_t *pPriority)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 index, pri;
+    rtl8367c_vlanconfiguser mbrCfg;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pPvid)
+        return RT_ERR_NULL_POINTER;
+
+    if(NULL == pPriority)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicVlanPortBasedVID(rtk_switch_port_L2P_get(port), &index, &pri)) != RT_ERR_OK)
+        return retVal;
+
+    memset(&mbrCfg, 0x00, sizeof(rtl8367c_vlanconfiguser));
+    if ((retVal = rtl8367c_getAsicVlanMemberConfig(index, &mbrCfg)) != RT_ERR_OK)
+        return retVal;
+
+    *pPvid = mbrCfg.evid;
+    *pPriority = pri;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_portIgrFilterEnable_set
+ * Description:
+ *      Set VLAN ingress for each port.
+ * Input:
+ *      port - Port id.
+ *      igr_filter - VLAN ingress function enable status.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number
+ *      RT_ERR_ENABLE       - Invalid enable input
+ * Note:
+ *      The status of vlan ingress filter is as following:
+ *      - DISABLED
+ *      - ENABLED
+ *      While VLAN function is enabled, ASIC will decide VLAN ID for each received frame and get belonged member
+ *      ports from VLAN table. If received port is not belonged to VLAN member ports, ASIC will drop received frame if VLAN ingress function is enabled.
+ */
+rtk_api_ret_t rtk_vlan_portIgrFilterEnable_set(rtk_port_t port, rtk_enable_t igr_filter)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (igr_filter >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if ((retVal = rtl8367c_setAsicVlanIngressFilter(rtk_switch_port_L2P_get(port), igr_filter)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_portIgrFilterEnable_get
+ * Description:
+ *      Get VLAN Ingress Filter
+ * Input:
+ *      port        - Port id.
+ * Output:
+ *      pIgr_filter - VLAN ingress function enable status.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *     The API can Get the VLAN ingress filter status.
+ *     The status of vlan ingress filter is as following:
+ *     - DISABLED
+ *     - ENABLED
+ */
+rtk_api_ret_t rtk_vlan_portIgrFilterEnable_get(rtk_port_t port, rtk_enable_t *pIgr_filter)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pIgr_filter)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicVlanIngressFilter(rtk_switch_port_L2P_get(port), pIgr_filter)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_portAcceptFrameType_set
+ * Description:
+ *      Set VLAN accept_frame_type
+ * Input:
+ *      port                - Port id.
+ *      accept_frame_type   - accept frame type
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK                       - OK
+ *      RT_ERR_FAILED                   - Failed
+ *      RT_ERR_SMI                      - SMI access error
+ *      RT_ERR_PORT_ID                  - Invalid port number.
+ *      RT_ERR_VLAN_ACCEPT_FRAME_TYPE   - Invalid frame type.
+ * Note:
+ *      The API is used for checking 802.1Q tagged frames.
+ *      The accept frame type as following:
+ *      - ACCEPT_FRAME_TYPE_ALL
+ *      - ACCEPT_FRAME_TYPE_TAG_ONLY
+ *      - ACCEPT_FRAME_TYPE_UNTAG_ONLY
+ */
+rtk_api_ret_t rtk_vlan_portAcceptFrameType_set(rtk_port_t port, rtk_vlan_acceptFrameType_t accept_frame_type)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (accept_frame_type >= ACCEPT_FRAME_TYPE_END)
+        return RT_ERR_VLAN_ACCEPT_FRAME_TYPE;
+
+    if ((retVal = rtl8367c_setAsicVlanAccpetFrameType(rtk_switch_port_L2P_get(port), (rtl8367c_accframetype)accept_frame_type)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_portAcceptFrameType_get
+ * Description:
+ *      Get VLAN accept_frame_type
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pAccept_frame_type - accept frame type
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *     The API can Get the VLAN ingress filter.
+ *     The accept frame type as following:
+ *     - ACCEPT_FRAME_TYPE_ALL
+ *     - ACCEPT_FRAME_TYPE_TAG_ONLY
+ *     - ACCEPT_FRAME_TYPE_UNTAG_ONLY
+ */
+rtk_api_ret_t rtk_vlan_portAcceptFrameType_get(rtk_port_t port, rtk_vlan_acceptFrameType_t *pAccept_frame_type)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_accframetype   acc_frm_type;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pAccept_frame_type)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicVlanAccpetFrameType(rtk_switch_port_L2P_get(port), &acc_frm_type)) != RT_ERR_OK)
+        return retVal;
+
+    *pAccept_frame_type = (rtk_vlan_acceptFrameType_t)acc_frm_type;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_protoAndPortBasedVlan_add
+ * Description:
+ *      Add the protocol-and-port-based vlan to the specified port of device.
+ * Input:
+ *      port  - Port id.
+ *      pInfo - Protocol and port based VLAN configuration information.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_VLAN_VID         - Invalid VID parameter.
+ *      RT_ERR_VLAN_PRIORITY    - Invalid priority.
+ *      RT_ERR_TBL_FULL         - Table is full.
+ *      RT_ERR_OUT_OF_RANGE     - input out of range.
+ * Note:
+ *      The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline
+ *      The frame type is shown in the following:
+ *      - FRAME_TYPE_ETHERNET
+ *      - FRAME_TYPE_RFC1042
+ *      - FRAME_TYPE_LLCOTHER
+ */
+rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_add(rtk_port_t port, rtk_vlan_protoAndPortInfo_t *pInfo)
+{
+    rtk_api_ret_t retVal, i;
+    rtk_uint32 exist, empty, used, index;
+    rtl8367c_protocolgdatacfg ppb_data_cfg;
+    rtl8367c_protocolvlancfg ppb_vlan_cfg;
+    rtl8367c_provlan_frametype tmp;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pInfo)
+        return RT_ERR_NULL_POINTER;
+
+    if (pInfo->proto_type > RTK_MAX_NUM_OF_PROTO_TYPE)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if (pInfo->frame_type >= FRAME_TYPE_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if (pInfo->cvid > RTL8367C_VIDMAX)
+        return RT_ERR_VLAN_VID;
+
+    if (pInfo->cpri > RTL8367C_PRIMAX)
+        return RT_ERR_VLAN_PRIORITY;
+
+    exist = 0xFF;
+    empty = 0xFF;
+    for (i = RTL8367C_PROTOVLAN_GIDX_MAX; i >= 0; i--)
+    {
+        if ((retVal = rtl8367c_getAsicVlanProtocolBasedGroupData(i, &ppb_data_cfg)) != RT_ERR_OK)
+            return retVal;
+        tmp = pInfo->frame_type;
+        if (ppb_data_cfg.etherType == pInfo->proto_type && ppb_data_cfg.frameType == tmp)
+        {
+            /*Already exist*/
+            exist = i;
+            break;
+        }
+        else if (ppb_data_cfg.etherType == 0 && ppb_data_cfg.frameType == 0)
+        {
+            /*find empty index*/
+            empty = i;
+        }
+    }
+
+    used = 0xFF;
+    /*No empty and exist index*/
+    if (0xFF == exist && 0xFF == empty)
+        return RT_ERR_TBL_FULL;
+    else if (exist<RTL8367C_PROTOVLAN_GROUPNO)
+    {
+       /*exist index*/
+       used = exist;
+    }
+    else if (empty<RTL8367C_PROTOVLAN_GROUPNO)
+    {
+        /*No exist index, but have empty index*/
+        ppb_data_cfg.frameType = pInfo->frame_type;
+        ppb_data_cfg.etherType = pInfo->proto_type;
+        if ((retVal = rtl8367c_setAsicVlanProtocolBasedGroupData(empty, &ppb_data_cfg)) != RT_ERR_OK)
+            return retVal;
+        used = empty;
+    }
+    else
+        return RT_ERR_FAILED;
+
+    if((retVal = rtk_vlan_checkAndCreateMbr(pInfo->cvid, &index)) != RT_ERR_OK)
+        return retVal;
+
+    ppb_vlan_cfg.vlan_idx = index;
+    ppb_vlan_cfg.valid = TRUE;
+    ppb_vlan_cfg.priority = pInfo->cpri;
+    if ((retVal = rtl8367c_setAsicVlanPortAndProtocolBased(rtk_switch_port_L2P_get(port), used, &ppb_vlan_cfg)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_protoAndPortBasedVlan_get
+ * Description:
+ *      Get the protocol-and-port-based vlan to the specified port of device.
+ * Input:
+ *      port - Port id.
+ *      proto_type - protocol-and-port-based vlan protocol type.
+ *      frame_type - protocol-and-port-based vlan frame type.
+ * Output:
+ *      pInfo - Protocol and port based VLAN configuration information.
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_OUT_OF_RANGE     - input out of range.
+ *      RT_ERR_TBL_FULL         - Table is full.
+ * Note:
+ *     The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline
+ *     The frame type is shown in the following:
+ *      - FRAME_TYPE_ETHERNET
+ *      - FRAME_TYPE_RFC1042
+ *      - FRAME_TYPE_LLCOTHER
+ */
+rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_get(rtk_port_t port, rtk_vlan_proto_type_t proto_type, rtk_vlan_protoVlan_frameType_t frame_type, rtk_vlan_protoAndPortInfo_t *pInfo)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 i;
+    rtk_uint32 ppb_idx;
+    rtl8367c_protocolgdatacfg ppb_data_cfg;
+    rtl8367c_protocolvlancfg ppb_vlan_cfg;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (proto_type > RTK_MAX_NUM_OF_PROTO_TYPE)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if (frame_type >= FRAME_TYPE_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+   ppb_idx = 0;
+
+    for (i = 0; i<= RTL8367C_PROTOVLAN_GIDX_MAX; i++)
+    {
+        if ((retVal = rtl8367c_getAsicVlanProtocolBasedGroupData(i, &ppb_data_cfg)) != RT_ERR_OK)
+            return retVal;
+
+        if ( (ppb_data_cfg.frameType == (rtl8367c_provlan_frametype)frame_type) && (ppb_data_cfg.etherType == proto_type) )
+        {
+            ppb_idx = i;
+            break;
+        }
+        else if (RTL8367C_PROTOVLAN_GIDX_MAX == i)
+            return RT_ERR_TBL_FULL;
+    }
+
+    if ((retVal = rtl8367c_getAsicVlanPortAndProtocolBased(rtk_switch_port_L2P_get(port), ppb_idx, &ppb_vlan_cfg)) != RT_ERR_OK)
+        return retVal;
+
+    if (FALSE == ppb_vlan_cfg.valid)
+        return RT_ERR_FAILED;
+
+    pInfo->frame_type = frame_type;
+    pInfo->proto_type = proto_type;
+    pInfo->cvid = vlan_mbrCfgVid[ppb_vlan_cfg.vlan_idx];
+    pInfo->cpri = ppb_vlan_cfg.priority;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_protoAndPortBasedVlan_del
+ * Description:
+ *      Delete the protocol-and-port-based vlan from the specified port of device.
+ * Input:
+ *      port        - Port id.
+ *      proto_type  - protocol-and-port-based vlan protocol type.
+ *      frame_type  - protocol-and-port-based vlan frame type.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_OUT_OF_RANGE     - input out of range.
+ *      RT_ERR_TBL_FULL         - Table is full.
+ * Note:
+ *     The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline
+ *     The frame type is shown in the following:
+ *      - FRAME_TYPE_ETHERNET
+ *      - FRAME_TYPE_RFC1042
+ *      - FRAME_TYPE_LLCOTHER
+ */
+rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_del(rtk_port_t port, rtk_vlan_proto_type_t proto_type, rtk_vlan_protoVlan_frameType_t frame_type)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 i, bUsed;
+    rtk_uint32 ppb_idx;
+    rtl8367c_protocolgdatacfg ppb_data_cfg;
+    rtl8367c_protocolvlancfg ppb_vlan_cfg;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (proto_type > RTK_MAX_NUM_OF_PROTO_TYPE)
+        return RT_ERR_OUT_OF_RANGE;
+
+    if (frame_type >= FRAME_TYPE_END)
+        return RT_ERR_OUT_OF_RANGE;
+
+   ppb_idx = 0;
+
+    for (i = 0; i<= RTL8367C_PROTOVLAN_GIDX_MAX; i++)
+    {
+        if ((retVal = rtl8367c_getAsicVlanProtocolBasedGroupData(i, &ppb_data_cfg)) != RT_ERR_OK)
+            return retVal;
+
+        if ( (ppb_data_cfg.frameType == (rtl8367c_provlan_frametype)frame_type) && (ppb_data_cfg.etherType == proto_type) )
+        {
+            ppb_idx = i;
+            ppb_vlan_cfg.valid = FALSE;
+            ppb_vlan_cfg.vlan_idx = 0;
+            ppb_vlan_cfg.priority = 0;
+            if ((retVal = rtl8367c_setAsicVlanPortAndProtocolBased(rtk_switch_port_L2P_get(port), ppb_idx, &ppb_vlan_cfg)) != RT_ERR_OK)
+                return retVal;
+        }
+    }
+
+    bUsed = FALSE;
+    RTK_SCAN_ALL_PHY_PORTMASK(i)
+    {
+        if ((retVal = rtl8367c_getAsicVlanPortAndProtocolBased(i, ppb_idx, &ppb_vlan_cfg)) != RT_ERR_OK)
+            return retVal;
+
+        if (TRUE == ppb_vlan_cfg.valid)
+        {
+            bUsed = TRUE;
+                break;
+        }
+    }
+
+    if (FALSE == bUsed) /*No Port use this PPB Index, Delete it*/
+    {
+        ppb_data_cfg.etherType=0;
+        ppb_data_cfg.frameType=0;
+        if ((retVal = rtl8367c_setAsicVlanProtocolBasedGroupData(ppb_idx, &ppb_data_cfg)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_protoAndPortBasedVlan_delAll
+ * Description:
+ *     Delete all protocol-and-port-based vlans from the specified port of device.
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK               - OK
+ *      RT_ERR_FAILED           - Failed
+ *      RT_ERR_SMI              - SMI access error
+ *      RT_ERR_PORT_ID          - Invalid port number.
+ *      RT_ERR_OUT_OF_RANGE     - input out of range.
+ * Note:
+ *     The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline
+ *     Delete all flow table protocol-and-port-based vlan entries.
+ */
+rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_delAll(rtk_port_t port)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32 i, j, bUsed[4];
+    rtl8367c_protocolgdatacfg ppb_data_cfg;
+    rtl8367c_protocolvlancfg ppb_vlan_cfg;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    for (i = 0; i<= RTL8367C_PROTOVLAN_GIDX_MAX; i++)
+    {
+        ppb_vlan_cfg.valid = FALSE;
+        ppb_vlan_cfg.vlan_idx = 0;
+        ppb_vlan_cfg.priority = 0;
+        if ((retVal = rtl8367c_setAsicVlanPortAndProtocolBased(rtk_switch_port_L2P_get(port), i, &ppb_vlan_cfg)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    bUsed[0] = FALSE;
+    bUsed[1] = FALSE;
+    bUsed[2] = FALSE;
+    bUsed[3] = FALSE;
+    RTK_SCAN_ALL_PHY_PORTMASK(i)
+    {
+        for (j = 0; j <= RTL8367C_PROTOVLAN_GIDX_MAX; j++)
+        {
+            if ((retVal = rtl8367c_getAsicVlanPortAndProtocolBased(i,j, &ppb_vlan_cfg)) != RT_ERR_OK)
+                return retVal;
+
+            if (TRUE == ppb_vlan_cfg.valid)
+            {
+                bUsed[j] = TRUE;
+            }
+        }
+    }
+
+    for (i = 0; i<= RTL8367C_PROTOVLAN_GIDX_MAX; i++)
+    {
+        if (FALSE == bUsed[i]) /*No Port use this PPB Index, Delete it*/
+        {
+            ppb_data_cfg.etherType=0;
+            ppb_data_cfg.frameType=0;
+            if ((retVal = rtl8367c_setAsicVlanProtocolBasedGroupData(i, &ppb_data_cfg)) != RT_ERR_OK)
+                return retVal;
+        }
+    }
+
+
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_tagMode_set
+ * Description:
+ *      Set CVLAN egress tag mode
+ * Input:
+ *      port        - Port id.
+ *      tag_mode    - The egress tag mode.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ *      RT_ERR_ENABLE       - Invalid enable input.
+ * Note:
+ *      The API can set Egress tag mode. There are 4 mode for egress tag:
+ *      - VLAN_TAG_MODE_ORIGINAL,
+ *      - VLAN_TAG_MODE_KEEP_FORMAT,
+ *      - VLAN_TAG_MODE_PRI.
+ *      - VLAN_TAG_MODE_REAL_KEEP_FORMAT,
+ */
+rtk_api_ret_t rtk_vlan_tagMode_set(rtk_port_t port, rtk_vlan_tagMode_t tag_mode)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (tag_mode >= VLAN_TAG_MODE_END)
+        return RT_ERR_PORT_ID;
+
+    if ((retVal = rtl8367c_setAsicVlanEgressTagMode(rtk_switch_port_L2P_get(port), tag_mode)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_tagMode_get
+ * Description:
+ *      Get CVLAN egress tag mode
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pTag_mode - The egress tag mode.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      The API can get Egress tag mode. There are 4 mode for egress tag:
+ *      - VLAN_TAG_MODE_ORIGINAL,
+ *      - VLAN_TAG_MODE_KEEP_FORMAT,
+ *      - VLAN_TAG_MODE_PRI.
+ *      - VLAN_TAG_MODE_REAL_KEEP_FORMAT,
+ */
+rtk_api_ret_t rtk_vlan_tagMode_get(rtk_port_t port, rtk_vlan_tagMode_t *pTag_mode)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_egtagmode  mode;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pTag_mode)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicVlanEgressTagMode(rtk_switch_port_L2P_get(port), &mode)) != RT_ERR_OK)
+        return retVal;
+
+    *pTag_mode = (rtk_vlan_tagMode_t)mode;
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_transparent_set
+ * Description:
+ *      Set VLAN transparent mode
+ * Input:
+ *      egr_port        - Egress Port id.
+ *      pIgr_pmask      - Ingress Port Mask.
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      None.
+ */
+rtk_api_ret_t rtk_vlan_transparent_set(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask)
+{
+     rtk_api_ret_t retVal;
+     rtk_uint32    pmask;
+
+     /* Check initialization state */
+     RTK_CHK_INIT_STATE();
+
+     /* Check Port Valid */
+     RTK_CHK_PORT_VALID(egr_port);
+
+     if(NULL == pIgr_pmask)
+        return RT_ERR_NULL_POINTER;
+
+     RTK_CHK_PORTMASK_VALID(pIgr_pmask);
+
+     if(rtk_switch_portmask_L2P_get(pIgr_pmask, &pmask) != RT_ERR_OK)
+        return RT_ERR_FAILED;
+
+     if ((retVal = rtl8367c_setAsicVlanTransparent(rtk_switch_port_L2P_get(egr_port), pmask)) != RT_ERR_OK)
+         return retVal;
+
+     return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_transparent_get
+ * Description:
+ *      Get VLAN transparent mode
+ * Input:
+ *      egr_port        - Egress Port id.
+ * Output:
+ *      pIgr_pmask      - Ingress Port Mask
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      None.
+ */
+rtk_api_ret_t rtk_vlan_transparent_get(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask)
+{
+     rtk_api_ret_t retVal;
+     rtk_uint32    pmask;
+
+     /* Check initialization state */
+     RTK_CHK_INIT_STATE();
+
+     /* Check Port Valid */
+     RTK_CHK_PORT_VALID(egr_port);
+
+     if(NULL == pIgr_pmask)
+        return RT_ERR_NULL_POINTER;
+
+     if ((retVal = rtl8367c_getAsicVlanTransparent(rtk_switch_port_L2P_get(egr_port), &pmask)) != RT_ERR_OK)
+         return retVal;
+
+     if(rtk_switch_portmask_P2L_get(pmask, pIgr_pmask) != RT_ERR_OK)
+        return RT_ERR_FAILED;
+
+     return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_keep_set
+ * Description:
+ *      Set VLAN egress keep mode
+ * Input:
+ *      egr_port        - Egress Port id.
+ *      pIgr_pmask      - Ingress Port Mask.
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      None.
+ */
+rtk_api_ret_t rtk_vlan_keep_set(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask)
+{
+     rtk_api_ret_t retVal;
+     rtk_uint32    pmask;
+
+     /* Check initialization state */
+     RTK_CHK_INIT_STATE();
+
+     /* Check Port Valid */
+     RTK_CHK_PORT_VALID(egr_port);
+
+     if(NULL == pIgr_pmask)
+        return RT_ERR_NULL_POINTER;
+
+     RTK_CHK_PORTMASK_VALID(pIgr_pmask);
+
+     if(rtk_switch_portmask_L2P_get(pIgr_pmask, &pmask) != RT_ERR_OK)
+        return RT_ERR_FAILED;
+
+     if ((retVal = rtl8367c_setAsicVlanEgressKeep(rtk_switch_port_L2P_get(egr_port), pmask)) != RT_ERR_OK)
+         return retVal;
+
+     return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_keep_get
+ * Description:
+ *      Get VLAN egress keep mode
+ * Input:
+ *      egr_port        - Egress Port id.
+ * Output:
+ *      pIgr_pmask      - Ingress Port Mask
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ * Note:
+ *      None.
+ */
+rtk_api_ret_t rtk_vlan_keep_get(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask)
+{
+     rtk_api_ret_t retVal;
+     rtk_uint32    pmask;
+
+     /* Check initialization state */
+     RTK_CHK_INIT_STATE();
+
+     /* Check Port Valid */
+     RTK_CHK_PORT_VALID(egr_port);
+
+     if(NULL == pIgr_pmask)
+        return RT_ERR_NULL_POINTER;
+
+     if ((retVal = rtl8367c_getAsicVlanEgressKeep(rtk_switch_port_L2P_get(egr_port), &pmask)) != RT_ERR_OK)
+         return retVal;
+
+     if(rtk_switch_portmask_P2L_get(pmask, pIgr_pmask) != RT_ERR_OK)
+        return RT_ERR_FAILED;
+
+     return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_stg_set
+ * Description:
+ *      Set spanning tree group instance of the vlan to the specified device
+ * Input:
+ *      vid - Specified VLAN ID.
+ *      stg - spanning tree group instance.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_MSTI         - Invalid msti parameter
+ *      RT_ERR_INPUT        - Invalid input parameter.
+ *      RT_ERR_VLAN_VID     - Invalid VID parameter.
+ * Note:
+ *      The API can set spanning tree group instance of the vlan to the specified device.
+ */
+rtk_api_ret_t rtk_vlan_stg_set(rtk_vlan_t vid, rtk_stp_msti_id_t stg)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_user_vlan4kentry vlan4K;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* vid must be 0~4095 */
+    if (vid > RTL8367C_VIDMAX)
+        return RT_ERR_VLAN_VID;
+
+    /* priority must be 0~15 */
+    if (stg > RTL8367C_MSTIMAX)
+        return RT_ERR_MSTI;
+
+    /* update 4K table */
+    vlan4K.vid = vid;
+    if ((retVal = rtl8367c_getAsicVlan4kEntry(&vlan4K)) != RT_ERR_OK)
+        return retVal;
+
+    vlan4K.fid_msti= stg;
+    if ((retVal = rtl8367c_setAsicVlan4kEntry(&vlan4K)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_stg_get
+ * Description:
+ *      Get spanning tree group instance of the vlan to the specified device
+ * Input:
+ *      vid - Specified VLAN ID.
+ * Output:
+ *      pStg - spanning tree group instance.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Invalid input parameters.
+ *      RT_ERR_VLAN_VID     - Invalid VID parameter.
+ * Note:
+ *      The API can get spanning tree group instance of the vlan to the specified device.
+ */
+rtk_api_ret_t rtk_vlan_stg_get(rtk_vlan_t vid, rtk_stp_msti_id_t *pStg)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_user_vlan4kentry vlan4K;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* vid must be 0~4095 */
+    if (vid > RTL8367C_VIDMAX)
+        return RT_ERR_VLAN_VID;
+
+    if(NULL == pStg)
+        return RT_ERR_NULL_POINTER;
+
+    /* update 4K table */
+    vlan4K.vid = vid;
+    if ((retVal = rtl8367c_getAsicVlan4kEntry(&vlan4K)) != RT_ERR_OK)
+        return retVal;
+
+    *pStg = vlan4K.fid_msti;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_portFid_set
+ * Description:
+ *      Set port-based filtering database
+ * Input:
+ *      port - Port id.
+ *      enable - ebable port-based FID
+ *      fid - Specified filtering database.
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_L2_FID - Invalid fid.
+ *      RT_ERR_INPUT - Invalid input parameter.
+ *      RT_ERR_PORT_ID - Invalid port ID.
+ * Note:
+ *      The API can set port-based filtering database. If the function is enabled, all input
+ *      packets will be assigned to the port-based fid regardless vlan tag.
+ */
+rtk_api_ret_t rtk_vlan_portFid_set(rtk_port_t port, rtk_enable_t enable, rtk_fid_t fid)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (enable>=RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    /* fid must be 0~4095 */
+    if (fid > RTK_FID_MAX)
+        return RT_ERR_L2_FID;
+
+    if ((retVal = rtl8367c_setAsicPortBasedFidEn(rtk_switch_port_L2P_get(port), enable))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_setAsicPortBasedFid(rtk_switch_port_L2P_get(port), fid))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_portFid_get
+ * Description:
+ *      Get port-based filtering database
+ * Input:
+ *      port - Port id.
+ * Output:
+ *      pEnable - ebable port-based FID
+ *      pFid - Specified filtering database.
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_INPUT - Invalid input parameters.
+ *      RT_ERR_PORT_ID - Invalid port ID.
+ * Note:
+ *      The API can get port-based filtering database status. If the function is enabled, all input
+ *      packets will be assigned to the port-based fid regardless vlan tag.
+ */
+rtk_api_ret_t rtk_vlan_portFid_get(rtk_port_t port, rtk_enable_t *pEnable, rtk_fid_t *pFid)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if(NULL == pFid)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicPortBasedFidEn(rtk_switch_port_L2P_get(port), pEnable))!=RT_ERR_OK)
+        return retVal;
+
+    if ((retVal = rtl8367c_getAsicPortBasedFid(rtk_switch_port_L2P_get(port), pFid))!=RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_UntagDscpPriorityEnable_set
+ * Description:
+ *      Set Untag DSCP priority assign
+ * Input:
+ *      enable - state of Untag DSCP priority assign
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_ENABLE          - Invalid input parameters.
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_vlan_UntagDscpPriorityEnable_set(rtk_enable_t enable)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(enable >= RTK_ENABLE_END)
+        return RT_ERR_ENABLE;
+
+    if ((retVal = rtl8367c_setAsicVlanUntagDscpPriorityEn((rtk_uint32)enable)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_UntagDscpPriorityEnable_get
+ * Description:
+ *      Get Untag DSCP priority assign
+ * Input:
+ *      None
+ * Output:
+ *      pEnable - state of Untag DSCP priority assign
+ * Return:
+ *      RT_ERR_OK              - OK
+ *      RT_ERR_FAILED          - Failed
+ *      RT_ERR_SMI             - SMI access error
+ *      RT_ERR_NULL_POINTER    - Null pointer
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_vlan_UntagDscpPriorityEnable_get(rtk_enable_t *pEnable)
+{
+    rtk_api_ret_t retVal;
+    rtk_uint32  value;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pEnable)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicVlanUntagDscpPriorityEn(&value)) != RT_ERR_OK)
+        return retVal;
+
+    *pEnable = (rtk_enable_t)value;
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_stp_mstpState_set
+ * Description:
+ *      Configure spanning tree state per each port.
+ * Input:
+ *      port - Port id
+ *      msti - Multiple spanning tree instance.
+ *      stp_state - Spanning tree state for msti
+ * Output:
+ *      None
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_MSTI         - Invalid msti parameter.
+ *      RT_ERR_MSTP_STATE   - Invalid STP state.
+ * Note:
+ *      System supports per-port multiple spanning tree state for each msti.
+ *      There are four states supported by ASIC.
+ *      - STP_STATE_DISABLED
+ *      - STP_STATE_BLOCKING
+ *      - STP_STATE_LEARNING
+ *      - STP_STATE_FORWARDING
+ */
+rtk_api_ret_t rtk_stp_mstpState_set(rtk_stp_msti_id_t msti, rtk_port_t port, rtk_stp_state_t stp_state)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (msti > RTK_MAX_NUM_OF_MSTI)
+        return RT_ERR_MSTI;
+
+    if (stp_state >= STP_STATE_END)
+        return RT_ERR_MSTP_STATE;
+
+    if ((retVal = rtl8367c_setAsicSpanningTreeStatus(rtk_switch_port_L2P_get(port), msti, stp_state)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_stp_mstpState_get
+ * Description:
+ *      Get spanning tree state per each port.
+ * Input:
+ *      port - Port id.
+ *      msti - Multiple spanning tree instance.
+ * Output:
+ *      pStp_state - Spanning tree state for msti
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_PORT_ID      - Invalid port number.
+ *      RT_ERR_MSTI         - Invalid msti parameter.
+ * Note:
+ *      System supports per-port multiple spanning tree state for each msti.
+ *      There are four states supported by ASIC.
+ *      - STP_STATE_DISABLED
+ *      - STP_STATE_BLOCKING
+ *      - STP_STATE_LEARNING
+ *      - STP_STATE_FORWARDING
+ */
+rtk_api_ret_t rtk_stp_mstpState_get(rtk_stp_msti_id_t msti, rtk_port_t port, rtk_stp_state_t *pStp_state)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* Check Port Valid */
+    RTK_CHK_PORT_VALID(port);
+
+    if (msti > RTK_MAX_NUM_OF_MSTI)
+        return RT_ERR_MSTI;
+
+    if(NULL == pStp_state)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getAsicSpanningTreeStatus(rtk_switch_port_L2P_get(port), msti, pStp_state)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_checkAndCreateMbr
+ * Description:
+ *      Check and create Member configuration and return index
+ * Input:
+ *      vid  - VLAN id.
+ * Output:
+ *      pIndex  - Member configuration index
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_VLAN_VID     - Invalid VLAN ID.
+ *      RT_ERR_VLAN_ENTRY_NOT_FOUND - VLAN not found
+ *      RT_ERR_TBL_FULL     - Member Configuration table full
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_vlan_checkAndCreateMbr(rtk_vlan_t vid, rtk_uint32 *pIndex)
+{
+    rtk_api_ret_t retVal;
+    rtl8367c_user_vlan4kentry vlan4K;
+    rtl8367c_vlanconfiguser vlanMC;
+    rtk_uint32 idx;
+    rtk_uint32 empty_idx = 0xFFFF;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    /* vid must be 0~8191 */
+    if (vid > RTL8367C_EVIDMAX)
+        return RT_ERR_VLAN_VID;
+
+    /* Null pointer check */
+    if(NULL == pIndex)
+        return RT_ERR_NULL_POINTER;
+
+    /* Get 4K VLAN */
+    if (vid <= RTL8367C_VIDMAX)
+    {
+        memset(&vlan4K, 0x00, sizeof(rtl8367c_user_vlan4kentry));
+        vlan4K.vid = vid;
+        if ((retVal = rtl8367c_getAsicVlan4kEntry(&vlan4K)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    /* Search exist entry */
+    for (idx = 0; idx <= RTL8367C_CVIDXMAX; idx++)
+    {
+        if(vlan_mbrCfgUsage[idx] == MBRCFG_USED_BY_VLAN)
+        {
+            if(vlan_mbrCfgVid[idx] == vid)
+            {
+                /* Found! return index */
+                *pIndex = idx;
+                return RT_ERR_OK;
+            }
+        }
+    }
+
+    /* Not found, Read H/W Member Configuration table to update database */
+    for (idx = 0; idx <= RTL8367C_CVIDXMAX; idx++)
+    {
+        if ((retVal = rtl8367c_getAsicVlanMemberConfig(idx, &vlanMC)) != RT_ERR_OK)
+            return retVal;
+
+        if( (vlanMC.evid == 0) && (vlanMC.mbr == 0x00))
+        {
+            vlan_mbrCfgUsage[idx]   = MBRCFG_UNUSED;
+            vlan_mbrCfgVid[idx]     = 0;
+        }
+        else
+        {
+            vlan_mbrCfgUsage[idx]   = MBRCFG_USED_BY_VLAN;
+            vlan_mbrCfgVid[idx]     = vlanMC.evid;
+        }
+    }
+
+    /* Search exist entry again */
+    for (idx = 0; idx <= RTL8367C_CVIDXMAX; idx++)
+    {
+        if(vlan_mbrCfgUsage[idx] == MBRCFG_USED_BY_VLAN)
+        {
+            if(vlan_mbrCfgVid[idx] == vid)
+            {
+                /* Found! return index */
+                *pIndex = idx;
+                return RT_ERR_OK;
+            }
+        }
+    }
+
+    /* try to look up an empty index */
+    for (idx = 0; idx <= RTL8367C_CVIDXMAX; idx++)
+    {
+        if(vlan_mbrCfgUsage[idx] == MBRCFG_UNUSED)
+        {
+            empty_idx = idx;
+            break;
+        }
+    }
+
+    if(empty_idx == 0xFFFF)
+    {
+        /* No empty index */
+        return RT_ERR_TBL_FULL;
+    }
+
+    if (vid > RTL8367C_VIDMAX)
+    {
+        /* > 4K, there is no 4K entry, create on member configuration directly */
+        memset(&vlanMC, 0x00, sizeof(rtl8367c_vlanconfiguser));
+        vlanMC.evid = vid;
+        if ((retVal = rtl8367c_setAsicVlanMemberConfig(empty_idx, &vlanMC)) != RT_ERR_OK)
+            return retVal;
+    }
+    else
+    {
+        /* Copy from 4K table */
+        vlanMC.evid = vid;
+        vlanMC.mbr = vlan4K.mbr;
+        vlanMC.fid_msti = vlan4K.fid_msti;
+        vlanMC.meteridx= vlan4K.meteridx;
+        vlanMC.envlanpol= vlan4K.envlanpol;
+        vlanMC.vbpen = vlan4K.vbpen;
+        vlanMC.vbpri = vlan4K.vbpri;
+        if ((retVal = rtl8367c_setAsicVlanMemberConfig(empty_idx, &vlanMC)) != RT_ERR_OK)
+            return retVal;
+    }
+
+    /* Update Database */
+    vlan_mbrCfgUsage[empty_idx] = MBRCFG_USED_BY_VLAN;
+    vlan_mbrCfgVid[empty_idx] = vid;
+
+    *pIndex = empty_idx;
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_reservedVidAction_set
+ * Description:
+ *      Set Action of VLAN ID = 0 & 4095 tagged packet
+ * Input:
+ *      action_vid0     - Action for VID 0.
+ *      action_vid4095  - Action for VID 4095.
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Error Input
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_vlan_reservedVidAction_set(rtk_vlan_resVidAction_t action_vid0, rtk_vlan_resVidAction_t action_vid4095)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(action_vid0 >= RESVID_ACTION_END)
+        return RT_ERR_INPUT;
+
+    if(action_vid4095 >= RESVID_ACTION_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setReservedVidAction((rtk_uint32)action_vid0, (rtk_uint32)action_vid4095)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_reservedVidAction_get
+ * Description:
+ *      Get Action of VLAN ID = 0 & 4095 tagged packet
+ * Input:
+ *      pAction_vid0     - Action for VID 0.
+ *      pAction_vid4095  - Action for VID 4095.
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_NULL_POINTER - NULL Pointer
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_vlan_reservedVidAction_get(rtk_vlan_resVidAction_t *pAction_vid0, rtk_vlan_resVidAction_t *pAction_vid4095)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(pAction_vid0 == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    if(pAction_vid4095 == NULL)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getReservedVidAction((rtk_uint32 *)pAction_vid0, (rtk_uint32 *)pAction_vid4095)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_realKeepRemarkEnable_set
+ * Description:
+ *      Set Real keep 1p remarking feature
+ * Input:
+ *      enabled     - State of 1p remarking at real keep packet
+ * Output:
+ *      None.
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Error Input
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_vlan_realKeepRemarkEnable_set(rtk_enable_t enabled)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(enabled >= RTK_ENABLE_END)
+        return RT_ERR_INPUT;
+
+    if ((retVal = rtl8367c_setRealKeepRemarkEn((rtk_uint32)enabled)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_realKeepRemarkEnable_get
+ * Description:
+ *      Get Real keep 1p remarking feature
+ * Input:
+ *      None.
+ * Output:
+ *      pEnabled     - State of 1p remarking at real keep packet
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Error Input
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_vlan_realKeepRemarkEnable_get(rtk_enable_t *pEnabled)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if(NULL == pEnabled)
+        return RT_ERR_NULL_POINTER;
+
+    if ((retVal = rtl8367c_getRealKeepRemarkEn((rtk_uint32 *)pEnabled)) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
+/* Function Name:
+ *      rtk_vlan_reset
+ * Description:
+ *      Reset VLAN
+ * Input:
+ *      None.
+ * Output:
+ *      pEnabled     - State of 1p remarking at real keep packet
+ * Return:
+ *      RT_ERR_OK           - OK
+ *      RT_ERR_FAILED       - Failed
+ *      RT_ERR_SMI          - SMI access error
+ *      RT_ERR_INPUT        - Error Input
+ * Note:
+ *
+ */
+rtk_api_ret_t rtk_vlan_reset(void)
+{
+    rtk_api_ret_t retVal;
+
+    /* Check initialization state */
+    RTK_CHK_INIT_STATE();
+
+    if ((retVal = rtl8367c_resetVlan()) != RT_ERR_OK)
+        return retVal;
+
+    return RT_ERR_OK;
+}
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367s.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367s.c
new file mode 100644
index 0000000..6a55631
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367s.c
@@ -0,0 +1,580 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/switch.h>
+
+//include from rtl8367c dir
+#include  "./rtl8367c/include/rtk_switch.h"
+#include  "./rtl8367c/include/vlan.h"
+#include  "./rtl8367c/include/stat.h"
+#include  "./rtl8367c/include/port.h"
+
+#define RTL8367C_SW_CPU_PORT    6
+
+ //RTL8367C_PHY_PORT_NUM + ext0 + ext1
+#define RTL8367C_NUM_PORTS 7 
+#define RTL8367C_NUM_VIDS  4096   
+
+struct rtl8367_priv {
+	struct switch_dev	swdev;
+	bool			global_vlan_enable;
+};
+
+struct rtl8367_mib_counter {	
+	const char *name;
+};
+
+struct rtl8367_vlan_info {
+	unsigned short	vid;
+	unsigned int	untag;
+	unsigned int	member;
+	unsigned char		fid;
+};
+
+struct rtl8367_priv  rtl8367_priv_data;
+
+unsigned int rtl8367c_port_id[RTL8367C_NUM_PORTS]={0,1,2,3,4,EXT_PORT1,EXT_PORT0};
+
+void (*rtl8367_switch_reset_func)(void)=NULL;
+
+static  struct rtl8367_mib_counter  rtl8367c_mib_counters[] = {
+	{"ifInOctets"},
+	{"dot3StatsFCSErrors"},
+	{"dot3StatsSymbolErrors"},
+	{"dot3InPauseFrames"},
+	{"dot3ControlInUnknownOpcodes"},
+	{"etherStatsFragments"},
+	{"etherStatsJabbers"},
+	{"ifInUcastPkts"},
+	{"etherStatsDropEvents"},
+	{"etherStatsOctets"},
+	{"etherStatsUndersizePkts"},
+	{"etherStatsOversizePkts"},
+	{"etherStatsPkts64Octets"},
+	{"etherStatsPkts65to127Octets"},
+	{"etherStatsPkts128to255Octets"},
+	{"etherStatsPkts256to511Octets"},
+	{"etherStatsPkts512to1023Octets"},
+	{"etherStatsPkts1024toMaxOctets"},
+	{"etherStatsMcastPkts"}, 
+	{"etherStatsBcastPkts"},
+	{"ifOutOctets"},
+	{"dot3StatsSingleCollisionFrames"},
+	{"dot3StatsMultipleCollisionFrames"},
+	{"dot3StatsDeferredTransmissions"},
+	{"dot3StatsLateCollisions"}, 
+	{"etherStatsCollisions"},
+	{"dot3StatsExcessiveCollisions"},
+	{"dot3OutPauseFrames"},
+	{"dot1dBasePortDelayExceededDiscards"},
+	{"dot1dTpPortInDiscards"},
+	{"ifOutUcastPkts"},
+	{"ifOutMulticastPkts"},
+	{"ifOutBrocastPkts"},
+	{"outOampduPkts"},
+	{"inOampduPkts"},
+	{"pktgenPkts"},
+	{"inMldChecksumError"},
+	{"inIgmpChecksumError"},
+	{"inMldSpecificQuery"},
+	{"inMldGeneralQuery"},
+	{"inIgmpSpecificQuery"},
+	{"inIgmpGeneralQuery"},
+	{"inMldLeaves"},
+	{"inIgmpLeaves"},
+	{"inIgmpJoinsSuccess"},
+	{"inIgmpJoinsFail"},
+	{"inMldJoinsSuccess"},
+	{"inMldJoinsFail"},
+	{"inReportSuppressionDrop"},
+	{"inLeaveSuppressionDrop"},
+	{"outIgmpReports"},
+	{"outIgmpLeaves"},
+	{"outIgmpGeneralQuery"},
+	{"outIgmpSpecificQuery"},
+	{"outMldReports"},
+	{"outMldLeaves"},
+	{"outMldGeneralQuery"},
+	{"outMldSpecificQuery"},
+	{"inKnownMulticastPkts"},
+	{"ifInMulticastPkts"},
+	{"ifInBroadcastPkts"},
+	{"ifOutDiscards"}
+};
+
+/*rtl8367c  proprietary switch API wrapper */
+static inline unsigned int rtl8367c_sw_to_phy_port(int port)
+{
+	return rtl8367c_port_id[port];
+}
+
+static inline unsigned int rtl8367c_portmask_phy_to_sw(rtk_portmask_t phy_portmask)
+{
+	int i;
+	for (i = 0; i < RTL8367C_NUM_PORTS; i++) {
+		if(RTK_PORTMASK_IS_PORT_SET(phy_portmask,rtl8367c_sw_to_phy_port(i))) {
+			RTK_PORTMASK_PORT_CLEAR(phy_portmask,rtl8367c_sw_to_phy_port(i));
+			RTK_PORTMASK_PORT_SET(phy_portmask,i);
+		}		
+
+	}
+	return (unsigned int)phy_portmask.bits[0];
+}
+
+static int rtl8367c_reset_mibs(void)
+{
+	return rtk_stat_global_reset();
+}
+
+static int rtl8367c_reset_port_mibs(int port)
+{
+
+	return rtk_stat_port_reset(rtl8367c_sw_to_phy_port(port));
+}
+
+static int rtl8367c_get_mibs_num(void)
+{
+	return ARRAY_SIZE(rtl8367c_mib_counters);
+}
+
+static const char *rtl8367c_get_mib_name(int idx)
+{
+	
+	return rtl8367c_mib_counters[idx].name;
+}
+
+static int rtl8367c_get_port_mib_counter(int idx, int port, unsigned long long *counter)
+{
+	return rtk_stat_port_get(rtl8367c_sw_to_phy_port(port), idx, counter);
+}
+
+static int rtl8367c_is_vlan_valid(unsigned int vlan)
+{
+	unsigned max = RTL8367C_NUM_VIDS;	
+
+	if (vlan == 0 || vlan >= max)
+		return 0;
+
+	return 1;
+}
+
+static int rtl8367c_get_vlan( unsigned short vid, struct rtl8367_vlan_info *vlan)
+{	
+	rtk_vlan_cfg_t vlan_cfg;
+
+	memset(vlan, '\0', sizeof(struct rtl8367_vlan_info));
+
+	if (vid >= RTL8367C_NUM_VIDS)
+		return -EINVAL;	
+
+	if(rtk_vlan_get(vid,&vlan_cfg))
+       	return -EINVAL;		
+	
+	vlan->vid = vid;
+	vlan->member = rtl8367c_portmask_phy_to_sw(vlan_cfg.mbr);	
+	vlan->untag = rtl8367c_portmask_phy_to_sw(vlan_cfg.untag);	
+	vlan->fid = vlan_cfg.fid_msti;
+
+	return 0;
+}
+
+static int rtl8367c_set_vlan( unsigned short vid, u32 mbr, u32 untag, u8 fid)
+{	
+	rtk_vlan_cfg_t vlan_cfg;
+	int i;
+
+	memset(&vlan_cfg, 0x00, sizeof(rtk_vlan_cfg_t));	
+
+	for (i = 0; i < RTL8367C_NUM_PORTS; i++) {
+		if (mbr & (1 << i)) {
+			RTK_PORTMASK_PORT_SET(vlan_cfg.mbr, rtl8367c_sw_to_phy_port(i));
+			if(untag & (1 << i))
+				RTK_PORTMASK_PORT_SET(vlan_cfg.untag, rtl8367c_sw_to_phy_port(i));			
+		}
+	}
+	vlan_cfg.fid_msti=fid;
+	vlan_cfg.ivl_en = 1;
+	return rtk_vlan_set(vid, &vlan_cfg);
+}
+
+
+static int rtl8367c_get_pvid( int port, int *pvid)
+{
+	u32 prio=0;
+	
+	if (port >= RTL8367C_NUM_PORTS)
+		return -EINVAL;		
+
+	return rtk_vlan_portPvid_get(rtl8367c_sw_to_phy_port(port),pvid,&prio);
+}
+
+
+static int rtl8367c_set_pvid( int port, int pvid)
+{
+	u32 prio=0;
+	
+	if (port >= RTL8367C_NUM_PORTS)
+		return -EINVAL;		
+
+	return rtk_vlan_portPvid_set(rtl8367c_sw_to_phy_port(port),pvid,prio);
+}
+
+static int rtl8367c_get_port_link(int port, int *link, int *speed, int *duplex)
+{
+	
+	if(rtk_port_phyStatus_get(rtl8367c_sw_to_phy_port(port),(rtk_port_linkStatus_t *)link,
+					(rtk_port_speed_t *)speed,(rtk_port_duplex_t *)duplex))
+		return -EINVAL;
+
+	return 0;
+}
+
+/*common rtl8367 swconfig entry API*/
+
+static int
+rtl8367_sw_set_vlan_enable(struct switch_dev *dev,
+			   const struct switch_attr *attr,
+			   struct switch_val *val)
+{
+	struct rtl8367_priv *priv = container_of(dev, struct rtl8367_priv, swdev);	
+
+	priv->global_vlan_enable = val->value.i ;
+
+	return 0;
+}
+
+static int
+rtl8367_sw_get_vlan_enable(struct switch_dev *dev,
+			   const struct switch_attr *attr,
+			   struct switch_val *val)
+{
+	struct rtl8367_priv *priv = container_of(dev, struct rtl8367_priv, swdev);
+
+	val->value.i = priv->global_vlan_enable;
+
+	return 0;
+}
+
+static int rtl8367_sw_reset_mibs(struct switch_dev *dev,
+				  const struct switch_attr *attr,
+				  struct switch_val *val)
+{
+	return rtl8367c_reset_mibs();
+}
+
+
+static int rtl8367_sw_reset_port_mibs(struct switch_dev *dev,
+				       const struct switch_attr *attr,
+				       struct switch_val *val)
+{
+	int port;
+
+	port = val->port_vlan;
+	if (port >= RTL8367C_NUM_PORTS)
+		return -EINVAL;
+
+	return rtl8367c_reset_port_mibs(port);
+}
+
+static int rtl8367_sw_get_port_mib(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{	
+	int i, len = 0;
+	unsigned long long counter = 0;
+	static char mib_buf[4096];
+
+	if (val->port_vlan >= RTL8367C_NUM_PORTS)
+		return -EINVAL;
+
+	len += snprintf(mib_buf + len, sizeof(mib_buf) - len,
+			"Port %d MIB counters\n",
+			val->port_vlan);	
+
+	for (i = 0; i <rtl8367c_get_mibs_num(); ++i) {
+		len += snprintf(mib_buf + len, sizeof(mib_buf) - len,
+				"%-36s: ",rtl8367c_get_mib_name(i));
+		if (!rtl8367c_get_port_mib_counter(i, val->port_vlan,
+					       &counter))
+			len += snprintf(mib_buf + len, sizeof(mib_buf) - len,
+					"%llu\n", counter);
+		else
+			len += snprintf(mib_buf + len, sizeof(mib_buf) - len,
+					"%s\n", "N/A");
+	}
+
+	val->value.s = mib_buf;
+	val->len = len;
+	return 0;
+}
+
+
+static int rtl8367_sw_get_vlan_info(struct switch_dev *dev,
+			     const struct switch_attr *attr,
+			     struct switch_val *val)
+{	
+	int i;
+	u32 len = 0;
+	struct rtl8367_vlan_info vlan;
+	static char vlan_buf[256];
+	int err;
+
+	if (!rtl8367c_is_vlan_valid(val->port_vlan))
+		return -EINVAL;
+
+	memset(vlan_buf, '\0', sizeof(vlan_buf));
+
+	err = rtl8367c_get_vlan(val->port_vlan, &vlan);
+	if (err)
+		return err;
+
+	len += snprintf(vlan_buf + len, sizeof(vlan_buf) - len,
+			"VLAN %d: Ports: '", vlan.vid);
+
+	for (i = 0; i <RTL8367C_NUM_PORTS; i++) {
+		if (!(vlan.member & (1 << i)))
+			continue;
+
+		len += snprintf(vlan_buf + len, sizeof(vlan_buf) - len, "%d%s", i,
+				(vlan.untag & (1 << i)) ? "" : "t");
+	}
+
+	len += snprintf(vlan_buf + len, sizeof(vlan_buf) - len,
+			"', members=%04x, untag=%04x, fid=%u",
+			vlan.member, vlan.untag, vlan.fid);
+
+	val->value.s = vlan_buf;
+	val->len = len;
+
+	return 0;
+}
+
+
+static int rtl8367_sw_get_vlan_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct switch_port *port;
+	struct rtl8367_vlan_info vlan;
+	int i;	
+	
+	if (!rtl8367c_is_vlan_valid(val->port_vlan))
+		return -EINVAL;
+
+	if(rtl8367c_get_vlan(val->port_vlan, &vlan))
+		return -EINVAL;
+
+	port = &val->value.ports[0];
+	val->len = 0;
+	for (i = 0; i <RTL8367C_NUM_PORTS ; i++) {
+		if (!(vlan.member & BIT(i)))
+			continue;
+
+		port->id = i;
+		port->flags = (vlan.untag & BIT(i)) ?
+					0 : BIT(SWITCH_PORT_FLAG_TAGGED);
+		val->len++;
+		port++;
+	}
+	return 0;
+}
+
+
+static int rtl8367_sw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val)
+{
+	struct switch_port *port;
+	u32 member = 0;
+	u32 untag = 0;
+	u8 fid=0;
+	int err;
+	int i;	
+	
+	if (!rtl8367c_is_vlan_valid(val->port_vlan))
+		return -EINVAL;
+
+	port = &val->value.ports[0];
+	for (i = 0; i < val->len; i++, port++) {
+		int pvid = 0;
+		member |= BIT(port->id);
+
+		if (!(port->flags & BIT(SWITCH_PORT_FLAG_TAGGED)))
+			untag |= BIT(port->id);
+
+		/*
+		 * To ensure that we have a valid MC entry for this VLAN,
+		 * initialize the port VLAN ID here.
+		 */
+		err = rtl8367c_get_pvid(port->id, &pvid);
+		if (err < 0)
+			return err;
+		if (pvid == 0) {
+			err = rtl8367c_set_pvid(port->id, val->port_vlan);
+			if (err < 0)
+				return err;
+		}
+	}
+
+	//pr_info("[%s] vid=%d , mem=%x,untag=%x,fid=%d \n",__func__,val->port_vlan,member,untag,fid);
+
+	return rtl8367c_set_vlan(val->port_vlan, member, untag, fid);	
+
+}
+
+
+static int rtl8367_sw_get_port_pvid(struct switch_dev *dev, int port, int *val)
+{
+	return rtl8367c_get_pvid(port, val);
+}
+
+
+static int rtl8367_sw_set_port_pvid(struct switch_dev *dev, int port, int val)
+{	
+	return rtl8367c_set_pvid(port, val);
+}
+
+
+static int rtl8367_sw_reset_switch(struct switch_dev *dev)
+{
+	if(rtl8367_switch_reset_func)
+		(*rtl8367_switch_reset_func)();
+	else
+		printk("rest switch is not supported\n");
+
+	return 0;
+}
+
+static int rtl8367_sw_get_port_link(struct switch_dev *dev, int port,
+				    struct switch_port_link *link)
+{	
+	int speed;
+
+	if (port >= RTL8367C_NUM_PORTS)
+		return -EINVAL;
+
+	if(rtl8367c_get_port_link(port,(int *)&link->link,(int *)&speed,(int *)&link->duplex))
+		return -EINVAL;		
+
+	if (!link->link)
+		return 0;	
+
+	switch (speed) {
+	case 0:
+		link->speed = SWITCH_PORT_SPEED_10;
+		break;
+	case 1:
+		link->speed = SWITCH_PORT_SPEED_100;
+		break;
+	case 2:
+		link->speed = SWITCH_PORT_SPEED_1000;
+		break;
+	default:
+		link->speed = SWITCH_PORT_SPEED_UNKNOWN;
+		break;
+	}
+
+	return 0;
+}
+
+
+static struct switch_attr rtl8367_globals[] = {
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "enable_vlan",
+		.description = "Enable VLAN mode",
+		.set = rtl8367_sw_set_vlan_enable,
+		.get = rtl8367_sw_get_vlan_enable,
+		.max = 1,		
+	}, {		
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mibs",
+		.description = "Reset all MIB counters",
+		.set = rtl8367_sw_reset_mibs,
+	}
+};
+
+static struct switch_attr rtl8367_port[] = {
+	{
+		.type = SWITCH_TYPE_NOVAL,
+		.name = "reset_mib",
+		.description = "Reset single port MIB counters",
+		.set = rtl8367_sw_reset_port_mibs,
+	}, {
+		.type = SWITCH_TYPE_STRING,
+		.name = "mib",
+		.description = "Get MIB counters for port",
+		//.max = 33,
+		.set = NULL,
+		.get = rtl8367_sw_get_port_mib,
+	},
+};
+
+static struct switch_attr rtl8367_vlan[] = {
+	{
+		.type = SWITCH_TYPE_STRING,
+		.name = "info",
+		.description = "Get vlan information",
+		.max = 1,
+		.set = NULL,
+		.get = rtl8367_sw_get_vlan_info,
+	},
+};
+
+static const struct switch_dev_ops rtl8367_sw_ops = {
+	.attr_global = {
+		.attr = rtl8367_globals,
+		.n_attr = ARRAY_SIZE(rtl8367_globals),
+	},
+	.attr_port = {
+		.attr = rtl8367_port,
+		.n_attr = ARRAY_SIZE(rtl8367_port),
+	},
+	.attr_vlan = {
+		.attr = rtl8367_vlan,
+		.n_attr = ARRAY_SIZE(rtl8367_vlan),
+	},
+
+	.get_vlan_ports = rtl8367_sw_get_vlan_ports,
+	.set_vlan_ports = rtl8367_sw_set_vlan_ports,
+	.get_port_pvid = rtl8367_sw_get_port_pvid,
+	.set_port_pvid = rtl8367_sw_set_port_pvid,
+	.reset_switch = rtl8367_sw_reset_switch,
+	.get_port_link = rtl8367_sw_get_port_link,
+};
+
+int rtl8367s_swconfig_init(void (*reset_func)(void))
+{
+	struct rtl8367_priv  *priv = &rtl8367_priv_data;
+	struct switch_dev *dev=&priv->swdev;
+	int err=0;
+
+	rtl8367_switch_reset_func = reset_func ;
+	
+	memset(priv, 0, sizeof(struct rtl8367_priv));	
+	priv->global_vlan_enable =0;
+
+	dev->name = "RTL8367C";
+	dev->cpu_port = RTL8367C_SW_CPU_PORT;
+	dev->ports = RTL8367C_NUM_PORTS;
+	dev->vlans = RTL8367C_NUM_VIDS;
+	dev->ops = &rtl8367_sw_ops;
+	dev->alias = "RTL8367C";		
+	err = register_switch(dev, NULL);
+
+	pr_info("[%s]\n",__func__);
+
+	return err;
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367s_dbg.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367s_dbg.c
new file mode 100644
index 0000000..ec86679
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367s_dbg.c
@@ -0,0 +1,655 @@
+#include <linux/uaccess.h>
+#include <linux/trace_seq.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <linux/u64_stats_sync.h>
+
+#include  "./rtl8367c/include/rtk_switch.h"
+#include  "./rtl8367c/include/port.h"
+#include  "./rtl8367c/include/vlan.h"
+#include  "./rtl8367c/include/rtl8367c_asicdrv_port.h"
+#include  "./rtl8367c/include/stat.h"
+#include  "./rtl8367c/include/l2.h"
+#include  "./rtl8367c/include/smi.h"
+#include  "./rtl8367c/include/mirror.h"
+#include  "./rtl8367c/include/igmp.h"
+#include  "./rtl8367c/include/leaky.h"
+
+static struct proc_dir_entry *proc_reg_dir;
+static struct proc_dir_entry *proc_esw_cnt;
+static struct proc_dir_entry *proc_vlan_cnt;
+static struct proc_dir_entry *proc_mac_tbl;
+static struct proc_dir_entry *proc_reg;
+static struct proc_dir_entry *proc_phyreg;
+static struct proc_dir_entry *proc_mirror;
+static struct proc_dir_entry *proc_igmp;
+
+#define PROCREG_ESW_CNT         "esw_cnt"
+#define PROCREG_VLAN            "vlan"
+#define PROCREG_MAC_TBL            "mac_tbl"
+#define PROCREG_REG            "reg"
+#define PROCREG_PHYREG            "phyreg"
+#define PROCREG_MIRROR            "mirror"
+#define PROCREG_IGMP            "igmp"
+#define PROCREG_DIR             "rtk_gsw"
+
+#define RTK_SW_VID_RANGE        16
+
+static void rtk_dump_mib_type(rtk_stat_port_type_t cntr_idx)
+{
+	rtk_port_t port;
+	rtk_stat_counter_t Cntr;
+
+	for (port = UTP_PORT0; port < (UTP_PORT0 + 5); port++) {
+		rtk_stat_port_get(port, cntr_idx, &Cntr);
+		printk("%8llu", Cntr);
+	}
+
+	for (port = EXT_PORT0; port < (EXT_PORT0 + 2); port++) {
+		rtk_stat_port_get(port, cntr_idx, &Cntr);
+		printk("%8llu", Cntr);
+	}
+	
+	printk("\n");
+}
+static void rtk_hal_dump_mib(void)
+{
+
+	printk("==================%8s%8s%8s%8s%8s%8s%8s\n", "Port0", "Port1",
+	       "Port2", "Port3", "Port4", "Port16", "Port17");
+	/* Get TX Unicast Pkts */
+	printk("TX Unicast Pkts  :");
+	rtk_dump_mib_type(STAT_IfOutUcastPkts);
+	/* Get TX Multicast Pkts */
+	printk("TX Multicast Pkts:");
+	rtk_dump_mib_type(STAT_IfOutMulticastPkts);
+	/* Get TX BroadCast Pkts */
+	printk("TX BroadCast Pkts:");
+	rtk_dump_mib_type(STAT_IfOutBroadcastPkts);
+	/* Get TX Collisions */
+	/* Get TX Puase Frames */
+	printk("TX Pause Frames  :");
+	rtk_dump_mib_type(STAT_Dot3OutPauseFrames);
+	/* Get TX Drop Events */
+	/* Get RX Unicast Pkts */
+	printk("RX Unicast Pkts  :");
+	rtk_dump_mib_type(STAT_IfInUcastPkts);
+	/* Get RX Multicast Pkts */
+	printk("RX Multicast Pkts:");
+	rtk_dump_mib_type(STAT_IfInMulticastPkts);
+	/* Get RX Broadcast Pkts */
+	printk("RX Broadcast Pkts:");
+	rtk_dump_mib_type(STAT_IfInBroadcastPkts);
+	/* Get RX FCS Erros */
+	printk("RX FCS Errors    :");
+	rtk_dump_mib_type(STAT_Dot3StatsFCSErrors);
+	/* Get RX Undersize Pkts */
+	printk("RX Undersize Pkts:");
+	rtk_dump_mib_type(STAT_EtherStatsUnderSizePkts);
+	/* Get RX Discard Pkts */
+	printk("RX Discard Pkts  :");
+	rtk_dump_mib_type(STAT_Dot1dTpPortInDiscards);
+	/* Get RX Fragments */
+	printk("RX Fragments     :");
+	rtk_dump_mib_type(STAT_EtherStatsFragments);
+	/* Get RX Oversize Pkts */
+	printk("RX Oversize Pkts :");
+	rtk_dump_mib_type(STAT_EtherOversizeStats);
+	/* Get RX Jabbers */
+	printk("RX Jabbers       :");
+	rtk_dump_mib_type(STAT_EtherStatsJabbers);
+	/* Get RX Pause Frames */
+	printk("RX Pause Frames  :");
+	rtk_dump_mib_type(STAT_Dot3InPauseFrames);
+	/* clear MIB */
+	rtk_stat_global_reset();
+	
+}
+
+static int rtk_hal_dump_vlan(void)
+{
+	rtk_vlan_cfg_t vlan;
+	int i;
+
+	printk("vid    portmap\n");
+	for (i = 0; i < RTK_SW_VID_RANGE; i++) {
+		rtk_vlan_get(i, &vlan);
+		printk("%3d    ", i);
+		printk("%c",
+		       RTK_PORTMASK_IS_PORT_SET(vlan.mbr,
+	                                UTP_PORT0) ? '1' : '-');
+		printk("%c",
+	       	RTK_PORTMASK_IS_PORT_SET(vlan.mbr,
+	                                UTP_PORT1) ? '1' : '-');
+		printk("%c",
+		       RTK_PORTMASK_IS_PORT_SET(vlan.mbr,
+	                                UTP_PORT2) ? '1' : '-');
+		printk("%c",
+		       RTK_PORTMASK_IS_PORT_SET(vlan.mbr,
+	                                UTP_PORT3) ? '1' : '-');
+		printk("%c",
+	       	RTK_PORTMASK_IS_PORT_SET(vlan.mbr,
+	                                UTP_PORT4) ? '1' : '-');
+		printk("%c",
+		       RTK_PORTMASK_IS_PORT_SET(vlan.mbr,
+	                                EXT_PORT0) ? '1' : '-');
+		printk("%c",
+		       RTK_PORTMASK_IS_PORT_SET(vlan.mbr,
+	                                EXT_PORT1) ? '1' : '-');
+		printk("\n");
+	}
+	
+	return 0;
+}
+
+static void rtk_hal_dump_table(void)
+{
+	rtk_uint32 i;
+	rtk_uint32 address = 0;
+	rtk_l2_ucastAddr_t l2_data;
+	rtk_l2_ipMcastAddr_t ipMcastAddr;
+	rtk_l2_age_time_t age_timout;
+
+	rtk_l2_aging_get(&age_timout);
+	printk("Mac table age timeout =%d\n",(unsigned int)age_timout);
+
+	printk("hash  port(0:17)   fid   vid  mac-address\n");
+	while (1) {
+		if (rtk_l2_addr_next_get(READMETHOD_NEXT_L2UC, UTP_PORT0, &address, &l2_data) != RT_ERR_OK) {
+			break;
+		} else {
+			printk("%03x   ", l2_data.address);
+			for (i = 0; i < 5; i++)
+				if ( l2_data.port == i)
+					printk("1");
+				else
+					printk("-");
+			for (i = 16; i < 18; i++)
+				if ( l2_data.port == i)
+					printk("1");
+				else
+					printk("-");
+
+			printk("      %2d", l2_data.fid);
+			printk("  %4d", l2_data.cvid);
+			printk("  %02x%02x%02x%02x%02x%02x\n", l2_data.mac.octet[0],
+			l2_data.mac.octet[1], l2_data.mac.octet[2], l2_data.mac.octet[3],
+			l2_data.mac.octet[4], l2_data.mac.octet[5]);
+			address ++;
+			}
+	}
+
+	address = 0;
+	while (1) {
+        if (rtk_l2_ipMcastAddr_next_get(&address, &ipMcastAddr) != RT_ERR_OK) {
+            break;
+        } else {
+            printk("%03x   ", ipMcastAddr.address);
+            for (i = 0; i < 5; i++)
+                printk("%c", RTK_PORTMASK_IS_PORT_SET(ipMcastAddr.portmask, i) ? '1' : '-');
+            for (i = 16; i < 18; i++)
+                printk("%c", RTK_PORTMASK_IS_PORT_SET(ipMcastAddr.portmask, i) ? '1' : '-');
+			printk("                ");
+			printk("01005E%06x\n", (ipMcastAddr.dip & 0xefffff));
+            address ++;
+            }
+    }
+}
+
+static void rtk_hal_clear_table(void)
+{
+        rtk_api_ret_t ret;
+
+        ret = rtk_l2_table_clear();
+        if (ret != RT_ERR_OK)
+                printk("rtk_l2_table_clear failed\n");
+}
+
+static void rtk_hal_read_reg(unsigned int reg_addr)
+{
+        ret_t retVal;
+	 unsigned int reg_val;
+
+        retVal = smi_read(reg_addr, &reg_val);
+
+        if(retVal != RT_ERR_OK)
+                printk("switch reg read failed\n");
+        else
+                printk("reg0x%x = 0x%x\n", reg_addr, reg_val);
+}
+
+static void rtk_hal_write_reg(unsigned int reg_addr , unsigned int reg_val)
+{
+        ret_t retVal;
+
+    retVal = smi_write(reg_addr, reg_val);
+
+    if(retVal != RT_ERR_OK)
+        printk("switch reg write failed\n");
+    else
+        printk("write switch reg0x%x 0x%x success\n", reg_addr, reg_val);
+}
+
+static void rtk_hal_get_phy_reg(unsigned int port ,unsigned int reg_addr )
+{
+        ret_t retVal;
+        rtk_port_phy_data_t Data;
+
+        retVal = rtk_port_phyReg_get(port, reg_addr, &Data);
+        if (retVal == RT_ERR_OK)
+                printk("Get: phy[%d].reg[%d] = 0x%04x\n", port, reg_addr, Data);
+        else
+                printk("read phy reg failed\n");
+}
+
+static void rtk_hal_set_phy_reg(unsigned int port ,unsigned int reg_addr,unsigned int reg_val)
+{
+        ret_t retVal;
+
+        retVal = rtk_port_phyReg_set(port, reg_addr, reg_val);
+        if (retVal == RT_ERR_OK)
+                printk("Set: phy[%d].reg[%d] = 0x%04x\n", port, reg_addr, reg_val);
+        else
+                printk("write phy reg failed\n");
+}
+
+static void rtk_hal_set_port_mirror(unsigned int port ,unsigned int rx_port_map,unsigned int tx_port_map)
+{
+        rtk_portmask_t rx_portmask;
+        rtk_portmask_t tx_portmask;
+        rtk_api_ret_t ret;
+        int i;
+
+        rtk_mirror_portIso_set(ENABLED);
+        RTK_PORTMASK_CLEAR(rx_portmask);
+        RTK_PORTMASK_CLEAR(tx_portmask);
+
+	for (i = 0; i < 5; i++)
+                if (rx_port_map & (1 << i))
+                        RTK_PORTMASK_PORT_SET(rx_portmask, i);
+
+        for (i = 0; i < 2; i++)
+                if (rx_port_map & (1 << (i + 5)))
+                        RTK_PORTMASK_PORT_SET(rx_portmask, (i + EXT_PORT0));
+
+        RTK_PORTMASK_CLEAR(tx_portmask);
+
+	for (i = 0; i < 5; i++)
+		if (tx_port_map & (1 << i))
+		           RTK_PORTMASK_PORT_SET(tx_portmask, i);
+
+	for (i = 0; i < 2; i++)
+		if (tx_port_map & (1 << (i + 5)))
+			RTK_PORTMASK_PORT_SET(tx_portmask, (i + EXT_PORT0));
+
+	ret = rtk_mirror_portBased_set(port, &rx_portmask, &tx_portmask);
+
+        if (!ret)
+                printk("rtk_mirror_portBased_set success\n");
+
+}
+
+static void rtk_hal_enable_igmpsnoop(int hw_on)
+{
+        rtk_api_ret_t ret;
+        rtk_portmask_t pmask;
+
+        ret = rtk_igmp_init();
+        if (hw_on == 1) {
+                RTK_PORTMASK_CLEAR(pmask);
+                RTK_PORTMASK_PORT_SET(pmask, EXT_PORT0);
+                ret |= rtk_igmp_static_router_port_set(&pmask);
+                ret |= rtk_igmp_protocol_set(UTP_PORT4, PROTOCOL_IGMPv1, IGMP_ACTION_FORWARD);
+                ret |= rtk_igmp_protocol_set(UTP_PORT4, PROTOCOL_IGMPv2, IGMP_ACTION_FORWARD);
+                ret |= rtk_igmp_protocol_set(UTP_PORT4, PROTOCOL_MLDv1, IGMP_ACTION_FORWARD);
+                ret |= rtk_igmp_protocol_set(EXT_PORT1, PROTOCOL_IGMPv1, IGMP_ACTION_FORWARD);
+                ret |= rtk_igmp_protocol_set(EXT_PORT1, PROTOCOL_IGMPv2, IGMP_ACTION_FORWARD);
+                ret |= rtk_igmp_protocol_set(EXT_PORT1, PROTOCOL_MLDv1, IGMP_ACTION_FORWARD);
+                ret |= rtk_igmp_protocol_set(UTP_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC);
+                ret |= rtk_igmp_protocol_set(UTP_PORT1, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC);
+                ret |= rtk_igmp_protocol_set(UTP_PORT2, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC);
+                ret |= rtk_igmp_protocol_set(UTP_PORT3, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC);
+                ret |= rtk_igmp_protocol_set(EXT_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC);
+
+                ret |= rtk_leaky_vlan_set(LEAKY_IPMULTICAST, ENABLED);
+                ret |= rtk_l2_ipMcastForwardRouterPort_set(DISABLED);
+                /* drop unknown multicast packets*/
+                /* ret |= rtk_trap_unknownMcastPktAction_set(UTP_PORT4, MCAST_IPV4, MCAST_ACTION_DROP);*/
+        } else {
+		RTK_PORTMASK_CLEAR(pmask);
+		RTK_PORTMASK_PORT_SET(pmask, EXT_PORT0);
+		RTK_PORTMASK_PORT_SET(pmask, EXT_PORT1);
+                ret |= rtk_igmp_protocol_set(UTP_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC);
+                ret |= rtk_igmp_protocol_set(UTP_PORT1, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC);
+                ret |= rtk_igmp_protocol_set(UTP_PORT2, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC);
+                ret |= rtk_igmp_protocol_set(UTP_PORT3, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC);
+                ret |= rtk_igmp_protocol_set(EXT_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC);
+
+                ret |= rtk_igmp_static_router_port_set(&pmask);
+        }
+
+        if(ret != RT_ERR_OK)
+                printk("enable switch igmpsnoop failed\n");
+
+}
+
+static void rtk_hal_disable_igmpsnoop(void)
+{
+        if (rtk_igmp_state_set(DISABLED) != RT_ERR_OK)
+                printk("Disable IGMP SNOOPING failed\n");
+}
+
+static ssize_t mac_tbl_write(struct file *file,
+                            const char __user *buffer, size_t count,
+                            loff_t *data)
+{
+	rtk_hal_clear_table();
+
+        return count;
+}
+
+
+static ssize_t phyreg_ops(struct file *file,
+                            const char __user *buffer, size_t count,
+                            loff_t *data)
+{
+        char buf[64];
+	 unsigned int port;
+        unsigned int offset;
+        unsigned int val;
+
+        memset(buf, 0, 64);
+
+        if (copy_from_user(buf, buffer, count))
+                return -EFAULT;
+
+
+        if(buf[0] == 'w') {
+
+                if(sscanf(buf, "w %d %x %x", &port,&offset,&val) == -1)
+                        return -EFAULT;
+                else
+                        rtk_hal_set_phy_reg(port,offset,val);
+
+        } else {
+
+		if(sscanf(buf, "r %d %x",&port, &offset) == -1)
+                        return -EFAULT;
+                else
+                        rtk_hal_get_phy_reg(port,offset);
+        }
+
+        return count;
+}
+
+static ssize_t reg_ops(struct file *file,
+                            const char __user *buffer, size_t count,
+                            loff_t *data)
+{
+        char buf[64];
+        unsigned int offset;
+        unsigned int val;
+
+        memset(buf, 0, 64);
+
+        if (copy_from_user(buf, buffer, count))
+                return -EFAULT;
+
+
+        if(buf[0] == 'w') {
+
+                if(sscanf(buf, "w %x %x", &offset,&val) == -1)
+                        return -EFAULT;
+                else
+                        rtk_hal_write_reg(offset,val);
+
+        } else {
+
+                if(sscanf(buf, "r %x", &offset) == -1)
+                        return -EFAULT;
+                else
+                        rtk_hal_read_reg(offset);
+        }
+
+        return count;
+}
+
+static ssize_t mirror_ops(struct file *file,
+                            const char __user *buffer, size_t count,
+                            loff_t *data)
+{
+        char buf[64];
+	 unsigned int port;
+        unsigned int tx_map,rx_map;
+
+        memset(buf, 0, 64);
+
+        if (copy_from_user(buf, buffer, count))
+                return -EFAULT;
+
+	if(sscanf(buf, "%d %x %x", &port,&rx_map,&tx_map) == -1)
+		return -EFAULT;
+	else
+		rtk_hal_set_port_mirror(port,rx_map,tx_map);
+
+        return count;
+}
+
+
+static ssize_t igmp_ops(struct file *file,
+                            const char __user *buffer, size_t count,
+                            loff_t *data)
+{
+        char buf[8];
+        unsigned int ops;
+
+        if (copy_from_user(buf, buffer, count))
+                return -EFAULT;
+
+	if(sscanf(buf, "%d", &ops) == -1)
+		return -EFAULT;
+
+        if(ops == 0)
+                rtk_hal_disable_igmpsnoop();
+	else if (ops == 1)
+		rtk_hal_enable_igmpsnoop(0);
+	else //hw igmp
+		rtk_hal_enable_igmpsnoop(1);
+
+        return count;
+}
+
+
+static int esw_cnt_read(struct seq_file *seq, void *v)
+{
+	rtk_hal_dump_mib();
+	return 0;
+}
+
+static int vlan_read(struct seq_file *seq, void *v)
+{
+	rtk_hal_dump_vlan();
+	return 0;
+}
+
+static int mac_tbl_read(struct seq_file *seq, void *v)
+{
+	rtk_hal_dump_table();
+	return 0;
+}
+
+static int reg_show(struct seq_file *seq, void *v)
+{
+	return 0;
+}
+
+static int phyreg_show(struct seq_file *seq, void *v)
+{
+	return 0;
+}
+
+static int mirror_show(struct seq_file *seq, void *v)
+{
+	return 0;
+}
+
+static int igmp_show(struct seq_file *seq, void *v)
+{
+	return 0;
+}
+
+static int switch_count_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, esw_cnt_read, 0);
+}
+
+static int switch_vlan_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, vlan_read, 0);
+}
+
+static int mac_tbl_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, mac_tbl_read, 0);
+}
+
+static int reg_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, reg_show, 0);
+}
+
+static int phyreg_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, phyreg_show, 0);
+}
+
+static int mirror_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, mirror_show, 0);
+}
+
+static int igmp_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, igmp_show, 0);
+}
+
+
+static const struct file_operations switch_count_fops = {
+	.owner = THIS_MODULE,
+	.open = switch_count_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release
+};
+
+static const struct file_operations switch_vlan_fops = {
+	.owner = THIS_MODULE,
+	.open = switch_vlan_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release
+};
+
+static const struct file_operations mac_tbl_fops = {
+        .owner = THIS_MODULE,
+        .open = mac_tbl_open,
+        .read = seq_read,
+        .llseek = seq_lseek,
+        .write = mac_tbl_write,
+        .release = single_release
+};
+
+static const struct file_operations reg_fops = {
+        .owner = THIS_MODULE,
+        .open = reg_open,
+        .read = seq_read,
+        .llseek = seq_lseek,
+        .write = reg_ops,
+        .release = single_release
+};
+
+static const struct file_operations phyreg_fops = {
+        .owner = THIS_MODULE,
+        .open = phyreg_open,
+        .read = seq_read,
+        .llseek = seq_lseek,
+        .write = phyreg_ops,
+        .release = single_release
+};
+
+static const struct file_operations mirror_fops = {
+        .owner = THIS_MODULE,
+        .open = mirror_open,
+        .read = seq_read,
+        .llseek = seq_lseek,
+        .write = mirror_ops,
+        .release = single_release
+};
+
+static const struct file_operations igmp_fops = {
+        .owner = THIS_MODULE,
+        .open = igmp_open,
+        .read = seq_read,
+        .llseek = seq_lseek,
+        .write = igmp_ops,
+        .release = single_release
+};
+
+int gsw_debug_proc_init(void)
+{
+
+	if (!proc_reg_dir)
+		proc_reg_dir = proc_mkdir(PROCREG_DIR, NULL);
+
+	proc_esw_cnt =
+	proc_create(PROCREG_ESW_CNT, 0, proc_reg_dir, &switch_count_fops);
+
+	if (!proc_esw_cnt)
+		pr_err("!! FAIL to create %s PROC !!\n", PROCREG_ESW_CNT);
+
+	proc_vlan_cnt =
+	proc_create(PROCREG_VLAN, 0, proc_reg_dir, &switch_vlan_fops);
+
+	if (!proc_vlan_cnt)
+		pr_err("!! FAIL to create %s PROC !!\n", PROCREG_VLAN);
+
+	proc_mac_tbl =
+	proc_create(PROCREG_MAC_TBL, 0, proc_reg_dir, &mac_tbl_fops);
+
+	if (!proc_mac_tbl)
+		pr_err("!! FAIL to create %s PROC !!\n", PROCREG_MAC_TBL);
+
+	proc_reg =
+	proc_create(PROCREG_REG, 0, proc_reg_dir, &reg_fops);
+
+	if (!proc_reg)
+		pr_err("!! FAIL to create %s PROC !!\n", PROCREG_REG);
+
+	proc_phyreg =
+	proc_create(PROCREG_PHYREG, 0, proc_reg_dir, &phyreg_fops);
+
+	if (!proc_phyreg)
+		pr_err("!! FAIL to create %s PROC !!\n", PROCREG_PHYREG);
+
+	proc_mirror =
+	proc_create(PROCREG_MIRROR, 0, proc_reg_dir, &mirror_fops);
+
+	if (!proc_mirror)
+		pr_err("!! FAIL to create %s PROC !!\n", PROCREG_MIRROR);
+
+	proc_igmp =
+	proc_create(PROCREG_IGMP, 0, proc_reg_dir, &igmp_fops);
+
+	if (!proc_igmp)
+		pr_err("!! FAIL to create %s PROC !!\n", PROCREG_IGMP);
+
+	return 0;
+}
+
+void gsw_debug_proc_exit(void)
+{
+	if (proc_esw_cnt)
+		remove_proc_entry(PROCREG_ESW_CNT, proc_reg_dir);
+}
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367s_mdio.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367s_mdio.c
new file mode 100644
index 0000000..ae958e8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/rtk/rtl8367s_mdio.c
@@ -0,0 +1,312 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+ 
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/of_mdio.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+
+
+#include  "./rtl8367c/include/rtk_switch.h"
+#include  "./rtl8367c/include/port.h"
+#include  "./rtl8367c/include/vlan.h"
+#include  "./rtl8367c/include/rtl8367c_asicdrv_port.h"
+
+struct rtk_gsw {
+ 	struct device           *dev;
+ 	struct mii_bus          *bus;
+	int reset_pin;
+};
+
+static struct rtk_gsw *_gsw;
+
+extern int gsw_debug_proc_init(void);
+extern void gsw_debug_proc_exit(void);
+
+#ifdef CONFIG_SWCONFIG
+extern int rtl8367s_swconfig_init( void (*reset_func)(void) );
+#endif
+
+/*mii_mgr_read/mii_mgr_write is the callback API for rtl8367 driver*/
+unsigned int mii_mgr_read(unsigned int phy_addr,unsigned int phy_register,unsigned int *read_data)
+{
+	struct mii_bus *bus = _gsw->bus;
+
+	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
+
+	*read_data = bus->read(bus, phy_addr, phy_register);
+
+	mutex_unlock(&bus->mdio_lock);
+
+	return 0;
+}
+
+unsigned int mii_mgr_write(unsigned int phy_addr,unsigned int phy_register,unsigned int write_data)
+{
+	struct mii_bus *bus =  _gsw->bus;
+
+	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
+
+	bus->write(bus, phy_addr, phy_register, write_data);
+
+	mutex_unlock(&bus->mdio_lock);
+	
+	return 0;
+}
+
+static int rtl8367s_hw_reset(void)
+{
+	struct rtk_gsw *gsw = _gsw;
+	int ret;
+
+	if (gsw->reset_pin < 0)
+		return 0;
+
+	ret = devm_gpio_request(gsw->dev, gsw->reset_pin, "mediatek,reset-pin");
+
+	if (ret)
+                printk("fail to devm_gpio_request\n");
+
+	gpio_direction_output(gsw->reset_pin, 0);
+
+	usleep_range(1000, 1100);
+
+	gpio_set_value(gsw->reset_pin, 1);
+
+	mdelay(500);
+
+	devm_gpio_free(gsw->dev, gsw->reset_pin);
+
+	return 0;
+	
+}
+
+static int rtl8367s_vlan_config(int want_at_p0)
+{
+	rtk_vlan_cfg_t vlan1, vlan2;
+	
+	/* Set LAN/WAN VLAN partition */
+	memset(&vlan1, 0x00, sizeof(rtk_vlan_cfg_t));
+
+	RTK_PORTMASK_PORT_SET(vlan1.mbr, EXT_PORT0);
+	RTK_PORTMASK_PORT_SET(vlan1.mbr, UTP_PORT1);
+	RTK_PORTMASK_PORT_SET(vlan1.mbr, UTP_PORT2);
+	RTK_PORTMASK_PORT_SET(vlan1.mbr, UTP_PORT3);
+	RTK_PORTMASK_PORT_SET(vlan1.untag, EXT_PORT0);
+	RTK_PORTMASK_PORT_SET(vlan1.untag, UTP_PORT1);
+	RTK_PORTMASK_PORT_SET(vlan1.untag, UTP_PORT2);
+	RTK_PORTMASK_PORT_SET(vlan1.untag, UTP_PORT3);
+  
+	 if (want_at_p0) {
+		RTK_PORTMASK_PORT_SET(vlan1.mbr, UTP_PORT4);
+		RTK_PORTMASK_PORT_SET(vlan1.untag, UTP_PORT4);
+        } else {
+		RTK_PORTMASK_PORT_SET(vlan1.mbr, UTP_PORT0);
+		RTK_PORTMASK_PORT_SET(vlan1.untag, UTP_PORT0);
+        }
+
+	vlan1.ivl_en = 1;
+	
+	rtk_vlan_set(1, &vlan1);
+	
+	memset(&vlan2, 0x00, sizeof(rtk_vlan_cfg_t));
+	
+	RTK_PORTMASK_PORT_SET(vlan2.mbr, EXT_PORT1);
+	RTK_PORTMASK_PORT_SET(vlan2.untag, EXT_PORT1);
+
+	if (want_at_p0) {
+		RTK_PORTMASK_PORT_SET(vlan2.mbr, UTP_PORT0);
+		RTK_PORTMASK_PORT_SET(vlan2.untag, UTP_PORT0);
+	} else {
+		RTK_PORTMASK_PORT_SET(vlan2.mbr, UTP_PORT4);
+		RTK_PORTMASK_PORT_SET(vlan2.untag, UTP_PORT4);
+	}
+
+	vlan2.ivl_en = 1;
+	rtk_vlan_set(2, &vlan2);
+
+	rtk_vlan_portPvid_set(EXT_PORT0, 1, 0);
+	rtk_vlan_portPvid_set(UTP_PORT1, 1, 0);
+	rtk_vlan_portPvid_set(UTP_PORT2, 1, 0);
+	rtk_vlan_portPvid_set(UTP_PORT3, 1, 0);
+	rtk_vlan_portPvid_set(EXT_PORT1, 2, 0);
+
+	if (want_at_p0) {
+		rtk_vlan_portPvid_set(UTP_PORT0, 2, 0);
+		rtk_vlan_portPvid_set(UTP_PORT4, 1, 0);
+	} else {
+		rtk_vlan_portPvid_set(UTP_PORT0, 1, 0);
+		rtk_vlan_portPvid_set(UTP_PORT4, 2, 0);
+	}
+
+	return 0;	
+}
+
+static int rtl8367s_hw_init(void)
+{
+
+	rtl8367s_hw_reset();
+
+	if(rtk_switch_init())
+	        return -1;
+
+	mdelay(500);
+
+	if (rtk_vlan_reset())
+	        return -1;
+
+	if (rtk_vlan_init())
+	        return -1;
+
+	return 0;
+}
+
+static void set_rtl8367s_sgmii(void)
+{
+	rtk_port_mac_ability_t mac_cfg;
+	rtk_mode_ext_t mode;
+
+	mode = MODE_EXT_HSGMII;
+	mac_cfg.forcemode = MAC_FORCE;
+	mac_cfg.speed = PORT_SPEED_2500M;
+	mac_cfg.duplex = PORT_FULL_DUPLEX;
+	mac_cfg.link = PORT_LINKUP;
+	mac_cfg.nway = DISABLED;
+	mac_cfg.txpause = ENABLED;
+	mac_cfg.rxpause = ENABLED;
+	rtk_port_macForceLinkExt_set(EXT_PORT0, mode, &mac_cfg);
+	rtk_port_sgmiiNway_set(EXT_PORT0, DISABLED);
+	rtk_port_phyEnableAll_set(ENABLED);
+
+}
+
+static void set_rtl8367s_rgmii(void)
+{
+	rtk_port_mac_ability_t mac_cfg;
+	rtk_mode_ext_t mode;
+
+	mode = MODE_EXT_RGMII;
+	mac_cfg.forcemode = MAC_FORCE;
+	mac_cfg.speed = PORT_SPEED_1000M;
+	mac_cfg.duplex = PORT_FULL_DUPLEX;
+	mac_cfg.link = PORT_LINKUP;
+	mac_cfg.nway = DISABLED;
+	mac_cfg.txpause = ENABLED;
+	mac_cfg.rxpause = ENABLED;
+	rtk_port_macForceLinkExt_set(EXT_PORT1, mode, &mac_cfg);
+	rtk_port_rgmiiDelayExt_set(EXT_PORT1, 1, 3);
+	rtk_port_phyEnableAll_set(ENABLED);
+	
+}
+
+void init_gsw(void)
+{
+	rtl8367s_hw_init();
+	set_rtl8367s_sgmii();
+	set_rtl8367s_rgmii();
+}
+
+// bleow are platform driver
+static const struct of_device_id rtk_gsw_match[] = {
+	{ .compatible = "mediatek,rtk-gsw" },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, rtk_gsw_match);
+
+static int rtk_gsw_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *mdio;
+	struct mii_bus *mdio_bus;
+	struct rtk_gsw *gsw;
+	const char *pm;
+
+	mdio = of_parse_phandle(np, "mediatek,mdio", 0);
+
+	if (!mdio)
+		return -EINVAL;
+
+	mdio_bus = of_mdio_find_bus(mdio);
+
+	if (!mdio_bus)
+		return -EPROBE_DEFER;
+
+	gsw = devm_kzalloc(&pdev->dev, sizeof(struct rtk_gsw), GFP_KERNEL);
+	
+	if (!gsw)
+		return -ENOMEM;	
+
+	gsw->dev = &pdev->dev;
+
+	gsw->bus = mdio_bus;
+
+	gsw->reset_pin = of_get_named_gpio(np, "mediatek,reset-pin", 0);
+
+	_gsw = gsw;
+
+	init_gsw();
+
+	//init default vlan or init swocnfig
+	if(!of_property_read_string(pdev->dev.of_node,
+						"mediatek,port_map", &pm)) {
+
+		if (!strcasecmp(pm, "wllll"))
+			rtl8367s_vlan_config(1); 
+		else
+			rtl8367s_vlan_config(0);
+		
+		} else {
+#ifdef CONFIG_SWCONFIG		
+		rtl8367s_swconfig_init(&init_gsw);
+#else
+		rtl8367s_vlan_config(0);
+#endif
+	}
+
+	gsw_debug_proc_init();
+
+	platform_set_drvdata(pdev, gsw);
+
+	return 0;
+	
+}
+
+static int rtk_gsw_remove(struct platform_device *pdev)
+{
+	platform_set_drvdata(pdev, NULL);
+	gsw_debug_proc_exit();
+
+	return 0;
+}
+
+static struct platform_driver gsw_driver = {
+	.probe = rtk_gsw_probe,
+	.remove = rtk_gsw_remove,
+	.driver = {
+		.name = "rtk-gsw",
+		.owner = THIS_MODULE,
+		.of_match_table = rtk_gsw_match,
+	},
+};
+
+module_platform_driver(gsw_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mark Lee <marklee0201@gmail.com>");
+MODULE_DESCRIPTION("rtl8367c switch driver for MT7622");
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/wireless/wifi_utility/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/wireless/wifi_utility/Makefile
new file mode 100644
index 0000000..25cc107
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/wireless/wifi_utility/Makefile
@@ -0,0 +1,4 @@
+#always build-in
+obj-y += mt_wifi_mtd.o
+obj-y += pci_mediatek_rbus.o
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/wireless/wifi_utility/mt_wifi_mtd.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/wireless/wifi_utility/mt_wifi_mtd.c
new file mode 100644
index 0000000..9294c73
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/wireless/wifi_utility/mt_wifi_mtd.c
@@ -0,0 +1,98 @@
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/concat.h>
+#include <linux/mtd/partitions.h>
+#if defined (CONFIG_MIPS)
+#include <asm/addrspace.h>
+#endif
+
+int mt_mtd_write_nm_wifi(char *name, loff_t to, size_t len, const u_char *buf)
+{
+	int ret = -1;
+	size_t rdlen, wrlen;
+	struct mtd_info *mtd;
+	struct erase_info ei;
+	u_char *bak = NULL;
+
+	mtd = get_mtd_device_nm(name);
+	if (IS_ERR(mtd))
+		return -1;
+
+	if (len > mtd->erasesize) {
+		put_mtd_device(mtd);
+		return -E2BIG;
+	}
+
+	bak = kmalloc(mtd->erasesize, GFP_KERNEL);
+	if (bak == NULL) {
+		put_mtd_device(mtd);
+		return -ENOMEM;
+	}
+
+	ret = mtd_read(mtd, 0, mtd->erasesize, &rdlen, bak);
+
+	if (ret != 0) {
+		put_mtd_device(mtd);
+		kfree(bak);
+		return ret;
+	}
+
+	if (rdlen != mtd->erasesize)
+		printk("warning: ra_mtd_write: rdlen is not equal to erasesize\n");
+
+	memcpy(bak + to, buf, len);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0))
+	ei.mtd = mtd;
+	ei.callback = NULL;
+	ei.priv = 0;
+#endif
+	ei.addr = 0;
+	ei.len = mtd->erasesize;
+	ret = mtd_erase(mtd, &ei);
+
+	if (ret != 0) {
+		put_mtd_device(mtd);
+		kfree(bak);
+		return ret;
+	}
+
+	ret = mtd_write(mtd, 0, mtd->erasesize, &wrlen, bak);
+
+
+
+	put_mtd_device(mtd);
+	kfree(bak);
+	return ret;
+}
+EXPORT_SYMBOL(mt_mtd_write_nm_wifi);
+
+
+int mt_mtd_read_nm_wifi(char *name, loff_t from, size_t len, u_char *buf)
+{
+	int ret;
+	size_t rdlen;
+	struct mtd_info *mtd;
+
+	mtd = get_mtd_device_nm(name);
+	if (IS_ERR(mtd))
+		return -1;
+
+	ret = mtd_read(mtd, from, len, &rdlen, buf);
+
+	if (rdlen != len)
+			printk("warning: ra_mtd_read_nm: rdlen is not equal to len\n");
+
+	put_mtd_device(mtd);
+
+	return ret;
+}
+EXPORT_SYMBOL(mt_mtd_read_nm_wifi);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/wireless/wifi_utility/pci_mediatek_rbus.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/wireless/wifi_utility/pci_mediatek_rbus.c
new file mode 100644
index 0000000..840834d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/wireless/wifi_utility/pci_mediatek_rbus.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2017 MediaTek Inc.
+ * Author: Star Chang <star.chang@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_pci.h>
+#include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/resource.h>
+#include <linux/types.h>
+#include <linux/pinctrl/consumer.h>
+
+
+/*platform device & platform driver match name*/
+#define OF_RBUS_NAME "mediatek,wbsys"
+#define OF_PIO_NAME "mediatek,mt7622-pctl-a-syscfg"
+
+#define RBUS_VENDOR_ID_OFFSET 0
+#define RBUS_CHIP_ID_OFFSET 2
+#define RBUS_BAR_OFFSET 0x10
+#define RBUS_DEFAULT_CHIP_ID 0x7622
+#define RBUS_DEFAULT_VEND_ID 0x14c3
+#define RBUS_TSSI_CTRL_OFFSET 0x34
+#define RBUS_TSSI_CTRL_MASK 0x1
+#define RBUS_PA_LNA_CTRL_OFFSET 0x38
+#define RBUS_PA_LNA_CTRL_MASK 0x3
+
+#define GPIO_G2_MISC_OFFSET 0x00000AF0
+#define GPIO_G2_MISC_MASK 0xffffff00
+
+static char rbus_string[] = "rbus";
+unsigned int dev_second_irq = 0;
+unsigned int multi_intr_2nd = 0;
+unsigned int multi_intr_3rd = 0;
+unsigned int multi_intr_4th = 0;
+EXPORT_SYMBOL(dev_second_irq);
+EXPORT_SYMBOL(multi_intr_2nd);
+EXPORT_SYMBOL(multi_intr_3rd);
+EXPORT_SYMBOL(multi_intr_4th);
+
+static const struct of_device_id rbus_of_ids[] = {
+	{   .compatible = OF_RBUS_NAME, },
+	{ },
+};
+
+struct rbus_dev {
+	char name[36];
+	struct device *dev;
+	struct resource *res;
+	struct list_head resources;
+	unsigned int base_addr;
+	unsigned int irq;
+	unsigned int chip_id;
+	unsigned int vend_id;
+};
+
+enum {
+	TSSI_MODE_DIS=0,
+	TSSI_MODE_EN=1
+};
+
+enum {
+	IPA_ILNA_MODE=0,
+	IPA_ELNA_MODE=1,
+	EPA_ELNA_MODE=2,
+	EPA_ILNA_MODE=3
+};
+
+#define RBUS_IO_READ32(_A, _R, _pV) (*(_pV) = readl((void *)(_A + _R)))
+#define RBUS_IO_WRITE32(_A, _R, _V)	 writel(_V, (void *)(_A + _R))
+
+/*fake configure space*/
+static unsigned char rbus_conf_space[] = {
+	0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x10, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x76, 0xc3, 0x14,
+	0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x60, 0x61, 0x12, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x05, 0x78, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0xc3, 0x01, 0x08, 0x00, 0x00, 0x00,
+	0x10, 0x00, 0x02, 0x00, 0x40, 0x83, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x12, 0x8c, 0x40, 0x01,
+	0x43, 0x00, 0x12, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static int
+rbus_tssi_config(struct platform_device *pdev, unsigned char mode)
+{
+	struct device_node *node = NULL;
+	unsigned long addr;
+	unsigned int value = 0;
+
+	node = of_find_compatible_node(NULL, NULL, OF_PIO_NAME);
+	if (!node) {
+		dev_err(&pdev->dev, "%s(): can't find node for %s\n", __func__, OF_PIO_NAME);
+		return -ENODEV;
+	}
+
+	addr = (unsigned long) of_iomap(node, 0);
+	RBUS_IO_READ32(addr, GPIO_G2_MISC_OFFSET, &value);
+
+	if (mode == TSSI_MODE_EN) {
+		value &= GPIO_G2_MISC_MASK;
+		RBUS_IO_WRITE32(addr, GPIO_G2_MISC_OFFSET, value);
+	}
+
+	RBUS_IO_READ32(addr, GPIO_G2_MISC_OFFSET, &value);
+	return 0;
+}
+
+static int
+rbus_pa_lan_config(struct platform_device *pdev, unsigned int devfn, unsigned char mode)
+{
+	struct pinctrl *p;
+	struct pinctrl_state *s;
+	unsigned char state[32] = "";
+	int ret = 0;
+
+	if (mode != IPA_ELNA_MODE && mode != EPA_ELNA_MODE)
+		return ret;
+
+	p = devm_pinctrl_get(&pdev->dev);
+
+	if (!p) {
+		dev_err(&pdev->dev, "%s(): can't get pinctrl by dev:%p\n", __func__, &pdev->dev);
+		return ret;
+	}
+
+	strncpy(state, "state_epa", sizeof("state_epa"));
+
+	s = pinctrl_lookup_state(p, state);
+
+	if (!s) {
+		dev_err(&pdev->dev, "%s(): can't find pinctrl state: %s\n", __func__, state);
+		return ret;
+	}
+
+	ret = pinctrl_select_state(p, s);
+
+	if (ret < 0)
+		dev_err(&pdev->dev, "%s(): pinctrl select to %s fail!, ret=%d\n", __func__, state, ret);
+
+	return ret;
+}
+
+static void
+rbus_init_config(struct rbus_dev *rbus)
+{
+	rbus_conf_space[RBUS_VENDOR_ID_OFFSET] = rbus->vend_id & 0xff;
+	rbus_conf_space[RBUS_VENDOR_ID_OFFSET + 1] = (rbus->vend_id >> 8) & 0xff;
+	rbus_conf_space[RBUS_CHIP_ID_OFFSET] = rbus->chip_id & 0xff;
+	rbus_conf_space[RBUS_CHIP_ID_OFFSET + 1] = (rbus->chip_id >> 8) & 0xff;
+	rbus_conf_space[RBUS_BAR_OFFSET + 3] = (rbus->base_addr >> 24) & 0xff;
+	rbus_conf_space[RBUS_BAR_OFFSET + 2] = (rbus->base_addr >> 16) & 0xff;
+	rbus_conf_space[RBUS_BAR_OFFSET + 1] = (rbus->base_addr >> 8) & 0xff;
+}
+
+static int
+rbus_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+			int size, u32 *value)
+{
+	u32 *cr;
+
+	if(where >= sizeof(rbus_conf_space))
+		return PCIBIOS_BUFFER_TOO_SMALL;
+
+	cr = (u32 *) &rbus_conf_space[where];
+
+	if(devfn == 0)
+		*value = *cr;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+rbus_write_config(struct pci_bus *bus, unsigned int devfn, int where,
+			int size, u32 value)
+{
+	int i;
+	struct platform_device *pdev = bus->sysdata;
+
+	if (devfn != 0)
+		goto end;
+
+	for (i = 0 ; i < size ; i++) {
+		rbus_conf_space[where + i] = (value << (i * 8)) & 0xff;
+	}
+	/*handle vendor specific action*/
+	switch(where) {
+	case RBUS_TSSI_CTRL_OFFSET:
+		rbus_tssi_config(pdev, (value & RBUS_TSSI_CTRL_MASK));
+	break;
+	case RBUS_PA_LNA_CTRL_OFFSET:
+		rbus_pa_lan_config(pdev, devfn, (value & RBUS_PA_LNA_CTRL_MASK));
+	break;
+	default:
+	break;
+	}
+end:
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
+struct pci_ops rbus_ops = {
+	.read  = rbus_read_config,
+	.write = rbus_write_config,
+};
+
+static int rbus_add_port(struct rbus_dev *rbus,
+				   struct platform_device *pdev)
+{
+	struct pci_bus *bus;
+	struct pci_dev *pci;
+
+	bus = pci_scan_root_bus(&pdev->dev, 0, &rbus_ops,
+				pdev, &rbus->resources);
+
+	if (!bus)
+		return -ENOMEM;
+
+	pci_bus_add_devices(bus);
+
+	pci = pci_scan_single_device(bus, 0);
+
+	if (pci) {
+		/*re-assign hw resource*/
+		pci->irq = rbus->irq;
+		pci->resource[0].start = rbus->res->start;
+		pci->resource[0].end = rbus->res->end;
+	}
+	return 0;
+}
+
+static int rbus_add_res(struct rbus_dev *rbus)
+{
+	struct device *dev = rbus->dev;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct resource bus_range;
+
+	INIT_LIST_HEAD(&rbus->resources);
+	/*resource allocate*/
+	rbus->res  = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	rbus->irq = platform_get_irq(pdev, 0);
+	rbus->base_addr = (unsigned int)rbus->res->start;
+	if (rbus->chip_id == 0x7629)
+		dev_second_irq = platform_get_irq(pdev, 1);
+	else if (rbus->chip_id == 0x7986) {
+		multi_intr_2nd = platform_get_irq(pdev, 1);
+		multi_intr_3rd = platform_get_irq(pdev, 2);
+		multi_intr_4th = platform_get_irq(pdev, 3);
+	}
+
+	pci_add_resource(&rbus->resources, rbus->res);
+
+	bus_range = (struct resource) {
+		.name	= "rbus_range",
+		.start	= 0,
+		.end	= 0xff,
+		.flags	= IORESOURCE_BUS,
+	};
+
+	pci_add_resource(&rbus->resources, &bus_range);
+	return 0;
+}
+
+/*
+*
+*/
+static int rbus_probe(struct platform_device *pdev)
+{
+	struct device_node *node = NULL;
+	struct rbus_dev *rbus;
+
+	node = of_find_compatible_node(NULL, NULL, OF_RBUS_NAME);
+	if (!node)
+		return -ENODEV;
+
+	rbus = devm_kzalloc(&pdev->dev, sizeof(*rbus), GFP_KERNEL);
+	if (!rbus)
+		return -ENOMEM;
+
+	rbus->dev = &pdev->dev;
+
+	if (of_property_read_u32_index(node, "chip_id", 0, &rbus->chip_id)) {
+		rbus->chip_id = RBUS_DEFAULT_CHIP_ID;
+	}
+
+	if (of_property_read_u32_index(node, "vend_id", 0, &rbus->vend_id)) {
+		rbus->vend_id = RBUS_DEFAULT_VEND_ID;
+	}
+	/*set priv_data to pdev*/
+	snprintf(rbus->name,sizeof(rbus->name),"mediatek-rbus");
+	platform_set_drvdata(pdev, rbus);
+	rbus_add_res(rbus);
+	/*init config, need run before add port*/
+	rbus_init_config(rbus);
+	/*add pci bus & device*/
+	rbus_add_port(rbus, pdev);
+	return -ENODEV;
+}
+
+/*
+*
+*/
+static int rbus_remove(struct platform_device *pdev)
+{
+	struct rbus_dev *rbus = platform_get_drvdata(pdev);
+	dev_err(&pdev->dev, "remove rbus name: %s\n", rbus->name);
+	return 0;
+}
+
+
+/*
+* global resource preparing
+*/
+static struct platform_driver rbus_driver = {
+	.probe  = rbus_probe,
+	.remove = rbus_remove,
+	.driver = {
+		.name   = rbus_string,
+		.owner  = THIS_MODULE,
+#ifdef CONFIG_OF
+		.of_match_table = rbus_of_ids,
+#endif /*CONFIG_OF*/
+	},
+};
+
+/* PCIe driver does not allow module unload */
+static int __init rbus_init(void)
+{
+	return platform_driver_probe(&rbus_driver, rbus_probe);
+}
+
+subsys_initcall_sync(rbus_init);
+
+MODULE_DESCRIPTION("Mediatek RBUS host controller driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pci/controller/pcie-mediatek-gen3.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pci/controller/pcie-mediatek-gen3.c
new file mode 100644
index 0000000..0e01fde
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pci/controller/pcie-mediatek-gen3.c
@@ -0,0 +1,1147 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek PCIe host controller driver.
+ *
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Jianjun Wang <jianjun.wang@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of_pci.h>
+#include <linux/pci.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+#include "../pci.h"
+
+#define PCIE_SETTING_REG		0x80
+#define PCIE_PCI_IDS_1			0x9c
+#define PCI_CLASS(class)		(class << 8)
+#define PCIE_RC_MODE			BIT(0)
+
+#define PCIE_CFGNUM_REG			0x140
+#define PCIE_CFG_DEVFN(devfn)		((devfn) & GENMASK(7, 0))
+#define PCIE_CFG_BUS(bus)		(((bus) << 8) & GENMASK(15, 8))
+#define PCIE_CFG_BYTE_EN(bytes)		(((bytes) << 16) & GENMASK(19, 16))
+#define PCIE_CFG_FORCE_BYTE_EN		BIT(20)
+#define PCIE_CFG_OFFSET_ADDR		0x1000
+#define PCIE_CFG_HEADER(bus, devfn) \
+	(PCIE_CFG_BUS(bus) | PCIE_CFG_DEVFN(devfn))
+
+#define PCIE_RST_CTRL_REG		0x148
+#define PCIE_MAC_RSTB			BIT(0)
+#define PCIE_PHY_RSTB			BIT(1)
+#define PCIE_BRG_RSTB			BIT(2)
+#define PCIE_PE_RSTB			BIT(3)
+
+#define PCIE_LTSSM_STATUS_REG		0x150
+#define PCIE_LTSSM_STATE_MASK		GENMASK(28, 24)
+#define PCIE_LTSSM_STATE(val)		((val & PCIE_LTSSM_STATE_MASK) >> 24)
+#define PCIE_LTSSM_STATE_L2_IDLE	0x14
+
+#define PCIE_LINK_STATUS_REG		0x154
+#define PCIE_PORT_LINKUP		BIT(8)
+
+#define PCIE_MSI_SET_NUM		8
+#define PCIE_MSI_IRQS_PER_SET		32
+#define PCIE_MSI_IRQS_NUM \
+	(PCIE_MSI_IRQS_PER_SET * PCIE_MSI_SET_NUM)
+
+#define PCIE_INT_ENABLE_REG		0x180
+#define PCIE_MSI_ENABLE			GENMASK(PCIE_MSI_SET_NUM + 8 - 1, 8)
+#define PCIE_MSI_SHIFT			8
+#define PCIE_INTX_SHIFT			24
+#define PCIE_INTX_ENABLE \
+	GENMASK(PCIE_INTX_SHIFT + PCI_NUM_INTX - 1, PCIE_INTX_SHIFT)
+
+#define PCIE_INT_STATUS_REG		0x184
+#define PCIE_MSI_SET_ENABLE_REG		0x190
+#define PCIE_MSI_SET_ENABLE		GENMASK(PCIE_MSI_SET_NUM - 1, 0)
+
+#define PCIE_MSI_SET_BASE_REG		0xc00
+#define PCIE_MSI_SET_OFFSET		0x10
+#define PCIE_MSI_SET_STATUS_OFFSET	0x04
+#define PCIE_MSI_SET_ENABLE_OFFSET	0x08
+#define PCIE_MSI_SET_GRP1_ENABLE_OFFSET	0x0c
+
+#define PCIE_MSI_SET_ADDR_HI_BASE	0xc80
+#define PCIE_MSI_SET_ADDR_HI_OFFSET	0x04
+
+#define PCIE_ICMD_PM_REG		0x198
+#define PCIE_TURN_OFF_LINK		BIT(4)
+
+#define PCIE_TRANS_TABLE_BASE_REG	0x800
+#define PCIE_ATR_SRC_ADDR_MSB_OFFSET	0x4
+#define PCIE_ATR_TRSL_ADDR_LSB_OFFSET	0x8
+#define PCIE_ATR_TRSL_ADDR_MSB_OFFSET	0xc
+#define PCIE_ATR_TRSL_PARAM_OFFSET	0x10
+#define PCIE_ATR_TLB_SET_OFFSET		0x20
+
+#define PCIE_MAX_TRANS_TABLES		8
+#define PCIE_ATR_EN			BIT(0)
+#define PCIE_ATR_SIZE(size) \
+	(((((size) - 1) << 1) & GENMASK(6, 1)) | PCIE_ATR_EN)
+#define PCIE_ATR_ID(id)			((id) & GENMASK(3, 0))
+#define PCIE_ATR_TYPE_MEM		PCIE_ATR_ID(0)
+#define PCIE_ATR_TYPE_IO		PCIE_ATR_ID(1)
+#define PCIE_ATR_TLP_TYPE(type)		(((type) << 16) & GENMASK(18, 16))
+#define PCIE_ATR_TLP_TYPE_MEM		PCIE_ATR_TLP_TYPE(0)
+#define PCIE_ATR_TLP_TYPE_IO		PCIE_ATR_TLP_TYPE(2)
+
+/**
+ * struct mtk_msi_set - MSI information for each set
+ * @base: IO mapped register base
+ * @msg_addr: MSI message address
+ * @saved_irq_state: IRQ enable state saved at suspend time
+ */
+struct mtk_msi_set {
+	void __iomem *base;
+	phys_addr_t msg_addr;
+	u32 saved_irq_state;
+};
+
+/**
+ * struct mtk_pcie_port - PCIe port information
+ * @dev: pointer to PCIe device
+ * @base: IO mapped register base
+ * @reg_base: physical register base
+ * @mac_reset: MAC reset control
+ * @phy_reset: PHY reset control
+ * @phy: PHY controller block
+ * @clks: PCIe clocks
+ * @num_clks: PCIe clocks count for this port
+ * @irq: PCIe controller interrupt number
+ * @saved_irq_state: IRQ enable state saved at suspend time
+ * @irq_lock: lock protecting IRQ register access
+ * @intx_domain: legacy INTx IRQ domain
+ * @msi_domain: MSI IRQ domain
+ * @msi_bottom_domain: MSI IRQ bottom domain
+ * @msi_sets: MSI sets information
+ * @lock: lock protecting IRQ bit map
+ * @msi_irq_in_use: bit map for assigned MSI IRQ
+ */
+struct mtk_pcie_port {
+	struct device *dev;
+	void __iomem *base;
+	phys_addr_t reg_base;
+	struct reset_control *mac_reset;
+	struct reset_control *phy_reset;
+	struct phy *phy;
+	struct clk_bulk_data *clks;
+	int num_clks;
+
+	int irq;
+	int direct_msi_enable;
+	int direct_msi[PCIE_MSI_IRQS_PER_SET];
+	u32 saved_irq_state;
+	raw_spinlock_t irq_lock;
+	struct irq_domain *intx_domain;
+	struct irq_domain *msi_domain;
+	struct irq_domain *msi_bottom_domain;
+	struct mtk_msi_set msi_sets[PCIE_MSI_SET_NUM];
+	struct mutex lock;
+	DECLARE_BITMAP(msi_irq_in_use, PCIE_MSI_IRQS_NUM);
+};
+
+/**
+ * mtk_pcie_config_tlp_header() - Configure a configuration TLP header
+ * @bus: PCI bus to query
+ * @devfn: device/function number
+ * @where: offset in config space
+ * @size: data size in TLP header
+ *
+ * Set byte enable field and device information in configuration TLP header.
+ */
+static void mtk_pcie_config_tlp_header(struct pci_bus *bus, unsigned int devfn,
+					int where, int size)
+{
+	struct mtk_pcie_port *port = bus->sysdata;
+	int bytes;
+	u32 val;
+
+	bytes = (GENMASK(size - 1, 0) & 0xf) << (where & 0x3);
+
+	val = PCIE_CFG_FORCE_BYTE_EN | PCIE_CFG_BYTE_EN(bytes) |
+	      PCIE_CFG_HEADER(bus->number, devfn);
+
+	writel_relaxed(val, port->base + PCIE_CFGNUM_REG);
+}
+
+static void __iomem *mtk_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
+				      int where)
+{
+	struct mtk_pcie_port *port = bus->sysdata;
+
+	return port->base + PCIE_CFG_OFFSET_ADDR + where;
+}
+
+static int mtk_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
+				int where, int size, u32 *val)
+{
+	mtk_pcie_config_tlp_header(bus, devfn, where, size);
+
+	return pci_generic_config_read32(bus, devfn, where, size, val);
+}
+
+static int mtk_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
+				 int where, int size, u32 val)
+{
+	mtk_pcie_config_tlp_header(bus, devfn, where, size);
+
+	if (size <= 2)
+		val <<= (where & 0x3) * 8;
+
+	return pci_generic_config_write32(bus, devfn, where, 4, val);
+}
+
+static struct pci_ops mtk_pcie_ops = {
+	.map_bus = mtk_pcie_map_bus,
+	.read  = mtk_pcie_config_read,
+	.write = mtk_pcie_config_write,
+};
+
+static int mtk_pcie_set_trans_table(struct mtk_pcie_port *port,
+				    resource_size_t cpu_addr,
+				    resource_size_t pci_addr,
+				    resource_size_t size,
+				    unsigned long type, int num)
+{
+	void __iomem *table;
+	u32 val;
+
+	if (num >= PCIE_MAX_TRANS_TABLES) {
+		dev_err(port->dev, "not enough translate table for addr: %#llx, limited to [%d]\n",
+			(unsigned long long)cpu_addr, PCIE_MAX_TRANS_TABLES);
+		return -ENODEV;
+	}
+
+	table = port->base + PCIE_TRANS_TABLE_BASE_REG +
+		num * PCIE_ATR_TLB_SET_OFFSET;
+
+	writel_relaxed(lower_32_bits(cpu_addr) | PCIE_ATR_SIZE(fls(size) - 1),
+		       table);
+	writel_relaxed(upper_32_bits(cpu_addr),
+		       table + PCIE_ATR_SRC_ADDR_MSB_OFFSET);
+	writel_relaxed(lower_32_bits(pci_addr),
+		       table + PCIE_ATR_TRSL_ADDR_LSB_OFFSET);
+	writel_relaxed(upper_32_bits(pci_addr),
+		       table + PCIE_ATR_TRSL_ADDR_MSB_OFFSET);
+
+	if (type == IORESOURCE_IO)
+		val = PCIE_ATR_TYPE_IO | PCIE_ATR_TLP_TYPE_IO;
+	else
+		val = PCIE_ATR_TYPE_MEM | PCIE_ATR_TLP_TYPE_MEM;
+
+	writel_relaxed(val, table + PCIE_ATR_TRSL_PARAM_OFFSET);
+
+	return 0;
+}
+
+static void mtk_pcie_enable_msi(struct mtk_pcie_port *port)
+{
+	int i;
+	u32 val;
+
+	for (i = 0; i < PCIE_MSI_SET_NUM; i++) {
+		struct mtk_msi_set *msi_set = &port->msi_sets[i];
+
+		msi_set->base = port->base + PCIE_MSI_SET_BASE_REG +
+				i * PCIE_MSI_SET_OFFSET;
+		msi_set->msg_addr = port->reg_base + PCIE_MSI_SET_BASE_REG +
+				    i * PCIE_MSI_SET_OFFSET;
+
+		/* Configure the MSI capture address */
+		writel_relaxed(lower_32_bits(msi_set->msg_addr), msi_set->base);
+		writel_relaxed(upper_32_bits(msi_set->msg_addr),
+			       port->base + PCIE_MSI_SET_ADDR_HI_BASE +
+			       i * PCIE_MSI_SET_ADDR_HI_OFFSET);
+	}
+
+	val = readl_relaxed(port->base + PCIE_MSI_SET_ENABLE_REG);
+	val |= PCIE_MSI_SET_ENABLE;
+	writel_relaxed(val, port->base + PCIE_MSI_SET_ENABLE_REG);
+
+	if (!port->direct_msi_enable) {
+		val = readl_relaxed(port->base + PCIE_INT_ENABLE_REG);
+		val |= PCIE_MSI_ENABLE;
+		writel_relaxed(val, port->base + PCIE_INT_ENABLE_REG);
+	}
+}
+
+static int mtk_pcie_startup_port(struct mtk_pcie_port *port)
+{
+	struct resource_entry *entry;
+	struct pci_host_bridge *host = pci_host_bridge_from_priv(port);
+	unsigned int table_index = 0;
+	int err;
+	u32 val;
+
+	/* Set as RC mode */
+	val = readl_relaxed(port->base + PCIE_SETTING_REG);
+	val |= PCIE_RC_MODE;
+	writel_relaxed(val, port->base + PCIE_SETTING_REG);
+
+	/* Set class code */
+	val = readl_relaxed(port->base + PCIE_PCI_IDS_1);
+	val &= ~GENMASK(31, 8);
+	val |= PCI_CLASS(PCI_CLASS_BRIDGE_PCI << 8);
+	writel_relaxed(val, port->base + PCIE_PCI_IDS_1);
+
+	/* Mask all INTx interrupts */
+	val = readl_relaxed(port->base + PCIE_INT_ENABLE_REG);
+	val &= ~PCIE_INTX_ENABLE;
+	writel_relaxed(val, port->base + PCIE_INT_ENABLE_REG);
+
+	/* Assert all reset signals */
+	val = readl_relaxed(port->base + PCIE_RST_CTRL_REG);
+	val |= PCIE_MAC_RSTB | PCIE_PHY_RSTB | PCIE_BRG_RSTB | PCIE_PE_RSTB;
+	writel_relaxed(val, port->base + PCIE_RST_CTRL_REG);
+
+	/*
+	 * Described in PCIe CEM specification setctions 2.2 (PERST# Signal)
+	 * and 2.2.1 (Initial Power-Up (G3 to S0)).
+	 * The deassertion of PERST# should be delayed 100ms (TPVPERL)
+	 * for the power and clock to become stable.
+	 */
+	msleep(100);
+
+	/* De-assert reset signals */
+	val &= ~(PCIE_MAC_RSTB | PCIE_PHY_RSTB | PCIE_BRG_RSTB | PCIE_PE_RSTB);
+	writel_relaxed(val, port->base + PCIE_RST_CTRL_REG);
+
+	/* Check if the link is up or not */
+	err = readl_poll_timeout(port->base + PCIE_LINK_STATUS_REG, val,
+				 !!(val & PCIE_PORT_LINKUP), 20,
+				 PCI_PM_D3COLD_WAIT * USEC_PER_MSEC);
+	if (err) {
+		val = readl_relaxed(port->base + PCIE_LTSSM_STATUS_REG);
+		dev_err(port->dev, "PCIe link down, ltssm reg val: %#x\n", val);
+		return err;
+	}
+
+	mtk_pcie_enable_msi(port);
+
+	/* Set PCIe translation windows */
+	resource_list_for_each_entry(entry, &host->windows) {
+		struct resource *res = entry->res;
+		unsigned long type = resource_type(res);
+		resource_size_t cpu_addr;
+		resource_size_t pci_addr;
+		resource_size_t size;
+		const char *range_type;
+
+		if (type == IORESOURCE_IO) {
+			cpu_addr = pci_pio_to_address(res->start);
+			range_type = "IO";
+		} else if (type == IORESOURCE_MEM) {
+			cpu_addr = res->start;
+			range_type = "MEM";
+		} else {
+			continue;
+		}
+
+		pci_addr = res->start - entry->offset;
+		size = resource_size(res);
+		err = mtk_pcie_set_trans_table(port, cpu_addr, pci_addr, size,
+					       type, table_index);
+		if (err)
+			return err;
+
+		dev_dbg(port->dev, "set %s trans window[%d]: cpu_addr = %#llx, pci_addr = %#llx, size = %#llx\n",
+			range_type, table_index, (unsigned long long)cpu_addr,
+			(unsigned long long)pci_addr, (unsigned long long)size);
+
+		table_index++;
+	}
+
+	return 0;
+}
+
+static int mtk_pcie_set_msi_affinity(struct irq_data *data,
+				 const struct cpumask *mask, bool force)
+{
+	struct mtk_pcie_port *port = data->domain->host_data;
+	struct irq_data *port_data;
+	struct irq_chip *port_chip;
+	int msi_bit, irq, ret;
+
+	msi_bit = data->hwirq % PCIE_MSI_IRQS_PER_SET;
+	irq = port->direct_msi[msi_bit];
+
+	port_data = irq_get_irq_data(irq);
+	port_chip = irq_data_get_irq_chip(port_data);
+	if (!port_chip || !port_chip->irq_set_affinity)
+		return -EINVAL;
+
+	ret = port_chip->irq_set_affinity(port_data, mask, force);
+
+	irq_data_update_effective_affinity(data, mask);
+
+	return ret;
+}
+
+static int mtk_pcie_set_affinity(struct irq_data *data,
+				 const struct cpumask *mask, bool force)
+{
+	return -EINVAL;
+}
+
+static void mtk_pcie_msi_irq_mask(struct irq_data *data)
+{
+	pci_msi_mask_irq(data);
+	irq_chip_mask_parent(data);
+}
+
+static void mtk_pcie_msi_irq_unmask(struct irq_data *data)
+{
+	pci_msi_unmask_irq(data);
+	irq_chip_unmask_parent(data);
+}
+
+static struct irq_chip mtk_msi_irq_chip = {
+	.irq_ack = irq_chip_ack_parent,
+	.irq_mask = mtk_pcie_msi_irq_mask,
+	.irq_unmask = mtk_pcie_msi_irq_unmask,
+	.name = "MSI",
+};
+
+static struct msi_domain_info mtk_msi_domain_info = {
+	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+		   MSI_FLAG_PCI_MSIX | MSI_FLAG_MULTI_PCI_MSI),
+	.chip	= &mtk_msi_irq_chip,
+};
+
+static void mtk_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+	struct mtk_msi_set *msi_set = irq_data_get_irq_chip_data(data);
+	struct mtk_pcie_port *port = data->domain->host_data;
+	unsigned long hwirq;
+
+	hwirq =	data->hwirq % PCIE_MSI_IRQS_PER_SET;
+
+	msg->address_hi = upper_32_bits(msi_set->msg_addr);
+	msg->address_lo = lower_32_bits(msi_set->msg_addr);
+	msg->data = hwirq;
+	dev_dbg(port->dev, "msi#%#lx address_hi %#x address_lo %#x data %d\n",
+		hwirq, msg->address_hi, msg->address_lo, msg->data);
+}
+
+static void mtk_msi_bottom_irq_ack(struct irq_data *data)
+{
+	struct mtk_msi_set *msi_set = irq_data_get_irq_chip_data(data);
+	unsigned long hwirq;
+
+	hwirq =	data->hwirq % PCIE_MSI_IRQS_PER_SET;
+
+	writel_relaxed(BIT(hwirq), msi_set->base + PCIE_MSI_SET_STATUS_OFFSET);
+}
+
+static void mtk_msi_bottom_irq_mask(struct irq_data *data)
+{
+	struct mtk_msi_set *msi_set = irq_data_get_irq_chip_data(data);
+	struct mtk_pcie_port *port = data->domain->host_data;
+	unsigned long hwirq, flags;
+	u32 val;
+
+	hwirq =	data->hwirq % PCIE_MSI_IRQS_PER_SET;
+
+	raw_spin_lock_irqsave(&port->irq_lock, flags);
+	if (port->direct_msi_enable) {
+		val = readl_relaxed(msi_set->base +
+					PCIE_MSI_SET_GRP1_ENABLE_OFFSET);
+		val &= ~BIT(hwirq);
+		writel_relaxed(val, msi_set->base +
+					PCIE_MSI_SET_GRP1_ENABLE_OFFSET);
+	} else {
+		val = readl_relaxed(msi_set->base + PCIE_MSI_SET_ENABLE_OFFSET);
+		val &= ~BIT(hwirq);
+		writel_relaxed(val, msi_set->base + PCIE_MSI_SET_ENABLE_OFFSET);
+	}
+	raw_spin_unlock_irqrestore(&port->irq_lock, flags);
+}
+
+static void mtk_msi_bottom_irq_unmask(struct irq_data *data)
+{
+	struct mtk_msi_set *msi_set = irq_data_get_irq_chip_data(data);
+	struct mtk_pcie_port *port = data->domain->host_data;
+	unsigned long hwirq, flags;
+	u32 val;
+
+	hwirq =	data->hwirq % PCIE_MSI_IRQS_PER_SET;
+
+	raw_spin_lock_irqsave(&port->irq_lock, flags);
+	if (port->direct_msi_enable) {
+		val = readl_relaxed(msi_set->base +
+					PCIE_MSI_SET_GRP1_ENABLE_OFFSET);
+		val |= BIT(hwirq);
+		writel_relaxed(val, msi_set->base +
+					PCIE_MSI_SET_GRP1_ENABLE_OFFSET);
+	} else {
+		val = readl_relaxed(msi_set->base + PCIE_MSI_SET_ENABLE_OFFSET);
+		val |= BIT(hwirq);
+		writel_relaxed(val, msi_set->base + PCIE_MSI_SET_ENABLE_OFFSET);
+	}
+	raw_spin_unlock_irqrestore(&port->irq_lock, flags);
+}
+
+static struct irq_chip mtk_msi_bottom_irq_chip = {
+	.irq_ack		= mtk_msi_bottom_irq_ack,
+	.irq_mask		= mtk_msi_bottom_irq_mask,
+	.irq_unmask		= mtk_msi_bottom_irq_unmask,
+	.irq_compose_msi_msg	= mtk_compose_msi_msg,
+	.irq_set_affinity	= mtk_pcie_set_affinity,
+	.name			= "MSI",
+};
+
+static int mtk_msi_bottom_domain_alloc(struct irq_domain *domain,
+				       unsigned int virq, unsigned int nr_irqs,
+				       void *arg)
+{
+	struct mtk_pcie_port *port = domain->host_data;
+	struct mtk_msi_set *msi_set;
+	int i, hwirq, set_idx;
+
+	mutex_lock(&port->lock);
+
+	hwirq = bitmap_find_free_region(port->msi_irq_in_use, PCIE_MSI_IRQS_NUM,
+					order_base_2(nr_irqs));
+
+	mutex_unlock(&port->lock);
+
+	if (hwirq < 0)
+		return -ENOSPC;
+
+	set_idx = hwirq / PCIE_MSI_IRQS_PER_SET;
+	msi_set = &port->msi_sets[set_idx];
+
+	for (i = 0; i < nr_irqs; i++)
+		irq_domain_set_info(domain, virq + i, hwirq + i,
+				    &mtk_msi_bottom_irq_chip, msi_set,
+				    handle_edge_irq, NULL, NULL);
+
+	return 0;
+}
+
+static void mtk_msi_bottom_domain_free(struct irq_domain *domain,
+				       unsigned int virq, unsigned int nr_irqs)
+{
+	struct mtk_pcie_port *port = domain->host_data;
+	struct irq_data *data = irq_domain_get_irq_data(domain, virq);
+
+	mutex_lock(&port->lock);
+
+	bitmap_release_region(port->msi_irq_in_use, data->hwirq,
+			      order_base_2(nr_irqs));
+
+	mutex_unlock(&port->lock);
+
+	irq_domain_free_irqs_common(domain, virq, nr_irqs);
+}
+
+static const struct irq_domain_ops mtk_msi_bottom_domain_ops = {
+	.alloc = mtk_msi_bottom_domain_alloc,
+	.free = mtk_msi_bottom_domain_free,
+};
+
+static void mtk_intx_mask(struct irq_data *data)
+{
+	struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data);
+	unsigned long flags;
+	u32 val;
+
+	raw_spin_lock_irqsave(&port->irq_lock, flags);
+	val = readl_relaxed(port->base + PCIE_INT_ENABLE_REG);
+	val &= ~BIT(data->hwirq + PCIE_INTX_SHIFT);
+	writel_relaxed(val, port->base + PCIE_INT_ENABLE_REG);
+	raw_spin_unlock_irqrestore(&port->irq_lock, flags);
+}
+
+static void mtk_intx_unmask(struct irq_data *data)
+{
+	struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data);
+	unsigned long flags;
+	u32 val;
+
+	raw_spin_lock_irqsave(&port->irq_lock, flags);
+	val = readl_relaxed(port->base + PCIE_INT_ENABLE_REG);
+	val |= BIT(data->hwirq + PCIE_INTX_SHIFT);
+	writel_relaxed(val, port->base + PCIE_INT_ENABLE_REG);
+	raw_spin_unlock_irqrestore(&port->irq_lock, flags);
+}
+
+/**
+ * mtk_intx_eoi() - Clear INTx IRQ status at the end of interrupt
+ * @data: pointer to chip specific data
+ *
+ * As an emulated level IRQ, its interrupt status will remain
+ * until the corresponding de-assert message is received; hence that
+ * the status can only be cleared when the interrupt has been serviced.
+ */
+static void mtk_intx_eoi(struct irq_data *data)
+{
+	struct mtk_pcie_port *port = irq_data_get_irq_chip_data(data);
+	unsigned long hwirq;
+
+	hwirq = data->hwirq + PCIE_INTX_SHIFT;
+	writel_relaxed(BIT(hwirq), port->base + PCIE_INT_STATUS_REG);
+}
+
+static struct irq_chip mtk_intx_irq_chip = {
+	.irq_mask		= mtk_intx_mask,
+	.irq_unmask		= mtk_intx_unmask,
+	.irq_eoi		= mtk_intx_eoi,
+	.irq_set_affinity	= mtk_pcie_set_affinity,
+	.name			= "INTx",
+};
+
+static int mtk_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
+			     irq_hw_number_t hwirq)
+{
+	irq_set_chip_data(irq, domain->host_data);
+	irq_set_chip_and_handler_name(irq, &mtk_intx_irq_chip,
+				      handle_fasteoi_irq, "INTx");
+	return 0;
+}
+
+static const struct irq_domain_ops intx_domain_ops = {
+	.map = mtk_pcie_intx_map,
+};
+
+static int mtk_pcie_init_irq_domains(struct mtk_pcie_port *port)
+{
+	struct device *dev = port->dev;
+	struct device_node *intc_node, *node = dev->of_node;
+	int ret;
+
+	raw_spin_lock_init(&port->irq_lock);
+
+	/* Setup INTx */
+	intc_node = of_get_child_by_name(node, "interrupt-controller");
+	if (!intc_node) {
+		dev_err(dev, "missing interrupt-controller node\n");
+		return -ENODEV;
+	}
+
+	port->intx_domain = irq_domain_add_linear(intc_node, PCI_NUM_INTX,
+						  &intx_domain_ops, port);
+	if (!port->intx_domain) {
+		dev_err(dev, "failed to create INTx IRQ domain\n");
+		return -ENODEV;
+	}
+
+	/* Setup MSI */
+	mutex_init(&port->lock);
+
+	port->msi_bottom_domain = irq_domain_add_linear(node, PCIE_MSI_IRQS_NUM,
+				  &mtk_msi_bottom_domain_ops, port);
+	if (!port->msi_bottom_domain) {
+		dev_err(dev, "failed to create MSI bottom domain\n");
+		ret = -ENODEV;
+		goto err_msi_bottom_domain;
+	}
+
+	port->msi_domain = pci_msi_create_irq_domain(dev->fwnode,
+						     &mtk_msi_domain_info,
+						     port->msi_bottom_domain);
+	if (!port->msi_domain) {
+		dev_err(dev, "failed to create MSI domain\n");
+		ret = -ENODEV;
+		goto err_msi_domain;
+	}
+
+	if (of_find_property(node, "direct_msi", NULL))
+		port->direct_msi_enable = true;
+	else
+		port->direct_msi_enable = false;
+
+	return 0;
+
+err_msi_domain:
+	irq_domain_remove(port->msi_bottom_domain);
+err_msi_bottom_domain:
+	irq_domain_remove(port->intx_domain);
+
+	return ret;
+}
+
+static void mtk_pcie_irq_teardown(struct mtk_pcie_port *port)
+{
+	irq_set_chained_handler_and_data(port->irq, NULL, NULL);
+
+	if (port->intx_domain)
+		irq_domain_remove(port->intx_domain);
+
+	if (port->msi_domain)
+		irq_domain_remove(port->msi_domain);
+
+	if (port->msi_bottom_domain)
+		irq_domain_remove(port->msi_bottom_domain);
+
+	irq_dispose_mapping(port->irq);
+}
+
+static void mtk_pcie_msi_handler(struct mtk_pcie_port *port, int set_idx)
+{
+	struct mtk_msi_set *msi_set = &port->msi_sets[set_idx];
+	unsigned long msi_enable, msi_status;
+	unsigned int virq;
+	irq_hw_number_t bit, hwirq;
+
+	msi_enable = readl_relaxed(msi_set->base + PCIE_MSI_SET_ENABLE_OFFSET);
+
+	do {
+		msi_status = readl_relaxed(msi_set->base +
+					   PCIE_MSI_SET_STATUS_OFFSET);
+		msi_status &= msi_enable;
+		if (!msi_status)
+			break;
+
+		for_each_set_bit(bit, &msi_status, PCIE_MSI_IRQS_PER_SET) {
+			hwirq = bit + set_idx * PCIE_MSI_IRQS_PER_SET;
+			virq = irq_find_mapping(port->msi_bottom_domain, hwirq);
+			generic_handle_irq(virq);
+		}
+	} while (true);
+}
+
+static void mtk_pcie_irq_handler(struct irq_desc *desc)
+{
+	struct mtk_pcie_port *port = irq_desc_get_handler_data(desc);
+	struct irq_chip *irqchip = irq_desc_get_chip(desc);
+	unsigned long status;
+	unsigned int virq;
+	irq_hw_number_t irq_bit = PCIE_INTX_SHIFT;
+
+	chained_irq_enter(irqchip, desc);
+
+	status = readl_relaxed(port->base + PCIE_INT_STATUS_REG);
+	for_each_set_bit_from(irq_bit, &status, PCI_NUM_INTX +
+			      PCIE_INTX_SHIFT) {
+		virq = irq_find_mapping(port->intx_domain,
+					irq_bit - PCIE_INTX_SHIFT);
+		generic_handle_irq(virq);
+	}
+
+	irq_bit = PCIE_MSI_SHIFT;
+	for_each_set_bit_from(irq_bit, &status, PCIE_MSI_SET_NUM +
+			      PCIE_MSI_SHIFT) {
+		mtk_pcie_msi_handler(port, irq_bit - PCIE_MSI_SHIFT);
+
+		writel_relaxed(BIT(irq_bit), port->base + PCIE_INT_STATUS_REG);
+	}
+
+	chained_irq_exit(irqchip, desc);
+}
+
+static void mtk_pcie_direct_msi_handler(struct irq_desc *desc)
+{
+	struct mtk_pcie_port *port = irq_desc_get_handler_data(desc);
+	struct irq_chip *irqchip = irq_desc_get_chip(desc);
+	unsigned long msi_enable, msi_status;
+	unsigned int virq;
+	irq_hw_number_t hwirq;
+	int i, msi_bit = -EINVAL;
+
+	for (i = 0; i < PCIE_MSI_IRQS_PER_SET; i++) {
+		if (port->direct_msi[i] == irq_desc_get_irq(desc)) {
+			msi_bit = i;
+			break;
+		}
+	}
+
+	if (msi_bit == -EINVAL)
+		return;
+
+	chained_irq_enter(irqchip, desc);
+
+	for (i = 0; i < PCIE_MSI_SET_NUM; i++) {
+		struct mtk_msi_set *msi_set = &port->msi_sets[i];
+
+		msi_status = readl_relaxed(msi_set->base +
+					   PCIE_MSI_SET_STATUS_OFFSET);
+		msi_enable = readl_relaxed(msi_set->base +
+					   PCIE_MSI_SET_GRP1_ENABLE_OFFSET);
+		msi_status &= msi_enable;
+		msi_status &= BIT(msi_bit);
+		if (!msi_status)
+			continue;
+
+		hwirq = msi_bit + i * PCIE_MSI_IRQS_PER_SET;
+		virq = irq_find_mapping(port->msi_bottom_domain, hwirq);
+		generic_handle_irq(virq);
+	}
+
+	chained_irq_exit(irqchip, desc);
+}
+
+static int mtk_pcie_setup_irq(struct mtk_pcie_port *port)
+{
+	struct device *dev = port->dev;
+	struct platform_device *pdev = to_platform_device(dev);
+	int err, i;
+
+	err = mtk_pcie_init_irq_domains(port);
+	if (err)
+		return err;
+
+	port->irq = platform_get_irq(pdev, 0);
+	if (port->irq < 0)
+		return port->irq;
+
+	irq_set_chained_handler_and_data(port->irq, mtk_pcie_irq_handler, port);
+
+	if (port->direct_msi_enable) {
+		mtk_msi_bottom_irq_chip.irq_set_affinity =
+						      mtk_pcie_set_msi_affinity;
+
+		for (i = 0; i < PCIE_MSI_IRQS_PER_SET; i++) {
+			port->direct_msi[i] = platform_get_irq(pdev, i + 1);
+			irq_set_chained_handler_and_data(port->direct_msi[i],
+					    mtk_pcie_direct_msi_handler, port);
+		}
+	}
+
+	return 0;
+}
+
+static int mtk_pcie_parse_port(struct mtk_pcie_port *port)
+{
+	struct device *dev = port->dev;
+	struct pci_host_bridge *host = pci_host_bridge_from_priv(port);
+	struct platform_device *pdev = to_platform_device(dev);
+	struct list_head *windows = &host->windows;
+	struct resource *regs, *bus;
+	int ret;
+
+	ret = pci_parse_request_of_pci_ranges(dev, windows, &bus);
+	if (ret) {
+		dev_err(dev, "failed to parse pci ranges\n");
+		return ret;
+	}
+
+	regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcie-mac");
+	port->base = devm_ioremap_resource(dev, regs);
+	if (IS_ERR(port->base)) {
+		dev_err(dev, "failed to map register base\n");
+		return PTR_ERR(port->base);
+	}
+
+	port->reg_base = regs->start;
+
+	port->phy_reset = devm_reset_control_get_optional_exclusive(dev, "phy");
+	if (IS_ERR(port->phy_reset)) {
+		ret = PTR_ERR(port->phy_reset);
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "failed to get PHY reset\n");
+
+		return ret;
+	}
+
+	port->mac_reset = devm_reset_control_get_optional_exclusive(dev, "mac");
+	if (IS_ERR(port->mac_reset)) {
+		ret = PTR_ERR(port->mac_reset);
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "failed to get MAC reset\n");
+
+		return ret;
+	}
+
+	port->phy = devm_phy_optional_get(dev, "pcie-phy");
+	if (IS_ERR(port->phy)) {
+		ret = PTR_ERR(port->phy);
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "failed to get PHY\n");
+
+		return ret;
+	}
+
+	port->num_clks = devm_clk_bulk_get_all(dev, &port->clks);
+	if (port->num_clks < 0) {
+		dev_err(dev, "failed to get clocks\n");
+		return port->num_clks;
+	}
+
+	return 0;
+}
+
+static int mtk_pcie_power_up(struct mtk_pcie_port *port)
+{
+	struct device *dev = port->dev;
+	int err;
+
+	/* PHY power on and enable pipe clock */
+	reset_control_deassert(port->phy_reset);
+
+	err = phy_init(port->phy);
+	if (err) {
+		dev_err(dev, "failed to initialize PHY\n");
+		goto err_phy_init;
+	}
+
+	err = phy_power_on(port->phy);
+	if (err) {
+		dev_err(dev, "failed to power on PHY\n");
+		goto err_phy_on;
+	}
+
+	/* MAC power on and enable transaction layer clocks */
+	reset_control_deassert(port->mac_reset);
+
+	pm_runtime_enable(dev);
+	pm_runtime_get_sync(dev);
+
+	err = clk_bulk_prepare_enable(port->num_clks, port->clks);
+	if (err) {
+		dev_err(dev, "failed to enable clocks\n");
+		goto err_clk_init;
+	}
+
+	return 0;
+
+err_clk_init:
+	pm_runtime_put_sync(dev);
+	pm_runtime_disable(dev);
+	reset_control_assert(port->mac_reset);
+	phy_power_off(port->phy);
+err_phy_on:
+	phy_exit(port->phy);
+err_phy_init:
+	reset_control_assert(port->phy_reset);
+
+	return err;
+}
+
+static void mtk_pcie_power_down(struct mtk_pcie_port *port)
+{
+	clk_bulk_disable_unprepare(port->num_clks, port->clks);
+
+	pm_runtime_put_sync(port->dev);
+	pm_runtime_disable(port->dev);
+	reset_control_assert(port->mac_reset);
+
+	phy_power_off(port->phy);
+	phy_exit(port->phy);
+	reset_control_assert(port->phy_reset);
+}
+
+static int mtk_pcie_setup(struct mtk_pcie_port *port)
+{
+	int err;
+
+	err = mtk_pcie_parse_port(port);
+	if (err)
+		return err;
+
+	/* Don't touch the hardware registers before power up */
+	err = mtk_pcie_power_up(port);
+	if (err)
+		return err;
+
+	/* Try link up */
+	err = mtk_pcie_startup_port(port);
+	if (err)
+		goto err_setup;
+
+	err = mtk_pcie_setup_irq(port);
+	if (err)
+		goto err_setup;
+
+	return 0;
+
+err_setup:
+	mtk_pcie_power_down(port);
+
+	return err;
+}
+
+static int mtk_pcie_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mtk_pcie_port *port;
+	struct pci_host_bridge *host;
+	int err;
+
+	host = devm_pci_alloc_host_bridge(dev, sizeof(*port));
+	if (!host)
+		return -ENOMEM;
+
+	port = pci_host_bridge_priv(host);
+
+	port->dev = dev;
+	platform_set_drvdata(pdev, port);
+
+	err = mtk_pcie_setup(port);
+	if (err)
+		return err;
+
+	host->dev.parent = port->dev;
+	host->ops = &mtk_pcie_ops;
+	host->map_irq = of_irq_parse_and_map_pci;
+	host->swizzle_irq = pci_common_swizzle;
+	host->sysdata = port;
+
+	err = pci_host_probe(host);
+	if (err) {
+		mtk_pcie_irq_teardown(port);
+		mtk_pcie_power_down(port);
+		return err;
+	}
+
+	return 0;
+}
+
+static int mtk_pcie_remove(struct platform_device *pdev)
+{
+	struct mtk_pcie_port *port = platform_get_drvdata(pdev);
+	struct pci_host_bridge *host = pci_host_bridge_from_priv(port);
+
+	pci_lock_rescan_remove();
+	pci_stop_root_bus(host->bus);
+	pci_remove_root_bus(host->bus);
+	pci_unlock_rescan_remove();
+
+	mtk_pcie_irq_teardown(port);
+	mtk_pcie_power_down(port);
+
+	return 0;
+}
+
+static void __maybe_unused mtk_pcie_irq_save(struct mtk_pcie_port *port)
+{
+	int i;
+
+	raw_spin_lock(&port->irq_lock);
+
+	port->saved_irq_state = readl_relaxed(port->base + PCIE_INT_ENABLE_REG);
+
+	for (i = 0; i < PCIE_MSI_SET_NUM; i++) {
+		struct mtk_msi_set *msi_set = &port->msi_sets[i];
+
+		if (port->direct_msi_enable)
+			msi_set->saved_irq_state = readl_relaxed(msi_set->base +
+					PCIE_MSI_SET_GRP1_ENABLE_OFFSET);
+		else
+			msi_set->saved_irq_state = readl_relaxed(msi_set->base +
+					PCIE_MSI_SET_ENABLE_OFFSET);
+	}
+
+	raw_spin_unlock(&port->irq_lock);
+}
+
+static void __maybe_unused mtk_pcie_irq_restore(struct mtk_pcie_port *port)
+{
+	int i;
+
+	raw_spin_lock(&port->irq_lock);
+
+	writel_relaxed(port->saved_irq_state, port->base + PCIE_INT_ENABLE_REG);
+
+	for (i = 0; i < PCIE_MSI_SET_NUM; i++) {
+		struct mtk_msi_set *msi_set = &port->msi_sets[i];
+
+		if (port->direct_msi_enable)
+			writel_relaxed(msi_set->saved_irq_state, msi_set->base +
+					PCIE_MSI_SET_GRP1_ENABLE_OFFSET);
+		else
+			writel_relaxed(msi_set->saved_irq_state, msi_set->base +
+					PCIE_MSI_SET_ENABLE_OFFSET);
+	}
+
+	raw_spin_unlock(&port->irq_lock);
+}
+
+static int __maybe_unused mtk_pcie_turn_off_link(struct mtk_pcie_port *port)
+{
+	u32 val;
+
+	val = readl_relaxed(port->base + PCIE_ICMD_PM_REG);
+	val |= PCIE_TURN_OFF_LINK;
+	writel_relaxed(val, port->base + PCIE_ICMD_PM_REG);
+
+	/* Check the link is L2 */
+	return readl_poll_timeout(port->base + PCIE_LTSSM_STATUS_REG, val,
+				  (PCIE_LTSSM_STATE(val) ==
+				   PCIE_LTSSM_STATE_L2_IDLE), 20,
+				   50 * USEC_PER_MSEC);
+}
+
+static int __maybe_unused mtk_pcie_suspend_noirq(struct device *dev)
+{
+	struct mtk_pcie_port *port = dev_get_drvdata(dev);
+	int err;
+	u32 val;
+
+	/* Trigger link to L2 state */
+	err = mtk_pcie_turn_off_link(port);
+	if (err) {
+		dev_err(port->dev, "cannot enter L2 state\n");
+		return err;
+	}
+
+	/* Pull down the PERST# pin */
+	val = readl_relaxed(port->base + PCIE_RST_CTRL_REG);
+	val |= PCIE_PE_RSTB;
+	writel_relaxed(val, port->base + PCIE_RST_CTRL_REG);
+
+	dev_dbg(port->dev, "entered L2 states successfully");
+
+	mtk_pcie_irq_save(port);
+	mtk_pcie_power_down(port);
+
+	return 0;
+}
+
+static int __maybe_unused mtk_pcie_resume_noirq(struct device *dev)
+{
+	struct mtk_pcie_port *port = dev_get_drvdata(dev);
+	int err;
+
+	err = mtk_pcie_power_up(port);
+	if (err)
+		return err;
+
+	err = mtk_pcie_startup_port(port);
+	if (err) {
+		mtk_pcie_power_down(port);
+		return err;
+	}
+
+	mtk_pcie_irq_restore(port);
+
+	return 0;
+}
+
+static const struct dev_pm_ops mtk_pcie_pm_ops = {
+	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_pcie_suspend_noirq,
+				      mtk_pcie_resume_noirq)
+};
+
+static const struct of_device_id mtk_pcie_of_match[] = {
+	{ .compatible = "mediatek,mt8192-pcie" },
+	{ .compatible = "mediatek,mt7986-pcie" },
+	{},
+};
+
+static struct platform_driver mtk_pcie_driver = {
+	.probe = mtk_pcie_probe,
+	.remove = mtk_pcie_remove,
+	.driver = {
+		.name = "mtk-pcie",
+		.of_match_table = mtk_pcie_of_match,
+		.pm = &mtk_pcie_pm_ops,
+	},
+};
+
+module_platform_driver(mtk_pcie_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7981.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7981.c
new file mode 100644
index 0000000..279ca6e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7981.c
@@ -0,0 +1,995 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The MT7986 driver based on Linux generic pinctrl binding.
+ *
+ * Copyright (C) 2020 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+#include "pinctrl-moore.h"
+
+#define MT7986_PIN(_number, _name)				\
+	MTK_PIN(_number, _name, 0, _number, DRV_GRP1)
+
+#define PIN_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, _x_bits)	\
+	PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit,	\
+		       _x_bits, 32, 0)
+
+#define PINS_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, _x_bits)	\
+	PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit,	\
+		      _x_bits, 32, 1)
+
+static const struct mtk_pin_field_calc mt7981_pin_mode_range[] = {
+	PIN_FIELD(0, 56, 0x300, 0x10, 0, 4),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_dir_range[] = {
+	PIN_FIELD(0, 56, 0x0, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_di_range[] = {
+	PIN_FIELD(0, 56, 0x200, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_do_range[] = {
+	PIN_FIELD(0, 56, 0x100, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_ies_range[] = {
+	PIN_FIELD_BASE(0, 0, 1, 0x10, 0x10, 1, 1),
+	PIN_FIELD_BASE(1, 1, 1, 0x10, 0x10, 0, 1),
+	PIN_FIELD_BASE(2, 2, 5, 0x20, 0x10, 6, 1),
+	PIN_FIELD_BASE(3, 3, 4, 0x20, 0x10, 6, 1),
+	PIN_FIELD_BASE(4, 4, 4, 0x20, 0x10, 2, 1),
+	PIN_FIELD_BASE(5, 5, 4, 0x20, 0x10, 1, 1),
+	PIN_FIELD_BASE(6, 6, 4, 0x20, 0x10, 3, 1),
+	PIN_FIELD_BASE(7, 7, 4, 0x20, 0x10, 0, 1),
+	PIN_FIELD_BASE(8, 8, 4, 0x20, 0x10, 4, 1),
+	PIN_FIELD_BASE(9, 9, 4, 0x20, 0x10, 9, 1),
+
+	PIN_FIELD_BASE(10, 10, 5, 0x20, 0x10, 8, 1),
+	PIN_FIELD_BASE(11, 11, 5, 0x40, 0x10, 10, 1),
+	PIN_FIELD_BASE(12, 12, 5, 0x20, 0x10, 7, 1),
+	PIN_FIELD_BASE(13, 13, 5, 0x20, 0x10, 11, 1),
+
+	PIN_FIELD_BASE(14, 14, 4, 0x20, 0x10, 8, 1),
+
+	PIN_FIELD_BASE(15, 15, 2, 0x20, 0x10, 0, 1),
+	PIN_FIELD_BASE(16, 16, 2, 0x20, 0x10, 1, 1),
+	PIN_FIELD_BASE(17, 17, 2, 0x20, 0x10, 5, 1),
+	PIN_FIELD_BASE(18, 18, 2, 0x20, 0x10, 4, 1),
+	PIN_FIELD_BASE(19, 19, 2, 0x20, 0x10, 2, 1),
+	PIN_FIELD_BASE(20, 20, 2, 0x20, 0x10, 3, 1),
+	PIN_FIELD_BASE(21, 21, 2, 0x20, 0x10, 6, 1),
+	PIN_FIELD_BASE(22, 22, 2, 0x20, 0x10, 7, 1),
+	PIN_FIELD_BASE(23, 23, 2, 0x20, 0x10, 10, 1),
+	PIN_FIELD_BASE(24, 24, 2, 0x20, 0x10, 9, 1),
+	PIN_FIELD_BASE(25, 25, 2, 0x20, 0x10, 8, 1),
+
+	PIN_FIELD_BASE(26, 26, 5, 0x20, 0x10, 0, 1),
+	PIN_FIELD_BASE(27, 27, 5, 0x20, 0x10, 4, 1),
+	PIN_FIELD_BASE(28, 28, 5, 0x20, 0x10, 3, 1),
+	PIN_FIELD_BASE(29, 29, 5, 0x20, 0x10, 1, 1),
+	PIN_FIELD_BASE(30, 30, 5, 0x20, 0x10, 2, 1),
+	PIN_FIELD_BASE(31, 31, 5, 0x20, 0x10, 5, 1),
+
+	PIN_FIELD_BASE(32, 32, 1, 0x10, 0x10, 2, 1),
+	PIN_FIELD_BASE(33, 33, 1, 0x10, 0x10, 3, 1),
+
+	PIN_FIELD_BASE(34, 34, 4, 0x20, 0x10, 5, 1),
+	PIN_FIELD_BASE(35, 35, 4, 0x20, 0x10, 7, 1),
+
+	PIN_FIELD_BASE(36, 36, 3, 0x10, 0x10, 2, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0x10, 0x10, 3, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x10, 0x10, 0, 1),
+	PIN_FIELD_BASE(39, 39, 3, 0x10, 0x10, 1, 1),
+
+	PIN_FIELD_BASE(40, 40, 7, 0x30, 0x10, 1, 1),
+	PIN_FIELD_BASE(41, 41, 7, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(42, 42, 7, 0x30, 0x10, 9, 1),
+	PIN_FIELD_BASE(43, 43, 7, 0x30, 0x10, 7, 1),
+	PIN_FIELD_BASE(44, 44, 7, 0x30, 0x10, 8, 1),
+	PIN_FIELD_BASE(45, 45, 7, 0x30, 0x10, 3, 1),
+	PIN_FIELD_BASE(46, 46, 7, 0x30, 0x10, 4, 1),
+	PIN_FIELD_BASE(47, 47, 7, 0x30, 0x10, 5, 1),
+	PIN_FIELD_BASE(48, 48, 7, 0x30, 0x10, 6, 1),
+	PIN_FIELD_BASE(49, 49, 7, 0x30, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(50, 50, 6, 0x10, 0x10, 0, 1),
+	PIN_FIELD_BASE(51, 51, 6, 0x10, 0x10, 2, 1),
+	PIN_FIELD_BASE(52, 52, 6, 0x10, 0x10, 3, 1),
+	PIN_FIELD_BASE(53, 53, 6, 0x10, 0x10, 4, 1),
+	PIN_FIELD_BASE(54, 54, 6, 0x10, 0x10, 5, 1),
+	PIN_FIELD_BASE(55, 55, 6, 0x10, 0x10, 6, 1),
+	PIN_FIELD_BASE(56, 56, 6, 0x10, 0x10, 1, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_smt_range[] = {
+	PIN_FIELD_BASE(0, 0, 1, 0x60, 0x10, 1, 1),
+	PIN_FIELD_BASE(1, 1, 1, 0x60, 0x10, 0, 1),
+	PIN_FIELD_BASE(2, 2, 5, 0x90, 0x10, 6, 1),
+	PIN_FIELD_BASE(3, 3, 4, 0x80, 0x10, 6, 1),
+	PIN_FIELD_BASE(4, 4, 4, 0x80, 0x10, 2, 1),
+	PIN_FIELD_BASE(5, 5, 4, 0x80, 0x10, 1, 1),
+	PIN_FIELD_BASE(6, 6, 4, 0x80, 0x10, 3, 1),
+	PIN_FIELD_BASE(7, 7, 4, 0x80, 0x10, 0, 1),
+	PIN_FIELD_BASE(8, 8, 4, 0x80, 0x10, 4, 1),
+	PIN_FIELD_BASE(9, 9, 4, 0x80, 0x10, 9, 1),
+
+	PIN_FIELD_BASE(10, 10, 5, 0x90, 0x10, 8, 1),
+	PIN_FIELD_BASE(11, 11, 5, 0x90, 0x10, 10, 1),
+	PIN_FIELD_BASE(12, 12, 5, 0x90, 0x10, 7, 1),
+	PIN_FIELD_BASE(13, 13, 5, 0x90, 0x10, 11, 1),
+
+	PIN_FIELD_BASE(14, 14, 4, 0x80, 0x10, 8, 1),
+
+	PIN_FIELD_BASE(15, 15, 2, 0x90, 0x10, 0, 1),
+	PIN_FIELD_BASE(16, 16, 2, 0x90, 0x10, 1, 1),
+	PIN_FIELD_BASE(17, 17, 2, 0x90, 0x10, 5, 1),
+	PIN_FIELD_BASE(18, 18, 2, 0x90, 0x10, 4, 1),
+	PIN_FIELD_BASE(19, 19, 2, 0x90, 0x10, 2, 1),
+	PIN_FIELD_BASE(20, 20, 2, 0x90, 0x10, 3, 1),
+	PIN_FIELD_BASE(21, 21, 2, 0x90, 0x10, 6, 1),
+	PIN_FIELD_BASE(22, 22, 2, 0x90, 0x10, 7, 1),
+	PIN_FIELD_BASE(23, 23, 2, 0x90, 0x10, 10, 1),
+	PIN_FIELD_BASE(24, 24, 2, 0x90, 0x10, 9, 1),
+	PIN_FIELD_BASE(25, 25, 2, 0x90, 0x10, 8, 1),
+
+	PIN_FIELD_BASE(26, 26, 5, 0x90, 0x10, 0, 1),
+	PIN_FIELD_BASE(27, 27, 5, 0x90, 0x10, 4, 1),
+	PIN_FIELD_BASE(28, 28, 5, 0x90, 0x10, 3, 1),
+	PIN_FIELD_BASE(29, 29, 5, 0x90, 0x10, 1, 1),
+	PIN_FIELD_BASE(30, 30, 5, 0x90, 0x10, 2, 1),
+	PIN_FIELD_BASE(31, 31, 5, 0x90, 0x10, 5, 1),
+
+	PIN_FIELD_BASE(32, 32, 1, 0x60, 0x10, 2, 1),
+	PIN_FIELD_BASE(33, 33, 1, 0x60, 0x10, 3, 1),
+
+	PIN_FIELD_BASE(34, 34, 4, 0x80, 0x10, 5, 1),
+	PIN_FIELD_BASE(35, 35, 4, 0x80, 0x10, 7, 1),
+
+	PIN_FIELD_BASE(36, 36, 3, 0x60, 0x10, 2, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0x60, 0x10, 3, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x60, 0x10, 0, 1),
+	PIN_FIELD_BASE(39, 39, 3, 0x60, 0x10, 1, 1),
+
+	PIN_FIELD_BASE(40, 40, 7, 0x70, 0x10, 1, 1),
+	PIN_FIELD_BASE(41, 41, 7, 0x70, 0x10, 0, 1),
+	PIN_FIELD_BASE(42, 42, 7, 0x70, 0x10, 9, 1),
+	PIN_FIELD_BASE(43, 43, 7, 0x70, 0x10, 7, 1),
+	PIN_FIELD_BASE(44, 44, 7, 0x30, 0x10, 8, 1),
+	PIN_FIELD_BASE(45, 45, 7, 0x70, 0x10, 3, 1),
+	PIN_FIELD_BASE(46, 46, 7, 0x70, 0x10, 4, 1),
+	PIN_FIELD_BASE(47, 47, 7, 0x70, 0x10, 5, 1),
+	PIN_FIELD_BASE(48, 48, 7, 0x70, 0x10, 6, 1),
+	PIN_FIELD_BASE(49, 49, 7, 0x70, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(50, 50, 6, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(51, 51, 6, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(52, 52, 6, 0x50, 0x10, 3, 1),
+	PIN_FIELD_BASE(53, 53, 6, 0x50, 0x10, 4, 1),
+	PIN_FIELD_BASE(54, 54, 6, 0x50, 0x10, 5, 1),
+	PIN_FIELD_BASE(55, 55, 6, 0x50, 0x10, 6, 1),
+	PIN_FIELD_BASE(56, 56, 6, 0x50, 0x10, 1, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_pu_range[] = {
+	PIN_FIELD_BASE(40, 40, 7, 0x50, 0x10, 1, 1),
+	PIN_FIELD_BASE(41, 41, 7, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(42, 42, 7, 0x50, 0x10, 9, 1),
+	PIN_FIELD_BASE(43, 43, 7, 0x50, 0x10, 7, 1),
+	PIN_FIELD_BASE(44, 44, 7, 0x50, 0x10, 8, 1),
+	PIN_FIELD_BASE(45, 45, 7, 0x50, 0x10, 3, 1),
+	PIN_FIELD_BASE(46, 46, 7, 0x50, 0x10, 4, 1),
+	PIN_FIELD_BASE(47, 47, 7, 0x50, 0x10, 5, 1),
+	PIN_FIELD_BASE(48, 48, 7, 0x50, 0x10, 6, 1),
+	PIN_FIELD_BASE(49, 49, 7, 0x50, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(50, 50, 6, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(51, 51, 6, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(52, 52, 6, 0x30, 0x10, 3, 1),
+	PIN_FIELD_BASE(53, 53, 6, 0x30, 0x10, 4, 1),
+	PIN_FIELD_BASE(54, 54, 6, 0x30, 0x10, 5, 1),
+	PIN_FIELD_BASE(55, 55, 6, 0x30, 0x10, 6, 1),
+	PIN_FIELD_BASE(56, 56, 6, 0x30, 0x10, 1, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_pd_range[] = {
+	PIN_FIELD_BASE(40, 40, 7, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(41, 41, 7, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(42, 42, 7, 0x40, 0x10, 9, 1),
+	PIN_FIELD_BASE(43, 43, 7, 0x40, 0x10, 7, 1),
+	PIN_FIELD_BASE(44, 44, 7, 0x40, 0x10, 8, 1),
+	PIN_FIELD_BASE(45, 45, 7, 0x40, 0x10, 3, 1),
+	PIN_FIELD_BASE(46, 46, 7, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(47, 47, 7, 0x40, 0x10, 5, 1),
+	PIN_FIELD_BASE(48, 48, 7, 0x40, 0x10, 6, 1),
+	PIN_FIELD_BASE(49, 49, 7, 0x40, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(50, 50, 6, 0x20, 0x10, 0, 1),
+	PIN_FIELD_BASE(51, 51, 6, 0x20, 0x10, 2, 1),
+	PIN_FIELD_BASE(52, 52, 6, 0x20, 0x10, 3, 1),
+	PIN_FIELD_BASE(53, 53, 6, 0x20, 0x10, 4, 1),
+	PIN_FIELD_BASE(54, 54, 6, 0x20, 0x10, 5, 1),
+	PIN_FIELD_BASE(55, 55, 6, 0x20, 0x10, 6, 1),
+	PIN_FIELD_BASE(56, 56, 6, 0x20, 0x10, 1, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_drv_range[] = {
+	PIN_FIELD_BASE(0, 0, 1, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(1, 1, 1, 0x00, 0x10, 0, 3),
+
+	PIN_FIELD_BASE(2, 2, 5, 0x00, 0x10, 18, 3),
+
+	PIN_FIELD_BASE(3, 3, 4, 0x00, 0x10, 18, 1),
+	PIN_FIELD_BASE(4, 4, 4, 0x00, 0x10, 6, 1),
+	PIN_FIELD_BASE(5, 5, 4, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(6, 6, 4, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(7, 7, 4, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(8, 8, 4, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(9, 9, 4, 0x00, 0x10, 27, 3),
+
+	PIN_FIELD_BASE(10, 10, 5, 0x00, 0x10, 24, 3),
+	PIN_FIELD_BASE(11, 11, 5, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(12, 12, 5, 0x00, 0x10, 21, 3),
+	PIN_FIELD_BASE(13, 13, 5, 0x00, 0x10, 3, 3),
+
+	PIN_FIELD_BASE(14, 14, 4, 0x00, 0x10, 27, 3),
+
+	PIN_FIELD_BASE(15, 15, 2, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(16, 16, 2, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(17, 17, 2, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(18, 18, 2, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(19, 19, 2, 0x00, 0x10, 6, 3),
+	PIN_FIELD_BASE(20, 20, 2, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(21, 21, 2, 0x00, 0x10, 18, 3),
+	PIN_FIELD_BASE(22, 22, 2, 0x00, 0x10, 21, 3),
+	PIN_FIELD_BASE(23, 23, 2, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(24, 24, 2, 0x00, 0x10, 27, 3),
+	PIN_FIELD_BASE(25, 25, 2, 0x00, 0x10, 24, 3),
+
+	PIN_FIELD_BASE(26, 26, 5, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(27, 27, 5, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(28, 28, 5, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(29, 29, 5, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(30, 30, 5, 0x00, 0x10, 6, 3),
+	PIN_FIELD_BASE(31, 31, 5, 0x00, 0x10, 15, 3),
+
+	PIN_FIELD_BASE(32, 32, 1, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(33, 33, 1, 0x00, 0x10, 12, 3),
+
+	PIN_FIELD_BASE(34, 34, 4, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(35, 35, 4, 0x00, 0x10, 21, 3),
+
+	PIN_FIELD_BASE(36, 36, 3, 0x00, 0x10, 6, 3),
+	PIN_FIELD_BASE(37, 37, 3, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(38, 38, 3, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(39, 39, 3, 0x00, 0x10, 3, 3),
+
+	PIN_FIELD_BASE(40, 40, 7, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(41, 41, 7, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(42, 42, 7, 0x00, 0x10, 27, 3),
+	PIN_FIELD_BASE(43, 43, 7, 0x00, 0x10, 21, 3),
+	PIN_FIELD_BASE(44, 44, 7, 0x00, 0x10, 24, 3),
+	PIN_FIELD_BASE(45, 45, 7, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(46, 46, 7, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(47, 47, 7, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(48, 48, 7, 0x00, 0x10, 18, 3),
+	PIN_FIELD_BASE(49, 49, 7, 0x00, 0x10, 6, 3),
+
+	PIN_FIELD_BASE(50, 50, 6, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(51, 51, 6, 0x00, 0x10, 6, 3),
+	PIN_FIELD_BASE(52, 52, 6, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(53, 53, 6, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(54, 54, 6, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(55, 55, 6, 0x00, 0x10, 18, 3),
+	PIN_FIELD_BASE(56, 56, 6, 0x00, 0x10, 3, 3),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_pupd_range[] = {
+	PIN_FIELD_BASE(0, 0, 1, 0x20, 0x10, 1, 1),
+	PIN_FIELD_BASE(1, 1, 1, 0x20, 0x10, 0, 1),
+	PIN_FIELD_BASE(2, 2, 5, 0x30, 0x10, 6, 1),
+	PIN_FIELD_BASE(3, 3, 4, 0x30, 0x10, 6, 1),
+	PIN_FIELD_BASE(4, 4, 4, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(5, 5, 4, 0x30, 0x10, 1, 1),
+	PIN_FIELD_BASE(6, 6, 4, 0x30, 0x10, 3, 1),
+	PIN_FIELD_BASE(7, 7, 4, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(8, 8, 4, 0x30, 0x10, 4, 1),
+	PIN_FIELD_BASE(9, 9, 4, 0x30, 0x10, 9, 1),
+
+	PIN_FIELD_BASE(10, 10, 5, 0x30, 0x10, 8, 1),
+	PIN_FIELD_BASE(11, 11, 5, 0x30, 0x10, 10, 1),
+	PIN_FIELD_BASE(12, 12, 5, 0x30, 0x10, 7, 1),
+	PIN_FIELD_BASE(13, 13, 5, 0x30, 0x10, 11, 1),
+
+	PIN_FIELD_BASE(14, 14, 4, 0x30, 0x10, 8, 1),
+
+	PIN_FIELD_BASE(15, 15, 2, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(16, 16, 2, 0x30, 0x10, 1, 1),
+	PIN_FIELD_BASE(17, 17, 2, 0x30, 0x10, 5, 1),
+	PIN_FIELD_BASE(18, 18, 2, 0x30, 0x10, 4, 1),
+	PIN_FIELD_BASE(19, 19, 2, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(20, 20, 2, 0x90, 0x10, 3, 1),
+	PIN_FIELD_BASE(21, 21, 2, 0x30, 0x10, 6, 1),
+	PIN_FIELD_BASE(22, 22, 2, 0x30, 0x10, 7, 1),
+	PIN_FIELD_BASE(23, 23, 2, 0x30, 0x10, 10, 1),
+	PIN_FIELD_BASE(24, 24, 2, 0x30, 0x10, 9, 1),
+	PIN_FIELD_BASE(25, 25, 2, 0x30, 0x10, 8, 1),
+
+	PIN_FIELD_BASE(26, 26, 5, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(27, 27, 5, 0x30, 0x10, 4, 1),
+	PIN_FIELD_BASE(28, 28, 5, 0x30, 0x10, 3, 1),
+	PIN_FIELD_BASE(29, 29, 5, 0x30, 0x10, 1, 1),
+	PIN_FIELD_BASE(30, 30, 5, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(31, 31, 5, 0x30, 0x10, 5, 1),
+
+	PIN_FIELD_BASE(32, 32, 1, 0x20, 0x10, 2, 1),
+	PIN_FIELD_BASE(33, 33, 1, 0x20, 0x10, 3, 1),
+
+	PIN_FIELD_BASE(34, 34, 4, 0x30, 0x10, 5, 1),
+	PIN_FIELD_BASE(35, 35, 4, 0x30, 0x10, 7, 1),
+
+	PIN_FIELD_BASE(36, 36, 3, 0x20, 0x10, 2, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0x20, 0x10, 3, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x20, 0x10, 0, 1),
+	PIN_FIELD_BASE(39, 39, 3, 0x20, 0x10, 1, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_r0_range[] = {
+	PIN_FIELD_BASE(0, 0, 1, 0x30, 0x10, 1, 1),
+	PIN_FIELD_BASE(1, 1, 1, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(2, 2, 5, 0x40, 0x10, 6, 1),
+	PIN_FIELD_BASE(3, 3, 4, 0x40, 0x10, 6, 1),
+	PIN_FIELD_BASE(4, 4, 4, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(5, 5, 4, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(6, 6, 4, 0x40, 0x10, 3, 1),
+	PIN_FIELD_BASE(7, 7, 4, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(8, 8, 4, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(9, 9, 4, 0x40, 0x10, 9, 1),
+
+	PIN_FIELD_BASE(10, 10, 5, 0x40, 0x10, 8, 1),
+	PIN_FIELD_BASE(11, 11, 5, 0x40, 0x10, 10, 1),
+	PIN_FIELD_BASE(12, 12, 5, 0x40, 0x10, 7, 1),
+	PIN_FIELD_BASE(13, 13, 5, 0x40, 0x10, 11, 1),
+
+	PIN_FIELD_BASE(14, 14, 4, 0x40, 0x10, 8, 1),
+
+	PIN_FIELD_BASE(15, 15, 2, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(16, 16, 2, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(17, 17, 2, 0x40, 0x10, 5, 1),
+	PIN_FIELD_BASE(18, 18, 2, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(19, 19, 2, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(20, 20, 2, 0x40, 0x10, 3, 1),
+	PIN_FIELD_BASE(21, 21, 2, 0x40, 0x10, 6, 1),
+	PIN_FIELD_BASE(22, 22, 2, 0x40, 0x10, 7, 1),
+	PIN_FIELD_BASE(23, 23, 2, 0x40, 0x10, 10, 1),
+	PIN_FIELD_BASE(24, 24, 2, 0x40, 0x10, 9, 1),
+	PIN_FIELD_BASE(25, 25, 2, 0x40, 0x10, 8, 1),
+
+	PIN_FIELD_BASE(26, 26, 5, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(27, 27, 5, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(28, 28, 5, 0x40, 0x10, 3, 1),
+	PIN_FIELD_BASE(29, 29, 5, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(30, 30, 5, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(31, 31, 5, 0x40, 0x10, 5, 1),
+
+	PIN_FIELD_BASE(32, 32, 1, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(33, 33, 1, 0x30, 0x10, 3, 1),
+
+	PIN_FIELD_BASE(34, 34, 4, 0x40, 0x10, 5, 1),
+	PIN_FIELD_BASE(35, 35, 4, 0x40, 0x10, 7, 1),
+
+	PIN_FIELD_BASE(36, 36, 3, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0x30, 0x10, 3, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(39, 39, 3, 0x30, 0x10, 1, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_r1_range[] = {
+	PIN_FIELD_BASE(0, 0, 1, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(1, 1, 1, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(2, 2, 5, 0x50, 0x10, 6, 1),
+	PIN_FIELD_BASE(3, 3, 4, 0x50, 0x10, 6, 1),
+	PIN_FIELD_BASE(4, 4, 4, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(5, 5, 4, 0x50, 0x10, 1, 1),
+	PIN_FIELD_BASE(6, 6, 4, 0x50, 0x10, 3, 1),
+	PIN_FIELD_BASE(7, 7, 4, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(8, 8, 4, 0x50, 0x10, 4, 1),
+	PIN_FIELD_BASE(9, 9, 4, 0x50, 0x10, 9, 1),
+
+	PIN_FIELD_BASE(10, 10, 5, 0x50, 0x10, 8, 1),
+	PIN_FIELD_BASE(11, 11, 5, 0x50, 0x10, 10, 1),
+	PIN_FIELD_BASE(12, 12, 5, 0x50, 0x10, 7, 1),
+	PIN_FIELD_BASE(13, 13, 5, 0x50, 0x10, 11, 1),
+
+	PIN_FIELD_BASE(14, 14, 4, 0x50, 0x10, 8, 1),
+
+	PIN_FIELD_BASE(15, 15, 2, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(16, 16, 2, 0x50, 0x10, 1, 1),
+	PIN_FIELD_BASE(17, 17, 2, 0x50, 0x10, 5, 1),
+	PIN_FIELD_BASE(18, 18, 2, 0x50, 0x10, 4, 1),
+	PIN_FIELD_BASE(19, 19, 2, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(20, 20, 2, 0x50, 0x10, 3, 1),
+	PIN_FIELD_BASE(21, 21, 2, 0x50, 0x10, 6, 1),
+	PIN_FIELD_BASE(22, 22, 2, 0x50, 0x10, 7, 1),
+	PIN_FIELD_BASE(23, 23, 2, 0x50, 0x10, 10, 1),
+	PIN_FIELD_BASE(24, 24, 2, 0x50, 0x10, 9, 1),
+	PIN_FIELD_BASE(25, 25, 2, 0x50, 0x10, 8, 1),
+
+	PIN_FIELD_BASE(26, 26, 5, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(27, 27, 5, 0x50, 0x10, 4, 1),
+	PIN_FIELD_BASE(28, 28, 5, 0x50, 0x10, 3, 1),
+	PIN_FIELD_BASE(29, 29, 5, 0x50, 0x10, 1, 1),
+	PIN_FIELD_BASE(30, 30, 5, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(31, 31, 5, 0x50, 0x10, 5, 1),
+
+	PIN_FIELD_BASE(32, 32, 1, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(33, 33, 1, 0x40, 0x10, 3, 1),
+
+	PIN_FIELD_BASE(34, 34, 4, 0x50, 0x10, 5, 1),
+	PIN_FIELD_BASE(35, 35, 4, 0x50, 0x10, 7, 1),
+
+	PIN_FIELD_BASE(36, 36, 3, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0x40, 0x10, 3, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(39, 39, 3, 0x40, 0x10, 1, 1),
+};
+
+static const struct mtk_pin_reg_calc mt7981_reg_cals[] = {
+	[PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7981_pin_mode_range),
+	[PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7981_pin_dir_range),
+	[PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7981_pin_di_range),
+	[PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7981_pin_do_range),
+	[PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7981_pin_smt_range),
+	[PINCTRL_PIN_REG_IES] = MTK_RANGE(mt7981_pin_ies_range),
+	[PINCTRL_PIN_REG_PU] = MTK_RANGE(mt7981_pin_pu_range),
+	[PINCTRL_PIN_REG_PD] = MTK_RANGE(mt7981_pin_pd_range),
+	[PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7981_pin_drv_range),
+	[PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt7981_pin_pupd_range),
+	[PINCTRL_PIN_REG_R0] = MTK_RANGE(mt7981_pin_r0_range),
+	[PINCTRL_PIN_REG_R1] = MTK_RANGE(mt7981_pin_r1_range),
+};
+
+static const struct mtk_pin_desc mt7981_pins[] = {
+	MT7986_PIN(0, "GPIO_WPS"),
+	MT7986_PIN(1, "GPIO_RESET"),
+	MT7986_PIN(2, "SYS_WATCHDOG"),
+	MT7986_PIN(3, "PCIE_PERESET_N"),
+	MT7986_PIN(4, "JTAG_JTDO"),
+	MT7986_PIN(5, "JTAG_JTDI"),
+	MT7986_PIN(6, "JTAG_JTMS"),
+	MT7986_PIN(7, "JTAG_JTCLK"),
+	MT7986_PIN(8, "JTAG_JTRST_N"),
+	MT7986_PIN(9, "WO_JTAG_JTDO"),
+	MT7986_PIN(10, "WO_JTAG_JTDI"),
+	MT7986_PIN(11, "WO_JTAG_JTMS"),
+	MT7986_PIN(12, "WO_JTAG_JTCLK"),
+	MT7986_PIN(13, "WO_JTAG_JTRST_N"),
+	MT7986_PIN(14, "USB_VBUS"),
+	MT7986_PIN(15, "PWM0"),
+	MT7986_PIN(16, "SPI0_CLK"),
+	MT7986_PIN(17, "SPI0_MOSI"),
+	MT7986_PIN(18, "SPI0_MISO"),
+	MT7986_PIN(19, "SPI0_CS"),
+	MT7986_PIN(20, "SPI0_HOLD"),
+	MT7986_PIN(21, "SPI0_WP"),
+	MT7986_PIN(22, "SPI1_CLK"),
+	MT7986_PIN(23, "SPI1_MOSI"),
+	MT7986_PIN(24, "SPI1_MISO"),
+	MT7986_PIN(25, "SPI1_CS"),
+	MT7986_PIN(26, "SPI2_CLK"),
+	MT7986_PIN(27, "SPI2_MOSI"),
+	MT7986_PIN(28, "SPI2_MISO"),
+	MT7986_PIN(29, "SPI2_CS"),
+	MT7986_PIN(30, "SPI2_HOLD"),
+	MT7986_PIN(31, "SPI2_WP"),
+	MT7986_PIN(32, "UART0_RXD"),
+	MT7986_PIN(33, "UART0_TXD"),
+	MT7986_PIN(34, "PCIE_CLK_REQ"),
+	MT7986_PIN(35, "PCIE_WAKE_N"),
+	MT7986_PIN(36, "SMI_MDC"),
+	MT7986_PIN(37, "SMI_MDIO"),
+	MT7986_PIN(38, "GBE_INT"),
+	MT7986_PIN(39, "GBE_RESET"),
+	MT7986_PIN(40, "WF_DIG_RESETB"),
+	MT7986_PIN(41, "WF_CBA_RESETB"),
+	MT7986_PIN(42, "WF_XO_REQ"),
+	MT7986_PIN(43, "WF_TOP_CLK"),
+	MT7986_PIN(44, "WF_TOP_DATA"),
+	MT7986_PIN(45, "WF_HB1"),
+	MT7986_PIN(46, "WF_HB2"),
+	MT7986_PIN(47, "WF_HB3"),
+	MT7986_PIN(48, "WF_HB4"),
+	MT7986_PIN(49, "WF_HB0"),
+	MT7986_PIN(50, "WF_HB0_B"),
+	MT7986_PIN(51, "WF_HB5"),
+	MT7986_PIN(52, "WF_HB6"),
+	MT7986_PIN(53, "WF_HB7"),
+	MT7986_PIN(54, "WF_HB8"),
+	MT7986_PIN(55, "WF_HB9"),
+	MT7986_PIN(56, "WF_HB10"),
+};
+
+/* List all groups consisting of these pins dedicated to the enablement of
+ * certain hardware block and the corresponding mode for all of the pins.
+ * The hardware probably has multiple combinations of these pinouts.
+ */
+
+/* WA_AICE */
+static int mt7981_wa_aice1_pins[] = { 0, 1, };
+static int mt7981_wa_aice1_funcs[] = { 2, 2, };
+
+static int mt7981_wa_aice2_pins[] = { 0, 1, };
+static int mt7981_wa_aice2_funcs[] = { 3, 3, };
+
+static int mt7981_wa_aice3_pins[] = { 28, 29, };
+static int mt7981_wa_aice3_funcs[] = { 3, 3, };
+
+static int mt7981_wm_aice1_pins[] = { 9, 10, };
+static int mt7981_wm_aice1_funcs[] = { 2, 2, };
+
+static int mt7981_wm_aice2_pins[] = { 30, 31, };
+static int mt7981_wm_aice2_funcs[] = { 5, 5, };
+
+/* WM_UART */
+static int mt7981_wm_uart_0_pins[] = { 0, 1, };
+static int mt7981_wm_uart_0_funcs[] = { 5, 5, };
+
+static int mt7981_wm_uart_1_pins[] = { 20, 21, };
+static int mt7981_wm_uart_1_funcs[] = { 4, 4, };
+
+static int mt7981_wm_uart_2_pins[] = { 30, 31, };
+static int mt7981_wm_uart_2_funcs[] = { 3, 3, };
+
+/* DFD */
+static int mt7981_dfd_pins[] = { 0, 1, 4, 5, };
+static int mt7981_dfd_funcs[] = { 5, 5, 6, 6, };
+
+/* SYS_WATCHDOG */
+static int mt7981_watchdog_pins[] = { 2, };
+static int mt7981_watchdog_funcs[] = { 1, };
+
+static int mt7981_watchdog1_pins[] = { 13, };
+static int mt7981_watchdog1_funcs[] = { 5, };
+
+/* PCIE_PERESET_N */
+static int mt7981_pcie_pereset_pins[] = { 3, };
+static int mt7981_pcie_pereset_funcs[] = { 1, };
+
+/* JTAG */
+static int mt7981_jtag_pins[] = { 4, 5, 6, 7, 8, };
+static int mt7981_jtag_funcs[] = { 1, 1, 1, 1, 1, };
+
+/* WM_JTAG */
+static int mt7981_wm_jtag_0_pins[] = { 4, 5, 6, 7, 8, };
+static int mt7981_wm_jtag_0_funcs[] = { 2, 2, 2, 2, 2, };
+
+static int mt7981_wm_jtag_1_pins[] = { 20, 21, 22, 23, 24, };
+static int mt7981_wm_jtag_1_funcs[] = { 5, 5, 5, 5, 5, };
+
+/* WO0_JTAG */
+static int mt7981_wo0_jtag_0_pins[] = { 9, 10, 11, 12, 13, };
+static int mt7981_wo0_jtag_0_funcs[] = { 1, 1, 1, 1, 1, };
+
+static int mt7981_wo0_jtag_1_pins[] = { 25, 26, 27, 28, 29, };
+static int mt7981_wo0_jtag_1_funcs[] = { 5, 5, 5, 5, 5, };
+
+/* UART2 */
+static int mt7981_uart2_0_pins[] = { 4, 5, 6, 7, };
+static int mt7981_uart2_0_funcs[] = { 3, 3, 3, 3, };
+
+/* GBE_LED0 */
+static int mt7981_gbe_led0_pins[] = { 8, };
+static int mt7981_gbe_led0_funcs[] = { 3, };
+
+/* PTA_EXT */
+static int mt7981_pta_ext_0_pins[] = { 4, 5, 6, };
+static int mt7981_pta_ext_0_funcs[] = { 4, 4, 4, };
+
+static int mt7981_pta_ext_1_pins[] = { 22, 23, 24, };
+static int mt7981_pta_ext_1_funcs[] = { 4, 4, 4, };
+
+/* PWM2 */
+static int mt7981_pwm2_pins[] = { 7, };
+static int mt7981_pwm2_funcs[] = { 4, };
+
+/* NET_WO0_UART_TXD */
+static int mt7981_net_wo0_uart_txd_0_pins[] = { 8, };
+static int mt7981_net_wo0_uart_txd_0_funcs[] = { 4, };
+
+static int mt7981_net_wo0_uart_txd_1_pins[] = { 14, };
+static int mt7981_net_wo0_uart_txd_1_funcs[] = { 3, };
+
+static int mt7981_net_wo0_uart_txd_2_pins[] = { 15, };
+static int mt7981_net_wo0_uart_txd_2_funcs[] = { 4, };
+
+/* SPI1 */
+static int mt7981_spi1_0_pins[] = { 4, 5, 6, 7, };
+static int mt7981_spi1_0_funcs[] = { 5, 5, 5, 5, };
+
+/* I2C */
+static int mt7981_i2c0_0_pins[] = { 6, 7, };
+static int mt7981_i2c0_0_funcs[] = { 6, 6, };
+
+static int mt7981_i2c0_1_pins[] = { 30, 31, };
+static int mt7981_i2c0_1_funcs[] = { 4, 4, };
+
+static int mt7981_i2c0_2_pins[] = { 36, 37, };
+static int mt7981_i2c0_2_funcs[] = { 2, 2, };
+
+static int mt7981_u2_phy_i2c_pins[] = { 30, 31, };
+static int mt7981_u2_phy_i2c_funcs[] = { 6, 6, };
+
+static int mt7981_u3_phy_i2c_pins[] = { 32, 33, };
+static int mt7981_u3_phy_i2c_funcs[] = { 3, 3, };
+
+static int mt7981_sgmii1_phy_i2c_pins[] = { 32, 33, };
+static int mt7981_sgmii1_phy_i2c_funcs[] = { 2, 2, };
+
+static int mt7981_sgmii0_phy_i2c_pins[] = { 32, 33, };
+static int mt7981_sgmii0_phy_i2c_funcs[] = { 5, 5, };
+
+/* DFD_NTRST */
+static int mt7981_dfd_ntrst_pins[] = { 8, };
+static int mt7981_dfd_ntrst_funcs[] = { 6, };
+
+/* PWM0 */
+static int mt7981_pwm0_0_pins[] = { 13, };
+static int mt7981_pwm0_0_funcs[] = { 2, };
+
+static int mt7981_pwm0_1_pins[] = { 15, };
+static int mt7981_pwm0_1_funcs[] = { 1, };
+
+/* PWM1 */
+static int mt7981_pwm1_0_pins[] = { 14, };
+static int mt7981_pwm1_0_funcs[] = { 2, };
+
+static int mt7981_pwm1_1_pins[] = { 15, };
+static int mt7981_pwm1_1_funcs[] = { 3, };
+
+/* GBE_LED1 */
+static int mt7981_gbe_led1_pins[] = { 13, };
+static int mt7981_gbe_led1_funcs[] = { 3, };
+
+/* PCM */
+static int mt7981_pcm_pins[] = { 9, 10, 11, 12, 13, 25 };
+static int mt7981_pcm_funcs[] = { 4, 4, 4, 4, 4, 4, };
+
+/* UDI */
+static int mt7981_udi_pins[] = { 9, 10, 11, 12, 13, };
+static int mt7981_udi_funcs[] = { 6, 6, 6, 6, 6, };
+
+/* DRV_VBUS */
+static int mt7981_drv_vbus_pins[] = { 14, };
+static int mt7981_drv_vbus_funcs[] = { 1, };
+
+/* EMMC */
+static int mt7981_emmc_45_pins[] = { 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, };
+static int mt7981_emmc_45_funcs[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, };
+
+/* SNFI */
+static int mt7981_snfi_pins[] = { 16, 17, 18, 19, 20, 21, };
+static int mt7981_snfi_funcs[] = { 3, 3, 3, 3, 3, 3, };
+
+/* SPI0 */
+static int mt7981_spi0_pins[] = { 16, 17, 18, 19, };
+static int mt7981_spi0_funcs[] = { 1, 1, 1, 1, };
+
+/* SPI0 */
+static int mt7981_spi0_wp_hold_pins[] = { 20, 21, };
+static int mt7981_spi0_wp_hold_funcs[] = { 1, 1, };
+
+/* SPI1 */
+static int mt7981_spi1_1_pins[] = { 22, 23, 24, 25, };
+static int mt7981_spi1_1_funcs[] = { 1, 1, 1, 1, };
+
+/* SPI2 */
+static int mt7981_spi2_pins[] = { 26, 27, 28, 29, };
+static int mt7981_spi2_funcs[] = { 1, 1, 1, 1, };
+
+/* SPI2 */
+static int mt7981_spi2_wp_hold_pins[] = { 30, 31, };
+static int mt7981_spi2_wp_hold_funcs[] = { 1, 1, };
+
+/* UART1 */
+static int mt7981_uart1_0_pins[] = { 16, 17, 18, 19, };
+static int mt7981_uart1_0_funcs[] = { 4, 4, 4, 4, };
+
+static int mt7981_uart1_1_pins[] = { 26, 27, 28, 29, };
+static int mt7981_uart1_1_funcs[] = { 2, 2, 2, 2, };
+
+/* UART2 */
+static int mt7981_uart2_1_pins[] = { 22, 23, 24, 25, };
+static int mt7981_uart2_1_funcs[] = { 3, 3, 3, 3, };
+
+/* UART0 */
+static int mt7981_uart0_pins[] = { 32, 33, };
+static int mt7981_uart0_funcs[] = { 1, 1, };
+
+/* PCIE_CLK_REQ */
+static int mt7981_pcie_clk_pins[] = { 34, };
+static int mt7981_pcie_clk_funcs[] = { 2, };
+
+/* PCIE_WAKE_N */
+static int mt7981_pcie_wake_pins[] = { 35, };
+static int mt7981_pcie_wake_funcs[] = { 2, };
+
+/* MDC_MDIO */
+static int mt7981_smi_mdc_mdio_pins[] = { 36, 37, };
+static int mt7981_smi_mdc_mdio_funcs[] = { 1, 1, };
+
+static int mt7981_gbe_ext_mdc_mdio_pins[] = { 36, 37, };
+static int mt7981_gbe_ext_mdc_mdio_funcs[] = { 3, 3, };
+
+/* WF0_MODE1 */
+static int mt7981_wf0_mode1_pins[] = { 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56 };
+static int mt7981_wf0_mode1_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+
+/* WF0_MODE3 */
+static int mt7981_wf0_mode3_pins[] = { 45, 46, 47, 48, 49, 51 };
+static int mt7981_wf0_mode3_funcs[] = { 2, 2, 2, 2, 2, 2 };
+
+/* WF2G_LED */
+static int mt7981_wf2g_led0_pins[] = { 30, };
+static int mt7981_wf2g_led0_funcs[] = { 2, };
+
+static int mt7981_wf2g_led1_pins[] = { 34, };
+static int mt7981_wf2g_led1_funcs[] = { 1, };
+
+/* WF5G_LED */
+static int mt7981_wf5g_led0_pins[] = { 31, };
+static int mt7981_wf5g_led0_funcs[] = { 2, };
+
+static int mt7981_wf5g_led1_pins[] = { 35, };
+static int mt7981_wf5g_led1_funcs[] = { 1, };
+
+/* MT7531_INT */
+static int mt7981_mt7531_int_pins[] = { 38, };
+static int mt7981_mt7531_int_funcs[] = { 1, };
+
+/* ANT_SEL */
+static int mt7981_ant_sel_pins[] = { 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 34, 35 };
+static int mt7981_ant_sel_funcs[] = { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 };
+
+static const struct group_desc mt7981_groups[] = {
+    /*  @GPIO(0,1): WA_AICE(2) */
+        PINCTRL_PIN_GROUP("wa_aice1", mt7981_wa_aice1),
+    /*  @GPIO(0,1): WA_AICE(3) */
+        PINCTRL_PIN_GROUP("wa_aice2", mt7981_wa_aice2),
+    /*  @GPIO(0,1): WM_UART(5) */
+        PINCTRL_PIN_GROUP("wm_uart_0", mt7981_wm_uart_0),
+    /*  @GPIO(0,1,4,5): DFD(6) */
+        PINCTRL_PIN_GROUP("dfd", mt7981_dfd),
+    /*  @GPIO(2): SYS_WATCHDOG(1) */
+        PINCTRL_PIN_GROUP("watchdog", mt7981_watchdog),
+    /*  @GPIO(3): PCIE_PERESET_N(1) */
+        PINCTRL_PIN_GROUP("pcie_pereset", mt7981_pcie_pereset),
+    /*  @GPIO(4,8) JTAG(1) */
+        PINCTRL_PIN_GROUP("jtag", mt7981_jtag),
+    /*  @GPIO(4,8) WM_JTAG(2) */
+        PINCTRL_PIN_GROUP("wm_jtag_0", mt7981_wm_jtag_0),
+    /*	@GPIO(9,13) WO0_JTAG(1) */
+	PINCTRL_PIN_GROUP("wo0_jtag_0", mt7981_wo0_jtag_0),
+    /*  @GPIO(4,7) WM_JTAG(3) */
+        PINCTRL_PIN_GROUP("uart2_0", mt7981_uart2_0),
+    /*  @GPIO(8) GBE_LED0(3) */
+        PINCTRL_PIN_GROUP("gbe_led0", mt7981_gbe_led0),
+    /*  @GPIO(4,6) PTA_EXT(4) */
+        PINCTRL_PIN_GROUP("pta_ext_0", mt7981_pta_ext_0),
+    /*  @GPIO(7) PWM2(4) */
+        PINCTRL_PIN_GROUP("pwm2", mt7981_pwm2),
+    /*  @GPIO(8) NET_WO0_UART_TXD(4) */
+        PINCTRL_PIN_GROUP("net_wo0_uart_txd_0", mt7981_net_wo0_uart_txd_0),
+    /*  @GPIO(4,7) SPI1(5) */
+        PINCTRL_PIN_GROUP("spi1_0", mt7981_spi1_0),
+    /*  @GPIO(6,7) I2C(5) */
+        PINCTRL_PIN_GROUP("i2c0_0", mt7981_i2c0_0),
+    /*  @GPIO(0,1,4,5): DFD_NTRST(6) */
+        PINCTRL_PIN_GROUP("dfd_ntrst", mt7981_dfd_ntrst),
+    /*  @GPIO(9,10): WM_AICE(2) */
+        PINCTRL_PIN_GROUP("wm_aice1", mt7981_wm_aice1),
+    /*  @GPIO(13): PWM0(2) */
+        PINCTRL_PIN_GROUP("pwm0_0", mt7981_pwm0_0),
+    /*  @GPIO(15): PWM0(1) */
+        PINCTRL_PIN_GROUP("pwm0_1", mt7981_pwm0_1),
+    /*  @GPIO(14): PWM1(2) */
+        PINCTRL_PIN_GROUP("pwm1_0", mt7981_pwm1_0),
+    /*  @GPIO(15): PWM1(3) */
+        PINCTRL_PIN_GROUP("pwm1_1", mt7981_pwm1_1),
+    /*  @GPIO(14) NET_WO0_UART_TXD(3) */
+        PINCTRL_PIN_GROUP("net_wo0_uart_txd_1", mt7981_net_wo0_uart_txd_1),
+    /*  @GPIO(15) NET_WO0_UART_TXD(4) */
+        PINCTRL_PIN_GROUP("net_wo0_uart_txd_2", mt7981_net_wo0_uart_txd_2),
+    /*  @GPIO(13) GBE_LED0(3) */
+        PINCTRL_PIN_GROUP("gbe_led1", mt7981_gbe_led1),
+    /*  @GPIO(9,13) PCM(4) */
+        PINCTRL_PIN_GROUP("pcm", mt7981_pcm),
+    /*  @GPIO(13): SYS_WATCHDOG1(5) */
+        PINCTRL_PIN_GROUP("watchdog1", mt7981_watchdog1),
+    /*  @GPIO(9,13) UDI(4) */
+        PINCTRL_PIN_GROUP("udi", mt7981_udi),
+    /*  @GPIO(14) DRV_VBUS(1) */
+        PINCTRL_PIN_GROUP("drv_vbus", mt7981_drv_vbus),
+    /*  @GPIO(15,25): EMMC(2) */
+        PINCTRL_PIN_GROUP("emmc_45", mt7981_emmc_45),
+    /*  @GPIO(16,21): SNFI(3) */
+        PINCTRL_PIN_GROUP("snfi", mt7981_snfi),
+    /*  @GPIO(16,19): SPI0(1) */
+        PINCTRL_PIN_GROUP("spi0", mt7981_spi0),
+	/*  @GPIO(20,21): SPI0(1) */
+        PINCTRL_PIN_GROUP("spi0_wp_hold", mt7981_spi0_wp_hold),
+    /*  @GPIO(22,25) SPI1(1) */
+        PINCTRL_PIN_GROUP("spi1_1", mt7981_spi1_1),
+    /*  @GPIO(26,29): SPI2(1) */
+        PINCTRL_PIN_GROUP("spi2", mt7981_spi2),
+	/*  @GPIO(30,31): SPI0(1) */
+        PINCTRL_PIN_GROUP("spi2_wp_hold", mt7981_spi2_wp_hold),
+    /*  @GPIO(16,19): UART1(4) */
+        PINCTRL_PIN_GROUP("uart1_0", mt7981_uart1_0),
+    /*  @GPIO(26,29): UART1(2) */
+        PINCTRL_PIN_GROUP("uart1_1", mt7981_uart1_1),
+    /*  @GPIO(22,25): UART1(3) */
+        PINCTRL_PIN_GROUP("uart2_1", mt7981_uart2_1),
+    /*  @GPIO(22,24) PTA_EXT(4) */
+        PINCTRL_PIN_GROUP("pta_ext_1", mt7981_pta_ext_1),
+    /*  @GPIO(20,21): WM_UART(4) */
+        PINCTRL_PIN_GROUP("wm_aurt_1", mt7981_wm_uart_1),
+    /*  @GPIO(30,31): WM_UART(3) */
+        PINCTRL_PIN_GROUP("wm_aurt_2", mt7981_wm_uart_2),
+    /*  @GPIO(20,24) WM_JTAG(5) */
+        PINCTRL_PIN_GROUP("wm_jtag_1", mt7981_wm_jtag_1),
+    /*	@GPIO(25,29) WO0_JTAG(5) */
+	PINCTRL_PIN_GROUP("wo0_jtag_1", mt7981_wo0_jtag_1),
+    /*  @GPIO(28,29): WA_AICE(3) */
+        PINCTRL_PIN_GROUP("wa_aice3", mt7981_wa_aice3),
+    /*  @GPIO(30,31): WM_AICE(5) */
+        PINCTRL_PIN_GROUP("wm_aice2", mt7981_wm_aice2),
+    /*  @GPIO(30,31): I2C(4) */
+        PINCTRL_PIN_GROUP("i2c0_1", mt7981_i2c0_1),
+    /*  @GPIO(30,31): I2C(6) */
+        PINCTRL_PIN_GROUP("u2_phy_i2c", mt7981_u2_phy_i2c),
+    /*  @GPIO(32,33): I2C(1) */
+        PINCTRL_PIN_GROUP("uart0", mt7981_uart0),
+    /*  @GPIO(32,33): I2C(2) */
+        PINCTRL_PIN_GROUP("sgmii1_phy_i2c", mt7981_sgmii1_phy_i2c),
+    /*  @GPIO(32,33): I2C(3) */
+        PINCTRL_PIN_GROUP("u3_phy_i2c", mt7981_u3_phy_i2c),
+    /*  @GPIO(32,33): I2C(5) */
+        PINCTRL_PIN_GROUP("sgmii0_phy_i2c", mt7981_sgmii0_phy_i2c),
+    /*  @GPIO(34): PCIE_CLK_REQ(2) */
+        PINCTRL_PIN_GROUP("pcie_clk", mt7981_pcie_clk),
+    /*  @GPIO(35): PCIE_WAKE_N(2) */
+        PINCTRL_PIN_GROUP("pcie_wake", mt7981_pcie_wake),
+    /*  @GPIO(36,37): I2C(2) */
+        PINCTRL_PIN_GROUP("i2c0_2", mt7981_i2c0_2),
+    /*  @GPIO(36,37): MDC_MDIO(1) */
+        PINCTRL_PIN_GROUP("smi_mdc_mdio", mt7981_smi_mdc_mdio),
+    /*  @GPIO(36,37): MDC_MDIO(3) */
+        PINCTRL_PIN_GROUP("gbe_ext_mdc_mdio", mt7981_gbe_ext_mdc_mdio),
+    /*  @GPIO(69,85): WF0_MODE1(1) */
+        PINCTRL_PIN_GROUP("wf0_mode1", mt7981_wf0_mode1),
+    /*  @GPIO(74,80): WF0_MODE3(3) */
+        PINCTRL_PIN_GROUP("wf0_mode3", mt7981_wf0_mode3),
+    /*  @GPIO(30): WF2G_LED(2) */
+        PINCTRL_PIN_GROUP("wf2g_led0", mt7981_wf2g_led0),
+    /*  @GPIO(34): WF2G_LED(1) */
+        PINCTRL_PIN_GROUP("wf2g_led1", mt7981_wf2g_led1),
+    /*  @GPIO(31): WF5G_LED(2) */
+        PINCTRL_PIN_GROUP("wf5g_led0", mt7981_wf5g_led0),
+    /*  @GPIO(35): WF5G_LED(1) */
+        PINCTRL_PIN_GROUP("wf5g_led1", mt7981_wf5g_led1),
+    /*  @GPIO(38): MT7531_INT(1) */
+        PINCTRL_PIN_GROUP("mt7531_int", mt7981_mt7531_int),
+    /*  @GPIO(14,15,26,17,18,19,20,21,22,23,24,25,34,35): ANT_SEL(1) */
+        PINCTRL_PIN_GROUP("ant_sel", mt7981_ant_sel),
+};
+
+/* Joint those groups owning the same capability in user point of view which
+ * allows that people tend to use through the device tree.
+ */
+static const char *mt7981_wa_aice_groups[] = { "wa_aice1", "wa_aice2", "wm_aice1_1",
+	"wa_aice3", "wm_aice1_2", };
+static const char *mt7981_uart_groups[] = { "wm_uart_0", "uart2_0",
+	"net_wo0_uart_txd_0", "net_wo0_uart_txd_1", "net_wo0_uart_txd_2",
+	"uart1_0", "uart1_1", "uart2_1", "wm_aurt_1", "wm_aurt_2", "uart0", };
+static const char *mt7981_dfd_groups[] = { "dfd", "dfd_ntrst", };
+static const char *mt7981_wdt_groups[] = { "watchdog", "watchdog1", };
+static const char *mt7981_pcie_groups[] = { "pcie_pereset", "pcie_clk", "pcie_wake", };
+static const char *mt7981_jtag_groups[] = { "jtag", "wm_jtag_0", "wo0_jtag_0",
+	"wo0_jtag_1", "wm_jtag_1", };
+static const char *mt7981_led_groups[] = { "gbe_led0", "gbe_led1", "wf2g_led0",
+	"wf2g_led1", "wf5g_led0", "wf5g_led1", };
+static const char *mt7981_pta_groups[] = { "pta_ext_0", "pta_ext_1", };
+static const char *mt7981_pwm_groups[] = { "pwm2", "pwm0_0", "pwm0_1",
+	"pwm1_0", "pwm1_1", };
+static const char *mt7981_spi_groups[] = { "spi1_0", "spi0", "spi0_wp_hold", "spi1_1", "spi2",
+	"spi2_wp_hold", };
+static const char *mt7981_i2c_groups[] = { "i2c0_0", "i2c0_1", "u2_phy_i2c",
+	"sgmii1_phy_i2c", "u3_phy_i2c", "sgmii0_phy_i2c", "i2c0_2", };
+static const char *mt7981_pcm_groups[] = { "pcm", };
+static const char *mt7981_udi_groups[] = { "udi", };
+static const char *mt7981_usb_groups[] = { "drv_vbus", };
+static const char *mt7981_flash_groups[] = { "emmc_45", "snfi", };
+static const char *mt7981_ethernet_groups[] = { "smi_mdc_mdio", "gbe_ext_mdc_mdio",
+	"wf0_mode1", "wf0_mode3", "mt7531_int", };
+static const char *mt7981_ant_groups[] = { "ant_sel", };
+
+static const struct function_desc mt7981_functions[] = {
+	{"wa_aice",	mt7981_wa_aice_groups, ARRAY_SIZE(mt7981_wa_aice_groups)},
+	{"dfd",	mt7981_dfd_groups, ARRAY_SIZE(mt7981_dfd_groups)},
+	{"jtag", mt7981_jtag_groups, ARRAY_SIZE(mt7981_jtag_groups)},
+	{"pta", mt7981_pta_groups, ARRAY_SIZE(mt7981_pta_groups)},
+	{"pcm", mt7981_pcm_groups, ARRAY_SIZE(mt7981_pcm_groups)},
+	{"udi", mt7981_udi_groups, ARRAY_SIZE(mt7981_udi_groups)},
+	{"usb", mt7981_usb_groups, ARRAY_SIZE(mt7981_usb_groups)},
+	{"ant", mt7981_ant_groups, ARRAY_SIZE(mt7981_ant_groups)},
+	{"eth",	mt7981_ethernet_groups, ARRAY_SIZE(mt7981_ethernet_groups)},
+	{"i2c", mt7981_i2c_groups, ARRAY_SIZE(mt7981_i2c_groups)},
+	{"led",	mt7981_led_groups, ARRAY_SIZE(mt7981_led_groups)},
+	{"pwm",	mt7981_pwm_groups, ARRAY_SIZE(mt7981_pwm_groups)},
+	{"spi",	mt7981_spi_groups, ARRAY_SIZE(mt7981_spi_groups)},
+	{"uart", mt7981_uart_groups, ARRAY_SIZE(mt7981_uart_groups)},
+	{"watchdog", mt7981_wdt_groups, ARRAY_SIZE(mt7981_wdt_groups)},
+	{"flash", mt7981_flash_groups, ARRAY_SIZE(mt7981_flash_groups)},
+	{"pcie", mt7981_pcie_groups, ARRAY_SIZE(mt7981_pcie_groups)},
+};
+
+static const struct mtk_eint_hw mt7981_eint_hw = {
+	.port_mask = 7,
+	.ports     = 7,
+	.ap_num    = ARRAY_SIZE(mt7981_pins),
+	.db_cnt    = 16,
+};
+
+static const char * const mt7981_pinctrl_register_base_names[] = {
+	"gpio_base", "iocfg_rt_base", "iocfg_rm_base", "iocfg_rb_base",
+	"iocfg_lb_base", "iocfg_bl_base", "iocfg_tm_base", "iocfg_tl_base",
+};
+
+static struct mtk_pin_soc mt7981_data = {
+	.reg_cal = mt7981_reg_cals,
+	.pins = mt7981_pins,
+	.npins = ARRAY_SIZE(mt7981_pins),
+	.grps = mt7981_groups,
+	.ngrps = ARRAY_SIZE(mt7981_groups),
+	.funcs = mt7981_functions,
+	.nfuncs = ARRAY_SIZE(mt7981_functions),
+	.eint_hw = &mt7981_eint_hw,
+	.gpio_m = 0,
+	.ies_present = false,
+	.base_names = mt7981_pinctrl_register_base_names,
+	.nbase_names = ARRAY_SIZE(mt7981_pinctrl_register_base_names),
+	.bias_disable_set = mtk_pinconf_bias_disable_set,
+	.bias_disable_get = mtk_pinconf_bias_disable_get,
+	.bias_set = mtk_pinconf_bias_set,
+	.bias_get = mtk_pinconf_bias_get,
+	.drive_set = mtk_pinconf_drive_set_rev1,
+	.drive_get = mtk_pinconf_drive_get_rev1,
+	.adv_pull_get = mtk_pinconf_adv_pull_get,
+	.adv_pull_set = mtk_pinconf_adv_pull_set,
+};
+
+static const struct of_device_id mt7981_pinctrl_of_match[] = {
+	{ .compatible = "mediatek,mt7981-pinctrl", },
+	{}
+};
+
+static int mt7981_pinctrl_probe(struct platform_device *pdev)
+{
+	return mtk_moore_pinctrl_probe(pdev, &mt7981_data);
+}
+
+static struct platform_driver mt7981_pinctrl_driver = {
+	.driver = {
+		.name = "mt7981-pinctrl",
+		.of_match_table = mt7981_pinctrl_of_match,
+	},
+	.probe = mt7981_pinctrl_probe,
+};
+
+static int __init mt7981_pinctrl_init(void)
+{
+	return platform_driver_register(&mt7981_pinctrl_driver);
+}
+arch_initcall(mt7981_pinctrl_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7986.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7986.c
new file mode 100644
index 0000000..b0f4c95
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7986.c
@@ -0,0 +1,1096 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The MT7986 driver based on Linux generic pinctrl binding.
+ *
+ * Copyright (C) 2020 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+#include "pinctrl-moore.h"
+
+#define MT7986_PIN(_number, _name)				\
+	MTK_PIN(_number, _name, 0, _number, DRV_GRP4)
+
+#define PIN_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, _x_bits)	\
+	PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit,	\
+		       _x_bits, 32, 0)
+
+#define PINS_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, _x_bits)	\
+	PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit,	\
+		      _x_bits, 32, 1)
+
+static const struct mtk_pin_field_calc mt7986_pin_mode_range[] = {
+	PIN_FIELD(0, 100, 0x300, 0x10, 0, 4),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_dir_range[] = {
+	PIN_FIELD(0, 100, 0x0, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_di_range[] = {
+	PIN_FIELD(0, 100, 0x200, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_do_range[] = {
+	PIN_FIELD(0, 100, 0x100, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_ies_range[] = {
+	PIN_FIELD_BASE(0, 0, 2, 0x40, 0x10, 17, 1),
+	PIN_FIELD_BASE(1, 1, 3, 0x20, 0x10, 10, 1),
+	PIN_FIELD_BASE(2, 2, 3, 0x20, 0x10, 11, 1),
+	PIN_FIELD_BASE(3, 3, 4, 0x20, 0x10, 0, 1),
+	PIN_FIELD_BASE(4, 4, 4, 0x20, 0x10, 1, 1),
+	PIN_FIELD_BASE(5, 5, 2, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(6, 6, 2, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(7, 7, 3, 0x20, 0x10, 0, 1),
+	PIN_FIELD_BASE(8, 8, 3, 0x20, 0x10, 1, 1),
+	PIN_FIELD_BASE(9, 9, 3, 0x20, 0x10, 2, 1),
+	PIN_FIELD_BASE(10, 10, 3, 0x20, 0x10, 3, 1),
+	PIN_FIELD_BASE(11, 11, 2, 0x40, 0x10, 8, 1),
+	PIN_FIELD_BASE(12, 12, 2, 0x40, 0x10, 9, 1),
+	PIN_FIELD_BASE(13, 13, 2, 0x40, 0x10, 10, 1),
+	PIN_FIELD_BASE(14, 14, 2, 0x40, 0x10, 11, 1),
+	PIN_FIELD_BASE(15, 15, 2, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(16, 16, 2, 0x40, 0x10, 3, 1),
+	PIN_FIELD_BASE(17, 17, 2, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(18, 18, 2, 0x40, 0x10, 5, 1),
+	PIN_FIELD_BASE(19, 19, 2, 0x40, 0x10, 6, 1),
+	PIN_FIELD_BASE(20, 20, 2, 0x40, 0x10, 7, 1),
+	PIN_FIELD_BASE(21, 21, 1, 0x30, 0x10, 12, 1),
+	PIN_FIELD_BASE(22, 22, 1, 0x30, 0x10, 13, 1),
+	PIN_FIELD_BASE(23, 23, 1, 0x30, 0x10, 14, 1),
+	PIN_FIELD_BASE(24, 24, 1, 0x30, 0x10, 18, 1),
+	PIN_FIELD_BASE(25, 25, 1, 0x30, 0x10, 17, 1),
+	PIN_FIELD_BASE(26, 26, 1, 0x30, 0x10, 15, 1),
+	PIN_FIELD_BASE(27, 27, 1, 0x30, 0x10, 16, 1),
+	PIN_FIELD_BASE(28, 28, 1, 0x30, 0x10, 19, 1),
+	PIN_FIELD_BASE(29, 29, 1, 0x30, 0x10, 20, 1),
+	PIN_FIELD_BASE(30, 30, 1, 0x30, 0x10, 23, 1),
+	PIN_FIELD_BASE(31, 31, 1, 0x30, 0x10, 22, 1),
+	PIN_FIELD_BASE(32, 32, 1, 0x30, 0x10, 21, 1),
+	PIN_FIELD_BASE(33, 33, 3, 0x20, 0x10, 4, 1),
+	PIN_FIELD_BASE(34, 34, 3, 0x20, 0x10, 8, 1),
+	PIN_FIELD_BASE(35, 35, 3, 0x20, 0x10, 7, 1),
+	PIN_FIELD_BASE(36, 36, 3, 0x20, 0x10, 5, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0x20, 0x10, 6, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x20, 0x10, 9, 1),
+	PIN_FIELD_BASE(39, 39, 2, 0x40, 0x10, 18, 1),
+	PIN_FIELD_BASE(40, 40, 2, 0x40, 0x10, 19, 1),
+	PIN_FIELD_BASE(41, 41, 2, 0x40, 0x10, 12, 1),
+	PIN_FIELD_BASE(42, 42, 2, 0x40, 0x10, 22, 1),
+	PIN_FIELD_BASE(43, 43, 2, 0x40, 0x10, 23, 1),
+	PIN_FIELD_BASE(44, 44, 2, 0x40, 0x10, 20, 1),
+	PIN_FIELD_BASE(45, 45, 2, 0x40, 0x10, 21, 1),
+	PIN_FIELD_BASE(46, 46, 2, 0x40, 0x10, 26, 1),
+	PIN_FIELD_BASE(47, 47, 2, 0x40, 0x10, 27, 1),
+	PIN_FIELD_BASE(48, 48, 2, 0x40, 0x10, 24, 1),
+	PIN_FIELD_BASE(49, 49, 2, 0x40, 0x10, 25, 1),
+	PIN_FIELD_BASE(50, 50, 1, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(51, 51, 1, 0x30, 0x10, 3, 1),
+	PIN_FIELD_BASE(52, 52, 1, 0x30, 0x10, 4, 1),
+	PIN_FIELD_BASE(53, 53, 1, 0x30, 0x10, 5, 1),
+	PIN_FIELD_BASE(54, 54, 1, 0x30, 0x10, 6, 1),
+	PIN_FIELD_BASE(55, 55, 1, 0x30, 0x10, 7, 1),
+	PIN_FIELD_BASE(56, 56, 1, 0x30, 0x10, 8, 1),
+	PIN_FIELD_BASE(57, 57, 1, 0x30, 0x10, 9, 1),
+	PIN_FIELD_BASE(58, 58, 1, 0x30, 0x10, 1, 1),
+	PIN_FIELD_BASE(59, 59, 1, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(60, 60, 1, 0x30, 0x10, 10, 1),
+	PIN_FIELD_BASE(61, 61, 1, 0x30, 0x10, 11, 1),
+	PIN_FIELD_BASE(62, 62, 2, 0x40, 0x10, 15, 1),
+	PIN_FIELD_BASE(63, 63, 2, 0x40, 0x10, 14, 1),
+	PIN_FIELD_BASE(64, 64, 2, 0x40, 0x10, 13, 1),
+	PIN_FIELD_BASE(65, 65, 2, 0x40, 0x10, 16, 1),
+	PIN_FIELD_BASE(66, 66, 4, 0x20, 0x10, 2, 1),
+	PIN_FIELD_BASE(67, 67, 4, 0x20, 0x10, 3, 1),
+	PIN_FIELD_BASE(68, 68, 4, 0x20, 0x10, 4, 1),
+	PIN_FIELD_BASE(69, 69, 5, 0x30, 0x10, 1, 1),
+	PIN_FIELD_BASE(70, 70, 5, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(71, 71, 5, 0x30, 0x10, 16, 1),
+	PIN_FIELD_BASE(72, 72, 5, 0x30, 0x10, 14, 1),
+	PIN_FIELD_BASE(73, 73, 5, 0x30, 0x10, 15, 1),
+	PIN_FIELD_BASE(74, 74, 5, 0x30, 0x10, 4, 1),
+	PIN_FIELD_BASE(75, 75, 5, 0x30, 0x10, 6, 1),
+	PIN_FIELD_BASE(76, 76, 5, 0x30, 0x10, 7, 1),
+	PIN_FIELD_BASE(77, 77, 5, 0x30, 0x10, 8, 1),
+	PIN_FIELD_BASE(78, 78, 5, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(79, 79, 5, 0x30, 0x10, 3, 1),
+	PIN_FIELD_BASE(80, 80, 5, 0x30, 0x10, 9, 1),
+	PIN_FIELD_BASE(81, 81, 5, 0x30, 0x10, 10, 1),
+	PIN_FIELD_BASE(82, 82, 5, 0x30, 0x10, 11, 1),
+	PIN_FIELD_BASE(83, 83, 5, 0x30, 0x10, 12, 1),
+	PIN_FIELD_BASE(84, 84, 5, 0x30, 0x10, 13, 1),
+	PIN_FIELD_BASE(85, 85, 5, 0x30, 0x10, 5, 1),
+	PIN_FIELD_BASE(86, 86, 6, 0x30, 0x10, 1, 1),
+	PIN_FIELD_BASE(87, 87, 6, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(88, 88, 6, 0x30, 0x10, 14, 1),
+	PIN_FIELD_BASE(89, 89, 6, 0x30, 0x10, 12, 1),
+	PIN_FIELD_BASE(90, 90, 6, 0x30, 0x10, 13, 1),
+	PIN_FIELD_BASE(91, 91, 6, 0x30, 0x10, 4, 1),
+	PIN_FIELD_BASE(92, 92, 6, 0x30, 0x10, 5, 1),
+	PIN_FIELD_BASE(93, 93, 6, 0x30, 0x10, 6, 1),
+	PIN_FIELD_BASE(94, 94, 6, 0x30, 0x10, 7, 1),
+	PIN_FIELD_BASE(95, 95, 6, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(96, 96, 6, 0x30, 0x10, 3, 1),
+	PIN_FIELD_BASE(97, 97, 6, 0x30, 0x10, 8, 1),
+	PIN_FIELD_BASE(98, 98, 6, 0x30, 0x10, 9, 1),
+	PIN_FIELD_BASE(99, 99, 6, 0x30, 0x10, 10, 1),
+	PIN_FIELD_BASE(100, 100, 6, 0x30, 0x10, 11, 1),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_smt_range[] = {
+	PIN_FIELD_BASE(0, 0, 2, 0xf0, 0x10, 17, 1),
+	PIN_FIELD_BASE(1, 1, 3, 0x90, 0x10, 10, 1),
+	PIN_FIELD_BASE(2, 2, 3, 0x90, 0x10, 11, 1),
+	PIN_FIELD_BASE(3, 3, 4, 0x90, 0x10, 0, 1),
+	PIN_FIELD_BASE(4, 4, 4, 0x90, 0x10, 1, 1),
+	PIN_FIELD_BASE(5, 5, 2, 0xf0, 0x10, 0, 1),
+	PIN_FIELD_BASE(6, 6, 2, 0xf0, 0x10, 1, 1),
+	PIN_FIELD_BASE(7, 7, 3, 0x90, 0x10, 0, 1),
+	PIN_FIELD_BASE(8, 8, 3, 0x90, 0x10, 1, 1),
+	PIN_FIELD_BASE(9, 9, 3, 0x90, 0x10, 2, 1),
+	PIN_FIELD_BASE(10, 10, 3, 0x90, 0x10, 3, 1),
+	PIN_FIELD_BASE(11, 11, 2, 0xf0, 0x10, 8, 1),
+	PIN_FIELD_BASE(12, 12, 2, 0xf0, 0x10, 9, 1),
+	PIN_FIELD_BASE(13, 13, 2, 0xf0, 0x10, 10, 1),
+	PIN_FIELD_BASE(14, 14, 2, 0xf0, 0x10, 11, 1),
+	PIN_FIELD_BASE(15, 15, 2, 0xf0, 0x10, 2, 1),
+	PIN_FIELD_BASE(16, 16, 2, 0xf0, 0x10, 3, 1),
+	PIN_FIELD_BASE(17, 17, 2, 0xf0, 0x10, 4, 1),
+	PIN_FIELD_BASE(18, 18, 2, 0xf0, 0x10, 5, 1),
+	PIN_FIELD_BASE(19, 19, 2, 0xf0, 0x10, 6, 1),
+	PIN_FIELD_BASE(20, 20, 2, 0xf0, 0x10, 7, 1),
+	PIN_FIELD_BASE(21, 21, 1, 0xc0, 0x10, 12, 1),
+	PIN_FIELD_BASE(22, 22, 1, 0xc0, 0x10, 13, 1),
+	PIN_FIELD_BASE(23, 23, 1, 0xc0, 0x10, 14, 1),
+	PIN_FIELD_BASE(24, 24, 1, 0xc0, 0x10, 18, 1),
+	PIN_FIELD_BASE(25, 25, 1, 0xc0, 0x10, 17, 1),
+	PIN_FIELD_BASE(26, 26, 1, 0xc0, 0x10, 15, 1),
+	PIN_FIELD_BASE(27, 27, 1, 0xc0, 0x10, 16, 1),
+	PIN_FIELD_BASE(28, 28, 1, 0xc0, 0x10, 19, 1),
+	PIN_FIELD_BASE(29, 29, 1, 0xc0, 0x10, 20, 1),
+	PIN_FIELD_BASE(30, 30, 1, 0xc0, 0x10, 23, 1),
+	PIN_FIELD_BASE(31, 31, 1, 0xc0, 0x10, 22, 1),
+	PIN_FIELD_BASE(32, 32, 1, 0xc0, 0x10, 21, 1),
+	PIN_FIELD_BASE(33, 33, 3, 0x90, 0x10, 4, 1),
+	PIN_FIELD_BASE(34, 34, 3, 0x90, 0x10, 8, 1),
+	PIN_FIELD_BASE(35, 35, 3, 0x90, 0x10, 7, 1),
+	PIN_FIELD_BASE(36, 36, 3, 0x90, 0x10, 5, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0x90, 0x10, 6, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x90, 0x10, 9, 1),
+	PIN_FIELD_BASE(39, 39, 2, 0xf0, 0x10, 18, 1),
+	PIN_FIELD_BASE(40, 40, 2, 0xf0, 0x10, 19, 1),
+	PIN_FIELD_BASE(41, 41, 2, 0xf0, 0x10, 12, 1),
+	PIN_FIELD_BASE(42, 42, 2, 0xf0, 0x10, 22, 1),
+	PIN_FIELD_BASE(43, 43, 2, 0xf0, 0x10, 23, 1),
+	PIN_FIELD_BASE(44, 44, 2, 0xf0, 0x10, 20, 1),
+	PIN_FIELD_BASE(45, 45, 2, 0xf0, 0x10, 21, 1),
+	PIN_FIELD_BASE(46, 46, 2, 0xf0, 0x10, 26, 1),
+	PIN_FIELD_BASE(47, 47, 2, 0xf0, 0x10, 27, 1),
+	PIN_FIELD_BASE(48, 48, 2, 0xf0, 0x10, 24, 1),
+	PIN_FIELD_BASE(49, 49, 2, 0xf0, 0x10, 25, 1),
+	PIN_FIELD_BASE(50, 50, 1, 0xc0, 0x10, 2, 1),
+	PIN_FIELD_BASE(51, 51, 1, 0xc0, 0x10, 3, 1),
+	PIN_FIELD_BASE(52, 52, 1, 0xc0, 0x10, 4, 1),
+	PIN_FIELD_BASE(53, 53, 1, 0xc0, 0x10, 5, 1),
+	PIN_FIELD_BASE(54, 54, 1, 0xc0, 0x10, 6, 1),
+	PIN_FIELD_BASE(55, 55, 1, 0xc0, 0x10, 7, 1),
+	PIN_FIELD_BASE(56, 56, 1, 0xc0, 0x10, 8, 1),
+	PIN_FIELD_BASE(57, 57, 1, 0xc0, 0x10, 9, 1),
+	PIN_FIELD_BASE(58, 58, 1, 0xc0, 0x10, 1, 1),
+	PIN_FIELD_BASE(59, 59, 1, 0xc0, 0x10, 0, 1),
+	PIN_FIELD_BASE(60, 60, 1, 0xc0, 0x10, 10, 1),
+	PIN_FIELD_BASE(61, 61, 1, 0xc0, 0x10, 11, 1),
+	PIN_FIELD_BASE(62, 62, 2, 0xf0, 0x10, 15, 1),
+	PIN_FIELD_BASE(63, 63, 2, 0xf0, 0x10, 14, 1),
+	PIN_FIELD_BASE(64, 64, 2, 0xf0, 0x10, 13, 1),
+	PIN_FIELD_BASE(65, 65, 2, 0xf0, 0x10, 16, 1),
+	PIN_FIELD_BASE(66, 66, 4, 0x90, 0x10, 2, 1),
+	PIN_FIELD_BASE(67, 67, 4, 0x90, 0x10, 3, 1),
+	PIN_FIELD_BASE(68, 68, 4, 0x90, 0x10, 4, 1),
+	PIN_FIELD_BASE(69, 69, 5, 0x80, 0x10, 1, 1),
+	PIN_FIELD_BASE(70, 70, 5, 0x80, 0x10, 0, 1),
+	PIN_FIELD_BASE(71, 71, 5, 0x80, 0x10, 16, 1),
+	PIN_FIELD_BASE(72, 72, 5, 0x80, 0x10, 14, 1),
+	PIN_FIELD_BASE(73, 73, 5, 0x80, 0x10, 15, 1),
+	PIN_FIELD_BASE(74, 74, 5, 0x80, 0x10, 4, 1),
+	PIN_FIELD_BASE(75, 75, 5, 0x80, 0x10, 6, 1),
+	PIN_FIELD_BASE(76, 76, 5, 0x80, 0x10, 7, 1),
+	PIN_FIELD_BASE(77, 77, 5, 0x80, 0x10, 8, 1),
+	PIN_FIELD_BASE(78, 78, 5, 0x80, 0x10, 2, 1),
+	PIN_FIELD_BASE(79, 79, 5, 0x80, 0x10, 3, 1),
+	PIN_FIELD_BASE(80, 80, 5, 0x80, 0x10, 9, 1),
+	PIN_FIELD_BASE(81, 81, 5, 0x80, 0x10, 10, 1),
+	PIN_FIELD_BASE(82, 82, 5, 0x80, 0x10, 11, 1),
+	PIN_FIELD_BASE(83, 83, 5, 0x80, 0x10, 12, 1),
+	PIN_FIELD_BASE(84, 84, 5, 0x80, 0x10, 13, 1),
+	PIN_FIELD_BASE(85, 85, 5, 0x80, 0x10, 5, 1),
+	PIN_FIELD_BASE(86, 86, 6, 0x70, 0x10, 1, 1),
+	PIN_FIELD_BASE(87, 87, 6, 0x70, 0x10, 0, 1),
+	PIN_FIELD_BASE(88, 88, 6, 0x70, 0x10, 14, 1),
+	PIN_FIELD_BASE(89, 89, 6, 0x70, 0x10, 12, 1),
+	PIN_FIELD_BASE(90, 90, 6, 0x70, 0x10, 13, 1),
+	PIN_FIELD_BASE(91, 91, 6, 0x70, 0x10, 4, 1),
+	PIN_FIELD_BASE(92, 92, 6, 0x70, 0x10, 5, 1),
+	PIN_FIELD_BASE(93, 93, 6, 0x70, 0x10, 6, 1),
+	PIN_FIELD_BASE(94, 94, 6, 0x70, 0x10, 7, 1),
+	PIN_FIELD_BASE(95, 95, 6, 0x70, 0x10, 2, 1),
+	PIN_FIELD_BASE(96, 96, 6, 0x70, 0x10, 3, 1),
+	PIN_FIELD_BASE(97, 97, 6, 0x70, 0x10, 8, 1),
+	PIN_FIELD_BASE(98, 98, 6, 0x70, 0x10, 9, 1),
+	PIN_FIELD_BASE(99, 99, 6, 0x70, 0x10, 10, 1),
+	PIN_FIELD_BASE(100, 100, 6, 0x70, 0x10, 11, 1),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_pu_range[] = {
+	PIN_FIELD_BASE(69, 69, 5, 0x50, 0x10, 1, 1),
+	PIN_FIELD_BASE(70, 70, 5, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(71, 71, 5, 0x50, 0x10, 16, 1),
+	PIN_FIELD_BASE(72, 72, 5, 0x50, 0x10, 14, 1),
+	PIN_FIELD_BASE(73, 73, 5, 0x50, 0x10, 15, 1),
+	PIN_FIELD_BASE(74, 74, 5, 0x50, 0x10, 4, 1),
+	PIN_FIELD_BASE(75, 75, 5, 0x50, 0x10, 6, 1),
+	PIN_FIELD_BASE(76, 76, 5, 0x50, 0x10, 7, 1),
+	PIN_FIELD_BASE(77, 77, 5, 0x50, 0x10, 8, 1),
+	PIN_FIELD_BASE(78, 78, 5, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(79, 79, 5, 0x50, 0x10, 3, 1),
+	PIN_FIELD_BASE(80, 80, 5, 0x50, 0x10, 9, 1),
+	PIN_FIELD_BASE(81, 81, 5, 0x50, 0x10, 10, 1),
+	PIN_FIELD_BASE(82, 82, 5, 0x50, 0x10, 11, 1),
+	PIN_FIELD_BASE(83, 83, 5, 0x50, 0x10, 12, 1),
+	PIN_FIELD_BASE(84, 84, 5, 0x50, 0x10, 13, 1),
+	PIN_FIELD_BASE(85, 85, 5, 0x50, 0x10, 5, 1),
+	PIN_FIELD_BASE(86, 86, 6, 0x50, 0x10, 1, 1),
+	PIN_FIELD_BASE(87, 87, 6, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(88, 88, 6, 0x50, 0x10, 14, 1),
+	PIN_FIELD_BASE(89, 89, 6, 0x50, 0x10, 12, 1),
+	PIN_FIELD_BASE(90, 90, 6, 0x50, 0x10, 13, 1),
+	PIN_FIELD_BASE(91, 91, 6, 0x50, 0x10, 4, 1),
+	PIN_FIELD_BASE(92, 92, 6, 0x50, 0x10, 5, 1),
+	PIN_FIELD_BASE(93, 93, 6, 0x50, 0x10, 6, 1),
+	PIN_FIELD_BASE(94, 94, 6, 0x50, 0x10, 7, 1),
+	PIN_FIELD_BASE(95, 95, 6, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(96, 96, 6, 0x50, 0x10, 3, 1),
+	PIN_FIELD_BASE(97, 97, 6, 0x50, 0x10, 8, 1),
+	PIN_FIELD_BASE(98, 98, 6, 0x50, 0x10, 9, 1),
+	PIN_FIELD_BASE(99, 99, 6, 0x50, 0x10, 10, 1),
+	PIN_FIELD_BASE(100, 100, 6, 0x50, 0x10, 11, 1),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_pd_range[] = {
+	PIN_FIELD_BASE(69, 69, 5, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(70, 70, 5, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(71, 71, 5, 0x40, 0x10, 16, 1),
+	PIN_FIELD_BASE(72, 72, 5, 0x40, 0x10, 14, 1),
+	PIN_FIELD_BASE(73, 73, 5, 0x40, 0x10, 15, 1),
+	PIN_FIELD_BASE(74, 74, 5, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(75, 75, 5, 0x40, 0x10, 6, 1),
+	PIN_FIELD_BASE(76, 76, 5, 0x40, 0x10, 7, 1),
+	PIN_FIELD_BASE(77, 77, 5, 0x40, 0x10, 8, 1),
+	PIN_FIELD_BASE(78, 78, 5, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(79, 79, 5, 0x40, 0x10, 3, 1),
+	PIN_FIELD_BASE(80, 80, 5, 0x40, 0x10, 9, 1),
+	PIN_FIELD_BASE(81, 81, 5, 0x40, 0x10, 10, 1),
+	PIN_FIELD_BASE(82, 82, 5, 0x40, 0x10, 11, 1),
+	PIN_FIELD_BASE(83, 83, 5, 0x40, 0x10, 12, 1),
+	PIN_FIELD_BASE(84, 84, 5, 0x40, 0x10, 13, 1),
+	PIN_FIELD_BASE(85, 85, 5, 0x40, 0x10, 5, 1),
+	PIN_FIELD_BASE(86, 86, 6, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(87, 87, 6, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(88, 88, 6, 0x40, 0x10, 14, 1),
+	PIN_FIELD_BASE(89, 89, 6, 0x40, 0x10, 12, 1),
+	PIN_FIELD_BASE(90, 90, 6, 0x40, 0x10, 13, 1),
+	PIN_FIELD_BASE(91, 91, 6, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(92, 92, 6, 0x40, 0x10, 5, 1),
+	PIN_FIELD_BASE(93, 93, 6, 0x40, 0x10, 6, 1),
+	PIN_FIELD_BASE(94, 94, 6, 0x40, 0x10, 7, 1),
+	PIN_FIELD_BASE(95, 95, 6, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(96, 96, 6, 0x40, 0x10, 3, 1),
+	PIN_FIELD_BASE(97, 97, 6, 0x40, 0x10, 8, 1),
+	PIN_FIELD_BASE(98, 98, 6, 0x40, 0x10, 9, 1),
+	PIN_FIELD_BASE(99, 99, 6, 0x40, 0x10, 10, 1),
+	PIN_FIELD_BASE(100, 100, 6, 0x40, 0x10, 11, 1),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_drv_range[] = {
+	PIN_FIELD_BASE(0, 0, 2, 0x10, 0x10, 21, 3),
+	PIN_FIELD_BASE(1, 1, 3, 0x10, 0x10, 0, 3),
+	PIN_FIELD_BASE(2, 2, 3, 0x10, 0x10, 3, 3),
+	PIN_FIELD_BASE(3, 3, 4, 0x00, 0x10, 0, 1),
+	PIN_FIELD_BASE(4, 4, 4, 0x00, 0x10, 1, 1),
+	PIN_FIELD_BASE(5, 5, 2, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(6, 6, 2, 0x00, 0x10, 21, 3),
+	PIN_FIELD_BASE(7, 7, 3, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(8, 8, 3, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(9, 9, 3, 0x00, 0x10, 6, 3),
+	PIN_FIELD_BASE(10, 10, 3, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(11, 11, 2, 0x00, 0x10, 24, 3),
+	PIN_FIELD_BASE(12, 12, 2, 0x00, 0x10, 27, 3),
+	PIN_FIELD_BASE(13, 13, 2, 0x10, 0x10, 0, 3),
+	PIN_FIELD_BASE(14, 14, 2, 0x10, 0x10, 3, 3),
+	PIN_FIELD_BASE(15, 15, 2, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(16, 16, 2, 0x00, 0x10, 6, 3),
+	PIN_FIELD_BASE(17, 17, 2, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(18, 18, 2, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(19, 19, 2, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(20, 20, 2, 0x00, 0x10, 18, 3),
+	PIN_FIELD_BASE(21, 21, 1, 0x10, 0x10, 6, 3),
+	PIN_FIELD_BASE(22, 22, 1, 0x10, 0x10, 9, 3),
+	PIN_FIELD_BASE(23, 23, 1, 0x10, 0x10, 12, 3),
+	PIN_FIELD_BASE(24, 24, 1, 0x10, 0x10, 24, 3),
+	PIN_FIELD_BASE(25, 25, 1, 0x10, 0x10, 21, 3),
+	PIN_FIELD_BASE(26, 26, 1, 0x10, 0x10, 15, 3),
+	PIN_FIELD_BASE(27, 27, 1, 0x10, 0x10, 18, 3),
+	PIN_FIELD_BASE(28, 28, 1, 0x10, 0x10, 27, 3),
+	PIN_FIELD_BASE(29, 29, 1, 0x20, 0x10, 0, 3),
+	PIN_FIELD_BASE(30, 30, 1, 0x20, 0x10, 9, 3),
+	PIN_FIELD_BASE(31, 31, 1, 0x20, 0x10, 6, 3),
+	PIN_FIELD_BASE(32, 32, 1, 0x20, 0x10, 3, 3),
+	PIN_FIELD_BASE(33, 33, 3, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(34, 34, 3, 0x00, 0x10, 24, 3),
+	PIN_FIELD_BASE(35, 35, 3, 0x00, 0x10, 21, 3),
+	PIN_FIELD_BASE(36, 36, 3, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(37, 37, 3, 0x00, 0x10, 18, 3),
+	PIN_FIELD_BASE(38, 38, 3, 0x00, 0x10, 27, 3),
+	PIN_FIELD_BASE(39, 39, 2, 0x10, 0x10, 27, 3),
+	PIN_FIELD_BASE(40, 40, 2, 0x20, 0x10, 0, 3),
+	PIN_FIELD_BASE(41, 41, 2, 0x10, 0x10, 6, 3),
+	PIN_FIELD_BASE(42, 42, 2, 0x20, 0x10, 9, 3),
+	PIN_FIELD_BASE(43, 43, 2, 0x20, 0x10, 12, 3),
+	PIN_FIELD_BASE(44, 44, 2, 0x20, 0x10, 3, 3),
+	PIN_FIELD_BASE(45, 45, 2, 0x20, 0x10, 6, 3),
+	PIN_FIELD_BASE(46, 46, 2, 0x20, 0x10, 21, 3),
+	PIN_FIELD_BASE(47, 47, 2, 0x20, 0x10, 24, 3),
+	PIN_FIELD_BASE(48, 48, 2, 0x20, 0x10, 15, 3),
+	PIN_FIELD_BASE(49, 49, 2, 0x20, 0x10, 18, 3),
+	PIN_FIELD_BASE(50, 50, 1, 0x00, 0x10, 6, 3),
+	PIN_FIELD_BASE(51, 51, 1, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(52, 52, 1, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(53, 53, 1, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(54, 54, 1, 0x00, 0x10, 18, 3),
+	PIN_FIELD_BASE(55, 55, 1, 0x00, 0x10, 21, 3),
+	PIN_FIELD_BASE(56, 56, 1, 0x00, 0x10, 24, 3),
+	PIN_FIELD_BASE(57, 57, 1, 0x00, 0x10, 27, 3),
+	PIN_FIELD_BASE(58, 58, 1, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(59, 59, 1, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(60, 60, 1, 0x10, 0x10, 0, 3),
+	PIN_FIELD_BASE(61, 61, 1, 0x10, 0x10, 3, 3),
+	PIN_FIELD_BASE(62, 62, 2, 0x10, 0x10, 15, 3),
+	PIN_FIELD_BASE(63, 63, 2, 0x10, 0x10, 12, 3),
+	PIN_FIELD_BASE(64, 64, 2, 0x10, 0x10, 9, 3),
+	PIN_FIELD_BASE(65, 65, 2, 0x10, 0x10, 18, 3),
+	PIN_FIELD_BASE(66, 66, 4, 0x00, 0x10, 2, 3),
+	PIN_FIELD_BASE(67, 67, 4, 0x00, 0x10, 5, 3),
+	PIN_FIELD_BASE(68, 68, 4, 0x00, 0x10, 8, 3),
+	PIN_FIELD_BASE(69, 69, 5, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(70, 70, 5, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(71, 71, 5, 0x10, 0x10, 18, 3),
+	PIN_FIELD_BASE(72, 72, 5, 0x10, 0x10, 12, 3),
+	PIN_FIELD_BASE(73, 73, 5, 0x10, 0x10, 15, 3),
+	PIN_FIELD_BASE(74, 74, 5, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(75, 75, 5, 0x00, 0x10, 18, 3),
+	PIN_FIELD_BASE(76, 76, 5, 0x00, 0x10, 21, 3),
+	PIN_FIELD_BASE(77, 77, 5, 0x00, 0x10, 24, 3),
+	PIN_FIELD_BASE(78, 78, 5, 0x00, 0x10, 6, 3),
+	PIN_FIELD_BASE(79, 79, 5, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(80, 80, 5, 0x00, 0x10, 27, 3),
+	PIN_FIELD_BASE(81, 81, 5, 0x10, 0x10, 0, 3),
+	PIN_FIELD_BASE(82, 82, 5, 0x10, 0x10, 3, 3),
+	PIN_FIELD_BASE(83, 83, 5, 0x10, 0x10, 6, 3),
+	PIN_FIELD_BASE(84, 84, 5, 0x10, 0x10, 9, 3),
+	PIN_FIELD_BASE(85, 85, 5, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(86, 86, 6, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(87, 87, 6, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(88, 88, 6, 0x10, 0x10, 12, 3),
+	PIN_FIELD_BASE(89, 89, 6, 0x10, 0x10, 6, 3),
+	PIN_FIELD_BASE(90, 90, 6, 0x10, 0x10, 9, 3),
+	PIN_FIELD_BASE(91, 91, 6, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(92, 92, 6, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(93, 93, 6, 0x00, 0x10, 18, 3),
+	PIN_FIELD_BASE(94, 94, 6, 0x00, 0x10, 21, 3),
+	PIN_FIELD_BASE(95, 95, 6, 0x00, 0x10, 6, 3),
+	PIN_FIELD_BASE(96, 96, 6, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(97, 97, 6, 0x00, 0x10, 24, 3),
+	PIN_FIELD_BASE(98, 98, 6, 0x00, 0x10, 27, 3),
+	PIN_FIELD_BASE(99, 99, 6, 0x10, 0x10, 2, 3),
+	PIN_FIELD_BASE(100, 100, 6, 0x10, 0x10, 5, 3),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_pupd_range[] = {
+	PIN_FIELD_BASE(0, 0, 2, 0x60, 0x10, 17, 1),
+	PIN_FIELD_BASE(1, 1, 3, 0x30, 0x10, 10, 1),
+	PIN_FIELD_BASE(2, 2, 3, 0x30, 0x10, 11, 1),
+	PIN_FIELD_BASE(3, 3, 4, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(4, 4, 4, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(5, 5, 2, 0x60, 0x10, 0, 1),
+	PIN_FIELD_BASE(6, 6, 2, 0x60, 0x10, 1, 1),
+	PIN_FIELD_BASE(7, 7, 3, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(8, 8, 3, 0x30, 0x10, 1, 1),
+	PIN_FIELD_BASE(9, 9, 3, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(10, 10, 3, 0x30, 0x10, 3, 1),
+	PIN_FIELD_BASE(11, 11, 2, 0x60, 0x10, 8, 1),
+	PIN_FIELD_BASE(12, 12, 2, 0x60, 0x10, 9, 1),
+	PIN_FIELD_BASE(13, 13, 2, 0x60, 0x10, 10, 1),
+	PIN_FIELD_BASE(14, 14, 2, 0x60, 0x10, 11, 1),
+	PIN_FIELD_BASE(15, 15, 2, 0x60, 0x10, 2, 1),
+	PIN_FIELD_BASE(16, 16, 2, 0x60, 0x10, 3, 1),
+	PIN_FIELD_BASE(17, 17, 2, 0x60, 0x10, 4, 1),
+	PIN_FIELD_BASE(18, 18, 2, 0x60, 0x10, 5, 1),
+	PIN_FIELD_BASE(19, 19, 2, 0x60, 0x10, 6, 1),
+	PIN_FIELD_BASE(20, 20, 2, 0x60, 0x10, 7, 1),
+	PIN_FIELD_BASE(21, 21, 1, 0x40, 0x10, 12, 1),
+	PIN_FIELD_BASE(22, 22, 1, 0x40, 0x10, 13, 1),
+	PIN_FIELD_BASE(23, 23, 1, 0x40, 0x10, 14, 1),
+	PIN_FIELD_BASE(24, 24, 1, 0x40, 0x10, 18, 1),
+	PIN_FIELD_BASE(25, 25, 1, 0x40, 0x10, 17, 1),
+	PIN_FIELD_BASE(26, 26, 1, 0x40, 0x10, 15, 1),
+	PIN_FIELD_BASE(27, 27, 1, 0x40, 0x10, 16, 1),
+	PIN_FIELD_BASE(28, 28, 1, 0x40, 0x10, 19, 1),
+	PIN_FIELD_BASE(29, 29, 1, 0x40, 0x10, 20, 1),
+	PIN_FIELD_BASE(30, 30, 1, 0x40, 0x10, 23, 1),
+	PIN_FIELD_BASE(31, 31, 1, 0x40, 0x10, 22, 1),
+	PIN_FIELD_BASE(32, 32, 1, 0x40, 0x10, 21, 1),
+	PIN_FIELD_BASE(33, 33, 3, 0x30, 0x10, 4, 1),
+	PIN_FIELD_BASE(34, 34, 3, 0x30, 0x10, 8, 1),
+	PIN_FIELD_BASE(35, 35, 3, 0x30, 0x10, 7, 1),
+	PIN_FIELD_BASE(36, 36, 3, 0x30, 0x10, 5, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0x30, 0x10, 6, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x30, 0x10, 9, 1),
+	PIN_FIELD_BASE(39, 39, 2, 0x60, 0x10, 18, 1),
+	PIN_FIELD_BASE(40, 40, 2, 0x60, 0x10, 19, 1),
+	PIN_FIELD_BASE(41, 41, 2, 0x60, 0x10, 12, 1),
+	PIN_FIELD_BASE(42, 42, 2, 0x60, 0x10, 23, 1),
+	PIN_FIELD_BASE(43, 43, 2, 0x60, 0x10, 24, 1),
+	PIN_FIELD_BASE(44, 44, 2, 0x60, 0x10, 21, 1),
+	PIN_FIELD_BASE(45, 45, 2, 0x60, 0x10, 22, 1),
+	PIN_FIELD_BASE(46, 46, 2, 0x60, 0x10, 27, 1),
+	PIN_FIELD_BASE(47, 47, 2, 0x60, 0x10, 28, 1),
+	PIN_FIELD_BASE(48, 48, 2, 0x60, 0x10, 25, 1),
+	PIN_FIELD_BASE(49, 49, 2, 0x60, 0x10, 26, 1),
+	PIN_FIELD_BASE(50, 50, 1, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(51, 51, 1, 0x40, 0x10, 3, 1),
+	PIN_FIELD_BASE(52, 52, 1, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(53, 53, 1, 0x40, 0x10, 5, 1),
+	PIN_FIELD_BASE(54, 54, 1, 0x40, 0x10, 6, 1),
+	PIN_FIELD_BASE(55, 55, 1, 0x40, 0x10, 7, 1),
+	PIN_FIELD_BASE(56, 56, 1, 0x40, 0x10, 8, 1),
+	PIN_FIELD_BASE(57, 57, 1, 0x40, 0x10, 9, 1),
+	PIN_FIELD_BASE(58, 58, 1, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(59, 59, 1, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(60, 60, 1, 0x40, 0x10, 10, 1),
+	PIN_FIELD_BASE(61, 61, 1, 0x40, 0x10, 11, 1),
+	PIN_FIELD_BASE(62, 62, 2, 0x60, 0x10, 15, 1),
+	PIN_FIELD_BASE(63, 63, 2, 0x60, 0x10, 14, 1),
+	PIN_FIELD_BASE(64, 64, 2, 0x60, 0x10, 13, 1),
+	PIN_FIELD_BASE(65, 65, 2, 0x60, 0x10, 16, 1),
+	PIN_FIELD_BASE(66, 66, 4, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(67, 67, 4, 0x40, 0x10, 3, 1),
+	PIN_FIELD_BASE(68, 68, 4, 0x40, 0x10, 4, 1),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_r0_range[] = {
+	PIN_FIELD_BASE(0, 0, 2, 0x70, 0x10, 17, 1),
+	PIN_FIELD_BASE(1, 1, 3, 0x40, 0x10, 10, 1),
+	PIN_FIELD_BASE(2, 2, 3, 0x40, 0x10, 11, 1),
+	PIN_FIELD_BASE(3, 3, 4, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(4, 4, 4, 0x50, 0x10, 1, 1),
+	PIN_FIELD_BASE(5, 5, 2, 0x70, 0x10, 0, 1),
+	PIN_FIELD_BASE(6, 6, 2, 0x70, 0x10, 1, 1),
+	PIN_FIELD_BASE(7, 7, 3, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(8, 8, 3, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(9, 9, 3, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(10, 10, 3, 0x40, 0x10, 3, 1),
+	PIN_FIELD_BASE(11, 11, 2, 0x70, 0x10, 8, 1),
+	PIN_FIELD_BASE(12, 12, 2, 0x70, 0x10, 9, 1),
+	PIN_FIELD_BASE(13, 13, 2, 0x70, 0x10, 10, 1),
+	PIN_FIELD_BASE(14, 14, 2, 0x70, 0x10, 11, 1),
+	PIN_FIELD_BASE(15, 15, 2, 0x70, 0x10, 2, 1),
+	PIN_FIELD_BASE(16, 16, 2, 0x70, 0x10, 3, 1),
+	PIN_FIELD_BASE(17, 17, 2, 0x70, 0x10, 4, 1),
+	PIN_FIELD_BASE(18, 18, 2, 0x70, 0x10, 5, 1),
+	PIN_FIELD_BASE(19, 19, 2, 0x70, 0x10, 6, 1),
+	PIN_FIELD_BASE(20, 20, 2, 0x70, 0x10, 7, 1),
+	PIN_FIELD_BASE(21, 21, 1, 0x50, 0x10, 12, 1),
+	PIN_FIELD_BASE(22, 22, 1, 0x50, 0x10, 13, 1),
+	PIN_FIELD_BASE(23, 23, 1, 0x50, 0x10, 14, 1),
+	PIN_FIELD_BASE(24, 24, 1, 0x50, 0x10, 18, 1),
+	PIN_FIELD_BASE(25, 25, 1, 0x50, 0x10, 17, 1),
+	PIN_FIELD_BASE(26, 26, 1, 0x50, 0x10, 15, 1),
+	PIN_FIELD_BASE(27, 27, 1, 0x50, 0x10, 16, 1),
+	PIN_FIELD_BASE(28, 28, 1, 0x50, 0x10, 19, 1),
+	PIN_FIELD_BASE(29, 29, 1, 0x50, 0x10, 20, 1),
+	PIN_FIELD_BASE(30, 30, 1, 0x50, 0x10, 23, 1),
+	PIN_FIELD_BASE(31, 31, 1, 0x50, 0x10, 22, 1),
+	PIN_FIELD_BASE(32, 32, 1, 0x50, 0x10, 21, 1),
+	PIN_FIELD_BASE(33, 33, 3, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(34, 34, 3, 0x40, 0x10, 8, 1),
+	PIN_FIELD_BASE(35, 35, 3, 0x40, 0x10, 7, 1),
+	PIN_FIELD_BASE(36, 36, 3, 0x40, 0x10, 5, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0x40, 0x10, 6, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x40, 0x10, 9, 1),
+	PIN_FIELD_BASE(39, 39, 2, 0x70, 0x10, 18, 1),
+	PIN_FIELD_BASE(40, 40, 2, 0x70, 0x10, 19, 1),
+	PIN_FIELD_BASE(41, 41, 2, 0x70, 0x10, 12, 1),
+	PIN_FIELD_BASE(42, 42, 2, 0x70, 0x10, 23, 1),
+	PIN_FIELD_BASE(43, 43, 2, 0x70, 0x10, 24, 1),
+	PIN_FIELD_BASE(44, 44, 2, 0x70, 0x10, 21, 1),
+	PIN_FIELD_BASE(45, 45, 2, 0x70, 0x10, 22, 1),
+	PIN_FIELD_BASE(46, 46, 2, 0x70, 0x10, 27, 1),
+	PIN_FIELD_BASE(47, 47, 2, 0x70, 0x10, 28, 1),
+	PIN_FIELD_BASE(48, 48, 2, 0x70, 0x10, 25, 1),
+	PIN_FIELD_BASE(49, 49, 2, 0x70, 0x10, 26, 1),
+	PIN_FIELD_BASE(50, 50, 1, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(51, 51, 1, 0x50, 0x10, 3, 1),
+	PIN_FIELD_BASE(52, 52, 1, 0x50, 0x10, 4, 1),
+	PIN_FIELD_BASE(53, 53, 1, 0x50, 0x10, 5, 1),
+	PIN_FIELD_BASE(54, 54, 1, 0x50, 0x10, 6, 1),
+	PIN_FIELD_BASE(55, 55, 1, 0x50, 0x10, 7, 1),
+	PIN_FIELD_BASE(56, 56, 1, 0x50, 0x10, 8, 1),
+	PIN_FIELD_BASE(57, 57, 1, 0x50, 0x10, 9, 1),
+	PIN_FIELD_BASE(58, 58, 1, 0x50, 0x10, 1, 1),
+	PIN_FIELD_BASE(59, 59, 1, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(60, 60, 1, 0x50, 0x10, 10, 1),
+	PIN_FIELD_BASE(61, 61, 1, 0x50, 0x10, 11, 1),
+	PIN_FIELD_BASE(62, 62, 2, 0x70, 0x10, 15, 1),
+	PIN_FIELD_BASE(63, 63, 2, 0x70, 0x10, 14, 1),
+	PIN_FIELD_BASE(64, 64, 2, 0x70, 0x10, 13, 1),
+	PIN_FIELD_BASE(65, 65, 2, 0x70, 0x10, 16, 1),
+	PIN_FIELD_BASE(66, 66, 4, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(67, 67, 4, 0x50, 0x10, 3, 1),
+	PIN_FIELD_BASE(68, 68, 4, 0x50, 0x10, 4, 1),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_r1_range[] = {
+	PIN_FIELD_BASE(0, 0, 2, 0x80, 0x10, 17, 1),
+	PIN_FIELD_BASE(1, 1, 3, 0x50, 0x10, 10, 1),
+	PIN_FIELD_BASE(2, 2, 3, 0x50, 0x10, 11, 1),
+	PIN_FIELD_BASE(3, 3, 4, 0x60, 0x10, 0, 1),
+	PIN_FIELD_BASE(4, 4, 4, 0x60, 0x10, 1, 1),
+	PIN_FIELD_BASE(5, 5, 2, 0x80, 0x10, 0, 1),
+	PIN_FIELD_BASE(6, 6, 2, 0x80, 0x10, 1, 1),
+	PIN_FIELD_BASE(7, 7, 3, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(8, 8, 3, 0x50, 0x10, 1, 1),
+	PIN_FIELD_BASE(9, 9, 3, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(10, 10, 3, 0x50, 0x10, 3, 1),
+	PIN_FIELD_BASE(11, 11, 2, 0x80, 0x10, 8, 1),
+	PIN_FIELD_BASE(12, 12, 2, 0x80, 0x10, 9, 1),
+	PIN_FIELD_BASE(13, 13, 2, 0x80, 0x10, 10, 1),
+	PIN_FIELD_BASE(14, 14, 2, 0x80, 0x10, 11, 1),
+	PIN_FIELD_BASE(15, 15, 2, 0x80, 0x10, 2, 1),
+	PIN_FIELD_BASE(16, 16, 2, 0x80, 0x10, 3, 1),
+	PIN_FIELD_BASE(17, 17, 2, 0x80, 0x10, 4, 1),
+	PIN_FIELD_BASE(18, 18, 2, 0x80, 0x10, 5, 1),
+	PIN_FIELD_BASE(19, 19, 2, 0x80, 0x10, 6, 1),
+	PIN_FIELD_BASE(20, 20, 2, 0x80, 0x10, 7, 1),
+	PIN_FIELD_BASE(21, 21, 1, 0x60, 0x10, 12, 1),
+	PIN_FIELD_BASE(22, 22, 1, 0x60, 0x10, 13, 1),
+	PIN_FIELD_BASE(23, 23, 1, 0x60, 0x10, 14, 1),
+	PIN_FIELD_BASE(24, 24, 1, 0x60, 0x10, 18, 1),
+	PIN_FIELD_BASE(25, 25, 1, 0x60, 0x10, 17, 1),
+	PIN_FIELD_BASE(26, 26, 1, 0x60, 0x10, 15, 1),
+	PIN_FIELD_BASE(27, 27, 1, 0x60, 0x10, 16, 1),
+	PIN_FIELD_BASE(28, 28, 1, 0x60, 0x10, 19, 1),
+	PIN_FIELD_BASE(29, 29, 1, 0x60, 0x10, 20, 1),
+	PIN_FIELD_BASE(30, 30, 1, 0x60, 0x10, 23, 1),
+	PIN_FIELD_BASE(31, 31, 1, 0x60, 0x10, 22, 1),
+	PIN_FIELD_BASE(32, 32, 1, 0x60, 0x10, 21, 1),
+	PIN_FIELD_BASE(33, 33, 3, 0x50, 0x10, 4, 1),
+	PIN_FIELD_BASE(34, 34, 3, 0x50, 0x10, 8, 1),
+	PIN_FIELD_BASE(35, 35, 3, 0x50, 0x10, 7, 1),
+	PIN_FIELD_BASE(36, 36, 3, 0x50, 0x10, 5, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0x50, 0x10, 6, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x50, 0x10, 9, 1),
+	PIN_FIELD_BASE(39, 39, 2, 0x80, 0x10, 18, 1),
+	PIN_FIELD_BASE(40, 40, 2, 0x80, 0x10, 19, 1),
+	PIN_FIELD_BASE(41, 41, 2, 0x80, 0x10, 12, 1),
+	PIN_FIELD_BASE(42, 42, 2, 0x80, 0x10, 23, 1),
+	PIN_FIELD_BASE(43, 43, 2, 0x80, 0x10, 24, 1),
+	PIN_FIELD_BASE(44, 44, 2, 0x80, 0x10, 21, 1),
+	PIN_FIELD_BASE(45, 45, 2, 0x80, 0x10, 22, 1),
+	PIN_FIELD_BASE(46, 46, 2, 0x80, 0x10, 27, 1),
+	PIN_FIELD_BASE(47, 47, 2, 0x80, 0x10, 28, 1),
+	PIN_FIELD_BASE(48, 48, 2, 0x80, 0x10, 25, 1),
+	PIN_FIELD_BASE(49, 49, 2, 0x80, 0x10, 26, 1),
+	PIN_FIELD_BASE(50, 50, 1, 0x60, 0x10, 2, 1),
+	PIN_FIELD_BASE(51, 51, 1, 0x60, 0x10, 3, 1),
+	PIN_FIELD_BASE(52, 52, 1, 0x60, 0x10, 4, 1),
+	PIN_FIELD_BASE(53, 53, 1, 0x60, 0x10, 5, 1),
+	PIN_FIELD_BASE(54, 54, 1, 0x60, 0x10, 6, 1),
+	PIN_FIELD_BASE(55, 55, 1, 0x60, 0x10, 7, 1),
+	PIN_FIELD_BASE(56, 56, 1, 0x60, 0x10, 8, 1),
+	PIN_FIELD_BASE(57, 57, 1, 0x60, 0x10, 9, 1),
+	PIN_FIELD_BASE(58, 58, 1, 0x60, 0x10, 1, 1),
+	PIN_FIELD_BASE(59, 59, 1, 0x60, 0x10, 0, 1),
+	PIN_FIELD_BASE(60, 60, 1, 0x60, 0x10, 10, 1),
+	PIN_FIELD_BASE(61, 61, 1, 0x60, 0x10, 11, 1),
+	PIN_FIELD_BASE(62, 62, 2, 0x80, 0x10, 15, 1),
+	PIN_FIELD_BASE(63, 63, 2, 0x80, 0x10, 14, 1),
+	PIN_FIELD_BASE(64, 64, 2, 0x80, 0x10, 13, 1),
+	PIN_FIELD_BASE(65, 65, 2, 0x80, 0x10, 16, 1),
+	PIN_FIELD_BASE(66, 66, 4, 0x60, 0x10, 2, 1),
+	PIN_FIELD_BASE(67, 67, 4, 0x60, 0x10, 3, 1),
+	PIN_FIELD_BASE(68, 68, 4, 0x60, 0x10, 4, 1),
+};
+
+static const struct mtk_pin_reg_calc mt7986_reg_cals[] = {
+	[PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7986_pin_mode_range),
+	[PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7986_pin_dir_range),
+	[PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7986_pin_di_range),
+	[PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7986_pin_do_range),
+	[PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7986_pin_smt_range),
+	[PINCTRL_PIN_REG_IES] = MTK_RANGE(mt7986_pin_ies_range),
+	[PINCTRL_PIN_REG_PU] = MTK_RANGE(mt7986_pin_pu_range),
+	[PINCTRL_PIN_REG_PD] = MTK_RANGE(mt7986_pin_pd_range),
+	[PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7986_pin_drv_range),
+	[PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt7986_pin_pupd_range),
+	[PINCTRL_PIN_REG_R0] = MTK_RANGE(mt7986_pin_r0_range),
+	[PINCTRL_PIN_REG_R1] = MTK_RANGE(mt7986_pin_r1_range),
+};
+
+static const struct mtk_pin_desc mt7986_pins[] = {
+	MT7986_PIN(0, "SYS_WATCHDOG"),
+	MT7986_PIN(1, "WF2G_LED"),
+	MT7986_PIN(2, "WF5G_LED"),
+	MT7986_PIN(3, "I2C_SCL"),
+	MT7986_PIN(4, "I2C_SDA"),
+	MT7986_PIN(5, "GPIO_0"),
+	MT7986_PIN(6, "GPIO_1"),
+	MT7986_PIN(7, "GPIO_2"),
+	MT7986_PIN(8, "GPIO_3"),
+	MT7986_PIN(9, "GPIO_4"),
+	MT7986_PIN(10, "GPIO_5"),
+	MT7986_PIN(11, "GPIO_6"),
+	MT7986_PIN(12, "GPIO_7"),
+	MT7986_PIN(13, "GPIO_8"),
+	MT7986_PIN(14, "GPIO_9"),
+	MT7986_PIN(15, "GPIO_10"),
+	MT7986_PIN(16, "GPIO_11"),
+	MT7986_PIN(17, "GPIO_12"),
+	MT7986_PIN(18, "GPIO_13"),
+	MT7986_PIN(19, "GPIO_14"),
+	MT7986_PIN(20, "GPIO_15"),
+	MT7986_PIN(21, "PWM0"),
+	MT7986_PIN(22, "PWM1"),
+	MT7986_PIN(23, "SPI0_CLK"),
+	MT7986_PIN(24, "SPI0_MOSI"),
+	MT7986_PIN(25, "SPI0_MISO"),
+	MT7986_PIN(26, "SPI0_CS"),
+	MT7986_PIN(27, "SPI0_HOLD"),
+	MT7986_PIN(28, "SPI0_WP"),
+	MT7986_PIN(29, "SPI1_CLK"),
+	MT7986_PIN(30, "SPI1_MOSI"),
+	MT7986_PIN(31, "SPI1_MISO"),
+	MT7986_PIN(32, "SPI1_CS"),
+	MT7986_PIN(33, "SPI2_CLK"),
+	MT7986_PIN(34, "SPI2_MOSI"),
+	MT7986_PIN(35, "SPI2_MISO"),
+	MT7986_PIN(36, "SPI2_CS"),
+	MT7986_PIN(37, "SPI2_HOLD"),
+	MT7986_PIN(38, "SPI2_WP"),
+	MT7986_PIN(39, "UART0_RXD"),
+	MT7986_PIN(40, "UART0_TXD"),
+	MT7986_PIN(41, "PCIE_PERESET_N"),
+	MT7986_PIN(42, "UART1_RXD"),
+	MT7986_PIN(43, "UART1_TXD"),
+	MT7986_PIN(44, "UART1_CTS"),
+	MT7986_PIN(45, "UART1_RTS"),
+	MT7986_PIN(46, "UART2_RXD"),
+	MT7986_PIN(47, "UART2_TXD"),
+	MT7986_PIN(48, "UART2_CTS"),
+	MT7986_PIN(49, "UART2_RTS"),
+	MT7986_PIN(50, "EMMC_DATA_0"),
+	MT7986_PIN(51, "EMMC_DATA_1"),
+	MT7986_PIN(52, "EMMC_DATA_2"),
+	MT7986_PIN(53, "EMMC_DATA_3"),
+	MT7986_PIN(54, "EMMC_DATA_4"),
+	MT7986_PIN(55, "EMMC_DATA_5"),
+	MT7986_PIN(56, "EMMC_DATA_6"),
+	MT7986_PIN(57, "EMMC_DATA_7"),
+	MT7986_PIN(58, "EMMC_CMD"),
+	MT7986_PIN(59, "EMMC_CK"),
+	MT7986_PIN(60, "EMMC_DSL"),
+	MT7986_PIN(61, "EMMC_RSTB"),
+	MT7986_PIN(62, "PCM_DTX"),
+	MT7986_PIN(63, "PCM_DRX"),
+	MT7986_PIN(64, "PCM_CLK"),
+	MT7986_PIN(65, "PCM_FS"),
+	MT7986_PIN(66, "MT7531_INT"),
+	MT7986_PIN(67, "SMI_MDC"),
+	MT7986_PIN(68, "SMI_MDIO"),
+	MT7986_PIN(69, "WF0_DIG_RESETB"),
+	MT7986_PIN(70, "WF0_CBA_RESETB"),
+	MT7986_PIN(71, "WF0_XO_REQ"),
+	MT7986_PIN(72, "WF0_TOP_CLK"),
+	MT7986_PIN(73, "WF0_TOP_DATA"),
+	MT7986_PIN(74, "WF0_HB1"),
+	MT7986_PIN(75, "WF0_HB2"),
+	MT7986_PIN(76, "WF0_HB3"),
+	MT7986_PIN(77, "WF0_HB4"),
+	MT7986_PIN(78, "WF0_HB0"),
+	MT7986_PIN(79, "WF0_HB0_B"),
+	MT7986_PIN(80, "WF0_HB5"),
+	MT7986_PIN(81, "WF0_HB6"),
+	MT7986_PIN(82, "WF0_HB7"),
+	MT7986_PIN(83, "WF0_HB8"),
+	MT7986_PIN(84, "WF0_HB9"),
+	MT7986_PIN(85, "WF0_HB10"),
+	MT7986_PIN(86, "WF1_DIG_RESETB"),
+	MT7986_PIN(87, "WF1_CBA_RESETB"),
+	MT7986_PIN(88, "WF1_XO_REQ"),
+	MT7986_PIN(89, "WF1_TOP_CLK"),
+	MT7986_PIN(90, "WF1_TOP_DATA"),
+	MT7986_PIN(91, "WF1_HB1"),
+	MT7986_PIN(92, "WF1_HB2"),
+	MT7986_PIN(93, "WF1_HB3"),
+	MT7986_PIN(94, "WF1_HB4"),
+	MT7986_PIN(95, "WF1_HB0"),
+	MT7986_PIN(96, "WF1_HB0_B"),
+	MT7986_PIN(97, "WF1_HB5"),
+	MT7986_PIN(98, "WF1_HB6"),
+	MT7986_PIN(99, "WF1_HB7"),
+	MT7986_PIN(100, "WF1_HB8"),
+};
+
+/* List all groups consisting of these pins dedicated to the enablement of
+ * certain hardware block and the corresponding mode for all of the pins.
+ * The hardware probably has multiple combinations of these pinouts.
+ */
+
+/* SYS_WATCHDOG */
+static int mt7986_watchdog_pins[] = { 0, };
+static int mt7986_watchdog_funcs[] = { 1, };
+
+/* WF2G_LED(1), WF5G_LED */
+static int mt7986_wifi_led_pins[] = { 1, 2, };
+static int mt7986_wifi_led_funcs[] = { 1, 1, };
+
+/* I2C */
+static int mt7986_i2c_pins[] = { 3, 4, };
+static int mt7986_i2c_funcs[] = { 1, 1, };
+
+/* UART1 */
+static int mt7986_uart1_0_pins[] = { 7, 8, 9, 10, };
+static int mt7986_uart1_0_funcs[] = { 3, 3, 3, 3, };
+
+/* JTAG */
+static int mt7986_jtag_pins[] = { 11, 12, 13, 14, 15, };
+static int mt7986_jtag_funcs[] = { 1, 1, 1, 1, 1, };
+
+/* SPI1 */
+static int mt7986_spi1_0_pins[] = { 11, 12, 13, 14, };
+static int mt7986_spi1_0_funcs[] = { 3, 3, 3, 3, };
+
+/* PWM */
+static int mt7986_pwm1_1_pins[] = { 20, };
+static int mt7986_pwm1_1_funcs[] = { 2, };
+
+/* PWM */
+static int mt7986_pwm0_pins[] = { 21, };
+static int mt7986_pwm0_funcs[] = { 1, };
+
+/* PWM */
+static int mt7986_pwm1_0_pins[] = { 22, };
+static int mt7986_pwm1_0_funcs[] = { 1, };
+
+/* EMMC */
+static int mt7986_emmc_45_pins[] = { 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, };
+static int mt7986_emmc_45_funcs[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, };
+
+/* SNFI */
+static int mt7986_snfi_pins[] = { 23, 24, 25, 26, 27, 28, };
+static int mt7986_snfi_funcs[] = { 1, 1, 1, 1, 1, 1, };
+
+/* SPI1 */
+static int mt7986_spi1_1_pins[] = { 23, 24, 25, 26, };
+static int mt7986_spi1_1_funcs[] = { 3, 3, 3, 3, };
+
+/* UART1 */
+static int mt7986_uart1_1_pins[] = { 23, 24, 25, 26, };
+static int mt7986_uart1_1_funcs[] = { 4, 4, 4, 4, };
+
+/* SPI1 */
+static int mt7986_spi1_2_pins[] = { 29, 30, 31, 32, };
+static int mt7986_spi1_2_funcs[] = { 1, 1, 1, 1, };
+
+/* UART1 */
+static int mt7986_uart1_2_pins[] = { 29, 30, 31, 32, };
+static int mt7986_uart1_2_funcs[] = { 3, 3, 3, 3, };
+
+/* UART2 */
+static int mt7986_uart2_0_pins[] = { 29, 30, 31, 32, };
+static int mt7986_uart2_0_funcs[] = { 4, 4, 4, 4, };
+
+/* SPI0 */
+static int mt7986_spi0_pins[] = { 33, 34, 35, 36, };
+static int mt7986_spi0_funcs[] = { 1, 1, 1, 1, };
+
+/* SPI0 */
+static int mt7986_spi0_wp_hold_pins[] = { 37, 38, };
+static int mt7986_spi0_wp_hold_funcs[] = { 1, 1, };
+
+/* UART2 */
+static int mt7986_uart2_1_pins[] = { 33, 34, 35, 36, };
+static int mt7986_uart2_1_funcs[] = { 3, 3, 3, 3, };
+
+/* UART1 */
+static int mt7986_uart1_3_rx_tx_pins[] = { 35, 36, };
+static int mt7986_uart1_3_rx_tx_funcs[] = { 2, 2, };
+
+/* UART1 */
+static int mt7986_uart1_3_cts_rts_pins[] = { 37, 38, };
+static int mt7986_uart1_3_cts_rts_funcs[] = { 2, 2, };
+
+/* SPI1 */
+static int mt7986_spi1_3_pins[] = { 33, 34, 35, 36, };
+static int mt7986_spi1_3_funcs[] = { 4, 4, 4, 4, };
+
+/* UART0 */
+static int mt7986_uart0_pins[] = { 39, 40, };
+static int mt7986_uart0_funcs[] = { 1, 1, };
+
+/* PCIE_PERESET_N */
+static int mt7986_pcie_reset_pins[] = { 41, };
+static int mt7986_pcie_reset_funcs[] = { 1, };
+
+/* UART1 */
+static int mt7986_uart1_pins[] = { 42, 43, 44, 45, };
+static int mt7986_uart1_funcs[] = { 1, 1, 1, 1, };
+
+/* UART1 */
+static int mt7986_uart2_pins[] = { 46, 47, 48, 49, };
+static int mt7986_uart2_funcs[] = { 1, 1, 1, 1, };
+
+/* EMMC */
+static int mt7986_emmc_51_pins[] = { 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, };
+static int mt7986_emmc_51_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, };
+
+/* PCM */
+static int mt7986_pcm_pins[] = { 62, 63, 64, 65, };
+static int mt7986_pcm_funcs[] = { 1, 1, 1, 1, };
+
+/* MT7531_INT */
+static int mt7986_switch_int_pins[] = { 66, };
+static int mt7986_switch_int_funcs[] = { 1, };
+
+/* MDC_MDIO */
+static int mt7986_mdc_mdio_pins[] = { 67, 68, };
+static int mt7986_mdc_mdio_funcs[] = { 1, 1, };
+
+/* WF0_MODE1 */
+static int mt7986_wf0_mode1_pins[] = { 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85 };
+static int mt7986_wf0_mode1_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+
+static int mt7986_wf_2g_pins[] = {74, 75, 76, 77, 78, 79, 80, 81, 82, 83, };
+static int mt7986_wf_2g_funcs[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, };
+
+static int mt7986_wf_5g_pins[] = {91, 92, 93, 94, 95, 96, 97, 98, 99, 100, };
+static int mt7986_wf_5g_funcs[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, };
+
+static int mt7986_wf_dbdc_pins[] = {
+	74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, };
+static int mt7986_wf_dbdc_funcs[] = {
+	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, };
+
+/* WF0_HB */
+static int mt7986_wf0_hb_pins[] = { 74, 75, 76, 77, 78 };
+static int mt7986_wf0_hb_funcs[] = { 2, 2, 2, 2, 2 };
+
+/* WF0_MODE3 */
+static int mt7986_wf0_mode3_pins[] = { 74, 75, 76, 77, 78, 80 };
+static int mt7986_wf0_mode3_funcs[] = { 3, 3, 3, 3, 3, 3 };
+
+/* WF1_HB */
+static int mt7986_wf1_hb_pins[] = { 79, 80, 81, 82, 83, 84, 85 };
+static int mt7986_wf1_hb_funcs[] = { 2, 2, 2, 2, 2, 2, 2 };
+
+/* WF1_MODE1 */
+static int mt7986_wf1_mode1_pins[] = { 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100 };
+static int mt7986_wf1_mode1_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+
+/* WF1_MODE2 */
+static int mt7986_wf1_mode2_pins[] = { 91, 92, 93, 94, 95, 97 };
+static int mt7986_wf1_mode2_funcs[] = { 2, 2, 2, 2, 2, 2 };
+
+/* PCIE_CLK_REQ */
+static int mt7986_pcie_clk_pins[] = { 9, };
+static int mt7986_pcie_clk_funcs[] = { 1, };
+
+/* PCIE_WAKE_N */
+static int mt7986_pcie_wake_pins[] = { 10, };
+static int mt7986_pcie_wake_funcs[] = { 1, };
+
+static const struct group_desc mt7986_groups[] = {
+	/*  @GPIO(0): SYS_WATCHDOG(1) */
+        PINCTRL_PIN_GROUP("watchdog", mt7986_watchdog),
+	/*  @GPIO(1,2): WF2G_LED(1), WF5G_LED(1) */
+        PINCTRL_PIN_GROUP("wifi_led", mt7986_wifi_led),
+	/*  @GPIO(3,4): I2C(1) */
+        PINCTRL_PIN_GROUP("i2c", mt7986_i2c),
+	/*  @GPIO(7,10): UART1(3) */
+        PINCTRL_PIN_GROUP("uart1_0", mt7986_uart1_0),
+        /*  @GPIO(9): PCIE_CLK_REQ(9) */
+        PINCTRL_PIN_GROUP("pcie_clk", mt7986_pcie_clk),
+        /*  @GPIO(10): PCIE_WAKE_N(10) */
+        PINCTRL_PIN_GROUP("pcie_wake", mt7986_pcie_wake),
+	/*  @GPIO(11,15): JTAG(1) */
+        PINCTRL_PIN_GROUP("jtag", mt7986_jtag),
+	/*  @GPIO(11,15): SPI1(3) */
+        PINCTRL_PIN_GROUP("spi1_0", mt7986_spi1_0),
+	/*  @GPIO(20): PWM(2) */
+        PINCTRL_PIN_GROUP("pwm1_1", mt7986_pwm1_1),
+	/*  @GPIO(21): PWM(1) */
+        PINCTRL_PIN_GROUP("pwm0", mt7986_pwm0),
+	/*  @GPIO(22): PWM(1) */
+        PINCTRL_PIN_GROUP("pwm1_0", mt7986_pwm1_0),
+	/*  @GPIO(22,32): EMMC(2) */
+        PINCTRL_PIN_GROUP("emmc_45", mt7986_emmc_45),
+	/*  @GPIO(23,28): SNFI(1) */
+        PINCTRL_PIN_GROUP("snfi", mt7986_snfi),
+	/*  @GPIO(23,26): SPI1(2) */
+        PINCTRL_PIN_GROUP("spi1_1", mt7986_spi1_1),
+	/*  @GPIO(23,26): UART1(4) */
+        PINCTRL_PIN_GROUP("uart1_1", mt7986_uart1_1),
+	/*  @GPIO(29,32): SPI1(1) */
+        PINCTRL_PIN_GROUP("spi1_2", mt7986_spi1_2),
+	/*  @GPIO(29,32): UART1(3) */
+        PINCTRL_PIN_GROUP("uart1_2", mt7986_uart1_2),
+	/*  @GPIO(29,32): UART2(4) */
+        PINCTRL_PIN_GROUP("uart2_0", mt7986_uart2_0),
+	/*  @GPIO(33,36): SPI0(1) */
+        PINCTRL_PIN_GROUP("spi0", mt7986_spi0),
+	/*  @GPIO(37,38): SPI0(1) */
+        PINCTRL_PIN_GROUP("spi0_wp_hold", mt7986_spi0_wp_hold),
+	/*  @GPIO(33,36): UART2(3) */
+        PINCTRL_PIN_GROUP("uart2_1", mt7986_uart2_1),
+	/*  @GPIO(35,36): UART1(2) */
+        PINCTRL_PIN_GROUP("uart1_3_rx_tx", mt7986_uart1_3_rx_tx),
+	/*  @GPIO(37,38): UART1(2) */
+        PINCTRL_PIN_GROUP("uart1_3_cts_rts", mt7986_uart1_3_cts_rts),
+	/*  @GPIO(33,36): SPI1(4) */
+        PINCTRL_PIN_GROUP("spi1_3", mt7986_spi1_3),
+	/*  @GPIO(39,40): UART0(1) */
+        PINCTRL_PIN_GROUP("uart0", mt7986_uart0),
+	/*  @GPIO(41): PCIE_PERESET_N(1) */
+        PINCTRL_PIN_GROUP("pcie_pereset", mt7986_pcie_reset),
+	/*  @GPIO(42,45): UART1(1) */
+        PINCTRL_PIN_GROUP("uart1", mt7986_uart1),
+	/*  @GPIO(46,49): UART1(1) */
+        PINCTRL_PIN_GROUP("uart2", mt7986_uart2),
+	/*  @GPIO(50,61): EMMC(1) */
+        PINCTRL_PIN_GROUP("emmc_51", mt7986_emmc_51),
+	/*  @GPIO(62,65): PCM(1) */
+        PINCTRL_PIN_GROUP("pcm", mt7986_pcm),
+	/*  @GPIO(66): MT7531_INT(1) */
+        PINCTRL_PIN_GROUP("switch_int", mt7986_switch_int),
+	/*  @GPIO(67,68): MDC_MDIO(1) */
+        PINCTRL_PIN_GROUP("mdc_mdio", mt7986_mdc_mdio),
+    /*  @GPIO(69,85): WF0_MODE1(1) */
+        PINCTRL_PIN_GROUP("wf0_mode1", mt7986_wf0_mode1),
+    /*  @GPIO(74,78): WF0_HB(2) */
+        PINCTRL_PIN_GROUP("wf0_hb", mt7986_wf0_hb),
+    /*  @GPIO(74,80): WF0_MODE3(3) */
+        PINCTRL_PIN_GROUP("wf0_mode3", mt7986_wf0_mode3),
+    /*  @GPIO(79,85): WF1_HB(2) */
+        PINCTRL_PIN_GROUP("wf1_hb", mt7986_wf1_hb),
+    /*  @GPIO(86,100): WF1_MODE1(1) */
+        PINCTRL_PIN_GROUP("wf1_mode1", mt7986_wf1_mode1),
+     /*  @GPIO(91,97): WF1_MODE2(2) */
+        PINCTRL_PIN_GROUP("wf1_mode2", mt7986_wf1_mode2),
+
+
+	PINCTRL_PIN_GROUP("wf_2g", mt7986_wf_2g),
+	PINCTRL_PIN_GROUP("wf_5g", mt7986_wf_5g),
+	PINCTRL_PIN_GROUP("wf_dbdc", mt7986_wf_dbdc),
+};
+
+/* Joint those groups owning the same capability in user point of view which
+ * allows that people tend to use through the device tree.
+ */
+static const char *mt7986_ethernet_groups[] = { "mdc_mdio", "wf0_mode1", "wf0_hb",
+						"wf0_mode3", "wf1_hb", "wf1_mode1", "wf1_mode2" };
+static const char *mt7986_i2c_groups[] = { "i2c", };
+static const char *mt7986_led_groups[] = { "wifi_led", };
+static const char *mt7986_pwm_groups[] = { "pwm0", "pwm1_0", "pwm1_1", };
+static const char *mt7986_spi_groups[] = { "spi0", "spi1_0", "spi1_1",
+					   "spi1_2", "spi1_3", };
+static const char *mt7986_uart_groups[] = { "uart1_0", "uart1_1", "uart1_2",
+					    "uart1_3_rx_tx", "uart1_3_cts_rts",
+					    "uart2_0", "uart2_1",
+					    "uart0", "uart1", "uart2", };
+static const char *mt7986_wdt_groups[] = { "watchdog", };
+static const char *mt7986_flash_groups[] = { "snfi", "emmc_45", "emmc_51", "spi0", "spi0_wp_hold"};
+static const char *mt7986_pcie_groups[] = { "pcie_clk", "pcie_wake", "pcie_pereset"};
+static const char *mt7986_wf_groups[] = { "wf_2g", "wf_5g", "wf_dbdc", };
+
+static const struct function_desc mt7986_functions[] = {
+	{"eth",	mt7986_ethernet_groups, ARRAY_SIZE(mt7986_ethernet_groups)},
+	{"i2c", mt7986_i2c_groups, ARRAY_SIZE(mt7986_i2c_groups)},
+	{"led",	mt7986_led_groups, ARRAY_SIZE(mt7986_led_groups)},
+	{"pwm",	mt7986_pwm_groups, ARRAY_SIZE(mt7986_pwm_groups)},
+	{"spi",	mt7986_spi_groups, ARRAY_SIZE(mt7986_spi_groups)},
+	{"uart", mt7986_uart_groups, ARRAY_SIZE(mt7986_uart_groups)},
+	{"watchdog", mt7986_wdt_groups, ARRAY_SIZE(mt7986_wdt_groups)},
+	{"flash", mt7986_flash_groups, ARRAY_SIZE(mt7986_flash_groups)},
+	{"pcie", mt7986_pcie_groups, ARRAY_SIZE(mt7986_pcie_groups)},
+	{"wifi", mt7986_wf_groups, ARRAY_SIZE(mt7986_wf_groups)},
+};
+
+static const struct mtk_eint_hw mt7986_eint_hw = {
+	.port_mask = 7,
+	.ports     = 7,
+	.ap_num    = ARRAY_SIZE(mt7986_pins),
+	.db_cnt    = 16,
+};
+
+static const char * const mt7986_pinctrl_register_base_names[] = {
+	"gpio_base", "iocfg_rt_base", "iocfg_rb_base", "iocfg_lt_base",
+	"iocfg_lb_base", "iocfg_tr_base", "iocfg_tl_base",
+};
+
+static struct mtk_pin_soc mt7986_data = {
+	.reg_cal = mt7986_reg_cals,
+	.pins = mt7986_pins,
+	.npins = ARRAY_SIZE(mt7986_pins),
+	.grps = mt7986_groups,
+	.ngrps = ARRAY_SIZE(mt7986_groups),
+	.funcs = mt7986_functions,
+	.nfuncs = ARRAY_SIZE(mt7986_functions),
+	.eint_hw = &mt7986_eint_hw,
+	.gpio_m = 0,
+	.ies_present = false,
+	.base_names = mt7986_pinctrl_register_base_names,
+	.nbase_names = ARRAY_SIZE(mt7986_pinctrl_register_base_names),
+	.bias_disable_set = mtk_pinconf_bias_disable_set,
+	.bias_disable_get = mtk_pinconf_bias_disable_get,
+	.bias_set = mtk_pinconf_bias_set,
+	.bias_get = mtk_pinconf_bias_get,
+	.drive_set = mtk_pinconf_drive_set_rev1,
+	.drive_get = mtk_pinconf_drive_get_rev1,
+	.adv_pull_get = mtk_pinconf_adv_pull_get,
+	.adv_pull_set = mtk_pinconf_adv_pull_set,
+};
+
+static const struct of_device_id mt7986_pinctrl_of_match[] = {
+	{ .compatible = "mediatek,mt7986-pinctrl", },
+	{}
+};
+
+static int mt7986_pinctrl_probe(struct platform_device *pdev)
+{
+	return mtk_moore_pinctrl_probe(pdev, &mt7986_data);
+}
+
+static struct platform_driver mt7986_pinctrl_driver = {
+	.driver = {
+		.name = "mt7986-pinctrl",
+		.of_match_table = mt7986_pinctrl_of_match,
+	},
+	.probe = mt7986_pinctrl_probe,
+};
+
+static int __init mt7986_pinctrl_init(void)
+{
+	return platform_driver_register(&mt7986_pinctrl_driver);
+}
+arch_initcall(mt7986_pinctrl_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/thermal/mtk_thermal.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/thermal/mtk_thermal.c
new file mode 100644
index 0000000..1351b13
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/thermal/mtk_thermal.c
@@ -0,0 +1,1321 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: Hanyi Wu <hanyi.wu@mediatek.com>
+ *         Sascha Hauer <s.hauer@pengutronix.de>
+ *         Dawei Chien <dawei.chien@mediatek.com>
+ *         Louis Yu <louis.yu@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/thermal.h>
+#include <linux/reset.h>
+#include <linux/types.h>
+
+/* AUXADC Registers */
+#define AUXADC_CON1_SET_V	0x008
+#define AUXADC_CON1_CLR_V	0x00c
+#define AUXADC_CON2_V		0x010
+#define AUXADC_DATA(channel)	(0x14 + (channel) * 4)
+
+#define APMIXED_SYS_TS_CON1	0x604
+
+/* Thermal Controller Registers */
+#define TEMP_MONCTL0		0x000
+#define TEMP_MONCTL1		0x004
+#define TEMP_MONCTL2		0x008
+#define TEMP_MONIDET0		0x014
+#define TEMP_MONIDET1		0x018
+#define TEMP_MSRCTL0		0x038
+#define TEMP_MSRCTL1		0x03c
+#define TEMP_AHBPOLL		0x040
+#define TEMP_AHBTO		0x044
+#define TEMP_ADCPNP0		0x048
+#define TEMP_ADCPNP1		0x04c
+#define TEMP_ADCPNP2		0x050
+#define TEMP_ADCPNP3		0x0b4
+
+#define TEMP_ADCMUX		0x054
+#define TEMP_ADCEN		0x060
+#define TEMP_PNPMUXADDR		0x064
+#define TEMP_ADCMUXADDR		0x068
+#define TEMP_ADCENADDR		0x074
+#define TEMP_ADCVALIDADDR	0x078
+#define TEMP_ADCVOLTADDR	0x07c
+#define TEMP_RDCTRL		0x080
+#define TEMP_ADCVALIDMASK	0x084
+#define TEMP_ADCVOLTAGESHIFT	0x088
+#define TEMP_ADCWRITECTRL	0x08c
+#define TEMP_MSR0		0x090
+#define TEMP_MSR1		0x094
+#define TEMP_MSR2		0x098
+#define TEMP_MSR3		0x0B8
+
+#define TEMP_SPARE0		0x0f0
+
+#define TEMP_ADCPNP0_1          0x148
+#define TEMP_ADCPNP1_1          0x14c
+#define TEMP_ADCPNP2_1          0x150
+#define TEMP_MSR0_1             0x190
+#define TEMP_MSR1_1             0x194
+#define TEMP_MSR2_1             0x198
+#define TEMP_ADCPNP3_1          0x1b4
+#define TEMP_MSR3_1             0x1B8
+
+#define PTPCORESEL		0x400
+
+#define TEMP_MONCTL1_PERIOD_UNIT(x)	((x) & 0x3ff)
+
+#define TEMP_MONCTL2_FILTER_INTERVAL(x)	(((x) & 0x3ff) << 16)
+#define TEMP_MONCTL2_SENSOR_INTERVAL(x)	((x) & 0x3ff)
+
+#define TEMP_AHBPOLL_ADC_POLL_INTERVAL(x)	(x)
+
+#define TEMP_ADCWRITECTRL_ADC_PNP_WRITE		BIT(0)
+#define TEMP_ADCWRITECTRL_ADC_MUX_WRITE		BIT(1)
+
+#define TEMP_ADCVALIDMASK_VALID_HIGH		BIT(5)
+#define TEMP_ADCVALIDMASK_VALID_POS(bit)	(bit)
+
+/* MT8173 thermal sensors */
+#define MT8173_TS1	0
+#define MT8173_TS2	1
+#define MT8173_TS3	2
+#define MT8173_TS4	3
+#define MT8173_TSABB	4
+
+/* AUXADC channel 11 is used for the temperature sensors */
+#define MT8173_TEMP_AUXADC_CHANNEL	11
+
+/* The total number of temperature sensors in the MT8173 */
+#define MT8173_NUM_SENSORS		5
+
+/* The number of banks in the MT8173 */
+#define MT8173_NUM_ZONES		4
+
+/* The number of sensing points per bank */
+#define MT8173_NUM_SENSORS_PER_ZONE	4
+
+/* The number of controller in the MT8173 */
+#define MT8173_NUM_CONTROLLER		1
+
+/* The calibration coefficient of sensor  */
+#define MT8173_CALIBRATION	165
+
+/*
+ * Layout of the fuses providing the calibration data
+ * These macros could be used for MT8183, MT8173, MT2701, and MT2712.
+ * MT8183 has 6 sensors and needs 6 VTS calibration data.
+ * MT8173 has 5 sensors and needs 5 VTS calibration data.
+ * MT2701 has 3 sensors and needs 3 VTS calibration data.
+ * MT2712 has 4 sensors and needs 4 VTS calibration data.
+ */
+#define CALIB_BUF0_VALID_V1		BIT(0)
+#define CALIB_BUF1_ADC_GE_V1(x)		(((x) >> 22) & 0x3ff)
+#define CALIB_BUF0_VTS_TS1_V1(x)	(((x) >> 17) & 0x1ff)
+#define CALIB_BUF0_VTS_TS2_V1(x)	(((x) >> 8) & 0x1ff)
+#define CALIB_BUF1_VTS_TS3_V1(x)	(((x) >> 0) & 0x1ff)
+#define CALIB_BUF2_VTS_TS4_V1(x)	(((x) >> 23) & 0x1ff)
+#define CALIB_BUF2_VTS_TS5_V1(x)	(((x) >> 5) & 0x1ff)
+#define CALIB_BUF2_VTS_TSABB_V1(x)	(((x) >> 14) & 0x1ff)
+#define CALIB_BUF0_DEGC_CALI_V1(x)	(((x) >> 1) & 0x3f)
+#define CALIB_BUF0_O_SLOPE_V1(x)	(((x) >> 26) & 0x3f)
+#define CALIB_BUF0_O_SLOPE_SIGN_V1(x)	(((x) >> 7) & 0x1)
+#define CALIB_BUF1_ID_V1(x)		(((x) >> 9) & 0x1)
+
+/*
+ * Layout of the fuses providing the calibration data
+ * These macros could be used for MT7622.
+ */
+#define CALIB_BUF0_ADC_OE_V2(x)		(((x) >> 22) & 0x3ff)
+#define CALIB_BUF0_ADC_GE_V2(x)		(((x) >> 12) & 0x3ff)
+#define CALIB_BUF0_DEGC_CALI_V2(x)	(((x) >> 6) & 0x3f)
+#define CALIB_BUF0_O_SLOPE_V2(x)	(((x) >> 0) & 0x3f)
+#define CALIB_BUF1_VTS_TS1_V2(x)	(((x) >> 23) & 0x1ff)
+#define CALIB_BUF1_VTS_TS2_V2(x)	(((x) >> 14) & 0x1ff)
+#define CALIB_BUF1_VTS_TSABB_V2(x)	(((x) >> 5) & 0x1ff)
+#define CALIB_BUF1_VALID_V2(x)		(((x) >> 4) & 0x1)
+#define CALIB_BUF1_O_SLOPE_SIGN_V2(x)	(((x) >> 3) & 0x1)
+
+/*
+ * Layout of the fuses providing the calibration data
+ * These macros could be used for MT7981 and MT7986.
+ */
+#define CALIB_BUF0_ADC_GE_V3(x)		(((x) >> 0) & 0x3ff)
+#define CALIB_BUF0_ADC_OE_V3(x)		(((x) >> 10) & 0x3ff)
+#define CALIB_BUF0_DEGC_CALI_V3(x)	(((x) >> 20) & 0x3f)
+#define CALIB_BUF0_O_SLOPE_V3(x)	(((x) >> 26) & 0x3f)
+#define CALIB_BUF1_VTS_TS1_V3(x)	(((x) >> 0) & 0x1ff)
+#define CALIB_BUF1_VTS_TS2_V3(x)	(((x) >> 21) & 0x1ff)
+#define CALIB_BUF1_VTS_TSABB_V3(x)	(((x) >> 9) & 0x1ff)
+#define CALIB_BUF1_VALID_V3(x)		(((x) >> 18) & 0x1)
+#define CALIB_BUF1_O_SLOPE_SIGN_V3(x)	(((x) >> 19) & 0x1)
+#define CALIB_BUF1_ID_V3(x)		(((x) >> 20) & 0x1)
+
+enum {
+	VTS1,
+	VTS2,
+	VTS3,
+	VTS4,
+	VTS5,
+	VTSABB,
+	MAX_NUM_VTS,
+};
+
+enum mtk_thermal_version {
+	MTK_THERMAL_V1 = 1,
+	MTK_THERMAL_V2,
+	MTK_THERMAL_V3,
+};
+
+/* MT2701 thermal sensors */
+#define MT2701_TS1	0
+#define MT2701_TS2	1
+#define MT2701_TSABB	2
+
+/* AUXADC channel 11 is used for the temperature sensors */
+#define MT2701_TEMP_AUXADC_CHANNEL	11
+
+/* The total number of temperature sensors in the MT2701 */
+#define MT2701_NUM_SENSORS	3
+
+/* The number of sensing points per bank */
+#define MT2701_NUM_SENSORS_PER_ZONE	3
+
+/* The number of controller in the MT2701 */
+#define MT2701_NUM_CONTROLLER		1
+
+/* The calibration coefficient of sensor  */
+#define MT2701_CALIBRATION	165
+
+/* MT2712 thermal sensors */
+#define MT2712_TS1	0
+#define MT2712_TS2	1
+#define MT2712_TS3	2
+#define MT2712_TS4	3
+
+/* AUXADC channel 11 is used for the temperature sensors */
+#define MT2712_TEMP_AUXADC_CHANNEL	11
+
+/* The total number of temperature sensors in the MT2712 */
+#define MT2712_NUM_SENSORS	4
+
+/* The number of sensing points per bank */
+#define MT2712_NUM_SENSORS_PER_ZONE	4
+
+/* The number of controller in the MT2712 */
+#define MT2712_NUM_CONTROLLER		1
+
+/* The calibration coefficient of sensor  */
+#define MT2712_CALIBRATION	165
+
+#define MT7622_TEMP_AUXADC_CHANNEL	11
+#define MT7622_NUM_SENSORS		1
+#define MT7622_NUM_ZONES		1
+#define MT7622_NUM_SENSORS_PER_ZONE	1
+#define MT7622_TS1	0
+#define MT7622_NUM_CONTROLLER		1
+
+/* The maximum number of banks */
+#define MAX_NUM_ZONES		8
+
+/* The calibration coefficient of sensor  */
+#define MT7622_CALIBRATION	165
+
+/* MT8183 thermal sensors */
+#define MT8183_TS1	0
+#define MT8183_TS2	1
+#define MT8183_TS3	2
+#define MT8183_TS4	3
+#define MT8183_TS5	4
+#define MT8183_TSABB	5
+
+/* AUXADC channel  is used for the temperature sensors */
+#define MT8183_TEMP_AUXADC_CHANNEL	11
+
+/* The total number of temperature sensors in the MT8183 */
+#define MT8183_NUM_SENSORS	6
+
+/* The number of banks in the MT8183 */
+#define MT8183_NUM_ZONES               1
+
+/* The number of sensing points per bank */
+#define MT8183_NUM_SENSORS_PER_ZONE	 6
+
+/* The number of controller in the MT8183 */
+#define MT8183_NUM_CONTROLLER		2
+
+/* The calibration coefficient of sensor  */
+#define MT8183_CALIBRATION	153
+
+/* AUXADC channel 11 is used for the temperature sensors */
+#define MT7981_TEMP_AUXADC_CHANNEL	11
+
+/* The total number of temperature sensors in the MT7981 */
+#define MT7981_NUM_SENSORS		1
+
+/* The number of banks in the MT7981 */
+#define MT7981_NUM_ZONES		1
+
+/* The number of sensing points per bank */
+#define MT7981_NUM_SENSORS_PER_ZONE	1
+
+/* MT7981 thermal sensors */
+#define MT7981_TS1	0
+
+/* The number of controller in the MT7981 */
+#define MT7981_NUM_CONTROLLER		1
+
+/* The calibration coefficient of sensor  */
+#define MT7981_CALIBRATION		165
+
+/* AUXADC channel 11 is used for the temperature sensors */
+#define MT7986_TEMP_AUXADC_CHANNEL	11
+
+/* The total number of temperature sensors in the MT7986 */
+#define MT7986_NUM_SENSORS		1
+
+/* The number of banks in the MT7986 */
+#define MT7986_NUM_ZONES		1
+
+/* The number of sensing points per bank */
+#define MT7986_NUM_SENSORS_PER_ZONE	1
+
+/* MT7986 thermal sensors */
+#define MT7986_TS1	0
+
+/* The number of controller in the MT7986 */
+#define MT7986_NUM_CONTROLLER		1
+
+/* The calibration coefficient of sensor  */
+#define MT7986_CALIBRATION		165
+
+struct mtk_thermal;
+
+struct thermal_bank_cfg {
+	unsigned int num_sensors;
+	const int *sensors;
+};
+
+struct mtk_thermal_bank {
+	struct mtk_thermal *mt;
+	int id;
+};
+
+struct mtk_thermal_data {
+	s32 num_banks;
+	s32 num_sensors;
+	s32 auxadc_channel;
+	const int *vts_index;
+	const int *sensor_mux_values;
+	const int *msr;
+	const int *adcpnp;
+	const int cali_val;
+	const int num_controller;
+	const int *controller_offset;
+	bool need_switch_bank;
+	struct thermal_bank_cfg bank_data[MAX_NUM_ZONES];
+	enum mtk_thermal_version version;
+};
+
+struct mtk_thermal {
+	struct device *dev;
+	void __iomem *thermal_base;
+
+	struct clk *clk_peri_therm;
+	struct clk *clk_auxadc;
+	struct clk *clk_adc_32k;
+	/* lock: for getting and putting banks */
+	struct mutex lock;
+
+	/* Calibration values */
+	s32 adc_ge;
+	s32 adc_oe;
+	s32 degc_cali;
+	s32 o_slope;
+	s32 o_slope_sign;
+	s32 vts[MAX_NUM_VTS];
+
+	const struct mtk_thermal_data *conf;
+	struct mtk_thermal_bank banks[MAX_NUM_ZONES];
+};
+
+/* MT8183 thermal sensor data */
+static const int mt8183_bank_data[MT8183_NUM_SENSORS] = {
+	MT8183_TS1, MT8183_TS2, MT8183_TS3, MT8183_TS4, MT8183_TS5, MT8183_TSABB
+};
+
+static const int mt8183_msr[MT8183_NUM_SENSORS_PER_ZONE] = {
+	TEMP_MSR0_1, TEMP_MSR1_1, TEMP_MSR2_1, TEMP_MSR1, TEMP_MSR0, TEMP_MSR3_1
+};
+
+static const int mt8183_adcpnp[MT8183_NUM_SENSORS_PER_ZONE] = {
+	TEMP_ADCPNP0_1, TEMP_ADCPNP1_1, TEMP_ADCPNP2_1,
+	TEMP_ADCPNP1, TEMP_ADCPNP0, TEMP_ADCPNP3_1
+};
+
+static const int mt8183_mux_values[MT8183_NUM_SENSORS] = { 0, 1, 2, 3, 4, 0 };
+static const int mt8183_tc_offset[MT8183_NUM_CONTROLLER] = {0x0, 0x100};
+
+static const int mt8183_vts_index[MT8183_NUM_SENSORS] = {
+	VTS1, VTS2, VTS3, VTS4, VTS5, VTSABB
+};
+
+/* MT8173 thermal sensor data */
+static const int mt8173_bank_data[MT8173_NUM_ZONES][3] = {
+	{ MT8173_TS2, MT8173_TS3 },
+	{ MT8173_TS2, MT8173_TS4 },
+	{ MT8173_TS1, MT8173_TS2, MT8173_TSABB },
+	{ MT8173_TS2 },
+};
+
+static const int mt8173_msr[MT8173_NUM_SENSORS_PER_ZONE] = {
+	TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR3
+};
+
+static const int mt8173_adcpnp[MT8173_NUM_SENSORS_PER_ZONE] = {
+	TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2, TEMP_ADCPNP3
+};
+
+static const int mt8173_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 };
+static const int mt8173_tc_offset[MT8173_NUM_CONTROLLER] = { 0x0, };
+
+static const int mt8173_vts_index[MT8173_NUM_SENSORS] = {
+	VTS1, VTS2, VTS3, VTS4, VTSABB
+};
+
+/* MT2701 thermal sensor data */
+static const int mt2701_bank_data[MT2701_NUM_SENSORS] = {
+	MT2701_TS1, MT2701_TS2, MT2701_TSABB
+};
+
+static const int mt2701_msr[MT2701_NUM_SENSORS_PER_ZONE] = {
+	TEMP_MSR0, TEMP_MSR1, TEMP_MSR2
+};
+
+static const int mt2701_adcpnp[MT2701_NUM_SENSORS_PER_ZONE] = {
+	TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2
+};
+
+static const int mt2701_mux_values[MT2701_NUM_SENSORS] = { 0, 1, 16 };
+static const int mt2701_tc_offset[MT2701_NUM_CONTROLLER] = { 0x0, };
+
+static const int mt2701_vts_index[MT2701_NUM_SENSORS] = {
+	VTS1, VTS2, VTS3
+};
+
+/* MT2712 thermal sensor data */
+static const int mt2712_bank_data[MT2712_NUM_SENSORS] = {
+	MT2712_TS1, MT2712_TS2, MT2712_TS3, MT2712_TS4
+};
+
+static const int mt2712_msr[MT2712_NUM_SENSORS_PER_ZONE] = {
+	TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR3
+};
+
+static const int mt2712_adcpnp[MT2712_NUM_SENSORS_PER_ZONE] = {
+	TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2, TEMP_ADCPNP3
+};
+
+static const int mt2712_mux_values[MT2712_NUM_SENSORS] = { 0, 1, 2, 3 };
+static const int mt2712_tc_offset[MT2712_NUM_CONTROLLER] = { 0x0, };
+
+static const int mt2712_vts_index[MT2712_NUM_SENSORS] = {
+	VTS1, VTS2, VTS3, VTS4
+};
+
+/* MT7622 thermal sensor data */
+static const int mt7622_bank_data[MT7622_NUM_SENSORS] = { MT7622_TS1, };
+static const int mt7622_msr[MT7622_NUM_SENSORS_PER_ZONE] = { TEMP_MSR0, };
+static const int mt7622_adcpnp[MT7622_NUM_SENSORS_PER_ZONE] = { TEMP_ADCPNP0, };
+static const int mt7622_mux_values[MT7622_NUM_SENSORS] = { 0, };
+static const int mt7622_vts_index[MT7622_NUM_SENSORS] = { VTS1 };
+static const int mt7622_tc_offset[MT7622_NUM_CONTROLLER] = { 0x0, };
+
+/* MT7981 thermal sensor data */
+static const int mt7981_bank_data[MT7981_NUM_SENSORS] = { MT7981_TS1, };
+static const int mt7981_msr[MT7981_NUM_SENSORS_PER_ZONE] = { TEMP_MSR0, };
+static const int mt7981_adcpnp[MT7981_NUM_SENSORS_PER_ZONE] = {	TEMP_ADCPNP0, };
+static const int mt7981_mux_values[MT7981_NUM_SENSORS] = { 0, };
+static const int mt7981_vts_index[MT7981_NUM_SENSORS] = { VTS1 };
+static const int mt7981_tc_offset[MT7981_NUM_CONTROLLER] = { 0x0, };
+
+/* MT7986 thermal sensor data */
+static const int mt7986_bank_data[MT7986_NUM_SENSORS] = { MT7986_TS1, };
+static const int mt7986_msr[MT7986_NUM_SENSORS_PER_ZONE] = { TEMP_MSR0, };
+static const int mt7986_adcpnp[MT7986_NUM_SENSORS_PER_ZONE] = {	TEMP_ADCPNP0, };
+static const int mt7986_mux_values[MT7986_NUM_SENSORS] = { 0, };
+static const int mt7986_vts_index[MT7986_NUM_SENSORS] = { VTS1 };
+static const int mt7986_tc_offset[MT7986_NUM_CONTROLLER] = { 0x0, };
+
+/*
+ * The MT8173 thermal controller has four banks. Each bank can read up to
+ * four temperature sensors simultaneously. The MT8173 has a total of 5
+ * temperature sensors. We use each bank to measure a certain area of the
+ * SoC. Since TS2 is located centrally in the SoC it is influenced by multiple
+ * areas, hence is used in different banks.
+ *
+ * The thermal core only gets the maximum temperature of all banks, so
+ * the bank concept wouldn't be necessary here. However, the SVS (Smart
+ * Voltage Scaling) unit makes its decisions based on the same bank
+ * data, and this indeed needs the temperatures of the individual banks
+ * for making better decisions.
+ */
+static const struct mtk_thermal_data mt8173_thermal_data = {
+	.auxadc_channel = MT8173_TEMP_AUXADC_CHANNEL,
+	.num_banks = MT8173_NUM_ZONES,
+	.num_sensors = MT8173_NUM_SENSORS,
+	.vts_index = mt8173_vts_index,
+	.cali_val = MT8173_CALIBRATION,
+	.num_controller = MT8173_NUM_CONTROLLER,
+	.controller_offset = mt8173_tc_offset,
+	.need_switch_bank = true,
+	.bank_data = {
+		{
+			.num_sensors = 2,
+			.sensors = mt8173_bank_data[0],
+		}, {
+			.num_sensors = 2,
+			.sensors = mt8173_bank_data[1],
+		}, {
+			.num_sensors = 3,
+			.sensors = mt8173_bank_data[2],
+		}, {
+			.num_sensors = 1,
+			.sensors = mt8173_bank_data[3],
+		},
+	},
+	.msr = mt8173_msr,
+	.adcpnp = mt8173_adcpnp,
+	.sensor_mux_values = mt8173_mux_values,
+	.version = MTK_THERMAL_V1,
+};
+
+/*
+ * The MT2701 thermal controller has one bank, which can read up to
+ * three temperature sensors simultaneously. The MT2701 has a total of 3
+ * temperature sensors.
+ *
+ * The thermal core only gets the maximum temperature of this one bank,
+ * so the bank concept wouldn't be necessary here. However, the SVS (Smart
+ * Voltage Scaling) unit makes its decisions based on the same bank
+ * data.
+ */
+static const struct mtk_thermal_data mt2701_thermal_data = {
+	.auxadc_channel = MT2701_TEMP_AUXADC_CHANNEL,
+	.num_banks = 1,
+	.num_sensors = MT2701_NUM_SENSORS,
+	.vts_index = mt2701_vts_index,
+	.cali_val = MT2701_CALIBRATION,
+	.num_controller = MT2701_NUM_CONTROLLER,
+	.controller_offset = mt2701_tc_offset,
+	.need_switch_bank = true,
+	.bank_data = {
+		{
+			.num_sensors = 3,
+			.sensors = mt2701_bank_data,
+		},
+	},
+	.msr = mt2701_msr,
+	.adcpnp = mt2701_adcpnp,
+	.sensor_mux_values = mt2701_mux_values,
+	.version = MTK_THERMAL_V1,
+};
+
+/*
+ * The MT2712 thermal controller has one bank, which can read up to
+ * four temperature sensors simultaneously. The MT2712 has a total of 4
+ * temperature sensors.
+ *
+ * The thermal core only gets the maximum temperature of this one bank,
+ * so the bank concept wouldn't be necessary here. However, the SVS (Smart
+ * Voltage Scaling) unit makes its decisions based on the same bank
+ * data.
+ */
+static const struct mtk_thermal_data mt2712_thermal_data = {
+	.auxadc_channel = MT2712_TEMP_AUXADC_CHANNEL,
+	.num_banks = 1,
+	.num_sensors = MT2712_NUM_SENSORS,
+	.vts_index = mt2712_vts_index,
+	.cali_val = MT2712_CALIBRATION,
+	.num_controller = MT2712_NUM_CONTROLLER,
+	.controller_offset = mt2712_tc_offset,
+	.need_switch_bank = true,
+	.bank_data = {
+		{
+			.num_sensors = 4,
+			.sensors = mt2712_bank_data,
+		},
+	},
+	.msr = mt2712_msr,
+	.adcpnp = mt2712_adcpnp,
+	.sensor_mux_values = mt2712_mux_values,
+	.version = MTK_THERMAL_V1,
+};
+
+/*
+ * MT7622 have only one sensing point which uses AUXADC Channel 11 for raw data
+ * access.
+ */
+static const struct mtk_thermal_data mt7622_thermal_data = {
+	.auxadc_channel = MT7622_TEMP_AUXADC_CHANNEL,
+	.num_banks = MT7622_NUM_ZONES,
+	.num_sensors = MT7622_NUM_SENSORS,
+	.vts_index = mt7622_vts_index,
+	.cali_val = MT7622_CALIBRATION,
+	.num_controller = MT7622_NUM_CONTROLLER,
+	.controller_offset = mt7622_tc_offset,
+	.need_switch_bank = true,
+	.bank_data = {
+		{
+			.num_sensors = 1,
+			.sensors = mt7622_bank_data,
+		},
+	},
+	.msr = mt7622_msr,
+	.adcpnp = mt7622_adcpnp,
+	.sensor_mux_values = mt7622_mux_values,
+	.version = MTK_THERMAL_V2,
+};
+
+/*
+ * The MT8183 thermal controller has one bank for the current SW framework.
+ * The MT8183 has a total of 6 temperature sensors.
+ * There are two thermal controller to control the six sensor.
+ * The first one bind 2 sensor, and the other bind 4 sensors.
+ * The thermal core only gets the maximum temperature of all sensor, so
+ * the bank concept wouldn't be necessary here. However, the SVS (Smart
+ * Voltage Scaling) unit makes its decisions based on the same bank
+ * data, and this indeed needs the temperatures of the individual banks
+ * for making better decisions.
+ */
+static const struct mtk_thermal_data mt8183_thermal_data = {
+	.auxadc_channel = MT8183_TEMP_AUXADC_CHANNEL,
+	.num_banks = MT8183_NUM_ZONES,
+	.num_sensors = MT8183_NUM_SENSORS,
+	.vts_index = mt8183_vts_index,
+	.cali_val = MT8183_CALIBRATION,
+	.num_controller = MT8183_NUM_CONTROLLER,
+	.controller_offset = mt8183_tc_offset,
+	.need_switch_bank = false,
+	.bank_data = {
+		{
+			.num_sensors = 6,
+			.sensors = mt8183_bank_data,
+		},
+	},
+
+	.msr = mt8183_msr,
+	.adcpnp = mt8183_adcpnp,
+	.sensor_mux_values = mt8183_mux_values,
+	.version = MTK_THERMAL_V1,
+};
+
+/*
+ * MT7981 uses AUXADC Channel 11 for raw data access.
+ */
+static const struct mtk_thermal_data mt7981_thermal_data = {
+	.auxadc_channel = MT7981_TEMP_AUXADC_CHANNEL,
+	.num_banks = MT7981_NUM_ZONES,
+	.num_sensors = MT7981_NUM_SENSORS,
+	.vts_index = mt7981_vts_index,
+	.cali_val = MT7981_CALIBRATION,
+	.num_controller = MT7981_NUM_CONTROLLER,
+	.controller_offset = mt7981_tc_offset,
+	.need_switch_bank = true,
+	.bank_data = {
+		{
+			.num_sensors = 1,
+			.sensors = mt7981_bank_data,
+		},
+	},
+	.msr = mt7981_msr,
+	.adcpnp = mt7981_adcpnp,
+	.sensor_mux_values = mt7981_mux_values,
+	.version = MTK_THERMAL_V3,
+};
+
+/*
+ * MT7986 uses AUXADC Channel 11 for raw data access.
+ */
+static const struct mtk_thermal_data mt7986_thermal_data = {
+	.auxadc_channel = MT7986_TEMP_AUXADC_CHANNEL,
+	.num_banks = MT7986_NUM_ZONES,
+	.num_sensors = MT7986_NUM_SENSORS,
+	.vts_index = mt7986_vts_index,
+	.cali_val = MT7986_CALIBRATION,
+	.num_controller = MT7986_NUM_CONTROLLER,
+	.controller_offset = mt7986_tc_offset,
+	.need_switch_bank = true,
+	.bank_data = {
+		{
+			.num_sensors = 1,
+			.sensors = mt7986_bank_data,
+		},
+	},
+	.msr = mt7986_msr,
+	.adcpnp = mt7986_adcpnp,
+	.sensor_mux_values = mt7986_mux_values,
+	.version = MTK_THERMAL_V3,
+};
+
+/**
+ * raw_to_mcelsius - convert a raw ADC value to mcelsius
+ * @mt:	The thermal controller
+ * @sensno:	sensor number
+ * @raw:	raw ADC value
+ *
+ * This converts the raw ADC value to mcelsius using the SoC specific
+ * calibration constants
+ */
+static int raw_to_mcelsius_v1(struct mtk_thermal *mt, int sensno, s32 raw)
+{
+	s32 tmp;
+
+	raw &= 0xfff;
+
+	tmp = 203450520 << 3;
+	tmp /= mt->conf->cali_val + mt->o_slope;
+	tmp /= 10000 + mt->adc_ge;
+	tmp *= raw - mt->vts[sensno] - 3350;
+	tmp >>= 3;
+
+	return mt->degc_cali * 500 - tmp;
+}
+
+static int raw_to_mcelsius_v2(struct mtk_thermal *mt, int sensno, s32 raw)
+{
+	s32 format_1;
+	s32 format_2;
+	s32 g_oe;
+	s32 g_gain;
+	s32 g_x_roomt;
+	s32 tmp;
+
+	if (raw == 0)
+		return 0;
+
+	raw &= 0xfff;
+	g_gain = 10000 + (((mt->adc_ge - 512) * 10000) >> 12);
+	g_oe = mt->adc_oe - 512;
+	format_1 = mt->vts[VTS2] + 3105 - g_oe;
+	format_2 = (mt->degc_cali * 10) >> 1;
+	g_x_roomt = (((format_1 * 10000) >> 12) * 10000) / g_gain;
+
+	tmp = (((((raw - g_oe) * 10000) >> 12) * 10000) / g_gain) - g_x_roomt;
+	tmp = tmp * 10 * 100 / 11;
+
+	if (mt->o_slope_sign == 0)
+		tmp = tmp / (165 - mt->o_slope);
+	else
+		tmp = tmp / (165 + mt->o_slope);
+
+	return (format_2 - tmp) * 100;
+}
+
+static int raw_to_mcelsius_v3(struct mtk_thermal *mt, int sensno, s32 raw)
+{
+	s32 tmp;
+
+	if (raw == 0)
+		return 0;
+
+	raw &= 0xfff;
+	tmp = 100000 * 15 / 16 * 10000;
+	tmp /= 4096 - 512 + mt->adc_ge;
+	tmp /= 1490;
+	tmp *= raw - mt->vts[sensno] - 2900;
+
+	return mt->degc_cali * 500 - tmp;
+}
+
+/**
+ * mtk_thermal_get_bank - get bank
+ * @bank:	The bank
+ *
+ * The bank registers are banked, we have to select a bank in the
+ * PTPCORESEL register to access it.
+ */
+static void mtk_thermal_get_bank(struct mtk_thermal_bank *bank)
+{
+	struct mtk_thermal *mt = bank->mt;
+	u32 val;
+
+	if (mt->conf->need_switch_bank) {
+		mutex_lock(&mt->lock);
+
+		val = readl(mt->thermal_base + PTPCORESEL);
+		val &= ~0xf;
+		val |= bank->id;
+		writel(val, mt->thermal_base + PTPCORESEL);
+	}
+}
+
+/**
+ * mtk_thermal_put_bank - release bank
+ * @bank:	The bank
+ *
+ * release a bank previously taken with mtk_thermal_get_bank,
+ */
+static void mtk_thermal_put_bank(struct mtk_thermal_bank *bank)
+{
+	struct mtk_thermal *mt = bank->mt;
+
+	if (mt->conf->need_switch_bank)
+		mutex_unlock(&mt->lock);
+}
+
+/**
+ * mtk_thermal_bank_temperature - get the temperature of a bank
+ * @bank:	The bank
+ *
+ * The temperature of a bank is considered the maximum temperature of
+ * the sensors associated to the bank.
+ */
+static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank)
+{
+	struct mtk_thermal *mt = bank->mt;
+	const struct mtk_thermal_data *conf = mt->conf;
+	int i, temp = INT_MIN, max = INT_MIN;
+	u32 raw;
+
+	for (i = 0; i < conf->bank_data[bank->id].num_sensors; i++) {
+		raw = readl(mt->thermal_base + conf->msr[i]);
+
+		if (mt->conf->version == MTK_THERMAL_V1) {
+			temp = raw_to_mcelsius_v1(
+				mt, conf->bank_data[bank->id].sensors[i], raw);
+		} else if (mt->conf->version == MTK_THERMAL_V2) {
+			temp = raw_to_mcelsius_v2(
+				mt, conf->bank_data[bank->id].sensors[i], raw);
+		} else {
+			temp = raw_to_mcelsius_v3(
+				mt, conf->bank_data[bank->id].sensors[i], raw);
+		}
+
+		/*
+		 * The first read of a sensor often contains very high bogus
+		 * temperature value. Filter these out so that the system does
+		 * not immediately shut down.
+		 */
+		if (temp > 200000)
+			temp = 0;
+
+		if (temp > max)
+			max = temp;
+	}
+
+	return max;
+}
+
+static int mtk_read_temp(void *data, int *temperature)
+{
+	struct mtk_thermal *mt = data;
+	int i;
+	int tempmax = INT_MIN;
+
+	for (i = 0; i < mt->conf->num_banks; i++) {
+		struct mtk_thermal_bank *bank = &mt->banks[i];
+
+		mtk_thermal_get_bank(bank);
+
+		tempmax = max(tempmax, mtk_thermal_bank_temperature(bank));
+
+		mtk_thermal_put_bank(bank);
+	}
+
+	*temperature = tempmax;
+
+	return 0;
+}
+
+static const struct thermal_zone_of_device_ops mtk_thermal_ops = {
+	.get_temp = mtk_read_temp,
+};
+
+static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,
+				  u32 apmixed_phys_base, u32 auxadc_phys_base,
+				  int ctrl_id)
+{
+	struct mtk_thermal_bank *bank = &mt->banks[num];
+	const struct mtk_thermal_data *conf = mt->conf;
+	int i;
+
+	int offset = mt->conf->controller_offset[ctrl_id];
+	void __iomem *controller_base = mt->thermal_base + offset;
+
+	bank->id = num;
+	bank->mt = mt;
+
+	mtk_thermal_get_bank(bank);
+
+	/* bus clock 66M counting unit is 12 * 15.15ns * 256 = 46.540us */
+	writel(TEMP_MONCTL1_PERIOD_UNIT(12), controller_base + TEMP_MONCTL1);
+
+	/*
+	 * filt interval is 1 * 46.540us = 46.54us,
+	 * sen interval is 429 * 46.540us = 19.96ms
+	 */
+	writel(TEMP_MONCTL2_FILTER_INTERVAL(1) |
+			TEMP_MONCTL2_SENSOR_INTERVAL(429),
+			controller_base + TEMP_MONCTL2);
+
+	/* poll is set to 10u */
+	writel(TEMP_AHBPOLL_ADC_POLL_INTERVAL(768),
+	       controller_base + TEMP_AHBPOLL);
+
+	/* temperature sampling control, 1 sample */
+	writel(0x0, controller_base + TEMP_MSRCTL0);
+
+	/* exceed this polling time, IRQ would be inserted */
+	writel(0xffffffff, controller_base + TEMP_AHBTO);
+
+	/* number of interrupts per event, 1 is enough */
+	writel(0x0, controller_base + TEMP_MONIDET0);
+	writel(0x0, controller_base + TEMP_MONIDET1);
+
+	/*
+	 * The MT8173 thermal controller does not have its own ADC. Instead it
+	 * uses AHB bus accesses to control the AUXADC. To do this the thermal
+	 * controller has to be programmed with the physical addresses of the
+	 * AUXADC registers and with the various bit positions in the AUXADC.
+	 * Also the thermal controller controls a mux in the APMIXEDSYS register
+	 * space.
+	 */
+
+	/*
+	 * this value will be stored to TEMP_PNPMUXADDR (TEMP_SPARE0)
+	 * automatically by hw
+	 */
+	writel(BIT(conf->auxadc_channel), controller_base + TEMP_ADCMUX);
+
+	/* AHB address for auxadc mux selection */
+	writel(auxadc_phys_base + AUXADC_CON1_CLR_V,
+	       controller_base + TEMP_ADCMUXADDR);
+
+	if (mt->conf->version == MTK_THERMAL_V1) {
+		/* AHB address for pnp sensor mux selection */
+		writel(apmixed_phys_base + APMIXED_SYS_TS_CON1,
+		       controller_base + TEMP_PNPMUXADDR);
+	}
+
+	/* AHB value for auxadc enable */
+	writel(BIT(conf->auxadc_channel), controller_base + TEMP_ADCEN);
+
+	/* AHB address for auxadc enable (channel 0 immediate mode selected) */
+	writel(auxadc_phys_base + AUXADC_CON1_SET_V,
+	       controller_base + TEMP_ADCENADDR);
+
+	/* AHB address for auxadc valid bit */
+	writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel),
+	       controller_base + TEMP_ADCVALIDADDR);
+
+	/* AHB address for auxadc voltage output */
+	writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel),
+	       controller_base + TEMP_ADCVOLTADDR);
+
+	/* read valid & voltage are at the same register */
+	writel(0x0, controller_base + TEMP_RDCTRL);
+
+	/* indicate where the valid bit is */
+	writel(TEMP_ADCVALIDMASK_VALID_HIGH | TEMP_ADCVALIDMASK_VALID_POS(12),
+	       controller_base + TEMP_ADCVALIDMASK);
+
+	/* no shift */
+	writel(0x0, controller_base + TEMP_ADCVOLTAGESHIFT);
+
+	/* enable auxadc mux write transaction */
+	writel(TEMP_ADCWRITECTRL_ADC_MUX_WRITE,
+		controller_base + TEMP_ADCWRITECTRL);
+
+	for (i = 0; i < conf->bank_data[num].num_sensors; i++)
+		writel(conf->sensor_mux_values[conf->bank_data[num].sensors[i]],
+		       mt->thermal_base + conf->adcpnp[i]);
+
+	writel((1 << conf->bank_data[num].num_sensors) - 1,
+	       controller_base + TEMP_MONCTL0);
+
+	writel(TEMP_ADCWRITECTRL_ADC_PNP_WRITE |
+	       TEMP_ADCWRITECTRL_ADC_MUX_WRITE,
+	       controller_base + TEMP_ADCWRITECTRL);
+
+	mtk_thermal_put_bank(bank);
+}
+
+static u64 of_get_phys_base(struct device_node *np)
+{
+	u64 size64;
+	const __be32 *regaddr_p;
+
+	regaddr_p = of_get_address(np, 0, &size64, NULL);
+	if (!regaddr_p)
+		return OF_BAD_ADDR;
+
+	return of_translate_address(np, regaddr_p);
+}
+
+static int mtk_thermal_extract_efuse_v1(struct mtk_thermal *mt, u32 *buf)
+{
+	int i;
+
+	if (!(buf[0] & CALIB_BUF0_VALID_V1))
+		return -EINVAL;
+
+	mt->adc_ge = CALIB_BUF1_ADC_GE_V1(buf[1]);
+
+	for (i = 0; i < mt->conf->num_sensors; i++) {
+		switch (mt->conf->vts_index[i]) {
+		case VTS1:
+			mt->vts[VTS1] = CALIB_BUF0_VTS_TS1_V1(buf[0]);
+			break;
+		case VTS2:
+			mt->vts[VTS2] = CALIB_BUF0_VTS_TS2_V1(buf[0]);
+			break;
+		case VTS3:
+			mt->vts[VTS3] = CALIB_BUF1_VTS_TS3_V1(buf[1]);
+			break;
+		case VTS4:
+			mt->vts[VTS4] = CALIB_BUF2_VTS_TS4_V1(buf[2]);
+			break;
+		case VTS5:
+			mt->vts[VTS5] = CALIB_BUF2_VTS_TS5_V1(buf[2]);
+			break;
+		case VTSABB:
+			mt->vts[VTSABB] =
+				CALIB_BUF2_VTS_TSABB_V1(buf[2]);
+			break;
+		default:
+			break;
+		}
+	}
+
+	mt->degc_cali = CALIB_BUF0_DEGC_CALI_V1(buf[0]);
+	if (CALIB_BUF1_ID_V1(buf[1]) &
+	    CALIB_BUF0_O_SLOPE_SIGN_V1(buf[0]))
+		mt->o_slope = -CALIB_BUF0_O_SLOPE_V1(buf[0]);
+	else
+		mt->o_slope = CALIB_BUF0_O_SLOPE_V1(buf[0]);
+
+	return 0;
+}
+
+static int mtk_thermal_extract_efuse_v2(struct mtk_thermal *mt, u32 *buf)
+{
+	if (!CALIB_BUF1_VALID_V2(buf[1]))
+		return -EINVAL;
+
+	mt->adc_oe = CALIB_BUF0_ADC_OE_V2(buf[0]);
+	mt->adc_ge = CALIB_BUF0_ADC_GE_V2(buf[0]);
+	mt->degc_cali = CALIB_BUF0_DEGC_CALI_V2(buf[0]);
+	mt->o_slope = CALIB_BUF0_O_SLOPE_V2(buf[0]);
+	mt->vts[VTS1] = CALIB_BUF1_VTS_TS1_V2(buf[1]);
+	mt->vts[VTS2] = CALIB_BUF1_VTS_TS2_V2(buf[1]);
+	mt->vts[VTSABB] = CALIB_BUF1_VTS_TSABB_V2(buf[1]);
+	mt->o_slope_sign = CALIB_BUF1_O_SLOPE_SIGN_V2(buf[1]);
+
+	return 0;
+}
+
+static int mtk_thermal_extract_efuse_v3(struct mtk_thermal *mt, u32 *buf)
+{
+	if (!CALIB_BUF1_VALID_V3(buf[1]))
+		return -EINVAL;
+
+	mt->adc_oe = CALIB_BUF0_ADC_OE_V3(buf[0]);
+	mt->adc_ge = CALIB_BUF0_ADC_GE_V3(buf[0]);
+	mt->degc_cali = CALIB_BUF0_DEGC_CALI_V3(buf[0]);
+	mt->o_slope = CALIB_BUF0_O_SLOPE_V3(buf[0]);
+	mt->vts[VTS1] = CALIB_BUF1_VTS_TS1_V3(buf[1]);
+	mt->vts[VTS2] = CALIB_BUF1_VTS_TS2_V3(buf[1]);
+	mt->vts[VTSABB] = CALIB_BUF1_VTS_TSABB_V3(buf[1]);
+	mt->o_slope_sign = CALIB_BUF1_O_SLOPE_SIGN_V3(buf[1]);
+
+	if (CALIB_BUF1_ID_V3(buf[1]) == 0)
+		mt->o_slope = 0;
+
+	return 0;
+}
+
+static int mtk_thermal_get_calibration_data(struct device *dev,
+					    struct mtk_thermal *mt)
+{
+	struct nvmem_cell *cell;
+	u32 *buf;
+	size_t len;
+	int i, ret = 0;
+
+	/* Start with default values */
+	mt->adc_ge = 512;
+	mt->adc_oe = 512;
+	for (i = 0; i < mt->conf->num_sensors; i++)
+		mt->vts[i] = 260;
+	mt->degc_cali = 40;
+	mt->o_slope = 0;
+
+	cell = nvmem_cell_get(dev, "calibration-data");
+	if (IS_ERR(cell)) {
+		if (PTR_ERR(cell) == -EPROBE_DEFER)
+			return PTR_ERR(cell);
+		return 0;
+	}
+
+	buf = (u32 *)nvmem_cell_read(cell, &len);
+
+	nvmem_cell_put(cell);
+
+	if (IS_ERR(buf))
+		return PTR_ERR(buf);
+
+	if (len < 3 * sizeof(u32)) {
+		dev_warn(dev, "invalid calibration data\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (mt->conf->version == MTK_THERMAL_V1)
+		ret = mtk_thermal_extract_efuse_v1(mt, buf);
+	else if (mt->conf->version == MTK_THERMAL_V2)
+		ret = mtk_thermal_extract_efuse_v2(mt, buf);
+	else
+		ret = mtk_thermal_extract_efuse_v3(mt, buf);
+
+	if (ret) {
+		dev_info(dev, "Device not calibrated, using default calibration values\n");
+		ret = 0;
+	}
+
+out:
+	kfree(buf);
+
+	return ret;
+}
+
+static const struct of_device_id mtk_thermal_of_match[] = {
+	{
+		.compatible = "mediatek,mt8173-thermal",
+		.data = (void *)&mt8173_thermal_data,
+	},
+	{
+		.compatible = "mediatek,mt2701-thermal",
+		.data = (void *)&mt2701_thermal_data,
+	},
+	{
+		.compatible = "mediatek,mt2712-thermal",
+		.data = (void *)&mt2712_thermal_data,
+	},
+	{
+		.compatible = "mediatek,mt7622-thermal",
+		.data = (void *)&mt7622_thermal_data,
+	},
+	{
+		.compatible = "mediatek,mt8183-thermal",
+		.data = (void *)&mt8183_thermal_data,
+	},
+	{
+		.compatible = "mediatek,mt7981-thermal",
+		.data = (void *)&mt7981_thermal_data,
+	},
+	{
+		.compatible = "mediatek,mt7986-thermal",
+		.data = (void *)&mt7986_thermal_data,
+	}, {
+	},
+};
+MODULE_DEVICE_TABLE(of, mtk_thermal_of_match);
+
+static void mtk_thermal_turn_on_buffer(void __iomem *apmixed_base)
+{
+	int tmp;
+
+	tmp = readl(apmixed_base + APMIXED_SYS_TS_CON1);
+	tmp &= ~(0x37);
+	tmp |= 0x1;
+	writel(tmp, apmixed_base + APMIXED_SYS_TS_CON1);
+	udelay(200);
+}
+
+static void mtk_thermal_release_periodic_ts(struct mtk_thermal *mt,
+					    void __iomem *auxadc_base)
+{
+	int tmp;
+
+	writel(0x800, auxadc_base + AUXADC_CON1_SET_V);
+	writel(0x1, mt->thermal_base + TEMP_MONCTL0);
+	tmp = readl(mt->thermal_base + TEMP_MSRCTL1);
+	writel((tmp & (~0x10e)), mt->thermal_base + TEMP_MSRCTL1);
+}
+
+static int mtk_thermal_probe(struct platform_device *pdev)
+{
+	int ret, i, ctrl_id;
+	struct device_node *auxadc, *apmixedsys, *np = pdev->dev.of_node;
+	struct mtk_thermal *mt;
+	struct resource *res;
+	u64 auxadc_phys_base, apmixed_phys_base;
+	struct thermal_zone_device *tzdev;
+	void __iomem *apmixed_base, *auxadc_base;
+
+	mt = devm_kzalloc(&pdev->dev, sizeof(*mt), GFP_KERNEL);
+	if (!mt)
+		return -ENOMEM;
+
+	mt->conf = of_device_get_match_data(&pdev->dev);
+
+	mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm");
+	if (IS_ERR(mt->clk_peri_therm))
+		return PTR_ERR(mt->clk_peri_therm);
+
+	mt->clk_auxadc = devm_clk_get(&pdev->dev, "auxadc");
+	if (IS_ERR(mt->clk_auxadc))
+		return PTR_ERR(mt->clk_auxadc);
+
+	if (mt->conf->version == MTK_THERMAL_V3) {
+		mt->clk_adc_32k = devm_clk_get(&pdev->dev, "adc_32k");
+		if (IS_ERR(mt->clk_adc_32k))
+			return PTR_ERR(mt->clk_adc_32k);
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	mt->thermal_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(mt->thermal_base))
+		return PTR_ERR(mt->thermal_base);
+
+	ret = mtk_thermal_get_calibration_data(&pdev->dev, mt);
+	if (ret)
+		return ret;
+
+	mutex_init(&mt->lock);
+
+	mt->dev = &pdev->dev;
+
+	auxadc = of_parse_phandle(np, "mediatek,auxadc", 0);
+	if (!auxadc) {
+		dev_err(&pdev->dev, "missing auxadc node\n");
+		return -ENODEV;
+	}
+
+	auxadc_base = of_iomap(auxadc, 0);
+	auxadc_phys_base = of_get_phys_base(auxadc);
+
+	of_node_put(auxadc);
+
+	if (auxadc_phys_base == OF_BAD_ADDR) {
+		dev_err(&pdev->dev, "Can't get auxadc phys address\n");
+		return -EINVAL;
+	}
+
+	apmixedsys = of_parse_phandle(np, "mediatek,apmixedsys", 0);
+	if (!apmixedsys) {
+		dev_err(&pdev->dev, "missing apmixedsys node\n");
+		return -ENODEV;
+	}
+
+	apmixed_base = of_iomap(apmixedsys, 0);
+	apmixed_phys_base = of_get_phys_base(apmixedsys);
+
+	of_node_put(apmixedsys);
+
+	if (apmixed_phys_base == OF_BAD_ADDR) {
+		dev_err(&pdev->dev, "Can't get auxadc phys address\n");
+		return -EINVAL;
+	}
+
+	ret = device_reset_optional(&pdev->dev);
+	if (ret)
+		return ret;
+
+	if (mt->conf->version == MTK_THERMAL_V3) {
+		ret = clk_prepare_enable(mt->clk_adc_32k);
+		if (ret) {
+			dev_err(&pdev->dev, "Can't enable auxadc 32k clk: %d\n", ret);
+			return ret;
+		}
+	}
+
+	ret = clk_prepare_enable(mt->clk_auxadc);
+	if (ret) {
+		dev_err(&pdev->dev, "Can't enable auxadc clk: %d\n", ret);
+		goto err_disable_clk_adc_32k;
+	}
+
+	ret = clk_prepare_enable(mt->clk_peri_therm);
+	if (ret) {
+		dev_err(&pdev->dev, "Can't enable peri clk: %d\n", ret);
+		goto err_disable_clk_auxadc;
+	}
+
+	if (mt->conf->version == MTK_THERMAL_V2 ||
+	    mt->conf->version == MTK_THERMAL_V3) {
+		mtk_thermal_turn_on_buffer(apmixed_base);
+		mtk_thermal_release_periodic_ts(mt, auxadc_base);
+	}
+
+	for (ctrl_id = 0; ctrl_id < mt->conf->num_controller ; ctrl_id++)
+		for (i = 0; i < mt->conf->num_banks; i++)
+			mtk_thermal_init_bank(mt, i, apmixed_phys_base,
+					      auxadc_phys_base, ctrl_id);
+
+	platform_set_drvdata(pdev, mt);
+
+	tzdev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, mt,
+						     &mtk_thermal_ops);
+	if (IS_ERR(tzdev)) {
+		ret = PTR_ERR(tzdev);
+		goto err_disable_clk_peri_therm;
+	}
+
+	return 0;
+
+err_disable_clk_peri_therm:
+	clk_disable_unprepare(mt->clk_peri_therm);
+err_disable_clk_auxadc:
+	clk_disable_unprepare(mt->clk_auxadc);
+err_disable_clk_adc_32k:
+	if (mt->conf->version == MTK_THERMAL_V3)
+		clk_disable_unprepare(mt->clk_adc_32k);
+
+	return ret;
+}
+
+static int mtk_thermal_remove(struct platform_device *pdev)
+{
+	struct mtk_thermal *mt = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(mt->clk_peri_therm);
+	clk_disable_unprepare(mt->clk_auxadc);
+
+	if (mt->conf->version == MTK_THERMAL_V3)
+		clk_disable_unprepare(mt->clk_adc_32k);
+
+	return 0;
+}
+
+static struct platform_driver mtk_thermal_driver = {
+	.probe = mtk_thermal_probe,
+	.remove = mtk_thermal_remove,
+	.driver = {
+		.name = "mtk-thermal",
+		.of_match_table = mtk_thermal_of_match,
+	},
+};
+
+module_platform_driver(mtk_thermal_driver);
+
+MODULE_AUTHOR("Michael Kao <michael.kao@mediatek.com>");
+MODULE_AUTHOR("Louis Yu <louis.yu@mediatek.com>");
+MODULE_AUTHOR("Dawei Chien <dawei.chien@mediatek.com>");
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_AUTHOR("Hanyi Wu <hanyi.wu@mediatek.com>");
+MODULE_DESCRIPTION("Mediatek thermal driver");
+MODULE_LICENSE("GPL v2");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/unusual-declaration.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/unusual-declaration.h
new file mode 100644
index 0000000..f517e20
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/unusual-declaration.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * xhci-mtk-unusuallib.h -- xhci toolkit header file
+ *
+ * Copyright (C) 2021 Mediatek Inc - http://www.mediatek.com
+ *
+ * Author: Zhanyong Wang <zhanyong.wang@mediatek.com>
+ */
+
+ DEVICE_ATTR_DECLARED(RG_USB20_INTR_EN);
+ DEVICE_ATTR_DECLARED(RG_USB20_VRT_VREF_SEL);
+ DEVICE_ATTR_DECLARED(RG_USB20_TERM_VREF_SEL);
+ DEVICE_ATTR_DECLARED(RG_USB20_HSTX_SRCTRL);
+ DEVICE_ATTR_DECLARED(RG_USB20_DISCTH);
+ DEVICE_ATTR_DECLARED(RG_CHGDT_EN);
+
+ #define HQA_INFORMACTION_COLLECTS() do {\
+	ECHO_HQA(USB20_PHY_USBPHYACR0, RG_USB20_INTR_EN, 1); \
+	ECHO_HQA(USB20_PHY_USBPHYACR1, RG_USB20_VRT_VREF_SEL, 3); \
+	ECHO_HQA(USB20_PHY_USBPHYACR1, RG_USB20_TERM_VREF_SEL, 3); \
+	ECHO_HQA(USB20_PHY_USBPHYACR5, RG_USB20_HSTX_SRCTRL, 3); \
+	ECHO_HQA(USB20_PHY_USBPHYACR6, RG_USB20_DISCTH, 4); \
+	ECHO_HQA(USB20_PHY_U2PHYBC12C, RG_CHGDT_EN, 1); \
+	} while (0)
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/unusual-statement.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/unusual-statement.h
new file mode 100644
index 0000000..b929342
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/unusual-statement.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * xhci-mtk-unusuallib.h -- xhci toolkit header file
+ *
+ * Copyright (C) 2021 Mediatek Inc - http://www.mediatek.com
+ *
+ * Author: Zhanyong Wang <zhanyong.wang@mediatek.com>
+ */
+
+UNUSUAL_DEVICE_ATTR(RG_USB20_INTR_EN),
+UNUSUAL_DEVICE_ATTR(RG_USB20_VRT_VREF_SEL),
+UNUSUAL_DEVICE_ATTR(RG_USB20_TERM_VREF_SEL),
+UNUSUAL_DEVICE_ATTR(RG_USB20_HSTX_SRCTRL),
+UNUSUAL_DEVICE_ATTR(RG_USB20_DISCTH),
+UNUSUAL_DEVICE_ATTR(RG_CHGDT_EN),
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-chgdt-en.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-chgdt-en.c
new file mode 100644
index 0000000..13626c1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-chgdt-en.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * xHCI host controller toolkit driver for chgdt-en
+ *
+ * Copyright (C) 2021  MediaTek Inc.
+ *
+ *  Author: Zhanyong Wang <zhanyong.wang@mediatek.com>
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include "xhci-mtk.h"
+#include "xhci-mtk-test.h"
+#include "xhci-mtk-unusual.h"
+
+static ssize_t RG_CHGDT_EN_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = mtk->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	ssize_t cnt = 0;
+	void __iomem *addr;
+	u32 val;
+	u32 i;
+	int ports;
+	char str[32];
+	int index = 0;
+	u32 io, length;
+	int ret;
+
+	ports = mtk->num_u3_ports + mtk->num_u2_ports;
+	cnt += sprintf(buf + cnt, " RG_CHGDT_EN usage:\n");
+	cnt += sprintf(buf + cnt,
+		"   echo u2p index 1b0 > RG_CHGDT_EN\n");
+	if (mtk->num_u3_ports + 1 != ports)
+		cnt += sprintf(buf + cnt, "	parameter: u2p: %i ~ %i\n",
+					mtk->num_u3_ports + 1, ports);
+	else
+		cnt += sprintf(buf + cnt, "	parameter: u2p: %i\n",
+					mtk->num_u3_ports + 1);
+	if (mtk->num_u2_ports > 1)
+		cnt += sprintf(buf + cnt, "	parameter: index: 0 ~ %i\n",
+			       mtk->num_u2_ports);
+	else
+		cnt += sprintf(buf + cnt, "	parameter: index: 0\n");
+
+	cnt += sprintf(buf + cnt, " e.g.: echo 2 0 1b1 > RG_CHGDT_EN\n");
+	cnt += sprintf(buf + cnt,
+		"  port2 binding phy 0, enable 1b'1 as CHGDT_EN\n");
+
+	cnt += sprintf(buf + cnt,
+			"\n=========current HQA setting check=========\n");
+	for (i = 1; i <= ports; i++) {
+		addr = &xhci->op_regs->port_status_base +
+			NUM_PORT_REGS * ((i - 1) & 0xff);
+		val = readl(addr);
+		if (i <= mtk->num_u3_ports) {
+			cnt += sprintf(buf + cnt,
+				       "USB30 Port%i: 0x%08X\n", i, val);
+		} else {
+			cnt += sprintf(buf + cnt,
+				       "USB20 Port%i: 0x%08X\n", i, val);
+
+			ret = query_phy_addr(dev->of_node,
+						 &index, &io, &length);
+			if (ret && ret != -EACCES) {
+				if (ret == -EPERM)
+					cnt += sprintf(buf + cnt,
+					"USB20 Port%i (Phy%i: absent)\n",
+					i, index);
+				else
+					cnt += sprintf(buf + cnt,
+					"USB20 Port%i (Phy%i) failure %i\n",
+						 i, index, ret);
+				continue;
+			}
+
+			cnt += sprintf(buf + cnt,
+				"USB20 Port%i (Phy%i:%sable): 0x%08X 0x%08X\n",
+				i, index, ret ? " dis" : " en", io, length);
+
+			addr   = ioremap_nocache(io, length);
+			addr  += (length != 0x100) ? 0x300 : 0;
+
+			HQA_INFORMACTION_COLLECTS();
+
+			iounmap(addr);
+			index ++;
+		}
+	}
+
+	if (mtk->hqa_pos) {
+		cnt += sprintf(buf + cnt, "%s", mtk->hqa_buf);
+		mtk->hqa_pos = 0;
+	}
+
+	return cnt;
+}
+
+static ssize_t RG_CHGDT_EN_store(struct device *dev,
+                        struct device_attribute *attr,
+                        const char *buf, size_t n)
+{
+	u32 val;
+	u32 io;
+	u32 length;
+	int ports;
+	int words;
+	int port;
+	int index;
+	int ret;
+	char *str = NULL;
+	void __iomem *addr;
+	struct xhci_hcd_mtk *mtk  = dev_get_drvdata(dev);
+	struct device_node  *node = dev->of_node;
+
+	ports = mtk->num_u3_ports + mtk->num_u2_ports;
+	mtk->hqa_pos = 0;
+
+	memset(mtk->hqa_buf, 0, mtk->hqa_size);
+
+	str = kzalloc(n, GFP_ATOMIC);
+
+	hqa_info(mtk, "RG_CHGDT_EN(%lu): %s\n", n, buf);
+
+	words = sscanf(buf, "%i %i 1b%1[0,1]", &port, &index, str);
+	if ((words != 3) ||
+	    (port < mtk->num_u3_ports || port > ports)) {
+		hqa_info(mtk, "Check params(%i):\" %i %i %s\", Please!\n",
+			words, port, index, str);
+
+		ret = -EINVAL;
+		goto error;
+	}
+
+	hqa_info(mtk, " params: %i %i %s\n",
+		port, index, str);
+
+	ret = query_phy_addr(node, &index, &io, &length);
+	if (ret && ret != -EACCES)
+		goto error;
+
+	io += (length != 0x100) ? 0x300 : 0;
+	io += USB20_PHY_U2PHYBC12C;
+
+	addr = ioremap_nocache(io, 4);
+	val = binary_write_width1(addr, SHFT_RG_CHGDT_EN, str);
+	hqa_info(mtk, "Port%i(Phy%i)[0x%08X]: 0x%08X but 0x%08X\n",
+		port, index, io, val, readl(addr));
+
+	iounmap(addr);
+	ret = n;
+
+error:
+	kfree(str);
+	return ret;
+}
+DEVICE_ATTR_RW(RG_CHGDT_EN);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-discth.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-discth.c
new file mode 100644
index 0000000..66a024a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-discth.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * xHCI host controller toolkit driver for usb20 discth
+ *
+ * Copyright (C) 2021  MediaTek Inc.
+ *
+ *  Author: Zhanyong Wang <zhanyong.wang@mediatek.com>
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include "xhci-mtk.h"
+#include "xhci-mtk-test.h"
+#include "xhci-mtk-unusual.h"
+
+static ssize_t RG_USB20_DISCTH_show(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+	struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = mtk->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	ssize_t cnt = 0;
+	void __iomem *addr;
+	u32 val;
+	u32 i;
+	int ports;
+	char str[32];
+	int index = 0;
+	u32 io, length;
+	int ret;
+
+	ports = mtk->num_u3_ports + mtk->num_u2_ports;
+	cnt += sprintf(buf + cnt, " RG_USB20_DISCTH usage:\n");
+	cnt += sprintf(buf + cnt,
+		"   echo u2p index 4b0011 > RG_USB20_DISCTH\n");
+	if (mtk->num_u3_ports + 1 != ports)
+		cnt += sprintf(buf + cnt, "	parameter: u2p: %i ~ %i\n",
+					mtk->num_u3_ports + 1, ports);
+	else
+		cnt += sprintf(buf + cnt, "	parameter: u2p: %i\n",
+					mtk->num_u3_ports + 1);
+
+	if (mtk->num_u2_ports > 1)
+		cnt += sprintf(buf + cnt, "	parameter: index: 0 ~ %i\n",
+			       mtk->num_u2_ports);
+	else
+		cnt += sprintf(buf + cnt, "	parameter: index: 0\n");
+
+	cnt += sprintf(buf + cnt,
+			 " e.g.: echo 2 0 4b1010 > RG_USB20_DISCTH\n");
+	cnt += sprintf(buf + cnt,
+		"  port2 binding phy 0, tune 4b'1010 as DISCTH value\n");
+
+	cnt += sprintf(buf + cnt,
+			"\n=========current HQA setting check=========\n");
+	for (i = 1; i <= ports; i++) {
+		addr = &xhci->op_regs->port_status_base +
+			NUM_PORT_REGS * ((i - 1) & 0xff);
+		val = readl(addr);
+		if (i <= mtk->num_u3_ports) {
+			cnt += sprintf(buf + cnt,
+				       "USB30 Port%i: 0x%08X\n", i, val);
+		} else {
+			cnt += sprintf(buf + cnt,
+				       "USB20 Port%i: 0x%08X\n", i, val);
+
+			ret = query_phy_addr(dev->of_node,
+						 &index, &io, &length);
+			if (ret && ret != -EACCES) {
+				if (ret == -EPERM)
+					cnt += sprintf(buf + cnt,
+					"USB20 Port%i (Phy%i: absent)\n",
+					i, index);
+				else
+					cnt += sprintf(buf + cnt,
+					"USB20 Port%i (Phy%i) failure %i\n",
+						 i, index, ret);
+				continue;
+			}
+
+			cnt += sprintf(buf + cnt,
+				"USB20 Port%i (Phy%i:%sable): 0x%08X 0x%08X\n",
+				i, index, ret ? " dis" : " en", io, length);
+
+			addr   = ioremap_nocache(io, length);
+			addr  += (length != 0x100) ? 0x300 : 0;
+
+			HQA_INFORMACTION_COLLECTS();
+
+			iounmap(addr);
+			index ++;
+		}
+	}
+
+	if (mtk->hqa_pos) {
+		cnt += sprintf(buf + cnt, "%s", mtk->hqa_buf);
+		mtk->hqa_pos = 0;
+	}
+
+	return cnt;
+}
+
+static ssize_t RG_USB20_DISCTH_store(struct device *dev,
+                        struct device_attribute *attr,
+                        const char *buf, size_t n)
+{
+	u32 val;
+	u32 io;
+	u32 length;
+	int ports;
+	int words;
+	int port;
+	int index;
+	int ret;
+	char *str = NULL;
+	void __iomem *addr;
+	struct xhci_hcd_mtk *mtk  = dev_get_drvdata(dev);
+	struct device_node  *node = dev->of_node;
+
+	ports = mtk->num_u3_ports + mtk->num_u2_ports;
+	mtk->hqa_pos = 0;
+
+	memset(mtk->hqa_buf, 0, mtk->hqa_size);
+
+	str = kzalloc(n, GFP_ATOMIC);
+
+	hqa_info(mtk, "RG_USB20_DISCTH(%lu): %s\n", n, buf);
+
+	words = sscanf(buf, "%i %i 4b%4[0,1]", &port, &index, str);
+	if ((words != 3) ||
+	    (port < mtk->num_u3_ports || port > ports)) {
+		hqa_info(mtk, "Check params(%i):\" %i %i %s\", Please!\n",
+			words, port, index, str);
+
+		ret = -EINVAL;
+		goto error;
+	}
+
+	hqa_info(mtk, " params: %i %i %s\n",
+		port, index, str);
+
+	ret = query_phy_addr(node, &index, &io, &length);
+	if (ret && ret != -EACCES)
+		goto error;
+
+	io += (length != 0x100) ? 0x300 : 0;
+	io += USB20_PHY_USBPHYACR6;
+
+	addr = ioremap_nocache(io, 4);
+	val = binary_write_width4(addr, SHFT_RG_USB20_DISCTH, str);
+	hqa_info(mtk, "Port%i(Phy%i)[0x%08X]: 0x%08X but 0x%08X\n",
+		port, index, io, val, readl(addr));
+
+	iounmap(addr);
+	ret = n;
+
+error:
+	kfree(str);
+	return ret;
+}
+DEVICE_ATTR_RW(RG_USB20_DISCTH);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-hstx-srctrl.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-hstx-srctrl.c
new file mode 100644
index 0000000..a7791cf
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-hstx-srctrl.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * xHCI host controller toolkit driver for hstx-srctrl
+ *
+ * Copyright (C) 2021  MediaTek Inc.
+ *
+ *  Author: Zhanyong Wang <zhanyong.wang@mediatek.com>
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include "xhci-mtk.h"
+#include "xhci-mtk-test.h"
+#include "xhci-mtk-unusual.h"
+
+static ssize_t RG_USB20_HSTX_SRCTRL_show(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+	struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = mtk->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	ssize_t cnt = 0;
+	void __iomem *addr;
+	u32 val;
+	u32 i;
+	int ports;
+	char str[32];
+	int index = 0;
+	u32 io, length;
+	int ret;
+
+	ports = mtk->num_u3_ports + mtk->num_u2_ports;
+	cnt += sprintf(buf + cnt, " RG_USB20_HSTX_SRCTRL usage:\n");
+	cnt += sprintf(buf + cnt,
+	"   echo u2p index 3b011 > RG_USB20_HSTX_SRCTRL\n");
+	if (mtk->num_u3_ports + 1 != ports)
+		cnt += sprintf(buf + cnt, "	parameter: u2p: %i ~ %i\n",
+					mtk->num_u3_ports + 1, ports);
+	else
+		cnt += sprintf(buf + cnt, "	parameter: u2p: %i\n",
+					mtk->num_u3_ports + 1);
+
+	if (mtk->num_u2_ports > 1)
+		cnt += sprintf(buf + cnt, "	parameter: index: 0 ~ %i\n",
+			       mtk->num_u2_ports);
+	else
+		cnt += sprintf(buf + cnt, "	parameter: index: 0\n");
+
+	cnt += sprintf(buf + cnt,
+			 " e.g.: echo 2 0 3b010 > RG_USB20_HSTX_SRCTRL\n");
+	cnt += sprintf(buf + cnt,
+	"  port2 binding phy 0, tune 3b'010 as HSTX_SRCTRL value\n");
+
+	cnt += sprintf(buf + cnt,
+			"\n=========current HQA setting check=========\n");
+	for (i = 1; i <= ports; i++) {
+		addr = &xhci->op_regs->port_status_base +
+			NUM_PORT_REGS * ((i - 1) & 0xff);
+		val = readl(addr);
+		if (i <= mtk->num_u3_ports) {
+			cnt += sprintf(buf + cnt,
+				       "USB30 Port%i: 0x%08X\n", i, val);
+		} else {
+			cnt += sprintf(buf + cnt,
+				       "USB20 Port%i: 0x%08X\n", i, val);
+
+			ret = query_phy_addr(dev->of_node,
+						 &index, &io, &length);
+			if (ret && ret != -EACCES) {
+				if (ret == -EPERM)
+					cnt += sprintf(buf + cnt,
+					"USB20 Port%i (Phy%i: absent)\n",
+					i, index);
+				else
+					cnt += sprintf(buf + cnt,
+					"USB20 Port%i (Phy%i) failure %i\n",
+						 i, index, ret);
+				continue;
+			}
+
+			cnt += sprintf(buf + cnt,
+				"USB20 Port%i (Phy%i:%sable): 0x%08X 0x%08X\n",
+				i, index, ret ? " dis" : " en", io, length);
+
+			addr   = ioremap_nocache(io, length);
+			addr  += (length != 0x100) ? 0x300 : 0;
+
+			HQA_INFORMACTION_COLLECTS();
+
+			iounmap(addr);
+			index ++;
+		}
+	}
+
+	if (mtk->hqa_pos) {
+		cnt += sprintf(buf + cnt, "%s", mtk->hqa_buf);
+		mtk->hqa_pos = 0;
+	}
+
+	return cnt;
+}
+
+static ssize_t RG_USB20_HSTX_SRCTRL_store(struct device *dev,
+                        struct device_attribute *attr,
+                        const char *buf, size_t n)
+{
+	u32 val;
+	u32 io;
+	u32 length;
+	int ports;
+	int words;
+	int port;
+	int index;
+	int ret;
+	char *str = NULL;
+	void __iomem *addr;
+	struct xhci_hcd_mtk *mtk  = dev_get_drvdata(dev);
+	struct device_node  *node = dev->of_node;
+
+	ports = mtk->num_u3_ports + mtk->num_u2_ports;
+	mtk->hqa_pos = 0;
+
+	memset(mtk->hqa_buf, 0, mtk->hqa_size);
+
+	str = kzalloc(n, GFP_ATOMIC);
+
+	hqa_info(mtk, "RG_USB20_HSTX_SRCTRL(%lu): %s\n", n, buf);
+
+	words = sscanf(buf, "%i %i 3b%3[0,1]", &port, &index, str);
+	if ((words != 3) ||
+	    (port < mtk->num_u3_ports || port > ports)) {
+		hqa_info(mtk, "Check params(%i):\" %i %i %s\", Please!\n",
+			words, port, index, str);
+
+		ret = -EINVAL;
+		goto error;
+	}
+
+	hqa_info(mtk, " params: %i %i %s\n",
+		port, index, str);
+
+	ret = query_phy_addr(node, &index, &io, &length);
+	if (ret && ret != -EACCES)
+		goto error;
+
+	io += (length != 0x100) ? 0x300 : 0;
+	io += USB20_PHY_USBPHYACR5;
+
+	addr = ioremap_nocache(io, 4);
+	val = binary_write_width3(addr, SHFT_RG_USB20_HSTX_SRCTRL, str);
+	hqa_info(mtk, "Port%i(Phy%i)[0x%08X]: 0x%08X but 0x%08X\n",
+		port, index, io, val, readl(addr));
+
+	iounmap(addr);
+	ret = n;
+
+error:
+	kfree(str);
+	return ret;
+}
+DEVICE_ATTR_RW(RG_USB20_HSTX_SRCTRL);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-intr-en.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-intr-en.c
new file mode 100644
index 0000000..acdaf8b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-intr-en.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * xHCI host controller toolkit driver for intr-en
+ *
+ * Copyright (C) 2021  MediaTek Inc.
+ *
+ *  Author: Zhanyong Wang <zhanyong.wang@mediatek.com>
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include "xhci-mtk.h"
+#include "xhci-mtk-test.h"
+#include "xhci-mtk-unusual.h"
+
+static ssize_t RG_USB20_INTR_EN_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = mtk->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	ssize_t cnt = 0;
+	void __iomem *addr;
+	u32 val;
+	u32 i;
+	int ports;
+	char str[32];
+	int index = 0;
+	u32 io, length;
+	int ret;
+
+	ports = mtk->num_u3_ports + mtk->num_u2_ports;
+	cnt += sprintf(buf + cnt, " RG_USB20_INTR_EN usage:\n");
+	cnt += sprintf(buf + cnt,
+                "   echo u2p index 1b0 > RG_USB20_INTR_EN\n");
+	if (mtk->num_u3_ports + 1 != ports)
+		cnt += sprintf(buf + cnt, "	parameter: u2p: %i ~ %i\n",
+					mtk->num_u3_ports + 1, ports);
+	else
+		cnt += sprintf(buf + cnt, "	parameter: u2p: %i\n",
+					mtk->num_u3_ports + 1);
+
+	if (mtk->num_u2_ports > 1)
+		cnt += sprintf(buf + cnt, "	parameter: index: 0 ~ %i\n",
+			       mtk->num_u2_ports);
+	else
+		cnt += sprintf(buf + cnt, "	parameter: index: 0\n");
+
+	cnt += sprintf(buf + cnt, " e.g.: echo 2 0 1b1 > RG_USB20_INTR_EN\n");
+	cnt += sprintf(buf + cnt,
+		"  port2 binding phy 0, enable 1b'1 as INTR_EN\n");
+
+	cnt += sprintf(buf + cnt,
+			"\n=========current HQA setting check=========\n");
+	for (i = 1; i <= ports; i++) {
+		addr = &xhci->op_regs->port_status_base +
+			NUM_PORT_REGS * ((i - 1) & 0xff);
+		val = readl(addr);
+		if (i <= mtk->num_u3_ports) {
+			cnt += sprintf(buf + cnt,
+				       "USB30 Port%i: 0x%08X\n", i, val);
+		} else {
+			cnt += sprintf(buf + cnt,
+				       "USB20 Port%i: 0x%08X\n", i, val);
+
+			ret = query_phy_addr(dev->of_node,
+						 &index, &io, &length);
+			if (ret && ret != -EACCES) {
+				if (ret == -EPERM)
+					cnt += sprintf(buf + cnt,
+					"USB20 Port%i (Phy%i: absent)\n",
+					i, index);
+				else
+					cnt += sprintf(buf + cnt,
+					"USB20 Port%i (Phy%i) failure %i\n",
+						 i, index, ret);
+				continue;
+			}
+
+			cnt += sprintf(buf + cnt,
+				"USB20 Port%i (Phy%i:%sable): 0x%08X 0x%08X\n",
+				i, index, ret ? " dis" : " en", io, length);
+
+			addr   = ioremap_nocache(io, length);
+			addr  += (length != 0x100) ? 0x300 : 0;
+
+			HQA_INFORMACTION_COLLECTS();
+
+			iounmap(addr);
+			index ++;
+		}
+	}
+
+	if (mtk->hqa_pos) {
+		cnt += sprintf(buf + cnt, "%s", mtk->hqa_buf);
+		mtk->hqa_pos = 0;
+	}
+
+	return cnt;
+}
+
+static ssize_t RG_USB20_INTR_EN_store(struct device *dev,
+                        struct device_attribute *attr,
+                        const char *buf, size_t n)
+{
+	u32 val;
+	u32 io;
+	u32 length;
+	int ports;
+	int words;
+	int port;
+	int index;
+	int ret;
+	char *str = NULL;
+	void __iomem *addr;
+	struct xhci_hcd_mtk *mtk  = dev_get_drvdata(dev);
+	struct device_node  *node = dev->of_node;
+
+	ports = mtk->num_u3_ports + mtk->num_u2_ports;
+	mtk->hqa_pos = 0;
+
+	memset(mtk->hqa_buf, 0, mtk->hqa_size);
+
+	str = kzalloc(n, GFP_ATOMIC);
+
+	hqa_info(mtk, "RG_USB20_INTR_EN(%lu): %s\n", n, buf);
+
+	words = sscanf(buf, "%i %i 1b%1[0,1]", &port, &index, str);
+	if ((words != 3) ||
+	    (port < mtk->num_u3_ports || port > ports)) {
+		hqa_info(mtk, "Check params(%i):\" %i %i %s\", Please!\n",
+			words, port, index, str);
+
+		ret = -EINVAL;
+		goto error;
+	}
+
+	hqa_info(mtk, " params: %i %i %s\n",
+		port, index, str);
+
+	ret = query_phy_addr(node, &index, &io, &length);
+	if (ret && ret != -EACCES)
+		goto error;
+
+	io += (length != 0x100) ? 0x300 : 0;
+	io += USB20_PHY_USBPHYACR0;
+
+	addr = ioremap_nocache(io, 4);
+	val = binary_write_width1(addr, SHFT_RG_USB20_INTR_EN, str);
+	hqa_info(mtk, "Port%i(Phy%i)[0x%08X]: 0x%08X but 0x%08X\n",
+		port, index, io, val, readl(addr));
+
+	iounmap(addr);
+	ret = n;
+
+error:
+	kfree(str);
+	return ret;
+}
+DEVICE_ATTR_RW(RG_USB20_INTR_EN);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-term-vref.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-term-vref.c
new file mode 100644
index 0000000..3b40ef9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-term-vref.c
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * xHCI host controller toolkit driver for term vref
+ *
+ * Copyright (C) 2021  MediaTek Inc.
+ *
+ *  Author: Zhanyong Wang <zhanyong.wang@mediatek.com>
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include "xhci-mtk.h"
+#include "xhci-mtk-test.h"
+#include "xhci-mtk-unusual.h"
+
+static
+ssize_t RG_USB20_TERM_VREF_SEL_show(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+	struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = mtk->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	ssize_t cnt = 0;
+	void __iomem *addr;
+	u32 val;
+	u32 i;
+	int ports;
+	char str[32];
+	int index = 0;
+	u32 io, length;
+	int ret;
+
+	ports = mtk->num_u3_ports + mtk->num_u2_ports;
+	cnt += sprintf(buf + cnt, " RG_USB20_TERM_VREF_SEL usage:\n");
+	cnt += sprintf(buf + cnt,
+		"   echo u2p index 3b011 > RG_USB20_TERM_VREF_SEL\n");
+	if (mtk->num_u3_ports + 1 != ports)
+		cnt += sprintf(buf + cnt, "	parameter: u2p: %i ~ %i\n",
+					mtk->num_u3_ports + 1, ports);
+	else
+		cnt += sprintf(buf + cnt, "	parameter: u2p: %i\n",
+					mtk->num_u3_ports + 1);
+
+	if (mtk->num_u2_ports > 1)
+		cnt += sprintf(buf + cnt, "	parameter: index: 0 ~ %i\n",
+			       mtk->num_u2_ports);
+	else
+		cnt += sprintf(buf + cnt, "	parameter: index: 0\n");
+
+	cnt += sprintf(buf + cnt,
+			 " e.g.: echo 2 0 3b010 > RG_USB20_TERM_VREF_SEL\n");
+	cnt += sprintf(buf + cnt,
+		"  port2 binding phy 0, tune 3b'010 as TERM_VREF value\n");
+
+	cnt += sprintf(buf + cnt,
+			"\n=========current HQA setting check=========\n");
+	for (i = 1; i <= ports; i++) {
+		addr = &xhci->op_regs->port_status_base +
+			NUM_PORT_REGS * ((i - 1) & 0xff);
+		val = readl(addr);
+		if (i <= mtk->num_u3_ports) {
+			cnt += sprintf(buf + cnt,
+				       "USB30 Port%i: 0x%08X\n", i, val);
+		} else {
+			cnt += sprintf(buf + cnt,
+				       "USB20 Port%i: 0x%08X\n", i, val);
+
+			ret = query_phy_addr(dev->of_node,
+						 &index, &io, &length);
+			if (ret && ret != -EACCES) {
+				if (ret == -EPERM)
+					cnt += sprintf(buf + cnt,
+					"USB20 Port%i (Phy%i: absent)\n",
+					i, index);
+				else
+					cnt += sprintf(buf + cnt,
+					"USB20 Port%i (Phy%i) failure %i\n",
+						 i, index, ret);
+				continue;
+			}
+
+			cnt += sprintf(buf + cnt,
+				"USB20 Port%i (Phy%i:%sable): 0x%08X 0x%08X\n",
+				i, index, ret ? " dis" : " en", io, length);
+
+			addr   = ioremap_nocache(io, length);
+			addr  += (length != 0x100) ? 0x300 : 0;
+
+			HQA_INFORMACTION_COLLECTS();
+
+			iounmap(addr);
+			index ++;
+		}
+	}
+
+	if (mtk->hqa_pos) {
+		cnt += sprintf(buf + cnt, "%s", mtk->hqa_buf);
+		mtk->hqa_pos = 0;
+	}
+
+	return cnt;
+}
+
+static
+ssize_t RG_USB20_TERM_VREF_SEL_store(struct device *dev,
+                        struct device_attribute *attr,
+                        const char *buf, size_t n)
+{
+	u32 val;
+	u32 io;
+	u32 length;
+	int ports;
+	int words;
+	int port;
+	int index;
+	int ret;
+	char *str = NULL;
+	void __iomem *addr;
+	struct xhci_hcd_mtk *mtk  = dev_get_drvdata(dev);
+	struct device_node  *node = dev->of_node;
+
+	ports = mtk->num_u3_ports + mtk->num_u2_ports;
+	mtk->hqa_pos = 0;
+
+	memset(mtk->hqa_buf, 0, mtk->hqa_size);
+
+	str = kzalloc(n, GFP_ATOMIC);
+
+	hqa_info(mtk, "RG_USB20_TERM_VREF_SEL(%lu): %s\n", n, buf);
+
+	words = sscanf(buf, "%i %i 3b%3[0,1]", &port, &index, str);
+	if ((words != 3) ||
+	    (port < mtk->num_u3_ports || port > ports)) {
+		hqa_info(mtk, "Check params(%i):\" %i %i %s\", Please!\n",
+			words, port, index, str);
+
+		ret = -EINVAL;
+		goto error;
+	}
+
+	hqa_info(mtk, " params: %i %i %s\n",
+		port, index, str);
+
+	ret = query_phy_addr(node, &index, &io, &length);
+	if (ret && ret != -EACCES)
+		goto error;
+
+	io += (length != 0x100) ? 0x300 : 0;
+	io += USB20_PHY_USBPHYACR1;
+
+	addr = ioremap_nocache(io, 4);
+	val = binary_write_width3(addr, SHFT_RG_USB20_TERM_VREF_SEL, str);
+	hqa_info(mtk, "Port%i(Phy%i)[0x%08X]: 0x%08X but 0x%08X\n",
+		port, index, io, val, readl(addr));
+
+	iounmap(addr);
+	ret = n;
+
+error:
+	kfree(str);
+	return ret;
+}
+DEVICE_ATTR_RW(RG_USB20_TERM_VREF_SEL);
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-test.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-test.c
new file mode 100644
index 0000000..4939e55
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-test.c
@@ -0,0 +1,617 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * xHCI host controller toolkit driver
+ *
+ * Copyright (C) 2021  MediaTek Inc.
+ *
+ *  Author: Zhanyong Wang <zhanyong.wang@mediatek.com>
+ *          Shaocheng.Wang <shaocheng.wang@mediatek.com>
+ *          Chunfeng.Yun <chunfeng.yun@mediatek.com>
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/kobject.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <dt-bindings/phy/phy.h>
+#include "../core/usb.h"
+#include "xhci-mtk.h"
+#include "xhci-mtk-test.h"
+#include "xhci-mtk-unusual.h"
+
+static int t_test_j(struct xhci_hcd_mtk *mtk, int argc, char **argv);
+static int t_test_k(struct xhci_hcd_mtk *mtk, int argc, char **argv);
+static int t_test_se0(struct xhci_hcd_mtk *mtk, int argc, char **argv);
+static int t_test_packet(struct xhci_hcd_mtk *mtk, int argc, char **argv);
+static int t_test_suspend(struct xhci_hcd_mtk *mtk, int argc, char **argv);
+static int t_test_resume(struct xhci_hcd_mtk *mtk, int argc, char **argv);
+static int t_test_get_device_descriptor(struct xhci_hcd_mtk *mtk,
+				int argc, char **argv);
+static int t_test_enumerate_bus(struct xhci_hcd_mtk *mtk,
+				int argc, char **argv);
+static int t_power_u1u2(struct xhci_hcd_mtk *mtk, int argc, char **argv);
+
+#define PORT_PLS_VALUE(p) ((p >> 5) & 0xf)
+
+#define MAX_NAME_SIZE 32
+#define MAX_ARG_SIZE 4
+
+struct hqa_test_cmd {
+	char name[MAX_NAME_SIZE];
+	int (*cb_func)(struct xhci_hcd_mtk *mtk, int argc, char **argv);
+	char *discription;
+};
+
+
+struct hqa_test_cmd xhci_mtk_hqa_cmds[] = {
+	{"test.j", &t_test_j, "Test_J"},
+	{"test.k", &t_test_k, "Test_K"},
+	{"test.se0", &t_test_se0, "Test_SE0_NAK"},
+	{"test.packet", &t_test_packet, "Test_PACKET"},
+	{"test.suspend", &t_test_suspend, "Port Suspend"},
+	{"test.resume", &t_test_resume, "Port Resume"},
+	{"test.enumbus", &t_test_enumerate_bus, "Enumerate Bus"},
+	{"test.getdesc", &t_test_get_device_descriptor,
+				"Get Device Discriptor"},
+	{"pm.u1u2", &t_power_u1u2, "Port U1,U2"},
+	{"", NULL, ""},
+};
+
+
+int call_hqa_func(struct xhci_hcd_mtk *mtk, char *buf)
+{
+	struct hqa_test_cmd *hqa;
+	struct usb_hcd *hcd = mtk->hcd;
+	char *argv[MAX_ARG_SIZE];
+	int argc;
+	int i;
+
+	argc = 0;
+	do {
+		argv[argc] = strsep(&buf, " ");
+		xhci_err(hcd_to_xhci(hcd), "[%d] %s\r\n", argc, argv[argc]);
+		argc++;
+	} while (buf);
+
+	for (i = 0; i < ARRAY_SIZE(xhci_mtk_hqa_cmds); i++) {
+		hqa = &xhci_mtk_hqa_cmds[i];
+		if ((!strcmp(hqa->name, argv[0])) && (hqa->cb_func != NULL))
+			return hqa->cb_func(mtk, argc, argv);
+	}
+
+	return -1;
+}
+
+static int test_mode_enter(struct xhci_hcd_mtk *mtk,
+				u32 port_id, u32 test_value)
+{
+	struct usb_hcd *hcd = mtk->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	u32 __iomem *addr;
+	u32 temp;
+
+	if (mtk->test_mode == 0) {
+		xhci_stop(hcd);
+		xhci_halt(xhci);
+	}
+
+	addr = &xhci->op_regs->port_power_base +
+			NUM_PORT_REGS * ((port_id - 1) & 0xff);
+	temp = readl(addr);
+	temp &= ~(0xf << 28);
+	temp |= (test_value << 28);
+	writel(temp, addr);
+	mtk->test_mode = 1;
+
+	return 0;
+}
+
+static int test_mode_exit(struct xhci_hcd_mtk *mtk)
+{
+	if (mtk->test_mode == 1)
+		mtk->test_mode = 0;
+
+	return 0;
+}
+
+static int t_test_j(struct xhci_hcd_mtk *mtk, int argc, char **argv)
+{
+	struct usb_hcd *hcd = mtk->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	long port_id;
+	u32 test_value;
+
+	port_id = 2;
+	test_value = 1;
+
+	if (argc > 1 && kstrtol(argv[1], 10, &port_id))
+		xhci_err(xhci, "mu3h %s get port-id failed\n", __func__);
+
+	xhci_err(xhci, "mu3h %s test port%d\n", __func__, (int)port_id);
+	test_mode_enter(mtk, port_id, test_value);
+
+	return 0;
+}
+
+static int t_test_k(struct xhci_hcd_mtk *mtk, int argc, char **argv)
+{
+	struct usb_hcd *hcd = mtk->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	long port_id;
+	u32 test_value;
+
+	port_id = 2;
+	test_value = 2;
+
+	if (argc > 1 && kstrtol(argv[1], 10, &port_id))
+		xhci_err(xhci, "mu3h %s get port-id failed\n", __func__);
+
+	xhci_err(xhci, "mu3h %s test port%d\n", __func__, (int)port_id);
+	test_mode_enter(mtk, port_id, test_value);
+
+	return 0;
+}
+
+static int t_test_se0(struct xhci_hcd_mtk *mtk, int argc, char **argv)
+{
+	struct usb_hcd *hcd = mtk->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	long port_id;
+	u32 test_value;
+
+	port_id = 2;
+	test_value = 3;
+
+	if (argc > 1 && kstrtol(argv[1], 10, &port_id))
+		xhci_err(xhci, "mu3h %s get port-id failed\n", __func__);
+
+	xhci_err(xhci, "mu3h %s test port%ld\n", __func__, port_id);
+	test_mode_enter(mtk, port_id, test_value);
+
+	return 0;
+}
+
+static int t_test_packet(struct xhci_hcd_mtk *mtk, int argc, char **argv)
+{
+	struct usb_hcd *hcd = mtk->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	long port_id;
+	u32 test_value;
+
+	port_id = 2;
+	test_value = 4;
+
+	if (argc > 1 && kstrtol(argv[1], 10, &port_id))
+		xhci_err(xhci, "mu3h %s get port-id failed\n", __func__);
+
+	xhci_err(xhci, "mu3h %s test port%ld\n", __func__, port_id);
+	test_mode_enter(mtk, port_id, test_value);
+
+	return 0;
+}
+
+/* only for u3 ports, valid values are 1, 2, ...*/
+static int t_power_u1u2(struct xhci_hcd_mtk *mtk, int argc, char **argv)
+{
+	struct usb_hcd *hcd = mtk->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	u32 __iomem *addr;
+	u32 temp;
+	int port_id;
+	int retval = 0;
+	int u_num = 1;
+	int u1_val = 1;
+	int u2_val = 0;
+
+	port_id = 1; /* first u3port by default */
+
+	if (argc > 1 && kstrtoint(argv[1], 10, &port_id))
+		xhci_err(xhci, "mu3h %s get port-id failed\n", __func__);
+
+	if (argc > 2 && kstrtoint(argv[2], 10, &u_num))
+		xhci_err(xhci, "mu3h %s get u_num failed\n", __func__);
+
+	if (argc > 3 && kstrtoint(argv[3], 10, &u1_val))
+		xhci_err(xhci, "mu3h %s get u1_val failed\n", __func__);
+
+	if (argc > 4 && kstrtoint(argv[4], 10, &u2_val))
+		xhci_err(xhci, "mu3h %s get u2_val failed\n", __func__);
+
+	xhci_err(xhci, "mu3h %s test port%d, u_num%d, u1_val%d, u2_val%d\n",
+		__func__, (int)port_id, u_num, u1_val, u2_val);
+
+	if (mtk->test_mode == 1) {
+		xhci_err(xhci, "please suspend port first\n");
+		return -1;
+	}
+
+	xhci_err(xhci, "%s: stop port polling\n", __func__);
+	clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+	del_timer_sync(&hcd->rh_timer);
+	clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
+	del_timer_sync(&xhci->shared_hcd->rh_timer);
+	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);
+
+	addr = &xhci->op_regs->port_power_base +
+			NUM_PORT_REGS * ((port_id - 1) & 0xff);
+
+	temp = readl(addr);
+	if (u_num == 1) {
+		temp &= ~PORT_U1_TIMEOUT_MASK;
+		temp |= PORT_U1_TIMEOUT(u1_val);
+	} else if (u_num == 2) {
+		temp &= ~PORT_U2_TIMEOUT_MASK;
+		temp |= PORT_U2_TIMEOUT(u2_val);
+	} else if (u_num == 3) {
+		temp &= ~(PORT_U1_TIMEOUT_MASK | PORT_U2_TIMEOUT_MASK);
+		temp |= PORT_U1_TIMEOUT(u1_val) | PORT_U2_TIMEOUT(u2_val);
+	}
+
+	writel(temp, addr);
+
+	return retval;
+}
+
+
+static int t_test_suspend(struct xhci_hcd_mtk *mtk, int argc, char **argv)
+{
+	struct usb_hcd *hcd = mtk->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	u32 __iomem *addr;
+	u32 temp;
+	long port_id;
+
+	port_id = 2;
+
+	if (argc > 1 && kstrtol(argv[1], 10, &port_id))
+		xhci_err(xhci, "mu3h %s get port-id failed\n", __func__);
+
+	xhci_err(xhci, "mu3h %s test port%d\n", __func__, (int)port_id);
+
+	xhci_err(xhci, "%s: stop port polling\n", __func__);
+	clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+	del_timer_sync(&hcd->rh_timer);
+	clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
+	del_timer_sync(&xhci->shared_hcd->rh_timer);
+	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);
+
+	temp = readl(&xhci->ir_set->irq_pending);
+	writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending);
+
+	if (mtk->test_mode == 1)
+		test_mode_exit(mtk);
+
+	/* set PLS = 3 */
+	addr = &xhci->op_regs->port_status_base +
+			NUM_PORT_REGS*((port_id - 1) & 0xff);
+
+	temp = readl(addr);
+	temp = xhci_port_state_to_neutral(temp);
+	temp = (temp & ~(0xf << 5));
+	temp = (temp | (3 << 5) | PORT_LINK_STROBE);
+	writel(temp, addr);
+	xhci_handshake(addr, (0xf << 5), (3 << 5), 30*1000);
+
+	temp = readl(addr);
+	if (PORT_PLS_VALUE(temp) != 3)
+		xhci_err(xhci, "port not enter suspend state\n");
+	else
+		xhci_err(xhci, "port enter suspend state\n");
+
+	return 0;
+}
+
+static int t_test_resume(struct xhci_hcd_mtk *mtk, int argc, char **argv)
+{
+	struct usb_hcd *hcd = mtk->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	u32 __iomem *addr;
+	u32 temp;
+	long port_id;
+	int retval = 0;
+
+	port_id = 2;
+
+	if (argc > 1 && kstrtol(argv[1], 10, &port_id))
+		xhci_err(xhci, "mu3h %s get port-id failed\n", __func__);
+
+	xhci_err(xhci, "mu3h %s test port%d\n", __func__, (int)port_id);
+
+	if (mtk->test_mode == 1) {
+		xhci_err(xhci, "please suspend port first\n");
+		return -1;
+	}
+	addr = &xhci->op_regs->port_status_base +
+			NUM_PORT_REGS * ((port_id - 1) & 0xff);
+
+	temp = readl(addr);
+	if (PORT_PLS_VALUE(temp) != 3) {
+		xhci_err(xhci, "port not in suspend state, please suspend port first\n");
+		retval = -1;
+	} else {
+		temp = xhci_port_state_to_neutral(temp);
+		temp = (temp & ~(0xf << 5));
+		temp = (temp | (15 << 5) | PORT_LINK_STROBE);
+		writel(temp, addr);
+		mdelay(20);
+
+		temp = readl(addr);
+		temp = xhci_port_state_to_neutral(temp);
+		temp = (temp & ~(0xf << 5));
+		temp = (temp | PORT_LINK_STROBE);
+		writel(temp, addr);
+
+		xhci_handshake(addr, (0xf << 5), (0 << 5), 100*1000);
+		temp = readl(addr);
+		if (PORT_PLS_VALUE(temp) != 0) {
+			xhci_err(xhci, "rusume fail,%x\n",
+				PORT_PLS_VALUE(temp));
+			retval = -1;
+		} else {
+			xhci_err(xhci, "port resume ok\n");
+		}
+	}
+
+	return retval;
+}
+
+static int t_test_enumerate_bus(struct xhci_hcd_mtk *mtk, int argc, char **argv)
+{
+	struct usb_hcd *hcd = mtk->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	struct usb_device *usb2_rh;
+	struct usb_device *udev;
+	long port_id;
+	u32 retval;
+
+	port_id = 2;
+
+	if (argc > 1 && kstrtol(argv[1], 10, &port_id))
+		xhci_err(xhci, "mu3h %s get port-id failed\n", __func__);
+
+	xhci_err(xhci, "mu3h %s test port%d\n", __func__, (int)port_id);
+
+	if (mtk->test_mode == 1) {
+		test_mode_exit(mtk);
+		return 0;
+	}
+
+	usb2_rh = hcd->self.root_hub;
+	udev = usb_hub_find_child(usb2_rh, port_id - 1);
+
+	if (udev != NULL) {
+		retval = usb_reset_device(udev);
+		if (retval) {
+			xhci_err(xhci, "ERROR: enumerate bus fail!\n");
+			return -1;
+		}
+	} else {
+		xhci_err(xhci, "ERROR: Device does not exist!\n");
+		return -1;
+	}
+
+	return 0;
+}
+static int t_test_get_device_descriptor(struct xhci_hcd_mtk *mtk,
+				int argc, char **argv)
+{
+	struct usb_hcd *hcd = mtk->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	struct usb_device *usb2_rh;
+	struct usb_device *udev;
+	long port_id;
+	u32 retval = 0;
+
+	port_id = 2;
+
+	if (argc > 1 && kstrtol(argv[1], 10, &port_id))
+		xhci_err(xhci, "mu3h %s get port-id failed\n", __func__);
+
+	xhci_err(xhci, "mu3h %s test port%d\n", __func__, (int)port_id);
+
+	if (mtk->test_mode == 1) {
+		test_mode_exit(mtk);
+		msleep(2000);
+	}
+
+	usb2_rh = hcd->self.root_hub;
+
+	udev = usb_hub_find_child(usb2_rh, port_id - 1);
+
+	if (udev != NULL) {
+		retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
+		if (retval != sizeof(udev->descriptor)) {
+			xhci_err(xhci, "ERROR: get device descriptor fail!\n");
+			return -1;
+		}
+	} else {
+		xhci_err(xhci, "ERROR: Device does not exist!\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static ssize_t hqa_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = mtk->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	u32 __iomem *addr;
+	u32 val;
+	u32 ports;
+	int len = 0;
+	int bufLen = PAGE_SIZE;
+	struct hqa_test_cmd *hqa;
+	int i;
+
+	len += snprintf(buf+len, bufLen-len, "info:\n");
+	len += snprintf(buf+len, bufLen-len,
+			"\techo -n item port-id > hqa\n");
+	len += snprintf(buf+len, bufLen-len,
+			"\tport-id : based on number of usb3-port, e.g.\n");
+	len += snprintf(buf+len, bufLen-len,
+			"\t\txHCI with 1 u3p, 2 u2p: 1st u2p-id is 2(1+1), 2nd is 3\n");
+	len += snprintf(buf+len, bufLen-len, "items:\n");
+
+	for (i = 0; i < ARRAY_SIZE(xhci_mtk_hqa_cmds); i++) {
+		hqa = &xhci_mtk_hqa_cmds[i];
+		len += snprintf(buf+len, bufLen-len,
+				"\t%s: %s\n", hqa->name, hqa->discription);
+	}
+
+	ports = mtk->num_u3_ports + mtk->num_u2_ports;
+	for (i = mtk->num_u3_ports + 1; i <= ports; i++) {
+		addr = &xhci->op_regs->port_power_base +
+			NUM_PORT_REGS * ((i - 1) & 0xff);
+		val = readl(addr);
+		len += snprintf(buf+len, bufLen-len,
+			"USB20 Port%i PORTMSC[31,28] 4b'0000: 0x%08X\n",
+			i, val);
+	}
+
+	return len;
+}
+
+static ssize_t hqa_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = mtk->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	int retval;
+
+	retval = call_hqa_func(mtk, (char *)buf);
+	if (retval < 0) {
+		xhci_err(xhci, "mu3h cli fail\n");
+		return -1;
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR_RW(hqa);
+
+static ssize_t usb3hqa_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = mtk->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	ssize_t cnt = 0;
+	u32 __iomem *addr;
+	u32 val;
+	u32 i;
+	int ports;
+
+	cnt += sprintf(buf + cnt, "usb3hqa usage:\n");
+	cnt += sprintf(buf + cnt, "	echo u3port >usb3hqa\n");
+
+	ports = mtk->num_u3_ports + mtk->num_u2_ports;
+	for (i = 1; i <= ports; i++) {
+		addr = &xhci->op_regs->port_status_base +
+			NUM_PORT_REGS * ((i - 1) & 0xff);
+		val = readl(addr);
+		if (i < mtk->num_u3_ports)
+			cnt += sprintf(buf + cnt,
+				"USB30 Port%i: 0x%08X\n", i, val);
+		else 
+			cnt += sprintf(buf + cnt,
+				"USB20 Port%i: 0x%08X\n", i, val);
+	}
+
+	if (mtk->hqa_pos) {
+		cnt += sprintf(buf + cnt, "%s", mtk->hqa_buf);
+		mtk->hqa_pos = 0;
+	}
+
+	return cnt;
+}
+
+static ssize_t
+usb3hqa_store(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t n)
+{
+	struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = mtk->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	u32 __iomem *addr;
+	u32 val;
+	int port;
+	int words;
+
+	mtk->hqa_pos = 0;
+	memset(mtk->hqa_buf, 0, mtk->hqa_size);
+
+	hqa_info(mtk, "usb3hqa: %s\n", buf);
+
+	words = sscanf(buf, "%d", &port);
+	if ((words != 1) ||
+	    (port < 1 || port > mtk->num_u3_ports)) {
+		hqa_info(mtk, "usb3hqa: param number:%i, port:%i failure\n",
+			words, port);
+		return -EINVAL;
+	}
+
+	addr = &xhci->op_regs->port_status_base +
+		NUM_PORT_REGS * ((port - 1) & 0xff);
+	val  = readl(addr);
+	val &= ~(PORT_PLS_MASK);
+	val |= (PORT_LINK_STROBE | XDEV_COMP_MODE);
+	writel(val, addr);
+	hqa_info(mtk, "usb3hqa: port%i: 0x%08X but 0x%08X\n",
+		port, val, readl(addr));
+
+	return n;
+}
+static DEVICE_ATTR_RW(usb3hqa);
+
+static struct device_attribute *mu3h_hqa_attr_list[] = {
+	&dev_attr_hqa,
+	&dev_attr_usb3hqa,
+#include "unusual-statement.h"
+};
+
+int hqa_create_attr(struct device *dev)
+{
+	int idx, err = 0;
+	int num = ARRAY_SIZE(mu3h_hqa_attr_list);
+	struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
+
+	if (dev == NULL || mtk == NULL)
+		return -EINVAL;
+
+	mtk->hqa_size = HQA_PREFIX_SIZE;
+	mtk->hqa_pos  = 0;
+	mtk->hqa_buf = kzalloc(mtk->hqa_size, GFP_KERNEL);
+	if (!mtk->hqa_buf)
+		return -ENOMEM;
+
+	for (idx = 0; idx < num; idx++) {
+		err = device_create_file(dev, mu3h_hqa_attr_list[idx]);
+		if (err)
+			break;
+	}
+
+	return err;
+}
+
+void hqa_remove_attr(struct device *dev)
+{
+	int idx;
+	int num = ARRAY_SIZE(mu3h_hqa_attr_list);
+	struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
+
+	for (idx = 0; idx < num; idx++)
+		device_remove_file(dev, mu3h_hqa_attr_list[idx]);
+
+	kfree(mtk->hqa_buf);
+	mtk->hqa_size = 0;
+	mtk->hqa_pos  = 0;
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-test.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-test.h
new file mode 100644
index 0000000..83e1542
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-test.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * xhci-mtk-unusuallib.h -- xhci toolkit header file
+ *
+ * Copyright (C) 2021 Mediatek Inc - http://www.mediatek.com
+ *
+ *  Author: Zhanyong Wang <zhanyong.wang@mediatek.com>
+ *          Shaocheng.Wang <shaocheng.wang@mediatek.com>
+ *          Chunfeng.Yun <chunfeng.yun@mediatek.com>
+ */
+
+#ifndef __XHCI_MTK_TEST_H
+#define __XHCI_MTK_TEST_H
+
+#ifdef CONFIG_USB_XHCI_MTK_DEBUGFS
+int hqa_create_attr(struct device *dev);
+void hqa_remove_attr(struct device *dev);
+#else
+static inline int hqa_create_attr(struct device *dev)
+{
+	return 0;
+}
+static inline void hqa_remove_attr(struct device *dev)
+{
+}
+#endif
+#endif /* __XHCI_MTK_TEST_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-unusual.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-unusual.c
new file mode 100644
index 0000000..14d7d0b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-unusual.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * xHCI host controller toolkit driver
+ *
+ * Copyright (C) 2021  MediaTek Inc.
+ *
+ *  Author: Zhanyong Wang <zhanyong.wang@mediatek.com>
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <dt-bindings/phy/phy.h>
+#include "xhci-mtk.h"
+#include "xhci-mtk-test.h"
+#include "xhci-mtk-unusual.h"
+
+
+u32 binary_write_width1(u32 __iomem *addr, u32 shift, const char *buf)
+{
+	u32 val = 0;
+
+	if (!strncmp(buf, STRNG_0_WIDTH_1, BIT_WIDTH_1))
+		val = 0;
+	else if (!strncmp(buf, STRNG_1_WIDTH_1, BIT_WIDTH_1))
+		val = 1;
+	else
+		val = 0xFFFFFFFF;
+
+	if (val <= 1)
+		val = usb20hqa_write(addr, shift, MSK_WIDTH_1, val);
+
+	return val;
+}
+
+u32 binary_write_width3(u32 __iomem *addr, u32 shift, const char *buf)
+{
+	u32 val = 0;
+
+	if (!strncmp(buf, STRNG_0_WIDTH_3, BIT_WIDTH_3))
+		val = 0;
+	else if (!strncmp(buf, STRNG_1_WIDTH_3, BIT_WIDTH_3))
+		val = 1;
+	else if (!strncmp(buf, STRNG_2_WIDTH_3, BIT_WIDTH_3))
+		val = 2;
+	else if (!strncmp(buf, STRNG_3_WIDTH_3, BIT_WIDTH_3))
+		val = 3;
+	else if (!strncmp(buf, STRNG_4_WIDTH_3, BIT_WIDTH_3))
+		val = 4;
+	else if (!strncmp(buf, STRNG_5_WIDTH_3, BIT_WIDTH_3))
+		val = 5;
+	else if (!strncmp(buf, STRNG_6_WIDTH_3, BIT_WIDTH_3))
+		val = 6;
+	else if (!strncmp(buf, STRNG_7_WIDTH_3, BIT_WIDTH_3))
+		val = 7;
+	else
+		val = 0xFFFFFFFF;
+
+	if (val <= 7)
+		val = usb20hqa_write(addr, shift, MSK_WIDTH_3, val);
+
+	return val;
+}
+
+u32 binary_write_width4(u32 __iomem *addr, u32 shift, const char *buf)
+{
+	u32 val = 0;
+
+	if (!strncmp(buf, STRNG_0_WIDTH_4, BIT_WIDTH_4))
+		val = 0;
+	else if (!strncmp(buf, STRNG_1_WIDTH_4, BIT_WIDTH_4))
+		val = 1;
+	else if (!strncmp(buf, STRNG_2_WIDTH_4, BIT_WIDTH_4))
+		val = 2;
+	else if (!strncmp(buf, STRNG_3_WIDTH_4, BIT_WIDTH_4))
+		val = 3;
+	else if (!strncmp(buf, STRNG_4_WIDTH_4, BIT_WIDTH_4))
+		val = 4;
+	else if (!strncmp(buf, STRNG_5_WIDTH_4, BIT_WIDTH_4))
+		val = 5;
+	else if (!strncmp(buf, STRNG_6_WIDTH_4, BIT_WIDTH_4))
+		val = 6;
+	else if (!strncmp(buf, STRNG_7_WIDTH_4, BIT_WIDTH_4))
+		val = 7;
+	else if (!strncmp(buf, STRNG_8_WIDTH_4, BIT_WIDTH_4))
+		val = 8;
+	else if (!strncmp(buf, STRNG_9_WIDTH_4, BIT_WIDTH_4))
+		val = 9;
+	else if (!strncmp(buf, STRNG_A_WIDTH_4, BIT_WIDTH_4))
+		val = 10;
+	else if (!strncmp(buf, STRNG_B_WIDTH_4, BIT_WIDTH_4))
+		val = 11;
+	else if (!strncmp(buf, STRNG_C_WIDTH_4, BIT_WIDTH_4))
+		val = 12;
+	else if (!strncmp(buf, STRNG_D_WIDTH_4, BIT_WIDTH_4))
+		val = 13;
+	else if (!strncmp(buf, STRNG_E_WIDTH_4, BIT_WIDTH_4))
+		val = 14;
+	else if (!strncmp(buf, STRNG_F_WIDTH_4, BIT_WIDTH_4))
+		val = 15;
+	else
+		val = 0xFFFFFFFF;
+
+	if (val <= 15)
+		val = usb20hqa_write(addr, shift, MSK_WIDTH_4, val);
+
+	return val;
+}
+
+u32 bin2str(u32 value, u32 width, char *buffer)
+{
+	int i, temp;
+
+	temp = value;
+	buffer[width] = '\0';
+	for (i = (width - 1); i >= 0; i--) {
+		buffer[i] = '0';
+		if (value % 2)
+			buffer[i] = '1';
+
+		value /= 2;
+	}
+
+	return value;
+}
+
+int query_phy_addr(struct device_node *np, int *start, u32 *addr, u32 *length)
+{
+	int ret = -EPERM;
+	struct of_phandle_args args;
+	struct resource res;
+	int numphys = 0;
+	int index;
+
+	if (start == NULL || addr == NULL || length == NULL)
+		return -EINVAL;
+
+	numphys = of_count_phandle_with_args(np, "phys", "#phy-cells");
+	for ( index = *start; (numphys > 0) && index < numphys; index++) {
+		ret = of_parse_phandle_with_args(np, "phys", "#phy-cells",
+				index, &args);
+		if (ret < 0)
+			break;
+
+		if (args.args[0] == PHY_TYPE_USB2) {
+			ret = of_address_to_resource(args.np, 0, &res);
+			if (ret < 0) {
+				of_node_put(args.np);
+				break;
+			}
+
+			*addr   = res.start;
+			*length = (u32)resource_size(&res);
+			*start  = index;
+			if (!of_device_is_available(args.np))
+				ret = -EACCES;
+
+			of_node_put(args.np);
+			break;
+		}
+	}
+
+	ret = index < numphys ? ret : -EPERM;
+	return ret;
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-unusual.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-unusual.h
new file mode 100644
index 0000000..ddbf4e3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-unusual.h
@@ -0,0 +1,195 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * xhci-mtk-unusuallib.h -- xhci toolkit header file
+ *
+ * Copyright (C) 2021 Mediatek Inc - http://www.mediatek.com
+ *
+ * Author: Zhanyong Wang <zhanyong.wang@mediatek.com>
+ */
+
+#ifndef __XHCI_MTK_UNUSUAL_H
+#define __XHCI_MTK_UNUSUAL_H
+
+#define HQA_PREFIX_SIZE		4*1024
+
+#define BIT_WIDTH_1		1
+#define MSK_WIDTH_1		0x1
+#define VAL_MAX_WDITH_1		0x1
+
+#define STRNG_0_WIDTH_1		"0"
+#define STRNG_1_WIDTH_1		"1"
+
+#define BIT_WIDTH_2		2
+#define MSK_WIDTH_2		0x3
+#define VAL_MAX_WDITH_2		0x3
+#define STRNG_0_WIDTH_2		"00"
+#define STRNG_1_WIDTH_2		"01"
+#define STRNG_2_WIDTH_2		"10"
+#define STRNG_3_WIDTH_2		"11"
+
+
+#define BIT_WIDTH_3		3
+#define MSK_WIDTH_3		0x7
+#define VAL_MAX_WDITH_3		0x7
+#define STRNG_0_WIDTH_3		"000"
+#define STRNG_1_WIDTH_3		"001"
+#define STRNG_2_WIDTH_3		"010"
+#define STRNG_3_WIDTH_3		"011"
+#define STRNG_4_WIDTH_3		"100"
+#define STRNG_5_WIDTH_3		"101"
+#define STRNG_6_WIDTH_3		"110"
+#define STRNG_7_WIDTH_3		"111"
+
+#define BIT_WIDTH_4		4
+#define MSK_WIDTH_4		0xf
+#define VAL_MAX_WDITH_4		0xf
+#define STRNG_0_WIDTH_4		"0000"
+#define STRNG_1_WIDTH_4		"0001"
+#define STRNG_2_WIDTH_4		"0010"
+#define STRNG_3_WIDTH_4		"0011"
+#define STRNG_4_WIDTH_4		"0100"
+#define STRNG_5_WIDTH_4		"0101"
+#define STRNG_6_WIDTH_4		"0110"
+#define STRNG_7_WIDTH_4		"0111"
+#define STRNG_8_WIDTH_4		"1000"
+#define STRNG_9_WIDTH_4		"1001"
+#define STRNG_A_WIDTH_4		"1010"
+#define STRNG_B_WIDTH_4		"1011"
+#define STRNG_C_WIDTH_4		"1100"
+#define STRNG_D_WIDTH_4		"1101"
+#define STRNG_E_WIDTH_4		"1110"
+#define STRNG_F_WIDTH_4		"1111"
+
+/* specific */
+#define NAME_RG_USB20_INTR_EN		"RG_USB20_INTR_EN"
+#define USB20_PHY_USBPHYACR0		0x00
+#define SHFT_RG_USB20_INTR_EN		5
+#define BV_RG_USB20_INTR_EN		BIT(5)
+
+#define NAME_RG_USB20_VRT_VREF_SEL	"RG_USB20_VRT_VREF_SEL"
+#define USB20_PHY_USBPHYACR1		0x04
+#define SHFT_RG_USB20_VRT_VREF_SEL	12
+#define BV_RG_USB20_VRT_VREF_SEL	GENMASK(14, 12)
+
+#define NAME_RG_USB20_TERM_VREF_SEL	"RG_USB20_TERM_VREF_SEL"
+#define SHFT_RG_USB20_TERM_VREF_SEL	8
+#define BV_RG_USB20_TERM_VREF_SEL       GENMASK(10,  8)
+
+#define NAME_RG_USB20_HSTX_SRCTRL	"RG_USB20_HSTX_SRCTRL"
+#define USB20_PHY_USBPHYACR5		0x14
+#define SHFT_RG_USB20_HSTX_SRCTRL	12
+#define BV_RG_USB20_HSTX_SRCTRL		GENMASK(14, 12)
+
+#define NAME_RG_USB20_DISCTH		"RG_USB20_DISCTH"
+#define USB20_PHY_USBPHYACR6		0x18
+#define SHFT_RG_USB20_DISCTH		4
+#define BV_RG_USB20_DISCTH		GENMASK(8, 4)
+
+#define NAME_RG_CHGDT_EN		"RG_CHGDT_EN"
+#define USB20_PHY_U2PHYBC12C		0x80
+#define SHFT_RG_CHGDT_EN		0
+#define BV_RG_CHGDT_EN			BIT(0)
+
+#define ECHO_HQA(reg, _bd, _bw)  do {\
+	val = usb20hqa_read(addr + (reg), \
+		 SHFT_##_bd, \
+		 BV_##_bd); \
+	val = bin2str(val, BIT_WIDTH_##_bw, str); \
+	cnt += sprintf(buf + cnt, "	%-22s = %ib%s\n", \
+			NAME_##_bd, _bw, str); } while(0)
+
+
+#ifdef CONFIG_USB_XHCI_MTK_DEBUGFS
+static inline u32 usb20hqa_write(u32 __iomem *addr,
+				u32 shift, u32 mask, u32 value)
+{
+	u32 val;
+
+	val  = readl(addr);
+	val &= ~((mask) << shift);
+	val |=  (((value) & (mask)) << shift);
+	writel(val, addr);
+
+	return val;
+}
+static inline u32 usb20hqa_read(u32 __iomem *addr, u32 shift, u32 mask)
+{
+	u32 val;
+
+	val   = readl(addr);
+	val  &= mask;
+	val >>=  shift;
+
+	return val;
+}
+
+u32 binary_write_width1(u32 __iomem *addr,
+				u32 shift, const char *buf);
+u32 binary_write_width3(u32 __iomem *addr,
+				u32 shift, const char *buf);
+u32 binary_write_width4(u32 __iomem *addr,
+				u32 shift, const char *buf);
+u32 bin2str(u32 value, u32 width, char *buffer);
+int query_phy_addr(struct device_node *np, int *start,
+				u32 *addr, u32 *length);
+static inline int remaining(struct xhci_hcd_mtk *mtk)
+{
+	u32 surplus = 0;
+	if (mtk && mtk->hqa_pos < mtk->hqa_size)
+		surplus = mtk->hqa_size - mtk->hqa_pos;
+
+	return surplus;
+}
+
+#define hqa_info(mtk, fmt, args...)  \
+	(mtk)->hqa_pos += snprintf((mtk)->hqa_buf + (mtk)->hqa_pos, \
+		remaining(mtk), fmt, ## args)
+
+#define DEVICE_ATTR_DECLARED(_name) \
+		extern struct device_attribute dev_attr_##_name;
+#define UNUSUAL_DEVICE_ATTR(_name)  &dev_attr_##_name
+#else
+static inline u32 usb20hqa_write(u32 __iomem *addr,
+					u32 shift, u32 mask, u32 value)
+{
+	return 0;
+}
+static inline u32 usb20hqa_read(u32 __iomem *addr, u32 shift, u32 mask)
+{
+	return 0;
+}
+static inline u32 binary_write_width1(u32 __iomem *addr,
+					u32 shift, const char *buf)
+{
+	return 0;
+};
+static inline u32 binary_write_width3(u32 __iomem *addr,
+					u32 shift, const char *buf)
+{
+	return 0;
+};
+static inline u32 binary_write_width4(u32 __iomem *addr,
+					u32 shift, const char *buf)
+{
+	return 0;
+};
+static inline u32 bin2str(u32 value, u32 width, char *buffer)
+{
+	return 0;
+};
+static inline int query_phy_addr(struct device_node *np, int *start,
+					u32 *addr, u32 *length)
+{
+	return -EPERM;
+}
+static inline int remaining(int wrote)
+{
+	return 0;
+}
+#define hqa_info(mtk, fmt, args...)
+#define DEVICE_ATTR_DECLARED(...)
+#endif
+
+#include "unusual-declaration.h"
+
+#endif /* __XHCI_MTK_UNUSUAL_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-vrt-vref.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-vrt-vref.c
new file mode 100644
index 0000000..ec0ef75
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/usb/host/xhci-mtk-vrt-vref.c
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * xHCI host controller toolkit driver for vrt vref
+ *
+ * Copyright (C) 2021  MediaTek Inc.
+ *
+ *  Author: Zhanyong Wang <zhanyong.wang@mediatek.com>
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include "xhci-mtk.h"
+#include "xhci-mtk-test.h"
+#include "xhci-mtk-unusual.h"
+
+static ssize_t RG_USB20_VRT_VREF_SEL_show(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+	struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = mtk->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	ssize_t cnt = 0;
+	void __iomem *addr;
+	u32 val;
+	u32 i;
+	int ports;
+	char str[32];
+	int index = 0;
+	u32 io, length;
+	int ret;
+
+	ports = mtk->num_u3_ports + mtk->num_u2_ports;
+	cnt += sprintf(buf + cnt, " RG_USB20_VRT_VREF_SEL usage:\n");
+	cnt += sprintf(buf + cnt,
+		"   echo u2p index 3b011 > RG_USB20_VRT_VREF_SEL\n");
+	if (mtk->num_u3_ports + 1 != ports)
+		cnt += sprintf(buf + cnt, "	parameter: u2p: %i ~ %i\n",
+					mtk->num_u3_ports + 1, ports);
+	else
+		cnt += sprintf(buf + cnt, "	parameter: u2p: %i\n",
+					mtk->num_u3_ports + 1);
+
+	if (mtk->num_u2_ports > 1)
+		cnt += sprintf(buf + cnt, "	parameter: index: 0 ~ %i\n",
+			       mtk->num_u2_ports);
+	else
+		cnt += sprintf(buf + cnt, "	parameter: index: 0\n");
+
+	cnt += sprintf(buf + cnt,
+			 " e.g.: echo 2 0 3b101 > RG_USB20_VRT_VREF_SEL\n");
+	cnt += sprintf(buf + cnt,
+		"  port2 binding phy 0, tune 3b'010 as VRT_VREF value\n");
+
+	cnt += sprintf(buf + cnt,
+			"\n=========current HQA setting check=========\n");
+	for (i = 1; i <= ports; i++) {
+		addr = &xhci->op_regs->port_status_base +
+			NUM_PORT_REGS * ((i - 1) & 0xff);
+		val = readl(addr);
+		if (i <= mtk->num_u3_ports) {
+			cnt += sprintf(buf + cnt,
+				       "USB30 Port%i: 0x%08X\n", i, val);
+		} else {
+			cnt += sprintf(buf + cnt,
+				       "USB20 Port%i: 0x%08X\n", i, val);
+
+			ret = query_phy_addr(dev->of_node,
+						 &index, &io, &length);
+			if (ret && ret != -EACCES) {
+				if (ret == -EPERM)
+					cnt += sprintf(buf + cnt,
+					"USB20 Port%i (Phy%i: absent)\n",
+					i, index);
+				else
+					cnt += sprintf(buf + cnt,
+					"USB20 Port%i (Phy%i) failure %i\n",
+						 i, index, ret);
+				continue;
+			}
+
+			cnt += sprintf(buf + cnt,
+				"USB20 Port%i (Phy%i:%sable): 0x%08X 0x%08X\n",
+				i, index, ret ? " dis" : " en", io, length);
+
+			addr   = ioremap_nocache(io, length);
+			addr  += (length != 0x100) ? 0x300 : 0;
+
+			HQA_INFORMACTION_COLLECTS();
+
+			iounmap(addr);
+			index ++;
+		}
+	}
+
+	if (mtk->hqa_pos) {
+		cnt += sprintf(buf + cnt, "%s", mtk->hqa_buf);          
+		mtk->hqa_pos = 0;
+	}
+
+	return cnt;
+}
+
+
+static ssize_t RG_USB20_VRT_VREF_SEL_store(struct device *dev,
+                        struct device_attribute *attr,
+                        const char *buf, size_t n)
+{
+	u32 val;
+	u32 io;
+	u32 length;
+	int ports;
+	int words;
+	int port;
+	int index;
+	int ret;
+	char *str = NULL;
+	void __iomem *addr;
+	struct xhci_hcd_mtk *mtk  = dev_get_drvdata(dev);
+	struct device_node  *node = dev->of_node;
+
+	ports = mtk->num_u3_ports + mtk->num_u2_ports;
+	mtk->hqa_pos = 0;
+
+	memset(mtk->hqa_buf, 0, mtk->hqa_size);
+
+	str = kzalloc(n, GFP_ATOMIC);
+
+	hqa_info(mtk, "RG_USB20_VRT_VREF_SEL(%lu): %s\n", n, buf);
+
+	words = sscanf(buf, "%i %i 3b%3[0,1]", &port, &index, str);
+	if ((words != 3) ||
+	    (port < mtk->num_u3_ports || port > ports)) {
+		hqa_info(mtk, "Check params(%i):\" %i %i %s\", Please!\n",
+			words, port, index, str);
+
+		ret = -EINVAL;
+		goto error;
+	}
+
+	hqa_info(mtk, " params: %i %i %s\n",
+		port, index, str);
+
+	ret = query_phy_addr(node, &index, &io, &length);
+	if (ret && ret != -EACCES) 
+		goto error;
+
+	io += (length != 0x100) ? 0x300 : 0;
+	io += USB20_PHY_USBPHYACR1;
+
+	addr = ioremap_nocache(io, 4);
+	val = binary_write_width3(addr, SHFT_RG_USB20_VRT_VREF_SEL, str);
+	hqa_info(mtk, "Port%i(Phy%i)[0x%08X]: 0x%08X but 0x%08X\n",
+		port, index, io, val, readl(addr));
+
+	iounmap(addr);
+	ret = n;
+      
+error:
+	kfree(str);
+	return ret;
+}
+DEVICE_ATTR_RW(RG_USB20_VRT_VREF_SEL);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/dt-bindings/clock/mt7981-clk.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/dt-bindings/clock/mt7981-clk.h
new file mode 100644
index 0000000..95ebc47
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/dt-bindings/clock/mt7981-clk.h
@@ -0,0 +1,274 @@
+/*

+ * Copyright (c) 2021 MediaTek Inc.

+ * Author: Wenzhen.Yu <wenzhen.yu@mediatek.com>

+ *

+ * This program is free software; you can redistribute it and/or modify

+ * it under the terms of the GNU General Public License version 2 as

+ * published by the Free Software Foundation.

+ *

+ * This program is distributed in the hope that it will be useful,

+ * but WITHOUT ANY WARRANTY; without even the implied warranty of

+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+ * GNU General Public License for more details.

+ */

+

+#ifndef _DT_BINDINGS_CLK_MT7981_H

+#define _DT_BINDINGS_CLK_MT7981_H

+

+/* INFRACFG */

+

+#define CK_INFRA_CK_F26M		0

+#define CK_INFRA_UART			1

+#define CK_INFRA_ISPI0			2

+#define CK_INFRA_I2C			3

+#define CK_INFRA_ISPI1			4

+#define CK_INFRA_PWM			5

+#define CK_INFRA_66M_MCK		6

+#define CK_INFRA_CK_F32K		7

+#define CK_INFRA_PCIE_CK		8

+#define CK_INFRA_PWM_BCK		9

+#define CK_INFRA_PWM_CK1		10

+#define CK_INFRA_PWM_CK2		11

+#define CK_INFRA_133M_HCK		12

+#define CK_INFRA_66M_PHCK		13

+#define CK_INFRA_FAUD_L_CK		14

+#define CK_INFRA_FAUD_AUD_CK		15

+#define CK_INFRA_FAUD_EG2_CK		16

+#define CK_INFRA_I2CS_CK		17

+#define CK_INFRA_MUX_UART0		18

+#define CK_INFRA_MUX_UART1		19

+#define CK_INFRA_MUX_UART2		20

+#define CK_INFRA_NFI_CK			21

+#define CK_INFRA_SPINFI_CK		22

+#define CK_INFRA_MUX_SPI0		23

+#define CK_INFRA_MUX_SPI1		24

+#define CK_INFRA_MUX_SPI2		25

+#define CK_INFRA_RTC_32K		26

+#define CK_INFRA_FMSDC_CK		27

+#define CK_INFRA_FMSDC_HCK_CK		28

+#define CK_INFRA_PERI_133M		29

+#define CK_INFRA_133M_PHCK		30

+#define CK_INFRA_USB_SYS_CK		31

+#define CK_INFRA_USB_CK			32

+#define CK_INFRA_USB_XHCI_CK		33

+#define CK_INFRA_PCIE_GFMUX_TL_O_PRE	34

+#define CK_INFRA_F26M_CK0		35

+#define CK_INFRA_133M_MCK		36

+#define CLK_INFRA_NR_CLK		37

+

+/* TOPCKGEN */

+

+#define CK_TOP_CB_CKSQ_40M		0

+#define CK_TOP_CB_M_416M		1

+#define CK_TOP_CB_M_D2			2

+#define CK_TOP_CB_M_D3			3

+#define CK_TOP_M_D3_D2			4

+#define CK_TOP_CB_M_D4			5

+#define CK_TOP_CB_M_D8			6

+#define CK_TOP_M_D8_D2			7

+#define CK_TOP_CB_MM_720M		8

+#define CK_TOP_CB_MM_D2			9

+#define CK_TOP_CB_MM_D3			10

+#define CK_TOP_CB_MM_D3_D5		11

+#define CK_TOP_CB_MM_D4			12

+#define CK_TOP_CB_MM_D6			13

+#define CK_TOP_MM_D6_D2			14

+#define CK_TOP_CB_MM_D8			15

+#define CK_TOP_CB_APLL2_196M		16

+#define CK_TOP_APLL2_D2			17

+#define CK_TOP_APLL2_D4			18

+#define CK_TOP_NET1_2500M		19

+#define CK_TOP_CB_NET1_D4		20

+#define CK_TOP_CB_NET1_D5		21

+#define CK_TOP_NET1_D5_D2		22

+#define CK_TOP_NET1_D5_D4		23

+#define CK_TOP_CB_NET1_D8		24

+#define CK_TOP_NET1_D8_D2		25

+#define CK_TOP_NET1_D8_D4		26

+#define CK_TOP_CB_NET2_800M		27

+#define CK_TOP_CB_NET2_D2		28

+#define CK_TOP_CB_NET2_D4		29

+#define CK_TOP_NET2_D4_D2		30

+#define CK_TOP_NET2_D4_D4		31

+#define CK_TOP_CB_NET2_D6		32

+#define CK_TOP_CB_WEDMCU_208M		33

+#define CK_TOP_CB_SGM_325M		34

+#define CK_TOP_CKSQ_40M_D2		35

+#define CK_TOP_CB_RTC_32K		36

+#define CK_TOP_CB_RTC_32P7K		37

+#define CK_TOP_USB_TX250M		38

+#define CK_TOP_FAUD			39

+#define CK_TOP_NFI1X			40

+#define CK_TOP_USB_EQ_RX250M		41

+#define CK_TOP_USB_CDR_CK		42

+#define CK_TOP_USB_LN0_CK		43

+#define CK_TOP_SPINFI_BCK		44

+#define CK_TOP_SPI			45

+#define CK_TOP_SPIM_MST			46

+#define CK_TOP_UART_BCK			47

+#define CK_TOP_PWM_BCK			48

+#define CK_TOP_I2C_BCK			49

+#define CK_TOP_PEXTP_TL			50

+#define CK_TOP_EMMC_208M		51

+#define CK_TOP_EMMC_400M		52

+#define CK_TOP_DRAMC_REF		53

+#define CK_TOP_DRAMC_MD32		54

+#define CK_TOP_SYSAXI			55

+#define CK_TOP_SYSAPB			56

+#define CK_TOP_ARM_DB_MAIN		57

+#define CK_TOP_AP2CNN_HOST		58

+#define CK_TOP_NETSYS			59

+#define CK_TOP_NETSYS_500M		60

+#define CK_TOP_NETSYS_WED_MCU		61

+#define CK_TOP_NETSYS_2X		62

+#define CK_TOP_SGM_325M			63

+#define CK_TOP_SGM_REG			64

+#define CK_TOP_F26M			65

+#define CK_TOP_EIP97B			66

+#define CK_TOP_USB3_PHY			67

+#define CK_TOP_AUD			68

+#define CK_TOP_A1SYS			69

+#define CK_TOP_AUD_L			70

+#define CK_TOP_A_TUNER			71

+#define CK_TOP_U2U3_REF			72

+#define CK_TOP_U2U3_SYS			73

+#define CK_TOP_U2U3_XHCI		74

+#define CK_TOP_USB_FRMCNT		75

+#define CK_TOP_NFI1X_SEL		76

+#define CK_TOP_SPINFI_SEL		77

+#define CK_TOP_SPI_SEL			78

+#define CK_TOP_SPIM_MST_SEL		79

+#define CK_TOP_UART_SEL			80

+#define CK_TOP_PWM_SEL			81

+#define CK_TOP_I2C_SEL			82

+#define CK_TOP_PEXTP_TL_SEL		83

+#define CK_TOP_EMMC_208M_SEL		84

+#define CK_TOP_EMMC_400M_SEL		85

+#define CK_TOP_F26M_SEL			86

+#define CK_TOP_DRAMC_SEL		87

+#define CK_TOP_DRAMC_MD32_SEL		88

+#define CK_TOP_SYSAXI_SEL		89

+#define CK_TOP_SYSAPB_SEL		90

+#define CK_TOP_ARM_DB_MAIN_SEL		91

+#define CK_TOP_AP2CNN_HOST_SEL		92

+#define CK_TOP_NETSYS_SEL		93

+#define CK_TOP_NETSYS_500M_SEL		94

+#define CK_TOP_NETSYS_MCU_SEL		95

+#define CK_TOP_NETSYS_2X_SEL		96

+#define CK_TOP_SGM_325M_SEL		97

+#define CK_TOP_SGM_REG_SEL		98

+#define CK_TOP_EIP97B_SEL		99

+#define CK_TOP_USB3_PHY_SEL		100

+#define CK_TOP_AUD_SEL			101

+#define CK_TOP_A1SYS_SEL		102

+#define CK_TOP_AUD_L_SEL		103

+#define CK_TOP_A_TUNER_SEL		104

+#define CK_TOP_U2U3_SEL			105

+#define CK_TOP_U2U3_SYS_SEL		106

+#define CK_TOP_U2U3_XHCI_SEL		107

+#define CK_TOP_USB_FRMCNT_SEL		108

+#define CK_TOP_AUD_I2S_M		109

+#define CLK_TOP_NR_CLK			110

+

+/* INFRACFG_AO */

+

+#define CK_INFRA_UART0_SEL		0

+#define CK_INFRA_UART1_SEL		1

+#define CK_INFRA_UART2_SEL		2

+#define CK_INFRA_SPI0_SEL		3

+#define CK_INFRA_SPI1_SEL		4

+#define CK_INFRA_SPI2_SEL		5

+#define CK_INFRA_PWM1_SEL		6

+#define CK_INFRA_PWM2_SEL		7

+#define CK_INFRA_PWM3_SEL		8

+#define CK_INFRA_PWM_BSEL		9

+#define CK_INFRA_PCIE_SEL		10

+#define CK_INFRA_GPT_STA		11

+#define CK_INFRA_PWM_HCK		12

+#define CK_INFRA_PWM_STA		13

+#define CK_INFRA_PWM1_CK		14

+#define CK_INFRA_PWM2_CK		15

+#define CK_INFRA_PWM3_CK		16

+#define CK_INFRA_CQ_DMA_CK		17

+#define CK_INFRA_AUD_BUS_CK		18

+#define CK_INFRA_AUD_26M_CK		19

+#define CK_INFRA_AUD_L_CK		20

+#define CK_INFRA_AUD_AUD_CK		21

+#define CK_INFRA_AUD_EG2_CK		22

+#define CK_INFRA_DRAMC_26M_CK		23

+#define CK_INFRA_DBG_CK			24

+#define CK_INFRA_AP_DMA_CK		25

+#define CK_INFRA_SEJ_CK			26

+#define CK_INFRA_SEJ_13M_CK		27

+#define CK_INFRA_THERM_CK		28

+#define CK_INFRA_I2CO_CK		29

+#define CK_INFRA_UART0_CK		30

+#define CK_INFRA_UART1_CK		31

+#define CK_INFRA_UART2_CK		32

+#define CK_INFRA_SPI2_CK		33

+#define CK_INFRA_SPI2_HCK_CK		34

+#define CK_INFRA_NFI1_CK		35

+#define CK_INFRA_SPINFI1_CK		36

+#define CK_INFRA_NFI_HCK_CK		37

+#define CK_INFRA_SPI0_CK		38

+#define CK_INFRA_SPI1_CK		39

+#define CK_INFRA_SPI0_HCK_CK		40

+#define CK_INFRA_SPI1_HCK_CK		41

+#define CK_INFRA_FRTC_CK		42

+#define CK_INFRA_MSDC_CK		43

+#define CK_INFRA_MSDC_HCK_CK		44

+#define CK_INFRA_MSDC_133M_CK		45

+#define CK_INFRA_MSDC_66M_CK		46

+#define CK_INFRA_ADC_26M_CK		47

+#define CK_INFRA_ADC_FRC_CK		48

+#define CK_INFRA_FBIST2FPC_CK		49

+#define CK_INFRA_I2C_MCK_CK		50

+#define CK_INFRA_I2C_PCK_CK		51

+#define CK_INFRA_IUSB_133_CK		52

+#define CK_INFRA_IUSB_66M_CK		53

+#define CK_INFRA_IUSB_SYS_CK		54

+#define CK_INFRA_IUSB_CK		55

+#define CK_INFRA_IPCIE_CK		56

+#define CK_INFRA_IPCIE_PIPE_CK  	57

+#define CK_INFRA_IPCIER_CK		58

+#define CK_INFRA_IPCIEB_CK		59

+#define CLK_INFRA_AO_NR_CLK		60

+

+/* APMIXEDSYS */

+

+#define CK_APMIXED_ARMPLL		0

+#define CK_APMIXED_NET2PLL		1

+#define CK_APMIXED_MMPLL		2

+#define CK_APMIXED_SGMPLL		3

+#define CK_APMIXED_WEDMCUPLL		4

+#define CK_APMIXED_NET1PLL		5

+#define CK_APMIXED_MPLL			6

+#define CK_APMIXED_APLL2		7

+#define CLK_APMIXED_NR_CLK		8

+

+/* SGMIISYS_0 */

+

+#define CK_SGM0_TX_EN			0

+#define CK_SGM0_RX_EN			1

+#define CK_SGM0_CK0_EN			2

+#define CK_SGM0_CDR_CK0_EN		3

+#define CLK_SGMII0_NR_CLK		4

+

+/* SGMIISYS_1 */

+

+#define CK_SGM1_TX_EN			0

+#define CK_SGM1_RX_EN			1

+#define CK_SGM1_CK1_EN			2

+#define CK_SGM1_CDR_CK1_EN		3

+#define CLK_SGMII1_NR_CLK		4

+

+/* ETHSYS */

+

+#define CK_ETH_FE_EN			0

+#define CK_ETH_GP2_EN			1

+#define CK_ETH_GP1_EN			2

+#define CK_ETH_WOCPU0_EN		3

+#define CLK_ETH_NR_CLK			4

+

+#endif /* _DT_BINDINGS_CLK_MT7981_H */

+

diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/dt-bindings/clock/mt7986-clk.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/dt-bindings/clock/mt7986-clk.h
new file mode 100644
index 0000000..284b0bd
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/dt-bindings/clock/mt7986-clk.h
@@ -0,0 +1,252 @@
+/*

+ * Copyright (c) 2017 MediaTek Inc.

+ * Author: Chen Zhong <chen.zhong@mediatek.com>

+ *

+ * This program is free software; you can redistribute it and/or modify

+ * it under the terms of the GNU General Public License version 2 as

+ * published by the Free Software Foundation.

+ *

+ * This program is distributed in the hope that it will be useful,

+ * but WITHOUT ANY WARRANTY; without even the implied warranty of

+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+ * GNU General Public License for more details.

+ */

+

+#ifndef _DT_BINDINGS_CLK_MT7986_H

+#define _DT_BINDINGS_CLK_MT7986_H

+

+/* INFRACFG */

+

+#define CK_INFRA_CK_F26M		0

+#define CK_INFRA_UART			1

+#define CK_INFRA_ISPI0			2

+#define CK_INFRA_I2C			3

+#define CK_INFRA_ISPI1			4

+#define CK_INFRA_PWM			5

+#define CK_INFRA_66M_MCK		6

+#define CK_INFRA_CK_F32K		7

+#define CK_INFRA_PCIE_CK		8

+#define CK_INFRA_PWM_BCK		9

+#define CK_INFRA_PWM_CK1		10

+#define CK_INFRA_PWM_CK2		11

+#define CK_INFRA_133M_HCK		12

+#define CK_INFRA_EIP_CK			13

+#define CK_INFRA_66M_PHCK		14

+#define CK_INFRA_FAUD_L_CK		15

+#define CK_INFRA_FAUD_AUD_CK		16

+#define CK_INFRA_FAUD_EG2_CK		17

+#define CK_INFRA_I2CS_CK		18

+#define CK_INFRA_MUX_UART0		19

+#define CK_INFRA_MUX_UART1		20

+#define CK_INFRA_MUX_UART2		21

+#define CK_INFRA_NFI_CK			22

+#define CK_INFRA_SPINFI_CK		23

+#define CK_INFRA_MUX_SPI0		24

+#define CK_INFRA_MUX_SPI1		25

+#define CK_INFRA_RTC_32K		26

+#define CK_INFRA_FMSDC_CK		27

+#define CK_INFRA_FMSDC_HCK_CK		28

+#define CK_INFRA_PERI_133M		29

+#define CK_INFRA_133M_PHCK		30

+#define CK_INFRA_USB_SYS_CK		31

+#define CK_INFRA_USB_CK			32

+#define CK_INFRA_USB_XHCI_CK		33

+#define CK_INFRA_PCIE_GFMUX_TL_O_PRE	34

+#define CK_INFRA_F26M_CK0		35

+#define CK_INFRA_HD_133M        36

+#define CLK_INFRA_NR_CLK		37

+

+/* TOPCKGEN */

+

+#define CK_TOP_CB_CKSQ_40M		0

+#define CK_TOP_CB_M_416M		1

+#define CK_TOP_CB_M_D2			2

+#define CK_TOP_CB_M_D4			3

+#define CK_TOP_CB_M_D8			4

+#define CK_TOP_M_D8_D2			5

+#define CK_TOP_M_D3_D2			6

+#define CK_TOP_CB_MM_D2			7

+#define CK_TOP_CB_MM_D4			8

+#define CK_TOP_CB_MM_D8			9

+#define CK_TOP_MM_D8_D2			10

+#define CK_TOP_MM_D3_D8			11

+#define CK_TOP_CB_U2_PHYD_CK		12

+#define CK_TOP_CB_APLL2_196M		13

+#define CK_TOP_APLL2_D4			14

+#define CK_TOP_CB_NET1_D4		15

+#define CK_TOP_CB_NET1_D5		16

+#define CK_TOP_NET1_D5_D2		17

+#define CK_TOP_NET1_D5_D4		18

+#define CK_TOP_NET1_D8_D2		19

+#define CK_TOP_NET1_D8_D4		20

+#define CK_TOP_CB_NET2_800M		21

+#define CK_TOP_CB_NET2_D4		22

+#define CK_TOP_NET2_D4_D2		23

+#define CK_TOP_NET2_D3_D2		24

+#define CK_TOP_CB_WEDMCU_760M		25

+#define CK_TOP_WEDMCU_D5_D2		26

+#define CK_TOP_CB_SGM_325M		27

+#define CK_TOP_CB_CKSQ_40M_D2		28

+#define CK_TOP_CB_RTC_32K		29

+#define CK_TOP_CB_RTC_32P7K		30

+#define CK_TOP_NFI1X			31

+#define CK_TOP_USB_EQ_RX250M		32

+#define CK_TOP_USB_TX250M		33

+#define CK_TOP_USB_LN0_CK		34

+#define CK_TOP_USB_CDR_CK		35

+#define CK_TOP_SPINFI_BCK		36

+#define CK_TOP_I2C_BCK			37

+#define CK_TOP_PEXTP_TL			38

+#define CK_TOP_EMMC_250M		39

+#define CK_TOP_EMMC_416M		40

+#define CK_TOP_F_26M_ADC_CK		41

+#define CK_TOP_SYSAXI			42

+#define CK_TOP_NETSYS_WED_MCU		43

+#define CK_TOP_NETSYS_2X		44

+#define CK_TOP_SGM_325M			45

+#define CK_TOP_A1SYS			46

+#define CK_TOP_EIP_B			47

+#define CK_TOP_F26M			48

+#define CK_TOP_AUD_L			49

+#define CK_TOP_A_TUNER			50

+#define CK_TOP_U2U3_REF			51

+#define CK_TOP_U2U3_SYS			52

+#define CK_TOP_U2U3_XHCI		53

+#define CK_TOP_AP2CNN_HOST		54

+#define CK_TOP_NFI1X_SEL		55

+#define CK_TOP_SPINFI_SEL		56

+#define CK_TOP_SPI_SEL			57

+#define CK_TOP_SPIM_MST_SEL		58

+#define CK_TOP_UART_SEL			59

+#define CK_TOP_PWM_SEL			60

+#define CK_TOP_I2C_SEL			61

+#define CK_TOP_PEXTP_TL_SEL		62

+#define CK_TOP_EMMC_250M_SEL		63

+#define CK_TOP_EMMC_416M_SEL		64

+#define CK_TOP_F_26M_ADC_SEL		65

+#define CK_TOP_DRAMC_SEL		66

+#define CK_TOP_DRAMC_MD32_SEL		67

+#define CK_TOP_SYSAXI_SEL		68

+#define CK_TOP_SYSAPB_SEL		69

+#define CK_TOP_ARM_DB_MAIN_SEL		70

+#define CK_TOP_ARM_DB_JTSEL		71

+#define CK_TOP_NETSYS_SEL		72

+#define CK_TOP_NETSYS_500M_SEL		73

+#define CK_TOP_NETSYS_MCU_SEL		74

+#define CK_TOP_NETSYS_2X_SEL		75

+#define CK_TOP_SGM_325M_SEL		76

+#define CK_TOP_SGM_REG_SEL		77

+#define CK_TOP_A1SYS_SEL		78

+#define CK_TOP_CONN_MCUSYS_SEL		79

+#define CK_TOP_EIP_B_SEL		80

+#define CK_TOP_PCIE_PHY_SEL		81

+#define CK_TOP_USB3_PHY_SEL		82

+#define CK_TOP_F26M_SEL			83

+#define CK_TOP_AUD_L_SEL		84

+#define CK_TOP_A_TUNER_SEL		85

+#define CK_TOP_U2U3_SEL			86

+#define CK_TOP_U2U3_SYS_SEL		87

+#define CK_TOP_U2U3_XHCI_SEL		88

+#define CK_TOP_DA_U2_REFSEL		89

+#define CK_TOP_DA_U2_CK_1P_SEL		90

+#define CK_TOP_AP2CNN_HOST_SEL		91

+#define CLK_TOP_NR_CLK			92

+

+/* INFRACFG_AO */

+

+#define CK_INFRA_UART0_SEL		0

+#define CK_INFRA_UART1_SEL		1

+#define CK_INFRA_UART2_SEL		2

+#define CK_INFRA_SPI0_SEL		3

+#define CK_INFRA_SPI1_SEL		4

+#define CK_INFRA_PWM1_SEL		5

+#define CK_INFRA_PWM2_SEL		6

+#define CK_INFRA_PWM_BSEL		7

+#define CK_INFRA_PCIE_SEL		8

+#define CK_INFRA_GPT_STA		9

+#define CK_INFRA_PWM_HCK		10

+#define CK_INFRA_PWM_STA		11

+#define CK_INFRA_PWM1_CK		12

+#define CK_INFRA_PWM2_CK		13

+#define CK_INFRA_CQ_DMA_CK		14

+#define CK_INFRA_EIP97_CK		15

+#define CK_INFRA_AUD_BUS_CK		16

+#define CK_INFRA_AUD_26M_CK		17

+#define CK_INFRA_AUD_L_CK		18

+#define CK_INFRA_AUD_AUD_CK		19

+#define CK_INFRA_AUD_EG2_CK		20

+#define CK_INFRA_DRAMC_26M_CK		21

+#define CK_INFRA_DBG_CK			22

+#define CK_INFRA_AP_DMA_CK		23

+#define CK_INFRA_SEJ_CK			24

+#define CK_INFRA_SEJ_13M_CK		25

+#define CK_INFRA_THERM_CK		26

+#define CK_INFRA_I2CO_CK		27

+#define CK_INFRA_UART0_CK		28

+#define CK_INFRA_UART1_CK		29

+#define CK_INFRA_UART2_CK		30

+#define CK_INFRA_NFI1_CK		31

+#define CK_INFRA_SPINFI1_CK		32

+#define CK_INFRA_NFI_HCK_CK		33

+#define CK_INFRA_SPI0_CK		34

+#define CK_INFRA_SPI1_CK		35

+#define CK_INFRA_SPI0_HCK_CK		36

+#define CK_INFRA_SPI1_HCK_CK		37

+#define CK_INFRA_FRTC_CK		38

+#define CK_INFRA_MSDC_CK		39

+#define CK_INFRA_MSDC_HCK_CK		40

+#define CK_INFRA_MSDC_133M_CK		41

+#define CK_INFRA_MSDC_66M_CK		42

+#define CK_INFRA_ADC_26M_CK		43

+#define CK_INFRA_ADC_FRC_CK		44

+#define CK_INFRA_FBIST2FPC_CK		45

+#define CK_INFRA_IUSB_133_CK		46

+#define CK_INFRA_IUSB_66M_CK		47

+#define CK_INFRA_IUSB_SYS_CK		48

+#define CK_INFRA_IUSB_CK		49

+#define CK_INFRA_IPCIE_CK		50

+#define CK_INFRA_IPCIE_PIPE_CK  51

+#define CK_INFRA_IPCIER_CK		52

+#define CK_INFRA_IPCIEB_CK		53

+#define CK_INFRA_TRNG_CK		54

+#define CLK_INFRA_AO_NR_CLK		55

+

+/* APMIXEDSYS */

+

+#define CK_APMIXED_ARMPLL		0

+#define CK_APMIXED_NET2PLL		1

+#define CK_APMIXED_MMPLL		2

+#define CK_APMIXED_SGMPLL		3

+#define CK_APMIXED_WEDMCUPLL		4

+#define CK_APMIXED_NET1PLL		5

+#define CK_APMIXED_MPLL			6

+#define CK_APMIXED_APLL2		7

+#define CLK_APMIXED_NR_CLK		8

+

+/* SGMIISYS_0 */

+

+#define CK_SGM0_TX_EN			0

+#define CK_SGM0_RX_EN			1

+#define CK_SGM0_CK0_EN			2

+#define CK_SGM0_CDR_CK0_EN		3

+#define CLK_SGMII0_NR_CLK		4

+

+/* SGMIISYS_1 */

+

+#define CK_SGM1_TX_EN			0

+#define CK_SGM1_RX_EN			1

+#define CK_SGM1_CK1_EN			2

+#define CK_SGM1_CDR_CK1_EN		3

+#define CLK_SGMII1_NR_CLK		4

+

+/* ETHSYS */

+

+#define CK_ETH_FE_EN			0

+#define CK_ETH_GP2_EN			1

+#define CK_ETH_GP1_EN			2

+#define CK_ETH_WOCPU1_EN		3

+#define CK_ETH_WOCPU0_EN		4

+#define CLK_ETH_NR_CLK			5

+

+#endif /* _DT_BINDINGS_CLK_MT7986_H */

+

diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/dt-bindings/reset/mt7986-resets.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/dt-bindings/reset/mt7986-resets.h
new file mode 100644
index 0000000..98ffaf7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/dt-bindings/reset/mt7986-resets.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2019 MediaTek Inc. */
+
+#ifndef _DT_BINDINGS_RESET_CONTROLLER_MT2712
+#define _DT_BINDINGS_RESET_CONTROLLER_MT2712
+
+#define MT7986_TOPRGU_CONSYS_RST				23
+
+#define MT7986_TOPRGU_SW_RST_NUM				32
+
+#endif  /* _DT_BINDINGS_RESET_CONTROLLER_MT2712 */
\ No newline at end of file
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/linux/soc/mediatek/mtk_sip_svc.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/linux/soc/mediatek/mtk_sip_svc.h
new file mode 100644
index 0000000..24d5c65
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/linux/soc/mediatek/mtk_sip_svc.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 MediaTek Inc.
+ */
+#ifndef __MTK_SIP_SVC_H
+#define __MTK_SIP_SVC_H
+
+/* Error Code */
+#define SIP_SVC_E_SUCCESS               0
+#define SIP_SVC_E_NOT_SUPPORTED         -1
+#define SIP_SVC_E_INVALID_PARAMS        -2
+#define SIP_SVC_E_INVALID_RANGE         -3
+#define SIP_SVC_E_PERMISSION_DENIED     -4
+
+#ifdef CONFIG_ARM64
+#define MTK_SIP_SMC_CONVENTION          ARM_SMCCC_SMC_64
+#else
+#define MTK_SIP_SMC_CONVENTION          ARM_SMCCC_SMC_32
+#endif
+
+#define MTK_SIP_SMC_CMD(fn_id) \
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, MTK_SIP_SMC_CONVENTION, \
+			   ARM_SMCCC_OWNER_SIP, fn_id)
+
+#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/net/ra_nat.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/net/ra_nat.h
new file mode 100755
index 0000000..83412a4
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/net/ra_nat.h
@@ -0,0 +1,558 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: Harry Huang <harry.huang@mediatek.com>
+ */
+
+#ifndef _RA_NAT_WANTED
+#define _RA_NAT_WANTED
+
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+
+
+#ifndef NEXTHDR_IPIP
+#define NEXTHDR_IPIP 4
+#endif
+
+#define hwnat_vlan_tx_tag_present(__skb)     ((__skb)->vlan_tci & VLAN_TAG_PRESENT)
+#define hwnat_vlan_tag_get(__skb)         ((__skb)->vlan_tci & ~VLAN_TAG_PRESENT)
+
+#if defined(CONFIG_HW_NAT)
+extern void hwnat_magic_tag_set_zero(struct sk_buff *skb);
+extern void hwnat_check_magic_tag(struct sk_buff *skb);
+extern void hwnat_set_headroom_zero(struct sk_buff *skb);
+extern void hwnat_set_tailroom_zero(struct sk_buff *skb);
+extern void hwnat_copy_headroom(u8 *data, struct sk_buff *skb);
+extern void hwnat_copy_tailroom(u8 *data, int size, struct sk_buff *skb);
+extern void hwnat_setup_dma_ops(struct device *dev, bool coherent);
+#else
+
+static inline void hwnat_magic_tag_set_zero(struct sk_buff *skb)
+{
+}
+
+static inline void hwnat_check_magic_tag(struct sk_buff *skb)
+{
+}
+
+static inline void hwnat_set_headroom_zero(struct sk_buff *skb)
+{
+}
+
+static inline void hwnat_set_tailroom_zero(struct sk_buff *skb)
+{
+}
+
+static inline void hwnat_copy_headroom(u8 *data, struct sk_buff *skb)
+{
+}
+
+static inline void hwnat_copy_tailroom(u8 *data, int size, struct sk_buff *skb)
+{
+}
+
+#endif
+enum foe_cpu_reason {
+	TTL_0 = 0x02,		/* IPv4(IPv6) TTL(hop limit) = 0 */
+	/* IPv4(IPv6) has option(extension) header */
+	HAS_OPTION_HEADER = 0x03,
+	NO_FLOW_IS_ASSIGNED = 0x07,	/* No flow is assigned */
+	/* IPv4 HNAT doesn't support IPv4 /w fragment */
+	IPV4_WITH_FRAGMENT = 0x08,
+	/* IPv4 HNAPT/DS-Lite doesn't support IPv4 /w fragment */
+	IPV4_HNAPT_DSLITE_WITH_FRAGMENT = 0x09,
+	/* IPv4 HNAPT/DS-Lite can't find TCP/UDP sport/dport */
+	IPV4_HNAPT_DSLITE_WITHOUT_TCP_UDP = 0x0A,
+	/* IPv6 5T-route/6RD can't find TCP/UDP sport/dport */
+	IPV6_5T_6RD_WITHOUT_TCP_UDP = 0x0B,
+	/* Ingress packet is TCP fin/syn/rst */
+	/*(for IPv4 NAPT/DS-Lite or IPv6 5T-route/6RD) */
+	TCP_FIN_SYN_RST = 0x0C,
+	UN_HIT = 0x0D,		/* FOE Un-hit */
+	HIT_UNBIND = 0x0E,	/* FOE Hit unbind */
+	/* FOE Hit unbind & rate reach */
+	HIT_UNBIND_RATE_REACH = 0x0F,
+	HIT_BIND_TCP_FIN = 0x10,	/* Hit bind PPE TCP FIN entry */
+	/* Hit bind PPE entry and TTL(hop limit) = 1 */
+	/* and TTL(hot limit) - 1 */
+	HIT_BIND_TTL_1 = 0x11,
+	/* Hit bind and VLAN replacement violation */
+	/*(Ingress 1(0) VLAN layers and egress 4(3 or 4) VLAN layers) */
+	HIT_BIND_WITH_VLAN_VIOLATION = 0x12,
+	/* Hit bind and keep alive with unicast old-header packet */
+	HIT_BIND_KEEPALIVE_UC_OLD_HDR = 0x13,
+	/* Hit bind and keep alive with multicast new-header packet */
+	HIT_BIND_KEEPALIVE_MC_NEW_HDR = 0x14,
+	/* Hit bind and keep alive with duplicate old-header packet */
+	HIT_BIND_KEEPALIVE_DUP_OLD_HDR = 0x15,
+	/* FOE Hit bind & force to CPU */
+	HIT_BIND_FORCE_TO_CPU = 0x16,
+	/* Hit bind and remove tunnel IP header, */
+	/* but inner IP has option/next header */
+	HIT_BIND_WITH_OPTION_HEADER = 0x17,
+	/* Hit bind and exceed MTU */
+	HIT_BIND_EXCEED_MTU = 0x1C,
+	HIT_BIND_PACKET_SAMPLING = 0x1B,	/*  PS packet */
+	/*  Switch clone multicast packet to CPU */
+	HIT_BIND_MULTICAST_TO_CPU = 0x18,
+	/*  Switch clone multicast packet to GMAC1 & CPU */
+	HIT_BIND_MULTICAST_TO_GMAC_CPU = 0x19,
+	HIT_PRE_BIND = 0x1A	/*  Pre-bind */
+};
+
+#define MAX_IF_NUM 64
+
+struct dmad_rx_descinfo4 {
+	uint32_t foe_entry_num:15;
+	uint32_t rsv0:3;
+	uint32_t CRSN:5;
+	uint32_t rsv1:3;
+	uint32_t SPORT:4;
+	uint32_t ppe:1;
+	uint32_t ALG:1;
+	uint32_t IF:8;
+	uint32_t WDMAID:2;
+	uint32_t RXID:2;
+	uint32_t WCID:10;
+	uint32_t BSSID:6;
+	uint32_t rsv3:4;
+	uint16_t minfo:1;
+	uint16_t ntype:3;
+	uint16_t chid:8;
+	uint16_t rsv4:4;
+	u16 MAGIC_TAG_PROTECT;
+} __packed;
+
+struct pdma_rx_desc_info4 {
+	u16 MAGIC_TAG_PROTECT;
+	uint32_t foe_entry_num:14;
+	uint32_t CRSN:5;
+	uint32_t SPORT:4;
+	uint32_t rsv:6;
+	uint32_t foe_entry_num_1:1;
+	uint32_t ppe:1;
+	uint32_t ALG:1;
+	uint32_t IF:8;
+	uint32_t WDMAID:2;
+	uint32_t RXID:2;
+	uint32_t WCID:10;
+	uint32_t BSSID:6;
+	uint32_t rsv2:4;
+	uint16_t minfo:1;
+	uint16_t ntype:3;
+	uint16_t chid:8;
+	uint16_t rsv3:4;
+#if defined(CONFIG_RA_HW_NAT_PPTP_L2TP)
+	u16 SOURCE;
+	u16 DEST;
+#endif
+} __packed;
+
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+struct head_rx_descinfo4 {
+	uint32_t foe_entry_num:14;
+	uint32_t CRSN:5;
+	uint32_t SPORT:4;
+	uint32_t rsv:6;
+	uint32_t foe_entry_num_1:1;
+	uint32_t ppe:1;
+	uint32_t ALG:1;
+	uint32_t IF:8;
+	uint32_t WDMAID:2;
+	uint32_t RXID:2;
+	uint32_t WCID:10;
+	uint32_t BSSID:6;
+	uint32_t rsv2:4;
+	uint16_t minfo:1;
+	uint16_t ntype:3;
+	uint16_t chid:8;
+	uint16_t rsv3:4;
+#if defined(CONFIG_RA_HW_NAT_PPTP_L2TP)
+	u16 SOURCE;
+	u16 DEST;
+#endif
+	u16 MAGIC_TAG_PROTECT;
+} __packed;
+#else
+struct head_rx_descinfo4 {
+	uint32_t foe_entry_num:14;
+	uint32_t CRSN:5;
+	uint32_t SPORT:3;
+	uint32_t rsv:1;
+	uint32_t ALG:1;
+	uint32_t IF:4;
+	uint32_t rsv2:4;
+	uint32_t MAGIC_TAG_PROTECT: 16;
+	uint32_t WDMAID:2;
+	uint32_t RXID:2;
+	uint32_t WCID:10;
+	uint32_t BSSID:6;
+#if defined(CONFIG_RA_HW_NAT_PPTP_L2TP)
+	u16 SOURCE;
+	u16 DEST;
+#endif
+} __packed;
+#endif
+
+struct cb_rx_desc_info4 {
+	u16 MAGIC_TAG_PROTECT0;
+	uint32_t foe_entry_num:15;
+	uint32_t CRSN:5;
+	uint32_t SPORT:4;
+	uint32_t ALG:1;
+	uint32_t rsv:7;
+	uint16_t IF:8;
+	uint16_t WDMAID:2;
+	uint16_t RXID:2;
+	uint16_t WCID:10;
+	uint16_t BSSID:6;
+	uint16_t rsv1:4;
+	uint16_t minfo:1;
+	uint16_t ntype:3;
+	uint16_t chid:8;
+	uint16_t rsv2:4;
+#if defined(CONFIG_RA_HW_NAT_PPTP_L2TP)
+	u16 SOURCE;
+	u16 DEST;
+#endif
+	u16 MAGIC_TAG_PROTECT1;
+} __packed;
+
+
+
+#define FOE_INFO_LEN		    12
+#define WIFI_INFO_LEN		    6
+
+
+#if defined(CONFIG_RA_HW_NAT_PPTP_L2TP)
+#define FOE_INFO_LEN		    (6 + 4 + WIFI_INFO_LEN)
+#define FOE_MAGIC_FASTPATH	    0x77
+#define FOE_MAGIC_L2TPPATH	    0x78
+#endif
+
+#define FOE_MAGIC_PCI		    0x73
+#define FOE_MAGIC_WLAN		    0x74
+#define FOE_MAGIC_GE		    0x75
+#define FOE_MAGIC_PPE		    0x76
+#define FOE_MAGIC_WED0		    0x78
+#define FOE_MAGIC_WED1		    0x79
+#define FOE_MAGIC_MED		    0x80
+#define FOE_MAGIC_EDMA0		    0x81
+#define FOE_MAGIC_EDMA1		    0x82
+#define TAG_PROTECT                 0x6789
+#define USE_HEAD_ROOM               0
+#define USE_TAIL_ROOM               1
+#define USE_CB                      2
+#define ALL_INFO_ERROR              3
+
+/**************************DMAD FORMAT********************************/
+#define FOE_TAG_PROTECT(skb)  \
+	(((struct dmad_rx_descinfo4 *)((skb)->head))->MAGIC_TAG_PROTECT)
+
+#define FOE_ENTRY_NUM(skb)  \
+	(((struct dmad_rx_descinfo4 *)((skb)->head))->foe_entry_num)
+#define FOE_ALG(skb)  \
+	(((struct dmad_rx_descinfo4 *)((skb)->head))->ALG)
+#define FOE_AI(skb)  \
+	(((struct dmad_rx_descinfo4 *)((skb)->head))->CRSN)
+#define FOE_SP(skb)  \
+	(((struct dmad_rx_descinfo4 *)((skb)->head))->SPORT)
+#define FOE_MAGIC_TAG(skb)  \
+	(((struct dmad_rx_descinfo4 *)((skb)->head))->IF)
+#define FOE_WDMA_ID(skb)  \
+	(((struct dmad_rx_descinfo4 *)((skb)->head))->WDMAID)
+#define FOE_RX_ID(skb)	(((struct dmad_rx_descinfo4 *)((skb)->head))->RXID)
+#define FOE_WC_ID(skb)	(((struct dmad_rx_descinfo4 *)((skb)->head))->WCID)
+#define FOE_BSS_ID(skb)	(((struct dmad_rx_descinfo4 *)((skb)->head))->BSSID)
+#define FOE_PPE(skb)	(((struct dmad_rx_descinfo4 *)((skb)->head))->ppe)
+
+/***********************HEAD FORMAT*************************************/
+
+#define FOE_TAG_PROTECT_HEAD(skb)  \
+	(((struct head_rx_descinfo4 *)((skb)->head))->MAGIC_TAG_PROTECT)
+#define FOE_ENTRY_NUM_LSB_HEAD(skb)  \
+	(((struct head_rx_descinfo4 *)((skb)->head))->foe_entry_num)
+#define FOE_ENTRY_NUM_MSB_HEAD(skb)  \
+	(((struct head_rx_descinfo4 *)((skb)->head))->foe_entry_num_1)
+
+#define FOE_ENTRY_NUM_HEAD(skb)  \
+	(((FOE_ENTRY_NUM_MSB_HEAD(skb) & 0x1) << 14) | FOE_ENTRY_NUM_LSB_HEAD(skb))
+
+
+#define FOE_ALG_HEAD(skb)  \
+	(((struct head_rx_descinfo4 *)((skb)->head))->ALG)
+#define FOE_AI_HEAD(skb)  \
+	(((struct head_rx_descinfo4 *)((skb)->head))->CRSN)
+#define FOE_SP_HEAD(skb)  \
+	(((struct head_rx_descinfo4 *)((skb)->head))->SPORT)
+#define FOE_MAGIC_TAG_HEAD(skb)  \
+	(((struct head_rx_descinfo4 *)((skb)->head))->IF)
+
+
+#define FOE_WDMA_ID_HEAD(skb)  \
+	(((struct head_rx_descinfo4 *)((skb)->head))->WDMAID)
+#define FOE_RX_ID_HEAD(skb)  \
+	(((struct head_rx_descinfo4 *)((skb)->head))->RXID)
+#define FOE_WC_ID_HEAD(skb)  \
+	(((struct head_rx_descinfo4 *)((skb)->head))->WCID)
+#define FOE_BSS_ID_HEAD(skb)  \
+	(((struct head_rx_descinfo4 *)((skb)->head))->BSSID)
+#define FOE_PPE_HEAD(skb)  \
+	(((struct head_rx_descinfo4 *)((skb)->head))->PPE)
+
+/****************************TAIL FORMAT***************************************/
+#define FOE_TAG_PROTECT_TAIL(skb)  \
+	(((struct pdma_rx_desc_info4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->MAGIC_TAG_PROTECT)
+#define FOE_ENTRY_NUM_LSB_TAIL(skb)  \
+	(((struct pdma_rx_desc_info4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->foe_entry_num)
+
+#define FOE_ENTRY_NUM_MSB_TAIL(skb)  \
+	(((struct pdma_rx_desc_info4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->foe_entry_num_1)
+#define FOE_ENTRY_NUM_TAIL(skb)  \
+	(((FOE_ENTRY_NUM_MSB_TAIL(skb) & 0x1) << 14) | FOE_ENTRY_NUM_LSB_TAIL(skb))
+#define FOE_ALG_TAIL(skb)  \
+	(((struct pdma_rx_desc_info4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->ALG)
+#define FOE_AI_TAIL(skb)  \
+	(((struct pdma_rx_desc_info4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->CRSN)
+#define FOE_SP_TAIL(skb)  \
+	(((struct pdma_rx_desc_info4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->SPORT)
+#define FOE_MAGIC_TAG_TAIL(skb)  \
+	(((struct pdma_rx_desc_info4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->IF)
+
+#define FOE_WDMA_ID_TAIL(skb)  \
+	(((struct pdma_rx_desc_info4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->WDMAID)
+#define FOE_RX_ID_TAIL(skb)  \
+	(((struct pdma_rx_desc_info4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->RXID)
+#define FOE_WC_ID_TAIL(skb)  \
+	(((struct pdma_rx_desc_info4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->WCID)
+#define FOE_BSS_ID_TAIL(skb)  \
+	(((struct pdma_rx_desc_info4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->BSSID)
+
+#define FOE_PPE_TAIL(skb)  \
+	(((struct pdma_rx_desc_info4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->ppe)
+/*********************************************************************/
+#define FOE_WDMA_ID_CB(skb)  \
+	(((struct cb_rx_desc_info4 *)((skb)->head))->WDMAID)
+#define FOE_RX_ID_CB(skb)  \
+	(((struct cb_rx_desc_info4 *)((skb)->head))->RXID)
+#define FOE_WC_ID_CB(skb)  \
+	(((struct cb_rx_desc_info4 *)((skb)->head))->WCID)
+#define FOE_BSS_ID_CB(skb)  \
+	(((struct cb_rx_desc_info4 *)((skb)->head))->BSSID)
+
+#define FOE_MINFO(skb)	(((struct head_rx_descinfo4 *)((skb)->head))->minfo)
+#define FOE_MINFO_NTYPE(skb)	(((struct head_rx_descinfo4 *)((skb)->head))->ntype)
+#define FOE_MINFO_CHID(skb)	(((struct head_rx_descinfo4 *)((skb)->head))->chid)
+#define FOE_MINFO_HEAD(skb)	(((struct head_rx_descinfo4 *)((skb)->head))->minfo)
+#define FOE_MINFO_NTYPE_HEAD(skb)	(((struct head_rx_descinfo4 *)((skb)->head))->ntype)
+#define FOE_MINFO_CHID_HEAD(skb)	(((struct head_rx_descinfo4 *)((skb)->head))->chid)
+
+#define FOE_MINFO_TAIL(skb)  \
+	(((struct pdma_rx_desc_info4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->minfo)
+#define FOE_MINFO_NTYPE_TAIL(skb)  \
+	(((struct pdma_rx_desc_info4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->ntype)
+#define FOE_MINFO_CHID_TAIL(skb)  \
+	(((struct pdma_rx_desc_info4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->chid)
+
+#if defined(CONFIG_RA_HW_NAT_PPTP_L2TP)
+#define FOE_SOURCE(skb)	(((struct head_rx_descinfo4 *)((skb)->head))->SOURCE)
+#define FOE_DEST(skb)	(((struct head_rx_descinfo4 *)((skb)->head))->DEST)
+#endif
+
+#define IS_SPACE_AVAILABLE_HEAD(skb)  \
+	((((skb_headroom(skb) >= FOE_INFO_LEN) ? 1 : 0)))
+#define IS_SPACE_AVAILABLE_HEAD(skb)  \
+	((((skb_headroom(skb) >= FOE_INFO_LEN) ? 1 : 0)))
+#define FOE_INFO_START_ADDR_HEAD(skb)	(skb->head)
+
+#if defined(CONFIG_RA_HW_NAT_PPTP_L2TP)
+#define FOE_SOURCE_HEAD(skb)  \
+	(((struct head_rx_descinfo4 *)((skb)->head))->SOURCE)
+#define FOE_DEST_HEAD(skb)  \
+	(((struct head_rx_descinfo4 *)((skb)->head))->DEST)
+#endif
+
+#if defined(CONFIG_RA_HW_NAT_PPTP_L2TP)
+#define FOE_SOURCE_HEAD(skb)  \
+	(((struct head_rx_descinfo4 *)((skb)->head))->SOURCE)
+#define FOE_DEST_HEAD(skb)  \
+	(((struct head_rx_descinfo4 *)((skb)->head))->DEST)
+#endif
+#define IS_SPACE_AVAILABLE_TAIL(skb)  \
+	(((skb_tailroom(skb) >= FOE_INFO_LEN) ? 1 : 0))
+#define IS_SPACE_AVAILABLE_TAIL(skb)  \
+	(((skb_tailroom(skb) >= FOE_INFO_LEN) ? 1 : 0))
+#define FOE_INFO_START_ADDR_TAIL(skb)  \
+	((unsigned char *)(long)(skb_end_pointer(skb) - FOE_INFO_LEN))
+
+#if defined(CONFIG_RA_HW_NAT_PPTP_L2TP)
+#define FOE_SOURCE_TAIL(skb)  \
+	(((struct pdma_rx_desc_info4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->SOURCE)
+#define FOE_DEST_TAIL(skb)  \
+	(((struct pdma_rx_desc_info4 *)((long)((skb_end_pointer(skb)) - FOE_INFO_LEN)))->DEST)
+#endif
+
+/* change the position of skb_CB if necessary */
+#define CB_OFFSET		    40
+#define IS_SPACE_AVAILABLE_CB(skb)    1
+#define FOE_INFO_START_ADDR_CB(skb)    (skb->cb +  CB_OFFSET)
+#define FOE_TAG_PROTECT_CB0(skb)  \
+	(((struct cb_rx_desc_info4 *)((skb)->cb + CB_OFFSET))->MAGIC_TAG_PROTECT0)
+#define FOE_TAG_PROTECT_CB1(skb)  \
+	(((struct cb_rx_desc_info4 *)((skb)->cb + CB_OFFSET))->MAGIC_TAG_PROTECT1)
+#define FOE_ENTRY_NUM_CB(skb)  \
+	(((struct cb_rx_desc_info4 *)((skb)->cb + CB_OFFSET))->foe_entry_num)
+#define FOE_ALG_CB(skb)  \
+	(((struct cb_rx_desc_info4 *)((skb)->cb + CB_OFFSET))->ALG)
+#define FOE_AI_CB(skb)  \
+	(((struct cb_rx_desc_info4 *)((skb)->cb + CB_OFFSET))->CRSN)
+#define FOE_SP_CB(skb)  \
+	(((struct cb_rx_desc_info4 *)((skb)->cb + CB_OFFSET))->SPORT)
+#define FOE_MAGIC_TAG_CB(skb)  \
+	(((struct cb_rx_desc_info4 *)((skb)->cb + CB_OFFSET))->IF)
+
+#if defined(CONFIG_RA_HW_NAT_PPTP_L2TP)
+#define FOE_SOURCE_CB(skb)	(((struct cb_rx_desc_info4 *)((skb)->cb + CB_OFFSET))->SOURCE)
+#define FOE_DEST_CB(skb)	(((struct cb_rx_desc_info4 *)((skb)->cb + CB_OFFSET))->DEST)
+#endif
+
+#define IS_MAGIC_TAG_PROTECT_VALID_HEAD(skb)  \
+	(FOE_TAG_PROTECT_HEAD(skb) == TAG_PROTECT)
+#define IS_MAGIC_TAG_PROTECT_VALID_TAIL(skb)  \
+	(FOE_TAG_PROTECT_TAIL(skb) == TAG_PROTECT)
+#define IS_MAGIC_TAG_PROTECT_VALID_CB(skb)  \
+	((FOE_TAG_PROTECT_CB0(skb) == TAG_PROTECT) && \
+	(FOE_TAG_PROTECT_CB0(skb) == FOE_TAG_PROTECT_CB1(skb)))
+
+#define IS_IF_PCIE_WLAN_HEAD(skb)  \
+	((FOE_MAGIC_TAG_HEAD(skb) == FOE_MAGIC_PCI) || \
+	(FOE_MAGIC_TAG_HEAD(skb) == FOE_MAGIC_WLAN) || \
+	(FOE_MAGIC_TAG_HEAD(skb) == FOE_MAGIC_GE))
+
+#define IS_IF_PCIE_WLAN_TAIL(skb)  \
+	((FOE_MAGIC_TAG_TAIL(skb) == FOE_MAGIC_PCI) || \
+	(FOE_MAGIC_TAG_TAIL(skb) == FOE_MAGIC_WLAN))
+
+#define IS_IF_PCIE_WLAN_CB(skb)  \
+	((FOE_MAGIC_TAG_CB(skb) == FOE_MAGIC_PCI) || \
+	(FOE_MAGIC_TAG_CB(skb) == FOE_MAGIC_WLAN))
+
+/* macros */
+#define magic_tag_set_zero(skb) \
+{ \
+	if ((FOE_MAGIC_TAG_HEAD(skb) == FOE_MAGIC_PCI) || \
+	    (FOE_MAGIC_TAG_HEAD(skb) == FOE_MAGIC_WLAN) || \
+	    (FOE_MAGIC_TAG_HEAD(skb) == FOE_MAGIC_GE)) { \
+		if (IS_SPACE_AVAILABLE_HEAD(skb)) \
+			FOE_MAGIC_TAG_HEAD(skb) = 0; \
+	} \
+	if ((FOE_MAGIC_TAG_TAIL(skb) == FOE_MAGIC_PCI) || \
+	    (FOE_MAGIC_TAG_TAIL(skb) == FOE_MAGIC_WLAN) || \
+	    (FOE_MAGIC_TAG_TAIL(skb) == FOE_MAGIC_GE)) { \
+		if (IS_SPACE_AVAILABLE_TAIL(skb)) \
+			FOE_MAGIC_TAG_TAIL(skb) = 0; \
+	} \
+}
+
+static inline void hwnat_set_l2tp_unhit(struct iphdr *iph, struct sk_buff *skb)
+{
+#if defined(CONFIG_RA_HW_NAT_PPTP_L2TP)
+	/* only clear headeroom for TCP OR not L2TP packets */
+	if ((iph->protocol == 0x6) || (ntohs(udp_hdr(skb)->dest) != 1701)) {
+		if (IS_SPACE_AVAILABLE_HEAD(skb)) {
+			FOE_MAGIC_TAG(skb) = 0;
+			FOE_AI(skb) = UN_HIT;
+		}
+	}
+#endif
+}
+
+static inline void hwnat_set_l2tp_fast_path(u32 l2tp_fast_path, u32 pptp_fast_path)
+{
+#if defined(CONFIG_RA_HW_NAT_PPTP_L2TP)
+	l2tp_fast_path = 1;
+	pptp_fast_path = 0;
+#endif
+}
+
+static inline void hwnat_clear_l2tp_fast_path(u32 l2tp_fast_path)
+{
+#if defined(CONFIG_RA_HW_NAT_PPTP_L2TP)
+	l2tp_fast_path = 0;
+#endif
+}
+
+/* #define CONFIG_HW_NAT_IPI */
+#if defined(CONFIG_HW_NAT_IPI)
+extern int debug_level;
+int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
+		struct rps_dev_flow **rflowp);
+uint32_t ppe_extif_rx_handler(struct sk_buff *skb);
+int hitbind_force_to_cpu_handler(struct sk_buff *skb, struct foe_entry *entry);
+extern unsigned int ipidbg[num_possible_cpus()][10];
+extern unsigned int ipidbg2[num_possible_cpus()][10];
+/* #define HNAT_IPI_RXQUEUE	1 */
+#define HNAT_IPI_DQ		1
+#define HNAT_IPI_HASH_NORMAL	0
+#define HNAT_IPI_HASH_VTAG		1
+#define HNAT_IPI_HASH_FROM_EXTIF	2
+#define HNAT_IPI_HASH_FROM_GMAC		4
+
+struct hnat_ipi_s {
+#if defined(HNAT_IPI_DQ)
+	struct sk_buff_head     skb_input_queue;
+	struct sk_buff_head     skb_process_queue;
+#elif defined(HNAT_IPI_RXQUEUE)
+	atomic_t rx_queue_num;
+	unsigned int rx_queue_ridx;
+	unsigned int rx_queue_widx;
+	struct sk_buff **rx_queue;
+#else
+	/* unsigned int dummy0[0]; */
+	struct sk_buff_head     skb_ipi_queue;
+	/* unsigned int dummy1[8]; */
+#endif
+	unsigned long time_rec, recv_time;
+	unsigned int ipi_accum;
+	/*hwnat ipi use*/
+	spinlock_t      ipilock;
+	struct tasklet_struct smp_func_call_tsk;
+} ____cacheline_aligned_in_smp;
+
+struct hnat_ipi_stat {
+	unsigned long drop_pkt_num_from_extif;
+	unsigned long drop_pkt_num_from_ppehit;
+	unsigned int smp_call_cnt_from_extif;
+	unsigned int smp_call_cnt_from_ppehit;
+	atomic_t cpu_status;
+	/* atomic_t cpu_status_from_extif; */
+	/* atomic_t cpu_status_from_ppehit; */
+
+	/* atomic_t hook_status_from_extif; */
+	/* atomic_t hook_status_from_ppehit; */
+} ____cacheline_aligned_in_smp;
+
+#define cpu_status_from_extif	cpu_status
+#define cpu_status_from_ppehit	cpu_status
+
+struct hnat_ipi_cfg {
+	unsigned int enable_from_extif;
+	unsigned int enable_from_ppehit;
+	unsigned int queue_thresh_from_extif;
+	unsigned int queue_thresh_from_ppehit;
+	unsigned int drop_pkt_from_extif;
+	unsigned int drop_pkt_from_ppehit;
+	unsigned int ipi_cnt_mod_from_extif;
+	unsigned int ipi_cnt_mod_from_ppehit;
+} ____cacheline_aligned_in_smp;
+
+int hnat_ipi_init(void);
+int hnat_ipi_de_init(void);
+#endif
+
+#define QDMA_RX		5
+#define PDMA_RX		0
+
+
+#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/uapi/linux/mtk_nl80211_inc/mtk_vendor_nl80211.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/uapi/linux/mtk_nl80211_inc/mtk_vendor_nl80211.h
new file mode 100755
index 0000000..22ada41
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/uapi/linux/mtk_nl80211_inc/mtk_vendor_nl80211.h
@@ -0,0 +1,667 @@
+/*
+ * Copyright (c) [2020], MediaTek Inc. All rights reserved.
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws.
+ * The information contained herein is confidential and proprietary to
+ * MediaTek Inc. and/or its licensors.
+ * Except as otherwise provided in the applicable licensing terms with
+ * MediaTek Inc. and/or its licensors, any reproduction, modification, use or
+ * disclosure of MediaTek Software, and information contained herein, in whole
+ * or in part, shall be strictly prohibited.
+*/
+
+#ifndef __MTK_VENDOR_NL80211_H
+#define __MTK_VENDOR_NL80211_H
+/*
+ * This header file defines the userspace API to the wireless stack. Please
+ * be careful not to break things - i.e. don't move anything around or so
+ * unless you can demonstrate that it breaks neither API nor ABI.
+ *
+ */
+
+#include <linux/types.h>
+
+#ifndef GNU_PACKED
+#define GNU_PACKED  __attribute__ ((packed))
+#endif /* GNU_PACKED */
+
+#define MTK_NL80211_VENDOR_ID	0x0ce7
+
+/**
+ * enum mtk_nl80211_vendor_commands - supported mtk nl80211 vendor commands
+ *
+ * @MTK_NL80211_VENDOR_SUBCMD_UNSPEC: Reserved value 0
+ * @MTK_NL80211_VENDOR_SUBCMD_TEST: Test for nl80211command/event
+ * @MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL = 0x000000ae:
+ * @MTK_NL80211_VENDOR_SUBCMD_CSI_CTRL = 0x000000c2:
+ * @MTK_NL80211_VENDOR_SUBCMD_RFEATURE_CTRL:
+ * @MTK_NL80211_VENDOR_SUBCMD_WIRELESS_CTRL:
+ * @MTK_NL80211_VENDOR_SUBCMD_SET_DOT11V_WNM:
+ * @MTK_NL80211_VENDOR_SUBCMD_SET_WAPP:
+ * @MTK_NL80211_VENDOR_SUBCMD_SET_CH_MONITOR:
+ * @MTK_NL80211_VENDOR_SUBCMD_BSS_INFO:
+ * @MTK_NL80211_VENDOR_SUBCMD_SET_MAP_R3:
+ * @MTK_NL80211_VENDOR_SUBCMD_SET_HS_ANQP_RSP:
+ * @MTK_NL80211_VENDOR_SUBCMD_SET_HS:
+ * @MTK_NL80211_VENDOR_SUBCMD_SET_OFFCH_SCAN:
+ * @MTK_NL80211_VENDOR_SUBCMD_SET_DFS_INFO:
+ * @MTK_NL80211_VENDOR_SUBCMD_SET_WSC:
+ * @MTK_NL80211_VENDOR_SUBCMD_SET_MBO_MSG:
+ * @MTK_NL80211_VENDOR_SUBCMD_SET_RRM_COMMAND:
+ * @MTK_NL80211_VENDOR_SUBCMD_SET_QOS:
+ * @MTK_NL80211_VENDOR_SUBCMD_GET_CAP: command to get capability information
+ *  from wifi driver, it requres mtk_nl80211_vendor_attr_get_cap attributes.
+ * @MTK_NL80211_VENDOR_SUBCMD_GET_RUNTIME_INFO: command to get run time information
+ *  from wifi driver, it requres mtk_nl80211_vendor_attr_get_runtime_info attributes.
+ * @MTK_NL80211_VENDOR_SUBCMD_GET_STATISTIC: command to get statistic information
+ *  from wifi driver, it requres mtk_nl80211_vendor_attr_get_static_info attributes.
+ * @MTK_NL80211_VENDOR_SUBCMD_GET_SRG_BITMAP:
+ * @MTK_NL80211_VENDOR_SUBCMD_GET_STATIC_INFO:
+ * @MTK_NL80211_VENDOR_SUBCMD_GET_WNM:
+ * @MTK_NL80211_VENDOR_SUBCMD_GET_HS:
+ * @MTK_NL80211_VENDOR_SUBCMD_GET_WSC:
+ * @MTK_NL80211_VENDOR_SUBCMD_GET_DFS_ZERO_WAIT:
+ * @MTK_NL80211_VENDOR_SUBCMD_GET_FRAME:
+ * @MTK_NL80211_VENDOR_SUBCMD_GET_APCLI_INFO:
+ * @MTK_NL80211_VENDOR_SUBCMD_BBP:
+ * @MTK_NL80211_VENDOR_SUBCMD_MAC: command to set or get mac register
+ *  information to/from wifi driver, require mtk_nl80211_vendor_attrs_mac
+ *  attributes.
+ * @MTK_NL80211_VENDOR_SUBCMD_E2P:
+ * @MTK_NL80211_VENDOR_SUBCMD_ATE:
+ * @MTK_NL80211_VENDOR_SUBCMD_STATISTICS: command to get statistic information
+ *  in string from wifi driver, this command is used to be compatible with
+ *  old iwpriv stat command, it requres mtk_nl80211_vendor_attrs_statistics
+ *  attributes.
+ * @MTK_NL80211_VENDOR_SUBCMD_ADD_PMKID_CACHE:
+ * @MTK_NL80211_VENDOR_SUBCMD_RADIUS_DATA:
+ * @MTK_NL80211_VENDOR_SUBCMD_GSITESURVEY:
+ * @MTK_NL80211_VENDOR_SUBCMD_GET_MAC_TABLE:
+ * @MTK_NL80211_VENDOR_SUBCMD_STATIC_WEP_COPY:
+ * @MTK_NL80211_VENDOR_SUBCMD_WSC_PROFILE:
+ * @MTK_NL80211_VENDOR_SUBCMD_RF:
+ * @MTK_NL80211_VENDOR_SUBCMD_SET_WSC_PROFILE_U32_ITEM:
+ * @MTK_NL80211_VENDOR_SUBCMD_QUERY_BATABLE:
+ * @MTK_NL80211_VENDOR_SUBCMD_RD:
+ * @MTK_NL80211_VENDOR_SUBCMD_SET_FT_PARAM:
+ * @MTK_NL80211_VENDOR_SUBCMD_SET_WSCOOB:
+ * @MTK_NL80211_VENDOR_SUBCMD_WSC_CALLBACK:
+ * @MTK_NL80211_VENDOR_SUBCMD_RX_STATISTICS:
+ * @MTK_NL80211_VENDOR_SUBCMD_GET_DRIVER_INFO:
+ * @MTK_NL80211_VENDOR_SUBCMD_STA_VLAN:
+ * @MTK_NL80211_VENDOR_SUBCMD_PHY_STATE:
+ * @MTK_NL80211_VENDOR_SUBCMD_VENDOR_SET: command to set old iwpriv set command
+ *  string to wifi driver, it requires mtk_nl80211_vendor_attrs_vendor_set attributes,
+ *  please note that this command is just used to be compatible with old iwpriv
+ *  set command, and it will be discarded in some time.
+ *
+ * @MTK_NL80211_VENDOR_SUBCMD_VENDOR_SHOW: command to set old iwpriv show command
+ *  string to wifi driver, require mtk_nl80211_vendor_attrs_vendor_show attributes,
+ *  please note that this command is just used to be compatible with old iwpriv
+ *  show command, and it will be discarded in some time.
+ *
+ * @MTK_NL80211_VENDOR_SUBCMD_HS:
+ * @MTK_NL80211_VENDOR_SUBCMD_WNM:
+ * @MTK_NL80211_VENDOR_SUBCMD_MBO_MSG:
+ * @MTK_NL80211_VENDOR_SUBCMD_NEIGHBOR_REPORT:
+ * @MTK_NL80211_VENDOR_SUBCMD_OFFCHANNEL_INFO:
+ * @MTK_NL80211_VENDOR_SUBCMD_OCE_MSG:
+ * @MTK_NL80211_VENDOR_SUBCMD_WAPP_REQ: command to set or get wapp requred
+ *  information from wifi driver, require mtk_nl80211_vendor_attr_wapp_req attributes.
+ * @MTK_NL80211_VENDOR_SUBCMD_SET_AP_SECURITY: command to set ap security configurations
+ *  to a specific bss in wifi driver, it requires mtk_nl80211_vendor_attrs_ap_security
+ *  attributes.
+ * @MTK_NL80211_VENDOR_SUBCMD_SET_AP_VOW:  command to set ap vow configurations
+ *  it requires mtk_nl80211_vendor_attrs_ap_vow attributes.
+ * @MTK_NL80211_VENDOR_CMD_MAX: highest used command number
+ * @__MTK_NL80211_VENDOR_CMD_AFTER_LAST: internal use
+ */
+enum mtk_nl80211_vendor_commands {
+	MTK_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
+	MTK_NL80211_VENDOR_SUBCMD_TEST = 1,
+
+/* don't change the order or add anything between, this is ABI! */
+	MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL = 0x000000ae,
+	MTK_NL80211_VENDOR_SUBCMD_CSI_CTRL = 0x000000c2,
+	MTK_NL80211_VENDOR_SUBCMD_RFEATURE_CTRL,
+	MTK_NL80211_VENDOR_SUBCMD_WIRELESS_CTRL,
+	MTK_NL80211_VENDOR_SUBCMD_SET_DOT11V_WNM,
+	MTK_NL80211_VENDOR_SUBCMD_SET_WAPP,
+	MTK_NL80211_VENDOR_SUBCMD_SET_CH_MONITOR,
+	MTK_NL80211_VENDOR_SUBCMD_BSS_INFO,
+	MTK_NL80211_VENDOR_SUBCMD_SET_MAP_R3,
+	MTK_NL80211_VENDOR_SUBCMD_SET_HS_ANQP_RSP,
+	MTK_NL80211_VENDOR_SUBCMD_SET_HS,
+	MTK_NL80211_VENDOR_SUBCMD_SET_OFFCH_SCAN,
+	MTK_NL80211_VENDOR_SUBCMD_SET_DFS_INFO,
+	MTK_NL80211_VENDOR_SUBCMD_SET_WSC,
+	MTK_NL80211_VENDOR_SUBCMD_SET_MBO_MSG,
+	MTK_NL80211_VENDOR_SUBCMD_SET_RRM_COMMAND,
+	MTK_NL80211_VENDOR_SUBCMD_SET_QOS,
+	MTK_NL80211_VENDOR_SUBCMD_GET_CAP,
+	MTK_NL80211_VENDOR_SUBCMD_GET_RUNTIME_INFO,
+	MTK_NL80211_VENDOR_SUBCMD_GET_STATISTIC,
+	MTK_NL80211_VENDOR_SUBCMD_GET_SRG_BITMAP,
+	MTK_NL80211_VENDOR_SUBCMD_GET_STATIC_INFO,
+	MTK_NL80211_VENDOR_SUBCMD_GET_WNM,
+	MTK_NL80211_VENDOR_SUBCMD_GET_HS,
+	MTK_NL80211_VENDOR_SUBCMD_GET_WSC,
+	MTK_NL80211_VENDOR_SUBCMD_GET_DFS_ZERO_WAIT,
+	MTK_NL80211_VENDOR_SUBCMD_GET_FRAME,
+	MTK_NL80211_VENDOR_SUBCMD_GET_APCLI_INFO,
+	MTK_NL80211_VENDOR_SUBCMD_BBP,
+	MTK_NL80211_VENDOR_SUBCMD_MAC,
+	MTK_NL80211_VENDOR_SUBCMD_E2P,
+	MTK_NL80211_VENDOR_SUBCMD_ATE,
+	MTK_NL80211_VENDOR_SUBCMD_STATISTICS,
+	MTK_NL80211_VENDOR_SUBCMD_ADD_PMKID_CACHE,
+	MTK_NL80211_VENDOR_SUBCMD_RADIUS_DATA,
+	MTK_NL80211_VENDOR_SUBCMD_GSITESURVEY,
+	MTK_NL80211_VENDOR_SUBCMD_GET_MAC_TABLE,
+	MTK_NL80211_VENDOR_SUBCMD_STATIC_WEP_COPY,
+	MTK_NL80211_VENDOR_SUBCMD_WSC_PROFILE  ,
+	MTK_NL80211_VENDOR_SUBCMD_RF,
+	MTK_NL80211_VENDOR_SUBCMD_SET_WSC_PROFILE_U32_ITEM,
+	MTK_NL80211_VENDOR_SUBCMD_QUERY_BATABLE,
+	MTK_NL80211_VENDOR_SUBCMD_RD,
+	MTK_NL80211_VENDOR_SUBCMD_SET_FT_PARAM,
+	MTK_NL80211_VENDOR_SUBCMD_SET_WSCOOB,
+	MTK_NL80211_VENDOR_SUBCMD_WSC_CALLBACK,
+	MTK_NL80211_VENDOR_SUBCMD_RX_STATISTICS,
+	MTK_NL80211_VENDOR_SUBCMD_GET_DRIVER_INFO,
+	MTK_NL80211_VENDOR_SUBCMD_STA_VLAN,
+	MTK_NL80211_VENDOR_SUBCMD_PHY_STATE,
+	MTK_NL80211_VENDOR_SUBCMD_VENDOR_SET,
+	MTK_NL80211_VENDOR_SUBCMD_VENDOR_SHOW,
+	MTK_NL80211_VENDOR_SUBCMD_HS,
+	MTK_NL80211_VENDOR_SUBCMD_WNM,
+	MTK_NL80211_VENDOR_SUBCMD_MBO_MSG,
+	MTK_NL80211_VENDOR_SUBCMD_NEIGHBOR_REPORT,
+	MTK_NL80211_VENDOR_SUBCMD_OFFCHANNEL_INFO,
+	MTK_NL80211_VENDOR_SUBCMD_OCE_MSG,
+	MTK_NL80211_VENDOR_SUBCMD_WAPP_REQ,
+	MTK_NL80211_VENDOR_SUBCMD_SET_AP_SECURITY,
+	MTK_NL80211_VENDOR_SUBCMD_SET_AP_VOW,
+	/* add new commands above here */
+	/* used to define NL80211_CMD_MAX below */
+	__MTK_NL80211_VENDOR_CMD_AFTER_LAST,
+	MTK_NL80211_VENDOR_CMD_MAX = __MTK_NL80211_VENDOR_CMD_AFTER_LAST - 1
+};
+
+/**
+ * enum mtk_nl80211_vendor_events - MediaTek nl80211 asynchoronous event identifiers
+ *
+ * @MTK_NL80211_VENDOR_EVENT_UNSPEC: Reserved value 0
+ *
+ * @MTK_NL80211_VENDOR_EVENT_TEST: Test for nl80211command/event
+ */
+enum mtk_nl80211_vendor_events {
+	/* don't change the order or add anything between, this is ABI! */
+	MTK_NL80211_VENDOR_EVENT_UNSPEC = 0,
+	MTK_NL80211_VENDOR_EVENT_TEST,
+
+	MTK_NL80211_VENDOR_EVENT_RSP_WAPP_EVENT,
+
+	/* add new events above here */
+};
+
+/**
+ * enum mtk_nl80211_vendor_attr_test - Specifies the values for vendor test
+ * command MTK_NL80211_VENDOR_ATTR_TEST
+ * @MTK_NL80211_VENDOR_ATTR_TEST:enable nl80211 test
+ */
+enum mtk_nl80211_vendor_attr_test {
+	/* don't change the order or add anything between, this is ABI! */
+	MTK_NL80211_VENDOR_ATTR_TEST_INVALID = 0,
+
+	MTK_NL80211_VENDOR_ATTR_TEST,
+
+	__MTK_NL80211_VENDOR_ATTR_TEST_LAST,
+	MTK_NL80211_VENDOR_ATTR_TEST_MAX =
+	__MTK_NL80211_VENDOR_ATTR_TEST_LAST - 1
+};
+
+/**
+ * enum mtk_nl80211_vendor_attr_event_test - Specifies the values for vendor test
+ * event MTK_NL80211_VENDOR_ATTR_TEST
+ * @MTK_NL80211_VENDOR_ATTR_TEST:receive nl80211 test event
+ */
+enum mtk_nl80211_vendor_attr_event_test {
+	/* don't change the order or add anything between, this is ABI! */
+	MTK_NL80211_VENDOR_ATTR_EVENT_TEST_INVALID = 0,
+
+	MTK_NL80211_VENDOR_ATTR_EVENT_TEST,
+
+	__MTK_NL80211_VENDOR_ATTR_EVENT_TEST_LAST,
+	MTK_NL80211_VENDOR_ATTR_EVENT_TEST_MAX =
+	__MTK_NL80211_VENDOR_ATTR_EVENT_TEST_LAST - 1
+};
+
+/**
+ * enum mtk_nl80211_vendor_attrs_wnm - This enum defines
+ * attributes required for MTK_NL80211_VENDOR_SUBCMD_SET_DOT11V_WNM.
+ * Information in these attributes is used to set/get wnm information
+ * to/from driver from/to user application.
+ *
+ * @MTK_NL80211_VENDOR_ATTR_WNM_CMD:
+ * @MTK_NL80211_VENDOR_ATTR_WNM_BTM_REQ: BTM request frame
+ * @MTK_NL80211_VENDOR_ATTR_WNM_BTM_RSP:
+ */
+enum mtk_nl80211_vendor_attrs_dot11v_wnm {
+/* don't change the order or add anything between, this is ABI! */
+	MTK_NL80211_VENDOR_ATTR_DOT11V_WNM_INVALID = 0,
+	MTK_NL80211_VENDOR_ATTR_DOT11V_WNM_CMD,
+	MTK_NL80211_VENDOR_ATTR_DOT11V_WNM_BTM_REQ,
+	MTK_NL80211_VENDOR_ATTR_DOT11V_WNM_BTM_RSP,
+	/* add attributes here, update the policy in nl80211.c */
+
+	__MTK_NL80211_VENDOR_ATTR_DOT11V_WNM_AFTER_LAST,
+	MTK_NL80211_VENDOR_DOT11V_WNM_ATTR_MAX = __MTK_NL80211_VENDOR_ATTR_DOT11V_WNM_AFTER_LAST - 1
+};
+
+/**
+ * enum mtk_nl80211_vendor_attrs_vendor_set - This enum defines
+ * attributes required for MTK_NL80211_VENDOR_SUBCMD_VENDOR_SET.
+ * Information in these attributes is used to set information
+ * to driver from user application.
+ *
+ * @MTK_NL80211_VENDOR_ATTR_VENDOR_SET_CMD_STR: command string
+ */
+enum mtk_nl80211_vendor_attrs_vendor_set {
+/* don't change the order or add anything between, this is ABI! */
+	MTK_NL80211_VENDOR_ATTR_VENDOR_SET_INVALID = 0,
+	MTK_NL80211_VENDOR_ATTR_VENDOR_SET_CMD_STR,
+	/* add attributes here, update the policy in nl80211.c */
+
+	__MTK_NL80211_VENDOR_ATTR_VENDOR_SET_AFTER_LAST,
+	MTK_NL80211_VENDOR_ATTR_VENDOR_SET_ATTR_MAX = __MTK_NL80211_VENDOR_ATTR_VENDOR_SET_AFTER_LAST - 1
+};
+
+/**
+ * enum mtk_nl80211_vendor_attrs_vendor_show - This enum defines
+ * attributes required for MTK_NL80211_VENDOR_SUBCMD_VENDOR_SHOW.
+ * Information in these attributes is used to get information
+ * from driver to user application.
+ *
+ * @MTK_NL80211_VENDOR_ATTR_VENDOR_SHOW_CMD_STR: command string
+ * @MTK_NL80211_VENDOR_ATTR_VENDOR_SHOW_RSP_STR: show rsp string buffer
+ */
+enum mtk_nl80211_vendor_attrs_vendor_show {
+/* don't change the order or add anything between, this is ABI! */
+	MTK_NL80211_VENDOR_ATTR_VENDOR_SHOW_INVALID = 0,
+	MTK_NL80211_VENDOR_ATTR_VENDOR_SHOW_CMD_STR,
+	MTK_NL80211_VENDOR_ATTR_VENDOR_SHOW_RSP_STR,
+	/* add attributes here, update the policy in nl80211.c */
+
+	__MTK_NL80211_VENDOR_ATTR_VENDOR_SHOW_AFTER_LAST,
+	MTK_NL80211_VENDOR_ATTR_VENDOR_SHOW_ATTR_MAX = __MTK_NL80211_VENDOR_ATTR_VENDOR_SHOW_AFTER_LAST - 1
+};
+
+/**
+ * enum mtk_nl80211_vendor_attrs_statistics - This enum defines
+ * attributes required for MTK_NL80211_VENDOR_SUBCMD_STATISTICS.
+ * Information in these attributes is used to get wnm information
+ * to/from driver from/to user application.
+ *
+ * @MTK_NL80211_VENDOR_ATTR_STATISTICS_STR: statistic information string
+ */
+enum mtk_nl80211_vendor_attrs_statistics {
+/* don't change the order or add anything between, this is ABI! */
+	MTK_NL80211_VENDOR_ATTR_STATISTICS_INVALID = 0,
+	MTK_NL80211_VENDOR_ATTR_STATISTICS_STR,
+	/* add attributes here, update the policy in nl80211.c */
+
+	__MTK_NL80211_VENDOR_ATTR_STATISTICS_AFTER_LAST,
+	MTK_NL80211_VENDOR_ATTR_STATISTICS_ATTR_MAX = __MTK_NL80211_VENDOR_ATTR_STATISTICS_AFTER_LAST - 1
+};
+
+/**
+ * structure mac_param - This structure defines the payload format of
+ * MTK_NL80211_VENDOR_ATTR_MAC_WRITE_PARAM and MTK_NL80211_VENDOR_ATTR_MAC_SHOW_PARAM.
+ * Information in this structure is used to get/set mac register information
+ * from/to driver.
+ *
+ * @start: start mac address
+ * @end: end mac address
+ * @value: value for the mac register
+ */
+struct GNU_PACKED mac_param {
+	unsigned int start;
+	unsigned int end;
+	unsigned int value;
+};
+
+/**
+ * enum mtk_nl80211_vendor_attrs_mac - This enum defines
+ * attributes required for MTK_NL80211_VENDOR_SUBCMD_MAC.
+ * Information in these attributes is used to get/set mac information
+ * from/to driver.
+ *
+ * @MTK_NL80211_VENDOR_ATTR_MAC_WRITE_PARAM: params, refer to struct GNU_PACKED mac_param
+ * @MTK_NL80211_VENDOR_ATTR_MAC_SHOW_PARAM: params, refer to struct GNU_PACKED mac_param
+ * @MTK_NL80211_VENDOR_ATTR_MAC_RSP_STR: RSP string
+ */
+enum mtk_nl80211_vendor_attrs_mac {
+/* don't change the order or add anything between, this is ABI! */
+	MTK_NL80211_VENDOR_ATTR_MAC_INVALID = 0,
+	MTK_NL80211_VENDOR_ATTR_MAC_WRITE_PARAM,
+	MTK_NL80211_VENDOR_ATTR_MAC_SHOW_PARAM,
+	MTK_NL80211_VENDOR_ATTR_MAC_RSP_STR,
+	/* add attributes here, update the policy in nl80211.c */
+
+	__MTK_NL80211_VENDOR_ATTR_MAC_AFTER_LAST,
+	MTK_NL80211_VENDOR_ATTR_MAC_ATTR_MAX = __MTK_NL80211_VENDOR_ATTR_MAC_AFTER_LAST - 1
+};
+
+/**
+ * enum mtk_vendor_attr_authmode - This enum defines the value of
+ * MTK_NL80211_VENDOR_ATTR_AP_SECURITY_AUTHMODE.
+ * Information in these attributes is used set auth mode of a specific bss.
+ */
+enum mtk_vendor_attr_authmode {
+	NL80211_AUTH_OPEN,
+	NL80211_AUTH_SHARED,
+	NL80211_AUTH_WEPAUTO,
+	NL80211_AUTH_WPA,
+	NL80211_AUTH_WPAPSK,
+	NL80211_AUTH_WPANONE,
+	NL80211_AUTH_WPA2,
+	NL80211_AUTH_WPA2MIX,
+	NL80211_AUTH_WPA2PSK,
+	NL80211_AUTH_WPA3,
+	NL80211_AUTH_WPA3_192,
+	NL80211_AUTH_WPA3PSK,
+	NL80211_AUTH_WPA2PSKWPA3PSK,
+	NL80211_AUTH_WPA2PSKMIXWPA3PSK,
+	NL80211_AUTH_WPA1WPA2,
+	NL80211_AUTH_WPAPSKWPA2PSK,
+	NL80211_AUTH_WPA_AES_WPA2_TKIPAES,
+	NL80211_AUTH_WPA_AES_WPA2_TKIP,
+	NL80211_AUTH_WPA_TKIP_WPA2_AES,
+	NL80211_AUTH_WPA_TKIP_WPA2_TKIPAES,
+	NL80211_AUTH_WPA_TKIPAES_WPA2_AES,
+	NL80211_AUTH_WPA_TKIPAES_WPA2_TKIPAES,
+	NL80211_AUTH_WPA_TKIPAES_WPA2_TKIP,
+	NL80211_AUTH_OWE,
+	NL80211_AUTH_FILS_SHA256,
+	NL80211_AUTH_FILS_SHA384,
+	NL80211_AUTH_WAICERT,
+	NL80211_AUTH_WAIPSK,
+	NL80211_AUTH_DPP,
+	NL80211_AUTH_DPPWPA2PSK,
+	NL80211_AUTH_DPPWPA3PSK,
+	NL80211_AUTH_DPPWPA3PSKWPA2PSK,
+	NL80211_AUTH_WPA2_ENT_OSEN
+};
+
+/**
+ * enum mtk_vendor_attr_encryptype - This enum defines the value of
+ * MTK_NL80211_VENDOR_ATTR_AP_SECURITY_ENCRYPTYPE.
+ * Information in these attributes is used set encryption type of a specific bss.
+ */
+enum mtk_vendor_attr_encryptype {
+	NL80211_ENCRYPTYPE_NONE,
+	NL80211_ENCRYPTYPE_WEP,
+	NL80211_ENCRYPTYPE_TKIP,
+	NL80211_ENCRYPTYPE_AES,
+	NL80211_ENCRYPTYPE_CCMP128,
+	NL80211_ENCRYPTYPE_CCMP256,
+	NL80211_ENCRYPTYPE_GCMP128,
+	NL80211_ENCRYPTYPE_GCMP256,
+	NL80211_ENCRYPTYPE_TKIPAES,
+	NL80211_ENCRYPTYPE_TKIPCCMP128,
+	NL80211_ENCRYPTYPE_WPA_AES_WPA2_TKIPAES,
+	NL80211_ENCRYPTYPE_WPA_AES_WPA2_TKIP,
+	NL80211_ENCRYPTYPE_WPA_TKIP_WPA2_AES,
+	NL80211_ENCRYPTYPE_WPA_TKIP_WPA2_TKIPAES,
+	NL80211_ENCRYPTYPE_WPA_TKIPAES_WPA2_AES,
+	NL80211_ENCRYPTYPE_WPA_TKIPAES_WPA2_TKIPAES,
+	NL80211_ENCRYPTYPE_WPA_TKIPAES_WPA2_TKIP,
+	NL80211_ENCRYPTYPE_SMS4
+};
+
+#define MAX_WEP_KEY_LEN 32
+/**
+ * structure wep_key_param - This structure defines the payload format of
+ * MTK_NL80211_VENDOR_ATTR_AP_SECURITY_WEPKEY. Information in this structure
+ * is used to set wep key information to a specific bss in wifi driver.
+ *
+ * @key_idx: key index
+ * @key_len: key length
+ * @key: key value
+ */
+struct GNU_PACKED wep_key_param {
+	unsigned char key_idx;
+	unsigned int key_len;
+	unsigned char key[MAX_WEP_KEY_LEN];
+};
+
+/**
+ * structure vow_group_en_param - This structure defines the payload format of
+ * MTK_NL80211_VENDOR_ATTR_AP_VOW_ATC_EN_INFO &
+ * MTK_NL80211_VENDOR_ATTR_AP_VOW_BW_CTL_EN_INFO.
+ * Information in this structure is used to set vow airtime control enable configuration
+ * to a specific group in wifi driver.
+ *
+ * @group: vow group
+ * @en: Enable/Disable
+ */
+struct GNU_PACKED vow_group_en_param {
+	unsigned int group;
+	unsigned int en;
+};
+
+/**
+ * structure vow_group_en_param - This structure defines the payload format of
+ * MTK_NL80211_VENDOR_ATTR_AP_VOW_MIN_RATE_INFO &
+ * MTK_NL80211_VENDOR_ATTR_AP_VOW_MAX_RATE_INFO.
+ * Information in this structure is used to set vow airtime rate configuration
+ * to a specific group in wifi driver.
+ *
+ * @group: vow group
+ * @rate: vow rate
+ */
+struct GNU_PACKED vow_rate_param {
+	unsigned int group;
+	unsigned int rate;
+};
+
+/**
+ * structure vow_group_en_param - This structure defines the payload format of
+ * MTK_NL80211_VENDOR_ATTR_AP_VOW_MIN_RATIO_INFO &
+ * MTK_NL80211_VENDOR_ATTR_AP_VOW_MAX_RATIO_INFO.
+ * Information in this structure is used to set vow airtime ratio configuration
+ * to a specific group in wifi driver.
+ *
+ * @group: vow group
+ * @ratio: vow ratio
+ */
+struct GNU_PACKED vow_ratio_param {
+	unsigned int group;
+	unsigned int ratio;
+};
+
+/**
+ * enum mtk_nl80211_vendor_attrs_ap_vow - This enum defines
+ * attributes required for MTK_NL80211_VENDOR_SUBCMD_SET_AP_VOW.
+ * Information in these attributes is used to set vow configuration
+ * to driver from user application.
+ *
+ * @MTK_NL80211_VENDOR_ATTR_AP_VOW_ATF_EN_INFO: u8, air time fairness enable attributes
+ * @MTK_NL80211_VENDOR_ATTR_AP_VOW_ATC_EN_INFO: refer to vow_group_en_param
+ * @MTK_NL80211_VENDOR_ATTR_AP_VOW_BW_EN_INFO: u8, air time bw enalbe attributes
+ * @MTK_NL80211_VENDOR_ATTR_AP_VOW_BW_CTL_EN_INFO: refer to vow_group_en_param
+ * @MTK_NL80211_VENDOR_ATTR_AP_VOW_MIN_RATE_INFO: refer to vow_rate_param
+ * @MTK_NL80211_VENDOR_ATTR_AP_VOW_MAX_RATE_INFO: refer to vow_rate_param
+ * @MTK_NL80211_VENDOR_ATTR_AP_VOW_MIN_RATIO_INFO: refer to vow_ratio_param
+ * @MTK_NL80211_VENDOR_ATTR_AP_VOW_MAX_RATIO_INFO: refer to vow_ratio_param
+ */
+enum mtk_nl80211_vendor_attrs_ap_vow{
+/* don't change the order or add anything between, this is ABI! */
+	MTK_NL80211_VENDOR_ATTR_AP_VOW_INVALID = 0,
+	MTK_NL80211_VENDOR_ATTR_AP_VOW_ATF_EN_INFO,
+	MTK_NL80211_VENDOR_ATTR_AP_VOW_ATC_EN_INFO,
+	MTK_NL80211_VENDOR_ATTR_AP_VOW_BW_EN_INFO,
+	MTK_NL80211_VENDOR_ATTR_AP_VOW_BW_CTL_EN_INFO,
+	MTK_NL80211_VENDOR_ATTR_AP_VOW_MIN_RATE_INFO,
+	MTK_NL80211_VENDOR_ATTR_AP_VOW_MAX_RATE_INFO,
+	MTK_NL80211_VENDOR_ATTR_AP_VOW_MIN_RATIO_INFO,
+	MTK_NL80211_VENDOR_ATTR_AP_VOW_MAX_RATIO_INFO,
+	__MTK_NL80211_VENDOR_ATTR_AP_VOW_AFTER_LAST,
+	MTK_NL80211_VENDOR_AP_VOW_ATTR_MAX = __MTK_NL80211_VENDOR_ATTR_AP_VOW_AFTER_LAST - 1
+};
+/**
+ * enum mtk_nl80211_vendor_attrs_ap_security - This enum defines
+ * attributes required for MTK_NL80211_VENDOR_SUBCMD_SET_AP_SECURITY.
+ * Information in these attributes is used to set security information
+ * to driver from user application.
+ *
+ * @MTK_NL80211_VENDOR_ATTR_AP_SECURITY_AUTHMODE:  u32, auth mode attributes, refer to mtk_vendor_attr_authmode
+ * @MTK_NL80211_VENDOR_ATTR_AP_SECURITY_ENCRYPTYPE: u32, encryptype, refer to mtk_vendor_attr_encryptype
+ * @MTK_NL80211_VENDOR_ATTR_AP_SECURITY_REKEYINTERVAL: u32, rekey interval in seconds
+ * @MTK_NL80211_VENDOR_ATTR_AP_SECURITY_REKEYMETHOD: u8, 0-by time, 1-by pkt count
+ * @MTK_NL80211_VENDOR_ATTR_AP_SECURITY_DEFAULTKEYID: u8, default key index
+ * @MTK_NL80211_VENDOR_ATTR_AP_SECURITY_WEPKEY: refer to wep_key_param
+ * @MTK_NL80211_VENDOR_ATTR_AP_SECURITY_PASSPHRASE: string
+ * @MTK_NL80211_VENDOR_ATTR_AP_SECURITY_PMF: u8 1-support pmf, 0-not support pmf
+ * @MTK_NL80211_VENDOR_ATTR_AP_SECURITY_PMF_REQUIRE: u8 1-pmf is required, 0-pmf is not required
+ * @MTK_NL80211_VENDOR_ATTR_AP_SECURITY_PMF_SHA256: u8 1-pmfsha256 is desired, 0-pmfsha256 is not desired
+ */
+enum mtk_nl80211_vendor_attrs_ap_security {
+/* don't change the order or add anything between, this is ABI! */
+	MTK_NL80211_VENDOR_ATTR_AP_SECURITY_INVALID = 0,
+	MTK_NL80211_VENDOR_ATTR_AP_SECURITY_AUTHMODE,
+	MTK_NL80211_VENDOR_ATTR_AP_SECURITY_ENCRYPTYPE,
+	MTK_NL80211_VENDOR_ATTR_AP_SECURITY_REKEYINTERVAL,
+	MTK_NL80211_VENDOR_ATTR_AP_SECURITY_REKEYMETHOD,
+	MTK_NL80211_VENDOR_ATTR_AP_SECURITY_DEFAULTKEYID,
+	MTK_NL80211_VENDOR_ATTR_AP_SECURITY_WEPKEY,
+	MTK_NL80211_VENDOR_ATTR_AP_SECURITY_PASSPHRASE,
+	MTK_NL80211_VENDOR_ATTR_AP_SECURITY_PMF_CAPABLE,
+	MTK_NL80211_VENDOR_ATTR_AP_SECURITY_PMF_REQUIRE,
+	MTK_NL80211_VENDOR_ATTR_AP_SECURITY_PMF_SHA256,
+	/* add attributes here, update the policy in nl80211.c */
+
+	__MTK_NL80211_VENDOR_ATTR_AP_SECURITY_AFTER_LAST,
+	MTK_NL80211_VENDOR_AP_SECURITY_ATTR_MAX = __MTK_NL80211_VENDOR_ATTR_AP_SECURITY_AFTER_LAST - 1
+};
+
+/**
+ * enum mtk_nl80211_vendor_attr_get_static_info - Specifies the vendor attribute values
+ * to get static info
+ */
+enum mtk_nl80211_vendor_attr_get_static_info {
+	/* don't change the order or add anything between, this is ABI! */
+	MTK_NL80211_VENDOR_ATTR_GET_STATIC_INFO_INVALID = 0,
+
+	MTK_NL80211_VENDOR_ATTR_GET_STATIC_INFO_CHIP_ID,
+	MTK_NL80211_VENDOR_ATTR_GET_STATIC_INFO_DRIVER_VER,
+	MTK_NL80211_VENDOR_ATTR_GET_STATIC_INFO_COEXISTENCE,
+	MTK_NL80211_VENDOR_ATTR_GET_STATIC_INFO_WIFI_VER,
+	MTK_NL80211_VENDOR_ATTR_GET_STATIC_INFO_WAPP_SUPPORT_VER,
+
+	__MTK_NL80211_VENDOR_ATTR_GET_STATIC_INFO_LAST,
+	MTK_NL80211_VENDOR_ATTR_GET_STATIC_INFO_MAX =
+	__MTK_NL80211_VENDOR_ATTR_GET_STATIC_INFO_LAST - 1
+};
+
+/**
+ * enum mtk_nl80211_vendor_attr_get_runtime_info - Specifies the vendor attribute values
+ * to get runtime info
+ */
+enum mtk_nl80211_vendor_attr_get_runtime_info {
+	/* don't change the order or add anything between, this is ABI! */
+	MTK_NL80211_VENDOR_ATTR_GET_RUNTIME_INFO_INVALID = 0,
+
+	MTK_NL80211_VENDOR_ATTR_GET_RUNTIME_INFO_GET_MAX_NUM_OF_STA,
+	MTK_NL80211_VENDOR_ATTR_GET_RUNTIME_INFO_GET_CHAN_LIST,
+	MTK_NL80211_VENDOR_ATTR_GET_RUNTIME_INFO_GET_OP_CLASS,
+	MTK_NL80211_VENDOR_ATTR_GET_RUNTIME_INFO_GET_BSS_INFO,
+	MTK_NL80211_VENDOR_ATTR_GET_RUNTIME_INFO_GET_NOP_CHANNEL_LIST,
+	MTK_NL80211_VENDOR_ATTR_GET_RUNTIME_INFO_GET_WMODE,
+	MTK_NL80211_VENDOR_ATTR_GET_RUNTIME_INFO_GET_WAPP_WSC_PROFILES,
+	MTK_NL80211_VENDOR_ATTR_GET_RUNTIME_INFO_GET_PMK_BY_PEER_MAC,
+	MTK_NL80211_VENDOR_ATTR_GET_RUNTIME_INFO_GET_802_11_AUTHENTICATION_MODE,
+	MTK_NL80211_VENDOR_ATTR_GET_RUNTIME_INFO_GET_802_11_MAC_ADDRESS,
+	MTK_NL80211_VENDOR_ATTR_GET_RUNTIME_INFO_GET_802_11_CURRENTCHANNEL,
+
+	__MTK_NL80211_VENDOR_ATTR_GET_RUNTIME_INFO_LAST,
+	MTK_NL80211_VENDOR_ATTR_GET_RUNTIME_INFO_MAX =
+	__MTK_NL80211_VENDOR_ATTR_GET_RUNTIME_INFO_LAST - 1
+};
+
+/**
+ * enum mtk_nl80211_vendor_attr_get_statistic - Specifies the vendor attribute values
+ * to get statistic info
+ */
+enum mtk_nl80211_vendor_attr_get_statistic {
+	/* don't change the order or add anything between, this is ABI! */
+	MTK_NL80211_VENDOR_ATTR_GET_STATISTIC_INVALID = 0,
+
+	MTK_NL80211_VENDOR_ATTR_GET_802_11_STATISTICS,
+	MTK_NL80211_VENDOR_ATTR_GET_TX_PWR,
+	MTK_NL80211_VENDOR_ATTR_GET_AP_METRICS,
+	MTK_NL80211_VENDOR_ATTR_GET_802_11_PER_BSS_STATISTICS,
+	MTK_NL80211_VENDOR_ATTR_GET_CPU_TEMPERATURE,
+
+	_MTK_NL80211_VENDOR_ATTR_GET_STATISTIC_LAST,
+	MTK_NL80211_VENDOR_ATTR_GET_STATISTIC_MAX =
+	_MTK_NL80211_VENDOR_ATTR_GET_STATISTIC_LAST - 1
+};
+
+/**
+ * enum mtk_nl80211_vendor_attr_wapp_req - Specifies the vendor attribute values
+ * to request wifi info
+ */
+enum mtk_nl80211_vendor_attr_wapp_req {
+	/* don't change the order or add anything between, this is ABI! */
+	MTK_NL80211_VENDOR_ATTR_WAPP_REQ_INVALID = 0,
+
+	MTK_NL80211_VENDOR_ATTR_WAPP_REQ,
+
+	__MTK_NL80211_VENDOR_ATTR_WAPP_REQ_LAST,
+	MTK_NL80211_VENDOR_ATTR_WAPP_REQ_MAX =
+	__MTK_NL80211_VENDOR_ATTR_WAPP_REQ_LAST - 1
+};
+
+/**
+ * enum mtk_nl80211_vendor_attr_event_rsp_wapp_event - Specifies the vendor attribute values
+ * to get wifi info event
+ */
+enum mtk_nl80211_vendor_attr_event_rsp_wapp_event {
+	/* don't change the order or add anything between, this is ABI! */
+	MTK_NL80211_VENDOR_ATTR_EVENT_RSP_WAPP_EVENT_INVALID = 0,
+
+	MTK_NL80211_VENDOR_ATTR_EVENT_RSP_WAPP_EVENT,
+
+	__MTK_NL80211_VENDOR_ATTR_EVENT_RSP_WAPP_EVENT_LAST,
+	MTK_NL80211_VENDOR_ATTR_EVENT_RSP_WAPP_EVENT_MAX =
+	__MTK_NL80211_VENDOR_ATTR_EVENT_RSP_WAPP_EVENT_LAST - 1
+};
+
+/**
+ * enum mtk_nl80211_vendor_attr_get_cap - Specifies the vendor attribute values
+ * to get capability info
+ */
+enum mtk_nl80211_vendor_attr_get_cap {
+	/* don't change the order or add anything between, this is ABI! */
+	MTK_NL80211_VENDOR_ATTR_GET_CAP_INFO_INVALID = 0,
+
+	MTK_NL80211_VENDOR_ATTR_GET_CAP_INFO_CAC_CAP,
+	MTK_NL80211_VENDOR_ATTR_GET_CAP_INFO_MISC_CAP,
+	MTK_NL80211_VENDOR_ATTR_GET_CAP_INFO_HT_CAP,
+	MTK_NL80211_VENDOR_ATTR_GET_CAP_INFO_VHT_CAP,
+	MTK_NL80211_VENDOR_ATTR_GET_CAP_INFO_WF6_CAPABILTY,
+	MTK_NL80211_VENDOR_ATTR_GET_CAP_INFO_HE_CAP,
+	MTK_NL80211_VENDOR_ATTR_GET_CAP_QUERY_11H_CAPABILITY,
+	MTK_NL80211_VENDOR_ATTR_GET_CAP_QUERY_RRM_CAPABILITY,
+	MTK_NL80211_VENDOR_ATTR_GET_CAP_QUERY_KVR_CAPABILITY,
+
+
+	__MTK_NL80211_VENDOR_ATTR_GET_CAP_INFO_LAST,
+	MTK_NL80211_VENDOR_ATTR_GET_CAP_INFO_MAX =
+	__MTK_NL80211_VENDOR_ATTR_GET_CAP_INFO_LAST - 1
+};
+
+#endif /* __MTK_VENDOR_NL80211_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/uapi/linux/wapp/mt_wlan_cmm_oid.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/uapi/linux/wapp/mt_wlan_cmm_oid.h
new file mode 100644
index 0000000..ce31b3b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/uapi/linux/wapp/mt_wlan_cmm_oid.h
@@ -0,0 +1,80 @@
+/*
+ ***************************************************************************
+ * Mediatek Tech Inc.
+ * 4F, No. 2 Technology 5th Rd.
+ * Science-based Industrial Park
+ * Hsin-chu, Taiwan, R.O.C.
+ *
+ * (c) Copyright 2020-2021, Mediatek Technology, Inc.
+ *
+ * All rights reserved. Mediatek's source code is an unpublished work and the
+ * use of a copyright notice does not imply otherwise. This source code
+ * contains confidential trade secret material of Mediatek Tech. Any attemp
+ * or participation in deciphering, decoding, reverse engineering or in any
+ * way altering the source code is stricitly prohibited, unless the prior
+ * written consent of Mediatek Technology, Inc. is obtained.
+ ***************************************************************************
+
+        Module Name:
+        wapp_cmm_type.h
+
+        Abstract:
+
+        Revision History:
+        Who         When          What
+        --------    ----------    ----------------------------------------------
+*/
+/* This file is used by wifi driver and wapp.
+   Keep data structure sync */
+
+#define OID_802_11_APCLI_ENABLE			0x09B0
+#define OID_802_11_AUTO_ROAM			0x09B1
+#define OID_802_11_APCLI_BSSID			0x09B2
+#define OID_802_11_APPROXY_REFRESH		0x09B3
+#define OID_802_11_AUTH_MODE			0x09B4
+#define OID_802_11_APCLI_PMFMFPC		0x09B5
+#define OID_802_11_APCLI_SSID			0x09B6
+#define OID_802_11_APCLI_WPAPSK			0x09B7
+#define OID_802_11_APCLI_AUTH_MODE		0x09B8
+#define OID_802_11_APCLI_ENCRY_TYPE		0x09B9
+#define OID_802_11_ACL_ADDENTRY			0x09BA
+#define OID_802_11_ACL_DELENTRY			0x09BB
+#define OID_802_11_ACL_CLEARALL			0x09BC
+#define OID_802_11_ACCESS_POLICY		0x09BD
+#define OID_802_11_APCLI_AUTO_CONNECT		0x09BE
+#define OID_802_11_BCNREQ			0x09BF
+#define OID_802_11_BLADD			0x09C0
+#define OID_802_11_BLDEL			0x09C1
+#define OID_802_11_BHBSS			0x09C2
+#define OID_802_11_SET_CHANNEL			0x09C3
+#define OID_802_11_DPP_ENABLE			0x09C4
+#define OID_802_11_DISCONNECT_STA		0x09C5
+#define OID_802_11_DEFAULT_KEYID		0x09C6
+#define OID_802_11_DISCONNECT_ALL_STA		0x09C7
+#define OID_802_11_ENCRYP_TYPE			0x09C8
+#define OID_802_11_FHBSS			0x09C9
+#define OID_802_11_HTBSSCOEX			0x09CA
+#define OID_802_11_HIDE_SSID			0x09CB
+#define OID_802_11_HTBW				0x09CC
+#define OID_802_11_KEY1				0x09CD
+#define OID_802_11_MAP_CHANNEL			0x09CE
+#define OID_802_11_MNT_ENABLE			0x09CF
+#define OID_802_11_MNT_RULE			0x09D0
+#define OID_802_11_MNT_STA0			0x09D1
+#define OID_802_11_MAP_CHANNEL_ENABLE		0x09D2
+#define OID_802_11_MAP_ENABLE			0x09D3
+#define OID_802_11_PMFMFPC			0x09D4
+#define OID_802_11_RADIOON			0x09D5
+#define OID_802_11_SITESURVEY			0x09D6
+#define OID_802_11_TS_BH_PRIMARY_VID		0x09D7
+#define OID_802_11_TS_BH_PRIMARY_PCP		0x09D8
+#define OID_802_11_TS_BH_VID			0x09D9
+#define OID_802_11_TS_FH_VID			0x09DA
+#define OID_802_11_TRANSPARENT_VID		0x09DB
+#define OID_802_11_VHTBW			0x09DC
+#define OID_802_11_V10_CONVERTER		0x09DD
+#define OID_802_11_WSC_STOP			0x09DE
+#define OID_802_11_WSCCONF_MODE			0x09DF
+#define OID_802_11_WSC_MODE			0x09E0
+#define OID_802_11_WSC_GET_CONF			0x09E1
+#define OID_802_11_WSCCONF_STATUS		0x09E2
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/uapi/linux/wapp/wapp_cmm_type.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/uapi/linux/wapp/wapp_cmm_type.h
new file mode 100755
index 0000000..d9216c9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/uapi/linux/wapp/wapp_cmm_type.h
@@ -0,0 +1,1139 @@
+/*
+ ***************************************************************************
+ * Mediatek Tech Inc.
+ * 4F, No. 2 Technology 5th Rd.
+ * Science-based Industrial Park
+ * Hsin-chu, Taiwan, R.O.C.
+ *
+ * (c) Copyright 2002-2011, Mediatek Technology, Inc.
+ *
+ * All rights reserved. Mediatek's source code is an unpublished work and the
+ * use of a copyright notice does not imply otherwise. This source code
+ * contains confidential trade secret material of Mediatek Tech. Any attemp
+ * or participation in deciphering, decoding, reverse engineering or in any
+ * way altering the source code is stricitly prohibited, unless the prior
+ * written consent of Mediatek Technology, Inc. is obtained.
+ ***************************************************************************
+
+	Module Name:
+	wapp_cmm_type.h
+
+	Abstract:
+
+	Revision History:
+	Who         When          What
+	--------    ----------    ----------------------------------------------
+*/
+/* This file is used by wifi driver and wapp.
+   Keep data structure sync */
+
+#ifndef __WAPP_TYPES_H__
+#define __WAPP_TYPES_H__
+
+//#include <linux/if_ether.h>
+#ifdef WAPP_SUPPORT
+#define MAX_BSSLOAD_THRD			100
+#endif /* WAPP_SUPPORT */
+
+#ifndef GNU_PACKED
+#define GNU_PACKED  (__attribute__ ((packed)))
+#endif /* GNU_PACKED */
+
+#ifndef MAC_ADDR_LEN
+#define MAC_ADDR_LEN				6
+#endif
+#ifndef LEN_PMK
+#define LEN_PMK					32
+#endif
+#ifndef LEN_PMK_MAX
+#define LEN_PMK_MAX				48
+#endif
+#ifndef LEN_PMKID
+#define LEN_PMKID				16
+#endif
+#ifndef LEN_MAX_PTK
+#define LEN_MAX_PTK				88
+#endif
+#ifndef LEN_PSK
+#define LEN_PSK					64
+#endif
+#ifndef LEN_MAX_URI
+#define LEN_MAX_URI                             120
+#endif
+
+#ifndef AC_NUM
+#define AC_NUM						4
+#endif
+#define MAX_HE_MCS_LEN 12
+#define MAX_OP_CLASS 16
+#define MAX_LEN_OF_SSID 32
+#define MAX_NUM_OF_CHANNELS		59 // 14 channels @2.4G +  12@UNII(lower/middle) + 16@HiperLAN2 + 11@UNII(upper) + 0@Japan + 1 as NULL termination
+#define ASSOC_REQ_LEN 154
+#define ASSOC_REQ_LEN_MAX 512
+#define PREQ_IE_LEN 200
+#define BCN_RPT_LEN 200
+#define IWSC_MAX_SUB_MASK_LIST_COUNT	3
+#define WMODE_CAP_N(_x)                        (((_x) & (WMODE_GN | WMODE_AN)) != 0)
+#define WMODE_CAP_AC(_x)               (((_x) & (WMODE_AC)) != 0)
+#define WMODE_CAP_AX(_x)	((_x) & (WMODE_AX_24G | WMODE_AX_5G | WMODE_AX_6G))
+#define WMODE_CAP(_x, _mode)   (((_x) & (_mode)) != 0)
+
+#define MAX_SUPPORT_INF_NUM 17 * MAX_NUM_OF_RADIO /* 16MBSS+1APCLI */
+#define MAX_NUM_OF_WAPP_CHANNELS 59
+#define MAX_PROFILE_CNT 4
+#define PER_EVENT_LIST_MAX_NUM 		5
+#define	DAEMON_NEIGHBOR_REPORT_MAX_NUM 128
+#define VERSION_WAPP_CMM "v3.0.0.1"
+#ifdef MAP_R3_WF6
+#define MAX_TID 4
+#endif
+typedef enum {
+	WAPP_STA_INVALID,
+	WAPP_STA_DISCONNECTED,
+	WAPP_STA_CONNECTED,
+} WAPP_STA_STATE;
+
+typedef enum {
+	WAPP_BSS_STOP = 0,
+	WAPP_BSS_START,
+} WAPP_BSS_STATE;
+
+typedef enum {
+	WAPP_AUTH = 0,
+	WAPP_ASSOC,
+	WAPP_EAPOL
+} WAPP_CNNCT_STAGE;
+
+typedef enum {
+	WAPP_BSSLOAD_NORMAL = 0,
+	WAPP_BSSLOAD_HIGH,
+	WAPP_BSSLOAD_LOW,
+} WAPP_BSSLOAD_STATE;
+
+typedef enum {
+	NOT_FAILURE = 0,
+	AP_NOT_READY,
+	ACL_CHECK_FAIL,
+	BSSID_NOT_FOUND,
+	BSSID_MISMATCH,
+	BSSID_IF_NOT_READY,
+	BND_STRG_CONNECT_CHECK_FAIL,
+	DISALLOW_NEW_ASSOCI,
+	EZ_CONNECT_DISALLOW,
+	EZ_SETUP_FUNC_DISABLED,
+	FT_ERROR,
+	GO_UPDATE_NOT_COMPLETE,
+	MLME_NO_RESOURCE,
+	MLME_ASSOC_REJ_TEMP,
+	MLME_UNABLE_HANDLE_STA,
+	MLME_EZ_CNNCT_LOOP,
+	MLME_REQ_WITH_INVALID_PARAM,
+	MLME_REJECT_TIMEOUT,
+	MLME_UNSPECIFY_FAILURE,
+	NOT_FOUND_IN_RADIUS_ACL,
+	PEER_REQ_SANITY_FAIL,
+} WAPP_CNNCT_FAIL_REASON_LIST;
+
+typedef enum {
+	WAPP_APCLI_DISASSOCIATED = 0,
+	WAPP_APCLI_ASSOCIATED,
+} WAPP_APCLI_ASSOC_STATE;
+
+typedef enum {
+	WAPP_DEV_QUERY_RSP = 1,
+	WAPP_HT_CAP_QUERY_RSP,
+	WAPP_VHT_CAP_QUERY_RSP,
+	WAPP_HE_CAP_QUERY_RSP,
+	WAPP_MISC_CAP_QUERY_RSP,
+	WAPP_CLI_QUERY_RSP,
+	WAPP_CLI_LIST_QUERY_RSP,
+	WAPP_CLI_JOIN_EVENT,
+	WAPP_CLI_LEAVE_EVENT,
+	WAPP_CLI_PROBE_EVENT,
+	WAPP_CHN_LIST_RSP,
+	WAPP_OP_CLASS_RSP,
+	WAPP_BSS_INFO_RSP,
+	WAPP_AP_METRIC_RSP,
+	WAPP_CH_UTIL_QUERY_RSP,
+	WAPP_AP_CONFIG_RSP,
+	WAPP_APCLI_QUERY_RSP,
+	MAP_BH_STA_WPS_DONE,
+	MAP_TRIGGER_RSSI_STEER,
+	WAPP_RCEV_BCN_REPORT,
+	WAPP_RCEV_BCN_REPORT_COMPLETE,
+	WAPP_RCEV_MONITOR_INFO,
+	WAPP_BSSLOAD_RSP,
+	WAPP_BSSLOAD_CROSSING,
+	WAPP_BSS_STATE_CHANGE,
+	WAPP_CH_CHANGE,
+	WAPP_TX_POWER_CHANGE,
+	WAPP_APCLI_ASSOC_STATE_CHANGE,
+	WAPP_STA_RSSI_RSP,
+	WAPP_CLI_ACTIVE_CHANGE,
+	WAPP_CSA_EVENT,
+	WAPP_STA_CNNCT_REJ,
+	WAPP_APCLI_RSSI_RSP,
+	WAPP_SCAN_RESULT_RSP,
+	WAPP_MAP_VENDOR_IE,
+	WAPP_WSC_SCAN_COMP_NOTIF,
+	WAPP_MAP_WSC_CONFIG,
+	WAPP_WSC_EAPOL_START_NOTIF,
+	WAPP_WSC_EAPOL_COMPLETE_NOTIF,
+	WAPP_SCAN_COMPLETE_NOTIF,
+	WAPP_A4_ENTRY_MISSING_NOTIF,
+	WAPP_RADAR_DETECT_NOTIF,
+	WAPP_APCLI_ASSOC_STATE_CHANGE_VENDOR10,
+	WAPP_CAC_STOP, //MAP R2
+	WAPP_STA_DISASSOC_EVENT,
+	WAPP_RADIO_METRIC_RSP,
+	WAPP_DPP_ACTION_FRAME_RECEIVED,
+	WAPP_DPP_ACTION_FRAME_STATUS,
+	WAPP_DPP_CCE_RSP,
+	WAPP_CAC_PERIOD_EVENT,
+	WAPP_UNSAFE_CHANNEL_EVENT,
+	WAPP_BAND_STATUS_CHANGE_EVENT,
+	WAPP_STA_INFO,
+	WAPP_R3_RECONFIG_TRIGGER,
+	WAPP_R3_DPP_URI_INFO,
+	WAPP_NO_STA_CONNECT_TIMEOUT_EVENT,
+	WAPP_NO_DATA_TRAFFIC_TIMEOUT_EVENT,
+	WAPP_WIFI_UP_EVENT,
+	WAPP_WIFI_DOWN_EVENT,
+	WAPP_QOS_ACTION_FRAME_EVENT = 70,
+	WAPP_MSCS_CLASSIFIER_PARAM_EVENT,
+	WAPP_VEND_SPEC_UP_TUPLE_EVENT,
+	WAPP_CH_CHANGE_R3,
+	WAPP_SELF_SRG_BITMAP_EVENT,
+	WAPP_UPLINK_TRAFFIC_EVENT,
+	WAPP_CONFIG_WPS_EVENT,
+} WAPP_EVENT_ID;
+
+typedef enum {
+	WAPP_DEV_QUERY_REQ = 1,
+	WAPP_HT_CAP_QUERY_REQ,
+	WAPP_VHT_CAP_QUERY_REQ,
+	WAPP_HE_CAP_QUERY_REQ,
+	WAPP_MISC_CAP_QUERY_REQ,
+	WAPP_CLI_QUERY_REQ,
+	WAPP_CLI_LIST_QUERY_REQ,
+	WAPP_CHN_LIST_QUERY_REQ,
+	WAPP_OP_CLASS_QUERY_REQ,
+	WAPP_BSS_INFO_QUERY_REQ,
+	WAPP_AP_METRIC_QUERY_REQ,
+	WAPP_CH_UTIL_QUERY_REQ,
+	WAPP_APCLI_QUERY_REQ,
+	WAPP_BSS_START_REQ,
+	WAPP_BSS_STOP_REQ,
+	WAPP_TXPWR_PRCTG_REQ,
+	WAPP_STEERING_POLICY_SET_REQ,
+	WAPP_BSS_LOAD_THRD_SET_REQ,
+	WAPP_AP_CONFIG_SET_REQ,
+	WAPP_BSSLOAD_QUERY_REQ,
+	WAPP_HECAP_QUERY_REQ,
+	WAPP_STA_RSSI_QUERY_REQ,
+	WAPP_APCLI_RSSI_QUERY_REQ,
+	WAPP_GET_SCAN_RESULTS,
+	WAPP_SEND_NULL_FRAMES,
+	WAPP_WSC_PBC_EXEC,
+	WAPP_WSC_SET_BH_PROFILE,
+	WAPP_SET_SCAN_BH_SSIDS,
+	WAPP_SET_AVOID_SCAN_CAC,
+#ifdef MAP_R2
+	WAPP_RADIO_METRICS_REQ,
+#endif
+#ifdef DPP_R2_SUPPORT
+	WAPP_GET_CCE_RESULT,
+#endif
+	WAPP_SET_SRG_BITMAP,
+	WAPP_SET_TOPOLOGY_UPDATE,
+	WAPP_SET_SRG_UPLINK_STATUS,
+} WAPP_REQ_ID;
+
+typedef enum {
+	PARAM_DGAF_DISABLED,
+	PARAM_PROXY_ARP,
+	PARAM_L2_FILTER,
+	PARAM_ICMPV4_DENY,
+	PARAM_MMPDU_SIZE,
+	PARAM_EXTERNAL_ANQP_SERVER_TEST,
+	PARAM_GAS_COME_BACK_DELAY,
+	PARAM_WNM_NOTIFICATION,
+	PARAM_QOSMAP,
+	PARAM_WNM_BSS_TRANSITION_MANAGEMENT,
+} WAPP_PARAM;
+
+typedef struct GNU_PACKED _WAPP_CONNECT_FAILURE_REASON {
+	u8	connect_stage;
+	u16	reason;
+} WAPP_CONNECT_FAILURE_REASON;
+
+typedef struct GNU_PACKED _wapp_dev_info {
+	u32	ifindex;
+	u8	ifname[IFNAMSIZ];
+	u8	mac_addr[MAC_ADDR_LEN];
+	u8	dev_type;
+	u8	radio_id;
+	u16	wireless_mode;
+	uintptr_t	adpt_id;
+	u8 dev_active;
+} wapp_dev_info;
+
+typedef struct GNU_PACKED _wdev_ht_cap {
+	u8	tx_stream;
+	u8	rx_stream;
+	u8	sgi_20;
+	u8	sgi_40;
+	u8	ht_40;
+} wdev_ht_cap;
+
+typedef struct GNU_PACKED _wdev_vht_cap {
+	u8	sup_tx_mcs[2];
+	u8	sup_rx_mcs[2];
+	u8	tx_stream;
+	u8	rx_stream;
+	u8	sgi_80;
+	u8	sgi_160;
+	u8	vht_160;
+	u8	vht_8080;
+	u8	su_bf;
+	u8	mu_bf;
+} wdev_vht_cap;
+
+typedef struct GNU_PACKED _wdev_he_cap {
+	unsigned char he_mcs_len;
+	unsigned char he_mcs[MAX_HE_MCS_LEN];
+	unsigned char tx_stream;
+	unsigned char rx_stream;
+	unsigned char he_8080;
+	unsigned char he_160;
+	unsigned char su_bf_cap;
+	unsigned char mu_bf_cap;
+	unsigned char ul_mu_mimo_cap;
+	unsigned char ul_mu_mimo_ofdma_cap;
+	unsigned char dl_mu_mimo_ofdma_cap;
+	unsigned char ul_ofdma_cap;
+	unsigned char dl_ofdma_cap;
+	unsigned char gi; /* 0:auto;1:800;2:1600;3:3200 */
+} wdev_he_cap;
+
+
+#ifdef MAP_R2
+typedef struct GNU_PACKED _wdev_extended_ap_metrics {
+	u32 uc_tx;
+	u32 uc_rx;
+	u32 mc_tx;
+	u32 mc_rx;
+	u32 bc_tx;
+	u32 bc_rx;
+} wdev_extended_ap_metric;
+
+
+typedef struct GNU_PACKED _wdev_sta_extended_info {
+#if 0
+	u8 bssid[MAC_ADDR_LEN];
+#endif
+	u32 last_data_ul_rate;
+	u32 last_data_dl_rate;
+	u32 utilization_rx;
+	u32 utilization_tx;
+} wdev_sta_ext_info;
+
+typedef struct GNU_PACKED _wdev_extended_sta_metrics {
+#if 0
+	u8 sta_mac[MAC_ADDR_LEN];
+	u8 extended_info_cnt;
+#endif
+	wdev_sta_ext_info sta_info;
+} wdev_extended_sta_metrics;
+
+#endif
+typedef struct GNU_PACKED _wapp_cac_info {
+	u8 channel;
+	u8 ret;
+	u8 cac_timer;
+} wapp_cac_info;
+#ifdef MAP_R2
+typedef enum cac_mode
+{
+	CONTINUOUS_CAC,
+	DEDICATED_CAC,
+	REDUCED_MIMO_CAC,
+} CAC_MODE;
+#endif
+
+
+typedef struct GNU_PACKED _wdev_misc_cap {
+	u8	max_num_of_cli;
+	u8	max_num_of_bss;
+	u8	num_of_bss;
+	u8	max_num_of_block_cli;
+} wdev_misc_cap;
+
+struct GNU_PACKED he_nss{
+	u16 nss_80:2;
+	u16 nss_160:2;
+	u16 nss_8080:2;
+};
+
+struct GNU_PACKED map_cli_cap {
+	u16 bw:2;
+	u16 phy_mode:3;
+	u16 nss:2;
+	u16 btm_capable:1;
+	u16 rrm_capable:1;
+	u16 mbo_capable:1;
+	struct he_nss nss_he;
+};
+
+#ifdef MAP_R3_WF6
+struct GNU_PACKED assoc_wifi6_sta_info {
+	unsigned char tid;
+	unsigned char tid_q_size;
+};
+
+typedef struct GNU_PACKED _wdev_wf6_cap {
+	unsigned char he_mcs_len;
+	unsigned char he_mcs[MAX_HE_MCS_LEN];
+	unsigned char tx_stream;
+	unsigned char rx_stream;
+	unsigned char he_8080;
+	unsigned char he_160;
+	unsigned char su_bf_cap;
+	unsigned char mu_bf_cap;
+	unsigned char ul_mu_mimo_cap;
+	unsigned char ul_mu_mimo_ofdma_cap;
+	unsigned char dl_mu_mimo_ofdma_cap;
+	unsigned char ul_ofdma_cap;
+	unsigned char dl_ofdma_cap;
+	unsigned char agent_role;
+	unsigned char su_beamformee_status;
+	unsigned char beamformee_sts_less80;
+	unsigned char beamformee_sts_more80;
+	unsigned char max_user_dl_tx_mu_mimo;
+	unsigned char max_user_ul_rx_mu_mimo;
+	unsigned char max_user_dl_tx_ofdma;
+	unsigned char max_user_ul_rx_ofdma;
+	unsigned char rts_status;
+	unsigned char mu_rts_status;
+	unsigned char m_bssid_status;
+	unsigned char mu_edca_status;
+	unsigned char twt_requester_status;
+	unsigned char twt_responder_status;
+} wdev_wf6_cap;
+
+typedef struct GNU_PACKED _wdev_wf6_cap_roles {
+	unsigned char role_supp;
+	wdev_wf6_cap wf6_role[2];
+} wdev_wf6_cap_roles;
+#endif
+
+typedef struct GNU_PACKED _wapp_client_info {
+	u8 mac_addr[MAC_ADDR_LEN];
+	u8 bssid[MAC_ADDR_LEN];
+	u8 sta_status; /* WAPP_STA_STATE */
+	u16 assoc_time;
+	u16 downlink;
+	u16 uplink;
+	signed char uplink_rssi;
+	/*traffic stats*/
+	u32 bytes_sent;
+	u32 bytes_received;
+	u32 packets_sent;
+	u32 packets_received;
+	u32 tx_packets_errors;
+	u32 rx_packets_errors;
+	u32 retransmission_count;
+	u16 link_availability;
+	u16 assoc_req_len;
+	u8 bLocalSteerDisallow;
+	u8 bBTMSteerDisallow;
+	u8 status;
+	/* ht_cap */
+	/* vht_cap */
+
+	/* Throughput for Tx/Rx */
+	u32 tx_tp;
+	u32 rx_tp;
+	struct map_cli_cap cli_caps;
+#ifdef MAP_R2
+	wdev_extended_sta_metrics ext_metric_info;
+#endif
+	u16 disassoc_reason;
+#ifdef MAP_R2
+	u8 IsReassoc;
+#endif
+	u8  is_APCLI;
+#ifdef MAP_R3_WF6
+	u8 tid_cnt;
+	struct assoc_wifi6_sta_info status_tlv[MAX_TID];
+#endif
+} wapp_client_info;
+
+struct GNU_PACKED chnList {
+	u8 channel;
+	u8 pref;
+	u16 cac_timer;
+};
+
+typedef struct GNU_PACKED _wdev_chn_info {
+	u8		op_ch;
+	u8		op_class;
+	u16		band; /* 24g; 5g1; 5g2 */
+	u8		ch_list_num;
+	u8		non_op_chn_num;
+	u16		dl_mcs;
+	struct chnList ch_list[32];
+	u8		non_op_ch_list[32];
+	u8		AutoChannelSkipListNum;
+	u8		AutoChannelSkipList[MAX_NUM_OF_CHANNELS + 1];
+} wdev_chn_info;
+
+struct GNU_PACKED opClassInfo {
+	u8	op_class;
+	u8	num_of_ch;
+	u8	ch_list[13];
+};
+
+typedef struct GNU_PACKED _wdev_op_class_info {
+	u8		num_of_op_class;
+	struct opClassInfo opClassInfo[MAX_OP_CLASS];
+} wdev_op_class_info;
+
+struct GNU_PACKED opClassInfoExt {
+	u8	op_class;
+	u8	num_of_ch;
+	u8	ch_list[MAX_NUM_OF_CHANNELS];
+};
+
+struct GNU_PACKED _wdev_op_class_info_ext {
+	u8		num_of_op_class;
+	struct opClassInfoExt opClassInfoExt[MAX_OP_CLASS];
+};
+
+typedef struct GNU_PACKED _wdev_bss_info {
+	u8 if_addr[MAC_ADDR_LEN];
+	u8 bssid[MAC_ADDR_LEN];
+	char ssid[MAX_LEN_OF_SSID + 1];
+	u8 SsidLen;
+	u8 map_role;
+	u32 auth_mode;
+	u32 enc_type;
+	u8 key_len;
+	u8 key[64 + 1];
+	u8 hidden_ssid;
+} wdev_bss_info;
+
+typedef struct GNU_PACKED _wsc_apcli_config {
+	char ssid[MAX_LEN_OF_SSID + 1];
+	u8 SsidLen;
+	u16 AuthType;
+	u16 EncrType;
+	u8 Key[64];
+	u16 KeyLength;
+	u8 KeyIndex;
+	u8 bssid[MAC_ADDR_LEN];
+	u8 peer_map_role;
+	u8 own_map_role;
+} wsc_apcli_config;
+
+typedef struct GNU_PACKED _wsc_apcli_config_msg {
+	u32 profile_count;
+	wsc_apcli_config apcli_config[0];
+} wsc_apcli_config_msg, *p_wsc_apcli_config_msg;
+
+typedef struct GNU_PACKED _wdev_ap_metric {
+	u8		bssid[MAC_ADDR_LEN];
+	u8		cu;
+	u8 		ESPI_AC[AC_NUM][3];
+#ifdef MAP_R2
+	wdev_extended_ap_metric ext_ap_metric;
+#endif
+} wdev_ap_metric;
+
+#ifdef MAP_R2
+typedef struct GNU_PACKED _wdev_radio_metric {
+	u8 cu_noise;
+	u8 cu_tx;
+	u8 cu_rx;
+	u8 cu_other;
+	u32 edcca;
+} wdev_radio_metric;
+#endif
+typedef struct GNU_PACKED _wdev_ap_config {
+	u8 sta_report_on_cop;
+	u8 sta_report_not_cop;
+	u8 rssi_steer;
+} wdev_ap_config;
+
+struct GNU_PACKED pwr_limit {
+	u8	op_class;
+	u8	max_pwr;
+};
+
+typedef struct GNU_PACKED _wdev_tx_power {
+	u8		num_of_op_class;
+	struct pwr_limit tx_pwr_limit[MAX_OP_CLASS];
+	u16 tx_pwr;
+} wdev_tx_power;
+
+/*Driver detects sta needed to steer*/
+typedef struct GNU_PACKED _wdev_steer_sta {
+	u8 mac_addr[MAC_ADDR_LEN];
+} wdev_steer_sta;
+
+typedef struct GNU_PACKED _wapp_probe_info {
+	u8 mac_addr[MAC_ADDR_LEN];
+	u8 channel;
+	signed char rssi;
+	u8 preq_len;
+	u8 preq[PREQ_IE_LEN];
+} wapp_probe_info;
+
+typedef struct GNU_PACKED _wapp_bcn_rpt_info {
+	u8 sta_addr[MAC_ADDR_LEN];
+	u8 last_fragment;
+	u16 bcn_rpt_len;
+	u8 bcn_rpt[BCN_RPT_LEN];
+} wapp_bcn_rpt_info;
+
+typedef struct GNU_PACKED wapp_bhsta_info {
+	u8 mac_addr[MAC_ADDR_LEN];
+	u8 connected_bssid[MAC_ADDR_LEN];
+	u8 peer_map_enable;
+} wapp_bhsta_info;
+
+typedef struct GNU_PACKED _wdev_steer_policy {
+	u8 steer_policy;
+	u8 cu_thr;
+	u8 rcpi_thr;
+} wdev_steer_policy;
+
+typedef struct GNU_PACKED _bssload_threshold {
+	u8 high_bssload_thrd;
+	u8 low_bssload_thrd;
+} bssload_threshold;
+
+typedef struct GNU_PACKED _wapp_bssload_info {
+	u16 sta_cnt;
+	u8 ch_util;
+	u16 AvalAdmCap;
+} wapp_bssload_info;
+
+/* By air monitor*/
+typedef struct GNU_PACKED _wapp_mnt_info {
+	u8 sta_addr[MAC_ADDR_LEN];
+	signed char rssi;
+} wapp_mnt_info;
+
+typedef struct GNU_PACKED _wapp_csa_info {
+	u8 new_channel;
+} wapp_csa_info;
+
+#ifdef WPS_UNCONFIG_FEATURE_SUPPORT
+struct GNU_PACKED wapp_wps_config_info {
+	u8 SSID[33];	/* mandatory */
+	u8 channel;
+	u16 AuthType;	/* mandatory, 1: open, 2: wpa-psk, 4: shared, 8:wpa, 0x10: wpa2, 0x20: wpa2-psk */
+	u16 EncrType;	/* mandatory, 1: none, 2: wep, 4: tkip, 8: aes */
+	u8 Key[64];		/* mandatory, Maximum 64 byte */
+	u16 KeyLength;
+	u8 MacAddr[MAC_ADDR_LEN];	/* mandatory, AP MAC address */
+	u8 bss_role;				/*0-Fronthaul, 1-Backhaul*/
+	u8 index;
+};
+#endif
+typedef struct GNU_PACKED _wapp_bss_state_info {
+	u32 interface_index;
+	WAPP_BSS_STATE bss_state;
+} wapp_bss_state_info;
+
+typedef struct GNU_PACKED _wapp_ch_change_info {
+	u32 interface_index;
+	u8 new_ch;/*New channel IEEE number*/
+	u8 op_class;
+} wapp_ch_change_info;
+
+typedef struct GNU_PACKED _wapp_txpower_change_info {
+	u32 interface_index;
+	u16 new_tx_pwr;/*New TX power*/
+} wapp_txpower_change_info;
+
+typedef struct GNU_PACKED _wapp_apcli_association_info {
+	u32 interface_index;
+	WAPP_APCLI_ASSOC_STATE apcli_assoc_state;
+	signed char rssi;
+	signed char PeerMAPEnable;
+} wapp_apcli_association_info;
+
+typedef struct GNU_PACKED _wapp_bssload_crossing_info {
+	u32 interface_index;
+	u8 bssload_high_thrd;
+	u8 bssload_low_thrd;
+	u8 bssload;
+} wapp_bssload_crossing_info;
+
+typedef struct GNU_PACKED _wapp_sta_cnnct_rejected_info {
+	u32 interface_index;
+	u8 sta_mac[MAC_ADDR_LEN];
+	u8 bssid[MAC_ADDR_LEN];
+	WAPP_CONNECT_FAILURE_REASON cnnct_fail;
+#ifdef MAP_R2
+	u16 assoc_status_code;
+	u16 assoc_reason_code;
+#endif
+} wapp_sta_cnnct_rej_info;
+
+struct GNU_PACKED map_vendor_ie
+{
+	u8 type;
+	u8 subtype;
+	u8 root_distance;
+	u8 connectivity_to_controller;
+	u16 uplink_rate;
+	u8 uplink_bssid[MAC_ADDR_LEN];
+	u8 bssid_5g[MAC_ADDR_LEN];
+	u8 bssid_2g[MAC_ADDR_LEN];
+};
+
+typedef struct _qbss_load_param {
+	u8     bValid;                     /* 1: variable contains valid value */
+	u16      StaNum;
+	u8       ChannelUtilization;
+	u16      RemainingAdmissionControl;  /* in unit of 32-us */
+} QBSS_LOAD_PARM, *PQBSS_LOAD_PARM;
+
+#ifdef MAP_R2
+typedef struct GNU_PACKED _wapp_qbss_load {
+	u8 bValid;/*1: variable contains valid value*/
+	u16  StaNum;
+	u8   ChannelUtilization;
+	u16  RemainingAdmissionControl;/*in unit of 32-us*/
+} WAPP_QBSS_LOAD_PARM;
+
+#endif
+#ifdef MAP_6E_SUPPORT
+struct GNU_PACKED map_rnr {
+	u8 channel;
+	u8 op;
+	u8 cce_ind;
+};
+#endif
+
+#ifdef DPP_R2_SUPPORT
+struct GNU_PACKED cce_vendor_ie
+{
+	u8 value;
+};
+
+#define MAX_CCE_CHANNEL 128
+
+struct GNU_PACKED cce_vendor_ie_result {
+	u8 num;
+	u8 cce_ch[MAX_CCE_CHANNEL];//channel list, on which beacon includes cce ie
+};
+#endif
+
+struct GNU_PACKED scan_bss_info {
+	u8 Bssid[MAC_ADDR_LEN];
+	u8 Channel;
+	u8 CentralChannel;
+	signed char Rssi;
+	signed char MinSNR;
+	u8 Privacy;
+
+	u8 SsidLen;
+	u8 Ssid[MAX_LEN_OF_SSID];
+
+	u16 AuthMode;
+	u16 EncrypType;
+	wdev_ht_cap ht_cap;
+	wdev_vht_cap vht_cap;
+	wdev_he_cap he_cap;
+	u8 map_vendor_ie_found;
+	struct map_vendor_ie map_info;
+#ifdef MAP_R2
+        WAPP_QBSS_LOAD_PARM QbssLoad;
+#endif
+#ifdef MAP_6E_SUPPORT
+	struct map_rnr rnr_6e;
+#endif
+};
+struct GNU_PACKED wapp_scan_info {
+	u32 interface_index;
+	u8 more_bss;
+	u8 bss_count;
+	struct scan_bss_info bss[0];
+};
+
+struct GNU_PACKED wapp_wsc_scan_info {
+	u8 bss_count;
+	u8 Uuid[16];
+};
+
+struct GNU_PACKED radar_notif_s
+{
+	u32 channel;
+	u32 status;
+	u32 bw;
+};
+
+#ifdef WIFI_MD_COEX_SUPPORT
+struct GNU_PACKED unsafe_channel_notif_s
+{
+	u32 ch_bitmap[4];
+};
+
+struct GNU_PACKED band_status_change {
+	u8 status;	/*0-radio temporarily cannot be used, 1-radio can be used*/
+};
+#endif
+
+typedef struct GNU_PACKED _NDIS_802_11_SSID {
+	u32 SsidLength;	/* length of SSID field below, in bytes; */
+	/* this can be zero. */
+	char Ssid[MAX_LEN_OF_SSID];	/* SSID information field */
+} NDIS_802_11_SSID, *PNDIS_802_11_SSID;
+struct GNU_PACKED nop_channel_list_s
+{
+	u8 channel_count;
+	u8 channel_list[MAX_NUM_OF_WAPP_CHANNELS];
+};
+
+/* WSC configured credential */
+typedef struct _WSC_CREDENTIAL {
+	NDIS_802_11_SSID SSID;	/* mandatory */
+	u16 AuthType;	/* mandatory, 1: open, 2: wpa-psk, 4: shared, 8:wpa, 0x10: wpa2, 0x20: wpa2-psk */
+	u16 EncrType;	/* mandatory, 1: none, 2: wep, 4: tkip, 8: aes */
+	u8 Key[64];		/* mandatory, Maximum 64 byte */
+	u16 KeyLength;
+	u8 MacAddr[MAC_ADDR_LEN];	/* mandatory, AP MAC address */
+	u8 KeyIndex;		/* optional, default is 1 */
+	u8 bFromUPnP;	/* TRUE: This credential is from external UPnP registrar */
+	u8 bss_role;		/*0-Fronthaul, 1-Backhaul*/
+	u8 DevPeerRole;	/* Device role for the peer device sending M8 */
+	u16 IpConfigMethod;
+	u32				RegIpv4Addr;
+	u32				Ipv4SubMask;
+	u32				EnrIpv4Addr;
+	u32				AvaIpv4SubmaskList[IWSC_MAX_SUB_MASK_LIST_COUNT];
+} WSC_CREDENTIAL, *PWSC_CREDENTIAL;
+
+struct scan_SSID
+{
+	char ssid[MAX_LEN_OF_SSID+ 1];
+	unsigned char SsidLen;
+};
+
+struct vendor_map_element {
+	u8 eid;
+	u8 length;
+	char oui[3]; /* 0x50 6F 9A */
+	char mtk_ie_element[4];
+	char type;
+	char subtype;
+	char root_distance;
+	char controller_connectivity;
+	short uplink_rate;
+	char uplink_bssid[MAC_ADDR_LEN];
+	char _5g_bssid[MAC_ADDR_LEN];
+	char _2g_bssid[MAC_ADDR_LEN];
+};
+
+struct GNU_PACKED scan_BH_ssids
+{
+	unsigned long scan_cookie;
+	unsigned char scan_channel_count;
+	unsigned char scan_channel_list[32];
+	unsigned char profile_cnt;
+	struct scan_SSID scan_SSID_val[MAX_PROFILE_CNT];
+};
+
+struct GNU_PACKED action_frm_data {
+	u32 ifindex;
+	u8 bssid[MAC_ADDR_LEN];
+	u8 destination_addr[MAC_ADDR_LEN];
+	u8 transmitter_addr[MAC_ADDR_LEN];
+	u32 chan;
+	u32 wait_time;
+	u32 no_cck;
+	u32 frm_len;
+	u16 seq_no;
+	char frm[0];
+};
+
+struct GNU_PACKED roc_req {
+	u32 ifindex;
+	u32 chan;
+	u32 wait_time;
+};
+
+#ifdef DPP_SUPPORT
+struct GNU_PACKED wapp_dpp_action_frame {
+	u8 src[MAC_ADDR_LEN];
+	u32 wapp_dpp_frame_id_no;
+	u32 chan;
+	u32 frm_len;
+	u32 is_gas;
+	u8 frm[0];
+};
+
+struct GNU_PACKED wapp_dpp_frm_tx_status {
+	u8 tx_success;
+	u16 seq_no;
+};
+
+struct GNU_PACKED pmk_req {
+	u32 ifindex;
+	u8 pmk[LEN_PMK];
+	u8 pmk_len;
+	u8 pmkid[LEN_PMKID];
+	u8 authenticator_addr[MAC_ADDR_LEN];
+	u8 supplicant_addr[MAC_ADDR_LEN];
+	int timeout;
+	int akmp;
+	u8 ssid[MAX_LEN_OF_SSID];
+	size_t ssidlen;
+};
+#endif /*DPP_SUPPORT*/
+#ifdef MAP_R3
+struct GNU_PACKED wapp_sta_info {
+        u8 src[MAC_ADDR_LEN];
+        char ssid[MAX_LEN_OF_SSID + 1];
+        unsigned char SsidLen;
+	u8 passphrase[LEN_PSK];
+	u8 pmk_len;
+        u8 pmk[LEN_PMK_MAX];
+	u8 ptk_len;
+        u8 ptk[LEN_MAX_PTK];
+};
+
+struct GNU_PACKED wapp_uri_info {
+	u8 src_mac[MAC_ADDR_LEN];
+	u8 uri_len;
+	u8 rcvd_uri[LEN_MAX_URI];
+};
+#endif /* MAP_R3 */
+
+struct GNU_PACKED wapp_srg_bitmap {
+	u32 color_31_0;
+	u32 color_63_32;
+	u32 bssid_31_0;
+	u32 bssid_63_32;
+};
+
+struct GNU_PACKED wapp_mesh_sr_info {
+	u8 sr_mode;
+	u8 ul_traffic_status;
+	struct wapp_srg_bitmap bm_info;
+};
+
+struct GNU_PACKED wapp_mesh_sr_topology {
+	u8 map_dev_count;
+	u8 map_dev_sr_support_mode;
+	u8 self_role;
+	u8 map_remote_al_mac[MAC_ADDR_LEN];
+	u8 map_remote_fh_bssid[MAC_ADDR_LEN];
+	u8 map_remote_bh_mac[MAC_ADDR_LEN];
+	unsigned char ssid_len;
+	unsigned char ssid[MAX_LEN_OF_SSID + 1];
+};
+
+typedef union GNU_PACKED _wapp_event_data {
+	wapp_dev_info dev_info;
+	wdev_ht_cap ht_cap;
+	wdev_vht_cap vht_cap;
+	wdev_misc_cap misc_cap;
+	wapp_client_info cli_info;
+	wdev_chn_info chn_list;
+	wdev_op_class_info op_class;
+	wdev_bss_info bss_info;
+	wdev_ap_metric ap_metrics;
+	wdev_ap_config ap_conf;
+	wdev_tx_power tx_pwr;
+	wdev_steer_sta str_sta;
+	wapp_probe_info probe_info;
+	wapp_bcn_rpt_info bcn_rpt_info;
+	wapp_bssload_info bssload_info;
+	wapp_bssload_crossing_info bssload_crossing_info;
+	wapp_mnt_info mnt_info;
+	wapp_bss_state_info bss_state_info;
+	wapp_ch_change_info ch_change_info;
+	wapp_txpower_change_info txpwr_change_info;
+	wapp_apcli_association_info apcli_association_info;
+	wapp_bhsta_info bhsta_info;
+	wapp_csa_info csa_info;
+	wapp_sta_cnnct_rej_info sta_cnnct_rej_info;
+	u8 ch_util;
+	struct wapp_scan_info scan_info;
+	struct wapp_wsc_scan_info wsc_scan_info;
+	u32 a4_missing_entry_ip;
+	struct radar_notif_s radar_notif;
+#ifdef WPS_UNCONFIG_FEATURE_SUPPORT
+	struct wapp_wps_config_info wps_conf_info;
+#endif
+        wapp_cac_info cac_info;
+#ifdef MAP_R2
+	wdev_extended_ap_metric ext_ap_metrics;
+	wdev_radio_metric radio_metrics;
+#endif
+#ifdef DPP_SUPPORT
+	u32 wapp_dpp_frame_id_no;
+	struct wapp_dpp_action_frame frame;
+	struct wapp_dpp_frm_tx_status tx_status;
+#ifdef DPP_R2_SUPPORT
+	struct cce_vendor_ie_result cce_ie_result;
+#endif
+#endif /*DPP_SUPPORT*/
+	unsigned char cac_enable;
+#ifdef WIFI_MD_COEX_SUPPORT
+	struct unsafe_channel_notif_s unsafe_ch_notif;
+	struct band_status_change band_status;
+#endif
+#ifdef MAP_R3
+	struct wapp_sta_info sta_info;
+        struct wapp_uri_info uri_info;
+#endif /* MAP_R3 */
+#ifdef QOS_R1
+	u8 *qos_frm;
+#endif
+	u8	ifname[IFNAMSIZ];
+#ifdef MAP_R3
+	struct wapp_mesh_sr_info mesh_sr_info;
+#endif /* MAP_R3 */
+} wapp_event_data;
+struct GNU_PACKED _wapp_event2_data {
+	wapp_client_info cli_info;
+};
+typedef struct GNU_PACKED _wapp_req_data {
+	u32	ifindex;
+	u8 mac_addr[MAC_ADDR_LEN];
+	u32 value;
+	bssload_threshold bssload_thrd;
+	wdev_steer_policy str_policy;
+	wdev_ap_config ap_conf;
+	WSC_CREDENTIAL bh_wsc_profile;
+	struct scan_BH_ssids scan_bh_ssids;
+#ifdef MAP_R3
+	struct wapp_srg_bitmap bm_info;
+	u8 band_index;
+	struct wapp_mesh_sr_topology topology_update;
+#endif /* MAP_R3 */
+} wapp_req_data;
+
+struct GNU_PACKED wapp_req {
+	u8 req_id;
+	u8 data_len;
+	wapp_req_data data;
+};
+
+struct GNU_PACKED wapp_event {
+	u8 len;
+	u8 event_id;
+	u32 ifindex;
+	wapp_event_data data;
+};
+struct GNU_PACKED wapp_event2 {
+	u8 len;
+	u8 event_id;
+	u32 ifindex;
+	struct _wapp_event2_data data;
+};
+typedef struct GNU_PACKED _tbtt_info_set {
+	u8 NrAPTbttOffset;
+	u32 ShortBssid;
+} tbtt_info_set;
+
+typedef struct GNU_PACKED _wapp_nr_info
+{
+	u8 	Bssid[MAC_ADDR_LEN];
+	u32 BssidInfo;
+	u8  RegulatoryClass;
+	u8  ChNum;
+	u8  PhyType;
+	u8  CandidatePrefSubID;
+	u8  CandidatePrefSubLen;
+	u8  CandidatePref;
+	/* extra sec info */
+	u32 akm;
+	u32 cipher;
+	u8  TbttInfoSetNum;
+	tbtt_info_set TbttInfoSet;
+	u8  Rssi;
+} wapp_nr_info;
+
+/* for NR IE , append Bssid ~ CandidatePref */
+#define NEIGHBOR_REPORT_IE_SIZE 	sizeof(wapp_nr_info) - 15
+
+
+typedef struct daemon_nr_list {
+	u8 	CurrListNum;
+	wapp_nr_info NRInfo[DAEMON_NEIGHBOR_REPORT_MAX_NUM];
+} DAEMON_NR_LIST, *P_DAEMON_NR_LIST;
+
+typedef struct GNU_PACKED daemon_neighbor_report_list {
+	u8	Newlist;
+	u8 	TotalNum;
+	u8 	CurrNum;
+	u8 	reserved;
+	wapp_nr_info EvtNRInfo[PER_EVENT_LIST_MAX_NUM];
+} DAEMON_EVENT_NR_LIST, *P_DAEMON_EVENT_NR_LIST;
+
+
+typedef struct GNU_PACKED neighbor_report_msg {
+	DAEMON_EVENT_NR_LIST evt_nr_list;
+} DAEMON_NR_MSG, *P_DAEMON_NR_MSG;
+
+
+/* for coverting wireless mode to string  */
+enum WIFI_MODE {
+	WMODE_INVALID = 0,
+	WMODE_A = 1 << 0,
+	WMODE_B = 1 << 1,
+	WMODE_G = 1 << 2,
+	WMODE_GN = 1 << 3,
+	WMODE_AN = 1 << 4,
+	WMODE_AC = 1 << 5,
+	WMODE_AX_24G = 1 << 6,
+	WMODE_AX_5G = 1 << 7,
+	WMODE_AX_6G = 1 << 8,
+	WMODE_COMP = 9, /* total types of supported wireless mode, add this value once yow add new type */
+};
+typedef union GNU_PACKED _RRM_BSSID_INFO
+{
+	struct GNU_PACKED
+	{
+#ifdef RT_BIG_ENDIAN
+		u32 Reserved:18;
+		u32 FTM:1;
+		u32 VHT:1;
+		u32 HT:1;
+		u32 MobilityDomain:1;
+		u32 ImmediateBA:1;
+		u32 DelayBlockAck:1;
+		u32 RRM:1;
+		u32 APSD:1;
+		u32 Qos:1;
+		u32 SpectrumMng:1;
+		u32 KeyScope:1;
+		u32 Security:1;
+		u32 APReachAble:2;
+#else
+		u32 APReachAble:2;
+		u32 Security:1;
+		u32 KeyScope:1;
+		u32 SpectrumMng:1;
+		u32 Qos:1;
+		u32 APSD:1;
+		u32 RRM:1;
+		u32 DelayBlockAck:1;
+		u32 ImmediateBA:1;
+		u32 MobilityDomain:1;
+		u32 HT:1;
+		u32 VHT:1;
+		u32 FTM:1;
+		u32 Reserved:18;
+#endif
+	} field;
+	u32 word;
+} RRM_BSSID_INFO, *PRRM_BSSID_INFO;
+#endif /* __WAPP_TYPES_H__ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/net/nat/foe_hook/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/net/nat/foe_hook/Makefile
new file mode 100755
index 0000000..b0d41e5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/net/nat/foe_hook/Makefile
@@ -0,0 +1,5 @@
+obj-y		+= foe_hook.o
+
+foe_hook-objs	+= hook_base.o
+foe_hook-objs	+= hook_ext.o
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/net/nat/foe_hook/hook_base.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/net/nat/foe_hook/hook_base.c
new file mode 100755
index 0000000..2e41170
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/net/nat/foe_hook/hook_base.c
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: Harry Huang <harry.huang@mediatek.com>
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <net/ra_nat.h>
+#define PURPOSE "FAST_NAT_SUPPORT"
+
+int (*ra_sw_nat_hook_rx)(struct sk_buff *skb) = NULL;
+EXPORT_SYMBOL(ra_sw_nat_hook_rx);
+
+int (*ra_sw_nat_hook_tx)(struct sk_buff *skb, int gmac_no) = NULL;
+EXPORT_SYMBOL(ra_sw_nat_hook_tx);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/net/nat/foe_hook/hook_ext.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/net/nat/foe_hook/hook_ext.c
new file mode 100755
index 0000000..72afec4
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/net/nat/foe_hook/hook_ext.c
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: Harry Huang <harry.huang@mediatek.com>
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <net/ra_nat.h>
+
+struct net_device	*dst_port[MAX_IF_NUM];
+EXPORT_SYMBOL(dst_port);
+u8 dst_port_type[MAX_IF_NUM];
+EXPORT_SYMBOL(dst_port_type);
+
+struct foe_entry *ppe_virt_foe_base_tmp;
+EXPORT_SYMBOL(ppe_virt_foe_base_tmp);
+struct foe_entry *ppe1_virt_foe_base_tmp;
+EXPORT_SYMBOL(ppe1_virt_foe_base_tmp);
+
+int (*ppe_hook_rx_wifi)(struct sk_buff *skb) = NULL;
+EXPORT_SYMBOL(ppe_hook_rx_wifi);
+int (*ppe_hook_tx_wifi)(struct sk_buff *skb, int gmac_no) = NULL;
+EXPORT_SYMBOL(ppe_hook_tx_wifi);
+
+int (*ppe_hook_rx_modem)(struct sk_buff *skb, u32 cpu_reason, u32 foe_entry_num) = NULL;
+EXPORT_SYMBOL(ppe_hook_rx_modem);
+int (*ppe_hook_tx_modem)(struct sk_buff *skb, u32 net_type, u32 channel_id) = NULL;
+EXPORT_SYMBOL(ppe_hook_tx_modem);
+
+int (*ppe_hook_rx_eth)(struct sk_buff *skb) = NULL;
+EXPORT_SYMBOL(ppe_hook_rx_eth);
+int (*ppe_hook_tx_eth)(struct sk_buff *skb, int gmac_no) = NULL;
+EXPORT_SYMBOL(ppe_hook_tx_eth);
+
+int (*ppe_hook_rx_ext)(struct sk_buff *skb) = NULL;
+EXPORT_SYMBOL(ppe_hook_rx_ext);
+int (*ppe_hook_tx_ext)(struct sk_buff *skb, int gmac_no) = NULL;
+EXPORT_SYMBOL(ppe_hook_tx_ext);
+
+void (*ppe_dev_register_hook)(struct net_device *dev) = NULL;
+EXPORT_SYMBOL(ppe_dev_register_hook);
+void (*ppe_dev_unregister_hook)(struct net_device *dev) = NULL;
+EXPORT_SYMBOL(ppe_dev_unregister_hook);
+
+void  hwnat_magic_tag_set_zero(struct sk_buff *skb)
+{
+	if ((FOE_MAGIC_TAG_HEAD(skb) == FOE_MAGIC_PCI) ||
+	    (FOE_MAGIC_TAG_HEAD(skb) == FOE_MAGIC_WLAN) ||
+	    (FOE_MAGIC_TAG_HEAD(skb) == FOE_MAGIC_GE)) {
+		if (IS_SPACE_AVAILABLE_HEAD(skb))
+			FOE_MAGIC_TAG_HEAD(skb) = 0;
+	}
+	if ((FOE_MAGIC_TAG_TAIL(skb) == FOE_MAGIC_PCI) ||
+	    (FOE_MAGIC_TAG_TAIL(skb) == FOE_MAGIC_WLAN) ||
+	    (FOE_MAGIC_TAG_TAIL(skb) == FOE_MAGIC_GE)) {
+		if (IS_SPACE_AVAILABLE_TAIL(skb))
+			FOE_MAGIC_TAG_TAIL(skb) = 0;
+	}
+}
+EXPORT_SYMBOL(hwnat_magic_tag_set_zero);
+
+void hwnat_check_magic_tag(struct sk_buff *skb)
+{
+	if (IS_SPACE_AVAILABLE_HEAD(skb)) {
+		FOE_MAGIC_TAG_HEAD(skb) = 0;
+		FOE_AI_HEAD(skb) = UN_HIT;
+	}
+	if (IS_SPACE_AVAILABLE_TAIL(skb)) {
+		FOE_MAGIC_TAG_TAIL(skb) = 0;
+		FOE_AI_TAIL(skb) = UN_HIT;
+	}
+}
+EXPORT_SYMBOL(hwnat_check_magic_tag);
+
+void hwnat_set_headroom_zero(struct sk_buff *skb)
+{
+	if (skb->cloned != 1) {
+		if (IS_MAGIC_TAG_PROTECT_VALID_HEAD(skb) ||
+		    (FOE_MAGIC_TAG_HEAD(skb) == FOE_MAGIC_PPE)) {
+			if (IS_SPACE_AVAILABLE_HEAD(skb))
+				memset(FOE_INFO_START_ADDR_HEAD(skb), 0,
+				       FOE_INFO_LEN);
+		}
+	}
+}
+EXPORT_SYMBOL(hwnat_set_headroom_zero);
+
+void hwnat_set_tailroom_zero(struct sk_buff *skb)
+{
+	if (skb->cloned != 1) {
+		if (IS_MAGIC_TAG_PROTECT_VALID_TAIL(skb) ||
+		    (FOE_MAGIC_TAG_TAIL(skb) == FOE_MAGIC_PPE)) {
+			if (IS_SPACE_AVAILABLE_TAIL(skb))
+				memset(FOE_INFO_START_ADDR_TAIL(skb), 0,
+				       FOE_INFO_LEN);
+		}
+	}
+}
+EXPORT_SYMBOL(hwnat_set_tailroom_zero);
+
+void hwnat_copy_headroom(u8 *data, struct sk_buff *skb)
+{
+	memcpy(data, skb->head, FOE_INFO_LEN);
+}
+EXPORT_SYMBOL(hwnat_copy_headroom);
+
+void hwnat_copy_tailroom(u8 *data, int size, struct sk_buff *skb)
+{
+	memcpy((data + size - FOE_INFO_LEN),
+	       (skb_end_pointer(skb) - FOE_INFO_LEN),
+	       FOE_INFO_LEN);
+}
+EXPORT_SYMBOL(hwnat_copy_tailroom);
+
+void hwnat_setup_dma_ops(struct device *dev, bool coherent)
+{
+	arch_setup_dma_ops(dev, 0, 0, NULL, coherent);
+}
+EXPORT_SYMBOL(hwnat_setup_dma_ops);
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/Makefile
new file mode 100644
index 0000000..958ad63
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/Makefile
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# platform driver
+snd-soc-mt79xx-afe-objs := \
+	mt79xx-afe-pcm.o \
+	mt79xx-afe-clk.o \
+	mt79xx-dai-etdm.o
+
+obj-$(CONFIG_SND_SOC_MT79XX) += snd-soc-mt79xx-afe.o
+obj-$(CONFIG_SND_SOC_MT79XX_WM8960) += mt79xx-wm8960.o
+obj-$(CONFIG_SND_SOC_MT79XX_SI3218X) += mt79xx-si3218x.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-clk.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-clk.c
new file mode 100644
index 0000000..6f13c42
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-clk.c
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt79xx-afe-clk.c  --  Mediatek 79xx afe clock ctrl
+//
+// Copyright (c) 2021 MediaTek Inc.
+// Author: Vic Wu <vic.wu@mediatek.com>
+
+#include <linux/clk.h>
+
+#include "mt79xx-afe-common.h"
+#include "mt79xx-afe-clk.h"
+#include "mt79xx-reg.h"
+
+enum {
+	CK_INFRA_AUD_BUS_CK = 0,
+	CK_INFRA_AUD_26M_CK,
+	CK_INFRA_AUD_L_CK,
+	CK_INFRA_AUD_AUD_CK,
+	CK_INFRA_AUD_EG2_CK,
+	CLK_NUM
+};
+
+static const char *aud_clks[CLK_NUM] = {
+	[CK_INFRA_AUD_BUS_CK] = "aud_bus_ck",
+	[CK_INFRA_AUD_26M_CK] = "aud_26m_ck",
+	[CK_INFRA_AUD_L_CK] = "aud_l_ck",
+	[CK_INFRA_AUD_AUD_CK] = "aud_aud_ck",
+	[CK_INFRA_AUD_EG2_CK] = "aud_eg2_ck",
+};
+
+int mt79xx_init_clock(struct mtk_base_afe *afe)
+{
+	struct mt79xx_afe_private *afe_priv = afe->platform_priv;
+	int i;
+
+	afe_priv->clk = devm_kcalloc(afe->dev, CLK_NUM, sizeof(*afe_priv->clk),
+				     GFP_KERNEL);
+	if (!afe_priv->clk)
+		return -ENOMEM;
+
+	for (i = 0; i < CLK_NUM; i++) {
+		afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]);
+		if (IS_ERR(afe_priv->clk[i])) {
+			dev_err(afe->dev, "%s(), devm_clk_get %s fail,\
+				ret %ld\n", __func__, aud_clks[i],
+				PTR_ERR(afe_priv->clk[i]));
+			return PTR_ERR(afe_priv->clk[i]);
+		}
+	}
+
+	return 0;
+}
+
+int mt79xx_afe_enable_clock(struct mtk_base_afe *afe)
+{
+	struct mt79xx_afe_private *afe_priv = afe->platform_priv;
+	int ret;
+
+	ret = clk_prepare_enable(afe_priv->clk[CK_INFRA_AUD_BUS_CK]);
+	if (ret) {
+		dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[CK_INFRA_AUD_BUS_CK], ret);
+		goto CK_INFRA_AUD_BUS_CK_ERR;
+	}
+
+	ret = clk_prepare_enable(afe_priv->clk[CK_INFRA_AUD_26M_CK]);
+	if (ret) {
+		dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[CK_INFRA_AUD_26M_CK], ret);
+		goto CK_INFRA_AUD_26M_ERR;
+	}
+
+	ret = clk_prepare_enable(afe_priv->clk[CK_INFRA_AUD_L_CK]);
+	if (ret) {
+		dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[CK_INFRA_AUD_L_CK], ret);
+		goto CK_INFRA_AUD_L_CK_ERR;
+	}
+
+	ret = clk_prepare_enable(afe_priv->clk[CK_INFRA_AUD_AUD_CK]);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[CK_INFRA_AUD_AUD_CK], ret);
+		goto CK_INFRA_AUD_AUD_CK_ERR;
+	}
+
+	ret = clk_prepare_enable(afe_priv->clk[CK_INFRA_AUD_EG2_CK]);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[CK_INFRA_AUD_EG2_CK], ret);
+		goto CK_INFRA_AUD_EG2_CK_ERR;
+	}
+
+	return 0;
+
+CK_INFRA_AUD_EG2_CK_ERR:
+	clk_disable_unprepare(afe_priv->clk[CK_INFRA_AUD_AUD_CK]);
+CK_INFRA_AUD_AUD_CK_ERR:
+	clk_disable_unprepare(afe_priv->clk[CK_INFRA_AUD_L_CK]);
+CK_INFRA_AUD_L_CK_ERR:
+	clk_disable_unprepare(afe_priv->clk[CK_INFRA_AUD_26M_CK]);
+CK_INFRA_AUD_26M_ERR:
+	clk_disable_unprepare(afe_priv->clk[CK_INFRA_AUD_BUS_CK]);
+CK_INFRA_AUD_BUS_CK_ERR:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(mt79xx_afe_enable_clock);
+
+int mt79xx_afe_disable_clock(struct mtk_base_afe *afe)
+{
+	struct mt79xx_afe_private *afe_priv = afe->platform_priv;
+
+	clk_disable_unprepare(afe_priv->clk[CK_INFRA_AUD_EG2_CK]);
+	clk_disable_unprepare(afe_priv->clk[CK_INFRA_AUD_AUD_CK]);
+	clk_disable_unprepare(afe_priv->clk[CK_INFRA_AUD_L_CK]);
+	clk_disable_unprepare(afe_priv->clk[CK_INFRA_AUD_26M_CK]);
+	clk_disable_unprepare(afe_priv->clk[CK_INFRA_AUD_BUS_CK]);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mt79xx_afe_disable_clock);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-clk.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-clk.h
new file mode 100644
index 0000000..50424d8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-clk.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt79xx-afe-clk.h  --  Mediatek 79xx afe clock ctrl definition
+ *
+ * Copyright (c) 2021 MediaTek Inc.
+ * Author: Vic Wu <vic.wu@mediatek.com>
+ */
+
+#ifndef _MT79XX_AFE_CLK_H_
+#define _MT79XX_AFE_CLK_H_
+
+struct mtk_base_afe;
+
+int mt79xx_init_clock(struct mtk_base_afe *afe);
+int mt79xx_afe_enable_clock(struct mtk_base_afe *afe);
+int mt79xx_afe_disable_clock(struct mtk_base_afe *afe);
+#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-common.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-common.h
new file mode 100644
index 0000000..277d10c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-common.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt79xx-afe-common.h  --  Mediatek 79xx audio driver definitions
+ *
+ * Copyright (c) 2021 MediaTek Inc.
+ * Author: Vic Wu <vic.wu@mediatek.com>
+ */
+
+#ifndef _MT_79XX_AFE_COMMON_H_
+#define _MT_79XX_AFE_COMMON_H_
+
+#include <sound/soc.h>
+#include <linux/list.h>
+#include <linux/regmap.h>
+#include "../common/mtk-base-afe.h"
+
+enum {
+	MT79XX_MEMIF_DL1,
+	MT79XX_MEMIF_VUL12,
+	MT79XX_MEMIF_NUM,
+	MT79XX_DAI_ETDM = MT79XX_MEMIF_NUM,
+	MT79XX_DAI_NUM,
+};
+
+enum {
+	MT79XX_IRQ_0,
+	MT79XX_IRQ_1,
+	MT79XX_IRQ_2,
+	MT79XX_IRQ_NUM,
+};
+
+struct clk;
+
+struct mt79xx_afe_private {
+	struct clk **clk;
+
+	int pm_runtime_bypass_reg_ctl;
+
+	/* dai */
+	void *dai_priv[MT79XX_DAI_NUM];
+};
+
+unsigned int mt79xx_afe_rate_transform(struct device *dev,
+				       unsigned int rate);
+
+/* dai register */
+int mt79xx_dai_etdm_register(struct mtk_base_afe *afe);
+#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-pcm.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-pcm.c
new file mode 100644
index 0000000..63162c7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-pcm.c
@@ -0,0 +1,607 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Mediatek ALSA SoC AFE platform driver for 79xx
+//
+// Copyright (c) 2021 MediaTek Inc.
+// Author: Vic Wu <vic.wu@mediatek.com>
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+
+#include "mt79xx-afe-common.h"
+#include "mt79xx-afe-clk.h"
+#include "mt79xx-reg.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "../common/mtk-afe-fe-dai.h"
+
+enum {
+	MTK_AFE_RATE_8K = 0,
+	MTK_AFE_RATE_11K = 1,
+	MTK_AFE_RATE_12K = 2,
+	MTK_AFE_RATE_16K = 4,
+	MTK_AFE_RATE_22K = 5,
+	MTK_AFE_RATE_24K = 6,
+	MTK_AFE_RATE_32K = 8,
+	MTK_AFE_RATE_44K = 9,
+	MTK_AFE_RATE_48K = 10,
+	MTK_AFE_RATE_88K = 13,
+	MTK_AFE_RATE_96K = 14,
+	MTK_AFE_RATE_176K = 17,
+	MTK_AFE_RATE_192K = 18,
+};
+
+unsigned int mt79xx_afe_rate_transform(struct device *dev,
+				       unsigned int rate)
+{
+	switch (rate) {
+	case 8000:
+		return MTK_AFE_RATE_8K;
+	case 11025:
+		return MTK_AFE_RATE_11K;
+	case 12000:
+		return MTK_AFE_RATE_12K;
+	case 16000:
+		return MTK_AFE_RATE_16K;
+	case 22050:
+		return MTK_AFE_RATE_22K;
+	case 24000:
+		return MTK_AFE_RATE_24K;
+	case 32000:
+		return MTK_AFE_RATE_32K;
+	case 44100:
+		return MTK_AFE_RATE_44K;
+	case 48000:
+		return MTK_AFE_RATE_48K;
+	case 88200:
+		return MTK_AFE_RATE_88K;
+	case 96000:
+		return MTK_AFE_RATE_96K;
+	case 176400:
+		return MTK_AFE_RATE_176K;
+	case 192000:
+		return MTK_AFE_RATE_192K;
+	default:
+		dev_warn(dev, "%s(), rate %u invalid, use %d!!!\n",
+			 __func__, rate, MTK_AFE_RATE_48K);
+		return MTK_AFE_RATE_48K;
+	}
+}
+
+static const struct snd_pcm_hardware mt79xx_afe_hardware = {
+	.info = SNDRV_PCM_INFO_MMAP |
+		SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_MMAP_VALID,
+	.formats = SNDRV_PCM_FMTBIT_S16_LE |
+		   SNDRV_PCM_FMTBIT_S24_LE |
+		   SNDRV_PCM_FMTBIT_S32_LE,
+	.period_bytes_min = 256,
+	.period_bytes_max = 4 * 48 * 1024,
+	.periods_min = 2,
+	.periods_max = 256,
+	.buffer_bytes_max = 8 * 48 * 1024,
+	.fifo_size = 0,
+};
+
+static int mt79xx_memif_fs(struct snd_pcm_substream *substream,
+			   unsigned int rate)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_component *component =
+		snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+
+	return mt79xx_afe_rate_transform(afe->dev, rate);
+}
+
+static int mt79xx_irq_fs(struct snd_pcm_substream *substream,
+			 unsigned int rate)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_component *component =
+		snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+
+	return mt79xx_afe_rate_transform(afe->dev, rate);
+}
+
+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\
+		       SNDRV_PCM_RATE_88200 |\
+		       SNDRV_PCM_RATE_96000 |\
+		       SNDRV_PCM_RATE_176400 |\
+		       SNDRV_PCM_RATE_192000)
+
+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+			 SNDRV_PCM_FMTBIT_S24_LE |\
+			 SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mt79xx_memif_dai_driver[] = {
+	/* FE DAIs: memory intefaces to CPU */
+	{
+		.name = "DL1",
+		.id = MT79XX_MEMIF_DL1,
+		.playback = {
+			.stream_name = "DL1",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+	{
+		.name = "UL1",
+		.id = MT79XX_MEMIF_VUL12,
+		.capture = {
+			.stream_name = "UL1",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_PCM_RATES,
+			.formats = MTK_PCM_FORMATS,
+		},
+		.ops = &mtk_afe_fe_ops,
+	},
+};
+
+static const struct snd_kcontrol_new o018_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I150_Switch", AFE_CONN018_4, 22, 1, 0),
+};
+
+static const struct snd_kcontrol_new o019_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I151_Switch", AFE_CONN019_4, 23, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mt79xx_memif_widgets[] = {
+	/* DL */
+	SND_SOC_DAPM_MIXER("I032", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I033", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	/* UL */
+	SND_SOC_DAPM_MIXER("O018", SND_SOC_NOPM, 0, 0,
+			   o018_mix, ARRAY_SIZE(o018_mix)),
+	SND_SOC_DAPM_MIXER("O019", SND_SOC_NOPM, 0, 0,
+			   o019_mix, ARRAY_SIZE(o019_mix)),
+};
+
+static const struct snd_soc_dapm_route mt79xx_memif_routes[] = {
+	{"I032", NULL, "DL1"},
+	{"I033", NULL, "DL1"},
+	{"UL1", NULL, "O018"},
+	{"UL1", NULL, "O019"},
+	{"O018", "I150_Switch", "I150"},
+	{"O019", "I151_Switch", "I151"},
+};
+
+static const struct snd_soc_component_driver mt79xx_afe_pcm_dai_component = {
+	.name = "mt79xx-afe-pcm-dai",
+};
+
+static const struct mtk_base_memif_data memif_data[MT79XX_MEMIF_NUM] = {
+	[MT79XX_MEMIF_DL1] = {
+		.name = "DL1",
+		.id = MT79XX_MEMIF_DL1,
+		.reg_ofs_base = AFE_DL0_BASE,
+		.reg_ofs_cur = AFE_DL0_CUR,
+		.reg_ofs_end = AFE_DL0_END,
+		.reg_ofs_base_msb = AFE_DL0_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_DL0_CUR_MSB,
+		.reg_ofs_end_msb = AFE_DL0_END_MSB,
+		.fs_reg = AFE_DL0_CON0,
+		.fs_shift =  DL0_MODE_SFT,
+		.fs_maskbit =  DL0_MODE_MASK,
+		.mono_reg = AFE_DL0_CON0,
+		.mono_shift = DL0_MONO_SFT,
+		.enable_reg = AFE_DL0_CON0,
+		.enable_shift = DL0_ON_SFT,
+		.hd_reg = AFE_DL0_CON0,
+		.hd_shift = DL0_HD_MODE_SFT,
+		.hd_align_reg = AFE_DL0_CON0,
+		.hd_align_mshift = DL0_HALIGN_SFT,
+		.pbuf_reg = AFE_DL0_CON0,
+		.pbuf_shift = DL0_PBUF_SIZE_SFT,
+		.minlen_reg = AFE_DL0_CON0,
+		.minlen_shift = DL0_MINLEN_SFT,
+	},
+	[MT79XX_MEMIF_VUL12] = {
+		.name = "VUL12",
+		.id = MT79XX_MEMIF_VUL12,
+		.reg_ofs_base = AFE_VUL0_BASE,
+		.reg_ofs_cur = AFE_VUL0_CUR,
+		.reg_ofs_end = AFE_VUL0_END,
+		.reg_ofs_base_msb = AFE_VUL0_BASE_MSB,
+		.reg_ofs_cur_msb = AFE_VUL0_CUR_MSB,
+		.reg_ofs_end_msb = AFE_VUL0_END_MSB,
+		.fs_reg = AFE_VUL0_CON0,
+		.fs_shift = VUL0_MODE_SFT,
+		.fs_maskbit = VUL0_MODE_MASK,
+		.mono_reg = AFE_VUL0_CON0,
+		.mono_shift = VUL0_MONO_SFT,
+		.enable_reg = AFE_VUL0_CON0,
+		.enable_shift = VUL0_ON_SFT,
+		.hd_reg = AFE_VUL0_CON0,
+		.hd_shift = VUL0_HD_MODE_SFT,
+		.hd_align_reg = AFE_VUL0_CON0,
+		.hd_align_mshift = VUL0_HALIGN_SFT,
+	},
+};
+
+static const struct mtk_base_irq_data irq_data[MT79XX_IRQ_NUM] = {
+	[MT79XX_IRQ_0] = {
+		.id = MT79XX_IRQ_0,
+		.irq_cnt_reg = AFE_IRQ0_MCU_CFG1,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.irq_fs_reg = AFE_IRQ0_MCU_CFG0,
+		.irq_fs_shift = IRQ_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ0_MCU_CFG0,
+		.irq_en_shift = IRQ_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ0_MCU_CLR_SFT,
+	},
+	[MT79XX_IRQ_1] = {
+		.id = MT79XX_IRQ_1,
+		.irq_cnt_reg = AFE_IRQ1_MCU_CFG1,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.irq_fs_reg = AFE_IRQ1_MCU_CFG0,
+		.irq_fs_shift = IRQ_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ1_MCU_CFG0,
+		.irq_en_shift = IRQ_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ1_MCU_CLR_SFT,
+	},
+	[MT79XX_IRQ_2] = {
+		.id = MT79XX_IRQ_2,
+		.irq_cnt_reg = AFE_IRQ2_MCU_CFG1,
+		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+		.irq_fs_reg = AFE_IRQ2_MCU_CFG0,
+		.irq_fs_shift = IRQ_MCU_MODE_SFT,
+		.irq_fs_maskbit = IRQ_MCU_MODE_MASK,
+		.irq_en_reg = AFE_IRQ2_MCU_CFG0,
+		.irq_en_shift = IRQ_MCU_ON_SFT,
+		.irq_clr_reg = AFE_IRQ_MCU_CLR,
+		.irq_clr_shift = IRQ2_MCU_CLR_SFT,
+	},
+};
+
+static bool mt79xx_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	/* these auto-gen reg has read-only bit, so put it as volatile */
+	/* volatile reg cannot be cached, so cannot be set when power off */
+	switch (reg) {
+	case AFE_DL0_CUR_MSB:
+	case AFE_DL0_CUR:
+	case AFE_DL0_RCH_MON:
+	case AFE_DL0_LCH_MON:
+	case AFE_VUL0_CUR_MSB:
+	case AFE_VUL0_CUR:
+	case AFE_IRQ_MCU_STATUS:
+	case AFE_MEMIF_RD_MON:
+	case AFE_MEMIF_WR_MON:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_config mt79xx_afe_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.volatile_reg = mt79xx_is_volatile_reg,
+	.max_register = AFE_MAX_REGISTER,
+	.num_reg_defaults_raw = ((AFE_MAX_REGISTER / 4) + 1),
+};
+
+static irqreturn_t mt79xx_afe_irq_handler(int irq_id, void *dev)
+{
+	struct mtk_base_afe *afe = dev;
+	struct mtk_base_afe_irq *irq;
+	unsigned int status;
+	unsigned int status_mcu;
+	unsigned int mcu_en;
+	int ret;
+	int i;
+	irqreturn_t irq_ret = IRQ_HANDLED;
+
+	/* get irq that is sent to MCU */
+	regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_en);
+
+	ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &status);
+	/* only care IRQ which is sent to MCU */
+	status_mcu = status & mcu_en & AFE_IRQ_STATUS_BITS;
+
+	if (ret || status_mcu == 0) {
+		dev_err(afe->dev, "%s(), irq status err, ret %d, status 0x%x,\
+			mcu_en 0x%x\n", __func__, ret, status, mcu_en);
+
+		irq_ret = IRQ_NONE;
+		goto err_irq;
+	}
+
+	for (i = 0; i < MT79XX_MEMIF_NUM; i++) {
+		struct mtk_base_afe_memif *memif = &afe->memif[i];
+
+		if (!memif->substream)
+			continue;
+
+		if (memif->irq_usage < 0)
+			continue;
+
+		irq = &afe->irqs[memif->irq_usage];
+
+		if (status_mcu & (1 << irq->irq_data->irq_en_shift))
+			snd_pcm_period_elapsed(memif->substream);
+	}
+
+err_irq:
+	/* clear irq */
+	regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, status_mcu);
+
+	return irq_ret;
+}
+
+static int mt79xx_afe_runtime_suspend(struct device *dev)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dev);
+	struct mt79xx_afe_private *afe_priv = afe->platform_priv;
+
+	if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
+		goto skip_regmap;
+
+	/* disable clk*/
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0x3fff);
+	regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK,
+			   0);
+	regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK,
+			   0);
+
+	/* make sure all irq status are cleared, twice intended */
+	regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CLR, 0xffff, 0xffff);
+
+skip_regmap:
+	return mt79xx_afe_disable_clock(afe);
+}
+
+static int mt79xx_afe_runtime_resume(struct device *dev)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dev);
+	struct mt79xx_afe_private *afe_priv = afe->platform_priv;
+	int ret;
+
+	ret = mt79xx_afe_enable_clock(afe);
+	if (ret)
+		return ret;
+
+	if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
+		goto skip_regmap;
+
+	/* enable clk*/
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0);
+	regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK,
+			   AUD_APLL2_EN);
+	regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK,
+			   AUD_26M_EN);
+
+skip_regmap:
+	return 0;
+}
+
+static int mt79xx_afe_component_probe(struct snd_soc_component *component)
+{
+	return mtk_afe_add_sub_dai_control(component);
+}
+
+static const struct snd_soc_component_driver mt79xx_afe_component = {
+	.name = AFE_PCM_NAME,
+	.ops = &mtk_afe_pcm_ops,
+	.pcm_new = mtk_afe_pcm_new,
+	.pcm_free = mtk_afe_pcm_free,
+	.probe = mt79xx_afe_component_probe,
+};
+
+static int mt79xx_dai_memif_register(struct mtk_base_afe *afe)
+{
+	struct mtk_base_afe_dai *dai;
+
+	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+	if (!dai)
+		return -ENOMEM;
+
+	list_add(&dai->list, &afe->sub_dais);
+
+	dai->dai_drivers = mt79xx_memif_dai_driver;
+	dai->num_dai_drivers = ARRAY_SIZE(mt79xx_memif_dai_driver);
+
+	dai->dapm_widgets = mt79xx_memif_widgets;
+	dai->num_dapm_widgets = ARRAY_SIZE(mt79xx_memif_widgets);
+	dai->dapm_routes = mt79xx_memif_routes;
+	dai->num_dapm_routes = ARRAY_SIZE(mt79xx_memif_routes);
+
+	return 0;
+}
+
+typedef int (*dai_register_cb)(struct mtk_base_afe *);
+static const dai_register_cb dai_register_cbs[] = {
+	mt79xx_dai_etdm_register,
+	mt79xx_dai_memif_register,
+};
+
+static int mt79xx_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+	struct mtk_base_afe *afe;
+	struct mt79xx_afe_private *afe_priv;
+	struct device *dev;
+	int i, irq_id, ret;
+
+	afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
+	if (!afe)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, afe);
+
+	afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
+					  GFP_KERNEL);
+	if (!afe->platform_priv)
+		return -ENOMEM;
+
+	afe_priv = afe->platform_priv;
+	afe->dev = &pdev->dev;
+	dev = afe->dev;
+
+	afe->base_addr = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(afe->base_addr))
+		return PTR_ERR(afe->base_addr);
+
+	/* initial audio related clock */
+	ret = mt79xx_init_clock(afe);
+	if (ret) {
+		dev_err(dev, "init clock error\n");
+		return ret;
+	}
+
+	pm_runtime_enable(dev);
+
+	/* enable clock for regcache get default value from hw */
+	afe_priv->pm_runtime_bypass_reg_ctl = true;
+	pm_runtime_get_sync(&pdev->dev);
+
+	afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr,
+		      &mt79xx_afe_regmap_config);
+	if (IS_ERR(afe->regmap)) {
+		ret = PTR_ERR(afe->regmap);
+		goto err_pm_disable;
+	}
+
+	pm_runtime_put_sync(&pdev->dev);
+	afe_priv->pm_runtime_bypass_reg_ctl = false;
+
+	/* init memif */
+	afe->memif_size = MT79XX_MEMIF_NUM;
+	afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif),
+				  GFP_KERNEL);
+	if (!afe->memif)
+		goto err_pm_disable;
+
+	for (i = 0; i < afe->memif_size; i++) {
+		afe->memif[i].data = &memif_data[i];
+		afe->memif[i].irq_usage = -1;
+	}
+
+	mutex_init(&afe->irq_alloc_lock);
+
+	/* irq initialize */
+	afe->irqs_size = MT79XX_IRQ_NUM;
+	afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
+				 GFP_KERNEL);
+	if (!afe->irqs)
+		goto err_pm_disable;
+
+	for (i = 0; i < afe->irqs_size; i++)
+		afe->irqs[i].irq_data = &irq_data[i];
+
+	/* request irq */
+	irq_id = platform_get_irq(pdev, 0);
+	if (!irq_id) {
+		dev_err(dev, "%pOFn no irq found\n", dev->of_node);
+		goto err_pm_disable;
+	}
+	ret = devm_request_irq(dev, irq_id, mt79xx_afe_irq_handler,
+			       IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
+	if (ret) {
+		dev_err(dev, "could not request_irq for asys-isr\n");
+		goto err_pm_disable;
+	}
+
+	/* init sub_dais */
+	INIT_LIST_HEAD(&afe->sub_dais);
+
+	for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
+		ret = dai_register_cbs[i](afe);
+		if (ret) {
+			dev_warn(afe->dev, "dai register i %d fail, ret %d\n",
+				 i, ret);
+			goto err_pm_disable;
+		}
+	}
+
+	/* init dai_driver and component_driver */
+	ret = mtk_afe_combine_sub_dai(afe);
+	if (ret) {
+		dev_warn(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n",
+			 ret);
+		goto err_pm_disable;
+	}
+
+	afe->mtk_afe_hardware = &mt79xx_afe_hardware;
+	afe->memif_fs = mt79xx_memif_fs;
+	afe->irq_fs = mt79xx_irq_fs;
+
+	afe->runtime_resume = mt79xx_afe_runtime_resume;
+	afe->runtime_suspend = mt79xx_afe_runtime_suspend;
+
+	/* register component */
+	ret = devm_snd_soc_register_component(&pdev->dev,
+					      &mt79xx_afe_component,
+					      NULL, 0);
+	if (ret) {
+		dev_warn(dev, "err_platform\n");
+		goto err_pm_disable;
+	}
+
+	ret = devm_snd_soc_register_component(afe->dev,
+					      &mt79xx_afe_pcm_dai_component,
+					      afe->dai_drivers,
+					      afe->num_dai_drivers);
+	if (ret) {
+		dev_warn(dev, "err_dai_component\n");
+		goto err_pm_disable;
+	}
+
+	return ret;
+
+err_pm_disable:
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	return ret;
+}
+
+static int mt79xx_afe_pcm_dev_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		mt79xx_afe_runtime_suspend(&pdev->dev);
+
+	return 0;
+}
+
+static const struct of_device_id mt79xx_afe_pcm_dt_match[] = {
+	{ .compatible = "mediatek,mt79xx-audio", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mt79xx_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mt79xx_afe_pm_ops = {
+	SET_RUNTIME_PM_OPS(mt79xx_afe_runtime_suspend,
+			   mt79xx_afe_runtime_resume, NULL)
+};
+
+static struct platform_driver mt79xx_afe_pcm_driver = {
+	.driver = {
+		   .name = "mt79xx-audio",
+		   .of_match_table = mt79xx_afe_pcm_dt_match,
+		   .pm = &mt79xx_afe_pm_ops,
+	},
+	.probe = mt79xx_afe_pcm_dev_probe,
+	.remove = mt79xx_afe_pcm_dev_remove,
+};
+
+module_platform_driver(mt79xx_afe_pcm_driver);
+
+MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 79xx");
+MODULE_AUTHOR("Vic Wu <vic.wu@mediatek.com>");
+MODULE_LICENSE("GPL");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-dai-etdm.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-dai-etdm.c
new file mode 100644
index 0000000..0048647
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-dai-etdm.c
@@ -0,0 +1,419 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI eTDM Control
+//
+// Copyright (c) 2021 MediaTek Inc.
+// Author: Vic Wu <vic.wu@mediatek.com>
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt79xx-afe-clk.h"
+#include "mt79xx-afe-common.h"
+#include "mt79xx-reg.h"
+
+enum {
+	HOPPING_CLK = 0,
+	APLL_CLK = 1,
+};
+
+enum {
+	MTK_DAI_ETDM_FORMAT_I2S = 0,
+	MTK_DAI_ETDM_FORMAT_DSPA = 4,
+	MTK_DAI_ETDM_FORMAT_DSPB = 5,
+};
+
+enum {
+	ETDM_IN5 = 2,
+	ETDM_OUT5 = 10,
+};
+
+enum {
+	MTK_ETDM_RATE_8K = 0,
+	MTK_ETDM_RATE_12K = 1,
+	MTK_ETDM_RATE_16K = 2,
+	MTK_ETDM_RATE_24K = 3,
+	MTK_ETDM_RATE_32K = 4,
+	MTK_ETDM_RATE_48K = 5,
+	MTK_ETDM_RATE_96K = 7,
+	MTK_ETDM_RATE_192K = 9,
+	MTK_ETDM_RATE_11K = 16,
+	MTK_ETDM_RATE_22K = 17,
+	MTK_ETDM_RATE_44K = 18,
+	MTK_ETDM_RATE_88K = 19,
+	MTK_ETDM_RATE_176K = 20,
+};
+
+struct mtk_dai_etdm_priv {
+	bool bck_inv;
+	bool lrck_inv;
+	bool slave_mode;
+	unsigned int format;
+};
+
+static unsigned int mt79xx_etdm_rate_transform(struct device *dev,
+					unsigned int rate)
+{
+	switch (rate) {
+	case 8000:
+		return MTK_ETDM_RATE_8K;
+	case 11025:
+		return MTK_ETDM_RATE_11K;
+	case 12000:
+		return MTK_ETDM_RATE_12K;
+	case 16000:
+		return MTK_ETDM_RATE_16K;
+	case 22050:
+		return MTK_ETDM_RATE_22K;
+	case 24000:
+		return MTK_ETDM_RATE_24K;
+	case 32000:
+		return MTK_ETDM_RATE_32K;
+	case 44100:
+		return MTK_ETDM_RATE_44K;
+	case 48000:
+		return MTK_ETDM_RATE_48K;
+	case 88200:
+		return MTK_ETDM_RATE_88K;
+	case 96000:
+		return MTK_ETDM_RATE_96K;
+	case 176400:
+		return MTK_ETDM_RATE_176K;
+	case 192000:
+		return MTK_ETDM_RATE_192K;
+	default:
+		dev_warn(dev, "%s(), rate %u invalid, use %d!!!\n",
+			 __func__, rate, MTK_ETDM_RATE_48K);
+		return MTK_ETDM_RATE_48K;
+	}
+}
+
+static int get_etdm_wlen(unsigned int bitwidth)
+{
+	return bitwidth <= 16 ? 16 : 32;
+}
+
+/* dai component */
+/* interconnection */
+
+static const struct snd_kcontrol_new o124_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I032_Switch", AFE_CONN124_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new o125_mix[] = {
+	SOC_DAPM_SINGLE_AUTODISABLE("I033_Switch", AFE_CONN125_1, 1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mtk_dai_etdm_widgets[] = {
+
+	/* DL */
+	SND_SOC_DAPM_MIXER("I150", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("I151", SND_SOC_NOPM, 0, 0, NULL, 0),
+	/* UL */
+	SND_SOC_DAPM_MIXER("O124", SND_SOC_NOPM, 0, 0,
+			   o124_mix, ARRAY_SIZE(o124_mix)),
+	SND_SOC_DAPM_MIXER("O125", SND_SOC_NOPM, 0, 0,
+			   o125_mix, ARRAY_SIZE(o125_mix)),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_etdm_routes[] = {
+	{"I150", NULL, "ETDM Capture"},
+	{"I151", NULL, "ETDM Capture"},
+	{"ETDM Playback", NULL, "O124"},
+	{"ETDM Playback", NULL, "O125"},
+	{"O124", "I032_Switch", "I032"},
+	{"O125", "I033_Switch", "I033"},
+};
+
+/* dai ops */
+static int mtk_dai_etdm_startup(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+	mt79xx_afe_enable_clock(afe);
+
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK,
+			   0);
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK,
+			   0);
+
+	return 0;
+}
+
+static void mtk_dai_etdm_shutdown(struct snd_pcm_substream *substream,
+				  struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK,
+			   CLK_OUT5_PDN);
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK,
+			   CLK_IN5_PDN);
+
+	mt79xx_afe_disable_clock(afe);
+}
+
+static unsigned int get_etdm_ch_fixup(unsigned int channels)
+{
+	if (channels > 16)
+		return 24;
+	else if (channels > 8)
+		return 16;
+	else if (channels > 4)
+		return 8;
+	else if (channels > 2)
+		return 4;
+	else
+		return 2;
+}
+
+static int mtk_dai_etdm_config(struct mtk_base_afe *afe,
+			       struct snd_pcm_hw_params *params,
+			       struct snd_soc_dai *dai,
+			       int stream)
+{
+	struct mt79xx_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id];
+	unsigned int rate = params_rate(params);
+	unsigned int etdm_rate = mt79xx_etdm_rate_transform(afe->dev, rate);
+	unsigned int afe_rate = mt79xx_afe_rate_transform(afe->dev, rate);
+	unsigned int channels = params_channels(params);
+	unsigned int bit_width = params_width(params);
+	unsigned int wlen = get_etdm_wlen(bit_width);
+	unsigned int val = 0;
+	unsigned int mask = 0;
+
+	dev_dbg(afe->dev, "%s(), stream %d, rate %u, bitwidth %u\n",
+		 __func__, stream, rate, bit_width);
+
+	/* CON0 */
+	mask |= ETDM_BIT_LEN_MASK;
+	val |= ETDM_BIT_LEN(bit_width);
+	mask |= ETDM_WRD_LEN_MASK;
+	val |= ETDM_WRD_LEN(wlen);
+	mask |= ETDM_FMT_MASK;
+	val |= ETDM_FMT(etdm_data->format);
+	mask |= ETDM_CH_NUM_MASK;
+	val |= ETDM_CH_NUM(get_etdm_ch_fixup(channels));
+	mask |= RELATCH_SRC_MASK;
+	val |= RELATCH_SRC(APLL_CLK);
+
+	switch (stream) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		/* set ETDM_OUT5_CON0 */
+		regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, mask, val);
+
+		/* set ETDM_OUT5_CON4 */
+		regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,
+				   OUT_RELATCH_MASK, OUT_RELATCH(afe_rate));
+		regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,
+				   OUT_CLK_SRC_MASK, OUT_CLK_SRC(APLL_CLK));
+		regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,
+				   OUT_SEL_FS_MASK, OUT_SEL_FS(etdm_rate));
+
+		/* set ETDM_OUT5_CON5 */
+		regmap_update_bits(afe->regmap, ETDM_OUT5_CON5,
+				   ETDM_CLK_DIV_MASK, ETDM_CLK_DIV);
+		break;
+	case SNDRV_PCM_STREAM_CAPTURE:
+		/* set ETDM_IN5_CON0 */
+		regmap_update_bits(afe->regmap, ETDM_IN5_CON0, mask, val);
+		regmap_update_bits(afe->regmap, ETDM_IN5_CON0,
+				   ETDM_SYNC_MASK, ETDM_SYNC);
+
+		/* set ETDM_IN5_CON2 */
+		regmap_update_bits(afe->regmap, ETDM_IN5_CON2,
+				   IN_CLK_SRC_MASK, IN_CLK_SRC(APLL_CLK));
+
+		/* set ETDM_IN5_CON3 */
+		regmap_update_bits(afe->regmap, ETDM_IN5_CON3,
+				   IN_SEL_FS_MASK, IN_SEL_FS(etdm_rate));
+
+		/* set ETDM_IN5_CON4 */
+		regmap_update_bits(afe->regmap, ETDM_IN5_CON4,
+				   IN_RELATCH_MASK, IN_RELATCH(afe_rate));
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mtk_dai_etdm_hw_params(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params,
+				  struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+	mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_PLAYBACK);
+	mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_CAPTURE);
+
+	return 0;
+}
+
+static int mtk_dai_etdm_trigger(struct snd_pcm_substream *substream, int cmd,
+				struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+	dev_dbg(afe->dev, "%s(), cmd %d, dai id %d\n", __func__, cmd, dai->id);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK,
+				   ETDM_EN);
+		regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK,
+				   ETDM_EN);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK,
+				   0);
+		regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK,
+				   0);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+	struct mt79xx_afe_private *afe_priv = afe->platform_priv;
+	struct mtk_dai_etdm_priv *etdm_data;
+	void *priv_data;
+
+	switch (dai->id) {
+	case MT79XX_DAI_ETDM:
+		break;
+	default:
+		dev_warn(afe->dev, "%s(), id %d not support\n",
+			 __func__, dai->id);
+		return -EINVAL;
+	}
+
+	priv_data = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_etdm_priv),
+				 GFP_KERNEL);
+	if (!priv_data)
+		return -ENOMEM;
+
+	afe_priv->dai_priv[dai->id] = priv_data;
+	etdm_data = afe_priv->dai_priv[dai->id];
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		etdm_data->format = MTK_DAI_ETDM_FORMAT_I2S;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPA;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPB;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		etdm_data->bck_inv = false;
+		etdm_data->lrck_inv = false;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		etdm_data->bck_inv = false;
+		etdm_data->lrck_inv = true;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		etdm_data->bck_inv = true;
+		etdm_data->lrck_inv = false;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		etdm_data->bck_inv = true;
+		etdm_data->lrck_inv = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		etdm_data->slave_mode = true;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		etdm_data->slave_mode = false;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_etdm_ops = {
+	.startup = mtk_dai_etdm_startup,
+	.shutdown = mtk_dai_etdm_shutdown,
+	.hw_params = mtk_dai_etdm_hw_params,
+	.trigger = mtk_dai_etdm_trigger,
+	.set_fmt = mtk_dai_etdm_set_fmt,
+};
+
+/* dai driver */
+#define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_48000 |\
+			SNDRV_PCM_RATE_88200 |\
+			SNDRV_PCM_RATE_96000 |\
+			SNDRV_PCM_RATE_176400 |\
+			SNDRV_PCM_RATE_192000)
+
+#define MTK_ETDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+			  SNDRV_PCM_FMTBIT_S24_LE |\
+			  SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
+	{
+		.name = "ETDM",
+		.id = MT79XX_DAI_ETDM,
+		.capture = {
+			.stream_name = "ETDM Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_ETDM_RATES,
+			.formats = MTK_ETDM_FORMATS,
+		},
+		.playback = {
+			.stream_name = "ETDM Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = MTK_ETDM_RATES,
+			.formats = MTK_ETDM_FORMATS,
+		},
+		.ops = &mtk_dai_etdm_ops,
+		.symmetric_rates = 1,
+		.symmetric_samplebits = 1,
+	},
+};
+
+int mt79xx_dai_etdm_register(struct mtk_base_afe *afe)
+{
+	struct mtk_base_afe_dai *dai;
+
+	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+	if (!dai)
+		return -ENOMEM;
+
+	list_add(&dai->list, &afe->sub_dais);
+
+	dai->dai_drivers = mtk_dai_etdm_driver;
+	dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_etdm_driver);
+
+	dai->dapm_widgets = mtk_dai_etdm_widgets;
+	dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_etdm_widgets);
+	dai->dapm_routes = mtk_dai_etdm_routes;
+	dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_etdm_routes);
+
+	return 0;
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-reg.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-reg.h
new file mode 100644
index 0000000..b8d2d56
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-reg.h
@@ -0,0 +1,205 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt79xx-reg.h  --  Mediatek 79xx audio driver reg definition
+ *
+ * Copyright (c) 2021 MediaTek Inc.
+ * Author: Vic Wu <vic.wu@mediatek.com>
+ */
+
+#ifndef _MT79XX_REG_H_
+#define _MT79XX_REG_H_
+
+#define AUDIO_TOP_CON2                  0x0008
+#define AUDIO_TOP_CON4                  0x0010
+#define AUDIO_ENGEN_CON0                0x0014
+#define AFE_IRQ_MCU_EN                  0x0100
+#define AFE_IRQ_MCU_STATUS              0x0120
+#define AFE_IRQ_MCU_CLR                 0x0128
+#define AFE_IRQ0_MCU_CFG0               0x0140
+#define AFE_IRQ0_MCU_CFG1               0x0144
+#define AFE_IRQ1_MCU_CFG0               0x0148
+#define AFE_IRQ1_MCU_CFG1               0x014c
+#define AFE_IRQ2_MCU_CFG0               0x0150
+#define AFE_IRQ2_MCU_CFG1               0x0154
+#define ETDM_IN5_CON0                   0x13f0
+#define ETDM_IN5_CON1                   0x13f4
+#define ETDM_IN5_CON2                   0x13f8
+#define ETDM_IN5_CON3                   0x13fc
+#define ETDM_IN5_CON4                   0x1400
+#define ETDM_OUT5_CON0                  0x1570
+#define ETDM_OUT5_CON4                  0x1580
+#define ETDM_OUT5_CON5                  0x1584
+#define ETDM_4_7_COWORK_CON0            0x15e0
+#define ETDM_4_7_COWORK_CON1            0x15e4
+#define AFE_CONN018_1                   0x1b44
+#define AFE_CONN018_4                   0x1b50
+#define AFE_CONN019_1                   0x1b64
+#define AFE_CONN019_4                   0x1b70
+#define AFE_CONN124_1                   0x2884
+#define AFE_CONN124_4                   0x2890
+#define AFE_CONN125_1                   0x28a4
+#define AFE_CONN125_4                   0x28b0
+#define AFE_CONN_RS_0                   0x3920
+#define AFE_CONN_RS_3                   0x392c
+#define AFE_CONN_16BIT_0                0x3960
+#define AFE_CONN_16BIT_3                0x396c
+#define AFE_CONN_24BIT_0                0x3980
+#define AFE_CONN_24BIT_3                0x398c
+#define AFE_MEMIF_CON0                  0x3d98
+#define AFE_MEMIF_RD_MON                0x3da0
+#define AFE_MEMIF_WR_MON                0x3da4
+#define AFE_DL0_BASE_MSB                0x3e40
+#define AFE_DL0_BASE                    0x3e44
+#define AFE_DL0_CUR_MSB                 0x3e48
+#define AFE_DL0_CUR                     0x3e4c
+#define AFE_DL0_END_MSB                 0x3e50
+#define AFE_DL0_END                     0x3e54
+#define AFE_DL0_RCH_MON                 0x3e58
+#define AFE_DL0_LCH_MON                 0x3e5c
+#define AFE_DL0_CON0                    0x3e60
+#define AFE_VUL0_BASE_MSB               0x4220
+#define AFE_VUL0_BASE                   0x4224
+#define AFE_VUL0_CUR_MSB                0x4228
+#define AFE_VUL0_CUR                    0x422c
+#define AFE_VUL0_END_MSB                0x4230
+#define AFE_VUL0_END                    0x4234
+#define AFE_VUL0_CON0                   0x4238
+
+#define AFE_MAX_REGISTER AFE_VUL0_CON0
+#define AFE_IRQ_STATUS_BITS             0x7
+#define AFE_IRQ_CNT_SHIFT               0
+#define AFE_IRQ_CNT_MASK	        0xffffff
+
+/* AUDIO_TOP_CON2 */
+#define CLK_OUT5_PDN                    BIT(14)
+#define CLK_OUT5_PDN_MASK               BIT(14)
+#define CLK_IN5_PDN                     BIT(7)
+#define CLK_IN5_PDN_MASK                BIT(7)
+
+/* AUDIO_TOP_CON4 */
+#define PDN_APLL_TUNER2                 BIT(12)
+#define PDN_APLL_TUNER2_MASK            BIT(12)
+
+/* AUDIO_ENGEN_CON0 */
+#define AUD_APLL2_EN                    BIT(3)
+#define AUD_APLL2_EN_MASK               BIT(3)
+#define AUD_26M_EN                      BIT(0)
+#define AUD_26M_EN_MASK                 BIT(0)
+
+/* AFE_DL0_CON0 */
+#define DL0_ON_SFT                      28
+#define DL0_ON_MASK                     0x1
+#define DL0_ON_MASK_SFT                 BIT(28)
+#define DL0_MINLEN_SFT                  20
+#define DL0_MINLEN_MASK                 0xf
+#define DL0_MINLEN_MASK_SFT             (0xf << 20)
+#define DL0_MODE_SFT                    8
+#define DL0_MODE_MASK                   0x1f
+#define DL0_MODE_MASK_SFT               (0x1f << 8)
+#define DL0_PBUF_SIZE_SFT               5
+#define DL0_PBUF_SIZE_MASK              0x3
+#define DL0_PBUF_SIZE_MASK_SFT          (0x3 << 5)
+#define DL0_MONO_SFT                    4
+#define DL0_MONO_MASK                   0x1
+#define DL0_MONO_MASK_SFT               BIT(4)
+#define DL0_HALIGN_SFT                  2
+#define DL0_HALIGN_MASK                 0x1
+#define DL0_HALIGN_MASK_SFT             BIT(2)
+#define DL0_HD_MODE_SFT                 0
+#define DL0_HD_MODE_MASK                0x3
+#define DL0_HD_MODE_MASK_SFT            (0x3 << 0)
+
+/* AFE_VUL0_CON0 */
+#define VUL0_ON_SFT                     28
+#define VUL0_ON_MASK                    0x1
+#define VUL0_ON_MASK_SFT                BIT(28)
+#define VUL0_MODE_SFT                   8
+#define VUL0_MODE_MASK                  0x1f
+#define VUL0_MODE_MASK_SFT              (0x1f << 8)
+#define VUL0_MONO_SFT                   4
+#define VUL0_MONO_MASK                  0x1
+#define VUL0_MONO_MASK_SFT              BIT(4)
+#define VUL0_HALIGN_SFT                 2
+#define VUL0_HALIGN_MASK                0x1
+#define VUL0_HALIGN_MASK_SFT            BIT(2)
+#define VUL0_HD_MODE_SFT                0
+#define VUL0_HD_MODE_MASK               0x3
+#define VUL0_HD_MODE_MASK_SFT           (0x3 << 0)
+
+/* AFE_IRQ_MCU_CON */
+#define IRQ_MCU_MODE_SFT                4
+#define IRQ_MCU_MODE_MASK               0x1f
+#define IRQ_MCU_MODE_MASK_SFT           (0x1f << 4)
+#define IRQ_MCU_ON_SFT                  0
+#define IRQ_MCU_ON_MASK                 0x1
+#define IRQ_MCU_ON_MASK_SFT             BIT(0)
+#define IRQ0_MCU_CLR_SFT                0
+#define IRQ0_MCU_CLR_MASK               0x1
+#define IRQ0_MCU_CLR_MASK_SFT           BIT(0)
+#define IRQ1_MCU_CLR_SFT                1
+#define IRQ1_MCU_CLR_MASK               0x1
+#define IRQ1_MCU_CLR_MASK_SFT           BIT(1)
+#define IRQ2_MCU_CLR_SFT                2
+#define IRQ2_MCU_CLR_MASK               0x1
+#define IRQ2_MCU_CLR_MASK_SFT           BIT(2)
+
+/* ETDM_IN5_CON2 */
+#define IN_CLK_SRC(x)                   ((x) << 10)
+#define IN_CLK_SRC_SFT                  10
+#define IN_CLK_SRC_MASK                 GENMASK(12, 10)
+
+/* ETDM_IN5_CON3 */
+#define IN_SEL_FS(x)                    ((x) << 26)
+#define IN_SEL_FS_SFT                   26
+#define IN_SEL_FS_MASK                  GENMASK(30, 26)
+
+/* ETDM_IN5_CON4 */
+#define IN_RELATCH(x)                   ((x) << 20)
+#define IN_RELATCH_SFT                  20
+#define IN_RELATCH_MASK                 GENMASK(24, 20)
+#define IN_CLK_INV                      BIT(18)
+#define IN_CLK_INV_MASK                 BIT(18)
+
+/* ETDM_IN5_CON0 & ETDM_OUT5_CON0 */
+#define RELATCH_SRC(x)                  ((x) << 28)
+#define RELATCH_SRC_SFT                 28
+#define RELATCH_SRC_MASK                GENMASK(30, 28)
+#define ETDM_CH_NUM(x)                  (((x) - 1) << 23)
+#define ETDM_CH_NUM_SFT                 23
+#define ETDM_CH_NUM_MASK                GENMASK(27, 23)
+#define ETDM_WRD_LEN(x)                 (((x) - 1) << 16)
+#define ETDM_WRD_LEN_SFT                16
+#define ETDM_WRD_LEN_MASK               GENMASK(20, 16)
+#define ETDM_BIT_LEN(x)                 (((x) - 1) << 11)
+#define ETDM_BIT_LEN_SFT                11
+#define ETDM_BIT_LEN_MASK               GENMASK(15, 11)
+#define ETDM_FMT(x)                     ((x) << 6)
+#define ETDM_FMT_SFT                    6
+#define ETDM_FMT_MASK                   GENMASK(8, 6)
+#define ETDM_SYNC                       BIT(1)
+#define ETDM_SYNC_MASK                  BIT(1)
+#define ETDM_EN                         BIT(0)
+#define ETDM_EN_MASK                    BIT(0)
+
+/* ETDM_OUT5_CON4 */
+#define OUT_RELATCH(x)                  ((x) << 24)
+#define OUT_RELATCH_SFT                 24
+#define OUT_RELATCH_MASK                GENMASK(28, 24)
+#define OUT_CLK_SRC(x)                  ((x) << 6)
+#define OUT_CLK_SRC_SFT                 6
+#define OUT_CLK_SRC_MASK                GENMASK(8, 6)
+#define OUT_SEL_FS(x)                   ((x) << 0)
+#define OUT_SEL_FS_SFT                  0
+#define OUT_SEL_FS_MASK                 GENMASK(4, 0)
+
+/* ETDM_OUT5_CON5 */
+#define ETDM_CLK_DIV                    BIT(12)
+#define ETDM_CLK_DIV_MASK               BIT(12)
+#define OUT_CLK_INV                     BIT(9)
+#define OUT_CLK_INV_MASK                BIT(9)
+
+/* ETDM_4_7_COWORK_CON0 */
+#define OUT_SEL(x)                      ((x) << 12)
+#define OUT_SEL_SFT                     12
+#define OUT_SEL_MASK                    GENMASK(15, 12)
+#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-si3218x.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-si3218x.c
new file mode 100644
index 0000000..6a45595
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-si3218x.c
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt79xx-si3218x.c  --  MT79xx WM8960 ALSA SoC machine driver
+ *
+ * Copyright (c) 2021 MediaTek Inc.
+ * Author: Vic Wu <vic.wu@mediatek.com>
+ */
+
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#include "mt79xx-afe-clk.h"
+#include "mt79xx-afe-common.h"
+#include "mt79xx-reg.h"
+#include "../common/mtk-afe-platform-driver.h"
+
+enum {
+	HOPPING_CLK = 0,
+	APLL_CLK = 1,
+};
+
+enum {
+	I2S = 0,
+	PCMA = 4,
+	PCMB,
+};
+
+enum {
+	ETDM_IN5 = 2,
+	ETDM_OUT5 = 10,
+};
+
+enum {
+	AFE_FS_8K = 0,
+	AFE_FS_11K = 1,
+	AFE_FS_12K = 2,
+	AFE_FS_16K = 4,
+	AFE_FS_22K = 5,
+	AFE_FS_24K = 6,
+	AFE_FS_32K = 8,
+	AFE_FS_44K = 9,
+	AFE_FS_48K = 10,
+	AFE_FS_88K = 13,
+	AFE_FS_96K = 14,
+	AFE_FS_176K = 17,
+	AFE_FS_192K = 18,
+};
+
+enum {
+	ETDM_FS_8K = 0,
+	ETDM_FS_12K = 1,
+	ETDM_FS_16K = 2,
+	ETDM_FS_24K = 3,
+	ETDM_FS_32K = 4,
+	ETDM_FS_48K = 5,
+	ETDM_FS_96K = 7,
+	ETDM_FS_192K = 9,
+	ETDM_FS_11K = 16,
+	ETDM_FS_22K = 17,
+	ETDM_FS_44K = 18,
+	ETDM_FS_88K = 19,
+	ETDM_FS_176K = 20,
+};
+
+struct mt79xx_si3218x_priv {
+	struct device_node *platform_node;
+	struct device_node *codec_node;
+};
+
+static int mt79xx_si3218x_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_component *component =
+		snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+
+	/* enable clk */
+	mt79xx_afe_enable_clock(afe);
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK,
+			   0);
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK,
+			   0);
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0);
+	regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK,
+			   AUD_APLL2_EN);
+	regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK,
+			   AUD_26M_EN);
+
+	/* set ETDM_IN5_CON0 */
+	regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_SYNC_MASK,
+			   ETDM_SYNC);
+	regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_FMT_MASK,
+			   ETDM_FMT(PCMA));
+	regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_BIT_LEN_MASK,
+			   ETDM_BIT_LEN(16));
+	regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_WRD_LEN_MASK,
+			   ETDM_WRD_LEN(16));
+	regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_CH_NUM_MASK,
+			   ETDM_CH_NUM(4));
+	regmap_update_bits(afe->regmap, ETDM_IN5_CON0, RELATCH_SRC_MASK,
+			   RELATCH_SRC(APLL_CLK));
+
+	/* set ETDM_IN5_CON2 */
+	regmap_update_bits(afe->regmap, ETDM_IN5_CON2, IN_CLK_SRC_MASK,
+			   IN_CLK_SRC(APLL_CLK));
+
+	/* set ETDM_IN5_CON3 */
+	regmap_update_bits(afe->regmap, ETDM_IN5_CON3, IN_SEL_FS_MASK,
+			   IN_SEL_FS(ETDM_FS_16K));
+
+	/* set ETDM_IN5_CON4 */
+	regmap_update_bits(afe->regmap, ETDM_IN5_CON4, IN_CLK_INV_MASK,
+			   IN_CLK_INV);
+	regmap_update_bits(afe->regmap, ETDM_IN5_CON4, IN_RELATCH_MASK,
+			   IN_RELATCH(AFE_FS_16K));
+
+	/* set ETDM_OUT5_CON0 */
+	regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_FMT_MASK,
+			   ETDM_FMT(PCMA));
+	regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_BIT_LEN_MASK,
+			   ETDM_BIT_LEN(16));
+	regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_WRD_LEN_MASK,
+			   ETDM_WRD_LEN(16));
+	regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_CH_NUM_MASK,
+			   ETDM_CH_NUM(4));
+	regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, RELATCH_SRC_MASK,
+			   RELATCH_SRC(APLL_CLK));
+
+	/* set ETDM_OUT5_CON4 */
+	regmap_update_bits(afe->regmap, ETDM_OUT5_CON4, OUT_SEL_FS_MASK,
+			   OUT_SEL_FS(ETDM_FS_16K));
+	regmap_update_bits(afe->regmap, ETDM_OUT5_CON4, OUT_CLK_SRC_MASK,
+			   OUT_CLK_SRC(APLL_CLK));
+	regmap_update_bits(afe->regmap, ETDM_OUT5_CON4, OUT_RELATCH_MASK,
+			   OUT_RELATCH(AFE_FS_16K));
+
+	/* set ETDM_OUT5_CON5 */
+	regmap_update_bits(afe->regmap, ETDM_OUT5_CON5, OUT_CLK_INV_MASK,
+			   OUT_CLK_INV);
+	regmap_update_bits(afe->regmap, ETDM_OUT5_CON5, ETDM_CLK_DIV_MASK,
+			   ETDM_CLK_DIV);
+
+	/* set external loopback */
+	regmap_update_bits(afe->regmap, ETDM_4_7_COWORK_CON0, OUT_SEL_MASK,
+			   OUT_SEL(ETDM_IN5));
+
+	/* enable ETDM */
+	regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK,
+			   ETDM_EN);
+	regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK,
+			   ETDM_EN);
+
+	return 0;
+}
+
+SND_SOC_DAILINK_DEFS(playback,
+	DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
+	DAILINK_COMP_ARRAY(COMP_DUMMY()),
+	DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture,
+	DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
+	DAILINK_COMP_ARRAY(COMP_DUMMY()),
+	DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(codec,
+	DAILINK_COMP_ARRAY(COMP_CPU("ETDM")),
+	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "proslic_spi-aif")),
+	DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static struct snd_soc_dai_link mt79xx_si3218x_dai_links[] = {
+	/* FE */
+	{
+		.name = "si3218x-playback",
+		.stream_name = "si3218x-playback",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		SND_SOC_DAILINK_REG(playback),
+	},
+	{
+		.name = "si3218x-capture",
+		.stream_name = "si3218x-capture",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(capture),
+	},
+	/* BE */
+	{
+		.name = "si3218x-codec",
+		.no_pcm = 1,
+		.dai_fmt = SND_SOC_DAIFMT_DSP_A |
+			SND_SOC_DAIFMT_IB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+		.init = mt79xx_si3218x_init,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(codec),
+	},
+};
+
+static struct snd_soc_card mt79xx_si3218x_card = {
+	.name = "mt79xx-si3218x",
+	.owner = THIS_MODULE,
+	.dai_link = mt79xx_si3218x_dai_links,
+	.num_links = ARRAY_SIZE(mt79xx_si3218x_dai_links),
+};
+
+static int mt79xx_si3218x_machine_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &mt79xx_si3218x_card;
+	struct snd_soc_dai_link *dai_link;
+	struct mt79xx_si3218x_priv *priv;
+	int ret, i;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->platform_node = of_parse_phandle(pdev->dev.of_node,
+					       "mediatek,platform", 0);
+	if (!priv->platform_node) {
+		dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+		return -EINVAL;
+	}
+
+	for_each_card_prelinks(card, i, dai_link) {
+		if (dai_link->platforms->name)
+			continue;
+		dai_link->platforms->of_node = priv->platform_node;
+	}
+
+	card->dev = &pdev->dev;
+
+	priv->codec_node = of_parse_phandle(pdev->dev.of_node,
+					    "mediatek,ext-codec", 0);
+	if (!priv->codec_node) {
+		dev_err(&pdev->dev,
+			"Property 'audio-codec' missing or invalid\n");
+		of_node_put(priv->platform_node);
+		return -EINVAL;
+	}
+
+	for_each_card_prelinks(card, i, dai_link) {
+		if (dai_link->codecs->name)
+			continue;
+		dai_link->codecs->of_node = priv->codec_node;
+	}
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret) {
+		dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+			__func__, ret);
+		of_node_put(priv->codec_node);
+		of_node_put(priv->platform_node);
+	}
+
+	return ret;
+}
+
+static int mt79xx_si3218x_machine_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct mt79xx_si3218x_priv *priv = snd_soc_card_get_drvdata(card);
+
+	of_node_put(priv->codec_node);
+	of_node_put(priv->platform_node);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mt79xx_si3218x_machine_dt_match[] = {
+	{.compatible = "mediatek,mt79xx-si3218x-machine",},
+	{}
+};
+#endif
+
+static struct platform_driver mt79xx_si3218x_machine = {
+	.driver = {
+		.name = "mt79xx-si3218x",
+#ifdef CONFIG_OF
+		.of_match_table = mt79xx_si3218x_machine_dt_match,
+#endif
+	},
+	.probe = mt79xx_si3218x_machine_probe,
+	.remove = mt79xx_si3218x_machine_remove,
+};
+
+module_platform_driver(mt79xx_si3218x_machine);
+
+/* Module information */
+MODULE_DESCRIPTION("MT79xx SI3218x ALSA SoC machine driver");
+MODULE_AUTHOR("Vic Wu <vic.wu@mediatek.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("mt79xx si3218x soc card");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-wm8960.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-wm8960.c
new file mode 100644
index 0000000..c66a117
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-wm8960.c
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt79xx-wm8960.c  --  MT79xx WM8960 ALSA SoC machine driver
+ *
+ * Copyright (c) 2021 MediaTek Inc.
+ * Author: Vic Wu <vic.wu@mediatek.com>
+ */
+
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#include "mt79xx-afe-common.h"
+
+struct mt79xx_wm8960_priv {
+	struct device_node *platform_node;
+	struct device_node *codec_node;
+};
+
+static const struct snd_soc_dapm_widget mt79xx_wm8960_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone", NULL),
+	SND_SOC_DAPM_MIC("AMIC", NULL),
+};
+
+static const struct snd_kcontrol_new mt79xx_wm8960_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphone"),
+	SOC_DAPM_PIN_SWITCH("AMIC"),
+};
+
+SND_SOC_DAILINK_DEFS(playback,
+	DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
+	DAILINK_COMP_ARRAY(COMP_DUMMY()),
+	DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture,
+	DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
+	DAILINK_COMP_ARRAY(COMP_DUMMY()),
+	DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(codec,
+	DAILINK_COMP_ARRAY(COMP_CPU("ETDM")),
+	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8960-hifi")),
+	DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static struct snd_soc_dai_link mt79xx_wm8960_dai_links[] = {
+	/* FE */
+	{
+		.name = "wm8960-playback",
+		.stream_name = "wm8960-playback",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+		SND_SOC_DAILINK_REG(playback),
+	},
+	{
+		.name = "wm8960-capture",
+		.stream_name = "wm8960-capture",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(capture),
+	},
+	/* BE */
+	{
+		.name = "wm8960-codec",
+		.no_pcm = 1,
+		.dai_fmt = SND_SOC_DAIFMT_I2S |
+			SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS |
+			SND_SOC_DAIFMT_GATED,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+		SND_SOC_DAILINK_REG(codec),
+	},
+};
+
+static struct snd_soc_card mt79xx_wm8960_card = {
+	.name = "mt79xx-wm8960",
+	.owner = THIS_MODULE,
+	.dai_link = mt79xx_wm8960_dai_links,
+	.num_links = ARRAY_SIZE(mt79xx_wm8960_dai_links),
+	.controls = mt79xx_wm8960_controls,
+	.num_controls = ARRAY_SIZE(mt79xx_wm8960_controls),
+	.dapm_widgets = mt79xx_wm8960_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(mt79xx_wm8960_widgets),
+};
+
+static int mt79xx_wm8960_machine_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &mt79xx_wm8960_card;
+	struct snd_soc_dai_link *dai_link;
+	struct mt79xx_wm8960_priv *priv;
+	int ret, i;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->platform_node = of_parse_phandle(pdev->dev.of_node,
+					       "mediatek,platform", 0);
+	if (!priv->platform_node) {
+		dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+		return -EINVAL;
+	}
+
+	for_each_card_prelinks(card, i, dai_link) {
+		if (dai_link->platforms->name)
+			continue;
+		dai_link->platforms->of_node = priv->platform_node;
+	}
+
+	card->dev = &pdev->dev;
+
+	priv->codec_node = of_parse_phandle(pdev->dev.of_node,
+					    "mediatek,audio-codec", 0);
+	if (!priv->codec_node) {
+		dev_err(&pdev->dev,
+			"Property 'audio-codec' missing or invalid\n");
+		of_node_put(priv->platform_node);
+		return -EINVAL;
+	}
+
+	for_each_card_prelinks(card, i, dai_link) {
+		if (dai_link->codecs->name)
+			continue;
+		dai_link->codecs->of_node = priv->codec_node;
+	}
+
+	ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
+	if (ret) {
+		dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret);
+		goto err_of_node_put;
+	}
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret) {
+		dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+			__func__, ret);
+		goto err_of_node_put;
+	}
+
+err_of_node_put:
+	of_node_put(priv->codec_node);
+	of_node_put(priv->platform_node);
+	return ret;
+}
+
+static int mt79xx_wm8960_machine_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct mt79xx_wm8960_priv *priv = snd_soc_card_get_drvdata(card);
+
+	of_node_put(priv->codec_node);
+	of_node_put(priv->platform_node);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mt79xx_wm8960_machine_dt_match[] = {
+	{.compatible = "mediatek,mt79xx-wm8960-machine",},
+	{}
+};
+#endif
+
+static struct platform_driver mt79xx_wm8960_machine = {
+	.driver = {
+		.name = "mt79xx-wm8960",
+#ifdef CONFIG_OF
+		.of_match_table = mt79xx_wm8960_machine_dt_match,
+#endif
+	},
+	.probe = mt79xx_wm8960_machine_probe,
+	.remove = mt79xx_wm8960_machine_remove,
+};
+
+module_platform_driver(mt79xx_wm8960_machine);
+
+/* Module information */
+MODULE_DESCRIPTION("MT79xx WM8960 ALSA SoC machine driver");
+MODULE_AUTHOR("Vic Wu <vic.wu@mediatek.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("mt79xx wm8960 soc card");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986-32bit.cfg b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986-32bit.cfg
new file mode 100644
index 0000000..a735f68
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986-32bit.cfg
@@ -0,0 +1,467 @@
+CONFIG_AHCI_MTK=y
+# CONFIG_AIROHA_EN8801S_PHY is not set
+CONFIG_ALIGNMENT_TRAP=y
+CONFIG_ARCH_32BIT_OFF_T=y
+CONFIG_ARCH_CLOCKSOURCE_DATA=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_KEEP_MEMBLOCK=y
+CONFIG_ARCH_MEDIATEK=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_MULTIPLATFORM=y
+CONFIG_ARCH_MULTI_V6_V7=y
+CONFIG_ARCH_MULTI_V7=y
+CONFIG_ARCH_NR_GPIO=0
+CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y
+CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARM=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
+CONFIG_ARM_CPU_SUSPEND=y
+CONFIG_ARM_GIC=y
+CONFIG_ARM_GIC_V3=y
+CONFIG_ARM_GIC_V3_ITS=y
+CONFIG_ARM_GIC_V3_ITS_PCI=y
+CONFIG_ARM_HAS_SG_CHAIN=y
+CONFIG_ARM_HEAVY_MB=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+CONFIG_ARM_L1_CACHE_SHIFT_6=y
+CONFIG_ARM_MEDIATEK_CPUFREQ=y
+CONFIG_ARM_PATCH_IDIV=y
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+CONFIG_ARM_PMU=y
+CONFIG_ARM_PSCI=y
+CONFIG_ARM_PSCI_FW=y
+CONFIG_ARM_THUMB=y
+CONFIG_ARM_UNWIND=y
+CONFIG_ARM_VIRT_EXT=y
+CONFIG_ATA=y
+CONFIG_AUTO_ZRELADDR=y
+CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_BLK_DEV_DM_BUILTIN=y
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_MQ_PCI=y
+CONFIG_BLK_PM=y
+CONFIG_BLK_SCSI_REQUEST=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_BT=y
+CONFIG_BT_BCM=y
+CONFIG_BT_BREDR=y
+CONFIG_BT_DEBUGFS=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_BCM=y
+# CONFIG_BT_HCIUART_INTEL is not set
+# CONFIG_BT_HCIUART_NOKIA is not set
+CONFIG_BT_HCIUART_QCA=y
+CONFIG_BT_HCIUART_SERDEV=y
+CONFIG_BT_HCIVHCI=y
+CONFIG_BT_HS=y
+CONFIG_BT_LE=y
+CONFIG_BT_MTKUART=y
+CONFIG_BT_QCA=y
+CONFIG_CACHE_L2X0=y
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_CLOCK_THERMAL=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_COMMON_CLK=y
+CONFIG_COMMON_CLK_MEDIATEK=y
+CONFIG_COMMON_CLK_MT2701=y
+# CONFIG_COMMON_CLK_MT2701_AUDSYS is not set
+# CONFIG_COMMON_CLK_MT2701_BDPSYS is not set
+# CONFIG_COMMON_CLK_MT2701_ETHSYS is not set
+# CONFIG_COMMON_CLK_MT2701_G3DSYS is not set
+# CONFIG_COMMON_CLK_MT2701_HIFSYS is not set
+# CONFIG_COMMON_CLK_MT2701_IMGSYS is not set
+# CONFIG_COMMON_CLK_MT2701_MMSYS is not set
+# CONFIG_COMMON_CLK_MT2701_VDECSYS is not set
+CONFIG_COMMON_CLK_MT7622=y
+# CONFIG_COMMON_CLK_MT7622_AUDSYS is not set
+# CONFIG_COMMON_CLK_MT7622_ETHSYS is not set
+# CONFIG_COMMON_CLK_MT7622_HIFSYS is not set
+CONFIG_COMMON_CLK_MT7629=y
+# CONFIG_COMMON_CLK_MT7629_ETHSYS is not set
+# CONFIG_COMMON_CLK_MT7629_HIFSYS is not set
+# CONFIG_COMMON_CLK_MT7981 is not set
+CONFIG_COMMON_CLK_MT7986=y
+CONFIG_COMMON_CLK_MT8135=y
+# CONFIG_COMMON_CLK_MT8173 is not set
+CONFIG_COMMON_CLK_MT8516=y
+# CONFIG_COMMON_CLK_MT8516_AUDSYS is not set
+CONFIG_COMPAT_32BIT_TIME=y
+CONFIG_CONSOLE_LOGLEVEL_DEFAULT=15
+# CONFIG_CPUFREQ_DT is not set
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+CONFIG_CPU_FREQ=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ATTR_SET=y
+CONFIG_CPU_FREQ_GOV_COMMON=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_RMAP=y
+CONFIG_CPU_SPECTRE=y
+CONFIG_CPU_THERMAL=y
+CONFIG_CPU_THUMB_CAPABLE=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_V7=y
+CONFIG_CRC16=y
+CONFIG_CRYPTO_ACOMP2=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_CMAC=y
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_DRBG=y
+CONFIG_CRYPTO_DRBG_HMAC=y
+CONFIG_CRYPTO_DRBG_MENU=y
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_ECC=y
+CONFIG_CRYPTO_ECDH=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_HASH_INFO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_JITTERENTROPY=y
+CONFIG_CRYPTO_KPP=y
+CONFIG_CRYPTO_KPP2=y
+CONFIG_CRYPTO_LIB_SHA256=y
+CONFIG_CRYPTO_LZO=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_NULL2=y
+CONFIG_CRYPTO_RNG=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_RNG_DEFAULT=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_DCACHE_WORD_ACCESS=y
+CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
+CONFIG_DEBUG_MISC=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_DMADEVICES=y
+CONFIG_DMATEST=y
+CONFIG_DMA_ENGINE=y
+CONFIG_DMA_ENGINE_RAID=y
+CONFIG_DMA_OF=y
+CONFIG_DMA_REMAP=y
+CONFIG_DMA_VIRTUAL_CHANNELS=y
+CONFIG_DM_BUFIO=y
+# CONFIG_DM_CRYPT is not set
+# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set
+CONFIG_DM_INIT=y
+# CONFIG_DM_MIRROR is not set
+# CONFIG_DM_SNAPSHOT is not set
+CONFIG_DM_VERITY=y
+# CONFIG_DM_VERITY_FEC is not set
+# CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG is not set
+CONFIG_DTC=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_EDAC_ATOMIC_SCRUB=y
+CONFIG_EDAC_SUPPORT=y
+CONFIG_EINT_MTK=y
+CONFIG_FIXED_PHY=y
+CONFIG_FIX_EARLYCON_MEM=y
+CONFIG_FW_LOADER_PAGED_BUF=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_ARCH_TOPOLOGY=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_CPU_AUTOPROBE=y
+CONFIG_GENERIC_EARLY_IOREMAP=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
+CONFIG_GENERIC_IRQ_MIGRATION=y
+CONFIG_GENERIC_IRQ_MULTI_HANDLER=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
+CONFIG_GENERIC_MSI_IRQ=y
+CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PHY=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_PINCTRL_GROUPS=y
+CONFIG_GENERIC_PINMUX_FUNCTIONS=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GLOB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPY211_PHY=y
+CONFIG_GRO_CELLS=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_HARDEN_BRANCH_PREDICTOR=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HAVE_SMP=y
+CONFIG_HOTPLUG_CPU=y
+# CONFIG_HW_NAT is not set
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MTK=y
+CONFIG_HZ=250
+CONFIG_HZ_250=y
+CONFIG_HZ_FIXED=0
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MT65XX=y
+CONFIG_ICPLUS_PHY=y
+CONFIG_IIO=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IO_URING=y
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_IRQ_WORK=y
+CONFIG_JUMP_LABEL=y
+# CONFIG_LEDS_UBNT_LEDBAR is not set
+CONFIG_LIBFDT=y
+CONFIG_LOCK_DEBUGGING_SUPPORT=y
+CONFIG_LOCK_SPIN_ON_OWNER=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+# CONFIG_MACH_MT2701 is not set
+# CONFIG_MACH_MT6589 is not set
+# CONFIG_MACH_MT6592 is not set
+# CONFIG_MACH_MT7623 is not set
+CONFIG_MACH_MT7629=y
+# CONFIG_MACH_MT8127 is not set
+# CONFIG_MACH_MT8135 is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MD=y
+CONFIG_MDIO_BUS=y
+CONFIG_MDIO_DEVICE=y
+# CONFIG_MEDIATEK_GE_PHY is not set
+CONFIG_MEDIATEK_MT6577_AUXADC=y
+CONFIG_MEDIATEK_NETSYS_V2=y
+CONFIG_MEDIATEK_WATCHDOG=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEMFD_CREATE=y
+CONFIG_MESSAGE_LOGLEVEL_DEFAULT=7
+CONFIG_MFD_SYSCON=y
+CONFIG_MIGHT_HAVE_CACHE_L2X0=y
+CONFIG_MIGRATION=y
+CONFIG_MMC=y
+CONFIG_MMC_MTK=y
+CONFIG_MODULES_TREE_LOOKUP=y
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_MT753X_GSW=y
+CONFIG_MTD_NAND_CORE=y
+CONFIG_MTD_NAND_ECC_SW_HAMMING=y
+CONFIG_MTD_NAND_MTK=y
+CONFIG_MTD_RAW_NAND=y
+CONFIG_MTD_SPI_NAND=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPLIT_FIRMWARE=y
+CONFIG_MTD_SPLIT_FIT_FW=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_BEB_LIMIT=20
+CONFIG_MTD_UBI_BLOCK=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+# CONFIG_MTK_CMDQ is not set
+# CONFIG_MTK_CQDMA is not set
+CONFIG_MTK_EFUSE=y
+CONFIG_MTK_HSDMA=y
+CONFIG_MTK_ICE_DEBUG=y
+CONFIG_MTK_INFRACFG=y
+CONFIG_MTK_PMIC_WRAP=y
+CONFIG_MTK_SCPSYS=y
+CONFIG_MTK_SPI_NAND=y
+CONFIG_MTK_THERMAL=y
+CONFIG_MTK_TIMER=y
+# CONFIG_MTK_UART_APDMA is not set
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NET_DEVLINK=y
+CONFIG_NET_DSA=y
+CONFIG_NET_DSA_MT7530=y
+CONFIG_NET_DSA_TAG_MTK=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NET_MEDIATEK_SOC=y
+CONFIG_NET_SWITCHDEV=y
+CONFIG_NET_VENDOR_MEDIATEK=y
+CONFIG_NLS=y
+CONFIG_NMBM=y
+# CONFIG_NMBM_LOG_LEVEL_DEBUG is not set
+# CONFIG_NMBM_LOG_LEVEL_EMERG is not set
+# CONFIG_NMBM_LOG_LEVEL_ERR is not set
+CONFIG_NMBM_LOG_LEVEL_INFO=y
+# CONFIG_NMBM_LOG_LEVEL_NONE is not set
+# CONFIG_NMBM_LOG_LEVEL_WARN is not set
+CONFIG_NMBM_MTD=y
+CONFIG_NO_HZ_COMMON=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NR_CPUS=4
+CONFIG_NVMEM=y
+CONFIG_NVMEM_SYSFS=y
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_KOBJ=y
+CONFIG_OF_MDIO=y
+CONFIG_OF_NET=y
+CONFIG_OLD_SIGACTION=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_OUTER_CACHE=y
+CONFIG_OUTER_CACHE_SYNC=y
+CONFIG_PADATA=y
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PARTITION_PERCPU=y
+CONFIG_PCI=y
+CONFIG_PCIE_MEDIATEK=y
+CONFIG_PCIE_MEDIATEK_GEN3=y
+CONFIG_PCI_DEBUG=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DOMAINS_GENERIC=y
+CONFIG_PCI_MSI=y
+CONFIG_PCI_MSI_IRQ_DOMAIN=y
+CONFIG_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYLIB=y
+CONFIG_PHYLINK=y
+CONFIG_PHY_MTK_TPHY=y
+# CONFIG_PHY_MTK_UFS is not set
+# CONFIG_PHY_MTK_XSPHY is not set
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_MT7629=y
+# CONFIG_PINCTRL_MT7981 is not set
+CONFIG_PINCTRL_MT7986=y
+CONFIG_PINCTRL_MTK_MOORE=y
+CONFIG_PM=y
+CONFIG_PM_CLK=y
+CONFIG_PM_GENERIC_DOMAINS=y
+CONFIG_PM_GENERIC_DOMAINS_OF=y
+CONFIG_PM_OPP=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_PRINTK_TIME=y
+CONFIG_PWM=y
+CONFIG_PWM_MEDIATEK=y
+# CONFIG_PWM_MTK_DISP is not set
+CONFIG_PWM_SYSFS=y
+CONFIG_RAS=y
+CONFIG_RATIONAL=y
+# CONFIG_RAVE_SP_CORE is not set
+CONFIG_RCU_NEED_SEGCBLIST=y
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_REALTEK_PHY=y
+CONFIG_REFCOUNT_FULL=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_MT6380=y
+CONFIG_RESET_CONTROLLER=y
+CONFIG_RESET_TI_SYSCON=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RPS=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_MT7622=y
+CONFIG_RTC_I2C_AND_SPI=y
+CONFIG_RTC_MC146818_LIB=y
+# CONFIG_RTL8367S_GSW is not set
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+CONFIG_SCHED_MC=y
+CONFIG_SCSI=y
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
+CONFIG_SERIAL_8250_FSL=y
+CONFIG_SERIAL_8250_MT6577=y
+CONFIG_SERIAL_8250_NR_UARTS=3
+CONFIG_SERIAL_8250_RUNTIME_UARTS=3
+CONFIG_SERIAL_DEV_BUS=y
+CONFIG_SERIAL_DEV_CTRL_TTYPORT=y
+CONFIG_SERIAL_MCTRL_GPIO=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SGL_ALLOC=y
+CONFIG_SG_POOL=y
+CONFIG_SMP=y
+CONFIG_SMP_ON_UP=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_MEM=y
+CONFIG_SPI_MT65XX=y
+# CONFIG_SPI_MTK_NOR is not set
+CONFIG_SPI_MTK_SNFI=y
+CONFIG_SRCU=y
+CONFIG_SWPHY=y
+CONFIG_SWP_EMULATE=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
+CONFIG_THERMAL_EMULATION=y
+CONFIG_THERMAL_GOV_BANG_BANG=y
+CONFIG_THERMAL_GOV_FAIR_SHARE=y
+CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_USER_SPACE=y
+CONFIG_THERMAL_OF=y
+CONFIG_THERMAL_WRITABLE_TRIPS=y
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TIMER_OF=y
+CONFIG_TIMER_PROBE=y
+CONFIG_TREE_RCU=y
+CONFIG_TREE_SRCU=y
+CONFIG_UBIFS_FS=y
+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UCLAMP_TASK is not set
+CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
+CONFIG_UNWINDER_ARM=y
+CONFIG_USB=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_UAS=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_MTK=y
+CONFIG_USB_XHCI_MTK_DEBUGFS=y
+# CONFIG_USB_XHCI_PLATFORM is not set
+CONFIG_USE_OF=y
+# CONFIG_VFP is not set
+CONFIG_WATCHDOG_CORE=y
+CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC=y
+CONFIG_WATCHDOG_PRETIMEOUT_GOV=y
+# CONFIG_WATCHDOG_PRETIMEOUT_GOV_NOOP is not set
+CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC=y
+CONFIG_WATCHDOG_PRETIMEOUT_GOV_SEL=m
+CONFIG_WATCHDOG_SYSFS=y
+CONFIG_XPS=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_ZLIB_INFLATE=y
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986.cfg b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986.cfg
new file mode 100644
index 0000000..ffceaa2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986.cfg
@@ -0,0 +1,529 @@
+CONFIG_64BIT=y
+CONFIG_AHCI_MTK=y
+CONFIG_AIROHA_EN8801S_PHY=y
+CONFIG_ARCH_CLOCKSOURCE_DATA=y
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_ARCH_KEEP_MEMBLOCK=y
+CONFIG_ARCH_MEDIATEK=y
+CONFIG_ARCH_MMAP_RND_BITS=18
+CONFIG_ARCH_MMAP_RND_BITS_MAX=24
+CONFIG_ARCH_MMAP_RND_BITS_MIN=18
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS=11
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11
+CONFIG_ARCH_PROC_KCORE_TEXT=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARM64=y
+CONFIG_ARM64_4K_PAGES=y
+CONFIG_ARM64_CNP=y
+CONFIG_ARM64_CONT_SHIFT=4
+CONFIG_ARM64_ERRATUM_1165522=y
+CONFIG_ARM64_ERRATUM_1286807=y
+CONFIG_ARM64_ERRATUM_1418040=y
+CONFIG_ARM64_HW_AFDBM=y
+CONFIG_ARM64_PAGE_SHIFT=12
+CONFIG_ARM64_PAN=y
+CONFIG_ARM64_PA_BITS=48
+CONFIG_ARM64_PA_BITS_48=y
+CONFIG_ARM64_PTR_AUTH=y
+CONFIG_ARM64_SSBD=y
+CONFIG_ARM64_SVE=y
+# CONFIG_ARM64_SW_TTBR0_PAN is not set
+CONFIG_ARM64_TAGGED_ADDR_ABI=y
+CONFIG_ARM64_UAO=y
+CONFIG_ARM64_VA_BITS=39
+CONFIG_ARM64_VA_BITS_39=y
+CONFIG_ARM64_VHE=y
+CONFIG_ARM64_WORKAROUND_REPEAT_TLBI=y
+# CONFIG_ARMV8_DEPRECATED is not set
+CONFIG_ARM_AMBA=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
+CONFIG_ARM_GIC=y
+CONFIG_ARM_GIC_V2M=y
+CONFIG_ARM_GIC_V3=y
+CONFIG_ARM_GIC_V3_ITS=y
+CONFIG_ARM_GIC_V3_ITS_PCI=y
+CONFIG_ARM_MEDIATEK_CPUFREQ=y
+CONFIG_ARM_PMU=y
+CONFIG_ARM_PSCI_FW=y
+CONFIG_ATA=y
+CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_BLK_DEV_DM_BUILTIN=y
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_MQ_PCI=y
+CONFIG_BLK_PM=y
+CONFIG_BLK_SCSI_REQUEST=y
+CONFIG_BLOCK_COMPAT=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_BT=y
+CONFIG_BT_BCM=y
+CONFIG_BT_BREDR=y
+CONFIG_BT_DEBUGFS=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_BCM=y
+# CONFIG_BT_HCIUART_INTEL is not set
+# CONFIG_BT_HCIUART_NOKIA is not set
+CONFIG_BT_HCIUART_QCA=y
+CONFIG_BT_HCIUART_SERDEV=y
+CONFIG_BT_HCIVHCI=y
+CONFIG_BT_HS=y
+CONFIG_BT_LE=y
+CONFIG_BT_MTKUART=y
+CONFIG_BT_QCA=y
+CONFIG_CAVIUM_TX2_ERRATUM_219=y
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_CLOCK_THERMAL=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_COMMON_CLK=y
+CONFIG_COMMON_CLK_MEDIATEK=y
+CONFIG_COMMON_CLK_MT2712=y
+# CONFIG_COMMON_CLK_MT2712_BDPSYS is not set
+# CONFIG_COMMON_CLK_MT2712_IMGSYS is not set
+# CONFIG_COMMON_CLK_MT2712_JPGDECSYS is not set
+# CONFIG_COMMON_CLK_MT2712_MFGCFG is not set
+# CONFIG_COMMON_CLK_MT2712_MMSYS is not set
+# CONFIG_COMMON_CLK_MT2712_VDECSYS is not set
+# CONFIG_COMMON_CLK_MT2712_VENCSYS is not set
+# CONFIG_COMMON_CLK_MT6779 is not set
+# CONFIG_COMMON_CLK_MT6797 is not set
+CONFIG_COMMON_CLK_MT7622=y
+# CONFIG_COMMON_CLK_MT7622_AUDSYS is not set
+# CONFIG_COMMON_CLK_MT7622_ETHSYS is not set
+# CONFIG_COMMON_CLK_MT7622_HIFSYS is not set
+# CONFIG_COMMON_CLK_MT7981 is not set
+CONFIG_COMMON_CLK_MT7986=y
+# CONFIG_COMMON_CLK_MT8173 is not set
+CONFIG_COMMON_CLK_MT8183=y
+# CONFIG_COMMON_CLK_MT8183_AUDIOSYS is not set
+# CONFIG_COMMON_CLK_MT8183_CAMSYS is not set
+# CONFIG_COMMON_CLK_MT8183_IMGSYS is not set
+# CONFIG_COMMON_CLK_MT8183_IPU_ADL is not set
+# CONFIG_COMMON_CLK_MT8183_IPU_CONN is not set
+# CONFIG_COMMON_CLK_MT8183_IPU_CORE0 is not set
+# CONFIG_COMMON_CLK_MT8183_IPU_CORE1 is not set
+# CONFIG_COMMON_CLK_MT8183_MFGCFG is not set
+# CONFIG_COMMON_CLK_MT8183_MMSYS is not set
+# CONFIG_COMMON_CLK_MT8183_VDECSYS is not set
+# CONFIG_COMMON_CLK_MT8183_VENCSYS is not set
+CONFIG_COMMON_CLK_MT8516=y
+# CONFIG_COMMON_CLK_MT8516_AUDSYS is not set
+CONFIG_COMPAT=y
+CONFIG_COMPAT_32BIT_TIME=y
+CONFIG_COMPAT_BINFMT_ELF=y
+CONFIG_COMPAT_NETLINK_MESSAGES=y
+CONFIG_COMPAT_OLD_SIGACTION=y
+CONFIG_CONSOLE_LOGLEVEL_DEFAULT=15
+# CONFIG_CPUFREQ_DT is not set
+CONFIG_CPU_FREQ=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ATTR_SET=y
+CONFIG_CPU_FREQ_GOV_COMMON=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_RMAP=y
+CONFIG_CPU_THERMAL=y
+CONFIG_CRC16=y
+CONFIG_CRYPTO_ACOMP2=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_AUTHENC=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CMAC=y
+CONFIG_CRYPTO_CRYPTD=y
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_DEV_SAFEXCEL=y
+CONFIG_CRYPTO_DRBG=y
+CONFIG_CRYPTO_DRBG_HMAC=y
+CONFIG_CRYPTO_DRBG_MENU=y
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_ECC=y
+CONFIG_CRYPTO_ECDH=y
+CONFIG_CRYPTO_ECHAINIV=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_HASH_INFO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_JITTERENTROPY=y
+CONFIG_CRYPTO_KPP=y
+CONFIG_CRYPTO_KPP2=y
+CONFIG_CRYPTO_LIB_DES=y
+CONFIG_CRYPTO_LIB_SHA256=y
+CONFIG_CRYPTO_LZO=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_NULL=y
+CONFIG_CRYPTO_NULL2=y
+CONFIG_CRYPTO_RNG=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_RNG_DEFAULT=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA512=y
+CONFIG_CRYPTO_TEST=m
+CONFIG_DCACHE_WORD_ACCESS=y
+CONFIG_DEBUG_MISC=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_DMADEVICES=y
+CONFIG_DMATEST=y
+CONFIG_DMA_DIRECT_REMAP=y
+CONFIG_DMA_ENGINE=y
+CONFIG_DMA_ENGINE_RAID=y
+CONFIG_DMA_OF=y
+CONFIG_DMA_REMAP=y
+CONFIG_DMA_VIRTUAL_CHANNELS=y
+CONFIG_DM_BUFIO=y
+# CONFIG_DM_CRYPT is not set
+# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set
+CONFIG_DM_INIT=y
+# CONFIG_DM_MIRROR is not set
+# CONFIG_DM_SNAPSHOT is not set
+CONFIG_DM_VERITY=y
+# CONFIG_DM_VERITY_FEC is not set
+# CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG is not set
+CONFIG_DRM_RCAR_WRITEBACK=y
+CONFIG_DTC=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_EDAC_SUPPORT=y
+CONFIG_EINT_MTK=y
+CONFIG_FIXED_PHY=y
+CONFIG_FIX_EARLYCON_MEM=y
+# CONFIG_FLATMEM_MANUAL is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FUJITSU_ERRATUM_010001=y
+CONFIG_FW_LOADER_PAGED_BUF=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_ARCH_TOPOLOGY=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_CPU_AUTOPROBE=y
+CONFIG_GENERIC_CPU_VULNERABILITIES=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_GENERIC_EARLY_IOREMAP=y
+CONFIG_GENERIC_GETTIMEOFDAY=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
+CONFIG_GENERIC_IRQ_MIGRATION=y
+CONFIG_GENERIC_IRQ_MULTI_HANDLER=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
+CONFIG_GENERIC_MSI_IRQ=y
+CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PHY=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_PINCTRL_GROUPS=y
+CONFIG_GENERIC_PINMUX_FUNCTIONS=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GLOB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPY211_PHY=y
+CONFIG_GRO_CELLS=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_HARDEN_BRANCH_PREDICTOR=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HOLES_IN_ZONE=y
+CONFIG_HOTPLUG_CPU=y
+# CONFIG_HW_NAT is not set
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MTK=y
+CONFIG_HZ=250
+CONFIG_HZ_250=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MT65XX=y
+CONFIG_ICPLUS_PHY=y
+CONFIG_IIO=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_ESP_OFFLOAD is not set
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_TUNNEL=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IO_URING=y
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_IRQ_WORK=y
+CONFIG_JUMP_LABEL=y
+# CONFIG_LEDS_UBNT_LEDBAR is not set
+CONFIG_LIBFDT=y
+CONFIG_LOCK_DEBUGGING_SUPPORT=y
+CONFIG_LOCK_SPIN_ON_OWNER=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MAGIC_SYSRQ_SERIAL=y
+CONFIG_MD=y
+CONFIG_MDIO_BUS=y
+CONFIG_MDIO_DEVICE=y
+# CONFIG_MEDIATEK_GE_PHY is not set
+CONFIG_MEDIATEK_MT6577_AUXADC=y
+CONFIG_MEDIATEK_NETSYS_V2=y
+CONFIG_MEDIATEK_WATCHDOG=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEMFD_CREATE=y
+CONFIG_MESSAGE_LOGLEVEL_DEFAULT=7
+CONFIG_MFD_SYSCON=y
+CONFIG_MIGRATION=y
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_MTK=y
+CONFIG_MODULES_TREE_LOOKUP=y
+CONFIG_MODULES_USE_ELF_RELA=y
+CONFIG_MT753X_GSW=y
+CONFIG_MTD_NAND_CORE=y
+CONFIG_MTD_NAND_ECC_SW_HAMMING=y
+CONFIG_MTD_NAND_MTK=y
+CONFIG_MTD_RAW_NAND=y
+CONFIG_MTD_SPI_NAND=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPLIT_FIRMWARE=y
+CONFIG_MTD_SPLIT_FIT_FW=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_BEB_LIMIT=20
+CONFIG_MTD_UBI_BLOCK=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+# CONFIG_MTK_CMDQ is not set
+# CONFIG_MTK_CQDMA is not set
+CONFIG_MTK_EFUSE=y
+CONFIG_MTK_HSDMA=y
+CONFIG_MTK_ICE_DEBUG=y
+CONFIG_MTK_INFRACFG=y
+CONFIG_MTK_PMIC_WRAP=y
+CONFIG_MTK_SCPSYS=y
+CONFIG_MTK_SPI_NAND=y
+CONFIG_MTK_THERMAL=y
+CONFIG_MTK_TIMER=y
+# CONFIG_MTK_UART_APDMA is not set
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_SG_DMA_LENGTH=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_NAT=m
+CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m
+CONFIG_NET_DEVLINK=y
+CONFIG_NET_DSA=y
+CONFIG_NET_DSA_MT7530=y
+CONFIG_NET_DSA_TAG_MTK=y
+CONFIG_NET_FLOW_LIMIT=y
+# CONFIG_NET_MEDIATEK_HNAT is not set
+CONFIG_NET_MEDIATEK_SOC=y
+CONFIG_NET_SWITCHDEV=y
+CONFIG_NET_VENDOR_MEDIATEK=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_DEFRAG_IPV4=y
+CONFIG_NF_NAT=m
+CONFIG_NF_NAT_MASQUERADE=y
+CONFIG_NLS=y
+CONFIG_NMBM=y
+# CONFIG_NMBM_LOG_LEVEL_DEBUG is not set
+# CONFIG_NMBM_LOG_LEVEL_EMERG is not set
+# CONFIG_NMBM_LOG_LEVEL_ERR is not set
+CONFIG_NMBM_LOG_LEVEL_INFO=y
+# CONFIG_NMBM_LOG_LEVEL_NONE is not set
+# CONFIG_NMBM_LOG_LEVEL_WARN is not set
+CONFIG_NMBM_MTD=y
+CONFIG_NO_HZ_COMMON=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NR_CPUS=4
+CONFIG_NVMEM=y
+CONFIG_NVMEM_SYSFS=y
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_KOBJ=y
+CONFIG_OF_MDIO=y
+CONFIG_OF_NET=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_PADATA=y
+CONFIG_PARTITION_PERCPU=y
+CONFIG_PCI=y
+# CONFIG_PCIE_MEDIATEK is not set
+CONFIG_PCIE_MEDIATEK_GEN3=y
+CONFIG_PCI_DEBUG=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DOMAINS_GENERIC=y
+CONFIG_PCI_MSI=y
+CONFIG_PCI_MSI_IRQ_DOMAIN=y
+CONFIG_PERF_EVENTS=y
+CONFIG_PGTABLE_LEVELS=3
+CONFIG_PHYLIB=y
+CONFIG_PHYLINK=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_PHY_MTK_TPHY=y
+# CONFIG_PHY_MTK_UFS is not set
+# CONFIG_PHY_MTK_XSPHY is not set
+CONFIG_PINCTRL=y
+# CONFIG_PINCTRL_MT2712 is not set
+# CONFIG_PINCTRL_MT6765 is not set
+# CONFIG_PINCTRL_MT6797 is not set
+# CONFIG_PINCTRL_MT7622 is not set
+# CONFIG_PINCTRL_MT7981 is not set
+CONFIG_PINCTRL_MT7986=y
+# CONFIG_PINCTRL_MT8173 is not set
+# CONFIG_PINCTRL_MT8183 is not set
+CONFIG_PINCTRL_MT8516=y
+CONFIG_PINCTRL_MTK=y
+CONFIG_PINCTRL_MTK_MOORE=y
+CONFIG_PM=y
+CONFIG_PM_CLK=y
+CONFIG_PM_GENERIC_DOMAINS=y
+CONFIG_PM_GENERIC_DOMAINS_OF=y
+CONFIG_PM_OPP=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_PRINTK_TIME=y
+CONFIG_PWM=y
+CONFIG_PWM_MEDIATEK=y
+# CONFIG_PWM_MTK_DISP is not set
+CONFIG_PWM_SYSFS=y
+CONFIG_QUEUED_RWLOCKS=y
+CONFIG_QUEUED_SPINLOCKS=y
+CONFIG_RAS=y
+CONFIG_RATIONAL=y
+# CONFIG_RAVE_SP_CORE is not set
+CONFIG_RCU_NEED_SEGCBLIST=y
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_REALTEK_PHY=y
+CONFIG_REFCOUNT_FULL=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_MT6380=y
+CONFIG_RESET_CONTROLLER=y
+CONFIG_RESET_TI_SYSCON=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RODATA_FULL_DEFAULT_ENABLED=y
+CONFIG_RPS=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_MT7622=y
+CONFIG_RTC_I2C_AND_SPI=y
+# CONFIG_RTL8367S_GSW is not set
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+CONFIG_SCHED_MC=y
+CONFIG_SCSI=y
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
+CONFIG_SERIAL_8250_FSL=y
+CONFIG_SERIAL_8250_MT6577=y
+CONFIG_SERIAL_8250_NR_UARTS=3
+CONFIG_SERIAL_8250_RUNTIME_UARTS=3
+CONFIG_SERIAL_DEV_BUS=y
+CONFIG_SERIAL_DEV_CTRL_TTYPORT=y
+CONFIG_SERIAL_MCTRL_GPIO=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SGL_ALLOC=y
+CONFIG_SG_POOL=y
+CONFIG_SKB_EXTENSIONS=y
+CONFIG_SMP=y
+CONFIG_SPARSEMEM=y
+CONFIG_SPARSEMEM_EXTREME=y
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM_VMEMMAP=y
+CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_MEM=y
+CONFIG_SPI_MT65XX=y
+# CONFIG_SPI_MTK_NOR is not set
+CONFIG_SPI_MTK_SNFI=y
+CONFIG_SRCU=y
+CONFIG_SWIOTLB=y
+CONFIG_SWPHY=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_SYSVIPC_COMPAT=y
+CONFIG_SYS_SUPPORTS_HUGETLBFS=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
+CONFIG_THERMAL_EMULATION=y
+CONFIG_THERMAL_GOV_BANG_BANG=y
+CONFIG_THERMAL_GOV_FAIR_SHARE=y
+CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_USER_SPACE=y
+CONFIG_THERMAL_OF=y
+CONFIG_THERMAL_WRITABLE_TRIPS=y
+CONFIG_THREAD_INFO_IN_TASK=y
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TIMER_OF=y
+CONFIG_TIMER_PROBE=y
+CONFIG_TREE_RCU=y
+CONFIG_TREE_SRCU=y
+CONFIG_UBIFS_FS=y
+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UCLAMP_TASK is not set
+# CONFIG_UNMAP_KERNEL_AT_EL0 is not set
+CONFIG_USB=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_UAS=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_MTK=y
+CONFIG_USB_XHCI_MTK_DEBUGFS=y
+# CONFIG_USB_XHCI_PLATFORM is not set
+CONFIG_VMAP_STACK=y
+CONFIG_WATCHDOG_CORE=y
+CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC=y
+CONFIG_WATCHDOG_PRETIMEOUT_GOV=y
+# CONFIG_WATCHDOG_PRETIMEOUT_GOV_NOOP is not set
+CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC=y
+CONFIG_WATCHDOG_PRETIMEOUT_GOV_SEL=m
+CONFIG_WATCHDOG_SYSFS=y
+CONFIG_XFRM_ALGO=y
+CONFIG_XFRM_IPCOMP=y
+CONFIG_XFRM_USER=y
+CONFIG_XPS=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZONE_DMA32=y
+CONFIG_NVMEM=y
+CONFIG_MTK_EFUSE=y
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0001-clk-mtk-add-mt7986-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0001-clk-mtk-add-mt7986-support.patch
new file mode 100644
index 0000000..930e88b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0001-clk-mtk-add-mt7986-support.patch
@@ -0,0 +1,41 @@
+diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
+index 7efc361..5f11280 100644
+--- a/drivers/clk/mediatek/Kconfig
++++ b/drivers/clk/mediatek/Kconfig
+@@ -258,6 +258,15 @@ config COMMON_CLK_MT7629_HIFSYS
+ 	  This driver supports MediaTek MT7629 HIFSYS clocks providing
+ 	  to PCI-E and USB.
+
++config COMMON_CLK_MT7986
++	bool "Clock driver for MediaTek MT7986"
++	depends on ARCH_MEDIATEK || COMPILE_TEST
++	select COMMON_CLK_MEDIATEK
++	default ARCH_MEDIATEK && ARM
++	---help---
++	  This driver supports MediaTek MT7986 basic clocks and clocks
++	  required for various periperals found on MediaTek.
++
+ config COMMON_CLK_MT8135
+ 	bool "Clock driver for MediaTek MT8135"
+ 	depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST
+diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
+index 8cdb76a..8c392f4 100644
+--- a/drivers/clk/mediatek/Makefile
++++ b/drivers/clk/mediatek/Makefile
+@@ -39,6 +39,7 @@ obj-$(CONFIG_COMMON_CLK_MT7622_AUDSYS) += clk-mt7622-aud.o
+ obj-$(CONFIG_COMMON_CLK_MT7629) += clk-mt7629.o
+ obj-$(CONFIG_COMMON_CLK_MT7629_ETHSYS) += clk-mt7629-eth.o
+ obj-$(CONFIG_COMMON_CLK_MT7629_HIFSYS) += clk-mt7629-hif.o
++obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986.o
+ obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o
+ obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173.o
+ obj-$(CONFIG_COMMON_CLK_MT8183) += clk-mt8183.o
+@@ -55,3 +56,4 @@ obj-$(CONFIG_COMMON_CLK_MT8183_VDECSYS) += clk-mt8183-vdec.o
+ obj-$(CONFIG_COMMON_CLK_MT8183_VENCSYS) += clk-mt8183-venc.o
+ obj-$(CONFIG_COMMON_CLK_MT8516) += clk-mt8516.o
+ obj-$(CONFIG_COMMON_CLK_MT8516_AUDSYS) += clk-mt8516-aud.o
++obj-y += clk-bringup.o
+\ No newline at end of file
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0001-v5.7-spi-make-spi-max-frequency-optional.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0001-v5.7-spi-make-spi-max-frequency-optional.patch
new file mode 100644
index 0000000..79ce15c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0001-v5.7-spi-make-spi-max-frequency-optional.patch
@@ -0,0 +1,38 @@
+From 671c3bf50ae498dc12aef6c70abe5cfa066b1348 Mon Sep 17 00:00:00 2001
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Fri, 6 Mar 2020 16:50:49 +0800
+Subject: [PATCH 1/2] spi: make spi-max-frequency optional
+
+We only need a spi-max-frequency when we specifically request a
+spi frequency lower than the max speed of spi host.
+This property is already documented as optional property and current
+host drivers are implemented to operate at highest speed possible
+when spi->max_speed_hz is 0.
+This patch makes spi-max-frequency an optional property so that
+we could just omit it to use max controller speed.
+
+Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
+Link: https://lore.kernel.org/r/20200306085052.28258-2-gch981213@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+ drivers/spi/spi.c | 9 ++-------
+ 1 file changed, 2 insertions(+), 7 deletions(-)
+
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -1809,13 +1809,8 @@ static int of_spi_parse_dt(struct spi_co
+ 		spi->mode |= SPI_CS_HIGH;
+ 
+ 	/* Device speed */
+-	rc = of_property_read_u32(nc, "spi-max-frequency", &value);
+-	if (rc) {
+-		dev_err(&ctlr->dev,
+-			"%pOF has no valid 'spi-max-frequency' property (%d)\n", nc, rc);
+-		return rc;
+-	}
+-	spi->max_speed_hz = value;
++	if (!of_property_read_u32(nc, "spi-max-frequency", &value))
++		spi->max_speed_hz = value;
+ 
+ 	return 0;
+ }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0002-clk-mtk-add-mt7981-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0002-clk-mtk-add-mt7981-support.patch
new file mode 100644
index 0000000..72f9e8a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0002-clk-mtk-add-mt7981-support.patch
@@ -0,0 +1,34 @@
+diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
+index 1c48fe9..23393d5 100644
+--- a/drivers/clk/mediatek/Kconfig
++++ b/drivers/clk/mediatek/Kconfig
+@@ -267,6 +267,14 @@ config COMMON_CLK_MT7986
+ 	  This driver supports MediaTek MT7986 basic clocks and clocks
+ 	  required for various periperals found on MediaTek.
+ 
++config COMMON_CLK_MT7981
++	bool "Clock driver for MediaTek MT7981"
++	depends on ARCH_MEDIATEK || COMPILE_TEST
++	select COMMON_CLK_MEDIATEK
++	---help---
++	  This driver supports MediaTek MT7981 basic clocks and clocks
++	  required for various periperals found on MediaTek.
++
+ config COMMON_CLK_MT8135
+ 	bool "Clock driver for MediaTek MT8135"
+ 	depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST
+diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
+index 8c392f4..ffe0850 100644
+--- a/drivers/clk/mediatek/Makefile
++++ b/drivers/clk/mediatek/Makefile
+@@ -40,6 +40,7 @@ obj-$(CONFIG_COMMON_CLK_MT7629) += clk-mt7629.o
+ obj-$(CONFIG_COMMON_CLK_MT7629_ETHSYS) += clk-mt7629-eth.o
+ obj-$(CONFIG_COMMON_CLK_MT7629_HIFSYS) += clk-mt7629-hif.o
+ obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986.o
++obj-$(CONFIG_COMMON_CLK_MT7981) += clk-mt7981.o
+ obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o
+ obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173.o
+ obj-$(CONFIG_COMMON_CLK_MT8183) += clk-mt8183.o
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0002-v5.7-spi-add-support-for-mediatek-spi-nor-controller.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0002-v5.7-spi-add-support-for-mediatek-spi-nor-controller.patch
new file mode 100644
index 0000000..0a63bdd
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0002-v5.7-spi-add-support-for-mediatek-spi-nor-controller.patch
@@ -0,0 +1,761 @@
+From 881d1ee9fe81ff2be1b90809a07621be97404a57 Mon Sep 17 00:00:00 2001
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Fri, 6 Mar 2020 16:50:50 +0800
+Subject: [PATCH 2/2] spi: add support for mediatek spi-nor controller
+
+This is a driver for mtk spi-nor controller using spi-mem interface.
+The same controller already has limited support provided by mtk-quadspi
+driver under spi-nor framework and this new driver is a replacement
+for the old one.
+
+Comparing to the old driver, this driver has following advantages:
+1. It can handle any full-duplex spi transfer up to 6 bytes, and
+   this is implemented using generic spi interface.
+2. It take account into command opcode properly. The reading routine
+   in this controller can only use 0x03 or 0x0b as opcode on 1-1-1
+   transfers, but old driver doesn't implement this properly. This
+   driver checks supported opcode explicitly and use (1) to perform
+   unmatched operations.
+3. It properly handles SFDP reading. Old driver can't read SFDP
+   due to the bug mentioned in (2).
+4. It can do 1-2-2 and 1-4-4 fast reading on spi-nor. These two ops
+   requires parsing SFDP, which isn't possible in old driver. And
+   the old driver is only flagged to support 1-1-2 mode.
+5. It takes advantage of the DMA feature in this controller for
+   long reads and supports IRQ on DMA requests to free cpu cycles
+   from polling status registers on long DMA reading. It achieves
+   up to 17.5MB/s reading speed (1-4-4 mode) which is way faster
+   than the old one. IRQ is implemented as optional to maintain
+   backward compatibility.
+
+Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
+Link: https://lore.kernel.org/r/20200306085052.28258-3-gch981213@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+---
+ drivers/spi/Kconfig       |  10 +
+ drivers/spi/Makefile      |   1 +
+ drivers/spi/spi-mtk-nor.c | 689 ++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 700 insertions(+)
+ create mode 100644 drivers/spi/spi-mtk-nor.c
+
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -433,6 +433,16 @@ config SPI_MT7621
+ 	help
+ 	  This selects a driver for the MediaTek MT7621 SPI Controller.
+ 
++config SPI_MTK_NOR
++	tristate "MediaTek SPI NOR controller"
++	depends on ARCH_MEDIATEK || COMPILE_TEST
++	help
++	  This enables support for SPI NOR controller found on MediaTek
++	  ARM SoCs. This is a controller specifically for SPI-NOR flash.
++	  It can perform generic SPI transfers up to 6 bytes via generic
++	  SPI interface as well as several SPI-NOR specific instructions
++	  via SPI MEM interface.
++
+ config SPI_NPCM_FIU
+ 	tristate "Nuvoton NPCM FLASH Interface Unit"
+ 	depends on ARCH_NPCM || COMPILE_TEST
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -61,6 +61,7 @@ obj-$(CONFIG_SPI_MPC52xx_PSC)		+= spi-mp
+ obj-$(CONFIG_SPI_MPC52xx)		+= spi-mpc52xx.o
+ obj-$(CONFIG_SPI_MT65XX)                += spi-mt65xx.o
+ obj-$(CONFIG_SPI_MT7621)		+= spi-mt7621.o
++obj-$(CONFIG_SPI_MTK_NOR)		+= spi-mtk-nor.o
+ obj-$(CONFIG_SPI_MXIC)			+= spi-mxic.o
+ obj-$(CONFIG_SPI_MXS)			+= spi-mxs.o
+ obj-$(CONFIG_SPI_NPCM_FIU)		+= spi-npcm-fiu.o
+--- /dev/null
++++ b/drivers/spi/spi-mtk-nor.c
+@@ -0,0 +1,689 @@
++// SPDX-License-Identifier: GPL-2.0
++//
++// Mediatek SPI NOR controller driver
++//
++// Copyright (C) 2020 Chuanhong Guo <gch981213@gmail.com>
++
++#include <linux/bits.h>
++#include <linux/clk.h>
++#include <linux/completion.h>
++#include <linux/dma-mapping.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/iopoll.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of_device.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi-mem.h>
++#include <linux/string.h>
++
++#define DRIVER_NAME "mtk-spi-nor"
++
++#define MTK_NOR_REG_CMD			0x00
++#define MTK_NOR_CMD_WRITE		BIT(4)
++#define MTK_NOR_CMD_PROGRAM		BIT(2)
++#define MTK_NOR_CMD_READ		BIT(0)
++#define MTK_NOR_CMD_MASK		GENMASK(5, 0)
++
++#define MTK_NOR_REG_PRG_CNT		0x04
++#define MTK_NOR_REG_RDATA		0x0c
++
++#define MTK_NOR_REG_RADR0		0x10
++#define MTK_NOR_REG_RADR(n)		(MTK_NOR_REG_RADR0 + 4 * (n))
++#define MTK_NOR_REG_RADR3		0xc8
++
++#define MTK_NOR_REG_WDATA		0x1c
++
++#define MTK_NOR_REG_PRGDATA0		0x20
++#define MTK_NOR_REG_PRGDATA(n)		(MTK_NOR_REG_PRGDATA0 + 4 * (n))
++#define MTK_NOR_REG_PRGDATA_MAX		5
++
++#define MTK_NOR_REG_SHIFT0		0x38
++#define MTK_NOR_REG_SHIFT(n)		(MTK_NOR_REG_SHIFT0 + 4 * (n))
++#define MTK_NOR_REG_SHIFT_MAX		9
++
++#define MTK_NOR_REG_CFG1		0x60
++#define MTK_NOR_FAST_READ		BIT(0)
++
++#define MTK_NOR_REG_CFG2		0x64
++#define MTK_NOR_WR_CUSTOM_OP_EN		BIT(4)
++#define MTK_NOR_WR_BUF_EN		BIT(0)
++
++#define MTK_NOR_REG_PP_DATA		0x98
++
++#define MTK_NOR_REG_IRQ_STAT		0xa8
++#define MTK_NOR_REG_IRQ_EN		0xac
++#define MTK_NOR_IRQ_DMA			BIT(7)
++#define MTK_NOR_IRQ_MASK		GENMASK(7, 0)
++
++#define MTK_NOR_REG_CFG3		0xb4
++#define MTK_NOR_DISABLE_WREN		BIT(7)
++#define MTK_NOR_DISABLE_SR_POLL		BIT(5)
++
++#define MTK_NOR_REG_WP			0xc4
++#define MTK_NOR_ENABLE_SF_CMD		0x30
++
++#define MTK_NOR_REG_BUSCFG		0xcc
++#define MTK_NOR_4B_ADDR			BIT(4)
++#define MTK_NOR_QUAD_ADDR		BIT(3)
++#define MTK_NOR_QUAD_READ		BIT(2)
++#define MTK_NOR_DUAL_ADDR		BIT(1)
++#define MTK_NOR_DUAL_READ		BIT(0)
++#define MTK_NOR_BUS_MODE_MASK		GENMASK(4, 0)
++
++#define MTK_NOR_REG_DMA_CTL		0x718
++#define MTK_NOR_DMA_START		BIT(0)
++
++#define MTK_NOR_REG_DMA_FADR		0x71c
++#define MTK_NOR_REG_DMA_DADR		0x720
++#define MTK_NOR_REG_DMA_END_DADR	0x724
++
++#define MTK_NOR_PRG_MAX_SIZE		6
++// Reading DMA src/dst addresses have to be 16-byte aligned
++#define MTK_NOR_DMA_ALIGN		16
++#define MTK_NOR_DMA_ALIGN_MASK		(MTK_NOR_DMA_ALIGN - 1)
++// and we allocate a bounce buffer if destination address isn't aligned.
++#define MTK_NOR_BOUNCE_BUF_SIZE		PAGE_SIZE
++
++// Buffered page program can do one 128-byte transfer
++#define MTK_NOR_PP_SIZE			128
++
++#define CLK_TO_US(sp, clkcnt)		((clkcnt) * 1000000 / sp->spi_freq)
++
++struct mtk_nor {
++	struct spi_controller *ctlr;
++	struct device *dev;
++	void __iomem *base;
++	u8 *buffer;
++	struct clk *spi_clk;
++	struct clk *ctlr_clk;
++	unsigned int spi_freq;
++	bool wbuf_en;
++	bool has_irq;
++	struct completion op_done;
++};
++
++static inline void mtk_nor_rmw(struct mtk_nor *sp, u32 reg, u32 set, u32 clr)
++{
++	u32 val = readl(sp->base + reg);
++
++	val &= ~clr;
++	val |= set;
++	writel(val, sp->base + reg);
++}
++
++static inline int mtk_nor_cmd_exec(struct mtk_nor *sp, u32 cmd, ulong clk)
++{
++	ulong delay = CLK_TO_US(sp, clk);
++	u32 reg;
++	int ret;
++
++	writel(cmd, sp->base + MTK_NOR_REG_CMD);
++	ret = readl_poll_timeout(sp->base + MTK_NOR_REG_CMD, reg, !(reg & cmd),
++				 delay / 3, (delay + 1) * 200);
++	if (ret < 0)
++		dev_err(sp->dev, "command %u timeout.\n", cmd);
++	return ret;
++}
++
++static void mtk_nor_set_addr(struct mtk_nor *sp, const struct spi_mem_op *op)
++{
++	u32 addr = op->addr.val;
++	int i;
++
++	for (i = 0; i < 3; i++) {
++		writeb(addr & 0xff, sp->base + MTK_NOR_REG_RADR(i));
++		addr >>= 8;
++	}
++	if (op->addr.nbytes == 4) {
++		writeb(addr & 0xff, sp->base + MTK_NOR_REG_RADR3);
++		mtk_nor_rmw(sp, MTK_NOR_REG_BUSCFG, MTK_NOR_4B_ADDR, 0);
++	} else {
++		mtk_nor_rmw(sp, MTK_NOR_REG_BUSCFG, 0, MTK_NOR_4B_ADDR);
++	}
++}
++
++static bool mtk_nor_match_read(const struct spi_mem_op *op)
++{
++	int dummy = 0;
++
++	if (op->dummy.buswidth)
++		dummy = op->dummy.nbytes * BITS_PER_BYTE / op->dummy.buswidth;
++
++	if ((op->data.buswidth == 2) || (op->data.buswidth == 4)) {
++		if (op->addr.buswidth == 1)
++			return dummy == 8;
++		else if (op->addr.buswidth == 2)
++			return dummy == 4;
++		else if (op->addr.buswidth == 4)
++			return dummy == 6;
++	} else if ((op->addr.buswidth == 1) && (op->data.buswidth == 1)) {
++		if (op->cmd.opcode == 0x03)
++			return dummy == 0;
++		else if (op->cmd.opcode == 0x0b)
++			return dummy == 8;
++	}
++	return false;
++}
++
++static int mtk_nor_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
++{
++	size_t len;
++
++	if (!op->data.nbytes)
++		return 0;
++
++	if ((op->addr.nbytes == 3) || (op->addr.nbytes == 4)) {
++		if ((op->data.dir == SPI_MEM_DATA_IN) &&
++		    mtk_nor_match_read(op)) {
++			if ((op->addr.val & MTK_NOR_DMA_ALIGN_MASK) ||
++			    (op->data.nbytes < MTK_NOR_DMA_ALIGN))
++				op->data.nbytes = 1;
++			else if (!((ulong)(op->data.buf.in) &
++				   MTK_NOR_DMA_ALIGN_MASK))
++				op->data.nbytes &= ~MTK_NOR_DMA_ALIGN_MASK;
++			else if (op->data.nbytes > MTK_NOR_BOUNCE_BUF_SIZE)
++				op->data.nbytes = MTK_NOR_BOUNCE_BUF_SIZE;
++			return 0;
++		} else if (op->data.dir == SPI_MEM_DATA_OUT) {
++			if (op->data.nbytes >= MTK_NOR_PP_SIZE)
++				op->data.nbytes = MTK_NOR_PP_SIZE;
++			else
++				op->data.nbytes = 1;
++			return 0;
++		}
++	}
++
++	len = MTK_NOR_PRG_MAX_SIZE - sizeof(op->cmd.opcode) - op->addr.nbytes -
++	      op->dummy.nbytes;
++	if (op->data.nbytes > len)
++		op->data.nbytes = len;
++
++	return 0;
++}
++
++static bool mtk_nor_supports_op(struct spi_mem *mem,
++				const struct spi_mem_op *op)
++{
++	size_t len;
++
++	if (op->cmd.buswidth != 1)
++		return false;
++
++	if ((op->addr.nbytes == 3) || (op->addr.nbytes == 4)) {
++		if ((op->data.dir == SPI_MEM_DATA_IN) && mtk_nor_match_read(op))
++			return true;
++		else if (op->data.dir == SPI_MEM_DATA_OUT)
++			return (op->addr.buswidth == 1) &&
++			       (op->dummy.buswidth == 0) &&
++			       (op->data.buswidth == 1);
++	}
++	len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes;
++	if ((len > MTK_NOR_PRG_MAX_SIZE) ||
++	    ((op->data.nbytes) && (len == MTK_NOR_PRG_MAX_SIZE)))
++		return false;
++	return true;
++}
++
++static void mtk_nor_setup_bus(struct mtk_nor *sp, const struct spi_mem_op *op)
++{
++	u32 reg = 0;
++
++	if (op->addr.nbytes == 4)
++		reg |= MTK_NOR_4B_ADDR;
++
++	if (op->data.buswidth == 4) {
++		reg |= MTK_NOR_QUAD_READ;
++		writeb(op->cmd.opcode, sp->base + MTK_NOR_REG_PRGDATA(4));
++		if (op->addr.buswidth == 4)
++			reg |= MTK_NOR_QUAD_ADDR;
++	} else if (op->data.buswidth == 2) {
++		reg |= MTK_NOR_DUAL_READ;
++		writeb(op->cmd.opcode, sp->base + MTK_NOR_REG_PRGDATA(3));
++		if (op->addr.buswidth == 2)
++			reg |= MTK_NOR_DUAL_ADDR;
++	} else {
++		if (op->cmd.opcode == 0x0b)
++			mtk_nor_rmw(sp, MTK_NOR_REG_CFG1, MTK_NOR_FAST_READ, 0);
++		else
++			mtk_nor_rmw(sp, MTK_NOR_REG_CFG1, 0, MTK_NOR_FAST_READ);
++	}
++	mtk_nor_rmw(sp, MTK_NOR_REG_BUSCFG, reg, MTK_NOR_BUS_MODE_MASK);
++}
++
++static int mtk_nor_read_dma(struct mtk_nor *sp, u32 from, unsigned int length,
++			    u8 *buffer)
++{
++	int ret = 0;
++	ulong delay;
++	u32 reg;
++	dma_addr_t dma_addr;
++
++	dma_addr = dma_map_single(sp->dev, buffer, length, DMA_FROM_DEVICE);
++	if (dma_mapping_error(sp->dev, dma_addr)) {
++		dev_err(sp->dev, "failed to map dma buffer.\n");
++		return -EINVAL;
++	}
++
++	writel(from, sp->base + MTK_NOR_REG_DMA_FADR);
++	writel(dma_addr, sp->base + MTK_NOR_REG_DMA_DADR);
++	writel(dma_addr + length, sp->base + MTK_NOR_REG_DMA_END_DADR);
++
++	if (sp->has_irq) {
++		reinit_completion(&sp->op_done);
++		mtk_nor_rmw(sp, MTK_NOR_REG_IRQ_EN, MTK_NOR_IRQ_DMA, 0);
++	}
++
++	mtk_nor_rmw(sp, MTK_NOR_REG_DMA_CTL, MTK_NOR_DMA_START, 0);
++
++	delay = CLK_TO_US(sp, (length + 5) * BITS_PER_BYTE);
++
++	if (sp->has_irq) {
++		if (!wait_for_completion_timeout(&sp->op_done,
++						 (delay + 1) * 100))
++			ret = -ETIMEDOUT;
++	} else {
++		ret = readl_poll_timeout(sp->base + MTK_NOR_REG_DMA_CTL, reg,
++					 !(reg & MTK_NOR_DMA_START), delay / 3,
++					 (delay + 1) * 100);
++	}
++
++	dma_unmap_single(sp->dev, dma_addr, length, DMA_FROM_DEVICE);
++	if (ret < 0)
++		dev_err(sp->dev, "dma read timeout.\n");
++
++	return ret;
++}
++
++static int mtk_nor_read_bounce(struct mtk_nor *sp, u32 from,
++			       unsigned int length, u8 *buffer)
++{
++	unsigned int rdlen;
++	int ret;
++
++	if (length & MTK_NOR_DMA_ALIGN_MASK)
++		rdlen = (length + MTK_NOR_DMA_ALIGN) & ~MTK_NOR_DMA_ALIGN_MASK;
++	else
++		rdlen = length;
++
++	ret = mtk_nor_read_dma(sp, from, rdlen, sp->buffer);
++	if (ret)
++		return ret;
++
++	memcpy(buffer, sp->buffer, length);
++	return 0;
++}
++
++static int mtk_nor_read_pio(struct mtk_nor *sp, const struct spi_mem_op *op)
++{
++	u8 *buf = op->data.buf.in;
++	int ret;
++
++	ret = mtk_nor_cmd_exec(sp, MTK_NOR_CMD_READ, 6 * BITS_PER_BYTE);
++	if (!ret)
++		buf[0] = readb(sp->base + MTK_NOR_REG_RDATA);
++	return ret;
++}
++
++static int mtk_nor_write_buffer_enable(struct mtk_nor *sp)
++{
++	int ret;
++	u32 val;
++
++	if (sp->wbuf_en)
++		return 0;
++
++	val = readl(sp->base + MTK_NOR_REG_CFG2);
++	writel(val | MTK_NOR_WR_BUF_EN, sp->base + MTK_NOR_REG_CFG2);
++	ret = readl_poll_timeout(sp->base + MTK_NOR_REG_CFG2, val,
++				 val & MTK_NOR_WR_BUF_EN, 0, 10000);
++	if (!ret)
++		sp->wbuf_en = true;
++	return ret;
++}
++
++static int mtk_nor_write_buffer_disable(struct mtk_nor *sp)
++{
++	int ret;
++	u32 val;
++
++	if (!sp->wbuf_en)
++		return 0;
++	val = readl(sp->base + MTK_NOR_REG_CFG2);
++	writel(val & ~MTK_NOR_WR_BUF_EN, sp->base + MTK_NOR_REG_CFG2);
++	ret = readl_poll_timeout(sp->base + MTK_NOR_REG_CFG2, val,
++				 !(val & MTK_NOR_WR_BUF_EN), 0, 10000);
++	if (!ret)
++		sp->wbuf_en = false;
++	return ret;
++}
++
++static int mtk_nor_pp_buffered(struct mtk_nor *sp, const struct spi_mem_op *op)
++{
++	const u8 *buf = op->data.buf.out;
++	u32 val;
++	int ret, i;
++
++	ret = mtk_nor_write_buffer_enable(sp);
++	if (ret < 0)
++		return ret;
++
++	for (i = 0; i < op->data.nbytes; i += 4) {
++		val = buf[i + 3] << 24 | buf[i + 2] << 16 | buf[i + 1] << 8 |
++		      buf[i];
++		writel(val, sp->base + MTK_NOR_REG_PP_DATA);
++	}
++	return mtk_nor_cmd_exec(sp, MTK_NOR_CMD_WRITE,
++				(op->data.nbytes + 5) * BITS_PER_BYTE);
++}
++
++static int mtk_nor_pp_unbuffered(struct mtk_nor *sp,
++				 const struct spi_mem_op *op)
++{
++	const u8 *buf = op->data.buf.out;
++	int ret;
++
++	ret = mtk_nor_write_buffer_disable(sp);
++	if (ret < 0)
++		return ret;
++	writeb(buf[0], sp->base + MTK_NOR_REG_WDATA);
++	return mtk_nor_cmd_exec(sp, MTK_NOR_CMD_WRITE, 6 * BITS_PER_BYTE);
++}
++
++int mtk_nor_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
++{
++	struct mtk_nor *sp = spi_controller_get_devdata(mem->spi->master);
++	int ret;
++
++	if ((op->data.nbytes == 0) ||
++	    ((op->addr.nbytes != 3) && (op->addr.nbytes != 4)))
++		return -ENOTSUPP;
++
++	if (op->data.dir == SPI_MEM_DATA_OUT) {
++		mtk_nor_set_addr(sp, op);
++		writeb(op->cmd.opcode, sp->base + MTK_NOR_REG_PRGDATA0);
++		if (op->data.nbytes == MTK_NOR_PP_SIZE)
++			return mtk_nor_pp_buffered(sp, op);
++		return mtk_nor_pp_unbuffered(sp, op);
++	}
++
++	if ((op->data.dir == SPI_MEM_DATA_IN) && mtk_nor_match_read(op)) {
++		ret = mtk_nor_write_buffer_disable(sp);
++		if (ret < 0)
++			return ret;
++		mtk_nor_setup_bus(sp, op);
++		if (op->data.nbytes == 1) {
++			mtk_nor_set_addr(sp, op);
++			return mtk_nor_read_pio(sp, op);
++		} else if (((ulong)(op->data.buf.in) &
++			    MTK_NOR_DMA_ALIGN_MASK)) {
++			return mtk_nor_read_bounce(sp, op->addr.val,
++						   op->data.nbytes,
++						   op->data.buf.in);
++		} else {
++			return mtk_nor_read_dma(sp, op->addr.val,
++						op->data.nbytes,
++						op->data.buf.in);
++		}
++	}
++
++	return -ENOTSUPP;
++}
++
++static int mtk_nor_setup(struct spi_device *spi)
++{
++	struct mtk_nor *sp = spi_controller_get_devdata(spi->master);
++
++	if (spi->max_speed_hz && (spi->max_speed_hz < sp->spi_freq)) {
++		dev_err(&spi->dev, "spi clock should be %u Hz.\n",
++			sp->spi_freq);
++		return -EINVAL;
++	}
++	spi->max_speed_hz = sp->spi_freq;
++
++	return 0;
++}
++
++static int mtk_nor_transfer_one_message(struct spi_controller *master,
++					struct spi_message *m)
++{
++	struct mtk_nor *sp = spi_controller_get_devdata(master);
++	struct spi_transfer *t = NULL;
++	unsigned long trx_len = 0;
++	int stat = 0;
++	int reg_offset = MTK_NOR_REG_PRGDATA_MAX;
++	void __iomem *reg;
++	const u8 *txbuf;
++	u8 *rxbuf;
++	int i;
++
++	list_for_each_entry(t, &m->transfers, transfer_list) {
++		txbuf = t->tx_buf;
++		for (i = 0; i < t->len; i++, reg_offset--) {
++			reg = sp->base + MTK_NOR_REG_PRGDATA(reg_offset);
++			if (txbuf)
++				writeb(txbuf[i], reg);
++			else
++				writeb(0, reg);
++		}
++		trx_len += t->len;
++	}
++
++	writel(trx_len * BITS_PER_BYTE, sp->base + MTK_NOR_REG_PRG_CNT);
++
++	stat = mtk_nor_cmd_exec(sp, MTK_NOR_CMD_PROGRAM,
++				trx_len * BITS_PER_BYTE);
++	if (stat < 0)
++		goto msg_done;
++
++	reg_offset = trx_len - 1;
++	list_for_each_entry(t, &m->transfers, transfer_list) {
++		rxbuf = t->rx_buf;
++		for (i = 0; i < t->len; i++, reg_offset--) {
++			reg = sp->base + MTK_NOR_REG_SHIFT(reg_offset);
++			if (rxbuf)
++				rxbuf[i] = readb(reg);
++		}
++	}
++
++	m->actual_length = trx_len;
++msg_done:
++	m->status = stat;
++	spi_finalize_current_message(master);
++
++	return 0;
++}
++
++static void mtk_nor_disable_clk(struct mtk_nor *sp)
++{
++	clk_disable_unprepare(sp->spi_clk);
++	clk_disable_unprepare(sp->ctlr_clk);
++}
++
++static int mtk_nor_enable_clk(struct mtk_nor *sp)
++{
++	int ret;
++
++	ret = clk_prepare_enable(sp->spi_clk);
++	if (ret)
++		return ret;
++
++	ret = clk_prepare_enable(sp->ctlr_clk);
++	if (ret) {
++		clk_disable_unprepare(sp->spi_clk);
++		return ret;
++	}
++
++	return 0;
++}
++
++static int mtk_nor_init(struct mtk_nor *sp)
++{
++	int ret;
++
++	ret = mtk_nor_enable_clk(sp);
++	if (ret)
++		return ret;
++
++	sp->spi_freq = clk_get_rate(sp->spi_clk);
++
++	writel(MTK_NOR_ENABLE_SF_CMD, sp->base + MTK_NOR_REG_WP);
++	mtk_nor_rmw(sp, MTK_NOR_REG_CFG2, MTK_NOR_WR_CUSTOM_OP_EN, 0);
++	mtk_nor_rmw(sp, MTK_NOR_REG_CFG3,
++		    MTK_NOR_DISABLE_WREN | MTK_NOR_DISABLE_SR_POLL, 0);
++
++	return ret;
++}
++
++static irqreturn_t mtk_nor_irq_handler(int irq, void *data)
++{
++	struct mtk_nor *sp = data;
++	u32 irq_status, irq_enabled;
++
++	irq_status = readl(sp->base + MTK_NOR_REG_IRQ_STAT);
++	irq_enabled = readl(sp->base + MTK_NOR_REG_IRQ_EN);
++	// write status back to clear interrupt
++	writel(irq_status, sp->base + MTK_NOR_REG_IRQ_STAT);
++
++	if (!(irq_status & irq_enabled))
++		return IRQ_NONE;
++
++	if (irq_status & MTK_NOR_IRQ_DMA) {
++		complete(&sp->op_done);
++		writel(0, sp->base + MTK_NOR_REG_IRQ_EN);
++	}
++
++	return IRQ_HANDLED;
++}
++
++static size_t mtk_max_msg_size(struct spi_device *spi)
++{
++	return MTK_NOR_PRG_MAX_SIZE;
++}
++
++static const struct spi_controller_mem_ops mtk_nor_mem_ops = {
++	.adjust_op_size = mtk_nor_adjust_op_size,
++	.supports_op = mtk_nor_supports_op,
++	.exec_op = mtk_nor_exec_op
++};
++
++static const struct of_device_id mtk_nor_match[] = {
++	{ .compatible = "mediatek,mt8173-nor" },
++	{ /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, mtk_nor_match);
++
++static int mtk_nor_probe(struct platform_device *pdev)
++{
++	struct spi_controller *ctlr;
++	struct mtk_nor *sp;
++	void __iomem *base;
++	u8 *buffer;
++	struct clk *spi_clk, *ctlr_clk;
++	int ret, irq;
++
++	base = devm_platform_ioremap_resource(pdev, 0);
++	if (IS_ERR(base))
++		return PTR_ERR(base);
++
++	spi_clk = devm_clk_get(&pdev->dev, "spi");
++	if (IS_ERR(spi_clk))
++		return PTR_ERR(spi_clk);
++
++	ctlr_clk = devm_clk_get(&pdev->dev, "sf");
++	if (IS_ERR(ctlr_clk))
++		return PTR_ERR(ctlr_clk);
++
++	buffer = devm_kmalloc(&pdev->dev,
++			      MTK_NOR_BOUNCE_BUF_SIZE + MTK_NOR_DMA_ALIGN,
++			      GFP_KERNEL);
++	if (!buffer)
++		return -ENOMEM;
++
++	if ((ulong)buffer & MTK_NOR_DMA_ALIGN_MASK)
++		buffer = (u8 *)(((ulong)buffer + MTK_NOR_DMA_ALIGN) &
++				~MTK_NOR_DMA_ALIGN_MASK);
++
++	ctlr = spi_alloc_master(&pdev->dev, sizeof(*sp));
++	if (!ctlr) {
++		dev_err(&pdev->dev, "failed to allocate spi controller\n");
++		return -ENOMEM;
++	}
++
++	ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
++	ctlr->dev.of_node = pdev->dev.of_node;
++	ctlr->max_message_size = mtk_max_msg_size;
++	ctlr->mem_ops = &mtk_nor_mem_ops;
++	ctlr->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_DUAL | SPI_TX_QUAD;
++	ctlr->num_chipselect = 1;
++	ctlr->setup = mtk_nor_setup;
++	ctlr->transfer_one_message = mtk_nor_transfer_one_message;
++
++	dev_set_drvdata(&pdev->dev, ctlr);
++
++	sp = spi_controller_get_devdata(ctlr);
++	sp->base = base;
++	sp->buffer = buffer;
++	sp->has_irq = false;
++	sp->wbuf_en = false;
++	sp->ctlr = ctlr;
++	sp->dev = &pdev->dev;
++	sp->spi_clk = spi_clk;
++	sp->ctlr_clk = ctlr_clk;
++
++	irq = platform_get_irq_optional(pdev, 0);
++	if (irq < 0) {
++		dev_warn(sp->dev, "IRQ not available.");
++	} else {
++		writel(MTK_NOR_IRQ_MASK, base + MTK_NOR_REG_IRQ_STAT);
++		writel(0, base + MTK_NOR_REG_IRQ_EN);
++		ret = devm_request_irq(sp->dev, irq, mtk_nor_irq_handler, 0,
++				       pdev->name, sp);
++		if (ret < 0) {
++			dev_warn(sp->dev, "failed to request IRQ.");
++		} else {
++			init_completion(&sp->op_done);
++			sp->has_irq = true;
++		}
++	}
++
++	ret = mtk_nor_init(sp);
++	if (ret < 0) {
++		kfree(ctlr);
++		return ret;
++	}
++
++	dev_info(&pdev->dev, "spi frequency: %d Hz\n", sp->spi_freq);
++
++	return devm_spi_register_controller(&pdev->dev, ctlr);
++}
++
++static int mtk_nor_remove(struct platform_device *pdev)
++{
++	struct spi_controller *ctlr;
++	struct mtk_nor *sp;
++
++	ctlr = dev_get_drvdata(&pdev->dev);
++	sp = spi_controller_get_devdata(ctlr);
++
++	mtk_nor_disable_clk(sp);
++
++	return 0;
++}
++
++static struct platform_driver mtk_nor_driver = {
++	.driver = {
++		.name = DRIVER_NAME,
++		.of_match_table = mtk_nor_match,
++	},
++	.probe = mtk_nor_probe,
++	.remove = mtk_nor_remove,
++};
++
++module_platform_driver(mtk_nor_driver);
++
++MODULE_DESCRIPTION("Mediatek SPI NOR controller driver");
++MODULE_AUTHOR("Chuanhong Guo <gch981213@gmail.com>");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0003-switch-add-mt7531.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0003-switch-add-mt7531.patch
new file mode 100644
index 0000000..6fae99c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0003-switch-add-mt7531.patch
@@ -0,0 +1,19 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -329,6 +329,8 @@ config RTL8367B_PHY
+ 
+ endif # RTL8366_SMI
+ 
++source "drivers/net/phy/mtk/mt753x/Kconfig"
++
+ comment "MII PHY device drivers"
+ 
+ config SFP
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -109,3 +109,5 @@ obj-$(CONFIG_STE10XP)		+= ste10Xp.o
+ obj-$(CONFIG_TERANETICS_PHY)	+= teranetics.o
+ obj-$(CONFIG_VITESSE_PHY)	+= vitesse.o
+ obj-$(CONFIG_XILINX_GMII2RGMII) += xilinx_gmii2rgmii.o
++obj-$(CONFIG_MT753X_GSW)        += mtk/mt753x/
++
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0005-dts-mt7622-add-gsw.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0005-dts-mt7622-add-gsw.patch
new file mode 100644
index 0000000..d40cbfb
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0005-dts-mt7622-add-gsw.patch
@@ -0,0 +1,258 @@
+--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
+@@ -53,6 +53,13 @@
+ 		};
+ 	};
+ 
++	gsw: gsw@0 {
++		compatible = "mediatek,mt753x";
++		mediatek,ethsys = <&ethsys>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++	};
++
+ 	leds {
+ 		compatible = "gpio-leds";
+ 
+@@ -146,6 +153,36 @@
+ 	};
+ };
+ 
++&gsw {
++	mediatek,mdio = <&mdio>;
++	mediatek,portmap = "wllll";
++	mediatek,mdio_master_pinmux = <0>;
++	reset-gpios = <&pio 54 0>;
++	interrupt-parent = <&pio>;
++	interrupts = <53 IRQ_TYPE_LEVEL_HIGH>;
++	status = "okay";
++
++	port5: port@5 {
++		compatible = "mediatek,mt753x-port";
++		reg = <5>;
++		phy-mode = "rgmii";
++		fixed-link {
++			speed = <1000>;
++			full-duplex;
++		};
++	};
++
++	port6: port@6 {
++		compatible = "mediatek,mt753x-port";
++		reg = <6>;
++		phy-mode = "sgmii";
++		fixed-link {
++			speed = <2500>;
++			full-duplex;
++		};
++	};
++};
++
+ &i2c1 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&i2c1_pins>;
+--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
+@@ -1,7 +1,6 @@
+ /*
+- * Copyright (c) 2017 MediaTek Inc.
+- * Author: Ming Huang <ming.huang@mediatek.com>
+- *	   Sean Wang <sean.wang@mediatek.com>
++ * Copyright (c) 2018 MediaTek Inc.
++ * Author: Ryder Lee <ryder.lee@mediatek.com>
+  *
+  * SPDX-License-Identifier: (GPL-2.0 OR MIT)
+  */
+@@ -14,7 +13,7 @@
+ #include "mt6380.dtsi"
+ 
+ / {
+-	model = "MediaTek MT7622 RFB1 board";
++	model = "MT7622_MT7531 RFB";
+ 	compatible = "mediatek,mt7622-rfb1", "mediatek,mt7622";
+ 
+ 	aliases {
+@@ -23,7 +22,7 @@
+ 
+ 	chosen {
+ 		stdout-path = "serial0:115200n8";
+-		bootargs = "earlycon=uart8250,mmio32,0x11002000 swiotlb=512";
++		bootargs = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n1 swiotlb=512";
+ 	};
+ 
+ 	cpus {
+@@ -40,23 +39,36 @@
+ 
+ 	gpio-keys {
+ 		compatible = "gpio-keys";
+-		poll-interval = <100>;
+ 
+ 		factory {
+ 			label = "factory";
+ 			linux,code = <BTN_0>;
+-			gpios = <&pio 0 0>;
++			gpios = <&pio 0 GPIO_ACTIVE_LOW>;
+ 		};
+ 
+ 		wps {
+ 			label = "wps";
+ 			linux,code = <KEY_WPS_BUTTON>;
+-			gpios = <&pio 102 0>;
++			gpios = <&pio 102 GPIO_ACTIVE_LOW>;
++		};
++	};
++
++	leds {
++		compatible = "gpio-leds";
++
++		green {
++			label = "bpi-r64:pio:green";
++			gpios = <&pio 89 GPIO_ACTIVE_HIGH>;
++		};
++
++		red {
++			label = "bpi-r64:pio:red";
++			gpios = <&pio 88 GPIO_ACTIVE_HIGH>;
+ 		};
+ 	};
+ 
+ 	memory {
+-		reg = <0 0x40000000 0 0x20000000>;
++		reg = <0 0x40000000 0 0x40000000>;
+ 	};
+ 
+ 	reg_1p8v: regulator-1p8v {
+@@ -101,23 +113,82 @@
+ };
+ 
+ &eth {
+-	pinctrl-names = "default";
+-	pinctrl-0 = <&eth_pins>;
+ 	status = "okay";
++	gmac0: mac@0 {
++		compatible = "mediatek,eth-mac";
++		reg = <0>;
++		phy-mode = "2500base-x";
++
++		fixed-link {
++			speed = <2500>;
++			full-duplex;
++			pause;
++		};
++	};
+ 
+ 	gmac1: mac@1 {
+ 		compatible = "mediatek,eth-mac";
+ 		reg = <1>;
+-		phy-handle = <&phy5>;
++		phy-mode = "rgmii";
++
++		fixed-link {
++			speed = <1000>;
++			full-duplex;
++			pause;
++		};
+ 	};
+ 
+-	mdio-bus {
++	mdio: mdio-bus {
+ 		#address-cells = <1>;
+ 		#size-cells = <0>;
+ 
+-		phy5: ethernet-phy@5 {
+-			reg = <5>;
+-			phy-mode = "sgmii";
++		switch@0 {
++			compatible = "mediatek,mt7531";
++			reg = <0>;
++			reset-gpios = <&pio 54 0>;
++
++			ports {
++				#address-cells = <1>;
++				#size-cells = <0>;
++
++				port@0 {
++					reg = <0>;
++					label = "lan1";
++				};
++
++				port@1 {
++					reg = <1>;
++					label = "lan2";
++				};
++
++				port@2 {
++					reg = <2>;
++					label = "lan3";
++				};
++
++				port@3 {
++					reg = <3>;
++					label = "lan4";
++				};
++
++				port@4 {
++					reg = <4>;
++					label = "wan";
++				};
++
++				port@6 {
++					reg = <6>;
++					label = "cpu";
++					ethernet = <&gmac0>;
++					phy-mode = "2500base-x";
++
++					fixed-link {
++						speed = <2500>;
++						full-duplex;
++						pause;
++					};
++				};
++			};
+ 		};
+ 	};
+ };
+@@ -185,15 +256,28 @@
+ 
+ &pcie {
+ 	pinctrl-names = "default";
+-	pinctrl-0 = <&pcie0_pins>;
++	pinctrl-0 = <&pcie0_pins>, <&pcie1_pins>;
+ 	status = "okay";
+ 
+ 	pcie@0,0 {
+ 		status = "okay";
+ 	};
++
++	pcie@1,0 {
++		status = "okay";
++	};
+ };
+ 
+ &pio {
++	/* Attention: GPIO 90 is used to switch between PCIe@1,0 and
++	 * SATA functions. i.e. output-high: PCIe, output-low: SATA
++	 */
++	asm_sel {
++		gpio-hog;
++		gpios = <90 GPIO_ACTIVE_HIGH>;
++		output-high;
++	};
++
+ 	/* eMMC is shared pin with parallel NAND */
+ 	emmc_pins_default: emmc-pins-default {
+ 		mux {
+@@ -460,11 +544,11 @@
+ };
+ 
+ &sata {
+-	status = "okay";
++	status = "disable";
+ };
+ 
+ &sata_phy {
+-	status = "okay";
++	status = "disable";
+ };
+ 
+ &spi0 {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0005-dts-mt7629-add-gsw.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0005-dts-mt7629-add-gsw.patch
new file mode 100644
index 0000000..773a69f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0005-dts-mt7629-add-gsw.patch
@@ -0,0 +1,67 @@
+--- a/arch/arm/boot/dts/mt7629-rfb.dts
++++ b/arch/arm/boot/dts/mt7629-rfb.dts
+@@ -18,6 +18,7 @@
+ 
+ 	chosen {
+ 		stdout-path = "serial0:115200n8";
++		bootargs = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n8";
+ 	};
+ 
+ 	gpio-keys {
+@@ -36,6 +37,13 @@
+ 		};
+ 	};
+ 
++	gsw: gsw@0 {
++		compatible = "mediatek,mt753x";
++		mediatek,ethsys = <&ethsys>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++	};
++
+ 	memory@40000000 {
+ 		device_type = "memory";
+ 		reg = <0x40000000 0x10000000>;
+@@ -69,6 +77,7 @@
+ 	gmac0: mac@0 {
+ 		compatible = "mediatek,eth-mac";
+ 		reg = <0>;
++		mtd-mac-address = <&factory 0x2a>;
+ 		phy-mode = "2500base-x";
+ 		fixed-link {
+ 			speed = <2500>;
+@@ -80,6 +89,7 @@
+ 	gmac1: mac@1 {
+ 		compatible = "mediatek,eth-mac";
+ 		reg = <1>;
++		mtd-mac-address = <&factory 0x24>;
+ 		phy-mode = "gmii";
+ 		phy-handle = <&phy0>;
+ 	};
+@@ -93,6 +103,26 @@
+ 		};
+ 	};
+ };
++
++&gsw {
++	mediatek,mdio = <&mdio>;
++	mediatek,portmap = "llllw";
++	mediatek,mdio_master_pinmux = <0>;
++	reset-gpios = <&pio 28 0>;
++	interrupt-parent = <&pio>;
++	interrupts = <6 IRQ_TYPE_LEVEL_HIGH>;
++	status = "okay";
++
++	port6: port@6 {
++		compatible = "mediatek,mt753x-port";
++		reg = <6>;
++		phy-mode = "sgmii";
++		fixed-link {
++			speed = <2500>;
++			full-duplex;
++		};
++	};
++};
+ 
+ &i2c {
+ 	pinctrl-names = "default";
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0006-dts-fix-bpi2-console.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0006-dts-fix-bpi2-console.patch
new file mode 100644
index 0000000..b725117
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0006-dts-fix-bpi2-console.patch
@@ -0,0 +1,10 @@
+--- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
++++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
+@@ -19,6 +19,7 @@
+ 
+ 	chosen {
+ 		stdout-path = "serial2:115200n8";
++		bootargs = "console=ttyS2,115200n8";
+ 	};
+ 
+ 	cpus {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0006-dts-fix-bpi64-console.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0006-dts-fix-bpi64-console.patch
new file mode 100644
index 0000000..07a2eae
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0006-dts-fix-bpi64-console.patch
@@ -0,0 +1,11 @@
+--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
+@@ -22,7 +22,7 @@
+ 
+ 	chosen {
+ 		stdout-path = "serial0:115200n8";
+-		bootargs = "earlycon=uart8250,mmio32,0x11002000 swiotlb=512";
++		bootargs = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n1 swiotlb=512";
+ 	};
+ 
+ 	cpus {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0010-dts-mt7629-rfb-fix-firmware-partition.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0010-dts-mt7629-rfb-fix-firmware-partition.patch
new file mode 100644
index 0000000..5d0a19e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0010-dts-mt7629-rfb-fix-firmware-partition.patch
@@ -0,0 +1,13 @@
+--- a/arch/arm/boot/dts/mt7629-rfb.dts
++++ b/arch/arm/boot/dts/mt7629-rfb.dts
+@@ -163,8 +163,9 @@
+ 			};
+ 
+ 			partition@b0000 {
+-				label = "kernel";
++				label = "firmware";
+ 				reg = <0xb0000 0xb50000>;
++				compatible = "denx,fit";
+ 			};
+ 		};
+ 	};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0020-dts-mt7622-enable-new-mtk-snand-for-ubi.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0020-dts-mt7622-enable-new-mtk-snand-for-ubi.patch
new file mode 100644
index 0000000..3a9e061
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0020-dts-mt7622-enable-new-mtk-snand-for-ubi.patch
@@ -0,0 +1,23 @@
+--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
+@@ -567,6 +567,20 @@
+ 		status = "disabled";
+ 	};
+ 
++	snand: snfi@1100d000 {
++		compatible = "mediatek,mt7622-snand";
++		reg = <0 0x1100d000 0 0x1000>, <0 0x1100e000 0 0x1000>;
++		reg-names = "nfi", "ecc";
++		interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>;
++		clocks = <&pericfg CLK_PERI_NFI_PD>,
++			 <&pericfg CLK_PERI_SNFI_PD>,
++			 <&pericfg CLK_PERI_NFIECC_PD>;
++		clock-names = "nfi_clk", "pad_clk", "ecc_clk";
++		#address-cells = <1>;
++		#size-cells = <0>;
++		status = "disabled";
++	};
++
+ 	nor_flash: spi@11014000 {
+ 		compatible = "mediatek,mt7622-nor",
+ 			     "mediatek,mt8173-nor";
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0021-dts-mt7622-remove-cooling-device.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0021-dts-mt7622-remove-cooling-device.patch
new file mode 100644
index 0000000..efcc14f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0021-dts-mt7622-remove-cooling-device.patch
@@ -0,0 +1,31 @@
+--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
+@@ -167,25 +167,6 @@
+ 				};
+ 			};
+ 
+-			cooling-maps {
+-				map0 {
+-					trip = <&cpu_passive>;
+-					cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-							 <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+-				};
+-
+-				map1 {
+-					trip = <&cpu_active>;
+-					cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-							 <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+-				};
+-
+-				map2 {
+-					trip = <&cpu_hot>;
+-					cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+-							 <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+-				};
+-			};
+ 		};
+ 	};
+ 
+-- 
+2.29.2
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0100-hwnat_Kconfig_Makefile.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0100-hwnat_Kconfig_Makefile.patch
new file mode 100755
index 0000000..e0ac7ab
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0100-hwnat_Kconfig_Makefile.patch
@@ -0,0 +1,33 @@
+--- a/net/Kconfig	2020-04-29 17:25:49.750444000 +0800
++++ b/net/Kconfig	2020-04-29 17:42:40.950424000 +0800
+@@ -451,6 +451,18 @@
+ 	  migration of VMs with direct attached VFs by failing over to the
+ 	  paravirtual datapath when the VF is unplugged.
+ 
++config HW_NAT
++	bool "HW NAT support"
++	default n
++	---help---
++	 This feature provides a fast path to support network lan/wan nat.
++	 If you need hw_nat engine to reduce cpu loading, please say Y.
++
++	  Note that the answer to this question doesn't directly affect the
++	  kernel: saying N will just cause the configurator to skip all
++	  the questions about Mediatek Ethernet devices. If you say Y,
++	  you will be asked for your specific card in the following questions.
++
+ endif   # if NET
+ 
+ # Used by archs to tell that they support BPF JIT compiler plus which flavour.
+--- a/net/Makefile	2020-04-23 16:36:46.000000000 +0800
++++ b/net/Makefile	2020-04-29 17:42:58.106487000 +0800
+@@ -62,6 +62,9 @@
+ obj-$(CONFIG_6LOWPAN)		+= 6lowpan/
+ obj-$(CONFIG_IEEE802154)	+= ieee802154/
+ obj-$(CONFIG_MAC802154)		+= mac802154/
++ifeq ($(CONFIG_HW_NAT),y)
++obj-y                           += nat/foe_hook/
++endif
+ 
+ ifeq ($(CONFIG_NET),y)
+ obj-$(CONFIG_SYSCTL)		+= sysctl_net.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0101-add-mtk-wifi-utility-rbus.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0101-add-mtk-wifi-utility-rbus.patch
new file mode 100644
index 0000000..211324b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0101-add-mtk-wifi-utility-rbus.patch
@@ -0,0 +1,11 @@
+diff -urN a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
+--- a/drivers/net/wireless/Makefile	2020-05-08 12:16:50.030922777 +0800
++++ b/drivers/net/wireless/Makefile	2020-05-08 12:16:55.718755223 +0800
+@@ -12,6 +12,7 @@
+ obj-$(CONFIG_WLAN_VENDOR_INTERSIL) += intersil/
+ obj-$(CONFIG_WLAN_VENDOR_MARVELL) += marvell/
+ obj-$(CONFIG_WLAN_VENDOR_MEDIATEK) += mediatek/
++obj-y += wifi_utility/
+ obj-$(CONFIG_WLAN_VENDOR_RALINK) += ralink/
+ obj-$(CONFIG_WLAN_VENDOR_REALTEK) += realtek/
+ obj-$(CONFIG_WLAN_VENDOR_RSI) += rsi/
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0111-mt7986-trng-add-rng-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0111-mt7986-trng-add-rng-support.patch
new file mode 100644
index 0000000..1b132a3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0111-mt7986-trng-add-rng-support.patch
@@ -0,0 +1,46 @@
+From 6d4a858d6f7db2a86f6513a543feb8f7b8a8b4c1 Mon Sep 17 00:00:00 2001
+From: "Mingming.Su" <Mingming.Su@mediatek.com>
+Date: Wed, 30 Jun 2021 16:59:32 +0800
+Subject: [PATCH] mt7986: trng: add rng support
+
+1. Add trng compatible name for MT7986
+2. Fix mtk_rng_wait_ready() function
+
+Signed-off-by: Mingming.Su <Mingming.Su@mediatek.com>
+---
+ drivers/char/hw_random/mtk-rng.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/char/hw_random/mtk-rng.c b/drivers/char/hw_random/mtk-rng.c
+index e649be5a5..496adb0a0 100644
+--- a/drivers/char/hw_random/mtk-rng.c
++++ b/drivers/char/hw_random/mtk-rng.c
+@@ -22,7 +22,7 @@
+ #define RNG_AUTOSUSPEND_TIMEOUT		100
+ 
+ #define USEC_POLL			2
+-#define TIMEOUT_POLL			20
++#define TIMEOUT_POLL			60
+ 
+ #define RNG_CTRL			0x00
+ #define RNG_EN				BIT(0)
+@@ -77,7 +77,7 @@ static bool mtk_rng_wait_ready(struct hwrng *rng, bool wait)
+ 		readl_poll_timeout_atomic(priv->base + RNG_CTRL, ready,
+ 					  ready & RNG_READY, USEC_POLL,
+ 					  TIMEOUT_POLL);
+-	return !!ready;
++	return !!(ready & RNG_READY);
+ }
+ 
+ static int mtk_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+@@ -181,6 +181,7 @@ static UNIVERSAL_DEV_PM_OPS(mtk_rng_pm_ops, mtk_rng_runtime_suspend,
+ #endif	/* CONFIG_PM */
+ 
+ static const struct of_device_id mtk_rng_match[] = {
++	{ .compatible = "mediatek,mt7986-rng" },
+ 	{ .compatible = "mediatek,mt7623-rng" },
+ 	{},
+ };
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0200-show_model_name_in_cpuinfo_on_arm64.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0200-show_model_name_in_cpuinfo_on_arm64.patch
new file mode 100644
index 0000000..98e5ab6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0200-show_model_name_in_cpuinfo_on_arm64.patch
@@ -0,0 +1,16 @@
+Index: linux-5.4.70/arch/arm64/kernel/cpuinfo.c
+===================================================================
+--- linux-5.4.70.orig/arch/arm64/kernel/cpuinfo.c
++++ linux-5.4.70/arch/arm64/kernel/cpuinfo.c
+@@ -139,9 +139,8 @@ static int c_show(struct seq_file *m, vo
+ 		 * "processor".  Give glibc what it expects.
+ 		 */
+ 		seq_printf(m, "processor\t: %d\n", i);
+-		if (compat)
+-			seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n",
+-				   MIDR_REVISION(midr), COMPAT_ELF_PLATFORM);
++		seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n",
++			   MIDR_REVISION(midr), COMPAT_ELF_PLATFORM);
+ 
+ 		seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
+ 			   loops_per_jiffy / (500000UL/HZ),
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0226-phy-phy-mtk-tphy-Add-hifsys-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0226-phy-phy-mtk-tphy-Add-hifsys-support.patch
new file mode 100644
index 0000000..f2647e8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0226-phy-phy-mtk-tphy-Add-hifsys-support.patch
@@ -0,0 +1,66 @@
+From 28f9a5e2a3f5441ab5594669ed82da11e32277a9 Mon Sep 17 00:00:00 2001
+From: Kristian Evensen <kristian.evensen@gmail.com>
+Date: Mon, 30 Apr 2018 14:38:01 +0200
+Subject: [PATCH] phy: phy-mtk-tphy: Add hifsys-support
+
+---
+ drivers/phy/mediatek/phy-mtk-tphy.c | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+--- a/drivers/phy/mediatek/phy-mtk-tphy.c
++++ b/drivers/phy/mediatek/phy-mtk-tphy.c
+@@ -15,6 +15,8 @@
+ #include <linux/of_device.h>
+ #include <linux/phy/phy.h>
+ #include <linux/platform_device.h>
++#include <linux/mfd/syscon.h>
++#include <linux/regmap.h>
+ 
+ /* version V1 sub-banks offset base address */
+ /* banks shared by multiple phys */
+@@ -263,6 +265,9 @@
+ #define RG_CDR_BIRLTD0_GEN3_MSK		GENMASK(4, 0)
+ #define RG_CDR_BIRLTD0_GEN3_VAL(x)	(0x1f & (x))
+ 
++#define HIF_SYSCFG1			0x14
++#define HIF_SYSCFG1_PHY2_MASK		(0x3 << 20)
++
+ enum mtk_phy_version {
+ 	MTK_PHY_V1 = 1,
+ 	MTK_PHY_V2,
+@@ -310,6 +315,7 @@ struct mtk_tphy {
+ 	struct clk *u3phya_ref;	/* reference clock of usb3 anolog phy */
+ 	const struct mtk_phy_pdata *pdata;
+ 	struct mtk_phy_instance **phys;
++	struct regmap *hif;
+ 	int nphys;
+ 	int src_ref_clk; /* MHZ, reference clock for slew rate calibrate */
+ 	int src_coef; /* coefficient for slew rate calibrate */
+@@ -629,6 +635,10 @@ static void pcie_phy_instance_init(struc
+ 	if (tphy->pdata->version != MTK_PHY_V1)
+ 		return;
+ 
++	if (tphy->hif)
++		regmap_update_bits(tphy->hif, HIF_SYSCFG1,
++				   HIF_SYSCFG1_PHY2_MASK, 0);
++
+ 	tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG0);
+ 	tmp &= ~(P3A_RG_XTAL_EXT_PE1H | P3A_RG_XTAL_EXT_PE2H);
+ 	tmp |= P3A_RG_XTAL_EXT_PE1H_VAL(0x2) | P3A_RG_XTAL_EXT_PE2H_VAL(0x2);
+@@ -1114,6 +1124,16 @@ static int mtk_tphy_probe(struct platfor
+ 		&tphy->src_ref_clk);
+ 	device_property_read_u32(dev, "mediatek,src-coef", &tphy->src_coef);
+ 
++	if (of_find_property(np, "mediatek,phy-switch", NULL)) {
++		tphy->hif = syscon_regmap_lookup_by_phandle(np,
++							    "mediatek,phy-switch");
++		if (IS_ERR(tphy->hif)) {
++			dev_err(&pdev->dev,
++				"missing \"mediatek,phy-switch\" phandle\n");
++			return PTR_ERR(tphy->hif);
++		}
++	}
++
+ 	port = 0;
+ 	for_each_child_of_node(np, child_np) {
+ 		struct mtk_phy_instance *instance;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0227-arm-dts-Add-Unielec-U7623-DTS.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0227-arm-dts-Add-Unielec-U7623-DTS.patch
new file mode 100644
index 0000000..3cb1dab
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0227-arm-dts-Add-Unielec-U7623-DTS.patch
@@ -0,0 +1,387 @@
+From 004eb24e939b5b31f828333f37fb5cb2a877d6f2 Mon Sep 17 00:00:00 2001
+From: Kristian Evensen <kristian.evensen@gmail.com>
+Date: Sun, 17 Jun 2018 14:41:47 +0200
+Subject: [PATCH] arm: dts: Add Unielec U7623 DTS
+
+---
+ arch/arm/boot/dts/Makefile                         |   1 +
+ .../dts/mt7623a-unielec-u7623-02-emmc-512m.dts     |  18 +
+ .../boot/dts/mt7623a-unielec-u7623-02-emmc.dtsi    | 366 +++++++++++++++++++++
+ 3 files changed, 385 insertions(+)
+ create mode 100644 arch/arm/boot/dts/mt7623a-unielec-u7623-02-emmc-512m.dts
+ create mode 100644 arch/arm/boot/dts/mt7623a-unielec-u7623-02-emmc.dtsi
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -1272,6 +1272,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \
+ 	mt7623a-rfb-nand.dtb \
+ 	mt7623n-rfb-emmc.dtb \
+ 	mt7623n-bananapi-bpi-r2.dtb \
++	mt7623a-unielec-u7623-02-emmc-512m.dtb \
+ 	mt7629-rfb.dtb \
+ 	mt8127-moose.dtb \
+ 	mt8135-evbp1.dtb
+--- /dev/null
++++ b/arch/arm/boot/dts/mt7623a-unielec-u7623-02-emmc-512m.dts
+@@ -0,0 +1,18 @@
++/*
++ * Copyright 2018 Kristian Evensen <kristian.evensen@gmail.com>
++ *
++ * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++ */
++
++/dts-v1/;
++#include "mt7623a-unielec-u7623-02-emmc.dtsi"
++
++/ {
++	model = "UniElec U7623-02 eMMC (512M RAM)";
++	compatible = "unielec,u7623-02-emmc-512m", "unielec,u7623-02-emmc", "mediatek,mt7623";
++
++	memory@80000000 {
++		device_type = "memory";
++		reg = <0 0x80000000 0 0x20000000>;
++	};
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/mt7623a-unielec-u7623-02-emmc.dtsi
+@@ -0,0 +1,340 @@
++/*
++ * Copyright 2018 Kristian Evensen <kristian.evensen@gmail.com>
++ *
++ * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++ */
++
++#include <dt-bindings/input/input.h>
++#include "mt7623.dtsi"
++#include "mt6323.dtsi"
++
++/ {
++	compatible = "unielec,u7623-02-emmc", "mediatek,mt7623";
++
++	aliases {
++		serial2 = &uart2;
++	};
++
++	chosen {
++		bootargs = "root=/dev/mmcblk0p2 rootfstype=squashfs,f2fs console=ttyS0,115200 blkdevparts=mmcblk0:3M@6M(recovery),256M@9M(root)";
++		stdout-path = "serial2:115200n8";
++	};
++
++	cpus {
++		cpu@0 {
++			proc-supply = <&mt6323_vproc_reg>;
++		};
++
++		cpu@1 {
++			proc-supply = <&mt6323_vproc_reg>;
++		};
++
++		cpu@2 {
++			proc-supply = <&mt6323_vproc_reg>;
++		};
++
++		cpu@3 {
++			proc-supply = <&mt6323_vproc_reg>;
++		};
++	};
++
++	reg_1p8v: regulator-1p8v {
++		compatible = "regulator-fixed";
++		regulator-name = "fixed-1.8V";
++		regulator-min-microvolt = <1800000>;
++		regulator-max-microvolt = <1800000>;
++		regulator-boot-on;
++		regulator-always-on;
++	};
++
++	reg_3p3v: regulator-3p3v {
++		compatible = "regulator-fixed";
++		regulator-name = "fixed-3.3V";
++		regulator-min-microvolt = <3300000>;
++		regulator-max-microvolt = <3300000>;
++		regulator-boot-on;
++		regulator-always-on;
++	};
++
++	reg_5v: regulator-5v {
++		compatible = "regulator-fixed";
++		regulator-name = "fixed-5V";
++		regulator-min-microvolt = <5000000>;
++		regulator-max-microvolt = <5000000>;
++		regulator-boot-on;
++		regulator-always-on;
++	};
++
++	gpio-keys {
++		compatible = "gpio-keys";
++		pinctrl-names = "default";
++		pinctrl-0 = <&key_pins_a>;
++
++		factory {
++			label = "factory";
++			linux,code = <KEY_RESTART>;
++			gpios = <&pio 256 GPIO_ACTIVE_LOW>;
++		};
++	};
++
++	leds {
++		compatible = "gpio-leds";
++		pinctrl-names = "default";
++		pinctrl-0 = <&led_pins_unielec>;
++
++		led3 {
++			label = "u7623-01:green:led3";
++			gpios = <&pio 14 GPIO_ACTIVE_LOW>;
++		};
++
++		led4 {
++			label = "u7623-01:green:led4";
++			gpios = <&pio 15 GPIO_ACTIVE_LOW>;
++		};
++	};
++};
++
++&crypto {
++	status = "okay";
++};
++
++&eth {
++	status = "okay";
++
++	gmac0: mac@0 {
++		compatible = "mediatek,eth-mac";
++		reg = <0>;
++		phy-mode = "trgmii";
++
++		fixed-link {
++			speed = <1000>;
++			full-duplex;
++			pause;
++		};
++	};
++
++	mdio: mdio-bus {
++		#address-cells = <1>;
++		#size-cells = <0>;
++
++		mt7530: switch@0 {
++			compatible = "mediatek,mt7530";
++		};
++	};
++};
++
++&mt7530 {
++	compatible = "mediatek,mt7530";
++	#address-cells = <1>;
++	#size-cells = <0>;
++	reg = <0>;
++	pinctrl-names = "default";
++	mediatek,mcm;
++	resets = <&ethsys 2>;
++	reset-names = "mcm";
++	core-supply = <&mt6323_vpa_reg>;
++	io-supply = <&mt6323_vemc3v3_reg>;
++
++	dsa,mii-bus = <&mdio>;
++
++	ports {
++		#address-cells = <1>;
++		#size-cells = <0>;
++		reg = <0>;
++
++		port@0 {
++			reg = <0>;
++			label = "lan0";
++			cpu = <&cpu_port0>;
++		};
++
++		port@1 {
++			reg = <1>;
++			label = "lan1";
++			cpu = <&cpu_port0>;
++		};
++
++		port@2 {
++			reg = <2>;
++			label = "lan2";
++			cpu = <&cpu_port0>;
++		};
++
++		port@3 {
++			reg = <3>;
++			label = "lan3";
++			cpu = <&cpu_port0>;
++		};
++
++		port@4 {
++			reg = <4>;
++			label = "wan";
++			cpu = <&cpu_port0>;
++		};
++
++		cpu_port0: port@6 {
++			reg = <6>;
++			label = "cpu";
++			ethernet = <&gmac0>;
++			phy-mode = "trgmii";
++
++			fixed-link {
++				speed = <1000>;
++				full-duplex;
++			};
++		};
++	};
++};
++
++&mmc0 {
++	pinctrl-names = "default", "state_uhs";
++	pinctrl-0 = <&mmc0_pins_default>;
++	pinctrl-1 = <&mmc0_pins_uhs>;
++	status = "okay";
++	bus-width = <8>;
++	max-frequency = <50000000>;
++	cap-mmc-highspeed;
++	vmmc-supply = <&reg_3p3v>;
++	vqmmc-supply = <&reg_1p8v>;
++	non-removable;
++};
++
++&pio {
++	key_pins_a: keys-alt {
++		pins-keys {
++			pinmux = <MT7623_PIN_256_GPIO256_FUNC_GPIO256>,
++				 <MT7623_PIN_257_GPIO257_FUNC_GPIO257>;
++			input-enable;
++		};
++	};
++
++	led_pins_unielec: leds-unielec {
++		pins-leds {
++			pinmux = <MT7623_PIN_14_GPIO14_FUNC_GPIO14>,
++				 <MT7623_PIN_15_GPIO15_FUNC_GPIO15>;
++		};
++	};
++
++	mmc0_pins_default: mmc0default {
++		pins_cmd_dat {
++			pinmux = <MT7623_PIN_111_MSDC0_DAT7_FUNC_MSDC0_DAT7>,
++				 <MT7623_PIN_112_MSDC0_DAT6_FUNC_MSDC0_DAT6>,
++				 <MT7623_PIN_113_MSDC0_DAT5_FUNC_MSDC0_DAT5>,
++				 <MT7623_PIN_114_MSDC0_DAT4_FUNC_MSDC0_DAT4>,
++				 <MT7623_PIN_118_MSDC0_DAT3_FUNC_MSDC0_DAT3>,
++				 <MT7623_PIN_119_MSDC0_DAT2_FUNC_MSDC0_DAT2>,
++				 <MT7623_PIN_120_MSDC0_DAT1_FUNC_MSDC0_DAT1>,
++				 <MT7623_PIN_121_MSDC0_DAT0_FUNC_MSDC0_DAT0>,
++				 <MT7623_PIN_116_MSDC0_CMD_FUNC_MSDC0_CMD>;
++			input-enable;
++			bias-pull-up;
++		};
++
++		pins_clk {
++			pinmux = <MT7623_PIN_117_MSDC0_CLK_FUNC_MSDC0_CLK>;
++			bias-pull-down;
++		};
++
++		pins_rst {
++			pinmux = <MT7623_PIN_115_MSDC0_RSTB_FUNC_MSDC0_RSTB>;
++			bias-pull-up;
++		};
++	};
++
++	mmc0_pins_uhs: mmc0 {
++		pins_cmd_dat {
++			pinmux = <MT7623_PIN_111_MSDC0_DAT7_FUNC_MSDC0_DAT7>,
++				 <MT7623_PIN_112_MSDC0_DAT6_FUNC_MSDC0_DAT6>,
++				 <MT7623_PIN_113_MSDC0_DAT5_FUNC_MSDC0_DAT5>,
++				 <MT7623_PIN_114_MSDC0_DAT4_FUNC_MSDC0_DAT4>,
++				 <MT7623_PIN_118_MSDC0_DAT3_FUNC_MSDC0_DAT3>,
++				 <MT7623_PIN_119_MSDC0_DAT2_FUNC_MSDC0_DAT2>,
++				 <MT7623_PIN_120_MSDC0_DAT1_FUNC_MSDC0_DAT1>,
++				 <MT7623_PIN_121_MSDC0_DAT0_FUNC_MSDC0_DAT0>,
++				 <MT7623_PIN_116_MSDC0_CMD_FUNC_MSDC0_CMD>;
++			input-enable;
++			drive-strength = <MTK_DRIVE_2mA>;
++			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
++		};
++
++		pins_clk {
++			pinmux = <MT7623_PIN_117_MSDC0_CLK_FUNC_MSDC0_CLK>;
++			drive-strength = <MTK_DRIVE_2mA>;
++			bias-pull-down = <MTK_PUPD_SET_R1R0_01>;
++		};
++
++		pins_rst {
++			pinmux = <MT7623_PIN_115_MSDC0_RSTB_FUNC_MSDC0_RSTB>;
++			bias-pull-up;
++		};
++	};
++
++	pcie_default: pcie_pin_default {
++		pins_cmd_dat {
++			pinmux = <MT7623_PIN_208_AUD_EXT_CK1_FUNC_PCIE0_PERST_N>,
++				 <MT7623_PIN_209_AUD_EXT_CK2_FUNC_PCIE1_PERST_N>;
++			bias-disable;
++		};
++	};
++};
++
++&pwm {
++	pinctrl-names = "default";
++	pinctrl-0 = <&pwm_pins_a>;
++	status = "okay";
++};
++
++&pwrap {
++	mt6323 {
++		mt6323led: led {
++			compatible = "mediatek,mt6323-led";
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			led@0 {
++				reg = <0>;
++				label = "led0";
++			};
++		};
++	};
++};
++
++&uart2 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&uart2_pins_b>;
++	status = "okay";
++};
++
++&usb1 {
++	vusb33-supply = <&reg_3p3v>;
++	vbus-supply = <&reg_3p3v>;
++	status = "okay";
++};
++
++&u3phy1 {
++	status = "okay";
++};
++
++&u3phy2 {
++	status = "okay";
++	mediatek,phy-switch = <&hifsys>;
++};
++
++&pcie {
++	pinctrl-names = "default";
++	pinctrl-0 = <&pcie_default>;
++	status = "okay";
++
++	pcie@1,0 {
++		status = "okay";
++	};
++
++	pcie@2,0 {
++		status = "okay";
++	};
++};
++
++&pcie1_phy {
++	status = "okay";
++};
++
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0301-mtd-mtk-ecc-move-mtk-ecc-header-file-to-include-mtd.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0301-mtd-mtk-ecc-move-mtk-ecc-header-file-to-include-mtd.patch
new file mode 100644
index 0000000..d9ab339
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0301-mtd-mtk-ecc-move-mtk-ecc-header-file-to-include-mtd.patch
@@ -0,0 +1,139 @@
+From a2479dc254ebe31c84fbcfda73f35e2321576494 Mon Sep 17 00:00:00 2001
+From: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
+Date: Tue, 19 Mar 2019 13:57:38 +0800
+Subject: [PATCH 1/6] mtd: mtk ecc: move mtk ecc header file to include/mtd
+
+Change-Id: I8dc1d30e21b40d68ef5efd9587012f82970156a5
+Signed-off-by: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
+---
+ drivers/mtd/nand/raw/mtk_ecc.c                        | 3 +--
+ drivers/mtd/nand/raw/mtk_nand.c                       | 2 +-
+ {drivers/mtd/nand/raw => include/linux/mtd}/mtk_ecc.h | 0
+ 3 files changed, 2 insertions(+), 3 deletions(-)
+ rename {drivers/mtd/nand/raw => include/linux/mtd}/mtk_ecc.h (100%)
+
+--- a/drivers/mtd/nand/raw/mtk_ecc.c
++++ b/drivers/mtd/nand/raw/mtk_ecc.c
+@@ -15,8 +15,7 @@
+ #include <linux/of.h>
+ #include <linux/of_platform.h>
+ #include <linux/mutex.h>
+-
+-#include "mtk_ecc.h"
++#include <linux/mtd/mtk_ecc.h>
+ 
+ #define ECC_IDLE_MASK		BIT(0)
+ #define ECC_IRQ_EN		BIT(0)
+--- a/drivers/mtd/nand/raw/mtk_nand.c
++++ b/drivers/mtd/nand/raw/mtk_nand.c
+@@ -17,7 +17,7 @@
+ #include <linux/iopoll.h>
+ #include <linux/of.h>
+ #include <linux/of_device.h>
+-#include "mtk_ecc.h"
++#include <linux/mtd/mtk_ecc.h>
+ 
+ /* NAND controller register definition */
+ #define NFI_CNFG		(0x00)
+--- /dev/null
++++ b/include/linux/mtd/mtk_ecc.h
+@@ -0,0 +1,49 @@
++/*
++ * MTK SDG1 ECC controller
++ *
++ * Copyright (c) 2016 Mediatek
++ * Authors:	Xiaolei Li		<xiaolei.li@mediatek.com>
++ *		Jorge Ramirez-Ortiz	<jorge.ramirez-ortiz@linaro.org>
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef __DRIVERS_MTD_NAND_MTK_ECC_H__
++#define __DRIVERS_MTD_NAND_MTK_ECC_H__
++
++#include <linux/types.h>
++
++enum mtk_ecc_mode {ECC_DMA_MODE = 0, ECC_NFI_MODE = 1};
++enum mtk_ecc_operation {ECC_ENCODE, ECC_DECODE};
++
++struct device_node;
++struct mtk_ecc;
++
++struct mtk_ecc_stats {
++	u32 corrected;
++	u32 bitflips;
++	u32 failed;
++};
++
++struct mtk_ecc_config {
++	enum mtk_ecc_operation op;
++	enum mtk_ecc_mode mode;
++	dma_addr_t addr;
++	u32 strength;
++	u32 sectors;
++	u32 len;
++};
++
++int mtk_ecc_encode(struct mtk_ecc *, struct mtk_ecc_config *, u8 *, u32);
++void mtk_ecc_get_stats(struct mtk_ecc *, struct mtk_ecc_stats *, int);
++int mtk_ecc_wait_done(struct mtk_ecc *, enum mtk_ecc_operation);
++int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *);
++void mtk_ecc_disable(struct mtk_ecc *);
++void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p);
++unsigned int mtk_ecc_get_parity_bits(struct mtk_ecc *ecc);
++
++struct mtk_ecc *of_mtk_ecc_get(struct device_node *);
++void mtk_ecc_release(struct mtk_ecc *);
++
++#endif
+--- a/drivers/mtd/nand/raw/mtk_ecc.h
++++ /dev/null
+@@ -1,47 +0,0 @@
+-/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+-/*
+- * MTK SDG1 ECC controller
+- *
+- * Copyright (c) 2016 Mediatek
+- * Authors:	Xiaolei Li		<xiaolei.li@mediatek.com>
+- *		Jorge Ramirez-Ortiz	<jorge.ramirez-ortiz@linaro.org>
+- */
+-
+-#ifndef __DRIVERS_MTD_NAND_MTK_ECC_H__
+-#define __DRIVERS_MTD_NAND_MTK_ECC_H__
+-
+-#include <linux/types.h>
+-
+-enum mtk_ecc_mode {ECC_DMA_MODE = 0, ECC_NFI_MODE = 1};
+-enum mtk_ecc_operation {ECC_ENCODE, ECC_DECODE};
+-
+-struct device_node;
+-struct mtk_ecc;
+-
+-struct mtk_ecc_stats {
+-	u32 corrected;
+-	u32 bitflips;
+-	u32 failed;
+-};
+-
+-struct mtk_ecc_config {
+-	enum mtk_ecc_operation op;
+-	enum mtk_ecc_mode mode;
+-	dma_addr_t addr;
+-	u32 strength;
+-	u32 sectors;
+-	u32 len;
+-};
+-
+-int mtk_ecc_encode(struct mtk_ecc *, struct mtk_ecc_config *, u8 *, u32);
+-void mtk_ecc_get_stats(struct mtk_ecc *, struct mtk_ecc_stats *, int);
+-int mtk_ecc_wait_done(struct mtk_ecc *, enum mtk_ecc_operation);
+-int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *);
+-void mtk_ecc_disable(struct mtk_ecc *);
+-void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p);
+-unsigned int mtk_ecc_get_parity_bits(struct mtk_ecc *ecc);
+-
+-struct mtk_ecc *of_mtk_ecc_get(struct device_node *);
+-void mtk_ecc_release(struct mtk_ecc *);
+-
+-#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0306-spi-spi-mem-MediaTek-Add-SPI-NAND-Flash-interface-dr.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0306-spi-spi-mem-MediaTek-Add-SPI-NAND-Flash-interface-dr.patch
new file mode 100644
index 0000000..b3672e5
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0306-spi-spi-mem-MediaTek-Add-SPI-NAND-Flash-interface-dr.patch
@@ -0,0 +1,1246 @@
+From 1ecb38eabd90efe93957d0a822a167560c39308a Mon Sep 17 00:00:00 2001
+From: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
+Date: Wed, 20 Mar 2019 16:19:51 +0800
+Subject: [PATCH 6/6] spi: spi-mem: MediaTek: Add SPI NAND Flash interface
+ driver for MediaTek MT7622
+
+Change-Id: I3e78406bb9b46b0049d3988a5c71c7069e4f809c
+Signed-off-by: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
+---
+ drivers/spi/Kconfig        |    9 +
+ drivers/spi/Makefile       |    1 +
+ drivers/spi/spi-mtk-snfi.c | 1183 ++++++++++++++++++++++++++++++++++++
+ 3 files changed, 1193 insertions(+)
+ create mode 100644 drivers/spi/spi-mtk-snfi.c
+
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -60,6 +60,7 @@ obj-$(CONFIG_SPI_MPC512x_PSC)		+= spi-mp
+ obj-$(CONFIG_SPI_MPC52xx_PSC)		+= spi-mpc52xx-psc.o
+ obj-$(CONFIG_SPI_MPC52xx)		+= spi-mpc52xx.o
+ obj-$(CONFIG_SPI_MT65XX)                += spi-mt65xx.o
++obj-$(CONFIG_SPI_MTK_SNFI)              += spi-mtk-snfi.o
+ obj-$(CONFIG_SPI_MT7621)		+= spi-mt7621.o
+ obj-$(CONFIG_SPI_MTK_NOR)		+= spi-mtk-nor.o
+ obj-$(CONFIG_SPI_MXIC)			+= spi-mxic.o
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -427,6 +427,15 @@ config SPI_MT65XX
+ 	  say Y or M here.If you are not sure, say N.
+ 	  SPI drivers for Mediatek MT65XX and MT81XX series ARM SoCs.
+ 
++config SPI_MTK_SNFI
++	tristate "MediaTek SPI NAND interface"
++	select MTD_SPI_NAND
++	help
++	  This selects the SPI NAND FLASH interface(SNFI),
++	  which could be found on MediaTek Soc.
++	  Say Y or M here.If you are not sure, say N.
++	  Note Parallel Nand and SPI NAND is alternative on MediaTek SoCs.
++
+ config SPI_MT7621
+ 	tristate "MediaTek MT7621 SPI Controller"
+ 	depends on RALINK || COMPILE_TEST
+--- /dev/null
++++ b/drivers/spi/spi-mtk-snfi.c
+@@ -0,0 +1,1200 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Driver for MediaTek SPI Nand interface
++ *
++ * Copyright (C) 2018 MediaTek Inc.
++ * Authors:	Xiangsheng Hou	<xiangsheng.hou@mediatek.com>
++ *
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <linux/interrupt.h>
++#include <linux/iopoll.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/mtk_ecc.h>
++#include <linux/mtd/spinand.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi-mem.h>
++
++/* NAND controller register definition */
++/* NFI control */
++#define NFI_CNFG		0x00
++#define		CNFG_DMA		BIT(0)
++#define		CNFG_READ_EN		BIT(1)
++#define		CNFG_DMA_BURST_EN	BIT(2)
++#define		CNFG_BYTE_RW		BIT(6)
++#define		CNFG_HW_ECC_EN		BIT(8)
++#define		CNFG_AUTO_FMT_EN	BIT(9)
++#define		CNFG_OP_PROGRAM		(3UL << 12)
++#define		CNFG_OP_CUST		(6UL << 12)
++#define NFI_PAGEFMT		0x04
++#define		PAGEFMT_512		0
++#define		PAGEFMT_2K		1
++#define		PAGEFMT_4K		2
++#define		PAGEFMT_FDM_SHIFT	8
++#define		PAGEFMT_FDM_ECC_SHIFT	12
++#define NFI_CON			0x08
++#define		CON_FIFO_FLUSH		BIT(0)
++#define		CON_NFI_RST		BIT(1)
++#define		CON_BRD			BIT(8)
++#define		CON_BWR			BIT(9)
++#define		CON_SEC_SHIFT		12
++#define NFI_INTR_EN		0x10
++#define		INTR_AHB_DONE_EN	BIT(6)
++#define NFI_INTR_STA		0x14
++#define NFI_CMD			0x20
++#define NFI_STA			0x60
++#define		STA_EMP_PAGE		BIT(12)
++#define		NAND_FSM_MASK		(0x1f << 24)
++#define		NFI_FSM_MASK		(0xf << 16)
++#define NFI_ADDRCNTR		0x70
++#define		CNTR_MASK		GENMASK(16, 12)
++#define		ADDRCNTR_SEC_SHIFT	12
++#define		ADDRCNTR_SEC(val) \
++		(((val) & CNTR_MASK) >> ADDRCNTR_SEC_SHIFT)
++#define NFI_STRADDR		0x80
++#define NFI_BYTELEN		0x84
++#define NFI_CSEL		0x90
++#define NFI_FDML(x)		(0xa0 + (x) * sizeof(u32) * 2)
++#define NFI_FDMM(x)		(0xa4 + (x) * sizeof(u32) * 2)
++#define NFI_MASTER_STA		0x224
++#define		MASTER_STA_MASK		0x0fff
++/* NFI_SPI control */
++#define SNFI_MAC_OUTL		0x504
++#define SNFI_MAC_INL		0x508
++#define SNFI_RD_CTL2		0x510
++#define		RD_CMD_MASK		0x00ff
++#define		RD_DUMMY_SHIFT		8
++#define SNFI_RD_CTL3		0x514
++#define		RD_ADDR_MASK		0xffff
++#define SNFI_MISC_CTL		0x538
++#define		RD_MODE_X2		BIT(16)
++#define		RD_MODE_X4		(2UL << 16)
++#define		RD_QDUAL_IO		(4UL << 16)
++#define		RD_MODE_MASK		(7UL << 16)
++#define		RD_CUSTOM_EN		BIT(6)
++#define		WR_CUSTOM_EN		BIT(7)
++#define		WR_X4_EN		BIT(20)
++#define		SW_RST			BIT(28)
++#define SNFI_MISC_CTL2		0x53c
++#define		WR_LEN_SHIFT		16
++#define SNFI_PG_CTL1		0x524
++#define		WR_LOAD_CMD_SHIFT	8
++#define SNFI_PG_CTL2		0x528
++#define		WR_LOAD_ADDR_MASK	0xffff
++#define SNFI_MAC_CTL		0x500
++#define		MAC_WIP			BIT(0)
++#define		MAC_WIP_READY		BIT(1)
++#define		MAC_TRIG		BIT(2)
++#define		MAC_EN			BIT(3)
++#define		MAC_SIO_SEL		BIT(4)
++#define SNFI_STA_CTL1		0x550
++#define		SPI_STATE_IDLE		0xf
++#define SNFI_CNFG		0x55c
++#define		SNFI_MODE_EN		BIT(0)
++#define SNFI_GPRAM_DATA		0x800
++#define		SNFI_GPRAM_MAX_LEN	16
++
++/* Dummy command trigger NFI to spi mode */
++#define NAND_CMD_DUMMYREAD	0x00
++#define NAND_CMD_DUMMYPROG	0x80
++
++#define MTK_TIMEOUT		500000
++#define MTK_RESET_TIMEOUT	1000000
++#define MTK_SNFC_MIN_SPARE	16
++#define KB(x)			((x) * 1024UL)
++
++/*
++ * supported spare size of each IP.
++ * order should be the same with the spare size bitfiled defination of
++ * register NFI_PAGEFMT.
++ */
++static const u8 spare_size_mt7622[] = {
++	16, 26, 27, 28
++};
++
++struct mtk_snfi_caps {
++	const u8 *spare_size;
++	u8 num_spare_size;
++	u32 nand_sec_size;
++	u8 nand_fdm_size;
++	u8 nand_fdm_ecc_size;
++	u8 ecc_parity_bits;
++	u8 pageformat_spare_shift;
++	u8 bad_mark_swap;
++};
++
++struct mtk_snfi_bad_mark_ctl {
++	void (*bm_swap)(struct spi_mem *mem, u8 *buf, int raw);
++	u32 sec;
++	u32 pos;
++};
++
++struct mtk_snfi_nand_chip {
++	struct mtk_snfi_bad_mark_ctl bad_mark;
++	u32 spare_per_sector;
++};
++
++struct mtk_snfi_clk {
++	struct clk *nfi_clk;
++	struct clk *spi_clk;
++};
++
++struct mtk_snfi {
++	const struct mtk_snfi_caps *caps;
++	struct mtk_snfi_nand_chip snfi_nand;
++	struct mtk_snfi_clk clk;
++	struct mtk_ecc_config ecc_cfg;
++	struct mtk_ecc *ecc;
++	struct completion done;
++	struct device *dev;
++
++	void __iomem *regs;
++
++	u8 *buffer;
++};
++
++static inline u8 *oob_ptr(struct spi_mem *mem, int i)
++{
++	struct spinand_device *spinand = spi_mem_get_drvdata(mem);
++	struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++	struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand;
++	u8 *poi;
++
++	/* map the sector's FDM data to free oob:
++	 * the beginning of the oob area stores the FDM data of bad mark
++	 */
++
++	if (i < snfi_nand->bad_mark.sec)
++		poi = spinand->oobbuf + (i + 1) * snfi->caps->nand_fdm_size;
++	else if (i == snfi_nand->bad_mark.sec)
++		poi = spinand->oobbuf;
++	else
++		poi = spinand->oobbuf + i * snfi->caps->nand_fdm_size;
++
++	return poi;
++}
++
++static inline int mtk_data_len(struct spi_mem *mem)
++{
++	struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++	struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand;
++
++	return snfi->caps->nand_sec_size + snfi_nand->spare_per_sector;
++}
++
++static inline u8 *mtk_oob_ptr(struct spi_mem *mem,
++			      const u8 *p, int i)
++{
++	struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++
++	return (u8 *)p + i * mtk_data_len(mem) + snfi->caps->nand_sec_size;
++}
++
++static void mtk_snfi_bad_mark_swap(struct spi_mem *mem,
++				   u8 *buf, int raw)
++{
++	struct spinand_device *spinand = spi_mem_get_drvdata(mem);
++	struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++	struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand;
++	u32 bad_pos = snfi_nand->bad_mark.pos;
++
++	if (raw)
++		bad_pos += snfi_nand->bad_mark.sec * mtk_data_len(mem);
++	else
++		bad_pos += snfi_nand->bad_mark.sec * snfi->caps->nand_sec_size;
++
++	swap(spinand->oobbuf[0], buf[bad_pos]);
++}
++
++static void mtk_snfi_set_bad_mark_ctl(struct mtk_snfi_bad_mark_ctl *bm_ctl,
++				      struct spi_mem *mem)
++{
++	struct spinand_device *spinand = spi_mem_get_drvdata(mem);
++	struct mtd_info *mtd = spinand_to_mtd(spinand);
++
++	bm_ctl->bm_swap = mtk_snfi_bad_mark_swap;
++	bm_ctl->sec = mtd->writesize / mtk_data_len(mem);
++	bm_ctl->pos = mtd->writesize % mtk_data_len(mem);
++}
++
++static void mtk_snfi_mac_enable(struct mtk_snfi *snfi)
++{
++	u32 mac;
++
++	mac = readl(snfi->regs + SNFI_MAC_CTL);
++	mac &= ~MAC_SIO_SEL;
++	mac |= MAC_EN;
++
++	writel(mac, snfi->regs + SNFI_MAC_CTL);
++}
++
++static int mtk_snfi_mac_trigger(struct mtk_snfi *snfi)
++{
++	u32 mac, reg;
++	int ret = 0;
++
++	mac = readl(snfi->regs + SNFI_MAC_CTL);
++	mac |= MAC_TRIG;
++	writel(mac, snfi->regs + SNFI_MAC_CTL);
++
++	ret = readl_poll_timeout_atomic(snfi->regs + SNFI_MAC_CTL, reg,
++					reg & MAC_WIP_READY, 10,
++					MTK_TIMEOUT);
++	if (ret < 0) {
++		dev_err(snfi->dev, "polling wip ready for read timeout\n");
++		return -EIO;
++	}
++
++	ret = readl_poll_timeout_atomic(snfi->regs + SNFI_MAC_CTL, reg,
++					!(reg & MAC_WIP), 10,
++					MTK_TIMEOUT);
++	if (ret < 0) {
++		dev_err(snfi->dev, "polling flash update timeout\n");
++		return -EIO;
++	}
++
++	return ret;
++}
++
++static void mtk_snfi_mac_leave(struct mtk_snfi *snfi)
++{
++	u32 mac;
++
++	mac = readl(snfi->regs + SNFI_MAC_CTL);
++	mac &= ~(MAC_TRIG | MAC_EN | MAC_SIO_SEL);
++	writel(mac, snfi->regs + SNFI_MAC_CTL);
++}
++
++static int mtk_snfi_mac_op(struct mtk_snfi *snfi)
++{
++	int ret = 0;
++
++	mtk_snfi_mac_enable(snfi);
++
++	ret = mtk_snfi_mac_trigger(snfi);
++	if (ret)
++		return ret;
++
++	mtk_snfi_mac_leave(snfi);
++
++	return ret;
++}
++
++static irqreturn_t mtk_snfi_irq(int irq, void *id)
++{
++	struct mtk_snfi *snfi = id;
++	u16 sta, ien;
++
++	sta = readw(snfi->regs + NFI_INTR_STA);
++	ien = readw(snfi->regs + NFI_INTR_EN);
++
++	if (!(sta & ien))
++		return IRQ_NONE;
++
++	writew(~sta & ien, snfi->regs + NFI_INTR_EN);
++	complete(&snfi->done);
++
++	return IRQ_HANDLED;
++}
++
++static int mtk_snfi_enable_clk(struct device *dev, struct mtk_snfi_clk *clk)
++{
++	int ret;
++
++	ret = clk_prepare_enable(clk->nfi_clk);
++	if (ret) {
++		dev_err(dev, "failed to enable nfi clk\n");
++		return ret;
++	}
++
++	ret = clk_prepare_enable(clk->spi_clk);
++	if (ret) {
++		dev_err(dev, "failed to enable spi clk\n");
++		clk_disable_unprepare(clk->nfi_clk);
++		return ret;
++	}
++
++	return 0;
++}
++
++static void mtk_snfi_disable_clk(struct mtk_snfi_clk *clk)
++{
++	clk_disable_unprepare(clk->nfi_clk);
++	clk_disable_unprepare(clk->spi_clk);
++}
++
++static int mtk_snfi_reset(struct mtk_snfi *snfi)
++{
++	u32 val;
++	int ret;
++
++	/* SW reset controller */
++	val = readl(snfi->regs + SNFI_MISC_CTL) | SW_RST;
++	writel(val, snfi->regs + SNFI_MISC_CTL);
++
++	ret = readw_poll_timeout(snfi->regs + SNFI_STA_CTL1, val,
++				 !(val & SPI_STATE_IDLE), 50,
++				 MTK_RESET_TIMEOUT);
++	if (ret) {
++		dev_warn(snfi->dev, "spi state active in reset [0x%x] = 0x%x\n",
++			 SNFI_STA_CTL1, val);
++		return ret;
++	}
++
++	val = readl(snfi->regs + SNFI_MISC_CTL);
++	val &= ~SW_RST;
++	writel(val, snfi->regs + SNFI_MISC_CTL);
++
++	/* reset all registers and force the NFI master to terminate */
++	writew(CON_FIFO_FLUSH | CON_NFI_RST, snfi->regs + NFI_CON);
++	ret = readw_poll_timeout(snfi->regs + NFI_STA, val,
++				 !(val & (NFI_FSM_MASK | NAND_FSM_MASK)), 50,
++				 MTK_RESET_TIMEOUT);
++	if (ret) {
++		dev_warn(snfi->dev, "nfi active in reset [0x%x] = 0x%x\n",
++			 NFI_STA, val);
++		return ret;
++	}
++
++	return 0;
++}
++
++static int mtk_snfi_set_spare_per_sector(struct spinand_device *spinand,
++					 const struct mtk_snfi_caps *caps,
++					 u32 *sps)
++{
++	struct mtd_info *mtd = spinand_to_mtd(spinand);
++	const u8 *spare = caps->spare_size;
++	u32 sectors, i, closest_spare = 0;
++
++	sectors = mtd->writesize / caps->nand_sec_size;
++	*sps = mtd->oobsize / sectors;
++
++	if (*sps < MTK_SNFC_MIN_SPARE)
++		return -EINVAL;
++
++	for (i = 0; i < caps->num_spare_size; i++) {
++		if (*sps >= spare[i] && spare[i] >= spare[closest_spare]) {
++			closest_spare = i;
++			if (*sps == spare[i])
++				break;
++		}
++	}
++
++	*sps = spare[closest_spare];
++
++	return 0;
++}
++
++static void mtk_snfi_read_fdm_data(struct spi_mem *mem,
++				   u32 sectors)
++{
++	struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++	const struct mtk_snfi_caps *caps = snfi->caps;
++	u32 vall, valm;
++	int i, j;
++	u8 *oobptr;
++
++	for (i = 0; i < sectors; i++) {
++		oobptr = oob_ptr(mem, i);
++		vall = readl(snfi->regs + NFI_FDML(i));
++		valm = readl(snfi->regs + NFI_FDMM(i));
++
++		for (j = 0; j < caps->nand_fdm_size; j++)
++			oobptr[j] = (j >= 4 ? valm : vall) >> ((j % 4) * 8);
++	}
++}
++
++static void mtk_snfi_write_fdm_data(struct spi_mem *mem,
++				    u32 sectors)
++{
++	struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++	const struct mtk_snfi_caps *caps = snfi->caps;
++	u32 vall, valm;
++	int i, j;
++	u8 *oobptr;
++
++	for (i = 0; i < sectors; i++) {
++		oobptr = oob_ptr(mem, i);
++		vall = 0;
++		valm = 0;
++		for (j = 0; j < 8; j++) {
++			if (j < 4)
++				vall |= (j < caps->nand_fdm_size ? oobptr[j] :
++					 0xff) << (j * 8);
++			else
++				valm |= (j < caps->nand_fdm_size ? oobptr[j] :
++					 0xff) << ((j - 4) * 8);
++		}
++		writel(vall, snfi->regs + NFI_FDML(i));
++		writel(valm, snfi->regs + NFI_FDMM(i));
++	}
++}
++
++static int mtk_snfi_update_ecc_stats(struct spi_mem *mem,
++				     u8 *buf, u32 sectors)
++{
++	struct spinand_device *spinand = spi_mem_get_drvdata(mem);
++	struct mtd_info *mtd = spinand_to_mtd(spinand);
++	struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++	struct mtk_ecc_stats stats;
++	int rc, i;
++
++	rc = readl(snfi->regs + NFI_STA) & STA_EMP_PAGE;
++	if (rc) {
++		memset(buf, 0xff, sectors * snfi->caps->nand_sec_size);
++		for (i = 0; i < sectors; i++)
++			memset(spinand->oobbuf, 0xff,
++			       snfi->caps->nand_fdm_size);
++		return 0;
++	}
++
++	mtk_ecc_get_stats(snfi->ecc, &stats, sectors);
++	mtd->ecc_stats.corrected += stats.corrected;
++	mtd->ecc_stats.failed += stats.failed;
++
++	return 0;
++}
++
++static int mtk_snfi_hw_runtime_config(struct spi_mem *mem)
++{
++	struct spinand_device *spinand = spi_mem_get_drvdata(mem);
++	struct mtd_info *mtd = spinand_to_mtd(spinand);
++	struct nand_device *nand = mtd_to_nanddev(mtd);
++	struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++	const struct mtk_snfi_caps *caps = snfi->caps;
++	struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand;
++	u32 fmt, spare, i = 0;
++	int ret;
++
++	ret = mtk_snfi_set_spare_per_sector(spinand, caps, &spare);
++	if (ret)
++		return ret;
++
++	/* calculate usable oob bytes for ecc parity data */
++	snfi_nand->spare_per_sector = spare;
++	spare -= caps->nand_fdm_size;
++
++	nand->memorg.oobsize = snfi_nand->spare_per_sector
++		* (mtd->writesize / caps->nand_sec_size);
++	mtd->oobsize = nanddev_per_page_oobsize(nand);
++
++	snfi->ecc_cfg.strength = (spare << 3) / caps->ecc_parity_bits;
++	mtk_ecc_adjust_strength(snfi->ecc, &snfi->ecc_cfg.strength);
++
++	switch (mtd->writesize) {
++	case 512:
++		fmt = PAGEFMT_512;
++		break;
++	case KB(2):
++		fmt = PAGEFMT_2K;
++		break;
++	case KB(4):
++		fmt = PAGEFMT_4K;
++		break;
++	default:
++		dev_err(snfi->dev, "invalid page len: %d\n", mtd->writesize);
++		return -EINVAL;
++	}
++
++	/* Setup PageFormat */
++	while (caps->spare_size[i] != snfi_nand->spare_per_sector) {
++		i++;
++		if (i == (caps->num_spare_size - 1)) {
++			dev_err(snfi->dev, "invalid spare size %d\n",
++				snfi_nand->spare_per_sector);
++			return -EINVAL;
++		}
++	}
++
++	fmt |= i << caps->pageformat_spare_shift;
++	fmt |= caps->nand_fdm_size << PAGEFMT_FDM_SHIFT;
++	fmt |= caps->nand_fdm_ecc_size << PAGEFMT_FDM_ECC_SHIFT;
++	writel(fmt, snfi->regs + NFI_PAGEFMT);
++
++	snfi->ecc_cfg.len = caps->nand_sec_size + caps->nand_fdm_ecc_size;
++
++	mtk_snfi_set_bad_mark_ctl(&snfi_nand->bad_mark, mem);
++
++	return 0;
++}
++
++static int mtk_snfi_read_from_cache(struct spi_mem *mem,
++				    const struct spi_mem_op *op, int oob_on)
++{
++	struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++	struct spinand_device *spinand = spi_mem_get_drvdata(mem);
++	struct mtd_info *mtd = spinand_to_mtd(spinand);
++	u32 sectors = mtd->writesize / snfi->caps->nand_sec_size;
++	struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand;
++	u32 reg, len, col_addr = 0;
++	int dummy_cycle, ret;
++	dma_addr_t dma_addr;
++
++	len = sectors * (snfi->caps->nand_sec_size
++	      + snfi_nand->spare_per_sector);
++
++	dma_addr = dma_map_single(snfi->dev, snfi->buffer,
++				  len, DMA_FROM_DEVICE);
++	ret = dma_mapping_error(snfi->dev, dma_addr);
++	if (ret) {
++		dev_err(snfi->dev, "dma mapping error\n");
++		return -EINVAL;
++	}
++
++	/* set Read cache command and dummy cycle */
++	dummy_cycle = (op->dummy.nbytes << 3) >> (ffs(op->dummy.buswidth) - 1);
++	reg = ((op->cmd.opcode & RD_CMD_MASK) |
++	       (dummy_cycle << RD_DUMMY_SHIFT));
++	writel(reg, snfi->regs + SNFI_RD_CTL2);
++
++	writel((col_addr & RD_ADDR_MASK), snfi->regs + SNFI_RD_CTL3);
++
++	reg = readl(snfi->regs + SNFI_MISC_CTL);
++	reg |= RD_CUSTOM_EN;
++	reg &= ~(RD_MODE_MASK | WR_X4_EN);
++
++	/* set data and addr buswidth */
++	if (op->data.buswidth == 4)
++		reg |= RD_MODE_X4;
++	else if (op->data.buswidth == 2)
++		reg |= RD_MODE_X2;
++
++	if (op->addr.buswidth == 4 || op->addr.buswidth == 2)
++		reg |= RD_QDUAL_IO;
++	writel(reg, snfi->regs + SNFI_MISC_CTL);
++
++	writel(len, snfi->regs + SNFI_MISC_CTL2);
++	writew(sectors << CON_SEC_SHIFT, snfi->regs + NFI_CON);
++	reg = readw(snfi->regs + NFI_CNFG);
++	reg |= CNFG_READ_EN | CNFG_DMA_BURST_EN | CNFG_DMA | CNFG_OP_CUST;
++
++	if (!oob_on) {
++		reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN;
++		writew(reg, snfi->regs + NFI_CNFG);
++
++		snfi->ecc_cfg.mode = ECC_NFI_MODE;
++		snfi->ecc_cfg.sectors = sectors;
++		snfi->ecc_cfg.op = ECC_DECODE;
++		ret = mtk_ecc_enable(snfi->ecc, &snfi->ecc_cfg);
++		if (ret) {
++			dev_err(snfi->dev, "ecc enable failed\n");
++			/* clear NFI_CNFG */
++			reg &= ~(CNFG_READ_EN | CNFG_DMA_BURST_EN | CNFG_DMA |
++				CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
++			writew(reg, snfi->regs + NFI_CNFG);
++			goto out;
++		}
++	} else {
++		writew(reg, snfi->regs + NFI_CNFG);
++	}
++
++	writel(lower_32_bits(dma_addr), snfi->regs + NFI_STRADDR);
++	readw(snfi->regs + NFI_INTR_STA);
++	writew(INTR_AHB_DONE_EN, snfi->regs + NFI_INTR_EN);
++
++	init_completion(&snfi->done);
++
++	/* set dummy command to trigger NFI enter SPI mode */
++	writew(NAND_CMD_DUMMYREAD, snfi->regs + NFI_CMD);
++	reg = readl(snfi->regs + NFI_CON) | CON_BRD;
++	writew(reg, snfi->regs + NFI_CON);
++
++	ret = wait_for_completion_timeout(&snfi->done, msecs_to_jiffies(500));
++	if (!ret) {
++		dev_err(snfi->dev, "read ahb done timeout\n");
++		writew(0, snfi->regs + NFI_INTR_EN);
++		ret = -ETIMEDOUT;
++		goto out;
++	}
++
++	ret = readl_poll_timeout_atomic(snfi->regs + NFI_BYTELEN, reg,
++					ADDRCNTR_SEC(reg) >= sectors, 10,
++					MTK_TIMEOUT);
++	if (ret < 0) {
++		dev_err(snfi->dev, "polling read byte len timeout\n");
++		ret = -EIO;
++	} else {
++		if (!oob_on) {
++			ret = mtk_ecc_wait_done(snfi->ecc, ECC_DECODE);
++			if (ret) {
++				dev_warn(snfi->dev, "wait ecc done timeout\n");
++			} else {
++				mtk_snfi_update_ecc_stats(mem, snfi->buffer,
++							  sectors);
++				mtk_snfi_read_fdm_data(mem, sectors);
++			}
++		}
++	}
++
++	if (oob_on)
++		goto out;
++
++	mtk_ecc_disable(snfi->ecc);
++out:
++	dma_unmap_single(snfi->dev, dma_addr, len, DMA_FROM_DEVICE);
++	writel(0, snfi->regs + NFI_CON);
++	writel(0, snfi->regs + NFI_CNFG);
++	reg = readl(snfi->regs + SNFI_MISC_CTL);
++	reg &= ~RD_CUSTOM_EN;
++	writel(reg, snfi->regs + SNFI_MISC_CTL);
++
++	return ret;
++}
++
++static int mtk_snfi_write_to_cache(struct spi_mem *mem,
++				   const struct spi_mem_op *op,
++				   int oob_on)
++{
++	struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++	struct spinand_device *spinand = spi_mem_get_drvdata(mem);
++	struct mtd_info *mtd = spinand_to_mtd(spinand);
++	u32 sectors = mtd->writesize / snfi->caps->nand_sec_size;
++	struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand;
++	u32 reg, len, col_addr = 0;
++	dma_addr_t dma_addr;
++	int ret;
++
++	len = sectors * (snfi->caps->nand_sec_size
++	      + snfi_nand->spare_per_sector);
++
++	dma_addr = dma_map_single(snfi->dev, snfi->buffer, len,
++				  DMA_TO_DEVICE);
++	ret = dma_mapping_error(snfi->dev, dma_addr);
++	if (ret) {
++		dev_err(snfi->dev, "dma mapping error\n");
++		return -EINVAL;
++	}
++
++	/* set program load cmd and address */
++	reg = (op->cmd.opcode << WR_LOAD_CMD_SHIFT);
++	writel(reg, snfi->regs + SNFI_PG_CTL1);
++	writel(col_addr & WR_LOAD_ADDR_MASK, snfi->regs + SNFI_PG_CTL2);
++
++	reg = readl(snfi->regs + SNFI_MISC_CTL);
++	reg |= WR_CUSTOM_EN;
++	reg &= ~(RD_MODE_MASK | WR_X4_EN);
++
++	if (op->data.buswidth == 4)
++		reg |= WR_X4_EN;
++	writel(reg, snfi->regs + SNFI_MISC_CTL);
++
++	writel(len << WR_LEN_SHIFT, snfi->regs + SNFI_MISC_CTL2);
++	writew(sectors << CON_SEC_SHIFT, snfi->regs + NFI_CON);
++
++	reg = readw(snfi->regs + NFI_CNFG);
++	reg &= ~(CNFG_READ_EN | CNFG_BYTE_RW);
++	reg |= CNFG_DMA | CNFG_DMA_BURST_EN | CNFG_OP_PROGRAM;
++
++	if (!oob_on) {
++		reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN;
++		writew(reg, snfi->regs + NFI_CNFG);
++
++		snfi->ecc_cfg.mode = ECC_NFI_MODE;
++		snfi->ecc_cfg.op = ECC_ENCODE;
++		ret = mtk_ecc_enable(snfi->ecc, &snfi->ecc_cfg);
++		if (ret) {
++			dev_err(snfi->dev, "ecc enable failed\n");
++			/* clear NFI_CNFG */
++			reg &= ~(CNFG_DMA_BURST_EN | CNFG_DMA |
++					CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
++			writew(reg, snfi->regs + NFI_CNFG);
++			dma_unmap_single(snfi->dev, dma_addr, len,
++					 DMA_FROM_DEVICE);
++			goto out;
++		}
++		/* write OOB into the FDM registers (OOB area in MTK NAND) */
++		mtk_snfi_write_fdm_data(mem, sectors);
++	} else {
++		writew(reg, snfi->regs + NFI_CNFG);
++	}
++	writel(lower_32_bits(dma_addr), snfi->regs + NFI_STRADDR);
++	readw(snfi->regs + NFI_INTR_STA);
++	writew(INTR_AHB_DONE_EN, snfi->regs + NFI_INTR_EN);
++
++	init_completion(&snfi->done);
++
++	/* set dummy command to trigger NFI enter SPI mode */
++	writew(NAND_CMD_DUMMYPROG, snfi->regs + NFI_CMD);
++	reg = readl(snfi->regs + NFI_CON) | CON_BWR;
++	writew(reg, snfi->regs + NFI_CON);
++
++	ret = wait_for_completion_timeout(&snfi->done, msecs_to_jiffies(500));
++	if (!ret) {
++		dev_err(snfi->dev, "custom program done timeout\n");
++		writew(0, snfi->regs + NFI_INTR_EN);
++		ret = -ETIMEDOUT;
++		goto ecc_disable;
++	}
++
++	ret = readl_poll_timeout_atomic(snfi->regs + NFI_ADDRCNTR, reg,
++					ADDRCNTR_SEC(reg) >= sectors,
++					10, MTK_TIMEOUT);
++	if (ret)
++		dev_err(snfi->dev, "hwecc write timeout\n");
++
++ecc_disable:
++	mtk_ecc_disable(snfi->ecc);
++
++out:
++	dma_unmap_single(snfi->dev, dma_addr, len, DMA_TO_DEVICE);
++	writel(0, snfi->regs + NFI_CON);
++	writel(0, snfi->regs + NFI_CNFG);
++	reg = readl(snfi->regs + SNFI_MISC_CTL);
++	reg &= ~WR_CUSTOM_EN;
++	writel(reg, snfi->regs + SNFI_MISC_CTL);
++
++	return ret;
++}
++
++static int mtk_snfi_read(struct spi_mem *mem,
++			 const struct spi_mem_op *op)
++{
++	struct spinand_device *spinand = spi_mem_get_drvdata(mem);
++	struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++	struct mtd_info *mtd = spinand_to_mtd(spinand);
++	struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand;
++	u32 col_addr = op->addr.val;
++	int i, ret, sectors, oob_on = false;
++
++	if (col_addr == mtd->writesize)
++		oob_on = true;
++
++	ret = mtk_snfi_read_from_cache(mem, op, oob_on);
++	if (ret) {
++		dev_warn(snfi->dev, "read from cache fail\n");
++		return ret;
++	}
++
++	sectors = mtd->writesize / snfi->caps->nand_sec_size;
++	for (i = 0; i < sectors; i++) {
++		if (oob_on)
++			memcpy(oob_ptr(mem, i),
++			       mtk_oob_ptr(mem, snfi->buffer, i),
++			       snfi->caps->nand_fdm_size);
++
++		if (i == snfi_nand->bad_mark.sec && snfi->caps->bad_mark_swap)
++			snfi_nand->bad_mark.bm_swap(mem, snfi->buffer,
++							oob_on);
++	}
++
++	if (!oob_on)
++		memcpy(spinand->databuf, snfi->buffer, mtd->writesize);
++
++	return ret;
++}
++
++static int mtk_snfi_write(struct spi_mem *mem,
++			  const struct spi_mem_op *op)
++{
++	struct spinand_device *spinand = spi_mem_get_drvdata(mem);
++	struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++	struct mtd_info *mtd = spinand_to_mtd(spinand);
++	struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand;
++	u32 ret, i, sectors, col_addr = op->addr.val;
++	int oob_on = false;
++
++	if (col_addr == mtd->writesize)
++		oob_on = true;
++
++	sectors = mtd->writesize / snfi->caps->nand_sec_size;
++	memset(snfi->buffer, 0xff, mtd->writesize + mtd->oobsize);
++
++	if (!oob_on)
++		memcpy(snfi->buffer, spinand->databuf, mtd->writesize);
++
++	for (i = 0; i < sectors; i++) {
++		if (i == snfi_nand->bad_mark.sec && snfi->caps->bad_mark_swap)
++			snfi_nand->bad_mark.bm_swap(mem, snfi->buffer, oob_on);
++
++		if (oob_on)
++			memcpy(mtk_oob_ptr(mem, snfi->buffer, i),
++			       oob_ptr(mem, i),
++			       snfi->caps->nand_fdm_size);
++	}
++
++	ret = mtk_snfi_write_to_cache(mem, op, oob_on);
++	if (ret)
++		dev_warn(snfi->dev, "write to cache fail\n");
++
++	return ret;
++}
++
++static int mtk_snfi_command_exec(struct mtk_snfi *snfi,
++				 const u8 *txbuf, u8 *rxbuf,
++				 const u32 txlen, const u32 rxlen)
++{
++	u32 tmp, i, j, reg, m;
++	u8 *p_tmp = (u8 *)(&tmp);
++	int ret = 0;
++
++	/* Moving tx data to NFI_SPI GPRAM */
++	for (i = 0, m = 0; i < txlen; ) {
++		for (j = 0, tmp = 0; i < txlen && j < 4; i++, j++)
++			p_tmp[j] = txbuf[i];
++
++		writel(tmp, snfi->regs + SNFI_GPRAM_DATA + m);
++		m += 4;
++	}
++
++	writel(txlen, snfi->regs + SNFI_MAC_OUTL);
++	writel(rxlen, snfi->regs + SNFI_MAC_INL);
++	ret = mtk_snfi_mac_op(snfi);
++	if (ret)
++		return ret;
++
++	/* For NULL input data, this loop will be skipped */
++	if (rxlen)
++		for (i = 0, m = 0; i < rxlen; ) {
++			reg = readl(snfi->regs +
++					    SNFI_GPRAM_DATA + m);
++			for (j = 0; i < rxlen && j < 4; i++, j++, rxbuf++) {
++				if (m == 0 && i == 0)
++					j = i + txlen;
++				*rxbuf = (reg >> (j * 8)) & 0xFF;
++			}
++			m += 4;
++		}
++
++	return ret;
++}
++
++/*
++ * mtk_snfi_exec_op - to process command/data to send to the
++ * SPI NAND by mtk controller
++ */
++static int mtk_snfi_exec_op(struct spi_mem *mem,
++			    const struct spi_mem_op *op)
++
++{
++	struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master);
++	struct spinand_device *spinand = spi_mem_get_drvdata(mem);
++	struct mtd_info *mtd = spinand_to_mtd(spinand);
++	struct nand_device *nand = mtd_to_nanddev(mtd);
++	const struct spi_mem_op *read_cache;
++	const struct spi_mem_op *write_cache;
++	const struct spi_mem_op *update_cache;
++	u32 tmpbufsize, txlen = 0, rxlen = 0;
++	u8 *txbuf, *rxbuf = NULL, *buf;
++	int i, ret = 0;
++	
++	ret = mtk_snfi_reset(snfi);
++	if (ret) {
++		dev_warn(snfi->dev, "reset spi memory controller fail\n");
++		return ret;
++	}
++
++	/*if bbt initial, framework have detect nand information */
++	if (nand->bbt.cache) {
++		read_cache = spinand->op_templates.read_cache;
++		write_cache = spinand->op_templates.write_cache;
++		update_cache = spinand->op_templates.update_cache;
++
++		ret = mtk_snfi_hw_runtime_config(mem);
++		if (ret)
++			return ret;
++
++		/* For Read/Write with cache, Erase use framework flow */
++		if (op->cmd.opcode == read_cache->cmd.opcode) {
++			ret = mtk_snfi_read(mem, op);
++			if (ret)
++				dev_warn(snfi->dev, "snfi read fail\n");
++			
++			return ret;
++		} else if ((op->cmd.opcode == write_cache->cmd.opcode)
++			       	|| (op->cmd.opcode == update_cache->cmd.opcode)) {
++			ret = mtk_snfi_write(mem, op);
++			if (ret)
++				dev_warn(snfi->dev, "snfi write fail\n");
++			
++			return ret;
++		}
++	}
++
++	tmpbufsize = sizeof(op->cmd.opcode) + op->addr.nbytes +
++		     op->dummy.nbytes + op->data.nbytes;
++
++	txbuf = kzalloc(tmpbufsize, GFP_KERNEL);
++	if (!txbuf)
++		return -ENOMEM;
++
++	txbuf[txlen++] = op->cmd.opcode;
++
++	if (op->addr.nbytes)
++		for (i = 0; i < op->addr.nbytes; i++)
++			txbuf[txlen++] = op->addr.val >>
++					(8 * (op->addr.nbytes - i - 1));
++
++	txlen += op->dummy.nbytes;
++
++	if (op->data.dir == SPI_MEM_DATA_OUT)
++		for (i = 0; i < op->data.nbytes; i++) {
++			buf = (u8 *)op->data.buf.out;
++			txbuf[txlen++] = buf[i];
++		}
++
++	if (op->data.dir == SPI_MEM_DATA_IN) {
++		rxbuf = (u8 *)op->data.buf.in;
++		rxlen += op->data.nbytes;
++	}
++
++	ret = mtk_snfi_command_exec(snfi, txbuf, rxbuf, txlen, rxlen);
++	kfree(txbuf);
++
++	return ret;
++}
++
++static int mtk_snfi_init(struct mtk_snfi *snfi)
++{
++	int ret;
++
++	/* Reset the state machine and data FIFO */
++	ret = mtk_snfi_reset(snfi);
++	if (ret) {
++		dev_warn(snfi->dev, "MTK reset controller fail\n");
++		return ret;
++	}
++
++	snfi->buffer = devm_kzalloc(snfi->dev, 4096 + 256, GFP_KERNEL);
++	if (!snfi->buffer)
++		return  -ENOMEM;
++
++	/* Clear interrupt, read clear. */
++	readw(snfi->regs + NFI_INTR_STA);
++	writew(0, snfi->regs + NFI_INTR_EN);
++
++	writel(0, snfi->regs + NFI_CON);
++	writel(0, snfi->regs + NFI_CNFG);
++
++	/* Change to NFI_SPI mode. */
++	writel(SNFI_MODE_EN, snfi->regs + SNFI_CNFG);
++
++	return 0;
++}
++
++static int mtk_snfi_check_buswidth(u8 width)
++{
++	switch (width) {
++	case 1:
++	case 2:
++	case 4:
++		return 0;
++
++	default:
++		break;
++	}
++
++	return -ENOTSUPP;
++}
++
++static bool mtk_snfi_supports_op(struct spi_mem *mem,
++				 const struct spi_mem_op *op)
++{
++	int ret = 0;
++
++	/* For MTK Spi Nand controller, cmd buswidth just support 1 bit*/
++	if (op->cmd.buswidth != 1)
++		ret = -ENOTSUPP;
++
++	if (op->addr.nbytes)
++		ret |= mtk_snfi_check_buswidth(op->addr.buswidth);
++
++	if (op->dummy.nbytes)
++		ret |= mtk_snfi_check_buswidth(op->dummy.buswidth);
++
++	if (op->data.nbytes)
++		ret |= mtk_snfi_check_buswidth(op->data.buswidth);
++
++	if (ret)
++		return false;
++
++	return true;
++}
++
++static const struct spi_controller_mem_ops mtk_snfi_ops = {
++	.supports_op = mtk_snfi_supports_op,
++	.exec_op = mtk_snfi_exec_op,
++};
++
++static const struct mtk_snfi_caps snfi_mt7622 = {
++	.spare_size = spare_size_mt7622,
++	.num_spare_size = 4,
++	.nand_sec_size = 512,
++	.nand_fdm_size = 8,
++	.nand_fdm_ecc_size = 1,
++	.ecc_parity_bits = 13,
++	.pageformat_spare_shift = 4,
++	.bad_mark_swap = 0,
++};
++
++static const struct mtk_snfi_caps snfi_mt7629 = {
++	.spare_size = spare_size_mt7622,
++	.num_spare_size = 4,
++	.nand_sec_size = 512,
++	.nand_fdm_size = 8,
++	.nand_fdm_ecc_size = 1,
++	.ecc_parity_bits = 13,
++	.pageformat_spare_shift = 4,
++	.bad_mark_swap = 1,
++};
++
++static const struct of_device_id mtk_snfi_id_table[] = {
++	{ .compatible = "mediatek,mt7622-snfi", .data = &snfi_mt7622, },
++	{ .compatible = "mediatek,mt7629-snfi", .data = &snfi_mt7629, },
++	{  /* sentinel */ }
++};
++
++static int mtk_snfi_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct device_node *np = dev->of_node;
++	struct spi_controller *ctlr;
++	struct mtk_snfi *snfi;
++	struct resource *res;
++	int ret = 0, irq;
++
++	ctlr = spi_alloc_master(&pdev->dev, sizeof(*snfi));
++	if (!ctlr)
++		return -ENOMEM;
++
++	snfi = spi_controller_get_devdata(ctlr);
++	snfi->caps = of_device_get_match_data(dev);
++	snfi->dev = dev;
++
++	snfi->ecc = of_mtk_ecc_get(np);
++	if (IS_ERR_OR_NULL(snfi->ecc))
++		goto err_put_master;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	snfi->regs = devm_ioremap_resource(dev, res);
++	if (IS_ERR(snfi->regs)) {
++		ret = PTR_ERR(snfi->regs);
++		goto release_ecc;
++	}
++
++	/* find the clocks */
++	snfi->clk.nfi_clk = devm_clk_get(dev, "nfi_clk");
++	if (IS_ERR(snfi->clk.nfi_clk)) {
++		dev_err(dev, "no nfi clk\n");
++		ret = PTR_ERR(snfi->clk.nfi_clk);
++		goto release_ecc;
++	}
++
++	snfi->clk.spi_clk = devm_clk_get(dev, "spi_clk");
++	if (IS_ERR(snfi->clk.spi_clk)) {
++		dev_err(dev, "no spi clk\n");
++		ret = PTR_ERR(snfi->clk.spi_clk);
++		goto release_ecc;
++	}
++
++	ret = mtk_snfi_enable_clk(dev, &snfi->clk);
++	if (ret)
++		goto release_ecc;
++
++	/* find the irq */
++	irq = platform_get_irq(pdev, 0);
++	if (irq < 0) {
++		dev_err(dev, "no snfi irq resource\n");
++		ret = -EINVAL;
++		goto clk_disable;
++	}
++
++	ret = devm_request_irq(dev, irq, mtk_snfi_irq, 0, "mtk-snfi", snfi);
++	if (ret) {
++		dev_err(dev, "failed to request snfi irq\n");
++		goto clk_disable;
++	}
++
++	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
++	if (ret) {
++		dev_err(dev, "failed to set dma mask\n");
++		goto clk_disable;
++	}
++
++	ctlr->dev.of_node = np;
++	ctlr->mem_ops = &mtk_snfi_ops;
++
++	platform_set_drvdata(pdev, snfi);
++	ret = mtk_snfi_init(snfi);
++	if (ret) {
++		dev_err(dev, "failed to init snfi\n");
++		goto clk_disable;
++	}
++
++	ret = devm_spi_register_master(dev, ctlr);
++	if (ret)
++		goto clk_disable;
++
++	return 0;
++
++clk_disable:
++	mtk_snfi_disable_clk(&snfi->clk);
++
++release_ecc:
++	mtk_ecc_release(snfi->ecc);
++
++err_put_master:
++	spi_master_put(ctlr);
++
++	dev_err(dev, "MediaTek SPI NAND interface probe failed %d\n", ret);
++	return ret;
++}
++
++static int mtk_snfi_remove(struct platform_device *pdev)
++{
++	struct mtk_snfi *snfi = platform_get_drvdata(pdev);
++
++	mtk_snfi_disable_clk(&snfi->clk);
++
++	return 0;
++}
++
++static int mtk_snfi_suspend(struct platform_device *pdev, pm_message_t state)
++{
++	struct mtk_snfi *snfi = platform_get_drvdata(pdev);
++
++	mtk_snfi_disable_clk(&snfi->clk);
++
++	return 0;
++}
++
++static int mtk_snfi_resume(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct mtk_snfi *snfi = dev_get_drvdata(dev);
++	int ret;
++
++	ret = mtk_snfi_enable_clk(dev, &snfi->clk);
++	if (ret)
++		return ret;
++
++	ret = mtk_snfi_init(snfi);
++	if (ret)
++		dev_err(dev, "failed to init snfi controller\n");
++
++	return ret;
++}
++
++static struct platform_driver mtk_snfi_driver = {
++	.driver = {
++		.name	= "mtk-snfi",
++		.of_match_table = mtk_snfi_id_table,
++	},
++	.probe		= mtk_snfi_probe,
++	.remove		= mtk_snfi_remove,
++	.suspend	= mtk_snfi_suspend,
++	.resume		= mtk_snfi_resume,
++};
++
++module_platform_driver(mtk_snfi_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Xiangsheng Hou <xiangsheng.hou@mediatek.com>");
++MODULE_DESCRIPTION("Mediatek SPI Memory Interface Driver");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0307-dts-mt7629-add-snand-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0307-dts-mt7629-add-snand-support.patch
new file mode 100644
index 0000000..753c111
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0307-dts-mt7629-add-snand-support.patch
@@ -0,0 +1,97 @@
+From c813fbe806257c574240770ef716fbee19f7dbfa Mon Sep 17 00:00:00 2001
+From: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
+Date: Thu, 6 Jun 2019 16:29:04 +0800
+Subject: [PATCH] spi: spi-mem: Mediatek: Add SPI Nand support for MT7629
+
+Signed-off-by: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
+---
+ arch/arm/boot/dts/mt7629-rfb.dts | 45 ++++++++++++++++++++++++++++++++
+ arch/arm/boot/dts/mt7629.dtsi    | 22 ++++++++++++++++
+ 3 files changed, 79 insertions(+)
+
+--- a/arch/arm/boot/dts/mt7629.dtsi
++++ b/arch/arm/boot/dts/mt7629.dtsi
+@@ -258,6 +258,28 @@
+ 			status = "disabled";
+ 		};
+ 
++		bch: ecc@1100e000 {
++			compatible = "mediatek,mt7622-ecc";
++			reg = <0x1100e000 0x1000>;
++			interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_LOW>;
++			clocks = <&pericfg CLK_PERI_NFIECC_PD>;
++			clock-names = "nfiecc_clk";
++			status = "disabled";
++		};
++
++		snfi: spi@1100d000 {
++			compatible = "mediatek,mt7629-snfi";
++			reg = <0x1100d000 0x1000>;
++			interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>;
++			clocks = <&pericfg CLK_PERI_NFI_PD>,
++				 <&pericfg CLK_PERI_SNFI_PD>;
++			clock-names = "nfi_clk", "spi_clk";
++			ecc-engine = <&bch>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++			status = "disabled";
++		};
++
+ 		spi: spi@1100a000 {
+ 			compatible = "mediatek,mt7629-spi",
+ 				     "mediatek,mt7622-spi";
+--- a/arch/arm/boot/dts/mt7629-rfb.dts
++++ b/arch/arm/boot/dts/mt7629-rfb.dts
+@@ -276,6 +276,52 @@
+ 	};
+ };
+ 
++&bch {
++	status = "okay";
++};
++
++&snfi {
++	pinctrl-names = "default";
++	pinctrl-0 = <&serial_nand_pins>;
++	status = "okay";
++
++	spi_nand@0 {
++		#address-cells = <1>;
++		#size-cells = <1>;
++		compatible = "spi-nand";
++		spi-max-frequency = <104000000>;
++		reg = <0>;
++
++		partitions {
++		compatible = "fixed-partitions";
++		#address-cells = <1>;
++		#size-cells = <1>;
++
++		partition@0 {
++			label = "Bootloader";
++			reg = <0x00000 0x0100000>;
++			read-only;
++		};
++
++		partition@100000 {
++			label = "Config";
++			reg = <0x100000 0x0040000>;
++		};
++
++		partition@140000 {
++			label = "factory";
++			reg = <0x140000 0x0080000>;
++		};
++
++		partition@1c0000 {
++			label = "firmware";
++			reg = <0x1c0000 0x1000000>;
++		};
++
++		};
++	};
++};
++
+ &spi {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&spi_pins>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0308-dts-mt7622-add-snand-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0308-dts-mt7622-add-snand-support.patch
new file mode 100644
index 0000000..b287780
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0308-dts-mt7622-add-snand-support.patch
@@ -0,0 +1,96 @@
+--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
+@@ -554,6 +554,19 @@
+ 		status = "disabled";
+ 	};
+ 
++	snfi: spi@1100d000 {
++		compatible = "mediatek,mt7622-snfi";
++		reg = <0 0x1100d000 0 0x1000>;
++		interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>;
++		clocks = <&pericfg CLK_PERI_NFI_PD>,
++			 <&pericfg CLK_PERI_SNFI_PD>;
++		clock-names = "nfi_clk", "spi_clk";
++		ecc-engine = <&bch>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		status = "disabled";
++	};
++
+ 	nor_flash: spi@11014000 {
+ 		compatible = "mediatek,mt7622-nor",
+ 			     "mediatek,mt8173-nor";
+--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
+@@ -99,7 +99,7 @@
+ };
+ 
+ &bch {
+-	status = "disabled";
++	status = "okay";
+ };
+ 
+ &btif {
+@@ -551,6 +551,62 @@
+ 	status = "disable";
+ };
+ 
++&snfi {
++	pinctrl-names = "default";
++	pinctrl-0 = <&serial_nand_pins>;
++	status = "okay";
++
++	spi_nand@0 {
++		#address-cells = <1>;
++		#size-cells = <1>;
++		compatible = "spi-nand";
++		spi-max-frequency = <104000000>;
++		reg = <0>;
++
++		partitions {
++			compatible = "fixed-partitions";
++			#address-cells = <1>;
++			#size-cells = <1>;
++
++			partition@0 {
++				label = "Preloader";
++				reg = <0x00000 0x0080000>;
++				read-only;
++			};
++
++			partition@80000 {
++				label = "ATF";
++				reg = <0x80000 0x0040000>;
++			};
++
++			partition@c0000 {
++				label = "Bootloader";
++				reg = <0xc0000 0x0080000>;
++			};
++
++			partition@140000 {
++				label = "Config";
++				reg = <0x140000 0x0080000>;
++			};
++
++			partition@1c0000 {
++				label = "Factory";
++				reg = <0x1c0000 0x0040000>;
++			};
++
++			partition@200000 {
++				label = "firmware";
++				reg = <0x200000 0x2000000>;
++			};
++
++			partition@2200000 {
++				label = "User_data";
++				reg = <0x2200000 0x4000000>;
++			};
++		};
++	};
++};
++
+ &spi0 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&spic0_pins>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0310-dts-add-wmac-support-for-mt7622-rfb1.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0310-dts-add-wmac-support-for-mt7622-rfb1.patch
new file mode 100644
index 0000000..84aed89
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0310-dts-add-wmac-support-for-mt7622-rfb1.patch
@@ -0,0 +1,40 @@
+--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
+@@ -716,6 +716,17 @@
+ 		status = "disabled";
+ 	};
+ 
++	wmac: wmac@18000000 {
++		compatible = "mediatek,mt7622-wmac";
++		reg = <0 0x18000000 0 0x100000>;
++		interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_LOW>;
++
++		mediatek,infracfg = <&infracfg>;
++		status = "disabled";
++
++		power-domains = <&scpsys MT7622_POWER_DOMAIN_WB>;
++	};
++
+ 	ssusbsys: ssusbsys@1a000000 {
+ 		compatible = "mediatek,mt7622-ssusbsys",
+ 			     "syscon";
+--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
+@@ -589,7 +589,7 @@
+ 				reg = <0x140000 0x0080000>;
+ 			};
+ 
+-			partition@1c0000 {
++			factory: partition@1c0000 {
+ 				label = "Factory";
+ 				reg = <0x1c0000 0x0040000>;
+ 			};
+@@ -646,3 +646,8 @@
+ 	pinctrl-0 = <&watchdog_pins>;
+ 	status = "okay";
+ };
++
++&wmac {
++	mediatek,mtd-eeprom = <&factory 0x0000>;
++	status = "okay";
++};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0400-sound-add-some-helpers-to-control-mtk_memif.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0400-sound-add-some-helpers-to-control-mtk_memif.patch
new file mode 100644
index 0000000..ddeb5a4
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0400-sound-add-some-helpers-to-control-mtk_memif.patch
@@ -0,0 +1,313 @@
+--- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c
++++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
+@@ -361,6 +361,222 @@
+ }
+ EXPORT_SYMBOL_GPL(mtk_afe_dai_resume);
+ 
++int mtk_memif_set_enable(struct mtk_base_afe *afe, int id)
++{
++	struct mtk_base_afe_memif *memif = &afe->memif[id];
++
++	if (memif->data->enable_shift < 0) {
++		dev_warn(afe->dev, "%s(), error, id %d, enable_shift < 0\n",
++			 __func__, id);
++		return 0;
++	}
++	return mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg,
++				      1, 1, memif->data->enable_shift);
++}
++EXPORT_SYMBOL_GPL(mtk_memif_set_enable);
++
++int mtk_memif_set_disable(struct mtk_base_afe *afe, int id)
++{
++	struct mtk_base_afe_memif *memif = &afe->memif[id];
++
++	if (memif->data->enable_shift < 0) {
++		dev_warn(afe->dev, "%s(), error, id %d, enable_shift < 0\n",
++			 __func__, id);
++		return 0;
++	}
++	return mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg,
++				      1, 0, memif->data->enable_shift);
++}
++EXPORT_SYMBOL_GPL(mtk_memif_set_disable);
++
++int mtk_memif_set_addr(struct mtk_base_afe *afe, int id,
++		       unsigned char *dma_area,
++		       dma_addr_t dma_addr,
++		       size_t dma_bytes)
++{
++	struct mtk_base_afe_memif *memif = &afe->memif[id];
++	int msb_at_bit33 = upper_32_bits(dma_addr) ? 1 : 0;
++	unsigned int phys_buf_addr = lower_32_bits(dma_addr);
++	unsigned int phys_buf_addr_upper_32 = upper_32_bits(dma_addr);
++
++	memif->dma_area = dma_area;
++	memif->dma_addr = dma_addr;
++	memif->dma_bytes = dma_bytes;
++
++	/* start */
++	mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base,
++			 phys_buf_addr);
++	/* end */
++	if (memif->data->reg_ofs_end)
++		mtk_regmap_write(afe->regmap,
++				 memif->data->reg_ofs_end,
++				 phys_buf_addr + dma_bytes - 1);
++	else
++		mtk_regmap_write(afe->regmap,
++				 memif->data->reg_ofs_base +
++				 AFE_BASE_END_OFFSET,
++				 phys_buf_addr + dma_bytes - 1);
++
++	/* set start, end, upper 32 bits */
++	if (memif->data->reg_ofs_base_msb) {
++		mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base_msb,
++				 phys_buf_addr_upper_32);
++		mtk_regmap_write(afe->regmap,
++				 memif->data->reg_ofs_end_msb,
++				 phys_buf_addr_upper_32);
++	}
++
++	/* set MSB to 33-bit */
++	if (memif->data->msb_reg >= 0)
++		mtk_regmap_update_bits(afe->regmap, memif->data->msb_reg,
++				       1, msb_at_bit33, memif->data->msb_shift);
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(mtk_memif_set_addr);
++
++int mtk_memif_set_channel(struct mtk_base_afe *afe,
++			  int id, unsigned int channel)
++{
++	struct mtk_base_afe_memif *memif = &afe->memif[id];
++	unsigned int mono;
++
++	if (memif->data->mono_shift < 0)
++		return 0;
++
++	if (memif->data->quad_ch_mask) {
++		unsigned int quad_ch = (channel == 4) ? 1 : 0;
++
++		mtk_regmap_update_bits(afe->regmap, memif->data->quad_ch_reg,
++				       memif->data->quad_ch_mask,
++				       quad_ch, memif->data->quad_ch_shift);
++	}
++
++	if (memif->data->mono_invert)
++		mono = (channel == 1) ? 0 : 1;
++	else
++		mono = (channel == 1) ? 1 : 0;
++
++	return mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg,
++				      1, mono, memif->data->mono_shift);
++}
++EXPORT_SYMBOL_GPL(mtk_memif_set_channel);
++
++static int mtk_memif_set_rate_fs(struct mtk_base_afe *afe,
++				 int id, int fs)
++{
++	struct mtk_base_afe_memif *memif = &afe->memif[id];
++
++	if (memif->data->fs_shift >= 0)
++		mtk_regmap_update_bits(afe->regmap, memif->data->fs_reg,
++				       memif->data->fs_maskbit,
++				       fs, memif->data->fs_shift);
++
++	return 0;
++}
++
++int mtk_memif_set_rate(struct mtk_base_afe *afe,
++		       int id, unsigned int rate)
++{
++	int fs = 0;
++
++	if (!afe->get_dai_fs) {
++		dev_err(afe->dev, "%s(), error, afe->get_dai_fs == NULL\n",
++			__func__);
++		return -EINVAL;
++	}
++
++	fs = afe->get_dai_fs(afe, id, rate);
++
++	if (fs < 0)
++		return -EINVAL;
++
++	return mtk_memif_set_rate_fs(afe, id, fs);
++}
++EXPORT_SYMBOL_GPL(mtk_memif_set_rate);
++
++int mtk_memif_set_rate_substream(struct snd_pcm_substream *substream,
++				 int id, unsigned int rate)
++{
++	struct snd_soc_pcm_runtime *rtd = substream->private_data;
++	struct snd_soc_component *component =
++		snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
++	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
++
++	int fs = 0;
++
++	if (!afe->memif_fs) {
++		dev_err(afe->dev, "%s(), error, afe->memif_fs == NULL\n",
++			__func__);
++		return -EINVAL;
++	}
++
++	fs = afe->memif_fs(substream, rate);
++
++	if (fs < 0)
++		return -EINVAL;
++
++	return mtk_memif_set_rate_fs(afe, id, fs);
++}
++EXPORT_SYMBOL_GPL(mtk_memif_set_rate_substream);
++
++int mtk_memif_set_format(struct mtk_base_afe *afe,
++			 int id, snd_pcm_format_t format)
++{
++	struct mtk_base_afe_memif *memif = &afe->memif[id];
++	int hd_audio = 0;
++	int hd_align = 0;
++
++	/* set hd mode */
++	switch (format) {
++	case SNDRV_PCM_FORMAT_S16_LE:
++	case SNDRV_PCM_FORMAT_U16_LE:
++		hd_audio = 0;
++		break;
++	case SNDRV_PCM_FORMAT_S32_LE:
++	case SNDRV_PCM_FORMAT_U32_LE:
++		hd_audio = 1;
++		hd_align = 1;
++		break;
++	case SNDRV_PCM_FORMAT_S24_LE:
++	case SNDRV_PCM_FORMAT_U24_LE:
++		hd_audio = 1;
++		break;
++	default:
++		dev_err(afe->dev, "%s() error: unsupported format %d\n",
++			__func__, format);
++		break;
++	}
++
++	mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg,
++			       1, hd_audio, memif->data->hd_shift);
++
++	mtk_regmap_update_bits(afe->regmap, memif->data->hd_align_reg,
++			       1, hd_align, memif->data->hd_align_mshift);
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(mtk_memif_set_format);
++
++int mtk_memif_set_pbuf_size(struct mtk_base_afe *afe,
++			    int id, int pbuf_size)
++{
++	const struct mtk_base_memif_data *memif_data = afe->memif[id].data;
++
++	if (memif_data->pbuf_mask == 0 || memif_data->minlen_mask == 0)
++		return 0;
++
++	mtk_regmap_update_bits(afe->regmap, memif_data->pbuf_reg,
++			       memif_data->pbuf_mask,
++			       pbuf_size, memif_data->pbuf_shift);
++
++	mtk_regmap_update_bits(afe->regmap, memif_data->minlen_reg,
++			       memif_data->minlen_mask,
++			       pbuf_size, memif_data->minlen_shift);
++	return 0;
++}
++EXPORT_SYMBOL_GPL(mtk_memif_set_pbuf_size);
++
+ MODULE_DESCRIPTION("Mediatek simple fe dai operator");
+ MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
+ MODULE_LICENSE("GPL v2");
+--- a/sound/soc/mediatek/common/mtk-afe-fe-dai.h
++++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.h
+@@ -34,4 +34,20 @@
+ int mtk_afe_dai_suspend(struct snd_soc_dai *dai);
+ int mtk_afe_dai_resume(struct snd_soc_dai *dai);
+ 
++int mtk_memif_set_enable(struct mtk_base_afe *afe, int id);
++int mtk_memif_set_disable(struct mtk_base_afe *afe, int id);
++int mtk_memif_set_addr(struct mtk_base_afe *afe, int id,
++		       unsigned char *dma_area,
++		       dma_addr_t dma_addr,
++		       size_t dma_bytes);
++int mtk_memif_set_channel(struct mtk_base_afe *afe,
++			  int id, unsigned int channel);
++int mtk_memif_set_rate(struct mtk_base_afe *afe,
++		       int id, unsigned int rate);
++int mtk_memif_set_rate_substream(struct snd_pcm_substream *substream,
++				 int id, unsigned int rate);
++int mtk_memif_set_format(struct mtk_base_afe *afe,
++			 int id, snd_pcm_format_t format);
++int mtk_memif_set_pbuf_size(struct mtk_base_afe *afe,
++			    int id, int pbuf_size);
+ #endif
+--- a/sound/soc/mediatek/common/mtk-base-afe.h
++++ b/sound/soc/mediatek/common/mtk-base-afe.h
+@@ -16,21 +16,38 @@
+ 	const char *name;
+ 	int reg_ofs_base;
+ 	int reg_ofs_cur;
++	int reg_ofs_end;
++	int reg_ofs_base_msb;
++	int reg_ofs_cur_msb;
++	int reg_ofs_end_msb;
+ 	int fs_reg;
+ 	int fs_shift;
+ 	int fs_maskbit;
+ 	int mono_reg;
+ 	int mono_shift;
++	int mono_invert;
++	int quad_ch_reg;
++	int quad_ch_mask;
++	int quad_ch_shift;
+ 	int enable_reg;
+ 	int enable_shift;
+ 	int hd_reg;
+-	int hd_align_reg;
+ 	int hd_shift;
++	int hd_align_reg;
+ 	int hd_align_mshift;
+ 	int msb_reg;
+ 	int msb_shift;
++	int msb2_reg;
++	int msb2_shift;
+ 	int agent_disable_reg;
+ 	int agent_disable_shift;
++	/* playback memif only */
++	int pbuf_reg;
++	int pbuf_mask;
++	int pbuf_shift;
++	int minlen_reg;
++	int minlen_mask;
++	int minlen_shift;
+ };
+ 
+ struct mtk_base_irq_data {
+@@ -84,6 +101,12 @@
+ 			unsigned int rate);
+ 	int (*irq_fs)(struct snd_pcm_substream *substream,
+ 		      unsigned int rate);
++	int (*get_dai_fs)(struct mtk_base_afe *afe,
++			  int dai_id, unsigned int rate);
++	int (*get_memif_pbuf_size)(struct snd_pcm_substream *substream);
++
++	int (*request_dram_resource)(struct device *dev);
++	int (*release_dram_resource)(struct device *dev);
+ 
+ 	void *platform_priv;
+ };
+@@ -95,6 +118,9 @@
+ 	const struct mtk_base_memif_data *data;
+ 	int irq_usage;
+ 	int const_irq;
++	unsigned char *dma_area;
++	dma_addr_t dma_addr;
++	size_t dma_bytes;
+ };
+ 
+ struct mtk_base_afe_irq {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0401-sound-refine-hw-params-and-hw-prepare.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0401-sound-refine-hw-params-and-hw-prepare.patch
new file mode 100644
index 0000000..3e24d51
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0401-sound-refine-hw-params-and-hw-prepare.patch
@@ -0,0 +1,221 @@
+--- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c
++++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
+@@ -6,11 +6,13 @@
+  * Author: Garlic Tseng <garlic.tseng@mediatek.com>
+  */
+ 
++#include <linux/io.h>
+ #include <linux/module.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/regmap.h>
+ #include <sound/soc.h>
+ #include "mtk-afe-platform-driver.h"
++#include <sound/pcm_params.h>
+ #include "mtk-afe-fe-dai.h"
+ #include "mtk-base-afe.h"
+ 
+@@ -120,50 +122,64 @@
+ {
+ 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ 	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+-	struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
+-	int msb_at_bit33 = 0;
+-	int ret, fs = 0;
++	int id = rtd->cpu_dai->id;
++	struct mtk_base_afe_memif *memif = &afe->memif[id];
++	int ret;
++	unsigned int channels = params_channels(params);
++	unsigned int rate = params_rate(params);
++	snd_pcm_format_t format = params_format(params);
+ 
+ 	ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+ 	if (ret < 0)
+ 		return ret;
+ 
+-	msb_at_bit33 = upper_32_bits(substream->runtime->dma_addr) ? 1 : 0;
+-	memif->phys_buf_addr = lower_32_bits(substream->runtime->dma_addr);
+-	memif->buffer_size = substream->runtime->dma_bytes;
+-
+-	/* start */
+-	mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base,
+-			 memif->phys_buf_addr);
+-	/* end */
+-	mtk_regmap_write(afe->regmap,
+-			 memif->data->reg_ofs_base + AFE_BASE_END_OFFSET,
+-			 memif->phys_buf_addr + memif->buffer_size - 1);
+-
+-	/* set MSB to 33-bit */
+-	mtk_regmap_update_bits(afe->regmap, memif->data->msb_reg,
+-			       1, msb_at_bit33, memif->data->msb_shift);
++	if (afe->request_dram_resource)
++		afe->request_dram_resource(afe->dev);
+ 
+-	/* set channel */
+-	if (memif->data->mono_shift >= 0) {
+-		unsigned int mono = (params_channels(params) == 1) ? 1 : 0;
++	dev_dbg(afe->dev, "%s(), %s, ch %d, rate %d, fmt %d, dma_addr %pad, dma_area %p, dma_bytes 0x%zx\n",
++		__func__, memif->data->name,
++		channels, rate, format,
++		&substream->runtime->dma_addr,
++		substream->runtime->dma_area,
++		substream->runtime->dma_bytes);
++
++	memset_io(substream->runtime->dma_area, 0,
++		  substream->runtime->dma_bytes);
++
++	/* set addr */
++	ret = mtk_memif_set_addr(afe, id,
++				 substream->runtime->dma_area,
++				 substream->runtime->dma_addr,
++				 substream->runtime->dma_bytes);
++	if (ret) {
++		dev_err(afe->dev, "%s(), error, id %d, set addr, ret %d\n",
++			__func__, id, ret);
++		return ret;
++	}
+ 
+-		mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg,
+-				       1, mono, memif->data->mono_shift);
++	/* set channel */
++	ret = mtk_memif_set_channel(afe, id, channels);
++	if (ret) {
++		dev_err(afe->dev, "%s(), error, id %d, set channel %d, ret %d\n",
++			__func__, id, channels, ret);
++		return ret;
+ 	}
+ 
+ 	/* set rate */
+-	if (memif->data->fs_shift < 0)
+-		return 0;
+-
+-	fs = afe->memif_fs(substream, params_rate(params));
+-
+-	if (fs < 0)
+-		return -EINVAL;
++	ret = mtk_memif_set_rate_substream(substream, id, rate);
++	if (ret) {
++		dev_err(afe->dev, "%s(), error, id %d, set rate %d, ret %d\n",
++			__func__, id, rate, ret);
++		return ret;
++	}
+ 
+-	mtk_regmap_update_bits(afe->regmap, memif->data->fs_reg,
+-			       memif->data->fs_maskbit, fs,
+-			       memif->data->fs_shift);
++	/* set format */
++	ret = mtk_memif_set_format(afe, id, format);
++	if (ret) {
++		dev_err(afe->dev, "%s(), error, id %d, set format %d, ret %d\n",
++			__func__, id, format, ret);
++		return ret;
++	}
+ 
+ 	return 0;
+ }
+@@ -172,6 +188,11 @@
+ int mtk_afe_fe_hw_free(struct snd_pcm_substream *substream,
+ 		       struct snd_soc_dai *dai)
+ {
++	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
++
++	if (afe->release_dram_resource)
++		afe->release_dram_resource(afe->dev);
++
+ 	return snd_pcm_lib_free_pages(substream);
+ }
+ EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_free);
+@@ -182,20 +203,25 @@
+ 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ 	struct snd_pcm_runtime * const runtime = substream->runtime;
+ 	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+-	struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
++	int id = rtd->cpu_dai->id;
++	struct mtk_base_afe_memif *memif = &afe->memif[id];
+ 	struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage];
+ 	const struct mtk_base_irq_data *irq_data = irqs->irq_data;
+ 	unsigned int counter = runtime->period_size;
+ 	int fs;
++	int ret;
+ 
+ 	dev_dbg(afe->dev, "%s %s cmd=%d\n", __func__, memif->data->name, cmd);
+ 
+ 	switch (cmd) {
+ 	case SNDRV_PCM_TRIGGER_START:
+ 	case SNDRV_PCM_TRIGGER_RESUME:
+-		mtk_regmap_update_bits(afe->regmap,
+-				       memif->data->enable_reg,
+-				       1, 1, memif->data->enable_shift);
++		ret = mtk_memif_set_enable(afe, id);
++		if (ret) {
++			dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n",
++				__func__, id, ret);
++			return ret;
++		}
+ 
+ 		/* set irq counter */
+ 		mtk_regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg,
+@@ -219,15 +245,19 @@
+ 		return 0;
+ 	case SNDRV_PCM_TRIGGER_STOP:
+ 	case SNDRV_PCM_TRIGGER_SUSPEND:
+-		mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg,
+-				       1, 0, memif->data->enable_shift);
++		ret = mtk_memif_set_disable(afe, id);
++		if (ret) {
++			dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n",
++				__func__, id, ret);
++		}
++
+ 		/* disable interrupt */
+ 		mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg,
+ 				       1, 0, irq_data->irq_en_shift);
+ 		/* and clear pending IRQ */
+ 		mtk_regmap_write(afe->regmap, irq_data->irq_clr_reg,
+ 				 1 << irq_data->irq_clr_shift);
+-		return 0;
++		return ret;
+ 	default:
+ 		return -EINVAL;
+ 	}
+@@ -239,34 +269,15 @@
+ {
+ 	struct snd_soc_pcm_runtime *rtd  = substream->private_data;
+ 	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+-	struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
+-	int hd_audio = 0;
+-	int hd_align = 0;
++	int id = rtd->cpu_dai->id;
++	int pbuf_size;
+ 
+-	/* set hd mode */
+-	switch (substream->runtime->format) {
+-	case SNDRV_PCM_FORMAT_S16_LE:
+-		hd_audio = 0;
+-		break;
+-	case SNDRV_PCM_FORMAT_S32_LE:
+-		hd_audio = 1;
+-		hd_align = 1;
+-		break;
+-	case SNDRV_PCM_FORMAT_S24_LE:
+-		hd_audio = 1;
+-		break;
+-	default:
+-		dev_err(afe->dev, "%s() error: unsupported format %d\n",
+-			__func__, substream->runtime->format);
+-		break;
++	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++		if (afe->get_memif_pbuf_size) {
++			pbuf_size = afe->get_memif_pbuf_size(substream);
++			mtk_memif_set_pbuf_size(afe, id, pbuf_size);
++		}
+ 	}
+-
+-	mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg,
+-			       1, hd_audio, memif->data->hd_shift);
+-
+-	mtk_regmap_update_bits(afe->regmap, memif->data->hd_align_reg,
+-			       1, hd_align, memif->data->hd_align_mshift);
+-
+ 	return 0;
+ }
+ EXPORT_SYMBOL_GPL(mtk_afe_fe_prepare);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0402-sound-add-mt7986-driver-and-slic-driver.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0402-sound-add-mt7986-driver-and-slic-driver.patch
new file mode 100644
index 0000000..ee5ea6f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0402-sound-add-mt7986-driver-and-slic-driver.patch
@@ -0,0 +1,91 @@
+--- a/sound/soc/codecs/Kconfig
++++ b/sound/soc/codecs/Kconfig
+@@ -164,6 +164,7 @@
+ 	select SND_SOC_RT5677 if I2C && SPI_MASTER
+ 	select SND_SOC_RT5682 if I2C
+ 	select SND_SOC_SGTL5000 if I2C
++	select SND_SOC_SI3218X_SPI
+ 	select SND_SOC_SI476X if MFD_SI476X_CORE
+ 	select SND_SOC_SIMPLE_AMPLIFIER
+ 	select SND_SOC_SIRF_AUDIO_CODEC
+@@ -1484,6 +1485,14 @@
+ config SND_SOC_NAU8825
+ 	tristate
+ 
++config SND_SOC_SI3218X
++	tristate
++
++config SND_SOC_SI3218X_SPI
++	tristate "Proslic SI3218X"
++	depends on SPI
++	select SND_SOC_SI3218X
++
+ config SND_SOC_TPA6130A2
+ 	tristate "Texas Instruments TPA6130A2 headphone amplifier"
+ 	depends on I2C
+--- a/sound/soc/codecs/Makefile
++++ b/sound/soc/codecs/Makefile
+@@ -176,6 +176,7 @@
+ snd-soc-sigmadsp-objs := sigmadsp.o
+ snd-soc-sigmadsp-i2c-objs := sigmadsp-i2c.o
+ snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o
++snd-soc-si3218x-spi-objs := si3218x-spi.o
+ snd-soc-si476x-objs := si476x.o
+ snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o
+ snd-soc-spdif-tx-objs := spdif_transmitter.o
+@@ -563,3 +564,7 @@
+ obj-$(CONFIG_SND_SOC_MAX98504)	+= snd-soc-max98504.o
+ obj-$(CONFIG_SND_SOC_SIMPLE_AMPLIFIER)	+= snd-soc-simple-amplifier.o
+ obj-$(CONFIG_SND_SOC_TPA6130A2)	+= snd-soc-tpa6130a2.o
++
++# Proslic si3218x
++obj-$(CONFIG_SND_SOC_SI3218X)	+= si3218x/
++obj-$(CONFIG_SND_SOC_SI3218X_SPI)	+= snd-soc-si3218x-spi.o
+--- a/sound/soc/mediatek/Kconfig
++++ b/sound/soc/mediatek/Kconfig
+@@ -53,6 +53,36 @@
+ 	  Select Y if you have such device.
+ 	  If unsure select "N".
+ 
++config SND_SOC_MT79XX
++	tristate "ASoC support for Mediatek MT79XX chip"
++	depends on ARCH_MEDIATEK
++	select SND_SOC_MEDIATEK
++	help
++	  This adds ASoC platform driver support for Mediatek MT79XX chip
++	  that can be used with other codecs.
++	  Select Y if you have such device.
++	  If unsure select "N".
++
++config SND_SOC_MT79XX_WM8960
++	tristate "ASoc Audio driver for MT79XX with WM8960 codec"
++	depends on SND_SOC_MT79XX && I2C
++	select SND_SOC_WM8960
++	help
++	  This adds ASoC driver for Mediatek MT79XX boards
++	  with the WM8960 codecs.
++	  Select Y if you have such device.
++	  If unsure select "N".
++
++config SND_SOC_MT79XX_SI3218X
++	tristate "ASoc Audio driver for MT79XX with SI3218X codec"
++	depends on SND_SOC_MT79XX && SPI
++	select SND_SOC_SI3218X_SPI
++	help
++	  This adds ASoC driver for Mediatek MT79XX boards
++	  with the SI3218X codecs.
++	  Select Y if you have such device.
++	  If unsure select "N".
++
+ config SND_SOC_MT8173
+ 	tristate "ASoC support for Mediatek MT8173 chip"
+ 	depends on ARCH_MEDIATEK
+--- a/sound/soc/mediatek/Makefile
++++ b/sound/soc/mediatek/Makefile
+@@ -2,5 +2,6 @@
+ obj-$(CONFIG_SND_SOC_MEDIATEK) += common/
+ obj-$(CONFIG_SND_SOC_MT2701) += mt2701/
+ obj-$(CONFIG_SND_SOC_MT6797) += mt6797/
++obj-$(CONFIG_SND_SOC_MT79XX) += mt79xx/
+ obj-$(CONFIG_SND_SOC_MT8173) += mt8173/
+ obj-$(CONFIG_SND_SOC_MT8183) += mt8183/
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0500-v5.6-crypto-backport-inside-secure.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0500-v5.6-crypto-backport-inside-secure.patch
new file mode 100644
index 0000000..2fae90e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0500-v5.6-crypto-backport-inside-secure.patch
@@ -0,0 +1,5464 @@
+--- a/drivers/crypto/inside-secure/safexcel.c
++++ b/drivers/crypto/inside-secure/safexcel.c
+@@ -75,9 +75,9 @@ static void eip197_trc_cache_banksel(str
+ }
+ 
+ static u32 eip197_trc_cache_probe(struct safexcel_crypto_priv *priv,
+-				  int maxbanks, u32 probemask)
++				  int maxbanks, u32 probemask, u32 stride)
+ {
+-	u32 val, addrhi, addrlo, addrmid;
++	u32 val, addrhi, addrlo, addrmid, addralias, delta, marker;
+ 	int actbank;
+ 
+ 	/*
+@@ -87,32 +87,37 @@ static u32 eip197_trc_cache_probe(struct
+ 	addrhi = 1 << (16 + maxbanks);
+ 	addrlo = 0;
+ 	actbank = min(maxbanks - 1, 0);
+-	while ((addrhi - addrlo) > 32) {
++	while ((addrhi - addrlo) > stride) {
+ 		/* write marker to lowest address in top half */
+ 		addrmid = (addrhi + addrlo) >> 1;
++		marker = (addrmid ^ 0xabadbabe) & probemask; /* Unique */
+ 		eip197_trc_cache_banksel(priv, addrmid, &actbank);
+-		writel((addrmid | (addrlo << 16)) & probemask,
++		writel(marker,
+ 			priv->base + EIP197_CLASSIFICATION_RAMS +
+ 			(addrmid & 0xffff));
+ 
+-		/* write marker to lowest address in bottom half */
+-		eip197_trc_cache_banksel(priv, addrlo, &actbank);
+-		writel((addrlo | (addrhi << 16)) & probemask,
+-			priv->base + EIP197_CLASSIFICATION_RAMS +
+-			(addrlo & 0xffff));
++		/* write invalid markers to possible aliases */
++		delta = 1 << __fls(addrmid);
++		while (delta >= stride) {
++			addralias = addrmid - delta;
++			eip197_trc_cache_banksel(priv, addralias, &actbank);
++			writel(~marker,
++			       priv->base + EIP197_CLASSIFICATION_RAMS +
++			       (addralias & 0xffff));
++			delta >>= 1;
++		}
+ 
+ 		/* read back marker from top half */
+ 		eip197_trc_cache_banksel(priv, addrmid, &actbank);
+ 		val = readl(priv->base + EIP197_CLASSIFICATION_RAMS +
+ 			    (addrmid & 0xffff));
+ 
+-		if (val == ((addrmid | (addrlo << 16)) & probemask)) {
++		if ((val & probemask) == marker)
+ 			/* read back correct, continue with top half */
+ 			addrlo = addrmid;
+-		} else {
++		else
+ 			/* not read back correct, continue with bottom half */
+ 			addrhi = addrmid;
+-		}
+ 	}
+ 	return addrhi;
+ }
+@@ -150,7 +155,7 @@ static void eip197_trc_cache_clear(struc
+ 		       htable_offset + i * sizeof(u32));
+ }
+ 
+-static void eip197_trc_cache_init(struct safexcel_crypto_priv *priv)
++static int eip197_trc_cache_init(struct safexcel_crypto_priv *priv)
+ {
+ 	u32 val, dsize, asize;
+ 	int cs_rc_max, cs_ht_wc, cs_trc_rec_wc, cs_trc_lg_rec_wc;
+@@ -183,7 +188,7 @@ static void eip197_trc_cache_init(struct
+ 	writel(val, priv->base + EIP197_TRC_PARAMS);
+ 
+ 	/* Probed data RAM size in bytes */
+-	dsize = eip197_trc_cache_probe(priv, maxbanks, 0xffffffff);
++	dsize = eip197_trc_cache_probe(priv, maxbanks, 0xffffffff, 32);
+ 
+ 	/*
+ 	 * Now probe the administration RAM size pretty much the same way
+@@ -196,11 +201,18 @@ static void eip197_trc_cache_init(struct
+ 	writel(val, priv->base + EIP197_TRC_PARAMS);
+ 
+ 	/* Probed admin RAM size in admin words */
+-	asize = eip197_trc_cache_probe(priv, 0, 0xbfffffff) >> 4;
++	asize = eip197_trc_cache_probe(priv, 0, 0x3fffffff, 16) >> 4;
+ 
+ 	/* Clear any ECC errors detected while probing! */
+ 	writel(0, priv->base + EIP197_TRC_ECCCTRL);
+ 
++	/* Sanity check probing results */
++	if (dsize < EIP197_MIN_DSIZE || asize < EIP197_MIN_ASIZE) {
++		dev_err(priv->dev, "Record cache probing failed (%d,%d).",
++			dsize, asize);
++		return -ENODEV;
++	}
++
+ 	/*
+ 	 * Determine optimal configuration from RAM sizes
+ 	 * Note that we assume that the physical RAM configuration is sane
+@@ -251,6 +263,7 @@ static void eip197_trc_cache_init(struct
+ 
+ 	dev_info(priv->dev, "TRC init: %dd,%da (%dr,%dh)\n",
+ 		 dsize, asize, cs_rc_max, cs_ht_wc + cs_ht_wc);
++	return 0;
+ }
+ 
+ static void eip197_init_firmware(struct safexcel_crypto_priv *priv)
+@@ -298,13 +311,14 @@ static void eip197_init_firmware(struct
+ static int eip197_write_firmware(struct safexcel_crypto_priv *priv,
+ 				  const struct firmware *fw)
+ {
+-	const u32 *data = (const u32 *)fw->data;
++	const __be32 *data = (const __be32 *)fw->data;
+ 	int i;
+ 
+ 	/* Write the firmware */
+ 	for (i = 0; i < fw->size / sizeof(u32); i++)
+ 		writel(be32_to_cpu(data[i]),
+-		       priv->base + EIP197_CLASSIFICATION_RAMS + i * sizeof(u32));
++		       priv->base + EIP197_CLASSIFICATION_RAMS +
++		       i * sizeof(__be32));
+ 
+ 	/* Exclude final 2 NOPs from size */
+ 	return i - EIP197_FW_TERMINAL_NOPS;
+@@ -471,6 +485,14 @@ static int safexcel_hw_setup_cdesc_rings
+ 		cd_fetch_cnt = ((1 << priv->hwconfig.hwcfsize) /
+ 				cd_size_rnd) - 1;
+ 	}
++	/*
++	 * Since we're using command desc's way larger than formally specified,
++	 * we need to check whether we can fit even 1 for low-end EIP196's!
++	 */
++	if (!cd_fetch_cnt) {
++		dev_err(priv->dev, "Unable to fit even 1 command desc!\n");
++		return -ENODEV;
++	}
+ 
+ 	for (i = 0; i < priv->config.rings; i++) {
+ 		/* ring base address */
+@@ -479,12 +501,12 @@ static int safexcel_hw_setup_cdesc_rings
+ 		writel(upper_32_bits(priv->ring[i].cdr.base_dma),
+ 		       EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_HI);
+ 
+-		writel(EIP197_xDR_DESC_MODE_64BIT | (priv->config.cd_offset << 16) |
+-		       priv->config.cd_size,
++		writel(EIP197_xDR_DESC_MODE_64BIT | EIP197_CDR_DESC_MODE_ADCP |
++		       (priv->config.cd_offset << 14) | priv->config.cd_size,
+ 		       EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_DESC_SIZE);
+ 		writel(((cd_fetch_cnt *
+ 			 (cd_size_rnd << priv->hwconfig.hwdataw)) << 16) |
+-		       (cd_fetch_cnt * priv->config.cd_offset),
++		       (cd_fetch_cnt * (priv->config.cd_offset / sizeof(u32))),
+ 		       EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_CFG);
+ 
+ 		/* Configure DMA tx control */
+@@ -527,13 +549,13 @@ static int safexcel_hw_setup_rdesc_rings
+ 		writel(upper_32_bits(priv->ring[i].rdr.base_dma),
+ 		       EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_HI);
+ 
+-		writel(EIP197_xDR_DESC_MODE_64BIT | (priv->config.rd_offset << 16) |
++		writel(EIP197_xDR_DESC_MODE_64BIT | (priv->config.rd_offset << 14) |
+ 		       priv->config.rd_size,
+ 		       EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_DESC_SIZE);
+ 
+ 		writel(((rd_fetch_cnt *
+ 			 (rd_size_rnd << priv->hwconfig.hwdataw)) << 16) |
+-		       (rd_fetch_cnt * priv->config.rd_offset),
++		       (rd_fetch_cnt * (priv->config.rd_offset / sizeof(u32))),
+ 		       EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_CFG);
+ 
+ 		/* Configure DMA tx control */
+@@ -559,7 +581,7 @@ static int safexcel_hw_setup_rdesc_rings
+ static int safexcel_hw_init(struct safexcel_crypto_priv *priv)
+ {
+ 	u32 val;
+-	int i, ret, pe;
++	int i, ret, pe, opbuflo, opbufhi;
+ 
+ 	dev_dbg(priv->dev, "HW init: using %d pipe(s) and %d ring(s)\n",
+ 		priv->config.pes, priv->config.rings);
+@@ -595,8 +617,8 @@ static int safexcel_hw_init(struct safex
+ 		writel(EIP197_DxE_THR_CTRL_RESET_PE,
+ 		       EIP197_HIA_DFE_THR(priv) + EIP197_HIA_DFE_THR_CTRL(pe));
+ 
+-		if (priv->flags & SAFEXCEL_HW_EIP197)
+-			/* Reset HIA input interface arbiter (EIP197 only) */
++		if (priv->flags & EIP197_PE_ARB)
++			/* Reset HIA input interface arbiter (if present) */
+ 			writel(EIP197_HIA_RA_PE_CTRL_RESET,
+ 			       EIP197_HIA_AIC(priv) + EIP197_HIA_RA_PE_CTRL(pe));
+ 
+@@ -639,9 +661,16 @@ static int safexcel_hw_init(struct safex
+ 			;
+ 
+ 		/* DMA transfer size to use */
++		if (priv->hwconfig.hwnumpes > 4) {
++			opbuflo = 9;
++			opbufhi = 10;
++		} else {
++			opbuflo = 7;
++			opbufhi = 8;
++		}
+ 		val = EIP197_HIA_DSE_CFG_DIS_DEBUG;
+-		val |= EIP197_HIA_DxE_CFG_MIN_DATA_SIZE(7) |
+-		       EIP197_HIA_DxE_CFG_MAX_DATA_SIZE(8);
++		val |= EIP197_HIA_DxE_CFG_MIN_DATA_SIZE(opbuflo) |
++		       EIP197_HIA_DxE_CFG_MAX_DATA_SIZE(opbufhi);
+ 		val |= EIP197_HIA_DxE_CFG_DATA_CACHE_CTRL(WR_CACHE_3BITS);
+ 		val |= EIP197_HIA_DSE_CFG_ALWAYS_BUFFERABLE;
+ 		/* FIXME: instability issues can occur for EIP97 but disabling
+@@ -655,8 +684,8 @@ static int safexcel_hw_init(struct safex
+ 		writel(0, EIP197_HIA_DSE_THR(priv) + EIP197_HIA_DSE_THR_CTRL(pe));
+ 
+ 		/* Configure the procesing engine thresholds */
+-		writel(EIP197_PE_OUT_DBUF_THRES_MIN(7) |
+-		       EIP197_PE_OUT_DBUF_THRES_MAX(8),
++		writel(EIP197_PE_OUT_DBUF_THRES_MIN(opbuflo) |
++		       EIP197_PE_OUT_DBUF_THRES_MAX(opbufhi),
+ 		       EIP197_PE(priv) + EIP197_PE_OUT_DBUF_THRES(pe));
+ 
+ 		/* Processing Engine configuration */
+@@ -696,7 +725,7 @@ static int safexcel_hw_init(struct safex
+ 		writel(0,
+ 		       EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_PROC_PNTR);
+ 
+-		writel((EIP197_DEFAULT_RING_SIZE * priv->config.cd_offset) << 2,
++		writel((EIP197_DEFAULT_RING_SIZE * priv->config.cd_offset),
+ 		       EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_RING_SIZE);
+ 	}
+ 
+@@ -719,7 +748,7 @@ static int safexcel_hw_init(struct safex
+ 		       EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_PROC_PNTR);
+ 
+ 		/* Ring size */
+-		writel((EIP197_DEFAULT_RING_SIZE * priv->config.rd_offset) << 2,
++		writel((EIP197_DEFAULT_RING_SIZE * priv->config.rd_offset),
+ 		       EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_RING_SIZE);
+ 	}
+ 
+@@ -736,19 +765,28 @@ static int safexcel_hw_init(struct safex
+ 	/* Clear any HIA interrupt */
+ 	writel(GENMASK(30, 20), EIP197_HIA_AIC_G(priv) + EIP197_HIA_AIC_G_ACK);
+ 
+-	if (priv->flags & SAFEXCEL_HW_EIP197) {
+-		eip197_trc_cache_init(priv);
+-		priv->flags |= EIP197_TRC_CACHE;
++	if (priv->flags & EIP197_SIMPLE_TRC) {
++		writel(EIP197_STRC_CONFIG_INIT |
++		       EIP197_STRC_CONFIG_LARGE_REC(EIP197_CS_TRC_REC_WC) |
++		       EIP197_STRC_CONFIG_SMALL_REC(EIP197_CS_TRC_REC_WC),
++		       priv->base + EIP197_STRC_CONFIG);
++		writel(EIP197_PE_EIP96_TOKEN_CTRL2_CTX_DONE,
++		       EIP197_PE(priv) + EIP197_PE_EIP96_TOKEN_CTRL2(0));
++	} else if (priv->flags & SAFEXCEL_HW_EIP197) {
++		ret = eip197_trc_cache_init(priv);
++		if (ret)
++			return ret;
++	}
+ 
++	if (priv->flags & EIP197_ICE) {
+ 		ret = eip197_load_firmwares(priv);
+ 		if (ret)
+ 			return ret;
+ 	}
+ 
+-	safexcel_hw_setup_cdesc_rings(priv);
+-	safexcel_hw_setup_rdesc_rings(priv);
+-
+-	return 0;
++	return safexcel_hw_setup_cdesc_rings(priv) ?:
++	       safexcel_hw_setup_rdesc_rings(priv) ?:
++	       0;
+ }
+ 
+ /* Called with ring's lock taken */
+@@ -836,20 +874,24 @@ finalize:
+ 	spin_unlock_bh(&priv->ring[ring].lock);
+ 
+ 	/* let the RDR know we have pending descriptors */
+-	writel((rdesc * priv->config.rd_offset) << 2,
++	writel((rdesc * priv->config.rd_offset),
+ 	       EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_PREP_COUNT);
+ 
+ 	/* let the CDR know we have pending descriptors */
+-	writel((cdesc * priv->config.cd_offset) << 2,
++	writel((cdesc * priv->config.cd_offset),
+ 	       EIP197_HIA_CDR(priv, ring) + EIP197_HIA_xDR_PREP_COUNT);
+ }
+ 
+ inline int safexcel_rdesc_check_errors(struct safexcel_crypto_priv *priv,
+-				       struct safexcel_result_desc *rdesc)
++				       void *rdp)
+ {
+-	if (likely((!rdesc->descriptor_overflow) &&
+-		   (!rdesc->buffer_overflow) &&
+-		   (!rdesc->result_data.error_code)))
++	struct safexcel_result_desc *rdesc = rdp;
++	struct result_data_desc *result_data = rdp + priv->config.res_offset;
++
++	if (likely((!rdesc->last_seg) || /* Rest only valid if last seg! */
++		   ((!rdesc->descriptor_overflow) &&
++		    (!rdesc->buffer_overflow) &&
++		    (!result_data->error_code))))
+ 		return 0;
+ 
+ 	if (rdesc->descriptor_overflow)
+@@ -858,13 +900,14 @@ inline int safexcel_rdesc_check_errors(s
+ 	if (rdesc->buffer_overflow)
+ 		dev_err(priv->dev, "Buffer overflow detected");
+ 
+-	if (rdesc->result_data.error_code & 0x4066) {
++	if (result_data->error_code & 0x4066) {
+ 		/* Fatal error (bits 1,2,5,6 & 14) */
+ 		dev_err(priv->dev,
+ 			"result descriptor error (%x)",
+-			rdesc->result_data.error_code);
++			result_data->error_code);
++
+ 		return -EIO;
+-	} else if (rdesc->result_data.error_code &
++	} else if (result_data->error_code &
+ 		   (BIT(7) | BIT(4) | BIT(3) | BIT(0))) {
+ 		/*
+ 		 * Give priority over authentication fails:
+@@ -872,7 +915,7 @@ inline int safexcel_rdesc_check_errors(s
+ 		 * something wrong with the input!
+ 		 */
+ 		return -EINVAL;
+-	} else if (rdesc->result_data.error_code & BIT(9)) {
++	} else if (result_data->error_code & BIT(9)) {
+ 		/* Authentication failed */
+ 		return -EBADMSG;
+ 	}
+@@ -931,16 +974,18 @@ int safexcel_invalidate_cache(struct cry
+ {
+ 	struct safexcel_command_desc *cdesc;
+ 	struct safexcel_result_desc *rdesc;
++	struct safexcel_token  *dmmy;
+ 	int ret = 0;
+ 
+ 	/* Prepare command descriptor */
+-	cdesc = safexcel_add_cdesc(priv, ring, true, true, 0, 0, 0, ctxr_dma);
++	cdesc = safexcel_add_cdesc(priv, ring, true, true, 0, 0, 0, ctxr_dma,
++				   &dmmy);
+ 	if (IS_ERR(cdesc))
+ 		return PTR_ERR(cdesc);
+ 
+ 	cdesc->control_data.type = EIP197_TYPE_EXTENDED;
+ 	cdesc->control_data.options = 0;
+-	cdesc->control_data.refresh = 0;
++	cdesc->control_data.context_lo &= ~EIP197_CONTEXT_SIZE_MASK;
+ 	cdesc->control_data.control0 = CONTEXT_CONTROL_INV_TR;
+ 
+ 	/* Prepare result descriptor */
+@@ -1003,7 +1048,7 @@ handle_results:
+ acknowledge:
+ 	if (i)
+ 		writel(EIP197_xDR_PROC_xD_PKT(i) |
+-		       EIP197_xDR_PROC_xD_COUNT(tot_descs * priv->config.rd_offset),
++		       (tot_descs * priv->config.rd_offset),
+ 		       EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_PROC_COUNT);
+ 
+ 	/* If the number of requests overflowed the counter, try to proceed more
+@@ -1171,6 +1216,44 @@ static struct safexcel_alg_template *saf
+ 	&safexcel_alg_xts_aes,
+ 	&safexcel_alg_gcm,
+ 	&safexcel_alg_ccm,
++	&safexcel_alg_crc32,
++	&safexcel_alg_cbcmac,
++	&safexcel_alg_xcbcmac,
++	&safexcel_alg_cmac,
++	&safexcel_alg_chacha20,
++	&safexcel_alg_chachapoly,
++	&safexcel_alg_chachapoly_esp,
++	&safexcel_alg_sm3,
++	&safexcel_alg_hmac_sm3,
++	&safexcel_alg_ecb_sm4,
++	&safexcel_alg_cbc_sm4,
++	&safexcel_alg_ofb_sm4,
++	&safexcel_alg_cfb_sm4,
++	&safexcel_alg_ctr_sm4,
++	&safexcel_alg_authenc_hmac_sha1_cbc_sm4,
++	&safexcel_alg_authenc_hmac_sm3_cbc_sm4,
++	&safexcel_alg_authenc_hmac_sha1_ctr_sm4,
++	&safexcel_alg_authenc_hmac_sm3_ctr_sm4,
++	&safexcel_alg_sha3_224,
++	&safexcel_alg_sha3_256,
++	&safexcel_alg_sha3_384,
++	&safexcel_alg_sha3_512,
++	&safexcel_alg_hmac_sha3_224,
++	&safexcel_alg_hmac_sha3_256,
++	&safexcel_alg_hmac_sha3_384,
++	&safexcel_alg_hmac_sha3_512,
++	&safexcel_alg_authenc_hmac_sha1_cbc_des,
++	&safexcel_alg_authenc_hmac_sha256_cbc_des3_ede,
++	&safexcel_alg_authenc_hmac_sha224_cbc_des3_ede,
++	&safexcel_alg_authenc_hmac_sha512_cbc_des3_ede,
++	&safexcel_alg_authenc_hmac_sha384_cbc_des3_ede,
++	&safexcel_alg_authenc_hmac_sha256_cbc_des,
++	&safexcel_alg_authenc_hmac_sha224_cbc_des,
++	&safexcel_alg_authenc_hmac_sha512_cbc_des,
++	&safexcel_alg_authenc_hmac_sha384_cbc_des,
++	&safexcel_alg_rfc4106_gcm,
++	&safexcel_alg_rfc4543_gcm,
++	&safexcel_alg_rfc4309_ccm,
+ };
+ 
+ static int safexcel_register_algorithms(struct safexcel_crypto_priv *priv)
+@@ -1240,30 +1323,30 @@ static void safexcel_unregister_algorith
+ 
+ static void safexcel_configure(struct safexcel_crypto_priv *priv)
+ {
+-	u32 val, mask = 0;
+-
+-	val = readl(EIP197_HIA_AIC_G(priv) + EIP197_HIA_OPTIONS);
+-
+-	/* Read number of PEs from the engine */
+-	if (priv->flags & SAFEXCEL_HW_EIP197)
+-		/* Wider field width for all EIP197 type engines */
+-		mask = EIP197_N_PES_MASK;
+-	else
+-		/* Narrow field width for EIP97 type engine */
+-		mask = EIP97_N_PES_MASK;
+-
+-	priv->config.pes = (val >> EIP197_N_PES_OFFSET) & mask;
++	u32 mask = BIT(priv->hwconfig.hwdataw) - 1;
+ 
+-	priv->config.rings = min_t(u32, val & GENMASK(3, 0), max_rings);
++	priv->config.pes = priv->hwconfig.hwnumpes;
++	priv->config.rings = min_t(u32, priv->hwconfig.hwnumrings, max_rings);
++	/* Cannot currently support more rings than we have ring AICs! */
++	priv->config.rings = min_t(u32, priv->config.rings,
++					priv->hwconfig.hwnumraic);
+ 
+-	val = (val & GENMASK(27, 25)) >> 25;
+-	mask = BIT(val) - 1;
+-
+-	priv->config.cd_size = (sizeof(struct safexcel_command_desc) / sizeof(u32));
++	priv->config.cd_size = EIP197_CD64_FETCH_SIZE;
+ 	priv->config.cd_offset = (priv->config.cd_size + mask) & ~mask;
++	priv->config.cdsh_offset = (EIP197_MAX_TOKENS + mask) & ~mask;
+ 
+-	priv->config.rd_size = (sizeof(struct safexcel_result_desc) / sizeof(u32));
++	/* res token is behind the descr, but ofs must be rounded to buswdth */
++	priv->config.res_offset = (EIP197_RD64_FETCH_SIZE + mask) & ~mask;
++	/* now the size of the descr is this 1st part plus the result struct */
++	priv->config.rd_size    = priv->config.res_offset +
++				  EIP197_RD64_RESULT_SIZE;
+ 	priv->config.rd_offset = (priv->config.rd_size + mask) & ~mask;
++
++	/* convert dwords to bytes */
++	priv->config.cd_offset *= sizeof(u32);
++	priv->config.cdsh_offset *= sizeof(u32);
++	priv->config.rd_offset *= sizeof(u32);
++	priv->config.res_offset *= sizeof(u32);
+ }
+ 
+ static void safexcel_init_register_offsets(struct safexcel_crypto_priv *priv)
+@@ -1309,7 +1392,7 @@ static int safexcel_probe_generic(void *
+ 				  int is_pci_dev)
+ {
+ 	struct device *dev = priv->dev;
+-	u32 peid, version, mask, val, hiaopt;
++	u32 peid, version, mask, val, hiaopt, hwopt, peopt;
+ 	int i, ret, hwctg;
+ 
+ 	priv->context_pool = dmam_pool_create("safexcel-context", dev,
+@@ -1371,13 +1454,16 @@ static int safexcel_probe_generic(void *
+ 	 */
+ 	version = readl(EIP197_GLOBAL(priv) + EIP197_VERSION);
+ 	if (((priv->flags & SAFEXCEL_HW_EIP197) &&
+-	     (EIP197_REG_LO16(version) != EIP197_VERSION_LE)) ||
++	     (EIP197_REG_LO16(version) != EIP197_VERSION_LE) &&
++	     (EIP197_REG_LO16(version) != EIP196_VERSION_LE)) ||
+ 	    ((!(priv->flags & SAFEXCEL_HW_EIP197) &&
+ 	     (EIP197_REG_LO16(version) != EIP97_VERSION_LE)))) {
+ 		/*
+ 		 * We did not find the device that matched our initial probing
+ 		 * (or our initial probing failed) Report appropriate error.
+ 		 */
++		dev_err(priv->dev, "Probing for EIP97/EIP19x failed - no such device (read %08x)\n",
++			version);
+ 		return -ENODEV;
+ 	}
+ 
+@@ -1385,6 +1471,14 @@ static int safexcel_probe_generic(void *
+ 	hwctg = version >> 28;
+ 	peid = version & 255;
+ 
++	/* Detect EIP206 processing pipe */
++	version = readl(EIP197_PE(priv) + + EIP197_PE_VERSION(0));
++	if (EIP197_REG_LO16(version) != EIP206_VERSION_LE) {
++		dev_err(priv->dev, "EIP%d: EIP206 not detected\n", peid);
++		return -ENODEV;
++	}
++	priv->hwconfig.ppver = EIP197_VERSION_MASK(version);
++
+ 	/* Detect EIP96 packet engine and version */
+ 	version = readl(EIP197_PE(priv) + EIP197_PE_EIP96_VERSION(0));
+ 	if (EIP197_REG_LO16(version) != EIP96_VERSION_LE) {
+@@ -1393,10 +1487,13 @@ static int safexcel_probe_generic(void *
+ 	}
+ 	priv->hwconfig.pever = EIP197_VERSION_MASK(version);
+ 
++	hwopt = readl(EIP197_GLOBAL(priv) + EIP197_OPTIONS);
+ 	hiaopt = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_OPTIONS);
+ 
+ 	if (priv->flags & SAFEXCEL_HW_EIP197) {
+ 		/* EIP197 */
++		peopt = readl(EIP197_PE(priv) + EIP197_PE_OPTIONS(0));
++
+ 		priv->hwconfig.hwdataw  = (hiaopt >> EIP197_HWDATAW_OFFSET) &
+ 					  EIP197_HWDATAW_MASK;
+ 		priv->hwconfig.hwcfsize = ((hiaopt >> EIP197_CFSIZE_OFFSET) &
+@@ -1405,6 +1502,19 @@ static int safexcel_probe_generic(void *
+ 		priv->hwconfig.hwrfsize = ((hiaopt >> EIP197_RFSIZE_OFFSET) &
+ 					   EIP197_RFSIZE_MASK) +
+ 					  EIP197_RFSIZE_ADJUST;
++		priv->hwconfig.hwnumpes	= (hiaopt >> EIP197_N_PES_OFFSET) &
++					  EIP197_N_PES_MASK;
++		priv->hwconfig.hwnumrings = (hiaopt >> EIP197_N_RINGS_OFFSET) &
++					    EIP197_N_RINGS_MASK;
++		if (hiaopt & EIP197_HIA_OPT_HAS_PE_ARB)
++			priv->flags |= EIP197_PE_ARB;
++		if (EIP206_OPT_ICE_TYPE(peopt) == 1)
++			priv->flags |= EIP197_ICE;
++		/* If not a full TRC, then assume simple TRC */
++		if (!(hwopt & EIP197_OPT_HAS_TRC))
++			priv->flags |= EIP197_SIMPLE_TRC;
++		/* EIP197 always has SOME form of TRC */
++		priv->flags |= EIP197_TRC_CACHE;
+ 	} else {
+ 		/* EIP97 */
+ 		priv->hwconfig.hwdataw  = (hiaopt >> EIP197_HWDATAW_OFFSET) &
+@@ -1413,6 +1523,23 @@ static int safexcel_probe_generic(void *
+ 					  EIP97_CFSIZE_MASK;
+ 		priv->hwconfig.hwrfsize = (hiaopt >> EIP97_RFSIZE_OFFSET) &
+ 					  EIP97_RFSIZE_MASK;
++		priv->hwconfig.hwnumpes	= 1; /* by definition */
++		priv->hwconfig.hwnumrings = (hiaopt >> EIP197_N_RINGS_OFFSET) &
++					    EIP197_N_RINGS_MASK;
++	}
++
++	/* Scan for ring AIC's */
++	for (i = 0; i < EIP197_MAX_RING_AIC; i++) {
++		version = readl(EIP197_HIA_AIC_R(priv) +
++				EIP197_HIA_AIC_R_VERSION(i));
++		if (EIP197_REG_LO16(version) != EIP201_VERSION_LE)
++			break;
++	}
++	priv->hwconfig.hwnumraic = i;
++	/* Low-end EIP196 may not have any ring AIC's ... */
++	if (!priv->hwconfig.hwnumraic) {
++		dev_err(priv->dev, "No ring interrupt controller present!\n");
++		return -ENODEV;
+ 	}
+ 
+ 	/* Get supported algorithms from EIP96 transform engine */
+@@ -1420,10 +1547,12 @@ static int safexcel_probe_generic(void *
+ 				    EIP197_PE_EIP96_OPTIONS(0));
+ 
+ 	/* Print single info line describing what we just detected */
+-	dev_info(priv->dev, "EIP%d:%x(%d)-HIA:%x(%d,%d,%d),PE:%x,alg:%08x\n",
+-		 peid, priv->hwconfig.hwver, hwctg, priv->hwconfig.hiaver,
+-		 priv->hwconfig.hwdataw, priv->hwconfig.hwcfsize,
+-		 priv->hwconfig.hwrfsize, priv->hwconfig.pever,
++	dev_info(priv->dev, "EIP%d:%x(%d,%d,%d,%d)-HIA:%x(%d,%d,%d),PE:%x/%x,alg:%08x\n",
++		 peid, priv->hwconfig.hwver, hwctg, priv->hwconfig.hwnumpes,
++		 priv->hwconfig.hwnumrings, priv->hwconfig.hwnumraic,
++		 priv->hwconfig.hiaver, priv->hwconfig.hwdataw,
++		 priv->hwconfig.hwcfsize, priv->hwconfig.hwrfsize,
++		 priv->hwconfig.ppver, priv->hwconfig.pever,
+ 		 priv->hwconfig.algo_flags);
+ 
+ 	safexcel_configure(priv);
+@@ -1547,7 +1676,6 @@ static void safexcel_hw_reset_rings(stru
+ 	}
+ }
+ 
+-#if IS_ENABLED(CONFIG_OF)
+ /* for Device Tree platform driver */
+ 
+ static int safexcel_probe(struct platform_device *pdev)
+@@ -1625,6 +1753,7 @@ static int safexcel_remove(struct platfo
+ 	safexcel_unregister_algorithms(priv);
+ 	safexcel_hw_reset_rings(priv);
+ 
++	clk_disable_unprepare(priv->reg_clk);
+ 	clk_disable_unprepare(priv->clk);
+ 
+ 	for (i = 0; i < priv->config.rings; i++)
+@@ -1666,9 +1795,7 @@ static struct platform_driver  crypto_sa
+ 		.of_match_table = safexcel_of_match_table,
+ 	},
+ };
+-#endif
+ 
+-#if IS_ENABLED(CONFIG_PCI)
+ /* PCIE devices - i.e. Inside Secure development boards */
+ 
+ static int safexcel_pci_probe(struct pci_dev *pdev,
+@@ -1759,7 +1886,7 @@ static int safexcel_pci_probe(struct pci
+ 	return rc;
+ }
+ 
+-void safexcel_pci_remove(struct pci_dev *pdev)
++static void safexcel_pci_remove(struct pci_dev *pdev)
+ {
+ 	struct safexcel_crypto_priv *priv = pci_get_drvdata(pdev);
+ 	int i;
+@@ -1789,54 +1916,32 @@ static struct pci_driver safexcel_pci_dr
+ 	.probe         = safexcel_pci_probe,
+ 	.remove        = safexcel_pci_remove,
+ };
+-#endif
+-
+-/* Unfortunately, we have to resort to global variables here */
+-#if IS_ENABLED(CONFIG_PCI)
+-int pcireg_rc = -EINVAL; /* Default safe value */
+-#endif
+-#if IS_ENABLED(CONFIG_OF)
+-int ofreg_rc = -EINVAL; /* Default safe value */
+-#endif
+ 
+ static int __init safexcel_init(void)
+ {
+-#if IS_ENABLED(CONFIG_PCI)
++	int ret;
++
+ 	/* Register PCI driver */
+-	pcireg_rc = pci_register_driver(&safexcel_pci_driver);
+-#endif
++	ret = pci_register_driver(&safexcel_pci_driver);
+ 
+-#if IS_ENABLED(CONFIG_OF)
+ 	/* Register platform driver */
+-	ofreg_rc = platform_driver_register(&crypto_safexcel);
+- #if IS_ENABLED(CONFIG_PCI)
+-	/* Return success if either PCI or OF registered OK */
+-	return pcireg_rc ? ofreg_rc : 0;
+- #else
+-	return ofreg_rc;
+- #endif
+-#else
+- #if IS_ENABLED(CONFIG_PCI)
+-	return pcireg_rc;
+- #else
+-	return -EINVAL;
+- #endif
+-#endif
++	if (IS_ENABLED(CONFIG_OF) && !ret) {
++		ret = platform_driver_register(&crypto_safexcel);
++		if (ret)
++			pci_unregister_driver(&safexcel_pci_driver);
++	}
++
++	return ret;
+ }
+ 
+ static void __exit safexcel_exit(void)
+ {
+-#if IS_ENABLED(CONFIG_OF)
+ 	/* Unregister platform driver */
+-	if (!ofreg_rc)
++	if (IS_ENABLED(CONFIG_OF))
+ 		platform_driver_unregister(&crypto_safexcel);
+-#endif
+ 
+-#if IS_ENABLED(CONFIG_PCI)
+ 	/* Unregister PCI driver if successfully registered before */
+-	if (!pcireg_rc)
+-		pci_unregister_driver(&safexcel_pci_driver);
+-#endif
++	pci_unregister_driver(&safexcel_pci_driver);
+ }
+ 
+ module_init(safexcel_init);
+--- a/drivers/crypto/inside-secure/safexcel_cipher.c
++++ b/drivers/crypto/inside-secure/safexcel_cipher.c
+@@ -5,18 +5,22 @@
+  * Antoine Tenart <antoine.tenart@free-electrons.com>
+  */
+ 
++#include <asm/unaligned.h>
+ #include <linux/device.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/dmapool.h>
+-
+ #include <crypto/aead.h>
+ #include <crypto/aes.h>
+ #include <crypto/authenc.h>
++#include <crypto/chacha.h>
+ #include <crypto/ctr.h>
+ #include <crypto/internal/des.h>
+ #include <crypto/gcm.h>
+ #include <crypto/ghash.h>
++#include <crypto/poly1305.h>
+ #include <crypto/sha.h>
++#include <crypto/sm3.h>
++#include <crypto/sm4.h>
+ #include <crypto/xts.h>
+ #include <crypto/skcipher.h>
+ #include <crypto/internal/aead.h>
+@@ -33,6 +37,8 @@ enum safexcel_cipher_alg {
+ 	SAFEXCEL_DES,
+ 	SAFEXCEL_3DES,
+ 	SAFEXCEL_AES,
++	SAFEXCEL_CHACHA20,
++	SAFEXCEL_SM4,
+ };
+ 
+ struct safexcel_cipher_ctx {
+@@ -41,8 +47,12 @@ struct safexcel_cipher_ctx {
+ 
+ 	u32 mode;
+ 	enum safexcel_cipher_alg alg;
+-	bool aead;
+-	int  xcm; /* 0=authenc, 1=GCM, 2 reserved for CCM */
++	u8 aead; /* !=0=AEAD, 2=IPSec ESP AEAD, 3=IPsec ESP GMAC */
++	u8 xcm;  /* 0=authenc, 1=GCM, 2 reserved for CCM */
++	u8 aadskip;
++	u8 blocksz;
++	u32 ivmask;
++	u32 ctrinit;
+ 
+ 	__le32 key[16];
+ 	u32 nonce;
+@@ -51,10 +61,11 @@ struct safexcel_cipher_ctx {
+ 	/* All the below is AEAD specific */
+ 	u32 hash_alg;
+ 	u32 state_sz;
+-	u32 ipad[SHA512_DIGEST_SIZE / sizeof(u32)];
+-	u32 opad[SHA512_DIGEST_SIZE / sizeof(u32)];
++	__be32 ipad[SHA512_DIGEST_SIZE / sizeof(u32)];
++	__be32 opad[SHA512_DIGEST_SIZE / sizeof(u32)];
+ 
+ 	struct crypto_cipher *hkaes;
++	struct crypto_aead *fback;
+ };
+ 
+ struct safexcel_cipher_req {
+@@ -65,206 +76,298 @@ struct safexcel_cipher_req {
+ 	int  nr_src, nr_dst;
+ };
+ 
+-static void safexcel_cipher_token(struct safexcel_cipher_ctx *ctx, u8 *iv,
+-				  struct safexcel_command_desc *cdesc)
++static int safexcel_skcipher_iv(struct safexcel_cipher_ctx *ctx, u8 *iv,
++				struct safexcel_command_desc *cdesc)
+ {
+-	u32 block_sz = 0;
+-
+ 	if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD) {
+ 		cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD;
+-
+ 		/* 32 bit nonce */
+ 		cdesc->control_data.token[0] = ctx->nonce;
+ 		/* 64 bit IV part */
+ 		memcpy(&cdesc->control_data.token[1], iv, 8);
+-		/* 32 bit counter, start at 1 (big endian!) */
+-		cdesc->control_data.token[3] = cpu_to_be32(1);
+-
+-		return;
+-	} else if (ctx->xcm == EIP197_XCM_MODE_GCM) {
+-		cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD;
+-
+-		/* 96 bit IV part */
+-		memcpy(&cdesc->control_data.token[0], iv, 12);
+-		/* 32 bit counter, start at 1 (big endian!) */
+-		cdesc->control_data.token[3] = cpu_to_be32(1);
+-
+-		return;
+-	} else if (ctx->xcm == EIP197_XCM_MODE_CCM) {
++		/* 32 bit counter, start at 0 or 1 (big endian!) */
++		cdesc->control_data.token[3] =
++			(__force u32)cpu_to_be32(ctx->ctrinit);
++		return 4;
++	}
++	if (ctx->alg == SAFEXCEL_CHACHA20) {
+ 		cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD;
+-
+-		/* Variable length IV part */
+-		memcpy(&cdesc->control_data.token[0], iv, 15 - iv[0]);
+-		/* Start variable length counter at 0 */
+-		memset((u8 *)&cdesc->control_data.token[0] + 15 - iv[0],
+-		       0, iv[0] + 1);
+-
+-		return;
++		/* 96 bit nonce part */
++		memcpy(&cdesc->control_data.token[0], &iv[4], 12);
++		/* 32 bit counter */
++		cdesc->control_data.token[3] = *(u32 *)iv;
++		return 4;
+ 	}
+ 
+-	if (ctx->mode != CONTEXT_CONTROL_CRYPTO_MODE_ECB) {
+-		switch (ctx->alg) {
+-		case SAFEXCEL_DES:
+-			block_sz = DES_BLOCK_SIZE;
+-			cdesc->control_data.options |= EIP197_OPTION_2_TOKEN_IV_CMD;
+-			break;
+-		case SAFEXCEL_3DES:
+-			block_sz = DES3_EDE_BLOCK_SIZE;
+-			cdesc->control_data.options |= EIP197_OPTION_2_TOKEN_IV_CMD;
+-			break;
+-		case SAFEXCEL_AES:
+-			block_sz = AES_BLOCK_SIZE;
+-			cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD;
+-			break;
+-		}
+-		memcpy(cdesc->control_data.token, iv, block_sz);
+-	}
++	cdesc->control_data.options |= ctx->ivmask;
++	memcpy(cdesc->control_data.token, iv, ctx->blocksz);
++	return ctx->blocksz / sizeof(u32);
+ }
+ 
+ static void safexcel_skcipher_token(struct safexcel_cipher_ctx *ctx, u8 *iv,
+ 				    struct safexcel_command_desc *cdesc,
++				    struct safexcel_token *atoken,
+ 				    u32 length)
+ {
+ 	struct safexcel_token *token;
++	int ivlen;
+ 
+-	safexcel_cipher_token(ctx, iv, cdesc);
+-
+-	/* skip over worst case IV of 4 dwords, no need to be exact */
+-	token = (struct safexcel_token *)(cdesc->control_data.token + 4);
++	ivlen = safexcel_skcipher_iv(ctx, iv, cdesc);
++	if (ivlen == 4) {
++		/* No space in cdesc, instruction moves to atoken */
++		cdesc->additional_cdata_size = 1;
++		token = atoken;
++	} else {
++		/* Everything fits in cdesc */
++		token = (struct safexcel_token *)(cdesc->control_data.token + 2);
++		/* Need to pad with NOP */
++		eip197_noop_token(&token[1]);
++	}
++
++	token->opcode = EIP197_TOKEN_OPCODE_DIRECTION;
++	token->packet_length = length;
++	token->stat = EIP197_TOKEN_STAT_LAST_PACKET |
++		      EIP197_TOKEN_STAT_LAST_HASH;
++	token->instructions = EIP197_TOKEN_INS_LAST |
++			      EIP197_TOKEN_INS_TYPE_CRYPTO |
++			      EIP197_TOKEN_INS_TYPE_OUTPUT;
++}
+ 
+-	token[0].opcode = EIP197_TOKEN_OPCODE_DIRECTION;
+-	token[0].packet_length = length;
+-	token[0].stat = EIP197_TOKEN_STAT_LAST_PACKET |
+-			EIP197_TOKEN_STAT_LAST_HASH;
+-	token[0].instructions = EIP197_TOKEN_INS_LAST |
+-				EIP197_TOKEN_INS_TYPE_CRYPTO |
+-				EIP197_TOKEN_INS_TYPE_OUTPUT;
++static void safexcel_aead_iv(struct safexcel_cipher_ctx *ctx, u8 *iv,
++			     struct safexcel_command_desc *cdesc)
++{
++	if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD ||
++	    ctx->aead & EIP197_AEAD_TYPE_IPSEC_ESP) { /* _ESP and _ESP_GMAC */
++		/* 32 bit nonce */
++		cdesc->control_data.token[0] = ctx->nonce;
++		/* 64 bit IV part */
++		memcpy(&cdesc->control_data.token[1], iv, 8);
++		/* 32 bit counter, start at 0 or 1 (big endian!) */
++		cdesc->control_data.token[3] =
++			(__force u32)cpu_to_be32(ctx->ctrinit);
++		return;
++	}
++	if (ctx->xcm == EIP197_XCM_MODE_GCM || ctx->alg == SAFEXCEL_CHACHA20) {
++		/* 96 bit IV part */
++		memcpy(&cdesc->control_data.token[0], iv, 12);
++		/* 32 bit counter, start at 0 or 1 (big endian!) */
++		cdesc->control_data.token[3] =
++			(__force u32)cpu_to_be32(ctx->ctrinit);
++		return;
++	}
++	/* CBC */
++	memcpy(cdesc->control_data.token, iv, ctx->blocksz);
+ }
+ 
+ static void safexcel_aead_token(struct safexcel_cipher_ctx *ctx, u8 *iv,
+ 				struct safexcel_command_desc *cdesc,
++				struct safexcel_token *atoken,
+ 				enum safexcel_cipher_direction direction,
+ 				u32 cryptlen, u32 assoclen, u32 digestsize)
+ {
+-	struct safexcel_token *token;
++	struct safexcel_token *aadref;
++	int atoksize = 2; /* Start with minimum size */
++	int assocadj = assoclen - ctx->aadskip, aadalign;
+ 
+-	safexcel_cipher_token(ctx, iv, cdesc);
++	/* Always 4 dwords of embedded IV  for AEAD modes */
++	cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD;
+ 
+-	if (direction == SAFEXCEL_ENCRYPT) {
+-		/* align end of instruction sequence to end of token */
+-		token = (struct safexcel_token *)(cdesc->control_data.token +
+-			 EIP197_MAX_TOKENS - 13);
+-
+-		token[12].opcode = EIP197_TOKEN_OPCODE_INSERT;
+-		token[12].packet_length = digestsize;
+-		token[12].stat = EIP197_TOKEN_STAT_LAST_HASH |
+-				 EIP197_TOKEN_STAT_LAST_PACKET;
+-		token[12].instructions = EIP197_TOKEN_INS_TYPE_OUTPUT |
+-					 EIP197_TOKEN_INS_INSERT_HASH_DIGEST;
+-	} else {
++	if (direction == SAFEXCEL_DECRYPT)
+ 		cryptlen -= digestsize;
+ 
+-		/* align end of instruction sequence to end of token */
+-		token = (struct safexcel_token *)(cdesc->control_data.token +
+-			 EIP197_MAX_TOKENS - 14);
+-
+-		token[12].opcode = EIP197_TOKEN_OPCODE_RETRIEVE;
+-		token[12].packet_length = digestsize;
+-		token[12].stat = EIP197_TOKEN_STAT_LAST_HASH |
+-				 EIP197_TOKEN_STAT_LAST_PACKET;
+-		token[12].instructions = EIP197_TOKEN_INS_INSERT_HASH_DIGEST;
+-
+-		token[13].opcode = EIP197_TOKEN_OPCODE_VERIFY;
+-		token[13].packet_length = digestsize |
+-					  EIP197_TOKEN_HASH_RESULT_VERIFY;
+-		token[13].stat = EIP197_TOKEN_STAT_LAST_HASH |
+-				 EIP197_TOKEN_STAT_LAST_PACKET;
+-		token[13].instructions = EIP197_TOKEN_INS_TYPE_OUTPUT;
+-	}
+-
+-	token[6].opcode = EIP197_TOKEN_OPCODE_DIRECTION;
+-	token[6].packet_length = assoclen;
+-
+-	if (likely(cryptlen)) {
+-		token[6].instructions = EIP197_TOKEN_INS_TYPE_HASH;
+-
+-		token[10].opcode = EIP197_TOKEN_OPCODE_DIRECTION;
+-		token[10].packet_length = cryptlen;
+-		token[10].stat = EIP197_TOKEN_STAT_LAST_HASH;
+-		token[10].instructions = EIP197_TOKEN_INS_LAST |
+-					 EIP197_TOKEN_INS_TYPE_CRYPTO |
+-					 EIP197_TOKEN_INS_TYPE_HASH |
+-					 EIP197_TOKEN_INS_TYPE_OUTPUT;
+-	} else if (ctx->xcm != EIP197_XCM_MODE_CCM) {
+-		token[6].stat = EIP197_TOKEN_STAT_LAST_HASH;
+-		token[6].instructions = EIP197_TOKEN_INS_LAST |
+-					EIP197_TOKEN_INS_TYPE_HASH;
+-	}
+-
+-	if (!ctx->xcm)
+-		return;
+-
+-	token[8].opcode = EIP197_TOKEN_OPCODE_INSERT_REMRES;
+-	token[8].packet_length = 0;
+-	token[8].instructions = AES_BLOCK_SIZE;
+-
+-	token[9].opcode = EIP197_TOKEN_OPCODE_INSERT;
+-	token[9].packet_length = AES_BLOCK_SIZE;
+-	token[9].instructions = EIP197_TOKEN_INS_TYPE_OUTPUT |
+-				EIP197_TOKEN_INS_TYPE_CRYPTO;
+-
+-	if (ctx->xcm == EIP197_XCM_MODE_GCM) {
+-		token[6].instructions = EIP197_TOKEN_INS_LAST |
+-					EIP197_TOKEN_INS_TYPE_HASH;
+-	} else {
+-		u8 *cbcmaciv = (u8 *)&token[1];
+-		u32 *aadlen = (u32 *)&token[5];
+-
++	if (unlikely(ctx->xcm == EIP197_XCM_MODE_CCM)) {
+ 		/* Construct IV block B0 for the CBC-MAC */
+-		token[0].opcode = EIP197_TOKEN_OPCODE_INSERT;
+-		token[0].packet_length = AES_BLOCK_SIZE +
+-					 ((assoclen > 0) << 1);
+-		token[0].instructions = EIP197_TOKEN_INS_ORIGIN_TOKEN |
+-					EIP197_TOKEN_INS_TYPE_HASH;
+-		/* Variable length IV part */
+-		memcpy(cbcmaciv, iv, 15 - iv[0]);
+-		/* fixup flags byte */
+-		cbcmaciv[0] |= ((assoclen > 0) << 6) | ((digestsize - 2) << 2);
+-		/* Clear upper bytes of variable message length to 0 */
+-		memset(cbcmaciv + 15 - iv[0], 0, iv[0] - 1);
+-		/* insert lower 2 bytes of message length */
+-		cbcmaciv[14] = cryptlen >> 8;
+-		cbcmaciv[15] = cryptlen & 255;
+-
+-		if (assoclen) {
+-			*aadlen = cpu_to_le32(cpu_to_be16(assoclen));
+-			assoclen += 2;
++		u8 *final_iv = (u8 *)cdesc->control_data.token;
++		u8 *cbcmaciv = (u8 *)&atoken[1];
++		__le32 *aadlen = (__le32 *)&atoken[5];
++
++		if (ctx->aead == EIP197_AEAD_TYPE_IPSEC_ESP) {
++			/* Length + nonce */
++			cdesc->control_data.token[0] = ctx->nonce;
++			/* Fixup flags byte */
++			*(__le32 *)cbcmaciv =
++				cpu_to_le32(ctx->nonce |
++					    ((assocadj > 0) << 6) |
++					    ((digestsize - 2) << 2));
++			/* 64 bit IV part */
++			memcpy(&cdesc->control_data.token[1], iv, 8);
++			memcpy(cbcmaciv + 4, iv, 8);
++			/* Start counter at 0 */
++			cdesc->control_data.token[3] = 0;
++			/* Message length */
++			*(__be32 *)(cbcmaciv + 12) = cpu_to_be32(cryptlen);
++		} else {
++			/* Variable length IV part */
++			memcpy(final_iv, iv, 15 - iv[0]);
++			memcpy(cbcmaciv, iv, 15 - iv[0]);
++			/* Start variable length counter at 0 */
++			memset(final_iv + 15 - iv[0], 0, iv[0] + 1);
++			memset(cbcmaciv + 15 - iv[0], 0, iv[0] - 1);
++			/* fixup flags byte */
++			cbcmaciv[0] |= ((assocadj > 0) << 6) |
++				       ((digestsize - 2) << 2);
++			/* insert lower 2 bytes of message length */
++			cbcmaciv[14] = cryptlen >> 8;
++			cbcmaciv[15] = cryptlen & 255;
++		}
++
++		atoken->opcode = EIP197_TOKEN_OPCODE_INSERT;
++		atoken->packet_length = AES_BLOCK_SIZE +
++					((assocadj > 0) << 1);
++		atoken->stat = 0;
++		atoken->instructions = EIP197_TOKEN_INS_ORIGIN_TOKEN |
++				       EIP197_TOKEN_INS_TYPE_HASH;
++
++		if (likely(assocadj)) {
++			*aadlen = cpu_to_le32((assocadj >> 8) |
++					      (assocadj & 255) << 8);
++			atoken += 6;
++			atoksize += 7;
++		} else {
++			atoken += 5;
++			atoksize += 6;
+ 		}
+ 
+-		token[6].instructions = EIP197_TOKEN_INS_TYPE_HASH;
+-
+-		/* Align AAD data towards hash engine */
+-		token[7].opcode = EIP197_TOKEN_OPCODE_INSERT;
+-		assoclen &= 15;
+-		token[7].packet_length = assoclen ? 16 - assoclen : 0;
+-
++		/* Process AAD data */
++		aadref = atoken;
++		atoken->opcode = EIP197_TOKEN_OPCODE_DIRECTION;
++		atoken->packet_length = assocadj;
++		atoken->stat = 0;
++		atoken->instructions = EIP197_TOKEN_INS_TYPE_HASH;
++		atoken++;
++
++		/* For CCM only, align AAD data towards hash engine */
++		atoken->opcode = EIP197_TOKEN_OPCODE_INSERT;
++		aadalign = (assocadj + 2) & 15;
++		atoken->packet_length = assocadj && aadalign ?
++						16 - aadalign :
++						0;
+ 		if (likely(cryptlen)) {
+-			token[7].instructions = EIP197_TOKEN_INS_TYPE_HASH;
+-
+-			/* Align crypto data towards hash engine */
+-			token[10].stat = 0;
++			atoken->stat = 0;
++			atoken->instructions = EIP197_TOKEN_INS_TYPE_HASH;
++		} else {
++			atoken->stat = EIP197_TOKEN_STAT_LAST_HASH;
++			atoken->instructions = EIP197_TOKEN_INS_LAST |
++					       EIP197_TOKEN_INS_TYPE_HASH;
++		}
++	} else {
++		safexcel_aead_iv(ctx, iv, cdesc);
+ 
+-			token[11].opcode = EIP197_TOKEN_OPCODE_INSERT;
+-			cryptlen &= 15;
+-			token[11].packet_length = cryptlen ? 16 - cryptlen : 0;
+-			token[11].stat = EIP197_TOKEN_STAT_LAST_HASH;
+-			token[11].instructions = EIP197_TOKEN_INS_TYPE_HASH;
++		/* Process AAD data */
++		aadref = atoken;
++		atoken->opcode = EIP197_TOKEN_OPCODE_DIRECTION;
++		atoken->packet_length = assocadj;
++		atoken->stat = EIP197_TOKEN_STAT_LAST_HASH;
++		atoken->instructions = EIP197_TOKEN_INS_LAST |
++				       EIP197_TOKEN_INS_TYPE_HASH;
++	}
++	atoken++;
++
++	if (ctx->aead == EIP197_AEAD_TYPE_IPSEC_ESP) {
++		/* For ESP mode (and not GMAC), skip over the IV */
++		atoken->opcode = EIP197_TOKEN_OPCODE_DIRECTION;
++		atoken->packet_length = EIP197_AEAD_IPSEC_IV_SIZE;
++		atoken->stat = 0;
++		atoken->instructions = 0;
++		atoken++;
++		atoksize++;
++	} else if (unlikely(ctx->alg == SAFEXCEL_CHACHA20 &&
++			    direction == SAFEXCEL_DECRYPT)) {
++		/* Poly-chacha decryption needs a dummy NOP here ... */
++		atoken->opcode = EIP197_TOKEN_OPCODE_INSERT;
++		atoken->packet_length = 16; /* According to Op Manual */
++		atoken->stat = 0;
++		atoken->instructions = 0;
++		atoken++;
++		atoksize++;
++	}
++
++	if  (ctx->xcm) {
++		/* For GCM and CCM, obtain enc(Y0) */
++		atoken->opcode = EIP197_TOKEN_OPCODE_INSERT_REMRES;
++		atoken->packet_length = 0;
++		atoken->stat = 0;
++		atoken->instructions = AES_BLOCK_SIZE;
++		atoken++;
++
++		atoken->opcode = EIP197_TOKEN_OPCODE_INSERT;
++		atoken->packet_length = AES_BLOCK_SIZE;
++		atoken->stat = 0;
++		atoken->instructions = EIP197_TOKEN_INS_TYPE_OUTPUT |
++				       EIP197_TOKEN_INS_TYPE_CRYPTO;
++		atoken++;
++		atoksize += 2;
++	}
++
++	if (likely(cryptlen || ctx->alg == SAFEXCEL_CHACHA20)) {
++		/* Fixup stat field for AAD direction instruction */
++		aadref->stat = 0;
++
++		/* Process crypto data */
++		atoken->opcode = EIP197_TOKEN_OPCODE_DIRECTION;
++		atoken->packet_length = cryptlen;
++
++		if (unlikely(ctx->aead == EIP197_AEAD_TYPE_IPSEC_ESP_GMAC)) {
++			/* Fixup instruction field for AAD dir instruction */
++			aadref->instructions = EIP197_TOKEN_INS_TYPE_HASH;
++
++			/* Do not send to crypt engine in case of GMAC */
++			atoken->instructions = EIP197_TOKEN_INS_LAST |
++					       EIP197_TOKEN_INS_TYPE_HASH |
++					       EIP197_TOKEN_INS_TYPE_OUTPUT;
++		} else {
++			atoken->instructions = EIP197_TOKEN_INS_LAST |
++					       EIP197_TOKEN_INS_TYPE_CRYPTO |
++					       EIP197_TOKEN_INS_TYPE_HASH |
++					       EIP197_TOKEN_INS_TYPE_OUTPUT;
++		}
++
++		cryptlen &= 15;
++		if (unlikely(ctx->xcm == EIP197_XCM_MODE_CCM && cryptlen)) {
++			atoken->stat = 0;
++			/* For CCM only, pad crypto data to the hash engine */
++			atoken++;
++			atoksize++;
++			atoken->opcode = EIP197_TOKEN_OPCODE_INSERT;
++			atoken->packet_length = 16 - cryptlen;
++			atoken->stat = EIP197_TOKEN_STAT_LAST_HASH;
++			atoken->instructions = EIP197_TOKEN_INS_TYPE_HASH;
+ 		} else {
+-			token[7].stat = EIP197_TOKEN_STAT_LAST_HASH;
+-			token[7].instructions = EIP197_TOKEN_INS_LAST |
+-						EIP197_TOKEN_INS_TYPE_HASH;
++			atoken->stat = EIP197_TOKEN_STAT_LAST_HASH;
+ 		}
++		atoken++;
++		atoksize++;
+ 	}
++
++	if (direction == SAFEXCEL_ENCRYPT) {
++		/* Append ICV */
++		atoken->opcode = EIP197_TOKEN_OPCODE_INSERT;
++		atoken->packet_length = digestsize;
++		atoken->stat = EIP197_TOKEN_STAT_LAST_HASH |
++			       EIP197_TOKEN_STAT_LAST_PACKET;
++		atoken->instructions = EIP197_TOKEN_INS_TYPE_OUTPUT |
++				       EIP197_TOKEN_INS_INSERT_HASH_DIGEST;
++	} else {
++		/* Extract ICV */
++		atoken->opcode = EIP197_TOKEN_OPCODE_RETRIEVE;
++		atoken->packet_length = digestsize;
++		atoken->stat = EIP197_TOKEN_STAT_LAST_HASH |
++			       EIP197_TOKEN_STAT_LAST_PACKET;
++		atoken->instructions = EIP197_TOKEN_INS_INSERT_HASH_DIGEST;
++		atoken++;
++		atoksize++;
++
++		/* Verify ICV */
++		atoken->opcode = EIP197_TOKEN_OPCODE_VERIFY;
++		atoken->packet_length = digestsize |
++					EIP197_TOKEN_HASH_RESULT_VERIFY;
++		atoken->stat = EIP197_TOKEN_STAT_LAST_HASH |
++			       EIP197_TOKEN_STAT_LAST_PACKET;
++		atoken->instructions = EIP197_TOKEN_INS_TYPE_OUTPUT;
++	}
++
++	/* Fixup length of the token in the command descriptor */
++	cdesc->additional_cdata_size = atoksize;
+ }
+ 
+ static int safexcel_skcipher_aes_setkey(struct crypto_skcipher *ctfm,
+@@ -277,14 +380,12 @@ static int safexcel_skcipher_aes_setkey(
+ 	int ret, i;
+ 
+ 	ret = aes_expandkey(&aes, key, len);
+-	if (ret) {
+-		crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
++	if (ret)
+ 		return ret;
+-	}
+ 
+ 	if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) {
+ 		for (i = 0; i < len / sizeof(u32); i++) {
+-			if (ctx->key[i] != cpu_to_le32(aes.key_enc[i])) {
++			if (le32_to_cpu(ctx->key[i]) != aes.key_enc[i]) {
+ 				ctx->base.needs_inv = true;
+ 				break;
+ 			}
+@@ -309,43 +410,57 @@ static int safexcel_aead_setkey(struct c
+ 	struct safexcel_crypto_priv *priv = ctx->priv;
+ 	struct crypto_authenc_keys keys;
+ 	struct crypto_aes_ctx aes;
+-	int err = -EINVAL;
++	int err = -EINVAL, i;
+ 
+-	if (crypto_authenc_extractkeys(&keys, key, len) != 0)
++	if (unlikely(crypto_authenc_extractkeys(&keys, key, len)))
+ 		goto badkey;
+ 
+ 	if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD) {
+-		/* Minimum keysize is minimum AES key size + nonce size */
+-		if (keys.enckeylen < (AES_MIN_KEY_SIZE +
+-				      CTR_RFC3686_NONCE_SIZE))
++		/* Must have at least space for the nonce here */
++		if (unlikely(keys.enckeylen < CTR_RFC3686_NONCE_SIZE))
+ 			goto badkey;
+ 		/* last 4 bytes of key are the nonce! */
+ 		ctx->nonce = *(u32 *)(keys.enckey + keys.enckeylen -
+ 				      CTR_RFC3686_NONCE_SIZE);
+ 		/* exclude the nonce here */
+-		keys.enckeylen -= CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD;
++		keys.enckeylen -= CTR_RFC3686_NONCE_SIZE;
+ 	}
+ 
+ 	/* Encryption key */
+ 	switch (ctx->alg) {
++	case SAFEXCEL_DES:
++		err = verify_aead_des_key(ctfm, keys.enckey, keys.enckeylen);
++		if (unlikely(err))
++			goto badkey;
++		break;
+ 	case SAFEXCEL_3DES:
+ 		err = verify_aead_des3_key(ctfm, keys.enckey, keys.enckeylen);
+ 		if (unlikely(err))
+-			goto badkey_expflags;
++			goto badkey;
+ 		break;
+ 	case SAFEXCEL_AES:
+ 		err = aes_expandkey(&aes, keys.enckey, keys.enckeylen);
+ 		if (unlikely(err))
+ 			goto badkey;
+ 		break;
++	case SAFEXCEL_SM4:
++		if (unlikely(keys.enckeylen != SM4_KEY_SIZE))
++			goto badkey;
++		break;
+ 	default:
+ 		dev_err(priv->dev, "aead: unsupported cipher algorithm\n");
+ 		goto badkey;
+ 	}
+ 
+-	if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma &&
+-	    memcmp(ctx->key, keys.enckey, keys.enckeylen))
+-		ctx->base.needs_inv = true;
++	if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) {
++		for (i = 0; i < keys.enckeylen / sizeof(u32); i++) {
++			if (le32_to_cpu(ctx->key[i]) !=
++			    ((u32 *)keys.enckey)[i]) {
++				ctx->base.needs_inv = true;
++				break;
++			}
++		}
++	}
+ 
+ 	/* Auth key */
+ 	switch (ctx->hash_alg) {
+@@ -374,21 +489,24 @@ static int safexcel_aead_setkey(struct c
+ 					 keys.authkeylen, &istate, &ostate))
+ 			goto badkey;
+ 		break;
++	case CONTEXT_CONTROL_CRYPTO_ALG_SM3:
++		if (safexcel_hmac_setkey("safexcel-sm3", keys.authkey,
++					 keys.authkeylen, &istate, &ostate))
++			goto badkey;
++		break;
+ 	default:
+ 		dev_err(priv->dev, "aead: unsupported hash algorithm\n");
+ 		goto badkey;
+ 	}
+ 
+-	crypto_aead_set_flags(ctfm, crypto_aead_get_flags(ctfm) &
+-				    CRYPTO_TFM_RES_MASK);
+-
+ 	if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma &&
+ 	    (memcmp(ctx->ipad, istate.state, ctx->state_sz) ||
+ 	     memcmp(ctx->opad, ostate.state, ctx->state_sz)))
+ 		ctx->base.needs_inv = true;
+ 
+ 	/* Now copy the keys into the context */
+-	memcpy(ctx->key, keys.enckey, keys.enckeylen);
++	for (i = 0; i < keys.enckeylen / sizeof(u32); i++)
++		ctx->key[i] = cpu_to_le32(((u32 *)keys.enckey)[i]);
+ 	ctx->key_len = keys.enckeylen;
+ 
+ 	memcpy(ctx->ipad, &istate.state, ctx->state_sz);
+@@ -398,8 +516,6 @@ static int safexcel_aead_setkey(struct c
+ 	return 0;
+ 
+ badkey:
+-	crypto_aead_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+-badkey_expflags:
+ 	memzero_explicit(&keys, sizeof(keys));
+ 	return err;
+ }
+@@ -423,6 +539,17 @@ static int safexcel_context_control(stru
+ 				CONTEXT_CONTROL_DIGEST_XCM |
+ 				ctx->hash_alg |
+ 				CONTEXT_CONTROL_SIZE(ctrl_size);
++		} else if (ctx->alg == SAFEXCEL_CHACHA20) {
++			/* Chacha20-Poly1305 */
++			cdesc->control_data.control0 =
++				CONTEXT_CONTROL_KEY_EN |
++				CONTEXT_CONTROL_CRYPTO_ALG_CHACHA20 |
++				(sreq->direction == SAFEXCEL_ENCRYPT ?
++					CONTEXT_CONTROL_TYPE_ENCRYPT_HASH_OUT :
++					CONTEXT_CONTROL_TYPE_HASH_DECRYPT_IN) |
++				ctx->hash_alg |
++				CONTEXT_CONTROL_SIZE(ctrl_size);
++			return 0;
+ 		} else {
+ 			ctrl_size += ctx->state_sz / sizeof(u32) * 2;
+ 			cdesc->control_data.control0 =
+@@ -431,17 +558,21 @@ static int safexcel_context_control(stru
+ 				ctx->hash_alg |
+ 				CONTEXT_CONTROL_SIZE(ctrl_size);
+ 		}
+-		if (sreq->direction == SAFEXCEL_ENCRYPT)
+-			cdesc->control_data.control0 |=
+-				(ctx->xcm == EIP197_XCM_MODE_CCM) ?
+-					CONTEXT_CONTROL_TYPE_HASH_ENCRYPT_OUT :
+-					CONTEXT_CONTROL_TYPE_ENCRYPT_HASH_OUT;
+ 
++		if (sreq->direction == SAFEXCEL_ENCRYPT &&
++		    (ctx->xcm == EIP197_XCM_MODE_CCM ||
++		     ctx->aead == EIP197_AEAD_TYPE_IPSEC_ESP_GMAC))
++			cdesc->control_data.control0 |=
++				CONTEXT_CONTROL_TYPE_HASH_ENCRYPT_OUT;
++		else if (sreq->direction == SAFEXCEL_ENCRYPT)
++			cdesc->control_data.control0 |=
++				CONTEXT_CONTROL_TYPE_ENCRYPT_HASH_OUT;
++		else if (ctx->xcm == EIP197_XCM_MODE_CCM)
++			cdesc->control_data.control0 |=
++				CONTEXT_CONTROL_TYPE_DECRYPT_HASH_IN;
+ 		else
+ 			cdesc->control_data.control0 |=
+-				(ctx->xcm == EIP197_XCM_MODE_CCM) ?
+-					CONTEXT_CONTROL_TYPE_DECRYPT_HASH_IN :
+-					CONTEXT_CONTROL_TYPE_HASH_DECRYPT_IN;
++				CONTEXT_CONTROL_TYPE_HASH_DECRYPT_IN;
+ 	} else {
+ 		if (sreq->direction == SAFEXCEL_ENCRYPT)
+ 			cdesc->control_data.control0 =
+@@ -480,6 +611,12 @@ static int safexcel_context_control(stru
+ 				ctx->key_len >> ctx->xts);
+ 			return -EINVAL;
+ 		}
++	} else if (ctx->alg == SAFEXCEL_CHACHA20) {
++		cdesc->control_data.control0 |=
++			CONTEXT_CONTROL_CRYPTO_ALG_CHACHA20;
++	} else if (ctx->alg == SAFEXCEL_SM4) {
++		cdesc->control_data.control0 |=
++			CONTEXT_CONTROL_CRYPTO_ALG_SM4;
+ 	}
+ 
+ 	return 0;
+@@ -563,6 +700,7 @@ static int safexcel_send_req(struct cryp
+ 	unsigned int totlen;
+ 	unsigned int totlen_src = cryptlen + assoclen;
+ 	unsigned int totlen_dst = totlen_src;
++	struct safexcel_token *atoken;
+ 	int n_cdesc = 0, n_rdesc = 0;
+ 	int queued, i, ret = 0;
+ 	bool first = true;
+@@ -637,56 +775,60 @@ static int safexcel_send_req(struct cryp
+ 
+ 	memcpy(ctx->base.ctxr->data, ctx->key, ctx->key_len);
+ 
+-	/* The EIP cannot deal with zero length input packets! */
+-	if (totlen == 0)
+-		totlen = 1;
++	if (!totlen) {
++		/*
++		 * The EIP97 cannot deal with zero length input packets!
++		 * So stuff a dummy command descriptor indicating a 1 byte
++		 * (dummy) input packet, using the context record as source.
++		 */
++		first_cdesc = safexcel_add_cdesc(priv, ring,
++						 1, 1, ctx->base.ctxr_dma,
++						 1, 1, ctx->base.ctxr_dma,
++						 &atoken);
++		if (IS_ERR(first_cdesc)) {
++			/* No space left in the command descriptor ring */
++			ret = PTR_ERR(first_cdesc);
++			goto cdesc_rollback;
++		}
++		n_cdesc = 1;
++		goto skip_cdesc;
++	}
+ 
+ 	/* command descriptors */
+ 	for_each_sg(src, sg, sreq->nr_src, i) {
+ 		int len = sg_dma_len(sg);
+ 
+ 		/* Do not overflow the request */
+-		if (queued - len < 0)
++		if (queued < len)
+ 			len = queued;
+ 
+ 		cdesc = safexcel_add_cdesc(priv, ring, !n_cdesc,
+ 					   !(queued - len),
+ 					   sg_dma_address(sg), len, totlen,
+-					   ctx->base.ctxr_dma);
++					   ctx->base.ctxr_dma, &atoken);
+ 		if (IS_ERR(cdesc)) {
+ 			/* No space left in the command descriptor ring */
+ 			ret = PTR_ERR(cdesc);
+ 			goto cdesc_rollback;
+ 		}
+-		n_cdesc++;
+ 
+-		if (n_cdesc == 1) {
++		if (!n_cdesc)
+ 			first_cdesc = cdesc;
+-		}
+ 
++		n_cdesc++;
+ 		queued -= len;
+ 		if (!queued)
+ 			break;
+ 	}
+-
+-	if (unlikely(!n_cdesc)) {
+-		/*
+-		 * Special case: zero length input buffer.
+-		 * The engine always needs the 1st command descriptor, however!
+-		 */
+-		first_cdesc = safexcel_add_cdesc(priv, ring, 1, 1, 0, 0, totlen,
+-						 ctx->base.ctxr_dma);
+-		n_cdesc = 1;
+-	}
+-
++skip_cdesc:
+ 	/* Add context control words and token to first command descriptor */
+ 	safexcel_context_control(ctx, base, sreq, first_cdesc);
+ 	if (ctx->aead)
+-		safexcel_aead_token(ctx, iv, first_cdesc,
++		safexcel_aead_token(ctx, iv, first_cdesc, atoken,
+ 				    sreq->direction, cryptlen,
+ 				    assoclen, digestsize);
+ 	else
+-		safexcel_skcipher_token(ctx, iv, first_cdesc,
++		safexcel_skcipher_token(ctx, iv, first_cdesc, atoken,
+ 					cryptlen);
+ 
+ 	/* result descriptors */
+@@ -1073,6 +1215,8 @@ static int safexcel_skcipher_cra_init(st
+ 
+ 	ctx->base.send = safexcel_skcipher_send;
+ 	ctx->base.handle_result = safexcel_skcipher_handle_result;
++	ctx->ivmask = EIP197_OPTION_4_TOKEN_IV_CMD;
++	ctx->ctrinit = 1;
+ 	return 0;
+ }
+ 
+@@ -1137,6 +1281,8 @@ static int safexcel_skcipher_aes_ecb_cra
+ 	safexcel_skcipher_cra_init(tfm);
+ 	ctx->alg  = SAFEXCEL_AES;
+ 	ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_ECB;
++	ctx->blocksz = 0;
++	ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
+ 	return 0;
+ }
+ 
+@@ -1171,6 +1317,7 @@ static int safexcel_skcipher_aes_cbc_cra
+ 
+ 	safexcel_skcipher_cra_init(tfm);
+ 	ctx->alg  = SAFEXCEL_AES;
++	ctx->blocksz = AES_BLOCK_SIZE;
+ 	ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CBC;
+ 	return 0;
+ }
+@@ -1207,6 +1354,7 @@ static int safexcel_skcipher_aes_cfb_cra
+ 
+ 	safexcel_skcipher_cra_init(tfm);
+ 	ctx->alg  = SAFEXCEL_AES;
++	ctx->blocksz = AES_BLOCK_SIZE;
+ 	ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CFB;
+ 	return 0;
+ }
+@@ -1243,6 +1391,7 @@ static int safexcel_skcipher_aes_ofb_cra
+ 
+ 	safexcel_skcipher_cra_init(tfm);
+ 	ctx->alg  = SAFEXCEL_AES;
++	ctx->blocksz = AES_BLOCK_SIZE;
+ 	ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_OFB;
+ 	return 0;
+ }
+@@ -1288,14 +1437,12 @@ static int safexcel_skcipher_aesctr_setk
+ 	/* exclude the nonce here */
+ 	keylen = len - CTR_RFC3686_NONCE_SIZE;
+ 	ret = aes_expandkey(&aes, key, keylen);
+-	if (ret) {
+-		crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
++	if (ret)
+ 		return ret;
+-	}
+ 
+ 	if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) {
+ 		for (i = 0; i < keylen / sizeof(u32); i++) {
+-			if (ctx->key[i] != cpu_to_le32(aes.key_enc[i])) {
++			if (le32_to_cpu(ctx->key[i]) != aes.key_enc[i]) {
+ 				ctx->base.needs_inv = true;
+ 				break;
+ 			}
+@@ -1317,6 +1464,7 @@ static int safexcel_skcipher_aes_ctr_cra
+ 
+ 	safexcel_skcipher_cra_init(tfm);
+ 	ctx->alg  = SAFEXCEL_AES;
++	ctx->blocksz = AES_BLOCK_SIZE;
+ 	ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD;
+ 	return 0;
+ }
+@@ -1352,6 +1500,7 @@ static int safexcel_des_setkey(struct cr
+ 			       unsigned int len)
+ {
+ 	struct safexcel_cipher_ctx *ctx = crypto_skcipher_ctx(ctfm);
++	struct safexcel_crypto_priv *priv = ctx->priv;
+ 	int ret;
+ 
+ 	ret = verify_skcipher_des_key(ctfm, key);
+@@ -1359,7 +1508,7 @@ static int safexcel_des_setkey(struct cr
+ 		return ret;
+ 
+ 	/* if context exits and key changed, need to invalidate it */
+-	if (ctx->base.ctxr_dma)
++	if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma)
+ 		if (memcmp(ctx->key, key, len))
+ 			ctx->base.needs_inv = true;
+ 
+@@ -1375,6 +1524,8 @@ static int safexcel_skcipher_des_cbc_cra
+ 
+ 	safexcel_skcipher_cra_init(tfm);
+ 	ctx->alg  = SAFEXCEL_DES;
++	ctx->blocksz = DES_BLOCK_SIZE;
++	ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
+ 	ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CBC;
+ 	return 0;
+ }
+@@ -1412,6 +1563,8 @@ static int safexcel_skcipher_des_ecb_cra
+ 	safexcel_skcipher_cra_init(tfm);
+ 	ctx->alg  = SAFEXCEL_DES;
+ 	ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_ECB;
++	ctx->blocksz = 0;
++	ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
+ 	return 0;
+ }
+ 
+@@ -1444,6 +1597,7 @@ static int safexcel_des3_ede_setkey(stru
+ 				   const u8 *key, unsigned int len)
+ {
+ 	struct safexcel_cipher_ctx *ctx = crypto_skcipher_ctx(ctfm);
++	struct safexcel_crypto_priv *priv = ctx->priv;
+ 	int err;
+ 
+ 	err = verify_skcipher_des3_key(ctfm, key);
+@@ -1451,13 +1605,11 @@ static int safexcel_des3_ede_setkey(stru
+ 		return err;
+ 
+ 	/* if context exits and key changed, need to invalidate it */
+-	if (ctx->base.ctxr_dma) {
++	if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma)
+ 		if (memcmp(ctx->key, key, len))
+ 			ctx->base.needs_inv = true;
+-	}
+ 
+ 	memcpy(ctx->key, key, len);
+-
+ 	ctx->key_len = len;
+ 
+ 	return 0;
+@@ -1469,6 +1621,8 @@ static int safexcel_skcipher_des3_cbc_cr
+ 
+ 	safexcel_skcipher_cra_init(tfm);
+ 	ctx->alg  = SAFEXCEL_3DES;
++	ctx->blocksz = DES3_EDE_BLOCK_SIZE;
++	ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
+ 	ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CBC;
+ 	return 0;
+ }
+@@ -1506,6 +1660,8 @@ static int safexcel_skcipher_des3_ecb_cr
+ 	safexcel_skcipher_cra_init(tfm);
+ 	ctx->alg  = SAFEXCEL_3DES;
+ 	ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_ECB;
++	ctx->blocksz = 0;
++	ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
+ 	return 0;
+ }
+ 
+@@ -1561,6 +1717,9 @@ static int safexcel_aead_cra_init(struct
+ 	ctx->priv = tmpl->priv;
+ 
+ 	ctx->alg  = SAFEXCEL_AES; /* default */
++	ctx->blocksz = AES_BLOCK_SIZE;
++	ctx->ivmask = EIP197_OPTION_4_TOKEN_IV_CMD;
++	ctx->ctrinit = 1;
+ 	ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CBC; /* default */
+ 	ctx->aead = true;
+ 	ctx->base.send = safexcel_aead_send;
+@@ -1749,6 +1908,8 @@ static int safexcel_aead_sha1_des3_cra_i
+ 
+ 	safexcel_aead_sha1_cra_init(tfm);
+ 	ctx->alg = SAFEXCEL_3DES; /* override default */
++	ctx->blocksz = DES3_EDE_BLOCK_SIZE;
++	ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
+ 	return 0;
+ }
+ 
+@@ -1777,6 +1938,330 @@ struct safexcel_alg_template safexcel_al
+ 	},
+ };
+ 
++static int safexcel_aead_sha256_des3_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_aead_sha256_cra_init(tfm);
++	ctx->alg = SAFEXCEL_3DES; /* override default */
++	ctx->blocksz = DES3_EDE_BLOCK_SIZE;
++	ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
++	return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha256_cbc_des3_ede = {
++	.type = SAFEXCEL_ALG_TYPE_AEAD,
++	.algo_mask = SAFEXCEL_ALG_DES | SAFEXCEL_ALG_SHA2_256,
++	.alg.aead = {
++		.setkey = safexcel_aead_setkey,
++		.encrypt = safexcel_aead_encrypt,
++		.decrypt = safexcel_aead_decrypt,
++		.ivsize = DES3_EDE_BLOCK_SIZE,
++		.maxauthsize = SHA256_DIGEST_SIZE,
++		.base = {
++			.cra_name = "authenc(hmac(sha256),cbc(des3_ede))",
++			.cra_driver_name = "safexcel-authenc-hmac-sha256-cbc-des3_ede",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY,
++			.cra_blocksize = DES3_EDE_BLOCK_SIZE,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_aead_sha256_des3_cra_init,
++			.cra_exit = safexcel_aead_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
++	},
++};
++
++static int safexcel_aead_sha224_des3_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_aead_sha224_cra_init(tfm);
++	ctx->alg = SAFEXCEL_3DES; /* override default */
++	ctx->blocksz = DES3_EDE_BLOCK_SIZE;
++	ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
++	return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha224_cbc_des3_ede = {
++	.type = SAFEXCEL_ALG_TYPE_AEAD,
++	.algo_mask = SAFEXCEL_ALG_DES | SAFEXCEL_ALG_SHA2_256,
++	.alg.aead = {
++		.setkey = safexcel_aead_setkey,
++		.encrypt = safexcel_aead_encrypt,
++		.decrypt = safexcel_aead_decrypt,
++		.ivsize = DES3_EDE_BLOCK_SIZE,
++		.maxauthsize = SHA224_DIGEST_SIZE,
++		.base = {
++			.cra_name = "authenc(hmac(sha224),cbc(des3_ede))",
++			.cra_driver_name = "safexcel-authenc-hmac-sha224-cbc-des3_ede",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY,
++			.cra_blocksize = DES3_EDE_BLOCK_SIZE,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_aead_sha224_des3_cra_init,
++			.cra_exit = safexcel_aead_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
++	},
++};
++
++static int safexcel_aead_sha512_des3_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_aead_sha512_cra_init(tfm);
++	ctx->alg = SAFEXCEL_3DES; /* override default */
++	ctx->blocksz = DES3_EDE_BLOCK_SIZE;
++	ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
++	return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha512_cbc_des3_ede = {
++	.type = SAFEXCEL_ALG_TYPE_AEAD,
++	.algo_mask = SAFEXCEL_ALG_DES | SAFEXCEL_ALG_SHA2_512,
++	.alg.aead = {
++		.setkey = safexcel_aead_setkey,
++		.encrypt = safexcel_aead_encrypt,
++		.decrypt = safexcel_aead_decrypt,
++		.ivsize = DES3_EDE_BLOCK_SIZE,
++		.maxauthsize = SHA512_DIGEST_SIZE,
++		.base = {
++			.cra_name = "authenc(hmac(sha512),cbc(des3_ede))",
++			.cra_driver_name = "safexcel-authenc-hmac-sha512-cbc-des3_ede",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY,
++			.cra_blocksize = DES3_EDE_BLOCK_SIZE,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_aead_sha512_des3_cra_init,
++			.cra_exit = safexcel_aead_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
++	},
++};
++
++static int safexcel_aead_sha384_des3_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_aead_sha384_cra_init(tfm);
++	ctx->alg = SAFEXCEL_3DES; /* override default */
++	ctx->blocksz = DES3_EDE_BLOCK_SIZE;
++	ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
++	return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha384_cbc_des3_ede = {
++	.type = SAFEXCEL_ALG_TYPE_AEAD,
++	.algo_mask = SAFEXCEL_ALG_DES | SAFEXCEL_ALG_SHA2_512,
++	.alg.aead = {
++		.setkey = safexcel_aead_setkey,
++		.encrypt = safexcel_aead_encrypt,
++		.decrypt = safexcel_aead_decrypt,
++		.ivsize = DES3_EDE_BLOCK_SIZE,
++		.maxauthsize = SHA384_DIGEST_SIZE,
++		.base = {
++			.cra_name = "authenc(hmac(sha384),cbc(des3_ede))",
++			.cra_driver_name = "safexcel-authenc-hmac-sha384-cbc-des3_ede",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY,
++			.cra_blocksize = DES3_EDE_BLOCK_SIZE,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_aead_sha384_des3_cra_init,
++			.cra_exit = safexcel_aead_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
++	},
++};
++
++static int safexcel_aead_sha1_des_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_aead_sha1_cra_init(tfm);
++	ctx->alg = SAFEXCEL_DES; /* override default */
++	ctx->blocksz = DES_BLOCK_SIZE;
++	ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
++	return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_cbc_des = {
++	.type = SAFEXCEL_ALG_TYPE_AEAD,
++	.algo_mask = SAFEXCEL_ALG_DES | SAFEXCEL_ALG_SHA1,
++	.alg.aead = {
++		.setkey = safexcel_aead_setkey,
++		.encrypt = safexcel_aead_encrypt,
++		.decrypt = safexcel_aead_decrypt,
++		.ivsize = DES_BLOCK_SIZE,
++		.maxauthsize = SHA1_DIGEST_SIZE,
++		.base = {
++			.cra_name = "authenc(hmac(sha1),cbc(des))",
++			.cra_driver_name = "safexcel-authenc-hmac-sha1-cbc-des",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY,
++			.cra_blocksize = DES_BLOCK_SIZE,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_aead_sha1_des_cra_init,
++			.cra_exit = safexcel_aead_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
++	},
++};
++
++static int safexcel_aead_sha256_des_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_aead_sha256_cra_init(tfm);
++	ctx->alg = SAFEXCEL_DES; /* override default */
++	ctx->blocksz = DES_BLOCK_SIZE;
++	ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
++	return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha256_cbc_des = {
++	.type = SAFEXCEL_ALG_TYPE_AEAD,
++	.algo_mask = SAFEXCEL_ALG_DES | SAFEXCEL_ALG_SHA2_256,
++	.alg.aead = {
++		.setkey = safexcel_aead_setkey,
++		.encrypt = safexcel_aead_encrypt,
++		.decrypt = safexcel_aead_decrypt,
++		.ivsize = DES_BLOCK_SIZE,
++		.maxauthsize = SHA256_DIGEST_SIZE,
++		.base = {
++			.cra_name = "authenc(hmac(sha256),cbc(des))",
++			.cra_driver_name = "safexcel-authenc-hmac-sha256-cbc-des",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY,
++			.cra_blocksize = DES_BLOCK_SIZE,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_aead_sha256_des_cra_init,
++			.cra_exit = safexcel_aead_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
++	},
++};
++
++static int safexcel_aead_sha224_des_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_aead_sha224_cra_init(tfm);
++	ctx->alg = SAFEXCEL_DES; /* override default */
++	ctx->blocksz = DES_BLOCK_SIZE;
++	ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
++	return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha224_cbc_des = {
++	.type = SAFEXCEL_ALG_TYPE_AEAD,
++	.algo_mask = SAFEXCEL_ALG_DES | SAFEXCEL_ALG_SHA2_256,
++	.alg.aead = {
++		.setkey = safexcel_aead_setkey,
++		.encrypt = safexcel_aead_encrypt,
++		.decrypt = safexcel_aead_decrypt,
++		.ivsize = DES_BLOCK_SIZE,
++		.maxauthsize = SHA224_DIGEST_SIZE,
++		.base = {
++			.cra_name = "authenc(hmac(sha224),cbc(des))",
++			.cra_driver_name = "safexcel-authenc-hmac-sha224-cbc-des",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY,
++			.cra_blocksize = DES_BLOCK_SIZE,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_aead_sha224_des_cra_init,
++			.cra_exit = safexcel_aead_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
++	},
++};
++
++static int safexcel_aead_sha512_des_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_aead_sha512_cra_init(tfm);
++	ctx->alg = SAFEXCEL_DES; /* override default */
++	ctx->blocksz = DES_BLOCK_SIZE;
++	ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
++	return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha512_cbc_des = {
++	.type = SAFEXCEL_ALG_TYPE_AEAD,
++	.algo_mask = SAFEXCEL_ALG_DES | SAFEXCEL_ALG_SHA2_512,
++	.alg.aead = {
++		.setkey = safexcel_aead_setkey,
++		.encrypt = safexcel_aead_encrypt,
++		.decrypt = safexcel_aead_decrypt,
++		.ivsize = DES_BLOCK_SIZE,
++		.maxauthsize = SHA512_DIGEST_SIZE,
++		.base = {
++			.cra_name = "authenc(hmac(sha512),cbc(des))",
++			.cra_driver_name = "safexcel-authenc-hmac-sha512-cbc-des",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY,
++			.cra_blocksize = DES_BLOCK_SIZE,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_aead_sha512_des_cra_init,
++			.cra_exit = safexcel_aead_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
++	},
++};
++
++static int safexcel_aead_sha384_des_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_aead_sha384_cra_init(tfm);
++	ctx->alg = SAFEXCEL_DES; /* override default */
++	ctx->blocksz = DES_BLOCK_SIZE;
++	ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
++	return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha384_cbc_des = {
++	.type = SAFEXCEL_ALG_TYPE_AEAD,
++	.algo_mask = SAFEXCEL_ALG_DES | SAFEXCEL_ALG_SHA2_512,
++	.alg.aead = {
++		.setkey = safexcel_aead_setkey,
++		.encrypt = safexcel_aead_encrypt,
++		.decrypt = safexcel_aead_decrypt,
++		.ivsize = DES_BLOCK_SIZE,
++		.maxauthsize = SHA384_DIGEST_SIZE,
++		.base = {
++			.cra_name = "authenc(hmac(sha384),cbc(des))",
++			.cra_driver_name = "safexcel-authenc-hmac-sha384-cbc-des",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY,
++			.cra_blocksize = DES_BLOCK_SIZE,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_aead_sha384_des_cra_init,
++			.cra_exit = safexcel_aead_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
++	},
++};
++
+ static int safexcel_aead_sha1_ctr_cra_init(struct crypto_tfm *tfm)
+ {
+ 	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+@@ -1965,14 +2450,12 @@ static int safexcel_skcipher_aesxts_setk
+ 	/* Only half of the key data is cipher key */
+ 	keylen = (len >> 1);
+ 	ret = aes_expandkey(&aes, key, keylen);
+-	if (ret) {
+-		crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
++	if (ret)
+ 		return ret;
+-	}
+ 
+ 	if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) {
+ 		for (i = 0; i < keylen / sizeof(u32); i++) {
+-			if (ctx->key[i] != cpu_to_le32(aes.key_enc[i])) {
++			if (le32_to_cpu(ctx->key[i]) != aes.key_enc[i]) {
+ 				ctx->base.needs_inv = true;
+ 				break;
+ 			}
+@@ -1984,15 +2467,13 @@ static int safexcel_skcipher_aesxts_setk
+ 
+ 	/* The other half is the tweak key */
+ 	ret = aes_expandkey(&aes, (u8 *)(key + keylen), keylen);
+-	if (ret) {
+-		crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
++	if (ret)
+ 		return ret;
+-	}
+ 
+ 	if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) {
+ 		for (i = 0; i < keylen / sizeof(u32); i++) {
+-			if (ctx->key[i + keylen / sizeof(u32)] !=
+-			    cpu_to_le32(aes.key_enc[i])) {
++			if (le32_to_cpu(ctx->key[i + keylen / sizeof(u32)]) !=
++			    aes.key_enc[i]) {
+ 				ctx->base.needs_inv = true;
+ 				break;
+ 			}
+@@ -2015,6 +2496,7 @@ static int safexcel_skcipher_aes_xts_cra
+ 
+ 	safexcel_skcipher_cra_init(tfm);
+ 	ctx->alg  = SAFEXCEL_AES;
++	ctx->blocksz = AES_BLOCK_SIZE;
+ 	ctx->xts  = 1;
+ 	ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_XTS;
+ 	return 0;
+@@ -2075,14 +2557,13 @@ static int safexcel_aead_gcm_setkey(stru
+ 
+ 	ret = aes_expandkey(&aes, key, len);
+ 	if (ret) {
+-		crypto_aead_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ 		memzero_explicit(&aes, sizeof(aes));
+ 		return ret;
+ 	}
+ 
+ 	if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) {
+ 		for (i = 0; i < len / sizeof(u32); i++) {
+-			if (ctx->key[i] != cpu_to_le32(aes.key_enc[i])) {
++			if (le32_to_cpu(ctx->key[i]) != aes.key_enc[i]) {
+ 				ctx->base.needs_inv = true;
+ 				break;
+ 			}
+@@ -2099,8 +2580,6 @@ static int safexcel_aead_gcm_setkey(stru
+ 	crypto_cipher_set_flags(ctx->hkaes, crypto_aead_get_flags(ctfm) &
+ 				CRYPTO_TFM_REQ_MASK);
+ 	ret = crypto_cipher_setkey(ctx->hkaes, key, len);
+-	crypto_aead_set_flags(ctfm, crypto_cipher_get_flags(ctx->hkaes) &
+-			      CRYPTO_TFM_RES_MASK);
+ 	if (ret)
+ 		return ret;
+ 
+@@ -2109,7 +2588,7 @@ static int safexcel_aead_gcm_setkey(stru
+ 
+ 	if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) {
+ 		for (i = 0; i < AES_BLOCK_SIZE / sizeof(u32); i++) {
+-			if (ctx->ipad[i] != cpu_to_be32(hashkey[i])) {
++			if (be32_to_cpu(ctx->ipad[i]) != hashkey[i]) {
+ 				ctx->base.needs_inv = true;
+ 				break;
+ 			}
+@@ -2135,10 +2614,7 @@ static int safexcel_aead_gcm_cra_init(st
+ 	ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_XCM; /* override default */
+ 
+ 	ctx->hkaes = crypto_alloc_cipher("aes", 0, 0);
+-	if (IS_ERR(ctx->hkaes))
+-		return PTR_ERR(ctx->hkaes);
+-
+-	return 0;
++	return PTR_ERR_OR_ZERO(ctx->hkaes);
+ }
+ 
+ static void safexcel_aead_gcm_cra_exit(struct crypto_tfm *tfm)
+@@ -2192,14 +2668,13 @@ static int safexcel_aead_ccm_setkey(stru
+ 
+ 	ret = aes_expandkey(&aes, key, len);
+ 	if (ret) {
+-		crypto_aead_set_flags(ctfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ 		memzero_explicit(&aes, sizeof(aes));
+ 		return ret;
+ 	}
+ 
+ 	if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma) {
+ 		for (i = 0; i < len / sizeof(u32); i++) {
+-			if (ctx->key[i] != cpu_to_le32(aes.key_enc[i])) {
++			if (le32_to_cpu(ctx->key[i]) != aes.key_enc[i]) {
+ 				ctx->base.needs_inv = true;
+ 				break;
+ 			}
+@@ -2235,6 +2710,7 @@ static int safexcel_aead_ccm_cra_init(st
+ 	ctx->state_sz = 3 * AES_BLOCK_SIZE;
+ 	ctx->xcm = EIP197_XCM_MODE_CCM;
+ 	ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_XCM; /* override default */
++	ctx->ctrinit = 0;
+ 	return 0;
+ }
+ 
+@@ -2301,5 +2777,949 @@ struct safexcel_alg_template safexcel_al
+ 			.cra_exit = safexcel_aead_cra_exit,
+ 			.cra_module = THIS_MODULE,
+ 		},
++	},
++};
++
++static void safexcel_chacha20_setkey(struct safexcel_cipher_ctx *ctx,
++				     const u8 *key)
++{
++	struct safexcel_crypto_priv *priv = ctx->priv;
++
++	if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma)
++		if (memcmp(ctx->key, key, CHACHA_KEY_SIZE))
++			ctx->base.needs_inv = true;
++
++	memcpy(ctx->key, key, CHACHA_KEY_SIZE);
++	ctx->key_len = CHACHA_KEY_SIZE;
++}
++
++static int safexcel_skcipher_chacha20_setkey(struct crypto_skcipher *ctfm,
++					     const u8 *key, unsigned int len)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_skcipher_ctx(ctfm);
++
++	if (len != CHACHA_KEY_SIZE)
++		return -EINVAL;
++
++	safexcel_chacha20_setkey(ctx, key);
++
++	return 0;
++}
++
++static int safexcel_skcipher_chacha20_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_skcipher_cra_init(tfm);
++	ctx->alg  = SAFEXCEL_CHACHA20;
++	ctx->ctrinit = 0;
++	ctx->mode = CONTEXT_CONTROL_CHACHA20_MODE_256_32;
++	return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_chacha20 = {
++	.type = SAFEXCEL_ALG_TYPE_SKCIPHER,
++	.algo_mask = SAFEXCEL_ALG_CHACHA20,
++	.alg.skcipher = {
++		.setkey = safexcel_skcipher_chacha20_setkey,
++		.encrypt = safexcel_encrypt,
++		.decrypt = safexcel_decrypt,
++		.min_keysize = CHACHA_KEY_SIZE,
++		.max_keysize = CHACHA_KEY_SIZE,
++		.ivsize = CHACHA_IV_SIZE,
++		.base = {
++			.cra_name = "chacha20",
++			.cra_driver_name = "safexcel-chacha20",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY,
++			.cra_blocksize = 1,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_skcipher_chacha20_cra_init,
++			.cra_exit = safexcel_skcipher_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
++	},
++};
++
++static int safexcel_aead_chachapoly_setkey(struct crypto_aead *ctfm,
++				    const u8 *key, unsigned int len)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_aead_ctx(ctfm);
++
++	if (ctx->aead  == EIP197_AEAD_TYPE_IPSEC_ESP &&
++	    len > EIP197_AEAD_IPSEC_NONCE_SIZE) {
++		/* ESP variant has nonce appended to key */
++		len -= EIP197_AEAD_IPSEC_NONCE_SIZE;
++		ctx->nonce = *(u32 *)(key + len);
++	}
++	if (len != CHACHA_KEY_SIZE)
++		return -EINVAL;
++
++	safexcel_chacha20_setkey(ctx, key);
++
++	return 0;
++}
++
++static int safexcel_aead_chachapoly_setauthsize(struct crypto_aead *tfm,
++					 unsigned int authsize)
++{
++	if (authsize != POLY1305_DIGEST_SIZE)
++		return -EINVAL;
++	return 0;
++}
++
++static int safexcel_aead_chachapoly_crypt(struct aead_request *req,
++					  enum safexcel_cipher_direction dir)
++{
++	struct safexcel_cipher_req *creq = aead_request_ctx(req);
++	struct crypto_aead *aead = crypto_aead_reqtfm(req);
++	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++	struct aead_request *subreq = aead_request_ctx(req);
++	u32 key[CHACHA_KEY_SIZE / sizeof(u32) + 1];
++	int ret = 0;
++
++	/*
++	 * Instead of wasting time detecting umpteen silly corner cases,
++	 * just dump all "small" requests to the fallback implementation.
++	 * HW would not be faster on such small requests anyway.
++	 */
++	if (likely((ctx->aead != EIP197_AEAD_TYPE_IPSEC_ESP ||
++		    req->assoclen >= EIP197_AEAD_IPSEC_IV_SIZE) &&
++		   req->cryptlen > POLY1305_DIGEST_SIZE)) {
++		return safexcel_queue_req(&req->base, creq, dir);
++	}
++
++	/* HW cannot do full (AAD+payload) zero length, use fallback */
++	memcpy(key, ctx->key, CHACHA_KEY_SIZE);
++	if (ctx->aead == EIP197_AEAD_TYPE_IPSEC_ESP) {
++		/* ESP variant has nonce appended to the key */
++		key[CHACHA_KEY_SIZE / sizeof(u32)] = ctx->nonce;
++		ret = crypto_aead_setkey(ctx->fback, (u8 *)key,
++					 CHACHA_KEY_SIZE +
++					 EIP197_AEAD_IPSEC_NONCE_SIZE);
++	} else {
++		ret = crypto_aead_setkey(ctx->fback, (u8 *)key,
++					 CHACHA_KEY_SIZE);
++	}
++	if (ret) {
++		crypto_aead_clear_flags(aead, CRYPTO_TFM_REQ_MASK);
++		crypto_aead_set_flags(aead, crypto_aead_get_flags(ctx->fback) &
++					    CRYPTO_TFM_REQ_MASK);
++		return ret;
++	}
++
++	aead_request_set_tfm(subreq, ctx->fback);
++	aead_request_set_callback(subreq, req->base.flags, req->base.complete,
++				  req->base.data);
++	aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen,
++			       req->iv);
++	aead_request_set_ad(subreq, req->assoclen);
++
++	return (dir ==  SAFEXCEL_ENCRYPT) ?
++		crypto_aead_encrypt(subreq) :
++		crypto_aead_decrypt(subreq);
++}
++
++static int safexcel_aead_chachapoly_encrypt(struct aead_request *req)
++{
++	return safexcel_aead_chachapoly_crypt(req, SAFEXCEL_ENCRYPT);
++}
++
++static int safexcel_aead_chachapoly_decrypt(struct aead_request *req)
++{
++	return safexcel_aead_chachapoly_crypt(req, SAFEXCEL_DECRYPT);
++}
++
++static int safexcel_aead_fallback_cra_init(struct crypto_tfm *tfm)
++{
++	struct crypto_aead *aead = __crypto_aead_cast(tfm);
++	struct aead_alg *alg = crypto_aead_alg(aead);
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_aead_cra_init(tfm);
++
++	/* Allocate fallback implementation */
++	ctx->fback = crypto_alloc_aead(alg->base.cra_name, 0,
++				       CRYPTO_ALG_ASYNC |
++				       CRYPTO_ALG_NEED_FALLBACK);
++	if (IS_ERR(ctx->fback))
++		return PTR_ERR(ctx->fback);
++
++	crypto_aead_set_reqsize(aead, max(sizeof(struct safexcel_cipher_req),
++					  sizeof(struct aead_request) +
++					  crypto_aead_reqsize(ctx->fback)));
++
++	return 0;
++}
++
++static int safexcel_aead_chachapoly_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_aead_fallback_cra_init(tfm);
++	ctx->alg  = SAFEXCEL_CHACHA20;
++	ctx->mode = CONTEXT_CONTROL_CHACHA20_MODE_256_32 |
++		    CONTEXT_CONTROL_CHACHA20_MODE_CALC_OTK;
++	ctx->ctrinit = 0;
++	ctx->hash_alg = CONTEXT_CONTROL_CRYPTO_ALG_POLY1305;
++	ctx->state_sz = 0; /* Precomputed by HW */
++	return 0;
++}
++
++static void safexcel_aead_fallback_cra_exit(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	crypto_free_aead(ctx->fback);
++	safexcel_aead_cra_exit(tfm);
++}
++
++struct safexcel_alg_template safexcel_alg_chachapoly = {
++	.type = SAFEXCEL_ALG_TYPE_AEAD,
++	.algo_mask = SAFEXCEL_ALG_CHACHA20 | SAFEXCEL_ALG_POLY1305,
++	.alg.aead = {
++		.setkey = safexcel_aead_chachapoly_setkey,
++		.setauthsize = safexcel_aead_chachapoly_setauthsize,
++		.encrypt = safexcel_aead_chachapoly_encrypt,
++		.decrypt = safexcel_aead_chachapoly_decrypt,
++		.ivsize = CHACHAPOLY_IV_SIZE,
++		.maxauthsize = POLY1305_DIGEST_SIZE,
++		.base = {
++			.cra_name = "rfc7539(chacha20,poly1305)",
++			.cra_driver_name = "safexcel-chacha20-poly1305",
++			/* +1 to put it above HW chacha + SW poly */
++			.cra_priority = SAFEXCEL_CRA_PRIORITY + 1,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY |
++				     CRYPTO_ALG_NEED_FALLBACK,
++			.cra_blocksize = 1,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_aead_chachapoly_cra_init,
++			.cra_exit = safexcel_aead_fallback_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
++	},
++};
++
++static int safexcel_aead_chachapolyesp_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++	int ret;
++
++	ret = safexcel_aead_chachapoly_cra_init(tfm);
++	ctx->aead  = EIP197_AEAD_TYPE_IPSEC_ESP;
++	ctx->aadskip = EIP197_AEAD_IPSEC_IV_SIZE;
++	return ret;
++}
++
++struct safexcel_alg_template safexcel_alg_chachapoly_esp = {
++	.type = SAFEXCEL_ALG_TYPE_AEAD,
++	.algo_mask = SAFEXCEL_ALG_CHACHA20 | SAFEXCEL_ALG_POLY1305,
++	.alg.aead = {
++		.setkey = safexcel_aead_chachapoly_setkey,
++		.setauthsize = safexcel_aead_chachapoly_setauthsize,
++		.encrypt = safexcel_aead_chachapoly_encrypt,
++		.decrypt = safexcel_aead_chachapoly_decrypt,
++		.ivsize = CHACHAPOLY_IV_SIZE - EIP197_AEAD_IPSEC_NONCE_SIZE,
++		.maxauthsize = POLY1305_DIGEST_SIZE,
++		.base = {
++			.cra_name = "rfc7539esp(chacha20,poly1305)",
++			.cra_driver_name = "safexcel-chacha20-poly1305-esp",
++			/* +1 to put it above HW chacha + SW poly */
++			.cra_priority = SAFEXCEL_CRA_PRIORITY + 1,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY |
++				     CRYPTO_ALG_NEED_FALLBACK,
++			.cra_blocksize = 1,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_aead_chachapolyesp_cra_init,
++			.cra_exit = safexcel_aead_fallback_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
++	},
++};
++
++static int safexcel_skcipher_sm4_setkey(struct crypto_skcipher *ctfm,
++					const u8 *key, unsigned int len)
++{
++	struct crypto_tfm *tfm = crypto_skcipher_tfm(ctfm);
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++	struct safexcel_crypto_priv *priv = ctx->priv;
++
++	if (len != SM4_KEY_SIZE)
++		return -EINVAL;
++
++	if (priv->flags & EIP197_TRC_CACHE && ctx->base.ctxr_dma)
++		if (memcmp(ctx->key, key, SM4_KEY_SIZE))
++			ctx->base.needs_inv = true;
++
++	memcpy(ctx->key, key, SM4_KEY_SIZE);
++	ctx->key_len = SM4_KEY_SIZE;
++
++	return 0;
++}
++
++static int safexcel_sm4_blk_encrypt(struct skcipher_request *req)
++{
++	/* Workaround for HW bug: EIP96 4.3 does not report blocksize error */
++	if (req->cryptlen & (SM4_BLOCK_SIZE - 1))
++		return -EINVAL;
++	else
++		return safexcel_queue_req(&req->base, skcipher_request_ctx(req),
++					  SAFEXCEL_ENCRYPT);
++}
++
++static int safexcel_sm4_blk_decrypt(struct skcipher_request *req)
++{
++	/* Workaround for HW bug: EIP96 4.3 does not report blocksize error */
++	if (req->cryptlen & (SM4_BLOCK_SIZE - 1))
++		return -EINVAL;
++	else
++		return safexcel_queue_req(&req->base, skcipher_request_ctx(req),
++					  SAFEXCEL_DECRYPT);
++}
++
++static int safexcel_skcipher_sm4_ecb_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_skcipher_cra_init(tfm);
++	ctx->alg  = SAFEXCEL_SM4;
++	ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_ECB;
++	ctx->blocksz = 0;
++	ctx->ivmask = EIP197_OPTION_2_TOKEN_IV_CMD;
++	return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_ecb_sm4 = {
++	.type = SAFEXCEL_ALG_TYPE_SKCIPHER,
++	.algo_mask = SAFEXCEL_ALG_SM4,
++	.alg.skcipher = {
++		.setkey = safexcel_skcipher_sm4_setkey,
++		.encrypt = safexcel_sm4_blk_encrypt,
++		.decrypt = safexcel_sm4_blk_decrypt,
++		.min_keysize = SM4_KEY_SIZE,
++		.max_keysize = SM4_KEY_SIZE,
++		.base = {
++			.cra_name = "ecb(sm4)",
++			.cra_driver_name = "safexcel-ecb-sm4",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY,
++			.cra_blocksize = SM4_BLOCK_SIZE,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_skcipher_sm4_ecb_cra_init,
++			.cra_exit = safexcel_skcipher_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
++	},
++};
++
++static int safexcel_skcipher_sm4_cbc_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_skcipher_cra_init(tfm);
++	ctx->alg  = SAFEXCEL_SM4;
++	ctx->blocksz = SM4_BLOCK_SIZE;
++	ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CBC;
++	return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_cbc_sm4 = {
++	.type = SAFEXCEL_ALG_TYPE_SKCIPHER,
++	.algo_mask = SAFEXCEL_ALG_SM4,
++	.alg.skcipher = {
++		.setkey = safexcel_skcipher_sm4_setkey,
++		.encrypt = safexcel_sm4_blk_encrypt,
++		.decrypt = safexcel_sm4_blk_decrypt,
++		.min_keysize = SM4_KEY_SIZE,
++		.max_keysize = SM4_KEY_SIZE,
++		.ivsize = SM4_BLOCK_SIZE,
++		.base = {
++			.cra_name = "cbc(sm4)",
++			.cra_driver_name = "safexcel-cbc-sm4",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY,
++			.cra_blocksize = SM4_BLOCK_SIZE,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_skcipher_sm4_cbc_cra_init,
++			.cra_exit = safexcel_skcipher_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
++	},
++};
++
++static int safexcel_skcipher_sm4_ofb_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_skcipher_cra_init(tfm);
++	ctx->alg  = SAFEXCEL_SM4;
++	ctx->blocksz = SM4_BLOCK_SIZE;
++	ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_OFB;
++	return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_ofb_sm4 = {
++	.type = SAFEXCEL_ALG_TYPE_SKCIPHER,
++	.algo_mask = SAFEXCEL_ALG_SM4 | SAFEXCEL_ALG_AES_XFB,
++	.alg.skcipher = {
++		.setkey = safexcel_skcipher_sm4_setkey,
++		.encrypt = safexcel_encrypt,
++		.decrypt = safexcel_decrypt,
++		.min_keysize = SM4_KEY_SIZE,
++		.max_keysize = SM4_KEY_SIZE,
++		.ivsize = SM4_BLOCK_SIZE,
++		.base = {
++			.cra_name = "ofb(sm4)",
++			.cra_driver_name = "safexcel-ofb-sm4",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY,
++			.cra_blocksize = 1,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_skcipher_sm4_ofb_cra_init,
++			.cra_exit = safexcel_skcipher_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
++	},
++};
++
++static int safexcel_skcipher_sm4_cfb_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_skcipher_cra_init(tfm);
++	ctx->alg  = SAFEXCEL_SM4;
++	ctx->blocksz = SM4_BLOCK_SIZE;
++	ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CFB;
++	return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_cfb_sm4 = {
++	.type = SAFEXCEL_ALG_TYPE_SKCIPHER,
++	.algo_mask = SAFEXCEL_ALG_SM4 | SAFEXCEL_ALG_AES_XFB,
++	.alg.skcipher = {
++		.setkey = safexcel_skcipher_sm4_setkey,
++		.encrypt = safexcel_encrypt,
++		.decrypt = safexcel_decrypt,
++		.min_keysize = SM4_KEY_SIZE,
++		.max_keysize = SM4_KEY_SIZE,
++		.ivsize = SM4_BLOCK_SIZE,
++		.base = {
++			.cra_name = "cfb(sm4)",
++			.cra_driver_name = "safexcel-cfb-sm4",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY,
++			.cra_blocksize = 1,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_skcipher_sm4_cfb_cra_init,
++			.cra_exit = safexcel_skcipher_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
++	},
++};
++
++static int safexcel_skcipher_sm4ctr_setkey(struct crypto_skcipher *ctfm,
++					   const u8 *key, unsigned int len)
++{
++	struct crypto_tfm *tfm = crypto_skcipher_tfm(ctfm);
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	/* last 4 bytes of key are the nonce! */
++	ctx->nonce = *(u32 *)(key + len - CTR_RFC3686_NONCE_SIZE);
++	/* exclude the nonce here */
++	len -= CTR_RFC3686_NONCE_SIZE;
++
++	return safexcel_skcipher_sm4_setkey(ctfm, key, len);
++}
++
++static int safexcel_skcipher_sm4_ctr_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_skcipher_cra_init(tfm);
++	ctx->alg  = SAFEXCEL_SM4;
++	ctx->blocksz = SM4_BLOCK_SIZE;
++	ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD;
++	return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_ctr_sm4 = {
++	.type = SAFEXCEL_ALG_TYPE_SKCIPHER,
++	.algo_mask = SAFEXCEL_ALG_SM4,
++	.alg.skcipher = {
++		.setkey = safexcel_skcipher_sm4ctr_setkey,
++		.encrypt = safexcel_encrypt,
++		.decrypt = safexcel_decrypt,
++		/* Add nonce size */
++		.min_keysize = SM4_KEY_SIZE + CTR_RFC3686_NONCE_SIZE,
++		.max_keysize = SM4_KEY_SIZE + CTR_RFC3686_NONCE_SIZE,
++		.ivsize = CTR_RFC3686_IV_SIZE,
++		.base = {
++			.cra_name = "rfc3686(ctr(sm4))",
++			.cra_driver_name = "safexcel-ctr-sm4",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY,
++			.cra_blocksize = 1,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_skcipher_sm4_ctr_cra_init,
++			.cra_exit = safexcel_skcipher_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
++	},
++};
++
++static int safexcel_aead_sm4_blk_encrypt(struct aead_request *req)
++{
++	/* Workaround for HW bug: EIP96 4.3 does not report blocksize error */
++	if (req->cryptlen & (SM4_BLOCK_SIZE - 1))
++		return -EINVAL;
++
++	return safexcel_queue_req(&req->base, aead_request_ctx(req),
++				  SAFEXCEL_ENCRYPT);
++}
++
++static int safexcel_aead_sm4_blk_decrypt(struct aead_request *req)
++{
++	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
++
++	/* Workaround for HW bug: EIP96 4.3 does not report blocksize error */
++	if ((req->cryptlen - crypto_aead_authsize(tfm)) & (SM4_BLOCK_SIZE - 1))
++		return -EINVAL;
++
++	return safexcel_queue_req(&req->base, aead_request_ctx(req),
++				  SAFEXCEL_DECRYPT);
++}
++
++static int safexcel_aead_sm4cbc_sha1_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_aead_cra_init(tfm);
++	ctx->alg = SAFEXCEL_SM4;
++	ctx->blocksz = SM4_BLOCK_SIZE;
++	ctx->hash_alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA1;
++	ctx->state_sz = SHA1_DIGEST_SIZE;
++	return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_cbc_sm4 = {
++	.type = SAFEXCEL_ALG_TYPE_AEAD,
++	.algo_mask = SAFEXCEL_ALG_SM4 | SAFEXCEL_ALG_SHA1,
++	.alg.aead = {
++		.setkey = safexcel_aead_setkey,
++		.encrypt = safexcel_aead_sm4_blk_encrypt,
++		.decrypt = safexcel_aead_sm4_blk_decrypt,
++		.ivsize = SM4_BLOCK_SIZE,
++		.maxauthsize = SHA1_DIGEST_SIZE,
++		.base = {
++			.cra_name = "authenc(hmac(sha1),cbc(sm4))",
++			.cra_driver_name = "safexcel-authenc-hmac-sha1-cbc-sm4",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY,
++			.cra_blocksize = SM4_BLOCK_SIZE,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_aead_sm4cbc_sha1_cra_init,
++			.cra_exit = safexcel_aead_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
++	},
++};
++
++static int safexcel_aead_fallback_setkey(struct crypto_aead *ctfm,
++					 const u8 *key, unsigned int len)
++{
++	struct crypto_tfm *tfm = crypto_aead_tfm(ctfm);
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	/* Keep fallback cipher synchronized */
++	return crypto_aead_setkey(ctx->fback, (u8 *)key, len) ?:
++	       safexcel_aead_setkey(ctfm, key, len);
++}
++
++static int safexcel_aead_fallback_setauthsize(struct crypto_aead *ctfm,
++					      unsigned int authsize)
++{
++	struct crypto_tfm *tfm = crypto_aead_tfm(ctfm);
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	/* Keep fallback cipher synchronized */
++	return crypto_aead_setauthsize(ctx->fback, authsize);
++}
++
++static int safexcel_aead_fallback_crypt(struct aead_request *req,
++					enum safexcel_cipher_direction dir)
++{
++	struct crypto_aead *aead = crypto_aead_reqtfm(req);
++	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++	struct aead_request *subreq = aead_request_ctx(req);
++
++	aead_request_set_tfm(subreq, ctx->fback);
++	aead_request_set_callback(subreq, req->base.flags, req->base.complete,
++				  req->base.data);
++	aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen,
++			       req->iv);
++	aead_request_set_ad(subreq, req->assoclen);
++
++	return (dir ==  SAFEXCEL_ENCRYPT) ?
++		crypto_aead_encrypt(subreq) :
++		crypto_aead_decrypt(subreq);
++}
++
++static int safexcel_aead_sm4cbc_sm3_encrypt(struct aead_request *req)
++{
++	struct safexcel_cipher_req *creq = aead_request_ctx(req);
++
++	/* Workaround for HW bug: EIP96 4.3 does not report blocksize error */
++	if (req->cryptlen & (SM4_BLOCK_SIZE - 1))
++		return -EINVAL;
++	else if (req->cryptlen || req->assoclen) /* If input length > 0 only */
++		return safexcel_queue_req(&req->base, creq, SAFEXCEL_ENCRYPT);
++
++	/* HW cannot do full (AAD+payload) zero length, use fallback */
++	return safexcel_aead_fallback_crypt(req, SAFEXCEL_ENCRYPT);
++}
++
++static int safexcel_aead_sm4cbc_sm3_decrypt(struct aead_request *req)
++{
++	struct safexcel_cipher_req *creq = aead_request_ctx(req);
++	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
++
++	/* Workaround for HW bug: EIP96 4.3 does not report blocksize error */
++	if ((req->cryptlen - crypto_aead_authsize(tfm)) & (SM4_BLOCK_SIZE - 1))
++		return -EINVAL;
++	else if (req->cryptlen > crypto_aead_authsize(tfm) || req->assoclen)
++		/* If input length > 0 only */
++		return safexcel_queue_req(&req->base, creq, SAFEXCEL_DECRYPT);
++
++	/* HW cannot do full (AAD+payload) zero length, use fallback */
++	return safexcel_aead_fallback_crypt(req, SAFEXCEL_DECRYPT);
++}
++
++static int safexcel_aead_sm4cbc_sm3_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_aead_fallback_cra_init(tfm);
++	ctx->alg = SAFEXCEL_SM4;
++	ctx->blocksz = SM4_BLOCK_SIZE;
++	ctx->hash_alg = CONTEXT_CONTROL_CRYPTO_ALG_SM3;
++	ctx->state_sz = SM3_DIGEST_SIZE;
++	return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sm3_cbc_sm4 = {
++	.type = SAFEXCEL_ALG_TYPE_AEAD,
++	.algo_mask = SAFEXCEL_ALG_SM4 | SAFEXCEL_ALG_SM3,
++	.alg.aead = {
++		.setkey = safexcel_aead_fallback_setkey,
++		.setauthsize = safexcel_aead_fallback_setauthsize,
++		.encrypt = safexcel_aead_sm4cbc_sm3_encrypt,
++		.decrypt = safexcel_aead_sm4cbc_sm3_decrypt,
++		.ivsize = SM4_BLOCK_SIZE,
++		.maxauthsize = SM3_DIGEST_SIZE,
++		.base = {
++			.cra_name = "authenc(hmac(sm3),cbc(sm4))",
++			.cra_driver_name = "safexcel-authenc-hmac-sm3-cbc-sm4",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY |
++				     CRYPTO_ALG_NEED_FALLBACK,
++			.cra_blocksize = SM4_BLOCK_SIZE,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_aead_sm4cbc_sm3_cra_init,
++			.cra_exit = safexcel_aead_fallback_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
++	},
++};
++
++static int safexcel_aead_sm4ctr_sha1_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_aead_sm4cbc_sha1_cra_init(tfm);
++	ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD;
++	return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_ctr_sm4 = {
++	.type = SAFEXCEL_ALG_TYPE_AEAD,
++	.algo_mask = SAFEXCEL_ALG_SM4 | SAFEXCEL_ALG_SHA1,
++	.alg.aead = {
++		.setkey = safexcel_aead_setkey,
++		.encrypt = safexcel_aead_encrypt,
++		.decrypt = safexcel_aead_decrypt,
++		.ivsize = CTR_RFC3686_IV_SIZE,
++		.maxauthsize = SHA1_DIGEST_SIZE,
++		.base = {
++			.cra_name = "authenc(hmac(sha1),rfc3686(ctr(sm4)))",
++			.cra_driver_name = "safexcel-authenc-hmac-sha1-ctr-sm4",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY,
++			.cra_blocksize = 1,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_aead_sm4ctr_sha1_cra_init,
++			.cra_exit = safexcel_aead_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
++	},
++};
++
++static int safexcel_aead_sm4ctr_sm3_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_aead_sm4cbc_sm3_cra_init(tfm);
++	ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD;
++	return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_authenc_hmac_sm3_ctr_sm4 = {
++	.type = SAFEXCEL_ALG_TYPE_AEAD,
++	.algo_mask = SAFEXCEL_ALG_SM4 | SAFEXCEL_ALG_SM3,
++	.alg.aead = {
++		.setkey = safexcel_aead_setkey,
++		.encrypt = safexcel_aead_encrypt,
++		.decrypt = safexcel_aead_decrypt,
++		.ivsize = CTR_RFC3686_IV_SIZE,
++		.maxauthsize = SM3_DIGEST_SIZE,
++		.base = {
++			.cra_name = "authenc(hmac(sm3),rfc3686(ctr(sm4)))",
++			.cra_driver_name = "safexcel-authenc-hmac-sm3-ctr-sm4",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY,
++			.cra_blocksize = 1,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_aead_sm4ctr_sm3_cra_init,
++			.cra_exit = safexcel_aead_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
++	},
++};
++
++static int safexcel_rfc4106_gcm_setkey(struct crypto_aead *ctfm, const u8 *key,
++				       unsigned int len)
++{
++	struct crypto_tfm *tfm = crypto_aead_tfm(ctfm);
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	/* last 4 bytes of key are the nonce! */
++	ctx->nonce = *(u32 *)(key + len - CTR_RFC3686_NONCE_SIZE);
++
++	len -= CTR_RFC3686_NONCE_SIZE;
++	return safexcel_aead_gcm_setkey(ctfm, key, len);
++}
++
++static int safexcel_rfc4106_gcm_setauthsize(struct crypto_aead *tfm,
++					    unsigned int authsize)
++{
++	return crypto_rfc4106_check_authsize(authsize);
++}
++
++static int safexcel_rfc4106_encrypt(struct aead_request *req)
++{
++	return crypto_ipsec_check_assoclen(req->assoclen) ?:
++	       safexcel_aead_encrypt(req);
++}
++
++static int safexcel_rfc4106_decrypt(struct aead_request *req)
++{
++	return crypto_ipsec_check_assoclen(req->assoclen) ?:
++	       safexcel_aead_decrypt(req);
++}
++
++static int safexcel_rfc4106_gcm_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++	int ret;
++
++	ret = safexcel_aead_gcm_cra_init(tfm);
++	ctx->aead  = EIP197_AEAD_TYPE_IPSEC_ESP;
++	ctx->aadskip = EIP197_AEAD_IPSEC_IV_SIZE;
++	return ret;
++}
++
++struct safexcel_alg_template safexcel_alg_rfc4106_gcm = {
++	.type = SAFEXCEL_ALG_TYPE_AEAD,
++	.algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_GHASH,
++	.alg.aead = {
++		.setkey = safexcel_rfc4106_gcm_setkey,
++		.setauthsize = safexcel_rfc4106_gcm_setauthsize,
++		.encrypt = safexcel_rfc4106_encrypt,
++		.decrypt = safexcel_rfc4106_decrypt,
++		.ivsize = GCM_RFC4106_IV_SIZE,
++		.maxauthsize = GHASH_DIGEST_SIZE,
++		.base = {
++			.cra_name = "rfc4106(gcm(aes))",
++			.cra_driver_name = "safexcel-rfc4106-gcm-aes",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY,
++			.cra_blocksize = 1,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_rfc4106_gcm_cra_init,
++			.cra_exit = safexcel_aead_gcm_cra_exit,
++		},
++	},
++};
++
++static int safexcel_rfc4543_gcm_setauthsize(struct crypto_aead *tfm,
++					    unsigned int authsize)
++{
++	if (authsize != GHASH_DIGEST_SIZE)
++		return -EINVAL;
++
++	return 0;
++}
++
++static int safexcel_rfc4543_gcm_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++	int ret;
++
++	ret = safexcel_aead_gcm_cra_init(tfm);
++	ctx->aead  = EIP197_AEAD_TYPE_IPSEC_ESP_GMAC;
++	return ret;
++}
++
++struct safexcel_alg_template safexcel_alg_rfc4543_gcm = {
++	.type = SAFEXCEL_ALG_TYPE_AEAD,
++	.algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_GHASH,
++	.alg.aead = {
++		.setkey = safexcel_rfc4106_gcm_setkey,
++		.setauthsize = safexcel_rfc4543_gcm_setauthsize,
++		.encrypt = safexcel_rfc4106_encrypt,
++		.decrypt = safexcel_rfc4106_decrypt,
++		.ivsize = GCM_RFC4543_IV_SIZE,
++		.maxauthsize = GHASH_DIGEST_SIZE,
++		.base = {
++			.cra_name = "rfc4543(gcm(aes))",
++			.cra_driver_name = "safexcel-rfc4543-gcm-aes",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY,
++			.cra_blocksize = 1,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_rfc4543_gcm_cra_init,
++			.cra_exit = safexcel_aead_gcm_cra_exit,
++		},
++	},
++};
++
++static int safexcel_rfc4309_ccm_setkey(struct crypto_aead *ctfm, const u8 *key,
++				       unsigned int len)
++{
++	struct crypto_tfm *tfm = crypto_aead_tfm(ctfm);
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	/* First byte of the nonce = L = always 3 for RFC4309 (4 byte ctr) */
++	*(u8 *)&ctx->nonce = EIP197_AEAD_IPSEC_COUNTER_SIZE - 1;
++	/* last 3 bytes of key are the nonce! */
++	memcpy((u8 *)&ctx->nonce + 1, key + len -
++	       EIP197_AEAD_IPSEC_CCM_NONCE_SIZE,
++	       EIP197_AEAD_IPSEC_CCM_NONCE_SIZE);
++
++	len -= EIP197_AEAD_IPSEC_CCM_NONCE_SIZE;
++	return safexcel_aead_ccm_setkey(ctfm, key, len);
++}
++
++static int safexcel_rfc4309_ccm_setauthsize(struct crypto_aead *tfm,
++					    unsigned int authsize)
++{
++	/* Borrowed from crypto/ccm.c */
++	switch (authsize) {
++	case 8:
++	case 12:
++	case 16:
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static int safexcel_rfc4309_ccm_encrypt(struct aead_request *req)
++{
++	struct safexcel_cipher_req *creq = aead_request_ctx(req);
++
++	/* Borrowed from crypto/ccm.c */
++	if (req->assoclen != 16 && req->assoclen != 20)
++		return -EINVAL;
++
++	return safexcel_queue_req(&req->base, creq, SAFEXCEL_ENCRYPT);
++}
++
++static int safexcel_rfc4309_ccm_decrypt(struct aead_request *req)
++{
++	struct safexcel_cipher_req *creq = aead_request_ctx(req);
++
++	/* Borrowed from crypto/ccm.c */
++	if (req->assoclen != 16 && req->assoclen != 20)
++		return -EINVAL;
++
++	return safexcel_queue_req(&req->base, creq, SAFEXCEL_DECRYPT);
++}
++
++static int safexcel_rfc4309_ccm_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
++	int ret;
++
++	ret = safexcel_aead_ccm_cra_init(tfm);
++	ctx->aead  = EIP197_AEAD_TYPE_IPSEC_ESP;
++	ctx->aadskip = EIP197_AEAD_IPSEC_IV_SIZE;
++	return ret;
++}
++
++struct safexcel_alg_template safexcel_alg_rfc4309_ccm = {
++	.type = SAFEXCEL_ALG_TYPE_AEAD,
++	.algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_CBC_MAC_ALL,
++	.alg.aead = {
++		.setkey = safexcel_rfc4309_ccm_setkey,
++		.setauthsize = safexcel_rfc4309_ccm_setauthsize,
++		.encrypt = safexcel_rfc4309_ccm_encrypt,
++		.decrypt = safexcel_rfc4309_ccm_decrypt,
++		.ivsize = EIP197_AEAD_IPSEC_IV_SIZE,
++		.maxauthsize = AES_BLOCK_SIZE,
++		.base = {
++			.cra_name = "rfc4309(ccm(aes))",
++			.cra_driver_name = "safexcel-rfc4309-ccm-aes",
++			.cra_priority = SAFEXCEL_CRA_PRIORITY,
++			.cra_flags = CRYPTO_ALG_ASYNC |
++				     CRYPTO_ALG_KERN_DRIVER_ONLY,
++			.cra_blocksize = 1,
++			.cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
++			.cra_alignmask = 0,
++			.cra_init = safexcel_rfc4309_ccm_cra_init,
++			.cra_exit = safexcel_aead_cra_exit,
++			.cra_module = THIS_MODULE,
++		},
+ 	},
+ };
+--- a/drivers/crypto/inside-secure/safexcel.h
++++ b/drivers/crypto/inside-secure/safexcel.h
+@@ -17,8 +17,11 @@
+ #define EIP197_HIA_VERSION_BE			0xca35
+ #define EIP197_HIA_VERSION_LE			0x35ca
+ #define EIP97_VERSION_LE			0x9e61
++#define EIP196_VERSION_LE			0x3bc4
+ #define EIP197_VERSION_LE			0x3ac5
+ #define EIP96_VERSION_LE			0x9f60
++#define EIP201_VERSION_LE			0x36c9
++#define EIP206_VERSION_LE			0x31ce
+ #define EIP197_REG_LO16(reg)			(reg & 0xffff)
+ #define EIP197_REG_HI16(reg)			((reg >> 16) & 0xffff)
+ #define EIP197_VERSION_MASK(reg)		((reg >> 16) & 0xfff)
+@@ -26,12 +29,23 @@
+ 						((reg >> 4) & 0xf0) | \
+ 						((reg >> 12) & 0xf))
+ 
++/* EIP197 HIA OPTIONS ENCODING */
++#define EIP197_HIA_OPT_HAS_PE_ARB		BIT(29)
++
++/* EIP206 OPTIONS ENCODING */
++#define EIP206_OPT_ICE_TYPE(n)			((n>>8)&3)
++
++/* EIP197 OPTIONS ENCODING */
++#define EIP197_OPT_HAS_TRC			BIT(31)
++
+ /* Static configuration */
+ #define EIP197_DEFAULT_RING_SIZE		400
+-#define EIP197_MAX_TOKENS			18
++#define EIP197_EMB_TOKENS			4 /* Pad CD to 16 dwords */
++#define EIP197_MAX_TOKENS			16
+ #define EIP197_MAX_RINGS			4
+ #define EIP197_FETCH_DEPTH			2
+ #define EIP197_MAX_BATCH_SZ			64
++#define EIP197_MAX_RING_AIC			14
+ 
+ #define EIP197_GFP_FLAGS(base)	((base).flags & CRYPTO_TFM_REQ_MAY_SLEEP ? \
+ 				 GFP_KERNEL : GFP_ATOMIC)
+@@ -138,6 +152,7 @@
+ #define EIP197_HIA_AIC_R_ENABLED_STAT(r)	(0xe010 - EIP197_HIA_AIC_R_OFF(r))
+ #define EIP197_HIA_AIC_R_ACK(r)			(0xe010 - EIP197_HIA_AIC_R_OFF(r))
+ #define EIP197_HIA_AIC_R_ENABLE_CLR(r)		(0xe014 - EIP197_HIA_AIC_R_OFF(r))
++#define EIP197_HIA_AIC_R_VERSION(r)		(0xe01c - EIP197_HIA_AIC_R_OFF(r))
+ #define EIP197_HIA_AIC_G_ENABLE_CTRL		0xf808
+ #define EIP197_HIA_AIC_G_ENABLED_STAT		0xf810
+ #define EIP197_HIA_AIC_G_ACK			0xf810
+@@ -157,12 +172,16 @@
+ #define EIP197_PE_EIP96_FUNCTION_EN(n)		(0x1004 + (0x2000 * (n)))
+ #define EIP197_PE_EIP96_CONTEXT_CTRL(n)		(0x1008 + (0x2000 * (n)))
+ #define EIP197_PE_EIP96_CONTEXT_STAT(n)		(0x100c + (0x2000 * (n)))
++#define EIP197_PE_EIP96_TOKEN_CTRL2(n)		(0x102c + (0x2000 * (n)))
+ #define EIP197_PE_EIP96_FUNCTION2_EN(n)		(0x1030 + (0x2000 * (n)))
+ #define EIP197_PE_EIP96_OPTIONS(n)		(0x13f8 + (0x2000 * (n)))
+ #define EIP197_PE_EIP96_VERSION(n)		(0x13fc + (0x2000 * (n)))
+ #define EIP197_PE_OUT_DBUF_THRES(n)		(0x1c00 + (0x2000 * (n)))
+ #define EIP197_PE_OUT_TBUF_THRES(n)		(0x1d00 + (0x2000 * (n)))
++#define EIP197_PE_OPTIONS(n)			(0x1ff8 + (0x2000 * (n)))
++#define EIP197_PE_VERSION(n)			(0x1ffc + (0x2000 * (n)))
+ #define EIP197_MST_CTRL				0xfff4
++#define EIP197_OPTIONS				0xfff8
+ #define EIP197_VERSION				0xfffc
+ 
+ /* EIP197-specific registers, no indirection */
+@@ -178,6 +197,7 @@
+ #define EIP197_TRC_ECCADMINSTAT			0xf0838
+ #define EIP197_TRC_ECCDATASTAT			0xf083c
+ #define EIP197_TRC_ECCDATA			0xf0840
++#define EIP197_STRC_CONFIG			0xf43f0
+ #define EIP197_FLUE_CACHEBASE_LO(n)		(0xf6000 + (32 * (n)))
+ #define EIP197_FLUE_CACHEBASE_HI(n)		(0xf6004 + (32 * (n)))
+ #define EIP197_FLUE_CONFIG(n)			(0xf6010 + (32 * (n)))
+@@ -188,6 +208,7 @@
+ 
+ /* EIP197_HIA_xDR_DESC_SIZE */
+ #define EIP197_xDR_DESC_MODE_64BIT		BIT(31)
++#define EIP197_CDR_DESC_MODE_ADCP		BIT(30)
+ 
+ /* EIP197_HIA_xDR_DMA_CFG */
+ #define EIP197_HIA_xDR_WR_RES_BUF		BIT(22)
+@@ -213,7 +234,6 @@
+ /* EIP197_HIA_xDR_PROC_COUNT */
+ #define EIP197_xDR_PROC_xD_PKT_OFFSET		24
+ #define EIP197_xDR_PROC_xD_PKT_MASK		GENMASK(6, 0)
+-#define EIP197_xDR_PROC_xD_COUNT(n)		((n) << 2)
+ #define EIP197_xDR_PROC_xD_PKT(n)		((n) << 24)
+ #define EIP197_xDR_PROC_CLR_COUNT		BIT(31)
+ 
+@@ -228,6 +248,8 @@
+ #define EIP197_HIA_RA_PE_CTRL_EN		BIT(30)
+ 
+ /* EIP197_HIA_OPTIONS */
++#define EIP197_N_RINGS_OFFSET			0
++#define EIP197_N_RINGS_MASK			GENMASK(3, 0)
+ #define EIP197_N_PES_OFFSET			4
+ #define EIP197_N_PES_MASK			GENMASK(4, 0)
+ #define EIP97_N_PES_MASK			GENMASK(2, 0)
+@@ -237,13 +259,13 @@
+ #define EIP197_CFSIZE_OFFSET			9
+ #define EIP197_CFSIZE_ADJUST			4
+ #define EIP97_CFSIZE_OFFSET			8
+-#define EIP197_CFSIZE_MASK			GENMASK(3, 0)
+-#define EIP97_CFSIZE_MASK			GENMASK(4, 0)
++#define EIP197_CFSIZE_MASK			GENMASK(2, 0)
++#define EIP97_CFSIZE_MASK			GENMASK(3, 0)
+ #define EIP197_RFSIZE_OFFSET			12
+ #define EIP197_RFSIZE_ADJUST			4
+ #define EIP97_RFSIZE_OFFSET			12
+-#define EIP197_RFSIZE_MASK			GENMASK(3, 0)
+-#define EIP97_RFSIZE_MASK			GENMASK(4, 0)
++#define EIP197_RFSIZE_MASK			GENMASK(2, 0)
++#define EIP97_RFSIZE_MASK			GENMASK(3, 0)
+ 
+ /* EIP197_HIA_AIC_R_ENABLE_CTRL */
+ #define EIP197_CDR_IRQ(n)			BIT((n) * 2)
+@@ -257,9 +279,9 @@
+ #define EIP197_HIA_DxE_CFG_MIN_CTRL_SIZE(n)	((n) << 16)
+ #define EIP197_HIA_DxE_CFG_CTRL_CACHE_CTRL(n)	(((n) & 0x7) << 20)
+ #define EIP197_HIA_DxE_CFG_MAX_CTRL_SIZE(n)	((n) << 24)
+-#define EIP197_HIA_DFE_CFG_DIS_DEBUG		(BIT(31) | BIT(29))
++#define EIP197_HIA_DFE_CFG_DIS_DEBUG		GENMASK(31, 29)
+ #define EIP197_HIA_DSE_CFG_EN_SINGLE_WR		BIT(29)
+-#define EIP197_HIA_DSE_CFG_DIS_DEBUG		BIT(31)
++#define EIP197_HIA_DSE_CFG_DIS_DEBUG		GENMASK(31, 30)
+ 
+ /* EIP197_HIA_DFE/DSE_THR_CTRL */
+ #define EIP197_DxE_THR_CTRL_EN			BIT(30)
+@@ -327,13 +349,21 @@
+ #define EIP197_ADDRESS_MODE			BIT(8)
+ #define EIP197_CONTROL_MODE			BIT(9)
+ 
++/* EIP197_PE_EIP96_TOKEN_CTRL2 */
++#define EIP197_PE_EIP96_TOKEN_CTRL2_CTX_DONE	BIT(3)
++
++/* EIP197_STRC_CONFIG */
++#define EIP197_STRC_CONFIG_INIT			BIT(31)
++#define EIP197_STRC_CONFIG_LARGE_REC(s)		(s<<8)
++#define EIP197_STRC_CONFIG_SMALL_REC(s)		(s<<0)
++
+ /* EIP197_FLUE_CONFIG */
+ #define EIP197_FLUE_CONFIG_MAGIC		0xc7000004
+ 
+ /* Context Control */
+ struct safexcel_context_record {
+-	u32 control0;
+-	u32 control1;
++	__le32 control0;
++	__le32 control1;
+ 
+ 	__le32 data[40];
+ } __packed;
+@@ -358,10 +388,14 @@ struct safexcel_context_record {
+ #define CONTEXT_CONTROL_CRYPTO_ALG_AES128	(0x5 << 17)
+ #define CONTEXT_CONTROL_CRYPTO_ALG_AES192	(0x6 << 17)
+ #define CONTEXT_CONTROL_CRYPTO_ALG_AES256	(0x7 << 17)
++#define CONTEXT_CONTROL_CRYPTO_ALG_CHACHA20	(0x8 << 17)
++#define CONTEXT_CONTROL_CRYPTO_ALG_SM4		(0xd << 17)
++#define CONTEXT_CONTROL_DIGEST_INITIAL		(0x0 << 21)
+ #define CONTEXT_CONTROL_DIGEST_PRECOMPUTED	(0x1 << 21)
+ #define CONTEXT_CONTROL_DIGEST_XCM		(0x2 << 21)
+ #define CONTEXT_CONTROL_DIGEST_HMAC		(0x3 << 21)
+ #define CONTEXT_CONTROL_CRYPTO_ALG_MD5		(0x0 << 23)
++#define CONTEXT_CONTROL_CRYPTO_ALG_CRC32	(0x0 << 23)
+ #define CONTEXT_CONTROL_CRYPTO_ALG_SHA1		(0x2 << 23)
+ #define CONTEXT_CONTROL_CRYPTO_ALG_SHA224	(0x4 << 23)
+ #define CONTEXT_CONTROL_CRYPTO_ALG_SHA256	(0x3 << 23)
+@@ -371,17 +405,25 @@ struct safexcel_context_record {
+ #define CONTEXT_CONTROL_CRYPTO_ALG_XCBC128	(0x1 << 23)
+ #define CONTEXT_CONTROL_CRYPTO_ALG_XCBC192	(0x2 << 23)
+ #define CONTEXT_CONTROL_CRYPTO_ALG_XCBC256	(0x3 << 23)
++#define CONTEXT_CONTROL_CRYPTO_ALG_SM3		(0x7 << 23)
++#define CONTEXT_CONTROL_CRYPTO_ALG_SHA3_256	(0xb << 23)
++#define CONTEXT_CONTROL_CRYPTO_ALG_SHA3_224	(0xc << 23)
++#define CONTEXT_CONTROL_CRYPTO_ALG_SHA3_512	(0xd << 23)
++#define CONTEXT_CONTROL_CRYPTO_ALG_SHA3_384	(0xe << 23)
++#define CONTEXT_CONTROL_CRYPTO_ALG_POLY1305	(0xf << 23)
+ #define CONTEXT_CONTROL_INV_FR			(0x5 << 24)
+ #define CONTEXT_CONTROL_INV_TR			(0x6 << 24)
+ 
+ /* control1 */
+ #define CONTEXT_CONTROL_CRYPTO_MODE_ECB		(0 << 0)
+ #define CONTEXT_CONTROL_CRYPTO_MODE_CBC		(1 << 0)
++#define CONTEXT_CONTROL_CHACHA20_MODE_256_32	(2 << 0)
+ #define CONTEXT_CONTROL_CRYPTO_MODE_OFB		(4 << 0)
+ #define CONTEXT_CONTROL_CRYPTO_MODE_CFB		(5 << 0)
+ #define CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD	(6 << 0)
+ #define CONTEXT_CONTROL_CRYPTO_MODE_XTS		(7 << 0)
+ #define CONTEXT_CONTROL_CRYPTO_MODE_XCM		((6 << 0) | BIT(17))
++#define CONTEXT_CONTROL_CHACHA20_MODE_CALC_OTK	(12 << 0)
+ #define CONTEXT_CONTROL_IV0			BIT(5)
+ #define CONTEXT_CONTROL_IV1			BIT(6)
+ #define CONTEXT_CONTROL_IV2			BIT(7)
+@@ -394,6 +436,13 @@ struct safexcel_context_record {
+ #define EIP197_XCM_MODE_GCM			1
+ #define EIP197_XCM_MODE_CCM			2
+ 
++#define EIP197_AEAD_TYPE_IPSEC_ESP		2
++#define EIP197_AEAD_TYPE_IPSEC_ESP_GMAC		3
++#define EIP197_AEAD_IPSEC_IV_SIZE		8
++#define EIP197_AEAD_IPSEC_NONCE_SIZE		4
++#define EIP197_AEAD_IPSEC_COUNTER_SIZE		4
++#define EIP197_AEAD_IPSEC_CCM_NONCE_SIZE	3
++
+ /* The hash counter given to the engine in the context has a granularity of
+  * 64 bits.
+  */
+@@ -423,6 +472,8 @@ struct safexcel_context_record {
+ #define EIP197_TRC_PARAMS2_RC_SZ_SMALL(n)	((n) << 18)
+ 
+ /* Cache helpers */
++#define EIP197_MIN_DSIZE			1024
++#define EIP197_MIN_ASIZE			8
+ #define EIP197_CS_TRC_REC_WC			64
+ #define EIP197_CS_RC_SIZE			(4 * sizeof(u32))
+ #define EIP197_CS_RC_NEXT(x)			(x)
+@@ -447,7 +498,7 @@ struct result_data_desc {
+ 	u16 application_id;
+ 	u16 rsvd1;
+ 
+-	u32 rsvd2;
++	u32 rsvd2[5];
+ } __packed;
+ 
+ 
+@@ -465,16 +516,15 @@ struct safexcel_result_desc {
+ 
+ 	u32 data_lo;
+ 	u32 data_hi;
+-
+-	struct result_data_desc result_data;
+ } __packed;
+ 
+ /*
+  * The EIP(1)97 only needs to fetch the descriptor part of
+  * the result descriptor, not the result token part!
+  */
+-#define EIP197_RD64_FETCH_SIZE		((sizeof(struct safexcel_result_desc) -\
+-					  sizeof(struct result_data_desc)) /\
++#define EIP197_RD64_FETCH_SIZE		(sizeof(struct safexcel_result_desc) /\
++					 sizeof(u32))
++#define EIP197_RD64_RESULT_SIZE		(sizeof(struct result_data_desc) /\
+ 					 sizeof(u32))
+ 
+ struct safexcel_token {
+@@ -505,6 +555,8 @@ static inline void eip197_noop_token(str
+ {
+ 	token->opcode = EIP197_TOKEN_OPCODE_NOOP;
+ 	token->packet_length = BIT(2);
++	token->stat = 0;
++	token->instructions = 0;
+ }
+ 
+ /* Instructions */
+@@ -526,14 +578,13 @@ struct safexcel_control_data_desc {
+ 	u16 application_id;
+ 	u16 rsvd;
+ 
+-	u8 refresh:2;
+-	u32 context_lo:30;
++	u32 context_lo;
+ 	u32 context_hi;
+ 
+ 	u32 control0;
+ 	u32 control1;
+ 
+-	u32 token[EIP197_MAX_TOKENS];
++	u32 token[EIP197_EMB_TOKENS];
+ } __packed;
+ 
+ #define EIP197_OPTION_MAGIC_VALUE	BIT(0)
+@@ -543,7 +594,10 @@ struct safexcel_control_data_desc {
+ #define EIP197_OPTION_2_TOKEN_IV_CMD	GENMASK(11, 10)
+ #define EIP197_OPTION_4_TOKEN_IV_CMD	GENMASK(11, 9)
+ 
++#define EIP197_TYPE_BCLA		0x0
+ #define EIP197_TYPE_EXTENDED		0x3
++#define EIP197_CONTEXT_SMALL		0x2
++#define EIP197_CONTEXT_SIZE_MASK	0x3
+ 
+ /* Basic Command Descriptor format */
+ struct safexcel_command_desc {
+@@ -551,16 +605,22 @@ struct safexcel_command_desc {
+ 	u8 rsvd0:5;
+ 	u8 last_seg:1;
+ 	u8 first_seg:1;
+-	u16 additional_cdata_size:8;
++	u8 additional_cdata_size:8;
+ 
+ 	u32 rsvd1;
+ 
+ 	u32 data_lo;
+ 	u32 data_hi;
+ 
++	u32 atok_lo;
++	u32 atok_hi;
++
+ 	struct safexcel_control_data_desc control_data;
+ } __packed;
+ 
++#define EIP197_CD64_FETCH_SIZE		(sizeof(struct safexcel_command_desc) /\
++					sizeof(u32))
++
+ /*
+  * Internal structures & functions
+  */
+@@ -578,15 +638,20 @@ enum eip197_fw {
+ 
+ struct safexcel_desc_ring {
+ 	void *base;
++	void *shbase;
+ 	void *base_end;
++	void *shbase_end;
+ 	dma_addr_t base_dma;
++	dma_addr_t shbase_dma;
+ 
+ 	/* write and read pointers */
+ 	void *write;
++	void *shwrite;
+ 	void *read;
+ 
+ 	/* descriptor element offset */
+-	unsigned offset;
++	unsigned int offset;
++	unsigned int shoffset;
+ };
+ 
+ enum safexcel_alg_type {
+@@ -601,9 +666,11 @@ struct safexcel_config {
+ 
+ 	u32 cd_size;
+ 	u32 cd_offset;
++	u32 cdsh_offset;
+ 
+ 	u32 rd_size;
+ 	u32 rd_offset;
++	u32 res_offset;
+ };
+ 
+ struct safexcel_work_data {
+@@ -654,6 +721,12 @@ enum safexcel_eip_version {
+ /* Priority we use for advertising our algorithms */
+ #define SAFEXCEL_CRA_PRIORITY		300
+ 
++/* SM3 digest result for zero length message */
++#define EIP197_SM3_ZEROM_HASH	"\x1A\xB2\x1D\x83\x55\xCF\xA1\x7F" \
++				"\x8E\x61\x19\x48\x31\xE8\x1A\x8F" \
++				"\x22\xBE\xC8\xC7\x28\xFE\xFB\x74" \
++				"\x7E\xD0\x35\xEB\x50\x82\xAA\x2B"
++
+ /* EIP algorithm presence flags */
+ enum safexcel_eip_algorithms {
+ 	SAFEXCEL_ALG_BC0      = BIT(5),
+@@ -697,16 +770,23 @@ struct safexcel_register_offsets {
+ enum safexcel_flags {
+ 	EIP197_TRC_CACHE	= BIT(0),
+ 	SAFEXCEL_HW_EIP197	= BIT(1),
++	EIP197_PE_ARB		= BIT(2),
++	EIP197_ICE		= BIT(3),
++	EIP197_SIMPLE_TRC	= BIT(4),
+ };
+ 
+ struct safexcel_hwconfig {
+ 	enum safexcel_eip_algorithms algo_flags;
+ 	int hwver;
+ 	int hiaver;
++	int ppver;
+ 	int pever;
+ 	int hwdataw;
+ 	int hwcfsize;
+ 	int hwrfsize;
++	int hwnumpes;
++	int hwnumrings;
++	int hwnumraic;
+ };
+ 
+ struct safexcel_crypto_priv {
+@@ -778,7 +858,7 @@ struct safexcel_inv_result {
+ 
+ void safexcel_dequeue(struct safexcel_crypto_priv *priv, int ring);
+ int safexcel_rdesc_check_errors(struct safexcel_crypto_priv *priv,
+-				struct safexcel_result_desc *rdesc);
++				void *rdp);
+ void safexcel_complete(struct safexcel_crypto_priv *priv, int ring);
+ int safexcel_invalidate_cache(struct crypto_async_request *async,
+ 			      struct safexcel_crypto_priv *priv,
+@@ -797,7 +877,8 @@ struct safexcel_command_desc *safexcel_a
+ 						 bool first, bool last,
+ 						 dma_addr_t data, u32 len,
+ 						 u32 full_data_len,
+-						 dma_addr_t context);
++						 dma_addr_t context,
++						 struct safexcel_token **atoken);
+ struct safexcel_result_desc *safexcel_add_rdesc(struct safexcel_crypto_priv *priv,
+ 						 int ring_id,
+ 						bool first, bool last,
+@@ -853,5 +934,43 @@ extern struct safexcel_alg_template safe
+ extern struct safexcel_alg_template safexcel_alg_xts_aes;
+ extern struct safexcel_alg_template safexcel_alg_gcm;
+ extern struct safexcel_alg_template safexcel_alg_ccm;
++extern struct safexcel_alg_template safexcel_alg_crc32;
++extern struct safexcel_alg_template safexcel_alg_cbcmac;
++extern struct safexcel_alg_template safexcel_alg_xcbcmac;
++extern struct safexcel_alg_template safexcel_alg_cmac;
++extern struct safexcel_alg_template safexcel_alg_chacha20;
++extern struct safexcel_alg_template safexcel_alg_chachapoly;
++extern struct safexcel_alg_template safexcel_alg_chachapoly_esp;
++extern struct safexcel_alg_template safexcel_alg_sm3;
++extern struct safexcel_alg_template safexcel_alg_hmac_sm3;
++extern struct safexcel_alg_template safexcel_alg_ecb_sm4;
++extern struct safexcel_alg_template safexcel_alg_cbc_sm4;
++extern struct safexcel_alg_template safexcel_alg_ofb_sm4;
++extern struct safexcel_alg_template safexcel_alg_cfb_sm4;
++extern struct safexcel_alg_template safexcel_alg_ctr_sm4;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_cbc_sm4;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sm3_cbc_sm4;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_ctr_sm4;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sm3_ctr_sm4;
++extern struct safexcel_alg_template safexcel_alg_sha3_224;
++extern struct safexcel_alg_template safexcel_alg_sha3_256;
++extern struct safexcel_alg_template safexcel_alg_sha3_384;
++extern struct safexcel_alg_template safexcel_alg_sha3_512;
++extern struct safexcel_alg_template safexcel_alg_hmac_sha3_224;
++extern struct safexcel_alg_template safexcel_alg_hmac_sha3_256;
++extern struct safexcel_alg_template safexcel_alg_hmac_sha3_384;
++extern struct safexcel_alg_template safexcel_alg_hmac_sha3_512;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_cbc_des;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha256_cbc_des3_ede;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha224_cbc_des3_ede;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha512_cbc_des3_ede;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha384_cbc_des3_ede;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha256_cbc_des;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha224_cbc_des;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha512_cbc_des;
++extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha384_cbc_des;
++extern struct safexcel_alg_template safexcel_alg_rfc4106_gcm;
++extern struct safexcel_alg_template safexcel_alg_rfc4543_gcm;
++extern struct safexcel_alg_template safexcel_alg_rfc4309_ccm;
+ 
+ #endif
+--- a/drivers/crypto/inside-secure/safexcel_hash.c
++++ b/drivers/crypto/inside-secure/safexcel_hash.c
+@@ -5,9 +5,13 @@
+  * Antoine Tenart <antoine.tenart@free-electrons.com>
+  */
+ 
++#include <crypto/aes.h>
+ #include <crypto/hmac.h>
+ #include <crypto/md5.h>
+ #include <crypto/sha.h>
++#include <crypto/sha3.h>
++#include <crypto/skcipher.h>
++#include <crypto/sm3.h>
+ #include <linux/device.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/dmapool.h>
+@@ -19,9 +23,19 @@ struct safexcel_ahash_ctx {
+ 	struct safexcel_crypto_priv *priv;
+ 
+ 	u32 alg;
+-
+-	u32 ipad[SHA512_DIGEST_SIZE / sizeof(u32)];
+-	u32 opad[SHA512_DIGEST_SIZE / sizeof(u32)];
++	u8  key_sz;
++	bool cbcmac;
++	bool do_fallback;
++	bool fb_init_done;
++	bool fb_do_setkey;
++
++	__le32 ipad[SHA3_512_BLOCK_SIZE / sizeof(__le32)];
++	__le32 opad[SHA3_512_BLOCK_SIZE / sizeof(__le32)];
++
++	struct crypto_cipher *kaes;
++	struct crypto_ahash *fback;
++	struct crypto_shash *shpre;
++	struct shash_desc *shdesc;
+ };
+ 
+ struct safexcel_ahash_req {
+@@ -31,6 +45,8 @@ struct safexcel_ahash_req {
+ 	bool needs_inv;
+ 	bool hmac_zlen;
+ 	bool len_is_le;
++	bool not_first;
++	bool xcbcmac;
+ 
+ 	int nents;
+ 	dma_addr_t result_dma;
+@@ -39,7 +55,9 @@ struct safexcel_ahash_req {
+ 
+ 	u8 state_sz;    /* expected state size, only set once */
+ 	u8 block_sz;    /* block size, only set once */
+-	u32 state[SHA512_DIGEST_SIZE / sizeof(u32)] __aligned(sizeof(u32));
++	u8 digest_sz;   /* output digest size, only set once */
++	__le32 state[SHA3_512_BLOCK_SIZE /
++		     sizeof(__le32)] __aligned(sizeof(__le32));
+ 
+ 	u64 len;
+ 	u64 processed;
+@@ -57,22 +75,36 @@ static inline u64 safexcel_queued_len(st
+ }
+ 
+ static void safexcel_hash_token(struct safexcel_command_desc *cdesc,
+-				u32 input_length, u32 result_length)
++				u32 input_length, u32 result_length,
++				bool cbcmac)
+ {
+ 	struct safexcel_token *token =
+ 		(struct safexcel_token *)cdesc->control_data.token;
+ 
+ 	token[0].opcode = EIP197_TOKEN_OPCODE_DIRECTION;
+ 	token[0].packet_length = input_length;
+-	token[0].stat = EIP197_TOKEN_STAT_LAST_HASH;
+ 	token[0].instructions = EIP197_TOKEN_INS_TYPE_HASH;
+ 
+-	token[1].opcode = EIP197_TOKEN_OPCODE_INSERT;
+-	token[1].packet_length = result_length;
+-	token[1].stat = EIP197_TOKEN_STAT_LAST_HASH |
++	input_length &= 15;
++	if (unlikely(cbcmac && input_length)) {
++		token[0].stat =  0;
++		token[1].opcode = EIP197_TOKEN_OPCODE_INSERT;
++		token[1].packet_length = 16 - input_length;
++		token[1].stat = EIP197_TOKEN_STAT_LAST_HASH;
++		token[1].instructions = EIP197_TOKEN_INS_TYPE_HASH;
++	} else {
++		token[0].stat = EIP197_TOKEN_STAT_LAST_HASH;
++		eip197_noop_token(&token[1]);
++	}
++
++	token[2].opcode = EIP197_TOKEN_OPCODE_INSERT;
++	token[2].stat = EIP197_TOKEN_STAT_LAST_HASH |
+ 			EIP197_TOKEN_STAT_LAST_PACKET;
+-	token[1].instructions = EIP197_TOKEN_INS_TYPE_OUTPUT |
++	token[2].packet_length = result_length;
++	token[2].instructions = EIP197_TOKEN_INS_TYPE_OUTPUT |
+ 				EIP197_TOKEN_INS_INSERT_HASH_DIGEST;
++
++	eip197_noop_token(&token[3]);
+ }
+ 
+ static void safexcel_context_control(struct safexcel_ahash_ctx *ctx,
+@@ -82,29 +114,49 @@ static void safexcel_context_control(str
+ 	struct safexcel_crypto_priv *priv = ctx->priv;
+ 	u64 count = 0;
+ 
+-	cdesc->control_data.control0 |= ctx->alg;
++	cdesc->control_data.control0 = ctx->alg;
++	cdesc->control_data.control1 = 0;
+ 
+ 	/*
+ 	 * Copy the input digest if needed, and setup the context
+ 	 * fields. Do this now as we need it to setup the first command
+ 	 * descriptor.
+ 	 */
+-	if (!req->processed) {
+-		/* First - and possibly only - block of basic hash only */
+-		if (req->finish) {
++	if (unlikely(req->digest == CONTEXT_CONTROL_DIGEST_XCM)) {
++		if (req->xcbcmac)
++			memcpy(ctx->base.ctxr->data, ctx->ipad, ctx->key_sz);
++		else
++			memcpy(ctx->base.ctxr->data, req->state, req->state_sz);
++
++		if (!req->finish && req->xcbcmac)
++			cdesc->control_data.control0 |=
++				CONTEXT_CONTROL_DIGEST_XCM |
++				CONTEXT_CONTROL_TYPE_HASH_OUT  |
++				CONTEXT_CONTROL_NO_FINISH_HASH |
++				CONTEXT_CONTROL_SIZE(req->state_sz /
++						     sizeof(u32));
++		else
+ 			cdesc->control_data.control0 |=
++				CONTEXT_CONTROL_DIGEST_XCM |
++				CONTEXT_CONTROL_TYPE_HASH_OUT  |
++				CONTEXT_CONTROL_SIZE(req->state_sz /
++						     sizeof(u32));
++		return;
++	} else if (!req->processed) {
++		/* First - and possibly only - block of basic hash only */
++		if (req->finish)
++			cdesc->control_data.control0 |= req->digest |
+ 				CONTEXT_CONTROL_TYPE_HASH_OUT |
+ 				CONTEXT_CONTROL_RESTART_HASH  |
+ 				/* ensure its not 0! */
+ 				CONTEXT_CONTROL_SIZE(1);
+-		} else {
+-			cdesc->control_data.control0 |=
++		else
++			cdesc->control_data.control0 |= req->digest |
+ 				CONTEXT_CONTROL_TYPE_HASH_OUT  |
+ 				CONTEXT_CONTROL_RESTART_HASH   |
+ 				CONTEXT_CONTROL_NO_FINISH_HASH |
+ 				/* ensure its not 0! */
+ 				CONTEXT_CONTROL_SIZE(1);
+-		}
+ 		return;
+ 	}
+ 
+@@ -204,7 +256,7 @@ static int safexcel_handle_req_result(st
+ 	}
+ 
+ 	if (sreq->result_dma) {
+-		dma_unmap_single(priv->dev, sreq->result_dma, sreq->state_sz,
++		dma_unmap_single(priv->dev, sreq->result_dma, sreq->digest_sz,
+ 				 DMA_FROM_DEVICE);
+ 		sreq->result_dma = 0;
+ 	}
+@@ -223,14 +275,15 @@ static int safexcel_handle_req_result(st
+ 			memcpy(sreq->cache, sreq->state,
+ 			       crypto_ahash_digestsize(ahash));
+ 
+-			memcpy(sreq->state, ctx->opad, sreq->state_sz);
++			memcpy(sreq->state, ctx->opad, sreq->digest_sz);
+ 
+ 			sreq->len = sreq->block_sz +
+ 				    crypto_ahash_digestsize(ahash);
+ 			sreq->processed = sreq->block_sz;
+ 			sreq->hmac = 0;
+ 
+-			ctx->base.needs_inv = true;
++			if (priv->flags & EIP197_TRC_CACHE)
++				ctx->base.needs_inv = true;
+ 			areq->nbytes = 0;
+ 			safexcel_ahash_enqueue(areq);
+ 
+@@ -238,8 +291,14 @@ static int safexcel_handle_req_result(st
+ 			return 1;
+ 		}
+ 
+-		memcpy(areq->result, sreq->state,
+-		       crypto_ahash_digestsize(ahash));
++		if (unlikely(sreq->digest == CONTEXT_CONTROL_DIGEST_XCM &&
++			     ctx->alg == CONTEXT_CONTROL_CRYPTO_ALG_CRC32)) {
++			/* Undo final XOR with 0xffffffff ...*/
++			*(__le32 *)areq->result = ~sreq->state[0];
++		} else {
++			memcpy(areq->result, sreq->state,
++			       crypto_ahash_digestsize(ahash));
++		}
+ 	}
+ 
+ 	cache_len = safexcel_queued_len(sreq);
+@@ -261,10 +320,11 @@ static int safexcel_ahash_send_req(struc
+ 	struct safexcel_command_desc *cdesc, *first_cdesc = NULL;
+ 	struct safexcel_result_desc *rdesc;
+ 	struct scatterlist *sg;
+-	int i, extra = 0, n_cdesc = 0, ret = 0;
+-	u64 queued, len, cache_len;
++	struct safexcel_token *dmmy;
++	int i, extra = 0, n_cdesc = 0, ret = 0, cache_len, skip = 0;
++	u64 queued, len;
+ 
+-	queued = len = safexcel_queued_len(req);
++	queued = safexcel_queued_len(req);
+ 	if (queued <= HASH_CACHE_SIZE)
+ 		cache_len = queued;
+ 	else
+@@ -287,15 +347,52 @@ static int safexcel_ahash_send_req(struc
+ 				   areq->nbytes - extra);
+ 
+ 		queued -= extra;
+-		len -= extra;
+ 
+ 		if (!queued) {
+ 			*commands = 0;
+ 			*results = 0;
+ 			return 0;
+ 		}
++
++		extra = 0;
++	}
++
++	if (unlikely(req->xcbcmac && req->processed > AES_BLOCK_SIZE)) {
++		if (unlikely(cache_len < AES_BLOCK_SIZE)) {
++			/*
++			 * Cache contains less than 1 full block, complete.
++			 */
++			extra = AES_BLOCK_SIZE - cache_len;
++			if (queued > cache_len) {
++				/* More data follows: borrow bytes */
++				u64 tmp = queued - cache_len;
++
++				skip = min_t(u64, tmp, extra);
++				sg_pcopy_to_buffer(areq->src,
++					sg_nents(areq->src),
++					req->cache + cache_len,
++					skip, 0);
++			}
++			extra -= skip;
++			memset(req->cache + cache_len + skip, 0, extra);
++			if (!ctx->cbcmac && extra) {
++				// 10- padding for XCBCMAC & CMAC
++				req->cache[cache_len + skip] = 0x80;
++				// HW will use K2 iso K3 - compensate!
++				for (i = 0; i < AES_BLOCK_SIZE / sizeof(u32); i++)
++					((__be32 *)req->cache)[i] ^=
++					  cpu_to_be32(le32_to_cpu(
++					    ctx->ipad[i] ^ ctx->ipad[i + 4]));
++			}
++			cache_len = AES_BLOCK_SIZE;
++			queued = queued + extra;
++		}
++
++		/* XCBC continue: XOR previous result into 1st word */
++		crypto_xor(req->cache, (const u8 *)req->state, AES_BLOCK_SIZE);
+ 	}
+ 
++	len = queued;
+ 	/* Add a command descriptor for the cached data, if any */
+ 	if (cache_len) {
+ 		req->cache_dma = dma_map_single(priv->dev, req->cache,
+@@ -306,8 +403,9 @@ static int safexcel_ahash_send_req(struc
+ 		req->cache_sz = cache_len;
+ 		first_cdesc = safexcel_add_cdesc(priv, ring, 1,
+ 						 (cache_len == len),
+-						 req->cache_dma, cache_len, len,
+-						 ctx->base.ctxr_dma);
++						 req->cache_dma, cache_len,
++						 len, ctx->base.ctxr_dma,
++						 &dmmy);
+ 		if (IS_ERR(first_cdesc)) {
+ 			ret = PTR_ERR(first_cdesc);
+ 			goto unmap_cache;
+@@ -319,10 +417,6 @@ static int safexcel_ahash_send_req(struc
+ 			goto send_command;
+ 	}
+ 
+-	/* Skip descriptor generation for zero-length requests */
+-	if (!areq->nbytes)
+-		goto send_command;
+-
+ 	/* Now handle the current ahash request buffer(s) */
+ 	req->nents = dma_map_sg(priv->dev, areq->src,
+ 				sg_nents_for_len(areq->src,
+@@ -336,26 +430,34 @@ static int safexcel_ahash_send_req(struc
+ 	for_each_sg(areq->src, sg, req->nents, i) {
+ 		int sglen = sg_dma_len(sg);
+ 
++		if (unlikely(sglen <= skip)) {
++			skip -= sglen;
++			continue;
++		}
++
+ 		/* Do not overflow the request */
+-		if (queued < sglen)
++		if ((queued + skip) <= sglen)
+ 			sglen = queued;
++		else
++			sglen -= skip;
+ 
+ 		cdesc = safexcel_add_cdesc(priv, ring, !n_cdesc,
+ 					   !(queued - sglen),
+-					   sg_dma_address(sg),
+-					   sglen, len, ctx->base.ctxr_dma);
++					   sg_dma_address(sg) + skip, sglen,
++					   len, ctx->base.ctxr_dma, &dmmy);
+ 		if (IS_ERR(cdesc)) {
+ 			ret = PTR_ERR(cdesc);
+ 			goto unmap_sg;
+ 		}
+-		n_cdesc++;
+ 
+-		if (n_cdesc == 1)
++		if (!n_cdesc)
+ 			first_cdesc = cdesc;
++		n_cdesc++;
+ 
+ 		queued -= sglen;
+ 		if (!queued)
+ 			break;
++		skip = 0;
+ 	}
+ 
+ send_command:
+@@ -363,9 +465,9 @@ send_command:
+ 	safexcel_context_control(ctx, req, first_cdesc);
+ 
+ 	/* Add the token */
+-	safexcel_hash_token(first_cdesc, len, req->state_sz);
++	safexcel_hash_token(first_cdesc, len, req->digest_sz, ctx->cbcmac);
+ 
+-	req->result_dma = dma_map_single(priv->dev, req->state, req->state_sz,
++	req->result_dma = dma_map_single(priv->dev, req->state, req->digest_sz,
+ 					 DMA_FROM_DEVICE);
+ 	if (dma_mapping_error(priv->dev, req->result_dma)) {
+ 		ret = -EINVAL;
+@@ -374,7 +476,7 @@ send_command:
+ 
+ 	/* Add a result descriptor */
+ 	rdesc = safexcel_add_rdesc(priv, ring, 1, 1, req->result_dma,
+-				   req->state_sz);
++				   req->digest_sz);
+ 	if (IS_ERR(rdesc)) {
+ 		ret = PTR_ERR(rdesc);
+ 		goto unmap_result;
+@@ -382,17 +484,20 @@ send_command:
+ 
+ 	safexcel_rdr_req_set(priv, ring, rdesc, &areq->base);
+ 
+-	req->processed += len;
++	req->processed += len - extra;
+ 
+ 	*commands = n_cdesc;
+ 	*results = 1;
+ 	return 0;
+ 
+ unmap_result:
+-	dma_unmap_single(priv->dev, req->result_dma, req->state_sz,
++	dma_unmap_single(priv->dev, req->result_dma, req->digest_sz,
+ 			 DMA_FROM_DEVICE);
+ unmap_sg:
+-	dma_unmap_sg(priv->dev, areq->src, req->nents, DMA_TO_DEVICE);
++	if (req->nents) {
++		dma_unmap_sg(priv->dev, areq->src, req->nents, DMA_TO_DEVICE);
++		req->nents = 0;
++	}
+ cdesc_rollback:
+ 	for (i = 0; i < n_cdesc; i++)
+ 		safexcel_ring_rollback_wptr(priv, &priv->ring[ring].cdr);
+@@ -590,16 +695,12 @@ static int safexcel_ahash_enqueue(struct
+ 
+ 	if (ctx->base.ctxr) {
+ 		if (priv->flags & EIP197_TRC_CACHE && !ctx->base.needs_inv &&
+-		    req->processed &&
+-		    (/* invalidate for basic hash continuation finish */
+-		     (req->finish &&
+-		      (req->digest == CONTEXT_CONTROL_DIGEST_PRECOMPUTED)) ||
++		     /* invalidate for *any* non-XCBC continuation */
++		   ((req->not_first && !req->xcbcmac) ||
+ 		     /* invalidate if (i)digest changed */
+ 		     memcmp(ctx->base.ctxr->data, req->state, req->state_sz) ||
+-		     /* invalidate for HMAC continuation finish */
+-		     (req->finish && (req->processed != req->block_sz)) ||
+ 		     /* invalidate for HMAC finish with odigest changed */
+-		     (req->finish &&
++		     (req->finish && req->hmac &&
+ 		      memcmp(ctx->base.ctxr->data + (req->state_sz>>2),
+ 			     ctx->opad, req->state_sz))))
+ 			/*
+@@ -622,6 +723,7 @@ static int safexcel_ahash_enqueue(struct
+ 		if (!ctx->base.ctxr)
+ 			return -ENOMEM;
+ 	}
++	req->not_first = true;
+ 
+ 	ring = ctx->base.ring;
+ 
+@@ -691,8 +793,34 @@ static int safexcel_ahash_final(struct a
+ 		else if (ctx->alg == CONTEXT_CONTROL_CRYPTO_ALG_SHA512)
+ 			memcpy(areq->result, sha512_zero_message_hash,
+ 			       SHA512_DIGEST_SIZE);
++		else if (ctx->alg == CONTEXT_CONTROL_CRYPTO_ALG_SM3) {
++			memcpy(areq->result,
++			       EIP197_SM3_ZEROM_HASH, SM3_DIGEST_SIZE);
++		}
+ 
+ 		return 0;
++	} else if (unlikely(req->digest == CONTEXT_CONTROL_DIGEST_XCM &&
++			    ctx->alg == CONTEXT_CONTROL_CRYPTO_ALG_MD5 &&
++			    req->len == sizeof(u32) && !areq->nbytes)) {
++		/* Zero length CRC32 */
++		memcpy(areq->result, ctx->ipad, sizeof(u32));
++		return 0;
++	} else if (unlikely(ctx->cbcmac && req->len == AES_BLOCK_SIZE &&
++			    !areq->nbytes)) {
++		/* Zero length CBC MAC */
++		memset(areq->result, 0, AES_BLOCK_SIZE);
++		return 0;
++	} else if (unlikely(req->xcbcmac && req->len == AES_BLOCK_SIZE &&
++			    !areq->nbytes)) {
++		/* Zero length (X)CBC/CMAC */
++		int i;
++
++		for (i = 0; i < AES_BLOCK_SIZE / sizeof(u32); i++)
++			((__be32 *)areq->result)[i] =
++				cpu_to_be32(le32_to_cpu(ctx->ipad[i + 4]));//K3
++		areq->result[0] ^= 0x80;			// 10- padding
++		crypto_cipher_encrypt_one(ctx->kaes, areq->result, areq->result);
++		return 0;
+ 	} else if (unlikely(req->hmac &&
+ 			    (req->len == req->block_sz) &&
+ 			    !areq->nbytes)) {
+@@ -792,6 +920,7 @@ static int safexcel_ahash_cra_init(struc
+ 	ctx->priv = tmpl->priv;
+ 	ctx->base.send = safexcel_ahash_send;
+ 	ctx->base.handle_result = safexcel_handle_result;
++	ctx->fb_do_setkey = false;
+ 
+ 	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+ 				 sizeof(struct safexcel_ahash_req));
+@@ -808,6 +937,7 @@ static int safexcel_sha1_init(struct aha
+ 	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA1;
+ 	req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+ 	req->state_sz = SHA1_DIGEST_SIZE;
++	req->digest_sz = SHA1_DIGEST_SIZE;
+ 	req->block_sz = SHA1_BLOCK_SIZE;
+ 
+ 	return 0;
+@@ -889,6 +1019,7 @@ static int safexcel_hmac_sha1_init(struc
+ 	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA1;
+ 	req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+ 	req->state_sz = SHA1_DIGEST_SIZE;
++	req->digest_sz = SHA1_DIGEST_SIZE;
+ 	req->block_sz = SHA1_BLOCK_SIZE;
+ 	req->hmac = true;
+ 
+@@ -1125,6 +1256,7 @@ static int safexcel_sha256_init(struct a
+ 	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA256;
+ 	req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+ 	req->state_sz = SHA256_DIGEST_SIZE;
++	req->digest_sz = SHA256_DIGEST_SIZE;
+ 	req->block_sz = SHA256_BLOCK_SIZE;
+ 
+ 	return 0;
+@@ -1180,6 +1312,7 @@ static int safexcel_sha224_init(struct a
+ 	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA224;
+ 	req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+ 	req->state_sz = SHA256_DIGEST_SIZE;
++	req->digest_sz = SHA256_DIGEST_SIZE;
+ 	req->block_sz = SHA256_BLOCK_SIZE;
+ 
+ 	return 0;
+@@ -1248,6 +1381,7 @@ static int safexcel_hmac_sha224_init(str
+ 	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA224;
+ 	req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+ 	req->state_sz = SHA256_DIGEST_SIZE;
++	req->digest_sz = SHA256_DIGEST_SIZE;
+ 	req->block_sz = SHA256_BLOCK_SIZE;
+ 	req->hmac = true;
+ 
+@@ -1318,6 +1452,7 @@ static int safexcel_hmac_sha256_init(str
+ 	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA256;
+ 	req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+ 	req->state_sz = SHA256_DIGEST_SIZE;
++	req->digest_sz = SHA256_DIGEST_SIZE;
+ 	req->block_sz = SHA256_BLOCK_SIZE;
+ 	req->hmac = true;
+ 
+@@ -1375,6 +1510,7 @@ static int safexcel_sha512_init(struct a
+ 	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA512;
+ 	req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+ 	req->state_sz = SHA512_DIGEST_SIZE;
++	req->digest_sz = SHA512_DIGEST_SIZE;
+ 	req->block_sz = SHA512_BLOCK_SIZE;
+ 
+ 	return 0;
+@@ -1430,6 +1566,7 @@ static int safexcel_sha384_init(struct a
+ 	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA384;
+ 	req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+ 	req->state_sz = SHA512_DIGEST_SIZE;
++	req->digest_sz = SHA512_DIGEST_SIZE;
+ 	req->block_sz = SHA512_BLOCK_SIZE;
+ 
+ 	return 0;
+@@ -1498,6 +1635,7 @@ static int safexcel_hmac_sha512_init(str
+ 	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA512;
+ 	req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+ 	req->state_sz = SHA512_DIGEST_SIZE;
++	req->digest_sz = SHA512_DIGEST_SIZE;
+ 	req->block_sz = SHA512_BLOCK_SIZE;
+ 	req->hmac = true;
+ 
+@@ -1568,6 +1706,7 @@ static int safexcel_hmac_sha384_init(str
+ 	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA384;
+ 	req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+ 	req->state_sz = SHA512_DIGEST_SIZE;
++	req->digest_sz = SHA512_DIGEST_SIZE;
+ 	req->block_sz = SHA512_BLOCK_SIZE;
+ 	req->hmac = true;
+ 
+@@ -1625,6 +1764,7 @@ static int safexcel_md5_init(struct ahas
+ 	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_MD5;
+ 	req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+ 	req->state_sz = MD5_DIGEST_SIZE;
++	req->digest_sz = MD5_DIGEST_SIZE;
+ 	req->block_sz = MD5_HMAC_BLOCK_SIZE;
+ 
+ 	return 0;
+@@ -1686,6 +1826,7 @@ static int safexcel_hmac_md5_init(struct
+ 	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_MD5;
+ 	req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
+ 	req->state_sz = MD5_DIGEST_SIZE;
++	req->digest_sz = MD5_DIGEST_SIZE;
+ 	req->block_sz = MD5_HMAC_BLOCK_SIZE;
+ 	req->len_is_le = true; /* MD5 is little endian! ... */
+ 	req->hmac = true;
+@@ -1738,5 +1879,1235 @@ struct safexcel_alg_template safexcel_al
+ 				.cra_module = THIS_MODULE,
+ 			},
+ 		},
++	},
++};
++
++static int safexcel_crc32_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(tfm);
++	int ret = safexcel_ahash_cra_init(tfm);
++
++	/* Default 'key' is all zeroes */
++	memset(ctx->ipad, 0, sizeof(u32));
++	return ret;
++}
++
++static int safexcel_crc32_init(struct ahash_request *areq)
++{
++	struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq));
++	struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++	memset(req, 0, sizeof(*req));
++
++	/* Start from loaded key */
++	req->state[0]	= (__force __le32)le32_to_cpu(~ctx->ipad[0]);
++	/* Set processed to non-zero to enable invalidation detection */
++	req->len	= sizeof(u32);
++	req->processed	= sizeof(u32);
++
++	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_CRC32;
++	req->digest = CONTEXT_CONTROL_DIGEST_XCM;
++	req->state_sz = sizeof(u32);
++	req->digest_sz = sizeof(u32);
++	req->block_sz = sizeof(u32);
++
++	return 0;
++}
++
++static int safexcel_crc32_setkey(struct crypto_ahash *tfm, const u8 *key,
++				 unsigned int keylen)
++{
++	struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm));
++
++	if (keylen != sizeof(u32))
++		return -EINVAL;
++
++	memcpy(ctx->ipad, key, sizeof(u32));
++	return 0;
++}
++
++static int safexcel_crc32_digest(struct ahash_request *areq)
++{
++	return safexcel_crc32_init(areq) ?: safexcel_ahash_finup(areq);
++}
++
++struct safexcel_alg_template safexcel_alg_crc32 = {
++	.type = SAFEXCEL_ALG_TYPE_AHASH,
++	.algo_mask = 0,
++	.alg.ahash = {
++		.init = safexcel_crc32_init,
++		.update = safexcel_ahash_update,
++		.final = safexcel_ahash_final,
++		.finup = safexcel_ahash_finup,
++		.digest = safexcel_crc32_digest,
++		.setkey = safexcel_crc32_setkey,
++		.export = safexcel_ahash_export,
++		.import = safexcel_ahash_import,
++		.halg = {
++			.digestsize = sizeof(u32),
++			.statesize = sizeof(struct safexcel_ahash_export_state),
++			.base = {
++				.cra_name = "crc32",
++				.cra_driver_name = "safexcel-crc32",
++				.cra_priority = SAFEXCEL_CRA_PRIORITY,
++				.cra_flags = CRYPTO_ALG_OPTIONAL_KEY |
++					     CRYPTO_ALG_ASYNC |
++					     CRYPTO_ALG_KERN_DRIVER_ONLY,
++				.cra_blocksize = 1,
++				.cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++				.cra_init = safexcel_crc32_cra_init,
++				.cra_exit = safexcel_ahash_cra_exit,
++				.cra_module = THIS_MODULE,
++			},
++		},
++	},
++};
++
++static int safexcel_cbcmac_init(struct ahash_request *areq)
++{
++	struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq));
++	struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++	memset(req, 0, sizeof(*req));
++
++	/* Start from loaded keys */
++	memcpy(req->state, ctx->ipad, ctx->key_sz);
++	/* Set processed to non-zero to enable invalidation detection */
++	req->len	= AES_BLOCK_SIZE;
++	req->processed	= AES_BLOCK_SIZE;
++
++	req->digest   = CONTEXT_CONTROL_DIGEST_XCM;
++	req->state_sz = ctx->key_sz;
++	req->digest_sz = AES_BLOCK_SIZE;
++	req->block_sz = AES_BLOCK_SIZE;
++	req->xcbcmac  = true;
++
++	return 0;
++}
++
++static int safexcel_cbcmac_setkey(struct crypto_ahash *tfm, const u8 *key,
++				 unsigned int len)
++{
++	struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm));
++	struct crypto_aes_ctx aes;
++	int ret, i;
++
++	ret = aes_expandkey(&aes, key, len);
++	if (ret)
++		return ret;
++
++	memset(ctx->ipad, 0, 2 * AES_BLOCK_SIZE);
++	for (i = 0; i < len / sizeof(u32); i++)
++		ctx->ipad[i + 8] = (__force __le32)cpu_to_be32(aes.key_enc[i]);
++
++	if (len == AES_KEYSIZE_192) {
++		ctx->alg    = CONTEXT_CONTROL_CRYPTO_ALG_XCBC192;
++		ctx->key_sz = AES_MAX_KEY_SIZE + 2 * AES_BLOCK_SIZE;
++	} else if (len == AES_KEYSIZE_256) {
++		ctx->alg    = CONTEXT_CONTROL_CRYPTO_ALG_XCBC256;
++		ctx->key_sz = AES_MAX_KEY_SIZE + 2 * AES_BLOCK_SIZE;
++	} else {
++		ctx->alg    = CONTEXT_CONTROL_CRYPTO_ALG_XCBC128;
++		ctx->key_sz = AES_MIN_KEY_SIZE + 2 * AES_BLOCK_SIZE;
++	}
++	ctx->cbcmac  = true;
++
++	memzero_explicit(&aes, sizeof(aes));
++	return 0;
++}
++
++static int safexcel_cbcmac_digest(struct ahash_request *areq)
++{
++	return safexcel_cbcmac_init(areq) ?: safexcel_ahash_finup(areq);
++}
++
++struct safexcel_alg_template safexcel_alg_cbcmac = {
++	.type = SAFEXCEL_ALG_TYPE_AHASH,
++	.algo_mask = 0,
++	.alg.ahash = {
++		.init = safexcel_cbcmac_init,
++		.update = safexcel_ahash_update,
++		.final = safexcel_ahash_final,
++		.finup = safexcel_ahash_finup,
++		.digest = safexcel_cbcmac_digest,
++		.setkey = safexcel_cbcmac_setkey,
++		.export = safexcel_ahash_export,
++		.import = safexcel_ahash_import,
++		.halg = {
++			.digestsize = AES_BLOCK_SIZE,
++			.statesize = sizeof(struct safexcel_ahash_export_state),
++			.base = {
++				.cra_name = "cbcmac(aes)",
++				.cra_driver_name = "safexcel-cbcmac-aes",
++				.cra_priority = SAFEXCEL_CRA_PRIORITY,
++				.cra_flags = CRYPTO_ALG_ASYNC |
++					     CRYPTO_ALG_KERN_DRIVER_ONLY,
++				.cra_blocksize = 1,
++				.cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++				.cra_init = safexcel_ahash_cra_init,
++				.cra_exit = safexcel_ahash_cra_exit,
++				.cra_module = THIS_MODULE,
++			},
++		},
++	},
++};
++
++static int safexcel_xcbcmac_setkey(struct crypto_ahash *tfm, const u8 *key,
++				 unsigned int len)
++{
++	struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm));
++	struct crypto_aes_ctx aes;
++	u32 key_tmp[3 * AES_BLOCK_SIZE / sizeof(u32)];
++	int ret, i;
++
++	ret = aes_expandkey(&aes, key, len);
++	if (ret)
++		return ret;
++
++	/* precompute the XCBC key material */
++	crypto_cipher_clear_flags(ctx->kaes, CRYPTO_TFM_REQ_MASK);
++	crypto_cipher_set_flags(ctx->kaes, crypto_ahash_get_flags(tfm) &
++				CRYPTO_TFM_REQ_MASK);
++	ret = crypto_cipher_setkey(ctx->kaes, key, len);
++	if (ret)
++		return ret;
++
++	crypto_cipher_encrypt_one(ctx->kaes, (u8 *)key_tmp + 2 * AES_BLOCK_SIZE,
++		"\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1\x1");
++	crypto_cipher_encrypt_one(ctx->kaes, (u8 *)key_tmp,
++		"\x2\x2\x2\x2\x2\x2\x2\x2\x2\x2\x2\x2\x2\x2\x2\x2");
++	crypto_cipher_encrypt_one(ctx->kaes, (u8 *)key_tmp + AES_BLOCK_SIZE,
++		"\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3");
++	for (i = 0; i < 3 * AES_BLOCK_SIZE / sizeof(u32); i++)
++		ctx->ipad[i] =
++			cpu_to_le32((__force u32)cpu_to_be32(key_tmp[i]));
++
++	crypto_cipher_clear_flags(ctx->kaes, CRYPTO_TFM_REQ_MASK);
++	crypto_cipher_set_flags(ctx->kaes, crypto_ahash_get_flags(tfm) &
++				CRYPTO_TFM_REQ_MASK);
++	ret = crypto_cipher_setkey(ctx->kaes,
++				   (u8 *)key_tmp + 2 * AES_BLOCK_SIZE,
++				   AES_MIN_KEY_SIZE);
++	if (ret)
++		return ret;
++
++	ctx->alg    = CONTEXT_CONTROL_CRYPTO_ALG_XCBC128;
++	ctx->key_sz = AES_MIN_KEY_SIZE + 2 * AES_BLOCK_SIZE;
++	ctx->cbcmac = false;
++
++	memzero_explicit(&aes, sizeof(aes));
++	return 0;
++}
++
++static int safexcel_xcbcmac_cra_init(struct crypto_tfm *tfm)
++{
++	struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_ahash_cra_init(tfm);
++	ctx->kaes = crypto_alloc_cipher("aes", 0, 0);
++	return PTR_ERR_OR_ZERO(ctx->kaes);
++}
++
++static void safexcel_xcbcmac_cra_exit(struct crypto_tfm *tfm)
++{
++	struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	crypto_free_cipher(ctx->kaes);
++	safexcel_ahash_cra_exit(tfm);
++}
++
++struct safexcel_alg_template safexcel_alg_xcbcmac = {
++	.type = SAFEXCEL_ALG_TYPE_AHASH,
++	.algo_mask = 0,
++	.alg.ahash = {
++		.init = safexcel_cbcmac_init,
++		.update = safexcel_ahash_update,
++		.final = safexcel_ahash_final,
++		.finup = safexcel_ahash_finup,
++		.digest = safexcel_cbcmac_digest,
++		.setkey = safexcel_xcbcmac_setkey,
++		.export = safexcel_ahash_export,
++		.import = safexcel_ahash_import,
++		.halg = {
++			.digestsize = AES_BLOCK_SIZE,
++			.statesize = sizeof(struct safexcel_ahash_export_state),
++			.base = {
++				.cra_name = "xcbc(aes)",
++				.cra_driver_name = "safexcel-xcbc-aes",
++				.cra_priority = SAFEXCEL_CRA_PRIORITY,
++				.cra_flags = CRYPTO_ALG_ASYNC |
++					     CRYPTO_ALG_KERN_DRIVER_ONLY,
++				.cra_blocksize = AES_BLOCK_SIZE,
++				.cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++				.cra_init = safexcel_xcbcmac_cra_init,
++				.cra_exit = safexcel_xcbcmac_cra_exit,
++				.cra_module = THIS_MODULE,
++			},
++		},
++	},
++};
++
++static int safexcel_cmac_setkey(struct crypto_ahash *tfm, const u8 *key,
++				unsigned int len)
++{
++	struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm));
++	struct crypto_aes_ctx aes;
++	__be64 consts[4];
++	u64 _const[2];
++	u8 msb_mask, gfmask;
++	int ret, i;
++
++	ret = aes_expandkey(&aes, key, len);
++	if (ret)
++		return ret;
++
++	for (i = 0; i < len / sizeof(u32); i++)
++		ctx->ipad[i + 8] =
++			cpu_to_le32((__force u32)cpu_to_be32(aes.key_enc[i]));
++
++	/* precompute the CMAC key material */
++	crypto_cipher_clear_flags(ctx->kaes, CRYPTO_TFM_REQ_MASK);
++	crypto_cipher_set_flags(ctx->kaes, crypto_ahash_get_flags(tfm) &
++				CRYPTO_TFM_REQ_MASK);
++	ret = crypto_cipher_setkey(ctx->kaes, key, len);
++	if (ret)
++		return ret;
++
++	/* code below borrowed from crypto/cmac.c */
++	/* encrypt the zero block */
++	memset(consts, 0, AES_BLOCK_SIZE);
++	crypto_cipher_encrypt_one(ctx->kaes, (u8 *)consts, (u8 *)consts);
++
++	gfmask = 0x87;
++	_const[0] = be64_to_cpu(consts[1]);
++	_const[1] = be64_to_cpu(consts[0]);
++
++	/* gf(2^128) multiply zero-ciphertext with u and u^2 */
++	for (i = 0; i < 4; i += 2) {
++		msb_mask = ((s64)_const[1] >> 63) & gfmask;
++		_const[1] = (_const[1] << 1) | (_const[0] >> 63);
++		_const[0] = (_const[0] << 1) ^ msb_mask;
++
++		consts[i + 0] = cpu_to_be64(_const[1]);
++		consts[i + 1] = cpu_to_be64(_const[0]);
++	}
++	/* end of code borrowed from crypto/cmac.c */
++
++	for (i = 0; i < 2 * AES_BLOCK_SIZE / sizeof(u32); i++)
++		ctx->ipad[i] = (__force __le32)cpu_to_be32(((u32 *)consts)[i]);
++
++	if (len == AES_KEYSIZE_192) {
++		ctx->alg    = CONTEXT_CONTROL_CRYPTO_ALG_XCBC192;
++		ctx->key_sz = AES_MAX_KEY_SIZE + 2 * AES_BLOCK_SIZE;
++	} else if (len == AES_KEYSIZE_256) {
++		ctx->alg    = CONTEXT_CONTROL_CRYPTO_ALG_XCBC256;
++		ctx->key_sz = AES_MAX_KEY_SIZE + 2 * AES_BLOCK_SIZE;
++	} else {
++		ctx->alg    = CONTEXT_CONTROL_CRYPTO_ALG_XCBC128;
++		ctx->key_sz = AES_MIN_KEY_SIZE + 2 * AES_BLOCK_SIZE;
++	}
++	ctx->cbcmac = false;
++
++	memzero_explicit(&aes, sizeof(aes));
++	return 0;
++}
++
++struct safexcel_alg_template safexcel_alg_cmac = {
++	.type = SAFEXCEL_ALG_TYPE_AHASH,
++	.algo_mask = 0,
++	.alg.ahash = {
++		.init = safexcel_cbcmac_init,
++		.update = safexcel_ahash_update,
++		.final = safexcel_ahash_final,
++		.finup = safexcel_ahash_finup,
++		.digest = safexcel_cbcmac_digest,
++		.setkey = safexcel_cmac_setkey,
++		.export = safexcel_ahash_export,
++		.import = safexcel_ahash_import,
++		.halg = {
++			.digestsize = AES_BLOCK_SIZE,
++			.statesize = sizeof(struct safexcel_ahash_export_state),
++			.base = {
++				.cra_name = "cmac(aes)",
++				.cra_driver_name = "safexcel-cmac-aes",
++				.cra_priority = SAFEXCEL_CRA_PRIORITY,
++				.cra_flags = CRYPTO_ALG_ASYNC |
++					     CRYPTO_ALG_KERN_DRIVER_ONLY,
++				.cra_blocksize = AES_BLOCK_SIZE,
++				.cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++				.cra_init = safexcel_xcbcmac_cra_init,
++				.cra_exit = safexcel_xcbcmac_cra_exit,
++				.cra_module = THIS_MODULE,
++			},
++		},
++	},
++};
++
++static int safexcel_sm3_init(struct ahash_request *areq)
++{
++	struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq));
++	struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++	memset(req, 0, sizeof(*req));
++
++	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SM3;
++	req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
++	req->state_sz = SM3_DIGEST_SIZE;
++	req->digest_sz = SM3_DIGEST_SIZE;
++	req->block_sz = SM3_BLOCK_SIZE;
++
++	return 0;
++}
++
++static int safexcel_sm3_digest(struct ahash_request *areq)
++{
++	int ret = safexcel_sm3_init(areq);
++
++	if (ret)
++		return ret;
++
++	return safexcel_ahash_finup(areq);
++}
++
++struct safexcel_alg_template safexcel_alg_sm3 = {
++	.type = SAFEXCEL_ALG_TYPE_AHASH,
++	.algo_mask = SAFEXCEL_ALG_SM3,
++	.alg.ahash = {
++		.init = safexcel_sm3_init,
++		.update = safexcel_ahash_update,
++		.final = safexcel_ahash_final,
++		.finup = safexcel_ahash_finup,
++		.digest = safexcel_sm3_digest,
++		.export = safexcel_ahash_export,
++		.import = safexcel_ahash_import,
++		.halg = {
++			.digestsize = SM3_DIGEST_SIZE,
++			.statesize = sizeof(struct safexcel_ahash_export_state),
++			.base = {
++				.cra_name = "sm3",
++				.cra_driver_name = "safexcel-sm3",
++				.cra_priority = SAFEXCEL_CRA_PRIORITY,
++				.cra_flags = CRYPTO_ALG_ASYNC |
++					     CRYPTO_ALG_KERN_DRIVER_ONLY,
++				.cra_blocksize = SM3_BLOCK_SIZE,
++				.cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++				.cra_init = safexcel_ahash_cra_init,
++				.cra_exit = safexcel_ahash_cra_exit,
++				.cra_module = THIS_MODULE,
++			},
++		},
++	},
++};
++
++static int safexcel_hmac_sm3_setkey(struct crypto_ahash *tfm, const u8 *key,
++				    unsigned int keylen)
++{
++	return safexcel_hmac_alg_setkey(tfm, key, keylen, "safexcel-sm3",
++					SM3_DIGEST_SIZE);
++}
++
++static int safexcel_hmac_sm3_init(struct ahash_request *areq)
++{
++	struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(areq));
++	struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++	memset(req, 0, sizeof(*req));
++
++	/* Start from ipad precompute */
++	memcpy(req->state, ctx->ipad, SM3_DIGEST_SIZE);
++	/* Already processed the key^ipad part now! */
++	req->len	= SM3_BLOCK_SIZE;
++	req->processed	= SM3_BLOCK_SIZE;
++
++	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SM3;
++	req->digest = CONTEXT_CONTROL_DIGEST_PRECOMPUTED;
++	req->state_sz = SM3_DIGEST_SIZE;
++	req->digest_sz = SM3_DIGEST_SIZE;
++	req->block_sz = SM3_BLOCK_SIZE;
++	req->hmac = true;
++
++	return 0;
++}
++
++static int safexcel_hmac_sm3_digest(struct ahash_request *areq)
++{
++	int ret = safexcel_hmac_sm3_init(areq);
++
++	if (ret)
++		return ret;
++
++	return safexcel_ahash_finup(areq);
++}
++
++struct safexcel_alg_template safexcel_alg_hmac_sm3 = {
++	.type = SAFEXCEL_ALG_TYPE_AHASH,
++	.algo_mask = SAFEXCEL_ALG_SM3,
++	.alg.ahash = {
++		.init = safexcel_hmac_sm3_init,
++		.update = safexcel_ahash_update,
++		.final = safexcel_ahash_final,
++		.finup = safexcel_ahash_finup,
++		.digest = safexcel_hmac_sm3_digest,
++		.setkey = safexcel_hmac_sm3_setkey,
++		.export = safexcel_ahash_export,
++		.import = safexcel_ahash_import,
++		.halg = {
++			.digestsize = SM3_DIGEST_SIZE,
++			.statesize = sizeof(struct safexcel_ahash_export_state),
++			.base = {
++				.cra_name = "hmac(sm3)",
++				.cra_driver_name = "safexcel-hmac-sm3",
++				.cra_priority = SAFEXCEL_CRA_PRIORITY,
++				.cra_flags = CRYPTO_ALG_ASYNC |
++					     CRYPTO_ALG_KERN_DRIVER_ONLY,
++				.cra_blocksize = SM3_BLOCK_SIZE,
++				.cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++				.cra_init = safexcel_ahash_cra_init,
++				.cra_exit = safexcel_ahash_cra_exit,
++				.cra_module = THIS_MODULE,
++			},
++		},
++	},
++};
++
++static int safexcel_sha3_224_init(struct ahash_request *areq)
++{
++	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++	struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++	struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++	memset(req, 0, sizeof(*req));
++
++	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA3_224;
++	req->digest = CONTEXT_CONTROL_DIGEST_INITIAL;
++	req->state_sz = SHA3_224_DIGEST_SIZE;
++	req->digest_sz = SHA3_224_DIGEST_SIZE;
++	req->block_sz = SHA3_224_BLOCK_SIZE;
++	ctx->do_fallback = false;
++	ctx->fb_init_done = false;
++	return 0;
++}
++
++static int safexcel_sha3_fbcheck(struct ahash_request *req)
++{
++	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
++	struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++	struct ahash_request *subreq = ahash_request_ctx(req);
++	int ret = 0;
++
++	if (ctx->do_fallback) {
++		ahash_request_set_tfm(subreq, ctx->fback);
++		ahash_request_set_callback(subreq, req->base.flags,
++					   req->base.complete, req->base.data);
++		ahash_request_set_crypt(subreq, req->src, req->result,
++					req->nbytes);
++		if (!ctx->fb_init_done) {
++			if (ctx->fb_do_setkey) {
++				/* Set fallback cipher HMAC key */
++				u8 key[SHA3_224_BLOCK_SIZE];
++
++				memcpy(key, ctx->ipad,
++				       crypto_ahash_blocksize(ctx->fback) / 2);
++				memcpy(key +
++				       crypto_ahash_blocksize(ctx->fback) / 2,
++				       ctx->opad,
++				       crypto_ahash_blocksize(ctx->fback) / 2);
++				ret = crypto_ahash_setkey(ctx->fback, key,
++					crypto_ahash_blocksize(ctx->fback));
++				memzero_explicit(key,
++					crypto_ahash_blocksize(ctx->fback));
++				ctx->fb_do_setkey = false;
++			}
++			ret = ret ?: crypto_ahash_init(subreq);
++			ctx->fb_init_done = true;
++		}
++	}
++	return ret;
++}
++
++static int safexcel_sha3_update(struct ahash_request *req)
++{
++	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
++	struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++	struct ahash_request *subreq = ahash_request_ctx(req);
++
++	ctx->do_fallback = true;
++	return safexcel_sha3_fbcheck(req) ?: crypto_ahash_update(subreq);
++}
++
++static int safexcel_sha3_final(struct ahash_request *req)
++{
++	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
++	struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++	struct ahash_request *subreq = ahash_request_ctx(req);
++
++	ctx->do_fallback = true;
++	return safexcel_sha3_fbcheck(req) ?: crypto_ahash_final(subreq);
++}
++
++static int safexcel_sha3_finup(struct ahash_request *req)
++{
++	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
++	struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++	struct ahash_request *subreq = ahash_request_ctx(req);
++
++	ctx->do_fallback |= !req->nbytes;
++	if (ctx->do_fallback)
++		/* Update or ex/import happened or len 0, cannot use the HW */
++		return safexcel_sha3_fbcheck(req) ?:
++		       crypto_ahash_finup(subreq);
++	else
++		return safexcel_ahash_finup(req);
++}
++
++static int safexcel_sha3_digest_fallback(struct ahash_request *req)
++{
++	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
++	struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++	struct ahash_request *subreq = ahash_request_ctx(req);
++
++	ctx->do_fallback = true;
++	ctx->fb_init_done = false;
++	return safexcel_sha3_fbcheck(req) ?: crypto_ahash_finup(subreq);
++}
++
++static int safexcel_sha3_224_digest(struct ahash_request *req)
++{
++	if (req->nbytes)
++		return safexcel_sha3_224_init(req) ?: safexcel_ahash_finup(req);
++
++	/* HW cannot do zero length hash, use fallback instead */
++	return safexcel_sha3_digest_fallback(req);
++}
++
++static int safexcel_sha3_export(struct ahash_request *req, void *out)
++{
++	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
++	struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++	struct ahash_request *subreq = ahash_request_ctx(req);
++
++	ctx->do_fallback = true;
++	return safexcel_sha3_fbcheck(req) ?: crypto_ahash_export(subreq, out);
++}
++
++static int safexcel_sha3_import(struct ahash_request *req, const void *in)
++{
++	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
++	struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++	struct ahash_request *subreq = ahash_request_ctx(req);
++
++	ctx->do_fallback = true;
++	return safexcel_sha3_fbcheck(req) ?: crypto_ahash_import(subreq, in);
++	// return safexcel_ahash_import(req, in);
++}
++
++static int safexcel_sha3_cra_init(struct crypto_tfm *tfm)
++{
++	struct crypto_ahash *ahash = __crypto_ahash_cast(tfm);
++	struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	safexcel_ahash_cra_init(tfm);
++
++	/* Allocate fallback implementation */
++	ctx->fback = crypto_alloc_ahash(crypto_tfm_alg_name(tfm), 0,
++					CRYPTO_ALG_ASYNC |
++					CRYPTO_ALG_NEED_FALLBACK);
++	if (IS_ERR(ctx->fback))
++		return PTR_ERR(ctx->fback);
++
++	/* Update statesize from fallback algorithm! */
++	crypto_hash_alg_common(ahash)->statesize =
++		crypto_ahash_statesize(ctx->fback);
++	crypto_ahash_set_reqsize(ahash, max(sizeof(struct safexcel_ahash_req),
++					    sizeof(struct ahash_request) +
++					    crypto_ahash_reqsize(ctx->fback)));
++	return 0;
++}
++
++static void safexcel_sha3_cra_exit(struct crypto_tfm *tfm)
++{
++	struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	crypto_free_ahash(ctx->fback);
++	safexcel_ahash_cra_exit(tfm);
++}
++
++struct safexcel_alg_template safexcel_alg_sha3_224 = {
++	.type = SAFEXCEL_ALG_TYPE_AHASH,
++	.algo_mask = SAFEXCEL_ALG_SHA3,
++	.alg.ahash = {
++		.init = safexcel_sha3_224_init,
++		.update = safexcel_sha3_update,
++		.final = safexcel_sha3_final,
++		.finup = safexcel_sha3_finup,
++		.digest = safexcel_sha3_224_digest,
++		.export = safexcel_sha3_export,
++		.import = safexcel_sha3_import,
++		.halg = {
++			.digestsize = SHA3_224_DIGEST_SIZE,
++			.statesize = sizeof(struct safexcel_ahash_export_state),
++			.base = {
++				.cra_name = "sha3-224",
++				.cra_driver_name = "safexcel-sha3-224",
++				.cra_priority = SAFEXCEL_CRA_PRIORITY,
++				.cra_flags = CRYPTO_ALG_ASYNC |
++					     CRYPTO_ALG_KERN_DRIVER_ONLY |
++					     CRYPTO_ALG_NEED_FALLBACK,
++				.cra_blocksize = SHA3_224_BLOCK_SIZE,
++				.cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++				.cra_init = safexcel_sha3_cra_init,
++				.cra_exit = safexcel_sha3_cra_exit,
++				.cra_module = THIS_MODULE,
++			},
++		},
++	},
++};
++
++static int safexcel_sha3_256_init(struct ahash_request *areq)
++{
++	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++	struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++	struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++	memset(req, 0, sizeof(*req));
++
++	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA3_256;
++	req->digest = CONTEXT_CONTROL_DIGEST_INITIAL;
++	req->state_sz = SHA3_256_DIGEST_SIZE;
++	req->digest_sz = SHA3_256_DIGEST_SIZE;
++	req->block_sz = SHA3_256_BLOCK_SIZE;
++	ctx->do_fallback = false;
++	ctx->fb_init_done = false;
++	return 0;
++}
++
++static int safexcel_sha3_256_digest(struct ahash_request *req)
++{
++	if (req->nbytes)
++		return safexcel_sha3_256_init(req) ?: safexcel_ahash_finup(req);
++
++	/* HW cannot do zero length hash, use fallback instead */
++	return safexcel_sha3_digest_fallback(req);
++}
++
++struct safexcel_alg_template safexcel_alg_sha3_256 = {
++	.type = SAFEXCEL_ALG_TYPE_AHASH,
++	.algo_mask = SAFEXCEL_ALG_SHA3,
++	.alg.ahash = {
++		.init = safexcel_sha3_256_init,
++		.update = safexcel_sha3_update,
++		.final = safexcel_sha3_final,
++		.finup = safexcel_sha3_finup,
++		.digest = safexcel_sha3_256_digest,
++		.export = safexcel_sha3_export,
++		.import = safexcel_sha3_import,
++		.halg = {
++			.digestsize = SHA3_256_DIGEST_SIZE,
++			.statesize = sizeof(struct safexcel_ahash_export_state),
++			.base = {
++				.cra_name = "sha3-256",
++				.cra_driver_name = "safexcel-sha3-256",
++				.cra_priority = SAFEXCEL_CRA_PRIORITY,
++				.cra_flags = CRYPTO_ALG_ASYNC |
++					     CRYPTO_ALG_KERN_DRIVER_ONLY |
++					     CRYPTO_ALG_NEED_FALLBACK,
++				.cra_blocksize = SHA3_256_BLOCK_SIZE,
++				.cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++				.cra_init = safexcel_sha3_cra_init,
++				.cra_exit = safexcel_sha3_cra_exit,
++				.cra_module = THIS_MODULE,
++			},
++		},
++	},
++};
++
++static int safexcel_sha3_384_init(struct ahash_request *areq)
++{
++	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++	struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++	struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++	memset(req, 0, sizeof(*req));
++
++	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA3_384;
++	req->digest = CONTEXT_CONTROL_DIGEST_INITIAL;
++	req->state_sz = SHA3_384_DIGEST_SIZE;
++	req->digest_sz = SHA3_384_DIGEST_SIZE;
++	req->block_sz = SHA3_384_BLOCK_SIZE;
++	ctx->do_fallback = false;
++	ctx->fb_init_done = false;
++	return 0;
++}
++
++static int safexcel_sha3_384_digest(struct ahash_request *req)
++{
++	if (req->nbytes)
++		return safexcel_sha3_384_init(req) ?: safexcel_ahash_finup(req);
++
++	/* HW cannot do zero length hash, use fallback instead */
++	return safexcel_sha3_digest_fallback(req);
++}
++
++struct safexcel_alg_template safexcel_alg_sha3_384 = {
++	.type = SAFEXCEL_ALG_TYPE_AHASH,
++	.algo_mask = SAFEXCEL_ALG_SHA3,
++	.alg.ahash = {
++		.init = safexcel_sha3_384_init,
++		.update = safexcel_sha3_update,
++		.final = safexcel_sha3_final,
++		.finup = safexcel_sha3_finup,
++		.digest = safexcel_sha3_384_digest,
++		.export = safexcel_sha3_export,
++		.import = safexcel_sha3_import,
++		.halg = {
++			.digestsize = SHA3_384_DIGEST_SIZE,
++			.statesize = sizeof(struct safexcel_ahash_export_state),
++			.base = {
++				.cra_name = "sha3-384",
++				.cra_driver_name = "safexcel-sha3-384",
++				.cra_priority = SAFEXCEL_CRA_PRIORITY,
++				.cra_flags = CRYPTO_ALG_ASYNC |
++					     CRYPTO_ALG_KERN_DRIVER_ONLY |
++					     CRYPTO_ALG_NEED_FALLBACK,
++				.cra_blocksize = SHA3_384_BLOCK_SIZE,
++				.cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++				.cra_init = safexcel_sha3_cra_init,
++				.cra_exit = safexcel_sha3_cra_exit,
++				.cra_module = THIS_MODULE,
++			},
++		},
++	},
++};
++
++static int safexcel_sha3_512_init(struct ahash_request *areq)
++{
++	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++	struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++	struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++	memset(req, 0, sizeof(*req));
++
++	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA3_512;
++	req->digest = CONTEXT_CONTROL_DIGEST_INITIAL;
++	req->state_sz = SHA3_512_DIGEST_SIZE;
++	req->digest_sz = SHA3_512_DIGEST_SIZE;
++	req->block_sz = SHA3_512_BLOCK_SIZE;
++	ctx->do_fallback = false;
++	ctx->fb_init_done = false;
++	return 0;
++}
++
++static int safexcel_sha3_512_digest(struct ahash_request *req)
++{
++	if (req->nbytes)
++		return safexcel_sha3_512_init(req) ?: safexcel_ahash_finup(req);
++
++	/* HW cannot do zero length hash, use fallback instead */
++	return safexcel_sha3_digest_fallback(req);
++}
++
++struct safexcel_alg_template safexcel_alg_sha3_512 = {
++	.type = SAFEXCEL_ALG_TYPE_AHASH,
++	.algo_mask = SAFEXCEL_ALG_SHA3,
++	.alg.ahash = {
++		.init = safexcel_sha3_512_init,
++		.update = safexcel_sha3_update,
++		.final = safexcel_sha3_final,
++		.finup = safexcel_sha3_finup,
++		.digest = safexcel_sha3_512_digest,
++		.export = safexcel_sha3_export,
++		.import = safexcel_sha3_import,
++		.halg = {
++			.digestsize = SHA3_512_DIGEST_SIZE,
++			.statesize = sizeof(struct safexcel_ahash_export_state),
++			.base = {
++				.cra_name = "sha3-512",
++				.cra_driver_name = "safexcel-sha3-512",
++				.cra_priority = SAFEXCEL_CRA_PRIORITY,
++				.cra_flags = CRYPTO_ALG_ASYNC |
++					     CRYPTO_ALG_KERN_DRIVER_ONLY |
++					     CRYPTO_ALG_NEED_FALLBACK,
++				.cra_blocksize = SHA3_512_BLOCK_SIZE,
++				.cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++				.cra_init = safexcel_sha3_cra_init,
++				.cra_exit = safexcel_sha3_cra_exit,
++				.cra_module = THIS_MODULE,
++			},
++		},
++	},
++};
++
++static int safexcel_hmac_sha3_cra_init(struct crypto_tfm *tfm, const char *alg)
++{
++	struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(tfm);
++	int ret;
++
++	ret = safexcel_sha3_cra_init(tfm);
++	if (ret)
++		return ret;
++
++	/* Allocate precalc basic digest implementation */
++	ctx->shpre = crypto_alloc_shash(alg, 0, CRYPTO_ALG_NEED_FALLBACK);
++	if (IS_ERR(ctx->shpre))
++		return PTR_ERR(ctx->shpre);
++
++	ctx->shdesc = kmalloc(sizeof(*ctx->shdesc) +
++			      crypto_shash_descsize(ctx->shpre), GFP_KERNEL);
++	if (!ctx->shdesc) {
++		crypto_free_shash(ctx->shpre);
++		return -ENOMEM;
++	}
++	ctx->shdesc->tfm = ctx->shpre;
++	return 0;
++}
++
++static void safexcel_hmac_sha3_cra_exit(struct crypto_tfm *tfm)
++{
++	struct safexcel_ahash_ctx *ctx = crypto_tfm_ctx(tfm);
++
++	crypto_free_ahash(ctx->fback);
++	crypto_free_shash(ctx->shpre);
++	kfree(ctx->shdesc);
++	safexcel_ahash_cra_exit(tfm);
++}
++
++static int safexcel_hmac_sha3_setkey(struct crypto_ahash *tfm, const u8 *key,
++				     unsigned int keylen)
++{
++	struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++	int ret = 0;
++
++	if (keylen > crypto_ahash_blocksize(tfm)) {
++		/*
++		 * If the key is larger than the blocksize, then hash it
++		 * first using our fallback cipher
++		 */
++		ret = crypto_shash_digest(ctx->shdesc, key, keylen,
++					  (u8 *)ctx->ipad);
++		keylen = crypto_shash_digestsize(ctx->shpre);
++
++		/*
++		 * If the digest is larger than half the blocksize, we need to
++		 * move the rest to opad due to the way our HMAC infra works.
++		 */
++		if (keylen > crypto_ahash_blocksize(tfm) / 2)
++			/* Buffers overlap, need to use memmove iso memcpy! */
++			memmove(ctx->opad,
++				(u8 *)ctx->ipad +
++					crypto_ahash_blocksize(tfm) / 2,
++				keylen - crypto_ahash_blocksize(tfm) / 2);
++	} else {
++		/*
++		 * Copy the key to our ipad & opad buffers
++		 * Note that ipad and opad each contain one half of the key,
++		 * to match the existing HMAC driver infrastructure.
++		 */
++		if (keylen <= crypto_ahash_blocksize(tfm) / 2) {
++			memcpy(ctx->ipad, key, keylen);
++		} else {
++			memcpy(ctx->ipad, key,
++			       crypto_ahash_blocksize(tfm) / 2);
++			memcpy(ctx->opad,
++			       key + crypto_ahash_blocksize(tfm) / 2,
++			       keylen - crypto_ahash_blocksize(tfm) / 2);
++		}
++	}
++
++	/* Pad key with zeroes */
++	if (keylen <= crypto_ahash_blocksize(tfm) / 2) {
++		memset((u8 *)ctx->ipad + keylen, 0,
++		       crypto_ahash_blocksize(tfm) / 2 - keylen);
++		memset(ctx->opad, 0, crypto_ahash_blocksize(tfm) / 2);
++	} else {
++		memset((u8 *)ctx->opad + keylen -
++		       crypto_ahash_blocksize(tfm) / 2, 0,
++		       crypto_ahash_blocksize(tfm) - keylen);
++	}
++
++	/* If doing fallback, still need to set the new key! */
++	ctx->fb_do_setkey = true;
++	return ret;
++}
++
++static int safexcel_hmac_sha3_224_init(struct ahash_request *areq)
++{
++	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++	struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++	struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++	memset(req, 0, sizeof(*req));
++
++	/* Copy (half of) the key */
++	memcpy(req->state, ctx->ipad, SHA3_224_BLOCK_SIZE / 2);
++	/* Start of HMAC should have len == processed == blocksize */
++	req->len	= SHA3_224_BLOCK_SIZE;
++	req->processed	= SHA3_224_BLOCK_SIZE;
++	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA3_224;
++	req->digest = CONTEXT_CONTROL_DIGEST_HMAC;
++	req->state_sz = SHA3_224_BLOCK_SIZE / 2;
++	req->digest_sz = SHA3_224_DIGEST_SIZE;
++	req->block_sz = SHA3_224_BLOCK_SIZE;
++	req->hmac = true;
++	ctx->do_fallback = false;
++	ctx->fb_init_done = false;
++	return 0;
++}
++
++static int safexcel_hmac_sha3_224_digest(struct ahash_request *req)
++{
++	if (req->nbytes)
++		return safexcel_hmac_sha3_224_init(req) ?:
++		       safexcel_ahash_finup(req);
++
++	/* HW cannot do zero length HMAC, use fallback instead */
++	return safexcel_sha3_digest_fallback(req);
++}
++
++static int safexcel_hmac_sha3_224_cra_init(struct crypto_tfm *tfm)
++{
++	return safexcel_hmac_sha3_cra_init(tfm, "sha3-224");
++}
++
++struct safexcel_alg_template safexcel_alg_hmac_sha3_224 = {
++	.type = SAFEXCEL_ALG_TYPE_AHASH,
++	.algo_mask = SAFEXCEL_ALG_SHA3,
++	.alg.ahash = {
++		.init = safexcel_hmac_sha3_224_init,
++		.update = safexcel_sha3_update,
++		.final = safexcel_sha3_final,
++		.finup = safexcel_sha3_finup,
++		.digest = safexcel_hmac_sha3_224_digest,
++		.setkey = safexcel_hmac_sha3_setkey,
++		.export = safexcel_sha3_export,
++		.import = safexcel_sha3_import,
++		.halg = {
++			.digestsize = SHA3_224_DIGEST_SIZE,
++			.statesize = sizeof(struct safexcel_ahash_export_state),
++			.base = {
++				.cra_name = "hmac(sha3-224)",
++				.cra_driver_name = "safexcel-hmac-sha3-224",
++				.cra_priority = SAFEXCEL_CRA_PRIORITY,
++				.cra_flags = CRYPTO_ALG_ASYNC |
++					     CRYPTO_ALG_KERN_DRIVER_ONLY |
++					     CRYPTO_ALG_NEED_FALLBACK,
++				.cra_blocksize = SHA3_224_BLOCK_SIZE,
++				.cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++				.cra_init = safexcel_hmac_sha3_224_cra_init,
++				.cra_exit = safexcel_hmac_sha3_cra_exit,
++				.cra_module = THIS_MODULE,
++			},
++		},
++	},
++};
++
++static int safexcel_hmac_sha3_256_init(struct ahash_request *areq)
++{
++	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++	struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++	struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++	memset(req, 0, sizeof(*req));
++
++	/* Copy (half of) the key */
++	memcpy(req->state, ctx->ipad, SHA3_256_BLOCK_SIZE / 2);
++	/* Start of HMAC should have len == processed == blocksize */
++	req->len	= SHA3_256_BLOCK_SIZE;
++	req->processed	= SHA3_256_BLOCK_SIZE;
++	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA3_256;
++	req->digest = CONTEXT_CONTROL_DIGEST_HMAC;
++	req->state_sz = SHA3_256_BLOCK_SIZE / 2;
++	req->digest_sz = SHA3_256_DIGEST_SIZE;
++	req->block_sz = SHA3_256_BLOCK_SIZE;
++	req->hmac = true;
++	ctx->do_fallback = false;
++	ctx->fb_init_done = false;
++	return 0;
++}
++
++static int safexcel_hmac_sha3_256_digest(struct ahash_request *req)
++{
++	if (req->nbytes)
++		return safexcel_hmac_sha3_256_init(req) ?:
++		       safexcel_ahash_finup(req);
++
++	/* HW cannot do zero length HMAC, use fallback instead */
++	return safexcel_sha3_digest_fallback(req);
++}
++
++static int safexcel_hmac_sha3_256_cra_init(struct crypto_tfm *tfm)
++{
++	return safexcel_hmac_sha3_cra_init(tfm, "sha3-256");
++}
++
++struct safexcel_alg_template safexcel_alg_hmac_sha3_256 = {
++	.type = SAFEXCEL_ALG_TYPE_AHASH,
++	.algo_mask = SAFEXCEL_ALG_SHA3,
++	.alg.ahash = {
++		.init = safexcel_hmac_sha3_256_init,
++		.update = safexcel_sha3_update,
++		.final = safexcel_sha3_final,
++		.finup = safexcel_sha3_finup,
++		.digest = safexcel_hmac_sha3_256_digest,
++		.setkey = safexcel_hmac_sha3_setkey,
++		.export = safexcel_sha3_export,
++		.import = safexcel_sha3_import,
++		.halg = {
++			.digestsize = SHA3_256_DIGEST_SIZE,
++			.statesize = sizeof(struct safexcel_ahash_export_state),
++			.base = {
++				.cra_name = "hmac(sha3-256)",
++				.cra_driver_name = "safexcel-hmac-sha3-256",
++				.cra_priority = SAFEXCEL_CRA_PRIORITY,
++				.cra_flags = CRYPTO_ALG_ASYNC |
++					     CRYPTO_ALG_KERN_DRIVER_ONLY |
++					     CRYPTO_ALG_NEED_FALLBACK,
++				.cra_blocksize = SHA3_256_BLOCK_SIZE,
++				.cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++				.cra_init = safexcel_hmac_sha3_256_cra_init,
++				.cra_exit = safexcel_hmac_sha3_cra_exit,
++				.cra_module = THIS_MODULE,
++			},
++		},
++	},
++};
++
++static int safexcel_hmac_sha3_384_init(struct ahash_request *areq)
++{
++	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++	struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++	struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++	memset(req, 0, sizeof(*req));
++
++	/* Copy (half of) the key */
++	memcpy(req->state, ctx->ipad, SHA3_384_BLOCK_SIZE / 2);
++	/* Start of HMAC should have len == processed == blocksize */
++	req->len	= SHA3_384_BLOCK_SIZE;
++	req->processed	= SHA3_384_BLOCK_SIZE;
++	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA3_384;
++	req->digest = CONTEXT_CONTROL_DIGEST_HMAC;
++	req->state_sz = SHA3_384_BLOCK_SIZE / 2;
++	req->digest_sz = SHA3_384_DIGEST_SIZE;
++	req->block_sz = SHA3_384_BLOCK_SIZE;
++	req->hmac = true;
++	ctx->do_fallback = false;
++	ctx->fb_init_done = false;
++	return 0;
++}
++
++static int safexcel_hmac_sha3_384_digest(struct ahash_request *req)
++{
++	if (req->nbytes)
++		return safexcel_hmac_sha3_384_init(req) ?:
++		       safexcel_ahash_finup(req);
++
++	/* HW cannot do zero length HMAC, use fallback instead */
++	return safexcel_sha3_digest_fallback(req);
++}
++
++static int safexcel_hmac_sha3_384_cra_init(struct crypto_tfm *tfm)
++{
++	return safexcel_hmac_sha3_cra_init(tfm, "sha3-384");
++}
++
++struct safexcel_alg_template safexcel_alg_hmac_sha3_384 = {
++	.type = SAFEXCEL_ALG_TYPE_AHASH,
++	.algo_mask = SAFEXCEL_ALG_SHA3,
++	.alg.ahash = {
++		.init = safexcel_hmac_sha3_384_init,
++		.update = safexcel_sha3_update,
++		.final = safexcel_sha3_final,
++		.finup = safexcel_sha3_finup,
++		.digest = safexcel_hmac_sha3_384_digest,
++		.setkey = safexcel_hmac_sha3_setkey,
++		.export = safexcel_sha3_export,
++		.import = safexcel_sha3_import,
++		.halg = {
++			.digestsize = SHA3_384_DIGEST_SIZE,
++			.statesize = sizeof(struct safexcel_ahash_export_state),
++			.base = {
++				.cra_name = "hmac(sha3-384)",
++				.cra_driver_name = "safexcel-hmac-sha3-384",
++				.cra_priority = SAFEXCEL_CRA_PRIORITY,
++				.cra_flags = CRYPTO_ALG_ASYNC |
++					     CRYPTO_ALG_KERN_DRIVER_ONLY |
++					     CRYPTO_ALG_NEED_FALLBACK,
++				.cra_blocksize = SHA3_384_BLOCK_SIZE,
++				.cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++				.cra_init = safexcel_hmac_sha3_384_cra_init,
++				.cra_exit = safexcel_hmac_sha3_cra_exit,
++				.cra_module = THIS_MODULE,
++			},
++		},
++	},
++};
++
++static int safexcel_hmac_sha3_512_init(struct ahash_request *areq)
++{
++	struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++	struct safexcel_ahash_ctx *ctx = crypto_ahash_ctx(tfm);
++	struct safexcel_ahash_req *req = ahash_request_ctx(areq);
++
++	memset(req, 0, sizeof(*req));
++
++	/* Copy (half of) the key */
++	memcpy(req->state, ctx->ipad, SHA3_512_BLOCK_SIZE / 2);
++	/* Start of HMAC should have len == processed == blocksize */
++	req->len	= SHA3_512_BLOCK_SIZE;
++	req->processed	= SHA3_512_BLOCK_SIZE;
++	ctx->alg = CONTEXT_CONTROL_CRYPTO_ALG_SHA3_512;
++	req->digest = CONTEXT_CONTROL_DIGEST_HMAC;
++	req->state_sz = SHA3_512_BLOCK_SIZE / 2;
++	req->digest_sz = SHA3_512_DIGEST_SIZE;
++	req->block_sz = SHA3_512_BLOCK_SIZE;
++	req->hmac = true;
++	ctx->do_fallback = false;
++	ctx->fb_init_done = false;
++	return 0;
++}
++
++static int safexcel_hmac_sha3_512_digest(struct ahash_request *req)
++{
++	if (req->nbytes)
++		return safexcel_hmac_sha3_512_init(req) ?:
++		       safexcel_ahash_finup(req);
++
++	/* HW cannot do zero length HMAC, use fallback instead */
++	return safexcel_sha3_digest_fallback(req);
++}
++
++static int safexcel_hmac_sha3_512_cra_init(struct crypto_tfm *tfm)
++{
++	return safexcel_hmac_sha3_cra_init(tfm, "sha3-512");
++}
++struct safexcel_alg_template safexcel_alg_hmac_sha3_512 = {
++	.type = SAFEXCEL_ALG_TYPE_AHASH,
++	.algo_mask = SAFEXCEL_ALG_SHA3,
++	.alg.ahash = {
++		.init = safexcel_hmac_sha3_512_init,
++		.update = safexcel_sha3_update,
++		.final = safexcel_sha3_final,
++		.finup = safexcel_sha3_finup,
++		.digest = safexcel_hmac_sha3_512_digest,
++		.setkey = safexcel_hmac_sha3_setkey,
++		.export = safexcel_sha3_export,
++		.import = safexcel_sha3_import,
++		.halg = {
++			.digestsize = SHA3_512_DIGEST_SIZE,
++			.statesize = sizeof(struct safexcel_ahash_export_state),
++			.base = {
++				.cra_name = "hmac(sha3-512)",
++				.cra_driver_name = "safexcel-hmac-sha3-512",
++				.cra_priority = SAFEXCEL_CRA_PRIORITY,
++				.cra_flags = CRYPTO_ALG_ASYNC |
++					     CRYPTO_ALG_KERN_DRIVER_ONLY |
++					     CRYPTO_ALG_NEED_FALLBACK,
++				.cra_blocksize = SHA3_512_BLOCK_SIZE,
++				.cra_ctxsize = sizeof(struct safexcel_ahash_ctx),
++				.cra_init = safexcel_hmac_sha3_512_cra_init,
++				.cra_exit = safexcel_hmac_sha3_cra_exit,
++				.cra_module = THIS_MODULE,
++			},
++		},
+ 	},
+ };
+--- a/drivers/crypto/inside-secure/safexcel_ring.c
++++ b/drivers/crypto/inside-secure/safexcel_ring.c
+@@ -14,7 +14,12 @@ int safexcel_init_ring_descriptors(struc
+ 				   struct safexcel_desc_ring *cdr,
+ 				   struct safexcel_desc_ring *rdr)
+ {
+-	cdr->offset = sizeof(u32) * priv->config.cd_offset;
++	int i;
++	struct safexcel_command_desc *cdesc;
++	dma_addr_t atok;
++
++	/* Actual command descriptor ring */
++	cdr->offset = priv->config.cd_offset;
+ 	cdr->base = dmam_alloc_coherent(priv->dev,
+ 					cdr->offset * EIP197_DEFAULT_RING_SIZE,
+ 					&cdr->base_dma, GFP_KERNEL);
+@@ -24,7 +29,34 @@ int safexcel_init_ring_descriptors(struc
+ 	cdr->base_end = cdr->base + cdr->offset * (EIP197_DEFAULT_RING_SIZE - 1);
+ 	cdr->read = cdr->base;
+ 
+-	rdr->offset = sizeof(u32) * priv->config.rd_offset;
++	/* Command descriptor shadow ring for storing additional token data */
++	cdr->shoffset = priv->config.cdsh_offset;
++	cdr->shbase = dmam_alloc_coherent(priv->dev,
++					  cdr->shoffset *
++					  EIP197_DEFAULT_RING_SIZE,
++					  &cdr->shbase_dma, GFP_KERNEL);
++	if (!cdr->shbase)
++		return -ENOMEM;
++	cdr->shwrite = cdr->shbase;
++	cdr->shbase_end = cdr->shbase + cdr->shoffset *
++					(EIP197_DEFAULT_RING_SIZE - 1);
++
++	/*
++	 * Populate command descriptors with physical pointers to shadow descs.
++	 * Note that we only need to do this once if we don't overwrite them.
++	 */
++	cdesc = cdr->base;
++	atok = cdr->shbase_dma;
++	for (i = 0; i < EIP197_DEFAULT_RING_SIZE; i++) {
++		cdesc->atok_lo = lower_32_bits(atok);
++		cdesc->atok_hi = upper_32_bits(atok);
++		cdesc = (void *)cdesc + cdr->offset;
++		atok += cdr->shoffset;
++	}
++
++	rdr->offset = priv->config.rd_offset;
++	/* Use shoffset for result token offset here */
++	rdr->shoffset = priv->config.res_offset;
+ 	rdr->base = dmam_alloc_coherent(priv->dev,
+ 					rdr->offset * EIP197_DEFAULT_RING_SIZE,
+ 					&rdr->base_dma, GFP_KERNEL);
+@@ -42,11 +74,40 @@ inline int safexcel_select_ring(struct s
+ 	return (atomic_inc_return(&priv->ring_used) % priv->config.rings);
+ }
+ 
+-static void *safexcel_ring_next_wptr(struct safexcel_crypto_priv *priv,
+-				     struct safexcel_desc_ring *ring)
++static void *safexcel_ring_next_cwptr(struct safexcel_crypto_priv *priv,
++				     struct safexcel_desc_ring *ring,
++				     bool first,
++				     struct safexcel_token **atoken)
+ {
+ 	void *ptr = ring->write;
+ 
++	if (first)
++		*atoken = ring->shwrite;
++
++	if ((ring->write == ring->read - ring->offset) ||
++	    (ring->read == ring->base && ring->write == ring->base_end))
++		return ERR_PTR(-ENOMEM);
++
++	if (ring->write == ring->base_end) {
++		ring->write = ring->base;
++		ring->shwrite = ring->shbase;
++	} else {
++		ring->write += ring->offset;
++		ring->shwrite += ring->shoffset;
++	}
++
++	return ptr;
++}
++
++static void *safexcel_ring_next_rwptr(struct safexcel_crypto_priv *priv,
++				     struct safexcel_desc_ring *ring,
++				     struct result_data_desc **rtoken)
++{
++	void *ptr = ring->write;
++
++	/* Result token at relative offset shoffset */
++	*rtoken = ring->write + ring->shoffset;
++
+ 	if ((ring->write == ring->read - ring->offset) ||
+ 	    (ring->read == ring->base && ring->write == ring->base_end))
+ 		return ERR_PTR(-ENOMEM);
+@@ -106,10 +167,13 @@ void safexcel_ring_rollback_wptr(struct
+ 	if (ring->write == ring->read)
+ 		return;
+ 
+-	if (ring->write == ring->base)
++	if (ring->write == ring->base) {
+ 		ring->write = ring->base_end;
+-	else
++		ring->shwrite = ring->shbase_end;
++	} else {
+ 		ring->write -= ring->offset;
++		ring->shwrite -= ring->shoffset;
++	}
+ }
+ 
+ struct safexcel_command_desc *safexcel_add_cdesc(struct safexcel_crypto_priv *priv,
+@@ -117,26 +181,26 @@ struct safexcel_command_desc *safexcel_a
+ 						 bool first, bool last,
+ 						 dma_addr_t data, u32 data_len,
+ 						 u32 full_data_len,
+-						 dma_addr_t context) {
++						 dma_addr_t context,
++						 struct safexcel_token **atoken)
++{
+ 	struct safexcel_command_desc *cdesc;
+-	int i;
+ 
+-	cdesc = safexcel_ring_next_wptr(priv, &priv->ring[ring_id].cdr);
++	cdesc = safexcel_ring_next_cwptr(priv, &priv->ring[ring_id].cdr,
++					 first, atoken);
+ 	if (IS_ERR(cdesc))
+ 		return cdesc;
+ 
+-	memset(cdesc, 0, sizeof(struct safexcel_command_desc));
+-
+-	cdesc->first_seg = first;
+-	cdesc->last_seg = last;
+ 	cdesc->particle_size = data_len;
++	cdesc->rsvd0 = 0;
++	cdesc->last_seg = last;
++	cdesc->first_seg = first;
++	cdesc->additional_cdata_size = 0;
++	cdesc->rsvd1 = 0;
+ 	cdesc->data_lo = lower_32_bits(data);
+ 	cdesc->data_hi = upper_32_bits(data);
+ 
+-	if (first && context) {
+-		struct safexcel_token *token =
+-			(struct safexcel_token *)cdesc->control_data.token;
+-
++	if (first) {
+ 		/*
+ 		 * Note that the length here MUST be >0 or else the EIP(1)97
+ 		 * may hang. Newer EIP197 firmware actually incorporates this
+@@ -146,20 +210,12 @@ struct safexcel_command_desc *safexcel_a
+ 		cdesc->control_data.packet_length = full_data_len ?: 1;
+ 		cdesc->control_data.options = EIP197_OPTION_MAGIC_VALUE |
+ 					      EIP197_OPTION_64BIT_CTX |
+-					      EIP197_OPTION_CTX_CTRL_IN_CMD;
+-		cdesc->control_data.context_lo =
+-			(lower_32_bits(context) & GENMASK(31, 2)) >> 2;
++					      EIP197_OPTION_CTX_CTRL_IN_CMD |
++					      EIP197_OPTION_RC_AUTO;
++		cdesc->control_data.type = EIP197_TYPE_BCLA;
++		cdesc->control_data.context_lo = lower_32_bits(context) |
++						 EIP197_CONTEXT_SMALL;
+ 		cdesc->control_data.context_hi = upper_32_bits(context);
+-
+-		if (priv->version == EIP197B_MRVL ||
+-		    priv->version == EIP197D_MRVL)
+-			cdesc->control_data.options |= EIP197_OPTION_RC_AUTO;
+-
+-		/* TODO: large xform HMAC with SHA-384/512 uses refresh = 3 */
+-		cdesc->control_data.refresh = 2;
+-
+-		for (i = 0; i < EIP197_MAX_TOKENS; i++)
+-			eip197_noop_token(&token[i]);
+ 	}
+ 
+ 	return cdesc;
+@@ -171,18 +227,27 @@ struct safexcel_result_desc *safexcel_ad
+ 						dma_addr_t data, u32 len)
+ {
+ 	struct safexcel_result_desc *rdesc;
++	struct result_data_desc *rtoken;
+ 
+-	rdesc = safexcel_ring_next_wptr(priv, &priv->ring[ring_id].rdr);
++	rdesc = safexcel_ring_next_rwptr(priv, &priv->ring[ring_id].rdr,
++					 &rtoken);
+ 	if (IS_ERR(rdesc))
+ 		return rdesc;
+ 
+-	memset(rdesc, 0, sizeof(struct safexcel_result_desc));
+-
+-	rdesc->first_seg = first;
+-	rdesc->last_seg = last;
+ 	rdesc->particle_size = len;
++	rdesc->rsvd0 = 0;
++	rdesc->descriptor_overflow = 0;
++	rdesc->buffer_overflow = 0;
++	rdesc->last_seg = last;
++	rdesc->first_seg = first;
++	rdesc->result_size = EIP197_RD64_RESULT_SIZE;
++	rdesc->rsvd1 = 0;
+ 	rdesc->data_lo = lower_32_bits(data);
+ 	rdesc->data_hi = upper_32_bits(data);
+ 
++	/* Clear length & error code in result token */
++	rtoken->packet_length = 0;
++	rtoken->error_code = 0;
++
+ 	return rdesc;
+ }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0501-crypto-add-eip97-inside-secure-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0501-crypto-add-eip97-inside-secure-support.patch
new file mode 100644
index 0000000..3eda4f2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0501-crypto-add-eip97-inside-secure-support.patch
@@ -0,0 +1,27 @@
+--- a/drivers/crypto/inside-secure/safexcel.c
++++ b/drivers/crypto/inside-secure/safexcel.c
+@@ -595,6 +595,14 @@ static int safexcel_hw_init(struct safex
+ 		val |= EIP197_MST_CTRL_TX_MAX_CMD(5);
+ 		writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL);
+ 	}
++	/*
++	 * Set maximum number of TX commands to 2^4 = 16 for EIP97 HW2.1/HW2.3
++	 */
++	else {
++		val = 0;
++		val |= EIP97_MST_CTRL_TX_MAX_CMD(4);
++		writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL);
++	}
+ 
+ 	/* Configure wr/rd cache values */
+ 	writel(EIP197_MST_CTRL_RD_CACHE(RD_CACHE_4BITS) |
+--- a/drivers/crypto/inside-secure/safexcel.h
++++ b/drivers/crypto/inside-secure/safexcel.h
+@@ -306,6 +306,7 @@
+ #define EIP197_MST_CTRL_RD_CACHE(n)		(((n) & 0xf) << 0)
+ #define EIP197_MST_CTRL_WD_CACHE(n)		(((n) & 0xf) << 4)
+ #define EIP197_MST_CTRL_TX_MAX_CMD(n)		(((n) & 0xf) << 20)
++#define EIP97_MST_CTRL_TX_MAX_CMD(n)		(((n) & 0xf) << 4)
+ #define EIP197_MST_CTRL_BYTE_SWAP		BIT(24)
+ #define EIP197_MST_CTRL_NO_BYTE_SWAP		BIT(25)
+ #define EIP197_MST_CTRL_BYTE_SWAP_BITS          GENMASK(25, 24)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0502-dts-mt7623-eip97-inside-secure-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0502-dts-mt7623-eip97-inside-secure-support.patch
new file mode 100644
index 0000000..06077fb
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0502-dts-mt7623-eip97-inside-secure-support.patch
@@ -0,0 +1,23 @@
+--- a/arch/arm/boot/dts/mt7623.dtsi
++++ b/arch/arm/boot/dts/mt7623.dtsi
+@@ -1047,17 +1047,14 @@
+ 	};
+ 
+ 	crypto: crypto@1b240000 {
+-		compatible = "mediatek,eip97-crypto";
++		compatible = "inside-secure,safexcel-eip97";
+ 		reg = <0 0x1b240000 0 0x20000>;
+ 		interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_LOW>,
+ 			     <GIC_SPI 83 IRQ_TYPE_LEVEL_LOW>,
+ 			     <GIC_SPI 84 IRQ_TYPE_LEVEL_LOW>,
+-			     <GIC_SPI 91 IRQ_TYPE_LEVEL_LOW>,
+-			     <GIC_SPI 97 IRQ_TYPE_LEVEL_LOW>;
++			     <GIC_SPI 91 IRQ_TYPE_LEVEL_LOW>;
++		interrupt-names = "ring0", "ring1", "ring2", "ring3";
+ 		clocks = <&ethsys CLK_ETHSYS_CRYPTO>;
+-		clock-names = "cryp";
+-		power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>;
+-		status = "disabled";
+ 	};
+ 
+ 	bdpsys: syscon@1c000000 {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0503-crypto-fix-eip97-cache-incoherent.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0503-crypto-fix-eip97-cache-incoherent.patch
new file mode 100644
index 0000000..5bc0fd0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0503-crypto-fix-eip97-cache-incoherent.patch
@@ -0,0 +1,26 @@
+--- a/drivers/crypto/inside-secure/safexcel.h
++++ b/drivers/crypto/inside-secure/safexcel.h
+@@ -722,6 +722,9 @@ enum safexcel_eip_version {
+ /* Priority we use for advertising our algorithms */
+ #define SAFEXCEL_CRA_PRIORITY		300
+ 
++/* System cache line size */
++#define SYSTEM_CACHELINE_SIZE		64
++
+ /* SM3 digest result for zero length message */
+ #define EIP197_SM3_ZEROM_HASH	"\x1A\xB2\x1D\x83\x55\xCF\xA1\x7F" \
+ 				"\x8E\x61\x19\x48\x31\xE8\x1A\x8F" \
+--- a/drivers/crypto/inside-secure/safexcel_hash.c
++++ b/drivers/crypto/inside-secure/safexcel_hash.c
+@@ -57,9 +57,9 @@ struct safexcel_ahash_req {
+ 	u8 block_sz;    /* block size, only set once */
+ 	u8 digest_sz;   /* output digest size, only set once */
+ 	__le32 state[SHA3_512_BLOCK_SIZE /
+-		     sizeof(__le32)] __aligned(sizeof(__le32));
++		     sizeof(__le32)] __aligned(SYSTEM_CACHELINE_SIZE);
+ 
+-	u64 len;
++	u64 len __aligned(SYSTEM_CACHELINE_SIZE);
+ 	u64 processed;
+ 
+ 	u8 cache[HASH_CACHE_SIZE] __aligned(sizeof(u32));
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0504-macsec-revert-async-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0504-macsec-revert-async-support.patch
new file mode 100644
index 0000000..d52db50
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0504-macsec-revert-async-support.patch
@@ -0,0 +1,12 @@
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -1309,8 +1309,7 @@
+ 	struct crypto_aead *tfm;
+ 	int ret;
+ 
+-	/* Pick a sync gcm(aes) cipher to ensure order is preserved. */
+-	tfm = crypto_alloc_aead("gcm(aes)", 0, CRYPTO_ALG_ASYNC);
++	tfm = crypto_alloc_aead("gcm(aes)", 0, 0);
+ 
+ 	if (IS_ERR(tfm))
+ 		return tfm;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0600-net-phylink-propagate-resolved-link-config-via-mac_l.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0600-net-phylink-propagate-resolved-link-config-via-mac_l.patch
new file mode 100644
index 0000000..a49b921
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0600-net-phylink-propagate-resolved-link-config-via-mac_l.patch
@@ -0,0 +1,230 @@
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Wed, 26 Feb 2020 10:23:41 +0000
+Subject: [PATCH] net: phylink: propagate resolved link config via
+ mac_link_up()
+
+Propagate the resolved link parameters via the mac_link_up() call for
+MACs that do not automatically track their PCS state. We propagate the
+link parameters via function arguments so that inappropriate members
+of struct phylink_link_state can't be accessed, and creating a new
+structure just for this adds needless complexity to the API.
+
+Tested-by: Andre Przywara <andre.przywara@arm.com>
+Tested-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Tested-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/Documentation/networking/sfp-phylink.rst
++++ b/Documentation/networking/sfp-phylink.rst
+@@ -74,10 +74,13 @@ phylib to the sfp/phylink support.  Plea
+ this documentation.
+ 
+ 1. Optionally split the network driver's phylib update function into
+-   three parts dealing with link-down, link-up and reconfiguring the
+-   MAC settings. This can be done as a separate preparation commit.
++   two parts dealing with link-down and link-up. This can be done as
++   a separate preparation commit.
+ 
+-   An example of this preparation can be found in git commit fc548b991fb0.
++   An older example of this preparation can be found in git commit
++   fc548b991fb0, although this was splitting into three parts; the
++   link-up part now includes configuring the MAC for the link settings.
++   Please see :c:func:`mac_link_up` for more information on this.
+ 
+ 2. Replace::
+ 
+@@ -207,6 +210,14 @@ this documentation.
+    using. This is particularly important for in-band negotiation
+    methods such as 1000base-X and SGMII.
+ 
++   The :c:func:`mac_link_up` method is used to inform the MAC that the
++   link has come up. The call includes the negotiation mode and interface
++   for reference only. The finalised link parameters are also supplied
++   (speed, duplex and flow control/pause enablement settings) which
++   should be used to configure the MAC when the MAC and PCS are not
++   tightly integrated, or when the settings are not coming from in-band
++   negotiation.
++
+    The :c:func:`mac_config` method is used to update the MAC with the
+    requested state, and must avoid unnecessarily taking the link down
+    when making changes to the MAC configuration.  This means the
+--- a/drivers/net/ethernet/marvell/mvneta.c
++++ b/drivers/net/ethernet/marvell/mvneta.c
+@@ -3655,9 +3655,11 @@ static void mvneta_mac_link_down(struct
+ 	mvneta_set_eee(pp, false);
+ }
+ 
+-static void mvneta_mac_link_up(struct phylink_config *config, unsigned int mode,
+-			       phy_interface_t interface,
+-			       struct phy_device *phy)
++static void mvneta_mac_link_up(struct phylink_config *config,
++			       struct phy_device *phy,
++			       unsigned int mode, phy_interface_t interface,
++			       int speed, int duplex,
++			       bool tx_pause, bool rx_pause)
+ {
+ 	struct net_device *ndev = to_net_dev(config->dev);
+ 	struct mvneta_port *pp = netdev_priv(ndev);
+--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+@@ -58,8 +58,11 @@ static struct {
+  */
+ static void mvpp2_mac_config(struct phylink_config *config, unsigned int mode,
+ 			     const struct phylink_link_state *state);
+-static void mvpp2_mac_link_up(struct phylink_config *config, unsigned int mode,
+-			      phy_interface_t interface, struct phy_device *phy);
++static void mvpp2_mac_link_up(struct phylink_config *config,
++			      struct phy_device *phy,
++			      unsigned int mode, phy_interface_t interface,
++			      int speed, int duplex,
++			      bool tx_pause, bool rx_pause);
+ 
+ /* Queue modes */
+ #define MVPP2_QDIST_SINGLE_MODE	0
+@@ -3468,8 +3471,9 @@ static void mvpp2_start_dev(struct mvpp2
+ 			.interface = port->phy_interface,
+ 		};
+ 		mvpp2_mac_config(&port->phylink_config, MLO_AN_INBAND, &state);
+-		mvpp2_mac_link_up(&port->phylink_config, MLO_AN_INBAND,
+-				  port->phy_interface, NULL);
++		mvpp2_mac_link_up(&port->phylink_config, NULL,
++				  MLO_AN_INBAND, port->phy_interface,
++				  SPEED_UNKNOWN, DUPLEX_UNKNOWN, false, false);
+ 	}
+ 
+ 	netif_tx_start_all_queues(port->dev);
+@@ -5125,8 +5129,11 @@ static void mvpp2_mac_config(struct phyl
+ 	mvpp2_port_enable(port);
+ }
+ 
+-static void mvpp2_mac_link_up(struct phylink_config *config, unsigned int mode,
+-			      phy_interface_t interface, struct phy_device *phy)
++static void mvpp2_mac_link_up(struct phylink_config *config,
++			      struct phy_device *phy,
++			      unsigned int mode, phy_interface_t interface,
++			      int speed, int duplex,
++			      bool tx_pause, bool rx_pause)
+ {
+ 	struct mvpp2_port *port = mvpp2_phylink_to_port(config);
+ 	u32 val;
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -925,8 +925,10 @@ static void stmmac_mac_link_down(struct
+ }
+ 
+ static void stmmac_mac_link_up(struct phylink_config *config,
++			       struct phy_device *phy,
+ 			       unsigned int mode, phy_interface_t interface,
+-			       struct phy_device *phy)
++			       int speed, int duplex,
++			       bool tx_pause, bool rx_pause)
+ {
+ 	struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
+ 
+--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
++++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+@@ -1501,9 +1501,10 @@ static void axienet_mac_link_down(struct
+ }
+ 
+ static void axienet_mac_link_up(struct phylink_config *config,
+-				unsigned int mode,
+-				phy_interface_t interface,
+-				struct phy_device *phy)
++				struct phy_device *phy,
++				unsigned int mode, phy_interface_t interface,
++				int speed, int duplex,
++				bool tx_pause, bool rx_pause)
+ {
+ 	/* nothing meaningful to do */
+ }
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -447,8 +447,11 @@ static void phylink_mac_link_up(struct p
+ 	struct net_device *ndev = pl->netdev;
+ 
+ 	pl->cur_interface = link_state.interface;
+-	pl->ops->mac_link_up(pl->config, pl->cur_link_an_mode,
+-			     pl->cur_interface, pl->phydev);
++	pl->ops->mac_link_up(pl->config, pl->phydev,
++			     pl->cur_link_an_mode, pl->cur_interface,
++			     link_state.speed, link_state.duplex,
++			     !!(link_state.pause & MLO_PAUSE_TX),
++			     !!(link_state.pause & MLO_PAUSE_RX));
+ 
+ 	if (ndev)
+ 		netif_carrier_on(ndev);
+--- a/include/linux/phylink.h
++++ b/include/linux/phylink.h
+@@ -91,9 +91,10 @@ struct phylink_mac_ops {
+ 	void (*mac_an_restart)(struct phylink_config *config);
+ 	void (*mac_link_down)(struct phylink_config *config, unsigned int mode,
+ 			      phy_interface_t interface);
+-	void (*mac_link_up)(struct phylink_config *config, unsigned int mode,
+-			    phy_interface_t interface,
+-			    struct phy_device *phy);
++	void (*mac_link_up)(struct phylink_config *config,
++			    struct phy_device *phy, unsigned int mode,
++			    phy_interface_t interface, int speed, int duplex,
++			    bool tx_pause, bool rx_pause);
+ };
+ 
+ #if 0 /* For kernel-doc purposes only. */
+@@ -217,19 +218,34 @@ void mac_link_down(struct phylink_config
+ /**
+  * mac_link_up() - allow the link to come up
+  * @config: a pointer to a &struct phylink_config.
++ * @phy: any attached phy
+  * @mode: link autonegotiation mode
+  * @interface: link &typedef phy_interface_t mode
+- * @phy: any attached phy
++ * @speed: link speed
++ * @duplex: link duplex
++ * @tx_pause: link transmit pause enablement status
++ * @rx_pause: link receive pause enablement status
++ *
++ * Configure the MAC for an established link.
++ *
++ * @speed, @duplex, @tx_pause and @rx_pause indicate the finalised link
++ * settings, and should be used to configure the MAC block appropriately
++ * where these settings are not automatically conveyed from the PCS block,
++ * or if in-band negotiation (as defined by phylink_autoneg_inband(@mode))
++ * is disabled.
++ *
++ * Note that when 802.3z in-band negotiation is in use, it is possible
++ * that the user wishes to override the pause settings, and this should
++ * be allowed when considering the implementation of this method.
+  *
+- * If @mode is not an in-band negotiation mode (as defined by
+- * phylink_autoneg_inband()), allow the link to come up. If @phy
+- * is non-%NULL, configure Energy Efficient Ethernet by calling
++ * If in-band negotiation mode is disabled, allow the link to come up. If
++ * @phy is non-%NULL, configure Energy Efficient Ethernet by calling
+  * phy_init_eee() and perform appropriate MAC configuration for EEE.
+  * Interface type selection must be done in mac_config().
+  */
+-void mac_link_up(struct phylink_config *config, unsigned int mode,
+-		 phy_interface_t interface,
+-		 struct phy_device *phy);
++void mac_link_up(struct phylink_config *config, struct phy_device *phy,
++		 unsigned int mode, phy_interface_t interface,
++		 int speed, int duplex, bool tx_pause, bool rx_pause);
+ #endif
+ 
+ struct phylink *phylink_create(struct phylink_config *, struct fwnode_handle *,
+--- a/net/dsa/port.c
++++ b/net/dsa/port.c
+@@ -529,9 +529,11 @@ void dsa_port_phylink_mac_link_down(stru
+ EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_link_down);
+ 
+ void dsa_port_phylink_mac_link_up(struct phylink_config *config,
++				  struct phy_device *phydev,
+ 				  unsigned int mode,
+ 				  phy_interface_t interface,
+-				  struct phy_device *phydev)
++				  int speed, int duplex,
++				  bool tx_pause, bool rx_pause)
+ {
+ 	struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
+ 	struct dsa_switch *ds = dp->ds;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0601-net-dsa-propagate-resolved-link-config-via-mac_link_.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0601-net-dsa-propagate-resolved-link-config-via-mac_link_.patch
new file mode 100644
index 0000000..ee5a52e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0601-net-dsa-propagate-resolved-link-config-via-mac_link_.patch
@@ -0,0 +1,143 @@
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Wed, 26 Feb 2020 10:23:46 +0000
+Subject: [PATCH] net: dsa: propagate resolved link config via mac_link_up()
+
+Propagate the resolved link configuration down via DSA's
+phylink_mac_link_up() operation to allow split PCS/MAC to work.
+
+Tested-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -1284,7 +1284,9 @@ EXPORT_SYMBOL(b53_phylink_mac_link_down)
+ void b53_phylink_mac_link_up(struct dsa_switch *ds, int port,
+ 			     unsigned int mode,
+ 			     phy_interface_t interface,
+-			     struct phy_device *phydev)
++			     struct phy_device *phydev,
++			     int speed, int duplex,
++			     bool tx_pause, bool rx_pause)
+ {
+ 	struct b53_device *dev = ds->priv;
+ 
+--- a/drivers/net/dsa/b53/b53_priv.h
++++ b/drivers/net/dsa/b53/b53_priv.h
+@@ -337,7 +337,9 @@ void b53_phylink_mac_link_down(struct ds
+ void b53_phylink_mac_link_up(struct dsa_switch *ds, int port,
+ 			     unsigned int mode,
+ 			     phy_interface_t interface,
+-			     struct phy_device *phydev);
++			     struct phy_device *phydev,
++			     int speed, int duplex,
++			     bool tx_pause, bool rx_pause);
+ int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering);
+ int b53_vlan_prepare(struct dsa_switch *ds, int port,
+ 		     const struct switchdev_obj_port_vlan *vlan);
+--- a/drivers/net/dsa/bcm_sf2.c
++++ b/drivers/net/dsa/bcm_sf2.c
+@@ -636,7 +636,9 @@ static void bcm_sf2_sw_mac_link_down(str
+ static void bcm_sf2_sw_mac_link_up(struct dsa_switch *ds, int port,
+ 				   unsigned int mode,
+ 				   phy_interface_t interface,
+-				   struct phy_device *phydev)
++				   struct phy_device *phydev,
++				   int speed, int duplex,
++				   bool tx_pause, bool rx_pause)
+ {
+ 	struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
+ 	struct ethtool_eee *p = &priv->dev->ports[port].eee;
+--- a/drivers/net/dsa/lantiq_gswip.c
++++ b/drivers/net/dsa/lantiq_gswip.c
+@@ -1664,7 +1664,9 @@ static void gswip_phylink_mac_link_down(
+ static void gswip_phylink_mac_link_up(struct dsa_switch *ds, int port,
+ 				      unsigned int mode,
+ 				      phy_interface_t interface,
+-				      struct phy_device *phydev)
++				      struct phy_device *phydev,
++				      int speed, int duplex,
++				      bool tx_pause, bool rx_pause)
+ {
+ 	struct gswip_priv *priv = ds->priv;
+ 
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -1440,7 +1440,9 @@ static void mt7530_phylink_mac_link_down
+ static void mt7530_phylink_mac_link_up(struct dsa_switch *ds, int port,
+ 				       unsigned int mode,
+ 				       phy_interface_t interface,
+-				       struct phy_device *phydev)
++				       struct phy_device *phydev,
++				       int speed, int duplex,
++				       bool tx_pause, bool rx_pause)
+ {
+ 	struct mt7530_priv *priv = ds->priv;
+ 
+--- a/drivers/net/dsa/mv88e6xxx/chip.c
++++ b/drivers/net/dsa/mv88e6xxx/chip.c
+@@ -652,7 +652,9 @@ static void mv88e6xxx_mac_link_down(stru
+ 
+ static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port,
+ 				  unsigned int mode, phy_interface_t interface,
+-				  struct phy_device *phydev)
++				  struct phy_device *phydev,
++				  int speed, int duplex,
++				  bool tx_pause, bool rx_pause)
+ {
+ 	if (mode == MLO_AN_FIXED)
+ 		mv88e6xxx_mac_link_force(ds, port, LINK_FORCED_UP);
+--- a/drivers/net/dsa/sja1105/sja1105_main.c
++++ b/drivers/net/dsa/sja1105/sja1105_main.c
+@@ -831,7 +831,9 @@ static void sja1105_mac_link_down(struct
+ static void sja1105_mac_link_up(struct dsa_switch *ds, int port,
+ 				unsigned int mode,
+ 				phy_interface_t interface,
+-				struct phy_device *phydev)
++				struct phy_device *phydev,
++				int speed, int duplex,
++				bool tx_pause, bool rx_pause)
+ {
+ 	sja1105_inhibit_tx(ds->priv, BIT(port), false);
+ }
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -406,7 +406,9 @@ struct dsa_switch_ops {
+ 	void	(*phylink_mac_link_up)(struct dsa_switch *ds, int port,
+ 				       unsigned int mode,
+ 				       phy_interface_t interface,
+-				       struct phy_device *phydev);
++				       struct phy_device *phydev,
++				       int speed, int duplex,
++				       bool tx_pause, bool rx_pause);
+ 	void	(*phylink_fixed_state)(struct dsa_switch *ds, int port,
+ 				       struct phylink_link_state *state);
+ 	/*
+--- a/net/dsa/port.c
++++ b/net/dsa/port.c
+@@ -544,7 +544,8 @@ void dsa_port_phylink_mac_link_up(struct
+ 		return;
+ 	}
+ 
+-	ds->ops->phylink_mac_link_up(ds, dp->index, mode, interface, phydev);
++	ds->ops->phylink_mac_link_up(ds, dp->index, mode, interface, phydev,
++				     speed, duplex, tx_pause, rx_pause);
+ }
+ EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_link_up);
+ 
+--- a/net/dsa/dsa_priv.h
++++ b/net/dsa/dsa_priv.h
+@@ -192,9 +192,11 @@ void dsa_port_phylink_mac_link_down(stru
+ 				    unsigned int mode,
+ 				    phy_interface_t interface);
+ void dsa_port_phylink_mac_link_up(struct phylink_config *config,
++				  struct phy_device *phydev,
+ 				  unsigned int mode,
+ 				  phy_interface_t interface,
+-				  struct phy_device *phydev);
++				  int speed, int duplex,
++				  bool tx_pause, bool rx_pause);
+ extern const struct phylink_mac_ops dsa_port_phylink_mac_ops;
+ 
+ /* slave.c */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0602-net-dsa-mt7530-use-resolved-link-config-in-mac_link_.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0602-net-dsa-mt7530-use-resolved-link-config-in-mac_link_.patch
new file mode 100644
index 0000000..23fba85
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0602-net-dsa-mt7530-use-resolved-link-config-in-mac_link_.patch
@@ -0,0 +1,145 @@
+From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= <opensource@vdorst.com>
+Date: Fri, 27 Mar 2020 15:44:12 +0100
+Subject: [PATCH] net: dsa: mt7530: use resolved link config in mac_link_up()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Convert the mt7530 switch driver to use the finalised link
+parameters in mac_link_up() rather than the parameters in mac_config().
+
+Signed-off-by: René van Dorst <opensource@vdorst.com>
+Tested-by: Sean Wang <sean.wang@mediatek.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -489,17 +489,6 @@ mt7530_mib_reset(struct dsa_switch *ds)
+ 	mt7530_write(priv, MT7530_MIB_CCR, CCR_MIB_ACTIVATE);
+ }
+ 
+-static void
+-mt7530_port_set_status(struct mt7530_priv *priv, int port, int enable)
+-{
+-	u32 mask = PMCR_TX_EN | PMCR_RX_EN | PMCR_FORCE_LNK;
+-
+-	if (enable)
+-		mt7530_set(priv, MT7530_PMCR_P(port), mask);
+-	else
+-		mt7530_clear(priv, MT7530_PMCR_P(port), mask);
+-}
+-
+ static int mt7530_phy_read(struct dsa_switch *ds, int port, int regnum)
+ {
+ 	struct mt7530_priv *priv = ds->priv;
+@@ -673,7 +662,7 @@ mt7530_port_enable(struct dsa_switch *ds
+ 	priv->ports[port].enable = true;
+ 	mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
+ 		   priv->ports[port].pm);
+-	mt7530_port_set_status(priv, port, 0);
++	mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
+ 
+ 	mutex_unlock(&priv->reg_mutex);
+ 
+@@ -696,7 +685,7 @@ mt7530_port_disable(struct dsa_switch *d
+ 	priv->ports[port].enable = false;
+ 	mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
+ 		   PCR_MATRIX_CLR);
+-	mt7530_port_set_status(priv, port, 0);
++	mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
+ 
+ 	mutex_unlock(&priv->reg_mutex);
+ }
+@@ -1395,8 +1384,7 @@ static void mt7530_phylink_mac_config(st
+ 
+ 	mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port));
+ 	mcr_new = mcr_cur;
+-	mcr_new &= ~(PMCR_FORCE_SPEED_1000 | PMCR_FORCE_SPEED_100 |
+-		     PMCR_FORCE_FDX | PMCR_TX_FC_EN | PMCR_RX_FC_EN);
++	mcr_new &= ~PMCR_LINK_SETTINGS_MASK;
+ 	mcr_new |= PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | PMCR_BACKOFF_EN |
+ 		   PMCR_BACKPR_EN | PMCR_FORCE_MODE;
+ 
+@@ -1404,26 +1392,6 @@ static void mt7530_phylink_mac_config(st
+ 	if (port == 5 && dsa_is_user_port(ds, 5))
+ 		mcr_new |= PMCR_EXT_PHY;
+ 
+-	switch (state->speed) {
+-	case SPEED_1000:
+-		mcr_new |= PMCR_FORCE_SPEED_1000;
+-		if (priv->eee_enable & BIT(port))
+-			mcr_new |= PMCR_FORCE_EEE1G;
+-		break;
+-	case SPEED_100:
+-		mcr_new |= PMCR_FORCE_SPEED_100;
+-		if (priv->eee_enable & BIT(port))
+-			mcr_new |= PMCR_FORCE_EEE100;
+-		break;
+-	}
+-	if (state->duplex == DUPLEX_FULL) {
+-		mcr_new |= PMCR_FORCE_FDX;
+-		if (state->pause & MLO_PAUSE_TX)
+-			mcr_new |= PMCR_TX_FC_EN;
+-		if (state->pause & MLO_PAUSE_RX)
+-			mcr_new |= PMCR_RX_FC_EN;
+-	}
+-
+ 	if (mcr_new != mcr_cur)
+ 		mt7530_write(priv, MT7530_PMCR_P(port), mcr_new);
+ }
+@@ -1434,7 +1402,7 @@ static void mt7530_phylink_mac_link_down
+ {
+ 	struct mt7530_priv *priv = ds->priv;
+ 
+-	mt7530_port_set_status(priv, port, 0);
++	mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
+ }
+ 
+ static void mt7530_phylink_mac_link_up(struct dsa_switch *ds, int port,
+@@ -1445,8 +1413,31 @@ static void mt7530_phylink_mac_link_up(s
+ 				       bool tx_pause, bool rx_pause)
+ {
+ 	struct mt7530_priv *priv = ds->priv;
++	u32 mcr;
++
++	mcr = PMCR_RX_EN | PMCR_TX_EN | PMCR_FORCE_LNK;
++
++	switch (speed) {
++	case SPEED_1000:
++		mcr |= PMCR_FORCE_SPEED_1000;
++		if (priv->eee_enable & BIT(port))
++			mcr_new |= PMCR_FORCE_EEE1G;
++		break;
++	case SPEED_100:
++		mcr |= PMCR_FORCE_SPEED_100;
++		if (priv->eee_enable & BIT(port))
++			mcr_new |= PMCR_FORCE_EEE100;
++		break;
++	}
++	if (duplex == DUPLEX_FULL) {
++		mcr |= PMCR_FORCE_FDX;
++		if (tx_pause)
++			mcr |= PMCR_TX_FC_EN;
++		if (rx_pause)
++			mcr |= PMCR_RX_FC_EN;
++	}
+ 
+-	mt7530_port_set_status(priv, port, 1);
++	mt7530_set(priv, MT7530_PMCR_P(port), mcr);
+ }
+ 
+ static void mt7530_phylink_validate(struct dsa_switch *ds, int port,
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -222,6 +222,10 @@ enum mt7530_vlan_port_attr {
+ #define  PMCR_FORCE_LNK			BIT(0)
+ #define  PMCR_SPEED_MASK		(PMCR_FORCE_SPEED_100 | \
+ 					 PMCR_FORCE_SPEED_1000)
++#define  PMCR_LINK_SETTINGS_MASK	(PMCR_TX_EN | PMCR_FORCE_SPEED_1000 | \
++					 PMCR_RX_EN | PMCR_FORCE_SPEED_100 | \
++					 PMCR_TX_FC_EN | PMCR_RX_FC_EN | \
++					 PMCR_FORCE_FDX | PMCR_FORCE_LNK)
+ 
+ #define MT7530_PMSR_P(x)		(0x3008 + (x) * 0x100)
+ #define  PMSR_EEE1G			BIT(7)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0603-net-dsa-mt7530-Extend-device-data-ready-for-adding-a.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0603-net-dsa-mt7530-Extend-device-data-ready-for-adding-a.patch
new file mode 100644
index 0000000..718ed8e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0603-net-dsa-mt7530-Extend-device-data-ready-for-adding-a.patch
@@ -0,0 +1,458 @@
+From: Landen Chao <landen.chao@mediatek.com>
+Date: Fri, 4 Sep 2020 22:21:57 +0800
+Subject: [PATCH] net: dsa: mt7530: Extend device data ready for adding a
+ new hardware
+
+Add a structure holding required operations for each device such as device
+initialization, PHY port read or write, a checker whether PHY interface is
+supported on a certain port, MAC port setup for either bus pad or a
+specific PHY interface.
+
+The patch is done for ready adding a new hardware MT7531, and keep the
+same setup logic of existing hardware.
+
+Signed-off-by: Landen Chao <landen.chao@mediatek.com>
+Signed-off-by: Sean Wang <sean.wang@mediatek.com>
+---
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -373,8 +373,9 @@ mt7530_fdb_write(struct mt7530_priv *pri
+ 		mt7530_write(priv, MT7530_ATA1 + (i * 4), reg[i]);
+ }
+ 
++/* Setup TX circuit including relevant PAD and driving */
+ static int
+-mt7530_pad_clk_setup(struct dsa_switch *ds, int mode)
++mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface)
+ {
+ 	struct mt7530_priv *priv = ds->priv;
+ 	u32 ncpo1, ssc_delta, trgint, i, xtal;
+@@ -388,7 +389,7 @@ mt7530_pad_clk_setup(struct dsa_switch *
+ 		return -EINVAL;
+ 	}
+ 
+-	switch (mode) {
++	switch (interface) {
+ 	case PHY_INTERFACE_MODE_RGMII:
+ 		trgint = 0;
+ 		/* PLL frequency: 125MHz */
+@@ -410,7 +411,8 @@ mt7530_pad_clk_setup(struct dsa_switch *
+ 		}
+ 		break;
+ 	default:
+-		dev_err(priv->dev, "xMII mode %d not supported\n", mode);
++		dev_err(priv->dev, "xMII interface %d not supported\n",
++			interface);
+ 		return -EINVAL;
+ 	}
+ 
+@@ -1332,12 +1334,11 @@ mt7530_setup(struct dsa_switch *ds)
+ 	return 0;
+ }
+ 
+-static void mt7530_phylink_mac_config(struct dsa_switch *ds, int port,
+-				      unsigned int mode,
+-				      const struct phylink_link_state *state)
++static bool
++mt7530_phy_mode_supported(struct dsa_switch *ds, int port,
++			  const struct phylink_link_state *state)
+ {
+ 	struct mt7530_priv *priv = ds->priv;
+-	u32 mcr_cur, mcr_new;
+ 
+ 	switch (port) {
+ 	case 0: /* Internal phy */
+@@ -1346,33 +1347,114 @@ static void mt7530_phylink_mac_config(st
+ 	case 3:
+ 	case 4:
+ 		if (state->interface != PHY_INTERFACE_MODE_GMII)
+-			return;
++			goto unsupported;
+ 		break;
+ 	case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
+-		if (priv->p5_interface == state->interface)
+-			break;
+ 		if (!phy_interface_mode_is_rgmii(state->interface) &&
+ 		    state->interface != PHY_INTERFACE_MODE_MII &&
+ 		    state->interface != PHY_INTERFACE_MODE_GMII)
+-			return;
++			goto unsupported;
++		break;
++	case 6: /* 1st cpu port */
++		if (state->interface != PHY_INTERFACE_MODE_RGMII &&
++		    state->interface != PHY_INTERFACE_MODE_TRGMII)
++			goto unsupported;
++		break;
++	default:
++		dev_err(priv->dev, "%s: unsupported port: %i\n", __func__,
++			port);
++		goto unsupported;
++	}
++
++	return true;
++
++unsupported:
++	return false;
++}
++
++static bool
++mt753x_phy_mode_supported(struct dsa_switch *ds, int port,
++			  const struct phylink_link_state *state)
++{
++	struct mt7530_priv *priv = ds->priv;
++
++	return priv->info->phy_mode_supported(ds, port, state);
++}
++
++static int
++mt753x_pad_setup(struct dsa_switch *ds, const struct phylink_link_state *state)
++{
++	struct mt7530_priv *priv = ds->priv;
++
++	return priv->info->pad_setup(ds, state->interface);
++}
++
++static int
++mt7530_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
++		  phy_interface_t interface)
++{
++	struct mt7530_priv *priv = ds->priv;
++
++	/* Only need to setup port5. */
++	if (port != 5)
++		return 0;
++
++	mt7530_setup_port5(priv->ds, interface);
++
++	return 0;
++}
++
++static int
++mt753x_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
++		  const struct phylink_link_state *state)
++{
++	struct mt7530_priv *priv = ds->priv;
++
++	return priv->info->mac_port_config(ds, port, mode, state->interface);
++}
++
++static void
++mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
++			  const struct phylink_link_state *state)
++{
++	struct mt7530_priv *priv = ds->priv;
++	u32 mcr_cur, mcr_new;
++
++	if (!mt753x_phy_mode_supported(ds, port, state))
++		goto unsupported;
++
++	switch (port) {
++	case 0: /* Internal phy */
++	case 1:
++	case 2:
++	case 3:
++	case 4:
++		if (state->interface != PHY_INTERFACE_MODE_GMII)
++			goto unsupported;
++		break;
++	case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
++		if (priv->p5_interface == state->interface)
++			break;
++
++		if (mt753x_mac_config(ds, port, mode, state) < 0)
++			goto unsupported;
+ 
+-		mt7530_setup_port5(ds, state->interface);
+ 		break;
+ 	case 6: /* 1st cpu port */
+ 		if (priv->p6_interface == state->interface)
+ 			break;
+ 
+-		if (state->interface != PHY_INTERFACE_MODE_RGMII &&
+-		    state->interface != PHY_INTERFACE_MODE_TRGMII)
+-			return;
++		mt753x_pad_setup(ds, state);
+ 
+-		/* Setup TX circuit incluing relevant PAD and driving */
+-		mt7530_pad_clk_setup(ds, state->interface);
++		if (mt753x_mac_config(ds, port, mode, state) < 0)
++			goto unsupported;
+ 
+ 		priv->p6_interface = state->interface;
+ 		break;
+ 	default:
+-		dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port);
++unsupported:
++		dev_err(ds->dev, "%s: unsupported %s port: %i\n",
++			__func__, phy_modes(state->interface), port);
+ 		return;
+ 	}
+ 
+@@ -1440,61 +1522,44 @@ static void mt7530_phylink_mac_link_up(s
+ 	mt7530_set(priv, MT7530_PMCR_P(port), mcr);
+ }
+ 
+-static void mt7530_phylink_validate(struct dsa_switch *ds, int port,
+-				    unsigned long *supported,
+-				    struct phylink_link_state *state)
++static void
++mt7530_mac_port_validate(struct dsa_switch *ds, int port,
++			 unsigned long *supported)
+ {
++	if (port == 5)
++		phylink_set(supported, 1000baseX_Full);
++}
++
++static void
++mt753x_phylink_validate(struct dsa_switch *ds, int port,
++			unsigned long *supported,
++			struct phylink_link_state *state)
++{
++	struct mt7530_priv *priv = ds->priv;
+ 	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+ 
+-	switch (port) {
+-	case 0: /* Internal phy */
+-	case 1:
+-	case 2:
+-	case 3:
+-	case 4:
+-		if (state->interface != PHY_INTERFACE_MODE_NA &&
+-		    state->interface != PHY_INTERFACE_MODE_GMII)
+-			goto unsupported;
+-		break;
+-	case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
+-		if (state->interface != PHY_INTERFACE_MODE_NA &&
+-		    !phy_interface_mode_is_rgmii(state->interface) &&
+-		    state->interface != PHY_INTERFACE_MODE_MII &&
+-		    state->interface != PHY_INTERFACE_MODE_GMII)
+-			goto unsupported;
+-		break;
+-	case 6: /* 1st cpu port */
+-		if (state->interface != PHY_INTERFACE_MODE_NA &&
+-		    state->interface != PHY_INTERFACE_MODE_RGMII &&
+-		    state->interface != PHY_INTERFACE_MODE_TRGMII)
+-			goto unsupported;
+-		break;
+-	default:
+-		dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port);
+-unsupported:
++	if (state->interface != PHY_INTERFACE_MODE_NA &&
++	    !mt753x_phy_mode_supported(ds, port, state)) {
+ 		linkmode_zero(supported);
+ 		return;
+ 	}
+ 
+ 	phylink_set_port_modes(mask);
+-	phylink_set(mask, Autoneg);
+ 
+-	if (state->interface == PHY_INTERFACE_MODE_TRGMII) {
+-		phylink_set(mask, 1000baseT_Full);
+-	} else {
++	if (state->interface != PHY_INTERFACE_MODE_TRGMII) {
+ 		phylink_set(mask, 10baseT_Half);
+ 		phylink_set(mask, 10baseT_Full);
+ 		phylink_set(mask, 100baseT_Half);
+ 		phylink_set(mask, 100baseT_Full);
+-
+-		if (state->interface != PHY_INTERFACE_MODE_MII) {
+-			/* This switch only supports 1G full-duplex. */
+-			phylink_set(mask, 1000baseT_Full);
+-			if (port == 5)
+-				phylink_set(mask, 1000baseX_Full);
+-		}
++		phylink_set(mask, Autoneg);
+ 	}
+ 
++	/* This switch only supports 1G full-duplex. */
++	if (state->interface != PHY_INTERFACE_MODE_MII)
++		phylink_set(mask, 1000baseT_Full);
++
++	priv->info->mac_port_validate(ds, port, mask);
++
+ 	phylink_set(mask, Pause);
+ 	phylink_set(mask, Asym_Pause);
+ 
+@@ -1590,12 +1655,45 @@ static int mt7530_set_mac_eee(struct dsa
+ 	return 0;
+ }
+ 
++static int
++mt753x_phylink_mac_link_state(struct dsa_switch *ds, int port,
++			      struct phylink_link_state *state)
++{
++	struct mt7530_priv *priv = ds->priv;
++
++	return priv->info->mac_port_get_state(ds, port, state);
++}
++
++static int
++mt753x_setup(struct dsa_switch *ds)
++{
++	struct mt7530_priv *priv = ds->priv;
++
++	return priv->info->sw_setup(ds);
++}
++
++static int
++mt753x_phy_read(struct dsa_switch *ds, int port, int regnum)
++{
++	struct mt7530_priv *priv = ds->priv;
++
++	return priv->info->phy_read(ds, port, regnum);
++}
++
++static int
++mt753x_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
++{
++	struct mt7530_priv *priv = ds->priv;
++
++	return priv->info->phy_write(ds, port, regnum, val);
++}
++
+ static const struct dsa_switch_ops mt7530_switch_ops = {
+ 	.get_tag_protocol	= mtk_get_tag_protocol,
+-	.setup			= mt7530_setup,
++	.setup			= mt753x_setup,
+ 	.get_strings		= mt7530_get_strings,
+-	.phy_read		= mt7530_phy_read,
+-	.phy_write		= mt7530_phy_write,
++	.phy_read		= mt753x_phy_read,
++	.phy_write		= mt753x_phy_write,
+ 	.get_ethtool_stats	= mt7530_get_ethtool_stats,
+ 	.get_sset_count		= mt7530_get_sset_count,
+ 	.port_enable		= mt7530_port_enable,
+@@ -1612,18 +1710,43 @@ static const struct dsa_switch_ops mt753
+ 	.port_vlan_del		= mt7530_port_vlan_del,
+ 	.port_mirror_add	= mt7530_port_mirror_add,
+ 	.port_mirror_del	= mt7530_port_mirror_del,
+-	.phylink_validate	= mt7530_phylink_validate,
+-	.phylink_mac_link_state = mt7530_phylink_mac_link_state,
+-	.phylink_mac_config	= mt7530_phylink_mac_config,
++	.phylink_validate	= mt753x_phylink_validate,
++	.phylink_mac_link_state	= mt753x_phylink_mac_link_state,
++	.phylink_mac_config	= mt753x_phylink_mac_config,
+ 	.phylink_mac_link_down	= mt7530_phylink_mac_link_down,
+ 	.phylink_mac_link_up	= mt7530_phylink_mac_link_up,
+ 	.get_mac_eee		= mt7530_get_mac_eee,
+ 	.set_mac_eee		= mt7530_set_mac_eee,
+ };
+ 
++static const struct mt753x_info mt753x_table[] = {
++	[ID_MT7621] = {
++		.id = ID_MT7621,
++		.sw_setup = mt7530_setup,
++		.phy_read = mt7530_phy_read,
++		.phy_write = mt7530_phy_write,
++		.pad_setup = mt7530_pad_clk_setup,
++		.phy_mode_supported = mt7530_phy_mode_supported,
++		.mac_port_validate = mt7530_mac_port_validate,
++		.mac_port_get_state = mt7530_phylink_mac_link_state,
++		.mac_port_config = mt7530_mac_config,
++	},
++	[ID_MT7530] = {
++		.id = ID_MT7530,
++		.sw_setup = mt7530_setup,
++		.phy_read = mt7530_phy_read,
++		.phy_write = mt7530_phy_write,
++		.pad_setup = mt7530_pad_clk_setup,
++		.phy_mode_supported = mt7530_phy_mode_supported,
++		.mac_port_validate = mt7530_mac_port_validate,
++		.mac_port_get_state = mt7530_phylink_mac_link_state,
++		.mac_port_config = mt7530_mac_config,
++	},
++};
++
+ static const struct of_device_id mt7530_of_match[] = {
+-	{ .compatible = "mediatek,mt7621", .data = (void *)ID_MT7621, },
+-	{ .compatible = "mediatek,mt7530", .data = (void *)ID_MT7530, },
++	{ .compatible = "mediatek,mt7621", .data = &mt753x_table[ID_MT7621], },
++	{ .compatible = "mediatek,mt7530", .data = &mt753x_table[ID_MT7530], },
+ 	{ /* sentinel */ },
+ };
+ MODULE_DEVICE_TABLE(of, mt7530_of_match);
+@@ -1661,8 +1784,21 @@ mt7530_probe(struct mdio_device *mdiodev
+ 	/* Get the hardware identifier from the devicetree node.
+ 	 * We will need it for some of the clock and regulator setup.
+ 	 */
+-	priv->id = (unsigned int)(unsigned long)
+-		of_device_get_match_data(&mdiodev->dev);
++	priv->info = of_device_get_match_data(&mdiodev->dev);
++	if (!priv->info)
++		return -EINVAL;
++
++	/* Sanity check if these required device operations are filled
++	 * properly.
++	 */
++	if (!priv->info->sw_setup || !priv->info->pad_setup ||
++	    !priv->info->phy_read || !priv->info->phy_write ||
++	    !priv->info->phy_mode_supported ||
++	    !priv->info->mac_port_validate ||
++	    !priv->info->mac_port_get_state || !priv->info->mac_port_config)
++		return -EINVAL;
++
++	priv->id = priv->info->id;
+ 
+ 	if (priv->id == ID_MT7530) {
+ 		priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core");
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -11,7 +11,7 @@
+ #define MT7530_NUM_FDB_RECORDS		2048
+ #define MT7530_ALL_MEMBERS		0xff
+ 
+-enum {
++enum mt753x_id {
+ 	ID_MT7530 = 0,
+ 	ID_MT7621 = 1,
+ };
+@@ -451,6 +451,40 @@ static const char *p5_intf_modes(unsigne
+ 	}
+ }
+ 
++/* struct mt753x_info -	This is the main data structure for holding the specific
++ *			part for each supported device
++ * @sw_setup:		Holding the handler to a device initialization
++ * @phy_read:		Holding the way reading PHY port
++ * @phy_write:		Holding the way writing PHY port
++ * @pad_setup:		Holding the way setting up the bus pad for a certain
++ *			MAC port
++ * @phy_mode_supported:	Check if the PHY type is being supported on a certain
++ *			port
++ * @mac_port_validate:	Holding the way to set addition validate type for a
++ *			certan MAC port
++ * @mac_port_get_state: Holding the way getting the MAC/PCS state for a certain
++ *			MAC port
++ * @mac_port_config:	Holding the way setting up the PHY attribute to a
++ *			certain MAC port
++ */
++struct mt753x_info {
++	enum mt753x_id id;
++
++	int (*sw_setup)(struct dsa_switch *ds);
++	int (*phy_read)(struct dsa_switch *ds, int port, int regnum);
++	int (*phy_write)(struct dsa_switch *ds, int port, int regnum, u16 val);
++	int (*pad_setup)(struct dsa_switch *ds, phy_interface_t interface);
++	bool (*phy_mode_supported)(struct dsa_switch *ds, int port,
++				   const struct phylink_link_state *state);
++	void (*mac_port_validate)(struct dsa_switch *ds, int port,
++				  unsigned long *supported);
++	int (*mac_port_get_state)(struct dsa_switch *ds, int port,
++				  struct phylink_link_state *state);
++	int (*mac_port_config)(struct dsa_switch *ds, int port,
++			       unsigned int mode,
++			       phy_interface_t interface);
++};
++
+ /* struct mt7530_priv -	This is the main data structure for holding the state
+  *			of the driver
+  * @dev:		The device pointer
+@@ -476,6 +510,7 @@ struct mt7530_priv {
+ 	struct regulator	*core_pwr;
+ 	struct regulator	*io_pwr;
+ 	struct gpio_desc	*reset;
++	const struct mt753x_info *info;
+ 	unsigned int		id;
+ 	bool			mcm;
+ 	phy_interface_t		p6_interface;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0604-net-dsa-mt7530-Add-the-support-of-MT7531-switch.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0604-net-dsa-mt7530-Add-the-support-of-MT7531-switch.patch
new file mode 100644
index 0000000..8ede862
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0604-net-dsa-mt7530-Add-the-support-of-MT7531-switch.patch
@@ -0,0 +1,1510 @@
+From: Landen Chao <landen.chao@mediatek.com>
+Date: Fri, 4 Sep 2020 22:21:59 +0800
+Subject: [PATCH] net: dsa: mt7530: Add the support of MT7531 switch
+
+Add new support for MT7531:
+
+MT7531 is the next generation of MT7530. It is also a 7-ports switch with
+5 giga embedded phys, 2 cpu ports, and the same MAC logic of MT7530. Cpu
+port 6 only supports SGMII interface. Cpu port 5 supports either RGMII
+or SGMII in different HW sku, but cannot be muxed to PHY of port 0/4 like
+mt7530. Due to SGMII interface support, pll, and pad setting are different
+from MT7530. This patch adds different initial setting, and SGMII phylink
+handlers of MT7531.
+
+MT7531 SGMII interface can be configured in following mode:
+- 'SGMII AN mode' with in-band negotiation capability
+    which is compatible with PHY_INTERFACE_MODE_SGMII.
+- 'SGMII force mode' without in-band negotiation
+    which is compatible with 10B/8B encoding of
+    PHY_INTERFACE_MODE_1000BASEX with fixed full-duplex and fixed pause.
+- 2.5 times faster clocked 'SGMII force mode' without in-band negotiation
+    which is compatible with 10B/8B encoding of
+    PHY_INTERFACE_MODE_2500BASEX with fixed full-duplex and fixed pause.
+
+Signed-off-by: Landen Chao <landen.chao@mediatek.com>
+Signed-off-by: Sean Wang <sean.wang@mediatek.com>
+---
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -235,6 +235,12 @@ mt7530_write(struct mt7530_priv *priv, u
+ }
+ 
+ static u32
++_mt7530_unlocked_read(struct mt7530_dummy_poll *p)
++{
++	return mt7530_mii_read(p->priv, p->reg);
++}
++
++static u32
+ _mt7530_read(struct mt7530_dummy_poll *p)
+ {
+ 	struct mii_bus		*bus = p->priv->bus;
+@@ -482,6 +488,108 @@ mt7530_pad_clk_setup(struct dsa_switch *
+ 	return 0;
+ }
+ 
++static bool mt7531_dual_sgmii_supported(struct mt7530_priv *priv)
++{
++	u32 val;
++
++	val = mt7530_read(priv, MT7531_TOP_SIG_SR);
++
++	return (val & PAD_DUAL_SGMII_EN) != 0;
++}
++
++static int
++mt7531_pad_setup(struct dsa_switch *ds, phy_interface_t interface)
++{
++	struct mt7530_priv *priv = ds->priv;
++	u32 val;
++	u32 top_sig;
++	u32 hwstrap;
++	u32 xtal;
++
++	if (mt7531_dual_sgmii_supported(priv))
++		return 0;
++
++	val = mt7530_read(priv, MT7531_CREV);
++	top_sig = mt7530_read(priv, MT7531_TOP_SIG_SR);
++	hwstrap = mt7530_read(priv, MT7531_HWTRAP);
++	if ((val & CHIP_REV_M) > 0)
++		xtal = (top_sig & PAD_MCM_SMI_EN) ? HWTRAP_XTAL_FSEL_40MHZ :
++						    HWTRAP_XTAL_FSEL_25MHZ;
++	else
++		xtal = hwstrap & HWTRAP_XTAL_FSEL_MASK;
++
++	/* Step 1 : Disable MT7531 COREPLL */
++	val = mt7530_read(priv, MT7531_PLLGP_EN);
++	val &= ~EN_COREPLL;
++	mt7530_write(priv, MT7531_PLLGP_EN, val);
++
++	/* Step 2: switch to XTAL output */
++	val = mt7530_read(priv, MT7531_PLLGP_EN);
++	val |= SW_CLKSW;
++	mt7530_write(priv, MT7531_PLLGP_EN, val);
++
++	val = mt7530_read(priv, MT7531_PLLGP_CR0);
++	val &= ~RG_COREPLL_EN;
++	mt7530_write(priv, MT7531_PLLGP_CR0, val);
++
++	/* Step 3: disable PLLGP and enable program PLLGP */
++	val = mt7530_read(priv, MT7531_PLLGP_EN);
++	val |= SW_PLLGP;
++	mt7530_write(priv, MT7531_PLLGP_EN, val);
++
++	/* Step 4: program COREPLL output frequency to 500MHz */
++	val = mt7530_read(priv, MT7531_PLLGP_CR0);
++	val &= ~RG_COREPLL_POSDIV_M;
++	val |= 2 << RG_COREPLL_POSDIV_S;
++	mt7530_write(priv, MT7531_PLLGP_CR0, val);
++	usleep_range(25, 35);
++
++	switch (xtal) {
++	case HWTRAP_XTAL_FSEL_25MHZ:
++		val = mt7530_read(priv, MT7531_PLLGP_CR0);
++		val &= ~RG_COREPLL_SDM_PCW_M;
++		val |= 0x140000 << RG_COREPLL_SDM_PCW_S;
++		mt7530_write(priv, MT7531_PLLGP_CR0, val);
++		break;
++	case HWTRAP_XTAL_FSEL_40MHZ:
++		val = mt7530_read(priv, MT7531_PLLGP_CR0);
++		val &= ~RG_COREPLL_SDM_PCW_M;
++		val |= 0x190000 << RG_COREPLL_SDM_PCW_S;
++		mt7530_write(priv, MT7531_PLLGP_CR0, val);
++		break;
++	};
++
++	/* Set feedback divide ratio update signal to high */
++	val = mt7530_read(priv, MT7531_PLLGP_CR0);
++	val |= RG_COREPLL_SDM_PCW_CHG;
++	mt7530_write(priv, MT7531_PLLGP_CR0, val);
++	/* Wait for at least 16 XTAL clocks */
++	usleep_range(10, 20);
++
++	/* Step 5: set feedback divide ratio update signal to low */
++	val = mt7530_read(priv, MT7531_PLLGP_CR0);
++	val &= ~RG_COREPLL_SDM_PCW_CHG;
++	mt7530_write(priv, MT7531_PLLGP_CR0, val);
++
++	/* Enable 325M clock for SGMII */
++	mt7530_write(priv, MT7531_ANA_PLLGP_CR5, 0xad0000);
++
++	/* Enable 250SSC clock for RGMII */
++	mt7530_write(priv, MT7531_ANA_PLLGP_CR2, 0x4f40000);
++
++	/* Step 6: Enable MT7531 PLL */
++	val = mt7530_read(priv, MT7531_PLLGP_CR0);
++	val |= RG_COREPLL_EN;
++	mt7530_write(priv, MT7531_PLLGP_CR0, val);
++
++	val = mt7530_read(priv, MT7531_PLLGP_EN);
++	val |= EN_COREPLL;
++	mt7530_write(priv, MT7531_PLLGP_EN, val);
++	usleep_range(25, 35);
++
++	return 0;
++}
++
+ static void
+ mt7530_mib_reset(struct dsa_switch *ds)
+ {
+@@ -506,6 +614,217 @@ static int mt7530_phy_write(struct dsa_s
+ 	return mdiobus_write_nested(priv->bus, port, regnum, val);
+ }
+ 
++static int
++mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
++			int regnum)
++{
++	struct mii_bus *bus = priv->bus;
++	struct mt7530_dummy_poll p;
++	u32 reg, val;
++	int ret;
++
++	INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
++
++	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++
++	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
++				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
++	if (ret < 0) {
++		dev_err(priv->dev, "poll timeout\n");
++		goto out;
++	}
++
++	reg = MT7531_MDIO_CL45_ADDR | MT7531_MDIO_PHY_ADDR(port) |
++	      MT7531_MDIO_DEV_ADDR(devad) | regnum;
++	mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
++
++	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
++				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
++	if (ret < 0) {
++		dev_err(priv->dev, "poll timeout\n");
++		goto out;
++	}
++
++	reg = MT7531_MDIO_CL45_READ | MT7531_MDIO_PHY_ADDR(port) |
++	      MT7531_MDIO_DEV_ADDR(devad);
++	mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
++
++	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
++				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
++	if (ret < 0) {
++		dev_err(priv->dev, "poll timeout\n");
++		goto out;
++	}
++
++	ret = val & MT7531_MDIO_RW_DATA_MASK;
++out:
++	mutex_unlock(&bus->mdio_lock);
++
++	return ret;
++}
++
++static int
++mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
++			 int regnum, u32 data)
++{
++	struct mii_bus *bus = priv->bus;
++	struct mt7530_dummy_poll p;
++	u32 val, reg;
++	int ret;
++
++	INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
++
++	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++
++	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
++				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
++	if (ret < 0) {
++		dev_err(priv->dev, "poll timeout\n");
++		goto out;
++	}
++
++	reg = MT7531_MDIO_CL45_ADDR | MT7531_MDIO_PHY_ADDR(port) |
++	      MT7531_MDIO_DEV_ADDR(devad) | regnum;
++	mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
++
++	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
++				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
++	if (ret < 0) {
++		dev_err(priv->dev, "poll timeout\n");
++		goto out;
++	}
++
++	reg = MT7531_MDIO_CL45_WRITE | MT7531_MDIO_PHY_ADDR(port) |
++	      MT7531_MDIO_DEV_ADDR(devad) | data;
++	mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
++
++	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
++				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
++	if (ret < 0) {
++		dev_err(priv->dev, "poll timeout\n");
++		goto out;
++	}
++
++out:
++	mutex_unlock(&bus->mdio_lock);
++
++	return ret;
++}
++
++static int
++mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)
++{
++	struct mii_bus *bus = priv->bus;
++	struct mt7530_dummy_poll p;
++	int ret;
++	u32 val;
++
++	INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
++
++	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++
++	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
++				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
++	if (ret < 0) {
++		dev_err(priv->dev, "poll timeout\n");
++		goto out;
++	}
++
++	val = MT7531_MDIO_CL22_READ | MT7531_MDIO_PHY_ADDR(port) |
++	      MT7531_MDIO_REG_ADDR(regnum);
++
++	mt7530_mii_write(priv, MT7531_PHY_IAC, val | MT7531_PHY_ACS_ST);
++
++	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
++				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
++	if (ret < 0) {
++		dev_err(priv->dev, "poll timeout\n");
++		goto out;
++	}
++
++	ret = val & MT7531_MDIO_RW_DATA_MASK;
++out:
++	mutex_unlock(&bus->mdio_lock);
++
++	return ret;
++}
++
++static int
++mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,
++			 u16 data)
++{
++	struct mii_bus *bus = priv->bus;
++	struct mt7530_dummy_poll p;
++	int ret;
++	u32 reg;
++
++	INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
++
++	mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++
++	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
++				 !(reg & MT7531_PHY_ACS_ST), 20, 100000);
++	if (ret < 0) {
++		dev_err(priv->dev, "poll timeout\n");
++		goto out;
++	}
++
++	reg = MT7531_MDIO_CL22_WRITE | MT7531_MDIO_PHY_ADDR(port) |
++	      MT7531_MDIO_REG_ADDR(regnum) | data;
++
++	mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
++
++	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
++				 !(reg & MT7531_PHY_ACS_ST), 20, 100000);
++	if (ret < 0) {
++		dev_err(priv->dev, "poll timeout\n");
++		goto out;
++	}
++
++out:
++	mutex_unlock(&bus->mdio_lock);
++
++	return ret;
++}
++
++static int
++mt7531_ind_phy_read(struct dsa_switch *ds, int port, int regnum)
++{
++	struct mt7530_priv *priv = ds->priv;
++	int devad;
++	int ret;
++
++	if (regnum & MII_ADDR_C45) {
++		devad = (regnum >> MII_DEVADDR_C45_SHIFT) & 0x1f;
++		ret = mt7531_ind_c45_phy_read(priv, port, devad,
++					      regnum & MII_REGADDR_C45_MASK);
++	} else {
++		ret = mt7531_ind_c22_phy_read(priv, port, regnum);
++	}
++
++	return ret;
++}
++
++static int
++mt7531_ind_phy_write(struct dsa_switch *ds, int port, int regnum,
++		     u16 data)
++{
++	struct mt7530_priv *priv = ds->priv;
++	int devad;
++	int ret;
++
++	if (regnum & MII_ADDR_C45) {
++		devad = (regnum >> MII_DEVADDR_C45_SHIFT) & 0x1f;
++		ret = mt7531_ind_c45_phy_write(priv, port, devad,
++					       regnum & MII_REGADDR_C45_MASK,
++					       data);
++	} else {
++		ret = mt7531_ind_c22_phy_write(priv, port, regnum, data);
++	}
++
++	return ret;
++}
++
+ static void
+ mt7530_get_strings(struct dsa_switch *ds, int port, u32 stringset,
+ 		   uint8_t *data)
+@@ -622,9 +941,14 @@ unlock_exit:
+ }
+ 
+ static int
+-mt7530_cpu_port_enable(struct mt7530_priv *priv,
+-		       int port)
++mt753x_cpu_port_enable(struct dsa_switch *ds, int port)
+ {
++	struct mt7530_priv *priv = ds->priv;
++
++	/* Setup max capability of CPU port at first */
++	if (priv->info->cpu_port_config)
++		priv->info->cpu_port_config(ds, port);
++
+ 	/* Enable Mediatek header mode on the cpu port */
+ 	mt7530_write(priv, MT7530_PVC_P(port),
+ 		     PORT_SPEC_TAG);
+@@ -637,7 +961,7 @@ mt7530_cpu_port_enable(struct mt7530_pri
+ 		mt7530_rmw(priv, MT7530_MFC, CPU_MASK, CPU_EN | CPU_PORT(port));
+ 
+ 	/* CPU port gets connected to all user ports of
+-	 * the switch
++	 * the switch.
+ 	 */
+ 	mt7530_write(priv, MT7530_PCR_P(port),
+ 		     PCR_MATRIX(dsa_user_ports(priv->ds)));
+@@ -1120,27 +1444,42 @@ mt7530_port_vlan_del(struct dsa_switch *
+ 	return 0;
+ }
+ 
+-static int mt7530_port_mirror_add(struct dsa_switch *ds, int port,
++static int mt753x_mirror_port_get(unsigned int id, u32 val)
++{
++	return (id == ID_MT7531) ? MT7531_MIRROR_PORT_GET(val) :
++				   MIRROR_PORT(val);
++}
++
++static int mt753x_mirror_port_set(unsigned int id, u32 val)
++{
++	return (id == ID_MT7531) ? MT7531_MIRROR_PORT_SET(val) :
++				   MIRROR_PORT(val);
++}
++
++static int mt753x_port_mirror_add(struct dsa_switch *ds, int port,
+ 				  struct dsa_mall_mirror_tc_entry *mirror,
+ 				  bool ingress)
+ {
+ 	struct mt7530_priv *priv = ds->priv;
++	int monitor_port;
+ 	u32 val;
+ 
+ 	/* Check for existent entry */
+ 	if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port))
+ 		return -EEXIST;
+ 
+-	val = mt7530_read(priv, MT7530_MFC);
++	val = mt7530_read(priv, MT753X_MIRROR_REG(priv->id));
+ 
+ 	/* MT7530 only supports one monitor port */
+-	if (val & MIRROR_EN && MIRROR_PORT(val) != mirror->to_local_port)
++	monitor_port = mt753x_mirror_port_get(priv->id, val);
++	if (val & MT753X_MIRROR_EN(priv->id) &&
++	    monitor_port != mirror->to_local_port)
+ 		return -EEXIST;
+ 
+-	val |= MIRROR_EN;
+-	val &= ~MIRROR_MASK;
+-	val |= mirror->to_local_port;
+-	mt7530_write(priv, MT7530_MFC, val);
++	val |= MT753X_MIRROR_EN(priv->id);
++	val &= ~MT753X_MIRROR_MASK(priv->id);
++	val |= mt753x_mirror_port_set(priv->id, mirror->to_local_port);
++	mt7530_write(priv, MT753X_MIRROR_REG(priv->id), val);
+ 
+ 	val = mt7530_read(priv, MT7530_PCR_P(port));
+ 	if (ingress) {
+@@ -1155,7 +1494,7 @@ static int mt7530_port_mirror_add(struct
+ 	return 0;
+ }
+ 
+-static void mt7530_port_mirror_del(struct dsa_switch *ds, int port,
++static void mt753x_port_mirror_del(struct dsa_switch *ds, int port,
+ 				   struct dsa_mall_mirror_tc_entry *mirror)
+ {
+ 	struct mt7530_priv *priv = ds->priv;
+@@ -1172,9 +1511,9 @@ static void mt7530_port_mirror_del(struc
+ 	mt7530_write(priv, MT7530_PCR_P(port), val);
+ 
+ 	if (!priv->mirror_rx && !priv->mirror_tx) {
+-		val = mt7530_read(priv, MT7530_MFC);
+-		val &= ~MIRROR_EN;
+-		mt7530_write(priv, MT7530_MFC, val);
++		val = mt7530_read(priv, MT753X_MIRROR_REG(priv->id));
++		val &= ~MT753X_MIRROR_EN(priv->id);
++		mt7530_write(priv, MT753X_MIRROR_REG(priv->id), val);
+ 	}
+ }
+ 
+@@ -1280,7 +1619,7 @@ mt7530_setup(struct dsa_switch *ds)
+ 			   PCR_MATRIX_CLR);
+ 
+ 		if (dsa_is_cpu_port(ds, i))
+-			mt7530_cpu_port_enable(priv, i);
++			mt753x_cpu_port_enable(ds, i);
+ 		else
+ 			mt7530_port_disable(ds, i);
+ 
+@@ -1334,6 +1673,118 @@ mt7530_setup(struct dsa_switch *ds)
+ 	return 0;
+ }
+ 
++static int
++mt7531_setup(struct dsa_switch *ds)
++{
++	struct mt7530_priv *priv = ds->priv;
++	struct mt7530_dummy_poll p;
++	u32 val, id;
++	int ret, i;
++
++	/* Reset whole chip through gpio pin or memory-mapped registers for
++	 * different type of hardware
++	 */
++	if (priv->mcm) {
++		reset_control_assert(priv->rstc);
++		usleep_range(1000, 1100);
++		reset_control_deassert(priv->rstc);
++	} else {
++		gpiod_set_value_cansleep(priv->reset, 0);
++		usleep_range(1000, 1100);
++		gpiod_set_value_cansleep(priv->reset, 1);
++	}
++
++	/* Waiting for MT7530 got to stable */
++	INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_HWTRAP);
++	ret = readx_poll_timeout(_mt7530_read, &p, val, val != 0,
++				 20, 1000000);
++	if (ret < 0) {
++		dev_err(priv->dev, "reset timeout\n");
++		return ret;
++	}
++
++	id = mt7530_read(priv, MT7531_CREV);
++	id >>= CHIP_NAME_SHIFT;
++
++	if (id != MT7531_ID) {
++		dev_err(priv->dev, "chip %x can't be supported\n", id);
++		return -ENODEV;
++	}
++
++	/* Reset the switch through internal reset */
++	mt7530_write(priv, MT7530_SYS_CTRL,
++		     SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
++		     SYS_CTRL_REG_RST);
++
++	if (mt7531_dual_sgmii_supported(priv)) {
++		priv->p5_intf_sel = P5_INTF_SEL_GMAC5_SGMII;
++
++		/* Let ds->slave_mii_bus be able to access external phy. */
++		mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO11_RG_RXD2_MASK,
++			   MT7531_EXT_P_MDC_11);
++		mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO12_RG_RXD3_MASK,
++			   MT7531_EXT_P_MDIO_12);
++	} else {
++		priv->p5_intf_sel = P5_INTF_SEL_GMAC5;
++	}
++	dev_dbg(ds->dev, "P5 support %s interface\n",
++		p5_intf_modes(priv->p5_intf_sel));
++
++	mt7530_rmw(priv, MT7531_GPIO_MODE0, MT7531_GPIO0_MASK,
++		   MT7531_GPIO0_INTERRUPT);
++
++	/* Let phylink decide the interface later. */
++	priv->p5_interface = PHY_INTERFACE_MODE_NA;
++	priv->p6_interface = PHY_INTERFACE_MODE_NA;
++
++	/* Enable PHY core PLL, since phy_device has not yet been created
++	 * provided for phy_[read,write]_mmd_indirect is called, we provide
++	 * our own mt7531_ind_mmd_phy_[read,write] to complete this
++	 * function.
++	 */
++	val = mt7531_ind_c45_phy_read(priv, MT753X_CTRL_PHY_ADDR,
++				      MDIO_MMD_VEND2, CORE_PLL_GROUP4);
++	val |= MT7531_PHY_PLL_BYPASS_MODE;
++	val &= ~MT7531_PHY_PLL_OFF;
++	mt7531_ind_c45_phy_write(priv, MT753X_CTRL_PHY_ADDR, MDIO_MMD_VEND2,
++				 CORE_PLL_GROUP4, val);
++
++	/* BPDU to CPU port */
++	mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK,
++		   BIT(MT7530_CPU_PORT));
++	mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK,
++		   MT753X_BPDU_CPU_ONLY);
++
++	/* Enable and reset MIB counters */
++	mt7530_mib_reset(ds);
++
++	for (i = 0; i < MT7530_NUM_PORTS; i++) {
++		/* Disable forwarding by default on all ports */
++		mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
++			   PCR_MATRIX_CLR);
++
++		mt7530_set(priv, MT7531_DBG_CNT(i), MT7531_DIS_CLR);
++
++		if (dsa_is_cpu_port(ds, i))
++			mt753x_cpu_port_enable(ds, i);
++		else
++			mt7530_port_disable(ds, i);
++
++		/* Enable consistent egress tag */
++		mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK,
++			   PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
++	}
++
++	ds->configure_vlan_while_not_filtering = true;
++
++	/* Flush the FDB table */
++	ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL);
++	if (ret < 0)
++		return ret;
++
++	return 0;
++}
++
+ static bool
+ mt7530_phy_mode_supported(struct dsa_switch *ds, int port,
+ 			  const struct phylink_link_state *state)
+@@ -1372,6 +1823,47 @@ unsupported:
+ 	return false;
+ }
+ 
++static bool mt7531_is_rgmii_port(struct mt7530_priv *priv, u32 port)
++{
++	return (port == 5) && (priv->p5_intf_sel != P5_INTF_SEL_GMAC5_SGMII);
++}
++
++static bool
++mt7531_phy_supported(struct dsa_switch *ds, int port,
++		     const struct phylink_link_state *state)
++{
++	struct mt7530_priv *priv = ds->priv;
++
++	switch (port) {
++	case 0: /* Internal phy */
++	case 1:
++	case 2:
++	case 3:
++	case 4:
++		if (state->interface != PHY_INTERFACE_MODE_GMII)
++			goto unsupported;
++		break;
++	case 5: /* 2nd cpu port supports either rgmii or sgmii/8023z */
++		if (mt7531_is_rgmii_port(priv, port))
++			return phy_interface_mode_is_rgmii(state->interface);
++		fallthrough;
++	case 6: /* 1st cpu port supports sgmii/8023z only */
++		if (state->interface != PHY_INTERFACE_MODE_SGMII &&
++		    !phy_interface_mode_is_8023z(state->interface))
++			goto unsupported;
++		break;
++	default:
++		dev_err(priv->dev, "%s: unsupported port: %i\n", __func__,
++			port);
++		goto unsupported;
++	}
++
++	return true;
++
++unsupported:
++	return false;
++}
++
+ static bool
+ mt753x_phy_mode_supported(struct dsa_switch *ds, int port,
+ 			  const struct phylink_link_state *state)
+@@ -1404,6 +1896,227 @@ mt7530_mac_config(struct dsa_switch *ds,
+ 	return 0;
+ }
+ 
++static int mt7531_rgmii_setup(struct mt7530_priv *priv, u32 port,
++			      phy_interface_t interface,
++			      struct phy_device *phydev)
++{
++	u32 val;
++
++	if (!mt7531_is_rgmii_port(priv, port)) {
++		dev_err(priv->dev, "RGMII mode is not available for port %d\n",
++			port);
++		return -EINVAL;
++	}
++
++	val = mt7530_read(priv, MT7531_CLKGEN_CTRL);
++	val |= GP_CLK_EN;
++	val &= ~GP_MODE_MASK;
++	val |= GP_MODE(MT7531_GP_MODE_RGMII);
++	val &= ~CLK_SKEW_IN_MASK;
++	val |= CLK_SKEW_IN(MT7531_CLK_SKEW_NO_CHG);
++	val &= ~CLK_SKEW_OUT_MASK;
++	val |= CLK_SKEW_OUT(MT7531_CLK_SKEW_NO_CHG);
++	val |= TXCLK_NO_REVERSE | RXCLK_NO_DELAY;
++
++	/* Do not adjust rgmii delay when vendor phy driver presents. */
++	if (!phydev || phy_driver_is_genphy(phydev)) {
++		val &= ~(TXCLK_NO_REVERSE | RXCLK_NO_DELAY);
++		switch (interface) {
++		case PHY_INTERFACE_MODE_RGMII:
++			val |= TXCLK_NO_REVERSE;
++			val |= RXCLK_NO_DELAY;
++			break;
++		case PHY_INTERFACE_MODE_RGMII_RXID:
++			val |= TXCLK_NO_REVERSE;
++			break;
++		case PHY_INTERFACE_MODE_RGMII_TXID:
++			val |= RXCLK_NO_DELAY;
++			break;
++		case PHY_INTERFACE_MODE_RGMII_ID:
++			break;
++		default:
++			return -EINVAL;
++		}
++	}
++	mt7530_write(priv, MT7531_CLKGEN_CTRL, val);
++
++	return 0;
++}
++
++static void mt7531_sgmii_validate(struct mt7530_priv *priv, int port,
++				  unsigned long *supported)
++{
++	/* Port5 supports ethier RGMII or SGMII.
++	 * Port6 supports SGMII only.
++	 */
++	switch (port) {
++	case 5:
++		if (mt7531_is_rgmii_port(priv, port))
++			break;
++		fallthrough;
++	case 6:
++		phylink_set(supported, 1000baseX_Full);
++		phylink_set(supported, 2500baseX_Full);
++		phylink_set(supported, 2500baseT_Full);
++	}
++}
++
++static void
++mt7531_sgmii_link_up_force(struct dsa_switch *ds, int port,
++			   unsigned int mode, phy_interface_t interface,
++			   int speed, int duplex)
++{
++	struct mt7530_priv *priv = ds->priv;
++	unsigned int val;
++
++	/* For adjusting speed and duplex of SGMII force mode. */
++	if (interface != PHY_INTERFACE_MODE_SGMII ||
++	    phylink_autoneg_inband(mode))
++		return;
++
++	/* SGMII force mode setting */
++	val = mt7530_read(priv, MT7531_SGMII_MODE(port));
++	val &= ~MT7531_SGMII_IF_MODE_MASK;
++
++	switch (speed) {
++	case SPEED_10:
++		val |= MT7531_SGMII_FORCE_SPEED_10;
++		break;
++	case SPEED_100:
++		val |= MT7531_SGMII_FORCE_SPEED_100;
++		break;
++	case SPEED_1000:
++		val |= MT7531_SGMII_FORCE_SPEED_1000;
++		break;
++	}
++
++	/* MT7531 SGMII 1G force mode can only work in full duplex mode,
++	 * no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not.
++	 */
++	if ((speed == SPEED_10 || speed == SPEED_100) &&
++	    duplex != DUPLEX_FULL)
++		val |= MT7531_SGMII_FORCE_HALF_DUPLEX;
++
++	mt7530_write(priv, MT7531_SGMII_MODE(port), val);
++}
++
++static bool mt753x_is_mac_port(u32 port)
++{
++	return (port == 5 || port == 6);
++}
++
++static int mt7531_sgmii_setup_mode_force(struct mt7530_priv *priv, u32 port,
++					 phy_interface_t interface)
++{
++	u32 val;
++
++	if (!mt753x_is_mac_port(port))
++		return -EINVAL;
++
++	mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port),
++		   MT7531_SGMII_PHYA_PWD);
++
++	val = mt7530_read(priv, MT7531_PHYA_CTRL_SIGNAL3(port));
++	val &= ~MT7531_RG_TPHY_SPEED_MASK;
++	/* Setup 2.5 times faster clock for 2.5Gbps data speeds with 10B/8B
++	 * encoding.
++	 */
++	val |= (interface == PHY_INTERFACE_MODE_2500BASEX) ?
++		MT7531_RG_TPHY_SPEED_3_125G : MT7531_RG_TPHY_SPEED_1_25G;
++	mt7530_write(priv, MT7531_PHYA_CTRL_SIGNAL3(port), val);
++
++	mt7530_clear(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE);
++
++	/* MT7531 SGMII 1G and 2.5G force mode can only work in full duplex
++	 * mode, no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not.
++	 */
++	mt7530_rmw(priv, MT7531_SGMII_MODE(port),
++		   MT7531_SGMII_IF_MODE_MASK | MT7531_SGMII_REMOTE_FAULT_DIS,
++		   MT7531_SGMII_FORCE_SPEED_1000);
++
++	mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0);
++
++	return 0;
++}
++
++static int mt7531_sgmii_setup_mode_an(struct mt7530_priv *priv, int port,
++				      phy_interface_t interface)
++{
++	if (!mt753x_is_mac_port(port))
++		return -EINVAL;
++
++	mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port),
++		   MT7531_SGMII_PHYA_PWD);
++
++	mt7530_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port),
++		   MT7531_RG_TPHY_SPEED_MASK, MT7531_RG_TPHY_SPEED_1_25G);
++
++	mt7530_set(priv, MT7531_SGMII_MODE(port),
++		   MT7531_SGMII_REMOTE_FAULT_DIS |
++		   MT7531_SGMII_SPEED_DUPLEX_AN);
++
++	mt7530_rmw(priv, MT7531_PCS_SPEED_ABILITY(port),
++		   MT7531_SGMII_TX_CONFIG_MASK, 1);
++
++	mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE);
++
++	mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_RESTART);
++
++	mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0);
++
++	return 0;
++}
++
++static void mt7531_sgmii_restart_an(struct dsa_switch *ds, int port)
++{
++	struct mt7530_priv *priv = ds->priv;
++	u32 val;
++
++	/* Only restart AN when AN is enabled */
++	val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port));
++	if (val & MT7531_SGMII_AN_ENABLE) {
++		val |= MT7531_SGMII_AN_RESTART;
++		mt7530_write(priv, MT7531_PCS_CONTROL_1(port), val);
++	}
++}
++
++static int
++mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
++		  phy_interface_t interface)
++{
++	struct mt7530_priv *priv = ds->priv;
++	struct phy_device *phydev;
++	const struct dsa_port *dp;
++
++	if (!mt753x_is_mac_port(port)) {
++		dev_err(priv->dev, "port %d is not a MAC port\n", port);
++		return -EINVAL;
++	}
++
++	switch (interface) {
++	case PHY_INTERFACE_MODE_RGMII:
++	case PHY_INTERFACE_MODE_RGMII_ID:
++	case PHY_INTERFACE_MODE_RGMII_RXID:
++	case PHY_INTERFACE_MODE_RGMII_TXID:
++		dp = dsa_to_port(ds, port);
++		phydev = dp->slave->phydev;
++		return mt7531_rgmii_setup(priv, port, interface, phydev);
++	case PHY_INTERFACE_MODE_SGMII:
++		return mt7531_sgmii_setup_mode_an(priv, port, interface);
++	case PHY_INTERFACE_MODE_NA:
++	case PHY_INTERFACE_MODE_1000BASEX:
++	case PHY_INTERFACE_MODE_2500BASEX:
++		if (phylink_autoneg_inband(mode))
++			return -EINVAL;
++
++		return mt7531_sgmii_setup_mode_force(priv, port, interface);
++	default:
++		return -EINVAL;
++	}
++
++	return -EINVAL;
++}
++
+ static int
+ mt753x_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
+ 		  const struct phylink_link_state *state)
+@@ -1439,6 +2152,8 @@ mt753x_phylink_mac_config(struct dsa_swi
+ 		if (mt753x_mac_config(ds, port, mode, state) < 0)
+ 			goto unsupported;
+ 
++		if (priv->p5_intf_sel != P5_DISABLED)
++			priv->p5_interface = state->interface;
+ 		break;
+ 	case 6: /* 1st cpu port */
+ 		if (priv->p6_interface == state->interface)
+@@ -1458,7 +2173,8 @@ unsupported:
+ 		return;
+ 	}
+ 
+-	if (phylink_autoneg_inband(mode)) {
++	if (phylink_autoneg_inband(mode) &&
++	    state->interface != PHY_INTERFACE_MODE_SGMII) {
+ 		dev_err(ds->dev, "%s: in-band negotiation unsupported\n",
+ 			__func__);
+ 		return;
+@@ -1468,7 +2184,7 @@ unsupported:
+ 	mcr_new = mcr_cur;
+ 	mcr_new &= ~PMCR_LINK_SETTINGS_MASK;
+ 	mcr_new |= PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | PMCR_BACKOFF_EN |
+-		   PMCR_BACKPR_EN | PMCR_FORCE_MODE;
++		   PMCR_BACKPR_EN | PMCR_FORCE_MODE_ID(priv->id);
+ 
+ 	/* Are we connected to external phy */
+ 	if (port == 5 && dsa_is_user_port(ds, 5))
+@@ -1478,7 +2194,18 @@ unsupported:
+ 		mt7530_write(priv, MT7530_PMCR_P(port), mcr_new);
+ }
+ 
+-static void mt7530_phylink_mac_link_down(struct dsa_switch *ds, int port,
++static void
++mt753x_phylink_mac_an_restart(struct dsa_switch *ds, int port)
++{
++	struct mt7530_priv *priv = ds->priv;
++
++	if (!priv->info->mac_pcs_an_restart)
++		return;
++
++	priv->info->mac_pcs_an_restart(ds, port);
++}
++
++static void mt753x_phylink_mac_link_down(struct dsa_switch *ds, int port,
+ 					 unsigned int mode,
+ 					 phy_interface_t interface)
+ {
+@@ -1487,7 +2214,19 @@ static void mt7530_phylink_mac_link_down
+ 	mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
+ }
+ 
+-static void mt7530_phylink_mac_link_up(struct dsa_switch *ds, int port,
++static void mt753x_mac_pcs_link_up(struct dsa_switch *ds, int port,
++				   unsigned int mode, phy_interface_t interface,
++				   int speed, int duplex)
++{
++	struct mt7530_priv *priv = ds->priv;
++
++	if (!priv->info->mac_pcs_link_up)
++		return;
++
++	priv->info->mac_pcs_link_up(ds, port, mode, interface, speed, duplex);
++}
++
++static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port,
+ 				       unsigned int mode,
+ 				       phy_interface_t interface,
+ 				       struct phy_device *phydev,
+@@ -1497,18 +2236,29 @@ static void mt7530_phylink_mac_link_up(s
+ 	struct mt7530_priv *priv = ds->priv;
+ 	u32 mcr;
+ 
++	mt753x_mac_pcs_link_up(ds, port, mode, interface, speed, duplex);
++
+ 	mcr = PMCR_RX_EN | PMCR_TX_EN | PMCR_FORCE_LNK;
+ 
++	/* MT753x MAC works in 1G full duplex mode for all up-clocked
++	 * variants.
++	 */
++	if (interface == PHY_INTERFACE_MODE_TRGMII ||
++	    (phy_interface_mode_is_8023z(interface))) {
++		speed = SPEED_1000;
++		duplex = DUPLEX_FULL;
++	}
++
+ 	switch (speed) {
+ 	case SPEED_1000:
+ 		mcr |= PMCR_FORCE_SPEED_1000;
+ 		if (priv->eee_enable & BIT(port))
+-			mcr_new |= PMCR_FORCE_EEE1G;
++			mcr |= PMCR_FORCE_EEE1G;
+ 		break;
+ 	case SPEED_100:
+ 		mcr |= PMCR_FORCE_SPEED_100;
+ 		if (priv->eee_enable & BIT(port))
+-			mcr_new |= PMCR_FORCE_EEE100;
++			mcr |= PMCR_FORCE_EEE100;
+ 		break;
+ 	}
+ 	if (duplex == DUPLEX_FULL) {
+@@ -1522,6 +2272,45 @@ static void mt7530_phylink_mac_link_up(s
+ 	mt7530_set(priv, MT7530_PMCR_P(port), mcr);
+ }
+ 
++static int
++mt7531_cpu_port_config(struct dsa_switch *ds, int port)
++{
++	struct mt7530_priv *priv = ds->priv;
++	phy_interface_t interface;
++	int speed;
++
++	switch (port) {
++	case 5:
++		if (mt7531_is_rgmii_port(priv, port))
++			interface = PHY_INTERFACE_MODE_RGMII;
++		else
++			interface = PHY_INTERFACE_MODE_2500BASEX;
++
++		priv->p5_interface = interface;
++		break;
++	case 6:
++		interface = PHY_INTERFACE_MODE_2500BASEX;
++
++		mt7531_pad_setup(ds, interface);
++
++		priv->p6_interface = interface;
++		break;
++	};
++
++	if (interface == PHY_INTERFACE_MODE_2500BASEX)
++		speed = SPEED_2500;
++	else
++		speed = SPEED_1000;
++
++	mt7531_mac_config(ds, port, MLO_AN_FIXED, interface);
++	mt7530_write(priv, MT7530_PMCR_P(port),
++		     PMCR_CPU_PORT_SETTING(priv->id));
++	mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED, interface, NULL,
++				   speed, DUPLEX_FULL, true, true);
++
++	return 0;
++}
++
+ static void
+ mt7530_mac_port_validate(struct dsa_switch *ds, int port,
+ 			 unsigned long *supported)
+@@ -1530,6 +2319,14 @@ mt7530_mac_port_validate(struct dsa_swit
+ 		phylink_set(supported, 1000baseX_Full);
+ }
+ 
++static void mt7531_mac_port_validate(struct dsa_switch *ds, int port,
++				     unsigned long *supported)
++{
++	struct mt7530_priv *priv = ds->priv;
++
++	mt7531_sgmii_validate(priv, port, supported);
++}
++
+ static void
+ mt753x_phylink_validate(struct dsa_switch *ds, int port,
+ 			unsigned long *supported,
+@@ -1546,7 +2343,8 @@ mt753x_phylink_validate(struct dsa_switc
+ 
+ 	phylink_set_port_modes(mask);
+ 
+-	if (state->interface != PHY_INTERFACE_MODE_TRGMII) {
++	if (state->interface != PHY_INTERFACE_MODE_TRGMII ||
++	    !phy_interface_mode_is_8023z(state->interface)) {
+ 		phylink_set(mask, 10baseT_Half);
+ 		phylink_set(mask, 10baseT_Full);
+ 		phylink_set(mask, 100baseT_Half);
+@@ -1565,6 +2363,11 @@ mt753x_phylink_validate(struct dsa_switc
+ 
+ 	linkmode_and(supported, supported, mask);
+ 	linkmode_and(state->advertising, state->advertising, mask);
++
++	/* We can only operate at 2500BaseX or 1000BaseX.  If requested
++	 * to advertise both, only report advertising at 2500BaseX.
++	 */
++	phylink_helper_basex_speed(state);
+ }
+ 
+ static int
+@@ -1655,6 +2458,63 @@ static int mt7530_set_mac_eee(struct dsa
+ 	return 0;
+ }
+ 
++#ifdef notyet
++static int
++mt7531_sgmii_pcs_get_state_an(struct mt7530_priv *priv, int port,
++			      struct phylink_link_state *state)
++{
++	u32 status, val;
++	u16 config_reg;
++
++	status = mt7530_read(priv, MT7531_PCS_CONTROL_1(port));
++	state->link = !!(status & MT7531_SGMII_LINK_STATUS);
++	if (state->interface == PHY_INTERFACE_MODE_SGMII &&
++	    (status & MT7531_SGMII_AN_ENABLE)) {
++		val = mt7530_read(priv, MT7531_PCS_SPEED_ABILITY(port));
++		config_reg = val >> 16;
++
++		switch (config_reg & LPA_SGMII_SPD_MASK) {
++		case LPA_SGMII_1000:
++			state->speed = SPEED_1000;
++			break;
++		case LPA_SGMII_100:
++			state->speed = SPEED_100;
++			break;
++		case LPA_SGMII_10:
++			state->speed = SPEED_10;
++			break;
++		default:
++			dev_err(priv->dev, "invalid sgmii PHY speed\n");
++			state->link = false;
++			return -EINVAL;
++		}
++
++		if (config_reg & LPA_SGMII_FULL_DUPLEX)
++			state->duplex = DUPLEX_FULL;
++		else
++			state->duplex = DUPLEX_HALF;
++	}
++
++	return 0;
++}
++#endif
++
++static int
++mt7531_phylink_mac_link_state(struct dsa_switch *ds, int port,
++			      struct phylink_link_state *state)
++{
++#ifdef notyet
++	struct mt7530_priv *priv = ds->priv;
++
++	if (state->interface == PHY_INTERFACE_MODE_SGMII)
++		return mt7531_sgmii_pcs_get_state_an(priv, port, state);
++#else
++	return mt7530_phylink_mac_link_state(ds, port, state);
++#endif
++
++	return -EOPNOTSUPP;
++}
++
+ static int
+ mt753x_phylink_mac_link_state(struct dsa_switch *ds, int port,
+ 			      struct phylink_link_state *state)
+@@ -1708,13 +2568,14 @@ static const struct dsa_switch_ops mt753
+ 	.port_vlan_prepare	= mt7530_port_vlan_prepare,
+ 	.port_vlan_add		= mt7530_port_vlan_add,
+ 	.port_vlan_del		= mt7530_port_vlan_del,
+-	.port_mirror_add	= mt7530_port_mirror_add,
+-	.port_mirror_del	= mt7530_port_mirror_del,
++	.port_mirror_add	= mt753x_port_mirror_add,
++	.port_mirror_del	= mt753x_port_mirror_del,
+ 	.phylink_validate	= mt753x_phylink_validate,
+ 	.phylink_mac_link_state	= mt753x_phylink_mac_link_state,
+ 	.phylink_mac_config	= mt753x_phylink_mac_config,
+-	.phylink_mac_link_down	= mt7530_phylink_mac_link_down,
+-	.phylink_mac_link_up	= mt7530_phylink_mac_link_up,
++	.phylink_mac_an_restart	= mt753x_phylink_mac_an_restart,
++	.phylink_mac_link_down	= mt753x_phylink_mac_link_down,
++	.phylink_mac_link_up	= mt753x_phylink_mac_link_up,
+ 	.get_mac_eee		= mt7530_get_mac_eee,
+ 	.set_mac_eee		= mt7530_set_mac_eee,
+ };
+@@ -1742,11 +2603,26 @@ static const struct mt753x_info mt753x_t
+ 		.mac_port_get_state = mt7530_phylink_mac_link_state,
+ 		.mac_port_config = mt7530_mac_config,
+ 	},
++	[ID_MT7531] = {
++		.id = ID_MT7531,
++		.sw_setup = mt7531_setup,
++		.phy_read = mt7531_ind_phy_read,
++		.phy_write = mt7531_ind_phy_write,
++		.pad_setup = mt7531_pad_setup,
++		.cpu_port_config = mt7531_cpu_port_config,
++		.phy_mode_supported = mt7531_phy_supported,
++		.mac_port_validate = mt7531_mac_port_validate,
++		.mac_port_get_state = mt7531_phylink_mac_link_state,
++		.mac_port_config = mt7531_mac_config,
++		.mac_pcs_an_restart = mt7531_sgmii_restart_an,
++		.mac_pcs_link_up = mt7531_sgmii_link_up_force,
++	},
+ };
+ 
+ static const struct of_device_id mt7530_of_match[] = {
+ 	{ .compatible = "mediatek,mt7621", .data = &mt753x_table[ID_MT7621], },
+ 	{ .compatible = "mediatek,mt7530", .data = &mt753x_table[ID_MT7530], },
++	{ .compatible = "mediatek,mt7531", .data = &mt753x_table[ID_MT7531], },
+ 	{ /* sentinel */ },
+ };
+ MODULE_DEVICE_TABLE(of, mt7530_of_match);
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -14,6 +14,7 @@
+ enum mt753x_id {
+ 	ID_MT7530 = 0,
+ 	ID_MT7621 = 1,
++	ID_MT7531 = 2,
+ };
+ 
+ #define	NUM_TRGMII_CTRL			5
+@@ -41,6 +42,33 @@ enum mt753x_id {
+ #define  MIRROR_PORT(x)			((x) & 0x7)
+ #define  MIRROR_MASK			0x7
+ 
++/* Registers for CPU forward control */
++#define MT7531_CFC			0x4
++#define  MT7531_MIRROR_EN		BIT(19)
++#define  MT7531_MIRROR_MASK		(MIRROR_MASK << 16)
++#define  MT7531_MIRROR_PORT_GET(x)	(((x) >> 16) & MIRROR_MASK)
++#define  MT7531_MIRROR_PORT_SET(x)	(((x) & MIRROR_MASK) << 16)
++#define  MT7531_CPU_PMAP_MASK		GENMASK(7, 0)
++
++#define MT753X_MIRROR_REG(id)		(((id) == ID_MT7531) ? \
++					 MT7531_CFC : MT7530_MFC)
++#define MT753X_MIRROR_EN(id)		(((id) == ID_MT7531) ? \
++					 MT7531_MIRROR_EN : MIRROR_EN)
++#define MT753X_MIRROR_MASK(id)		(((id) == ID_MT7531) ? \
++					 MT7531_MIRROR_MASK : MIRROR_MASK)
++
++/* Registers for BPDU and PAE frame control*/
++#define MT753X_BPC			0x24
++#define  MT753X_BPDU_PORT_FW_MASK	GENMASK(2, 0)
++
++enum mt753x_bpdu_port_fw {
++	MT753X_BPDU_FOLLOW_MFC,
++	MT753X_BPDU_CPU_EXCLUDE = 4,
++	MT753X_BPDU_CPU_INCLUDE = 5,
++	MT753X_BPDU_CPU_ONLY = 6,
++	MT753X_BPDU_DROP = 7,
++};
++
+ /* Registers for address table access */
+ #define MT7530_ATA1			0x74
+ #define  STATIC_EMP			0
+@@ -222,10 +250,30 @@ enum mt7530_vlan_port_attr {
+ #define  PMCR_FORCE_LNK			BIT(0)
+ #define  PMCR_SPEED_MASK		(PMCR_FORCE_SPEED_100 | \
+ 					 PMCR_FORCE_SPEED_1000)
++#define  MT7531_FORCE_LNK		BIT(31)
++#define  MT7531_FORCE_SPD		BIT(30)
++#define  MT7531_FORCE_DPX		BIT(29)
++#define  MT7531_FORCE_RX_FC		BIT(28)
++#define  MT7531_FORCE_TX_FC		BIT(27)
++#define  MT7531_FORCE_MODE		(MT7531_FORCE_LNK | \
++					 MT7531_FORCE_SPD | \
++					 MT7531_FORCE_DPX | \
++					 MT7531_FORCE_RX_FC | \
++					 MT7531_FORCE_TX_FC)
++#define  PMCR_FORCE_MODE_ID(id)		(((id) == ID_MT7531) ? \
++					 MT7531_FORCE_MODE : \
++					 PMCR_FORCE_MODE)
+ #define  PMCR_LINK_SETTINGS_MASK	(PMCR_TX_EN | PMCR_FORCE_SPEED_1000 | \
+ 					 PMCR_RX_EN | PMCR_FORCE_SPEED_100 | \
+ 					 PMCR_TX_FC_EN | PMCR_RX_FC_EN | \
+ 					 PMCR_FORCE_FDX | PMCR_FORCE_LNK)
++#define  PMCR_CPU_PORT_SETTING(id)	(PMCR_FORCE_MODE_ID((id)) | \
++					 PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \
++					 PMCR_BACKOFF_EN | PMCR_BACKPR_EN | \
++					 PMCR_TX_EN | PMCR_RX_EN | \
++					 PMCR_TX_FC_EN | PMCR_RX_FC_EN | \
++					 PMCR_FORCE_SPEED_1000 | \
++					 PMCR_FORCE_FDX | PMCR_FORCE_LNK)
+ 
+ #define MT7530_PMSR_P(x)		(0x3008 + (x) * 0x100)
+ #define  PMSR_EEE1G			BIT(7)
+@@ -245,6 +293,10 @@ enum mt7530_vlan_port_attr {
+ #define  LPI_THRESH(x)			((x & 0xFFF) << 4)
+ #define  LPI_MODE_EN			BIT(0)
+ 
++/* Register for port debug count */
++#define MT7531_DBG_CNT(x)		(0x3018 + (x) * 0x100)
++#define  MT7531_DIS_CLR			BIT(31)
++
+ /* Register for MIB */
+ #define MT7530_PORT_MIB_COUNTER(x)	(0x4000 + (x) * 0x100)
+ #define MT7530_MIB_CCR			0x4fe0
+@@ -262,12 +314,118 @@ enum mt7530_vlan_port_attr {
+ 					 CCR_RX_OCT_CNT_BAD | \
+ 					 CCR_TX_OCT_CNT_GOOD | \
+ 					 CCR_TX_OCT_CNT_BAD)
++
++/* MT7531 SGMII register group */
++#define MT7531_SGMII_REG_BASE		0x5000
++#define MT7531_SGMII_REG(p, r)		(MT7531_SGMII_REG_BASE + \
++					((p) - 5) * 0x1000 + (r))
++
++/* Register forSGMII PCS_CONTROL_1 */
++#define MT7531_PCS_CONTROL_1(p)		MT7531_SGMII_REG(p, 0x00)
++#define  MT7531_SGMII_LINK_STATUS	BIT(18)
++#define  MT7531_SGMII_AN_ENABLE		BIT(12)
++#define  MT7531_SGMII_AN_RESTART	BIT(9)
++
++/* Register for SGMII PCS_SPPED_ABILITY */
++#define MT7531_PCS_SPEED_ABILITY(p)	MT7531_SGMII_REG(p, 0x08)
++#define  MT7531_SGMII_TX_CONFIG_MASK	GENMASK(15, 0)
++#define  MT7531_SGMII_TX_CONFIG		BIT(0)
++
++/* Register for SGMII_MODE */
++#define MT7531_SGMII_MODE(p)		MT7531_SGMII_REG(p, 0x20)
++#define  MT7531_SGMII_REMOTE_FAULT_DIS	BIT(8)
++#define  MT7531_SGMII_IF_MODE_MASK	GENMASK(5, 1)
++#define  MT7531_SGMII_FORCE_DUPLEX	BIT(4)
++#define  MT7531_SGMII_FORCE_SPEED_MASK	GENMASK(3, 2)
++#define  MT7531_SGMII_FORCE_SPEED_1000	BIT(3)
++#define  MT7531_SGMII_FORCE_SPEED_100	BIT(2)
++#define  MT7531_SGMII_FORCE_SPEED_10	0
++#define  MT7531_SGMII_SPEED_DUPLEX_AN	BIT(1)
++
++enum mt7531_sgmii_force_duplex {
++	MT7531_SGMII_FORCE_FULL_DUPLEX = 0,
++	MT7531_SGMII_FORCE_HALF_DUPLEX = 0x10,
++};
++
++/* Fields of QPHY_PWR_STATE_CTRL */
++#define MT7531_QPHY_PWR_STATE_CTRL(p)	MT7531_SGMII_REG(p, 0xe8)
++#define  MT7531_SGMII_PHYA_PWD		BIT(4)
++
++/* Values of SGMII SPEED */
++#define MT7531_PHYA_CTRL_SIGNAL3(p)	MT7531_SGMII_REG(p, 0x128)
++#define  MT7531_RG_TPHY_SPEED_MASK	(BIT(2) | BIT(3))
++#define  MT7531_RG_TPHY_SPEED_1_25G	0x0
++#define  MT7531_RG_TPHY_SPEED_3_125G	BIT(2)
++
+ /* Register for system reset */
+ #define MT7530_SYS_CTRL			0x7000
+ #define  SYS_CTRL_PHY_RST		BIT(2)
+ #define  SYS_CTRL_SW_RST		BIT(1)
+ #define  SYS_CTRL_REG_RST		BIT(0)
+ 
++/* Register for PHY Indirect Access Control */
++#define MT7531_PHY_IAC			0x701C
++#define  MT7531_PHY_ACS_ST		BIT(31)
++#define  MT7531_MDIO_REG_ADDR_MASK	(0x1f << 25)
++#define  MT7531_MDIO_PHY_ADDR_MASK	(0x1f << 20)
++#define  MT7531_MDIO_CMD_MASK		(0x3 << 18)
++#define  MT7531_MDIO_ST_MASK		(0x3 << 16)
++#define  MT7531_MDIO_RW_DATA_MASK	(0xffff)
++#define  MT7531_MDIO_REG_ADDR(x)	(((x) & 0x1f) << 25)
++#define  MT7531_MDIO_DEV_ADDR(x)	(((x) & 0x1f) << 25)
++#define  MT7531_MDIO_PHY_ADDR(x)	(((x) & 0x1f) << 20)
++#define  MT7531_MDIO_CMD(x)		(((x) & 0x3) << 18)
++#define  MT7531_MDIO_ST(x)		(((x) & 0x3) << 16)
++
++enum mt7531_phy_iac_cmd {
++	MT7531_MDIO_ADDR = 0,
++	MT7531_MDIO_WRITE = 1,
++	MT7531_MDIO_READ = 2,
++	MT7531_MDIO_READ_CL45 = 3,
++};
++
++/* MDIO_ST: MDIO start field */
++enum mt7531_mdio_st {
++	MT7531_MDIO_ST_CL45 = 0,
++	MT7531_MDIO_ST_CL22 = 1,
++};
++
++#define  MT7531_MDIO_CL22_READ		(MT7531_MDIO_ST(MT7531_MDIO_ST_CL22) | \
++					 MT7531_MDIO_CMD(MT7531_MDIO_READ))
++#define  MT7531_MDIO_CL22_WRITE		(MT7531_MDIO_ST(MT7531_MDIO_ST_CL22) | \
++					 MT7531_MDIO_CMD(MT7531_MDIO_WRITE))
++#define  MT7531_MDIO_CL45_ADDR		(MT7531_MDIO_ST(MT7531_MDIO_ST_CL45) | \
++					 MT7531_MDIO_CMD(MT7531_MDIO_ADDR))
++#define  MT7531_MDIO_CL45_READ		(MT7531_MDIO_ST(MT7531_MDIO_ST_CL45) | \
++					 MT7531_MDIO_CMD(MT7531_MDIO_READ))
++#define  MT7531_MDIO_CL45_WRITE		(MT7531_MDIO_ST(MT7531_MDIO_ST_CL45) | \
++					 MT7531_MDIO_CMD(MT7531_MDIO_WRITE))
++
++/* Register for RGMII clock phase */
++#define MT7531_CLKGEN_CTRL		0x7500
++#define  CLK_SKEW_OUT(x)		(((x) & 0x3) << 8)
++#define  CLK_SKEW_OUT_MASK		GENMASK(9, 8)
++#define  CLK_SKEW_IN(x)			(((x) & 0x3) << 6)
++#define  CLK_SKEW_IN_MASK		GENMASK(7, 6)
++#define  RXCLK_NO_DELAY			BIT(5)
++#define  TXCLK_NO_REVERSE		BIT(4)
++#define  GP_MODE(x)			(((x) & 0x3) << 1)
++#define  GP_MODE_MASK			GENMASK(2, 1)
++#define  GP_CLK_EN			BIT(0)
++
++enum mt7531_gp_mode {
++	MT7531_GP_MODE_RGMII = 0,
++	MT7531_GP_MODE_MII = 1,
++	MT7531_GP_MODE_REV_MII = 2
++};
++
++enum mt7531_clk_skew {
++	MT7531_CLK_SKEW_NO_CHG = 0,
++	MT7531_CLK_SKEW_DLY_100PPS = 1,
++	MT7531_CLK_SKEW_DLY_200PPS = 2,
++	MT7531_CLK_SKEW_REVERSE = 3,
++};
++
+ /* Register for hw trap status */
+ #define MT7530_HWTRAP			0x7800
+ #define  HWTRAP_XTAL_MASK		(BIT(10) | BIT(9))
+@@ -275,6 +433,16 @@ enum mt7530_vlan_port_attr {
+ #define  HWTRAP_XTAL_40MHZ		(BIT(10))
+ #define  HWTRAP_XTAL_20MHZ		(BIT(9))
+ 
++#define MT7531_HWTRAP			0x7800
++#define  HWTRAP_XTAL_FSEL_MASK		BIT(7)
++#define  HWTRAP_XTAL_FSEL_25MHZ		BIT(7)
++#define  HWTRAP_XTAL_FSEL_40MHZ		0
++/* Unique fields of (M)HWSTRAP for MT7531 */
++#define  XTAL_FSEL_S			7
++#define  XTAL_FSEL_M			BIT(7)
++#define  PHY_EN				BIT(6)
++#define  CHG_STRAP			BIT(8)
++
+ /* Register for hw trap modification */
+ #define MT7530_MHWTRAP			0x7804
+ #define  MHWTRAP_PHY0_SEL		BIT(20)
+@@ -289,14 +457,37 @@ enum mt7530_vlan_port_attr {
+ #define MT7530_TOP_SIG_CTRL		0x7808
+ #define  TOP_SIG_CTRL_NORMAL		(BIT(17) | BIT(16))
+ 
++#define MT7531_TOP_SIG_SR		0x780c
++#define  PAD_DUAL_SGMII_EN		BIT(1)
++#define  PAD_MCM_SMI_EN			BIT(0)
++
+ #define MT7530_IO_DRV_CR		0x7810
+ #define  P5_IO_CLK_DRV(x)		((x) & 0x3)
+ #define  P5_IO_DATA_DRV(x)		(((x) & 0x3) << 4)
+ 
++#define MT7531_CHIP_REV			0x781C
++
++#define MT7531_PLLGP_EN			0x7820
++#define  EN_COREPLL			BIT(2)
++#define  SW_CLKSW			BIT(1)
++#define  SW_PLLGP			BIT(0)
++
+ #define MT7530_P6ECR			0x7830
+ #define  P6_INTF_MODE_MASK		0x3
+ #define  P6_INTF_MODE(x)		((x) & 0x3)
+ 
++#define MT7531_PLLGP_CR0		0x78a8
++#define  RG_COREPLL_EN			BIT(22)
++#define  RG_COREPLL_POSDIV_S		23
++#define  RG_COREPLL_POSDIV_M		0x3800000
++#define  RG_COREPLL_SDM_PCW_S		1
++#define  RG_COREPLL_SDM_PCW_M		0x3ffffe
++#define  RG_COREPLL_SDM_PCW_CHG		BIT(0)
++
++/* Registers for RGMII and SGMII PLL clock */
++#define MT7531_ANA_PLLGP_CR2		0x78b0
++#define MT7531_ANA_PLLGP_CR5		0x78bc
++
+ /* Registers for TRGMII on the both side */
+ #define MT7530_TRGMII_RCK_CTRL		0x7a00
+ #define  RX_RST				BIT(31)
+@@ -335,10 +526,25 @@ enum mt7530_vlan_port_attr {
+ #define MT7530_P5RGMIITXCR		0x7b04
+ #define  CSR_RGMII_TXC_CFG(x)		((x) & 0x1f)
+ 
++/* Registers for GPIO mode */
++#define MT7531_GPIO_MODE0		0x7c0c
++#define  MT7531_GPIO0_MASK		GENMASK(3, 0)
++#define  MT7531_GPIO0_INTERRUPT		1
++
++#define MT7531_GPIO_MODE1		0x7c10
++#define  MT7531_GPIO11_RG_RXD2_MASK	GENMASK(15, 12)
++#define  MT7531_EXT_P_MDC_11		(2 << 12)
++#define  MT7531_GPIO12_RG_RXD3_MASK	GENMASK(19, 16)
++#define  MT7531_EXT_P_MDIO_12		(2 << 16)
++
+ #define MT7530_CREV			0x7ffc
+ #define  CHIP_NAME_SHIFT		16
+ #define  MT7530_ID			0x7530
+ 
++#define MT7531_CREV			0x781C
++#define  CHIP_REV_M			0x0f
++#define  MT7531_ID			0x7531
++
+ /* Registers for core PLL access through mmd indirect */
+ #define CORE_PLL_GROUP2			0x401
+ #define  RG_SYSPLL_EN_NORMAL		BIT(15)
+@@ -355,6 +561,10 @@ enum mt7530_vlan_port_attr {
+ #define  RG_SYSPLL_DDSFBK_EN		BIT(12)
+ #define  RG_SYSPLL_BIAS_EN		BIT(11)
+ #define  RG_SYSPLL_BIAS_LPF_EN		BIT(10)
++#define  MT7531_PHY_PLL_OFF		BIT(5)
++#define  MT7531_PHY_PLL_BYPASS_MODE	BIT(4)
++
++#define MT753X_CTRL_PHY_ADDR		0
+ 
+ #define CORE_PLL_GROUP5			0x404
+ #define  RG_LCDDS_PCW_NCPO1(x)		((x) & 0xffff)
+@@ -433,6 +643,7 @@ enum p5_interface_select {
+ 	P5_INTF_SEL_PHY_P0,
+ 	P5_INTF_SEL_PHY_P4,
+ 	P5_INTF_SEL_GMAC5,
++	P5_INTF_SEL_GMAC5_SGMII,
+ };
+ 
+ static const char *p5_intf_modes(unsigned int p5_interface)
+@@ -446,6 +657,8 @@ static const char *p5_intf_modes(unsigne
+ 		return "PHY P4";
+ 	case P5_INTF_SEL_GMAC5:
+ 		return "GMAC5";
++	case P5_INTF_SEL_GMAC5_SGMII:
++		return "GMAC5_SGMII";
+ 	default:
+ 		return "unknown";
+ 	}
+@@ -466,6 +679,10 @@ static const char *p5_intf_modes(unsigne
+  *			MAC port
+  * @mac_port_config:	Holding the way setting up the PHY attribute to a
+  *			certain MAC port
++ * @mac_pcs_an_restart	Holding the way restarting PCS autonegotiation for a
++ *			certain MAC port
++ * @mac_pcs_link_up:	Holding the way setting up the PHY attribute to the pcs
++ *			of the certain MAC port
+  */
+ struct mt753x_info {
+ 	enum mt753x_id id;
+@@ -474,6 +691,7 @@ struct mt753x_info {
+ 	int (*phy_read)(struct dsa_switch *ds, int port, int regnum);
+ 	int (*phy_write)(struct dsa_switch *ds, int port, int regnum, u16 val);
+ 	int (*pad_setup)(struct dsa_switch *ds, phy_interface_t interface);
++	int (*cpu_port_config)(struct dsa_switch *ds, int port);
+ 	bool (*phy_mode_supported)(struct dsa_switch *ds, int port,
+ 				   const struct phylink_link_state *state);
+ 	void (*mac_port_validate)(struct dsa_switch *ds, int port,
+@@ -483,6 +701,10 @@ struct mt753x_info {
+ 	int (*mac_port_config)(struct dsa_switch *ds, int port,
+ 			       unsigned int mode,
+ 			       phy_interface_t interface);
++	void (*mac_pcs_an_restart)(struct dsa_switch *ds, int port);
++	void (*mac_pcs_link_up)(struct dsa_switch *ds, int port,
++				unsigned int mode, phy_interface_t interface,
++				int speed, int duplex);
+ };
+ 
+ /* struct mt7530_priv -	This is the main data structure for holding the state
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0605-arm64-dts-mt7622-add-mt7531-dsa-to-bananapi-bpi-r64-board.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0605-arm64-dts-mt7622-add-mt7531-dsa-to-bananapi-bpi-r64-board.patch
new file mode 100644
index 0000000..8c3fe52
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0605-arm64-dts-mt7622-add-mt7531-dsa-to-bananapi-bpi-r64-board.patch
@@ -0,0 +1,71 @@
+From: Landen Chao <landen.chao@mediatek.com>
+Subject: [PATCH net-next 6/6] arm64: dts: mt7622: add mt7531 dsa to
+ bananapi-bpi-r64 board
+Date: Tue, 10 Dec 2019 16:14:42 +0800
+
+Add mt7531 dsa to bananapi-bpi-r64 board for 5 giga Ethernet ports support.
+
+Signed-off-by: Landen Chao <landen.chao@mediatek.com>
+---
+ .../dts/mediatek/mt7622-bananapi-bpi-r64.dts  | 50 +++++++++++++++++++
+ 1 file changed, 50 insertions(+)
+
+--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
+@@ -150,6 +150,56 @@
+ 	mdio: mdio-bus {
+ 		#address-cells = <1>;
+ 		#size-cells = <0>;
++
++		switch@0 {
++			compatible = "mediatek,mt7531";
++			reg = <0>;
++			reset-gpios = <&pio 54 0>;
++
++			ports {
++				#address-cells = <1>;
++				#size-cells = <0>;
++
++				port@0 {
++					reg = <0>;
++					label = "wan";
++				};
++
++				port@1 {
++					reg = <1>;
++					label = "lan0";
++				};
++
++				port@2 {
++					reg = <2>;
++					label = "lan1";
++				};
++
++				port@3 {
++					reg = <3>;
++					label = "lan2";
++				};
++
++				port@4 {
++					reg = <4>;
++					label = "lan3";
++				};
++
++				port@6 {
++					reg = <6>;
++					label = "cpu";
++					ethernet = <&gmac0>;
++					phy-mode = "2500base-x";
++
++					fixed-link {
++						speed = <2500>;
++						full-duplex;
++						pause;
++					};
++				};
++			};
++		};
++
+ 	};
+ };
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0666-add-spimem-support-to-mtk-spi.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0666-add-spimem-support-to-mtk-spi.patch
new file mode 100644
index 0000000..d50aa25
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0666-add-spimem-support-to-mtk-spi.patch
@@ -0,0 +1,636 @@
+From 675b477b2a50b2fb97f35944756f89644bf70092 Mon Sep 17 00:00:00 2001
+From: Qii Wang <qii.wang@mediatek.com>
+Date: Tue, 5 Jan 2021 16:48:39 +0800
+Subject: [PATCH] spi: mediatek: support IPM Design
+
+[Description]
+1. support sigle mode;
+2. support dual/quad mode with spi-mem framework.
+
+Signed-off-by: Leilk Liu <leilk.liu@mediatek.com>
+Reviewed-by: Qii Wang <qii.wang@mediatek.com>
+---
+ drivers/spi/spi-mt65xx.c                 | 395 +++++++++++++++++++++--
+ include/linux/platform_data/spi-mt65xx.h |   2 +-
+ 2 files changed, 370 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c
+index 8acf24f7c..9183c64e4 100644
+--- a/drivers/spi/spi-mt65xx.c
++++ b/drivers/spi/spi-mt65xx.c
+@@ -17,6 +17,7 @@
+ #include <linux/platform_data/spi-mt65xx.h>
+ #include <linux/pm_runtime.h>
+ #include <linux/spi/spi.h>
++#include <linux/spi/spi-mem.h>
+ #include <linux/dma-mapping.h>
+ 
+ #define SPI_CFG0_REG                      0x0000
+@@ -31,6 +32,7 @@
+ #define SPI_CFG2_REG                      0x0028
+ #define SPI_TX_SRC_REG_64                 0x002c
+ #define SPI_RX_DST_REG_64                 0x0030
++#define SPI_CFG3_IPM_REG                  0x0040
+ 
+ #define SPI_CFG0_SCK_HIGH_OFFSET          0
+ #define SPI_CFG0_SCK_LOW_OFFSET           8
+@@ -42,13 +44,15 @@
+ #define SPI_CFG1_CS_IDLE_OFFSET           0
+ #define SPI_CFG1_PACKET_LOOP_OFFSET       8
+ #define SPI_CFG1_PACKET_LENGTH_OFFSET     16
+-#define SPI_CFG1_GET_TICK_DLY_OFFSET      30
++#define SPI_CFG1_GET_TICKDLY_OFFSET       29
+ 
++#define SPI_CFG1_GET_TICKDLY_MASK	  GENMASK(31, 29)
+ #define SPI_CFG1_CS_IDLE_MASK             0xff
+ #define SPI_CFG1_PACKET_LOOP_MASK         0xff00
+ #define SPI_CFG1_PACKET_LENGTH_MASK       0x3ff0000
++#define SPI_CFG1_IPM_PACKET_LENGTH_MASK   GENMASK(31, 16)
+ #define SPI_CFG2_SCK_HIGH_OFFSET          0
+-#define SPI_CFG2_SCK_LOW_OFFSET           16
++#define SPI_CFG2_SCK_LOW_OFFSET		  16
+ 
+ #define SPI_CMD_ACT                  BIT(0)
+ #define SPI_CMD_RESUME               BIT(1)
+@@ -67,6 +71,25 @@
+ #define SPI_CMD_TX_ENDIAN            BIT(15)
+ #define SPI_CMD_FINISH_IE            BIT(16)
+ #define SPI_CMD_PAUSE_IE             BIT(17)
++#define SPI_CMD_IPM_NONIDLE_MODE     BIT(19)
++#define SPI_CMD_IPM_SPIM_LOOP        BIT(21)
++#define SPI_CMD_IPM_GET_TICKDLY_OFFSET    22
++
++#define SPI_CMD_IPM_GET_TICKDLY_MASK	GENMASK(24, 22)
++
++#define PIN_MODE_CFG(x)	((x) / 2)
++
++#define SPI_CFG3_IPM_PIN_MODE_OFFSET		0
++#define SPI_CFG3_IPM_HALF_DUPLEX_DIR		BIT(2)
++#define SPI_CFG3_IPM_HALF_DUPLEX_EN		BIT(3)
++#define SPI_CFG3_IPM_XMODE_EN			BIT(4)
++#define SPI_CFG3_IPM_NODATA_FLAG		BIT(5)
++#define SPI_CFG3_IPM_CMD_BYTELEN_OFFSET		8
++#define SPI_CFG3_IPM_ADDR_BYTELEN_OFFSET	12
++
++#define SPI_CFG3_IPM_CMD_PIN_MODE_MASK		GENMASK(1, 0)
++#define SPI_CFG3_IPM_CMD_BYTELEN_MASK		GENMASK(11, 8)
++#define SPI_CFG3_IPM_ADDR_BYTELEN_MASK		GENMASK(15, 12)
+ 
+ #define MT8173_SPI_MAX_PAD_SEL 3
+ 
+@@ -77,6 +100,9 @@
+ 
+ #define MTK_SPI_MAX_FIFO_SIZE 32U
+ #define MTK_SPI_PACKET_SIZE 1024
++#define MTK_SPI_IPM_PACKET_SIZE SZ_64K
++#define MTK_SPI_IPM_PACKET_LOOP SZ_256
++
+ #define MTK_SPI_32BITS_MASK  (0xffffffff)
+ 
+ #define DMA_ADDR_EXT_BITS (36)
+@@ -90,6 +116,9 @@ struct mtk_spi_compatible {
+ 	bool enhance_timing;
+ 	/* some IC support DMA addr extension */
+ 	bool dma_ext;
++	/* the IPM IP design improve some feature, and support dual/quad mode */
++	bool ipm_design;
++	bool support_quad;
+ };
+ 
+ struct mtk_spi {
+@@ -104,6 +133,12 @@ struct mtk_spi {
+ 	struct scatterlist *tx_sgl, *rx_sgl;
+ 	u32 tx_sgl_len, rx_sgl_len;
+ 	const struct mtk_spi_compatible *dev_comp;
++
++	struct completion spimem_done;
++	bool use_spimem;
++	struct device *dev;
++	dma_addr_t tx_dma;
++	dma_addr_t rx_dma;
+ };
+ 
+ static const struct mtk_spi_compatible mtk_common_compat;
+@@ -112,6 +147,14 @@ static const struct mtk_spi_compatible mt2712_compat = {
+ 	.must_tx = true,
+ };
+ 
++static const struct mtk_spi_compatible ipm_compat = {
++	.must_tx = true,
++	.enhance_timing = true,
++	.dma_ext = true,
++	.ipm_design = true,
++	.support_quad = true,
++};
++
+ static const struct mtk_spi_compatible mt6765_compat = {
+ 	.need_pad_sel = true,
+ 	.must_tx = true,
+@@ -140,11 +183,14 @@ static const struct mtk_spi_compatible mt8183_compat = {
+  * supplies it.
+  */
+ static const struct mtk_chip_config mtk_default_chip_info = {
+-	.cs_pol = 0,
+ 	.sample_sel = 0,
++	.get_tick_dly = 0,
+ };
+ 
+ static const struct of_device_id mtk_spi_of_match[] = {
++	{ .compatible = "mediatek,ipm-spi",
++		.data = (void *)&ipm_compat,
++	},
+ 	{ .compatible = "mediatek,mt2701-spi",
+ 		.data = (void *)&mtk_common_compat,
+ 	},
+@@ -190,19 +236,48 @@ static void mtk_spi_reset(struct mtk_spi *mdata)
+ 	writel(reg_val, mdata->base + SPI_CMD_REG);
+ }
+ 
+-static int mtk_spi_prepare_message(struct spi_master *master,
+-				   struct spi_message *msg)
++static int mtk_spi_hw_init(struct spi_master *master,
++			   struct spi_device *spi)
+ {
+ 	u16 cpha, cpol;
+ 	u32 reg_val;
+-	struct spi_device *spi = msg->spi;
+ 	struct mtk_chip_config *chip_config = spi->controller_data;
+ 	struct mtk_spi *mdata = spi_master_get_devdata(master);
+ 
+ 	cpha = spi->mode & SPI_CPHA ? 1 : 0;
+ 	cpol = spi->mode & SPI_CPOL ? 1 : 0;
+ 
++	if (mdata->dev_comp->enhance_timing) {
++		if (mdata->dev_comp->ipm_design) {
++			/* CFG3 reg only used for spi-mem,
++			 * here write to default value
++			 */
++			writel(0x0, mdata->base + SPI_CFG3_IPM_REG);
++
++			reg_val = readl(mdata->base + SPI_CMD_REG);
++			reg_val &= ~SPI_CMD_IPM_GET_TICKDLY_MASK;
++			reg_val |= chip_config->get_tick_dly
++				   << SPI_CMD_IPM_GET_TICKDLY_OFFSET;
++			writel(reg_val, mdata->base + SPI_CMD_REG);
++		} else {
++			reg_val = readl(mdata->base + SPI_CFG1_REG);
++			reg_val &= ~SPI_CFG1_GET_TICKDLY_MASK;
++			reg_val |= chip_config->get_tick_dly
++				   << SPI_CFG1_GET_TICKDLY_OFFSET;
++			writel(reg_val, mdata->base + SPI_CFG1_REG);
++		}
++	}
++
+ 	reg_val = readl(mdata->base + SPI_CMD_REG);
++	if (mdata->dev_comp->ipm_design) {
++		/* SPI transfer without idle time until packet length done */
++		reg_val |= SPI_CMD_IPM_NONIDLE_MODE;
++		if (spi->mode & SPI_LOOP)
++			reg_val |= SPI_CMD_IPM_SPIM_LOOP;
++		else
++			reg_val &= ~SPI_CMD_IPM_SPIM_LOOP;
++	}
++
+ 	if (cpha)
+ 		reg_val |= SPI_CMD_CPHA;
+ 	else
+@@ -231,10 +306,12 @@ static int mtk_spi_prepare_message(struct spi_master *master,
+ #endif
+ 
+ 	if (mdata->dev_comp->enhance_timing) {
+-		if (chip_config->cs_pol)
++		/* set CS polarity */
++		if (spi->mode & SPI_CS_HIGH)
+ 			reg_val |= SPI_CMD_CS_POL;
+ 		else
+ 			reg_val &= ~SPI_CMD_CS_POL;
++
+ 		if (chip_config->sample_sel)
+ 			reg_val |= SPI_CMD_SAMPLE_SEL;
+ 		else
+@@ -260,11 +337,20 @@ static int mtk_spi_prepare_message(struct spi_master *master,
+ 	return 0;
+ }
+ 
++static int mtk_spi_prepare_message(struct spi_master *master,
++				   struct spi_message *msg)
++{
++	return mtk_spi_hw_init(master, msg->spi);
++}
++
+ static void mtk_spi_set_cs(struct spi_device *spi, bool enable)
+ {
+ 	u32 reg_val;
+ 	struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
+ 
++	if (spi->mode & SPI_CS_HIGH)
++		enable = !enable;
++
+ 	reg_val = readl(mdata->base + SPI_CMD_REG);
+ 	if (!enable) {
+ 		reg_val |= SPI_CMD_PAUSE_EN;
+@@ -278,14 +364,14 @@ static void mtk_spi_set_cs(struct spi_device *spi, bool enable)
+ }
+ 
+ static void mtk_spi_prepare_transfer(struct spi_master *master,
+-				     struct spi_transfer *xfer)
++				     u32 speed_hz)
+ {
+ 	u32 spi_clk_hz, div, sck_time, cs_time, reg_val;
+ 	struct mtk_spi *mdata = spi_master_get_devdata(master);
+ 
+ 	spi_clk_hz = clk_get_rate(mdata->spi_clk);
+-	if (xfer->speed_hz < spi_clk_hz / 2)
+-		div = DIV_ROUND_UP(spi_clk_hz, xfer->speed_hz);
++	if (speed_hz < spi_clk_hz / 2)
++		div = DIV_ROUND_UP(spi_clk_hz, speed_hz);
+ 	else
+ 		div = 1;
+ 
+@@ -323,12 +409,24 @@ static void mtk_spi_setup_packet(struct spi_master *master)
+ 	u32 packet_size, packet_loop, reg_val;
+ 	struct mtk_spi *mdata = spi_master_get_devdata(master);
+ 
+-	packet_size = min_t(u32, mdata->xfer_len, MTK_SPI_PACKET_SIZE);
++	if (mdata->dev_comp->ipm_design)
++		packet_size = min_t(u32,
++				    mdata->xfer_len,
++				    MTK_SPI_IPM_PACKET_SIZE);
++	else
++		packet_size = min_t(u32,
++				    mdata->xfer_len,
++				    MTK_SPI_PACKET_SIZE);
++
+ 	packet_loop = mdata->xfer_len / packet_size;
+ 
+ 	reg_val = readl(mdata->base + SPI_CFG1_REG);
+-	reg_val &= ~(SPI_CFG1_PACKET_LENGTH_MASK | SPI_CFG1_PACKET_LOOP_MASK);
++	if (mdata->dev_comp->ipm_design)
++		reg_val &= ~SPI_CFG1_IPM_PACKET_LENGTH_MASK;
++	else
++		reg_val &= ~SPI_CFG1_PACKET_LENGTH_MASK;
+ 	reg_val |= (packet_size - 1) << SPI_CFG1_PACKET_LENGTH_OFFSET;
++	reg_val &= ~SPI_CFG1_PACKET_LOOP_MASK;
+ 	reg_val |= (packet_loop - 1) << SPI_CFG1_PACKET_LOOP_OFFSET;
+ 	writel(reg_val, mdata->base + SPI_CFG1_REG);
+ }
+@@ -423,7 +521,7 @@ static int mtk_spi_fifo_transfer(struct spi_master *master,
+ 	mdata->cur_transfer = xfer;
+ 	mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, xfer->len);
+ 	mdata->num_xfered = 0;
+-	mtk_spi_prepare_transfer(master, xfer);
++	mtk_spi_prepare_transfer(master, xfer->speed_hz);
+ 	mtk_spi_setup_packet(master);
+ 
+ 	cnt = xfer->len / 4;
+@@ -455,7 +553,7 @@ static int mtk_spi_dma_transfer(struct spi_master *master,
+ 	mdata->cur_transfer = xfer;
+ 	mdata->num_xfered = 0;
+ 
+-	mtk_spi_prepare_transfer(master, xfer);
++	mtk_spi_prepare_transfer(master, xfer->speed_hz);
+ 
+ 	cmd = readl(mdata->base + SPI_CMD_REG);
+ 	if (xfer->tx_buf)
+@@ -532,6 +630,13 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
+ 	else
+ 		mdata->state = MTK_SPI_IDLE;
+ 
++	/* SPI-MEM ops */
++	if (mdata->use_spimem) {
++		complete(&mdata->spimem_done);
++
++		return IRQ_HANDLED;
++	}
++
+ 	if (!master->can_dma(master, NULL, trans)) {
+ 		if (trans->rx_buf) {
+ 			cnt = mdata->xfer_len / 4;
+@@ -615,12 +720,241 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
+ 	return IRQ_HANDLED;
+ }
+ 
++static bool mtk_spi_mem_supports_op(struct spi_mem *mem,
++				     const struct spi_mem_op *op)
++{
++	if (op->data.buswidth > 4 || op->addr.buswidth > 4 ||
++	    op->dummy.buswidth > 4 || op->cmd.buswidth > 4)
++		return false;
++
++	if (op->addr.nbytes && op->dummy.nbytes &&
++	    op->addr.buswidth != op->dummy.buswidth)
++		return false;
++
++	if (op->addr.nbytes + op->dummy.nbytes > 16)
++		return false;
++
++	if (op->data.nbytes > MTK_SPI_IPM_PACKET_SIZE) {
++		if (op->data.nbytes / MTK_SPI_IPM_PACKET_SIZE >
++		    MTK_SPI_IPM_PACKET_LOOP ||
++		    op->data.nbytes % MTK_SPI_IPM_PACKET_SIZE != 0)
++			return false;
++	}
++
++	if (op->data.dir == SPI_MEM_DATA_IN &&
++	    !IS_ALIGNED((size_t)op->data.buf.in, 4))
++		return false;
++
++	return true;
++}
++
++static void mtk_spi_mem_setup_dma_xfer(struct spi_master *master,
++				   const struct spi_mem_op *op)
++{
++	struct mtk_spi *mdata = spi_master_get_devdata(master);
++
++	writel((u32)(mdata->tx_dma & MTK_SPI_32BITS_MASK),
++	       mdata->base + SPI_TX_SRC_REG);
++#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
++	if (mdata->dev_comp->dma_ext)
++		writel((u32)(mdata->tx_dma >> 32),
++		       mdata->base + SPI_TX_SRC_REG_64);
++#endif
++
++	if (op->data.dir == SPI_MEM_DATA_IN) {
++		writel((u32)(mdata->rx_dma & MTK_SPI_32BITS_MASK),
++			   mdata->base + SPI_RX_DST_REG);
++#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
++		if (mdata->dev_comp->dma_ext)
++			writel((u32)(mdata->rx_dma >> 32),
++				   mdata->base + SPI_RX_DST_REG_64);
++#endif
++	}
++}
++
++static int mtk_spi_transfer_wait(struct spi_mem *mem,
++				 const struct spi_mem_op *op)
++{
++	struct mtk_spi *mdata = spi_master_get_devdata(mem->spi->master);
++	unsigned long long ms = 1;
++
++	if (op->data.dir == SPI_MEM_NO_DATA)
++		ms = 8LL * 1000LL * 32;
++	else
++		ms = 8LL * 1000LL * op->data.nbytes;
++	do_div(ms, mem->spi->max_speed_hz);
++	ms += ms + 1000; /* 1s tolerance */
++
++	if (ms > UINT_MAX)
++		ms = UINT_MAX;
++
++	if (!wait_for_completion_timeout(&mdata->spimem_done,
++					 msecs_to_jiffies(ms))) {
++		dev_err(mdata->dev, "spi-mem transfer timeout\n");
++		return -ETIMEDOUT;
++	}
++
++	return 0;
++}
++
++static int mtk_spi_mem_exec_op(struct spi_mem *mem,
++				const struct spi_mem_op *op)
++{
++	struct mtk_spi *mdata = spi_master_get_devdata(mem->spi->master);
++	u32 reg_val, nio = 1, tx_size;
++	char *tx_tmp_buf;
++	int ret = 0;
++
++	mdata->use_spimem = true;
++	reinit_completion(&mdata->spimem_done);
++
++	mtk_spi_reset(mdata);
++	mtk_spi_hw_init(mem->spi->master, mem->spi);
++	mtk_spi_prepare_transfer(mem->spi->master, mem->spi->max_speed_hz);
++
++	reg_val = readl(mdata->base + SPI_CFG3_IPM_REG);
++	/* opcode byte len */
++	reg_val &= ~SPI_CFG3_IPM_CMD_BYTELEN_MASK;
++	reg_val |= 1 << SPI_CFG3_IPM_CMD_BYTELEN_OFFSET;
++
++	/* addr & dummy byte len */
++	reg_val &= ~SPI_CFG3_IPM_ADDR_BYTELEN_MASK;
++	if (op->addr.nbytes || op->dummy.nbytes)
++		reg_val |= (op->addr.nbytes + op->dummy.nbytes) <<
++			    SPI_CFG3_IPM_ADDR_BYTELEN_OFFSET;
++
++	/* data byte len */
++	if (op->data.dir == SPI_MEM_NO_DATA) {
++		reg_val |= SPI_CFG3_IPM_NODATA_FLAG;
++		writel(0, mdata->base + SPI_CFG1_REG);
++	} else {
++		reg_val &= ~SPI_CFG3_IPM_NODATA_FLAG;
++		mdata->xfer_len = op->data.nbytes;
++		mtk_spi_setup_packet(mem->spi->master);
++	}
++
++	if (op->addr.nbytes || op->dummy.nbytes) {
++		if (op->addr.buswidth == 1 || op->dummy.buswidth == 1)
++			reg_val |= SPI_CFG3_IPM_XMODE_EN;
++		else
++			reg_val &= ~SPI_CFG3_IPM_XMODE_EN;
++	}
++
++	if (op->addr.buswidth == 2 ||
++	    op->dummy.buswidth == 2 ||
++	    op->data.buswidth == 2)
++		nio = 2;
++	else if (op->addr.buswidth == 4 ||
++		 op->dummy.buswidth == 4 ||
++		 op->data.buswidth == 4)
++		nio = 4;
++
++	reg_val &= ~SPI_CFG3_IPM_CMD_PIN_MODE_MASK;
++	reg_val |= PIN_MODE_CFG(nio) << SPI_CFG3_IPM_PIN_MODE_OFFSET;
++
++	reg_val |= SPI_CFG3_IPM_HALF_DUPLEX_EN;
++	if (op->data.dir == SPI_MEM_DATA_IN)
++		reg_val |= SPI_CFG3_IPM_HALF_DUPLEX_DIR;
++	else
++		reg_val &= ~SPI_CFG3_IPM_HALF_DUPLEX_DIR;
++	writel(reg_val, mdata->base + SPI_CFG3_IPM_REG);
++
++	tx_size = 1 + op->addr.nbytes + op->dummy.nbytes;
++	if (op->data.dir == SPI_MEM_DATA_OUT)
++		tx_size += op->data.nbytes;
++
++	tx_size = max(tx_size, (u32)32);
++
++	tx_tmp_buf = kzalloc(tx_size, GFP_KERNEL | GFP_DMA);
++	if (!tx_tmp_buf)
++		return -ENOMEM;
++
++	tx_tmp_buf[0] = op->cmd.opcode;
++
++	if (op->addr.nbytes) {
++		int i;
++
++		for (i = 0; i < op->addr.nbytes; i++)
++			tx_tmp_buf[i + 1] = op->addr.val >>
++					(8 * (op->addr.nbytes - i - 1));
++	}
++
++	if (op->dummy.nbytes)
++		memset(tx_tmp_buf + op->addr.nbytes + 1,
++		       0xff,
++		       op->dummy.nbytes);
++
++	if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT)
++		memcpy(tx_tmp_buf + op->dummy.nbytes + op->addr.nbytes + 1,
++		       op->data.buf.out,
++		       op->data.nbytes);
++
++	mdata->tx_dma = dma_map_single(mdata->dev, tx_tmp_buf,
++				       tx_size, DMA_TO_DEVICE);
++	if (dma_mapping_error(mdata->dev, mdata->tx_dma)) {
++		ret = -ENOMEM;
++		goto err_exit;
++	}
++
++	if (op->data.dir == SPI_MEM_DATA_IN) {
++		mdata->rx_dma = dma_map_single(mdata->dev,
++					       op->data.buf.in,
++					       op->data.nbytes,
++					       DMA_FROM_DEVICE);
++		if (dma_mapping_error(mdata->dev, mdata->rx_dma)) {
++			ret = -ENOMEM;
++			goto unmap_tx_dma;
++		}
++	}
++
++	reg_val = readl(mdata->base + SPI_CMD_REG);
++	reg_val |= SPI_CMD_TX_DMA;
++	if (op->data.dir == SPI_MEM_DATA_IN)
++		reg_val |= SPI_CMD_RX_DMA;
++	writel(reg_val, mdata->base + SPI_CMD_REG);
++
++	mtk_spi_mem_setup_dma_xfer(mem->spi->master, op);
++
++	mtk_spi_enable_transfer(mem->spi->master);
++
++	/* Wait for the interrupt. */
++	ret = mtk_spi_transfer_wait(mem, op);
++	if (ret)
++		goto unmap_rx_dma;
++
++	/* spi disable dma */
++	reg_val = readl(mdata->base + SPI_CMD_REG);
++	reg_val &= ~SPI_CMD_TX_DMA;
++	if (op->data.dir == SPI_MEM_DATA_IN)
++		reg_val &= ~SPI_CMD_RX_DMA;
++	writel(reg_val, mdata->base + SPI_CMD_REG);
++
++	if (op->data.dir == SPI_MEM_DATA_IN)
++		dma_unmap_single(mdata->dev, mdata->rx_dma,
++				 op->data.nbytes, DMA_FROM_DEVICE);
++unmap_rx_dma:
++	dma_unmap_single(mdata->dev, mdata->rx_dma,
++			 op->data.nbytes, DMA_FROM_DEVICE);
++unmap_tx_dma:
++	dma_unmap_single(mdata->dev, mdata->tx_dma,
++			 tx_size, DMA_TO_DEVICE);
++err_exit:
++	kfree(tx_tmp_buf);
++	mdata->use_spimem = false;
++
++	return ret;
++}
++
++static const struct spi_controller_mem_ops mtk_spi_mem_ops = {
++	.supports_op = mtk_spi_mem_supports_op,
++	.exec_op = mtk_spi_mem_exec_op,
++};
++
+ static int mtk_spi_probe(struct platform_device *pdev)
+ {
+ 	struct spi_master *master;
+ 	struct mtk_spi *mdata;
+ 	const struct of_device_id *of_id;
+-	struct resource *res;
+ 	int i, irq, ret, addr_bits;
+ 
+ 	master = spi_alloc_master(&pdev->dev, sizeof(*mdata));
+@@ -629,7 +963,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
+ 		return -ENOMEM;
+ 	}
+ 
+-	master->auto_runtime_pm = true;
++//	master->auto_runtime_pm = true;
+ 	master->dev.of_node = pdev->dev.of_node;
+ 	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+ 
+@@ -648,9 +982,25 @@ static int mtk_spi_probe(struct platform_device *pdev)
+ 
+ 	mdata = spi_master_get_devdata(master);
+ 	mdata->dev_comp = of_id->data;
++
++	if (mdata->dev_comp->enhance_timing)
++		master->mode_bits |= SPI_CS_HIGH;
++
+ 	if (mdata->dev_comp->must_tx)
+ 		master->flags = SPI_MASTER_MUST_TX;
+ 
++	if (mdata->dev_comp->ipm_design)
++		master->mode_bits |= SPI_LOOP;
++
++	if (mdata->dev_comp->support_quad) {
++		master->mem_ops = &mtk_spi_mem_ops;
++		master->mode_bits |= SPI_RX_DUAL | SPI_TX_DUAL |
++				     SPI_RX_QUAD | SPI_TX_QUAD;
++
++		mdata->dev = &pdev->dev;
++		init_completion(&mdata->spimem_done);
++	}
++
+ 	if (mdata->dev_comp->need_pad_sel) {
+ 		mdata->pad_num = of_property_count_u32_elems(
+ 			pdev->dev.of_node,
+@@ -683,15 +1033,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
+ 	}
+ 
+ 	platform_set_drvdata(pdev, master);
+-
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	if (!res) {
+-		ret = -ENODEV;
+-		dev_err(&pdev->dev, "failed to determine base address\n");
+-		goto err_put_master;
+-	}
+-
+-	mdata->base = devm_ioremap_resource(&pdev->dev, res);
++	mdata->base = devm_platform_ioremap_resource(pdev, 0);
+ 	if (IS_ERR(mdata->base)) {
+ 		ret = PTR_ERR(mdata->base);
+ 		goto err_put_master;
+@@ -713,6 +1055,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
+ 		goto err_put_master;
+ 	}
+ 
++/*
+ 	mdata->parent_clk = devm_clk_get(&pdev->dev, "parent-clk");
+ 	if (IS_ERR(mdata->parent_clk)) {
+ 		ret = PTR_ERR(mdata->parent_clk);
+@@ -750,7 +1093,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
+ 	clk_disable_unprepare(mdata->spi_clk);
+ 
+ 	pm_runtime_enable(&pdev->dev);
+-
++*/
+ 	ret = devm_spi_register_master(&pdev->dev, master);
+ 	if (ret) {
+ 		dev_err(&pdev->dev, "failed to register master (%d)\n", ret);
+diff --git a/include/linux/platform_data/spi-mt65xx.h b/include/linux/platform_data/spi-mt65xx.h
+index f0e6d6483..fae9bc15c 100644
+--- a/include/linux/platform_data/spi-mt65xx.h
++++ b/include/linux/platform_data/spi-mt65xx.h
+@@ -11,7 +11,7 @@
+ 
+ /* Board specific platform_data */
+ struct mtk_chip_config {
+-	u32 cs_pol;
+ 	u32 sample_sel;
++	u32 get_tick_dly;
+ };
+ #endif
+-- 
+2.17.1
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0666-spi-mtk-nor-fix-timeout-calculation-overflow.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0666-spi-mtk-nor-fix-timeout-calculation-overflow.patch
new file mode 100644
index 0000000..86b2089
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0666-spi-mtk-nor-fix-timeout-calculation-overflow.patch
@@ -0,0 +1,179 @@
+From patchwork Tue Sep 22 11:49:02 2020
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: Chuanhong Guo <gch981213@gmail.com>
+X-Patchwork-Id: 11792387
+Return-Path: 
+ <SRS0=i66O=C7=lists.infradead.org=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@kernel.org>
+Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org
+ [172.30.200.123])
+	by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 21EB0618
+	for <patchwork-linux-arm@patchwork.kernel.org>;
+ Tue, 22 Sep 2020 11:51:33 +0000 (UTC)
+Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134])
+	(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
+	(No client certificate requested)
+	by mail.kernel.org (Postfix) with ESMTPS id E15FF221EB
+	for <patchwork-linux-arm@patchwork.kernel.org>;
+ Tue, 22 Sep 2020 11:51:32 +0000 (UTC)
+Authentication-Results: mail.kernel.org;
+	dkim=pass (2048-bit key) header.d=lists.infradead.org
+ header.i=@lists.infradead.org header.b="KBg/skkC";
+	dkim=fail reason="signature verification failed" (2048-bit key)
+ header.d=gmail.com header.i=@gmail.com header.b="Gtqp4rrT"
+DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E15FF221EB
+Authentication-Results: mail.kernel.org;
+ dmarc=fail (p=none dis=none) header.from=gmail.com
+Authentication-Results: mail.kernel.org;
+ spf=none
+ smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
+	d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding:
+	Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive:
+	List-Unsubscribe:List-Id:MIME-Version:Message-Id:Date:Subject:To:From:
+	Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender
+	:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Owner;
+	bh=Xg61WV47qNPjINdHDPnF6T3q8GN8f9evwhTMdYR0Zqs=; b=KBg/skkCvnF7/8AlleTay0p/H2
+	hC4Lzo+slWhX5/eepUEXzhTr5ORf4Dx9gD65UEuordKQKFpg6Y9ApoGaYtmBJ0vABdAZt+oVG4sFf
+	K3z3CYV6EZ5qvwsZt53Xm3YsHojgu+Lnc/MGgGWBRjCtTP7gshm480pZ0w6ADgHvrym5hNajUF6+5
+	zMm5Wwq34jxUApGU7k5FAPsvO5ctYCuhECq/mLB6tplCVh3/+XLdSiHMUlY17fh+xs732kgaDotuQ
+	QYgXtDmMB1pVKCq5cf3Bcuz7Ww47vLSx4rBxtdB/vpp2w9SdrU6K8Q7DuJ3+XrGfbMhKtBU5ektA8
+	GxEUUaKw==;
+Received: from localhost ([::1] helo=merlin.infradead.org)
+	by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux))
+	id 1kKgo2-0000Ze-Fb; Tue, 22 Sep 2020 11:50:00 +0000
+Received: from mail-pg1-x543.google.com ([2607:f8b0:4864:20::543])
+ by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1kKgnr-0000Vv-6z; Tue, 22 Sep 2020 11:49:49 +0000
+Received: by mail-pg1-x543.google.com with SMTP id o25so6798387pgm.0;
+ Tue, 22 Sep 2020 04:49:46 -0700 (PDT)
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;
+ h=from:to:cc:subject:date:message-id:mime-version
+ :content-transfer-encoding;
+ bh=EJwpKrbgqo/Jc/SWHvyAGB9CrpkZ5L1Hzq9tInFHTYk=;
+ b=Gtqp4rrTgM1+bYxfUQXe+lfPcgHRW6GccdN42Iszl6ozMbezvftl1BUcKE22S6eFW3
+ Vs+lcKZN9Eh9C53YAAd0cuZYhJ2GqlfGNLA/9SyB7s/gIwHqO9Cuu17YpB9dAFfEUxoS
+ 825uUcTeRe6BTagZAh2/MBluiMY3TszRi94MbOftxUg+wSqp0wMAPe9RN0gAEc/l2xgK
+ 8PhXbZv3uItI4QqoKYiz93vrF/zYhj+oGTI44g2li2fpAgCNL7lXCpSE2C9NsEe+YqTw
+ aO5A3W8t4jvp8oCJEvr/MWY1ZZLd1fVJ17W3aGXoDi/7EUcAvX9G5Ee7U68UXGMtty/d
+ z5Nw==
+X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
+ d=1e100.net; s=20161025;
+ h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version
+ :content-transfer-encoding;
+ bh=EJwpKrbgqo/Jc/SWHvyAGB9CrpkZ5L1Hzq9tInFHTYk=;
+ b=XhcpP16zYyJr/qCT9JbO3fn8RyfI44xJL3hvgNrlcr4ljkEZ4TF6OfyhjdEZYeeA3C
+ kLlWuAqrSn6mweuhS2LZ0BV5QL/YYaVO4wP4B/y3j+tNbnW3JNM0NtEY19pOtaM4vYK/
+ tPuNxld5RvJWxQ9BLs8hH6y7j/ob6oDug170P5YkwK6Wa/FLCi2bw92/vldhdnFP/Nny
+ 1bbiWRVls1Ra/Q3z90tGViMkBdlcff6MI9DR5M6a1HTQN7kN9rLDCMGs3r9XVComY07N
+ ECbrZbL+iJwuRuT43RAUxE72X/Pn0WYD20unzITf8bta92usNDRgEuxc1bLyL+uHxgUk
+ YQKA==
+X-Gm-Message-State: AOAM531Xr1Bg4uwupCAPpH4eBWVrXGALjIWa+5AVNZ8w6ltS4BGgWv6b
+ e4g6ycKnUp/KalpJhOMi90o=
+X-Google-Smtp-Source: 
+ ABdhPJx36OliaaLkiX3ZeZNNWgd/qSKiRor2X0eeHScDrjMSi5bTiEzAfX5j7hkQgqz8ZUT0qqLRNA==
+X-Received: by 2002:a63:1863:: with SMTP id 35mr3131307pgy.413.1600775385014;
+ Tue, 22 Sep 2020 04:49:45 -0700 (PDT)
+Received: from guoguo-omen.lan ([156.96.148.94])
+ by smtp.gmail.com with ESMTPSA id r4sm2223750pjf.4.2020.09.22.04.49.42
+ (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
+ Tue, 22 Sep 2020 04:49:44 -0700 (PDT)
+From: Chuanhong Guo <gch981213@gmail.com>
+To: linux-spi@vger.kernel.org
+Subject: [PATCH v2] spi: spi-mtk-nor: fix timeout calculation overflow
+Date: Tue, 22 Sep 2020 19:49:02 +0800
+Message-Id: <20200922114905.2942859-1-gch981213@gmail.com>
+X-Mailer: git-send-email 2.26.2
+MIME-Version: 1.0
+X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 
+X-CRM114-CacheID: sfid-20200922_074948_345420_69207EBE 
+X-CRM114-Status: GOOD (  12.60  )
+X-Spam-Score: 2.6 (++)
+X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary:
+ Content analysis details:   (2.6 points)
+ pts rule name              description
+ ---- ----------------------
+ --------------------------------------------------
+ 2.6 RCVD_IN_SBL            RBL: Received via a relay in Spamhaus SBL
+ [156.96.148.94 listed in zen.spamhaus.org]
+ -0.0 RCVD_IN_DNSWL_NONE     RBL: Sender listed at https://www.dnswl.org/,
+ no trust [2607:f8b0:4864:20:0:0:0:543 listed in]
+ [list.dnswl.org]
+ 0.0 FREEMAIL_FROM          Sender email is commonly abused enduser mail
+ provider [gch981213[at]gmail.com]
+ 0.2 FREEMAIL_ENVFROM_END_DIGIT Envelope-from freemail username ends
+ in digit [gch981213[at]gmail.com]
+ -0.0 SPF_PASS               SPF: sender matches SPF record
+ 0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
+ -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature
+ -0.1 DKIM_VALID_AU          Message has a valid DKIM or DK signature from
+ author's domain
+ -0.1 DKIM_VALID_EF          Message has a valid DKIM or DK signature from
+ envelope-from domain
+ 0.1 DKIM_SIGNED            Message has a DKIM or DK signature,
+ not necessarily
+ valid
+X-BeenThere: linux-arm-kernel@lists.infradead.org
+X-Mailman-Version: 2.1.29
+Precedence: list
+List-Id: <linux-arm-kernel.lists.infradead.org>
+List-Unsubscribe: 
+ <http://lists.infradead.org/mailman/options/linux-arm-kernel>,
+ <mailto:linux-arm-kernel-request@lists.infradead.org?subject=unsubscribe>
+List-Archive: <http://lists.infradead.org/pipermail/linux-arm-kernel/>
+List-Post: <mailto:linux-arm-kernel@lists.infradead.org>
+List-Help: <mailto:linux-arm-kernel-request@lists.infradead.org?subject=help>
+List-Subscribe: 
+ <http://lists.infradead.org/mailman/listinfo/linux-arm-kernel>,
+ <mailto:linux-arm-kernel-request@lists.infradead.org?subject=subscribe>
+Cc: linux-kernel@vger.kernel.org, stable@vger.kernel.org,
+ Mark Brown <broonie@kernel.org>, linux-mediatek@lists.infradead.org,
+ bayi.cheng@mediatek.com, Matthias Brugger <matthias.bgg@gmail.com>,
+ Chuanhong Guo <gch981213@gmail.com>, linux-arm-kernel@lists.infradead.org
+Sender: "linux-arm-kernel" <linux-arm-kernel-bounces@lists.infradead.org>
+Errors-To: 
+ linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org
+
+CLK_TO_US macro is used to calculate potential transfer time for various
+timeout handling. However it overflows on transfer bigger than 512 bytes
+because it first did (len * 8 * 1000000).
+This controller typically operates at 45MHz. This patch did 2 things:
+1. calculate clock / 1000000 first
+2. add a 4M transfer size cap so that the final timeout in DMA reading
+   doesn't overflow
+
+Fixes: 881d1ee9fe81f ("spi: add support for mediatek spi-nor controller")
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
+---
+
+Change since v1: fix transfer size cap to 4M
+
+ drivers/spi/spi-mtk-nor.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
+index 6e6ca2b8e6c82..62f5ff2779884 100644
+--- a/drivers/spi/spi-mtk-nor.c
++++ b/drivers/spi/spi-mtk-nor.c
+@@ -89,7 +89,7 @@
+ // Buffered page program can do one 128-byte transfer
+ #define MTK_NOR_PP_SIZE			128
+ 
+-#define CLK_TO_US(sp, clkcnt)		((clkcnt) * 1000000 / sp->spi_freq)
++#define CLK_TO_US(sp, clkcnt)		DIV_ROUND_UP(clkcnt, sp->spi_freq / 1000000)
+ 
+ struct mtk_nor {
+ 	struct spi_controller *ctlr;
+@@ -177,6 +177,10 @@ static int mtk_nor_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
+ 	if ((op->addr.nbytes == 3) || (op->addr.nbytes == 4)) {
+ 		if ((op->data.dir == SPI_MEM_DATA_IN) &&
+ 		    mtk_nor_match_read(op)) {
++			// limit size to prevent timeout calculation overflow
++			if (op->data.nbytes > 0x400000)
++				op->data.nbytes = 0x400000;
++
+ 			if ((op->addr.val & MTK_NOR_DMA_ALIGN_MASK) ||
+ 			    (op->data.nbytes < MTK_NOR_DMA_ALIGN))
+ 				op->data.nbytes = 1;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0667-spi-mediatek-fix-timeout-for-large-data.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0667-spi-mediatek-fix-timeout-for-large-data.patch
new file mode 100644
index 0000000..a04f5d6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0667-spi-mediatek-fix-timeout-for-large-data.patch
@@ -0,0 +1,34 @@
+--- a/drivers/spi/spi-mt65xx.c
++++ b/drivers/spi/spi-mt65xx.c
+@@ -720,6 +720,23 @@ static irqreturn_t mtk_spi_interrupt(int
+ 	return IRQ_HANDLED;
+ }
+ 
++static int mtk_spi_mem_adjust_op_size(struct spi_mem *mem,
++                                      struct spi_mem_op *op)
++{
++	int opcode_len;
++
++	if(!op->data.nbytes)
++		return 0;
++
++	if (op->data.dir != SPI_MEM_NO_DATA) {
++		opcode_len = 1 + op->addr.nbytes + op->dummy.nbytes;
++		if (opcode_len + op->data.nbytes > MTK_SPI_IPM_PACKET_SIZE)
++			op->data.nbytes = MTK_SPI_IPM_PACKET_SIZE -opcode_len;
++	}
++
++	return 0;
++}
++
+ static bool mtk_spi_mem_supports_op(struct spi_mem *mem,
+ 				     const struct spi_mem_op *op)
+ {
+@@ -946,6 +963,7 @@ err_exit:
+ }
+ 
+ static const struct spi_controller_mem_ops mtk_spi_mem_ops = {
++	.adjust_op_size = mtk_spi_mem_adjust_op_size,
+ 	.supports_op = mtk_spi_mem_supports_op,
+ 	.exec_op = mtk_spi_mem_exec_op,
+ };
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0668-spi-mediatek-fix-dma-unmap-twice.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0668-spi-mediatek-fix-dma-unmap-twice.patch
new file mode 100644
index 0000000..31562bf
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0668-spi-mediatek-fix-dma-unmap-twice.patch
@@ -0,0 +1,16 @@
+--- a/drivers/spi/spi-mt65xx.c
++++ b/drivers/spi/spi-mt65xx.c
+@@ -946,12 +946,10 @@ static int mtk_spi_mem_exec_op(struct sp
+ 		reg_val &= ~SPI_CMD_RX_DMA;
+ 	writel(reg_val, mdata->base + SPI_CMD_REG);
+ 
++unmap_rx_dma:
+ 	if (op->data.dir == SPI_MEM_DATA_IN)
+ 		dma_unmap_single(mdata->dev, mdata->rx_dma,
+ 				 op->data.nbytes, DMA_FROM_DEVICE);
+-unmap_rx_dma:
+-	dma_unmap_single(mdata->dev, mdata->rx_dma,
+-			 op->data.nbytes, DMA_FROM_DEVICE);
+ unmap_tx_dma:
+ 	dma_unmap_single(mdata->dev, mdata->tx_dma,
+ 			 tx_size, DMA_TO_DEVICE);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0669-fix-SPIM-NAND-and-NOR-probing.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0669-fix-SPIM-NAND-and-NOR-probing.patch
new file mode 100644
index 0000000..582771b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0669-fix-SPIM-NAND-and-NOR-probing.patch
@@ -0,0 +1,33 @@
+--- a/drivers/spi/spi-mt65xx.c
++++ b/drivers/spi/spi-mt65xx.c
+@@ -1073,7 +1073,7 @@ static int mtk_spi_probe(struct platform
+ 		goto err_put_master;
+ 	}
+ 
+-/*
++
+ 	mdata->parent_clk = devm_clk_get(&pdev->dev, "parent-clk");
+ 	if (IS_ERR(mdata->parent_clk)) {
+ 		ret = PTR_ERR(mdata->parent_clk);
+@@ -1101,17 +1101,17 @@ static int mtk_spi_probe(struct platform
+ 		goto err_put_master;
+ 	}
+ 
+-	ret = clk_set_parent(mdata->sel_clk, mdata->parent_clk);
++	/*ret = clk_set_parent(mdata->sel_clk, mdata->parent_clk);
+ 	if (ret < 0) {
+ 		dev_err(&pdev->dev, "failed to clk_set_parent (%d)\n", ret);
+ 		clk_disable_unprepare(mdata->spi_clk);
+ 		goto err_put_master;
+ 	}
+ 
+-	clk_disable_unprepare(mdata->spi_clk);
++	clk_disable_unprepare(mdata->sel_clk);*/
++
++	//pm_runtime_enable(&pdev->dev);
+ 
+-	pm_runtime_enable(&pdev->dev);
+-*/
+ 	ret = devm_spi_register_master(&pdev->dev, master);
+ 	if (ret) {
+ 		dev_err(&pdev->dev, "failed to register master (%d)\n", ret);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0670-fix-SPIM-dma-buffer-not-aligned.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0670-fix-SPIM-dma-buffer-not-aligned.patch
new file mode 100644
index 0000000..d4534e7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0670-fix-SPIM-dma-buffer-not-aligned.patch
@@ -0,0 +1,81 @@
+--- a/drivers/spi/spi-mt65xx.c
++++ b/drivers/spi/spi-mt65xx.c
+@@ -184,7 +184,7 @@ static const struct mtk_spi_compatible m
+  */
+ static const struct mtk_chip_config mtk_default_chip_info = {
+ 	.sample_sel = 0,
+-	.get_tick_dly = 0,
++	.get_tick_dly = 1,
+ };
+ 
+ static const struct of_device_id mtk_spi_of_match[] = {
+@@ -730,8 +730,11 @@ static int mtk_spi_mem_adjust_op_size(st
+ 
+ 	if (op->data.dir != SPI_MEM_NO_DATA) {
+ 		opcode_len = 1 + op->addr.nbytes + op->dummy.nbytes;
+-		if (opcode_len + op->data.nbytes > MTK_SPI_IPM_PACKET_SIZE)
++		if (opcode_len + op->data.nbytes > MTK_SPI_IPM_PACKET_SIZE) {
+ 			op->data.nbytes = MTK_SPI_IPM_PACKET_SIZE -opcode_len;
++			/* force data buffer dma-aligned. */
++			op->data.nbytes -= op->data.nbytes % 4;
++		}
+ 	}
+ 
+ 	return 0;
+@@ -758,10 +761,6 @@ static bool mtk_spi_mem_supports_op(stru
+ 			return false;
+ 	}
+ 
+-	if (op->data.dir == SPI_MEM_DATA_IN &&
+-	    !IS_ALIGNED((size_t)op->data.buf.in, 4))
+-		return false;
+-
+ 	return true;
+ }
+ 
+@@ -820,6 +819,7 @@ static int mtk_spi_mem_exec_op(struct sp
+ 	struct mtk_spi *mdata = spi_master_get_devdata(mem->spi->master);
+ 	u32 reg_val, nio = 1, tx_size;
+ 	char *tx_tmp_buf;
++	char *rx_tmp_buf;
+ 	int ret = 0;
+ 
+ 	mdata->use_spimem = true;
+@@ -914,10 +914,18 @@ static int mtk_spi_mem_exec_op(struct sp
+ 	}
+ 
+ 	if (op->data.dir == SPI_MEM_DATA_IN) {
++		if(!IS_ALIGNED((size_t)op->data.buf.in, 4)) {
++			rx_tmp_buf = kzalloc(op->data.nbytes, GFP_KERNEL | GFP_DMA);
++			if (!rx_tmp_buf)
++				return -ENOMEM;
++		}
++		else
++			rx_tmp_buf = op->data.buf.in;
++
+ 		mdata->rx_dma = dma_map_single(mdata->dev,
+-					       op->data.buf.in,
+-					       op->data.nbytes,
+-					       DMA_FROM_DEVICE);
++						   rx_tmp_buf,
++						   op->data.nbytes,
++						   DMA_FROM_DEVICE);
+ 		if (dma_mapping_error(mdata->dev, mdata->rx_dma)) {
+ 			ret = -ENOMEM;
+ 			goto unmap_tx_dma;
+@@ -947,9 +955,14 @@ static int mtk_spi_mem_exec_op(struct sp
+ 	writel(reg_val, mdata->base + SPI_CMD_REG);
+ 
+ unmap_rx_dma:
+-	if (op->data.dir == SPI_MEM_DATA_IN)
++	if (op->data.dir == SPI_MEM_DATA_IN) {
++		if(!IS_ALIGNED((size_t)op->data.buf.in, 4)) {
++			memcpy(op->data.buf.in, rx_tmp_buf, op->data.nbytes);
++			kfree(rx_tmp_buf);
++		}
+ 		dma_unmap_single(mdata->dev, mdata->rx_dma,
+ 				 op->data.nbytes, DMA_FROM_DEVICE);
++	}
+ unmap_tx_dma:
+ 	dma_unmap_single(mdata->dev, mdata->tx_dma,
+ 			 tx_size, DMA_TO_DEVICE);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0671-add-micron-MT29F4G01ABAFD-spi-nand-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0671-add-micron-MT29F4G01ABAFD-spi-nand-support.patch
new file mode 100644
index 0000000..40833c0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0671-add-micron-MT29F4G01ABAFD-spi-nand-support.patch
@@ -0,0 +1,111 @@
+--- a/drivers/mtd/nand/spi/micron.c
++++ b/drivers/mtd/nand/spi/micron.c
+@@ -18,7 +18,9 @@
+ #define MICRON_STATUS_ECC_4TO6_BITFLIPS	(3 << 4)
+ #define MICRON_STATUS_ECC_7TO8_BITFLIPS	(5 << 4)
+ 
+-static SPINAND_OP_VARIANTS(read_cache_variants,
++#define MICRON_CFG_CR			BIT(0)
++
++static SPINAND_OP_VARIANTS(quadio_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),
+@@ -26,46 +28,46 @@ static SPINAND_OP_VARIANTS(read_cache_va
+ 		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,
++static SPINAND_OP_VARIANTS(x4_write_cache_variants,
+ 		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
+ 		SPINAND_PROG_LOAD(true, 0, NULL, 0));
+ 
+-static SPINAND_OP_VARIANTS(update_cache_variants,
++static SPINAND_OP_VARIANTS(x4_update_cache_variants,
+ 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
+ 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
+ 
+-static int mt29f2g01abagd_ooblayout_ecc(struct mtd_info *mtd, int section,
+-					struct mtd_oob_region *region)
++static int micron_8_ooblayout_ecc(struct mtd_info *mtd, int section,
++				  struct mtd_oob_region *region)
+ {
+ 	if (section)
+ 		return -ERANGE;
+ 
+-	region->offset = 64;
+-	region->length = 64;
++	region->offset = mtd->oobsize / 2;
++	region->length = mtd->oobsize / 2;
+ 
+ 	return 0;
+ }
+ 
+-static int mt29f2g01abagd_ooblayout_free(struct mtd_info *mtd, int section,
+-					 struct mtd_oob_region *region)
++static int micron_8_ooblayout_free(struct mtd_info *mtd, int section,
++				   struct mtd_oob_region *region)
+ {
+ 	if (section)
+ 		return -ERANGE;
+ 
+ 	/* Reserve 2 bytes for the BBM. */
+ 	region->offset = 2;
+-	region->length = 62;
++	region->length = (mtd->oobsize / 2) - 2;
+ 
+ 	return 0;
+ }
+ 
+-static const struct mtd_ooblayout_ops mt29f2g01abagd_ooblayout = {
+-	.ecc = mt29f2g01abagd_ooblayout_ecc,
+-	.free = mt29f2g01abagd_ooblayout_free,
++static const struct mtd_ooblayout_ops micron_8_ooblayout = {
++	.ecc = micron_8_ooblayout_ecc,
++	.free = micron_8_ooblayout_free,
+ };
+ 
+-static int mt29f2g01abagd_ecc_get_status(struct spinand_device *spinand,
+-					 u8 status)
++static int micron_8_ecc_get_status(struct spinand_device *spinand,
++				   u8 status)
+ {
+ 	switch (status & MICRON_STATUS_ECC_MASK) {
+ 	case STATUS_ECC_NO_BITFLIPS:
+@@ -94,12 +96,21 @@ static const struct spinand_info micron_
+ 	SPINAND_INFO("MT29F2G01ABAGD", 0x24,
+ 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
+ 		     NAND_ECCREQ(8, 512),
+-		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+-					      &write_cache_variants,
+-					      &update_cache_variants),
++		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
++					      &x4_write_cache_variants,
++					      &x4_update_cache_variants),
+ 		     0,
+-		     SPINAND_ECCINFO(&mt29f2g01abagd_ooblayout,
+-				     mt29f2g01abagd_ecc_get_status)),
++		     SPINAND_ECCINFO(&micron_8_ooblayout,
++				     micron_8_ecc_get_status)),
++	SPINAND_INFO("MT29F4G01ABAFD", 0x34,
++		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
++		     NAND_ECCREQ(8, 512),
++		     SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
++					      &x4_write_cache_variants,
++					      &x4_update_cache_variants),
++		     SPINAND_HAS_CR_FEAT_BIT,
++		     SPINAND_ECCINFO(&micron_8_ooblayout,
++				     micron_8_ecc_get_status)),
+ };
+ 
+ static int micron_spinand_detect(struct spinand_device *spinand)
+--- a/include/linux/mtd/spinand.h
++++ b/include/linux/mtd/spinand.h
+@@ -270,6 +270,7 @@ struct spinand_ecc_info {
+ };
+ 
+ #define SPINAND_HAS_QE_BIT		BIT(0)
++#define SPINAND_HAS_CR_FEAT_BIT		BIT(1)
+ 
+ /**
+  * struct spinand_info - Structure used to describe SPI NAND chips
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0672-add-F50L1G41LB-and-GD5F1GQ5UExxG-snand-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0672-add-F50L1G41LB-and-GD5F1GQ5UExxG-snand-support.patch
new file mode 100644
index 0000000..63eee5d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0672-add-F50L1G41LB-and-GD5F1GQ5UExxG-snand-support.patch
@@ -0,0 +1,75 @@
+Index: linux-5.4.158/drivers/mtd/nand/spi/gigadevice.c
+===================================================================
+--- linux-5.4.158.orig/drivers/mtd/nand/spi/gigadevice.c
++++ linux-5.4.158/drivers/mtd/nand/spi/gigadevice.c
+@@ -36,6 +36,15 @@ 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));
+ 
++/* 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));
+@@ -223,7 +232,54 @@ static int gd5fxgq4ufxxg_ecc_get_status(
+ 	return -EINVAL;
+ }
+ 
++static int esmt_1_ooblayout_ecc(struct mtd_info *mtd, int section,
++				  struct mtd_oob_region *region)
++{
++	if (section > 3)
++		return -ERANGE;
++
++	region->offset = (16 * section) + 8;
++	region->length = 8;
++
++	return 0;
++}
++
++static int esmt_1_ooblayout_free(struct mtd_info *mtd, int section,
++				   struct mtd_oob_region *region)
++{
++	if (section > 3)
++		return -ERANGE;
++
++	region->offset = (16 * section) + 2;
++	region->length = 6;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops esmt_1_ooblayout = {
++	.ecc = esmt_1_ooblayout_ecc,
++	.free = esmt_1_ooblayout_free,
++};
++
+ static const struct spinand_info gigadevice_spinand_table[] = {
++	SPINAND_INFO("F50L1G41LB", 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(&esmt_1_ooblayout,
++				     NULL)),
++	SPINAND_INFO("GD5F1GQ5UExxG", 0x51,
++		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
++		     NAND_ECCREQ(4, 512),
++		     SPINAND_INFO_OP_VARIANTS(&gd5f1gq5_read_cache_variants,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     SPINAND_HAS_QE_BIT,
++		     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
++				     gd5fxgq4xa_ecc_get_status)),
+ 	SPINAND_INFO("GD5F1GQ4xA", 0xF1,
+ 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+ 		     NAND_ECCREQ(8, 512),
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0701-fix-mtk-nfi-driver-dependency.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0701-fix-mtk-nfi-driver-dependency.patch
new file mode 100644
index 0000000..3023076
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0701-fix-mtk-nfi-driver-dependency.patch
@@ -0,0 +1,10 @@
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -429,6 +429,7 @@ config SPI_MT65XX
+ 
+ config SPI_MTK_SNFI
+ 	tristate "MediaTek SPI NAND interface"
++	depends on MTD
+ 	select MTD_SPI_NAND
+ 	help
+ 	  This selects the SPI NAND FLASH interface(SNFI),
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0801-mtk-sd-add-mt7986-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0801-mtk-sd-add-mt7986-support.patch
new file mode 100644
index 0000000..6b76993
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0801-mtk-sd-add-mt7986-support.patch
@@ -0,0 +1,29 @@
+--- a/drivers/mmc/host/mtk-sd.c
++++ b/drivers/mmc/host/mtk-sd.c
+@@ -508,6 +508,18 @@ static const struct mtk_mmc_compatible m
+ 	.support_64g = false,
+ };
+ 
++static const struct mtk_mmc_compatible mt7986_compat = {
++	.clk_div_bits = 12,
++	.hs400_tune = false,
++	.pad_tune_reg = MSDC_PAD_TUNE0,
++	.async_fifo = true,
++	.data_tune = true,
++	.busy_check = true,
++	.stop_clk_fix = true,
++	.enhance_rx = true,
++	.support_64g = true,
++};
++
+ static const struct mtk_mmc_compatible mt8516_compat = {
+ 	.clk_div_bits = 12,
+ 	.hs400_tune = false,
+@@ -537,6 +549,7 @@ static const struct of_device_id msdc_of
+ 	{ .compatible = "mediatek,mt2701-mmc", .data = &mt2701_compat},
+ 	{ .compatible = "mediatek,mt2712-mmc", .data = &mt2712_compat},
+ 	{ .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat},
++	{ .compatible = "mediatek,mt7986-mmc", .data = &mt7986_compat},
+ 	{ .compatible = "mediatek,mt8516-mmc", .data = &mt8516_compat},
+ 	{ .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat},
+ 	{}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0900-bt-mtk-serial-fix.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0900-bt-mtk-serial-fix.patch
new file mode 100644
index 0000000..2b3a4ae
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0900-bt-mtk-serial-fix.patch
@@ -0,0 +1,33 @@
+--- a/drivers/tty/serial/8250/8250.h
++++ b/drivers/tty/serial/8250/8250.h
+@@ -82,6 +82,7 @@ struct serial8250_config {
+ #define UART_CAP_MINI	(1 << 17)	/* Mini UART on BCM283X family lacks:
+ 					 * STOP PARITY EPAR SPAR WLEN5 WLEN6
+ 					 */
++#define UART_CAP_NMOD	(1 << 18)	/* UART doesn't do termios */
+ 
+ #define UART_BUG_QUOT	(1 << 0)	/* UART has buggy quot LSB */
+ #define UART_BUG_TXEN	(1 << 1)	/* UART has buggy TX IIR status */
+--- a/drivers/tty/serial/8250/8250_port.c
++++ b/drivers/tty/serial/8250/8250_port.c
+@@ -291,7 +291,7 @@ static const struct serial8250_config ua
+ 		.tx_loadsz	= 16,
+ 		.fcr		= UART_FCR_ENABLE_FIFO |
+ 				  UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
+-		.flags		= UART_CAP_FIFO,
++		.flags		= UART_CAP_FIFO | UART_CAP_NMOD,
+ 	},
+ 	[PORT_NPCM] = {
+ 		.name		= "Nuvoton 16550",
+@@ -2598,6 +2598,11 @@ serial8250_do_set_termios(struct uart_po
+ 	unsigned long flags;
+ 	unsigned int baud, quot, frac = 0;
+ 
++	if (up->capabilities & UART_CAP_NMOD) {
++		termios->c_cflag = 0;
++		return;
++	}
++
+ 	if (up->capabilities & UART_CAP_MINI) {
+ 		termios->c_cflag &= ~(CSTOPB | PARENB | PARODD | CMSPAR);
+ 		if ((termios->c_cflag & CSIZE) == CS5 ||
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0900-i2c-busses-add-mt7986-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0900-i2c-busses-add-mt7986-support.patch
new file mode 100644
index 0000000..a375842
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0900-i2c-busses-add-mt7986-support.patch
@@ -0,0 +1,32 @@
+diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
+index e1ef012..4fd4721 100644
+--- a/drivers/i2c/busses/i2c-mt65xx.c
++++ b/drivers/i2c/busses/i2c-mt65xx.c
+@@ -289,6 +289,19 @@ static const struct mtk_i2c_compatible mt7622_compat = {
+ 	.ltiming_adjust = 0,
+ };
+
++static const struct mtk_i2c_compatible mt7986_compat = {
++	.quirks = &mt7622_i2c_quirks,
++	.regs = mt_i2c_regs_v1,
++	.pmic_i2c = 0,
++	.dcm = 1,
++	.auto_restart = 1,
++	.aux_len_reg = 1,
++	.support_33bits = 0,
++	.timing_adjust = 0,
++	.dma_sync = 1,
++	.ltiming_adjust = 0,
++};
++
+ static const struct mtk_i2c_compatible mt8173_compat = {
+ 	.regs = mt_i2c_regs_v1,
+ 	.pmic_i2c = 0,
+@@ -319,6 +332,7 @@ static const struct of_device_id mtk_i2c_of_match[] = {
+ 	{ .compatible = "mediatek,mt6577-i2c", .data = &mt6577_compat },
+ 	{ .compatible = "mediatek,mt6589-i2c", .data = &mt6589_compat },
+ 	{ .compatible = "mediatek,mt7622-i2c", .data = &mt7622_compat },
++	{ .compatible = "mediatek,mt7986-i2c", .data = &mt7986_compat },
+ 	{ .compatible = "mediatek,mt8173-i2c", .data = &mt8173_compat },
+ 	{ .compatible = "mediatek,mt8183-i2c", .data = &mt8183_compat },
+ 	{}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0901-i2c-busses-add-mt7981-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0901-i2c-busses-add-mt7981-support.patch
new file mode 100644
index 0000000..f79d2f8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0901-i2c-busses-add-mt7981-support.patch
@@ -0,0 +1,43 @@
+diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
+index e1ef012..4fd4721 100644
+--- a/drivers/i2c/busses/i2c-mt65xx.c
++++ b/drivers/i2c/busses/i2c-mt65xx.c
+@@ -157,7 +157,7 @@ static const u16 mt_i2c_regs_v1[] = {
+ 
+ static const u16 mt_i2c_regs_v2[] = {
+ 	[OFFSET_DATA_PORT] = 0x0,
+-	[OFFSET_SLAVE_ADDR] = 0x4,
++	[OFFSET_SLAVE_ADDR] = 0x94,
+ 	[OFFSET_INTR_MASK] = 0x8,
+ 	[OFFSET_INTR_STAT] = 0xc,
+ 	[OFFSET_CONTROL] = 0x10,
+@@ -289,6 +289,18 @@ static const struct mtk_i2c_compatible mt7622_compat = {
+ 	.ltiming_adjust = 0,
+ };
+ 
++static const struct mtk_i2c_compatible mt7981_compat = {
++	.regs = mt_i2c_regs_v2,
++	.pmic_i2c = 0,
++	.dcm = 0,
++	.auto_restart = 1,
++	.aux_len_reg = 1,
++	.support_33bits = 1,
++	.timing_adjust = 1,
++	.dma_sync = 1,
++	.ltiming_adjust = 1,
++};
++
+ static const struct mtk_i2c_compatible mt7986_compat = {
+ 	.quirks = &mt7622_i2c_quirks,
+ 	.regs = mt_i2c_regs_v1,
+@@ -332,6 +344,7 @@ static const struct of_device_id mtk_i2c_of_match[] = {
+ 	{ .compatible = "mediatek,mt6577-i2c", .data = &mt6577_compat },
+ 	{ .compatible = "mediatek,mt6589-i2c", .data = &mt6589_compat },
+ 	{ .compatible = "mediatek,mt7622-i2c", .data = &mt7622_compat },
++	{ .compatible = "mediatek,mt7981-i2c", .data = &mt7981_compat },
+ 	{ .compatible = "mediatek,mt7986-i2c", .data = &mt7986_compat },
+ 	{ .compatible = "mediatek,mt8173-i2c", .data = &mt8173_compat },
+ 	{ .compatible = "mediatek,mt8183-i2c", .data = &mt8183_compat },
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0930-pwm-add-mt7986-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0930-pwm-add-mt7986-support.patch
new file mode 100644
index 0000000..a791d3a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0930-pwm-add-mt7986-support.patch
@@ -0,0 +1,24 @@
+diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c
+index b94e0d0..35a0db2 100644
+--- a/drivers/pwm/pwm-mediatek.c
++++ b/drivers/pwm/pwm-mediatek.c
+@@ -302,6 +302,11 @@ static const struct pwm_mediatek_of_data mt7629_pwm_data = {
+ 	.pwm45_fixup = false,
+ };
+
++static const struct pwm_mediatek_of_data mt7986_pwm_data = {
++	.num_pwms = 2,
++	.pwm45_fixup = false,
++};
++
+ static const struct pwm_mediatek_of_data mt8516_pwm_data = {
+ 	.num_pwms = 5,
+ 	.pwm45_fixup = false,
+@@ -313,6 +318,7 @@ static const struct of_device_id pwm_mediatek_of_match[] = {
+ 	{ .compatible = "mediatek,mt7623-pwm", .data = &mt7623_pwm_data },
+ 	{ .compatible = "mediatek,mt7628-pwm", .data = &mt7628_pwm_data },
+ 	{ .compatible = "mediatek,mt7629-pwm", .data = &mt7629_pwm_data },
++	{ .compatible = "mediatek,mt7986-pwm", .data = &mt7986_pwm_data },
+ 	{ .compatible = "mediatek,mt8516-pwm", .data = &mt8516_pwm_data },
+ 	{ },
+ };
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0931-pwm-add-mt7981-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0931-pwm-add-mt7981-support.patch
new file mode 100644
index 0000000..b926383
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0931-pwm-add-mt7981-support.patch
@@ -0,0 +1,133 @@
+diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c
+index 7c56ee2..3a5a456 100644
+--- a/drivers/pwm/pwm-mediatek.c
++++ b/drivers/pwm/pwm-mediatek.c
+@@ -33,10 +32,13 @@
+ #define PWM45THRES_FIXUP	0x34
+ 
+ #define PWM_CLK_DIV_MAX		7
++#define REG_V1			1
++#define REG_V2			2
+ 
+ struct pwm_mediatek_of_data {
+ 	unsigned int num_pwms;
+ 	bool pwm45_fixup;
++	int reg_ver;
+ };
+ 
+ /**
+@@ -57,10 +59,14 @@ struct pwm_mediatek_chip {
+ 	const struct pwm_mediatek_of_data *soc;
+ };
+ 
+-static const unsigned int pwm_mediatek_reg_offset[] = {
++static const unsigned int mtk_pwm_reg_offset_v1[] = {
+ 	0x0010, 0x0050, 0x0090, 0x00d0, 0x0110, 0x0150, 0x0190, 0x0220
+ };
+ 
++static const unsigned int mtk_pwm_reg_offset_v2[] = {
++	0x0080, 0x00c0, 0x0100, 0x0140, 0x0180, 0x1c0, 0x200, 0x0240
++};
++
+ static inline struct pwm_mediatek_chip *
+ to_pwm_mediatek_chip(struct pwm_chip *chip)
+ {
+@@ -108,14 +114,38 @@ static void pwm_mediatek_clk_disable(struct pwm_chip *chip,
+ static inline u32 pwm_mediatek_readl(struct pwm_mediatek_chip *chip,
+ 				     unsigned int num, unsigned int offset)
+ {
+-	return readl(chip->regs + pwm_mediatek_reg_offset[num] + offset);
++	u32 pwm_offset;
++
++	switch (chip->soc->reg_ver) {
++	case REG_V2:
++		pwm_offset = mtk_pwm_reg_offset_v2[num];
++		break;
++
++	case REG_V1:
++	default:
++		pwm_offset = mtk_pwm_reg_offset_v1[num];
++	}
++
++	return readl(chip->regs + pwm_offset + offset);
+ }
+ 
+ static inline void pwm_mediatek_writel(struct pwm_mediatek_chip *chip,
+ 				       unsigned int num, unsigned int offset,
+ 				       u32 value)
+ {
+-	writel(value, chip->regs + pwm_mediatek_reg_offset[num] + offset);
++	u32 pwm_offset;
++
++	switch (chip->soc->reg_ver) {
++	case REG_V2:
++		pwm_offset = mtk_pwm_reg_offset_v2[num];
++		break;
++
++	case REG_V1:
++	default:
++		pwm_offset = mtk_pwm_reg_offset_v1[num];
++	}
++
++	writel(value, chip->regs + pwm_offset + offset);
+ }
+ 
+ static int pwm_mediatek_config(struct pwm_chip *chip, struct pwm_device *pwm,
+@@ -281,36 +311,49 @@ static int pwm_mediatek_remove(struct platform_device *pdev)
+ static const struct pwm_mediatek_of_data mt2712_pwm_data = {
+ 	.num_pwms = 8,
+ 	.pwm45_fixup = false,
++	.reg_ver = REG_V1,
+ };
+ 
+ static const struct pwm_mediatek_of_data mt7622_pwm_data = {
+ 	.num_pwms = 6,
+ 	.pwm45_fixup = false,
++	.reg_ver = REG_V1,
+ };
+ 
+ static const struct pwm_mediatek_of_data mt7623_pwm_data = {
+ 	.num_pwms = 5,
+ 	.pwm45_fixup = true,
++	.reg_ver = REG_V1,
+ };
+ 
+ static const struct pwm_mediatek_of_data mt7628_pwm_data = {
+ 	.num_pwms = 4,
+ 	.pwm45_fixup = true,
++	.reg_ver = REG_V1,
+ };
+ 
+ static const struct pwm_mediatek_of_data mt7629_pwm_data = {
+ 	.num_pwms = 1,
+ 	.pwm45_fixup = false,
++	.reg_ver = REG_V1,
++};
++
++static const struct pwm_mediatek_of_data mt7981_pwm_data = {
++	.num_pwms = 3,
++	.pwm45_fixup = false,
++	.reg_ver = REG_V2,
+ };
+ 
+ static const struct pwm_mediatek_of_data mt7986_pwm_data = {
+ 	.num_pwms = 2,
+ 	.pwm45_fixup = false,
++	.reg_ver = REG_V2,
+ };
+ 
+ static const struct pwm_mediatek_of_data mt8516_pwm_data = {
+ 	.num_pwms = 5,
+ 	.pwm45_fixup = false,
++	.reg_ver = REG_V1,
+ };
+ 
+ static const struct of_device_id pwm_mediatek_of_match[] = {
+@@ -319,6 +362,7 @@ static const struct of_device_id pwm_mediatek_of_match[] = {
+ 	{ .compatible = "mediatek,mt7623-pwm", .data = &mt7623_pwm_data },
+ 	{ .compatible = "mediatek,mt7628-pwm", .data = &mt7628_pwm_data },
+ 	{ .compatible = "mediatek,mt7629-pwm", .data = &mt7629_pwm_data },
++	{ .compatible = "mediatek,mt7981-pwm", .data = &mt7981_pwm_data },
+ 	{ .compatible = "mediatek,mt7986-pwm", .data = &mt7986_pwm_data },
+ 	{ .compatible = "mediatek,mt8516-pwm", .data = &mt8516_pwm_data },
+ 	{ },
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0960-watchdog-add-mt7986-assert.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0960-watchdog-add-mt7986-assert.patch
new file mode 100644
index 0000000..619fc10
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0960-watchdog-add-mt7986-assert.patch
@@ -0,0 +1,328 @@
+diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c
+index 9c3d003..30127d1 100644
+--- a/drivers/watchdog/mtk_wdt.c
++++ b/drivers/watchdog/mtk_wdt.c
+@@ -9,6 +9,8 @@
+  * Based on sunxi_wdt.c
+  */
+ 
++#include <dt-bindings/reset/mt7986-resets.h>
++#include <linux/delay.h>
+ #include <linux/err.h>
+ #include <linux/init.h>
+ #include <linux/io.h>
+@@ -16,13 +18,15 @@
+ #include <linux/module.h>
+ #include <linux/moduleparam.h>
+ #include <linux/of.h>
++#include <linux/of_device.h>
+ #include <linux/platform_device.h>
++#include <linux/reset-controller.h>
+ #include <linux/types.h>
+ #include <linux/watchdog.h>
+-#include <linux/delay.h>
++#include <linux/interrupt.h>
+ 
+ #define WDT_MAX_TIMEOUT		31
+-#define WDT_MIN_TIMEOUT		1
++#define WDT_MIN_TIMEOUT		2
+ #define WDT_LENGTH_TIMEOUT(n)	((n) << 5)
+ 
+ #define WDT_LENGTH		0x04
+@@ -44,6 +48,9 @@
+ #define WDT_SWRST		0x14
+ #define WDT_SWRST_KEY		0x1209
+ 
++#define WDT_SWSYSRST		0x18U
++#define WDT_SWSYS_RST_KEY	0x88000000
++
+ #define DRV_NAME		"mtk-wdt"
+ #define DRV_VERSION		"1.0"
+ 
+@@ -53,8 +60,91 @@ static unsigned int timeout;
+ struct mtk_wdt_dev {
+ 	struct watchdog_device wdt_dev;
+ 	void __iomem *wdt_base;
++	spinlock_t lock; /* protects WDT_SWSYSRST reg */
++	struct reset_controller_dev rcdev;
++	bool disable_wdt_extrst;
++};
++
++struct mtk_wdt_data {
++	int toprgu_sw_rst_num;
++};
++
++static const struct mtk_wdt_data mt7986_data = {
++	.toprgu_sw_rst_num = MT7986_TOPRGU_SW_RST_NUM,
++};
++
++static int toprgu_reset_update(struct reset_controller_dev *rcdev,
++			       unsigned long id, bool assert)
++{
++	unsigned int tmp;
++	unsigned long flags;
++	struct mtk_wdt_dev *data =
++		 container_of(rcdev, struct mtk_wdt_dev, rcdev);
++
++	spin_lock_irqsave(&data->lock, flags);
++
++	tmp = readl(data->wdt_base + WDT_SWSYSRST);
++	if (assert)
++		tmp |= BIT(id);
++	else
++		tmp &= ~BIT(id);
++	tmp |= WDT_SWSYS_RST_KEY;
++	writel(tmp, data->wdt_base + WDT_SWSYSRST);
++
++	spin_unlock_irqrestore(&data->lock, flags);
++
++	return 0;
++}
++
++static int toprgu_reset_assert(struct reset_controller_dev *rcdev,
++			       unsigned long id)
++{
++	return toprgu_reset_update(rcdev, id, true);
++}
++
++static int toprgu_reset_deassert(struct reset_controller_dev *rcdev,
++				 unsigned long id)
++{
++	return toprgu_reset_update(rcdev, id, false);
++}
++
++static int toprgu_reset(struct reset_controller_dev *rcdev,
++			unsigned long id)
++{
++	int ret;
++
++	ret = toprgu_reset_assert(rcdev, id);
++	if (ret)
++		return ret;
++
++	return toprgu_reset_deassert(rcdev, id);
++}
++
++static const struct reset_control_ops toprgu_reset_ops = {
++	.assert = toprgu_reset_assert,
++	.deassert = toprgu_reset_deassert,
++	.reset = toprgu_reset,
+ };
+ 
++static int toprgu_register_reset_controller(struct platform_device *pdev,
++					    int rst_num)
++{
++	int ret;
++	struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev);
++
++	spin_lock_init(&mtk_wdt->lock);
++
++	mtk_wdt->rcdev.owner = THIS_MODULE;
++	mtk_wdt->rcdev.nr_resets = rst_num;
++	mtk_wdt->rcdev.ops = &toprgu_reset_ops;
++	mtk_wdt->rcdev.of_node = pdev->dev.of_node;
++	ret = devm_reset_controller_register(&pdev->dev, &mtk_wdt->rcdev);
++	if (ret != 0)
++		dev_err(&pdev->dev,
++			"couldn't register wdt reset controller: %d\n", ret);
++	return ret;
++}
++
+ static int mtk_wdt_restart(struct watchdog_device *wdt_dev,
+ 			   unsigned long action, void *data)
+ {
+@@ -89,12 +179,19 @@ static int mtk_wdt_set_timeout(struct watchdog_device *wdt_dev,
+ 	u32 reg;
+ 
+ 	wdt_dev->timeout = timeout;
++	/*
++	 * In dual mode, irq will be triggered at timeout / 2
++	 * the real timeout occurs at timeout
++	 */
++	if (wdt_dev->pretimeout)
++		wdt_dev->pretimeout = timeout / 2;
+ 
+ 	/*
+ 	 * One bit is the value of 512 ticks
+ 	 * The clock has 32 KHz
+ 	 */
+-	reg = WDT_LENGTH_TIMEOUT(timeout << 6) | WDT_LENGTH_KEY;
++	reg = WDT_LENGTH_TIMEOUT((timeout - wdt_dev->pretimeout) << 6)
++			| WDT_LENGTH_KEY;
+ 	iowrite32(reg, wdt_base + WDT_LENGTH);
+ 
+ 	mtk_wdt_ping(wdt_dev);
+@@ -102,6 +199,19 @@ static int mtk_wdt_set_timeout(struct watchdog_device *wdt_dev,
+ 	return 0;
+ }
+ 
++static void mtk_wdt_init(struct watchdog_device *wdt_dev)
++{
++	struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
++	void __iomem *wdt_base;
++
++	wdt_base = mtk_wdt->wdt_base;
++
++	if (readl(wdt_base + WDT_MODE) & WDT_MODE_EN) {
++		set_bit(WDOG_HW_RUNNING, &wdt_dev->status);
++		mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
++	}
++}
++
+ static int mtk_wdt_stop(struct watchdog_device *wdt_dev)
+ {
+ 	struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
+@@ -128,13 +238,50 @@ static int mtk_wdt_start(struct watchdog_device *wdt_dev)
+ 		return ret;
+ 
+ 	reg = ioread32(wdt_base + WDT_MODE);
+-	reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
++	if (wdt_dev->pretimeout)
++		reg |= (WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
++	else
++		reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
++	if (mtk_wdt->disable_wdt_extrst)
++		reg &= ~WDT_MODE_EXRST_EN;
+ 	reg |= (WDT_MODE_EN | WDT_MODE_KEY);
+ 	iowrite32(reg, wdt_base + WDT_MODE);
+ 
+ 	return 0;
+ }
+ 
++static int mtk_wdt_set_pretimeout(struct watchdog_device *wdd,
++				  unsigned int timeout)
++{
++	struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdd);
++	void __iomem *wdt_base = mtk_wdt->wdt_base;
++	u32 reg = ioread32(wdt_base + WDT_MODE);
++
++	if (timeout && !wdd->pretimeout) {
++		wdd->pretimeout = wdd->timeout / 2;
++		reg |= (WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
++	} else if (!timeout && wdd->pretimeout) {
++		wdd->pretimeout = 0;
++		reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
++	} else {
++		return 0;
++	}
++
++	reg |= WDT_MODE_KEY;
++	iowrite32(reg, wdt_base + WDT_MODE);
++
++	return mtk_wdt_set_timeout(wdd, wdd->timeout);
++}
++
++static irqreturn_t mtk_wdt_isr(int irq, void *arg)
++{
++	struct watchdog_device *wdd = arg;
++
++	watchdog_notify_pretimeout(wdd);
++
++	return IRQ_HANDLED;
++}
++
+ static const struct watchdog_info mtk_wdt_info = {
+ 	.identity	= DRV_NAME,
+ 	.options	= WDIOF_SETTIMEOUT |
+@@ -142,12 +289,21 @@ static const struct watchdog_info mtk_wdt_info = {
+ 			  WDIOF_MAGICCLOSE,
+ };
+ 
++static const struct watchdog_info mtk_wdt_pt_info = {
++	.identity	= DRV_NAME,
++	.options	= WDIOF_SETTIMEOUT |
++			  WDIOF_PRETIMEOUT |
++			  WDIOF_KEEPALIVEPING |
++			  WDIOF_MAGICCLOSE,
++};
++
+ static const struct watchdog_ops mtk_wdt_ops = {
+ 	.owner		= THIS_MODULE,
+ 	.start		= mtk_wdt_start,
+ 	.stop		= mtk_wdt_stop,
+ 	.ping		= mtk_wdt_ping,
+ 	.set_timeout	= mtk_wdt_set_timeout,
++	.set_pretimeout	= mtk_wdt_set_pretimeout,
+ 	.restart	= mtk_wdt_restart,
+ };
+ 
+@@ -155,7 +311,8 @@ static int mtk_wdt_probe(struct platform_device *pdev)
+ {
+ 	struct device *dev = &pdev->dev;
+ 	struct mtk_wdt_dev *mtk_wdt;
+-	int err;
++	const struct mtk_wdt_data *wdt_data;
++	int err, irq;
+ 
+ 	mtk_wdt = devm_kzalloc(dev, sizeof(*mtk_wdt), GFP_KERNEL);
+ 	if (!mtk_wdt)
+@@ -167,10 +324,25 @@ static int mtk_wdt_probe(struct platform_device *pdev)
+ 	if (IS_ERR(mtk_wdt->wdt_base))
+ 		return PTR_ERR(mtk_wdt->wdt_base);
+ 
+-	mtk_wdt->wdt_dev.info = &mtk_wdt_info;
++	irq = platform_get_irq(pdev, 0);
++	if (irq > 0) {
++		err = devm_request_irq(&pdev->dev, irq, mtk_wdt_isr, 0, "wdt_bark",
++				       &mtk_wdt->wdt_dev);
++		if (err)
++			return err;
++
++		mtk_wdt->wdt_dev.info = &mtk_wdt_pt_info;
++		mtk_wdt->wdt_dev.pretimeout = WDT_MAX_TIMEOUT / 2;
++	} else {
++		if (irq == -EPROBE_DEFER)
++			return -EPROBE_DEFER;
++
++		mtk_wdt->wdt_dev.info = &mtk_wdt_info;
++	}
++
+ 	mtk_wdt->wdt_dev.ops = &mtk_wdt_ops;
+ 	mtk_wdt->wdt_dev.timeout = WDT_MAX_TIMEOUT;
+-	mtk_wdt->wdt_dev.max_timeout = WDT_MAX_TIMEOUT;
++	mtk_wdt->wdt_dev.max_hw_heartbeat_ms = WDT_MAX_TIMEOUT * 1000;
+ 	mtk_wdt->wdt_dev.min_timeout = WDT_MIN_TIMEOUT;
+ 	mtk_wdt->wdt_dev.parent = dev;
+ 
+@@ -180,7 +352,7 @@ static int mtk_wdt_probe(struct platform_device *pdev)
+ 
+ 	watchdog_set_drvdata(&mtk_wdt->wdt_dev, mtk_wdt);
+ 
+-	mtk_wdt_stop(&mtk_wdt->wdt_dev);
++	mtk_wdt_init(&mtk_wdt->wdt_dev);
+ 
+ 	watchdog_stop_on_reboot(&mtk_wdt->wdt_dev);
+ 	err = devm_watchdog_register_device(dev, &mtk_wdt->wdt_dev);
+@@ -190,6 +362,17 @@ static int mtk_wdt_probe(struct platform_device *pdev)
+ 	dev_info(dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)\n",
+ 		 mtk_wdt->wdt_dev.timeout, nowayout);
+ 
++	wdt_data = of_device_get_match_data(dev);
++	if (wdt_data) {
++		err = toprgu_register_reset_controller(pdev,
++						       wdt_data->toprgu_sw_rst_num);
++		if (err)
++			return err;
++	}
++
++	mtk_wdt->disable_wdt_extrst =
++		of_property_read_bool(dev->of_node, "mediatek,disable-extrst");
++
+ 	return 0;
+ }
+ 
+@@ -219,6 +402,7 @@ static int mtk_wdt_resume(struct device *dev)
+ 
+ static const struct of_device_id mtk_wdt_dt_ids[] = {
+ 	{ .compatible = "mediatek,mt6589-wdt" },
++	{ .compatible = "mediatek,mt7986-wdt", .data = &mt7986_data },
+ 	{ /* sentinel */ }
+ };
+ MODULE_DEVICE_TABLE(of, mtk_wdt_dt_ids);
+@@ -249,4 +433,4 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Matthias Brugger <matthias.bgg@gmail.com>");
+ MODULE_DESCRIPTION("Mediatek WatchDog Timer Driver");
+-MODULE_VERSION(DRV_VERSION);
++MODULE_VERSION(DRV_VERSION);
+\ No newline at end of file
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0990-gsw-rtl8367s-mt7622-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0990-gsw-rtl8367s-mt7622-support.patch
new file mode 100644
index 0000000..a3d49e9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0990-gsw-rtl8367s-mt7622-support.patch
@@ -0,0 +1,23 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -42,6 +42,12 @@ config MDIO_BCM_IPROC
+ 	  This module provides a driver for the MDIO busses found in the
+ 	  Broadcom iProc SoC's.
+ 
++config RTL8367S_GSW
++	tristate "rtl8367 Gigabit Switch support for mt7622"
++	depends on NET_VENDOR_MEDIATEK
++	help
++	  This driver supports rtl8367s in mt7622
++
+ config MDIO_BCM_UNIMAC
+ 	tristate "Broadcom UniMAC MDIO bus controller"
+ 	depends on HAS_IOMEM
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -110,4 +110,5 @@ obj-$(CONFIG_TERANETICS_PHY)	+= teraneti
+ obj-$(CONFIG_VITESSE_PHY)	+= vitesse.o
+ obj-$(CONFIG_XILINX_GMII2RGMII) += xilinx_gmii2rgmii.o
+ obj-$(CONFIG_MT753X_GSW)        += mtk/mt753x/
++obj-$(CONFIG_RTL8367S_GSW)	+= rtk/
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0991-dt-bindings-PCI-Mediatek-Update-PCIe-binding.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0991-dt-bindings-PCI-Mediatek-Update-PCIe-binding.patch
new file mode 100644
index 0000000..02e4c13
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0991-dt-bindings-PCI-Mediatek-Update-PCIe-binding.patch
@@ -0,0 +1,415 @@
+From patchwork Thu May 28 06:16:45 2020
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: Chuanjia Liu <chuanjia.liu@mediatek.com>
+X-Patchwork-Id: 11574793
+Return-Path: 
+ <SRS0=ftSA=7K=lists.infradead.org=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@kernel.org>
+Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org
+ [172.30.200.123])
+	by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 391201392
+	for <patchwork-linux-mediatek@patchwork.kernel.org>;
+ Thu, 28 May 2020 06:20:27 +0000 (UTC)
+Received: from bombadil.infradead.org (bombadil.infradead.org
+ [198.137.202.133])
+	(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
+	(No client certificate requested)
+	by mail.kernel.org (Postfix) with ESMTPS id 104F620657
+	for <patchwork-linux-mediatek@patchwork.kernel.org>;
+ Thu, 28 May 2020 06:20:27 +0000 (UTC)
+Authentication-Results: mail.kernel.org;
+	dkim=pass (2048-bit key) header.d=lists.infradead.org
+ header.i=@lists.infradead.org header.b="raZHaWxs";
+	dkim=fail reason="signature verification failed" (1024-bit key)
+ header.d=mediatek.com header.i=@mediatek.com header.b="YztrByG/"
+DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 104F620657
+Authentication-Results: mail.kernel.org;
+ dmarc=fail (p=none dis=none) header.from=mediatek.com
+Authentication-Results: mail.kernel.org;
+ spf=none
+ smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
+	d=lists.infradead.org; s=bombadil.20170209; h=Sender:
+	Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post:
+	List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:
+	Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description:
+	Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:
+	List-Owner; bh=aVtKU+Ey8KEM97+S66fz9ZMo+H8BP570jhAAvaRsNWc=; b=raZHaWxsfCxsrd
+	Byn/w1oLN/J82ApnNdBBXixq9Qj0uXIU2tBVqkiQ9lG6QDk7uguxQSJLeTqrsI/uxQmCI/PGQtZdP
+	sH0oboi2sbQSqJ/1ud4uL2pPaiLRJCxINF5oWjoZMsjn/b2fWvn52P6vTr/dxDTaabiVhY0HL0J+X
+	7YGc1aYtO76HZHE2ke3puR42QkI8hE9E2cEhiLWeuUiLdUBegNM5MdYftu4nJTcCXnAeJjp/wIpYG
+	7X737N9cmanDf6Bxr2bNPgaYzH+m7JK6eGxuAvWo0+PE9OX7MLrXY3KjixcjD/b0he0mfEM++gBAq
+	KBYKl5wh1mnlR2WIWXew==;
+Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org)
+	by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux))
+	id 1jeBtx-0005JC-DJ; Thu, 28 May 2020 06:20:25 +0000
+Received: from mailgw01.mediatek.com ([216.200.240.184])
+ by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1jeBtW-0002f2-75; Thu, 28 May 2020 06:20:01 +0000
+X-UUID: d5cb6d96c2a5421796c2f8a284ff3670-20200527
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
+ d=mediatek.com;
+ s=dk;
+ h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From;
+ bh=EqjC+5cHgv6eykN7FPf2mtwK9UivJ3XSCE0jEvb8h+8=;
+ b=YztrByG/Ia304l9KDPBwoHFYkFCN6qBXPqwZgg56CA9VitadAg2+K1VgfEU+oHqsqcsGAMdZTRMQh17tpm4bJParw6MMzAQ28te2TcxvQMV8PZMkerJdZyyYblI7ybauPWuofAQgQMtuwSKVii8eTRJbf99OZ9vDGJP3zo2j1wU=;
+X-UUID: d5cb6d96c2a5421796c2f8a284ff3670-20200527
+Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by
+ mailgw01.mediatek.com
+ (envelope-from <chuanjia.liu@mediatek.com>)
+ (musrelay.mediatek.com ESMTP with TLS)
+ with ESMTP id 681958707; Wed, 27 May 2020 22:20:16 -0800
+Received: from MTKMBS07N2.mediatek.inc (172.21.101.141) by
+ MTKMBS62N1.mediatek.inc (172.29.193.41) with Microsoft SMTP Server (TLS) id
+ 15.0.1497.2; Wed, 27 May 2020 23:18:52 -0700
+Received: from mtkcas07.mediatek.inc (172.21.101.84) by
+ mtkmbs07n2.mediatek.inc (172.21.101.141) with Microsoft SMTP Server (TLS) id
+ 15.0.1497.2; Thu, 28 May 2020 14:18:49 +0800
+Received: from localhost.localdomain (10.17.3.153) by mtkcas07.mediatek.inc
+ (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend
+ Transport; Thu, 28 May 2020 14:18:47 +0800
+From: <chuanjia.liu@mediatek.com>
+To: <robh+dt@kernel.org>, <ryder.lee@mediatek.com>, <matthias.bgg@gmail.com>
+Subject: [PATCH v2 1/4] dt-bindings: PCI: Mediatek: Update PCIe binding
+Date: Thu, 28 May 2020 14:16:45 +0800
+Message-ID: <20200528061648.32078-2-chuanjia.liu@mediatek.com>
+X-Mailer: git-send-email 2.18.0
+In-Reply-To: <20200528061648.32078-1-chuanjia.liu@mediatek.com>
+References: <20200528061648.32078-1-chuanjia.liu@mediatek.com>
+MIME-Version: 1.0
+X-MTK: N
+X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 
+X-CRM114-CacheID: sfid-20200527_231958_261064_608CC03E 
+X-CRM114-Status: GOOD (  13.95  )
+X-Spam-Score: -0.2 (/)
+X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary:
+ Content analysis details:   (-0.2 points)
+ pts rule name              description
+ ---- ----------------------
+ --------------------------------------------------
+ -0.0 SPF_PASS               SPF: sender matches SPF record
+ 0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
+ 0.0 MIME_BASE64_TEXT       RAW: Message text disguised using base64
+ encoding
+ -0.1 DKIM_VALID_AU          Message has a valid DKIM or DK signature from
+ author's domain
+ 0.1 DKIM_SIGNED            Message has a DKIM or DK signature,
+ not necessarily
+ valid
+ -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature
+ -0.1 DKIM_VALID_EF          Message has a valid DKIM or DK signature from
+ envelope-from domain
+ 0.0 UNPARSEABLE_RELAY      Informational: message has unparseable relay
+ lines
+X-BeenThere: linux-mediatek@lists.infradead.org
+X-Mailman-Version: 2.1.29
+Precedence: list
+List-Id: <linux-mediatek.lists.infradead.org>
+List-Unsubscribe: <http://lists.infradead.org/mailman/options/linux-mediatek>,
+ <mailto:linux-mediatek-request@lists.infradead.org?subject=unsubscribe>
+List-Archive: <http://lists.infradead.org/pipermail/linux-mediatek/>
+List-Post: <mailto:linux-mediatek@lists.infradead.org>
+List-Help: <mailto:linux-mediatek-request@lists.infradead.org?subject=help>
+List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-mediatek>,
+ <mailto:linux-mediatek-request@lists.infradead.org?subject=subscribe>
+Cc: devicetree@vger.kernel.org, lorenzo.pieralisi@arm.com,
+ srv_heupstream@mediatek.com, "chuanjia.liu" <Chuanjia.Liu@mediatek.com>,
+ linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org,
+ jianjun.wang@mediatek.com, linux-mediatek@lists.infradead.org,
+ yong.wu@mediatek.com, bhelgaas@google.com,
+ linux-arm-kernel@lists.infradead.org, amurray@thegoodpenguin.co.uk
+Sender: "Linux-mediatek" <linux-mediatek-bounces@lists.infradead.org>
+Errors-To: 
+ linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org
+
+From: "chuanjia.liu" <Chuanjia.Liu@mediatek.com>
+
+There are two independent PCIe controllers in MT2712/MT7622 platform,
+and each of them should contain an independent MSI domain.
+
+In current architecture, MSI domain will be inherited from the root
+bridge, and all of the devices will share the same MSI domain.
+Hence that, the PCIe devices will not work properly if the irq number
+which required is more than 32.
+
+Split the PCIe node for MT2712/MT7622 platform to fix MSI issue and
+comply with the hardware design.
+
+Signed-off-by: chuanjia.liu <Chuanjia.Liu@mediatek.com>
+---
+ .../bindings/pci/mediatek-pcie-cfg.yaml       |  38 +++++
+ .../devicetree/bindings/pci/mediatek-pcie.txt | 144 +++++++++++-------
+ 2 files changed, 129 insertions(+), 53 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/pci/mediatek-pcie-cfg.yaml
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/pci/mediatek-pcie-cfg.yaml
+@@ -0,0 +1,38 @@
++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/pci/mediatek-pcie-cfg.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: Mediatek PCIECFG controller
++
++maintainers:
++  - Chuanjia Liu <chuanjia.liu@mediatek.com>
++  - Jianjun Wang <jianjun.wang@mediatek.com>
++
++description: |
++  The MediaTek PCIECFG controller controls some feature about
++  LTSSM, ASPM and so on.
++
++properties:
++  compatible:
++      items:
++        - enum:
++            - mediatek,mt7622-pciecfg
++            - mediatek,mt7629-pciecfg
++        - const: syscon
++
++  reg:
++    maxItems: 1
++
++required:
++  - compatible
++  - reg
++
++examples:
++  - |
++    pciecfg: pciecfg@1a140000 {
++        compatible = "mediatek,mt7622-pciecfg", "syscon";
++        reg = <0 0x1a140000 0 0x1000>;
++    };
++...
+--- a/Documentation/devicetree/bindings/pci/mediatek-pcie.txt
++++ b/Documentation/devicetree/bindings/pci/mediatek-pcie.txt
+@@ -8,7 +8,7 @@ Required properties:
+ 	"mediatek,mt7623-pcie"
+ 	"mediatek,mt7629-pcie"
+ - device_type: Must be "pci"
+-- reg: Base addresses and lengths of the PCIe subsys and root ports.
++- reg: Base addresses and lengths of the root ports.
+ - reg-names: Names of the above areas to use during resource lookup.
+ - #address-cells: Address representation for root ports (must be 3)
+ - #size-cells: Size representation for root ports (must be 2)
+@@ -19,10 +19,10 @@ Required properties:
+    - sys_ckN :transaction layer and data link layer clock
+   Required entries for MT2701/MT7623:
+    - free_ck :for reference clock of PCIe subsys
+-  Required entries for MT2712/MT7622:
++  Required entries for MT2712/MT7622/MT7629:
+    - ahb_ckN :AHB slave interface operating clock for CSR access and RC
+ 	      initiated MMIO access
+-  Required entries for MT7622:
++  Required entries for MT7622/MT7629:
+    - axi_ckN :application layer MMIO channel operating clock
+    - aux_ckN :pe2_mac_bridge and pe2_mac_core operating clock when
+ 	      pcie_mac_ck/pcie_pipe_ck is turned off
+@@ -47,10 +47,13 @@ Required properties for MT7623/MT2701:
+ - reset-names: Must be "pcie-rst0", "pcie-rst1", "pcie-rstN".. based on the
+   number of root ports.
+ 
+-Required properties for MT2712/MT7622:
++Required properties for MT2712/MT7622/MT7629:
+ -interrupts: A list of interrupt outputs of the controller, must have one
+ 	     entry for each PCIe port
+ 
++Required properties for MT7622/MT7629:
++- mediatek,pcie-subsys: Should be a phandle of the pciecfg node.
++
+ In addition, the device tree node must have sub-nodes describing each
+ PCIe port interface, having the following mandatory properties:
+ 
+@@ -143,56 +146,73 @@ Examples for MT7623:
+ 
+ Examples for MT2712:
+ 
+-	pcie: pcie@11700000 {
++	pcie1: pcie@112ff000 {
+ 		compatible = "mediatek,mt2712-pcie";
+ 		device_type = "pci";
+-		reg = <0 0x11700000 0 0x1000>,
+-		      <0 0x112ff000 0 0x1000>;
+-		reg-names = "port0", "port1";
++		reg = <0 0x112ff000 0 0x1000>;
++		reg-names = "port1";
+ 		#address-cells = <3>;
+ 		#size-cells = <2>;
+-		interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
+-			     <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+-		clocks = <&topckgen CLK_TOP_PE2_MAC_P0_SEL>,
+-			 <&topckgen CLK_TOP_PE2_MAC_P1_SEL>,
+-			 <&pericfg CLK_PERI_PCIE0>,
++		interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "pcie_irq";
++		clocks = <&topckgen CLK_TOP_PE2_MAC_P1_SEL>,
+ 			 <&pericfg CLK_PERI_PCIE1>;
+-		clock-names = "sys_ck0", "sys_ck1", "ahb_ck0", "ahb_ck1";
+-		phys = <&pcie0_phy PHY_TYPE_PCIE>, <&pcie1_phy PHY_TYPE_PCIE>;
+-		phy-names = "pcie-phy0", "pcie-phy1";
++		clock-names = "sys_ck1", "ahb_ck1";
++		phys = <&u3port1 PHY_TYPE_PCIE>;
++		phy-names = "pcie-phy1";
+ 		bus-range = <0x00 0xff>;
+-		ranges = <0x82000000 0 0x20000000  0x0 0x20000000  0 0x10000000>;
++		ranges = <0x82000000 0 0x11400000  0x0 0x11400000  0 0x300000>;
++		status = "disabled";
+ 
+-		pcie0: pcie@0,0 {
+-			reg = <0x0000 0 0 0 0>;
++		slot1: pcie@1,0 {
++			reg = <0x0800 0 0 0 0>;
+ 			#address-cells = <3>;
+ 			#size-cells = <2>;
+ 			#interrupt-cells = <1>;
+ 			ranges;
+ 			interrupt-map-mask = <0 0 0 7>;
+-			interrupt-map = <0 0 0 1 &pcie_intc0 0>,
+-					<0 0 0 2 &pcie_intc0 1>,
+-					<0 0 0 3 &pcie_intc0 2>,
+-					<0 0 0 4 &pcie_intc0 3>;
+-			pcie_intc0: interrupt-controller {
++			interrupt-map = <0 0 0 1 &pcie_intc1 0>,
++					<0 0 0 2 &pcie_intc1 1>,
++					<0 0 0 3 &pcie_intc1 2>,
++					<0 0 0 4 &pcie_intc1 3>;
++			pcie_intc1: interrupt-controller {
+ 				interrupt-controller;
+ 				#address-cells = <0>;
+ 				#interrupt-cells = <1>;
+ 			};
+ 		};
++	};
+ 
+-		pcie1: pcie@1,0 {
+-			reg = <0x0800 0 0 0 0>;
++	pcie0: pcie@11700000 {
++		compatible = "mediatek,mt2712-pcie";
++		device_type = "pci";
++		reg = <0 0x11700000 0 0x1000>;
++		reg-names = "port0";
++		#address-cells = <3>;
++		#size-cells = <2>;
++		interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "pcie_irq";
++		clocks = <&topckgen CLK_TOP_PE2_MAC_P0_SEL>,
++			 <&pericfg CLK_PERI_PCIE0>;
++		clock-names = "sys_ck0", "ahb_ck0";
++		phys = <&u3port0 PHY_TYPE_PCIE>;
++		phy-names = "pcie-phy0";
++		bus-range = <0x00 0xff>;
++		ranges = <0x82000000 0 0x20000000  0x0 0x20000000  0 0x10000000>;
++		status = "disabled";
++
++		slot0: pcie@0,0 {
++			reg = <0x0000 0 0 0 0>;
+ 			#address-cells = <3>;
+ 			#size-cells = <2>;
+ 			#interrupt-cells = <1>;
+ 			ranges;
+ 			interrupt-map-mask = <0 0 0 7>;
+-			interrupt-map = <0 0 0 1 &pcie_intc1 0>,
+-					<0 0 0 2 &pcie_intc1 1>,
+-					<0 0 0 3 &pcie_intc1 2>,
+-					<0 0 0 4 &pcie_intc1 3>;
+-			pcie_intc1: interrupt-controller {
++			interrupt-map = <0 0 0 1 &pcie_intc0 0>,
++					<0 0 0 2 &pcie_intc0 1>,
++					<0 0 0 3 &pcie_intc0 2>,
++					<0 0 0 4 &pcie_intc0 3>;
++			pcie_intc0: interrupt-controller {
+ 				interrupt-controller;
+ 				#address-cells = <0>;
+ 				#interrupt-cells = <1>;
+@@ -202,39 +222,31 @@ Examples for MT2712:
+ 
+ Examples for MT7622:
+ 
+-	pcie: pcie@1a140000 {
++	pcie0: pcie@1a143000 {
+ 		compatible = "mediatek,mt7622-pcie";
+ 		device_type = "pci";
+-		reg = <0 0x1a140000 0 0x1000>,
+-		      <0 0x1a143000 0 0x1000>,
+-		      <0 0x1a145000 0 0x1000>;
+-		reg-names = "subsys", "port0", "port1";
++		reg = <0 0x1a143000 0 0x1000>;
++		reg-names = "port0";
++		mediatek,pcie-cfg = <&pciecfg>;
+ 		#address-cells = <3>;
+ 		#size-cells = <2>;
+-		interrupts = <GIC_SPI 228 IRQ_TYPE_LEVEL_LOW>,
+-			     <GIC_SPI 229 IRQ_TYPE_LEVEL_LOW>;
++		interrupts = <GIC_SPI 228 IRQ_TYPE_LEVEL_LOW>;
++		interrupt-names = "pcie_irq";
+ 		clocks = <&pciesys CLK_PCIE_P0_MAC_EN>,
+-			 <&pciesys CLK_PCIE_P1_MAC_EN>,
+ 			 <&pciesys CLK_PCIE_P0_AHB_EN>,
+-			 <&pciesys CLK_PCIE_P1_AHB_EN>,
+ 			 <&pciesys CLK_PCIE_P0_AUX_EN>,
+-			 <&pciesys CLK_PCIE_P1_AUX_EN>,
+ 			 <&pciesys CLK_PCIE_P0_AXI_EN>,
+-			 <&pciesys CLK_PCIE_P1_AXI_EN>,
+ 			 <&pciesys CLK_PCIE_P0_OBFF_EN>,
+-			 <&pciesys CLK_PCIE_P1_OBFF_EN>,
+-			 <&pciesys CLK_PCIE_P0_PIPE_EN>,
+-			 <&pciesys CLK_PCIE_P1_PIPE_EN>;
+-		clock-names = "sys_ck0", "sys_ck1", "ahb_ck0", "ahb_ck1",
+-			      "aux_ck0", "aux_ck1", "axi_ck0", "axi_ck1",
+-			      "obff_ck0", "obff_ck1", "pipe_ck0", "pipe_ck1";
+-		phys = <&pcie0_phy PHY_TYPE_PCIE>, <&pcie1_phy PHY_TYPE_PCIE>;
+-		phy-names = "pcie-phy0", "pcie-phy1";
++			 <&pciesys CLK_PCIE_P0_PIPE_EN>;
++		clock-names = "sys_ck0", "ahb_ck0", "aux_ck0",
++			      "axi_ck0", "obff_ck0", "pipe_ck0";
++
+ 		power-domains = <&scpsys MT7622_POWER_DOMAIN_HIF0>;
+ 		bus-range = <0x00 0xff>;
+-		ranges = <0x82000000 0 0x20000000  0x0 0x20000000  0 0x10000000>;
++		ranges = <0x82000000 0 0x20000000  0 0x20000000  0 0x8000000>;
++		status = "disabled";
+ 
+-		pcie0: pcie@0,0 {
++		slot0: pcie@0,0 {
+ 			reg = <0x0000 0 0 0 0>;
+ 			#address-cells = <3>;
+ 			#size-cells = <2>;
+@@ -251,8 +263,34 @@ Examples for MT7622:
+ 				#interrupt-cells = <1>;
+ 			};
+ 		};
++	};
++
++	pcie1: pcie@1a145000 {
++		compatible = "mediatek,mt7622-pcie";
++		device_type = "pci";
++		reg = <0 0x1a145000 0 0x1000>;
++		reg-names = "port1";
++		mediatek,pcie-cfg = <&pciecfg>;
++		#address-cells = <3>;
++		#size-cells = <2>;
++		interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_LOW>;
++		interrupt-names = "pcie_irq";
++		clocks = <&pciesys CLK_PCIE_P1_MAC_EN>,
++			 /* designer has connect RC1 with p0_ahb clock */
++			 <&pciesys CLK_PCIE_P0_AHB_EN>,
++			 <&pciesys CLK_PCIE_P1_AUX_EN>,
++			 <&pciesys CLK_PCIE_P1_AXI_EN>,
++			 <&pciesys CLK_PCIE_P1_OBFF_EN>,
++			 <&pciesys CLK_PCIE_P1_PIPE_EN>;
++		clock-names = "sys_ck1", "ahb_ck1", "aux_ck1",
++			      "axi_ck1", "obff_ck1", "pipe_ck1";
++
++		power-domains = <&scpsys MT7622_POWER_DOMAIN_HIF0>;
++		bus-range = <0x00 0xff>;
++		ranges = <0x82000000 0 0x28000000  0 0x28000000  0 0x8000000>;
++		status = "disabled";
+ 
+-		pcie1: pcie@1,0 {
++		slot1: pcie@1,0 {
+ 			reg = <0x0800 0 0 0 0>;
+ 			#address-cells = <3>;
+ 			#size-cells = <2>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0992-PCI-mediatek-Use-regmap-to-get-shared-pcie-cfg-base.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0992-PCI-mediatek-Use-regmap-to-get-shared-pcie-cfg-base.patch
new file mode 100644
index 0000000..3e4d44f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0992-PCI-mediatek-Use-regmap-to-get-shared-pcie-cfg-base.patch
@@ -0,0 +1,217 @@
+From patchwork Thu May 28 06:16:46 2020
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: Chuanjia Liu <chuanjia.liu@mediatek.com>
+X-Patchwork-Id: 11574781
+Return-Path: 
+ <SRS0=ftSA=7K=lists.infradead.org=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@kernel.org>
+Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org
+ [172.30.200.123])
+	by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0A99B60D
+	for <patchwork-linux-mediatek@patchwork.kernel.org>;
+ Thu, 28 May 2020 06:19:04 +0000 (UTC)
+Received: from bombadil.infradead.org (bombadil.infradead.org
+ [198.137.202.133])
+	(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
+	(No client certificate requested)
+	by mail.kernel.org (Postfix) with ESMTPS id DCC99208FE
+	for <patchwork-linux-mediatek@patchwork.kernel.org>;
+ Thu, 28 May 2020 06:19:03 +0000 (UTC)
+Authentication-Results: mail.kernel.org;
+	dkim=pass (2048-bit key) header.d=lists.infradead.org
+ header.i=@lists.infradead.org header.b="SpOi0ueF";
+	dkim=fail reason="signature verification failed" (1024-bit key)
+ header.d=mediatek.com header.i=@mediatek.com header.b="UGIBoIEG"
+DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DCC99208FE
+Authentication-Results: mail.kernel.org;
+ dmarc=fail (p=none dis=none) header.from=mediatek.com
+Authentication-Results: mail.kernel.org;
+ spf=none
+ smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
+	d=lists.infradead.org; s=bombadil.20170209; h=Sender:
+	Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post:
+	List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:
+	Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description:
+	Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:
+	List-Owner; bh=LIr5poLUT/UdH6/akh/pnICGGa3rUBkN+4FhE1DyOrU=; b=SpOi0ueFcoJ/ka
+	4esa6cDd5oU4fp0z684ZVPaVvvhm/azSZBBMYinHaAW6EvzKcMNYIX9grP8eg/728lEPNTKVq0I8H
+	PQZ9KvD4uTu8Opo1hD8LsRSLr+YLpNKt3KPOY/4gpwQ97uU9rI5PwkuAxPBgR949Vh5EiG0Vaww1H
+	Ep+I5BFRn2LVVQZP1Z7U0A0VUcOTLJ4znoWRLEXxtM9/Wd4hwQsrEPQszeDFti/RbwGfJ5efOb5UL
+	fhwBzSxELEzAAgH7env/XD2sSSpVf2Qsn6WO8D3ZepMtWrRtARiaRKSNxSBQTg2SSHcjmBSJSzcX+
+	w8wqWaUMs0crlBuZWS1g==;
+Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org)
+	by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux))
+	id 1jeBsc-0001tI-88; Thu, 28 May 2020 06:19:02 +0000
+Received: from mailgw01.mediatek.com ([216.200.240.184])
+ by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1jeBsZ-0001rp-6g; Thu, 28 May 2020 06:19:01 +0000
+X-UUID: beeaf5765357439c91eab1f67ca7ef43-20200527
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
+ d=mediatek.com;
+ s=dk;
+ h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From;
+ bh=+IjWjsF/DhknqZB+lLSZ50cyvxDap+8w4tvqhp8Dv68=;
+ b=UGIBoIEGJUuq5pEvYEad1HVGpiv6yma+94hva83D2gD8lYmihRWkpJxB2yn+dVtNm7ZXXoQBf+jvvULOmslJgs1HZTLJTnjpdvLmQqo42OXRXSVpTE49HdRkJZDAIWIAReBfOEkFgNxcIX3uedrtnww/NLJ2lagrYPG5ET4lI2E=;
+X-UUID: beeaf5765357439c91eab1f67ca7ef43-20200527
+Received: from mtkcas68.mediatek.inc [(172.29.94.19)] by mailgw01.mediatek.com
+ (envelope-from <chuanjia.liu@mediatek.com>)
+ (musrelay.mediatek.com ESMTP with TLS)
+ with ESMTP id 603406343; Wed, 27 May 2020 22:19:17 -0800
+Received: from mtkmbs07n1.mediatek.inc (172.21.101.16) by
+ MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id
+ 15.0.1497.2; Wed, 27 May 2020 23:18:47 -0700
+Received: from mtkcas07.mediatek.inc (172.21.101.84) by
+ mtkmbs07n1.mediatek.inc (172.21.101.16) with Microsoft SMTP Server (TLS) id
+ 15.0.1497.2; Thu, 28 May 2020 14:18:51 +0800
+Received: from localhost.localdomain (10.17.3.153) by mtkcas07.mediatek.inc
+ (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend
+ Transport; Thu, 28 May 2020 14:18:49 +0800
+From: <chuanjia.liu@mediatek.com>
+To: <robh+dt@kernel.org>, <ryder.lee@mediatek.com>, <matthias.bgg@gmail.com>
+Subject: [PATCH v2 2/4] PCI: mediatek: Use regmap to get shared pcie-cfg base
+Date: Thu, 28 May 2020 14:16:46 +0800
+Message-ID: <20200528061648.32078-3-chuanjia.liu@mediatek.com>
+X-Mailer: git-send-email 2.18.0
+In-Reply-To: <20200528061648.32078-1-chuanjia.liu@mediatek.com>
+References: <20200528061648.32078-1-chuanjia.liu@mediatek.com>
+MIME-Version: 1.0
+X-MTK: N
+X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 
+X-CRM114-CacheID: sfid-20200527_231859_251275_BED2B1E2 
+X-CRM114-Status: GOOD (  11.62  )
+X-Spam-Score: -0.2 (/)
+X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary:
+ Content analysis details:   (-0.2 points)
+ pts rule name              description
+ ---- ----------------------
+ --------------------------------------------------
+ -0.0 SPF_PASS               SPF: sender matches SPF record
+ 0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
+ 0.0 MIME_BASE64_TEXT       RAW: Message text disguised using base64
+ encoding
+ -0.1 DKIM_VALID_AU          Message has a valid DKIM or DK signature from
+ author's domain
+ 0.1 DKIM_SIGNED            Message has a DKIM or DK signature,
+ not necessarily
+ valid
+ -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature
+ -0.1 DKIM_VALID_EF          Message has a valid DKIM or DK signature from
+ envelope-from domain
+ 0.0 UNPARSEABLE_RELAY      Informational: message has unparseable relay
+ lines
+X-BeenThere: linux-mediatek@lists.infradead.org
+X-Mailman-Version: 2.1.29
+Precedence: list
+List-Id: <linux-mediatek.lists.infradead.org>
+List-Unsubscribe: <http://lists.infradead.org/mailman/options/linux-mediatek>,
+ <mailto:linux-mediatek-request@lists.infradead.org?subject=unsubscribe>
+List-Archive: <http://lists.infradead.org/pipermail/linux-mediatek/>
+List-Post: <mailto:linux-mediatek@lists.infradead.org>
+List-Help: <mailto:linux-mediatek-request@lists.infradead.org?subject=help>
+List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-mediatek>,
+ <mailto:linux-mediatek-request@lists.infradead.org?subject=subscribe>
+Cc: devicetree@vger.kernel.org, lorenzo.pieralisi@arm.com,
+ srv_heupstream@mediatek.com, "chuanjia.liu" <Chuanjia.Liu@mediatek.com>,
+ linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org,
+ jianjun.wang@mediatek.com, linux-mediatek@lists.infradead.org,
+ yong.wu@mediatek.com, bhelgaas@google.com,
+ linux-arm-kernel@lists.infradead.org, amurray@thegoodpenguin.co.uk
+Sender: "Linux-mediatek" <linux-mediatek-bounces@lists.infradead.org>
+Errors-To: 
+ linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org
+
+From: "chuanjia.liu" <Chuanjia.Liu@mediatek.com>
+
+Use regmap to get shared pcie-cfg base and change
+the method to get pcie irq.
+
+Signed-off-by: chuanjia.liu <Chuanjia.Liu@mediatek.com>
+---
+ drivers/pci/controller/pcie-mediatek.c | 25 ++++++++++++++++++-------
+ 1 file changed, 18 insertions(+), 7 deletions(-)
+
+--- a/drivers/pci/controller/pcie-mediatek.c
++++ b/drivers/pci/controller/pcie-mediatek.c
+@@ -14,6 +14,7 @@
+ #include <linux/irqchip/chained_irq.h>
+ #include <linux/irqdomain.h>
+ #include <linux/kernel.h>
++#include <linux/mfd/syscon.h>
+ #include <linux/msi.h>
+ #include <linux/module.h>
+ #include <linux/of_address.h>
+@@ -23,6 +24,7 @@
+ #include <linux/phy/phy.h>
+ #include <linux/platform_device.h>
+ #include <linux/pm_runtime.h>
++#include <linux/regmap.h>
+ #include <linux/reset.h>
+ 
+ #include "../pci.h"
+@@ -205,6 +207,7 @@ struct mtk_pcie_port {
+  * struct mtk_pcie - PCIe host information
+  * @dev: pointer to PCIe device
+  * @base: IO mapped register base
++ * @cfg: IO mapped register map for PCIe config
+  * @free_ck: free-run reference clock
+  * @mem: non-prefetchable memory resource
+  * @ports: pointer to PCIe port information
+@@ -214,6 +217,7 @@ struct mtk_pcie_port {
+ struct mtk_pcie {
+ 	struct device *dev;
+ 	void __iomem *base;
++	struct regmap *cfg;
+ 	struct clk *free_ck;
+ 
+ 	struct resource mem;
+@@ -651,7 +655,7 @@ static int mtk_pcie_setup_irq(struct mtk
+ 		return err;
+ 	}
+ 
+-	port->irq = platform_get_irq(pdev, port->slot);
++	port->irq = platform_get_irq_byname(pdev, "pcie_irq");
+ 	irq_set_chained_handler_and_data(port->irq,
+ 					 mtk_pcie_intr_handler, port);
+ 
+@@ -666,12 +670,11 @@ static int mtk_pcie_startup_port_v2(stru
+ 	u32 val;
+ 	int err;
+ 
+-	/* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */
+-	if (pcie->base) {
+-		val = readl(pcie->base + PCIE_SYS_CFG_V2);
+-		val |= PCIE_CSR_LTSSM_EN(port->slot) |
+-		       PCIE_CSR_ASPM_L1_EN(port->slot);
+-		writel(val, pcie->base + PCIE_SYS_CFG_V2);
++	/* MT7622/MT7629 platforms need to enable LTSSM and ASPM. */
++	if (pcie->cfg) {
++		val = PCIE_CSR_LTSSM_EN(port->slot) |
++		      PCIE_CSR_ASPM_L1_EN(port->slot);
++		regmap_update_bits(pcie->cfg, PCIE_SYS_CFG_V2, val, val);
+ 	}
+ 
+ 	/* Assert all reset signals */
+@@ -977,6 +980,7 @@ static int mtk_pcie_subsys_powerup(struc
+ 	struct device *dev = pcie->dev;
+ 	struct platform_device *pdev = to_platform_device(dev);
+ 	struct resource *regs;
++	struct device_node *cfg_node;
+ 	int err;
+ 
+ 	/* get shared registers, which are optional */
+@@ -989,6 +993,13 @@ static int mtk_pcie_subsys_powerup(struc
+ 		}
+ 	}
+ 
++	cfg_node = of_parse_phandle(dev->of_node, "mediatek,pcie-cfg", 0);
++	if (cfg_node) {
++		pcie->cfg = syscon_node_to_regmap(cfg_node);
++		if (IS_ERR(pcie->cfg))
++			return PTR_ERR(pcie->cfg);
++	}
++
+ 	pcie->free_ck = devm_clk_get(dev, "free_ck");
+ 	if (IS_ERR(pcie->free_ck)) {
+ 		if (PTR_ERR(pcie->free_ck) == -EPROBE_DEFER)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0993-arm64-dts-mediatek-Split-PCIe-node-for-MT2712-MT7622.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0993-arm64-dts-mediatek-Split-PCIe-node-for-MT2712-MT7622.patch
new file mode 100644
index 0000000..3c5558b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0993-arm64-dts-mediatek-Split-PCIe-node-for-MT2712-MT7622.patch
@@ -0,0 +1,417 @@
+From patchwork Thu May 28 06:16:47 2020
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: Chuanjia Liu <chuanjia.liu@mediatek.com>
+X-Patchwork-Id: 11574785
+Return-Path: 
+ <SRS0=ftSA=7K=lists.infradead.org=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@kernel.org>
+Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org
+ [172.30.200.123])
+	by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 933301391
+	for <patchwork-linux-mediatek@patchwork.kernel.org>;
+ Thu, 28 May 2020 06:19:16 +0000 (UTC)
+Received: from bombadil.infradead.org (bombadil.infradead.org
+ [198.137.202.133])
+	(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
+	(No client certificate requested)
+	by mail.kernel.org (Postfix) with ESMTPS id D19F02078C
+	for <patchwork-linux-mediatek@patchwork.kernel.org>;
+ Thu, 28 May 2020 06:19:15 +0000 (UTC)
+Authentication-Results: mail.kernel.org;
+	dkim=pass (2048-bit key) header.d=lists.infradead.org
+ header.i=@lists.infradead.org header.b="s8K7t7DF";
+	dkim=fail reason="signature verification failed" (1024-bit key)
+ header.d=mediatek.com header.i=@mediatek.com header.b="RhX81Iqp"
+DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D19F02078C
+Authentication-Results: mail.kernel.org;
+ dmarc=fail (p=none dis=none) header.from=mediatek.com
+Authentication-Results: mail.kernel.org;
+ spf=none
+ smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
+	d=lists.infradead.org; s=bombadil.20170209; h=Sender:
+	Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post:
+	List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:
+	Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description:
+	Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:
+	List-Owner; bh=NHyHqNMcE7LW10MwduOJoKiWe8cv+XayY+L6WDZeSu0=; b=s8K7t7DFh1iQ5w
+	eGvuMRgXEQv/YWRuSZRyX8lx8R2H9IuawEIgkhO6lEo6xv0VdsRuj8SptfoWg5afCItMhih373M21
+	6sUy3tEiuKGgklfxLU0reLEkaATkKRGLJDY3eSSs1mvZDrydKuZLDTka+YDGaiESlOhqMr95Nm6YM
+	yK8O00qTwSRPJUILRsBv1e/Kz8NRCmYhs56snABJkKeJ51NRAkb20R6qGTEd6UyBlz3jTVYwluLgF
+	bdqzywDT6+BNg/Agh6Zd+v2PpO4cmwCpGm62+3UUyZkfi/aQ4qZ/AFAfSQI+3ZBAgsKMC1PGifOi/
+	FgGxIvAUk6atBy7DAHuw==;
+Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org)
+	by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux))
+	id 1jeBsn-00025C-EF; Thu, 28 May 2020 06:19:13 +0000
+Received: from mailgw01.mediatek.com ([216.200.240.184])
+ by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1jeBsZ-0001s4-6j; Thu, 28 May 2020 06:19:01 +0000
+X-UUID: c6210e6371fa445db0ae40a8b8a7a0a1-20200527
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
+ d=mediatek.com;
+ s=dk;
+ h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From;
+ bh=X9AwTdbhpWmlWY4LjTm8KLq4Cca3YI9UnyCX3O0BAak=;
+ b=RhX81Iqp0mWhBDyMQMFSEtt23+DGAWoin1SrFGP1bzp6GEtu38b2pK5RJVBshJtuxi/a1uMXZjeDsHJn02VGdNA07FrzZ7jq6YYEL+8cJs2DnhySmNElZazXPv2vKu9TWygfilTT24h/u8V/eszuRuhkdoUKWol8LwDlPl9gskg=;
+X-UUID: c6210e6371fa445db0ae40a8b8a7a0a1-20200527
+Received: from mtkcas68.mediatek.inc [(172.29.94.19)] by mailgw01.mediatek.com
+ (envelope-from <chuanjia.liu@mediatek.com>)
+ (musrelay.mediatek.com ESMTP with TLS)
+ with ESMTP id 7561992; Wed, 27 May 2020 22:19:17 -0800
+Received: from mtkmbs07n1.mediatek.inc (172.21.101.16) by
+ MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id
+ 15.0.1497.2; Wed, 27 May 2020 23:18:47 -0700
+Received: from mtkcas07.mediatek.inc (172.21.101.84) by
+ mtkmbs07n1.mediatek.inc (172.21.101.16) with Microsoft SMTP Server (TLS) id
+ 15.0.1497.2; Thu, 28 May 2020 14:18:52 +0800
+Received: from localhost.localdomain (10.17.3.153) by mtkcas07.mediatek.inc
+ (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend
+ Transport; Thu, 28 May 2020 14:18:51 +0800
+From: <chuanjia.liu@mediatek.com>
+To: <robh+dt@kernel.org>, <ryder.lee@mediatek.com>, <matthias.bgg@gmail.com>
+Subject: [PATCH v2 3/4] arm64: dts: mediatek: Split PCIe node for
+ MT2712/MT7622
+Date: Thu, 28 May 2020 14:16:47 +0800
+Message-ID: <20200528061648.32078-4-chuanjia.liu@mediatek.com>
+X-Mailer: git-send-email 2.18.0
+In-Reply-To: <20200528061648.32078-1-chuanjia.liu@mediatek.com>
+References: <20200528061648.32078-1-chuanjia.liu@mediatek.com>
+MIME-Version: 1.0
+X-MTK: N
+X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 
+X-CRM114-CacheID: sfid-20200527_231859_253529_B6751C5A 
+X-CRM114-Status: GOOD (  12.20  )
+X-Spam-Score: -0.2 (/)
+X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary:
+ Content analysis details:   (-0.2 points)
+ pts rule name              description
+ ---- ----------------------
+ --------------------------------------------------
+ -0.0 SPF_PASS               SPF: sender matches SPF record
+ 0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
+ 0.0 MIME_BASE64_TEXT       RAW: Message text disguised using base64
+ encoding
+ -0.1 DKIM_VALID_AU          Message has a valid DKIM or DK signature from
+ author's domain
+ 0.1 DKIM_SIGNED            Message has a DKIM or DK signature,
+ not necessarily
+ valid
+ -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature
+ -0.1 DKIM_VALID_EF          Message has a valid DKIM or DK signature from
+ envelope-from domain
+ 0.0 UNPARSEABLE_RELAY      Informational: message has unparseable relay
+ lines
+X-BeenThere: linux-mediatek@lists.infradead.org
+X-Mailman-Version: 2.1.29
+Precedence: list
+List-Id: <linux-mediatek.lists.infradead.org>
+List-Unsubscribe: <http://lists.infradead.org/mailman/options/linux-mediatek>,
+ <mailto:linux-mediatek-request@lists.infradead.org?subject=unsubscribe>
+List-Archive: <http://lists.infradead.org/pipermail/linux-mediatek/>
+List-Post: <mailto:linux-mediatek@lists.infradead.org>
+List-Help: <mailto:linux-mediatek-request@lists.infradead.org?subject=help>
+List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-mediatek>,
+ <mailto:linux-mediatek-request@lists.infradead.org?subject=subscribe>
+Cc: devicetree@vger.kernel.org, lorenzo.pieralisi@arm.com,
+ srv_heupstream@mediatek.com, "chuanjia.liu" <Chuanjia.Liu@mediatek.com>,
+ linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org,
+ jianjun.wang@mediatek.com, linux-mediatek@lists.infradead.org,
+ yong.wu@mediatek.com, bhelgaas@google.com,
+ linux-arm-kernel@lists.infradead.org, amurray@thegoodpenguin.co.uk
+Sender: "Linux-mediatek" <linux-mediatek-bounces@lists.infradead.org>
+Errors-To: 
+ linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org
+
+From: "chuanjia.liu" <Chuanjia.Liu@mediatek.com>
+
+There are two independent PCIe controllers in MT2712/MT7622 platform,
+and each of them should contain an independent MSI domain.
+
+In current architecture, MSI domain will be inherited from the root
+bridge, and all of the devices will share the same MSI domain.
+Hence that, the PCIe devices will not work properly if the irq number
+which required is more than 32.
+
+Split the PCIe node for MT2712/MT7622 platform to fix MSI issue and
+comply with the hardware design.
+
+Signed-off-by: chuanjia.liu <Chuanjia.Liu@mediatek.com>
+---
+ arch/arm64/boot/dts/mediatek/mt2712e.dtsi     | 75 +++++++++++--------
+ .../dts/mediatek/mt7622-bananapi-bpi-r64.dts  | 16 ++--
+ arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts  |  6 +-
+ arch/arm64/boot/dts/mediatek/mt7622.dtsi      | 68 +++++++++++------
+ 4 files changed, 96 insertions(+), 69 deletions(-)
+
+--- a/arch/arm64/boot/dts/mediatek/mt2712e.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt2712e.dtsi
+@@ -791,60 +791,73 @@
+ 		};
+ 	};
+ 
+-	pcie: pcie@11700000 {
++	pcie1: pcie@112ff000 {
+ 		compatible = "mediatek,mt2712-pcie";
+ 		device_type = "pci";
+-		reg = <0 0x11700000 0 0x1000>,
+-		      <0 0x112ff000 0 0x1000>;
+-		reg-names = "port0", "port1";
++		reg = <0 0x112ff000 0 0x1000>;
++		reg-names = "port1";
+ 		#address-cells = <3>;
+ 		#size-cells = <2>;
+-		interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
+-			     <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+-		clocks = <&topckgen CLK_TOP_PE2_MAC_P0_SEL>,
+-			 <&topckgen CLK_TOP_PE2_MAC_P1_SEL>,
+-			 <&pericfg CLK_PERI_PCIE0>,
++		interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "pcie_irq";
++		clocks = <&topckgen CLK_TOP_PE2_MAC_P1_SEL>,
+ 			 <&pericfg CLK_PERI_PCIE1>;
+-		clock-names = "sys_ck0", "sys_ck1", "ahb_ck0", "ahb_ck1";
+-		phys = <&u3port0 PHY_TYPE_PCIE>, <&u3port1 PHY_TYPE_PCIE>;
+-		phy-names = "pcie-phy0", "pcie-phy1";
++		clock-names = "sys_ck1", "ahb_ck1";
++		phys = <&u3port1 PHY_TYPE_PCIE>;
++		phy-names = "pcie-phy1";
+ 		bus-range = <0x00 0xff>;
+-		ranges = <0x82000000 0 0x20000000  0x0 0x20000000  0 0x10000000>;
++		ranges = <0x82000000 0 0x11400000  0x0 0x11400000  0 0x300000>;
++		status = "disabled";
+ 
+-		pcie0: pcie@0,0 {
+-			device_type = "pci";
+-			status = "disabled";
+-			reg = <0x0000 0 0 0 0>;
++		slot1: pcie@1,0 {
++			reg = <0x0800 0 0 0 0>;
+ 			#address-cells = <3>;
+ 			#size-cells = <2>;
+ 			#interrupt-cells = <1>;
+ 			ranges;
+ 			interrupt-map-mask = <0 0 0 7>;
+-			interrupt-map = <0 0 0 1 &pcie_intc0 0>,
+-					<0 0 0 2 &pcie_intc0 1>,
+-					<0 0 0 3 &pcie_intc0 2>,
+-					<0 0 0 4 &pcie_intc0 3>;
+-			pcie_intc0: interrupt-controller {
++			interrupt-map = <0 0 0 1 &pcie_intc1 0>,
++					<0 0 0 2 &pcie_intc1 1>,
++					<0 0 0 3 &pcie_intc1 2>,
++					<0 0 0 4 &pcie_intc1 3>;
++			pcie_intc1: interrupt-controller {
+ 				interrupt-controller;
+ 				#address-cells = <0>;
+ 				#interrupt-cells = <1>;
+ 			};
+ 		};
++	};
+ 
+-		pcie1: pcie@1,0 {
+-			device_type = "pci";
+-			status = "disabled";
+-			reg = <0x0800 0 0 0 0>;
++	pcie0: pcie@11700000 {
++		compatible = "mediatek,mt2712-pcie";
++		device_type = "pci";
++		reg = <0 0x11700000 0 0x1000>;
++		reg-names = "port0";
++		#address-cells = <3>;
++		#size-cells = <2>;
++		interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "pcie_irq";
++		clocks = <&topckgen CLK_TOP_PE2_MAC_P0_SEL>,
++			 <&pericfg CLK_PERI_PCIE0>;
++		clock-names = "sys_ck0", "ahb_ck0";
++		phys = <&u3port0 PHY_TYPE_PCIE>;
++		phy-names = "pcie-phy0";
++		bus-range = <0x00 0xff>;
++		ranges = <0x82000000 0 0x20000000 0x0 0x20000000 0 0x10000000>;
++		status = "disabled";
++
++		slot0: pcie@0,0 {
++			reg = <0x0000 0 0 0 0>;
+ 			#address-cells = <3>;
+ 			#size-cells = <2>;
+ 			#interrupt-cells = <1>;
+ 			ranges;
+ 			interrupt-map-mask = <0 0 0 7>;
+-			interrupt-map = <0 0 0 1 &pcie_intc1 0>,
+-					<0 0 0 2 &pcie_intc1 1>,
+-					<0 0 0 3 &pcie_intc1 2>,
+-					<0 0 0 4 &pcie_intc1 3>;
+-			pcie_intc1: interrupt-controller {
++			interrupt-map = <0 0 0 1 &pcie_intc0 0>,
++					<0 0 0 2 &pcie_intc0 1>,
++					<0 0 0 3 &pcie_intc0 2>,
++					<0 0 0 4 &pcie_intc0 3>;
++			pcie_intc0: interrupt-controller {
+ 				interrupt-controller;
+ 				#address-cells = <0>;
+ 				#interrupt-cells = <1>;
+--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts
+@@ -294,18 +294,16 @@
+ 	};
+ };
+ 
+-&pcie {
++&pcie0 {
+ 	pinctrl-names = "default";
+-	pinctrl-0 = <&pcie0_pins>, <&pcie1_pins>;
++	pinctrl-0 = <&pcie0_pins>;
+ 	status = "okay";
++};
+ 
+-	pcie@0,0 {
+-		status = "okay";
+-	};
+-
+-	pcie@1,0 {
+-		status = "okay";
+-	};
++&pcie1 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&pcie1_pins>;
++	status = "okay";
+ };
+ 
+ &pio {
+--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
+@@ -794,45 +794,41 @@
+ 		#reset-cells = <1>;
+ 	};
+ 
+-	pcie: pcie@1a140000 {
++	pciecfg: pciecfg@1a140000 {
++		compatible = "mediatek,mt7622-pciecfg", "syscon";
++		reg = <0 0x1a140000 0 0x1000>;
++	};
++
++	pcie0: pcie@1a143000 {
+ 		compatible = "mediatek,mt7622-pcie";
+ 		device_type = "pci";
+-		reg = <0 0x1a140000 0 0x1000>,
+-		      <0 0x1a143000 0 0x1000>,
+-		      <0 0x1a145000 0 0x1000>;
+-		reg-names = "subsys", "port0", "port1";
++		reg = <0 0x1a143000 0 0x1000>;
++		reg-names = "port0";
++		mediatek,pcie-cfg = <&pciecfg>;
+ 		#address-cells = <3>;
+ 		#size-cells = <2>;
+-		interrupts = <GIC_SPI 228 IRQ_TYPE_LEVEL_LOW>,
+-			     <GIC_SPI 229 IRQ_TYPE_LEVEL_LOW>;
++		interrupts = <GIC_SPI 228 IRQ_TYPE_LEVEL_LOW>;
++		interrupt-names = "pcie_irq";
+ 		clocks = <&pciesys CLK_PCIE_P0_MAC_EN>,
+-			 <&pciesys CLK_PCIE_P1_MAC_EN>,
+-			 <&pciesys CLK_PCIE_P0_AHB_EN>,
+ 			 <&pciesys CLK_PCIE_P0_AHB_EN>,
+ 			 <&pciesys CLK_PCIE_P0_AUX_EN>,
+-			 <&pciesys CLK_PCIE_P1_AUX_EN>,
+ 			 <&pciesys CLK_PCIE_P0_AXI_EN>,
+-			 <&pciesys CLK_PCIE_P1_AXI_EN>,
+ 			 <&pciesys CLK_PCIE_P0_OBFF_EN>,
+-			 <&pciesys CLK_PCIE_P1_OBFF_EN>,
+-			 <&pciesys CLK_PCIE_P0_PIPE_EN>,
+-			 <&pciesys CLK_PCIE_P1_PIPE_EN>;
+-		clock-names = "sys_ck0", "sys_ck1", "ahb_ck0", "ahb_ck1",
+-			      "aux_ck0", "aux_ck1", "axi_ck0", "axi_ck1",
+-			      "obff_ck0", "obff_ck1", "pipe_ck0", "pipe_ck1";
++			 <&pciesys CLK_PCIE_P0_PIPE_EN>;
++		clock-names = "sys_ck0", "ahb_ck0", "aux_ck0",
++			      "axi_ck0", "obff_ck0", "pipe_ck0";
++
+ 		power-domains = <&scpsys MT7622_POWER_DOMAIN_HIF0>;
+ 		bus-range = <0x00 0xff>;
+-		ranges = <0x82000000 0 0x20000000 0x0 0x20000000 0 0x10000000>;
++		ranges = <0x82000000 0 0x20000000  0x0 0x20000000  0 0x8000000>;
+ 		status = "disabled";
+ 
+-		pcie0: pcie@0,0 {
++		slot0: pcie@0,0 {
+ 			reg = <0x0000 0 0 0 0>;
+ 			#address-cells = <3>;
+ 			#size-cells = <2>;
+ 			#interrupt-cells = <1>;
+ 			ranges;
+-			status = "disabled";
+-
+ 			interrupt-map-mask = <0 0 0 7>;
+ 			interrupt-map = <0 0 0 1 &pcie_intc0 0>,
+ 					<0 0 0 2 &pcie_intc0 1>,
+@@ -844,15 +840,39 @@
+ 				#interrupt-cells = <1>;
+ 			};
+ 		};
++	};
+ 
+-		pcie1: pcie@1,0 {
++	pcie1: pcie@1a145000 {
++		compatible = "mediatek,mt7622-pcie";
++		device_type = "pci";
++		reg = <0 0x1a145000 0 0x1000>;
++		reg-names = "port1";
++		mediatek,pcie-cfg = <&pciecfg>;
++		#address-cells = <3>;
++		#size-cells = <2>;
++		interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_LOW>;
++		interrupt-names = "pcie_irq";
++		clocks = <&pciesys CLK_PCIE_P1_MAC_EN>,
++			 /* designer has connect RC1 with p0_ahb clock */
++			 <&pciesys CLK_PCIE_P0_AHB_EN>,
++			 <&pciesys CLK_PCIE_P1_AUX_EN>,
++			 <&pciesys CLK_PCIE_P1_AXI_EN>,
++			 <&pciesys CLK_PCIE_P1_OBFF_EN>,
++			 <&pciesys CLK_PCIE_P1_PIPE_EN>;
++		clock-names = "sys_ck1", "ahb_ck1", "aux_ck1",
++			      "axi_ck1", "obff_ck1", "pipe_ck1";
++
++		power-domains = <&scpsys MT7622_POWER_DOMAIN_HIF0>;
++		bus-range = <0x00 0xff>;
++		ranges = <0x82000000 0 0x28000000  0x0 0x28000000  0 0x8000000>;
++		status = "disabled";
++
++		slot1: pcie@1,0 {
+ 			reg = <0x0800 0 0 0 0>;
+ 			#address-cells = <3>;
+ 			#size-cells = <2>;
+ 			#interrupt-cells = <1>;
+ 			ranges;
+-			status = "disabled";
+-
+ 			interrupt-map-mask = <0 0 0 7>;
+ 			interrupt-map = <0 0 0 1 &pcie_intc1 0>,
+ 					<0 0 0 2 &pcie_intc1 1>,
+--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
+@@ -254,18 +254,16 @@
+ 	};
+ };
+ 
+-&pcie {
++&pcie0 {
+ 	pinctrl-names = "default";
+-	pinctrl-0 = <&pcie0_pins>, <&pcie1_pins>;
++	pinctrl-0 = <&pcie0_pins>;
+ 	status = "okay";
++};
+ 
+-	pcie@0,0 {
+-		status = "okay";
+-	};
+-
+-	pcie@1,0 {
+-		status = "okay";
+-	};
++&pcie1 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&pcie1_pins>;
++	status = "okay";
+ };
+ 
+ &pio {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0994-ARM-dts-mediatek-Update-mt7629-PCIe-node.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0994-ARM-dts-mediatek-Update-mt7629-PCIe-node.patch
new file mode 100644
index 0000000..b20e1fc
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0994-ARM-dts-mediatek-Update-mt7629-PCIe-node.patch
@@ -0,0 +1,203 @@
+From patchwork Thu May 28 06:16:48 2020
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: Chuanjia Liu <chuanjia.liu@mediatek.com>
+X-Patchwork-Id: 11574797
+Return-Path: 
+ <SRS0=ftSA=7K=lists.infradead.org=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@kernel.org>
+Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org
+ [172.30.200.123])
+	by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 30A5E1392
+	for <patchwork-linux-mediatek@patchwork.kernel.org>;
+ Thu, 28 May 2020 06:29:05 +0000 (UTC)
+Received: from bombadil.infradead.org (bombadil.infradead.org
+ [198.137.202.133])
+	(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
+	(No client certificate requested)
+	by mail.kernel.org (Postfix) with ESMTPS id 08B6320721
+	for <patchwork-linux-mediatek@patchwork.kernel.org>;
+ Thu, 28 May 2020 06:29:05 +0000 (UTC)
+Authentication-Results: mail.kernel.org;
+	dkim=pass (2048-bit key) header.d=lists.infradead.org
+ header.i=@lists.infradead.org header.b="auhxDafY";
+	dkim=fail reason="signature verification failed" (1024-bit key)
+ header.d=mediatek.com header.i=@mediatek.com header.b="Kj09Arxb"
+DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 08B6320721
+Authentication-Results: mail.kernel.org;
+ dmarc=fail (p=none dis=none) header.from=mediatek.com
+Authentication-Results: mail.kernel.org;
+ spf=none
+ smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
+	d=lists.infradead.org; s=bombadil.20170209; h=Sender:
+	Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post:
+	List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:
+	Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description:
+	Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:
+	List-Owner; bh=+QPxF1vlOH7StIZYuXJa3V40x8QVDxCLF9AFXHblB9M=; b=auhxDafYBeaUZO
+	aYp2KVO8Aie0v4tYtRwBon7hF+x55JwD78SAxQR2RsSvrlOo9cMYYby+ToUWflVUWQ60FapAl+w+l
+	nkEjIOrLBErHwxNOcsD8T5kjyCBMqlz4OMAQYUDNJ3fSugRlGhOtxkjCGd9ebB8N2Rvu6/U8P1A9n
+	P15mEQoc+RLonR1+9mBgwTEXErjsraxkimTD4Txsp4IvMs3UdsMkP+r3OT5S/p+Uj6O9ES0h7xIon
+	aL79KaVqRLHrfZxnrVwuGiecAiTp8qLy9clHuJU32NA6ZcXH1OnWipKApgp8Ck7ys80WPKaMrat9B
+	XuskJ63w13DZAbCVvuGQ==;
+Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org)
+	by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux))
+	id 1jeC2J-00014n-M9; Thu, 28 May 2020 06:29:03 +0000
+Received: from mailgw02.mediatek.com ([216.200.240.185])
+ by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux))
+ id 1jeC2H-00013t-Li; Thu, 28 May 2020 06:29:03 +0000
+X-UUID: a4877c1586e64afeb2d6172e10605d2b-20200527
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
+ d=mediatek.com;
+ s=dk;
+ h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From;
+ bh=CIwcBFK1x0LbOjDt1BG6/knHFxDHRiqj8ov/jWEZDBY=;
+ b=Kj09ArxbnLVTc9bpaVPT3jQrIVjhL87sSYyVF9dFypS976k78Ce9gZd0f4K3zAZbYZHYoQtuyOQ9TOeufQfgD+Cr+j5VR7pTdO2E1iXHFs/eQAz5gAjvjlK01z1JiunrLnn9dvIr6c1gEkjQHny0VpuZ1duxx79jwYusg/Nw6Wc=;
+X-UUID: a4877c1586e64afeb2d6172e10605d2b-20200527
+Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by
+ mailgw02.mediatek.com
+ (envelope-from <chuanjia.liu@mediatek.com>)
+ (musrelay.mediatek.com ESMTP with TLS)
+ with ESMTP id 899663677; Wed, 27 May 2020 22:29:21 -0800
+Received: from MTKMBS07N2.mediatek.inc (172.21.101.141) by
+ MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id
+ 15.0.1497.2; Wed, 27 May 2020 23:18:50 -0700
+Received: from mtkcas07.mediatek.inc (172.21.101.84) by
+ mtkmbs07n2.mediatek.inc (172.21.101.141) with Microsoft SMTP Server (TLS) id
+ 15.0.1497.2; Thu, 28 May 2020 14:18:54 +0800
+Received: from localhost.localdomain (10.17.3.153) by mtkcas07.mediatek.inc
+ (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend
+ Transport; Thu, 28 May 2020 14:18:52 +0800
+From: <chuanjia.liu@mediatek.com>
+To: <robh+dt@kernel.org>, <ryder.lee@mediatek.com>, <matthias.bgg@gmail.com>
+Subject: [PATCH v2 4/4] ARM: dts: mediatek: Update mt7629 PCIe node
+Date: Thu, 28 May 2020 14:16:48 +0800
+Message-ID: <20200528061648.32078-5-chuanjia.liu@mediatek.com>
+X-Mailer: git-send-email 2.18.0
+In-Reply-To: <20200528061648.32078-1-chuanjia.liu@mediatek.com>
+References: <20200528061648.32078-1-chuanjia.liu@mediatek.com>
+MIME-Version: 1.0
+X-MTK: N
+X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 
+X-CRM114-CacheID: sfid-20200527_232901_719172_E5A99C62 
+X-CRM114-Status: GOOD (  11.61  )
+X-Spam-Score: -0.2 (/)
+X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary:
+ Content analysis details:   (-0.2 points)
+ pts rule name              description
+ ---- ----------------------
+ --------------------------------------------------
+ -0.0 SPF_PASS               SPF: sender matches SPF record
+ 0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
+ 0.0 MIME_BASE64_TEXT       RAW: Message text disguised using base64
+ encoding
+ -0.1 DKIM_VALID_AU          Message has a valid DKIM or DK signature from
+ author's domain
+ 0.1 DKIM_SIGNED            Message has a DKIM or DK signature,
+ not necessarily
+ valid
+ -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature
+ -0.1 DKIM_VALID_EF          Message has a valid DKIM or DK signature from
+ envelope-from domain
+ 0.0 UNPARSEABLE_RELAY      Informational: message has unparseable relay
+ lines
+X-BeenThere: linux-mediatek@lists.infradead.org
+X-Mailman-Version: 2.1.29
+Precedence: list
+List-Id: <linux-mediatek.lists.infradead.org>
+List-Unsubscribe: <http://lists.infradead.org/mailman/options/linux-mediatek>,
+ <mailto:linux-mediatek-request@lists.infradead.org?subject=unsubscribe>
+List-Archive: <http://lists.infradead.org/pipermail/linux-mediatek/>
+List-Post: <mailto:linux-mediatek@lists.infradead.org>
+List-Help: <mailto:linux-mediatek-request@lists.infradead.org?subject=help>
+List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-mediatek>,
+ <mailto:linux-mediatek-request@lists.infradead.org?subject=subscribe>
+Cc: devicetree@vger.kernel.org, lorenzo.pieralisi@arm.com,
+ srv_heupstream@mediatek.com, "chuanjia.liu" <Chuanjia.Liu@mediatek.com>,
+ linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org,
+ jianjun.wang@mediatek.com, linux-mediatek@lists.infradead.org,
+ yong.wu@mediatek.com, bhelgaas@google.com,
+ linux-arm-kernel@lists.infradead.org, amurray@thegoodpenguin.co.uk
+Sender: "Linux-mediatek" <linux-mediatek-bounces@lists.infradead.org>
+Errors-To: 
+ linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org
+
+From: "chuanjia.liu" <Chuanjia.Liu@mediatek.com>
+
+Remove unused property and add pciecfg node.
+
+Signed-off-by: chuanjia.liu <Chuanjia.Liu@mediatek.com>
+---
+ arch/arm/boot/dts/mt7629-rfb.dts |  3 ++-
+ arch/arm/boot/dts/mt7629.dtsi    | 23 +++++++++++++----------
+ 2 files changed, 15 insertions(+), 11 deletions(-)
+
+--- a/arch/arm/boot/dts/mt7629-rfb.dts
++++ b/arch/arm/boot/dts/mt7629-rfb.dts
+@@ -171,9 +171,10 @@
+ 	};
+ };
+ 
+-&pcie {
++&pcie1 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&pcie_pins>;
++	status = "okay";
+ };
+ 
+ &pciephy1 {
+--- a/arch/arm/boot/dts/mt7629.dtsi
++++ b/arch/arm/boot/dts/mt7629.dtsi
+@@ -368,16 +368,21 @@
+ 			#reset-cells = <1>;
+ 		};
+ 
+-		pcie: pcie@1a140000 {
++		pciecfg: pciecfg@1a140000 {
++			compatible = "mediatek,mt7629-pciecfg", "syscon";
++			reg = <0x1a140000 0x1000>;
++		};
++
++		pcie1: pcie@1a145000 {
+ 			compatible = "mediatek,mt7629-pcie";
+ 			device_type = "pci";
+-			reg = <0x1a140000 0x1000>,
+-			      <0x1a145000 0x1000>;
+-			reg-names = "subsys","port1";
++			reg = <0x1a145000 0x1000>;
++			reg-names = "port1";
++			mediatek,pcie-cfg = <&pciecfg>;
+ 			#address-cells = <3>;
+ 			#size-cells = <2>;
+-			interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_LOW>,
+-				     <GIC_SPI 229 IRQ_TYPE_LEVEL_LOW>;
++			interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_LOW>;
++			interrupt-names = "pcie_irq";
+ 			clocks = <&pciesys CLK_PCIE_P1_MAC_EN>,
+ 				 <&pciesys CLK_PCIE_P0_AHB_EN>,
+ 				 <&pciesys CLK_PCIE_P1_AUX_EN>,
+@@ -398,21 +403,19 @@
+ 			power-domains = <&scpsys MT7622_POWER_DOMAIN_HIF0>;
+ 			bus-range = <0x00 0xff>;
+ 			ranges = <0x82000000 0 0x20000000 0x20000000 0 0x10000000>;
++			status = "disabled";
+ 
+-			pcie1: pcie@1,0 {
+-				device_type = "pci";
++			slot1: pcie@1,0 {
+ 				reg = <0x0800 0 0 0 0>;
+ 				#address-cells = <3>;
+ 				#size-cells = <2>;
+ 				#interrupt-cells = <1>;
+ 				ranges;
+-				num-lanes = <1>;
+ 				interrupt-map-mask = <0 0 0 7>;
+ 				interrupt-map = <0 0 0 1 &pcie_intc1 0>,
+ 						<0 0 0 2 &pcie_intc1 1>,
+ 						<0 0 0 3 &pcie_intc1 2>,
+ 						<0 0 0 4 &pcie_intc1 3>;
+-
+ 				pcie_intc1: interrupt-controller {
+ 					interrupt-controller;
+ 					#address-cells = <0>;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1001-mtkhnat-ipv6-fix-pskb-expand-head-limitation.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1001-mtkhnat-ipv6-fix-pskb-expand-head-limitation.patch
new file mode 100644
index 0000000..72719c8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1001-mtkhnat-ipv6-fix-pskb-expand-head-limitation.patch
@@ -0,0 +1,22 @@
+diff --git a/net/core/skbuff.c b/net/core/skbuff.c
+index 5ba1c72f..f4239459 100644
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -69,6 +69,7 @@
+ #include <net/ip6_checksum.h>
+ #include <net/xfrm.h>
+ #include <net/mpls.h>
++#include <net/ra_nat.h>
+ 
+ #include <linux/uaccess.h>
+ #include <trace/events/skb.h>
+@@ -1666,6 +1667,9 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
+ 	       skb_shinfo(skb),
+ 	       offsetof(struct skb_shared_info, frags[skb_shinfo(skb)->nr_frags]));
+ 
++	/*headroom copy*/
++	memcpy(data, skb->head, FOE_INFO_LEN);
++
+ 	/*
+ 	 * if shinfo is shared we must drop the old head gracefully, but if it
+ 	 * is not we can just drop the old head and let the existing refcount
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1002-mtkhnat-add-support-for-virtual-interface-acceleration.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1002-mtkhnat-add-support-for-virtual-interface-acceleration.patch
new file mode 100644
index 0000000..150087a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1002-mtkhnat-add-support-for-virtual-interface-acceleration.patch
@@ -0,0 +1,127 @@
+diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
+index 3d73c0c..960ade1 100644
+--- a/include/net/netfilter/nf_flow_table.h
++++ b/include/net/netfilter/nf_flow_table.h
+@@ -92,9 +92,12 @@ struct flow_offload {
+ #define FLOW_OFFLOAD_PATH_VLAN		BIT(1)
+ #define FLOW_OFFLOAD_PATH_PPPOE		BIT(2)
+ #define FLOW_OFFLOAD_PATH_DSA		BIT(3)
++#define FLOW_OFFLOAD_PATH_DSLITE	BIT(4)
++#define FLOW_OFFLOAD_PATH_6RD		BIT(5)
+ 
+ struct flow_offload_hw_path {
+ 	struct net_device *dev;
++	struct net_device *virt_dev;
+ 	u32 flags;
+ 
+ 	u8 eth_src[ETH_ALEN];
+diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
+index be6801524..c51af70f6 100644
+--- a/net/8021q/vlan_dev.c
++++ b/net/8021q/vlan_dev.c
+@@ -761,6 +761,7 @@ static int vlan_dev_flow_offload_check(struct flow_offload_hw_path *path)
+ 	path->flags |= FLOW_OFFLOAD_PATH_VLAN;
+ 	path->vlan_proto = vlan->vlan_proto;
+ 	path->vlan_id = vlan->vlan_id;
++	path->virt_dev = dev;
+ 	path->dev = vlan->real_dev;
+ 
+ 	if (vlan->real_dev->netdev_ops->ndo_flow_offload_check)
+diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
+index 1b7e3141c..da4e34f74 100644
+--- a/net/ipv6/ip6_tunnel.c
++++ b/net/ipv6/ip6_tunnel.c
+@@ -57,6 +57,11 @@
+ #include <net/netns/generic.h>
+ #include <net/dst_metadata.h>
+ 
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++#include <linux/netfilter.h>
++#include <net/netfilter/nf_flow_table.h>
++#endif
++
+ MODULE_AUTHOR("Ville Nuorvala");
+ MODULE_DESCRIPTION("IPv6 tunneling device");
+ MODULE_LICENSE("GPL");
+@@ -1880,6 +1885,22 @@ int ip6_tnl_get_iflink(const struct net_device *dev)
+ }
+ EXPORT_SYMBOL(ip6_tnl_get_iflink);
+ 
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++static int ipip6_dev_flow_offload_check(struct flow_offload_hw_path *path)
++{
++	struct net_device *dev = path->dev;
++	struct ip6_tnl *tnl = netdev_priv(dev);
++
++	if (path->flags & FLOW_OFFLOAD_PATH_DSLITE)
++		return -EEXIST;
++
++	path->flags |= FLOW_OFFLOAD_PATH_DSLITE;
++	path->dev = tnl->dev;
++
++	return 0;
++}
++#endif /* CONFIG_NF_FLOW_TABLE */
++
+ int ip6_tnl_encap_add_ops(const struct ip6_tnl_encap_ops *ops,
+ 			  unsigned int num)
+ {
+@@ -1941,6 +1962,9 @@ static const struct net_device_ops ip6_tnl_netdev_ops = {
+ 	.ndo_change_mtu = ip6_tnl_change_mtu,
+ 	.ndo_get_stats	= ip6_get_stats,
+ 	.ndo_get_iflink = ip6_tnl_get_iflink,
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++	.ndo_flow_offload_check = ipip6_dev_flow_offload_check,
++#endif
+ };
+ 
+ #define IPXIPX_FEATURES (NETIF_F_SG |		\
+diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
+index 98954830c..42b6e8c4c 100644
+--- a/net/ipv6/sit.c
++++ b/net/ipv6/sit.c
+@@ -52,6 +52,11 @@
+ #include <net/net_namespace.h>
+ #include <net/netns/generic.h>
+ 
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++#include <linux/netfilter.h>
++#include <net/netfilter/nf_flow_table.h>
++#endif
++
+ /*
+    This version of net/ipv6/sit.c is cloned of net/ipv4/ip_gre.c
+ 
+@@ -1345,6 +1350,22 @@ ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+ 	return err;
+ }
+ 
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++static int ipip6_dev_flow_offload_check(struct flow_offload_hw_path *path)
++{
++	struct net_device *dev = path->dev;
++	struct ip_tunnel *tnl = netdev_priv(dev);
++
++	if (path->flags & FLOW_OFFLOAD_PATH_6RD)
++		return -EEXIST;
++
++	path->flags |= FLOW_OFFLOAD_PATH_6RD;
++	path->dev = tnl->dev;
++
++	return 0;
++}
++#endif /* CONFIG_NF_FLOW_TABLE */
++
+ static const struct net_device_ops ipip6_netdev_ops = {
+ 	.ndo_init	= ipip6_tunnel_init,
+ 	.ndo_uninit	= ipip6_tunnel_uninit,
+@@ -1352,6 +1373,9 @@ static const struct net_device_ops ipip6_netdev_ops = {
+ 	.ndo_do_ioctl	= ipip6_tunnel_ioctl,
+ 	.ndo_get_stats64 = ip_tunnel_get_stats64,
+ 	.ndo_get_iflink = ip_tunnel_get_iflink,
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++	.ndo_flow_offload_check = ipip6_dev_flow_offload_check,
++#endif
+ };
+ 
+ static void ipip6_dev_free(struct net_device *dev)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1003-dts-mt7622-rfb-change-to-ax-mtd-layout.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1003-dts-mt7622-rfb-change-to-ax-mtd-layout.patch
new file mode 100644
index 0000000..74a294f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1003-dts-mt7622-rfb-change-to-ax-mtd-layout.patch
@@ -0,0 +1,23 @@
+--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
+@@ -589,17 +589,17 @@
+ 
+ 			factory: partition@1c0000 {
+ 				label = "Factory";
+-				reg = <0x1c0000 0x0040000>;
++				reg = <0x1c0000 0x0100000>;
+ 			};
+ 
+ 			partition@200000 {
+ 				label = "firmware";
+-				reg = <0x200000 0x2000000>;
++				reg = <0x2c0000 0x2000000>;
+ 			};
+ 
+ 			partition@2200000 {
+ 				label = "User_data";
+-				reg = <0x2200000 0x4000000>;
++				reg = <0x22c0000 0x4000000>;
+ 			};
+ 		};
+ 	};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1004_remove_eth_transmit_timeout_hw_reset.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1004_remove_eth_transmit_timeout_hw_reset.patch
new file mode 100755
index 0000000..69a0acb
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1004_remove_eth_transmit_timeout_hw_reset.patch
@@ -0,0 +1,14 @@
+Index: linux-5.4.143/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+===================================================================
+--- linux-5.4.143.orig/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ linux-5.4.143/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -2483,9 +2483,7 @@ static void mtk_tx_timeout(struct net_de
+ 	eth->netdev[mac->id]->stats.tx_errors++;
+ 	netif_err(eth, tx_err, dev,
+ 		  "transmit timed out\n");
+-	schedule_work(&eth->pending_work);
+ }
+-
+ static irqreturn_t mtk_handle_irq_rx(int irq, void *priv)
+ {
+ 	struct mtk_napi *rx_napi = priv;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1005-mtkhnat-fix-pse-hang-for-multi-stations.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1005-mtkhnat-fix-pse-hang-for-multi-stations.patch
new file mode 100644
index 0000000..aaf1794
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1005-mtkhnat-fix-pse-hang-for-multi-stations.patch
@@ -0,0 +1,12 @@
+diff --git a/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
+index c0794e37..2968eb68 100644
+--- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
+@@ -250,6 +250,7 @@ static int hnat_start(int ppe_id)
+ 	writel(0, hnat_priv->ppe_base[ppe_id] + PPE_DFT_CPORT); /* pdma */
+ 	/* writel(0x55555555, hnat_priv->ppe_base[ppe_id] + PPE_DFT_CPORT); */ /* qdma */
+ 	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_GLO_CFG, TTL0_DRP, 0);
++	cr_set_field(hnat_priv->ppe_base[ppe_id] + PPE_GLO_CFG, MCAST_TB_EN, 1);
+ 
+ 	if (hnat_priv->data->version == MTK_HNAT_V4) {
+ 		writel(0xcb777, hnat_priv->ppe_base[ppe_id] + PPE_DFT_CPORT1);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1010-pcie-mediatek-fix-clearing-interrupt-status.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1010-pcie-mediatek-fix-clearing-interrupt-status.patch
new file mode 100644
index 0000000..d3ef78d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1010-pcie-mediatek-fix-clearing-interrupt-status.patch
@@ -0,0 +1,24 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 4 Sep 2020 18:33:27 +0200
+Subject: [PATCH] pcie-mediatek: fix clearing interrupt status
+
+Clearing the status needs to happen after running the handler, otherwise
+we will get an extra spurious interrupt after the cause has been cleared
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/pci/controller/pcie-mediatek.c
++++ b/drivers/pci/controller/pcie-mediatek.c
+@@ -616,10 +616,10 @@ static void mtk_pcie_intr_handler(struct
+ 	if (status & INTX_MASK) {
+ 		for_each_set_bit_from(bit, &status, PCI_NUM_INTX + INTX_SHIFT) {
+ 			/* Clear the INTx */
+-			writel(1 << bit, port->base + PCIE_INT_STATUS);
+ 			virq = irq_find_mapping(port->irq_domain,
+ 						bit - INTX_SHIFT);
+ 			generic_handle_irq(virq);
++			writel(1 << bit, port->base + PCIE_INT_STATUS);
+ 		}
+ 	}
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1015-pcie-add-pcie-gen3-upstream-driver.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1015-pcie-add-pcie-gen3-upstream-driver.patch
new file mode 100644
index 0000000..4b99d9d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1015-pcie-add-pcie-gen3-upstream-driver.patch
@@ -0,0 +1,36 @@
+diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
+index 70e0782..67988f8 100644
+--- a/drivers/pci/controller/Kconfig
++++ b/drivers/pci/controller/Kconfig
+@@ -241,6 +241,19 @@ config PCIE_MEDIATEK
+ 	  Say Y here if you want to enable PCIe controller support on
+ 	  MediaTek SoCs.
+ 
++config PCIE_MEDIATEK_GEN3
++	tristate "MediaTek Gen3 PCIe controller"
++	depends on ARCH_MEDIATEK || COMPILE_TEST
++	depends on PCI_MSI_IRQ_DOMAIN
++	help
++	  Adds support for PCIe Gen3 MAC controller for MediaTek SoCs.
++	  This PCIe controller is compatible with Gen3, Gen2 and Gen1 speed,
++	  and support up to 256 MSI interrupt numbers for
++	  multi-function devices.
++
++	  Say Y here if you want to enable Gen3 PCIe controller support on
++	  MediaTek SoCs.
++
+ config PCIE_MOBIVEIL
+ 	bool "Mobiveil AXI PCIe controller"
+ 	depends on ARCH_ZYNQMP || COMPILE_TEST
+diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
+index a2a22c9..54a496a 100644
+--- a/drivers/pci/controller/Makefile
++++ b/drivers/pci/controller/Makefile
+@@ -27,6 +27,7 @@ obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o
+ obj-$(CONFIG_PCIE_ROCKCHIP_EP) += pcie-rockchip-ep.o
+ obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie-rockchip-host.o
+ obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o
++obj-$(CONFIG_PCIE_MEDIATEK_GEN3) += pcie-mediatek-gen3.o
+ obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
+ obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
+ obj-$(CONFIG_VMD) += vmd.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1020-spi-nor-w25q512jv.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1020-spi-nor-w25q512jv.patch
new file mode 100644
index 0000000..a234555
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1020-spi-nor-w25q512jv.patch
@@ -0,0 +1,25 @@
+From: David Bauer <mail@david-bauer.net>
+Date: Thu, 11 Feb 2021 19:57:26 +0100
+Subject: [PATCH] mtd: spi-nor: add support for Winbond W25Q512
+
+The Winbond W25Q512 is a 512mb SPI-NOR chip. It supports 4K sectors as
+well as block protection and Dual-/Quad-read.
+
+Tested on: Ubiquiti UniFi 6 LR
+
+Signed-off-by: David Bauer <mail@david-bauer.net>
+
+Ref: https://patchwork.ozlabs.org/project/linux-mtd/patch/20210213151047.11700-1-mail@david-bauer.net/
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -2552,6 +2552,9 @@ static const struct flash_info spi_nor_i
+ 			  .fixups = &w25q256_fixups },
+ 	{ "w25q256jvm", INFO(0xef7019, 0, 64 * 1024, 512,
+ 			     SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++	{ "w25q512jv", INFO(0xef4020, 0, 64 * 1024, 1024,
++			SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_DUAL_READ |
++			SPI_NOR_HAS_TB | SPI_NOR_HAS_LOCK) },
+ 	{ "w25m512jv", INFO(0xef7119, 0, 64 * 1024, 1024,
+ 			SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_DUAL_READ) },
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1021-ubnt-ledbar-driver.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1021-ubnt-ledbar-driver.patch
new file mode 100644
index 0000000..41ab094
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1021-ubnt-ledbar-driver.patch
@@ -0,0 +1,29 @@
+--- a/drivers/leds/Kconfig
++++ b/drivers/leds/Kconfig
+@@ -824,6 +824,16 @@ config LEDS_LM36274
+ 	  Say Y to enable the LM36274 LED driver for TI LMU devices.
+ 	  This supports the LED device LM36274.
+ 
++config LEDS_UBNT_LEDBAR
++	tristate "LED support for Ubiquiti UniFi 6 LR"
++	depends on LEDS_CLASS && I2C && OF
++	help
++	  This option enables support for the Ubiquiti LEDBAR
++	  LED driver.
++
++	  To compile this driver as a module, choose M here: the module
++	  will be called leds-ubnt-ledbar.
++
+ comment "LED Triggers"
+ source "drivers/leds/trigger/Kconfig"
+ 
+--- a/drivers/leds/Makefile
++++ b/drivers/leds/Makefile
+@@ -85,6 +85,7 @@ obj-$(CONFIG_LEDS_LM3601X)		+= leds-lm36
+ obj-$(CONFIG_LEDS_TI_LMU_COMMON)	+= leds-ti-lmu-common.o
+ obj-$(CONFIG_LEDS_LM3697)		+= leds-lm3697.o
+ obj-$(CONFIG_LEDS_LM36274)		+= leds-lm36274.o
++obj-$(CONFIG_LEDS_UBNT_LEDBAR)	+= leds-ubnt-ledbar.o
+ 
+ # LED SPI Drivers
+ obj-$(CONFIG_LEDS_CR0014114)		+= leds-cr0014114.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1023-kgdb-add-interrupt-control.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1023-kgdb-add-interrupt-control.patch
new file mode 100644
index 0000000..e0ee954
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1023-kgdb-add-interrupt-control.patch
@@ -0,0 +1,42 @@
+diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c
+index 1a157ca..258fe4b 100644
+--- a/arch/arm64/kernel/kgdb.c
++++ b/arch/arm64/kernel/kgdb.c
+@@ -18,6 +18,10 @@
+ #include <asm/debug-monitors.h>
+ #include <asm/insn.h>
+ #include <asm/traps.h>
++#include <asm/ptrace.h>
++
++
++static DEFINE_PER_CPU(unsigned int, kgdb_pstate);
+ 
+ struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
+ 	{ "x0", 8, offsetof(struct pt_regs, regs[0])},
+@@ -206,6 +210,8 @@ int kgdb_arch_handle_exception(int exception_vector, int signo,
+ 		err = 0;
+ 		break;
+ 	case 's':
++		__this_cpu_write(kgdb_pstate, linux_regs->pstate);
++		linux_regs->pstate |= PSR_I_BIT;
+ 		/*
+ 		 * Update step address value with address passed
+ 		 * with step packet.
+@@ -249,9 +255,17 @@ NOKPROBE_SYMBOL(kgdb_compiled_brk_fn);
+ 
+ static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned int esr)
+ {
++	unsigned int pstate;
++
+ 	if (!kgdb_single_step)
+ 		return DBG_HOOK_ERROR;
++	kernel_disable_single_step();
+ 
++	pstate = __this_cpu_read(kgdb_pstate);
++	if (pstate & PSR_I_BIT)
++		regs->pstate |= PSR_I_BIT;
++	else
++		regs->pstate &= ~PSR_I_BIT;
+ 	kgdb_handle_exception(0, SIGTRAP, 0, regs);
+ 	return DBG_HOOK_HANDLED;
+ }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1024-pcie-add-multi-MSI-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1024-pcie-add-multi-MSI-support.patch
new file mode 100644
index 0000000..5cf486c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1024-pcie-add-multi-MSI-support.patch
@@ -0,0 +1,64 @@
+diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c
+index 2a54fa7a3..132b3204c 100644
+--- a/drivers/pci/controller/pcie-mediatek.c
++++ b/drivers/pci/controller/pcie-mediatek.c
+@@ -446,24 +446,24 @@ static int mtk_pcie_irq_domain_alloc(struct irq_domain *domain, unsigned int vir
+ 				     unsigned int nr_irqs, void *args)
+ {
+ 	struct mtk_pcie_port *port = domain->host_data;
+-	unsigned long bit;
++	int bit, i;
+ 
+-	WARN_ON(nr_irqs != 1);
+ 	mutex_lock(&port->lock);
+ 
+-	bit = find_first_zero_bit(port->msi_irq_in_use, MTK_MSI_IRQS_NUM);
+-	if (bit >= MTK_MSI_IRQS_NUM) {
++	bit = bitmap_find_free_region(port->msi_irq_in_use, MTK_MSI_IRQS_NUM,
++							order_base_2(nr_irqs));
++	if (bit < 0) {
+ 		mutex_unlock(&port->lock);
+ 		return -ENOSPC;
+ 	}
+ 
+-	__set_bit(bit, port->msi_irq_in_use);
+-
+ 	mutex_unlock(&port->lock);
+ 
+-	irq_domain_set_info(domain, virq, bit, &mtk_msi_bottom_irq_chip,
+-			    domain->host_data, handle_edge_irq,
+-			    NULL, NULL);
++	for (i = 0; i < nr_irqs; i++) {
++		irq_domain_set_info(domain, virq + i, bit + i,
++				    &mtk_msi_bottom_irq_chip, domain->host_data,
++				    handle_edge_irq, NULL, NULL);
++	}
+ 
+ 	return 0;
+ }
+@@ -501,7 +501,7 @@ static struct irq_chip mtk_msi_irq_chip = {
+ 
+ static struct msi_domain_info mtk_msi_domain_info = {
+ 	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+-		   MSI_FLAG_PCI_MSIX),
++		   MSI_FLAG_PCI_MSIX | MSI_FLAG_MULTI_PCI_MSI),
+ 	.chip	= &mtk_msi_irq_chip,
+ };
+ 
+@@ -633,14 +633,14 @@ static void mtk_pcie_intr_handler(struct irq_desc *desc)
+ 		if (status & MSI_STATUS){
+ 			unsigned long imsi_status;
+ 
++			/* Clear MSI interrupt status */
++			writel(MSI_STATUS, port->base + PCIE_INT_STATUS);
+ 			while ((imsi_status = readl(port->base + PCIE_IMSI_STATUS))) {
+ 				for_each_set_bit(bit, &imsi_status, MTK_MSI_IRQS_NUM) {
+ 					virq = irq_find_mapping(port->inner_domain, bit);
+ 					generic_handle_irq(virq);
+ 				}
+ 			}
+-			/* Clear MSI interrupt status */
+-			writel(MSI_STATUS, port->base + PCIE_INT_STATUS);
+ 		}
+ 	}
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1661-Add-trngv2-driver-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1661-Add-trngv2-driver-support.patch
new file mode 100644
index 0000000..7c09a71
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1661-Add-trngv2-driver-support.patch
@@ -0,0 +1,185 @@
+From ae5611b1b7a857edb3d9c8e900b550c76f7c236e Mon Sep 17 00:00:00 2001
+From: "Mingming.Su" <Mingming.Su@mediatek.com>
+Date: Fri, 17 Dec 2021 20:27:34 +0800
+Subject: [PATCH] Add trngv2 driver support
+
+---
+ drivers/char/hw_random/mtk-rng.c | 105 +++++++++++++++++++++++--------
+ 1 file changed, 78 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/char/hw_random/mtk-rng.c b/drivers/char/hw_random/mtk-rng.c
+index a8bd06da7..75fca4cef 100644
+--- a/drivers/char/hw_random/mtk-rng.c
++++ b/drivers/char/hw_random/mtk-rng.c
+@@ -6,6 +6,7 @@
+  */
+ #define MTK_RNG_DEV KBUILD_MODNAME
+ 
++#include <linux/arm-smccc.h>
+ #include <linux/clk.h>
+ #include <linux/delay.h>
+ #include <linux/err.h>
+@@ -15,8 +16,12 @@
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/of.h>
++#include <linux/of_device.h>
+ #include <linux/platform_device.h>
+ #include <linux/pm_runtime.h>
++#include <linux/soc/mediatek/mtk_sip_svc.h>
++
++#define MTK_SIP_KERNEL_GET_RND		MTK_SIP_SMC_CMD(0x550)
+ 
+ /* Runtime PM autosuspend timeout: */
+ #define RNG_AUTOSUSPEND_TIMEOUT		100
+@@ -32,10 +37,15 @@
+ 
+ #define to_mtk_rng(p)	container_of(p, struct mtk_rng, rng)
+ 
++struct mtk_rng_of_data{
++	unsigned int rng_version;
++};
++
+ struct mtk_rng {
+ 	void __iomem *base;
+ 	struct clk *clk;
+ 	struct hwrng rng;
++	const struct mtk_rng_of_data *soc;
+ };
+ 
+ static int mtk_rng_init(struct hwrng *rng)
+@@ -103,41 +113,74 @@ static int mtk_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+ 	return retval || !wait ? retval : -EIO;
+ }
+ 
++static int mtk_rngv2_read(struct hwrng *rng, void *buf, size_t max, bool wait)
++{
++	struct arm_smccc_res res;
++	int retval = 0;
++
++	while (max >= sizeof(u32)) {
++		arm_smccc_smc(MTK_SIP_KERNEL_GET_RND, 0, 0, 0, 0, 0, 0, 0,
++			      &res);
++		if (res.a0)
++			break;
++
++		*(u32 *)buf = res.a1;
++		retval += sizeof(u32);
++		buf += sizeof(u32);
++		max -= sizeof(u32);
++	}
++
++	return retval || !wait ? retval : -EIO;
++}
++
+ static int mtk_rng_probe(struct platform_device *pdev)
+ {
+ 	struct resource *res;
+ 	int ret;
+ 	struct mtk_rng *priv;
+ 
+-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	if (!res) {
+-		dev_err(&pdev->dev, "no iomem resource\n");
+-		return -ENXIO;
+-	}
+-
+ 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ 	if (!priv)
+ 		return -ENOMEM;
+ 
+-	priv->rng.name = pdev->name;
++	priv->soc = of_device_get_match_data(&pdev->dev);
++	if (priv->soc->rng_version == 1) {
++		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++		if (!res) {
++			dev_err(&pdev->dev, "no iomem resource\n");
++			return -ENXIO;
++		}
++
++		priv->base = devm_ioremap_resource(&pdev->dev, res);
++		if (IS_ERR(priv->base))
++			return PTR_ERR(priv->base);
++
++		priv->clk = devm_clk_get(&pdev->dev, "rng");
++		if (IS_ERR(priv->clk)) {
++			ret = PTR_ERR(priv->clk);
++			dev_err(&pdev->dev, "no clock for device: %d\n", ret);
++			return ret;
++		}
++
+ #ifndef CONFIG_PM
+-	priv->rng.init = mtk_rng_init;
+-	priv->rng.cleanup = mtk_rng_cleanup;
++		priv->rng.init = mtk_rng_init;
++		priv->rng.cleanup = mtk_rng_cleanup;
+ #endif
+-	priv->rng.read = mtk_rng_read;
++		priv->rng.read = mtk_rng_read;
++
++		pm_runtime_set_autosuspend_delay(&pdev->dev,
++						 RNG_AUTOSUSPEND_TIMEOUT);
++		pm_runtime_use_autosuspend(&pdev->dev);
++		pm_runtime_enable(&pdev->dev);
++	} else {
++		priv->rng.read = mtk_rngv2_read;
++	}
++
++	priv->rng.name = pdev->name;
+ 	priv->rng.priv = (unsigned long)&pdev->dev;
+ 	priv->rng.quality = 900;
+ 
+-	priv->clk = devm_clk_get(&pdev->dev, "rng");
+-	if (IS_ERR(priv->clk)) {
+-		ret = PTR_ERR(priv->clk);
+-		dev_err(&pdev->dev, "no clock for device: %d\n", ret);
+-		return ret;
+-	}
+-
+-	priv->base = devm_ioremap_resource(&pdev->dev, res);
+-	if (IS_ERR(priv->base))
+-		return PTR_ERR(priv->base);
++	dev_set_drvdata(&pdev->dev, priv);
+ 
+ 	ret = devm_hwrng_register(&pdev->dev, &priv->rng);
+ 	if (ret) {
+@@ -146,11 +189,6 @@ static int mtk_rng_probe(struct platform_device *pdev)
+ 		return ret;
+ 	}
+ 
+-	dev_set_drvdata(&pdev->dev, priv);
+-	pm_runtime_set_autosuspend_delay(&pdev->dev, RNG_AUTOSUSPEND_TIMEOUT);
+-	pm_runtime_use_autosuspend(&pdev->dev);
+-	pm_runtime_enable(&pdev->dev);
+-
+ 	dev_info(&pdev->dev, "registered RNG driver\n");
+ 
+ 	return 0;
+@@ -185,9 +223,22 @@ static const struct dev_pm_ops mtk_rng_pm_ops = {
+ #define MTK_RNG_PM_OPS NULL
+ #endif	/* CONFIG_PM */
+ 
++static const struct mtk_rng_of_data mt7981_rng_data = {
++	.rng_version = 2,
++};
++
++static const struct mtk_rng_of_data mt7986_rng_data = {
++	.rng_version = 1,
++};
++
++static const struct mtk_rng_of_data mt7623_rng_data = {
++	.rng_version = 1,
++};
++
+ static const struct of_device_id mtk_rng_match[] = {
+-	{ .compatible = "mediatek,mt7986-rng" },
+-	{ .compatible = "mediatek,mt7623-rng" },
++	{ .compatible = "mediatek,mt7981-rng", .data = &mt7981_rng_data },
++	{ .compatible = "mediatek,mt7986-rng", .data = &mt7986_rng_data },
++	{ .compatible = "mediatek,mt7623-rng", .data = &mt7623_rng_data },
+ 	{},
+ };
+ MODULE_DEVICE_TABLE(of, mtk_rng_match);
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/2000-misc-add-mtk-platform.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/2000-misc-add-mtk-platform.patch
new file mode 100644
index 0000000..f280e10
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/2000-misc-add-mtk-platform.patch
@@ -0,0 +1,17 @@
+diff -urN a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+--- a/drivers/misc/Kconfig	2021-06-29 15:10:00.970788831 +0800
++++ b/drivers/misc/Kconfig	2021-06-29 15:09:41.579158152 +0800
+@@ -481,4 +481,5 @@
+ source "drivers/misc/ocxl/Kconfig"
+ source "drivers/misc/cardreader/Kconfig"
+ source "drivers/misc/habanalabs/Kconfig"
++source "drivers/misc/mediatek/Kconfig"
+ endmenu
+diff -urN a/drivers/misc/Makefile b/drivers/misc/Makefile
+--- a/drivers/misc/Makefile	2021-06-29 15:10:15.150518461 +0800
++++ b/drivers/misc/Makefile	2021-06-29 15:09:46.939056121 +0800
+@@ -57,3 +57,4 @@
+ obj-$(CONFIG_PVPANIC)   	+= pvpanic.o
+ obj-$(CONFIG_HABANA_AI)		+= habanalabs/
+ obj-$(CONFIG_XILINX_SDFEC)	+= xilinx_sdfec.o
++obj-$(CONFIG_ARCH_MEDIATEK)	+= mediatek/
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/400-mtd-add-mtk-snand-driver.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/400-mtd-add-mtk-snand-driver.patch
new file mode 100644
index 0000000..f283bd2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/400-mtd-add-mtk-snand-driver.patch
@@ -0,0 +1,21 @@
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -230,6 +230,8 @@ source "drivers/mtd/hyperbus/Kconfig"
+ 
+ source "drivers/mtd/nmbm/Kconfig"
+ 
++source "drivers/mtd/mtk-snand/Kconfig"
++
+ source "drivers/mtd/composite/Kconfig"
+ 
+ endif # MTD
+--- a/drivers/mtd/Makefile
++++ b/drivers/mtd/Makefile
+@@ -35,5 +35,7 @@ obj-$(CONFIG_MTD_HYPERBUS)	+= hyperbus/
+ 
+ obj-y				+= nmbm/
+ 
++obj-$(CONFIG_MTK_SPI_NAND)	+= mtk-snand/
++
+ # Composite drivers must be loaded last
+ obj-y				+= composite/
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/401-pinctrl-add-mt7986-driver.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/401-pinctrl-add-mt7986-driver.patch
new file mode 100644
index 0000000..5022e49
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/401-pinctrl-add-mt7986-driver.patch
@@ -0,0 +1,28 @@
+diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
+index 701f9af..9109f91 100644
+--- a/drivers/pinctrl/mediatek/Kconfig
++++ b/drivers/pinctrl/mediatek/Kconfig
+@@ -100,6 +100,11 @@ config PINCTRL_MT7622
+ 	default ARM64 && ARCH_MEDIATEK
+ 	select PINCTRL_MTK_MOORE
+ 
++config PINCTRL_MT7986
++	bool "Mediatek MT7986 pin control"
++	depends on OF
++	select PINCTRL_MTK_MOORE
++
+ config PINCTRL_MT8173
+ 	bool "Mediatek MT8173 pin control"
+ 	depends on OF
+diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile
+index a74325a..d408585 100644
+--- a/drivers/pinctrl/mediatek/Makefile
++++ b/drivers/pinctrl/mediatek/Makefile
+@@ -15,6 +15,7 @@ obj-$(CONFIG_PINCTRL_MT6797)	+= pinctrl-mt6797.o
+ obj-$(CONFIG_PINCTRL_MT7622)	+= pinctrl-mt7622.o
+ obj-$(CONFIG_PINCTRL_MT7623)	+= pinctrl-mt7623.o
+ obj-$(CONFIG_PINCTRL_MT7629)	+= pinctrl-mt7629.o
++obj-$(CONFIG_PINCTRL_MT7986)	+= pinctrl-mt7986.o
+ obj-$(CONFIG_PINCTRL_MT8173)	+= pinctrl-mt8173.o
+ obj-$(CONFIG_PINCTRL_MT8183)	+= pinctrl-mt8183.o
+ obj-$(CONFIG_PINCTRL_MT8516)	+= pinctrl-mt8516.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/402-pinctrl-add-mt7981-driver.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/402-pinctrl-add-mt7981-driver.patch
new file mode 100644
index 0000000..9e67ee7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/402-pinctrl-add-mt7981-driver.patch
@@ -0,0 +1,41 @@
+From 1b529849f324edec053a34292e3f874bde8f7401 Mon Sep 17 00:00:00 2001
+From: Sam Shih <sam.shih@mediatek.com>
+Date: Fri, 25 Jun 2021 15:43:55 +0800
+Subject: [PATCH] Add mt7981 pinctrl driver support
+
+---
+ drivers/pinctrl/mediatek/Kconfig  | 7 +++++++
+ drivers/pinctrl/mediatek/Makefile | 1 +
+ 2 files changed, 8 insertions(+)
+
+diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
+index 9109f91..d40aee5 100644
+--- a/drivers/pinctrl/mediatek/Kconfig
++++ b/drivers/pinctrl/mediatek/Kconfig
+@@ -100,6 +100,11 @@ config PINCTRL_MT7622
+ 	default ARM64 && ARCH_MEDIATEK
+ 	select PINCTRL_MTK_MOORE
+ 
++config PINCTRL_MT7981
++	bool "Mediatek MT7981 pin control"
++	depends on OF
++	select PINCTRL_MTK_MOORE
++
+ config PINCTRL_MT7986
+ 	bool "Mediatek MT7986 pin control"
+ 	depends on OF
+diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile
+index d408585..e6813cf 100644
+--- a/drivers/pinctrl/mediatek/Makefile
++++ b/drivers/pinctrl/mediatek/Makefile
+@@ -15,6 +15,7 @@ obj-$(CONFIG_PINCTRL_MT6797)	+= pinctrl-mt6797.o
+ obj-$(CONFIG_PINCTRL_MT7622)	+= pinctrl-mt7622.o
+ obj-$(CONFIG_PINCTRL_MT7623)	+= pinctrl-mt7623.o
+ obj-$(CONFIG_PINCTRL_MT7629)	+= pinctrl-mt7629.o
++obj-$(CONFIG_PINCTRL_MT7981)	+= pinctrl-mt7981.o
+ obj-$(CONFIG_PINCTRL_MT7986)	+= pinctrl-mt7986.o
+ obj-$(CONFIG_PINCTRL_MT8173)	+= pinctrl-mt8173.o
+ obj-$(CONFIG_PINCTRL_MT8183)	+= pinctrl-mt8183.o
+-- 
+2.6.4
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/500-auxadc-add-auxadc-32k-clk.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/500-auxadc-add-auxadc-32k-clk.patch
new file mode 100644
index 0000000..dc0dd2f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/500-auxadc-add-auxadc-32k-clk.patch
@@ -0,0 +1,68 @@
+diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c
+index 2449d91..b8a43eb 100644
+--- a/drivers/iio/adc/mt6577_auxadc.c
++++ b/drivers/iio/adc/mt6577_auxadc.c
+@@ -42,6 +42,7 @@ struct mtk_auxadc_compatible {
+ struct mt6577_auxadc_device {
+ 	void __iomem *reg_base;
+ 	struct clk *adc_clk;
++	struct clk *adc_32k_clk;
+ 	struct mutex lock;
+ 	const struct mtk_auxadc_compatible *dev_comp;
+ };
+@@ -214,6 +215,12 @@ static int __maybe_unused mt6577_auxadc_resume(struct device *dev)
+ 		return ret;
+ 	}
+ 
++	ret = clk_prepare_enable(adc_dev->adc_32k_clk);
++	if (ret) {
++		pr_err("failed to enable auxadc clock\n");
++		return ret;
++	}
++
+ 	mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
+ 			      MT6577_AUXADC_PDN_EN, 0);
+ 	mdelay(MT6577_AUXADC_POWER_READY_MS);
+@@ -228,6 +235,8 @@ static int __maybe_unused mt6577_auxadc_suspend(struct device *dev)
+ 
+ 	mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
+ 			      0, MT6577_AUXADC_PDN_EN);
++
++	clk_disable_unprepare(adc_dev->adc_32k_clk);
+ 	clk_disable_unprepare(adc_dev->adc_clk);
+ 
+ 	return 0;
+@@ -272,6 +281,17 @@ static int mt6577_auxadc_probe(struct platform_device *pdev)
+ 		return ret;
+ 	}
+ 
++	adc_dev->adc_32k_clk = devm_clk_get(&pdev->dev, "32k");
++	if (IS_ERR(adc_dev->adc_32k_clk)) {
++		dev_err(&pdev->dev, "failed to get auxadc 32k clock\n");
++	} else {
++		ret = clk_prepare_enable(adc_dev->adc_32k_clk);
++		if (ret) {
++			dev_err(&pdev->dev, "failed to enable auxadc 32k clock\n");
++			return ret;
++		}
++	}
++
+ 	adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
+ 	if (!adc_clk_rate) {
+ 		ret = -EINVAL;
+@@ -301,6 +321,7 @@ static int mt6577_auxadc_probe(struct platform_device *pdev)
+ 	mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
+ 			      0, MT6577_AUXADC_PDN_EN);
+ err_disable_clk:
++	clk_disable_unprepare(adc_dev->adc_32k_clk);
+ 	clk_disable_unprepare(adc_dev->adc_clk);
+ 	return ret;
+ }
+@@ -315,6 +336,7 @@ static int mt6577_auxadc_remove(struct platform_device *pdev)
+ 	mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
+ 			      0, MT6577_AUXADC_PDN_EN);
+ 
++	clk_disable_unprepare(adc_dev->adc_32k_clk);
+ 	clk_disable_unprepare(adc_dev->adc_clk);
+ 
+ 	return 0;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/730-net-ethernet-mtk_eth_soc-add-mtk-dsa-tag-rx-offload.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/730-net-ethernet-mtk_eth_soc-add-mtk-dsa-tag-rx-offload.patch
new file mode 100644
index 0000000..6b10584
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/730-net-ethernet-mtk_eth_soc-add-mtk-dsa-tag-rx-offload.patch
@@ -0,0 +1,44 @@
+--- linux-5.4.77.orig/net/dsa/tag_mtk.c
++++ linux-5.4.77/net/dsa/tag_mtk.c
+@@ -73,22 +73,28 @@ static struct sk_buff *mtk_tag_rcv(struc
+ 	bool is_multicast_skb = is_multicast_ether_addr(dest) &&
+ 				!is_broadcast_ether_addr(dest);
+ 
+-	if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN)))
+-		return NULL;
++	if (dev->features & NETIF_F_HW_VLAN_CTAG_RX) {
++		hdr = ntohs(skb->vlan_proto);
++		skb->vlan_proto = 0;
++		skb->vlan_tci = 0;
++	} else {
++		if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN)))
++			return NULL;
+ 
+-	/* The MTK header is added by the switch between src addr
+-	 * and ethertype at this point, skb->data points to 2 bytes
+-	 * after src addr so header should be 2 bytes right before.
+-	 */
+-	phdr = (__be16 *)(skb->data - 2);
+-	hdr = ntohs(*phdr);
++		/* The MTK header is added by the switch between src addr
++		 * and ethertype at this point, skb->data points to 2 bytes
++		 * after src addr so header should be 2 bytes right before.
++		 */
++		phdr = (__be16 *)(skb->data - 2);
++		hdr = ntohs(*phdr);
+ 
+-	/* Remove MTK tag and recalculate checksum. */
+-	skb_pull_rcsum(skb, MTK_HDR_LEN);
++		/* Remove MTK tag and recalculate checksum. */
++		skb_pull_rcsum(skb, MTK_HDR_LEN);
+ 
+-	memmove(skb->data - ETH_HLEN,
+-		skb->data - ETH_HLEN - MTK_HDR_LEN,
+-		2 * ETH_ALEN);
++		memmove(skb->data - ETH_HLEN,
++			skb->data - ETH_HLEN - MTK_HDR_LEN,
++			2 * ETH_ALEN);
++	}
+ 
+ 	/* Get source port information */
+ 	port = (hdr & MTK_HDR_RECV_SOURCE_PORT_MASK);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/738-mt7531-gsw-internal_phy_calibration.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/738-mt7531-gsw-internal_phy_calibration.patch
new file mode 100755
index 0000000..361eca6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/738-mt7531-gsw-internal_phy_calibration.patch
@@ -0,0 +1,1282 @@
+Index: drivers/net/phy/mtk/mt753x/Makefile
+===================================================================
+--- a/drivers/net/phy/mtk/mt753x/Makefile
++++ b/drivers/net/phy/mtk/mt753x/Makefile
+@@ -7,5 +7,5 @@ obj-$(CONFIG_MT753X_GSW)	+= mt753x.o
+ mt753x-$(CONFIG_SWCONFIG)	+= mt753x_swconfig.o
+ 
+ mt753x-y			+= mt753x_mdio.o mt7530.o mt7531.o \
+-					mt753x_common.o mt753x_vlan.o mt753x_nl.o
++					mt753x_common.o mt753x_vlan.o mt753x_nl.o mt753x_phy.o
+ 
+Index: drivers/net/phy/mtk/mt753x/mt7531.c
+===================================================================
+--- a/drivers/net/phy/mtk/mt753x/mt7531.c
++++ b/drivers/net/phy/mtk/mt753x/mt7531.c
+@@ -658,6 +658,27 @@ static void mt7531_core_pll_setup(struct
+ 
+ static int mt7531_internal_phy_calibration(struct gsw_mt753x *gsw)
+ {
++	u32 i, val;
++	int ret;
++
++	dev_info(gsw->dev,">>>>>>>>>>>>>>>>>>>>>>>>>>>>> START CALIBRATION:\n");
++
++	/* gphy value from sw path */
++	val = gsw->mmd_read(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_403);
++	val |= GBE_EFUSE_SETTING;
++	gsw->mmd_write(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_403, val);
++
++	for (i = 0; i < 5; i++) {
++		dev_info(gsw->dev, "-------- gephy-calbration (port:%d) --------\n",
++			 i);
++		ret = mt753x_phy_calibration(gsw, i);
++
++		/* set Auto-negotiation with giga extension. */
++		gsw->mii_write(gsw, i, 0, 0x1340);
++		if (ret)
++			return ret;
++	}
++
+ 	return 0;
+ }
+ 
+Index: drivers/net/phy/mtk/mt753x/mt753x.h
+===================================================================
+--- a/drivers/net/phy/mtk/mt753x/mt753x.h
++++ b/drivers/net/phy/mtk/mt753x/mt753x.h
+@@ -140,6 +140,8 @@ void mt753x_irq_enable(struct gsw_mt753x
+ int mt753x_phy_calibration(struct gsw_mt753x *gsw, u8 phyaddr);
+ int extphy_init(struct gsw_mt753x *gsw, int addr);
+ 
++int mt753x_phy_calibration(struct gsw_mt753x *gsw, u8 phyaddr);
++
+ /* MDIO Indirect Access Registers */
+ #define MII_MMD_ACC_CTL_REG		0x0d
+ #define MMD_CMD_S			14
+Index: drivers/net/phy/mtk/mt753x/mt753x_phy.c
+===================================================================
+new file mode 100644
+--- /dev/null
++++ b/drivers/net/phy/mtk/mt753x/mt753x_phy.c
+@@ -0,0 +1,1069 @@
++// SPDX-License-Identifier:	GPL-2.0+
++/*
++ * Common part for MediaTek MT753x gigabit switch
++ *
++ * Copyright (C) 2018 MediaTek Inc. All Rights Reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <linux/kernel.h>
++#include <linux/delay.h>
++
++#include "mt753x.h"
++#include "mt753x_regs.h"
++#include "mt753x_phy.h"
++
++u32 tc_phy_read_dev_reg(struct gsw_mt753x *gsw, u32 port_num, u32 dev_addr, u32 reg_addr)
++{
++	u32 phy_val;
++    phy_val = gsw->mmd_read(gsw, port_num, dev_addr, reg_addr);
++    
++    //printk("switch phy cl45 r %d 0x%x 0x%x = %x\n",port_num, dev_addr, reg_addr, phy_val);
++	//switch_phy_read_cl45(port_num, dev_addr, reg_addr, &phy_val);
++	return phy_val;
++}
++
++void tc_phy_write_dev_reg(struct gsw_mt753x *gsw, u32 port_num, u32 dev_addr, u32 reg_addr, u32 write_data)
++{
++	u32 phy_val;
++    gsw->mmd_write(gsw, port_num, dev_addr, reg_addr, write_data);
++    phy_val = gsw->mmd_read(gsw, port_num, dev_addr, reg_addr);
++    //printk("switch phy cl45 w %d 0x%x 0x%x 0x%x --> read back 0x%x\n",port_num, dev_addr, reg_addr, write_data, phy_val);
++	//switch_phy_write_cl45(port_num, dev_addr, reg_addr, write_data);
++}
++
++void switch_phy_write(struct gsw_mt753x *gsw, u32 port_num, u32 reg_addr, u32 write_data){
++	gsw->mii_write(gsw, port_num, reg_addr, write_data);
++}
++
++u32 switch_phy_read(struct gsw_mt753x *gsw, u32 port_num, u32 reg_addr){
++	return gsw->mii_read(gsw, port_num, reg_addr);
++}
++
++const u8 MT753x_ZCAL_TO_R50ohm_GE_TBL_100[64] = {
++	127, 127, 127, 127, 127, 127, 127, 127,
++	127, 127, 127, 127, 127, 123, 122, 117,
++	115, 112, 103, 100, 98, 87, 85, 83,
++	81, 72, 70, 68, 66, 64, 55, 53,
++	52, 50, 49, 48, 38, 36, 35, 34,
++	33, 32, 22, 21, 20, 19, 18, 17,
++	16, 7, 6, 5, 4, 3, 2, 1,
++	0, 0, 0, 0, 0, 0, 0, 0
++};
++
++const u8 MT753x_TX_OFFSET_TBL[64] = {
++	0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
++	0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
++	0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8,
++	0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0,
++	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
++	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
++	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
++	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
++};
++
++u8 ge_cal_flag;
++
++u8 all_ge_ana_cal_wait(struct gsw_mt753x *gsw, u32 delay, u32 phyaddr) // for EN7512 
++{
++	u8 all_ana_cal_status;	
++	u32 cnt, tmp_1e_17c;
++	//tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017c, 0x0001);	// da_calin_flag pull high
++	tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x17c, 0x0001);
++	//printk("delay = %d\n", delay);
++	
++	cnt = 10000;
++	do {
++		udelay(delay);
++		cnt--;
++		all_ana_cal_status = tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x17b) & 0x1;
++
++	} while ((all_ana_cal_status == 0) && (cnt != 0));
++
++
++	if(all_ana_cal_status == 1) {
++		tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x17c, 0);
++		return all_ana_cal_status;
++	} else {
++		tmp_1e_17c = tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x17c);
++		if ((tmp_1e_17c & 0x1) != 1) {
++			pr_info("FIRST MDC/MDIO write error\n");
++			pr_info("FIRST 1e_17c = %x\n", tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x17c));
++
++		}
++		printk("re-K again\n");
++        
++		tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x17c, 0);
++		tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x17c, 0x0001);
++		cnt = 10000;
++		do {
++			udelay(delay);
++			cnt--;
++			tmp_1e_17c = tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x17c);
++			if ((tmp_1e_17c & 0x1) != 1) {
++				pr_info("SECOND MDC/MDIO write error\n");
++				pr_info("SECOND 1e_17c = %x\n", tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x17c));
++				tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x17c, 0x0001);
++				tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x17c, 0x0001);
++				tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x17c, 0x0001);
++			}
++		} while ((cnt != 0) && (tmp_1e_17c == 0));
++
++		cnt = 10000;
++		do {
++			udelay(delay);
++			cnt--;
++			all_ana_cal_status = tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x17b) & 0x1;
++	
++		} while ((all_ana_cal_status == 0) && (cnt != 0));
++	
++		tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x17c, 0);
++	}
++
++    if(all_ana_cal_status == 0){
++        pr_info("!!!!!!!!!!!! dev1Eh_reg17b ERROR\n");
++    }
++	
++	return all_ana_cal_status;
++}
++
++
++
++
++int ge_cal_rext(struct gsw_mt753x *gsw, u8 phyaddr, u32 delay)
++{
++	u8 rg_zcal_ctrl, all_ana_cal_status;
++	u16 ad_cal_comp_out_init;
++	u16 dev1e_e0_ana_cal_r5;
++	int calibration_polarity;
++	u8 cnt = 0;
++	u16 dev1e_17a_tmp, dev1e_e0_tmp;
++
++	/* *** Iext/Rext Cal start ************ */
++	all_ana_cal_status = ANACAL_INIT;
++	/* analog calibration enable, Rext calibration enable */
++	/* 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a */
++	/* 1e_dc[0]:rg_txvos_calen */
++	/* 1e_e1[4]:rg_cal_refsel(0:1.2V) */
++	//tc_phy_write_dev_reg(phyaddr, 0x1e, 0x00db, 0x1110)
++	tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00db, 0x1110);
++	//tc_phy_write_dev_reg(phyaddr, 0x1e, 0x00dc, 0x0000);
++	tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00dc, 0);
++	//tc_phy_write_dev_reg(phyaddr, 0x1e, 0x00e1, 0x0000);
++	//tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00e1, 0x10);
++	
++	rg_zcal_ctrl = 0x20;/* start with 0 dB */
++	dev1e_e0_ana_cal_r5 = tc_phy_read_dev_reg(gsw,  PHY0, 0x1e, 0xe0); // get default value
++	/* 1e_e0[5:0]:rg_zcal_ctrl */
++	tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0xe0, rg_zcal_ctrl);
++	all_ana_cal_status = all_ge_ana_cal_wait(gsw, delay, phyaddr);/* delay 20 usec */
++
++	if (all_ana_cal_status == 0) {
++		all_ana_cal_status = ANACAL_ERROR;
++		printk(" GE Rext AnaCal ERROR init!   \r\n");
++		return -1;
++	}
++	/* 1e_17a[8]:ad_cal_comp_out */
++	ad_cal_comp_out_init = (tc_phy_read_dev_reg(gsw,  PHY0, 0x1e, 0x017a) >> 8) & 0x1;
++	if (ad_cal_comp_out_init == 1)
++		calibration_polarity = -1;
++	else /* ad_cal_comp_out_init == 0 */
++		calibration_polarity = 1;
++	cnt = 0;
++	while (all_ana_cal_status < ANACAL_ERROR) {
++		cnt++;
++		rg_zcal_ctrl += calibration_polarity;
++		tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0xe0, (rg_zcal_ctrl));
++		all_ana_cal_status = all_ge_ana_cal_wait(gsw, delay, phyaddr); /* delay 20 usec */
++		dev1e_17a_tmp = tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x017a);
++		if (all_ana_cal_status == 0) {
++			all_ana_cal_status = ANACAL_ERROR;
++			printk("  GE Rext AnaCal ERROR 2!   \r\n");
++			return -1;
++		} else if (((dev1e_17a_tmp >> 8) & 0x1) != ad_cal_comp_out_init) {
++			all_ana_cal_status = ANACAL_FINISH;
++			//printk("  GE Rext AnaCal Done! (%d)(0x%x)  \r\n", cnt, rg_zcal_ctrl);
++		} else {
++			dev1e_17a_tmp = tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x017a);
++			dev1e_e0_tmp =	tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0xe0);
++			if ((rg_zcal_ctrl == 0x3F) || (rg_zcal_ctrl == 0x00)) {
++				all_ana_cal_status = ANACAL_SATURATION;  /* need to FT(IC fail?) */
++				printk(" GE Rext AnaCal Saturation!  \r\n");
++				rg_zcal_ctrl = 0x20;  /* 0 dB */
++			} 
++		}
++	}
++
++	if (all_ana_cal_status == ANACAL_ERROR) {
++		rg_zcal_ctrl = 0x20;  /* 0 dB */
++		tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00e0, (dev1e_e0_ana_cal_r5 | rg_zcal_ctrl));
++	} else if(all_ana_cal_status == ANACAL_FINISH){
++		//tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00e0, (dev1e_e0_ana_cal_r5 | rg_zcal_ctrl));
++		tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00e0, ((rg_zcal_ctrl << 8) | rg_zcal_ctrl));
++		printk("0x1e-e0 = %x\n", tc_phy_read_dev_reg(gsw,  PHY0, 0x1e, 0x00e0));
++		/* ****  1f_115[2:0] = rg_zcal_ctrl[5:3]  // Mog review */
++		tc_phy_write_dev_reg(gsw, PHY0, 0x1f, 0x0115, ((rg_zcal_ctrl & 0x3f) >> 3));
++		printk("0x1f-115 = %x\n", tc_phy_read_dev_reg(gsw,  PHY0, 0x1f, 0x115));
++		printk("  GE Rext AnaCal Done! (%d)(0x%x)  \r\n", cnt, rg_zcal_ctrl);
++		ge_cal_flag = 1;
++	} else {
++		printk("GE Rxet cal something wrong2\n");
++	}
++	tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00db, 0x0000);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00db, 0x0000);
++	tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00dc, 0x0000);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dc, 0x0000);
++
++	return 0;
++}
++
++//-----------------------------------------------------------------
++int ge_cal_r50(struct gsw_mt753x *gsw, u8 phyaddr, u32 delay)
++{
++	u8 rg_zcal_ctrl, all_ana_cal_status, calibration_pair;
++	u16 ad_cal_comp_out_init;
++	u16 dev1e_e0_ana_cal_r5;
++	int calibration_polarity;
++	u8 cnt = 0;
++	tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00db, 0x1100);	// 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a
++	tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00dc, 0x0000);	// 1e_dc[0]:rg_txvos_calen
++
++	for(calibration_pair = ANACAL_PAIR_A; calibration_pair <= ANACAL_PAIR_D; calibration_pair ++) {
++		rg_zcal_ctrl = 0x20;  						// start with 0 dB
++		dev1e_e0_ana_cal_r5 = (tc_phy_read_dev_reg(gsw,  PHY0, 0x1e, 0x00e0) & (~0x003f));
++		tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00e0, (dev1e_e0_ana_cal_r5 | rg_zcal_ctrl));	// 1e_e0[5:0]:rg_zcal_ctrl
++		if(calibration_pair == ANACAL_PAIR_A)
++		{
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00db, 0x1101);	// 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dc, 0x0000);	
++			//printk("R50 pair A 1e_db=%x 1e_db=%x\n", tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x00db), tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x00dc));
++
++		}
++		else if(calibration_pair == ANACAL_PAIR_B)
++		{
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00db, 0x1100);	// 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dc, 0x1000);	// 1e_dc[12]:rg_zcalen_b
++			//printk("R50 pair B 1e_db=%x 1e_db=%x\n", tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x00db),tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x00dc));
++
++		}
++		else if(calibration_pair == ANACAL_PAIR_C)
++		{
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00db, 0x1100);	// 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dc, 0x0100);	// 1e_dc[8]:rg_zcalen_c
++			//printk("R50 pair C 1e_db=%x 1e_db=%x\n", tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x00db), tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x00dc));
++
++		}
++		else // if(calibration_pair == ANACAL_PAIR_D)
++		{
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00db, 0x1100);	// 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dc, 0x0010);	// 1e_dc[4]:rg_zcalen_d
++			//printk("R50 pair D 1e_db=%x 1e_db=%x\n", tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x00db), tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x00dc));
++
++		}
++
++		all_ana_cal_status = all_ge_ana_cal_wait(gsw, delay, phyaddr); // delay 20 usec
++		if(all_ana_cal_status == 0)
++		{
++			all_ana_cal_status = ANACAL_ERROR;	
++			printk( "GE R50 AnaCal ERROR init!   \r\n");
++			return -1;
++		}
++	
++		ad_cal_comp_out_init = (tc_phy_read_dev_reg(gsw,  PHY0, 0x1e, 0x017a)>>8) & 0x1;		// 1e_17a[8]:ad_cal_comp_out	
++		if(ad_cal_comp_out_init == 1)
++			calibration_polarity = -1;
++		else
++			calibration_polarity = 1;
++
++		cnt = 0;
++		while(all_ana_cal_status < ANACAL_ERROR)
++		{
++			cnt ++;
++			rg_zcal_ctrl += calibration_polarity;
++			tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00e0, (dev1e_e0_ana_cal_r5 | rg_zcal_ctrl));
++			all_ana_cal_status = all_ge_ana_cal_wait(gsw, delay, phyaddr); // delay 20 usec
++
++			if(all_ana_cal_status == 0)
++			{
++				all_ana_cal_status = ANACAL_ERROR;	
++				printk( "  GE R50 AnaCal ERROR 2!   \r\n");
++				return -1;
++			}
++			else if(((tc_phy_read_dev_reg(gsw,  PHY0, 0x1e, 0x017a)>>8)&0x1) != ad_cal_comp_out_init) 
++			{
++				all_ana_cal_status = ANACAL_FINISH;	
++			}
++			else {
++				if((rg_zcal_ctrl == 0x3F)||(rg_zcal_ctrl == 0x00))	
++				{
++					all_ana_cal_status = ANACAL_SATURATION;  // need to FT
++					printk( " GE R50 AnaCal Saturation!  \r\n");
++				}
++			}
++		}
++		
++		if(all_ana_cal_status == ANACAL_ERROR) {	
++			rg_zcal_ctrl = 0x20;  // 0 dB
++			//tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00e0, (dev1e_e0_ana_cal_r5 | rg_zcal_ctrl));
++		}
++		else {
++			rg_zcal_ctrl = MT753x_ZCAL_TO_R50ohm_GE_TBL_100[rg_zcal_ctrl - 9];	// wait Mog zcal/r50 mapping table
++			printk( " GE R50 AnaCal Done! (%d) (0x%x)(0x%x) \r\n", cnt, rg_zcal_ctrl, (rg_zcal_ctrl|0x80));
++		}
++		
++		if(calibration_pair == ANACAL_PAIR_A) {
++			ad_cal_comp_out_init = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0174) & (~0x7f00);
++			//ad_cal_comp_out_init = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0174);
++			//printk( " GE-a 1e_174(0x%x)(0x%x), 1e_175(0x%x)  \r\n", tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0174), ad_cal_comp_out_init, tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0175));
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0174, (ad_cal_comp_out_init | (((rg_zcal_ctrl<<8)&0xff00) | 0x8000)));	// 1e_174[15:8]
++			//printk( " GE-a 1e_174(0x%x), 1e_175(0x%x)  \r\n", tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0174), tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0175));
++		}
++		else if(calibration_pair == ANACAL_PAIR_B) {
++			ad_cal_comp_out_init = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0174) & (~0x007f);
++			//ad_cal_comp_out_init = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0174);
++			//printk( " GE-b 1e_174(0x%x)(0x%x), 1e_175(0x%x)  \r\n", tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0174), ad_cal_comp_out_init, tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0175));
++			
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0174, (ad_cal_comp_out_init | (((rg_zcal_ctrl<<0)&0x00ff) | 0x0080)));	// 1e_174[7:0]
++			//printk( " GE-b 1e_174(0x%x), 1e_175(0x%x)  \r\n", tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0174), tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0175));
++		}
++		else if(calibration_pair == ANACAL_PAIR_C) {
++			ad_cal_comp_out_init = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0175) & (~0x7f00);
++			//ad_cal_comp_out_init = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0175);
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0175, (ad_cal_comp_out_init | (((rg_zcal_ctrl<<8)&0xff00) | 0x8000)));	// 1e_175[15:8]
++			//printk( " GE-c 1e_174(0x%x), 1e_175(0x%x)  \r\n", tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0174), tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0175));
++		} else {// if(calibration_pair == ANACAL_PAIR_D) 
++			ad_cal_comp_out_init = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0175) & (~0x007f);
++			//ad_cal_comp_out_init = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0175);
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0175, (ad_cal_comp_out_init | (((rg_zcal_ctrl<<0)&0x00ff) | 0x0080)));	// 1e_175[7:0]
++			//printk( " GE-d 1e_174(0x%x), 1e_175(0x%x)  \r\n", tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0174), tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0175));
++		}
++		//tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00e0, ((rg_zcal_ctrl<<8)|rg_zcal_ctrl));
++	}
++	
++	printk( " GE 1e_174(0x%x), 1e_175(0x%x)  \r\n", tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0174), tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x0175));
++	tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00db, 0x0000);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00db, 0x0000);
++	tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00dc, 0x0000);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dc, 0x0000);
++
++	return 0;
++}
++
++int ge_cal_tx_offset(struct gsw_mt753x *gsw,  u8 phyaddr, u32 delay)
++{
++	u8 all_ana_cal_status, calibration_pair;
++	u16 ad_cal_comp_out_init;
++	int calibration_polarity, tx_offset_temp;
++	u8 tx_offset_reg_shift, tabl_idx, i;
++	u8 cnt = 0;
++	u16 tx_offset_reg, reg_temp, cal_temp;
++	//switch_phy_write(phyaddr, R0, 0x2100);//harry tmp
++	tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00db, 0x0100);	// 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a
++	tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00dc, 0x0001);	// 1e_dc[0]:rg_txvos_calen
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0096, 0x8000);	// 1e_96[15]:bypass_tx_offset_cal, Hw bypass, Fw cal
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x003e, 0xf808);	// 1e_3e
++	for(i = 0; i <= 4; i++)
++		tc_phy_write_dev_reg(gsw, i, 0x1e, 0x00dd, 0x0000);	
++	for(calibration_pair = ANACAL_PAIR_A; calibration_pair <= ANACAL_PAIR_D; calibration_pair ++)
++	{
++		tabl_idx = 31;
++		tx_offset_temp = MT753x_TX_OFFSET_TBL[tabl_idx];
++
++		if(calibration_pair == ANACAL_PAIR_A) {
++			//tc_phy_write_dev_reg(phyaddr, 0x1e, 0x145, 0x5010);
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dd, 0x1000);				// 1e_dd[12]:rg_txg_calen_a
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017d, (0x8000|DAC_IN_0V));	// 1e_17d:dac_in0_a
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0181, (0x8000|DAC_IN_0V));	// 1e_181:dac_in1_a
++			//printk("tx offset pairA 1e_dd = %x, 1e_17d=%x, 1e_181=%x\n", tc_phy_read_dev_reg(phyaddr, 0x1e, 0x00dd), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x017d), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x0181));
++			reg_temp = (tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0172) & (~0x3f00));
++			tx_offset_reg_shift = 8;									// 1e_172[13:8]
++			tx_offset_reg = 0x0172;
++
++			//tc_phy_write_dev_reg(phyaddr, 0x1e, tx_offset_reg, (reg_temp|(tx_offset_temp<<tx_offset_reg_shift)));
++		} else if(calibration_pair == ANACAL_PAIR_B) {
++			//tc_phy_write_dev_reg(phyaddr, 0x1e, 0x145, 0x5018);
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dd, 0x0100);				// 1e_dd[8]:rg_txg_calen_b
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017e, (0x8000|DAC_IN_0V));	// 1e_17e:dac_in0_b
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0182, (0x8000|DAC_IN_0V));	// 1e_182:dac_in1_b
++			//printk("tx offset pairB 1e_dd = %x, 1e_17d=%x, 1e_181=%x\n", tc_phy_read_dev_reg(phyaddr, 0x1e, 0x00dd), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x017d), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x0181));
++			reg_temp = (tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0172) & (~0x003f));
++			tx_offset_reg_shift = 0;									// 1e_172[5:0]
++			tx_offset_reg = 0x0172;
++			//tc_phy_write_dev_reg(phyaddr, 0x1e, tx_offset_reg, (reg_temp|(tx_offset_temp<<tx_offset_reg_shift)));
++		} else if(calibration_pair == ANACAL_PAIR_C) {
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dd, 0x0010);				// 1e_dd[4]:rg_txg_calen_c
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017f, (0x8000|DAC_IN_0V));	// 1e_17f:dac_in0_c
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0183, (0x8000|DAC_IN_0V));	// 1e_183:dac_in1_c
++			reg_temp = (tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0173) & (~0x3f00));
++			//printk("tx offset pairC 1e_dd = %x, 1e_17d=%x, 1e_181=%x\n", tc_phy_read_dev_reg(phyaddr, 0x1e, 0x00dd), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x017d), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x0181));
++			tx_offset_reg_shift = 8;									// 1e_173[13:8]
++			tx_offset_reg = 0x0173;
++			//tc_phy_write_dev_reg(phyaddr, 0x1e, tx_offset_reg, (reg_temp|(tx_offset_temp<<tx_offset_reg_shift)));
++		} else {// if(calibration_pair == ANACAL_PAIR_D)
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dd, 0x0001);				// 1e_dd[0]:rg_txg_calen_d
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0180, (0x8000|DAC_IN_0V));	// 1e_180:dac_in0_d
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0184, (0x8000|DAC_IN_0V));	// 1e_184:dac_in1_d
++			//printk("tx offset pairD 1e_dd = %x, 1e_17d=%x, 1e_181=%x\n", tc_phy_read_dev_reg(phyaddr, 0x1e, 0x00dd), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x017d), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x0181));
++			reg_temp = (tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x0173) & (~0x003f));
++			tx_offset_reg_shift = 0;									// 1e_173[5:0]
++			tx_offset_reg = 0x0173;
++			//tc_phy_write_dev_reg(phyaddr, 0x1e, tx_offset_reg, (reg_temp|(tx_offset_temp<<tx_offset_reg_shift)));
++		}
++		tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_offset_reg, (reg_temp|(tx_offset_temp<<tx_offset_reg_shift)));	// 1e_172, 1e_173
++		all_ana_cal_status = all_ge_ana_cal_wait(gsw, delay, phyaddr); // delay 20 usec
++		if(all_ana_cal_status == 0) {
++			all_ana_cal_status = ANACAL_ERROR;	
++			printk( " GE Tx offset AnaCal ERROR init!   \r\n");
++			return -1;
++		}
++	
++		ad_cal_comp_out_init = (tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x017a)>>8) & 0x1;		// 1e_17a[8]:ad_cal_comp_out	
++		if(ad_cal_comp_out_init == 1)
++			calibration_polarity = 1;
++		else
++			calibration_polarity = -1;
++
++		cnt = 0;
++		//printk("TX offset cnt = %d, tabl_idx= %x, offset_val = %x\n", cnt, tabl_idx, MT753x_TX_OFFSET_TBL[tabl_idx]);
++		while(all_ana_cal_status < ANACAL_ERROR) {
++			
++			cnt ++;
++			tabl_idx += calibration_polarity;
++			//tx_offset_temp += calibration_polarity;
++			//cal_temp = tx_offset_temp;
++			cal_temp = MT753x_TX_OFFSET_TBL[tabl_idx];
++			//printk("TX offset cnt = %d, tabl_idx= %x, offset_val = %x\n", cnt, tabl_idx, MT753x_TX_OFFSET_TBL[tabl_idx]);
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_offset_reg, (reg_temp|(cal_temp<<tx_offset_reg_shift)));
++
++			all_ana_cal_status = all_ge_ana_cal_wait(gsw, delay, phyaddr); // delay 20 usec
++			if(all_ana_cal_status == 0) {
++				all_ana_cal_status = ANACAL_ERROR;	
++				printk( " GE Tx offset AnaCal ERROR init 2!   \r\n");
++				return -1;
++			} else if(((tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x017a)>>8)&0x1) != ad_cal_comp_out_init) {
++				all_ana_cal_status = ANACAL_FINISH;	
++			} else {
++				if((tabl_idx == 0)||(tabl_idx == 0x3f)) {
++					all_ana_cal_status = ANACAL_SATURATION;  // need to FT
++					printk( " GE Tx offset AnaCal Saturation!  \r\n");
++				}
++			}
++		}
++		
++		if(all_ana_cal_status == ANACAL_ERROR) {	
++			tx_offset_temp = TX_AMP_OFFSET_0MV;
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_offset_reg, (reg_temp|(tx_offset_temp<<tx_offset_reg_shift)));
++		} else {
++			printk( " GE Tx offset AnaCal Done! (pair-%d)(%d)(0x%x) 0x1e_%x=0x%x\n", calibration_pair, cnt, MT753x_TX_OFFSET_TBL[tabl_idx], tx_offset_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_offset_reg));
++		}
++	}
++
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017d, 0x0000);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017e, 0x0000);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017f, 0x0000);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0180, 0x0000);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0181, 0x0000);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0182, 0x0000);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0183, 0x0000);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0184, 0x0000);
++	
++	tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00db, 0x0000);	// disable analog calibration circuit
++	tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00dc, 0x0000);	// disable Tx offset calibration circuit
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00db, 0x0000);	// disable analog calibration circuit
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dc, 0x0000);	// disable Tx offset calibration circuit
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x003e, 0x0000);	// disable Tx VLD force mode
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dd, 0x0000);	// disable Tx offset/amplitude calibration circuit	
++
++	return 0;
++}
++
++int ge_cal_tx_amp(struct gsw_mt753x *gsw, u8 phyaddr, u32 delay)
++{
++	u8	all_ana_cal_status, calibration_pair, i;
++	u16	ad_cal_comp_out_init;
++	int	calibration_polarity;
++	u32	tx_amp_reg_shift; 
++	u16	reg_temp;
++	u32	tx_amp_temp, tx_amp_reg, cnt=0, tx_amp_reg_100;
++	u32	debug_tmp, reg_backup, reg_tmp; 
++	u32	orig_1e_11, orig_1f_300;
++
++	tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00db, 0x1100);	// 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a
++	tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00dc, 0x0001);	// 1e_dc[0]:rg_txvos_calen
++	tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00e1, 0x0010);	// 1e_e1[4]:select 1V
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x003e, 0xf808);	// 1e_3e:enable Tx VLD
++
++	orig_1e_11 = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x11);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x11, 0xff00);
++//	tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x27a, 0x33);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0xc9, 0xffff);
++	orig_1f_300 = tc_phy_read_dev_reg(gsw, phyaddr, 0x1f, 0x300);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x300, 0x4);
++	for(i = 0; i <= 4; i++)
++		tc_phy_write_dev_reg(gsw, i, 0x1e, 0x00dd, 0x0000);
++	for(calibration_pair = ANACAL_PAIR_A; calibration_pair <= ANACAL_PAIR_D; calibration_pair ++) {
++		tx_amp_temp = 0x20;	// start with 0 dB
++
++		if(calibration_pair == ANACAL_PAIR_A) {
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dd, 0x1000);				// 1e_dd[12]:tx_a amp calibration enable
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017d, (0x8000|DAC_IN_2V));	// 1e_17d:dac_in0_a	
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0181, (0x8000|DAC_IN_2V));	// 1e_181:dac_in1_a
++			reg_temp = (tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x012) & (~0xfc00));
++			tx_amp_reg_shift = 10;										// 1e_12[15:10]
++			tx_amp_reg = 0x12;
++			tx_amp_reg_100 = 0x16;
++		} else if(calibration_pair == ANACAL_PAIR_B) {
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dd, 0x0100);				// 1e_dd[8]:tx_b amp calibration enable
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017e, (0x8000|DAC_IN_2V));	// 1e_17e:dac_in0_b
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0182, (0x8000|DAC_IN_2V));	// 1e_182:dac_in1_b
++			reg_temp = (tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x017) & (~0x3f00));
++			tx_amp_reg_shift = 8;										// 1e_17[13:8]
++			tx_amp_reg = 0x17;
++			tx_amp_reg_100 = 0x18;
++		} else if(calibration_pair == ANACAL_PAIR_C) {
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dd, 0x0010);				// 1e_dd[4]:tx_c amp calibration enable
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017f, (0x8000|DAC_IN_2V));	// 1e_17f:dac_in0_c
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0183, (0x8000|DAC_IN_2V));	// 1e_183:dac_in1_c
++			reg_temp = (tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x019) & (~0x3f00));
++			tx_amp_reg_shift = 8;										// 1e_19[13:8]
++			tx_amp_reg = 0x19;
++			tx_amp_reg_100 = 0x20;
++		} else { //if(calibration_pair == ANACAL_PAIR_D)
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dd, 0x0001);				// 1e_dd[0]:tx_d amp calibration enable
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0180, (0x8000|DAC_IN_2V));	// 1e_180:dac_in0_d
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0184, (0x8000|DAC_IN_2V));	// 1e_184:dac_in1_d
++			reg_temp = (tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x021) & (~0x3f00));
++			tx_amp_reg_shift = 8;										// 1e_21[13:8]
++			tx_amp_reg = 0x21;
++			tx_amp_reg_100 = 0x22;
++		}
++		tc_phy_write_dev_reg( gsw, phyaddr, 0x1e, tx_amp_reg, (tx_amp_temp|(tx_amp_temp<<tx_amp_reg_shift)));	// 1e_12, 1e_17, 1e_19, 1e_21
++		tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100, (tx_amp_temp|(tx_amp_temp<<tx_amp_reg_shift)));
++		all_ana_cal_status = all_ge_ana_cal_wait(gsw, delay, phyaddr); 	// delay 20 usec
++		if(all_ana_cal_status == 0) {
++			all_ana_cal_status = ANACAL_ERROR;	
++			printk( " GE Tx amp AnaCal ERROR init init!   \r\n");
++			return -1;
++		}
++	
++		ad_cal_comp_out_init = (tc_phy_read_dev_reg(gsw,  PHY0, 0x1e, 0x017a)>>8) & 0x1;		// 1e_17a[8]:ad_cal_comp_out
++		if(ad_cal_comp_out_init == 1)
++			calibration_polarity = -1;
++		else
++			calibration_polarity = 1;
++
++		cnt =0;
++		while(all_ana_cal_status < ANACAL_ERROR) {
++			cnt ++;
++			tx_amp_temp += calibration_polarity;
++			//printk("tx_amp : %x, 1e %x = %x\n", tx_amp_temp, tx_amp_reg, (reg_temp|(tx_amp_temp<<tx_amp_reg_shift)));
++			tc_phy_write_dev_reg( gsw, phyaddr, 0x1e, tx_amp_reg, (tx_amp_temp|(tx_amp_temp<<tx_amp_reg_shift)));
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100, (tx_amp_temp|(tx_amp_temp<<tx_amp_reg_shift)));
++			all_ana_cal_status = all_ge_ana_cal_wait(gsw, delay, phyaddr); // delay 20 usec
++			if(all_ana_cal_status == 0) {
++				all_ana_cal_status = ANACAL_ERROR;	
++				printk( " GE Tx amp AnaCal ERROR 2!   \r\n");
++				return -1;
++			} else if(((tc_phy_read_dev_reg(gsw,  PHY0, 0x1e, 0x017a)>>8)&0x1) != ad_cal_comp_out_init) {
++				//printk("TX AMP ANACAL_FINISH\n");
++				all_ana_cal_status = ANACAL_FINISH;
++				if (phyaddr == 0) {
++					if (calibration_pair == ANACAL_PAIR_A)
++						tx_amp_temp = tx_amp_temp - 2;
++					else if(calibration_pair == ANACAL_PAIR_B)
++						tx_amp_temp = tx_amp_temp - 1;
++					else if(calibration_pair == ANACAL_PAIR_C)
++						tx_amp_temp = tx_amp_temp - 2;
++					else if(calibration_pair == ANACAL_PAIR_D)
++						tx_amp_temp = tx_amp_temp - 1;
++				} else if (phyaddr == 1) {
++					if (calibration_pair == ANACAL_PAIR_A)
++						tx_amp_temp = tx_amp_temp - 1;
++					else if(calibration_pair == ANACAL_PAIR_B)
++						tx_amp_temp = tx_amp_temp ;
++					else if(calibration_pair == ANACAL_PAIR_C)
++						tx_amp_temp = tx_amp_temp - 1;
++					else if(calibration_pair == ANACAL_PAIR_D)
++						tx_amp_temp = tx_amp_temp - 1;
++				} else if (phyaddr == 2) {
++					if (calibration_pair == ANACAL_PAIR_A)
++						tx_amp_temp = tx_amp_temp;
++					else if(calibration_pair == ANACAL_PAIR_B)
++						tx_amp_temp = tx_amp_temp - 1;
++					else if(calibration_pair == ANACAL_PAIR_C)
++						tx_amp_temp = tx_amp_temp;
++					else if(calibration_pair == ANACAL_PAIR_D)
++						tx_amp_temp = tx_amp_temp - 1;
++				} else if (phyaddr == 3) {
++					tx_amp_temp = tx_amp_temp;
++				} else if (phyaddr == 4) {
++					if (calibration_pair == ANACAL_PAIR_A)
++						tx_amp_temp = tx_amp_temp;
++					else if(calibration_pair == ANACAL_PAIR_B)
++						tx_amp_temp = tx_amp_temp - 1;
++					else if(calibration_pair == ANACAL_PAIR_C)
++						tx_amp_temp = tx_amp_temp;
++					else if(calibration_pair == ANACAL_PAIR_D)
++						tx_amp_temp = tx_amp_temp;
++				}								
++				reg_temp = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, tx_amp_reg)&(~0xff00);
++				tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((tx_amp_temp)<<tx_amp_reg_shift)));
++				tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg, (tx_amp_temp|((tx_amp_temp)<<tx_amp_reg_shift)));
++				if (phyaddr == 0) {
++					if ((tx_amp_reg == 0x12) || (tx_amp_reg == 0x17)) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg));
++						tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg, ((tx_amp_temp|((tx_amp_temp)<<tx_amp_reg_shift)) + 7));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg));
++					}
++					if (tx_amp_reg_100 == 0x16) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100));
++						tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((tx_amp_temp+1+4)<<tx_amp_reg_shift)));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100));
++					}
++					if (tx_amp_reg_100 == 0x18) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100));
++						tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((tx_amp_temp+4)<<tx_amp_reg_shift)));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100));
++					}
++				} else if (phyaddr == 1) {
++					if (tx_amp_reg == 0x12) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg));
++						tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg, ((tx_amp_temp|((tx_amp_temp)<<tx_amp_reg_shift)) + 9));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg));
++					}
++					if (tx_amp_reg == 0x17){
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg));
++						tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg, ((tx_amp_temp|((tx_amp_temp)<<tx_amp_reg_shift)) + 7));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg));
++					}
++					if (tx_amp_reg_100 == 0x16) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100));
++						tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((tx_amp_temp+4)<<tx_amp_reg_shift)));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100));
++					}
++					if (tx_amp_reg_100 == 0x18) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100));
++						tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((tx_amp_temp-1+4)<<tx_amp_reg_shift)));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100));
++					}
++				} else if (phyaddr == 2) {
++					if ((tx_amp_reg == 0x12) || (tx_amp_reg == 0x17)) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg));
++						tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg, ((tx_amp_temp|((tx_amp_temp)<<tx_amp_reg_shift)) + 6));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg));
++					}
++					if ((tx_amp_reg_100 == 0x16) || (tx_amp_reg_100 == 0x18)) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100));
++						tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((tx_amp_temp-1+4)<<tx_amp_reg_shift)));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100));
++					}
++				} else if (phyaddr == 3) {
++					if (tx_amp_reg == 0x12) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg));
++						tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg, ((tx_amp_temp|((tx_amp_temp)<<tx_amp_reg_shift)) + 4));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg));
++					}
++					if (tx_amp_reg == 0x17) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg));
++						tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg, ((tx_amp_temp|((tx_amp_temp)<<tx_amp_reg_shift)) + 7));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg));
++					}
++					if (tx_amp_reg_100 == 0x16) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100));
++						tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((tx_amp_temp-2+4)<<tx_amp_reg_shift)));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100));
++					}
++					if (tx_amp_reg_100 == 0x18) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100));
++						tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((tx_amp_temp-1+3)<<tx_amp_reg_shift)));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100));
++					}
++				} else if (phyaddr == 4) {
++					if ((tx_amp_reg == 0x12) || (tx_amp_reg == 0x17)) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg));
++						tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg, ((tx_amp_temp|((tx_amp_temp)<<tx_amp_reg_shift)) + 5));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg));
++					}
++					if (tx_amp_reg_100 == 0x16) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100));
++						tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((tx_amp_temp-2+4)<<tx_amp_reg_shift)));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100));
++					}
++					if (tx_amp_reg_100 == 0x18) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100));
++						tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((tx_amp_temp-1+4)<<tx_amp_reg_shift)));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg_100));
++					}
++				}	
++
++				if (calibration_pair == ANACAL_PAIR_A){
++					reg_backup = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x12);
++					reg_tmp = ((reg_backup & 0xfc00) >> 10);
++					reg_tmp -= 8;
++                                       reg_backup = 0x0000;
++                                       reg_backup |= ((reg_tmp << 10) | (reg_tmp << 0));
++					tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x12, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x12);
++					//printk("PORT[%d] 1e.012 = %x (OFFSET_1000M_PAIR_A)\n", phyaddr, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x16);
++					reg_tmp = ((reg_backup & 0x3f) >> 0);
++					reg_tmp -= 8;
++					reg_backup = (reg_backup & (~0x3f));
++					reg_backup |= (reg_tmp << 0);
++					tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x16, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x16);
++					//printk("PORT[%d] 1e.016 = %x (OFFSET_TESTMODE_1000M_PAIR_A)\n", phyaddr, reg_backup);
++				}
++				else if(calibration_pair == ANACAL_PAIR_B){
++					reg_backup = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x17);
++					reg_tmp = ((reg_backup & 0x3f00) >> 8);
++					reg_tmp -= 8;
++                                       reg_backup = 0x0000;
++                                       reg_backup |= ((reg_tmp << 8) | (reg_tmp << 0));
++					tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x17, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x17);
++					//printk("PORT[%d] 1e.017 = %x (OFFSET_1000M_PAIR_B)\n", phyaddr, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x18);
++					reg_tmp = ((reg_backup & 0x3f) >> 0);
++					reg_tmp -= 8;
++					reg_backup = (reg_backup & (~0x3f));
++					reg_backup |= (reg_tmp << 0);
++					tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x18, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x18);
++					//printk("PORT[%d] 1e.018 = %x (OFFSET_TESTMODE_1000M_PAIR_B)\n", phyaddr, reg_backup);
++				}
++				else if(calibration_pair == ANACAL_PAIR_C){
++					reg_backup = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x19);
++					reg_tmp = ((reg_backup & 0x3f00) >> 8);
++					reg_tmp -= 8;
++					reg_backup = (reg_backup & (~0x3f00));
++					reg_backup |= (reg_tmp << 8);
++					tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x19, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x19);
++					//printk("PORT[%d] 1e.019 = %x (OFFSET_1000M_PAIR_C)\n", phyaddr, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x20);
++					reg_tmp = ((reg_backup & 0x3f) >> 0);
++					reg_tmp -= 8;
++					reg_backup = (reg_backup & (~0x3f));
++					reg_backup |= (reg_tmp << 0);
++					tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x20, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x20);
++					//printk("PORT[%d] 1e.020 = %x (OFFSET_TESTMODE_1000M_PAIR_C)\n", phyaddr, reg_backup);
++				}
++				else if(calibration_pair == ANACAL_PAIR_D){
++					reg_backup = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x21);
++					reg_tmp = ((reg_backup & 0x3f00) >> 8);
++					reg_tmp -= 8;
++					reg_backup = (reg_backup & (~0x3f00));
++					reg_backup |= (reg_tmp << 8);
++					tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x21, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x21);
++					//printk("PORT[%d] 1e.021 = %x (OFFSET_1000M_PAIR_D)\n", phyaddr, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x22);
++					reg_tmp = ((reg_backup & 0x3f) >> 0);
++					reg_tmp -= 8;
++					reg_backup = (reg_backup & (~0x3f));
++					reg_backup |= (reg_tmp << 0);
++					tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x22, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x22);
++					//printk("PORT[%d] 1e.022 = %x (OFFSET_TESTMODE_1000M_PAIR_D)\n", phyaddr, reg_backup);
++				}
++
++				if (calibration_pair == ANACAL_PAIR_A){
++					//printk("PORT (%d) TX_AMP PAIR (A) FINAL CALIBRATION RESULT\n", phyaddr);
++					debug_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x12);
++					//printk("1e.012 = 0x%x\n", debug_tmp);
++					debug_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x16);
++					//printk("1e.016 = 0x%x\n", debug_tmp);
++				}
++	
++				else if(calibration_pair == ANACAL_PAIR_B){
++					//printk("PORT (%d) TX_AMP PAIR (A) FINAL CALIBRATION RESULT\n", phyaddr);
++					debug_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x17);
++					//printk("1e.017 = 0x%x\n", debug_tmp);
++					debug_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x18);
++					//printk("1e.018 = 0x%x\n", debug_tmp);
++				}
++				else if(calibration_pair == ANACAL_PAIR_C){
++					//printk("PORT (%d) TX_AMP PAIR (A) FINAL CALIBRATION RESULT\n", phyaddr);
++					debug_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x19);
++					//printk("1e.019 = 0x%x\n", debug_tmp);
++					debug_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x20);
++					//printk("1e.020 = 0x%x\n", debug_tmp);
++				}
++				else if(calibration_pair == ANACAL_PAIR_D){
++					//printk("PORT (%d) TX_AMP PAIR (A) FINAL CALIBRATION RESULT\n", phyaddr);
++					debug_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x21);
++					//printk("1e.021 = 0x%x\n", debug_tmp);
++					debug_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x22);
++					//printk("1e.022 = 0x%x\n", debug_tmp);
++				}
++
++
++				printk( " GE Tx amp AnaCal Done! (pair-%d)(1e_%x = 0x%x)\n", calibration_pair, tx_amp_reg, tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg));
++				
++			} else {
++				if((tx_amp_temp == 0x3f)||(tx_amp_temp == 0x00)) {
++					all_ana_cal_status = ANACAL_SATURATION;  // need to FT
++					printk( " GE Tx amp AnaCal Saturation!  \r\n");
++				}
++			}
++		}
++
++		if(all_ana_cal_status == ANACAL_ERROR) {	
++			tx_amp_temp = 0x20;
++			tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, tx_amp_reg, (reg_temp|(tx_amp_temp<<tx_amp_reg_shift)));
++		}
++	}
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017d, 0x0000);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017e, 0x0000);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x017f, 0x0000);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0180, 0x0000);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0181, 0x0000);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0182, 0x0000);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0183, 0x0000);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x0184, 0x0000);
++	
++	/* disable analog calibration circuit */
++	tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00db, 0x0000);
++	tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00dc, 0x0000);	// disable Tx offset calibration circuit
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00db, 0x0000);	// disable analog calibration circuit
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dc, 0x0000);	// disable Tx offset calibration circuit
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x003e, 0x0000);	// disable Tx VLD force mode
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x00dd, 0x0000);	// disable Tx offset/amplitude calibration circuit
++	
++	
++
++	//tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x273, 0x2000);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0xc9, 0x0fff);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x145, 0x1000);
++
++	/* Restore CR to default */
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x11, orig_1e_11);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x300, orig_1f_300);
++
++	return 0;
++}
++
++//-----------------------------------------------------------------
++
++int phy_calibration(struct gsw_mt753x *gsw, u8 phyaddr)
++{
++	//u32	reg_tmp,reg_tmp0, reg_tmp1, i;
++	u32 reg_tmp;
++	u32 CALDLY = 40;
++	u32 orig_1e_11, orig_1e_185, orig_1e_e1, orig_1f_100;
++	int ret;
++	/* set [12]AN disable, [8]full duplex, [13/6]1000Mbps */
++	//tc_phy_write_dev_reg(phyaddr, 0x0,  0x0140);
++	switch_phy_write(gsw, phyaddr, R0, 0x140);
++
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x145, 0x1010);/* fix mdi */
++	orig_1e_185 = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, RG_185);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, RG_185, 0);/* disable tx slew control */
++	orig_1f_100 = tc_phy_read_dev_reg(gsw, phyaddr, 0x1f, 0x100);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x100, 0xc000);/* BG voltage output */
++	//tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x403, 0x1099); //bypass efuse
++
++#if (1)
++	//	1f_27c[12:8] cr_da_tx_i2mpb_10m	Trimming TX bias setup(@10M)
++	//tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x27c, 0x1f1f);
++	//tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x27c, 0x3300);
++
++	//reg_tmp1 = tc_phy_read_dev_reg(gsw,  PHY0, 0x1f, 0x27c);
++	//dev1Fh_reg273h TXVLD DA register	- Adjust voltage mode TX amplitude.
++	//tc_phy_write_dev_reg(phyaddr, 0x1f, 0x273, 0);
++	//tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x273, 0x1000);
++	//reg_tmp1 = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1f, 0x273);
++	//printk("reg_tmp1273 = %x\n", reg_tmp1);
++	/*1e_11 TX  overshoot Enable (PAIR A/B/C/D) in gbe mode*/
++
++	orig_1e_11 = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x11);
++	reg_tmp = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x11);
++	reg_tmp = reg_tmp | (0xf << 12);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x11, reg_tmp);
++	orig_1e_e1 = tc_phy_read_dev_reg(gsw, PHY0, 0x1e, 0x00e1);
++	tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00e1, 0x10);
++	/* calibration start ============ */
++	printk("CALDLY = %d\n", CALDLY);
++	if(ge_cal_flag == 0){
++		ret = ge_cal_rext(gsw, 0, CALDLY);
++		if (ret == -1){
++			printk("ge_cal_rext error K port =%d\n", phyaddr);
++			return ret;
++		}
++		ge_cal_flag = 1;
++	}
++
++	/* *** R50 Cal start ***************************** */
++	/*phyaddress = 0*/
++	ret = ge_cal_r50(gsw, phyaddr, CALDLY);
++	if (ret == -1){
++		printk("R50 error K port =%d\n", phyaddr);
++		return ret;
++	}
++	/* *** R50 Cal end *** */
++	/* *** Tx offset Cal start *********************** */
++	ret = ge_cal_tx_offset(gsw, phyaddr, CALDLY);
++	if (ret == -1){
++		printk("ge_cal_tx_offset error K port =%d\n", phyaddr);
++		return ret;
++	}
++	/* *** Tx offset Cal end *** */
++
++	/* *** Tx Amp Cal start *** */
++	ret = ge_cal_tx_amp(gsw, phyaddr, CALDLY);
++	if (ret == -1){
++		printk("ge_cal_tx_amp error K port =%d\n", phyaddr);
++		return ret;
++	}
++	/* *** Tx Amp Cal end *** */
++	/*tmp maybe changed*/
++	//tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x27c, 0x1111);
++	//tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x27b, 0x47);
++	//tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x273, 0x2000);
++
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x3a8, 0x0810);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x3aa, 0x0008);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x3ab, 0x0810);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x3ad, 0x0008);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x3ae, 0x0106);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x3b0, 0x0001);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x3b1, 0x0106);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x3b3, 0x0001);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x18c, 0x0001);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x18d, 0x0001);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x18e, 0x0001);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x18f, 0x0001);
++
++	/*da_tx_bias1_b_tx_standby = 5'b10 (dev1eh_reg3aah[12:8])*/
++	reg_tmp = tc_phy_read_dev_reg(gsw, phyaddr, 0x1e, 0x3aa);
++	reg_tmp = reg_tmp & ~(0x1f00);
++	reg_tmp = reg_tmp | 0x2 << 8;
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x3aa, reg_tmp);
++
++	/*da_tx_bias1_a_tx_standby = 5'b10 (dev1eh_reg3a9h[4:0])*/
++	reg_tmp = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1e, 0x3a9);
++	reg_tmp = reg_tmp & ~(0x1f);
++	reg_tmp = reg_tmp | 0x2;
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x3a9, reg_tmp);
++
++	/* Restore CR to default */
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, RG_185, orig_1e_185);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x100, orig_1f_100);
++	tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x11, orig_1e_11);
++	tc_phy_write_dev_reg(gsw, PHY0, 0x1e, 0x00e1, orig_1e_e1);
++#endif
++	return 0;
++}
++
++void rx_dc_offset(struct gsw_mt753x *gsw, u8 phyaddr)
++{
++    pr_info("PORT %d RX_DC_OFFSET\n", phyaddr);
++    tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x96, 0x8000);
++    tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x37, 0x3);
++    tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x107, 0x4000);
++    tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x171, 0x1e5);
++    tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x39, 0x200f);
++    udelay(40);
++    tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x39, 0x000f);
++    udelay(40);
++    tc_phy_write_dev_reg(gsw, phyaddr, 0x1e, 0x171, 0x65);
++}
++
++void check_rx_dc_offset_pair_a(struct gsw_mt753x *gsw, u8 phyaddr)
++{
++    u32 reg_tmp;
++
++    tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x114f);
++    reg_tmp = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1f, 0x1a);
++    reg_tmp = reg_tmp & 0xff;
++    pr_info("before pairA output = %x\n", reg_tmp);
++    udelay(40);
++    tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x1142);
++    udelay(40);
++    reg_tmp = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1f, 0x1a);
++    reg_tmp = reg_tmp & 0xff;   
++    pr_info("after pairA output = %x\n", reg_tmp);
++    if ((reg_tmp & 0x80) != 0)
++        reg_tmp = (~reg_tmp) + 1;
++    if ((reg_tmp & 0xff) >4)
++        pr_info("pairA RX_DC_OFFSET error");
++}
++
++void check_rx_dc_offset_pair_b(struct gsw_mt753x *gsw, u8 phyaddr)
++{
++    u32 reg_tmp;
++
++    tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x1151);
++    reg_tmp = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1f, 0x1a);
++    reg_tmp = reg_tmp & 0xff;
++    pr_info("before pairB output = %x\n", reg_tmp);
++    udelay(40);
++    tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x1143);
++    udelay(40);
++    reg_tmp = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1f, 0x1a);
++    reg_tmp = reg_tmp & 0xff;   
++    pr_info("after pairB output = %x\n", reg_tmp);
++    if ((reg_tmp & 0x80) != 0)
++        reg_tmp = (~reg_tmp) + 1;
++    if ((reg_tmp & 0xff) >4)
++        pr_info("pairB RX_DC_OFFSET error");
++}
++
++void check_rx_dc_offset_pair_c(struct gsw_mt753x *gsw, u8 phyaddr)
++{
++    u32 reg_tmp;
++
++    tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x1153);
++    reg_tmp = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1f, 0x1a);
++    reg_tmp = reg_tmp & 0xff;
++    pr_info("before pairC output = %x\n", reg_tmp);
++    udelay(40);
++    tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x1144);
++    udelay(40);
++    reg_tmp = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1f, 0x1a);
++    reg_tmp = reg_tmp & 0xff;   
++    pr_info("after pairC output = %x\n", reg_tmp);
++    if ((reg_tmp & 0x80) != 0)
++        reg_tmp = (~reg_tmp) + 1;
++    if ((reg_tmp & 0xff) >4)
++        pr_info("pairC RX_DC_OFFSET error");
++}
++
++void check_rx_dc_offset_pair_d(struct gsw_mt753x *gsw, u8 phyaddr)
++{
++    u32 reg_tmp;
++
++    tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x1155);
++    reg_tmp = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1f, 0x1a);
++    reg_tmp = reg_tmp & 0xff;
++    pr_info("before pairD output = %x\n", reg_tmp);
++    udelay(40);
++    tc_phy_write_dev_reg(gsw, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x1145);
++    udelay(40);
++    reg_tmp = tc_phy_read_dev_reg(gsw,  phyaddr, 0x1f, 0x1a);
++    reg_tmp = reg_tmp & 0xff;   
++    pr_info("after pairD output = %x\n", reg_tmp);
++    if ((reg_tmp & 0x80) != 0)
++        reg_tmp = (~reg_tmp) + 1;
++    if ((reg_tmp & 0xff) >4)
++        pr_info("pairD RX_DC_OFFSET error");
++}
++
++
++int mt753x_phy_calibration(struct gsw_mt753x *gsw, u8 phyaddr){
++
++	int ret;
++
++	ret = phy_calibration(gsw, phyaddr);
++
++	rx_dc_offset(gsw, phyaddr);
++	check_rx_dc_offset_pair_a(gsw, phyaddr);
++	check_rx_dc_offset_pair_b(gsw, phyaddr);
++	check_rx_dc_offset_pair_c(gsw, phyaddr);
++	check_rx_dc_offset_pair_d(gsw, phyaddr);
++
++	return ret;
++}
+Index: drivers/net/phy/mtk/mt753x/mt753x_phy.h
+===================================================================
+new file mode 100644
+--- /dev/null
++++ b/drivers/net/phy/mtk/mt753x/mt753x_phy.h
+@@ -0,0 +1,145 @@
++/* SPDX-License-Identifier:	GPL-2.0+ */
++/*
++ * Register definitions for MediaTek MT753x Gigabit switches
++ *
++ * Copyright (C) 2018 MediaTek Inc. All Rights Reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#ifndef _MT753X_PHY_H_
++#define _MT753X_PHY_H_
++
++#include <linux/bitops.h>
++
++/*phy calibration use*/
++#define DEV_1E				0x1E
++/*global device 0x1f, always set P0*/
++#define DEV_1F				0x1F
++
++
++/************IEXT/REXT CAL***************/
++/* bits range: for example BITS(16,23) = 0xFF0000*/
++#define BITS(m, n)   (~(BIT(m) - 1) & ((BIT(n) - 1) | BIT(n)))
++#define ANACAL_INIT			0x01
++#define ANACAL_ERROR			0xFD
++#define ANACAL_SATURATION		0xFE
++#define	ANACAL_FINISH			0xFF
++#define ANACAL_PAIR_A			0
++#define ANACAL_PAIR_B			1
++#define ANACAL_PAIR_C			2
++#define ANACAL_PAIR_D			3
++#define DAC_IN_0V			0x00
++#define DAC_IN_2V			0xf0
++#define TX_AMP_OFFSET_0MV		0x20
++#define TX_AMP_OFFSET_VALID_BITS	6
++
++#define R0				0
++#define PHY0				0
++#define PHY1				1
++#define PHY2				2
++#define PHY3				3
++#define PHY4				4
++#define ANA_TEST_MODE			BITS(8, 15)
++#define TST_TCLK_SEL			BITs(6, 7)
++#define ANA_TEST_VGA_RG			0x100
++
++#define FORCE_MDI_CROSS_OVER		BITS(3, 4)
++#define T10_TEST_CTL_RG			0x145
++#define RG_185				0x185
++#define RG_TX_SLEW			BIT(0)
++#define ANA_CAL_0			0xdb
++#define RG_CAL_CKINV			BIT(12)
++#define RG_ANA_CALEN			BIT(8)
++#define RG_REXT_CALEN			BIT(4)
++#define RG_ZCALEN_A			BIT(0)
++#define ANA_CAL_1			0xdc
++#define RG_ZCALEN_B			BIT(12)
++#define RG_ZCALEN_C			BIT(8)
++#define RG_ZCALEN_D			BIT(4)
++#define RG_TXVOS_CALEN			BIT(0)
++#define ANA_CAL_6			0xe1
++#define RG_CAL_REFSEL			BIT(4)
++#define RG_CAL_COMP_PWD			BIT(0)
++#define ANA_CAL_5			0xe0
++#define RG_REXT_TRIM			BITs(8, 13)
++#define RG_ZCAL_CTRL			BITs(0, 5)
++#define RG_17A				0x17a
++#define AD_CAL_COMP_OUT			BIT(8)
++#define RG_17B				0x17b
++#define AD_CAL_CLK			bit(0)
++#define RG_17C				0x17c
++#define DA_CALIN_FLAG			bit(0)
++/************R50 CAL****************************/
++#define RG_174				0x174
++#define RG_R50OHM_RSEL_TX_A_EN		BIT[15]
++#define CR_R50OHM_RSEL_TX_A		BITS[8:14]
++#define RG_R50OHM_RSEL_TX_B_EN		BIT[7]
++#define CR_R50OHM_RSEL_TX_B		BITS[6:0]
++#define RG_175				0x175
++#define RG_R50OHM_RSEL_TX_C_EN		BITS[15]
++#define CR_R50OHM_RSEL_TX_C		BITS[8:14]
++#define RG_R50OHM_RSEL_TX_D_EN		BIT[7]
++#define CR_R50OHM_RSEL_TX_D		BITS[0:6]
++/**********TX offset Calibration***************************/
++#define RG_95				0x96
++#define BYPASS_TX_OFFSET_CAL		BIT(15)
++#define RG_3E				0x3e
++#define BYPASS_PD_TXVLD_A		BIT(15)
++#define BYPASS_PD_TXVLD_B		BIT(14)
++#define BYPASS_PD_TXVLD_C		BIT(13)
++#define BYPASS_PD_TXVLD_D		BIT(12)
++#define BYPASS_PD_TX_10M		BIT(11)
++#define POWER_DOWN_TXVLD_A		BIT(7)
++#define POWER_DOWN_TXVLD_B		BIT(6)
++#define POWER_DOWN_TXVLD_C		BIT(5)
++#define POWER_DOWN_TXVLD_D		BIT(4)
++#define POWER_DOWN_TX_10M		BIT(3)
++#define RG_DD				0xdd
++#define RG_TXG_CALEN_A			BIT(12)
++#define RG_TXG_CALEN_B			BIT(8)
++#define RG_TXG_CALEN_C			BIT(4)
++#define RG_TXG_CALEN_D			BIT(0)
++#define RG_17D				0x17D
++#define FORCE_DASN_DAC_IN0_A		BIT(15)
++#define DASN_DAC_IN0_A			BITS(0, 9)
++#define RG_17E				0x17E
++#define FORCE_DASN_DAC_IN0_B		BIT(15)
++#define DASN_DAC_IN0_B			BITS(0, 9)
++#define RG_17F				0x17F
++
++#define FORCE_DASN_DAC_IN0_C		BIT(15)
++#define DASN_DAC_IN0_C			BITS(0, 9)
++#define RG_180				0x180
++#define FORCE_DASN_DAC_IN0_D		BIT(15)
++#define DASN_DAC_IN0_D			BITS(0, 9)
++
++#define RG_181				0x181
++#define FORCE_DASN_DAC_IN1_A		BIT(15)
++#define DASN_DAC_IN1_A			BITS(0, 9)
++#define RG_182				0x182
++#define FORCE_DASN_DAC_IN1_B		BIT(15)
++#define DASN_DAC_IN1_B			BITS(0, 9)
++#define RG_183				0x183
++#define FORCE_DASN_DAC_IN1_C		BIT15]
++#define DASN_DAC_IN1_C			BITS(0, 9)
++#define RG_184				0x184
++#define FORCE_DASN_DAC_IN1_D		BIT(15)
++#define DASN_DAC_IN1_D			BITS(0, 9)
++#define RG_172				0x172
++#define CR_TX_AMP_OFFSET_A		BITS(8, 13)
++#define CR_TX_AMP_OFFSET_B		BITS(0, 5)
++#define RG_173				0x173
++#define CR_TX_AMP_OFFSET_C		BITS(8, 13)
++#define CR_TX_AMP_OFFSET_D		BITS(0, 5)
++/**********TX Amp Calibration ***************************/
++#define RG_12				0x12
++#define DA_TX_I2MPB_A_GBE		BITS(10, 15)
++#define RG_17				0x17
++#define DA_TX_I2MPB_B_GBE		BITS(8, 13)
++#define RG_19				0x19
++#define DA_TX_I2MPB_C_GBE		BITS(8, 13)
++#define RG_21				0x21
++#define DA_TX_I2MPB_D_GBE		BITS(8, 13)
++
++#endif /* _MT753X_REGS_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/739-mt7531-gsw-port5_external_phy_init.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/739-mt7531-gsw-port5_external_phy_init.patch
new file mode 100755
index 0000000..0d88c60
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/739-mt7531-gsw-port5_external_phy_init.patch
@@ -0,0 +1,156 @@
+From 9206472ba03032aea120604e8637b52408ca4b3a Mon Sep 17 00:00:00 2001
+From: Landen Chao <landen.chao@mediatek.com>
+Date: Fri, 29 May 2020 15:12:35 +0800
+Subject: [PATCH 2/2] 740_patch
+
+Change-Id: I7e0164751702f573d5185c4290ff78688f42f603
+---
+ drivers/net/phy/mtk/mt753x/Makefile        |  3 +-
+ drivers/net/phy/mtk/mt753x/mt7531.c        |  3 +
+ drivers/net/phy/mtk/mt753x/mt753x.h        |  1 +
+ drivers/net/phy/mtk/mt753x/mt753x_extphy.c | 69 ++++++++++++++++++++++
+ drivers/net/phy/mtk/mt753x/mt753x_extphy.h | 18 ++++++
+ 5 files changed, 93 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/net/phy/mtk/mt753x/mt753x_extphy.c
+ create mode 100644 drivers/net/phy/mtk/mt753x/mt753x_extphy.h
+
+diff --git a/drivers/net/phy/mtk/mt753x/Makefile b/drivers/net/phy/mtk/mt753x/Makefile
+index 384b0ff7..694ffa83 100644
+--- a/drivers/net/phy/mtk/mt753x/Makefile
++++ b/drivers/net/phy/mtk/mt753x/Makefile
+@@ -7,5 +7,6 @@ obj-$(CONFIG_MT753X_GSW)	+= mt753x.o
+ mt753x-$(CONFIG_SWCONFIG)	+= mt753x_swconfig.o
+ 
+ mt753x-y			+= mt753x_mdio.o mt7530.o mt7531.o \
+-					mt753x_common.o mt753x_vlan.o mt753x_nl.o mt753x_phy.o
++					mt753x_common.o mt753x_vlan.o mt753x_nl.o mt753x_phy.o \
++					mt753x_extphy.o
+ 
+diff --git a/drivers/net/phy/mtk/mt753x/mt7531.c b/drivers/net/phy/mtk/mt753x/mt7531.c
+index 04729835..4a2943b1 100644
+--- a/drivers/net/phy/mtk/mt753x/mt7531.c
++++ b/drivers/net/phy/mtk/mt753x/mt7531.c
+@@ -265,6 +265,9 @@ static int mt7531_set_port_sgmii_force_mode(struct gsw_mt753x *gsw, u32 port,
+ 		return -EINVAL;
+ 	}
+ 
++	if (port == 5)
++		extphy_init(gsw, port);
++
+ 	port_base = port - 5;
+ 
+ 	switch (port_cfg->speed) {
+diff --git a/drivers/net/phy/mtk/mt753x/mt753x.h b/drivers/net/phy/mtk/mt753x/mt753x.h
+index 5053a7d7..a3f343cd 100644
+--- a/drivers/net/phy/mtk/mt753x/mt753x.h
++++ b/drivers/net/phy/mtk/mt753x/mt753x.h
+@@ -154,6 +154,7 @@ void mt753x_irq_worker(struct work_struct *work);
+ void mt753x_irq_enable(struct gsw_mt753x *gsw);
+ 
+ int mt753x_phy_calibration(struct gsw_mt753x *gsw, u8 phyaddr);
++int extphy_init(struct gsw_mt753x *gsw, int addr);
+ 
+ /* MDIO Indirect Access Registers */
+ #define MII_MMD_ACC_CTL_REG		0x0d
+diff --git a/drivers/net/phy/mtk/mt753x/mt753x_extphy.c b/drivers/net/phy/mtk/mt753x/mt753x_extphy.c
+new file mode 100644
+index 00000000..f58e8a62
+--- /dev/null
++++ b/drivers/net/phy/mtk/mt753x/mt753x_extphy.c
+@@ -0,0 +1,69 @@
++/*
++ * Driver for MediaTek MT7531 gigabit switch
++ *
++ * Copyright (C) 2018 MediaTek Inc. All Rights Reserved.
++ *
++ * Author: Landen Chao <landen.chao@mediatek.com>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <linux/kernel.h>
++#include <linux/mii.h>
++
++#include "mt753x.h"
++#include "mt753x_regs.h"
++#include "mt753x_extphy.h"
++
++int gpy211_init(struct gsw_mt753x *gsw, int addr)
++{
++	/* Enable rate adaption */
++	gsw->mmd_write(gsw, addr, 0x1e, 0x8, 0x24e2);
++
++	return 0;
++}
++
++static struct mt753x_extphy_id extphy_tbl[] = {
++        {0x67c9de00, 0x0fffffff0, gpy211_init},
++};
++
++static u32 get_cl22_phy_id(struct gsw_mt753x *gsw, int addr)
++{
++	int phy_reg;
++	u32 phy_id = 0;
++
++	phy_reg = gsw->mii_read(gsw, addr, MII_PHYSID1);
++	if (phy_reg < 0)
++		return 0;
++	phy_id = (phy_reg & 0xffff) << 16;
++
++	/* Grab the bits from PHYIR2, and put them in the lower half */
++	phy_reg = gsw->mii_read(gsw, addr, MII_PHYSID2);
++	if (phy_reg < 0)
++		return 0;
++
++	phy_id |= (phy_reg & 0xffff);
++
++	return phy_id;
++}
++
++static inline bool phy_id_is_match(u32 id, struct mt753x_extphy_id *phy)
++{
++	return ((id & phy->phy_id_mask) == (phy->phy_id & phy->phy_id_mask));
++}
++
++int extphy_init(struct gsw_mt753x *gsw, int addr)
++{
++	int i;
++	u32 phy_id;
++	struct mt753x_extphy_id *extphy;
++
++	phy_id = get_cl22_phy_id(gsw, addr);
++	for (i = 0; i < ARRAY_SIZE(extphy_tbl); i++) {
++		extphy = &extphy_tbl[i];
++		if(phy_id_is_match(phy_id, extphy))
++			extphy->init(gsw, addr);
++	}
++
++	return 0;
++}
+diff --git a/drivers/net/phy/mtk/mt753x/mt753x_extphy.h b/drivers/net/phy/mtk/mt753x/mt753x_extphy.h
+new file mode 100644
+index 00000000..2b72c8a9
+--- /dev/null
++++ b/drivers/net/phy/mtk/mt753x/mt753x_extphy.h
+@@ -0,0 +1,18 @@
++/*
++ * Driver for MediaTek MT753x gigabit switch
++ *
++ * Copyright (C) 2018 MediaTek Inc. All Rights Reserved.
++ *
++ * Author: Landen Chao <landen.chao@mediatek.com>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef _MT753X_EXTPHY_H_
++#define _MT753X_EXTPHY_H_
++struct mt753x_extphy_id {
++        u32 phy_id;
++        u32 phy_id_mask;
++	int (*init)(struct gsw_mt753x *gsw, int addr);
++};
++#endif
+-- 
+2.17.1
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/740-add-gpy211-phy-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/740-add-gpy211-phy-support.patch
new file mode 100644
index 0000000..2496084
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/740-add-gpy211-phy-support.patch
@@ -0,0 +1,28 @@
+Index: linux-5.4.119/drivers/net/phy/Kconfig
+===================================================================
+--- linux-5.4.119.orig/drivers/net/phy/Kconfig
++++ linux-5.4.119/drivers/net/phy/Kconfig
+@@ -468,6 +468,11 @@ config FIXED_PHY
+ 
+ 	  Currently tested with mpc866ads and mpc8349e-mitx.
+ 
++config GPY211_PHY
++	tristate "GPY211 PHY"
++	---help---
++	  Supports the Intel GPY211 PHY with rate adaption.
++
+ config ICPLUS_PHY
+ 	tristate "ICPlus PHYs"
+ 	---help---
+Index: linux-5.4.119/drivers/net/phy/Makefile
+===================================================================
+--- linux-5.4.119.orig/drivers/net/phy/Makefile
++++ linux-5.4.119/drivers/net/phy/Makefile
+@@ -86,6 +86,7 @@ obj-$(CONFIG_DP83TC811_PHY)	+= dp83tc811
+ obj-$(CONFIG_DP83848_PHY)	+= dp83848.o
+ obj-$(CONFIG_DP83867_PHY)	+= dp83867.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed_phy.o
++obj-$(CONFIG_GPY211_PHY)	+= gpy211.o
+ obj-$(CONFIG_ICPLUS_PHY)	+= icplus.o
+ obj-$(CONFIG_INTEL_XWAY_PHY)	+= intel-xway.o
+ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/741-add-default-setting-to-dsa-unused-port.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/741-add-default-setting-to-dsa-unused-port.patch
new file mode 100644
index 0000000..7769ebd
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/741-add-default-setting-to-dsa-unused-port.patch
@@ -0,0 +1,124 @@
+Index: linux-5.4.124/drivers/net/dsa/mt7530.c
+===================================================================
+--- linux-5.4.124.orig/drivers/net/dsa/mt7530.c
++++ linux-5.4.124/drivers/net/dsa/mt7530.c
+@@ -1021,6 +1021,9 @@ mt7530_stp_state_set(struct dsa_switch *
+ 	struct mt7530_priv *priv = ds->priv;
+ 	u32 stp_state;
+ 
++	if (dsa_is_unused_port(ds, port))
++		return;
++
+ 	switch (state) {
+ 	case BR_STATE_DISABLED:
+ 		stp_state = MT7530_STP_DISABLED;
+@@ -1676,10 +1679,58 @@ mt7530_setup(struct dsa_switch *ds)
+ }
+ 
+ static int
++setup_unused_ports(struct dsa_switch *ds, u32 pm)
++{
++	struct mt7530_priv *priv = ds->priv;
++	u32 egtag_mask = 0;
++	u32 egtag_val = 0;
++	int i;
++
++	if (!pm)
++		return 0;
++
++	for (i = 0; i < MT7530_NUM_PORTS; i++) {
++		if (!dsa_is_unused_port(ds, i))
++			continue;
++
++		/* Setup MAC port with maximum capability. */
++		if ((i == 5) || (i == 6))
++			if (priv->info->cpu_port_config)
++				priv->info->cpu_port_config(ds, i);
++
++		mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK | PCR_PORT_VLAN_MASK,
++			   PCR_MATRIX(pm) | MT7530_PORT_SECURITY_MODE);
++		egtag_mask |= ETAG_CTRL_P_MASK(i);
++		egtag_val |=  ETAG_CTRL_P(i, MT7530_VLAN_EGRESS_UNTAG);
++	}
++
++	/* Add unused ports to VLAN2 group for using IVL fdb. */
++	mt7530_write(priv, MT7530_VAWD1,
++		     IVL_MAC | VTAG_EN | PORT_MEM(pm) | VLAN_VALID);
++	mt7530_rmw(priv, MT7530_VAWD2, egtag_mask, egtag_val);
++	mt7530_vlan_cmd(priv, MT7530_VTCR_WR_VID, MT753X_RESERVED_VLAN);
++
++	for (i = 0; i < MT7530_NUM_PORTS; i++) {
++		if (!dsa_is_unused_port(ds, i))
++			continue;
++
++		mt7530_rmw(priv, MT7530_PPBV1_P(i), G0_PORT_VID_MASK,
++			   G0_PORT_VID(MT753X_RESERVED_VLAN));
++		mt7530_rmw(priv, MT7530_SSP_P(i), FID_PST_MASK, MT7530_STP_FORWARDING);
++
++		dev_dbg(ds->dev, "Add unused port%d to reserved VLAN%d group\n",
++			i, MT753X_RESERVED_VLAN);
++	}
++
++	return 0;
++}
++
++static int
+ mt7531_setup(struct dsa_switch *ds)
+ {
+ 	struct mt7530_priv *priv = ds->priv;
+ 	struct mt7530_dummy_poll p;
++	u32 unused_pm = 0;
+ 	u32 val, id;
+ 	int ret, i;
+ 
+@@ -1767,7 +1818,9 @@ mt7531_setup(struct dsa_switch *ds)
+ 
+ 		mt7530_set(priv, MT7531_DBG_CNT(i), MT7531_DIS_CLR);
+ 
+-		if (dsa_is_cpu_port(ds, i))
++		if (dsa_is_unused_port(ds, i))
++			unused_pm |= BIT(i);
++		else if (dsa_is_cpu_port(ds, i))
+ 			mt753x_cpu_port_enable(ds, i);
+ 		else
+ 			mt7530_port_disable(ds, i);
+@@ -1777,6 +1830,9 @@ mt7531_setup(struct dsa_switch *ds)
+ 			   PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
+ 	}
+ 
++	/* Group and enable unused ports as a standalone dumb switch. */
++	setup_unused_ports(ds, unused_pm);
++
+ 	ds->configure_vlan_while_not_filtering = true;
+ 
+ 	/* Flush the FDB table */
+@@ -2101,7 +2157,7 @@ mt7531_mac_config(struct dsa_switch *ds,
+ 	case PHY_INTERFACE_MODE_RGMII_RXID:
+ 	case PHY_INTERFACE_MODE_RGMII_TXID:
+ 		dp = dsa_to_port(ds, port);
+-		phydev = dp->slave->phydev;
++		phydev = (dp->slave) ? dp->slave->phydev : NULL;
+ 		return mt7531_rgmii_setup(priv, port, interface, phydev);
+ 	case PHY_INTERFACE_MODE_SGMII:
+ 		return mt7531_sgmii_setup_mode_an(priv, port, interface);
+@@ -2641,7 +2697,7 @@ mt7530_probe(struct mdio_device *mdiodev
+ 	if (!priv)
+ 		return -ENOMEM;
+ 
+-	priv->ds = dsa_switch_alloc(&mdiodev->dev, DSA_MAX_PORTS);
++	priv->ds = dsa_switch_alloc(&mdiodev->dev, MT7530_NUM_PORTS);
+ 	if (!priv->ds)
+ 		return -ENOMEM;
+ 
+Index: linux-5.4.124/drivers/net/dsa/mt7530.h
+===================================================================
+--- linux-5.4.124.orig/drivers/net/dsa/mt7530.h
++++ linux-5.4.124/drivers/net/dsa/mt7530.h
+@@ -10,6 +10,7 @@
+ #define MT7530_CPU_PORT			6
+ #define MT7530_NUM_FDB_RECORDS		2048
+ #define MT7530_ALL_MEMBERS		0xff
++#define MT753X_RESERVED_VLAN		2
+ 
+ enum mt753x_id {
+ 	ID_MT7530 = 0,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/742-net-dsa-add-MT7531-Gigabit-Ethernet-PHY-setting.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/742-net-dsa-add-MT7531-Gigabit-Ethernet-PHY-setting.patch
new file mode 100644
index 0000000..948bb69
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/742-net-dsa-add-MT7531-Gigabit-Ethernet-PHY-setting.patch
@@ -0,0 +1,1687 @@
+Index: linux-5.4.124/drivers/net/dsa/mt7530.c
+===================================================================
+--- linux-5.4.124.orig/drivers/net/dsa/mt7530.c
++++ linux-5.4.124/drivers/net/dsa/mt7530.c
+@@ -1830,6 +1830,8 @@ mt7531_setup(struct dsa_switch *ds)
+ 			   PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
+ 	}
+ 
++	mt7531_phy_setup(ds);
++
+ 	/* Group and enable unused ports as a standalone dumb switch. */
+ 	setup_unused_ports(ds, unused_pm);
+ 
+Index: linux-5.4.124/drivers/net/dsa/mt7530.h
+===================================================================
+--- linux-5.4.124.orig/drivers/net/dsa/mt7530.h
++++ linux-5.4.124/drivers/net/dsa/mt7530.h
+@@ -782,4 +782,5 @@ static inline void INIT_MT7530_DUMMY_POL
+ 	p->reg = reg;
+ }
+ 
++int mt7531_phy_setup(struct dsa_switch *ds);
+ #endif /* __MT7530_H */
+Index: linux-5.4.124/drivers/net/dsa/mt7531_phy.c
+===================================================================
+--- /dev/null
++++ linux-5.4.124/drivers/net/dsa/mt7531_phy.c
+@@ -0,0 +1,1378 @@
++// SPDX-License-Identifier:	GPL-2.0+
++/*
++ * Common part for MediaTek MT753x gigabit switch
++ *
++ * Copyright (C) 2018 MediaTek Inc. All Rights Reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <linux/delay.h>
++#include <linux/hrtimer.h>
++#include <linux/kernel.h>
++#include <net/dsa.h>
++#include "mt7530.h"
++#include "mt7531_phy.h"
++
++#define MT7531_NUM_PHYS 5
++
++static u32 tc_phy_read_dev_reg(struct dsa_switch *ds, u32 port_num, u32 dev_addr, u32 reg_addr)
++{
++	struct mt7530_priv *priv = ds->priv;
++	u32 phy_val;
++	u32 addr;
++
++	addr = MII_ADDR_C45 | (dev_addr << 16) | (reg_addr & 0xffff);
++	phy_val = priv->info->phy_read(ds, port_num, addr);
++
++	//printk("switch phy cl45 r %d 0x%x 0x%x = %x\n",port_num, dev_addr, reg_addr, phy_val);
++	return phy_val;
++}
++
++static void tc_phy_write_dev_reg(struct dsa_switch *ds, u32 port_num, u32 dev_addr, u32 reg_addr, u32 write_data)
++{
++	struct mt7530_priv *priv = ds->priv;
++	u32 addr;
++
++	addr = MII_ADDR_C45 | (dev_addr << 16) | (reg_addr & 0xffff);
++
++	priv->info->phy_write(ds, port_num, addr, write_data);
++
++	//u32 phy_val = priv->info->phy_read(ds, port_num, addr);
++	//printk("switch phy cl45 w %d 0x%x 0x%x 0x%x --> read back 0x%x\n",port_num, dev_addr, reg_addr, write_data, phy_val);
++}
++
++static void switch_phy_write(struct dsa_switch *ds, u32 port_num, u32 reg_addr, u32 write_data){
++	struct mt7530_priv *priv = ds->priv;
++
++	priv->info->phy_write(ds, port_num, reg_addr, write_data);
++}
++
++static u32 switch_phy_read(struct dsa_switch *ds, u32 port_num, u32 reg_addr){
++	struct mt7530_priv *priv = ds->priv;
++
++	return priv->info->phy_read(ds, port_num, reg_addr);
++}
++
++static void mt753x_tr_write(struct dsa_switch *ds, int addr, u8 ch, u8 node, u8 daddr,
++		     u32 data)
++{
++	ktime_t timeout;
++	u32 timeout_us;
++	u32 val;
++
++	switch_phy_write(ds, addr, PHY_CL22_PAGE_CTRL, PHY_TR_PAGE);
++
++	val = switch_phy_read(ds, addr, PHY_TR_CTRL);
++
++	timeout_us = 100000;
++	timeout = ktime_add_us(ktime_get(), timeout_us);
++	while (1) {
++		val = switch_phy_read(ds, addr, PHY_TR_CTRL);
++
++		if (!!(val & PHY_TR_PKT_XMT_STA))
++			break;
++
++		if (ktime_compare(ktime_get(), timeout) > 0)
++			goto out;
++	}
++
++	switch_phy_write(ds, addr, PHY_TR_LOW_DATA, PHY_TR_LOW_VAL(data));
++	switch_phy_write(ds, addr, PHY_TR_HIGH_DATA, PHY_TR_HIGH_VAL(data));
++	val = PHY_TR_PKT_XMT_STA | (PHY_TR_WRITE << PHY_TR_WR_S) |
++	      (ch << PHY_TR_CH_ADDR_S) | (node << PHY_TR_NODE_ADDR_S) |
++	      (daddr << PHY_TR_DATA_ADDR_S);
++	switch_phy_write(ds, addr, PHY_TR_CTRL, val);
++
++	timeout_us = 100000;
++	timeout = ktime_add_us(ktime_get(), timeout_us);
++	while (1) {
++		val = switch_phy_read(ds, addr, PHY_TR_CTRL);
++
++		if (!!(val & PHY_TR_PKT_XMT_STA))
++			break;
++
++		if (ktime_compare(ktime_get(), timeout) > 0)
++			goto out;
++	}
++out:
++	switch_phy_write(ds, addr, PHY_CL22_PAGE_CTRL, 0);
++}
++
++static int mt753x_tr_read(struct dsa_switch *ds, int addr, u8 ch, u8 node, u8 daddr)
++{
++	ktime_t timeout;
++	u32 timeout_us;
++	u32 val;
++	u8 val_h;
++
++	switch_phy_write(ds, addr, PHY_CL22_PAGE_CTRL, PHY_TR_PAGE);
++
++	val = switch_phy_read(ds, addr, PHY_TR_CTRL);
++
++	timeout_us = 100000;
++	timeout = ktime_add_us(ktime_get(), timeout_us);
++	while (1) {
++		val = switch_phy_read(ds, addr, PHY_TR_CTRL);
++
++		if (!!(val & PHY_TR_PKT_XMT_STA))
++			break;
++
++		if (ktime_compare(ktime_get(), timeout) > 0) {
++			switch_phy_write(ds, addr, PHY_CL22_PAGE_CTRL, 0);
++			return -ETIMEDOUT;
++		}
++	}
++
++	val = PHY_TR_PKT_XMT_STA | (PHY_TR_READ << PHY_TR_WR_S) |
++	      (ch << PHY_TR_CH_ADDR_S) | (node << PHY_TR_NODE_ADDR_S) |
++	      (daddr << PHY_TR_DATA_ADDR_S);
++	switch_phy_write(ds, addr, PHY_TR_CTRL, val);
++
++	timeout_us = 100000;
++	timeout = ktime_add_us(ktime_get(), timeout_us);
++	while (1) {
++		val = switch_phy_read(ds, addr, PHY_TR_CTRL);
++
++		if (!!(val & PHY_TR_PKT_XMT_STA))
++			break;
++
++		if (ktime_compare(ktime_get(), timeout) > 0) {
++			switch_phy_write(ds, addr, PHY_CL22_PAGE_CTRL, 0);
++			return -ETIMEDOUT;
++		}
++	}
++
++	val = switch_phy_read(ds, addr, PHY_TR_LOW_DATA);
++	val_h = switch_phy_read(ds, addr, PHY_TR_HIGH_DATA);
++	val |= (val_h << 16);
++
++	switch_phy_write(ds, addr, PHY_CL22_PAGE_CTRL, 0);
++
++	return val;
++}
++
++static const u8 MT753x_ZCAL_TO_R50ohm_GE_TBL_100[64] = {
++	127, 127, 127, 127, 127, 127, 127, 127,
++	127, 127, 127, 127, 127, 123, 122, 117,
++	115, 112, 103, 100, 98, 87, 85, 83,
++	81, 72, 70, 68, 66, 64, 55, 53,
++	52, 50, 49, 48, 38, 36, 35, 34,
++	33, 32, 22, 21, 20, 19, 18, 17,
++	16, 7, 6, 5, 4, 3, 2, 1,
++	0, 0, 0, 0, 0, 0, 0, 0
++};
++
++static const u8 MT753x_TX_OFFSET_TBL[64] = {
++	0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
++	0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
++	0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8,
++	0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0,
++	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
++	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
++	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
++	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
++};
++
++static u8 ge_cal_flag;
++
++static u8 all_ge_ana_cal_wait(struct dsa_switch *ds, u32 delay, u32 phyaddr)
++{
++	u8 all_ana_cal_status;
++	u32 cnt, tmp_1e_17c;
++	//tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x017c, 0x0001);	// da_calin_flag pull high
++	tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x17c, 0x0001);
++	//printk("delay = %d\n", delay);
++
++	cnt = 10000;
++	do {
++		udelay(delay);
++		cnt--;
++		all_ana_cal_status = tc_phy_read_dev_reg(ds, PHY0, 0x1e, 0x17b) & 0x1;
++
++	} while ((all_ana_cal_status == 0) && (cnt != 0));
++
++
++	if(all_ana_cal_status == 1) {
++		tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x17c, 0);
++		return all_ana_cal_status;
++	} else {
++		tmp_1e_17c = tc_phy_read_dev_reg(ds, PHY0, 0x1e, 0x17c);
++		if ((tmp_1e_17c & 0x1) != 1) {
++			pr_info("FIRST MDC/MDIO write error\n");
++			pr_info("FIRST 1e_17c = %x\n", tc_phy_read_dev_reg(ds, PHY0, 0x1e, 0x17c));
++
++		}
++		printk("re-K again\n");
++
++		tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x17c, 0);
++		tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x17c, 0x0001);
++		cnt = 10000;
++		do {
++			udelay(delay);
++			cnt--;
++			tmp_1e_17c = tc_phy_read_dev_reg(ds, PHY0, 0x1e, 0x17c);
++			if ((tmp_1e_17c & 0x1) != 1) {
++				pr_info("SECOND MDC/MDIO write error\n");
++				pr_info("SECOND 1e_17c = %x\n", tc_phy_read_dev_reg(ds, PHY0, 0x1e, 0x17c));
++				tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x17c, 0x0001);
++				tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x17c, 0x0001);
++				tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x17c, 0x0001);
++			}
++		} while ((cnt != 0) && (tmp_1e_17c == 0));
++
++		cnt = 10000;
++		do {
++			udelay(delay);
++			cnt--;
++			all_ana_cal_status = tc_phy_read_dev_reg(ds, PHY0, 0x1e, 0x17b) & 0x1;
++
++		} while ((all_ana_cal_status == 0) && (cnt != 0));
++
++		tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x17c, 0);
++	}
++
++	if(all_ana_cal_status == 0){
++		pr_info("!!!!!!!!!!!! dev1Eh_reg17b ERROR\n");
++	}
++
++	return all_ana_cal_status;
++}
++
++
++
++
++static int ge_cal_rext(struct dsa_switch *ds, u8 phyaddr, u32 delay)
++{
++	u8 rg_zcal_ctrl, all_ana_cal_status;
++	u16 ad_cal_comp_out_init;
++	u16 dev1e_e0_ana_cal_r5;
++	int calibration_polarity;
++	u8 cnt = 0;
++	u16 dev1e_17a_tmp, dev1e_e0_tmp;
++
++	/* *** Iext/Rext Cal start ************ */
++	all_ana_cal_status = ANACAL_INIT;
++	/* analog calibration enable, Rext calibration enable */
++	/* 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a */
++	/* 1e_dc[0]:rg_txvos_calen */
++	/* 1e_e1[4]:rg_cal_refsel(0:1.2V) */
++	//tc_phy_write_dev_reg(phyaddr, 0x1e, 0x00db, 0x1110)
++	tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00db, 0x1110);
++	//tc_phy_write_dev_reg(phyaddr, 0x1e, 0x00dc, 0x0000);
++	tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00dc, 0);
++	//tc_phy_write_dev_reg(phyaddr, 0x1e, 0x00e1, 0x0000);
++	//tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00e1, 0x10);
++
++	rg_zcal_ctrl = 0x20;/* start with 0 dB */
++	dev1e_e0_ana_cal_r5 = tc_phy_read_dev_reg(ds,  PHY0, 0x1e, 0xe0); // get default value
++	/* 1e_e0[5:0]:rg_zcal_ctrl */
++	tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0xe0, rg_zcal_ctrl);
++	all_ana_cal_status = all_ge_ana_cal_wait(ds, delay, phyaddr);/* delay 20 usec */
++
++	if (all_ana_cal_status == 0) {
++		all_ana_cal_status = ANACAL_ERROR;
++		printk(" GE Rext AnaCal ERROR init!   \r\n");
++		return -1;
++	}
++	/* 1e_17a[8]:ad_cal_comp_out */
++	ad_cal_comp_out_init = (tc_phy_read_dev_reg(ds,  PHY0, 0x1e, 0x017a) >> 8) & 0x1;
++	if (ad_cal_comp_out_init == 1)
++		calibration_polarity = -1;
++	else /* ad_cal_comp_out_init == 0 */
++		calibration_polarity = 1;
++	cnt = 0;
++	while (all_ana_cal_status < ANACAL_ERROR) {
++		cnt++;
++		rg_zcal_ctrl += calibration_polarity;
++		tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0xe0, (rg_zcal_ctrl));
++		all_ana_cal_status = all_ge_ana_cal_wait(ds, delay, phyaddr); /* delay 20 usec */
++		dev1e_17a_tmp = tc_phy_read_dev_reg(ds, PHY0, 0x1e, 0x017a);
++		if (all_ana_cal_status == 0) {
++			all_ana_cal_status = ANACAL_ERROR;
++			printk("  GE Rext AnaCal ERROR 2!   \r\n");
++			return -1;
++		} else if (((dev1e_17a_tmp >> 8) & 0x1) != ad_cal_comp_out_init) {
++			all_ana_cal_status = ANACAL_FINISH;
++			//printk("  GE Rext AnaCal Done! (%d)(0x%x)  \r\n", cnt, rg_zcal_ctrl);
++		} else {
++			dev1e_17a_tmp = tc_phy_read_dev_reg(ds, PHY0, 0x1e, 0x017a);
++			dev1e_e0_tmp =	tc_phy_read_dev_reg(ds, PHY0, 0x1e, 0xe0);
++			if ((rg_zcal_ctrl == 0x3F) || (rg_zcal_ctrl == 0x00)) {
++				all_ana_cal_status = ANACAL_SATURATION;  /* need to FT(IC fail?) */
++				printk(" GE Rext AnaCal Saturation!  \r\n");
++				rg_zcal_ctrl = 0x20;  /* 0 dB */
++			}
++		}
++	}
++
++	if (all_ana_cal_status == ANACAL_ERROR) {
++		rg_zcal_ctrl = 0x20;  /* 0 dB */
++		tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00e0, (dev1e_e0_ana_cal_r5 | rg_zcal_ctrl));
++	} else if(all_ana_cal_status == ANACAL_FINISH){
++		//tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00e0, (dev1e_e0_ana_cal_r5 | rg_zcal_ctrl));
++		tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00e0, ((rg_zcal_ctrl << 8) | rg_zcal_ctrl));
++		printk("0x1e-e0 = %x\n", tc_phy_read_dev_reg(ds,  PHY0, 0x1e, 0x00e0));
++		/* ****  1f_115[2:0] = rg_zcal_ctrl[5:3]  // Mog review */
++		tc_phy_write_dev_reg(ds, PHY0, 0x1f, 0x0115, ((rg_zcal_ctrl & 0x3f) >> 3));
++		printk("0x1f-115 = %x\n", tc_phy_read_dev_reg(ds,  PHY0, 0x1f, 0x115));
++		printk("  GE Rext AnaCal Done! (%d)(0x%x)  \r\n", cnt, rg_zcal_ctrl);
++		ge_cal_flag = 1;
++	} else {
++		printk("GE Rxet cal something wrong2\n");
++	}
++	tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00db, 0x0000);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00db, 0x0000);
++	tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00dc, 0x0000);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00dc, 0x0000);
++
++	return 0;
++}
++
++//-----------------------------------------------------------------
++static int ge_cal_r50(struct dsa_switch *ds, u8 phyaddr, u32 delay)
++{
++	u8 rg_zcal_ctrl, all_ana_cal_status, calibration_pair;
++	u16 ad_cal_comp_out_init;
++	u16 dev1e_e0_ana_cal_r5;
++	int calibration_polarity;
++	u8 cnt = 0;
++	tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00db, 0x1100);	// 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a
++	tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00dc, 0x0000);	// 1e_dc[0]:rg_txvos_calen
++
++	for(calibration_pair = ANACAL_PAIR_A; calibration_pair <= ANACAL_PAIR_D; calibration_pair ++) {
++		rg_zcal_ctrl = 0x20;  						// start with 0 dB
++		dev1e_e0_ana_cal_r5 = (tc_phy_read_dev_reg(ds,  PHY0, 0x1e, 0x00e0) & (~0x003f));
++		tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00e0, (dev1e_e0_ana_cal_r5 | rg_zcal_ctrl));	// 1e_e0[5:0]:rg_zcal_ctrl
++		if(calibration_pair == ANACAL_PAIR_A)
++		{
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00db, 0x1101);	// 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00dc, 0x0000);
++			//printk("R50 pair A 1e_db=%x 1e_db=%x\n", tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x00db), tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x00dc));
++
++		}
++		else if(calibration_pair == ANACAL_PAIR_B)
++		{
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00db, 0x1100);	// 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00dc, 0x1000);	// 1e_dc[12]:rg_zcalen_b
++			//printk("R50 pair B 1e_db=%x 1e_db=%x\n", tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x00db),tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x00dc));
++
++		}
++		else if(calibration_pair == ANACAL_PAIR_C)
++		{
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00db, 0x1100);	// 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00dc, 0x0100);	// 1e_dc[8]:rg_zcalen_c
++			//printk("R50 pair C 1e_db=%x 1e_db=%x\n", tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x00db), tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x00dc));
++
++		}
++		else // if(calibration_pair == ANACAL_PAIR_D)
++		{
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00db, 0x1100);	// 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00dc, 0x0010);	// 1e_dc[4]:rg_zcalen_d
++			//printk("R50 pair D 1e_db=%x 1e_db=%x\n", tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x00db), tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x00dc));
++
++		}
++
++		all_ana_cal_status = all_ge_ana_cal_wait(ds, delay, phyaddr); // delay 20 usec
++		if(all_ana_cal_status == 0)
++		{
++			all_ana_cal_status = ANACAL_ERROR;
++			printk( "GE R50 AnaCal ERROR init!   \r\n");
++			return -1;
++		}
++
++		ad_cal_comp_out_init = (tc_phy_read_dev_reg(ds,  PHY0, 0x1e, 0x017a)>>8) & 0x1;		// 1e_17a[8]:ad_cal_comp_out
++		if(ad_cal_comp_out_init == 1)
++			calibration_polarity = -1;
++		else
++			calibration_polarity = 1;
++
++		cnt = 0;
++		while(all_ana_cal_status < ANACAL_ERROR)
++		{
++			cnt ++;
++			rg_zcal_ctrl += calibration_polarity;
++			tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00e0, (dev1e_e0_ana_cal_r5 | rg_zcal_ctrl));
++			all_ana_cal_status = all_ge_ana_cal_wait(ds, delay, phyaddr); // delay 20 usec
++
++			if(all_ana_cal_status == 0)
++			{
++				all_ana_cal_status = ANACAL_ERROR;
++				printk( "  GE R50 AnaCal ERROR 2!   \r\n");
++				return -1;
++			}
++			else if(((tc_phy_read_dev_reg(ds,  PHY0, 0x1e, 0x017a)>>8)&0x1) != ad_cal_comp_out_init)
++			{
++				all_ana_cal_status = ANACAL_FINISH;
++			}
++			else {
++				if((rg_zcal_ctrl == 0x3F)||(rg_zcal_ctrl == 0x00))
++				{
++					all_ana_cal_status = ANACAL_SATURATION;  // need to FT
++					printk( " GE R50 AnaCal Saturation!  \r\n");
++				}
++			}
++		}
++
++		if(all_ana_cal_status == ANACAL_ERROR) {
++			rg_zcal_ctrl = 0x20;  // 0 dB
++			//tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00e0, (dev1e_e0_ana_cal_r5 | rg_zcal_ctrl));
++		}
++		else {
++			rg_zcal_ctrl = MT753x_ZCAL_TO_R50ohm_GE_TBL_100[rg_zcal_ctrl - 9];	// wait Mog zcal/r50 mapping table
++			printk( " GE R50 AnaCal Done! (%d) (0x%x)(0x%x) \r\n", cnt, rg_zcal_ctrl, (rg_zcal_ctrl|0x80));
++		}
++
++		if(calibration_pair == ANACAL_PAIR_A) {
++			ad_cal_comp_out_init = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0174) & (~0x7f00);
++			//ad_cal_comp_out_init = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0174);
++			//printk( " GE-a 1e_174(0x%x)(0x%x), 1e_175(0x%x)  \r\n", tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0174), ad_cal_comp_out_init, tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0175));
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0174, (ad_cal_comp_out_init | (((rg_zcal_ctrl<<8)&0xff00) | 0x8000)));	// 1e_174[15:8]
++			//printk( " GE-a 1e_174(0x%x), 1e_175(0x%x)  \r\n", tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0174), tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0175));
++		}
++		else if(calibration_pair == ANACAL_PAIR_B) {
++			ad_cal_comp_out_init = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0174) & (~0x007f);
++			//ad_cal_comp_out_init = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0174);
++			//printk( " GE-b 1e_174(0x%x)(0x%x), 1e_175(0x%x)  \r\n", tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0174), ad_cal_comp_out_init, tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0175));
++
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0174, (ad_cal_comp_out_init | (((rg_zcal_ctrl<<0)&0x00ff) | 0x0080)));	// 1e_174[7:0]
++			//printk( " GE-b 1e_174(0x%x), 1e_175(0x%x)  \r\n", tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0174), tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0175));
++		}
++		else if(calibration_pair == ANACAL_PAIR_C) {
++			ad_cal_comp_out_init = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0175) & (~0x7f00);
++			//ad_cal_comp_out_init = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0175);
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0175, (ad_cal_comp_out_init | (((rg_zcal_ctrl<<8)&0xff00) | 0x8000)));	// 1e_175[15:8]
++			//printk( " GE-c 1e_174(0x%x), 1e_175(0x%x)  \r\n", tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0174), tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0175));
++		} else {// if(calibration_pair == ANACAL_PAIR_D)
++			ad_cal_comp_out_init = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0175) & (~0x007f);
++			//ad_cal_comp_out_init = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0175);
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0175, (ad_cal_comp_out_init | (((rg_zcal_ctrl<<0)&0x00ff) | 0x0080)));	// 1e_175[7:0]
++			//printk( " GE-d 1e_174(0x%x), 1e_175(0x%x)  \r\n", tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0174), tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0175));
++		}
++		//tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00e0, ((rg_zcal_ctrl<<8)|rg_zcal_ctrl));
++	}
++
++	printk( " GE 1e_174(0x%x), 1e_175(0x%x)  \r\n", tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0174), tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x0175));
++	tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00db, 0x0000);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00db, 0x0000);
++	tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00dc, 0x0000);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00dc, 0x0000);
++
++	return 0;
++}
++
++static int ge_cal_tx_offset(struct dsa_switch *ds,  u8 phyaddr, u32 delay)
++{
++	u8 all_ana_cal_status, calibration_pair;
++	u16 ad_cal_comp_out_init;
++	int calibration_polarity, tx_offset_temp;
++	u8 tx_offset_reg_shift, tabl_idx, i;
++	u8 cnt = 0;
++	u16 tx_offset_reg, reg_temp, cal_temp;
++	//switch_phy_write(phyaddr, R0, 0x2100);//harry tmp
++	tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00db, 0x0100);	// 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a
++	tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00dc, 0x0001);	// 1e_dc[0]:rg_txvos_calen
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0096, 0x8000);	// 1e_96[15]:bypass_tx_offset_cal, Hw bypass, Fw cal
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x003e, 0xf808);	// 1e_3e
++	for(i = 0; i <= 4; i++)
++		tc_phy_write_dev_reg(ds, i, 0x1e, 0x00dd, 0x0000);
++	for(calibration_pair = ANACAL_PAIR_A; calibration_pair <= ANACAL_PAIR_D; calibration_pair ++)
++	{
++		tabl_idx = 31;
++		tx_offset_temp = MT753x_TX_OFFSET_TBL[tabl_idx];
++
++		if(calibration_pair == ANACAL_PAIR_A) {
++			//tc_phy_write_dev_reg(phyaddr, 0x1e, 0x145, 0x5010);
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00dd, 0x1000);				// 1e_dd[12]:rg_txg_calen_a
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x017d, (0x8000|DAC_IN_0V));	// 1e_17d:dac_in0_a
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0181, (0x8000|DAC_IN_0V));	// 1e_181:dac_in1_a
++			//printk("tx offset pairA 1e_dd = %x, 1e_17d=%x, 1e_181=%x\n", tc_phy_read_dev_reg(phyaddr, 0x1e, 0x00dd), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x017d), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x0181));
++			reg_temp = (tc_phy_read_dev_reg(ds, phyaddr, 0x1e, 0x0172) & (~0x3f00));
++			tx_offset_reg_shift = 8;									// 1e_172[13:8]
++			tx_offset_reg = 0x0172;
++
++			//tc_phy_write_dev_reg(phyaddr, 0x1e, tx_offset_reg, (reg_temp|(tx_offset_temp<<tx_offset_reg_shift)));
++		} else if(calibration_pair == ANACAL_PAIR_B) {
++			//tc_phy_write_dev_reg(phyaddr, 0x1e, 0x145, 0x5018);
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00dd, 0x0100);				// 1e_dd[8]:rg_txg_calen_b
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x017e, (0x8000|DAC_IN_0V));	// 1e_17e:dac_in0_b
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0182, (0x8000|DAC_IN_0V));	// 1e_182:dac_in1_b
++			//printk("tx offset pairB 1e_dd = %x, 1e_17d=%x, 1e_181=%x\n", tc_phy_read_dev_reg(phyaddr, 0x1e, 0x00dd), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x017d), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x0181));
++			reg_temp = (tc_phy_read_dev_reg(ds, phyaddr, 0x1e, 0x0172) & (~0x003f));
++			tx_offset_reg_shift = 0;									// 1e_172[5:0]
++			tx_offset_reg = 0x0172;
++			//tc_phy_write_dev_reg(phyaddr, 0x1e, tx_offset_reg, (reg_temp|(tx_offset_temp<<tx_offset_reg_shift)));
++		} else if(calibration_pair == ANACAL_PAIR_C) {
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00dd, 0x0010);				// 1e_dd[4]:rg_txg_calen_c
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x017f, (0x8000|DAC_IN_0V));	// 1e_17f:dac_in0_c
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0183, (0x8000|DAC_IN_0V));	// 1e_183:dac_in1_c
++			reg_temp = (tc_phy_read_dev_reg(ds, phyaddr, 0x1e, 0x0173) & (~0x3f00));
++			//printk("tx offset pairC 1e_dd = %x, 1e_17d=%x, 1e_181=%x\n", tc_phy_read_dev_reg(phyaddr, 0x1e, 0x00dd), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x017d), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x0181));
++			tx_offset_reg_shift = 8;									// 1e_173[13:8]
++			tx_offset_reg = 0x0173;
++			//tc_phy_write_dev_reg(phyaddr, 0x1e, tx_offset_reg, (reg_temp|(tx_offset_temp<<tx_offset_reg_shift)));
++		} else {// if(calibration_pair == ANACAL_PAIR_D)
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00dd, 0x0001);				// 1e_dd[0]:rg_txg_calen_d
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0180, (0x8000|DAC_IN_0V));	// 1e_180:dac_in0_d
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0184, (0x8000|DAC_IN_0V));	// 1e_184:dac_in1_d
++			//printk("tx offset pairD 1e_dd = %x, 1e_17d=%x, 1e_181=%x\n", tc_phy_read_dev_reg(phyaddr, 0x1e, 0x00dd), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x017d), tc_phy_read_dev_reg(phyaddr, 0x1e, 0x0181));
++			reg_temp = (tc_phy_read_dev_reg(ds, phyaddr, 0x1e, 0x0173) & (~0x003f));
++			tx_offset_reg_shift = 0;									// 1e_173[5:0]
++			tx_offset_reg = 0x0173;
++			//tc_phy_write_dev_reg(phyaddr, 0x1e, tx_offset_reg, (reg_temp|(tx_offset_temp<<tx_offset_reg_shift)));
++		}
++		tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_offset_reg, (reg_temp|(tx_offset_temp<<tx_offset_reg_shift)));	// 1e_172, 1e_173
++		all_ana_cal_status = all_ge_ana_cal_wait(ds, delay, phyaddr); // delay 20 usec
++		if(all_ana_cal_status == 0) {
++			all_ana_cal_status = ANACAL_ERROR;
++			printk( " GE Tx offset AnaCal ERROR init!   \r\n");
++			return -1;
++		}
++
++		ad_cal_comp_out_init = (tc_phy_read_dev_reg(ds, PHY0, 0x1e, 0x017a)>>8) & 0x1;		// 1e_17a[8]:ad_cal_comp_out
++		if(ad_cal_comp_out_init == 1)
++			calibration_polarity = 1;
++		else
++			calibration_polarity = -1;
++
++		cnt = 0;
++		//printk("TX offset cnt = %d, tabl_idx= %x, offset_val = %x\n", cnt, tabl_idx, MT753x_TX_OFFSET_TBL[tabl_idx]);
++		while(all_ana_cal_status < ANACAL_ERROR) {
++
++			cnt ++;
++			tabl_idx += calibration_polarity;
++			//tx_offset_temp += calibration_polarity;
++			//cal_temp = tx_offset_temp;
++			cal_temp = MT753x_TX_OFFSET_TBL[tabl_idx];
++			//printk("TX offset cnt = %d, tabl_idx= %x, offset_val = %x\n", cnt, tabl_idx, MT753x_TX_OFFSET_TBL[tabl_idx]);
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_offset_reg, (reg_temp|(cal_temp<<tx_offset_reg_shift)));
++
++			all_ana_cal_status = all_ge_ana_cal_wait(ds, delay, phyaddr); // delay 20 usec
++			if(all_ana_cal_status == 0) {
++				all_ana_cal_status = ANACAL_ERROR;
++				printk( " GE Tx offset AnaCal ERROR init 2!   \r\n");
++				return -1;
++			} else if(((tc_phy_read_dev_reg(ds, PHY0, 0x1e, 0x017a)>>8)&0x1) != ad_cal_comp_out_init) {
++				all_ana_cal_status = ANACAL_FINISH;
++			} else {
++				if((tabl_idx == 0)||(tabl_idx == 0x3f)) {
++					all_ana_cal_status = ANACAL_SATURATION;  // need to FT
++					printk( " GE Tx offset AnaCal Saturation!  \r\n");
++				}
++			}
++		}
++
++		if(all_ana_cal_status == ANACAL_ERROR) {
++			tx_offset_temp = TX_AMP_OFFSET_0MV;
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_offset_reg, (reg_temp|(tx_offset_temp<<tx_offset_reg_shift)));
++		} else {
++			printk( " GE Tx offset AnaCal Done! (pair-%d)(%d)(0x%x) 0x1e_%x=0x%x\n", calibration_pair, cnt, MT753x_TX_OFFSET_TBL[tabl_idx], tx_offset_reg, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_offset_reg));
++		}
++	}
++
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x017d, 0x0000);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x017e, 0x0000);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x017f, 0x0000);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0180, 0x0000);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0181, 0x0000);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0182, 0x0000);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0183, 0x0000);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0184, 0x0000);
++
++	tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00db, 0x0000);	// disable analog calibration circuit
++	tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00dc, 0x0000);	// disable Tx offset calibration circuit
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00db, 0x0000);	// disable analog calibration circuit
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00dc, 0x0000);	// disable Tx offset calibration circuit
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x003e, 0x0000);	// disable Tx VLD force mode
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00dd, 0x0000);	// disable Tx offset/amplitude calibration circuit
++
++	return 0;
++}
++
++u16 tx_amp_check_thres(int pair, u32 reg, u16 val, s16 offset)
++{
++	if ((offset < 0 && (0 - offset) > TX_AMP_MAX_OFFSET) ||
++	    (offset > TX_AMP_MAX_OFFSET)) {
++		pr_info(" offset=%d exceed tx amp max offset=%d\n", offset, TX_AMP_MAX_OFFSET);
++		return val;
++	}
++
++	if (offset < 0 && val < TX_AMP_LOW_TS - offset) {
++		if (val < TX_AMP_LOWEST_TS - offset) {
++			pr_info(" GE Tx amp AnaCal underflow! (pair-%d)(1e_%x) seed 0x%x < 0x%x)\n",
++				pair, reg, val, TX_AMP_LOWEST_TS - offset);
++		}
++		return 0;
++	}
++
++	if (offset >= 0 && val > TX_AMP_HIGH_TS - offset) {
++		if ( val > TX_AMP_HIGHEST_TS - offset) {
++			pr_info(" GE Tx amp AnaCal overflow! (pair-%d)(1e_%x) seed = 0x%x > 0x%x)\n",
++				pair, reg, val, TX_AMP_HIGHEST_TS - offset);
++		}
++		return TX_AMP_MAX;
++	}
++
++	return val + offset;
++}
++
++static int ge_cal_tx_amp(struct dsa_switch *ds, u8 phyaddr, u32 delay)
++{
++	u8	all_ana_cal_status, calibration_pair, i;
++	u16	ad_cal_comp_out_init;
++	int	calibration_polarity;
++	u32	tx_amp_reg_shift;
++	u16	reg_temp;
++	u32	tx_amp_temp, tx_amp_reg, cnt=0, tx_amp_reg_100;
++	u32	debug_tmp, reg_backup, reg_tmp;
++	u32	orig_1e_11, orig_1f_300;
++
++	tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00db, 0x1100);	// 1e_db[12]:rg_cal_ckinv, [8]:rg_ana_calen, [4]:rg_rext_calen, [0]:rg_zcalen_a
++	tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00dc, 0x0001);	// 1e_dc[0]:rg_txvos_calen
++	tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00e1, 0x0010);	// 1e_e1[4]:select 1V
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x003e, 0xf808);	// 1e_3e:enable Tx VLD
++
++	orig_1e_11 = tc_phy_read_dev_reg(ds, phyaddr, 0x1e, 0x11);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x11, 0xff00);
++//	tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x27a, 0x33);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0xc9, 0xffff);
++	orig_1f_300 = tc_phy_read_dev_reg(ds, phyaddr, 0x1f, 0x300);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x300, 0x4);
++	for(i = 0; i <= 4; i++)
++		tc_phy_write_dev_reg(ds, i, 0x1e, 0x00dd, 0x0000);
++	for(calibration_pair = ANACAL_PAIR_A; calibration_pair <= ANACAL_PAIR_D; calibration_pair ++) {
++		tx_amp_temp = 0x20;	// start with 0 dB
++
++		if(calibration_pair == ANACAL_PAIR_A) {
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00dd, 0x1000);				// 1e_dd[12]:tx_a amp calibration enable
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x017d, (0x8000|DAC_IN_2V));	// 1e_17d:dac_in0_a
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0181, (0x8000|DAC_IN_2V));	// 1e_181:dac_in1_a
++			reg_temp = (tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x012) & (~0xfc00));
++			tx_amp_reg_shift = 10;										// 1e_12[15:10]
++			tx_amp_reg = 0x12;
++			tx_amp_reg_100 = 0x16;
++		} else if(calibration_pair == ANACAL_PAIR_B) {
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00dd, 0x0100);				// 1e_dd[8]:tx_b amp calibration enable
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x017e, (0x8000|DAC_IN_2V));	// 1e_17e:dac_in0_b
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0182, (0x8000|DAC_IN_2V));	// 1e_182:dac_in1_b
++			reg_temp = (tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x017) & (~0x3f00));
++			tx_amp_reg_shift = 8;										// 1e_17[13:8]
++			tx_amp_reg = 0x17;
++			tx_amp_reg_100 = 0x18;
++		} else if(calibration_pair == ANACAL_PAIR_C) {
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00dd, 0x0010);				// 1e_dd[4]:tx_c amp calibration enable
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x017f, (0x8000|DAC_IN_2V));	// 1e_17f:dac_in0_c
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0183, (0x8000|DAC_IN_2V));	// 1e_183:dac_in1_c
++			reg_temp = (tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x019) & (~0x3f00));
++			tx_amp_reg_shift = 8;										// 1e_19[13:8]
++			tx_amp_reg = 0x19;
++			tx_amp_reg_100 = 0x20;
++		} else { //if(calibration_pair == ANACAL_PAIR_D)
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00dd, 0x0001);				// 1e_dd[0]:tx_d amp calibration enable
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0180, (0x8000|DAC_IN_2V));	// 1e_180:dac_in0_d
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0184, (0x8000|DAC_IN_2V));	// 1e_184:dac_in1_d
++			reg_temp = (tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x021) & (~0x3f00));
++			tx_amp_reg_shift = 8;										// 1e_21[13:8]
++			tx_amp_reg = 0x21;
++			tx_amp_reg_100 = 0x22;
++		}
++		tc_phy_write_dev_reg( ds, phyaddr, 0x1e, tx_amp_reg, (tx_amp_temp|(tx_amp_temp<<tx_amp_reg_shift)));	// 1e_12, 1e_17, 1e_19, 1e_21
++		tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100, (tx_amp_temp|(tx_amp_temp<<tx_amp_reg_shift)));
++		all_ana_cal_status = all_ge_ana_cal_wait(ds, delay, phyaddr); 	// delay 20 usec
++		if(all_ana_cal_status == 0) {
++			all_ana_cal_status = ANACAL_ERROR;
++			printk( " GE Tx amp AnaCal ERROR init init!   \r\n");
++			return -1;
++		}
++
++		ad_cal_comp_out_init = (tc_phy_read_dev_reg(ds,  PHY0, 0x1e, 0x017a)>>8) & 0x1;		// 1e_17a[8]:ad_cal_comp_out
++		if(ad_cal_comp_out_init == 1)
++			calibration_polarity = -1;
++		else
++			calibration_polarity = 1;
++
++		cnt =0;
++		while(all_ana_cal_status < ANACAL_ERROR) {
++			cnt ++;
++			tx_amp_temp += calibration_polarity;
++			//printk("tx_amp : %x, 1e %x = %x\n", tx_amp_temp, tx_amp_reg, (reg_temp|(tx_amp_temp<<tx_amp_reg_shift)));
++			tc_phy_write_dev_reg( ds, phyaddr, 0x1e, tx_amp_reg, (tx_amp_temp|(tx_amp_temp<<tx_amp_reg_shift)));
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100, (tx_amp_temp|(tx_amp_temp<<tx_amp_reg_shift)));
++			all_ana_cal_status = all_ge_ana_cal_wait(ds, delay, phyaddr); // delay 20 usec
++			if(all_ana_cal_status == 0) {
++				all_ana_cal_status = ANACAL_ERROR;
++				printk( " GE Tx amp AnaCal ERROR 2!   \r\n");
++				return -1;
++			} else if(((tc_phy_read_dev_reg(ds,  PHY0, 0x1e, 0x017a)>>8)&0x1) != ad_cal_comp_out_init) {
++				//printk("TX AMP ANACAL_FINISH\n");
++				all_ana_cal_status = ANACAL_FINISH;
++				if (phyaddr == 0) {
++					if (calibration_pair == ANACAL_PAIR_A)
++						tx_amp_temp = tx_amp_temp - 2;
++					else if(calibration_pair == ANACAL_PAIR_B)
++						tx_amp_temp = tx_amp_temp - 1;
++					else if(calibration_pair == ANACAL_PAIR_C)
++						tx_amp_temp = tx_amp_temp - 2;
++					else if(calibration_pair == ANACAL_PAIR_D)
++						tx_amp_temp = tx_amp_temp - 1;
++				} else if (phyaddr == 1) {
++					if (calibration_pair == ANACAL_PAIR_A)
++						tx_amp_temp = tx_amp_temp - 1;
++					else if(calibration_pair == ANACAL_PAIR_B)
++						tx_amp_temp = tx_amp_temp ;
++					else if(calibration_pair == ANACAL_PAIR_C)
++						tx_amp_temp = tx_amp_temp - 1;
++					else if(calibration_pair == ANACAL_PAIR_D)
++						tx_amp_temp = tx_amp_temp - 1;
++				} else if (phyaddr == 2) {
++					if (calibration_pair == ANACAL_PAIR_A)
++						tx_amp_temp = tx_amp_temp;
++					else if(calibration_pair == ANACAL_PAIR_B)
++						tx_amp_temp = tx_amp_temp - 1;
++					else if(calibration_pair == ANACAL_PAIR_C)
++						tx_amp_temp = tx_amp_temp;
++					else if(calibration_pair == ANACAL_PAIR_D)
++						tx_amp_temp = tx_amp_temp - 1;
++				} else if (phyaddr == 3) {
++					tx_amp_temp = tx_amp_temp;
++				} else if (phyaddr == 4) {
++					if (calibration_pair == ANACAL_PAIR_A)
++						tx_amp_temp = tx_amp_temp;
++					else if(calibration_pair == ANACAL_PAIR_B)
++						tx_amp_temp = tx_amp_temp - 1;
++					else if(calibration_pair == ANACAL_PAIR_C)
++						tx_amp_temp = tx_amp_temp;
++					else if(calibration_pair == ANACAL_PAIR_D)
++						tx_amp_temp = tx_amp_temp;
++				}
++				reg_temp = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, tx_amp_reg)&(~0xff00);
++				tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((tx_amp_temp)<<tx_amp_reg_shift)));
++				tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg, (tx_amp_temp|((tx_amp_temp)<<tx_amp_reg_shift)));
++				if (phyaddr == 0) {
++					if ((tx_amp_reg == 0x12) || (tx_amp_reg == 0x17)) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg));
++						reg_tmp = tx_amp_check_thres(calibration_pair, tx_amp_reg, tx_amp_temp, 7);
++						tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg, ((reg_tmp|((tx_amp_temp)<<tx_amp_reg_shift))));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg));
++					}
++					if (tx_amp_reg_100 == 0x16) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100));
++						reg_tmp = tx_amp_check_thres(calibration_pair, tx_amp_reg_100, tx_amp_temp, 1+4);
++						tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((reg_tmp)<<tx_amp_reg_shift)));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100));
++					}
++					if (tx_amp_reg_100 == 0x18) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100));
++						reg_tmp = tx_amp_check_thres(calibration_pair, tx_amp_reg_100, tx_amp_temp, 4);
++						tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((reg_tmp)<<tx_amp_reg_shift)));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100));
++					}
++				} else if (phyaddr == 1) {
++					if (tx_amp_reg == 0x12) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg));
++						reg_tmp = tx_amp_check_thres(calibration_pair, tx_amp_reg, tx_amp_temp, 9);
++						tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg, ((reg_tmp|((tx_amp_temp)<<tx_amp_reg_shift))));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg));
++					}
++					if (tx_amp_reg == 0x17){
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg));
++						reg_tmp = tx_amp_check_thres(calibration_pair, tx_amp_reg, tx_amp_temp, 7);
++						tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg, ((reg_tmp|((tx_amp_temp)<<tx_amp_reg_shift))));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg));
++					}
++					if (tx_amp_reg_100 == 0x16) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100));
++						reg_tmp = tx_amp_check_thres(calibration_pair, tx_amp_reg_100, tx_amp_temp, 4);
++						tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((reg_tmp)<<tx_amp_reg_shift)));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100));
++					}
++					if (tx_amp_reg_100 == 0x18) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100));
++						reg_tmp = tx_amp_check_thres(calibration_pair, tx_amp_reg_100, tx_amp_temp, -1+4);
++						tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((reg_tmp)<<tx_amp_reg_shift)));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100));
++					}
++				} else if (phyaddr == 2) {
++					if ((tx_amp_reg == 0x12) || (tx_amp_reg == 0x17)) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg));
++						reg_tmp = tx_amp_check_thres(calibration_pair, tx_amp_reg, tx_amp_temp, 6);
++						tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg, ((reg_tmp|((tx_amp_temp)<<tx_amp_reg_shift))));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg));
++					}
++					if ((tx_amp_reg_100 == 0x16) || (tx_amp_reg_100 == 0x18)) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100));
++						reg_tmp = tx_amp_check_thres(calibration_pair, tx_amp_reg_100, tx_amp_temp, -1+4);
++						tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((reg_tmp)<<tx_amp_reg_shift)));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100));
++					}
++				} else if (phyaddr == 3) {
++					if (tx_amp_reg == 0x12) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg));
++						reg_tmp = tx_amp_check_thres(calibration_pair, tx_amp_reg, tx_amp_temp, 4);
++						tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg, ((reg_tmp|((tx_amp_temp)<<tx_amp_reg_shift))));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg));
++					}
++					if (tx_amp_reg == 0x17) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg));
++						reg_tmp = tx_amp_check_thres(calibration_pair, tx_amp_reg, tx_amp_temp, 7);
++						tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg, ((reg_tmp|((tx_amp_temp)<<tx_amp_reg_shift))));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg));
++					}
++					if (tx_amp_reg_100 == 0x16) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100));
++						reg_tmp = tx_amp_check_thres(calibration_pair, tx_amp_reg_100, tx_amp_temp, -2+4);
++						tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((reg_tmp)<<tx_amp_reg_shift)));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100));
++					}
++					if (tx_amp_reg_100 == 0x18) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100));
++						reg_tmp = tx_amp_check_thres(calibration_pair, tx_amp_reg_100, tx_amp_temp, -1+3);
++						tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((reg_tmp)<<tx_amp_reg_shift)));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100));
++					}
++				} else if (phyaddr == 4) {
++					if ((tx_amp_reg == 0x12) || (tx_amp_reg == 0x17)) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg));
++						reg_tmp = tx_amp_check_thres(calibration_pair, tx_amp_reg, tx_amp_temp, 5);
++						tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg, ((reg_tmp|((tx_amp_temp)<<tx_amp_reg_shift))));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg));
++					}
++					if (tx_amp_reg_100 == 0x16) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100));
++						reg_tmp = tx_amp_check_thres(calibration_pair, tx_amp_reg_100, tx_amp_temp, -2+4);
++						tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((reg_tmp)<<tx_amp_reg_shift)));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100));
++					}
++					if (tx_amp_reg_100 == 0x18) {
++						//printk("before : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100));
++						reg_tmp = tx_amp_check_thres(calibration_pair, tx_amp_reg_100, tx_amp_temp, -1+4);
++						tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100,(tx_amp_temp|((reg_tmp)<<tx_amp_reg_shift)));
++						//printk("after : PORT[%d] 1e_%x = %x\n", phyaddr, tx_amp_reg_100, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg_100));
++					}
++				}
++
++				if (calibration_pair == ANACAL_PAIR_A){
++					reg_backup = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x12);
++					reg_tmp = ((reg_backup & 0xfc00) >> 10);
++					tx_amp_temp = tx_amp_check_thres(calibration_pair, tx_amp_reg, reg_tmp, -8);
++					reg_backup = 0x0000;
++					reg_backup |= ((tx_amp_temp << 10) | (tx_amp_temp << 0));
++					tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x12, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x12);
++					//printk("PORT[%d] 1e.012 = %x (OFFSET_1000M_PAIR_A)\n", phyaddr, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x16);
++					reg_tmp = ((reg_backup & 0x3f) >> 0);
++					tx_amp_temp = tx_amp_check_thres(calibration_pair, tx_amp_reg, reg_tmp, -8);
++					reg_backup = (reg_backup & (~0x3f));
++					reg_backup |= (tx_amp_temp << 0);
++					tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x16, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x16);
++					//printk("PORT[%d] 1e.016 = %x (OFFSET_TESTMODE_1000M_PAIR_A)\n", phyaddr, reg_backup);
++				}
++				else if(calibration_pair == ANACAL_PAIR_B){
++					reg_backup = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x17);
++					reg_tmp = ((reg_backup & 0x3f00) >> 8);
++					tx_amp_temp = tx_amp_check_thres(calibration_pair, tx_amp_reg, reg_tmp, -8);
++					reg_backup = 0x0000;
++                                       reg_backup |= ((tx_amp_temp << 8) | (tx_amp_temp << 0));
++					tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x17, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x17);
++					//printk("PORT[%d] 1e.017 = %x (OFFSET_1000M_PAIR_B)\n", phyaddr, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x18);
++					reg_tmp = ((reg_backup & 0x3f) >> 0);
++					tx_amp_temp = tx_amp_check_thres(calibration_pair, tx_amp_reg, reg_tmp, -8);
++					reg_backup = (reg_backup & (~0x3f));
++					reg_backup |= (tx_amp_temp << 0);
++					tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x18, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x18);
++					//printk("PORT[%d] 1e.018 = %x (OFFSET_TESTMODE_1000M_PAIR_B)\n", phyaddr, reg_backup);
++				}
++				else if(calibration_pair == ANACAL_PAIR_C){
++					reg_backup = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x19);
++					reg_tmp = ((reg_backup & 0x3f00) >> 8);
++					tx_amp_temp = tx_amp_check_thres(calibration_pair, tx_amp_reg, reg_tmp, -8);
++					reg_backup = (reg_backup & (~0x3f00));
++					reg_backup |= (tx_amp_temp << 8);
++					tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x19, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x19);
++					//printk("PORT[%d] 1e.019 = %x (OFFSET_1000M_PAIR_C)\n", phyaddr, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x20);
++					reg_tmp = ((reg_backup & 0x3f) >> 0);
++					tx_amp_temp = tx_amp_check_thres(calibration_pair, tx_amp_reg, reg_tmp, -8);
++					reg_backup = (reg_backup & (~0x3f));
++					reg_backup |= (tx_amp_temp << 0);
++					tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x20, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x20);
++					//printk("PORT[%d] 1e.020 = %x (OFFSET_TESTMODE_1000M_PAIR_C)\n", phyaddr, reg_backup);
++				}
++				else if(calibration_pair == ANACAL_PAIR_D){
++					reg_backup = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x21);
++					reg_tmp = ((reg_backup & 0x3f00) >> 8);
++					tx_amp_temp = tx_amp_check_thres(calibration_pair, tx_amp_reg, reg_tmp, -8);
++					reg_backup = (reg_backup & (~0x3f00));
++					reg_backup |= (tx_amp_temp << 8);
++					tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x21, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x21);
++					//printk("PORT[%d] 1e.021 = %x (OFFSET_1000M_PAIR_D)\n", phyaddr, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x22);
++					reg_tmp = ((reg_backup & 0x3f) >> 0);
++					tx_amp_temp = tx_amp_check_thres(calibration_pair, tx_amp_reg, reg_tmp, -8);
++					reg_backup = (reg_backup & (~0x3f));
++					reg_backup |= (tx_amp_temp << 0);
++					tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x22, reg_backup);
++					reg_backup = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x22);
++					//printk("PORT[%d] 1e.022 = %x (OFFSET_TESTMODE_1000M_PAIR_D)\n", phyaddr, reg_backup);
++				}
++
++				if (calibration_pair == ANACAL_PAIR_A){
++					//printk("PORT (%d) TX_AMP PAIR (A) FINAL CALIBRATION RESULT\n", phyaddr);
++					debug_tmp = tc_phy_read_dev_reg(ds, phyaddr, 0x1e, 0x12);
++					//printk("1e.012 = 0x%x\n", debug_tmp);
++					debug_tmp = tc_phy_read_dev_reg(ds, phyaddr, 0x1e, 0x16);
++					//printk("1e.016 = 0x%x\n", debug_tmp);
++				}
++
++				else if(calibration_pair == ANACAL_PAIR_B){
++					//printk("PORT (%d) TX_AMP PAIR (A) FINAL CALIBRATION RESULT\n", phyaddr);
++					debug_tmp = tc_phy_read_dev_reg(ds, phyaddr, 0x1e, 0x17);
++					//printk("1e.017 = 0x%x\n", debug_tmp);
++					debug_tmp = tc_phy_read_dev_reg(ds, phyaddr, 0x1e, 0x18);
++					//printk("1e.018 = 0x%x\n", debug_tmp);
++				}
++				else if(calibration_pair == ANACAL_PAIR_C){
++					//printk("PORT (%d) TX_AMP PAIR (A) FINAL CALIBRATION RESULT\n", phyaddr);
++					debug_tmp = tc_phy_read_dev_reg(ds, phyaddr, 0x1e, 0x19);
++					//printk("1e.019 = 0x%x\n", debug_tmp);
++					debug_tmp = tc_phy_read_dev_reg(ds, phyaddr, 0x1e, 0x20);
++					//printk("1e.020 = 0x%x\n", debug_tmp);
++				}
++				else if(calibration_pair == ANACAL_PAIR_D){
++					//printk("PORT (%d) TX_AMP PAIR (A) FINAL CALIBRATION RESULT\n", phyaddr);
++					debug_tmp = tc_phy_read_dev_reg(ds, phyaddr, 0x1e, 0x21);
++					//printk("1e.021 = 0x%x\n", debug_tmp);
++					debug_tmp = tc_phy_read_dev_reg(ds, phyaddr, 0x1e, 0x22);
++					//printk("1e.022 = 0x%x\n", debug_tmp);
++				}
++
++
++				printk( " GE Tx amp AnaCal Done! (pair-%d)(1e_%x = 0x%x)(0x%x)\n", calibration_pair, tx_amp_reg, tc_phy_read_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg), reg_tmp);
++
++			} else {
++				if((tx_amp_temp == 0x3f)||(tx_amp_temp == 0x00)) {
++					all_ana_cal_status = ANACAL_SATURATION;  // need to FT
++					printk( " GE Tx amp AnaCal Saturation!  \r\n");
++				}
++			}
++		}
++
++		if(all_ana_cal_status == ANACAL_ERROR) {
++			tx_amp_temp = 0x20;
++			tc_phy_write_dev_reg(ds, phyaddr, 0x1e, tx_amp_reg, (reg_temp|(tx_amp_temp<<tx_amp_reg_shift)));
++		}
++	}
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x017d, 0x0000);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x017e, 0x0000);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x017f, 0x0000);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0180, 0x0000);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0181, 0x0000);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0182, 0x0000);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0183, 0x0000);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x0184, 0x0000);
++
++	/* disable analog calibration circuit */
++	tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00db, 0x0000);
++	tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00dc, 0x0000);	// disable Tx offset calibration circuit
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00db, 0x0000);	// disable analog calibration circuit
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00dc, 0x0000);	// disable Tx offset calibration circuit
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x003e, 0x0000);	// disable Tx VLD force mode
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x00dd, 0x0000);	// disable Tx offset/amplitude calibration circuit
++
++
++
++	//tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x273, 0x2000);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0xc9, 0x0fff);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x145, 0x1000);
++
++	/* Restore CR to default */
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x11, orig_1e_11);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x300, orig_1f_300);
++
++	return 0;
++}
++
++//-----------------------------------------------------------------
++
++static int phy_calibration(struct dsa_switch *ds, u8 phyaddr)
++{
++	//u32	reg_tmp,reg_tmp0, reg_tmp1, i;
++	u32 reg_tmp;
++	u32 CALDLY = 40;
++	u32 orig_1e_11, orig_1e_185, orig_1e_e1, orig_1f_100;
++	int ret;
++
++	/* Use SW calibration data. */
++	reg_tmp = tc_phy_read_dev_reg(ds, phyaddr, 0x1f, 0x403);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x403, reg_tmp | BIT(3));
++	/* set [12]AN disable, [8]full duplex, [13/6]1000Mbps */
++	//tc_phy_write_dev_reg(phyaddr, 0x0,  0x0140);
++	switch_phy_write(ds, phyaddr, R0, 0x140);
++
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x145, 0x1010);/* fix mdi */
++	orig_1e_185 = tc_phy_read_dev_reg(ds, phyaddr, 0x1e, RG_185);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, RG_185, 0);/* disable tx slew control */
++	orig_1f_100 = tc_phy_read_dev_reg(ds, phyaddr, 0x1f, 0x100);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x100, 0xc000);/* BG voltage output */
++	//tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x403, 0x1099); //bypass efuse
++
++#if (1)
++	//	1f_27c[12:8] cr_da_tx_i2mpb_10m	Trimming TX bias setup(@10M)
++	//tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x27c, 0x1f1f);
++	//tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x27c, 0x3300);
++
++	//reg_tmp1 = tc_phy_read_dev_reg(ds,  PHY0, 0x1f, 0x27c);
++	//dev1Fh_reg273h TXVLD DA register	- Adjust voltage mode TX amplitude.
++	//tc_phy_write_dev_reg(phyaddr, 0x1f, 0x273, 0);
++	//tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x273, 0x1000);
++	//reg_tmp1 = tc_phy_read_dev_reg(ds,  phyaddr, 0x1f, 0x273);
++	//printk("reg_tmp1273 = %x\n", reg_tmp1);
++	/*1e_11 TX  overshoot Enable (PAIR A/B/C/D) in gbe mode*/
++
++	orig_1e_11 = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x11);
++	reg_tmp = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x11);
++	reg_tmp = reg_tmp | (0xf << 12);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x11, reg_tmp);
++	orig_1e_e1 = tc_phy_read_dev_reg(ds, PHY0, 0x1e, 0x00e1);
++	tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00e1, 0x10);
++	/* calibration start ============ */
++	printk("CALDLY = %d\n", CALDLY);
++	if(ge_cal_flag == 0){
++		ret = ge_cal_rext(ds, 0, CALDLY);
++		if (ret == -1){
++			printk("ge_cal_rext error K port =%d\n", phyaddr);
++			return ret;
++		}
++		ge_cal_flag = 1;
++	}
++
++	/* *** R50 Cal start ***************************** */
++	/*phyaddress = 0*/
++	ret = ge_cal_r50(ds, phyaddr, CALDLY);
++	if (ret == -1){
++		printk("R50 error K port =%d\n", phyaddr);
++		return ret;
++	}
++	/* *** R50 Cal end *** */
++	/* *** Tx offset Cal start *********************** */
++	ret = ge_cal_tx_offset(ds, phyaddr, CALDLY);
++	if (ret == -1){
++		printk("ge_cal_tx_offset error K port =%d\n", phyaddr);
++		return ret;
++	}
++	/* *** Tx offset Cal end *** */
++
++	/* *** Tx Amp Cal start *** */
++	ret = ge_cal_tx_amp(ds, phyaddr, CALDLY);
++	if (ret == -1){
++		printk("ge_cal_tx_amp error K port =%d\n", phyaddr);
++		return ret;
++	}
++	/* *** Tx Amp Cal end *** */
++	/*tmp maybe changed*/
++	//tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x27c, 0x1111);
++	//tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x27b, 0x47);
++	//tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x273, 0x2000);
++
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x3a8, 0x0810);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x3aa, 0x0008);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x3ab, 0x0810);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x3ad, 0x0008);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x3ae, 0x0106);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x3b0, 0x0001);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x3b1, 0x0106);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x3b3, 0x0001);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x18c, 0x0001);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x18d, 0x0001);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x18e, 0x0001);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x18f, 0x0001);
++
++	/*da_tx_bias1_b_tx_standby = 5'b10 (dev1eh_reg3aah[12:8])*/
++	reg_tmp = tc_phy_read_dev_reg(ds, phyaddr, 0x1e, 0x3aa);
++	reg_tmp = reg_tmp & ~(0x1f00);
++	reg_tmp = reg_tmp | 0x2 << 8;
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x3aa, reg_tmp);
++
++	/*da_tx_bias1_a_tx_standby = 5'b10 (dev1eh_reg3a9h[4:0])*/
++	reg_tmp = tc_phy_read_dev_reg(ds,  phyaddr, 0x1e, 0x3a9);
++	reg_tmp = reg_tmp & ~(0x1f);
++	reg_tmp = reg_tmp | 0x2;
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x3a9, reg_tmp);
++
++	/* Restore CR to default */
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, RG_185, orig_1e_185);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x100, orig_1f_100);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x11, orig_1e_11);
++	tc_phy_write_dev_reg(ds, PHY0, 0x1e, 0x00e1, orig_1e_e1);
++#endif
++	return 0;
++}
++
++static void rx_dc_offset(struct dsa_switch *ds, u8 phyaddr)
++{
++	pr_info("PORT %d RX_DC_OFFSET\n", phyaddr);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x96, 0x8000);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x37, 0x3);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x107, 0x4000);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x171, 0x1e5);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x39, 0x200f);
++	udelay(40);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x39, 0x000f);
++	udelay(40);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1e, 0x171, 0x65);
++}
++
++static void check_rx_dc_offset_pair_a(struct dsa_switch *ds, u8 phyaddr)
++{
++	u32 reg_tmp;
++
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x114f);
++	reg_tmp = tc_phy_read_dev_reg(ds,  phyaddr, 0x1f, 0x1a);
++	reg_tmp = reg_tmp & 0xff;
++	pr_info("before pairA output = %x\n", reg_tmp);
++	udelay(40);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x1142);
++	udelay(40);
++	reg_tmp = tc_phy_read_dev_reg(ds,  phyaddr, 0x1f, 0x1a);
++	reg_tmp = reg_tmp & 0xff;
++	pr_info("after pairA output = %x\n", reg_tmp);
++	if ((reg_tmp & 0x80) != 0)
++		reg_tmp = (~reg_tmp) + 1;
++	if ((reg_tmp & 0xff) >4)
++		pr_info("pairA RX_DC_OFFSET error");
++}
++
++static void check_rx_dc_offset_pair_b(struct dsa_switch *ds, u8 phyaddr)
++{
++	u32 reg_tmp;
++
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x1151);
++	reg_tmp = tc_phy_read_dev_reg(ds,  phyaddr, 0x1f, 0x1a);
++	reg_tmp = reg_tmp & 0xff;
++	pr_info("before pairB output = %x\n", reg_tmp);
++	udelay(40);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x1143);
++	udelay(40);
++	reg_tmp = tc_phy_read_dev_reg(ds,  phyaddr, 0x1f, 0x1a);
++	reg_tmp = reg_tmp & 0xff;
++	pr_info("after pairB output = %x\n", reg_tmp);
++	if ((reg_tmp & 0x80) != 0)
++		reg_tmp = (~reg_tmp) + 1;
++	if ((reg_tmp & 0xff) >4)
++		pr_info("pairB RX_DC_OFFSET error");
++}
++
++static void check_rx_dc_offset_pair_c(struct dsa_switch *ds, u8 phyaddr)
++{
++	u32 reg_tmp;
++
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x1153);
++	reg_tmp = tc_phy_read_dev_reg(ds,  phyaddr, 0x1f, 0x1a);
++	reg_tmp = reg_tmp & 0xff;
++	pr_info("before pairC output = %x\n", reg_tmp);
++	udelay(40);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x1144);
++	udelay(40);
++	reg_tmp = tc_phy_read_dev_reg(ds,  phyaddr, 0x1f, 0x1a);
++	reg_tmp = reg_tmp & 0xff;
++	pr_info("after pairC output = %x\n", reg_tmp);
++	if ((reg_tmp & 0x80) != 0)
++		reg_tmp = (~reg_tmp) + 1;
++	if ((reg_tmp & 0xff) >4)
++		pr_info("pairC RX_DC_OFFSET error");
++}
++
++static void check_rx_dc_offset_pair_d(struct dsa_switch *ds, u8 phyaddr)
++{
++	u32 reg_tmp;
++
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x1155);
++	reg_tmp = tc_phy_read_dev_reg(ds,  phyaddr, 0x1f, 0x1a);
++	reg_tmp = reg_tmp & 0xff;
++	pr_info("before pairD output = %x\n", reg_tmp);
++	udelay(40);
++	tc_phy_write_dev_reg(ds, phyaddr, 0x1f, 0x15, (phyaddr << 13) | 0x1145);
++	udelay(40);
++	reg_tmp = tc_phy_read_dev_reg(ds,  phyaddr, 0x1f, 0x1a);
++	reg_tmp = reg_tmp & 0xff;
++	pr_info("after pairD output = %x\n", reg_tmp);
++	if ((reg_tmp & 0x80) != 0)
++		reg_tmp = (~reg_tmp) + 1;
++	if ((reg_tmp & 0xff) >4)
++		pr_info("pairD RX_DC_OFFSET error");
++}
++
++/* 12 registers for TX_MLT3 waveform tuning.
++ *    012 345 678 9ab
++ *  1    __
++ *     _/  \_
++ *  0_/      \
++ *            \_    _/
++ * -1           \__/
++ */
++static void mt7531_phy_100m_eye_diag_setting(struct dsa_switch *ds, u32 port)
++{
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0x0, 0x187);
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0x1, 0x1c9);
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0x2, 0x1c6);
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0x3, 0x182);
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0x4, 0x208);
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0x5, 0x205);
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0x6, 0x384);
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0x7, 0x3cb);
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0x8, 0x3c4);
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0x9, 0x30a);
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0xa, 0x00b);
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1E, PHY_TX_MLT3_BASE + 0xb, 0x002);
++}
++
++static void mt7531_phy_setting(struct dsa_switch *ds)
++{
++	int i;
++	u32 val;
++
++	for (i = 0; i < MT7531_NUM_PHYS; i++) {
++		mt7531_phy_100m_eye_diag_setting(ds, i);
++
++		/* Enable HW auto downshift */
++		switch_phy_write(ds, i, 0x1f, 0x1);
++		val = switch_phy_read(ds, i, PHY_EXT_REG_14);
++		val |= PHY_EN_DOWN_SHFIT;
++		switch_phy_write(ds, i, PHY_EXT_REG_14, val);
++
++		/* Decrease SlvDPSready time */
++		val = mt753x_tr_read(ds, i, PMA_CH, PMA_NOD, PMA_17);
++		val &= ~SLV_DSP_READY_TIME_M;
++		val |= 0xc << SLV_DSP_READY_TIME_S;
++		mt753x_tr_write(ds, i, PMA_CH, PMA_NOD, PMA_17, val);
++
++		/* Enable Random Update Mechanism */
++		val = mt753x_tr_read(ds, i, PMA_CH, PMA_NOD, PMA_18);
++		val |= ENABLE_RANDOM_UPDATE_TRIGGER;
++		mt753x_tr_write(ds, i, PMA_CH, PMA_NOD, PMA_18, val);
++
++		/* PHY link down power saving enable */
++		val = switch_phy_read(ds, i, PHY_EXT_REG_17);
++		val |= PHY_LINKDOWN_POWER_SAVING_EN;
++		switch_phy_write(ds, i, PHY_EXT_REG_17, val);
++
++		val = tc_phy_read_dev_reg(ds, i, PHY_DEV1E, PHY_DEV1E_REG_0C6);
++		val &= ~PHY_POWER_SAVING_M;
++		val |= PHY_POWER_SAVING_TX << PHY_POWER_SAVING_S;
++		tc_phy_write_dev_reg(ds, i, PHY_DEV1E, PHY_DEV1E_REG_0C6, val);
++
++		/* Timing Recovery for GbE slave mode */
++		mt753x_tr_write(ds, i, PMA_CH, PMA_NOD, PMA_01, 0x6fb90a);
++		mt753x_tr_write(ds, i, DSP_CH, DSP_NOD, DSP_06, 0x2ebaef);
++		val = tc_phy_read_dev_reg(ds, i, PHY_DEV1E, PHY_DEV1E_REG_234);
++		val |= TR_OPEN_LOOP_EN;
++		tc_phy_write_dev_reg(ds, i, PHY_DEV1E, PHY_DEV1E_REG_234, val);
++
++		/* Enable Asymmetric Pause Capability */
++		val = switch_phy_read(ds, i, MII_ADVERTISE);
++		val |= ADVERTISE_PAUSE_ASYM;
++		switch_phy_write(ds, i, MII_ADVERTISE, val);
++	}
++}
++
++static void mt7531_adjust_line_driving(struct dsa_switch *ds, u32 port)
++{
++	/* For ADC timing margin window for LDO calibration */
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1E, RXADC_LDO_CONTROL_2, 0x2222);
++
++	/* Adjust AD sample timing */
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1E, RXADC_CONTROL_3, 0x4444);
++
++	/* Adjust Line driver current for different mode */
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1F, TXVLD_DA_271, 0x2ca5);
++
++	/* Adjust Line driver current for different mode */
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1F, TXVLD_DA_272, 0xc6b);
++
++	/* Adjust Line driver gain for 10BT from 1000BT calibration result */
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1F, TXVLD_DA_273, 0x3000);
++
++	/* Adjust RX Echo path filter */
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1E, PHY_DEV1E_REG_0FE, 0x2);
++
++	/* Adjust RX HVGA bias current */
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1E, PHY_DEV1E_REG_41, 0x3333);
++
++	/* Adjust TX class AB driver 1 */
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1F, PHY_DEV1F_REG_268, 0x384);
++
++	/* Adjust TX class AB driver 2 */
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1F, PHY_DEV1F_REG_269, 0x1114);
++
++	/* Adjust DAC delay for TX Pairs */
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1E, PHY_DEV1E_REG_13, 0x404);
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1E, PHY_DEV1E_REG_14, 0x404);
++
++	/* Adjust DAC digital delay for TX Delay */
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1F, PHY_DEV1F_REG_44, 0xc0);
++
++	/* Adjust Line driver compensation cap for stability concern due to
++	 * increase current.
++	 */
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1F, PHY_DEV1F_REG_26A, 0x3333);
++}
++
++static void mt7531_eee_setting(struct dsa_switch *ds, u32 port)
++{
++	u32 val;
++
++	/* Disable EEE */
++	tc_phy_write_dev_reg(ds, port, PHY_DEV07, PHY_DEV07_REG_03C, 0);
++
++	/* Disable generate signal to clear the scramble_lock when lpi mode */
++	val = tc_phy_read_dev_reg(ds, port, PHY_DEV1E, PHY_DEV1E_REG_189);
++	val &= ~DESCRAMBLER_CLEAR_EN;
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1E, PHY_DEV1E_REG_189, val);
++
++	/* Roll back EEE Slave Mode */
++	tc_phy_write_dev_reg(ds, port, 0x1e, 0x2d1, 0);
++	mt753x_tr_write(ds, port, DSP_CH, DSP_NOD, DSP_08, 0x1b);
++	mt753x_tr_write(ds, port, DSP_CH, DSP_NOD, DSP_0f, 0);
++	mt753x_tr_write(ds, port, DSP_CH, DSP_NOD, DSP_10, 0x5000);
++
++	/* Adjust 100_mse_threshold */
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1E, PHY_DEV1E_REG_123, 0xffff);
++
++	/* Disable mcc */
++	tc_phy_write_dev_reg(ds, port, PHY_DEV1E, PHY_DEV1E_REG_A6, 0x300);
++}
++
++int mt7531_phy_setup(struct dsa_switch *ds)
++{
++	int ret;
++	int i;
++
++	mt7531_phy_setting(ds);
++
++	for (i = 0; i < MT7531_NUM_PHYS; i++) {
++		mt7531_adjust_line_driving(ds, i);
++		mt7531_eee_setting(ds, i);
++	}
++
++	/*for (i = 0; i < MT7531_NUM_PHYS; i++) {
++		ret = phy_calibration(ds, i);
++
++		rx_dc_offset(ds, i);
++		check_rx_dc_offset_pair_a(ds, i);
++		check_rx_dc_offset_pair_b(ds, i);
++		check_rx_dc_offset_pair_c(ds, i);
++		check_rx_dc_offset_pair_d(ds, i);
++
++		switch_phy_write(ds, i, 0, 0x1040);
++	}*/
++
++	return ret;
++}
+Index: linux-5.4.124/drivers/net/dsa/mt7531_phy.h
+===================================================================
+--- /dev/null
++++ linux-5.4.124/drivers/net/dsa/mt7531_phy.h
+@@ -0,0 +1,262 @@
++/* SPDX-License-Identifier:	GPL-2.0+ */
++/*
++ * Register definitions for MediaTek MT753x Gigabit switches
++ *
++ * Copyright (C) 2018 MediaTek Inc. All Rights Reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#ifndef _MT753X_PHY_H_
++#define _MT753X_PHY_H_
++
++#include <linux/bitops.h>
++
++/*phy calibration use*/
++#define DEV_1E				0x1E
++/*global device 0x1f, always set P0*/
++#define DEV_1F				0x1F
++
++
++/************IEXT/REXT CAL***************/
++/* bits range: for example BITS(16,23) = 0xFF0000*/
++#define BITS(m, n)   (~(BIT(m) - 1) & ((BIT(n) - 1) | BIT(n)))
++#define ANACAL_INIT			0x01
++#define ANACAL_ERROR			0xFD
++#define ANACAL_SATURATION		0xFE
++#define	ANACAL_FINISH			0xFF
++#define ANACAL_PAIR_A			0
++#define ANACAL_PAIR_B			1
++#define ANACAL_PAIR_C			2
++#define ANACAL_PAIR_D			3
++#define DAC_IN_0V			0x00
++#define DAC_IN_2V			0xf0
++#define TX_AMP_OFFSET_0MV		0x20
++#define TX_AMP_OFFSET_VALID_BITS	6
++
++#define R0				0
++#define PHY0				0
++#define PHY1				1
++#define PHY2				2
++#define PHY3				3
++#define PHY4				4
++#define ANA_TEST_MODE			BITS(8, 15)
++#define TST_TCLK_SEL			BITs(6, 7)
++#define ANA_TEST_VGA_RG			0x100
++
++#define FORCE_MDI_CROSS_OVER		BITS(3, 4)
++#define T10_TEST_CTL_RG			0x145
++#define RG_185				0x185
++#define RG_TX_SLEW			BIT(0)
++#define ANA_CAL_0			0xdb
++#define RG_CAL_CKINV			BIT(12)
++#define RG_ANA_CALEN			BIT(8)
++#define RG_REXT_CALEN			BIT(4)
++#define RG_ZCALEN_A			BIT(0)
++#define ANA_CAL_1			0xdc
++#define RG_ZCALEN_B			BIT(12)
++#define RG_ZCALEN_C			BIT(8)
++#define RG_ZCALEN_D			BIT(4)
++#define RG_TXVOS_CALEN			BIT(0)
++#define ANA_CAL_6			0xe1
++#define RG_CAL_REFSEL			BIT(4)
++#define RG_CAL_COMP_PWD			BIT(0)
++#define ANA_CAL_5			0xe0
++#define RG_REXT_TRIM			BITs(8, 13)
++#define RG_ZCAL_CTRL			BITs(0, 5)
++#define RG_17A				0x17a
++#define AD_CAL_COMP_OUT			BIT(8)
++#define RG_17B				0x17b
++#define AD_CAL_CLK			bit(0)
++#define RG_17C				0x17c
++#define DA_CALIN_FLAG			bit(0)
++/************R50 CAL****************************/
++#define RG_174				0x174
++#define RG_R50OHM_RSEL_TX_A_EN		BIT[15]
++#define CR_R50OHM_RSEL_TX_A		BITS[8:14]
++#define RG_R50OHM_RSEL_TX_B_EN		BIT[7]
++#define CR_R50OHM_RSEL_TX_B		BITS[6:0]
++#define RG_175				0x175
++#define RG_R50OHM_RSEL_TX_C_EN		BITS[15]
++#define CR_R50OHM_RSEL_TX_C		BITS[8:14]
++#define RG_R50OHM_RSEL_TX_D_EN		BIT[7]
++#define CR_R50OHM_RSEL_TX_D		BITS[0:6]
++/**********TX offset Calibration***************************/
++#define RG_95				0x96
++#define BYPASS_TX_OFFSET_CAL		BIT(15)
++#define RG_3E				0x3e
++#define BYPASS_PD_TXVLD_A		BIT(15)
++#define BYPASS_PD_TXVLD_B		BIT(14)
++#define BYPASS_PD_TXVLD_C		BIT(13)
++#define BYPASS_PD_TXVLD_D		BIT(12)
++#define BYPASS_PD_TX_10M		BIT(11)
++#define POWER_DOWN_TXVLD_A		BIT(7)
++#define POWER_DOWN_TXVLD_B		BIT(6)
++#define POWER_DOWN_TXVLD_C		BIT(5)
++#define POWER_DOWN_TXVLD_D		BIT(4)
++#define POWER_DOWN_TX_10M		BIT(3)
++#define RG_DD				0xdd
++#define RG_TXG_CALEN_A			BIT(12)
++#define RG_TXG_CALEN_B			BIT(8)
++#define RG_TXG_CALEN_C			BIT(4)
++#define RG_TXG_CALEN_D			BIT(0)
++#define RG_17D				0x17D
++#define FORCE_DASN_DAC_IN0_A		BIT(15)
++#define DASN_DAC_IN0_A			BITS(0, 9)
++#define RG_17E				0x17E
++#define FORCE_DASN_DAC_IN0_B		BIT(15)
++#define DASN_DAC_IN0_B			BITS(0, 9)
++#define RG_17F				0x17F
++
++#define FORCE_DASN_DAC_IN0_C		BIT(15)
++#define DASN_DAC_IN0_C			BITS(0, 9)
++#define RG_180				0x180
++#define FORCE_DASN_DAC_IN0_D		BIT(15)
++#define DASN_DAC_IN0_D			BITS(0, 9)
++
++#define RG_181				0x181
++#define FORCE_DASN_DAC_IN1_A		BIT(15)
++#define DASN_DAC_IN1_A			BITS(0, 9)
++#define RG_182				0x182
++#define FORCE_DASN_DAC_IN1_B		BIT(15)
++#define DASN_DAC_IN1_B			BITS(0, 9)
++#define RG_183				0x183
++#define FORCE_DASN_DAC_IN1_C		BIT(15)
++#define DASN_DAC_IN1_C			BITS(0, 9)
++#define RG_184				0x184
++#define FORCE_DASN_DAC_IN1_D		BIT(15)
++#define DASN_DAC_IN1_D			BITS(0, 9)
++#define RG_172				0x172
++#define CR_TX_AMP_OFFSET_A		BITS(8, 13)
++#define CR_TX_AMP_OFFSET_B		BITS(0, 5)
++#define RG_173				0x173
++#define CR_TX_AMP_OFFSET_C		BITS(8, 13)
++#define CR_TX_AMP_OFFSET_D		BITS(0, 5)
++/**********TX Amp Calibration ***************************/
++#define RG_12				0x12
++#define DA_TX_I2MPB_A_GBE		BITS(10, 15)
++#define RG_17				0x17
++#define DA_TX_I2MPB_B_GBE		BITS(8, 13)
++#define RG_19				0x19
++#define DA_TX_I2MPB_C_GBE		BITS(8, 13)
++#define RG_21				0x21
++#define DA_TX_I2MPB_D_GBE		BITS(8, 13)
++#define TX_AMP_MAX			0x3f
++#define TX_AMP_MAX_OFFSET		0xb
++#define TX_AMP_HIGHEST_TS		((TX_AMP_MAX) + 3)
++#define TX_AMP_LOWEST_TS		(0 - 3)
++#define TX_AMP_HIGH_TS			(TX_AMP_MAX)
++#define TX_AMP_LOW_TS			0
++
++/* PHY Extend Register 0x14 bitmap of define */
++#define PHY_EXT_REG_14			0x14
++
++/* Fields of PHY_EXT_REG_14 */
++#define PHY_EN_DOWN_SHFIT		BIT(4)
++
++/* PHY Extend Register 0x17 bitmap of define */
++#define PHY_EXT_REG_17			0x17
++
++/* Fields of PHY_EXT_REG_17 */
++#define PHY_LINKDOWN_POWER_SAVING_EN	BIT(4)
++
++/* PHY PMA Register 0x17 bitmap of define */
++#define SLV_DSP_READY_TIME_S		15
++#define SLV_DSP_READY_TIME_M		(0xff << SLV_DSP_READY_TIME_S)
++
++/* PHY PMA Register 0x18 bitmap of define */
++#define ENABLE_RANDOM_UPDATE_TRIGGER	BIT(8)
++
++/* PHY EEE Register bitmap of define */
++#define PHY_DEV07			0x07
++#define PHY_DEV07_REG_03C		0x3c
++
++/* PHY DEV 0x1e Register bitmap of define */
++#define PHY_DEV1E			0x1e
++#define PHY_DEV1F			0x1f
++
++/* Proprietory Control Register of Internal Phy device 0x1e */
++#define PHY_TX_MLT3_BASE		0x0
++#define PHY_DEV1E_REG_13		0x13
++#define PHY_DEV1E_REG_14		0x14
++#define PHY_DEV1E_REG_41		0x41
++#define PHY_DEV1E_REG_A6		0xa6
++#define RXADC_CONTROL_3			0xc2
++#define PHY_DEV1E_REG_0C6		0xc6
++#define RXADC_LDO_CONTROL_2		0xd3
++#define PHY_DEV1E_REG_0FE		0xfe
++#define PHY_DEV1E_REG_123		0x123
++#define PHY_DEV1E_REG_189		0x189
++#define PHY_DEV1E_REG_234		0x234
++
++/* Proprietory Control Register of Internal Phy device 0x1f */
++#define PHY_DEV1F_REG_44		0x44
++#define PHY_DEV1F_REG_268		0x268
++#define PHY_DEV1F_REG_269		0x269
++#define PHY_DEV1F_REG_26A		0x26A
++#define TXVLD_DA_271			0x271
++#define TXVLD_DA_272			0x272
++#define TXVLD_DA_273			0x273
++
++/* Fields of PHY_DEV1E_REG_0C6 */
++#define PHY_POWER_SAVING_S		8
++#define PHY_POWER_SAVING_M		0x300
++#define PHY_POWER_SAVING_TX		0x0
++
++/* Fields of PHY_DEV1E_REG_189 */
++#define DESCRAMBLER_CLEAR_EN		0x1
++
++/* Fields of PHY_DEV1E_REG_234 */
++#define TR_OPEN_LOOP_EN			BIT(0)
++
++/* Internal GPHY Page Control Register */
++#define PHY_CL22_PAGE_CTRL		0x1f
++#define PHY_TR_PAGE			0x52b5
++
++/* Internal GPHY Token Ring Access Registers */
++#define PHY_TR_CTRL			0x10
++#define PHY_TR_LOW_DATA			0x11
++#define PHY_TR_HIGH_DATA		0x12
++
++/* Fields of PHY_TR_CTRL */
++#define PHY_TR_PKT_XMT_STA		BIT(15)
++#define PHY_TR_WR_S			13
++#define PHY_TR_CH_ADDR_S		11
++#define PHY_TR_NODE_ADDR_S		7
++#define PHY_TR_DATA_ADDR_S		1
++
++enum phy_tr_wr {
++	PHY_TR_WRITE = 0,
++	PHY_TR_READ = 1,
++};
++
++/* Helper macro for GPHY Token Ring Access */
++#define PHY_TR_LOW_VAL(x)		((x) & 0xffff)
++#define PHY_TR_HIGH_VAL(x)		(((x) & 0xff0000) >> 16)
++
++/* Token Ring Channels */
++#define PMA_CH				0x1
++#define DSP_CH				0x2
++
++/* Token Ring Nodes */
++#define PMA_NOD				0xf
++#define DSP_NOD				0xd
++
++/* Token Ring register range */
++enum tr_pma_reg_addr {
++	PMA_MIN = 0x0,
++	PMA_01  = 0x1,
++	PMA_17  = 0x17,
++	PMA_18  = 0x18,
++	PMA_MAX = 0x3d,
++};
++
++enum tr_dsp_reg_addr {
++	DSP_MIN = 0x0,
++	DSP_06  = 0x6,
++	DSP_08  = 0x8,
++	DSP_0f  = 0xf,
++	DSP_10  = 0x10,
++	DSP_MAX = 0x3e,
++};
++#endif /* _MT753X_REGS_H_ */
+Index: linux-5.4.124/drivers/net/dsa/Makefile
+===================================================================
+--- linux-5.4.124.orig/drivers/net/dsa/Makefile
++++ linux-5.4.124/drivers/net/dsa/Makefile
+@@ -6,7 +6,8 @@ ifdef CONFIG_NET_DSA_LOOP
+ obj-$(CONFIG_FIXED_PHY)		+= dsa_loop_bdinfo.o
+ endif
+ obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o
+-obj-$(CONFIG_NET_DSA_MT7530)	+= mt7530.o
++obj-$(CONFIG_NET_DSA_MT7530)	+= mt7530-dsa.o
++mt7530-dsa-objs			:= mt7530.o mt7531_phy.o
+ obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
+ obj-$(CONFIG_NET_DSA_QCA8K)	+= qca8k.o
+ obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/743-add-mediatek-ge-gphy-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/743-add-mediatek-ge-gphy-support.patch
new file mode 100644
index 0000000..718f324
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/743-add-mediatek-ge-gphy-support.patch
@@ -0,0 +1,24 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -512,6 +512,11 @@ config MESON_GXL_PHY
+ 	---help---
+ 	  Currently has a driver for the Amlogic Meson GXL Internal PHY
+ 
++config MEDIATEK_GE_PHY
++	tristate "MediaTek Gigabit Ethernet PHYs"
++	help
++	  Supports the MediaTek Gigabit Ethernet PHYs.
++
+ config MICREL_PHY
+ 	tristate "Micrel PHYs"
+ 	---help---
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -93,6 +93,7 @@ obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c
+ obj-$(CONFIG_LXT_PHY)		+= lxt.o
+ obj-$(CONFIG_MARVELL_PHY)	+= marvell.o
+ obj-$(CONFIG_MARVELL_10G_PHY)	+= marvell10g.o
++obj-$(CONFIG_MEDIATEK_GE_PHY)	+= mediatek-ge.o
+ obj-$(CONFIG_MESON_GXL_PHY)	+= meson-gxl.o
+ obj-$(CONFIG_MICREL_KS8995MA)	+= spi_ks8995.o
+ obj-$(CONFIG_MICREL_PHY)	+= micrel.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/744-en8801s-gphy-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/744-en8801s-gphy-support.patch
new file mode 100644
index 0000000..23a0333
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/744-en8801s-gphy-support.patch
@@ -0,0 +1,585 @@
+Index: drivers/net/phy/Kconfig
+===================================================================
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -345,6 +345,11 @@ config SFP
+ 	depends on HWMON || HWMON=n
+ 	select MDIO_I2C
+ 
++config AIROHA_EN8801S_PHY
++	tristate "Drivers for Airoha EN8801S Gigabit PHYs"
++	---help---
++	  Currently supports the Airoha EN8801S PHY.
++
+ config ADIN_PHY
+ 	tristate "Analog Devices Industrial Ethernet PHYs"
+ 	help
+Index: drivers/net/phy/Makefile
+===================================================================
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -67,6 +67,7 @@ aquantia-objs			+= aquantia_main.o
+ ifdef CONFIG_HWMON
+ aquantia-objs			+= aquantia_hwmon.o
+ endif
++obj-$(CONFIG_AIROHA_EN8801S_PHY)	+= en8801s.o
+ obj-$(CONFIG_AQUANTIA_PHY)	+= aquantia.o
+ obj-$(CONFIG_AX88796B_PHY)	+= ax88796b.o
+ obj-$(CONFIG_AT803X_PHY)	+= at803x.o
+Index: drivers/net/phy/en8801s.c
+===================================================================
+--- /dev/null
++++ b/drivers/net/phy/en8801s.c
+@@ -0,0 +1,394 @@
++// SPDX-License-Identifier: GPL-2.0
++/* FILE NAME:  airoha.c
++ * PURPOSE:
++ *      EN8801S phy driver for Linux
++ * NOTES:
++ *
++ */
++
++/* INCLUDE FILE DECLARATIONS
++ */
++
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/errno.h>
++#include <linux/unistd.h>
++#include <linux/interrupt.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/spinlock.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/mii.h>
++#include <linux/ethtool.h>
++#include <linux/phy.h>
++#include <linux/delay.h>
++
++//#include <linux/bitfield.h>
++#include <linux/uaccess.h>
++#include <linux/version.h>
++
++#include "en8801s.h"
++
++/* #define TEST_BOARD */
++
++MODULE_DESCRIPTION("Airoha EN8801S PHY drivers");
++MODULE_AUTHOR("Airoha");
++MODULE_LICENSE("GPL");
++
++static int preSpeed = 0;
++/************************************************************************
++*                  F U N C T I O N S
++************************************************************************/
++unsigned int mdiobus_write45(struct mii_bus *bus, u32 port, u32 devad, u32 reg, u16 val)
++{
++    mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, devad);
++    mdiobus_write(bus, port, MII_MMD_ADDR_DATA_REG, reg);
++    mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
++    mdiobus_write(bus, port, MII_MMD_ADDR_DATA_REG, val);
++    return 0;
++}
++
++unsigned int mdiobus_read45(struct mii_bus *bus, u32 port, u32 devad, u32 reg, u32 *read_data)
++{
++    mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, devad);
++    mdiobus_write(bus, port, MII_MMD_ADDR_DATA_REG, reg);
++    mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
++    *read_data = mdiobus_read(bus, port, MII_MMD_ADDR_DATA_REG);
++    return 0;
++}
++
++/* Airoha MII read function */
++unsigned int ecnt_mii_cl22_read(struct mii_bus *ebus, unsigned int phy_addr,unsigned int phy_register,unsigned int *read_data)
++{
++    *read_data = mdiobus_read(ebus, phy_addr, phy_register);
++    return 0;
++}
++
++/* Airoha MII write function */
++unsigned int ecnt_mii_cl22_write(struct mii_bus *ebus, unsigned int phy_addr, unsigned int phy_register,unsigned int write_data)
++{
++    mdiobus_write(ebus, phy_addr, phy_register, write_data);
++    return 0;
++}
++
++/* EN8801 PBUS write function */
++void En8801_PbusRegWr(struct mii_bus *ebus, unsigned long pbus_address, unsigned long pbus_data)
++{
++    ecnt_mii_cl22_write(ebus, EN8801S_PBUS_PHY_ID, 0x1F, (unsigned int)(pbus_address >> 6));
++    ecnt_mii_cl22_write(ebus, EN8801S_PBUS_PHY_ID, (unsigned int)((pbus_address >> 2) & 0xf), (unsigned int)(pbus_data & 0xFFFF));
++    ecnt_mii_cl22_write(ebus, EN8801S_PBUS_PHY_ID, 0x10, (unsigned int)(pbus_data >> 16));
++    return;
++}
++
++/* EN8801 PBUS read function */
++unsigned long En8801_PbusRegRd(struct mii_bus *ebus, unsigned long pbus_address)
++{
++    unsigned long pbus_data;
++    unsigned int pbus_data_low, pbus_data_high;
++
++    ecnt_mii_cl22_write(ebus, EN8801S_PBUS_PHY_ID, 0x1F, (unsigned int)(pbus_address >> 6));
++    ecnt_mii_cl22_read(ebus, EN8801S_PBUS_PHY_ID, (unsigned int)((pbus_address >> 2) & 0xf), &pbus_data_low);
++    ecnt_mii_cl22_read(ebus, EN8801S_PBUS_PHY_ID, 0x10, &pbus_data_high);
++    pbus_data = (pbus_data_high << 16) + pbus_data_low;
++    return pbus_data;
++}
++
++/* Use default PBUS_PHY_ID */
++/* EN8801 PBUS write function */
++void En8801_varPbusRegWr(struct mii_bus *ebus, unsigned long pbus_id,unsigned long pbus_address, unsigned long pbus_data)
++{
++    ecnt_mii_cl22_write(ebus, pbus_id, 0x1F, (unsigned int)(pbus_address >> 6));
++    ecnt_mii_cl22_write(ebus, pbus_id, (unsigned int)((pbus_address >> 2) & 0xf), (unsigned int)(pbus_data & 0xFFFF));
++    ecnt_mii_cl22_write(ebus, pbus_id, 0x10, (unsigned int)(pbus_data >> 16));
++    return;
++}
++
++/* EN8801 PBUS read function */
++unsigned long En8801_varPbusRegRd(struct mii_bus *ebus, unsigned long pbus_id, unsigned long pbus_address)
++{
++    unsigned long pbus_data;
++    unsigned int pbus_data_low, pbus_data_high;
++
++    ecnt_mii_cl22_write(ebus, pbus_id, 0x1F, (unsigned int)(pbus_address >> 6));
++    ecnt_mii_cl22_read(ebus,  pbus_id, (unsigned int)((pbus_address >> 2) & 0xf), &pbus_data_low);
++    ecnt_mii_cl22_read(ebus,  pbus_id, 0x10, &pbus_data_high);
++    pbus_data = (pbus_data_high << 16) + pbus_data_low;
++    return pbus_data;
++}
++
++/* EN8801 Token Ring Write function */
++void En8801_TR_RegWr(struct mii_bus *ebus, unsigned long tr_address, unsigned long tr_data)
++{
++    ecnt_mii_cl22_write(ebus, EN8801S_MDIO_PHY_ID, 0x1F, 0x52b5);       /* page select */
++    ecnt_mii_cl22_write(ebus, EN8801S_MDIO_PHY_ID, 0x11, (unsigned int)(tr_data & 0xffff));
++    ecnt_mii_cl22_write(ebus, EN8801S_MDIO_PHY_ID, 0x12, (unsigned int)(tr_data >> 16));
++    ecnt_mii_cl22_write(ebus, EN8801S_MDIO_PHY_ID, 0x10, (unsigned int)(tr_address | TrReg_WR));
++    ecnt_mii_cl22_write(ebus, EN8801S_MDIO_PHY_ID, 0x1F, 0x0);          /* page resetore */
++    return;
++}
++
++/* EN8801 Token Ring Read function */
++unsigned long En8801_TR_RegRd(struct mii_bus *ebus, unsigned long tr_address)
++{
++    unsigned long tr_data;
++    unsigned int tr_data_low, tr_data_high;
++
++    ecnt_mii_cl22_write(ebus, EN8801S_MDIO_PHY_ID, 0x1F, 0x52b5);       /* page select */
++    ecnt_mii_cl22_write(ebus, EN8801S_MDIO_PHY_ID, 0x10, (unsigned int)(tr_address | TrReg_RD));
++    ecnt_mii_cl22_read(ebus, EN8801S_MDIO_PHY_ID, 0x11, &tr_data_low);
++    ecnt_mii_cl22_read(ebus, EN8801S_MDIO_PHY_ID, 0x12, &tr_data_high);
++    ecnt_mii_cl22_write(ebus, EN8801S_MDIO_PHY_ID, 0x1F, 0x0);          /* page resetore */
++    tr_data = (tr_data_high << 16) + tr_data_low;
++    return tr_data;
++}
++
++static int en8801s_config_init(struct phy_device *phydev)
++{
++    gephy_all_REG_LpiReg1Ch      GPHY_RG_LPI_1C;
++    gephy_all_REG_dev1Eh_reg324h GPHY_RG_1E_324;
++    gephy_all_REG_dev1Eh_reg012h GPHY_RG_1E_012;
++    gephy_all_REG_dev1Eh_reg017h GPHY_RG_1E_017;
++    unsigned long pbus_data;
++    unsigned int pbusAddress;
++    u32 reg_value;
++    int retry;
++    struct mii_bus *mbus;
++
++    #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0))
++    mbus = phydev->bus;
++    #else
++    mbus = phydev->mdio.bus;
++    #endif
++
++    pbusAddress = EN8801S_PBUS_DEFAULT_ID;
++    retry = MAX_OUI_CHECK;
++    while(1)
++    {
++        pbus_data = En8801_varPbusRegRd(mbus, pbusAddress, EN8801S_RG_ETHER_PHY_OUI);      /* PHY OUI */
++        if(EN8801S_PBUS_OUI == pbus_data)
++        {
++            pbus_data = En8801_varPbusRegRd(mbus, pbusAddress, EN8801S_RG_SMI_ADDR);       /* SMI ADDR */
++            pbus_data = (pbus_data & 0xffff0000) | (unsigned long)(EN8801S_PBUS_PHY_ID << 8) | (unsigned long)(EN8801S_MDIO_PHY_ID );
++            printk("[Airoha] EN8801S SMI_ADDR=%lx (renew)\n", pbus_data);
++            En8801_varPbusRegWr(mbus, pbusAddress, EN8801S_RG_SMI_ADDR, pbus_data);
++            En8801_varPbusRegWr(mbus, EN8801S_PBUS_PHY_ID, EN8801S_RG_BUCK_CTL, 0x03);
++            mdelay(10);
++            break;
++        }
++        else
++        {
++            pbusAddress = EN8801S_PBUS_PHY_ID;
++        }
++        retry --;
++        if (0 == retry)
++        {
++            printk("[Airoha] EN8801S probe fail !\n");
++            return 0;
++        }
++    }
++
++    reg_value = (En8801_PbusRegRd(mbus, EN8801S_RG_LTR_CTL) & 0xfffffffc) | 0x10 | (EN8801S_RX_POLARITY << 1) | EN8801S_TX_POLARITY;
++    En8801_PbusRegWr(mbus, 0xcf8, reg_value);
++    mdelay(10);
++    reg_value &= 0xffffffef;
++    En8801_PbusRegWr(mbus, 0xcf8, reg_value);
++
++    retry = MAX_RETRY;
++    while (1)
++    {
++        mdelay(10);
++        reg_value = phy_read(phydev, MII_PHYSID2);
++        if (reg_value == EN8801S_PHY_ID2)
++        {
++            break;    /* wait GPHY ready */
++        }
++        retry--;
++        if (0 == retry)
++        {
++            printk("[Airoha] EN8801S initialize fail !\n");
++            return 0;
++        }
++    }
++    /* Software Reset PHY */
++    reg_value = phy_read(phydev, MII_BMCR);
++    reg_value |= BMCR_RESET;
++    phy_write(phydev, MII_BMCR, reg_value);
++    retry = MAX_RETRY;
++    do
++    {
++        mdelay(10);
++        reg_value = phy_read(phydev, MII_BMCR);
++        retry--;
++        if (0 == retry)
++        {
++            printk("[Airoha] EN8801S reset fail !\n");
++            return 0;
++        }
++    } while (reg_value & BMCR_RESET);
++
++    En8801_PbusRegWr(mbus, 0x0600, 0x0c000c00);
++    En8801_PbusRegWr(mbus, 0x10, 0xD801);
++    En8801_PbusRegWr(mbus, 0x0,  0x9140);
++
++    En8801_PbusRegWr(mbus, 0x0A14, 0x0003);
++    En8801_PbusRegWr(mbus, 0x0600, 0x0c000c00);
++    /* Set FCM control */
++    En8801_PbusRegWr(mbus, 0x1404, 0x004b);
++    En8801_PbusRegWr(mbus, 0x140c, 0x0007);
++    /* Set GPHY Perfomance*/
++    /* Token Ring */
++    En8801_TR_RegWr(mbus, RgAddr_PMA_01h,     0x6FB90A);
++    En8801_TR_RegWr(mbus, RgAddr_PMA_18h,     0x0E2F00);
++    En8801_TR_RegWr(mbus, RgAddr_DSPF_06h,    0x2EBAEF);
++    En8801_TR_RegWr(mbus, RgAddr_DSPF_11h,    0x040001);
++    En8801_TR_RegWr(mbus, RgAddr_DSPF_03h,    0x000004);
++    En8801_TR_RegWr(mbus, RgAddr_DSPF_1Ch,    0x003210);
++    En8801_TR_RegWr(mbus, RgAddr_DSPF_14h,    0x00024A);
++    En8801_TR_RegWr(mbus, RgAddr_DSPF_0Ch,    0x00704D);
++    En8801_TR_RegWr(mbus, RgAddr_DSPF_0Dh,    0x02314F);
++    En8801_TR_RegWr(mbus, RgAddr_DSPF_10h,    0x005010);
++    En8801_TR_RegWr(mbus, RgAddr_DSPF_0Fh,    0x003028);
++    En8801_TR_RegWr(mbus, RgAddr_TR_26h,      0x444444);
++    En8801_TR_RegWr(mbus, RgAddr_R1000DEC_15h,0x0055A0);
++    /* CL22 & CL45 */
++    phy_write(phydev, 0x1f, 0x03);
++    GPHY_RG_LPI_1C.DATA = phy_read(phydev, RgAddr_LpiReg1Ch);
++    GPHY_RG_LPI_1C.DataBitField.smi_deton_th = 0x0C;
++    phy_write(phydev, RgAddr_LpiReg1Ch, GPHY_RG_LPI_1C.DATA);
++    phy_write(phydev, 0x1f, 0x0);
++    mdiobus_write45(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x122, 0xffff);
++    mdiobus_write45(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x234, 0x0180);
++    mdiobus_write45(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x238, 0x0120);
++    mdiobus_write45(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x120, 0x9014);
++    mdiobus_write45(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x239, 0x0117);
++    mdiobus_write45(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x14A, 0xEE20);
++    mdiobus_write45(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x19B, 0x0111);
++    mdiobus_write45(mbus, EN8801S_MDIO_PHY_ID, 0x1F, 0x268, 0x07F4);
++
++    mdiobus_read45(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x324, &reg_value);
++    GPHY_RG_1E_324.DATA=(u16)reg_value;
++    GPHY_RG_1E_324.DataBitField.smi_det_deglitch_off = 0;
++    mdiobus_write45(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x324, (u32)GPHY_RG_1E_324.DATA);
++    mdiobus_write45(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x19E, 0xC2);
++    mdiobus_write45(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x013, 0x0);
++
++    /* EFUSE */
++    En8801_PbusRegWr(mbus, 0x1C08, 0x40000040);
++    retry = MAX_RETRY;
++    while (0 != retry)
++    {
++        mdelay(1);
++        reg_value = En8801_PbusRegRd(mbus, 0x1C08);
++        if ((reg_value & (1 << 30)) == 0)
++        {
++            break;
++        }
++        retry--;
++    }
++    reg_value = En8801_PbusRegRd(mbus, 0x1C38);          /* RAW#2 */
++    GPHY_RG_1E_012.DataBitField.da_tx_i2mpb_a_tbt = reg_value & 0x03f;
++    mdiobus_write45(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x12, (u32)GPHY_RG_1E_012.DATA);
++    GPHY_RG_1E_017.DataBitField.da_tx_i2mpb_b_tbt=(reg_value >> 8) & 0x03f;
++    mdiobus_write45(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x12, (u32)GPHY_RG_1E_017.DATA);
++
++    En8801_PbusRegWr(mbus, 0x1C08, 0x40400040);
++    retry = MAX_RETRY;
++    while (0 != retry)
++    {
++        mdelay(1);
++        reg_value = En8801_PbusRegRd(mbus, 0x1C08);
++        if ((reg_value & (1 << 30)) == 0)
++        {
++            break;
++        }
++        retry--;
++    }
++    reg_value = En8801_PbusRegRd(mbus, 0x1C30);          /* RAW#16 */
++    GPHY_RG_1E_324.DataBitField.smi_det_deglitch_off = (reg_value >> 12) & 0x01;
++    mdiobus_write45(mbus, EN8801S_MDIO_PHY_ID, 0x1E, 0x324, (u32)GPHY_RG_1E_324.DATA);
++
++    printk("[Airoha] EN8801S initialize OK ! (1.0.5)\n");
++    return 0;
++}
++
++static int en8801s_read_status(struct phy_device *phydev)
++{
++    int ret;
++    struct mii_bus *mbus;
++
++    #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0))
++    mbus = phydev->bus;
++    #else
++    mbus = phydev->mdio.bus;
++    #endif
++
++    ret = genphy_read_status(phydev);
++    if (LINK_DOWN == phydev->link) preSpeed =0;
++
++    if ((preSpeed != phydev->speed) && (LINK_UP == phydev->link))
++    {
++        preSpeed = phydev->speed;
++        En8801_PbusRegWr(mbus, 0x0600, 0x0c000c00);
++        if (SPEED_1000 == preSpeed)
++        {
++            En8801_PbusRegWr(mbus, 0x10, 0xD801);
++            En8801_PbusRegWr(mbus, 0x0,  0x9140);
++
++            En8801_PbusRegWr(mbus, 0x0A14, 0x0003);
++            En8801_PbusRegWr(mbus, 0x0600, 0x0c000c00);
++            mdelay(2);      /* delay 2 ms */
++            En8801_PbusRegWr(mbus, 0x1404, 0x004b);
++            En8801_PbusRegWr(mbus, 0x140c, 0x0007);
++        }
++        else if (SPEED_100 == preSpeed)
++        {
++            En8801_PbusRegWr(mbus, 0x10, 0xD401);
++            En8801_PbusRegWr(mbus, 0x0,  0x9140);
++
++            En8801_PbusRegWr(mbus, 0x0A14, 0x0007);
++            En8801_PbusRegWr(mbus, 0x0600, 0x0c11);
++            mdelay(2);      /* delay 2 ms */
++            En8801_PbusRegWr(mbus, 0x1404, 0x0027);
++            En8801_PbusRegWr(mbus, 0x140c, 0x0007);
++        }
++        else if (SPEED_10 == preSpeed)
++        {
++            En8801_PbusRegWr(mbus, 0x10, 0xD001);
++            En8801_PbusRegWr(mbus, 0x0,  0x9140);
++
++            En8801_PbusRegWr(mbus, 0x0A14, 0x000b);
++            En8801_PbusRegWr(mbus, 0x0600, 0x0c11);
++            mdelay(2);      /* delay 2 ms */
++            En8801_PbusRegWr(mbus, 0x1404, 0x0027);
++            En8801_PbusRegWr(mbus, 0x140c, 0x0007);
++        }
++    }
++    return ret;
++}
++
++static struct phy_driver Airoha_driver[] = {
++{
++    .phy_id         = EN8801S_PHY_ID,
++    .name           = "Airoha EN8801S",
++    .phy_id_mask    = 0x0ffffff0,
++    .features       = PHY_GBIT_FEATURES,
++    .config_init    = en8801s_config_init,
++    .config_aneg    = genphy_config_aneg,
++    .read_status    = en8801s_read_status,
++    .suspend        = genphy_suspend,
++    .resume         = genphy_resume,
++} };
++
++module_phy_driver(Airoha_driver);
++
++static struct mdio_device_id __maybe_unused Airoha_tbl[] = {
++    { EN8801S_PHY_ID, 0x0ffffff0 },
++    { }
++};
++
++MODULE_DEVICE_TABLE(mdio, Airoha_tbl);
++MODULE_LICENSE("GPL");
+Index: drivers/net/phy/en8801s.h
+===================================================================
+--- /dev/null
++++ b/drivers/net/phy/en8801s.h
+@@ -0,0 +1,153 @@
++// SPDX-License-Identifier: GPL-2.0
++/* FILE NAME:  airoha.h
++ * PURPOSE:
++ *      Define EN8801S driver function
++ *
++ * NOTES:
++ *
++ */
++
++#ifndef __AIROHA_H
++#define __AIROHA_H
++
++/* NAMING DECLARATIONS
++ */
++#define PHY_ADDRESS_RANGE       0x18
++#define EN8801S_PBUS_DEFAULT_ID 0x1e
++#define EN8801S_MDIO_PHY_ID     0x18       /* Range PHY_ADDRESS_RANGE .. 0x1e */
++#define EN8801S_PBUS_PHY_ID     (EN8801S_MDIO_PHY_ID + 1)
++
++#define EN8801S_RG_ETHER_PHY_OUI 0x19a4
++#define EN8801S_RG_SMI_ADDR      0x19a8
++#define EN8801S_RG_BUCK_CTL      0x1a20
++#define EN8801S_RG_LTR_CTL      0x0cf8
++
++#define EN8801S_PBUS_OUI        0x17a5
++#define EN8801S_PHY_ID1         0x03a2
++#define EN8801S_PHY_ID2         0x9461
++#define EN8801S_PHY_ID          (unsigned long)((EN8801S_PHY_ID1 << 16) | EN8801S_PHY_ID2)
++
++#define DEV1E_REG013_VALUE      0
++#define DEV1E_REG19E_VALUE      0xC2
++#define DEV1E_REG324_VALUE      0x200
++
++#define TRUE                    1
++#define FALSE                   0
++#define LINK_UP                 1
++#define LINK_DOWN               0
++
++#if defined(TEST_BOARD)
++#define EN8801S_TX_POLARITY     1
++#define EN8801S_RX_POLARITY     0
++#else
++#define EN8801S_TX_POLARITY     0
++#define EN8801S_RX_POLARITY     1 /* The ping default assignment is set to 1 */
++#endif
++
++#define MAX_RETRY               5
++#define MAX_OUI_CHECK           2
++/* CL45 MDIO control */
++#define MII_MMD_ACC_CTL_REG     0x0d
++#define MII_MMD_ADDR_DATA_REG   0x0e
++#define MMD_OP_MODE_DATA        BIT(14)
++
++#define MAX_TRG_COUNTER         5
++
++/* CL22 Reg Support Page Select */
++#define RgAddr_Reg1Fh        0x1f
++#define CL22_Page_Reg        0x0000
++#define CL22_Page_ExtReg     0x0001
++#define CL22_Page_MiscReg    0x0002
++#define CL22_Page_LpiReg     0x0003
++#define CL22_Page_tReg       0x02A3
++#define CL22_Page_TrReg      0x52B5
++
++/* CL45 Reg Support DEVID */
++#define DEVID_03             0x03
++#define DEVID_07             0x07
++#define DEVID_1E             0x1E
++#define DEVID_1F             0x1F
++
++/* TokenRing Reg Access */
++#define TrReg_PKT_XMT_STA    0x8000
++#define TrReg_WR             0x8000
++#define TrReg_RD             0xA000
++
++#define RgAddr_LpiReg1Ch     0x1c
++#define RgAddr_PMA_01h       0x0f82
++#define RgAddr_PMA_18h       0x0fb0
++#define RgAddr_DSPF_03h      0x1686
++#define RgAddr_DSPF_06h      0x168c
++#define RgAddr_DSPF_0Ch      0x1698
++#define RgAddr_DSPF_0Dh      0x169a
++#define RgAddr_DSPF_0Fh      0x169e
++#define RgAddr_DSPF_10h      0x16a0
++#define RgAddr_DSPF_11h      0x16a2
++#define RgAddr_DSPF_14h      0x16a8
++#define RgAddr_DSPF_1Ch      0x16b8
++#define RgAddr_TR_26h        0x0ecc
++#define RgAddr_R1000DEC_15h  0x03aa
++
++/* DATA TYPE DECLARATIONS
++ */
++typedef struct
++{
++    u16 DATA_Lo;
++    u16 DATA_Hi;
++}TR_DATA_T;
++
++typedef union
++{
++    struct
++    {
++        /* b[15:00] */
++        u16 smi_deton_wt                             : 3;
++        u16 smi_det_mdi_inv                          : 1;
++        u16 smi_detoff_wt                            : 3;
++        u16 smi_sigdet_debouncing_en                 : 1;
++        u16 smi_deton_th                             : 6;
++        u16 rsv_14                                   : 2;
++    } DataBitField;
++    u16 DATA;
++} gephy_all_REG_LpiReg1Ch, *Pgephy_all_REG_LpiReg1Ch;
++
++typedef union
++{
++    struct
++    {
++        /* b[15:00] */
++        u16 rg_smi_detcnt_max                        : 6;
++        u16 rsv_6                                    : 2;
++        u16 rg_smi_det_max_en                        : 1;
++        u16 smi_det_deglitch_off                     : 1;
++        u16 rsv_10                                   : 6;
++    } DataBitField;
++    u16 DATA;
++} gephy_all_REG_dev1Eh_reg324h, *Pgephy_all_REG_dev1Eh_reg324h;
++
++typedef union
++{
++    struct
++    {
++        /* b[15:00] */
++        u16 da_tx_i2mpb_a_tbt                        : 6;
++        u16 rsv_6                                    : 4;
++        u16 da_tx_i2mpb_a_gbe                        : 6;
++    } DataBitField;
++    u16 DATA;
++} gephy_all_REG_dev1Eh_reg012h, *Pgephy_all_REG_dev1Eh_reg012h;
++
++typedef union
++{
++    struct
++    {
++        /* b[15:00] */
++        u16 da_tx_i2mpb_b_tbt                        : 6;
++        u16 rsv_6                                    : 2;
++        u16 da_tx_i2mpb_b_gbe                        : 6;
++        u16 rsv_14                                   : 2;
++    } DataBitField;
++    u16 DATA;
++} gephy_all_REG_dev1Eh_reg017h, *Pgephy_all_REG_dev1Eh_reg017h;
++
++#endif /* End of __AIROHA_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8000-PATCH-1-4-tphy-support-type-switch-by-pericfg.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8000-PATCH-1-4-tphy-support-type-switch-by-pericfg.patch
new file mode 100644
index 0000000..4ae4991
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8000-PATCH-1-4-tphy-support-type-switch-by-pericfg.patch
@@ -0,0 +1,168 @@
+From ddeda571f3d79dcccef6541b6413cb184de40afd Mon Sep 17 00:00:00 2001
+From: Zhanyong Wang <zhanyong.wang@mediatek.com>
+Date: Fri, 17 Sep 2021 15:56:53 +0800
+Subject: [PATCH] phy: phy-mtk-tphy: support type switch by pericfg
+
+Add support type switch between USB3, PCIe, SATA and SGMII by
+pericfg register, this is used to take the place of efuse or
+jumper.
+
+Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Zhanyong Wang <zhanyong.wang@mediatek.com>
+---
+ drivers/phy/mediatek/phy-mtk-tphy.c | 84 +++++++++++++++++++++++++++--
+ 1 file changed, 81 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c
+index d1ecf088032b..759e1c0c370a 100644
+--- a/drivers/phy/mediatek/phy-mtk-tphy.c
++++ b/drivers/phy/mediatek/phy-mtk-tphy.c
+@@ -10,12 +10,12 @@
+ #include <linux/delay.h>
+ #include <linux/io.h>
+ #include <linux/iopoll.h>
++#include <linux/mfd/syscon.h>
+ #include <linux/module.h>
+ #include <linux/of_address.h>
+ #include <linux/of_device.h>
+ #include <linux/phy/phy.h>
+ #include <linux/platform_device.h>
+-#include <linux/mfd/syscon.h>
+ #include <linux/regmap.h>
+ 
+ /* version V1 sub-banks offset base address */
+@@ -268,6 +268,14 @@
+ #define HIF_SYSCFG1			0x14
+ #define HIF_SYSCFG1_PHY2_MASK		(0x3 << 20)
+ 
++/* PHY switch between pcie/usb3/sgmii/sata */
++#define USB_PHY_SWITCH_CTRL	0x0
++#define RG_PHY_SW_TYPE		GENMASK(3, 0)
++#define RG_PHY_SW_PCIE		0x0
++#define RG_PHY_SW_USB3		0x1
++#define RG_PHY_SW_SGMII		0x2
++#define RG_PHY_SW_SATA		0x3
++
+ enum mtk_phy_version {
+ 	MTK_PHY_V1 = 1,
+ 	MTK_PHY_V2,
+@@ -301,7 +309,10 @@ struct mtk_phy_instance {
+ 	};
+ 	struct clk *ref_clk;	/* reference clock of anolog phy */
+ 	u32 index;
+-	u8 type;
++	u32 type;
++	struct regmap *type_sw;
++	u32 type_sw_reg;
++	u32 type_sw_index;
+ 	int eye_src;
+ 	int eye_vrt;
+ 	int eye_term;
+@@ -900,6 +911,64 @@ static void u2_phy_props_set(struct mtk_tphy *tphy,
+ 	}
+ }
+ 
++/* type switch for usb3/pcie/sgmii/sata */
++static int phy_type_syscon_get(struct mtk_phy_instance *instance,
++			       struct device_node *dn)
++{
++	struct of_phandle_args args;
++	int ret;
++
++	/* type switch function is optional */
++	if (!of_property_read_bool(dn, "mediatek,syscon-type"))
++		return 0;
++
++	ret = of_parse_phandle_with_fixed_args(dn, "mediatek,syscon-type",
++					       2, 0, &args);
++	if (ret)
++		return ret;
++
++	instance->type_sw_reg = args.args[0];
++	instance->type_sw_index = args.args[1] & 0x3; /* <=3 */
++	instance->type_sw = syscon_node_to_regmap(args.np);
++	of_node_put(args.np);
++	dev_info(&instance->phy->dev, "type_sw - reg %#x, index %d\n",
++		 instance->type_sw_reg, instance->type_sw_index);
++
++	return PTR_ERR_OR_ZERO(instance->type_sw);
++}
++
++static int phy_type_set(struct mtk_phy_instance *instance)
++{
++	int type;
++	u32 mask;
++
++	if (!instance->type_sw)
++		return 0;
++
++	switch (instance->type) {
++	case PHY_TYPE_USB3:
++		type = RG_PHY_SW_USB3;
++		break;
++	case PHY_TYPE_PCIE:
++		type = RG_PHY_SW_PCIE;
++		break;
++	case PHY_TYPE_SGMII:
++		type = RG_PHY_SW_SGMII;
++		break;
++	case PHY_TYPE_SATA:
++		type = RG_PHY_SW_SATA;
++		break;
++	case PHY_TYPE_USB2:
++	default:
++		return 0;
++	}
++
++	mask = RG_PHY_SW_TYPE << (instance->type_sw_index * BITS_PER_BYTE);
++	regmap_update_bits(instance->type_sw, instance->type_sw_reg, mask, type);
++
++	return 0;
++}
++
+ static int mtk_phy_init(struct phy *phy)
+ {
+ 	struct mtk_phy_instance *instance = phy_get_drvdata(phy);
+@@ -932,6 +1001,9 @@ static int mtk_phy_init(struct phy *phy)
+ 	case PHY_TYPE_SATA:
+ 		sata_phy_instance_init(tphy, instance);
+ 		break;
++	case PHY_TYPE_SGMII:
++		/* nothing to do, only used to set type */
++		break;
+ 	default:
+ 		dev_err(tphy->dev, "incompatible PHY type\n");
+ 		return -EINVAL;
+@@ -1020,7 +1092,8 @@ static struct phy *mtk_phy_xlate(struct device *dev,
+ 	if (!(instance->type == PHY_TYPE_USB2 ||
+ 	      instance->type == PHY_TYPE_USB3 ||
+ 	      instance->type == PHY_TYPE_PCIE ||
+-	      instance->type == PHY_TYPE_SATA)) {
++	      instance->type == PHY_TYPE_SATA ||
++	      instance->type == PHY_TYPE_SGMII)) {
+ 		dev_err(dev, "unsupported device type: %d\n", instance->type);
+ 		return ERR_PTR(-EINVAL);
+ 	}
+@@ -1035,6 +1108,7 @@ static struct phy *mtk_phy_xlate(struct device *dev,
+ 	}
+ 
+ 	phy_parse_property(tphy, instance);
++	phy_type_set(instance);
+ 
+ 	return instance->phy;
+ }
+@@ -1183,6 +1257,10 @@ static int mtk_tphy_probe(struct platform_device *pdev)
+ 			retval = PTR_ERR(instance->ref_clk);
+ 			goto put_child;
+ 		}
++
++		retval = phy_type_syscon_get(instance, child_np);
++		if (retval)
++			goto put_child;
+ 	}
+ 
+ 	provider = devm_of_phy_provider_register(dev, mtk_phy_xlate);
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8001-PATCH-2-4-dt-bindings-phy-Add-PHY_TYPE_DP-definition.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8001-PATCH-2-4-dt-bindings-phy-Add-PHY_TYPE_DP-definition.patch
new file mode 100644
index 0000000..f83e220
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8001-PATCH-2-4-dt-bindings-phy-Add-PHY_TYPE_DP-definition.patch
@@ -0,0 +1,29 @@
+From 8a79db5e83a5d52c74e6f3c40d6f312cf899213e Mon Sep 17 00:00:00 2001
+From: Jyri Sarha <jsarha@ti.com>
+Date: Wed, 8 Jan 2020 10:30:07 +0200
+Subject: [PATCH 1/5] dt-bindings: phy: Add PHY_TYPE_DP definition
+
+Add definition for DisplayPort phy type.
+
+Signed-off-by: Jyri Sarha <jsarha@ti.com>
+Reviewed-by: Roger Quadros <rogerq@ti.com>
+Reviewed-by: Kishon Vijay Abraham I <kishon@ti.com>
+Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
+---
+ include/dt-bindings/phy/phy.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h
+index b6a1eaf1b339..1f3f866fae7b 100644
+--- a/include/dt-bindings/phy/phy.h
++++ b/include/dt-bindings/phy/phy.h
+@@ -16,5 +16,6 @@
+ #define PHY_TYPE_USB2		3
+ #define PHY_TYPE_USB3		4
+ #define PHY_TYPE_UFS		5
++#define PHY_TYPE_DP		6
+ 
+ #endif /* _DT_BINDINGS_PHY */
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8002-PATCH-3-4-dt-bindings-phy-Add-PHY_TYPE_XPCS-definition.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8002-PATCH-3-4-dt-bindings-phy-Add-PHY_TYPE_XPCS-definition.patch
new file mode 100644
index 0000000..7bd1ca7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8002-PATCH-3-4-dt-bindings-phy-Add-PHY_TYPE_XPCS-definition.patch
@@ -0,0 +1,30 @@
+From c5d3cdad688ed75fb311a3a671eb30ba7106d7d3 Mon Sep 17 00:00:00 2001
+From: Dilip Kota <eswara.kota@linux.intel.com>
+Date: Tue, 19 May 2020 14:19:19 +0800
+Subject: [PATCH 2/5] dt-bindings: phy: Add PHY_TYPE_XPCS definition
+
+Add definition for Ethernet PCS phy type.
+
+Signed-off-by: Dilip Kota <eswara.kota@linux.intel.com>
+Acked-by: Rob Herring <robh@kernel.org>
+Acked-By: Vinod Koul <vkoul@kernel.org>
+Link: https://lore.kernel.org/r/6091f0d2a1046f1e3656d9e33b6cc433d5465eaf.1589868358.git.eswara.kota@linux.intel.com
+Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
+---
+ include/dt-bindings/phy/phy.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h
+index 1f3f866fae7b..3727ef72138b 100644
+--- a/include/dt-bindings/phy/phy.h
++++ b/include/dt-bindings/phy/phy.h
+@@ -17,5 +17,6 @@
+ #define PHY_TYPE_USB3		4
+ #define PHY_TYPE_UFS		5
+ #define PHY_TYPE_DP		6
++#define PHY_TYPE_XPCS		7
+ 
+ #endif /* _DT_BINDINGS_PHY */
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8003-PATCH-4-4-dt-bindings-phy-Add-DT-bindings-for-Xilinx-ZynqMP-PS.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8003-PATCH-4-4-dt-bindings-phy-Add-DT-bindings-for-Xilinx-ZynqMP-PS.patch
new file mode 100644
index 0000000..ef5df66
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8003-PATCH-4-4-dt-bindings-phy-Add-DT-bindings-for-Xilinx-ZynqMP-PS.patch
@@ -0,0 +1,33 @@
+From cea0f76a483d1270ac6f6513964e3e75193dda48 Mon Sep 17 00:00:00 2001
+From: Anurag Kumar Vulisha <anurag.kumar.vulisha@xilinx.com>
+Date: Mon, 29 Jun 2020 15:00:52 +0300
+Subject: [PATCH 3/5] dt-bindings: phy: Add DT bindings for Xilinx ZynqMP PSGTR
+ PHY
+
+Add DT bindings for the Xilinx ZynqMP PHY. ZynqMP SoCs have a High Speed
+Processing System Gigabit Transceiver which provides PHY capabilities to
+USB, SATA, PCIE, Display Port and Ehernet SGMII controllers.
+
+Signed-off-by: Anurag Kumar Vulisha <anurag.kumar.vulisha@xilinx.com>
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Reviewed-by: Rob Herring <robh@kernel.org>
+Link: https://lore.kernel.org/r/20200629120054.29338-2-laurent.pinchart@ideasonboard.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+---
+ include/dt-bindings/phy/phy.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h
+index 3727ef72138b..36e8c241cf48 100644
+--- a/include/dt-bindings/phy/phy.h
++++ b/include/dt-bindings/phy/phy.h
+@@ -18,5 +18,6 @@
+ #define PHY_TYPE_UFS		5
+ #define PHY_TYPE_DP		6
+ #define PHY_TYPE_XPCS		7
++#define PHY_TYPE_SGMII		8
+ 
+ #endif /* _DT_BINDINGS_PHY */
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8004-nvmem-core-Add-functions-to-make-number-reading-easy.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8004-nvmem-core-Add-functions-to-make-number-reading-easy.patch
new file mode 100644
index 0000000..969ec3f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8004-nvmem-core-Add-functions-to-make-number-reading-easy.patch
@@ -0,0 +1,307 @@
+From 8dc0b1158dcffd78ea2b3a5604b82ee826de687b Mon Sep 17 00:00:00 2001
+From: Zhanyong Wang <zhanyong.wang@mediatek.com>
+Date: Mon, 8 Nov 2021 13:58:51 +0800
+Subject: [PATCH 1/5] nvmem: core: Add functions to make number reading easy
+
+Sometimes the clients of nvmem just want to get a number out of
+nvmem. They don't want to think about exactly how many bytes the nvmem
+cell took up. They just want the number. Let's make it easy.
+
+In general this concept is useful because nvmem space is precious and
+usually the fewest bits are allocated that will hold a given value on
+a given system. However, even though small numbers might be fine on
+one system that doesn't mean that logically the number couldn't be
+bigger. Imagine nvmem containing a max frequency for a component. On
+one system perhaps that fits in 16 bits. On another system it might
+fit in 32 bits. The code reading this number doesn't care--it just
+wants the number.
+
+We'll provide two functions: nvmem_cell_read_variable_le_u32() and
+nvmem_cell_read_variable_le_u64().
+
+Comparing these to the existing functions like nvmem_cell_read_u32():
+* These new functions have no problems if the value was stored in
+  nvmem in fewer bytes. It's OK to use these function as long as the
+  value stored will fit in 32-bits (or 64-bits).
+* These functions avoid problems that the earlier APIs had with bit
+  offsets. For instance, you can't use nvmem_cell_read_u32() to read a
+  value has nbits=32 and bit_offset=4 because the nvmem cell must be
+  at least 5 bytes big to hold this value. The new API accounts for
+  this and works fine.
+* These functions make it very explicit that they assume that the
+  number was stored in little endian format. The old functions made
+  this assumption whenever bit_offset was non-zero (see
+  nvmem_shift_read_buffer_in_place()) but didn't whenever the
+  bit_offset was zero.
+
+NOTE: it's assumed that we don't need an 8-bit or 16-bit version of
+this function. The 32-bit version of the function can be used to read
+8-bit or 16-bit data.
+
+At the moment, I'm only adding the "unsigned" versions of these
+functions, but if it ends up being useful someone could add a "signed"
+version that did 2's complement sign extension.
+
+At the moment, I'm only adding the "little endian" versions of these
+functions. Adding the "big endian" version would require adding "big
+endian" support to nvmem_shift_read_buffer_in_place().
+
+Signed-off-by: Douglas Anderson <dianders@chromium.org>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Link: https://lore.kernel.org/r/20210330111241.19401-7-srinivas.kandagatla@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
+Signed-off-by: Zhanyong Wang <zhanyong.wang@mediatek.com>
+Change-Id: I3e1d96ec1680812d5e24681c79852c9b36899559
+---
+ drivers/nvmem/core.c           | 161 +++++++++++++++++++++++++++------
+ include/linux/nvmem-consumer.h |  15 +++
+ 2 files changed, 150 insertions(+), 26 deletions(-)
+
+diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
+index c0f4324d8f7c..e26b25b5c288 100644
+--- a/drivers/nvmem/core.c
++++ b/drivers/nvmem/core.c
+@@ -1102,16 +1102,8 @@ int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len)
+ }
+ EXPORT_SYMBOL_GPL(nvmem_cell_write);
+ 
+-/**
+- * nvmem_cell_read_u16() - Read a cell value as an u16
+- *
+- * @dev: Device that requests the nvmem cell.
+- * @cell_id: Name of nvmem cell to read.
+- * @val: pointer to output value.
+- *
+- * Return: 0 on success or negative errno.
+- */
+-int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val)
++static int nvmem_cell_read_common(struct device *dev, const char *cell_id,
++				  void *val, size_t count)
+ {
+ 	struct nvmem_cell *cell;
+ 	void *buf;
+@@ -1126,21 +1118,50 @@ int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val)
+ 		nvmem_cell_put(cell);
+ 		return PTR_ERR(buf);
+ 	}
+-	if (len != sizeof(*val)) {
++	if (len != count) {
+ 		kfree(buf);
+ 		nvmem_cell_put(cell);
+ 		return -EINVAL;
+ 	}
+-	memcpy(val, buf, sizeof(*val));
++	memcpy(val, buf, count);
+ 	kfree(buf);
+ 	nvmem_cell_put(cell);
+ 
+ 	return 0;
+ }
++
++/**
++ * nvmem_cell_read_u8() - Read a cell value as a u8
++ *
++ * @dev: Device that requests the nvmem cell.
++ * @cell_id: Name of nvmem cell to read.
++ * @val: pointer to output value.
++ *
++ * Return: 0 on success or negative errno.
++ */
++int nvmem_cell_read_u8(struct device *dev, const char *cell_id, u8 *val)
++{
++	return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val));
++}
++EXPORT_SYMBOL_GPL(nvmem_cell_read_u8);
++
++/**
++ * nvmem_cell_read_u16() - Read a cell value as a u16
++ *
++ * @dev: Device that requests the nvmem cell.
++ * @cell_id: Name of nvmem cell to read.
++ * @val: pointer to output value.
++ *
++ * Return: 0 on success or negative errno.
++ */
++int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val)
++{
++	return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val));
++}
+ EXPORT_SYMBOL_GPL(nvmem_cell_read_u16);
+ 
+ /**
+- * nvmem_cell_read_u32() - Read a cell value as an u32
++ * nvmem_cell_read_u32() - Read a cell value as a u32
+  *
+  * @dev: Device that requests the nvmem cell.
+  * @cell_id: Name of nvmem cell to read.
+@@ -1149,32 +1170,120 @@ EXPORT_SYMBOL_GPL(nvmem_cell_read_u16);
+  * Return: 0 on success or negative errno.
+  */
+ int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val)
++{
++	return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val));
++}
++EXPORT_SYMBOL_GPL(nvmem_cell_read_u32);
++
++/**
++ * nvmem_cell_read_u64() - Read a cell value as a u64
++ *
++ * @dev: Device that requests the nvmem cell.
++ * @cell_id: Name of nvmem cell to read.
++ * @val: pointer to output value.
++ *
++ * Return: 0 on success or negative errno.
++ */
++int nvmem_cell_read_u64(struct device *dev, const char *cell_id, u64 *val)
++{
++	return nvmem_cell_read_common(dev, cell_id, val, sizeof(*val));
++}
++EXPORT_SYMBOL_GPL(nvmem_cell_read_u64);
++
++static const void *nvmem_cell_read_variable_common(struct device *dev,
++						   const char *cell_id,
++						   size_t max_len, size_t *len)
+ {
+ 	struct nvmem_cell *cell;
++	int nbits;
+ 	void *buf;
+-	size_t len;
+ 
+ 	cell = nvmem_cell_get(dev, cell_id);
+ 	if (IS_ERR(cell))
+-		return PTR_ERR(cell);
++		return cell;
+ 
+-	buf = nvmem_cell_read(cell, &len);
+-	if (IS_ERR(buf)) {
+-		nvmem_cell_put(cell);
+-		return PTR_ERR(buf);
+-	}
+-	if (len != sizeof(*val)) {
++	nbits = cell->nbits;
++	buf = nvmem_cell_read(cell, len);
++	nvmem_cell_put(cell);
++	if (IS_ERR(buf))
++		return buf;
++
++	/*
++	 * If nbits is set then nvmem_cell_read() can significantly exaggerate
++	 * the length of the real data. Throw away the extra junk.
++	 */
++	if (nbits)
++		*len = DIV_ROUND_UP(nbits, 8);
++
++	if (*len > max_len) {
+ 		kfree(buf);
+-		nvmem_cell_put(cell);
+-		return -EINVAL;
++		return ERR_PTR(-ERANGE);
+ 	}
+-	memcpy(val, buf, sizeof(*val));
++
++	return buf;
++}
++
++/**
++ * nvmem_cell_read_variable_le_u32() - Read up to 32-bits of data as a little endian number.
++ *
++ * @dev: Device that requests the nvmem cell.
++ * @cell_id: Name of nvmem cell to read.
++ * @val: pointer to output value.
++ *
++ * Return: 0 on success or negative errno.
++ */
++int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id,
++				    u32 *val)
++{
++	size_t len;
++	const u8 *buf;
++	int i;
++
++	buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len);
++	if (IS_ERR(buf))
++		return PTR_ERR(buf);
++
++	/* Copy w/ implicit endian conversion */
++	*val = 0;
++	for (i = 0; i < len; i++)
++		*val |= buf[i] << (8 * i);
+ 
+ 	kfree(buf);
+-	nvmem_cell_put(cell);
++
+ 	return 0;
+ }
+-EXPORT_SYMBOL_GPL(nvmem_cell_read_u32);
++EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u32);
++
++/**
++ * nvmem_cell_read_variable_le_u64() - Read up to 64-bits of data as a little endian number.
++ *
++ * @dev: Device that requests the nvmem cell.
++ * @cell_id: Name of nvmem cell to read.
++ * @val: pointer to output value.
++ *
++ * Return: 0 on success or negative errno.
++ */
++int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id,
++				    u64 *val)
++{
++	size_t len;
++	const u8 *buf;
++	int i;
++
++	buf = nvmem_cell_read_variable_common(dev, cell_id, sizeof(*val), &len);
++	if (IS_ERR(buf))
++		return PTR_ERR(buf);
++
++	/* Copy w/ implicit endian conversion */
++	*val = 0;
++	for (i = 0; i < len; i++)
++		*val |= (uint64_t)buf[i] << (8 * i);
++
++	kfree(buf);
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u64);
+ 
+ /**
+  * nvmem_device_cell_read() - Read a given nvmem device and cell
+diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h
+index 5c17cb733224..e328c0f7eef3 100644
+--- a/include/linux/nvmem-consumer.h
++++ b/include/linux/nvmem-consumer.h
+@@ -63,6 +63,10 @@ void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len);
+ int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len);
+ int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val);
+ int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val);
++int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id,
++				    u32 *val);
++int nvmem_cell_read_variable_le_u64(struct device *dev, const char *cell_id,
++				    u64 *val);
+ 
+ /* direct nvmem device read/write interface */
+ struct nvmem_device *nvmem_device_get(struct device *dev, const char *name);
+@@ -134,6 +138,17 @@ static inline int nvmem_cell_read_u32(struct device *dev,
+ {
+ 	return -EOPNOTSUPP;
+ }
++static inline int nvmem_cell_read_variable_le_u32(struct device *dev,
++						const char *cell_id, u32 *val)
++{
++	return -ENOSYS;
++}
++
++static inline int nvmem_cell_read_variable_le_u64(struct device *dev,
++						const char *cell_id, u64 *val);
++{
++	return -ENOSYS;
++}
+ 
+ static inline struct nvmem_device *nvmem_device_get(struct device *dev,
+ 						    const char *name)
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8005-nvmem-mtk-efuse-support-minimum-one-byte-access-stri.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8005-nvmem-mtk-efuse-support-minimum-one-byte-access-stri.patch
new file mode 100644
index 0000000..8de4c2a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8005-nvmem-mtk-efuse-support-minimum-one-byte-access-stri.patch
@@ -0,0 +1,51 @@
+From 44ae4ed142265a6d50a9d3e6f4c395f97b6849ab Mon Sep 17 00:00:00 2001
+From: Zhanyong Wang <zhanyong.wang@mediatek.com>
+Date: Sat, 6 Nov 2021 20:06:30 +0800
+Subject: [PATCH 2/5] nvmem: mtk-efuse: support minimum one byte access stride
+ and granularity
+
+In order to support nvmem bits property, should support minimum 1 byte
+read stride and minimum 1 byte read granularity at the same time.
+
+Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
+Signed-off-by: Zhanyong Wang <zhanyong.wang@mediatek.com>
+Change-Id: Iafe1ebf195d58a3e9e3518913f795d14a01dfd3b
+---
+ drivers/nvmem/mtk-efuse.c | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/nvmem/mtk-efuse.c b/drivers/nvmem/mtk-efuse.c
+index 856d9c3fc38e..2e728fed0b49 100644
+--- a/drivers/nvmem/mtk-efuse.c
++++ b/drivers/nvmem/mtk-efuse.c
+@@ -19,11 +19,12 @@ static int mtk_reg_read(void *context,
+ 			unsigned int reg, void *_val, size_t bytes)
+ {
+ 	struct mtk_efuse_priv *priv = context;
+-	u32 *val = _val;
+-	int i = 0, words = bytes / 4;
++	void __iomem *addr = priv->base + reg;
++	u8 *val = _val;
++	int i;
+ 
+-	while (words--)
+-		*val++ = readl(priv->base + reg + (i++ * 4));
++	for (i = 0; i < bytes; i++, val++)
++		*val = readb(addr + i);
+ 
+ 	return 0;
+ }
+@@ -58,8 +59,8 @@ static int mtk_efuse_probe(struct platform_device *pdev)
+ 	if (IS_ERR(priv->base))
+ 		return PTR_ERR(priv->base);
+ 
+-	econfig.stride = 4;
+-	econfig.word_size = 4;
++	econfig.stride = 1;
++	econfig.word_size = 1;
+ 	econfig.reg_read = mtk_reg_read;
+ 	econfig.reg_write = mtk_reg_write;
+ 	econfig.size = resource_size(res);
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8006-phy-phy-mtk-tphy-add-support-efuse-setting.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8006-phy-phy-mtk-tphy-add-support-efuse-setting.patch
new file mode 100644
index 0000000..5cc8a65
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8006-phy-phy-mtk-tphy-add-support-efuse-setting.patch
@@ -0,0 +1,312 @@
+From afb123e0f9992d35d0fb28ed875f2b7b7884652f Mon Sep 17 00:00:00 2001
+From: Zhanyong Wang <zhanyong.wang@mediatek.com>
+Date: Mon, 8 Nov 2021 14:51:38 +0800
+Subject: [PATCH 3/5] phy: phy-mtk-tphy: add support efuse setting
+
+Due to some SoCs have a bit shift issue that will drop a bit for usb3
+phy or pcie phy, fix it by adding software efuse reading and setting,
+but only support it optionally for versoin.
+
+Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
+Signed-off-by: Zhanyong Wang <zhanyong.wang@mediatek.com>
+Change-Id: Ibf88868668b3889f18c7930531981400cac732f1
+---
+ drivers/phy/mediatek/phy-mtk-tphy.c | 194 ++++++++++++++++++++++++++++
+ 1 file changed, 194 insertions(+)
+
+diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c
+index cb2ed3b25068..05a1ad4ff334 100644
+--- a/drivers/phy/mediatek/phy-mtk-tphy.c
++++ b/drivers/phy/mediatek/phy-mtk-tphy.c
+@@ -11,6 +11,7 @@
+ #include <linux/io.h>
+ #include <linux/iopoll.h>
+ #include <linux/module.h>
++#include <linux/nvmem-consumer.h>
+ #include <linux/of_address.h>
+ #include <linux/of_device.h>
+ #include <linux/phy/phy.h>
+@@ -38,11 +39,16 @@
+ #define SSUSB_SIFSLV_V2_U3PHYD		0x200
+ #define SSUSB_SIFSLV_V2_U3PHYA		0x400
+ 
++#define U3P_MISC_REG1		0x04
++#define MR1_EFUSE_AUTO_LOAD_DIS		BIT(6)
++
+ #define U3P_USBPHYACR0		0x000
+ #define PA0_RG_U2PLL_FORCE_ON		BIT(15)
+ #define PA0_RG_USB20_INTR_EN		BIT(5)
+ 
+ #define U3P_USBPHYACR1		0x004
++#define PA1_RG_INTR_CAL		GENMASK(23, 19)
++#define PA1_RG_INTR_CAL_VAL(x)	((0x1f & (x)) << 19)
+ #define PA1_RG_VRT_SEL			GENMASK(14, 12)
+ #define PA1_RG_VRT_SEL_VAL(x)	((0x7 & (x)) << 12)
+ #define PA1_RG_TERM_SEL		GENMASK(10, 8)
+@@ -114,6 +120,8 @@
+ #define P3C_RG_SWRST_U3_PHYD_FORCE_EN	BIT(24)
+ 
+ #define U3P_U3_PHYA_REG0	0x000
++#define P3A_RG_IEXT_INTR		GENMASK(15, 10)
++#define P3A_RG_IEXT_INTR_VAL(x)		((0x3f & (x)) << 10)
+ #define P3A_RG_CLKDRV_OFF		GENMASK(3, 2)
+ #define P3A_RG_CLKDRV_OFF_VAL(x)	((0x3 & (x)) << 2)
+ 
+@@ -168,6 +176,25 @@
+ #define P3D_RG_FWAKE_TH		GENMASK(21, 16)
+ #define P3D_RG_FWAKE_TH_VAL(x)	((0x3f & (x)) << 16)
+ 
++#define U3P_U3_PHYD_IMPCAL0		0x010
++#define P3D_RG_FORCE_TX_IMPEL		BIT(31)
++#define P3D_RG_TX_IMPEL			GENMASK(28, 24)
++#define P3D_RG_TX_IMPEL_VAL(x)		((0x1f & (x)) << 24)
++
++#define U3P_U3_PHYD_IMPCAL1		0x014
++#define P3D_RG_FORCE_RX_IMPEL		BIT(31)
++#define P3D_RG_RX_IMPEL			GENMASK(28, 24)
++#define P3D_RG_RX_IMPEL_VAL(x)		((0x1f & (x)) << 24)
++
++#define U3P_U3_PHYD_RX0			0x02c
++
++#define U3P_U3_PHYD_T2RLB		0x030
++
++#define U3P_U3_PHYD_PIPE0		0x040
++
++#define U3P_U3_PHYD_RSV			0x054
++#define P3D_RG_EFUSE_AUTO_LOAD_DIS	BIT(12)
++
+ #define U3P_U3_PHYD_CDR1		0x05c
+ #define P3D_RG_CDR_BIR_LTD1		GENMASK(28, 24)
+ #define P3D_RG_CDR_BIR_LTD1_VAL(x)	((0x1f & (x)) << 24)
+@@ -266,11 +293,23 @@
+ enum mtk_phy_version {
+ 	MTK_PHY_V1 = 1,
+ 	MTK_PHY_V2,
++	MTK_PHY_V3,
+ };
+ 
+ struct mtk_phy_pdata {
+ 	/* avoid RX sensitivity level degradation only for mt8173 */
+ 	bool avoid_rx_sen_degradation;
++	/*
++	 * u2phy should use integer mode instead of fractional mode of
++	 * 48M PLL, fix it by switching PLL to 26M from default 48M
++	 * for mt8195
++	 */
++	bool sx_pll_48m_to_26m;
++	/*
++	 * Some SoCs (e.g. mt8195) drop a bit when use auto load efuse,
++	 * support sw way, also support it for v2/v3 optionally.
++	 */
++	bool sw_efuse_supported;
+ 	enum mtk_phy_version version;
+ };
+ 
+@@ -295,6 +334,10 @@ struct mtk_phy_instance {
+ 		struct u3phy_banks u3_banks;
+ 	};
+ 	struct clk *ref_clk;	/* reference clock of anolog phy */
++	u32 efuse_sw_en;
++	u32 efuse_intr;
++	u32 efuse_tx_imp;
++	u32 efuse_rx_imp;
+ 	u32 index;
+ 	u8 type;
+ 	int eye_src;
+@@ -890,6 +933,138 @@ static void u2_phy_props_set(struct mtk_tphy *tphy,
+ 	}
+ }
+ 
++static int phy_efuse_get(struct mtk_tphy *tphy, struct mtk_phy_instance *instance)
++{
++	struct device *dev = &instance->phy->dev;
++	int ret = 0;
++
++	dev_err(dev, "try to get sw efuse\n");
++
++	/* tphy v1 doesn't support sw efuse, skip it */
++	if (!tphy->pdata->sw_efuse_supported) {
++		instance->efuse_sw_en = 0;
++		return 0;
++	}
++
++	/* software efuse is optional */
++	instance->efuse_sw_en = device_property_read_bool(dev, "nvmem-cells");
++	if (!instance->efuse_sw_en)
++		return 0;
++
++	dev_err(dev, "try to get sw efuse+\n");
++
++	switch (instance->type) {
++	case PHY_TYPE_USB2:
++		ret = nvmem_cell_read_variable_le_u32(dev, "intr", &instance->efuse_intr);
++		if (ret) {
++			dev_err(dev, "fail to get u2 intr efuse, %d\n", ret);
++			break;
++		}
++
++		/* no efuse, ignore it */
++		if (!instance->efuse_intr) {
++			dev_warn(dev, "no u2 intr efuse, but dts enable it\n");
++			instance->efuse_sw_en = 0;
++			break;
++		}
++
++		dev_info(dev, "u2 efuse - intr %x\n", instance->efuse_intr);
++		break;
++	case PHY_TYPE_USB3:
++	case PHY_TYPE_PCIE:
++		ret = nvmem_cell_read_variable_le_u32(dev, "intr", &instance->efuse_intr);
++		if (ret) {
++			dev_err(dev, "fail to get u3 intr efuse, %d\n", ret);
++			break;
++		}
++
++		ret = nvmem_cell_read_variable_le_u32(dev, "rx_imp", &instance->efuse_rx_imp);
++		if (ret) {
++			dev_err(dev, "fail to get u3 rx_imp efuse, %d\n", ret);
++			break;
++		}
++
++		ret = nvmem_cell_read_variable_le_u32(dev, "tx_imp", &instance->efuse_tx_imp);
++		if (ret) {
++			dev_err(dev, "fail to get u3 tx_imp efuse, %d\n", ret);
++			break;
++		}
++
++		/* no efuse, ignore it */
++		if (!instance->efuse_intr &&
++		    !instance->efuse_rx_imp &&
++		    !instance->efuse_tx_imp) {
++			dev_warn(dev, "no u3 intr efuse, but dts enable it\n");
++			instance->efuse_sw_en = 0;
++			break;
++		}
++
++		dev_info(dev, "u3 efuse - intr %x, rx_imp %x, tx_imp %x\n",
++			 instance->efuse_intr, instance->efuse_rx_imp,
++			 instance->efuse_tx_imp);
++		break;
++	default:
++		dev_err(dev, "no sw efuse for type %d\n", instance->type);
++		ret = -EINVAL;
++	}
++
++	return ret;
++}
++
++static void phy_efuse_set(struct mtk_phy_instance *instance)
++{
++	struct device *dev = &instance->phy->dev;
++	struct u2phy_banks *u2_banks = &instance->u2_banks;
++	struct u3phy_banks *u3_banks = &instance->u3_banks;
++	u32 tmp;
++
++	if (!instance->efuse_sw_en)
++		return;
++
++	switch (instance->type) {
++	case PHY_TYPE_USB2:
++		tmp = readl(u2_banks->misc + U3P_MISC_REG1);
++		tmp |= MR1_EFUSE_AUTO_LOAD_DIS;
++		writel(tmp, u2_banks->misc + U3P_MISC_REG1);
++
++		tmp = readl(u2_banks->com + U3P_USBPHYACR1);
++		tmp &= ~PA1_RG_INTR_CAL;
++		tmp |= PA1_RG_INTR_CAL_VAL(instance->efuse_intr);
++		writel(tmp, u2_banks->com + U3P_USBPHYACR1);
++		pr_err("%s set efuse intr %x\n", __func__, instance->efuse_intr);
++
++		break;
++	case PHY_TYPE_USB3:
++	case PHY_TYPE_PCIE:
++		tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RSV);
++		tmp |= P3D_RG_EFUSE_AUTO_LOAD_DIS;
++		writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RSV);
++
++		tmp = readl(u3_banks->phyd + U3P_U3_PHYD_IMPCAL0);
++		tmp &= ~P3D_RG_TX_IMPEL;
++		tmp |= P3D_RG_TX_IMPEL_VAL(instance->efuse_tx_imp);
++		tmp |= P3D_RG_FORCE_TX_IMPEL;
++		writel(tmp, u3_banks->phyd + U3P_U3_PHYD_IMPCAL0);
++
++		tmp = readl(u3_banks->phyd + U3P_U3_PHYD_IMPCAL1);
++		tmp &= ~P3D_RG_RX_IMPEL;
++		tmp |= P3D_RG_RX_IMPEL_VAL(instance->efuse_rx_imp);
++		tmp |= P3D_RG_FORCE_RX_IMPEL;
++		writel(tmp, u3_banks->phyd + U3P_U3_PHYD_IMPCAL1);
++
++		tmp = readl(u3_banks->phya + U3P_U3_PHYA_REG0);
++		tmp &= ~P3A_RG_IEXT_INTR;
++		tmp |= P3A_RG_IEXT_INTR_VAL(instance->efuse_intr);
++		writel(tmp, u3_banks->phya + U3P_U3_PHYA_REG0);
++		pr_err("%s set efuse, tx_imp %x, rx_imp %x intr %x\n",
++			__func__, instance->efuse_tx_imp,
++			instance->efuse_rx_imp, instance->efuse_intr);
++		break;
++	default:
++		dev_warn(dev, "no sw efuse for type %d\n", instance->type);
++	}
++}
++
+ static int mtk_phy_init(struct phy *phy)
+ {
+ 	struct mtk_phy_instance *instance = phy_get_drvdata(phy);
+@@ -908,6 +1083,8 @@ static int mtk_phy_init(struct phy *phy)
+ 		return ret;
+ 	}
+ 
++	phy_efuse_set(instance);
++
+ 	switch (instance->type) {
+ 	case PHY_TYPE_USB2:
+ 		u2_phy_instance_init(tphy, instance);
+@@ -989,6 +1166,7 @@ static struct phy *mtk_phy_xlate(struct device *dev,
+ 	struct mtk_phy_instance *instance = NULL;
+ 	struct device_node *phy_np = args->np;
+ 	int index;
++	int ret;
+ 
+ 	if (args->args_count != 1) {
+ 		dev_err(dev, "invalid number of cells in 'phy' property\n");
+@@ -1024,6 +1202,10 @@ static struct phy *mtk_phy_xlate(struct device *dev,
+ 		return ERR_PTR(-EINVAL);
+ 	}
+ 
++	ret = phy_efuse_get(tphy, instance);
++	if (ret)
++		return ERR_PTR(ret);
++
+ 	phy_parse_property(tphy, instance);
+ 
+ 	return instance->phy;
+@@ -1045,14 +1227,26 @@ static const struct mtk_phy_pdata tphy_v1_pdata = {
+ 
+ static const struct mtk_phy_pdata tphy_v2_pdata = {
+ 	.avoid_rx_sen_degradation = false,
++	.sw_efuse_supported = true,
+ 	.version = MTK_PHY_V2,
+ };
+ 
++static const struct mtk_phy_pdata tphy_v3_pdata = {
++	.sw_efuse_supported = true,
++	.version = MTK_PHY_V3,
++};
++
+ static const struct mtk_phy_pdata mt8173_pdata = {
+ 	.avoid_rx_sen_degradation = true,
+ 	.version = MTK_PHY_V1,
+ };
+ 
++static const struct mtk_phy_pdata mt8195_pdata = {
++	.sx_pll_48m_to_26m = true,
++	.sw_efuse_supported = true,
++	.version = MTK_PHY_V3,
++};
++
+ static const struct of_device_id mtk_tphy_id_table[] = {
+ 	{ .compatible = "mediatek,mt2701-u3phy", .data = &tphy_v1_pdata },
+ 	{ .compatible = "mediatek,mt2712-u3phy", .data = &tphy_v2_pdata },
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8007-phy-phy-mtk-tphy-Add-PCIe-2-lane-efuse-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8007-phy-phy-mtk-tphy-Add-PCIe-2-lane-efuse-support.patch
new file mode 100644
index 0000000..b710695
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8007-phy-phy-mtk-tphy-Add-PCIe-2-lane-efuse-support.patch
@@ -0,0 +1,229 @@
+From 41ffe32e7ec23f592e21c508b5108899ad393059 Mon Sep 17 00:00:00 2001
+From: Zhanyong Wang <zhanyong.wang@mediatek.com>
+Date: Tue, 25 Jan 2022 16:50:47 +0800
+Subject: [PATCH 4/5] phy: phy-mtk-tphy: Add PCIe 2 lane efuse support
+
+Add PCIe 2 lane efuse support in tphy driver.
+
+Signed-off-by: Jie Yang <jieyy.yang@mediatek.com>
+Signed-off-by: Zhanyong Wang <zhanyong.wang@mediatek.com>
+---
+ drivers/phy/mediatek/phy-mtk-tphy.c | 140 ++++++++++++++++++++++++++++
+ 1 file changed, 140 insertions(+)
+
+diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c
+index 05a1ad4..59d6ac3 100644
+--- a/drivers/phy/mediatek/phy-mtk-tphy.c
++++ b/drivers/phy/mediatek/phy-mtk-tphy.c
+@@ -39,6 +39,15 @@
+ #define SSUSB_SIFSLV_V2_U3PHYD		0x200
+ #define SSUSB_SIFSLV_V2_U3PHYA		0x400
+ 
++/* version V4 sub-banks offset base address */
++/* pcie phy banks */
++#define SSUSB_SIFSLV_V4_SPLLC		0x000
++#define SSUSB_SIFSLV_V4_CHIP		0x100
++#define SSUSB_SIFSLV_V4_U3PHYD		0x900
++#define SSUSB_SIFSLV_V4_U3PHYA		0xb00
++
++#define SSUSB_LN1_OFFSET		0x10000
++
+ #define U3P_MISC_REG1		0x04
+ #define MR1_EFUSE_AUTO_LOAD_DIS		BIT(6)
+ 
+@@ -294,6 +303,7 @@ enum mtk_phy_version {
+ 	MTK_PHY_V1 = 1,
+ 	MTK_PHY_V2,
+ 	MTK_PHY_V3,
++	MTK_PHY_V4,
+ };
+ 
+ struct mtk_phy_pdata {
+@@ -338,6 +348,9 @@ struct mtk_phy_instance {
+ 	u32 efuse_intr;
+ 	u32 efuse_tx_imp;
+ 	u32 efuse_rx_imp;
++	u32 efuse_intr_ln1;
++	u32 efuse_tx_imp_ln1;
++	u32 efuse_rx_imp_ln1;
+ 	u32 index;
+ 	u8 type;
+ 	int eye_src;
+@@ -878,6 +891,36 @@ static void phy_v2_banks_init(struct mtk_tphy *tphy,
+ 	}
+ }
+ 
++static void phy_v4_banks_init(struct mtk_tphy *tphy,
++			      struct mtk_phy_instance *instance)
++{
++	struct u2phy_banks *u2_banks = &instance->u2_banks;
++	struct u3phy_banks *u3_banks = &instance->u3_banks;
++
++	switch (instance->type) {
++	case PHY_TYPE_USB2:
++		u2_banks->misc = instance->port_base + SSUSB_SIFSLV_V2_MISC;
++		u2_banks->fmreg = instance->port_base + SSUSB_SIFSLV_V2_U2FREQ;
++		u2_banks->com = instance->port_base + SSUSB_SIFSLV_V2_U2PHY_COM;
++		break;
++	case PHY_TYPE_USB3:
++		u3_banks->spllc = instance->port_base + SSUSB_SIFSLV_V2_SPLLC;
++		u3_banks->chip = instance->port_base + SSUSB_SIFSLV_V2_CHIP;
++		u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V2_U3PHYD;
++		u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V2_U3PHYA;
++		break;
++	case PHY_TYPE_PCIE:
++		u3_banks->spllc = instance->port_base + SSUSB_SIFSLV_V4_SPLLC;
++		u3_banks->chip = instance->port_base + SSUSB_SIFSLV_V4_CHIP;
++		u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V4_U3PHYD;
++		u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V4_U3PHYA;
++		break;
++	default:
++		dev_err(tphy->dev, "incompatible PHY type\n");
++		return;
++	}
++}
++
+ static void phy_parse_property(struct mtk_tphy *tphy,
+ 				struct mtk_phy_instance *instance)
+ {
+@@ -1002,6 +1045,40 @@ static int phy_efuse_get(struct mtk_tphy *tphy, struct mtk_phy_instance *instanc
+ 		dev_info(dev, "u3 efuse - intr %x, rx_imp %x, tx_imp %x\n",
+ 			 instance->efuse_intr, instance->efuse_rx_imp,
+ 			 instance->efuse_tx_imp);
++
++		if (tphy->pdata->version != MTK_PHY_V4)
++			break;
++
++		ret = nvmem_cell_read_variable_le_u32(dev, "intr_ln1", &instance->efuse_intr_ln1);
++		if (ret) {
++			dev_err(dev, "fail to get u3 lane1 intr efuse, %d\n", ret);
++			break;
++		}
++
++		ret = nvmem_cell_read_variable_le_u32(dev, "rx_imp_ln1", &instance->efuse_rx_imp_ln1);
++		if (ret) {
++			dev_err(dev, "fail to get u3 lane1 rx_imp efuse, %d\n", ret);
++			break;
++		}
++
++		ret = nvmem_cell_read_variable_le_u32(dev, "tx_imp_ln1", &instance->efuse_tx_imp_ln1);
++		if (ret) {
++			dev_err(dev, "fail to get u3 lane1 tx_imp efuse, %d\n", ret);
++			break;
++		}
++
++		/* no efuse, ignore it */
++		if (!instance->efuse_intr_ln1 &&
++		    !instance->efuse_rx_imp_ln1 &&
++		    !instance->efuse_tx_imp_ln1) {
++			dev_warn(dev, "no u3 lane1 efuse, but dts enable it\n");
++			instance->efuse_sw_en = 0;
++			break;
++		}
++
++		dev_info(dev, "u3 lane1 efuse - intr %x, rx_imp %x, tx_imp %x\n",
++			 instance->efuse_intr_ln1, instance->efuse_rx_imp_ln1,
++			 instance->efuse_tx_imp_ln1);
+ 		break;
+ 	default:
+ 		dev_err(dev, "no sw efuse for type %d\n", instance->type);
+@@ -1035,6 +1112,31 @@ static void phy_efuse_set(struct mtk_phy_instance *instance)
+ 
+ 		break;
+ 	case PHY_TYPE_USB3:
++		tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RSV);
++		tmp |= P3D_RG_EFUSE_AUTO_LOAD_DIS;
++		writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RSV);
++
++		tmp = readl(u3_banks->phyd + U3P_U3_PHYD_IMPCAL0);
++		tmp &= ~P3D_RG_TX_IMPEL;
++		tmp |= P3D_RG_TX_IMPEL_VAL(instance->efuse_tx_imp);
++		tmp |= P3D_RG_FORCE_TX_IMPEL;
++		writel(tmp, u3_banks->phyd + U3P_U3_PHYD_IMPCAL0);
++
++		tmp = readl(u3_banks->phyd + U3P_U3_PHYD_IMPCAL1);
++		tmp &= ~P3D_RG_RX_IMPEL;
++		tmp |= P3D_RG_RX_IMPEL_VAL(instance->efuse_rx_imp);
++		tmp |= P3D_RG_FORCE_RX_IMPEL;
++		writel(tmp, u3_banks->phyd + U3P_U3_PHYD_IMPCAL1);
++
++		tmp = readl(u3_banks->phya + U3P_U3_PHYA_REG0);
++		tmp &= ~P3A_RG_IEXT_INTR;
++		tmp |= P3A_RG_IEXT_INTR_VAL(instance->efuse_intr);
++		writel(tmp, u3_banks->phya + U3P_U3_PHYA_REG0);
++		pr_err("%s set efuse, tx_imp %x, rx_imp %x intr %x\n",
++			__func__, instance->efuse_tx_imp,
++			instance->efuse_rx_imp, instance->efuse_intr);
++
++		break;
+ 	case PHY_TYPE_PCIE:
+ 		tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RSV);
+ 		tmp |= P3D_RG_EFUSE_AUTO_LOAD_DIS;
+@@ -1059,6 +1161,35 @@ static void phy_efuse_set(struct mtk_phy_instance *instance)
+ 		pr_err("%s set efuse, tx_imp %x, rx_imp %x intr %x\n",
+ 			__func__, instance->efuse_tx_imp,
+ 			instance->efuse_rx_imp, instance->efuse_intr);
++
++		if (!instance->efuse_intr_ln1 &&
++		    !instance->efuse_rx_imp_ln1 &&
++		    !instance->efuse_tx_imp_ln1)
++			break;
++
++		tmp = readl(u3_banks->phyd + SSUSB_LN1_OFFSET + U3P_U3_PHYD_RSV);
++		tmp |= P3D_RG_EFUSE_AUTO_LOAD_DIS;
++		writel(tmp, u3_banks->phyd + SSUSB_LN1_OFFSET + U3P_U3_PHYD_RSV);
++
++		tmp = readl(u3_banks->phyd + SSUSB_LN1_OFFSET + U3P_U3_PHYD_IMPCAL0);
++		tmp &= ~P3D_RG_TX_IMPEL;
++		tmp |= P3D_RG_TX_IMPEL_VAL(instance->efuse_tx_imp_ln1);
++		tmp |= P3D_RG_FORCE_TX_IMPEL;
++		writel(tmp, u3_banks->phyd + SSUSB_LN1_OFFSET + U3P_U3_PHYD_IMPCAL0);
++
++		tmp = readl(u3_banks->phyd + SSUSB_LN1_OFFSET + U3P_U3_PHYD_IMPCAL1);
++		tmp &= ~P3D_RG_RX_IMPEL;
++		tmp |= P3D_RG_RX_IMPEL_VAL(instance->efuse_rx_imp_ln1);
++		tmp |= P3D_RG_FORCE_RX_IMPEL;
++		writel(tmp, u3_banks->phyd + SSUSB_LN1_OFFSET + U3P_U3_PHYD_IMPCAL1);
++
++		tmp = readl(u3_banks->phya + SSUSB_LN1_OFFSET + U3P_U3_PHYA_REG0);
++		tmp &= ~P3A_RG_IEXT_INTR;
++		tmp |= P3A_RG_IEXT_INTR_VAL(instance->efuse_intr_ln1);
++		writel(tmp, u3_banks->phya + SSUSB_LN1_OFFSET + U3P_U3_PHYA_REG0);
++		pr_err("%s set LN1 efuse, tx_imp %x, rx_imp %x intr %x\n",
++			__func__, instance->efuse_tx_imp_ln1,
++			instance->efuse_rx_imp_ln1, instance->efuse_intr_ln1);
+ 		break;
+ 	default:
+ 		dev_warn(dev, "no sw efuse for type %d\n", instance->type);
+@@ -1197,6 +1328,8 @@ static struct phy *mtk_phy_xlate(struct device *dev,
+ 		phy_v1_banks_init(tphy, instance);
+ 	} else if (tphy->pdata->version == MTK_PHY_V2) {
+ 		phy_v2_banks_init(tphy, instance);
++	} else if (tphy->pdata->version == MTK_PHY_V4) {
++		phy_v4_banks_init(tphy, instance);
+ 	} else {
+ 		dev_err(dev, "phy version is not supported\n");
+ 		return ERR_PTR(-EINVAL);
+@@ -1247,12 +1380,19 @@ static const struct mtk_phy_pdata mt8195_pdata = {
+ 	.version = MTK_PHY_V3,
+ };
+ 
++static const struct mtk_phy_pdata tphy_v4_pdata = {
++	.avoid_rx_sen_degradation = false,
++	.sw_efuse_supported = true,
++	.version = MTK_PHY_V4,
++};
++
+ static const struct of_device_id mtk_tphy_id_table[] = {
+ 	{ .compatible = "mediatek,mt2701-u3phy", .data = &tphy_v1_pdata },
+ 	{ .compatible = "mediatek,mt2712-u3phy", .data = &tphy_v2_pdata },
+ 	{ .compatible = "mediatek,mt8173-u3phy", .data = &mt8173_pdata },
+ 	{ .compatible = "mediatek,generic-tphy-v1", .data = &tphy_v1_pdata },
+ 	{ .compatible = "mediatek,generic-tphy-v2", .data = &tphy_v2_pdata },
++	{ .compatible = "mediatek,generic-tphy-v4", .data = &tphy_v4_pdata },
+ 	{ },
+ };
+ MODULE_DEVICE_TABLE(of, mtk_tphy_id_table);
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8008-phy-phy-mtk-tphy-add-auto-load-valid-check-mechanism.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8008-phy-phy-mtk-tphy-add-auto-load-valid-check-mechanism.patch
new file mode 100644
index 0000000..1223fb6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8008-phy-phy-mtk-tphy-add-auto-load-valid-check-mechanism.patch
@@ -0,0 +1,153 @@
+From 1d5819e90f2ef6dead11809744372a9863227a92 Mon Sep 17 00:00:00 2001
+From: Zhanyong Wang <zhanyong.wang@mediatek.com>
+Date: Tue, 25 Jan 2022 19:03:34 +0800
+Subject: [PATCH 5/5] phy: phy-mtk-tphy: add auto-load-valid check mechanism
+ support
+
+add auto-load-valid check mechanism support
+
+Signed-off-by: Zhanyong Wang <zhanyong.wang@mediatek.com>
+---
+ drivers/phy/mediatek/phy-mtk-tphy.c | 67 +++++++++++++++++++++++++++--
+ 1 file changed, 64 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c
+index 59d6ac3..4adc505 100644
+--- a/drivers/phy/mediatek/phy-mtk-tphy.c
++++ b/drivers/phy/mediatek/phy-mtk-tphy.c
+@@ -345,9 +345,13 @@ struct mtk_phy_instance {
+ 	};
+ 	struct clk *ref_clk;	/* reference clock of anolog phy */
+ 	u32 efuse_sw_en;
++	bool efuse_alv_en;
++	u32 efuse_autoloadvalid;
+ 	u32 efuse_intr;
+ 	u32 efuse_tx_imp;
+ 	u32 efuse_rx_imp;
++	bool efuse_alv_ln1_en;
++	u32 efuse_ln1_autoloadvalid;
+ 	u32 efuse_intr_ln1;
+ 	u32 efuse_tx_imp_ln1;
+ 	u32 efuse_rx_imp_ln1;
+@@ -980,6 +984,7 @@ static int phy_efuse_get(struct mtk_tphy *tphy, struct mtk_phy_instance *instanc
+ {
+ 	struct device *dev = &instance->phy->dev;
+ 	int ret = 0;
++	bool alv = false;
+ 
+ 	dev_err(dev, "try to get sw efuse\n");
+ 
+@@ -998,6 +1003,20 @@ static int phy_efuse_get(struct mtk_tphy *tphy, struct mtk_phy_instance *instanc
+ 
+ 	switch (instance->type) {
+ 	case PHY_TYPE_USB2:
++		alv = of_property_read_bool(dev->of_node, "auto_load_valid");
++		if (alv) {
++			instance->efuse_alv_en = alv;
++			ret = nvmem_cell_read_variable_le_u32(dev, "auto_load_valid",
++							&instance->efuse_autoloadvalid);
++			if (ret) {
++				dev_err(dev, "fail to get u2 alv efuse, %d\n", ret);
++				break;
++			}
++			dev_info(dev,
++				"u2 auto load valid efuse: ENABLE with value: %u\n",
++				instance->efuse_autoloadvalid);
++		}
++
+ 		ret = nvmem_cell_read_variable_le_u32(dev, "intr", &instance->efuse_intr);
+ 		if (ret) {
+ 			dev_err(dev, "fail to get u2 intr efuse, %d\n", ret);
+@@ -1015,6 +1034,20 @@ static int phy_efuse_get(struct mtk_tphy *tphy, struct mtk_phy_instance *instanc
+ 		break;
+ 	case PHY_TYPE_USB3:
+ 	case PHY_TYPE_PCIE:
++		alv = of_property_read_bool(dev->of_node, "auto_load_valid");
++		if (alv) {
++			instance->efuse_alv_en = alv;
++			ret = nvmem_cell_read_variable_le_u32(dev, "auto_load_valid",
++							&instance->efuse_autoloadvalid);
++			if (ret) {
++				dev_err(dev, "fail to get u3(pcei) alv efuse, %d\n", ret);
++				break;
++			}
++			dev_info(dev,
++				"u3 auto load valid efuse: ENABLE with value: %u\n",
++				instance->efuse_autoloadvalid);
++		}
++
+ 		ret = nvmem_cell_read_variable_le_u32(dev, "intr", &instance->efuse_intr);
+ 		if (ret) {
+ 			dev_err(dev, "fail to get u3 intr efuse, %d\n", ret);
+@@ -1049,6 +1082,20 @@ static int phy_efuse_get(struct mtk_tphy *tphy, struct mtk_phy_instance *instanc
+ 		if (tphy->pdata->version != MTK_PHY_V4)
+ 			break;
+ 
++		alv = of_property_read_bool(dev->of_node, "auto_load_valid_ln1");
++		if (alv) {
++			instance->efuse_alv_ln1_en = alv;
++			ret = nvmem_cell_read_variable_le_u32(dev, "auto_load_valid_ln1",
++							&instance->efuse_ln1_autoloadvalid);
++			if (ret) {
++				dev_err(dev, "fail to get pcie auto_load_valid efuse, %d\n", ret);
++				break;
++			}
++			dev_info(dev,
++				"pcie auto load valid efuse: ENABLE with value: %u\n",
++				instance->efuse_ln1_autoloadvalid);
++		}
++
+ 		ret = nvmem_cell_read_variable_le_u32(dev, "intr_ln1", &instance->efuse_intr_ln1);
+ 		if (ret) {
+ 			dev_err(dev, "fail to get u3 lane1 intr efuse, %d\n", ret);
+@@ -1100,6 +1147,10 @@ static void phy_efuse_set(struct mtk_phy_instance *instance)
+ 
+ 	switch (instance->type) {
+ 	case PHY_TYPE_USB2:
++		if (instance->efuse_alv_en &&
++		    instance->efuse_autoloadvalid == 1)
++			break;
++
+ 		tmp = readl(u2_banks->misc + U3P_MISC_REG1);
+ 		tmp |= MR1_EFUSE_AUTO_LOAD_DIS;
+ 		writel(tmp, u2_banks->misc + U3P_MISC_REG1);
+@@ -1112,6 +1163,10 @@ static void phy_efuse_set(struct mtk_phy_instance *instance)
+ 
+ 		break;
+ 	case PHY_TYPE_USB3:
++		if (instance->efuse_alv_en &&
++		    instance->efuse_autoloadvalid == 1)
++			break;
++
+ 		tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RSV);
+ 		tmp |= P3D_RG_EFUSE_AUTO_LOAD_DIS;
+ 		writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RSV);
+@@ -1138,6 +1193,10 @@ static void phy_efuse_set(struct mtk_phy_instance *instance)
+ 
+ 		break;
+ 	case PHY_TYPE_PCIE:
++		if (instance->efuse_alv_en &&
++		    instance->efuse_autoloadvalid == 1)
++			break;
++
+ 		tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RSV);
+ 		tmp |= P3D_RG_EFUSE_AUTO_LOAD_DIS;
+ 		writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RSV);
+@@ -1162,9 +1221,11 @@ static void phy_efuse_set(struct mtk_phy_instance *instance)
+ 			__func__, instance->efuse_tx_imp,
+ 			instance->efuse_rx_imp, instance->efuse_intr);
+ 
+-		if (!instance->efuse_intr_ln1 &&
+-		    !instance->efuse_rx_imp_ln1 &&
+-		    !instance->efuse_tx_imp_ln1)
++		if ((!instance->efuse_intr_ln1 &&
++		     !instance->efuse_rx_imp_ln1 &&
++		     !instance->efuse_tx_imp_ln1) ||
++		    (instance->efuse_alv_ln1_en &&
++		     instance->efuse_ln1_autoloadvalid == 1))
+ 			break;
+ 
+ 		tmp = readl(u3_banks->phyd + SSUSB_LN1_OFFSET + U3P_U3_PHYD_RSV);
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9001-PATCH-1-2-xHCI-MT7986-USB-2.0-USBIF-compliance-toolkit.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9001-PATCH-1-2-xHCI-MT7986-USB-2.0-USBIF-compliance-toolkit.patch
new file mode 100644
index 0000000..738d9b2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9001-PATCH-1-2-xHCI-MT7986-USB-2.0-USBIF-compliance-toolkit.patch
@@ -0,0 +1,134 @@
+From b4048b5efd1ac39f85d86dedbf54a9b614d17d64 Mon Sep 17 00:00:00 2001
+From: Zhanyong Wang <zhanyong.wang@mediatek.com>
+Date: Thu, 27 May 2021 11:44:17 +0800
+Subject: [PATCH 1/2] xHCI: MT7986 USB 2.0 USBIF compliance toolkit
+
+MT7986 USB 2.0 USBIF compliance toolkit
+
+Signed-off-by: Zhanyong Wang <zhanyong.wang@mediatek.com>
+---
+ drivers/usb/host/Kconfig    | 9 +++++++++
+ drivers/usb/host/Makefile   | 8 ++++++++
+ drivers/usb/host/xhci-mtk.c | 5 ++++-
+ drivers/usb/host/xhci-mtk.h | 7 +++++++
+ drivers/usb/host/xhci.c     | 2 +-
+ drivers/usb/host/xhci.h     | 1 +
+ 6 files changed, 30 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
+index 79b2e79dddd0..12b1bf9aa043 100644
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -69,6 +69,15 @@ config USB_XHCI_MTK
+ 	  found in MediaTek SoCs.
+ 	  If unsure, say N.
+ 
++config USB_XHCI_MTK_DEBUGFS
++	tristate "xHCI DEBUGFS support for Mediatek MT65xx"
++	depends on USB_XHCI_MTK && DEBUG_FS
++       default y
++	---help---
++	  Say 'Y' to enable the debugfs support for the xHCI host controller
++	  found in Mediatek MT65xx SoCs.
++	  If don't need, say N.
++
+ config USB_XHCI_MVEBU
+ 	tristate "xHCI support for Marvell Armada 375/38x/37xx"
+ 	select USB_XHCI_PLATFORM
+diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
+index b191361257cc..704237831a58 100644
+--- a/drivers/usb/host/Makefile
++++ b/drivers/usb/host/Makefile
+@@ -21,6 +21,14 @@ endif
+ 
+ ifneq ($(CONFIG_USB_XHCI_MTK), )
+ 	xhci-hcd-y += xhci-mtk-sch.o
++	xhci-hcd-$(CONFIG_USB_XHCI_MTK_DEBUGFS) += xhci-mtk-test.o
++	xhci-hcd-$(CONFIG_USB_XHCI_MTK_DEBUGFS) += xhci-mtk-unusual.o
++	xhci-hcd-$(CONFIG_USB_XHCI_MTK_DEBUGFS) += xhci-mtk-intr-en.o
++	xhci-hcd-$(CONFIG_USB_XHCI_MTK_DEBUGFS) += xhci-mtk-vrt-vref.o
++	xhci-hcd-$(CONFIG_USB_XHCI_MTK_DEBUGFS) += xhci-mtk-term-vref.o
++	xhci-hcd-$(CONFIG_USB_XHCI_MTK_DEBUGFS) += xhci-mtk-hstx-srctrl.o
++	xhci-hcd-$(CONFIG_USB_XHCI_MTK_DEBUGFS) += xhci-mtk-discth.o
++	xhci-hcd-$(CONFIG_USB_XHCI_MTK_DEBUGFS) += xhci-mtk-chgdt-en.o
+ endif
+ 
+ xhci-plat-hcd-y := xhci-plat.o
+diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
+index 5c0eb35cd007..8bd4c95a5435 100644
+--- a/drivers/usb/host/xhci-mtk.c
++++ b/drivers/usb/host/xhci-mtk.c
+@@ -18,9 +18,10 @@
+ #include <linux/pm_runtime.h>
+ #include <linux/regmap.h>
+ #include <linux/regulator/consumer.h>
+-
++#include <linux/usb/of.h>
+ #include "xhci.h"
+ #include "xhci-mtk.h"
++#include "xhci-mtk-test.h"
+ 
+ /* ip_pw_ctrl0 register */
+ #define CTRL0_IP_SW_RST	BIT(0)
+@@ -570,6 +571,7 @@ static int xhci_mtk_probe(struct platform_device *pdev)
+ 	ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
+ 	if (ret)
+ 		goto dealloc_usb2_hcd;
++	hqa_create_attr(dev);
+ 
+ 	return 0;
+ 
+@@ -604,6 +606,7 @@ static int xhci_mtk_remove(struct platform_device *dev)
+ 	struct usb_hcd	*hcd = mtk->hcd;
+ 	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
+ 	struct usb_hcd  *shared_hcd = xhci->shared_hcd;
++	hqa_remove_attr(&dev->dev);
+ 
+ 	pm_runtime_put_noidle(&dev->dev);
+ 	pm_runtime_disable(&dev->dev);
+diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h
+index 985e7a19f6f6..1540c66799d7 100644
+--- a/drivers/usb/host/xhci-mtk.h
++++ b/drivers/usb/host/xhci-mtk.h
+@@ -158,6 +158,13 @@ struct xhci_hcd_mtk {
+ 	struct regmap *uwk;
+ 	u32 uwk_reg_base;
+ 	u32 uwk_vers;
++
++#ifdef CONFIG_USB_XHCI_MTK_DEBUGFS
++	int     test_mode;
++	size_t  hqa_size;
++	u32     hqa_pos;
++	char   *hqa_buf;
++#endif
+ };
+ 
+ static inline struct xhci_hcd_mtk *hcd_to_mtk(struct usb_hcd *hcd)
+diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
+index 4bb850370bb6..710ccbe5a3b8 100644
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -713,7 +713,7 @@ EXPORT_SYMBOL_GPL(xhci_run);
+  * Disable device contexts, disable IRQs, and quiesce the HC.
+  * Reset the HC, finish any completed transactions, and cleanup memory.
+  */
+-static void xhci_stop(struct usb_hcd *hcd)
++void xhci_stop(struct usb_hcd *hcd)
+ {
+ 	u32 temp;
+ 	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index 02df309e4409..3af400068324 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -2067,6 +2067,7 @@ int xhci_halt(struct xhci_hcd *xhci);
+ int xhci_start(struct xhci_hcd *xhci);
+ int xhci_reset(struct xhci_hcd *xhci);
+ int xhci_run(struct usb_hcd *hcd);
++void xhci_stop(struct usb_hcd *hcd);
+ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks);
+ void xhci_shutdown(struct usb_hcd *hcd);
+ void xhci_init_driver(struct hc_driver *drv,
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9002-PATCH-1-1-usb-add-embedded-Host-feature-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9002-PATCH-1-1-usb-add-embedded-Host-feature-support.patch
new file mode 100644
index 0000000..356ae99
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9002-PATCH-1-1-usb-add-embedded-Host-feature-support.patch
@@ -0,0 +1,124 @@
+From 801da3c9fd916d3743b8af174f4ef4aefc071981 Mon Sep 17 00:00:00 2001
+From: Zhanyong Wang <zhanyong.wang@mediatek.com>
+Date: Thu, 17 Jun 2021 16:09:04 +0800
+Subject: [PATCH 2/2] usb: add embedded Host feature support
+
+add EH(Embedded Host) feature for PET authentication
+1. need CONFIG_USB_OTG_WHITELIST enable
+   CONFIG_USB_OTG_WHITELIST=y
+
+2. host device tree node need include "tpl-support" keyword
+   &xhci {
+	   tpl-support;
+   }
+
+Signed-off-by: Zhanyong Wang <zhanyong.wang@mediatek.com>
+---
+ drivers/usb/core/hub.c           |  9 +++++---
+ drivers/usb/core/otg_whitelist.h | 39 ++++++++++++++++++++++++++++++++
+ drivers/usb/host/xhci-mtk.c      |  2 ++
+ 3 files changed, 47 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
+index 303e8b3c1bda..b8c96ac26886 100644
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -2419,6 +2419,8 @@ static int usb_enumerate_device(struct usb_device *udev)
+ 			if (err < 0)
+ 				dev_dbg(&udev->dev, "HNP fail, %d\n", err);
+ 		}
++
++		dev_info(&udev->dev, "Unsupported Device!\n");
+ 		return -ENOTSUPP;
+ 	}
+ 
+@@ -4778,9 +4780,10 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
+ 				goto fail;
+ 			}
+ 			if (r) {
+-				if (r != -ENODEV)
+-					dev_err(&udev->dev, "device descriptor read/64, error %d\n",
+-							r);
++				if (r != -ENODEV) {
++					dev_err(&udev->dev, "device descriptor read/64, error %d\n", r);
++					dev_info(&udev->dev, "Device No Respond\n");
++				}
+ 				retval = -EMSGSIZE;
+ 				continue;
+ 			}
+diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h
+index 2ae90158ded7..a8dd221334c1 100644
+--- a/drivers/usb/core/otg_whitelist.h
++++ b/drivers/usb/core/otg_whitelist.h
+@@ -39,9 +39,44 @@ static struct usb_device_id whitelist_table[] = {
+ { USB_DEVICE(0x0525, 0xa4a0), },
+ #endif
+ 
++/* xhci-mtk usb3 root-hub */
++{ USB_DEVICE(0x1d6b, 0x0003), },
++
++/* xhci-mtk usb2 root-hub */
++{ USB_DEVICE(0x1d6b, 0x0002), },
++
++/*  */
++{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, 0, 0) },
++
+ { }	/* Terminating entry */
+ };
+ 
++static bool usb_match_any_interface(struct usb_device *udev,
++				    const struct usb_device_id *id)
++{
++	unsigned int i;
++
++	for (i = 0; i < udev->descriptor.bNumConfigurations; ++i) {
++		struct usb_host_config *cfg = &udev->config[i];
++		unsigned int j;
++
++		for (j = 0; j < cfg->desc.bNumInterfaces; ++j) {
++			struct usb_interface_cache *cache;
++			struct usb_host_interface *intf;
++
++			cache = cfg->intf_cache[j];
++			if (cache->num_altsetting == 0)
++				continue;
++
++			intf = &cache->altsetting[0];
++			if (id->bInterfaceClass == intf->desc.bInterfaceClass)
++				return true;
++		}
++	}
++
++	return false;
++}
++
+ static int is_targeted(struct usb_device *dev)
+ {
+ 	struct usb_device_id	*id = whitelist_table;
+@@ -90,6 +125,10 @@ static int is_targeted(struct usb_device *dev)
+ 		    (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
+ 			continue;
+ 
++		if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_INFO) &&
++		    !usb_match_any_interface(dev, id))
++			continue;
++
+ 		return 1;
+ 	}
+ 
+diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
+index 8bd4c95a5435..876e134a01b4 100644
+--- a/drivers/usb/host/xhci-mtk.c
++++ b/drivers/usb/host/xhci-mtk.c
+@@ -560,6 +560,8 @@ static int xhci_mtk_probe(struct platform_device *pdev)
+ 		goto disable_device_wakeup;
+ 	}
+ 
++	hcd->tpl_support = of_usb_host_tpl_support(node);
++	xhci->shared_hcd->tpl_support = hcd->tpl_support;
+ 	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ 	if (ret)
+ 		goto put_usb3_hcd;
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9009-Add-spi-runtime-PM-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9009-Add-spi-runtime-PM-support.patch
new file mode 100644
index 0000000..8371b57
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9009-Add-spi-runtime-PM-support.patch
@@ -0,0 +1,198 @@
+From 0c1e4af01506c913cc54e63f66bb5470f50790c7 Mon Sep 17 00:00:00 2001
+From: Leilk Liu <leilk.liu@mediatek.com>
+Date: Tue, 13 Jul 2021 21:45:59 +0800
+Subject: [PATCH] [Add spi runtime PM support]
+
+[Description]
+Add ahb clk and enable runtime pm
+
+[Release-log]
+N/A
+
+Change-Id: I0529f6e829f5fc4c5880508971c97b9434820340
+Signed-off-by: Leilk Liu <leilk.liu@mediatek.com>
+---
+ drivers/spi/spi-mt65xx.c | 77 ++++++++++++++++++++++++++++++++++------
+ 1 file changed, 67 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c
+index 7e54984..ff2d825 100644
+--- a/drivers/spi/spi-mt65xx.c
++++ b/drivers/spi/spi-mt65xx.c
+@@ -119,6 +119,8 @@ struct mtk_spi_compatible {
+ 	/* the IPM IP design improve some feature, and support dual/quad mode */
+ 	bool ipm_design;
+ 	bool support_quad;
++	/* some IC ahb & apb clk is different and also need to be enabled */
++	bool need_ahb_clk;
+ };
+ 
+ struct mtk_spi {
+@@ -126,7 +128,7 @@ struct mtk_spi {
+ 	u32 state;
+ 	int pad_num;
+ 	u32 *pad_sel;
+-	struct clk *parent_clk, *sel_clk, *spi_clk;
++	struct clk *parent_clk, *sel_clk, *spi_clk, *spi_hclk;
+ 	struct spi_transfer *cur_transfer;
+ 	u32 xfer_len;
+ 	u32 num_xfered;
+@@ -147,12 +149,21 @@ static const struct mtk_spi_compatible mt2712_compat = {
+ 	.must_tx = true,
+ };
+ 
+-static const struct mtk_spi_compatible ipm_compat = {
++static const struct mtk_spi_compatible ipm_compat_single = {
++	.must_tx = true,
++	.enhance_timing = true,
++	.dma_ext = true,
++	.ipm_design = true,
++	.need_ahb_clk = true,
++};
++
++static const struct mtk_spi_compatible ipm_compat_quad = {
+ 	.must_tx = true,
+ 	.enhance_timing = true,
+ 	.dma_ext = true,
+ 	.ipm_design = true,
+ 	.support_quad = true,
++	.need_ahb_clk = true,
+ };
+ 
+ static const struct mtk_spi_compatible mt6765_compat = {
+@@ -188,8 +199,11 @@ static const struct mtk_chip_config mtk_default_chip_info = {
+ };
+ 
+ static const struct of_device_id mtk_spi_of_match[] = {
+-	{ .compatible = "mediatek,ipm-spi",
+-		.data = (void *)&ipm_compat,
++	{ .compatible = "mediatek,ipm-spi-single",
++		.data = (void *)&ipm_compat_single,
++	},
++	{ .compatible = "mediatek,ipm-spi-quad",
++		.data = (void *)&ipm_compat_quad,
+ 	},
+ 	{ .compatible = "mediatek,mt2701-spi",
+ 		.data = (void *)&mtk_common_compat,
+@@ -992,7 +1006,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
+ 		return -ENOMEM;
+ 	}
+ 
+-//	master->auto_runtime_pm = true;
++	master->auto_runtime_pm = true;
+ 	master->dev.of_node = pdev->dev.of_node;
+ 	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+ 
+@@ -1106,22 +1120,40 @@ static int mtk_spi_probe(struct platform_device *pdev)
+ 		goto err_put_master;
+ 	}
+ 
++	if (mdata->dev_comp->need_ahb_clk) {
++		mdata->spi_hclk = devm_clk_get(&pdev->dev, "spi-hclk");
++		if (IS_ERR(mdata->spi_hclk)) {
++			ret = PTR_ERR(mdata->spi_hclk);
++			dev_err(&pdev->dev, "failed to get spi-hclk: %d\n", ret);
++			goto err_put_master;
++		}
++
++		ret = clk_prepare_enable(mdata->spi_hclk);
++		if (ret < 0) {
++			dev_err(&pdev->dev, "failed to enable spi_hclk (%d)\n", ret);
++			goto err_put_master;
++		}
++	}
++
+ 	ret = clk_prepare_enable(mdata->spi_clk);
+ 	if (ret < 0) {
+ 		dev_err(&pdev->dev, "failed to enable spi_clk (%d)\n", ret);
+ 		goto err_put_master;
+ 	}
+ 
+-	/*ret = clk_set_parent(mdata->sel_clk, mdata->parent_clk);
++	ret = clk_set_parent(mdata->sel_clk, mdata->parent_clk);
+ 	if (ret < 0) {
+ 		dev_err(&pdev->dev, "failed to clk_set_parent (%d)\n", ret);
+ 		clk_disable_unprepare(mdata->spi_clk);
+ 		goto err_put_master;
+ 	}
+ 
+-	clk_disable_unprepare(mdata->sel_clk);*/
++	clk_disable_unprepare(mdata->spi_clk);
++
++	if (mdata->dev_comp->need_ahb_clk)
++		clk_disable_unprepare(mdata->spi_hclk);
+ 
+-	//pm_runtime_enable(&pdev->dev);
++	pm_runtime_enable(&pdev->dev);
+ 
+ 	ret = devm_spi_register_master(&pdev->dev, master);
+ 	if (ret) {
+@@ -1201,8 +1233,11 @@ static int mtk_spi_suspend(struct device *dev)
+ 	if (ret)
+ 		return ret;
+ 
+-	if (!pm_runtime_suspended(dev))
++	if (!pm_runtime_suspended(dev)) {
+ 		clk_disable_unprepare(mdata->spi_clk);
++		if (mdata->dev_comp->need_ahb_clk)
++			clk_disable_unprepare(mdata->spi_hclk);
++	}
+ 
+ 	return ret;
+ }
+@@ -1214,6 +1249,14 @@ static int mtk_spi_resume(struct device *dev)
+ 	struct mtk_spi *mdata = spi_master_get_devdata(master);
+ 
+ 	if (!pm_runtime_suspended(dev)) {
++		if (mdata->dev_comp->need_ahb_clk) {
++			ret = clk_prepare_enable(mdata->spi_hclk);
++			if (ret < 0) {
++				dev_err(dev, "failed to enable spi_hclk (%d)\n", ret);
++				return ret;
++			}
++		}
++
+ 		ret = clk_prepare_enable(mdata->spi_clk);
+ 		if (ret < 0) {
+ 			dev_err(dev, "failed to enable spi_clk (%d)\n", ret);
+@@ -1222,8 +1265,11 @@ static int mtk_spi_resume(struct device *dev)
+ 	}
+ 
+ 	ret = spi_master_resume(master);
+-	if (ret < 0)
++	if (ret < 0) {
+ 		clk_disable_unprepare(mdata->spi_clk);
++		if (mdata->dev_comp->need_ahb_clk)
++			clk_disable_unprepare(mdata->spi_hclk);
++	}
+ 
+ 	return ret;
+ }
+@@ -1237,6 +1283,9 @@ static int mtk_spi_runtime_suspend(struct device *dev)
+ 
+ 	clk_disable_unprepare(mdata->spi_clk);
+ 
++	if (mdata->dev_comp->need_ahb_clk)
++		clk_disable_unprepare(mdata->spi_hclk);
++
+ 	return 0;
+ }
+ 
+@@ -1246,6 +1295,14 @@ static int mtk_spi_runtime_resume(struct device *dev)
+ 	struct mtk_spi *mdata = spi_master_get_devdata(master);
+ 	int ret;
+ 
++	if (mdata->dev_comp->need_ahb_clk) {
++		ret = clk_prepare_enable(mdata->spi_hclk);
++		if (ret < 0) {
++			dev_err(dev, "failed to enable spi_hclk (%d)\n", ret);
++			return ret;
++		}
++	}
++
+ 	ret = clk_prepare_enable(mdata->spi_clk);
+ 	if (ret < 0) {
+ 		dev_err(dev, "failed to enable spi_clk (%d)\n", ret);
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9010-iwconfig-wireless-rate-fix.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9010-iwconfig-wireless-rate-fix.patch
new file mode 100644
index 0000000..b29e4cc
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9010-iwconfig-wireless-rate-fix.patch
@@ -0,0 +1,20 @@
+--- a/include/uapi/linux/wireless.h

++++ b/include/uapi/linux/wireless.h

+@@ -678,7 +678,7 @@

+  *	Generic format for most parameters that fit in an int

+  */

+ struct iw_param {

+-  __s32		value;		/* The value of the parameter itself */

++  __u64		value;		/* The value of the parameter itself */

+   __u8		fixed;		/* Hardware should not use auto select */

+   __u8		disabled;	/* Disable the feature */

+   __u16		flags;		/* Various specifc flags (if any) */

+@@ -1002,7 +1002,7 @@ struct iw_range {

+ 

+ 	/* Rates */

+ 	__u8		num_bitrates;	/* Number of entries in the list */

+-	__s32		bitrate[IW_MAX_BITRATES];	/* list, in bps */

++	__u64		bitrate[IW_MAX_BITRATES];	/* list, in bps */

+ 

+ 	/* RTS threshold */

+ 	__s32		min_rts;	/* Minimal RTS threshold */

diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-add_armv7_support_for_panther.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-add_armv7_support_for_panther.patch
new file mode 100644
index 0000000..24dadf3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-add_armv7_support_for_panther.patch
@@ -0,0 +1,14 @@
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index 8a50efb..f601368 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -576,6 +576,8 @@ config ARCH_MULTI_V7
+ 	select ARCH_MULTI_V6_V7
+ 	select CPU_V7
+ 	select HAVE_SMP
++	select ARM_GIC_V3
++	select HAVE_ARM_ARCH_TIMER
+ 
+ config ARCH_MULTI_V6_V7
+ 	bool
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9999-null-test.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9999-null-test.patch
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9999-null-test.patch
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
new file mode 100644
index 0000000..2fbfbf9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
@@ -0,0 +1,101 @@
+#patch patches-5.4 (come from openwrt/lede/target/linux/mediatek)
+SRC_URI_append = " \
+    file://0001-clk-mtk-add-mt7986-support.patch \
+    file://0001-v5.7-spi-make-spi-max-frequency-optional.patch \
+    file://0002-clk-mtk-add-mt7981-support.patch \
+    file://0002-v5.7-spi-add-support-for-mediatek-spi-nor-controller.patch \
+    file://0003-switch-add-mt7531.patch \
+    file://0005-dts-mt7622-add-gsw.patch \
+    file://0005-dts-mt7629-add-gsw.patch \
+    file://0006-dts-fix-bpi2-console.patch \
+    file://0006-dts-fix-bpi64-console.patch \
+    file://0010-dts-mt7629-rfb-fix-firmware-partition.patch \
+    file://0020-dts-mt7622-enable-new-mtk-snand-for-ubi.patch \
+    file://0021-dts-mt7622-remove-cooling-device.patch \
+    file://0100-hwnat_Kconfig_Makefile.patch \
+    file://0101-add-mtk-wifi-utility-rbus.patch \
+    file://0111-mt7986-trng-add-rng-support.patch \
+    file://0200-show_model_name_in_cpuinfo_on_arm64.patch \
+    file://0226-phy-phy-mtk-tphy-Add-hifsys-support.patch \
+    file://0227-arm-dts-Add-Unielec-U7623-DTS.patch \
+    file://0301-mtd-mtk-ecc-move-mtk-ecc-header-file-to-include-mtd.patch \
+    file://0306-spi-spi-mem-MediaTek-Add-SPI-NAND-Flash-interface-dr.patch \
+    file://0307-dts-mt7629-add-snand-support.patch \
+    file://0308-dts-mt7622-add-snand-support.patch \
+    file://0310-dts-add-wmac-support-for-mt7622-rfb1.patch \
+    file://0400-sound-add-some-helpers-to-control-mtk_memif.patch \
+    file://0401-sound-refine-hw-params-and-hw-prepare.patch \
+    file://0402-sound-add-mt7986-driver-and-slic-driver.patch \
+    file://0500-v5.6-crypto-backport-inside-secure.patch \
+    file://0501-crypto-add-eip97-inside-secure-support.patch \
+    file://0502-dts-mt7623-eip97-inside-secure-support.patch \
+    file://0503-crypto-fix-eip97-cache-incoherent.patch \
+    file://0504-macsec-revert-async-support.patch \
+    file://0600-net-phylink-propagate-resolved-link-config-via-mac_l.patch \
+    file://0601-net-dsa-propagate-resolved-link-config-via-mac_link_.patch \
+    file://0602-net-dsa-mt7530-use-resolved-link-config-in-mac_link_.patch \
+    file://0603-net-dsa-mt7530-Extend-device-data-ready-for-adding-a.patch \
+    file://0604-net-dsa-mt7530-Add-the-support-of-MT7531-switch.patch \
+    file://0605-arm64-dts-mt7622-add-mt7531-dsa-to-bananapi-bpi-r64-board.patch \
+    file://0666-add-spimem-support-to-mtk-spi.patch \
+    file://0666-spi-mtk-nor-fix-timeout-calculation-overflow.patch \
+    file://0667-spi-mediatek-fix-timeout-for-large-data.patch \
+    file://0668-spi-mediatek-fix-dma-unmap-twice.patch \
+    file://0669-fix-SPIM-NAND-and-NOR-probing.patch \
+    file://0670-fix-SPIM-dma-buffer-not-aligned.patch \
+    file://0671-add-micron-MT29F4G01ABAFD-spi-nand-support.patch \
+    file://0672-add-F50L1G41LB-and-GD5F1GQ5UExxG-snand-support.patch \
+    file://0701-fix-mtk-nfi-driver-dependency.patch \
+    file://0801-mtk-sd-add-mt7986-support.patch \
+    file://0900-bt-mtk-serial-fix.patch \
+    file://0900-i2c-busses-add-mt7986-support.patch \
+    file://0901-i2c-busses-add-mt7981-support.patch \
+    file://0930-pwm-add-mt7986-support.patch \
+    file://0931-pwm-add-mt7981-support.patch \
+    file://0960-watchdog-add-mt7986-assert.patch \
+    file://0990-gsw-rtl8367s-mt7622-support.patch \
+    file://0991-dt-bindings-PCI-Mediatek-Update-PCIe-binding.patch \
+    file://0992-PCI-mediatek-Use-regmap-to-get-shared-pcie-cfg-base.patch \
+    file://0993-arm64-dts-mediatek-Split-PCIe-node-for-MT2712-MT7622.patch \
+    file://0994-ARM-dts-mediatek-Update-mt7629-PCIe-node.patch \
+    file://1001-mtkhnat-ipv6-fix-pskb-expand-head-limitation.patch \
+    file://1002-mtkhnat-add-support-for-virtual-interface-acceleration.patch \
+    file://1003-dts-mt7622-rfb-change-to-ax-mtd-layout.patch \
+    file://1004_remove_eth_transmit_timeout_hw_reset.patch \
+    file://1005-mtkhnat-fix-pse-hang-for-multi-stations.patch \
+    file://1010-pcie-mediatek-fix-clearing-interrupt-status.patch \
+    file://1015-pcie-add-pcie-gen3-upstream-driver.patch \
+    file://1020-spi-nor-w25q512jv.patch \
+    file://1021-ubnt-ledbar-driver.patch \
+    file://1023-kgdb-add-interrupt-control.patch \
+    file://1024-pcie-add-multi-MSI-support.patch \
+    file://1661-Add-trngv2-driver-support.patch \
+    file://2000-misc-add-mtk-platform.patch \
+    file://400-mtd-add-mtk-snand-driver.patch \
+    file://401-pinctrl-add-mt7986-driver.patch \
+    file://402-pinctrl-add-mt7981-driver.patch \
+    file://500-auxadc-add-auxadc-32k-clk.patch \
+    file://730-net-ethernet-mtk_eth_soc-add-mtk-dsa-tag-rx-offload.patch \
+    file://738-mt7531-gsw-internal_phy_calibration.patch \
+    file://739-mt7531-gsw-port5_external_phy_init.patch \
+    file://740-add-gpy211-phy-support.patch \
+    file://741-add-default-setting-to-dsa-unused-port.patch \
+    file://742-net-dsa-add-MT7531-Gigabit-Ethernet-PHY-setting.patch \
+    file://743-add-mediatek-ge-gphy-support.patch \
+    file://744-en8801s-gphy-support.patch \
+    file://8000-PATCH-1-4-tphy-support-type-switch-by-pericfg.patch \
+    file://8001-PATCH-2-4-dt-bindings-phy-Add-PHY_TYPE_DP-definition.patch \
+    file://8002-PATCH-3-4-dt-bindings-phy-Add-PHY_TYPE_XPCS-definition.patch \
+    file://8003-PATCH-4-4-dt-bindings-phy-Add-DT-bindings-for-Xilinx-ZynqMP-PS.patch \
+    file://8004-nvmem-core-Add-functions-to-make-number-reading-easy.patch \
+    file://8005-nvmem-mtk-efuse-support-minimum-one-byte-access-stri.patch \
+    file://8006-phy-phy-mtk-tphy-add-support-efuse-setting.patch \
+    file://8007-phy-phy-mtk-tphy-Add-PCIe-2-lane-efuse-support.patch \
+    file://8008-phy-phy-mtk-tphy-add-auto-load-valid-check-mechanism.patch \
+    file://9001-PATCH-1-2-xHCI-MT7986-USB-2.0-USBIF-compliance-toolkit.patch \
+    file://9002-PATCH-1-1-usb-add-embedded-Host-feature-support.patch \
+    file://9009-Add-spi-runtime-PM-support.patch \
+    file://9010-iwconfig-wireless-rate-fix.patch \
+    file://999-add_armv7_support_for_panther.patch \
+    file://9999-null-test.patch \
+    "
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/rdkb_cfg/iptables.cfg b/recipes-kernel/linux/linux-mediatek-5.4/rdkb_cfg/iptables.cfg
new file mode 100644
index 0000000..fcfc3a4
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/rdkb_cfg/iptables.cfg
@@ -0,0 +1,46 @@
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_INET_UDP_DIAG=m
+CONFIG_IPV6=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_HL=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_RECENT=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_IP_SET=m
+CONFIG_IP_VS=m
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_REJECT_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/rdkb_cfg/mac80211.cfg b/recipes-kernel/linux/linux-mediatek-5.4/rdkb_cfg/mac80211.cfg
new file mode 100644
index 0000000..ece7502
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/rdkb_cfg/mac80211.cfg
@@ -0,0 +1,5 @@
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_CCM=y
+CONFIG_CRYPTO_GCM=y
+CONFIG_CRYPTO_CMAC=y
+CONFIG_RELAY=y
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/rdkb_cfg/openvswitch.cfg b/recipes-kernel/linux/linux-mediatek-5.4/rdkb_cfg/openvswitch.cfg
new file mode 100644
index 0000000..3eb2743
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/rdkb_cfg/openvswitch.cfg
@@ -0,0 +1,5 @@
+CONFIG_OPENVSWITCH=m
+CONFIG_OPENVSWITCH_GRE=m
+CONFIG_GENEVE=y
+CONFIG_NET_IPGRE_DEMUX=y
+CONFIG_NET_IPGRE=y
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/rdkb_cfg/prplmesh.cfg b/recipes-kernel/linux/linux-mediatek-5.4/rdkb_cfg/prplmesh.cfg
new file mode 100644
index 0000000..3e75a44
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/rdkb_cfg/prplmesh.cfg
@@ -0,0 +1,13 @@
+# Needed only for case BWL_HAL=DUMMY to create
+# dummy ifaces "wlan0" and "wlan2"
+CONFIG_DUMMY=y
+
+CONFIG_BRIDGE=y
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_NETFILTER=y
+
+CONFIG_NETFILTER=y  
+CONFGI_NETFILTER_ADVANCED=y
+CONFIG_NF_TABLES=y
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/rdkb_cfg/turris_rdkb.cfg b/recipes-kernel/linux/linux-mediatek-5.4/rdkb_cfg/turris_rdkb.cfg
new file mode 100644
index 0000000..532889c6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/rdkb_cfg/turris_rdkb.cfg
@@ -0,0 +1,6 @@
+CONFIG_POSIX_MQUEUE=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_CGROUPS=y
+CONFIG_NFS_FS=y
+CONFIG_NFSD=y
+CONFIG_CGROUP_BPF=y